Merge "Add ctre support for arm64"
diff --git a/.bazelignore b/.bazelignore
index 9da1960..7fa8e45 100644
--- a/.bazelignore
+++ b/.bazelignore
@@ -13,3 +13,4 @@
 scouting/www/view/node_modules
 scouting/www/pit_scouting/node_modules
 scouting/www/scan/node_modules
+aos/analysis/foxglove_extension/node_modules
diff --git a/.bazelrc b/.bazelrc
index be75aa1..09c943f 100644
--- a/.bazelrc
+++ b/.bazelrc
@@ -157,6 +157,30 @@
 build:remote --remote_instance_name=fuse
 build:remote --verbose_failures
 
+# How to use IWYU - Include What You Use
+# Start by deleting any *.iwyu.txt files that you might have from a previous run:
+#  find -L bazel-bin/ -name "*.iwyu.txt" | xargs rm
+# Build desired target(s)
+#  bazel build --config=iwyu //my:target
+# run script to fix includes
+#  find -L bazel-bin/ -name "*.iwyu.txt" | \
+#  xargs -I % sh -c 'external/iwyu_prebuilt_pkg/bin/fix_includes.py --nosafe_headers < $1' sh %
+# run clang-format to get includes in the right order
+#  bazel run //tools/lint:clang_format
+# build targets, or ideally everything, to make sure that it still builds.
+#
+# If you are unhappy with the result, you have the following options:
+# Use pragmas or mappings.
+# https://github.com/include-what-you-use/include-what-you-use/blob/master/docs/IWYUPragmas.md
+# https://github.com/include-what-you-use/include-what-you-use/blob/master/docs/IWYUMappings.md
+# Our mapping files are in tools/iwyu.
+build:iwyu --aspects @com_github_storypku_bazel_iwyu//bazel/iwyu:iwyu.bzl%iwyu_aspect
+build:iwyu --@com_github_storypku_bazel_iwyu//:iwyu_mappings=//tools/iwyu:mappings
+build:iwyu --output_groups=report
+build:iwyu --@com_github_storypku_bazel_iwyu//:iwyu_opts=--no_fwd_decls,--cxx17ns,--verbose=3
+build:iwyu --strategy=iwyu=sandboxed,standalone
+
+
 # Load a local file that users can use to customize bazel invocations.  This
 # should stay the last line in this file so users can override things when they
 # want.
diff --git a/WORKSPACE b/WORKSPACE
index 0692615..99b76a7 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -374,16 +374,6 @@
 )
 
 http_archive(
-    name = "com_github_stevengj_nlopt",
-    build_file = "@//debian:nlopt.BUILD",
-    patch_args = ["-p1"],
-    patches = ["//debian:nlopt.patch"],
-    sha256 = "2d65815b21c30813499fe19c63947f7da56b10c0d4a459dce05417899b43e461",
-    strip_prefix = "nlopt-496be736b8b249273838b891f4c8ca3669551127",
-    url = "https://software.frc971.org/Build-Dependencies/nlopt-496be736b8b249273838b891f4c8ca3669551127.zip",
-)
-
-http_archive(
     name = "com_google_absl",
     patch_args = ["-p1"],
     patches = ["//third_party/abseil:abseil.patch"],
@@ -430,11 +420,8 @@
 # C++ rules for Bazel.
 http_archive(
     name = "rules_cc",
-    sha256 = "ed36cc7a6f46b7c28ab4009db4a37e350e1ba367446b0886bcc9cdc1df92752e",
-    strip_prefix = "rules_cc-608c7b605fb844a20e96a3eddc9b49ad2542adab",
-    urls = [
-        "https://software.frc971.org/Build-Dependencies/rules_cc-608c7b605fb844a20e96a3eddc9b49ad2542adab.zip",
-    ],
+    sha256 = "d75a040c32954da0d308d3f2ea2ba735490f49b3a7aa3e4b40259ca4b814f825",
+    urls = ["https://github.com/bazelbuild/rules_cc/releases/download/0.0.10-rc1/rules_cc-0.0.10-rc1.tar.gz"],
 )
 
 new_local_repository(
@@ -964,6 +951,7 @@
 npm_translate_lock(
     name = "npm",
     data = [
+        "//aos/analysis/foxglove_extension:package.json",
         "@//:package.json",
         "@//:pnpm-workspace.yaml",
         "@//scouting/webserver/requests/messages:package.json",
@@ -1706,18 +1694,6 @@
 )
 
 http_archive(
-    name = "com_github_nvidia_cuco",
-    build_file = "//third_party/cuco:cuco.BUILD",
-    patch_args = ["-p1"],
-    patches = [
-        "//third_party/cuco:template.patch",
-    ],
-    sha256 = "eecc9a111956a195f28ebc4b4fd23ac6991d072f5c1d7c68a59d059e05d7ad78",
-    strip_prefix = "cuCollections-b7514d2010967fdfe4a1d414894bb945bc09fddc",
-    url = "https://github.com/NVIDIA/cuCollections/archive/b7514d2010967fdfe4a1d414894bb945bc09fddc.zip",
-)
-
-http_archive(
     name = "com_github_nvidia_cccl",
     build_file = "//third_party/cccl:cccl.BUILD",
     sha256 = "38160c628a9e32b7cd55553f299768f72b24074cc9c1a993ba40a177877b3421",
@@ -1767,3 +1743,31 @@
     strip_prefix = "expected-1.1.0",
     url = "https://github.com/TartanLlama/expected/archive/refs/tags/v1.1.0.tar.gz",
 )
+
+http_archive(
+    name = "com_github_storypku_bazel_iwyu",
+    integrity = "sha256-R/rVwWn3SveoC8lAcicw6MOfdTqLLkubpaljT4qHjJg=",
+    strip_prefix = "bazel_iwyu-bb102395e553215abd66603bcdeb6e93c66ca6d7",
+    urls = [
+        "https://github.com/storypku/bazel_iwyu/archive/bb102395e553215abd66603bcdeb6e93c66ca6d7.zip",
+    ],
+)
+
+load("@com_github_storypku_bazel_iwyu//bazel:dependencies.bzl", "bazel_iwyu_dependencies")
+
+bazel_iwyu_dependencies()
+
+http_archive(
+    name = "m4_v1.4.18",
+    build_file = "@//debian:m4.BUILD",
+    sha256 = "ee8dfe664ac8c1d066bab64f71bd076a021875581b3cc47dac4a14a475f50b15",
+    url = "http://software.frc971.org/Build-Dependencies/m4.tar.gz",
+)
+
+http_archive(
+    name = "symengine",
+    build_file = "@//debian:symengine.BUILD",
+    sha256 = "1b5c3b0bc6a9f187635f93585649f24a18e9c7f2167cebcd885edeaaf211d956",
+    strip_prefix = "symengine-0.12.0",
+    url = "http://software.frc971.org/Build-Dependencies/github.com/symengine/symengine/releases/download/v0.12.0/symengine-0.12.0.tar.gz",
+)
diff --git a/aos/actions/action_test.cc b/aos/actions/action_test.cc
index c7c3c48..fca60a3 100644
--- a/aos/actions/action_test.cc
+++ b/aos/actions/action_test.cc
@@ -1,17 +1,27 @@
-#include <unistd.h>
+#include <stdint.h>
 
 #include <chrono>
+#include <functional>
 #include <memory>
-#include <thread>
+#include <ostream>
+#include <string>
 
+#include "flatbuffers/buffer.h"
+#include "glog/logging.h"
 #include "gtest/gtest.h"
 
 #include "aos/actions/actions.h"
 #include "aos/actions/actions_generated.h"
 #include "aos/actions/actor.h"
 #include "aos/actions/test_action_generated.h"
+#include "aos/configuration.h"
+#include "aos/events/event_loop.h"
 #include "aos/events/simulated_event_loop.h"
+#include "aos/flatbuffers.h"
+#include "aos/json_to_flatbuffer.h"
+#include "aos/logging/implementations.h"
 #include "aos/testing/path.h"
+#include "aos/time/time.h"
 
 namespace aos::common::actions::testing {
 
diff --git a/aos/actions/actions.cc b/aos/actions/actions.cc
index 133101b..0e0e6fd 100644
--- a/aos/actions/actions.cc
+++ b/aos/actions/actions.cc
@@ -1,5 +1,7 @@
 #include "aos/actions/actions.h"
 
+#include <utility>
+
 namespace aos::common::actions {
 
 void ActionQueue::EnqueueAction(::std::unique_ptr<Action> action) {
diff --git a/aos/actions/actions.h b/aos/actions/actions.h
index f60f20b..1aae62f 100644
--- a/aos/actions/actions.h
+++ b/aos/actions/actions.h
@@ -1,14 +1,17 @@
 #ifndef AOS_ACTIONS_ACTIONS_H_
 #define AOS_ACTIONS_ACTIONS_H_
 
-#include <sys/types.h>
 #include <unistd.h>
 
 #include <atomic>
 #include <cinttypes>
 #include <memory>
+#include <ostream>
+#include <string>
 #include <type_traits>
 
+#include "glog/logging.h"
+
 #include "aos/actions/actions_generated.h"
 #include "aos/events/event_loop.h"
 #include "aos/json_to_flatbuffer.h"
diff --git a/aos/actions/actor.h b/aos/actions/actor.h
index f7066fc..b0b6bd4 100644
--- a/aos/actions/actor.h
+++ b/aos/actions/actor.h
@@ -3,11 +3,19 @@
 
 #include <chrono>
 #include <cinttypes>
-#include <cstdio>
+#include <compare>
 #include <functional>
+#include <ostream>
+#include <string>
+#include <type_traits>
+
+#include "flatbuffers/string.h"
+#include "glog/logging.h"
 
 #include "aos/actions/actions_generated.h"
+#include "aos/configuration_generated.h"
 #include "aos/events/event_loop.h"
+#include "aos/json_to_flatbuffer.h"
 #include "aos/logging/logging.h"
 #include "aos/time/time.h"
 #include "aos/util/phased_loop.h"
diff --git a/aos/analysis/foxglove_extension/.eslintrc.yaml b/aos/analysis/foxglove_extension/.eslintrc.yaml
new file mode 100644
index 0000000..10d5ae0
--- /dev/null
+++ b/aos/analysis/foxglove_extension/.eslintrc.yaml
@@ -0,0 +1,27 @@
+root: true
+
+env:
+  browser: true
+  es2020: true
+  node: false
+
+ignorePatterns:
+  - dist
+
+plugins:
+  - jest
+
+extends:
+  - plugin:@foxglove/base
+  - plugin:@foxglove/react
+
+rules:
+  react-hooks/exhaustive-deps:
+    - error
+
+overrides:
+  - files: ["*.ts", "*.tsx"]
+    extends:
+      - plugin:@foxglove/typescript
+    parserOptions:
+      project: ./tsconfig.json
diff --git a/aos/analysis/foxglove_extension/.gitignore b/aos/analysis/foxglove_extension/.gitignore
new file mode 100644
index 0000000..e9b56e6
--- /dev/null
+++ b/aos/analysis/foxglove_extension/.gitignore
@@ -0,0 +1,107 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+lerna-debug.log*
+
+# Diagnostic reports (https://nodejs.org/api/report.html)
+report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
+
+# Runtime data
+pids
+*.pid
+*.seed
+*.pid.lock
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+*.lcov
+
+# nyc test coverage
+.nyc_output
+
+# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+# Bower dependency directory (https://bower.io/)
+bower_components
+
+# node-waf configuration
+.lock-wscript
+
+# Compiled binary addons (https://nodejs.org/api/addons.html)
+build/Release
+
+# Dependency directories
+node_modules/
+jspm_packages/
+
+# TypeScript cache
+*.tsbuildinfo
+
+# Optional npm cache directory
+.npm
+
+# Optional eslint cache
+.eslintcache
+
+# Microbundle cache
+.rpt2_cache/
+.rts2_cache_cjs/
+.rts2_cache_es/
+.rts2_cache_umd/
+
+# Optional REPL history
+.node_repl_history
+
+# Output of 'npm pack'
+*.tgz
+
+# Yarn Integrity file
+.yarn-integrity
+
+# dotenv environment variables file
+.env
+.env.test
+
+# parcel-bundler cache (https://parceljs.org/)
+.cache
+
+# Next.js build output
+.next
+
+# Nuxt.js build / generate output
+.nuxt
+dist
+
+# Gatsby files
+.cache/
+# Comment in the public line in if your project uses Gatsby and *not* Next.js
+# https://nextjs.org/blog/next-9-1#public-directory-support
+# public
+
+# vuepress build output
+.vuepress/dist
+
+# Serverless directories
+.serverless/
+
+# FuseBox cache
+.fusebox/
+
+# DynamoDB Local files
+.dynamodb/
+
+# TernJS port file
+.tern-port
+
+# Build output
+www/js/*
+
+# MacOS
+.DS_Store
diff --git a/aos/analysis/foxglove_extension/.prettierrc.yaml b/aos/analysis/foxglove_extension/.prettierrc.yaml
new file mode 100644
index 0000000..e57cc20
--- /dev/null
+++ b/aos/analysis/foxglove_extension/.prettierrc.yaml
@@ -0,0 +1,5 @@
+arrowParens: always
+printWidth: 100
+trailingComma: "all"
+tabWidth: 2
+semi: true
diff --git a/aos/analysis/foxglove_extension/BUILD.bazel b/aos/analysis/foxglove_extension/BUILD.bazel
new file mode 100644
index 0000000..60f03dc
--- /dev/null
+++ b/aos/analysis/foxglove_extension/BUILD.bazel
@@ -0,0 +1,8 @@
+load("@npm//:defs.bzl", "npm_link_all_packages")
+load("//tools/build_rules:foxglove.bzl", "foxglove_extension")
+
+npm_link_all_packages(name = "node_modules")
+
+foxglove_extension(
+    name = "extension",
+)
diff --git a/aos/analysis/foxglove_extension/CHANGELOG.md b/aos/analysis/foxglove_extension/CHANGELOG.md
new file mode 100644
index 0000000..7bff0ee
--- /dev/null
+++ b/aos/analysis/foxglove_extension/CHANGELOG.md
@@ -0,0 +1,5 @@
+# foxglove_extension version history
+
+## 0.0.0
+
+- Alpha testing
diff --git a/aos/analysis/foxglove_extension/LICENSE b/aos/analysis/foxglove_extension/LICENSE
new file mode 100644
index 0000000..03127ea
--- /dev/null
+++ b/aos/analysis/foxglove_extension/LICENSE
@@ -0,0 +1 @@
+Add your extension license here and update the package.json "license" field before publishing. License templates can be found at <https://github.com/licenses/license-templates>.
diff --git a/aos/analysis/foxglove_extension/README.md b/aos/analysis/foxglove_extension/README.md
new file mode 100644
index 0000000..abd505e
--- /dev/null
+++ b/aos/analysis/foxglove_extension/README.md
@@ -0,0 +1,51 @@
+# IMPORTANT NOTE
+
+The contents of this directory are the result of:
+
+    $ cd aos/analysis/
+    $ ../../tools/foxglove/create-foxglove-extension foxglove_extension
+
+Future patches will change the contents of this directory to be actually useful
+for analysis of AOS systems.
+
+# foxglove_extension
+
+## _A Foxglove Studio Extension_
+
+[Foxglove Studio](https://github.com/foxglove/studio) allows developers to create extensions, or custom code that is loaded and executed inside the Foxglove Studio application. This can be used to add custom panels. Extensions are authored in TypeScript using the `@foxglove/studio` SDK.
+
+## Develop
+
+Extension development uses the `npm` package manager to install development dependencies and run build scripts.
+
+To install extension dependencies, run `npm` from the root of the extension package.
+
+```sh
+npm install
+```
+
+To build and install the extension into your local Foxglove Studio desktop app, run:
+
+```sh
+npm run local-install
+```
+
+Open the `Foxglove Studio` desktop (or `ctrl-R` to refresh if it is already open). Your extension is installed and available within the app.
+
+## Package
+
+Extensions are packaged into `.foxe` files. These files contain the metadata (package.json) and the build code for the extension.
+
+Before packaging, make sure to set `name`, `publisher`, `version`, and `description` fields in _package.json_. When ready to distribute the extension, run:
+
+```sh
+npm run package
+```
+
+This command will package the extension into a `.foxe` file in the local directory.
+
+## Publish
+
+You can publish the extension for the public marketplace or privately for your organization.
+
+See documentation here: https://foxglove.dev/docs/studio/extensions/publish#packaging-your-extension
diff --git a/aos/analysis/foxglove_extension/package.json b/aos/analysis/foxglove_extension/package.json
new file mode 100644
index 0000000..7678259
--- /dev/null
+++ b/aos/analysis/foxglove_extension/package.json
@@ -0,0 +1,43 @@
+{
+    "dependencies": {
+        "@foxglove/eslint-plugin": "^1",
+        "@foxglove/studio": "^1",
+        "@types/react": "^18",
+        "@types/react-dom": "^18",
+        "@typescript-eslint/eslint-plugin": "^6",
+        "@typescript-eslint/parser": "^6",
+        "create-foxglove-extension": "^0",
+        "eslint": "^8",
+        "eslint-config-prettier": "^8",
+        "eslint-plugin-es": "^4",
+        "eslint-plugin-filenames": "^1",
+        "eslint-plugin-import": "^2",
+        "eslint-plugin-jest": "^27",
+        "eslint-plugin-prettier": "^5",
+        "eslint-plugin-react": "^7",
+        "eslint-plugin-react-hooks": "^4",
+        "prettier": "^3",
+        "react": "^18",
+        "react-dom": "^18",
+        "ts-loader": "^9",
+        "typescript": "^5"
+    },
+    "description": "",
+    "displayName": "foxglove_extension",
+    "homepage": "",
+    "keywords": [],
+    "license": "UNLICENSED",
+    "main": "./dist/extension.js",
+    "name": "foxglove_extension",
+    "publisher": "unknown",
+    "scripts": {
+        "build": "foxglove-extension build",
+        "foxglove:prepublish": "foxglove-extension build --mode production",
+        "lint": "eslint --report-unused-disable-directives --fix .",
+        "lint:ci": "eslint --report-unused-disable-directives .",
+        "local-install": "foxglove-extension install",
+        "package": "foxglove-extension package",
+        "pretest": "foxglove-extension pretest"
+    },
+    "version": "0.0.0"
+}
\ No newline at end of file
diff --git a/aos/analysis/foxglove_extension/src/ExamplePanel.tsx b/aos/analysis/foxglove_extension/src/ExamplePanel.tsx
new file mode 100644
index 0000000..61ccb6a
--- /dev/null
+++ b/aos/analysis/foxglove_extension/src/ExamplePanel.tsx
@@ -0,0 +1,86 @@
+import { Immutable, MessageEvent, PanelExtensionContext, Topic } from "@foxglove/studio";
+import { useEffect, useLayoutEffect, useState } from "react";
+import ReactDOM from "react-dom";
+
+function ExamplePanel({ context }: { context: PanelExtensionContext }): JSX.Element {
+  const [topics, setTopics] = useState<undefined | Immutable<Topic[]>>();
+  const [messages, setMessages] = useState<undefined | Immutable<MessageEvent[]>>();
+
+  const [renderDone, setRenderDone] = useState<(() => void) | undefined>();
+
+  // We use a layout effect to setup render handling for our panel. We also setup some topic subscriptions.
+  useLayoutEffect(() => {
+    // The render handler is run by the broader studio system during playback when your panel
+    // needs to render because the fields it is watching have changed. How you handle rendering depends on your framework.
+    // You can only setup one render handler - usually early on in setting up your panel.
+    //
+    // Without a render handler your panel will never receive updates.
+    //
+    // The render handler could be invoked as often as 60hz during playback if fields are changing often.
+    context.onRender = (renderState, done) => {
+      // render functions receive a _done_ callback. You MUST call this callback to indicate your panel has finished rendering.
+      // Your panel will not receive another render callback until _done_ is called from a prior render. If your panel is not done
+      // rendering before the next render call, studio shows a notification to the user that your panel is delayed.
+      //
+      // Set the done callback into a state variable to trigger a re-render.
+      setRenderDone(() => done);
+
+      // We may have new topics - since we are also watching for messages in the current frame, topics may not have changed
+      // It is up to you to determine the correct action when state has not changed.
+      setTopics(renderState.topics);
+
+      // currentFrame has messages on subscribed topics since the last render call
+      setMessages(renderState.currentFrame);
+    };
+
+    // After adding a render handler, you must indicate which fields from RenderState will trigger updates.
+    // If you do not watch any fields then your panel will never render since the panel context will assume you do not want any updates.
+
+    // tell the panel context that we care about any update to the _topic_ field of RenderState
+    context.watch("topics");
+
+    // tell the panel context we want messages for the current frame for topics we've subscribed to
+    // This corresponds to the _currentFrame_ field of render state.
+    context.watch("currentFrame");
+
+    // subscribe to some topics, you could do this within other effects, based on input fields, etc
+    // Once you subscribe to topics, currentFrame will contain message events from those topics (assuming there are messages).
+    context.subscribe([{ topic: "/some/topic" }]);
+  }, [context]);
+
+  // invoke the done callback once the render is complete
+  useEffect(() => {
+    renderDone?.();
+  }, [renderDone]);
+
+  return (
+    <div style={{ padding: "1rem" }}>
+      <h2>Welcome to your new extension panel!</h2>
+      <p>
+        Check the{" "}
+        <a href="https://foxglove.dev/docs/studio/extensions/getting-started">documentation</a> for
+        more details on building extension panels for Foxglove Studio.
+      </p>
+      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", rowGap: "0.2rem" }}>
+        <b style={{ borderBottom: "1px solid" }}>Topic</b>
+        <b style={{ borderBottom: "1px solid" }}>Datatype</b>
+        {(topics ?? []).map((topic) => (
+          <>
+            <div key={topic.name}>{topic.name}</div>
+            <div key={topic.datatype}>{topic.datatype}</div>
+          </>
+        ))}
+      </div>
+      <div>{messages?.length}</div>
+    </div>
+  );
+}
+
+export function initExamplePanel(context: PanelExtensionContext): () => void {
+  ReactDOM.render(<ExamplePanel context={context} />, context.panelElement);
+
+  // Return a function to run when the panel is removed
+  return () => {
+    ReactDOM.unmountComponentAtNode(context.panelElement);
+  };
+}
diff --git a/aos/analysis/foxglove_extension/src/index.ts b/aos/analysis/foxglove_extension/src/index.ts
new file mode 100644
index 0000000..63b17eb
--- /dev/null
+++ b/aos/analysis/foxglove_extension/src/index.ts
@@ -0,0 +1,6 @@
+import { ExtensionContext } from "@foxglove/studio";
+import { initExamplePanel } from "./ExamplePanel";
+
+export function activate(extensionContext: ExtensionContext): void {
+  extensionContext.registerPanel({ name: "example-panel", initPanel: initExamplePanel });
+}
diff --git a/aos/analysis/foxglove_extension/tsconfig.json b/aos/analysis/foxglove_extension/tsconfig.json
new file mode 100644
index 0000000..73995c3
--- /dev/null
+++ b/aos/analysis/foxglove_extension/tsconfig.json
@@ -0,0 +1,26 @@
+{
+  "extends": "create-foxglove-extension/tsconfig/tsconfig.json",
+
+  "include": ["./src/**/*"],
+  "compilerOptions": {
+    "rootDir": "./src",
+    "outDir": "./dist",
+    "lib": ["dom", "es2022"],
+
+    // These two settings prevent typescript from emitting .d.ts files we don't need in
+    // the compiled extension.
+    "composite": false,
+    "declaration": false,
+
+    // Additional TypeScript error reporting checks are enabled by default to improve code quality.
+    // Enable/disable these checks as necessary to suit your coding preferences or work with
+    // existing code
+    "noFallthroughCasesInSwitch": true,
+    "noImplicitAny": true,
+    "noImplicitReturns": true,
+    "noUncheckedIndexedAccess": true,
+    "noUnusedLocals": true,
+    "noUnusedParameters": true,
+    "forceConsistentCasingInFileNames": true
+  }
+}
diff --git a/aos/analysis/in_process_plotter.cc b/aos/analysis/in_process_plotter.cc
index 88591b3..dcb60b7 100644
--- a/aos/analysis/in_process_plotter.cc
+++ b/aos/analysis/in_process_plotter.cc
@@ -1,5 +1,12 @@
 #include "aos/analysis/in_process_plotter.h"
 
+#include <algorithm>
+#include <ostream>
+
+#include "flatbuffers/flatbuffer_builder.h"
+#include "flatbuffers/vector.h"
+#include "glog/logging.h"
+
 #include "aos/configuration.h"
 
 namespace aos::analysis {
diff --git a/aos/analysis/in_process_plotter.h b/aos/analysis/in_process_plotter.h
index 0d00deb..8c00096 100644
--- a/aos/analysis/in_process_plotter.h
+++ b/aos/analysis/in_process_plotter.h
@@ -1,10 +1,21 @@
 #ifndef AOS_ANALYSIS_IN_PROCESS_PLOTTER_H_
 #define AOS_ANALYSIS_IN_PROCESS_PLOTTER_H_
 
+#include <stddef.h>
+
+#include <memory>
+#include <string>
+#include <string_view>
 #include <vector>
 
+#include "flatbuffers/buffer.h"
+#include "flatbuffers/string.h"
+
 #include "aos/analysis/plot_data_generated.h"
+#include "aos/configuration_generated.h"
+#include "aos/events/event_loop.h"
 #include "aos/events/simulated_event_loop.h"
+#include "aos/flatbuffers.h"
 #include "aos/network/web_proxy.h"
 
 namespace aos::analysis {
diff --git a/aos/analysis/in_process_plotter_demo.cc b/aos/analysis/in_process_plotter_demo.cc
index 6141d6a..5b92ab7 100644
--- a/aos/analysis/in_process_plotter_demo.cc
+++ b/aos/analysis/in_process_plotter_demo.cc
@@ -1,3 +1,7 @@
+#include <algorithm>
+#include <cmath>
+#include <vector>
+
 #include "aos/analysis/in_process_plotter.h"
 #include "aos/init.h"
 
diff --git a/aos/analysis/local_foxglove.cc b/aos/analysis/local_foxglove.cc
index ade56a5..b07a628 100644
--- a/aos/analysis/local_foxglove.cc
+++ b/aos/analysis/local_foxglove.cc
@@ -1,8 +1,11 @@
-#include "glog/logging.h"
+#include <memory>
+
+#include "gflags/gflags.h"
 
 #include "aos/init.h"
 #include "aos/seasocks/seasocks_logger.h"
 #include "internal/Embedded.h"
+#include "seasocks/Logger.h"
 #include "seasocks/Server.h"
 
 DEFINE_string(data_path, "external/foxglove_studio",
diff --git a/aos/analysis/py_log_reader.cc b/aos/analysis/py_log_reader.cc
index 4a97a0f..340140c 100644
--- a/aos/analysis/py_log_reader.cc
+++ b/aos/analysis/py_log_reader.cc
@@ -16,16 +16,29 @@
 #define PY_SSIZE_T_CLEAN
 // Note that Python.h needs to be included before anything else.
 #include <Python.h>
+#include <stddef.h>
+#include <stdint.h>
 
+#include <algorithm>
 #include <cerrno>
+#include <chrono>
 #include <memory>
+#include <string>
+#include <vector>
+
+#include "absl/types/span.h"
+#include "glog/logging.h"
 
 #include "aos/configuration.h"
+#include "aos/events/context.h"
+#include "aos/events/event_loop.h"
 #include "aos/events/logging/log_reader.h"
 #include "aos/events/simulated_event_loop.h"
 #include "aos/flatbuffer_merge.h"
+#include "aos/flatbuffers.h"
 #include "aos/init.h"
 #include "aos/json_to_flatbuffer.h"
+#include "aos/time/time.h"
 
 namespace aos::analysis {
 namespace {
diff --git a/aos/aos_cli_utils.cc b/aos/aos_cli_utils.cc
index bd54e38..9a2c738 100644
--- a/aos/aos_cli_utils.cc
+++ b/aos/aos_cli_utils.cc
@@ -5,7 +5,12 @@
 #include <unistd.h>
 
 #include <chrono>
+#include <iomanip>
 #include <iostream>
+#include <set>
+#include <string>
+#include <string_view>
+#include <utility>
 
 #include "aos/configuration.h"
 #include "aos/events/shm_event_loop.h"
@@ -29,6 +34,10 @@
             "If true, print out the channels for all nodes, not just the "
             "channels which are visible on this node.");
 
+DEFINE_bool(
+    canonical, false,
+    "If true, print out the canonical channel names instead of the aliases.");
+
 namespace aos {
 namespace {
 
@@ -108,20 +117,62 @@
     }
 
     if (channel_name.empty() && message_type.empty()) {
+      // Just print all the channels (or the ones that pass through the filter).
+      // Sort them before doing so.
       std::cout << "Channels:\n";
+      std::set<std::pair<std::string, std::string>> channels_to_print;
       for (const aos::Channel *channel : *channels) {
         if (FLAGS_all || channel_filter(channel)) {
-          std::cout << channel->name()->c_str() << ' '
-                    << channel->type()->c_str() << '\n';
+          if (FLAGS_canonical) {
+            channels_to_print.emplace(channel->name()->c_str(),
+                                      channel->type()->c_str());
+          } else {
+            std::set<std::string> aliases = configuration::GetChannelAliases(
+                event_loop->configuration(), channel->name()->string_view(),
+                channel->type()->string_view(), "", event_loop->node());
+            CHECK_GT(aliases.size(), 0u);
+            if (aliases.size() == 1) {
+              // There were no aliases. Just print the canonical name.
+              channels_to_print.emplace(channel->name()->str(),
+                                        channel->type()->str());
+            } else {
+              // Assume that the shortest alias (excluding the input name) is
+              // the base alias, and use that.
+              // TODO(Sanjay): Consider having GetChannelAliases return a
+              // hierarchical list instead.
+              CHECK_EQ(aliases.erase(channel->name()->str()), 1u);
+              auto it = aliases.begin();
+              std::string_view shortest_alias = *it;
+              while (it != aliases.end()) {
+                if (shortest_alias.size() > it->size()) {
+                  shortest_alias = *it;
+                }
+                ++it;
+              }
+              channels_to_print.emplace(std::string(shortest_alias),
+                                        channel->type()->c_str());
+            }
+          }
         }
       }
+      for (const auto &[name, type] : channels_to_print) {
+        std::cout << name << ' ' << type << '\n';
+      }
       return true;
     }
 
     std::vector<const aos::Channel *> found_channels_now;
     bool found_exact = false;
     for (const aos::Channel *channel : *channels) {
-      if (channel->name()->c_str() != channel_name) {
+      const std::set<std::string> aliases =
+          aos::configuration::GetChannelAliases(
+              event_loop->configuration(), channel->name()->string_view(),
+              channel->type()->string_view(), "", event_loop->node());
+      if (auto it = std::find_if(aliases.begin(), aliases.end(),
+                                 [channel_name](const std::string &alias) {
+                                   return alias == channel_name;
+                                 });
+          it == aliases.end()) {
         continue;
       }
 
@@ -186,27 +237,33 @@
   if (!unique_match && (editing_message || editing_channel)) {
     for (const aos::Channel *channel : *config_msg->channels()) {
       if (FLAGS_all || channel_filter(channel)) {
+        const std::set<std::string> aliases =
+            aos::configuration::GetChannelAliases(
+                config_msg, channel->name()->string_view(),
+                channel->type()->string_view(), "", event_loop->node());
         // Suggest only message types if the message type argument is being
         // entered.
         if (editing_message) {
-          // Then, filter for only channel names that match exactly and types
-          // that begin with message_type.
-          if (channel->name()->string_view() == channel_name &&
+          // Then, filter for channel names that exactly match one of the
+          // aliases and types that begin with message_type.
+          if (aliases.contains(std::string(channel_name)) &&
               channel->type()->string_view().find(message_type) == 0) {
             std::cout << '\'' << channel->type()->c_str() << "' ";
           }
-        } else if (channel->name()->string_view().find(channel_name) == 0) {
-          // If the message type empty, then return full autocomplete.
+        } else if (auto it =
+                       std::find_if(aliases.begin(), aliases.end(),
+                                    [channel_name](const std::string &alias) {
+                                      return alias.find(channel_name) == 0;
+                                    });
+                   it != aliases.end()) {
+          // If the message type is empty, then return full autocomplete.
           // Otherwise, since the message type is poulated yet not being edited,
           // the user must be editing the channel name alone, in which case only
           // suggest channel names, not pairs.
-          // If _split_complete flag is set then dont return
-          // pairs of values
           if (!FLAGS__zsh_compatability && message_type.empty()) {
-            std::cout << '\'' << channel->name()->c_str() << ' '
-                      << channel->type()->c_str() << "' ";
+            std::cout << '\'' << *it << ' ' << channel->type()->c_str() << "' ";
           } else {
-            std::cout << '\'' << channel->name()->c_str() << "' ";
+            std::cout << '\'' << *it << "' ";
           }
         }
       }
diff --git a/aos/aos_jitter.cc b/aos/aos_jitter.cc
index 3ac35e8..5f23935 100644
--- a/aos/aos_jitter.cc
+++ b/aos/aos_jitter.cc
@@ -1,6 +1,7 @@
 #include <unistd.h>
 
-#include <iostream>
+#include <iomanip>
+#include <iostream>  // IWYU pragma: keep
 
 #include "gflags/gflags.h"
 
diff --git a/aos/containers/error_list.h b/aos/containers/error_list.h
index 42400fb..7ceb1fe 100644
--- a/aos/containers/error_list.h
+++ b/aos/containers/error_list.h
@@ -1,9 +1,13 @@
 #ifndef AOS_CONTAINERS_ERROR_LIST_H_
 #define AOS_CONTAINERS_ERROR_LIST_H_
 
-#include <iostream>
+#include <stddef.h>
 
-#include "flatbuffers/flatbuffers.h"
+#include <algorithm>
+
+#include "flatbuffers/buffer.h"
+#include "flatbuffers/flatbuffer_builder.h"
+#include "flatbuffers/vector.h"
 
 #include "aos/containers/sized_array.h"
 
diff --git a/aos/containers/error_list_test.cc b/aos/containers/error_list_test.cc
index 94eabf9..98d7257 100644
--- a/aos/containers/error_list_test.cc
+++ b/aos/containers/error_list_test.cc
@@ -1,5 +1,9 @@
 #include "aos/containers/error_list.h"
 
+#include <stdint.h>
+
+#include <memory>
+
 #include "gtest/gtest.h"
 
 #include "aos/json_to_flatbuffer_generated.h"
diff --git a/aos/containers/inlined_vector.h b/aos/containers/inlined_vector.h
index abd375d..5cf33a4 100644
--- a/aos/containers/inlined_vector.h
+++ b/aos/containers/inlined_vector.h
@@ -1,6 +1,8 @@
 #ifndef AOS_CONTAINERS_INLINED_VECTOR_H_
 #define AOS_CONTAINERS_INLINED_VECTOR_H_
 
+#include <stddef.h>
+
 #include <vector>
 
 #include "absl/container/inlined_vector.h"
diff --git a/aos/containers/inlined_vector_test.cc b/aos/containers/inlined_vector_test.cc
index c9f2dd2..b8aab6b 100644
--- a/aos/containers/inlined_vector_test.cc
+++ b/aos/containers/inlined_vector_test.cc
@@ -1,5 +1,6 @@
 #include "aos/containers/inlined_vector.h"
 
+#include "gflags/gflags.h"
 #include "gtest/gtest.h"
 
 #include "aos/realtime.h"
diff --git a/aos/containers/priority_queue.h b/aos/containers/priority_queue.h
index d4d0196..90861dc 100644
--- a/aos/containers/priority_queue.h
+++ b/aos/containers/priority_queue.h
@@ -1,8 +1,9 @@
 #ifndef AOS_CONTAINERS_PRIORITY_QUEUE_H_
 #define AOS_CONTAINERS_PRIORITY_QUEUE_H_
 
+#include <stddef.h>
+
 #include <array>
-#include <iterator>
 #include <optional>
 
 namespace aos {
diff --git a/aos/containers/priority_queue_test.cc b/aos/containers/priority_queue_test.cc
index f27a206..5e75d1e 100644
--- a/aos/containers/priority_queue_test.cc
+++ b/aos/containers/priority_queue_test.cc
@@ -1,5 +1,8 @@
 #include "aos/containers/priority_queue.h"
 
+#include <functional>
+#include <vector>
+
 #include "gtest/gtest.h"
 
 namespace aos::testing {
diff --git a/aos/containers/resizeable_buffer.h b/aos/containers/resizeable_buffer.h
index 9f9967f..484d93e 100644
--- a/aos/containers/resizeable_buffer.h
+++ b/aos/containers/resizeable_buffer.h
@@ -1,6 +1,10 @@
 #ifndef AOS_CONTAINERS_RESIZEABLE_BUFFER_H_
 #define AOS_CONTAINERS_RESIZEABLE_BUFFER_H_
 
+#include <stdint.h>
+#include <string.h>
+
+#include <algorithm>
 #include <cstdlib>
 #include <memory>
 
diff --git a/aos/containers/resizeable_buffer_test.cc b/aos/containers/resizeable_buffer_test.cc
index 2665ba8..6e3beb8 100644
--- a/aos/containers/resizeable_buffer_test.cc
+++ b/aos/containers/resizeable_buffer_test.cc
@@ -1,6 +1,7 @@
 #include "aos/containers/resizeable_buffer.h"
 
 #include <numeric>
+#include <vector>
 
 #include "absl/types/span.h"
 #include "gmock/gmock.h"
diff --git a/aos/containers/ring_buffer.h b/aos/containers/ring_buffer.h
index 7d0bb7e..083d7cf 100644
--- a/aos/containers/ring_buffer.h
+++ b/aos/containers/ring_buffer.h
@@ -3,6 +3,9 @@
 
 #include <array>
 #include <cstddef>
+#include <iterator>
+#include <new>
+#include <type_traits>
 
 namespace aos {
 
diff --git a/aos/containers/ring_buffer_test.cc b/aos/containers/ring_buffer_test.cc
index c06ef0e..b7b0f17 100644
--- a/aos/containers/ring_buffer_test.cc
+++ b/aos/containers/ring_buffer_test.cc
@@ -1,5 +1,8 @@
 #include "aos/containers/ring_buffer.h"
 
+#include <memory>
+#include <ostream>
+
 #include "glog/logging.h"
 #include "gtest/gtest.h"
 
diff --git a/aos/containers/sized_array.h b/aos/containers/sized_array.h
index 8a8d2de..4febf55 100644
--- a/aos/containers/sized_array.h
+++ b/aos/containers/sized_array.h
@@ -1,6 +1,8 @@
 #ifndef AOS_CONTAINERS_SIZED_ARRAY_H_
 #define AOS_CONTAINERS_SIZED_ARRAY_H_
 
+#include <cstddef>
+
 #include "absl/container/inlined_vector.h"
 
 namespace aos {
diff --git a/aos/containers/sized_array_test.cc b/aos/containers/sized_array_test.cc
index 645d669..5fc4b38 100644
--- a/aos/containers/sized_array_test.cc
+++ b/aos/containers/sized_array_test.cc
@@ -1,5 +1,8 @@
 #include "aos/containers/sized_array.h"
 
+#include <iterator>
+#include <memory>
+
 #include "gtest/gtest.h"
 
 namespace aos::testing {
diff --git a/aos/events/epoll.cc b/aos/events/epoll.cc
index 8c5c3e1..61c346e 100644
--- a/aos/events/epoll.cc
+++ b/aos/events/epoll.cc
@@ -1,14 +1,20 @@
 #include "aos/events/epoll.h"
 
+#include <errno.h>
 #include <fcntl.h>
 #include <sys/epoll.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
 #include <sys/timerfd.h>
+#include <time.h>
 #include <unistd.h>
 
+#include <algorithm>
 #include <atomic>
 #include <cstring>
+#include <ostream>
+#include <string>
+#include <utility>
 #include <vector>
 
 #include "glog/logging.h"
diff --git a/aos/events/epoll.h b/aos/events/epoll.h
index 526c6a7..80ae721 100644
--- a/aos/events/epoll.h
+++ b/aos/events/epoll.h
@@ -1,13 +1,12 @@
 #ifndef AOS_EVENTS_EPOLL_H_
 #define AOS_EVENTS_EPOLL_H_
 
-#include <fcntl.h>
+#include <stdint.h>
 #include <sys/epoll.h>
-#include <sys/timerfd.h>
-#include <unistd.h>
 
 #include <atomic>
 #include <functional>
+#include <memory>
 #include <vector>
 
 #include "aos/time/time.h"
diff --git a/aos/events/event_loop_event.h b/aos/events/event_loop_event.h
index 588b851..4d1ff07 100644
--- a/aos/events/event_loop_event.h
+++ b/aos/events/event_loop_event.h
@@ -1,6 +1,10 @@
 #ifndef AOS_EVENTS_EVENT_LOOP_EVENT_H
 #define AOS_EVENTS_EVENT_LOOP_EVENT_H
 
+#include <stddef.h>
+
+#include <chrono>
+
 #include "glog/logging.h"
 
 #include "aos/time/time.h"
diff --git a/aos/events/logging/boot_timestamp.h b/aos/events/logging/boot_timestamp.h
index e9c7877..dc5967c 100644
--- a/aos/events/logging/boot_timestamp.h
+++ b/aos/events/logging/boot_timestamp.h
@@ -1,7 +1,13 @@
 #ifndef AOS_EVENTS_LOGGING_BOOT_TIMESTAMP_H_
 #define AOS_EVENTS_LOGGING_BOOT_TIMESTAMP_H_
 
+#include <stddef.h>
+#include <stdint.h>
+
+#include <chrono>
+#include <compare>
 #include <iostream>
+#include <limits>
 
 #include "glog/logging.h"
 
diff --git a/aos/events/logging/file_operations.cc b/aos/events/logging/file_operations.cc
index 04e695e..d54c8b6 100644
--- a/aos/events/logging/file_operations.cc
+++ b/aos/events/logging/file_operations.cc
@@ -1,5 +1,8 @@
 #include "aos/events/logging/file_operations.h"
 
+#include <algorithm>
+#include <ostream>
+
 #include "absl/strings/match.h"
 #include "glog/logging.h"
 
diff --git a/aos/events/logging/file_operations.h b/aos/events/logging/file_operations.h
index 0c2133d..5f87ca5 100644
--- a/aos/events/logging/file_operations.h
+++ b/aos/events/logging/file_operations.h
@@ -1,8 +1,11 @@
 #ifndef AOS_EVENTS_LOGGING_FILE_OPERATIONS_H_
 #define AOS_EVENTS_LOGGING_FILE_OPERATIONS_H_
 
+#include <stddef.h>
+
 #include <filesystem>
 #include <string>
+#include <string_view>
 #include <vector>
 
 namespace aos::logger::internal {
diff --git a/aos/events/shm_event_loop.cc b/aos/events/shm_event_loop.cc
index 9d010b7..e15c014 100644
--- a/aos/events/shm_event_loop.cc
+++ b/aos/events/shm_event_loop.cc
@@ -1035,6 +1035,7 @@
 
   if (watchers_.size() > 0) {
     signalfd_.reset(new ipc_lib::SignalFd({ipc_lib::kWakeupSignal}));
+    signalfd_->LeaveSignalBlocked(ipc_lib::kWakeupSignal);
 
     epoll_.OnReadable(signalfd_->fd(), [this]() { HandleEvent(); });
   }
diff --git a/aos/events/simulated_event_loop.cc b/aos/events/simulated_event_loop.cc
index d698b7d..1b193db 100644
--- a/aos/events/simulated_event_loop.cc
+++ b/aos/events/simulated_event_loop.cc
@@ -1571,6 +1571,21 @@
   }
 }
 
+bool SimulatedEventLoopFactory::RunUntil(realtime_clock::time_point now,
+                                         const aos::Node *node) {
+  bool ran_until_time = scheduler_scheduler_.RunUntil(
+      now, &GetNodeEventLoopFactory(node)->scheduler_, [this, &node](void) {
+        return GetNodeEventLoopFactory(node)->realtime_offset();
+      });
+  for (std::unique_ptr<NodeEventLoopFactory> &node : node_factories_) {
+    if (node) {
+      for (SimulatedEventLoop *loop : node->event_loops_) {
+        CHECK(!loop->is_running());
+      }
+    }
+  }
+  return ran_until_time;
+}
 void SimulatedEventLoopFactory::Run() {
   // This sets running to true too.
   scheduler_scheduler_.Run();
diff --git a/aos/events/simulated_event_loop.h b/aos/events/simulated_event_loop.h
index e976544..5fad005 100644
--- a/aos/events/simulated_event_loop.h
+++ b/aos/events/simulated_event_loop.h
@@ -91,6 +91,10 @@
   void Run();
   // Executes the event loops for a duration.
   void RunFor(distributed_clock::duration duration);
+  // Executes the event loops until a time.
+  // Returns true if there are still events remaining.
+  bool RunUntil(aos::realtime_clock::time_point time,
+                const aos::Node *node = nullptr);
 
   // Stops executing all event loops.  Meant to be called from within an event
   // loop handler.
@@ -209,6 +213,8 @@
         realtime_now.time_since_epoch() - monotonic_now.time_since_epoch();
   }
 
+  inline std::chrono::nanoseconds realtime_offset() { return realtime_offset_; }
+
   // Returns the current time on both clocks.
   inline monotonic_clock::time_point monotonic_now() const;
   inline realtime_clock::time_point realtime_now() const;
diff --git a/aos/flatbuffers/base.cc b/aos/flatbuffers/base.cc
index 8ad3b98..97b3b36 100644
--- a/aos/flatbuffers/base.cc
+++ b/aos/flatbuffers/base.cc
@@ -1,4 +1,9 @@
 #include "aos/flatbuffers/base.h"
+
+#include <string.h>
+
+#include <iomanip>
+
 namespace aos::fbs {
 
 namespace {
diff --git a/aos/flatbuffers/base.h b/aos/flatbuffers/base.h
index 387dbc3..ff81c9a 100644
--- a/aos/flatbuffers/base.h
+++ b/aos/flatbuffers/base.h
@@ -1,12 +1,19 @@
 #ifndef AOS_FLATBUFFERS_BASE_H_
 #define AOS_FLATBUFFERS_BASE_H_
-#include <iomanip>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <cstring>
 #include <memory>
 #include <optional>
+#include <ostream>
 #include <span>
+#include <utility>
+#include <vector>
 
 #include "flatbuffers/base.h"
 #include "glog/logging.h"
+
 namespace aos::fbs {
 using ::flatbuffers::soffset_t;
 using ::flatbuffers::uoffset_t;
diff --git a/aos/flatbuffers/base_test.cc b/aos/flatbuffers/base_test.cc
index 522882d..f0eaf04 100644
--- a/aos/flatbuffers/base_test.cc
+++ b/aos/flatbuffers/base_test.cc
@@ -1,5 +1,9 @@
 #include "aos/flatbuffers/base.h"
 
+#include <stddef.h>
+
+#include <algorithm>
+
 #include "gtest/gtest.h"
 
 namespace aos::fbs::testing {
diff --git a/aos/flatbuffers/generate.cc b/aos/flatbuffers/generate.cc
index 030de35..9a2e5fd 100644
--- a/aos/flatbuffers/generate.cc
+++ b/aos/flatbuffers/generate.cc
@@ -1,4 +1,7 @@
+#include <stdlib.h>
+
 #include "flatbuffers/reflection_generated.h"
+#include "gflags/gflags.h"
 
 #include "aos/flatbuffers.h"
 #include "aos/flatbuffers/static_flatbuffers.h"
diff --git a/aos/flatbuffers/static_flatbuffers.cc b/aos/flatbuffers/static_flatbuffers.cc
index c1b617f..c2e0454 100644
--- a/aos/flatbuffers/static_flatbuffers.cc
+++ b/aos/flatbuffers/static_flatbuffers.cc
@@ -1,13 +1,28 @@
 #include "aos/flatbuffers/static_flatbuffers.h"
 
+#include <stddef.h>
+#include <stdint.h>
+
+#include <algorithm>
+#include <map>
+#include <optional>
+#include <ostream>
+#include <utility>
+#include <vector>
+
+#include "absl/strings/numbers.h"
 #include "absl/strings/str_cat.h"
 #include "absl/strings/str_format.h"
 #include "absl/strings/str_join.h"
 #include "absl/strings/str_replace.h"
+#include "flatbuffers/base.h"
+#include "flatbuffers/string.h"
+#include "flatbuffers/vector.h"
 #include "glog/logging.h"
 
-#include "aos/flatbuffers/static_table.h"
+#include "aos/flatbuffers/base.h"
 #include "aos/json_to_flatbuffer.h"
+
 namespace aos::fbs {
 namespace {
 // Represents a given field within a type with all of the data that we actually
diff --git a/aos/flatbuffers/static_flatbuffers.h b/aos/flatbuffers/static_flatbuffers.h
index 6a5f800..11e21ae 100644
--- a/aos/flatbuffers/static_flatbuffers.h
+++ b/aos/flatbuffers/static_flatbuffers.h
@@ -1,12 +1,11 @@
 #ifndef AOS_FLATBUFFERS_STATIC_FLATBUFFERS_H_
 #define AOS_FLATBUFFERS_STATIC_FLATBUFFERS_H_
-#include <map>
-#include <set>
+#include <set>  // IWYU pragma: keep
 #include <string>
 #include <string_view>
-#include <vector>
 
-#include "flatbuffers/reflection_generated.h"
+#include "flatbuffers/reflection_generated.h"  // IWYU pragma: keep
+
 namespace aos::fbs {
 
 // Raw C++ code needed to represent a single flatbuffer table.
diff --git a/aos/flatbuffers/static_flatbuffers_fuzz_test.cc b/aos/flatbuffers/static_flatbuffers_fuzz_test.cc
index 755dd57..ae6fc71 100644
--- a/aos/flatbuffers/static_flatbuffers_fuzz_test.cc
+++ b/aos/flatbuffers/static_flatbuffers_fuzz_test.cc
@@ -1,17 +1,15 @@
-#include "absl/strings/str_format.h"
+#include <functional>
+#include <span>
+#include <string>
+#include <string_view>
+#include <vector>
+
 #include "absl/strings/str_join.h"
-#include "gmock/gmock.h"
 #include "gtest/gtest.h"
 
-#include "aos/flatbuffers.h"
 #include "aos/flatbuffers/builder.h"
-#include "aos/flatbuffers/static_flatbuffers.h"
-#include "aos/flatbuffers/test_dir/type_coverage_static.h"
 #include "aos/flatbuffers/test_static.h"
 #include "aos/json_to_flatbuffer.h"
-#include "aos/testing/path.h"
-#include "aos/testing/tmpdir.h"
-#include "aos/util/file.h"
 
 namespace aos::fbs::testing {
 
diff --git a/aos/flatbuffers/static_flatbuffers_test.cc b/aos/flatbuffers/static_flatbuffers_test.cc
index 26dfc50..a971d82 100644
--- a/aos/flatbuffers/static_flatbuffers_test.cc
+++ b/aos/flatbuffers/static_flatbuffers_test.cc
@@ -1,17 +1,42 @@
 #include "aos/flatbuffers/static_flatbuffers.h"
 
+#include <stdint.h>
+#include <string.h>
+
+#include <algorithm>
+#include <iostream>
+#include <iterator>
+#include <memory>
+#include <span>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
 #include "absl/strings/str_format.h"
 #include "absl/strings/str_join.h"
+#include "absl/types/span.h"
 #include "external/com_github_google_flatbuffers/src/annotated_binary_text_gen.h"
 #include "external/com_github_google_flatbuffers/src/binary_annotator.h"
-#include "gmock/gmock.h"
+#include "flatbuffers/base.h"
+#include "flatbuffers/buffer.h"
+#include "flatbuffers/flatbuffer_builder.h"
+#include "flatbuffers/stl_emulation.h"
+#include "flatbuffers/string.h"
+#include "flatbuffers/vector.h"
+#include "glog/logging.h"
 #include "gtest/gtest.h"
 
 #include "aos/flatbuffers.h"
+#include "aos/flatbuffers/base.h"
 #include "aos/flatbuffers/builder.h"
 #include "aos/flatbuffers/interesting_schemas.h"
+#include "aos/flatbuffers/static_vector.h"
+#include "aos/flatbuffers/test_dir/include_generated.h"
 #include "aos/flatbuffers/test_dir/include_reflection_static.h"
+#include "aos/flatbuffers/test_dir/include_static.h"
+#include "aos/flatbuffers/test_dir/type_coverage_generated.h"
 #include "aos/flatbuffers/test_dir/type_coverage_static.h"
+#include "aos/flatbuffers/test_generated.h"
 #include "aos/flatbuffers/test_schema.h"
 #include "aos/flatbuffers/test_static.h"
 #include "aos/json_to_flatbuffer.h"
diff --git a/aos/ipc_lib/aos_sync.cc b/aos/ipc_lib/aos_sync.cc
index b1a9fb0..78c6b2c 100644
--- a/aos/ipc_lib/aos_sync.cc
+++ b/aos/ipc_lib/aos_sync.cc
@@ -7,18 +7,16 @@
 
 #include <linux/futex.h>
 #include <pthread.h>
-#include <sched.h>
+#include <signal.h>
+#include <stdio.h>
 #include <sys/syscall.h>
-#include <sys/types.h>
 #include <unistd.h>
 
 #include <cassert>
 #include <cerrno>
 #include <cinttypes>
 #include <climits>
-#include <cstddef>
-#include <cstdint>
-#include <cstring>
+#include <ostream>
 
 #include "aos/ipc_lib/shm_observers.h"
 
@@ -26,9 +24,6 @@
 #include <sanitizer/tsan_interface_atomic.h>
 #endif
 
-#include <algorithm>
-#include <type_traits>
-
 #include "absl/base/call_once.h"
 #include "glog/logging.h"
 
diff --git a/aos/ipc_lib/aos_sync.h b/aos/ipc_lib/aos_sync.h
index 157c1b2..0cdab30 100644
--- a/aos/ipc_lib/aos_sync.h
+++ b/aos/ipc_lib/aos_sync.h
@@ -1,11 +1,8 @@
 #ifndef AOS_IPC_LIB_SYNC_H_
 #define AOS_IPC_LIB_SYNC_H_
 
-#include <signal.h>
-#include <stdbool.h>
 #include <stddef.h>
 #include <stdint.h>
-#include <stdlib.h>
 
 #ifdef __cplusplus
 extern "C" {
diff --git a/aos/ipc_lib/core_lib.c b/aos/ipc_lib/core_lib.c
index bfe80c1..6f9aad2 100644
--- a/aos/ipc_lib/core_lib.c
+++ b/aos/ipc_lib/core_lib.c
@@ -4,6 +4,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 
+#include "aos/ipc_lib/aos_sync.h"
 #include "aos/ipc_lib/shared_mem_types.h"
 
 static uint8_t aos_8max(uint8_t l, uint8_t r) { return (l > r) ? l : r; }
diff --git a/aos/ipc_lib/core_lib.h b/aos/ipc_lib/core_lib.h
index d62f602..a3a5ba8 100644
--- a/aos/ipc_lib/core_lib.h
+++ b/aos/ipc_lib/core_lib.h
@@ -1,10 +1,9 @@
 #ifndef _AOS_CORE_LIB_H_
 #define _AOS_CORE_LIB_H_
 
+#include <stddef.h>
 #include <stdint.h>
 
-#include "aos/ipc_lib/aos_sync.h"
-
 #ifdef __cplusplus
 extern "C" {
 #endif  // __cplusplus
diff --git a/aos/ipc_lib/event.cc b/aos/ipc_lib/event.cc
index 6b58e33..fd5bcaf 100644
--- a/aos/ipc_lib/event.cc
+++ b/aos/ipc_lib/event.cc
@@ -1,6 +1,10 @@
 #include "aos/ipc_lib/event.h"
 
+#include <time.h>
+
 #include <chrono>
+#include <ostream>
+#include <ratio>
 
 #include "glog/logging.h"
 
diff --git a/aos/ipc_lib/event_test.cc b/aos/ipc_lib/event_test.cc
index eda9156..5a8e644 100644
--- a/aos/ipc_lib/event_test.cc
+++ b/aos/ipc_lib/event_test.cc
@@ -1,6 +1,7 @@
 #include "aos/ipc_lib/event.h"
 
 #include <chrono>
+#include <memory>
 #include <thread>
 
 #include "gtest/gtest.h"
diff --git a/aos/ipc_lib/eventfd_latency.cc b/aos/ipc_lib/eventfd_latency.cc
index efd326e..4a5616f 100644
--- a/aos/ipc_lib/eventfd_latency.cc
+++ b/aos/ipc_lib/eventfd_latency.cc
@@ -1,18 +1,21 @@
+#include <inttypes.h>
+#include <string.h>
 #include <sys/eventfd.h>
-#include <sys/stat.h>
-#include <sys/types.h>
+#include <unistd.h>
 
+#include <algorithm>
 #include <chrono>
+#include <compare>
 #include <random>
+#include <ratio>
 #include <thread>
 
 #include "gflags/gflags.h"
+#include "glog/logging.h"
 
 #include "aos/events/epoll.h"
-#include "aos/init.h"
 #include "aos/ipc_lib/latency_lib.h"
 #include "aos/logging/implementations.h"
-#include "aos/logging/logging.h"
 #include "aos/realtime.h"
 #include "aos/time/time.h"
 
diff --git a/aos/ipc_lib/futex_latency.cc b/aos/ipc_lib/futex_latency.cc
index 80ba711..eee015e 100644
--- a/aos/ipc_lib/futex_latency.cc
+++ b/aos/ipc_lib/futex_latency.cc
@@ -1,18 +1,19 @@
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
+#include <inttypes.h>
+#include <signal.h>
 
+#include <algorithm>
 #include <chrono>
+#include <compare>
 #include <random>
+#include <ratio>
 #include <thread>
 
 #include "gflags/gflags.h"
+#include "glog/logging.h"
 
 #include "aos/condition.h"
-#include "aos/init.h"
 #include "aos/ipc_lib/latency_lib.h"
 #include "aos/logging/implementations.h"
-#include "aos/logging/logging.h"
 #include "aos/mutex/mutex.h"
 #include "aos/realtime.h"
 #include "aos/time/time.h"
diff --git a/aos/ipc_lib/index.h b/aos/ipc_lib/index.h
index 75f1e9b..c4cc64a 100644
--- a/aos/ipc_lib/index.h
+++ b/aos/ipc_lib/index.h
@@ -2,10 +2,8 @@
 #define AOS_IPC_LIB_INDEX_H_
 
 #include <stdint.h>
-#include <sys/types.h>
 
-#include <atomic>
-#include <string>
+#include <limits>
 
 #include "glog/logging.h"
 
@@ -25,10 +23,6 @@
 
 namespace aos::ipc_lib {
 
-struct AtomicQueueIndex;
-class AtomicIndex;
-class Index;
-
 namespace testing {
 class QueueIndexTest;
 }  // namespace testing
diff --git a/aos/ipc_lib/index_test.cc b/aos/ipc_lib/index_test.cc
index 8e0da6d..334696e 100644
--- a/aos/ipc_lib/index_test.cc
+++ b/aos/ipc_lib/index_test.cc
@@ -1,5 +1,7 @@
 #include "aos/ipc_lib/index.h"
 
+#include <ostream>
+
 #include "glog/logging.h"
 #include "gtest/gtest.h"
 
diff --git a/aos/ipc_lib/ipc_comparison.cc b/aos/ipc_lib/ipc_comparison.cc
index f15db53..8bb78d7 100644
--- a/aos/ipc_lib/ipc_comparison.cc
+++ b/aos/ipc_lib/ipc_comparison.cc
@@ -1,23 +1,30 @@
+#include <arpa/inet.h>
+#include <errno.h>
 #include <fcntl.h>
+#include <inttypes.h>
 #include <mqueue.h>
 #include <netinet/in.h>
 #include <netinet/tcp.h>
 #include <pthread.h>
 #include <semaphore.h>
+#include <stdio.h>
+#include <string.h>
 #include <sys/eventfd.h>
+#include <sys/ipc.h>
 #include <sys/msg.h>
 #include <sys/sem.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/un.h>
+#include <unistd.h>
 
 #include <atomic>
 #include <chrono>
+#include <compare>
 #include <cstdint>
 #include <memory>
 #include <string>
 #include <thread>
+#include <utility>
 
 #include "gflags/gflags.h"
 
@@ -25,7 +32,6 @@
 #include "aos/init.h"
 #include "aos/ipc_lib/event.h"
 #include "aos/logging/implementations.h"
-#include "aos/logging/logging.h"
 #include "aos/mutex/mutex.h"
 #include "aos/realtime.h"
 #include "aos/time/time.h"
diff --git a/aos/ipc_lib/latency_lib.cc b/aos/ipc_lib/latency_lib.cc
index 0fcb8de..a31df1d 100644
--- a/aos/ipc_lib/latency_lib.cc
+++ b/aos/ipc_lib/latency_lib.cc
@@ -1,8 +1,9 @@
 #include "aos/ipc_lib/latency_lib.h"
 
+#include <algorithm>
 #include <chrono>
+#include <compare>
 #include <random>
-#include <thread>
 
 #include "aos/logging/logging.h"
 #include "aos/realtime.h"
diff --git a/aos/ipc_lib/latency_lib.h b/aos/ipc_lib/latency_lib.h
index 97bc434..8206f3e 100644
--- a/aos/ipc_lib/latency_lib.h
+++ b/aos/ipc_lib/latency_lib.h
@@ -2,10 +2,8 @@
 #define AOS_IPC_LIB_LATENCY_LIB_H_
 
 #include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <chrono>
+#include <string.h>
+#include <unistd.h>
 
 #include "glog/logging.h"
 
diff --git a/aos/ipc_lib/lockless_queue.cc b/aos/ipc_lib/lockless_queue.cc
index 57a2e9e..ae3a493 100644
--- a/aos/ipc_lib/lockless_queue.cc
+++ b/aos/ipc_lib/lockless_queue.cc
@@ -2,21 +2,25 @@
 
 #include <linux/futex.h>
 #include <pwd.h>
+#include <sched.h>
+#include <string.h>
+#include <sys/syscall.h>
 #include <sys/types.h>
-#include <syscall.h>
 #include <unistd.h>
 
 #include <algorithm>
+#include <chrono>
+#include <compare>
 #include <iomanip>
 #include <iostream>
-#include <sstream>
+#include <string>
+#include <string_view>
 
 #include "absl/strings/escaping.h"
 #include "gflags/gflags.h"
 #include "glog/logging.h"
 
 #include "aos/ipc_lib/lockless_queue_memory.h"
-#include "aos/realtime.h"
 #include "aos/util/compiler_memory_barrier.h"
 
 DEFINE_bool(dump_lockless_queue_data, false,
diff --git a/aos/ipc_lib/lockless_queue.h b/aos/ipc_lib/lockless_queue.h
index 462b2b6..ce067e6 100644
--- a/aos/ipc_lib/lockless_queue.h
+++ b/aos/ipc_lib/lockless_queue.h
@@ -1,14 +1,18 @@
 #ifndef AOS_IPC_LIB_LOCKLESS_QUEUE_H_
 #define AOS_IPC_LIB_LOCKLESS_QUEUE_H_
 
-#include <sys/signalfd.h>
-#include <sys/types.h>
+#include <signal.h>
+#include <stdint.h>
 
-#include <csignal>
+#include <atomic>
+#include <functional>
+#include <iosfwd>
 #include <optional>
+#include <utility>
 #include <vector>
 
 #include "absl/types/span.h"
+#include "glog/logging.h"
 
 #include "aos/events/context.h"
 #include "aos/ipc_lib/aos_sync.h"
diff --git a/aos/ipc_lib/lockless_queue_death_test.cc b/aos/ipc_lib/lockless_queue_death_test.cc
index bc5ebb7..c61c62c 100644
--- a/aos/ipc_lib/lockless_queue_death_test.cc
+++ b/aos/ipc_lib/lockless_queue_death_test.cc
@@ -1,31 +1,25 @@
-#include <dlfcn.h>
-#include <elf.h>
-#include <linux/futex.h>
+#include <stdio.h>
 #include <sys/mman.h>
-#include <sys/procfs.h>
-#include <sys/ptrace.h>
-#include <sys/syscall.h>
-#include <sys/uio.h>
-#include <unistd.h>
-#include <wait.h>
 
 #include <chrono>
 #include <cinttypes>
 #include <functional>
 #include <memory>
-#include <thread>
+#include <optional>
+#include <ostream>
 
-#include "gflags/gflags.h"
 #include "glog/logging.h"
 #include "gtest/gtest.h"
 
-#include "aos/ipc_lib/aos_sync.h"
+#include "aos/events/context.h"
+#include "aos/ipc_lib/index.h"
 #include "aos/ipc_lib/lockless_queue.h"
 #include "aos/ipc_lib/lockless_queue_memory.h"
 #include "aos/ipc_lib/lockless_queue_stepping.h"
-#include "aos/ipc_lib/shm_observers.h"
-#include "aos/realtime.h"
+#include "aos/ipc_lib/robust_ownership_tracker.h"
 #include "aos/testing/test_logging.h"
+#include "aos/time/time.h"
+#include "aos/uuid.h"
 
 namespace aos::ipc_lib::testing {
 
diff --git a/aos/ipc_lib/lockless_queue_memory.h b/aos/ipc_lib/lockless_queue_memory.h
index 70fc8a8..12aec89 100644
--- a/aos/ipc_lib/lockless_queue_memory.h
+++ b/aos/ipc_lib/lockless_queue_memory.h
@@ -1,6 +1,7 @@
 #ifndef AOS_IPC_LIB_LOCKLESS_QUEUE_MEMORY_H_
 #define AOS_IPC_LIB_LOCKLESS_QUEUE_MEMORY_H_
 
+#include <stdint.h>
 #include <sys/types.h>
 
 #include <cstddef>
@@ -8,7 +9,6 @@
 #include "aos/ipc_lib/aos_sync.h"
 #include "aos/ipc_lib/index.h"
 #include "aos/ipc_lib/lockless_queue.h"
-#include "aos/time/time.h"
 
 namespace aos::ipc_lib {
 
diff --git a/aos/ipc_lib/lockless_queue_stepping.cc b/aos/ipc_lib/lockless_queue_stepping.cc
index 40d1631..a7bd233 100644
--- a/aos/ipc_lib/lockless_queue_stepping.cc
+++ b/aos/ipc_lib/lockless_queue_stepping.cc
@@ -1,24 +1,30 @@
 #include "aos/ipc_lib/lockless_queue_stepping.h"
 
-#include <dlfcn.h>
+#include <assert.h>
 #include <elf.h>
-#include <linux/futex.h>
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
 #include <sys/mman.h>
 #include <sys/procfs.h>
 #include <sys/ptrace.h>
 #include <sys/syscall.h>
 #include <sys/uio.h>
+#include <sys/wait.h>
 #include <unistd.h>
-#include <wait.h>
 
-#include <memory>
+#include <atomic>
+#include <new>
+#include <optional>
+#include <ostream>
+#include <string>
 #include <thread>
+#include <utility>
 
 #include "glog/logging.h"
 #include "gtest/gtest.h"
 
 #include "aos/ipc_lib/aos_sync.h"
-#include "aos/ipc_lib/lockless_queue_memory.h"
 #include "aos/ipc_lib/shm_observers.h"
 #include "aos/libc/aos_strsignal.h"
 #include "aos/testing/prevent_exit.h"
diff --git a/aos/ipc_lib/lockless_queue_stepping.h b/aos/ipc_lib/lockless_queue_stepping.h
index 590534f..8be7b44 100644
--- a/aos/ipc_lib/lockless_queue_stepping.h
+++ b/aos/ipc_lib/lockless_queue_stepping.h
@@ -1,11 +1,14 @@
 #ifndef AOS_IPC_LIB_LOCKLESS_QUEUE_STEPPING_H_
 #define AOS_IPC_LIB_LOCKLESS_QUEUE_STEPPING_H_
 
+#include <stdlib.h>
+#include <unistd.h>
+
 #include <cinttypes>
 #include <functional>
+#include <tuple>
 
 #include "aos/ipc_lib/lockless_queue.h"
-#include "aos/ipc_lib/lockless_queue_memory.h"
 
 namespace aos::ipc_lib::testing {
 
diff --git a/aos/ipc_lib/lockless_queue_test.cc b/aos/ipc_lib/lockless_queue_test.cc
index a2c0992..4169c93 100644
--- a/aos/ipc_lib/lockless_queue_test.cc
+++ b/aos/ipc_lib/lockless_queue_test.cc
@@ -1,21 +1,26 @@
 #include "aos/ipc_lib/lockless_queue.h"
 
-#include <sys/mman.h>
-#include <unistd.h>
-#include <wait.h>
+#include <sched.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/signalfd.h>
 
+#include <algorithm>
 #include <chrono>
 #include <cinttypes>
+#include <compare>
 #include <csignal>
-#include <memory>
+#include <new>
+#include <ostream>
 #include <random>
+#include <ratio>
 #include <thread>
+#include <type_traits>
 
 #include "gflags/gflags.h"
 #include "gtest/gtest.h"
 
 #include "aos/events/epoll.h"
-#include "aos/ipc_lib/aos_sync.h"
 #include "aos/ipc_lib/event.h"
 #include "aos/ipc_lib/lockless_queue_memory.h"
 #include "aos/ipc_lib/lockless_queue_stepping.h"
diff --git a/aos/ipc_lib/memory_mapped_queue.cc b/aos/ipc_lib/memory_mapped_queue.cc
index dc457fe..8daf5a1 100644
--- a/aos/ipc_lib/memory_mapped_queue.cc
+++ b/aos/ipc_lib/memory_mapped_queue.cc
@@ -1,10 +1,22 @@
 #include "aos/ipc_lib/memory_mapped_queue.h"
 
+#include <errno.h>
 #include <fcntl.h>
 #include <sys/mman.h>
+#include <sys/stat.h>
 #include <unistd.h>
 
+#include <chrono>
+#include <limits>
+#include <ostream>
+#include <thread>
+
 #include "absl/strings/str_cat.h"
+#include "flatbuffers/string.h"
+#include "glog/logging.h"
+
+#include "aos/ipc_lib/index.h"
+#include "aos/util/file.h"
 
 namespace aos::ipc_lib {
 
diff --git a/aos/ipc_lib/memory_mapped_queue.h b/aos/ipc_lib/memory_mapped_queue.h
index bd766c1..f16f88e 100644
--- a/aos/ipc_lib/memory_mapped_queue.h
+++ b/aos/ipc_lib/memory_mapped_queue.h
@@ -1,6 +1,12 @@
 #ifndef AOS_IPC_LIB_MEMORY_MAPPED_QUEUE_H_
 #define AOS_IPC_LIB_MEMORY_MAPPED_QUEUE_H_
 
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+#include <string_view>
+
 #include "absl/types/span.h"
 
 #include "aos/configuration.h"
diff --git a/aos/ipc_lib/named_pipe_latency.cc b/aos/ipc_lib/named_pipe_latency.cc
index 032b72e..023853d 100644
--- a/aos/ipc_lib/named_pipe_latency.cc
+++ b/aos/ipc_lib/named_pipe_latency.cc
@@ -1,17 +1,22 @@
+#include <fcntl.h>
+#include <inttypes.h>
+#include <string.h>
 #include <sys/stat.h>
-#include <sys/types.h>
+#include <unistd.h>
 
+#include <algorithm>
 #include <chrono>
+#include <compare>
 #include <random>
+#include <ratio>
 #include <thread>
 
 #include "gflags/gflags.h"
+#include "glog/logging.h"
 
 #include "aos/events/epoll.h"
-#include "aos/init.h"
 #include "aos/ipc_lib/latency_lib.h"
 #include "aos/logging/implementations.h"
-#include "aos/logging/logging.h"
 #include "aos/realtime.h"
 #include "aos/time/time.h"
 
diff --git a/aos/ipc_lib/print_lockless_queue_memory.cc b/aos/ipc_lib/print_lockless_queue_memory.cc
index 2cbcf12..4bad81c 100644
--- a/aos/ipc_lib/print_lockless_queue_memory.cc
+++ b/aos/ipc_lib/print_lockless_queue_memory.cc
@@ -1,7 +1,11 @@
 #include <fcntl.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
-#include <sys/types.h>
+#include <unistd.h>
+
+#include <ostream>
+
+#include "glog/logging.h"
 
 #include "aos/ipc_lib/lockless_queue.h"
 
diff --git a/aos/ipc_lib/queue_racer.cc b/aos/ipc_lib/queue_racer.cc
index 2797c24..67ed6c5 100644
--- a/aos/ipc_lib/queue_racer.cc
+++ b/aos/ipc_lib/queue_racer.cc
@@ -1,11 +1,20 @@
 #include "aos/ipc_lib/queue_racer.h"
 
+#include <stdio.h>
+
+#include <algorithm>
 #include <cinttypes>
 #include <cstring>
 #include <limits>
+#include <optional>
+#include <ostream>
+#include <thread>
 
+#include "absl/types/span.h"
+#include "glog/logging.h"
 #include "gtest/gtest.h"
 
+#include "aos/events/context.h"
 #include "aos/ipc_lib/event.h"
 
 namespace aos::ipc_lib {
diff --git a/aos/ipc_lib/queue_racer.h b/aos/ipc_lib/queue_racer.h
index 2cbe3ed..1c07c49 100644
--- a/aos/ipc_lib/queue_racer.h
+++ b/aos/ipc_lib/queue_racer.h
@@ -1,9 +1,18 @@
 #ifndef AOS_IPC_LIB_QUEUE_RACER_H_
 #define AOS_IPC_LIB_QUEUE_RACER_H_
 
-#include <cstring>
+#include <stdint.h>
 
+#include <atomic>
+#include <chrono>
+#include <cstring>
+#include <functional>
+#include <vector>
+
+#include "aos/ipc_lib/index.h"
 #include "aos/ipc_lib/lockless_queue.h"
+#include "aos/time/time.h"
+#include "aos/uuid.h"
 
 namespace aos::ipc_lib {
 
diff --git a/aos/ipc_lib/robust_ownership_tracker.cc b/aos/ipc_lib/robust_ownership_tracker.cc
index 13edebc..449e151 100644
--- a/aos/ipc_lib/robust_ownership_tracker.cc
+++ b/aos/ipc_lib/robust_ownership_tracker.cc
@@ -1,7 +1,5 @@
 #include "aos/ipc_lib/robust_ownership_tracker.h"
 
-#include "aos/ipc_lib/lockless_queue.h"
-
 namespace aos::ipc_lib {
 
 ::std::string RobustOwnershipTracker::DebugString() const {
diff --git a/aos/ipc_lib/robust_ownership_tracker.h b/aos/ipc_lib/robust_ownership_tracker.h
index a8bbca3..34c8b7a 100644
--- a/aos/ipc_lib/robust_ownership_tracker.h
+++ b/aos/ipc_lib/robust_ownership_tracker.h
@@ -1,11 +1,20 @@
 #ifndef AOS_IPC_LIB_ROBUST_OWNERSHIP_TRACKER_H_
 #define AOS_IPC_LIB_ROBUST_OWNERSHIP_TRACKER_H_
 
+#include <assert.h>
 #include <linux/futex.h>
+#include <stdint.h>
 #include <sys/syscall.h>
+#include <unistd.h>
 
+#include <atomic>
+#include <limits>
+#include <optional>
+#include <ostream>
 #include <string>
 
+#include "glog/logging.h"
+
 #include "aos/ipc_lib/aos_sync.h"
 #include "aos/util/top.h"
 
diff --git a/aos/ipc_lib/robust_ownership_tracker_test.cc b/aos/ipc_lib/robust_ownership_tracker_test.cc
index b204886..8df5da0 100644
--- a/aos/ipc_lib/robust_ownership_tracker_test.cc
+++ b/aos/ipc_lib/robust_ownership_tracker_test.cc
@@ -1,5 +1,7 @@
 #include "aos/ipc_lib/robust_ownership_tracker.h"
 
+#include <errno.h>
+#include <stdlib.h>
 #include <sys/mman.h>
 #include <sys/wait.h>
 
diff --git a/aos/ipc_lib/shared_mem.cc b/aos/ipc_lib/shared_mem.cc
index e5de366..30dd173 100644
--- a/aos/ipc_lib/shared_mem.cc
+++ b/aos/ipc_lib/shared_mem.cc
@@ -1,8 +1,8 @@
 #include "aos/ipc_lib/shared_mem.h"
 
 #include <fcntl.h>
+#include <stdint.h>
 #include <sys/mman.h>
-#include <sys/types.h>
 #include <unistd.h>
 
 #include <cassert>
@@ -10,11 +10,11 @@
 #include <cstdio>
 #include <cstdlib>
 #include <cstring>
+#include <ostream>
 
 #include "glog/logging.h"
 
 #include "aos/ipc_lib/aos_sync.h"
-#include "aos/ipc_lib/core_lib.h"
 
 // the path for the shared memory segment. see shm_open(3) for restrictions
 #define AOS_SHM_NAME "/aos_shared_mem"
diff --git a/aos/ipc_lib/shared_mem.h b/aos/ipc_lib/shared_mem.h
index 89a700e..4c2d8d7 100644
--- a/aos/ipc_lib/shared_mem.h
+++ b/aos/ipc_lib/shared_mem.h
@@ -2,8 +2,6 @@
 #define _SHARED_MEM_H_
 
 #include <stddef.h>
-#include <time.h>
-#include <unistd.h>
 
 #include "aos/ipc_lib/shared_mem_types.h"
 
diff --git a/aos/ipc_lib/shm_base.cc b/aos/ipc_lib/shm_base.cc
index 22bf915..5db25d3 100644
--- a/aos/ipc_lib/shm_base.cc
+++ b/aos/ipc_lib/shm_base.cc
@@ -1,5 +1,7 @@
 #include "aos/ipc_lib/shm_base.h"
 
+#include <string>
+
 DEFINE_string(shm_base, "/dev/shm/aos",
               "Directory to place queue backing mmaped files in.");
 namespace aos::testing {
diff --git a/aos/ipc_lib/shm_base.h b/aos/ipc_lib/shm_base.h
index b70df06..1d06a69 100644
--- a/aos/ipc_lib/shm_base.h
+++ b/aos/ipc_lib/shm_base.h
@@ -1,6 +1,8 @@
 #ifndef AOS_IPC_LIB_SHM_BASE_H_
 #define AOS_IPC_LIB_SHM_BASE_H_
 
+#include <string_view>
+
 #include "gflags/gflags.h"
 
 DECLARE_string(shm_base);
diff --git a/aos/ipc_lib/signal_stress.cc b/aos/ipc_lib/signal_stress.cc
index 0559bce..b2749af 100644
--- a/aos/ipc_lib/signal_stress.cc
+++ b/aos/ipc_lib/signal_stress.cc
@@ -1,17 +1,21 @@
+#include <inttypes.h>
 #include <sys/signalfd.h>
+#include <unistd.h>
 
+#include <algorithm>
 #include <chrono>
+#include <compare>
 #include <csignal>
 #include <random>
+#include <ratio>
 #include <thread>
 
 #include "gflags/gflags.h"
+#include "glog/logging.h"
 
 #include "aos/events/epoll.h"
-#include "aos/init.h"
 #include "aos/ipc_lib/latency_lib.h"
 #include "aos/logging/implementations.h"
-#include "aos/logging/logging.h"
 #include "aos/realtime.h"
 #include "aos/time/time.h"
 
diff --git a/aos/ipc_lib/signalfd.cc b/aos/ipc_lib/signalfd.cc
index d25151d..c9634a5 100644
--- a/aos/ipc_lib/signalfd.cc
+++ b/aos/ipc_lib/signalfd.cc
@@ -1,8 +1,10 @@
 #include "aos/ipc_lib/signalfd.h"
 
+#include <string.h>
 #include <sys/types.h>
 
 #include <csignal>
+#include <ostream>
 #if __has_feature(memory_sanitizer)
 #include <sanitizer/msan_interface.h>
 #endif
@@ -74,7 +76,7 @@
   CHECK_EQ(0, wrapped_pthread_sigmask(SIG_BLOCK, &blocked_mask_, &old_mask));
   for (int signal : signals) {
     if (sigismember(&old_mask, signal)) {
-      CHECK_EQ(0, sigdelset(&blocked_mask_, signal));
+      LeaveSignalBlocked(signal);
     }
   }
 }
@@ -117,4 +119,8 @@
   return result;
 }
 
+void SignalFd::LeaveSignalBlocked(unsigned int signal) {
+  CHECK_EQ(0, sigdelset(&blocked_mask_, signal));
+}
+
 }  // namespace aos::ipc_lib
diff --git a/aos/ipc_lib/signalfd.h b/aos/ipc_lib/signalfd.h
index 014ad5c..3afdf99 100644
--- a/aos/ipc_lib/signalfd.h
+++ b/aos/ipc_lib/signalfd.h
@@ -1,8 +1,8 @@
 #ifndef AOS_IPC_LIB_SIGNALFD_H_
 #define AOS_IPC_LIB_SIGNALFD_H_
 
+#include <signal.h>
 #include <sys/signalfd.h>
-#include <sys/types.h>
 
 #include <initializer_list>
 
@@ -26,6 +26,11 @@
   // will be 0.
   signalfd_siginfo Read();
 
+  // Ensures the destructor will leave the specific signal blocked. This can be
+  // helpful if the signal is sent asynchronously, such that it may arrive after
+  // this object is destroyed, to ensure that doesn't kill the process.
+  void LeaveSignalBlocked(unsigned int signal);
+
  private:
   int fd_ = -1;
 
diff --git a/aos/ipc_lib/signalfd_test.cc b/aos/ipc_lib/signalfd_test.cc
index 2f349c1..025d66b 100644
--- a/aos/ipc_lib/signalfd_test.cc
+++ b/aos/ipc_lib/signalfd_test.cc
@@ -1,5 +1,8 @@
 #include "aos/ipc_lib/signalfd.h"
 
+#include <memory>
+#include <thread>
+
 #include "glog/logging.h"
 #include "gtest/gtest.h"
 
diff --git a/aos/libc/aos_strerror.cc b/aos/libc/aos_strerror.cc
index 9d270c0..3c37a19 100644
--- a/aos/libc/aos_strerror.cc
+++ b/aos/libc/aos_strerror.cc
@@ -1,7 +1,5 @@
 #include "aos/libc/aos_strerror.h"
 
-#include <sys/types.h>
-
 #include <cassert>
 #include <cstdio>
 #include <cstring>
diff --git a/aos/libc/aos_strerror_test.cc b/aos/libc/aos_strerror_test.cc
index 06a012a..5b328d7 100644
--- a/aos/libc/aos_strerror_test.cc
+++ b/aos/libc/aos_strerror_test.cc
@@ -1,6 +1,9 @@
 #include "aos/libc/aos_strerror.h"
 
+#include <string.h>
+
 #include <cerrno>
+#include <string>
 
 #include "gtest/gtest.h"
 
diff --git a/aos/libc/aos_strsignal.cc b/aos/libc/aos_strsignal.cc
index 12838b4..6a91973 100644
--- a/aos/libc/aos_strsignal.cc
+++ b/aos/libc/aos_strsignal.cc
@@ -1,5 +1,9 @@
 #include "aos/libc/aos_strsignal.h"
 
+#include <features.h>
+#include <stdio.h>
+#include <string.h>
+
 #include <csignal>
 
 #include "glog/logging.h"
diff --git a/aos/libc/aos_strsignal_test.cc b/aos/libc/aos_strsignal_test.cc
index 7e91d46..7a607bd 100644
--- a/aos/libc/aos_strsignal_test.cc
+++ b/aos/libc/aos_strsignal_test.cc
@@ -1,6 +1,10 @@
 #include "aos/libc/aos_strsignal.h"
 
+#include <string.h>
+
 #include <csignal>
+#include <functional>
+#include <memory>
 #include <thread>
 
 #include "gtest/gtest.h"
diff --git a/aos/libc/dirname.cc b/aos/libc/dirname.cc
index e73030c..324d71c 100644
--- a/aos/libc/dirname.cc
+++ b/aos/libc/dirname.cc
@@ -1,5 +1,7 @@
 #include "aos/libc/dirname.h"
 
+#include <stddef.h>
+
 namespace aos::libc {
 namespace {
 
diff --git a/aos/libc/dirname_test.cc b/aos/libc/dirname_test.cc
index 501b752..26ae23c 100644
--- a/aos/libc/dirname_test.cc
+++ b/aos/libc/dirname_test.cc
@@ -1,6 +1,7 @@
 #include "aos/libc/dirname.h"
 
 #include <libgen.h>
+#include <string.h>
 
 #include "gtest/gtest.h"
 
diff --git a/aos/logging/BUILD b/aos/logging/BUILD
index 5f56a50..b08f465 100644
--- a/aos/logging/BUILD
+++ b/aos/logging/BUILD
@@ -35,6 +35,7 @@
     visibility = ["//visibility:public"],
     deps = [
         "//aos:configuration",
+        "//aos/time",
         "@com_github_google_glog//:glog",
     ],
 )
diff --git a/aos/logging/context.cc b/aos/logging/context.cc
index 5e5d53c..00b7f3c 100644
--- a/aos/logging/context.cc
+++ b/aos/logging/context.cc
@@ -8,11 +8,14 @@
 #include <sanitizer/msan_interface.h>
 #endif
 #include <sys/prctl.h>
-#include <sys/types.h>
 #include <unistd.h>
 
-#include <cerrno>
+#include <algorithm>
+#include <cstddef>
 #include <cstring>
+#include <limits>
+#include <optional>
+#include <ostream>
 #include <string>
 
 extern char *program_invocation_name;
@@ -20,8 +23,6 @@
 
 #include "glog/logging.h"
 
-#include "aos/logging/implementations.h"
-
 namespace aos::logging::internal {
 namespace {
 
diff --git a/aos/logging/context.h b/aos/logging/context.h
index bb53b99..10993e8 100644
--- a/aos/logging/context.h
+++ b/aos/logging/context.h
@@ -3,10 +3,7 @@
 
 #include <sys/types.h>
 
-#include <atomic>
 #include <cinttypes>
-#include <climits>
-#include <cstddef>
 #include <memory>
 #include <string_view>
 
diff --git a/aos/logging/dynamic_logging.cc b/aos/logging/dynamic_logging.cc
index a3461b5..48c9dcb 100644
--- a/aos/logging/dynamic_logging.cc
+++ b/aos/logging/dynamic_logging.cc
@@ -1,5 +1,9 @@
 #include "aos/logging/dynamic_logging.h"
 
+#include <ostream>
+#include <string_view>
+
+#include "flatbuffers/string.h"
 #include "glog/logging.h"
 
 namespace aos::logging {
diff --git a/aos/logging/dynamic_logging.h b/aos/logging/dynamic_logging.h
index e3d3a6f..352d4b7 100644
--- a/aos/logging/dynamic_logging.h
+++ b/aos/logging/dynamic_logging.h
@@ -1,9 +1,8 @@
 #include <string>
 
-#include "glog/logging.h"
-
 #include "aos/events/event_loop.h"
 #include "aos/logging/dynamic_log_command_generated.h"
+#include "aos/macros.h"
 
 // The purpose of this class is to listen for /aos aos.logging.DynamicLogCommand
 // and make changes to the log level of the current application based on that
diff --git a/aos/logging/dynamic_logging_test.cc b/aos/logging/dynamic_logging_test.cc
index 70e491d..21e0c36 100644
--- a/aos/logging/dynamic_logging_test.cc
+++ b/aos/logging/dynamic_logging_test.cc
@@ -1,12 +1,18 @@
 #include "aos/logging/dynamic_logging.h"
 
-#include <sys/stat.h>
+#include <chrono>
+#include <memory>
+#include <ostream>
 
+#include "flatbuffers/buffer.h"
+#include "flatbuffers/flatbuffer_builder.h"
 #include "glog/logging.h"
 #include "gtest/gtest.h"
 
+#include "aos/configuration.h"
 #include "aos/events/event_loop.h"
 #include "aos/events/simulated_event_loop.h"
+#include "aos/flatbuffers.h"
 #include "aos/testing/path.h"
 
 using aos::testing::ArtifactPath;
diff --git a/aos/logging/implementations.cc b/aos/logging/implementations.cc
index da9e72b..042a09b 100644
--- a/aos/logging/implementations.cc
+++ b/aos/logging/implementations.cc
@@ -1,8 +1,6 @@
 #include "aos/logging/implementations.h"
 
-#include <algorithm>
 #include <chrono>
-#include <cinttypes>
 #include <cstdarg>
 
 #include "aos/logging/printf_formats.h"
diff --git a/aos/logging/implementations.h b/aos/logging/implementations.h
index 4e740f5..294750b 100644
--- a/aos/logging/implementations.h
+++ b/aos/logging/implementations.h
@@ -2,18 +2,13 @@
 #define AOS_LOGGING_IMPLEMENTATIONS_H_
 
 #include <sys/types.h>
-#include <unistd.h>
 
-#include <atomic>
-#include <climits>
-#include <cstdarg>
 #include <cstdint>
-#include <cstdio>
-#include <cstring>
 #include <functional>
 #include <memory>
 #include <string>
 #include <string_view>
+#include <utility>
 
 #include "aos/logging/context.h"
 #include "aos/logging/interface.h"
diff --git a/aos/logging/implementations_test.cc b/aos/logging/implementations_test.cc
index 693a91e..08fdc7b 100644
--- a/aos/logging/implementations_test.cc
+++ b/aos/logging/implementations_test.cc
@@ -1,5 +1,8 @@
 #include "aos/logging/implementations.h"
 
+#include <signal.h>
+#include <stdlib.h>
+
 #include <chrono>
 #include <cinttypes>
 #include <string>
diff --git a/aos/logging/interface.cc b/aos/logging/interface.cc
index e0ce6a8..326f28e 100644
--- a/aos/logging/interface.cc
+++ b/aos/logging/interface.cc
@@ -1,9 +1,12 @@
 #include "aos/logging/interface.h"
 
+#include <algorithm>
 #include <cstdarg>
 #include <cstdio>
 #include <cstring>
-#include <functional>
+#include <memory>
+#include <ostream>
+#include <string>
 #include <type_traits>
 
 #include "glog/logging.h"
@@ -11,6 +14,7 @@
 #include "aos/die.h"
 #include "aos/logging/context.h"
 #include "aos/logging/implementations.h"
+#include "aos/time/time.h"
 
 namespace aos::logging {
 namespace internal {
diff --git a/aos/logging/interface.h b/aos/logging/interface.h
index d2663e7..9889078 100644
--- a/aos/logging/interface.h
+++ b/aos/logging/interface.h
@@ -1,9 +1,9 @@
 #ifndef AOS_LOGGING_INTERFACE_H_
 #define AOS_LOGGING_INTERFACE_H_
 
+#include <stddef.h>
+
 #include <cstdarg>
-#include <functional>
-#include <string>
 #include <string_view>
 
 #include "aos/logging/logging.h"
@@ -13,8 +13,6 @@
 
 namespace aos {
 
-struct MessageType;
-
 namespace logging {
 
 // Takes a message and logs it. It will set everything up and then call DoLog
diff --git a/aos/logging/log_namer.cc b/aos/logging/log_namer.cc
index 412c74e..d5005bb 100644
--- a/aos/logging/log_namer.cc
+++ b/aos/logging/log_namer.cc
@@ -1,22 +1,21 @@
 #include "aos/logging/log_namer.h"
 
 #include <dirent.h>
-#include <fcntl.h>
 #include <mntent.h>
-#include <pwd.h>
-#include <sys/types.h>
 #include <unistd.h>
 
 #include <cerrno>
 #include <cstdio>
 #include <cstdlib>
 #include <cstring>
-#include <ctime>
+#include <ostream>
 #include <string>
 
+#include "gflags/gflags.h"
 #include "glog/logging.h"
 
 #include "aos/configuration.h"
+#include "aos/time/time.h"
 
 #if defined(__clang)
 #pragma clang diagnostic ignored "-Wformat-nonliteral"
@@ -53,8 +52,11 @@
         PLOG(FATAL) << "readdir(" << d << ") failed";
       }
     } else {
-      const std::string format_string = std::string(basename) + "-%d";
-      if (sscanf(dir->d_name, format_string.c_str(), &index) == 1) {
+      char previous_date[512];
+      // Look for previous index and date
+      const std::string format_string = std::string(basename) + "-%d_%s";
+      if (sscanf(dir->d_name, format_string.c_str(), &index, &previous_date) ==
+          2) {
         if (index >= fileindex) {
           fileindex = index + 1;
         }
@@ -72,7 +74,13 @@
     previous[0] = '\0';
     LOG(INFO) << "Could not find " << path;
   }
-  if (asprintf(filename, "%s/%s-%03d", directory, basename, fileindex) == -1) {
+  // Remove subsecond accuracy (after the ".").  We don't need it, and it makes
+  // the string very long
+  std::string time_short = aos::ToString(aos::realtime_clock::now());
+  time_short = time_short.substr(0, time_short.find("."));
+
+  if (asprintf(filename, "%s/%s-%03d_%s", directory, basename, fileindex,
+               time_short.c_str()) == -1) {
     PLOG(FATAL) << "couldn't create final name";
   }
   // Fix basename formatting.
diff --git a/aos/mutex/mutex.cc b/aos/mutex/mutex.cc
index 5c5dcbe..30a9534 100644
--- a/aos/mutex/mutex.cc
+++ b/aos/mutex/mutex.cc
@@ -1,13 +1,7 @@
 #include "aos/mutex/mutex.h"
 
-#include <cinttypes>
-#include <cstdio>
-#include <cstring>
-
 #include "glog/logging.h"
 
-#include "aos/type_traits/type_traits.h"
-
 namespace aos {
 
 // Lock and Unlock use the return values of mutex_lock/mutex_unlock
diff --git a/aos/mutex/mutex.h b/aos/mutex/mutex.h
index 869f429..dfc212a 100644
--- a/aos/mutex/mutex.h
+++ b/aos/mutex/mutex.h
@@ -1,6 +1,8 @@
 #ifndef AOS_MUTEX_H_
 #define AOS_MUTEX_H_
 
+#include <ostream>
+
 #include "glog/logging.h"
 
 #include "aos/ipc_lib/aos_sync.h"
@@ -8,9 +10,6 @@
 #include "aos/type_traits/type_traits.h"
 
 namespace aos {
-
-class Condition;
-
 // An abstraction of a mutex that is easy to implement for environments other
 // than Linux too.
 // If there are multiple threads or processes contending for the mutex,
diff --git a/aos/mutex/mutex_test.cc b/aos/mutex/mutex_test.cc
index 8d10b26..9f8efbf 100644
--- a/aos/mutex/mutex_test.cc
+++ b/aos/mutex/mutex_test.cc
@@ -1,20 +1,17 @@
 #include "aos/mutex/mutex.h"
 
-#include <pthread.h>
-#include <sched.h>
-
 #include <chrono>
-#include <cmath>
+#include <memory>
+#include <new>
 #include <thread>
 
 #include "gtest/gtest.h"
 
 #include "aos/die.h"
-#include "aos/ipc_lib/aos_sync.h"
 #include "aos/ipc_lib/core_lib.h"
+#include "aos/logging/implementations.h"
 #include "aos/testing/test_logging.h"
 #include "aos/testing/test_shm.h"
-#include "aos/time/time.h"
 #include "aos/util/death_test_log_implementation.h"
 
 namespace aos::testing {
diff --git a/aos/network/BUILD b/aos/network/BUILD
index 8186abb..96f8b50 100644
--- a/aos/network/BUILD
+++ b/aos/network/BUILD
@@ -876,6 +876,30 @@
     ],
 )
 
+cc_binary(
+    name = "ping",
+    srcs = [
+        "ping.cc",
+    ],
+    deps = [
+        ":sctp_server",
+        "//aos:init",
+        "//aos/events:shm_event_loop",
+    ],
+)
+
+cc_binary(
+    name = "pong",
+    srcs = [
+        "pong.cc",
+    ],
+    deps = [
+        ":sctp_client",
+        "//aos:init",
+        "//aos/events:shm_event_loop",
+    ],
+)
+
 cc_test(
     name = "timestamp_channel_test",
     srcs = ["timestamp_channel_test.cc"],
diff --git a/aos/network/ping.cc b/aos/network/ping.cc
new file mode 100644
index 0000000..f105133
--- /dev/null
+++ b/aos/network/ping.cc
@@ -0,0 +1,136 @@
+#include <chrono>
+
+#include "gflags/gflags.h"
+#include "glog/logging.h"
+
+#include "aos/events/shm_event_loop.h"
+#include "aos/init.h"
+#include "aos/network/sctp_server.h"
+
+DEFINE_string(config, "aos_config.json", "Path to the config.");
+DEFINE_uint32(port, 1323, "Port to pingpong on");
+DEFINE_uint32(size, 1000000, "Size of data to send in bytes");
+DEFINE_uint32(duration, 1000, "Period to send at in milliseconds");
+DEFINE_uint32(ttl, 0, "TTL in milliseconds");
+
+namespace aos {
+namespace message_bridge {
+
+namespace chrono = std::chrono;
+
+class PingServer {
+ public:
+  PingServer(aos::ShmEventLoop *event_loop)
+      : event_loop_(event_loop), server_(2, "::", FLAGS_port) {
+    event_loop_->epoll()->OnReadable(server_.fd(),
+                                     [this]() { MessageReceived(); });
+    server_.SetMaxReadSize(FLAGS_size + 100);
+    server_.SetMaxWriteSize(FLAGS_size + 100);
+
+    timer_ = event_loop_->AddTimer([this]() { Timer(); });
+
+    event_loop_->OnRun([this]() {
+      timer_->Schedule(event_loop_->monotonic_now(),
+                       chrono::milliseconds(FLAGS_duration));
+    });
+
+    event_loop_->SetRuntimeRealtimePriority(5);
+  }
+
+  ~PingServer() { event_loop_->epoll()->DeleteFd(server_.fd()); }
+
+  aos::TimerHandler *timer_;
+  sctp_assoc_t sac_assoc_id_ = 0;
+
+  void Timer() {
+    if (sac_assoc_id_ == 0) {
+      LOG(INFO) << "No client, not sending";
+      return;
+    }
+
+    std::string data(FLAGS_size, 'a');
+
+    if (server_.Send(data, sac_assoc_id_, 0, FLAGS_ttl)) {
+      LOG(INFO) << "Sent " << data.size();
+    } else {
+      PLOG(ERROR) << "Failed to send";
+    }
+  }
+
+  void MessageReceived() {
+    aos::unique_c_ptr<Message> message = server_.Read();
+    if (!message) {
+      return;
+    }
+
+    if (message->message_type == Message::kNotification) {
+      const union sctp_notification *snp =
+          (const union sctp_notification *)message->data();
+
+      if (VLOG_IS_ON(2)) {
+        PrintNotification(message.get());
+      }
+
+      switch (snp->sn_header.sn_type) {
+        case SCTP_ASSOC_CHANGE: {
+          const struct sctp_assoc_change *sac = &snp->sn_assoc_change;
+          switch (sac->sac_state) {
+            case SCTP_COMM_UP:
+              NodeConnected(sac->sac_assoc_id);
+              VLOG(1) << "Peer connected";
+              break;
+            case SCTP_COMM_LOST:
+            case SCTP_SHUTDOWN_COMP:
+            case SCTP_CANT_STR_ASSOC:
+              NodeDisconnected(sac->sac_assoc_id);
+              VLOG(1) << "Disconnect";
+              break;
+            case SCTP_RESTART:
+              LOG(FATAL) << "Never seen this before.";
+              break;
+          }
+        } break;
+      }
+    } else if (message->message_type == Message::kMessage) {
+      HandleData(message.get());
+    }
+  }
+
+  void NodeConnected(sctp_assoc_t assoc_id) {
+    sac_assoc_id_ = assoc_id;
+    server_.SetPriorityScheduler(assoc_id);
+  }
+  void NodeDisconnected(sctp_assoc_t /*assoc_id*/) { sac_assoc_id_ = 0; }
+
+  void HandleData(const Message *message) {
+    VLOG(1) << "Received data of length " << message->size;
+
+    if (VLOG_IS_ON(1)) {
+      message->LogRcvInfo();
+    }
+  }
+
+ private:
+  aos::ShmEventLoop *event_loop_;
+  SctpServer server_;
+};
+
+int Main() {
+  aos::FlatbufferDetachedBuffer<aos::Configuration> config =
+      aos::configuration::ReadConfig(FLAGS_config);
+
+  aos::ShmEventLoop event_loop(&config.message());
+  PingServer server(&event_loop);
+  event_loop.Run();
+
+  return EXIT_SUCCESS;
+}
+
+}  // namespace message_bridge
+}  // namespace aos
+
+int main(int argc, char **argv) {
+  aos::InitGoogle(&argc, &argv);
+
+  return aos::message_bridge::Main();
+}
diff --git a/aos/network/pong.cc b/aos/network/pong.cc
new file mode 100644
index 0000000..8f08836
--- /dev/null
+++ b/aos/network/pong.cc
@@ -0,0 +1,138 @@
+#include <chrono>
+
+#include "gflags/gflags.h"
+#include "glog/logging.h"
+
+#include "aos/events/shm_event_loop.h"
+#include "aos/init.h"
+#include "aos/network/sctp_client.h"
+
+DEFINE_string(config, "aos_config.json", "Path to the config.");
+DEFINE_uint32(port, 1323, "Port to pingpong on");
+DEFINE_string(target, "vpu0-0a", "Host to connect to");
+DEFINE_uint32(rx_size, 1000000,
+              "RX buffer size to set the max size to be in bytes.");
+DEFINE_uint32(size, 1000, "Size of data to send in bytes");
+DEFINE_uint32(ttl, 0, "TTL in milliseconds");
+
+namespace aos {
+namespace message_bridge {
+
+namespace chrono = std::chrono;
+
+class PingClient {
+ public:
+  PingClient(aos::ShmEventLoop *event_loop)
+      : event_loop_(event_loop), client_(FLAGS_target, FLAGS_port, 2, "::", 0) {
+    client_.SetMaxReadSize(std::max(FLAGS_rx_size, FLAGS_size) + 100);
+    client_.SetMaxWriteSize(std::max(FLAGS_rx_size, FLAGS_size) + 100);
+
+    timer_ = event_loop_->AddTimer([this]() { Timer(); });
+
+    event_loop_->OnRun([this]() {
+      timer_->Schedule(event_loop_->monotonic_now(),
+                       chrono::milliseconds(1000));
+    });
+
+    event_loop_->epoll()->OnReadable(client_.fd(),
+                                     [this]() { MessageReceived(); });
+    event_loop_->SetRuntimeRealtimePriority(5);
+  }
+
+  ~PingClient() { event_loop_->epoll()->DeleteFd(client_.fd()); }
+
+  aos::TimerHandler *timer_;
+  sctp_assoc_t sac_assoc_id_ = 0;
+
+  void Timer() {
+    std::string data(FLAGS_size, 'a');
+
+    if (client_.Send(0, data, FLAGS_ttl)) {
+      LOG(INFO) << "Sent " << data.size();
+    } else {
+      PLOG(ERROR) << "Failed to send";
+    }
+  }
+
+  void MessageReceived() {
+    aos::unique_c_ptr<Message> message = client_.Read();
+    ++count_;
+    if (!message) {
+      return;
+    }
+
+    if (message->message_type == Message::kNotification) {
+      const union sctp_notification *snp =
+          (const union sctp_notification *)message->data();
+
+      if (VLOG_IS_ON(2)) {
+        PrintNotification(message.get());
+      }
+
+      switch (snp->sn_header.sn_type) {
+        case SCTP_ASSOC_CHANGE: {
+          const struct sctp_assoc_change *sac = &snp->sn_assoc_change;
+          switch (sac->sac_state) {
+            case SCTP_COMM_UP:
+              NodeConnected(sac->sac_assoc_id);
+              VLOG(1) << "Peer connected";
+              break;
+            case SCTP_COMM_LOST:
+            case SCTP_SHUTDOWN_COMP:
+            case SCTP_CANT_STR_ASSOC:
+              NodeDisconnected(sac->sac_assoc_id);
+              VLOG(1) << "Disconnect";
+              break;
+            case SCTP_RESTART:
+              LOG(FATAL) << "Never seen this before.";
+              break;
+          }
+        } break;
+      }
+    } else if (message->message_type == Message::kMessage) {
+      HandleData(message.get());
+    }
+  }
+
+  void NodeConnected(sctp_assoc_t assoc_id) {
+    client_.SetPriorityScheduler(assoc_id);
+  }
+  void NodeDisconnected(sctp_assoc_t /*assoc_id*/) {}
+
+  void HandleData(const Message *message) {
+    LOG(INFO) << "Received data of length " << message->size << " total "
+              << size_ << " count " << count_;
+    size_ += message->size;
+
+    if (VLOG_IS_ON(1)) {
+      message->LogRcvInfo();
+    }
+  }
+
+ private:
+  aos::ShmEventLoop *event_loop_;
+  SctpClient client_;
+
+  size_t count_ = 0;
+  size_t size_ = 0;
+};
+
+int Main() {
+  aos::FlatbufferDetachedBuffer<aos::Configuration> config =
+      aos::configuration::ReadConfig(FLAGS_config);
+
+  aos::ShmEventLoop event_loop(&config.message());
+  PingClient server(&event_loop);
+  event_loop.Run();
+
+  return EXIT_SUCCESS;
+}
+
+}  // namespace message_bridge
+}  // namespace aos
+
+int main(int argc, char **argv) {
+  aos::InitGoogle(&argc, &argv);
+
+  return aos::message_bridge::Main();
+}
diff --git a/aos/scoped/scoped_fd.cc b/aos/scoped/scoped_fd.cc
index 846736d..f2375ab 100644
--- a/aos/scoped/scoped_fd.cc
+++ b/aos/scoped/scoped_fd.cc
@@ -1,5 +1,9 @@
 #include "aos/scoped/scoped_fd.h"
 
+#include <unistd.h>
+
+#include <ostream>
+
 #include "glog/logging.h"
 
 namespace aos {
diff --git a/aos/scoped/scoped_fd.h b/aos/scoped/scoped_fd.h
index e393e89..bd52657 100644
--- a/aos/scoped/scoped_fd.h
+++ b/aos/scoped/scoped_fd.h
@@ -1,10 +1,6 @@
 #ifndef AOS_SCOPED_SCOPED_FD_H_
 #define AOS_SCOPED_SCOPED_FD_H_
 
-#include <unistd.h>
-
-#include "aos/macros.h"
-
 namespace aos {
 
 // Smart "pointer" (container) for a file descriptor.
diff --git a/aos/starter/irq_affinity.cc b/aos/starter/irq_affinity.cc
index 7459e5e..94c9c71 100644
--- a/aos/starter/irq_affinity.cc
+++ b/aos/starter/irq_affinity.cc
@@ -1,15 +1,36 @@
 #include <linux/securebits.h>
 #include <pwd.h>
+#include <sched.h>
+#include <stdint.h>
 #include <sys/prctl.h>
 #include <sys/resource.h>
-#include <sys/types.h>
+#include <unistd.h>
 
+#include <algorithm>
+#include <map>
+#include <optional>
+#include <ostream>
+#include <string>
+#include <string_view>
+#include <utility>
+#include <vector>
+
+#include "absl/strings/str_cat.h"
+#include "flatbuffers/buffer.h"
+#include "flatbuffers/string.h"
+#include "flatbuffers/vector.h"
 #include "gflags/gflags.h"
+#include "glog/logging.h"
 
+#include "aos/configuration.h"
+#include "aos/events/event_loop.h"
 #include "aos/events/shm_event_loop.h"
+#include "aos/flatbuffers.h"
 #include "aos/init.h"
+#include "aos/json_to_flatbuffer.h"
 #include "aos/starter/irq_affinity_lib.h"
 #include "aos/starter/kthread_generated.h"
+#include "aos/util/file.h"
 #include "aos/util/top.h"
 
 DEFINE_string(config, "aos_config.json", "File path of aos configuration");
diff --git a/aos/starter/irq_affinity_lib.cc b/aos/starter/irq_affinity_lib.cc
index 2128f52..7075e31 100644
--- a/aos/starter/irq_affinity_lib.cc
+++ b/aos/starter/irq_affinity_lib.cc
@@ -1,10 +1,18 @@
 #include "aos/starter/irq_affinity_lib.h"
 
 #include <fcntl.h>
+#include <unistd.h>
 
-#include "absl/strings/escaping.h"
+#include <algorithm>
+#include <ostream>
+#include <utility>
+
+#include "absl/strings/ascii.h"
 #include "absl/strings/match.h"
+#include "absl/strings/numbers.h"
 #include "absl/strings/str_split.h"
+#include "absl/strings/string_view.h"
+#include "glog/logging.h"
 
 #include "aos/scoped/scoped_fd.h"
 
diff --git a/aos/starter/irq_affinity_lib.h b/aos/starter/irq_affinity_lib.h
index 8bbad15..414acdd 100644
--- a/aos/starter/irq_affinity_lib.h
+++ b/aos/starter/irq_affinity_lib.h
@@ -1,10 +1,11 @@
 #ifndef AOS_STARTER_IRQ_AFFINITY_LIB_H_
 #define AOS_STARTER_IRQ_AFFINITY_LIB_H_
 
-#include <string>
-#include <vector>
+#include <stddef.h>
 
-#include "glog/logging.h"
+#include <string>
+#include <string_view>
+#include <vector>
 
 namespace aos {
 
diff --git a/aos/starter/mock_starter.cc b/aos/starter/mock_starter.cc
index 541e17f..d52db95 100644
--- a/aos/starter/mock_starter.cc
+++ b/aos/starter/mock_starter.cc
@@ -1,5 +1,20 @@
 #include "aos/starter/mock_starter.h"
 
+#include <algorithm>
+#include <ostream>
+#include <string_view>
+#include <utility>
+
+#include "flatbuffers/buffer.h"
+#include "flatbuffers/flatbuffer_builder.h"
+#include "flatbuffers/string.h"
+#include "flatbuffers/vector.h"
+#include "glog/logging.h"
+
+#include "aos/configuration.h"
+#include "aos/starter/starter_rpc_generated.h"
+#include "aos/starter/starterd_lib.h"
+
 namespace aos::starter {
 
 MockStarter::MockStarter(aos::EventLoop *event_loop)
diff --git a/aos/starter/mock_starter.h b/aos/starter/mock_starter.h
index 212f1e5..4197bea 100644
--- a/aos/starter/mock_starter.h
+++ b/aos/starter/mock_starter.h
@@ -1,10 +1,14 @@
+#include <chrono>
 #include <map>
+#include <memory>
+#include <string>
+#include <vector>
 
+#include "aos/configuration_generated.h"
 #include "aos/events/event_loop.h"
 #include "aos/events/simulated_event_loop.h"
 #include "aos/starter/starter_generated.h"
-#include "aos/starter/starter_rpc_generated.h"
-#include "aos/starter/starterd_lib.h"
+#include "aos/time/time.h"
 
 namespace aos::starter {
 
diff --git a/aos/starter/starter_cmd.cc b/aos/starter/starter_cmd.cc
index 6c172fe..b79485a 100644
--- a/aos/starter/starter_cmd.cc
+++ b/aos/starter/starter_cmd.cc
@@ -1,17 +1,33 @@
+#include <ctype.h>
+#include <stdlib.h>
+
 #include <algorithm>
 #include <chrono>
+#include <compare>
 #include <functional>
 #include <iostream>
+#include <map>
+#include <memory>
 #include <optional>
+#include <string>
 #include <string_view>
+#include <tuple>
 #include <unordered_map>
+#include <utility>
+#include <vector>
 
 #include "absl/strings/str_format.h"
 #include "absl/strings/str_join.h"
+#include "flatbuffers/string.h"
+#include "flatbuffers/vector.h"
 #include "gflags/gflags.h"
+#include "glog/logging.h"
 
+#include "aos/configuration.h"
+#include "aos/flatbuffers.h"
 #include "aos/init.h"
-#include "aos/json_to_flatbuffer.h"
+#include "aos/starter/starter_generated.h"
+#include "aos/starter/starter_rpc_generated.h"
 #include "aos/starter/starter_rpc_lib.h"
 #include "aos/time/time.h"
 
diff --git a/aos/starter/starter_rpc_lib.cc b/aos/starter/starter_rpc_lib.cc
index 754fc2c..230e1b1 100644
--- a/aos/starter/starter_rpc_lib.cc
+++ b/aos/starter/starter_rpc_lib.cc
@@ -1,7 +1,15 @@
 #include "aos/starter/starter_rpc_lib.h"
 
+#include <algorithm>
+#include <ostream>
+
+#include "flatbuffers/buffer.h"
+#include "flatbuffers/flatbuffer_builder.h"
+#include "flatbuffers/string.h"
+#include "flatbuffers/vector.h"
 #include "glog/logging.h"
 
+#include "aos/events/context.h"
 #include "aos/events/shm_event_loop.h"
 #include "aos/flatbuffer_merge.h"
 #include "aos/starter/starterd_lib.h"
diff --git a/aos/starter/starter_rpc_lib.h b/aos/starter/starter_rpc_lib.h
index a949928..f94e617 100644
--- a/aos/starter/starter_rpc_lib.h
+++ b/aos/starter/starter_rpc_lib.h
@@ -1,15 +1,23 @@
 #ifndef AOS_STARTER_STARTER_RPC_LIB_H_
 #define AOS_STARTER_STARTER_RPC_LIB_H_
 
+#include <stdint.h>
+
 #include <chrono>
+#include <functional>
 #include <map>
 #include <optional>
+#include <string>
+#include <string_view>
+#include <utility>
 #include <vector>
 
 #include "aos/configuration.h"
 #include "aos/events/event_loop.h"
+#include "aos/flatbuffers.h"
 #include "aos/starter/starter_generated.h"
 #include "aos/starter/starter_rpc_generated.h"
+#include "aos/time/time.h"
 
 namespace aos::starter {
 
diff --git a/aos/starter/starter_test.cc b/aos/starter/starter_test.cc
index 5888233..0a074e0 100644
--- a/aos/starter/starter_test.cc
+++ b/aos/starter/starter_test.cc
@@ -1,19 +1,35 @@
+#include <stdint.h>
+
+#include <atomic>
 #include <chrono>
 #include <csignal>
-#include <future>
+#include <functional>
+#include <ostream>
+#include <string>
 #include <thread>
 
+#include "absl/strings/str_format.h"
+#include "flatbuffers/string.h"
+#include "gflags/gflags.h"
+#include "glog/logging.h"
 #include "gtest/gtest.h"
 
+#include "aos/configuration.h"
+#include "aos/events/event_loop.h"
 #include "aos/events/ping_generated.h"
-#include "aos/events/pong_generated.h"
+#include "aos/events/shm_event_loop.h"
+#include "aos/flatbuffers.h"
 #include "aos/ipc_lib/event.h"
+#include "aos/ipc_lib/shm_base.h"
+#include "aos/json_to_flatbuffer.h"
 #include "aos/network/team_number.h"
+#include "aos/starter/starter_generated.h"
+#include "aos/starter/starter_rpc_generated.h"
 #include "aos/starter/starter_rpc_lib.h"
 #include "aos/starter/starterd_lib.h"
 #include "aos/testing/path.h"
-#include "aos/testing/tmpdir.h"
 #include "aos/util/file.h"
+#include "aos/util/process_info_generated.h"
 
 using aos::testing::ArtifactPath;
 
diff --git a/aos/starter/starterd.cc b/aos/starter/starterd.cc
index 1ac4514..64858d4 100644
--- a/aos/starter/starterd.cc
+++ b/aos/starter/starterd.cc
@@ -1,8 +1,15 @@
 #include <pwd.h>
-#include <sys/types.h>
+#include <unistd.h>
+
+#include <ostream>
+#include <string>
 
 #include "gflags/gflags.h"
+#include "glog/logging.h"
 
+#include "aos/configuration.h"
+#include "aos/events/event_loop.h"
+#include "aos/flatbuffers.h"
 #include "aos/init.h"
 #include "aos/starter/starterd_lib.h"
 #include "aos/util/file.h"
diff --git a/aos/starter/starterd_lib.cc b/aos/starter/starterd_lib.cc
index 4c71057..6917bb5 100644
--- a/aos/starter/starterd_lib.cc
+++ b/aos/starter/starterd_lib.cc
@@ -1,12 +1,24 @@
 #include "aos/starter/starterd_lib.h"
 
+#include <string.h>
+
 #include <algorithm>
+#include <chrono>
+#include <functional>
+#include <ostream>
+#include <set>
+#include <string_view>
+#include <thread>
 #include <utility>
 
-#include "absl/strings/str_format.h"
+#include "flatbuffers/buffer.h"
+#include "flatbuffers/flatbuffer_builder.h"
+#include "flatbuffers/string.h"
+#include "flatbuffers/vector.h"
+#include "gflags/gflags.h"
 #include "glog/logging.h"
-#include "glog/stl_logging.h"
 
+#include "aos/events/context.h"
 #include "aos/json_to_flatbuffer.h"
 
 // FLAGS_shm_base is defined elsewhere, declare it here so it can be used
diff --git a/aos/starter/starterd_lib.h b/aos/starter/starterd_lib.h
index 1ffc782..a5aa406 100644
--- a/aos/starter/starterd_lib.h
+++ b/aos/starter/starterd_lib.h
@@ -2,17 +2,20 @@
 #define AOS_STARTER_STARTERD_LIB_H_
 
 #include <sys/signalfd.h>
-#include <sys/wait.h>
 
 #include <csignal>
-#include <cstdio>
+#include <memory>
+#include <mutex>
 #include <string>
 #include <unordered_map>
 #include <vector>
 
 #include "aos/configuration.h"
+#include "aos/events/event_loop.h"
+#include "aos/events/event_loop_generated.h"
+#include "aos/events/shm_event_loop.h"
+#include "aos/ftrace.h"
 #include "aos/ipc_lib/memory_mapped_queue.h"
-#include "aos/ipc_lib/signalfd.h"
 #include "aos/macros.h"
 #include "aos/starter/starter_generated.h"
 #include "aos/starter/starter_rpc_generated.h"
diff --git a/aos/starter/subprocess.cc b/aos/starter/subprocess.cc
index 07057a0..60f6b92 100644
--- a/aos/starter/subprocess.cc
+++ b/aos/starter/subprocess.cc
@@ -1,15 +1,26 @@
 #include "aos/starter/subprocess.h"
 
+#include <errno.h>
 #include <grp.h>
 #include <pwd.h>
+#include <signal.h>
+#include <stdlib.h>
 #include <sys/prctl.h>
-#include <sys/types.h>
+#include <sys/stat.h>
 #include <sys/wait.h>
+#include <unistd.h>
 
+#include <compare>
+#include <iterator>
+#include <ostream>
+#include <ratio>
+
+#include "absl/strings/str_cat.h"
 #include "absl/strings/str_split.h"
 #include "glog/logging.h"
 
-#include "aos/flatbuffer_merge.h"
+#include "aos/util/file.h"
+#include "aos/util/process_info_generated.h"
 
 namespace aos::starter {
 
diff --git a/aos/starter/subprocess.h b/aos/starter/subprocess.h
index eb36874..33b0dc9 100644
--- a/aos/starter/subprocess.h
+++ b/aos/starter/subprocess.h
@@ -1,16 +1,37 @@
 #ifndef AOS_STARTER_SUBPROCESS_H_
 #define AOS_STARTER_SUBPROCESS_H_
 
-#include <filesystem>
+#include <stdint.h>
+#include <sys/signalfd.h>
+#include <sys/types.h>
+
+#include <algorithm>
+#include <chrono>
+#include <filesystem>  // IWYU pragma: keep
+#include <functional>
+#include <initializer_list>
 #include <memory>
+#include <optional>
 #include <string>
-#include <tuple>
+#include <string_view>
+#include <utility>
 #include <vector>
 
+#include "flatbuffers/buffer.h"
+#include "flatbuffers/flatbuffer_builder.h"
+#include "flatbuffers/string.h"
+#include "flatbuffers/vector.h"
+
+#include "aos/configuration_generated.h"
+#include "aos/events/epoll.h"
 #include "aos/events/event_loop.h"
+#include "aos/events/event_loop_generated.h"
 #include "aos/events/shm_event_loop.h"
+#include "aos/ipc_lib/signalfd.h"
+#include "aos/macros.h"
 #include "aos/starter/starter_generated.h"
 #include "aos/starter/starter_rpc_generated.h"
+#include "aos/time/time.h"
 #include "aos/util/scoped_pipe.h"
 #include "aos/util/top.h"
 
diff --git a/aos/starter/subprocess_reliable_test.cc b/aos/starter/subprocess_reliable_test.cc
index 701de11..a395870 100644
--- a/aos/starter/subprocess_reliable_test.cc
+++ b/aos/starter/subprocess_reliable_test.cc
@@ -1,16 +1,27 @@
+#include <errno.h>
 #include <signal.h>
-#include <sys/types.h>
+#include <sys/wait.h>
 
+#include <chrono>
 #include <filesystem>
+#include <memory>
+#include <ostream>
+#include <string>
+#include <thread>
 
+#include "absl/strings/str_cat.h"
+#include "glog/logging.h"
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 
+#include "aos/configuration.h"
+#include "aos/events/event_loop.h"
 #include "aos/events/shm_event_loop.h"
+#include "aos/flatbuffers.h"
+#include "aos/starter/starter_generated.h"
 #include "aos/starter/subprocess.h"
 #include "aos/testing/path.h"
 #include "aos/testing/tmpdir.h"
-#include "aos/util/file.h"
 
 namespace aos::starter::testing {
 
diff --git a/aos/starter/subprocess_test.cc b/aos/starter/subprocess_test.cc
index fcc1128..2951b2b 100644
--- a/aos/starter/subprocess_test.cc
+++ b/aos/starter/subprocess_test.cc
@@ -1,13 +1,22 @@
 #include "aos/starter/subprocess.h"
 
 #include <signal.h>
-#include <sys/types.h>
+#include <stdlib.h>
+#include <sys/stat.h>
 
+#include <ostream>
+
+#include "absl/strings/str_cat.h"
 #include "absl/strings/str_join.h"
+#include "gflags/gflags.h"
+#include "glog/logging.h"
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 
+#include "aos/configuration.h"
 #include "aos/events/shm_event_loop.h"
+#include "aos/flatbuffers.h"
+#include "aos/ipc_lib/shm_base.h"
 #include "aos/testing/path.h"
 #include "aos/testing/tmpdir.h"
 #include "aos/util/file.h"
diff --git a/aos/stl_mutex/stl_mutex.h b/aos/stl_mutex/stl_mutex.h
index 5aaa6b6..c719805 100644
--- a/aos/stl_mutex/stl_mutex.h
+++ b/aos/stl_mutex/stl_mutex.h
@@ -2,6 +2,7 @@
 #define AOS_STL_MUTEX_H_
 
 #include <mutex>
+#include <ostream>
 
 #include "glog/logging.h"
 
diff --git a/aos/stl_mutex/stl_mutex_test.cc b/aos/stl_mutex/stl_mutex_test.cc
index 5343974..0eb50d4 100644
--- a/aos/stl_mutex/stl_mutex_test.cc
+++ b/aos/stl_mutex/stl_mutex_test.cc
@@ -1,5 +1,7 @@
 #include "aos/stl_mutex/stl_mutex.h"
 
+#include <memory>
+
 #include "gtest/gtest.h"
 
 #include "aos/die.h"
diff --git a/aos/testing/gtest_main.cc b/aos/testing/gtest_main.cc
index 6071bde..1940988 100644
--- a/aos/testing/gtest_main.cc
+++ b/aos/testing/gtest_main.cc
@@ -1,7 +1,3 @@
-#include <getopt.h>
-
-#include <iostream>
-
 #include "gflags/gflags.h"
 #include "glog/logging.h"
 #include "gtest/gtest.h"
diff --git a/aos/testing/test_logging.cc b/aos/testing/test_logging.cc
index 56875bb..15cb64b 100644
--- a/aos/testing/test_logging.cc
+++ b/aos/testing/test_logging.cc
@@ -1,6 +1,12 @@
 #include "aos/testing/test_logging.h"
 
+#include <string.h>
+
+#include <algorithm>
 #include <cstdio>
+#include <memory>
+#include <mutex>
+#include <string_view>
 #include <vector>
 
 #include "absl/base/call_once.h"
@@ -8,6 +14,7 @@
 
 #include "aos/logging/implementations.h"
 #include "aos/stl_mutex/stl_mutex.h"
+#include "aos/time/time.h"
 
 using ::aos::logging::LogMessage;
 
diff --git a/aos/testing/test_logging.h b/aos/testing/test_logging.h
index 3671aa1..b7e8977 100644
--- a/aos/testing/test_logging.h
+++ b/aos/testing/test_logging.h
@@ -1,8 +1,6 @@
 #ifndef AOS_TESTING_TEST_LOGGING_H_
 #define AOS_TESTING_TEST_LOGGING_H_
 
-#include "aos/time/time.h"
-
 namespace aos::testing {
 
 // Enables the logging framework for use during a gtest test.
diff --git a/aos/testing/test_logging_test.cc b/aos/testing/test_logging_test.cc
index 5731545..b37bec4 100644
--- a/aos/testing/test_logging_test.cc
+++ b/aos/testing/test_logging_test.cc
@@ -1,5 +1,6 @@
 #include "aos/testing/test_logging.h"
 
+#include <memory>
 #include <thread>
 
 #include "gtest/gtest.h"
diff --git a/aos/testing/test_shm.cc b/aos/testing/test_shm.cc
index 1b168ea..4922b63 100644
--- a/aos/testing/test_shm.cc
+++ b/aos/testing/test_shm.cc
@@ -1,9 +1,9 @@
 #include "aos/testing/test_shm.h"
 
+#include <stddef.h>
 #include <sys/mman.h>
 
-#include "gflags/gflags.h"
-
+#include "aos/ipc_lib/shared_mem.h"
 #include "aos/logging/logging.h"
 #include "aos/testing/test_logging.h"
 
diff --git a/aos/testing/test_shm.h b/aos/testing/test_shm.h
index 658a72d..24c87ce 100644
--- a/aos/testing/test_shm.h
+++ b/aos/testing/test_shm.h
@@ -1,7 +1,7 @@
 #ifndef AOS_TESTING_TEST_SHM_H_
 #define AOS_TESTING_TEST_SHM_H_
 
-#include "aos/ipc_lib/shared_mem.h"
+#include "aos/ipc_lib/shared_mem_types.h"
 
 namespace aos::testing {
 
diff --git a/aos/time/time.cc b/aos/time/time.cc
index e75fe45..fe8422b 100644
--- a/aos/time/time.cc
+++ b/aos/time/time.cc
@@ -1,11 +1,16 @@
 #include "aos/time/time.h"
 
+#include <ctype.h>
+#include <errno.h>
+#include <sys/time.h>
+
 #include <algorithm>
 #include <chrono>
-#include <cinttypes>
-#include <cstring>
+#include <compare>
+#include <cstdint>
 #include <ctime>
 #include <iomanip>
+#include <ratio>
 #include <sstream>
 
 #ifdef __linux__
diff --git a/aos/time/time.h b/aos/time/time.h
index 8462625..f0b3a06 100644
--- a/aos/time/time.h
+++ b/aos/time/time.h
@@ -1,14 +1,14 @@
 #ifndef AOS_TIME_H_
 #define AOS_TIME_H_
 
-#include <sys/time.h>
-
 #include <chrono>
-#include <cstdint>
 #include <ctime>
+#include <limits>
 #include <optional>
 #include <ostream>
-#include <thread>
+#include <string>
+#include <string_view>
+#include <thread>  // IWYU pragma: keep
 
 namespace aos {
 
diff --git a/aos/time/time_test.cc b/aos/time/time_test.cc
index 97116b0..eb97859 100644
--- a/aos/time/time_test.cc
+++ b/aos/time/time_test.cc
@@ -1,13 +1,11 @@
 #include "aos/time/time.h"
 
-#include <thread>
+#include <sys/time.h>
 
-#include "glog/logging.h"
+#include <memory>
+
 #include "gtest/gtest.h"
 
-#include "aos/macros.h"
-#include "aos/util/death_test_log_implementation.h"
-
 namespace aos::time::testing {
 
 namespace chrono = std::chrono;
diff --git a/aos/type_traits/type_traits_test.cpp b/aos/type_traits/type_traits_test.cpp
index 4c060bb..dc18887 100644
--- a/aos/type_traits/type_traits_test.cpp
+++ b/aos/type_traits/type_traits_test.cpp
@@ -1,5 +1,9 @@
 #include "aos/type_traits/type_traits.h"
 
+#include <stdint.h>
+#include <string.h>
+#include <memory>
+
 #include "gtest/gtest.h"
 
 namespace aos {
diff --git a/aos/util/bitpacking.h b/aos/util/bitpacking.h
index 844a940..4c9bfc8 100644
--- a/aos/util/bitpacking.h
+++ b/aos/util/bitpacking.h
@@ -1,6 +1,10 @@
 #ifndef AOS_UTIL_BITPACKING_H_
 #define AOS_UTIL_BITPACKING_H_
 
+#include <stddef.h>
+#include <stdint.h>
+
+#include <algorithm>
 #include <cassert>
 #include <type_traits>
 
diff --git a/aos/util/bitpacking_test.cc b/aos/util/bitpacking_test.cc
index 0f534a1..bcf72b4 100644
--- a/aos/util/bitpacking_test.cc
+++ b/aos/util/bitpacking_test.cc
@@ -2,6 +2,7 @@
 
 #include <array>
 #include <cstdint>
+#include <memory>
 
 #include "gtest/gtest.h"
 
diff --git a/aos/util/clock_publisher.cc b/aos/util/clock_publisher.cc
index f8c731f..2b70768 100644
--- a/aos/util/clock_publisher.cc
+++ b/aos/util/clock_publisher.cc
@@ -1,5 +1,17 @@
 #include "aos/util/clock_publisher.h"
 
+#include <algorithm>
+#include <chrono>
+#include <vector>
+
+#include "flatbuffers/buffer.h"
+#include "flatbuffers/flatbuffer_builder.h"
+#include "flatbuffers/string.h"
+#include "flatbuffers/vector.h"
+
+#include "aos/configuration_generated.h"
+#include "aos/events/context.h"
+
 namespace aos {
 ClockPublisher::ClockPublisher(aos::SimulatedEventLoopFactory *factory,
                                aos::EventLoop *event_loop)
diff --git a/aos/util/clock_publisher.h b/aos/util/clock_publisher.h
index a6d3488..44e1c4a 100644
--- a/aos/util/clock_publisher.h
+++ b/aos/util/clock_publisher.h
@@ -1,5 +1,6 @@
 #ifndef AOS_UTIL_CLOCK_PUBLISHER_H_
 #define AOS_UTIL_CLOCK_PUBLISHER_H_
+#include "aos/events/event_loop.h"
 #include "aos/events/simulated_event_loop.h"
 #include "aos/util/clock_timepoints_generated.h"
 
diff --git a/aos/util/config_validator.cc b/aos/util/config_validator.cc
index df21ba0..0ee1018 100644
--- a/aos/util/config_validator.cc
+++ b/aos/util/config_validator.cc
@@ -1,4 +1,12 @@
+#include <memory>
+
+#include "gflags/gflags.h"
+#include "gtest/gtest.h"
+
+#include "aos/configuration.h"
+#include "aos/flatbuffers.h"
 #include "aos/json_to_flatbuffer.h"
+#include "aos/util/config_validator_config_generated.h"
 #include "aos/util/config_validator_lib.h"
 
 DEFINE_string(config, "", "Name of the config file to replay using.");
diff --git a/aos/util/config_validator_lib.cc b/aos/util/config_validator_lib.cc
index ad85027..eb5205a 100644
--- a/aos/util/config_validator_lib.cc
+++ b/aos/util/config_validator_lib.cc
@@ -1,14 +1,39 @@
 #include "aos/util/config_validator_lib.h"
 
+#include <algorithm>
 #include <chrono>
+#include <cstdlib>
+#include <initializer_list>
+#include <map>
+#include <memory>
+#include <ostream>
+#include <set>
+#include <string>
+#include <string_view>
+#include <utility>
+#include <vector>
 
+#include "flatbuffers/buffer.h"
+#include "flatbuffers/detached_buffer.h"
+#include "flatbuffers/string.h"
+#include "flatbuffers/vector.h"
+#include "gflags/gflags_declare.h"
+#include "glog/logging.h"
+#include "gtest/gtest.h"
+
+#include "aos/events/event_loop.h"
 #include "aos/events/logging/log_reader.h"
-#include "aos/events/logging/log_writer.h"
+#include "aos/events/logging/logfile_sorting.h"
+#include "aos/events/logging/logfile_utils.h"
 #include "aos/events/simulated_event_loop.h"
+#include "aos/flatbuffers/builder.h"
+#include "aos/flatbuffers/static_vector.h"
+#include "aos/json_to_flatbuffer.h"
 #include "aos/network/remote_message_generated.h"
 #include "aos/network/timestamp_channel.h"
 #include "aos/testing/tmpdir.h"
 #include "aos/util/config_validator_config_static.h"
+#include "aos/util/file.h"
 #include "aos/util/simulation_logger.h"
 
 DECLARE_bool(validate_timestamp_logger_nodes);
diff --git a/aos/util/config_validator_lib.h b/aos/util/config_validator_lib.h
index aa855e5..59ef6d5 100644
--- a/aos/util/config_validator_lib.h
+++ b/aos/util/config_validator_lib.h
@@ -1,10 +1,9 @@
 #ifndef AOS_UTIL_CONFIG_VALIDATOR_H_
 #define AOS_UTIL_CONFIG_VALIDATOR_H_
 
-#include "gtest/gtest.h"
-
-#include "aos/configuration.h"
+#include "aos/configuration.h"  // IWYU pragma: keep
 #include "aos/util/config_validator_config_generated.h"
+
 namespace aos::util {
 
 void ConfigIsValid(const aos::Configuration *config,
diff --git a/aos/util/config_validator_lib_test.cc b/aos/util/config_validator_lib_test.cc
index 55b723a..78b9e4c 100644
--- a/aos/util/config_validator_lib_test.cc
+++ b/aos/util/config_validator_lib_test.cc
@@ -1,7 +1,11 @@
 #include "aos/util/config_validator_lib.h"
 
-#include "gtest/gtest-spi.h"
+#include <memory>
 
+#include "gtest/gtest-spi.h"  // IWYU pragma: keep
+#include "gtest/gtest.h"
+
+#include "aos/flatbuffers.h"
 #include "aos/json_to_flatbuffer.h"
 #include "aos/testing/path.h"
 
diff --git a/aos/util/error_counter.h b/aos/util/error_counter.h
index 1e04571..e08c67e 100644
--- a/aos/util/error_counter.h
+++ b/aos/util/error_counter.h
@@ -1,6 +1,12 @@
 #ifndef AOS_UTIL_ERROR_COUNTER_H_
 #define AOS_UTIL_ERROR_COUNTER_H_
-#include "flatbuffers/flatbuffers.h"
+#include <stddef.h>
+
+#include <array>
+
+#include "flatbuffers/buffer.h"
+#include "flatbuffers/flatbuffer_builder.h"
+#include "flatbuffers/vector.h"
 #include "glog/logging.h"
 
 namespace aos::util {
diff --git a/aos/util/error_counter_test.cc b/aos/util/error_counter_test.cc
index 0a786bf..d59142d 100644
--- a/aos/util/error_counter_test.cc
+++ b/aos/util/error_counter_test.cc
@@ -1,5 +1,8 @@
 #include "aos/util/error_counter.h"
 
+#include <algorithm>
+#include <memory>
+
 #include "gtest/gtest.h"
 
 #include "aos/events/event_loop_generated.h"
diff --git a/aos/util/file.cc b/aos/util/file.cc
index ef958c6..b2528a9 100644
--- a/aos/util/file.cc
+++ b/aos/util/file.cc
@@ -1,18 +1,26 @@
 #include "aos/util/file.h"
 
+#include <errno.h>
 #include <fcntl.h>
 #include <fts.h>
+#include <stdio.h>
+#include <string.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <algorithm>
+#include <iterator>
 #include <optional>
+#include <ostream>
 #include <string_view>
 #if __has_feature(memory_sanitizer)
 #include <sanitizer/msan_interface.h>
 #endif
 
+#include "flatbuffers/util.h"
+
 #include "aos/scoped/scoped_fd.h"
 
 namespace aos::util {
diff --git a/aos/util/file.h b/aos/util/file.h
index e0d5c6b..2fc4b2b 100644
--- a/aos/util/file.h
+++ b/aos/util/file.h
@@ -1,18 +1,18 @@
 #ifndef AOS_UTIL_FILE_H_
 #define AOS_UTIL_FILE_H_
 
-#include <fcntl.h>
+#include <stdint.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 
+#include <array>
 #include <memory>
 #include <optional>
 #include <string>
 #include <string_view>
+#include <vector>
 
-#include "absl/strings/numbers.h"
 #include "absl/types/span.h"
-#include "flatbuffers/util.h"
 #include "glog/logging.h"
 
 #include "aos/scoped/scoped_fd.h"
diff --git a/aos/util/file_test.cc b/aos/util/file_test.cc
index b3f1e66..bd319b5 100644
--- a/aos/util/file_test.cc
+++ b/aos/util/file_test.cc
@@ -1,10 +1,12 @@
 #include "aos/util/file.h"
 
+#include <unistd.h>
+
 #include <cstdlib>
 #include <optional>
 #include <string>
 
-#include "gmock/gmock-matchers.h"
+#include "gmock/gmock.h"
 #include "gtest/gtest.h"
 
 #include "aos/realtime.h"
diff --git a/aos/util/filesystem_monitor.cc b/aos/util/filesystem_monitor.cc
index 4efb141..df1dd22 100644
--- a/aos/util/filesystem_monitor.cc
+++ b/aos/util/filesystem_monitor.cc
@@ -1,9 +1,26 @@
+#include <stddef.h>
 #include <sys/statvfs.h>
 
-#include "absl/strings/str_split.h"
-#include "gflags/gflags.h"
+#include <algorithm>
+#include <chrono>
+#include <istream>
+#include <optional>
+#include <string>
+#include <string_view>
+#include <vector>
 
+#include "absl/strings/str_split.h"
+#include "flatbuffers/buffer.h"
+#include "flatbuffers/flatbuffer_builder.h"
+#include "flatbuffers/string.h"
+#include "flatbuffers/vector.h"
+#include "gflags/gflags.h"
+#include "glog/logging.h"
+
+#include "aos/configuration.h"
+#include "aos/events/event_loop.h"
 #include "aos/events/shm_event_loop.h"
+#include "aos/flatbuffers.h"
 #include "aos/init.h"
 #include "aos/util/filesystem_generated.h"
 
diff --git a/aos/util/foxglove_websocket.cc b/aos/util/foxglove_websocket.cc
index 44e24c8..57326de 100644
--- a/aos/util/foxglove_websocket.cc
+++ b/aos/util/foxglove_websocket.cc
@@ -1,6 +1,10 @@
+#include <string>
+
 #include "gflags/gflags.h"
 
+#include "aos/configuration.h"
 #include "aos/events/shm_event_loop.h"
+#include "aos/flatbuffers.h"
 #include "aos/init.h"
 #include "aos/util/foxglove_websocket_lib.h"
 
diff --git a/aos/util/foxglove_websocket_lib.cc b/aos/util/foxglove_websocket_lib.cc
index fd2cfd4..7a825e4 100644
--- a/aos/util/foxglove_websocket_lib.cc
+++ b/aos/util/foxglove_websocket_lib.cc
@@ -1,9 +1,27 @@
 #include "aos/util/foxglove_websocket_lib.h"
 
-#include "absl/strings/escaping.h"
-#include "gflags/gflags.h"
+#include <chrono>
+#include <compare>
+#include <string>
+#include <utility>
 
+#include "absl/container/btree_set.h"
+#include "absl/strings/escaping.h"
+#include "absl/types/span.h"
+#include "flatbuffers/reflection_generated.h"
+#include "flatbuffers/string.h"
+#include "flatbuffers/vector.h"
+#include "gflags/gflags.h"
+#include "glog/logging.h"
+#include "nlohmann/json.hpp"
+#include <foxglove/websocket/server.hpp>
+
+#include "aos/configuration.h"
+#include "aos/events/context.h"
 #include "aos/flatbuffer_merge.h"
+#include "aos/flatbuffers.h"
+#include "aos/json_to_flatbuffer.h"
+#include "aos/time/time.h"
 #include "aos/util/mcap_logger.h"
 
 DEFINE_uint32(sorting_buffer_ms, 100,
diff --git a/aos/util/foxglove_websocket_lib.h b/aos/util/foxglove_websocket_lib.h
index 2590e27..6836786 100644
--- a/aos/util/foxglove_websocket_lib.h
+++ b/aos/util/foxglove_websocket_lib.h
@@ -1,6 +1,9 @@
 #ifndef AOS_UTIL_FOXGLOVE_WEBSOCKET_LIB_H_
 #define AOS_UTIL_FOXGLOVE_WEBSOCKET_LIB_H_
+#include <stdint.h>
+
 #include <map>
+#include <memory>
 #include <set>
 
 #include "foxglove/websocket/server.hpp"
diff --git a/aos/util/generate_test_log.cc b/aos/util/generate_test_log.cc
index dda7912..106e972 100644
--- a/aos/util/generate_test_log.cc
+++ b/aos/util/generate_test_log.cc
@@ -1,11 +1,16 @@
+#include <chrono>
+#include <memory>
+
 #include "gflags/gflags.h"
 
 #include "aos/configuration.h"
+#include "aos/events/event_loop.h"
 #include "aos/events/logging/log_writer.h"
 #include "aos/events/ping_lib.h"
 #include "aos/events/pong_lib.h"
+#include "aos/events/simulated_event_loop.h"
+#include "aos/flatbuffers.h"
 #include "aos/init.h"
-#include "aos/json_to_flatbuffer.h"
 #include "aos/testing/path.h"
 
 DEFINE_string(output_folder, "",
diff --git a/aos/util/global_factory.h b/aos/util/global_factory.h
index 2a4028e..99dfc2a 100644
--- a/aos/util/global_factory.h
+++ b/aos/util/global_factory.h
@@ -5,6 +5,7 @@
 #include <memory>
 #include <string>
 #include <unordered_map>
+#include <utility>
 
 // // File Usage Description:
 // class ExampleBaseClass { virtual ~ExampleBaseClass(); }
diff --git a/aos/util/log_to_mcap.cc b/aos/util/log_to_mcap.cc
index d0a2415..8661246 100644
--- a/aos/util/log_to_mcap.cc
+++ b/aos/util/log_to_mcap.cc
@@ -1,6 +1,21 @@
+#include <algorithm>
+#include <memory>
+#include <optional>
+#include <ostream>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "flatbuffers/reflection_generated.h"
+#include "gflags/gflags.h"
+#include "glog/logging.h"
+
 #include "aos/configuration.h"
-#include "aos/events/event_loop_generated.h"
+#include "aos/events/event_loop.h"
 #include "aos/events/logging/log_reader.h"
+#include "aos/events/logging/logfile_sorting.h"
+#include "aos/events/simulated_event_loop.h"
+#include "aos/flatbuffers.h"
 #include "aos/init.h"
 #include "aos/util/clock_publisher.h"
 #include "aos/util/clock_timepoints_schema.h"
diff --git a/aos/util/math.h b/aos/util/math.h
index 5a3df11..54bd79a 100644
--- a/aos/util/math.h
+++ b/aos/util/math.h
@@ -3,7 +3,7 @@
 
 #include <cmath>
 
-#include "Eigen/Dense"
+#include "Eigen/Core"
 
 namespace aos::math {
 
diff --git a/aos/util/math_test.cc b/aos/util/math_test.cc
index df68f00..7f3f8b2 100644
--- a/aos/util/math_test.cc
+++ b/aos/util/math_test.cc
@@ -1,5 +1,7 @@
 #include "aos/util/math.h"
 
+#include <memory>
+
 #include "gtest/gtest.h"
 
 namespace aos::math::testing {
diff --git a/aos/util/mcap_logger.cc b/aos/util/mcap_logger.cc
index df2b2d4..0dbb88e 100644
--- a/aos/util/mcap_logger.cc
+++ b/aos/util/mcap_logger.cc
@@ -1,12 +1,30 @@
 #include "aos/util/mcap_logger.h"
 
-#include "absl/strings/str_replace.h"
-#include "lz4/lz4.h"
+#include <algorithm>
+#include <chrono>
+#include <numeric>
+#include <ostream>
+#include <set>
+
+#include "absl/strings/str_cat.h"
+#include "absl/types/span.h"
+#include "flatbuffers/buffer.h"
+#include "flatbuffers/detached_buffer.h"
+#include "flatbuffers/flatbuffer_builder.h"
+#include "flatbuffers/reflection.h"
+#include "flatbuffers/reflection_generated.h"
+#include "flatbuffers/string.h"
+#include "flatbuffers/vector.h"
+#include "gflags/gflags.h"
+#include "glog/logging.h"
+#include "glog/vlog_is_on.h"
 #include "lz4/lz4frame.h"
 #include "nlohmann/json.hpp"
 
+#include "aos/configuration.h"
 #include "aos/configuration_schema.h"
 #include "aos/flatbuffer_merge.h"
+#include "aos/json_to_flatbuffer.h"
 
 DEFINE_uint64(mcap_chunk_size, 10'000'000,
               "Size, in bytes, of individual MCAP chunks");
diff --git a/aos/util/mcap_logger.h b/aos/util/mcap_logger.h
index d9d6f36..c67abda 100644
--- a/aos/util/mcap_logger.h
+++ b/aos/util/mcap_logger.h
@@ -1,12 +1,27 @@
 #ifndef AOS_UTIL_MCAP_LOGGER_H_
 #define AOS_UTIL_MCAP_LOGGER_H_
 
-#include "nlohmann/json.hpp"
+#include <stddef.h>
+#include <stdint.h>
+
+#include <iosfwd>
+#include <map>
+#include <memory>
+#include <optional>
+#include <string>
+#include <string_view>
+#include <utility>
+#include <vector>
+
+#include "nlohmann/json_fwd.hpp"
 
 #include "aos/configuration_generated.h"
+#include "aos/events/context.h"
 #include "aos/events/event_loop.h"
 #include "aos/fast_string_builder.h"
 #include "aos/flatbuffer_utils.h"
+#include "aos/flatbuffers.h"
+#include "aos/time/time.h"
 
 namespace aos {
 
diff --git a/aos/util/mcap_logger_test.cc b/aos/util/mcap_logger_test.cc
index 3684e93..351e124 100644
--- a/aos/util/mcap_logger_test.cc
+++ b/aos/util/mcap_logger_test.cc
@@ -1,9 +1,8 @@
 #include "aos/util/mcap_logger.h"
 
-#include <iostream>
-
 #include "flatbuffers/reflection_generated.h"
 #include "gtest/gtest.h"
+#include "nlohmann/json.hpp"
 
 namespace aos::testing {
 // TODO(james): Write a proper test for the McapLogger itself. However, that
diff --git a/aos/util/options.h b/aos/util/options.h
index f393030..55c48a9 100644
--- a/aos/util/options.h
+++ b/aos/util/options.h
@@ -1,13 +1,8 @@
 #ifndef AOS_UTIL_OPTIONS_H_
 #define AOS_UTIL_OPTIONS_H_
 
-#include <sys/types.h>
-
 namespace aos {
 
-template <class Owner>
-class Options;
-
 // An "option" that can be combined with other options and passed as one
 // argument. This class is designed to emulate integral constants (except be
 // type-safe), so its instances can be combined with operator| (creating an
diff --git a/aos/util/options_test.cc b/aos/util/options_test.cc
index f560fe6..536b319 100644
--- a/aos/util/options_test.cc
+++ b/aos/util/options_test.cc
@@ -1,5 +1,7 @@
 #include "aos/util/options.h"
 
+#include <memory>
+
 #include "gtest/gtest.h"
 
 namespace aos::testing {
diff --git a/aos/util/phased_loop.cc b/aos/util/phased_loop.cc
index 476cc3f..5f87bd0 100644
--- a/aos/util/phased_loop.cc
+++ b/aos/util/phased_loop.cc
@@ -1,5 +1,8 @@
 #include "aos/util/phased_loop.h"
 
+#include <compare>
+#include <ratio>
+
 #include "glog/logging.h"
 
 namespace aos::time {
diff --git a/aos/util/phased_loop.h b/aos/util/phased_loop.h
index dc2dc96..f63481e 100644
--- a/aos/util/phased_loop.h
+++ b/aos/util/phased_loop.h
@@ -1,6 +1,7 @@
 #ifndef AOS_UTIL_PHASED_LOOP_H_
 #define AOS_UTIL_PHASED_LOOP_H_
 
+#include <chrono>
 #include <optional>
 
 #include "aos/time/time.h"
diff --git a/aos/util/phased_loop_test.cc b/aos/util/phased_loop_test.cc
index af33567..e74be4c 100644
--- a/aos/util/phased_loop_test.cc
+++ b/aos/util/phased_loop_test.cc
@@ -1,6 +1,8 @@
 #include "aos/util/phased_loop.h"
 
-#include "glog/logging.h"
+#include <memory>
+#include <ratio>
+
 #include "gtest/gtest.h"
 
 #include "aos/time/time.h"
diff --git a/aos/util/scoped_pipe.cc b/aos/util/scoped_pipe.cc
index d64fad1..a4e5b46 100644
--- a/aos/util/scoped_pipe.cc
+++ b/aos/util/scoped_pipe.cc
@@ -1,6 +1,10 @@
 #include "aos/util/scoped_pipe.h"
 
+#include <errno.h>
 #include <fcntl.h>
+#include <unistd.h>
+
+#include <ostream>
 
 #include "glog/logging.h"
 
diff --git a/aos/util/scoped_pipe.h b/aos/util/scoped_pipe.h
index fb91e02..c6ce0cb 100644
--- a/aos/util/scoped_pipe.h
+++ b/aos/util/scoped_pipe.h
@@ -1,10 +1,12 @@
 #ifndef AOS_UTIL_SCOPED_PIPE_H_
 #define AOS_UTIL_SCOPED_PIPE_H_
 
+#include <stddef.h>
 #include <stdint.h>
 
 #include <memory>
 #include <optional>
+#include <string>
 
 #include "absl/types/span.h"
 
@@ -14,6 +16,7 @@
 class ScopedPipe {
  public:
   class ScopedReadPipe;
+
   class ScopedWritePipe;
 
   struct PipePair {
diff --git a/aos/util/scoped_pipe_test.cc b/aos/util/scoped_pipe_test.cc
index 80059f8..55a8f62 100644
--- a/aos/util/scoped_pipe_test.cc
+++ b/aos/util/scoped_pipe_test.cc
@@ -2,6 +2,7 @@
 
 #include <fcntl.h>
 
+#include <algorithm>
 #include <array>
 #include <string>
 
diff --git a/aos/util/simulation_logger.cc b/aos/util/simulation_logger.cc
index 32ff706..fabfd92 100644
--- a/aos/util/simulation_logger.cc
+++ b/aos/util/simulation_logger.cc
@@ -1,6 +1,14 @@
 #include "aos/util/simulation_logger.h"
 
+#include <algorithm>
+#include <chrono>
+#include <utility>
+
+#include "absl/strings/str_cat.h"
+
+#include "aos/configuration.h"
 #include "aos/events/logging/logfile_utils.h"
+#include "aos/time/time.h"
 
 namespace aos::util {
 LoggerState::LoggerState(aos::SimulatedEventLoopFactory *factory,
diff --git a/aos/util/simulation_logger.h b/aos/util/simulation_logger.h
index af43d02..c1499b8 100644
--- a/aos/util/simulation_logger.h
+++ b/aos/util/simulation_logger.h
@@ -1,9 +1,16 @@
 #ifndef AOS_UTIL_SIMULATION_LOGGER_H_
 #define AOS_UTIL_SIMULATION_LOGGER_H_
+#include <memory>
+#include <string>
 #include <string_view>
+#include <vector>
 
+#include "aos/configuration_generated.h"
+#include "aos/events/event_loop.h"
+#include "aos/events/logging/log_namer.h"
 #include "aos/events/logging/log_writer.h"
 #include "aos/events/simulated_event_loop.h"
+
 namespace aos::util {
 
 class LoggerState {
diff --git a/aos/util/threaded_consumer.h b/aos/util/threaded_consumer.h
index 3bf4f36..471f6e1 100644
--- a/aos/util/threaded_consumer.h
+++ b/aos/util/threaded_consumer.h
@@ -5,6 +5,8 @@
 #include <optional>
 #include <thread>
 
+#include "glog/logging.h"
+
 #include "aos/condition.h"
 #include "aos/containers/ring_buffer.h"
 #include "aos/mutex/mutex.h"
diff --git a/aos/util/threaded_consumer_test.cc b/aos/util/threaded_consumer_test.cc
index 36f3121..27dc183 100644
--- a/aos/util/threaded_consumer_test.cc
+++ b/aos/util/threaded_consumer_test.cc
@@ -1,5 +1,11 @@
 #include "aos/util/threaded_consumer.h"
 
+#include <atomic>
+#include <chrono>
+#include <initializer_list>
+#include <memory>
+#include <ostream>
+
 #include "gtest/gtest.h"
 
 namespace aos::util {
diff --git a/aos/util/threaded_queue.h b/aos/util/threaded_queue.h
index 943609e..1bbde48 100644
--- a/aos/util/threaded_queue.h
+++ b/aos/util/threaded_queue.h
@@ -94,5 +94,5 @@
 
 }  // namespace aos::util
 
-#include "aos/util/threaded_queue_tmpl.h"
-#endif  // AOS_UTIL_THREADED_QUEUE_H_
+#include "aos/util/threaded_queue_tmpl.h"  // IWYU pragma: keep
+#endif                                     // AOS_UTIL_THREADED_QUEUE_H_
diff --git a/aos/util/threaded_queue_test.cc b/aos/util/threaded_queue_test.cc
index c97792c..8fd08e8 100644
--- a/aos/util/threaded_queue_test.cc
+++ b/aos/util/threaded_queue_test.cc
@@ -1,5 +1,9 @@
 #include "aos/util/threaded_queue.h"
 
+#include <atomic>
+#include <memory>
+#include <utility>
+
 #include "gtest/gtest.h"
 
 namespace aos::util {
diff --git a/aos/util/top.cc b/aos/util/top.cc
index c22fee4..10ebd4d 100644
--- a/aos/util/top.cc
+++ b/aos/util/top.cc
@@ -1,16 +1,28 @@
 #include "aos/util/top.h"
 
 #include <dirent.h>
-#include <sys/types.h>  // used for DIR
+#include <errno.h>
 #include <unistd.h>
 
+#include <algorithm>
+#include <array>
+#include <atomic>
 #include <cstring>
+#include <istream>
 #include <queue>
+#include <ratio>
 #include <string>
+#include <string_view>
+#include <vector>
 
+#include "absl/numeric/int128.h"
 #include "absl/strings/numbers.h"
+#include "absl/strings/str_cat.h"
 #include "absl/strings/str_format.h"
 #include "absl/strings/str_split.h"
+#include "flatbuffers/string.h"
+#include "flatbuffers/vector.h"
+#include "glog/logging.h"
 
 #define PF_KTHREAD 0x00200000
 
diff --git a/aos/util/top.h b/aos/util/top.h
index c24d56c..1aaaff0 100644
--- a/aos/util/top.h
+++ b/aos/util/top.h
@@ -1,11 +1,23 @@
 #ifndef AOS_UTIL_TOP_H_
 #define AOS_UTIL_TOP_H_
 
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <chrono>
+#include <functional>
 #include <map>
+#include <optional>
+#include <set>
 #include <string>
+#include <utility>
+
+#include "flatbuffers/buffer.h"
+#include "flatbuffers/flatbuffer_builder.h"
 
 #include "aos/containers/ring_buffer.h"
 #include "aos/events/event_loop.h"
+#include "aos/time/time.h"
 #include "aos/util/process_info_generated.h"
 
 namespace aos::util {
diff --git a/aos/util/top_test.cc b/aos/util/top_test.cc
index ce9986f..7d9d2bb 100644
--- a/aos/util/top_test.cc
+++ b/aos/util/top_test.cc
@@ -1,18 +1,33 @@
 #include "aos/util/top.h"
 
+#include <pthread.h>
+#include <signal.h>
 #include <unistd.h>
 
-#include <array>
+#include <algorithm>
+#include <atomic>
+#include <limits>
+#include <ostream>
 #include <string>
+#include <string_view>
 #include <thread>
+#include <vector>
 
+#include "flatbuffers/string.h"
+#include "flatbuffers/vector.h"
+#include "gflags/gflags.h"
+#include "glog/logging.h"
 #include "gtest/gtest.h"
 #include <gmock/gmock.h>
 
+#include "aos/configuration.h"
 #include "aos/events/shm_event_loop.h"
+#include "aos/flatbuffers.h"
+#include "aos/ipc_lib/shm_base.h"
 #include "aos/json_to_flatbuffer.h"
 #include "aos/testing/path.h"
 #include "aos/testing/tmpdir.h"
+#include "aos/util/file.h"
 
 namespace aos::util::testing {
 
diff --git a/aos/util/trapezoid_profile.cc b/aos/util/trapezoid_profile.cc
index 05e79ca..be61889 100644
--- a/aos/util/trapezoid_profile.cc
+++ b/aos/util/trapezoid_profile.cc
@@ -1,7 +1,15 @@
 #include "aos/util/trapezoid_profile.h"
 
+#include <math.h>
+
+#include <algorithm>
+#include <cstdlib>
+#include <ostream>
+
 #include "glog/logging.h"
 
+#include "aos/time/time.h"
+
 namespace aos::util {
 
 AsymmetricTrapezoidProfile::AsymmetricTrapezoidProfile(
diff --git a/aos/util/trapezoid_profile.h b/aos/util/trapezoid_profile.h
index 621ff30..32b2996 100644
--- a/aos/util/trapezoid_profile.h
+++ b/aos/util/trapezoid_profile.h
@@ -1,10 +1,11 @@
 #ifndef AOS_UTIL_TRAPEZOID_PROFILE_H_
 #define AOS_UTIL_TRAPEZOID_PROFILE_H_
 
-#include "Eigen/Dense"
+#include <chrono>
+
+#include "Eigen/Core"
 
 #include "aos/macros.h"
-#include "aos/time/time.h"
 
 namespace aos::util {
 
diff --git a/aos/util/trapezoid_profile_test.cc b/aos/util/trapezoid_profile_test.cc
index 54ffeb5..32461d3 100644
--- a/aos/util/trapezoid_profile_test.cc
+++ b/aos/util/trapezoid_profile_test.cc
@@ -1,7 +1,11 @@
 #include "aos/util/trapezoid_profile.h"
 
-#include "Eigen/Dense"
-#include "glog/logging.h"
+#include <compare>
+#include <cstdlib>
+#include <memory>
+#include <ratio>
+
+#include "Eigen/Dense"  // IWYU pragma: keep
 #include "gtest/gtest.h"
 
 namespace aos::util::testing {
diff --git a/aos/util/wrapping_counter_test.cc b/aos/util/wrapping_counter_test.cc
index 17605a0..7d452d7 100644
--- a/aos/util/wrapping_counter_test.cc
+++ b/aos/util/wrapping_counter_test.cc
@@ -1,6 +1,6 @@
 #include "aos/util/wrapping_counter.h"
 
-#include <climits>
+#include <memory>
 
 #include "gtest/gtest.h"
 
diff --git a/aos/vision/blob/codec.cc b/aos/vision/blob/codec.cc
index be11281..d3ab72d 100644
--- a/aos/vision/blob/codec.cc
+++ b/aos/vision/blob/codec.cc
@@ -1,5 +1,10 @@
 #include "aos/vision/blob/codec.h"
 
+#include <stddef.h>
+
+#include <utility>
+#include <vector>
+
 namespace aos::vision {
 
 size_t CalculateSize(const BlobList &blob_list) {
diff --git a/aos/vision/blob/codec.h b/aos/vision/blob/codec.h
index 5872b44..1656b4a 100644
--- a/aos/vision/blob/codec.h
+++ b/aos/vision/blob/codec.h
@@ -1,6 +1,9 @@
 #ifndef _AOS_VISION_BLOB_CODEC_H_
 #define _AOS_VISION_BLOB_CODEC_H_
 
+#include <stdint.h>
+#include <string.h>
+
 #include <string>
 
 #include "aos/vision/blob/range_image.h"
diff --git a/aos/vision/blob/codec_test.cc b/aos/vision/blob/codec_test.cc
index 889dfbb..3d483a4 100644
--- a/aos/vision/blob/codec_test.cc
+++ b/aos/vision/blob/codec_test.cc
@@ -1,6 +1,10 @@
 #include "aos/vision/blob/codec.h"
 
+#include <stddef.h>
+
 #include <algorithm>
+#include <utility>
+#include <vector>
 
 #include "gtest/gtest.h"
 
diff --git a/aos/vision/blob/contour.cc b/aos/vision/blob/contour.cc
index 5e82d4c..a789b77 100644
--- a/aos/vision/blob/contour.cc
+++ b/aos/vision/blob/contour.cc
@@ -1,5 +1,7 @@
 #include "aos/vision/blob/contour.h"
 
+#include <vector>
+
 namespace aos::vision {
 
 namespace {
diff --git a/aos/vision/blob/find_blob.cc b/aos/vision/blob/find_blob.cc
index 8ee8e92..29b1640 100644
--- a/aos/vision/blob/find_blob.cc
+++ b/aos/vision/blob/find_blob.cc
@@ -1,5 +1,8 @@
 #include "aos/vision/blob/find_blob.h"
 
+#include <utility>
+#include <vector>
+
 #include "aos/vision/blob/disjoint_set.h"
 
 namespace aos::vision {
diff --git a/aos/vision/blob/hierarchical_contour_merge.cc b/aos/vision/blob/hierarchical_contour_merge.cc
index 06c34d4..c5d3eb9 100644
--- a/aos/vision/blob/hierarchical_contour_merge.cc
+++ b/aos/vision/blob/hierarchical_contour_merge.cc
@@ -1,7 +1,11 @@
 #include "aos/vision/blob/hierarchical_contour_merge.h"
 
+#include <stdint.h>
+
+#include <algorithm>
 #include <cmath>
 #include <queue>
+#include <utility>
 
 #include "aos/vision/blob/disjoint_set.h"
 
diff --git a/aos/vision/blob/move_scale.cc b/aos/vision/blob/move_scale.cc
index 45337fc..ac2c30a 100644
--- a/aos/vision/blob/move_scale.cc
+++ b/aos/vision/blob/move_scale.cc
@@ -1,5 +1,8 @@
 #include "aos/vision/blob/move_scale.h"
 
+#include <algorithm>
+#include <utility>
+
 namespace aos::vision {
 
 RangeImage MoveScale(const RangeImage &img, int dx, int dy, int scale) {
diff --git a/aos/vision/blob/move_scale.h b/aos/vision/blob/move_scale.h
index 94a9e9d..4f38bcf 100644
--- a/aos/vision/blob/move_scale.h
+++ b/aos/vision/blob/move_scale.h
@@ -1,7 +1,6 @@
 #ifndef AOS_VISION_BLOB_MOVE_SCALE_H_
 #define AOS_VISION_BLOB_MOVE_SCALE_H_
 
-#include <limits>
 #include <vector>
 
 #include "aos/vision/blob/range_image.h"
diff --git a/aos/vision/blob/range_image.cc b/aos/vision/blob/range_image.cc
index 92f77cc..ef9cc19 100644
--- a/aos/vision/blob/range_image.cc
+++ b/aos/vision/blob/range_image.cc
@@ -1,7 +1,9 @@
 #include "aos/vision/blob/range_image.h"
 
+#include <stdio.h>
+
 #include <algorithm>
-#include <cmath>
+#include <ostream>
 
 namespace aos::vision {
 namespace {
diff --git a/aos/vision/blob/range_image.h b/aos/vision/blob/range_image.h
index 10e801f..3e8c35c 100644
--- a/aos/vision/blob/range_image.h
+++ b/aos/vision/blob/range_image.h
@@ -1,6 +1,9 @@
 #ifndef _AOS_VISION_BLOB_RANGE_IMAGE_H_
 #define _AOS_VISION_BLOB_RANGE_IMAGE_H_
 
+#include <iosfwd>
+#include <string>
+#include <utility>
 #include <vector>
 
 #include "aos/vision/image/image_types.h"
diff --git a/aos/vision/blob/test_utils.cc b/aos/vision/blob/test_utils.cc
index 0e7240f..54d5fe6 100644
--- a/aos/vision/blob/test_utils.cc
+++ b/aos/vision/blob/test_utils.cc
@@ -1,5 +1,8 @@
 #include "aos/vision/blob/test_utils.h"
 
+#include <utility>
+#include <vector>
+
 namespace aos::vision {
 
 RangeImage LoadFromTestData(int mini, const char *data) {
diff --git a/aos/vision/blob/threshold.cc b/aos/vision/blob/threshold.cc
index 5403bbd..d25ab44 100644
--- a/aos/vision/blob/threshold.cc
+++ b/aos/vision/blob/threshold.cc
@@ -1,5 +1,7 @@
 #include "aos/vision/blob/threshold.h"
 
+#include <string.h>
+
 #include "aos/logging/logging.h"
 
 namespace aos::vision {
diff --git a/aos/vision/blob/threshold.h b/aos/vision/blob/threshold.h
index 95330c5..effd321 100644
--- a/aos/vision/blob/threshold.h
+++ b/aos/vision/blob/threshold.h
@@ -1,11 +1,16 @@
 #ifndef AOS_VISION_BLOB_THRESHOLD_H_
 #define AOS_VISION_BLOB_THRESHOLD_H_
 
+#include <stdint.h>
+
 #include <array>
 #include <condition_variable>
 #include <functional>
 #include <mutex>
 #include <thread>
+#include <type_traits>
+#include <utility>
+#include <vector>
 
 #include "aos/vision/blob/range_image.h"
 #include "aos/vision/image/image_types.h"
diff --git a/aos/vision/blob/threshold_test.cc b/aos/vision/blob/threshold_test.cc
index 4b23f3e..4ec519c 100644
--- a/aos/vision/blob/threshold_test.cc
+++ b/aos/vision/blob/threshold_test.cc
@@ -1,9 +1,11 @@
 #include "aos/vision/blob/threshold.h"
 
+#include <stddef.h>
+
+#include <limits>
 #include <random>
 #include <vector>
 
-#include "gmock/gmock.h"
 #include "gtest/gtest.h"
 
 #include "aos/vision/blob/range_image.h"
diff --git a/aos/vision/blob/transpose.cc b/aos/vision/blob/transpose.cc
index b59e8c5..25fd207 100644
--- a/aos/vision/blob/transpose.cc
+++ b/aos/vision/blob/transpose.cc
@@ -2,6 +2,7 @@
 
 #include <algorithm>
 #include <limits>
+#include <utility>
 
 namespace aos::vision {
 
diff --git a/aos/vision/blob/transpose.h b/aos/vision/blob/transpose.h
index d2b609e..e2ff8b4 100644
--- a/aos/vision/blob/transpose.h
+++ b/aos/vision/blob/transpose.h
@@ -1,6 +1,8 @@
 #ifndef AOS_VISION_BLOB_TRANSPOSE_H_
 #define AOS_VISION_BLOB_TRANSPOSE_H_
 
+#include <vector>
+
 #include "aos/vision/blob/range_image.h"
 
 namespace aos::vision {
diff --git a/aos/vision/blob/transpose_test.cc b/aos/vision/blob/transpose_test.cc
index a4a9705..9eb9bac 100644
--- a/aos/vision/blob/transpose_test.cc
+++ b/aos/vision/blob/transpose_test.cc
@@ -1,6 +1,5 @@
 #include "aos/vision/blob/transpose.h"
 
-#include <algorithm>
 #include <string>
 
 #include "gtest/gtest.h"
diff --git a/aos/vision/events/epoll_events.cc b/aos/vision/events/epoll_events.cc
index 1a5ad7e..ce3e5af 100644
--- a/aos/vision/events/epoll_events.cc
+++ b/aos/vision/events/epoll_events.cc
@@ -1,9 +1,6 @@
 #include "aos/vision/events/epoll_events.h"
 
-#include <fcntl.h>
 #include <sys/epoll.h>
-#include <sys/socket.h>
-#include <sys/types.h>
 
 #include <cstring>
 #include <vector>
diff --git a/aos/vision/events/epoll_events.h b/aos/vision/events/epoll_events.h
index e3eeb85..e78db53 100644
--- a/aos/vision/events/epoll_events.h
+++ b/aos/vision/events/epoll_events.h
@@ -3,9 +3,10 @@
 
 #include <sys/epoll.h>
 
+#include <chrono>
 #include <climits>
+#include <compare>
 #include <cstdint>
-#include <memory>
 #include <vector>
 
 #include "aos/scoped/scoped_fd.h"
diff --git a/aos/vision/events/tcp_client.cc b/aos/vision/events/tcp_client.cc
index 65b646c..3c64add 100644
--- a/aos/vision/events/tcp_client.cc
+++ b/aos/vision/events/tcp_client.cc
@@ -4,14 +4,11 @@
 #include <fcntl.h>
 #include <netdb.h>
 #include <netinet/in.h>
+#include <strings.h>
 #include <sys/socket.h>
-#include <sys/types.h>
-#include <unistd.h>
 
-#include <cerrno>
 #include <cstdio>
 #include <cstdlib>
-#include <cstring>
 
 #include "aos/logging/logging.h"
 
diff --git a/aos/vision/events/tcp_client.h b/aos/vision/events/tcp_client.h
index 16d7265..e89e0fe 100644
--- a/aos/vision/events/tcp_client.h
+++ b/aos/vision/events/tcp_client.h
@@ -1,7 +1,6 @@
 #ifndef _AOS_VISION_DEBUG_TCP_CLIENT_H_
 #define _AOS_VISION_DEBUG_TCP_CLIENT_H_
 
-#include <memory>
 #include <string>
 
 #include "aos/vision/events/epoll_events.h"
diff --git a/aos/vision/events/tcp_server.cc b/aos/vision/events/tcp_server.cc
index fa2a369..38e2874 100644
--- a/aos/vision/events/tcp_server.cc
+++ b/aos/vision/events/tcp_server.cc
@@ -2,17 +2,13 @@
 
 #include <arpa/inet.h>
 #include <fcntl.h>
-#include <netdb.h>
 #include <netinet/in.h>
-#include <sys/epoll.h>
+#include <stdint.h>
+#include <strings.h>
 #include <sys/socket.h>
-#include <sys/types.h>
 #include <unistd.h>
 
 #include <cerrno>
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
 
 #include "aos/logging/logging.h"
 
diff --git a/aos/vision/events/tcp_server.h b/aos/vision/events/tcp_server.h
index 49a5a8c..b901077 100644
--- a/aos/vision/events/tcp_server.h
+++ b/aos/vision/events/tcp_server.h
@@ -2,19 +2,21 @@
 #define _AOS_VISION_EVENTS_TCP_SERVER_H_
 
 #include <memory>
-#include <vector>
 
 #include "aos/vision/events/epoll_events.h"
 #include "aos/vision/events/intrusive_free_list.h"
 
 namespace aos::events {
 
+// IWYU pragma: begin_keep
 // Non-templatized base class of TCP server.
 // TCPServer implements Construct which specializes the client connection
 // based on the specific use-case.
 template <class T>
 class TCPServer;
+// IWYU pragma: end_keep
 class SocketConnection;
+
 class TCPServerBase : public EpollEvent {
  public:
   TCPServerBase(int fd) : EpollEvent(fd) {}
diff --git a/aos/vision/events/udp.cc b/aos/vision/events/udp.cc
index cf7ad23..1b1a053 100644
--- a/aos/vision/events/udp.cc
+++ b/aos/vision/events/udp.cc
@@ -1,6 +1,11 @@
 #include "aos/vision/events/udp.h"
 
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+
 #include <cstring>
+#include <ostream>
 
 #include "glog/logging.h"
 
diff --git a/aos/vision/events/udp.h b/aos/vision/events/udp.h
index 4acb04d..bbe5a54 100644
--- a/aos/vision/events/udp.h
+++ b/aos/vision/events/udp.h
@@ -1,13 +1,7 @@
 #ifndef AOS_VISION_EVENTS_UDP_H_
 #define AOS_VISION_EVENTS_UDP_H_
 
-#include <arpa/inet.h>
-#include <sys/socket.h>
-#include <unistd.h>
-
-#include <cmath>
 #include <string>
-#include <vector>
 
 #include "aos/macros.h"
 #include "aos/scoped/scoped_fd.h"
diff --git a/aos/vision/image/image_dataset.cc b/aos/vision/image/image_dataset.cc
index 82a8886..8eade2b 100644
--- a/aos/vision/image/image_dataset.cc
+++ b/aos/vision/image/image_dataset.cc
@@ -1,5 +1,8 @@
 #include "aos/vision/image/image_dataset.h"
 
+#include <stdlib.h>
+
+#include <cstdio>
 #include <fstream>
 
 #include "aos/vision/image/image_types.h"
diff --git a/aos/vision/image/image_stream.h b/aos/vision/image/image_stream.h
index 5a45c6f..797178f 100644
--- a/aos/vision/image/image_stream.h
+++ b/aos/vision/image/image_stream.h
@@ -1,10 +1,17 @@
 #ifndef AOS_VISION_IMAGE_IMAGE_STREAM_H_
 #define AOS_VISION_IMAGE_IMAGE_STREAM_H_
 
+#include <chrono>
+#include <functional>
 #include <memory>
+#include <string>
+#include <string_view>
+#include <utility>
 
+#include "aos/time/time.h"
 #include "aos/vision/events/epoll_events.h"
 #include "aos/vision/image/camera_params.pb.h"
+#include "aos/vision/image/image_types.h"
 #include "aos/vision/image/reader.h"
 
 namespace aos::vision {
diff --git a/aos/vision/image/jpeg_routines.cc b/aos/vision/image/jpeg_routines.cc
index 9d46895..1c1f738 100644
--- a/aos/vision/image/jpeg_routines.cc
+++ b/aos/vision/image/jpeg_routines.cc
@@ -1,13 +1,8 @@
 #include "aos/vision/image/jpeg_routines.h"
 
-#include <sys/mman.h>
-#include <unistd.h>
-
-#include <cerrno>
 #include <csetjmp>
 #include <cstdint>
 #include <cstdio>
-#include <cstdlib>
 #include <cstring>
 
 #include "third_party/libjpeg/jpeglib.h"
diff --git a/aos/vision/image/jpeg_routines.h b/aos/vision/image/jpeg_routines.h
index 4bac976..755a205 100644
--- a/aos/vision/image/jpeg_routines.h
+++ b/aos/vision/image/jpeg_routines.h
@@ -1,11 +1,6 @@
 #ifndef _AOS_VISION_IMAGE_JPEGROUTINES_H_
 #define _AOS_VISION_IMAGE_JPEGROUTINES_H_
 
-#include <unistd.h>
-
-#include <cstdio>
-#include <cstdlib>
-
 #include "aos/vision/image/image_types.h"
 
 namespace aos::vision {
diff --git a/aos/vision/image/reader.cc b/aos/vision/image/reader.cc
index 3fbcd1d..d216490 100644
--- a/aos/vision/image/reader.cc
+++ b/aos/vision/image/reader.cc
@@ -1,20 +1,19 @@
 #include "aos/vision/image/reader.h"
 
 #include <fcntl.h>
-#include <malloc.h>
+#include <linux/v4l2-controls.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <unistd.h>
 
 #include <cerrno>
 #include <cstdio>
 #include <cstdlib>
 #include <cstring>
+#include <utility>
 
 #include "aos/logging/logging.h"
 #include "aos/time/time.h"
+#include "aos/vision/image/V4L2.h"
 
 #define CLEAR(x) memset(&(x), 0, sizeof(x))
 
diff --git a/aos/vision/image/reader.h b/aos/vision/image/reader.h
index 8f7b6b7..8791403 100644
--- a/aos/vision/image/reader.h
+++ b/aos/vision/image/reader.h
@@ -1,12 +1,13 @@
 #ifndef AOS_VISION_IMAGE_READER_H_
 #define AOS_VISION_IMAGE_READER_H_
 
+#include <linux/videodev2.h>
+
 #include <cinttypes>
 #include <functional>
 #include <string>
 
 #include "aos/time/time.h"
-#include "aos/vision/image/V4L2.h"
 #include "aos/vision/image/camera_params.pb.h"
 #include "aos/vision/image/image_types.h"
 
@@ -52,6 +53,7 @@
   // The number of buffers currently queued in v4l2.
   uint32_t queued_;
   struct Buffer;
+
   // TODO(parker): This should be a smart pointer, but it cannot
   // because the buffers are not ummapped.
   Buffer *buffers_;
diff --git a/aos/vision/math/vector.h b/aos/vision/math/vector.h
index ce29901..04203e6 100644
--- a/aos/vision/math/vector.h
+++ b/aos/vision/math/vector.h
@@ -1,9 +1,12 @@
 #ifndef AOS_VISION_MATH_VECTOR_H_
 #define AOS_VISION_MATH_VECTOR_H_
 
+#include <algorithm>
 #include <cmath>
+#include <utility>
 
-#include "Eigen/Dense"
+#include "Eigen/Core"
+#include "Eigen/Geometry"
 
 namespace aos::vision {
 
diff --git a/aos/vision/math/vector_test.cc b/aos/vision/math/vector_test.cc
index 214a50c..d137d5e 100644
--- a/aos/vision/math/vector_test.cc
+++ b/aos/vision/math/vector_test.cc
@@ -1,5 +1,7 @@
 #include "aos/vision/math/vector.h"
 
+#include <memory>
+
 #include "gtest/gtest.h"
 
 namespace aos::vision::testing {
diff --git a/aos/vision/tools/camera_primer.cc b/aos/vision/tools/camera_primer.cc
index fcd7d0b..d409d2d 100644
--- a/aos/vision/tools/camera_primer.cc
+++ b/aos/vision/tools/camera_primer.cc
@@ -1,7 +1,13 @@
-#include "aos/logging/implementations.h"
-#include "aos/logging/logging.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <string>
+
+#include "aos/time/time.h"
 #include "aos/vision/events/epoll_events.h"
+#include "aos/vision/image/camera_params.pb.h"
 #include "aos/vision/image/image_stream.h"
+#include "aos/vision/image/image_types.h"
 
 class ImageStream : public aos::vision::ImageStreamEvent {
  public:
diff --git a/compilers/orin_debian_rootfs.BUILD b/compilers/orin_debian_rootfs.BUILD
index 1d174b8..4c1d75b 100644
--- a/compilers/orin_debian_rootfs.BUILD
+++ b/compilers/orin_debian_rootfs.BUILD
@@ -29587,6 +29587,100 @@
 )
 
 cc_library(
+    name = "usr_lib_aarch64-linux-gnu_libpanelw.so.6.4",
+    srcs = ["usr/lib/aarch64-linux-gnu/libpanelw.so.6.4"],
+    deps = [
+        ":usr_lib_aarch64-linux-gnu_libc.so.6",
+        ":usr_lib_aarch64-linux-gnu_libncursesw.so.6.4",
+        ":usr_lib_aarch64-linux-gnu_libtinfo.so.6.4",
+    ],
+)
+
+cc_library(
+    name = "usr_lib_aarch64-linux-gnu_libc.so.6",
+    srcs = ["usr/lib/aarch64-linux-gnu/libc.so.6"],
+    deps = [
+        ":usr_lib_aarch64-linux-gnu_ld-linux-aarch64.so.1",
+    ],
+)
+
+cc_library(
+    name = "usr_lib_aarch64-linux-gnu_ld-linux-aarch64.so.1",
+    srcs = ["usr/lib/aarch64-linux-gnu/ld-linux-aarch64.so.1"],
+    deps = [
+    ],
+)
+
+cc_library(
+    name = "usr_lib_aarch64-linux-gnu_libtinfo.so.6.4",
+    srcs = ["usr/lib/aarch64-linux-gnu/libtinfo.so.6.4"],
+    deps = [
+        ":usr_lib_aarch64-linux-gnu_ld-linux-aarch64.so.1",
+        ":usr_lib_aarch64-linux-gnu_libc.so.6",
+    ],
+)
+
+cc_library(
+    name = "usr_lib_aarch64-linux-gnu_libncursesw.so.6.4",
+    srcs = ["usr/lib/aarch64-linux-gnu/libncursesw.so.6.4"],
+    deps = [
+        ":usr_lib_aarch64-linux-gnu_ld-linux-aarch64.so.1",
+        ":usr_lib_aarch64-linux-gnu_libc.so.6",
+        ":usr_lib_aarch64-linux-gnu_libtinfo.so.6.4",
+    ],
+)
+
+cc_library(
+    name = "usr_lib_aarch64-linux-gnu_libmenuw.so.6.4",
+    srcs = ["usr/lib/aarch64-linux-gnu/libmenuw.so.6.4"],
+    deps = [
+        ":usr_lib_aarch64-linux-gnu_ld-linux-aarch64.so.1",
+        ":usr_lib_aarch64-linux-gnu_libc.so.6",
+        ":usr_lib_aarch64-linux-gnu_libncursesw.so.6.4",
+        ":usr_lib_aarch64-linux-gnu_libtinfo.so.6.4",
+    ],
+)
+
+cc_library(
+    name = "usr_lib_aarch64-linux-gnu_libformw.so.6.4",
+    srcs = ["usr/lib/aarch64-linux-gnu/libformw.so.6.4"],
+    deps = [
+        ":usr_lib_aarch64-linux-gnu_ld-linux-aarch64.so.1",
+        ":usr_lib_aarch64-linux-gnu_libc.so.6",
+        ":usr_lib_aarch64-linux-gnu_libncursesw.so.6.4",
+        ":usr_lib_aarch64-linux-gnu_libtinfo.so.6.4",
+    ],
+)
+
+cc_library(
+    name = "usr_lib_aarch64-linux-gnu_libpcre2-32.so.0.11.2",
+    srcs = ["usr/lib/aarch64-linux-gnu/libpcre2-32.so.0.11.2"],
+    deps = [
+        ":usr_lib_aarch64-linux-gnu_ld-linux-aarch64.so.1",
+        ":usr_lib_aarch64-linux-gnu_libc.so.6",
+    ],
+)
+
+cc_library(
+    name = "usr_lib_aarch64-linux-gnu_libpcre2-posix.so.3.0.4",
+    srcs = ["usr/lib/aarch64-linux-gnu/libpcre2-posix.so.3.0.4"],
+    deps = [
+        ":usr_lib_aarch64-linux-gnu_ld-linux-aarch64.so.1",
+        ":usr_lib_aarch64-linux-gnu_libc.so.6",
+        ":usr_lib_aarch64-linux-gnu_libpcre2-8.so.0.11.2",
+    ],
+)
+
+cc_library(
+    name = "usr_lib_aarch64-linux-gnu_libpcre2-8.so.0.11.2",
+    srcs = ["usr/lib/aarch64-linux-gnu/libpcre2-8.so.0.11.2"],
+    deps = [
+        ":usr_lib_aarch64-linux-gnu_ld-linux-aarch64.so.1",
+        ":usr_lib_aarch64-linux-gnu_libc.so.6",
+    ],
+)
+
+cc_library(
     name = "usr_lib_aarch64-linux-gnu_libopencv_shape.so.4.6.0-lib",
     srcs = ["usr/lib/aarch64-linux-gnu/libopencv_shape.so.4.6.0"],
     deps = [
diff --git a/debian/nlopt.BUILD b/debian/nlopt.BUILD
deleted file mode 100644
index 4648561..0000000
--- a/debian/nlopt.BUILD
+++ /dev/null
@@ -1,148 +0,0 @@
-genrule(
-    name = "empty_nlopt_config",
-    outs = ["build/nlopt_config.h"],
-    cmd = "echo > $(OUTS)",
-)
-
-cc_library(
-    name = "nlopt",
-    srcs = [
-        "build/nlopt_config.h",
-        "src/algs/ags/ags.cc",
-        "src/algs/ags/ags.h",
-        "src/algs/ags/data_types.hpp",
-        "src/algs/ags/evolvent.cc",
-        "src/algs/ags/evolvent.hpp",
-        "src/algs/ags/local_optimizer.cc",
-        "src/algs/ags/local_optimizer.hpp",
-        "src/algs/ags/solver.cc",
-        "src/algs/ags/solver.hpp",
-        "src/algs/auglag/auglag.c",
-        "src/algs/auglag/auglag.h",
-        "src/algs/bobyqa/bobyqa.c",
-        "src/algs/bobyqa/bobyqa.h",
-        "src/algs/cdirect/cdirect.c",
-        "src/algs/cdirect/cdirect.h",
-        "src/algs/cdirect/hybrid.c",
-        "src/algs/cobyla/cobyla.c",
-        "src/algs/cobyla/cobyla.h",
-        "src/algs/crs/crs.c",
-        "src/algs/crs/crs.h",
-        "src/algs/direct/DIRect.c",
-        "src/algs/direct/DIRserial.c",
-        "src/algs/direct/DIRsubrout.c",
-        "src/algs/direct/direct.h",
-        "src/algs/direct/direct-internal.h",
-        "src/algs/direct/direct_wrap.c",
-        "src/algs/esch/esch.c",
-        "src/algs/esch/esch.h",
-        "src/algs/isres/isres.c",
-        "src/algs/isres/isres.h",
-        "src/algs/luksan/luksan.h",
-        "src/algs/luksan/mssubs.c",
-        "src/algs/luksan/plip.c",
-        "src/algs/luksan/plis.c",
-        "src/algs/luksan/pnet.c",
-        "src/algs/luksan/pssubs.c",
-        "src/algs/mlsl/mlsl.c",
-        "src/algs/mlsl/mlsl.h",
-        "src/algs/mma/ccsa_quadratic.c",
-        "src/algs/mma/mma.c",
-        "src/algs/mma/mma.h",
-        "src/algs/neldermead/neldermead.h",
-        "src/algs/neldermead/nldrmd.c",
-        "src/algs/neldermead/sbplx.c",
-        "src/algs/newuoa/newuoa.c",
-        "src/algs/newuoa/newuoa.h",
-        "src/algs/praxis/praxis.c",
-        "src/algs/praxis/praxis.h",
-        "src/algs/slsqp/slsqp.c",
-        "src/algs/slsqp/slsqp.h",
-        "src/algs/stogo/global.cc",
-        "src/algs/stogo/global.h",
-        "src/algs/stogo/linalg.cc",
-        "src/algs/stogo/linalg.h",
-        "src/algs/stogo/local.cc",
-        "src/algs/stogo/local.h",
-        "src/algs/stogo/stogo.cc",
-        "src/algs/stogo/stogo.h",
-        "src/algs/stogo/stogo_config.h",
-        "src/algs/stogo/tools.cc",
-        "src/algs/stogo/tools.h",
-        "src/api/deprecated.c",
-        "src/api/f77api.c",
-        "src/api/f77funcs.h",
-        "src/api/f77funcs_.h",
-        "src/api/general.c",
-        "src/api/nlopt-internal.h",
-        "src/api/optimize.c",
-        "src/api/options.c",
-        "src/util/mt19937ar.c",
-        "src/util/nlopt-util.h",
-        "src/util/qsort_r.c",
-        "src/util/redblack.c",
-        "src/util/redblack.h",
-        "src/util/rescale.c",
-        "src/util/soboldata.h",
-        "src/util/sobolseq.c",
-        "src/util/stop.c",
-        "src/util/timer.c",
-    ],
-    hdrs = ["src/api/nlopt.h"],
-    copts = [
-        "-Wno-format-nonliteral",
-        "-DBUGFIX_VERSION=0",
-        "-DHAVE_COPYSIGN",
-        "-DHAVE_DLFCN_H",
-        "-DHAVE_FPCLASSIFY",
-        "-DHAVE_GETOPT_H",
-        "-DHAVE_GETOPT",
-        "-DHAVE_GETPID",
-        "-DHAVE_GETTID_SYSCALL=1",
-        "-DHAVE_GETTIMEOFDAY",
-        "-DHAVE_INTTYPES_H",
-        "-DHAVE_ISINF",
-        "-DHAVE_ISNAN",
-        "-DHAVE_MEMORY_H",
-        "-DHAVE_QSORT_R",
-        "-DHAVE_STDINT_H",
-        "-DHAVE_STDLIB_H",
-        "-DHAVE_STRINGS_H",
-        "-DHAVE_STRING_H",
-        "-DHAVE_SYS_STAT_H",
-        "-DHAVE_SYS_TYPES_H",
-        "-DHAVE_SYS_TIME_H",
-        "-DHAVE_TIME",
-        "-DHAVE_UINT32_T",
-        "-DHAVE_UNISTD_H",
-        "-DMAJOR_VERSION=2",
-        "-DMINOR_VERSION=7",
-        "-DTHREADLOCAL=__thread",
-        "-DTIME_WITH_SYS_TIME",
-        "-DNLOPT_CXX11",
-        "-DNLOPT_CXX",
-    ],
-    includes = [
-        "build",
-        "src/algs/ags",
-        "src/algs/auglag",
-        "src/algs/bobyqa",
-        "src/algs/cdirect",
-        "src/algs/cobyla",
-        "src/algs/crs",
-        "src/algs/direct",
-        "src/algs/esch",
-        "src/algs/isres",
-        "src/algs/luksan",
-        "src/algs/mlsl",
-        "src/algs/mma",
-        "src/algs/neldermead",
-        "src/algs/newuoa",
-        "src/algs/praxis",
-        "src/algs/slsqp",
-        "src/algs/stogo",
-        "src/api",
-        "src/util",
-    ],
-    visibility = ["//visibility:public"],
-)
diff --git a/debian/nlopt.patch b/debian/nlopt.patch
deleted file mode 100644
index 9b60608..0000000
--- a/debian/nlopt.patch
+++ /dev/null
@@ -1,13 +0,0 @@
-diff --git a/src/algs/ags/solver.cc b/src/algs/ags/solver.cc
-index 63b8760..b837112 100644
---- a/src/algs/ags/solver.cc
-+++ b/src/algs/ags/solver.cc
-@@ -38,6 +38,8 @@ namespace
-         mRightBound = rightBound;
-       }
- 
-+      virtual ~ProblemInternal() {}
-+
-       double Calculate(const double* y, int fNumber) const
-       {
-         return mFunctions[fNumber](y);
diff --git a/debian/symengine.BUILD b/debian/symengine.BUILD
new file mode 100644
index 0000000..0ccd7fd
--- /dev/null
+++ b/debian/symengine.BUILD
@@ -0,0 +1,571 @@
+load("@bazel_skylib//rules:write_file.bzl", "write_file")
+
+genrule(
+    name = "symengine_config_h_gen",
+    srcs = ["symengine/symengine_config.h.in"],
+    outs = ["symengine/symengine_config.h"],
+    cmd = "|".join(
+        [
+            "cat $(SRCS)",
+            "sed 's/$${SYMENGINE_MAJOR_VERSION}/0/'",
+            "sed 's/$${SYMENGINE_MINOR_VERSION}/11/'",
+            "sed 's/$${SYMENGINE_PATCH_VERSION}/2/'",
+            "sed 's/$${SYMENGINE_VERSION}/0.11.2/'",
+            "sed 's/$${SYMENGINE_INTEGER_CLASS}/GMP/'",
+            "sed 's/$${SYMENGINE_SIZEOF_LONG_DOUBLE}/16/'",
+        ] + [
+            "sed 's/#cmakedefine " + x + "/\\/* #undef " + x + " *\\//'"
+            for x in [
+                "WITH_SYMENGINE_ASSERT",
+                "WITH_SYMENGINE_TEUCHOS",
+                "WITH_SYMENGINE_THREAD_SAFE",
+                "HAVE_SYMENGINE_ECM",
+                "HAVE_SYMENGINE_PRIMESIEVE",
+                "WITH_SYMENGINE_VIRTUAL_TYPEID",
+                "HAVE_SYMENGINE_FLINT",
+                "HAVE_SYMENGINE_ARB",
+                "HAVE_SYMENGINE_PIRANHA",
+                "HAVE_SYMENGINE_BOOST",
+                "HAVE_SYMENGINE_LLVM",
+                "HAVE_C_FUNCTION_NOT_FUNC",
+                # TODO(austin): Turn these on at some point...
+                "HAVE_SYMENGINE_MPFR",
+                "HAVE_SYMENGINE_MPC",
+            ]
+        ] + [
+            "sed 's/#cmakedefine " + x + "/#define " + x + "/'"
+            for x in [
+                "HAVE_SYMENGINE_GMP",
+                "WITH_SYMENGINE_RCP",
+                "HAVE_SYMENGINE_PTHREAD",
+                "HAVE_DEFAULT_CONSTRUCTORS",
+                "HAVE_SYMENGINE_NOEXCEPT",
+                "HAVE_SYMENGINE_IS_CONSTRUCTIBLE",
+                "HAVE_SYMENGINE_RESERVE",
+                "HAVE_SYMENGINE_STD_TO_STRING",
+            ]
+        ] + [
+            " cat - > $(OUTS)",
+        ],
+    ),
+)
+
+write_file(
+    name = "symengine_export_h",
+    out = "symengine/symengine_export.h",
+    content = [
+        "",
+        "#ifndef SYMENGINE_EXPORT_H",
+        "#define SYMENGINE_EXPORT_H",
+        "",
+        "#ifdef SYMENGINE_STATIC_DEFINE",
+        "#  define SYMENGINE_EXPORT",
+        "#  define SYMENGINE_NO_EXPORT",
+        "#else",
+        "#  ifndef SYMENGINE_EXPORT",
+        "#    ifdef symengine_EXPORTS",
+        "        /* We are building this library */",
+        "#      define SYMENGINE_EXPORT",
+        "#    else",
+        "        /* We are using this library */",
+        "#      define SYMENGINE_EXPORT",
+        "#    endif",
+        "#  endif",
+        "",
+        "#  ifndef SYMENGINE_NO_EXPORT",
+        "#    define SYMENGINE_NO_EXPORT",
+        "#  endif",
+        "#endif",
+        "",
+        "#ifndef SYMENGINE_DEPRECATED",
+        "#  define SYMENGINE_DEPRECATED __attribute__ ((__deprecated__))",
+        "#endif",
+        "",
+        "#ifndef SYMENGINE_DEPRECATED_EXPORT",
+        "#  define SYMENGINE_DEPRECATED_EXPORT SYMENGINE_EXPORT SYMENGINE_DEPRECATED",
+        "#endif",
+        "",
+        "#ifndef SYMENGINE_DEPRECATED_NO_EXPORT",
+        "#  define SYMENGINE_DEPRECATED_NO_EXPORT SYMENGINE_NO_EXPORT SYMENGINE_DEPRECATED",
+        "#endif",
+        "",
+        "#if 0 /* DEFINE_NO_DEPRECATED */",
+        "#  ifndef SYMENGINE_NO_DEPRECATED",
+        "#    define SYMENGINE_NO_DEPRECATED",
+        "#  endif",
+        "#endif",
+        "",
+        "#endif /* SYMENGINE_EXPORT_H */",
+    ],
+    is_executable = False,
+)
+
+cc_library(
+    name = "cerial",
+    hdrs = [
+        "symengine/utilities/cereal/include/cereal/access.hpp",
+        "symengine/utilities/cereal/include/cereal/archives/adapters.hpp",
+        "symengine/utilities/cereal/include/cereal/archives/binary.hpp",
+        "symengine/utilities/cereal/include/cereal/archives/json.hpp",
+        "symengine/utilities/cereal/include/cereal/archives/portable_binary.hpp",
+        "symengine/utilities/cereal/include/cereal/archives/xml.hpp",
+        "symengine/utilities/cereal/include/cereal/cereal.hpp",
+        "symengine/utilities/cereal/include/cereal/details/helpers.hpp",
+        "symengine/utilities/cereal/include/cereal/details/polymorphic_impl.hpp",
+        "symengine/utilities/cereal/include/cereal/details/polymorphic_impl_fwd.hpp",
+        "symengine/utilities/cereal/include/cereal/details/static_object.hpp",
+        "symengine/utilities/cereal/include/cereal/details/traits.hpp",
+        "symengine/utilities/cereal/include/cereal/details/util.hpp",
+        "symengine/utilities/cereal/include/cereal/macros.hpp",
+        "symengine/utilities/cereal/include/cereal/specialize.hpp",
+        "symengine/utilities/cereal/include/cereal/types/array.hpp",
+        "symengine/utilities/cereal/include/cereal/types/atomic.hpp",
+        "symengine/utilities/cereal/include/cereal/types/base_class.hpp",
+        "symengine/utilities/cereal/include/cereal/types/bitset.hpp",
+        "symengine/utilities/cereal/include/cereal/types/boost_variant.hpp",
+        "symengine/utilities/cereal/include/cereal/types/chrono.hpp",
+        "symengine/utilities/cereal/include/cereal/types/common.hpp",
+        "symengine/utilities/cereal/include/cereal/types/complex.hpp",
+        "symengine/utilities/cereal/include/cereal/types/concepts/pair_associative_container.hpp",
+        "symengine/utilities/cereal/include/cereal/types/deque.hpp",
+        "symengine/utilities/cereal/include/cereal/types/forward_list.hpp",
+        "symengine/utilities/cereal/include/cereal/types/functional.hpp",
+        "symengine/utilities/cereal/include/cereal/types/list.hpp",
+        "symengine/utilities/cereal/include/cereal/types/map.hpp",
+        "symengine/utilities/cereal/include/cereal/types/memory.hpp",
+        "symengine/utilities/cereal/include/cereal/types/optional.hpp",
+        "symengine/utilities/cereal/include/cereal/types/polymorphic.hpp",
+        "symengine/utilities/cereal/include/cereal/types/queue.hpp",
+        "symengine/utilities/cereal/include/cereal/types/set.hpp",
+        "symengine/utilities/cereal/include/cereal/types/stack.hpp",
+        "symengine/utilities/cereal/include/cereal/types/string.hpp",
+        "symengine/utilities/cereal/include/cereal/types/tuple.hpp",
+        "symengine/utilities/cereal/include/cereal/types/unordered_map.hpp",
+        "symengine/utilities/cereal/include/cereal/types/unordered_set.hpp",
+        "symengine/utilities/cereal/include/cereal/types/utility.hpp",
+        "symengine/utilities/cereal/include/cereal/types/valarray.hpp",
+        "symengine/utilities/cereal/include/cereal/types/variant.hpp",
+        "symengine/utilities/cereal/include/cereal/types/vector.hpp",
+        "symengine/utilities/cereal/include/cereal/version.hpp",
+    ],
+    includes = [
+        "symengine/utilities/cereal/include",
+    ],
+)
+
+cc_library(
+    name = "symengine",
+    srcs = [
+        "symengine/add.cpp",
+        "symengine/assumptions.cpp",
+        "symengine/basic.cpp",
+        "symengine/complex.cpp",
+        "symengine/complex_double.cpp",
+        "symengine/constants.cpp",
+        "symengine/cse.cpp",
+        "symengine/cwrapper.cpp",
+        "symengine/dense_matrix.cpp",
+        "symengine/derivative.cpp",
+        "symengine/dict.cpp",
+        "symengine/diophantine.cpp",
+        "symengine/eval.cpp",
+        "symengine/eval_double.cpp",
+        "symengine/expand.cpp",
+        "symengine/expression.cpp",
+        "symengine/fields.cpp",
+        "symengine/finitediff.cpp",
+        "symengine/functions.cpp",
+        "symengine/infinity.cpp",
+        "symengine/integer.cpp",
+        "symengine/logic.cpp",
+        "symengine/matrices/conjugate_matrix.cpp",
+        "symengine/matrices/diagonal_matrix.cpp",
+        "symengine/matrices/hadamard_product.cpp",
+        "symengine/matrices/identity_matrix.cpp",
+        "symengine/matrices/immutable_dense_matrix.cpp",
+        "symengine/matrices/is_diagonal.cpp",
+        "symengine/matrices/is_lower.cpp",
+        "symengine/matrices/is_real.cpp",
+        "symengine/matrices/is_square.cpp",
+        "symengine/matrices/is_symmetric.cpp",
+        "symengine/matrices/is_toeplitz.cpp",
+        "symengine/matrices/is_upper.cpp",
+        "symengine/matrices/is_zero.cpp",
+        "symengine/matrices/matrix_add.cpp",
+        "symengine/matrices/matrix_mul.cpp",
+        "symengine/matrices/matrix_symbol.cpp",
+        "symengine/matrices/size.cpp",
+        "symengine/matrices/trace.cpp",
+        "symengine/matrices/transpose.cpp",
+        "symengine/matrices/zero_matrix.cpp",
+        "symengine/matrix.cpp",
+        "symengine/monomials.cpp",
+        "symengine/mp_wrapper.cpp",
+        "symengine/mul.cpp",
+        "symengine/nan.cpp",
+        "symengine/ntheory.cpp",
+        "symengine/ntheory_funcs.cpp",
+        "symengine/number.cpp",
+        "symengine/numer_denom.cpp",
+        "symengine/parser/parser.cpp",
+        "symengine/parser/parser.tab.cc",
+        "symengine/parser/parser_old.cpp",
+        "symengine/parser/sbml/sbml_parser.cpp",
+        "symengine/parser/sbml/sbml_parser.tab.cc",
+        "symengine/parser/sbml/sbml_tokenizer.cpp",
+        "symengine/parser/tokenizer.cpp",
+        "symengine/polys/basic_conversions.cpp",
+        "symengine/polys/msymenginepoly.cpp",
+        "symengine/polys/uexprpoly.cpp",
+        "symengine/polys/uintpoly.cpp",
+        "symengine/polys/uratpoly.cpp",
+        "symengine/pow.cpp",
+        "symengine/prime_sieve.cpp",
+        "symengine/printers/codegen.cpp",
+        "symengine/printers/latex.cpp",
+        "symengine/printers/mathml.cpp",
+        "symengine/printers/sbml.cpp",
+        "symengine/printers/stringbox.cpp",
+        "symengine/printers/strprinter.cpp",
+        "symengine/printers/unicode.cpp",
+        "symengine/rational.cpp",
+        "symengine/real_double.cpp",
+        "symengine/refine.cpp",
+        "symengine/rewrite.cpp",
+        "symengine/rings.cpp",
+        "symengine/series.cpp",
+        "symengine/series_generic.cpp",
+        "symengine/set_funcs.cpp",
+        "symengine/sets.cpp",
+        "symengine/simplify.cpp",
+        "symengine/solve.cpp",
+        "symengine/sparse_matrix.cpp",
+        "symengine/symbol.cpp",
+        "symengine/symengine_rcp.cpp",
+        "symengine/test_visitors.cpp",
+        "symengine/tuple.cpp",
+        "symengine/visitor.cpp",
+    ],
+    hdrs = [
+        "symengine/add.h",
+        "symengine/assumptions.h",
+        "symengine/basic.h",
+        "symengine/basic-inl.h",
+        "symengine/basic-methods.inc",
+        "symengine/complex.h",
+        "symengine/complex_double.h",
+        "symengine/complex_mpc.h",
+        "symengine/constants.h",
+        "symengine/cwrapper.h",
+        "symengine/derivative.h",
+        "symengine/dict.h",
+        "symengine/diophantine.h",
+        "symengine/eval.h",
+        "symengine/eval_double.h",
+        "symengine/eval_mpc.h",
+        "symengine/eval_mpfr.h",
+        "symengine/expression.h",
+        "symengine/fields.h",
+        "symengine/finitediff.h",
+        "symengine/functions.h",
+        "symengine/infinity.h",
+        "symengine/integer.h",
+        "symengine/lambda_double.h",
+        "symengine/logic.h",
+        "symengine/matrices/conjugate_matrix.h",
+        "symengine/matrices/diagonal_matrix.h",
+        "symengine/matrices/hadamard_product.h",
+        "symengine/matrices/identity_matrix.h",
+        "symengine/matrices/immutable_dense_matrix.h",
+        "symengine/matrices/matrix_add.h",
+        "symengine/matrices/matrix_expr.h",
+        "symengine/matrices/matrix_mul.h",
+        "symengine/matrices/matrix_symbol.h",
+        "symengine/matrices/size.h",
+        "symengine/matrices/trace.h",
+        "symengine/matrices/transpose.h",
+        "symengine/matrices/zero_matrix.h",
+        "symengine/matrix.h",
+        "symengine/matrix_expressions.h",
+        "symengine/monomials.h",
+        "symengine/mp_class.h",
+        "symengine/mp_wrapper.h",
+        "symengine/mul.h",
+        "symengine/nan.h",
+        "symengine/ntheory.h",
+        "symengine/ntheory_funcs.h",
+        "symengine/number.h",
+        "symengine/parser.h",
+        "symengine/parser/parser.h",
+        "symengine/parser/parser.tab.hh",
+        "symengine/parser/sbml/sbml_parser.h",
+        "symengine/parser/sbml/sbml_parser.tab.hh",
+        "symengine/parser/sbml/sbml_tokenizer.h",
+        "symengine/parser/tokenizer.h",
+        "symengine/polys/basic_conversions.h",
+        "symengine/polys/msymenginepoly.h",
+        "symengine/polys/uexprpoly.h",
+        "symengine/polys/uintpoly.h",
+        "symengine/polys/uintpoly_flint.h",
+        "symengine/polys/uintpoly_piranha.h",
+        "symengine/polys/upolybase.h",
+        "symengine/polys/uratpoly.h",
+        "symengine/polys/usymenginepoly.h",
+        "symengine/pow.h",
+        "symengine/prime_sieve.h",
+        "symengine/printers.h",
+        "symengine/printers/codegen.h",
+        "symengine/printers/latex.h",
+        "symengine/printers/mathml.h",
+        "symengine/printers/sbml.h",
+        "symengine/printers/stringbox.h",
+        "symengine/printers/strprinter.h",
+        "symengine/printers/unicode.h",
+        "symengine/rational.h",
+        "symengine/real_double.h",
+        "symengine/real_mpfr.h",
+        "symengine/refine.h",
+        "symengine/rings.h",
+        "symengine/serialize-cereal.h",
+        "symengine/series.h",
+        "symengine/series_flint.h",
+        "symengine/series_generic.h",
+        "symengine/series_piranha.h",
+        "symengine/series_visitor.h",
+        "symengine/sets.h",
+        "symengine/simplify.h",
+        "symengine/solve.h",
+        "symengine/subs.h",
+        "symengine/symbol.h",
+        "symengine/symengine_assert.h",
+        "symengine/symengine_casts.h",
+        "symengine/symengine_exception.h",
+        "symengine/symengine_rcp.h",
+        "symengine/test_visitors.h",
+        "symengine/tribool.h",
+        "symengine/tuple.h",
+        "symengine/type_codes.inc",
+        "symengine/utilities/stream_fmt.h",
+        "symengine/visitor.h",
+    ],
+    copts = ["-Wno-unused-but-set-variable"],
+    includes = [
+        ".",
+    ],
+    textual_hdrs = [
+        "symengine/as_real_imag.cpp",
+    ],
+    visibility = ["//visibility:public"],
+    deps = [
+        ":cerial",
+        ":config",
+        "@//third_party/gmp",
+    ],
+)
+
+cc_library(
+    name = "config",
+    hdrs = [
+        "symengine/symengine_config.h",
+        "symengine/symengine_export.h",
+    ],
+    includes = [
+        ".",
+    ],
+)
+
+cc_library(
+    name = "catch",
+    srcs = [
+        "symengine/utilities/catch/catch.cpp",
+    ],
+    hdrs = [
+        "symengine/utilities/catch/catch.hpp",
+    ],
+    includes = [
+        "symengine/utilities/catch",
+    ],
+    textual_hdrs = [
+        "symengine/numer_denom.cpp",
+    ],
+    deps = [":symengine"],
+)
+
+[
+    cc_test(
+        name = x,
+        srcs = [
+            "symengine/tests/basic/" + x + ".cpp",
+        ],
+        deps = [
+            ":catch",
+            ":symengine",
+        ],
+    )
+    for x in [
+        "test_basic",
+        "test_arit",
+        "test_poly",
+        "test_series",
+        "test_series_generic",
+        "test_functions",
+        "test_subs",
+        "test_integer",
+        "test_rational",
+        "test_relationals",
+        "test_number",
+        "test_as_numer_denom",
+        "test_parser",
+        "test_serialize-cereal",
+        "test_sbml_parser",
+        "test_sets",
+        "test_fields",
+        "test_infinity",
+        "test_nan",
+        "test_solve",
+        "test_as_real_imag",
+        "test_cse",
+        "test_count_ops",
+        "test_test_visitors",
+        "test_assumptions",
+        "test_refine",
+        "test_simplify",
+        "test_tuple",
+        "test_tribool",
+    ]
+]
+
+[
+    cc_test(
+        name = x,
+        srcs = [
+            "symengine/tests/eval/" + x + ".cpp",
+        ],
+        deps = [
+            ":catch",
+            ":symengine",
+        ],
+    )
+    for x in [
+        "test_evalf",
+        "test_eval_double",
+        "test_lambda_double",
+    ]
+]
+
+cc_test(
+    name = "test_expression",
+    srcs = [
+        "symengine/tests/expression/test_expression.cpp",
+    ],
+    deps = [
+        ":catch",
+        ":symengine",
+    ],
+)
+
+cc_test(
+    name = "test_finitediff",
+    srcs = [
+        "symengine/tests/finitediff/test_finitediff.cpp",
+    ],
+    deps = [
+        ":catch",
+        ":symengine",
+    ],
+)
+
+cc_test(
+    name = "test_logic",
+    srcs = [
+        "symengine/tests/logic/test_logic.cpp",
+    ],
+    deps = [
+        ":catch",
+        ":symengine",
+    ],
+)
+
+[
+    cc_test(
+        name = x,
+        srcs = [
+            "symengine/tests/matrix/" + x + ".cpp",
+        ],
+        deps = [
+            ":catch",
+            ":symengine",
+        ],
+    )
+    for x in [
+        "test_matrix",
+        "test_matrixexpr",
+    ]
+]
+
+[
+    cc_test(
+        name = x,
+        srcs = [
+            "symengine/tests/ntheory/" + x + ".cpp",
+        ],
+        deps = [
+            ":catch",
+            ":symengine",
+        ],
+    )
+    for x in [
+        "test_ntheory",
+        "test_diophantine",
+        "test_ntheory_funcs",
+    ]
+]
+
+[
+    cc_test(
+        name = x,
+        srcs = [
+            "symengine/tests/polynomial/" + x + ".cpp",
+        ],
+        deps = [
+            ":catch",
+            ":symengine",
+        ],
+    )
+    for x in [
+        "test_uintpoly",
+        "test_uratpoly",
+        "test_mintpoly",
+        "test_uexprpoly",
+        "test_mexprpoly",
+        "test_basic_conversions",
+    ]
+]
+
+[
+    cc_test(
+        name = x,
+        srcs = [
+            "symengine/tests/printing/" + x + ".cpp",
+        ],
+        deps = [
+            ":catch",
+            ":symengine",
+        ],
+    )
+    for x in [
+        "test_printing",
+        "test_ccode",
+    ]
+]
+
+cc_test(
+    name = "test_rcp",
+    srcs = [
+        "symengine/tests/rcp/test_rcp.cpp",
+    ],
+    deps = [
+        ":catch",
+        ":symengine",
+    ],
+)
diff --git a/frc971/codelab/basic.cc b/frc971/codelab/basic.cc
index a78da41..9576e6b 100644
--- a/frc971/codelab/basic.cc
+++ b/frc971/codelab/basic.cc
@@ -3,12 +3,12 @@
 namespace frc971::codelab {
 
 Basic::Basic(::aos::EventLoop *event_loop, const ::std::string &name)
-    : frc971::controls::ControlLoop<Goal, Position, Status, Output>(event_loop,
-                                                                    name) {}
+    : frc971::controls::ControlLoop<Goal, Position, StatusStatic, OutputStatic>(
+          event_loop, name) {}
 
 void Basic::RunIteration(const Goal *goal, const Position *position,
-                         aos::Sender<Output>::Builder *output,
-                         aos::Sender<Status>::Builder *status) {
+                         aos::Sender<OutputStatic>::StaticBuilder *output,
+                         aos::Sender<StatusStatic>::StaticBuilder *status) {
   // FIX HERE: Set the intake_voltage to 12 Volts when
   // intake is requested (via intake in goal). Make sure not to set
   // the motor to anything but 0 V when the limit_sensor is pressed.
@@ -19,20 +19,18 @@
   (void)goal, (void)position;
 
   if (output != nullptr) {
-    Output::Builder builder = output->MakeBuilder<Output>();
-
     // FIX HERE: As of now, this sets the intake voltage to 0 in
     // all circumstances. Add to this code to output a different
     // intake voltage depending on the circumstances to make the
     // tests pass.
-    builder.add_intake_voltage(0.0);
+    output->get()->set_intake_voltage(0.0);
 
     // Ignore the return value of Send
-    (void)output->Send(builder.Finish());
+    (void)output->CheckOk(output->Send());
   }
 
   if (status != nullptr) {
-    Status::Builder builder = status->MakeBuilder<Status>();
+    (void)status;
     // FIX HERE: Fill out the Status message! In order to fill the
     // information in the message, use the add_<name of the field>() method
     // on the builder, just like we do with the Output message above.
@@ -40,7 +38,6 @@
     // the name of the field.
 
     // Ignore the return value of Send
-    (void)status->Send(builder.Finish());
   }
 }
 
diff --git a/frc971/codelab/basic.h b/frc971/codelab/basic.h
index 6439d84..3073012 100644
--- a/frc971/codelab/basic.h
+++ b/frc971/codelab/basic.h
@@ -3,23 +3,24 @@
 
 #include "aos/time/time.h"
 #include "frc971/codelab/basic_goal_generated.h"
-#include "frc971/codelab/basic_output_generated.h"
+#include "frc971/codelab/basic_output_static.h"
 #include "frc971/codelab/basic_position_generated.h"
-#include "frc971/codelab/basic_status_generated.h"
+#include "frc971/codelab/basic_status_static.h"
 #include "frc971/control_loops/control_loop.h"
 
 namespace frc971::codelab {
 
 class Basic
-    : public ::frc971::controls::ControlLoop<Goal, Position, Status, Output> {
+    : public ::frc971::controls::ControlLoop<Goal, Position, StatusStatic,
+                                             OutputStatic> {
  public:
   explicit Basic(::aos::EventLoop *event_loop,
                  const ::std::string &name = "/codelab");
 
  protected:
   void RunIteration(const Goal *goal, const Position *position,
-                    aos::Sender<Output>::Builder *output,
-                    aos::Sender<Status>::Builder *status) override;
+                    aos::Sender<OutputStatic>::StaticBuilder *output,
+                    aos::Sender<StatusStatic>::StaticBuilder *status) override;
 };
 
 }  // namespace frc971::codelab
diff --git a/frc971/control_loops/BUILD b/frc971/control_loops/BUILD
index 9ce0e99..ccaac40 100644
--- a/frc971/control_loops/BUILD
+++ b/frc971/control_loops/BUILD
@@ -87,6 +87,7 @@
         "//aos/actions:action_lib",
         "//aos/events:event_loop",
         "//aos/events:shm_event_loop",
+        "//aos/flatbuffers:static_table",
         "//aos/logging",
         "//aos/time",
         "//aos/util:log_interval",
@@ -381,9 +382,11 @@
     name = "runge_kutta",
     hdrs = [
         "runge_kutta.h",
+        "runge_kutta_helpers.h",
     ],
     target_compatible_with = ["@platforms//os:linux"],
     deps = [
+        "@com_github_google_glog//:glog",
         "@org_tuxfamily_eigen//:eigen",
     ],
 )
diff --git a/frc971/control_loops/control_loop-tmpl.h b/frc971/control_loops/control_loop-tmpl.h
index d86c97c..bf2a223 100644
--- a/frc971/control_loops/control_loop-tmpl.h
+++ b/frc971/control_loops/control_loop-tmpl.h
@@ -20,9 +20,8 @@
           class OutputType>
 void ControlLoop<GoalType, PositionType, StatusType,
                  OutputType>::ZeroOutputs() {
-  typename ::aos::Sender<OutputType>::Builder builder =
-      output_sender_.MakeBuilder();
-  builder.CheckOk(builder.Send(Zero(&builder)));
+  auto builder = BuilderType<OutputType>::MakeBuilder(&output_sender_);
+  BuilderType<OutputType>::SendZeroFlatbuffer(this, &builder);
 }
 
 template <class GoalType, class PositionType, class StatusType,
@@ -73,21 +72,20 @@
     outputs_enabled = false;
   }
 
-  typename ::aos::Sender<StatusType>::Builder status =
-      status_sender_.MakeBuilder();
+  StatusBuilder status = BuilderType<StatusType>::MakeBuilder(&status_sender_);
   if (outputs_enabled) {
-    typename ::aos::Sender<OutputType>::Builder output =
-        output_sender_.MakeBuilder();
+    OutputBuilder output =
+        BuilderType<OutputType>::MakeBuilder(&output_sender_);
     RunIteration(goal, &position, &output, &status);
 
-    output.CheckSent();
+    BuilderType<OutputType>::CheckSent(&output);
   } else {
     // The outputs are disabled, so pass nullptr in for the output.
     RunIteration(goal, &position, nullptr, &status);
     ZeroOutputs();
   }
 
-  status.CheckSent();
+  BuilderType<StatusType>::CheckSent(&status);
 }
 
 }  // namespace frc971::controls
diff --git a/frc971/control_loops/control_loop.h b/frc971/control_loops/control_loop.h
index c7b8a6d..e9892a3 100644
--- a/frc971/control_loops/control_loop.h
+++ b/frc971/control_loops/control_loop.h
@@ -6,6 +6,7 @@
 
 #include "aos/actions/actor.h"
 #include "aos/events/event_loop.h"
+#include "aos/flatbuffers/static_table.h"
 #include "aos/time/time.h"
 #include "aos/util/log_interval.h"
 #include "frc971/input/joystick_state_generated.h"
@@ -17,6 +18,56 @@
 constexpr ::std::chrono::nanoseconds kLoopFrequency =
     aos::common::actions::kLoopFrequency;
 
+// In order to support using both "raw" and the static flatbuffer APIs with the
+// outputs of the ControlLoop class (i.e., the Output and Status messages), we
+// need to provide different compile-time code for each option. In order to do
+// this, we set up two different specializations of the BuilderType class, and
+// will select the appropriate one depending on the type of the flatbuffer. The
+// methods and types within BuilderType are then used within the ControlLoop
+// class whenever we need to call methods associated with the flatbuffers or
+// senders themselves.
+template <typename T, class Enable = void>
+struct BuilderType;
+
+template <class GoalType, class PositionType, class StatusType,
+          class OutputType>
+class ControlLoop;
+
+template <typename T>
+struct BuilderType<T, typename std::enable_if_t<
+                          std::is_base_of<flatbuffers::Table, T>::value>> {
+  typedef aos::Sender<T>::Builder Builder;
+  typedef T FlatbufferType;
+  static Builder MakeBuilder(aos::Sender<T> *sender) {
+    return sender->MakeBuilder();
+  }
+  template <class GoalType, class PositionType, class StatusType,
+            class OutputType>
+  static void SendZeroFlatbuffer(
+      ControlLoop<GoalType, PositionType, StatusType, OutputType> *loop,
+      Builder *builder);
+  static void CheckSent(Builder *builder) { builder->CheckSent(); }
+};
+
+template <typename T>
+struct BuilderType<
+    T, typename std::enable_if_t<std::is_base_of<aos::fbs::Table, T>::value>> {
+  typedef aos::Sender<T>::StaticBuilder Builder;
+  typedef T::Flatbuffer FlatbufferType;
+  static Builder MakeBuilder(aos::Sender<T> *sender) {
+    return sender->MakeStaticBuilder();
+  }
+  template <class GoalType, class PositionType, class StatusType,
+            class OutputType>
+  static void SendZeroFlatbuffer(
+      ControlLoop<GoalType, PositionType, StatusType, OutputType> *loop,
+      Builder *builder);
+  static void CheckSent(Builder *builder) {
+    // TODO (niko) create a CheckSent() function for static flatbuffers
+    (void)builder;
+  }
+};
+
 // Provides helper methods to assist in writing control loops.
 // It will then call the RunIteration method every cycle that it has enough
 // valid data for the control loop to run.
@@ -24,6 +75,10 @@
           class OutputType>
 class ControlLoop {
  public:
+  using StatusBuilder = typename BuilderType<StatusType>::Builder;
+  using OutputBuilder = typename BuilderType<OutputType>::Builder;
+  using OutputFlatbufferType = typename BuilderType<OutputType>::FlatbufferType;
+
   ControlLoop(aos::EventLoop *event_loop, const ::std::string &name)
       : event_loop_(event_loop), name_(name) {
     output_sender_ = event_loop_->MakeSender<OutputType>(name_);
@@ -63,9 +118,9 @@
   // Sets the output to zero.
   // Override this if a value of zero (or false) is not "off" for this
   // subsystem.
-  virtual flatbuffers::Offset<OutputType> Zero(
-      typename ::aos::Sender<OutputType>::Builder *builder) {
-    return builder->template MakeBuilder<OutputType>().Finish();
+  virtual flatbuffers::Offset<OutputFlatbufferType> Zero(
+      typename ::aos::Sender<OutputFlatbufferType>::Builder *builder) {
+    return builder->template MakeBuilder<OutputFlatbufferType>().Finish();
   }
 
  protected:
@@ -87,10 +142,8 @@
   // output is going to be ignored and set to 0.
   // status is the status of the control loop.
   // Both output and status should be filled in by the implementation.
-  virtual void RunIteration(
-      const GoalType *goal, const PositionType *position,
-      typename ::aos::Sender<OutputType>::Builder *output,
-      typename ::aos::Sender<StatusType>::Builder *status) = 0;
+  virtual void RunIteration(const GoalType *goal, const PositionType *position,
+                            OutputBuilder *output, StatusBuilder *status) = 0;
 
  private:
   static constexpr ::std::chrono::milliseconds kStaleLogInterval =
@@ -132,6 +185,28 @@
       SimpleLogInterval(kStaleLogInterval, ERROR, "no goal");
 };
 
+template <typename T>
+template <class GoalType, class PositionType, class StatusType,
+          class OutputType>
+void BuilderType<T, typename std::enable_if_t<
+                        std::is_base_of<flatbuffers::Table, T>::value>>::
+    SendZeroFlatbuffer(
+        ControlLoop<GoalType, PositionType, StatusType, OutputType> *loop,
+        Builder *builder) {
+  builder->CheckOk(builder->Send(loop->Zero(builder)));
+}
+
+template <typename T>
+template <class GoalType, class PositionType, class StatusType,
+          class OutputType>
+void BuilderType<
+    T, typename std::enable_if_t<std::is_base_of<aos::fbs::Table, T>::value>>::
+    SendZeroFlatbuffer(ControlLoop<GoalType, PositionType, StatusType,
+                                   OutputType> * /* loop */,
+                       Builder *builder) {
+  builder->CheckOk(builder->Send());
+}
+
 }  // namespace frc971::controls
 
 #include "frc971/control_loops/control_loop-tmpl.h"  // IWYU pragma: export
diff --git a/frc971/control_loops/drivetrain/swerve/BUILD b/frc971/control_loops/drivetrain/swerve/BUILD
deleted file mode 100644
index 5b94fa8..0000000
--- a/frc971/control_loops/drivetrain/swerve/BUILD
+++ /dev/null
@@ -1,13 +0,0 @@
-load("//aos/flatbuffers:generate.bzl", "static_flatbuffer")
-
-package(default_visibility = ["//visibility:public"])
-
-static_flatbuffer(
-    name = "swerve_drivetrain_output_fbs",
-    srcs = ["swerve_drivetrain_output.fbs"],
-)
-
-static_flatbuffer(
-    name = "swerve_drivetrain_position_fbs",
-    srcs = ["swerve_drivetrain_position.fbs"],
-)
diff --git a/frc971/control_loops/drivetrain/swerve/swerve_drivetrain_output.fbs b/frc971/control_loops/drivetrain/swerve/swerve_drivetrain_output.fbs
deleted file mode 100644
index 43ba0ed..0000000
--- a/frc971/control_loops/drivetrain/swerve/swerve_drivetrain_output.fbs
+++ /dev/null
@@ -1,16 +0,0 @@
-namespace frc971.control_loops.drivetrain.swerve;
-
-table SwerveModuleOutput {
-  // Current in Amps.
-  rotation_current:double (id: 0);
-  translation_current:double (id: 1);
-}
-
-table Output {
-  front_left_output:SwerveModuleOutput (id: 0);
-  front_right_output:SwerveModuleOutput (id: 1);
-  back_left_output:SwerveModuleOutput (id: 2);
-  back_right_output:SwerveModuleOutput (id: 3);
-}
-
-root_type Output;
diff --git a/frc971/control_loops/drivetrain/swerve/swerve_drivetrain_position.fbs b/frc971/control_loops/drivetrain/swerve/swerve_drivetrain_position.fbs
deleted file mode 100644
index e0f5571..0000000
--- a/frc971/control_loops/drivetrain/swerve/swerve_drivetrain_position.fbs
+++ /dev/null
@@ -1,22 +0,0 @@
-namespace frc971.control_loops.drivetrain.swerve;
-
-table SwerveModulePosition {
-  // Rotation in radians
-  rotation_encoder:double (id: 0);
-  // Translation in meters
-  translation_encoder:double (id: 1);
-
-  // Speed in radians/s
-  rotation_speed:double (id: 2);
-  // Speed in m/s
-  translation_speed:double (id: 3);
-}
-
-table Position {
-  front_left_position:SwerveModulePosition (id: 0);
-  front_right_position:SwerveModulePosition (id: 1);
-  back_left_position:SwerveModulePosition (id: 2);
-  back_right_position:SwerveModulePosition (id: 3);
-}
-
-root_type Position;
diff --git a/frc971/control_loops/runge_kutta.h b/frc971/control_loops/runge_kutta.h
index ed5a359..173014e 100644
--- a/frc971/control_loops/runge_kutta.h
+++ b/frc971/control_loops/runge_kutta.h
@@ -1,8 +1,11 @@
 #ifndef FRC971_CONTROL_LOOPS_RUNGE_KUTTA_H_
 #define FRC971_CONTROL_LOOPS_RUNGE_KUTTA_H_
 
+#include "glog/logging.h"
 #include <Eigen/Dense>
 
+#include "frc971/control_loops/runge_kutta_helpers.h"
+
 namespace frc971::control_loops {
 
 // Implements Runge Kutta integration (4th order).  fn is the function to
@@ -66,6 +69,144 @@
   return X + dt / 6.0 * (k1 + 2.0 * k2 + 2.0 * k3 + k4);
 }
 
+// Integrates f(t, y) from t0 to t0 + dt using an explicit Runge Kutta 5(4) to
+// implement an adaptive step size.  Translated from Scipy.
+//
+// This uses the Dormand-Prince pair of formulas. The error is controlled
+// assuming accuracy of the fourth-order method accuracy, but steps are taken
+// using the fifth-order accurate formula (local extrapolation is done).  A
+// quartic interpolation polynomial is used for the dense output.
+//
+// fn(t, y) is the function to integrate.  y0 is the initial y, t0 is the
+// initial time, dt is the duration to integrate, rtol is the relative
+// tolerance, and atol is the absolute tolerance.
+template <typename F, typename T>
+T AdaptiveRungeKutta(const F &fn, T y0, double t0, double dt,
+                     double rtol = 1e-3, double atol = 1e-6) {
+  // Multiply steps computed from asymptotic behaviour of errors by this.
+  constexpr double SAFETY = 0.9;
+  // Minimum allowed decrease in a step size.
+  constexpr double MIN_FACTOR = 0.2;
+  // Maximum allowed increase in a step size.
+  constexpr double MAX_FACTOR = 10;
+
+  // Final time
+  const double t_bound = t0 + dt;
+
+  constexpr int order = 5;
+  constexpr int error_estimator_order = 4;
+  constexpr int n_stages = 6;
+  constexpr int states = y0.rows();
+  const double sqrt_rows = std::sqrt(static_cast<double>(states));
+  const Eigen::Matrix<double, 1, n_stages> C =
+      (Eigen::Matrix<double, 1, n_stages>() << 0, 1.0 / 5.0, 3.0 / 10.0,
+       4.0 / 5.0, 8.0 / 9.0, 1.0)
+          .finished();
+
+  const Eigen::Matrix<double, n_stages, order> A =
+      (Eigen::Matrix<double, n_stages, order>() << 0.0, 0.0, 0.0, 0.0, 0.0,
+       1.0 / 5.0, 0.0, 0.0, 0.0, 0.0, 3.0 / 40.0, 9.0 / 40.0, 0.0, 0.0, 0.0,
+       44.0 / 45.0, -56.0 / 15.0, 32.0 / 9.0, 0.0, 0.0, 19372.0 / 6561.0,
+       -25360.0 / 2187.0, 64448.0 / 6561.0, -212.0 / 729.0, 0.0,
+       9017.0 / 3168.0, -355.0 / 33.0, 46732.0 / 5247.0, 49.0 / 176.0,
+       -5103.0 / 18656.0)
+          .finished();
+
+  const Eigen::Matrix<double, 1, n_stages> B =
+      (Eigen::Matrix<double, 1, n_stages>() << 35.0 / 384.0, 0.0,
+       500.0 / 1113.0, 125.0 / 192.0, -2187.0 / 6784.0, 11.0 / 84.0)
+          .finished();
+
+  const Eigen::Matrix<double, 1, n_stages + 1> E =
+      (Eigen::Matrix<double, 1, n_stages + 1>() << -71.0 / 57600.0, 0.0,
+       71.0 / 16695.0, -71.0 / 1920.0, 17253.0 / 339200.0, -22.0 / 525.0,
+       1.0 / 40.0)
+          .finished();
+
+  T f = fn(t0, y0);
+  double h_abs = SelectRungeKuttaInitialStep(fn, t0, y0, f,
+                                             error_estimator_order, rtol, atol);
+  Eigen::Matrix<double, n_stages + 1, states> K;
+
+  Eigen::Matrix<double, states, 1> y = y0;
+  const double error_exponent = -1.0 / (error_estimator_order + 1.0);
+
+  double t = t0;
+  while (true) {
+    if (t >= t_bound) {
+      return y;
+    }
+
+    // Step
+    double min_step =
+        10 * (std::nextafter(t, std::numeric_limits<double>::infinity()) - t);
+
+    // TODO(austin): max_step if we care.
+    if (h_abs < min_step) {
+      h_abs = min_step;
+    }
+
+    bool step_accepted = false;
+    bool step_rejected = false;
+
+    double t_new;
+    Eigen::Matrix<double, states, 1> y_new;
+    Eigen::Matrix<double, states, 1> f_new;
+    while (!step_accepted) {
+      // TODO(austin): Tell the user rather than just explode?
+      CHECK_GE(h_abs, min_step);
+
+      double h = h_abs;
+      t_new = t + h;
+      if (t_new >= t_bound) {
+        t_new = t_bound;
+      }
+      h = t_new - t;
+      h_abs = std::abs(h);
+
+      std::tie(y_new, f_new) =
+          RKStep<states, n_stages, order>(fn, t, y, f, h, A, B, C, K);
+
+      const Eigen::Matrix<double, states, 1> scale =
+          atol + y.array().abs().max(y_new.array().abs()) * rtol;
+
+      double error_norm =
+          (((K.transpose() * E.transpose()) * h).array() / scale.array())
+              .matrix()
+              .norm() /
+          sqrt_rows;
+
+      if (error_norm < 1) {
+        double factor;
+        if (error_norm == 0) {
+          factor = MAX_FACTOR;
+        } else {
+          factor = std::min(MAX_FACTOR,
+                            SAFETY * std::pow(error_norm, error_exponent));
+        }
+
+        if (step_rejected) {
+          factor = std::min(1.0, factor);
+        }
+
+        h_abs *= factor;
+
+        step_accepted = true;
+      } else {
+        h_abs *=
+            std::max(MIN_FACTOR, SAFETY * std::pow(error_norm, error_exponent));
+        step_rejected = true;
+      }
+    }
+
+    t = t_new;
+    y = y_new;
+    f = f_new;
+  }
+
+  return y;
+}
+
 }  // namespace frc971::control_loops
 
 #endif  // FRC971_CONTROL_LOOPS_RUNGE_KUTTA_H_
diff --git a/frc971/control_loops/runge_kutta_helpers.h b/frc971/control_loops/runge_kutta_helpers.h
new file mode 100644
index 0000000..f9a4ecf
--- /dev/null
+++ b/frc971/control_loops/runge_kutta_helpers.h
@@ -0,0 +1,72 @@
+#ifndef FRC971_CONTROL_LOOPS_RUNGE_KUTTA_HELPERS_H_
+#define FRC971_CONTROL_LOOPS_RUNGE_KUTTA_HELPERS_H_
+
+#include "glog/logging.h"
+#include <Eigen/Dense>
+
+namespace frc971::control_loops {
+
+// Returns a reasonable Runge Kutta initial step size. This is translated from
+// scipy.
+template <typename F, typename T>
+double SelectRungeKuttaInitialStep(const F &fn, size_t t0, T y0, T f0,
+                                   int error_estimator_order, double rtol,
+                                   double atol) {
+  constexpr int states = y0.rows();
+  const Eigen::Matrix<double, states, 1> scale =
+      atol + (y0.cwiseAbs().matrix() * rtol).array();
+  const double sqrt_rows = std::sqrt(static_cast<double>(states));
+  const double d0 = (y0.array() / scale.array()).matrix().norm() / sqrt_rows;
+  const double d1 = (f0.array() / scale.array()).matrix().norm() / sqrt_rows;
+  double h0;
+  if (d0 < 1e-5 || d1 < 1e-5) {
+    h0 = 1e-6;
+  } else {
+    h0 = 0.01 * d0 / d1;
+  }
+
+  const Eigen::Matrix<double, states, 1> y1 = y0 + h0 * f0;
+  const Eigen::Matrix<double, states, 1> f1 = fn(t0 + h0, y1);
+  const double d2 =
+      ((f1 - f0).array() / scale.array()).matrix().norm() / sqrt_rows / h0;
+
+  double h1;
+  if (d1 <= 1e-15 && d2 <= 1e-15) {
+    h1 = std::max(1e-6, h0 * 1e-3);
+  } else {
+    h1 = std::pow((0.01 / std::max(d1, d2)),
+                  (1.0 / (error_estimator_order + 1.0)));
+  }
+
+  return std::min(100 * h0, h1);
+}
+
+// Performs a single step of Runge Kutta integration for the adaptive algorithm
+// below. This is translated from scipy.
+template <size_t N, size_t NStages, size_t Order, typename F>
+std::tuple<Eigen::Matrix<double, N, 1>, Eigen::Matrix<double, N, 1>> RKStep(
+    const F &fn, const double t, const Eigen::Matrix<double, N, 1> &y0,
+    const Eigen::Matrix<double, N, 1> &f0, const double h,
+    const Eigen::Matrix<double, NStages, Order> &A,
+    const Eigen::Matrix<double, 1, NStages> &B,
+    const Eigen::Matrix<double, 1, NStages> &C,
+    Eigen::Matrix<double, NStages + 1, N> &K) {
+  K.template block<N, 1>(0, 0) = f0;
+  for (size_t s = 1; s < NStages; ++s) {
+    Eigen::Matrix<double, N, 1> dy =
+        K.block(0, 0, s, N).transpose() * A.block(s, 0, 1, s).transpose() * h;
+    K.template block<1, N>(s, 0) = fn(t + C(0, s) * h, y0 + dy).transpose();
+  }
+
+  Eigen::Matrix<double, N, 1> y_new =
+      y0 + h * (K.template block<NStages, N>(0, 0).transpose() * B.transpose());
+  Eigen::Matrix<double, N, 1> f_new = fn(t + h, y_new);
+
+  K.template block<1, N>(NStages, 0) = f_new.transpose();
+
+  return std::make_tuple(y_new, f_new);
+}
+
+}  // namespace frc971::control_loops
+
+#endif  // FRC971_CONTROL_LOOPS_RUNGE_KUTTA_HELPERS_H_
diff --git a/frc971/control_loops/runge_kutta_test.cc b/frc971/control_loops/runge_kutta_test.cc
index 1022a47..357b7f5 100644
--- a/frc971/control_loops/runge_kutta_test.cc
+++ b/frc971/control_loops/runge_kutta_test.cc
@@ -90,4 +90,28 @@
   EXPECT_NEAR(y1(0, 0), RungeKuttaTimeVaryingSolution(6.0)(0, 0), 1e-7);
 }
 
+// Tests that integrating dx/dt = e^x works with RK45
+TEST(RungeKuttaTest, RungeKuttaTimeVaryingAdaptive) {
+  ::Eigen::Matrix<double, 1, 1> y0 = RungeKuttaTimeVaryingSolution(5.0);
+
+  size_t count = 0;
+
+  ::Eigen::Matrix<double, 1, 1> y1 = AdaptiveRungeKutta(
+      [&](double t, ::Eigen::Matrix<double, 1, 1> x) {
+        ++count;
+        return (::Eigen::Matrix<double, 1, 1>()
+                << x(0, 0) * (2.0 / (::std::exp(t) + 1.0) - 1.0))
+            .finished();
+      },
+      y0, 5.0, 1.0, 1e-6, 1e-9);
+  EXPECT_NEAR(y1(0, 0), RungeKuttaTimeVaryingSolution(6.0)(0, 0), 1e-7);
+
+  // Using sympy as a benchmark, we should expect to see the function called 38
+  // times.
+  EXPECT_EQ(count, 38);
+
+  LOG(INFO) << "Got " << y1(0, 0) << " vs expected "
+            << RungeKuttaTimeVaryingSolution(6.0)(0, 0);
+}
+
 }  // namespace frc971::control_loops::testing
diff --git a/frc971/control_loops/swerve/BUILD b/frc971/control_loops/swerve/BUILD
index e411fc9..4fd73d2 100644
--- a/frc971/control_loops/swerve/BUILD
+++ b/frc971/control_loops/swerve/BUILD
@@ -1,3 +1,38 @@
+load("@aspect_bazel_lib//lib:run_binary.bzl", "run_binary")
+load("//aos:config.bzl", "aos_config")
+load("//aos/flatbuffers:generate.bzl", "static_flatbuffer")
+
+package(default_visibility = ["//visibility:public"])
+
+static_flatbuffer(
+    name = "swerve_drivetrain_goal_fbs",
+    srcs = ["swerve_drivetrain_goal.fbs"],
+)
+
+static_flatbuffer(
+    name = "swerve_drivetrain_status_fbs",
+    srcs = ["swerve_drivetrain_status.fbs"],
+    deps = ["//frc971/control_loops:profiled_subsystem_fbs"],
+)
+
+static_flatbuffer(
+    name = "swerve_drivetrain_output_fbs",
+    srcs = ["swerve_drivetrain_output.fbs"],
+    deps = ["//frc971/control_loops:can_talonfx_fbs"],
+)
+
+static_flatbuffer(
+    name = "swerve_drivetrain_can_position_fbs",
+    srcs = ["swerve_drivetrain_can_position.fbs"],
+    deps = ["//frc971/control_loops:can_talonfx_fbs"],
+)
+
+static_flatbuffer(
+    name = "swerve_drivetrain_position_fbs",
+    srcs = ["swerve_drivetrain_position.fbs"],
+    deps = ["//frc971/control_loops:control_loops_fbs"],
+)
+
 py_binary(
     name = "simulation",
     srcs = [
@@ -11,3 +46,103 @@
         "@pip//sympy",
     ],
 )
+
+cc_library(
+    name = "swerve_control_loops",
+    srcs = ["swerve_control_loops.cc"],
+    hdrs = ["swerve_control_loops.h"],
+    target_compatible_with = ["@platforms//os:linux"],
+    deps = [
+        ":swerve_drivetrain_can_position_fbs",
+        ":swerve_drivetrain_goal_fbs",
+        ":swerve_drivetrain_output_fbs",
+        ":swerve_drivetrain_position_fbs",
+        ":swerve_drivetrain_status_fbs",
+        "//frc971/control_loops:control_loop",
+    ],
+)
+
+cc_test(
+    name = "swerve_control_test",
+    srcs = ["swerve_control_test.cc"],
+    data = [
+        ":aos_config",
+    ],
+    target_compatible_with = ["@platforms//os:linux"],
+    deps = [
+        ":swerve_control_loops",
+        ":swerve_drivetrain_can_position_fbs",
+        ":swerve_drivetrain_goal_fbs",
+        ":swerve_drivetrain_output_fbs",
+        ":swerve_drivetrain_position_fbs",
+        ":swerve_drivetrain_status_fbs",
+        "//aos/events:shm_event_loop",
+        "//aos/testing:googletest",
+        "//frc971/control_loops:control_loop_test",
+        "//frc971/control_loops:state_feedback_loop",
+        "//frc971/control_loops:team_number_test_environment",
+    ],
+)
+
+aos_config(
+    name = "aos_config",
+    src = "swerve.json",
+    flatbuffers = [
+        ":swerve_drivetrain_goal_fbs",
+        ":swerve_drivetrain_output_fbs",
+        ":swerve_drivetrain_position_fbs",
+        ":swerve_drivetrain_can_position_fbs",
+        ":swerve_drivetrain_status_fbs",
+    ],
+    target_compatible_with = ["@platforms//os:linux"],
+    deps = ["//frc971/input:aos_config"],
+)
+
+cc_library(
+    name = "motors",
+    hdrs = [
+        "motors.h",
+    ],
+    deps = [
+        "@symengine",
+    ],
+)
+
+cc_binary(
+    name = "generate_physics",
+    srcs = [
+        "generate_physics.cc",
+    ],
+    deps = [
+        ":motors",
+        "//aos:init",
+        "//aos/util:file",
+        "@com_github_google_glog//:glog",
+        "@com_google_absl//absl/strings",
+        "@com_google_absl//absl/strings:str_format",
+        "@symengine",
+    ],
+)
+
+run_binary(
+    name = "dynamics_codegen",
+    outs = [
+        "dynamics.cc",
+        "dynamics.h",
+    ],
+    args = [
+        "--output_base=$(BINDIR)/",
+        "--cc_output_path=$(location :dynamics.cc)",
+        "--h_output_path=$(location :dynamics.h)",
+    ],
+    tool = ":generate_physics",
+)
+
+cc_library(
+    name = "dynamics",
+    srcs = ["dynamics.cc"],
+    hdrs = ["dynamics.h"],
+    deps = [
+        "@org_tuxfamily_eigen//:eigen",
+    ],
+)
diff --git a/frc971/control_loops/swerve/generate_physics.cc b/frc971/control_loops/swerve/generate_physics.cc
new file mode 100644
index 0000000..52f82f0
--- /dev/null
+++ b/frc971/control_loops/swerve/generate_physics.cc
@@ -0,0 +1,574 @@
+#include <symengine/add.h>
+#include <symengine/matrix.h>
+#include <symengine/number.h>
+#include <symengine/printers.h>
+#include <symengine/real_double.h>
+#include <symengine/simplify.h>
+#include <symengine/solve.h>
+#include <symengine/symbol.h>
+
+#include <array>
+#include <cmath>
+#include <numbers>
+#include <utility>
+
+#include "absl/strings/str_format.h"
+#include "absl/strings/str_join.h"
+#include "absl/strings/str_replace.h"
+#include "absl/strings/substitute.h"
+#include "gflags/gflags.h"
+#include "glog/logging.h"
+
+#include "aos/init.h"
+#include "aos/util/file.h"
+#include "frc971/control_loops/swerve/motors.h"
+
+DEFINE_string(output_base, "",
+              "Path to strip off the front of the output paths.");
+DEFINE_string(cc_output_path, "", "Path to write generated header code to");
+DEFINE_string(h_output_path, "", "Path to write generated cc code to");
+
+DEFINE_bool(symbolic, false, "If true, write everything out symbolically.");
+
+using SymEngine::add;
+using SymEngine::atan2;
+using SymEngine::Basic;
+using SymEngine::ccode;
+using SymEngine::cos;
+using SymEngine::DenseMatrix;
+using SymEngine::div;
+using SymEngine::Inf;
+using SymEngine::integer;
+using SymEngine::map_basic_basic;
+using SymEngine::minus_one;
+using SymEngine::neg;
+using SymEngine::NegInf;
+using SymEngine::pow;
+using SymEngine::RCP;
+using SymEngine::real_double;
+using SymEngine::RealDouble;
+using SymEngine::Set;
+using SymEngine::simplify;
+using SymEngine::sin;
+using SymEngine::solve;
+using SymEngine::symbol;
+using SymEngine::Symbol;
+
+namespace frc971::control_loops::swerve {
+
+// State per module.
+struct Module {
+  RCP<const Symbol> Is;
+
+  RCP<const Symbol> Id;
+
+  RCP<const Symbol> thetas;
+  RCP<const Symbol> omegas;
+  RCP<const Symbol> alphas;
+  RCP<const Basic> alphas_eqn;
+
+  RCP<const Symbol> thetad;
+  RCP<const Symbol> omegad;
+  RCP<const Symbol> alphad;
+  RCP<const Basic> alphad_eqn;
+
+  // Acceleration contribution from this module.
+  DenseMatrix accel;
+  RCP<const Basic> angular_accel;
+};
+
+class SwerveSimulation {
+ public:
+  SwerveSimulation() : drive_motor_(KrakenFOC()), steer_motor_(KrakenFOC()) {
+    auto fx = symbol("fx");
+    auto fy = symbol("fy");
+    auto moment = symbol("moment");
+
+    if (FLAGS_symbolic) {
+      Cx_ = symbol("Cx");
+      Cy_ = symbol("Cy");
+
+      r_w_ = symbol("r_w_");
+
+      m_ = symbol("m");
+      J_ = symbol("J");
+
+      Gd1_ = symbol("Gd1");
+      rs_ = symbol("rs");
+      rp_ = symbol("rp");
+      Gd2_ = symbol("Gd2");
+
+      rb1_ = symbol("rb1");
+      rb2_ = symbol("rb2");
+
+      Gd2_ = symbol("Gd3");
+      Gd_ = symbol("Gd");
+
+      Js_ = symbol("Js");
+
+      Gs_ = symbol("Gs");
+      wb_ = symbol("wb");
+
+      Jdm_ = symbol("Jdm");
+      Jsm_ = symbol("Jsm");
+      Kts_ = symbol("Kts");
+      Ktd_ = symbol("Ktd");
+
+      robot_width_ = symbol("robot_width");
+
+      caster_ = symbol("caster");
+      contact_patch_length_ = symbol("Lcp");
+    } else {
+      Cx_ = real_double(5 * 9.8 / 0.05 / 4.0);
+      Cy_ = real_double(5 * 9.8 / 0.05 / 4.0);
+
+      r_w_ = real_double(2 * 0.0254);
+
+      m_ = real_double(25.0);  // base is 20 kg without battery
+      J_ = real_double(6.0);
+
+      Gd1_ = real_double(12.0 / 42.0);
+      rs_ = real_double(28.0 / 20.0 / 2.0);
+      rp_ = real_double(18.0 / 20.0 / 2.0);
+      Gd2_ = div(rs_, rp_);
+
+      // 15 / 45 bevel ratio, calculated using python script ported over to
+      // GetBevelPitchRadius(double
+      // TODO(Justin): Use the function instead of computed constantss
+      rb1_ = real_double(0.3805473);
+      rb2_ = real_double(1.14164);
+
+      Gd3_ = div(rb1_, rb2_);
+      Gd_ = mul(mul(Gd1_, Gd2_), Gd3_);
+
+      Js_ = real_double(0.1);
+
+      Gs_ = real_double(35.0 / 468.0);
+      wb_ = real_double(0.725);
+
+      Jdm_ = real_double(drive_motor_.motor_inertia);
+      Jsm_ = real_double(steer_motor_.motor_inertia);
+      Kts_ = real_double(steer_motor_.Kt);
+      Ktd_ = real_double(drive_motor_.Kt);
+
+      robot_width_ = real_double(24.75 * 0.0254);
+
+      caster_ = real_double(0.01);
+      contact_patch_length_ = real_double(0.02);
+    }
+
+    x_ = symbol("x");
+    y_ = symbol("y");
+    theta_ = symbol("theta");
+
+    vx_ = symbol("vx");
+    vy_ = symbol("vy");
+    omega_ = symbol("omega");
+
+    ax_ = symbol("ax");
+    ay_ = symbol("ay");
+    atheta_ = symbol("atheta");
+
+    // Now, compute the accelerations due to the disturbance forces.
+    angular_accel_ = div(moment, J_);
+    DenseMatrix external_accel = DenseMatrix(2, 1, {div(fx, m_), div(fy, m_)});
+
+    // And compute the physics contributions from each module.
+    modules_[0] = ModulePhysics(
+        0, DenseMatrix(
+               2, 1,
+               {div(robot_width_, integer(2)), div(robot_width_, integer(2))}));
+    modules_[1] =
+        ModulePhysics(1, DenseMatrix(2, 1,
+                                     {div(robot_width_, integer(-2)),
+                                      div(robot_width_, integer(2))}));
+    modules_[2] =
+        ModulePhysics(2, DenseMatrix(2, 1,
+                                     {div(robot_width_, integer(-2)),
+                                      div(robot_width_, integer(-2))}));
+    modules_[3] =
+        ModulePhysics(3, DenseMatrix(2, 1,
+                                     {div(robot_width_, integer(2)),
+                                      div(robot_width_, integer(-2))}));
+
+    // And convert them into the overall robot contribution.
+    DenseMatrix temp0 = DenseMatrix(2, 1);
+    DenseMatrix temp1 = DenseMatrix(2, 1);
+    DenseMatrix temp2 = DenseMatrix(2, 1);
+    accel_ = DenseMatrix(2, 1);
+
+    add_dense_dense(modules_[0].accel, external_accel, temp0);
+    add_dense_dense(temp0, modules_[1].accel, temp1);
+    add_dense_dense(temp1, modules_[2].accel, temp2);
+    add_dense_dense(temp2, modules_[3].accel, accel_);
+
+    angular_accel_ = add(angular_accel_, modules_[0].angular_accel);
+    angular_accel_ = add(angular_accel_, modules_[1].angular_accel);
+    angular_accel_ = add(angular_accel_, modules_[2].angular_accel);
+    angular_accel_ = simplify(add(angular_accel_, modules_[3].angular_accel));
+
+    VLOG(1) << "accel(0, 0) = " << ccode(*accel_.get(0, 0));
+    VLOG(1) << "accel(1, 0) = " << ccode(*accel_.get(1, 0));
+    VLOG(1) << "angular_accel = " << ccode(*angular_accel_);
+  }
+
+  // Writes the physics out to the provided .cc and .h path.
+  void Write(std::string_view cc_path, std::string_view h_path) {
+    std::vector<std::string> result_cc;
+    std::vector<std::string> result_h;
+
+    std::string_view include_guard_stripped = FLAGS_h_output_path;
+    CHECK(absl::ConsumePrefix(&include_guard_stripped, FLAGS_output_base));
+    std::string include_guard =
+        absl::StrReplaceAll(absl::AsciiStrToUpper(include_guard_stripped),
+                            {{"/", "_"}, {".", "_"}});
+
+    // Write out the header.
+    result_h.emplace_back(absl::Substitute("#ifndef $0_", include_guard));
+    result_h.emplace_back(absl::Substitute("#define $0_", include_guard));
+    result_h.emplace_back("");
+    result_h.emplace_back("#include <Eigen/Dense>");
+    result_h.emplace_back("");
+    result_h.emplace_back("namespace frc971::control_loops::swerve {");
+    result_h.emplace_back("");
+    result_h.emplace_back("// Returns the derivative of our state vector");
+    result_h.emplace_back("// [thetas0, thetad0, omegas0, omegad0,");
+    result_h.emplace_back("//  thetas1, thetad1, omegas1, omegad1,");
+    result_h.emplace_back("//  thetas2, thetad2, omegas2, omegad2,");
+    result_h.emplace_back("//  thetas3, thetad3, omegas3, omegad3,");
+    result_h.emplace_back("//  x, y, theta, vx, vy, omega,");
+    result_h.emplace_back("//  Fx, Fy, Moment]");
+    result_h.emplace_back("Eigen::Matrix<double, 25, 1> SwervePhysics(");
+    result_h.emplace_back(
+        "    Eigen::Map<const Eigen::Matrix<double, 25, 1>> X,");
+    result_h.emplace_back(
+        "    Eigen::Map<const Eigen::Matrix<double, 8, 1>> U);");
+    result_h.emplace_back("");
+    result_h.emplace_back("}  // namespace frc971::control_loops::swerve");
+    result_h.emplace_back("");
+    result_h.emplace_back(absl::Substitute("#endif  // $0_", include_guard));
+
+    // Write out the .cc
+    result_cc.emplace_back(
+        absl::Substitute("#include \"$0\"", include_guard_stripped));
+    result_cc.emplace_back("");
+    result_cc.emplace_back("#include <cmath>");
+    result_cc.emplace_back("");
+    result_cc.emplace_back("namespace frc971::control_loops::swerve {");
+    result_cc.emplace_back("");
+    result_cc.emplace_back("Eigen::Matrix<double, 25, 1> SwervePhysics(");
+    result_cc.emplace_back(
+        "    Eigen::Map<const Eigen::Matrix<double, 25, 1>> X,");
+    result_cc.emplace_back(
+        "    Eigen::Map<const Eigen::Matrix<double, 8, 1>> U) {");
+    result_cc.emplace_back("  Eigen::Matrix<double, 25, 1> result;");
+
+    // Start by writing out variables matching each of the symbol names we use
+    // so we don't have to modify the computed equations too much.
+    for (size_t m = 0; m < kNumModules; ++m) {
+      result_cc.emplace_back(
+          absl::Substitute("  const double thetas$0 = X($1, 0);", m, m * 4));
+      result_cc.emplace_back(absl::Substitute(
+          "  const double omegas$0 = X($1, 0);", m, m * 4 + 2));
+      result_cc.emplace_back(absl::Substitute(
+          "  const double omegad$0 = X($1, 0);", m, m * 4 + 3));
+    }
+
+    result_cc.emplace_back(absl::Substitute("  const double theta = X($0, 0);",
+                                            kNumModules * 4 + 2));
+    result_cc.emplace_back(
+        absl::Substitute("  const double vx = X($0, 0);", kNumModules * 4 + 3));
+    result_cc.emplace_back(
+        absl::Substitute("  const double vy = X($0, 0);", kNumModules * 4 + 4));
+    result_cc.emplace_back(absl::Substitute("  const double omega = X($0, 0);",
+                                            kNumModules * 4 + 5));
+
+    result_cc.emplace_back(
+        absl::Substitute("  const double fx = X($0, 0);", kNumModules * 4 + 6));
+    result_cc.emplace_back(
+        absl::Substitute("  const double fy = X($0, 0);", kNumModules * 4 + 7));
+    result_cc.emplace_back(absl::Substitute("  const double moment = X($0, 0);",
+                                            kNumModules * 4 + 8));
+
+    // Now do the same for the inputs.
+    for (size_t m = 0; m < kNumModules; ++m) {
+      result_cc.emplace_back(
+          absl::Substitute("  const double Is$0 = U($1, 0);", m, m * 2));
+      result_cc.emplace_back(
+          absl::Substitute("  const double Id$0 = U($1, 0);", m, m * 2 + 1));
+    }
+
+    result_cc.emplace_back("");
+
+    // And then write out the derivative of each state.
+    for (size_t m = 0; m < kNumModules; ++m) {
+      result_cc.emplace_back(
+          absl::Substitute("  result($0, 0) = omegas$1;", m * 4, m));
+      result_cc.emplace_back(
+          absl::Substitute("  result($0, 0) = omegad$1;", m * 4 + 1, m));
+
+      result_cc.emplace_back(absl::Substitute(
+          "  result($0, 0) = $1;", m * 4 + 2, ccode(*modules_[m].alphas_eqn)));
+      result_cc.emplace_back(absl::Substitute(
+          "  result($0, 0) = $1;", m * 4 + 3, ccode(*modules_[m].alphad_eqn)));
+    }
+
+    result_cc.emplace_back(
+        absl::Substitute("  result($0, 0) = omega;", kNumModules * 4));
+    result_cc.emplace_back(
+        absl::Substitute("  result($0, 0) = vx;", kNumModules * 4 + 1));
+    result_cc.emplace_back(
+        absl::Substitute("  result($0, 0) = vy;", kNumModules * 4 + 2));
+
+    result_cc.emplace_back(absl::Substitute(
+        "  result($0, 0) = $1;", kNumModules * 4 + 3, ccode(*angular_accel_)));
+    result_cc.emplace_back(absl::Substitute("  result($0, 0) = $1;",
+                                            kNumModules * 4 + 4,
+                                            ccode(*accel_.get(0, 0))));
+    result_cc.emplace_back(absl::Substitute("  result($0, 0) = $1;",
+                                            kNumModules * 4 + 5,
+                                            ccode(*accel_.get(1, 0))));
+
+    result_cc.emplace_back(
+        absl::Substitute("  result($0, 0) = 0.0;", kNumModules * 4 + 6));
+    result_cc.emplace_back(
+        absl::Substitute("  result($0, 0) = 0.0;", kNumModules * 4 + 7));
+    result_cc.emplace_back(
+        absl::Substitute("  result($0, 0) = 0.0;", kNumModules * 4 + 8));
+
+    result_cc.emplace_back("");
+    result_cc.emplace_back("  return result;");
+    result_cc.emplace_back("}");
+    result_cc.emplace_back("");
+    result_cc.emplace_back("}  // namespace frc971::control_loops::swerve");
+
+    aos::util::WriteStringToFileOrDie(cc_path, absl::StrJoin(result_cc, "\n"));
+    aos::util::WriteStringToFileOrDie(h_path, absl::StrJoin(result_h, "\n"));
+  }
+
+ private:
+  static constexpr uint8_t kNumModules = 4;
+
+  Module ModulePhysics(const int m, DenseMatrix mounting_location) {
+    VLOG(1) << "Solving module " << m;
+
+    Module result;
+
+    result.Is = symbol(absl::StrFormat("Is%u", m));
+    result.Id = symbol(absl::StrFormat("Id%u", m));
+
+    RCP<const Symbol> thetamd = symbol(absl::StrFormat("theta_md%u", m));
+    RCP<const Symbol> omegamd = symbol(absl::StrFormat("omega_md%u", m));
+    RCP<const Symbol> alphamd = symbol(absl::StrFormat("alpha_md%u", m));
+
+    result.thetas = symbol(absl::StrFormat("thetas%u", m));
+    result.omegas = symbol(absl::StrFormat("omegas%u", m));
+    result.alphas = symbol(absl::StrFormat("alphas%u", m));
+
+    result.thetad = symbol(absl::StrFormat("thetad%u", m));
+    result.omegad = symbol(absl::StrFormat("omegad%u", m));
+    result.alphad = symbol(absl::StrFormat("alphad%u", m));
+
+    // Velocity of the module in field coordinates
+    DenseMatrix robot_velocity = DenseMatrix(2, 1, {vx_, vy_});
+    VLOG(1) << "robot velocity: " << robot_velocity.__str__();
+
+    // Velocity of the contact patch in field coordinates
+    DenseMatrix temp_matrix = DenseMatrix(2, 1);
+    DenseMatrix temp_matrix2 = DenseMatrix(2, 1);
+    DenseMatrix contact_patch_velocity = DenseMatrix(2, 1);
+
+    mul_dense_dense(R(theta_), mounting_location, temp_matrix);
+    add_dense_dense(angle_cross(temp_matrix, omega_), robot_velocity,
+                    temp_matrix2);
+    mul_dense_dense(R(add(theta_, result.thetas)),
+                    DenseMatrix(2, 1, {caster_, integer(0)}), temp_matrix);
+    add_dense_dense(temp_matrix2,
+                    angle_cross(temp_matrix, add(omega_, result.omegas)),
+                    contact_patch_velocity);
+
+    VLOG(1);
+    VLOG(1) << "contact patch velocity: " << contact_patch_velocity.__str__();
+
+    // Relative velocity of the surface of the wheel to the ground.
+    DenseMatrix wheel_ground_velocity = DenseMatrix(2, 1);
+    mul_dense_dense(R(neg(add(result.thetas, theta_))), contact_patch_velocity,
+                    wheel_ground_velocity);
+
+    VLOG(1);
+    VLOG(1) << "wheel ground velocity: " << wheel_ground_velocity.__str__();
+
+    RCP<const Basic> slip_angle =
+        atan2(wheel_ground_velocity.get(1, 0), wheel_ground_velocity.get(0, 0));
+
+    VLOG(1);
+    VLOG(1) << "slip angle: " << slip_angle->__str__();
+
+    RCP<const Basic> slip_ratio =
+        div(sub(mul(r_w_, result.omegad), wheel_ground_velocity.get(0, 0)),
+            wheel_ground_velocity.get(0, 0));
+    VLOG(1);
+    VLOG(1) << "Slip ratio " << slip_ratio->__str__();
+
+    RCP<const Basic> Fwx = simplify(mul(Cx_, slip_ratio));
+    RCP<const Basic> Fwy = simplify(mul(Cy_, slip_angle));
+
+    RCP<const Basic> Ms =
+        mul(Fwy, add(div(contact_patch_length_, integer(3)), caster_));
+    VLOG(1);
+    VLOG(1) << "Ms " << Ms->__str__();
+    VLOG(1);
+    VLOG(1) << "Fwx " << Fwx->__str__();
+    VLOG(1);
+    VLOG(1) << "Fwy " << Fwy->__str__();
+
+    // alphas = ...
+    RCP<const Basic> lhms =
+        mul(add(neg(wb_), mul(add(rs_, rp_), sub(integer(1), div(rb1_, rp_)))),
+            mul(div(r_w_, rb2_), Fwx));
+    RCP<const Basic> lhs = add(add(Ms, div(mul(Jsm_, result.Is), Gs_)), lhms);
+    RCP<const Basic> rhs = add(Jsm_, div(div(Js_, Gs_), Gs_));
+    RCP<const Basic> accel_steer_eqn = simplify(div(lhs, rhs));
+
+    VLOG(1);
+    VLOG(1) << result.alphas->__str__() << " = " << accel_steer_eqn->__str__();
+
+    lhs = sub(mul(sub(div(add(rp_, rs_), rp_), integer(1)), result.omegas),
+              mul(Gd1_, mul(Gd2_, omegamd)));
+    RCP<const Basic> dplanitary_eqn = sub(mul(Gd3_, lhs), result.omegad);
+
+    lhs = sub(mul(sub(div(add(rp_, rs_), rp_), integer(1)), result.alphas),
+              mul(Gd1_, mul(Gd2_, alphamd)));
+    RCP<const Basic> ddplanitary_eqn = sub(mul(Gd3_, lhs), result.alphad);
+
+    RCP<const Basic> drive_eqn = sub(
+        add(mul(neg(Jdm_), div(alphamd, Gd_)), mul(Ktd_, div(result.Id, Gd_))),
+        mul(Fwx, r_w_));
+
+    VLOG(1) << "drive_eqn: " << drive_eqn->__str__();
+
+    // Substitute in ddplanitary_eqn so we get rid of alphamd
+    map_basic_basic map;
+    RCP<const Set> reals = interval(NegInf, Inf, true, true);
+    RCP<const Set> solve_solution = solve(ddplanitary_eqn, alphamd, reals);
+    map[alphamd] = solve_solution->get_args()[1]->get_args()[0];
+    VLOG(1) << "temp: " << solve_solution->__str__();
+    RCP<const Basic> drive_eqn_subs = drive_eqn->subs(map);
+
+    map.clear();
+    map[result.alphas] = accel_steer_eqn;
+    RCP<const Basic> drive_eqn_subs2 = drive_eqn_subs->subs(map);
+    RCP<const Basic> drive_eqn_subs3 = simplify(drive_eqn_subs2);
+    VLOG(1) << "drive_eqn simplified: " << drive_eqn_subs3->__str__();
+
+    solve_solution = solve(drive_eqn_subs3, result.alphad, reals);
+
+    RCP<const Basic> drive_accel =
+        simplify(solve_solution->get_args()[1]->get_args()[0]);
+    VLOG(1) << "drive_accel: " << drive_accel->__str__();
+
+    DenseMatrix mat_output = DenseMatrix(2, 1);
+    mul_dense_dense(R(add(theta_, result.thetas)),
+                    DenseMatrix(2, 1, {Fwx, Fwy}), mat_output);
+
+    // Comput the resulting force from the module.
+    DenseMatrix F = mat_output;
+
+    RCP<const Basic> torque = simplify(force_cross(mounting_location, F));
+    result.accel = DenseMatrix(2, 1);
+    mul_dense_scalar(F, pow(m_, minus_one), result.accel);
+    result.angular_accel = div(torque, J_);
+    VLOG(1);
+    VLOG(1) << "angular_accel = " << result.angular_accel->__str__();
+
+    VLOG(1);
+    VLOG(1) << "accel(0, 0) = " << result.accel.get(0, 0)->__str__();
+    VLOG(1);
+    VLOG(1) << "accel(1, 0) = " << result.accel.get(1, 0)->__str__();
+
+    result.alphad_eqn = drive_accel;
+    result.alphas_eqn = accel_steer_eqn;
+    return result;
+  }
+
+  DenseMatrix R(const RCP<const Basic> theta) {
+    return DenseMatrix(2, 2,
+                       {cos(theta), neg(sin(theta)), sin(theta), cos(theta)});
+  }
+
+  DenseMatrix angle_cross(DenseMatrix a, RCP<const Basic> b) {
+    return DenseMatrix(2, 1, {mul(a.get(1, 0), b), mul(neg(a.get(0, 0)), b)});
+  }
+
+  RCP<const Basic> force_cross(DenseMatrix r, DenseMatrix f) {
+    return sub(mul(r.get(0, 0), f.get(1, 0)), mul(r.get(1, 0), f.get(0, 0)));
+  }
+
+  // z represents the number of teeth per gear, theta is the angle between
+  // shafts(in degrees), D_02 is the pitch diameter of gear 2 and b_2 is the
+  // length of the tooth of gear 2
+  // returns std::pair(r_01, r_02)
+  std::pair<double, double> GetBevelPitchRadius(double z1, double z2,
+                                                double theta, double D_02,
+                                                double b_2) {
+    double gamma_1 = std::atan2(z1, z2);
+    double gamma_2 = theta / 180.0 * std::numbers::pi - gamma_1;
+    double R_m = D_02 / 2 / std::sin(gamma_2) - b_2 / 2;
+    return std::pair(R_m * std::cos(gamma_2), R_m * std::sin(gamma_2));
+  }
+
+  Motor drive_motor_;
+  Motor steer_motor_;
+
+  RCP<const Basic> Cx_;
+  RCP<const Basic> Cy_;
+  RCP<const Basic> r_w_;
+  RCP<const Basic> m_;
+  RCP<const Basic> J_;
+  RCP<const Basic> Gd1_;
+  RCP<const Basic> rs_;
+  RCP<const Basic> rp_;
+  RCP<const Basic> Gd2_;
+  RCP<const Basic> rb1_;
+  RCP<const Basic> rb2_;
+  RCP<const Basic> Gd3_;
+  RCP<const Basic> Gd_;
+  RCP<const Basic> Js_;
+  RCP<const Basic> Gs_;
+  RCP<const Basic> wb_;
+  RCP<const Basic> Jdm_;
+  RCP<const Basic> Jsm_;
+  RCP<const Basic> Kts_;
+  RCP<const Basic> Ktd_;
+  RCP<const Basic> robot_width_;
+  RCP<const Basic> caster_;
+  RCP<const Basic> contact_patch_length_;
+  RCP<const Basic> x_;
+  RCP<const Basic> y_;
+  RCP<const Basic> theta_;
+  RCP<const Basic> vx_;
+  RCP<const Basic> vy_;
+  RCP<const Basic> omega_;
+  RCP<const Basic> ax_;
+  RCP<const Basic> ay_;
+  RCP<const Basic> atheta_;
+
+  std::array<Module, kNumModules> modules_;
+
+  DenseMatrix accel_;
+  RCP<const Basic> angular_accel_;
+};
+
+}  // namespace frc971::control_loops::swerve
+
+int main(int argc, char **argv) {
+  aos::InitGoogle(&argc, &argv);
+
+  frc971::control_loops::swerve::SwerveSimulation sim;
+
+  if (!FLAGS_cc_output_path.empty() && !FLAGS_h_output_path.empty()) {
+    sim.Write(FLAGS_cc_output_path, FLAGS_h_output_path);
+  }
+
+  return 0;
+}
diff --git a/frc971/control_loops/swerve/motors.h b/frc971/control_loops/swerve/motors.h
new file mode 100644
index 0000000..c59f997
--- /dev/null
+++ b/frc971/control_loops/swerve/motors.h
@@ -0,0 +1,52 @@
+#ifndef FRC971_CONTROL_LOOPS_SWERVE_MOTORS_
+#define FRC971_CONTROL_LOOPS_SWERVE_MOTORS_
+
+#include <numbers>
+
+namespace frc971::control_loops::swerve {
+
+// Class holding the physical parameters for a motor.
+struct Motor {
+  constexpr Motor(double stall_torque, double stall_current, double free_speed,
+                  double free_current, double motor_inertia)
+      : stall_torque(stall_torque),
+        stall_current(stall_current),
+        free_speed(free_speed),
+        free_current(free_current),
+        resistance(12 / stall_current),
+        Kv(free_speed / (12 - resistance * free_current)),
+        Kt(stall_torque / stall_current),
+        motor_inertia(motor_inertia) {}
+  // Stall Torque in Nm
+  double stall_torque;
+  // Stall Current in Amps
+  double stall_current;
+  // Free Speed in rad / sec
+  double free_speed;
+  // Free Current in Amps
+  double free_current;
+  // Resistance of the motor, divided by 2 to account for the 2 motors
+  double resistance;
+  // Motor velocity constant
+  double Kv;
+  // Torque constant
+  double Kt;
+  // Motor inertia in kg m^2
+  // Diameter of 1.9", weight of: 100 grams
+  // TODO(Filip/Justin): Update motor inertia for Kraken, currently using Falcon
+  // motor inertia
+  double motor_inertia;
+};
+
+// Struct representing the WCP Kraken X60 motor using
+// Field Oriented Controls (FOC) communication.
+//
+// All numbers based on data from
+// https://wcproducts.com/products/kraken.
+constexpr Motor KrakenFOC() {
+  return Motor{9.37, 483.0, 5800.0 / 60.0 * 2.0 * std::numbers::pi, 2.0,
+               0.1 * (0.95 * 0.0254) * (0.95 * 0.0254)};
+};
+}  // namespace frc971::control_loops::swerve
+
+#endif  // FRC971_CONTROL_LOOPS_SWERVE_MOTORS_
diff --git a/frc971/control_loops/swerve/swerve.json b/frc971/control_loops/swerve/swerve.json
new file mode 100644
index 0000000..1282b54
--- /dev/null
+++ b/frc971/control_loops/swerve/swerve.json
@@ -0,0 +1,27 @@
+{
+    "channels": [
+        {
+            "name": "/swerve",
+            "type": "frc971.control_loops.swerve.Goal"
+        },
+        {
+            "name": "/swerve",
+            "type": "frc971.control_loops.swerve.Output"
+        },
+        {
+            "name": "/swerve",
+            "type": "frc971.control_loops.swerve.CanPosition"
+        },
+        {
+            "name": "/swerve",
+            "type": "frc971.control_loops.swerve.Position"
+        },
+        {
+            "name": "/swerve",
+            "type": "frc971.control_loops.swerve.Status"
+        }
+    ],
+    "imports": [
+        "../../../frc971/input/robot_state_config.json"
+    ]
+}
diff --git a/frc971/control_loops/swerve/swerve_control_loops.cc b/frc971/control_loops/swerve/swerve_control_loops.cc
new file mode 100644
index 0000000..bd0d3bd
--- /dev/null
+++ b/frc971/control_loops/swerve/swerve_control_loops.cc
@@ -0,0 +1,63 @@
+#include "frc971/control_loops/swerve/swerve_control_loops.h"
+
+namespace frc971::control_loops::swerve {
+
+SwerveControlLoops::SwerveControlLoops(::aos::EventLoop *event_loop,
+                                       const ::std::string &name)
+    : frc971::controls::ControlLoop<Goal, Position, StatusStatic, OutputStatic>(
+          event_loop, name) {}
+
+void SwerveControlLoops::RunIteration(
+    const Goal *goal, const Position *position,
+    aos::Sender<OutputStatic>::StaticBuilder *output_builder,
+    aos::Sender<StatusStatic>::StaticBuilder *status_builder) {
+  (void)goal, (void)position;
+
+  if (output_builder != nullptr && goal != nullptr) {
+    OutputStatic *output = output_builder->get();
+
+    auto front_left_output = output->add_front_left_output();
+    front_left_output->set_rotation_current(0);
+    front_left_output->set_translation_current(
+        goal->front_left_goal()->translation_current());
+
+    auto front_right_output = output->add_front_right_output();
+    front_right_output->set_rotation_current(0);
+    front_right_output->set_translation_current(
+        goal->front_right_goal()->translation_current());
+
+    auto back_left_output = output->add_back_left_output();
+    back_left_output->set_rotation_current(0);
+    back_left_output->set_translation_current(
+        goal->back_left_goal()->translation_current());
+
+    auto back_right_output = output->add_back_right_output();
+    back_right_output->set_rotation_current(0);
+    back_right_output->set_translation_current(
+        goal->back_right_goal()->translation_current());
+
+    // Ignore the return value of Send
+    output_builder->CheckOk(output_builder->Send());
+  }
+
+  if (status_builder != nullptr) {
+    StatusStatic *status = status_builder->get();
+
+    auto front_left_status = status->add_front_left_status();
+    PopulateSwerveModuleRotation(front_left_status);
+
+    auto front_right_status = status->add_front_right_status();
+    PopulateSwerveModuleRotation(front_right_status);
+
+    auto back_left_status = status->add_back_left_status();
+    PopulateSwerveModuleRotation(back_left_status);
+
+    auto back_right_status = status->add_back_right_status();
+    PopulateSwerveModuleRotation(back_right_status);
+
+    // Ignore the return value of Send
+    status_builder->CheckOk(status_builder->Send());
+  }
+}
+
+}  // namespace frc971::control_loops::swerve
diff --git a/frc971/control_loops/swerve/swerve_control_loops.h b/frc971/control_loops/swerve/swerve_control_loops.h
new file mode 100644
index 0000000..78f6ba0
--- /dev/null
+++ b/frc971/control_loops/swerve/swerve_control_loops.h
@@ -0,0 +1,39 @@
+#ifndef FRC971_CONTROL_LOOPS_SWERVE_SWERVE_CONTROL_LOOPS_H_
+#define FRC971_CONTROL_LOOPS_SWERVE_SWERVE_CONTROL_LOOPS_H_
+
+#include "aos/time/time.h"
+#include "frc971/control_loops/control_loop.h"
+#include "frc971/control_loops/profiled_subsystem_generated.h"
+#include "frc971/control_loops/swerve/swerve_drivetrain_can_position_generated.h"
+#include "frc971/control_loops/swerve/swerve_drivetrain_goal_generated.h"
+#include "frc971/control_loops/swerve/swerve_drivetrain_output_static.h"
+#include "frc971/control_loops/swerve/swerve_drivetrain_position_generated.h"
+#include "frc971/control_loops/swerve/swerve_drivetrain_status_static.h"
+
+namespace frc971::control_loops::swerve {
+
+inline void PopulateSwerveModuleRotation(
+    SwerveModuleStatusStatic *swerve_module_table) {
+  auto rotation = swerve_module_table->add_rotation();
+  auto estimator_state = rotation->add_estimator_state();
+  (void)estimator_state;
+}
+
+// Handles the translation and rotation current for each swerve module
+class SwerveControlLoops
+    : public ::frc971::controls::ControlLoop<Goal, Position, StatusStatic,
+                                             OutputStatic> {
+ public:
+  explicit SwerveControlLoops(::aos::EventLoop *event_loop,
+                              const ::std::string &name = "/swerve");
+
+ protected:
+  void RunIteration(
+      const Goal *goal, const Position *position,
+      aos::Sender<OutputStatic>::StaticBuilder *output_builder,
+      aos::Sender<StatusStatic>::StaticBuilder *status_builder) override;
+};
+
+}  // namespace frc971::control_loops::swerve
+
+#endif  // FRC971_CONTROL_LOOPS_SWERVE_SWERVE_CONTROL_LOOPS_H_
diff --git a/frc971/control_loops/swerve/swerve_control_test.cc b/frc971/control_loops/swerve/swerve_control_test.cc
new file mode 100644
index 0000000..9378f1c
--- /dev/null
+++ b/frc971/control_loops/swerve/swerve_control_test.cc
@@ -0,0 +1,161 @@
+#include <unistd.h>
+
+#include <chrono>
+#include <memory>
+#include <vector>
+
+#include "gtest/gtest.h"
+
+#include "aos/events/shm_event_loop.h"
+#include "frc971/control_loops/control_loop_test.h"
+#include "frc971/control_loops/swerve/swerve_control_loops.h"
+#include "frc971/control_loops/swerve/swerve_drivetrain_can_position_generated.h"
+#include "frc971/control_loops/swerve/swerve_drivetrain_goal_generated.h"
+#include "frc971/control_loops/swerve/swerve_drivetrain_output_generated.h"
+#include "frc971/control_loops/swerve/swerve_drivetrain_position_generated.h"
+#include "frc971/control_loops/swerve/swerve_drivetrain_status_generated.h"
+#include "frc971/control_loops/team_number_test_environment.h"
+
+using namespace std;
+
+namespace frc971::control_loops::swerve::testing {
+namespace chrono = ::std::chrono;
+using aos::monotonic_clock;
+
+// Class which simulates stuff and sends out queue messages with the position.
+class SwerveControlSimulation {
+ public:
+  SwerveControlSimulation(::aos::EventLoop *event_loop, chrono::nanoseconds dt)
+      : event_loop_(event_loop),
+        position_sender_(event_loop_->MakeSender<Position>("/swerve")),
+        can_position_sender_(event_loop_->MakeSender<CanPosition>("/swerve")),
+        goal_fetcher_(event_loop_->MakeFetcher<Goal>("/swerve")),
+        status_fetcher_(event_loop_->MakeFetcher<Status>("/swerve")),
+        output_fetcher_(event_loop_->MakeFetcher<Output>("/swerve")) {
+    event_loop_->AddPhasedLoop(
+        [this](int) {
+          if (!first_) {
+            Simulate();
+          }
+          first_ = false;
+          SendPositionMessage();
+        },
+        dt);
+  }
+
+  // Sends a queue message with the position data.
+  void SendPositionMessage() {
+    auto builder = position_sender_.MakeBuilder();
+
+    Position::Builder position_builder = builder.MakeBuilder<Position>();
+
+    EXPECT_EQ(builder.Send(position_builder.Finish()),
+              aos::RawSender::Error::kOk);
+  }
+
+  void VerifyNearGoal() {
+    goal_fetcher_.Fetch();
+    status_fetcher_.Fetch();
+
+    ASSERT_TRUE(goal_fetcher_.get() != nullptr) << ": No goal";
+    ASSERT_TRUE(status_fetcher_.get() != nullptr) << ": No status";
+
+    constexpr double kEpsRotationAngle = 0.03;
+    constexpr double kEpsRotationVelocity = 0.03;
+    constexpr double kEpsTranslationSpeed = 0.03;
+
+    std::vector<const SwerveModuleStatus *> modules_status{
+        status_fetcher_->front_left_status(),
+        status_fetcher_->front_right_status(),
+        status_fetcher_->back_left_status(),
+        status_fetcher_->back_right_status()};
+
+    for (auto &module_status : modules_status) {
+      EXPECT_NEAR(module_status->rotation()->position(),
+                  module_status->rotation()->goal_position(),
+                  kEpsRotationAngle);
+      EXPECT_NEAR(module_status->rotation()->velocity(),
+                  module_status->rotation()->goal_velocity(),
+                  kEpsRotationVelocity);
+      EXPECT_NEAR(module_status->goal_translation_speed(),
+                  module_status->translation_speed(), kEpsTranslationSpeed);
+    }
+  }
+
+  // Simulates basic control loop for a single timestep.
+  void Simulate() { EXPECT_TRUE(output_fetcher_.Fetch()); }
+
+ private:
+  ::aos::EventLoop *event_loop_;
+
+  ::aos::Sender<Position> position_sender_;
+  ::aos::Sender<CanPosition> can_position_sender_;
+  ::aos::Sender<Goal> goal_sender_;
+
+  ::aos::Fetcher<CanPosition> can_position_fetcher_;
+  ::aos::Fetcher<Position> position_fetcher_;
+  ::aos::Fetcher<Goal> goal_fetcher_;
+  ::aos::Fetcher<Status> status_fetcher_;
+  ::aos::Fetcher<Output> output_fetcher_;
+
+  bool first_ = true;
+};
+
+class SwerveControlLoopTest : public ::frc971::testing::ControlLoopTest {
+ public:
+  SwerveControlLoopTest()
+      : ::frc971::testing::ControlLoopTest(
+            aos::configuration::ReadConfig(
+                "frc971/control_loops/swerve/aos_config.json"),
+            chrono::microseconds(5050)),
+        swerve_test_event_loop_(MakeEventLoop("test")),
+        goal_sender_(swerve_test_event_loop_->MakeSender<Goal>("/swerve")),
+
+        swerve_control_event_loop_(MakeEventLoop("swerve_control")),
+        swerve_control_loops_(swerve_control_event_loop_.get(), "/swerve"),
+
+        swerve_control_simulation_event_loop_(MakeEventLoop("simulation")),
+        swerve_control_simulation_(swerve_control_simulation_event_loop_.get(),
+                                   dt()) {
+    set_team_id(control_loops::testing::kTeamNumber);
+    SetEnabled(true);
+  }
+
+  ::std::unique_ptr<::aos::EventLoop> swerve_test_event_loop_;
+  ::aos::Sender<Goal> goal_sender_;
+
+  ::std::unique_ptr<::aos::EventLoop> swerve_control_event_loop_;
+  SwerveControlLoops swerve_control_loops_;
+
+  ::std::unique_ptr<::aos::EventLoop> swerve_control_simulation_event_loop_;
+  SwerveControlSimulation swerve_control_simulation_;
+};
+
+// Tests that the swerve modules' speeds are all set to 0.
+TEST_F(SwerveControlLoopTest, SwerveModulesDontMove) {
+  {
+    auto builder = goal_sender_.MakeBuilder();
+    SwerveModuleGoal::Builder swerve_module_builder =
+        builder.MakeBuilder<SwerveModuleGoal>();
+    swerve_module_builder.add_translation_control_type_goal(
+        TranslationControlTypeGoal::CURRENT);
+    swerve_module_builder.add_rotation_angle(0.0);
+    swerve_module_builder.add_translation_current(0.0);
+    swerve_module_builder.add_translation_speed(0.0);
+    auto empty_module_offset = swerve_module_builder.Finish();
+
+    Goal::Builder goal_builder = builder.MakeBuilder<Goal>();
+    goal_builder.add_front_left_goal(empty_module_offset);
+    goal_builder.add_front_right_goal(empty_module_offset);
+    goal_builder.add_back_left_goal(empty_module_offset);
+    goal_builder.add_back_right_goal(empty_module_offset);
+
+    ASSERT_EQ(builder.Send(goal_builder.Finish()), aos::RawSender::Error::kOk);
+  }
+
+  RunFor(dt() * 2);
+
+  swerve_control_simulation_.VerifyNearGoal();
+}
+
+}  // namespace frc971::control_loops::swerve::testing
\ No newline at end of file
diff --git a/frc971/control_loops/swerve/swerve_drivetrain_can_position.fbs b/frc971/control_loops/swerve/swerve_drivetrain_can_position.fbs
new file mode 100644
index 0000000..957bce8
--- /dev/null
+++ b/frc971/control_loops/swerve/swerve_drivetrain_can_position.fbs
@@ -0,0 +1,18 @@
+include "frc971/control_loops/can_talonfx.fbs";
+
+namespace frc971.control_loops.swerve;
+
+table SwerveModuleCanPosition {
+  rotation: frc971.control_loops.CANTalonFX (id: 0);
+  translation: frc971.control_loops.CANTalonFX (id: 1);
+}
+
+// CAN Readings from the CAN sensor reader loop for each swerve module
+table CanPosition {
+  front_left: SwerveModuleCanPosition (id: 0);
+  front_right: SwerveModuleCanPosition (id: 1);
+  back_left: SwerveModuleCanPosition (id: 2);
+  back_right: SwerveModuleCanPosition (id: 3);
+}
+
+root_type CanPosition;
diff --git a/frc971/control_loops/swerve/swerve_drivetrain_goal.fbs b/frc971/control_loops/swerve/swerve_drivetrain_goal.fbs
new file mode 100644
index 0000000..eab0d0d
--- /dev/null
+++ b/frc971/control_loops/swerve/swerve_drivetrain_goal.fbs
@@ -0,0 +1,32 @@
+namespace frc971.control_loops.swerve;
+
+// States what translation control type goal we will care about
+// SPEED means we will control translation with speed (m/s)
+// CURRENT mean we will control translation with current (amps)
+enum TranslationControlTypeGoal : ubyte {
+  SPEED,
+  CURRENT,
+}
+
+// Takes in either current or speed
+// Uses current if both are given
+table SwerveModuleGoal {
+  // Angle in radians.
+  rotation_angle:double (id: 0);
+  // Tells us whether we use current
+  // or speed to control translation
+  translation_control_type_goal: TranslationControlTypeGoal (id: 1);
+  // Current in amps.
+  translation_current:double (id: 2);
+  // Speed in meters per second.
+  translation_speed:double (id: 3);
+}
+
+table Goal {
+    front_left_goal:SwerveModuleGoal (id: 0);
+    front_right_goal:SwerveModuleGoal (id: 1);
+    back_left_goal:SwerveModuleGoal (id: 2);
+    back_right_goal:SwerveModuleGoal (id: 3);
+}
+
+root_type Goal;
diff --git a/frc971/control_loops/swerve/swerve_drivetrain_output.fbs b/frc971/control_loops/swerve/swerve_drivetrain_output.fbs
new file mode 100644
index 0000000..72517a6
--- /dev/null
+++ b/frc971/control_loops/swerve/swerve_drivetrain_output.fbs
@@ -0,0 +1,16 @@
+namespace frc971.control_loops.swerve;
+
+table SwerveModuleOutput {
+  // Current in Amps.
+  rotation_current:double (id: 0);
+  translation_current:double (id: 1);
+}
+
+table Output {
+  front_left_output:SwerveModuleOutput (id: 0);
+  front_right_output:SwerveModuleOutput (id: 1);
+  back_left_output:SwerveModuleOutput (id: 2);
+  back_right_output:SwerveModuleOutput (id: 3);
+}
+
+root_type Output;
diff --git a/frc971/control_loops/swerve/swerve_drivetrain_position.fbs b/frc971/control_loops/swerve/swerve_drivetrain_position.fbs
new file mode 100644
index 0000000..a5c921a
--- /dev/null
+++ b/frc971/control_loops/swerve/swerve_drivetrain_position.fbs
@@ -0,0 +1,19 @@
+include "frc971/control_loops/control_loops.fbs";
+
+namespace frc971.control_loops.swerve;
+
+table SwerveModulePosition {
+  // Position of the mag encoder for the rotation of the module.
+  rotation_position: frc971.AbsolutePosition (id: 0);
+}
+
+// Captures all of the roborio-sourced position information for a
+// swerve drivetrain.
+table Position {
+  front_left:SwerveModulePosition (id: 0);
+  front_right:SwerveModulePosition (id: 1);
+  back_left:SwerveModulePosition (id: 2);
+  back_right:SwerveModulePosition (id: 3);
+}
+
+root_type Position;
diff --git a/frc971/control_loops/swerve/swerve_drivetrain_status.fbs b/frc971/control_loops/swerve/swerve_drivetrain_status.fbs
new file mode 100644
index 0000000..dc50af5
--- /dev/null
+++ b/frc971/control_loops/swerve/swerve_drivetrain_status.fbs
@@ -0,0 +1,21 @@
+include "frc971/control_loops/profiled_subsystem.fbs";
+
+namespace frc971.control_loops.swerve;
+
+table SwerveModuleStatus {
+    // Goal speed in meters per second.
+    goal_translation_speed:double (id: 0);
+    // Absolute encoder for rotation
+    rotation:frc971.control_loops.AbsoluteEncoderProfiledJointStatus (id: 1);
+    // Translation speed in meters per second.
+    translation_speed:double (id: 2);
+}
+
+table Status {
+    front_left_status:SwerveModuleStatus (id: 0);
+    front_right_status:SwerveModuleStatus (id: 1);
+    back_left_status:SwerveModuleStatus (id: 2);
+    back_right_status:SwerveModuleStatus (id: 3);
+}
+
+root_type Status;
diff --git a/frc971/imu/imu_calibrator.h b/frc971/imu/imu_calibrator.h
index be4c4d4..58ff12b 100644
--- a/frc971/imu/imu_calibrator.h
+++ b/frc971/imu/imu_calibrator.h
@@ -124,7 +124,7 @@
   Scalar time_offset;
 
   void PopulateParameters(
-      ceres::EigenQuaternionParameterization *quaternion_local_parameterization,
+      ceres::EigenQuaternionManifold *quaternion_local_parameterization,
       ceres::Problem *problem, ceres::DynamicCostFunction *cost_function,
       std::vector<double *> *parameters,
       std::vector<std::function<void()>> *post_populate_methods) {
@@ -134,8 +134,8 @@
     parameters->push_back(&time_offset);
     post_populate_methods->emplace_back(
         [this, problem, quaternion_local_parameterization]() {
-          problem->SetParameterization(rotation.coeffs().data(),
-                                       quaternion_local_parameterization);
+          problem->SetManifold(rotation.coeffs().data(),
+                               quaternion_local_parameterization);
           problem->SetParameterLowerBound(&time_offset, 0, -0.03);
           problem->SetParameterUpperBound(&time_offset, 0, 0.03);
         });
@@ -189,7 +189,7 @@
   std::vector<ImuConfig<Scalar>> imus;
   std::tuple<std::vector<double *>, std::vector<std::function<void()>>>
   PopulateParameters(
-      ceres::EigenQuaternionParameterization *quaternion_local_parameterization,
+      ceres::EigenQuaternionManifold *quaternion_local_parameterization,
       ceres::Problem *problem, ceres::DynamicCostFunction *cost_function) {
     std::vector<std::function<void()>> post_populate_methods;
     std::vector<double *> parameters;
diff --git a/frc971/imu/imu_calibrator_solver.cc b/frc971/imu/imu_calibrator_solver.cc
index 19b82e5..8948a47 100644
--- a/frc971/imu/imu_calibrator_solver.cc
+++ b/frc971/imu/imu_calibrator_solver.cc
@@ -38,8 +38,8 @@
     const std::vector<ImuConfig<double>> &nominal_config) {
   ceres::Problem problem;
 
-  ceres::EigenQuaternionParameterization *quaternion_local_parameterization =
-      new ceres::EigenQuaternionParameterization();
+  ceres::EigenQuaternionManifold *quaternion_local_parameterization =
+      new ceres::EigenQuaternionManifold();
   AllParameters<double> parameters;
   std::vector<size_t> num_readings;
   CHECK_EQ(nominal_config.size(), readings.size());
diff --git a/frc971/input/joystick_state.fbs b/frc971/input/joystick_state.fbs
index 49d2690..e8646a9 100644
--- a/frc971/input/joystick_state.fbs
+++ b/frc971/input/joystick_state.fbs
@@ -3,7 +3,7 @@
 enum MatchType : byte { kNone, kPractice, kQualification, kElimination }
 
 table Joystick {
-  // A bitmask of the butotn state.
+  // A bitmask of the button state.
   buttons:ushort (id: 0);
 
   // The 6 joystick axes.
diff --git a/frc971/orin/BUILD b/frc971/orin/BUILD
index f69fe85..3ffd800 100644
--- a/frc971/orin/BUILD
+++ b/frc971/orin/BUILD
@@ -54,7 +54,6 @@
         "//third_party/apriltag",
         "@com_github_google_glog//:glog",
         "@com_github_nvidia_cccl//:cccl",
-        "@com_github_nvidia_cuco//:cuco",
     ],
 )
 
diff --git a/frc971/orin/doflash_frc971.sh b/frc971/orin/doflash_frc971.sh
index f8cbbc3..ff4a705 100755
--- a/frc971/orin/doflash_frc971.sh
+++ b/frc971/orin/doflash_frc971.sh
@@ -1,23 +1,31 @@
 #!/bin/bash
 set -ex
 
-TMPDIR=$(mktemp -d /tmp/yoctoflash.XXXXXXXXXX)
+# If we pass in a folder, then use that as TMPDIR and don't clean it up
+if [[ -d $1 ]]; then
+    TMPDIR=$1
+else
+    TMPDIR=$(mktemp -d /tmp/yoctoflash.XXXXXXXXXX)
+    trap finish EXIT
+fi
 
 # Cleanup on exit.
 function finish {
   sudo rm -rf "${TMPDIR}"
 }
-trap finish EXIT
 
 # Call sudo to get it started here, rather than waiting for after tar/cp's
 sudo echo "Flashing orin"
 
-# Assumes that the image has been copied into ./
-tar xf frc971-image-orin-nx-8g.tegraflash.tar.gz -C "${TMPDIR}"
+# If the files haven't been extracted yet, do so now; otherwise, just
+# re-use what's already there
+if [[ ! -f ${TMPDIR}/initrd-flash ]]; then 
+    # Assumes that the image has been copied into ./
+    tar xf frc971-image-orin-nx-8g.tegraflash.tar.gz -C "${TMPDIR}"
 
-# Replace the rootfs with our new image.
-cp --sparse=always arm64_bookworm_debian_yocto.img "${TMPDIR}/frc971-image.ext4"
+    # Replace the rootfs with our new image.
+    cp --sparse=always arm64_bookworm_debian_yocto.img "${TMPDIR}/frc971-image.ext4"
+fi
 
 cd ${TMPDIR}
-
 sudo ./initrd-flash
diff --git a/frc971/orin/virtual_packages/glib-2.0-dev/DEBIAN/control b/frc971/orin/virtual_packages/glib-2.0-dev/DEBIAN/control
new file mode 100644
index 0000000..a0ff880
--- /dev/null
+++ b/frc971/orin/virtual_packages/glib-2.0-dev/DEBIAN/control
@@ -0,0 +1,7 @@
+Package: glib-2.0-dev
+Version: 2.74.6-2
+Architecture: arm64
+Depends: libglib2.0-dev
+Maintainer: Jim Ostrowski <yimmy13@gmail.com>
+Provides: glib-2.0-dev
+Description: Adapter for glib-2.0-dev
diff --git a/frc971/orin/virtual_packages/libxcb-dev/DEBIAN/control b/frc971/orin/virtual_packages/libxcb-dev/DEBIAN/control
new file mode 100644
index 0000000..6dfad1a
--- /dev/null
+++ b/frc971/orin/virtual_packages/libxcb-dev/DEBIAN/control
@@ -0,0 +1,7 @@
+Package: libxcb-dev
+Version: 1.15-1
+Architecture: arm64
+Depends: libxcb1-dev
+Maintainer: Jim Ostrowski <yimmy13@gmail.com>
+Provides: libxcb-dev
+Description: Adapter for libxcb-dev
diff --git a/frc971/orin/virtual_packages/wayland-dev/DEBIAN/control b/frc971/orin/virtual_packages/wayland-dev/DEBIAN/control
new file mode 100644
index 0000000..4c8c4f7
--- /dev/null
+++ b/frc971/orin/virtual_packages/wayland-dev/DEBIAN/control
@@ -0,0 +1,7 @@
+Package: wayland-dev
+Version: 1.21.0-1
+Architecture: arm64
+Depends: libwayland-dev
+Maintainer: Jim Ostrowski <yimmy13@gmail.com>
+Provides: wayland-dev
+Description: Adapter for wayland-dev
diff --git a/frc971/vision/BUILD b/frc971/vision/BUILD
index 01a6d1a..14e3d41 100644
--- a/frc971/vision/BUILD
+++ b/frc971/vision/BUILD
@@ -3,6 +3,72 @@
 load("//aos:config.bzl", "aos_config")
 load("//aos/flatbuffers:generate.bzl", "static_flatbuffer")
 
+cc_binary(
+    name = "modify_extrinsics",
+    srcs = [
+        "modify_extrinsics.cc",
+    ],
+    target_compatible_with = ["@platforms//os:linux"],
+    visibility = ["//visibility:public"],
+    deps = [
+        "//aos:configuration",
+        "//aos:init",
+        "//aos/events:event_loop",
+        "//frc971/vision:calibration_fbs",
+        "//frc971/vision:vision_util_lib",
+        "@com_google_absl//absl/strings:str_format",
+        "@org_tuxfamily_eigen//:eigen",
+    ],
+)
+
+cc_binary(
+    name = "image_replay",
+    srcs = [
+        "image_replay.cc",
+    ],
+    target_compatible_with = ["@platforms//os:linux"],
+    visibility = ["//visibility:public"],
+    deps = [
+        "//aos:configuration",
+        "//aos:init",
+        "//aos/events:simulated_event_loop",
+        "//aos/events/logging:log_reader",
+        "//frc971/vision:vision_fbs",
+        "//third_party:opencv",
+    ],
+)
+
+cc_binary(
+    name = "image_logger",
+    srcs = [
+        "image_logger.cc",
+    ],
+    target_compatible_with = ["@platforms//os:linux"],
+    visibility = ["//visibility:public"],
+    deps = [
+        "//aos:configuration",
+        "//aos:init",
+        "//aos/events:shm_event_loop",
+        "//aos/events/logging:log_writer",
+        "//aos/logging:log_namer",
+        "//aos/util:filesystem_fbs",
+        "//frc971/input:joystick_state_fbs",
+        "@com_github_gflags_gflags//:gflags",
+        "@com_github_google_glog//:glog",
+    ],
+)
+
+cc_binary(
+    name = "foxglove_image_converter",
+    srcs = ["foxglove_image_converter.cc"],
+    visibility = ["//visibility:public"],
+    deps = [
+        "//aos:init",
+        "//aos/events:shm_event_loop",
+        "//frc971/vision:foxglove_image_converter_lib",
+    ],
+)
+
 static_flatbuffer(
     name = "vision_fbs",
     srcs = ["vision.fbs"],
@@ -343,12 +409,7 @@
         "intrinsics_calibration.cc",
     ],
     target_compatible_with = ["@platforms//os:linux"],
-    visibility = [
-        "//y2020:__subpackages__",
-        "//y2022:__subpackages__",
-        "//y2023:__subpackages__",
-        "//y2024:__subpackages__",
-    ],
+    visibility = ["//visibility:public"],
     deps = [
         ":intrinsics_calibration_lib",
         "//aos:init",
diff --git a/frc971/vision/calibration_accumulator.cc b/frc971/vision/calibration_accumulator.cc
index 13481b4..bbf51ee 100644
--- a/frc971/vision/calibration_accumulator.cc
+++ b/frc971/vision/calibration_accumulator.cc
@@ -1,6 +1,7 @@
 #include "frc971/vision/calibration_accumulator.h"
 
 #include <algorithm>
+#include <iomanip>
 #include <limits>
 
 #include "Eigen/Dense"
diff --git a/frc971/vision/extrinsics_calibration.cc b/frc971/vision/extrinsics_calibration.cc
index 619ea89..2bbba9a 100644
--- a/frc971/vision/extrinsics_calibration.cc
+++ b/frc971/vision/extrinsics_calibration.cc
@@ -836,8 +836,8 @@
     CalibrationParameters *calibration_parameters) {
   ceres::Problem problem;
 
-  ceres::EigenQuaternionParameterization *quaternion_local_parameterization =
-      new ceres::EigenQuaternionParameterization();
+  ceres::EigenQuaternionManifold *quaternion_local_parameterization =
+      new ceres::EigenQuaternionManifold();
   // Set up the only cost function (also known as residual). This uses
   // auto-differentiation to obtain the derivative (jacobian).
 
@@ -874,9 +874,8 @@
   if (calibration_parameters->has_pivot) {
     // Constrain Z since it's along the rotation axis and therefore
     // redundant.
-    problem.SetParameterization(
-        calibration_parameters->pivot_to_imu_translation.data(),
-        new ceres::SubsetParameterization(3, {2}));
+    problem.SetManifold(calibration_parameters->pivot_to_imu_translation.data(),
+                        new ceres::SubsetManifold(3, {2}));
   } else {
     problem.SetParameterBlockConstant(
         calibration_parameters->pivot_to_imu.coeffs().data());
@@ -895,18 +894,15 @@
         calibration_parameters->board_to_world.coeffs().data());
   }
 
-  problem.SetParameterization(
+  problem.SetManifold(
       calibration_parameters->initial_orientation.coeffs().data(),
       quaternion_local_parameterization);
-  problem.SetParameterization(
-      calibration_parameters->pivot_to_camera.coeffs().data(),
-      quaternion_local_parameterization);
-  problem.SetParameterization(
-      calibration_parameters->pivot_to_imu.coeffs().data(),
-      quaternion_local_parameterization);
-  problem.SetParameterization(
-      calibration_parameters->board_to_world.coeffs().data(),
-      quaternion_local_parameterization);
+  problem.SetManifold(calibration_parameters->pivot_to_camera.coeffs().data(),
+                      quaternion_local_parameterization);
+  problem.SetManifold(calibration_parameters->pivot_to_imu.coeffs().data(),
+                      quaternion_local_parameterization);
+  problem.SetManifold(calibration_parameters->board_to_world.coeffs().data(),
+                      quaternion_local_parameterization);
   for (int i = 0; i < 3; ++i) {
     problem.SetParameterLowerBound(calibration_parameters->gyro_bias.data(), i,
                                    -0.05);
diff --git a/y2024/vision/foxglove_image_converter.cc b/frc971/vision/foxglove_image_converter.cc
similarity index 100%
rename from y2024/vision/foxglove_image_converter.cc
rename to frc971/vision/foxglove_image_converter.cc
diff --git a/y2024/vision/image_logger.cc b/frc971/vision/image_logger.cc
similarity index 100%
rename from y2024/vision/image_logger.cc
rename to frc971/vision/image_logger.cc
diff --git a/frc971/vision/image_replay.cc b/frc971/vision/image_replay.cc
new file mode 100644
index 0000000..3b75c92
--- /dev/null
+++ b/frc971/vision/image_replay.cc
@@ -0,0 +1,47 @@
+#include "gflags/gflags.h"
+#include "opencv2/highgui.hpp"
+#include "opencv2/imgproc.hpp"
+
+#include "aos/events/logging/log_reader.h"
+#include "aos/events/logging/log_writer.h"
+#include "aos/events/simulated_event_loop.h"
+#include "aos/init.h"
+#include "aos/json_to_flatbuffer.h"
+#include "aos/logging/log_message_generated.h"
+#include "frc971/vision/vision_generated.h"
+
+DEFINE_string(node, "orin1", "The node to view the log from");
+DEFINE_string(channel, "/camera0", "The channel to view the log from");
+
+int main(int argc, char **argv) {
+  aos::InitGoogle(&argc, &argv);
+
+  // open logfiles
+  aos::logger::LogReader reader(
+      aos::logger::SortParts(aos::logger::FindLogs(argc, argv)));
+
+  aos::SimulatedEventLoopFactory factory(reader.configuration());
+  reader.Register(&factory);
+
+  aos::NodeEventLoopFactory *node = factory.GetNodeEventLoopFactory(FLAGS_node);
+
+  std::unique_ptr<aos::EventLoop> image_loop = node->MakeEventLoop("image");
+  image_loop->MakeWatcher(
+      "/" + FLAGS_node + "/" + FLAGS_channel,
+      [](const frc971::vision::CameraImage &msg) {
+        cv::Mat color_image(cv::Size(msg.cols(), msg.rows()), CV_8UC2,
+                            (void *)msg.data()->data());
+
+        cv::Mat bgr(color_image.size(), CV_8UC3);
+        cv::cvtColor(color_image, bgr, cv::COLOR_YUV2BGR_YUYV);
+
+        cv::imshow("Replay", bgr);
+        cv::waitKey(1);
+      });
+
+  factory.Run();
+
+  reader.Deregister();
+
+  return 0;
+}
diff --git a/y2024/vision/modify_extrinsics.cc b/frc971/vision/modify_extrinsics.cc
similarity index 100%
rename from y2024/vision/modify_extrinsics.cc
rename to frc971/vision/modify_extrinsics.cc
diff --git a/y2024/vision/rename_calibration_file.sh b/frc971/vision/rename_calibration_file.sh
similarity index 100%
copy from y2024/vision/rename_calibration_file.sh
copy to frc971/vision/rename_calibration_file.sh
diff --git a/frc971/vision/target_mapper.cc b/frc971/vision/target_mapper.cc
index b9b3712..57ab6e4 100644
--- a/frc971/vision/target_mapper.cc
+++ b/frc971/vision/target_mapper.cc
@@ -313,8 +313,8 @@
   }
 
   ceres::LossFunction *loss_function = new ceres::HuberLoss(2.0);
-  ceres::LocalParameterization *quaternion_local_parameterization =
-      new ceres::EigenQuaternionParameterization;
+  ceres::Manifold *quaternion_local_parameterization =
+      new ceres::EigenQuaternionManifold();
 
   int min_constraint_id = std::numeric_limits<int>::max();
   int max_constraint_id = std::numeric_limits<int>::min();
@@ -368,10 +368,10 @@
                               pose_end_iter->second.p.data(),
                               pose_end_iter->second.q.coeffs().data());
 
-    problem->SetParameterization(pose_begin_iter->second.q.coeffs().data(),
-                                 quaternion_local_parameterization);
-    problem->SetParameterization(pose_end_iter->second.q.coeffs().data(),
-                                 quaternion_local_parameterization);
+    problem->SetManifold(pose_begin_iter->second.q.coeffs().data(),
+                         quaternion_local_parameterization);
+    problem->SetManifold(pose_end_iter->second.q.coeffs().data(),
+                         quaternion_local_parameterization);
   }
 
   // The pose graph optimization problem has six DOFs that are not fully
@@ -411,14 +411,14 @@
       this, num_residuals, ceres::DO_NOT_TAKE_OWNERSHIP);
 
   ceres::LossFunction *loss_function = new ceres::HuberLoss(2.0);
-  ceres::LocalParameterization *quaternion_local_parameterization =
-      new ceres::EigenQuaternionParameterization;
+  ceres::Manifold *quaternion_local_parameterization =
+      new ceres::EigenQuaternionManifold();
 
   problem->AddResidualBlock(cost_function.get(), loss_function,
                             T_frozen_actual_.vector().data(),
                             R_frozen_actual_.coeffs().data());
-  problem->SetParameterization(R_frozen_actual_.coeffs().data(),
-                               quaternion_local_parameterization);
+  problem->SetManifold(R_frozen_actual_.coeffs().data(),
+                       quaternion_local_parameterization);
   return cost_function;
 }
 
diff --git a/frc971/wpilib/swerve/BUILD b/frc971/wpilib/swerve/BUILD
index 4493781..0b2cc1c 100644
--- a/frc971/wpilib/swerve/BUILD
+++ b/frc971/wpilib/swerve/BUILD
@@ -12,7 +12,9 @@
         ":swerve_module",
         "//aos/logging",
         "//frc971:can_configuration_fbs",
-        "//frc971/control_loops/drivetrain/swerve:swerve_drivetrain_output_fbs",
+        "//frc971/control_loops/swerve:swerve_drivetrain_can_position_fbs",
+        "//frc971/control_loops/swerve:swerve_drivetrain_output_fbs",
+        "//frc971/control_loops/swerve:swerve_drivetrain_position_fbs",
         "//frc971/wpilib:loop_output_handler",
         "//frc971/wpilib:talonfx",
         "//third_party:phoenix6",
@@ -25,6 +27,7 @@
         "swerve_module.h",
     ],
     deps = [
+        "//frc971/wpilib:encoder_and_potentiometer",
         "//frc971/wpilib:talonfx",
     ],
 )
diff --git a/frc971/wpilib/swerve/swerve_drivetrain_writer.cc b/frc971/wpilib/swerve/swerve_drivetrain_writer.cc
index e4b4ee9..44aff53 100644
--- a/frc971/wpilib/swerve/swerve_drivetrain_writer.cc
+++ b/frc971/wpilib/swerve/swerve_drivetrain_writer.cc
@@ -6,27 +6,21 @@
                                    int drivetrain_writer_priority,
                                    double max_voltage)
     : ::frc971::wpilib::LoopOutputHandler<
-          ::frc971::control_loops::drivetrain::swerve::Output>(event_loop,
-                                                               "/drivetrain"),
+          ::frc971::control_loops::swerve::Output>(event_loop, "/drivetrain"),
       max_voltage_(max_voltage) {
   event_loop->SetRuntimeRealtimePriority(drivetrain_writer_priority);
 
   event_loop->OnRun([this]() { WriteConfigs(); });
 }
 
-void DrivetrainWriter::set_talonfxs(std::shared_ptr<SwerveModule> front_left,
-                                    std::shared_ptr<SwerveModule> front_right,
-                                    std::shared_ptr<SwerveModule> back_left,
-                                    std::shared_ptr<SwerveModule> back_right) {
-  front_left_ = std::move(front_left);
-  front_right_ = std::move(front_right);
-  back_left_ = std::move(back_left);
-  back_right_ = std::move(back_right);
+void DrivetrainWriter::set_talonfxs(SwerveModules modules) {
+  modules_ = std::move(modules);
 }
 
 void DrivetrainWriter::HandleCANConfiguration(
     const CANConfiguration &configuration) {
-  for (auto module : {front_left_, front_right_, back_left_, back_right_}) {
+  for (auto module : {modules_.front_left, modules_.front_right,
+                      modules_.back_left, modules_.back_right}) {
     module->rotation->PrintConfigs();
     module->translation->PrintConfigs();
   }
@@ -36,24 +30,26 @@
 }
 
 void DrivetrainWriter::WriteConfigs() {
-  for (auto module : {front_left_, front_right_, back_left_, back_right_}) {
+  for (auto module : {modules_.front_left, modules_.front_right,
+                      modules_.back_left, modules_.back_right}) {
     module->rotation->WriteConfigs();
     module->translation->WriteConfigs();
   }
 }
 
 void DrivetrainWriter::Write(
-    const ::frc971::control_loops::drivetrain::swerve::Output &output) {
-  front_left_->WriteModule(output.front_left_output(), max_voltage_);
-  front_right_->WriteModule(output.front_right_output(), max_voltage_);
-  back_left_->WriteModule(output.back_left_output(), max_voltage_);
-  back_right_->WriteModule(output.back_right_output(), max_voltage_);
+    const ::frc971::control_loops::swerve::Output &output) {
+  modules_.front_left->WriteModule(output.front_left_output(), max_voltage_);
+  modules_.front_right->WriteModule(output.front_right_output(), max_voltage_);
+  modules_.back_left->WriteModule(output.back_left_output(), max_voltage_);
+  modules_.back_right->WriteModule(output.back_right_output(), max_voltage_);
 }
 
 void DrivetrainWriter::Stop() {
   AOS_LOG(WARNING, "drivetrain output too old\n");
 
-  for (auto module : {front_left_, front_right_, back_left_, back_right_}) {
+  for (auto module : {modules_.front_left, modules_.front_right,
+                      modules_.back_left, modules_.back_right}) {
     module->rotation->WriteCurrent(0, 0);
     module->translation->WriteCurrent(0, 0);
   }
diff --git a/frc971/wpilib/swerve/swerve_drivetrain_writer.h b/frc971/wpilib/swerve/swerve_drivetrain_writer.h
index 8e9e616..3b79186 100644
--- a/frc971/wpilib/swerve/swerve_drivetrain_writer.h
+++ b/frc971/wpilib/swerve/swerve_drivetrain_writer.h
@@ -4,7 +4,7 @@
 #include "ctre/phoenix6/TalonFX.hpp"
 
 #include "frc971/can_configuration_generated.h"
-#include "frc971/control_loops/drivetrain/swerve/swerve_drivetrain_output_generated.h"
+#include "frc971/control_loops/swerve/swerve_drivetrain_output_generated.h"
 #include "frc971/wpilib/loop_output_handler.h"
 #include "frc971/wpilib/swerve/swerve_module.h"
 #include "frc971/wpilib/talonfx.h"
@@ -13,32 +13,26 @@
 
 // Reads from the swerve output flatbuffer and uses wpilib to set the current
 // for each motor.
-class DrivetrainWriter
-    : public ::frc971::wpilib::LoopOutputHandler<
-          ::frc971::control_loops::drivetrain::swerve::Output> {
+class DrivetrainWriter : public ::frc971::wpilib::LoopOutputHandler<
+                             ::frc971::control_loops::swerve::Output> {
  public:
   DrivetrainWriter(::aos::EventLoop *event_loop, int drivetrain_writer_priority,
                    double max_voltage);
 
-  void set_talonfxs(std::shared_ptr<SwerveModule> front_left,
-                    std::shared_ptr<SwerveModule> front_right,
-                    std::shared_ptr<SwerveModule> back_left,
-                    std::shared_ptr<SwerveModule> back_right);
+  void set_talonfxs(SwerveModules modules);
 
   void HandleCANConfiguration(const CANConfiguration &configuration);
 
  private:
   void WriteConfigs();
 
-  void Write(const ::frc971::control_loops::drivetrain::swerve::Output &output)
-      override;
+  void Write(const ::frc971::control_loops::swerve::Output &output) override;
 
   void Stop() override;
 
   double SafeSpeed(double voltage);
 
-  std::shared_ptr<SwerveModule> front_left_, front_right_, back_left_,
-      back_right_;
+  SwerveModules modules_;
 
   double max_voltage_;
 };
diff --git a/frc971/wpilib/swerve/swerve_module.h b/frc971/wpilib/swerve/swerve_module.h
index c373a31..c01df24 100644
--- a/frc971/wpilib/swerve/swerve_module.h
+++ b/frc971/wpilib/swerve/swerve_module.h
@@ -1,10 +1,17 @@
 #ifndef FRC971_WPILIB_SWERVE_SWERVE_MODULE_H_
 #define FRC971_WPILIB_SWERVE_SWERVE_MODULE_H_
 
+#include "frc971/control_loops/swerve/swerve_drivetrain_can_position_static.h"
+#include "frc971/control_loops/swerve/swerve_drivetrain_output_generated.h"
+#include "frc971/control_loops/swerve/swerve_drivetrain_position_static.h"
+#include "frc971/wpilib/encoder_and_potentiometer.h"
 #include "frc971/wpilib/talonfx.h"
 
 namespace frc971::wpilib::swerve {
 
+// Contains the objects for interacting with the hardware for a given swerve
+// module, assuming that the module uses two TalonFX-based motor controllers and
+// has a CTRE mag encoder on the rotation of the module.
 struct SwerveModule {
   SwerveModule(TalonFXParams rotation_params, TalonFXParams translation_params,
                std::string canbus,
@@ -17,9 +24,10 @@
                                               signals, stator_current_limit,
                                               supply_current_limit)) {}
 
+  // Writes the requested torque currents from the module_output to the motors,
+  // setting the maximum voltage of the motor outputs to the requested value.
   void WriteModule(
-      const frc971::control_loops::drivetrain::swerve::SwerveModuleOutput
-          *module_output,
+      const frc971::control_loops::swerve::SwerveModuleOutput *module_output,
       double max_voltage) {
     double rotation_current = 0.0;
     double translation_current = 0.0;
@@ -33,8 +41,58 @@
     translation->WriteCurrent(translation_current, max_voltage);
   }
 
+  // Used during initialization to set the WPILib objects used by the mag
+  // encoder on the rotation joint.
+  void set_rotation_encoder(std::unique_ptr<frc::Encoder> encoder,
+                            std::unique_ptr<frc::DigitalInput> absolute_pwm) {
+    rotation_encoder.set_encoder(std::move(encoder));
+    rotation_encoder.set_absolute_pwm(std::move(absolute_pwm));
+  }
+
+  // Populates the Position message with the mag encoder values.
+  void PopulatePosition(
+      frc971::control_loops::swerve::SwerveModulePositionStatic *fbs) {
+    auto rotation_position = fbs->add_rotation_position();
+    rotation_position->set_encoder(rotation_encoder.ReadRelativeEncoder());
+    rotation_position->set_absolute_encoder(
+        rotation_encoder.ReadAbsoluteEncoder());
+  }
+
+  // Populates a CAN-position message with the CAN-based devices (currently,
+  // just the motors themselves).
+  void PopulateCanPosition(
+      frc971::control_loops::swerve::SwerveModuleCanPositionStatic
+          *can_position) {
+    // TODO(james): Source these numbers from the constants.json.
+    rotation->SerializePosition(can_position->add_rotation(), 1.0);
+    translation->SerializePosition(can_position->add_translation(), 1.0);
+  }
+
   std::shared_ptr<TalonFX> rotation;
   std::shared_ptr<TalonFX> translation;
+  frc971::wpilib::AbsoluteEncoder rotation_encoder;
+};
+
+// Represents all the modules in a swerve drivetrain.
+struct SwerveModules {
+  void PopulateFalconsVector(std::vector<std::shared_ptr<TalonFX>> *falcons) {
+    CHECK_NOTNULL(falcons)->push_back(front_left->rotation);
+    falcons->push_back(front_left->translation);
+
+    falcons->push_back(front_right->rotation);
+    falcons->push_back(front_right->translation);
+
+    falcons->push_back(back_left->rotation);
+    falcons->push_back(back_left->translation);
+
+    falcons->push_back(back_right->rotation);
+    falcons->push_back(back_right->translation);
+  }
+
+  std::shared_ptr<SwerveModule> front_left;
+  std::shared_ptr<SwerveModule> front_right;
+  std::shared_ptr<SwerveModule> back_left;
+  std::shared_ptr<SwerveModule> back_right;
 };
 
 }  // namespace frc971::wpilib::swerve
diff --git a/frc971/www/BUILD b/frc971/www/BUILD
new file mode 100644
index 0000000..060912b
--- /dev/null
+++ b/frc971/www/BUILD
@@ -0,0 +1,37 @@
+load("//tools/build_rules:js.bzl", "rollup_bundle", "ts_project")
+
+package(default_visibility = ["//visibility:public"])
+
+filegroup(
+    name = "starter_files",
+    srcs = [
+        "starter.html",
+        "starter_main_bundle.min.js",
+        "styles.css",
+    ],
+)
+
+ts_project(
+    name = "starter_main",
+    srcs = [
+        "starter_handler.ts",
+        "starter_main.ts",
+    ],
+    target_compatible_with = ["@platforms//os:linux"],
+    deps = [
+        "//aos/network:connect_ts_fbs",
+        "//aos/network:message_bridge_client_ts_fbs",
+        "//aos/network/www:proxy",
+        "//aos/starter:starter_ts_fbs",
+        "@com_github_google_flatbuffers//ts:flatbuffers_ts",
+    ],
+)
+
+rollup_bundle(
+    name = "starter_main_bundle",
+    entry_point = "starter_main.ts",
+    target_compatible_with = ["@platforms//os:linux"],
+    deps = [
+        ":starter_main",
+    ],
+)
diff --git a/y2024/www/starter.html b/frc971/www/starter.html
similarity index 100%
rename from y2024/www/starter.html
rename to frc971/www/starter.html
diff --git a/y2024/www/starter_handler.ts b/frc971/www/starter_handler.ts
similarity index 100%
rename from y2024/www/starter_handler.ts
rename to frc971/www/starter_handler.ts
diff --git a/y2024/www/starter_main.ts b/frc971/www/starter_main.ts
similarity index 100%
rename from y2024/www/starter_main.ts
rename to frc971/www/starter_main.ts
diff --git a/y2024/www/styles.css b/frc971/www/styles.css
similarity index 100%
rename from y2024/www/styles.css
rename to frc971/www/styles.css
diff --git a/package.json b/package.json
index f37a2b6..5f7b0f2 100644
--- a/package.json
+++ b/package.json
@@ -20,6 +20,7 @@
     "@types/babel__generator": "^7.6.8",
     "@types/pako": "2.0.3",
     "angularx-qrcode": "^16.0.2",
+    "create-foxglove-extension": "^0.8.6",
     "html-insert-assets": "0.14.3",
     "cypress": "13.3.1",
     "pako": "2.1.0",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 5411319..d8164ab 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -67,6 +67,9 @@
       angularx-qrcode:
         specifier: ^16.0.2
         version: 16.0.2(@angular/core@16.2.12)(@angular/platform-browser@16.2.12)
+      create-foxglove-extension:
+        specifier: ^0.8.6
+        version: 0.8.6(typescript@5.1.6)
       cypress:
         specifier: 13.3.1
         version: 13.3.1
@@ -101,6 +104,72 @@
         specifier: ^0.13.0
         version: 0.13.3
 
+  aos/analysis/foxglove_extension:
+    dependencies:
+      '@foxglove/eslint-plugin':
+        specifier: ^1
+        version: 1.0.1(eslint-config-prettier@8.10.0)(eslint-plugin-es@4.1.0)(eslint-plugin-filenames@1.3.2)(eslint-plugin-import@2.29.1)(eslint-plugin-prettier@5.1.3)(eslint@8.57.0)(prettier@3.2.5)
+      '@foxglove/studio':
+        specifier: ^1
+        version: 1.87.0
+      '@types/react':
+        specifier: ^18
+        version: 18.3.1
+      '@types/react-dom':
+        specifier: ^18
+        version: 18.3.0
+      '@typescript-eslint/eslint-plugin':
+        specifier: ^6
+        version: 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.57.0)(typescript@5.1.6)
+      '@typescript-eslint/parser':
+        specifier: ^6
+        version: 6.21.0(eslint@8.57.0)(typescript@5.1.6)
+      create-foxglove-extension:
+        specifier: ^0
+        version: 0.8.6(typescript@5.1.6)
+      eslint:
+        specifier: ^8
+        version: 8.57.0
+      eslint-config-prettier:
+        specifier: ^8
+        version: 8.10.0(eslint@8.57.0)
+      eslint-plugin-es:
+        specifier: ^4
+        version: 4.1.0(eslint@8.57.0)
+      eslint-plugin-filenames:
+        specifier: ^1
+        version: 1.3.2(eslint@8.57.0)
+      eslint-plugin-import:
+        specifier: ^2
+        version: 2.29.1(@typescript-eslint/parser@6.21.0)(eslint@8.57.0)
+      eslint-plugin-jest:
+        specifier: ^27
+        version: 27.9.0(@typescript-eslint/eslint-plugin@6.21.0)(eslint@8.57.0)(typescript@5.1.6)
+      eslint-plugin-prettier:
+        specifier: ^5
+        version: 5.1.3(eslint-config-prettier@8.10.0)(eslint@8.57.0)(prettier@3.2.5)
+      eslint-plugin-react:
+        specifier: ^7
+        version: 7.34.1(eslint@8.57.0)
+      eslint-plugin-react-hooks:
+        specifier: ^4
+        version: 4.6.2(eslint@8.57.0)
+      prettier:
+        specifier: ^3
+        version: 3.2.5
+      react:
+        specifier: ^18
+        version: 18.3.1
+      react-dom:
+        specifier: ^18
+        version: 18.3.1(react@18.3.1)
+      ts-loader:
+        specifier: ^9
+        version: 9.4.2(typescript@5.1.6)(webpack@5.75.0)
+      typescript:
+        specifier: ^5
+        version: 5.1.6
+
   scouting/webserver/requests/messages: {}
 
   scouting/www:
@@ -738,10 +807,96 @@
       - supports-color
     dev: true
 
+  /@eslint-community/eslint-utils@4.4.0(eslint@8.57.0):
+    resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    peerDependencies:
+      eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
+    dependencies:
+      eslint: 8.57.0
+      eslint-visitor-keys: 3.4.3
+    dev: false
+
+  /@eslint-community/regexpp@4.10.0:
+    resolution: {integrity: sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==}
+    engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
+    dev: false
+
+  /@eslint/eslintrc@2.1.4:
+    resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    dependencies:
+      ajv: 6.12.6
+      debug: 4.3.4(supports-color@8.1.1)
+      espree: 9.6.1
+      globals: 13.24.0
+      ignore: 5.3.1
+      import-fresh: 3.3.0
+      js-yaml: 4.1.0
+      minimatch: 3.1.2
+      strip-json-comments: 3.1.1
+    transitivePeerDependencies:
+      - supports-color
+    dev: false
+
+  /@eslint/js@8.57.0:
+    resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    dev: false
+
+  /@foxglove/eslint-plugin@1.0.1(eslint-config-prettier@8.10.0)(eslint-plugin-es@4.1.0)(eslint-plugin-filenames@1.3.2)(eslint-plugin-import@2.29.1)(eslint-plugin-prettier@5.1.3)(eslint@8.57.0)(prettier@3.2.5):
+    resolution: {integrity: sha512-5rDfBwQ2gQwXzVZgNGM0j9MrhcPSbEShG3JebkMBgMvh7SCyeWis3m78R2M03wzDsr7tU5RqM0+W//nH+ZDW2Q==}
+    peerDependencies:
+      eslint: ^7 || ^8
+      eslint-config-prettier: ^8 || ^9
+      eslint-plugin-es: ^4
+      eslint-plugin-filenames: ^1
+      eslint-plugin-import: ^2
+      eslint-plugin-prettier: ^5
+      prettier: ^3
+    dependencies:
+      '@typescript-eslint/utils': 6.21.0(eslint@8.57.0)(typescript@5.1.6)
+      eslint: 8.57.0
+      eslint-config-prettier: 8.10.0(eslint@8.57.0)
+      eslint-plugin-es: 4.1.0(eslint@8.57.0)
+      eslint-plugin-filenames: 1.3.2(eslint@8.57.0)
+      eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0)(eslint@8.57.0)
+      eslint-plugin-prettier: 5.1.3(eslint-config-prettier@8.10.0)(eslint@8.57.0)(prettier@3.2.5)
+      prettier: 3.2.5
+      tsutils: 3.21.0(typescript@5.1.6)
+      typescript: 5.1.6
+    transitivePeerDependencies:
+      - supports-color
+    dev: false
+
+  /@foxglove/studio@1.87.0:
+    resolution: {integrity: sha512-78wvD3SPBNUUoYTIe5b8Zol7Cv7lbf18iUNjnPXf8j43ZHuKLaBXXJv4eBK1alxQ+NRdRLHbb/iJdjtt6PTdLQ==}
+    dev: false
+
   /@gar/promisify@1.1.3:
     resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==}
     dev: true
 
+  /@humanwhocodes/config-array@0.11.14:
+    resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==}
+    engines: {node: '>=10.10.0'}
+    dependencies:
+      '@humanwhocodes/object-schema': 2.0.3
+      debug: 4.3.4(supports-color@8.1.1)
+      minimatch: 3.1.2
+    transitivePeerDependencies:
+      - supports-color
+    dev: false
+
+  /@humanwhocodes/module-importer@1.0.1:
+    resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
+    engines: {node: '>=12.22'}
+    dev: false
+
+  /@humanwhocodes/object-schema@2.0.3:
+    resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==}
+    dev: false
+
   /@isaacs/cliui@8.0.2:
     resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
     engines: {node: '>=12'}
@@ -766,7 +921,6 @@
   /@jridgewell/resolve-uri@3.1.0:
     resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==}
     engines: {node: '>=6.0.0'}
-    dev: true
 
   /@jridgewell/set-array@1.1.2:
     resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==}
@@ -775,7 +929,6 @@
 
   /@jridgewell/source-map@0.3.4:
     resolution: {integrity: sha512-KE/SxsDqNs3rrWwFHcRh15ZLVFrI0YoZtgAdIyIq9k5hUNmiWRXXThPomIxHuL20sLdgzbDFyvkUMna14bvtrw==}
-    dev: true
 
   /@jridgewell/sourcemap-codec@1.4.14:
     resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==}
@@ -783,7 +936,6 @@
 
   /@jridgewell/sourcemap-codec@1.4.15:
     resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==}
-    dev: true
 
   /@jridgewell/trace-mapping@0.3.18:
     resolution: {integrity: sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==}
@@ -792,12 +944,39 @@
       '@jridgewell/sourcemap-codec': 1.4.14
     dev: true
 
+  /@jridgewell/trace-mapping@0.3.25:
+    resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
+    dependencies:
+      '@jridgewell/resolve-uri': 3.1.0
+      '@jridgewell/sourcemap-codec': 1.4.15
+
   /@nicolo-ribaudo/chokidar-2@2.1.8-no-fsevents.3:
     resolution: {integrity: sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ==}
     requiresBuild: true
     dev: true
     optional: true
 
+  /@nodelib/fs.scandir@2.1.5:
+    resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
+    engines: {node: '>= 8'}
+    dependencies:
+      '@nodelib/fs.stat': 2.0.5
+      run-parallel: 1.2.0
+    dev: false
+
+  /@nodelib/fs.stat@2.0.5:
+    resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
+    engines: {node: '>= 8'}
+    dev: false
+
+  /@nodelib/fs.walk@1.2.8:
+    resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
+    engines: {node: '>= 8'}
+    dependencies:
+      '@nodelib/fs.scandir': 2.1.5
+      fastq: 1.17.1
+    dev: false
+
   /@npmcli/fs@2.1.2:
     resolution: {integrity: sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==}
     engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
@@ -880,6 +1059,11 @@
     dev: true
     optional: true
 
+  /@pkgr/core@0.1.1:
+    resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==}
+    engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
+    dev: false
+
   /@rollup/plugin-node-resolve@15.2.3(rollup@4.12.0):
     resolution: {integrity: sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ==}
     engines: {node: '>=14.0.0'}
@@ -1119,18 +1303,48 @@
     dependencies:
       '@types/node': 20.11.19
 
+  /@types/eslint-scope@3.7.7:
+    resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==}
+    dependencies:
+      '@types/eslint': 8.56.6
+      '@types/estree': 1.0.5
+
+  /@types/eslint@8.56.6:
+    resolution: {integrity: sha512-ymwc+qb1XkjT/gfoQwxIeHZ6ixH23A+tCT2ADSA/DPVKzAjwYkTXBMCQ/f6fe4wEa85Lhp26VPeUxI7wMhAi7A==}
+    dependencies:
+      '@types/estree': 1.0.5
+      '@types/json-schema': 7.0.15
+
+  /@types/estree@0.0.51:
+    resolution: {integrity: sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==}
+
   /@types/estree@1.0.5:
     resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==}
-    dev: true
 
   /@types/flatbuffers@1.10.0:
     resolution: {integrity: sha512-7btbphLrKvo5yl/5CC2OCxUSMx1wV1wvGT1qDXkSt7yi00/YW7E8k6qzXqJHsp+WU0eoG7r6MTQQXI9lIvd0qA==}
     dev: true
 
+  /@types/glob@7.2.0:
+    resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==}
+    dependencies:
+      '@types/minimatch': 5.1.2
+      '@types/node': 20.11.19
+
   /@types/jasmine@3.10.3:
     resolution: {integrity: sha512-SWyMrjgdAUHNQmutvDcKablrJhkDLy4wunTme8oYLjKp41GnHGxMRXr2MQMvy/qy8H3LdzwQk9gH4hZ6T++H8g==}
     dev: true
 
+  /@types/json-schema@7.0.15:
+    resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
+
+  /@types/json5@0.0.29:
+    resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
+    dev: false
+
+  /@types/minimatch@5.1.2:
+    resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==}
+
   /@types/node@18.19.22:
     resolution: {integrity: sha512-p3pDIfuMg/aXBmhkyanPshdfJuX5c5+bQjYLIikPLXAUycEogij/c50n/C+8XOA5L93cU4ZRXtn+dNQGi0IZqQ==}
     dependencies:
@@ -1145,10 +1359,31 @@
   /@types/pako@2.0.3:
     resolution: {integrity: sha512-bq0hMV9opAcrmE0Byyo0fY3Ew4tgOevJmQ9grUhpXQhYfyLJ1Kqg3P33JT5fdbT2AjeAjR51zqqVjAL/HMkx7Q==}
 
+  /@types/prop-types@15.7.12:
+    resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==}
+    dev: false
+
+  /@types/react-dom@18.3.0:
+    resolution: {integrity: sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==}
+    dependencies:
+      '@types/react': 18.3.1
+    dev: false
+
+  /@types/react@18.3.1:
+    resolution: {integrity: sha512-V0kuGBX3+prX+DQ/7r2qsv1NsdfnCLnTgnRJ1pYnxykBhGMz+qj+box5lq7XsO5mtZsBqpjwwTu/7wszPfMBcw==}
+    dependencies:
+      '@types/prop-types': 15.7.12
+      csstype: 3.1.3
+    dev: false
+
   /@types/resolve@1.20.2:
     resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
     dev: true
 
+  /@types/semver@7.5.8:
+    resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==}
+    dev: false
+
   /@types/sinonjs__fake-timers@8.1.1:
     resolution: {integrity: sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==}
     dev: true
@@ -1165,6 +1400,301 @@
     dev: true
     optional: true
 
+  /@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.57.0)(typescript@5.1.6):
+    resolution: {integrity: sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==}
+    engines: {node: ^16.0.0 || >=18.0.0}
+    peerDependencies:
+      '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha
+      eslint: ^7.0.0 || ^8.0.0
+      typescript: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+    dependencies:
+      '@eslint-community/regexpp': 4.10.0
+      '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.1.6)
+      '@typescript-eslint/scope-manager': 6.21.0
+      '@typescript-eslint/type-utils': 6.21.0(eslint@8.57.0)(typescript@5.1.6)
+      '@typescript-eslint/utils': 6.21.0(eslint@8.57.0)(typescript@5.1.6)
+      '@typescript-eslint/visitor-keys': 6.21.0
+      debug: 4.3.4(supports-color@8.1.1)
+      eslint: 8.57.0
+      graphemer: 1.4.0
+      ignore: 5.3.1
+      natural-compare: 1.4.0
+      semver: 7.6.0
+      ts-api-utils: 1.3.0(typescript@5.1.6)
+      typescript: 5.1.6
+    transitivePeerDependencies:
+      - supports-color
+    dev: false
+
+  /@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.6):
+    resolution: {integrity: sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==}
+    engines: {node: ^16.0.0 || >=18.0.0}
+    peerDependencies:
+      eslint: ^7.0.0 || ^8.0.0
+      typescript: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+    dependencies:
+      '@typescript-eslint/scope-manager': 6.21.0
+      '@typescript-eslint/types': 6.21.0
+      '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.1.6)
+      '@typescript-eslint/visitor-keys': 6.21.0
+      debug: 4.3.4(supports-color@8.1.1)
+      eslint: 8.57.0
+      typescript: 5.1.6
+    transitivePeerDependencies:
+      - supports-color
+    dev: false
+
+  /@typescript-eslint/scope-manager@5.62.0:
+    resolution: {integrity: sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    dependencies:
+      '@typescript-eslint/types': 5.62.0
+      '@typescript-eslint/visitor-keys': 5.62.0
+    dev: false
+
+  /@typescript-eslint/scope-manager@6.21.0:
+    resolution: {integrity: sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==}
+    engines: {node: ^16.0.0 || >=18.0.0}
+    dependencies:
+      '@typescript-eslint/types': 6.21.0
+      '@typescript-eslint/visitor-keys': 6.21.0
+    dev: false
+
+  /@typescript-eslint/type-utils@6.21.0(eslint@8.57.0)(typescript@5.1.6):
+    resolution: {integrity: sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==}
+    engines: {node: ^16.0.0 || >=18.0.0}
+    peerDependencies:
+      eslint: ^7.0.0 || ^8.0.0
+      typescript: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+    dependencies:
+      '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.1.6)
+      '@typescript-eslint/utils': 6.21.0(eslint@8.57.0)(typescript@5.1.6)
+      debug: 4.3.4(supports-color@8.1.1)
+      eslint: 8.57.0
+      ts-api-utils: 1.3.0(typescript@5.1.6)
+      typescript: 5.1.6
+    transitivePeerDependencies:
+      - supports-color
+    dev: false
+
+  /@typescript-eslint/types@5.62.0:
+    resolution: {integrity: sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    dev: false
+
+  /@typescript-eslint/types@6.21.0:
+    resolution: {integrity: sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==}
+    engines: {node: ^16.0.0 || >=18.0.0}
+    dev: false
+
+  /@typescript-eslint/typescript-estree@5.62.0(typescript@5.1.6):
+    resolution: {integrity: sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    peerDependencies:
+      typescript: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+    dependencies:
+      '@typescript-eslint/types': 5.62.0
+      '@typescript-eslint/visitor-keys': 5.62.0
+      debug: 4.3.4(supports-color@8.1.1)
+      globby: 11.1.0
+      is-glob: 4.0.3
+      semver: 7.6.0
+      tsutils: 3.21.0(typescript@5.1.6)
+      typescript: 5.1.6
+    transitivePeerDependencies:
+      - supports-color
+    dev: false
+
+  /@typescript-eslint/typescript-estree@6.21.0(typescript@5.1.6):
+    resolution: {integrity: sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==}
+    engines: {node: ^16.0.0 || >=18.0.0}
+    peerDependencies:
+      typescript: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+    dependencies:
+      '@typescript-eslint/types': 6.21.0
+      '@typescript-eslint/visitor-keys': 6.21.0
+      debug: 4.3.4(supports-color@8.1.1)
+      globby: 11.1.0
+      is-glob: 4.0.3
+      minimatch: 9.0.3
+      semver: 7.6.0
+      ts-api-utils: 1.3.0(typescript@5.1.6)
+      typescript: 5.1.6
+    transitivePeerDependencies:
+      - supports-color
+    dev: false
+
+  /@typescript-eslint/utils@5.62.0(eslint@8.57.0)(typescript@5.1.6):
+    resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    peerDependencies:
+      eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
+    dependencies:
+      '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
+      '@types/json-schema': 7.0.15
+      '@types/semver': 7.5.8
+      '@typescript-eslint/scope-manager': 5.62.0
+      '@typescript-eslint/types': 5.62.0
+      '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.1.6)
+      eslint: 8.57.0
+      eslint-scope: 5.1.1
+      semver: 7.6.0
+    transitivePeerDependencies:
+      - supports-color
+      - typescript
+    dev: false
+
+  /@typescript-eslint/utils@6.21.0(eslint@8.57.0)(typescript@5.1.6):
+    resolution: {integrity: sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==}
+    engines: {node: ^16.0.0 || >=18.0.0}
+    peerDependencies:
+      eslint: ^7.0.0 || ^8.0.0
+    dependencies:
+      '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
+      '@types/json-schema': 7.0.15
+      '@types/semver': 7.5.8
+      '@typescript-eslint/scope-manager': 6.21.0
+      '@typescript-eslint/types': 6.21.0
+      '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.1.6)
+      eslint: 8.57.0
+      semver: 7.6.0
+    transitivePeerDependencies:
+      - supports-color
+      - typescript
+    dev: false
+
+  /@typescript-eslint/visitor-keys@5.62.0:
+    resolution: {integrity: sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    dependencies:
+      '@typescript-eslint/types': 5.62.0
+      eslint-visitor-keys: 3.4.3
+    dev: false
+
+  /@typescript-eslint/visitor-keys@6.21.0:
+    resolution: {integrity: sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==}
+    engines: {node: ^16.0.0 || >=18.0.0}
+    dependencies:
+      '@typescript-eslint/types': 6.21.0
+      eslint-visitor-keys: 3.4.3
+    dev: false
+
+  /@ungap/structured-clone@1.2.0:
+    resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==}
+    dev: false
+
+  /@webassemblyjs/ast@1.11.1:
+    resolution: {integrity: sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==}
+    dependencies:
+      '@webassemblyjs/helper-numbers': 1.11.1
+      '@webassemblyjs/helper-wasm-bytecode': 1.11.1
+
+  /@webassemblyjs/floating-point-hex-parser@1.11.1:
+    resolution: {integrity: sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==}
+
+  /@webassemblyjs/helper-api-error@1.11.1:
+    resolution: {integrity: sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==}
+
+  /@webassemblyjs/helper-buffer@1.11.1:
+    resolution: {integrity: sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==}
+
+  /@webassemblyjs/helper-numbers@1.11.1:
+    resolution: {integrity: sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==}
+    dependencies:
+      '@webassemblyjs/floating-point-hex-parser': 1.11.1
+      '@webassemblyjs/helper-api-error': 1.11.1
+      '@xtuc/long': 4.2.2
+
+  /@webassemblyjs/helper-wasm-bytecode@1.11.1:
+    resolution: {integrity: sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==}
+
+  /@webassemblyjs/helper-wasm-section@1.11.1:
+    resolution: {integrity: sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==}
+    dependencies:
+      '@webassemblyjs/ast': 1.11.1
+      '@webassemblyjs/helper-buffer': 1.11.1
+      '@webassemblyjs/helper-wasm-bytecode': 1.11.1
+      '@webassemblyjs/wasm-gen': 1.11.1
+
+  /@webassemblyjs/ieee754@1.11.1:
+    resolution: {integrity: sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==}
+    dependencies:
+      '@xtuc/ieee754': 1.2.0
+
+  /@webassemblyjs/leb128@1.11.1:
+    resolution: {integrity: sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==}
+    dependencies:
+      '@xtuc/long': 4.2.2
+
+  /@webassemblyjs/utf8@1.11.1:
+    resolution: {integrity: sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==}
+
+  /@webassemblyjs/wasm-edit@1.11.1:
+    resolution: {integrity: sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==}
+    dependencies:
+      '@webassemblyjs/ast': 1.11.1
+      '@webassemblyjs/helper-buffer': 1.11.1
+      '@webassemblyjs/helper-wasm-bytecode': 1.11.1
+      '@webassemblyjs/helper-wasm-section': 1.11.1
+      '@webassemblyjs/wasm-gen': 1.11.1
+      '@webassemblyjs/wasm-opt': 1.11.1
+      '@webassemblyjs/wasm-parser': 1.11.1
+      '@webassemblyjs/wast-printer': 1.11.1
+
+  /@webassemblyjs/wasm-gen@1.11.1:
+    resolution: {integrity: sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==}
+    dependencies:
+      '@webassemblyjs/ast': 1.11.1
+      '@webassemblyjs/helper-wasm-bytecode': 1.11.1
+      '@webassemblyjs/ieee754': 1.11.1
+      '@webassemblyjs/leb128': 1.11.1
+      '@webassemblyjs/utf8': 1.11.1
+
+  /@webassemblyjs/wasm-opt@1.11.1:
+    resolution: {integrity: sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==}
+    dependencies:
+      '@webassemblyjs/ast': 1.11.1
+      '@webassemblyjs/helper-buffer': 1.11.1
+      '@webassemblyjs/wasm-gen': 1.11.1
+      '@webassemblyjs/wasm-parser': 1.11.1
+
+  /@webassemblyjs/wasm-parser@1.11.1:
+    resolution: {integrity: sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==}
+    dependencies:
+      '@webassemblyjs/ast': 1.11.1
+      '@webassemblyjs/helper-api-error': 1.11.1
+      '@webassemblyjs/helper-wasm-bytecode': 1.11.1
+      '@webassemblyjs/ieee754': 1.11.1
+      '@webassemblyjs/leb128': 1.11.1
+      '@webassemblyjs/utf8': 1.11.1
+
+  /@webassemblyjs/wast-printer@1.11.1:
+    resolution: {integrity: sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==}
+    dependencies:
+      '@webassemblyjs/ast': 1.11.1
+      '@xtuc/long': 4.2.2
+
+  /@xtuc/ieee754@1.2.0:
+    resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==}
+
+  /@xtuc/long@4.2.2:
+    resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==}
+
   /@yarnpkg/lockfile@1.1.0:
     resolution: {integrity: sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==}
     dev: true
@@ -1180,11 +1710,25 @@
       mime-types: 2.1.35
       negotiator: 0.6.3
 
+  /acorn-import-assertions@1.9.0(acorn@8.9.0):
+    resolution: {integrity: sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==}
+    peerDependencies:
+      acorn: ^8
+    dependencies:
+      acorn: 8.9.0
+
+  /acorn-jsx@5.3.2(acorn@8.9.0):
+    resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
+    peerDependencies:
+      acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
+    dependencies:
+      acorn: 8.9.0
+    dev: false
+
   /acorn@8.9.0:
     resolution: {integrity: sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ==}
     engines: {node: '>=0.4.0'}
     hasBin: true
-    dev: true
 
   /agent-base@6.0.2:
     resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
@@ -1221,6 +1765,21 @@
       ajv: 8.12.0
     dev: true
 
+  /ajv-keywords@3.5.2(ajv@6.12.6):
+    resolution: {integrity: sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==}
+    peerDependencies:
+      ajv: ^6.9.1
+    dependencies:
+      ajv: 6.12.6
+
+  /ajv@6.12.6:
+    resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
+    dependencies:
+      fast-deep-equal: 3.1.3
+      fast-json-stable-stringify: 2.1.0
+      json-schema-traverse: 0.4.1
+      uri-js: 4.4.1
+
   /ajv@8.12.0:
     resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==}
     dependencies:
@@ -1304,6 +1863,122 @@
       readable-stream: 3.6.2
     dev: true
 
+  /argparse@2.0.1:
+    resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
+    dev: false
+
+  /array-buffer-byte-length@1.0.1:
+    resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.7
+      is-array-buffer: 3.0.4
+    dev: false
+
+  /array-includes@3.1.8:
+    resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.7
+      define-properties: 1.2.1
+      es-abstract: 1.23.3
+      es-object-atoms: 1.0.0
+      get-intrinsic: 1.2.4
+      is-string: 1.0.7
+    dev: false
+
+  /array-union@1.0.2:
+    resolution: {integrity: sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==}
+    engines: {node: '>=0.10.0'}
+    dependencies:
+      array-uniq: 1.0.3
+
+  /array-union@2.1.0:
+    resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
+    engines: {node: '>=8'}
+    dev: false
+
+  /array-uniq@1.0.3:
+    resolution: {integrity: sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==}
+    engines: {node: '>=0.10.0'}
+
+  /array.prototype.findlast@1.2.5:
+    resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.7
+      define-properties: 1.2.1
+      es-abstract: 1.23.3
+      es-errors: 1.3.0
+      es-object-atoms: 1.0.0
+      es-shim-unscopables: 1.0.2
+    dev: false
+
+  /array.prototype.findlastindex@1.2.5:
+    resolution: {integrity: sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.7
+      define-properties: 1.2.1
+      es-abstract: 1.23.3
+      es-errors: 1.3.0
+      es-object-atoms: 1.0.0
+      es-shim-unscopables: 1.0.2
+    dev: false
+
+  /array.prototype.flat@1.3.2:
+    resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.2
+      define-properties: 1.2.1
+      es-abstract: 1.23.3
+      es-shim-unscopables: 1.0.2
+    dev: false
+
+  /array.prototype.flatmap@1.3.2:
+    resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.2
+      define-properties: 1.2.1
+      es-abstract: 1.23.3
+      es-shim-unscopables: 1.0.2
+    dev: false
+
+  /array.prototype.toreversed@1.1.2:
+    resolution: {integrity: sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==}
+    dependencies:
+      call-bind: 1.0.2
+      define-properties: 1.2.1
+      es-abstract: 1.23.3
+      es-shim-unscopables: 1.0.2
+    dev: false
+
+  /array.prototype.tosorted@1.1.3:
+    resolution: {integrity: sha512-/DdH4TiTmOKzyQbp/eadcCVexiCb36xJg7HshYOYJnNZFDj33GEv0P7GxsynpShhq4OLYJzbGcBDkLsDt7MnNg==}
+    dependencies:
+      call-bind: 1.0.7
+      define-properties: 1.2.1
+      es-abstract: 1.23.3
+      es-errors: 1.3.0
+      es-shim-unscopables: 1.0.2
+    dev: false
+
+  /arraybuffer.prototype.slice@1.0.3:
+    resolution: {integrity: sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      array-buffer-byte-length: 1.0.1
+      call-bind: 1.0.7
+      define-properties: 1.2.1
+      es-abstract: 1.23.3
+      es-errors: 1.3.0
+      get-intrinsic: 1.2.4
+      is-array-buffer: 3.0.4
+      is-shared-array-buffer: 1.0.3
+    dev: false
+
   /asn1@0.2.6:
     resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==}
     dependencies:
@@ -1333,6 +2008,13 @@
     engines: {node: '>= 4.0.0'}
     dev: true
 
+  /available-typed-arrays@1.0.7:
+    resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      possible-typed-array-names: 1.0.0
+    dev: false
+
   /aws-sign2@0.7.0:
     resolution: {integrity: sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==}
     dev: true
@@ -1408,7 +2090,6 @@
     resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
     dependencies:
       balanced-match: 1.0.2
-    dev: true
 
   /braces@3.0.2:
     resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==}
@@ -1425,7 +2106,6 @@
       electron-to-chromium: 1.4.679
       node-releases: 2.0.14
       update-browserslist-db: 1.0.13(browserslist@4.23.0)
-    dev: true
 
   /buffer-crc32@0.2.13:
     resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==}
@@ -1433,7 +2113,6 @@
 
   /buffer-from@1.1.2:
     resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
-    dev: true
 
   /buffer@5.7.1:
     resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
@@ -1512,13 +2191,28 @@
       function-bind: 1.1.2
       get-intrinsic: 1.2.1
 
+  /call-bind@1.0.7:
+    resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      es-define-property: 1.0.0
+      es-errors: 1.3.0
+      function-bind: 1.1.2
+      get-intrinsic: 1.2.4
+      set-function-length: 1.2.2
+    dev: false
+
+  /callsites@3.1.0:
+    resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
+    engines: {node: '>=6'}
+    dev: false
+
   /camelcase@5.3.1:
     resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==}
     engines: {node: '>=6'}
 
   /caniuse-lite@1.0.30001588:
     resolution: {integrity: sha512-+hVY9jE44uKLkH0SrUTqxjxqNTOWHsbnQDIKjwkZ3lNTzUUVdBLBGXtj/q5Mp5u98r3droaZAewQuEDzjQdZlQ==}
-    dev: true
 
   /caseless@0.12.0:
     resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==}
@@ -1539,7 +2233,6 @@
     dependencies:
       ansi-styles: 4.3.0
       supports-color: 7.2.0
-    dev: true
 
   /chardet@0.7.0:
     resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==}
@@ -1569,6 +2262,10 @@
     engines: {node: '>=10'}
     dev: true
 
+  /chrome-trace-event@1.0.3:
+    resolution: {integrity: sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==}
+    engines: {node: '>=6.0'}
+
   /ci-info@3.8.0:
     resolution: {integrity: sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==}
     engines: {node: '>=8'}
@@ -1579,6 +2276,15 @@
     engines: {node: '>=6'}
     dev: true
 
+  /clean-webpack-plugin@4.0.0(webpack@5.75.0):
+    resolution: {integrity: sha512-WuWE1nyTNAyW5T7oNyys2EN0cfP2fdRxhxnIQWiAp0bMabPdHhoGxM8A6YL2GhqwgrPnnaemVE7nv5XJ2Fhh2w==}
+    engines: {node: '>=10.0.0'}
+    peerDependencies:
+      webpack: '>=4.0.0 <6.0.0'
+    dependencies:
+      del: 4.1.1
+      webpack: 5.75.0
+
   /cli-cursor@3.1.0:
     resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==}
     engines: {node: '>=8'}
@@ -1676,9 +2382,12 @@
       delayed-stream: 1.0.0
     dev: true
 
+  /commander@10.0.0:
+    resolution: {integrity: sha512-zS5PnTI22FIRM6ylNW8G4Ap0IEOyk62fhLSD0+uHRT9McRCLGpkVNvao4bjimpK/GShynyQkFFxHhwMcETmduA==}
+    engines: {node: '>=14'}
+
   /commander@2.20.3:
     resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
-    dev: true
 
   /commander@4.1.1:
     resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
@@ -1739,6 +2448,30 @@
       object-assign: 4.1.1
       vary: 1.1.2
 
+  /create-foxglove-extension@0.8.6(typescript@5.1.6):
+    resolution: {integrity: sha512-DML7hw3wLcT/5tmIcwl759RYL+to9s8geKJ8TuKQMqhhBeYBx8UwRBweIFA3jFB9+F8zkkqoFq7RlXvz5qpgug==}
+    engines: {node: '>= 14'}
+    hasBin: true
+    dependencies:
+      clean-webpack-plugin: 4.0.0(webpack@5.75.0)
+      commander: 10.0.0
+      jszip: 3.10.1
+      mkdirp: 2.1.5
+      ncp: 2.0.0
+      node-fetch: 2.6.9
+      path-browserify: 1.0.1
+      rimraf: 4.3.1
+      sanitize-filename: 1.6.3
+      ts-loader: 9.4.2(typescript@5.1.6)(webpack@5.75.0)
+      webpack: 5.75.0
+    transitivePeerDependencies:
+      - '@swc/core'
+      - encoding
+      - esbuild
+      - typescript
+      - uglify-js
+      - webpack-cli
+
   /cross-spawn@7.0.3:
     resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
     engines: {node: '>= 8'}
@@ -1746,7 +2479,10 @@
       path-key: 3.1.1
       shebang-command: 2.0.0
       which: 2.0.2
-    dev: true
+
+  /csstype@3.1.3:
+    resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
+    dev: false
 
   /custom-event@1.0.1:
     resolution: {integrity: sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==}
@@ -1809,6 +2545,33 @@
       assert-plus: 1.0.0
     dev: true
 
+  /data-view-buffer@1.0.1:
+    resolution: {integrity: sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.7
+      es-errors: 1.3.0
+      is-data-view: 1.0.1
+    dev: false
+
+  /data-view-byte-length@1.0.1:
+    resolution: {integrity: sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.7
+      es-errors: 1.3.0
+      is-data-view: 1.0.1
+    dev: false
+
+  /data-view-byte-offset@1.0.0:
+    resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.7
+      es-errors: 1.3.0
+      is-data-view: 1.0.1
+    dev: false
+
   /date-format@4.0.14:
     resolution: {integrity: sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==}
     engines: {node: '>=4.0'}
@@ -1837,7 +2600,6 @@
     dependencies:
       ms: 2.1.3
       supports-color: 8.1.1
-    dev: true
 
   /debug@4.3.4(supports-color@8.1.1):
     resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
@@ -1855,6 +2617,10 @@
     resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==}
     engines: {node: '>=0.10.0'}
 
+  /deep-is@0.1.4:
+    resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
+    dev: false
+
   /deepmerge@4.3.1:
     resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
     engines: {node: '>=0.10.0'}
@@ -1866,11 +2632,41 @@
       clone: 1.0.4
     dev: true
 
+  /define-data-property@1.1.4:
+    resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      es-define-property: 1.0.0
+      es-errors: 1.3.0
+      gopd: 1.0.1
+    dev: false
+
   /define-lazy-prop@2.0.0:
     resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==}
     engines: {node: '>=8'}
     dev: true
 
+  /define-properties@1.2.1:
+    resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      define-data-property: 1.1.4
+      has-property-descriptors: 1.0.2
+      object-keys: 1.1.1
+    dev: false
+
+  /del@4.1.1:
+    resolution: {integrity: sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==}
+    engines: {node: '>=6'}
+    dependencies:
+      '@types/glob': 7.2.0
+      globby: 6.1.0
+      is-path-cwd: 2.2.0
+      is-path-in-cwd: 2.1.0
+      p-map: 2.1.0
+      pify: 4.0.1
+      rimraf: 2.7.1
+
   /delayed-stream@1.0.0:
     resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
     engines: {node: '>=0.4.0'}
@@ -1902,6 +2698,27 @@
   /dijkstrajs@1.0.3:
     resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==}
 
+  /dir-glob@3.0.1:
+    resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
+    engines: {node: '>=8'}
+    dependencies:
+      path-type: 4.0.0
+    dev: false
+
+  /doctrine@2.1.0:
+    resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
+    engines: {node: '>=0.10.0'}
+    dependencies:
+      esutils: 2.0.3
+    dev: false
+
+  /doctrine@3.0.0:
+    resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
+    engines: {node: '>=6.0.0'}
+    dependencies:
+      esutils: 2.0.3
+    dev: false
+
   /dom-serialize@2.2.1:
     resolution: {integrity: sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ==}
     dependencies:
@@ -1926,7 +2743,6 @@
 
   /electron-to-chromium@1.4.679:
     resolution: {integrity: sha512-NhQMsz5k0d6m9z3qAxnsOR/ebal4NAGsrNVRwcDo4Kc/zQ7KdsTKZUxZoygHcVRb0QDW3waEDIcE3isZ79RP6g==}
-    dev: true
 
   /emoji-regex@8.0.0:
     resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
@@ -1979,6 +2795,13 @@
       - supports-color
       - utf-8-validate
 
+  /enhanced-resolve@5.16.0:
+    resolution: {integrity: sha512-O+QWCviPNSSLAD9Ucn8Awv+poAkqn3T1XY5/N7kR7rQO9yfSGWkYZDwpJ+iKF7B8rxaQKWngSqACpgzeapSyoA==}
+    engines: {node: '>=10.13.0'}
+    dependencies:
+      graceful-fs: 4.2.11
+      tapable: 2.2.1
+
   /enquirer@2.3.6:
     resolution: {integrity: sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==}
     engines: {node: '>=8.6'}
@@ -1998,6 +2821,124 @@
     resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==}
     dev: true
 
+  /es-abstract@1.23.3:
+    resolution: {integrity: sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      array-buffer-byte-length: 1.0.1
+      arraybuffer.prototype.slice: 1.0.3
+      available-typed-arrays: 1.0.7
+      call-bind: 1.0.7
+      data-view-buffer: 1.0.1
+      data-view-byte-length: 1.0.1
+      data-view-byte-offset: 1.0.0
+      es-define-property: 1.0.0
+      es-errors: 1.3.0
+      es-object-atoms: 1.0.0
+      es-set-tostringtag: 2.0.3
+      es-to-primitive: 1.2.1
+      function.prototype.name: 1.1.6
+      get-intrinsic: 1.2.4
+      get-symbol-description: 1.0.2
+      globalthis: 1.0.3
+      gopd: 1.0.1
+      has-property-descriptors: 1.0.2
+      has-proto: 1.0.3
+      has-symbols: 1.0.3
+      hasown: 2.0.2
+      internal-slot: 1.0.7
+      is-array-buffer: 3.0.4
+      is-callable: 1.2.7
+      is-data-view: 1.0.1
+      is-negative-zero: 2.0.3
+      is-regex: 1.1.4
+      is-shared-array-buffer: 1.0.3
+      is-string: 1.0.7
+      is-typed-array: 1.1.13
+      is-weakref: 1.0.2
+      object-inspect: 1.13.1
+      object-keys: 1.1.1
+      object.assign: 4.1.5
+      regexp.prototype.flags: 1.5.2
+      safe-array-concat: 1.1.2
+      safe-regex-test: 1.0.3
+      string.prototype.trim: 1.2.9
+      string.prototype.trimend: 1.0.8
+      string.prototype.trimstart: 1.0.8
+      typed-array-buffer: 1.0.2
+      typed-array-byte-length: 1.0.1
+      typed-array-byte-offset: 1.0.2
+      typed-array-length: 1.0.6
+      unbox-primitive: 1.0.2
+      which-typed-array: 1.1.15
+    dev: false
+
+  /es-define-property@1.0.0:
+    resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      get-intrinsic: 1.2.4
+    dev: false
+
+  /es-errors@1.3.0:
+    resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
+    engines: {node: '>= 0.4'}
+    dev: false
+
+  /es-iterator-helpers@1.0.19:
+    resolution: {integrity: sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.7
+      define-properties: 1.2.1
+      es-abstract: 1.23.3
+      es-errors: 1.3.0
+      es-set-tostringtag: 2.0.3
+      function-bind: 1.1.2
+      get-intrinsic: 1.2.4
+      globalthis: 1.0.3
+      has-property-descriptors: 1.0.2
+      has-proto: 1.0.3
+      has-symbols: 1.0.3
+      internal-slot: 1.0.7
+      iterator.prototype: 1.1.2
+      safe-array-concat: 1.1.2
+    dev: false
+
+  /es-module-lexer@0.9.3:
+    resolution: {integrity: sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==}
+
+  /es-object-atoms@1.0.0:
+    resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      es-errors: 1.3.0
+    dev: false
+
+  /es-set-tostringtag@2.0.3:
+    resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      get-intrinsic: 1.2.4
+      has-tostringtag: 1.0.2
+      hasown: 2.0.1
+    dev: false
+
+  /es-shim-unscopables@1.0.2:
+    resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==}
+    dependencies:
+      hasown: 2.0.1
+    dev: false
+
+  /es-to-primitive@1.2.1:
+    resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      is-callable: 1.2.7
+      is-date-object: 1.0.5
+      is-symbol: 1.0.4
+    dev: false
+
   /escalade@3.1.1:
     resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==}
     engines: {node: '>=6'}
@@ -2010,10 +2951,313 @@
     engines: {node: '>=0.8.0'}
     dev: true
 
+  /escape-string-regexp@4.0.0:
+    resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
+    engines: {node: '>=10'}
+    dev: false
+
+  /eslint-config-prettier@8.10.0(eslint@8.57.0):
+    resolution: {integrity: sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==}
+    hasBin: true
+    peerDependencies:
+      eslint: '>=7.0.0'
+    dependencies:
+      eslint: 8.57.0
+    dev: false
+
+  /eslint-import-resolver-node@0.3.9:
+    resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==}
+    dependencies:
+      debug: 3.2.7(supports-color@8.1.1)
+      is-core-module: 2.13.1
+      resolve: 1.22.8
+    transitivePeerDependencies:
+      - supports-color
+    dev: false
+
+  /eslint-module-utils@2.8.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint@8.57.0):
+    resolution: {integrity: sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==}
+    engines: {node: '>=4'}
+    peerDependencies:
+      '@typescript-eslint/parser': '*'
+      eslint: '*'
+      eslint-import-resolver-node: '*'
+      eslint-import-resolver-typescript: '*'
+      eslint-import-resolver-webpack: '*'
+    peerDependenciesMeta:
+      '@typescript-eslint/parser':
+        optional: true
+      eslint:
+        optional: true
+      eslint-import-resolver-node:
+        optional: true
+      eslint-import-resolver-typescript:
+        optional: true
+      eslint-import-resolver-webpack:
+        optional: true
+    dependencies:
+      '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.1.6)
+      debug: 3.2.7(supports-color@8.1.1)
+      eslint: 8.57.0
+      eslint-import-resolver-node: 0.3.9
+    transitivePeerDependencies:
+      - supports-color
+    dev: false
+
+  /eslint-plugin-es@4.1.0(eslint@8.57.0):
+    resolution: {integrity: sha512-GILhQTnjYE2WorX5Jyi5i4dz5ALWxBIdQECVQavL6s7cI76IZTDWleTHkxz/QT3kvcs2QlGHvKLYsSlPOlPXnQ==}
+    engines: {node: '>=8.10.0'}
+    peerDependencies:
+      eslint: '>=4.19.1'
+    dependencies:
+      eslint: 8.57.0
+      eslint-utils: 2.1.0
+      regexpp: 3.2.0
+    dev: false
+
+  /eslint-plugin-filenames@1.3.2(eslint@8.57.0):
+    resolution: {integrity: sha512-tqxJTiEM5a0JmRCUYQmxw23vtTxrb2+a3Q2mMOPhFxvt7ZQQJmdiuMby9B/vUAuVMghyP7oET+nIf6EO6CBd/w==}
+    peerDependencies:
+      eslint: '*'
+    dependencies:
+      eslint: 8.57.0
+      lodash.camelcase: 4.3.0
+      lodash.kebabcase: 4.1.1
+      lodash.snakecase: 4.1.1
+      lodash.upperfirst: 4.3.1
+    dev: false
+
+  /eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0)(eslint@8.57.0):
+    resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==}
+    engines: {node: '>=4'}
+    peerDependencies:
+      '@typescript-eslint/parser': '*'
+      eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8
+    peerDependenciesMeta:
+      '@typescript-eslint/parser':
+        optional: true
+    dependencies:
+      '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.1.6)
+      array-includes: 3.1.8
+      array.prototype.findlastindex: 1.2.5
+      array.prototype.flat: 1.3.2
+      array.prototype.flatmap: 1.3.2
+      debug: 3.2.7(supports-color@8.1.1)
+      doctrine: 2.1.0
+      eslint: 8.57.0
+      eslint-import-resolver-node: 0.3.9
+      eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint@8.57.0)
+      hasown: 2.0.1
+      is-core-module: 2.13.1
+      is-glob: 4.0.3
+      minimatch: 3.1.2
+      object.fromentries: 2.0.8
+      object.groupby: 1.0.3
+      object.values: 1.2.0
+      semver: 6.3.1
+      tsconfig-paths: 3.15.0
+    transitivePeerDependencies:
+      - eslint-import-resolver-typescript
+      - eslint-import-resolver-webpack
+      - supports-color
+    dev: false
+
+  /eslint-plugin-jest@27.9.0(@typescript-eslint/eslint-plugin@6.21.0)(eslint@8.57.0)(typescript@5.1.6):
+    resolution: {integrity: sha512-QIT7FH7fNmd9n4se7FFKHbsLKGQiw885Ds6Y/sxKgCZ6natwCsXdgPOADnYVxN2QrRweF0FZWbJ6S7Rsn7llug==}
+    engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+    peerDependencies:
+      '@typescript-eslint/eslint-plugin': ^5.0.0 || ^6.0.0 || ^7.0.0
+      eslint: ^7.0.0 || ^8.0.0
+      jest: '*'
+    peerDependenciesMeta:
+      '@typescript-eslint/eslint-plugin':
+        optional: true
+      jest:
+        optional: true
+    dependencies:
+      '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0)(eslint@8.57.0)(typescript@5.1.6)
+      '@typescript-eslint/utils': 5.62.0(eslint@8.57.0)(typescript@5.1.6)
+      eslint: 8.57.0
+    transitivePeerDependencies:
+      - supports-color
+      - typescript
+    dev: false
+
+  /eslint-plugin-prettier@5.1.3(eslint-config-prettier@8.10.0)(eslint@8.57.0)(prettier@3.2.5):
+    resolution: {integrity: sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==}
+    engines: {node: ^14.18.0 || >=16.0.0}
+    peerDependencies:
+      '@types/eslint': '>=8.0.0'
+      eslint: '>=8.0.0'
+      eslint-config-prettier: '*'
+      prettier: '>=3.0.0'
+    peerDependenciesMeta:
+      '@types/eslint':
+        optional: true
+      eslint-config-prettier:
+        optional: true
+    dependencies:
+      eslint: 8.57.0
+      eslint-config-prettier: 8.10.0(eslint@8.57.0)
+      prettier: 3.2.5
+      prettier-linter-helpers: 1.0.0
+      synckit: 0.8.8
+    dev: false
+
+  /eslint-plugin-react-hooks@4.6.2(eslint@8.57.0):
+    resolution: {integrity: sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==}
+    engines: {node: '>=10'}
+    peerDependencies:
+      eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0
+    dependencies:
+      eslint: 8.57.0
+    dev: false
+
+  /eslint-plugin-react@7.34.1(eslint@8.57.0):
+    resolution: {integrity: sha512-N97CxlouPT1AHt8Jn0mhhN2RrADlUAsk1/atcT2KyA/l9Q/E6ll7OIGwNumFmWfZ9skV3XXccYS19h80rHtgkw==}
+    engines: {node: '>=4'}
+    peerDependencies:
+      eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8
+    dependencies:
+      array-includes: 3.1.8
+      array.prototype.findlast: 1.2.5
+      array.prototype.flatmap: 1.3.2
+      array.prototype.toreversed: 1.1.2
+      array.prototype.tosorted: 1.1.3
+      doctrine: 2.1.0
+      es-iterator-helpers: 1.0.19
+      eslint: 8.57.0
+      estraverse: 5.3.0
+      jsx-ast-utils: 3.3.5
+      minimatch: 3.1.2
+      object.entries: 1.1.8
+      object.fromentries: 2.0.8
+      object.hasown: 1.1.4
+      object.values: 1.2.0
+      prop-types: 15.8.1
+      resolve: 2.0.0-next.5
+      semver: 6.3.1
+      string.prototype.matchall: 4.0.11
+    dev: false
+
+  /eslint-scope@5.1.1:
+    resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==}
+    engines: {node: '>=8.0.0'}
+    dependencies:
+      esrecurse: 4.3.0
+      estraverse: 4.3.0
+
+  /eslint-scope@7.2.2:
+    resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    dependencies:
+      esrecurse: 4.3.0
+      estraverse: 5.3.0
+    dev: false
+
+  /eslint-utils@2.1.0:
+    resolution: {integrity: sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==}
+    engines: {node: '>=6'}
+    dependencies:
+      eslint-visitor-keys: 1.3.0
+    dev: false
+
+  /eslint-visitor-keys@1.3.0:
+    resolution: {integrity: sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==}
+    engines: {node: '>=4'}
+    dev: false
+
+  /eslint-visitor-keys@3.4.3:
+    resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    dev: false
+
+  /eslint@8.57.0:
+    resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    hasBin: true
+    dependencies:
+      '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
+      '@eslint-community/regexpp': 4.10.0
+      '@eslint/eslintrc': 2.1.4
+      '@eslint/js': 8.57.0
+      '@humanwhocodes/config-array': 0.11.14
+      '@humanwhocodes/module-importer': 1.0.1
+      '@nodelib/fs.walk': 1.2.8
+      '@ungap/structured-clone': 1.2.0
+      ajv: 6.12.6
+      chalk: 4.1.2
+      cross-spawn: 7.0.3
+      debug: 4.3.4(supports-color@8.1.1)
+      doctrine: 3.0.0
+      escape-string-regexp: 4.0.0
+      eslint-scope: 7.2.2
+      eslint-visitor-keys: 3.4.3
+      espree: 9.6.1
+      esquery: 1.5.0
+      esutils: 2.0.3
+      fast-deep-equal: 3.1.3
+      file-entry-cache: 6.0.1
+      find-up: 5.0.0
+      glob-parent: 6.0.2
+      globals: 13.24.0
+      graphemer: 1.4.0
+      ignore: 5.3.1
+      imurmurhash: 0.1.4
+      is-glob: 4.0.3
+      is-path-inside: 3.0.3
+      js-yaml: 4.1.0
+      json-stable-stringify-without-jsonify: 1.0.1
+      levn: 0.4.1
+      lodash.merge: 4.6.2
+      minimatch: 3.1.2
+      natural-compare: 1.4.0
+      optionator: 0.9.4
+      strip-ansi: 6.0.1
+      text-table: 0.2.0
+    transitivePeerDependencies:
+      - supports-color
+    dev: false
+
+  /espree@9.6.1:
+    resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==}
+    engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+    dependencies:
+      acorn: 8.9.0
+      acorn-jsx: 5.3.2(acorn@8.9.0)
+      eslint-visitor-keys: 3.4.3
+    dev: false
+
+  /esquery@1.5.0:
+    resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==}
+    engines: {node: '>=0.10'}
+    dependencies:
+      estraverse: 5.3.0
+    dev: false
+
+  /esrecurse@4.3.0:
+    resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}
+    engines: {node: '>=4.0'}
+    dependencies:
+      estraverse: 5.3.0
+
+  /estraverse@4.3.0:
+    resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==}
+    engines: {node: '>=4.0'}
+
+  /estraverse@5.3.0:
+    resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
+    engines: {node: '>=4.0'}
+
   /estree-walker@2.0.2:
     resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
     dev: true
 
+  /esutils@2.0.3:
+    resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
+    engines: {node: '>=0.10.0'}
+    dev: false
+
   /eventemitter2@6.4.7:
     resolution: {integrity: sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg==}
     dev: true
@@ -2021,6 +3265,10 @@
   /eventemitter3@4.0.7:
     resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==}
 
+  /events@3.3.0:
+    resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
+    engines: {node: '>=0.8.x'}
+
   /execa@4.1.0:
     resolution: {integrity: sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==}
     engines: {node: '>=10'}
@@ -2080,7 +3328,34 @@
 
   /fast-deep-equal@3.1.3:
     resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
-    dev: true
+
+  /fast-diff@1.3.0:
+    resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==}
+    dev: false
+
+  /fast-glob@3.3.2:
+    resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==}
+    engines: {node: '>=8.6.0'}
+    dependencies:
+      '@nodelib/fs.stat': 2.0.5
+      '@nodelib/fs.walk': 1.2.8
+      glob-parent: 5.1.2
+      merge2: 1.4.1
+      micromatch: 4.0.5
+    dev: false
+
+  /fast-json-stable-stringify@2.1.0:
+    resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
+
+  /fast-levenshtein@2.0.6:
+    resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
+    dev: false
+
+  /fastq@1.17.1:
+    resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==}
+    dependencies:
+      reusify: 1.0.4
+    dev: false
 
   /fd-slicer@1.1.0:
     resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==}
@@ -2095,6 +3370,13 @@
       escape-string-regexp: 1.0.5
     dev: true
 
+  /file-entry-cache@6.0.1:
+    resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
+    engines: {node: ^10.12.0 || >=12.0.0}
+    dependencies:
+      flat-cache: 3.2.0
+    dev: false
+
   /fill-range@7.0.1:
     resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==}
     engines: {node: '>=8'}
@@ -2123,6 +3405,23 @@
       locate-path: 5.0.0
       path-exists: 4.0.0
 
+  /find-up@5.0.0:
+    resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
+    engines: {node: '>=10'}
+    dependencies:
+      locate-path: 6.0.0
+      path-exists: 4.0.0
+    dev: false
+
+  /flat-cache@3.2.0:
+    resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==}
+    engines: {node: ^10.12.0 || >=12.0.0}
+    dependencies:
+      flatted: 3.3.1
+      keyv: 4.5.4
+      rimraf: 3.0.2
+    dev: false
+
   /flatted@3.3.1:
     resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==}
 
@@ -2135,6 +3434,12 @@
       debug:
         optional: true
 
+  /for-each@0.3.3:
+    resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
+    dependencies:
+      is-callable: 1.2.7
+    dev: false
+
   /foreground-child@3.1.1:
     resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==}
     engines: {node: '>=14'}
@@ -2208,6 +3513,20 @@
   /function-bind@1.1.2:
     resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
 
+  /function.prototype.name@1.1.6:
+    resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.7
+      define-properties: 1.2.1
+      es-abstract: 1.23.3
+      functions-have-names: 1.2.3
+    dev: false
+
+  /functions-have-names@1.2.3:
+    resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==}
+    dev: false
+
   /gauge@4.0.4:
     resolution: {integrity: sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==}
     engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
@@ -2239,6 +3558,17 @@
       has-proto: 1.0.1
       has-symbols: 1.0.3
 
+  /get-intrinsic@1.2.4:
+    resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      es-errors: 1.3.0
+      function-bind: 1.1.2
+      has-proto: 1.0.1
+      has-symbols: 1.0.3
+      hasown: 2.0.1
+    dev: false
+
   /get-stream@5.2.0:
     resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==}
     engines: {node: '>=8'}
@@ -2246,6 +3576,15 @@
       pump: 3.0.0
     dev: true
 
+  /get-symbol-description@1.0.2:
+    resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.7
+      es-errors: 1.3.0
+      get-intrinsic: 1.2.4
+    dev: false
+
   /getos@3.2.1:
     resolution: {integrity: sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==}
     dependencies:
@@ -2265,6 +3604,16 @@
     dependencies:
       is-glob: 4.0.3
 
+  /glob-parent@6.0.2:
+    resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
+    engines: {node: '>=10.13.0'}
+    dependencies:
+      is-glob: 4.0.3
+    dev: false
+
+  /glob-to-regexp@0.4.1:
+    resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==}
+
   /glob@10.3.10:
     resolution: {integrity: sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==}
     engines: {node: '>=16 || 14 >=14.17'}
@@ -2298,6 +3647,15 @@
       once: 1.4.0
     dev: true
 
+  /glob@9.3.5:
+    resolution: {integrity: sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==}
+    engines: {node: '>=16 || 14 >=14.17'}
+    dependencies:
+      fs.realpath: 1.0.0
+      minimatch: 8.0.4
+      minipass: 4.2.8
+      path-scurry: 1.10.1
+
   /global-dirs@3.0.1:
     resolution: {integrity: sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==}
     engines: {node: '>=10'}
@@ -2310,9 +3668,59 @@
     engines: {node: '>=4'}
     dev: true
 
+  /globals@13.24.0:
+    resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==}
+    engines: {node: '>=8'}
+    dependencies:
+      type-fest: 0.20.2
+    dev: false
+
+  /globalthis@1.0.3:
+    resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      define-properties: 1.2.1
+    dev: false
+
+  /globby@11.1.0:
+    resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==}
+    engines: {node: '>=10'}
+    dependencies:
+      array-union: 2.1.0
+      dir-glob: 3.0.1
+      fast-glob: 3.3.2
+      ignore: 5.3.1
+      merge2: 1.4.1
+      slash: 3.0.0
+    dev: false
+
+  /globby@6.1.0:
+    resolution: {integrity: sha512-KVbFv2TQtbzCoxAnfD6JcHZTYCzyliEaaeM/gH8qQdkKr5s0OP9scEgvdcngyk7AVdY6YVW/TJHd+lQ/Df3Daw==}
+    engines: {node: '>=0.10.0'}
+    dependencies:
+      array-union: 1.0.2
+      glob: 7.2.3
+      object-assign: 4.1.1
+      pify: 2.3.0
+      pinkie-promise: 2.0.1
+
+  /gopd@1.0.1:
+    resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==}
+    dependencies:
+      get-intrinsic: 1.2.4
+    dev: false
+
   /graceful-fs@4.2.11:
     resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
 
+  /graphemer@1.4.0:
+    resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
+    dev: false
+
+  /has-bigints@1.0.2:
+    resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==}
+    dev: false
+
   /has-flag@3.0.0:
     resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
     engines: {node: '>=4'}
@@ -2322,14 +3730,32 @@
     resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
     engines: {node: '>=8'}
 
+  /has-property-descriptors@1.0.2:
+    resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==}
+    dependencies:
+      es-define-property: 1.0.0
+    dev: false
+
   /has-proto@1.0.1:
     resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==}
     engines: {node: '>= 0.4'}
 
+  /has-proto@1.0.3:
+    resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==}
+    engines: {node: '>= 0.4'}
+    dev: false
+
   /has-symbols@1.0.3:
     resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==}
     engines: {node: '>= 0.4'}
 
+  /has-tostringtag@1.0.2:
+    resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      has-symbols: 1.0.3
+    dev: false
+
   /has-unicode@2.0.1:
     resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==}
     dev: true
@@ -2345,7 +3771,13 @@
     engines: {node: '>= 0.4'}
     dependencies:
       function-bind: 1.1.2
-    dev: true
+
+  /hasown@2.0.2:
+    resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      function-bind: 1.1.2
+    dev: false
 
   /hosted-git-info@6.1.1:
     resolution: {integrity: sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==}
@@ -2453,14 +3885,25 @@
       minimatch: 9.0.3
     dev: true
 
+  /ignore@5.3.1:
+    resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==}
+    engines: {node: '>= 4'}
+    dev: false
+
   /immediate@3.0.6:
     resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==}
+
+  /import-fresh@3.3.0:
+    resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
+    engines: {node: '>=6'}
+    dependencies:
+      parent-module: 1.0.1
+      resolve-from: 4.0.0
     dev: false
 
   /imurmurhash@0.1.4:
     resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
     engines: {node: '>=0.8.19'}
-    dev: true
 
   /indent-string@4.0.0:
     resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==}
@@ -2511,10 +3954,40 @@
       wrap-ansi: 7.0.0
     dev: true
 
+  /internal-slot@1.0.7:
+    resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      es-errors: 1.3.0
+      hasown: 2.0.1
+      side-channel: 1.0.4
+    dev: false
+
   /ip@2.0.0:
     resolution: {integrity: sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==}
     dev: true
 
+  /is-array-buffer@3.0.4:
+    resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.7
+      get-intrinsic: 1.2.4
+    dev: false
+
+  /is-async-function@2.0.0:
+    resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      has-tostringtag: 1.0.2
+    dev: false
+
+  /is-bigint@1.0.4:
+    resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==}
+    dependencies:
+      has-bigints: 1.0.2
+    dev: false
+
   /is-binary-path@2.1.0:
     resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
     engines: {node: '>=8'}
@@ -2522,6 +3995,14 @@
     dependencies:
       binary-extensions: 2.2.0
 
+  /is-boolean-object@1.1.2:
+    resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.7
+      has-tostringtag: 1.0.2
+    dev: false
+
   /is-builtin-module@3.2.1:
     resolution: {integrity: sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==}
     engines: {node: '>=6'}
@@ -2529,6 +4010,11 @@
       builtin-modules: 3.3.0
     dev: true
 
+  /is-callable@1.2.7:
+    resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==}
+    engines: {node: '>= 0.4'}
+    dev: false
+
   /is-ci@3.0.1:
     resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==}
     hasBin: true
@@ -2546,7 +4032,20 @@
     resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==}
     dependencies:
       hasown: 2.0.1
-    dev: true
+
+  /is-data-view@1.0.1:
+    resolution: {integrity: sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      is-typed-array: 1.1.13
+    dev: false
+
+  /is-date-object@1.0.5:
+    resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      has-tostringtag: 1.0.2
+    dev: false
 
   /is-docker@2.2.1:
     resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==}
@@ -2559,10 +4058,23 @@
     engines: {node: '>=0.10.0'}
     requiresBuild: true
 
+  /is-finalizationregistry@1.0.2:
+    resolution: {integrity: sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==}
+    dependencies:
+      call-bind: 1.0.7
+    dev: false
+
   /is-fullwidth-code-point@3.0.0:
     resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
     engines: {node: '>=8'}
 
+  /is-generator-function@1.0.10:
+    resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      has-tostringtag: 1.0.2
+    dev: false
+
   /is-glob@4.0.3:
     resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
     engines: {node: '>=0.10.0'}
@@ -2587,25 +4099,98 @@
     resolution: {integrity: sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==}
     dev: true
 
+  /is-map@2.0.3:
+    resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==}
+    engines: {node: '>= 0.4'}
+    dev: false
+
   /is-module@1.0.0:
     resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==}
     dev: true
 
+  /is-negative-zero@2.0.3:
+    resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==}
+    engines: {node: '>= 0.4'}
+    dev: false
+
+  /is-number-object@1.0.7:
+    resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      has-tostringtag: 1.0.2
+    dev: false
+
   /is-number@7.0.0:
     resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
     engines: {node: '>=0.12.0'}
     requiresBuild: true
 
+  /is-path-cwd@2.2.0:
+    resolution: {integrity: sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==}
+    engines: {node: '>=6'}
+
+  /is-path-in-cwd@2.1.0:
+    resolution: {integrity: sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==}
+    engines: {node: '>=6'}
+    dependencies:
+      is-path-inside: 2.1.0
+
+  /is-path-inside@2.1.0:
+    resolution: {integrity: sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==}
+    engines: {node: '>=6'}
+    dependencies:
+      path-is-inside: 1.0.2
+
   /is-path-inside@3.0.3:
     resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==}
     engines: {node: '>=8'}
-    dev: true
+
+  /is-regex@1.1.4:
+    resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.7
+      has-tostringtag: 1.0.2
+    dev: false
+
+  /is-set@2.0.3:
+    resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==}
+    engines: {node: '>= 0.4'}
+    dev: false
+
+  /is-shared-array-buffer@1.0.3:
+    resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.7
+    dev: false
 
   /is-stream@2.0.1:
     resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
     engines: {node: '>=8'}
     dev: true
 
+  /is-string@1.0.7:
+    resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      has-tostringtag: 1.0.2
+    dev: false
+
+  /is-symbol@1.0.4:
+    resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      has-symbols: 1.0.3
+    dev: false
+
+  /is-typed-array@1.1.13:
+    resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      which-typed-array: 1.1.15
+    dev: false
+
   /is-typedarray@1.0.0:
     resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==}
     dev: true
@@ -2615,6 +4200,25 @@
     engines: {node: '>=10'}
     dev: true
 
+  /is-weakmap@2.0.2:
+    resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==}
+    engines: {node: '>= 0.4'}
+    dev: false
+
+  /is-weakref@1.0.2:
+    resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==}
+    dependencies:
+      call-bind: 1.0.7
+    dev: false
+
+  /is-weakset@2.0.3:
+    resolution: {integrity: sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.7
+      get-intrinsic: 1.2.4
+    dev: false
+
   /is-wsl@2.2.0:
     resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==}
     engines: {node: '>=8'}
@@ -2624,6 +4228,9 @@
 
   /isarray@1.0.0:
     resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==}
+
+  /isarray@2.0.5:
+    resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==}
     dev: false
 
   /isbinaryfile@4.0.10:
@@ -2632,12 +4239,21 @@
 
   /isexe@2.0.0:
     resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
-    dev: true
 
   /isstream@0.1.2:
     resolution: {integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==}
     dev: true
 
+  /iterator.prototype@1.1.2:
+    resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==}
+    dependencies:
+      define-properties: 1.2.1
+      get-intrinsic: 1.2.4
+      has-symbols: 1.0.3
+      reflect.getprototypeof: 1.0.6
+      set-function-name: 2.0.2
+    dev: false
+
   /jackspeak@2.3.6:
     resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==}
     engines: {node: '>=14'}
@@ -2647,9 +4263,23 @@
       '@pkgjs/parseargs': 0.11.0
     dev: true
 
+  /jest-worker@27.5.1:
+    resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==}
+    engines: {node: '>= 10.13.0'}
+    dependencies:
+      '@types/node': 20.11.19
+      merge-stream: 2.0.0
+      supports-color: 8.1.1
+
   /js-tokens@4.0.0:
     resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
-    dev: true
+
+  /js-yaml@4.1.0:
+    resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
+    hasBin: true
+    dependencies:
+      argparse: 2.0.1
+    dev: false
 
   /jsbn@0.1.1:
     resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==}
@@ -2661,11 +4291,21 @@
     hasBin: true
     dev: true
 
+  /json-buffer@3.0.1:
+    resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
+    dev: false
+
+  /json-parse-even-better-errors@2.3.1:
+    resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==}
+
   /json-parse-even-better-errors@3.0.0:
     resolution: {integrity: sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA==}
     engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
     dev: true
 
+  /json-schema-traverse@0.4.1:
+    resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
+
   /json-schema-traverse@1.0.0:
     resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==}
     dev: true
@@ -2674,10 +4314,21 @@
     resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==}
     dev: true
 
+  /json-stable-stringify-without-jsonify@1.0.1:
+    resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
+    dev: false
+
   /json-stringify-safe@5.0.1:
     resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==}
     dev: true
 
+  /json5@1.0.2:
+    resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==}
+    hasBin: true
+    dependencies:
+      minimist: 1.2.8
+    dev: false
+
   /json5@2.2.3:
     resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
     engines: {node: '>=6'}
@@ -2716,6 +4367,16 @@
       verror: 1.10.0
     dev: true
 
+  /jsx-ast-utils@3.3.5:
+    resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==}
+    engines: {node: '>=4.0'}
+    dependencies:
+      array-includes: 3.1.8
+      array.prototype.flat: 1.3.2
+      object.assign: 4.1.5
+      object.values: 1.2.0
+    dev: false
+
   /jszip@3.10.1:
     resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==}
     dependencies:
@@ -2723,7 +4384,6 @@
       pako: 1.0.11
       readable-stream: 2.3.8
       setimmediate: 1.0.5
-    dev: false
 
   /karma-safari-launcher@1.0.0(karma@6.4.3):
     resolution: {integrity: sha512-qmypLWd6F2qrDJfAETvXDfxHvKDk+nyIjpH9xIeI3/hENr0U3nuqkxaftq73PfXZ4aOuOChA6SnLW4m4AxfRjQ==}
@@ -2767,16 +4427,29 @@
       - supports-color
       - utf-8-validate
 
+  /keyv@4.5.4:
+    resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
+    dependencies:
+      json-buffer: 3.0.1
+    dev: false
+
   /lazy-ass@1.6.0:
     resolution: {integrity: sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==}
     engines: {node: '> 0.8'}
     dev: true
 
+  /levn@0.4.1:
+    resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
+    engines: {node: '>= 0.8.0'}
+    dependencies:
+      prelude-ls: 1.2.1
+      type-check: 0.4.0
+    dev: false
+
   /lie@3.3.0:
     resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==}
     dependencies:
       immediate: 3.0.6
-    dev: false
 
   /listr2@3.14.0(enquirer@2.3.6):
     resolution: {integrity: sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==}
@@ -2798,16 +4471,47 @@
       wrap-ansi: 7.0.0
     dev: true
 
+  /loader-runner@4.3.0:
+    resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==}
+    engines: {node: '>=6.11.5'}
+
   /locate-path@5.0.0:
     resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==}
     engines: {node: '>=8'}
     dependencies:
       p-locate: 4.1.0
 
+  /locate-path@6.0.0:
+    resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
+    engines: {node: '>=10'}
+    dependencies:
+      p-locate: 5.0.0
+    dev: false
+
+  /lodash.camelcase@4.3.0:
+    resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==}
+    dev: false
+
+  /lodash.kebabcase@4.1.1:
+    resolution: {integrity: sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==}
+    dev: false
+
+  /lodash.merge@4.6.2:
+    resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
+    dev: false
+
   /lodash.once@4.1.1:
     resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==}
     dev: true
 
+  /lodash.snakecase@4.1.1:
+    resolution: {integrity: sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==}
+    dev: false
+
+  /lodash.upperfirst@4.3.1:
+    resolution: {integrity: sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg==}
+    dev: false
+
   /lodash@4.17.21:
     resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
 
@@ -2841,10 +4545,16 @@
     transitivePeerDependencies:
       - supports-color
 
+  /loose-envify@1.4.0:
+    resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
+    hasBin: true
+    dependencies:
+      js-tokens: 4.0.0
+    dev: false
+
   /lru-cache@10.2.0:
     resolution: {integrity: sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==}
     engines: {node: 14 || >=16.14}
-    dev: true
 
   /lru-cache@5.1.1:
     resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
@@ -2857,7 +4567,6 @@
     engines: {node: '>=10'}
     dependencies:
       yallist: 4.0.0
-    dev: true
 
   /lru-cache@7.18.3:
     resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==}
@@ -2933,7 +4642,18 @@
 
   /merge-stream@2.0.0:
     resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
-    dev: true
+
+  /merge2@1.4.1:
+    resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
+    engines: {node: '>= 8'}
+    dev: false
+
+  /micromatch@4.0.5:
+    resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==}
+    engines: {node: '>=8.6'}
+    dependencies:
+      braces: 3.0.2
+      picomatch: 2.3.1
 
   /mime-db@1.52.0:
     resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
@@ -2967,12 +4687,17 @@
       brace-expansion: 2.0.1
     dev: true
 
+  /minimatch@8.0.4:
+    resolution: {integrity: sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==}
+    engines: {node: '>=16 || 14 >=14.17'}
+    dependencies:
+      brace-expansion: 2.0.1
+
   /minimatch@9.0.3:
     resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==}
     engines: {node: '>=16 || 14 >=14.17'}
     dependencies:
       brace-expansion: 2.0.1
-    dev: true
 
   /minimist@1.2.8:
     resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
@@ -3041,6 +4766,10 @@
       yallist: 4.0.0
     dev: true
 
+  /minipass@4.2.8:
+    resolution: {integrity: sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==}
+    engines: {node: '>=8'}
+
   /minipass@5.0.0:
     resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==}
     engines: {node: '>=8'}
@@ -3049,7 +4778,6 @@
   /minipass@7.0.4:
     resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==}
     engines: {node: '>=16 || 14 >=14.17'}
-    dev: true
 
   /minizlib@2.1.2:
     resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==}
@@ -3071,6 +4799,11 @@
     hasBin: true
     dev: true
 
+  /mkdirp@2.1.5:
+    resolution: {integrity: sha512-jbjfql+shJtAPrFoKxHOXip4xS+kul9W3OzfzzrqueWK2QMGon2bFH2opl6W9EagBThjEz+iysyi/swOoVfB/w==}
+    engines: {node: '>=10'}
+    hasBin: true
+
   /ms@2.0.0:
     resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}
 
@@ -3079,16 +4812,37 @@
 
   /ms@2.1.3:
     resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
-    dev: true
 
   /mute-stream@0.0.8:
     resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==}
     dev: true
 
+  /natural-compare@1.4.0:
+    resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
+    dev: false
+
+  /ncp@2.0.0:
+    resolution: {integrity: sha512-zIdGUrPRFTUELUvr3Gmc7KZ2Sw/h1PiVM0Af/oHB6zgnV1ikqSfRk+TOufi79aHYCW3NiOXmr1BP5nWbzojLaA==}
+    hasBin: true
+
   /negotiator@0.6.3:
     resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==}
     engines: {node: '>= 0.6'}
 
+  /neo-async@2.6.2:
+    resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==}
+
+  /node-fetch@2.6.9:
+    resolution: {integrity: sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==}
+    engines: {node: 4.x || >=6.0.0}
+    peerDependencies:
+      encoding: ^0.1.0
+    peerDependenciesMeta:
+      encoding:
+        optional: true
+    dependencies:
+      whatwg-url: 5.0.0
+
   /node-gyp@9.4.1:
     resolution: {integrity: sha512-OQkWKbjQKbGkMf/xqI1jjy3oCTgMKJac58G2+bjZb3fza6gW2YrCSdMQYaoTb70crvE//Gngr4f0AgVHmqHvBQ==}
     engines: {node: ^12.13 || ^14.13 || >=16}
@@ -3112,7 +4866,6 @@
 
   /node-releases@2.0.14:
     resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==}
-    dev: true
 
   /nopt@6.0.0:
     resolution: {integrity: sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==}
@@ -3222,6 +4975,71 @@
   /object-inspect@1.12.3:
     resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==}
 
+  /object-inspect@1.13.1:
+    resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==}
+    dev: false
+
+  /object-keys@1.1.1:
+    resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
+    engines: {node: '>= 0.4'}
+    dev: false
+
+  /object.assign@4.1.5:
+    resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.7
+      define-properties: 1.2.1
+      has-symbols: 1.0.3
+      object-keys: 1.1.1
+    dev: false
+
+  /object.entries@1.1.8:
+    resolution: {integrity: sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.7
+      define-properties: 1.2.1
+      es-object-atoms: 1.0.0
+    dev: false
+
+  /object.fromentries@2.0.8:
+    resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.7
+      define-properties: 1.2.1
+      es-abstract: 1.23.3
+      es-object-atoms: 1.0.0
+    dev: false
+
+  /object.groupby@1.0.3:
+    resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.7
+      define-properties: 1.2.1
+      es-abstract: 1.23.3
+    dev: false
+
+  /object.hasown@1.1.4:
+    resolution: {integrity: sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      define-properties: 1.2.1
+      es-abstract: 1.23.3
+      es-object-atoms: 1.0.0
+    dev: false
+
+  /object.values@1.2.0:
+    resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.7
+      define-properties: 1.2.1
+      es-object-atoms: 1.0.0
+    dev: false
+
   /on-finished@2.3.0:
     resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==}
     engines: {node: '>= 0.8'}
@@ -3255,6 +5073,18 @@
       is-wsl: 2.2.0
     dev: true
 
+  /optionator@0.9.4:
+    resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
+    engines: {node: '>= 0.8.0'}
+    dependencies:
+      deep-is: 0.1.4
+      fast-levenshtein: 2.0.6
+      levn: 0.4.1
+      prelude-ls: 1.2.1
+      type-check: 0.4.0
+      word-wrap: 1.2.5
+    dev: false
+
   /ora@5.4.1:
     resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==}
     engines: {node: '>=10'}
@@ -3285,12 +5115,30 @@
     dependencies:
       p-try: 2.2.0
 
+  /p-limit@3.1.0:
+    resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
+    engines: {node: '>=10'}
+    dependencies:
+      yocto-queue: 0.1.0
+    dev: false
+
   /p-locate@4.1.0:
     resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==}
     engines: {node: '>=8'}
     dependencies:
       p-limit: 2.3.0
 
+  /p-locate@5.0.0:
+    resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
+    engines: {node: '>=10'}
+    dependencies:
+      p-limit: 3.1.0
+    dev: false
+
+  /p-map@2.1.0:
+    resolution: {integrity: sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==}
+    engines: {node: '>=6'}
+
   /p-map@4.0.0:
     resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==}
     engines: {node: '>=10'}
@@ -3332,11 +5180,17 @@
 
   /pako@1.0.11:
     resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==}
-    dev: false
 
   /pako@2.1.0:
     resolution: {integrity: sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==}
 
+  /parent-module@1.0.1:
+    resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
+    engines: {node: '>=6'}
+    dependencies:
+      callsites: 3.1.0
+    dev: false
+
   /parse5@6.0.1:
     resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==}
     dev: true
@@ -3345,6 +5199,9 @@
     resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
     engines: {node: '>= 0.8'}
 
+  /path-browserify@1.0.1:
+    resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==}
+
   /path-exists@4.0.0:
     resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
     engines: {node: '>=8'}
@@ -3353,14 +5210,15 @@
     resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
     engines: {node: '>=0.10.0'}
 
+  /path-is-inside@1.0.2:
+    resolution: {integrity: sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==}
+
   /path-key@3.1.1:
     resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
     engines: {node: '>=8'}
-    dev: true
 
   /path-parse@1.0.7:
     resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
-    dev: true
 
   /path-scurry@1.10.1:
     resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==}
@@ -3368,7 +5226,11 @@
     dependencies:
       lru-cache: 10.2.0
       minipass: 7.0.4
-    dev: true
+
+  /path-type@4.0.0:
+    resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
+    engines: {node: '>=8'}
+    dev: false
 
   /pend@1.2.0:
     resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==}
@@ -3380,7 +5242,6 @@
 
   /picocolors@1.0.0:
     resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
-    dev: true
 
   /picomatch@2.3.1:
     resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
@@ -3389,23 +5250,54 @@
   /pify@2.3.0:
     resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==}
     engines: {node: '>=0.10.0'}
-    dev: true
 
   /pify@4.0.1:
     resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==}
     engines: {node: '>=6'}
-    dev: true
+
+  /pinkie-promise@2.0.1:
+    resolution: {integrity: sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==}
+    engines: {node: '>=0.10.0'}
+    dependencies:
+      pinkie: 2.0.4
+
+  /pinkie@2.0.4:
+    resolution: {integrity: sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==}
+    engines: {node: '>=0.10.0'}
 
   /pngjs@5.0.0:
     resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==}
     engines: {node: '>=10.13.0'}
 
+  /possible-typed-array-names@1.0.0:
+    resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==}
+    engines: {node: '>= 0.4'}
+    dev: false
+
+  /prelude-ls@1.2.1:
+    resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
+    engines: {node: '>= 0.8.0'}
+    dev: false
+
+  /prettier-linter-helpers@1.0.0:
+    resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==}
+    engines: {node: '>=6.0.0'}
+    dependencies:
+      fast-diff: 1.3.0
+    dev: false
+
   /prettier@2.6.1:
     resolution: {integrity: sha512-8UVbTBYGwN37Bs9LERmxCPjdvPxlEowx2urIL6urHzdb3SDq4B/Z6xLFCblrSnE4iKWcS6ziJ3aOYrc1kz/E2A==}
     engines: {node: '>=10.13.0'}
     hasBin: true
     dev: true
 
+  /prettier@3.2.5:
+    resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==}
+    engines: {node: '>=14'}
+    hasBin: true
+    dev: false
+
   /pretty-bytes@5.6.0:
     resolution: {integrity: sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==}
     engines: {node: '>=6'}
@@ -3418,7 +5310,6 @@
 
   /process-nextick-args@2.0.1:
     resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
-    dev: false
 
   /process@0.11.10:
     resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==}
@@ -3442,6 +5333,14 @@
       retry: 0.12.0
     dev: true
 
+  /prop-types@15.8.1:
+    resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
+    dependencies:
+      loose-envify: 1.4.0
+      object-assign: 4.1.1
+      react-is: 16.13.1
+    dev: false
+
   /proxy-from-env@1.0.0:
     resolution: {integrity: sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==}
     dev: true
@@ -3460,7 +5359,6 @@
   /punycode@2.3.0:
     resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==}
     engines: {node: '>=6'}
-    dev: true
 
   /qjobs@1.2.0:
     resolution: {integrity: sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==}
@@ -3493,6 +5391,15 @@
     resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==}
     dev: true
 
+  /queue-microtask@1.2.3:
+    resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
+    dev: false
+
+  /randombytes@2.1.0:
+    resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
+    dependencies:
+      safe-buffer: 5.2.1
+
   /range-parser@1.2.1:
     resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
     engines: {node: '>= 0.6'}
@@ -3506,6 +5413,27 @@
       iconv-lite: 0.4.24
       unpipe: 1.0.0
 
+  /react-dom@18.3.1(react@18.3.1):
+    resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==}
+    peerDependencies:
+      react: ^18.3.1
+    dependencies:
+      loose-envify: 1.4.0
+      react: 18.3.1
+      scheduler: 0.23.2
+    dev: false
+
+  /react-is@16.13.1:
+    resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
+    dev: false
+
+  /react@18.3.1:
+    resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==}
+    engines: {node: '>=0.10.0'}
+    dependencies:
+      loose-envify: 1.4.0
+    dev: false
+
   /read-package-json-fast@3.0.2:
     resolution: {integrity: sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==}
     engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
@@ -3534,7 +5462,6 @@
       safe-buffer: 5.1.2
       string_decoder: 1.1.1
       util-deprecate: 1.0.2
-    dev: false
 
   /readable-stream@3.6.2:
     resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
@@ -3556,6 +5483,34 @@
     resolution: {integrity: sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==}
     dev: true
 
+  /reflect.getprototypeof@1.0.6:
+    resolution: {integrity: sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.7
+      define-properties: 1.2.1
+      es-abstract: 1.23.3
+      es-errors: 1.3.0
+      get-intrinsic: 1.2.4
+      globalthis: 1.0.3
+      which-builtin-type: 1.1.3
+    dev: false
+
+  /regexp.prototype.flags@1.5.2:
+    resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.7
+      define-properties: 1.2.1
+      es-errors: 1.3.0
+      set-function-name: 2.0.2
+    dev: false
+
+  /regexpp@3.2.0:
+    resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==}
+    engines: {node: '>=8'}
+    dev: false
+
   /request-progress@3.0.0:
     resolution: {integrity: sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg==}
     dependencies:
@@ -3583,6 +5538,11 @@
   /requires-port@1.0.0:
     resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==}
 
+  /resolve-from@4.0.0:
+    resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
+    engines: {node: '>=4'}
+    dev: false
+
   /resolve@1.22.2:
     resolution: {integrity: sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==}
     hasBin: true
@@ -3592,6 +5552,24 @@
       supports-preserve-symlinks-flag: 1.0.0
     dev: true
 
+  /resolve@1.22.8:
+    resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==}
+    hasBin: true
+    dependencies:
+      is-core-module: 2.13.1
+      path-parse: 1.0.7
+      supports-preserve-symlinks-flag: 1.0.0
+    dev: false
+
+  /resolve@2.0.0-next.5:
+    resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==}
+    hasBin: true
+    dependencies:
+      is-core-module: 2.13.1
+      path-parse: 1.0.7
+      supports-preserve-symlinks-flag: 1.0.0
+    dev: false
+
   /restore-cursor@3.1.0:
     resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==}
     engines: {node: '>=8'}
@@ -3605,15 +5583,33 @@
     engines: {node: '>= 4'}
     dev: true
 
+  /reusify@1.0.4:
+    resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
+    engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
+    dev: false
+
   /rfdc@1.3.0:
     resolution: {integrity: sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==}
 
+  /rimraf@2.7.1:
+    resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==}
+    hasBin: true
+    dependencies:
+      glob: 7.2.3
+
   /rimraf@3.0.2:
     resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
     hasBin: true
     dependencies:
       glob: 7.2.3
 
+  /rimraf@4.3.1:
+    resolution: {integrity: sha512-GfHJHBzFQra23IxDzIdBqhOWfbtdgS1/dCHrDy+yvhpoJY5TdwdT28oWaHWfRpKFDLd3GZnGTx6Mlt4+anbsxQ==}
+    engines: {node: '>=14'}
+    hasBin: true
+    dependencies:
+      glob: 9.3.5
+
   /rollup@4.12.0:
     resolution: {integrity: sha512-wz66wn4t1OHIJw3+XU7mJJQV/2NAfw5OAk6G6Hoo3zcvz/XOfQ52Vgi+AN4Uxoxi0KBBwk2g8zPrTDA4btSB/Q==}
     engines: {node: '>=18.0.0', npm: '>=8.0.0'}
@@ -3642,6 +5638,12 @@
     engines: {node: '>=0.12.0'}
     dev: true
 
+  /run-parallel@1.2.0:
+    resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
+    dependencies:
+      queue-microtask: 1.2.3
+    dev: false
+
   /rxjs@7.5.7:
     resolution: {integrity: sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==}
     dependencies:
@@ -3653,17 +5655,53 @@
       tslib: 2.6.0
     dev: true
 
+  /safe-array-concat@1.1.2:
+    resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==}
+    engines: {node: '>=0.4'}
+    dependencies:
+      call-bind: 1.0.7
+      get-intrinsic: 1.2.4
+      has-symbols: 1.0.3
+      isarray: 2.0.5
+    dev: false
+
   /safe-buffer@5.1.2:
     resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==}
-    dev: false
 
   /safe-buffer@5.2.1:
     resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
-    dev: true
+
+  /safe-regex-test@1.0.3:
+    resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.7
+      es-errors: 1.3.0
+      is-regex: 1.1.4
+    dev: false
 
   /safer-buffer@2.1.2:
     resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
 
+  /sanitize-filename@1.6.3:
+    resolution: {integrity: sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==}
+    dependencies:
+      truncate-utf8-bytes: 1.0.2
+
+  /scheduler@0.23.2:
+    resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==}
+    dependencies:
+      loose-envify: 1.4.0
+    dev: false
+
+  /schema-utils@3.3.0:
+    resolution: {integrity: sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==}
+    engines: {node: '>= 10.13.0'}
+    dependencies:
+      '@types/json-schema': 7.0.15
+      ajv: 6.12.6
+      ajv-keywords: 3.5.2(ajv@6.12.6)
+
   /selenium-webdriver@4.18.1:
     resolution: {integrity: sha512-uP4OJ5wR4+VjdTi5oi/k8oieV2fIhVdVuaOPrklKghgS59w7Zz3nGa5gcG73VcU9EBRv5IZEBRhPr7qFJAj5mQ==}
     engines: {node: '>= 14.20.0'}
@@ -3684,7 +5722,6 @@
   /semver@6.3.1:
     resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
     hasBin: true
-    dev: true
 
   /semver@7.5.4:
     resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==}
@@ -3700,14 +5737,39 @@
     hasBin: true
     dependencies:
       lru-cache: 6.0.0
-    dev: true
+
+  /serialize-javascript@6.0.2:
+    resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==}
+    dependencies:
+      randombytes: 2.1.0
 
   /set-blocking@2.0.0:
     resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
 
+  /set-function-length@1.2.2:
+    resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      define-data-property: 1.1.4
+      es-errors: 1.3.0
+      function-bind: 1.1.2
+      get-intrinsic: 1.2.4
+      gopd: 1.0.1
+      has-property-descriptors: 1.0.2
+    dev: false
+
+  /set-function-name@2.0.2:
+    resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      define-data-property: 1.1.4
+      es-errors: 1.3.0
+      functions-have-names: 1.2.3
+      has-property-descriptors: 1.0.2
+    dev: false
+
   /setimmediate@1.0.5:
     resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==}
-    dev: false
 
   /setprototypeof@1.2.0:
     resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
@@ -3717,12 +5779,10 @@
     engines: {node: '>=8'}
     dependencies:
       shebang-regex: 3.0.0
-    dev: true
 
   /shebang-regex@3.0.0:
     resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
     engines: {node: '>=8'}
-    dev: true
 
   /side-channel@1.0.4:
     resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==}
@@ -3731,6 +5791,16 @@
       get-intrinsic: 1.2.1
       object-inspect: 1.12.3
 
+  /side-channel@1.0.6:
+    resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.7
+      es-errors: 1.3.0
+      get-intrinsic: 1.2.4
+      object-inspect: 1.13.1
+    dev: false
+
   /signal-exit@3.0.7:
     resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
     dev: true
@@ -3759,6 +5829,11 @@
     engines: {node: '>=6'}
     dev: true
 
+  /slash@3.0.0:
+    resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
+    engines: {node: '>=8'}
+    dev: false
+
   /slice-ansi@3.0.0:
     resolution: {integrity: sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==}
     engines: {node: '>=8'}
@@ -3841,7 +5916,6 @@
     dependencies:
       buffer-from: 1.1.2
       source-map: 0.6.1
-    dev: true
 
   /source-map@0.6.1:
     resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
@@ -3939,11 +6013,55 @@
       strip-ansi: 7.1.0
     dev: true
 
+  /string.prototype.matchall@4.0.11:
+    resolution: {integrity: sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.7
+      define-properties: 1.2.1
+      es-abstract: 1.23.3
+      es-errors: 1.3.0
+      es-object-atoms: 1.0.0
+      get-intrinsic: 1.2.4
+      gopd: 1.0.1
+      has-symbols: 1.0.3
+      internal-slot: 1.0.7
+      regexp.prototype.flags: 1.5.2
+      set-function-name: 2.0.2
+      side-channel: 1.0.6
+    dev: false
+
+  /string.prototype.trim@1.2.9:
+    resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.7
+      define-properties: 1.2.1
+      es-abstract: 1.23.3
+      es-object-atoms: 1.0.0
+    dev: false
+
+  /string.prototype.trimend@1.0.8:
+    resolution: {integrity: sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==}
+    dependencies:
+      call-bind: 1.0.7
+      define-properties: 1.2.1
+      es-object-atoms: 1.0.0
+    dev: false
+
+  /string.prototype.trimstart@1.0.8:
+    resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.7
+      define-properties: 1.2.1
+      es-object-atoms: 1.0.0
+    dev: false
+
   /string_decoder@1.1.1:
     resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==}
     dependencies:
       safe-buffer: 5.1.2
-    dev: false
 
   /string_decoder@1.3.0:
     resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
@@ -3964,11 +6082,21 @@
       ansi-regex: 6.0.1
     dev: true
 
+  /strip-bom@3.0.0:
+    resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
+    engines: {node: '>=4'}
+    dev: false
+
   /strip-final-newline@2.0.0:
     resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==}
     engines: {node: '>=6'}
     dev: true
 
+  /strip-json-comments@3.1.1:
+    resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
+    engines: {node: '>=8'}
+    dev: false
+
   /supports-color@5.5.0:
     resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
     engines: {node: '>=4'}
@@ -3981,7 +6109,6 @@
     engines: {node: '>=8'}
     dependencies:
       has-flag: 4.0.0
-    dev: true
 
   /supports-color@8.1.1:
     resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==}
@@ -3992,13 +6119,24 @@
   /supports-preserve-symlinks-flag@1.0.0:
     resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
     engines: {node: '>= 0.4'}
-    dev: true
 
   /symbol-observable@4.0.0:
     resolution: {integrity: sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==}
     engines: {node: '>=0.10'}
     dev: true
 
+  /synckit@0.8.8:
+    resolution: {integrity: sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==}
+    engines: {node: ^14.18.0 || >=16.0.0}
+    dependencies:
+      '@pkgr/core': 0.1.1
+      tslib: 2.6.2
+    dev: false
+
+  /tapable@2.2.1:
+    resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==}
+    engines: {node: '>=6'}
+
   /tar@6.1.15:
     resolution: {integrity: sha512-/zKt9UyngnxIT/EAGYuxaMYgOIJiP81ab9ZfkILq4oNLPFX50qyYmu7jRj9qeXoxmJHjGlbH0+cm2uy1WCs10A==}
     engines: {node: '>=10'}
@@ -4011,6 +6149,29 @@
       yallist: 4.0.0
     dev: true
 
+  /terser-webpack-plugin@5.3.10(webpack@5.75.0):
+    resolution: {integrity: sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==}
+    engines: {node: '>= 10.13.0'}
+    peerDependencies:
+      '@swc/core': '*'
+      esbuild: '*'
+      uglify-js: '*'
+      webpack: ^5.1.0
+    peerDependenciesMeta:
+      '@swc/core':
+        optional: true
+      esbuild:
+        optional: true
+      uglify-js:
+        optional: true
+    dependencies:
+      '@jridgewell/trace-mapping': 0.3.25
+      jest-worker: 27.5.1
+      schema-utils: 3.3.0
+      serialize-javascript: 6.0.2
+      terser: 5.30.0
+      webpack: 5.75.0
+
   /terser@5.16.4:
     resolution: {integrity: sha512-5yEGuZ3DZradbogeYQ1NaGz7rXVBDWujWlx1PT8efXO6Txn+eWbfKqB2bTDVmFXmePFkoLU6XI8UektMIEA0ug==}
     engines: {node: '>=10'}
@@ -4022,6 +6183,20 @@
       source-map-support: 0.5.21
     dev: true
 
+  /terser@5.30.0:
+    resolution: {integrity: sha512-Y/SblUl5kEyEFzhMAQdsxVHh+utAxd4IuRNJzKywY/4uzSogh3G219jqbDDxYu4MXO9CzY3tSEqmZvW6AoEDJw==}
+    engines: {node: '>=10'}
+    hasBin: true
+    dependencies:
+      '@jridgewell/source-map': 0.3.4
+      acorn: 8.9.0
+      commander: 2.20.3
+      source-map-support: 0.5.21
+
+  /text-table@0.2.0:
+    resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
+    dev: false
+
   /throttleit@1.0.0:
     resolution: {integrity: sha512-rkTVqu6IjfQ/6+uNuuc3sZek4CEYxTJom3IktzgdSxcZqdARuebbA/f4QmAxMQIxqq9ZLEUkSYqvuk1I6VKq4g==}
     dev: true
@@ -4069,9 +6244,67 @@
       url-parse: 1.5.10
     dev: true
 
+  /tr46@0.0.3:
+    resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
+
+  /truncate-utf8-bytes@1.0.2:
+    resolution: {integrity: sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==}
+    dependencies:
+      utf8-byte-length: 1.0.4
+
+  /ts-api-utils@1.3.0(typescript@5.1.6):
+    resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==}
+    engines: {node: '>=16'}
+    peerDependencies:
+      typescript: '>=4.2.0'
+    dependencies:
+      typescript: 5.1.6
+    dev: false
+
+  /ts-loader@9.4.2(typescript@5.1.6)(webpack@5.75.0):
+    resolution: {integrity: sha512-OmlC4WVmFv5I0PpaxYb+qGeGOdm5giHU7HwDDUjw59emP2UYMHy9fFSDcYgSNoH8sXcj4hGCSEhlDZ9ULeDraA==}
+    engines: {node: '>=12.0.0'}
+    peerDependencies:
+      typescript: '*'
+      webpack: ^5.0.0
+    dependencies:
+      chalk: 4.1.2
+      enhanced-resolve: 5.16.0
+      micromatch: 4.0.5
+      semver: 7.6.0
+      typescript: 5.1.6
+      webpack: 5.75.0
+
+  /tsconfig-paths@3.15.0:
+    resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==}
+    dependencies:
+      '@types/json5': 0.0.29
+      json5: 1.0.2
+      minimist: 1.2.8
+      strip-bom: 3.0.0
+    dev: false
+
+  /tslib@1.14.1:
+    resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
+    dev: false
+
   /tslib@2.6.0:
     resolution: {integrity: sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==}
 
+  /tslib@2.6.2:
+    resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
+    dev: false
+
+  /tsutils@3.21.0(typescript@5.1.6):
+    resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
+    engines: {node: '>= 6'}
+    peerDependencies:
+      typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta'
+    dependencies:
+      tslib: 1.14.1
+      typescript: 5.1.6
+    dev: false
+
   /tuf-js@1.1.7:
     resolution: {integrity: sha512-i3P9Kgw3ytjELUfpuKVDNBJvk4u5bXL6gskv572mcevPbSKCV3zt3djhmlEQ65yERjIbOSncy7U4cQJaB1CBCg==}
     engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
@@ -4093,6 +6326,18 @@
     resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==}
     dev: true
 
+  /type-check@0.4.0:
+    resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
+    engines: {node: '>= 0.8.0'}
+    dependencies:
+      prelude-ls: 1.2.1
+    dev: false
+
+  /type-fest@0.20.2:
+    resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==}
+    engines: {node: '>=10'}
+    dev: false
+
   /type-fest@0.21.3:
     resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==}
     engines: {node: '>=10'}
@@ -4105,15 +6350,67 @@
       media-typer: 0.3.0
       mime-types: 2.1.35
 
+  /typed-array-buffer@1.0.2:
+    resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.7
+      es-errors: 1.3.0
+      is-typed-array: 1.1.13
+    dev: false
+
+  /typed-array-byte-length@1.0.1:
+    resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.7
+      for-each: 0.3.3
+      gopd: 1.0.1
+      has-proto: 1.0.3
+      is-typed-array: 1.1.13
+    dev: false
+
+  /typed-array-byte-offset@1.0.2:
+    resolution: {integrity: sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      available-typed-arrays: 1.0.7
+      call-bind: 1.0.7
+      for-each: 0.3.3
+      gopd: 1.0.1
+      has-proto: 1.0.3
+      is-typed-array: 1.1.13
+    dev: false
+
+  /typed-array-length@1.0.6:
+    resolution: {integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      call-bind: 1.0.7
+      for-each: 0.3.3
+      gopd: 1.0.1
+      has-proto: 1.0.3
+      is-typed-array: 1.1.13
+      possible-typed-array-names: 1.0.0
+    dev: false
+
   /typescript@5.1.6:
     resolution: {integrity: sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==}
     engines: {node: '>=14.17'}
     hasBin: true
-    dev: true
 
   /ua-parser-js@0.7.37:
     resolution: {integrity: sha512-xV8kqRKM+jhMvcHWUKthV9fNebIzrNy//2O9ZwWcfiBFR5f25XVZPLlEajk/sf3Ra15V92isyQqnIEXRDaZWEA==}
 
+  /unbox-primitive@1.0.2:
+    resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==}
+    dependencies:
+      call-bind: 1.0.7
+      has-bigints: 1.0.2
+      has-symbols: 1.0.3
+      which-boxed-primitive: 1.0.2
+    dev: false
+
   /undici-types@5.26.5:
     resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
 
@@ -4177,13 +6474,11 @@
       browserslist: 4.23.0
       escalade: 3.1.1
       picocolors: 1.0.0
-    dev: true
 
   /uri-js@4.4.1:
     resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
     dependencies:
       punycode: 2.3.0
-    dev: true
 
   /url-parse@1.5.10:
     resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==}
@@ -4192,6 +6487,9 @@
       requires-port: 1.0.0
     dev: true
 
+  /utf8-byte-length@1.0.4:
+    resolution: {integrity: sha512-4+wkEYLBbWxqTahEsWrhxepcoVOJ+1z5PGIjPZxRkytcdSUaNjIjBM7Xn8E+pdSuV7SzvWovBFA54FO0JSoqhA==}
+
   /util-deprecate@1.0.2:
     resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
 
@@ -4235,22 +6533,129 @@
     resolution: {integrity: sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==}
     engines: {node: '>=0.10.0'}
 
+  /watchpack@2.4.1:
+    resolution: {integrity: sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==}
+    engines: {node: '>=10.13.0'}
+    dependencies:
+      glob-to-regexp: 0.4.1
+      graceful-fs: 4.2.11
+
   /wcwidth@1.0.1:
     resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==}
     dependencies:
       defaults: 1.0.4
     dev: true
 
+  /webidl-conversions@3.0.1:
+    resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
+
+  /webpack-sources@3.2.3:
+    resolution: {integrity: sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==}
+    engines: {node: '>=10.13.0'}
+
+  /webpack@5.75.0:
+    resolution: {integrity: sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==}
+    engines: {node: '>=10.13.0'}
+    hasBin: true
+    peerDependencies:
+      webpack-cli: '*'
+    peerDependenciesMeta:
+      webpack-cli:
+        optional: true
+    dependencies:
+      '@types/eslint-scope': 3.7.7
+      '@types/estree': 0.0.51
+      '@webassemblyjs/ast': 1.11.1
+      '@webassemblyjs/wasm-edit': 1.11.1
+      '@webassemblyjs/wasm-parser': 1.11.1
+      acorn: 8.9.0
+      acorn-import-assertions: 1.9.0(acorn@8.9.0)
+      browserslist: 4.23.0
+      chrome-trace-event: 1.0.3
+      enhanced-resolve: 5.16.0
+      es-module-lexer: 0.9.3
+      eslint-scope: 5.1.1
+      events: 3.3.0
+      glob-to-regexp: 0.4.1
+      graceful-fs: 4.2.11
+      json-parse-even-better-errors: 2.3.1
+      loader-runner: 4.3.0
+      mime-types: 2.1.35
+      neo-async: 2.6.2
+      schema-utils: 3.3.0
+      tapable: 2.2.1
+      terser-webpack-plugin: 5.3.10(webpack@5.75.0)
+      watchpack: 2.4.1
+      webpack-sources: 3.2.3
+    transitivePeerDependencies:
+      - '@swc/core'
+      - esbuild
+      - uglify-js
+
+  /whatwg-url@5.0.0:
+    resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
+    dependencies:
+      tr46: 0.0.3
+      webidl-conversions: 3.0.1
+
+  /which-boxed-primitive@1.0.2:
+    resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==}
+    dependencies:
+      is-bigint: 1.0.4
+      is-boolean-object: 1.1.2
+      is-number-object: 1.0.7
+      is-string: 1.0.7
+      is-symbol: 1.0.4
+    dev: false
+
+  /which-builtin-type@1.1.3:
+    resolution: {integrity: sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      function.prototype.name: 1.1.6
+      has-tostringtag: 1.0.2
+      is-async-function: 2.0.0
+      is-date-object: 1.0.5
+      is-finalizationregistry: 1.0.2
+      is-generator-function: 1.0.10
+      is-regex: 1.1.4
+      is-weakref: 1.0.2
+      isarray: 2.0.5
+      which-boxed-primitive: 1.0.2
+      which-collection: 1.0.2
+      which-typed-array: 1.1.15
+    dev: false
+
+  /which-collection@1.0.2:
+    resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      is-map: 2.0.3
+      is-set: 2.0.3
+      is-weakmap: 2.0.2
+      is-weakset: 2.0.3
+    dev: false
+
   /which-module@2.0.1:
     resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==}
 
+  /which-typed-array@1.1.15:
+    resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==}
+    engines: {node: '>= 0.4'}
+    dependencies:
+      available-typed-arrays: 1.0.7
+      call-bind: 1.0.7
+      for-each: 0.3.3
+      gopd: 1.0.1
+      has-tostringtag: 1.0.2
+    dev: false
+
   /which@2.0.2:
     resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
     engines: {node: '>= 8'}
     hasBin: true
     dependencies:
       isexe: 2.0.0
-    dev: true
 
   /which@3.0.1:
     resolution: {integrity: sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==}
@@ -4266,6 +6671,11 @@
       string-width: 4.2.3
     dev: true
 
+  /word-wrap@1.2.5:
+    resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
+    engines: {node: '>=0.10.0'}
+    dev: false
+
   /wrap-ansi@6.2.0:
     resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==}
     engines: {node: '>=8'}
@@ -4332,7 +6742,6 @@
 
   /yallist@4.0.0:
     resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
-    dev: true
 
   /yargs-parser@18.1.3:
     resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==}
@@ -4398,6 +6807,11 @@
       fd-slicer: 1.1.0
     dev: true
 
+  /yocto-queue@0.1.0:
+    resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
+    engines: {node: '>=10'}
+    dev: false
+
   /zone.js@0.13.3:
     resolution: {integrity: sha512-MKPbmZie6fASC/ps4dkmIhaT5eonHkEt6eAy80K42tAm0G2W+AahLJjbfi6X9NPdciOE9GRFTTM8u2IiF6O3ww==}
     dependencies:
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
index 6eac091..f18844b 100644
--- a/pnpm-workspace.yaml
+++ b/pnpm-workspace.yaml
@@ -1,5 +1,6 @@
 packages:
-  - 'scouting/webserver/requests/messages'
-  - 'scouting/www'
-  - 'scouting/www/*'
-  - 'scouting/www/test/*'
+- scouting/webserver/requests/messages
+- scouting/www
+- scouting/www/*
+- scouting/www/test/*
+- aos/analysis/foxglove_extension
diff --git a/third_party/ceres/.github/workflows/android.yml b/third_party/ceres/.github/workflows/android.yml
new file mode 100644
index 0000000..ee5e966
--- /dev/null
+++ b/third_party/ceres/.github/workflows/android.yml
@@ -0,0 +1,171 @@
+name: Android
+
+on: [push, pull_request]
+
+jobs:
+  build-android:
+    name: NDK-${{matrix.abi}}-${{matrix.build_type}}-${{matrix.lib}}
+    runs-on: ${{matrix.os}}
+    defaults:
+      run:
+        shell: bash -e -o pipefail {0}
+    env:
+      CCACHE_DIR: ${{github.workspace}}/ccache
+      CMAKE_GENERATOR: Ninja
+      DEBIAN_FRONTEND: noninteractive
+    strategy:
+      fail-fast: true
+      matrix:
+        os:
+          - ubuntu-20.04
+        abi:
+          - arm64-v8a
+          - armeabi-v7a
+          - x86
+          - x86_64
+        build_type:
+          - Release
+        lib:
+          - shared
+          - static
+        android_api_level:
+          - '28'
+
+    steps:
+      - uses: actions/checkout@v4
+
+      - name: Setup Dependencies
+        run: |
+          sudo apt-get update
+          sudo apt-get install -y \
+            ccache \
+            ninja-build
+
+      # Ensure the declared NDK version is always installed even if it's removed
+      # from the virtual environment.
+      - name: Setup NDK
+        env:
+          ANDROID_NDK_VERSION: 23.2.8568313
+          ANDROID_SDK_ROOT: /usr/local/lib/android/sdk
+        run: |
+          echo 'y' | ${{env.ANDROID_SDK_ROOT}}/cmdline-tools/latest/bin/sdkmanager --install 'ndk;${{env.ANDROID_NDK_VERSION}}'
+          echo "ANDROID_NDK_ROOT=${{env.ANDROID_SDK_ROOT}}/ndk/${{env.ANDROID_NDK_VERSION}}" >> $GITHUB_ENV
+
+      - name: Cache Eigen
+        id: cache-eigen
+        uses: actions/cache@v4
+        with:
+          path: eigen/
+          key: NDK-${{matrix.os}}-eigen-3.4.0-${{matrix.abi}}
+
+      - name: Download Eigen
+        if: steps.cache-eigen.outputs.cache-hit != 'true'
+        run: |
+          wget https://gitlab.com/libeigen/eigen/-/archive/3.4.0/eigen-3.4.0.zip
+          unzip eigen-3.4.0.zip
+
+      - name: Setup Eigen
+        if: steps.cache-eigen.outputs.cache-hit != 'true'
+        run: |
+          cmake -S eigen-3.4.0 -B build-eigen \
+                -DBUILD_TESTING=OFF \
+                -DCMAKE_ANDROID_API=${{matrix.android_api_level}} \
+                -DCMAKE_ANDROID_ARCH_ABI=${{matrix.abi}} \
+                -DCMAKE_ANDROID_STL_TYPE=c++_shared \
+                -DCMAKE_Fortran_COMPILER= \
+                -DCMAKE_INSTALL_PREFIX=${{github.workspace}}/eigen \
+                -DCMAKE_SYSTEM_NAME=Android \
+                -DEIGEN_BUILD_DOC=OFF
+          cmake --build build-eigen \
+                --config ${{matrix.build_type}} \
+                --target install
+
+      - name: Cache gflags
+        id: cache-gflags
+        uses: actions/cache@v4
+        with:
+          path: gflags/
+          key: NDK-${{matrix.os}}-gflags-2.2.2-${{matrix.abi}}-${{matrix.build_type}}-${{matrix.lib}}
+
+      - name: Download gflags
+        if: steps.cache-gflags.outputs.cache-hit != 'true'
+        run: |
+          wget https://github.com/gflags/gflags/archive/refs/tags/v2.2.2.zip
+          unzip v2.2.2.zip
+
+      - name: Setup gflags
+        if: steps.cache-gflags.outputs.cache-hit != 'true'
+        run: |
+          cmake -S gflags-2.2.2 -B build-gflags \
+                -DBUILD_SHARED_LIBS=${{matrix.lib == 'shared'}} \
+                -DBUILD_TESTING=OFF \
+                -DCMAKE_ANDROID_API=${{matrix.android_api_level}} \
+                -DCMAKE_ANDROID_ARCH_ABI=${{matrix.abi}} \
+                -DCMAKE_ANDROID_STL_TYPE=c++_shared \
+                -DCMAKE_BUILD_TYPE=${{matrix.build_type}} \
+                -DCMAKE_INSTALL_PREFIX=${{github.workspace}}/gflags \
+                -DCMAKE_SYSTEM_NAME=Android
+          cmake --build build-gflags \
+                --config ${{matrix.build_type}} \
+                --target install
+
+      - name: Cache glog
+        id: cache-glog
+        uses: actions/cache@v4
+        with:
+          path: glog/
+          key: NDK-${{matrix.os}}-glog-0.5-${{matrix.abi}}-${{matrix.build_type}}-${{matrix.lib}}
+
+      - name: Download glog
+        if: steps.cache-glog.outputs.cache-hit != 'true'
+        run: |
+          wget https://github.com/google/glog/archive/refs/tags/v0.5.0.zip
+          unzip v0.5.0.zip
+
+      - name: Setup glog
+        if: steps.cache-glog.outputs.cache-hit != 'true'
+        run: |
+          cmake -S glog-0.5.0 -B build-glog \
+                -DBUILD_SHARED_LIBS=${{matrix.lib == 'shared'}} \
+                -DBUILD_TESTING=OFF \
+                -DCMAKE_ANDROID_API=${{matrix.android_api_level}} \
+                -DCMAKE_ANDROID_ARCH_ABI=${{matrix.abi}} \
+                -DCMAKE_ANDROID_STL_TYPE=c++_shared \
+                -DCMAKE_BUILD_TYPE=${{matrix.build_type}} \
+                -DCMAKE_FIND_ROOT_PATH=${{github.workspace}}/gflags \
+                -DCMAKE_INSTALL_PREFIX=${{github.workspace}}/glog \
+                -DCMAKE_SYSTEM_NAME=Android
+          cmake --build build-glog \
+                --config ${{matrix.build_type}} \
+                --target install
+
+      - name: Cache Build
+        id: cache-build
+        uses: actions/cache@v4
+        with:
+          path: ${{env.CCACHE_DIR}}
+          key: NDK-${{matrix.os}}-ccache-${{matrix.abi}}-${{matrix.build_type}}-${{matrix.lib}}-${{github.run_id}}
+          restore-keys: NDK-${{matrix.os}}-ccache-${{matrix.abi}}-${{matrix.build_type}}-${{matrix.lib}}-
+
+      - name: Setup Environment
+        if: matrix.build_type == 'Release'
+        run: |
+          echo 'CXXFLAGS=-flto' >> $GITHUB_ENV
+
+      - name: Configure
+        run: |
+          cmake -S . -B build_${{matrix.abi}} \
+                -DBUILD_SHARED_LIBS=${{matrix.lib == 'shared'}} \
+                -DCMAKE_ANDROID_API=${{matrix.android_api_level}} \
+                -DCMAKE_ANDROID_ARCH_ABI=${{matrix.abi}} \
+                -DCMAKE_ANDROID_STL_TYPE=c++_shared \
+                -DCMAKE_BUILD_TYPE=${{matrix.build_type}} \
+                -DCMAKE_C_COMPILER_LAUNCHER=$(which ccache) \
+                -DCMAKE_CXX_COMPILER_LAUNCHER=$(which ccache) \
+                -DCMAKE_FIND_ROOT_PATH="${{github.workspace}}/eigen;${{github.workspace}}/gflags;${{github.workspace}}/glog" \
+                -DCMAKE_SYSTEM_NAME=Android
+
+      - name: Build
+        run: |
+          cmake --build build_${{matrix.abi}} \
+                --config ${{matrix.build_type}}
diff --git a/third_party/ceres/.github/workflows/linux.yml b/third_party/ceres/.github/workflows/linux.yml
new file mode 100644
index 0000000..8cd9d8e
--- /dev/null
+++ b/third_party/ceres/.github/workflows/linux.yml
@@ -0,0 +1,122 @@
+name: Linux
+
+on: [push, pull_request]
+
+jobs:
+  build:
+    name: ${{matrix.os}}-${{matrix.build_type}}-${{matrix.lib}}-${{matrix.gpu}}
+    runs-on: ubuntu-latest
+    container: ${{matrix.os}}
+    defaults:
+      run:
+        shell: bash -e -o pipefail {0}
+    env:
+      CCACHE_DIR: ${{github.workspace}}/ccache
+      CMAKE_GENERATOR: Ninja
+      DEBIAN_FRONTEND: noninteractive
+    strategy:
+      fail-fast: true
+      matrix:
+        os:
+          - ubuntu:22.04
+          - ubuntu:24.04
+        build_type:
+          - Release
+        lib:
+          - shared
+          - static
+        gpu:
+          - cuda
+          - no-cuda
+
+    steps:
+      - uses: actions/checkout@v4
+
+      - name: Setup Dependencies
+        run: |
+          apt-get update
+          apt-get install -y \
+            build-essential \
+            ccache \
+            cmake \
+            libbenchmark-dev \
+            libblas-dev \
+            libeigen3-dev \
+            libgflags-dev \
+            libgoogle-glog-dev \
+            liblapack-dev \
+            libmetis-dev \
+            libsuitesparse-dev \
+            ninja-build \
+            wget
+
+      # nvidia cuda toolkit + gcc combo shipped with 22.04LTS is broken
+      # and is not able to compile code that uses thrust
+      # https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1006962
+      - name: Setup CUDA Toolkit Repositories (22.04)
+        if: matrix.gpu == 'cuda' && matrix.os == 'ubuntu:22.04'
+        run: |
+          wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/cuda-keyring_1.0-1_all.deb
+          dpkg -i cuda-keyring_1.0-1_all.deb
+
+      - name: Setup CUDA Toolkit Repositories (24.04)
+        if: matrix.gpu == 'cuda' && matrix.os == 'ubuntu:24.04'
+        run: |
+          wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2404/x86_64/cuda-keyring_1.1-1_all.deb
+          dpkg -i cuda-keyring_1.1-1_all.deb
+
+      - name: Setup CUDA Toolkit (<24.04)
+        if: matrix.gpu == 'cuda' && matrix.os != 'ubuntu:24.04'
+        run: |
+          apt-get update
+          apt-get install -y cuda
+          echo "CUDACXX=/usr/local/cuda/bin/nvcc" >> $GITHUB_ENV
+
+      - name: Setup CUDA Toolkit (>=24.04)
+        if: matrix.gpu == 'cuda' && matrix.os == 'ubuntu:24.04'
+        run: |
+          apt-get update
+          apt-get install -y nvidia-cuda-toolkit
+          echo "CUDACXX=/usr/lib/nvidia-cuda-toolkit/bin/nvcc" >> $GITHUB_ENV
+
+      - name: Cache Build
+        id: cache-build
+        uses: actions/cache@v4
+        with:
+          path: ${{env.CCACHE_DIR}}
+          key: ${{matrix.os}}-ccache-${{matrix.build_type}}-${{matrix.lib}}-${{matrix.gpu}}-${{github.run_id}}
+          restore-keys: ${{matrix.os}}-ccache-${{matrix.build_type}}-${{matrix.lib}}-${{matrix.gpu}}-
+
+      - name: Setup Environment
+        if: matrix.build_type == 'Release'
+        run: |
+          echo 'CXXFLAGS=-flto' >> $GITHUB_ENV
+
+      - name: Configure
+        run: |
+          cmake -S . -B build_${{matrix.build_type}} \
+                -DBUILD_SHARED_LIBS=${{matrix.lib == 'shared'}} \
+                -DUSE_CUDA=${{matrix.gpu == 'cuda'}} \
+                -DCMAKE_BUILD_TYPE=${{matrix.build_type}} \
+                -DCMAKE_C_COMPILER_LAUNCHER=$(which ccache) \
+                -DCMAKE_CXX_COMPILER_LAUNCHER=$(which ccache) \
+                -DCMAKE_INSTALL_PREFIX=${{github.workspace}}/install
+
+      - name: Build
+        run: |
+          cmake --build build_${{matrix.build_type}} \
+                --config ${{matrix.build_type}}
+
+      - name: Test
+        if: matrix.gpu == 'no-cuda'
+        run: |
+          cd build_${{matrix.build_type}}/
+          ctest --config ${{matrix.build_type}} \
+                --output-on-failure \
+                -j$(nproc)
+
+      - name: Install
+        run: |
+          cmake --build build_${{matrix.build_type}}/ \
+                --config ${{matrix.build_type}} \
+                --target install
diff --git a/third_party/ceres/.github/workflows/macos.yml b/third_party/ceres/.github/workflows/macos.yml
new file mode 100644
index 0000000..89c3534
--- /dev/null
+++ b/third_party/ceres/.github/workflows/macos.yml
@@ -0,0 +1,108 @@
+name: macOS
+
+on: [push, pull_request]
+
+jobs:
+  build:
+    name: ${{matrix.os}}-${{matrix.build_type}}-${{matrix.lib}}-${{matrix.target}}
+    runs-on: ${{matrix.os}}
+    defaults:
+      run:
+        shell: bash -e -o pipefail {0}
+    env:
+      CCACHE_DIR: ${{github.workspace}}/ccache
+      CMAKE_GENERATOR: Ninja
+    strategy:
+      fail-fast: true
+      matrix:
+        os:
+          - macos-12
+          - macos-13
+          - macos-14
+        build_type:
+          - Release
+        lib:
+          - shared
+          - static
+        target:
+          - host
+          - ios
+
+    steps:
+      - uses: actions/checkout@v4
+
+      - name: Setup Dependencies (iOS)
+        if: matrix.target == 'ios'
+        run: |
+          brew install \
+            ccache \
+            eigen \
+            ninja
+
+      - name: Setup Dependencies (Host)
+        if: matrix.target == 'host'
+        run: |
+          brew install \
+            ccache \
+            eigen \
+            gflags \
+            glog \
+            google-benchmark \
+            metis \
+            ninja \
+            suite-sparse
+
+      - name: Cache Build
+        id: cache-build
+        uses: actions/cache@v4
+        with:
+          path: ${{env.CCACHE_DIR}}
+          key: ${{matrix.os}}-ccache-${{matrix.build_type}}-${{matrix.lib}}-${{matrix.target}}-${{github.run_id}}
+          restore-keys: ${{matrix.os}}-ccache-${{matrix.build_type}}-${{matrix.lib}}-${{matrix.target}}-
+
+      - name: Setup Environment
+        if: matrix.build_type == 'Release'
+        run: |
+          echo 'CXXFLAGS=-flto' >> $GITHUB_ENV
+
+      - name: Configure (iOS)
+        if: matrix.target == 'ios'
+        run: |
+          cmake -S . -B build_${{matrix.build_type}} \
+                -DBUILD_SHARED_LIBS=${{matrix.lib == 'shared'}} \
+                -DCMAKE_BUILD_TYPE=${{matrix.build_type}} \
+                -DCMAKE_C_COMPILER_LAUNCHER=$(which ccache) \
+                -DCMAKE_CXX_COMPILER_LAUNCHER=$(which ccache) \
+                -DCMAKE_TOOLCHAIN_FILE=${{github.workspace}}/cmake/iOS.cmake \
+                -DEigen3_DIR=$(brew --prefix)/share/eigen3/cmake \
+                -DIOS_PLATFORM=OS \
+                -DCMAKE_INSTALL_PREFIX=${{github.workspace}}/install
+
+      - name: Configure (Host)
+        if: matrix.target == 'host'
+        run: |
+          cmake -S . -B build_${{matrix.build_type}} \
+                -DBUILD_SHARED_LIBS=${{matrix.lib == 'shared'}} \
+                -DCMAKE_BUILD_TYPE=${{matrix.build_type}} \
+                -DCMAKE_C_COMPILER_LAUNCHER=$(which ccache) \
+                -DCMAKE_CXX_COMPILER_LAUNCHER=$(which ccache) \
+                -DCMAKE_INSTALL_PREFIX=${{github.workspace}}/install
+
+      - name: Build
+        run: |
+          cmake --build build_${{matrix.build_type}} \
+                --config ${{matrix.build_type}}
+
+      - name: Test
+        if: matrix.target == 'host'
+        run: |
+          ctest --test-dir build_${{matrix.build_type}} \
+                --config ${{matrix.build_type}} \
+                --output-on-failure \
+                -j$(sysctl -n hw.ncpu)
+
+      - name: Install
+        run: |
+          cmake --build build_${{matrix.build_type}}/ \
+                --config ${{matrix.build_type}} \
+                --target install
diff --git a/third_party/ceres/.github/workflows/windows.yml b/third_party/ceres/.github/workflows/windows.yml
new file mode 100644
index 0000000..c340f9f
--- /dev/null
+++ b/third_party/ceres/.github/workflows/windows.yml
@@ -0,0 +1,259 @@
+name: Windows
+
+on: [push, pull_request]
+
+jobs:
+  build-mingw:
+    name: ${{matrix.sys}}-${{matrix.env}}-${{matrix.build_type}}-${{matrix.lib}}
+    runs-on: windows-latest
+    defaults:
+      run:
+        shell: msys2 {0}
+    env:
+      CCACHE_DIR: ${{github.workspace}}/ccache
+    strategy:
+      fail-fast: true
+      matrix:
+        build_type: [Release]
+        sys: [mingw64]
+        lib: [shared, static]
+        include:
+          - sys: mingw64
+            env: x86_64
+
+    steps:
+    - uses: actions/checkout@v4
+
+    - name: Setup Dependencies
+      uses: msys2/setup-msys2@v2
+      with:
+        msystem: ${{matrix.sys}}
+        install: >-
+          mingw-w64-${{matrix.env}}-ccache
+          mingw-w64-${{matrix.env}}-cmake
+          mingw-w64-${{matrix.env}}-eigen3
+          mingw-w64-${{matrix.env}}-gcc
+          mingw-w64-${{matrix.env}}-gflags
+          mingw-w64-${{matrix.env}}-glog
+          ${{matrix.sys == 'mingw64' && format('mingw-w64-{0}-metis', matrix.env) || ''}}
+          mingw-w64-${{matrix.env}}-ninja
+          mingw-w64-${{matrix.env}}-suitesparse
+
+    - name: Setup Environment
+      if: ${{matrix.build_type == 'Release'}}
+      run: |
+        echo 'CFLAGS=-flto' >> ~/.bash_profile
+        echo 'CXXFLAGS=-flto' >> ~/.bash_profile
+
+    - name: Cache Build
+      id: cache-build
+      uses: actions/cache@v4
+      with:
+        path: ${{env.CCACHE_DIR}}
+        key: ${{runner.os}}-${{matrix.sys}}-${{matrix.env}}-${{matrix.build_type}}-${{matrix.lib}}-ccache-${{github.run_id}}
+        restore-keys: ${{runner.os}}-${{matrix.sys}}-${{matrix.env}}-${{matrix.build_type}}-${{matrix.lib}}-ccache-
+
+    - name: Configure
+      run: |
+        cmake -S . -B build_${{matrix.build_type}}/ \
+              -DBUILD_SHARED_LIBS=${{matrix.lib == 'shared'}} \
+              -DCMAKE_BUILD_TYPE=${{matrix.build_type}} \
+              -DCMAKE_C_COMPILER_LAUNCHER:FILEPATH=ccache \
+              -DCMAKE_CXX_COMPILER_LAUNCHER:FILEPATH=ccache \
+              -G Ninja
+
+    - name: Build
+      run: |
+        cmake --build build_${{matrix.build_type}}/ \
+              --config ${{matrix.build_type}}
+
+    - name: Test
+      run: |
+        cd build_${{matrix.build_type}}/
+        ctest --config ${{matrix.build_type}} \
+              --output-on-failure \
+              -j$(nproc)
+
+    - name: Install
+      run: |
+        cmake --build build_${{matrix.build_type}}/ \
+              --config ${{matrix.build_type}} \
+              --target install
+
+  build-msvc:
+    name: ${{matrix.msvc}}-${{matrix.arch}}-${{matrix.build_type}}-${{matrix.lib}}-${{matrix.gpu}}
+    runs-on: ${{matrix.os}}
+    defaults:
+      run:
+        shell: powershell
+    env:
+      CL: /MP
+      CMAKE_GENERATOR: ${{matrix.generator}}
+      CMAKE_GENERATOR_PLATFORM: ${{matrix.arch}}
+    strategy:
+      fail-fast: true
+      matrix:
+        arch:
+          - x64
+        build_type:
+          - Release
+        msvc:
+          - VS-16-2019
+          - VS-17-2022
+        lib:
+          - shared
+        gpu:
+          - cuda
+          - no-cuda
+        include:
+          - msvc: VS-16-2019
+            os: windows-2019
+            generator: 'Visual Studio 16 2019'
+            marker: vc16
+          - msvc: VS-17-2022
+            os: windows-2022
+            generator: 'Visual Studio 17 2022'
+            marker: vc17
+
+    steps:
+      - uses: actions/checkout@v4
+
+      - name: Download and install CUDA toolkit
+        if: matrix.gpu == 'cuda'
+        run: |
+          Invoke-WebRequest https://developer.download.nvidia.com/compute/cuda/12.2.1/network_installers/cuda_12.2.1_windows_network.exe -OutFile cuda_toolkit_windows.exe
+          Start-Process -Wait -FilePath .\cuda_toolkit_windows.exe -ArgumentList "-s cusolver_dev_12.2 cusparse_dev_12.2 cublas_dev_12.2 thrust_12.2 nvcc_12.2 cudart_12.2 nvrtc_dev_12.2 visual_studio_integration_12.2"
+          Remove-Item .\cuda_toolkit_windows.exe
+          $CUDA_PATH = "C:/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v12.2"
+          echo "CUDA_PATH=$CUDA_PATH" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
+          echo "CUDA_PATH_V12_2=$CUDA_PATH" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
+          echo "$CUDA_PATH/bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
+
+      - name: Cache gflags
+        id: cache-gflags
+        uses: actions/cache@v4
+        with:
+          path: gflags/
+          key: ${{matrix.msvc}}-gflags-2.2.2-${{matrix.arch}}-${{matrix.build_type}}-${{matrix.lib}}
+
+      - name: Download gflags
+        if: steps.cache-gflags.outputs.cache-hit != 'true'
+        run: |
+          (New-Object System.Net.WebClient).DownloadFile("https://github.com/gflags/gflags/archive/refs/tags/v2.2.2.zip", "v2.2.2.zip");
+          Expand-Archive -Path v2.2.2.zip -DestinationPath .;
+
+      - name: Setup gflags
+        if: steps.cache-gflags.outputs.cache-hit != 'true'
+        run: |
+          cmake -S gflags-2.2.2 -B build-gflags `
+                -DBUILD_SHARED_LIBS=${{matrix.lib == 'shared'}} `
+                -DBUILD_TESTING=OFF `
+                -DCMAKE_INSTALL_PREFIX=${{github.workspace}}/gflags
+          cmake --build build-gflags `
+                --config ${{matrix.build_type}} `
+                --target install
+
+      - name: Cache glog
+        id: cache-glog
+        uses: actions/cache@v4
+        with:
+          path: glog/
+          key: ${{matrix.msvc}}-glog-0.6.0-${{matrix.arch}}-${{matrix.build_type}}-${{matrix.lib}}
+
+      - name: Download glog
+        if: steps.cache-glog.outputs.cache-hit != 'true'
+        run: |
+          (New-Object System.Net.WebClient).DownloadFile("https://github.com/google/glog/archive/refs/tags/v0.6.0.zip", "v0.6.0.zip");
+          Expand-Archive -Path v0.6.0.zip -DestinationPath .;
+
+      - name: Setup glog
+        if: steps.cache-glog.outputs.cache-hit != 'true'
+        run: |
+          cmake -S glog-0.6.0 -B build-glog `
+                -DBUILD_SHARED_LIBS=${{matrix.lib == 'shared'}} `
+                -DBUILD_TESTING=OFF `
+                -DCMAKE_INSTALL_PREFIX=${{github.workspace}}/glog `
+                -DCMAKE_PREFIX_PATH=${{github.workspace}}/gflags
+          cmake --build build-glog `
+                --config ${{matrix.build_type}} `
+                --target install
+
+      - name: Cache SuiteSparse
+        id: cache-suitesparse
+        uses: actions/cache@v4
+        with:
+          path: suitesparse/
+          key: ${{matrix.msvc}}-suitesparse-5.13.0-cmake.3-${{matrix.arch}}-${{matrix.build_type}}-${{matrix.lib}}
+
+      - name: Download SuiteSparse
+        if: steps.cache-suitesparse.outputs.cache-hit != 'true'
+        run: |
+          (New-Object System.Net.WebClient).DownloadFile("https://github.com/sergiud/SuiteSparse/releases/download/5.13.0-cmake.3/SuiteSparse-5.13.0-cmake.3-${{matrix.marker}}-Win64-${{matrix.build_type}}-${{matrix.lib}}-gpl-metis.zip", "suitesparse.zip");
+          Expand-Archive -Path suitesparse.zip -DestinationPath ${{github.workspace}}/suitesparse;
+
+      - name: Cache Eigen
+        id: cache-eigen
+        uses: actions/cache@v4
+        with:
+          path: eigen/
+          key: ${{runner.os}}-eigen-3.4.0
+
+      - name: Download Eigen
+        if: steps.cache-eigen.outputs.cache-hit != 'true'
+        run: |
+          (New-Object System.Net.WebClient).DownloadFile("https://gitlab.com/libeigen/eigen/-/archive/3.4.0/eigen-3.4.0.zip", "eigen-3.4.0.zip");
+          Expand-Archive -Path eigen-3.4.0.zip -DestinationPath .;
+
+      - name: Setup Eigen
+        if: steps.cache-eigen.outputs.cache-hit != 'true'
+        run: |
+          cmake -S eigen-3.4.0 -B build-eigen `
+                -DBUILD_TESTING=OFF `
+                -DCMAKE_Fortran_COMPILER= `
+                -DCMAKE_INSTALL_PREFIX=${{github.workspace}}/eigen `
+                -DEIGEN_BUILD_DOC=OFF
+          cmake --build build-eigen `
+                --config ${{matrix.build_type}} `
+                --target install
+
+      - name: Setup Build Environment
+        run: |
+          echo "Eigen3_ROOT=${{github.workspace}}/eigen" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
+          echo "gflags_ROOT=${{github.workspace}}/gflags" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
+          echo "glog_ROOT=${{github.workspace}}/glog" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
+          echo "CMAKE_PREFIX_PATH=${{github.workspace}}/suitesparse" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
+
+      - name: Setup Runtime Environment
+        run: |
+          echo '${{github.workspace}}\gflags\bin' | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
+          echo '${{github.workspace}}\glog\bin' | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
+          echo '${{github.workspace}}\suitesparse\bin' | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
+
+      - name: Configure
+        run: |
+          cmake -S . -B build_${{matrix.build_type}}/ `
+                -DBLAS_blas_LIBRARY=${{github.workspace}}/suitesparse/lib/libblas.lib `
+                -DBUILD_SHARED_LIBS=${{matrix.lib == 'shared'}} `
+                -DCMAKE_CONFIGURATION_TYPES=${{matrix.build_type}} `
+                -DCMAKE_INSTALL_PREFIX:PATH=${{github.workspace}}/install `
+                -DLAPACK_lapack_LIBRARY=${{github.workspace}}/suitesparse/lib/liblapack.lib
+
+      - name: Build
+        run: |
+          cmake --build build_${{matrix.build_type}}/ `
+                --config ${{matrix.build_type}}
+
+      - name: Test
+        if: matrix.gpu == 'no-cuda'
+        env:
+          CTEST_OUTPUT_ON_FAILURE: 1
+        run: |
+          cmake --build build_${{matrix.build_type}}/ `
+                --config ${{matrix.build_type}} `
+                --target RUN_TESTS
+
+      - name: Install
+        run: |
+          cmake --build build_${{matrix.build_type}}/ `
+                --config ${{matrix.build_type}} `
+                --target INSTALL
diff --git a/third_party/ceres/.gitignore b/third_party/ceres/.gitignore
index f6aae3f..ca55495 100644
--- a/third_party/ceres/.gitignore
+++ b/third_party/ceres/.gitignore
@@ -23,3 +23,7 @@
 .buildinfo
 bazel-*
 *.pyc
+.idea*
+
+cmake-build*
+small-blas-benchmarks
\ No newline at end of file
diff --git a/third_party/ceres/.travis.yml b/third_party/ceres/.travis.yml
deleted file mode 100644
index 3e109b5..0000000
--- a/third_party/ceres/.travis.yml
+++ /dev/null
@@ -1,70 +0,0 @@
-language: cpp
-
-matrix:
-  fast_finish: true
-  include:
-  - os: linux
-    dist: bionic
-    sudo: required
-    compiler: gcc
-    env: CERES_BUILD_TARGET=LINUX
-  - os: linux
-    dist: bionic
-    sudo: required
-    compiler: gcc
-    env: CERES_BUILD_TARGET=ANDROID
-  - os: osx
-    osx_image: xcode11.2
-    env: CERES_BUILD_TARGET=OSX
-  - os: osx
-    osx_image: xcode11.2
-    env: CERES_BUILD_TARGET=IOS
-
-env:
-  # As per http://docs.travis-ci.com/user/languages/cpp/#OpenMP-projects don't be greedy with OpenMP.
-  - OMP_NUM_THREADS=4
-
-before_install:
-  - if [ $TRAVIS_OS_NAME = linux ]; then sudo apt-get update -qq; fi
-  - |
-    if [[ "$CERES_BUILD_TARGET" == "ANDROID" ]]; then
-      cd /tmp
-      wget https://dl.google.com/android/repository/android-ndk-r20b-linux-x86_64.zip
-      unzip -qq android-ndk-r20b-linux-x86_64.zip
-    fi
-
-install:
-  - if [ $TRAVIS_OS_NAME = linux ]; then $TRAVIS_BUILD_DIR/travis/install_travis_linux_deps.sh; fi
-  - if [ $TRAVIS_OS_NAME = osx ]; then $TRAVIS_BUILD_DIR/travis/install_travis_osx_deps.sh; fi
-
-before_script:
-  - mkdir /tmp/ceres-build
-  - cd /tmp/ceres-build
-
-script:
-  # NOTE: TRAVIS_BUILD_DIR is actually the source directory for Ceres.
-  - |
-    if [[ "$CERES_BUILD_TARGET" == "LINUX" || "$CERES_BUILD_TARGET" == "OSX" ]]; then
-      cmake $TRAVIS_BUILD_DIR
-    fi
-  - |
-    if [[ "$CERES_BUILD_TARGET" == "ANDROID" ]]; then
-      cmake -DCMAKE_TOOLCHAIN_FILE=/tmp/android-ndk-r20b/build/cmake/android.toolchain.cmake -DEigen3_DIR=/usr/lib/cmake/eigen3 -DANDROID_ABI=arm64-v8a -DANDROID_STL=c++_shared -DANDROID_NATIVE_API_LEVEL=android-29 -DMINIGLOG=ON -DBUILD_EXAMPLES=OFF $TRAVIS_BUILD_DIR
-    fi
-  - |
-    if [[ "$CERES_BUILD_TARGET" == "IOS" ]]; then
-      cmake -DCMAKE_TOOLCHAIN_FILE=$TRAVIS_BUILD_DIR/cmake/iOS.cmake -DEigen3_DIR=/usr/local/share/eigen3/cmake -DIOS_PLATFORM=OS $TRAVIS_BUILD_DIR
-    fi
-  - make -j 4
-  - |
-    if [[ "$CERES_BUILD_TARGET" == "LINUX" || "$CERES_BUILD_TARGET" == "OSX" ]]; then
-      sudo make install
-      ctest --output-on-failure -j 4
-    fi
-
-notifications:
-  email:
-    - alexs.mac@gmail.com
-    - sandwichmaker@gmail.com
-    - keir@google.com
-    - wjr@google.com
diff --git a/third_party/ceres/BUILD b/third_party/ceres/BUILD
index cb25844..eba1473 100644
--- a/third_party/ceres/BUILD
+++ b/third_party/ceres/BUILD
@@ -1,5 +1,5 @@
 # Ceres Solver - A fast non-linear least squares minimizer
-# Copyright 2018 Google Inc. All rights reserved.
+# Copyright 2023 Google Inc. All rights reserved.
 # http://ceres-solver.org/
 #
 # Redistribution and use in source and binary forms, with or without
@@ -74,7 +74,7 @@
 CERES_TESTS = [
     "array_utils",
     "autodiff_cost_function",
-    "autodiff_local_parameterization",
+    "autodiff_manifold",
     "autodiff",
     "block_jacobi_preconditioner",
     "block_random_access_dense_matrix",
@@ -92,6 +92,7 @@
     "cost_function_to_functor",
     "covariance",
     "cubic_interpolation",
+    "dense_cholesky",
     "dense_linear_solver",
     "dense_sparse_matrix",
     "detect_structure",
@@ -120,7 +121,6 @@
     "levenberg_marquardt_strategy",
     "line_search_minimizer",
     "line_search_preprocessor",
-    "local_parameterization",
     "loss_function",
     "minimizer",
     "normal_prior",
@@ -197,7 +197,7 @@
 # dependency that we'd prefer to avoid.
 [cc_test(
     name = test_filename.split("/")[-1][:-3],  # Remove .cc.
-    timeout = "moderate",
+    timeout = "long",
     srcs = [test_filename],
     copts = TEST_COPTS,
 
diff --git a/third_party/ceres/CITATION.cff b/third_party/ceres/CITATION.cff
new file mode 100644
index 0000000..08848f8
--- /dev/null
+++ b/third_party/ceres/CITATION.cff
@@ -0,0 +1,15 @@
+cff-version: 1.2.0
+message: If you use Ceres Solver for a publication, please cite it as below.
+title: Ceres Solver
+abstract: A large scale non-linear optimization library
+authors:
+- family-names: Agarwal
+  given-names: Sameer
+- family-names: Mierle
+  given-names: Keir
+- name: The Ceres Solver Team
+version: 2.2
+date-released: 2023-10-13
+license: Apache-2.0
+repository-code: https://github.com/ceres-solver/ceres-solver
+url: http://ceres-solver.org
diff --git a/third_party/ceres/CMakeLists.txt b/third_party/ceres/CMakeLists.txt
index ea7e9b8..6cbc942 100644
--- a/third_party/ceres/CMakeLists.txt
+++ b/third_party/ceres/CMakeLists.txt
@@ -1,5 +1,5 @@
 # Ceres Solver - A fast non-linear least squares minimizer
-# Copyright 2015 Google Inc. All rights reserved.
+# Copyright 2024 Google Inc. All rights reserved.
 # http://ceres-solver.org/
 #
 # Redistribution and use in source and binary forms, with or without
@@ -29,69 +29,24 @@
 # Authors: keir@google.com (Keir Mierle)
 #          alexs.mac@gmail.com (Alex Stewart)
 
-cmake_minimum_required(VERSION 3.5)
-cmake_policy(VERSION 3.5)
-if (POLICY CMP0074)
-  # FindTBB.cmake uses TBB_ROOT in a way that is historical, but also compliant
-  # with CMP0074 so suppress the legacy compatibility warning and allow its use.
-  cmake_policy(SET CMP0074 NEW)
-endif()
-
-# Set the C++ version (must be >= C++14) when compiling Ceres.
-#
-# Reflect a user-specified (via -D) CMAKE_CXX_STANDARD if present, otherwise
-# default to C++14.
-set(DEFAULT_CXX_STANDARD ${CMAKE_CXX_STANDARD})
-if (NOT DEFAULT_CXX_STANDARD)
-  set(DEFAULT_CXX_STANDARD 14)
-endif()
-set(CMAKE_CXX_STANDARD ${DEFAULT_CXX_STANDARD} CACHE STRING
-  "C++ standard (minimum 14)" FORCE)
-# Restrict CMAKE_CXX_STANDARD to the valid versions permitted and ensure that
-# if one was forced via -D that it is in the valid set.
-set(ALLOWED_CXX_STANDARDS 14 17 20)
-set_property(CACHE CMAKE_CXX_STANDARD PROPERTY STRINGS ${ALLOWED_CXX_STANDARDS})
-list(FIND ALLOWED_CXX_STANDARDS ${CMAKE_CXX_STANDARD} POSITION)
-if (POSITION LESS 0)
-  message(FATAL_ERROR "Invalid CMAKE_CXX_STANDARD: ${CMAKE_CXX_STANDARD}. "
-    "Must be one of: ${ALLOWED_CXX_STANDARDS}")
-endif()
-# Specify the standard as a hard requirement, otherwise CMAKE_CXX_STANDARD is
-# interpreted as a suggestion that can decay *back* to lower versions.
-set(CMAKE_CXX_STANDARD_REQUIRED ON CACHE BOOL "")
-mark_as_advanced(CMAKE_CXX_STANDARD_REQUIRED)
-
-# MSVC versions < 2015 did not fully support >= C++14, and technically even
-# 2015 did not support a couple of smaller features
-if (CMAKE_CXX_COMPILER_ID MATCHES MSVC AND
-    CMAKE_CXX_COMPILER_VERSION VERSION_LESS 14.0)
-  message(FATAL_ERROR "Invalid CMAKE_CXX_COMPILER_VERSION: "
-    "${CMAKE_CXX_COMPILER_VERSION}. Ceres requires at least MSVC 2015 for "
-    "C++14 support.")
-endif()
-
-# On macOS, add the Homebrew prefix (with appropriate suffixes) to the
-# respective HINTS directories (after any user-specified locations).  This
-# handles Homebrew installations into non-standard locations (not /usr/local).
-# We do not use CMAKE_PREFIX_PATH for this as given the search ordering of
-# find_xxx(), doing so would override any user-specified HINTS locations with
-# the Homebrew version if it exists.
-if (CMAKE_SYSTEM_NAME MATCHES "Darwin")
-  find_program(HOMEBREW_EXECUTABLE brew)
-  mark_as_advanced(FORCE HOMEBREW_EXECUTABLE)
-  if (HOMEBREW_EXECUTABLE)
-    # Detected a Homebrew install, query for its install prefix.
-    execute_process(COMMAND ${HOMEBREW_EXECUTABLE} --prefix
-      OUTPUT_VARIABLE HOMEBREW_INSTALL_PREFIX
-      OUTPUT_STRIP_TRAILING_WHITESPACE)
-    message(STATUS "Detected Homebrew with install prefix: "
-      "${HOMEBREW_INSTALL_PREFIX}, adding to CMake search paths.")
-    list(APPEND CMAKE_PREFIX_PATH "${HOMEBREW_INSTALL_PREFIX}")
-  endif()
-endif()
-
+cmake_minimum_required(VERSION 3.16...3.29)
 project(Ceres C CXX)
 
+# NOTE: The following CMake variables must be applied consistently to all
+# targets in project to avoid visibility warnings by placing the variables at
+# the project top.
+
+# Always build position-independent code (PIC), even when building Ceres as a
+# static library so that shared libraries can link against it, not just
+# executables (PIC does not apply on Windows). Global variable can be overridden
+# by the user whereas target properties can be not.
+set(CMAKE_POSITION_INDEPENDENT_CODE ON)
+# Set the default symbol visibility to hidden to unify the behavior among
+# the various compilers and to get smaller binaries
+set(CMAKE_C_VISIBILITY_PRESET hidden)
+set(CMAKE_CXX_VISIBILITY_PRESET hidden)
+set(CMAKE_VISIBILITY_INLINES_HIDDEN ON)
+
 # NOTE: The 'generic' CMake variables CMAKE_[SOURCE/BINARY]_DIR should not be
 #       used.  Always use the project-specific variants (generated by CMake):
 #       <PROJECT_NAME_MATCHING_CASE>_[SOURCE/BINARY]_DIR, e.g.
@@ -106,8 +61,14 @@
 # additional paths via -D.
 list(APPEND CMAKE_MODULE_PATH "${Ceres_SOURCE_DIR}/cmake")
 include(AddCompileFlagsIfSupported)
+include(CheckCXXCompilerFlag)
+include(CheckLibraryExists)
+include(GNUInstallDirs)
 include(UpdateCacheVariable)
 
+check_cxx_compiler_flag(/bigobj HAVE_BIGOBJ)
+check_library_exists(m pow "" HAVE_LIBM)
+
 # Xcode 11.0-1 with macOS 10.15 (Catalina) broke alignment.
 include(DetectBrokenStackCheckMacOSXcodePairing)
 detect_broken_stack_check_macos_xcode_pairing()
@@ -130,30 +91,21 @@
 
 enable_testing()
 
-include(CeresThreadingModels)
+include(CMakeDependentOption)
 include(PrettyPrintCMakeList)
-find_available_ceres_threading_models(CERES_THREADING_MODELS_AVAILABLE)
-pretty_print_cmake_list(PRETTY_CERES_THREADING_MODELS_AVAILABLE
-  ${CERES_THREADING_MODELS_AVAILABLE})
-message("-- Detected available Ceres threading models: "
-  "${PRETTY_CERES_THREADING_MODELS_AVAILABLE}")
-set(CERES_THREADING_MODEL "${CERES_THREADING_MODEL}" CACHE STRING
-  "Ceres threading back-end" FORCE)
-if (NOT CERES_THREADING_MODEL)
-  list(GET CERES_THREADING_MODELS_AVAILABLE 0 DEFAULT_THREADING_MODEL)
-  update_cache_variable(CERES_THREADING_MODEL ${DEFAULT_THREADING_MODEL})
-endif()
-set_property(CACHE CERES_THREADING_MODEL PROPERTY STRINGS
-  ${CERES_THREADING_MODELS_AVAILABLE})
 
 option(MINIGLOG "Use a stripped down version of glog." OFF)
 option(GFLAGS "Enable Google Flags." ON)
 option(SUITESPARSE "Enable SuiteSparse." ON)
-option(CXSPARSE "Enable CXSparse." ON)
 if (APPLE)
   option(ACCELERATESPARSE
     "Enable use of sparse solvers in Apple's Accelerate framework." ON)
+  option(ENABLE_BITCODE
+    "Enable bitcode for iOS builds (disables inline optimizations for Eigen)." OFF)
 endif()
+# We can't have an option called 'CUDA' since that is a reserved word -- a
+# language definition.
+set(USE_CUDA "default" CACHE STRING "Enable use of CUDA linear algebra solvers.")
 option(LAPACK "Enable use of LAPACK directly within Ceres." ON)
 # Template specializations for the Schur complement based solvers. If
 # compile time, binary size or compiler performance is an issue, you
@@ -165,6 +117,7 @@
 # Enable the use of Eigen as a sparse linear algebra library for
 # solving the nonlinear least squares problems.
 option(EIGENSPARSE "Enable Eigen as a sparse linear algebra library." ON)
+cmake_dependent_option(EIGENMETIS "Enable Eigen METIS support." ON EIGENSPARSE OFF)
 option(EXPORT_BUILD_DIR
   "Export build directory using CMake (enables external use without install)." OFF)
 option(BUILD_TESTING "Enable tests" ON)
@@ -179,35 +132,6 @@
 if (ANDROID)
   option(ANDROID_STRIP_DEBUG_SYMBOLS "Strip debug symbols from Android builds (reduces file sizes)" ON)
 endif()
-if (MSVC)
-  option(MSVC_USE_STATIC_CRT
-    "MS Visual Studio: Use static C-Run Time Library in place of shared." OFF)
-endif()
-
-# Allow user to specify a suffix for the library install directory, the only
-# really sensible option (other than "") being "64", such that:
-# ${CMAKE_INSTALL_PREFIX}/lib -> ${CMAKE_INSTALL_PREFIX}/lib64.
-#
-# Heuristic for determining LIB_SUFFIX. FHS recommends that 64-bit systems
-# install native libraries to lib64 rather than lib. Most distros seem to
-# follow this convention with a couple notable exceptions (Debian-based and
-# Arch-based distros) which we try to detect here.
-if (CMAKE_SYSTEM_NAME MATCHES "Linux" AND
-    NOT DEFINED LIB_SUFFIX AND
-    NOT CMAKE_CROSSCOMPILING AND
-    CMAKE_SIZEOF_VOID_P EQUAL "8" AND
-    NOT EXISTS "/etc/debian_version" AND
-    NOT EXISTS "/etc/arch-release")
-  message("-- Detected non-Debian/Arch-based 64-bit Linux distribution. "
-    "Defaulting to library install directory: lib${LIB_SUFFIX}. You can "
-    "override this by specifying LIB_SUFFIX.")
-  set(LIB_SUFFIX "64")
-endif ()
-# Only create the cache variable (for the CMake GUI) after attempting to detect
-# the suffix *if not specified by the user* (NOT DEFINED LIB_SUFFIX in if())
-# s/t the user could override our autodetected suffix with "" if desired.
-set(LIB_SUFFIX "${LIB_SUFFIX}" CACHE STRING
-  "Suffix of library install directory (to support lib/lib64)." FORCE)
 
 # IOS is defined iff using the iOS.cmake CMake toolchain to build a static
 # library for iOS.
@@ -226,27 +150,26 @@
   # Apple claims that the BLAS call dsyrk_ is a private API, and will not allow
   # you to submit to the Apple Store if the symbol is present.
   update_cache_variable(LAPACK OFF)
-  message(STATUS "Building for iOS: SuiteSparse, CXSparse, LAPACK, gflags, "
-    "and OpenMP are not available.")
+  message(STATUS "Building for iOS: SuiteSparse, LAPACK, gflags "
+    "are not available.")
 
   update_cache_variable(BUILD_EXAMPLES OFF)
   message(STATUS "Building for iOS: Will not build examples.")
 endif (IOS)
 
 unset(CERES_COMPILE_OPTIONS)
-message("-- Building with C++${CMAKE_CXX_STANDARD}")
 
 # Eigen.
 # Eigen delivers Eigen3Config.cmake since v3.3.3
 find_package(Eigen3 3.3 REQUIRED)
-if (EIGEN3_FOUND)
-  message("-- Found Eigen version ${EIGEN3_VERSION_STRING}: ${EIGEN3_INCLUDE_DIRS}")
+if (Eigen3_FOUND)
+  message("-- Found Eigen version ${Eigen3_VERSION}: ${Eigen3_DIR}")
   if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64.*|AARCH64.*)" AND
-      EIGEN3_VERSION_STRING VERSION_LESS 3.3.4)
+      Eigen3_VERSION VERSION_LESS 3.3.4)
     # As per issue #289: https://github.com/ceres-solver/ceres-solver/issues/289
     # the bundle_adjustment_test will fail for Eigen < 3.3.4 on aarch64.
     message(FATAL_ERROR "-- Ceres requires Eigen version >= 3.3.4 on aarch64. "
-      "Detected version of Eigen is: ${EIGEN3_VERSION_STRING}.")
+      "Detected version of Eigen is: ${Eigen3_VERSION}.")
   endif()
 
   if (EIGENSPARSE)
@@ -258,7 +181,109 @@
     message("   which can still use the EIGEN_SPARSE_QR algorithm.")
     add_definitions(-DEIGEN_MPL2_ONLY)
   endif (EIGENSPARSE)
-endif (EIGEN3_FOUND)
+endif (Eigen3_FOUND)
+
+if (CMAKE_VERSION VERSION_LESS 3.17)
+  set_property(CACHE USE_CUDA PROPERTY STRINGS OFF default)
+else (CMAKE_VERSION VERSION_LESS 3.17)
+  set_property(CACHE USE_CUDA PROPERTY STRINGS OFF default static)
+endif (CMAKE_VERSION VERSION_LESS 3.17)
+
+if (USE_CUDA)
+  if (CMAKE_VERSION VERSION_LESS 3.17)
+    # On older versions of CMake (20.04 default is 3.16) FindCUDAToolkit was
+    # not available, but FindCUDA was deprecated. To avoid special-case handling
+    # elsewhere, emulate the effects of FindCUDAToolkit locally in terms of the
+    # expected CMake imported targets and defined variables. This can be removed
+    # from as soon as the min CMake version is >= 3.17.
+    find_package(CUDA QUIET)
+    if (CUDA_FOUND)
+      message("-- Found CUDA version ${CUDA_VERSION} installed in: "
+        "${CUDA_TOOLKIT_ROOT_DIR} via legacy (< 3.17) CMake module. "
+        "Using the legacy CMake module means that any installation of "
+        "Ceres will require that the CUDA libraries be installed in a "
+        "location included in the LD_LIBRARY_PATH.")
+      enable_language(CUDA)
+
+      macro(DECLARE_IMPORTED_CUDA_TARGET COMPONENT)
+        add_library(CUDA::${COMPONENT} INTERFACE IMPORTED)
+        target_include_directories(
+          CUDA::${COMPONENT} INTERFACE ${CUDA_INCLUDE_DIRS})
+        target_link_libraries(
+          CUDA::${COMPONENT} INTERFACE ${CUDA_${COMPONENT}_LIBRARY} ${ARGN})
+      endmacro()
+
+      declare_imported_cuda_target(cublas)
+      declare_imported_cuda_target(cusolver)
+      declare_imported_cuda_target(cusparse)
+      declare_imported_cuda_target(cudart ${CUDA_LIBRARIES})
+
+      set(CERES_CUDA_TARGET_SUFFIX "")
+      set(CUDAToolkit_BIN_DIR ${CUDA_TOOLKIT_ROOT_DIR}/bin)
+
+    else (CUDA_FOUND)
+      message("-- Did not find CUDA, disabling CUDA support.")
+      update_cache_variable(USE_CUDA OFF)
+    endif (CUDA_FOUND)
+  else (CMAKE_VERSION VERSION_LESS 3.17)
+    find_package(CUDAToolkit QUIET)
+    if (CUDAToolkit_FOUND)
+      message("-- Found CUDA version ${CUDAToolkit_VERSION} installed in: "
+        "${CUDAToolkit_TARGET_DIR}")
+      set(CUDAToolkit_DEPENDENCY
+        "find_dependency(CUDAToolkit ${CUDAToolkit_VERSION})")
+      enable_language(CUDA)
+      if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.18")
+        # Support Maxwell GPUs (Default).
+        set(CMAKE_CUDA_ARCHITECTURES "50")
+        # Support other architectures depending on CUDA toolkit version.
+        if (CUDAToolkit_VERSION VERSION_GREATER_EQUAL "8.0")
+          # Support Pascal GPUs.
+          list(APPEND CMAKE_CUDA_ARCHITECTURES "60")
+        endif(CUDAToolkit_VERSION VERSION_GREATER_EQUAL "8.0")
+        if (CUDAToolkit_VERSION VERSION_GREATER_EQUAL "9.0")
+          # Support Volta GPUs.
+          list(APPEND CMAKE_CUDA_ARCHITECTURES "70")
+        endif(CUDAToolkit_VERSION VERSION_GREATER_EQUAL "9.0")
+        if (CUDAToolkit_VERSION VERSION_GREATER_EQUAL "10.0")
+          # Support Turing  GPUs.
+          list(APPEND CMAKE_CUDA_ARCHITECTURES "75")
+        endif(CUDAToolkit_VERSION VERSION_GREATER_EQUAL "10.0")
+        if (CUDAToolkit_VERSION VERSION_GREATER_EQUAL "11.0")
+          # Support Ampere GPUs.
+          list(APPEND CMAKE_CUDA_ARCHITECTURES "80")
+        endif(CUDAToolkit_VERSION VERSION_GREATER_EQUAL "11.0")
+        if (CUDAToolkit_VERSION VERSION_GREATER_EQUAL "11.8")
+          # Support Hopper GPUs.
+          list(APPEND CMAKE_CUDA_ARCHITECTURES "90")
+        endif(CUDAToolkit_VERSION VERSION_GREATER_EQUAL "11.8")
+        message("-- Setting CUDA Architecture to ${CMAKE_CUDA_ARCHITECTURES}")
+      endif()
+
+      if (USE_CUDA STREQUAL "static")
+        set(CERES_CUDA_TARGET_SUFFIX "_static")
+      else (USE_CUDA STREQUAL "static")
+        set(CERES_CUDA_TARGET_SUFFIX "")
+      endif (USE_CUDA STREQUAL "static")
+    else (CUDAToolkit_FOUND)
+      message("-- Did not find CUDA, disabling CUDA support.")
+      update_cache_variable(USE_CUDA OFF)
+    endif (CUDAToolkit_FOUND)
+  endif (CMAKE_VERSION VERSION_LESS 3.17)
+endif (USE_CUDA)
+
+if (USE_CUDA)
+  list(APPEND CERES_CUDA_LIBRARIES
+    CUDA::cublas${CERES_CUDA_TARGET_SUFFIX}
+    CUDA::cudart${CERES_CUDA_TARGET_SUFFIX}
+    CUDA::cusolver${CERES_CUDA_TARGET_SUFFIX}
+    CUDA::cusparse${CERES_CUDA_TARGET_SUFFIX})
+  unset (CERES_CUDA_TARGET_SUFFIX)
+  set(CMAKE_CUDA_RUNTIME_LIBRARY NONE)
+else (USE_CUDA)
+  message("-- Building without CUDA.")
+  list(APPEND CERES_COMPILE_OPTIONS CERES_NO_CUDA)
+endif (USE_CUDA)
 
 if (LAPACK)
   find_package(LAPACK QUIET)
@@ -274,70 +299,67 @@
   list(APPEND CERES_COMPILE_OPTIONS CERES_NO_LAPACK)
 endif (LAPACK)
 
+# Set the install path for the installed CeresConfig.cmake configuration file
+# relative to CMAKE_INSTALL_PREFIX.
+set(RELATIVE_CMAKECONFIG_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/Ceres)
+
 if (SUITESPARSE)
   # By default, if SuiteSparse and all dependencies are found, Ceres is
   # built with SuiteSparse support.
 
   # Check for SuiteSparse and dependencies.
-  find_package(SuiteSparse)
-  if (SUITESPARSE_FOUND)
-    # On Ubuntu the system install of SuiteSparse (v3.4.0) up to at least
-    # Ubuntu 13.10 cannot be used to link shared libraries.
-    if (BUILD_SHARED_LIBS AND
-        SUITESPARSE_IS_BROKEN_SHARED_LINKING_UBUNTU_SYSTEM_VERSION)
-      message(FATAL_ERROR "You are attempting to build Ceres as a shared "
-        "library on Ubuntu using a system package install of SuiteSparse "
-        "3.4.0. This package is broken and does not support the "
-        "construction of shared libraries (you can still build Ceres as "
-        "a static library).  If you wish to build a shared version of Ceres "
-        "you should uninstall the system install of SuiteSparse "
-        "(libsuitesparse-dev) and perform a source install of SuiteSparse "
-        "(we recommend that you use the latest version), "
-        "see http://ceres-solver.org/building.html for more information.")
-    endif (BUILD_SHARED_LIBS AND
-      SUITESPARSE_IS_BROKEN_SHARED_LINKING_UBUNTU_SYSTEM_VERSION)
-
+  find_package(SuiteSparse 4.5.6 COMPONENTS CHOLMOD SPQR
+    OPTIONAL_COMPONENTS Partition)
+  if (SuiteSparse_FOUND)
+    set(SuiteSparse_DEPENDENCY "find_dependency(SuiteSparse ${SuiteSparse_VERSION})")
     # By default, if all of SuiteSparse's dependencies are found, Ceres is
     # built with SuiteSparse support.
-    message("-- Found SuiteSparse ${SUITESPARSE_VERSION}, "
+    message("-- Found SuiteSparse ${SuiteSparse_VERSION}, "
             "building with SuiteSparse.")
-  else (SUITESPARSE_FOUND)
+
+    if (SuiteSparse_NO_CMAKE OR NOT SuiteSparse_DIR)
+      install(FILES ${Ceres_SOURCE_DIR}/cmake/FindSuiteSparse.cmake
+                    ${Ceres_SOURCE_DIR}/cmake/FindMETIS.cmake
+              DESTINATION ${RELATIVE_CMAKECONFIG_INSTALL_DIR})
+    endif (SuiteSparse_NO_CMAKE OR NOT SuiteSparse_DIR)
+  else (SuiteSparse_FOUND)
     # Disable use of SuiteSparse if it cannot be found and continue.
     message("-- Did not find all SuiteSparse dependencies, disabling "
       "SuiteSparse support.")
     update_cache_variable(SUITESPARSE OFF)
     list(APPEND CERES_COMPILE_OPTIONS CERES_NO_SUITESPARSE)
-  endif (SUITESPARSE_FOUND)
+  endif (SuiteSparse_FOUND)
 else (SUITESPARSE)
   message("-- Building without SuiteSparse.")
   list(APPEND CERES_COMPILE_OPTIONS CERES_NO_SUITESPARSE)
 endif (SUITESPARSE)
 
-# CXSparse.
-if (CXSPARSE)
-  # Don't search with REQUIRED as we can continue without CXSparse.
-  find_package(CXSparse)
-  if (CXSPARSE_FOUND)
-    # By default, if CXSparse and all dependencies are found, Ceres is
-    # built with CXSparse support.
-    message("-- Found CXSparse version: ${CXSPARSE_VERSION}, "
-      "building with CXSparse.")
-  else (CXSPARSE_FOUND)
-    # Disable use of CXSparse if it cannot be found and continue.
-    message("-- Did not find CXSparse, Building without CXSparse.")
-    update_cache_variable(CXSPARSE OFF)
-    list(APPEND CERES_COMPILE_OPTIONS CERES_NO_CXSPARSE)
-  endif (CXSPARSE_FOUND)
-else (CXSPARSE)
-  message("-- Building without CXSparse.")
-  list(APPEND CERES_COMPILE_OPTIONS CERES_NO_CXSPARSE)
-  # Mark as advanced (remove from default GUI view) the CXSparse search
-  # variables in case user enabled CXSPARSE, FindCXSparse did not find it, so
-  # made search variables visible in GUI for user to set, but then user disables
-  # CXSPARSE instead of setting them.
-  mark_as_advanced(FORCE CXSPARSE_INCLUDE_DIR
-                         CXSPARSE_LIBRARY)
-endif (CXSPARSE)
+if (NOT SuiteSparse_Partition_FOUND)
+  list (APPEND CERES_COMPILE_OPTIONS CERES_NO_CHOLMOD_PARTITION)
+endif (NOT SuiteSparse_Partition_FOUND)
+
+if (EIGENMETIS)
+  find_package (METIS)
+  if (METIS_FOUND)
+    # Since METIS is a private dependency of Ceres, it requires access to the
+    # link-only METIS::METIS target to avoid undefined linker errors in projects
+    # relying on Ceres. We do not actually need to propagate anything besides
+    # the link libraries (such as include directories.)
+    set(METIS_DEPENDENCY "find_dependency(METIS ${METIS_VERSION})")
+    # METIS find module must be installed unless a package config is being used.
+    if (NOT METIS_DIR)
+      install(FILES ${Ceres_SOURCE_DIR}/cmake/FindMETIS.cmake
+              DESTINATION ${RELATIVE_CMAKECONFIG_INSTALL_DIR})
+    endif (NOT METIS_DIR)
+  else (METIS_FOUND)
+    message("-- Did not find METIS, disabling Eigen METIS support.")
+    update_cache_variable(EIGENMETIS OFF)
+    list (APPEND CERES_COMPILE_OPTIONS CERES_NO_EIGEN_METIS)
+  endif (METIS_FOUND)
+else (EIGENMETIS)
+  message("-- Building without Eigen METIS support.")
+  list (APPEND CERES_COMPILE_OPTIONS CERES_NO_EIGEN_METIS)
+endif (EIGENMETIS)
 
 if (ACCELERATESPARSE)
   find_package(AccelerateSparse)
@@ -358,9 +380,9 @@
 endif()
 
 # Ensure that the user understands they have disabled all sparse libraries.
-if (NOT SUITESPARSE AND NOT CXSPARSE AND NOT EIGENSPARSE AND NOT ACCELERATESPARSE)
+if (NOT SUITESPARSE AND NOT EIGENSPARSE AND NOT ACCELERATESPARSE)
   message("   ===============================================================")
-  message("   Compiling without any sparse library: SuiteSparse, CXSparse ")
+  message("   Compiling without any sparse library: SuiteSparse, ")
   message("   EigenSparse & Apple's Accelerate are all disabled or unavailable.  ")
   message("   No sparse linear solvers (SPARSE_NORMAL_CHOLESKY & SPARSE_SCHUR)")
   message("   will be available when Ceres is used.")
@@ -458,10 +480,9 @@
   message("-- Disabling custom blas")
 endif (NOT CUSTOM_BLAS)
 
-set_ceres_threading_model("${CERES_THREADING_MODEL}")
-
 if (BUILD_BENCHMARKS)
-  find_package(benchmark QUIET)
+  # Version 1.3 was first to provide import targets
+  find_package(benchmark 1.3 QUIET)
   if (benchmark_FOUND)
      message("-- Found Google benchmark library. Building Ceres benchmarks.")
   else()
@@ -471,14 +492,9 @@
   mark_as_advanced(benchmark_DIR)
 endif()
 
+# TODO Report features using the FeatureSummary CMake module
 if (BUILD_SHARED_LIBS)
   message("-- Building Ceres as a shared library.")
-  # The CERES_BUILDING_SHARED_LIBRARY compile definition is NOT stored in
-  # CERES_COMPILE_OPTIONS as it must only be defined when Ceres is compiled
-  # not when it is used as it controls the CERES_EXPORT macro which provides
-  # symbol import/export support.
-  add_definitions(-DCERES_BUILDING_SHARED_LIBRARY)
-  list(APPEND CERES_COMPILE_OPTIONS CERES_USING_SHARED_LIBRARY)
 else (BUILD_SHARED_LIBS)
   message("-- Building Ceres as a static library.")
 endif (BUILD_SHARED_LIBS)
@@ -516,76 +532,42 @@
 
 # After the tweaks for the compile settings, disable some warnings on MSVC.
 if (MSVC)
-  # On MSVC, math constants are not included in <cmath> or <math.h> unless
-  # _USE_MATH_DEFINES is defined [1].  As we use M_PI in the examples, ensure
-  # that _USE_MATH_DEFINES is defined before the first inclusion of <cmath>.
-  #
-  # [1] https://msdn.microsoft.com/en-us/library/4hwaceh6.aspx
-  add_definitions("-D_USE_MATH_DEFINES")
+  # Insecure standard library functions
+  add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
+  # std::numeric_limits<T>::has_denorm is deprecated in C++23
+  add_compile_definitions($<$<COMPILE_LANGUAGE:CXX>:_SILENCE_CXX23_DENORM_DEPRECATION_WARNING>)
+  # std::aligned_storage is deprecated in C++23
+  add_compile_definitions($<$<COMPILE_LANGUAGE:CXX>:_SILENCE_CXX23_ALIGNED_STORAGE_DEPRECATION_WARNING>)
   # Disable signed/unsigned int conversion warnings.
-  add_compile_options("/wd4018" "/wd4267")
-  # Disable warning about using struct/class for the same symobl.
-  add_compile_options("/wd4099")
-  # Disable warning about the insecurity of using "std::copy".
-  add_compile_options("/wd4996")
+  add_compile_options($<$<COMPILE_LANGUAGE:CXX>:/wd4018>)
+  add_compile_options($<$<COMPILE_LANGUAGE:CXX>:/wd4267>)
+  # Disable warning about using struct/class for the same symbol.
+  add_compile_options($<$<COMPILE_LANGUAGE:CXX>:/wd4099>)
   # Disable performance warning about int-to-bool conversion.
-  add_compile_options("/wd4800")
-  # Disable performance warning about fopen insecurity.
-  add_compile_options("/wd4996")
+  add_compile_options($<$<COMPILE_LANGUAGE:CXX>:/wd4800>)
   # Disable warning about int64 to int32 conversion. Disabling
   # this warning may not be correct; needs investigation.
   # TODO(keir): Investigate these warnings in more detail.
-  add_compile_options("/wd4244")
+  add_compile_options($<$<COMPILE_LANGUAGE:CXX>:/wd4244>)
   # It's not possible to use STL types in DLL interfaces in a portable and
   # reliable way. However, that's what happens with Google Log and Google Flags
   # on Windows. MSVC gets upset about this and throws warnings that we can't do
   # much about. The real solution is to link static versions of Google Log and
   # Google Test, but that seems tricky on Windows. So, disable the warning.
-  add_compile_options("/wd4251")
+  add_compile_options($<$<COMPILE_LANGUAGE:CXX>:/wd4251>)
 
   # Add bigobj flag otherwise the build would fail due to large object files
   # probably resulting from generated headers (like the fixed-size schur
   # specializations).
-  add_compile_options("/bigobj")
+  add_compile_options($<$<COMPILE_LANGUAGE:CXX>:/bigobj>)
 
   # Google Flags doesn't have their DLL import/export stuff set up correctly,
   # which results in linker warnings. This is irrelevant for Ceres, so ignore
   # the warnings.
   set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ignore:4049")
 
-  # Update the C/CXX flags for MSVC to use either the static or shared
-  # C-Run Time (CRT) library based on the user option: MSVC_USE_STATIC_CRT.
-  list(APPEND C_CXX_FLAGS
-    CMAKE_CXX_FLAGS
-    CMAKE_CXX_FLAGS_DEBUG
-    CMAKE_CXX_FLAGS_RELEASE
-    CMAKE_CXX_FLAGS_MINSIZEREL
-    CMAKE_CXX_FLAGS_RELWITHDEBINFO)
-
-  foreach(FLAG_VAR ${C_CXX_FLAGS})
-    if (MSVC_USE_STATIC_CRT)
-      # Use static CRT.
-      if (${FLAG_VAR} MATCHES "/MD")
-        string(REGEX REPLACE "/MD" "/MT" ${FLAG_VAR} "${${FLAG_VAR}}")
-      endif (${FLAG_VAR} MATCHES "/MD")
-    else (MSVC_USE_STATIC_CRT)
-      # Use shared, not static, CRT.
-      if (${FLAG_VAR} MATCHES "/MT")
-        string(REGEX REPLACE "/MT" "/MD" ${FLAG_VAR} "${${FLAG_VAR}}")
-      endif (${FLAG_VAR} MATCHES "/MT")
-    endif (MSVC_USE_STATIC_CRT)
-  endforeach()
-
   # Tuple sizes of 10 are used by Gtest.
   add_definitions("-D_VARIADIC_MAX=10")
-
-  include(CheckIfUnderscorePrefixedBesselFunctionsExist)
-  check_if_underscore_prefixed_bessel_functions_exist(
-    HAVE_UNDERSCORE_PREFIXED_BESSEL_FUNCTIONS)
-  if (HAVE_UNDERSCORE_PREFIXED_BESSEL_FUNCTIONS)
-    list(APPEND CERES_COMPILE_OPTIONS
-      CERES_MSVC_USE_UNDERSCORE_PREFIXED_BESSEL_FUNCTIONS)
-  endif()
 endif (MSVC)
 
 if (UNIX)
@@ -605,17 +587,22 @@
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CERES_STRICT_CXX_FLAGS}")
 endif (UNIX)
 
-# Use a larger inlining threshold for Clang, since it hobbles Eigen,
-# resulting in an unreasonably slow version of the blas routines. The
-# -Qunused-arguments is needed because CMake passes the inline
-# threshold to the linker and clang complains about it and dies.
 if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") # Matches Clang & AppleClang.
-  set(CMAKE_CXX_FLAGS
-    "${CMAKE_CXX_FLAGS} -Qunused-arguments -mllvm -inline-threshold=600")
-
+  # Optimize for Eigen OR enable bitcode; you cannot do both since bitcode is an
+  # intermediate representation.
+  if (ENABLE_BITCODE)
+    set(CMAKE_CXX_FLAGS
+      "${CMAKE_CXX_FLAGS} -fembed-bitcode")
+  else ()
+    # Use a larger inlining threshold for Clang, since it hobbles Eigen,
+    # resulting in an unreasonably slow version of the blas routines. The
+    # -Qunused-arguments is needed because CMake passes the inline
+    # threshold to the linker and clang complains about it and dies.
+    set(CMAKE_CXX_FLAGS
+      "${CMAKE_CXX_FLAGS} -Qunused-arguments -mllvm -inline-threshold=600")
+  endif ()
   # Older versions of Clang (<= 2.9) do not support the 'return-type-c-linkage'
   # option, so check for its presence before adding it to the default flags set.
-  include(CheckCXXCompilerFlag)
   check_cxx_compiler_flag("-Wno-return-type-c-linkage"
                           HAVE_RETURN_TYPE_C_LINKAGE)
   if (HAVE_RETURN_TYPE_C_LINKAGE)
@@ -623,6 +610,8 @@
   endif(HAVE_RETURN_TYPE_C_LINKAGE)
 endif ()
 
+add_compile_definitions($<$<BOOL:${WIN32}>:NOMINMAX>)
+
 # Configure the Ceres config.h compile options header using the current
 # compile options and put the configured header into the Ceres build
 # directory.  Note that the ceres/internal subdir in <build>/config where
@@ -632,17 +621,14 @@
 list(REMOVE_DUPLICATES CERES_COMPILE_OPTIONS)
 include(CreateCeresConfig)
 create_ceres_config("${CERES_COMPILE_OPTIONS}"
-  ${Ceres_BINARY_DIR}/config/ceres/internal)
+  ${Ceres_BINARY_DIR}/${CMAKE_INSTALL_INCLUDEDIR}/ceres/internal)
 
 add_subdirectory(internal/ceres)
 
 if (BUILD_DOCUMENTATION)
-  set(CERES_DOCS_INSTALL_DIR "share/doc/ceres" CACHE STRING
-      "Ceres docs install path relative to CMAKE_INSTALL_PREFIX")
-
-  find_package(Sphinx QUIET)
-  if (NOT SPHINX_FOUND)
-    message("-- Failed to find Sphinx, disabling build of documentation.")
+  find_package (Sphinx REQUIRED COMPONENTS sphinx_rtd_theme)
+  if (NOT Sphinx_FOUND)
+    message("-- Failed to find Sphinx and/or its dependencies, disabling build of documentation.")
     update_cache_variable(BUILD_DOCUMENTATION OFF)
   else()
     # Generate the User's Guide (html).
@@ -661,21 +647,22 @@
 
 # Setup installation of Ceres public headers.
 file(GLOB CERES_HDRS ${Ceres_SOURCE_DIR}/include/ceres/*.h)
-install(FILES ${CERES_HDRS} DESTINATION include/ceres)
+install(FILES ${CERES_HDRS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/ceres)
 
 file(GLOB CERES_PUBLIC_INTERNAL_HDRS ${Ceres_SOURCE_DIR}/include/ceres/internal/*.h)
-install(FILES ${CERES_PUBLIC_INTERNAL_HDRS} DESTINATION include/ceres/internal)
+install(FILES ${CERES_PUBLIC_INTERNAL_HDRS} DESTINATION
+  ${CMAKE_INSTALL_INCLUDEDIR}/ceres/internal)
 
 # Also setup installation of Ceres config.h configured with the current
-# build options into the installed headers directory.
-install(FILES ${Ceres_BINARY_DIR}/config/ceres/internal/config.h
-        DESTINATION include/ceres/internal)
+# build options and export.h into the installed headers directory.
+install(DIRECTORY ${Ceres_BINARY_DIR}/${CMAKE_INSTALL_INCLUDEDIR}/
+        DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
 
 if (MINIGLOG)
   # Install miniglog header if being used as logging #includes appear in
   # installed public Ceres headers.
   install(FILES ${Ceres_SOURCE_DIR}/internal/ceres/miniglog/glog/logging.h
-          DESTINATION include/ceres/internal/miniglog/glog)
+          DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/ceres/internal/miniglog/glog)
 endif (MINIGLOG)
 
 # Ceres supports two mechanisms by which it can be detected & imported into
@@ -715,14 +702,6 @@
 
 # Install method #1: Put Ceres in CMAKE_INSTALL_PREFIX: /usr/local or equivalent.
 
-# Set the install path for the installed CeresConfig.cmake configuration file
-# relative to CMAKE_INSTALL_PREFIX.
-if (WIN32)
-  set(RELATIVE_CMAKECONFIG_INSTALL_DIR CMake)
-else ()
-  set(RELATIVE_CMAKECONFIG_INSTALL_DIR lib${LIB_SUFFIX}/cmake/Ceres)
-endif ()
-
 # This "exports" for installation all targets which have been put into the
 # export set "CeresExport". This generates a CeresTargets.cmake file which,
 # when read in by a client project as part of find_package(Ceres) creates
@@ -788,13 +767,23 @@
     ${Ceres_BINARY_DIR}
     ${Ceres_SOURCE_DIR})
 
+  set (Ceres_EXPORT_TARGETS ceres)
+
+  if (TARGET ceres_cuda_kernels)
+    # The target ceres depends on ceres_cuda_kernels requiring the latter to be
+    # exported as part of the same export set.
+    list (APPEND Ceres_EXPORT_TARGETS ceres_cuda_kernels)
+  endif (TARGET ceres_cuda_kernels)
+
   # Analogously to install(EXPORT ...), export the Ceres target from the build
   # directory as a package called Ceres into the local CMake package registry.
-  export(TARGETS ceres
+  export(TARGETS ${Ceres_EXPORT_TARGETS}
          NAMESPACE Ceres::
          FILE ${Ceres_BINARY_DIR}/CeresTargets.cmake)
   export(PACKAGE ${CMAKE_PROJECT_NAME})
 
+  unset (Ceres_EXPORT_TARGETS)
+
   # Configure a CeresConfig.cmake file for the export of the Ceres build
   # directory from the template, reflecting the current build options.
   set(SETUP_CERES_CONFIG_FOR_INSTALLATION FALSE)
diff --git a/third_party/ceres/LICENSE b/third_party/ceres/LICENSE
index cf69df2..b5d967c 100644
--- a/third_party/ceres/LICENSE
+++ b/third_party/ceres/LICENSE
@@ -1,5 +1,5 @@
 Ceres Solver - A fast non-linear least squares minimizer
-Copyright 2015 Google Inc. All rights reserved.
+Copyright 2023 Google Inc. All rights reserved.
 http://ceres-solver.org/
 
 Redistribution and use in source and binary forms, with or without
diff --git a/third_party/ceres/README.md b/third_party/ceres/README.md
index b091574..7de8f0d 100644
--- a/third_party/ceres/README.md
+++ b/third_party/ceres/README.md
@@ -1,4 +1,7 @@
-[![Build Status](https://travis-ci.org/ceres-solver/ceres-solver.svg?branch=master)](https://travis-ci.org/ceres-solver/ceres-solver)
+[![Android](https://github.com/ceres-solver/ceres-solver/actions/workflows/android.yml/badge.svg)](https://github.com/ceres-solver/ceres-solver/actions/workflows/android.yml)
+[![Linux](https://github.com/ceres-solver/ceres-solver/actions/workflows/linux.yml/badge.svg)](https://github.com/ceres-solver/ceres-solver/actions/workflows/linux.yml)
+[![macOS](https://github.com/ceres-solver/ceres-solver/actions/workflows/macos.yml/badge.svg)](https://github.com/ceres-solver/ceres-solver/actions/workflows/macos.yml)
+[![Windows](https://github.com/ceres-solver/ceres-solver/actions/workflows/windows.yml/badge.svg)](https://github.com/ceres-solver/ceres-solver/actions/workflows/windows.yml)
 
 Ceres Solver
 ============
diff --git a/third_party/ceres/WORKSPACE b/third_party/ceres/WORKSPACE
index e1e5eca..40a84a3 100644
--- a/third_party/ceres/WORKSPACE
+++ b/third_party/ceres/WORKSPACE
@@ -1,5 +1,5 @@
 # Ceres Solver - A fast non-linear least squares minimizer
-# Copyright 2018 Google Inc. All rights reserved.
+# Copyright 2023 Google Inc. All rights reserved.
 # http://ceres-solver.org/
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/third_party/ceres/bazel/ceres.bzl b/third_party/ceres/bazel/ceres.bzl
index e1bc356..7da049e 100644
--- a/third_party/ceres/bazel/ceres.bzl
+++ b/third_party/ceres/bazel/ceres.bzl
@@ -1,5 +1,5 @@
 # Ceres Solver - A fast non-linear least squares minimizer
-# Copyright 2018 Google Inc. All rights reserved.
+# Copyright 2023 Google Inc. All rights reserved.
 # http://ceres-solver.org/
 #
 # Redistribution and use in source and binary forms, with or without
@@ -31,10 +31,9 @@
 CERES_SRCS = ["internal/ceres/" + filename for filename in [
     "accelerate_sparse.cc",
     "array_utils.cc",
-    "blas.cc",
     "block_evaluate_preparer.cc",
-    "block_jacobian_writer.cc",
     "block_jacobi_preconditioner.cc",
+    "block_jacobian_writer.cc",
     "block_random_access_dense_matrix.cc",
     "block_random_access_diagonal_matrix.cc",
     "block_random_access_matrix.cc",
@@ -49,14 +48,16 @@
     "compressed_row_jacobian_writer.cc",
     "compressed_row_sparse_matrix.cc",
     "conditioned_cost_function.cc",
-    "conjugate_gradients_solver.cc",
     "context.cc",
     "context_impl.cc",
     "coordinate_descent_minimizer.cc",
     "corrector.cc",
+    "cost_function.cc",
     "covariance.cc",
     "covariance_impl.cc",
+    "dense_cholesky.cc",
     "dense_normal_cholesky_solver.cc",
+    "dense_qr.cc",
     "dense_qr_solver.cc",
     "dense_sparse_matrix.cc",
     "detect_structure.cc",
@@ -65,38 +66,42 @@
     "dynamic_compressed_row_sparse_matrix.cc",
     "dynamic_sparse_normal_cholesky_solver.cc",
     "eigensparse.cc",
+    "evaluation_callback.cc",
     "evaluator.cc",
     "file.cc",
+    "first_order_function.cc",
+    "float_suitesparse.cc",
     "function_sample.cc",
     "gradient_checker.cc",
     "gradient_checking_cost_function.cc",
     "gradient_problem.cc",
     "gradient_problem_solver.cc",
-    "is_close.cc",
     "implicit_schur_complement.cc",
     "inner_product_computer.cc",
+    "is_close.cc",
+    "iteration_callback.cc",
     "iterative_refiner.cc",
     "iterative_schur_complement_solver.cc",
-    "lapack.cc",
     "levenberg_marquardt_strategy.cc",
     "line_search.cc",
     "line_search_direction.cc",
     "line_search_minimizer.cc",
+    "line_search_preprocessor.cc",
     "linear_least_squares_problems.cc",
     "linear_operator.cc",
-    "line_search_preprocessor.cc",
     "linear_solver.cc",
-    "local_parameterization.cc",
     "loss_function.cc",
     "low_rank_inverse_hessian.cc",
+    "manifold.cc",
     "minimizer.cc",
     "normal_prior.cc",
-    "parallel_for_cxx.cc",
-    "parallel_for_openmp.cc",
+    "parallel_invoke.cc",
     "parallel_utils.cc",
+    "parallel_vector_ops.cc",
     "parameter_block_ordering.cc",
     "partitioned_matrix_view.cc",
     "polynomial.cc",
+    "power_series_expansion_preconditioner.cc",
     "preconditioner.cc",
     "preprocessor.cc",
     "problem.cc",
@@ -116,7 +121,6 @@
     "sparse_cholesky.cc",
     "sparse_matrix.cc",
     "sparse_normal_cholesky_solver.cc",
-    "split.cc",
     "stringprintf.cc",
     "subset_preconditioner.cc",
     "suitesparse.cc",
@@ -173,14 +177,17 @@
                 "include/ceres/internal/*.h",
             ]) +
 
-            # This is an empty config, since the Bazel-based build does not
-            # generate a config.h from config.h.in. This is fine, since Bazel
-            # properly handles propagating -D defines to dependent targets.
+            # This is an empty config and export, since the
+            # Bazel-based build does not generate a
+            # config.h/export.h. This is fine, since Bazel properly
+            # handles propagating -D defines to dependent targets.
             native.glob([
                 "config/ceres/internal/config.h",
+                "config/ceres/internal/export.h",
             ]),
         copts = [
             "-I" + internal,
+            "-Wunused-parameter",
             "-Wno-sign-compare",
             "-Wno-format-nonliteral",
             "-Wno-unused-parameter",
@@ -194,12 +201,15 @@
         # part of a Skylark Ceres target macro.
         # https://github.com/ceres-solver/ceres-solver/issues/396
         defines = [
-            "CERES_NO_SUITESPARSE",
-            "CERES_NO_CXSPARSE",
+            "CERES_EXPORT=",
             "CERES_NO_ACCELERATE_SPARSE",
+            "CERES_NO_CHOLMOD_PARTITION",
+            "CERES_NO_CUDA",
+            "CERES_NO_EIGEN_METIS",
+            "CERES_NO_EXPORT=",
             "CERES_NO_LAPACK",
+            "CERES_NO_SUITESPARSE",
             "CERES_USE_EIGEN_SPARSE",
-            "CERES_USE_CXX_THREADS",
         ],
         includes = [
             "config",
diff --git a/third_party/ceres/cmake/AddCompileFlagsIfSupported.cmake b/third_party/ceres/cmake/AddCompileFlagsIfSupported.cmake
index 1af9ee8..d947fdf 100644
--- a/third_party/ceres/cmake/AddCompileFlagsIfSupported.cmake
+++ b/third_party/ceres/cmake/AddCompileFlagsIfSupported.cmake
@@ -1,5 +1,5 @@
 # Ceres Solver - A fast non-linear least squares minimizer
-# Copyright 2017 Google Inc. All rights reserved.
+# Copyright 2023 Google Inc. All rights reserved.
 # http://ceres-solver.org/
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/third_party/ceres/cmake/AddGerritCommitHook.cmake b/third_party/ceres/cmake/AddGerritCommitHook.cmake
index 65b2fab..070158c 100644
--- a/third_party/ceres/cmake/AddGerritCommitHook.cmake
+++ b/third_party/ceres/cmake/AddGerritCommitHook.cmake
@@ -1,5 +1,5 @@
 # Ceres Solver - A fast non-linear least squares minimizer
-# Copyright 2015 Google Inc. All rights reserved.
+# Copyright 2023 Google Inc. All rights reserved.
 # http://ceres-solver.org/
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/third_party/ceres/cmake/AppendTargetProperty.cmake b/third_party/ceres/cmake/AppendTargetProperty.cmake
deleted file mode 100644
index e0bc3a4..0000000
--- a/third_party/ceres/cmake/AppendTargetProperty.cmake
+++ /dev/null
@@ -1,61 +0,0 @@
-# Ceres Solver - A fast non-linear least squares minimizer
-# Copyright 2015 Google Inc. All rights reserved.
-# http://ceres-solver.org/
-#
-# 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 Google Inc. 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.
-#
-# Author: alexs.mac@gmail.com (Alex Stewart)
-
-# Append item(s) to a property on a declared CMake target:
-#
-#    append_target_property(target property item_to_append1
-#                                           [... item_to_appendN])
-#
-# The set_target_properties() CMake function will overwrite the contents of the
-# specified target property.  This function instead appends to it, so can
-# be called multiple times with the same target & property to iteratively
-# populate it.
-function(append_target_property TARGET PROPERTY)
-  if (NOT TARGET ${TARGET})
-    message(FATAL_ERROR "Invalid target: ${TARGET} cannot append: ${ARGN} "
-      "to property: ${PROPERTY}")
-  endif()
-  if (NOT PROPERTY)
-    message(FATAL_ERROR "Invalid property to update for target: ${TARGET}")
-  endif()
-  # Get the initial state of the specified property for the target s/t
-  # we can append to it (not overwrite it).
-  get_target_property(INITIAL_PROPERTY_STATE ${TARGET} ${PROPERTY})
-  if (NOT INITIAL_PROPERTY_STATE)
-    # Ensure that if the state is unset, we do not insert the XXX-NOTFOUND
-    # returned by CMake into the property.
-    set(INITIAL_PROPERTY_STATE "")
-  endif()
-  # Delistify (remove ; separators) the potentially set of items to append
-  # to the specified target property.
-  string(REPLACE ";" " " ITEMS_TO_APPEND "${ARGN}")
-  set_target_properties(${TARGET} PROPERTIES ${PROPERTY}
-    "${INITIAL_PROPERTY_STATE} ${ITEMS_TO_APPEND}")
-endfunction()
diff --git a/third_party/ceres/cmake/CeresCompileOptionsToComponents.cmake b/third_party/ceres/cmake/CeresCompileOptionsToComponents.cmake
index 5be0fb2..64634d5 100644
--- a/third_party/ceres/cmake/CeresCompileOptionsToComponents.cmake
+++ b/third_party/ceres/cmake/CeresCompileOptionsToComponents.cmake
@@ -1,5 +1,5 @@
 # Ceres Solver - A fast non-linear least squares minimizer
-# Copyright 2016 Google Inc. All rights reserved.
+# Copyright 2023 Google Inc. All rights reserved.
 # http://ceres-solver.org/
 #
 # Redistribution and use in source and binary forms, with or without
@@ -77,15 +77,9 @@
   add_to_output_if_not_found(CURRENT_CERES_COMPILE_OPTIONS ${CERES_COMPONENTS_VAR}
     CERES_NO_SUITESPARSE "SuiteSparse;SparseLinearAlgebraLibrary")
   add_to_output_if_not_found(CURRENT_CERES_COMPILE_OPTIONS ${CERES_COMPONENTS_VAR}
-    CERES_NO_CXSPARSE "CXSparse;SparseLinearAlgebraLibrary")
-  add_to_output_if_not_found(CURRENT_CERES_COMPILE_OPTIONS ${CERES_COMPONENTS_VAR}
     CERES_NO_ACCELERATE_SPARSE "AccelerateSparse;SparseLinearAlgebraLibrary")
   add_to_output_if_not_found(CURRENT_CERES_COMPILE_OPTIONS ${CERES_COMPONENTS_VAR}
     CERES_RESTRICT_SCHUR_SPECIALIZATION "SchurSpecializations")
-  add_to_output_if_found(CURRENT_CERES_COMPILE_OPTIONS ${CERES_COMPONENTS_VAR}
-    CERES_USE_OPENMP "OpenMP;Multithreading")
-  add_to_output_if_found(CURRENT_CERES_COMPILE_OPTIONS ${CERES_COMPONENTS_VAR}
-    CERES_USE_CXX_THREADS "Multithreading")
   # Remove duplicates of SparseLinearAlgebraLibrary if multiple sparse backends
   # are present.
   list(REMOVE_DUPLICATES ${CERES_COMPONENTS_VAR})
diff --git a/third_party/ceres/cmake/CeresConfig.cmake.in b/third_party/ceres/cmake/CeresConfig.cmake.in
index e5e2976..ceb7e26 100644
--- a/third_party/ceres/cmake/CeresConfig.cmake.in
+++ b/third_party/ceres/cmake/CeresConfig.cmake.in
@@ -1,5 +1,5 @@
 # Ceres Solver - A fast non-linear least squares minimizer
-# Copyright 2015 Google Inc. All rights reserved.
+# Copyright 2022 Google Inc. All rights reserved.
 # http://ceres-solver.org/
 #
 # Redistribution and use in source and binary forms, with or without
@@ -173,10 +173,14 @@
 endif(CERES_WAS_INSTALLED)
 
 # Set the version.
-set(CERES_VERSION @CERES_VERSION@ )
+set(CERES_VERSION @CERES_VERSION@)
 
 include(CMakeFindDependencyMacro)
-find_dependency(Threads)
+# Optional dependencies
+@METIS_DEPENDENCY@
+@SuiteSparse_DEPENDENCY@
+@CUDAToolkit_DEPENDENCY@
+@Threads_DEPENDENCY@
 
 # As imported CMake targets are not re-exported when a dependent target is
 # exported, we must invoke find_package(XXX) here to reload the definition
@@ -187,30 +191,30 @@
 
 # Eigen.
 # Flag set during configuration and build of Ceres.
-set(CERES_EIGEN_VERSION @EIGEN3_VERSION_STRING@)
+set(CERES_EIGEN_VERSION @Eigen3_VERSION@)
 # Search quietly to control the timing of the error message if not found. The
 # search should be for an exact match, but for usability reasons do a soft
 # match and reject with an explanation below.
 find_package(Eigen3 ${CERES_EIGEN_VERSION} QUIET)
-if (EIGEN3_FOUND)
-  if (NOT EIGEN3_VERSION_STRING VERSION_EQUAL CERES_EIGEN_VERSION)
+if (Eigen3_FOUND)
+  if (NOT Eigen3_VERSION VERSION_EQUAL CERES_EIGEN_VERSION)
     # CMake's VERSION check in FIND_PACKAGE() will accept any version >= the
     # specified version. However, only version = is supported. Improve
     # usability by explaining why we don't accept non-exact version matching.
     ceres_report_not_found("Found Eigen dependency, but the version of Eigen "
-      "found (${EIGEN3_VERSION_STRING}) does not exactly match the version of Eigen "
+      "found (${Eigen3_VERSION}) does not exactly match the version of Eigen "
       "Ceres was compiled with (${CERES_EIGEN_VERSION}). This can cause subtle "
       "bugs by triggering violations of the One Definition Rule. See the "
       "Wikipedia article http://en.wikipedia.org/wiki/One_Definition_Rule "
       "for more details")
   endif ()
   ceres_message(STATUS "Found required Ceres dependency: "
-    "Eigen version ${CERES_EIGEN_VERSION} in ${EIGEN3_INCLUDE_DIRS}")
-else (EIGEN3_FOUND)
+    "Eigen version ${CERES_EIGEN_VERSION} in ${Eigen3_DIR}")
+else (Eigen3_FOUND)
   ceres_report_not_found("Missing required Ceres "
     "dependency: Eigen version ${CERES_EIGEN_VERSION}, please set "
     "Eigen3_DIR.")
-endif (EIGEN3_FOUND)
+endif (Eigen3_FOUND)
 
 # glog (and maybe gflags).
 #
diff --git a/third_party/ceres/cmake/CeresThreadingModels.cmake b/third_party/ceres/cmake/CeresThreadingModels.cmake
deleted file mode 100644
index 571dd7d..0000000
--- a/third_party/ceres/cmake/CeresThreadingModels.cmake
+++ /dev/null
@@ -1,82 +0,0 @@
-# Ceres Solver - A fast non-linear least squares minimizer
-# Copyright 2018 Google Inc. All rights reserved.
-# http://ceres-solver.org/
-#
-# 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 Google Inc. 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.
-#
-# Author: alexs.mac@gmail.com (Alex Stewart)
-
-# Ordered by expected preference.
-set(CERES_THREADING_MODELS "CXX_THREADS;OPENMP;NO_THREADS")
-
-function(find_available_ceres_threading_models CERES_THREADING_MODELS_AVAILABLE_VAR)
-  set(CERES_THREADING_MODELS_AVAILABLE ${CERES_THREADING_MODELS})
-  # Remove any threading models for which the dependencies are not available.
-  find_package(OpenMP QUIET)
-  if (NOT OPENMP_FOUND)
-    list(REMOVE_ITEM CERES_THREADING_MODELS_AVAILABLE "OPENMP")
-  endif()
-  if (NOT CERES_THREADING_MODELS_AVAILABLE)
-    # At least NO_THREADS should never be removed.  This check is purely
-    # protective against future threading model updates.
-    message(FATAL_ERROR "Ceres bug: Removed all threading models.")
-  endif()
-  set(${CERES_THREADING_MODELS_AVAILABLE_VAR}
-    ${CERES_THREADING_MODELS_AVAILABLE} PARENT_SCOPE)
-endfunction()
-
-macro(set_ceres_threading_model_to_cxx11_threads)
-  list(APPEND CERES_COMPILE_OPTIONS CERES_USE_CXX_THREADS)
-endmacro()
-
-macro(set_ceres_threading_model_to_openmp)
-  find_package(OpenMP REQUIRED)
-  list(APPEND CERES_COMPILE_OPTIONS CERES_USE_OPENMP)
-  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
-  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
-endmacro()
-
-macro(set_ceres_threading_model_to_no_threads)
-  list(APPEND CERES_COMPILE_OPTIONS CERES_NO_THREADS)
-endmacro()
-
-macro(set_ceres_threading_model CERES_THREADING_MODEL_TO_SET)
-  if ("${CERES_THREADING_MODEL_TO_SET}" STREQUAL "CXX_THREADS")
-    set_ceres_threading_model_to_cxx11_threads()
-  elseif ("${CERES_THREADING_MODEL_TO_SET}" STREQUAL "OPENMP")
-    set_ceres_threading_model_to_openmp()
-  elseif ("${CERES_THREADING_MODEL_TO_SET}" STREQUAL "NO_THREADS")
-    set_ceres_threading_model_to_no_threads()
-  else()
-    include(PrettyPrintCMakeList)
-    find_available_ceres_threading_models(_AVAILABLE_THREADING_MODELS)
-    pretty_print_cmake_list(
-      _AVAILABLE_THREADING_MODELS ${_AVAILABLE_THREADING_MODELS})
-    message(FATAL_ERROR "Unknown threading model specified: "
-      "'${CERES_THREADING_MODEL_TO_SET}'. Available threading models for "
-      "this platform are: ${_AVAILABLE_THREADING_MODELS}")
-  endif()
-  message("-- Using Ceres threading model: ${CERES_THREADING_MODEL_TO_SET}")
-endmacro()
diff --git a/third_party/ceres/cmake/CheckIfUnderscorePrefixedBesselFunctionsExist.cmake b/third_party/ceres/cmake/CheckIfUnderscorePrefixedBesselFunctionsExist.cmake
deleted file mode 100644
index a05721c..0000000
--- a/third_party/ceres/cmake/CheckIfUnderscorePrefixedBesselFunctionsExist.cmake
+++ /dev/null
@@ -1,54 +0,0 @@
-# Ceres Solver - A fast non-linear least squares minimizer
-# Copyright 2017 Google Inc. All rights reserved.
-# http://ceres-solver.org/
-#
-# 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 Google Inc. 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.
-#
-# Author: alexs.mac@gmail.com (Alex Stewart)
-
-# Microsoft deprecated the POSIX Bessel functions: j[0,1,n]() in favour
-# of _j[0,1,n](), it appears since at least MSVC 2005 [1].  This function
-# checks if the underscore prefixed versions of the Bessel functions are
-# defined, and sets ${HAVE_UNDERSCORE_PREFIXED_BESSEL_FUNCTIONS_VAR} to
-# TRUE if they do.
-#
-# [1] https://msdn.microsoft.com/en-us/library/ms235384(v=vs.100).aspx
-function(check_if_underscore_prefixed_bessel_functions_exist
-    HAVE_UNDERSCORE_PREFIXED_BESSEL_FUNCTIONS_VAR)
-  include(CheckCXXSourceCompiles)
-  check_cxx_source_compiles(
-    "#include <math.h>
-     int main(int argc, char * argv[]) {
-       double result;
-       result = _j0(1.2345);
-       result = _j1(1.2345);
-       result = _jn(2, 1.2345);
-       return 0;
-     }"
-     HAVE_UNDERSCORE_PREFIXED_BESSEL_FUNCTIONS)
-   set(${HAVE_UNDERSCORE_PREFIXED_BESSEL_FUNCTIONS_VAR}
-     ${HAVE_UNDERSCORE_PREFIXED_BESSEL_FUNCTIONS}
-     PARENT_SCOPE)
-endfunction()
diff --git a/third_party/ceres/cmake/CreateCeresConfig.cmake b/third_party/ceres/cmake/CreateCeresConfig.cmake
index 89db68c..f0037cc 100644
--- a/third_party/ceres/cmake/CreateCeresConfig.cmake
+++ b/third_party/ceres/cmake/CreateCeresConfig.cmake
@@ -1,5 +1,5 @@
 # Ceres Solver - A fast non-linear least squares minimizer
-# Copyright 2015 Google Inc. All rights reserved.
+# Copyright 2023 Google Inc. All rights reserved.
 # http://ceres-solver.org/
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/third_party/ceres/cmake/DetectBrokenStackCheckMacOSXcodePairing.cmake b/third_party/ceres/cmake/DetectBrokenStackCheckMacOSXcodePairing.cmake
index 151e28c..f333ed9 100644
--- a/third_party/ceres/cmake/DetectBrokenStackCheckMacOSXcodePairing.cmake
+++ b/third_party/ceres/cmake/DetectBrokenStackCheckMacOSXcodePairing.cmake
@@ -1,5 +1,5 @@
 # Ceres Solver - A fast non-linear least squares minimizer
-# Copyright 2019 Google Inc. All rights reserved.
+# Copyright 2023 Google Inc. All rights reserved.
 # http://ceres-solver.org/
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/third_party/ceres/cmake/EnableSanitizer.cmake b/third_party/ceres/cmake/EnableSanitizer.cmake
index 1ef68c3..9a8d484 100644
--- a/third_party/ceres/cmake/EnableSanitizer.cmake
+++ b/third_party/ceres/cmake/EnableSanitizer.cmake
@@ -1,5 +1,5 @@
 # Ceres Solver - A fast non-linear least squares minimizer
-# Copyright 2019 Google Inc. All rights reserved.
+# Copyright 2023 Google Inc. All rights reserved.
 # http://ceres-solver.org/
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/third_party/ceres/cmake/FindAccelerateSparse.cmake b/third_party/ceres/cmake/FindAccelerateSparse.cmake
index f2f4340..3a2e431 100644
--- a/third_party/ceres/cmake/FindAccelerateSparse.cmake
+++ b/third_party/ceres/cmake/FindAccelerateSparse.cmake
@@ -1,5 +1,5 @@
 # Ceres Solver - A fast non-linear least squares minimizer
-# Copyright 2018 Google Inc. All rights reserved.
+# Copyright 2023 Google Inc. All rights reserved.
 # http://ceres-solver.org/
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/third_party/ceres/cmake/FindCXSparse.cmake b/third_party/ceres/cmake/FindCXSparse.cmake
deleted file mode 100644
index 8b380c9..0000000
--- a/third_party/ceres/cmake/FindCXSparse.cmake
+++ /dev/null
@@ -1,261 +0,0 @@
-# Ceres Solver - A fast non-linear least squares minimizer
-# Copyright 2015 Google Inc. All rights reserved.
-# http://ceres-solver.org/
-#
-# 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 Google Inc. 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.
-#
-# Author: alexs.mac@gmail.com (Alex Stewart)
-#
-
-# FindCXSparse.cmake - Find CXSparse libraries & dependencies.
-#
-# This module defines the following variables which should be referenced
-# by the caller to use the library.
-#
-# CXSPARSE_FOUND: TRUE iff CXSparse and all dependencies have been found.
-# CXSPARSE_INCLUDE_DIRS: Include directories for CXSparse.
-# CXSPARSE_LIBRARIES: Libraries for CXSparse and all dependencies.
-#
-# CXSPARSE_VERSION: Extracted from cs.h.
-# CXSPARSE_MAIN_VERSION: Equal to 3 if CXSPARSE_VERSION = 3.1.2
-# CXSPARSE_SUB_VERSION: Equal to 1 if CXSPARSE_VERSION = 3.1.2
-# CXSPARSE_SUBSUB_VERSION: Equal to 2 if CXSPARSE_VERSION = 3.1.2
-#
-# The following variables control the behaviour of this module:
-#
-# CXSPARSE_INCLUDE_DIR_HINTS: List of additional directories in which to
-#                             search for CXSparse includes,
-#                             e.g: /timbuktu/include.
-# CXSPARSE_LIBRARY_DIR_HINTS: List of additional directories in which to
-#                             search for CXSparse libraries, e.g: /timbuktu/lib.
-#
-# The following variables are also defined by this module, but in line with
-# CMake recommended FindPackage() module style should NOT be referenced directly
-# by callers (use the plural variables detailed above instead).  These variables
-# do however affect the behaviour of the module via FIND_[PATH/LIBRARY]() which
-# are NOT re-called (i.e. search for library is not repeated) if these variables
-# are set with valid values _in the CMake cache_. This means that if these
-# variables are set directly in the cache, either by the user in the CMake GUI,
-# or by the user passing -DVAR=VALUE directives to CMake when called (which
-# explicitly defines a cache variable), then they will be used verbatim,
-# bypassing the HINTS variables and other hard-coded search locations.
-#
-# CXSPARSE_INCLUDE_DIR: Include directory for CXSparse, not including the
-#                       include directory of any dependencies.
-# CXSPARSE_LIBRARY: CXSparse library, not including the libraries of any
-#                   dependencies.
-
-# Reset CALLERS_CMAKE_FIND_LIBRARY_PREFIXES to its value when
-# FindCXSparse was invoked.
-macro(CXSPARSE_RESET_FIND_LIBRARY_PREFIX)
-  if (MSVC)
-    set(CMAKE_FIND_LIBRARY_PREFIXES "${CALLERS_CMAKE_FIND_LIBRARY_PREFIXES}")
-  endif (MSVC)
-endmacro(CXSPARSE_RESET_FIND_LIBRARY_PREFIX)
-
-# Called if we failed to find CXSparse or any of it's required dependencies,
-# unsets all public (designed to be used externally) variables and reports
-# error message at priority depending upon [REQUIRED/QUIET/<NONE>] argument.
-macro(CXSPARSE_REPORT_NOT_FOUND REASON_MSG)
-  unset(CXSPARSE_FOUND)
-  unset(CXSPARSE_INCLUDE_DIRS)
-  unset(CXSPARSE_LIBRARIES)
-  # Make results of search visible in the CMake GUI if CXSparse has not
-  # been found so that user does not have to toggle to advanced view.
-  mark_as_advanced(CLEAR CXSPARSE_INCLUDE_DIR
-                         CXSPARSE_LIBRARY)
-
-  cxsparse_reset_find_library_prefix()
-
-  # Note <package>_FIND_[REQUIRED/QUIETLY] variables defined by FindPackage()
-  # use the camelcase library name, not uppercase.
-  if (CXSparse_FIND_QUIETLY)
-    message(STATUS "Failed to find CXSparse - " ${REASON_MSG} ${ARGN})
-  elseif (CXSparse_FIND_REQUIRED)
-    message(FATAL_ERROR "Failed to find CXSparse - " ${REASON_MSG} ${ARGN})
-  else()
-    # Neither QUIETLY nor REQUIRED, use no priority which emits a message
-    # but continues configuration and allows generation.
-    message("-- Failed to find CXSparse - " ${REASON_MSG} ${ARGN})
-  endif ()
-  return()
-endmacro(CXSPARSE_REPORT_NOT_FOUND)
-
-# Protect against any alternative find_package scripts for this library having
-# been called previously (in a client project) which set CXSPARSE_FOUND, but not
-# the other variables we require / set here which could cause the search logic
-# here to fail.
-unset(CXSPARSE_FOUND)
-
-# Handle possible presence of lib prefix for libraries on MSVC, see
-# also CXSPARSE_RESET_FIND_LIBRARY_PREFIX().
-if (MSVC)
-  # Preserve the caller's original values for CMAKE_FIND_LIBRARY_PREFIXES
-  # s/t we can set it back before returning.
-  set(CALLERS_CMAKE_FIND_LIBRARY_PREFIXES "${CMAKE_FIND_LIBRARY_PREFIXES}")
-  # The empty string in this list is important, it represents the case when
-  # the libraries have no prefix (shared libraries / DLLs).
-  set(CMAKE_FIND_LIBRARY_PREFIXES "lib" "" "${CMAKE_FIND_LIBRARY_PREFIXES}")
-endif (MSVC)
-
-# On macOS, add the Homebrew prefix (with appropriate suffixes) to the
-# respective HINTS directories (after any user-specified locations).  This
-# handles Homebrew installations into non-standard locations (not /usr/local).
-# We do not use CMAKE_PREFIX_PATH for this as given the search ordering of
-# find_xxx(), doing so would override any user-specified HINTS locations with
-# the Homebrew version if it exists.
-if (CMAKE_SYSTEM_NAME MATCHES "Darwin")
-  find_program(HOMEBREW_EXECUTABLE brew)
-  mark_as_advanced(FORCE HOMEBREW_EXECUTABLE)
-  if (HOMEBREW_EXECUTABLE)
-    # Detected a Homebrew install, query for its install prefix.
-    execute_process(COMMAND ${HOMEBREW_EXECUTABLE} --prefix
-      OUTPUT_VARIABLE HOMEBREW_INSTALL_PREFIX
-      OUTPUT_STRIP_TRAILING_WHITESPACE)
-    message(STATUS "Detected Homebrew with install prefix: "
-      "${HOMEBREW_INSTALL_PREFIX}, adding to CMake search paths.")
-    list(APPEND CXSPARSE_INCLUDE_DIR_HINTS "${HOMEBREW_INSTALL_PREFIX}/include")
-    list(APPEND CXSPARSE_LIBRARY_DIR_HINTS "${HOMEBREW_INSTALL_PREFIX}/lib")
-  endif()
-endif()
-
-# Search user-installed locations first, so that we prefer user installs
-# to system installs where both exist.
-#
-# TODO: Add standard Windows search locations for CXSparse.
-list(APPEND CXSPARSE_CHECK_INCLUDE_DIRS
-  /usr/local/include
-  /usr/local/homebrew/include # Mac OS X
-  /opt/local/var/macports/software # Mac OS X.
-  /opt/local/include
-  /usr/include)
-list(APPEND CXSPARSE_CHECK_LIBRARY_DIRS
-  /usr/local/lib
-  /usr/local/homebrew/lib # Mac OS X.
-  /opt/local/lib
-  /usr/lib)
-# Additional suffixes to try appending to each search path.
-list(APPEND CXSPARSE_CHECK_PATH_SUFFIXES
-  suitesparse) # Linux/Windows
-
-# Search supplied hint directories first if supplied.
-find_path(CXSPARSE_INCLUDE_DIR
-  NAMES cs.h
-  HINTS ${CXSPARSE_INCLUDE_DIR_HINTS}
-  PATHS ${CXSPARSE_CHECK_INCLUDE_DIRS}
-  PATH_SUFFIXES ${CXSPARSE_CHECK_PATH_SUFFIXES})
-if (NOT CXSPARSE_INCLUDE_DIR OR
-    NOT EXISTS ${CXSPARSE_INCLUDE_DIR})
-  cxsparse_report_not_found(
-    "Could not find CXSparse include directory, set CXSPARSE_INCLUDE_DIR "
-    "to directory containing cs.h")
-endif (NOT CXSPARSE_INCLUDE_DIR OR
-       NOT EXISTS ${CXSPARSE_INCLUDE_DIR})
-
-find_library(CXSPARSE_LIBRARY NAMES cxsparse
-  HINTS ${CXSPARSE_LIBRARY_DIR_HINTS}
-  PATHS ${CXSPARSE_CHECK_LIBRARY_DIRS}
-  PATH_SUFFIXES ${CXSPARSE_CHECK_PATH_SUFFIXES})
-if (NOT CXSPARSE_LIBRARY OR
-    NOT EXISTS ${CXSPARSE_LIBRARY})
-  cxsparse_report_not_found(
-    "Could not find CXSparse library, set CXSPARSE_LIBRARY "
-    "to full path to libcxsparse.")
-endif (NOT CXSPARSE_LIBRARY OR
-       NOT EXISTS ${CXSPARSE_LIBRARY})
-
-# Mark internally as found, then verify. CXSPARSE_REPORT_NOT_FOUND() unsets
-# if called.
-set(CXSPARSE_FOUND TRUE)
-
-# Extract CXSparse version from cs.h
-if (CXSPARSE_INCLUDE_DIR)
-  set(CXSPARSE_VERSION_FILE ${CXSPARSE_INCLUDE_DIR}/cs.h)
-  if (NOT EXISTS ${CXSPARSE_VERSION_FILE})
-    cxsparse_report_not_found(
-      "Could not find file: ${CXSPARSE_VERSION_FILE} "
-      "containing version information in CXSparse install located at: "
-      "${CXSPARSE_INCLUDE_DIR}.")
-  else (NOT EXISTS ${CXSPARSE_VERSION_FILE})
-    file(READ ${CXSPARSE_INCLUDE_DIR}/cs.h CXSPARSE_VERSION_FILE_CONTENTS)
-
-    string(REGEX MATCH "#define CS_VER [0-9]+"
-      CXSPARSE_MAIN_VERSION "${CXSPARSE_VERSION_FILE_CONTENTS}")
-    string(REGEX REPLACE "#define CS_VER ([0-9]+)" "\\1"
-      CXSPARSE_MAIN_VERSION "${CXSPARSE_MAIN_VERSION}")
-
-    string(REGEX MATCH "#define CS_SUBVER [0-9]+"
-      CXSPARSE_SUB_VERSION "${CXSPARSE_VERSION_FILE_CONTENTS}")
-    string(REGEX REPLACE "#define CS_SUBVER ([0-9]+)" "\\1"
-      CXSPARSE_SUB_VERSION "${CXSPARSE_SUB_VERSION}")
-
-    string(REGEX MATCH "#define CS_SUBSUB [0-9]+"
-      CXSPARSE_SUBSUB_VERSION "${CXSPARSE_VERSION_FILE_CONTENTS}")
-    string(REGEX REPLACE "#define CS_SUBSUB ([0-9]+)" "\\1"
-      CXSPARSE_SUBSUB_VERSION "${CXSPARSE_SUBSUB_VERSION}")
-
-    # This is on a single line s/t CMake does not interpret it as a list of
-    # elements and insert ';' separators which would result in 3.;1.;2 nonsense.
-    set(CXSPARSE_VERSION "${CXSPARSE_MAIN_VERSION}.${CXSPARSE_SUB_VERSION}.${CXSPARSE_SUBSUB_VERSION}")
-  endif (NOT EXISTS ${CXSPARSE_VERSION_FILE})
-endif (CXSPARSE_INCLUDE_DIR)
-
-# Catch the case when the caller has set CXSPARSE_LIBRARY in the cache / GUI and
-# thus FIND_LIBRARY was not called, but specified library is invalid, otherwise
-# we would report CXSparse as found.
-# TODO: This regex for CXSparse library is pretty primitive, we use lowercase
-#       for comparison to handle Windows using CamelCase library names, could
-#       this check be better?
-string(TOLOWER "${CXSPARSE_LIBRARY}" LOWERCASE_CXSPARSE_LIBRARY)
-if (CXSPARSE_LIBRARY AND
-    EXISTS ${CXSPARSE_LIBRARY} AND
-    NOT "${LOWERCASE_CXSPARSE_LIBRARY}" MATCHES ".*cxsparse[^/]*")
-  cxsparse_report_not_found(
-    "Caller defined CXSPARSE_LIBRARY: "
-    "${CXSPARSE_LIBRARY} does not match CXSparse.")
-endif (CXSPARSE_LIBRARY AND
-       EXISTS ${CXSPARSE_LIBRARY} AND
-       NOT "${LOWERCASE_CXSPARSE_LIBRARY}" MATCHES ".*cxsparse[^/]*")
-
-# Set standard CMake FindPackage variables if found.
-if (CXSPARSE_FOUND)
-  set(CXSPARSE_INCLUDE_DIRS ${CXSPARSE_INCLUDE_DIR})
-  set(CXSPARSE_LIBRARIES ${CXSPARSE_LIBRARY})
-endif (CXSPARSE_FOUND)
-
-cxsparse_reset_find_library_prefix()
-
-# Handle REQUIRED / QUIET optional arguments and version.
-include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(CXSparse
-  REQUIRED_VARS CXSPARSE_INCLUDE_DIRS CXSPARSE_LIBRARIES
-  VERSION_VAR CXSPARSE_VERSION)
-
-# Only mark internal variables as advanced if we found CXSparse, otherwise
-# leave them visible in the standard GUI for the user to set manually.
-if (CXSPARSE_FOUND)
-  mark_as_advanced(FORCE CXSPARSE_INCLUDE_DIR
-                         CXSPARSE_LIBRARY)
-endif (CXSPARSE_FOUND)
diff --git a/third_party/ceres/cmake/FindGlog.cmake b/third_party/ceres/cmake/FindGlog.cmake
index 1a7b6c0..2ef6914 100644
--- a/third_party/ceres/cmake/FindGlog.cmake
+++ b/third_party/ceres/cmake/FindGlog.cmake
@@ -1,5 +1,5 @@
 # Ceres Solver - A fast non-linear least squares minimizer
-# Copyright 2015 Google Inc. All rights reserved.
+# Copyright 2023 Google Inc. All rights reserved.
 # http://ceres-solver.org/
 #
 # Redistribution and use in source and binary forms, with or without
@@ -345,6 +345,11 @@
   endif (GLOG_LIBRARY AND
     NOT "${LOWERCASE_GLOG_LIBRARY}" MATCHES ".*glog[^/]*")
 
+  # add glog::glog target
+  add_library(glog::glog INTERFACE IMPORTED)
+  target_include_directories(glog::glog INTERFACE ${GLOG_INCLUDE_DIRS})
+  target_link_libraries(glog::glog INTERFACE ${GLOG_LIBRARY})
+
   glog_reset_find_library_prefix()
 
 endif(NOT GLOG_FOUND)
diff --git a/third_party/ceres/cmake/FindMETIS.cmake b/third_party/ceres/cmake/FindMETIS.cmake
new file mode 100644
index 0000000..5f41792
--- /dev/null
+++ b/third_party/ceres/cmake/FindMETIS.cmake
@@ -0,0 +1,110 @@
+#
+# Copyright (c) 2022 Sergiu Deitsch
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTMETISLAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+#[=======================================================================[.rst:
+Module for locating METIS
+=========================
+
+Read-only variables:
+
+``METIS_FOUND``
+  Indicates whether the library has been found.
+
+``METIS_VERSION``
+  Indicates library version.
+
+Targets
+-------
+
+``METIS::METIS``
+  Specifies targets that should be passed to target_link_libararies.
+]=======================================================================]
+
+include (FindPackageHandleStandardArgs)
+
+find_path (METIS_INCLUDE_DIR NAMES metis.h
+  PATH_SUFFIXES include
+  DOC "METIS include directory")
+find_library (METIS_LIBRARY_DEBUG NAMES metis
+  PATH_SUFFIXES Debug
+  DOC "METIS debug library")
+find_library (METIS_LIBRARY_RELEASE NAMES metis
+  PATH_SUFFIXES Release
+  DOC "METIS release library")
+
+if (METIS_LIBRARY_RELEASE)
+  if (METIS_LIBRARY_DEBUG)
+    set (METIS_LIBRARY debug ${METIS_LIBRARY_DEBUG} optimized
+      ${METIS_LIBRARY_RELEASE} CACHE STRING "METIS library")
+  else (METIS_LIBRARY_DEBUG)
+    set (METIS_LIBRARY ${METIS_LIBRARY_RELEASE} CACHE FILEPATH "METIS library")
+  endif (METIS_LIBRARY_DEBUG)
+elseif (METIS_LIBRARY_DEBUG)
+  set (METIS_LIBRARY ${METIS_LIBRARY_DEBUG} CACHE FILEPATH "METIS library")
+endif (METIS_LIBRARY_RELEASE)
+
+set (_METIS_VERSION_HEADER ${METIS_INCLUDE_DIR}/metis.h)
+
+if (EXISTS ${_METIS_VERSION_HEADER})
+  file (READ ${_METIS_VERSION_HEADER} _METIS_VERSION_CONTENTS)
+
+  string (REGEX REPLACE ".*#define METIS_VER_MAJOR[ \t]+([0-9]+).*" "\\1"
+    METIS_VERSION_MAJOR "${_METIS_VERSION_CONTENTS}")
+  string (REGEX REPLACE ".*#define METIS_VER_MINOR[ \t]+([0-9]+).*" "\\1"
+    METIS_VERSION_MINOR "${_METIS_VERSION_CONTENTS}")
+  string (REGEX REPLACE ".*#define METIS_VER_SUBMINOR[ \t]+([0-9]+).*" "\\1"
+    METIS_VERSION_PATCH "${_METIS_VERSION_CONTENTS}")
+
+  set (METIS_VERSION
+    ${METIS_VERSION_MAJOR}.${METIS_VERSION_MINOR}.${METIS_VERSION_PATCH})
+  set (METIS_VERSION_COMPONENTS 3)
+endif (EXISTS ${_METIS_VERSION_HEADER})
+
+mark_as_advanced (METIS_INCLUDE_DIR METIS_LIBRARY_DEBUG METIS_LIBRARY_RELEASE
+  METIS_LIBRARY)
+
+if (NOT TARGET METIS::METIS)
+  if (METIS_INCLUDE_DIR OR METIS_LIBRARY)
+    add_library (METIS::METIS IMPORTED UNKNOWN)
+  endif (METIS_INCLUDE_DIR OR METIS_LIBRARY)
+endif (NOT TARGET METIS::METIS)
+
+if (METIS_INCLUDE_DIR)
+  set_property (TARGET METIS::METIS PROPERTY INTERFACE_INCLUDE_DIRECTORIES
+    ${METIS_INCLUDE_DIR})
+endif (METIS_INCLUDE_DIR)
+
+if (METIS_LIBRARY_RELEASE)
+  set_property (TARGET METIS::METIS PROPERTY IMPORTED_LOCATION_RELEASE
+    ${METIS_LIBRARY_RELEASE})
+  set_property (TARGET METIS::METIS APPEND PROPERTY IMPORTED_CONFIGURATIONS
+    RELEASE)
+endif (METIS_LIBRARY_RELEASE)
+
+if (METIS_LIBRARY_DEBUG)
+  set_property (TARGET METIS::METIS PROPERTY IMPORTED_LOCATION_DEBUG
+    ${METIS_LIBRARY_DEBUG})
+  set_property (TARGET METIS::METIS APPEND PROPERTY IMPORTED_CONFIGURATIONS
+    DEBUG)
+endif (METIS_LIBRARY_DEBUG)
+
+find_package_handle_standard_args (METIS REQUIRED_VARS
+  METIS_INCLUDE_DIR METIS_LIBRARY VERSION_VAR METIS_VERSION)
diff --git a/third_party/ceres/cmake/FindSphinx.cmake b/third_party/ceres/cmake/FindSphinx.cmake
index 220108d..d1488eb 100644
--- a/third_party/ceres/cmake/FindSphinx.cmake
+++ b/third_party/ceres/cmake/FindSphinx.cmake
@@ -1,5 +1,5 @@
 # Ceres Solver - A fast non-linear least squares minimizer
-# Copyright 2015 Google Inc. All rights reserved.
+# Copyright 2023 Google Inc. All rights reserved.
 # http://ceres-solver.org/
 #
 # Redistribution and use in source and binary forms, with or without
@@ -29,38 +29,96 @@
 # Author: pablo.speciale@gmail.com (Pablo Speciale)
 #
 
-# Find the Sphinx documentation generator
-#
-# This modules defines
-#  SPHINX_EXECUTABLE
-#  SPHINX_FOUND
+#[=======================================================================[.rst:
+FindSphinx
+==========
 
-find_program(SPHINX_EXECUTABLE
-             NAMES sphinx-build
-             PATHS
-               /usr/bin
-               /usr/local/bin
-               /opt/local/bin
-             DOC "Sphinx documentation generator")
+Module for locating Sphinx and its components.
 
-if (NOT SPHINX_EXECUTABLE)
-  set(_Python_VERSIONS 2.7 2.6 2.5 2.4 2.3 2.2 2.1 2.0 1.6 1.5)
+This modules defines the following variables:
 
-  foreach (_version ${_Python_VERSIONS})
-    set(_sphinx_NAMES sphinx-build-${_version})
+``Sphinx_FOUND``
+  ``TRUE`` iff Sphinx and all of its components have been found.
 
-    find_program(SPHINX_EXECUTABLE
-                 NAMES ${_sphinx_NAMES}
-                 PATHS
-                   /usr/bin
-                   /usr/local/bin
-                   /opt/local/bin
-                 DOC "Sphinx documentation generator")
-  endforeach ()
-endif ()
+``Sphinx_BUILD_EXECUTABLE``
+  Path to the ``sphinx-build`` tool.
+]=======================================================================]
 
-include(FindPackageHandleStandardArgs)
+include (FindPackageHandleStandardArgs)
 
-find_package_handle_standard_args(Sphinx DEFAULT_MSG SPHINX_EXECUTABLE)
+find_program (Sphinx_BUILD_EXECUTABLE
+  NAMES sphinx-build
+  PATHS /opt/local/bin
+  DOC "Sphinx documentation generator"
+)
 
-mark_as_advanced(SPHINX_EXECUTABLE)
+mark_as_advanced (Sphinx_BUILD_EXECUTABLE)
+
+if (Sphinx_BUILD_EXECUTABLE)
+  execute_process (
+    COMMAND ${Sphinx_BUILD_EXECUTABLE} --version
+    ERROR_STRIP_TRAILING_WHITESPACE
+    ERROR_VARIABLE _Sphinx_BUILD_ERROR
+    OUTPUT_STRIP_TRAILING_WHITESPACE
+    OUTPUT_VARIABLE _Sphinx_VERSION_STRING
+    RESULT_VARIABLE _Sphinx_BUILD_RESULT
+  )
+
+  if (_Sphinx_BUILD_RESULT EQUAL 0)
+    string (REGEX REPLACE "^sphinx-build[ \t]+([^ \t]+)$" "\\1" Sphinx_VERSION
+      "${_Sphinx_VERSION_STRING}")
+
+    if (Sphinx_VERSION MATCHES "[0-9]+\\.[0-9]+\\.[0-9]+")
+      set (Sphinx_VERSION_COMPONENTS 3)
+      set (Sphinx_VERSION_MAJOR ${CMAKE_MATCH_1})
+      set (Sphinx_VERSION_MINOR ${CMAKE_MATCH_2})
+      set (Sphinx_VERSION_PATCH ${CMAKE_MATCH_3})
+    endif (Sphinx_VERSION MATCHES "[0-9]+\\.[0-9]+\\.[0-9]+")
+  else (_Sphinx_BUILD_RESULT EQUAL 0)
+    message (WARNING "Could not determine sphinx-build version: ${_Sphinx_BUILD_ERROR}")
+  endif (_Sphinx_BUILD_RESULT EQUAL 0)
+
+  unset (_Sphinx_BUILD_ERROR)
+  unset (_Sphinx_BUILD_RESULT)
+  unset (_Sphinx_VERSION_STRING)
+
+  find_package (Python COMPONENTS Interpreter)
+  set (_Sphinx_BUILD_RESULT FALSE)
+
+  if (Python_Interpreter_FOUND)
+    # Check for Sphinx theme dependency for documentation
+    foreach (component IN LISTS Sphinx_FIND_COMPONENTS)
+      string (REGEX MATCH "^(.+_theme)$" theme_component "${component}")
+
+      if (NOT theme_component STREQUAL component)
+        continue ()
+      endif (NOT theme_component STREQUAL component)
+
+      execute_process (
+        COMMAND ${Python_EXECUTABLE} -c "import ${theme_component}"
+        ERROR_STRIP_TRAILING_WHITESPACE
+        ERROR_VARIABLE _Sphinx_BUILD_ERROR
+        OUTPUT_QUIET
+        RESULT_VARIABLE _Sphinx_BUILD_RESULT
+      )
+
+      if (_Sphinx_BUILD_RESULT EQUAL 0)
+        set (Sphinx_${component}_FOUND TRUE)
+      elseif (_Sphinx_BUILD_RESULT EQUAL 0)
+        message (WARNING "Could not determine whether Sphinx component '${theme_component}' is available: ${_Sphinx_BUILD_ERROR}")
+        set (Sphinx_${component}_FOUND FALSE)
+      endif (_Sphinx_BUILD_RESULT EQUAL 0)
+
+      unset (_Sphinx_BUILD_ERROR)
+      unset (_Sphinx_BUILD_RESULT)
+    endforeach (component)
+
+    unset (theme_component)
+  endif (Python_Interpreter_FOUND)
+endif (Sphinx_BUILD_EXECUTABLE)
+
+find_package_handle_standard_args (Sphinx
+  REQUIRED_VARS Sphinx_BUILD_EXECUTABLE
+  VERSION_VAR Sphinx_VERSION
+  HANDLE_COMPONENTS
+)
diff --git a/third_party/ceres/cmake/FindSuiteSparse.cmake b/third_party/ceres/cmake/FindSuiteSparse.cmake
index aad8904..49c089c 100644
--- a/third_party/ceres/cmake/FindSuiteSparse.cmake
+++ b/third_party/ceres/cmake/FindSuiteSparse.cmake
@@ -1,5 +1,5 @@
 # Ceres Solver - A fast non-linear least squares minimizer
-# Copyright 2015 Google Inc. All rights reserved.
+# Copyright 2023 Google Inc. All rights reserved.
 # http://ceres-solver.org/
 #
 # Redistribution and use in source and binary forms, with or without
@@ -29,103 +29,146 @@
 # Author: alexs.mac@gmail.com (Alex Stewart)
 #
 
-# FindSuiteSparse.cmake - Find SuiteSparse libraries & dependencies.
-#
-# This module defines the following variables:
-#
-# SUITESPARSE_FOUND: TRUE iff SuiteSparse and all dependencies have been found.
-# SUITESPARSE_INCLUDE_DIRS: Include directories for all SuiteSparse components.
-# SUITESPARSE_LIBRARIES: Libraries for all SuiteSparse component libraries and
-#                        dependencies.
-# SUITESPARSE_VERSION: Extracted from UFconfig.h (<= v3) or
-#                      SuiteSparse_config.h (>= v4).
-# SUITESPARSE_MAIN_VERSION: Equal to 4 if SUITESPARSE_VERSION = 4.2.1
-# SUITESPARSE_SUB_VERSION: Equal to 2 if SUITESPARSE_VERSION = 4.2.1
-# SUITESPARSE_SUBSUB_VERSION: Equal to 1 if SUITESPARSE_VERSION = 4.2.1
-#
-# SUITESPARSE_IS_BROKEN_SHARED_LINKING_UBUNTU_SYSTEM_VERSION: TRUE iff running
-#     on Ubuntu, SUITESPARSE_VERSION is 3.4.0 and found SuiteSparse is a system
-#     install, in which case found version of SuiteSparse cannot be used to link
-#     a shared library due to a bug (static linking is unaffected).
-#
-# The following variables control the behaviour of this module:
-#
-# SUITESPARSE_INCLUDE_DIR_HINTS: List of additional directories in which to
-#                                search for SuiteSparse includes,
-#                                e.g: /timbuktu/include.
-# SUITESPARSE_LIBRARY_DIR_HINTS: List of additional directories in which to
-#                                search for SuiteSparse libraries,
-#                                e.g: /timbuktu/lib.
-#
-# The following variables define the presence / includes & libraries for the
-# SuiteSparse components searched for, the SUITESPARSE_XX variables are the
-# union of the variables for all components.
-#
-# == Symmetric Approximate Minimum Degree (AMD)
-# AMD_FOUND
-# AMD_INCLUDE_DIR
-# AMD_LIBRARY
-#
-# == Constrained Approximate Minimum Degree (CAMD)
-# CAMD_FOUND
-# CAMD_INCLUDE_DIR
-# CAMD_LIBRARY
-#
-# == Column Approximate Minimum Degree (COLAMD)
-# COLAMD_FOUND
-# COLAMD_INCLUDE_DIR
-# COLAMD_LIBRARY
-#
-# Constrained Column Approximate Minimum Degree (CCOLAMD)
-# CCOLAMD_FOUND
-# CCOLAMD_INCLUDE_DIR
-# CCOLAMD_LIBRARY
-#
-# == Sparse Supernodal Cholesky Factorization and Update/Downdate (CHOLMOD)
-# CHOLMOD_FOUND
-# CHOLMOD_INCLUDE_DIR
-# CHOLMOD_LIBRARY
-#
-# == Multifrontal Sparse QR (SuiteSparseQR)
-# SUITESPARSEQR_FOUND
-# SUITESPARSEQR_INCLUDE_DIR
-# SUITESPARSEQR_LIBRARY
-#
-# == Common configuration for all but CSparse (SuiteSparse version >= 4).
-# SUITESPARSE_CONFIG_FOUND
-# SUITESPARSE_CONFIG_INCLUDE_DIR
-# SUITESPARSE_CONFIG_LIBRARY
-#
-# == Common configuration for all but CSparse (SuiteSparse version < 4).
-# UFCONFIG_FOUND
-# UFCONFIG_INCLUDE_DIR
-#
-# Optional SuiteSparse Dependencies:
-#
-# == Serial Graph Partitioning and Fill-reducing Matrix Ordering (METIS)
-# METIS_FOUND
-# METIS_LIBRARY
+#[=======================================================================[.rst:
+FindSuiteSparse
+===============
+
+Module for locating SuiteSparse libraries and its dependencies.
+
+This module defines the following variables:
+
+``SuiteSparse_FOUND``
+   ``TRUE`` iff SuiteSparse and all dependencies have been found.
+
+``SuiteSparse_VERSION``
+   Extracted from ``SuiteSparse_config.h`` (>= v4).
+
+``SuiteSparse_VERSION_MAJOR``
+    Equal to 4 if ``SuiteSparse_VERSION`` = 4.2.1
+
+``SuiteSparse_VERSION_MINOR``
+    Equal to 2 if ``SuiteSparse_VERSION`` = 4.2.1
+
+``SuiteSparse_VERSION_PATCH``
+    Equal to 1 if ``SuiteSparse_VERSION`` = 4.2.1
+
+The following variables control the behaviour of this module:
+
+``SuiteSparse_NO_CMAKE``
+  Do not attempt to use the native SuiteSparse CMake package configuration.
+
+
+Targets
+-------
+
+The following targets define the SuiteSparse components searched for.
+
+``SuiteSparse::AMD``
+    Symmetric Approximate Minimum Degree (AMD)
+
+``SuiteSparse::CAMD``
+    Constrained Approximate Minimum Degree (CAMD)
+
+``SuiteSparse::COLAMD``
+    Column Approximate Minimum Degree (COLAMD)
+
+``SuiteSparse::CCOLAMD``
+    Constrained Column Approximate Minimum Degree (CCOLAMD)
+
+``SuiteSparse::CHOLMOD``
+    Sparse Supernodal Cholesky Factorization and Update/Downdate (CHOLMOD)
+
+``SuiteSparse::Partition``
+    CHOLMOD with METIS support
+
+``SuiteSparse::SPQR``
+    Multifrontal Sparse QR (SuiteSparseQR)
+
+``SuiteSparse::Config``
+    Common configuration for all but CSparse (SuiteSparse version >= 4).
+
+Optional SuiteSparse dependencies:
+
+``METIS::METIS``
+    Serial Graph Partitioning and Fill-reducing Matrix Ordering (METIS)
+]=======================================================================]
+
+if (NOT SuiteSparse_NO_CMAKE)
+  find_package (SuiteSparse NO_MODULE QUIET)
+endif (NOT SuiteSparse_NO_CMAKE)
+
+if (SuiteSparse_FOUND)
+  return ()
+endif (SuiteSparse_FOUND)
+
+# Push CMP0057 to enable support for IN_LIST, when cmake_minimum_required is
+# set to <3.3.
+cmake_policy (PUSH)
+cmake_policy (SET CMP0057 NEW)
+
+if (NOT SuiteSparse_FIND_COMPONENTS)
+  set (SuiteSparse_FIND_COMPONENTS
+    AMD
+    CAMD
+    CCOLAMD
+    CHOLMOD
+    COLAMD
+    SPQR
+  )
+
+  foreach (component IN LISTS SuiteSparse_FIND_COMPONENTS)
+    set (SuiteSparse_FIND_REQUIRED_${component} TRUE)
+  endforeach (component IN LISTS SuiteSparse_FIND_COMPONENTS)
+endif (NOT SuiteSparse_FIND_COMPONENTS)
+
+# Assume SuiteSparse was found and set it to false only if third-party
+# dependencies could not be located. SuiteSparse components are handled by
+# FindPackageHandleStandardArgs HANDLE_COMPONENTS option.
+set (SuiteSparse_FOUND TRUE)
+
+include (CheckLibraryExists)
+include (CheckSymbolExists)
+include (CMakePushCheckState)
+
+# Config is a base component and thus always required
+set (SuiteSparse_IMPLICIT_COMPONENTS Config)
+
+# CHOLMOD depends on AMD, CAMD, CCOLAMD, and COLAMD.
+if (CHOLMOD IN_LIST SuiteSparse_FIND_COMPONENTS)
+  list (APPEND SuiteSparse_IMPLICIT_COMPONENTS AMD CAMD CCOLAMD COLAMD)
+endif (CHOLMOD IN_LIST SuiteSparse_FIND_COMPONENTS)
+
+# SPQR depends on CHOLMOD.
+if (SPQR IN_LIST SuiteSparse_FIND_COMPONENTS)
+  list (APPEND SuiteSparse_IMPLICIT_COMPONENTS CHOLMOD)
+endif (SPQR IN_LIST SuiteSparse_FIND_COMPONENTS)
+
+# Implicit components are always required
+foreach (component IN LISTS SuiteSparse_IMPLICIT_COMPONENTS)
+  set (SuiteSparse_FIND_REQUIRED_${component} TRUE)
+endforeach (component IN LISTS SuiteSparse_IMPLICIT_COMPONENTS)
+
+list (APPEND SuiteSparse_FIND_COMPONENTS ${SuiteSparse_IMPLICIT_COMPONENTS})
+
+# Do not list components multiple times.
+list (REMOVE_DUPLICATES SuiteSparse_FIND_COMPONENTS)
 
 # Reset CALLERS_CMAKE_FIND_LIBRARY_PREFIXES to its value when
 # FindSuiteSparse was invoked.
-macro(SUITESPARSE_RESET_FIND_LIBRARY_PREFIX)
+macro(SuiteSparse_RESET_FIND_LIBRARY_PREFIX)
   if (MSVC)
     set(CMAKE_FIND_LIBRARY_PREFIXES "${CALLERS_CMAKE_FIND_LIBRARY_PREFIXES}")
   endif (MSVC)
-endmacro(SUITESPARSE_RESET_FIND_LIBRARY_PREFIX)
+endmacro(SuiteSparse_RESET_FIND_LIBRARY_PREFIX)
 
 # Called if we failed to find SuiteSparse or any of it's required dependencies,
 # unsets all public (designed to be used externally) variables and reports
 # error message at priority depending upon [REQUIRED/QUIET/<NONE>] argument.
-macro(SUITESPARSE_REPORT_NOT_FOUND REASON_MSG)
-  unset(SUITESPARSE_FOUND)
-  unset(SUITESPARSE_INCLUDE_DIRS)
-  unset(SUITESPARSE_LIBRARIES)
-  unset(SUITESPARSE_VERSION)
-  unset(SUITESPARSE_MAIN_VERSION)
-  unset(SUITESPARSE_SUB_VERSION)
-  unset(SUITESPARSE_SUBSUB_VERSION)
-  # Do NOT unset SUITESPARSE_FOUND_REQUIRED_VARS here, as it is used by
+macro(SuiteSparse_REPORT_NOT_FOUND REASON_MSG)
+  # Will be set to FALSE by find_package_handle_standard_args
+  unset (SuiteSparse_FOUND)
+
+  # Do NOT unset SuiteSparse_REQUIRED_VARS here, as it is used by
   # FindPackageHandleStandardArgs() to generate the automatic error message on
   # failure which highlights which components are missing.
 
@@ -146,16 +189,10 @@
   # Do not call return(), s/t we keep processing if not called with REQUIRED
   # and report all missing components, rather than bailing after failing to find
   # the first.
-endmacro(SUITESPARSE_REPORT_NOT_FOUND)
-
-# Protect against any alternative find_package scripts for this library having
-# been called previously (in a client project) which set SUITESPARSE_FOUND, but
-# not the other variables we require / set here which could cause the search
-# logic here to fail.
-unset(SUITESPARSE_FOUND)
+endmacro(SuiteSparse_REPORT_NOT_FOUND)
 
 # Handle possible presence of lib prefix for libraries on MSVC, see
-# also SUITESPARSE_RESET_FIND_LIBRARY_PREFIX().
+# also SuiteSparse_RESET_FIND_LIBRARY_PREFIX().
 if (MSVC)
   # Preserve the caller's original values for CMAKE_FIND_LIBRARY_PREFIXES
   # s/t we can set it back before returning.
@@ -165,119 +202,92 @@
   set(CMAKE_FIND_LIBRARY_PREFIXES "lib" "" "${CMAKE_FIND_LIBRARY_PREFIXES}")
 endif (MSVC)
 
-# On macOS, add the Homebrew prefix (with appropriate suffixes) to the
-# respective HINTS directories (after any user-specified locations).  This
-# handles Homebrew installations into non-standard locations (not /usr/local).
-# We do not use CMAKE_PREFIX_PATH for this as given the search ordering of
-# find_xxx(), doing so would override any user-specified HINTS locations with
-# the Homebrew version if it exists.
-if (CMAKE_SYSTEM_NAME MATCHES "Darwin")
-  find_program(HOMEBREW_EXECUTABLE brew)
-  mark_as_advanced(FORCE HOMEBREW_EXECUTABLE)
-  if (HOMEBREW_EXECUTABLE)
-    # Detected a Homebrew install, query for its install prefix.
-    execute_process(COMMAND ${HOMEBREW_EXECUTABLE} --prefix
-      OUTPUT_VARIABLE HOMEBREW_INSTALL_PREFIX
-      OUTPUT_STRIP_TRAILING_WHITESPACE)
-    message(STATUS "Detected Homebrew with install prefix: "
-      "${HOMEBREW_INSTALL_PREFIX}, adding to CMake search paths.")
-    list(APPEND SUITESPARSE_INCLUDE_DIR_HINTS "${HOMEBREW_INSTALL_PREFIX}/include")
-    list(APPEND SUITESPARSE_LIBRARY_DIR_HINTS "${HOMEBREW_INSTALL_PREFIX}/lib")
-  endif()
-endif()
-
-# Specify search directories for include files and libraries (this is the union
-# of the search directories for all OSs).  Search user-specified hint
-# directories first if supplied, and search user-installed locations first
-# so that we prefer user installs to system installs where both exist.
-list(APPEND SUITESPARSE_CHECK_INCLUDE_DIRS
-  /opt/local/include
-  /opt/local/include/ufsparse # Mac OS X
-  /usr/local/homebrew/include # Mac OS X
-  /usr/local/include
-  /usr/include)
-list(APPEND SUITESPARSE_CHECK_LIBRARY_DIRS
-  /opt/local/lib
-  /opt/local/lib/ufsparse # Mac OS X
-  /usr/local/homebrew/lib # Mac OS X
-  /usr/local/lib
-  /usr/lib)
 # Additional suffixes to try appending to each search path.
-list(APPEND SUITESPARSE_CHECK_PATH_SUFFIXES
+list(APPEND SuiteSparse_CHECK_PATH_SUFFIXES
   suitesparse) # Windows/Ubuntu
 
 # Wrappers to find_path/library that pass the SuiteSparse search hints/paths.
 #
 # suitesparse_find_component(<component> [FILES name1 [name2 ...]]
-#                                        [LIBRARIES name1 [name2 ...]]
-#                                        [REQUIRED])
+#                                        [LIBRARIES name1 [name2 ...]])
 macro(suitesparse_find_component COMPONENT)
   include(CMakeParseArguments)
-  set(OPTIONS REQUIRED)
   set(MULTI_VALUE_ARGS FILES LIBRARIES)
-  cmake_parse_arguments(SUITESPARSE_FIND_${COMPONENT}
-    "${OPTIONS}" "" "${MULTI_VALUE_ARGS}" ${ARGN})
+  cmake_parse_arguments(SuiteSparse_FIND_COMPONENT_${COMPONENT}
+    "" "" "${MULTI_VALUE_ARGS}" ${ARGN})
 
-  if (SUITESPARSE_FIND_${COMPONENT}_REQUIRED)
-    list(APPEND SUITESPARSE_FOUND_REQUIRED_VARS ${COMPONENT}_FOUND)
-  endif()
-
-  set(${COMPONENT}_FOUND TRUE)
-  if (SUITESPARSE_FIND_${COMPONENT}_FILES)
-    find_path(${COMPONENT}_INCLUDE_DIR
-      NAMES ${SUITESPARSE_FIND_${COMPONENT}_FILES}
-      HINTS ${SUITESPARSE_INCLUDE_DIR_HINTS}
-      PATHS ${SUITESPARSE_CHECK_INCLUDE_DIRS}
-      PATH_SUFFIXES ${SUITESPARSE_CHECK_PATH_SUFFIXES})
-    if (${COMPONENT}_INCLUDE_DIR)
+  set(SuiteSparse_${COMPONENT}_FOUND TRUE)
+  if (SuiteSparse_FIND_COMPONENT_${COMPONENT}_FILES)
+    find_path(SuiteSparse_${COMPONENT}_INCLUDE_DIR
+      NAMES ${SuiteSparse_FIND_COMPONENT_${COMPONENT}_FILES}
+      PATH_SUFFIXES ${SuiteSparse_CHECK_PATH_SUFFIXES})
+    if (SuiteSparse_${COMPONENT}_INCLUDE_DIR)
       message(STATUS "Found ${COMPONENT} headers in: "
-        "${${COMPONENT}_INCLUDE_DIR}")
-      mark_as_advanced(${COMPONENT}_INCLUDE_DIR)
+        "${SuiteSparse_${COMPONENT}_INCLUDE_DIR}")
+      mark_as_advanced(SuiteSparse_${COMPONENT}_INCLUDE_DIR)
     else()
       # Specified headers not found.
-      set(${COMPONENT}_FOUND FALSE)
-      if (SUITESPARSE_FIND_${COMPONENT}_REQUIRED)
+      set(SuiteSparse_${COMPONENT}_FOUND FALSE)
+      if (SuiteSparse_FIND_REQUIRED_${COMPONENT})
         suitesparse_report_not_found(
           "Did not find ${COMPONENT} header (required SuiteSparse component).")
       else()
         message(STATUS "Did not find ${COMPONENT} header (optional "
           "SuiteSparse component).")
         # Hide optional vars from CMake GUI even if not found.
-        mark_as_advanced(${COMPONENT}_INCLUDE_DIR)
+        mark_as_advanced(SuiteSparse_${COMPONENT}_INCLUDE_DIR)
       endif()
     endif()
   endif()
 
-  if (SUITESPARSE_FIND_${COMPONENT}_LIBRARIES)
-    find_library(${COMPONENT}_LIBRARY
-      NAMES ${SUITESPARSE_FIND_${COMPONENT}_LIBRARIES}
-      HINTS ${SUITESPARSE_LIBRARY_DIR_HINTS}
-      PATHS ${SUITESPARSE_CHECK_LIBRARY_DIRS}
-      PATH_SUFFIXES ${SUITESPARSE_CHECK_PATH_SUFFIXES})
-    if (${COMPONENT}_LIBRARY)
-      message(STATUS "Found ${COMPONENT} library: ${${COMPONENT}_LIBRARY}")
-      mark_as_advanced(${COMPONENT}_LIBRARY)
+  if (SuiteSparse_FIND_COMPONENT_${COMPONENT}_LIBRARIES)
+    find_library(SuiteSparse_${COMPONENT}_LIBRARY
+      NAMES ${SuiteSparse_FIND_COMPONENT_${COMPONENT}_LIBRARIES}
+      PATH_SUFFIXES ${SuiteSparse_CHECK_PATH_SUFFIXES})
+    if (SuiteSparse_${COMPONENT}_LIBRARY)
+      message(STATUS "Found ${COMPONENT} library: ${SuiteSparse_${COMPONENT}_LIBRARY}")
+      mark_as_advanced(SuiteSparse_${COMPONENT}_LIBRARY)
     else ()
       # Specified libraries not found.
-      set(${COMPONENT}_FOUND FALSE)
-      if (SUITESPARSE_FIND_${COMPONENT}_REQUIRED)
+      set(SuiteSparse_${COMPONENT}_FOUND FALSE)
+      if (SuiteSparse_FIND_REQUIRED_${COMPONENT})
         suitesparse_report_not_found(
           "Did not find ${COMPONENT} library (required SuiteSparse component).")
       else()
         message(STATUS "Did not find ${COMPONENT} library (optional SuiteSparse "
           "dependency)")
         # Hide optional vars from CMake GUI even if not found.
-        mark_as_advanced(${COMPONENT}_LIBRARY)
+        mark_as_advanced(SuiteSparse_${COMPONENT}_LIBRARY)
       endif()
     endif()
   endif()
+
+  # A component can be optional (given to OPTIONAL_COMPONENTS). However, if the
+  # component is implicit (must be always present, such as the Config component)
+  # assume it be required as well.
+  if (SuiteSparse_FIND_REQUIRED_${COMPONENT})
+    list (APPEND SuiteSparse_REQUIRED_VARS SuiteSparse_${COMPONENT}_INCLUDE_DIR)
+    list (APPEND SuiteSparse_REQUIRED_VARS SuiteSparse_${COMPONENT}_LIBRARY)
+  endif (SuiteSparse_FIND_REQUIRED_${COMPONENT})
+
+  # Define the target only if the include directory and the library were found
+  if (SuiteSparse_${COMPONENT}_INCLUDE_DIR AND SuiteSparse_${COMPONENT}_LIBRARY)
+    if (NOT TARGET SuiteSparse::${COMPONENT})
+      add_library(SuiteSparse::${COMPONENT} IMPORTED UNKNOWN)
+    endif (NOT TARGET SuiteSparse::${COMPONENT})
+
+    set_property(TARGET SuiteSparse::${COMPONENT} PROPERTY
+      INTERFACE_INCLUDE_DIRECTORIES ${SuiteSparse_${COMPONENT}_INCLUDE_DIR})
+    set_property(TARGET SuiteSparse::${COMPONENT} PROPERTY
+      IMPORTED_LOCATION ${SuiteSparse_${COMPONENT}_LIBRARY})
+  endif (SuiteSparse_${COMPONENT}_INCLUDE_DIR AND SuiteSparse_${COMPONENT}_LIBRARY)
 endmacro()
 
 # Given the number of components of SuiteSparse, and to ensure that the
 # automatic failure message generated by FindPackageHandleStandardArgs()
 # when not all required components are found is helpful, we maintain a list
 # of all variables that must be defined for SuiteSparse to be considered found.
-unset(SUITESPARSE_FOUND_REQUIRED_VARS)
+unset(SuiteSparse_REQUIRED_VARS)
 
 # BLAS.
 find_package(BLAS QUIET)
@@ -285,7 +295,6 @@
   suitesparse_report_not_found(
     "Did not find BLAS library (required for SuiteSparse).")
 endif (NOT BLAS_FOUND)
-list(APPEND SUITESPARSE_FOUND_REQUIRED_VARS BLAS_FOUND)
 
 # LAPACK.
 find_package(LAPACK QUIET)
@@ -293,239 +302,226 @@
   suitesparse_report_not_found(
     "Did not find LAPACK library (required for SuiteSparse).")
 endif (NOT LAPACK_FOUND)
-list(APPEND SUITESPARSE_FOUND_REQUIRED_VARS LAPACK_FOUND)
 
-suitesparse_find_component(AMD REQUIRED FILES amd.h LIBRARIES amd)
-suitesparse_find_component(CAMD REQUIRED FILES camd.h LIBRARIES camd)
-suitesparse_find_component(COLAMD REQUIRED FILES colamd.h LIBRARIES colamd)
-suitesparse_find_component(CCOLAMD REQUIRED FILES ccolamd.h LIBRARIES ccolamd)
-suitesparse_find_component(CHOLMOD REQUIRED FILES cholmod.h LIBRARIES cholmod)
-suitesparse_find_component(
-  SUITESPARSEQR REQUIRED FILES SuiteSparseQR.hpp LIBRARIES spqr)
-if (SUITESPARSEQR_FOUND)
+foreach (component IN LISTS SuiteSparse_FIND_COMPONENTS)
+  if (component STREQUAL Partition)
+    # Partition is a meta component that neither provides additional headers nor
+    # a separate library. It is strictly part of CHOLMOD.
+    continue ()
+  endif (component STREQUAL Partition)
+  string (TOLOWER ${component} component_library)
+
+  if (component STREQUAL "Config")
+    set (component_header SuiteSparse_config.h)
+    set (component_library suitesparseconfig)
+  elseif (component STREQUAL "SPQR")
+    set (component_header SuiteSparseQR.hpp)
+  else (component STREQUAL "SPQR")
+    set (component_header ${component_library}.h)
+  endif (component STREQUAL "Config")
+
+  suitesparse_find_component(${component}
+    FILES ${component_header}
+    LIBRARIES ${component_library})
+endforeach (component IN LISTS SuiteSparse_FIND_COMPONENTS)
+
+if (TARGET SuiteSparse::SPQR)
   # SuiteSparseQR may be compiled with Intel Threading Building Blocks,
   # we assume that if TBB is installed, SuiteSparseQR was compiled with
   # support for it, this will do no harm if it wasn't.
-  find_package(TBB QUIET)
+  find_package(TBB QUIET NO_MODULE)
   if (TBB_FOUND)
     message(STATUS "Found Intel Thread Building Blocks (TBB) library "
-      "(${TBB_VERSION_MAJOR}.${TBB_VERSION_MINOR} / ${TBB_INTERFACE_VERSION}) "
-      "include location: ${TBB_INCLUDE_DIRS}. Assuming SuiteSparseQR was "
-      "compiled with TBB.")
+      "(${TBB_VERSION_MAJOR}.${TBB_VERSION_MINOR} / ${TBB_INTERFACE_VERSION}). "
+      "Assuming SuiteSparseQR was compiled with TBB.")
     # Add the TBB libraries to the SuiteSparseQR libraries (the only
     # libraries to optionally depend on TBB).
-    list(APPEND SUITESPARSEQR_LIBRARY ${TBB_LIBRARIES})
-  else()
+    set_property (TARGET SuiteSparse::SPQR APPEND PROPERTY
+      INTERFACE_LINK_LIBRARIES TBB::tbb)
+  else (TBB_FOUND)
     message(STATUS "Did not find Intel TBB library, assuming SuiteSparseQR was "
       "not compiled with TBB.")
-  endif()
-endif(SUITESPARSEQR_FOUND)
+  endif (TBB_FOUND)
+endif (TARGET SuiteSparse::SPQR)
 
-# UFconfig / SuiteSparse_config.
-#
-# If SuiteSparse version is >= 4 then SuiteSparse_config is required.
-# For SuiteSparse 3, UFconfig.h is required.
-suitesparse_find_component(
-  SUITESPARSE_CONFIG FILES SuiteSparse_config.h LIBRARIES suitesparseconfig)
+check_library_exists(rt shm_open "" HAVE_LIBRT)
 
-if (SUITESPARSE_CONFIG_FOUND)
+if (TARGET SuiteSparse::Config)
   # SuiteSparse_config (SuiteSparse version >= 4) requires librt library for
   # timing by default when compiled on Linux or Unix, but not on OSX (which
   # does not have librt).
-  if (CMAKE_SYSTEM_NAME MATCHES "Linux" OR UNIX AND NOT APPLE)
-    suitesparse_find_component(LIBRT LIBRARIES rt)
-    if (LIBRT_FOUND)
-      message(STATUS "Adding librt: ${LIBRT_LIBRARY} to "
-        "SuiteSparse_config libraries (required on Linux & Unix [not OSX] if "
-        "SuiteSparse is compiled with timing).")
-      list(APPEND SUITESPARSE_CONFIG_LIBRARY ${LIBRT_LIBRARY})
-    else()
-      message(STATUS "Could not find librt, but found SuiteSparse_config, "
-        "assuming that SuiteSparse was compiled without timing.")
-    endif ()
-  endif (CMAKE_SYSTEM_NAME MATCHES "Linux" OR UNIX AND NOT APPLE)
-else()
-  # Failed to find SuiteSparse_config (>= v4 installs), instead look for
-  # UFconfig header which should be present in < v4 installs.
-  suitesparse_find_component(UFCONFIG FILES UFconfig.h)
-endif ()
+  if (HAVE_LIBRT)
+    message(STATUS "Adding librt to "
+      "SuiteSparse_config libraries (required on Linux & Unix [not OSX] if "
+      "SuiteSparse is compiled with timing).")
+    set_property (TARGET SuiteSparse::Config APPEND PROPERTY
+      INTERFACE_LINK_LIBRARIES $<LINK_ONLY:rt>)
+  else (HAVE_LIBRT)
+    message(STATUS "Could not find librt, but found SuiteSparse_config, "
+      "assuming that SuiteSparse was compiled without timing.")
+  endif (HAVE_LIBRT)
 
-if (NOT SUITESPARSE_CONFIG_FOUND AND
-    NOT UFCONFIG_FOUND)
-  suitesparse_report_not_found(
-    "Failed to find either: SuiteSparse_config header & library (should be "
-    "present in all SuiteSparse >= v4 installs), or UFconfig header (should "
-    "be present in all SuiteSparse < v4 installs).")
-endif()
+  # Add BLAS and LAPACK as dependencies of SuiteSparse::Config for convenience
+  # given that all components depend on it.
+  if (BLAS_FOUND)
+    if (TARGET BLAS::BLAS)
+      set_property (TARGET SuiteSparse::Config APPEND PROPERTY
+        INTERFACE_LINK_LIBRARIES $<LINK_ONLY:BLAS::BLAS>)
+    else (TARGET BLAS::BLAS)
+      set_property (TARGET SuiteSparse::Config APPEND PROPERTY
+        INTERFACE_LINK_LIBRARIES ${BLAS_LIBRARIES})
+    endif (TARGET BLAS::BLAS)
+  endif (BLAS_FOUND)
 
-# Extract the SuiteSparse version from the appropriate header (UFconfig.h for
-# <= v3, SuiteSparse_config.h for >= v4).
-list(APPEND SUITESPARSE_FOUND_REQUIRED_VARS SUITESPARSE_VERSION)
+  if (LAPACK_FOUND)
+    if (TARGET LAPACK::LAPACK)
+      set_property (TARGET SuiteSparse::Config APPEND PROPERTY
+        INTERFACE_LINK_LIBRARIES $<LINK_ONLY:LAPACK::LAPACK>)
+    else (TARGET LAPACK::LAPACK)
+      set_property (TARGET SuiteSparse::Config APPEND PROPERTY
+        INTERFACE_LINK_LIBRARIES ${LAPACK_LIBRARIES})
+    endif (TARGET LAPACK::LAPACK)
+  endif (LAPACK_FOUND)
 
-if (UFCONFIG_FOUND)
-  # SuiteSparse version <= 3.
-  set(SUITESPARSE_VERSION_FILE ${UFCONFIG_INCLUDE_DIR}/UFconfig.h)
-  if (NOT EXISTS ${SUITESPARSE_VERSION_FILE})
-    suitesparse_report_not_found(
-      "Could not find file: ${SUITESPARSE_VERSION_FILE} containing version "
-      "information for <= v3 SuiteSparse installs, but UFconfig was found "
-      "(only present in <= v3 installs).")
-  else (NOT EXISTS ${SUITESPARSE_VERSION_FILE})
-    file(READ ${SUITESPARSE_VERSION_FILE} UFCONFIG_CONTENTS)
-
-    string(REGEX MATCH "#define SUITESPARSE_MAIN_VERSION [0-9]+"
-      SUITESPARSE_MAIN_VERSION "${UFCONFIG_CONTENTS}")
-    string(REGEX REPLACE "#define SUITESPARSE_MAIN_VERSION ([0-9]+)" "\\1"
-      SUITESPARSE_MAIN_VERSION "${SUITESPARSE_MAIN_VERSION}")
-
-    string(REGEX MATCH "#define SUITESPARSE_SUB_VERSION [0-9]+"
-      SUITESPARSE_SUB_VERSION "${UFCONFIG_CONTENTS}")
-    string(REGEX REPLACE "#define SUITESPARSE_SUB_VERSION ([0-9]+)" "\\1"
-      SUITESPARSE_SUB_VERSION "${SUITESPARSE_SUB_VERSION}")
-
-    string(REGEX MATCH "#define SUITESPARSE_SUBSUB_VERSION [0-9]+"
-      SUITESPARSE_SUBSUB_VERSION "${UFCONFIG_CONTENTS}")
-    string(REGEX REPLACE "#define SUITESPARSE_SUBSUB_VERSION ([0-9]+)" "\\1"
-      SUITESPARSE_SUBSUB_VERSION "${SUITESPARSE_SUBSUB_VERSION}")
-
-    # This is on a single line s/t CMake does not interpret it as a list of
-    # elements and insert ';' separators which would result in 4.;2.;1 nonsense.
-    set(SUITESPARSE_VERSION
-      "${SUITESPARSE_MAIN_VERSION}.${SUITESPARSE_SUB_VERSION}.${SUITESPARSE_SUBSUB_VERSION}")
-  endif (NOT EXISTS ${SUITESPARSE_VERSION_FILE})
-endif (UFCONFIG_FOUND)
-
-if (SUITESPARSE_CONFIG_FOUND)
   # SuiteSparse version >= 4.
-  set(SUITESPARSE_VERSION_FILE
-    ${SUITESPARSE_CONFIG_INCLUDE_DIR}/SuiteSparse_config.h)
-  if (NOT EXISTS ${SUITESPARSE_VERSION_FILE})
+  set(SuiteSparse_VERSION_FILE
+    ${SuiteSparse_Config_INCLUDE_DIR}/SuiteSparse_config.h)
+  if (NOT EXISTS ${SuiteSparse_VERSION_FILE})
     suitesparse_report_not_found(
-      "Could not find file: ${SUITESPARSE_VERSION_FILE} containing version "
+      "Could not find file: ${SuiteSparse_VERSION_FILE} containing version "
       "information for >= v4 SuiteSparse installs, but SuiteSparse_config was "
       "found (only present in >= v4 installs).")
-  else (NOT EXISTS ${SUITESPARSE_VERSION_FILE})
-    file(READ ${SUITESPARSE_VERSION_FILE} SUITESPARSE_CONFIG_CONTENTS)
+  else (NOT EXISTS ${SuiteSparse_VERSION_FILE})
+    file(READ ${SuiteSparse_VERSION_FILE} Config_CONTENTS)
 
-    string(REGEX MATCH "#define SUITESPARSE_MAIN_VERSION [0-9]+"
-      SUITESPARSE_MAIN_VERSION "${SUITESPARSE_CONFIG_CONTENTS}")
-    string(REGEX REPLACE "#define SUITESPARSE_MAIN_VERSION ([0-9]+)" "\\1"
-      SUITESPARSE_MAIN_VERSION "${SUITESPARSE_MAIN_VERSION}")
+    string(REGEX MATCH "#define SUITESPARSE_MAIN_VERSION[ \t]+([0-9]+)"
+      SuiteSparse_VERSION_LINE "${Config_CONTENTS}")
+    set (SuiteSparse_VERSION_MAJOR ${CMAKE_MATCH_1})
 
-    string(REGEX MATCH "#define SUITESPARSE_SUB_VERSION [0-9]+"
-      SUITESPARSE_SUB_VERSION "${SUITESPARSE_CONFIG_CONTENTS}")
-    string(REGEX REPLACE "#define SUITESPARSE_SUB_VERSION ([0-9]+)" "\\1"
-      SUITESPARSE_SUB_VERSION "${SUITESPARSE_SUB_VERSION}")
+    string(REGEX MATCH "#define SUITESPARSE_SUB_VERSION[ \t]+([0-9]+)"
+      SuiteSparse_VERSION_LINE "${Config_CONTENTS}")
+    set (SuiteSparse_VERSION_MINOR ${CMAKE_MATCH_1})
 
-    string(REGEX MATCH "#define SUITESPARSE_SUBSUB_VERSION [0-9]+"
-      SUITESPARSE_SUBSUB_VERSION "${SUITESPARSE_CONFIG_CONTENTS}")
-    string(REGEX REPLACE "#define SUITESPARSE_SUBSUB_VERSION ([0-9]+)" "\\1"
-      SUITESPARSE_SUBSUB_VERSION "${SUITESPARSE_SUBSUB_VERSION}")
+    string(REGEX MATCH "#define SUITESPARSE_SUBSUB_VERSION[ \t]+([0-9]+)"
+      SuiteSparse_VERSION_LINE "${Config_CONTENTS}")
+    set (SuiteSparse_VERSION_PATCH ${CMAKE_MATCH_1})
+
+    unset (SuiteSparse_VERSION_LINE)
 
     # This is on a single line s/t CMake does not interpret it as a list of
     # elements and insert ';' separators which would result in 4.;2.;1 nonsense.
-    set(SUITESPARSE_VERSION
-      "${SUITESPARSE_MAIN_VERSION}.${SUITESPARSE_SUB_VERSION}.${SUITESPARSE_SUBSUB_VERSION}")
-  endif (NOT EXISTS ${SUITESPARSE_VERSION_FILE})
-endif (SUITESPARSE_CONFIG_FOUND)
+    set(SuiteSparse_VERSION
+      "${SuiteSparse_VERSION_MAJOR}.${SuiteSparse_VERSION_MINOR}.${SuiteSparse_VERSION_PATCH}")
 
-# METIS (Optional dependency).
-suitesparse_find_component(METIS LIBRARIES metis)
+    if (SuiteSparse_VERSION MATCHES "[0-9]+\\.[0-9]+\\.[0-9]+")
+      set(SuiteSparse_VERSION_COMPONENTS 3)
+    else (SuiteSparse_VERSION MATCHES "[0-9]+\\.[0-9]+\\.[0-9]+")
+      message (WARNING "Could not parse SuiteSparse_config.h: SuiteSparse "
+        "version will not be available")
 
-# Only mark SuiteSparse as found if all required components and dependencies
-# have been found.
-set(SUITESPARSE_FOUND TRUE)
-foreach(REQUIRED_VAR ${SUITESPARSE_FOUND_REQUIRED_VARS})
-  if (NOT ${REQUIRED_VAR})
-    set(SUITESPARSE_FOUND FALSE)
-  endif (NOT ${REQUIRED_VAR})
-endforeach(REQUIRED_VAR ${SUITESPARSE_FOUND_REQUIRED_VARS})
+      unset (SuiteSparse_VERSION)
+      unset (SuiteSparse_VERSION_MAJOR)
+      unset (SuiteSparse_VERSION_MINOR)
+      unset (SuiteSparse_VERSION_PATCH)
+    endif (SuiteSparse_VERSION MATCHES "[0-9]+\\.[0-9]+\\.[0-9]+")
+  endif (NOT EXISTS ${SuiteSparse_VERSION_FILE})
+endif (TARGET SuiteSparse::Config)
 
-if (SUITESPARSE_FOUND)
-  list(APPEND SUITESPARSE_INCLUDE_DIRS
-    ${AMD_INCLUDE_DIR}
-    ${CAMD_INCLUDE_DIR}
-    ${COLAMD_INCLUDE_DIR}
-    ${CCOLAMD_INCLUDE_DIR}
-    ${CHOLMOD_INCLUDE_DIR}
-    ${SUITESPARSEQR_INCLUDE_DIR})
-  # Handle config separately, as otherwise at least one of them will be set
-  # to NOTFOUND which would cause any check on SUITESPARSE_INCLUDE_DIRS to fail.
-  if (SUITESPARSE_CONFIG_FOUND)
-    list(APPEND SUITESPARSE_INCLUDE_DIRS
-      ${SUITESPARSE_CONFIG_INCLUDE_DIR})
-  endif (SUITESPARSE_CONFIG_FOUND)
-  if (UFCONFIG_FOUND)
-    list(APPEND SUITESPARSE_INCLUDE_DIRS
-      ${UFCONFIG_INCLUDE_DIR})
-  endif (UFCONFIG_FOUND)
-  # As SuiteSparse includes are often all in the same directory, remove any
-  # repetitions.
-  list(REMOVE_DUPLICATES SUITESPARSE_INCLUDE_DIRS)
+# CHOLMOD requires AMD CAMD CCOLAMD COLAMD
+if (TARGET SuiteSparse::CHOLMOD)
+  foreach (component IN ITEMS AMD CAMD CCOLAMD COLAMD)
+    if (TARGET SuiteSparse::${component})
+      set_property (TARGET SuiteSparse::CHOLMOD APPEND PROPERTY
+        INTERFACE_LINK_LIBRARIES SuiteSparse::${component})
+    else (TARGET SuiteSparse::${component})
+      # Consider CHOLMOD not found if COLAMD cannot be found
+      set (SuiteSparse_CHOLMOD_FOUND FALSE)
+    endif (TARGET SuiteSparse::${component})
+  endforeach (component IN ITEMS AMD CAMD CCOLAMD COLAMD)
+endif (TARGET SuiteSparse::CHOLMOD)
 
-  # Important: The ordering of these libraries is *NOT* arbitrary, as these
-  # could potentially be static libraries their link ordering is important.
-  list(APPEND SUITESPARSE_LIBRARIES
-    ${SUITESPARSEQR_LIBRARY}
-    ${CHOLMOD_LIBRARY}
-    ${CCOLAMD_LIBRARY}
-    ${CAMD_LIBRARY}
-    ${COLAMD_LIBRARY}
-    ${AMD_LIBRARY}
-    ${LAPACK_LIBRARIES}
-    ${BLAS_LIBRARIES})
-  if (SUITESPARSE_CONFIG_FOUND)
-    list(APPEND SUITESPARSE_LIBRARIES
-      ${SUITESPARSE_CONFIG_LIBRARY})
-  endif (SUITESPARSE_CONFIG_FOUND)
-  if (METIS_FOUND)
-    list(APPEND SUITESPARSE_LIBRARIES
-      ${METIS_LIBRARY})
-  endif (METIS_FOUND)
-endif()
+# SPQR requires CHOLMOD
+if (TARGET SuiteSparse::SPQR)
+  if (TARGET SuiteSparse::CHOLMOD)
+    set_property (TARGET SuiteSparse::SPQR APPEND PROPERTY
+      INTERFACE_LINK_LIBRARIES SuiteSparse::CHOLMOD)
+  else (TARGET SuiteSparse::CHOLMOD)
+    # Consider SPQR not found if CHOLMOD cannot be found
+    set (SuiteSparse_SQPR_FOUND FALSE)
+  endif (TARGET SuiteSparse::CHOLMOD)
+endif (TARGET SuiteSparse::SPQR)
 
-# Determine if we are running on Ubuntu with the package install of SuiteSparse
-# which is broken and does not support linking a shared library.
-set(SUITESPARSE_IS_BROKEN_SHARED_LINKING_UBUNTU_SYSTEM_VERSION FALSE)
-if (CMAKE_SYSTEM_NAME MATCHES "Linux" AND
-    SUITESPARSE_VERSION VERSION_EQUAL 3.4.0)
-  find_program(LSB_RELEASE_EXECUTABLE lsb_release)
-  if (LSB_RELEASE_EXECUTABLE)
-    # Any even moderately recent Ubuntu release (likely to be affected by
-    # this bug) should have lsb_release, if it isn't present we are likely
-    # on a different Linux distribution (should be fine).
-    execute_process(COMMAND ${LSB_RELEASE_EXECUTABLE} -si
-      OUTPUT_VARIABLE LSB_DISTRIBUTOR_ID
-      OUTPUT_STRIP_TRAILING_WHITESPACE)
+# Add SuiteSparse::Config as dependency to all components
+if (TARGET SuiteSparse::Config)
+  foreach (component IN LISTS SuiteSparse_FIND_COMPONENTS)
+    if (component STREQUAL Config)
+      continue ()
+    endif (component STREQUAL Config)
 
-    if (LSB_DISTRIBUTOR_ID MATCHES "Ubuntu" AND
-        SUITESPARSE_LIBRARIES MATCHES "/usr/lib/libamd")
-      # We are on Ubuntu, and the SuiteSparse version matches the broken
-      # system install version and is a system install.
-      set(SUITESPARSE_IS_BROKEN_SHARED_LINKING_UBUNTU_SYSTEM_VERSION TRUE)
-      message(STATUS "Found system install of SuiteSparse "
-        "${SUITESPARSE_VERSION} running on Ubuntu, which has a known bug "
-        "preventing linking of shared libraries (static linking unaffected).")
-    endif (LSB_DISTRIBUTOR_ID MATCHES "Ubuntu" AND
-      SUITESPARSE_LIBRARIES MATCHES "/usr/lib/libamd")
-  endif (LSB_RELEASE_EXECUTABLE)
-endif (CMAKE_SYSTEM_NAME MATCHES "Linux" AND
-  SUITESPARSE_VERSION VERSION_EQUAL 3.4.0)
+    if (TARGET SuiteSparse::${component})
+      set_property (TARGET SuiteSparse::${component} APPEND PROPERTY
+        INTERFACE_LINK_LIBRARIES SuiteSparse::Config)
+    endif (TARGET SuiteSparse::${component})
+  endforeach (component IN LISTS SuiteSparse_FIND_COMPONENTS)
+endif (TARGET SuiteSparse::Config)
+
+# Check whether CHOLMOD was compiled with METIS support. The check can be
+# performed only after the main components have been set up.
+if (TARGET SuiteSparse::CHOLMOD)
+  # NOTE If SuiteSparse was compiled as a static library we'll need to link
+  # against METIS already during the check. Otherwise, the check can fail due to
+  # undefined references even though SuiteSparse was compiled with METIS.
+  find_package (METIS)
+
+  if (TARGET METIS::METIS)
+    cmake_push_check_state (RESET)
+    set (CMAKE_REQUIRED_LIBRARIES SuiteSparse::CHOLMOD METIS::METIS)
+    check_symbol_exists (cholmod_metis cholmod.h SuiteSparse_CHOLMOD_USES_METIS)
+    cmake_pop_check_state ()
+
+    if (SuiteSparse_CHOLMOD_USES_METIS)
+      set_property (TARGET SuiteSparse::CHOLMOD APPEND PROPERTY
+        INTERFACE_LINK_LIBRARIES $<LINK_ONLY:METIS::METIS>)
+
+      # Provide the SuiteSparse::Partition component whose availability indicates
+      # that CHOLMOD was compiled with the Partition module.
+      if (NOT TARGET SuiteSparse::Partition)
+        add_library (SuiteSparse::Partition IMPORTED INTERFACE)
+      endif (NOT TARGET SuiteSparse::Partition)
+
+      set_property (TARGET SuiteSparse::Partition APPEND PROPERTY
+        INTERFACE_LINK_LIBRARIES SuiteSparse::CHOLMOD)
+    endif (SuiteSparse_CHOLMOD_USES_METIS)
+  endif (TARGET METIS::METIS)
+endif (TARGET SuiteSparse::CHOLMOD)
+
+# We do not use suitesparse_find_component to find Partition and therefore must
+# handle the availability in an extra step.
+if (TARGET SuiteSparse::Partition)
+  set (SuiteSparse_Partition_FOUND TRUE)
+else (TARGET SuiteSparse::Partition)
+  set (SuiteSparse_Partition_FOUND FALSE)
+endif (TARGET SuiteSparse::Partition)
 
 suitesparse_reset_find_library_prefix()
 
 # Handle REQUIRED and QUIET arguments to FIND_PACKAGE
 include(FindPackageHandleStandardArgs)
-if (SUITESPARSE_FOUND)
+if (SuiteSparse_FOUND)
   find_package_handle_standard_args(SuiteSparse
-    REQUIRED_VARS ${SUITESPARSE_FOUND_REQUIRED_VARS}
-    VERSION_VAR SUITESPARSE_VERSION
-    FAIL_MESSAGE "Failed to find some/all required components of SuiteSparse.")
-else (SUITESPARSE_FOUND)
+    REQUIRED_VARS ${SuiteSparse_REQUIRED_VARS}
+    VERSION_VAR SuiteSparse_VERSION
+    FAIL_MESSAGE "Failed to find some/all required components of SuiteSparse."
+    HANDLE_COMPONENTS)
+else (SuiteSparse_FOUND)
   # Do not pass VERSION_VAR to FindPackageHandleStandardArgs() if we failed to
   # find SuiteSparse to avoid a confusing autogenerated failure message
   # that states 'not found (missing: FOO) (found version: x.y.z)'.
   find_package_handle_standard_args(SuiteSparse
-    REQUIRED_VARS ${SUITESPARSE_FOUND_REQUIRED_VARS}
-    FAIL_MESSAGE "Failed to find some/all required components of SuiteSparse.")
-endif (SUITESPARSE_FOUND)
+    REQUIRED_VARS ${SuiteSparse_REQUIRED_VARS}
+    FAIL_MESSAGE "Failed to find some/all required components of SuiteSparse."
+    HANDLE_COMPONENTS)
+endif (SuiteSparse_FOUND)
+
+# Pop CMP0057.
+cmake_policy (POP)
diff --git a/third_party/ceres/cmake/FindTBB.cmake b/third_party/ceres/cmake/FindTBB.cmake
deleted file mode 100644
index 5ae7b61..0000000
--- a/third_party/ceres/cmake/FindTBB.cmake
+++ /dev/null
@@ -1,455 +0,0 @@
-# - Find ThreadingBuildingBlocks include dirs and libraries
-# Use this module by invoking find_package with the form:
-#  find_package(TBB
-#    [REQUIRED]             # Fail with error if TBB is not found
-#    )                      #
-# Once done, this will define
-#
-#  TBB_FOUND - system has TBB
-#  TBB_INCLUDE_DIRS - the TBB include directories
-#  TBB_LIBRARIES - TBB libraries to be lined, doesn't include malloc or
-#                  malloc proxy
-#  TBB::tbb - imported target for the TBB library
-#
-#  TBB_VERSION_MAJOR - Major Product Version Number
-#  TBB_VERSION_MINOR - Minor Product Version Number
-#  TBB_INTERFACE_VERSION - Engineering Focused Version Number
-#  TBB_COMPATIBLE_INTERFACE_VERSION - The oldest major interface version
-#                                     still supported. This uses the engineering
-#                                     focused interface version numbers.
-#
-#  TBB_MALLOC_FOUND - system has TBB malloc library
-#  TBB_MALLOC_INCLUDE_DIRS - the TBB malloc include directories
-#  TBB_MALLOC_LIBRARIES - The TBB malloc libraries to be lined
-#  TBB::malloc - imported target for the TBB malloc library
-#
-#  TBB_MALLOC_PROXY_FOUND - system has TBB malloc proxy library
-#  TBB_MALLOC_PROXY_INCLUDE_DIRS = the TBB malloc proxy include directories
-#  TBB_MALLOC_PROXY_LIBRARIES - The TBB malloc proxy libraries to be lined
-#  TBB::malloc_proxy - imported target for the TBB malloc proxy library
-#
-#
-# This module reads hints about search locations from variables:
-#  ENV TBB_ARCH_PLATFORM - for eg. set it to "mic" for Xeon Phi builds
-#  ENV TBB_ROOT or just TBB_ROOT - root directory of tbb installation
-#  ENV TBB_BUILD_PREFIX - specifies the build prefix for user built tbb
-#                         libraries. Should be specified with ENV TBB_ROOT
-#                         and optionally...
-#  ENV TBB_BUILD_DIR - if build directory is different than ${TBB_ROOT}/build
-#
-#
-# Modified by Robert Maynard from the original OGRE source
-#
-#-------------------------------------------------------------------
-# This file is part of the CMake build system for OGRE
-#     (Object-oriented Graphics Rendering Engine)
-# For the latest info, see http://www.ogre3d.org/
-#
-# The contents of this file are placed in the public domain. Feel
-# free to make use of it in any way you like.
-#-------------------------------------------------------------------
-#
-# =========================================================================
-# Taken from Copyright.txt in the root of the VTK source tree as per
-# instructions to substitute the full license in place of the summary
-# reference when distributing outside of VTK
-# =========================================================================
-#
-#  Program:   Visualization Toolkit
-#  Module:    Copyright.txt
-#
-# Copyright (c) 1993-2015 Ken Martin, Will Schroeder, Bill Lorensen
-# All rights reserved.
-#
-# 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 name of Ken Martin, Will Schroeder, or Bill Lorensen nor the names
-#   of any 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 AUTHORS 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.
-#
-# =========================================================================*/
-
-#=============================================================================
-#  FindTBB helper functions and macros
-#
-
-#====================================================
-# Fix the library path in case it is a linker script
-#====================================================
-function(tbb_extract_real_library library real_library)
-  if(NOT UNIX OR NOT EXISTS ${library})
-    set(${real_library} "${library}" PARENT_SCOPE)
-    return()
-  endif()
-
-  #Read in the first 4 bytes and see if they are the ELF magic number
-  set(_elf_magic "7f454c46")
-  file(READ ${library} _hex_data OFFSET 0 LIMIT 4 HEX)
-  if(_hex_data STREQUAL _elf_magic)
-    #we have opened a elf binary so this is what
-    #we should link to
-    set(${real_library} "${library}" PARENT_SCOPE)
-    return()
-  endif()
-
-  file(READ ${library} _data OFFSET 0 LIMIT 1024)
-  if("${_data}" MATCHES "INPUT \\(([^(]+)\\)")
-    #extract out the .so name from REGEX MATCH command
-    set(_proper_so_name "${CMAKE_MATCH_1}")
-
-    #construct path to the real .so which is presumed to be in the same directory
-    #as the input file
-    get_filename_component(_so_dir "${library}" DIRECTORY)
-    set(${real_library} "${_so_dir}/${_proper_so_name}" PARENT_SCOPE)
-  else()
-    #unable to determine what this library is so just hope everything works
-    #and pass it unmodified.
-    set(${real_library} "${library}" PARENT_SCOPE)
-  endif()
-endfunction()
-
-#===============================================
-# Do the final processing for the package find.
-#===============================================
-macro(findpkg_finish PREFIX TARGET_NAME)
-  if (${PREFIX}_INCLUDE_DIR AND ${PREFIX}_LIBRARY)
-    set(${PREFIX}_FOUND TRUE)
-    set (${PREFIX}_INCLUDE_DIRS ${${PREFIX}_INCLUDE_DIR})
-    set (${PREFIX}_LIBRARIES ${${PREFIX}_LIBRARY})
-  else ()
-    if (${PREFIX}_FIND_REQUIRED AND NOT ${PREFIX}_FIND_QUIETLY)
-      message(FATAL_ERROR "Required library ${PREFIX} not found.")
-    endif ()
-  endif ()
-
-  if (NOT TARGET "TBB::${TARGET_NAME}")
-    if (${PREFIX}_LIBRARY_RELEASE)
-      tbb_extract_real_library(${${PREFIX}_LIBRARY_RELEASE} real_release)
-    endif ()
-    if (${PREFIX}_LIBRARY_DEBUG)
-      tbb_extract_real_library(${${PREFIX}_LIBRARY_DEBUG} real_debug)
-    endif ()
-    add_library(TBB::${TARGET_NAME} UNKNOWN IMPORTED)
-    set_target_properties(TBB::${TARGET_NAME} PROPERTIES
-      INTERFACE_INCLUDE_DIRECTORIES "${${PREFIX}_INCLUDE_DIR}")
-    if (${PREFIX}_LIBRARY_DEBUG AND ${PREFIX}_LIBRARY_RELEASE)
-      set_target_properties(TBB::${TARGET_NAME} PROPERTIES
-        IMPORTED_LOCATION "${real_release}"
-        IMPORTED_LOCATION_DEBUG "${real_debug}"
-        IMPORTED_LOCATION_RELEASE "${real_release}")
-    elseif (${PREFIX}_LIBRARY_RELEASE)
-      set_target_properties(TBB::${TARGET_NAME} PROPERTIES
-        IMPORTED_LOCATION "${real_release}")
-    elseif (${PREFIX}_LIBRARY_DEBUG)
-      set_target_properties(TBB::${TARGET_NAME} PROPERTIES
-        IMPORTED_LOCATION "${real_debug}")
-    endif ()
-  endif ()
-
-  #mark the following variables as internal variables
-  mark_as_advanced(${PREFIX}_INCLUDE_DIR
-                   ${PREFIX}_LIBRARY
-                   ${PREFIX}_LIBRARY_DEBUG
-                   ${PREFIX}_LIBRARY_RELEASE)
-endmacro()
-
-#===============================================
-# Generate debug names from given release names
-#===============================================
-macro(get_debug_names PREFIX)
-  foreach(i ${${PREFIX}})
-    set(${PREFIX}_DEBUG ${${PREFIX}_DEBUG} ${i}d ${i}D ${i}_d ${i}_D ${i}_debug ${i})
-  endforeach()
-endmacro()
-
-#===============================================
-# See if we have env vars to help us find tbb
-#===============================================
-macro(getenv_path VAR)
-   set(ENV_${VAR} $ENV{${VAR}})
-   # replace won't work if var is blank
-   if (ENV_${VAR})
-     string( REGEX REPLACE "\\\\" "/" ENV_${VAR} ${ENV_${VAR}} )
-   endif ()
-endmacro()
-
-#===============================================
-# Couple a set of release AND debug libraries
-#===============================================
-macro(make_library_set PREFIX)
-  if (${PREFIX}_RELEASE AND ${PREFIX}_DEBUG)
-    set(${PREFIX} optimized ${${PREFIX}_RELEASE} debug ${${PREFIX}_DEBUG})
-  elseif (${PREFIX}_RELEASE)
-    set(${PREFIX} ${${PREFIX}_RELEASE})
-  elseif (${PREFIX}_DEBUG)
-    set(${PREFIX} ${${PREFIX}_DEBUG})
-  endif ()
-endmacro()
-
-#===============================================
-# Ensure that the release & debug libraries found are from the same installation.
-#===============================================
-macro(find_tbb_library_verifying_release_debug_locations PREFIX)
-  find_library(${PREFIX}_RELEASE
-    NAMES ${${PREFIX}_NAMES}
-    HINTS ${TBB_LIB_SEARCH_PATH})
-  if (${PREFIX}_RELEASE)
-    # To avoid finding a mismatched set of release & debug libraries from
-    # different installations if the first found does not have debug libraries
-    # by forcing the search for debug to only occur within the detected release
-    # library directory (if found).  Although this would break detection if the
-    # release & debug libraries were shipped in different directories, this is
-    # not the case in the official TBB releases for any platform.
-    get_filename_component(
-      FOUND_RELEASE_LIB_DIR "${${PREFIX}_RELEASE}" DIRECTORY)
-    find_library(${PREFIX}_DEBUG
-      NAMES ${${PREFIX}_NAMES_DEBUG}
-      HINTS ${FOUND_RELEASE_LIB_DIR}
-      NO_DEFAULT_PATH)
-  else()
-    find_library(${PREFIX}_DEBUG
-      NAMES ${${PREFIX}_NAMES_DEBUG}
-      HINTS ${TBB_LIB_SEARCH_PATH})
-  endif()
-endmacro()
-
-#=============================================================================
-#  Now to actually find TBB
-#
-
-# Get path, convert backslashes as ${ENV_${var}}
-getenv_path(TBB_ROOT)
-
-# initialize search paths
-set(TBB_PREFIX_PATH ${TBB_ROOT} ${ENV_TBB_ROOT})
-set(TBB_INC_SEARCH_PATH "")
-set(TBB_LIB_SEARCH_PATH "")
-
-
-# If user built from sources
-set(TBB_BUILD_PREFIX $ENV{TBB_BUILD_PREFIX})
-if (TBB_BUILD_PREFIX AND ENV_TBB_ROOT)
-  getenv_path(TBB_BUILD_DIR)
-  if (NOT ENV_TBB_BUILD_DIR)
-    set(ENV_TBB_BUILD_DIR ${ENV_TBB_ROOT}/build)
-  endif ()
-
-  # include directory under ${ENV_TBB_ROOT}/include
-  list(APPEND TBB_LIB_SEARCH_PATH
-    ${ENV_TBB_BUILD_DIR}/${TBB_BUILD_PREFIX}_release
-    ${ENV_TBB_BUILD_DIR}/${TBB_BUILD_PREFIX}_debug)
-endif ()
-
-
-# For Windows, let's assume that the user might be using the precompiled
-# TBB packages from the main website. These use a rather awkward directory
-# structure (at least for automatically finding the right files) depending
-# on platform and compiler, but we'll do our best to accommodate it.
-# Not adding the same effort for the precompiled linux builds, though. Those
-# have different versions for CC compiler versions and linux kernels which
-# will never adequately match the user's setup, so there is no feasible way
-# to detect the "best" version to use. The user will have to manually
-# select the right files. (Chances are the distributions are shipping their
-# custom version of tbb, anyway, so the problem is probably nonexistent.)
-if (WIN32 AND MSVC)
-  set(COMPILER_PREFIX "vc7.1")
-  if (MSVC_VERSION EQUAL 1400)
-    set(COMPILER_PREFIX "vc8")
-  elseif(MSVC_VERSION EQUAL 1500)
-    set(COMPILER_PREFIX "vc9")
-  elseif(MSVC_VERSION EQUAL 1600)
-    set(COMPILER_PREFIX "vc10")
-  elseif(MSVC_VERSION EQUAL 1700)
-    set(COMPILER_PREFIX "vc11")
-  elseif(MSVC_VERSION EQUAL 1800)
-    set(COMPILER_PREFIX "vc12")
-  elseif(MSVC_VERSION GREATER_EQUAL 1900)
-    set(COMPILER_PREFIX "vc14")
-  endif ()
-
-  # for each prefix path, add ia32/64\${COMPILER_PREFIX}\lib to the lib search path
-  foreach (dir IN LISTS TBB_PREFIX_PATH)
-    if (CMAKE_CL_64)
-      list(APPEND TBB_LIB_SEARCH_PATH ${dir}/ia64/${COMPILER_PREFIX}/lib)
-      list(APPEND TBB_LIB_SEARCH_PATH ${dir}/lib/ia64/${COMPILER_PREFIX})
-      list(APPEND TBB_LIB_SEARCH_PATH ${dir}/intel64/${COMPILER_PREFIX}/lib)
-      list(APPEND TBB_LIB_SEARCH_PATH ${dir}/lib/intel64/${COMPILER_PREFIX})
-    else ()
-      list(APPEND TBB_LIB_SEARCH_PATH ${dir}/ia32/${COMPILER_PREFIX}/lib)
-      list(APPEND TBB_LIB_SEARCH_PATH ${dir}/lib/ia32/${COMPILER_PREFIX})
-    endif ()
-  endforeach ()
-endif ()
-
-# For OS X binary distribution, choose libc++ based libraries for Mavericks (10.9)
-# and above and AppleClang
-if (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND
-    NOT CMAKE_SYSTEM_VERSION VERSION_LESS 13.0)
-  set (USE_LIBCXX OFF)
-  cmake_policy(GET CMP0025 POLICY_VAR)
-
-  if (POLICY_VAR STREQUAL "NEW")
-    if (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
-      set (USE_LIBCXX ON)
-    endif ()
-  else ()
-    if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
-      set (USE_LIBCXX ON)
-    endif ()
-  endif ()
-
-  if (USE_LIBCXX)
-    foreach (dir IN LISTS TBB_PREFIX_PATH)
-      list (APPEND TBB_LIB_SEARCH_PATH ${dir}/lib/libc++ ${dir}/libc++/lib)
-    endforeach ()
-  endif ()
-endif ()
-
-# check compiler ABI
-if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
-  set(COMPILER_PREFIX)
-  if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.8)
-    list(APPEND COMPILER_PREFIX "gcc4.8")
-  endif()
-  if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.7)
-    list(APPEND COMPILER_PREFIX "gcc4.7")
-  endif()
-  if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.4)
-    list(APPEND COMPILER_PREFIX "gcc4.4")
-  endif()
-  list(APPEND COMPILER_PREFIX "gcc4.1")
-elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
-  set(COMPILER_PREFIX)
-  if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.0) # Complete guess
-    list(APPEND COMPILER_PREFIX "gcc4.8")
-  endif()
-  if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.6)
-    list(APPEND COMPILER_PREFIX "gcc4.7")
-  endif()
-  list(APPEND COMPILER_PREFIX "gcc4.4")
-else() # Assume compatibility with 4.4 for other compilers
-  list(APPEND COMPILER_PREFIX "gcc4.4")
-endif ()
-
-# if platform architecture is explicitly specified
-set(TBB_ARCH_PLATFORM $ENV{TBB_ARCH_PLATFORM})
-if (TBB_ARCH_PLATFORM)
-  foreach (dir IN LISTS TBB_PREFIX_PATH)
-    list(APPEND TBB_LIB_SEARCH_PATH ${dir}/${TBB_ARCH_PLATFORM}/lib)
-    list(APPEND TBB_LIB_SEARCH_PATH ${dir}/lib/${TBB_ARCH_PLATFORM})
-  endforeach ()
-endif ()
-
-foreach (dir IN LISTS TBB_PREFIX_PATH)
-  foreach (prefix IN LISTS COMPILER_PREFIX)
-    if (CMAKE_SIZEOF_VOID_P EQUAL 8)
-      list(APPEND TBB_LIB_SEARCH_PATH ${dir}/lib/intel64)
-      list(APPEND TBB_LIB_SEARCH_PATH ${dir}/lib/intel64/${prefix})
-      list(APPEND TBB_LIB_SEARCH_PATH ${dir}/intel64/lib)
-      list(APPEND TBB_LIB_SEARCH_PATH ${dir}/intel64/${prefix}/lib)
-    else ()
-      list(APPEND TBB_LIB_SEARCH_PATH ${dir}/lib/ia32)
-      list(APPEND TBB_LIB_SEARCH_PATH ${dir}/lib/ia32/${prefix})
-      list(APPEND TBB_LIB_SEARCH_PATH ${dir}/ia32/lib)
-      list(APPEND TBB_LIB_SEARCH_PATH ${dir}/ia32/${prefix}/lib)
-    endif ()
-  endforeach()
-endforeach ()
-
-# add general search paths
-foreach (dir IN LISTS TBB_PREFIX_PATH)
-  list(APPEND TBB_LIB_SEARCH_PATH ${dir}/lib ${dir}/Lib ${dir}/lib/tbb
-    ${dir}/Libs)
-  list(APPEND TBB_INC_SEARCH_PATH ${dir}/include ${dir}/Include
-    ${dir}/include/tbb)
-endforeach ()
-
-set(TBB_LIBRARY_NAMES tbb)
-get_debug_names(TBB_LIBRARY_NAMES)
-
-find_path(TBB_INCLUDE_DIR
-          NAMES tbb/tbb.h
-          HINTS ${TBB_INC_SEARCH_PATH})
-find_tbb_library_verifying_release_debug_locations(TBB_LIBRARY)
-make_library_set(TBB_LIBRARY)
-
-findpkg_finish(TBB tbb)
-
-#if we haven't found TBB no point on going any further
-if (NOT TBB_FOUND)
-  return()
-endif ()
-
-#=============================================================================
-# Look for TBB's malloc package
-set(TBB_MALLOC_LIBRARY_NAMES tbbmalloc)
-get_debug_names(TBB_MALLOC_LIBRARY_NAMES)
-
-find_path(TBB_MALLOC_INCLUDE_DIR
-          NAMES tbb/tbb.h
-          HINTS ${TBB_INC_SEARCH_PATH})
-find_tbb_library_verifying_release_debug_locations(TBB_MALLOC_LIBRARY)
-make_library_set(TBB_MALLOC_LIBRARY)
-
-findpkg_finish(TBB_MALLOC tbbmalloc)
-
-#=============================================================================
-# Look for TBB's malloc proxy package
-set(TBB_MALLOC_PROXY_LIBRARY_NAMES tbbmalloc_proxy)
-get_debug_names(TBB_MALLOC_PROXY_LIBRARY_NAMES)
-
-find_path(TBB_MALLOC_PROXY_INCLUDE_DIR
-          NAMES tbb/tbbmalloc_proxy.h
-          HINTS ${TBB_INC_SEARCH_PATH})
-find_tbb_library_verifying_release_debug_locations(TBB_MALLOC_PROXY_LIBRARY)
-make_library_set(TBB_MALLOC_PROXY_LIBRARY)
-
-findpkg_finish(TBB_MALLOC_PROXY tbbmalloc_proxy)
-
-
-#=============================================================================
-#parse all the version numbers from tbb
-if(NOT TBB_VERSION)
-
- #only read the start of the file
- file(STRINGS
-      "${TBB_INCLUDE_DIR}/tbb/tbb_stddef.h"
-      TBB_VERSION_CONTENTS
-      REGEX "VERSION")
-
-  string(REGEX REPLACE
-    ".*#define TBB_VERSION_MAJOR ([0-9]+).*" "\\1"
-    TBB_VERSION_MAJOR "${TBB_VERSION_CONTENTS}")
-
-  string(REGEX REPLACE
-    ".*#define TBB_VERSION_MINOR ([0-9]+).*" "\\1"
-    TBB_VERSION_MINOR "${TBB_VERSION_CONTENTS}")
-
-  string(REGEX REPLACE
-        ".*#define TBB_INTERFACE_VERSION ([0-9]+).*" "\\1"
-        TBB_INTERFACE_VERSION "${TBB_VERSION_CONTENTS}")
-
-  string(REGEX REPLACE
-        ".*#define TBB_COMPATIBLE_INTERFACE_VERSION ([0-9]+).*" "\\1"
-        TBB_COMPATIBLE_INTERFACE_VERSION "${TBB_VERSION_CONTENTS}")
-
-endif()
diff --git a/third_party/ceres/cmake/PrettyPrintCMakeList.cmake b/third_party/ceres/cmake/PrettyPrintCMakeList.cmake
index 067883c..30151fe 100644
--- a/third_party/ceres/cmake/PrettyPrintCMakeList.cmake
+++ b/third_party/ceres/cmake/PrettyPrintCMakeList.cmake
@@ -1,5 +1,5 @@
 # Ceres Solver - A fast non-linear least squares minimizer
-# Copyright 2018 Google Inc. All rights reserved.
+# Copyright 2023 Google Inc. All rights reserved.
 # http://ceres-solver.org/
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/third_party/ceres/cmake/ReadCeresVersionFromSource.cmake b/third_party/ceres/cmake/ReadCeresVersionFromSource.cmake
index 2859744..53e29c4 100644
--- a/third_party/ceres/cmake/ReadCeresVersionFromSource.cmake
+++ b/third_party/ceres/cmake/ReadCeresVersionFromSource.cmake
@@ -1,5 +1,5 @@
 # Ceres Solver - A fast non-linear least squares minimizer
-# Copyright 2015 Google Inc. All rights reserved.
+# Copyright 2023 Google Inc. All rights reserved.
 # http://ceres-solver.org/
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/third_party/ceres/cmake/UpdateCacheVariable.cmake b/third_party/ceres/cmake/UpdateCacheVariable.cmake
index 82ae571..bf3b594 100644
--- a/third_party/ceres/cmake/UpdateCacheVariable.cmake
+++ b/third_party/ceres/cmake/UpdateCacheVariable.cmake
@@ -1,5 +1,5 @@
 # Ceres Solver - A fast non-linear least squares minimizer
-# Copyright 2015 Google Inc. All rights reserved.
+# Copyright 2023 Google Inc. All rights reserved.
 # http://ceres-solver.org/
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/third_party/ceres/cmake/config.h.in b/third_party/ceres/cmake/config.h.in
index 4a516f6..1566795 100644
--- a/third_party/ceres/cmake/config.h.in
+++ b/third_party/ceres/cmake/config.h.in
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2022 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -50,15 +50,14 @@
 // If defined, Ceres was compiled without SuiteSparse.
 @CERES_NO_SUITESPARSE@
 
-// If defined, Ceres was compiled without CXSparse.
-@CERES_NO_CXSPARSE@
+// If defined, Ceres was compiled without CUDA.
+@CERES_NO_CUDA@
 
 // If defined, Ceres was compiled without Apple's Accelerate framework solvers.
 @CERES_NO_ACCELERATE_SPARSE@
 
 #if defined(CERES_NO_SUITESPARSE) &&              \
     defined(CERES_NO_ACCELERATE_SPARSE) &&        \
-    defined(CERES_NO_CXSPARSE) &&                 \
     !defined(CERES_USE_EIGEN_SPARSE)  // NOLINT
 // If defined Ceres was compiled without any sparse linear algebra support.
 #define CERES_NO_SPARSE
@@ -71,19 +70,26 @@
 // routines.
 @CERES_NO_CUSTOM_BLAS@
 
-// If defined, Ceres was compiled without multithreading support.
-@CERES_NO_THREADS@
-// If defined Ceres was compiled with OpenMP multithreading.
-@CERES_USE_OPENMP@
-// If defined Ceres was compiled with modern C++ multithreading.
-@CERES_USE_CXX_THREADS@
+// If defined, Ceres was compiled with a version of SuiteSparse/CHOLMOD without
+// the Partition module (requires METIS).
+@CERES_NO_CHOLMOD_PARTITION@
+// If defined Ceres was compiled without support for METIS via Eigen.
+@CERES_NO_EIGEN_METIS@
 
-// If defined, Ceres was built as a shared library.
-@CERES_USING_SHARED_LIBRARY@
 
-// If defined, Ceres was compiled with a version MSVC >= 2005 which
-// deprecated the standard POSIX names for bessel functions, replacing them
-// with underscore prefixed versions (e.g. j0() -> _j0()).
-@CERES_MSVC_USE_UNDERSCORE_PREFIXED_BESSEL_FUNCTIONS@
+// CERES_NO_SPARSE should be automatically defined by config.h if Ceres was
+// compiled without any sparse back-end.  Verify that it has not subsequently
+// been inconsistently redefined.
+#if defined(CERES_NO_SPARSE)
+#if !defined(CERES_NO_SUITESPARSE)
+#error CERES_NO_SPARSE requires CERES_NO_SUITESPARSE.
+#endif
+#if !defined(CERES_NO_ACCELERATE_SPARSE)
+#error CERES_NO_SPARSE requires CERES_NO_ACCELERATE_SPARSE
+#endif
+#if defined(CERES_USE_EIGEN_SPARSE)
+#error CERES_NO_SPARSE requires !CERES_USE_EIGEN_SPARSE
+#endif
+#endif
 
 #endif  // CERES_PUBLIC_INTERNAL_CONFIG_H_
diff --git a/third_party/ceres/cmake/iOS.cmake b/third_party/ceres/cmake/iOS.cmake
index 4029f96..0773d13 100644
--- a/third_party/ceres/cmake/iOS.cmake
+++ b/third_party/ceres/cmake/iOS.cmake
@@ -257,7 +257,7 @@
 
 set(CMAKE_C_FLAGS
   "${XCODE_IOS_PLATFORM_VERSION_FLAGS} -fobjc-abi-version=2 -fobjc-arc ${CMAKE_C_FLAGS}")
-# Hidden visibilty is required for C++ on iOS.
+# Hidden visibility is required for C++ on iOS.
 set(CMAKE_CXX_FLAGS
   "${XCODE_IOS_PLATFORM_VERSION_FLAGS} -fvisibility=hidden -fvisibility-inlines-hidden -fobjc-abi-version=2 -fobjc-arc ${CMAKE_CXX_FLAGS}")
 set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG -O3 -fomit-frame-pointer -ffast-math ${CMAKE_CXX_FLAGS_RELEASE}")
@@ -309,7 +309,7 @@
   ${CMAKE_OSX_SYSROOT}/Developer/Library/Frameworks)
 
 # Only search the specified iOS SDK, not the remainder of the host filesystem.
-set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
 set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
 set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
 set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
@@ -322,7 +322,6 @@
 
 # This macro lets you find executable programs on the host system.
 macro(find_host_package)
-  set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
   set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER)
   set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER)
   set(IOS FALSE)
@@ -330,7 +329,6 @@
   find_package(${ARGN})
 
   set(IOS TRUE)
-  set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY)
   set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
   set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
 endmacro(find_host_package)
diff --git a/third_party/ceres/config/ceres/internal/config.h b/third_party/ceres/config/ceres/internal/config.h
index 1cf034d..969e43b 100644
--- a/third_party/ceres/config/ceres/internal/config.h
+++ b/third_party/ceres/config/ceres/internal/config.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2022 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -30,16 +30,14 @@
 
 // Default (empty) configuration options for Ceres.
 //
-// IMPORTANT: Most users of Ceres will not use this file, when
-//            compiling Ceres with CMake, CMake will configure a new
-//            config.h with the currently selected Ceres compile
-//            options in <BUILD_DIR>/config, which will be added to
-//            the include path for compilation, and installed with the
-//            public Ceres headers.  However, for some users of Ceres
-//            who compile without CMake (Android), this file ensures
-//            that Ceres will compile, with the user either specifying
-//            manually the Ceres compile options, or passing them
-//            directly through the compiler.
+// IMPORTANT: Most users of Ceres will not use this file, when compiling Ceres
+//            with CMake, CMake will configure a new config.h with the currently
+//            selected Ceres compile options in <BUILD_DIR>/config, which will
+//            be added to the include path for compilation, and installed with
+//            the public Ceres headers.  However, for some users of Ceres who
+//            compile without CMake (Bazel), this file ensures that Ceres will
+//            compile, with the user either specifying manually the Ceres
+//            compile options, or passing them directly through the compiler.
 
 #ifndef CERES_PUBLIC_INTERNAL_CONFIG_H_
 #define CERES_PUBLIC_INTERNAL_CONFIG_H_
diff --git a/third_party/ceres/config/ceres/internal/export.h b/third_party/ceres/config/ceres/internal/export.h
new file mode 100644
index 0000000..0d4495d
--- /dev/null
+++ b/third_party/ceres/config/ceres/internal/export.h
@@ -0,0 +1,46 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2022 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: alexs.mac@gmail.com (Alex Stewart)
+
+// Default (empty) configuration options for Ceres.
+//
+// IMPORTANT: Most users of Ceres will not use this file, when compiling Ceres
+//            with CMake, CMake will configure a new config.h with the currently
+//            selected Ceres compile options in <BUILD_DIR>/export, which will
+//            be added to the include path for compilation, and installed with
+//            the public Ceres headers.  However, for some users of Ceres who
+//            compile without CMake (Bazel), this file ensures that Ceres will
+//            compile, with the user either specifying manually the Ceres
+//            compile options, or passing them directly through the compiler.
+
+#ifndef CERES_PUBLIC_INTERNAL_EXPORT_H_
+#define CERES_PUBLIC_INTERNAL_EXPORT_H_
+
+
+#endif  // CERES_PUBLIC_INTERNAL_EXPORT_H_
diff --git a/third_party/ceres/docs/CMakeLists.txt b/third_party/ceres/docs/CMakeLists.txt
index cfdd910..b5588ef 100644
--- a/third_party/ceres/docs/CMakeLists.txt
+++ b/third_party/ceres/docs/CMakeLists.txt
@@ -1,5 +1,5 @@
 # Ceres Solver - A fast non-linear least squares minimizer
-# Copyright 2015 Google Inc. All rights reserved.
+# Copyright 2023 Google Inc. All rights reserved.
 # http://ceres-solver.org/
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/third_party/ceres/docs/source/CMakeLists.txt b/third_party/ceres/docs/source/CMakeLists.txt
index 70bf998..1f8fed8 100644
--- a/third_party/ceres/docs/source/CMakeLists.txt
+++ b/third_party/ceres/docs/source/CMakeLists.txt
@@ -1,19 +1,21 @@
-find_package(Sphinx REQUIRED)
-
 # HTML output directory
 set(SPHINX_HTML_DIR "${Ceres_BINARY_DIR}/docs/html")
 
 # Install documentation
 install(DIRECTORY ${SPHINX_HTML_DIR}
-        DESTINATION "${CERES_DOCS_INSTALL_DIR}"
+        DESTINATION ${CMAKE_INSTALL_DOCDIR}
         COMPONENT Doc
         PATTERN "${SPHINX_HTML_DIR}/*")
 
+# Find python
+find_package(Python REQUIRED COMPONENTS Interpreter)
+
 # Building using 'make_docs.py' python script
 add_custom_target(ceres_docs ALL
-                  python
+                  $<TARGET_FILE:Python::Interpreter>
                   "${Ceres_SOURCE_DIR}/scripts/make_docs.py"
                   "${Ceres_SOURCE_DIR}"
                   "${Ceres_BINARY_DIR}/docs"
-                  "${SPHINX_EXECUTABLE}"
+                  "${Sphinx_BUILD_EXECUTABLE}"
+                  USES_TERMINAL
                   COMMENT "Building HTML documentation with Sphinx")
diff --git a/third_party/ceres/docs/source/automatic_derivatives.rst b/third_party/ceres/docs/source/automatic_derivatives.rst
index e15e911..3fe0727 100644
--- a/third_party/ceres/docs/source/automatic_derivatives.rst
+++ b/third_party/ceres/docs/source/automatic_derivatives.rst
@@ -37,9 +37,7 @@
   };
 
 
-  CostFunction* cost_function =
-        new AutoDiffCostFunction<Rat43CostFunctor, 1, 4>(
-          new Rat43CostFunctor(x, y));
+  auto* cost_function = new AutoDiffCostFunction<Rat43CostFunctor, 1, 4>(x, y);
 
 Notice that compared to numeric differentiation, the only difference
 when defining the functor for use with automatic differentiation is
@@ -298,7 +296,7 @@
 
 There is no single solution to this problem. In some cases one needs
 to reason explicitly about the points where indeterminacy may occur
-and use alternate expressions using `L'Hopital's rule
+and use alternate expressions using `L'Hôpital's rule
 <https://en.wikipedia.org/wiki/L'H%C3%B4pital's_rule>`_ (see for
 example some of the conversion routines in `rotation.h
 <https://github.com/ceres-solver/ceres-solver/blob/master/include/ceres/rotation.h>`_. In
diff --git a/third_party/ceres/docs/source/bibliography.rst b/third_party/ceres/docs/source/bibliography.rst
index c13c676..ba3bc87 100644
--- a/third_party/ceres/docs/source/bibliography.rst
+++ b/third_party/ceres/docs/source/bibliography.rst
@@ -4,6 +4,20 @@
 Bibliography
 ============
 
+Background Reading
+==================
+
+For a short but informative introduction to the subject we recommend
+the booklet by [Madsen]_ . For a general introduction to non-linear
+optimization we recommend [NocedalWright]_. [Bjorck]_ remains the
+seminal reference on least squares problems. [TrefethenBau]_ is our
+favorite text on introductory numerical linear algebra. [Triggs]_
+provides a thorough coverage of the bundle adjustment problem.
+
+
+References
+==========
+
 .. [Agarwal] S. Agarwal, N. Snavely, S. M. Seitz and R. Szeliski,
    **Bundle Adjustment in the Large**, *Proceedings of the European
    Conference on Computer Vision*, pp. 29--42, 2010.
@@ -31,6 +45,9 @@
 .. [Conn] A.R. Conn, N.I.M. Gould, and P.L. Toint, **Trust region
    methods**, *Society for Industrial Mathematics*, 2000.
 
+.. [Davis] Timothy A. Davis, **Direct methods for Sparse Linear
+   Systems**, *SIAM*, 2006.
+
 .. [Dellaert] F. Dellaert, J. Carlson, V. Ila, K. Ni and C. E. Thorpe,
    **Subgraph-preconditioned conjugate gradients for large scale SLAM**,
    *International Conference on Intelligent Robots and Systems*, 2010.
@@ -44,7 +61,7 @@
    Preconditioners for Sparse Linear Least-Squares Problems**,
    *ACM Trans. Math. Softw.*, 43(4), 2017.
 
-.. [HartleyZisserman] R.I. Hartley & A. Zisserman, **Multiview
+.. [HartleyZisserman] R.I. Hartley and A. Zisserman, **Multiview
    Geometry in Computer Vision**, Cambridge University Press, 2004.
 
 .. [Hertzberg] C. Hertzberg, R. Wagner, U. Frese and L. Schroder,
@@ -79,6 +96,11 @@
    preconditioner for large sparse least squares problems**, *SIAM
    Journal on Matrix Analysis and Applications*, 28(2):524-550, 2007.
 
+.. [LourakisArgyros] M. L. A. Lourakis, A. A. Argyros, **Is
+   Levenberg-Marquardt the most efficient algorithm for implementing
+   bundle adjustment?**, *International Conference on Computer
+   Vision*, 2005.
+
 .. [Madsen] K. Madsen, H.B. Nielsen, and O. Tingleff, **Methods for
    nonlinear least squares problems**, 2004.
 
@@ -100,7 +122,7 @@
 .. [Nocedal] J. Nocedal, **Updating Quasi-Newton Matrices with Limited
    Storage**, *Mathematics of Computation*, 35(151): 773--782, 1980.
 
-.. [NocedalWright] J. Nocedal & S. Wright, **Numerical Optimization**,
+.. [NocedalWright] J. Nocedal and S. Wright, **Numerical Optimization**,
    Springer, 2004.
 
 .. [Oren] S. S. Oren, **Self-scaling Variable Metric (SSVM) Algorithms
@@ -108,7 +130,7 @@
    20(5), 863-874, 1974.
 
 .. [Press] W. H. Press, S. A. Teukolsky, W. T. Vetterling
-   & B. P. Flannery, **Numerical Recipes**, Cambridge University
+   and B. P. Flannery, **Numerical Recipes**, Cambridge University
    Press, 2007.
 
 .. [Ridders] C. J. F. Ridders, **Accurate computation of F'(x) and
@@ -122,27 +144,37 @@
    systems**, SIAM, 2003.
 
 .. [Simon] I. Simon, N. Snavely and S. M. Seitz, **Scene Summarization
-   for Online Image Collections**, *International Conference on Computer Vision*, 2007.
+   for Online Image Collections**, *International Conference on
+   Computer Vision*, 2007.
 
 .. [Stigler] S. M. Stigler, **Gauss and the invention of least
    squares**, *The Annals of Statistics*, 9(3):465-474, 1981.
 
-.. [TenenbaumDirector] J. Tenenbaum & B. Director, **How Gauss
+.. [TenenbaumDirector] J. Tenenbaum and B. Director, **How Gauss
    Determined the Orbit of Ceres**.
 
 .. [TrefethenBau] L.N. Trefethen and D. Bau, **Numerical Linear
    Algebra**, SIAM, 1997.
 
-.. [Triggs] B. Triggs, P. F. Mclauchlan, R. I. Hartley &
+.. [Triggs] B. Triggs, P. F. Mclauchlan, R. I. Hartley and
    A. W. Fitzgibbon, **Bundle Adjustment: A Modern Synthesis**,
    Proceedings of the International Workshop on Vision Algorithms:
    Theory and Practice, pp. 298-372, 1999.
 
+.. [Weber] S. Weber, N. Demmel, TC Chan, D. Cremers, **Power Bundle
+   Adjustment for Large-Scale 3D Reconstruction**, *IEEE Conference on
+   Computer Vision and Pattern Recognition*, 2023.
+
 .. [Wiberg] T. Wiberg, **Computation of principal components when data
    are missing**, In Proc. *Second Symp. Computational Statistics*,
    pages 229-236, 1976.
 
-.. [WrightHolt] S. J. Wright and J. N. Holt, **An Inexact
-   Levenberg Marquardt Method for Large Sparse Nonlinear Least
-   Squares**, *Journal of the Australian Mathematical Society Series
-   B*, 26(4):387-403, 1985.
+.. [WrightHolt] S. J. Wright and J. N. Holt, **An Inexact Levenberg
+   Marquardt Method for Large Sparse Nonlinear Least Squares**,
+   *Journal of the Australian Mathematical Society Series B*,
+   26(4):387-403, 1985.
+
+.. [Zheng] Q. Zheng, Y. Xi and Y. Saad, **A power Schur Complement
+   low-rank correction preconditioner for general sparse linear
+   systems**, *SIAM Journal on Matrix Analysis and
+   Applications*, 2021.
diff --git a/third_party/ceres/docs/source/conf.py b/third_party/ceres/docs/source/conf.py
index c83468f..faa2403 100644
--- a/third_party/ceres/docs/source/conf.py
+++ b/third_party/ceres/docs/source/conf.py
@@ -25,7 +25,7 @@
 
 # Add any Sphinx extension module names here, as strings. They can be extensions
 # coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
-extensions = ['sphinx.ext.todo', 'sphinx.ext.mathjax', 'sphinx.ext.ifconfig']
+extensions = ['sphinx.ext.todo', 'sphinx.ext.mathjax', 'sphinx.ext.ifconfig', 'sphinxcontrib.jquery']
 
 # Add any paths that contain templates here, relative to this directory.
 templates_path = ['_templates']
@@ -41,16 +41,16 @@
 
 # General information about the project.
 project = u'Ceres Solver'
-copyright = u'2020 Google Inc'
+copyright = u'2023 Google Inc'
 
 # The version info for the project you're documenting, acts as replacement for
 # |version| and |release|, also used in various other places throughout the
 # built documents.
 #
 # The short X.Y version.
-version = '2.0'
+version = '2.2'
 # The full version, including alpha/beta/rc tags.
-release = '2.0.0'
+release = '2.2.0'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
@@ -246,7 +246,7 @@
 # By default MathJax does not use TeX fonts, which is a tragedy. Also
 # scaling the fonts down a bit makes them fit better with font sizing
 # in the "Read The Docs" theme.
-mathjax_config = {
+mathjax3_config = {
 'HTML-CSS' : {
         'availableFonts' : ["TeX"],
         'scale' : 90
diff --git a/third_party/ceres/docs/source/contributing.rst b/third_party/ceres/docs/source/contributing.rst
index a128e30..cba274c 100644
--- a/third_party/ceres/docs/source/contributing.rst
+++ b/third_party/ceres/docs/source/contributing.rst
@@ -118,8 +118,8 @@
 
    When the push succeeds, the console will display a URL showing the
    address of the review. Go to the URL and add at least one of the
-   maintainers (Sameer Agarwal, Keir Mierle, Alex Stewart or William
-   Rucklidge) as reviewers.
+   maintainers (Sameer Agarwal, Keir Mierle, Alex Stewart, William
+   Rucklidge or Sergiu Deitsch) as reviewers.
 
 3. Wait for a review.
 
diff --git a/third_party/ceres/docs/source/derivatives.rst b/third_party/ceres/docs/source/derivatives.rst
index bff6a29..d9a52b0 100644
--- a/third_party/ceres/docs/source/derivatives.rst
+++ b/third_party/ceres/docs/source/derivatives.rst
@@ -58,3 +58,4 @@
    numerical_derivatives
    automatic_derivatives
    interfacing_with_autodiff
+   inverse_and_implicit_function_theorems
diff --git a/third_party/ceres/docs/source/faqs.rst b/third_party/ceres/docs/source/faqs.rst
index 5a28f41..65c64e6 100644
--- a/third_party/ceres/docs/source/faqs.rst
+++ b/third_party/ceres/docs/source/faqs.rst
@@ -16,14 +16,3 @@
 
    modeling_faqs
    solving_faqs
-
-
-Further Reading
-===============
-
-For a short but informative introduction to the subject we recommend
-the booklet by [Madsen]_ . For a general introduction to non-linear
-optimization we recommend [NocedalWright]_. [Bjorck]_ remains the
-seminal reference on least squares problems. [TrefethenBau]_ book is
-our favorite text on introductory numerical linear algebra. [Triggs]_
-provides a thorough coverage of the bundle adjustment problem.
diff --git a/third_party/ceres/docs/source/features.rst b/third_party/ceres/docs/source/features.rst
index 724d6dc..609f41c 100644
--- a/third_party/ceres/docs/source/features.rst
+++ b/third_party/ceres/docs/source/features.rst
@@ -1,11 +1,15 @@
+.. default-domain:: cpp
+
+.. cpp:namespace:: ceres
+
 ====
 Why?
 ====
 .. _chapter-features:
 
 * **Code Quality** - Ceres Solver has been used in production at
-  Google for more than four years now. It is clean, extensively tested
-  and well documented code that is actively developed and supported.
+  Google since 2011. It is clean, extensively tested and well
+  documented code that is actively developed and supported.
 
 * **Modeling API** - It is rarely the case that one starts with the
   exact and complete formulation of the problem that one is trying to
@@ -27,10 +31,10 @@
     allows the user to *shape* their residuals using a
     :class:`LossFunction` to reduce the influence of outliers.
 
-  - **Local Parameterization** In many cases, some parameters lie on a
-    manifold other than Euclidean space, e.g., rotation matrices. In
-    such cases, the user can specify the geometry of the local tangent
-    space by specifying a :class:`LocalParameterization` object.
+  - **Manifolds** In many cases, some parameters lie on a manifold
+    other than Euclidean space, e.g., rotation matrices. In such
+    cases, the user can specify the geometry of the local tangent
+    space by specifying a :class:`Manifold` object.
 
 * **Solver Choice** Depending on the size, sparsity structure, time &
   memory budgets, and solution quality requirements, different
@@ -42,10 +46,11 @@
     computational cost in all of these methods is the solution of a
     linear system. To this end Ceres ships with a variety of linear
     solvers - dense QR and dense Cholesky factorization (using
-    `Eigen`_ or `LAPACK`_) for dense problems, sparse Cholesky
-    factorization (`SuiteSparse`_, `CXSparse`_ or `Eigen`_) for large
-    sparse problems, custom Schur complement based dense, sparse, and
-    iterative linear solvers for `bundle adjustment`_ problems.
+    `Eigen`_, `LAPACK`_ or `CUDA`_) for dense problems, sparse
+    Cholesky factorization (`SuiteSparse`_, `Apple's Accelerate`_,
+    `Eigen`_) for large sparse problems, custom Schur complement based
+    dense, sparse, and iterative linear solvers for `bundle
+    adjustment`_ problems.
 
   - **Line Search Solvers** - When the problem size is so large that
     storing and factoring the Jacobian is not feasible or a low
@@ -54,18 +59,21 @@
     of Non-linear Conjugate Gradients, BFGS and LBFGS.
 
 * **Speed** - Ceres Solver has been extensively optimized, with C++
-  templating, hand written linear algebra routines and OpenMP or
-  modern C++ threads based multithreading of the Jacobian evaluation
-  and the linear solvers.
+  templating, hand written linear algebra routines and modern C++
+  threads based multithreading of the Jacobian evaluation and the
+  linear solvers.
 
-* **Solution Quality** Ceres is the `best performing`_ solver on the NIST
-  problem set used by Mondragon and Borchers for benchmarking
+* **GPU Acceleration** If your system supports `CUDA`_ then Ceres
+  Solver can use the Nvidia GPU on your system to speed up the solver.
+
+* **Solution Quality** Ceres is the `best performing`_ solver on the
+  NIST problem set used by Mondragon and Borchers for benchmarking
   non-linear least squares solvers.
 
 * **Covariance estimation** - Evaluate the sensitivity/uncertainty of
   the solution by evaluating all or part of the covariance
-  matrix. Ceres is one of the few solvers that allows you to do
-  this analysis at scale.
+  matrix. Ceres is one of the few solvers that allows you to do this
+  analysis at scale.
 
 * **Community** Since its release as an open source software, Ceres
   has developed an active developer community that contributes new
@@ -82,6 +90,7 @@
 .. _SuiteSparse: http://www.cise.ufl.edu/research/sparse/SuiteSparse/
 .. _Eigen: http://eigen.tuxfamily.org/
 .. _LAPACK: http://www.netlib.org/lapack/
-.. _CXSparse: https://www.cise.ufl.edu/research/sparse/CXSparse/
 .. _automatic: http://en.wikipedia.org/wiki/Automatic_differentiation
 .. _numeric: http://en.wikipedia.org/wiki/Numerical_differentiation
+.. _CUDA : https://developer.nvidia.com/cuda-toolkit
+.. _Apple's Accelerate: https://developer.apple.com/documentation/accelerate/sparse_solvers
diff --git a/third_party/ceres/docs/source/gradient_solver.rst b/third_party/ceres/docs/source/gradient_solver.rst
index dde9d7e..4e3fc71 100644
--- a/third_party/ceres/docs/source/gradient_solver.rst
+++ b/third_party/ceres/docs/source/gradient_solver.rst
@@ -2,6 +2,8 @@
 
 .. default-domain:: cpp
 
+.. cpp:namespace:: ceres
+
 .. _chapter-gradient_problem_solver:
 
 ==================================
@@ -54,9 +56,9 @@
    public:
     explicit GradientProblem(FirstOrderFunction* function);
     GradientProblem(FirstOrderFunction* function,
-                    LocalParameterization* parameterization);
+                    Manifold* manifold);
     int NumParameters() const;
-    int NumLocalParameters() const;
+    int NumTangentParameters() const;
     bool Evaluate(const double* parameters, double* cost, double* gradient) const;
     bool Plus(const double* x, const double* delta, double* x_plus_delta) const;
   };
@@ -69,20 +71,18 @@
 form of the objective function.
 
 Structurally :class:`GradientProblem` is a composition of a
-:class:`FirstOrderFunction` and optionally a
-:class:`LocalParameterization`.
+:class:`FirstOrderFunction` and optionally a :class:`Manifold`.
 
 The :class:`FirstOrderFunction` is responsible for evaluating the cost
 and gradient of the objective function.
 
-The :class:`LocalParameterization` is responsible for going back and
-forth between the ambient space and the local tangent space. When a
-:class:`LocalParameterization` is not provided, then the tangent space
-is assumed to coincide with the ambient Euclidean space that the
-gradient vector lives in.
+The :class:`Manifold` is responsible for going back and forth between the
+ambient space and the local tangent space. When a :class:`Manifold` is not
+provided, then the tangent space is assumed to coincide with the ambient
+Euclidean space that the gradient vector lives in.
 
 The constructor takes ownership of the :class:`FirstOrderFunction` and
-:class:`LocalParamterization` objects passed to it.
+:class:`Manifold` objects passed to it.
 
 
 .. function:: void Solve(const GradientProblemSolver::Options& options, const GradientProblem& problem, double* parameters, GradientProblemSolver::Summary* summary)
@@ -103,7 +103,7 @@
    behavior of the solver. We list the various settings and their
    default values below.
 
-.. function:: bool GradientProblemSolver::Options::IsValid(string* error) const
+.. function:: bool GradientProblemSolver::Options::IsValid(std::string* error) const
 
    Validate the values in the options struct and returns true on
    success. If there is a problem, the method returns false with
@@ -123,7 +123,7 @@
    Choices are ``ARMIJO`` and ``WOLFE`` (strong Wolfe conditions).
    Note that in order for the assumptions underlying the ``BFGS`` and
    ``LBFGS`` line search direction algorithms to be guaranteed to be
-   satisifed, the ``WOLFE`` line search should be used.
+   satisfied, the ``WOLFE`` line search should be used.
 
 .. member:: NonlinearConjugateGradientType GradientProblemSolver::Options::nonlinear_conjugate_gradient_type
 
@@ -192,7 +192,7 @@
   low-sensitivity parameters. It can also reduce the robustness of the
   solution to errors in the Jacobians.
 
-.. member:: LineSearchIterpolationType GradientProblemSolver::Options::line_search_interpolation_type
+.. member:: LineSearchInterpolationType GradientProblemSolver::Options::line_search_interpolation_type
 
    Default: ``CUBIC``
 
@@ -342,8 +342,8 @@
 
    where :math:`\|\cdot\|_\infty` refers to the max norm, :math:`\Pi`
    is projection onto the bounds constraints and :math:`\boxplus` is
-   Plus operation for the overall local parameterization associated
-   with the parameter vector.
+   Plus operation for the manifold associated with the parameter
+   vector.
 
 .. member:: double GradientProblemSolver::Options::parameter_tolerance
 
@@ -388,14 +388,14 @@
    #. ``it`` is the time take by the current iteration.
    #. ``tt`` is the total time taken by the minimizer.
 
-.. member:: vector<IterationCallback> GradientProblemSolver::Options::callbacks
+.. member:: std::vector<IterationCallback> GradientProblemSolver::Options::callbacks
 
    Callbacks that are executed at the end of each iteration of the
    :class:`Minimizer`. They are executed in the order that they are
    specified in this vector. By default, parameter blocks are updated
    only at the end of the optimization, i.e., when the
    :class:`Minimizer` terminates. This behavior is controlled by
-   :member:`GradientProblemSolver::Options::update_state_every_variable`. If
+   :member:`GradientProblemSolver::Options::update_state_every_iteration`. If
    the user wishes to have access to the update parameter blocks when
    his/her callbacks are executed, then set
    :member:`GradientProblemSolver::Options::update_state_every_iteration`
@@ -404,7 +404,7 @@
    The solver does NOT take ownership of these pointers.
 
 
-.. member:: bool Solver::Options::update_state_every_iteration
+.. member:: bool GradientProblemSolver::Options::update_state_every_iteration
 
    Default: ``false``
 
@@ -420,12 +420,12 @@
 
    Summary of the various stages of the solver after termination.
 
-.. function:: string GradientProblemSolver::Summary::BriefReport() const
+.. function:: std::string GradientProblemSolver::Summary::BriefReport() const
 
    A brief one line description of the state of the solver after
    termination.
 
-.. function:: string GradientProblemSolver::Summary::FullReport() const
+.. function:: std::string GradientProblemSolver::Summary::FullReport() const
 
    A full multiline description of the state of the solver after
    termination.
@@ -444,7 +444,7 @@
 
    The cause of the minimizer terminating.
 
-.. member:: string GradientProblemSolver::Summary::message
+.. member:: std::string GradientProblemSolver::Summary::message
 
    Reason why the solver terminated.
 
@@ -458,7 +458,7 @@
    Cost of the problem (value of the objective function) after the
    optimization.
 
-.. member:: vector<IterationSummary> GradientProblemSolver::Summary::iterations
+.. member:: std::vector<IterationSummary> GradientProblemSolver::Summary::iterations
 
    :class:`IterationSummary` for each minimizer iteration in order.
 
@@ -486,11 +486,11 @@
 
    Number of parameters in the problem.
 
-.. member:: int GradientProblemSolver::Summary::num_local_parameters
+.. member:: int GradientProblemSolver::Summary::num_tangent_parameters
 
    Dimension of the tangent space of the problem. This is different
    from :member:`GradientProblemSolver::Summary::num_parameters` if a
-   :class:`LocalParameterization` object is used.
+   :class:`Manifold` object is used.
 
 .. member:: LineSearchDirectionType GradientProblemSolver::Summary::line_search_direction_type
 
diff --git a/third_party/ceres/docs/source/gradient_tutorial.rst b/third_party/ceres/docs/source/gradient_tutorial.rst
index 3fef6b6..2af44e1 100644
--- a/third_party/ceres/docs/source/gradient_tutorial.rst
+++ b/third_party/ceres/docs/source/gradient_tutorial.rst
@@ -2,52 +2,53 @@
 
 .. default-domain:: cpp
 
+.. cpp:namespace:: ceres
+
 .. _chapter-gradient_tutorial:
 
 ==================================
 General Unconstrained Minimization
 ==================================
 
-While much of Ceres Solver is devoted to solving non-linear least
-squares problems, internally it contains a solver that can solve
-general unconstrained optimization problems using just their objective
-function value and gradients. The ``GradientProblem`` and
-``GradientProblemSolver`` objects give the user access to this solver.
-
-So without much further ado, let us look at how one goes about using
-them.
+Ceres Solver besides being able to solve non-linear least squares
+problem can also solve general unconstrained problems using just their
+objective function value and gradients. In this chapter we will see
+how to do this.
 
 Rosenbrock's Function
 =====================
 
-We consider the minimization of the famous `Rosenbrock's function
+Consider minimizing the famous `Rosenbrock's function
 <http://en.wikipedia.org/wiki/Rosenbrock_function>`_ [#f1]_.
 
-We begin by defining an instance of the ``FirstOrderFunction``
-interface. This is the object that is responsible for computing the
-objective function value and the gradient (if required). This is the
-analog of the :class:`CostFunction` when defining non-linear least
-squares problems in Ceres.
+The simplest way to minimize is to define a templated functor to
+evaluate the objective value of this function and then use Ceres
+Solver's automatic differentiation to compute its derivatives.
+
+We begin by defining a templated functor and then using
+``AutoDiffFirstOrderFunction`` to construct an instance of the
+``FirstOrderFunction`` interface. This is the object that is
+responsible for computing the objective function value and the
+gradient (if required). This is the analog of the
+:class:`CostFunction` when defining non-linear least squares problems
+in Ceres.
 
 .. code::
 
-  class Rosenbrock : public ceres::FirstOrderFunction {
-   public:
-    virtual bool Evaluate(const double* parameters,
-                          double* cost,
-                          double* gradient) const {
-      const double x = parameters[0];
-      const double y = parameters[1];
-
+  // f(x,y) = (1-x)^2 + 100(y - x^2)^2;
+  struct Rosenbrock {
+    template <typename T>
+    bool operator()(const T* parameters, T* cost) const {
+      const T x = parameters[0];
+      const T y = parameters[1];
       cost[0] = (1.0 - x) * (1.0 - x) + 100.0 * (y - x * x) * (y - x * x);
-      if (gradient != nullptr) {
-        gradient[0] = -2.0 * (1.0 - x) - 200.0 * (y - x * x) * 2.0 * x;
-        gradient[1] = 200.0 * (y - x * x);
-      }
       return true;
     }
 
-    virtual int NumParameters() const { return 2; }
+    static ceres::FirstOrderFunction* Create() {
+      constexpr int kNumParameters = 2;
+      return new ceres::AutoDiffFirstOrderFunction<Rosenbrock, kNumParameters>();
+    }
   };
 
 
@@ -58,7 +59,7 @@
 
     double parameters[2] = {-1.2, 1.0};
 
-    ceres::GradientProblem problem(new Rosenbrock());
+    ceres::GradientProblem problem(Rosenbrock::Create());
 
     ceres::GradientProblemSolver::Options options;
     options.minimizer_progress_to_stdout = true;
@@ -74,65 +75,130 @@
 
 .. code-block:: bash
 
-     0: f: 2.420000e+01 d: 0.00e+00 g: 2.16e+02 h: 0.00e+00 s: 0.00e+00 e:  0 it: 2.00e-05 tt: 2.00e-05
-     1: f: 4.280493e+00 d: 1.99e+01 g: 1.52e+01 h: 2.01e-01 s: 8.62e-04 e:  2 it: 7.32e-05 tt: 2.19e-04
-     2: f: 3.571154e+00 d: 7.09e-01 g: 1.35e+01 h: 3.78e-01 s: 1.34e-01 e:  3 it: 2.50e-05 tt: 2.68e-04
-     3: f: 3.440869e+00 d: 1.30e-01 g: 1.73e+01 h: 1.36e-01 s: 1.00e+00 e:  1 it: 4.05e-06 tt: 2.92e-04
-     4: f: 3.213597e+00 d: 2.27e-01 g: 1.55e+01 h: 1.06e-01 s: 4.59e-01 e:  1 it: 2.86e-06 tt: 3.14e-04
-     5: f: 2.839723e+00 d: 3.74e-01 g: 1.05e+01 h: 1.34e-01 s: 5.24e-01 e:  1 it: 2.86e-06 tt: 3.36e-04
-     6: f: 2.448490e+00 d: 3.91e-01 g: 1.29e+01 h: 3.04e-01 s: 1.00e+00 e:  1 it: 4.05e-06 tt: 3.58e-04
-     7: f: 1.943019e+00 d: 5.05e-01 g: 4.00e+00 h: 8.81e-02 s: 7.43e-01 e:  1 it: 4.05e-06 tt: 3.79e-04
-     8: f: 1.731469e+00 d: 2.12e-01 g: 7.36e+00 h: 1.71e-01 s: 4.60e-01 e:  2 it: 9.06e-06 tt: 4.06e-04
-     9: f: 1.503267e+00 d: 2.28e-01 g: 6.47e+00 h: 8.66e-02 s: 1.00e+00 e:  1 it: 3.81e-06 tt: 4.33e-04
-    10: f: 1.228331e+00 d: 2.75e-01 g: 2.00e+00 h: 7.70e-02 s: 7.90e-01 e:  1 it: 3.81e-06 tt: 4.54e-04
-    11: f: 1.016523e+00 d: 2.12e-01 g: 5.15e+00 h: 1.39e-01 s: 3.76e-01 e:  2 it: 1.00e-05 tt: 4.82e-04
-    12: f: 9.145773e-01 d: 1.02e-01 g: 6.74e+00 h: 7.98e-02 s: 1.00e+00 e:  1 it: 3.10e-06 tt: 5.03e-04
-    13: f: 7.508302e-01 d: 1.64e-01 g: 3.88e+00 h: 5.76e-02 s: 4.93e-01 e:  1 it: 2.86e-06 tt: 5.25e-04
-    14: f: 5.832378e-01 d: 1.68e-01 g: 5.56e+00 h: 1.42e-01 s: 1.00e+00 e:  1 it: 3.81e-06 tt: 5.47e-04
-    15: f: 3.969581e-01 d: 1.86e-01 g: 1.64e+00 h: 1.17e-01 s: 1.00e+00 e:  1 it: 4.05e-06 tt: 5.68e-04
-    16: f: 3.171557e-01 d: 7.98e-02 g: 3.84e+00 h: 1.18e-01 s: 3.97e-01 e:  2 it: 9.06e-06 tt: 5.94e-04
-    17: f: 2.641257e-01 d: 5.30e-02 g: 3.27e+00 h: 6.14e-02 s: 1.00e+00 e:  1 it: 3.10e-06 tt: 6.16e-04
-    18: f: 1.909730e-01 d: 7.32e-02 g: 5.29e-01 h: 8.55e-02 s: 6.82e-01 e:  1 it: 4.05e-06 tt: 6.42e-04
-    19: f: 1.472012e-01 d: 4.38e-02 g: 3.11e+00 h: 1.20e-01 s: 3.47e-01 e:  2 it: 1.00e-05 tt: 6.69e-04
-    20: f: 1.093558e-01 d: 3.78e-02 g: 2.97e+00 h: 8.43e-02 s: 1.00e+00 e:  1 it: 3.81e-06 tt: 6.91e-04
-    21: f: 6.710346e-02 d: 4.23e-02 g: 1.42e+00 h: 9.64e-02 s: 8.85e-01 e:  1 it: 3.81e-06 tt: 7.12e-04
-    22: f: 3.993377e-02 d: 2.72e-02 g: 2.30e+00 h: 1.29e-01 s: 4.63e-01 e:  2 it: 9.06e-06 tt: 7.39e-04
-    23: f: 2.911794e-02 d: 1.08e-02 g: 2.55e+00 h: 6.55e-02 s: 1.00e+00 e:  1 it: 4.05e-06 tt: 7.62e-04
-    24: f: 1.457683e-02 d: 1.45e-02 g: 2.77e-01 h: 6.37e-02 s: 6.14e-01 e:  1 it: 3.81e-06 tt: 7.84e-04
-    25: f: 8.577515e-03 d: 6.00e-03 g: 2.86e+00 h: 1.40e-01 s: 1.00e+00 e:  1 it: 4.05e-06 tt: 8.05e-04
-    26: f: 3.486574e-03 d: 5.09e-03 g: 1.76e-01 h: 1.23e-02 s: 1.00e+00 e:  1 it: 4.05e-06 tt: 8.27e-04
-    27: f: 1.257570e-03 d: 2.23e-03 g: 1.39e-01 h: 5.08e-02 s: 1.00e+00 e:  1 it: 4.05e-06 tt: 8.48e-04
-    28: f: 2.783568e-04 d: 9.79e-04 g: 6.20e-01 h: 6.47e-02 s: 1.00e+00 e:  1 it: 4.05e-06 tt: 8.69e-04
-    29: f: 2.533399e-05 d: 2.53e-04 g: 1.68e-02 h: 1.98e-03 s: 1.00e+00 e:  1 it: 3.81e-06 tt: 8.91e-04
-    30: f: 7.591572e-07 d: 2.46e-05 g: 5.40e-03 h: 9.27e-03 s: 1.00e+00 e:  1 it: 3.81e-06 tt: 9.12e-04
-    31: f: 1.902460e-09 d: 7.57e-07 g: 1.62e-03 h: 1.89e-03 s: 1.00e+00 e:  1 it: 2.86e-06 tt: 9.33e-04
-    32: f: 1.003030e-12 d: 1.90e-09 g: 3.50e-05 h: 3.52e-05 s: 1.00e+00 e:  1 it: 3.10e-06 tt: 9.54e-04
-    33: f: 4.835994e-17 d: 1.00e-12 g: 1.05e-07 h: 1.13e-06 s: 1.00e+00 e:  1 it: 4.05e-06 tt: 9.81e-04
-    34: f: 1.885250e-22 d: 4.84e-17 g: 2.69e-10 h: 1.45e-08 s: 1.00e+00 e:  1 it: 4.05e-06 tt: 1.00e-03
+       0: f: 2.420000e+01 d: 0.00e+00 g: 2.16e+02 h: 0.00e+00 s: 0.00e+00 e:  0 it: 1.19e-05 tt: 1.19e-05
+       1: f: 4.280493e+00 d: 1.99e+01 g: 1.52e+01 h: 2.01e-01 s: 8.62e-04 e:  2 it: 7.30e-05 tt: 1.72e-04
+       2: f: 3.571154e+00 d: 7.09e-01 g: 1.35e+01 h: 3.78e-01 s: 1.34e-01 e:  3 it: 1.60e-05 tt: 1.93e-04
+       3: f: 3.440869e+00 d: 1.30e-01 g: 1.73e+01 h: 1.36e-01 s: 1.00e+00 e:  1 it: 9.54e-07 tt: 1.97e-04
+       4: f: 3.213597e+00 d: 2.27e-01 g: 1.55e+01 h: 1.06e-01 s: 4.59e-01 e:  1 it: 1.19e-06 tt: 2.00e-04
+       5: f: 2.839723e+00 d: 3.74e-01 g: 1.05e+01 h: 1.34e-01 s: 5.24e-01 e:  1 it: 9.54e-07 tt: 2.03e-04
+       6: f: 2.448490e+00 d: 3.91e-01 g: 1.29e+01 h: 3.04e-01 s: 1.00e+00 e:  1 it: 9.54e-07 tt: 2.05e-04
+       7: f: 1.943019e+00 d: 5.05e-01 g: 4.00e+00 h: 8.81e-02 s: 7.43e-01 e:  1 it: 9.54e-07 tt: 2.08e-04
+       8: f: 1.731469e+00 d: 2.12e-01 g: 7.36e+00 h: 1.71e-01 s: 4.60e-01 e:  2 it: 2.15e-06 tt: 2.11e-04
+       9: f: 1.503267e+00 d: 2.28e-01 g: 6.47e+00 h: 8.66e-02 s: 1.00e+00 e:  1 it: 9.54e-07 tt: 2.14e-04
+      10: f: 1.228331e+00 d: 2.75e-01 g: 2.00e+00 h: 7.70e-02 s: 7.90e-01 e:  1 it: 0.00e+00 tt: 2.16e-04
+      11: f: 1.016523e+00 d: 2.12e-01 g: 5.15e+00 h: 1.39e-01 s: 3.76e-01 e:  2 it: 1.91e-06 tt: 2.25e-04
+      12: f: 9.145773e-01 d: 1.02e-01 g: 6.74e+00 h: 7.98e-02 s: 1.00e+00 e:  1 it: 9.54e-07 tt: 2.28e-04
+      13: f: 7.508302e-01 d: 1.64e-01 g: 3.88e+00 h: 5.76e-02 s: 4.93e-01 e:  1 it: 9.54e-07 tt: 2.30e-04
+      14: f: 5.832378e-01 d: 1.68e-01 g: 5.56e+00 h: 1.42e-01 s: 1.00e+00 e:  1 it: 9.54e-07 tt: 2.33e-04
+      15: f: 3.969581e-01 d: 1.86e-01 g: 1.64e+00 h: 1.17e-01 s: 1.00e+00 e:  1 it: 1.19e-06 tt: 2.36e-04
+      16: f: 3.171557e-01 d: 7.98e-02 g: 3.84e+00 h: 1.18e-01 s: 3.97e-01 e:  2 it: 1.91e-06 tt: 2.39e-04
+      17: f: 2.641257e-01 d: 5.30e-02 g: 3.27e+00 h: 6.14e-02 s: 1.00e+00 e:  1 it: 1.19e-06 tt: 2.42e-04
+      18: f: 1.909730e-01 d: 7.32e-02 g: 5.29e-01 h: 8.55e-02 s: 6.82e-01 e:  1 it: 9.54e-07 tt: 2.45e-04
+      19: f: 1.472012e-01 d: 4.38e-02 g: 3.11e+00 h: 1.20e-01 s: 3.47e-01 e:  2 it: 1.91e-06 tt: 2.49e-04
+      20: f: 1.093558e-01 d: 3.78e-02 g: 2.97e+00 h: 8.43e-02 s: 1.00e+00 e:  1 it: 2.15e-06 tt: 2.52e-04
+      21: f: 6.710346e-02 d: 4.23e-02 g: 1.42e+00 h: 9.64e-02 s: 8.85e-01 e:  1 it: 8.82e-06 tt: 2.81e-04
+      22: f: 3.993377e-02 d: 2.72e-02 g: 2.30e+00 h: 1.29e-01 s: 4.63e-01 e:  2 it: 7.87e-06 tt: 2.96e-04
+      23: f: 2.911794e-02 d: 1.08e-02 g: 2.55e+00 h: 6.55e-02 s: 1.00e+00 e:  1 it: 9.54e-07 tt: 3.00e-04
+      24: f: 1.457683e-02 d: 1.45e-02 g: 2.77e-01 h: 6.37e-02 s: 6.14e-01 e:  1 it: 1.19e-06 tt: 3.03e-04
+      25: f: 8.577515e-03 d: 6.00e-03 g: 2.86e+00 h: 1.40e-01 s: 1.00e+00 e:  1 it: 9.54e-07 tt: 3.06e-04
+      26: f: 3.486574e-03 d: 5.09e-03 g: 1.76e-01 h: 1.23e-02 s: 1.00e+00 e:  1 it: 1.19e-06 tt: 3.09e-04
+      27: f: 1.257570e-03 d: 2.23e-03 g: 1.39e-01 h: 5.08e-02 s: 1.00e+00 e:  1 it: 9.54e-07 tt: 3.12e-04
+      28: f: 2.783568e-04 d: 9.79e-04 g: 6.20e-01 h: 6.47e-02 s: 1.00e+00 e:  1 it: 9.54e-07 tt: 3.15e-04
+      29: f: 2.533399e-05 d: 2.53e-04 g: 1.68e-02 h: 1.98e-03 s: 1.00e+00 e:  1 it: 9.54e-07 tt: 3.17e-04
+      30: f: 7.591572e-07 d: 2.46e-05 g: 5.40e-03 h: 9.27e-03 s: 1.00e+00 e:  1 it: 9.54e-07 tt: 3.20e-04
+      31: f: 1.902460e-09 d: 7.57e-07 g: 1.62e-03 h: 1.89e-03 s: 1.00e+00 e:  1 it: 9.54e-07 tt: 3.23e-04
+      32: f: 1.003030e-12 d: 1.90e-09 g: 3.50e-05 h: 3.52e-05 s: 1.00e+00 e:  1 it: 9.54e-07 tt: 3.26e-04
+      33: f: 4.835994e-17 d: 1.00e-12 g: 1.05e-07 h: 1.13e-06 s: 1.00e+00 e:  1 it: 1.19e-06 tt: 3.34e-04
+      34: f: 1.885250e-22 d: 4.84e-17 g: 2.69e-10 h: 1.45e-08 s: 1.00e+00 e:  1 it: 9.54e-07 tt: 3.37e-04
 
-  Solver Summary (v 1.12.0-lapack-suitesparse-cxsparse-no_openmp)
+    Solver Summary (v 2.2.0-eigen-(3.4.0)-lapack-suitesparse-(7.1.0)-metis-(5.1.0)-acceleratesparse-eigensparse)
 
-  Parameters                                  2
-  Line search direction              LBFGS (20)
-  Line search type                  CUBIC WOLFE
+    Parameters                                  2
+    Line search direction              LBFGS (20)
+    Line search type                  CUBIC WOLFE
 
 
-  Cost:
-  Initial                          2.420000e+01
-  Final                            1.885250e-22
-  Change                           2.420000e+01
+    Cost:
+    Initial                          2.420000e+01
+    Final                            1.955192e-27
+    Change                           2.420000e+01
 
-  Minimizer iterations                       35
+    Minimizer iterations                       36
 
-  Time (in seconds):
+    Time (in seconds):
 
-    Cost evaluation                       0.000
-    Gradient evaluation                   0.000
-  Total                                   0.003
+      Cost evaluation                    0.000000 (0)
+      Gradient & cost evaluation         0.000000 (44)
+      Polynomial minimization            0.000061
+    Total                                0.000438
 
-  Termination:                      CONVERGENCE (Gradient tolerance reached. Gradient max norm: 9.032775e-13 <= 1.000000e-10)
+    Termination:                      CONVERGENCE (Parameter tolerance reached. Relative step_norm: 1.890726e-11 <= 1.000000e-08.)
+
+    Initial x: -1.2 y: 1
+    Final   x: 1 y: 1
+
+
+
+
+If you are unable to use automatic differentiation for some reason
+(say because you need to call an external library), then you can
+use numeric differentiation. In that case the functor is defined as
+follows [#f2]_.
+
+.. code::
+
+  // f(x,y) = (1-x)^2 + 100(y - x^2)^2;
+  struct Rosenbrock {
+    bool operator()(const double* parameters, double* cost) const {
+      const double x = parameters[0];
+      const double y = parameters[1];
+      cost[0] = (1.0 - x) * (1.0 - x) + 100.0 * (y - x * x) * (y - x * x);
+      return true;
+    }
+
+    static ceres::FirstOrderFunction* Create() {
+      constexpr int kNumParameters = 2;
+      return new ceres::NumericDiffFirstOrderFunction<Rosenbrock,
+                                                      ceres::CENTRAL,
+                                                      kNumParameters>();
+    }
+  };
+
+And finally, if you would rather compute the derivatives by hand (say
+because the size of the parameter vector is too large to be
+automatically differentiated). Then you should define an instance of
+`FirstOrderFunction`, which is the analog of :class:`CostFunction` for
+non-linear least squares problems [#f3]_.
+
+.. code::
+
+  // f(x,y) = (1-x)^2 + 100(y - x^2)^2;
+  class Rosenbrock final  : public ceres::FirstOrderFunction {
+    public:
+      bool Evaluate(const double* parameters,
+                             double* cost,
+                             double* gradient) const override {
+         const double x = parameters[0];
+         const double y = parameters[1];
+
+         cost[0] = (1.0 - x) * (1.0 - x) + 100.0 * (y - x * x) * (y - x * x);
+         if (gradient) {
+           gradient[0] = -2.0 * (1.0 - x) - 200.0 * (y - x * x) * 2.0 * x;
+           gradient[1] = 200.0 * (y - x * x);
+         }
+        return true;
+     }
+
+     int NumParameters() const override { return 2; }
+  };
 
 .. rubric:: Footnotes
 
 .. [#f1] `examples/rosenbrock.cc
    <https://ceres-solver.googlesource.com/ceres-solver/+/master/examples/rosenbrock.cc>`_
+
+.. [#f2] `examples/rosenbrock_numeric_diff.cc
+   <https://ceres-solver.googlesource.com/ceres-solver/+/master/examples/rosenbrock_numeric_diff.cc>`_
+
+.. [#f3] `examples/rosenbrock_analytic_diff.cc
+   <https://ceres-solver.googlesource.com/ceres-solver/+/master/examples/rosenbrock_analytic_diff.cc>`_
diff --git a/third_party/ceres/docs/source/index.rst b/third_party/ceres/docs/source/index.rst
index d72368f..497b12c 100644
--- a/third_party/ceres/docs/source/index.rst
+++ b/third_party/ceres/docs/source/index.rst
@@ -44,12 +44,15 @@
 
 If you use Ceres Solver for a publication, please cite it as::
 
-    @misc{ceres-solver,
-      author = "Sameer Agarwal and Keir Mierle and Others",
-      title = "Ceres Solver",
-      howpublished = "\url{http://ceres-solver.org}",
-    }
-
+  @software{Agarwal_Ceres_Solver_2022,
+    author = {Agarwal, Sameer and Mierle, Keir and The Ceres Solver Team},
+    title = {{Ceres Solver}},
+    license = {Apache-2.0},
+    url = {https://github.com/ceres-solver/ceres-solver},
+    version = {2.2},
+    year = {2023},
+    month = {10}
+  }
 
 .. rubric:: Footnotes
 
diff --git a/third_party/ceres/docs/source/installation.rst b/third_party/ceres/docs/source/installation.rst
index 7f49783..4feb1a4 100644
--- a/third_party/ceres/docs/source/installation.rst
+++ b/third_party/ceres/docs/source/installation.rst
@@ -9,7 +9,7 @@
 .. _section-source:
 
 You can start with the `latest stable release
-<http://ceres-solver.org/ceres-solver-2.0.0.tar.gz>`_ . Or if you want
+<http://ceres-solver.org/ceres-solver-2.2.0.tar.gz>`_ . Or if you want
 the latest version, you can clone the git repository
 
 .. code-block:: bash
@@ -21,15 +21,16 @@
 Dependencies
 ============
 
-  .. NOTE ::
+ .. note ::
 
-    Starting with v2.0 Ceres requires a **fully C++14-compliant**
-    compiler.  In versions <= 1.14, C++11 was an optional requirement.
+    Ceres Solver 2.2 requires a **fully C++17-compliant** compiler.
 
 Ceres relies on a number of open source libraries, some of which are
 optional. For details on customizing the build process, see
 :ref:`section-customizing` .
 
+- `CMake <http://www.cmake.org>`_ 3.16 or later **required**.
+
 - `Eigen <http://eigen.tuxfamily.org/index.php?title=Main_Page>`_
   3.3 or later **required**.
 
@@ -39,9 +40,7 @@
     library. Please see the documentation for ``EIGENSPARSE`` for
     more details.
 
-- `CMake <http://www.cmake.org>`_ 3.5 or later **required**.
-
-- `glog <https://github.com/google/glog>`_ 0.3.1 or
+- `glog <https://github.com/google/glog>`_ 0.3.5 or
   later. **Recommended**
 
   ``glog`` is used extensively throughout Ceres for logging detailed
@@ -65,22 +64,13 @@
   recommend against it. ``miniglog`` has worse performance than
   ``glog`` and is much harder to control and use.
 
-  .. NOTE ::
-
-     If you are compiling ``glog`` from source, please note that
-     currently, the unit tests for ``glog`` (which are enabled by
-     default) do not compile against a default build of ``gflags`` 2.1
-     as the gflags namespace changed from ``google::`` to
-     ``gflags::``.  A patch to fix this is available from `here
-     <https://code.google.com/p/google-glog/issues/detail?id=194>`_.
-
 - `gflags <https://github.com/gflags/gflags>`_. Needed to build
   examples and tests and usually a dependency for glog.
 
-- `SuiteSparse
-  <http://faculty.cse.tamu.edu/davis/suitesparse.html>`_. Needed for
-  solving large sparse linear systems. **Optional; strongly recomended
-  for large scale bundle adjustment**
+- `SuiteSparse <http://faculty.cse.tamu.edu/davis/suitesparse.html>`_
+  4.5.6 or later. Needed for solving large sparse linear
+  systems. **Optional; strongly recommended for large scale bundle
+  adjustment**
 
   .. NOTE ::
 
@@ -90,10 +80,10 @@
      found TBB version. You can customize the searched TBB location
      with the ``TBB_ROOT`` variable.
 
-- `CXSparse <http://faculty.cse.tamu.edu/davis/suitesparse.html>`_.
-  Similar to ``SuiteSparse`` but simpler and slower. CXSparse has
-  no dependencies on ``LAPACK`` and ``BLAS``. This makes for a simpler
-  build process and a smaller binary. **Optional**
+  A CMake native version of SuiteSparse that can be compiled on a variety of
+  platforms (e.g., using Visual Studio, Xcode, MinGW, etc.) is maintained by the
+  `CMake support for SuiteSparse <https://github.com/sergiud/SuiteSparse>`_
+  project.
 
 - `Apple's Accelerate sparse solvers <https://developer.apple.com/documentation/accelerate/sparse_solvers>`_.
   As of Xcode 9.0, Apple's Accelerate framework includes support for
@@ -104,9 +94,13 @@
   ``SuiteSparse``, and optionally used by Ceres directly for some
   operations.
 
-  On ``UNIX`` OSes other than macOS we recommend `ATLAS
+  For best performance on ``x86`` based Linux systems we recommend
+  using `Intel MKL
+  <https://www.intel.com/content/www/us/en/develop/documentation/get-started-with-mkl-for-dpcpp/top.html>`_.
+
+  Two other good options are `ATLAS
   <http://math-atlas.sourceforge.net/>`_, which includes ``BLAS`` and
-  ``LAPACK`` routines. It is also possible to use `OpenBLAS
+  ``LAPACK`` routines and `OpenBLAS
   <https://github.com/xianyi/OpenBLAS>`_ . However, one needs to be
   careful to `turn off the threading
   <https://github.com/xianyi/OpenBLAS/wiki/faq#wiki-multi-threaded>`_
@@ -122,6 +116,15 @@
 
   **Optional but required for** ``SuiteSparse``.
 
+- `CUDA <https://developer.nvidia.com/cuda-toolkit>`_ If you have an
+  NVIDIA GPU then Ceres Solver can use it accelerate the solution of
+  the Gauss-Newton linear systems using the CMake flag ``USE_CUDA``.
+  Currently this support is limited to using the dense linear solvers that ship
+  with ``CUDA``. As a result GPU acceleration can be used to speed up
+  ``DENSE_QR``, ``DENSE_NORMAL_CHOLESKY`` and
+  ``DENSE_SCHUR``. This also enables ``CUDA`` mixed precision solves
+  for ``DENSE_NORMAL_CHOLESKY`` and ``DENSE_SCHUR``.  **Optional**.
+
 .. _section-linux:
 
 Linux
@@ -130,11 +133,12 @@
 We will use `Ubuntu <http://www.ubuntu.com>`_ as our example linux
 distribution.
 
-  .. NOTE ::
+.. NOTE::
 
-    These instructions are for Ubuntu 18.04 and newer. On Ubuntu 16.04
-    you need to manually get a more recent version of Eigen, such as
-    3.3.7.
+   Ceres Solver always supports the previous and current Ubuntu LTS
+   releases, currently 18.04 and 20.04, using the default Ubuntu
+   repositories and compiler toolchain. Support for earlier versions
+   is not guaranteed or maintained.
 
 Start by installing all the dependencies.
 
@@ -144,21 +148,21 @@
      sudo apt-get install cmake
      # google-glog + gflags
      sudo apt-get install libgoogle-glog-dev libgflags-dev
-     # BLAS & LAPACK
+     # Use ATLAS for BLAS & LAPACK
      sudo apt-get install libatlas-base-dev
      # Eigen3
      sudo apt-get install libeigen3-dev
-     # SuiteSparse and CXSparse (optional)
+     # SuiteSparse (optional)
      sudo apt-get install libsuitesparse-dev
 
 We are now ready to build, test, and install Ceres.
 
 .. code-block:: bash
 
- tar zxf ceres-solver-2.0.0.tar.gz
+ tar zxf ceres-solver-2.2.0.tar.gz
  mkdir ceres-bin
  cd ceres-bin
- cmake ../ceres-solver-2.0.0
+ cmake ../ceres-solver-2.2.0
  make -j3
  make test
  # Optionally install Ceres, it can also be exported using CMake which
@@ -172,7 +176,7 @@
 
 .. code-block:: bash
 
- bin/simple_bundle_adjuster ../ceres-solver-2.0.0/data/problem-16-22106-pre.txt
+ bin/simple_bundle_adjuster ../ceres-solver-2.2.0/data/problem-16-22106-pre.txt
 
 This runs Ceres for a maximum of 10 iterations using the
 ``DENSE_SCHUR`` linear solver. The output should look something like
@@ -181,63 +185,63 @@
 .. code-block:: bash
 
     iter      cost      cost_change  |gradient|   |step|    tr_ratio  tr_radius  ls_iter  iter_time  total_time
-       0  4.185660e+06    0.00e+00    1.09e+08   0.00e+00   0.00e+00  1.00e+04       0    7.59e-02    3.37e-01
-       1  1.062590e+05    4.08e+06    8.99e+06   5.36e+02   9.82e-01  3.00e+04       1    1.65e-01    5.03e-01
-       2  4.992817e+04    5.63e+04    8.32e+06   3.19e+02   6.52e-01  3.09e+04       1    1.45e-01    6.48e-01
-       3  1.899774e+04    3.09e+04    1.60e+06   1.24e+02   9.77e-01  9.26e+04       1    1.43e-01    7.92e-01
-       4  1.808729e+04    9.10e+02    3.97e+05   6.39e+01   9.51e-01  2.78e+05       1    1.45e-01    9.36e-01
-       5  1.803399e+04    5.33e+01    1.48e+04   1.23e+01   9.99e-01  8.33e+05       1    1.45e-01    1.08e+00
-       6  1.803390e+04    9.02e-02    6.35e+01   8.00e-01   1.00e+00  2.50e+06       1    1.50e-01    1.23e+00
+       0  4.185660e+06    0.00e+00    1.09e+08   0.00e+00   0.00e+00  1.00e+04        0    2.18e-02    6.57e-02
+       1  1.062590e+05    4.08e+06    8.99e+06   0.00e+00   9.82e-01  3.00e+04        1    5.07e-02    1.16e-01
+       2  4.992817e+04    5.63e+04    8.32e+06   3.19e+02   6.52e-01  3.09e+04        1    4.75e-02    1.64e-01
+       3  1.899774e+04    3.09e+04    1.60e+06   1.24e+02   9.77e-01  9.26e+04        1    4.74e-02    2.11e-01
+       4  1.808729e+04    9.10e+02    3.97e+05   6.39e+01   9.51e-01  2.78e+05        1    4.75e-02    2.59e-01
+       5  1.803399e+04    5.33e+01    1.48e+04   1.23e+01   9.99e-01  8.33e+05        1    4.74e-02    3.06e-01
+       6  1.803390e+04    9.02e-02    6.35e+01   8.00e-01   1.00e+00  2.50e+06        1    4.76e-02    3.54e-01
 
-    Ceres Solver v2.0.0 Solve Report
-    ----------------------------------
+    Solver Summary (v 2.2.0-eigen-(3.4.0)-lapack-suitesparse-(7.1.0)-metis-(5.1.0)-acceleratesparse-eigensparse)
+
                                          Original                  Reduced
     Parameter blocks                        22122                    22122
     Parameters                              66462                    66462
     Residual blocks                         83718                    83718
-    Residual                               167436                   167436
+    Residuals                              167436                   167436
 
     Minimizer                        TRUST_REGION
 
     Dense linear algebra library            EIGEN
     Trust region strategy     LEVENBERG_MARQUARDT
-
                                             Given                     Used
     Linear solver                     DENSE_SCHUR              DENSE_SCHUR
     Threads                                     1                        1
-    Linear solver threads                       1                        1
-    Linear solver ordering              AUTOMATIC                22106, 16
+    Linear solver ordering              AUTOMATIC                 22106,16
+    Schur structure                         2,3,9                    2,3,9
 
     Cost:
     Initial                          4.185660e+06
     Final                            1.803390e+04
     Change                           4.167626e+06
 
-    Minimizer iterations                        6
-    Successful steps                            6
+    Minimizer iterations                        7
+    Successful steps                            7
     Unsuccessful steps                          0
 
     Time (in seconds):
-    Preprocessor                            0.261
+    Preprocessor                         0.043895
 
-      Residual evaluation                   0.082
-      Jacobian evaluation                   0.412
-      Linear solver                         0.442
-    Minimizer                               1.051
+      Residual only evaluation           0.029855 (7)
+      Jacobian & residual evaluation     0.120581 (7)
+      Linear solver                      0.153665 (7)
+    Minimizer                            0.339275
 
-    Postprocessor                           0.002
-    Total                                   1.357
+    Postprocessor                        0.000540
+    Total                                0.383710
 
-    Termination:                      CONVERGENCE (Function tolerance reached. |cost_change|/cost: 1.769766e-09 <= 1.000000e-06)
+    Termination:                      CONVERGENCE (Function tolerance reached. |cost_change|/cost: 1.769759e-09 <= 1.000000e-06)
+
 
 .. section-macos:
 
 macOS
 =====
 
-On macOS, you can either use `Homebrew
-<https://brew.sh/>`_ (recommended) or `MacPorts
-<https://www.macports.org/>`_ to install Ceres Solver.
+On macOS, you can either use `Homebrew <https://brew.sh/>`_
+(recommended) or `MacPorts <https://www.macports.org/>`_ to install
+Ceres Solver.
 
 If using `Homebrew <https://brew.sh/>`_, then
 
@@ -277,17 +281,17 @@
       brew install glog gflags
       # Eigen3
       brew install eigen
-      # SuiteSparse and CXSparse
+      # SuiteSparse
       brew install suite-sparse
 
 We are now ready to build, test, and install Ceres.
 
 .. code-block:: bash
 
-   tar zxf ceres-solver-2.0.0.tar.gz
+   tar zxf ceres-solver-2.2.0.tar.gz
    mkdir ceres-bin
    cd ceres-bin
-   cmake ../ceres-solver-2.0.0
+   cmake ../ceres-solver-2.2.0
    make -j3
    make test
    # Optionally install Ceres, it can also be exported using CMake which
@@ -295,53 +299,59 @@
    # documentation for the EXPORT_BUILD_DIR option for more information.
    make install
 
-Building with OpenMP on macOS
------------------------------
-
-Up to at least Xcode 12, OpenMP support was disabled in Apple's version of
-Clang.  However, you can install the latest version of the LLVM toolchain
-from Homebrew which does support OpenMP, and thus build Ceres with OpenMP
-support on macOS.  To do this, you must install llvm via Homebrew:
-
-.. code-block:: bash
-
-      # Install latest version of LLVM toolchain.
-      brew install llvm
-
-As the LLVM formula in Homebrew is keg-only, it will not be installed to
-``/usr/local`` to avoid conflicts with the standard Apple LLVM toolchain.
-To build Ceres with the Homebrew LLVM toolchain you should do the
-following:
-
-.. code-block:: bash
-
-   tar zxf ceres-solver-2.0.0.tar.gz
-   mkdir ceres-bin
-   cd ceres-bin
-   # Configure the local shell only (not persistent) to use the Homebrew LLVM
-   # toolchain in favour of the default Apple version.  This is taken
-   # verbatim from the instructions output by Homebrew when installing the
-   # llvm formula.
-   export LDFLAGS="-L/usr/local/opt/llvm/lib -Wl,-rpath,/usr/local/opt/llvm/lib"
-   export CPPFLAGS="-I/usr/local/opt/llvm/include"
-   export PATH="/usr/local/opt/llvm/bin:$PATH"
-   # Force CMake to use the Homebrew version of Clang and enable OpenMP.
-   cmake -DCMAKE_C_COMPILER=/usr/local/opt/llvm/bin/clang -DCMAKE_CXX_COMPILER=/usr/local/opt/llvm/bin/clang++ -DCERES_THREADING_MODEL=OPENMP ../ceres-solver-2.0.0
-   make -j3
-   make test
-   # Optionally install Ceres.  It can also be exported using CMake which
-   # allows Ceres to be used without requiring installation.  See the
-   # documentation for the EXPORT_BUILD_DIR option for more information.
-   make install
-
-Like the Linux build, you should now be able to run
-``bin/simple_bundle_adjuster``.
-
 .. _section-windows:
 
 Windows
 =======
 
+Using a Library Manager
+-----------------------
+
+`vcpkg <https://github.com/microsoft/vcpkg>`_ is a library manager for Microsoft
+Windows that can be used to install Ceres Solver and all its dependencies.
+
+#. Install the library manager into a top-level directory ``vcpkg/`` on Windows
+   following the `guide
+   <https://github.com/microsoft/vcpkg#quick-start-windows>`_, e.g., using
+   Visual Studio 2022 community edition, or simply run
+
+    .. code:: bat
+
+        git clone https://github.com/Microsoft/vcpkg.git
+        cd vcpkg
+        .\bootstrap-vcpkg.bat
+        .\vcpkg integrate install
+
+#. Use vcpkg to install and build Ceres and all its dependencies, e.g., for 64
+   bit Windows
+
+   .. code:: bat
+
+      vcpkg\vcpkg.exe install ceres:x64-windows
+
+   Or with optional components, e.g., SuiteSparse, using
+
+   .. code:: bat
+
+      vcpkg\vcpkg.exe install ceres[suitesparse]:x64-windows
+
+#. Integrate vcpkg packages with Visual Studio to allow it to automatically
+   find all the libraries installed by vcpkg.
+
+   .. code:: bat
+
+      vcpkg\vcpkg.exe integrate install
+
+#. To use Ceres in a CMake project, follow our :ref:`instructions
+   <section-using-ceres>`.
+
+
+Building from Source
+--------------------
+
+Ceres Solver can also be built from source. For this purpose, we support Visual
+Studio 2019 and newer.
+
 .. NOTE::
 
   If you find the following CMake difficult to set up, then you may
@@ -349,36 +359,11 @@
   <https://github.com/tbennun/ceres-windows>`_ for Ceres Solver by Tal
   Ben-Nun.
 
-On Windows, we support building with Visual Studio 2015.2 of newer. Note
-that the Windows port is less featureful and less tested than the
-Linux or macOS versions due to the lack of an officially supported
-way of building SuiteSparse and CXSparse.  There are however a number
-of unofficial ways of building these libraries. Building on Windows
-also a bit more involved since there is no automated way to install
-dependencies.
+#. Create a top-level directory for dependencies, build, and sources somewhere,
+   e.g., ``ceres/``
 
-.. NOTE:: Using ``google-glog`` & ``miniglog`` with windows.h.
-
- The windows.h header if used with GDI (Graphics Device Interface)
- defines ``ERROR``, which conflicts with the definition of ``ERROR``
- as a LogSeverity level in ``google-glog`` and ``miniglog``.  There
- are at least two possible fixes to this problem:
-
- #. Use ``google-glog`` and define ``GLOG_NO_ABBREVIATED_SEVERITIES``
-    when building Ceres and your own project, as documented `here
-    <http://google-glog.googlecode.com/svn/trunk/doc/glog.html>`__.
-    Note that this fix will not work for ``miniglog``, but use of
-    ``miniglog`` is strongly discouraged on any platform for which
-    ``google-glog`` is available (which includes Windows).
- #. If you do not require GDI, then define ``NOGDI`` **before**
-    including windows.h.  This solution should work for both
-    ``google-glog`` and ``miniglog`` and is documented for
-    ``google-glog`` `here
-    <https://code.google.com/p/google-glog/issues/detail?id=33>`__.
-
-#. Make a toplevel directory for deps & build & src somewhere: ``ceres/``
 #. Get dependencies; unpack them as subdirectories in ``ceres/``
-   (``ceres/eigen``, ``ceres/glog``, etc)
+   (``ceres/eigen``, ``ceres/glog``, etc.)
 
    #. ``Eigen`` 3.3 . Configure and optionally install Eigen. It should be
       exported into the CMake package registry by default as part of the
@@ -394,45 +379,55 @@
       project.  If you wish to use ``SuiteSparse``, follow their
       instructions for obtaining and building it.
 
-   #. (Experimental) ``CXSparse`` Previously CXSparse was not
-      available on Windows, there are now several ports that enable it
-      to be, including: `[1] <https://github.com/PetterS/CXSparse>`_
-      and `[2] <https://github.com/TheFrenchLeaf/CXSparse>`_.  If you
-      wish to use ``CXSparse``, follow their instructions for
-      obtaining and building it.
+      Alternatively, Ceres Solver supports ``SuiteSparse`` binary
+      packages available for Visual Studio 2019 and 2022 provided by
+      the `CMake support for SuiteSparse
+      <https://github.com/sergiud/SuiteSparse>`_ project that also
+      include `reference LAPACK <http://www.netlib.org/blas>`_ (and
+      BLAS). The binary packages are used by Ceres Solver for
+      continuous testing on Github.
 
 #. Unpack the Ceres tarball into ``ceres``. For the tarball, you
    should get a directory inside ``ceres`` similar to
-   ``ceres-solver-2.0.0``. Alternately, checkout Ceres via ``git`` to
+   ``ceres-solver-2.2.0``. Alternately, checkout Ceres via ``git`` to
    get ``ceres-solver.git`` inside ``ceres``.
 
 #. Install ``CMake``,
 
-#. Make a dir ``ceres/ceres-bin`` (for an out-of-tree build)
+#. Create a directory ``ceres/ceres-bin`` (for an out-of-tree build)
+
+   #. If you use the above binary ``SuiteSparse`` package, make sure CMake can
+      find it, e.g., by assigning the path of the directory that contains the
+      unzipped contents to the ``CMAKE_PREFIX_PATH`` environment variable. In a
+      Windows command prompt this can be achieved as follows:
+
+      .. code:: bat
+
+        export CMAKE_PREFIX_PATH=C:/Downloads/SuiteSparse-5.11.0-cmake.1-vc16-Win64-Release-shared-gpl
 
 #. Run ``CMake``; select the ``ceres-solver-X.Y.Z`` or
    ``ceres-solver.git`` directory for the CMake file. Then select the
-   ``ceres-bin`` for the build dir.
+   ``ceres-bin`` for the build directory.
 
-#. Try running ``Configure``. It won't work. It'll show a bunch of options.
-   You'll need to set:
+#. Try running ``Configure`` which can fail at first because some dependencies
+   cannot be automatically located. In this case, you must set the following
+   CMake variables to the appropriate directories where you unpacked/built them:
 
    #. ``Eigen3_DIR`` (Set to directory containing ``Eigen3Config.cmake``)
    #. ``GLOG_INCLUDE_DIR_HINTS``
    #. ``GLOG_LIBRARY_DIR_HINTS``
    #. (Optional) ``gflags_DIR`` (Set to directory containing ``gflags-config.cmake``)
-   #. (Optional) ``SUITESPARSE_INCLUDE_DIR_HINTS``
-   #. (Optional) ``SUITESPARSE_LIBRARY_DIR_HINTS``
-   #. (Optional) ``CXSPARSE_INCLUDE_DIR_HINTS``
-   #. (Optional) ``CXSPARSE_LIBRARY_DIR_HINTS``
+   #. (SuiteSparse binary package) ``BLAS_blas_LIBRARY`` and
+      ``LAPACK_lapack_LIBRARY`` CMake variables must be `explicitly set` to
+      ``<path>/lib/blas.lib`` and ``<path>/lib/lapack.lib``, respectively, both
+      located in the unzipped package directory ``<path>``.
 
-   to the appropriate directories where you unpacked/built them. If
-   any of the variables are not visible in the ``CMake`` GUI, create a
-   new entry for them.  We recommend using the
-   ``<NAME>_(INCLUDE/LIBRARY)_DIR_HINTS`` variables rather than
-   setting the ``<NAME>_INCLUDE_DIR`` & ``<NAME>_LIBRARY`` variables
-   directly to keep all of the validity checking, and to avoid having
-   to specify the library files manually.
+   If any of the variables are not visible in the ``CMake`` GUI, create a new
+   entry for them.  We recommend using the
+   ``<NAME>_(INCLUDE/LIBRARY)_DIR_HINTS`` variables rather than setting the
+   ``<NAME>_INCLUDE_DIR`` & ``<NAME>_LIBRARY`` variables directly to keep all of
+   the validity checking, and to avoid having to specify the library files
+   manually.
 
 #. You may have to tweak some more settings to generate a MSVC
    project.  After each adjustment, try pressing Configure & Generate
@@ -447,17 +442,15 @@
 Like the Linux build, you should now be able to run
 ``bin/simple_bundle_adjuster``.
 
-Notes:
+.. note::
 
-#. The default build is Debug; consider switching it to release mode.
-#. Currently ``system_test`` is not working properly.
-#. CMake puts the resulting test binaries in ``ceres-bin/examples/Debug``
-   by default.
-#. The solvers supported on Windows are ``DENSE_QR``, ``DENSE_SCHUR``,
-   ``CGNR``, and ``ITERATIVE_SCHUR``.
-#. We're looking for someone to work with upstream ``SuiteSparse`` to
-   port their build system to something sane like ``CMake``, and get a
-   fully supported Windows port.
+    #. The default build is ``Debug``; consider switching it to ``Release`` for
+       optimal performance.
+    #. CMake puts the resulting test binaries in ``ceres-bin/examples/Debug`` by
+       default.
+    #. Without a sparse linear algebra library, only a subset of
+       solvers is usable, namely: ``DENSE_QR``, ``DENSE_SCHUR``,
+       ``CGNR``, and ``ITERATIVE_SCHUR``.
 
 
 .. _section-android:
@@ -556,9 +549,7 @@
 The default CMake configuration builds a bare bones version of Ceres
 Solver that only depends on Eigen (``MINIGLOG`` is compiled into Ceres
 if it is used), this should be sufficient for solving small to
-moderate sized problems (No ``SPARSE_SCHUR``,
-``SPARSE_NORMAL_CHOLESKY`` linear solvers and no ``CLUSTER_JACOBI``
-and ``CLUSTER_TRIDIAGONAL`` preconditioners).
+moderate sized problems.
 
 If you decide to use ``LAPACK`` and ``BLAS``, then you also need to
 add ``Accelerate.framework`` to your Xcode project's linking
@@ -648,22 +639,14 @@
       terms.  Ceres requires some components that are only licensed under
       GPL/Commercial terms.
 
-#. ``CXSPARSE [Default: ON]``: By default, Ceres will link to
-   ``CXSparse`` if all its dependencies are present. Turn this ``OFF``
-   to build Ceres without ``CXSparse``.
-
-   .. NOTE::
-
-      CXSparse is licensed under the LGPL.
-
 #. ``ACCELERATESPARSE [Default: ON]``: By default, Ceres will link to
    Apple's Accelerate framework directly if a version of it is detected
    which supports solving sparse linear systems.  Note that on Apple OSs
    Accelerate usually also provides the BLAS/LAPACK implementations and
    so would be linked against irrespective of the value of ``ACCELERATESPARSE``.
 
-#. ``EIGENSPARSE [Default: ON]``: By default, Ceres will not use
-   Eigen's sparse Cholesky factorization.
+#. ``EIGENSPARSE [Default: ON]``: By default, Ceres will use Eigen's
+   sparse Cholesky factorization.
 
 #. ``GFLAGS [Default: ON]``: Turn this ``OFF`` to build Ceres without
    ``gflags``. This will also prevent some of the example code from
@@ -680,11 +663,6 @@
    gains in the ``SPARSE_SCHUR`` solver, you can disable some of the
    template specializations by turning this ``OFF``.
 
-#. ``CERES_THREADING_MODEL [Default: CXX_THREADS > OPENMP > NO_THREADS]``:
-   Multi-threading backend Ceres should be compiled with.  This will
-   automatically be set to only accept the available subset of threading
-   options in the CMake GUI.
-
 #. ``BUILD_SHARED_LIBS [Default: OFF]``: By default Ceres is built as
    a static library, turn this ``ON`` to instead build Ceres as a
    shared library.
@@ -701,8 +679,8 @@
 
 #. ``BUILD_DOCUMENTATION [Default: OFF]``: Use this to enable building
    the documentation, requires `Sphinx <http://sphinx-doc.org/>`_ and
-   the `sphinx-better-theme
-   <https://pypi.python.org/pypi/sphinx-better-theme>`_ package
+   the `sphinx-rtd-theme
+   <https://pypi.org/project/sphinx-rtd-theme/>`_ package
    available from the Python package index. In addition, ``make
    ceres_docs`` can be used to build only the documentation.
 
@@ -865,25 +843,18 @@
 
 #. ``SuiteSparse``: Ceres built with SuiteSparse (``SUITESPARSE=ON``).
 
-#. ``CXSparse``: Ceres built with CXSparse (``CXSPARSE=ON``).
-
 #. ``AccelerateSparse``: Ceres built with Apple's Accelerate sparse solvers (``ACCELERATESPARSE=ON``).
 
 #. ``EigenSparse``: Ceres built with Eigen's sparse Cholesky factorization
    (``EIGENSPARSE=ON``).
 
-#. ``SparseLinearAlgebraLibrary``: Ceres built with *at least one* sparse linear
-   algebra library.  This is equivalent to ``SuiteSparse`` **OR** ``CXSparse``
-   **OR** ``AccelerateSparse``  **OR** ``EigenSparse``.
+#. ``SparseLinearAlgebraLibrary``: Ceres built with *at least one*
+   sparse linear algebra library.  This is equivalent to
+   ``SuiteSparse`` **OR** ``AccelerateSparse`` **OR** ``EigenSparse``.
 
 #. ``SchurSpecializations``: Ceres built with Schur specializations
    (``SCHUR_SPECIALIZATIONS=ON``).
 
-#. ``OpenMP``: Ceres built with OpenMP (``CERES_THREADING_MODEL=OPENMP``).
-
-#. ``Multithreading``: Ceres built with *a* multithreading library.
-   This is equivalent to (``CERES_THREAD != NO_THREADS``).
-
 To specify one/multiple Ceres components use the ``COMPONENTS`` argument to
 `find_package()
 <http://www.cmake.org/cmake/help/v3.5/command/find_package.html>`_ like so:
diff --git a/third_party/ceres/docs/source/interfacing_with_autodiff.rst b/third_party/ceres/docs/source/interfacing_with_autodiff.rst
index 02f58b2..fa05835 100644
--- a/third_party/ceres/docs/source/interfacing_with_autodiff.rst
+++ b/third_party/ceres/docs/source/interfacing_with_autodiff.rst
@@ -37,7 +37,7 @@
    template <typename T> T TemplatedComputeDistortion(const T r2) {
      const double k1 = 0.0082;
      const double k2 = 0.000023;
-     return 1.0 + k1 * y2 + k2 * r2 * r2;
+     return 1.0 + k1 * r2 + k2 * r2 * r2;
    }
 
    struct Affine2DWithDistortion {
@@ -118,12 +118,13 @@
        y[0] = y_in[0];
        y[1] = y_in[1];
 
-       compute_distortion.reset(new ceres::CostFunctionToFunctor<1, 1>(
-            new ceres::NumericDiffCostFunction<ComputeDistortionValueFunctor,
-                                               ceres::CENTRAL,
-                                               1,
-                                               1>(
-               new ComputeDistortionValueFunctor)));
+       compute_distortion = std::make_unique<ceres::CostFunctionToFunctor<1, 1>>(
+         std::make_unique<ceres::NumericDiffCostFunction<
+               ComputeDistortionValueFunctor
+             , ceres::CENTRAL, 1, 1
+           >
+         >()
+       );
      }
 
      template <typename T>
@@ -140,7 +141,7 @@
 
      double x[2];
      double y[2];
-     std::unique_ptr<ceres::CostFunctionToFunctor<1, 1> > compute_distortion;
+     std::unique_ptr<ceres::CostFunctionToFunctor<1, 1>> compute_distortion;
    };
 
 
@@ -148,7 +149,7 @@
 ------------------------------------------------
 
 Now suppose we are given a function :code:`ComputeDistortionValue`
-thatis able to compute its value and optionally its Jacobian on demand
+that is able to compute its value and optionally its Jacobian on demand
 and has the following signature:
 
 .. code-block:: c++
diff --git a/third_party/ceres/docs/source/inverse_and_implicit_function_theorems.rst b/third_party/ceres/docs/source/inverse_and_implicit_function_theorems.rst
new file mode 100644
index 0000000..7d8f7fa
--- /dev/null
+++ b/third_party/ceres/docs/source/inverse_and_implicit_function_theorems.rst
@@ -0,0 +1,214 @@
+.. default-domain:: cpp
+
+.. cpp:namespace:: ceres
+
+.. _chapter-inverse_function_theorem:
+
+==========================================
+Using Inverse & Implicit Function Theorems
+==========================================
+
+Until now we have considered methods for computing derivatives that
+work directly on the function being differentiated. However, this is
+not always possible. For example, if the function can only be computed
+via an iterative algorithm, or there is no explicit definition of the
+function available.  In this section we will see how we can use two
+basic results from calculus to get around these difficulties.
+
+
+Inverse Function Theorem
+========================
+
+Suppose we wish to evaluate the derivative of a function :math:`f(x)`,
+but evaluating :math:`f(x)` is not easy. Say it involves running an
+iterative algorithm. You could try automatically differentiating the
+iterative algorithm, but even if that is possible, it can become quite
+expensive.
+
+In some cases we get lucky, and computing the inverse of :math:`f(x)`
+is an easy operation. In these cases, we can use the `Inverse Function
+Theorem <http://en.wikipedia.org/wiki/Inverse_function_theorem>`_ to
+compute the derivative exactly. Here is the key idea:
+
+Assuming that :math:`y=f(x)` is continuously differentiable in a
+neighborhood of a point :math:`x` and :math:`Df(x)` is the invertible
+Jacobian of :math:`f` at :math:`x`, then by applying the chain rule to
+the identity :math:`f^{-1}(f(x)) = x`, we have
+:math:`Df^{-1}(f(x))Df(x) = I`, or :math:`Df^{-1}(y) = (Df(x))^{-1}`,
+i.e., the Jacobian of :math:`f^{-1}` is the inverse of the Jacobian of
+:math:`f`, or :math:`Df(x) = (Df^{-1}(y))^{-1}`.
+
+For example, let :math:`f(x) = e^x`. Now of course we know that
+:math:`Df(x) = e^x`, but let's try and compute it via the Inverse
+Function Theorem. For :math:`x > 0`, we have :math:`f^{-1}(y) = \log
+y`, so :math:`Df^{-1}(y) = \frac{1}{y}`, so :math:`Df(x) =
+(Df^{-1}(y))^{-1} = y = e^x`.
+
+You maybe wondering why the above is true. A smoothly differentiable
+function in a small neighborhood is well approximated by a linear
+function. Indeed this is a good way to think about the Jacobian, it is
+the matrix that best approximates the function linearly. Once you do
+that, it is straightforward to see that *locally* :math:`f^{-1}(y)` is
+best approximated linearly by the inverse of the Jacobian of
+:math:`f(x)`.
+
+Let us now consider a more practical example.
+
+Geodetic Coordinate System Conversion
+-------------------------------------
+
+When working with data related to the Earth, one can use two different
+coordinate systems. The familiar (latitude, longitude, height)
+Latitude-Longitude-Altitude coordinate system or the `ECEF
+<http://en.wikipedia.org/wiki/ECEF>`_ coordinate systems. The former
+is familiar but is not terribly convenient analytically. The latter is
+a Cartesian system but not particularly intuitive. So systems that
+process earth related data have to go back and forth between these
+coordinate systems.
+
+The conversion between the LLA and the ECEF coordinate system requires
+a model of the Earth, the most commonly used one being `WGS84
+<https://en.wikipedia.org/wiki/World_Geodetic_System#1984_version>`_.
+
+Going from the spherical :math:`(\phi,\lambda,h)` to the ECEF
+:math:`(x,y,z)` coordinates is easy.
+
+.. math::
+
+   \chi &= \sqrt{1 - e^2 \sin^2 \phi}
+
+   X &= \left( \frac{a}{\chi} + h \right) \cos \phi \cos \lambda
+
+   Y &= \left( \frac{a}{\chi} + h \right) \cos \phi \sin \lambda
+
+   Z &= \left(\frac{a(1-e^2)}{\chi}  +h \right) \sin \phi
+
+Here :math:`a` and :math:`e^2` are constants defined by `WGS84
+<https://en.wikipedia.org/wiki/World_Geodetic_System#1984_version>`_.
+
+Going from ECEF to LLA coordinates requires an iterative algorithm. So
+to compute the derivative of the this transformation we invoke the
+Inverse Function Theorem as follows:
+
+.. code-block:: c++
+
+   Eigen::Vector3d ecef; // Fill some values
+   // Iterative computation.
+   Eigen::Vector3d lla = ECEFToLLA(ecef);
+   // Analytic derivatives
+   Eigen::Matrix3d lla_to_ecef_jacobian = LLAToECEFJacobian(lla);
+   bool invertible;
+   Eigen::Matrix3d ecef_to_lla_jacobian;
+   lla_to_ecef_jacobian.computeInverseWithCheck(ecef_to_lla_jacobian, invertible);
+
+
+Implicit Function Theorem
+=========================
+
+Consider now the problem where we have two variables :math:`x \in
+\mathbb{R}^m` and :math:`y \in \mathbb{R}^n` and a function
+:math:`F:\mathbb{R}^m \times \mathbb{R}^n \rightarrow \mathbb{R}^n`
+such that :math:`F(x,y) = 0` and we wish to calculate the Jacobian of
+:math:`y` with respect to `x`. How do we do this?
+
+If for a given value of :math:`(x,y)`, the partial Jacobian
+:math:`D_2F(x,y)` is full rank, then the `Implicit Function Theorem
+<https://en.wikipedia.org/wiki/Implicit_function_theorem>`_ tells us
+that there exists a neighborhood of :math:`x` and a function :math:`G`
+such :math:`y = G(x)` in this neighborhood. Differentiating
+:math:`F(x,G(x)) = 0` gives us
+
+.. math::
+
+   D_1F(x,y) + D_2F(x,y)DG(x) &= 0
+
+                        DG(x) &= -(D_2F(x,y))^{-1} D_1 F(x,y)
+
+                        D y(x) &= -(D_2F(x,y))^{-1} D_1 F(x,y)
+
+This means that we can compute the derivative of :math:`y` with
+respect to :math:`x` by multiplying the Jacobian of :math:`F` w.r.t
+:math:`x` by the inverse of the Jacobian of :math:`F` w.r.t :math:`y`.
+
+Let's consider two examples.
+
+Roots of a Polynomial
+---------------------
+
+The first example we consider is a classic. Let :math:`p(x) = a_0 +
+a_1 x + \dots + a_n x^n` be a degree :math:`n` polynomial, and we wish
+to compute the derivative of its roots with respect to its
+coefficients. There is no closed form formula for computing the roots
+of a general degree :math:`n` polynomial. `Galois
+<https://en.wikipedia.org/wiki/%C3%89variste_Galois>`_ and `Abel
+<https://en.wikipedia.org/wiki/Niels_Henrik_Abel>`_ proved that. There
+are numerical algorithms like computing the eigenvalues of the
+`Companion Matrix
+<https://nhigham.com/2021/03/23/what-is-a-companion-matrix/>`_, but
+differentiating an eigenvalue solver does not seem like fun. But the
+Implicit Function Theorem offers us a simple path.
+
+If :math:`x` is a root of :math:`p(x)`, then :math:`F(\mathbf{a}, x) =
+a_0 + a_1 x + \dots + a_n x^n = 0`. So,
+
+.. math::
+
+   D_1 F(\mathbf{a}, x) &= [1, x, x^2, \dots, x^n]
+
+   D_2 F(\mathbf{a}, x) &= \sum_{k=1}^n k a_k x^{k-1} = Dp(x)
+
+        Dx(a) &= \frac{-1}{Dp(x)} [1, x, x^2, \dots, x^n]
+
+Differentiating the Solution to an Optimization Problem
+-------------------------------------------------------
+
+Sometimes we are required to solve optimization problems inside
+optimization problems, and this requires computing the derivative of
+the optimal solution (or a fixed point) of an optimization problem
+w.r.t its parameters.
+
+Let :math:`\theta \in \mathbb{R}^m` be a vector, :math:`A(\theta) \in
+\mathbb{R}^{k\times n}` be a matrix whose entries are a function of
+:math:`\theta` with :math:`k \ge n` and let :math:`b \in \mathbb{R}^k`
+be a constant vector, then consider the linear least squares problem:
+
+.. math::
+
+   x^* = \arg \min_x \|A(\theta) x - b\|_2^2
+
+How do we compute :math:`D_\theta x^*(\theta)`?
+
+One approach would be to observe that :math:`x^*(\theta) =
+(A^\top(\theta)A(\theta))^{-1}A^\top(\theta)b` and then differentiate
+this w.r.t :math:`\theta`. But this would require differentiating
+through the inverse of the matrix
+:math:`(A^\top(\theta)A(\theta))^{-1}`. Not exactly easy. Let's use
+the Implicit Function Theorem instead.
+
+The first step is to observe that :math:`x^*` satisfies the so called
+*normal equations*.
+
+.. math::
+
+   A^\top(\theta)A(\theta)x^* - A^\top(\theta)b = 0
+
+We will compute :math:`D_\theta x^*` column-wise, treating
+:math:`A(\theta)` as a function of one coordinate (:math:`\theta_i`)
+of :math:`\theta` at a time. So using the normal equations, let's
+define :math:`F(\theta_i, x^*) = A^\top(\theta_i)A(\theta_i)x^* -
+A^\top(\theta_i)b = 0`. Using which can now compute:
+
+.. math::
+
+   D_1F(\theta_i, x^*) &= D_{\theta_i}A^\top A + A^\top
+   D_{\theta_i}Ax^* - D_{\theta_i} A^\top b = g_i
+
+   D_2F(\theta_i, x^*) &= A^\top A
+
+   Dx^*(\theta_i) & = -(A^\top A)^{-1} g_i
+
+   Dx^*(\theta) & = -(A^\top A )^{-1} \left[g_1, \dots, g_m\right]
+
+Observe that we only need to compute the inverse of :math:`A^\top A`,
+to compute :math:`D x^*(\theta)`, which we needed anyways to compute
+:math:`x^*`.
diff --git a/third_party/ceres/docs/source/license.rst b/third_party/ceres/docs/source/license.rst
index a3c55c9..ed85f6a 100644
--- a/third_party/ceres/docs/source/license.rst
+++ b/third_party/ceres/docs/source/license.rst
@@ -12,7 +12,7 @@
 
 Ceres Solver is licensed under the New BSD license, whose terms are as follows.
 
-Copyright 2016 Google Inc. All rights reserved.
+Copyright 2023 Google Inc. All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:
diff --git a/third_party/ceres/docs/source/loss.png b/third_party/ceres/docs/source/loss.png
index 9f98d00..5c9ac07 100644
--- a/third_party/ceres/docs/source/loss.png
+++ b/third_party/ceres/docs/source/loss.png
Binary files differ
diff --git a/third_party/ceres/docs/source/modeling_faqs.rst b/third_party/ceres/docs/source/modeling_faqs.rst
index a0c8f2f..0d23de4 100644
--- a/third_party/ceres/docs/source/modeling_faqs.rst
+++ b/third_party/ceres/docs/source/modeling_faqs.rst
@@ -37,7 +37,7 @@
    automatic and numeric differentiation. See
    :class:`CostFunctionToFunctor`.
 
-#. When using Quaternions,  consider using :class:`QuaternionParameterization`.
+#. When using Quaternions,  consider using :class:`QuaternionManifold`.
 
    `Quaternions <https://en.wikipedia.org/wiki/Quaternion>`_ are a
    four dimensional parameterization of the space of three dimensional
@@ -47,14 +47,14 @@
    associate a local parameterization with parameter blocks
    representing a Quaternion. Assuming that the order of entries in
    your parameter block is :math:`w,x,y,z`, you can use
-   :class:`QuaternionParameterization`.
+   :class:`QuaternionManifold`.
 
    .. NOTE::
 
      If you are using `Eigen's Quaternion
      <http://eigen.tuxfamily.org/dox/classEigen_1_1Quaternion.html>`_
      object, whose layout is :math:`x,y,z,w`, then you should use
-     :class:`EigenQuaternionParameterization`.
+     :class:`EigenQuaternionManifold`.
 
 
 #. How do I solve problems with general linear & non-linear
@@ -85,50 +85,4 @@
 
 #. How do I set one or more components of a parameter block constant?
 
-   Using :class:`SubsetParameterization`.
-
-#. Putting `Inverse Function Theorem
-   <http://en.wikipedia.org/wiki/Inverse_function_theorem>`_ to use.
-
-   Every now and then we have to deal with functions which cannot be
-   evaluated analytically. Computing the Jacobian in such cases is
-   tricky. A particularly interesting case is where the inverse of the
-   function is easy to compute analytically. An example of such a
-   function is the Coordinate transformation between the `ECEF
-   <http://en.wikipedia.org/wiki/ECEF>`_ and the `WGS84
-   <http://en.wikipedia.org/wiki/World_Geodetic_System>`_ where the
-   conversion from WGS84 to ECEF is analytic, but the conversion
-   back to WGS84 uses an iterative algorithm. So how do you compute the
-   derivative of the ECEF to WGS84 transformation?
-
-   One obvious approach would be to numerically
-   differentiate the conversion function. This is not a good idea. For
-   one, it will be slow, but it will also be numerically quite
-   bad.
-
-   Turns out you can use the `Inverse Function Theorem
-   <http://en.wikipedia.org/wiki/Inverse_function_theorem>`_ in this
-   case to compute the derivatives more or less analytically.
-
-   The key result here is. If :math:`x = f^{-1}(y)`, and :math:`Df(x)`
-   is the invertible Jacobian of :math:`f` at :math:`x`. Then the
-   Jacobian :math:`Df^{-1}(y) = [Df(x)]^{-1}`, i.e., the Jacobian of
-   the :math:`f^{-1}` is the inverse of the Jacobian of :math:`f`.
-
-   Algorithmically this means that given :math:`y`, compute :math:`x =
-   f^{-1}(y)` by whatever means you can. Evaluate the Jacobian of
-   :math:`f` at :math:`x`. If the Jacobian matrix is invertible, then
-   its inverse is the Jacobian of :math:`f^{-1}(y)` at  :math:`y`.
-
-   One can put this into practice with the following code fragment.
-
-   .. code-block:: c++
-
-      Eigen::Vector3d ecef; // Fill some values
-      // Iterative computation.
-      Eigen::Vector3d lla = ECEFToLLA(ecef);
-      // Analytic derivatives
-      Eigen::Matrix3d lla_to_ecef_jacobian = LLAToECEFJacobian(lla);
-      bool invertible;
-      Eigen::Matrix3d ecef_to_lla_jacobian;
-      lla_to_ecef_jacobian.computeInverseWithCheck(ecef_to_lla_jacobian, invertible);
+   Using :class:`SubsetManifold`.
diff --git a/third_party/ceres/docs/source/nnls_covariance.rst b/third_party/ceres/docs/source/nnls_covariance.rst
index 66afd44..f95d246 100644
--- a/third_party/ceres/docs/source/nnls_covariance.rst
+++ b/third_party/ceres/docs/source/nnls_covariance.rst
@@ -1,3 +1,4 @@
+.. highlight:: c++
 
 .. default-domain:: cpp
 
@@ -115,7 +116,7 @@
      four dimensional quaternion used to parameterize :math:`SO(3)`,
      which is a three dimensional manifold. In cases like this, the
      user should use an appropriate
-     :class:`LocalParameterization`. Not only will this lead to better
+     :class:`Manifold`. Not only will this lead to better
      numerical behaviour of the Solver, it will also expose the rank
      deficiency to the :class:`Covariance` object so that it can
      handle it correctly.
@@ -166,7 +167,7 @@
       moderately fast algorithm suitable for small to medium sized
       matrices. For best performance we recommend using
       ``SuiteSparseQR`` which is enabled by setting
-      :member:`Covaraince::Options::sparse_linear_algebra_library_type`
+      :member:`Covariance::Options::sparse_linear_algebra_library_type`
       to ``SUITE_SPARSE``.
 
       ``SPARSE_QR`` cannot compute the covariance if the
@@ -187,6 +188,23 @@
       well as rank deficient Jacobians.
 
 
+.. member:: double Covariance::Options::column_pivot_threshold
+
+   Default: :math:`-1`
+
+    During QR factorization, if a column with Euclidean norm less than
+    ``column_pivot_threshold`` is encountered it is treated as zero.
+
+    If ``column_pivot_threshold < 0``, then an automatic default value
+    of `20*(m+n)*eps*sqrt(max(diag(J’*J)))` is used.  Here `m` and `n`
+    are the number of rows and columns of the Jacobian (`J`)
+    respectively.
+
+    This is an advanced option meant for users who know enough about
+    their Jacobian matrices that they can determine a value better
+    than the default.
+
+
 .. member:: int Covariance::Options::min_reciprocal_condition_number
 
    Default: :math:`10^{-14}`
@@ -221,7 +239,7 @@
       .. math:: \frac{\sigma_{\text{min}}}{\sigma_{\text{max}}}  < \sqrt{\text{min_reciprocal_condition_number}}
 
       where :math:`\sigma_{\text{min}}` and
-      :math:`\sigma_{\text{max}}` are the minimum and maxiumum
+      :math:`\sigma_{\text{max}}` are the minimum and maximum
       singular values of :math:`J` respectively.
 
    2. ``SPARSE_QR``
@@ -285,7 +303,7 @@
    entire documentation for :class:`Covariance::Options` before using
    :class:`Covariance`.
 
-.. function:: bool Covariance::Compute(const vector<pair<const double*, const double*> >& covariance_blocks, Problem* problem)
+.. function:: bool Covariance::Compute(const std::vector<std::pair<const double*, const double*> >& covariance_blocks, Problem* problem)
 
    Compute a part of the covariance matrix.
 
@@ -361,7 +379,7 @@
  Covariance::Options options;
  Covariance covariance(options);
 
- vector<pair<const double*, const double*> > covariance_blocks;
+ std::vector<std::pair<const double*, const double*> > covariance_blocks;
  covariance_blocks.push_back(make_pair(x, x));
  covariance_blocks.push_back(make_pair(y, y));
  covariance_blocks.push_back(make_pair(x, y));
diff --git a/third_party/ceres/docs/source/nnls_modeling.rst b/third_party/ceres/docs/source/nnls_modeling.rst
index c0c3227..be87149 100644
--- a/third_party/ceres/docs/source/nnls_modeling.rst
+++ b/third_party/ceres/docs/source/nnls_modeling.rst
@@ -1,3 +1,5 @@
+.. highlight:: c++
+
 .. default-domain:: cpp
 
 .. cpp:namespace:: ceres
@@ -50,7 +52,7 @@
 
 As a special case, when :math:`\rho_i(x) = x`, i.e., the identity
 function, and :math:`l_j = -\infty` and :math:`u_j = \infty` we get
-the more familiar unconstrained `non-linear least squares problem
+the usual unconstrained `non-linear least squares problem
 <http://en.wikipedia.org/wiki/Non-linear_least_squares>`_.
 
 .. math:: :label: ceresproblemunconstrained
@@ -80,12 +82,12 @@
      public:
       virtual bool Evaluate(double const* const* parameters,
                             double* residuals,
-                            double** jacobians) = 0;
-      const vector<int32>& parameter_block_sizes();
+                            double** jacobians) const = 0;
+      const std::vector<int32>& parameter_block_sizes();
       int num_residuals() const;
 
      protected:
-      vector<int32>* mutable_parameter_block_sizes();
+      std::vector<int32>* mutable_parameter_block_sizes();
       void set_num_residuals(int num_residuals);
     };
 
@@ -98,7 +100,7 @@
 the corresponding accessors. This information will be verified by the
 :class:`Problem` when added with :func:`Problem::AddResidualBlock`.
 
-.. function:: bool CostFunction::Evaluate(double const* const* parameters, double* residuals, double** jacobians)
+.. function:: bool CostFunction::Evaluate(double const* const* parameters, double* residuals, double** jacobians) const
 
    Compute the residual vector and the Jacobian matrices.
 
@@ -179,12 +181,19 @@
      class AutoDiffCostFunction : public
      SizedCostFunction<kNumResiduals, Ns> {
       public:
-       AutoDiffCostFunction(CostFunctor* functor, ownership = TAKE_OWNERSHIP);
+       // Instantiate CostFunctor using the supplied arguments.
+       template<class ...Args>
+       explicit AutoDiffCostFunction(Args&& ...args);
+       explicit AutoDiffCostFunction(std::unique_ptr<CostFunctor> functor);
+       explicit AutoDiffCostFunction(CostFunctor* functor, ownership = TAKE_OWNERSHIP);
+
        // Ignore the template parameter kNumResiduals and use
        // num_residuals instead.
        AutoDiffCostFunction(CostFunctor* functor,
                             int num_residuals,
                             ownership = TAKE_OWNERSHIP);
+       AutoDiffCostFunction(std::unique_ptr<CostFunctor> functor,
+                            int num_residuals);
      };
 
    To get an auto differentiated cost function, you must define a
@@ -242,9 +251,9 @@
 
    .. code-block:: c++
 
-    CostFunction* cost_function
-        = new AutoDiffCostFunction<MyScalarCostFunctor, 1, 2, 2>(
-            new MyScalarCostFunctor(1.0));              ^  ^  ^
+    auto* cost_function
+        = new AutoDiffCostFunction<MyScalarCostFunctor, 1, 2, 2>(1.0);
+                                                        ^  ^  ^
                                                         |  |  |
                             Dimension of residual ------+  |  |
                             Dimension of x ----------------+  |
@@ -270,7 +279,7 @@
    .. code-block:: c++
 
     MyScalarCostFunctor functor(1.0)
-    CostFunction* cost_function
+    auto* cost_function
         = new AutoDiffCostFunction<MyScalarCostFunctor, 1, 2, 2>(
             &functor, DO_NOT_TAKE_OWNERSHIP);
 
@@ -279,9 +288,11 @@
 
    .. code-block:: c++
 
-     CostFunction* cost_function
-         = new AutoDiffCostFunction<MyScalarCostFunctor, DYNAMIC, 2, 2>(
-             new CostFunctorWithDynamicNumResiduals(1.0),   ^     ^  ^
+     auto functor = std::make_unique<CostFunctorWithDynamicNumResiduals>(1.0);
+     auto* cost_function
+         = new AutoDiffCostFunction<CostFunctorWithDynamicNumResiduals,
+                                                         DYNAMIC, 2, 2>(
+             std::move(functor),                            ^     ^  ^
              runtime_number_of_residuals); <----+           |     |  |
                                                 |           |     |  |
                                                 |           |     |  |
@@ -290,13 +301,13 @@
                Dimension of x ------------------------------------+  |
                Dimension of y ---------------------------------------+
 
-   **WARNING 1** A common beginner's error when first using
-   :class:`AutoDiffCostFunction` is to get the sizing wrong. In particular,
-   there is a tendency to set the template parameters to (dimension of
-   residual, number of parameters) instead of passing a dimension
-   parameter for *every parameter block*. In the example above, that
-   would be ``<MyScalarCostFunction, 1, 2>``, which is missing the 2
-   as the last template argument.
+   .. warning::
+       A common beginner's error when first using :class:`AutoDiffCostFunction`
+       is to get the sizing wrong. In particular, there is a tendency to set the
+       template parameters to (dimension of residual, number of parameters)
+       instead of passing a dimension parameter for *every parameter block*. In
+       the example above, that would be ``<MyScalarCostFunction, 1, 2>``, which
+       is missing the 2 as the last template argument.
 
 
 :class:`DynamicAutoDiffCostFunction`
@@ -334,9 +345,7 @@
 
      .. code-block:: c++
 
-       DynamicAutoDiffCostFunction<MyCostFunctor, 4>* cost_function =
-         new DynamicAutoDiffCostFunction<MyCostFunctor, 4>(
-           new MyCostFunctor());
+       auto* cost_function = new DynamicAutoDiffCostFunction<MyCostFunctor, 4>();
        cost_function->AddParameterBlock(5);
        cost_function->AddParameterBlock(10);
        cost_function->SetNumResiduals(21);
@@ -441,9 +450,9 @@
 
   .. code-block:: c++
 
-    CostFunction* cost_function
-        = new NumericDiffCostFunction<MyScalarCostFunctor, CENTRAL, 1, 2, 2>(
-            new MyScalarCostFunctor(1.0));                    ^     ^  ^  ^
+    auto* cost_function
+        = new NumericDiffCostFunction<MyScalarCostFunctor, CENTRAL, 1, 2, 2>(1.0)
+                                                              ^     ^  ^  ^
                                                               |     |  |  |
                                   Finite Differencing Scheme -+     |  |  |
                                   Dimension of residual ------------+  |  |
@@ -463,17 +472,18 @@
 
    .. code-block:: c++
 
-     CostFunction* cost_function
-         = new NumericDiffCostFunction<MyScalarCostFunctor, CENTRAL, DYNAMIC, 2, 2>(
-             new CostFunctorWithDynamicNumResiduals(1.0),               ^     ^  ^
-             TAKE_OWNERSHIP,                                            |     |  |
-             runtime_number_of_residuals); <----+                       |     |  |
-                                                |                       |     |  |
-                                                |                       |     |  |
-               Actual number of residuals ------+                       |     |  |
-               Indicate dynamic number of residuals --------------------+     |  |
-               Dimension of x ------------------------------------------------+  |
-               Dimension of y ---------------------------------------------------+
+     auto functor = std::make_unique<CostFunctorWithDynamicNumResiduals>(1.0);
+     auto* cost_function
+         = new NumericDiffCostFunction<CostFunctorWithDynamicNumResiduals,
+                                                CENTRAL, DYNAMIC, 2, 2>(
+             std::move(functor),                            ^     ^  ^
+             runtime_number_of_residuals); <----+           |     |  |
+                                                |           |     |  |
+                                                |           |     |  |
+               Actual number of residuals ------+           |     |  |
+               Indicate dynamic number of residuals --------+     |  |
+               Dimension of x ------------------------------------+  |
+               Dimension of y ---------------------------------------+
 
 
   There are three available numeric differentiation schemes in ceres-solver:
@@ -502,18 +512,18 @@
   results, either try forward difference to improve performance or
   Ridders' method to improve accuracy.
 
-  **WARNING** A common beginner's error when first using
-  :class:`NumericDiffCostFunction` is to get the sizing wrong. In
-  particular, there is a tendency to set the template parameters to
-  (dimension of residual, number of parameters) instead of passing a
-  dimension parameter for *every parameter*. In the example above,
-  that would be ``<MyScalarCostFunctor, 1, 2>``, which is missing the
-  last ``2`` argument. Please be careful when setting the size
-  parameters.
+  .. warning::
+      A common beginner's error when first using
+      :class:`NumericDiffCostFunction` is to get the sizing wrong. In
+      particular, there is a tendency to set the template parameters to
+      (dimension of residual, number of parameters) instead of passing a
+      dimension parameter for *every parameter*. In the example above, that
+      would be ``<MyScalarCostFunctor, 1, 2>``, which is missing the last ``2``
+      argument. Please be careful when setting the size parameters.
 
 
-Numeric Differentiation & LocalParameterization
------------------------------------------------
+Numeric Differentiation & Manifolds
+-----------------------------------
 
    If your cost function depends on a parameter block that must lie on
    a manifold and the functor cannot be evaluated for values of that
@@ -522,11 +532,10 @@
 
    This is because numeric differentiation in Ceres is performed by
    perturbing the individual coordinates of the parameter blocks that
-   a cost functor depends on. In doing so, we assume that the
-   parameter blocks live in an Euclidean space and ignore the
-   structure of manifold that they live As a result some of the
-   perturbations may not lie on the manifold corresponding to the
-   parameter block.
+   a cost functor depends on. This perturbation assumes that the
+   parameter block lives on a Euclidean Manifold rather than the
+   actual manifold associated with the parameter block. As a result
+   some of the perturbed points may not lie on the manifold anymore.
 
    For example consider a four dimensional parameter block that is
    interpreted as a unit Quaternion. Perturbing the coordinates of
@@ -534,7 +543,7 @@
    parameter block.
 
    Fixing this problem requires that :class:`NumericDiffCostFunction`
-   be aware of the :class:`LocalParameterization` associated with each
+   be aware of the :class:`Manifold` associated with each
    parameter block and only generate perturbations in the local
    tangent space of each parameter block.
 
@@ -568,9 +577,8 @@
 
    .. code-block:: c++
 
-     CostFunction* cost_function
-         = new NumericDiffCostFunction<MyCostFunction, CENTRAL, 1, 4, 8>(
-             new MyCostFunction(...), TAKE_OWNERSHIP);
+     auto* cost_function
+         = new NumericDiffCostFunction<MyCostFunction, CENTRAL, 1, 4, 8>(...);
 
    where ``MyCostFunction`` has 1 residual and 2 parameter blocks with
    sizes 4 and 8 respectively. Look at the tests for a more detailed
@@ -611,8 +619,7 @@
 
      .. code-block:: c++
 
-       DynamicNumericDiffCostFunction<MyCostFunctor>* cost_function =
-         new DynamicNumericDiffCostFunction<MyCostFunctor>(new MyCostFunctor);
+       auto cost_function = std::make_unique<DynamicNumericDiffCostFunction<MyCostFunctor>>();
        cost_function->AddParameterBlock(5);
        cost_function->AddParameterBlock(10);
        cost_function->SetNumResiduals(21);
@@ -620,9 +627,9 @@
    As a rule of thumb, try using :class:`NumericDiffCostFunction` before
    you use :class:`DynamicNumericDiffCostFunction`.
 
-   **WARNING** The same caution about mixing local parameterizations
-   with numeric differentiation applies as is the case with
-   :class:`NumericDiffCostFunction`.
+   .. warning::
+       The same caution about mixing manifolds with numeric differentiation
+       applies as is the case with :class:`NumericDiffCostFunction`.
 
 :class:`CostFunctionToFunctor`
 ==============================
@@ -671,8 +678,8 @@
    .. code-block:: c++
 
     struct CameraProjection {
-      CameraProjection(double* observation)
-      : intrinsic_projection_(new IntrinsicProjection(observation)) {
+      explicit CameraProjection(double* observation)
+      : intrinsic_projection_(std::make_unique<IntrinsicProjection>(observation)) {
       }
 
       template <typename T>
@@ -690,7 +697,7 @@
       }
 
      private:
-      CostFunctionToFunctor<2,5,3> intrinsic_projection_;
+      CostFunctionToFunctor<2, 5, 3> intrinsic_projection_;
     };
 
    Note that :class:`CostFunctionToFunctor` takes ownership of the
@@ -732,10 +739,9 @@
   .. code-block:: c++
 
    struct CameraProjection {
-     CameraProjection(double* observation)
+     explicit CameraProjection(double* observation)
         : intrinsic_projection_(
-              new NumericDiffCostFunction<IntrinsicProjection, CENTRAL, 2, 5, 3>(
-                  new IntrinsicProjection(observation))) {}
+              std::make_unique<NumericDiffCostFunction<IntrinsicProjection, CENTRAL, 2, 5, 3>>()) {}
 
      template <typename T>
      bool operator()(const T* rotation,
@@ -793,8 +799,8 @@
    .. code-block:: c++
 
     struct CameraProjection {
-      CameraProjection(double* observation)
-          : intrinsic_projection_(new IntrinsicProjection(observation)) {
+      explicit CameraProjection(double* observation)
+          : intrinsic_projection_(std::make_unique<IntrinsicProjection>(observation)) {
       }
 
       template <typename T>
@@ -841,7 +847,7 @@
        //  my_cost_function produces N residuals
        CostFunction* my_cost_function = ...
        CHECK_EQ(N, my_cost_function->num_residuals());
-       vector<CostFunction*> conditioners;
+       std::vector<CostFunction*> conditioners;
 
        //  Make N 1x1 cost functions (1 parameter, 1 residual)
        CostFunction* f_1 = ...
@@ -864,38 +870,39 @@
 
 
 :class:`GradientChecker`
-================================
+========================
 
 .. class:: GradientChecker
 
-    This class compares the Jacobians returned by a cost function against
-    derivatives estimated using finite differencing. It is meant as a tool for
-    unit testing, giving you more fine-grained control than the check_gradients
-    option in the solver options.
+    This class compares the Jacobians returned by a cost function
+    against derivatives estimated using finite differencing. It is
+    meant as a tool for unit testing, giving you more fine-grained
+    control than the check_gradients option in the solver options.
 
     The condition enforced is that
 
     .. math:: \forall{i,j}: \frac{J_{ij} - J'_{ij}}{max_{ij}(J_{ij} - J'_{ij})} < r
 
-    where :math:`J_{ij}` is the jacobian as computed by the supplied cost
-    function (by the user) multiplied by the local parameterization Jacobian,
+    where :math:`J_{ij}` is the jacobian as computed by the supplied
+    cost function multiplied by the `Manifold::PlusJacobian`,
     :math:`J'_{ij}` is the jacobian as computed by finite differences,
-    multiplied by the local parameterization Jacobian as well, and :math:`r`
+    multiplied by the `Manifold::PlusJacobian` as well, and :math:`r`
     is the relative precision.
 
    Usage:
 
    .. code-block:: c++
 
-       //  my_cost_function takes two parameter blocks. The first has a local
-       //  parameterization associated with it.
+       // my_cost_function takes two parameter blocks. The first has a
+       // manifold associated with it.
+
        CostFunction* my_cost_function = ...
-       LocalParameterization* my_parameterization = ...
+       Manifold* my_manifold = ...
        NumericDiffOptions numeric_diff_options;
 
-       std::vector<LocalParameterization*> local_parameterizations;
-       local_parameterizations.push_back(my_parameterization);
-       local_parameterizations.push_back(nullptr);
+       std::vector<Manifold*> manifolds;
+       manifolds.push_back(my_manifold);
+       manifolds.push_back(nullptr);
 
        std::vector parameter1;
        std::vector parameter2;
@@ -906,7 +913,8 @@
        parameter_blocks.push_back(parameter2.data());
 
        GradientChecker gradient_checker(my_cost_function,
-           local_parameterizations, numeric_diff_options);
+                                        manifolds,
+                                        numeric_diff_options);
        GradientCheckResults results;
        if (!gradient_checker.Probe(parameter_blocks.data(), 1e-9, &results) {
          LOG(ERROR) << "An error has occurred:\n" << results.error_log;
@@ -1065,6 +1073,10 @@
 
    .. math:: \rho(s,a,b) = b \log(1 + e^{(s - a) / b}) - b \log(1 + e^{-a / b})
 
+.. class:: TukeyLoss
+
+   .. math:: \rho(s) = \begin{cases} \frac{1}{3} (1 - (1 - s)^3) & s \le 1\\ \frac{1}{3} & s > 1 \end{cases}
+
 .. class:: ComposedLoss
 
    Given two loss functions ``f`` and ``g``, implements the loss
@@ -1115,9 +1127,8 @@
 
      // Add parameter blocks
 
-     CostFunction* cost_function =
-         new AutoDiffCostFunction < UW_Camera_Mapper, 2, 9, 3>(
-             new UW_Camera_Mapper(feature_x, feature_y));
+     auto* cost_function =
+         new AutoDiffCostFunction<UW_Camera_Mapper, 2, 9, 3>(feature_x, feature_y);
 
      LossFunctionWrapper* loss_function(new HuberLoss(1.0), TAKE_OWNERSHIP);
      problem.AddResidualBlock(cost_function, loss_function, parameters);
@@ -1154,7 +1165,6 @@
 matrix such that the robustified Gauss-Newton step corresponds to an
 ordinary linear least squares problem.
 
-
 Let :math:`\alpha` be a root of
 
 .. math:: \frac{1}{2}\alpha^2 - \alpha - \frac{\rho''}{\rho'}\|f(x)\|^2 = 0.
@@ -1178,363 +1188,644 @@
 problems.
 
 
-:class:`LocalParameterization`
-==============================
-
-.. class:: LocalParameterization
-
-  In many optimization problems, especially sensor fusion problems,
-  one has to model quantities that live in spaces known as `Manifolds
-  <https://en.wikipedia.org/wiki/Manifold>`_ , for example the
-  rotation/orientation of a sensor that is represented by a
-  `Quaternion
-  <https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation>`_.
-
-  Manifolds are spaces, which locally look like Euclidean spaces. More
-  precisely, at each point on the manifold there is a linear space
-  that is tangent to the manifold. It has dimension equal to the
-  intrinsic dimension of the manifold itself, which is less than or
-  equal to the ambient space in which the manifold is embedded.
-
-  For example, the tangent space to a point on a sphere in three
-  dimensions is the two dimensional plane that is tangent to the
-  sphere at that point. There are two reasons tangent spaces are
-  interesting:
-
-  1. They are Euclidean spaces, so the usual vector space operations
-     apply there, which makes numerical operations easy.
-
-  2. Movement in the tangent space translate into movements along the
-     manifold.  Movements perpendicular to the tangent space do not
-     translate into movements on the manifold.
-
-     Returning to our sphere example, moving in the 2 dimensional
-     plane tangent to the sphere and projecting back onto the sphere
-     will move you away from the point you started from but moving
-     along the normal at the same point and the projecting back onto
-     the sphere brings you back to the point.
-
-  Besides the mathematical niceness, modeling manifold valued
-  quantities correctly and paying attention to their geometry has
-  practical benefits too:
-
-  1. It naturally constrains the quantity to the manifold through out
-     the optimization. Freeing the user from hacks like *quaternion
-     normalization*.
-
-  2. It reduces the dimension of the optimization problem to its
-     *natural* size. For example, a quantity restricted to a line, is a
-     one dimensional object regardless of the dimension of the ambient
-     space in which this line lives.
-
-     Working in the tangent space reduces not just the computational
-     complexity of the optimization algorithm, but also improves the
-     numerical behaviour of the algorithm.
-
-  A basic operation one can perform on a manifold is the
-  :math:`\boxplus` operation that computes the result of moving along
-  delta in the tangent space at x, and then projecting back onto the
-  manifold that x belongs to. Also known as a *Retraction*,
-  :math:`\boxplus` is a generalization of vector addition in Euclidean
-  spaces. Formally, :math:`\boxplus` is a smooth map from a
-  manifold :math:`\mathcal{M}` and its tangent space
-  :math:`T_\mathcal{M}` to the manifold :math:`\mathcal{M}` that
-  obeys the identity
-
-  .. math::  \boxplus(x, 0) = x,\quad \forall x.
-
-  That is, it ensures that the tangent space is *centered* at :math:`x`
-  and the zero vector is the identity element. For more see
-  [Hertzberg]_ and section A.6.9 of [HartleyZisserman]_.
-
-  Let us consider two examples:
-
-  The Euclidean space :math:`R^n` is the simplest example of a
-  manifold. It has dimension :math:`n` (and so does its tangent space)
-  and :math:`\boxplus` is the familiar vector sum operation.
-
-    .. math:: \boxplus(x, \Delta) = x + \Delta
-
-  A more interesting case is :math:`SO(3)`, the special orthogonal
-  group in three dimensions - the space of 3x3 rotation
-  matrices. :math:`SO(3)` is a three dimensional manifold embedded in
-  :math:`R^9` or :math:`R^{3\times 3}`.
-
-  :math:`\boxplus` on :math:`SO(3)` is defined using the *Exponential*
-  map, from the tangent space (:math:`R^3`) to the manifold. The
-  Exponential map :math:`\operatorname{Exp}` is defined as:
-
-  .. math::
-
-     \operatorname{Exp}([p,q,r]) = \left [ \begin{matrix}
-     \cos \theta + cp^2 & -sr + cpq        &  sq + cpr \\
-     sr + cpq         & \cos \theta + cq^2& -sp + cqr \\
-     -sq + cpr        & sp + cqr         & \cos \theta + cr^2
-     \end{matrix} \right ]
-
-  where,
-
-  .. math::
-     \theta = \sqrt{p^2 + q^2 + r^2}, s = \frac{\sin \theta}{\theta},
-     c = \frac{1 - \cos \theta}{\theta^2}.
-
-  Then,
-
-  .. math::
-
-     \boxplus(x, \Delta) = x \operatorname{Exp}(\Delta)
-
-  The ``LocalParameterization`` interface allows the user to define
-  and associate with parameter blocks the manifold that they belong
-  to. It does so by defining the ``Plus`` (:math:`\boxplus`) operation
-  and its derivative with respect to :math:`\Delta` at :math:`\Delta =
-  0`.
-
-   .. code-block:: c++
-
-     class LocalParameterization {
-      public:
-       virtual ~LocalParameterization() {}
-       virtual bool Plus(const double* x,
-                         const double* delta,
-                         double* x_plus_delta) const = 0;
-       virtual bool ComputeJacobian(const double* x, double* jacobian) const = 0;
-       virtual bool MultiplyByJacobian(const double* x,
-                                       const int num_rows,
-                                       const double* global_matrix,
-                                       double* local_matrix) const;
-       virtual int GlobalSize() const = 0;
-       virtual int LocalSize() const = 0;
-     };
+While the theory described above is elegant, in practice we observe
+that using the Triggs correction when :math:`\rho'' > 0` leads to poor
+performance, so we upper bound it by zero. For more details see
+`corrector.cc <https://github.com/ceres-solver/ceres-solver/blob/master/internal/ceres/corrector.cc#L51>`_
 
 
-.. function:: int LocalParameterization::GlobalSize()
+:class:`Manifold`
+==================
 
-   The dimension of the ambient space in which the parameter block
-   :math:`x` lives.
+.. class:: Manifold
 
-.. function:: int LocalParameterization::LocalSize()
+In sensor fusion problems, we often have to model quantities that live
+in spaces known as `Manifolds
+<https://en.wikipedia.org/wiki/Manifold>`_, for example the
+rotation/orientation of a sensor that is represented by a `Quaternion
+<https://en.wikipedia.org/wiki/Quaternion>`_.
 
-   The size of the tangent space that :math:`\Delta` lives in.
+Manifolds are spaces which locally look like Euclidean spaces. More
+precisely, at each point on the manifold there is a linear space that
+is tangent to the manifold. It has dimension equal to the intrinsic
+dimension of the manifold itself, which is less than or equal to the
+ambient space in which the manifold is embedded.
 
-.. function:: bool LocalParameterization::Plus(const double* x, const double* delta, double* x_plus_delta) const
+For example, the tangent space to a point on a sphere in three
+dimensions is the two dimensional plane that is tangent to the sphere
+at that point. There are two reasons tangent spaces are interesting:
 
-    :func:`LocalParameterization::Plus` implements :math:`\boxplus(x,\Delta)`.
+1. They are Eucliean spaces so the usual vector space operations apply
+   there, which makes numerical operations easy.
 
-.. function:: bool LocalParameterization::ComputeJacobian(const double* x, double* jacobian) const
+2. Movements in the tangent space translate into movements along the
+   manifold.  Movements perpendicular to the tangent space do not
+   translate into movements on the manifold.
 
-   Computes the Jacobian matrix
+However, moving along the 2 dimensional plane tangent to the sphere
+and projecting back onto the sphere will move you away from the point
+you started from but moving along the normal at the same point and the
+projecting back onto the sphere brings you back to the point.
 
-   .. math:: J = D_2 \boxplus(x, 0)
+Besides the mathematical niceness, modeling manifold valued
+quantities correctly and paying attention to their geometry has
+practical benefits too:
 
-   in row major form.
+1. It naturally constrains the quantity to the manifold throughout the
+   optimization, freeing the user from hacks like *quaternion
+   normalization*.
 
-.. function:: bool MultiplyByJacobian(const double* x, const int num_rows, const double* global_matrix, double* local_matrix) const
+2. It reduces the dimension of the optimization problem to its
+   *natural* size. For example, a quantity restricted to a line is a
+   one dimensional object regardless of the dimension of the ambient
+   space in which this line lives.
 
-   ``local_matrix = global_matrix * jacobian``
+   Working in the tangent space reduces not just the computational
+   complexity of the optimization algorithm, but also improves the
+   numerical behaviour of the algorithm.
 
-   ``global_matrix`` is a ``num_rows x GlobalSize``  row major matrix.
-   ``local_matrix`` is a ``num_rows x LocalSize`` row major matrix.
-   ``jacobian`` is the matrix returned by :func:`LocalParameterization::ComputeJacobian` at :math:`x`.
+A basic operation one can perform on a manifold is the
+:math:`\boxplus` operation that computes the result of moving along
+:math:`\delta` in the tangent space at :math:`x`, and then projecting
+back onto the manifold that :math:`x` belongs to. Also known as a
+*Retraction*, :math:`\boxplus` is a generalization of vector addition
+in Euclidean spaces.
 
-   This is only used by :class:`GradientProblem`. For most normal
-   uses, it is okay to use the default implementation.
+The inverse of :math:`\boxplus` is :math:`\boxminus`, which given two
+points :math:`y` and :math:`x` on the manifold computes the tangent
+vector :math:`\Delta` at :math:`x` s.t. :math:`\boxplus(x, \Delta) =
+y`.
+
+Let us now consider two examples.
+
+The `Euclidean space <https://en.wikipedia.org/wiki/Euclidean_space>`_
+:math:`\mathbb{R}^n` is the simplest example of a manifold. It has
+dimension :math:`n` (and so does its tangent space) and
+:math:`\boxplus` and :math:`\boxminus` are the familiar vector sum and
+difference operations.
+
+.. math::
+   \begin{align*}
+   \boxplus(x, \Delta) &= x + \Delta = y\\
+   \boxminus(y, x) &= y - x = \Delta.
+   \end{align*}
+
+A more interesting case is the case :math:`SO(3)`, the `special
+orthogonal group <https://en.wikipedia.org/wiki/3D_rotation_group>`_
+in three dimensions - the space of :math:`3\times3` rotation
+matrices. :math:`SO(3)` is a three dimensional manifold embedded in
+:math:`\mathbb{R}^9` or :math:`\mathbb{R}^{3\times 3}`.  So points on :math:`SO(3)` are
+represented using 9 dimensional vectors or :math:`3\times 3` matrices,
+and points in its tangent spaces are represented by 3 dimensional
+vectors.
+
+For :math:`SO(3)`, :math:`\boxplus` and :math:`\boxminus` are defined
+in terms of the matrix :math:`\exp` and :math:`\log` operations as
+follows:
+
+Given a 3-vector :math:`\Delta = [\begin{matrix}p,&q,&r\end{matrix}]`, we have
+
+.. math::
+
+   \exp(\Delta) & = \left [ \begin{matrix}
+   \cos \theta + cp^2 & -sr + cpq        &  sq + cpr \\
+   sr + cpq         & \cos \theta + cq^2& -sp + cqr \\
+   -sq + cpr        & sp + cqr         & \cos \theta + cr^2
+   \end{matrix} \right ]
+
+where,
+
+.. math::
+     \begin{align}
+     \theta &= \sqrt{p^2 + q^2 + r^2},\\
+     s &= \frac{\sin \theta}{\theta},\\
+     c &= \frac{1 - \cos \theta}{\theta^2}.
+     \end{align}
+
+Given :math:`x \in SO(3)`, we have
+
+.. math::
+
+   \log(x) = 1/(2 \sin(\theta)/\theta)\left[\begin{matrix} x_{32} - x_{23},& x_{13} - x_{31},& x_{21} - x_{12}\end{matrix} \right]
+
+
+where,
+
+.. math:: \theta = \cos^{-1}((\operatorname{Trace}(x) - 1)/2)
+
+Then,
+
+.. math::
+   \begin{align*}
+   \boxplus(x, \Delta) &= x \exp(\Delta)
+   \\
+   \boxminus(y, x) &= \log(x^T y)
+   \end{align*}
+
+For :math:`\boxplus` and :math:`\boxminus` to be mathematically
+consistent, the following identities must be satisfied at all points
+:math:`x` on the manifold:
+
+1. :math:`\boxplus(x, 0) = x`. This ensures that the tangent space is
+   *centered* at :math:`x`, and the zero vector is the identity
+   element.
+2. For all :math:`y` on the manifold, :math:`\boxplus(x,
+   \boxminus(y,x)) = y`. This ensures that any :math:`y` can be
+   reached from :math:`x`.
+3. For all :math:`\Delta`, :math:`\boxminus(\boxplus(x, \Delta), x) =
+   \Delta`. This ensures that :math:`\boxplus` is an injective
+   (one-to-one) map.
+4. For all :math:`\Delta_1, \Delta_2\ |\boxminus(\boxplus(x, \Delta_1),
+   \boxplus(x, \Delta_2)) \leq |\Delta_1 - \Delta_2|`. Allows us to define
+   a metric on the manifold.
+
+Additionally we require that :math:`\boxplus` and :math:`\boxminus` be
+sufficiently smooth. In particular they need to be differentiable
+everywhere on the manifold.
+
+For more details, please see [Hertzberg]_
+
+The :class:`Manifold` interface allows the user to define a manifold
+for the purposes optimization by implementing ``Plus`` and ``Minus``
+operations and their derivatives (corresponding naturally to
+:math:`\boxplus` and :math:`\boxminus`).
+
+.. code-block:: c++
+
+  class Manifold {
+   public:
+    virtual ~Manifold();
+    virtual int AmbientSize() const = 0;
+    virtual int TangentSize() const = 0;
+    virtual bool Plus(const double* x,
+                      const double* delta,
+                      double* x_plus_delta) const = 0;
+    virtual bool PlusJacobian(const double* x, double* jacobian) const = 0;
+    virtual bool RightMultiplyByPlusJacobian(const double* x,
+                                             const int num_rows,
+                                             const double* ambient_matrix,
+                                             double* tangent_matrix) const;
+    virtual bool Minus(const double* y,
+                       const double* x,
+                       double* y_minus_x) const = 0;
+    virtual bool MinusJacobian(const double* x, double* jacobian) const = 0;
+  };
+
+
+.. function:: int Manifold::AmbientSize() const;
+
+   Dimension of the ambient space in which the manifold is embedded.
+
+.. function:: int Manifold::TangentSize() const;
+
+   Dimension of the manifold/tangent space.
+
+.. function:: bool Plus(const double* x, const double* delta, double* x_plus_delta) const;
+
+   Implements the :math:`\boxplus(x,\Delta)` operation for the manifold.
+
+   A generalization of vector addition in Euclidean space, ``Plus``
+   computes the result of moving along ``delta`` in the tangent space
+   at ``x``, and then projecting back onto the manifold that ``x``
+   belongs to.
+
+   ``x`` and ``x_plus_delta`` are :func:`Manifold::AmbientSize` vectors.
+   ``delta`` is a :func:`Manifold::TangentSize` vector.
+
+   Return value indicates if the operation was successful or not.
+
+.. function:: bool PlusJacobian(const double* x, double* jacobian) const;
+
+   Compute the derivative of :math:`\boxplus(x, \Delta)` w.r.t
+   :math:`\Delta` at :math:`\Delta = 0`, i.e. :math:`(D_2
+   \boxplus)(x, 0)`.
+
+   ``jacobian`` is a row-major :func:`Manifold::AmbientSize`
+   :math:`\times` :func:`Manifold::TangentSize` matrix.
+
+   Return value indicates whether the operation was successful or not.
+
+.. function:: bool RightMultiplyByPlusJacobian(const double* x, const int num_rows, const double* ambient_matrix, double* tangent_matrix) const;
+
+   ``tangent_matrix`` = ``ambient_matrix`` :math:`\times` plus_jacobian.
+
+
+   ``ambient_matrix`` is a row-major ``num_rows`` :math:`\times`
+   :func:`Manifold::AmbientSize` matrix.
+
+   ``tangent_matrix`` is a row-major ``num_rows`` :math:`\times`
+   :func:`Manifold::TangentSize` matrix.
+
+   Return value indicates whether the operation was successful or not.
+
+   This function is only used by the :class:`GradientProblemSolver`,
+   where the dimension of the parameter block can be large and it may
+   be more efficient to compute this product directly rather than
+   first evaluating the Jacobian into a matrix and then doing a matrix
+   vector product.
+
+   Because this is not an often used function, we provide a default
+   implementation for convenience. If performance becomes an issue
+   then the user should consider implementing a specialization.
+
+.. function:: bool Minus(const double* y, const double* x, double* y_minus_x) const;
+
+   Implements :math:`\boxminus(y,x)` operation for the manifold.
+
+   A generalization of vector subtraction in Euclidean spaces, given
+   two points ``x`` and ``y`` on the manifold, ``Minus`` computes the
+   change to ``x`` in the tangent space at ``x``, that will take it to
+   ``y``.
+
+   ``x`` and ``y`` are :func:`Manifold::AmbientSize` vectors.
+   ``y_minus_x`` is a ::func:`Manifold::TangentSize` vector.
+
+   Return value indicates if the operation was successful or not.
+
+.. function:: bool MinusJacobian(const double* x, double* jacobian) const = 0;
+
+   Compute the derivative of :math:`\boxminus(y, x)` w.r.t :math:`y`
+   at :math:`y = x`, i.e :math:`(D_1 \boxminus) (x, x)`.
+
+   ``jacobian`` is a row-major :func:`Manifold::TangentSize`
+   :math:`\times` :func:`Manifold::AmbientSize` matrix.
+
+   Return value indicates whether the operation was successful or not.
 
 Ceres Solver ships with a number of commonly used instances of
-:class:`LocalParameterization`. Another great place to find high
-quality implementations of :math:`\boxplus` operations on a variety of
-manifolds is the `Sophus <https://github.com/strasdat/Sophus>`_
-library developed by Hauke Strasdat and his collaborators.
+:class:`Manifold`.
 
-:class:`IdentityParameterization`
----------------------------------
+For `Lie Groups <https://en.wikipedia.org/wiki/Lie_group>`_, a great
+place to find high quality implementations is the `Sophus
+<https://github.com/strasdat/Sophus>`_ library developed by Hauke
+Strasdat and his collaborators.
 
-A trivial version of :math:`\boxplus` is when :math:`\Delta` is of the
-same size as :math:`x` and
+:class:`EuclideanManifold`
+--------------------------
 
-.. math::  \boxplus(x, \Delta) = x + \Delta
+.. class:: EuclideanManifold
 
-This is the same as :math:`x` living in a Euclidean manifold.
+:class:`EuclideanManifold` as the name implies represents a Euclidean
+space, where the :math:`\boxplus` and :math:`\boxminus` operations are
+the usual vector addition and subtraction.
 
-:class:`QuaternionParameterization`
------------------------------------
+.. math::
 
-Another example that occurs commonly in Structure from Motion problems
-is when camera rotations are parameterized using a quaternion. This is
-a 3-dimensional manifold that lives in 4-dimensional space.
+   \begin{align*}
+     \boxplus(x, \Delta) &= x + \Delta\\
+      \boxminus(y,x) &= y - x
+   \end{align*}
 
-.. math:: \boxplus(x, \Delta) = \left[ \cos(|\Delta|), \frac{\sin\left(|\Delta|\right)}{|\Delta|} \Delta \right] * x
+By default parameter blocks are assumed to be Euclidean, so there is
+no need to use this manifold on its own. It is provided for the
+purpose of testing and for use in combination with other manifolds
+using :class:`ProductManifold`.
 
-The multiplication :math:`*` between the two 4-vectors on the right
-hand side is the standard quaternion product.
+The class works with dynamic and static ambient space dimensions. If
+the ambient space dimensions is known at compile time use
 
-:class:`EigenQuaternionParameterization`
-----------------------------------------
+.. code-block:: c++
 
-`Eigen <http://eigen.tuxfamily.org/index.php?title=Main_Page>`_ uses a
-different internal memory layout for the elements of the quaternion
-than what is commonly used. Specifically, Eigen stores the elements in
-memory as :math:`(x, y, z, w)`, i.e., the *real* part (:math:`w`) is
-stored as the last element. Note, when creating an Eigen quaternion
-through the constructor the elements are accepted in :math:`w, x, y,
-z` order.
+   EuclideanManifold<3> manifold;
 
-Since Ceres operates on parameter blocks which are raw ``double``
-pointers this difference is important and requires a different
-parameterization. :class:`EigenQuaternionParameterization` uses the
-same ``Plus`` operation as :class:`QuaternionParameterization` but
-takes into account Eigen's internal memory element ordering.
+If the ambient space dimensions is not known at compile time the
+template parameter needs to be set to `ceres::DYNAMIC` and the actual
+dimension needs to be provided as a constructor argument:
 
-:class:`SubsetParameterization`
--------------------------------
+.. code-block:: c++
+
+   EuclideanManifold<ceres::DYNAMIC> manifold(ambient_dim);
+
+:class:`SubsetManifold`
+-----------------------
+
+.. class:: SubsetManifold
 
 Suppose :math:`x` is a two dimensional vector, and the user wishes to
 hold the first coordinate constant. Then, :math:`\Delta` is a scalar
 and :math:`\boxplus` is defined as
 
-.. math:: \boxplus(x, \Delta) = x + \left[ \begin{array}{c} 0 \\ 1 \end{array} \right] \Delta
+.. math::
+   \boxplus(x, \Delta) = x + \left[ \begin{array}{c} 0 \\ 1 \end{array} \right] \Delta
 
-:class:`SubsetParameterization` generalizes this construction to hold
+and given two, two-dimensional vectors :math:`x` and :math:`y` with
+the same first coordinate, :math:`\boxminus` is defined as:
+
+.. math::
+   \boxminus(y, x) = y[1] - x[1]
+
+:class:`SubsetManifold` generalizes this construction to hold
 any part of a parameter block constant by specifying the set of
 coordinates that are held constant.
 
 .. NOTE::
-   It is legal to hold all coordinates of a parameter block to constant
-   using a :class:`SubsetParameterization`. It is the same as calling
+
+   It is legal to hold *all* coordinates of a parameter block to
+   constant using a :class:`SubsetManifold`. It is the same as calling
    :func:`Problem::SetParameterBlockConstant` on that parameter block.
 
-:class:`HomogeneousVectorParameterization`
-------------------------------------------
 
-In computer vision, homogeneous vectors are commonly used to represent
-objects in projective geometry such as points in projective space. One
-example where it is useful to use this over-parameterization is in
-representing points whose triangulation is ill-conditioned. Here it is
-advantageous to use homogeneous vectors, instead of an Euclidean
-vector, because it can represent points at and near infinity.
+:class:`ProductManifold`
+------------------------
 
-:class:`HomogeneousVectorParameterization` defines a
-:class:`LocalParameterization` for an :math:`n-1` dimensional
-manifold that embedded in :math:`n` dimensional space where the
-scale of the vector does not matter, i.e., elements of the
-projective space :math:`\mathbb{P}^{n-1}`. It assumes that the last
-coordinate of the :math:`n`-vector is the *scalar* component of the
-homogenous vector, i.e., *finite* points in this representation are
-those for which the *scalar* component is non-zero.
-
-Further, ``HomogeneousVectorParameterization::Plus`` preserves the
-scale of :math:`x`.
-
-:class:`LineParameterization`
------------------------------
-
-This class provides a parameterization for lines, where the line is
-defined using an origin point and a direction vector. So the
-parameter vector size needs to be two times the ambient space
-dimension, where the first half is interpreted as the origin point
-and the second half as the direction. This local parameterization is
-a special case of the `Affine Grassmannian manifold
-<https://en.wikipedia.org/wiki/Affine_Grassmannian_(manifold))>`_
-for the case :math:`\operatorname{Graff}_1(R^n)`.
-
-Note that this is a parameterization for a line, rather than a point
-constrained to lie on a line. It is useful when one wants to optimize
-over the space of lines. For example, :math:`n` distinct points in 3D
-(measurements) we want to find the line that minimizes the sum of
-squared distances to all the points.
-
-:class:`ProductParameterization`
---------------------------------
-
-Consider an optimization problem over the space of rigid
-transformations :math:`SE(3)`, which is the Cartesian product of
-:math:`SO(3)` and :math:`\mathbb{R}^3`. Suppose you are using
-Quaternions to represent the rotation, Ceres ships with a local
-parameterization for that and :math:`\mathbb{R}^3` requires no, or
-:class:`IdentityParameterization` parameterization. So how do we
-construct a local parameterization for a parameter block a rigid
-transformation?
+.. class:: ProductManifold
 
 In cases, where a parameter block is the Cartesian product of a number
-of manifolds and you have the local parameterization of the individual
-manifolds available, :class:`ProductParameterization` can be used to
-construct a local parameterization of the cartesian product. For the
-case of the rigid transformation, where say you have a parameter block
-of size 7, where the first four entries represent the rotation as a
-quaternion, a local parameterization can be constructed as
+of manifolds and you have the manifold of the individual
+parameter blocks available, :class:`ProductManifold` can be used to
+construct a :class:`Manifold` of the Cartesian product.
+
+For the case of the rigid transformation, where say you have a
+parameter block of size 7, where the first four entries represent the
+rotation as a quaternion, and the next three the translation, a
+manifold can be constructed as:
 
 .. code-block:: c++
 
-   ProductParameterization se3_param(new QuaternionParameterization(),
-                                     new IdentityParameterization(3));
+   ProductManifold<QuaternionManifold, EuclideanManifold<3>> se3;
+
+Manifolds can be copied and moved to :class:`ProductManifold`:
+
+.. code-block:: c++
+
+   SubsetManifold manifold1(5, {2});
+   SubsetManifold manifold2(3, {0, 1});
+   ProductManifold<SubsetManifold, SubsetManifold> manifold(manifold1,
+                                                            manifold2);
+
+In advanced use cases, manifolds can be dynamically allocated and passed as (smart) pointers:
+
+.. code-block:: c++
+
+   ProductManifold<std::unique_ptr<QuaternionManifold>, EuclideanManifold<3>> se3
+        {std::make_unique<QuaternionManifold>(), EuclideanManifold<3>{}};
+
+The template parameters can also be left out as they are deduced automatically
+making the initialization much simpler:
+
+.. code-block:: c++
+
+   ProductManifold se3{QuaternionManifold{}, EuclideanManifold<3>{}};
 
 
-:class:`AutoDiffLocalParameterization`
-======================================
+:class:`QuaternionManifold`
+---------------------------
 
-.. class:: AutoDiffLocalParameterization
+.. class:: QuaternionManifold
 
-  :class:`AutoDiffLocalParameterization` does for
-  :class:`LocalParameterization` what :class:`AutoDiffCostFunction`
-  does for :class:`CostFunction`. It allows the user to define a
-  templated functor that implements the
-  :func:`LocalParameterization::Plus` operation and it uses automatic
-  differentiation to implement the computation of the Jacobian.
+.. NOTE::
 
-  To get an auto differentiated local parameterization, you must
-  define a class with a templated operator() (a functor) that computes
+   If you are using ``Eigen`` quaternions, then you should use
+   :class:`EigenQuaternionManifold` instead because ``Eigen`` uses a
+   different memory layout for its Quaternions.
 
-     .. math:: x' = \boxplus(x, \Delta x),
+Manifold for a Hamilton `Quaternion
+<https://en.wikipedia.org/wiki/Quaternion>`_. Quaternions are a three
+dimensional manifold represented as unit norm 4-vectors, i.e.
 
-  For example, Quaternions have a three dimensional local
-  parameterization. Its plus operation can be implemented as (taken
-  from `internal/ceres/autodiff_local_parameterization_test.cc
-  <https://ceres-solver.googlesource.com/ceres-solver/+/master/internal/ceres/autodiff_local_parameterization_test.cc>`_
-  )
+.. math:: q = \left [\begin{matrix}q_0,& q_1,& q_2,& q_3\end{matrix}\right], \quad \|q\| = 1
 
-    .. code-block:: c++
+is the ambient space representation. Here :math:`q_0` is the scalar
+part. :math:`q_1` is the coefficient of :math:`i`, :math:`q_2` is the
+coefficient of :math:`j`, and :math:`q_3` is the coefficient of
+:math:`k`. Where:
 
-      struct QuaternionPlus {
-        template<typename T>
-        bool operator()(const T* x, const T* delta, T* x_plus_delta) const {
-          const T squared_norm_delta =
-              delta[0] * delta[0] + delta[1] * delta[1] + delta[2] * delta[2];
+.. math::
 
-          T q_delta[4];
-          if (squared_norm_delta > 0.0) {
-            T norm_delta = sqrt(squared_norm_delta);
-            const T sin_delta_by_delta = sin(norm_delta) / norm_delta;
-            q_delta[0] = cos(norm_delta);
-            q_delta[1] = sin_delta_by_delta * delta[0];
-            q_delta[2] = sin_delta_by_delta * delta[1];
-            q_delta[3] = sin_delta_by_delta * delta[2];
-          } else {
-            // We do not just use q_delta = [1,0,0,0] here because that is a
-            // constant and when used for automatic differentiation will
-            // lead to a zero derivative. Instead we take a first order
-            // approximation and evaluate it at zero.
-            q_delta[0] = T(1.0);
-            q_delta[1] = delta[0];
-            q_delta[2] = delta[1];
-            q_delta[3] = delta[2];
-          }
+   \begin{align*}
+   i\times j &= k,\\
+   j\times k &= i,\\
+   k\times i &= j,\\
+   i\times i &= -1,\\
+   j\times j &= -1,\\
+   k\times k &= -1.
+   \end{align*}
 
-          Quaternionproduct(q_delta, x, x_plus_delta);
-          return true;
-        }
-      };
+The tangent space is three dimensional and the :math:`\boxplus` and
+:math:`\boxminus` operators are defined in term of :math:`\exp` and
+:math:`\log` operations.
 
-  Given this struct, the auto differentiated local
-  parameterization can now be constructed as
+.. math::
+   \begin{align*}
+   \boxplus(x, \Delta) &= \exp\left(\Delta\right) \otimes  x \\
+   \boxminus(y,x) &= \log\left(y \otimes x^{-1}\right)
+   \end{align*}
 
-  .. code-block:: c++
+Where :math:`\otimes` is the `Quaternion product
+<https://en.wikipedia.org/wiki/Quaternion#Hamilton_product>`_ and
+since :math:`x` is a unit quaternion, :math:`x^{-1} = [\begin{matrix}
+q_0,& -q_1,& -q_2,& -q_3\end{matrix}]`. Given a vector :math:`\Delta
+\in \mathbb{R}^3`,
 
-     LocalParameterization* local_parameterization =
-         new AutoDiffLocalParameterization<QuaternionPlus, 4, 3>;
-                                                           |  |
-                                Global Size ---------------+  |
-                                Local Size -------------------+
+.. math::
+   \exp(\Delta) = \left[ \begin{matrix}
+                         \cos\left(\|\Delta\|\right)\\
+			 \frac{\displaystyle \sin\left(|\Delta\|\right)}{\displaystyle \|\Delta\|} \Delta
+    	                 \end{matrix} \right]
 
+and given a unit quaternion :math:`q = \left [\begin{matrix}q_0,& q_1,& q_2,& q_3\end{matrix}\right]`
+
+.. math::
+
+   \log(q) =  \frac{\operatorname{atan2}\left(\sqrt{1-q_0^2},q_0\right)}{\sqrt{1-q_0^2}} \left [\begin{matrix}q_1,& q_2,& q_3\end{matrix}\right]
+
+
+:class:`EigenQuaternionManifold`
+--------------------------------
+
+.. class:: EigenQuaternionManifold
+
+Implements the quaternion manifold for `Eigen's
+<http://eigen.tuxfamily.org/index.php?title=Main_Page>`_
+representation of the Hamilton quaternion. Geometrically it is exactly
+the same as the :class:`QuaternionManifold` defined above. However,
+Eigen uses a different internal memory layout for the elements of the
+quaternion than what is commonly used. It stores the quaternion in
+memory as :math:`[q_1, q_2, q_3, q_0]` or :math:`[x, y, z, w]` where
+the real (scalar) part is last.
+
+Since Ceres operates on parameter blocks which are raw double pointers
+this difference is important and requires a different manifold.
+
+:class:`SphereManifold`
+-----------------------
+
+.. class:: SphereManifold
+
+This provides a manifold on a sphere meaning that the norm of the
+vector stays the same. Such cases often arises in Structure for Motion
+problems. One example where they are used is in representing points
+whose triangulation is ill-conditioned. Here it is advantageous to use
+an over-parameterization since homogeneous vectors can represent
+points at infinity.
+
+The ambient space dimension is required to be greater than 1.
+
+The class works with dynamic and static ambient space dimensions. If
+the ambient space dimensions is known at compile time use
+
+.. code-block:: c++
+
+   SphereManifold<3> manifold;
+
+If the ambient space dimensions is not known at compile time the
+template parameter needs to be set to `ceres::DYNAMIC` and the actual
+dimension needs to be provided as a constructor argument:
+
+.. code-block:: c++
+
+   SphereManifold<ceres::DYNAMIC> manifold(ambient_dim);
+
+For more details, please see Section B.2 (p.25) in [Hertzberg]_
+
+
+:class:`LineManifold`
+---------------------
+
+.. class:: LineManifold
+
+This class provides a manifold for lines, where the line is defined
+using an origin point and a direction vector. So the ambient size
+needs to be two times the dimension of the space in which the line
+lives.  The first half of the parameter block is interpreted as the
+origin point and the second half as the direction. This manifold is a
+special case of the `Affine Grassmannian manifold
+<https://en.wikipedia.org/wiki/Affine_Grassmannian_(manifold))>`_ for
+the case :math:`\operatorname{Graff}_1(R^n)`.
+
+Note that this is a manifold for a line, rather than a point
+constrained to lie on a line. It is useful when one wants to optimize
+over the space of lines. For example, given :math:`n` distinct points
+in 3D (measurements) we want to find the line that minimizes the sum
+of squared distances to all the points.
+
+:class:`AutoDiffManifold`
+=========================
+
+.. class:: AutoDiffManifold
+
+Create a :class:`Manifold` with Jacobians computed via automatic
+differentiation.
+
+To get an auto differentiated manifold, you must define a Functor with
+templated ``Plus`` and ``Minus`` functions that compute:
+
+.. code-block:: c++
+
+  x_plus_delta = Plus(x, delta);
+  y_minus_x    = Minus(y, x);
+
+Where, ``x``, ``y`` and ``x_plus_delta`` are vectors on the manifold in
+the ambient space (so they are ``kAmbientSize`` vectors) and
+``delta``, ``y_minus_x`` are vectors in the tangent space (so they are
+``kTangentSize`` vectors).
+
+The Functor should have the signature:
+
+.. code-block:: c++
+
+   struct Functor {
+    template <typename T>
+    bool Plus(const T* x, const T* delta, T* x_plus_delta) const;
+
+    template <typename T>
+    bool Minus(const T* y, const T* x, T* y_minus_x) const;
+   };
+
+
+Observe that  the ``Plus`` and  ``Minus`` operations are  templated on
+the parameter  ``T``.  The autodiff framework  substitutes appropriate
+``Jet``  objects for  ``T`` in  order to  compute the  derivative when
+necessary.  This  is  the  same  mechanism that  is  used  to  compute
+derivatives when using :class:`AutoDiffCostFunction`.
+
+``Plus`` and ``Minus`` should return true if the computation is
+successful and false otherwise, in which case the result will not be
+used.
+
+Given this Functor, the corresponding :class:`Manifold` can be constructed as:
+
+.. code-block:: c++
+
+   AutoDiffManifold<Functor, kAmbientSize, kTangentSize> manifold;
+
+.. NOTE::
+
+   The following is only used for illustration purposes. Ceres Solver
+   ships with an optimized, production grade :class:`QuaternionManifold`
+   implementation.
+
+As a concrete example consider the case of `Quaternions
+<https://en.wikipedia.org/wiki/Quaternion>`_. Quaternions form a three
+dimensional manifold embedded in :math:`\mathbb{R}^4`, i.e. they have
+an ambient dimension of 4 and their tangent space has dimension 3. The
+following Functor defines the ``Plus`` and ``Minus`` operations on the
+Quaternion manifold. It assumes that the quaternions are laid out as
+``[w,x,y,z]`` in memory, i.e. the real or scalar part is the first
+coordinate.
+
+.. code-block:: c++
+
+   struct QuaternionFunctor {
+     template <typename T>
+     bool Plus(const T* x, const T* delta, T* x_plus_delta) const {
+       const T squared_norm_delta =
+           delta[0] * delta[0] + delta[1] * delta[1] + delta[2] * delta[2];
+
+       T q_delta[4];
+       if (squared_norm_delta > T(0.0)) {
+         T norm_delta = sqrt(squared_norm_delta);
+         const T sin_delta_by_delta = sin(norm_delta) / norm_delta;
+         q_delta[0] = cos(norm_delta);
+         q_delta[1] = sin_delta_by_delta * delta[0];
+         q_delta[2] = sin_delta_by_delta * delta[1];
+         q_delta[3] = sin_delta_by_delta * delta[2];
+       } else {
+         // We do not just use q_delta = [1,0,0,0] here because that is a
+         // constant and when used for automatic differentiation will
+         // lead to a zero derivative. Instead we take a first order
+         // approximation and evaluate it at zero.
+         q_delta[0] = T(1.0);
+         q_delta[1] = delta[0];
+         q_delta[2] = delta[1];
+         q_delta[3] = delta[2];
+       }
+
+       QuaternionProduct(q_delta, x, x_plus_delta);
+       return true;
+     }
+
+     template <typename T>
+     bool Minus(const T* y, const T* x, T* y_minus_x) const {
+       T minus_x[4] = {x[0], -x[1], -x[2], -x[3]};
+       T ambient_y_minus_x[4];
+       QuaternionProduct(y, minus_x, ambient_y_minus_x);
+       T u_norm = sqrt(ambient_y_minus_x[1] * ambient_y_minus_x[1] +
+		       ambient_y_minus_x[2] * ambient_y_minus_x[2] +
+		       ambient_y_minus_x[3] * ambient_y_minus_x[3]);
+       if (u_norm > 0.0) {
+	 T theta = atan2(u_norm, ambient_y_minus_x[0]);
+	 y_minus_x[0] = theta * ambient_y_minus_x[1] / u_norm;
+	 y_minus_x[1] = theta * ambient_y_minus_x[2] / u_norm;
+	 y_minus_x[2] = theta * ambient_y_minus_x[3] / u_norm;
+       } else {
+	 We do not use [0,0,0] here because even though the value part is
+	 a constant, the derivative part is not.
+	 y_minus_x[0] = ambient_y_minus_x[1];
+	 y_minus_x[1] = ambient_y_minus_x[2];
+	 y_minus_x[2] = ambient_y_minus_x[3];
+       }
+       return true;
+     }
+   };
+
+
+Then given this struct, the auto differentiated Quaternion Manifold can now
+be constructed as
+
+.. code-block:: c++
+
+   Manifold* manifold = new AutoDiffManifold<QuaternionFunctor, 4, 3>;
 
 :class:`Problem`
 ================
@@ -1581,10 +1872,10 @@
 
    :func:`Problem::AddParameterBlock` explicitly adds a parameter
    block to the :class:`Problem`. Optionally it allows the user to
-   associate a :class:`LocalParameterization` object with the
-   parameter block too. Repeated calls with the same arguments are
-   ignored. Repeated calls with the same double pointer but a
-   different size results in undefined behavior.
+   associate a :class:`Manifold` object with the parameter block
+   too. Repeated calls with the same arguments are ignored. Repeated
+   calls with the same double pointer but a different size results in
+   undefined behavior.
 
    You can set any parameter block to be constant using
    :func:`Problem::SetParameterBlockConstant` and undo this using
@@ -1604,17 +1895,16 @@
    **Ownership**
 
    :class:`Problem` by default takes ownership of the
-   ``cost_function``, ``loss_function`` and ``local_parameterization``
-   pointers. These objects remain live for the life of the
-   :class:`Problem`. If the user wishes to keep control over the
-   destruction of these objects, then they can do this by setting the
-   corresponding enums in the :class:`Problem::Options` struct.
+   ``cost_function``, ``loss_function`` and ``manifold`` pointers. These
+   objects remain live for the life of the :class:`Problem`. If the user wishes
+   to keep control over the destruction of these objects, then they can do this
+   by setting the corresponding enums in the :class:`Problem::Options` struct.
 
-   Note that even though the Problem takes ownership of ``cost_function``
-   and ``loss_function``, it does not preclude the user from re-using
-   them in another residual block. The destructor takes care to call
-   delete on each ``cost_function`` or ``loss_function`` pointer only
-   once, regardless of how many residual blocks refer to them.
+   Note that even though the Problem takes ownership of objects,
+   ``cost_function`` and ``loss_function``, it does not preclude the
+   user from re-using them in another residual block. Similarly the
+   same ``manifold`` object can be used with multiple parameter blocks. The
+   destructor takes care to call delete on each owned object exactly once.
 
 .. class:: Problem::Options
 
@@ -1627,7 +1917,7 @@
    This option controls whether the Problem object owns the cost
    functions.
 
-   If set to TAKE_OWNERSHIP, then the problem object will delete the
+   If set to ``TAKE_OWNERSHIP``, then the problem object will delete the
    cost functions on destruction. The destructor is careful to delete
    the pointers only once, since sharing cost functions is allowed.
 
@@ -1638,21 +1928,19 @@
    This option controls whether the Problem object owns the loss
    functions.
 
-   If set to TAKE_OWNERSHIP, then the problem object will delete the
+   If set to ``TAKE_OWNERSHIP``, then the problem object will delete the
    loss functions on destruction. The destructor is careful to delete
    the pointers only once, since sharing loss functions is allowed.
 
-.. member:: Ownership Problem::Options::local_parameterization_ownership
+.. member:: Ownership Problem::Options::manifold_ownership
 
    Default: ``TAKE_OWNERSHIP``
 
-   This option controls whether the Problem object owns the local
-   parameterizations.
+   This option controls whether the Problem object owns the manifolds.
 
-   If set to TAKE_OWNERSHIP, then the problem object will delete the
-   local parameterizations on destruction. The destructor is careful
-   to delete the pointers only once, since sharing local
-   parameterizations is allowed.
+   If set to ``TAKE_OWNERSHIP``, then the problem object will delete the
+   manifolds on destruction. The destructor is careful to delete the
+   pointers only once, since sharing manifolds is allowed.
 
 .. member:: bool Problem::Options::enable_fast_removal
 
@@ -1689,12 +1977,13 @@
     overhead you want to avoid, then you can set
     disable_all_safety_checks to true.
 
-    **WARNING** Do not set this to true, unless you are absolutely
-    sure of what you are doing.
+    .. warning::
+        Do not set this to true, unless you are absolutely sure of what you are
+        doing.
 
 .. member:: Context* Problem::Options::context
 
-    Default: `nullptr`
+    Default: ``nullptr``
 
     A Ceres global context to use for solving this problem. This may
     help to reduce computation time as Ceres can reuse expensive
@@ -1705,7 +1994,7 @@
 
 .. member:: EvaluationCallback* Problem::Options::evaluation_callback
 
-    Default: `nullptr`
+    Default: ``nullptr``
 
     Using this callback interface, Ceres will notify you when it is
     about to evaluate the residuals or Jacobians.
@@ -1725,11 +2014,11 @@
 
        Evaluation callbacks are incompatible with inner iterations. So
        calling Solve with
-       :member:`Solver::Options::use_inner_iterations` set to `true`
+       :member:`Solver::Options::use_inner_iterations` set to ``true``
        on a :class:`Problem` with a non-null evaluation callback is an
        error.
 
-.. function:: ResidualBlockId Problem::AddResidualBlock(CostFunction* cost_function, LossFunction* loss_function, const vector<double*> parameter_blocks)
+.. function:: ResidualBlockId Problem::AddResidualBlock(CostFunction* cost_function, LossFunction* loss_function, const std::vector<double*> parameter_blocks)
 
 .. function:: template <typename Ts...> ResidualBlockId Problem::AddResidualBlock(CostFunction* cost_function, LossFunction* loss_function, double* x0, Ts... xs)
 
@@ -1738,7 +2027,7 @@
    parameter blocks it expects. The function checks that these match
    the sizes of the parameter blocks listed in parameter_blocks. The
    program aborts if a mismatch is detected. loss_function can be
-   `nullptr`, in which case the cost of the term is just the squared
+   ``nullptr``, in which case the cost of the term is just the squared
    norm of the residuals.
 
    The parameter blocks may be passed together as a
@@ -1756,11 +2045,12 @@
    keep control over the destruction of these objects, then they can
    do this by setting the corresponding enums in the Options struct.
 
-   Note: Even though the Problem takes ownership of cost_function
-   and loss_function, it does not preclude the user from re-using
-   them in another residual block. The destructor takes care to call
-   delete on each cost_function or loss_function pointer only once,
-   regardless of how many residual blocks refer to them.
+   .. note::
+       Even though the Problem takes ownership of ``cost_function``
+       and ``loss_function``, it does not preclude the user from re-using
+       them in another residual block. The destructor takes care to call
+       delete on each cost_function or loss_function pointer only once,
+       regardless of how many residual blocks refer to them.
 
    Example usage:
 
@@ -1769,9 +2059,9 @@
       double x1[] = {1.0, 2.0, 3.0};
       double x2[] = {1.0, 2.0, 5.0, 6.0};
       double x3[] = {3.0, 6.0, 2.0, 5.0, 1.0};
-      vector<double*> v1;
+      std::vector<double*> v1;
       v1.push_back(x1);
-      vector<double*> v2;
+      std::vector<double*> v2;
       v2.push_back(x2);
       v2.push_back(x1);
 
@@ -1782,12 +2072,19 @@
       problem.AddResidualBlock(new MyUnaryCostFunction(...), nullptr, v1);
       problem.AddResidualBlock(new MyBinaryCostFunction(...), nullptr, v2);
 
-.. function:: void Problem::AddParameterBlock(double* values, int size, LocalParameterization* local_parameterization)
+.. function:: void Problem::AddParameterBlock(double* values, int size, Manifold* manifold)
 
-   Add a parameter block with appropriate size to the problem.
+   Add a parameter block with appropriate size and Manifold to the
+   problem. It is okay for ``manifold`` to be ``nullptr``.
+
    Repeated calls with the same arguments are ignored. Repeated calls
-   with the same double pointer but a different size results in
-   undefined behavior.
+   with the same double pointer but a different size results in a crash
+   (unless :member:`Solver::Options::disable_all_safety_checks` is set to true).
+
+   Repeated calls with the same double pointer and size but different
+   :class:`Manifold` is equivalent to calling `SetManifold(manifold)`,
+   i.e., any previously associated :class:`Manifold` object will be replaced
+   with the `manifold`.
 
 .. function:: void Problem::AddParameterBlock(double* values, int size)
 
@@ -1798,35 +2095,46 @@
 
 .. function:: void Problem::RemoveResidualBlock(ResidualBlockId residual_block)
 
-   Remove a residual block from the problem. Any parameters that the residual
-   block depends on are not removed. The cost and loss functions for the
-   residual block will not get deleted immediately; won't happen until the
-   problem itself is deleted.  If Problem::Options::enable_fast_removal is
-   true, then the removal is fast (almost constant time). Otherwise, removing a
-   residual block will incur a scan of the entire Problem object to verify that
-   the residual_block represents a valid residual in the problem.
+   Remove a residual block from the problem.
 
-   **WARNING:** Removing a residual or parameter block will destroy
-   the implicit ordering, rendering the jacobian or residuals returned
-   from the solver uninterpretable. If you depend on the evaluated
-   jacobian, do not use remove! This may change in a future release.
-   Hold the indicated parameter block constant during optimization.
+   Since residual blocks are allowed to share cost function and loss
+   function objects, Ceres Solver uses a reference counting
+   mechanism. So when a residual block is deleted, the reference count
+   for the corresponding cost function and loss function objects are
+   decreased and when this count reaches zero, they are deleted.
+
+   If :member:`Problem::Options::enable_fast_removal` is ``true``, then the removal
+   is fast (almost constant time). Otherwise it is linear, requiring a
+   scan of the entire problem.
+
+   Removing a residual block has no effect on the parameter blocks
+   that the problem depends on.
+
+   .. warning::
+       Removing a residual or parameter block will destroy the implicit
+       ordering, rendering the jacobian or residuals returned from the solver
+       uninterpretable. If you depend on the evaluated jacobian, do not use
+       remove! This may change in a future release. Hold the indicated parameter
+       block constant during optimization.
 
 .. function:: void Problem::RemoveParameterBlock(const double* values)
 
-   Remove a parameter block from the problem. The parameterization of
-   the parameter block, if it exists, will persist until the deletion
-   of the problem (similar to cost/loss functions in residual block
-   removal). Any residual blocks that depend on the parameter are also
-   removed, as described above in RemoveResidualBlock().  If
-   Problem::Options::enable_fast_removal is true, then
-   the removal is fast (almost constant time). Otherwise, removing a
-   parameter block will incur a scan of the entire Problem object.
+   Remove a parameter block from the problem. Any residual blocks that
+   depend on the parameter are also removed, as described above in
+   :func:`RemoveResidualBlock()`.
 
-   **WARNING:** Removing a residual or parameter block will destroy
-   the implicit ordering, rendering the jacobian or residuals returned
-   from the solver uninterpretable. If you depend on the evaluated
-   jacobian, do not use remove! This may change in a future release.
+   The manifold of the parameter block, if it exists, will persist until the
+   deletion of the problem.
+
+   If :member:`Problem::Options::enable_fast_removal` is ``true``, then the removal
+   is fast (almost constant time). Otherwise, removing a parameter
+   block will scan the entire Problem.
+
+   .. warning::
+       Removing a residual or parameter block will destroy the implicit
+       ordering, rendering the jacobian or residuals returned from the solver
+       uninterpretable. If you depend on the evaluated jacobian, do not use
+       remove! This may change in a future release.
 
 .. function:: void Problem::SetParameterBlockConstant(const double* values)
 
@@ -1841,23 +2149,34 @@
    Returns ``true`` if a parameter block is set constant, and false
    otherwise. A parameter block may be set constant in two ways:
    either by calling ``SetParameterBlockConstant`` or by associating a
-   ``LocalParameterization`` with a zero dimensional tangent space
-   with it.
+   :class:`Manifold` with a zero dimensional tangent space with it.
 
-.. function:: void Problem::SetParameterization(double* values, LocalParameterization* local_parameterization)
+.. function:: void SetManifold(double* values, Manifold* manifold);
 
-   Set the local parameterization for one of the parameter blocks.
-   The local_parameterization is owned by the Problem by default. It
-   is acceptable to set the same parameterization for multiple
-   parameters; the destructor is careful to delete local
-   parameterizations only once. Calling `SetParameterization` with
-   `nullptr` will clear any previously set parameterization.
+   Set the :class:`Manifold` for the parameter block. Calling
+   :func:`Problem::SetManifold` with ``nullptr`` will clear any
+   previously set :class:`Manifold` for the parameter block.
 
-.. function:: LocalParameterization* Problem::GetParameterization(const double* values) const
+   Repeated calls will result in any previously associated
+   :class:`Manifold` object to be replaced with ``manifold``.
 
-   Get the local parameterization object associated with this
-   parameter block. If there is no parameterization object associated
-   then `nullptr` is returned
+   ``manifold`` is owned by :class:`Problem` by default (See
+   :class:`Problem::Options` to override this behaviour).
+
+   It is acceptable to set the same :class:`Manifold` for multiple
+   parameter blocks.
+
+.. function:: const Manifold* GetManifold(const double* values) const;
+
+   Get the :class:`Manifold` object associated with this parameter block.
+
+   If there is no :class:`Manifold` object associated with the parameter block,
+   then ``nullptr`` is returned.
+
+.. function:: bool HasManifold(const double* values) const;
+
+   Returns ``true`` if a :class:`Manifold` is associated with this parameter
+   block, ``false`` otherwise.
 
 .. function:: void Problem::SetParameterLowerBound(double* values, int index, double lower_bound)
 
@@ -1909,43 +2228,42 @@
 
    The size of the parameter block.
 
-.. function:: int Problem::ParameterBlockLocalSize(const double* values) const
+.. function:: int Problem::ParameterBlockTangentSize(const double* values) const
 
-   The size of local parameterization for the parameter block. If
-   there is no local parameterization associated with this parameter
-   block, then ``ParameterBlockLocalSize`` = ``ParameterBlockSize``.
+   The dimension of the tangent space of the :class:`Manifold` for the
+   parameter block. If there is no :class:`Manifold` associated with this
+   parameter block, then ``ParameterBlockTangentSize = ParameterBlockSize``.
 
 .. function:: bool Problem::HasParameterBlock(const double* values) const
 
    Is the given parameter block present in the problem or not?
 
-.. function:: void Problem::GetParameterBlocks(vector<double*>* parameter_blocks) const
+.. function:: void Problem::GetParameterBlocks(std::vector<double*>* parameter_blocks) const
 
    Fills the passed ``parameter_blocks`` vector with pointers to the
    parameter blocks currently in the problem. After this call,
    ``parameter_block.size() == NumParameterBlocks``.
 
-.. function:: void Problem::GetResidualBlocks(vector<ResidualBlockId>* residual_blocks) const
+.. function:: void Problem::GetResidualBlocks(std::vector<ResidualBlockId>* residual_blocks) const
 
    Fills the passed `residual_blocks` vector with pointers to the
    residual blocks currently in the problem. After this call,
    `residual_blocks.size() == NumResidualBlocks`.
 
-.. function:: void Problem::GetParameterBlocksForResidualBlock(const ResidualBlockId residual_block, vector<double*>* parameter_blocks) const
+.. function:: void Problem::GetParameterBlocksForResidualBlock(const ResidualBlockId residual_block, std::vector<double*>* parameter_blocks) const
 
    Get all the parameter blocks that depend on the given residual
    block.
 
-.. function:: void Problem::GetResidualBlocksForParameterBlock(const double* values, vector<ResidualBlockId>* residual_blocks) const
+.. function:: void Problem::GetResidualBlocksForParameterBlock(const double* values, std::vector<ResidualBlockId>* residual_blocks) const
 
    Get all the residual blocks that depend on the given parameter
    block.
 
-   If `Problem::Options::enable_fast_removal` is
-   `true`, then getting the residual blocks is fast and depends only
+   If :member:`Problem::Options::enable_fast_removal` is
+   ``true``, then getting the residual blocks is fast and depends only
    on the number of residual blocks. Otherwise, getting the residual
-   blocks for a parameter block will incur a scan of the entire
-   :class:`Problem` object.
+   blocks for a parameter block will scan the entire problem.
 
 .. function:: const CostFunction* Problem::GetCostFunctionForResidualBlock(const ResidualBlockId residual_block) const
 
@@ -1974,11 +2292,10 @@
    function returns false, the caller should expect the output
    memory locations to have been modified.
 
-   The returned cost and jacobians have had robustification and local
-   parameterizations applied already; for example, the jacobian for a
-   4-dimensional quaternion parameter using the
-   :class:`QuaternionParameterization` is ``num_residuals x 3``
-   instead of ``num_residuals x 4``.
+   The returned cost and jacobians have had robustification and
+   :class:`Manifold` applied already; for example, the jacobian for a
+   4-dimensional quaternion parameter using the :class:`QuaternionManifold` is
+   ``num_residuals x 3`` instead of ``num_residuals x 4``.
 
    ``apply_loss_function`` as the name implies allows the user to
    switch the application of the loss function on and off.
@@ -2014,10 +2331,10 @@
     :func:`Problem::EvaluateResidualBlock`).
 
 
-.. function:: bool Problem::Evaluate(const Problem::EvaluateOptions& options, double* cost, vector<double>* residuals, vector<double>* gradient, CRSMatrix* jacobian)
+.. function:: bool Problem::Evaluate(const Problem::EvaluateOptions& options, double* cost, std::vector<double>* residuals, std::vector<double>* gradient, CRSMatrix* jacobian)
 
    Evaluate a :class:`Problem`. Any of the output pointers can be
-   `nullptr`. Which residual blocks and parameter blocks are used is
+   ``nullptr``. Which residual blocks and parameter blocks are used is
    controlled by the :class:`Problem::EvaluateOptions` struct below.
 
    .. NOTE::
@@ -2048,10 +2365,10 @@
 
    .. NOTE::
 
-      If no local parameterizations are used, then the size of
-      the gradient vector is the sum of the sizes of all the parameter
-      blocks. If a parameter block has a local parameterization, then
-      it contributes "LocalSize" entries to the gradient vector.
+      If no :class:`Manifold` are used, then the size of the gradient vector is
+      the sum of the sizes of all the parameter blocks. If a parameter block has
+      a manifold then it contributes "TangentSize" entries to the gradient
+      vector.
 
    .. NOTE::
 
@@ -2070,7 +2387,7 @@
 
    Options struct that is used to control :func:`Problem::Evaluate`.
 
-.. member:: vector<double*> Problem::EvaluateOptions::parameter_blocks
+.. member:: std::vector<double*> Problem::EvaluateOptions::parameter_blocks
 
    The set of parameter blocks for which evaluation should be
    performed. This vector determines the order in which parameter
@@ -2086,7 +2403,7 @@
    should NOT point to new memory locations. Bad things will happen if
    you do.
 
-.. member:: vector<ResidualBlockId> Problem::EvaluateOptions::residual_blocks
+.. member:: std::vector<ResidualBlockId> Problem::EvaluateOptions::residual_blocks
 
    The set of residual blocks for which evaluation should be
    performed. This vector determines the order in which the residuals
@@ -2105,7 +2422,7 @@
 
 .. member:: int Problem::EvaluateOptions::num_threads
 
-   Number of threads to use. (Requires OpenMP).
+   Number of threads to use.
 
 
 :class:`EvaluationCallback`
@@ -2120,9 +2437,9 @@
 
       class EvaluationCallback {
        public:
-        virtual ~EvaluationCallback() {}
-        virtual void PrepareForEvaluation()(bool evaluate_jacobians
-                                            bool new_evaluation_point) = 0;
+        virtual ~EvaluationCallback();
+        virtual void PrepareForEvaluation(bool evaluate_jacobians,
+                                          bool new_evaluation_point) = 0;
       };
 
 .. function:: void EvaluationCallback::PrepareForEvaluation(bool evaluate_jacobians, bool new_evaluation_point)
@@ -2131,14 +2448,14 @@
    every time, and once before it computes the residuals and/or the
    Jacobians.
 
-   User parameters (the double* values provided by the us) are fixed
+   User parameters (the double* values provided by the user) are fixed
    until the next call to
    :func:`EvaluationCallback::PrepareForEvaluation`. If
    ``new_evaluation_point == true``, then this is a new point that is
    different from the last evaluated point. Otherwise, it is the same
    point that was evaluated previously (either Jacobian or residual)
    and the user can use cached results from previous evaluations. If
-   ``evaluate_jacobians`` is true, then Ceres will request Jacobians
+   ``evaluate_jacobians`` is ``true``, then Ceres will request Jacobians
    in the upcoming cost evaluation.
 
    Using this callback interface, Ceres can notify you when it is
@@ -2165,7 +2482,10 @@
    to use a global shared variable (discouraged; bug-prone).  As far
    as Ceres is concerned, it is evaluating cost functions like any
    other; it just so happens that behind the scenes the cost functions
-   reuse pre-computed data to execute faster.
+   reuse pre-computed data to execute faster. See
+   `examples/evaluation_callback_example.cc
+   <https://ceres-solver.googlesource.com/ceres-solver/+/master/examples/evaluation_callback_example.cc>`_
+   for an example.
 
    See ``evaluation_callback_test.cc`` for code that explicitly
    verifies the preconditions between
@@ -2207,14 +2527,14 @@
 .. function:: template <typename T> void RotationMatrixToAngleAxis(T const * R, T * angle_axis)
 .. function:: template <typename T> void AngleAxisToRotationMatrix(T const * angle_axis, T * R)
 
-   Conversions between 3x3 rotation matrix with given column and row strides and
+   Conversions between :math:`3\times3` rotation matrix with given column and row strides and
    axis-angle rotation representations. The functions that take a pointer to T instead
    of a MatrixAdapter assume a column major representation with unit row stride and a column stride of 3.
 
 .. function:: template <typename T, int row_stride, int col_stride> void EulerAnglesToRotationMatrix(const T* euler, const MatrixAdapter<T, row_stride, col_stride>& R)
 .. function:: template <typename T> void EulerAnglesToRotationMatrix(const T* euler, int row_stride, T* R)
 
-   Conversions between 3x3 rotation matrix with given column and row strides and
+   Conversions between :math:`3\times3` rotation matrix with given column and row strides and
    Euler angle (in degrees) rotation representations.
 
    The {pitch,roll,yaw} Euler angles are rotations around the {x,y,z}
@@ -2228,7 +2548,7 @@
 .. function:: template <typename T, int row_stride, int col_stride> void QuaternionToScaledRotation(const T q[4], const MatrixAdapter<T, row_stride, col_stride>& R)
 .. function:: template <typename T> void QuaternionToScaledRotation(const T q[4], T R[3 * 3])
 
-   Convert a 4-vector to a 3x3 scaled rotation matrix.
+   Convert a 4-vector to a :math:`3\times3` scaled rotation matrix.
 
    The choice of rotation is such that the quaternion
    :math:`\begin{bmatrix} 1 &0 &0 &0\end{bmatrix}` goes to an identity
@@ -2242,8 +2562,8 @@
 
    which corresponds to a Rodrigues approximation, the last matrix
    being the cross-product matrix of :math:`\begin{bmatrix} a& b&
-   c\end{bmatrix}`. Together with the property that :math:`R(q1 * q2)
-   = R(q1) * R(q2)` this uniquely defines the mapping from :math:`q` to
+   c\end{bmatrix}`. Together with the property that :math:`R(q_1 \otimes q_2)
+   = R(q_1) R(q_2)` this uniquely defines the mapping from :math:`q` to
    :math:`R`.
 
    In the function that accepts a pointer to T instead of a MatrixAdapter,
@@ -2252,7 +2572,7 @@
 
    No normalization of the quaternion is performed, i.e.
    :math:`R = \|q\|^2  Q`, where :math:`Q` is an orthonormal matrix
-   such that :math:`\det(Q) = 1` and :math:`Q*Q' = I`.
+   such that :math:`\det(Q) = 1` and :math:`QQ' = I`.
 
 
 .. function:: template <typename T> void QuaternionToRotation(const T q[4], const MatrixAdapter<T, row_stride, col_stride>& R)
@@ -2279,9 +2599,9 @@
 
 .. function:: template <typename T> void QuaternionProduct(const T z[4], const T w[4], T zw[4])
 
-   .. math:: zw = z * w
+   .. math:: zw = z \otimes w
 
-   where :math:`*` is the Quaternion product between 4-vectors.
+   where :math:`\otimes` is the Quaternion product between 4-vectors.
 
 
 .. function:: template <typename T> void CrossProduct(const T x[3], const T y[3], T x_cross_y[3])
diff --git a/third_party/ceres/docs/source/nnls_solving.rst b/third_party/ceres/docs/source/nnls_solving.rst
index 285df3a..184b94b 100644
--- a/third_party/ceres/docs/source/nnls_solving.rst
+++ b/third_party/ceres/docs/source/nnls_solving.rst
@@ -1,3 +1,4 @@
+.. highlight:: c++
 
 .. default-domain:: cpp
 
@@ -12,10 +13,10 @@
 Introduction
 ============
 
-Effective use of Ceres requires some familiarity with the basic
+Effective use of Ceres Solver requires some familiarity with the basic
 components of a non-linear least squares solver, so before we describe
 how to configure and use the solver, we will take a brief look at how
-some of the core optimization algorithms in Ceres work.
+some of the core optimization algorithms in Ceres Solver work.
 
 Let :math:`x \in \mathbb{R}^n` be an :math:`n`-dimensional vector of
 variables, and
@@ -27,15 +28,15 @@
           L \le x \le U
   :label: nonlinsq
 
-Where, :math:`L` and :math:`U` are lower and upper bounds on the
-parameter vector :math:`x`.
+Where, :math:`L` and :math:`U` are vector lower and upper bounds on
+the parameter vector :math:`x`. The inequality holds component-wise.
 
 Since the efficient global minimization of :eq:`nonlinsq` for
 general :math:`F(x)` is an intractable problem, we will have to settle
 for finding a local minimum.
 
 In the following, the Jacobian :math:`J(x)` of :math:`F(x)` is an
-:math:`m\times n` matrix, where :math:`J_{ij}(x) = \partial_j f_i(x)`
+:math:`m\times n` matrix, where :math:`J_{ij}(x) = D_j f_i(x)`
 and the gradient vector is :math:`g(x) = \nabla \frac{1}{2}\|F(x)\|^2
 = J(x)^\top F(x)`.
 
@@ -75,7 +76,7 @@
 Trust region methods are in some sense dual to line search methods:
 trust region methods first choose a step size (the size of the trust
 region) and then a step direction while line search methods first
-choose a step direction and then a step size. Ceres implements
+choose a step direction and then a step size. Ceres Solver implements
 multiple algorithms in both categories.
 
 .. _section-trust-region-methods:
@@ -152,8 +153,9 @@
 solving an unconstrained optimization of the form
 
 .. math:: \arg\min_{\Delta x} \frac{1}{2}\|J(x)\Delta x + F(x)\|^2 +\lambda  \|D(x)\Delta x\|^2
+   :label: lsqr-naive
 
-Where, :math:`\lambda` is a Lagrange multiplier that is inverse
+Where, :math:`\lambda` is a Lagrange multiplier that is inversely
 related to :math:`\mu`. In Ceres, we solve for
 
 .. math:: \arg\min_{\Delta x} \frac{1}{2}\|J(x)\Delta x + F(x)\|^2 + \frac{1}{\mu} \|D(x)\Delta x\|^2
@@ -162,39 +164,47 @@
 The matrix :math:`D(x)` is a non-negative diagonal matrix, typically
 the square root of the diagonal of the matrix :math:`J(x)^\top J(x)`.
 
-Before going further, let us make some notational simplifications. We
-will assume that the matrix :math:`\frac{1}{\sqrt{\mu}} D` has been concatenated
-at the bottom of the matrix :math:`J` and similarly a vector of zeros
-has been added to the bottom of the vector :math:`f` and the rest of
-our discussion will be in terms of :math:`J` and :math:`F`, i.e, the
-linear least squares problem.
+Before going further, let us make some notational simplifications.
+
+We will assume that the matrix :math:`\frac{1}{\sqrt{\mu}} D` has been
+concatenated at the bottom of the matrix :math:`J(x)` and a
+corresponding vector of zeroes has been added to the bottom of
+:math:`F(x)`, i.e.:
+
+.. math:: J(x) = \begin{bmatrix} J(x) \\ \frac{1}{\sqrt{\mu}} D
+          \end{bmatrix},\quad F(x) = \begin{bmatrix} F(x) \\ 0
+          \end{bmatrix}.
+
+This allows us to re-write :eq:`lsqr` as
 
 .. math:: \min_{\Delta x} \frac{1}{2} \|J(x)\Delta x + F(x)\|^2 .
    :label: simple
 
-For all but the smallest problems the solution of :eq:`simple` in
-each iteration of the Levenberg-Marquardt algorithm is the dominant
-computational cost in Ceres. Ceres provides a number of different
-options for solving :eq:`simple`. There are two major classes of
-methods - factorization and iterative.
+and only talk about :math:`J(x)` and :math:`F(x)` going forward.
+
+For all but the smallest problems the solution of :eq:`simple` in each
+iteration of the Levenberg-Marquardt algorithm is the dominant
+computational cost. Ceres provides a number of different options for
+solving :eq:`simple`. There are two major classes of methods -
+factorization and iterative.
 
 The factorization methods are based on computing an exact solution of
-:eq:`lsqr` using a Cholesky or a QR factorization and lead to an exact
-step Levenberg-Marquardt algorithm. But it is not clear if an exact
-solution of :eq:`lsqr` is necessary at each step of the LM algorithm
-to solve :eq:`nonlinsq`. In fact, we have already seen evidence
-that this may not be the case, as :eq:`lsqr` is itself a regularized
-version of :eq:`linearapprox`. Indeed, it is possible to
-construct non-linear optimization algorithms in which the linearized
-problem is solved approximately. These algorithms are known as inexact
-Newton or truncated Newton methods [NocedalWright]_.
+:eq:`lsqr` using a Cholesky or a QR factorization and lead to the so
+called exact step Levenberg-Marquardt algorithm. But it is not clear
+if an exact solution of :eq:`lsqr` is necessary at each step of the
+Levenberg-Mardquardt algorithm.  We have already seen evidence that
+this may not be the case, as :eq:`lsqr` is itself a regularized
+version of :eq:`linearapprox`. Indeed, it is possible to construct
+non-linear optimization algorithms in which the linearized problem is
+solved approximately. These algorithms are known as inexact Newton or
+truncated Newton methods [NocedalWright]_.
 
 An inexact Newton method requires two ingredients. First, a cheap
 method for approximately solving systems of linear
 equations. Typically an iterative linear solver like the Conjugate
-Gradients method is used for this
-purpose [NocedalWright]_. Second, a termination rule for
-the iterative solver. A typical termination rule is of the form
+Gradients method is used for this purpose [NocedalWright]_. Second, a
+termination rule for the iterative solver. A typical termination rule
+is of the form
 
 .. math:: \|H(x) \Delta x + g(x)\| \leq \eta_k \|g(x)\|.
    :label: inexact
@@ -212,14 +222,18 @@
 iterative linear solver, the inexact step Levenberg-Marquardt
 algorithm is used.
 
+We will talk more about the various linear solvers that you can use in
+:ref:`section-linear-solver`.
+
 .. _section-dogleg:
 
 Dogleg
 ------
 
 Another strategy for solving the trust region problem :eq:`trp` was
-introduced by M. J. D. Powell. The key idea there is to compute two
-vectors
+introduced by
+`M. J. D. Powell <https://en.wikipedia.org/wiki/Michael_J._D._Powell>`_. The
+key idea there is to compute two vectors
 
 .. math::
 
@@ -253,10 +267,14 @@
 Levenberg-Marquardt solves the linear approximation from scratch with
 a smaller value of :math:`\mu`. Dogleg on the other hand, only needs
 to compute the interpolation between the Gauss-Newton and the Cauchy
-vectors, as neither of them depend on the value of :math:`\mu`.
+vectors, as neither of them depend on the value of :math:`\mu`. As a
+result the Dogleg method only solves one linear system per successful
+step, while Levenberg-Marquardt may need to solve an arbitrary number
+of linear systems before it can make progress [LourakisArgyros]_.
 
-The Dogleg method can only be used with the exact factorization based
-linear solvers.
+A disadvantage of the Dogleg implementation in Ceres Solver is that is
+can only be used with method can only be used with exact factorization
+based linear solvers.
 
 .. _section-inner-iterations:
 
@@ -349,10 +367,10 @@
 enables the non-monotonic trust region algorithm as described by Conn,
 Gould & Toint in [Conn]_.
 
-Even though the value of the objective function may be larger
-than the minimum value encountered over the course of the
-optimization, the final parameters returned to the user are the
-ones corresponding to the minimum cost over all iterations.
+Even though the value of the objective function may be larger than the
+minimum value encountered over the course of the optimization, the
+final parameters returned to the user are the ones corresponding to
+the minimum cost over all iterations.
 
 The option to take non-monotonic steps is available for all trust
 region strategies.
@@ -363,11 +381,13 @@
 Line Search Methods
 ===================
 
-The line search method in Ceres Solver cannot handle bounds
-constraints right now, so it can only be used for solving
-unconstrained problems.
+.. NOTE::
 
-Line search algorithms
+   The line search method in Ceres Solver cannot handle bounds
+   constraints right now, so it can only be used for solving
+   unconstrained problems.
+
+The basic line search algorithm looks something like this:
 
    1. Given an initial point :math:`x`
    2. :math:`\Delta x = -H^{-1}(x) g(x)`
@@ -387,7 +407,7 @@
 direction :math:`\Delta x` and the method used for one dimensional
 optimization along :math:`\Delta x`. The choice of :math:`H(x)` is the
 primary source of computational complexity in these
-methods. Currently, Ceres Solver supports three choices of search
+methods. Currently, Ceres Solver supports four choices of search
 directions, all aimed at large scale problems.
 
 1. ``STEEPEST_DESCENT`` This corresponds to choosing :math:`H(x)` to
@@ -405,8 +425,8 @@
 3. ``BFGS`` A generalization of the Secant method to multiple
    dimensions in which a full, dense approximation to the inverse
    Hessian is maintained and used to compute a quasi-Newton step
-   [NocedalWright]_.  BFGS is currently the best known general
-   quasi-Newton algorithm.
+   [NocedalWright]_.  ``BFGS`` and its limited memory variant ``LBFGS``
+   are currently the best known general quasi-Newton algorithm.
 
 4. ``LBFGS`` A limited memory approximation to the full ``BFGS``
    method in which the last `M` iterations are used to approximate the
@@ -414,26 +434,31 @@
    [ByrdNocedal]_.
 
 Currently Ceres Solver supports both a backtracking and interpolation
-based Armijo line search algorithm, and a sectioning / zoom
-interpolation (strong) Wolfe condition line search algorithm.
-However, note that in order for the assumptions underlying the
-``BFGS`` and ``LBFGS`` methods to be guaranteed to be satisfied the
-Wolfe line search algorithm should be used.
+based `Armijo line search algorithm
+<https://en.wikipedia.org/wiki/Backtracking_line_search>`_ (``ARMIJO``)
+, and a sectioning / zoom interpolation (strong) `Wolfe condition line
+search algorithm <https://en.wikipedia.org/wiki/Wolfe_conditions>`_
+(``WOLFE``).
+
+.. NOTE::
+
+   In order for the assumptions underlying the ``BFGS`` and ``LBFGS``
+   methods to be satisfied the ``WOLFE`` algorithm must be used.
 
 .. _section-linear-solver:
 
-LinearSolver
-============
+Linear Solvers
+==============
 
-Recall that in both of the trust-region methods described above, the
+Observe that for both of the trust-region methods described above, the
 key computational cost is the solution of a linear least squares
 problem of the form
 
-.. math:: \min_{\Delta x} \frac{1}{2} \|J(x)\Delta x + f(x)\|^2 .
+.. math:: \min_{\Delta x} \frac{1}{2} \|J(x)\Delta x + F(x)\|^2 .
    :label: simple2
 
 Let :math:`H(x)= J(x)^\top J(x)` and :math:`g(x) = -J(x)^\top
-f(x)`. For notational convenience let us also drop the dependence on
+F(x)`. For notational convenience let us also drop the dependence on
 :math:`x`. Then it is easy to see that solving :eq:`simple2` is
 equivalent to solving the *normal equations*.
 
@@ -444,31 +469,65 @@
 
 .. _section-qr:
 
-``DENSE_QR``
-------------
+DENSE_QR
+--------
 
 For small problems (a couple of hundred parameters and a few thousand
-residuals) with relatively dense Jacobians, ``DENSE_QR`` is the method
-of choice [Bjorck]_. Let :math:`J = QR` be the QR-decomposition of
-:math:`J`, where :math:`Q` is an orthonormal matrix and :math:`R` is
-an upper triangular matrix [TrefethenBau]_. Then it can be shown that
-the solution to :eq:`normal` is given by
+residuals) with relatively dense Jacobians, QR-decomposition is the
+method of choice [Bjorck]_. Let :math:`J = QR` be the QR-decomposition
+of :math:`J`, where :math:`Q` is an orthonormal matrix and :math:`R`
+is an upper triangular matrix [TrefethenBau]_. Then it can be shown
+that the solution to :eq:`normal` is given by
 
 .. math:: \Delta x^* = -R^{-1}Q^\top f
 
+You can use QR-decomposition by setting
+:member:`Solver::Options::linear_solver_type` to ``DENSE_QR``.
 
-Ceres uses ``Eigen`` 's dense QR factorization routines.
+By default (``Solver::Options::dense_linear_algebra_library_type =
+EIGEN``) Ceres Solver will use `Eigen Householder QR factorization
+<https://eigen.tuxfamily.org/dox-devel/classEigen_1_1HouseholderQR.html>`_
+.
 
-.. _section-cholesky:
+If Ceres Solver has been built with an optimized LAPACK
+implementation, then the user can also choose to use LAPACK's
+`DGEQRF`_ routine by setting
+:member:`Solver::Options::dense_linear_algebra_library_type` to
+``LAPACK``. Depending on the `LAPACK` and the underlying `BLAS`
+implementation this may perform better than using Eigen's Householder
+QR factorization.
 
-``DENSE_NORMAL_CHOLESKY`` & ``SPARSE_NORMAL_CHOLESKY``
-------------------------------------------------------
+.. _DGEQRF: https://netlib.org/lapack/explore-html/df/dc5/group__variants_g_ecomputational_ga3766ea903391b5cf9008132f7440ec7b.html
 
-Large non-linear least square problems are usually sparse. In such
-cases, using a dense QR factorization is inefficient. Let :math:`H =
-R^\top R` be the Cholesky factorization of the normal equations, where
-:math:`R` is an upper triangular matrix, then the solution to
-:eq:`normal` is given by
+
+If an NVIDIA GPU is available and Ceres Solver has been built with
+CUDA support enabled, then the user can also choose to perform the
+QR-decomposition on the GPU by setting
+:member:`Solver::Options::dense_linear_algebra_library_type` to
+``CUDA``. Depending on the GPU this can lead to a substantial
+speedup. Using CUDA only makes sense for moderate to large sized
+problems. This is because to perform the decomposition on the GPU the
+matrix :math:`J` needs to be transferred from the CPU to the GPU and
+this incurs a cost. So unless the speedup from doing the decomposition
+on the GPU is large enough to also account for the time taken to
+transfer the Jacobian to the GPU, using CUDA will not be better than
+just doing the decomposition on the CPU.
+
+.. _section-dense-normal-cholesky:
+
+DENSE_NORMAL_CHOLESKY
+---------------------
+
+It is often the case that the number of rows in the Jacobian :math:`J`
+are much larger than the the number of columns. The complexity of QR
+factorization scales linearly with the number of rows, so beyond a
+certain size it is more efficient to solve :eq:`normal` using a dense
+`Cholesky factorization
+<https://en.wikipedia.org/wiki/Cholesky_decomposition>`_.
+
+Let :math:`H = R^\top R` be the Cholesky factorization of the normal
+equations, where :math:`R` is an upper triangular matrix, then the
+solution to :eq:`normal` is given by
 
 .. math::
 
@@ -479,69 +538,155 @@
 factorization of :math:`H` is the same upper triangular matrix
 :math:`R` in the QR factorization of :math:`J`. Since :math:`Q` is an
 orthonormal matrix, :math:`J=QR` implies that :math:`J^\top J = R^\top
-Q^\top Q R = R^\top R`. There are two variants of Cholesky
-factorization -- sparse and dense.
+Q^\top Q R = R^\top R`.
 
-``DENSE_NORMAL_CHOLESKY``  as the name implies performs a dense
-Cholesky factorization of the normal equations. Ceres uses
-``Eigen`` 's dense LDLT factorization routines.
+Unfortunately, forming the matrix :math:`H = J'J` squares the
+condition number. As a result while the cost of forming :math:`H` and
+computing its Cholesky factorization is lower than computing the
+QR-factorization of :math:`J`, we pay the price in terms of increased
+numerical instability and potential failure of the Cholesky
+factorization for ill-conditioned Jacobians.
 
-``SPARSE_NORMAL_CHOLESKY``, as the name implies performs a sparse
-Cholesky factorization of the normal equations. This leads to
-substantial savings in time and memory for large sparse
-problems. Ceres uses the sparse Cholesky factorization routines in
-Professor Tim Davis' ``SuiteSparse`` or ``CXSparse`` packages [Chen]_
-or the sparse Cholesky factorization algorithm in ``Eigen`` (which
-incidently is a port of the algorithm implemented inside ``CXSparse``)
+You can use dense Cholesky factorization by setting
+:member:`Solver::Options::linear_solver_type` to
+``DENSE_NORMAL_CHOLESKY``.
+
+By default (``Solver::Options::dense_linear_algebra_library_type =
+EIGEN``) Ceres Solver will use `Eigen's LLT factorization`_ routine.
+
+.. _Eigen's LLT Factorization:  https://eigen.tuxfamily.org/dox/classEigen_1_1LLT.html
+
+If Ceres Solver has been built with an optimized LAPACK
+implementation, then the user can also choose to use LAPACK's
+`DPOTRF`_ routine by setting
+:member:`Solver::Options::dense_linear_algebra_library_type` to
+``LAPACK``. Depending on the `LAPACK` and the underlying `BLAS`
+implementation this may perform better than using Eigen's Cholesky
+factorization.
+
+.. _DPOTRF: https://www.netlib.org/lapack/explore-html/d1/d7a/group__double_p_ocomputational_ga2f55f604a6003d03b5cd4a0adcfb74d6.html
+
+If an NVIDIA GPU is available and Ceres Solver has been built with
+CUDA support enabled, then the user can also choose to perform the
+Cholesky factorization on the GPU by setting
+:member:`Solver::Options::dense_linear_algebra_library_type` to
+``CUDA``. Depending on the GPU this can lead to a substantial speedup.
+Using CUDA only makes sense for moderate to large sized problems. This
+is because to perform the decomposition on the GPU the matrix
+:math:`H` needs to be transferred from the CPU to the GPU and this
+incurs a cost. So unless the speedup from doing the decomposition on
+the GPU is large enough to also account for the time taken to transfer
+the Jacobian to the GPU, using CUDA will not be better than just doing
+the decomposition on the CPU.
+
+
+.. _section-sparse-normal-cholesky:
+
+SPARSE_NORMAL_CHOLESKY
+----------------------
+
+Large non-linear least square problems are usually sparse. In such
+cases, using a dense QR or Cholesky factorization is inefficient. For
+such problems, Cholesky factorization routines which treat :math:`H`
+as a sparse matrix and computes a sparse factor :math:`R` are better
+suited [Davis]_. This can lead to substantial savings in memory and
+CPU time for large sparse problems.
+
+You can use dense Cholesky factorization by setting
+:member:`Solver::Options::linear_solver_type` to
+``SPARSE_NORMAL_CHOLESKY``.
+
+The use of this linear solver requires that Ceres is compiled with
+support for at least one of:
+
+ 1. `SuiteSparse <https://people.engr.tamu.edu/davis/suitesparse.html>`_ (``SUITE_SPARSE``).
+ 2. `Apple's Accelerate framework
+    <https://developer.apple.com/documentation/accelerate/sparse_solvers?language=objc>`_
+    (``ACCELERATE_SPARSE``).
+ 3. `Eigen's sparse linear solvers
+    <https://eigen.tuxfamily.org/dox/group__SparseCholesky__Module.html>`_
+    (``EIGEN_SPARSE``).
+
+SuiteSparse and Accelerate offer high performance sparse Cholesky
+factorization routines as they level-3 BLAS routines
+internally. Eigen's sparse Cholesky routines are *simplicial* and do
+not use dense linear algebra routines and as a result cannot compete
+with SuiteSparse and Accelerate, especially on large problems. As a
+result to get the best performance out of SuiteSparse it should be
+linked to high quality BLAS and LAPACK implementations e.g. `ATLAS
+<https://math-atlas.sourceforge.net/>`_, `OpenBLAS
+<https://www.openblas.net/>`_ or `Intel MKL
+<https://www.intel.com/content/www/us/en/developer/tools/oneapi/onemkl.html>`_.
+
+A critical part of a sparse Cholesky factorization routine is the use
+a fill-reducing ordering. By default Ceres Solver uses the Approximate
+Minimum Degree (``AMD``) ordering, which usually performs well, but
+there are other options that may perform better depending on the
+actual sparsity structure of the Jacobian. See :ref:`section-ordering`
+for more details.
 
 .. _section-cgnr:
 
-``CGNR``
---------
+CGNR
+----
 
-For general sparse problems, if the problem is too large for
-``CHOLMOD`` or a sparse linear algebra library is not linked into
-Ceres, another option is the ``CGNR`` solver. This solver uses the
-Conjugate Gradients solver on the *normal equations*, but without
-forming the normal equations explicitly. It exploits the relation
+For general sparse problems, if the problem is too large for sparse
+Cholesky factorization or a sparse linear algebra library is not
+linked into Ceres, another option is the ``CGNR`` solver. This solver
+uses the `Conjugate Gradients
+<https://en.wikipedia.org/wiki/Conjugate_gradient_method>_` method on
+the *normal equations*, but without forming the normal equations
+explicitly. It exploits the relation
 
 .. math::
     H x = J^\top J x = J^\top(J x)
 
-The convergence of Conjugate Gradients depends on the conditioner
-number :math:`\kappa(H)`. Usually :math:`H` is poorly conditioned and
-a :ref:`section-preconditioner` must be used to get reasonable
-performance. Currently only the ``JACOBI`` preconditioner is available
-for use with ``CGNR``. It uses the block diagonal of :math:`H` to
-precondition the normal equations.
+Because ``CGNR`` never solves the linear system exactly, when the user
+chooses ``CGNR`` as the linear solver, Ceres automatically switches
+from the exact step algorithm to an inexact step algorithm. This also
+means that ``CGNR`` can only be used with ``LEVENBERG_MARQUARDT`` and
+not with ``DOGLEG`` trust region strategy.
 
-When the user chooses ``CGNR`` as the linear solver, Ceres
-automatically switches from the exact step algorithm to an inexact
-step algorithm.
+``CGNR`` by default runs on the CPU. However, if an NVIDIA GPU is
+available and Ceres Solver has been built with CUDA support enabled,
+then the user can also choose to run ``CGNR`` on the GPU by setting
+:member:`Solver::Options::sparse_linear_algebra_library_type` to
+``CUDA_SPARSE``. The key complexity of ``CGNR`` comes from evaluating
+the two sparse-matrix vector products (SpMV) :math:`Jx` and
+:math:`J'y`. GPUs are particularly well suited for doing sparse
+matrix-vector products. As a result, for large problems using a GPU
+can lead to a substantial speedup.
+
+The convergence of Conjugate Gradients depends on the conditioner
+number :math:`\kappa(H)`. Usually :math:`H` is quite poorly
+conditioned and a `Preconditioner
+<https://en.wikipedia.org/wiki/Preconditioner>`_ must be used to get
+reasonable performance. See section on :ref:`section-preconditioner`
+for more details.
 
 .. _section-schur:
 
-``DENSE_SCHUR`` & ``SPARSE_SCHUR``
-----------------------------------
+DENSE_SCHUR & SPARSE_SCHUR
+--------------------------
 
 While it is possible to use ``SPARSE_NORMAL_CHOLESKY`` to solve bundle
-adjustment problems, bundle adjustment problem have a special
-structure, and a more efficient scheme for solving :eq:`normal`
-can be constructed.
+adjustment problems, they have a special sparsity structure that can
+be exploited to solve the normal equations more efficiently.
 
-Suppose that the SfM problem consists of :math:`p` cameras and
-:math:`q` points and the variable vector :math:`x` has the block
-structure :math:`x = [y_{1}, ... ,y_{p},z_{1}, ... ,z_{q}]`. Where,
-:math:`y` and :math:`z` correspond to camera and point parameters,
-respectively.  Further, let the camera blocks be of size :math:`c` and
-the point blocks be of size :math:`s` (for most problems :math:`c` =
-:math:`6`--`9` and :math:`s = 3`). Ceres does not impose any constancy
-requirement on these block sizes, but choosing them to be constant
-simplifies the exposition.
+Suppose that the bundle adjustment problem consists of :math:`p`
+cameras and :math:`q` points and the variable vector :math:`x` has the
+block structure :math:`x = [y_{1}, ... ,y_{p},z_{1},
+... ,z_{q}]`. Where, :math:`y` and :math:`z` correspond to camera and
+point parameters respectively.  Further, let the camera blocks be of
+size :math:`c` and the point blocks be of size :math:`s` (for most
+problems :math:`c` = :math:`6`--`9` and :math:`s = 3`). Ceres does not
+impose any constancy requirement on these block sizes, but choosing
+them to be constant simplifies the exposition.
 
-A key characteristic of the bundle adjustment problem is that there is
-no term :math:`f_{i}` that includes two or more point blocks.  This in
-turn implies that the matrix :math:`H` is of the form
+The key property of bundle adjustment problems which we will exploit
+is the fact that no term :math:`f_{i}` in :eq:`nonlinsq` includes two
+or more point blocks at the same time.  This in turn implies that the
+matrix :math:`H` is of the form
 
 .. math:: H = \left[ \begin{matrix} B & E\\ E^\top & C \end{matrix} \right]\ ,
    :label: hblock
@@ -585,123 +730,208 @@
 observe at least one common point.
 
 
-Now, :eq:`linear2` can be solved by first forming :math:`S`, solving for
-:math:`\Delta y`, and then back-substituting :math:`\Delta y` to
+Now :eq:`linear2` can be solved by first forming :math:`S`, solving
+for :math:`\Delta y`, and then back-substituting :math:`\Delta y` to
 obtain the value of :math:`\Delta z`.  Thus, the solution of what was
 an :math:`n\times n`, :math:`n=pc+qs` linear system is reduced to the
 inversion of the block diagonal matrix :math:`C`, a few matrix-matrix
 and matrix-vector multiplies, and the solution of block sparse
 :math:`pc\times pc` linear system :eq:`schur`.  For almost all
 problems, the number of cameras is much smaller than the number of
-points, :math:`p \ll q`, thus solving :eq:`schur` is
-significantly cheaper than solving :eq:`linear2`. This is the
-*Schur complement trick* [Brown]_.
+points, :math:`p \ll q`, thus solving :eq:`schur` is significantly
+cheaper than solving :eq:`linear2`. This is the *Schur complement
+trick* [Brown]_.
 
-This still leaves open the question of solving :eq:`schur`. The
-method of choice for solving symmetric positive definite systems
-exactly is via the Cholesky factorization [TrefethenBau]_ and
-depending upon the structure of the matrix, there are, in general, two
-options. The first is direct factorization, where we store and factor
-:math:`S` as a dense matrix [TrefethenBau]_. This method has
+This still leaves open the question of solving :eq:`schur`. As we
+discussed when considering the exact solution of the normal equations
+using Cholesky factorization, we have two options.
+
+1. ``DENSE_SCHUR`` - The first is **dense Cholesky factorization**,
+where we store and factor :math:`S` as a dense matrix. This method has
 :math:`O(p^2)` space complexity and :math:`O(p^3)` time complexity and
-is only practical for problems with up to a few hundred cameras. Ceres
-implements this strategy as the ``DENSE_SCHUR`` solver.
+is only practical for problems with up to a few hundred cameras.
 
-
-But, :math:`S` is typically a fairly sparse matrix, as most images
-only see a small fraction of the scene. This leads us to the second
-option: Sparse Direct Methods. These methods store :math:`S` as a
+2. ``SPARSE_SCHUR`` - For large bundle adjustment problems :math:`S`
+is typically a fairly sparse matrix, as most images only see a small
+fraction of the scene. This leads us to the second option: **sparse
+Cholesky factorization** [Davis]_.  Here we store :math:`S` as a
 sparse matrix, use row and column re-ordering algorithms to maximize
 the sparsity of the Cholesky decomposition, and focus their compute
-effort on the non-zero part of the factorization [Chen]_. Sparse
-direct methods, depending on the exact sparsity structure of the Schur
-complement, allow bundle adjustment algorithms to significantly scale
-up over those based on dense factorization. Ceres implements this
-strategy as the ``SPARSE_SCHUR`` solver.
+effort on the non-zero part of the factorization [Davis]_ [Chen]_
+. Sparse direct methods, depending on the exact sparsity structure of
+the Schur complement, allow bundle adjustment algorithms to scenes
+with thousands of cameras.
+
 
 .. _section-iterative_schur:
 
-``ITERATIVE_SCHUR``
--------------------
+ITERATIVE_SCHUR
+---------------
 
-Another option for bundle adjustment problems is to apply
-Preconditioned Conjugate Gradients to the reduced camera matrix
-:math:`S` instead of :math:`H`. One reason to do this is that
-:math:`S` is a much smaller matrix than :math:`H`, but more
-importantly, it can be shown that :math:`\kappa(S)\leq \kappa(H)`.
+Another option for bundle adjustment problems is to apply Conjugate
+Gradients to the reduced camera matrix :math:`S` instead of
+:math:`H`. One reason to do this is that :math:`S` is a much smaller
+matrix than :math:`H`, but more importantly, it can be shown that
+:math:`\kappa(S)\leq \kappa(H)` [Agarwal]_.
+
 Ceres implements Conjugate Gradients on :math:`S` as the
 ``ITERATIVE_SCHUR`` solver. When the user chooses ``ITERATIVE_SCHUR``
 as the linear solver, Ceres automatically switches from the exact step
 algorithm to an inexact step algorithm.
 
+
 The key computational operation when using Conjuagate Gradients is the
 evaluation of the matrix vector product :math:`Sx` for an arbitrary
-vector :math:`x`. There are two ways in which this product can be
-evaluated, and this can be controlled using
-``Solver::Options::use_explicit_schur_complement``. Depending on the
-problem at hand, the performance difference between these two methods
-can be quite substantial.
+vector :math:`x`. Because PCG only needs access to :math:`S` via its
+product with a vector, one way to evaluate :math:`Sx` is to observe
+that
 
-  1. **Implicit** This is default. Implicit evaluation is suitable for
-     large problems where the cost of computing and storing the Schur
-     Complement :math:`S` is prohibitive. Because PCG only needs
-     access to :math:`S` via its product with a vector, one way to
-     evaluate :math:`Sx` is to observe that
+.. math::  x_1 &= E^\top x\\
+           x_2 &= C^{-1} x_1\\
+           x_3 &= Ex_2\\
+           x_4 &= Bx\\
+           Sx &= x_4 - x_3
+   :label: schurtrick1
 
-     .. math::  x_1 &= E^\top x\\
-                x_2 &= C^{-1} x_1\\
-                x_3 &= Ex_2\\
-                x_4 &= Bx\\
-                Sx &= x_4 - x_3
-        :label: schurtrick1
+Thus, we can run Conjugate Gradients on :math:`S` with the same
+computational effort per iteration as Conjugate Gradients on
+:math:`H`, while reaping the benefits of a more powerful
+preconditioner. In fact, we do not even need to compute :math:`H`,
+:eq:`schurtrick1` can be implemented using just the columns of
+:math:`J`.
 
-     Thus, we can run PCG on :math:`S` with the same computational
-     effort per iteration as PCG on :math:`H`, while reaping the
-     benefits of a more powerful preconditioner. In fact, we do not
-     even need to compute :math:`H`, :eq:`schurtrick1` can be
-     implemented using just the columns of :math:`J`.
+Equation :eq:`schurtrick1` is closely related to *Domain Decomposition
+methods* for solving large linear systems that arise in structural
+engineering and partial differential equations. In the language of
+Domain Decomposition, each point in a bundle adjustment problem is a
+domain, and the cameras form the interface between these domains. The
+iterative solution of the Schur complement then falls within the
+sub-category of techniques known as Iterative Sub-structuring [Saad]_
+[Mathew]_.
 
-     Equation :eq:`schurtrick1` is closely related to *Domain
-     Decomposition methods* for solving large linear systems that
-     arise in structural engineering and partial differential
-     equations. In the language of Domain Decomposition, each point in
-     a bundle adjustment problem is a domain, and the cameras form the
-     interface between these domains. The iterative solution of the
-     Schur complement then falls within the sub-category of techniques
-     known as Iterative Sub-structuring [Saad]_ [Mathew]_.
+While in most cases the above method for evaluating :math:`Sx` is the
+way to go, for some problems it is better to compute the Schur
+complemenent :math:`S` explicitly and then run Conjugate Gradients on
+it. This can be done by settin
+``Solver::Options::use_explicit_schur_complement`` to ``true``. This
+option can only be used with the ``SCHUR_JACOBI`` preconditioner.
 
-  2. **Explicit** The complexity of implicit matrix-vector product
-     evaluation scales with the number of non-zeros in the
-     Jacobian. For small to medium sized problems, the cost of
-     constructing the Schur Complement is small enough that it is
-     better to construct it explicitly in memory and use it to
-     evaluate the product :math:`Sx`.
 
-When the user chooses ``ITERATIVE_SCHUR`` as the linear solver, Ceres
-automatically switches from the exact step algorithm to an inexact
-step algorithm.
+.. _section-schur_power_series_expansion:
 
-  .. NOTE::
+SCHUR_POWER_SERIES_EXPANSION
+----------------------------
 
-     In exact arithmetic, the choice of implicit versus explicit Schur
-     complement would have no impact on solution quality. However, in
-     practice if the Jacobian is poorly conditioned, one may observe
-     (usually small) differences in solution quality. This is a
-     natural consequence of performing computations in finite arithmetic.
+It can be shown that the inverse of the Schur complement can be
+written as an infinite power-series [Weber]_ [Zheng]_:
 
+.. math:: S      &= B - EC^{-1}E^\top\\
+	         &= B(I - B^{-1}EC^{-1}E^\top)\\
+	  S^{-1} &= (I - B^{-1}EC^{-1}E^\top)^{-1} B^{-1}\\
+	         & = \sum_{i=0}^\infty \left(B^{-1}EC^{-1}E^\top\right)^{i} B^{-1}
+
+As a result a truncated version of this power series expansion can be
+used to approximate the inverse and therefore the solution to
+:eq:`schur`. Ceres allows the user to use Schur power series expansion
+in three ways.
+
+1. As a linear solver. This is what [Weber]_ calls **Power Bundle
+   Adjustment** and corresponds to using the truncated power series to
+   approximate the inverse of the Schur complement. This is done by
+   setting the following options.
+
+   .. code-block:: c++
+
+      Solver::Options::linear_solver_type = ITERATIVE_SCHUR
+      Solver::Options::preconditioner_type = IDENTITY
+      Solver::Options::use_spse_initialization = true
+      Solver::Options::max_linear_solver_iterations = 0;
+
+      // The following two settings are worth tuning for your application.
+      Solver::Options::max_num_spse_iterations = 5;
+      Solver::Options::spse_tolerance = 0.1;
+
+
+2. As a preconditioner for ``ITERATIVE_SCHUR``. Any method for
+   approximating the inverse of a matrix can also be used as a
+   preconditioner. This is enabled by setting the following options.
+
+   .. code-block:: c++
+
+      Solver::Options::linear_solver_type = ITERATIVE_SCHUR
+      Solver::Options::preconditioner_type = SCHUR_POWER_SERIES_EXPANSION;
+      Solver::Options::use_spse_initialization = false;
+
+      // This is worth tuning for your application.
+      Solver::Options::max_num_spse_iterations = 5;
+
+
+3. As initialization for ``ITERATIIVE_SCHUR`` with any
+   preconditioner. This is a combination of the above two, where the
+   Schur Power Series Expansion
+
+   .. code-block:: c++
+
+      Solver::Options::linear_solver_type = ITERATIVE_SCHUR
+      Solver::Options::preconditioner_type = ... // Preconditioner of your choice.
+      Solver::Options::use_spse_initialization = true
+      Solver::Options::max_linear_solver_iterations = 0;
+
+      // The following two settings are worth tuning for your application.
+      Solver::Options::max_num_spse_iterations = 5;
+      // This only affects the initialization but not the preconditioner.
+      Solver::Options::spse_tolerance = 0.1;
+
+
+.. _section-mixed-precision:
+
+Mixed Precision Solves
+======================
+
+Generally speaking Ceres Solver does all its arithmetic in double
+precision. Sometimes though, one can use single precision arithmetic
+to get substantial speedups. Currently, for linear solvers that
+perform Cholesky factorization (sparse or dense) the user has the
+option cast the linear system to single precision and then use
+single precision Cholesky factorization routines to solve the
+resulting linear system. This can be enabled by setting
+:member:`Solver::Options::use_mixed_precision_solves` to ``true``.
+
+Depending on the conditioning of the problem, the use of single
+precision factorization may lead to some loss of accuracy. Some of
+this accuracy can be recovered by performing `Iterative Refinement
+<https://en.wikipedia.org/wiki/Iterative_refinement>`_. The number of
+iterations of iterative refinement are controlled by
+:member:`Solver::Options::max_num_refinement_iterations`. The default
+value of this parameter is zero, which means if
+:member:`Solver::Options::use_mixed_precision_solves` is ``true``,
+then no iterative refinement is performed. Usually 2-3 refinement
+iterations are enough.
+
+Mixed precision solves are available in the following linear solver
+configurations:
+
+1. ``DENSE_NORMAL_CHOLESKY`` + ``EIGEN``/ ``LAPACK`` / ``CUDA``.
+2. ``DENSE_SCHUR`` + ``EIGEN``/ ``LAPACK`` / ``CUDA``.
+3. ``SPARSE_NORMAL_CHOLESKY`` + ``EIGEN_SPARSE`` / ``ACCELERATE_SPARSE``
+4. ``SPARSE_SCHUR`` + ``EIGEN_SPARSE`` / ``ACCELERATE_SPARSE``
+
+Mixed precision solves area not available when using ``SUITE_SPARSE``
+as the sparse linear algebra backend because SuiteSparse/CHOLMOD does
+not support single precision solves.
 
 .. _section-preconditioner:
 
-Preconditioner
-==============
+Preconditioners
+===============
 
-The convergence rate of Conjugate Gradients for
-solving :eq:`normal` depends on the distribution of eigenvalues
-of :math:`H` [Saad]_. A useful upper bound is
-:math:`\sqrt{\kappa(H)}`, where, :math:`\kappa(H)` is the condition
-number of the matrix :math:`H`. For most bundle adjustment problems,
-:math:`\kappa(H)` is high and a direct application of Conjugate
-Gradients to :eq:`normal` results in extremely poor performance.
+The convergence rate of Conjugate Gradients for solving :eq:`normal`
+depends on the distribution of eigenvalues of :math:`H` [Saad]_. A
+useful upper bound is :math:`\sqrt{\kappa(H)}`, where,
+:math:`\kappa(H)` is the condition number of the matrix :math:`H`. For
+most non-linear least squares problems, :math:`\kappa(H)` is high and
+a direct application of Conjugate Gradients to :eq:`normal` results in
+extremely poor performance.
 
 The solution to this problem is to replace :eq:`normal` with a
 *preconditioned* system.  Given a linear system, :math:`Ax =b` and a
@@ -733,8 +963,15 @@
 problems with general sparsity as well as the special sparsity
 structure encountered in bundle adjustment problems.
 
-``JACOBI``
-----------
+IDENTITY
+--------
+
+This is equivalent to using an identity matrix as a preconditioner,
+i.e. no preconditioner at all.
+
+
+JACOBI
+------
 
 The simplest of all preconditioners is the diagonal or Jacobi
 preconditioner, i.e., :math:`M=\operatorname{diag}(A)`, which for
@@ -742,24 +979,27 @@
 block Jacobi preconditioner. The ``JACOBI`` preconditioner in Ceres
 when used with :ref:`section-cgnr` refers to the block diagonal of
 :math:`H` and when used with :ref:`section-iterative_schur` refers to
-the block diagonal of :math:`B` [Mandel]_. For detailed performance
-data about the performance of ``JACOBI`` on bundle adjustment problems
-see [Agarwal]_.
+the block diagonal of :math:`B` [Mandel]_.
+
+For detailed performance data about the performance of ``JACOBI`` on
+bundle adjustment problems see [Agarwal]_.
 
 
-``SCHUR_JACOBI``
-----------------
+SCHUR_JACOBI
+------------
 
 Another obvious choice for :ref:`section-iterative_schur` is the block
 diagonal of the Schur complement matrix :math:`S`, i.e, the block
 Jacobi preconditioner for :math:`S`. In Ceres we refer to it as the
-``SCHUR_JACOBI`` preconditioner.  For detailed performance data about
-the performance of ``SCHUR_JACOBI`` on bundle adjustment problems see
-[Agarwal]_.
+``SCHUR_JACOBI`` preconditioner.
 
 
-``CLUSTER_JACOBI`` and ``CLUSTER_TRIDIAGONAL``
-----------------------------------------------
+For detailed performance data about the performance of
+``SCHUR_JACOBI`` on bundle adjustment problems see [Agarwal]_.
+
+
+CLUSTER_JACOBI and CLUSTER_TRIDIAGONAL
+--------------------------------------
 
 For bundle adjustment problems arising in reconstruction from
 community photo collections, more effective preconditioners can be
@@ -790,8 +1030,19 @@
 algorithm. The choice of clustering algorithm is controlled by
 :member:`Solver::Options::visibility_clustering_type`.
 
-``SUBSET``
-----------
+SCHUR_POWER_SERIES_EXPANSION
+----------------------------
+
+As explained in :ref:`section-schur_power_series_expansion`, the Schur
+complement matrix admits a power series expansion and a truncated
+version of this power series can be used as a preconditioner for
+``ITERATIVE_SCHUR``. When used as a preconditioner
+:member:`Solver::Options::max_num_spse_iterations` controls the number
+of terms in the power series that are used.
+
+
+SUBSET
+------
 
 This is a  preconditioner for problems with general  sparsity. Given a
 subset  of residual  blocks of  a problem,  it uses  the corresponding
@@ -811,6 +1062,8 @@
 :math:`Q` approximates :math:`J^\top J`, or how well the chosen
 residual blocks approximate the full problem.
 
+This preconditioner is NOT available when running ``CGNR`` using
+``CUDA``.
 
 .. _section-ordering:
 
@@ -821,33 +1074,36 @@
 have a significant of impact on the efficiency and accuracy of the
 method. For example when doing sparse Cholesky factorization, there
 are matrices for which a good ordering will give a Cholesky factor
-with :math:`O(n)` storage, where as a bad ordering will result in an
+with :math:`O(n)` storage, whereas a bad ordering will result in an
 completely dense factor.
 
 Ceres allows the user to provide varying amounts of hints to the
 solver about the variable elimination ordering to use. This can range
-from no hints, where the solver is free to decide the best ordering
-based on the user's choices like the linear solver being used, to an
-exact order in which the variables should be eliminated, and a variety
-of possibilities in between.
+from no hints, where the solver is free to decide the best possible
+ordering based on the user's choices like the linear solver being
+used, to an exact order in which the variables should be eliminated,
+and a variety of possibilities in between.
 
-Instances of the :class:`ParameterBlockOrdering` class are used to
-communicate this information to Ceres.
+The simplest thing to do is to just set
+:member:`Solver::Options::linear_solver_ordering_type` to ``AMD``
+(default) or ``NESDIS`` based on your understanding of the problem or
+empirical testing.
 
-Formally an ordering is an ordered partitioning of the parameter
-blocks. Each parameter block belongs to exactly one group, and each
-group has a unique integer associated with it, that determines its
-order in the set of groups. We call these groups *Elimination Groups*
 
-Given such an ordering, Ceres ensures that the parameter blocks in the
-lowest numbered elimination group are eliminated first, and then the
-parameter blocks in the next lowest numbered elimination group and so
-on. Within each elimination group, Ceres is free to order the
-parameter blocks as it chooses. For example, consider the linear system
+More information can be commmuniucated by using an instance
+:class:`ParameterBlockOrdering` class.
+
+Formally an ordering is an ordered partitioning of the
+parameter blocks, i.e, each parameter block belongs to exactly
+one group, and each group has a unique non-negative integer
+associated with it, that determines its order in the set of
+groups.
+
+e.g. Consider the linear system
 
 .. math::
-  x + y &= 3\\
-  2x + 3y &= 7
+   x + y &= 3 \\
+   2x + 3y &= 7
 
 There are two ways in which it can be solved. First eliminating
 :math:`x` from the two equations, solving for :math:`y` and then back
@@ -855,33 +1111,92 @@
 for :math:`x` and back substituting for :math:`y`. The user can
 construct three orderings here.
 
-1. :math:`\{0: x\}, \{1: y\}` : Eliminate :math:`x` first.
-2. :math:`\{0: y\}, \{1: x\}` : Eliminate :math:`y` first.
-3. :math:`\{0: x, y\}`        : Solver gets to decide the elimination order.
+1. :math:`\{0: x\}, \{1: y\}` - eliminate :math:`x` first.
+2. :math:`\{0: y\}, \{1: x\}` - eliminate :math:`y` first.
+3. :math:`\{0: x, y\}` - Solver gets to decide the elimination order.
 
-Thus, to have Ceres determine the ordering automatically using
-heuristics, put all the variables in the same elimination group. The
-identity of the group does not matter. This is the same as not
-specifying an ordering at all. To control the ordering for every
-variable, create an elimination group per variable, ordering them in
-the desired order.
+Thus, to have Ceres determine the ordering automatically, put all the
+variables in group 0 and to control the ordering for every variable,
+create groups :math:`0 \dots N-1`, one per variable, in the desired
+order.
+
+``linear_solver_ordering == nullptr`` and an ordering where all the
+parameter blocks are in one elimination group mean the same thing -
+the solver is free to choose what it thinks is the best elimination
+ordering using the ordering algorithm (specified using
+:member:`Solver::Options::linear_solver_ordering_type`). Therefore in
+the following we will only consider the case where
+``linear_solver_ordering != nullptr``.
+
+The exact interpretation of the ``linear_solver_ordering`` depends on
+the values of :member:`Solver::Options::linear_solver_ordering_type`,
+:member:`Solver::Options::linear_solver_type`,
+:member:`Solver::Options::preconditioner_type` and
+:member:`Solver::Options::sparse_linear_algebra_library_type` as we will
+explain below.
+
+Bundle Adjustment
+-----------------
 
 If the user is using one of the Schur solvers (``DENSE_SCHUR``,
 ``SPARSE_SCHUR``, ``ITERATIVE_SCHUR``) and chooses to specify an
 ordering, it must have one important property. The lowest numbered
 elimination group must form an independent set in the graph
 corresponding to the Hessian, or in other words, no two parameter
-blocks in in the first elimination group should co-occur in the same
+blocks in the first elimination group should co-occur in the same
 residual block. For the best performance, this elimination group
 should be as large as possible. For standard bundle adjustment
 problems, this corresponds to the first elimination group containing
-all the 3d points, and the second containing the all the cameras
-parameter blocks.
+all the 3d points, and the second containing the parameter blocks for
+all the cameras.
 
 If the user leaves the choice to Ceres, then the solver uses an
 approximate maximum independent set algorithm to identify the first
 elimination group [LiSaad]_.
 
+``sparse_linear_algebra_library_type = SUITE_SPARSE``
+-----------------------------------------------------
+
+**linear_solver_ordering_type = AMD**
+
+A constrained Approximate Minimum Degree (CAMD) ordering is used where
+the parameter blocks in the lowest numbered group are eliminated
+first, and then the parameter blocks in the next lowest numbered group
+and so on. Within each group, CAMD is free to order the parameter blocks
+as it chooses.
+
+**linear_solver_ordering_type = NESDIS**
+
+a. ``linear_solver_type = SPARSE_NORMAL_CHOLESKY`` or
+   ``linear_solver_type = CGNR`` and ``preconditioner_type = SUBSET``
+
+   The value of ``linear_solver_ordering`` is ignored and a Nested
+   Dissection algorithm is used to compute a fill reducing ordering.
+
+b. ``linear_solver_type = SPARSE_SCHUR/DENSE_SCHUR/ITERATIVE_SCHUR``
+
+   ONLY the lowest group are used to compute the Schur complement, and
+   Nested Dissection is used to compute a fill reducing ordering for
+   the Schur Complement (or its preconditioner).
+
+``sparse_linear_algebra_library_type = EIGEN_SPARSE/ACCELERATE_SPARSE``
+-----------------------------------------------------------------------
+
+a. ``linear_solver_type = SPARSE_NORMAL_CHOLESKY`` or
+   ``linear_solver_type = CGNR`` and ``preconditioner_type = SUBSET``
+
+   The value of ``linear_solver_ordering`` is ignored and ``AMD`` or
+   ``NESDIS`` is used to compute a fill reducing ordering as requested
+   by the user.
+
+b. ``linear_solver_type = SPARSE_SCHUR/DENSE_SCHUR/ITERATIVE_SCHUR``
+
+   ONLY the lowest group are used to compute the Schur complement, and
+   ``AMD`` or ``NESID`` is used to compute a fill reducing ordering
+   for the Schur Complement (or its preconditioner) as requested by
+   the user.
+
+
 .. _section-solver-options:
 
 :class:`Solver::Options`
@@ -892,7 +1207,7 @@
    :class:`Solver::Options` controls the overall behavior of the
    solver. We list the various settings and their default values below.
 
-.. function:: bool Solver::Options::IsValid(string* error) const
+.. function:: bool Solver::Options::IsValid(std::string* error) const
 
    Validate the values in the options struct and returns true on
    success. If there is a problem, the method returns false with
@@ -913,14 +1228,18 @@
    Choices are ``STEEPEST_DESCENT``, ``NONLINEAR_CONJUGATE_GRADIENT``,
    ``BFGS`` and ``LBFGS``.
 
+   See :ref:`section-line-search-methods` for more details.
+
 .. member:: LineSearchType Solver::Options::line_search_type
 
    Default: ``WOLFE``
 
    Choices are ``ARMIJO`` and ``WOLFE`` (strong Wolfe conditions).
    Note that in order for the assumptions underlying the ``BFGS`` and
-   ``LBFGS`` line search direction algorithms to be guaranteed to be
-   satisifed, the ``WOLFE`` line search should be used.
+   ``LBFGS`` line search direction algorithms to be satisfied, the
+   ``WOLFE`` line search must be used.
+
+   See :ref:`section-line-search-methods` for more details.
 
 .. member:: NonlinearConjugateGradientType Solver::Options::nonlinear_conjugate_gradient_type
 
@@ -931,26 +1250,28 @@
 
 .. member:: int Solver::Options::max_lbfgs_rank
 
-   Default: 20
+   Default: ``20``
 
-   The L-BFGS hessian approximation is a low rank approximation to the
-   inverse of the Hessian matrix. The rank of the approximation
-   determines (linearly) the space and time complexity of using the
-   approximation. Higher the rank, the better is the quality of the
-   approximation. The increase in quality is however is bounded for a
-   number of reasons.
+   The LBFGS hessian approximation is a low rank approximation to
+   the inverse of the Hessian matrix. The rank of the
+   approximation determines (linearly) the space and time
+   complexity of using the approximation. Higher the rank, the
+   better is the quality of the approximation. The increase in
+   quality is however is bounded for a number of reasons.
 
-     1. The method only uses secant information and not actual
-        derivatives.
+   1. The method only uses secant information and not actual
+   derivatives.
+   2. The Hessian approximation is constrained to be positive
+   definite.
 
-     2. The Hessian approximation is constrained to be positive
-        definite.
+   So increasing this rank to a large number will cost time and
+   space complexity without the corresponding increase in solution
+   quality. There are no hard and fast rules for choosing the
+   maximum rank. The best choice usually requires some problem
+   specific experimentation.
 
-   So increasing this rank to a large number will cost time and space
-   complexity without the corresponding increase in solution
-   quality. There are no hard and fast rules for choosing the maximum
-   rank. The best choice usually requires some problem specific
-   experimentation.
+   For more theoretical and implementation details of the LBFGS
+   method, please see [Nocedal]_.
 
 .. member:: bool Solver::Options::use_approximate_eigenvalue_bfgs_scaling
 
@@ -999,6 +1320,8 @@
 
 .. member:: double Solver::Options::min_line_search_step_size
 
+   Default: ``1e-9``
+
    The line search terminates if:
 
    .. math:: \|\Delta x_k\|_\infty < \text{min_line_search_step_size}
@@ -1153,7 +1476,8 @@
 
 .. member:: double Solver::Options::max_solver_time_in_seconds
 
-   Default: ``1e6``
+   Default: ``1e9``
+
    Maximum amount of time for which the solver should run.
 
 .. member:: int Solver::Options::num_threads
@@ -1239,8 +1563,8 @@
 
    where :math:`\|\cdot\|_\infty` refers to the max norm, :math:`\Pi`
    is projection onto the bounds constraints and :math:`\boxplus` is
-   Plus operation for the overall local parameterization associated
-   with the parameter vector.
+   Plus operation for the overall manifold associated with the
+   parameter vector.
 
 .. member:: double Solver::Options::parameter_tolerance
 
@@ -1260,7 +1584,7 @@
    Type of linear solver used to compute the solution to the linear
    least squares problem in each iteration of the Levenberg-Marquardt
    algorithm. If Ceres is built with support for ``SuiteSparse`` or
-   ``CXSparse`` or ``Eigen``'s sparse Cholesky factorization, the
+   ``Accelerate`` or ``Eigen``'s sparse Cholesky factorization, the
    default is ``SPARSE_NORMAL_CHOLESKY``, it is ``DENSE_QR``
    otherwise.
 
@@ -1271,8 +1595,9 @@
    The preconditioner used by the iterative linear solver. The default
    is the block Jacobi preconditioner. Valid values are (in increasing
    order of complexity) ``IDENTITY``, ``JACOBI``, ``SCHUR_JACOBI``,
-   ``CLUSTER_JACOBI`` and ``CLUSTER_TRIDIAGONAL``. See
-   :ref:`section-preconditioner` for more details.
+   ``CLUSTER_JACOBI``, ``CLUSTER_TRIDIAGONAL``, ``SUBSET`` and
+   ``SCHUR_POWER_SERIES_EXPANSION``. See :ref:`section-preconditioner`
+   for more details.
 
 .. member:: VisibilityClusteringType Solver::Options::visibility_clustering_type
 
@@ -1296,7 +1621,7 @@
    recommend that you try ``CANONICAL_VIEWS`` first and if it is too
    expensive try ``SINGLE_LINKAGE``.
 
-.. member:: std::unordered_set<ResidualBlockId> residual_blocks_for_subset_preconditioner
+.. member:: std::unordered_set<ResidualBlockId> Solver::Options::residual_blocks_for_subset_preconditioner
 
    ``SUBSET`` preconditioner is a preconditioner for problems with
    general sparsity. Given a subset of residual blocks of a problem,
@@ -1321,65 +1646,76 @@
 
 .. member:: DenseLinearAlgebraLibrary Solver::Options::dense_linear_algebra_library_type
 
-   Default:``EIGEN``
+   Default: ``EIGEN``
 
    Ceres supports using multiple dense linear algebra libraries for
-   dense matrix factorizations. Currently ``EIGEN`` and ``LAPACK`` are
-   the valid choices. ``EIGEN`` is always available, ``LAPACK`` refers
-   to the system ``BLAS + LAPACK`` library which may or may not be
-   available.
+   dense matrix factorizations. Currently ``EIGEN``, ``LAPACK`` and
+   ``CUDA`` are the valid choices. ``EIGEN`` is always available,
+   ``LAPACK`` refers to the system ``BLAS + LAPACK`` library which may
+   or may not be available. ``CUDA`` refers to Nvidia's GPU based
+   dense linear algebra library which may or may not be available.
 
    This setting affects the ``DENSE_QR``, ``DENSE_NORMAL_CHOLESKY``
-   and ``DENSE_SCHUR`` solvers. For small to moderate sized probem
+   and ``DENSE_SCHUR`` solvers. For small to moderate sized problem
    ``EIGEN`` is a fine choice but for large problems, an optimized
-   ``LAPACK + BLAS`` implementation can make a substantial difference
-   in performance.
+   ``LAPACK + BLAS`` or ``CUDA`` implementation can make a substantial
+   difference in performance.
 
 .. member:: SparseLinearAlgebraLibrary Solver::Options::sparse_linear_algebra_library_type
 
    Default: The highest available according to: ``SUITE_SPARSE`` >
-   ``CX_SPARSE`` > ``EIGEN_SPARSE`` > ``NO_SPARSE``
+   ``ACCELERATE_SPARSE`` > ``EIGEN_SPARSE`` > ``NO_SPARSE``
 
    Ceres supports the use of three sparse linear algebra libraries,
    ``SuiteSparse``, which is enabled by setting this parameter to
-   ``SUITE_SPARSE``, ``CXSparse``, which can be selected by setting
-   this parameter to ``CX_SPARSE`` and ``Eigen`` which is enabled by
-   setting this parameter to ``EIGEN_SPARSE``.  Lastly, ``NO_SPARSE``
-   means that no sparse linear solver should be used; note that this is
-   irrespective of whether Ceres was compiled with support for one.
+   ``SUITE_SPARSE``, ``Acclerate``, which can be selected by setting
+   this parameter to ``ACCELERATE_SPARSE`` and ``Eigen`` which is
+   enabled by setting this parameter to ``EIGEN_SPARSE``.  Lastly,
+   ``NO_SPARSE`` means that no sparse linear solver should be used;
+   note that this is irrespective of whether Ceres was compiled with
+   support for one.
 
-   ``SuiteSparse`` is a sophisticated and complex sparse linear
-   algebra library and should be used in general.
+   ``SuiteSparse`` is a sophisticated sparse linear algebra library
+   and should be used in general. On MacOS you may want to use the
+   ``Accelerate`` framework.
 
    If your needs/platforms prevent you from using ``SuiteSparse``,
-   consider using ``CXSparse``, which is a much smaller, easier to
-   build library. As can be expected, its performance on large
-   problems is not comparable to that of ``SuiteSparse``.
+   consider using the sparse linear algebra routines in ``Eigen``. The
+   sparse Cholesky algorithms currently included with ``Eigen`` are
+   not as sophisticated as the ones in ``SuiteSparse`` and
+   ``Accelerate`` and as a result its performance is considerably
+   worse.
 
-   Last but not the least you can use the sparse linear algebra
-   routines in ``Eigen``. Currently the performance of this library is
-   the poorest of the three. But this should change in the near
-   future.
+.. member:: LinearSolverOrderingType Solver::Options::linear_solver_ordering_type
 
-   Another thing to consider here is that the sparse Cholesky
-   factorization libraries in Eigen are licensed under ``LGPL`` and
-   building Ceres with support for ``EIGEN_SPARSE`` will result in an
-   LGPL licensed library (since the corresponding code from Eigen is
-   compiled into the library).
+   Default: ``AMD``
 
-   The upside is that you do not need to build and link to an external
-   library to use ``EIGEN_SPARSE``.
+    The order in which variables are eliminated in a linear solver can
+    have a significant impact on the efficiency and accuracy of the
+    method. e.g., when doing sparse Cholesky factorization, there are
+    matrices for which a good ordering will give a Cholesky factor
+    with :math:`O(n)` storage, where as a bad ordering will result in
+    an completely dense factor.
 
+    Sparse direct solvers like ``SPARSE_NORMAL_CHOLESKY`` and
+    ``SPARSE_SCHUR`` use a fill reducing ordering of the columns and
+    rows of the matrix being factorized before computing the numeric
+    factorization.
 
-.. member:: shared_ptr<ParameterBlockOrdering> Solver::Options::linear_solver_ordering
+    This enum controls the type of algorithm used to compute this fill
+    reducing ordering. There is no single algorithm that works on all
+    matrices, so determining which algorithm works better is a matter
+    of empirical experimentation.
 
-   Default: ``NULL``
+.. member:: std::shared_ptr<ParameterBlockOrdering> Solver::Options::linear_solver_ordering
+
+   Default: ``nullptr``
 
    An instance of the ordering object informs the solver about the
    desired order in which parameter blocks should be eliminated by the
-   linear solvers. See section~\ref{sec:ordering`` for more details.
+   linear solvers.
 
-   If ``NULL``, the solver is free to choose an ordering that it
+   If ``nullptr``, the solver is free to choose an ordering that it
    thinks is best.
 
    See :ref:`section-ordering` for more details.
@@ -1404,41 +1740,15 @@
    efficient to explicitly compute it and use it for evaluating the
    matrix-vector products.
 
-   Enabling this option tells ``ITERATIVE_SCHUR`` to use an explicitly
-   computed Schur complement. This can improve the performance of the
-   ``ITERATIVE_SCHUR`` solver significantly.
-
-   .. NOTE:
+   .. NOTE::
 
      This option can only be used with the ``SCHUR_JACOBI``
      preconditioner.
 
-.. member:: bool Solver::Options::use_post_ordering
+.. member:: bool Solver::Options::dynamic_sparsity
 
    Default: ``false``
 
-   Sparse Cholesky factorization algorithms use a fill-reducing
-   ordering to permute the columns of the Jacobian matrix. There are
-   two ways of doing this.
-
-   1. Compute the Jacobian matrix in some order and then have the
-      factorization algorithm permute the columns of the Jacobian.
-
-   2. Compute the Jacobian with its columns already permuted.
-
-   The first option incurs a significant memory penalty. The
-   factorization algorithm has to make a copy of the permuted Jacobian
-   matrix, thus Ceres pre-permutes the columns of the Jacobian matrix
-   and generally speaking, there is no performance penalty for doing
-   so.
-
-   In some rare cases, it is worth using a more complicated reordering
-   algorithm which has slightly better runtime performance at the
-   expense of an extra copy of the Jacobian matrix. Setting
-   ``use_postordering`` to ``true`` enables this tradeoff.
-
-.. member:: bool Solver::Options::dynamic_sparsity
-
    Some non-linear least squares problems are symbolically dense but
    numerically sparse. i.e. at any given state only a small number of
    Jacobian entries are non-zero, but the position and number of
@@ -1453,6 +1763,29 @@
 
    This setting only affects the `SPARSE_NORMAL_CHOLESKY` solver.
 
+.. member:: bool Solver::Options::use_mixed_precision_solves
+
+   Default: ``false``
+
+   If true, the Gauss-Newton matrix is computed in *double* precision, but
+   its factorization is computed in **single** precision. This can result in
+   significant time and memory savings at the cost of some accuracy in the
+   Gauss-Newton step. Iterative refinement is used to recover some
+   of this accuracy back.
+
+   If ``use_mixed_precision_solves`` is true, we recommend setting
+   ``max_num_refinement_iterations`` to 2-3.
+
+   See :ref:`section-mixed-precision` for more details.
+
+.. member:: int Solver::Options::max_num_refinement_iterations
+
+   Default: ``0``
+
+   Number steps of the iterative refinement process to run when
+   computing the Gauss-Newton step, see
+   :member:`Solver::Options::use_mixed_precision_solves`.
+
 .. member:: int Solver::Options::min_linear_solver_iterations
 
    Default: ``0``
@@ -1469,6 +1802,34 @@
    makes sense when the linear solver is an iterative solver, e.g.,
    ``ITERATIVE_SCHUR`` or ``CGNR``.
 
+.. member:: int Solver::Options::max_num_spse_iterations
+
+   Default: `5`
+
+   Maximum number of iterations performed by
+   ``SCHUR_POWER_SERIES_EXPANSION``. Each iteration corresponds to one
+   more term in the power series expansion od the inverse of the Schur
+   complement.  This value controls the maximum number of iterations
+   whether it is used as a preconditioner or just to initialize the
+   solution for ``ITERATIVE_SCHUR``.
+
+.. member:: bool Solver:Options::use_spse_initialization
+
+   Default: ``false``
+
+   Use Schur power series expansion to initialize the solution for
+   ``ITERATIVE_SCHUR``. This option can be set ``true`` regardless of
+   what preconditioner is being used.
+
+.. member:: double Solver::Options::spse_tolerance
+
+   Default: `0.1`
+
+   When ``use_spse_initialization`` is ``true``, this parameter along
+   with ``max_num_spse_iterations`` controls the number of
+   ``SCHUR_POWER_SERIES_EXPANSION`` iterations performed for
+   initialization. It is not used to control the preconditioner.
+
 .. member:: double Solver::Options::eta
 
    Default: ``1e-1``
@@ -1502,6 +1863,25 @@
    objects that have an :class:`EvaluationCallback` associated with
    them.
 
+.. member:: std::shared_ptr<ParameterBlockOrdering> Solver::Options::inner_iteration_ordering
+
+   Default: ``nullptr``
+
+   If :member:`Solver::Options::use_inner_iterations` true, then the
+   user has two choices.
+
+   1. Let the solver heuristically decide which parameter blocks to
+      optimize in each inner iteration. To do this, set
+      :member:`Solver::Options::inner_iteration_ordering` to ``nullptr``.
+
+   2. Specify a collection of of ordered independent sets. The lower
+      numbered groups are optimized before the higher number groups
+      during the inner optimization phase. Each group must be an
+      independent set. Not all parameter blocks need to be included in
+      the ordering.
+
+   See :ref:`section-ordering` for more details.
+
 .. member:: double Solver::Options::inner_iteration_tolerance
 
    Default: ``1e-3``
@@ -1516,37 +1896,21 @@
    inner iterations in subsequent trust region minimizer iterations is
    disabled.
 
-.. member:: shared_ptr<ParameterBlockOrdering> Solver::Options::inner_iteration_ordering
-
-   Default: ``NULL``
-
-   If :member:`Solver::Options::use_inner_iterations` true, then the
-   user has two choices.
-
-   1. Let the solver heuristically decide which parameter blocks to
-      optimize in each inner iteration. To do this, set
-      :member:`Solver::Options::inner_iteration_ordering` to ``NULL``.
-
-   2. Specify a collection of of ordered independent sets. The lower
-      numbered groups are optimized before the higher number groups
-      during the inner optimization phase. Each group must be an
-      independent set. Not all parameter blocks need to be included in
-      the ordering.
-
-   See :ref:`section-ordering` for more details.
 
 .. member:: LoggingType Solver::Options::logging_type
 
    Default: ``PER_MINIMIZER_ITERATION``
 
+   Valid values are ``SILENT`` and ``PER_MINIMIZER_ITERATION``.
+
 .. member:: bool Solver::Options::minimizer_progress_to_stdout
 
    Default: ``false``
 
-   By default the :class:`Minimizer` progress is logged to ``STDERR``
+   By default the Minimizer's progress is logged to ``STDERR``
    depending on the ``vlog`` level. If this flag is set to true, and
-   :member:`Solver::Options::logging_type` is not ``SILENT``, the logging
-   output is sent to ``STDOUT``.
+   :member:`Solver::Options::logging_type` is not ``SILENT``, the
+   logging output is sent to ``STDOUT``.
 
    For ``TRUST_REGION_MINIMIZER`` the progress display looks like
 
@@ -1595,7 +1959,7 @@
    #. ``it`` is the time take by the current iteration.
    #. ``tt`` is the total time taken by the minimizer.
 
-.. member:: vector<int> Solver::Options::trust_region_minimizer_iterations_to_dump
+.. member:: std::vector<int> Solver::Options::trust_region_minimizer_iterations_to_dump
 
    Default: ``empty``
 
@@ -1603,7 +1967,7 @@
    the trust region problem. Useful for testing and benchmarking. If
    ``empty``, no problems are dumped.
 
-.. member:: string Solver::Options::trust_region_problem_dump_directory
+.. member:: std::string Solver::Options::trust_region_problem_dump_directory
 
    Default: ``/tmp``
 
@@ -1614,7 +1978,7 @@
     :member:`Solver::Options::trust_region_problem_dump_format_type` is not
     ``CONSOLE``.
 
-.. member:: DumpFormatType Solver::Options::trust_region_problem_dump_format
+.. member:: DumpFormatType Solver::Options::trust_region_problem_dump_format_type
 
    Default: ``TEXTFILE``
 
@@ -1708,23 +2072,32 @@
    should not expect to look at the parameter blocks and interpret
    their values.
 
-.. member:: vector<IterationCallback> Solver::Options::callbacks
+.. member:: std::vector<IterationCallback*> Solver::Options::callbacks
+
+   Default: ``empty``
 
    Callbacks that are executed at the end of each iteration of the
-   :class:`Minimizer`. They are executed in the order that they are
+   minimizer. They are executed in the order that they are
    specified in this vector.
 
    By default, parameter blocks are updated only at the end of the
-   optimization, i.e., when the :class:`Minimizer` terminates. This
-   means that by default, if an :class:`IterationCallback` inspects
-   the parameter blocks, they will not see them changing in the course
-   of the optimization.
+   optimization, i.e., when the minimizer terminates. This means that
+   by default, if an :class:`IterationCallback` inspects the parameter
+   blocks, they will not see them changing in the course of the
+   optimization.
 
    To tell Ceres to update the parameter blocks at the end of each
    iteration and before calling the user's callback, set
    :member:`Solver::Options::update_state_every_iteration` to
    ``true``.
 
+   See `examples/iteration_callback_example.cc
+   <https://ceres-solver.googlesource.com/ceres-solver/+/master/examples/iteration_callback_example.cc>`_
+   for an example of an :class:`IterationCallback` that uses
+   :member:`Solver::Options::update_state_every_iteration` to log
+   changes to the parameter blocks over the course of the
+   optimization.
+
    The solver does NOT take ownership of these pointers.
 
 :class:`ParameterBlockOrdering`
@@ -1786,8 +2159,8 @@
 
    Number of groups with one or more elements.
 
-:class:`IterationCallback`
-==========================
+:class:`IterationSummary`
+=========================
 
 .. class:: IterationSummary
 
@@ -1863,7 +2236,7 @@
 
    Size of the trust region at the end of the current iteration. For
    the Levenberg-Marquardt algorithm, the regularization parameter is
-   1.0 / member::`IterationSummary::trust_region_radius`.
+   1.0 / :member:`IterationSummary::trust_region_radius`.
 
 .. member:: double IterationSummary::eta
 
@@ -1906,6 +2279,8 @@
 
    Time (in seconds) since the user called Solve().
 
+:class:`IterationCallback`
+==========================
 
 .. class:: IterationCallback
 
@@ -1939,6 +2314,10 @@
   #. ``SOLVER_CONTINUE`` indicates that the solver should continue
      optimizing.
 
+  The return values can be used to implement custom termination
+  criterion that supercede the iteration/time/tolerance based
+  termination implemented by Ceres.
+
   For example, the following :class:`IterationCallback` is used
   internally by Ceres to log the progress of the optimization.
 
@@ -1978,6 +2357,12 @@
     };
 
 
+  See `examples/evaluation_callback_example.cc
+  <https://ceres-solver.googlesource.com/ceres-solver/+/master/examples/iteration_callback_example.cc>`_
+  for another example that uses
+  :member:`Solver::Options::update_state_every_iteration` to log
+  changes to the parameter blocks over the course of the optimization.
+
 
 :class:`CRSMatrix`
 ==================
@@ -1995,13 +2380,13 @@
 
    Number of columns.
 
-.. member:: vector<int> CRSMatrix::rows
+.. member:: std::vector<int> CRSMatrix::rows
 
    :member:`CRSMatrix::rows` is a :member:`CRSMatrix::num_rows` + 1
    sized array that points into the :member:`CRSMatrix::cols` and
    :member:`CRSMatrix::values` array.
 
-.. member:: vector<int> CRSMatrix::cols
+.. member:: std::vector<int> CRSMatrix::cols
 
    :member:`CRSMatrix::cols` contain as many entries as there are
    non-zeros in the matrix.
@@ -2009,7 +2394,7 @@
    For each row ``i``, ``cols[rows[i]]`` ... ``cols[rows[i + 1] - 1]``
    are the indices of the non-zero columns of row ``i``.
 
-.. member:: vector<int> CRSMatrix::values
+.. member:: std::vector<double> CRSMatrix::values
 
    :member:`CRSMatrix::values` contain as many entries as there are
    non-zeros in the matrix.
@@ -2043,12 +2428,12 @@
 
    Summary of the various stages of the solver after termination.
 
-.. function:: string Solver::Summary::BriefReport() const
+.. function:: std::string Solver::Summary::BriefReport() const
 
    A brief one line description of the state of the solver after
    termination.
 
-.. function:: string Solver::Summary::FullReport() const
+.. function:: std::string Solver::Summary::FullReport() const
 
    A full multiline description of the state of the solver after
    termination.
@@ -2071,7 +2456,7 @@
 
    The cause of the minimizer terminating.
 
-.. member:: string Solver::Summary::message
+.. member:: std::string Solver::Summary::message
 
    Reason why the solver terminated.
 
@@ -2091,14 +2476,14 @@
    were held fixed by the preprocessor because all the parameter
    blocks that they depend on were fixed.
 
-.. member:: vector<IterationSummary> Solver::Summary::iterations
+.. member:: std::vector<IterationSummary> Solver::Summary::iterations
 
    :class:`IterationSummary` for each minimizer iteration in order.
 
 .. member:: int Solver::Summary::num_successful_steps
 
    Number of minimizer iterations in which the step was
-   accepted. Unless :member:`Solver::Options::use_non_monotonic_steps`
+   accepted. Unless :member:`Solver::Options::use_nonmonotonic_steps`
    is `true` this is also the number of steps in which the objective
    function value/cost went down.
 
@@ -2112,13 +2497,13 @@
 
    Number of times inner iterations were performed.
 
- .. member:: int Solver::Summary::num_line_search_steps
+.. member:: int Solver::Summary::num_line_search_steps
 
-    Total number of iterations inside the line search algorithm across
-    all invocations. We call these iterations "steps" to distinguish
-    them from the outer iterations of the line search and trust region
-    minimizer algorithms which call the line search algorithm as a
-    subroutine.
+   Total number of iterations inside the line search algorithm across
+   all invocations. We call these iterations "steps" to distinguish
+   them from the outer iterations of the line search and trust region
+   minimizer algorithms which call the line search algorithm as a
+   subroutine.
 
 .. member:: double Solver::Summary::preprocessor_time_in_seconds
 
@@ -2126,7 +2511,7 @@
 
 .. member:: double Solver::Summary::minimizer_time_in_seconds
 
-   Time (in seconds) spent in the Minimizer.
+   Time (in seconds) spent in the minimizer.
 
 .. member:: double Solver::Summary::postprocessor_time_in_seconds
 
@@ -2180,7 +2565,7 @@
    Dimension of the tangent space of the problem (or the number of
    columns in the Jacobian for the problem). This is different from
    :member:`Solver::Summary::num_parameters` if a parameter block is
-   associated with a :class:`LocalParameterization`.
+   associated with a :class:`Manifold`.
 
 .. member:: int Solver::Summary::num_residual_blocks
 
@@ -2206,7 +2591,7 @@
    number of columns in the Jacobian for the reduced problem). This is
    different from :member:`Solver::Summary::num_parameters_reduced` if
    a parameter block in the reduced problem is associated with a
-   :class:`LocalParameterization`.
+   :class:`Manifold`.
 
 .. member:: int Solver::Summary::num_residual_blocks_reduced
 
@@ -2224,9 +2609,7 @@
 .. member:: int Solver::Summary::num_threads_used
 
    Number of threads actually used by the solver for Jacobian and
-   residual evaluation. This number is not equal to
-   :member:`Solver::Summary::num_threads_given` if none of `OpenMP`
-   or `CXX_THREADS` is available.
+   residual evaluation.
 
 .. member:: LinearSolverType Solver::Summary::linear_solver_type_given
 
@@ -2242,12 +2625,12 @@
    `SPARSE_NORMAL_CHOLESKY` but no sparse linear algebra library was
    available.
 
-.. member:: vector<int> Solver::Summary::linear_solver_ordering_given
+.. member:: std::vector<int> Solver::Summary::linear_solver_ordering_given
 
    Size of the elimination groups given by the user as hints to the
    linear solver.
 
-.. member:: vector<int> Solver::Summary::linear_solver_ordering_used
+.. member:: std::vector<int> Solver::Summary::linear_solver_ordering_used
 
    Size of the parameter groups used by the solver when ordering the
    columns of the Jacobian.  This maybe different from
@@ -2285,12 +2668,12 @@
    actually performed. For example, in a problem with just one parameter
    block, inner iterations are not performed.
 
-.. member:: vector<int> inner_iteration_ordering_given
+.. member:: std::vector<int> Solver::Summary::inner_iteration_ordering_given
 
    Size of the parameter groups given by the user for performing inner
    iterations.
 
-.. member:: vector<int> inner_iteration_ordering_used
+.. member:: std::vector<int> Solver::Summary::inner_iteration_ordering_used
 
    Size of the parameter groups given used by the solver for
    performing inner iterations. This maybe different from
@@ -2315,7 +2698,7 @@
 
    Type of clustering algorithm used for visibility based
    preconditioning. Only meaningful when the
-   :member:`Solver::Summary::preconditioner_type` is
+   :member:`Solver::Summary::preconditioner_type_used` is
    ``CLUSTER_JACOBI`` or ``CLUSTER_TRIDIAGONAL``.
 
 .. member:: TrustRegionStrategyType Solver::Summary::trust_region_strategy_type
diff --git a/third_party/ceres/docs/source/nnls_tutorial.rst b/third_party/ceres/docs/source/nnls_tutorial.rst
index 6c89032..6de800e 100644
--- a/third_party/ceres/docs/source/nnls_tutorial.rst
+++ b/third_party/ceres/docs/source/nnls_tutorial.rst
@@ -2,6 +2,8 @@
 
 .. default-domain:: cpp
 
+.. cpp:namespace:: ceres
+
 .. _chapter-nnls_tutorial:
 
 ========================
@@ -110,7 +112,7 @@
      // Set up the only cost function (also known as residual). This uses
      // auto-differentiation to obtain the derivative (jacobian).
      CostFunction* cost_function =
-         new AutoDiffCostFunction<CostFunctor, 1, 1>(new CostFunctor);
+         new AutoDiffCostFunction<CostFunctor, 1, 1>();
      problem.AddResidualBlock(cost_function, nullptr, &x);
 
      // Run the solver!
@@ -210,8 +212,7 @@
 .. code-block:: c++
 
   CostFunction* cost_function =
-    new NumericDiffCostFunction<NumericDiffCostFunctor, ceres::CENTRAL, 1, 1>(
-        new NumericDiffCostFunctor);
+    new NumericDiffCostFunction<NumericDiffCostFunctor, ceres::CENTRAL, 1, 1>();
   problem.AddResidualBlock(cost_function, nullptr, &x);
 
 Notice the parallel from when we were using automatic differentiation
@@ -219,7 +220,7 @@
 .. code-block:: c++
 
   CostFunction* cost_function =
-      new AutoDiffCostFunction<CostFunctor, 1, 1>(new CostFunctor);
+      new AutoDiffCostFunction<CostFunctor, 1, 1>();
   problem.AddResidualBlock(cost_function, nullptr, &x);
 
 The construction looks almost identical to the one used for automatic
@@ -355,16 +356,16 @@
 
   Problem problem;
 
-  // Add residual terms to the problem using the using the autodiff
+  // Add residual terms to the problem using the autodiff
   // wrapper to get the derivatives automatically.
   problem.AddResidualBlock(
-    new AutoDiffCostFunction<F1, 1, 1, 1>(new F1), nullptr, &x1, &x2);
+    new AutoDiffCostFunction<F1, 1, 1, 1>(), nullptr, &x1, &x2);
   problem.AddResidualBlock(
-    new AutoDiffCostFunction<F2, 1, 1, 1>(new F2), nullptr, &x3, &x4);
+    new AutoDiffCostFunction<F2, 1, 1, 1>(), nullptr, &x3, &x4);
   problem.AddResidualBlock(
-    new AutoDiffCostFunction<F3, 1, 1, 1>(new F3), nullptr, &x2, &x3)
+    new AutoDiffCostFunction<F3, 1, 1, 1>(), nullptr, &x2, &x3);
   problem.AddResidualBlock(
-    new AutoDiffCostFunction<F4, 1, 1, 1>(new F4), nullptr, &x1, &x4);
+    new AutoDiffCostFunction<F4, 1, 1, 1>(), nullptr, &x1, &x4);
 
 
 Note that each ``ResidualBlock`` only depends on the two parameters
@@ -377,62 +378,65 @@
 
     Initial x1 = 3, x2 = -1, x3 = 0, x4 = 1
     iter      cost      cost_change  |gradient|   |step|    tr_ratio  tr_radius  ls_iter  iter_time  total_time
-       0  1.075000e+02    0.00e+00    1.55e+02   0.00e+00   0.00e+00  1.00e+04       0    4.95e-04    2.30e-03
-       1  5.036190e+00    1.02e+02    2.00e+01   2.16e+00   9.53e-01  3.00e+04       1    4.39e-05    2.40e-03
-       2  3.148168e-01    4.72e+00    2.50e+00   6.23e-01   9.37e-01  9.00e+04       1    9.06e-06    2.43e-03
-       3  1.967760e-02    2.95e-01    3.13e-01   3.08e-01   9.37e-01  2.70e+05       1    8.11e-06    2.45e-03
-       4  1.229900e-03    1.84e-02    3.91e-02   1.54e-01   9.37e-01  8.10e+05       1    6.91e-06    2.48e-03
-       5  7.687123e-05    1.15e-03    4.89e-03   7.69e-02   9.37e-01  2.43e+06       1    7.87e-06    2.50e-03
-       6  4.804625e-06    7.21e-05    6.11e-04   3.85e-02   9.37e-01  7.29e+06       1    5.96e-06    2.52e-03
-       7  3.003028e-07    4.50e-06    7.64e-05   1.92e-02   9.37e-01  2.19e+07       1    5.96e-06    2.55e-03
-       8  1.877006e-08    2.82e-07    9.54e-06   9.62e-03   9.37e-01  6.56e+07       1    5.96e-06    2.57e-03
-       9  1.173223e-09    1.76e-08    1.19e-06   4.81e-03   9.37e-01  1.97e+08       1    7.87e-06    2.60e-03
-      10  7.333425e-11    1.10e-09    1.49e-07   2.40e-03   9.37e-01  5.90e+08       1    6.20e-06    2.63e-03
-      11  4.584044e-12    6.88e-11    1.86e-08   1.20e-03   9.37e-01  1.77e+09       1    6.91e-06    2.65e-03
-      12  2.865573e-13    4.30e-12    2.33e-09   6.02e-04   9.37e-01  5.31e+09       1    5.96e-06    2.67e-03
-      13  1.791438e-14    2.69e-13    2.91e-10   3.01e-04   9.37e-01  1.59e+10       1    7.15e-06    2.69e-03
+       0  1.075000e+02    0.00e+00    1.55e+02   0.00e+00   0.00e+00  1.00e+04        0    2.91e-05    3.40e-04
+       1  5.036190e+00    1.02e+02    2.00e+01   0.00e+00   9.53e-01  3.00e+04        1    4.98e-05    3.99e-04
+       2  3.148168e-01    4.72e+00    2.50e+00   6.23e-01   9.37e-01  9.00e+04        1    2.15e-06    4.06e-04
+       3  1.967760e-02    2.95e-01    3.13e-01   3.08e-01   9.37e-01  2.70e+05        1    9.54e-07    4.10e-04
+       4  1.229900e-03    1.84e-02    3.91e-02   1.54e-01   9.37e-01  8.10e+05        1    1.91e-06    4.14e-04
+       5  7.687123e-05    1.15e-03    4.89e-03   7.69e-02   9.37e-01  2.43e+06        1    1.91e-06    4.18e-04
+       6  4.804625e-06    7.21e-05    6.11e-04   3.85e-02   9.37e-01  7.29e+06        1    1.19e-06    4.21e-04
+       7  3.003028e-07    4.50e-06    7.64e-05   1.92e-02   9.37e-01  2.19e+07        1    1.91e-06    4.25e-04
+       8  1.877006e-08    2.82e-07    9.54e-06   9.62e-03   9.37e-01  6.56e+07        1    9.54e-07    4.28e-04
+       9  1.173223e-09    1.76e-08    1.19e-06   4.81e-03   9.37e-01  1.97e+08        1    9.54e-07    4.32e-04
+      10  7.333425e-11    1.10e-09    1.49e-07   2.40e-03   9.37e-01  5.90e+08        1    9.54e-07    4.35e-04
+      11  4.584044e-12    6.88e-11    1.86e-08   1.20e-03   9.37e-01  1.77e+09        1    9.54e-07    4.38e-04
+      12  2.865573e-13    4.30e-12    2.33e-09   6.02e-04   9.37e-01  5.31e+09        1    2.15e-06    4.42e-04
+      13  1.791438e-14    2.69e-13    2.91e-10   3.01e-04   9.37e-01  1.59e+10        1    1.91e-06    4.45e-04
+      14  1.120029e-15    1.68e-14    3.64e-11   1.51e-04   9.37e-01  4.78e+10        1    2.15e-06    4.48e-04
 
-    Ceres Solver v1.12.0 Solve Report
-    ----------------------------------
+    Solver Summary (v 2.2.0-eigen-(3.4.0)-lapack-suitesparse-(7.1.0)-metis-(5.1.0)-acceleratesparse-eigensparse)
+
                                          Original                  Reduced
     Parameter blocks                            4                        4
     Parameters                                  4                        4
     Residual blocks                             4                        4
-    Residual                                    4                        4
+    Residuals                                   4                        4
 
     Minimizer                        TRUST_REGION
 
     Dense linear algebra library            EIGEN
     Trust region strategy     LEVENBERG_MARQUARDT
-
                                             Given                     Used
     Linear solver                        DENSE_QR                 DENSE_QR
     Threads                                     1                        1
-    Linear solver threads                       1                        1
+    Linear solver ordering              AUTOMATIC                        4
 
     Cost:
     Initial                          1.075000e+02
-    Final                            1.791438e-14
+    Final                            1.120029e-15
     Change                           1.075000e+02
 
-    Minimizer iterations                       14
-    Successful steps                           14
+    Minimizer iterations                       15
+    Successful steps                           15
     Unsuccessful steps                          0
 
     Time (in seconds):
-    Preprocessor                            0.002
+    Preprocessor                         0.000311
 
-      Residual evaluation                   0.000
-      Jacobian evaluation                   0.000
-      Linear solver                         0.000
-    Minimizer                               0.001
+      Residual only evaluation           0.000002 (14)
+      Jacobian & residual evaluation     0.000023 (15)
+      Linear solver                      0.000043 (14)
+    Minimizer                            0.000163
 
-    Postprocessor                           0.000
-    Total                                   0.005
+    Postprocessor                        0.000012
+    Total                                0.000486
 
     Termination:                      CONVERGENCE (Gradient tolerance reached. Gradient max norm: 3.642190e-11 <= 1.000000e-10)
 
-    Final x1 = 0.000292189, x2 = -2.92189e-05, x3 = 4.79511e-05, x4 = 4.79511e-05
+    Final x1 = 0.000146222, x2 = -1.46222e-05, x3 = 2.40957e-05, x4 = 2.40957e-05
+
+
+
 
 It is easy to see that the optimal solution to this problem is at
 :math:`x_1=0, x_2=0, x_3=0, x_4=0` with an objective function value of
@@ -494,8 +498,8 @@
  Problem problem;
  for (int i = 0; i < kNumObservations; ++i) {
    CostFunction* cost_function =
-        new AutoDiffCostFunction<ExponentialResidual, 1, 1, 1>(
-            new ExponentialResidual(data[2 * i], data[2 * i + 1]));
+        new AutoDiffCostFunction<ExponentialResidual, 1, 1, 1>
+            (data[2 * i], data[2 * i + 1]);
    problem.AddResidualBlock(cost_function, nullptr, &m, &c);
  }
 
@@ -670,8 +674,8 @@
     // the client code.
     static ceres::CostFunction* Create(const double observed_x,
                                        const double observed_y) {
-      return (new ceres::AutoDiffCostFunction<SnavelyReprojectionError, 2, 9, 3>(
-                  new SnavelyReprojectionError(observed_x, observed_y)));
+      return new ceres::AutoDiffCostFunction<SnavelyReprojectionError, 2, 9, 3>
+        (observed_x, observed_y);
     }
 
    double observed_x;
@@ -728,7 +732,7 @@
 
 For a more sophisticated bundle adjustment example which demonstrates
 the use of Ceres' more advanced features including its various linear
-solvers, robust loss functions and local parameterizations see
+solvers, robust loss functions and manifolds see
 `examples/bundle_adjuster.cc
 <https://ceres-solver.googlesource.com/ceres-solver/+/master/examples/bundle_adjuster.cc>`_
 
@@ -862,23 +866,23 @@
    measurement and the predicted measurement is:
 
    .. math:: r_{ab} =
-	     \left[
-	     \begin{array}{c}
-	       R_a^T\left(p_b - p_a\right) - \hat{p}_{ab} \\
-	       \mathrm{Normalize}\left(\psi_b - \psi_a - \hat{\psi}_{ab}\right)
-	     \end{array}
-	     \right]
+             \left[
+             \begin{array}{c}
+               R_a^T\left(p_b - p_a\right) - \hat{p}_{ab} \\
+               \mathrm{Normalize}\left(\psi_b - \psi_a - \hat{\psi}_{ab}\right)
+             \end{array}
+             \right]
 
    where the function :math:`\mathrm{Normalize}()` normalizes the angle in the range
    :math:`[-\pi,\pi)`, and :math:`R` is the rotation matrix given by
 
    .. math:: R_a =
-	     \left[
-	     \begin{array}{cc}
-	       \cos \psi_a & -\sin \psi_a \\
-	       \sin \psi_a & \cos \psi_a \\
-	     \end{array}
-	     \right]
+             \left[
+             \begin{array}{cc}
+               \cos \psi_a & -\sin \psi_a \\
+               \sin \psi_a & \cos \psi_a \\
+             \end{array}
+             \right]
 
    To finish the cost function, we need to weight the residual by the
    uncertainty of the measurement. Hence, we pre-multiply the residual by the
@@ -886,10 +890,12 @@
    i.e. :math:`\Sigma_{ab}^{-\frac{1}{2}} r_{ab}` where :math:`\Sigma_{ab}` is
    the covariance.
 
-   Lastly, we use a local parameterization to normalize the orientation in the
-   range which is normalized between :math:`[-\pi,\pi)`.  Specially, we define
-   the :member:`AngleLocalParameterization::operator()` function to be:
-   :math:`\mathrm{Normalize}(\psi + \delta \psi)`.
+   Lastly, we use a manifold to normalize the orientation in the range
+   :math:`[-\pi,\pi)`.  Specially, we define the
+   :member:`AngleManifold::Plus()` function to be:
+   :math:`\mathrm{Normalize}(\psi + \Delta)` and
+   :member:`AngleManifold::Minus()` function to be
+   :math:`\mathrm{Normalize}(y) - \mathrm{Normalize}(x)`.
 
    This package includes an executable :member:`pose_graph_2d` that will read a
    problem definition file. This executable can work with any 2D problem
@@ -980,17 +986,18 @@
    i.e. :math:`\Sigma_{ab}^{-\frac{1}{2}} r_{ab}` where :math:`\Sigma_{ab}` is
    the covariance.
 
-   Given that we are using a quaternion to represent the orientation, we need to
-   use a local parameterization (:class:`EigenQuaternionParameterization`) to
+   Given that we are using a quaternion to represent the orientation,
+   we need to use a manifold (:class:`EigenQuaternionManifold`) to
    only apply updates orthogonal to the 4-vector defining the
-   quaternion. Eigen's quaternion uses a different internal memory layout for
-   the elements of the quaternion than what is commonly used. Specifically,
-   Eigen stores the elements in memory as :math:`[x, y, z, w]` where the real
-   part is last whereas it is typically stored first. Note, when creating an
-   Eigen quaternion through the constructor the elements are accepted in
-   :math:`w`, :math:`x`, :math:`y`, :math:`z` order. Since Ceres operates on
-   parameter blocks which are raw double pointers this difference is important
-   and requires a different parameterization.
+   quaternion. Eigen's quaternion uses a different internal memory
+   layout for the elements of the quaternion than what is commonly
+   used. Specifically, Eigen stores the elements in memory as
+   :math:`[x, y, z, w]` where the real part is last whereas it is
+   typically stored first. Note, when creating an Eigen quaternion
+   through the constructor the elements are accepted in :math:`w`,
+   :math:`x`, :math:`y`, :math:`z` order. Since Ceres operates on
+   parameter blocks which are raw double pointers this difference is
+   important and requires a different parameterization.
 
    This package includes an executable :member:`pose_graph_3d` that will read a
    problem definition file. This executable can work with any 3D problem
diff --git a/third_party/ceres/docs/source/numerical_derivatives.rst b/third_party/ceres/docs/source/numerical_derivatives.rst
index 57b46bf..8d7fb3a 100644
--- a/third_party/ceres/docs/source/numerical_derivatives.rst
+++ b/third_party/ceres/docs/source/numerical_derivatives.rst
@@ -61,8 +61,7 @@
   }
 
   CostFunction* cost_function =
-    new NumericDiffCostFunction<Rat43CostFunctor, FORWARD, 1, 4>(
-      new Rat43CostFunctor(x, y));
+    new NumericDiffCostFunction<Rat43CostFunctor, FORWARD, 1, 4>(x, y);
 
 This is about the minimum amount of work one can expect to do to
 define the cost function. The only thing that the user needs to do is
@@ -326,7 +325,7 @@
 Compared to the *correct* value :math:`Df(1.0) = 140.73773557129658`,
 :math:`A(5, 1)` has a relative error of :math:`10^{-13}`. For
 comparison, the relative error for the central difference formula with
-the same stepsize (:math:`0.01/2^4 = 0.000625`) is :math:`10^{-5}`.
+the same step size (:math:`0.01/2^4 = 0.000625`) is :math:`10^{-5}`.
 
 The above tableau is the basis of Ridders' method for numeric
 differentiation. The full implementation is an adaptive scheme that
diff --git a/third_party/ceres/docs/source/solving_faqs.rst b/third_party/ceres/docs/source/solving_faqs.rst
index 64604c4..3842e4d 100644
--- a/third_party/ceres/docs/source/solving_faqs.rst
+++ b/third_party/ceres/docs/source/solving_faqs.rst
@@ -23,16 +23,13 @@
 
    2. For general sparse problems (i.e., the Jacobian matrix has a
       substantial number of zeros) use
-      ``SPARSE_NORMAL_CHOLESKY``. This requires that you have
-      ``SuiteSparse`` or ``CXSparse`` installed.
+      ``SPARSE_NORMAL_CHOLESKY``.
 
    3. For bundle adjustment problems with up to a hundred or so
       cameras, use ``DENSE_SCHUR``.
 
    4. For larger bundle adjustment problems with sparse Schur
-      Complement/Reduced camera matrices use ``SPARSE_SCHUR``. This
-      requires that you build Ceres with support for ``SuiteSparse``,
-      ``CXSparse`` or Eigen's sparse linear algebra libraries.
+      Complement/Reduced camera matrices use ``SPARSE_SCHUR``.
 
       If you do not have access to these libraries for whatever
       reason, ``ITERATIVE_SCHUR`` with ``SCHUR_JACOBI`` is an
diff --git a/third_party/ceres/docs/source/version_history.rst b/third_party/ceres/docs/source/version_history.rst
index 72ae832..50f8353 100644
--- a/third_party/ceres/docs/source/version_history.rst
+++ b/third_party/ceres/docs/source/version_history.rst
@@ -1,9 +1,320 @@
+.. default-domain:: cpp
+
+.. highlight:: c++
+
+.. cpp:namespace:: ceres
+
+
 .. _chapter-version-history:
 
 ===============
 Version History
 ===============
 
+2.2.0
+=====
+
+New Features
+------------
+
+#. Substantial improvement to threading performance across the board
+   (Dmitry Korchemkin)
+#. Mixed precision solves + iterative refinement when using ``CUDA`` or
+   CPU based dense linear solvers, or ``EIGEN_SPARSE`` as the sparse
+   linear algebra library. (Sameer Agarwal & Joydeep Biswas)
+#. Cuda based CGNR and preconditioner support (Joydeep Biswas & Sameer
+   Agarwal)
+#. Nested Dissection (``NESDIS``) is now supported as an ordering method
+   in addition to ``AMD``. (Sameer Agarwal, Alex Stewart & Sergiu
+   Deitsch)
+#. **Power Bundle Adjustment** is available as a linear solver and as
+   a preconditioner by the name of ``SCHUR POWER SERIES EXPANSION``
+   (Mark Shachkov).
+#. Generalized Euler Angle conversions (hs293go@)
+
+
+Backward Incompatible API Changes
+---------------------------------
+
+#. :class:`LocalParameterization` has been removed, use
+   :class:`Manifold` instead.
+#. Ceres Solver now requires a C++17 compliant compiler.
+#. Ceres Solver now requires CMake version 3.16 or later.
+#. Ceres Solver now requires SuiteSparse version 4.5.6 or later.
+#. OpenMP and NO_THREADING backends have been removed. C++ threads is
+   how all threading is done.
+#. Support for ``CX_SPARSE`` as a sparse linear algebra backend has
+   been removed. Similar or better performance can be expected from
+   ``Eigen`` as the sparse linear algebra library.
+
+
+Bug Fixes & Minor Changes
+-------------------------
+#. Optimize the computation of the LM diagonal in TinySolver
+#. Improvements to multi-threaded performance for small problems that
+   had regressed due to changes to threading (Dmitrity Korchemkin)
+#. Fix handling of M_PI for MSVC (Sergiu Deitsch)
+#. Add a default value for Solver::Summary::linear_solver_ordering_type (Sameer Agarwal)
+#. Make sure that the code compiles well with CUDA 11 (Dmitriy
+   Korchemkin)
+#. Rework MSVC warning suppression (Sergiu Deitsch)
+#. Add an example for EvaluationCallback (Sameer Agarwal)
+#. Add an example for IterationCallback (Sameer Agarwal)
+#. Add end-to-end BA tests for SCHUR_POWER_SERIES_EXPANSION (Sameer Agarwal)
+#. Update documentation for linear solvers (Sameer Agarwal)
+#. Add an accessor for the CostFunctor in DynamicAutoDiffCostFunction (Sameer Agarwal)
+#. Runtime check for cudaMallocAsync support (Dmitriy Korchemkin)
+#. Remove cuda-memcheck based tests (Sameer Agarwal)
+#. Modernize ``Sphinx`` related CMake handling as well the ``Sphinx``
+   build process in the terminal. (Sergiu Deitsch)
+#. Fix macos ``sprintf`` security related warnings (Sergiu Deitsch)
+#. Lots of Cuda releated build system fixes (Sergiu Deitsch, Dmitriy
+   Korchemkin, Jason Mak)
+#. Improved windows build support (Sergiu Deitsch)
+#. Various documentation fixes (Maxim Smolskiy, Evan Levine)
+#. Improved handling of large Jacobians (Sameer Agarwal)
+#. Improved handling of infinite initial cost (Sameer Agarwal)
+#. Improved traits support for Jets (Sameer Agarwal)
+#. Improved tests for Euler angle conversion routines (@Hs293Go)
+#. Use a std::tuple to store ProductManifold for better efficiency
+   (Sergiu Deitsch)
+#. Allow default construction of ProductManifold when underlying
+   manifolds have default constructors (Sergiu Deitsch)
+#. Move LineManifold and SphereManifold into their own headers (Sameer
+   Agarwal)
+#. Fix a byte vs number of elements error when dealing with CUDA
+   workspace computations (Joydeep Biswas)
+#. Hide and prevent internal symbols from being exported (Sergiu
+   Deitsch)
+#. Switch to imported SuiteSparse, CXSparse & METIS targets.
+#. Improve compilation on Ubuntu 20.04 (Sergiu Deitsch)
+#. Update to using gtest 1.11.0 (Sameer Agarwal)
+#. Fix Euler angle conversion code to not rely on constexpr
+   constrctors for Jets. (Sameer Agarwal)
+#. BlockRandomAccessSparseMatrix now uses a BlockSparseMatrix as
+   storage instead of TripletSparseMatrix. (Dmitriy Korchemkin)
+#. Deduction guide for DynamicAutoDiffCostFunction (Sergiu Deitsch)
+#. Explicit conversions from long to ints (Alexander Ivanov)
+#. Unused code deletion/commenting and code modernization (Alexander
+   Ivanov)
+#. Improve the bazel build & tests (Alexander Ivanov)
+#. Fix a bug in QuaternionRotatePoint introduced by the use of hypot
+   earlier in this release cycle (Jonathan Taylor & Sameer Agarwal)
+#. Lots of GitHub CI improvements (Sergiu Deitsch & Dmitry Korchemkin)
+#. Improve the robustness of the Cuda based dense linear algebra tests
+   (Joydeep Biswas)
+#. Refactor storage & threading support in BlockRandomAccessMatrix and
+   its subclasses (Sameer Agarwal)
+#. Fix a bug in CoordinateDescentMinimizer related to uninitialized
+   variables (Sameer Agarwal)
+#. Remove OpenMP and NO_THREADS backends. (Sameer Agarwal)
+#. Fix version string parsing starting with SuiteSparse 6.0 (Sergiu
+   Deitsch)
+#. Use FindCUDAToolkit for CMake >= 3.17 (Alex Stewart)
+#. Add a const accessor for the Problem::Options struct used by
+   Problem. (Alex Stewart)
+#. Fix a serious performance regression when using SuiteSparse
+   introduced in `d09f7e9d5e
+   <https://github.com/ceres-solver/ceres-solver/commit/d09f7e9d5e3bfab2d7ec7e81fd6a55786edca17a>`_. (Sameer
+   Agarwal)
+#. Fix the build on QNX (Alex Stewart)
+#. Improve testing macros and documentation for Manifolds (Alex
+   Stewart)
+#. Improved code formatting (Tyler Hovanec)
+#. Better use of std::unique_ptr in the code (Mike Vitus)
+#. Fix a memory leak in ContextImpl (Sameer Agarwal)
+#. Faster locking when num_thread = 1 (Sameer Agarwal)
+#. Fix how x_norm is computed in TrustRegionMinimizer (Sameer Agarwal)
+#. Faster JACOBI preconditioner for CGNR (Sameer Agarwal)
+#. Convert internal enums to class enums (Sameer Agarwal)
+#. Improve the code in small_blas to be more compiler friendly (Sameer
+   Agarwal)
+#. Add the ability to specify the pivot threshold in
+   ::class::`Covariance::Options` (Sameer Agarwal)
+#. Modernize the internals to use C++17 (Sameer Agarwal)
+#. Choose SPMV algorithm based on the CUDA SDK Version (Joydeep
+   Biswas)
+#. Better defaults in ``bundle_adjuster.cc`` (Sameer Agarwal)
+#. Use ``foo.data()`` instead of ``&foo[0]`` (Sameer Agarwal)
+#. Fix GCC 12.1.1 LTO -Walloc-size-larger-than= warnings (Sergiu
+   Deitsch)
+#. Improved determinism in tests by re-using the same PRNG (Sergiu
+   Deitsch)
+#. Improved docs for ``vcpkg`` installation. (Sergiu Deitsch)
+#. Update FindGlog.cmake to create glog::glog target (KrisThielemans@)
+#. Improve consistency & correctness of Sphere & Line Manifolds
+   (Julio L. Paneque)
+#. Remove ``ceres/internal/random.h`` in favor of ``<random>``.
+#. Fix a crash in ``InnerProductComputer`` (Sameer Agarwal)
+#. Various fixes to improve compilation on windows using MinGW & MSVC
+   (Sergiu Deitsch)
+#. Fix fmin/fmax() to use Jet averaging on equality (Alex Stewart)
+#. Fix use of conditional preprocessor checks within a macro in tests
+   (Alex Stewart)
+#. Better support for ``CUDA memcheck`` (Joydeep Biswas)
+#. Improve the logic for linking to the platform specific threading
+   library (Sergiu Deitsch)
+#. Generate the version string at compile time (Sergiu Deitsch)
+#. :class:`NumericDiffFirstOrderFunction` can now take a dynamically
+   sized parameter vector. (Sameer Agarwal)
+#. Fix compilation with SuiteSparse 7.2.0 (Mark Shackov)
+
+2.1.0
+=====
+
+New Features
+------------
+
+#. Support for CUDA based dense solvers - ``DENSE_QR``,
+   ``DENSE_NORMAL_CHOLESKY`` & ``DENSE_SCHUR`` (Joydeep Biswas, Sameer
+   Agarwal)
+
+#. :class:`Manifold` is the new
+   :class:`LocalParameterization`. Version 2.1 is the transition
+   release where users can use both :class:`LocalParameterization` as
+   well as :class:`Manifold` objects as they transition from the
+   former to the latter. :class:`LocalParameterization` will be
+   removed in version 2.2. There should be no numerical change to the
+   results as a result of this change. (Sameer Agarwal, Johannes Beck,
+   Sergiu Deitsch)
+
+#. A number of changes to :class:`Jet` s (Sergiu Deitsch)
+
+   * :class:`Jet` gained support for, ``copysign``, ``fma`` (fused
+     multiply-add), ``midpoint`` (C++20 and above), ``lerp`` (C++20
+     and above), 3-argument ``hypot`` (C++17 and above), ``log10``,
+     ``log1p``, ``exp1m``, ``norm`` (squared :math:`L^2` norm).
+
+   * Quiet floating-point comparison: ``isless``, ``isgreater``,
+     ``islessgreater``, ``islessequal``, ``isgreaterequal``,
+     ``isunordered``, ``signbit``, ``fdim``
+
+   * Categorization and comparison operations are applied exclusively
+     and consistently to the scalar part of a Jet now: ``isnan``,
+     ``isinf``, ``isnormal``, ``isfinite``, ``fpclassify`` (new),
+     ``fmin``, ``fmax``
+
+   * It is now possible to safely compare a :class:`Jet` against a scalar
+     (or literal) without constructing a :class:`Jet` first (even if it's
+     nested):
+
+     .. code-block:: c++
+
+        Jet<Jet<Jet<T, N>, M>, O> x;
+        if (x == 2) { } // equivalent to x.a.a.a == 2
+
+
+     This enables interaction with various arithmetic functions that
+     expect a scalar like instance, such as ``boost::math::pow<-N>``
+     for reciprocal computation.
+
+#. Add :class:`NumericDiffFirstOrderFunction` (Sameer Agarwal)
+
+
+Backward Incompatible API Changes
+---------------------------------
+
+#. :class:`LocalParameterization` is deprecated. It will be removed in
+   version 2.2. Use :class:`Manifold` instead.
+#. Classification functions like ``IsFinite`` are deprecated. Use the
+   ``C++11`` functions (``isfinite``, ``isnan`` etc) going
+   forward. However to maintain consistent behaviour with comparison
+   operators, these functions only inspect the scalar part of the
+   :class:`Jet`.
+
+Bug Fixes & Minor Changes
+-------------------------
+
+#. Worked around an MSVC ordering bug when using C++17/20 (Sergiu
+   Deitsch)
+#. Added a CITATION.cff file. (Sergiu Deitsch)
+#. Updated included gtest version to 1.11.0. This should fix some
+   ``C++20`` compilation problems. (Sameer Agarwal).
+#. Workaround ``MSVC`` ``STL`` deficiency in ``C++17`` mode (Sergiu
+   Deitsch)
+#. Fix ``Jet`` test failures on ``ARMv8`` with recent ``Xcode``
+   (Sergiu Deitsch)
+#. Fix unused arguments of ``Make1stOrderPerturbation`` (Dmitriy
+   Korchemkin)
+#. Fix ``SuiteSparse`` path and version reporting (Sergiu Deitsch)
+#. Enable `GitHub` workflows and deprecate ``TravisCI`` (Sergiu
+   Deitsch)
+#. Add missing includes (Sergiu Deitsch, Sameer Agarwal)
+#. Fix path for ``cuda-memcheck`` tests (Joydeep Biswas)
+#. ClangFormat cleanup (Sameer Agarwal)
+#. Set ``CMP0057`` policy for ``IN_LIST`` operator in
+   ``FindSuiteSparse.cmake`` (Brent Yi)
+#. Do not define unusable import targets (Sergiu Deitsch)
+#. Fix Ubuntu 18.04 shared library build (Sergiu Deitsch)
+#. Force ``C++`` linker when building the ``C`` API (Sergiu Deitsch)
+#. Modernize the code to be inline with ``C++14`` (Sergiu Deitsch,
+   Sameer Agarwal)
+#. Lots of fixes to make Ceres compile out of the box on Windows
+   (Sergiu Deitsch)
+#. Standardize path handling using ``GNUImstallDirs`` (Sergiu Deitsch)
+#. Add final specifier to classes to help the compiler with
+   devirtualization (Sameer Agarwal)
+#. LOTs of clean & modernization of the CMake build files (Sergiu
+   Deitsch & Alex Stewart)
+#. Simplification to the symbol export logic (Sergiu Deitsch)
+#. Add cmake option ``ENABLE_BITCODE`` for iOS builds (John Harrison)
+#. Add const accessor for functor wrapped by auto/numeric-diff objects
+   (Alex Stewart)
+#. Cleanup & refactor ``jet_test.cc``. (Sameer Agarwal)
+#. Fix docs of supported sparse backends for mixed precision solvers
+   (Alex Stewart)
+#. Fix C++20 compilation (Sergiu Deitsch)
+#. Add an example for ``BiCubicInterpolator`` (Dmitriy Korcchemkin)
+#. Add a section to the documentation on implicit and inverse function
+   theorems (Sameer Agarwal)
+#. Add a note about Trigg's correction (Sameer Agarwal)
+#. Fix the docs for ``Problem::RemoveResidualBlock`` &
+   ``Problem::RemoveParameterBlock`` (Sameer Agarwal)
+#. Fix an incorrect check in ``reorder_program.cc`` (William Gandler)
+#. Add ``function_tolerance`` based convergence testing to ``TinySolver``
+   (Sameer Agarwal).
+#. Fix a number of typos in ``rotation.h`` (@yiping)
+#. Fix a typo in ``interfacing_with_autodiff.rst`` (@tangobravo)
+#. Fix a matrix sizing bug in covariance_impl.cc (William Gandler)
+#. Fix a bug in ``system_test.cc`` (William Gandler)
+#. Fix the Jacobian computation in ``trust_region_minimizer_test.cc``
+   (William Gandler)
+#. Fix a bug in ``local_parameterization_test.cc`` (William Gandler)
+#. Add accessors to ``GradientProblem`` (Sameer Agarwal)
+#. Refactor ``small_blas_gemm_benchmark`` (Ahmed Taei)
+#. Refactor ``small_blas_test`` (Ahmed Taei)
+#. Fix dependency check for building documentation (Sumit Dey)
+#. Fix an errant double link in the docs (Timon Knigge)
+#. Fix a typo in the version history (Noah Snavely)
+#. Fix typo in LossFunctionWrapper sample code (Dmitriy Korchemkin)
+#. Add fmax/fmin overloads for scalars (Alex Karatarakis)
+#. Introduce benchmarks for ``Jet`` operations (Alexander Karatarakis)
+#. Fix typos in documentation and fix the documentation for
+   ``IterationSummary`` (Alexander Karatarakis)
+#. Do not check MaxNumThreadsAvailable if the thread number is set
+   to 1. (Fuhao Shi)
+#. Add a macro ``CERES_GET_FLAG``. (Sameer Agarwal)
+#. Reduce log spam in ``covariance_impl.cc`` (Daniel Henell)
+#. Fix FindTBB version detection with TBB >= 2021.1.1 (Alex Stewart)
+#. Fix Eigen3_VERSION (Florian Berchtold)
+#. Allow Unity Build (Tobias Schluter)
+#. Make miniglog's InitGoogleLogging argument const (Tobias Schluter)
+#. Use portable expression for constant 2/sqrt(pi) (Tobias Schluter)
+#. Fix a number of compile errors related (Austin Schuch)
+
+   * ``format not a string literal``
+   * ``-Wno-maybe-uninitialized error``
+   * ``nonnull arg compared to NULL``
+   * ``-Wno-format-nonliteral``
+   * ``-Wmissing-field-initializers``
+   * ``-Werror``
+
+#. Fix ``cc_binary`` includes so examples build as an external repo
+   (Austin Schuh)
+#. Fix an explicit double in TinySolver (Bogdan Burlacu)
+#. Fix unit quaternion rotation (Mykyta Kozlov)
+
+
 2.0.0
 =====
 
@@ -1532,8 +1843,8 @@
 =======
 
 Ceres Solver grew out of the need for general least squares solving at
-Google. In early 2010, Sameer Agarwal and Fredrik Schaffalitzky
-started the development of Ceres Solver. Fredrik left Google shortly
+Google. In early 2010, Sameer Agarwal and Frederik Schaffalitzky
+started the development of Ceres Solver. Frederik left Google shortly
 thereafter and Keir Mierle stepped in to take his place. After two
 years of on-and-off development, Ceres Solver was released as open
 source in May of 2012.
diff --git a/third_party/ceres/examples/BUILD b/third_party/ceres/examples/BUILD
index 80d9a67..8741b94 100644
--- a/third_party/ceres/examples/BUILD
+++ b/third_party/ceres/examples/BUILD
@@ -32,6 +32,7 @@
     # Needed to silence GFlags complaints.
     "-Wno-sign-compare",
     "-Wno-unused-parameter",
+    # Needed to put fscanf in a function.
     "-Wno-format-nonliteral",
 ]
 
@@ -47,7 +48,6 @@
         "bal_problem.cc",
         "bal_problem.h",
         "bundle_adjuster.cc",
-        "random.h",
         "snavely_reprojection_error.h",
     ],
     copts = EXAMPLE_COPTS,
@@ -69,7 +69,6 @@
 cc_binary(
     name = "robot_pose_mle",
     srcs = [
-        "random.h",
         "robot_pose_mle.cc",
     ],
     copts = EXAMPLE_COPTS,
@@ -80,7 +79,7 @@
     name = "pose_graph_2d",
     srcs = [
         "slam/common/read_g2o.h",
-        "slam/pose_graph_2d/angle_local_parameterization.h",
+        "slam/pose_graph_2d/angle_manifold.h",
         "slam/pose_graph_2d/normalize_angle.h",
         "slam/pose_graph_2d/pose_graph_2d.cc",
         "slam/pose_graph_2d/pose_graph_2d_error_term.h",
diff --git a/third_party/ceres/examples/CMakeLists.txt b/third_party/ceres/examples/CMakeLists.txt
index 7f9b117..8af2077 100644
--- a/third_party/ceres/examples/CMakeLists.txt
+++ b/third_party/ceres/examples/CMakeLists.txt
@@ -1,5 +1,5 @@
 # Ceres Solver - A fast non-linear least squares minimizer
-# Copyright 2015 Google Inc. All rights reserved.
+# Copyright 2022 Google Inc. All rights reserved.
 # http://ceres-solver.org/
 #
 # Redistribution and use in source and binary forms, with or without
@@ -28,86 +28,96 @@
 #
 # Author: keir@google.com (Keir Mierle)
 
-# Only Ceres itself should be compiled with CERES_BUILDING_SHARED_LIBRARY
-# defined, any users of Ceres will have CERES_USING_SHARED_LIBRARY defined
-# for them in Ceres' config.h if appropriate.
-if (BUILD_SHARED_LIBS)
-  remove_definitions(-DCERES_BUILDING_SHARED_LIBRARY)
-endif()
-
 add_executable(helloworld helloworld.cc)
-target_link_libraries(helloworld Ceres::ceres)
+target_link_libraries(helloworld PRIVATE Ceres::ceres)
 
 add_executable(helloworld_numeric_diff helloworld_numeric_diff.cc)
-target_link_libraries(helloworld_numeric_diff Ceres::ceres)
+target_link_libraries(helloworld_numeric_diff PRIVATE Ceres::ceres)
 
 add_executable(helloworld_analytic_diff helloworld_analytic_diff.cc)
-target_link_libraries(helloworld_analytic_diff Ceres::ceres)
+target_link_libraries(helloworld_analytic_diff PRIVATE Ceres::ceres)
 
 add_executable(curve_fitting curve_fitting.cc)
-target_link_libraries(curve_fitting Ceres::ceres)
+target_link_libraries(curve_fitting PRIVATE Ceres::ceres)
 
 add_executable(rosenbrock rosenbrock.cc)
-target_link_libraries(rosenbrock Ceres::ceres)
+target_link_libraries(rosenbrock PRIVATE Ceres::ceres)
+
+add_executable(rosenbrock_analytic_diff rosenbrock_analytic_diff.cc)
+target_link_libraries(rosenbrock_analytic_diff PRIVATE Ceres::ceres)
+
+add_executable(rosenbrock_numeric_diff rosenbrock_numeric_diff.cc)
+target_link_libraries(rosenbrock_numeric_diff PRIVATE Ceres::ceres)
 
 add_executable(curve_fitting_c curve_fitting.c)
-target_link_libraries(curve_fitting_c Ceres::ceres)
-# Force CMake to link curve_fitting_c using the C linker.
-set_target_properties(curve_fitting_c PROPERTIES LINKER_LANGUAGE C)
+target_link_libraries(curve_fitting_c PRIVATE Ceres::ceres)
+# Force CMake to link curve_fitting_c using the C++ linker.
+set_target_properties(curve_fitting_c PROPERTIES LINKER_LANGUAGE CXX)
 # As this is a C file #including <math.h> we have to explicitly add the math
 # library (libm). Although some compilers (dependent upon options) will accept
 # the indirect link to libm via Ceres, at least GCC 4.8 on pure Debian won't.
-if (NOT MSVC)
-  target_link_libraries(curve_fitting_c m)
-endif (NOT MSVC)
+if (HAVE_LIBM)
+  target_link_libraries(curve_fitting_c PRIVATE m)
+endif (HAVE_LIBM)
 
 add_executable(ellipse_approximation ellipse_approximation.cc)
-target_link_libraries(ellipse_approximation Ceres::ceres)
+target_link_libraries(ellipse_approximation PRIVATE Ceres::ceres)
 
 add_executable(robust_curve_fitting robust_curve_fitting.cc)
-target_link_libraries(robust_curve_fitting Ceres::ceres)
+target_link_libraries(robust_curve_fitting PRIVATE Ceres::ceres)
 
 add_executable(simple_bundle_adjuster simple_bundle_adjuster.cc)
-target_link_libraries(simple_bundle_adjuster Ceres::ceres)
+target_link_libraries(simple_bundle_adjuster PRIVATE Ceres::ceres)
+
+add_executable(bicubic_interpolation bicubic_interpolation.cc)
+target_link_libraries(bicubic_interpolation PRIVATE Ceres::ceres)
+
+add_executable(bicubic_interpolation_analytic bicubic_interpolation_analytic.cc)
+target_link_libraries(bicubic_interpolation_analytic PRIVATE Ceres::ceres)
+
+add_executable(iteration_callback_example iteration_callback_example.cc)
+target_link_libraries(iteration_callback_example PRIVATE Ceres::ceres)
+
+add_executable(evaluation_callback_example evaluation_callback_example.cc)
+target_link_libraries(evaluation_callback_example PRIVATE Ceres::ceres)
 
 if (GFLAGS)
   add_executable(powell powell.cc)
-  target_link_libraries(powell Ceres::ceres gflags)
+  target_link_libraries(powell PRIVATE Ceres::ceres gflags)
 
   add_executable(nist nist.cc)
-  target_link_libraries(nist Ceres::ceres gflags)
-  if (MSVC)
-    target_compile_options(nist PRIVATE "/bigobj")
+  target_link_libraries(nist PRIVATE Ceres::ceres gflags)
+  if (HAVE_BIGOBJ)
+    target_compile_options(nist PRIVATE /bigobj)
   endif()
 
   add_executable(more_garbow_hillstrom more_garbow_hillstrom.cc)
-  target_link_libraries(more_garbow_hillstrom Ceres::ceres gflags)
+  target_link_libraries(more_garbow_hillstrom PRIVATE Ceres::ceres gflags)
 
   add_executable(circle_fit circle_fit.cc)
-  target_link_libraries(circle_fit Ceres::ceres gflags)
+  target_link_libraries(circle_fit PRIVATE Ceres::ceres gflags)
 
   add_executable(bundle_adjuster
                  bundle_adjuster.cc
                  bal_problem.cc)
-  target_link_libraries(bundle_adjuster Ceres::ceres gflags)
+  target_link_libraries(bundle_adjuster PRIVATE Ceres::ceres gflags)
 
   add_executable(libmv_bundle_adjuster
                  libmv_bundle_adjuster.cc)
-  target_link_libraries(libmv_bundle_adjuster Ceres::ceres gflags)
+  target_link_libraries(libmv_bundle_adjuster PRIVATE Ceres::ceres gflags)
 
   add_executable(libmv_homography
                  libmv_homography.cc)
-  target_link_libraries(libmv_homography Ceres::ceres gflags)
+  target_link_libraries(libmv_homography PRIVATE Ceres::ceres gflags)
 
   add_executable(denoising
                  denoising.cc
                  fields_of_experts.cc)
-  target_link_libraries(denoising Ceres::ceres gflags)
+  target_link_libraries(denoising PRIVATE Ceres::ceres gflags)
 
   add_executable(robot_pose_mle
                  robot_pose_mle.cc)
-  target_link_libraries(robot_pose_mle Ceres::ceres gflags)
-
+  target_link_libraries(robot_pose_mle PRIVATE Ceres::ceres gflags)
 endif (GFLAGS)
 
 add_subdirectory(sampled_function)
diff --git a/third_party/ceres/examples/Makefile.example b/third_party/ceres/examples/Makefile.example
deleted file mode 100644
index f2b0dc0..0000000
--- a/third_party/ceres/examples/Makefile.example
+++ /dev/null
@@ -1,82 +0,0 @@
-# Ceres Solver - A fast non-linear least squares minimizer
-# Copyright 2015 Google Inc. All rights reserved.
-# http://ceres-solver.org/
-#
-# 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 Google Inc. 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.
-#
-# Author: keir@google.com (Keir Mierle)
-#
-# This is an example Makefile for using Ceres. In practice, the Ceres authors
-# suggest using CMake instead, but if Make is needed for some reason, this
-# example serves to make it easy to do so.
-
-# This should point to place where you unpacked or cloned Ceres.
-CERES_SRC_DIR := /home/keir/wrk/ceres-extra
-
-# This should point to the place where you built Ceres. If you got Ceres by
-# installing it, then this will likely be /usr/local/lib.
-CERES_BIN_DIR := /home/keir/wrk/ceres-extra-bin
-
-# The place you unpacked or cloned Eigen. If Eigen was installed from packages,
-# this will likely be /usr/local/include.
-EIGEN_SRC_DIR := /home/keir/src/eigen-3.0.5
-
-INCLUDES := -I$(CERES_SRC_DIR)/include \
-            -I$(EIGEN_SRC_DIR)
-
-CERES_LIBRARY := -lceres
-CERES_LIBRARY_PATH := -L$(CERES_BIN_DIR)/lib
-CERES_LIBRARY_DEPENDENCIES = -lgflags -lglog
-
-# If Ceres was built with Suitesparse:
-CERES_LIBRARY_DEPENDENCIES += -llapack -lcamd -lamd -lccolamd -lcolamd -lcholmod
-
-# If Ceres was built with CXSparse:
-CERES_LIBRARY_DEPENDENCIES += -lcxsparse
-
-# If Ceres was built with OpenMP:
-CERES_LIBRARY_DEPENDENCIES += -fopenmp -lpthread -lgomp -lm
-
-# The set of object files for your application.
-APPLICATION_OBJS := simple_bundle_adjuster.o
-
-all: simple_bundle_adjuster
-
-simple_bundle_adjuster: $(APPLICATION_OBJS)
-	g++ \
-		$(APPLICATION_OBJS) \
-		$(CERES_LIBRARY_PATH) \
-		$(CERES_LIBRARY) \
-		$(CERES_LIBRARY_DEPENDENCIES) \
-		-o simple_bundle_adjuster
-
-# Disabling debug asserts via -DNDEBUG helps make Eigen faster, at the cost of
-# not getting handy assert failures when there are issues in your code.
-CFLAGS := -O2 -DNDEBUG
-
-# If you have files ending in .cpp instead of .cc, fix the next line
-# appropriately.
-%.o: %.cc $(DEPS)
-	g++ -c -o $@ $< $(CFLAGS) $(INCLUDES)
diff --git a/third_party/ceres/examples/bal_problem.cc b/third_party/ceres/examples/bal_problem.cc
index ceac89a..ccf7449 100644
--- a/third_party/ceres/examples/bal_problem.cc
+++ b/third_party/ceres/examples/bal_problem.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -30,22 +30,22 @@
 
 #include "bal_problem.h"
 
+#include <algorithm>
 #include <cstdio>
-#include <cstdlib>
 #include <fstream>
+#include <functional>
+#include <random>
 #include <string>
 #include <vector>
 
 #include "Eigen/Core"
 #include "ceres/rotation.h"
 #include "glog/logging.h"
-#include "random.h"
 
-namespace ceres {
-namespace examples {
+namespace ceres::examples {
 namespace {
-typedef Eigen::Map<Eigen::VectorXd> VectorRef;
-typedef Eigen::Map<const Eigen::VectorXd> ConstVectorRef;
+using VectorRef = Eigen::Map<Eigen::VectorXd>;
+using ConstVectorRef = Eigen::Map<const Eigen::VectorXd>;
 
 template <typename T>
 void FscanfOrDie(FILE* fptr, const char* format, T* value) {
@@ -55,15 +55,14 @@
   }
 }
 
-void PerturbPoint3(const double sigma, double* point) {
+void PerturbPoint3(std::function<double()> dist, double* point) {
   for (int i = 0; i < 3; ++i) {
-    point[i] += RandNormal() * sigma;
+    point[i] += dist();
   }
 }
 
 double Median(std::vector<double>* data) {
-  int n = data->size();
-  std::vector<double>::iterator mid_point = data->begin() + n / 2;
+  auto mid_point = data->begin() + data->size() / 2;
   std::nth_element(data->begin(), mid_point, data->end());
   return *mid_point;
 }
@@ -73,12 +72,12 @@
 BALProblem::BALProblem(const std::string& filename, bool use_quaternions) {
   FILE* fptr = fopen(filename.c_str(), "r");
 
-  if (fptr == NULL) {
+  if (fptr == nullptr) {
     LOG(FATAL) << "Error: unable to open file " << filename;
     return;
   };
 
-  // This wil die horribly on invalid files. Them's the breaks.
+  // This will die horribly on invalid files. Them's the breaks.
   FscanfOrDie(fptr, "%d", &num_cameras_);
   FscanfOrDie(fptr, "%d", &num_points_);
   FscanfOrDie(fptr, "%d", &num_observations_);
@@ -111,7 +110,7 @@
   if (use_quaternions) {
     // Switch the angle-axis rotations to quaternions.
     num_parameters_ = 10 * num_cameras_ + 3 * num_points_;
-    double* quaternion_parameters = new double[num_parameters_];
+    auto* quaternion_parameters = new double[num_parameters_];
     double* original_cursor = parameters_;
     double* quaternion_cursor = quaternion_parameters;
     for (int i = 0; i < num_cameras_; ++i) {
@@ -137,7 +136,7 @@
 void BALProblem::WriteToFile(const std::string& filename) const {
   FILE* fptr = fopen(filename.c_str(), "w");
 
-  if (fptr == NULL) {
+  if (fptr == nullptr) {
     LOG(FATAL) << "Error: unable to open file " << filename;
     return;
   };
@@ -161,8 +160,8 @@
     } else {
       memcpy(angleaxis, parameters_ + 9 * i, 9 * sizeof(double));
     }
-    for (int j = 0; j < 9; ++j) {
-      fprintf(fptr, "%.16g\n", angleaxis[j]);
+    for (double coeff : angleaxis) {
+      fprintf(fptr, "%.16g\n", coeff);
     }
   }
 
@@ -297,14 +296,20 @@
   CHECK_GE(point_sigma, 0.0);
   CHECK_GE(rotation_sigma, 0.0);
   CHECK_GE(translation_sigma, 0.0);
-
+  std::mt19937 prng;
+  std::normal_distribution<double> point_noise_distribution(0.0, point_sigma);
   double* points = mutable_points();
   if (point_sigma > 0) {
     for (int i = 0; i < num_points_; ++i) {
-      PerturbPoint3(point_sigma, points + 3 * i);
+      PerturbPoint3(std::bind(point_noise_distribution, std::ref(prng)),
+                    points + 3 * i);
     }
   }
 
+  std::normal_distribution<double> rotation_noise_distribution(0.0,
+                                                               point_sigma);
+  std::normal_distribution<double> translation_noise_distribution(
+      0.0, translation_sigma);
   for (int i = 0; i < num_cameras_; ++i) {
     double* camera = mutable_cameras() + camera_block_size() * i;
 
@@ -314,12 +319,14 @@
     // representation.
     CameraToAngleAxisAndCenter(camera, angle_axis, center);
     if (rotation_sigma > 0.0) {
-      PerturbPoint3(rotation_sigma, angle_axis);
+      PerturbPoint3(std::bind(rotation_noise_distribution, std::ref(prng)),
+                    angle_axis);
     }
     AngleAxisAndCenterToCamera(angle_axis, center, camera);
 
     if (translation_sigma > 0.0) {
-      PerturbPoint3(translation_sigma, camera + camera_block_size() - 6);
+      PerturbPoint3(std::bind(translation_noise_distribution, std::ref(prng)),
+                    camera + camera_block_size() - 6);
     }
   }
 }
@@ -331,5 +338,4 @@
   delete[] parameters_;
 }
 
-}  // namespace examples
-}  // namespace ceres
+}  // namespace ceres::examples
diff --git a/third_party/ceres/examples/bal_problem.h b/third_party/ceres/examples/bal_problem.h
index e6d4ace..93effc3 100644
--- a/third_party/ceres/examples/bal_problem.h
+++ b/third_party/ceres/examples/bal_problem.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -39,8 +39,7 @@
 
 #include <string>
 
-namespace ceres {
-namespace examples {
+namespace ceres::examples {
 
 class BALProblem {
  public:
@@ -105,7 +104,6 @@
   double* parameters_;
 };
 
-}  // namespace examples
-}  // namespace ceres
+}  // namespace ceres::examples
 
 #endif  // CERES_EXAMPLES_BAL_PROBLEM_H_
diff --git a/third_party/ceres/examples/bicubic_interpolation.cc b/third_party/ceres/examples/bicubic_interpolation.cc
new file mode 100644
index 0000000..21b3c7e
--- /dev/null
+++ b/third_party/ceres/examples/bicubic_interpolation.cc
@@ -0,0 +1,155 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Bicubic interpolation with automatic differentiation
+//
+// We will use estimation of 2d shift as a sample problem for bicubic
+// interpolation.
+//
+// Let us define f(x, y) = x * x - y * x + y * y
+// And optimize cost function sum_i [f(x_i + s_x, y_i + s_y) - v_i]^2
+//
+// Bicubic interpolation of f(x, y) will be exact, thus we can expect close to
+// perfect convergence
+
+#include <utility>
+
+#include "ceres/ceres.h"
+#include "ceres/cubic_interpolation.h"
+#include "glog/logging.h"
+
+using Grid = ceres::Grid2D<double>;
+using Interpolator = ceres::BiCubicInterpolator<Grid>;
+
+// Cost-function using autodiff interface of BiCubicInterpolator
+struct AutoDiffBiCubicCost {
+  EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
+
+  template <typename T>
+  bool operator()(const T* s, T* residual) const {
+    using Vector2T = Eigen::Matrix<T, 2, 1>;
+    Eigen::Map<const Vector2T> shift(s);
+
+    const Vector2T point = point_ + shift;
+
+    T v;
+    interpolator_.Evaluate(point.y(), point.x(), &v);
+
+    *residual = v - value_;
+    return true;
+  }
+
+  AutoDiffBiCubicCost(const Interpolator& interpolator,
+                      Eigen::Vector2d point,
+                      double value)
+      : point_(std::move(point)), value_(value), interpolator_(interpolator) {}
+
+  static ceres::CostFunction* Create(const Interpolator& interpolator,
+                                     const Eigen::Vector2d& point,
+                                     double value) {
+    return new ceres::AutoDiffCostFunction<AutoDiffBiCubicCost, 1, 2>(
+        interpolator, point, value);
+  }
+
+  const Eigen::Vector2d point_;
+  const double value_;
+  const Interpolator& interpolator_;
+};
+
+// Function for input data generation
+static double f(const double& x, const double& y) {
+  return x * x - y * x + y * y;
+}
+
+int main(int argc, char** argv) {
+  google::InitGoogleLogging(argv[0]);
+  // Problem sizes
+  const int kGridRowsHalf = 9;
+  const int kGridColsHalf = 11;
+  const int kGridRows = 2 * kGridRowsHalf + 1;
+  const int kGridCols = 2 * kGridColsHalf + 1;
+  const int kPoints = 4;
+
+  const Eigen::Vector2d shift(1.234, 2.345);
+  const std::array<Eigen::Vector2d, kPoints> points = {
+      Eigen::Vector2d{-2., -3.},
+      Eigen::Vector2d{-2., 3.},
+      Eigen::Vector2d{2., 3.},
+      Eigen::Vector2d{2., -3.}};
+
+  // Data is a row-major array of kGridRows x kGridCols values of function
+  // f(x, y) on the grid, with x in {-kGridColsHalf, ..., +kGridColsHalf},
+  // and y in {-kGridRowsHalf, ..., +kGridRowsHalf}
+  double data[kGridRows * kGridCols];
+  for (int i = 0; i < kGridRows; ++i) {
+    for (int j = 0; j < kGridCols; ++j) {
+      // Using row-major order
+      int index = i * kGridCols + j;
+      double y = i - kGridRowsHalf;
+      double x = j - kGridColsHalf;
+
+      data[index] = f(x, y);
+    }
+  }
+  const Grid grid(data,
+                  -kGridRowsHalf,
+                  kGridRowsHalf + 1,
+                  -kGridColsHalf,
+                  kGridColsHalf + 1);
+  const Interpolator interpolator(grid);
+
+  Eigen::Vector2d shift_estimate(3.1415, 1.337);
+
+  ceres::Problem problem;
+  problem.AddParameterBlock(shift_estimate.data(), 2);
+
+  for (const auto& p : points) {
+    const Eigen::Vector2d shifted = p + shift;
+
+    const double v = f(shifted.x(), shifted.y());
+    problem.AddResidualBlock(AutoDiffBiCubicCost::Create(interpolator, p, v),
+                             nullptr,
+                             shift_estimate.data());
+  }
+
+  ceres::Solver::Options options;
+  options.minimizer_progress_to_stdout = true;
+
+  ceres::Solver::Summary summary;
+  ceres::Solve(options, &problem, &summary);
+  std::cout << summary.BriefReport() << '\n';
+
+  std::cout << "Bicubic interpolation with automatic derivatives:\n";
+  std::cout << "Estimated shift: " << shift_estimate.transpose()
+            << ", ground-truth: " << shift.transpose()
+            << " (error: " << (shift_estimate - shift).transpose() << ")"
+            << std::endl;
+
+  CHECK_LT((shift_estimate - shift).norm(), 1e-9);
+  return 0;
+}
diff --git a/third_party/ceres/examples/bicubic_interpolation_analytic.cc b/third_party/ceres/examples/bicubic_interpolation_analytic.cc
new file mode 100644
index 0000000..4b79d56
--- /dev/null
+++ b/third_party/ceres/examples/bicubic_interpolation_analytic.cc
@@ -0,0 +1,166 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Bicubic interpolation with analytic differentiation
+//
+// We will use estimation of 2d shift as a sample problem for bicubic
+// interpolation.
+//
+// Let us define f(x, y) = x * x - y * x + y * y
+// And optimize cost function sum_i [f(x_i + s_x, y_i + s_y) - v_i]^2
+//
+// Bicubic interpolation of f(x, y) will be exact, thus we can expect close to
+// perfect convergence
+
+#include <utility>
+
+#include "ceres/ceres.h"
+#include "ceres/cubic_interpolation.h"
+#include "glog/logging.h"
+
+using Grid = ceres::Grid2D<double>;
+using Interpolator = ceres::BiCubicInterpolator<Grid>;
+
+// Cost-function using analytic interface of BiCubicInterpolator
+struct AnalyticBiCubicCost : public ceres::CostFunction {
+  EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
+
+  bool Evaluate(double const* const* parameters,
+                double* residuals,
+                double** jacobians) const override {
+    Eigen::Map<const Eigen::Vector2d> shift(parameters[0]);
+
+    const Eigen::Vector2d point = point_ + shift;
+
+    double* f = residuals;
+    double* dfdr = nullptr;
+    double* dfdc = nullptr;
+    if (jacobians && jacobians[0]) {
+      dfdc = jacobians[0];
+      dfdr = dfdc + 1;
+    }
+
+    interpolator_.Evaluate(point.y(), point.x(), f, dfdr, dfdc);
+
+    if (residuals) {
+      *f -= value_;
+    }
+    return true;
+  }
+
+  AnalyticBiCubicCost(const Interpolator& interpolator,
+                      Eigen::Vector2d point,
+                      double value)
+      : point_(std::move(point)), value_(value), interpolator_(interpolator) {
+    set_num_residuals(1);
+    *mutable_parameter_block_sizes() = {2};
+  }
+
+  static ceres::CostFunction* Create(const Interpolator& interpolator,
+                                     const Eigen::Vector2d& point,
+                                     double value) {
+    return new AnalyticBiCubicCost(interpolator, point, value);
+  }
+
+  const Eigen::Vector2d point_;
+  const double value_;
+  const Interpolator& interpolator_;
+};
+
+// Function for input data generation
+static double f(const double& x, const double& y) {
+  return x * x - y * x + y * y;
+}
+
+int main(int argc, char** argv) {
+  google::InitGoogleLogging(argv[0]);
+  // Problem sizes
+  const int kGridRowsHalf = 9;
+  const int kGridColsHalf = 11;
+  const int kGridRows = 2 * kGridRowsHalf + 1;
+  const int kGridCols = 2 * kGridColsHalf + 1;
+  const int kPoints = 4;
+
+  const Eigen::Vector2d shift(1.234, 2.345);
+  const std::array<Eigen::Vector2d, kPoints> points = {
+      Eigen::Vector2d{-2., -3.},
+      Eigen::Vector2d{-2., 3.},
+      Eigen::Vector2d{2., 3.},
+      Eigen::Vector2d{2., -3.}};
+
+  // Data is a row-major array of kGridRows x kGridCols values of function
+  // f(x, y) on the grid, with x in {-kGridColsHalf, ..., +kGridColsHalf},
+  // and y in {-kGridRowsHalf, ..., +kGridRowsHalf}
+  double data[kGridRows * kGridCols];
+  for (int i = 0; i < kGridRows; ++i) {
+    for (int j = 0; j < kGridCols; ++j) {
+      // Using row-major order
+      int index = i * kGridCols + j;
+      double y = i - kGridRowsHalf;
+      double x = j - kGridColsHalf;
+
+      data[index] = f(x, y);
+    }
+  }
+  const Grid grid(data,
+                  -kGridRowsHalf,
+                  kGridRowsHalf + 1,
+                  -kGridColsHalf,
+                  kGridColsHalf + 1);
+  const Interpolator interpolator(grid);
+
+  Eigen::Vector2d shift_estimate(3.1415, 1.337);
+
+  ceres::Problem problem;
+  problem.AddParameterBlock(shift_estimate.data(), 2);
+
+  for (const auto& p : points) {
+    const Eigen::Vector2d shifted = p + shift;
+
+    const double v = f(shifted.x(), shifted.y());
+    problem.AddResidualBlock(AnalyticBiCubicCost::Create(interpolator, p, v),
+                             nullptr,
+                             shift_estimate.data());
+  }
+
+  ceres::Solver::Options options;
+  options.minimizer_progress_to_stdout = true;
+
+  ceres::Solver::Summary summary;
+  ceres::Solve(options, &problem, &summary);
+  std::cout << summary.BriefReport() << '\n';
+
+  std::cout << "Bicubic interpolation with analytic derivatives:\n";
+  std::cout << "Estimated shift: " << shift_estimate.transpose()
+            << ", ground-truth: " << shift.transpose()
+            << " (error: " << (shift_estimate - shift).transpose() << ")"
+            << std::endl;
+
+  CHECK_LT((shift_estimate - shift).norm(), 1e-9);
+  return 0;
+}
diff --git a/third_party/ceres/examples/bundle_adjuster.cc b/third_party/ceres/examples/bundle_adjuster.cc
index e7b154e..582ae2e 100644
--- a/third_party/ceres/examples/bundle_adjuster.cc
+++ b/third_party/ceres/examples/bundle_adjuster.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -55,7 +55,9 @@
 #include <cmath>
 #include <cstdio>
 #include <cstdlib>
+#include <memory>
 #include <string>
+#include <thread>
 #include <vector>
 
 #include "bal_problem.h"
@@ -80,34 +82,45 @@
               "automatic, cameras, points, cameras,points, points,cameras");
 
 DEFINE_string(linear_solver, "sparse_schur", "Options are: "
-              "sparse_schur, dense_schur, iterative_schur, sparse_normal_cholesky, "
-              "dense_qr, dense_normal_cholesky and cgnr.");
+              "sparse_schur, dense_schur, iterative_schur, "
+              "sparse_normal_cholesky, dense_qr, dense_normal_cholesky, "
+              "and cgnr.");
 DEFINE_bool(explicit_schur_complement, false, "If using ITERATIVE_SCHUR "
             "then explicitly compute the Schur complement.");
 DEFINE_string(preconditioner, "jacobi", "Options are: "
-              "identity, jacobi, schur_jacobi, cluster_jacobi, "
+              "identity, jacobi, schur_jacobi, schur_power_series_expansion, cluster_jacobi, "
               "cluster_tridiagonal.");
 DEFINE_string(visibility_clustering, "canonical_views",
               "single_linkage, canonical_views");
+DEFINE_bool(use_spse_initialization, false,
+            "Use power series expansion to initialize the solution in ITERATIVE_SCHUR linear solver.");
 
 DEFINE_string(sparse_linear_algebra_library, "suite_sparse",
-              "Options are: suite_sparse and cx_sparse.");
+              "Options are: suite_sparse, accelerate_sparse, eigen_sparse, and "
+              "cuda_sparse.");
 DEFINE_string(dense_linear_algebra_library, "eigen",
-              "Options are: eigen and lapack.");
-DEFINE_string(ordering, "automatic", "Options are: automatic, user.");
+              "Options are: eigen, lapack, and cuda");
+DEFINE_string(ordering_type, "amd", "Options are: amd, nesdis");
+DEFINE_string(linear_solver_ordering, "user",
+              "Options are: automatic and user");
 
 DEFINE_bool(use_quaternions, false, "If true, uses quaternions to represent "
             "rotations. If false, angle axis is used.");
-DEFINE_bool(use_local_parameterization, false, "For quaternions, use a local "
-            "parameterization.");
+DEFINE_bool(use_manifolds, false, "For quaternions, use a manifold.");
 DEFINE_bool(robustify, false, "Use a robust loss function.");
 
 DEFINE_double(eta, 1e-2, "Default value for eta. Eta determines the "
               "accuracy of each linear solve of the truncated newton step. "
               "Changing this parameter can affect solve performance.");
 
-DEFINE_int32(num_threads, 1, "Number of threads.");
+DEFINE_int32(num_threads, -1, "Number of threads. -1 = std::thread::hardware_concurrency.");
 DEFINE_int32(num_iterations, 5, "Number of iterations.");
+DEFINE_int32(max_linear_solver_iterations, 500, "Maximum number of iterations"
+            " for solution of linear system.");
+DEFINE_double(spse_tolerance, 0.1,
+             "Tolerance to reach during the iterations of power series expansion initialization or preconditioning.");
+DEFINE_int32(max_num_spse_iterations, 5,
+             "Maximum number of iterations for power series expansion initialization or preconditioning.");
 DEFINE_double(max_solver_time, 1e32, "Maximum solve time in seconds.");
 DEFINE_bool(nonmonotonic_steps, false, "Trust region algorithm can use"
             " nonmonotic steps.");
@@ -120,7 +133,7 @@
               "perturbation.");
 DEFINE_int32(random_seed, 38401, "Random seed used to set the state "
              "of the pseudo random number generator used to generate "
-             "the pertubations.");
+             "the perturbations.");
 DEFINE_bool(line_search, false, "Use a line search instead of trust region "
             "algorithm.");
 DEFINE_bool(mixed_precision_solves, false, "Use mixed precision solves.");
@@ -128,29 +141,41 @@
 DEFINE_string(initial_ply, "", "Export the BAL file data as a PLY file.");
 DEFINE_string(final_ply, "", "Export the refined BAL file data as a PLY "
               "file.");
-
 // clang-format on
 
-namespace ceres {
-namespace examples {
+namespace ceres::examples {
 namespace {
 
 void SetLinearSolver(Solver::Options* options) {
-  CHECK(StringToLinearSolverType(FLAGS_linear_solver,
+  CHECK(StringToLinearSolverType(CERES_GET_FLAG(FLAGS_linear_solver),
                                  &options->linear_solver_type));
-  CHECK(StringToPreconditionerType(FLAGS_preconditioner,
+  CHECK(StringToPreconditionerType(CERES_GET_FLAG(FLAGS_preconditioner),
                                    &options->preconditioner_type));
-  CHECK(StringToVisibilityClusteringType(FLAGS_visibility_clustering,
-                                         &options->visibility_clustering_type));
+  CHECK(StringToVisibilityClusteringType(
+      CERES_GET_FLAG(FLAGS_visibility_clustering),
+      &options->visibility_clustering_type));
   CHECK(StringToSparseLinearAlgebraLibraryType(
-      FLAGS_sparse_linear_algebra_library,
+      CERES_GET_FLAG(FLAGS_sparse_linear_algebra_library),
       &options->sparse_linear_algebra_library_type));
   CHECK(StringToDenseLinearAlgebraLibraryType(
-      FLAGS_dense_linear_algebra_library,
+      CERES_GET_FLAG(FLAGS_dense_linear_algebra_library),
       &options->dense_linear_algebra_library_type));
-  options->use_explicit_schur_complement = FLAGS_explicit_schur_complement;
-  options->use_mixed_precision_solves = FLAGS_mixed_precision_solves;
-  options->max_num_refinement_iterations = FLAGS_max_num_refinement_iterations;
+  CHECK(
+      StringToLinearSolverOrderingType(CERES_GET_FLAG(FLAGS_ordering_type),
+                                       &options->linear_solver_ordering_type));
+  options->use_explicit_schur_complement =
+      CERES_GET_FLAG(FLAGS_explicit_schur_complement);
+  options->use_mixed_precision_solves =
+      CERES_GET_FLAG(FLAGS_mixed_precision_solves);
+  options->max_num_refinement_iterations =
+      CERES_GET_FLAG(FLAGS_max_num_refinement_iterations);
+  options->max_linear_solver_iterations =
+      CERES_GET_FLAG(FLAGS_max_linear_solver_iterations);
+  options->use_spse_initialization =
+      CERES_GET_FLAG(FLAGS_use_spse_initialization);
+  options->spse_tolerance = CERES_GET_FLAG(FLAGS_spse_tolerance);
+  options->max_num_spse_iterations =
+      CERES_GET_FLAG(FLAGS_max_num_spse_iterations);
 }
 
 void SetOrdering(BALProblem* bal_problem, Solver::Options* options) {
@@ -163,23 +188,27 @@
   double* cameras = bal_problem->mutable_cameras();
 
   if (options->use_inner_iterations) {
-    if (FLAGS_blocks_for_inner_iterations == "cameras") {
+    if (CERES_GET_FLAG(FLAGS_blocks_for_inner_iterations) == "cameras") {
       LOG(INFO) << "Camera blocks for inner iterations";
-      options->inner_iteration_ordering.reset(new ParameterBlockOrdering);
+      options->inner_iteration_ordering =
+          std::make_shared<ParameterBlockOrdering>();
       for (int i = 0; i < num_cameras; ++i) {
         options->inner_iteration_ordering->AddElementToGroup(
             cameras + camera_block_size * i, 0);
       }
-    } else if (FLAGS_blocks_for_inner_iterations == "points") {
+    } else if (CERES_GET_FLAG(FLAGS_blocks_for_inner_iterations) == "points") {
       LOG(INFO) << "Point blocks for inner iterations";
-      options->inner_iteration_ordering.reset(new ParameterBlockOrdering);
+      options->inner_iteration_ordering =
+          std::make_shared<ParameterBlockOrdering>();
       for (int i = 0; i < num_points; ++i) {
         options->inner_iteration_ordering->AddElementToGroup(
             points + point_block_size * i, 0);
       }
-    } else if (FLAGS_blocks_for_inner_iterations == "cameras,points") {
+    } else if (CERES_GET_FLAG(FLAGS_blocks_for_inner_iterations) ==
+               "cameras,points") {
       LOG(INFO) << "Camera followed by point blocks for inner iterations";
-      options->inner_iteration_ordering.reset(new ParameterBlockOrdering);
+      options->inner_iteration_ordering =
+          std::make_shared<ParameterBlockOrdering>();
       for (int i = 0; i < num_cameras; ++i) {
         options->inner_iteration_ordering->AddElementToGroup(
             cameras + camera_block_size * i, 0);
@@ -188,9 +217,11 @@
         options->inner_iteration_ordering->AddElementToGroup(
             points + point_block_size * i, 1);
       }
-    } else if (FLAGS_blocks_for_inner_iterations == "points,cameras") {
+    } else if (CERES_GET_FLAG(FLAGS_blocks_for_inner_iterations) ==
+               "points,cameras") {
       LOG(INFO) << "Point followed by camera blocks for inner iterations";
-      options->inner_iteration_ordering.reset(new ParameterBlockOrdering);
+      options->inner_iteration_ordering =
+          std::make_shared<ParameterBlockOrdering>();
       for (int i = 0; i < num_cameras; ++i) {
         options->inner_iteration_ordering->AddElementToGroup(
             cameras + camera_block_size * i, 1);
@@ -199,11 +230,12 @@
         options->inner_iteration_ordering->AddElementToGroup(
             points + point_block_size * i, 0);
       }
-    } else if (FLAGS_blocks_for_inner_iterations == "automatic") {
+    } else if (CERES_GET_FLAG(FLAGS_blocks_for_inner_iterations) ==
+               "automatic") {
       LOG(INFO) << "Choosing automatic blocks for inner iterations";
     } else {
       LOG(FATAL) << "Unknown block type for inner iterations: "
-                 << FLAGS_blocks_for_inner_iterations;
+                 << CERES_GET_FLAG(FLAGS_blocks_for_inner_iterations);
     }
   }
 
@@ -213,46 +245,54 @@
   // ITERATIVE_SCHUR solvers make use of this specialized
   // structure.
   //
-  // This can either be done by specifying Options::ordering_type =
-  // ceres::SCHUR, in which case Ceres will automatically determine
-  // the right ParameterBlock ordering, or by manually specifying a
-  // suitable ordering vector and defining
-  // Options::num_eliminate_blocks.
-  if (FLAGS_ordering == "automatic") {
-    return;
+  // This can either be done by specifying a
+  // Options::linear_solver_ordering or having Ceres figure it out
+  // automatically using a greedy maximum independent set algorithm.
+  if (CERES_GET_FLAG(FLAGS_linear_solver_ordering) == "user") {
+    auto* ordering = new ceres::ParameterBlockOrdering;
+
+    // The points come before the cameras.
+    for (int i = 0; i < num_points; ++i) {
+      ordering->AddElementToGroup(points + point_block_size * i, 0);
+    }
+
+    for (int i = 0; i < num_cameras; ++i) {
+      // When using axis-angle, there is a single parameter block for
+      // the entire camera.
+      ordering->AddElementToGroup(cameras + camera_block_size * i, 1);
+    }
+
+    options->linear_solver_ordering.reset(ordering);
   }
-
-  ceres::ParameterBlockOrdering* ordering = new ceres::ParameterBlockOrdering;
-
-  // The points come before the cameras.
-  for (int i = 0; i < num_points; ++i) {
-    ordering->AddElementToGroup(points + point_block_size * i, 0);
-  }
-
-  for (int i = 0; i < num_cameras; ++i) {
-    // When using axis-angle, there is a single parameter block for
-    // the entire camera.
-    ordering->AddElementToGroup(cameras + camera_block_size * i, 1);
-  }
-
-  options->linear_solver_ordering.reset(ordering);
 }
 
 void SetMinimizerOptions(Solver::Options* options) {
-  options->max_num_iterations = FLAGS_num_iterations;
+  options->max_num_iterations = CERES_GET_FLAG(FLAGS_num_iterations);
   options->minimizer_progress_to_stdout = true;
-  options->num_threads = FLAGS_num_threads;
-  options->eta = FLAGS_eta;
-  options->max_solver_time_in_seconds = FLAGS_max_solver_time;
-  options->use_nonmonotonic_steps = FLAGS_nonmonotonic_steps;
-  if (FLAGS_line_search) {
+  if (CERES_GET_FLAG(FLAGS_num_threads) == -1) {
+    const int num_available_threads =
+        static_cast<int>(std::thread::hardware_concurrency());
+    if (num_available_threads > 0) {
+      options->num_threads = num_available_threads;
+    }
+  } else {
+    options->num_threads = CERES_GET_FLAG(FLAGS_num_threads);
+  }
+  CHECK_GE(options->num_threads, 1);
+
+  options->eta = CERES_GET_FLAG(FLAGS_eta);
+  options->max_solver_time_in_seconds = CERES_GET_FLAG(FLAGS_max_solver_time);
+  options->use_nonmonotonic_steps = CERES_GET_FLAG(FLAGS_nonmonotonic_steps);
+  if (CERES_GET_FLAG(FLAGS_line_search)) {
     options->minimizer_type = ceres::LINE_SEARCH;
   }
 
-  CHECK(StringToTrustRegionStrategyType(FLAGS_trust_region_strategy,
-                                        &options->trust_region_strategy_type));
-  CHECK(StringToDoglegType(FLAGS_dogleg, &options->dogleg_type));
-  options->use_inner_iterations = FLAGS_inner_iterations;
+  CHECK(StringToTrustRegionStrategyType(
+      CERES_GET_FLAG(FLAGS_trust_region_strategy),
+      &options->trust_region_strategy_type));
+  CHECK(
+      StringToDoglegType(CERES_GET_FLAG(FLAGS_dogleg), &options->dogleg_type));
+  options->use_inner_iterations = CERES_GET_FLAG(FLAGS_inner_iterations);
 }
 
 void SetSolverOptionsFromFlags(BALProblem* bal_problem,
@@ -276,16 +316,17 @@
     CostFunction* cost_function;
     // Each Residual block takes a point and a camera as input and
     // outputs a 2 dimensional residual.
-    cost_function = (FLAGS_use_quaternions)
+    cost_function = (CERES_GET_FLAG(FLAGS_use_quaternions))
                         ? SnavelyReprojectionErrorWithQuaternions::Create(
                               observations[2 * i + 0], observations[2 * i + 1])
                         : SnavelyReprojectionError::Create(
                               observations[2 * i + 0], observations[2 * i + 1]);
 
     // If enabled use Huber's loss function.
-    LossFunction* loss_function = FLAGS_robustify ? new HuberLoss(1.0) : NULL;
+    LossFunction* loss_function =
+        CERES_GET_FLAG(FLAGS_robustify) ? new HuberLoss(1.0) : nullptr;
 
-    // Each observation correponds to a pair of a camera and a point
+    // Each observation corresponds to a pair of a camera and a point
     // which are identified by camera_index()[i] and point_index()[i]
     // respectively.
     double* camera =
@@ -294,60 +335,60 @@
     problem->AddResidualBlock(cost_function, loss_function, camera, point);
   }
 
-  if (FLAGS_use_quaternions && FLAGS_use_local_parameterization) {
-    LocalParameterization* camera_parameterization =
-        new ProductParameterization(new QuaternionParameterization(),
-                                    new IdentityParameterization(6));
+  if (CERES_GET_FLAG(FLAGS_use_quaternions) &&
+      CERES_GET_FLAG(FLAGS_use_manifolds)) {
+    Manifold* camera_manifold =
+        new ProductManifold<QuaternionManifold, EuclideanManifold<6>>{};
     for (int i = 0; i < bal_problem->num_cameras(); ++i) {
-      problem->SetParameterization(cameras + camera_block_size * i,
-                                   camera_parameterization);
+      problem->SetManifold(cameras + camera_block_size * i, camera_manifold);
     }
   }
 }
 
 void SolveProblem(const char* filename) {
-  BALProblem bal_problem(filename, FLAGS_use_quaternions);
+  BALProblem bal_problem(filename, CERES_GET_FLAG(FLAGS_use_quaternions));
 
-  if (!FLAGS_initial_ply.empty()) {
-    bal_problem.WriteToPLYFile(FLAGS_initial_ply);
+  if (!CERES_GET_FLAG(FLAGS_initial_ply).empty()) {
+    bal_problem.WriteToPLYFile(CERES_GET_FLAG(FLAGS_initial_ply));
   }
 
   Problem problem;
 
-  srand(FLAGS_random_seed);
+  srand(CERES_GET_FLAG(FLAGS_random_seed));
   bal_problem.Normalize();
-  bal_problem.Perturb(
-      FLAGS_rotation_sigma, FLAGS_translation_sigma, FLAGS_point_sigma);
+  bal_problem.Perturb(CERES_GET_FLAG(FLAGS_rotation_sigma),
+                      CERES_GET_FLAG(FLAGS_translation_sigma),
+                      CERES_GET_FLAG(FLAGS_point_sigma));
 
   BuildProblem(&bal_problem, &problem);
   Solver::Options options;
   SetSolverOptionsFromFlags(&bal_problem, &options);
   options.gradient_tolerance = 1e-16;
   options.function_tolerance = 1e-16;
+  options.parameter_tolerance = 1e-16;
   Solver::Summary summary;
   Solve(options, &problem, &summary);
   std::cout << summary.FullReport() << "\n";
 
-  if (!FLAGS_final_ply.empty()) {
-    bal_problem.WriteToPLYFile(FLAGS_final_ply);
+  if (!CERES_GET_FLAG(FLAGS_final_ply).empty()) {
+    bal_problem.WriteToPLYFile(CERES_GET_FLAG(FLAGS_final_ply));
   }
 }
 
 }  // namespace
-}  // namespace examples
-}  // namespace ceres
+}  // namespace ceres::examples
 
 int main(int argc, char** argv) {
   GFLAGS_NAMESPACE::ParseCommandLineFlags(&argc, &argv, true);
   google::InitGoogleLogging(argv[0]);
-  if (FLAGS_input.empty()) {
+  if (CERES_GET_FLAG(FLAGS_input).empty()) {
     LOG(ERROR) << "Usage: bundle_adjuster --input=bal_problem";
     return 1;
   }
 
-  CHECK(FLAGS_use_quaternions || !FLAGS_use_local_parameterization)
-      << "--use_local_parameterization can only be used with "
-      << "--use_quaternions.";
-  ceres::examples::SolveProblem(FLAGS_input.c_str());
+  CHECK(CERES_GET_FLAG(FLAGS_use_quaternions) ||
+        !CERES_GET_FLAG(FLAGS_use_manifolds))
+      << "--use_manifolds can only be used with --use_quaternions.";
+  ceres::examples::SolveProblem(CERES_GET_FLAG(FLAGS_input).c_str());
   return 0;
 }
diff --git a/third_party/ceres/examples/circle_fit.cc b/third_party/ceres/examples/circle_fit.cc
index c542475..fd848d9 100644
--- a/third_party/ceres/examples/circle_fit.cc
+++ b/third_party/ceres/examples/circle_fit.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -57,14 +57,6 @@
 #include "gflags/gflags.h"
 #include "glog/logging.h"
 
-using ceres::AutoDiffCostFunction;
-using ceres::CauchyLoss;
-using ceres::CostFunction;
-using ceres::LossFunction;
-using ceres::Problem;
-using ceres::Solve;
-using ceres::Solver;
-
 DEFINE_double(robust_threshold,
               0.0,
               "Robust loss parameter. Set to 0 for normal squared error (no "
@@ -128,21 +120,21 @@
   // Parameterize r as m^2 so that it can't be negative.
   double m = sqrt(r);
 
-  Problem problem;
+  ceres::Problem problem;
 
   // Configure the loss function.
-  LossFunction* loss = NULL;
-  if (FLAGS_robust_threshold) {
-    loss = new CauchyLoss(FLAGS_robust_threshold);
+  ceres::LossFunction* loss = nullptr;
+  if (CERES_GET_FLAG(FLAGS_robust_threshold)) {
+    loss = new ceres::CauchyLoss(CERES_GET_FLAG(FLAGS_robust_threshold));
   }
 
   // Add the residuals.
   double xx, yy;
   int num_points = 0;
   while (scanf("%lf %lf\n", &xx, &yy) == 2) {
-    CostFunction* cost =
-        new AutoDiffCostFunction<DistanceFromCircleCost, 1, 1, 1, 1>(
-            new DistanceFromCircleCost(xx, yy));
+    ceres::CostFunction* cost =
+        new ceres::AutoDiffCostFunction<DistanceFromCircleCost, 1, 1, 1, 1>(xx,
+                                                                            yy);
     problem.AddResidualBlock(cost, loss, &x, &y, &m);
     num_points++;
   }
@@ -150,11 +142,11 @@
   std::cout << "Got " << num_points << " points.\n";
 
   // Build and solve the problem.
-  Solver::Options options;
+  ceres::Solver::Options options;
   options.max_num_iterations = 500;
   options.linear_solver_type = ceres::DENSE_QR;
-  Solver::Summary summary;
-  Solve(options, &problem, &summary);
+  ceres::Solver::Summary summary;
+  ceres::Solve(options, &problem, &summary);
 
   // Recover r from m.
   r = m * m;
diff --git a/third_party/ceres/examples/curve_fitting.cc b/third_party/ceres/examples/curve_fitting.cc
index fc7ff94..105402e 100644
--- a/third_party/ceres/examples/curve_fitting.cc
+++ b/third_party/ceres/examples/curve_fitting.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -27,16 +27,13 @@
 // POSSIBILITY OF SUCH DAMAGE.
 //
 // Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// This example fits the curve f(x;m,c) = e^(m * x + c) to data, minimizing the
+// sum squared loss.
 
 #include "ceres/ceres.h"
 #include "glog/logging.h"
 
-using ceres::AutoDiffCostFunction;
-using ceres::CostFunction;
-using ceres::Problem;
-using ceres::Solve;
-using ceres::Solver;
-
 // Data generated using the following octave code.
 //   randn('seed', 23497);
 //   m = 0.3;
@@ -137,28 +134,30 @@
 int main(int argc, char** argv) {
   google::InitGoogleLogging(argv[0]);
 
-  double m = 0.0;
-  double c = 0.0;
+  const double initial_m = 0.0;
+  const double initial_c = 0.0;
+  double m = initial_m;
+  double c = initial_c;
 
-  Problem problem;
+  ceres::Problem problem;
   for (int i = 0; i < kNumObservations; ++i) {
     problem.AddResidualBlock(
-        new AutoDiffCostFunction<ExponentialResidual, 1, 1, 1>(
-            new ExponentialResidual(data[2 * i], data[2 * i + 1])),
-        NULL,
+        new ceres::AutoDiffCostFunction<ExponentialResidual, 1, 1, 1>(
+            data[2 * i], data[2 * i + 1]),
+        nullptr,
         &m,
         &c);
   }
 
-  Solver::Options options;
+  ceres::Solver::Options options;
   options.max_num_iterations = 25;
   options.linear_solver_type = ceres::DENSE_QR;
   options.minimizer_progress_to_stdout = true;
 
-  Solver::Summary summary;
-  Solve(options, &problem, &summary);
+  ceres::Solver::Summary summary;
+  ceres::Solve(options, &problem, &summary);
   std::cout << summary.BriefReport() << "\n";
-  std::cout << "Initial m: " << 0.0 << " c: " << 0.0 << "\n";
+  std::cout << "Initial m: " << initial_m << " c: " << initial_c << "\n";
   std::cout << "Final   m: " << m << " c: " << c << "\n";
   return 0;
 }
diff --git a/third_party/ceres/examples/denoising.cc b/third_party/ceres/examples/denoising.cc
index 61ea2c6..dc13d19 100644
--- a/third_party/ceres/examples/denoising.cc
+++ b/third_party/ceres/examples/denoising.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -33,7 +33,7 @@
 // Note that for good denoising results the weighting between the data term
 // and the Fields of Experts term needs to be adjusted. This is discussed
 // in [1]. This program assumes Gaussian noise. The noise model can be changed
-// by substituing another function for QuadraticCostFunction.
+// by substituting another function for QuadraticCostFunction.
 //
 // [1] S. Roth and M.J. Black. "Fields of Experts." International Journal of
 //     Computer Vision, 82(2):205--229, 2009.
@@ -102,8 +102,7 @@
               "The fraction of residual blocks to use for the"
               " subset preconditioner.");
 
-namespace ceres {
-namespace examples {
+namespace ceres::examples {
 namespace {
 
 // This cost function is used to build the data term.
@@ -113,12 +112,12 @@
 class QuadraticCostFunction : public ceres::SizedCostFunction<1, 1> {
  public:
   QuadraticCostFunction(double a, double b) : sqrta_(std::sqrt(a)), b_(b) {}
-  virtual bool Evaluate(double const* const* parameters,
-                        double* residuals,
-                        double** jacobians) const {
+  bool Evaluate(double const* const* parameters,
+                double* residuals,
+                double** jacobians) const override {
     const double x = parameters[0][0];
     residuals[0] = sqrta_ * (x - b_);
-    if (jacobians != NULL && jacobians[0] != NULL) {
+    if (jacobians != nullptr && jacobians[0] != nullptr) {
       jacobians[0][0] = sqrta_;
     }
     return true;
@@ -134,13 +133,14 @@
                    Problem* problem,
                    PGMImage<double>* solution) {
   // Create the data term
-  CHECK_GT(FLAGS_sigma, 0.0);
-  const double coefficient = 1 / (2.0 * FLAGS_sigma * FLAGS_sigma);
+  CHECK_GT(CERES_GET_FLAG(FLAGS_sigma), 0.0);
+  const double coefficient =
+      1 / (2.0 * CERES_GET_FLAG(FLAGS_sigma) * CERES_GET_FLAG(FLAGS_sigma));
   for (int index = 0; index < image.NumPixels(); ++index) {
     ceres::CostFunction* cost_function = new QuadraticCostFunction(
         coefficient, image.PixelFromLinearIndex(index));
     problem->AddResidualBlock(
-        cost_function, NULL, solution->MutablePixelFromLinearIndex(index));
+        cost_function, nullptr, solution->MutablePixelFromLinearIndex(index));
   }
 
   // Create Ceres cost and loss functions for regularization. One is needed for
@@ -175,31 +175,35 @@
 }
 
 void SetLinearSolver(Solver::Options* options) {
-  CHECK(StringToLinearSolverType(FLAGS_linear_solver,
+  CHECK(StringToLinearSolverType(CERES_GET_FLAG(FLAGS_linear_solver),
                                  &options->linear_solver_type));
-  CHECK(StringToPreconditionerType(FLAGS_preconditioner,
+  CHECK(StringToPreconditionerType(CERES_GET_FLAG(FLAGS_preconditioner),
                                    &options->preconditioner_type));
   CHECK(StringToSparseLinearAlgebraLibraryType(
-      FLAGS_sparse_linear_algebra_library,
+      CERES_GET_FLAG(FLAGS_sparse_linear_algebra_library),
       &options->sparse_linear_algebra_library_type));
-  options->use_mixed_precision_solves = FLAGS_mixed_precision_solves;
-  options->max_num_refinement_iterations = FLAGS_max_num_refinement_iterations;
+  options->use_mixed_precision_solves =
+      CERES_GET_FLAG(FLAGS_mixed_precision_solves);
+  options->max_num_refinement_iterations =
+      CERES_GET_FLAG(FLAGS_max_num_refinement_iterations);
 }
 
 void SetMinimizerOptions(Solver::Options* options) {
-  options->max_num_iterations = FLAGS_num_iterations;
+  options->max_num_iterations = CERES_GET_FLAG(FLAGS_num_iterations);
   options->minimizer_progress_to_stdout = true;
-  options->num_threads = FLAGS_num_threads;
-  options->eta = FLAGS_eta;
-  options->use_nonmonotonic_steps = FLAGS_nonmonotonic_steps;
-  if (FLAGS_line_search) {
+  options->num_threads = CERES_GET_FLAG(FLAGS_num_threads);
+  options->eta = CERES_GET_FLAG(FLAGS_eta);
+  options->use_nonmonotonic_steps = CERES_GET_FLAG(FLAGS_nonmonotonic_steps);
+  if (CERES_GET_FLAG(FLAGS_line_search)) {
     options->minimizer_type = ceres::LINE_SEARCH;
   }
 
-  CHECK(StringToTrustRegionStrategyType(FLAGS_trust_region_strategy,
-                                        &options->trust_region_strategy_type));
-  CHECK(StringToDoglegType(FLAGS_dogleg, &options->dogleg_type));
-  options->use_inner_iterations = FLAGS_inner_iterations;
+  CHECK(StringToTrustRegionStrategyType(
+      CERES_GET_FLAG(FLAGS_trust_region_strategy),
+      &options->trust_region_strategy_type));
+  CHECK(
+      StringToDoglegType(CERES_GET_FLAG(FLAGS_dogleg), &options->dogleg_type));
+  options->use_inner_iterations = CERES_GET_FLAG(FLAGS_inner_iterations);
 }
 
 // Solves the FoE problem using Ceres and post-processes it to make sure the
@@ -226,7 +230,7 @@
     std::default_random_engine engine;
     std::uniform_real_distribution<> distribution(0, 1);  // rage 0 - 1
     for (auto residual_block : residual_blocks) {
-      if (distribution(engine) <= FLAGS_subset_fraction) {
+      if (distribution(engine) <= CERES_GET_FLAG(FLAGS_subset_fraction)) {
         options.residual_blocks_for_subset_preconditioner.insert(
             residual_block);
       }
@@ -247,20 +251,19 @@
 }
 
 }  // namespace
-}  // namespace examples
-}  // namespace ceres
+}  // namespace ceres::examples
 
 int main(int argc, char** argv) {
   using namespace ceres::examples;
   GFLAGS_NAMESPACE::ParseCommandLineFlags(&argc, &argv, true);
   google::InitGoogleLogging(argv[0]);
 
-  if (FLAGS_input.empty()) {
+  if (CERES_GET_FLAG(FLAGS_input).empty()) {
     std::cerr << "Please provide an image file name using -input.\n";
     return 1;
   }
 
-  if (FLAGS_foe_file.empty()) {
+  if (CERES_GET_FLAG(FLAGS_foe_file).empty()) {
     std::cerr << "Please provide a Fields of Experts file name using -foe_file."
                  "\n";
     return 1;
@@ -268,15 +271,16 @@
 
   // Load the Fields of Experts filters from file.
   FieldsOfExperts foe;
-  if (!foe.LoadFromFile(FLAGS_foe_file)) {
-    std::cerr << "Loading \"" << FLAGS_foe_file << "\" failed.\n";
+  if (!foe.LoadFromFile(CERES_GET_FLAG(FLAGS_foe_file))) {
+    std::cerr << "Loading \"" << CERES_GET_FLAG(FLAGS_foe_file)
+              << "\" failed.\n";
     return 2;
   }
 
   // Read the images
-  PGMImage<double> image(FLAGS_input);
+  PGMImage<double> image(CERES_GET_FLAG(FLAGS_input));
   if (image.width() == 0) {
-    std::cerr << "Reading \"" << FLAGS_input << "\" failed.\n";
+    std::cerr << "Reading \"" << CERES_GET_FLAG(FLAGS_input) << "\" failed.\n";
     return 3;
   }
   PGMImage<double> solution(image.width(), image.height());
@@ -287,9 +291,9 @@
 
   SolveProblem(&problem, &solution);
 
-  if (!FLAGS_output.empty()) {
-    CHECK(solution.WriteToFile(FLAGS_output))
-        << "Writing \"" << FLAGS_output << "\" failed.";
+  if (!CERES_GET_FLAG(FLAGS_output).empty()) {
+    CHECK(solution.WriteToFile(CERES_GET_FLAG(FLAGS_output)))
+        << "Writing \"" << CERES_GET_FLAG(FLAGS_output) << "\" failed.";
   }
 
   return 0;
diff --git a/third_party/ceres/examples/ellipse_approximation.cc b/third_party/ceres/examples/ellipse_approximation.cc
index 74782f4..6fa8f1c 100644
--- a/third_party/ceres/examples/ellipse_approximation.cc
+++ b/third_party/ceres/examples/ellipse_approximation.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -36,6 +36,7 @@
 // dense but dynamically sparse.
 
 #include <cmath>
+#include <utility>
 #include <vector>
 
 #include "ceres/ceres.h"
@@ -275,8 +276,8 @@
 class PointToLineSegmentContourCostFunction : public ceres::CostFunction {
  public:
   PointToLineSegmentContourCostFunction(const int num_segments,
-                                        const Eigen::Vector2d& y)
-      : num_segments_(num_segments), y_(y) {
+                                        Eigen::Vector2d y)
+      : num_segments_(num_segments), y_(std::move(y)) {
     // The first parameter is the preimage position.
     mutable_parameter_block_sizes()->push_back(1);
     // The next parameters are the control points for the line segment contour.
@@ -286,9 +287,9 @@
     set_num_residuals(2);
   }
 
-  virtual bool Evaluate(const double* const* x,
-                        double* residuals,
-                        double** jacobians) const {
+  bool Evaluate(const double* const* x,
+                double* residuals,
+                double** jacobians) const override {
     // Convert the preimage position `t` into a segment index `i0` and the
     // line segment interpolation parameter `u`. `i1` is the index of the next
     // control point.
@@ -302,16 +303,16 @@
     residuals[0] = y_[0] - ((1.0 - u) * x[1 + i0][0] + u * x[1 + i1][0]);
     residuals[1] = y_[1] - ((1.0 - u) * x[1 + i0][1] + u * x[1 + i1][1]);
 
-    if (jacobians == NULL) {
+    if (jacobians == nullptr) {
       return true;
     }
 
-    if (jacobians[0] != NULL) {
+    if (jacobians[0] != nullptr) {
       jacobians[0][0] = x[1 + i0][0] - x[1 + i1][0];
       jacobians[0][1] = x[1 + i0][1] - x[1 + i1][1];
     }
     for (int i = 0; i < num_segments_; ++i) {
-      if (jacobians[i + 1] != NULL) {
+      if (jacobians[i + 1] != nullptr) {
         ceres::MatrixRef(jacobians[i + 1], 2, 2).setZero();
         if (i == i0) {
           jacobians[i + 1][0] = -(1.0 - u);
@@ -353,7 +354,7 @@
 
   static ceres::CostFunction* Create(const double sqrt_weight) {
     return new ceres::AutoDiffCostFunction<EuclideanDistanceFunctor, 2, 2, 2>(
-        new EuclideanDistanceFunctor(sqrt_weight));
+        sqrt_weight);
   }
 
  private:
@@ -385,8 +386,8 @@
 
   // Eigen::MatrixXd is column major so we define our own MatrixXd which is
   // row major. Eigen::VectorXd can be used directly.
-  typedef Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>
-      MatrixXd;
+  using MatrixXd =
+      Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
   using Eigen::VectorXd;
 
   // `X` is the matrix of control points which make up the contour of line
@@ -395,7 +396,7 @@
   //
   // Initialize `X` to points on the unit circle.
   VectorXd w(num_segments + 1);
-  w.setLinSpaced(num_segments + 1, 0.0, 2.0 * M_PI);
+  w.setLinSpaced(num_segments + 1, 0.0, 2.0 * ceres::constants::pi);
   w.conservativeResize(num_segments);
   MatrixXd X(num_segments, 2);
   X.col(0) = w.array().cos();
@@ -404,9 +405,9 @@
   // Each data point has an associated preimage position on the line segment
   // contour. For each data point we initialize the preimage positions to
   // the index of the closest control point.
-  const int num_observations = kY.rows();
+  const int64_t num_observations = kY.rows();
   VectorXd t(num_observations);
-  for (int i = 0; i < num_observations; ++i) {
+  for (int64_t i = 0; i < num_observations; ++i) {
     (X.rowwise() - kY.row(i)).rowwise().squaredNorm().minCoeff(&t[i]);
   }
 
@@ -415,7 +416,7 @@
   // For each data point add a residual which measures its distance to its
   // corresponding position on the line segment contour.
   std::vector<double*> parameter_blocks(1 + num_segments);
-  parameter_blocks[0] = NULL;
+  parameter_blocks[0] = nullptr;
   for (int i = 0; i < num_segments; ++i) {
     parameter_blocks[i + 1] = X.data() + 2 * i;
   }
@@ -423,7 +424,7 @@
     parameter_blocks[0] = &t[i];
     problem.AddResidualBlock(
         PointToLineSegmentContourCostFunction::Create(num_segments, kY.row(i)),
-        NULL,
+        nullptr,
         parameter_blocks);
   }
 
@@ -431,7 +432,7 @@
   for (int i = 0; i < num_segments; ++i) {
     problem.AddResidualBlock(
         EuclideanDistanceFunctor::Create(sqrt(regularization_weight)),
-        NULL,
+        nullptr,
         X.data() + 2 * i,
         X.data() + 2 * ((i + 1) % num_segments));
   }
diff --git a/third_party/ceres/examples/evaluation_callback_example.cc b/third_party/ceres/examples/evaluation_callback_example.cc
new file mode 100644
index 0000000..6dbf932
--- /dev/null
+++ b/third_party/ceres/examples/evaluation_callback_example.cc
@@ -0,0 +1,257 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// This example illustrates the use of the EvaluationCallback, which can be used
+// to perform high performance computation of the residual and Jacobians outside
+// Ceres (in this case using Eigen's vectorized code) and then the CostFunctions
+// just copy these computed residuals and Jacobians appropriately and pass them
+// to Ceres Solver.
+//
+// The results of running this example should be identical to the results
+// obtained by running curve_fitting.cc. The only difference between the two
+// examples is how the residuals and Jacobians are computed.
+//
+// The observant reader will note that both here and curve_fitting.cc instead of
+// creating one ResidualBlock for each observation one can just do one
+// ResidualBlock/CostFunction for the entire problem. The reason for keeping one
+// residual per observation is that it is what is needed if and when we need to
+// introduce a loss function which is what we do in robust_curve_fitting.cc
+
+#include <iostream>
+
+#include "Eigen/Core"
+#include "ceres/ceres.h"
+#include "glog/logging.h"
+
+// Data generated using the following octave code.
+//   randn('seed', 23497);
+//   m = 0.3;
+//   c = 0.1;
+//   x=[0:0.075:5];
+//   y = exp(m * x + c);
+//   noise = randn(size(x)) * 0.2;
+//   y_observed = y + noise;
+//   data = [x', y_observed'];
+
+const int kNumObservations = 67;
+// clang-format off
+const double data[] = {
+  0.000000e+00, 1.133898e+00,
+  7.500000e-02, 1.334902e+00,
+  1.500000e-01, 1.213546e+00,
+  2.250000e-01, 1.252016e+00,
+  3.000000e-01, 1.392265e+00,
+  3.750000e-01, 1.314458e+00,
+  4.500000e-01, 1.472541e+00,
+  5.250000e-01, 1.536218e+00,
+  6.000000e-01, 1.355679e+00,
+  6.750000e-01, 1.463566e+00,
+  7.500000e-01, 1.490201e+00,
+  8.250000e-01, 1.658699e+00,
+  9.000000e-01, 1.067574e+00,
+  9.750000e-01, 1.464629e+00,
+  1.050000e+00, 1.402653e+00,
+  1.125000e+00, 1.713141e+00,
+  1.200000e+00, 1.527021e+00,
+  1.275000e+00, 1.702632e+00,
+  1.350000e+00, 1.423899e+00,
+  1.425000e+00, 1.543078e+00,
+  1.500000e+00, 1.664015e+00,
+  1.575000e+00, 1.732484e+00,
+  1.650000e+00, 1.543296e+00,
+  1.725000e+00, 1.959523e+00,
+  1.800000e+00, 1.685132e+00,
+  1.875000e+00, 1.951791e+00,
+  1.950000e+00, 2.095346e+00,
+  2.025000e+00, 2.361460e+00,
+  2.100000e+00, 2.169119e+00,
+  2.175000e+00, 2.061745e+00,
+  2.250000e+00, 2.178641e+00,
+  2.325000e+00, 2.104346e+00,
+  2.400000e+00, 2.584470e+00,
+  2.475000e+00, 1.914158e+00,
+  2.550000e+00, 2.368375e+00,
+  2.625000e+00, 2.686125e+00,
+  2.700000e+00, 2.712395e+00,
+  2.775000e+00, 2.499511e+00,
+  2.850000e+00, 2.558897e+00,
+  2.925000e+00, 2.309154e+00,
+  3.000000e+00, 2.869503e+00,
+  3.075000e+00, 3.116645e+00,
+  3.150000e+00, 3.094907e+00,
+  3.225000e+00, 2.471759e+00,
+  3.300000e+00, 3.017131e+00,
+  3.375000e+00, 3.232381e+00,
+  3.450000e+00, 2.944596e+00,
+  3.525000e+00, 3.385343e+00,
+  3.600000e+00, 3.199826e+00,
+  3.675000e+00, 3.423039e+00,
+  3.750000e+00, 3.621552e+00,
+  3.825000e+00, 3.559255e+00,
+  3.900000e+00, 3.530713e+00,
+  3.975000e+00, 3.561766e+00,
+  4.050000e+00, 3.544574e+00,
+  4.125000e+00, 3.867945e+00,
+  4.200000e+00, 4.049776e+00,
+  4.275000e+00, 3.885601e+00,
+  4.350000e+00, 4.110505e+00,
+  4.425000e+00, 4.345320e+00,
+  4.500000e+00, 4.161241e+00,
+  4.575000e+00, 4.363407e+00,
+  4.650000e+00, 4.161576e+00,
+  4.725000e+00, 4.619728e+00,
+  4.800000e+00, 4.737410e+00,
+  4.875000e+00, 4.727863e+00,
+  4.950000e+00, 4.669206e+00,
+};
+// clang-format on
+
+// This implementation of the EvaluationCallback interface also stores the
+// residuals and Jacobians that the CostFunction copies their values from.
+class MyEvaluationCallback : public ceres::EvaluationCallback {
+ public:
+  // m and c are passed by reference so that we have access to their values as
+  // they evolve over time through the course of optimization.
+  MyEvaluationCallback(const double& m, const double& c) : m_(m), c_(c) {
+    x_ = Eigen::VectorXd::Zero(kNumObservations);
+    y_ = Eigen::VectorXd::Zero(kNumObservations);
+    residuals_ = Eigen::VectorXd::Zero(kNumObservations);
+    jacobians_ = Eigen::MatrixXd::Zero(kNumObservations, 2);
+    for (int i = 0; i < kNumObservations; ++i) {
+      x_[i] = data[2 * i];
+      y_[i] = data[2 * i + 1];
+    }
+    PrepareForEvaluation(true, true);
+  }
+
+  void PrepareForEvaluation(bool evaluate_jacobians,
+                            bool new_evaluation_point) final {
+    if (new_evaluation_point) {
+      ComputeResidualAndJacobian(evaluate_jacobians);
+      jacobians_are_stale_ = !evaluate_jacobians;
+    } else {
+      if (evaluate_jacobians && jacobians_are_stale_) {
+        ComputeResidualAndJacobian(evaluate_jacobians);
+        jacobians_are_stale_ = false;
+      }
+    }
+  }
+
+  const Eigen::VectorXd& residuals() const { return residuals_; }
+  const Eigen::MatrixXd& jacobians() const { return jacobians_; }
+  bool jacobians_are_stale() const { return jacobians_are_stale_; }
+
+ private:
+  void ComputeResidualAndJacobian(bool evaluate_jacobians) {
+    residuals_ = -(m_ * x_.array() + c_).exp();
+    if (evaluate_jacobians) {
+      jacobians_.col(0) = residuals_.array() * x_.array();
+      jacobians_.col(1) = residuals_;
+    }
+    residuals_ += y_;
+  }
+
+  const double& m_;
+  const double& c_;
+  Eigen::VectorXd x_;
+  Eigen::VectorXd y_;
+  Eigen::VectorXd residuals_;
+  Eigen::MatrixXd jacobians_;
+
+  // jacobians_are_stale_ keeps track of whether the jacobian matrix matches the
+  // residuals or not, we only compute it if we know that Solver is going to
+  // need access to it.
+  bool jacobians_are_stale_ = true;
+};
+
+// As the name implies this CostFunction does not do any computation, it just
+// copies the appropriate residual and Jacobian from the matrices stored in
+// MyEvaluationCallback.
+class CostAndJacobianCopyingCostFunction
+    : public ceres::SizedCostFunction<1, 1, 1> {
+ public:
+  CostAndJacobianCopyingCostFunction(
+      int index, const MyEvaluationCallback& evaluation_callback)
+      : index_(index), evaluation_callback_(evaluation_callback) {}
+  ~CostAndJacobianCopyingCostFunction() override = default;
+
+  bool Evaluate(double const* const* parameters,
+                double* residuals,
+                double** jacobians) const final {
+    residuals[0] = evaluation_callback_.residuals()(index_);
+    if (!jacobians) return true;
+
+    // Ensure that we are not using stale Jacobians.
+    CHECK(!evaluation_callback_.jacobians_are_stale());
+
+    if (jacobians[0] != nullptr)
+      jacobians[0][0] = evaluation_callback_.jacobians()(index_, 0);
+    if (jacobians[1] != nullptr)
+      jacobians[1][0] = evaluation_callback_.jacobians()(index_, 1);
+    return true;
+  }
+
+ private:
+  int index_ = -1;
+  const MyEvaluationCallback& evaluation_callback_;
+};
+
+int main(int argc, char** argv) {
+  google::InitGoogleLogging(argv[0]);
+
+  const double initial_m = 0.0;
+  const double initial_c = 0.0;
+  double m = initial_m;
+  double c = initial_c;
+
+  MyEvaluationCallback evaluation_callback(m, c);
+  ceres::Problem::Options problem_options;
+  problem_options.evaluation_callback = &evaluation_callback;
+  ceres::Problem problem(problem_options);
+  for (int i = 0; i < kNumObservations; ++i) {
+    problem.AddResidualBlock(
+        new CostAndJacobianCopyingCostFunction(i, evaluation_callback),
+        nullptr,
+        &m,
+        &c);
+  }
+
+  ceres::Solver::Options options;
+  options.max_num_iterations = 25;
+  options.linear_solver_type = ceres::DENSE_QR;
+  options.minimizer_progress_to_stdout = true;
+
+  ceres::Solver::Summary summary;
+  ceres::Solve(options, &problem, &summary);
+  std::cout << summary.BriefReport() << "\n";
+  std::cout << "Initial m: " << initial_m << " c: " << initial_c << "\n";
+  std::cout << "Final   m: " << m << " c: " << c << "\n";
+  return 0;
+}
diff --git a/third_party/ceres/examples/fields_of_experts.cc b/third_party/ceres/examples/fields_of_experts.cc
index 7b7983e..f59fe16 100644
--- a/third_party/ceres/examples/fields_of_experts.cc
+++ b/third_party/ceres/examples/fields_of_experts.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -28,7 +28,7 @@
 //
 // Author: strandmark@google.com (Petter Strandmark)
 //
-// Class for loading the data required for descibing a Fields of Experts (FoE)
+// Class for loading the data required for describing a Fields of Experts (FoE)
 // model.
 
 #include "fields_of_experts.h"
@@ -38,13 +38,12 @@
 
 #include "pgm_image.h"
 
-namespace ceres {
-namespace examples {
+namespace ceres::examples {
 
 FieldsOfExpertsCost::FieldsOfExpertsCost(const std::vector<double>& filter)
     : filter_(filter) {
   set_num_residuals(1);
-  for (int i = 0; i < filter_.size(); ++i) {
+  for (int64_t i = 0; i < filter_.size(); ++i) {
     mutable_parameter_block_sizes()->push_back(1);
   }
 }
@@ -54,15 +53,15 @@
 bool FieldsOfExpertsCost::Evaluate(double const* const* parameters,
                                    double* residuals,
                                    double** jacobians) const {
-  int num_variables = filter_.size();
+  const int64_t num_variables = filter_.size();
   residuals[0] = 0;
-  for (int i = 0; i < num_variables; ++i) {
+  for (int64_t i = 0; i < num_variables; ++i) {
     residuals[0] += filter_[i] * parameters[i][0];
   }
 
-  if (jacobians != NULL) {
-    for (int i = 0; i < num_variables; ++i) {
-      if (jacobians[i] != NULL) {
+  if (jacobians != nullptr) {
+    for (int64_t i = 0; i < num_variables; ++i) {
+      if (jacobians[i] != nullptr) {
         jacobians[i][0] = filter_[i];
       }
     }
@@ -145,5 +144,4 @@
   return new FieldsOfExpertsLoss(alpha_[alpha_index]);
 }
 
-}  // namespace examples
-}  // namespace ceres
+}  // namespace ceres::examples
diff --git a/third_party/ceres/examples/fields_of_experts.h b/third_party/ceres/examples/fields_of_experts.h
index 429881d..2ff8c94 100644
--- a/third_party/ceres/examples/fields_of_experts.h
+++ b/third_party/ceres/examples/fields_of_experts.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -28,7 +28,7 @@
 //
 // Author: strandmark@google.com (Petter Strandmark)
 //
-// Class for loading the data required for descibing a Fields of Experts (FoE)
+// Class for loading the data required for describing a Fields of Experts (FoE)
 // model. The Fields of Experts regularization consists of terms of the type
 //
 //   alpha * log(1 + (1/2)*sum(F .* X)^2),
@@ -52,8 +52,7 @@
 #include "ceres/sized_cost_function.h"
 #include "pgm_image.h"
 
-namespace ceres {
-namespace examples {
+namespace ceres::examples {
 
 // One sum in the FoE regularizer. This is a dot product between a filter and an
 // image patch. It simply calculates the dot product between the filter
@@ -63,9 +62,9 @@
   explicit FieldsOfExpertsCost(const std::vector<double>& filter);
   // The number of scalar parameters passed to Evaluate must equal the number of
   // filter coefficients passed to the constructor.
-  virtual bool Evaluate(double const* const* parameters,
-                        double* residuals,
-                        double** jacobians) const;
+  bool Evaluate(double const* const* parameters,
+                double* residuals,
+                double** jacobians) const override;
 
  private:
   const std::vector<double>& filter_;
@@ -78,7 +77,7 @@
 class FieldsOfExpertsLoss : public ceres::LossFunction {
  public:
   explicit FieldsOfExpertsLoss(double alpha) : alpha_(alpha) {}
-  virtual void Evaluate(double, double*) const;
+  void Evaluate(double, double*) const override;
 
  private:
   const double alpha_;
@@ -128,7 +127,6 @@
   std::vector<std::vector<double>> filters_;
 };
 
-}  // namespace examples
-}  // namespace ceres
+}  // namespace ceres::examples
 
 #endif  // CERES_EXAMPLES_FIELDS_OF_EXPERTS_H_
diff --git a/third_party/ceres/examples/helloworld.cc b/third_party/ceres/examples/helloworld.cc
index 9e32fad..40c2f2c 100644
--- a/third_party/ceres/examples/helloworld.cc
+++ b/third_party/ceres/examples/helloworld.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -36,12 +36,6 @@
 #include "ceres/ceres.h"
 #include "glog/logging.h"
 
-using ceres::AutoDiffCostFunction;
-using ceres::CostFunction;
-using ceres::Problem;
-using ceres::Solve;
-using ceres::Solver;
-
 // A templated cost functor that implements the residual r = 10 -
 // x. The method operator() is templated so that we can then use an
 // automatic differentiation wrapper around it to generate its
@@ -63,19 +57,19 @@
   const double initial_x = x;
 
   // Build the problem.
-  Problem problem;
+  ceres::Problem problem;
 
   // Set up the only cost function (also known as residual). This uses
   // auto-differentiation to obtain the derivative (jacobian).
-  CostFunction* cost_function =
-      new AutoDiffCostFunction<CostFunctor, 1, 1>(new CostFunctor);
+  ceres::CostFunction* cost_function =
+      new ceres::AutoDiffCostFunction<CostFunctor, 1, 1>();
   problem.AddResidualBlock(cost_function, nullptr, &x);
 
   // Run the solver!
-  Solver::Options options;
+  ceres::Solver::Options options;
   options.minimizer_progress_to_stdout = true;
-  Solver::Summary summary;
-  Solve(options, &problem, &summary);
+  ceres::Solver::Summary summary;
+  ceres::Solve(options, &problem, &summary);
 
   std::cout << summary.BriefReport() << "\n";
   std::cout << "x : " << initial_x << " -> " << x << "\n";
diff --git a/third_party/ceres/examples/helloworld_analytic_diff.cc b/third_party/ceres/examples/helloworld_analytic_diff.cc
index 6e120b5..b4826a2 100644
--- a/third_party/ceres/examples/helloworld_analytic_diff.cc
+++ b/third_party/ceres/examples/helloworld_analytic_diff.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -37,23 +37,15 @@
 #include "ceres/ceres.h"
 #include "glog/logging.h"
 
-using ceres::CostFunction;
-using ceres::Problem;
-using ceres::SizedCostFunction;
-using ceres::Solve;
-using ceres::Solver;
-
 // A CostFunction implementing analytically derivatives for the
 // function f(x) = 10 - x.
 class QuadraticCostFunction
-    : public SizedCostFunction<1 /* number of residuals */,
-                               1 /* size of first parameter */> {
+    : public ceres::SizedCostFunction<1 /* number of residuals */,
+                                      1 /* size of first parameter */> {
  public:
-  virtual ~QuadraticCostFunction() {}
-
-  virtual bool Evaluate(double const* const* parameters,
-                        double* residuals,
-                        double** jacobians) const {
+  bool Evaluate(double const* const* parameters,
+                double* residuals,
+                double** jacobians) const override {
     double x = parameters[0][0];
 
     // f(x) = 10 - x.
@@ -64,14 +56,14 @@
     // jacobians.
     //
     // Since the Evaluate function can be called with the jacobians
-    // pointer equal to NULL, the Evaluate function must check to see
+    // pointer equal to nullptr, the Evaluate function must check to see
     // if jacobians need to be computed.
     //
     // For this simple problem it is overkill to check if jacobians[0]
-    // is NULL, but in general when writing more complex
+    // is nullptr, but in general when writing more complex
     // CostFunctions, it is possible that Ceres may only demand the
     // derivatives w.r.t. a subset of the parameter blocks.
-    if (jacobians != NULL && jacobians[0] != NULL) {
+    if (jacobians != nullptr && jacobians[0] != nullptr) {
       jacobians[0][0] = -1;
     }
 
@@ -88,17 +80,17 @@
   const double initial_x = x;
 
   // Build the problem.
-  Problem problem;
+  ceres::Problem problem;
 
   // Set up the only cost function (also known as residual).
-  CostFunction* cost_function = new QuadraticCostFunction;
-  problem.AddResidualBlock(cost_function, NULL, &x);
+  ceres::CostFunction* cost_function = new QuadraticCostFunction;
+  problem.AddResidualBlock(cost_function, nullptr, &x);
 
   // Run the solver!
-  Solver::Options options;
+  ceres::Solver::Options options;
   options.minimizer_progress_to_stdout = true;
-  Solver::Summary summary;
-  Solve(options, &problem, &summary);
+  ceres::Solver::Summary summary;
+  ceres::Solve(options, &problem, &summary);
 
   std::cout << summary.BriefReport() << "\n";
   std::cout << "x : " << initial_x << " -> " << x << "\n";
diff --git a/third_party/ceres/examples/helloworld_numeric_diff.cc b/third_party/ceres/examples/helloworld_numeric_diff.cc
index 474adf3..4ed9ca6 100644
--- a/third_party/ceres/examples/helloworld_numeric_diff.cc
+++ b/third_party/ceres/examples/helloworld_numeric_diff.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -34,13 +34,6 @@
 #include "ceres/ceres.h"
 #include "glog/logging.h"
 
-using ceres::CENTRAL;
-using ceres::CostFunction;
-using ceres::NumericDiffCostFunction;
-using ceres::Problem;
-using ceres::Solve;
-using ceres::Solver;
-
 // A cost functor that implements the residual r = 10 - x.
 struct CostFunctor {
   bool operator()(const double* const x, double* residual) const {
@@ -58,19 +51,20 @@
   const double initial_x = x;
 
   // Build the problem.
-  Problem problem;
+  ceres::Problem problem;
 
   // Set up the only cost function (also known as residual). This uses
   // numeric differentiation to obtain the derivative (jacobian).
-  CostFunction* cost_function =
-      new NumericDiffCostFunction<CostFunctor, CENTRAL, 1, 1>(new CostFunctor);
-  problem.AddResidualBlock(cost_function, NULL, &x);
+  ceres::CostFunction* cost_function =
+      new ceres::NumericDiffCostFunction<CostFunctor, ceres::CENTRAL, 1, 1>(
+          new CostFunctor);
+  problem.AddResidualBlock(cost_function, nullptr, &x);
 
   // Run the solver!
-  Solver::Options options;
+  ceres::Solver::Options options;
   options.minimizer_progress_to_stdout = true;
-  Solver::Summary summary;
-  Solve(options, &problem, &summary);
+  ceres::Solver::Summary summary;
+  ceres::Solve(options, &problem, &summary);
 
   std::cout << summary.BriefReport() << "\n";
   std::cout << "x : " << initial_x << " -> " << x << "\n";
diff --git a/third_party/ceres/examples/iteration_callback_example.cc b/third_party/ceres/examples/iteration_callback_example.cc
new file mode 100644
index 0000000..0be2f36
--- /dev/null
+++ b/third_party/ceres/examples/iteration_callback_example.cc
@@ -0,0 +1,199 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// This example is a variant of curve_fitting.cc where we use an
+// IterationCallback to implement custom logging which prints out the values of
+// the parameter blocks as they evolve over the course of the optimization. This
+// also requires the use of Solver::Options::update_state_every_iteration.
+
+#include <iostream>
+
+#include "ceres/ceres.h"
+#include "glog/logging.h"
+
+// Data generated using the following octave code.
+//   randn('seed', 23497);
+//   m = 0.3;
+//   c = 0.1;
+//   x=[0:0.075:5];
+//   y = exp(m * x + c);
+//   noise = randn(size(x)) * 0.2;
+//   y_observed = y + noise;
+//   data = [x', y_observed'];
+
+const int kNumObservations = 67;
+// clang-format off
+const double data[] = {
+  0.000000e+00, 1.133898e+00,
+  7.500000e-02, 1.334902e+00,
+  1.500000e-01, 1.213546e+00,
+  2.250000e-01, 1.252016e+00,
+  3.000000e-01, 1.392265e+00,
+  3.750000e-01, 1.314458e+00,
+  4.500000e-01, 1.472541e+00,
+  5.250000e-01, 1.536218e+00,
+  6.000000e-01, 1.355679e+00,
+  6.750000e-01, 1.463566e+00,
+  7.500000e-01, 1.490201e+00,
+  8.250000e-01, 1.658699e+00,
+  9.000000e-01, 1.067574e+00,
+  9.750000e-01, 1.464629e+00,
+  1.050000e+00, 1.402653e+00,
+  1.125000e+00, 1.713141e+00,
+  1.200000e+00, 1.527021e+00,
+  1.275000e+00, 1.702632e+00,
+  1.350000e+00, 1.423899e+00,
+  1.425000e+00, 1.543078e+00,
+  1.500000e+00, 1.664015e+00,
+  1.575000e+00, 1.732484e+00,
+  1.650000e+00, 1.543296e+00,
+  1.725000e+00, 1.959523e+00,
+  1.800000e+00, 1.685132e+00,
+  1.875000e+00, 1.951791e+00,
+  1.950000e+00, 2.095346e+00,
+  2.025000e+00, 2.361460e+00,
+  2.100000e+00, 2.169119e+00,
+  2.175000e+00, 2.061745e+00,
+  2.250000e+00, 2.178641e+00,
+  2.325000e+00, 2.104346e+00,
+  2.400000e+00, 2.584470e+00,
+  2.475000e+00, 1.914158e+00,
+  2.550000e+00, 2.368375e+00,
+  2.625000e+00, 2.686125e+00,
+  2.700000e+00, 2.712395e+00,
+  2.775000e+00, 2.499511e+00,
+  2.850000e+00, 2.558897e+00,
+  2.925000e+00, 2.309154e+00,
+  3.000000e+00, 2.869503e+00,
+  3.075000e+00, 3.116645e+00,
+  3.150000e+00, 3.094907e+00,
+  3.225000e+00, 2.471759e+00,
+  3.300000e+00, 3.017131e+00,
+  3.375000e+00, 3.232381e+00,
+  3.450000e+00, 2.944596e+00,
+  3.525000e+00, 3.385343e+00,
+  3.600000e+00, 3.199826e+00,
+  3.675000e+00, 3.423039e+00,
+  3.750000e+00, 3.621552e+00,
+  3.825000e+00, 3.559255e+00,
+  3.900000e+00, 3.530713e+00,
+  3.975000e+00, 3.561766e+00,
+  4.050000e+00, 3.544574e+00,
+  4.125000e+00, 3.867945e+00,
+  4.200000e+00, 4.049776e+00,
+  4.275000e+00, 3.885601e+00,
+  4.350000e+00, 4.110505e+00,
+  4.425000e+00, 4.345320e+00,
+  4.500000e+00, 4.161241e+00,
+  4.575000e+00, 4.363407e+00,
+  4.650000e+00, 4.161576e+00,
+  4.725000e+00, 4.619728e+00,
+  4.800000e+00, 4.737410e+00,
+  4.875000e+00, 4.727863e+00,
+  4.950000e+00, 4.669206e+00,
+};
+// clang-format on
+
+struct ExponentialResidual {
+  ExponentialResidual(double x, double y) : x(x), y(y) {}
+
+  template <typename T>
+  bool operator()(const T* const m, const T* const c, T* residual) const {
+    residual[0] = y - exp(m[0] * x + c[0]);
+    return true;
+  }
+
+ private:
+  const double x;
+  const double y;
+};
+
+// MyIterationCallback prints the iteration number, the cost and the value of
+// the parameter blocks every iteration.
+class MyIterationCallback : public ceres::IterationCallback {
+ public:
+  MyIterationCallback(const double* m, const double* c) : m_(m), c_(c) {}
+
+  ~MyIterationCallback() override = default;
+
+  ceres::CallbackReturnType operator()(
+      const ceres::IterationSummary& summary) final {
+    std::cout << "Iteration: " << summary.iteration << " cost: " << summary.cost
+              << " m: " << *m_ << " c: " << *c_ << std::endl;
+    return ceres::SOLVER_CONTINUE;
+  }
+
+ private:
+  const double* m_ = nullptr;
+  const double* c_ = nullptr;
+};
+
+int main(int argc, char** argv) {
+  google::InitGoogleLogging(argv[0]);
+
+  const double initial_m = 0.0;
+  const double initial_c = 0.0;
+
+  double m = initial_m;
+  double c = initial_c;
+
+  ceres::Problem problem;
+  for (int i = 0; i < kNumObservations; ++i) {
+    problem.AddResidualBlock(
+        new ceres::AutoDiffCostFunction<ExponentialResidual, 1, 1, 1>(
+            data[2 * i], data[2 * i + 1]),
+        nullptr,
+        &m,
+        &c);
+  }
+
+  ceres::Solver::Options options;
+  options.max_num_iterations = 25;
+  options.linear_solver_type = ceres::DENSE_QR;
+
+  // Turn off the default logging from Ceres so that it does not interfere with
+  // MyIterationCallback.
+  options.minimizer_progress_to_stdout = false;
+
+  MyIterationCallback callback(&m, &c);
+  options.callbacks.push_back(&callback);
+
+  // Tell Ceres to update the value of the parameter blocks on each each
+  // iteration (successful or not) so that MyIterationCallback will be able to
+  // see them when called.
+  options.update_state_every_iteration = true;
+
+  ceres::Solver::Summary summary;
+  ceres::Solve(options, &problem, &summary);
+  std::cout << summary.BriefReport() << "\n";
+  std::cout << "Initial m: " << initial_m << " c: " << initial_c << "\n";
+  std::cout << "Final   m: " << m << " c: " << c << "\n";
+  return 0;
+}
diff --git a/third_party/ceres/examples/libmv_bundle_adjuster.cc b/third_party/ceres/examples/libmv_bundle_adjuster.cc
index b1eb220..9315ed7 100644
--- a/third_party/ceres/examples/libmv_bundle_adjuster.cc
+++ b/third_party/ceres/examples/libmv_bundle_adjuster.cc
@@ -60,7 +60,7 @@
 // Image number shall be greater or equal to zero. Order of cameras does not
 // matter and gaps are possible.
 //
-// Every 3D point is decribed by:
+// Every 3D point is described by:
 //
 //  - Track number point belongs to (single 4 bytes integer value).
 //  - 3D position vector, 3-component vector of float values.
@@ -100,12 +100,16 @@
 #define close _close
 typedef unsigned __int32 uint32_t;
 #else
-#include <stdint.h>
 #include <unistd.h>
 
+#include <cstdint>
+
+// NOTE MinGW does define the macro.
+#ifndef O_BINARY
 // O_BINARY is not defined on unix like platforms, as there is no
 // difference between binary and text files.
 #define O_BINARY 0
+#endif
 
 #endif
 
@@ -114,12 +118,10 @@
 #include "gflags/gflags.h"
 #include "glog/logging.h"
 
-typedef Eigen::Matrix<double, 3, 3> Mat3;
-typedef Eigen::Matrix<double, 6, 1> Vec6;
-typedef Eigen::Vector3d Vec3;
-typedef Eigen::Vector4d Vec4;
-
-using std::vector;
+using Mat3 = Eigen::Matrix<double, 3, 3>;
+using Vec6 = Eigen::Matrix<double, 6, 1>;
+using Vec3 = Eigen::Vector3d;
+using Vec4 = Eigen::Vector4d;
 
 DEFINE_string(input, "", "Input File name");
 DEFINE_string(refine_intrinsics,
@@ -135,10 +137,10 @@
 // R is a 3x3 matrix representing the rotation of the camera.
 // t is a translation vector representing its positions.
 struct EuclideanCamera {
-  EuclideanCamera() : image(-1) {}
-  EuclideanCamera(const EuclideanCamera& c) : image(c.image), R(c.R), t(c.t) {}
+  EuclideanCamera() = default;
+  EuclideanCamera(const EuclideanCamera& c) = default;
 
-  int image;
+  int image{-1};
   Mat3 R;
   Vec3 t;
 };
@@ -148,9 +150,9 @@
 // track identifies which track this point corresponds to.
 // X represents the 3D position of the track.
 struct EuclideanPoint {
-  EuclideanPoint() : track(-1) {}
-  EuclideanPoint(const EuclideanPoint& p) : track(p.track), X(p.X) {}
-  int track;
+  EuclideanPoint() = default;
+  EuclideanPoint(const EuclideanPoint& p) = default;
+  int track{-1};
   Vec3 X;
 };
 
@@ -203,32 +205,32 @@
 };
 
 // Returns a pointer to the camera corresponding to a image.
-EuclideanCamera* CameraForImage(vector<EuclideanCamera>* all_cameras,
+EuclideanCamera* CameraForImage(std::vector<EuclideanCamera>* all_cameras,
                                 const int image) {
   if (image < 0 || image >= all_cameras->size()) {
-    return NULL;
+    return nullptr;
   }
   EuclideanCamera* camera = &(*all_cameras)[image];
   if (camera->image == -1) {
-    return NULL;
+    return nullptr;
   }
   return camera;
 }
 
 const EuclideanCamera* CameraForImage(
-    const vector<EuclideanCamera>& all_cameras, const int image) {
+    const std::vector<EuclideanCamera>& all_cameras, const int image) {
   if (image < 0 || image >= all_cameras.size()) {
-    return NULL;
+    return nullptr;
   }
   const EuclideanCamera* camera = &all_cameras[image];
   if (camera->image == -1) {
-    return NULL;
+    return nullptr;
   }
   return camera;
 }
 
 // Returns maximal image number at which marker exists.
-int MaxImage(const vector<Marker>& all_markers) {
+int MaxImage(const std::vector<Marker>& all_markers) {
   if (all_markers.size() == 0) {
     return -1;
   }
@@ -241,14 +243,14 @@
 }
 
 // Returns a pointer to the point corresponding to a track.
-EuclideanPoint* PointForTrack(vector<EuclideanPoint>* all_points,
+EuclideanPoint* PointForTrack(std::vector<EuclideanPoint>* all_points,
                               const int track) {
   if (track < 0 || track >= all_points->size()) {
-    return NULL;
+    return nullptr;
   }
   EuclideanPoint* point = &(*all_points)[track];
   if (point->track == -1) {
-    return NULL;
+    return nullptr;
   }
   return point;
 }
@@ -262,7 +264,7 @@
 // denotes file endianness in this way.
 class EndianAwareFileReader {
  public:
-  EndianAwareFileReader(void) : file_descriptor_(-1) {
+  EndianAwareFileReader() {
     // Get an endian type of the host machine.
     union {
       unsigned char bytes[4];
@@ -272,7 +274,7 @@
     file_endian_type_ = host_endian_type_;
   }
 
-  ~EndianAwareFileReader(void) {
+  ~EndianAwareFileReader() {
     if (file_descriptor_ > 0) {
       close(file_descriptor_);
     }
@@ -284,7 +286,7 @@
       return false;
     }
     // Get an endian tpye of data in the file.
-    unsigned char file_endian_type_flag = Read<unsigned char>();
+    auto file_endian_type_flag = Read<unsigned char>();
     if (file_endian_type_flag == 'V') {
       file_endian_type_ = kBigEndian;
     } else if (file_endian_type_flag == 'v') {
@@ -297,9 +299,11 @@
 
   // Read value from the file, will switch endian if needed.
   template <typename T>
-  T Read(void) const {
+  T Read() const {
     T value;
+    CERES_DISABLE_DEPRECATED_WARNING
     CHECK_GT(read(file_descriptor_, &value, sizeof(value)), 0);
+    CERES_RESTORE_DEPRECATED_WARNING
     // Switch endian type if file contains data in different type
     // that current machine.
     if (file_endian_type_ != host_endian_type_) {
@@ -316,7 +320,7 @@
   template <typename T>
   T SwitchEndian(const T value) const {
     if (sizeof(T) == 4) {
-      unsigned int temp_value = static_cast<unsigned int>(value);
+      auto temp_value = static_cast<unsigned int>(value);
       // clang-format off
       return ((temp_value >> 24)) |
              ((temp_value << 8) & 0x00ff0000) |
@@ -333,7 +337,7 @@
 
   int host_endian_type_;
   int file_endian_type_;
-  int file_descriptor_;
+  int file_descriptor_{-1};
 };
 
 // Read 3x3 column-major matrix from the file
@@ -369,17 +373,17 @@
 // reading.
 bool ReadProblemFromFile(const std::string& file_name,
                          double camera_intrinsics[8],
-                         vector<EuclideanCamera>* all_cameras,
-                         vector<EuclideanPoint>* all_points,
+                         std::vector<EuclideanCamera>* all_cameras,
+                         std::vector<EuclideanPoint>* all_points,
                          bool* is_image_space,
-                         vector<Marker>* all_markers) {
+                         std::vector<Marker>* all_markers) {
   EndianAwareFileReader file_reader;
   if (!file_reader.OpenFile(file_name)) {
     return false;
   }
 
   // Read markers' space flag.
-  unsigned char is_image_space_flag = file_reader.Read<unsigned char>();
+  auto is_image_space_flag = file_reader.Read<unsigned char>();
   if (is_image_space_flag == 'P') {
     *is_image_space = true;
   } else if (is_image_space_flag == 'N') {
@@ -610,10 +614,10 @@
 //
 // Element with index i matches to a rotation+translation for
 // camera at image i.
-vector<Vec6> PackCamerasRotationAndTranslation(
-    const vector<Marker>& all_markers,
-    const vector<EuclideanCamera>& all_cameras) {
-  vector<Vec6> all_cameras_R_t;
+std::vector<Vec6> PackCamerasRotationAndTranslation(
+    const std::vector<Marker>& all_markers,
+    const std::vector<EuclideanCamera>& all_cameras) {
+  std::vector<Vec6> all_cameras_R_t;
   int max_image = MaxImage(all_markers);
 
   all_cameras_R_t.resize(max_image + 1);
@@ -633,9 +637,10 @@
 }
 
 // Convert cameras rotations fro mangle axis back to rotation matrix.
-void UnpackCamerasRotationAndTranslation(const vector<Marker>& all_markers,
-                                         const vector<Vec6>& all_cameras_R_t,
-                                         vector<EuclideanCamera>* all_cameras) {
+void UnpackCamerasRotationAndTranslation(
+    const std::vector<Marker>& all_markers,
+    const std::vector<Vec6>& all_cameras_R_t,
+    std::vector<EuclideanCamera>* all_cameras) {
   int max_image = MaxImage(all_markers);
 
   for (int i = 0; i <= max_image; i++) {
@@ -650,12 +655,12 @@
   }
 }
 
-void EuclideanBundleCommonIntrinsics(const vector<Marker>& all_markers,
+void EuclideanBundleCommonIntrinsics(const std::vector<Marker>& all_markers,
                                      const int bundle_intrinsics,
                                      const int bundle_constraints,
                                      double* camera_intrinsics,
-                                     vector<EuclideanCamera>* all_cameras,
-                                     vector<EuclideanPoint>* all_points) {
+                                     std::vector<EuclideanCamera>* all_cameras,
+                                     std::vector<EuclideanPoint>* all_points) {
   PrintCameraIntrinsics("Original intrinsics: ", camera_intrinsics);
 
   ceres::Problem::Options problem_options;
@@ -667,11 +672,11 @@
   //
   // Block for minimization has got the following structure:
   //   <3 elements for angle-axis> <3 elements for translation>
-  vector<Vec6> all_cameras_R_t =
+  std::vector<Vec6> all_cameras_R_t =
       PackCamerasRotationAndTranslation(all_markers, *all_cameras);
 
-  // Parameterization used to restrict camera motion for modal solvers.
-  ceres::SubsetParameterization* constant_transform_parameterization = NULL;
+  // Manifold used to restrict camera motion for modal solvers.
+  ceres::SubsetManifold* constant_transform_manifold = nullptr;
   if (bundle_constraints & BUNDLE_NO_TRANSLATION) {
     std::vector<int> constant_translation;
 
@@ -680,8 +685,8 @@
     constant_translation.push_back(4);
     constant_translation.push_back(5);
 
-    constant_transform_parameterization =
-        new ceres::SubsetParameterization(6, constant_translation);
+    constant_transform_manifold =
+        new ceres::SubsetManifold(6, constant_translation);
   }
 
   std::vector<OpenCVReprojectionError> errors;
@@ -692,11 +697,10 @@
 
   int num_residuals = 0;
   bool have_locked_camera = false;
-  for (int i = 0; i < all_markers.size(); ++i) {
-    const Marker& marker = all_markers[i];
+  for (const auto& marker : all_markers) {
     EuclideanCamera* camera = CameraForImage(all_cameras, marker.image);
     EuclideanPoint* point = PointForTrack(all_points, marker.track);
-    if (camera == NULL || point == NULL) {
+    if (camera == nullptr || point == nullptr) {
       continue;
     }
 
@@ -708,7 +712,7 @@
     costFunctions.emplace_back(&errors.back(), ceres::DO_NOT_TAKE_OWNERSHIP);
 
     problem.AddResidualBlock(&costFunctions.back(),
-                             NULL,
+                             nullptr,
                              camera_intrinsics,
                              current_camera_R_t,
                              &point->X(0));
@@ -720,8 +724,7 @@
     }
 
     if (bundle_constraints & BUNDLE_NO_TRANSLATION) {
-      problem.SetParameterization(current_camera_R_t,
-                                  constant_transform_parameterization);
+      problem.SetManifold(current_camera_R_t, constant_transform_manifold);
     }
 
     num_residuals++;
@@ -760,10 +763,8 @@
     // Always set K3 constant, it's not used at the moment.
     constant_intrinsics.push_back(OFFSET_K3);
 
-    ceres::SubsetParameterization* subset_parameterization =
-        new ceres::SubsetParameterization(8, constant_intrinsics);
-
-    problem.SetParameterization(camera_intrinsics, subset_parameterization);
+    auto* subset_manifold = new ceres::SubsetManifold(8, constant_intrinsics);
+    problem.SetManifold(camera_intrinsics, subset_manifold);
   }
 
   // Configure the solver.
@@ -793,18 +794,18 @@
   GFLAGS_NAMESPACE::ParseCommandLineFlags(&argc, &argv, true);
   google::InitGoogleLogging(argv[0]);
 
-  if (FLAGS_input.empty()) {
+  if (CERES_GET_FLAG(FLAGS_input).empty()) {
     LOG(ERROR) << "Usage: libmv_bundle_adjuster --input=blender_problem";
     return EXIT_FAILURE;
   }
 
   double camera_intrinsics[8];
-  vector<EuclideanCamera> all_cameras;
-  vector<EuclideanPoint> all_points;
+  std::vector<EuclideanCamera> all_cameras;
+  std::vector<EuclideanPoint> all_points;
   bool is_image_space;
-  vector<Marker> all_markers;
+  std::vector<Marker> all_markers;
 
-  if (!ReadProblemFromFile(FLAGS_input,
+  if (!ReadProblemFromFile(CERES_GET_FLAG(FLAGS_input),
                            camera_intrinsics,
                            &all_cameras,
                            &all_points,
@@ -828,14 +829,14 @@
   // declare which intrinsics need to be refined and in this case
   // refining flags does not depend on problem at all.
   int bundle_intrinsics = BUNDLE_NO_INTRINSICS;
-  if (FLAGS_refine_intrinsics.empty()) {
+  if (CERES_GET_FLAG(FLAGS_refine_intrinsics).empty()) {
     if (is_image_space) {
       bundle_intrinsics = BUNDLE_FOCAL_LENGTH | BUNDLE_RADIAL;
     }
   } else {
-    if (FLAGS_refine_intrinsics == "radial") {
+    if (CERES_GET_FLAG(FLAGS_refine_intrinsics) == "radial") {
       bundle_intrinsics = BUNDLE_FOCAL_LENGTH | BUNDLE_RADIAL;
-    } else if (FLAGS_refine_intrinsics != "none") {
+    } else if (CERES_GET_FLAG(FLAGS_refine_intrinsics) != "none") {
       LOG(ERROR) << "Unsupported value for refine-intrinsics";
       return EXIT_FAILURE;
     }
diff --git a/third_party/ceres/examples/libmv_homography.cc b/third_party/ceres/examples/libmv_homography.cc
index 55f3b70..b7c9eda 100644
--- a/third_party/ceres/examples/libmv_homography.cc
+++ b/third_party/ceres/examples/libmv_homography.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -60,17 +60,19 @@
 // This example demonstrates custom exit criterion by having a callback check
 // for image-space error.
 
+#include <utility>
+
 #include "ceres/ceres.h"
 #include "glog/logging.h"
 
-typedef Eigen::NumTraits<double> EigenDouble;
+using EigenDouble = Eigen::NumTraits<double>;
 
-typedef Eigen::MatrixXd Mat;
-typedef Eigen::VectorXd Vec;
-typedef Eigen::Matrix<double, 3, 3> Mat3;
-typedef Eigen::Matrix<double, 2, 1> Vec2;
-typedef Eigen::Matrix<double, Eigen::Dynamic, 8> MatX8;
-typedef Eigen::Vector3d Vec3;
+using Mat = Eigen::MatrixXd;
+using Vec = Eigen::VectorXd;
+using Mat3 = Eigen::Matrix<double, 3, 3>;
+using Vec2 = Eigen::Matrix<double, 2, 1>;
+using MatX8 = Eigen::Matrix<double, Eigen::Dynamic, 8>;
+using Vec3 = Eigen::Vector3d;
 
 namespace {
 
@@ -82,11 +84,10 @@
 struct EstimateHomographyOptions {
   // Default settings for homography estimation which should be suitable
   // for a wide range of use cases.
-  EstimateHomographyOptions()
-      : max_num_iterations(50), expected_average_symmetric_distance(1e-16) {}
+  EstimateHomographyOptions() = default;
 
   // Maximal number of iterations for the refinement step.
-  int max_num_iterations;
+  int max_num_iterations{50};
 
   // Expected average of symmetric geometric distance between
   // actual destination points and original ones transformed by
@@ -96,7 +97,7 @@
   // geometric distance is less or equal to this value.
   //
   // This distance is measured in the same units as input points are.
-  double expected_average_symmetric_distance;
+  double expected_average_symmetric_distance{1e-16};
 };
 
 // Calculate symmetric geometric cost terms:
@@ -111,7 +112,7 @@
                                      const Eigen::Matrix<T, 2, 1>& x2,
                                      T forward_error[2],
                                      T backward_error[2]) {
-  typedef Eigen::Matrix<T, 3, 1> Vec3;
+  using Vec3 = Eigen::Matrix<T, 3, 1>;
   Vec3 x(x1(0), x1(1), T(1.0));
   Vec3 y(x2(0), x2(1), T(1.0));
 
@@ -152,8 +153,8 @@
 template <typename T = double>
 class Homography2DNormalizedParameterization {
  public:
-  typedef Eigen::Matrix<T, 8, 1> Parameters;     // a, b, ... g, h
-  typedef Eigen::Matrix<T, 3, 3> Parameterized;  // H
+  using Parameters = Eigen::Matrix<T, 8, 1>;     // a, b, ... g, h
+  using Parameterized = Eigen::Matrix<T, 3, 3>;  // H
 
   // Convert from the 8 parameters to a H matrix.
   static void To(const Parameters& p, Parameterized* h) {
@@ -202,11 +203,11 @@
   assert(x1.rows() == x2.rows());
   assert(x1.cols() == x2.cols());
 
-  int n = x1.cols();
+  const int64_t n = x1.cols();
   MatX8 L = Mat::Zero(n * 3, 8);
   Mat b = Mat::Zero(n * 3, 1);
-  for (int i = 0; i < n; ++i) {
-    int j = 3 * i;
+  for (int64_t i = 0; i < n; ++i) {
+    int64_t j = 3 * i;
     L(j, 0) = x1(0, i);              // a
     L(j, 1) = x1(1, i);              // b
     L(j, 2) = 1.0;                   // c
@@ -242,13 +243,13 @@
 // used for homography matrix refinement.
 class HomographySymmetricGeometricCostFunctor {
  public:
-  HomographySymmetricGeometricCostFunctor(const Vec2& x, const Vec2& y)
-      : x_(x), y_(y) {}
+  HomographySymmetricGeometricCostFunctor(Vec2 x, Vec2 y)
+      : x_(std::move(x)), y_(std::move(y)) {}
 
   template <typename T>
   bool operator()(const T* homography_parameters, T* residuals) const {
-    typedef Eigen::Matrix<T, 3, 3> Mat3;
-    typedef Eigen::Matrix<T, 2, 1> Vec2;
+    using Mat3 = Eigen::Matrix<T, 3, 3>;
+    using Vec2 = Eigen::Matrix<T, 2, 1>;
 
     Mat3 H(homography_parameters);
     Vec2 x(T(x_(0)), T(x_(1)));
@@ -277,8 +278,8 @@
                               Mat3* H)
       : options_(options), x1_(x1), x2_(x2), H_(H) {}
 
-  virtual ceres::CallbackReturnType operator()(
-      const ceres::IterationSummary& summary) {
+  ceres::CallbackReturnType operator()(
+      const ceres::IterationSummary& summary) override {
     // If the step wasn't successful, there's nothing to do.
     if (!summary.step_is_successful) {
       return ceres::SOLVER_CONTINUE;
@@ -326,16 +327,11 @@
   // Step 2: Refine matrix using Ceres minimizer.
   ceres::Problem problem;
   for (int i = 0; i < x1.cols(); i++) {
-    HomographySymmetricGeometricCostFunctor*
-        homography_symmetric_geometric_cost_function =
-            new HomographySymmetricGeometricCostFunctor(x1.col(i), x2.col(i));
-
     problem.AddResidualBlock(
         new ceres::AutoDiffCostFunction<HomographySymmetricGeometricCostFunctor,
                                         4,  // num_residuals
-                                        9>(
-            homography_symmetric_geometric_cost_function),
-        NULL,
+                                        9>(x1.col(i), x2.col(i)),
+        nullptr,
         H->data());
   }
 
@@ -380,10 +376,10 @@
 
   Mat x2 = x1;
   for (int i = 0; i < x2.cols(); ++i) {
-    Vec3 homogenous_x1 = Vec3(x1(0, i), x1(1, i), 1.0);
-    Vec3 homogenous_x2 = homography_matrix * homogenous_x1;
-    x2(0, i) = homogenous_x2(0) / homogenous_x2(2);
-    x2(1, i) = homogenous_x2(1) / homogenous_x2(2);
+    Vec3 homogeneous_x1 = Vec3(x1(0, i), x1(1, i), 1.0);
+    Vec3 homogeneous_x2 = homography_matrix * homogeneous_x1;
+    x2(0, i) = homogeneous_x2(0) / homogeneous_x2(2);
+    x2(1, i) = homogeneous_x2(1) / homogeneous_x2(2);
 
     // Apply some noise so algebraic estimation is not good enough.
     x2(0, i) += static_cast<double>(rand() % 1000) / 5000.0;
diff --git a/third_party/ceres/examples/more_garbow_hillstrom.cc b/third_party/ceres/examples/more_garbow_hillstrom.cc
index e39d23c..f15e576 100644
--- a/third_party/ceres/examples/more_garbow_hillstrom.cc
+++ b/third_party/ceres/examples/more_garbow_hillstrom.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -72,55 +72,56 @@
              3,
              "Maximal number of extrapolations in Ridders' method.");
 
-namespace ceres {
-namespace examples {
+namespace ceres::examples {
 
 const double kDoubleMax = std::numeric_limits<double>::max();
 
 static void SetNumericDiffOptions(ceres::NumericDiffOptions* options) {
-  options->max_num_ridders_extrapolations = FLAGS_ridders_extrapolations;
+  options->max_num_ridders_extrapolations =
+      CERES_GET_FLAG(FLAGS_ridders_extrapolations);
 }
 
-#define BEGIN_MGH_PROBLEM(name, num_parameters, num_residuals)                \
-  struct name {                                                               \
-    static constexpr int kNumParameters = num_parameters;                     \
-    static const double initial_x[kNumParameters];                            \
-    static const double lower_bounds[kNumParameters];                         \
-    static const double upper_bounds[kNumParameters];                         \
-    static const double constrained_optimal_cost;                             \
-    static const double unconstrained_optimal_cost;                           \
-    static CostFunction* Create() {                                           \
-      if (FLAGS_use_numeric_diff) {                                           \
-        ceres::NumericDiffOptions options;                                    \
-        SetNumericDiffOptions(&options);                                      \
-        if (FLAGS_numeric_diff_method == "central") {                         \
-          return new NumericDiffCostFunction<name,                            \
-                                             ceres::CENTRAL,                  \
-                                             num_residuals,                   \
-                                             num_parameters>(                 \
-              new name, ceres::TAKE_OWNERSHIP, num_residuals, options);       \
-        } else if (FLAGS_numeric_diff_method == "forward") {                  \
-          return new NumericDiffCostFunction<name,                            \
-                                             ceres::FORWARD,                  \
-                                             num_residuals,                   \
-                                             num_parameters>(                 \
-              new name, ceres::TAKE_OWNERSHIP, num_residuals, options);       \
-        } else if (FLAGS_numeric_diff_method == "ridders") {                  \
-          return new NumericDiffCostFunction<name,                            \
-                                             ceres::RIDDERS,                  \
-                                             num_residuals,                   \
-                                             num_parameters>(                 \
-              new name, ceres::TAKE_OWNERSHIP, num_residuals, options);       \
-        } else {                                                              \
-          LOG(ERROR) << "Invalid numeric diff method specified";              \
-          return NULL;                                                        \
-        }                                                                     \
-      } else {                                                                \
-        return new AutoDiffCostFunction<name, num_residuals, num_parameters>( \
-            new name);                                                        \
-      }                                                                       \
-    }                                                                         \
-    template <typename T>                                                     \
+#define BEGIN_MGH_PROBLEM(name, num_parameters, num_residuals)               \
+  struct name {                                                              \
+    static constexpr int kNumParameters = num_parameters;                    \
+    static const double initial_x[kNumParameters];                           \
+    static const double lower_bounds[kNumParameters];                        \
+    static const double upper_bounds[kNumParameters];                        \
+    static const double constrained_optimal_cost;                            \
+    static const double unconstrained_optimal_cost;                          \
+    static CostFunction* Create() {                                          \
+      if (CERES_GET_FLAG(FLAGS_use_numeric_diff)) {                          \
+        ceres::NumericDiffOptions options;                                   \
+        SetNumericDiffOptions(&options);                                     \
+        if (CERES_GET_FLAG(FLAGS_numeric_diff_method) == "central") {        \
+          return new NumericDiffCostFunction<name,                           \
+                                             ceres::CENTRAL,                 \
+                                             num_residuals,                  \
+                                             num_parameters>(                \
+              new name, ceres::TAKE_OWNERSHIP, num_residuals, options);      \
+        } else if (CERES_GET_FLAG(FLAGS_numeric_diff_method) == "forward") { \
+          return new NumericDiffCostFunction<name,                           \
+                                             ceres::FORWARD,                 \
+                                             num_residuals,                  \
+                                             num_parameters>(                \
+              new name, ceres::TAKE_OWNERSHIP, num_residuals, options);      \
+        } else if (CERES_GET_FLAG(FLAGS_numeric_diff_method) == "ridders") { \
+          return new NumericDiffCostFunction<name,                           \
+                                             ceres::RIDDERS,                 \
+                                             num_residuals,                  \
+                                             num_parameters>(                \
+              new name, ceres::TAKE_OWNERSHIP, num_residuals, options);      \
+        } else {                                                             \
+          LOG(ERROR) << "Invalid numeric diff method specified";             \
+          return nullptr;                                                    \
+        }                                                                    \
+      } else {                                                               \
+        return new AutoDiffCostFunction<name,                                \
+                                        num_residuals,                       \
+                                        num_parameters>();                   \
+      }                                                                      \
+    }                                                                        \
+    template <typename T>                                                    \
     bool operator()(const T* const x, T* residual) const {
 // clang-format off
 
@@ -223,7 +224,7 @@
   const T x1 = x[0];
   const T x2 = x[1];
   const T x3 = x[2];
-  const T theta = (0.5 / M_PI)  * atan(x2 / x1) + (x1 > 0.0 ? 0.0 : 0.5);
+  const T theta = (0.5 / constants::pi)  * atan(x2 / x1) + (x1 > 0.0 ? 0.0 : 0.5);
   residual[0] = 10.0 * (x3 - 10.0 * theta);
   residual[1] = 10.0 * (sqrt(x1 * x1 + x2 * x2) - 1.0);
   residual[2] = x3;
@@ -548,7 +549,7 @@
   }
 
   Problem problem;
-  problem.AddResidualBlock(TestProblem::Create(), NULL, x);
+  problem.AddResidualBlock(TestProblem::Create(), nullptr, x);
   double optimal_cost = TestProblem::unconstrained_optimal_cost;
 
   if (is_constrained) {
@@ -580,13 +581,11 @@
   return success;
 }
 
-}  // namespace examples
-}  // namespace ceres
+}  // namespace ceres::examples
 
 int main(int argc, char** argv) {
   GFLAGS_NAMESPACE::ParseCommandLineFlags(&argc, &argv, true);
   google::InitGoogleLogging(argv[0]);
-
   using ceres::examples::Solve;
 
   int unconstrained_problems = 0;
@@ -597,7 +596,8 @@
 
 #define UNCONSTRAINED_SOLVE(n)                              \
   ss << "Unconstrained Problem " << n << " : ";             \
-  if (FLAGS_problem == #n || FLAGS_problem == "all") {      \
+  if (CERES_GET_FLAG(FLAGS_problem) == #n ||                \
+      CERES_GET_FLAG(FLAGS_problem) == "all") {             \
     unconstrained_problems += 3;                            \
     if (Solve<ceres::examples::TestProblem##n>(false, 0)) { \
       unconstrained_successes += 1;                         \
@@ -645,7 +645,8 @@
 
 #define CONSTRAINED_SOLVE(n)                               \
   ss << "Constrained Problem " << n << " : ";              \
-  if (FLAGS_problem == #n || FLAGS_problem == "all") {     \
+  if (CERES_GET_FLAG(FLAGS_problem) == #n ||               \
+      CERES_GET_FLAG(FLAGS_problem) == "all") {            \
     constrained_problems += 1;                             \
     if (Solve<ceres::examples::TestProblem##n>(true, 0)) { \
       constrained_successes += 1;                          \
diff --git a/third_party/ceres/examples/nist.cc b/third_party/ceres/examples/nist.cc
index 977b69d..b92c918 100644
--- a/third_party/ceres/examples/nist.cc
+++ b/third_party/ceres/examples/nist.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -71,9 +71,12 @@
 // Average LRE     2.3      4.3       4.0  6.8      4.4    9.4
 //      Winner       0        0         5   11        2     41
 
+#include <cstdlib>
 #include <fstream>
 #include <iostream>
 #include <iterator>
+#include <string>
+#include <vector>
 
 #include "Eigen/Core"
 #include "ceres/ceres.h"
@@ -99,6 +102,9 @@
               "dense_qr",
               "Options are: sparse_cholesky, dense_qr, dense_normal_cholesky "
               "and cgnr");
+DEFINE_string(dense_linear_algebra_library,
+              "eigen",
+              "Options are: eigen, lapack, and cuda.");
 DEFINE_string(preconditioner, "jacobi", "Options are: identity, jacobi");
 DEFINE_string(line_search,
               "wolfe",
@@ -114,7 +120,7 @@
              "Maximum number of restarts of line search direction algorithm.");
 DEFINE_string(line_search_interpolation,
               "cubic",
-              "Degree of polynomial aproximation in line search, choices are: "
+              "Degree of polynomial approximation in line search, choices are: "
               "bisection, quadratic & cubic.");
 DEFINE_int32(lbfgs_rank,
              20,
@@ -148,26 +154,18 @@
              3,
              "Maximal number of Ridders extrapolations.");
 
-namespace ceres {
-namespace examples {
+namespace ceres::examples {
 namespace {
 
 using Eigen::Dynamic;
 using Eigen::RowMajor;
-typedef Eigen::Matrix<double, Dynamic, 1> Vector;
-typedef Eigen::Matrix<double, Dynamic, Dynamic, RowMajor> Matrix;
+using Vector = Eigen::Matrix<double, Dynamic, 1>;
+using Matrix = Eigen::Matrix<double, Dynamic, Dynamic, RowMajor>;
 
-using std::atof;
-using std::atoi;
-using std::cout;
-using std::ifstream;
-using std::string;
-using std::vector;
-
-void SplitStringUsingChar(const string& full,
+void SplitStringUsingChar(const std::string& full,
                           const char delim,
-                          vector<string>* result) {
-  std::back_insert_iterator<vector<string>> it(*result);
+                          std::vector<std::string>* result) {
+  std::back_insert_iterator<std::vector<std::string>> it(*result);
 
   const char* p = full.data();
   const char* end = p + full.size();
@@ -177,22 +175,22 @@
     } else {
       const char* start = p;
       while (++p != end && *p != delim) {
-        // Skip to the next occurence of the delimiter.
+        // Skip to the next occurrence of the delimiter.
       }
-      *it++ = string(start, p - start);
+      *it++ = std::string(start, p - start);
     }
   }
 }
 
-bool GetAndSplitLine(ifstream& ifs, vector<string>* pieces) {
+bool GetAndSplitLine(std::ifstream& ifs, std::vector<std::string>* pieces) {
   pieces->clear();
   char buf[256];
   ifs.getline(buf, 256);
-  SplitStringUsingChar(string(buf), ' ', pieces);
+  SplitStringUsingChar(std::string(buf), ' ', pieces);
   return true;
 }
 
-void SkipLines(ifstream& ifs, int num_lines) {
+void SkipLines(std::ifstream& ifs, int num_lines) {
   char buf[256];
   for (int i = 0; i < num_lines; ++i) {
     ifs.getline(buf, 256);
@@ -201,24 +199,24 @@
 
 class NISTProblem {
  public:
-  explicit NISTProblem(const string& filename) {
-    ifstream ifs(filename.c_str(), ifstream::in);
+  explicit NISTProblem(const std::string& filename) {
+    std::ifstream ifs(filename.c_str(), std::ifstream::in);
     CHECK(ifs) << "Unable to open : " << filename;
 
-    vector<string> pieces;
+    std::vector<std::string> pieces;
     SkipLines(ifs, 24);
     GetAndSplitLine(ifs, &pieces);
-    const int kNumResponses = atoi(pieces[1].c_str());
+    const int kNumResponses = std::atoi(pieces[1].c_str());
 
     GetAndSplitLine(ifs, &pieces);
-    const int kNumPredictors = atoi(pieces[0].c_str());
+    const int kNumPredictors = std::atoi(pieces[0].c_str());
 
     GetAndSplitLine(ifs, &pieces);
-    const int kNumObservations = atoi(pieces[0].c_str());
+    const int kNumObservations = std::atoi(pieces[0].c_str());
 
     SkipLines(ifs, 4);
     GetAndSplitLine(ifs, &pieces);
-    const int kNumParameters = atoi(pieces[0].c_str());
+    const int kNumParameters = std::atoi(pieces[0].c_str());
     SkipLines(ifs, 8);
 
     // Get the first line of initial and final parameter values to
@@ -234,24 +232,26 @@
     // Parse the line for parameter b1.
     int parameter_id = 0;
     for (int i = 0; i < kNumTries; ++i) {
-      initial_parameters_(i, parameter_id) = atof(pieces[i + 2].c_str());
+      initial_parameters_(i, parameter_id) = std::atof(pieces[i + 2].c_str());
     }
-    final_parameters_(0, parameter_id) = atof(pieces[2 + kNumTries].c_str());
+    final_parameters_(0, parameter_id) =
+        std::atof(pieces[2 + kNumTries].c_str());
 
     // Parse the remaining parameter lines.
     for (int parameter_id = 1; parameter_id < kNumParameters; ++parameter_id) {
       GetAndSplitLine(ifs, &pieces);
       // b2, b3, ....
       for (int i = 0; i < kNumTries; ++i) {
-        initial_parameters_(i, parameter_id) = atof(pieces[i + 2].c_str());
+        initial_parameters_(i, parameter_id) = std::atof(pieces[i + 2].c_str());
       }
-      final_parameters_(0, parameter_id) = atof(pieces[2 + kNumTries].c_str());
+      final_parameters_(0, parameter_id) =
+          std::atof(pieces[2 + kNumTries].c_str());
     }
 
-    // Certfied cost
+    // Certified cost
     SkipLines(ifs, 1);
     GetAndSplitLine(ifs, &pieces);
-    certified_cost_ = atof(pieces[4].c_str()) / 2.0;
+    certified_cost_ = std::atof(pieces[4].c_str()) / 2.0;
 
     // Read the observations.
     SkipLines(ifs, 18 - kNumParameters);
@@ -259,12 +259,12 @@
       GetAndSplitLine(ifs, &pieces);
       // Response.
       for (int j = 0; j < kNumResponses; ++j) {
-        response_(i, j) = atof(pieces[j].c_str());
+        response_(i, j) = std::atof(pieces[j].c_str());
       }
 
       // Predictor variables.
       for (int j = 0; j < kNumPredictors; ++j) {
-        predictor_(i, j) = atof(pieces[j + kNumResponses].c_str());
+        predictor_(i, j) = std::atof(pieces[j + kNumResponses].c_str());
       }
     }
   }
@@ -455,47 +455,57 @@
 // clang-format on
 
 static void SetNumericDiffOptions(ceres::NumericDiffOptions* options) {
-  options->max_num_ridders_extrapolations = FLAGS_ridders_extrapolations;
-  options->ridders_relative_initial_step_size = FLAGS_ridders_step_size;
+  options->max_num_ridders_extrapolations =
+      CERES_GET_FLAG(FLAGS_ridders_extrapolations);
+  options->ridders_relative_initial_step_size =
+      CERES_GET_FLAG(FLAGS_ridders_step_size);
 }
 
 void SetMinimizerOptions(ceres::Solver::Options* options) {
-  CHECK(
-      ceres::StringToMinimizerType(FLAGS_minimizer, &options->minimizer_type));
-  CHECK(ceres::StringToLinearSolverType(FLAGS_linear_solver,
+  CHECK(ceres::StringToMinimizerType(CERES_GET_FLAG(FLAGS_minimizer),
+                                     &options->minimizer_type));
+  CHECK(ceres::StringToLinearSolverType(CERES_GET_FLAG(FLAGS_linear_solver),
                                         &options->linear_solver_type));
-  CHECK(ceres::StringToPreconditionerType(FLAGS_preconditioner,
+  CHECK(StringToDenseLinearAlgebraLibraryType(
+      CERES_GET_FLAG(FLAGS_dense_linear_algebra_library),
+      &options->dense_linear_algebra_library_type));
+  CHECK(ceres::StringToPreconditionerType(CERES_GET_FLAG(FLAGS_preconditioner),
                                           &options->preconditioner_type));
   CHECK(ceres::StringToTrustRegionStrategyType(
-      FLAGS_trust_region_strategy, &options->trust_region_strategy_type));
-  CHECK(ceres::StringToDoglegType(FLAGS_dogleg, &options->dogleg_type));
+      CERES_GET_FLAG(FLAGS_trust_region_strategy),
+      &options->trust_region_strategy_type));
+  CHECK(ceres::StringToDoglegType(CERES_GET_FLAG(FLAGS_dogleg),
+                                  &options->dogleg_type));
   CHECK(ceres::StringToLineSearchDirectionType(
-      FLAGS_line_search_direction, &options->line_search_direction_type));
-  CHECK(ceres::StringToLineSearchType(FLAGS_line_search,
+      CERES_GET_FLAG(FLAGS_line_search_direction),
+      &options->line_search_direction_type));
+  CHECK(ceres::StringToLineSearchType(CERES_GET_FLAG(FLAGS_line_search),
                                       &options->line_search_type));
   CHECK(ceres::StringToLineSearchInterpolationType(
-      FLAGS_line_search_interpolation,
+      CERES_GET_FLAG(FLAGS_line_search_interpolation),
       &options->line_search_interpolation_type));
 
-  options->max_num_iterations = FLAGS_num_iterations;
-  options->use_nonmonotonic_steps = FLAGS_nonmonotonic_steps;
-  options->initial_trust_region_radius = FLAGS_initial_trust_region_radius;
-  options->max_lbfgs_rank = FLAGS_lbfgs_rank;
-  options->line_search_sufficient_function_decrease = FLAGS_sufficient_decrease;
+  options->max_num_iterations = CERES_GET_FLAG(FLAGS_num_iterations);
+  options->use_nonmonotonic_steps = CERES_GET_FLAG(FLAGS_nonmonotonic_steps);
+  options->initial_trust_region_radius =
+      CERES_GET_FLAG(FLAGS_initial_trust_region_radius);
+  options->max_lbfgs_rank = CERES_GET_FLAG(FLAGS_lbfgs_rank);
+  options->line_search_sufficient_function_decrease =
+      CERES_GET_FLAG(FLAGS_sufficient_decrease);
   options->line_search_sufficient_curvature_decrease =
-      FLAGS_sufficient_curvature_decrease;
+      CERES_GET_FLAG(FLAGS_sufficient_curvature_decrease);
   options->max_num_line_search_step_size_iterations =
-      FLAGS_max_line_search_iterations;
+      CERES_GET_FLAG(FLAGS_max_line_search_iterations);
   options->max_num_line_search_direction_restarts =
-      FLAGS_max_line_search_restarts;
+      CERES_GET_FLAG(FLAGS_max_line_search_restarts);
   options->use_approximate_eigenvalue_bfgs_scaling =
-      FLAGS_approximate_eigenvalue_bfgs_scaling;
+      CERES_GET_FLAG(FLAGS_approximate_eigenvalue_bfgs_scaling);
   options->function_tolerance = std::numeric_limits<double>::epsilon();
   options->gradient_tolerance = std::numeric_limits<double>::epsilon();
   options->parameter_tolerance = std::numeric_limits<double>::epsilon();
 }
 
-string JoinPath(const string& dirname, const string& basename) {
+std::string JoinPath(const std::string& dirname, const std::string& basename) {
 #ifdef _WIN32
   static const char separator = '\\';
 #else
@@ -507,7 +517,7 @@
   } else if (dirname[dirname.size() - 1] == separator) {
     return dirname + basename;
   } else {
-    return dirname + string(&separator, 1) + basename;
+    return dirname + std::string(&separator, 1) + basename;
   }
 }
 
@@ -515,24 +525,24 @@
 CostFunction* CreateCostFunction(const Matrix& predictor,
                                  const Matrix& response,
                                  const int num_observations) {
-  Model* model = new Model(predictor.data(), response.data(), num_observations);
-  ceres::CostFunction* cost_function = NULL;
-  if (FLAGS_use_numeric_diff) {
+  auto* model = new Model(predictor.data(), response.data(), num_observations);
+  ceres::CostFunction* cost_function = nullptr;
+  if (CERES_GET_FLAG(FLAGS_use_numeric_diff)) {
     ceres::NumericDiffOptions options;
     SetNumericDiffOptions(&options);
-    if (FLAGS_numeric_diff_method == "central") {
+    if (CERES_GET_FLAG(FLAGS_numeric_diff_method) == "central") {
       cost_function = new NumericDiffCostFunction<Model,
                                                   ceres::CENTRAL,
                                                   ceres::DYNAMIC,
                                                   num_parameters>(
           model, ceres::TAKE_OWNERSHIP, num_observations, options);
-    } else if (FLAGS_numeric_diff_method == "forward") {
+    } else if (CERES_GET_FLAG(FLAGS_numeric_diff_method) == "forward") {
       cost_function = new NumericDiffCostFunction<Model,
                                                   ceres::FORWARD,
                                                   ceres::DYNAMIC,
                                                   num_parameters>(
           model, ceres::TAKE_OWNERSHIP, num_observations, options);
-    } else if (FLAGS_numeric_diff_method == "ridders") {
+    } else if (CERES_GET_FLAG(FLAGS_numeric_diff_method) == "ridders") {
       cost_function = new NumericDiffCostFunction<Model,
                                                   ceres::RIDDERS,
                                                   ceres::DYNAMIC,
@@ -540,7 +550,7 @@
           model, ceres::TAKE_OWNERSHIP, num_observations, options);
     } else {
       LOG(ERROR) << "Invalid numeric diff method specified";
-      return 0;
+      return nullptr;
     }
   } else {
     cost_function =
@@ -571,8 +581,9 @@
 }
 
 template <typename Model, int num_parameters>
-int RegressionDriver(const string& filename) {
-  NISTProblem nist_problem(JoinPath(FLAGS_nist_data_dir, filename));
+int RegressionDriver(const std::string& filename) {
+  NISTProblem nist_problem(
+      JoinPath(CERES_GET_FLAG(FLAGS_nist_data_dir), filename));
   CHECK_EQ(num_parameters, nist_problem.num_parameters());
 
   Matrix predictor = nist_problem.predictor();
@@ -593,9 +604,10 @@
     double initial_cost;
     double final_cost;
 
-    if (!FLAGS_use_tiny_solver) {
+    if (!CERES_GET_FLAG(FLAGS_use_tiny_solver)) {
       ceres::Problem problem;
-      problem.AddResidualBlock(cost_function, NULL, initial_parameters.data());
+      problem.AddResidualBlock(
+          cost_function, nullptr, initial_parameters.data());
       ceres::Solver::Summary summary;
       ceres::Solver::Options options;
       SetMinimizerOptions(&options);
@@ -605,15 +617,15 @@
     } else {
       ceres::TinySolverCostFunctionAdapter<Eigen::Dynamic, num_parameters> cfa(
           *cost_function);
-      typedef ceres::TinySolver<
-          ceres::TinySolverCostFunctionAdapter<Eigen::Dynamic, num_parameters>>
-          Solver;
+      using Solver = ceres::TinySolver<
+          ceres::TinySolverCostFunctionAdapter<Eigen::Dynamic, num_parameters>>;
       Solver solver;
-      solver.options.max_num_iterations = FLAGS_num_iterations;
+      solver.options.max_num_iterations = CERES_GET_FLAG(FLAGS_num_iterations);
       solver.options.gradient_tolerance =
           std::numeric_limits<double>::epsilon();
       solver.options.parameter_tolerance =
           std::numeric_limits<double>::epsilon();
+      solver.options.function_tolerance = 0.0;
 
       Eigen::Matrix<double, num_parameters, 1> x;
       x = initial_parameters.transpose();
@@ -645,11 +657,11 @@
 }
 
 void SolveNISTProblems() {
-  if (FLAGS_nist_data_dir.empty()) {
+  if (CERES_GET_FLAG(FLAGS_nist_data_dir).empty()) {
     LOG(FATAL) << "Must specify the directory containing the NIST problems";
   }
 
-  cout << "Lower Difficulty\n";
+  std::cout << "Lower Difficulty\n";
   int easy_success = 0;
   easy_success += RegressionDriver<Misra1a, 2>("Misra1a.dat");
   easy_success += RegressionDriver<Chwirut, 3>("Chwirut1.dat");
@@ -660,7 +672,7 @@
   easy_success += RegressionDriver<DanWood, 2>("DanWood.dat");
   easy_success += RegressionDriver<Misra1b, 2>("Misra1b.dat");
 
-  cout << "\nMedium Difficulty\n";
+  std::cout << "\nMedium Difficulty\n";
   int medium_success = 0;
   medium_success += RegressionDriver<Kirby2, 5>("Kirby2.dat");
   medium_success += RegressionDriver<Hahn1, 7>("Hahn1.dat");
@@ -674,7 +686,7 @@
   medium_success += RegressionDriver<Roszman1, 4>("Roszman1.dat");
   medium_success += RegressionDriver<ENSO, 9>("ENSO.dat");
 
-  cout << "\nHigher Difficulty\n";
+  std::cout << "\nHigher Difficulty\n";
   int hard_success = 0;
   hard_success += RegressionDriver<MGH09, 4>("MGH09.dat");
   hard_success += RegressionDriver<Thurber, 7>("Thurber.dat");
@@ -685,17 +697,16 @@
   hard_success += RegressionDriver<Rat43, 4>("Rat43.dat");
   hard_success += RegressionDriver<Bennet5, 3>("Bennett5.dat");
 
-  cout << "\n";
-  cout << "Easy    : " << easy_success << "/16\n";
-  cout << "Medium  : " << medium_success << "/22\n";
-  cout << "Hard    : " << hard_success << "/16\n";
-  cout << "Total   : " << easy_success + medium_success + hard_success
-       << "/54\n";
+  std::cout << "\n";
+  std::cout << "Easy    : " << easy_success << "/16\n";
+  std::cout << "Medium  : " << medium_success << "/22\n";
+  std::cout << "Hard    : " << hard_success << "/16\n";
+  std::cout << "Total   : " << easy_success + medium_success + hard_success
+            << "/54\n";
 }
 
 }  // namespace
-}  // namespace examples
-}  // namespace ceres
+}  // namespace ceres::examples
 
 int main(int argc, char** argv) {
   GFLAGS_NAMESPACE::ParseCommandLineFlags(&argc, &argv, true);
diff --git a/third_party/ceres/examples/pgm_image.h b/third_party/ceres/examples/pgm_image.h
index 3d2df63..033ab4d 100644
--- a/third_party/ceres/examples/pgm_image.h
+++ b/third_party/ceres/examples/pgm_image.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -43,8 +43,7 @@
 
 #include "glog/logging.h"
 
-namespace ceres {
-namespace examples {
+namespace ceres::examples {
 
 template <typename Real>
 class PGMImage {
@@ -311,7 +310,6 @@
   return data_;
 }
 
-}  // namespace examples
-}  // namespace ceres
+}  // namespace ceres::examples
 
 #endif  // CERES_EXAMPLES_PGM_IMAGE_H_
diff --git a/third_party/ceres/examples/powell.cc b/third_party/ceres/examples/powell.cc
index c75ad24..a4ca1b7 100644
--- a/third_party/ceres/examples/powell.cc
+++ b/third_party/ceres/examples/powell.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -50,12 +50,6 @@
 #include "gflags/gflags.h"
 #include "glog/logging.h"
 
-using ceres::AutoDiffCostFunction;
-using ceres::CostFunction;
-using ceres::Problem;
-using ceres::Solve;
-using ceres::Solver;
-
 struct F1 {
   template <typename T>
   bool operator()(const T* const x1, const T* const x2, T* residual) const {
@@ -105,24 +99,24 @@
   double x3 = 0.0;
   double x4 = 1.0;
 
-  Problem problem;
-  // Add residual terms to the problem using the using the autodiff
+  ceres::Problem problem;
+  // Add residual terms to the problem using the autodiff
   // wrapper to get the derivatives automatically. The parameters, x1 through
   // x4, are modified in place.
   problem.AddResidualBlock(
-      new AutoDiffCostFunction<F1, 1, 1, 1>(new F1), NULL, &x1, &x2);
+      new ceres::AutoDiffCostFunction<F1, 1, 1, 1>(), nullptr, &x1, &x2);
   problem.AddResidualBlock(
-      new AutoDiffCostFunction<F2, 1, 1, 1>(new F2), NULL, &x3, &x4);
+      new ceres::AutoDiffCostFunction<F2, 1, 1, 1>(), nullptr, &x3, &x4);
   problem.AddResidualBlock(
-      new AutoDiffCostFunction<F3, 1, 1, 1>(new F3), NULL, &x2, &x3);
+      new ceres::AutoDiffCostFunction<F3, 1, 1, 1>(), nullptr, &x2, &x3);
   problem.AddResidualBlock(
-      new AutoDiffCostFunction<F4, 1, 1, 1>(new F4), NULL, &x1, &x4);
+      new ceres::AutoDiffCostFunction<F4, 1, 1, 1>(), nullptr, &x1, &x4);
 
-  Solver::Options options;
-  LOG_IF(
-      FATAL,
-      !ceres::StringToMinimizerType(FLAGS_minimizer, &options.minimizer_type))
-      << "Invalid minimizer: " << FLAGS_minimizer
+  ceres::Solver::Options options;
+  LOG_IF(FATAL,
+         !ceres::StringToMinimizerType(CERES_GET_FLAG(FLAGS_minimizer),
+                                       &options.minimizer_type))
+      << "Invalid minimizer: " << CERES_GET_FLAG(FLAGS_minimizer)
       << ", valid options are: trust_region and line_search.";
 
   options.max_num_iterations = 100;
@@ -138,8 +132,8 @@
   // clang-format on
 
   // Run the solver!
-  Solver::Summary summary;
-  Solve(options, &problem, &summary);
+  ceres::Solver::Summary summary;
+  ceres::Solve(options, &problem, &summary);
 
   std::cout << summary.FullReport() << "\n";
   // clang-format off
diff --git a/third_party/ceres/examples/random.h b/third_party/ceres/examples/random.h
deleted file mode 100644
index ace0711..0000000
--- a/third_party/ceres/examples/random.h
+++ /dev/null
@@ -1,64 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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 Google Inc. 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.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_EXAMPLES_RANDOM_H_
-#define CERES_EXAMPLES_RANDOM_H_
-
-#include <math.h>
-#include <stdlib.h>
-
-namespace ceres {
-namespace examples {
-
-// Return a random number sampled from a uniform distribution in the range
-// [0,1].
-inline double RandDouble() {
-  double r = static_cast<double>(rand());
-  return r / RAND_MAX;
-}
-
-// Marsaglia Polar method for generation standard normal (pseudo)
-// random numbers http://en.wikipedia.org/wiki/Marsaglia_polar_method
-inline double RandNormal() {
-  double x1, x2, w;
-  do {
-    x1 = 2.0 * RandDouble() - 1.0;
-    x2 = 2.0 * RandDouble() - 1.0;
-    w = x1 * x1 + x2 * x2;
-  } while (w >= 1.0 || w == 0.0);
-
-  w = sqrt((-2.0 * log(w)) / w);
-  return x1 * w;
-}
-
-}  // namespace examples
-}  // namespace ceres
-
-#endif  // CERES_EXAMPLES_RANDOM_H_
diff --git a/third_party/ceres/examples/robot_pose_mle.cc b/third_party/ceres/examples/robot_pose_mle.cc
index ab9a098..cc60e14 100644
--- a/third_party/ceres/examples/robot_pose_mle.cc
+++ b/third_party/ceres/examples/robot_pose_mle.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -50,7 +50,7 @@
 //
 // There are two types of residuals in this problem:
 // 1) The OdometryConstraint residual, that accounts for the odometry readings
-//    between successive pose estimatess of the robot.
+//    between successive pose estimates of the robot.
 // 2) The RangeConstraint residual, that accounts for the errors in the observed
 //    range readings from each pose.
 //
@@ -97,14 +97,14 @@
 // timesteps 0 to i for that variable, both inclusive.
 //
 // Bayes' rule is used to derive eq. 3 from 2, and the independence of
-// odometry observations and range readings is expolited to derive 4 from 3.
+// odometry observations and range readings is exploited to derive 4 from 3.
 //
 // Thus, the Belief, up to scale, is factored as a product of a number of
 // terms, two for each pose, where for each pose term there is one term for the
 // range reading, P(y_i | u*_(0:i) and one term for the odometry reading,
 // P(u*_i | u_i) . Note that the term for the range reading is dependent on all
 // odometry values u*_(0:i), while the odometry term, P(u*_i | u_i) depends only
-// on a single value, u_i. Both the range reading as well as odoemtry
+// on a single value, u_i. Both the range reading as well as odometry
 // probability terms are modeled as the Normal distribution, and have the form:
 //
 // p(x) \propto \exp{-((x - x_mean) / x_stddev)^2}
@@ -123,30 +123,18 @@
 // variable, and will be computed by an AutoDiffCostFunction, while the term
 // for the range reading will depend on all previous odometry observations, and
 // will be computed by a DynamicAutoDiffCostFunction since the number of
-// odoemtry observations will only be known at run time.
+// odometry observations will only be known at run time.
 
-#include <math.h>
-
+#include <algorithm>
+#include <cmath>
 #include <cstdio>
+#include <random>
 #include <vector>
 
 #include "ceres/ceres.h"
 #include "ceres/dynamic_autodiff_cost_function.h"
 #include "gflags/gflags.h"
 #include "glog/logging.h"
-#include "random.h"
-
-using ceres::AutoDiffCostFunction;
-using ceres::CauchyLoss;
-using ceres::CostFunction;
-using ceres::DynamicAutoDiffCostFunction;
-using ceres::LossFunction;
-using ceres::Problem;
-using ceres::Solve;
-using ceres::Solver;
-using ceres::examples::RandNormal;
-using std::min;
-using std::vector;
 
 DEFINE_double(corridor_length,
               30.0,
@@ -169,7 +157,8 @@
 static constexpr int kStride = 10;
 
 struct OdometryConstraint {
-  typedef AutoDiffCostFunction<OdometryConstraint, 1, 1> OdometryCostFunction;
+  using OdometryCostFunction =
+      ceres::AutoDiffCostFunction<OdometryConstraint, 1, 1>;
 
   OdometryConstraint(double odometry_mean, double odometry_stddev)
       : odometry_mean(odometry_mean), odometry_stddev(odometry_stddev) {}
@@ -181,8 +170,8 @@
   }
 
   static OdometryCostFunction* Create(const double odometry_value) {
-    return new OdometryCostFunction(
-        new OdometryConstraint(odometry_value, FLAGS_odometry_stddev));
+    return new OdometryCostFunction(new OdometryConstraint(
+        odometry_value, CERES_GET_FLAG(FLAGS_odometry_stddev)));
   }
 
   const double odometry_mean;
@@ -190,8 +179,8 @@
 };
 
 struct RangeConstraint {
-  typedef DynamicAutoDiffCostFunction<RangeConstraint, kStride>
-      RangeCostFunction;
+  using RangeCostFunction =
+      ceres::DynamicAutoDiffCostFunction<RangeConstraint, kStride>;
 
   RangeConstraint(int pose_index,
                   double range_reading,
@@ -217,11 +206,14 @@
   // conveniently add to a ceres problem.
   static RangeCostFunction* Create(const int pose_index,
                                    const double range_reading,
-                                   vector<double>* odometry_values,
-                                   vector<double*>* parameter_blocks) {
-    RangeConstraint* constraint = new RangeConstraint(
-        pose_index, range_reading, FLAGS_range_stddev, FLAGS_corridor_length);
-    RangeCostFunction* cost_function = new RangeCostFunction(constraint);
+                                   std::vector<double>* odometry_values,
+                                   std::vector<double*>* parameter_blocks) {
+    auto* constraint =
+        new RangeConstraint(pose_index,
+                            range_reading,
+                            CERES_GET_FLAG(FLAGS_range_stddev),
+                            CERES_GET_FLAG(FLAGS_corridor_length));
+    auto* cost_function = new RangeCostFunction(constraint);
     // Add all the parameter blocks that affect this constraint.
     parameter_blocks->clear();
     for (int i = 0; i <= pose_index; ++i) {
@@ -240,37 +232,45 @@
 
 namespace {
 
-void SimulateRobot(vector<double>* odometry_values,
-                   vector<double>* range_readings) {
+void SimulateRobot(std::vector<double>* odometry_values,
+                   std::vector<double>* range_readings) {
   const int num_steps =
-      static_cast<int>(ceil(FLAGS_corridor_length / FLAGS_pose_separation));
+      static_cast<int>(ceil(CERES_GET_FLAG(FLAGS_corridor_length) /
+                            CERES_GET_FLAG(FLAGS_pose_separation)));
+  std::mt19937 prng;
+  std::normal_distribution<double> odometry_noise(
+      0.0, CERES_GET_FLAG(FLAGS_odometry_stddev));
+  std::normal_distribution<double> range_noise(
+      0.0, CERES_GET_FLAG(FLAGS_range_stddev));
 
   // The robot starts out at the origin.
   double robot_location = 0.0;
   for (int i = 0; i < num_steps; ++i) {
     const double actual_odometry_value =
-        min(FLAGS_pose_separation, FLAGS_corridor_length - robot_location);
+        std::min(CERES_GET_FLAG(FLAGS_pose_separation),
+                 CERES_GET_FLAG(FLAGS_corridor_length) - robot_location);
     robot_location += actual_odometry_value;
-    const double actual_range = FLAGS_corridor_length - robot_location;
+    const double actual_range =
+        CERES_GET_FLAG(FLAGS_corridor_length) - robot_location;
     const double observed_odometry =
-        RandNormal() * FLAGS_odometry_stddev + actual_odometry_value;
-    const double observed_range =
-        RandNormal() * FLAGS_range_stddev + actual_range;
+        actual_odometry_value + odometry_noise(prng);
+    const double observed_range = actual_range + range_noise(prng);
     odometry_values->push_back(observed_odometry);
     range_readings->push_back(observed_range);
   }
 }
 
-void PrintState(const vector<double>& odometry_readings,
-                const vector<double>& range_readings) {
+void PrintState(const std::vector<double>& odometry_readings,
+                const std::vector<double>& range_readings) {
   CHECK_EQ(odometry_readings.size(), range_readings.size());
   double robot_location = 0.0;
   printf("pose: location     odom    range  r.error  o.error\n");
   for (int i = 0; i < odometry_readings.size(); ++i) {
     robot_location += odometry_readings[i];
-    const double range_error =
-        robot_location + range_readings[i] - FLAGS_corridor_length;
-    const double odometry_error = FLAGS_pose_separation - odometry_readings[i];
+    const double range_error = robot_location + range_readings[i] -
+                               CERES_GET_FLAG(FLAGS_corridor_length);
+    const double odometry_error =
+        CERES_GET_FLAG(FLAGS_pose_separation) - odometry_readings[i];
     printf("%4d: %8.3f %8.3f %8.3f %8.3f %8.3f\n",
            static_cast<int>(i),
            robot_location,
@@ -287,13 +287,13 @@
   google::InitGoogleLogging(argv[0]);
   GFLAGS_NAMESPACE::ParseCommandLineFlags(&argc, &argv, true);
   // Make sure that the arguments parsed are all positive.
-  CHECK_GT(FLAGS_corridor_length, 0.0);
-  CHECK_GT(FLAGS_pose_separation, 0.0);
-  CHECK_GT(FLAGS_odometry_stddev, 0.0);
-  CHECK_GT(FLAGS_range_stddev, 0.0);
+  CHECK_GT(CERES_GET_FLAG(FLAGS_corridor_length), 0.0);
+  CHECK_GT(CERES_GET_FLAG(FLAGS_pose_separation), 0.0);
+  CHECK_GT(CERES_GET_FLAG(FLAGS_odometry_stddev), 0.0);
+  CHECK_GT(CERES_GET_FLAG(FLAGS_range_stddev), 0.0);
 
-  vector<double> odometry_values;
-  vector<double> range_readings;
+  std::vector<double> odometry_values;
+  std::vector<double> range_readings;
   SimulateRobot(&odometry_values, &range_readings);
 
   printf("Initial values:\n");
@@ -303,25 +303,25 @@
   for (int i = 0; i < odometry_values.size(); ++i) {
     // Create and add a DynamicAutoDiffCostFunction for the RangeConstraint from
     // pose i.
-    vector<double*> parameter_blocks;
+    std::vector<double*> parameter_blocks;
     RangeConstraint::RangeCostFunction* range_cost_function =
         RangeConstraint::Create(
             i, range_readings[i], &odometry_values, &parameter_blocks);
-    problem.AddResidualBlock(range_cost_function, NULL, parameter_blocks);
+    problem.AddResidualBlock(range_cost_function, nullptr, parameter_blocks);
 
     // Create and add an AutoDiffCostFunction for the OdometryConstraint for
     // pose i.
     problem.AddResidualBlock(OdometryConstraint::Create(odometry_values[i]),
-                             NULL,
+                             nullptr,
                              &(odometry_values[i]));
   }
 
   ceres::Solver::Options solver_options;
   solver_options.minimizer_progress_to_stdout = true;
 
-  Solver::Summary summary;
+  ceres::Solver::Summary summary;
   printf("Solving...\n");
-  Solve(solver_options, &problem, &summary);
+  ceres::Solve(solver_options, &problem, &summary);
   printf("Done.\n");
   std::cout << summary.FullReport() << "\n";
   printf("Final values:\n");
diff --git a/third_party/ceres/examples/robust_curve_fitting.cc b/third_party/ceres/examples/robust_curve_fitting.cc
index 9b526c5..e08b0df 100644
--- a/third_party/ceres/examples/robust_curve_fitting.cc
+++ b/third_party/ceres/examples/robust_curve_fitting.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -27,6 +27,12 @@
 // POSSIBILITY OF SUCH DAMAGE.
 //
 // Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// This example fits the curve f(x;m,c) = e^(m * x + c) to data. However unlike
+// the data in curve_fitting.cc, the data here has outliers in it, so minimizing
+// the sum squared loss will result in a bad fit. So this example illustrates
+// the use of a robust loss function (CauchyLoss) to reduce the influence of the
+// outliers on the fit.
 
 #include "ceres/ceres.h"
 #include "glog/logging.h"
@@ -115,13 +121,6 @@
 };
 // clang-format on
 
-using ceres::AutoDiffCostFunction;
-using ceres::CauchyLoss;
-using ceres::CostFunction;
-using ceres::Problem;
-using ceres::Solve;
-using ceres::Solver;
-
 struct ExponentialResidual {
   ExponentialResidual(double x, double y) : x_(x), y_(y) {}
 
@@ -139,25 +138,28 @@
 int main(int argc, char** argv) {
   google::InitGoogleLogging(argv[0]);
 
-  double m = 0.0;
-  double c = 0.0;
+  const double initial_m = 0.0;
+  const double initial_c = 0.0;
+  double m = initial_m;
+  double c = initial_c;
 
-  Problem problem;
+  ceres::Problem problem;
   for (int i = 0; i < kNumObservations; ++i) {
-    CostFunction* cost_function =
-        new AutoDiffCostFunction<ExponentialResidual, 1, 1, 1>(
-            new ExponentialResidual(data[2 * i], data[2 * i + 1]));
-    problem.AddResidualBlock(cost_function, new CauchyLoss(0.5), &m, &c);
+    ceres::CostFunction* cost_function =
+        new ceres::AutoDiffCostFunction<ExponentialResidual, 1, 1, 1>(
+            data[2 * i], data[2 * i + 1]);
+    problem.AddResidualBlock(cost_function, new ceres::CauchyLoss(0.5), &m, &c);
   }
 
-  Solver::Options options;
+  ceres::Solver::Options options;
+  options.max_num_iterations = 25;
   options.linear_solver_type = ceres::DENSE_QR;
   options.minimizer_progress_to_stdout = true;
 
-  Solver::Summary summary;
-  Solve(options, &problem, &summary);
+  ceres::Solver::Summary summary;
+  ceres::Solve(options, &problem, &summary);
   std::cout << summary.BriefReport() << "\n";
-  std::cout << "Initial m: " << 0.0 << " c: " << 0.0 << "\n";
+  std::cout << "Initial m: " << initial_m << " c: " << initial_c << "\n";
   std::cout << "Final   m: " << m << " c: " << c << "\n";
   return 0;
 }
diff --git a/third_party/ceres/examples/rosenbrock.cc b/third_party/ceres/examples/rosenbrock.cc
index 1b9aef6..a382ccd 100644
--- a/third_party/ceres/examples/rosenbrock.cc
+++ b/third_party/ceres/examples/rosenbrock.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -27,30 +27,29 @@
 // POSSIBILITY OF SUCH DAMAGE.
 //
 // Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Example of minimizing the Rosenbrock function
+// (https://en.wikipedia.org/wiki/Rosenbrock_function) using
+// GradientProblemSolver using automatically computed derivatives.
 
 #include "ceres/ceres.h"
 #include "glog/logging.h"
 
 // f(x,y) = (1-x)^2 + 100(y - x^2)^2;
-class Rosenbrock : public ceres::FirstOrderFunction {
- public:
-  virtual ~Rosenbrock() {}
-
-  virtual bool Evaluate(const double* parameters,
-                        double* cost,
-                        double* gradient) const {
-    const double x = parameters[0];
-    const double y = parameters[1];
-
+struct Rosenbrock {
+  template <typename T>
+  bool operator()(const T* parameters, T* cost) const {
+    const T x = parameters[0];
+    const T y = parameters[1];
     cost[0] = (1.0 - x) * (1.0 - x) + 100.0 * (y - x * x) * (y - x * x);
-    if (gradient != NULL) {
-      gradient[0] = -2.0 * (1.0 - x) - 200.0 * (y - x * x) * 2.0 * x;
-      gradient[1] = 200.0 * (y - x * x);
-    }
     return true;
   }
 
-  virtual int NumParameters() const { return 2; }
+  static ceres::FirstOrderFunction* Create() {
+    constexpr int kNumParameters = 2;
+    return new ceres::AutoDiffFirstOrderFunction<Rosenbrock, kNumParameters>(
+        new Rosenbrock);
+  }
 };
 
 int main(int argc, char** argv) {
@@ -62,7 +61,7 @@
   options.minimizer_progress_to_stdout = true;
 
   ceres::GradientProblemSolver::Summary summary;
-  ceres::GradientProblem problem(new Rosenbrock());
+  ceres::GradientProblem problem(Rosenbrock::Create());
   ceres::Solve(options, problem, parameters, &summary);
 
   std::cout << summary.FullReport() << "\n";
diff --git a/third_party/ceres/examples/rosenbrock_analytic_diff.cc b/third_party/ceres/examples/rosenbrock_analytic_diff.cc
new file mode 100644
index 0000000..65e49eb
--- /dev/null
+++ b/third_party/ceres/examples/rosenbrock_analytic_diff.cc
@@ -0,0 +1,77 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Example of minimizing the Rosenbrock function
+// (https://en.wikipedia.org/wiki/Rosenbrock_function) using
+// GradientProblemSolver using analytic derivatives.
+
+#include "ceres/ceres.h"
+#include "glog/logging.h"
+
+// f(x,y) = (1-x)^2 + 100(y - x^2)^2;
+class Rosenbrock final : public ceres::FirstOrderFunction {
+ public:
+  bool Evaluate(const double* parameters,
+                double* cost,
+                double* gradient) const override {
+    const double x = parameters[0];
+    const double y = parameters[1];
+
+    cost[0] = (1.0 - x) * (1.0 - x) + 100.0 * (y - x * x) * (y - x * x);
+
+    if (gradient) {
+      gradient[0] = -2.0 * (1.0 - x) - 200.0 * (y - x * x) * 2.0 * x;
+      gradient[1] = 200.0 * (y - x * x);
+    }
+
+    return true;
+  }
+
+  int NumParameters() const override { return 2; }
+};
+
+int main(int argc, char** argv) {
+  google::InitGoogleLogging(argv[0]);
+
+  double parameters[2] = {-1.2, 1.0};
+
+  ceres::GradientProblemSolver::Options options;
+  options.minimizer_progress_to_stdout = true;
+
+  ceres::GradientProblemSolver::Summary summary;
+  ceres::GradientProblem problem(new Rosenbrock());
+  ceres::Solve(options, problem, parameters, &summary);
+
+  std::cout << summary.FullReport() << "\n";
+  std::cout << "Initial x: " << -1.2 << " y: " << 1.0 << "\n";
+  std::cout << "Final   x: " << parameters[0] << " y: " << parameters[1]
+            << "\n";
+  return 0;
+}
diff --git a/third_party/ceres/examples/rosenbrock_numeric_diff.cc b/third_party/ceres/examples/rosenbrock_numeric_diff.cc
new file mode 100644
index 0000000..a711b2f
--- /dev/null
+++ b/third_party/ceres/examples/rosenbrock_numeric_diff.cc
@@ -0,0 +1,74 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//
+// Example of minimizing the Rosenbrock function
+// (https://en.wikipedia.org/wiki/Rosenbrock_function) using
+// GradientProblemSolver using derivatives computed using numeric
+// differentiation.
+
+#include "ceres/ceres.h"
+#include "glog/logging.h"
+
+// f(x,y) = (1-x)^2 + 100(y - x^2)^2;
+struct Rosenbrock {
+  bool operator()(const double* parameters, double* cost) const {
+    const double x = parameters[0];
+    const double y = parameters[1];
+    cost[0] = (1.0 - x) * (1.0 - x) + 100.0 * (y - x * x) * (y - x * x);
+    return true;
+  }
+
+  static ceres::FirstOrderFunction* Create() {
+    constexpr int kNumParameters = 2;
+    return new ceres::NumericDiffFirstOrderFunction<Rosenbrock,
+                                                    ceres::CENTRAL,
+                                                    kNumParameters>(
+        new Rosenbrock);
+  }
+};
+
+int main(int argc, char** argv) {
+  google::InitGoogleLogging(argv[0]);
+
+  double parameters[2] = {-1.2, 1.0};
+
+  ceres::GradientProblemSolver::Options options;
+  options.minimizer_progress_to_stdout = true;
+
+  ceres::GradientProblemSolver::Summary summary;
+  ceres::GradientProblem problem(Rosenbrock::Create());
+  ceres::Solve(options, problem, parameters, &summary);
+
+  std::cout << summary.FullReport() << "\n";
+  std::cout << "Initial x: " << -1.2 << " y: " << 1.0 << "\n";
+  std::cout << "Final   x: " << parameters[0] << " y: " << parameters[1]
+            << "\n";
+  return 0;
+}
diff --git a/third_party/ceres/examples/sampled_function/CMakeLists.txt b/third_party/ceres/examples/sampled_function/CMakeLists.txt
index 8a17cad..1013753 100644
--- a/third_party/ceres/examples/sampled_function/CMakeLists.txt
+++ b/third_party/ceres/examples/sampled_function/CMakeLists.txt
@@ -1,5 +1,5 @@
 # Ceres Solver - A fast non-linear least squares minimizer
-# Copyright 2015 Google Inc. All rights reserved.
+# Copyright 2023 Google Inc. All rights reserved.
 # http://ceres-solver.org/
 #
 # Redistribution and use in source and binary forms, with or without
@@ -29,4 +29,4 @@
 # Author: vitus@google.com (Michael Vitus)
 
 add_executable(sampled_function sampled_function.cc)
-target_link_libraries(sampled_function Ceres::ceres)
+target_link_libraries(sampled_function PRIVATE Ceres::ceres)
diff --git a/third_party/ceres/examples/sampled_function/README.md b/third_party/ceres/examples/sampled_function/README.md
index ef1af43..5fde415 100644
--- a/third_party/ceres/examples/sampled_function/README.md
+++ b/third_party/ceres/examples/sampled_function/README.md
@@ -32,7 +32,7 @@
 
 ```c++
 bool Evaluate(double const* const* parameters, double* residuals, double** jacobians) const {
-  if (jacobians == NULL || jacobians[0] == NULL)
+  if (jacobians == nullptr || jacobians[0] == nullptr)
     interpolator_.Evaluate(parameters[0][0], residuals);
   else
     interpolator_.Evaluate(parameters[0][0], residuals, jacobians[0]);
diff --git a/third_party/ceres/examples/sampled_function/sampled_function.cc b/third_party/ceres/examples/sampled_function/sampled_function.cc
index e96018d..40e9c1f 100644
--- a/third_party/ceres/examples/sampled_function/sampled_function.cc
+++ b/third_party/ceres/examples/sampled_function/sampled_function.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,35 +35,27 @@
 #include "ceres/cubic_interpolation.h"
 #include "glog/logging.h"
 
-using ceres::AutoDiffCostFunction;
-using ceres::CostFunction;
-using ceres::CubicInterpolator;
-using ceres::Grid1D;
-using ceres::Problem;
-using ceres::Solve;
-using ceres::Solver;
+using Interpolator = ceres::CubicInterpolator<ceres::Grid1D<double>>;
 
 // A simple cost functor that interfaces an interpolated table of
 // values with automatic differentiation.
 struct InterpolatedCostFunctor {
-  explicit InterpolatedCostFunctor(
-      const CubicInterpolator<Grid1D<double>>& interpolator)
-      : interpolator_(interpolator) {}
+  explicit InterpolatedCostFunctor(const Interpolator& interpolator)
+      : interpolator(interpolator) {}
 
   template <typename T>
   bool operator()(const T* x, T* residuals) const {
-    interpolator_.Evaluate(*x, residuals);
+    interpolator.Evaluate(*x, residuals);
     return true;
   }
 
-  static CostFunction* Create(
-      const CubicInterpolator<Grid1D<double>>& interpolator) {
-    return new AutoDiffCostFunction<InterpolatedCostFunctor, 1, 1>(
-        new InterpolatedCostFunctor(interpolator));
+  static ceres::CostFunction* Create(const Interpolator& interpolator) {
+    return new ceres::AutoDiffCostFunction<InterpolatedCostFunctor, 1, 1>(
+        interpolator);
   }
 
  private:
-  const CubicInterpolator<Grid1D<double>>& interpolator_;
+  const Interpolator& interpolator;
 };
 
 int main(int argc, char** argv) {
@@ -76,18 +68,19 @@
     values[i] = (i - 4.5) * (i - 4.5);
   }
 
-  Grid1D<double> array(values, 0, kNumSamples);
-  CubicInterpolator<Grid1D<double>> interpolator(array);
+  ceres::Grid1D<double> array(values, 0, kNumSamples);
+  Interpolator interpolator(array);
 
   double x = 1.0;
-  Problem problem;
-  CostFunction* cost_function = InterpolatedCostFunctor::Create(interpolator);
-  problem.AddResidualBlock(cost_function, NULL, &x);
+  ceres::Problem problem;
+  ceres::CostFunction* cost_function =
+      InterpolatedCostFunctor::Create(interpolator);
+  problem.AddResidualBlock(cost_function, nullptr, &x);
 
-  Solver::Options options;
+  ceres::Solver::Options options;
   options.minimizer_progress_to_stdout = true;
-  Solver::Summary summary;
-  Solve(options, &problem, &summary);
+  ceres::Solver::Summary summary;
+  ceres::Solve(options, &problem, &summary);
   std::cout << summary.BriefReport() << "\n";
   std::cout << "Expected x: 4.5. Actual x : " << x << std::endl;
   return 0;
diff --git a/third_party/ceres/examples/simple_bundle_adjuster.cc b/third_party/ceres/examples/simple_bundle_adjuster.cc
index 8180d73..bb0ba1c 100644
--- a/third_party/ceres/examples/simple_bundle_adjuster.cc
+++ b/third_party/ceres/examples/simple_bundle_adjuster.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -66,7 +66,7 @@
 
   bool LoadFile(const char* filename) {
     FILE* fptr = fopen(filename, "r");
-    if (fptr == NULL) {
+    if (fptr == nullptr) {
       return false;
     };
 
@@ -164,8 +164,8 @@
   // the client code.
   static ceres::CostFunction* Create(const double observed_x,
                                      const double observed_y) {
-    return (new ceres::AutoDiffCostFunction<SnavelyReprojectionError, 2, 9, 3>(
-        new SnavelyReprojectionError(observed_x, observed_y)));
+    return new ceres::AutoDiffCostFunction<SnavelyReprojectionError, 2, 9, 3>(
+        observed_x, observed_y);
   }
 
   double observed_x;
@@ -198,7 +198,7 @@
     ceres::CostFunction* cost_function = SnavelyReprojectionError::Create(
         observations[2 * i + 0], observations[2 * i + 1]);
     problem.AddResidualBlock(cost_function,
-                             NULL /* squared loss */,
+                             nullptr /* squared loss */,
                              bal_problem.mutable_camera_for_observation(i),
                              bal_problem.mutable_point_for_observation(i));
   }
diff --git a/third_party/ceres/examples/slam/CMakeLists.txt b/third_party/ceres/examples/slam/CMakeLists.txt
index c72aa16..d0b03d7 100644
--- a/third_party/ceres/examples/slam/CMakeLists.txt
+++ b/third_party/ceres/examples/slam/CMakeLists.txt
@@ -1,5 +1,5 @@
 # Ceres Solver - A fast non-linear least squares minimizer
-# Copyright 2016 Google Inc. All rights reserved.
+# Copyright 2023 Google Inc. All rights reserved.
 # http://ceres-solver.org/
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/third_party/ceres/examples/slam/common/read_g2o.h b/third_party/ceres/examples/slam/common/read_g2o.h
index fea32e9..490b054 100644
--- a/third_party/ceres/examples/slam/common/read_g2o.h
+++ b/third_party/ceres/examples/slam/common/read_g2o.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2016 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -38,8 +38,7 @@
 
 #include "glog/logging.h"
 
-namespace ceres {
-namespace examples {
+namespace ceres::examples {
 
 // Reads a single pose from the input and inserts it into the map. Returns false
 // if there is a duplicate entry.
@@ -60,7 +59,7 @@
   return true;
 }
 
-// Reads the contraints between two vertices in the pose graph
+// Reads the constraints between two vertices in the pose graph
 template <typename Constraint, typename Allocator>
 void ReadConstraint(std::ifstream* infile,
                     std::vector<Constraint, Allocator>* constraints) {
@@ -104,8 +103,8 @@
 bool ReadG2oFile(const std::string& filename,
                  std::map<int, Pose, std::less<int>, MapAllocator>* poses,
                  std::vector<Constraint, VectorAllocator>* constraints) {
-  CHECK(poses != NULL);
-  CHECK(constraints != NULL);
+  CHECK(poses != nullptr);
+  CHECK(constraints != nullptr);
 
   poses->clear();
   constraints->clear();
@@ -137,7 +136,6 @@
   return true;
 }
 
-}  // namespace examples
-}  // namespace ceres
+}  // namespace ceres::examples
 
 #endif  // EXAMPLES_CERES_READ_G2O_H_
diff --git a/third_party/ceres/examples/slam/pose_graph_2d/CMakeLists.txt b/third_party/ceres/examples/slam/pose_graph_2d/CMakeLists.txt
index 20af056..87943ec 100644
--- a/third_party/ceres/examples/slam/pose_graph_2d/CMakeLists.txt
+++ b/third_party/ceres/examples/slam/pose_graph_2d/CMakeLists.txt
@@ -1,5 +1,5 @@
 # Ceres Solver - A fast non-linear least squares minimizer
-# Copyright 2016 Google Inc. All rights reserved.
+# Copyright 2023 Google Inc. All rights reserved.
 # http://ceres-solver.org/
 #
 # Redistribution and use in source and binary forms, with or without
@@ -30,10 +30,10 @@
 
 if (GFLAGS)
   add_executable(pose_graph_2d
-    angle_local_parameterization.h
+    angle_manifold.h
     normalize_angle.h
     pose_graph_2d.cc
     pose_graph_2d_error_term.h
     types.h)
-  target_link_libraries(pose_graph_2d Ceres::ceres gflags)
+  target_link_libraries(pose_graph_2d PRIVATE Ceres::ceres gflags)
 endif (GFLAGS)
diff --git a/third_party/ceres/examples/slam/pose_graph_2d/angle_local_parameterization.h b/third_party/ceres/examples/slam/pose_graph_2d/angle_local_parameterization.h
deleted file mode 100644
index a81637c..0000000
--- a/third_party/ceres/examples/slam/pose_graph_2d/angle_local_parameterization.h
+++ /dev/null
@@ -1,64 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2016 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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 Google Inc. 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.
-//
-// Author: vitus@google.com (Michael Vitus)
-
-#ifndef CERES_EXAMPLES_POSE_GRAPH_2D_ANGLE_LOCAL_PARAMETERIZATION_H_
-#define CERES_EXAMPLES_POSE_GRAPH_2D_ANGLE_LOCAL_PARAMETERIZATION_H_
-
-#include "ceres/local_parameterization.h"
-#include "normalize_angle.h"
-
-namespace ceres {
-namespace examples {
-
-// Defines a local parameterization for updating the angle to be constrained in
-// [-pi to pi).
-class AngleLocalParameterization {
- public:
-  template <typename T>
-  bool operator()(const T* theta_radians,
-                  const T* delta_theta_radians,
-                  T* theta_radians_plus_delta) const {
-    *theta_radians_plus_delta =
-        NormalizeAngle(*theta_radians + *delta_theta_radians);
-
-    return true;
-  }
-
-  static ceres::LocalParameterization* Create() {
-    return (new ceres::AutoDiffLocalParameterization<AngleLocalParameterization,
-                                                     1,
-                                                     1>);
-  }
-};
-
-}  // namespace examples
-}  // namespace ceres
-
-#endif  // CERES_EXAMPLES_POSE_GRAPH_2D_ANGLE_LOCAL_PARAMETERIZATION_H_
diff --git a/third_party/ceres/examples/slam/pose_graph_2d/angle_manifold.h b/third_party/ceres/examples/slam/pose_graph_2d/angle_manifold.h
new file mode 100644
index 0000000..456d923
--- /dev/null
+++ b/third_party/ceres/examples/slam/pose_graph_2d/angle_manifold.h
@@ -0,0 +1,68 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: vitus@google.com (Michael Vitus)
+//         sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_EXAMPLES_POSE_GRAPH_2D_ANGLE_MANIFOLD_H_
+#define CERES_EXAMPLES_POSE_GRAPH_2D_ANGLE_MANIFOLD_H_
+
+#include "ceres/autodiff_manifold.h"
+#include "normalize_angle.h"
+
+namespace ceres::examples {
+
+// Defines a manifold for updating the angle to be constrained in [-pi to pi).
+class AngleManifold {
+ public:
+  template <typename T>
+  bool Plus(const T* x_radians,
+            const T* delta_radians,
+            T* x_plus_delta_radians) const {
+    *x_plus_delta_radians = NormalizeAngle(*x_radians + *delta_radians);
+    return true;
+  }
+
+  template <typename T>
+  bool Minus(const T* y_radians,
+             const T* x_radians,
+             T* y_minus_x_radians) const {
+    *y_minus_x_radians =
+        NormalizeAngle(*y_radians) - NormalizeAngle(*x_radians);
+
+    return true;
+  }
+
+  static ceres::Manifold* Create() {
+    return new ceres::AutoDiffManifold<AngleManifold, 1, 1>;
+  }
+};
+
+}  // namespace ceres::examples
+
+#endif  // CERES_EXAMPLES_POSE_GRAPH_2D_ANGLE_MANIFOLD_H_
diff --git a/third_party/ceres/examples/slam/pose_graph_2d/normalize_angle.h b/third_party/ceres/examples/slam/pose_graph_2d/normalize_angle.h
index c215671..0602878 100644
--- a/third_party/ceres/examples/slam/pose_graph_2d/normalize_angle.h
+++ b/third_party/ceres/examples/slam/pose_graph_2d/normalize_angle.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2016 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,19 +35,17 @@
 
 #include "ceres/ceres.h"
 
-namespace ceres {
-namespace examples {
+namespace ceres::examples {
 
 // Normalizes the angle in radians between [-pi and pi).
 template <typename T>
 inline T NormalizeAngle(const T& angle_radians) {
   // Use ceres::floor because it is specialized for double and Jet types.
-  T two_pi(2.0 * M_PI);
+  T two_pi(2.0 * constants::pi);
   return angle_radians -
-         two_pi * ceres::floor((angle_radians + T(M_PI)) / two_pi);
+         two_pi * ceres::floor((angle_radians + T(constants::pi)) / two_pi);
 }
 
-}  // namespace examples
-}  // namespace ceres
+}  // namespace ceres::examples
 
 #endif  // CERES_EXAMPLES_POSE_GRAPH_2D_NORMALIZE_ANGLE_H_
diff --git a/third_party/ceres/examples/slam/pose_graph_2d/pose_graph_2d.cc b/third_party/ceres/examples/slam/pose_graph_2d/pose_graph_2d.cc
index 1172123..3ebae3f 100644
--- a/third_party/ceres/examples/slam/pose_graph_2d/pose_graph_2d.cc
+++ b/third_party/ceres/examples/slam/pose_graph_2d/pose_graph_2d.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2016 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -39,7 +39,7 @@
 #include <string>
 #include <vector>
 
-#include "angle_local_parameterization.h"
+#include "angle_manifold.h"
 #include "ceres/ceres.h"
 #include "common/read_g2o.h"
 #include "gflags/gflags.h"
@@ -49,8 +49,7 @@
 
 DEFINE_string(input, "", "The pose graph definition filename in g2o format.");
 
-namespace ceres {
-namespace examples {
+namespace ceres::examples {
 namespace {
 
 // Constructs the nonlinear least squares optimization problem from the pose
@@ -58,29 +57,21 @@
 void BuildOptimizationProblem(const std::vector<Constraint2d>& constraints,
                               std::map<int, Pose2d>* poses,
                               ceres::Problem* problem) {
-  CHECK(poses != NULL);
-  CHECK(problem != NULL);
+  CHECK(poses != nullptr);
+  CHECK(problem != nullptr);
   if (constraints.empty()) {
     LOG(INFO) << "No constraints, no problem to optimize.";
     return;
   }
 
-  ceres::LossFunction* loss_function = NULL;
-  ceres::LocalParameterization* angle_local_parameterization =
-      AngleLocalParameterization::Create();
+  ceres::LossFunction* loss_function = nullptr;
+  ceres::Manifold* angle_manifold = AngleManifold::Create();
 
-  for (std::vector<Constraint2d>::const_iterator constraints_iter =
-           constraints.begin();
-       constraints_iter != constraints.end();
-       ++constraints_iter) {
-    const Constraint2d& constraint = *constraints_iter;
-
-    std::map<int, Pose2d>::iterator pose_begin_iter =
-        poses->find(constraint.id_begin);
+  for (const auto& constraint : constraints) {
+    auto pose_begin_iter = poses->find(constraint.id_begin);
     CHECK(pose_begin_iter != poses->end())
         << "Pose with ID: " << constraint.id_begin << " not found.";
-    std::map<int, Pose2d>::iterator pose_end_iter =
-        poses->find(constraint.id_end);
+    auto pose_end_iter = poses->find(constraint.id_end);
     CHECK(pose_end_iter != poses->end())
         << "Pose with ID: " << constraint.id_end << " not found.";
 
@@ -98,10 +89,8 @@
                               &pose_end_iter->second.y,
                               &pose_end_iter->second.yaw_radians);
 
-    problem->SetParameterization(&pose_begin_iter->second.yaw_radians,
-                                 angle_local_parameterization);
-    problem->SetParameterization(&pose_end_iter->second.yaw_radians,
-                                 angle_local_parameterization);
+    problem->SetManifold(&pose_begin_iter->second.yaw_radians, angle_manifold);
+    problem->SetManifold(&pose_end_iter->second.yaw_radians, angle_manifold);
   }
 
   // The pose graph optimization problem has three DOFs that are not fully
@@ -111,7 +100,7 @@
   // internal damping which mitigate this issue, but it is better to properly
   // constrain the gauge freedom. This can be done by setting one of the poses
   // as constant so the optimizer cannot change it.
-  std::map<int, Pose2d>::iterator pose_start_iter = poses->begin();
+  auto pose_start_iter = poses->begin();
   CHECK(pose_start_iter != poses->end()) << "There are no poses.";
   problem->SetParameterBlockConstant(&pose_start_iter->second.x);
   problem->SetParameterBlockConstant(&pose_start_iter->second.y);
@@ -120,7 +109,7 @@
 
 // Returns true if the solve was successful.
 bool SolveOptimizationProblem(ceres::Problem* problem) {
-  CHECK(problem != NULL);
+  CHECK(problem != nullptr);
 
   ceres::Solver::Options options;
   options.max_num_iterations = 100;
@@ -143,10 +132,7 @@
     std::cerr << "Error opening the file: " << filename << '\n';
     return false;
   }
-  for (std::map<int, Pose2d>::const_iterator poses_iter = poses.begin();
-       poses_iter != poses.end();
-       ++poses_iter) {
-    const std::map<int, Pose2d>::value_type& pair = *poses_iter;
+  for (const auto& pair : poses) {
     outfile << pair.first << " " << pair.second.x << " " << pair.second.y << ' '
             << pair.second.yaw_radians << '\n';
   }
@@ -154,8 +140,7 @@
 }
 
 }  // namespace
-}  // namespace examples
-}  // namespace ceres
+}  // namespace ceres::examples
 
 int main(int argc, char** argv) {
   google::InitGoogleLogging(argv[0]);
diff --git a/third_party/ceres/examples/slam/pose_graph_2d/pose_graph_2d_error_term.h b/third_party/ceres/examples/slam/pose_graph_2d/pose_graph_2d_error_term.h
index 2df31f6..3d34f8d 100644
--- a/third_party/ceres/examples/slam/pose_graph_2d/pose_graph_2d_error_term.h
+++ b/third_party/ceres/examples/slam/pose_graph_2d/pose_graph_2d_error_term.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2016 Google Inc. All rights reserved.
+// Copyright 2024 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -34,9 +34,9 @@
 #define CERES_EXAMPLES_POSE_GRAPH_2D_POSE_GRAPH_2D_ERROR_TERM_H_
 
 #include "Eigen/Core"
+#include "ceres/autodiff_cost_function.h"
 
-namespace ceres {
-namespace examples {
+namespace ceres::examples {
 
 template <typename T>
 Eigen::Matrix<T, 2, 2> RotationMatrix2D(T yaw_radians) {
@@ -96,10 +96,9 @@
                                      double y_ab,
                                      double yaw_ab_radians,
                                      const Eigen::Matrix3d& sqrt_information) {
-    return (new ceres::
-                AutoDiffCostFunction<PoseGraph2dErrorTerm, 3, 1, 1, 1, 1, 1, 1>(
-                    new PoseGraph2dErrorTerm(
-                        x_ab, y_ab, yaw_ab_radians, sqrt_information)));
+    return new ceres::
+        AutoDiffCostFunction<PoseGraph2dErrorTerm, 3, 1, 1, 1, 1, 1, 1>(
+            x_ab, y_ab, yaw_ab_radians, sqrt_information);
   }
 
   EIGEN_MAKE_ALIGNED_OPERATOR_NEW
@@ -113,7 +112,6 @@
   const Eigen::Matrix3d sqrt_information_;
 };
 
-}  // namespace examples
-}  // namespace ceres
+}  // namespace ceres::examples
 
 #endif  // CERES_EXAMPLES_POSE_GRAPH_2D_POSE_GRAPH_2D_ERROR_TERM_H_
diff --git a/third_party/ceres/examples/slam/pose_graph_2d/types.h b/third_party/ceres/examples/slam/pose_graph_2d/types.h
index 3c13824..caf4ccb 100644
--- a/third_party/ceres/examples/slam/pose_graph_2d/types.h
+++ b/third_party/ceres/examples/slam/pose_graph_2d/types.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2016 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,8 +40,7 @@
 #include "Eigen/Core"
 #include "normalize_angle.h"
 
-namespace ceres {
-namespace examples {
+namespace ceres::examples {
 
 // The state for each vertex in the pose graph.
 struct Pose2d {
@@ -95,7 +94,6 @@
   return input;
 }
 
-}  // namespace examples
-}  // namespace ceres
+}  // namespace ceres::examples
 
 #endif  // CERES_EXAMPLES_POSE_GRAPH_2D_TYPES_H_
diff --git a/third_party/ceres/examples/slam/pose_graph_3d/CMakeLists.txt b/third_party/ceres/examples/slam/pose_graph_3d/CMakeLists.txt
index b6421cc..544b00e 100644
--- a/third_party/ceres/examples/slam/pose_graph_3d/CMakeLists.txt
+++ b/third_party/ceres/examples/slam/pose_graph_3d/CMakeLists.txt
@@ -1,5 +1,5 @@
 # Ceres Solver - A fast non-linear least squares minimizer
-# Copyright 2016 Google Inc. All rights reserved.
+# Copyright 2023 Google Inc. All rights reserved.
 # http://ceres-solver.org/
 #
 # Redistribution and use in source and binary forms, with or without
@@ -30,5 +30,5 @@
 
 if (GFLAGS)
   add_executable(pose_graph_3d pose_graph_3d.cc)
-  target_link_libraries(pose_graph_3d Ceres::ceres gflags)
+  target_link_libraries(pose_graph_3d PRIVATE Ceres::ceres gflags)
 endif (GFLAGS)
diff --git a/third_party/ceres/examples/slam/pose_graph_3d/pose_graph_3d.cc b/third_party/ceres/examples/slam/pose_graph_3d/pose_graph_3d.cc
index 2f8d6a4..522e2a1 100644
--- a/third_party/ceres/examples/slam/pose_graph_3d/pose_graph_3d.cc
+++ b/third_party/ceres/examples/slam/pose_graph_3d/pose_graph_3d.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2016 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -41,8 +41,7 @@
 
 DEFINE_string(input, "", "The pose graph definition filename in g2o format.");
 
-namespace ceres {
-namespace examples {
+namespace ceres::examples {
 namespace {
 
 // Constructs the nonlinear least squares optimization problem from the pose
@@ -50,27 +49,21 @@
 void BuildOptimizationProblem(const VectorOfConstraints& constraints,
                               MapOfPoses* poses,
                               ceres::Problem* problem) {
-  CHECK(poses != NULL);
-  CHECK(problem != NULL);
+  CHECK(poses != nullptr);
+  CHECK(problem != nullptr);
   if (constraints.empty()) {
     LOG(INFO) << "No constraints, no problem to optimize.";
     return;
   }
 
-  ceres::LossFunction* loss_function = NULL;
-  ceres::LocalParameterization* quaternion_local_parameterization =
-      new EigenQuaternionParameterization;
+  ceres::LossFunction* loss_function = nullptr;
+  ceres::Manifold* quaternion_manifold = new EigenQuaternionManifold;
 
-  for (VectorOfConstraints::const_iterator constraints_iter =
-           constraints.begin();
-       constraints_iter != constraints.end();
-       ++constraints_iter) {
-    const Constraint3d& constraint = *constraints_iter;
-
-    MapOfPoses::iterator pose_begin_iter = poses->find(constraint.id_begin);
+  for (const auto& constraint : constraints) {
+    auto pose_begin_iter = poses->find(constraint.id_begin);
     CHECK(pose_begin_iter != poses->end())
         << "Pose with ID: " << constraint.id_begin << " not found.";
-    MapOfPoses::iterator pose_end_iter = poses->find(constraint.id_end);
+    auto pose_end_iter = poses->find(constraint.id_end);
     CHECK(pose_end_iter != poses->end())
         << "Pose with ID: " << constraint.id_end << " not found.";
 
@@ -87,10 +80,10 @@
                               pose_end_iter->second.p.data(),
                               pose_end_iter->second.q.coeffs().data());
 
-    problem->SetParameterization(pose_begin_iter->second.q.coeffs().data(),
-                                 quaternion_local_parameterization);
-    problem->SetParameterization(pose_end_iter->second.q.coeffs().data(),
-                                 quaternion_local_parameterization);
+    problem->SetManifold(pose_begin_iter->second.q.coeffs().data(),
+                         quaternion_manifold);
+    problem->SetManifold(pose_end_iter->second.q.coeffs().data(),
+                         quaternion_manifold);
   }
 
   // The pose graph optimization problem has six DOFs that are not fully
@@ -100,7 +93,7 @@
   // internal damping which mitigates this issue, but it is better to properly
   // constrain the gauge freedom. This can be done by setting one of the poses
   // as constant so the optimizer cannot change it.
-  MapOfPoses::iterator pose_start_iter = poses->begin();
+  auto pose_start_iter = poses->begin();
   CHECK(pose_start_iter != poses->end()) << "There are no poses.";
   problem->SetParameterBlockConstant(pose_start_iter->second.p.data());
   problem->SetParameterBlockConstant(pose_start_iter->second.q.coeffs().data());
@@ -108,7 +101,7 @@
 
 // Returns true if the solve was successful.
 bool SolveOptimizationProblem(ceres::Problem* problem) {
-  CHECK(problem != NULL);
+  CHECK(problem != nullptr);
 
   ceres::Solver::Options options;
   options.max_num_iterations = 200;
@@ -130,18 +123,7 @@
     LOG(ERROR) << "Error opening the file: " << filename;
     return false;
   }
-  for (std::map<int,
-                Pose3d,
-                std::less<int>,
-                Eigen::aligned_allocator<std::pair<const int, Pose3d>>>::
-           const_iterator poses_iter = poses.begin();
-       poses_iter != poses.end();
-       ++poses_iter) {
-    const std::map<int,
-                   Pose3d,
-                   std::less<int>,
-                   Eigen::aligned_allocator<std::pair<const int, Pose3d>>>::
-        value_type& pair = *poses_iter;
+  for (const auto& pair : poses) {
     outfile << pair.first << " " << pair.second.p.transpose() << " "
             << pair.second.q.x() << " " << pair.second.q.y() << " "
             << pair.second.q.z() << " " << pair.second.q.w() << '\n';
@@ -150,8 +132,7 @@
 }
 
 }  // namespace
-}  // namespace examples
-}  // namespace ceres
+}  // namespace ceres::examples
 
 int main(int argc, char** argv) {
   google::InitGoogleLogging(argv[0]);
diff --git a/third_party/ceres/examples/slam/pose_graph_3d/pose_graph_3d_error_term.h b/third_party/ceres/examples/slam/pose_graph_3d/pose_graph_3d_error_term.h
index 1f3e8de..b1c0138 100644
--- a/third_party/ceres/examples/slam/pose_graph_3d/pose_graph_3d_error_term.h
+++ b/third_party/ceres/examples/slam/pose_graph_3d/pose_graph_3d_error_term.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2016 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -31,12 +31,13 @@
 #ifndef EXAMPLES_CERES_POSE_GRAPH_3D_ERROR_TERM_H_
 #define EXAMPLES_CERES_POSE_GRAPH_3D_ERROR_TERM_H_
 
+#include <utility>
+
 #include "Eigen/Core"
 #include "ceres/autodiff_cost_function.h"
 #include "types.h"
 
-namespace ceres {
-namespace examples {
+namespace ceres::examples {
 
 // Computes the error term for two poses that have a relative pose measurement
 // between them. Let the hat variables be the measurement. We have two poses x_a
@@ -69,9 +70,10 @@
 // where I is the information matrix which is the inverse of the covariance.
 class PoseGraph3dErrorTerm {
  public:
-  PoseGraph3dErrorTerm(const Pose3d& t_ab_measured,
-                       const Eigen::Matrix<double, 6, 6>& sqrt_information)
-      : t_ab_measured_(t_ab_measured), sqrt_information_(sqrt_information) {}
+  PoseGraph3dErrorTerm(Pose3d t_ab_measured,
+                       Eigen::Matrix<double, 6, 6> sqrt_information)
+      : t_ab_measured_(std::move(t_ab_measured)),
+        sqrt_information_(std::move(sqrt_information)) {}
 
   template <typename T>
   bool operator()(const T* const p_a_ptr,
@@ -114,7 +116,7 @@
       const Pose3d& t_ab_measured,
       const Eigen::Matrix<double, 6, 6>& sqrt_information) {
     return new ceres::AutoDiffCostFunction<PoseGraph3dErrorTerm, 6, 3, 4, 3, 4>(
-        new PoseGraph3dErrorTerm(t_ab_measured, sqrt_information));
+        t_ab_measured, sqrt_information);
   }
 
   EIGEN_MAKE_ALIGNED_OPERATOR_NEW
@@ -126,7 +128,6 @@
   const Eigen::Matrix<double, 6, 6> sqrt_information_;
 };
 
-}  // namespace examples
-}  // namespace ceres
+}  // namespace ceres::examples
 
 #endif  // EXAMPLES_CERES_POSE_GRAPH_3D_ERROR_TERM_H_
diff --git a/third_party/ceres/examples/slam/pose_graph_3d/types.h b/third_party/ceres/examples/slam/pose_graph_3d/types.h
index d3f19ed..207dd5d 100644
--- a/third_party/ceres/examples/slam/pose_graph_3d/types.h
+++ b/third_party/ceres/examples/slam/pose_graph_3d/types.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2016 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -31,6 +31,7 @@
 #ifndef EXAMPLES_CERES_TYPES_H_
 #define EXAMPLES_CERES_TYPES_H_
 
+#include <functional>
 #include <istream>
 #include <map>
 #include <string>
@@ -39,8 +40,7 @@
 #include "Eigen/Core"
 #include "Eigen/Geometry"
 
-namespace ceres {
-namespace examples {
+namespace ceres::examples {
 
 struct Pose3d {
   Eigen::Vector3d p;
@@ -61,11 +61,11 @@
   return input;
 }
 
-typedef std::map<int,
-                 Pose3d,
-                 std::less<int>,
-                 Eigen::aligned_allocator<std::pair<const int, Pose3d>>>
-    MapOfPoses;
+using MapOfPoses =
+    std::map<int,
+             Pose3d,
+             std::less<int>,
+             Eigen::aligned_allocator<std::pair<const int, Pose3d>>>;
 
 // The constraint between two vertices in the pose graph. The constraint is the
 // transformation from vertex id_begin to vertex id_end.
@@ -103,10 +103,9 @@
   return input;
 }
 
-typedef std::vector<Constraint3d, Eigen::aligned_allocator<Constraint3d>>
-    VectorOfConstraints;
+using VectorOfConstraints =
+    std::vector<Constraint3d, Eigen::aligned_allocator<Constraint3d>>;
 
-}  // namespace examples
-}  // namespace ceres
+}  // namespace ceres::examples
 
 #endif  // EXAMPLES_CERES_TYPES_H_
diff --git a/third_party/ceres/examples/snavely_reprojection_error.h b/third_party/ceres/examples/snavely_reprojection_error.h
index eb39d23..aaf0c6c 100644
--- a/third_party/ceres/examples/snavely_reprojection_error.h
+++ b/third_party/ceres/examples/snavely_reprojection_error.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2024 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -41,10 +41,10 @@
 #ifndef CERES_EXAMPLES_SNAVELY_REPROJECTION_ERROR_H_
 #define CERES_EXAMPLES_SNAVELY_REPROJECTION_ERROR_H_
 
+#include "ceres/autodiff_cost_function.h"
 #include "ceres/rotation.h"
 
-namespace ceres {
-namespace examples {
+namespace ceres::examples {
 
 // Templated pinhole camera model for used with Ceres.  The camera is
 // parameterized using 9 parameters: 3 for rotation, 3 for translation, 1 for
@@ -95,8 +95,8 @@
   // the client code.
   static ceres::CostFunction* Create(const double observed_x,
                                      const double observed_y) {
-    return (new ceres::AutoDiffCostFunction<SnavelyReprojectionError, 2, 9, 3>(
-        new SnavelyReprojectionError(observed_x, observed_y)));
+    return new ceres::AutoDiffCostFunction<SnavelyReprojectionError, 2, 9, 3>(
+        observed_x, observed_y);
   }
 
   double observed_x;
@@ -123,7 +123,7 @@
     // We use QuaternionRotatePoint as it does not assume that the
     // quaternion is normalized, since one of the ways to run the
     // bundle adjuster is to let Ceres optimize all 4 quaternion
-    // parameters without a local parameterization.
+    // parameters without using a Quaternion manifold.
     T p[3];
     QuaternionRotatePoint(camera, point, p);
 
@@ -160,20 +160,15 @@
   // the client code.
   static ceres::CostFunction* Create(const double observed_x,
                                      const double observed_y) {
-    return (
-        new ceres::AutoDiffCostFunction<SnavelyReprojectionErrorWithQuaternions,
-                                        2,
-                                        10,
-                                        3>(
-            new SnavelyReprojectionErrorWithQuaternions(observed_x,
-                                                        observed_y)));
+    return new ceres::
+        AutoDiffCostFunction<SnavelyReprojectionErrorWithQuaternions, 2, 10, 3>(
+            observed_x, observed_y);
   }
 
   double observed_x;
   double observed_y;
 };
 
-}  // namespace examples
-}  // namespace ceres
+}  // namespace ceres::examples
 
 #endif  // CERES_EXAMPLES_SNAVELY_REPROJECTION_ERROR_H_
diff --git a/third_party/ceres/include/ceres/autodiff_cost_function.h b/third_party/ceres/include/ceres/autodiff_cost_function.h
index 207f0a4..878b2ec 100644
--- a/third_party/ceres/include/ceres/autodiff_cost_function.h
+++ b/third_party/ceres/include/ceres/autodiff_cost_function.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2024 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -82,9 +82,9 @@
 // Then given this class definition, the auto differentiated cost function for
 // it can be constructed as follows.
 //
-//   CostFunction* cost_function
-//       = new AutoDiffCostFunction<MyScalarCostFunctor, 1, 2, 2>(
-//            new MyScalarCostFunctor(1.0));             ^  ^  ^
+//   auto* cost_function
+//       = new AutoDiffCostFunction<MyScalarCostFunctor, 1, 2, 2>(1.0);
+//                                                       ^  ^  ^
 //                                                       |  |  |
 //                            Dimension of residual -----+  |  |
 //                            Dimension of x ---------------+  |
@@ -99,9 +99,11 @@
 // AutoDiffCostFunction also supports cost functions with a
 // runtime-determined number of residuals. For example:
 //
-//   CostFunction* cost_function
-//       = new AutoDiffCostFunction<MyScalarCostFunctor, DYNAMIC, 2, 2>(
-//           new CostFunctorWithDynamicNumResiduals(1.0),   ^     ^  ^
+//   auto functor = std::make_unique<CostFunctorWithDynamicNumResiduals>(1.0);
+//   auto* cost_function
+//       = new AutoDiffCostFunction<CostFunctorWithDynamicNumResiduals,
+//                                                       DYNAMIC, 2, 2>(
+//           std::move(functor),                            ^     ^  ^
 //           runtime_number_of_residuals); <----+           |     |  |
 //                                              |           |     |  |
 //                                              |           |     |  |
@@ -126,11 +128,11 @@
 #define CERES_PUBLIC_AUTODIFF_COST_FUNCTION_H_
 
 #include <memory>
+#include <type_traits>
 
 #include "ceres/internal/autodiff.h"
 #include "ceres/sized_cost_function.h"
 #include "ceres/types.h"
-#include "glog/logging.h"
 
 namespace ceres {
 
@@ -151,17 +153,36 @@
 template <typename CostFunctor,
           int kNumResiduals,  // Number of residuals, or ceres::DYNAMIC.
           int... Ns>          // Number of parameters in each parameter block.
-class AutoDiffCostFunction : public SizedCostFunction<kNumResiduals, Ns...> {
+class AutoDiffCostFunction final
+    : public SizedCostFunction<kNumResiduals, Ns...> {
  public:
   // Takes ownership of functor by default. Uses the template-provided
   // value for the number of residuals ("kNumResiduals").
+  explicit AutoDiffCostFunction(std::unique_ptr<CostFunctor> functor)
+      : AutoDiffCostFunction{std::move(functor), TAKE_OWNERSHIP, FIXED_INIT} {}
+
+  // Constructs the CostFunctor on the heap and takes the ownership.
+  // Invocable only if the number of residuals is known at compile-time.
+  template <class... Args,
+            bool kIsDynamic = kNumResiduals == DYNAMIC,
+            std::enable_if_t<!kIsDynamic &&
+                             std::is_constructible_v<CostFunctor, Args&&...>>* =
+                nullptr>
+  explicit AutoDiffCostFunction(Args&&... args)
+      // NOTE We explicitly use direct initialization using parentheses instead
+      // of uniform initialization using braces to avoid narrowing conversion
+      // warnings.
+      : AutoDiffCostFunction{
+            std::make_unique<CostFunctor>(std::forward<Args>(args)...)} {}
+
+  AutoDiffCostFunction(std::unique_ptr<CostFunctor> functor, int num_residuals)
+      : AutoDiffCostFunction{
+            std::move(functor), num_residuals, TAKE_OWNERSHIP, DYNAMIC_INIT} {}
+
   explicit AutoDiffCostFunction(CostFunctor* functor,
                                 Ownership ownership = TAKE_OWNERSHIP)
-      : functor_(functor), ownership_(ownership) {
-    static_assert(kNumResiduals != DYNAMIC,
-                  "Can't run the fixed-size constructor if the number of "
-                  "residuals is set to ceres::DYNAMIC.");
-  }
+      : AutoDiffCostFunction{
+            std::unique_ptr<CostFunctor>{functor}, ownership, FIXED_INIT} {}
 
   // Takes ownership of functor by default. Ignores the template-provided
   // kNumResiduals in favor of the "num_residuals" argument provided.
@@ -171,17 +192,18 @@
   AutoDiffCostFunction(CostFunctor* functor,
                        int num_residuals,
                        Ownership ownership = TAKE_OWNERSHIP)
-      : functor_(functor), ownership_(ownership) {
-    static_assert(kNumResiduals == DYNAMIC,
-                  "Can't run the dynamic-size constructor if the number of "
-                  "residuals is not ceres::DYNAMIC.");
-    SizedCostFunction<kNumResiduals, Ns...>::set_num_residuals(num_residuals);
-  }
+      : AutoDiffCostFunction{std::unique_ptr<CostFunctor>{functor},
+                             num_residuals,
+                             ownership,
+                             DYNAMIC_INIT} {}
 
-  explicit AutoDiffCostFunction(AutoDiffCostFunction&& other)
-      : functor_(std::move(other.functor_)), ownership_(other.ownership_) {}
+  AutoDiffCostFunction(AutoDiffCostFunction&& other) noexcept = default;
+  AutoDiffCostFunction& operator=(AutoDiffCostFunction&& other) noexcept =
+      default;
+  AutoDiffCostFunction(const AutoDiffCostFunction& other) = delete;
+  AutoDiffCostFunction& operator=(const AutoDiffCostFunction& other) = delete;
 
-  virtual ~AutoDiffCostFunction() {
+  ~AutoDiffCostFunction() override {
     // Manually release pointer if configured to not take ownership rather than
     // deleting only if ownership is taken.
     // This is to stay maximally compatible to old user code which may have
@@ -203,7 +225,7 @@
     using ParameterDims =
         typename SizedCostFunction<kNumResiduals, Ns...>::ParameterDims;
 
-    if (!jacobians) {
+    if (jacobians == nullptr) {
       return internal::VariadicEvaluate<ParameterDims>(
           *functor_, parameters, residuals);
     }
@@ -215,7 +237,36 @@
         jacobians);
   };
 
+  const CostFunctor& functor() const { return *functor_; }
+
  private:
+  // Tags used to differentiate between dynamic and fixed size constructor
+  // delegate invocations.
+  static constexpr std::integral_constant<int, DYNAMIC> DYNAMIC_INIT{};
+  static constexpr std::integral_constant<int, kNumResiduals> FIXED_INIT{};
+
+  template <class InitTag>
+  AutoDiffCostFunction(std::unique_ptr<CostFunctor> functor,
+                       int num_residuals,
+                       Ownership ownership,
+                       InitTag /*unused*/)
+      : functor_{std::move(functor)}, ownership_{ownership} {
+    static_assert(kNumResiduals == FIXED_INIT,
+                  "Can't run the fixed-size constructor if the number of "
+                  "residuals is set to ceres::DYNAMIC.");
+
+    if constexpr (InitTag::value == DYNAMIC_INIT) {
+      SizedCostFunction<kNumResiduals, Ns...>::set_num_residuals(num_residuals);
+    }
+  }
+
+  template <class InitTag>
+  AutoDiffCostFunction(std::unique_ptr<CostFunctor> functor,
+                       Ownership ownership,
+                       InitTag tag)
+      : AutoDiffCostFunction{
+            std::move(functor), kNumResiduals, ownership, tag} {}
+
   std::unique_ptr<CostFunctor> functor_;
   Ownership ownership_;
 };
diff --git a/third_party/ceres/include/ceres/autodiff_first_order_function.h b/third_party/ceres/include/ceres/autodiff_first_order_function.h
index b98d845..6cd1b13 100644
--- a/third_party/ceres/include/ceres/autodiff_first_order_function.h
+++ b/third_party/ceres/include/ceres/autodiff_first_order_function.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2024 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -32,6 +32,7 @@
 #define CERES_PUBLIC_AUTODIFF_FIRST_ORDER_FUNCTION_H_
 
 #include <memory>
+#include <type_traits>
 
 #include "ceres/first_order_function.h"
 #include "ceres/internal/eigen.h"
@@ -102,15 +103,25 @@
 // seen where instead of using a_ directly, a_ is wrapped with T(a_).
 
 template <typename FirstOrderFunctor, int kNumParameters>
-class AutoDiffFirstOrderFunction : public FirstOrderFunction {
+class AutoDiffFirstOrderFunction final : public FirstOrderFunction {
  public:
   // Takes ownership of functor.
   explicit AutoDiffFirstOrderFunction(FirstOrderFunctor* functor)
-      : functor_(functor) {
+      : AutoDiffFirstOrderFunction{
+            std::unique_ptr<FirstOrderFunctor>{functor}} {}
+
+  explicit AutoDiffFirstOrderFunction(
+      std::unique_ptr<FirstOrderFunctor> functor)
+      : functor_(std::move(functor)) {
     static_assert(kNumParameters > 0, "kNumParameters must be positive");
   }
 
-  virtual ~AutoDiffFirstOrderFunction() {}
+  template <class... Args,
+            std::enable_if_t<std::is_constructible_v<FirstOrderFunctor,
+                                                     Args&&...>>* = nullptr>
+  explicit AutoDiffFirstOrderFunction(Args&&... args)
+      : AutoDiffFirstOrderFunction{
+            std::make_unique<FirstOrderFunctor>(std::forward<Args>(args)...)} {}
 
   bool Evaluate(const double* const parameters,
                 double* cost,
@@ -119,7 +130,7 @@
       return (*functor_)(parameters, cost);
     }
 
-    typedef Jet<double, kNumParameters> JetT;
+    using JetT = Jet<double, kNumParameters>;
     internal::FixedArray<JetT, (256 * 7) / sizeof(JetT)> x(kNumParameters);
     for (int i = 0; i < kNumParameters; ++i) {
       x[i].a = parameters[i];
@@ -142,6 +153,8 @@
 
   int NumParameters() const override { return kNumParameters; }
 
+  const FirstOrderFunctor& functor() const { return *functor_; }
+
  private:
   std::unique_ptr<FirstOrderFunctor> functor_;
 };
diff --git a/third_party/ceres/include/ceres/autodiff_local_parameterization.h b/third_party/ceres/include/ceres/autodiff_local_parameterization.h
deleted file mode 100644
index d694376..0000000
--- a/third_party/ceres/include/ceres/autodiff_local_parameterization.h
+++ /dev/null
@@ -1,152 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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 Google Inc. 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.
-//
-// Author: sergey.vfx@gmail.com (Sergey Sharybin)
-//         mierle@gmail.com (Keir Mierle)
-//         sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_PUBLIC_AUTODIFF_LOCAL_PARAMETERIZATION_H_
-#define CERES_PUBLIC_AUTODIFF_LOCAL_PARAMETERIZATION_H_
-
-#include <memory>
-
-#include "ceres/internal/autodiff.h"
-#include "ceres/local_parameterization.h"
-
-namespace ceres {
-
-// Create local parameterization with Jacobians computed via automatic
-// differentiation. For more information on local parameterizations,
-// see include/ceres/local_parameterization.h
-//
-// To get an auto differentiated local parameterization, you must define
-// a class with a templated operator() (a functor) that computes
-//
-//   x_plus_delta = Plus(x, delta);
-//
-// the template parameter T. The autodiff framework substitutes appropriate
-// "Jet" objects for T in order to compute the derivative when necessary, but
-// this is hidden, and you should write the function as if T were a scalar type
-// (e.g. a double-precision floating point number).
-//
-// The function must write the computed value in the last argument (the only
-// non-const one) and return true to indicate success.
-//
-// For example, Quaternions have a three dimensional local
-// parameterization. It's plus operation can be implemented as (taken
-// from internal/ceres/auto_diff_local_parameterization_test.cc)
-//
-//   struct QuaternionPlus {
-//     template<typename T>
-//     bool operator()(const T* x, const T* delta, T* x_plus_delta) const {
-//       const T squared_norm_delta =
-//           delta[0] * delta[0] + delta[1] * delta[1] + delta[2] * delta[2];
-//
-//       T q_delta[4];
-//       if (squared_norm_delta > T(0.0)) {
-//         T norm_delta = sqrt(squared_norm_delta);
-//         const T sin_delta_by_delta = sin(norm_delta) / norm_delta;
-//         q_delta[0] = cos(norm_delta);
-//         q_delta[1] = sin_delta_by_delta * delta[0];
-//         q_delta[2] = sin_delta_by_delta * delta[1];
-//         q_delta[3] = sin_delta_by_delta * delta[2];
-//       } else {
-//         // We do not just use q_delta = [1,0,0,0] here because that is a
-//         // constant and when used for automatic differentiation will
-//         // lead to a zero derivative. Instead we take a first order
-//         // approximation and evaluate it at zero.
-//         q_delta[0] = T(1.0);
-//         q_delta[1] = delta[0];
-//         q_delta[2] = delta[1];
-//         q_delta[3] = delta[2];
-//       }
-//
-//       QuaternionProduct(q_delta, x, x_plus_delta);
-//       return true;
-//     }
-//   };
-//
-// Then given this struct, the auto differentiated local
-// parameterization can now be constructed as
-//
-//   LocalParameterization* local_parameterization =
-//     new AutoDiffLocalParameterization<QuaternionPlus, 4, 3>;
-//                                                       |  |
-//                            Global Size ---------------+  |
-//                            Local Size -------------------+
-//
-// WARNING: Since the functor will get instantiated with different types for
-// T, you must to convert from other numeric types to T before mixing
-// computations with other variables of type T. In the example above, this is
-// seen where instead of using k_ directly, k_ is wrapped with T(k_).
-
-template <typename Functor, int kGlobalSize, int kLocalSize>
-class AutoDiffLocalParameterization : public LocalParameterization {
- public:
-  AutoDiffLocalParameterization() : functor_(new Functor()) {}
-
-  // Takes ownership of functor.
-  explicit AutoDiffLocalParameterization(Functor* functor)
-      : functor_(functor) {}
-
-  virtual ~AutoDiffLocalParameterization() {}
-  bool Plus(const double* x,
-            const double* delta,
-            double* x_plus_delta) const override {
-    return (*functor_)(x, delta, x_plus_delta);
-  }
-
-  bool ComputeJacobian(const double* x, double* jacobian) const override {
-    double zero_delta[kLocalSize];
-    for (int i = 0; i < kLocalSize; ++i) {
-      zero_delta[i] = 0.0;
-    }
-
-    double x_plus_delta[kGlobalSize];
-    for (int i = 0; i < kGlobalSize; ++i) {
-      x_plus_delta[i] = 0.0;
-    }
-
-    const double* parameter_ptrs[2] = {x, zero_delta};
-    double* jacobian_ptrs[2] = {NULL, jacobian};
-    return internal::AutoDifferentiate<
-        kGlobalSize,
-        internal::StaticParameterDims<kGlobalSize, kLocalSize>>(
-        *functor_, parameter_ptrs, kGlobalSize, x_plus_delta, jacobian_ptrs);
-  }
-
-  int GlobalSize() const override { return kGlobalSize; }
-  int LocalSize() const override { return kLocalSize; }
-
- private:
-  std::unique_ptr<Functor> functor_;
-};
-
-}  // namespace ceres
-
-#endif  // CERES_PUBLIC_AUTODIFF_LOCAL_PARAMETERIZATION_H_
diff --git a/third_party/ceres/include/ceres/autodiff_manifold.h b/third_party/ceres/include/ceres/autodiff_manifold.h
new file mode 100644
index 0000000..4bf7e56
--- /dev/null
+++ b/third_party/ceres/include/ceres/autodiff_manifold.h
@@ -0,0 +1,259 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_PUBLIC_AUTODIFF_MANIFOLD_H_
+#define CERES_PUBLIC_AUTODIFF_MANIFOLD_H_
+
+#include <memory>
+
+#include "ceres/internal/autodiff.h"
+#include "ceres/manifold.h"
+
+namespace ceres {
+
+// Create a Manifold with Jacobians computed via automatic differentiation. For
+// more information on manifolds, see include/ceres/manifold.h
+//
+// To get an auto differentiated manifold, you must define a class/struct with
+// templated Plus and Minus functions that compute
+//
+//   x_plus_delta = Plus(x, delta);
+//   y_minus_x    = Minus(y, x);
+//
+// Where, x, y and x_plus_delta are vectors on the manifold in the ambient space
+// (so they are kAmbientSize vectors) and delta, y_minus_x are vectors in the
+// tangent space (so they are kTangentSize vectors).
+//
+// The Functor should have the signature:
+//
+// struct Functor {
+//   template <typename T>
+//   bool Plus(const T* x, const T* delta, T* x_plus_delta) const;
+//
+//   template <typename T>
+//   bool Minus(const T* y, const T* x, T* y_minus_x) const;
+// };
+//
+// Observe that the Plus and Minus operations are templated on the parameter T.
+// The autodiff framework substitutes appropriate "Jet" objects for T in order
+// to compute the derivative when necessary. This is the same mechanism that is
+// used to compute derivatives when using AutoDiffCostFunction.
+//
+// Plus and Minus should return true if the computation is successful and false
+// otherwise, in which case the result will not be used.
+//
+// Given this Functor, the corresponding Manifold can be constructed as:
+//
+// AutoDiffManifold<Functor, kAmbientSize, kTangentSize> manifold;
+//
+// As a concrete example consider the case of Quaternions. Quaternions form a
+// three dimensional manifold embedded in R^4, i.e. they have an ambient
+// dimension of 4 and their tangent space has dimension 3. The following Functor
+// (taken from autodiff_manifold_test.cc) defines the Plus and Minus operations
+// on the Quaternion manifold:
+//
+// NOTE: The following is only used for illustration purposes. Ceres Solver
+// ships with optimized production grade QuaternionManifold implementation. See
+// manifold.h.
+//
+// This functor assumes that the quaternions are laid out as [w,x,y,z] in
+// memory, i.e. the real or scalar part is the first coordinate.
+//
+// struct QuaternionFunctor {
+//   template <typename T>
+//   bool Plus(const T* x, const T* delta, T* x_plus_delta) const {
+//     const T squared_norm_delta =
+//         delta[0] * delta[0] + delta[1] * delta[1] + delta[2] * delta[2];
+//
+//     T q_delta[4];
+//     if (squared_norm_delta > T(0.0)) {
+//       T norm_delta = sqrt(squared_norm_delta);
+//       const T sin_delta_by_delta = sin(norm_delta) / norm_delta;
+//       q_delta[0] = cos(norm_delta);
+//       q_delta[1] = sin_delta_by_delta * delta[0];
+//       q_delta[2] = sin_delta_by_delta * delta[1];
+//       q_delta[3] = sin_delta_by_delta * delta[2];
+//     } else {
+//       // We do not just use q_delta = [1,0,0,0] here because that is a
+//       // constant and when used for automatic differentiation will
+//       // lead to a zero derivative. Instead we take a first order
+//       // approximation and evaluate it at zero.
+//       q_delta[0] = T(1.0);
+//       q_delta[1] = delta[0];
+//       q_delta[2] = delta[1];
+//       q_delta[3] = delta[2];
+//     }
+//
+//     QuaternionProduct(q_delta, x, x_plus_delta);
+//     return true;
+//   }
+//
+//   template <typename T>
+//   bool Minus(const T* y, const T* x, T* y_minus_x) const {
+//     T minus_x[4] = {x[0], -x[1], -x[2], -x[3]};
+//     T ambient_y_minus_x[4];
+//     QuaternionProduct(y, minus_x, ambient_y_minus_x);
+//     T u_norm = sqrt(ambient_y_minus_x[1] * ambient_y_minus_x[1] +
+//                     ambient_y_minus_x[2] * ambient_y_minus_x[2] +
+//                     ambient_y_minus_x[3] * ambient_y_minus_x[3]);
+//     if (u_norm > 0.0) {
+//       T theta = atan2(u_norm, ambient_y_minus_x[0]);
+//       y_minus_x[0] = theta * ambient_y_minus_x[1] / u_norm;
+//       y_minus_x[1] = theta * ambient_y_minus_x[2] / u_norm;
+//       y_minus_x[2] = theta * ambient_y_minus_x[3] / u_norm;
+//     } else {
+//       // We do not use [0,0,0] here because even though the value part is
+//       // a constant, the derivative part is not.
+//       y_minus_x[0] = ambient_y_minus_x[1];
+//       y_minus_x[1] = ambient_y_minus_x[2];
+//       y_minus_x[2] = ambient_y_minus_x[3];
+//     }
+//     return true;
+//   }
+// };
+//
+// Then given this struct, the auto differentiated Quaternion Manifold can now
+// be constructed as
+//
+//   Manifold* manifold = new AutoDiffManifold<QuaternionFunctor, 4, 3>;
+
+template <typename Functor, int kAmbientSize, int kTangentSize>
+class AutoDiffManifold final : public Manifold {
+ public:
+  AutoDiffManifold() : functor_(std::make_unique<Functor>()) {}
+
+  // Takes ownership of functor.
+  explicit AutoDiffManifold(Functor* functor) : functor_(functor) {}
+
+  int AmbientSize() const override { return kAmbientSize; }
+  int TangentSize() const override { return kTangentSize; }
+
+  bool Plus(const double* x,
+            const double* delta,
+            double* x_plus_delta) const override {
+    return functor_->Plus(x, delta, x_plus_delta);
+  }
+
+  bool PlusJacobian(const double* x, double* jacobian) const override;
+
+  bool Minus(const double* y,
+             const double* x,
+             double* y_minus_x) const override {
+    return functor_->Minus(y, x, y_minus_x);
+  }
+
+  bool MinusJacobian(const double* x, double* jacobian) const override;
+
+  const Functor& functor() const { return *functor_; }
+
+ private:
+  std::unique_ptr<Functor> functor_;
+};
+
+namespace internal {
+
+// The following two helper structs are needed to interface the Plus and Minus
+// methods of the ManifoldFunctor with the automatic differentiation which
+// expects a Functor with operator().
+template <typename Functor>
+struct PlusWrapper {
+  explicit PlusWrapper(const Functor& functor) : functor(functor) {}
+  template <typename T>
+  bool operator()(const T* x, const T* delta, T* x_plus_delta) const {
+    return functor.Plus(x, delta, x_plus_delta);
+  }
+  const Functor& functor;
+};
+
+template <typename Functor>
+struct MinusWrapper {
+  explicit MinusWrapper(const Functor& functor) : functor(functor) {}
+  template <typename T>
+  bool operator()(const T* y, const T* x, T* y_minus_x) const {
+    return functor.Minus(y, x, y_minus_x);
+  }
+  const Functor& functor;
+};
+}  // namespace internal
+
+template <typename Functor, int kAmbientSize, int kTangentSize>
+bool AutoDiffManifold<Functor, kAmbientSize, kTangentSize>::PlusJacobian(
+    const double* x, double* jacobian) const {
+  double zero_delta[kTangentSize];
+  for (int i = 0; i < kTangentSize; ++i) {
+    zero_delta[i] = 0.0;
+  }
+
+  double x_plus_delta[kAmbientSize];
+  for (int i = 0; i < kAmbientSize; ++i) {
+    x_plus_delta[i] = 0.0;
+  }
+
+  const double* parameter_ptrs[2] = {x, zero_delta};
+
+  // PlusJacobian is D_2 Plus(x,0) so we only need to compute the Jacobian
+  // w.r.t. the second argument.
+  double* jacobian_ptrs[2] = {nullptr, jacobian};
+  return internal::AutoDifferentiate<
+      kAmbientSize,
+      internal::StaticParameterDims<kAmbientSize, kTangentSize>>(
+      internal::PlusWrapper<Functor>(*functor_),
+      parameter_ptrs,
+      kAmbientSize,
+      x_plus_delta,
+      jacobian_ptrs);
+}
+
+template <typename Functor, int kAmbientSize, int kTangentSize>
+bool AutoDiffManifold<Functor, kAmbientSize, kTangentSize>::MinusJacobian(
+    const double* x, double* jacobian) const {
+  double y_minus_x[kTangentSize];
+  for (int i = 0; i < kTangentSize; ++i) {
+    y_minus_x[i] = 0.0;
+  }
+
+  const double* parameter_ptrs[2] = {x, x};
+
+  // MinusJacobian is D_1 Minus(x,x), so we only need to compute the Jacobian
+  // w.r.t. the first argument.
+  double* jacobian_ptrs[2] = {jacobian, nullptr};
+  return internal::AutoDifferentiate<
+      kTangentSize,
+      internal::StaticParameterDims<kAmbientSize, kAmbientSize>>(
+      internal::MinusWrapper<Functor>(*functor_),
+      parameter_ptrs,
+      kTangentSize,
+      y_minus_x,
+      jacobian_ptrs);
+}
+
+}  // namespace ceres
+
+#endif  // CERES_PUBLIC_AUTODIFF_MANIFOLD_H_
diff --git a/third_party/ceres/include/ceres/c_api.h b/third_party/ceres/include/ceres/c_api.h
index 91b82bf..30bcaaf 100644
--- a/third_party/ceres/include/ceres/c_api.h
+++ b/third_party/ceres/include/ceres/c_api.h
@@ -1,5 +1,5 @@
 /* Ceres Solver - A fast non-linear least squares minimizer
- * Copyright 2019 Google Inc. All rights reserved.
+ * Copyright 2023 Google Inc. All rights reserved.
  * http://ceres-solver.org/
  *
  * Redistribution and use in source and binary forms, with or without
@@ -39,7 +39,7 @@
 #define CERES_PUBLIC_C_API_H_
 
 // clang-format off
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 #include "ceres/internal/disable_warnings.h"
 // clang-format on
 
diff --git a/third_party/ceres/include/ceres/ceres.h b/third_party/ceres/include/ceres/ceres.h
index d249351..51f9d89 100644
--- a/third_party/ceres/include/ceres/ceres.h
+++ b/third_party/ceres/include/ceres/ceres.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -34,9 +34,12 @@
 #ifndef CERES_PUBLIC_CERES_H_
 #define CERES_PUBLIC_CERES_H_
 
+// IWYU pragma: begin_exports
 #include "ceres/autodiff_cost_function.h"
-#include "ceres/autodiff_local_parameterization.h"
+#include "ceres/autodiff_first_order_function.h"
+#include "ceres/autodiff_manifold.h"
 #include "ceres/conditioned_cost_function.h"
+#include "ceres/constants.h"
 #include "ceres/context.h"
 #include "ceres/cost_function.h"
 #include "ceres/cost_function_to_functor.h"
@@ -47,20 +50,26 @@
 #include "ceres/dynamic_cost_function_to_functor.h"
 #include "ceres/dynamic_numeric_diff_cost_function.h"
 #include "ceres/evaluation_callback.h"
+#include "ceres/first_order_function.h"
 #include "ceres/gradient_checker.h"
 #include "ceres/gradient_problem.h"
 #include "ceres/gradient_problem_solver.h"
 #include "ceres/iteration_callback.h"
 #include "ceres/jet.h"
-#include "ceres/local_parameterization.h"
+#include "ceres/line_manifold.h"
 #include "ceres/loss_function.h"
+#include "ceres/manifold.h"
 #include "ceres/numeric_diff_cost_function.h"
+#include "ceres/numeric_diff_first_order_function.h"
 #include "ceres/numeric_diff_options.h"
 #include "ceres/ordered_groups.h"
 #include "ceres/problem.h"
+#include "ceres/product_manifold.h"
 #include "ceres/sized_cost_function.h"
 #include "ceres/solver.h"
+#include "ceres/sphere_manifold.h"
 #include "ceres/types.h"
 #include "ceres/version.h"
+// IWYU pragma: end_exports
 
 #endif  // CERES_PUBLIC_CERES_H_
diff --git a/third_party/ceres/include/ceres/conditioned_cost_function.h b/third_party/ceres/include/ceres/conditioned_cost_function.h
index a57ee20..1edc006 100644
--- a/third_party/ceres/include/ceres/conditioned_cost_function.h
+++ b/third_party/ceres/include/ceres/conditioned_cost_function.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -71,18 +71,18 @@
 //   ccf_residual[i] = f_i(my_cost_function_residual[i])
 //
 // and the Jacobian will be affected appropriately.
-class CERES_EXPORT ConditionedCostFunction : public CostFunction {
+class CERES_EXPORT ConditionedCostFunction final : public CostFunction {
  public:
   // Builds a cost function based on a wrapped cost function, and a
   // per-residual conditioner. Takes ownership of all of the wrapped cost
   // functions, or not, depending on the ownership parameter. Conditioners
-  // may be NULL, in which case the corresponding residual is not modified.
+  // may be nullptr, in which case the corresponding residual is not modified.
   //
   // The conditioners can repeat.
   ConditionedCostFunction(CostFunction* wrapped_cost_function,
                           const std::vector<CostFunction*>& conditioners,
                           Ownership ownership);
-  virtual ~ConditionedCostFunction();
+  ~ConditionedCostFunction() override;
 
   bool Evaluate(double const* const* parameters,
                 double* residuals,
diff --git a/third_party/ceres/include/ceres/constants.h b/third_party/ceres/include/ceres/constants.h
new file mode 100644
index 0000000..584b669
--- /dev/null
+++ b/third_party/ceres/include/ceres/constants.h
@@ -0,0 +1,42 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: hellston20a@gmail.com (H S Helson Go)
+
+#ifndef CERES_PUBLIC_CONSTANTS_H_
+#define CERES_PUBLIC_CONSTANTS_H_
+
+// TODO(HSHelson): This header should no longer be necessary once C++20's
+// <numbers> (e.g. std::numbers::pi_v) becomes usable
+namespace ceres::constants {
+template <typename T>
+inline constexpr T pi_v(3.141592653589793238462643383279502884);
+inline constexpr double pi = pi_v<double>;
+}  // namespace ceres::constants
+
+#endif  // CERES_PUBLIC_CONSTANTS_H_
diff --git a/third_party/ceres/include/ceres/context.h b/third_party/ceres/include/ceres/context.h
index d08e32b..fe18726 100644
--- a/third_party/ceres/include/ceres/context.h
+++ b/third_party/ceres/include/ceres/context.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -31,6 +31,8 @@
 #ifndef CERES_PUBLIC_CONTEXT_H_
 #define CERES_PUBLIC_CONTEXT_H_
 
+#include "ceres/internal/export.h"
+
 namespace ceres {
 
 // A global context for processing data in Ceres.  This provides a mechanism to
@@ -39,13 +41,13 @@
 // Problems, either serially or in parallel. When using it with multiple
 // Problems at the same time, they may end up contending for resources
 // (e.g. threads) managed by the Context.
-class Context {
+class CERES_EXPORT Context {
  public:
-  Context() {}
+  Context();
   Context(const Context&) = delete;
   void operator=(const Context&) = delete;
 
-  virtual ~Context() {}
+  virtual ~Context();
 
   // Creates a context object and the caller takes ownership.
   static Context* Create();
diff --git a/third_party/ceres/include/ceres/cost_function.h b/third_party/ceres/include/ceres/cost_function.h
index d1550c1..2e5b1dd 100644
--- a/third_party/ceres/include/ceres/cost_function.h
+++ b/third_party/ceres/include/ceres/cost_function.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2024 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -48,7 +48,7 @@
 #include <vector>
 
 #include "ceres/internal/disable_warnings.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 
 namespace ceres {
 
@@ -63,11 +63,11 @@
 // when added with AddResidualBlock().
 class CERES_EXPORT CostFunction {
  public:
-  CostFunction() : num_residuals_(0) {}
+  CostFunction();
   CostFunction(const CostFunction&) = delete;
-  void operator=(const CostFunction&) = delete;
+  CostFunction& operator=(const CostFunction&) = delete;
 
-  virtual ~CostFunction() {}
+  virtual ~CostFunction();
 
   // Inputs:
   //
@@ -92,8 +92,8 @@
   //   jacobians[i][r*parameter_block_size_[i] + c] =
   //                              d residual[r] / d parameters[i][c]
   //
-  // If jacobians is NULL, then no derivatives are returned; this is
-  // the case when computing cost only. If jacobians[i] is NULL, then
+  // If jacobians is nullptr, then no derivatives are returned; this is
+  // the case when computing cost only. If jacobians[i] is nullptr, then
   // the jacobian block corresponding to the i'th parameter block must
   // not to be returned.
   //
@@ -124,6 +124,10 @@
   int num_residuals() const { return num_residuals_; }
 
  protected:
+  // Prevent moving through the base class
+  CostFunction(CostFunction&& other) noexcept;
+  CostFunction& operator=(CostFunction&& other) noexcept;
+
   std::vector<int32_t>* mutable_parameter_block_sizes() {
     return &parameter_block_sizes_;
   }
diff --git a/third_party/ceres/include/ceres/cost_function_to_functor.h b/third_party/ceres/include/ceres/cost_function_to_functor.h
index 9364293..573508e 100644
--- a/third_party/ceres/include/ceres/cost_function_to_functor.h
+++ b/third_party/ceres/include/ceres/cost_function_to_functor.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2024 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -94,10 +94,9 @@
 
 #include "ceres/cost_function.h"
 #include "ceres/dynamic_cost_function_to_functor.h"
-#include "ceres/internal/fixed_array.h"
 #include "ceres/internal/parameter_dims.h"
-#include "ceres/internal/port.h"
 #include "ceres/types.h"
+#include "glog/logging.h"
 
 namespace ceres {
 
@@ -106,12 +105,16 @@
  public:
   // Takes ownership of cost_function.
   explicit CostFunctionToFunctor(CostFunction* cost_function)
-      : cost_functor_(cost_function) {
-    CHECK(cost_function != nullptr);
+      : CostFunctionToFunctor{std::unique_ptr<CostFunction>{cost_function}} {}
+
+  // Takes ownership of cost_function.
+  explicit CostFunctionToFunctor(std::unique_ptr<CostFunction> cost_function)
+      : cost_functor_(std::move(cost_function)) {
+    CHECK(cost_functor_.function() != nullptr);
     CHECK(kNumResiduals > 0 || kNumResiduals == DYNAMIC);
 
     const std::vector<int32_t>& parameter_block_sizes =
-        cost_function->parameter_block_sizes();
+        cost_functor_.function()->parameter_block_sizes();
     const int num_parameter_blocks = ParameterDims::kNumParameterBlocks;
     CHECK_EQ(static_cast<int>(parameter_block_sizes.size()),
              num_parameter_blocks);
@@ -119,7 +122,7 @@
     if (parameter_block_sizes.size() == num_parameter_blocks) {
       for (int block = 0; block < num_parameter_blocks; ++block) {
         CHECK_EQ(ParameterDims::GetDim(block), parameter_block_sizes[block])
-            << "Parameter block size missmatch. The specified static parameter "
+            << "Parameter block size mismatch. The specified static parameter "
                "block dimension does not match the one from the cost function.";
       }
     }
diff --git a/third_party/ceres/include/ceres/covariance.h b/third_party/ceres/include/ceres/covariance.h
index 2fe025d..d477f31 100644
--- a/third_party/ceres/include/ceres/covariance.h
+++ b/third_party/ceres/include/ceres/covariance.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,8 +35,9 @@
 #include <utility>
 #include <vector>
 
+#include "ceres/internal/config.h"
 #include "ceres/internal/disable_warnings.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 #include "ceres/types.h"
 
 namespace ceres {
@@ -145,7 +146,7 @@
 //   a. The rank deficiency arises from overparameterization. e.g., a
 //   four dimensional quaternion used to parameterize SO(3), which is
 //   a three dimensional manifold. In cases like this, the user should
-//   use an appropriate LocalParameterization. Not only will this lead
+//   use an appropriate Manifold. Not only will this lead
 //   to better numerical behaviour of the Solver, it will also expose
 //   the rank deficiency to the Covariance object so that it can
 //   handle it correctly.
@@ -245,6 +246,20 @@
     // used.
     CovarianceAlgorithmType algorithm_type = SPARSE_QR;
 
+    // During QR factorization, if a column with Euclidean norm less
+    // than column_pivot_threshold is encountered it is treated as
+    // zero.
+    //
+    // If column_pivot_threshold < 0, then an automatic default value
+    // of 20*(m+n)*eps*sqrt(max(diag(J’*J))) is used. Here m and n are
+    // the number of rows and columns of the Jacobian (J)
+    // respectively.
+    //
+    // This is an advanced option meant for users who know enough
+    // about their Jacobian matrices that they can determine a value
+    // better than the default.
+    double column_pivot_threshold = -1;
+
     // If the Jacobian matrix is near singular, then inverting J'J
     // will result in unreliable results, e.g, if
     //
@@ -265,7 +280,7 @@
     //
     //      min_sigma / max_sigma < sqrt(min_reciprocal_condition_number)
     //
-    //    where min_sigma and max_sigma are the minimum and maxiumum
+    //    where min_sigma and max_sigma are the minimum and maximum
     //    singular values of J respectively.
     //
     // 2. SPARSE_QR
@@ -393,11 +408,9 @@
                           const double* parameter_block2,
                           double* covariance_block) const;
 
-  // Return the block of the cross-covariance matrix corresponding to
-  // parameter_block1 and parameter_block2.
-  // Returns cross-covariance in the tangent space if a local
-  // parameterization is associated with either parameter block;
-  // else returns cross-covariance in the ambient space.
+  // Returns the block of the cross-covariance in the tangent space if a
+  // manifold is associated with either parameter block; else returns
+  // cross-covariance in the ambient space.
   //
   // Compute must be called before the first call to
   // GetCovarianceBlock and the pair <parameter_block1,
@@ -429,9 +442,8 @@
                            double* covariance_matrix) const;
 
   // Return the covariance matrix corresponding to parameter_blocks
-  // in the tangent space if a local parameterization is associated
-  // with one of the parameter blocks else returns the covariance
-  // matrix in the ambient space.
+  // in the tangent space if a manifold is associated with one of the parameter
+  // blocks else returns the covariance matrix in the ambient space.
   //
   // Compute must be called before calling GetCovarianceMatrix and all
   // parameter_blocks must have been present in the vector
diff --git a/third_party/ceres/include/ceres/crs_matrix.h b/third_party/ceres/include/ceres/crs_matrix.h
index bc618fa..787b6a3 100644
--- a/third_party/ceres/include/ceres/crs_matrix.h
+++ b/third_party/ceres/include/ceres/crs_matrix.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -34,17 +34,17 @@
 #include <vector>
 
 #include "ceres/internal/disable_warnings.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 
 namespace ceres {
 
 // A compressed row sparse matrix used primarily for communicating the
 // Jacobian matrix to the user.
 struct CERES_EXPORT CRSMatrix {
-  CRSMatrix() : num_rows(0), num_cols(0) {}
+  CRSMatrix() = default;
 
-  int num_rows;
-  int num_cols;
+  int num_rows{0};
+  int num_cols{0};
 
   // A compressed row matrix stores its contents in three arrays,
   // rows, cols and values.
diff --git a/third_party/ceres/include/ceres/cubic_interpolation.h b/third_party/ceres/include/ceres/cubic_interpolation.h
index 9b9ea4a..f165d2b 100644
--- a/third_party/ceres/include/ceres/cubic_interpolation.h
+++ b/third_party/ceres/include/ceres/cubic_interpolation.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -32,7 +32,7 @@
 #define CERES_PUBLIC_CUBIC_INTERPOLATION_H_
 
 #include "Eigen/Core"
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 #include "glog/logging.h"
 
 namespace ceres {
@@ -59,8 +59,8 @@
 // http://en.wikipedia.org/wiki/Cubic_Hermite_spline
 // http://en.wikipedia.org/wiki/Bicubic_interpolation
 //
-// f if not NULL will contain the interpolated function values.
-// dfdx if not NULL will contain the interpolated derivative values.
+// f if not nullptr will contain the interpolated function values.
+// dfdx if not nullptr will contain the interpolated derivative values.
 template <int kDataDimension>
 void CubicHermiteSpline(const Eigen::Matrix<double, kDataDimension, 1>& p0,
                         const Eigen::Matrix<double, kDataDimension, 1>& p1,
@@ -69,7 +69,7 @@
                         const double x,
                         double* f,
                         double* dfdx) {
-  typedef Eigen::Matrix<double, kDataDimension, 1> VType;
+  using VType = Eigen::Matrix<double, kDataDimension, 1>;
   const VType a = 0.5 * (-p0 + 3.0 * p1 - 3.0 * p2 + p3);
   const VType b = 0.5 * (2.0 * p0 - 5.0 * p1 + 4.0 * p2 - p3);
   const VType c = 0.5 * (-p0 + p2);
@@ -79,12 +79,12 @@
   // derivative.
 
   // f = ax^3 + bx^2 + cx + d
-  if (f != NULL) {
+  if (f != nullptr) {
     Eigen::Map<VType>(f, kDataDimension) = d + x * (c + x * (b + x * a));
   }
 
   // dfdx = 3ax^2 + 2bx + c
-  if (dfdx != NULL) {
+  if (dfdx != nullptr) {
     Eigen::Map<VType>(dfdx, kDataDimension) = c + x * (2.0 * b + 3.0 * a * x);
   }
 }
@@ -143,7 +143,7 @@
   // The following two Evaluate overloads are needed for interfacing
   // with automatic differentiation. The first is for when a scalar
   // evaluation is done, and the second one is for when Jets are used.
-  void Evaluate(const double& x, double* f) const { Evaluate(x, f, NULL); }
+  void Evaluate(const double& x, double* f) const { Evaluate(x, f, nullptr); }
 
   template <typename JetT>
   void Evaluate(const JetT& x, JetT* f) const {
@@ -191,7 +191,7 @@
   }
 
   EIGEN_STRONG_INLINE void GetValue(const int n, double* f) const {
-    const int idx = std::min(std::max(begin_, n), end_ - 1) - begin_;
+    const int idx = (std::min)((std::max)(begin_, n), end_ - 1) - begin_;
     if (kInterleaved) {
       for (int i = 0; i < kDataDimension; ++i) {
         f[i] = static_cast<double>(data_[kDataDimension * idx + i]);
@@ -317,10 +317,10 @@
     // Interpolate vertically the interpolated value from each row and
     // compute the derivative along the columns.
     CubicHermiteSpline<Grid::DATA_DIMENSION>(f0, f1, f2, f3, r - row, f, dfdr);
-    if (dfdc != NULL) {
+    if (dfdc != nullptr) {
       // Interpolate vertically the derivative along the columns.
       CubicHermiteSpline<Grid::DATA_DIMENSION>(
-          df0dc, df1dc, df2dc, df3dc, r - row, dfdc, NULL);
+          df0dc, df1dc, df2dc, df3dc, r - row, dfdc, nullptr);
     }
   }
 
@@ -328,7 +328,7 @@
   // with automatic differentiation. The first is for when a scalar
   // evaluation is done, and the second one is for when Jets are used.
   void Evaluate(const double& r, const double& c, double* f) const {
-    Evaluate(r, c, f, NULL, NULL);
+    Evaluate(r, c, f, nullptr, nullptr);
   }
 
   template <typename JetT>
@@ -368,7 +368,7 @@
 //
 //   f001, f002, f011, f012, ...
 //
-// A commonly occuring example are color images (RGB) where the three
+// A commonly occurring example are color images (RGB) where the three
 // channels are stored interleaved.
 //
 // If kInterleaved = false, then it is stored as
@@ -402,9 +402,9 @@
 
   EIGEN_STRONG_INLINE void GetValue(const int r, const int c, double* f) const {
     const int row_idx =
-        std::min(std::max(row_begin_, r), row_end_ - 1) - row_begin_;
+        (std::min)((std::max)(row_begin_, r), row_end_ - 1) - row_begin_;
     const int col_idx =
-        std::min(std::max(col_begin_, c), col_end_ - 1) - col_begin_;
+        (std::min)((std::max)(col_begin_, c), col_end_ - 1) - col_begin_;
 
     const int n = (kRowMajor) ? num_cols_ * row_idx + col_idx
                               : num_rows_ * col_idx + row_idx;
diff --git a/third_party/ceres/include/ceres/dynamic_autodiff_cost_function.h b/third_party/ceres/include/ceres/dynamic_autodiff_cost_function.h
index 7ccf6a8..2b8724d 100644
--- a/third_party/ceres/include/ceres/dynamic_autodiff_cost_function.h
+++ b/third_party/ceres/include/ceres/dynamic_autodiff_cost_function.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2024 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,6 +35,7 @@
 #include <cmath>
 #include <memory>
 #include <numeric>
+#include <type_traits>
 #include <vector>
 
 #include "ceres/dynamic_cost_function.h"
@@ -65,8 +66,7 @@
 // also specify the sizes after creating the dynamic autodiff cost
 // function. For example:
 //
-//   DynamicAutoDiffCostFunction<MyCostFunctor, 3> cost_function(
-//       new MyCostFunctor());
+//   DynamicAutoDiffCostFunction<MyCostFunctor, 3> cost_function;
 //   cost_function.AddParameterBlock(5);
 //   cost_function.AddParameterBlock(10);
 //   cost_function.SetNumResiduals(21);
@@ -77,17 +77,38 @@
 // pass. There is a tradeoff with the size of the passes; you may want
 // to experiment with the stride.
 template <typename CostFunctor, int Stride = 4>
-class DynamicAutoDiffCostFunction : public DynamicCostFunction {
+class DynamicAutoDiffCostFunction final : public DynamicCostFunction {
  public:
+  // Constructs the CostFunctor on the heap and takes the ownership.
+  template <class... Args,
+            std::enable_if_t<std::is_constructible_v<CostFunctor, Args&&...>>* =
+                nullptr>
+  explicit DynamicAutoDiffCostFunction(Args&&... args)
+      // NOTE We explicitly use direct initialization using parentheses instead
+      // of uniform initialization using braces to avoid narrowing conversion
+      // warnings.
+      : DynamicAutoDiffCostFunction{
+            std::make_unique<CostFunctor>(std::forward<Args>(args)...)} {}
+
   // Takes ownership by default.
-  DynamicAutoDiffCostFunction(CostFunctor* functor,
-                              Ownership ownership = TAKE_OWNERSHIP)
-      : functor_(functor), ownership_(ownership) {}
+  explicit DynamicAutoDiffCostFunction(CostFunctor* functor,
+                                       Ownership ownership = TAKE_OWNERSHIP)
+      : DynamicAutoDiffCostFunction{std::unique_ptr<CostFunctor>{functor},
+                                    ownership} {}
 
-  explicit DynamicAutoDiffCostFunction(DynamicAutoDiffCostFunction&& other)
-      : functor_(std::move(other.functor_)), ownership_(other.ownership_) {}
+  explicit DynamicAutoDiffCostFunction(std::unique_ptr<CostFunctor> functor)
+      : DynamicAutoDiffCostFunction{std::move(functor), TAKE_OWNERSHIP} {}
 
-  virtual ~DynamicAutoDiffCostFunction() {
+  DynamicAutoDiffCostFunction(const DynamicAutoDiffCostFunction& other) =
+      delete;
+  DynamicAutoDiffCostFunction& operator=(
+      const DynamicAutoDiffCostFunction& other) = delete;
+  DynamicAutoDiffCostFunction(DynamicAutoDiffCostFunction&& other) noexcept =
+      default;
+  DynamicAutoDiffCostFunction& operator=(
+      DynamicAutoDiffCostFunction&& other) noexcept = default;
+
+  ~DynamicAutoDiffCostFunction() override {
     // Manually release pointer if configured to not take ownership
     // rather than deleting only if ownership is taken.  This is to
     // stay maximally compatible to old user code which may have
@@ -105,7 +126,7 @@
         << "You must call DynamicAutoDiffCostFunction::SetNumResiduals() "
         << "before DynamicAutoDiffCostFunction::Evaluate().";
 
-    if (jacobians == NULL) {
+    if (jacobians == nullptr) {
       return (*functor_)(parameters, residuals);
     }
 
@@ -150,7 +171,7 @@
       jet_parameters[i] = &input_jets[parameter_cursor];
 
       const int parameter_block_size = parameter_block_sizes()[i];
-      if (jacobians[i] != NULL) {
+      if (jacobians[i] != nullptr) {
         if (!in_derivative_section) {
           start_derivative_section.push_back(parameter_cursor);
           in_derivative_section = true;
@@ -209,7 +230,7 @@
               parameter_cursor >=
                   (start_derivative_section[current_derivative_section] +
                    current_derivative_section_cursor)) {
-            if (jacobians[i] != NULL) {
+            if (jacobians[i] != nullptr) {
               input_jets[parameter_cursor].v[active_parameter_count] = 1.0;
               ++active_parameter_count;
               ++current_derivative_section_cursor;
@@ -238,7 +259,7 @@
               parameter_cursor >=
                   (start_derivative_section[current_derivative_section] +
                    current_derivative_section_cursor)) {
-            if (jacobians[i] != NULL) {
+            if (jacobians[i] != nullptr) {
               for (int k = 0; k < num_residuals(); ++k) {
                 jacobians[i][k * parameter_block_sizes()[i] + j] =
                     output_jets[k].v[active_parameter_count];
@@ -264,11 +285,34 @@
     return true;
   }
 
+  const CostFunctor& functor() const { return *functor_; }
+
  private:
+  explicit DynamicAutoDiffCostFunction(std::unique_ptr<CostFunctor> functor,
+                                       Ownership ownership)
+      : functor_(std::move(functor)), ownership_(ownership) {}
+
   std::unique_ptr<CostFunctor> functor_;
   Ownership ownership_;
 };
 
+// Deduction guide that allows the user to avoid explicitly specifying the
+// template parameter of DynamicAutoDiffCostFunction. The class can instead be
+// instantiated as follows:
+//
+//   new DynamicAutoDiffCostFunction{new MyCostFunctor{}};
+//   new DynamicAutoDiffCostFunction{std::make_unique<MyCostFunctor>()};
+//
+template <typename CostFunctor>
+DynamicAutoDiffCostFunction(CostFunctor* functor)
+    -> DynamicAutoDiffCostFunction<CostFunctor>;
+template <typename CostFunctor>
+DynamicAutoDiffCostFunction(CostFunctor* functor, Ownership ownership)
+    -> DynamicAutoDiffCostFunction<CostFunctor>;
+template <typename CostFunctor>
+DynamicAutoDiffCostFunction(std::unique_ptr<CostFunctor> functor)
+    -> DynamicAutoDiffCostFunction<CostFunctor>;
+
 }  // namespace ceres
 
 #endif  // CERES_PUBLIC_DYNAMIC_AUTODIFF_COST_FUNCTION_H_
diff --git a/third_party/ceres/include/ceres/dynamic_cost_function.h b/third_party/ceres/include/ceres/dynamic_cost_function.h
index 6e8a076..02ce1e9 100644
--- a/third_party/ceres/include/ceres/dynamic_cost_function.h
+++ b/third_party/ceres/include/ceres/dynamic_cost_function.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -32,6 +32,7 @@
 #define CERES_PUBLIC_DYNAMIC_COST_FUNCTION_H_
 
 #include "ceres/cost_function.h"
+#include "ceres/internal/disable_warnings.h"
 
 namespace ceres {
 
@@ -40,8 +41,6 @@
 // parameter blocks and set the number of residuals at run time.
 class CERES_EXPORT DynamicCostFunction : public CostFunction {
  public:
-  ~DynamicCostFunction() {}
-
   virtual void AddParameterBlock(int size) {
     mutable_parameter_block_sizes()->push_back(size);
   }
@@ -53,4 +52,6 @@
 
 }  // namespace ceres
 
+#include "ceres/internal/reenable_warnings.h"
+
 #endif  // CERES_PUBLIC_DYNAMIC_COST_FUNCTION_H_
diff --git a/third_party/ceres/include/ceres/dynamic_cost_function_to_functor.h b/third_party/ceres/include/ceres/dynamic_cost_function_to_functor.h
index 8d174d8..45ed90f 100644
--- a/third_party/ceres/include/ceres/dynamic_cost_function_to_functor.h
+++ b/third_party/ceres/include/ceres/dynamic_cost_function_to_functor.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,10 @@
 #include <vector>
 
 #include "ceres/dynamic_cost_function.h"
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 #include "ceres/internal/fixed_array.h"
-#include "ceres/internal/port.h"
+#include "glog/logging.h"
 
 namespace ceres {
 
@@ -100,16 +102,22 @@
 //  private:
 //   DynamicCostFunctionToFunctor intrinsic_projection_;
 // };
-class DynamicCostFunctionToFunctor {
+class CERES_EXPORT DynamicCostFunctionToFunctor {
  public:
   // Takes ownership of cost_function.
   explicit DynamicCostFunctionToFunctor(CostFunction* cost_function)
-      : cost_function_(cost_function) {
-    CHECK(cost_function != nullptr);
+      : DynamicCostFunctionToFunctor{
+            std::unique_ptr<CostFunction>{cost_function}} {}
+
+  // Takes ownership of cost_function.
+  explicit DynamicCostFunctionToFunctor(
+      std::unique_ptr<CostFunction> cost_function)
+      : cost_function_(std::move(cost_function)) {
+    CHECK(cost_function_ != nullptr);
   }
 
   bool operator()(double const* const* parameters, double* residuals) const {
-    return cost_function_->Evaluate(parameters, residuals, NULL);
+    return cost_function_->Evaluate(parameters, residuals, nullptr);
   }
 
   template <typename JetT>
@@ -181,10 +189,14 @@
     return true;
   }
 
+  CostFunction* function() const noexcept { return cost_function_.get(); }
+
  private:
   std::unique_ptr<CostFunction> cost_function_;
 };
 
 }  // namespace ceres
 
+#include "ceres/internal/reenable_warnings.h"
+
 #endif  // CERES_PUBLIC_DYNAMIC_COST_FUNCTION_TO_FUNCTOR_H_
diff --git a/third_party/ceres/include/ceres/dynamic_numeric_diff_cost_function.h b/third_party/ceres/include/ceres/dynamic_numeric_diff_cost_function.h
index ccc8f66..1ce384f 100644
--- a/third_party/ceres/include/ceres/dynamic_numeric_diff_cost_function.h
+++ b/third_party/ceres/include/ceres/dynamic_numeric_diff_cost_function.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2024 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -37,6 +37,7 @@
 #include <cmath>
 #include <memory>
 #include <numeric>
+#include <type_traits>
 #include <vector>
 
 #include "ceres/dynamic_cost_function.h"
@@ -71,25 +72,47 @@
 // also specify the sizes after creating the
 // DynamicNumericDiffCostFunction. For example:
 //
-//   DynamicAutoDiffCostFunction<MyCostFunctor, CENTRAL> cost_function(
-//       new MyCostFunctor());
+//   DynamicAutoDiffCostFunction<MyCostFunctor, CENTRAL> cost_function;
 //   cost_function.AddParameterBlock(5);
 //   cost_function.AddParameterBlock(10);
 //   cost_function.SetNumResiduals(21);
-template <typename CostFunctor, NumericDiffMethodType method = CENTRAL>
-class DynamicNumericDiffCostFunction : public DynamicCostFunction {
+template <typename CostFunctor, NumericDiffMethodType kMethod = CENTRAL>
+class DynamicNumericDiffCostFunction final : public DynamicCostFunction {
  public:
   explicit DynamicNumericDiffCostFunction(
       const CostFunctor* functor,
       Ownership ownership = TAKE_OWNERSHIP,
       const NumericDiffOptions& options = NumericDiffOptions())
-      : functor_(functor), ownership_(ownership), options_(options) {}
+      : DynamicNumericDiffCostFunction{
+            std::unique_ptr<const CostFunctor>{functor}, ownership, options} {}
 
   explicit DynamicNumericDiffCostFunction(
-      DynamicNumericDiffCostFunction&& other)
-      : functor_(std::move(other.functor_)), ownership_(other.ownership_) {}
+      std::unique_ptr<const CostFunctor> functor,
+      const NumericDiffOptions& options = NumericDiffOptions())
+      : DynamicNumericDiffCostFunction{
+            std::move(functor), TAKE_OWNERSHIP, options} {}
 
-  virtual ~DynamicNumericDiffCostFunction() {
+  // Constructs the CostFunctor on the heap and takes the ownership.
+  template <class... Args,
+            std::enable_if_t<std::is_constructible_v<CostFunctor, Args&&...>>* =
+                nullptr>
+  explicit DynamicNumericDiffCostFunction(Args&&... args)
+      // NOTE We explicitly use direct initialization using parentheses instead
+      // of uniform initialization using braces to avoid narrowing conversion
+      // warnings.
+      : DynamicNumericDiffCostFunction{
+            std::make_unique<CostFunctor>(std::forward<Args>(args)...)} {}
+
+  DynamicNumericDiffCostFunction(const DynamicNumericDiffCostFunction&) =
+      delete;
+  DynamicNumericDiffCostFunction& operator=(
+      const DynamicNumericDiffCostFunction&) = delete;
+  DynamicNumericDiffCostFunction(
+      DynamicNumericDiffCostFunction&& other) noexcept = default;
+  DynamicNumericDiffCostFunction& operator=(
+      DynamicNumericDiffCostFunction&& other) noexcept = default;
+
+  ~DynamicNumericDiffCostFunction() override {
     if (ownership_ != TAKE_OWNERSHIP) {
       functor_.release();
     }
@@ -111,7 +134,7 @@
     const bool status =
         internal::VariadicEvaluate<internal::DynamicParameterDims>(
             *functor_.get(), parameters, residuals);
-    if (jacobians == NULL || !status) {
+    if (jacobians == nullptr || !status) {
       return status;
     }
 
@@ -119,7 +142,7 @@
     int parameters_size = accumulate(block_sizes.begin(), block_sizes.end(), 0);
     std::vector<double> parameters_copy(parameters_size);
     std::vector<double*> parameters_references_copy(block_sizes.size());
-    parameters_references_copy[0] = &parameters_copy[0];
+    parameters_references_copy[0] = parameters_copy.data();
     for (size_t block = 1; block < block_sizes.size(); ++block) {
       parameters_references_copy[block] =
           parameters_references_copy[block - 1] + block_sizes[block - 1];
@@ -133,21 +156,22 @@
     }
 
     for (size_t block = 0; block < block_sizes.size(); ++block) {
-      if (jacobians[block] != NULL &&
+      if (jacobians[block] != nullptr &&
           !NumericDiff<CostFunctor,
-                       method,
+                       kMethod,
                        ceres::DYNAMIC,
                        internal::DynamicParameterDims,
                        ceres::DYNAMIC,
                        ceres::DYNAMIC>::
-              EvaluateJacobianForParameterBlock(functor_.get(),
-                                                residuals,
-                                                options_,
-                                                this->num_residuals(),
-                                                block,
-                                                block_sizes[block],
-                                                &parameters_references_copy[0],
-                                                jacobians[block])) {
+              EvaluateJacobianForParameterBlock(
+                  functor_.get(),
+                  residuals,
+                  options_,
+                  this->num_residuals(),
+                  block,
+                  block_sizes[block],
+                  parameters_references_copy.data(),
+                  jacobians[block])) {
         return false;
       }
     }
@@ -155,11 +179,45 @@
   }
 
  private:
+  explicit DynamicNumericDiffCostFunction(
+      std::unique_ptr<const CostFunctor> functor,
+      Ownership ownership,
+      const NumericDiffOptions& options)
+      : functor_(std::move(functor)),
+        ownership_(ownership),
+        options_(options) {}
+
   std::unique_ptr<const CostFunctor> functor_;
   Ownership ownership_;
   NumericDiffOptions options_;
 };
 
+// Deduction guide that allows the user to avoid explicitly specifying the
+// template parameter of DynamicNumericDiffCostFunction. The class can instead
+// be instantiated as follows:
+//
+//   new DynamicNumericDiffCostFunction{new MyCostFunctor{}};
+//   new DynamicNumericDiffCostFunction{std::make_unique<MyCostFunctor>()};
+//
+template <typename CostFunctor>
+DynamicNumericDiffCostFunction(CostFunctor* functor)
+    -> DynamicNumericDiffCostFunction<CostFunctor>;
+template <typename CostFunctor>
+DynamicNumericDiffCostFunction(CostFunctor* functor, Ownership ownership)
+    -> DynamicNumericDiffCostFunction<CostFunctor>;
+template <typename CostFunctor>
+DynamicNumericDiffCostFunction(CostFunctor* functor,
+                               Ownership ownership,
+                               const NumericDiffOptions& options)
+    -> DynamicNumericDiffCostFunction<CostFunctor>;
+template <typename CostFunctor>
+DynamicNumericDiffCostFunction(std::unique_ptr<CostFunctor> functor)
+    -> DynamicNumericDiffCostFunction<CostFunctor>;
+template <typename CostFunctor>
+DynamicNumericDiffCostFunction(std::unique_ptr<CostFunctor> functor,
+                               const NumericDiffOptions& options)
+    -> DynamicNumericDiffCostFunction<CostFunctor>;
+
 }  // namespace ceres
 
 #endif  // CERES_PUBLIC_DYNAMIC_AUTODIFF_COST_FUNCTION_H_
diff --git a/third_party/ceres/include/ceres/evaluation_callback.h b/third_party/ceres/include/ceres/evaluation_callback.h
index b9f5bbb..e582dc8 100644
--- a/third_party/ceres/include/ceres/evaluation_callback.h
+++ b/third_party/ceres/include/ceres/evaluation_callback.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -31,7 +31,7 @@
 #ifndef CERES_PUBLIC_EVALUATION_CALLBACK_H_
 #define CERES_PUBLIC_EVALUATION_CALLBACK_H_
 
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 
 namespace ceres {
 
@@ -62,12 +62,16 @@
 // execute faster.
 class CERES_EXPORT EvaluationCallback {
  public:
-  virtual ~EvaluationCallback() {}
+  virtual ~EvaluationCallback();
 
   // Called before Ceres requests residuals or jacobians for a given setting of
   // the parameters. User parameters (the double* values provided to the cost
-  // functions) are fixed until the next call to PrepareForEvaluation(). If
-  // new_evaluation_point == true, then this is a new point that is different
+  // functions) are fixed until the next call to PrepareForEvaluation().
+  //
+  // If evaluate_jacobians == true, then the user provided CostFunctions will be
+  // asked to evaluate one or more of their Jacobians.
+  //
+  // If new_evaluation_point == true, then this is a new point that is different
   // from the last evaluated point. Otherwise, it is the same point that was
   // evaluated previously (either jacobian or residual) and the user can use
   // cached results from previous evaluations.
diff --git a/third_party/ceres/include/ceres/first_order_function.h b/third_party/ceres/include/ceres/first_order_function.h
index 1420153..ea42732 100644
--- a/third_party/ceres/include/ceres/first_order_function.h
+++ b/third_party/ceres/include/ceres/first_order_function.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -31,7 +31,7 @@
 #ifndef CERES_PUBLIC_FIRST_ORDER_FUNCTION_H_
 #define CERES_PUBLIC_FIRST_ORDER_FUNCTION_H_
 
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 
 namespace ceres {
 
@@ -39,7 +39,7 @@
 // and its gradient.
 class CERES_EXPORT FirstOrderFunction {
  public:
-  virtual ~FirstOrderFunction() {}
+  virtual ~FirstOrderFunction();
 
   // cost is never null. gradient may be null. The return value
   // indicates whether the evaluation was successful or not.
diff --git a/third_party/ceres/include/ceres/gradient_checker.h b/third_party/ceres/include/ceres/gradient_checker.h
index b79cf86..77f2c8e 100644
--- a/third_party/ceres/include/ceres/gradient_checker.h
+++ b/third_party/ceres/include/ceres/gradient_checker.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -25,7 +25,7 @@
 // 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.
-// Copyright 2007 Google Inc. All Rights Reserved.
+// Copyright 2023 Google Inc. All Rights Reserved.
 //
 // Authors: wjr@google.com (William Rucklidge),
 //          keir@google.com (Keir Mierle),
@@ -40,9 +40,11 @@
 
 #include "ceres/cost_function.h"
 #include "ceres/dynamic_numeric_diff_cost_function.h"
+#include "ceres/internal/disable_warnings.h"
 #include "ceres/internal/eigen.h"
+#include "ceres/internal/export.h"
 #include "ceres/internal/fixed_array.h"
-#include "ceres/local_parameterization.h"
+#include "ceres/manifold.h"
 #include "glog/logging.h"
 
 namespace ceres {
@@ -56,27 +58,27 @@
 //   ------------------------------------  <  relative_precision
 //   max(J_actual(i, j), J_numeric(i, j))
 //
-// where J_actual(i, j) is the jacobian as computed by the supplied cost
-// function (by the user) multiplied by the local parameterization Jacobian
-// and J_numeric is the jacobian as computed by finite differences, multiplied
-// by the local parameterization Jacobian as well.
+// where J_actual(i, j) is the Jacobian as computed by the supplied cost
+// function (by the user) multiplied by the manifold Jacobian and J_numeric is
+// the Jacobian as computed by finite differences, multiplied by the manifold
+// Jacobian as well.
 //
 // How to use: Fill in an array of pointers to parameter blocks for your
 // CostFunction, and then call Probe(). Check that the return value is 'true'.
 class CERES_EXPORT GradientChecker {
  public:
-  // This will not take ownership of the cost function or local
-  // parameterizations.
+  // This will not take ownership of the cost function or manifolds.
   //
   // function: The cost function to probe.
-  // local_parameterizations: A vector of local parameterizations for each
-  // parameter. May be NULL or contain NULL pointers to indicate that the
-  // respective parameter does not have a local parameterization.
+  //
+  // manifolds: A vector of manifolds for each parameter. May be nullptr or
+  // contain nullptrs to indicate that the respective parameter blocks are
+  // Euclidean.
+  //
   // options: Options to use for numerical differentiation.
-  GradientChecker(
-      const CostFunction* function,
-      const std::vector<const LocalParameterization*>* local_parameterizations,
-      const NumericDiffOptions& options);
+  GradientChecker(const CostFunction* function,
+                  const std::vector<const Manifold*>* manifolds,
+                  const NumericDiffOptions& options);
 
   // Contains results from a call to Probe for later inspection.
   struct CERES_EXPORT ProbeResults {
@@ -87,11 +89,11 @@
     Vector residuals;
 
     // The sizes of the Jacobians below are dictated by the cost function's
-    // parameter block size and residual block sizes. If a parameter block
-    // has a local parameterization associated with it, the size of the "local"
-    // Jacobian will be determined by the local parameterization dimension and
-    // residual block size, otherwise it will be identical to the regular
-    // Jacobian.
+    // parameter block size and residual block sizes. If a parameter block has a
+    // manifold associated with it, the size of the "local" Jacobian will be
+    // determined by the dimension of the manifold (which is the same as the
+    // dimension of the tangent space) and residual block size, otherwise it
+    // will be identical to the regular Jacobian.
 
     // Derivatives as computed by the cost function.
     std::vector<Matrix> jacobians;
@@ -114,20 +116,20 @@
   };
 
   // Call the cost function, compute alternative Jacobians using finite
-  // differencing and compare results. If local parameterizations are given,
-  // the Jacobians will be multiplied by the local parameterization Jacobians
-  // before performing the check, which effectively means that all errors along
-  // the null space of the local parameterization will be ignored.
-  // Returns false if the Jacobians don't match, the cost function return false,
-  // or if the cost function returns different residual when called with a
-  // Jacobian output argument vs. calling it without. Otherwise returns true.
+  // differencing and compare results. If manifolds are given, the Jacobians
+  // will be multiplied by the manifold Jacobians before performing the check,
+  // which effectively means that all errors along the null space of the
+  // manifold will be ignored.  Returns false if the Jacobians don't match, the
+  // cost function return false, or if a cost function returns a different
+  // residual when called with a Jacobian output argument vs. calling it
+  // without. Otherwise returns true.
   //
   // parameters: The parameter values at which to probe.
   // relative_precision: A threshold for the relative difference between the
   // Jacobians. If the Jacobians differ by more than this amount, then the
   // probe fails.
   // results: On return, the Jacobians (and other information) will be stored
-  // here. May be NULL.
+  // here. May be nullptr.
   //
   // Returns true if no problems are detected and the difference between the
   // Jacobians is less than error_tolerance.
@@ -140,11 +142,13 @@
   GradientChecker(const GradientChecker&) = delete;
   void operator=(const GradientChecker&) = delete;
 
-  std::vector<const LocalParameterization*> local_parameterizations_;
+  std::vector<const Manifold*> manifolds_;
   const CostFunction* function_;
   std::unique_ptr<CostFunction> finite_diff_cost_function_;
 };
 
 }  // namespace ceres
 
+#include "ceres/internal/reenable_warnings.h"
+
 #endif  // CERES_PUBLIC_GRADIENT_CHECKER_H_
diff --git a/third_party/ceres/include/ceres/gradient_problem.h b/third_party/ceres/include/ceres/gradient_problem.h
index 49d605e..96d6493 100644
--- a/third_party/ceres/include/ceres/gradient_problem.h
+++ b/third_party/ceres/include/ceres/gradient_problem.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -34,8 +34,9 @@
 #include <memory>
 
 #include "ceres/first_order_function.h"
-#include "ceres/internal/port.h"
-#include "ceres/local_parameterization.h"
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
+#include "ceres/manifold.h"
 
 namespace ceres {
 
@@ -43,23 +44,22 @@
 
 // Instances of GradientProblem represent general non-linear
 // optimization problems that must be solved using just the value of
-// the objective function and its gradient. Unlike the Problem class,
-// which can only be used to model non-linear least squares problems,
-// instances of GradientProblem not restricted in the form of the
-// objective function.
+// the objective function and its gradient.
+
+// Unlike the Problem class, which can only be used to model non-linear least
+// squares problems, instances of GradientProblem are not restricted in the form
+// of the objective function.
 //
-// Structurally GradientProblem is a composition of a
-// FirstOrderFunction and optionally a LocalParameterization.
+// Structurally GradientProblem is a composition of a FirstOrderFunction and
+// optionally a Manifold.
 //
-// The FirstOrderFunction is responsible for evaluating the cost and
-// gradient of the objective function.
+// The FirstOrderFunction is responsible for evaluating the cost and gradient of
+// the objective function.
 //
-// The LocalParameterization is responsible for going back and forth
-// between the ambient space and the local tangent space. (See
-// local_parameterization.h for more details). When a
-// LocalParameterization is not provided, then the tangent space is
-// assumed to coincide with the ambient Euclidean space that the
-// gradient vector lives in.
+// The Manifold is responsible for going back and forth between the ambient
+// space and the local tangent space. (See manifold.h for more details). When a
+// Manifold is not provided, then the tangent space is assumed to coincide with
+// the ambient Euclidean space that the gradient vector lives in.
 //
 // Example usage:
 //
@@ -78,7 +78,7 @@
 //     const double y = parameters[1];
 //
 //     cost[0] = (1.0 - x) * (1.0 - x) + 100.0 * (y - x * x) * (y - x * x);
-//     if (gradient != NULL) {
+//     if (gradient != nullptr) {
 //       gradient[0] = -2.0 * (1.0 - x) - 200.0 * (y - x * x) * 2.0 * x;
 //       gradient[1] = 200.0 * (y - x * x);
 //     }
@@ -94,23 +94,32 @@
   // Takes ownership of the function.
   explicit GradientProblem(FirstOrderFunction* function);
 
-  // Takes ownership of the function and the parameterization.
-  GradientProblem(FirstOrderFunction* function,
-                  LocalParameterization* parameterization);
+  // Takes ownership of the function and the manifold.
+  GradientProblem(FirstOrderFunction* function, Manifold* manifold);
 
   int NumParameters() const;
-  int NumLocalParameters() const;
+
+  // Dimension of the manifold (and its tangent space).
+  int NumTangentParameters() const;
 
   // This call is not thread safe.
   bool Evaluate(const double* parameters, double* cost, double* gradient) const;
   bool Plus(const double* x, const double* delta, double* x_plus_delta) const;
 
+  const FirstOrderFunction* function() const { return function_.get(); }
+  FirstOrderFunction* mutable_function() { return function_.get(); }
+
+  const Manifold* manifold() const { return manifold_.get(); }
+  Manifold* mutable_manifold() { return manifold_.get(); }
+
  private:
   std::unique_ptr<FirstOrderFunction> function_;
-  std::unique_ptr<LocalParameterization> parameterization_;
+  std::unique_ptr<Manifold> manifold_;
   std::unique_ptr<double[]> scratch_;
 };
 
 }  // namespace ceres
 
+#include "ceres/internal/reenable_warnings.h"
+
 #endif  // CERES_PUBLIC_GRADIENT_PROBLEM_H_
diff --git a/third_party/ceres/include/ceres/gradient_problem_solver.h b/third_party/ceres/include/ceres/gradient_problem_solver.h
index 9fab62e..f4c392f 100644
--- a/third_party/ceres/include/ceres/gradient_problem_solver.h
+++ b/third_party/ceres/include/ceres/gradient_problem_solver.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -36,6 +36,7 @@
 #include <vector>
 
 #include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 #include "ceres/internal/port.h"
 #include "ceres/iteration_callback.h"
 #include "ceres/types.h"
@@ -305,7 +306,7 @@
     int num_parameters = -1;
 
     // Dimension of the tangent space of the problem.
-    int num_local_parameters = -1;
+    int num_tangent_parameters = -1;
 
     // Type of line search direction used.
     LineSearchDirectionType line_search_direction_type = LBFGS;
diff --git a/third_party/ceres/include/ceres/internal/array_selector.h b/third_party/ceres/include/ceres/internal/array_selector.h
index 841797f..9480146 100644
--- a/third_party/ceres/include/ceres/internal/array_selector.h
+++ b/third_party/ceres/include/ceres/internal/array_selector.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2020 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -38,8 +38,7 @@
 #include "ceres/internal/fixed_array.h"
 #include "ceres/types.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // StaticFixedArray selects the best array implementation based on template
 // arguments. If the size is not known at compile-time, pass
@@ -73,23 +72,24 @@
                      true,
                      fits_on_stack>
     : ceres::internal::FixedArray<T, max_num_elements_on_stack> {
-  ArraySelector(int s)
+  explicit ArraySelector(int s)
       : ceres::internal::FixedArray<T, max_num_elements_on_stack>(s) {}
 };
 
 template <typename T, int num_elements, int max_num_elements_on_stack>
 struct ArraySelector<T, num_elements, max_num_elements_on_stack, false, true>
     : std::array<T, num_elements> {
-  ArraySelector(int s) { CHECK_EQ(s, num_elements); }
+  explicit ArraySelector(int s) { CHECK_EQ(s, num_elements); }
 };
 
 template <typename T, int num_elements, int max_num_elements_on_stack>
 struct ArraySelector<T, num_elements, max_num_elements_on_stack, false, false>
     : std::vector<T> {
-  ArraySelector(int s) : std::vector<T>(s) { CHECK_EQ(s, num_elements); }
+  explicit ArraySelector(int s) : std::vector<T>(s) {
+    CHECK_EQ(s, num_elements);
+  }
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_PUBLIC_INTERNAL_ARRAY_SELECTOR_H_
diff --git a/third_party/ceres/include/ceres/internal/autodiff.h b/third_party/ceres/include/ceres/internal/autodiff.h
index 9d7de75..8b02a2b 100644
--- a/third_party/ceres/include/ceres/internal/autodiff.h
+++ b/third_party/ceres/include/ceres/internal/autodiff.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -132,17 +132,16 @@
 // respectively. This is how autodiff works for functors taking multiple vector
 // valued arguments (up to 6).
 //
-// Jacobian NULL pointers
-// ----------------------
-// In general, the functions below will accept NULL pointers for all or some of
-// the Jacobian parameters, meaning that those Jacobians will not be computed.
+// Jacobian null pointers (nullptr)
+// --------------------------------
+// In general, the functions below will accept nullptr for all or some of the
+// Jacobian parameters, meaning that those Jacobians will not be computed.
 
 #ifndef CERES_PUBLIC_INTERNAL_AUTODIFF_H_
 #define CERES_PUBLIC_INTERNAL_AUTODIFF_H_
 
-#include <stddef.h>
-
 #include <array>
+#include <cstddef>
 #include <utility>
 
 #include "ceres/internal/array_selector.h"
@@ -165,8 +164,7 @@
 #define CERES_AUTODIFF_MAX_RESIDUALS_ON_STACK 20
 #endif
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // Extends src by a 1st order perturbation for every dimension and puts it in
 // dst. The size of src is N. Since this is also used for perturbations in
@@ -198,7 +196,7 @@
 template <int N, int Offset, typename T, typename JetT>
 struct Make1stOrderPerturbation<N, N, Offset, T, JetT> {
  public:
-  static void Apply(const T* src, JetT* dst) {}
+  static void Apply(const T* /* NOT USED */, JetT* /* NOT USED */) {}
 };
 
 // Calls Make1stOrderPerturbation for every parameter block.
@@ -311,7 +309,7 @@
                               int dynamic_num_outputs,
                               T* function_value,
                               T** jacobians) {
-  typedef Jet<T, ParameterDims::kNumParameters> JetT;
+  using JetT = Jet<T, ParameterDims::kNumParameters>;
   using Parameters = typename ParameterDims::Parameters;
 
   if (kNumResiduals != DYNAMIC) {
@@ -360,7 +358,6 @@
   return true;
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_PUBLIC_INTERNAL_AUTODIFF_H_
diff --git a/third_party/ceres/include/ceres/internal/disable_warnings.h b/third_party/ceres/include/ceres/internal/disable_warnings.h
index d7766a0..b6e38aa 100644
--- a/third_party/ceres/include/ceres/internal/disable_warnings.h
+++ b/third_party/ceres/include/ceres/internal/disable_warnings.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
diff --git a/third_party/ceres/include/ceres/internal/eigen.h b/third_party/ceres/include/ceres/internal/eigen.h
index b6d0b7f..fee6b52 100644
--- a/third_party/ceres/include/ceres/internal/eigen.h
+++ b/third_party/ceres/include/ceres/internal/eigen.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,39 +35,39 @@
 
 namespace ceres {
 
-typedef Eigen::Matrix<double, Eigen::Dynamic, 1> Vector;
-typedef Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>
-    Matrix;
-typedef Eigen::Map<Vector> VectorRef;
-typedef Eigen::Map<Matrix> MatrixRef;
-typedef Eigen::Map<const Vector> ConstVectorRef;
-typedef Eigen::Map<const Matrix> ConstMatrixRef;
+using Vector = Eigen::Matrix<double, Eigen::Dynamic, 1>;
+using Matrix =
+    Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
+using VectorRef = Eigen::Map<Vector>;
+using MatrixRef = Eigen::Map<Matrix>;
+using ConstVectorRef = Eigen::Map<const Vector>;
+using ConstMatrixRef = Eigen::Map<const Matrix>;
 
 // Column major matrices for DenseSparseMatrix/DenseQRSolver
-typedef Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor>
-    ColMajorMatrix;
+using ColMajorMatrix =
+    Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor>;
 
-typedef Eigen::Map<ColMajorMatrix, 0, Eigen::Stride<Eigen::Dynamic, 1>>
-    ColMajorMatrixRef;
+using ColMajorMatrixRef =
+    Eigen::Map<ColMajorMatrix, 0, Eigen::Stride<Eigen::Dynamic, 1>>;
 
-typedef Eigen::Map<const ColMajorMatrix, 0, Eigen::Stride<Eigen::Dynamic, 1>>
-    ConstColMajorMatrixRef;
+using ConstColMajorMatrixRef =
+    Eigen::Map<const ColMajorMatrix, 0, Eigen::Stride<Eigen::Dynamic, 1>>;
 
 // C++ does not support templated typdefs, thus the need for this
 // struct so that we can support statically sized Matrix and Maps.
 template <int num_rows = Eigen::Dynamic, int num_cols = Eigen::Dynamic>
 struct EigenTypes {
-  typedef Eigen::Matrix<double,
-                        num_rows,
-                        num_cols,
-                        num_cols == 1 ? Eigen::ColMajor : Eigen::RowMajor>
-      Matrix;
+  using Matrix =
+      Eigen::Matrix<double,
+                    num_rows,
+                    num_cols,
+                    num_cols == 1 ? Eigen::ColMajor : Eigen::RowMajor>;
 
-  typedef Eigen::Map<Matrix> MatrixRef;
-  typedef Eigen::Map<const Matrix> ConstMatrixRef;
-  typedef Eigen::Matrix<double, num_rows, 1> Vector;
-  typedef Eigen::Map<Eigen::Matrix<double, num_rows, 1>> VectorRef;
-  typedef Eigen::Map<const Eigen::Matrix<double, num_rows, 1>> ConstVectorRef;
+  using MatrixRef = Eigen::Map<Matrix>;
+  using ConstMatrixRef = Eigen::Map<const Matrix>;
+  using Vector = Eigen::Matrix<double, num_rows, 1>;
+  using VectorRef = Eigen::Map<Eigen::Matrix<double, num_rows, 1>>;
+  using ConstVectorRef = Eigen::Map<const Eigen::Matrix<double, num_rows, 1>>;
 };
 
 }  // namespace ceres
diff --git a/third_party/ceres/include/ceres/internal/euler_angles.h b/third_party/ceres/include/ceres/internal/euler_angles.h
new file mode 100644
index 0000000..38f2702
--- /dev/null
+++ b/third_party/ceres/include/ceres/internal/euler_angles.h
@@ -0,0 +1,199 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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 CERES_PUBLIC_INTERNAL_EULER_ANGLES_H_
+#define CERES_PUBLIC_INTERNAL_EULER_ANGLES_H_
+
+#include <type_traits>
+
+namespace ceres {
+namespace internal {
+
+// The EulerSystem struct represents an Euler Angle Convention in compile time.
+// It acts like a trait structure and is also used as a tag for dispatching
+// Euler angle conversion function templates
+//
+// Internally, it implements the convention laid out in "Euler angle
+// conversion", Ken Shoemake, Graphics Gems IV, where a choice of axis for the
+// first rotation (out of 3) and 3 binary choices compactly specify all 24
+// rotation conventions
+//
+//  - InnerAxis: Axis for the first rotation. This is specified by struct tags
+//  axis::X, axis::Y, and axis::Z
+//
+//  - Parity: Defines the parity of the axis permutation. The axis sequence has
+//  Even parity if the second axis of rotation is 'greater-than' the first axis
+//  of rotation according to the order X<Y<Z<X, otherwise it has Odd parity.
+//  This is specified by struct tags Even and Odd
+//
+//  - AngleConvention: Defines whether Proper Euler Angles (originally defined
+//  by Euler, which has the last axis repeated, i.e. ZYZ, ZXZ, etc), or
+//  Tait-Bryan Angles (introduced by the nautical and aerospace fields, i.e.
+//  using ZYX for roll-pitch-yaw) are used. This is specified by struct Tags
+//  ProperEuler and TaitBryan.
+//
+//  - FrameConvention: Defines whether the three rotations are be in a global
+//  frame of reference (extrinsic) or in a body centred frame of reference
+//  (intrinsic). This is specified by struct tags Extrinsic and Intrinsic
+
+namespace axis {
+struct X : std::integral_constant<int, 0> {};
+struct Y : std::integral_constant<int, 1> {};
+struct Z : std::integral_constant<int, 2> {};
+}  // namespace axis
+
+struct Even;
+struct Odd;
+
+struct ProperEuler;
+struct TaitBryan;
+
+struct Extrinsic;
+struct Intrinsic;
+
+template <typename InnerAxisType,
+          typename ParityType,
+          typename AngleConventionType,
+          typename FrameConventionType>
+struct EulerSystem {
+  static constexpr bool kIsParityOdd = std::is_same_v<ParityType, Odd>;
+  static constexpr bool kIsProperEuler =
+      std::is_same_v<AngleConventionType, ProperEuler>;
+  static constexpr bool kIsIntrinsic =
+      std::is_same_v<FrameConventionType, Intrinsic>;
+
+  static constexpr int kAxes[3] = {
+      InnerAxisType::value,
+      (InnerAxisType::value + 1 + static_cast<int>(kIsParityOdd)) % 3,
+      (InnerAxisType::value + 2 - static_cast<int>(kIsParityOdd)) % 3};
+};
+
+}  // namespace internal
+
+// Define human readable aliases to the type of the tags
+using ExtrinsicXYZ = internal::EulerSystem<internal::axis::X,
+                                           internal::Even,
+                                           internal::TaitBryan,
+                                           internal::Extrinsic>;
+using ExtrinsicXYX = internal::EulerSystem<internal::axis::X,
+                                           internal::Even,
+                                           internal::ProperEuler,
+                                           internal::Extrinsic>;
+using ExtrinsicXZY = internal::EulerSystem<internal::axis::X,
+                                           internal::Odd,
+                                           internal::TaitBryan,
+                                           internal::Extrinsic>;
+using ExtrinsicXZX = internal::EulerSystem<internal::axis::X,
+                                           internal::Odd,
+                                           internal::ProperEuler,
+                                           internal::Extrinsic>;
+using ExtrinsicYZX = internal::EulerSystem<internal::axis::Y,
+                                           internal::Even,
+                                           internal::TaitBryan,
+                                           internal::Extrinsic>;
+using ExtrinsicYZY = internal::EulerSystem<internal::axis::Y,
+                                           internal::Even,
+                                           internal::ProperEuler,
+                                           internal::Extrinsic>;
+using ExtrinsicYXZ = internal::EulerSystem<internal::axis::Y,
+                                           internal::Odd,
+                                           internal::TaitBryan,
+                                           internal::Extrinsic>;
+using ExtrinsicYXY = internal::EulerSystem<internal::axis::Y,
+                                           internal::Odd,
+                                           internal::ProperEuler,
+                                           internal::Extrinsic>;
+using ExtrinsicZXY = internal::EulerSystem<internal::axis::Z,
+                                           internal::Even,
+                                           internal::TaitBryan,
+                                           internal::Extrinsic>;
+using ExtrinsicZXZ = internal::EulerSystem<internal::axis::Z,
+                                           internal::Even,
+                                           internal::ProperEuler,
+                                           internal::Extrinsic>;
+using ExtrinsicZYX = internal::EulerSystem<internal::axis::Z,
+                                           internal::Odd,
+                                           internal::TaitBryan,
+                                           internal::Extrinsic>;
+using ExtrinsicZYZ = internal::EulerSystem<internal::axis::Z,
+                                           internal::Odd,
+                                           internal::ProperEuler,
+                                           internal::Extrinsic>;
+/* Rotating axes */
+using IntrinsicZYX = internal::EulerSystem<internal::axis::X,
+                                           internal::Even,
+                                           internal::TaitBryan,
+                                           internal::Intrinsic>;
+using IntrinsicXYX = internal::EulerSystem<internal::axis::X,
+                                           internal::Even,
+                                           internal::ProperEuler,
+                                           internal::Intrinsic>;
+using IntrinsicYZX = internal::EulerSystem<internal::axis::X,
+                                           internal::Odd,
+                                           internal::TaitBryan,
+                                           internal::Intrinsic>;
+using IntrinsicXZX = internal::EulerSystem<internal::axis::X,
+                                           internal::Odd,
+                                           internal::ProperEuler,
+                                           internal::Intrinsic>;
+using IntrinsicXZY = internal::EulerSystem<internal::axis::Y,
+                                           internal::Even,
+                                           internal::TaitBryan,
+                                           internal::Intrinsic>;
+using IntrinsicYZY = internal::EulerSystem<internal::axis::Y,
+                                           internal::Even,
+                                           internal::ProperEuler,
+                                           internal::Intrinsic>;
+using IntrinsicZXY = internal::EulerSystem<internal::axis::Y,
+                                           internal::Odd,
+                                           internal::TaitBryan,
+                                           internal::Intrinsic>;
+using IntrinsicYXY = internal::EulerSystem<internal::axis::Y,
+                                           internal::Odd,
+                                           internal::ProperEuler,
+                                           internal::Intrinsic>;
+using IntrinsicYXZ = internal::EulerSystem<internal::axis::Z,
+                                           internal::Even,
+                                           internal::TaitBryan,
+                                           internal::Intrinsic>;
+using IntrinsicZXZ = internal::EulerSystem<internal::axis::Z,
+                                           internal::Even,
+                                           internal::ProperEuler,
+                                           internal::Intrinsic>;
+using IntrinsicXYZ = internal::EulerSystem<internal::axis::Z,
+                                           internal::Odd,
+                                           internal::TaitBryan,
+                                           internal::Intrinsic>;
+using IntrinsicZYZ = internal::EulerSystem<internal::axis::Z,
+                                           internal::Odd,
+                                           internal::ProperEuler,
+                                           internal::Intrinsic>;
+
+}  // namespace ceres
+
+#endif  // CERES_PUBLIC_INTERNAL_EULER_ANGLES_H_
diff --git a/third_party/ceres/include/ceres/internal/fixed_array.h b/third_party/ceres/include/ceres/internal/fixed_array.h
index dcbddcd..0e35f63 100644
--- a/third_party/ceres/include/ceres/internal/fixed_array.h
+++ b/third_party/ceres/include/ceres/internal/fixed_array.h
@@ -41,8 +41,7 @@
 #include "ceres/internal/memory.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 constexpr static auto kFixedArrayUseDefault = static_cast<size_t>(-1);
 
@@ -372,8 +371,8 @@
     return std::addressof(ptr->array);
   }
 
-  static_assert(sizeof(StorageElement) == sizeof(value_type), "");
-  static_assert(alignof(StorageElement) == alignof(value_type), "");
+  static_assert(sizeof(StorageElement) == sizeof(value_type));
+  static_assert(alignof(StorageElement) == alignof(value_type));
 
   class NonEmptyInlinedStorage {
    public:
@@ -461,7 +460,6 @@
 constexpr typename FixedArray<T, N, A>::size_type
     FixedArray<T, N, A>::inline_elements;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_PUBLIC_INTERNAL_FIXED_ARRAY_H_
diff --git a/third_party/ceres/include/ceres/internal/householder_vector.h b/third_party/ceres/include/ceres/internal/householder_vector.h
index 55f68e5..dd8361c 100644
--- a/third_party/ceres/include/ceres/internal/householder_vector.h
+++ b/third_party/ceres/include/ceres/internal/householder_vector.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://code.google.com/p/ceres-solver/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -34,8 +34,7 @@
 #include "Eigen/Core"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // Algorithm 5.1.1 from 'Matrix Computations' by Golub et al. (Johns Hopkins
 // Studies in Mathematical Sciences) but using the nth element of the input
@@ -82,7 +81,14 @@
   v->head(v->rows() - 1) /= v_pivot;
 }
 
-}  // namespace internal
-}  // namespace ceres
+template <typename XVectorType, typename Derived>
+typename Derived::PlainObject ApplyHouseholderVector(
+    const XVectorType& y,
+    const Eigen::MatrixBase<Derived>& v,
+    const typename Derived::Scalar& beta) {
+  return (y - v * (beta * (v.transpose() * y)));
+}
+
+}  // namespace ceres::internal
 
 #endif  // CERES_PUBLIC_INTERNAL_HOUSEHOLDER_VECTOR_H_
diff --git a/third_party/ceres/include/ceres/internal/integer_sequence_algorithm.h b/third_party/ceres/include/ceres/internal/integer_sequence_algorithm.h
index 8c0f3bc..0c27d72 100644
--- a/third_party/ceres/include/ceres/internal/integer_sequence_algorithm.h
+++ b/third_party/ceres/include/ceres/internal/integer_sequence_algorithm.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -27,6 +27,7 @@
 // POSSIBILITY OF SUCH DAMAGE.
 //
 // Author: jodebo_beck@gmx.de (Johannes Beck)
+//         sergiu.deitsch@gmail.com (Sergiu Deitsch)
 //
 // Algorithms to be used together with integer_sequence, like computing the sum
 // or the exclusive scan (sometimes called exclusive prefix sum) at compile
@@ -37,70 +38,9 @@
 
 #include <utility>
 
-namespace ceres {
-namespace internal {
+#include "ceres/jet_fwd.h"
 
-// Implementation of calculating the sum of an integer sequence.
-// Recursively instantiate SumImpl and calculate the sum of the N first
-// numbers. This reduces the number of instantiations and speeds up
-// compilation.
-//
-// Examples:
-// 1) integer_sequence<int, 5>:
-//   Value = 5
-//
-// 2) integer_sequence<int, 4, 2>:
-//   Value = 4 + 2 + SumImpl<integer_sequence<int>>::Value
-//   Value = 4 + 2 + 0
-//
-// 3) integer_sequence<int, 2, 1, 4>:
-//   Value = 2 + 1 + SumImpl<integer_sequence<int, 4>>::Value
-//   Value = 2 + 1 + 4
-template <typename Seq>
-struct SumImpl;
-
-// Strip of and sum the first number.
-template <typename T, T N, T... Ns>
-struct SumImpl<std::integer_sequence<T, N, Ns...>> {
-  static constexpr T Value =
-      N + SumImpl<std::integer_sequence<T, Ns...>>::Value;
-};
-
-// Strip of and sum the first two numbers.
-template <typename T, T N1, T N2, T... Ns>
-struct SumImpl<std::integer_sequence<T, N1, N2, Ns...>> {
-  static constexpr T Value =
-      N1 + N2 + SumImpl<std::integer_sequence<T, Ns...>>::Value;
-};
-
-// Strip of and sum the first four numbers.
-template <typename T, T N1, T N2, T N3, T N4, T... Ns>
-struct SumImpl<std::integer_sequence<T, N1, N2, N3, N4, Ns...>> {
-  static constexpr T Value =
-      N1 + N2 + N3 + N4 + SumImpl<std::integer_sequence<T, Ns...>>::Value;
-};
-
-// Only one number is left. 'Value' is just that number ('recursion' ends).
-template <typename T, T N>
-struct SumImpl<std::integer_sequence<T, N>> {
-  static constexpr T Value = N;
-};
-
-// No number is left. 'Value' is the identity element (for sum this is zero).
-template <typename T>
-struct SumImpl<std::integer_sequence<T>> {
-  static constexpr T Value = T(0);
-};
-
-// Calculate the sum of an integer sequence. The resulting sum will be stored in
-// 'Value'.
-template <typename Seq>
-class Sum {
-  using T = typename Seq::value_type;
-
- public:
-  static constexpr T Value = SumImpl<Seq>::Value;
-};
+namespace ceres::internal {
 
 // Implementation of calculating an exclusive scan (exclusive prefix sum) of an
 // integer sequence. Exclusive means that the i-th input element is not included
@@ -164,7 +104,96 @@
 template <typename Seq>
 using ExclusiveScan = typename ExclusiveScanT<Seq>::Type;
 
-}  // namespace internal
-}  // namespace ceres
+// Removes all elements from a integer sequence corresponding to specified
+// ValueToRemove.
+//
+// This type should not be used directly but instead RemoveValue.
+template <typename T, T ValueToRemove, typename... Sequence>
+struct RemoveValueImpl;
+
+// Final filtered sequence
+template <typename T, T ValueToRemove, T... Values>
+struct RemoveValueImpl<T,
+                       ValueToRemove,
+                       std::integer_sequence<T, Values...>,
+                       std::integer_sequence<T>> {
+  using type = std::integer_sequence<T, Values...>;
+};
+
+// Found a matching value
+template <typename T, T ValueToRemove, T... Head, T... Tail>
+struct RemoveValueImpl<T,
+                       ValueToRemove,
+                       std::integer_sequence<T, Head...>,
+                       std::integer_sequence<T, ValueToRemove, Tail...>>
+    : RemoveValueImpl<T,
+                      ValueToRemove,
+                      std::integer_sequence<T, Head...>,
+                      std::integer_sequence<T, Tail...>> {};
+
+// Move one element from the tail to the head
+template <typename T, T ValueToRemove, T... Head, T MiddleValue, T... Tail>
+struct RemoveValueImpl<T,
+                       ValueToRemove,
+                       std::integer_sequence<T, Head...>,
+                       std::integer_sequence<T, MiddleValue, Tail...>>
+    : RemoveValueImpl<T,
+                      ValueToRemove,
+                      std::integer_sequence<T, Head..., MiddleValue>,
+                      std::integer_sequence<T, Tail...>> {};
+
+// Start recursion by splitting the integer sequence into two separate ones
+template <typename T, T ValueToRemove, T... Tail>
+struct RemoveValueImpl<T, ValueToRemove, std::integer_sequence<T, Tail...>>
+    : RemoveValueImpl<T,
+                      ValueToRemove,
+                      std::integer_sequence<T>,
+                      std::integer_sequence<T, Tail...>> {};
+
+// RemoveValue takes an integer Sequence of arbitrary type and removes all
+// elements matching ValueToRemove.
+//
+// In contrast to RemoveValueImpl, this implementation deduces the value type
+// eliminating the need to specify it explicitly.
+//
+// As an example, RemoveValue<std::integer_sequence<int, 1, 2, 3>, 4>::type will
+// not transform the type of the original sequence. However,
+// RemoveValue<std::integer_sequence<int, 0, 0, 2>, 2>::type will generate a new
+// sequence of type std::integer_sequence<int, 0, 0> by removing the value 2.
+template <typename Sequence, typename Sequence::value_type ValueToRemove>
+struct RemoveValue
+    : RemoveValueImpl<typename Sequence::value_type, ValueToRemove, Sequence> {
+};
+
+// Convenience template alias for RemoveValue.
+template <typename Sequence, typename Sequence::value_type ValueToRemove>
+using RemoveValue_t = typename RemoveValue<Sequence, ValueToRemove>::type;
+
+// Returns true if all elements of Values are equal to HeadValue.
+//
+// Returns true if Values is empty.
+template <typename T, T HeadValue, T... Values>
+inline constexpr bool AreAllEqual_v = ((HeadValue == Values) && ...);
+
+// Predicate determining whether an integer sequence is either empty or all
+// values are equal.
+template <typename Sequence>
+struct IsEmptyOrAreAllEqual;
+
+// Empty case.
+template <typename T>
+struct IsEmptyOrAreAllEqual<std::integer_sequence<T>> : std::true_type {};
+
+// General case for sequences containing at least one value.
+template <typename T, T HeadValue, T... Values>
+struct IsEmptyOrAreAllEqual<std::integer_sequence<T, HeadValue, Values...>>
+    : std::integral_constant<bool, AreAllEqual_v<T, HeadValue, Values...>> {};
+
+// Convenience variable template for IsEmptyOrAreAllEqual.
+template <class Sequence>
+inline constexpr bool IsEmptyOrAreAllEqual_v =
+    IsEmptyOrAreAllEqual<Sequence>::value;
+
+}  // namespace ceres::internal
 
 #endif  // CERES_PUBLIC_INTERNAL_INTEGER_SEQUENCE_ALGORITHM_H_
diff --git a/third_party/ceres/include/ceres/internal/jet_traits.h b/third_party/ceres/include/ceres/internal/jet_traits.h
new file mode 100644
index 0000000..f504a61
--- /dev/null
+++ b/third_party/ceres/include/ceres/internal/jet_traits.h
@@ -0,0 +1,195 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: sergiu.deitsch@gmail.com (Sergiu Deitsch)
+//
+
+#ifndef CERES_PUBLIC_INTERNAL_JET_TRAITS_H_
+#define CERES_PUBLIC_INTERNAL_JET_TRAITS_H_
+
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+#include "ceres/internal/integer_sequence_algorithm.h"
+#include "ceres/jet_fwd.h"
+
+namespace ceres {
+namespace internal {
+
+// Predicate that determines whether any of the Types is a Jet.
+template <typename... Types>
+struct AreAnyJet : std::false_type {};
+
+template <typename T, typename... Types>
+struct AreAnyJet<T, Types...> : AreAnyJet<Types...> {};
+
+template <typename T, int N, typename... Types>
+struct AreAnyJet<Jet<T, N>, Types...> : std::true_type {};
+
+// Convenience variable template for AreAnyJet.
+template <typename... Types>
+inline constexpr bool AreAnyJet_v = AreAnyJet<Types...>::value;
+
+// Extracts the underlying floating-point from a type T.
+template <typename T, typename E = void>
+struct UnderlyingScalar {
+  using type = T;
+};
+
+template <typename T, int N>
+struct UnderlyingScalar<Jet<T, N>> : UnderlyingScalar<T> {};
+
+// Convenience template alias for UnderlyingScalar type trait.
+template <typename T>
+using UnderlyingScalar_t = typename UnderlyingScalar<T>::type;
+
+// Predicate determining whether all Types in the pack are the same.
+//
+// Specifically, the predicate applies std::is_same recursively to pairs of
+// Types in the pack.
+template <typename T1, typename... Types>
+inline constexpr bool AreAllSame_v = (std::is_same<T1, Types>::value && ...);
+
+// Determines the rank of a type. This allows to ensure that types passed as
+// arguments are compatible to each other. The rank of Jet is determined by the
+// dimensions of the dual part. The rank of a scalar is always 0.
+// Non-specialized types default to a rank of -1.
+template <typename T, typename E = void>
+struct Rank : std::integral_constant<int, -1> {};
+
+// The rank of a scalar is 0.
+template <typename T>
+struct Rank<T, std::enable_if_t<std::is_scalar<T>::value>>
+    : std::integral_constant<int, 0> {};
+
+// The rank of a Jet is given by its dimensionality.
+template <typename T, int N>
+struct Rank<Jet<T, N>> : std::integral_constant<int, N> {};
+
+// Convenience variable template for Rank.
+template <typename T>
+inline constexpr int Rank_v = Rank<T>::value;
+
+// Constructs an integer sequence of ranks for each of the Types in the pack.
+template <typename... Types>
+using Ranks_t = std::integer_sequence<int, Rank_v<Types>...>;
+
+// Returns the scalar part of a type. This overload acts as an identity.
+template <typename T>
+constexpr decltype(auto) AsScalar(T&& value) noexcept {
+  return std::forward<T>(value);
+}
+
+// Recursively unwraps the scalar part of a Jet until a non-Jet scalar type is
+// encountered.
+template <typename T, int N>
+constexpr decltype(auto) AsScalar(const Jet<T, N>& value) noexcept(
+    noexcept(AsScalar(value.a))) {
+  return AsScalar(value.a);
+}
+
+}  // namespace internal
+
+// Type trait ensuring at least one of the types is a Jet,
+// the underlying scalar types are the same and Jet dimensions match.
+//
+// The type trait can be further specialized if necessary.
+//
+// This trait is a candidate for a concept definition once C++20 features can
+// be used.
+template <typename... Types>
+// clang-format off
+struct CompatibleJetOperands : std::integral_constant
+<
+    bool,
+    // At least one of the types is a Jet
+    internal::AreAnyJet_v<Types...> &&
+    // The underlying floating-point types are exactly the same
+    internal::AreAllSame_v<internal::UnderlyingScalar_t<Types>...> &&
+    // Non-zero ranks of types are equal
+    internal::IsEmptyOrAreAllEqual_v<internal::RemoveValue_t<internal::Ranks_t<Types...>, 0>>
+>
+// clang-format on
+{};
+
+// Single Jet operand is always compatible.
+template <typename T, int N>
+struct CompatibleJetOperands<Jet<T, N>> : std::true_type {};
+
+// Single non-Jet operand is always incompatible.
+template <typename T>
+struct CompatibleJetOperands<T> : std::false_type {};
+
+// Empty operands are always incompatible.
+template <>
+struct CompatibleJetOperands<> : std::false_type {};
+
+// Convenience variable template ensuring at least one of the types is a Jet,
+// the underlying scalar types are the same and Jet dimensions match.
+//
+// This trait is a candidate for a concept definition once C++20 features can
+// be used.
+template <typename... Types>
+inline constexpr bool CompatibleJetOperands_v =
+    CompatibleJetOperands<Types...>::value;
+
+// Type trait ensuring at least one of the types is a Jet,
+// the underlying scalar types are compatible among each other and Jet
+// dimensions match.
+//
+// The type trait can be further specialized if necessary.
+//
+// This trait is a candidate for a concept definition once C++20 features can
+// be used.
+template <typename... Types>
+// clang-format off
+struct PromotableJetOperands : std::integral_constant
+<
+    bool,
+    // Types can be compatible among each other
+    internal::AreAnyJet_v<Types...> &&
+    // Non-zero ranks of types are equal
+    internal::IsEmptyOrAreAllEqual_v<internal::RemoveValue_t<internal::Ranks_t<Types...>, 0>>
+>
+// clang-format on
+{};
+
+// Convenience variable template ensuring at least one of the types is a Jet,
+// the underlying scalar types are compatible among each other and Jet
+// dimensions match.
+//
+// This trait is a candidate for a concept definition once C++20 features can
+// be used.
+template <typename... Types>
+inline constexpr bool PromotableJetOperands_v =
+    PromotableJetOperands<Types...>::value;
+
+}  // namespace ceres
+
+#endif  // CERES_PUBLIC_INTERNAL_JET_TRAITS_H_
diff --git a/third_party/ceres/include/ceres/internal/line_parameterization.h b/third_party/ceres/include/ceres/internal/line_parameterization.h
index eda3901..f50603d 100644
--- a/third_party/ceres/include/ceres/internal/line_parameterization.h
+++ b/third_party/ceres/include/ceres/internal/line_parameterization.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2020 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
diff --git a/third_party/ceres/include/ceres/internal/memory.h b/third_party/ceres/include/ceres/internal/memory.h
index 45c5b67..e54cf2b 100644
--- a/third_party/ceres/include/ceres/internal/memory.h
+++ b/third_party/ceres/include/ceres/internal/memory.h
@@ -40,8 +40,7 @@
   } while (false)
 #endif  // CERES_HAVE_EXCEPTIONS
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template <typename Allocator, typename Iterator, typename... Args>
 void ConstructRange(Allocator& alloc,
@@ -84,7 +83,6 @@
   }
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_PUBLIC_INTERNAL_MEMORY_H_
diff --git a/third_party/ceres/include/ceres/internal/numeric_diff.h b/third_party/ceres/include/ceres/internal/numeric_diff.h
index ff7a2c3..ba28bec 100644
--- a/third_party/ceres/include/ceres/internal/numeric_diff.h
+++ b/third_party/ceres/include/ceres/internal/numeric_diff.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -47,8 +47,7 @@
 #include "ceres/types.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // This is split from the main class because C++ doesn't allow partial template
 // specializations for member functions. The alternative is to repeat the main
@@ -86,18 +85,18 @@
         (kParameterBlockSize != ceres::DYNAMIC ? kParameterBlockSize
                                                : parameter_block_size);
 
-    typedef Matrix<double, kNumResiduals, 1> ResidualVector;
-    typedef Matrix<double, kParameterBlockSize, 1> ParameterVector;
+    using ResidualVector = Matrix<double, kNumResiduals, 1>;
+    using ParameterVector = Matrix<double, kParameterBlockSize, 1>;
 
     // The convoluted reasoning for choosing the Row/Column major
     // ordering of the matrix is an artifact of the restrictions in
     // Eigen that prevent it from creating RowMajor matrices with a
     // single column. In these cases, we ask for a ColMajor matrix.
-    typedef Matrix<double,
-                   kNumResiduals,
-                   kParameterBlockSize,
-                   (kParameterBlockSize == 1) ? ColMajor : RowMajor>
-        JacobianMatrix;
+    using JacobianMatrix =
+        Matrix<double,
+               kNumResiduals,
+               kParameterBlockSize,
+               (kParameterBlockSize == 1) ? ColMajor : RowMajor>;
 
     Map<JacobianMatrix> parameter_jacobian(
         jacobian, num_residuals_internal, parameter_block_size_internal);
@@ -121,7 +120,7 @@
     // thus ridders_relative_initial_step_size is used.
     if (kMethod == RIDDERS) {
       min_step_size =
-          std::max(min_step_size, options.ridders_relative_initial_step_size);
+          (std::max)(min_step_size, options.ridders_relative_initial_step_size);
     }
 
     // For each parameter in the parameter block, use finite differences to
@@ -132,7 +131,7 @@
                                   num_residuals_internal);
 
     for (int j = 0; j < parameter_block_size_internal; ++j) {
-      const double delta = std::max(min_step_size, step_size(j));
+      const double delta = (std::max)(min_step_size, step_size(j));
 
       if (kMethod == RIDDERS) {
         if (!EvaluateRiddersJacobianColumn(functor,
@@ -184,8 +183,8 @@
     using Eigen::Map;
     using Eigen::Matrix;
 
-    typedef Matrix<double, kNumResiduals, 1> ResidualVector;
-    typedef Matrix<double, kParameterBlockSize, 1> ParameterVector;
+    using ResidualVector = Matrix<double, kNumResiduals, 1>;
+    using ParameterVector = Matrix<double, kParameterBlockSize, 1>;
 
     Map<const ParameterVector> x(x_ptr, parameter_block_size);
     Map<ParameterVector> x_plus_delta(x_plus_delta_ptr, parameter_block_size);
@@ -260,10 +259,10 @@
     using Eigen::Map;
     using Eigen::Matrix;
 
-    typedef Matrix<double, kNumResiduals, 1> ResidualVector;
-    typedef Matrix<double, kNumResiduals, Eigen::Dynamic>
-        ResidualCandidateMatrix;
-    typedef Matrix<double, kParameterBlockSize, 1> ParameterVector;
+    using ResidualVector = Matrix<double, kNumResiduals, 1>;
+    using ResidualCandidateMatrix =
+        Matrix<double, kNumResiduals, Eigen::Dynamic>;
+    using ParameterVector = Matrix<double, kParameterBlockSize, 1>;
 
     Map<const ParameterVector> x(x_ptr, parameter_block_size);
     Map<ParameterVector> x_plus_delta(x_plus_delta_ptr, parameter_block_size);
@@ -296,7 +295,7 @@
     // norm_error is supposed to decrease as the finite difference tableau
     // generation progresses, serving both as an estimate for differentiation
     // error and as a measure of differentiation numerical stability.
-    double norm_error = std::numeric_limits<double>::max();
+    double norm_error = (std::numeric_limits<double>::max)();
 
     // Loop over decreasing step sizes until:
     //  1. Error is smaller than a given value (ridders_epsilon),
@@ -342,7 +341,7 @@
                              options.ridders_step_shrink_factor;
 
         // Compute the difference between the previous value and the current.
-        double candidate_error = std::max(
+        double candidate_error = (std::max)(
             (current_candidates->col(k) - current_candidates->col(k - 1))
                 .norm(),
             (current_candidates->col(k) - previous_candidates->col(k - 1))
@@ -502,7 +501,6 @@
   }
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_PUBLIC_INTERNAL_NUMERIC_DIFF_H_
diff --git a/third_party/ceres/include/ceres/internal/parameter_dims.h b/third_party/ceres/include/ceres/internal/parameter_dims.h
index 2402106..b7cf935 100644
--- a/third_party/ceres/include/ceres/internal/parameter_dims.h
+++ b/third_party/ceres/include/ceres/internal/parameter_dims.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -36,22 +36,7 @@
 
 #include "ceres/internal/integer_sequence_algorithm.h"
 
-namespace ceres {
-namespace internal {
-
-// Checks, whether the given parameter block sizes are valid. Valid means every
-// dimension is bigger than zero.
-constexpr bool IsValidParameterDimensionSequence(std::integer_sequence<int>) {
-  return true;
-}
-
-template <int N, int... Ts>
-constexpr bool IsValidParameterDimensionSequence(
-    std::integer_sequence<int, N, Ts...>) {
-  return (N <= 0) ? false
-                  : IsValidParameterDimensionSequence(
-                        std::integer_sequence<int, Ts...>());
-}
+namespace ceres::internal {
 
 // Helper class that represents the parameter dimensions. The parameter
 // dimensions are either dynamic or the sizes are known at compile time. It is
@@ -70,8 +55,7 @@
 
   // The parameter dimensions are only valid if all parameter block dimensions
   // are greater than zero.
-  static constexpr bool kIsValid =
-      IsValidParameterDimensionSequence(Parameters());
+  static constexpr bool kIsValid = ((Ns > 0) && ...);
   static_assert(kIsValid,
                 "Invalid parameter block dimension detected. Each parameter "
                 "block dimension must be bigger than zero.");
@@ -81,8 +65,7 @@
   static_assert(kIsDynamic || kNumParameterBlocks > 0,
                 "At least one parameter block must be specified.");
 
-  static constexpr int kNumParameters =
-      Sum<std::integer_sequence<int, Ns...>>::Value;
+  static constexpr int kNumParameters = (Ns + ... + 0);
 
   static constexpr int GetDim(int dim) { return params_[dim]; }
 
@@ -118,7 +101,6 @@
 using StaticParameterDims = ParameterDims<false, Ns...>;
 using DynamicParameterDims = ParameterDims<true>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_PUBLIC_INTERNAL_PARAMETER_DIMS_H_
diff --git a/third_party/ceres/include/ceres/internal/port.h b/third_party/ceres/include/ceres/internal/port.h
index 040a1ef..d78ed51 100644
--- a/third_party/ceres/include/ceres/internal/port.h
+++ b/third_party/ceres/include/ceres/internal/port.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2024 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -31,80 +31,81 @@
 #ifndef CERES_PUBLIC_INTERNAL_PORT_H_
 #define CERES_PUBLIC_INTERNAL_PORT_H_
 
-// This file needs to compile as c code.
-#include "ceres/internal/config.h"
+#include <cmath>  // Necessary for __cpp_lib_math_special_functions feature test
 
-#if defined(CERES_USE_OPENMP)
-#if defined(CERES_USE_CXX_THREADS) || defined(CERES_NO_THREADS)
-#error CERES_USE_OPENMP is mutually exclusive to CERES_USE_CXX_THREADS and CERES_NO_THREADS
-#endif
-#elif defined(CERES_USE_CXX_THREADS)
-#if defined(CERES_USE_OPENMP) || defined(CERES_NO_THREADS)
-#error CERES_USE_CXX_THREADS is mutually exclusive to CERES_USE_OPENMP, CERES_USE_CXX_THREADS and CERES_NO_THREADS
-#endif
-#elif defined(CERES_NO_THREADS)
-#if defined(CERES_USE_OPENMP) || defined(CERES_USE_CXX_THREADS)
-#error CERES_NO_THREADS is mutually exclusive to CERES_USE_OPENMP and CERES_USE_CXX_THREADS
-#endif
-#else
-#  error One of CERES_USE_OPENMP, CERES_USE_CXX_THREADS or CERES_NO_THREADS must be defined.
-#endif
-
-// CERES_NO_SPARSE should be automatically defined by config.h if Ceres was
-// compiled without any sparse back-end.  Verify that it has not subsequently
-// been inconsistently redefined.
-#if defined(CERES_NO_SPARSE)
-#if !defined(CERES_NO_SUITESPARSE)
-#error CERES_NO_SPARSE requires CERES_NO_SUITESPARSE.
-#endif
-#if !defined(CERES_NO_CXSPARSE)
-#error CERES_NO_SPARSE requires CERES_NO_CXSPARSE
-#endif
-#if !defined(CERES_NO_ACCELERATE_SPARSE)
-#error CERES_NO_SPARSE requires CERES_NO_ACCELERATE_SPARSE
-#endif
-#if defined(CERES_USE_EIGEN_SPARSE)
-#error CERES_NO_SPARSE requires !CERES_USE_EIGEN_SPARSE
-#endif
-#endif
-
-// A macro to signal which functions and classes are exported when
-// building a shared library.
+// A macro to mark a function/variable/class as deprecated.
+// We use compiler specific attributes rather than the c++
+// attribute because they do not mix well with each other.
 #if defined(_MSC_VER)
-#define CERES_API_SHARED_IMPORT __declspec(dllimport)
-#define CERES_API_SHARED_EXPORT __declspec(dllexport)
+#define CERES_DEPRECATED_WITH_MSG(message) __declspec(deprecated(message))
 #elif defined(__GNUC__)
-#define CERES_API_SHARED_IMPORT __attribute__((visibility("default")))
-#define CERES_API_SHARED_EXPORT __attribute__((visibility("default")))
+#define CERES_DEPRECATED_WITH_MSG(message) __attribute__((deprecated(message)))
 #else
-#define CERES_API_SHARED_IMPORT
-#define CERES_API_SHARED_EXPORT
+// In the worst case fall back to c++ attribute.
+#define CERES_DEPRECATED_WITH_MSG(message) [[deprecated(message)]]
 #endif
 
-// CERES_BUILDING_SHARED_LIBRARY is only defined locally when Ceres itself is
-// compiled as a shared library, it is never exported to users.  In order that
-// we do not have to configure config.h separately when building Ceres as either
-// a static or dynamic library, we define both CERES_USING_SHARED_LIBRARY and
-// CERES_BUILDING_SHARED_LIBRARY when building as a shared library.
-#if defined(CERES_USING_SHARED_LIBRARY)
-#if defined(CERES_BUILDING_SHARED_LIBRARY)
-// Compiling Ceres itself as a shared library.
-#define CERES_EXPORT CERES_API_SHARED_EXPORT
-#else
-// Using Ceres as a shared library.
-#define CERES_EXPORT CERES_API_SHARED_IMPORT
-#endif
-#else
-// Ceres was compiled as a static library, export everything.
-#define CERES_EXPORT
+#ifndef CERES_GET_FLAG
+#define CERES_GET_FLAG(X) X
 #endif
 
-// Unit tests reach in and test internal functionality so we need a way to make
-// those symbols visible
-#ifdef CERES_EXPORT_INTERNAL_SYMBOLS
-#define CERES_EXPORT_INTERNAL CERES_EXPORT
-#else
-#define CERES_EXPORT_INTERNAL
+// Indicates whether C++20 is currently active
+#ifndef CERES_HAS_CPP20
+#if __cplusplus >= 202002L || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)
+#define CERES_HAS_CPP20
+#endif  // __cplusplus >= 202002L || (defined(_MSVC_LANG) && _MSVC_LANG >=
+        // 202002L)
+#endif  // !defined(CERES_HAS_CPP20)
+
+// Prevents symbols from being substituted by the corresponding macro definition
+// under the same name. For instance, min and max are defined as macros on
+// Windows (unless NOMINMAX is defined) which causes compilation errors when
+// defining or referencing symbols under the same name.
+//
+// To be robust in all cases particularly when NOMINMAX cannot be used, use this
+// macro to annotate min/max declarations/definitions. Examples:
+//
+//   int max CERES_PREVENT_MACRO_SUBSTITUTION();
+//   min CERES_PREVENT_MACRO_SUBSTITUTION(a, b);
+//   max CERES_PREVENT_MACRO_SUBSTITUTION(a, b);
+//
+// NOTE: In case the symbols for which the substitution must be prevented are
+// used within another macro, the substitution must be inhibited using parens as
+//
+//   (std::numerical_limits<double>::max)()
+//
+// since the helper macro will not work here. Do not use this technique in
+// general case, because it will prevent argument-dependent lookup (ADL).
+//
+#define CERES_PREVENT_MACRO_SUBSTITUTION  // Yes, it's empty
+
+// CERES_DISABLE_DEPRECATED_WARNING and CERES_RESTORE_DEPRECATED_WARNING allow
+// to temporarily disable deprecation warnings
+#if defined(_MSC_VER)
+#define CERES_DISABLE_DEPRECATED_WARNING \
+  _Pragma("warning(push)") _Pragma("warning(disable : 4996)")
+#define CERES_RESTORE_DEPRECATED_WARNING _Pragma("warning(pop)")
+#else  // defined(_MSC_VER)
+#define CERES_DISABLE_DEPRECATED_WARNING
+#define CERES_RESTORE_DEPRECATED_WARNING
+#endif  // defined(_MSC_VER)
+
+#if defined(__cpp_lib_math_special_functions) &&      \
+    ((__cpp_lib_math_special_functions >= 201603L) || \
+     defined(__STDCPP_MATH_SPEC_FUNCS__) &&           \
+         (__STDCPP_MATH_SPEC_FUNCS__ >= 201003L))
+// If defined, indicates whether C++17 Bessel functions (of the first kind) are
+// available. Some standard library implementations, such as libc++ (Android
+// NDK, Apple, Clang) do not yet provide these functions. Implementations that
+// do not support C++17, but support ISO 29124:2010, provide the functions if
+// __STDCPP_MATH_SPEC_FUNCS__ is defined by the implementation to a value at
+// least 201003L and if the user defines __STDCPP_WANT_MATH_SPEC_FUNCS__ before
+// including any standard library headers. Standard library Bessel functions are
+// preferred over any other implementation.
+#define CERES_HAS_CPP17_BESSEL_FUNCTIONS
+#elif defined(_SVID_SOURCE) || defined(_BSD_SOURCE) || defined(_XOPEN_SOURCE)
+// If defined, indicates that j0, j1, and jn from <math.h> are available.
+#define CERES_HAS_POSIX_BESSEL_FUNCTIONS
 #endif
 
 #endif  // CERES_PUBLIC_INTERNAL_PORT_H_
diff --git a/third_party/ceres/include/ceres/internal/reenable_warnings.h b/third_party/ceres/include/ceres/internal/reenable_warnings.h
index 2c5db06..a183c25 100644
--- a/third_party/ceres/include/ceres/internal/reenable_warnings.h
+++ b/third_party/ceres/include/ceres/internal/reenable_warnings.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
diff --git a/third_party/ceres/include/ceres/internal/sphere_manifold_functions.h b/third_party/ceres/include/ceres/internal/sphere_manifold_functions.h
new file mode 100644
index 0000000..4793442
--- /dev/null
+++ b/third_party/ceres/include/ceres/internal/sphere_manifold_functions.h
@@ -0,0 +1,163 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: vitus@google.com (Mike Vitus)
+//         jodebo_beck@gmx.de (Johannes Beck)
+
+#ifndef CERES_PUBLIC_INTERNAL_SPHERE_MANIFOLD_HELPERS_H_
+#define CERES_PUBLIC_INTERNAL_SPHERE_MANIFOLD_HELPERS_H_
+
+#include "ceres/constants.h"
+#include "ceres/internal/householder_vector.h"
+
+// This module contains functions to compute the SphereManifold plus and minus
+// operator and their Jacobians.
+//
+// As the parameters to these functions are shared between them, they are
+// described here: The following variable names are used:
+//  Plus(x, delta) = x + delta = x_plus_delta,
+//  Minus(y, x) = y - x = y_minus_x.
+//
+// The remaining ones are v and beta which describe the Householder
+// transformation of x, and norm_delta which is the norm of delta.
+//
+// The types of x, y, x_plus_delta and y_minus_x need to be equivalent to
+// Eigen::Matrix<double, AmbientSpaceDimension, 1> and the type of delta needs
+// to be equivalent to Eigen::Matrix<double, TangentSpaceDimension, 1>.
+//
+// The type of Jacobian plus needs to be equivalent to Eigen::Matrix<double,
+// AmbientSpaceDimension, TangentSpaceDimension, Eigen::RowMajor> and for
+// Jacobian minus Eigen::Matrix<double, TangentSpaceDimension,
+// AmbientSpaceDimension, Eigen::RowMajor>.
+//
+// For all vector / matrix inputs and outputs, template parameters are
+// used in order to allow also Eigen::Ref and Eigen block expressions to
+// be passed to the function.
+
+namespace ceres::internal {
+
+template <typename VT, typename XT, typename DeltaT, typename XPlusDeltaT>
+inline void ComputeSphereManifoldPlus(const VT& v,
+                                      double beta,
+                                      const XT& x,
+                                      const DeltaT& delta,
+                                      const double norm_delta,
+                                      XPlusDeltaT* x_plus_delta) {
+  constexpr int AmbientDim = VT::RowsAtCompileTime;
+
+  // Map the delta from the minimum representation to the over parameterized
+  // homogeneous vector. See B.2 p.25 equation (106) - (107) for more details.
+  const double sin_delta_by_delta = std::sin(norm_delta) / norm_delta;
+
+  Eigen::Matrix<double, AmbientDim, 1> y(v.size());
+  y << sin_delta_by_delta * delta, std::cos(norm_delta);
+
+  // Apply the delta update to remain on the sphere.
+  *x_plus_delta = x.norm() * ApplyHouseholderVector(y, v, beta);
+}
+
+template <typename VT, typename JacobianT>
+inline void ComputeSphereManifoldPlusJacobian(const VT& x,
+                                              JacobianT* jacobian) {
+  constexpr int AmbientSpaceDim = VT::RowsAtCompileTime;
+  using AmbientVector = Eigen::Matrix<double, AmbientSpaceDim, 1>;
+  const int ambient_size = x.size();
+  const int tangent_size = x.size() - 1;
+
+  AmbientVector v(ambient_size);
+  double beta;
+
+  // NOTE: The explicit template arguments are needed here because
+  // ComputeHouseholderVector is templated and some versions of MSVC
+  // have trouble deducing the type of v automatically.
+  ComputeHouseholderVector<VT, double, AmbientSpaceDim>(x, &v, &beta);
+
+  // The Jacobian is equal to J = H.leftCols(size_ - 1) where H is the
+  // Householder matrix (H = I - beta * v * v').
+  for (int i = 0; i < tangent_size; ++i) {
+    (*jacobian).col(i) = -beta * v(i) * v;
+    (*jacobian)(i, i) += 1.0;
+  }
+  (*jacobian) *= x.norm();
+}
+
+template <typename VT, typename XT, typename YT, typename YMinusXT>
+inline void ComputeSphereManifoldMinus(
+    const VT& v, double beta, const XT& x, const YT& y, YMinusXT* y_minus_x) {
+  constexpr int AmbientSpaceDim = VT::RowsAtCompileTime;
+  constexpr int TangentSpaceDim =
+      AmbientSpaceDim == Eigen::Dynamic ? Eigen::Dynamic : AmbientSpaceDim - 1;
+  using AmbientVector = Eigen::Matrix<double, AmbientSpaceDim, 1>;
+
+  const int tangent_size = v.size() - 1;
+
+  const AmbientVector hy = ApplyHouseholderVector(y, v, beta) / x.norm();
+
+  // Calculate y - x. See B.2 p.25 equation (108).
+  const double y_last = hy[tangent_size];
+  const double hy_norm = hy.template head<TangentSpaceDim>(tangent_size).norm();
+  if (hy_norm == 0.0) {
+    y_minus_x->setZero();
+    y_minus_x->data()[tangent_size - 1] = y_last >= 0 ? 0.0 : constants::pi;
+  } else {
+    *y_minus_x = std::atan2(hy_norm, y_last) / hy_norm *
+                 hy.template head<TangentSpaceDim>(tangent_size);
+  }
+}
+
+template <typename VT, typename JacobianT>
+inline void ComputeSphereManifoldMinusJacobian(const VT& x,
+                                               JacobianT* jacobian) {
+  constexpr int AmbientSpaceDim = VT::RowsAtCompileTime;
+  using AmbientVector = Eigen::Matrix<double, AmbientSpaceDim, 1>;
+  const int ambient_size = x.size();
+  const int tangent_size = x.size() - 1;
+
+  AmbientVector v(ambient_size);
+  double beta;
+
+  // NOTE: The explicit template arguments are needed here because
+  // ComputeHouseholderVector is templated and some versions of MSVC
+  // have trouble deducing the type of v automatically.
+  ComputeHouseholderVector<VT, double, AmbientSpaceDim>(x, &v, &beta);
+
+  // The Jacobian is equal to J = H.leftCols(size_ - 1) where H is the
+  // Householder matrix (H = I - beta * v * v').
+  for (int i = 0; i < tangent_size; ++i) {
+    // NOTE: The transpose is used for correctness (the product is expected to
+    // be a row vector), although here there seems to be no difference between
+    // transposing or not for Eigen (possibly a compile-time auto fix).
+    (*jacobian).row(i) = -beta * v(i) * v.transpose();
+    (*jacobian)(i, i) += 1.0;
+  }
+  (*jacobian) /= x.norm();
+}
+
+}  // namespace ceres::internal
+
+#endif
diff --git a/third_party/ceres/include/ceres/internal/variadic_evaluate.h b/third_party/ceres/include/ceres/internal/variadic_evaluate.h
index 47ff6b1..61af6b2 100644
--- a/third_party/ceres/include/ceres/internal/variadic_evaluate.h
+++ b/third_party/ceres/include/ceres/internal/variadic_evaluate.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -33,16 +33,14 @@
 #ifndef CERES_PUBLIC_INTERNAL_VARIADIC_EVALUATE_H_
 #define CERES_PUBLIC_INTERNAL_VARIADIC_EVALUATE_H_
 
-#include <stddef.h>
-
+#include <cstddef>
 #include <type_traits>
 #include <utility>
 
 #include "ceres/cost_function.h"
 #include "ceres/internal/parameter_dims.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // For fixed size cost functors
 template <typename Functor, typename T, int... Indices>
@@ -51,7 +49,7 @@
                                  T* output,
                                  std::false_type /*is_dynamic*/,
                                  std::integer_sequence<int, Indices...>) {
-  static_assert(sizeof...(Indices),
+  static_assert(sizeof...(Indices) > 0,
                 "Invalid number of parameter blocks. At least one parameter "
                 "block must be specified.");
   return functor(input[Indices]..., output);
@@ -108,7 +106,29 @@
   return VariadicEvaluateImpl<ParameterDims>(functor, input, output, &functor);
 }
 
-}  // namespace internal
-}  // namespace ceres
+// When differentiating dynamically sized CostFunctions, VariadicEvaluate
+// expects a functor with the signature:
+//
+// bool operator()(double const* const* parameters, double* cost) const
+//
+// However for NumericDiffFirstOrderFunction, the functor has the signature
+//
+// bool operator()(double const* parameters, double* cost) const
+//
+// This thin wrapper adapts the latter to the former.
+template <typename Functor>
+class FirstOrderFunctorAdapter {
+ public:
+  explicit FirstOrderFunctorAdapter(const Functor& functor)
+      : functor_(functor) {}
+  bool operator()(double const* const* parameters, double* cost) const {
+    return functor_(*parameters, cost);
+  }
+
+ private:
+  const Functor& functor_;
+};
+
+}  // namespace ceres::internal
 
 #endif  // CERES_PUBLIC_INTERNAL_VARIADIC_EVALUATE_H_
diff --git a/third_party/ceres/include/ceres/iteration_callback.h b/third_party/ceres/include/ceres/iteration_callback.h
index 4507fdf..955e2ad 100644
--- a/third_party/ceres/include/ceres/iteration_callback.h
+++ b/third_party/ceres/include/ceres/iteration_callback.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -36,6 +36,7 @@
 #define CERES_PUBLIC_ITERATION_CALLBACK_H_
 
 #include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 #include "ceres/types.h"
 
 namespace ceres {
@@ -164,8 +165,6 @@
 //     explicit LoggingCallback(bool log_to_stdout)
 //         : log_to_stdout_(log_to_stdout) {}
 //
-//     ~LoggingCallback() {}
-//
 //     CallbackReturnType operator()(const IterationSummary& summary) {
 //       const char* kReportRowFormat =
 //           "% 4d: f:% 8e d:% 3.2e g:% 3.2e h:% 3.2e "
@@ -194,7 +193,7 @@
 //
 class CERES_EXPORT IterationCallback {
  public:
-  virtual ~IterationCallback() {}
+  virtual ~IterationCallback();
   virtual CallbackReturnType operator()(const IterationSummary& summary) = 0;
 };
 
diff --git a/third_party/ceres/include/ceres/jet.h b/third_party/ceres/include/ceres/jet.h
index da49f32..3b7f23f 100644
--- a/third_party/ceres/include/ceres/jet.h
+++ b/third_party/ceres/include/ceres/jet.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2024 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -158,20 +158,59 @@
 #define CERES_PUBLIC_JET_H_
 
 #include <cmath>
+#include <complex>
 #include <iosfwd>
 #include <iostream>  // NOLINT
 #include <limits>
+#include <numeric>
 #include <string>
+#include <type_traits>
 
 #include "Eigen/Core"
+#include "ceres/internal/jet_traits.h"
 #include "ceres/internal/port.h"
+#include "ceres/jet_fwd.h"
+
+// Here we provide partial specializations of std::common_type for the Jet class
+// to allow determining a Jet type with a common underlying arithmetic type.
+// Such an arithmetic type can be either a scalar or an another Jet. An example
+// for a common type, say, between a float and a Jet<double, N> is a Jet<double,
+// N> (i.e., std::common_type_t<float, ceres::Jet<double, N>> and
+// ceres::Jet<double, N> refer to the same type.)
+//
+// The partial specialization are also used for determining compatible types by
+// means of SFINAE and thus allow such types to be expressed as operands of
+// logical comparison operators. Missing (partial) specialization of
+// std::common_type for a particular (custom) type will therefore disable the
+// use of comparison operators defined by Ceres.
+//
+// Since these partial specializations are used as SFINAE constraints, they
+// enable standard promotion rules between various scalar types and consequently
+// their use in comparison against a Jet without providing implicit
+// conversions from a scalar, such as an int, to a Jet (see the implementation
+// of logical comparison operators below).
+
+template <typename T, int N, typename U>
+struct std::common_type<T, ceres::Jet<U, N>> {
+  using type = ceres::Jet<common_type_t<T, U>, N>;
+};
+
+template <typename T, int N, typename U>
+struct std::common_type<ceres::Jet<T, N>, U> {
+  using type = ceres::Jet<common_type_t<T, U>, N>;
+};
+
+template <typename T, int N, typename U>
+struct std::common_type<ceres::Jet<T, N>, ceres::Jet<U, N>> {
+  using type = ceres::Jet<common_type_t<T, U>, N>;
+};
 
 namespace ceres {
 
 template <typename T, int N>
 struct Jet {
   enum { DIMENSION = N };
-  typedef T Scalar;
+  using Scalar = T;
 
   // Default-construct "a" because otherwise this can lead to false errors about
   // uninitialized uses when other classes relying on default constructed T
@@ -352,19 +391,21 @@
   return Jet<T, N>(f.a * s_inverse, f.v * s_inverse);
 }
 
-// Binary comparison operators for both scalars and jets.
-#define CERES_DEFINE_JET_COMPARISON_OPERATOR(op)                    \
-  template <typename T, int N>                                      \
-  inline bool operator op(const Jet<T, N>& f, const Jet<T, N>& g) { \
-    return f.a op g.a;                                              \
-  }                                                                 \
-  template <typename T, int N>                                      \
-  inline bool operator op(const T& s, const Jet<T, N>& g) {         \
-    return s op g.a;                                                \
-  }                                                                 \
-  template <typename T, int N>                                      \
-  inline bool operator op(const Jet<T, N>& f, const T& s) {         \
-    return f.a op s;                                                \
+// Binary comparison operators for both scalars and jets. At least one of the
+// operands must be a Jet. Promotable scalars (e.g., int, float, double etc.)
+// can appear on either side of the operator. std::common_type_t is used as an
+// SFINAE constraint to selectively enable compatible operand types. This allows
+// comparison, for instance, against int literals without implicit conversion.
+// In case the Jet arithmetic type is a Jet itself, a recursive expansion of Jet
+// value is performed.
+#define CERES_DEFINE_JET_COMPARISON_OPERATOR(op)                            \
+  template <typename Lhs,                                                   \
+            typename Rhs,                                                   \
+            std::enable_if_t<PromotableJetOperands_v<Lhs, Rhs>>* = nullptr> \
+  constexpr bool operator op(const Lhs& f, const Rhs& g) noexcept(          \
+      noexcept(internal::AsScalar(f) op internal::AsScalar(g))) {           \
+    using internal::AsScalar;                                               \
+    return AsScalar(f) op AsScalar(g);                                      \
   }
 CERES_DEFINE_JET_COMPARISON_OPERATOR(<)   // NOLINT
 CERES_DEFINE_JET_COMPARISON_OPERATOR(<=)  // NOLINT
@@ -386,43 +427,141 @@
 using std::atan2;
 using std::cbrt;
 using std::ceil;
+using std::copysign;
 using std::cos;
 using std::cosh;
+#ifdef CERES_HAS_CPP17_BESSEL_FUNCTIONS
+using std::cyl_bessel_j;
+#endif  // CERES_HAS_CPP17_BESSEL_FUNCTIONS
 using std::erf;
 using std::erfc;
 using std::exp;
 using std::exp2;
+using std::expm1;
+using std::fdim;
 using std::floor;
+using std::fma;
 using std::fmax;
 using std::fmin;
+using std::fpclassify;
 using std::hypot;
 using std::isfinite;
 using std::isinf;
 using std::isnan;
 using std::isnormal;
 using std::log;
+using std::log10;
+using std::log1p;
 using std::log2;
+using std::norm;
 using std::pow;
+using std::signbit;
 using std::sin;
 using std::sinh;
 using std::sqrt;
 using std::tan;
 using std::tanh;
 
+// MSVC (up to 1930) defines quiet comparison functions as template functions
+// which causes compilation errors due to ambiguity in the template parameter
+// type resolution for using declarations in the ceres namespace. Workaround the
+// issue by defining specific overload and bypass MSVC standard library
+// definitions.
+#if defined(_MSC_VER)
+inline bool isgreater(double lhs,
+                      double rhs) noexcept(noexcept(std::isgreater(lhs, rhs))) {
+  return std::isgreater(lhs, rhs);
+}
+inline bool isless(double lhs,
+                   double rhs) noexcept(noexcept(std::isless(lhs, rhs))) {
+  return std::isless(lhs, rhs);
+}
+inline bool islessequal(double lhs,
+                        double rhs) noexcept(noexcept(std::islessequal(lhs,
+                                                                       rhs))) {
+  return std::islessequal(lhs, rhs);
+}
+inline bool isgreaterequal(double lhs, double rhs) noexcept(
+    noexcept(std::isgreaterequal(lhs, rhs))) {
+  return std::isgreaterequal(lhs, rhs);
+}
+inline bool islessgreater(double lhs, double rhs) noexcept(
+    noexcept(std::islessgreater(lhs, rhs))) {
+  return std::islessgreater(lhs, rhs);
+}
+inline bool isunordered(double lhs,
+                        double rhs) noexcept(noexcept(std::isunordered(lhs,
+                                                                       rhs))) {
+  return std::isunordered(lhs, rhs);
+}
+#else
+using std::isgreater;
+using std::isgreaterequal;
+using std::isless;
+using std::islessequal;
+using std::islessgreater;
+using std::isunordered;
+#endif
+
+#ifdef CERES_HAS_CPP20
+using std::lerp;
+using std::midpoint;
+#endif  // defined(CERES_HAS_CPP20)
+
 // Legacy names from pre-C++11 days.
 // clang-format off
+CERES_DEPRECATED_WITH_MSG("ceres::IsFinite will be removed in a future Ceres Solver release. Please use ceres::isfinite.")
 inline bool IsFinite(double x)   { return std::isfinite(x); }
+CERES_DEPRECATED_WITH_MSG("ceres::IsInfinite will be removed in a future Ceres Solver release. Please use ceres::isinf.")
 inline bool IsInfinite(double x) { return std::isinf(x);    }
+CERES_DEPRECATED_WITH_MSG("ceres::IsNaN will be removed in a future Ceres Solver release. Please use ceres::isnan.")
 inline bool IsNaN(double x)      { return std::isnan(x);    }
+CERES_DEPRECATED_WITH_MSG("ceres::IsNormal will be removed in a future Ceres Solver release. Please use ceres::isnormal.")
 inline bool IsNormal(double x)   { return std::isnormal(x); }
 // clang-format on
 
 // In general, f(a + h) ~= f(a) + f'(a) h, via the chain rule.
 
-// abs(x + h) ~= x + h or -(x + h)
+// abs(x + h) ~= abs(x) + sgn(x)h
 template <typename T, int N>
 inline Jet<T, N> abs(const Jet<T, N>& f) {
-  return (f.a < T(0.0) ? -f : f);
+  return Jet<T, N>(abs(f.a), copysign(T(1), f.a) * f.v);
+}
+
+// copysign(a, b) composes a float with the magnitude of a and the sign of b.
+// Therefore, the function can be formally defined as
+//
+//   copysign(a, b) = sgn(b)|a|
+//
+// where
+//
+//   d/dx |x| = sgn(x)
+//   d/dx sgn(x) = 2δ(x)
+//
+// sgn(x) being the signum function. Differentiating copysign(a, b) with respect
+// to a and b gives:
+//
+//   d/da sgn(b)|a| = sgn(a) sgn(b)
+//   d/db sgn(b)|a| = 2|a|δ(b)
+//
+// with the dual representation given by
+//
+//   copysign(a + da, b + db) ~= sgn(b)|a| + (sgn(a)sgn(b) da + 2|a|δ(b) db)
+//
+// where δ(b) is the Dirac delta function.
+template <typename T, int N>
+inline Jet<T, N> copysign(const Jet<T, N>& f, const Jet<T, N> g) {
+  // The Dirac delta function  δ(b) is undefined at b=0 (here it's
+  // infinite) and 0 everywhere else.
+  T d = fpclassify(g) == FP_ZERO ? std::numeric_limits<T>::infinity() : T(0);
+  T sa = copysign(T(1), f.a);  // sgn(a)
+  T sb = copysign(T(1), g.a);  // sgn(b)
+  // The second part of the infinitesimal is 2|a|δ(b) which is either infinity
+  // or 0 unless a or any of the values of the b infinitesimal are 0. In the
+  // latter case, the corresponding values become NaNs (multiplying 0 by
+  // infinity gives NaN). We drop the constant factor 2 since it does not change
+  // the result (its values will still be either 0, infinity or NaN).
+  return Jet<T, N>(copysign(f.a, g.a), sa * sb * f.v + abs(f.a) * d * g.v);
 }
 
 // log(a + h) ~= log(a) + h / a
@@ -432,6 +571,21 @@
   return Jet<T, N>(log(f.a), f.v * a_inverse);
 }
 
+// log10(a + h) ~= log10(a) + h / (a log(10))
+template <typename T, int N>
+inline Jet<T, N> log10(const Jet<T, N>& f) {
+  // Most compilers will expand log(10) to a constant.
+  const T a_inverse = T(1.0) / (f.a * log(T(10.0)));
+  return Jet<T, N>(log10(f.a), f.v * a_inverse);
+}
+
+// log1p(a + h) ~= log1p(a) + h / (1 + a)
+template <typename T, int N>
+inline Jet<T, N> log1p(const Jet<T, N>& f) {
+  const T a_inverse = T(1.0) / (T(1.0) + f.a);
+  return Jet<T, N>(log1p(f.a), f.v * a_inverse);
+}
+
 // exp(a + h) ~= exp(a) + exp(a) h
 template <typename T, int N>
 inline Jet<T, N> exp(const Jet<T, N>& f) {
@@ -439,6 +593,14 @@
   return Jet<T, N>(tmp, tmp * f.v);
 }
 
+// expm1(a + h) ~= expm1(a) + exp(a) h
+template <typename T, int N>
+inline Jet<T, N> expm1(const Jet<T, N>& f) {
+  const T tmp = expm1(f.a);
+  const T expa = tmp + T(1.0);  // exp(a) = expm1(a) + 1
+  return Jet<T, N>(tmp, expa * f.v);
+}
+
 // sqrt(a + h) ~= sqrt(a) + h / (2 sqrt(a))
 template <typename T, int N>
 inline Jet<T, N> sqrt(const Jet<T, N>& f) {
@@ -565,31 +727,152 @@
   return Jet<T, N>(tmp, x.a / tmp * x.v + y.a / tmp * y.v);
 }
 
+// Like sqrt(x^2 + y^2 + z^2),
+// but acts to prevent underflow/overflow for small/large x/y/z.
+// Note that the function is non-smooth at x=y=z=0,
+// so the derivative is undefined there.
 template <typename T, int N>
-inline Jet<T, N> fmax(const Jet<T, N>& x, const Jet<T, N>& y) {
-  return x < y ? y : x;
+inline Jet<T, N> hypot(const Jet<T, N>& x,
+                       const Jet<T, N>& y,
+                       const Jet<T, N>& z) {
+  // d/da sqrt(a) = 0.5 / sqrt(a)
+  // d/dx x^2 + y^2 + z^2 = 2x
+  // So by the chain rule:
+  // d/dx sqrt(x^2 + y^2 + z^2)
+  //    = 0.5 / sqrt(x^2 + y^2 + z^2) * 2x
+  //    = x / sqrt(x^2 + y^2 + z^2)
+  // d/dy sqrt(x^2 + y^2 + z^2) = y / sqrt(x^2 + y^2 + z^2)
+  // d/dz sqrt(x^2 + y^2 + z^2) = z / sqrt(x^2 + y^2 + z^2)
+  const T tmp = hypot(x.a, y.a, z.a);
+  return Jet<T, N>(tmp, x.a / tmp * x.v + y.a / tmp * y.v + z.a / tmp * z.v);
 }
 
+// Like x * y + z but rounded only once.
 template <typename T, int N>
-inline Jet<T, N> fmin(const Jet<T, N>& x, const Jet<T, N>& y) {
-  return y < x ? y : x;
+inline Jet<T, N> fma(const Jet<T, N>& x,
+                     const Jet<T, N>& y,
+                     const Jet<T, N>& z) {
+  // d/dx fma(x, y, z) = y
+  // d/dy fma(x, y, z) = x
+  // d/dz fma(x, y, z) = 1
+  return Jet<T, N>(fma(x.a, y.a, z.a), y.a * x.v + x.a * y.v + z.v);
 }
 
-// erf is defined as an integral that cannot be expressed analyticaly
+// Return value of fmax() and fmin() on equality
+// ---------------------------------------------
+//
+// There is arguably no good answer to what fmax() & fmin() should return on
+// equality, which for Jets by definition ONLY compares the scalar parts. We
+// choose what we think is the least worst option (averaging as Jets) which
+// minimises undesirable/unexpected behaviour as used, and also supports client
+// code written against Ceres versions prior to type promotion being supported
+// in Jet comparisons (< v2.1).
+//
+// The std::max() convention of returning the first argument on equality is
+// problematic, as it means that the derivative component may or may not be
+// preserved (when comparing a Jet with a scalar) depending upon the ordering.
+//
+// Always returning the Jet in {Jet, scalar} cases on equality is problematic
+// as it is inconsistent with the behaviour that would be obtained if the scalar
+// was first cast to Jet and the {Jet, Jet} case was used. Prior to type
+// promotion (Ceres v2.1) client code would typically cast constants to Jets
+// e.g: fmax(x, T(2.0)) which means the {Jet, Jet} case predominates, and we
+// still want the result to be order independent.
+//
+// Our intuition is that preserving a non-zero derivative is best, even if
+// its value does not match either of the inputs. Averaging achieves this
+// whilst ensuring argument ordering independence. This is also the approach
+// used by the Jax library, and TensorFlow's reduce_max().
+
+// Returns the larger of the two arguments, with Jet averaging on equality.
+// NaNs are treated as missing data.
+//
+// NOTE: This function is NOT subject to any of the error conditions specified
+//       in `math_errhandling`.
+template <typename Lhs,
+          typename Rhs,
+          std::enable_if_t<CompatibleJetOperands_v<Lhs, Rhs>>* = nullptr>
+inline decltype(auto) fmax(const Lhs& x, const Rhs& y) {
+  using J = std::common_type_t<Lhs, Rhs>;
+  // As x == y may set FP exceptions in the presence of NaNs when used with
+  // non-default compiler options so we avoid its use here.
+  if (isnan(x) || isnan(y) || islessgreater(x, y)) {
+    return isnan(x) || isless(x, y) ? J{y} : J{x};
+  }
+  // x == y (scalar parts) return the average of their Jet representations.
+#if defined(CERES_HAS_CPP20)
+  return midpoint(J{x}, J{y});
+#else
+  return (J{x} + J{y}) * typename J::Scalar(0.5);
+#endif  // defined(CERES_HAS_CPP20)
+}
+
+// Returns the smaller of the two arguments, with Jet averaging on equality.
+// NaNs are treated as missing data.
+//
+// NOTE: This function is NOT subject to any of the error conditions specified
+//       in `math_errhandling`.
+template <typename Lhs,
+          typename Rhs,
+          std::enable_if_t<CompatibleJetOperands_v<Lhs, Rhs>>* = nullptr>
+inline decltype(auto) fmin(const Lhs& x, const Rhs& y) {
+  using J = std::common_type_t<Lhs, Rhs>;
+  // As x == y may set FP exceptions in the presence of NaNs when used with
+  // non-default compiler options so we avoid its use here.
+  if (isnan(x) || isnan(y) || islessgreater(x, y)) {
+    return isnan(x) || isgreater(x, y) ? J{y} : J{x};
+  }
+  // x == y (scalar parts) return the average of their Jet representations.
+#if defined(CERES_HAS_CPP20)
+  return midpoint(J{x}, J{y});
+#else
+  return (J{x} + J{y}) * typename J::Scalar(0.5);
+#endif  // defined(CERES_HAS_CPP20)
+}
+
+// Returns the positive difference (f - g) of two arguments and zero if f <= g.
+// If at least one argument is NaN, a NaN is return.
+//
+// NOTE At least one of the argument types must be a Jet, the other one can be a
+// scalar. In case both arguments are Jets, their dimensionality must match.
+template <typename Lhs,
+          typename Rhs,
+          std::enable_if_t<CompatibleJetOperands_v<Lhs, Rhs>>* = nullptr>
+inline decltype(auto) fdim(const Lhs& f, const Rhs& g) {
+  using J = std::common_type_t<Lhs, Rhs>;
+  if (isnan(f) || isnan(g)) {
+    return std::numeric_limits<J>::quiet_NaN();
+  }
+  return isgreater(f, g) ? J{f - g} : J{};
+}
+
+// erf is defined as an integral that cannot be expressed analytically
 // however, the derivative is trivial to compute
 // erf(x + h) = erf(x) + h * 2*exp(-x^2)/sqrt(pi)
 template <typename T, int N>
 inline Jet<T, N> erf(const Jet<T, N>& x) {
-  return Jet<T, N>(erf(x.a), x.v * M_2_SQRTPI * exp(-x.a * x.a));
+  // We evaluate the constant as follows:
+  //   2 / sqrt(pi) = 1 / sqrt(atan(1.))
+  // On POSIX systems it is defined as M_2_SQRTPI, but this is not
+  // portable and the type may not be T.  The above expression
+  // evaluates to full precision with IEEE arithmetic and, since it's
+  // constant, the compiler can generate exactly the same code.  gcc
+  // does so even at -O0.
+  return Jet<T, N>(erf(x.a), x.v * exp(-x.a * x.a) * (T(1) / sqrt(atan(T(1)))));
 }
 
 // erfc(x) = 1-erf(x)
 // erfc(x + h) = erfc(x) + h * (-2*exp(-x^2)/sqrt(pi))
 template <typename T, int N>
 inline Jet<T, N> erfc(const Jet<T, N>& x) {
-  return Jet<T, N>(erfc(x.a), -x.v * M_2_SQRTPI * exp(-x.a * x.a));
+  // See in erf() above for the evaluation of the constant in the derivative.
+  return Jet<T, N>(erfc(x.a),
+                   -x.v * exp(-x.a * x.a) * (T(1) / sqrt(atan(T(1)))));
 }
 
+#if defined(CERES_HAS_CPP17_BESSEL_FUNCTIONS) || \
+    defined(CERES_HAS_POSIX_BESSEL_FUNCTIONS)
+
 // Bessel functions of the first kind with integer order equal to 0, 1, n.
 //
 // Microsoft has deprecated the j[0,1,n]() POSIX Bessel functions in favour of
@@ -597,25 +880,33 @@
 // function errors in client code (the specific warning is suppressed when
 // Ceres itself is built).
 inline double BesselJ0(double x) {
-#if defined(CERES_MSVC_USE_UNDERSCORE_PREFIXED_BESSEL_FUNCTIONS)
-  return _j0(x);
+#ifdef CERES_HAS_CPP17_BESSEL_FUNCTIONS
+  return cyl_bessel_j(0, x);
 #else
+  CERES_DISABLE_DEPRECATED_WARNING
   return j0(x);
-#endif
+  CERES_RESTORE_DEPRECATED_WARNING
+#endif  // defined(CERES_HAS_CPP17_BESSEL_FUNCTIONS)
 }
+
 inline double BesselJ1(double x) {
-#if defined(CERES_MSVC_USE_UNDERSCORE_PREFIXED_BESSEL_FUNCTIONS)
-  return _j1(x);
+#ifdef CERES_HAS_CPP17_BESSEL_FUNCTIONS
+  return cyl_bessel_j(1, x);
 #else
+  CERES_DISABLE_DEPRECATED_WARNING
   return j1(x);
-#endif
+  CERES_RESTORE_DEPRECATED_WARNING
+#endif  // defined(CERES_HAS_CPP17_BESSEL_FUNCTIONS)
 }
+
 inline double BesselJn(int n, double x) {
-#if defined(CERES_MSVC_USE_UNDERSCORE_PREFIXED_BESSEL_FUNCTIONS)
-  return _jn(n, x);
+#ifdef CERES_HAS_CPP17_BESSEL_FUNCTIONS
+  return cyl_bessel_j(static_cast<double>(n), x);
 #else
+  CERES_DISABLE_DEPRECATED_WARNING
   return jn(n, x);
-#endif
+  CERES_RESTORE_DEPRECATED_WARNING
+#endif  // defined(CERES_HAS_CPP17_BESSEL_FUNCTIONS)
 }
 
 // For the formulae of the derivatives of the Bessel functions see the book:
@@ -628,100 +919,264 @@
 // j0(a + h) ~= j0(a) - j1(a) h
 template <typename T, int N>
 inline Jet<T, N> BesselJ0(const Jet<T, N>& f) {
+#ifdef CERES_HAS_CPP17_BESSEL_FUNCTIONS
+  return cyl_bessel_j(0, f);
+#else
   return Jet<T, N>(BesselJ0(f.a), -BesselJ1(f.a) * f.v);
+#endif  // defined(CERES_HAS_CPP17_BESSEL_FUNCTIONS)
 }
 
 // See formula http://dlmf.nist.gov/10.6#E1
 // j1(a + h) ~= j1(a) + 0.5 ( j0(a) - j2(a) ) h
 template <typename T, int N>
 inline Jet<T, N> BesselJ1(const Jet<T, N>& f) {
+#ifdef CERES_HAS_CPP17_BESSEL_FUNCTIONS
+  return cyl_bessel_j(1, f);
+#else
   return Jet<T, N>(BesselJ1(f.a),
                    T(0.5) * (BesselJ0(f.a) - BesselJn(2, f.a)) * f.v);
+#endif  // defined(CERES_HAS_CPP17_BESSEL_FUNCTIONS)
 }
 
 // See formula http://dlmf.nist.gov/10.6#E1
 // j_n(a + h) ~= j_n(a) + 0.5 ( j_{n-1}(a) - j_{n+1}(a) ) h
 template <typename T, int N>
 inline Jet<T, N> BesselJn(int n, const Jet<T, N>& f) {
+#ifdef CERES_HAS_CPP17_BESSEL_FUNCTIONS
+  return cyl_bessel_j(n, f);
+#else
   return Jet<T, N>(
       BesselJn(n, f.a),
       T(0.5) * (BesselJn(n - 1, f.a) - BesselJn(n + 1, f.a)) * f.v);
+#endif  // defined(CERES_HAS_CPP17_BESSEL_FUNCTIONS)
 }
 
-// Jet Classification. It is not clear what the appropriate semantics are for
-// these classifications. This picks that std::isfinite and std::isnormal are
-// "all" operations, i.e. all elements of the jet must be finite for the jet
-// itself to be finite (or normal). For IsNaN and IsInfinite, the answer is less
-// clear. This takes a "any" approach for IsNaN and IsInfinite such that if any
-// part of a jet is nan or inf, then the entire jet is nan or inf. This leads
-// to strange situations like a jet can be both IsInfinite and IsNaN, but in
-// practice the "any" semantics are the most useful for e.g. checking that
-// derivatives are sane.
+#endif  // defined(CERES_HAS_CPP17_BESSEL_FUNCTIONS) ||
+        // defined(CERES_HAS_POSIX_BESSEL_FUNCTIONS)
 
-// The jet is finite if all parts of the jet are finite.
+#ifdef CERES_HAS_CPP17_BESSEL_FUNCTIONS
+
+// See formula http://dlmf.nist.gov/10.6#E1
+// j_n(a + h) ~= j_n(a) + 0.5 ( j_{n-1}(a) - j_{n+1}(a) ) h
+template <typename T, int N>
+inline Jet<T, N> cyl_bessel_j(double v, const Jet<T, N>& f) {
+  // See formula http://dlmf.nist.gov/10.6#E3
+  // j0(a + h) ~= j0(a) - j1(a) h
+  if (fpclassify(v) == FP_ZERO) {
+    return Jet<T, N>(cyl_bessel_j(0, f.a), -cyl_bessel_j(1, f.a) * f.v);
+  }
+
+  return Jet<T, N>(
+      cyl_bessel_j(v, f.a),
+      T(0.5) * (cyl_bessel_j(v - 1, f.a) - cyl_bessel_j(v + 1, f.a)) * f.v);
+}
+
+#endif  // CERES_HAS_CPP17_BESSEL_FUNCTIONS
+
+// Classification and comparison functionality referencing only the scalar part
+// of a Jet. To classify the derivatives (e.g., for sanity checks), the dual
+// part should be referenced explicitly. For instance, to check whether the
+// derivatives of a Jet 'f' are reasonable, one can use
+//
+//  isfinite(f.v.array()).all()
+//  !isnan(f.v.array()).any()
+//
+// etc., depending on the desired semantics.
+//
+// NOTE: Floating-point classification and comparison functions and operators
+// should be used with care as no derivatives can be propagated by such
+// functions directly but only by expressions resulting from corresponding
+// conditional statements. At the same time, conditional statements can possibly
+// introduce a discontinuity in the cost function making it impossible to
+// evaluate its derivative and thus the optimization problem intractable.
+
+// Determines whether the scalar part of the Jet is finite.
 template <typename T, int N>
 inline bool isfinite(const Jet<T, N>& f) {
-  // Branchless implementation. This is more efficient for the false-case and
-  // works with the codegen system.
-  auto result = isfinite(f.a);
-  for (int i = 0; i < N; ++i) {
-    result = result & isfinite(f.v[i]);
-  }
-  return result;
+  return isfinite(f.a);
 }
 
-// The jet is infinite if any part of the Jet is infinite.
+// Determines whether the scalar part of the Jet is infinite.
 template <typename T, int N>
 inline bool isinf(const Jet<T, N>& f) {
-  auto result = isinf(f.a);
-  for (int i = 0; i < N; ++i) {
-    result = result | isinf(f.v[i]);
-  }
-  return result;
+  return isinf(f.a);
 }
 
-// The jet is NaN if any part of the jet is NaN.
+// Determines whether the scalar part of the Jet is NaN.
 template <typename T, int N>
 inline bool isnan(const Jet<T, N>& f) {
-  auto result = isnan(f.a);
-  for (int i = 0; i < N; ++i) {
-    result = result | isnan(f.v[i]);
-  }
-  return result;
+  return isnan(f.a);
 }
 
-// The jet is normal if all parts of the jet are normal.
+// Determines whether the scalar part of the Jet is neither zero, subnormal,
+// infinite, nor NaN.
 template <typename T, int N>
 inline bool isnormal(const Jet<T, N>& f) {
-  auto result = isnormal(f.a);
-  for (int i = 0; i < N; ++i) {
-    result = result & isnormal(f.v[i]);
-  }
-  return result;
+  return isnormal(f.a);
+}
+
+// Determines whether the scalar part of the Jet f is less than the scalar
+// part of g.
+//
+// NOTE: This function does NOT set any floating-point exceptions.
+template <typename Lhs,
+          typename Rhs,
+          std::enable_if_t<CompatibleJetOperands_v<Lhs, Rhs>>* = nullptr>
+inline bool isless(const Lhs& f, const Rhs& g) {
+  using internal::AsScalar;
+  return isless(AsScalar(f), AsScalar(g));
+}
+
+// Determines whether the scalar part of the Jet f is greater than the scalar
+// part of g.
+//
+// NOTE: This function does NOT set any floating-point exceptions.
+template <typename Lhs,
+          typename Rhs,
+          std::enable_if_t<CompatibleJetOperands_v<Lhs, Rhs>>* = nullptr>
+inline bool isgreater(const Lhs& f, const Rhs& g) {
+  using internal::AsScalar;
+  return isgreater(AsScalar(f), AsScalar(g));
+}
+
+// Determines whether the scalar part of the Jet f is less than or equal to the
+// scalar part of g.
+//
+// NOTE: This function does NOT set any floating-point exceptions.
+template <typename Lhs,
+          typename Rhs,
+          std::enable_if_t<CompatibleJetOperands_v<Lhs, Rhs>>* = nullptr>
+inline bool islessequal(const Lhs& f, const Rhs& g) {
+  using internal::AsScalar;
+  return islessequal(AsScalar(f), AsScalar(g));
+}
+
+// Determines whether the scalar part of the Jet f is less than or greater than
+// (f < g || f > g) the scalar part of g.
+//
+// NOTE: This function does NOT set any floating-point exceptions.
+template <typename Lhs,
+          typename Rhs,
+          std::enable_if_t<CompatibleJetOperands_v<Lhs, Rhs>>* = nullptr>
+inline bool islessgreater(const Lhs& f, const Rhs& g) {
+  using internal::AsScalar;
+  return islessgreater(AsScalar(f), AsScalar(g));
+}
+
+// Determines whether the scalar part of the Jet f is greater than or equal to
+// the scalar part of g.
+//
+// NOTE: This function does NOT set any floating-point exceptions.
+template <typename Lhs,
+          typename Rhs,
+          std::enable_if_t<CompatibleJetOperands_v<Lhs, Rhs>>* = nullptr>
+inline bool isgreaterequal(const Lhs& f, const Rhs& g) {
+  using internal::AsScalar;
+  return isgreaterequal(AsScalar(f), AsScalar(g));
+}
+
+// Determines if either of the scalar parts of the arguments are NaN and
+// thus cannot be ordered with respect to each other.
+template <typename Lhs,
+          typename Rhs,
+          std::enable_if_t<CompatibleJetOperands_v<Lhs, Rhs>>* = nullptr>
+inline bool isunordered(const Lhs& f, const Rhs& g) {
+  using internal::AsScalar;
+  return isunordered(AsScalar(f), AsScalar(g));
+}
+
+// Categorize scalar part as zero, subnormal, normal, infinite, NaN, or
+// implementation-defined.
+template <typename T, int N>
+inline int fpclassify(const Jet<T, N>& f) {
+  return fpclassify(f.a);
+}
+
+// Determines whether the scalar part of the argument is negative.
+template <typename T, int N>
+inline bool signbit(const Jet<T, N>& f) {
+  return signbit(f.a);
 }
 
 // Legacy functions from the pre-C++11 days.
 template <typename T, int N>
+CERES_DEPRECATED_WITH_MSG(
+    "ceres::IsFinite will be removed in a future Ceres Solver release. Please "
+    "use ceres::isfinite.")
 inline bool IsFinite(const Jet<T, N>& f) {
   return isfinite(f);
 }
 
 template <typename T, int N>
+CERES_DEPRECATED_WITH_MSG(
+    "ceres::IsNaN will be removed in a future Ceres Solver release. Please use "
+    "ceres::isnan.")
 inline bool IsNaN(const Jet<T, N>& f) {
   return isnan(f);
 }
 
 template <typename T, int N>
+CERES_DEPRECATED_WITH_MSG(
+    "ceres::IsNormal will be removed in a future Ceres Solver release. Please "
+    "use ceres::isnormal.")
 inline bool IsNormal(const Jet<T, N>& f) {
   return isnormal(f);
 }
 
 // The jet is infinite if any part of the jet is infinite.
 template <typename T, int N>
+CERES_DEPRECATED_WITH_MSG(
+    "ceres::IsInfinite will be removed in a future Ceres Solver release. "
+    "Please use ceres::isinf.")
 inline bool IsInfinite(const Jet<T, N>& f) {
   return isinf(f);
 }
 
+#ifdef CERES_HAS_CPP20
+// Computes the linear interpolation a + t(b - a) between a and b at the value
+// t. For arguments outside of the range 0 <= t <= 1, the values are
+// extrapolated.
+//
+// Differentiating lerp(a, b, t) with respect to a, b, and t gives:
+//
+//   d/da lerp(a, b, t) = 1 - t
+//   d/db lerp(a, b, t) = t
+//   d/dt lerp(a, b, t) = b - a
+//
+// with the dual representation given by
+//
+//   lerp(a + da, b + db, t + dt)
+//      ~= lerp(a, b, t) + (1 - t) da + t db + (b - a) dt .
+template <typename T, int N>
+inline Jet<T, N> lerp(const Jet<T, N>& a,
+                      const Jet<T, N>& b,
+                      const Jet<T, N>& t) {
+  return Jet<T, N>{lerp(a.a, b.a, t.a),
+                   (T(1) - t.a) * a.v + t.a * b.v + (b.a - a.a) * t.v};
+}
+
+// Computes the midpoint a + (b - a) / 2.
+//
+// Differentiating midpoint(a, b) with respect to a and b gives:
+//
+//   d/da midpoint(a, b) = 1/2
+//   d/db midpoint(a, b) = 1/2
+//
+// with the dual representation given by
+//
+//   midpoint(a + da, b + db) ~= midpoint(a, b) + (da + db) / 2 .
+template <typename T, int N>
+inline Jet<T, N> midpoint(const Jet<T, N>& a, const Jet<T, N>& b) {
+  Jet<T, N> result{midpoint(a.a, b.a)};
+  // To avoid overflow in the differential, compute
+  // (da + db) / 2 using midpoint.
+  for (int i = 0; i < N; ++i) {
+    result.v[i] = midpoint(a.v[i], b.v[i]);
+  }
+  return result;
+}
+#endif  // defined(CERES_HAS_CPP20)
+
 // atan2(b + db, a + da) ~= atan2(b, a) + (- b da + a db) / (a^2 + b^2)
 //
 // In words: the rate of change of theta is 1/r times the rate of
@@ -737,6 +1192,22 @@
   return Jet<T, N>(atan2(g.a, f.a), tmp * (-g.a * f.v + f.a * g.v));
 }
 
+// Computes the square x^2 of a real number x (not the Euclidean L^2 norm as
+// the name might suggest).
+//
+// NOTE: While std::norm is primarily intended for computing the squared
+// magnitude of a std::complex<> number, the current Jet implementation does not
+// support mixing a scalar T in its real part and std::complex<T> and in the
+// infinitesimal. Mixed Jet support is necessary for the type decay from
+// std::complex<T> to T (the squared magnitude of a complex number is always
+// real) performed by std::norm.
+//
+// norm(x + h) ~= norm(x) + 2x h
+template <typename T, int N>
+inline Jet<T, N> norm(const Jet<T, N>& f) {
+  return Jet<T, N>(norm(f.a), T(2) * f.a * f.v);
+}
+
 // pow -- base is a differentiable function, exponent is a constant.
 // (a+da)^p ~= a^p + p*a^(p-1) da
 template <typename T, int N>
@@ -760,14 +1231,14 @@
 inline Jet<T, N> pow(T f, const Jet<T, N>& g) {
   Jet<T, N> result;
 
-  if (f == T(0) && g.a > T(0)) {
+  if (fpclassify(f) == FP_ZERO && g > 0) {
     // Handle case 2.
     result = Jet<T, N>(T(0.0));
   } else {
-    if (f < 0 && g.a == floor(g.a)) {  // Handle case 3.
+    if (f < 0 && g == floor(g.a)) {  // Handle case 3.
       result = Jet<T, N>(pow(f, g.a));
       for (int i = 0; i < N; i++) {
-        if (g.v[i] != T(0.0)) {
+        if (fpclassify(g.v[i]) != FP_ZERO) {
           // Return a NaN when g.v != 0.
           result.v[i] = std::numeric_limits<T>::quiet_NaN();
         }
@@ -822,21 +1293,21 @@
 inline Jet<T, N> pow(const Jet<T, N>& f, const Jet<T, N>& g) {
   Jet<T, N> result;
 
-  if (f.a == T(0) && g.a >= T(1)) {
+  if (fpclassify(f) == FP_ZERO && g >= 1) {
     // Handle cases 2 and 3.
-    if (g.a > T(1)) {
+    if (g > 1) {
       result = Jet<T, N>(T(0.0));
     } else {
       result = f;
     }
 
   } else {
-    if (f.a < T(0) && g.a == floor(g.a)) {
+    if (f < 0 && g == floor(g.a)) {
       // Handle cases 7 and 8.
       T const tmp = g.a * pow(f.a, g.a - T(1.0));
       result = Jet<T, N>(pow(f.a, g.a), tmp * f.v);
       for (int i = 0; i < N; i++) {
-        if (g.v[i] != T(0.0)) {
+        if (fpclassify(g.v[i]) != FP_ZERO) {
           // Return a NaN when g.v != 0.
           result.v[i] = T(std::numeric_limits<double>::quiet_NaN());
         }
@@ -887,8 +1358,13 @@
   static constexpr bool is_bounded = std::numeric_limits<T>::is_bounded;
   static constexpr bool is_modulo = std::numeric_limits<T>::is_modulo;
 
+  // has_denorm (and has_denorm_loss, not defined for Jet) has been deprecated
+  // in C++23. However, without an intent to remove the declaration. Disable
+  // deprecation warnings temporarily just for the corresponding symbols.
+  CERES_DISABLE_DEPRECATED_WARNING
   static constexpr std::float_denorm_style has_denorm =
       std::numeric_limits<T>::has_denorm;
+  CERES_RESTORE_DEPRECATED_WARNING
   static constexpr std::float_round_style round_style =
       std::numeric_limits<T>::round_style;
 
@@ -904,8 +1380,9 @@
   static constexpr bool tinyness_before =
       std::numeric_limits<T>::tinyness_before;
 
-  static constexpr ceres::Jet<T, N> min() noexcept {
-    return ceres::Jet<T, N>(std::numeric_limits<T>::min());
+  static constexpr ceres::Jet<T, N> min
+  CERES_PREVENT_MACRO_SUBSTITUTION() noexcept {
+    return ceres::Jet<T, N>((std::numeric_limits<T>::min)());
   }
   static constexpr ceres::Jet<T, N> lowest() noexcept {
     return ceres::Jet<T, N>(std::numeric_limits<T>::lowest());
@@ -929,8 +1406,9 @@
     return ceres::Jet<T, N>(std::numeric_limits<T>::denorm_min());
   }
 
-  static constexpr ceres::Jet<T, N> max() noexcept {
-    return ceres::Jet<T, N>(std::numeric_limits<T>::max());
+  static constexpr ceres::Jet<T, N> max
+  CERES_PREVENT_MACRO_SUBSTITUTION() noexcept {
+    return ceres::Jet<T, N>((std::numeric_limits<T>::max)());
   }
 };
 
@@ -942,10 +1420,10 @@
 // Eigen arrays, getting all the goodness of Eigen combined with autodiff.
 template <typename T, int N>
 struct NumTraits<ceres::Jet<T, N>> {
-  typedef ceres::Jet<T, N> Real;
-  typedef ceres::Jet<T, N> NonInteger;
-  typedef ceres::Jet<T, N> Nested;
-  typedef ceres::Jet<T, N> Literal;
+  using Real = ceres::Jet<T, N>;
+  using NonInteger = ceres::Jet<T, N>;
+  using Nested = ceres::Jet<T, N>;
+  using Literal = ceres::Jet<T, N>;
 
   static typename ceres::Jet<T, N> dummy_precision() {
     return ceres::Jet<T, N>(1e-12);
@@ -956,6 +1434,7 @@
   }
 
   static inline int digits10() { return NumTraits<T>::digits10(); }
+  static inline int max_digits10() { return NumTraits<T>::max_digits10(); }
 
   enum {
     IsComplex = 0,
@@ -984,8 +1463,8 @@
     };
   };
 
-  static inline Real highest() { return Real(std::numeric_limits<T>::max()); }
-  static inline Real lowest() { return Real(-std::numeric_limits<T>::max()); }
+  static inline Real highest() { return Real((std::numeric_limits<T>::max)()); }
+  static inline Real lowest() { return Real(-(std::numeric_limits<T>::max)()); }
 };
 
 // Specifying the return type of binary operations between Jets and scalar types
@@ -996,11 +1475,11 @@
 // is only available on Eigen versions >= 3.3
 template <typename BinaryOp, typename T, int N>
 struct ScalarBinaryOpTraits<ceres::Jet<T, N>, T, BinaryOp> {
-  typedef ceres::Jet<T, N> ReturnType;
+  using ReturnType = ceres::Jet<T, N>;
 };
 template <typename BinaryOp, typename T, int N>
 struct ScalarBinaryOpTraits<T, ceres::Jet<T, N>, BinaryOp> {
-  typedef ceres::Jet<T, N> ReturnType;
+  using ReturnType = ceres::Jet<T, N>;
 };
 
 }  // namespace Eigen
diff --git a/third_party/ceres/include/ceres/jet_fwd.h b/third_party/ceres/include/ceres/jet_fwd.h
new file mode 100644
index 0000000..b5216da
--- /dev/null
+++ b/third_party/ceres/include/ceres/jet_fwd.h
@@ -0,0 +1,44 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: sergiu.deitsch@gmail.com (Sergiu Deitsch)
+//
+
+#ifndef CERES_PUBLIC_JET_FWD_H_
+#define CERES_PUBLIC_JET_FWD_H_
+
+namespace ceres {
+
+// Jet forward declaration necessary for the following partial specialization of
+// std::common_type and type traits.
+template <typename T, int N>
+struct Jet;
+
+}  // namespace ceres
+
+#endif  // CERES_PUBLIC_JET_FWD_H_
diff --git a/third_party/ceres/include/ceres/line_manifold.h b/third_party/ceres/include/ceres/line_manifold.h
new file mode 100644
index 0000000..dad9737
--- /dev/null
+++ b/third_party/ceres/include/ceres/line_manifold.h
@@ -0,0 +1,301 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: jodebo_beck@gmx.de (Johannes Beck)
+//
+
+#ifndef CERES_PUBLIC_LINE_MANIFOLD_H_
+#define CERES_PUBLIC_LINE_MANIFOLD_H_
+
+#include <Eigen/Core>
+#include <algorithm>
+#include <array>
+#include <memory>
+#include <vector>
+
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
+#include "ceres/internal/householder_vector.h"
+#include "ceres/internal/sphere_manifold_functions.h"
+#include "ceres/manifold.h"
+#include "ceres/types.h"
+#include "glog/logging.h"
+
+namespace ceres {
+// This provides a manifold for lines, where the line is
+// over-parameterized by an origin point and a direction vector. So the
+// parameter vector size needs to be two times the ambient space dimension,
+// where the first half is interpreted as the origin point and the second half
+// as the direction.
+//
+// The plus operator for the line direction is the same as for the
+// SphereManifold. The update of the origin point is
+// perpendicular to the line direction before the update.
+//
+// This manifold is a special case of the affine Grassmannian
+// manifold (see https://en.wikipedia.org/wiki/Affine_Grassmannian_(manifold))
+// for the case Graff_1(R^n).
+//
+// The class works with dynamic and static ambient space dimensions. If the
+// ambient space dimensions is known at compile time use
+//
+//    LineManifold<3> manifold;
+//
+// If the ambient space dimensions is not known at compile time the template
+// parameter needs to be set to ceres::DYNAMIC and the actual dimension needs
+// to be provided as a constructor argument:
+//
+//    LineManifold<ceres::DYNAMIC> manifold(ambient_dim);
+//
+template <int AmbientSpaceDimension>
+class LineManifold final : public Manifold {
+ public:
+  static_assert(AmbientSpaceDimension == DYNAMIC || AmbientSpaceDimension >= 2,
+                "The ambient space must be at least 2.");
+  static_assert(ceres::DYNAMIC == Eigen::Dynamic,
+                "ceres::DYNAMIC needs to be the same as Eigen::Dynamic.");
+
+  LineManifold();
+  explicit LineManifold(int size);
+
+  int AmbientSize() const override { return 2 * size_; }
+  int TangentSize() const override { return 2 * (size_ - 1); }
+  bool Plus(const double* x,
+            const double* delta,
+            double* x_plus_delta) const override;
+  bool PlusJacobian(const double* x, double* jacobian) const override;
+  bool Minus(const double* y,
+             const double* x,
+             double* y_minus_x) const override;
+  bool MinusJacobian(const double* x, double* jacobian) const override;
+
+ private:
+  static constexpr bool IsDynamic = (AmbientSpaceDimension == ceres::DYNAMIC);
+  static constexpr int TangentSpaceDimension =
+      IsDynamic ? ceres::DYNAMIC : AmbientSpaceDimension - 1;
+
+  static constexpr int DAmbientSpaceDimension =
+      IsDynamic ? ceres::DYNAMIC : 2 * AmbientSpaceDimension;
+  static constexpr int DTangentSpaceDimension =
+      IsDynamic ? ceres::DYNAMIC : 2 * TangentSpaceDimension;
+
+  using AmbientVector = Eigen::Matrix<double, AmbientSpaceDimension, 1>;
+  using TangentVector = Eigen::Matrix<double, TangentSpaceDimension, 1>;
+  using MatrixPlusJacobian = Eigen::Matrix<double,
+                                           DAmbientSpaceDimension,
+                                           DTangentSpaceDimension,
+                                           Eigen::RowMajor>;
+  using MatrixMinusJacobian = Eigen::Matrix<double,
+                                            DTangentSpaceDimension,
+                                            DAmbientSpaceDimension,
+                                            Eigen::RowMajor>;
+
+  const int size_{AmbientSpaceDimension};
+};
+
+template <int AmbientSpaceDimension>
+LineManifold<AmbientSpaceDimension>::LineManifold()
+    : size_{AmbientSpaceDimension} {
+  static_assert(
+      AmbientSpaceDimension != Eigen::Dynamic,
+      "The size is set to dynamic. Please call the constructor with a size.");
+}
+
+template <int AmbientSpaceDimension>
+LineManifold<AmbientSpaceDimension>::LineManifold(int size) : size_{size} {
+  if (AmbientSpaceDimension != Eigen::Dynamic) {
+    CHECK_EQ(AmbientSpaceDimension, size)
+        << "Specified size by template parameter differs from the supplied "
+           "one.";
+  } else {
+    CHECK_GT(size_, 1)
+        << "The size of the manifold needs to be greater than 1.";
+  }
+}
+
+template <int AmbientSpaceDimension>
+bool LineManifold<AmbientSpaceDimension>::Plus(const double* x_ptr,
+                                               const double* delta_ptr,
+                                               double* x_plus_delta_ptr) const {
+  // We seek a box plus operator of the form
+  //
+  //   [o*, d*] = Plus([o, d], [delta_o, delta_d])
+  //
+  // where o is the origin point, d is the direction vector, delta_o is
+  // the delta of the origin point and delta_d the delta of the direction and
+  // o* and d* is the updated origin point and direction.
+  //
+  // We separate the Plus operator into the origin point and directional part
+  //   d* = Plus_d(d, delta_d)
+  //   o* = Plus_o(o, d, delta_o)
+  //
+  // The direction update function Plus_d is the same as as the SphereManifold:
+  //
+  //   d* = H_{v(d)} [sinc(|delta_d|) delta_d, cos(|delta_d|)]^T
+  //
+  // where H is the householder matrix
+  //   H_{v} = I - (2 / |v|^2) v v^T
+  // and
+  //   v(d) = d - sign(d_n) |d| e_n.
+  //
+  // The origin point update function Plus_o is defined as
+  //
+  //   o* = o + H_{v(d)} [delta_o, 0]^T.
+
+  Eigen::Map<const AmbientVector> o(x_ptr, size_);
+  Eigen::Map<const AmbientVector> d(x_ptr + size_, size_);
+
+  Eigen::Map<const TangentVector> delta_o(delta_ptr, size_ - 1);
+  Eigen::Map<const TangentVector> delta_d(delta_ptr + size_ - 1, size_ - 1);
+  Eigen::Map<AmbientVector> o_plus_delta(x_plus_delta_ptr, size_);
+  Eigen::Map<AmbientVector> d_plus_delta(x_plus_delta_ptr + size_, size_);
+
+  const double norm_delta_d = delta_d.norm();
+
+  o_plus_delta = o;
+
+  // Shortcut for zero delta direction.
+  if (norm_delta_d == 0.0) {
+    d_plus_delta = d;
+
+    if (delta_o.isZero(0.0)) {
+      return true;
+    }
+  }
+
+  // Calculate the householder transformation which is needed for f_d and f_o.
+  AmbientVector v(size_);
+  double beta;
+
+  // NOTE: The explicit template arguments are needed here because
+  // ComputeHouseholderVector is templated and some versions of MSVC
+  // have trouble deducing the type of v automatically.
+  internal::ComputeHouseholderVector<Eigen::Map<const AmbientVector>,
+                                     double,
+                                     AmbientSpaceDimension>(d, &v, &beta);
+
+  if (norm_delta_d != 0.0) {
+    internal::ComputeSphereManifoldPlus(
+        v, beta, d, delta_d, norm_delta_d, &d_plus_delta);
+  }
+
+  // The null space is in the direction of the line, so the tangent space is
+  // perpendicular to the line direction. This is achieved by using the
+  // householder matrix of the direction and allow only movements
+  // perpendicular to e_n.
+  AmbientVector y(size_);
+  y << delta_o, 0;
+  o_plus_delta += internal::ApplyHouseholderVector(y, v, beta);
+
+  return true;
+}
+
+template <int AmbientSpaceDimension>
+bool LineManifold<AmbientSpaceDimension>::PlusJacobian(
+    const double* x_ptr, double* jacobian_ptr) const {
+  Eigen::Map<const AmbientVector> d(x_ptr + size_, size_);
+  Eigen::Map<MatrixPlusJacobian> jacobian(
+      jacobian_ptr, 2 * size_, 2 * (size_ - 1));
+
+  // Clear the Jacobian as only half of the matrix is not zero.
+  jacobian.setZero();
+
+  auto jacobian_d =
+      jacobian
+          .template topLeftCorner<AmbientSpaceDimension, TangentSpaceDimension>(
+              size_, size_ - 1);
+  auto jacobian_o = jacobian.template bottomRightCorner<AmbientSpaceDimension,
+                                                        TangentSpaceDimension>(
+      size_, size_ - 1);
+  internal::ComputeSphereManifoldPlusJacobian(d, &jacobian_d);
+  jacobian_o = jacobian_d;
+  return true;
+}
+
+template <int AmbientSpaceDimension>
+bool LineManifold<AmbientSpaceDimension>::Minus(const double* y_ptr,
+                                                const double* x_ptr,
+                                                double* y_minus_x) const {
+  Eigen::Map<const AmbientVector> y_o(y_ptr, size_);
+  Eigen::Map<const AmbientVector> y_d(y_ptr + size_, size_);
+  Eigen::Map<const AmbientVector> x_o(x_ptr, size_);
+  Eigen::Map<const AmbientVector> x_d(x_ptr + size_, size_);
+
+  Eigen::Map<TangentVector> y_minus_x_o(y_minus_x, size_ - 1);
+  Eigen::Map<TangentVector> y_minus_x_d(y_minus_x + size_ - 1, size_ - 1);
+
+  AmbientVector v(size_);
+  double beta;
+
+  // NOTE: The explicit template arguments are needed here because
+  // ComputeHouseholderVector is templated and some versions of MSVC
+  // have trouble deducing the type of v automatically.
+  internal::ComputeHouseholderVector<Eigen::Map<const AmbientVector>,
+                                     double,
+                                     AmbientSpaceDimension>(x_d, &v, &beta);
+
+  internal::ComputeSphereManifoldMinus(v, beta, x_d, y_d, &y_minus_x_d);
+
+  AmbientVector delta_o = y_o - x_o;
+  const AmbientVector h_delta_o =
+      internal::ApplyHouseholderVector(delta_o, v, beta);
+  y_minus_x_o = h_delta_o.template head<TangentSpaceDimension>(size_ - 1);
+
+  return true;
+}
+
+template <int AmbientSpaceDimension>
+bool LineManifold<AmbientSpaceDimension>::MinusJacobian(
+    const double* x_ptr, double* jacobian_ptr) const {
+  Eigen::Map<const AmbientVector> d(x_ptr + size_, size_);
+  Eigen::Map<MatrixMinusJacobian> jacobian(
+      jacobian_ptr, 2 * (size_ - 1), 2 * size_);
+
+  // Clear the Jacobian as only half of the matrix is not zero.
+  jacobian.setZero();
+
+  auto jacobian_d =
+      jacobian
+          .template topLeftCorner<TangentSpaceDimension, AmbientSpaceDimension>(
+              size_ - 1, size_);
+  auto jacobian_o = jacobian.template bottomRightCorner<TangentSpaceDimension,
+                                                        AmbientSpaceDimension>(
+      size_ - 1, size_);
+  internal::ComputeSphereManifoldMinusJacobian(d, &jacobian_d);
+  jacobian_o = jacobian_d;
+
+  return true;
+}
+
+}  // namespace ceres
+
+// clang-format off
+#include "ceres/internal/reenable_warnings.h"
+// clang-format on
+
+#endif  // CERES_PUBLIC_LINE_MANIFOLD_H_
diff --git a/third_party/ceres/include/ceres/local_parameterization.h b/third_party/ceres/include/ceres/local_parameterization.h
deleted file mode 100644
index ba7579d..0000000
--- a/third_party/ceres/include/ceres/local_parameterization.h
+++ /dev/null
@@ -1,363 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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 Google Inc. 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.
-//
-// Author: keir@google.com (Keir Mierle)
-//         sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_PUBLIC_LOCAL_PARAMETERIZATION_H_
-#define CERES_PUBLIC_LOCAL_PARAMETERIZATION_H_
-
-#include <array>
-#include <memory>
-#include <vector>
-
-#include "ceres/internal/disable_warnings.h"
-#include "ceres/internal/port.h"
-
-namespace ceres {
-
-// Purpose: Sometimes parameter blocks x can overparameterize a problem
-//
-//   min f(x)
-//    x
-//
-// In that case it is desirable to choose a parameterization for the
-// block itself to remove the null directions of the cost. More
-// generally, if x lies on a manifold of a smaller dimension than the
-// ambient space that it is embedded in, then it is numerically and
-// computationally more effective to optimize it using a
-// parameterization that lives in the tangent space of that manifold
-// at each point.
-//
-// For example, a sphere in three dimensions is a 2 dimensional
-// manifold, embedded in a three dimensional space. At each point on
-// the sphere, the plane tangent to it defines a two dimensional
-// tangent space. For a cost function defined on this sphere, given a
-// point x, moving in the direction normal to the sphere at that point
-// is not useful. Thus a better way to do a local optimization is to
-// optimize over two dimensional vector delta in the tangent space at
-// that point and then "move" to the point x + delta, where the move
-// operation involves projecting back onto the sphere. Doing so
-// removes a redundant dimension from the optimization, making it
-// numerically more robust and efficient.
-//
-// More generally we can define a function
-//
-//   x_plus_delta = Plus(x, delta),
-//
-// where x_plus_delta has the same size as x, and delta is of size
-// less than or equal to x. The function Plus, generalizes the
-// definition of vector addition. Thus it satisfies the identify
-//
-//   Plus(x, 0) = x, for all x.
-//
-// A trivial version of Plus is when delta is of the same size as x
-// and
-//
-//   Plus(x, delta) = x + delta
-//
-// A more interesting case if x is two dimensional vector, and the
-// user wishes to hold the first coordinate constant. Then, delta is a
-// scalar and Plus is defined as
-//
-//   Plus(x, delta) = x + [0] * delta
-//                        [1]
-//
-// An example that occurs commonly in Structure from Motion problems
-// is when camera rotations are parameterized using Quaternion. There,
-// it is useful to only make updates orthogonal to that 4-vector
-// defining the quaternion. One way to do this is to let delta be a 3
-// dimensional vector and define Plus to be
-//
-//   Plus(x, delta) = [cos(|delta|), sin(|delta|) delta / |delta|] * x
-//
-// The multiplication between the two 4-vectors on the RHS is the
-// standard quaternion product.
-//
-// Given f and a point x, optimizing f can now be restated as
-//
-//     min  f(Plus(x, delta))
-//    delta
-//
-// Given a solution delta to this problem, the optimal value is then
-// given by
-//
-//   x* = Plus(x, delta)
-//
-// The class LocalParameterization defines the function Plus and its
-// Jacobian which is needed to compute the Jacobian of f w.r.t delta.
-class CERES_EXPORT LocalParameterization {
- public:
-  virtual ~LocalParameterization();
-
-  // Generalization of the addition operation,
-  //
-  //   x_plus_delta = Plus(x, delta)
-  //
-  // with the condition that Plus(x, 0) = x.
-  virtual bool Plus(const double* x,
-                    const double* delta,
-                    double* x_plus_delta) const = 0;
-
-  // The jacobian of Plus(x, delta) w.r.t delta at delta = 0.
-  //
-  // jacobian is a row-major GlobalSize() x LocalSize() matrix.
-  virtual bool ComputeJacobian(const double* x, double* jacobian) const = 0;
-
-  // local_matrix = global_matrix * jacobian
-  //
-  // global_matrix is a num_rows x GlobalSize  row major matrix.
-  // local_matrix is a num_rows x LocalSize row major matrix.
-  // jacobian(x) is the matrix returned by ComputeJacobian at x.
-  //
-  // This is only used by GradientProblem. For most normal uses, it is
-  // okay to use the default implementation.
-  virtual bool MultiplyByJacobian(const double* x,
-                                  const int num_rows,
-                                  const double* global_matrix,
-                                  double* local_matrix) const;
-
-  // Size of x.
-  virtual int GlobalSize() const = 0;
-
-  // Size of delta.
-  virtual int LocalSize() const = 0;
-};
-
-// Some basic parameterizations
-
-// Identity Parameterization: Plus(x, delta) = x + delta
-class CERES_EXPORT IdentityParameterization : public LocalParameterization {
- public:
-  explicit IdentityParameterization(int size);
-  virtual ~IdentityParameterization() {}
-  bool Plus(const double* x,
-            const double* delta,
-            double* x_plus_delta) const override;
-  bool ComputeJacobian(const double* x, double* jacobian) const override;
-  bool MultiplyByJacobian(const double* x,
-                          const int num_cols,
-                          const double* global_matrix,
-                          double* local_matrix) const override;
-  int GlobalSize() const override { return size_; }
-  int LocalSize() const override { return size_; }
-
- private:
-  const int size_;
-};
-
-// Hold a subset of the parameters inside a parameter block constant.
-class CERES_EXPORT SubsetParameterization : public LocalParameterization {
- public:
-  explicit SubsetParameterization(int size,
-                                  const std::vector<int>& constant_parameters);
-  virtual ~SubsetParameterization() {}
-  bool Plus(const double* x,
-            const double* delta,
-            double* x_plus_delta) const override;
-  bool ComputeJacobian(const double* x, double* jacobian) const override;
-  bool MultiplyByJacobian(const double* x,
-                          const int num_cols,
-                          const double* global_matrix,
-                          double* local_matrix) const override;
-  int GlobalSize() const override {
-    return static_cast<int>(constancy_mask_.size());
-  }
-  int LocalSize() const override { return local_size_; }
-
- private:
-  const int local_size_;
-  std::vector<char> constancy_mask_;
-};
-
-// Plus(x, delta) = [cos(|delta|), sin(|delta|) delta / |delta|] * x
-// with * being the quaternion multiplication operator. Here we assume
-// that the first element of the quaternion vector is the real (cos
-// theta) part.
-class CERES_EXPORT QuaternionParameterization : public LocalParameterization {
- public:
-  virtual ~QuaternionParameterization() {}
-  bool Plus(const double* x,
-            const double* delta,
-            double* x_plus_delta) const override;
-  bool ComputeJacobian(const double* x, double* jacobian) const override;
-  int GlobalSize() const override { return 4; }
-  int LocalSize() const override { return 3; }
-};
-
-// Implements the quaternion local parameterization for Eigen's representation
-// of the quaternion. Eigen uses a different internal memory layout for the
-// elements of the quaternion than what is commonly used. Specifically, Eigen
-// stores the elements in memory as [x, y, z, w] where the real part is last
-// whereas it is typically stored first. Note, when creating an Eigen quaternion
-// through the constructor the elements are accepted in w, x, y, z order. Since
-// Ceres operates on parameter blocks which are raw double pointers this
-// difference is important and requires a different parameterization.
-//
-// Plus(x, delta) = [sin(|delta|) delta / |delta|, cos(|delta|)] * x
-// with * being the quaternion multiplication operator.
-class CERES_EXPORT EigenQuaternionParameterization
-    : public ceres::LocalParameterization {
- public:
-  virtual ~EigenQuaternionParameterization() {}
-  bool Plus(const double* x,
-            const double* delta,
-            double* x_plus_delta) const override;
-  bool ComputeJacobian(const double* x, double* jacobian) const override;
-  int GlobalSize() const override { return 4; }
-  int LocalSize() const override { return 3; }
-};
-
-// This provides a parameterization for homogeneous vectors which are commonly
-// used in Structure for Motion problems.  One example where they are used is
-// in representing points whose triangulation is ill-conditioned. Here
-// it is advantageous to use an over-parameterization since homogeneous vectors
-// can represent points at infinity.
-//
-// The plus operator is defined as
-// Plus(x, delta) =
-//    [sin(0.5 * |delta|) * delta / |delta|, cos(0.5 * |delta|)] * x
-// with * defined as an operator which applies the update orthogonal to x to
-// remain on the sphere. We assume that the last element of x is the scalar
-// component. The size of the homogeneous vector is required to be greater than
-// 1.
-class CERES_EXPORT HomogeneousVectorParameterization
-    : public LocalParameterization {
- public:
-  explicit HomogeneousVectorParameterization(int size);
-  virtual ~HomogeneousVectorParameterization() {}
-  bool Plus(const double* x,
-            const double* delta,
-            double* x_plus_delta) const override;
-  bool ComputeJacobian(const double* x, double* jacobian) const override;
-  int GlobalSize() const override { return size_; }
-  int LocalSize() const override { return size_ - 1; }
-
- private:
-  const int size_;
-};
-
-// This provides a parameterization for lines, where the line is
-// over-parameterized by an origin point and a direction vector. So the
-// parameter vector size needs to be two times the ambient space dimension,
-// where the first half is interpreted as the origin point and the second half
-// as the direction.
-//
-// The plus operator for the line direction is the same as for the
-// HomogeneousVectorParameterization. The update of the origin point is
-// perpendicular to the line direction before the update.
-//
-// This local parameterization is a special case of the affine Grassmannian
-// manifold (see https://en.wikipedia.org/wiki/Affine_Grassmannian_(manifold))
-// for the case Graff_1(R^n).
-template <int AmbientSpaceDimension>
-class LineParameterization : public LocalParameterization {
- public:
-  static_assert(AmbientSpaceDimension >= 2,
-                "The ambient space must be at least 2");
-
-  bool Plus(const double* x,
-            const double* delta,
-            double* x_plus_delta) const override;
-  bool ComputeJacobian(const double* x, double* jacobian) const override;
-  int GlobalSize() const override { return 2 * AmbientSpaceDimension; }
-  int LocalSize() const override { return 2 * (AmbientSpaceDimension - 1); }
-};
-
-// Construct a local parameterization by taking the Cartesian product
-// of a number of other local parameterizations. This is useful, when
-// a parameter block is the cartesian product of two or more
-// manifolds. For example the parameters of a camera consist of a
-// rotation and a translation, i.e., SO(3) x R^3.
-//
-// Example usage:
-//
-// ProductParameterization product_param(new QuaterionionParameterization(),
-//                                       new IdentityParameterization(3));
-//
-// is the local parameterization for a rigid transformation, where the
-// rotation is represented using a quaternion.
-class CERES_EXPORT ProductParameterization : public LocalParameterization {
- public:
-  ProductParameterization(const ProductParameterization&) = delete;
-  ProductParameterization& operator=(const ProductParameterization&) = delete;
-  virtual ~ProductParameterization() {}
-  //
-  // NOTE: The constructor takes ownership of the input local
-  // parameterizations.
-  //
-  template <typename... LocalParams>
-  ProductParameterization(LocalParams*... local_params)
-      : local_params_(sizeof...(LocalParams)),
-        local_size_{0},
-        global_size_{0},
-        buffer_size_{0} {
-    constexpr int kNumLocalParams = sizeof...(LocalParams);
-    static_assert(kNumLocalParams >= 2,
-                  "At least two local parameterizations must be specified.");
-
-    using LocalParameterizationPtr = std::unique_ptr<LocalParameterization>;
-
-    // Wrap all raw pointers into std::unique_ptr for exception safety.
-    std::array<LocalParameterizationPtr, kNumLocalParams> local_params_array{
-        LocalParameterizationPtr(local_params)...};
-
-    // Initialize internal state.
-    for (int i = 0; i < kNumLocalParams; ++i) {
-      LocalParameterizationPtr& param = local_params_[i];
-      param = std::move(local_params_array[i]);
-
-      buffer_size_ =
-          std::max(buffer_size_, param->LocalSize() * param->GlobalSize());
-      global_size_ += param->GlobalSize();
-      local_size_ += param->LocalSize();
-    }
-  }
-
-  bool Plus(const double* x,
-            const double* delta,
-            double* x_plus_delta) const override;
-  bool ComputeJacobian(const double* x,
-                       double* jacobian) const override;
-  int GlobalSize() const override { return global_size_; }
-  int LocalSize() const override { return local_size_; }
-
- private:
-  std::vector<std::unique_ptr<LocalParameterization>> local_params_;
-  int local_size_;
-  int global_size_;
-  int buffer_size_;
-};
-
-}  // namespace ceres
-
-// clang-format off
-#include "ceres/internal/reenable_warnings.h"
-#include "ceres/internal/line_parameterization.h"
-
-#endif  // CERES_PUBLIC_LOCAL_PARAMETERIZATION_H_
diff --git a/third_party/ceres/include/ceres/loss_function.h b/third_party/ceres/include/ceres/loss_function.h
index 7aabf7d..b8582f8 100644
--- a/third_party/ceres/include/ceres/loss_function.h
+++ b/third_party/ceres/include/ceres/loss_function.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,7 +35,7 @@
 //
 // For least squares problem where there are no outliers and standard
 // squared loss is expected, it is not necessary to create a loss
-// function; instead passing a NULL to the problem when adding
+// function; instead passing a nullptr to the problem when adding
 // residuals implies a standard squared loss.
 //
 // For least squares problems where the minimization may encounter
@@ -78,6 +78,7 @@
 #include <memory>
 
 #include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 #include "ceres/types.h"
 #include "glog/logging.h"
 
@@ -85,7 +86,7 @@
 
 class CERES_EXPORT LossFunction {
  public:
-  virtual ~LossFunction() {}
+  virtual ~LossFunction();
 
   // For a residual vector with squared 2-norm 'sq_norm', this method
   // is required to fill in the value and derivatives of the loss
@@ -125,10 +126,10 @@
 //
 // At s = 0: rho = [0, 1, 0].
 //
-// It is not normally necessary to use this, as passing NULL for the
+// It is not normally necessary to use this, as passing nullptr for the
 // loss function when building the problem accomplishes the same
 // thing.
-class CERES_EXPORT TrivialLoss : public LossFunction {
+class CERES_EXPORT TrivialLoss final : public LossFunction {
  public:
   void Evaluate(double, double*) const override;
 };
@@ -171,7 +172,7 @@
 //
 // The scaling parameter 'a' corresponds to 'delta' on this page:
 //   http://en.wikipedia.org/wiki/Huber_Loss_Function
-class CERES_EXPORT HuberLoss : public LossFunction {
+class CERES_EXPORT HuberLoss final : public LossFunction {
  public:
   explicit HuberLoss(double a) : a_(a), b_(a * a) {}
   void Evaluate(double, double*) const override;
@@ -187,7 +188,7 @@
 //   rho(s) = 2 (sqrt(1 + s) - 1).
 //
 // At s = 0: rho = [0, 1, -1 / (2 * a^2)].
-class CERES_EXPORT SoftLOneLoss : public LossFunction {
+class CERES_EXPORT SoftLOneLoss final : public LossFunction {
  public:
   explicit SoftLOneLoss(double a) : b_(a * a), c_(1 / b_) {}
   void Evaluate(double, double*) const override;
@@ -204,7 +205,7 @@
 //   rho(s) = log(1 + s).
 //
 // At s = 0: rho = [0, 1, -1 / a^2].
-class CERES_EXPORT CauchyLoss : public LossFunction {
+class CERES_EXPORT CauchyLoss final : public LossFunction {
  public:
   explicit CauchyLoss(double a) : b_(a * a), c_(1 / b_) {}
   void Evaluate(double, double*) const override;
@@ -225,7 +226,7 @@
 //   rho(s) = a atan(s / a).
 //
 // At s = 0: rho = [0, 1, 0].
-class CERES_EXPORT ArctanLoss : public LossFunction {
+class CERES_EXPORT ArctanLoss final : public LossFunction {
  public:
   explicit ArctanLoss(double a) : a_(a), b_(1 / (a * a)) {}
   void Evaluate(double, double*) const override;
@@ -264,7 +265,7 @@
 // concentrated in the range a - b to a + b.
 //
 // At s = 0: rho = [0, ~0, ~0].
-class CERES_EXPORT TolerantLoss : public LossFunction {
+class CERES_EXPORT TolerantLoss final : public LossFunction {
  public:
   explicit TolerantLoss(double a, double b);
   void Evaluate(double, double*) const override;
@@ -283,7 +284,7 @@
 //   rho(s) = a^2 / 3                            for s >  a^2.
 //
 // At s = 0: rho = [0, 1, -2 / a^2]
-class CERES_EXPORT TukeyLoss : public ceres::LossFunction {
+class CERES_EXPORT TukeyLoss final : public ceres::LossFunction {
  public:
   explicit TukeyLoss(double a) : a_squared_(a * a) {}
   void Evaluate(double, double*) const override;
@@ -294,14 +295,14 @@
 
 // Composition of two loss functions.  The error is the result of first
 // evaluating g followed by f to yield the composition f(g(s)).
-// The loss functions must not be NULL.
-class CERES_EXPORT ComposedLoss : public LossFunction {
+// The loss functions must not be nullptr.
+class CERES_EXPORT ComposedLoss final : public LossFunction {
  public:
   explicit ComposedLoss(const LossFunction* f,
                         Ownership ownership_f,
                         const LossFunction* g,
                         Ownership ownership_g);
-  virtual ~ComposedLoss();
+  ~ComposedLoss() override;
   void Evaluate(double, double*) const override;
 
  private:
@@ -322,11 +323,11 @@
 // s -> a * rho'(s)
 // s -> a * rho''(s)
 //
-// Since we treat the a NULL Loss function as the Identity loss
-// function, rho = NULL is a valid input and will result in the input
+// Since we treat the a nullptr Loss function as the Identity loss
+// function, rho = nullptr is a valid input and will result in the input
 // being scaled by a. This provides a simple way of implementing a
 // scaled ResidualBlock.
-class CERES_EXPORT ScaledLoss : public LossFunction {
+class CERES_EXPORT ScaledLoss final : public LossFunction {
  public:
   // Constructs a ScaledLoss wrapping another loss function. Takes
   // ownership of the wrapped loss function or not depending on the
@@ -336,7 +337,7 @@
   ScaledLoss(const ScaledLoss&) = delete;
   void operator=(const ScaledLoss&) = delete;
 
-  virtual ~ScaledLoss() {
+  ~ScaledLoss() override {
     if (ownership_ == DO_NOT_TAKE_OWNERSHIP) {
       rho_.release();
     }
@@ -361,8 +362,8 @@
 // whose scale can be mutated after an optimization problem has been
 // constructed.
 //
-// Since we treat the a NULL Loss function as the Identity loss
-// function, rho = NULL is a valid input.
+// Since we treat the a nullptr Loss function as the Identity loss
+// function, rho = nullptr is a valid input.
 //
 // Example usage
 //
@@ -374,7 +375,8 @@
 //    new AutoDiffCostFunction < UW_Camera_Mapper, 2, 9, 3>(
 //      new UW_Camera_Mapper(feature_x, feature_y));
 //
-//  LossFunctionWrapper* loss_function(new HuberLoss(1.0), TAKE_OWNERSHIP);
+//  LossFunctionWrapper* loss_function = new LossFunctionWrapper(
+//    new HuberLoss(1.0), TAKE_OWNERSHIP);
 //
 //  problem.AddResidualBlock(cost_function, loss_function, parameters);
 //
@@ -387,7 +389,7 @@
 //
 //  Solve(options, &problem, &summary)
 //
-class CERES_EXPORT LossFunctionWrapper : public LossFunction {
+class CERES_EXPORT LossFunctionWrapper final : public LossFunction {
  public:
   LossFunctionWrapper(LossFunction* rho, Ownership ownership)
       : rho_(rho), ownership_(ownership) {}
@@ -395,14 +397,14 @@
   LossFunctionWrapper(const LossFunctionWrapper&) = delete;
   void operator=(const LossFunctionWrapper&) = delete;
 
-  virtual ~LossFunctionWrapper() {
+  ~LossFunctionWrapper() override {
     if (ownership_ == DO_NOT_TAKE_OWNERSHIP) {
       rho_.release();
     }
   }
 
   void Evaluate(double sq_norm, double out[3]) const override {
-    if (rho_.get() == NULL) {
+    if (rho_.get() == nullptr) {
       out[0] = sq_norm;
       out[1] = 1.0;
       out[2] = 0.0;
diff --git a/third_party/ceres/include/ceres/manifold.h b/third_party/ceres/include/ceres/manifold.h
new file mode 100644
index 0000000..9bd6459
--- /dev/null
+++ b/third_party/ceres/include/ceres/manifold.h
@@ -0,0 +1,411 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_PUBLIC_MANIFOLD_H_
+#define CERES_PUBLIC_MANIFOLD_H_
+
+#include <Eigen/Core>
+#include <algorithm>
+#include <array>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
+#include "ceres/types.h"
+#include "glog/logging.h"
+
+namespace ceres {
+
+// In sensor fusion problems, often we have to model quantities that live in
+// spaces known as Manifolds, for example the rotation/orientation of a sensor
+// that is represented by a quaternion.
+//
+// Manifolds are spaces which locally look like Euclidean spaces. More
+// precisely, at each point on the manifold there is a linear space that is
+// tangent to the manifold. It has dimension equal to the intrinsic dimension of
+// the manifold itself, which is less than or equal to the ambient space in
+// which the manifold is embedded.
+//
+// For example, the tangent space to a point on a sphere in three dimensions is
+// the two dimensional plane that is tangent to the sphere at that point. There
+// are two reasons tangent spaces are interesting:
+//
+// 1. They are Eucliean spaces so the usual vector space operations apply there,
+//    which makes numerical operations easy.
+// 2. Movement in the tangent space translate into movements along the manifold.
+//    Movements perpendicular to the tangent space do not translate into
+//    movements on the manifold.
+//
+// Returning to our sphere example, moving in the 2 dimensional plane
+// tangent to the sphere and projecting back onto the sphere will move you away
+// from the point you started from but moving along the normal at the same point
+// and the projecting back onto the sphere brings you back to the point.
+//
+// The Manifold interface defines two operations (and their derivatives)
+// involving the tangent space, allowing filtering and optimization to be
+// performed on said manifold:
+//
+// 1. x_plus_delta = Plus(x, delta)
+// 2. delta = Minus(x_plus_delta, x)
+//
+// "Plus" computes the result of moving along delta in the tangent space at x,
+// and then projecting back onto the manifold that x belongs to. In Differential
+// Geometry this is known as a "Retraction". It is a generalization of vector
+// addition in Euclidean spaces.
+//
+// Given two points on the manifold, "Minus" computes the change delta to x in
+// the tangent space at x, that will take it to x_plus_delta.
+//
+// Let us now consider two examples.
+//
+// The Euclidean space R^n is the simplest example of a manifold. It has
+// dimension n (and so does its tangent space) and Plus and Minus are the
+// familiar vector sum and difference operations.
+//
+//  Plus(x, delta) = x + delta = y,
+//  Minus(y, x) = y - x = delta.
+//
+// A more interesting case is SO(3), the special orthogonal group in three
+// dimensions - the space of 3x3 rotation matrices. SO(3) is a three dimensional
+// manifold embedded in R^9 or R^(3x3). So points on SO(3) are represented using
+// 9 dimensional vectors or 3x3 matrices, and points in its tangent spaces are
+// represented by 3 dimensional vectors.
+//
+// Defining Plus and Minus are defined in terms of the matrix Exp and Log
+// operations as follows:
+//
+// Let Exp(p, q, r) = [cos(theta) + cp^2, -sr + cpq        ,  sq + cpr        ]
+//                    [sr + cpq         , cos(theta) + cq^2, -sp + cqr        ]
+//                    [-sq + cpr        , sp + cqr         , cos(theta) + cr^2]
+//
+// where: theta = sqrt(p^2 + q^2 + r^2)
+//            s = sinc(theta)
+//            c = (1 - cos(theta))/theta^2
+//
+// and Log(x) = 1/(2 sinc(theta))[x_32 - x_23, x_13 - x_31, x_21 - x_12]
+//
+// where: theta = acos((Trace(x) - 1)/2)
+//
+// Then,
+//
+// Plus(x, delta) = x Exp(delta)
+// Minus(y, x) = Log(x^T y)
+//
+// For Plus and Minus to be mathematically consistent, the following identities
+// must be satisfied at all points x on the manifold:
+//
+// 1.  Plus(x, 0) = x.
+// 2.  For all y, Plus(x, Minus(y, x)) = y.
+// 3.  For all delta, Minus(Plus(x, delta), x) = delta.
+// 4.  For all delta_1, delta_2
+//    |Minus(Plus(x, delta_1), Plus(x, delta_2)) <= |delta_1 - delta_2|
+//
+// Briefly:
+// (1) Ensures that the tangent space is "centered" at x, and the zero vector is
+//     the identity element.
+// (2) Ensures that any y can be reached from x.
+// (3) Ensures that Plus is an injective (one-to-one) map.
+// (4) Allows us to define a metric on the manifold.
+//
+// Additionally we require that Plus and Minus be sufficiently smooth. In
+// particular they need to be differentiable everywhere on the manifold.
+//
+// For more details, please see
+//
+// "Integrating Generic Sensor Fusion Algorithms with Sound State
+// Representations through Encapsulation of Manifolds"
+// By C. Hertzberg, R. Wagner, U. Frese and L. Schroder
+// https://arxiv.org/pdf/1107.1119.pdf
+class CERES_EXPORT Manifold {
+ public:
+  virtual ~Manifold();
+
+  // Dimension of the ambient space in which the manifold is embedded.
+  virtual int AmbientSize() const = 0;
+
+  // Dimension of the manifold/tangent space.
+  virtual int TangentSize() const = 0;
+
+  //   x_plus_delta = Plus(x, delta),
+  //
+  // A generalization of vector addition in Euclidean space, Plus computes the
+  // result of moving along delta in the tangent space at x, and then projecting
+  // back onto the manifold that x belongs to.
+  //
+  // x and x_plus_delta are AmbientSize() vectors.
+  // delta is a TangentSize() vector.
+  //
+  // Return value indicates if the operation was successful or not.
+  virtual bool Plus(const double* x,
+                    const double* delta,
+                    double* x_plus_delta) const = 0;
+
+  // Compute the derivative of Plus(x, delta) w.r.t delta at delta = 0, i.e.
+  //
+  // (D_2 Plus)(x, 0)
+  //
+  // jacobian is a row-major AmbientSize() x TangentSize() matrix.
+  //
+  // Return value indicates whether the operation was successful or not.
+  virtual bool PlusJacobian(const double* x, double* jacobian) const = 0;
+
+  // tangent_matrix = ambient_matrix * (D_2 Plus)(x, 0)
+  //
+  // ambient_matrix is a row-major num_rows x AmbientSize() matrix.
+  // tangent_matrix is a row-major num_rows x TangentSize() matrix.
+  //
+  // Return value indicates whether the operation was successful or not.
+  //
+  // This function is only used by the GradientProblemSolver, where the
+  // dimension of the parameter block can be large and it may be more efficient
+  // to compute this product directly rather than first evaluating the Jacobian
+  // into a matrix and then doing a matrix vector product.
+  //
+  // Because this is not an often used function, we provide a default
+  // implementation for convenience. If performance becomes an issue then the
+  // user should consider implementing a specialization.
+  virtual bool RightMultiplyByPlusJacobian(const double* x,
+                                           const int num_rows,
+                                           const double* ambient_matrix,
+                                           double* tangent_matrix) const;
+
+  // y_minus_x = Minus(y, x)
+  //
+  // Given two points on the manifold, Minus computes the change to x in the
+  // tangent space at x, that will take it to y.
+  //
+  // x and y are AmbientSize() vectors.
+  // y_minus_x is a TangentSize() vector.
+  //
+  // Return value indicates if the operation was successful or not.
+  virtual bool Minus(const double* y,
+                     const double* x,
+                     double* y_minus_x) const = 0;
+
+  // Compute the derivative of Minus(y, x) w.r.t y at y = x, i.e
+  //
+  //   (D_1 Minus) (x, x)
+  //
+  // Jacobian is a row-major TangentSize() x AmbientSize() matrix.
+  //
+  // Return value indicates whether the operation was successful or not.
+  virtual bool MinusJacobian(const double* x, double* jacobian) const = 0;
+};
+
+// The Euclidean manifold is another name for the ordinary vector space R^size,
+// where the plus and minus operations are the usual vector addition and
+// subtraction:
+//   Plus(x, delta) = x + delta
+//   Minus(y, x) = y - x.
+//
+// The class works with dynamic and static ambient space dimensions. If the
+// ambient space dimensions is know at compile time use
+//
+//    EuclideanManifold<3> manifold;
+//
+// If the ambient space dimensions is not known at compile time the template
+// parameter needs to be set to ceres::DYNAMIC and the actual dimension needs
+// to be provided as a constructor argument:
+//
+//    EuclideanManifold<ceres::DYNAMIC> manifold(ambient_dim);
+template <int Size>
+class EuclideanManifold final : public Manifold {
+ public:
+  static_assert(Size == ceres::DYNAMIC || Size >= 0,
+                "The size of the manifold needs to be non-negative.");
+  static_assert(ceres::DYNAMIC == Eigen::Dynamic,
+                "ceres::DYNAMIC needs to be the same as Eigen::Dynamic.");
+
+  EuclideanManifold() : size_{Size} {
+    static_assert(
+        Size != ceres::DYNAMIC,
+        "The size is set to dynamic. Please call the constructor with a size.");
+  }
+
+  explicit EuclideanManifold(int size) : size_(size) {
+    if (Size != ceres::DYNAMIC) {
+      CHECK_EQ(Size, size)
+          << "Specified size by template parameter differs from the supplied "
+             "one.";
+    } else {
+      CHECK_GE(size_, 0)
+          << "The size of the manifold needs to be non-negative.";
+    }
+  }
+
+  int AmbientSize() const override { return size_; }
+  int TangentSize() const override { return size_; }
+
+  bool Plus(const double* x_ptr,
+            const double* delta_ptr,
+            double* x_plus_delta_ptr) const override {
+    Eigen::Map<const AmbientVector> x(x_ptr, size_);
+    Eigen::Map<const AmbientVector> delta(delta_ptr, size_);
+    Eigen::Map<AmbientVector> x_plus_delta(x_plus_delta_ptr, size_);
+    x_plus_delta = x + delta;
+    return true;
+  }
+
+  bool PlusJacobian(const double* x_ptr, double* jacobian_ptr) const override {
+    Eigen::Map<MatrixJacobian> jacobian(jacobian_ptr, size_, size_);
+    jacobian.setIdentity();
+    return true;
+  }
+
+  bool RightMultiplyByPlusJacobian(const double* x,
+                                   const int num_rows,
+                                   const double* ambient_matrix,
+                                   double* tangent_matrix) const override {
+    std::copy_n(ambient_matrix, num_rows * size_, tangent_matrix);
+    return true;
+  }
+
+  bool Minus(const double* y_ptr,
+             const double* x_ptr,
+             double* y_minus_x_ptr) const override {
+    Eigen::Map<const AmbientVector> x(x_ptr, size_);
+    Eigen::Map<const AmbientVector> y(y_ptr, size_);
+    Eigen::Map<AmbientVector> y_minus_x(y_minus_x_ptr, size_);
+    y_minus_x = y - x;
+    return true;
+  }
+
+  bool MinusJacobian(const double* x_ptr, double* jacobian_ptr) const override {
+    Eigen::Map<MatrixJacobian> jacobian(jacobian_ptr, size_, size_);
+    jacobian.setIdentity();
+    return true;
+  }
+
+ private:
+  static constexpr bool IsDynamic = (Size == ceres::DYNAMIC);
+  using AmbientVector = Eigen::Matrix<double, Size, 1>;
+  using MatrixJacobian = Eigen::Matrix<double, Size, Size, Eigen::RowMajor>;
+
+  int size_{};
+};
+
+// Hold a subset of the parameters inside a parameter block constant.
+class CERES_EXPORT SubsetManifold final : public Manifold {
+ public:
+  SubsetManifold(int size, const std::vector<int>& constant_parameters);
+  int AmbientSize() const override;
+  int TangentSize() const override;
+
+  bool Plus(const double* x,
+            const double* delta,
+            double* x_plus_delta) const override;
+  bool PlusJacobian(const double* x, double* jacobian) const override;
+  bool RightMultiplyByPlusJacobian(const double* x,
+                                   const int num_rows,
+                                   const double* ambient_matrix,
+                                   double* tangent_matrix) const override;
+  bool Minus(const double* y,
+             const double* x,
+             double* y_minus_x) const override;
+  bool MinusJacobian(const double* x, double* jacobian) const override;
+
+ private:
+  const int tangent_size_ = 0;
+  std::vector<bool> constancy_mask_;
+};
+
+// Implements the manifold for a Hamilton quaternion as defined in
+// https://en.wikipedia.org/wiki/Quaternion. Quaternions are represented as
+// unit norm 4-vectors, i.e.
+//
+// q = [q0; q1; q2; q3], |q| = 1
+//
+// is the ambient space representation.
+//
+//   q0  scalar part.
+//   q1  coefficient of i.
+//   q2  coefficient of j.
+//   q3  coefficient of k.
+//
+// where: i*i = j*j = k*k = -1 and i*j = k, j*k = i, k*i = j.
+//
+// The tangent space is R^3, which relates to the ambient space through the
+// Plus and Minus operations defined as:
+//
+// Plus(x, delta) = [cos(|delta|); sin(|delta|) * delta / |delta|] * x
+//    Minus(y, x) = to_delta(y * x^{-1})
+//
+// where "*" is the quaternion product and because q is a unit quaternion
+// (|q|=1), q^-1 = [q0; -q1; -q2; -q3]
+//
+// and to_delta( [q0; u_{3x1}] ) = u / |u| * atan2(|u|, q0)
+class CERES_EXPORT QuaternionManifold final : public Manifold {
+ public:
+  int AmbientSize() const override { return 4; }
+  int TangentSize() const override { return 3; }
+
+  bool Plus(const double* x,
+            const double* delta,
+            double* x_plus_delta) const override;
+  bool PlusJacobian(const double* x, double* jacobian) const override;
+  bool Minus(const double* y,
+             const double* x,
+             double* y_minus_x) const override;
+  bool MinusJacobian(const double* x, double* jacobian) const override;
+};
+
+// Implements the quaternion manifold for Eigen's representation of the
+// Hamilton quaternion. Geometrically it is exactly the same as the
+// QuaternionManifold defined above. However, Eigen uses a different internal
+// memory layout for the elements of the quaternion than what is commonly
+// used. It stores the quaternion in memory as [q1, q2, q3, q0] or
+// [x, y, z, w] where the real (scalar) part is last.
+//
+// Since Ceres operates on parameter blocks which are raw double pointers this
+// difference is important and requires a different manifold.
+class CERES_EXPORT EigenQuaternionManifold final : public Manifold {
+ public:
+  int AmbientSize() const override { return 4; }
+  int TangentSize() const override { return 3; }
+
+  bool Plus(const double* x,
+            const double* delta,
+            double* x_plus_delta) const override;
+  bool PlusJacobian(const double* x, double* jacobian) const override;
+  bool Minus(const double* y,
+             const double* x,
+             double* y_minus_x) const override;
+  bool MinusJacobian(const double* x, double* jacobian) const override;
+};
+
+}  // namespace ceres
+
+// clang-format off
+#include "ceres/internal/reenable_warnings.h"
+// clang-format on
+
+#endif  // CERES_PUBLIC_MANIFOLD_H_
diff --git a/third_party/ceres/include/ceres/manifold_test_utils.h b/third_party/ceres/include/ceres/manifold_test_utils.h
new file mode 100644
index 0000000..3e61457
--- /dev/null
+++ b/third_party/ceres/include/ceres/manifold_test_utils.h
@@ -0,0 +1,345 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include <cmath>
+#include <limits>
+#include <memory>
+
+#include "ceres/dynamic_numeric_diff_cost_function.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/manifold.h"
+#include "ceres/numeric_diff_options.h"
+#include "ceres/types.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace ceres {
+
+// Matchers and macros to simplify testing of custom Manifold objects using the
+// gtest testing framework.
+//
+// Testing a Manifold has two parts.
+//
+// 1. Checking that Manifold::Plus() and Manifold::Minus() are correctly
+//    defined. This requires per manifold tests.
+//
+// 2. The other methods of the manifold have mathematical properties that make
+//    them compatible with Plus() and Minus(), as described in [1].
+//
+// To verify these general requirements for a custom Manifold, use the
+// EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD() macro from within a gtest test. Note
+// that additional domain-specific tests may also be prudent, e.g to verify the
+// behaviour of a Quaternion Manifold about pi.
+//
+// [1] "Integrating Generic Sensor Fusion Algorithms with Sound State
+//     Representations through Encapsulation of Manifolds", C. Hertzberg,
+//     R. Wagner, U. Frese and L. Schroder, https://arxiv.org/pdf/1107.1119.pdf
+
+// Verifies the general requirements for a custom Manifold are satisfied to
+// within the specified (numerical) tolerance.
+//
+// Example usage for a custom Manifold: ExampleManifold:
+//
+//    TEST(ExampleManifold, ManifoldInvariantsHold) {
+//      constexpr double kTolerance = 1.0e-9;
+//      ExampleManifold manifold;
+//      ceres::Vector x = ceres::Vector::Zero(manifold.AmbientSize());
+//      ceres::Vector y = ceres::Vector::Zero(manifold.AmbientSize());
+//      ceres::Vector delta = ceres::Vector::Zero(manifold.TangentSize());
+//      EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
+//    }
+#define EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, tolerance) \
+  ::ceres::Vector zero_tangent =                                               \
+      ::ceres::Vector::Zero(manifold.TangentSize());                           \
+  EXPECT_THAT(manifold, ::ceres::XPlusZeroIsXAt(x, tolerance));                \
+  EXPECT_THAT(manifold, ::ceres::XMinusXIsZeroAt(x, tolerance));               \
+  EXPECT_THAT(manifold, ::ceres::MinusPlusIsIdentityAt(x, delta, tolerance));  \
+  EXPECT_THAT(manifold,                                                        \
+              ::ceres::MinusPlusIsIdentityAt(x, zero_tangent, tolerance));     \
+  EXPECT_THAT(manifold, ::ceres::PlusMinusIsIdentityAt(x, x, tolerance));      \
+  EXPECT_THAT(manifold, ::ceres::PlusMinusIsIdentityAt(x, y, tolerance));      \
+  EXPECT_THAT(manifold, ::ceres::HasCorrectPlusJacobianAt(x, tolerance));      \
+  EXPECT_THAT(manifold, ::ceres::HasCorrectMinusJacobianAt(x, tolerance));     \
+  EXPECT_THAT(manifold, ::ceres::MinusPlusJacobianIsIdentityAt(x, tolerance)); \
+  EXPECT_THAT(manifold,                                                        \
+              ::ceres::HasCorrectRightMultiplyByPlusJacobianAt(x, tolerance));
+
+// Checks that the invariant Plus(x, 0) == x holds.
+MATCHER_P2(XPlusZeroIsXAt, x, tolerance, "") {
+  const int ambient_size = arg.AmbientSize();
+  const int tangent_size = arg.TangentSize();
+
+  Vector actual = Vector::Zero(ambient_size);
+  Vector zero = Vector::Zero(tangent_size);
+  EXPECT_TRUE(arg.Plus(x.data(), zero.data(), actual.data()));
+  const double n = (actual - Vector{x}).norm();
+  const double d = x.norm();
+  const double diffnorm = (d == 0.0) ? n : (n / d);
+  if (diffnorm > tolerance) {
+    *result_listener << "\nexpected (x): " << x.transpose()
+                     << "\nactual: " << actual.transpose()
+                     << "\ndiffnorm: " << diffnorm;
+    return false;
+  }
+  return true;
+}
+
+// Checks that the invariant Minus(x, x) == 0 holds.
+MATCHER_P2(XMinusXIsZeroAt, x, tolerance, "") {
+  const int tangent_size = arg.TangentSize();
+  Vector actual = Vector::Zero(tangent_size);
+  EXPECT_TRUE(arg.Minus(x.data(), x.data(), actual.data()));
+  const double diffnorm = actual.norm();
+  if (diffnorm > tolerance) {
+    *result_listener << "\nx: " << x.transpose()  //
+                     << "\nexpected: 0 0 0"
+                     << "\nactual: " << actual.transpose()
+                     << "\ndiffnorm: " << diffnorm;
+    return false;
+  }
+  return true;
+}
+
+// Helper struct to curry Plus(x, .) so that it can be numerically
+// differentiated.
+struct PlusFunctor {
+  PlusFunctor(const Manifold& manifold, const double* x)
+      : manifold(manifold), x(x) {}
+  bool operator()(double const* const* parameters, double* x_plus_delta) const {
+    return manifold.Plus(x, parameters[0], x_plus_delta);
+  }
+
+  const Manifold& manifold;
+  const double* x;
+};
+
+// Checks that the output of PlusJacobian matches the one obtained by
+// numerically evaluating D_2 Plus(x,0).
+MATCHER_P2(HasCorrectPlusJacobianAt, x, tolerance, "") {
+  const int ambient_size = arg.AmbientSize();
+  const int tangent_size = arg.TangentSize();
+
+  NumericDiffOptions options;
+  options.ridders_relative_initial_step_size = 1e-4;
+
+  DynamicNumericDiffCostFunction<PlusFunctor, RIDDERS> cost_function(
+      new PlusFunctor(arg, x.data()), TAKE_OWNERSHIP, options);
+  cost_function.AddParameterBlock(tangent_size);
+  cost_function.SetNumResiduals(ambient_size);
+
+  Vector zero = Vector::Zero(tangent_size);
+  double* parameters[1] = {zero.data()};
+
+  Vector x_plus_zero = Vector::Zero(ambient_size);
+  Matrix expected = Matrix::Zero(ambient_size, tangent_size);
+  double* jacobians[1] = {expected.data()};
+
+  EXPECT_TRUE(
+      cost_function.Evaluate(parameters, x_plus_zero.data(), jacobians));
+
+  Matrix actual = Matrix::Random(ambient_size, tangent_size);
+  EXPECT_TRUE(arg.PlusJacobian(x.data(), actual.data()));
+
+  const double n = (actual - expected).norm();
+  const double d = expected.norm();
+  const double diffnorm = (d == 0.0) ? n : n / d;
+  if (diffnorm > tolerance) {
+    *result_listener << "\nx: " << x.transpose() << "\nexpected: \n"
+                     << expected << "\nactual:\n"
+                     << actual << "\ndiff:\n"
+                     << expected - actual << "\ndiffnorm : " << diffnorm;
+    return false;
+  }
+  return true;
+}
+
+// Checks that the invariant Minus(Plus(x, delta), x) == delta holds.
+MATCHER_P3(MinusPlusIsIdentityAt, x, delta, tolerance, "") {
+  const int ambient_size = arg.AmbientSize();
+  const int tangent_size = arg.TangentSize();
+  Vector x_plus_delta = Vector::Zero(ambient_size);
+  EXPECT_TRUE(arg.Plus(x.data(), delta.data(), x_plus_delta.data()));
+  Vector actual = Vector::Zero(tangent_size);
+  EXPECT_TRUE(arg.Minus(x_plus_delta.data(), x.data(), actual.data()));
+
+  const double n = (actual - Vector{delta}).norm();
+  const double d = delta.norm();
+  const double diffnorm = (d == 0.0) ? n : (n / d);
+  if (diffnorm > tolerance) {
+    *result_listener << "\nx: " << x.transpose()
+                     << "\nexpected: " << delta.transpose()
+                     << "\nactual:" << actual.transpose()
+                     << "\ndiff:" << (delta - actual).transpose()
+                     << "\ndiffnorm: " << diffnorm;
+    return false;
+  }
+  return true;
+}
+
+// Checks that the invariant Plus(Minus(y, x), x) == y holds.
+MATCHER_P3(PlusMinusIsIdentityAt, x, y, tolerance, "") {
+  const int ambient_size = arg.AmbientSize();
+  const int tangent_size = arg.TangentSize();
+
+  Vector y_minus_x = Vector::Zero(tangent_size);
+  EXPECT_TRUE(arg.Minus(y.data(), x.data(), y_minus_x.data()));
+
+  Vector actual = Vector::Zero(ambient_size);
+  EXPECT_TRUE(arg.Plus(x.data(), y_minus_x.data(), actual.data()));
+
+  const double n = (actual - Vector{y}).norm();
+  const double d = y.norm();
+  const double diffnorm = (d == 0.0) ? n : (n / d);
+  if (diffnorm > tolerance) {
+    *result_listener << "\nx: " << x.transpose()
+                     << "\nexpected: " << y.transpose()
+                     << "\nactual:" << actual.transpose()
+                     << "\ndiff:" << (y - actual).transpose()
+                     << "\ndiffnorm: " << diffnorm;
+    return false;
+  }
+  return true;
+}
+
+// Helper struct to curry Minus(., x) so that it can be numerically
+// differentiated.
+struct MinusFunctor {
+  MinusFunctor(const Manifold& manifold, const double* x)
+      : manifold(manifold), x(x) {}
+  bool operator()(double const* const* parameters, double* y_minus_x) const {
+    return manifold.Minus(parameters[0], x, y_minus_x);
+  }
+
+  const Manifold& manifold;
+  const double* x;
+};
+
+// Checks that the output of MinusJacobian matches the one obtained by
+// numerically evaluating D_1 Minus(x,x).
+MATCHER_P2(HasCorrectMinusJacobianAt, x, tolerance, "") {
+  const int ambient_size = arg.AmbientSize();
+  const int tangent_size = arg.TangentSize();
+
+  Vector y = x;
+  Vector y_minus_x = Vector::Zero(tangent_size);
+
+  NumericDiffOptions options;
+  options.ridders_relative_initial_step_size = 1e-4;
+  DynamicNumericDiffCostFunction<MinusFunctor, RIDDERS> cost_function(
+      new MinusFunctor(arg, x.data()), TAKE_OWNERSHIP, options);
+  cost_function.AddParameterBlock(ambient_size);
+  cost_function.SetNumResiduals(tangent_size);
+
+  double* parameters[1] = {y.data()};
+
+  Matrix expected = Matrix::Zero(tangent_size, ambient_size);
+  double* jacobians[1] = {expected.data()};
+
+  EXPECT_TRUE(cost_function.Evaluate(parameters, y_minus_x.data(), jacobians));
+
+  Matrix actual = Matrix::Random(tangent_size, ambient_size);
+  EXPECT_TRUE(arg.MinusJacobian(x.data(), actual.data()));
+
+  const double n = (actual - expected).norm();
+  const double d = expected.norm();
+  const double diffnorm = (d == 0.0) ? n : (n / d);
+  if (diffnorm > tolerance) {
+    *result_listener << "\nx: " << x.transpose() << "\nexpected: \n"
+                     << expected << "\nactual:\n"
+                     << actual << "\ndiff:\n"
+                     << expected - actual << "\ndiffnorm: " << diffnorm;
+    return false;
+  }
+  return true;
+}
+
+// Checks that D_delta Minus(Plus(x, delta), x) at delta = 0 is an identity
+// matrix.
+MATCHER_P2(MinusPlusJacobianIsIdentityAt, x, tolerance, "") {
+  const int ambient_size = arg.AmbientSize();
+  const int tangent_size = arg.TangentSize();
+
+  Matrix plus_jacobian(ambient_size, tangent_size);
+  EXPECT_TRUE(arg.PlusJacobian(x.data(), plus_jacobian.data()));
+  Matrix minus_jacobian(tangent_size, ambient_size);
+  EXPECT_TRUE(arg.MinusJacobian(x.data(), minus_jacobian.data()));
+
+  const Matrix actual = minus_jacobian * plus_jacobian;
+  const Matrix expected = Matrix::Identity(tangent_size, tangent_size);
+
+  const double n = (actual - expected).norm();
+  const double d = expected.norm();
+  const double diffnorm = n / d;
+  if (diffnorm > tolerance) {
+    *result_listener << "\nx: " << x.transpose() << "\nexpected: \n"
+                     << expected << "\nactual:\n"
+                     << actual << "\ndiff:\n"
+                     << expected - actual << "\ndiffnorm: " << diffnorm;
+
+    return false;
+  }
+  return true;
+}
+
+// Verify that the output of RightMultiplyByPlusJacobian is ambient_matrix *
+// plus_jacobian.
+MATCHER_P2(HasCorrectRightMultiplyByPlusJacobianAt, x, tolerance, "") {
+  const int ambient_size = arg.AmbientSize();
+  const int tangent_size = arg.TangentSize();
+
+  constexpr int kMinNumRows = 0;
+  constexpr int kMaxNumRows = 3;
+  for (int num_rows = kMinNumRows; num_rows <= kMaxNumRows; ++num_rows) {
+    Matrix plus_jacobian = Matrix::Random(ambient_size, tangent_size);
+    EXPECT_TRUE(arg.PlusJacobian(x.data(), plus_jacobian.data()));
+
+    Matrix ambient_matrix = Matrix::Random(num_rows, ambient_size);
+    Matrix expected = ambient_matrix * plus_jacobian;
+
+    Matrix actual = Matrix::Random(num_rows, tangent_size);
+    EXPECT_TRUE(arg.RightMultiplyByPlusJacobian(
+        x.data(), num_rows, ambient_matrix.data(), actual.data()));
+    const double n = (actual - expected).norm();
+    const double d = expected.norm();
+    const double diffnorm = (d == 0.0) ? n : (n / d);
+    if (diffnorm > tolerance) {
+      *result_listener << "\nx: " << x.transpose() << "\nambient_matrix : \n"
+                       << ambient_matrix << "\nplus_jacobian : \n"
+                       << plus_jacobian << "\nexpected: \n"
+                       << expected << "\nactual:\n"
+                       << actual << "\ndiff:\n"
+                       << expected - actual << "\ndiffnorm : " << diffnorm;
+      return false;
+    }
+  }
+  return true;
+}
+
+}  // namespace ceres
diff --git a/third_party/ceres/include/ceres/normal_prior.h b/third_party/ceres/include/ceres/normal_prior.h
index 14ab379..5a26e01 100644
--- a/third_party/ceres/include/ceres/normal_prior.h
+++ b/third_party/ceres/include/ceres/normal_prior.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -57,11 +57,11 @@
 // which would be the case if the covariance matrix S is rank
 // deficient.
 
-class CERES_EXPORT NormalPrior : public CostFunction {
+class CERES_EXPORT NormalPrior final : public CostFunction {
  public:
   // Check that the number of rows in the vector b are the same as the
   // number of columns in the matrix A, crash otherwise.
-  NormalPrior(const Matrix& A, const Vector& b);
+  NormalPrior(const Matrix& A, Vector b);
   bool Evaluate(double const* const* parameters,
                 double* residuals,
                 double** jacobians) const override;
diff --git a/third_party/ceres/include/ceres/numeric_diff_cost_function.h b/third_party/ceres/include/ceres/numeric_diff_cost_function.h
index cf7971c..f2a377b 100644
--- a/third_party/ceres/include/ceres/numeric_diff_cost_function.h
+++ b/third_party/ceres/include/ceres/numeric_diff_cost_function.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2024 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -149,9 +149,8 @@
 // The numerically differentiated version of a cost function for a cost function
 // can be constructed as follows:
 //
-//   CostFunction* cost_function
-//       = new NumericDiffCostFunction<MyCostFunction, CENTRAL, 1, 4, 8>(
-//           new MyCostFunction(...), TAKE_OWNERSHIP);
+//   auto* cost_function
+//       = new NumericDiffCostFunction<MyCostFunction, CENTRAL, 1, 4, 8>();
 //
 // where MyCostFunction has 1 residual and 2 parameter blocks with sizes 4 and 8
 // respectively. Look at the tests for a more detailed example.
@@ -163,6 +162,7 @@
 
 #include <array>
 #include <memory>
+#include <type_traits>
 
 #include "Eigen/Dense"
 #include "ceres/cost_function.h"
@@ -171,31 +171,55 @@
 #include "ceres/numeric_diff_options.h"
 #include "ceres/sized_cost_function.h"
 #include "ceres/types.h"
-#include "glog/logging.h"
 
 namespace ceres {
 
 template <typename CostFunctor,
-          NumericDiffMethodType method = CENTRAL,
+          NumericDiffMethodType kMethod = CENTRAL,
           int kNumResiduals = 0,  // Number of residuals, or ceres::DYNAMIC
           int... Ns>              // Parameters dimensions for each block.
-class NumericDiffCostFunction : public SizedCostFunction<kNumResiduals, Ns...> {
+class NumericDiffCostFunction final
+    : public SizedCostFunction<kNumResiduals, Ns...> {
  public:
-  NumericDiffCostFunction(
+  explicit NumericDiffCostFunction(
       CostFunctor* functor,
       Ownership ownership = TAKE_OWNERSHIP,
       int num_residuals = kNumResiduals,
       const NumericDiffOptions& options = NumericDiffOptions())
-      : functor_(functor), ownership_(ownership), options_(options) {
-    if (kNumResiduals == DYNAMIC) {
-      SizedCostFunction<kNumResiduals, Ns...>::set_num_residuals(num_residuals);
-    }
-  }
+      : NumericDiffCostFunction{std::unique_ptr<CostFunctor>{functor},
+                                ownership,
+                                num_residuals,
+                                options} {}
 
-  explicit NumericDiffCostFunction(NumericDiffCostFunction&& other)
-      : functor_(std::move(other.functor_)), ownership_(other.ownership_) {}
+  explicit NumericDiffCostFunction(
+      std::unique_ptr<CostFunctor> functor,
+      int num_residuals = kNumResiduals,
+      const NumericDiffOptions& options = NumericDiffOptions())
+      : NumericDiffCostFunction{
+            std::move(functor), TAKE_OWNERSHIP, num_residuals, options} {}
 
-  virtual ~NumericDiffCostFunction() {
+  // Constructs the CostFunctor on the heap and takes the ownership.
+  // Invocable only if the number of residuals is known at compile-time.
+  template <class... Args,
+            bool kIsDynamic = kNumResiduals == DYNAMIC,
+            std::enable_if_t<!kIsDynamic &&
+                             std::is_constructible_v<CostFunctor, Args&&...>>* =
+                nullptr>
+  explicit NumericDiffCostFunction(Args&&... args)
+      // NOTE We explicitly use direct initialization using parentheses instead
+      // of uniform initialization using braces to avoid narrowing conversion
+      // warnings.
+      : NumericDiffCostFunction{
+            std::make_unique<CostFunctor>(std::forward<Args>(args)...),
+            TAKE_OWNERSHIP} {}
+
+  NumericDiffCostFunction(NumericDiffCostFunction&& other) noexcept = default;
+  NumericDiffCostFunction& operator=(NumericDiffCostFunction&& other) noexcept =
+      default;
+  NumericDiffCostFunction(const NumericDiffCostFunction&) = delete;
+  NumericDiffCostFunction& operator=(const NumericDiffCostFunction&) = delete;
+
+  ~NumericDiffCostFunction() override {
     if (ownership_ != TAKE_OWNERSHIP) {
       functor_.release();
     }
@@ -219,7 +243,7 @@
       return false;
     }
 
-    if (jacobians == NULL) {
+    if (jacobians == nullptr) {
       return true;
     }
 
@@ -235,7 +259,7 @@
     }
 
     internal::EvaluateJacobianForParameterBlocks<ParameterDims>::
-        template Apply<method, kNumResiduals>(
+        template Apply<kMethod, kNumResiduals>(
             functor_.get(),
             residuals,
             options_,
@@ -246,7 +270,19 @@
     return true;
   }
 
+  const CostFunctor& functor() const { return *functor_; }
+
  private:
+  explicit NumericDiffCostFunction(std::unique_ptr<CostFunctor> functor,
+                                   Ownership ownership,
+                                   [[maybe_unused]] int num_residuals,
+                                   const NumericDiffOptions& options)
+      : functor_(std::move(functor)), ownership_(ownership), options_(options) {
+    if constexpr (kNumResiduals == DYNAMIC) {
+      SizedCostFunction<kNumResiduals, Ns...>::set_num_residuals(num_residuals);
+    }
+  }
+
   std::unique_ptr<CostFunctor> functor_;
   Ownership ownership_;
   NumericDiffOptions options_;
diff --git a/third_party/ceres/include/ceres/numeric_diff_first_order_function.h b/third_party/ceres/include/ceres/numeric_diff_first_order_function.h
new file mode 100644
index 0000000..525f197
--- /dev/null
+++ b/third_party/ceres/include/ceres/numeric_diff_first_order_function.h
@@ -0,0 +1,271 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_PUBLIC_NUMERIC_DIFF_FIRST_ORDER_FUNCTION_H_
+#define CERES_PUBLIC_NUMERIC_DIFF_FIRST_ORDER_FUNCTION_H_
+
+#include <algorithm>
+#include <memory>
+#include <type_traits>
+#include <utility>
+
+#include "ceres/first_order_function.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/fixed_array.h"
+#include "ceres/internal/numeric_diff.h"
+#include "ceres/internal/parameter_dims.h"
+#include "ceres/internal/variadic_evaluate.h"
+#include "ceres/numeric_diff_options.h"
+#include "ceres/types.h"
+#include "glog/logging.h"
+
+namespace ceres {
+
+// Creates FirstOrderFunctions as needed by the GradientProblem
+// framework, with gradients computed via numeric differentiation. For
+// more information on numeric differentiation, see the wikipedia
+// article at https://en.wikipedia.org/wiki/Numerical_differentiation
+//
+// To get an numerically differentiated cost function, you must define
+// a class with an operator() (a functor) that computes the cost.
+//
+// The function must write the computed value in the last argument
+// (the only non-const one) and return true to indicate success.
+//
+// For example, consider a scalar error e = x'y - a, where both x and y are
+// two-dimensional column vector parameters, the prime sign indicates
+// transposition, and a is a constant.
+//
+// To write an numerically-differentiable cost function for the above model,
+// first define the object
+//
+//  class QuadraticCostFunctor {
+//   public:
+//    explicit QuadraticCostFunctor(double a) : a_(a) {}
+//    bool operator()(const double* const xy, double* cost) const {
+//      constexpr int kInputVectorLength = 2;
+//      const double* const x = xy;
+//      const double* const y = xy + kInputVectorLength;
+//      *cost = x[0] * y[0] + x[1] * y[1] - a_;
+//      return true;
+//    }
+//
+//   private:
+//    double a_;
+//  };
+//
+//
+// Note that in the declaration of operator() the input parameters xy
+// come first, and are passed as const pointers to array of
+// doubles. The output cost is the last parameter.
+//
+// Then given this class definition, the numerically differentiated
+// first order function with central differences used for computing the
+// derivative can be constructed as follows.
+//
+//   FirstOrderFunction* function
+//       = new NumericDiffFirstOrderFunction<MyScalarCostFunctor, CENTRAL, 4>(
+//           new QuadraticCostFunctor(1.0));                   ^     ^     ^
+//                                                             |     |     |
+//                                 Finite Differencing Scheme -+     |     |
+//                                 Dimension of xy ------------------------+
+//
+//
+// In the instantiation above, the template parameters following
+// "QuadraticCostFunctor", "CENTRAL, 4", describe the finite
+// differencing scheme as "central differencing" and the functor as
+// computing its cost from a 4 dimensional input.
+//
+// If the size of the parameter vector is not known at compile time, then an
+// alternate construction syntax can be used:
+//
+//   FirstOrderFunction* function
+//       = new NumericDiffFirstOrderFunction<MyScalarCostFunctor, CENTRAL>(
+//           new QuadraticCostFunctor(1.0), 4);
+//
+// Note that instead of passing 4 as a template argument, it is now passed as
+// the second argument to the constructor.
+template <typename FirstOrderFunctor,
+          NumericDiffMethodType kMethod,
+          int kNumParameters = DYNAMIC>
+class NumericDiffFirstOrderFunction final : public FirstOrderFunction {
+ public:
+  template <class... Args,
+            bool kIsDynamic = kNumParameters == DYNAMIC,
+            std::enable_if_t<!kIsDynamic &&
+                             std::is_constructible_v<FirstOrderFunctor,
+                                                     Args&&...>>* = nullptr>
+  explicit NumericDiffFirstOrderFunction(Args&&... args)
+      : NumericDiffFirstOrderFunction{std::make_unique<FirstOrderFunction>(
+            std::forward<Args>(args)...)} {}
+
+  NumericDiffFirstOrderFunction(const NumericDiffFirstOrderFunction&) = delete;
+  NumericDiffFirstOrderFunction& operator=(
+      const NumericDiffFirstOrderFunction&) = delete;
+  NumericDiffFirstOrderFunction(
+      NumericDiffFirstOrderFunction&& other) noexcept = default;
+  NumericDiffFirstOrderFunction& operator=(
+      NumericDiffFirstOrderFunction&& other) noexcept = default;
+
+  // Constructor for the case where the parameter size is known at compile time.
+  explicit NumericDiffFirstOrderFunction(
+      FirstOrderFunctor* functor,
+      Ownership ownership = TAKE_OWNERSHIP,
+      const NumericDiffOptions& options = NumericDiffOptions())
+      : NumericDiffFirstOrderFunction{
+            std::unique_ptr<FirstOrderFunctor>{functor},
+            kNumParameters,
+            ownership,
+            options,
+            FIXED_INIT} {}
+
+  // Constructor for the case where the parameter size is known at compile time.
+  explicit NumericDiffFirstOrderFunction(
+      std::unique_ptr<FirstOrderFunctor> functor,
+      const NumericDiffOptions& options = NumericDiffOptions())
+      : NumericDiffFirstOrderFunction{
+            std::move(functor), kNumParameters, TAKE_OWNERSHIP, FIXED_INIT} {}
+
+  // Constructor for the case where the parameter size is specified at run time.
+  explicit NumericDiffFirstOrderFunction(
+      FirstOrderFunctor* functor,
+      int num_parameters,
+      Ownership ownership = TAKE_OWNERSHIP,
+      const NumericDiffOptions& options = NumericDiffOptions())
+      : NumericDiffFirstOrderFunction{
+            std::unique_ptr<FirstOrderFunctor>{functor},
+            num_parameters,
+            ownership,
+            options,
+            DYNAMIC_INIT} {}
+
+  // Constructor for the case where the parameter size is specified at run time.
+  explicit NumericDiffFirstOrderFunction(
+      std::unique_ptr<FirstOrderFunctor> functor,
+      int num_parameters,
+      Ownership ownership = TAKE_OWNERSHIP,
+      const NumericDiffOptions& options = NumericDiffOptions())
+      : NumericDiffFirstOrderFunction{std::move(functor),
+                                      num_parameters,
+                                      ownership,
+                                      options,
+                                      DYNAMIC_INIT} {}
+
+  ~NumericDiffFirstOrderFunction() override {
+    if (ownership_ != TAKE_OWNERSHIP) {
+      functor_.release();
+    }
+  }
+
+  bool Evaluate(const double* const parameters,
+                double* cost,
+                double* gradient) const override {
+    // Get the function value (cost) at the the point to evaluate.
+    if (!(*functor_)(parameters, cost)) {
+      return false;
+    }
+
+    if (gradient == nullptr) {
+      return true;
+    }
+
+    // Create a copy of the parameters which will get mutated.
+    internal::FixedArray<double, 32> parameters_copy(num_parameters_);
+    std::copy_n(parameters, num_parameters_, parameters_copy.data());
+    double* parameters_ptr = parameters_copy.data();
+    constexpr int kNumResiduals = 1;
+    if constexpr (kNumParameters == DYNAMIC) {
+      internal::FirstOrderFunctorAdapter<FirstOrderFunctor> fofa(*functor_);
+      return internal::NumericDiff<
+          internal::FirstOrderFunctorAdapter<FirstOrderFunctor>,
+          kMethod,
+          kNumResiduals,
+          internal::DynamicParameterDims,
+          0,
+          DYNAMIC>::EvaluateJacobianForParameterBlock(&fofa,
+                                                      cost,
+                                                      options_,
+                                                      kNumResiduals,
+                                                      0,
+                                                      num_parameters_,
+                                                      &parameters_ptr,
+                                                      gradient);
+    } else {
+      return internal::EvaluateJacobianForParameterBlocks<
+          internal::StaticParameterDims<kNumParameters>>::
+          template Apply<kMethod, 1>(functor_.get(),
+                                     cost,
+                                     options_,
+                                     kNumResiduals,
+                                     &parameters_ptr,
+                                     &gradient);
+    }
+  }
+
+  int NumParameters() const override { return num_parameters_; }
+
+  const FirstOrderFunctor& functor() const { return *functor_; }
+
+ private:
+  // Tags used to differentiate between dynamic and fixed size constructor
+  // delegate invocations.
+  static constexpr std::integral_constant<int, DYNAMIC> DYNAMIC_INIT{};
+  static constexpr std::integral_constant<int, kNumParameters> FIXED_INIT{};
+
+  template <class InitTag>
+  explicit NumericDiffFirstOrderFunction(
+      std::unique_ptr<FirstOrderFunctor> functor,
+      int num_parameters,
+      Ownership ownership,
+      const NumericDiffOptions& options,
+      InitTag /*unused*/)
+      : functor_(std::move(functor)),
+        num_parameters_(num_parameters),
+        ownership_(ownership),
+        options_(options) {
+    static_assert(
+        kNumParameters == FIXED_INIT,
+        "Template parameter must be DYNAMIC when using this constructor. If "
+        "you want to provide the number of parameters statically use the other "
+        "constructor.");
+    if constexpr (InitTag::value == DYNAMIC_INIT) {
+      CHECK_GT(num_parameters, 0);
+    }
+  }
+
+  std::unique_ptr<FirstOrderFunctor> functor_;
+  int num_parameters_;
+  Ownership ownership_;
+  NumericDiffOptions options_;
+};
+
+}  // namespace ceres
+
+#endif  // CERES_PUBLIC_NUMERIC_DIFF_FIRST_ORDER_FUNCTION_H_
diff --git a/third_party/ceres/include/ceres/numeric_diff_options.h b/third_party/ceres/include/ceres/numeric_diff_options.h
index 64919ed..eefb7ad 100644
--- a/third_party/ceres/include/ceres/numeric_diff_options.h
+++ b/third_party/ceres/include/ceres/numeric_diff_options.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -32,7 +32,8 @@
 #ifndef CERES_PUBLIC_NUMERIC_DIFF_OPTIONS_H_
 #define CERES_PUBLIC_NUMERIC_DIFF_OPTIONS_H_
 
-#include "ceres/internal/port.h"
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 
 namespace ceres {
 
@@ -70,4 +71,6 @@
 
 }  // namespace ceres
 
+#include "ceres/internal/reenable_warnings.h"
+
 #endif  // CERES_PUBLIC_NUMERIC_DIFF_OPTIONS_H_
diff --git a/third_party/ceres/include/ceres/ordered_groups.h b/third_party/ceres/include/ceres/ordered_groups.h
index 954663c..d15d22d 100644
--- a/third_party/ceres/include/ceres/ordered_groups.h
+++ b/third_party/ceres/include/ceres/ordered_groups.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -36,7 +36,7 @@
 #include <unordered_map>
 #include <vector>
 
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 #include "glog/logging.h"
 
 namespace ceres {
@@ -190,7 +190,7 @@
 };
 
 // Typedef for the most commonly used version of OrderedGroups.
-typedef OrderedGroups<double*> ParameterBlockOrdering;
+using ParameterBlockOrdering = OrderedGroups<double*>;
 
 }  // namespace ceres
 
diff --git a/third_party/ceres/include/ceres/problem.h b/third_party/ceres/include/ceres/problem.h
index add12ea..4c6fd1b 100644
--- a/third_party/ceres/include/ceres/problem.h
+++ b/third_party/ceres/include/ceres/problem.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -43,6 +43,7 @@
 
 #include "ceres/context.h"
 #include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 #include "ceres/internal/port.h"
 #include "ceres/types.h"
 #include "glog/logging.h"
@@ -52,7 +53,7 @@
 class CostFunction;
 class EvaluationCallback;
 class LossFunction;
-class LocalParameterization;
+class Manifold;
 class Solver;
 struct CRSMatrix;
 
@@ -65,7 +66,7 @@
 
 // A ResidualBlockId is an opaque handle clients can use to remove residual
 // blocks from a Problem after adding them.
-typedef internal::ResidualBlock* ResidualBlockId;
+using ResidualBlockId = internal::ResidualBlock*;
 
 // A class to represent non-linear least squares problems. Such
 // problems have a cost function that is a sum of error terms (known
@@ -78,31 +79,28 @@
 //
 // where
 //
-//   r_ij     is residual number i, component j; the residual is a
-//            function of some subset of the parameters x1...xk. For
-//            example, in a structure from motion problem a residual
-//            might be the difference between a measured point in an
-//            image and the reprojected position for the matching
-//            camera, point pair. The residual would have two
-//            components, error in x and error in y.
+//   r_ij is residual number i, component j; the residual is a function of some
+//        subset of the parameters x1...xk. For example, in a structure from
+//        motion problem a residual might be the difference between a measured
+//        point in an image and the reprojected position for the matching
+//        camera, point pair. The residual would have two components, error in x
+//        and error in y.
 //
-//   loss(y)  is the loss function; for example, squared error or
-//            Huber L1 loss. If loss(y) = y, then the cost function is
-//            non-robustified least squares.
+//   loss(y) is the loss function; for example, squared error or Huber L1
+//           loss. If loss(y) = y, then the cost function is non-robustified
+//           least squares.
 //
-// This class is specifically designed to address the important subset
-// of "sparse" least squares problems, where each component of the
-// residual depends only on a small number number of parameters, even
-// though the total number of residuals and parameters may be very
-// large. This property affords tremendous gains in scale, allowing
-// efficient solving of large problems that are otherwise
-// inaccessible.
+// This class is specifically designed to address the important subset of
+// "sparse" least squares problems, where each component of the residual depends
+// only on a small number number of parameters, even though the total number of
+// residuals and parameters may be very large. This property affords tremendous
+// gains in scale, allowing efficient solving of large problems that are
+// otherwise inaccessible.
 //
 // The canonical example of a sparse least squares problem is
-// "structure-from-motion" (SFM), where the parameters are points and
-// cameras, and residuals are reprojection errors. Typically a single
-// residual will depend only on 9 parameters (3 for the point, 6 for
-// the camera).
+// "structure-from-motion" (SFM), where the parameters are points and cameras,
+// and residuals are reprojection errors. Typically a single residual will
+// depend only on 9 parameters (3 for the point, 6 for the camera).
 //
 // To create a least squares problem, use the AddResidualBlock() and
 // AddParameterBlock() methods, documented below. Here is an example least
@@ -122,38 +120,37 @@
 class CERES_EXPORT Problem {
  public:
   struct CERES_EXPORT Options {
-    // These flags control whether the Problem object owns the cost
-    // functions, loss functions, and parameterizations passed into
-    // the Problem. If set to TAKE_OWNERSHIP, then the problem object
-    // will delete the corresponding cost or loss functions on
-    // destruction. The destructor is careful to delete the pointers
-    // only once, since sharing cost/loss/parameterizations is
-    // allowed.
+    // These flags control whether the Problem object owns the CostFunctions,
+    // LossFunctions, and Manifolds passed into the Problem.
+    //
+    // If set to TAKE_OWNERSHIP, then the problem object will delete the
+    // corresponding object on destruction. The destructor is careful to delete
+    // the pointers only once, since sharing objects is allowed.
     Ownership cost_function_ownership = TAKE_OWNERSHIP;
     Ownership loss_function_ownership = TAKE_OWNERSHIP;
-    Ownership local_parameterization_ownership = TAKE_OWNERSHIP;
+    Ownership manifold_ownership = TAKE_OWNERSHIP;
 
     // If true, trades memory for faster RemoveResidualBlock() and
     // RemoveParameterBlock() operations.
     //
     // By default, RemoveParameterBlock() and RemoveResidualBlock() take time
-    // proportional to the size of the entire problem.  If you only ever remove
+    // proportional to the size of the entire problem. If you only ever remove
     // parameters or residuals from the problem occasionally, this might be
-    // acceptable.  However, if you have memory to spare, enable this option to
+    // acceptable. However, if you have memory to spare, enable this option to
     // make RemoveParameterBlock() take time proportional to the number of
     // residual blocks that depend on it, and RemoveResidualBlock() take (on
     // average) constant time.
     //
-    // The increase in memory usage is twofold: an additional hash set per
+    // The increase in memory usage is two-fold: an additional hash set per
     // parameter block containing all the residuals that depend on the parameter
     // block; and a hash set in the problem containing all residuals.
     bool enable_fast_removal = false;
 
     // By default, Ceres performs a variety of safety checks when constructing
-    // the problem. There is a small but measurable performance penalty to
-    // these checks, typically around 5% of construction time. If you are sure
-    // your problem construction is correct, and 5% of the problem construction
-    // time is truly an overhead you want to avoid, then you can set
+    // the problem. There is a small but measurable performance penalty to these
+    // checks, typically around 5% of construction time. If you are sure your
+    // problem construction is correct, and 5% of the problem construction time
+    // is truly an overhead you want to avoid, then you can set
     // disable_all_safety_checks to true.
     //
     // WARNING: Do not set this to true, unless you are absolutely sure of what
@@ -167,26 +164,23 @@
     // Ceres does NOT take ownership of the pointer.
     Context* context = nullptr;
 
-    // Using this callback interface, Ceres can notify you when it is
-    // about to evaluate the residuals or jacobians. With the
-    // callback, you can share computation between residual blocks by
-    // doing the shared computation in
+    // Using this callback interface, Ceres can notify you when it is about to
+    // evaluate the residuals or jacobians. With the callback, you can share
+    // computation between residual blocks by doing the shared computation in
     // EvaluationCallback::PrepareForEvaluation() before Ceres calls
-    // CostFunction::Evaluate(). It also enables caching results
-    // between a pure residual evaluation and a residual & jacobian
-    // evaluation.
+    // CostFunction::Evaluate(). It also enables caching results between a pure
+    // residual evaluation and a residual & jacobian evaluation.
     //
     // Problem DOES NOT take ownership of the callback.
     //
-    // NOTE: Evaluation callbacks are incompatible with inner
-    // iterations. So calling Solve with
-    // Solver::Options::use_inner_iterations = true on a Problem with
-    // a non-null evaluation callback is an error.
+    // NOTE: Evaluation callbacks are incompatible with inner iterations. So
+    // calling Solve with Solver::Options::use_inner_iterations = true on a
+    // Problem with a non-null evaluation callback is an error.
     EvaluationCallback* evaluation_callback = nullptr;
   };
 
-  // The default constructor is equivalent to the
-  // invocation Problem(Problem::Options()).
+  // The default constructor is equivalent to the invocation
+  // Problem(Problem::Options()).
   Problem();
   explicit Problem(const Options& options);
   Problem(Problem&&);
@@ -197,31 +191,29 @@
 
   ~Problem();
 
-  // Add a residual block to the overall cost function. The cost
-  // function carries with its information about the sizes of the
-  // parameter blocks it expects. The function checks that these match
-  // the sizes of the parameter blocks listed in parameter_blocks. The
-  // program aborts if a mismatch is detected. loss_function can be
-  // nullptr, in which case the cost of the term is just the squared norm
-  // of the residuals.
+  // Add a residual block to the overall cost function. The cost function
+  // carries with its information about the sizes of the parameter blocks it
+  // expects. The function checks that these match the sizes of the parameter
+  // blocks listed in parameter_blocks. The program aborts if a mismatch is
+  // detected. loss_function can be nullptr, in which case the cost of the term
+  // is just the squared norm of the residuals.
   //
-  // The user has the option of explicitly adding the parameter blocks
-  // using AddParameterBlock. This causes additional correctness
-  // checking; however, AddResidualBlock implicitly adds the parameter
-  // blocks if they are not present, so calling AddParameterBlock
-  // explicitly is not required.
+  // The user has the option of explicitly adding the parameter blocks using
+  // AddParameterBlock. This causes additional correctness checking; however,
+  // AddResidualBlock implicitly adds the parameter blocks if they are not
+  // present, so calling AddParameterBlock explicitly is not required.
   //
-  // The Problem object by default takes ownership of the
-  // cost_function and loss_function pointers. These objects remain
-  // live for the life of the Problem object. If the user wishes to
-  // keep control over the destruction of these objects, then they can
+  // The Problem object by default takes ownership of the cost_function and
+  // loss_function pointers (See Problem::Options to override this behaviour).
+  // These objects remain live for the life of the Problem object. If the user
+  // wishes to keep control over the destruction of these objects, then they can
   // do this by setting the corresponding enums in the Options struct.
   //
-  // Note: Even though the Problem takes ownership of cost_function
-  // and loss_function, it does not preclude the user from re-using
-  // them in another residual block. The destructor takes care to call
-  // delete on each cost_function or loss_function pointer only once,
-  // regardless of how many residual blocks refer to them.
+  // Note: Even though the Problem takes ownership of cost_function and
+  // loss_function, it does not preclude the user from re-using them in another
+  // residual block. The destructor takes care to call delete on each
+  // cost_function or loss_function pointer only once, regardless of how many
+  // residual blocks refer to them.
   //
   // Example usage:
   //
@@ -234,8 +226,8 @@
   //   problem.AddResidualBlock(new MyUnaryCostFunction(...), nullptr, x1);
   //   problem.AddResidualBlock(new MyBinaryCostFunction(...), nullptr, x2, x1);
   //
-  // Add a residual block by listing the parameter block pointers
-  // directly instead of wapping them in a container.
+  // Add a residual block by listing the parameter block pointers directly
+  // instead of wapping them in a container.
   template <typename... Ts>
   ResidualBlockId AddResidualBlock(CostFunction* cost_function,
                                    LossFunction* loss_function,
@@ -261,29 +253,32 @@
                                    double* const* const parameter_blocks,
                                    int num_parameter_blocks);
 
-  // Add a parameter block with appropriate size to the problem.
-  // Repeated calls with the same arguments are ignored. Repeated
-  // calls with the same double pointer but a different size results
-  // in undefined behaviour.
+  // Add a parameter block with appropriate size to the problem. Repeated calls
+  // with the same arguments are ignored. Repeated calls with the same double
+  // pointer but a different size will result in a crash.
   void AddParameterBlock(double* values, int size);
 
-  // Add a parameter block with appropriate size and parameterization
-  // to the problem. Repeated calls with the same arguments are
-  // ignored. Repeated calls with the same double pointer but a
-  // different size results in undefined behaviour.
-  void AddParameterBlock(double* values,
-                         int size,
-                         LocalParameterization* local_parameterization);
-
-  // Remove a parameter block from the problem. The parameterization of the
-  // parameter block, if it exists, will persist until the deletion of the
-  // problem (similar to cost/loss functions in residual block removal). Any
-  // residual blocks that depend on the parameter are also removed, as
-  // described above in RemoveResidualBlock().
+  // Add a parameter block with appropriate size and Manifold to the
+  // problem. It is okay for manifold to be nullptr.
   //
-  // If Problem::Options::enable_fast_removal is true, then the
-  // removal is fast (almost constant time). Otherwise, removing a parameter
-  // block will incur a scan of the entire Problem object.
+  // Repeated calls with the same arguments are ignored. Repeated calls
+  // with the same double pointer but a different size results in a crash
+  // (unless Solver::Options::disable_all_safety_checks is set to true).
+  //
+  // Repeated calls with the same double pointer and size but different Manifold
+  // is equivalent to calling SetManifold(manifold), i.e., any previously
+  // associated Manifold object will be replaced with the manifold.
+  void AddParameterBlock(double* values, int size, Manifold* manifold);
+
+  // Remove a parameter block from the problem. The Manifold of the parameter
+  // block, if it exists, will persist until the deletion of the problem
+  // (similar to cost/loss functions in residual block removal). Any residual
+  // blocks that depend on the parameter are also removed, as described above
+  // in RemoveResidualBlock().
+  //
+  // If Problem::Options::enable_fast_removal is true, then the removal is fast
+  // (almost constant time). Otherwise, removing a parameter block will incur a
+  // scan of the entire Problem object.
   //
   // WARNING: Removing a residual or parameter block will destroy the implicit
   // ordering, rendering the jacobian or residuals returned from the solver
@@ -308,35 +303,41 @@
   // Allow the indicated parameter block to vary during optimization.
   void SetParameterBlockVariable(double* values);
 
-  // Returns true if a parameter block is set constant, and false
-  // otherwise. A parameter block may be set constant in two ways:
-  // either by calling SetParameterBlockConstant or by associating a
-  // LocalParameterization with a zero dimensional tangent space with
-  // it.
+  // Returns true if a parameter block is set constant, and false otherwise. A
+  // parameter block may be set constant in two ways: either by calling
+  // SetParameterBlockConstant or by associating a Manifold with a zero
+  // dimensional tangent space with it.
   bool IsParameterBlockConstant(const double* values) const;
 
-  // Set the local parameterization for one of the parameter blocks.
-  // The local_parameterization is owned by the Problem by default. It
-  // is acceptable to set the same parameterization for multiple
-  // parameters; the destructor is careful to delete local
-  // parameterizations only once. Calling SetParameterization with
-  // nullptr will clear any previously set parameterization.
-  void SetParameterization(double* values,
-                           LocalParameterization* local_parameterization);
+  // Set the Manifold for the parameter block. Calling SetManifold with nullptr
+  // will clear any previously set Manifold for the parameter block.
+  //
+  // Repeated calls will result in any previously associated Manifold object to
+  // be replaced with the manifold.
+  //
+  // The manifold is owned by the Problem by default (See Problem::Options to
+  // override this behaviour).
+  //
+  // It is acceptable to set the same Manifold for multiple parameter blocks.
+  void SetManifold(double* values, Manifold* manifold);
 
-  // Get the local parameterization object associated with this
-  // parameter block. If there is no parameterization object
-  // associated then nullptr is returned.
-  const LocalParameterization* GetParameterization(const double* values) const;
+  // Get the Manifold object associated with this parameter block.
+  //
+  // If there is no Manifold object associated then nullptr is returned.
+  const Manifold* GetManifold(const double* values) const;
+
+  // Returns true if a Manifold is associated with this parameter block, false
+  // otherwise.
+  bool HasManifold(const double* values) const;
 
   // Set the lower/upper bound for the parameter at position "index".
   void SetParameterLowerBound(double* values, int index, double lower_bound);
   void SetParameterUpperBound(double* values, int index, double upper_bound);
 
-  // Get the lower/upper bound for the parameter at position
-  // "index". If the parameter is not bounded by the user, then its
-  // lower bound is -std::numeric_limits<double>::max() and upper
-  // bound is std::numeric_limits<double>::max().
+  // Get the lower/upper bound for the parameter at position "index". If the
+  // parameter is not bounded by the user, then its lower bound is
+  // -std::numeric_limits<double>::max() and upper bound is
+  // std::numeric_limits<double>::max().
   double GetParameterLowerBound(const double* values, int index) const;
   double GetParameterUpperBound(const double* values, int index) const;
 
@@ -344,37 +345,37 @@
   // parameter_blocks().size() and parameter_block_sizes().size().
   int NumParameterBlocks() const;
 
-  // The size of the parameter vector obtained by summing over the
-  // sizes of all the parameter blocks.
+  // The size of the parameter vector obtained by summing over the sizes of all
+  // the parameter blocks.
   int NumParameters() const;
 
   // Number of residual blocks in the problem. Always equals
   // residual_blocks().size().
   int NumResidualBlocks() const;
 
-  // The size of the residual vector obtained by summing over the
-  // sizes of all of the residual blocks.
+  // The size of the residual vector obtained by summing over the sizes of all
+  // of the residual blocks.
   int NumResiduals() const;
 
   // The size of the parameter block.
   int ParameterBlockSize(const double* values) const;
 
-  // The size of local parameterization for the parameter block. If
-  // there is no local parameterization associated with this parameter
-  // block, then ParameterBlockLocalSize = ParameterBlockSize.
-  int ParameterBlockLocalSize(const double* values) const;
+  // The dimension of the tangent space of the Manifold for the parameter block.
+  // If there is no Manifold associated with this parameter block, then
+  // ParameterBlockTangentSize = ParameterBlockSize.
+  int ParameterBlockTangentSize(const double* values) const;
 
   // Is the given parameter block present in this problem or not?
   bool HasParameterBlock(const double* values) const;
 
-  // Fills the passed parameter_blocks vector with pointers to the
-  // parameter blocks currently in the problem. After this call,
-  // parameter_block.size() == NumParameterBlocks.
+  // Fills the passed parameter_blocks vector with pointers to the parameter
+  // blocks currently in the problem. After this call, parameter_block.size() ==
+  // NumParameterBlocks.
   void GetParameterBlocks(std::vector<double*>* parameter_blocks) const;
 
-  // Fills the passed residual_blocks vector with pointers to the
-  // residual blocks currently in the problem. After this call,
-  // residual_blocks.size() == NumResidualBlocks.
+  // Fills the passed residual_blocks vector with pointers to the residual
+  // blocks currently in the problem. After this call, residual_blocks.size() ==
+  // NumResidualBlocks.
   void GetResidualBlocks(std::vector<ResidualBlockId>* residual_blocks) const;
 
   // Get all the parameter blocks that depend on the given residual block.
@@ -393,10 +394,10 @@
 
   // Get all the residual blocks that depend on the given parameter block.
   //
-  // If Problem::Options::enable_fast_removal is true, then
-  // getting the residual blocks is fast and depends only on the number of
-  // residual blocks. Otherwise, getting the residual blocks for a parameter
-  // block will incur a scan of the entire Problem object.
+  // If Problem::Options::enable_fast_removal is true, then getting the residual
+  // blocks is fast and depends only on the number of residual
+  // blocks. Otherwise, getting the residual blocks for a parameter block will
+  // incur a scan of the entire Problem object.
   void GetResidualBlocksForParameterBlock(
       const double* values,
       std::vector<ResidualBlockId>* residual_blocks) const;
@@ -404,49 +405,45 @@
   // Options struct to control Problem::Evaluate.
   struct EvaluateOptions {
     // The set of parameter blocks for which evaluation should be
-    // performed. This vector determines the order that parameter
-    // blocks occur in the gradient vector and in the columns of the
-    // jacobian matrix. If parameter_blocks is empty, then it is
-    // assumed to be equal to vector containing ALL the parameter
-    // blocks.  Generally speaking the parameter blocks will occur in
-    // the order in which they were added to the problem. But, this
-    // may change if the user removes any parameter blocks from the
-    // problem.
+    // performed. This vector determines the order that parameter blocks occur
+    // in the gradient vector and in the columns of the jacobian matrix. If
+    // parameter_blocks is empty, then it is assumed to be equal to vector
+    // containing ALL the parameter blocks. Generally speaking the parameter
+    // blocks will occur in the order in which they were added to the
+    // problem. But, this may change if the user removes any parameter blocks
+    // from the problem.
     //
-    // NOTE: This vector should contain the same pointers as the ones
-    // used to add parameter blocks to the Problem. These parameter
-    // block should NOT point to new memory locations. Bad things will
-    // happen otherwise.
+    // NOTE: This vector should contain the same pointers as the ones used to
+    // add parameter blocks to the Problem. These parameter block should NOT
+    // point to new memory locations. Bad things will happen otherwise.
     std::vector<double*> parameter_blocks;
 
-    // The set of residual blocks to evaluate. This vector determines
-    // the order in which the residuals occur, and how the rows of the
-    // jacobian are ordered. If residual_blocks is empty, then it is
-    // assumed to be equal to the vector containing ALL the residual
-    // blocks. Generally speaking the residual blocks will occur in
-    // the order in which they were added to the problem. But, this
-    // may change if the user removes any residual blocks from the
-    // problem.
+    // The set of residual blocks to evaluate. This vector determines the order
+    // in which the residuals occur, and how the rows of the jacobian are
+    // ordered. If residual_blocks is empty, then it is assumed to be equal to
+    // the vector containing ALL the residual blocks. Generally speaking the
+    // residual blocks will occur in the order in which they were added to the
+    // problem. But, this may change if the user removes any residual blocks
+    // from the problem.
     std::vector<ResidualBlockId> residual_blocks;
 
     // Even though the residual blocks in the problem may contain loss
-    // functions, setting apply_loss_function to false will turn off
-    // the application of the loss function to the output of the cost
-    // function. This is of use for example if the user wishes to
-    // analyse the solution quality by studying the distribution of
-    // residuals before and after the solve.
+    // functions, setting apply_loss_function to false will turn off the
+    // application of the loss function to the output of the cost function. This
+    // is of use for example if the user wishes to analyse the solution quality
+    // by studying the distribution of residuals before and after the solve.
     bool apply_loss_function = true;
 
     int num_threads = 1;
   };
 
-  // Evaluate Problem. Any of the output pointers can be nullptr. Which
-  // residual blocks and parameter blocks are used is controlled by
-  // the EvaluateOptions struct above.
+  // Evaluate Problem. Any of the output pointers can be nullptr. Which residual
+  // blocks and parameter blocks are used is controlled by the EvaluateOptions
+  // struct above.
   //
-  // Note 1: The evaluation will use the values stored in the memory
-  // locations pointed to by the parameter block pointers used at the
-  // time of the construction of the problem. i.e.,
+  // Note 1: The evaluation will use the values stored in the memory locations
+  // pointed to by the parameter block pointers used at the time of the
+  // construction of the problem. i.e.,
   //
   //   Problem problem;
   //   double x = 1;
@@ -456,8 +453,8 @@
   //   problem.Evaluate(Problem::EvaluateOptions(), &cost,
   //                    nullptr, nullptr, nullptr);
   //
-  // The cost is evaluated at x = 1. If you wish to evaluate the
-  // problem at x = 2, then
+  // The cost is evaluated at x = 1. If you wish to evaluate the problem at x =
+  // 2, then
   //
   //   x = 2;
   //   problem.Evaluate(Problem::EvaluateOptions(), &cost,
@@ -465,80 +462,74 @@
   //
   // is the way to do so.
   //
-  // Note 2: If no local parameterizations are used, then the size of
-  // the gradient vector (and the number of columns in the jacobian)
-  // is the sum of the sizes of all the parameter blocks. If a
-  // parameter block has a local parameterization, then it contributes
-  // "LocalSize" entries to the gradient vector (and the number of
-  // columns in the jacobian).
+  // Note 2: If no Manifolds are used, then the size of the gradient vector (and
+  // the number of columns in the jacobian) is the sum of the sizes of all the
+  // parameter blocks. If a parameter block has a Manifold, then it contributes
+  // "TangentSize" entries to the gradient vector (and the number of columns in
+  // the jacobian).
   //
-  // Note 3: This function cannot be called while the problem is being
-  // solved, for example it cannot be called from an IterationCallback
-  // at the end of an iteration during a solve.
+  // Note 3: This function cannot be called while the problem is being solved,
+  // for example it cannot be called from an IterationCallback at the end of an
+  // iteration during a solve.
   //
-  // Note 4: If an EvaluationCallback is associated with the problem,
-  // then its PrepareForEvaluation method will be called every time
-  // this method is called with new_point = true.
+  // Note 4: If an EvaluationCallback is associated with the problem, then its
+  // PrepareForEvaluation method will be called every time this method is called
+  // with new_point = true.
   bool Evaluate(const EvaluateOptions& options,
                 double* cost,
                 std::vector<double>* residuals,
                 std::vector<double>* gradient,
                 CRSMatrix* jacobian);
 
-  // Evaluates the residual block, storing the scalar cost in *cost,
-  // the residual components in *residuals, and the jacobians between
-  // the parameters and residuals in jacobians[i], in row-major order.
+  // Evaluates the residual block, storing the scalar cost in *cost, the
+  // residual components in *residuals, and the jacobians between the parameters
+  // and residuals in jacobians[i], in row-major order.
   //
   // If residuals is nullptr, the residuals are not computed.
   //
-  // If jacobians is nullptr, no Jacobians are computed. If
-  // jacobians[i] is nullptr, then the Jacobian for that parameter
-  // block is not computed.
+  // If jacobians is nullptr, no Jacobians are computed. If jacobians[i] is
+  // nullptr, then the Jacobian for that parameter block is not computed.
   //
-  // It is not okay to request the Jacobian w.r.t a parameter block
-  // that is constant.
+  // It is not okay to request the Jacobian w.r.t a parameter block that is
+  // constant.
   //
-  // The return value indicates the success or failure. Even if the
-  // function returns false, the caller should expect the output
-  // memory locations to have been modified.
+  // The return value indicates the success or failure. Even if the function
+  // returns false, the caller should expect the output memory locations to have
+  // been modified.
   //
-  // The returned cost and jacobians have had robustification and
-  // local parameterizations applied already; for example, the
-  // jacobian for a 4-dimensional quaternion parameter using the
-  // "QuaternionParameterization" is num_residuals by 3 instead of
-  // num_residuals by 4.
+  // The returned cost and jacobians have had robustification and Manifold
+  // applied already; for example, the jacobian for a 4-dimensional quaternion
+  // parameter using the "QuaternionParameterization" is num_residuals by 3
+  // instead of num_residuals by 4.
   //
-  // apply_loss_function as the name implies allows the user to switch
-  // the application of the loss function on and off.
+  // apply_loss_function as the name implies allows the user to switch the
+  // application of the loss function on and off.
   //
   // If an EvaluationCallback is associated with the problem, then its
-  // PrepareForEvaluation method will be called every time this method
-  // is called with new_point = true. This conservatively assumes that
-  // the user may have changed the parameter values since the previous
-  // call to evaluate / solve.  For improved efficiency, and only if
-  // you know that the parameter values have not changed between
-  // calls, see EvaluateResidualBlockAssumingParametersUnchanged().
+  // PrepareForEvaluation method will be called every time this method is called
+  // with new_point = true. This conservatively assumes that the user may have
+  // changed the parameter values since the previous call to evaluate / solve.
+  // For improved efficiency, and only if you know that the parameter values
+  // have not changed between calls, see
+  // EvaluateResidualBlockAssumingParametersUnchanged().
   bool EvaluateResidualBlock(ResidualBlockId residual_block_id,
                              bool apply_loss_function,
                              double* cost,
                              double* residuals,
                              double** jacobians) const;
 
-  // Same as EvaluateResidualBlock except that if an
-  // EvaluationCallback is associated with the problem, then its
-  // PrepareForEvaluation method will be called every time this method
-  // is called with new_point = false.
+  // Same as EvaluateResidualBlock except that if an EvaluationCallback is
+  // associated with the problem, then its PrepareForEvaluation method will be
+  // called every time this method is called with new_point = false.
   //
-  // This means, if an EvaluationCallback is associated with the
-  // problem then it is the user's responsibility to call
-  // PrepareForEvaluation before calling this method if necessary,
-  // i.e. iff the parameter values have been changed since the last
-  // call to evaluate / solve.'
+  // This means, if an EvaluationCallback is associated with the problem then it
+  // is the user's responsibility to call PrepareForEvaluation before calling
+  // this method if necessary, i.e. iff the parameter values have been changed
+  // since the last call to evaluate / solve.'
   //
-  // This is because, as the name implies, we assume that the
-  // parameter blocks did not change since the last time
-  // PrepareForEvaluation was called (via Solve, Evaluate or
-  // EvaluateResidualBlock).
+  // This is because, as the name implies, we assume that the parameter blocks
+  // did not change since the last time PrepareForEvaluation was called (via
+  // Solve, Evaluate or EvaluateResidualBlock).
   bool EvaluateResidualBlockAssumingParametersUnchanged(
       ResidualBlockId residual_block_id,
       bool apply_loss_function,
@@ -546,9 +537,13 @@
       double* residuals,
       double** jacobians) const;
 
+  // Returns reference to the options with which the Problem was constructed.
+  const Options& options() const;
+
+  // Returns pointer to Problem implementation
+  internal::ProblemImpl* mutable_impl();
+
  private:
-  friend class Solver;
-  friend class Covariance;
   std::unique_ptr<internal::ProblemImpl> impl_;
 };
 
diff --git a/third_party/ceres/include/ceres/product_manifold.h b/third_party/ceres/include/ceres/product_manifold.h
new file mode 100644
index 0000000..ed2d1f4
--- /dev/null
+++ b/third_party/ceres/include/ceres/product_manifold.h
@@ -0,0 +1,319 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//         sergiu.deitsch@gmail.com (Sergiu Deitsch)
+//
+
+#ifndef CERES_PUBLIC_PRODUCT_MANIFOLD_H_
+#define CERES_PUBLIC_PRODUCT_MANIFOLD_H_
+
+#include <algorithm>
+#include <array>
+#include <cassert>
+#include <cstddef>
+#include <numeric>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/fixed_array.h"
+#include "ceres/internal/port.h"
+#include "ceres/manifold.h"
+
+namespace ceres {
+
+// Construct a manifold by taking the Cartesian product of a number of other
+// manifolds. This is useful, when a parameter block is the Cartesian product
+// of two or more manifolds. For example the parameters of a camera consist of
+// a rotation and a translation, i.e., SO(3) x R^3.
+//
+// Example usage:
+//
+// ProductManifold<QuaternionManifold, EuclideanManifold<3>> se3;
+//
+// is the manifold for a rigid transformation, where the rotation is
+// represented using a quaternion.
+//
+// Manifolds can be copied and moved to ProductManifold:
+//
+// SubsetManifold manifold1(5, {2});
+// SubsetManifold manifold2(3, {0, 1});
+// ProductManifold<SubsetManifold, SubsetManifold> manifold(manifold1,
+//                                                          manifold2);
+//
+// In advanced use cases, manifolds can be dynamically allocated and passed as
+// (smart) pointers:
+//
+// ProductManifold<std::unique_ptr<QuaternionManifold>, EuclideanManifold<3>>
+//     se3{std::make_unique<QuaternionManifold>(), EuclideanManifold<3>{}};
+//
+// In C++17, the template parameters can be left out as they are automatically
+// deduced making the initialization much simpler:
+//
+// ProductManifold se3{QuaternionManifold{}, EuclideanManifold<3>{}};
+//
+// The manifold implementations must be either default constructible, copyable
+// or moveable to be usable in a ProductManifold.
+template <typename Manifold0, typename Manifold1, typename... ManifoldN>
+class ProductManifold final : public Manifold {
+ public:
+  // ProductManifold constructor perfect forwards arguments to store manifolds.
+  //
+  // Either use default construction or if you need to copy or move-construct a
+  // manifold instance, you need to pass an instance as an argument for all
+  // types given as class template parameters.
+  template <typename... Args,
+            std::enable_if_t<std::is_constructible<
+                std::tuple<Manifold0, Manifold1, ManifoldN...>,
+                Args...>::value>* = nullptr>
+  explicit ProductManifold(Args&&... manifolds)
+      : ProductManifold{std::make_index_sequence<kNumManifolds>{},
+                        std::forward<Args>(manifolds)...} {}
+
+  int AmbientSize() const override { return ambient_size_; }
+  int TangentSize() const override { return tangent_size_; }
+
+  bool Plus(const double* x,
+            const double* delta,
+            double* x_plus_delta) const override {
+    return PlusImpl(
+        x, delta, x_plus_delta, std::make_index_sequence<kNumManifolds>{});
+  }
+
+  bool Minus(const double* y,
+             const double* x,
+             double* y_minus_x) const override {
+    return MinusImpl(
+        y, x, y_minus_x, std::make_index_sequence<kNumManifolds>{});
+  }
+
+  bool PlusJacobian(const double* x, double* jacobian_ptr) const override {
+    MatrixRef jacobian(jacobian_ptr, AmbientSize(), TangentSize());
+    jacobian.setZero();
+    internal::FixedArray<double> buffer(buffer_size_);
+
+    return PlusJacobianImpl(
+        x, jacobian, buffer, std::make_index_sequence<kNumManifolds>{});
+  }
+
+  bool MinusJacobian(const double* x, double* jacobian_ptr) const override {
+    MatrixRef jacobian(jacobian_ptr, TangentSize(), AmbientSize());
+    jacobian.setZero();
+    internal::FixedArray<double> buffer(buffer_size_);
+
+    return MinusJacobianImpl(
+        x, jacobian, buffer, std::make_index_sequence<kNumManifolds>{});
+  }
+
+ private:
+  static constexpr std::size_t kNumManifolds = 2 + sizeof...(ManifoldN);
+
+  template <std::size_t... Indices, typename... Args>
+  explicit ProductManifold(std::index_sequence<Indices...>, Args&&... manifolds)
+      : manifolds_{std::forward<Args>(manifolds)...},
+        buffer_size_{(std::max)(
+            {(Dereference(std::get<Indices>(manifolds_)).TangentSize() *
+              Dereference(std::get<Indices>(manifolds_)).AmbientSize())...})},
+        ambient_sizes_{
+            Dereference(std::get<Indices>(manifolds_)).AmbientSize()...},
+        tangent_sizes_{
+            Dereference(std::get<Indices>(manifolds_)).TangentSize()...},
+        ambient_offsets_{ExclusiveScan(ambient_sizes_)},
+        tangent_offsets_{ExclusiveScan(tangent_sizes_)},
+        ambient_size_{
+            std::accumulate(ambient_sizes_.begin(), ambient_sizes_.end(), 0)},
+        tangent_size_{
+            std::accumulate(tangent_sizes_.begin(), tangent_sizes_.end(), 0)} {}
+
+  template <std::size_t Index0, std::size_t... Indices>
+  bool PlusImpl(const double* x,
+                const double* delta,
+                double* x_plus_delta,
+                std::index_sequence<Index0, Indices...>) const {
+    if (!Dereference(std::get<Index0>(manifolds_))
+             .Plus(x + ambient_offsets_[Index0],
+                   delta + tangent_offsets_[Index0],
+                   x_plus_delta + ambient_offsets_[Index0])) {
+      return false;
+    }
+
+    return PlusImpl(x, delta, x_plus_delta, std::index_sequence<Indices...>{});
+  }
+
+  static constexpr bool PlusImpl(const double* /*x*/,
+                                 const double* /*delta*/,
+                                 double* /*x_plus_delta*/,
+                                 std::index_sequence<>) noexcept {
+    return true;
+  }
+
+  template <std::size_t Index0, std::size_t... Indices>
+  bool MinusImpl(const double* y,
+                 const double* x,
+                 double* y_minus_x,
+                 std::index_sequence<Index0, Indices...>) const {
+    if (!Dereference(std::get<Index0>(manifolds_))
+             .Minus(y + ambient_offsets_[Index0],
+                    x + ambient_offsets_[Index0],
+                    y_minus_x + tangent_offsets_[Index0])) {
+      return false;
+    }
+
+    return MinusImpl(y, x, y_minus_x, std::index_sequence<Indices...>{});
+  }
+
+  static constexpr bool MinusImpl(const double* /*y*/,
+                                  const double* /*x*/,
+                                  double* /*y_minus_x*/,
+                                  std::index_sequence<>) noexcept {
+    return true;
+  }
+
+  template <std::size_t Index0, std::size_t... Indices>
+  bool PlusJacobianImpl(const double* x,
+                        MatrixRef& jacobian,
+                        internal::FixedArray<double>& buffer,
+                        std::index_sequence<Index0, Indices...>) const {
+    if (!Dereference(std::get<Index0>(manifolds_))
+             .PlusJacobian(x + ambient_offsets_[Index0], buffer.data())) {
+      return false;
+    }
+
+    jacobian.block(ambient_offsets_[Index0],
+                   tangent_offsets_[Index0],
+                   ambient_sizes_[Index0],
+                   tangent_sizes_[Index0]) =
+        MatrixRef(
+            buffer.data(), ambient_sizes_[Index0], tangent_sizes_[Index0]);
+
+    return PlusJacobianImpl(
+        x, jacobian, buffer, std::index_sequence<Indices...>{});
+  }
+
+  static constexpr bool PlusJacobianImpl(
+      const double* /*x*/,
+      MatrixRef& /*jacobian*/,
+      internal::FixedArray<double>& /*buffer*/,
+      std::index_sequence<>) noexcept {
+    return true;
+  }
+
+  template <std::size_t Index0, std::size_t... Indices>
+  bool MinusJacobianImpl(const double* x,
+                         MatrixRef& jacobian,
+                         internal::FixedArray<double>& buffer,
+                         std::index_sequence<Index0, Indices...>) const {
+    if (!Dereference(std::get<Index0>(manifolds_))
+             .MinusJacobian(x + ambient_offsets_[Index0], buffer.data())) {
+      return false;
+    }
+
+    jacobian.block(tangent_offsets_[Index0],
+                   ambient_offsets_[Index0],
+                   tangent_sizes_[Index0],
+                   ambient_sizes_[Index0]) =
+        MatrixRef(
+            buffer.data(), tangent_sizes_[Index0], ambient_sizes_[Index0]);
+
+    return MinusJacobianImpl(
+        x, jacobian, buffer, std::index_sequence<Indices...>{});
+  }
+
+  static constexpr bool MinusJacobianImpl(
+      const double* /*x*/,
+      MatrixRef& /*jacobian*/,
+      internal::FixedArray<double>& /*buffer*/,
+      std::index_sequence<>) noexcept {
+    return true;
+  }
+
+  template <typename T, std::size_t N>
+  static std::array<T, N> ExclusiveScan(const std::array<T, N>& values) {
+    std::array<T, N> result;
+    // TODO Replace with std::exclusive_scan once all platforms have full C++17
+    // STL support.
+    T init = 0;
+    for (std::size_t i = 0; i != N; ++i) {
+      result[i] = init;
+      init += values[i];
+    }
+    return result;
+  }
+
+  template <typename T, typename E = void>
+  struct IsDereferenceable : std::false_type {};
+
+  template <typename T>
+  struct IsDereferenceable<T, std::void_t<decltype(*std::declval<T>())>>
+      : std::true_type {};
+
+  template <typename T,
+            std::enable_if_t<!IsDereferenceable<T>::value>* = nullptr>
+  static constexpr decltype(auto) Dereference(T& value) {
+    return value;
+  }
+
+  // Support dereferenceable types such as std::unique_ptr, std::shared_ptr, raw
+  // pointers etc.
+  template <typename T,
+            std::enable_if_t<IsDereferenceable<T>::value>* = nullptr>
+  static constexpr decltype(auto) Dereference(T& value) {
+    return *value;
+  }
+
+  template <typename T>
+  static constexpr decltype(auto) Dereference(T* p) {
+    assert(p != nullptr);
+    return *p;
+  }
+
+  std::tuple<Manifold0, Manifold1, ManifoldN...> manifolds_;
+  int buffer_size_;
+  std::array<int, kNumManifolds> ambient_sizes_;
+  std::array<int, kNumManifolds> tangent_sizes_;
+  std::array<int, kNumManifolds> ambient_offsets_;
+  std::array<int, kNumManifolds> tangent_offsets_;
+  int ambient_size_;
+  int tangent_size_;
+};
+
+// C++17 deduction guide that allows the user to avoid explicitly specifying
+// the template parameters of ProductManifold. The class can instead be
+// instantiated as follows:
+//
+//   ProductManifold manifold{QuaternionManifold{}, EuclideanManifold<3>{}};
+//
+template <typename Manifold0, typename Manifold1, typename... Manifolds>
+ProductManifold(Manifold0&&, Manifold1&&, Manifolds&&...)
+    -> ProductManifold<Manifold0, Manifold1, Manifolds...>;
+
+}  // namespace ceres
+
+#endif  // CERES_PUBLIC_PRODUCT_MANIFOLD_H_
diff --git a/third_party/ceres/include/ceres/rotation.h b/third_party/ceres/include/ceres/rotation.h
index 0c82a41..0cccfa7 100644
--- a/third_party/ceres/include/ceres/rotation.h
+++ b/third_party/ceres/include/ceres/rotation.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -47,8 +47,9 @@
 
 #include <algorithm>
 #include <cmath>
-#include <limits>
 
+#include "ceres/constants.h"
+#include "ceres/internal/euler_angles.h"
 #include "glog/logging.h"
 
 namespace ceres {
@@ -60,7 +61,7 @@
 //
 // the expression  M(i, j) is equivalent to
 //
-//   arrary[i * row_stride + j * col_stride]
+//   array[i * row_stride + j * col_stride]
 //
 // Conversion functions to and from rotation matrices accept
 // MatrixAdapters to permit using row-major and column-major layouts,
@@ -136,6 +137,71 @@
 void EulerAnglesToRotationMatrix(
     const T* euler, const MatrixAdapter<T, row_stride, col_stride>& R);
 
+// Convert a generic Euler Angle sequence (in radians) to a 3x3 rotation matrix.
+//
+// Euler Angles define a sequence of 3 rotations about a sequence of axes,
+// typically taken to be the X, Y, or Z axes. The last axis may be the same as
+// the first axis (e.g. ZYZ) per Euler's original definition of his angles
+// (proper Euler angles) or not (e.g. ZYX / yaw-pitch-roll), per common usage in
+// the nautical and aerospace fields (Tait-Bryan angles). The three rotations
+// may be in a global frame of reference (Extrinsic) or in a body fixed frame of
+// reference (Intrinsic) that moves with the rotating object.
+//
+// Internally, Euler Axis sequences are classified by Ken Shoemake's scheme from
+// "Euler angle conversion", Graphics Gems IV, where a choice of axis for the
+// first rotation and 3 binary choices:
+// 1. Parity of the axis permutation. The axis sequence has Even parity if the
+// second axis of rotation is 'greater-than' the first axis of rotation
+// according to the order X<Y<Z<X, otherwise it has Odd parity.
+// 2. Proper Euler Angles v.s. Tait-Bryan Angles
+// 3. Extrinsic Rotations v.s. Intrinsic Rotations
+// compactly represent all 24 possible Euler Angle Conventions
+//
+// One template parameter: EulerSystem must be explicitly given. This parameter
+// is a tag named by 'Extrinsic' or 'Intrinsic' followed by three characters in
+// the set '[XYZ]', specifying the axis sequence, e.g. ceres::ExtrinsicYZY
+// (robotic arms), ceres::IntrinsicZYX (for aerospace), etc.
+//
+// The order of elements in the input array 'euler' follows the axis sequence
+template <typename EulerSystem, typename T>
+inline void EulerAnglesToRotation(const T* euler, T* R);
+
+template <typename EulerSystem, typename T, int row_stride, int col_stride>
+void EulerAnglesToRotation(const T* euler,
+                           const MatrixAdapter<T, row_stride, col_stride>& R);
+
+// Convert a 3x3 rotation matrix to a generic Euler Angle sequence (in radians)
+//
+// Euler Angles define a sequence of 3 rotations about a sequence of axes,
+// typically taken to be the X, Y, or Z axes. The last axis may be the same as
+// the first axis (e.g. ZYZ) per Euler's original definition of his angles
+// (proper Euler angles) or not (e.g. ZYX / yaw-pitch-roll), per common usage in
+// the nautical and aerospace fields (Tait-Bryan angles). The three rotations
+// may be in a global frame of reference (Extrinsic) or in a body fixed frame of
+// reference (Intrinsic) that moves with the rotating object.
+//
+// Internally, Euler Axis sequences are classified by Ken Shoemake's scheme from
+// "Euler angle conversion", Graphics Gems IV, where a choice of axis for the
+// first rotation and 3 binary choices:
+// 1. Oddness of the axis permutation, that defines whether the second axis is
+// 'greater-than' the first axis according to the order X>Y>Z>X)
+// 2. Proper Euler Angles v.s. Tait-Bryan Angles
+// 3. Extrinsic Rotations v.s. Intrinsic Rotations
+// compactly represent all 24 possible Euler Angle Conventions
+//
+// One template parameter: EulerSystem must be explicitly given. This parameter
+// is a tag named by 'Extrinsic' or 'Intrinsic' followed by three characters in
+// the set '[XYZ]', specifying the axis sequence, e.g. ceres::ExtrinsicYZY
+// (robotic arms), ceres::IntrinsicZYX (for aerospace), etc.
+//
+// The order of elements in the output array 'euler' follows the axis sequence
+template <typename EulerSystem, typename T>
+inline void RotationMatrixToEulerAngles(const T* R, T* euler);
+
+template <typename EulerSystem, typename T, int row_stride, int col_stride>
+void RotationMatrixToEulerAngles(
+    const MatrixAdapter<const T, row_stride, col_stride>& R, T* euler);
+
 // Convert a 4-vector to a 3x3 scaled rotation matrix.
 //
 // The choice of rotation is such that the quaternion [1 0 0 0] goes to an
@@ -247,14 +313,15 @@
 
 template <typename T>
 inline void AngleAxisToQuaternion(const T* angle_axis, T* quaternion) {
+  using std::fpclassify;
+  using std::hypot;
   const T& a0 = angle_axis[0];
   const T& a1 = angle_axis[1];
   const T& a2 = angle_axis[2];
-  const T theta_squared = a0 * a0 + a1 * a1 + a2 * a2;
+  const T theta = hypot(a0, a1, a2);
 
   // For points not at the origin, the full conversion is numerically stable.
-  if (theta_squared > T(0.0)) {
-    const T theta = sqrt(theta_squared);
+  if (fpclassify(theta) != FP_ZERO) {
     const T half_theta = theta * T(0.5);
     const T k = sin(half_theta) / theta;
     quaternion[0] = cos(half_theta);
@@ -276,15 +343,16 @@
 
 template <typename T>
 inline void QuaternionToAngleAxis(const T* quaternion, T* angle_axis) {
+  using std::fpclassify;
+  using std::hypot;
   const T& q1 = quaternion[1];
   const T& q2 = quaternion[2];
   const T& q3 = quaternion[3];
-  const T sin_squared_theta = q1 * q1 + q2 * q2 + q3 * q3;
+  const T sin_theta = hypot(q1, q2, q3);
 
   // For quaternions representing non-zero rotation, the conversion
   // is numerically stable.
-  if (sin_squared_theta > T(0.0)) {
-    const T sin_theta = sqrt(sin_squared_theta);
+  if (fpclassify(sin_theta) != FP_ZERO) {
     const T& cos_theta = quaternion[0];
 
     // If cos_theta is negative, theta is greater than pi/2, which
@@ -385,13 +453,14 @@
 template <typename T, int row_stride, int col_stride>
 void AngleAxisToRotationMatrix(
     const T* angle_axis, const MatrixAdapter<T, row_stride, col_stride>& R) {
+  using std::fpclassify;
+  using std::hypot;
   static const T kOne = T(1.0);
-  const T theta2 = DotProduct(angle_axis, angle_axis);
-  if (theta2 > T(std::numeric_limits<double>::epsilon())) {
+  const T theta = hypot(angle_axis[0], angle_axis[1], angle_axis[2]);
+  if (fpclassify(theta) != FP_ZERO) {
     // We want to be careful to only evaluate the square root if the
     // norm of the angle_axis vector is greater than zero. Otherwise
     // we get a division by zero.
-    const T theta = sqrt(theta2);
     const T wx = angle_axis[0] / theta;
     const T wy = angle_axis[1] / theta;
     const T wz = angle_axis[2] / theta;
@@ -411,7 +480,7 @@
     R(2, 2) =     costheta   + wz*wz*(kOne -    costheta);
     // clang-format on
   } else {
-    // Near zero, we switch to using the first order Taylor expansion.
+    // At zero, we switch to using the first order Taylor expansion.
     R(0, 0) = kOne;
     R(1, 0) = angle_axis[2];
     R(2, 0) = -angle_axis[1];
@@ -424,6 +493,141 @@
   }
 }
 
+template <typename EulerSystem, typename T>
+inline void EulerAnglesToRotation(const T* euler, T* R) {
+  EulerAnglesToRotation<EulerSystem>(euler, RowMajorAdapter3x3(R));
+}
+
+template <typename EulerSystem, typename T, int row_stride, int col_stride>
+void EulerAnglesToRotation(const T* euler,
+                           const MatrixAdapter<T, row_stride, col_stride>& R) {
+  using std::cos;
+  using std::sin;
+
+  const auto [i, j, k] = EulerSystem::kAxes;
+
+  T ea[3];
+  ea[1] = euler[1];
+  if constexpr (EulerSystem::kIsIntrinsic) {
+    ea[0] = euler[2];
+    ea[2] = euler[0];
+  } else {
+    ea[0] = euler[0];
+    ea[2] = euler[2];
+  }
+  if constexpr (EulerSystem::kIsParityOdd) {
+    ea[0] = -ea[0];
+    ea[1] = -ea[1];
+    ea[2] = -ea[2];
+  }
+
+  const T ci = cos(ea[0]);
+  const T cj = cos(ea[1]);
+  const T ch = cos(ea[2]);
+  const T si = sin(ea[0]);
+  const T sj = sin(ea[1]);
+  const T sh = sin(ea[2]);
+  const T cc = ci * ch;
+  const T cs = ci * sh;
+  const T sc = si * ch;
+  const T ss = si * sh;
+  if constexpr (EulerSystem::kIsProperEuler) {
+    R(i, i) = cj;
+    R(i, j) = sj * si;
+    R(i, k) = sj * ci;
+    R(j, i) = sj * sh;
+    R(j, j) = -cj * ss + cc;
+    R(j, k) = -cj * cs - sc;
+    R(k, i) = -sj * ch;
+    R(k, j) = cj * sc + cs;
+    R(k, k) = cj * cc - ss;
+  } else {
+    R(i, i) = cj * ch;
+    R(i, j) = sj * sc - cs;
+    R(i, k) = sj * cc + ss;
+    R(j, i) = cj * sh;
+    R(j, j) = sj * ss + cc;
+    R(j, k) = sj * cs - sc;
+    R(k, i) = -sj;
+    R(k, j) = cj * si;
+    R(k, k) = cj * ci;
+  }
+}
+
+template <typename EulerSystem, typename T>
+inline void RotationMatrixToEulerAngles(const T* R, T* euler) {
+  RotationMatrixToEulerAngles<EulerSystem>(RowMajorAdapter3x3(R), euler);
+}
+
+template <typename EulerSystem, typename T, int row_stride, int col_stride>
+void RotationMatrixToEulerAngles(
+    const MatrixAdapter<const T, row_stride, col_stride>& R, T* euler) {
+  using std::atan2;
+  using std::fpclassify;
+  using std::hypot;
+
+  const auto [i, j, k] = EulerSystem::kAxes;
+
+  T ea[3];
+  if constexpr (EulerSystem::kIsProperEuler) {
+    const T sy = hypot(R(i, j), R(i, k));
+    if (fpclassify(sy) != FP_ZERO) {
+      ea[0] = atan2(R(i, j), R(i, k));
+      ea[1] = atan2(sy, R(i, i));
+      ea[2] = atan2(R(j, i), -R(k, i));
+    } else {
+      ea[0] = atan2(-R(j, k), R(j, j));
+      ea[1] = atan2(sy, R(i, i));
+      ea[2] = T(0.0);
+    }
+  } else {
+    const T cy = hypot(R(i, i), R(j, i));
+    if (fpclassify(cy) != FP_ZERO) {
+      ea[0] = atan2(R(k, j), R(k, k));
+      ea[1] = atan2(-R(k, i), cy);
+      ea[2] = atan2(R(j, i), R(i, i));
+    } else {
+      ea[0] = atan2(-R(j, k), R(j, j));
+      ea[1] = atan2(-R(k, i), cy);
+      ea[2] = T(0.0);
+    }
+  }
+  if constexpr (EulerSystem::kIsParityOdd) {
+    ea[0] = -ea[0];
+    ea[1] = -ea[1];
+    ea[2] = -ea[2];
+  }
+  euler[1] = ea[1];
+  if constexpr (EulerSystem::kIsIntrinsic) {
+    euler[0] = ea[2];
+    euler[2] = ea[0];
+  } else {
+    euler[0] = ea[0];
+    euler[2] = ea[2];
+  }
+
+  // Proper euler angles are defined for angles in
+  //   [-pi, pi) x [0, pi / 2) x [-pi, pi)
+  // which is enforced here
+  if constexpr (EulerSystem::kIsProperEuler) {
+    const T kPi(constants::pi);
+    const T kTwoPi(2.0 * kPi);
+    if (euler[1] < T(0.0) || ea[1] > kPi) {
+      euler[0] += kPi;
+      euler[1] = -euler[1];
+      euler[2] -= kPi;
+    }
+
+    for (int i = 0; i < 3; ++i) {
+      if (euler[i] < -kPi) {
+        euler[i] += kTwoPi;
+      } else if (euler[i] > kPi) {
+        euler[i] -= kTwoPi;
+      }
+    }
+  }
+}
+
 template <typename T>
 inline void EulerAnglesToRotationMatrix(const T* euler,
                                         const int row_stride_parameter,
@@ -521,18 +725,18 @@
   DCHECK_NE(pt, result) << "Inplace rotation is not supported.";
 
   // clang-format off
-  const T t2 =  q[0] * q[1];
-  const T t3 =  q[0] * q[2];
-  const T t4 =  q[0] * q[3];
-  const T t5 = -q[1] * q[1];
-  const T t6 =  q[1] * q[2];
-  const T t7 =  q[1] * q[3];
-  const T t8 = -q[2] * q[2];
-  const T t9 =  q[2] * q[3];
-  const T t1 = -q[3] * q[3];
-  result[0] = T(2) * ((t8 + t1) * pt[0] + (t6 - t4) * pt[1] + (t3 + t7) * pt[2]) + pt[0];  // NOLINT
-  result[1] = T(2) * ((t4 + t6) * pt[0] + (t5 + t1) * pt[1] + (t9 - t2) * pt[2]) + pt[1];  // NOLINT
-  result[2] = T(2) * ((t7 - t3) * pt[0] + (t2 + t9) * pt[1] + (t5 + t8) * pt[2]) + pt[2];  // NOLINT
+  T uv0 = q[2] * pt[2] - q[3] * pt[1];
+  T uv1 = q[3] * pt[0] - q[1] * pt[2];
+  T uv2 = q[1] * pt[1] - q[2] * pt[0];
+  uv0 += uv0;
+  uv1 += uv1;
+  uv2 += uv2;
+  result[0] = pt[0] + q[0] * uv0;
+  result[1] = pt[1] + q[0] * uv1;
+  result[2] = pt[2] + q[0] * uv2;
+  result[0] += q[2] * uv2 - q[3] * uv1;
+  result[1] += q[3] * uv0 - q[1] * uv2;
+  result[2] += q[1] * uv1 - q[2] * uv0;
   // clang-format on
 }
 
@@ -589,9 +793,12 @@
                                  const T pt[3],
                                  T result[3]) {
   DCHECK_NE(pt, result) << "Inplace rotation is not supported.";
+  using std::fpclassify;
+  using std::hypot;
 
-  const T theta2 = DotProduct(angle_axis, angle_axis);
-  if (theta2 > T(std::numeric_limits<double>::epsilon())) {
+  const T theta = hypot(angle_axis[0], angle_axis[1], angle_axis[2]);
+
+  if (fpclassify(theta) != FP_ZERO) {
     // Away from zero, use the rodriguez formula
     //
     //   result = pt costheta +
@@ -602,7 +809,6 @@
     // norm of the angle_axis vector is greater than zero. Otherwise
     // we get a division by zero.
     //
-    const T theta = sqrt(theta2);
     const T costheta = cos(theta);
     const T sintheta = sin(theta);
     const T theta_inverse = T(1.0) / theta;
@@ -623,19 +829,19 @@
     result[1] = pt[1] * costheta + w_cross_pt[1] * sintheta + w[1] * tmp;
     result[2] = pt[2] * costheta + w_cross_pt[2] * sintheta + w[2] * tmp;
   } else {
-    // Near zero, the first order Taylor approximation of the rotation
-    // matrix R corresponding to a vector w and angle w is
+    // At zero, the first order Taylor approximation of the rotation
+    // matrix R corresponding to a vector w and angle theta is
     //
     //   R = I + hat(w) * sin(theta)
     //
     // But sintheta ~ theta and theta * w = angle_axis, which gives us
     //
-    //  R = I + hat(w)
+    //  R = I + hat(angle_axis)
     //
     // and actually performing multiplication with the point pt, gives us
-    // R * pt = pt + w x pt.
+    // R * pt = pt + angle_axis x pt.
     //
-    // Switching to the Taylor expansion near zero provides meaningful
+    // Switching to the Taylor expansion at zero provides meaningful
     // derivatives when evaluated using Jets.
     //
     // Explicitly inlined evaluation of the cross product for
diff --git a/third_party/ceres/include/ceres/sized_cost_function.h b/third_party/ceres/include/ceres/sized_cost_function.h
index 8e92f1b..8928c19 100644
--- a/third_party/ceres/include/ceres/sized_cost_function.h
+++ b/third_party/ceres/include/ceres/sized_cost_function.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2024 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -38,9 +38,10 @@
 #ifndef CERES_PUBLIC_SIZED_COST_FUNCTION_H_
 #define CERES_PUBLIC_SIZED_COST_FUNCTION_H_
 
+#include <initializer_list>
+
 #include "ceres/cost_function.h"
 #include "ceres/types.h"
-#include "glog/logging.h"
 #include "internal/parameter_dims.h"
 
 namespace ceres {
@@ -58,11 +59,9 @@
 
   SizedCostFunction() {
     set_num_residuals(kNumResiduals);
-    *mutable_parameter_block_sizes() = std::vector<int32_t>{Ns...};
+    *mutable_parameter_block_sizes() = std::initializer_list<int32_t>{Ns...};
   }
 
-  virtual ~SizedCostFunction() {}
-
   // Subclasses must implement Evaluate().
 };
 
diff --git a/third_party/ceres/include/ceres/solver.h b/third_party/ceres/include/ceres/solver.h
index 61b8dd5..68438a1 100644
--- a/third_party/ceres/include/ceres/solver.h
+++ b/third_party/ceres/include/ceres/solver.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -38,8 +38,9 @@
 #include <vector>
 
 #include "ceres/crs_matrix.h"
+#include "ceres/internal/config.h"
 #include "ceres/internal/disable_warnings.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 #include "ceres/iteration_callback.h"
 #include "ceres/ordered_groups.h"
 #include "ceres/problem.h"
@@ -63,8 +64,6 @@
     // with a message describing the problem.
     bool IsValid(std::string* error) const;
 
-    // Minimizer options ----------------------------------------
-
     // Ceres supports the two major families of optimization strategies -
     // Trust Region and Line Search.
     //
@@ -363,102 +362,158 @@
     std::unordered_set<ResidualBlockId>
         residual_blocks_for_subset_preconditioner;
 
-    // Ceres supports using multiple dense linear algebra libraries
-    // for dense matrix factorizations. Currently EIGEN and LAPACK are
-    // the valid choices. EIGEN is always available, LAPACK refers to
-    // the system BLAS + LAPACK library which may or may not be
+    // Ceres supports using multiple dense linear algebra libraries for dense
+    // matrix factorizations. Currently EIGEN, LAPACK and CUDA are the valid
+    // choices. EIGEN is always available, LAPACK refers to the system BLAS +
+    // LAPACK library which may or may not be available. CUDA refers to Nvidia's
+    // GPU based dense linear algebra library, which may or may not be
     // available.
     //
-    // This setting affects the DENSE_QR, DENSE_NORMAL_CHOLESKY and
-    // DENSE_SCHUR solvers. For small to moderate sized problem EIGEN
-    // is a fine choice but for large problems, an optimized LAPACK +
-    // BLAS implementation can make a substantial difference in
-    // performance.
+    // This setting affects the DENSE_QR, DENSE_NORMAL_CHOLESKY and DENSE_SCHUR
+    // solvers. For small to moderate sized problem EIGEN is a fine choice but
+    // for large problems, an optimized LAPACK + BLAS or CUDA implementation can
+    // make a substantial difference in performance.
     DenseLinearAlgebraLibraryType dense_linear_algebra_library_type = EIGEN;
 
-    // Ceres supports using multiple sparse linear algebra libraries
-    // for sparse matrix ordering and factorizations. Currently,
-    // SUITE_SPARSE and CX_SPARSE are the valid choices, depending on
-    // whether they are linked into Ceres at build time.
+    // Ceres supports using multiple sparse linear algebra libraries for sparse
+    // matrix ordering and factorizations.
     SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type =
 #if !defined(CERES_NO_SUITESPARSE)
         SUITE_SPARSE;
-#elif defined(CERES_USE_EIGEN_SPARSE)
-        EIGEN_SPARSE;
-#elif !defined(CERES_NO_CXSPARSE)
-        CX_SPARSE;
 #elif !defined(CERES_NO_ACCELERATE_SPARSE)
         ACCELERATE_SPARSE;
+#elif defined(CERES_USE_EIGEN_SPARSE)
+        EIGEN_SPARSE;
 #else
         NO_SPARSE;
 #endif
 
     // The order in which variables are eliminated in a linear solver
-    // can have a significant of impact on the efficiency and accuracy
-    // of the method. e.g., when doing sparse Cholesky factorization,
+    // can have a significant impact on the efficiency and accuracy of
+    // the method. e.g., when doing sparse Cholesky factorization,
     // there are matrices for which a good ordering will give a
     // Cholesky factor with O(n) storage, where as a bad ordering will
     // result in an completely dense factor.
     //
-    // Ceres allows the user to provide varying amounts of hints to
-    // the solver about the variable elimination ordering to use. This
-    // can range from no hints, where the solver is free to decide the
-    // best possible ordering based on the user's choices like the
-    // linear solver being used, to an exact order in which the
-    // variables should be eliminated, and a variety of possibilities
-    // in between.
+    // Sparse direct solvers like SPARSE_NORMAL_CHOLESKY and
+    // SPARSE_SCHUR use a fill reducing ordering of the columns and
+    // rows of the matrix being factorized before computing the
+    // numeric factorization.
     //
-    // Instances of the ParameterBlockOrdering class are used to
-    // communicate this information to Ceres.
+    // This enum controls the type of algorithm used to compute
+    // this fill reducing ordering. There is no single algorithm
+    // that works on all matrices, so determining which algorithm
+    // works better is a matter of empirical experimentation.
     //
-    // Formally an ordering is an ordered partitioning of the
-    // parameter blocks, i.e, each parameter block belongs to exactly
-    // one group, and each group has a unique non-negative integer
-    // associated with it, that determines its order in the set of
-    // groups.
+    // The exact behaviour of this setting is affected by the value of
+    // linear_solver_ordering as described below.
+    LinearSolverOrderingType linear_solver_ordering_type = AMD;
+
+    // Besides specifying the fill reducing ordering via
+    // linear_solver_ordering_type, Ceres allows the user to provide varying
+    // amounts of hints to the linear solver about the variable elimination
+    // ordering to use. This can range from no hints, where the solver is free
+    // to decide the best possible ordering based on the user's choices like the
+    // linear solver being used, to an exact order in which the variables should
+    // be eliminated, and a variety of possibilities in between.
     //
-    // Given such an ordering, Ceres ensures that the parameter blocks in
-    // the lowest numbered group are eliminated first, and then the
-    // parameter blocks in the next lowest numbered group and so on. Within
-    // each group, Ceres is free to order the parameter blocks as it
-    // chooses.
+    // Instances of the ParameterBlockOrdering class are used to communicate
+    // this information to Ceres.
     //
-    // If NULL, then all parameter blocks are assumed to be in the
-    // same group and the solver is free to decide the best
-    // ordering.
+    // Formally an ordering is an ordered partitioning of the parameter blocks,
+    // i.e, each parameter block belongs to exactly one group, and each group
+    // has a unique non-negative integer associated with it, that determines its
+    // order in the set of groups.
     //
     // e.g. Consider the linear system
     //
     //   x + y = 3
     //   2x + 3y = 7
     //
-    // There are two ways in which it can be solved. First eliminating x
-    // from the two equations, solving for y and then back substituting
-    // for x, or first eliminating y, solving for x and back substituting
-    // for y. The user can construct three orderings here.
+    // There are two ways in which it can be solved. First eliminating x from
+    // the two equations, solving for y and then back substituting for x, or
+    // first eliminating y, solving for x and back substituting for y. The user
+    // can construct three orderings here.
     //
     //   {0: x}, {1: y} - eliminate x first.
     //   {0: y}, {1: x} - eliminate y first.
     //   {0: x, y}      - Solver gets to decide the elimination order.
     //
-    // Thus, to have Ceres determine the ordering automatically using
-    // heuristics, put all the variables in group 0 and to control the
-    // ordering for every variable, create groups 0..N-1, one per
-    // variable, in the desired order.
+    // Thus, to have Ceres determine the ordering automatically, put all the
+    // variables in group 0 and to control the ordering for every variable
+    // create groups 0 ... N-1, one per variable, in the desired
+    // order.
+    //
+    // linear_solver_ordering == nullptr and an ordering where all the parameter
+    // blocks are in one elimination group mean the same thing - the solver is
+    // free to choose what it thinks is the best elimination ordering. Therefore
+    // in the following we will only consider the case where
+    // linear_solver_ordering is nullptr.
+    //
+    // The exact interpretation of this information depends on the values of
+    // linear_solver_ordering_type and linear_solver_type/preconditioner_type
+    // and sparse_linear_algebra_type.
     //
     // Bundle Adjustment
-    // -----------------
+    // =================
     //
-    // A particular case of interest is bundle adjustment, where the user
-    // has two options. The default is to not specify an ordering at all,
-    // the solver will see that the user wants to use a Schur type solver
-    // and figure out the right elimination ordering.
+    // If the user is using one of the Schur solvers (DENSE_SCHUR,
+    // SPARSE_SCHUR, ITERATIVE_SCHUR) and chooses to specify an
+    // ordering, it must have one important property. The lowest
+    // numbered elimination group must form an independent set in the
+    // graph corresponding to the Hessian, or in other words, no two
+    // parameter blocks in in the first elimination group should
+    // co-occur in the same residual block. For the best performance,
+    // this elimination group should be as large as possible. For
+    // standard bundle adjustment problems, this corresponds to the
+    // first elimination group containing all the 3d points, and the
+    // second containing the all the cameras parameter blocks.
     //
-    // But if the user already knows what parameter blocks are points and
-    // what are cameras, they can save preprocessing time by partitioning
-    // the parameter blocks into two groups, one for the points and one
-    // for the cameras, where the group containing the points has an id
-    // smaller than the group containing cameras.
+    // If the user leaves the choice to Ceres, then the solver uses an
+    // approximate maximum independent set algorithm to identify the first
+    // elimination group.
+    //
+    // sparse_linear_algebra_library_type = SUITE_SPARSE
+    // =================================================
+    //
+    // linear_solver_ordering_type = AMD
+    // ---------------------------------
+    //
+    // A Constrained Approximate Minimum Degree (CAMD) ordering used where the
+    // parameter blocks in the lowest numbered group are eliminated first, and
+    // then the parameter blocks in the next lowest numbered group and so
+    // on. Within each group, CAMD free to order the parameter blocks as it
+    // chooses.
+    //
+    // linear_solver_ordering_type = NESDIS
+    // -------------------------------------
+    //
+    // a. linear_solver_type = SPARSE_NORMAL_CHOLESKY or
+    //    linear_solver_type = CGNR and preconditioner_type = SUBSET
+    //
+    // The value of linear_solver_ordering is ignored and a Nested Dissection
+    // algorithm is used to compute a fill reducing ordering.
+    //
+    // b. linear_solver_type = SPARSE_SCHUR/DENSE_SCHUR/ITERATIVE_SCHUR
+    //
+    // ONLY the lowest group are used to compute the Schur complement, and
+    // Nested Dissection is used to compute a fill reducing ordering for the
+    // Schur Complement (or its preconditioner).
+    //
+    // sparse_linear_algebra_library_type = EIGEN_SPARSE or ACCELERATE_SPARSE
+    // ======================================================================
+    //
+    // a. linear_solver_type = SPARSE_NORMAL_CHOLESKY or
+    //    linear_solver_type = CGNR and preconditioner_type = SUBSET
+    //
+    // then the value of linear_solver_ordering is ignored and AMD or NESDIS is
+    // used to compute a fill reducing ordering as requested by the user.
+    //
+    // b. linear_solver_type = SPARSE_SCHUR/DENSE_SCHUR/ITERATIVE_SCHUR
+    //
+    // ONLY the lowest group are used to compute the Schur complement, and AMD
+    // or NESDIS is used to compute a fill reducing ordering for the Schur
+    // Complement (or its preconditioner).
     std::shared_ptr<ParameterBlockOrdering> linear_solver_ordering;
 
     // Use an explicitly computed Schur complement matrix with
@@ -499,12 +554,6 @@
     // Jacobian matrix and generally speaking, there is no performance
     // penalty for doing so.
 
-    // In some rare cases, it is worth using a more complicated
-    // reordering algorithm which has slightly better runtime
-    // performance at the expense of an extra copy of the Jacobian
-    // matrix. Setting use_postordering to true enables this tradeoff.
-    bool use_postordering = false;
-
     // Some non-linear least squares problems are symbolically dense but
     // numerically sparse. i.e. at any given state only a small number
     // of jacobian entries are non-zero, but the position and number of
@@ -520,11 +569,6 @@
     // This settings only affects the SPARSE_NORMAL_CHOLESKY solver.
     bool dynamic_sparsity = false;
 
-    // TODO(sameeragarwal): Further expand the documentation for the
-    // following two options.
-
-    // NOTE1: EXPERIMENTAL FEATURE, UNDER DEVELOPMENT, USE AT YOUR OWN RISK.
-    //
     // If use_mixed_precision_solves is true, the Gauss-Newton matrix
     // is computed in double precision, but its factorization is
     // computed in single precision. This can result in significant
@@ -535,15 +579,57 @@
     // If use_mixed_precision_solves is true, we recommend setting
     // max_num_refinement_iterations to 2-3.
     //
-    // NOTE2: The following two options are currently only applicable
-    // if sparse_linear_algebra_library_type is EIGEN_SPARSE and
-    // linear_solver_type is SPARSE_NORMAL_CHOLESKY, or SPARSE_SCHUR.
+    // This options is available when linear solver uses sparse or dense
+    // cholesky factorization, except when sparse_linear_algebra_library_type =
+    // SUITE_SPARSE.
     bool use_mixed_precision_solves = false;
 
     // Number steps of the iterative refinement process to run when
     // computing the Gauss-Newton step.
     int max_num_refinement_iterations = 0;
 
+    // Minimum number of iterations for which the linear solver should
+    // run, even if the convergence criterion is satisfied.
+    int min_linear_solver_iterations = 0;
+
+    // Maximum number of iterations for which the linear solver should
+    // run. If the solver does not converge in less than
+    // max_linear_solver_iterations, then it returns MAX_ITERATIONS,
+    // as its termination type.
+    int max_linear_solver_iterations = 500;
+
+    // Maximum number of iterations performed by SCHUR_POWER_SERIES_EXPANSION.
+    // Each iteration corresponds to one more term in the power series expansion
+    // od the inverse of the Schur complement.  This value controls the maximum
+    // number of iterations whether it is used as a preconditioner or just to
+    // initialize the solution for ITERATIVE_SCHUR.
+    int max_num_spse_iterations = 5;
+
+    // Use SCHUR_POWER_SERIES_EXPANSION to initialize the solution for
+    // ITERATIVE_SCHUR. This option can be set true regardless of what
+    // preconditioner is being used.
+    bool use_spse_initialization = false;
+
+    // When use_spse_initialization is true, this parameter along with
+    // max_num_spse_iterations controls the number of
+    // SCHUR_POWER_SERIES_EXPANSION iterations performed for initialization. It
+    // is not used to control the preconditioner.
+    double spse_tolerance = 0.1;
+
+    // Forcing sequence parameter. The truncated Newton solver uses
+    // this number to control the relative accuracy with which the
+    // Newton step is computed.
+    //
+    // This constant is passed to ConjugateGradientsSolver which uses
+    // it to terminate the iterations when
+    //
+    //  (Q_i - Q_{i-1})/Q_i < eta/i
+    double eta = 1e-1;
+
+    // Normalize the jacobian using Jacobi scaling before calling
+    // the linear least squares solver.
+    bool jacobi_scaling = true;
+
     // Some non-linear least squares problems have additional
     // structure in the way the parameter blocks interact that it is
     // beneficial to modify the way the trust region step is computed.
@@ -627,32 +713,6 @@
     // iterations is disabled.
     double inner_iteration_tolerance = 1e-3;
 
-    // Minimum number of iterations for which the linear solver should
-    // run, even if the convergence criterion is satisfied.
-    int min_linear_solver_iterations = 0;
-
-    // Maximum number of iterations for which the linear solver should
-    // run. If the solver does not converge in less than
-    // max_linear_solver_iterations, then it returns MAX_ITERATIONS,
-    // as its termination type.
-    int max_linear_solver_iterations = 500;
-
-    // Forcing sequence parameter. The truncated Newton solver uses
-    // this number to control the relative accuracy with which the
-    // Newton step is computed.
-    //
-    // This constant is passed to ConjugateGradientsSolver which uses
-    // it to terminate the iterations when
-    //
-    //  (Q_i - Q_{i-1})/Q_i < eta/i
-    double eta = 1e-1;
-
-    // Normalize the jacobian using Jacobi scaling before calling
-    // the linear least squares solver.
-    bool jacobi_scaling = true;
-
-    // Logging options ---------------------------------------------------------
-
     LoggingType logging_type = PER_MINIMIZER_ITERATION;
 
     // By default the Minimizer progress is logged to VLOG(1), which
@@ -789,10 +849,9 @@
     // IterationSummary for each minimizer iteration in order.
     std::vector<IterationSummary> iterations;
 
-    // Number of minimizer iterations in which the step was
-    // accepted. Unless use_non_monotonic_steps is true this is also
-    // the number of steps in which the objective function value/cost
-    // went down.
+    // Number of minimizer iterations in which the step was accepted. Unless
+    // use_nonmonotonic_steps is true this is also the number of steps in which
+    // the objective function value/cost went down.
     int num_successful_steps = -1;
 
     // Number of minimizer iterations in which the step was rejected
@@ -882,7 +941,7 @@
     // Dimension of the tangent space of the problem (or the number of
     // columns in the Jacobian for the problem). This is different
     // from num_parameters if a parameter block is associated with a
-    // LocalParameterization
+    // Manifold.
     int num_effective_parameters = -1;
 
     // Number of residual blocks in the problem.
@@ -903,7 +962,7 @@
     // number of columns in the Jacobian for the reduced
     // problem). This is different from num_parameters_reduced if a
     // parameter block in the reduced problem is associated with a
-    // LocalParameterization.
+    // Manifold.
     int num_effective_parameters_reduced = -1;
 
     // Number of residual blocks in the reduced problem.
@@ -920,8 +979,7 @@
     int num_threads_given = -1;
 
     // Number of threads actually used by the solver for Jacobian and
-    // residual evaluation. This number is not equal to
-    // num_threads_given if OpenMP is not available.
+    // residual evaluation.
     int num_threads_used = -1;
 
     // Type of the linear solver requested by the user.
@@ -944,6 +1002,10 @@
         SPARSE_NORMAL_CHOLESKY;
 #endif
 
+    bool mixed_precision_solves_used = false;
+
+    LinearSolverOrderingType linear_solver_ordering_type = AMD;
+
     // Size of the elimination groups given by the user as hints to
     // the linear solver.
     std::vector<int> linear_solver_ordering_given;
@@ -1003,7 +1065,7 @@
     PreconditionerType preconditioner_type_used = IDENTITY;
 
     // Type of clustering algorithm used for visibility based
-    // preconditioning. Only meaningful when the preconditioner_type
+    // preconditioning. Only meaningful when the preconditioner_type_used
     // is CLUSTER_JACOBI or CLUSTER_TRIDIAGONAL.
     VisibilityClusteringType visibility_clustering_type = CANONICAL_VIEWS;
 
diff --git a/third_party/ceres/include/ceres/sphere_manifold.h b/third_party/ceres/include/ceres/sphere_manifold.h
new file mode 100644
index 0000000..1c7458b
--- /dev/null
+++ b/third_party/ceres/include/ceres/sphere_manifold.h
@@ -0,0 +1,236 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: vitus@google.com (Mike Vitus)
+//         jodebo_beck@gmx.de (Johannes Beck)
+
+#ifndef CERES_PUBLIC_SPHERE_MANIFOLD_H_
+#define CERES_PUBLIC_SPHERE_MANIFOLD_H_
+
+#include <Eigen/Core>
+#include <algorithm>
+#include <array>
+#include <memory>
+#include <vector>
+
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
+#include "ceres/internal/householder_vector.h"
+#include "ceres/internal/sphere_manifold_functions.h"
+#include "ceres/manifold.h"
+#include "ceres/types.h"
+#include "glog/logging.h"
+
+namespace ceres {
+
+// This provides a manifold on a sphere meaning that the norm of the vector
+// stays the same. Such cases often arises in Structure for Motion
+// problems. One example where they are used is in representing points whose
+// triangulation is ill-conditioned. Here it is advantageous to use an
+// over-parameterization since homogeneous vectors can represent points at
+// infinity.
+//
+// The plus operator is defined as
+//  Plus(x, delta) =
+//    [sin(0.5 * |delta|) * delta / |delta|, cos(0.5 * |delta|)] * x
+//
+// The minus operator is defined as
+//  Minus(x, y) = 2 atan2(nhy, y[-1]) / nhy * hy[0 : size_ - 1]
+// with nhy = norm(hy[0 : size_ - 1])
+//
+// with * defined as an operator which applies the update orthogonal to x to
+// remain on the sphere. The ambient space dimension is required to be greater
+// than 1.
+//
+// The class works with dynamic and static ambient space dimensions. If the
+// ambient space dimensions is known at compile time use
+//
+//    SphereManifold<3> manifold;
+//
+// If the ambient space dimensions is not known at compile time the template
+// parameter needs to be set to ceres::DYNAMIC and the actual dimension needs
+// to be provided as a constructor argument:
+//
+//    SphereManifold<ceres::DYNAMIC> manifold(ambient_dim);
+//
+// See  section B.2 (p.25) in "Integrating Generic Sensor Fusion Algorithms
+// with Sound State Representations through Encapsulation of Manifolds" by C.
+// Hertzberg, R. Wagner, U. Frese and L. Schroder for more details
+// (https://arxiv.org/pdf/1107.1119.pdf)
+template <int AmbientSpaceDimension>
+class SphereManifold final : public Manifold {
+ public:
+  static_assert(
+      AmbientSpaceDimension == ceres::DYNAMIC || AmbientSpaceDimension > 1,
+      "The size of the homogeneous vector needs to be greater than 1.");
+  static_assert(ceres::DYNAMIC == Eigen::Dynamic,
+                "ceres::DYNAMIC needs to be the same as Eigen::Dynamic.");
+
+  SphereManifold();
+  explicit SphereManifold(int size);
+
+  int AmbientSize() const override {
+    return AmbientSpaceDimension == ceres::DYNAMIC ? size_
+                                                   : AmbientSpaceDimension;
+  }
+  int TangentSize() const override { return AmbientSize() - 1; }
+
+  bool Plus(const double* x,
+            const double* delta,
+            double* x_plus_delta) const override;
+  bool PlusJacobian(const double* x, double* jacobian) const override;
+
+  bool Minus(const double* y,
+             const double* x,
+             double* y_minus_x) const override;
+  bool MinusJacobian(const double* x, double* jacobian) const override;
+
+ private:
+  static constexpr int TangentSpaceDimension =
+      AmbientSpaceDimension > 0 ? AmbientSpaceDimension - 1 : Eigen::Dynamic;
+
+  // NOTE: Eigen does not allow to have a RowMajor column vector.
+  // In that case, change the storage order
+  static constexpr int SafeRowMajor =
+      TangentSpaceDimension == 1 ? Eigen::ColMajor : Eigen::RowMajor;
+
+  using AmbientVector = Eigen::Matrix<double, AmbientSpaceDimension, 1>;
+  using TangentVector = Eigen::Matrix<double, TangentSpaceDimension, 1>;
+  using MatrixPlusJacobian = Eigen::Matrix<double,
+                                           AmbientSpaceDimension,
+                                           TangentSpaceDimension,
+                                           SafeRowMajor>;
+  using MatrixMinusJacobian = Eigen::Matrix<double,
+                                            TangentSpaceDimension,
+                                            AmbientSpaceDimension,
+                                            Eigen::RowMajor>;
+
+  const int size_{};
+};
+
+template <int AmbientSpaceDimension>
+SphereManifold<AmbientSpaceDimension>::SphereManifold()
+    : size_{AmbientSpaceDimension} {
+  static_assert(
+      AmbientSpaceDimension != Eigen::Dynamic,
+      "The size is set to dynamic. Please call the constructor with a size.");
+}
+
+template <int AmbientSpaceDimension>
+SphereManifold<AmbientSpaceDimension>::SphereManifold(int size) : size_{size} {
+  if (AmbientSpaceDimension != Eigen::Dynamic) {
+    CHECK_EQ(AmbientSpaceDimension, size)
+        << "Specified size by template parameter differs from the supplied "
+           "one.";
+  } else {
+    CHECK_GT(size_, 1)
+        << "The size of the manifold needs to be greater than 1.";
+  }
+}
+
+template <int AmbientSpaceDimension>
+bool SphereManifold<AmbientSpaceDimension>::Plus(
+    const double* x_ptr,
+    const double* delta_ptr,
+    double* x_plus_delta_ptr) const {
+  Eigen::Map<const AmbientVector> x(x_ptr, size_);
+  Eigen::Map<const TangentVector> delta(delta_ptr, size_ - 1);
+  Eigen::Map<AmbientVector> x_plus_delta(x_plus_delta_ptr, size_);
+
+  const double norm_delta = delta.norm();
+
+  if (norm_delta == 0.0) {
+    x_plus_delta = x;
+    return true;
+  }
+
+  AmbientVector v(size_);
+  double beta;
+
+  // NOTE: The explicit template arguments are needed here because
+  // ComputeHouseholderVector is templated and some versions of MSVC
+  // have trouble deducing the type of v automatically.
+  internal::ComputeHouseholderVector<Eigen::Map<const AmbientVector>,
+                                     double,
+                                     AmbientSpaceDimension>(x, &v, &beta);
+
+  internal::ComputeSphereManifoldPlus(
+      v, beta, x, delta, norm_delta, &x_plus_delta);
+
+  return true;
+}
+
+template <int AmbientSpaceDimension>
+bool SphereManifold<AmbientSpaceDimension>::PlusJacobian(
+    const double* x_ptr, double* jacobian_ptr) const {
+  Eigen::Map<const AmbientVector> x(x_ptr, size_);
+  Eigen::Map<MatrixPlusJacobian> jacobian(jacobian_ptr, size_, size_ - 1);
+  internal::ComputeSphereManifoldPlusJacobian(x, &jacobian);
+
+  return true;
+}
+
+template <int AmbientSpaceDimension>
+bool SphereManifold<AmbientSpaceDimension>::Minus(const double* y_ptr,
+                                                  const double* x_ptr,
+                                                  double* y_minus_x_ptr) const {
+  AmbientVector y = Eigen::Map<const AmbientVector>(y_ptr, size_);
+  Eigen::Map<const AmbientVector> x(x_ptr, size_);
+  Eigen::Map<TangentVector> y_minus_x(y_minus_x_ptr, size_ - 1);
+
+  // Apply hoseholder transformation.
+  AmbientVector v(size_);
+  double beta;
+
+  // NOTE: The explicit template arguments are needed here because
+  // ComputeHouseholderVector is templated and some versions of MSVC
+  // have trouble deducing the type of v automatically.
+  internal::ComputeHouseholderVector<Eigen::Map<const AmbientVector>,
+                                     double,
+                                     AmbientSpaceDimension>(x, &v, &beta);
+  internal::ComputeSphereManifoldMinus(v, beta, x, y, &y_minus_x);
+  return true;
+}
+
+template <int AmbientSpaceDimension>
+bool SphereManifold<AmbientSpaceDimension>::MinusJacobian(
+    const double* x_ptr, double* jacobian_ptr) const {
+  Eigen::Map<const AmbientVector> x(x_ptr, size_);
+  Eigen::Map<MatrixMinusJacobian> jacobian(jacobian_ptr, size_ - 1, size_);
+
+  internal::ComputeSphereManifoldMinusJacobian(x, &jacobian);
+  return true;
+}
+
+}  // namespace ceres
+
+// clang-format off
+#include "ceres/internal/reenable_warnings.h"
+// clang-format on
+
+#endif  // CERES_PUBLIC_SPHERE_MANIFOLD_H_
diff --git a/third_party/ceres/include/ceres/tiny_solver.h b/third_party/ceres/include/ceres/tiny_solver.h
index 47db582..9242cd0 100644
--- a/third_party/ceres/include/ceres/tiny_solver.h
+++ b/third_party/ceres/include/ceres/tiny_solver.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -84,7 +84,8 @@
 //   double* parameters -- NUM_PARAMETERS or NumParameters()
 //   double* residuals  -- NUM_RESIDUALS or NumResiduals()
 //   double* jacobian   -- NUM_RESIDUALS * NUM_PARAMETERS in column-major format
-//                         (Eigen's default); or NULL if no jacobian requested.
+//                         (Eigen's default); or nullptr if no jacobian
+//                         requested.
 //
 // An example (fully statically sized):
 //
@@ -126,8 +127,8 @@
 //
 template <typename Function,
           typename LinearSolver =
-              Eigen::LDLT<Eigen::Matrix<typename Function::Scalar,
-                                        Function::NUM_PARAMETERS,
+              Eigen::LDLT<Eigen::Matrix<typename Function::Scalar,  //
+                                        Function::NUM_PARAMETERS,   //
                                         Function::NUM_PARAMETERS>>>
 class TinySolver {
  public:
@@ -139,41 +140,59 @@
     NUM_RESIDUALS = Function::NUM_RESIDUALS,
     NUM_PARAMETERS = Function::NUM_PARAMETERS
   };
-  typedef typename Function::Scalar Scalar;
-  typedef typename Eigen::Matrix<Scalar, NUM_PARAMETERS, 1> Parameters;
+  using Scalar = typename Function::Scalar;
+  using Parameters = typename Eigen::Matrix<Scalar, NUM_PARAMETERS, 1>;
 
   enum Status {
-    GRADIENT_TOO_SMALL,            // eps > max(J'*f(x))
-    RELATIVE_STEP_SIZE_TOO_SMALL,  // eps > ||dx|| / (||x|| + eps)
-    COST_TOO_SMALL,                // eps > ||f(x)||^2 / 2
+    // max_norm |J'(x) * f(x)| < gradient_tolerance
+    GRADIENT_TOO_SMALL,
+    //  ||dx|| <= parameter_tolerance * (||x|| + parameter_tolerance)
+    RELATIVE_STEP_SIZE_TOO_SMALL,
+    // cost_threshold > ||f(x)||^2 / 2
+    COST_TOO_SMALL,
+    // num_iterations >= max_num_iterations
     HIT_MAX_ITERATIONS,
+    // (new_cost - old_cost) < function_tolerance * old_cost
+    COST_CHANGE_TOO_SMALL,
 
     // TODO(sameeragarwal): Deal with numerical failures.
   };
 
   struct Options {
-    Scalar gradient_tolerance = 1e-10;  // eps > max(J'*f(x))
-    Scalar parameter_tolerance = 1e-8;  // eps > ||dx|| / ||x||
-    Scalar cost_threshold =             // eps > ||f(x)||
-        std::numeric_limits<Scalar>::epsilon();
-    Scalar initial_trust_region_radius = 1e4;
     int max_num_iterations = 50;
+
+    // max_norm |J'(x) * f(x)| < gradient_tolerance
+    Scalar gradient_tolerance = 1e-10;
+
+    //  ||dx|| <= parameter_tolerance * (||x|| + parameter_tolerance)
+    Scalar parameter_tolerance = 1e-8;
+
+    // (new_cost - old_cost) < function_tolerance * old_cost
+    Scalar function_tolerance = 1e-6;
+
+    // cost_threshold > ||f(x)||^2 / 2
+    Scalar cost_threshold = std::numeric_limits<Scalar>::epsilon();
+
+    Scalar initial_trust_region_radius = 1e4;
   };
 
   struct Summary {
-    Scalar initial_cost = -1;       // 1/2 ||f(x)||^2
-    Scalar final_cost = -1;         // 1/2 ||f(x)||^2
-    Scalar gradient_max_norm = -1;  // max(J'f(x))
+    // 1/2 ||f(x_0)||^2
+    Scalar initial_cost = -1;
+    // 1/2 ||f(x)||^2
+    Scalar final_cost = -1;
+    // max_norm(J'f(x))
+    Scalar gradient_max_norm = -1;
     int iterations = -1;
     Status status = HIT_MAX_ITERATIONS;
   };
 
   bool Update(const Function& function, const Parameters& x) {
-    if (!function(x.data(), error_.data(), jacobian_.data())) {
+    if (!function(x.data(), residuals_.data(), jacobian_.data())) {
       return false;
     }
 
-    error_ = -error_;
+    residuals_ = -residuals_;
 
     // On the first iteration, compute a diagonal (Jacobi) scaling
     // matrix, which we store as a vector.
@@ -192,9 +211,9 @@
     // factorization.
     jacobian_ = jacobian_ * jacobi_scaling_.asDiagonal();
     jtj_ = jacobian_.transpose() * jacobian_;
-    g_ = jacobian_.transpose() * error_;
+    g_ = jacobian_.transpose() * residuals_;
     summary.gradient_max_norm = g_.array().abs().maxCoeff();
-    cost_ = error_.squaredNorm() / 2;
+    cost_ = residuals_.squaredNorm() / 2;
     return true;
   }
 
@@ -229,10 +248,9 @@
       jtj_regularized_ = jtj_;
       const Scalar min_diagonal = 1e-6;
       const Scalar max_diagonal = 1e32;
-      for (int i = 0; i < lm_diagonal_.rows(); ++i) {
-        lm_diagonal_[i] = std::sqrt(
-            u * std::min(std::max(jtj_(i, i), min_diagonal), max_diagonal));
-        jtj_regularized_(i, i) += lm_diagonal_[i] * lm_diagonal_[i];
+      for (int i = 0; i < dx_.rows(); ++i) {
+        jtj_regularized_(i, i) +=
+            u * (std::min)((std::max)(jtj_(i, i), min_diagonal), max_diagonal);
       }
 
       // TODO(sameeragarwal): Check for failure and deal with it.
@@ -253,10 +271,9 @@
 
       // TODO(keir): Add proper handling of errors from user eval of cost
       // functions.
-      function(&x_new_[0], &f_x_new_[0], NULL);
+      function(&x_new_[0], &f_x_new_[0], nullptr);
 
       const Scalar cost_change = (2 * cost_ - f_x_new_.squaredNorm());
-
       // TODO(sameeragarwal): Better more numerically stable evaluation.
       const Scalar model_cost_change = lm_step_.dot(2 * g_ - jtj_ * lm_step_);
 
@@ -269,6 +286,12 @@
         // model fits well.
         x = x_new_;
 
+        if (std::abs(cost_change) < options.function_tolerance) {
+          cost_ = f_x_new_.squaredNorm() / 2;
+          summary.status = COST_CHANGE_TOO_SMALL;
+          break;
+        }
+
         // TODO(sameeragarwal): Deal with failure.
         Update(function, x);
         if (summary.gradient_max_norm < options.gradient_tolerance) {
@@ -282,16 +305,24 @@
         }
 
         Scalar tmp = Scalar(2 * rho - 1);
-        u = u * std::max(1 / 3., 1 - tmp * tmp * tmp);
+        u = u * (std::max)(Scalar(1 / 3.), Scalar(1) - tmp * tmp * tmp);
         v = 2;
-        continue;
-      }
 
-      // Reject the update because either the normal equations failed to solve
-      // or the local linear model was not good (rho < 0). Instead, increase u
-      // to move closer to gradient descent.
-      u *= v;
-      v *= 2;
+      } else {
+        // Reject the update because either the normal equations failed to solve
+        // or the local linear model was not good (rho < 0).
+
+        // Additionally if the cost change is too small, then terminate.
+        if (std::abs(cost_change) < options.function_tolerance) {
+          // Terminate
+          summary.status = COST_CHANGE_TOO_SMALL;
+          break;
+        }
+
+        // Reduce the size of the trust region.
+        u *= v;
+        v *= 2;
+      }
     }
 
     summary.final_cost = cost_;
@@ -306,8 +337,8 @@
   // linear system. This allows reusing the intermediate storage across solves.
   LinearSolver linear_solver_;
   Scalar cost_;
-  Parameters dx_, x_new_, g_, jacobi_scaling_, lm_diagonal_, lm_step_;
-  Eigen::Matrix<Scalar, NUM_RESIDUALS, 1> error_, f_x_new_;
+  Parameters dx_, x_new_, g_, jacobi_scaling_, lm_step_;
+  Eigen::Matrix<Scalar, NUM_RESIDUALS, 1> residuals_, f_x_new_;
   Eigen::Matrix<Scalar, NUM_RESIDUALS, NUM_PARAMETERS> jacobian_;
   Eigen::Matrix<Scalar, NUM_PARAMETERS, NUM_PARAMETERS> jtj_, jtj_regularized_;
 
@@ -317,7 +348,7 @@
 
   template <typename T>
   struct enable_if<true, T> {
-    typedef T type;
+    using type = T;
   };
 
   // The number of parameters and residuals are dynamically sized.
@@ -353,9 +384,8 @@
     x_new_.resize(num_parameters);
     g_.resize(num_parameters);
     jacobi_scaling_.resize(num_parameters);
-    lm_diagonal_.resize(num_parameters);
     lm_step_.resize(num_parameters);
-    error_.resize(num_residuals);
+    residuals_.resize(num_residuals);
     f_x_new_.resize(num_residuals);
     jacobian_.resize(num_residuals, num_parameters);
     jtj_.resize(num_parameters, num_parameters);
diff --git a/third_party/ceres/include/ceres/tiny_solver_autodiff_function.h b/third_party/ceres/include/ceres/tiny_solver_autodiff_function.h
index b782f54..1b9bd96 100644
--- a/third_party/ceres/include/ceres/tiny_solver_autodiff_function.h
+++ b/third_party/ceres/include/ceres/tiny_solver_autodiff_function.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -113,12 +113,12 @@
   // as a member a Jet type, which itself has a fixed-size Eigen type as member.
   EIGEN_MAKE_ALIGNED_OPERATOR_NEW
 
-  TinySolverAutoDiffFunction(const CostFunctor& cost_functor)
+  explicit TinySolverAutoDiffFunction(const CostFunctor& cost_functor)
       : cost_functor_(cost_functor) {
     Initialize<kNumResiduals>(cost_functor);
   }
 
-  typedef T Scalar;
+  using Scalar = T;
   enum {
     NUM_PARAMETERS = kNumParameters,
     NUM_RESIDUALS = kNumResiduals,
@@ -127,7 +127,7 @@
   // This is similar to AutoDifferentiate(), but since there is only one
   // parameter block it is easier to inline to avoid overhead.
   bool operator()(const T* parameters, T* residuals, T* jacobian) const {
-    if (jacobian == NULL) {
+    if (jacobian == nullptr) {
       // No jacobian requested, so just directly call the cost function with
       // doubles, skipping jets and derivatives.
       return cost_functor_(parameters, residuals);
@@ -171,7 +171,7 @@
   const CostFunctor& cost_functor_;
 
   // The number of residuals at runtime.
-  // This will be overriden if NUM_RESIDUALS == Eigen::Dynamic.
+  // This will be overridden if NUM_RESIDUALS == Eigen::Dynamic.
   int num_residuals_ = kNumResiduals;
 
   // To evaluate the cost function with jets, temporary storage is needed. These
diff --git a/third_party/ceres/include/ceres/tiny_solver_cost_function_adapter.h b/third_party/ceres/include/ceres/tiny_solver_cost_function_adapter.h
index 18ccb39..166f03f 100644
--- a/third_party/ceres/include/ceres/tiny_solver_cost_function_adapter.h
+++ b/third_party/ceres/include/ceres/tiny_solver_cost_function_adapter.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -75,7 +75,7 @@
           int kNumParameters = Eigen::Dynamic>
 class TinySolverCostFunctionAdapter {
  public:
-  typedef double Scalar;
+  using Scalar = double;
   enum ComponentSizeType {
     NUM_PARAMETERS = kNumParameters,
     NUM_RESIDUALS = kNumResiduals
@@ -85,7 +85,7 @@
   // fixed-size Eigen types.
   EIGEN_MAKE_ALIGNED_OPERATOR_NEW
 
-  TinySolverCostFunctionAdapter(const CostFunction& cost_function)
+  explicit TinySolverCostFunctionAdapter(const CostFunction& cost_function)
       : cost_function_(cost_function) {
     CHECK_EQ(cost_function_.parameter_block_sizes().size(), 1)
         << "Only CostFunctions with exactly one parameter blocks are allowed.";
@@ -108,7 +108,7 @@
                   double* residuals,
                   double* jacobian) const {
     if (!jacobian) {
-      return cost_function_.Evaluate(&parameters, residuals, NULL);
+      return cost_function_.Evaluate(&parameters, residuals, nullptr);
     }
 
     double* jacobians[1] = {row_major_jacobian_.data()};
diff --git a/third_party/ceres/include/ceres/types.h b/third_party/ceres/include/ceres/types.h
index 5ee6fdc..6e19c51 100644
--- a/third_party/ceres/include/ceres/types.h
+++ b/third_party/ceres/include/ceres/types.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,7 +40,7 @@
 #include <string>
 
 #include "ceres/internal/disable_warnings.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 
 namespace ceres {
 
@@ -67,8 +67,7 @@
   // Eigen.
   DENSE_QR,
 
-  // Solve the normal equations using a sparse cholesky solver; requires
-  // SuiteSparse or CXSparse.
+  // Solve the normal equations using a sparse cholesky solver;
   SPARSE_NORMAL_CHOLESKY,
 
   // Specialized solvers, specific to problems with a generalized
@@ -98,7 +97,7 @@
   // Block diagonal of the Gauss-Newton Hessian.
   JACOBI,
 
-  // Note: The following three preconditioners can only be used with
+  // Note: The following four preconditioners can only be used with
   // the ITERATIVE_SCHUR solver. They are well suited for Structure
   // from Motion problems.
 
@@ -106,6 +105,10 @@
   // only be used with the ITERATIVE_SCHUR solver.
   SCHUR_JACOBI,
 
+  // Use power series expansion to approximate the inversion of Schur complement
+  // as a preconditioner.
+  SCHUR_POWER_SERIES_EXPANSION,
+
   // Visibility clustering based preconditioners.
   //
   // The following two preconditioners use the visibility structure of
@@ -134,7 +137,7 @@
   // well the matrix Q approximates J'J, or how well the chosen
   // residual blocks approximate the non-linear least squares
   // problem.
-  SUBSET,
+  SUBSET
 };
 
 enum VisibilityClusteringType {
@@ -165,11 +168,6 @@
   // minimum degree ordering.
   SUITE_SPARSE,
 
-  // A lightweight replacement for SuiteSparse, which does not require
-  // a LAPACK/BLAS implementation. Consequently, its performance is
-  // also a bit lower than SuiteSparse.
-  CX_SPARSE,
-
   // Eigen's sparse linear algebra routines. In particular Ceres uses
   // the Simplicial LDLT routines.
   EIGEN_SPARSE,
@@ -177,15 +175,43 @@
   // Apple's Accelerate framework sparse linear algebra routines.
   ACCELERATE_SPARSE,
 
+  // Nvidia's cuSPARSE library.
+  CUDA_SPARSE,
+
   // No sparse linear solver should be used.  This does not necessarily
   // imply that Ceres was built without any sparse library, although that
   // is the likely use case, merely that one should not be used.
   NO_SPARSE
 };
 
+// The order in which variables are eliminated in a linear solver
+// can have a significant of impact on the efficiency and accuracy
+// of the method. e.g., when doing sparse Cholesky factorization,
+// there are matrices for which a good ordering will give a
+// Cholesky factor with O(n) storage, where as a bad ordering will
+// result in an completely dense factor.
+//
+// So sparse direct solvers like SPARSE_NORMAL_CHOLESKY and
+// SPARSE_SCHUR and preconditioners like SUBSET, CLUSTER_JACOBI &
+// CLUSTER_TRIDIAGONAL use a fill reducing ordering of the columns and
+// rows of the matrix being factorized before actually the numeric
+// factorization.
+//
+// This enum controls the class of algorithm used to compute this
+// fill reducing ordering. There is no single algorithm that works
+// on all matrices, so determining which algorithm works better is a
+// matter of empirical experimentation.
+enum LinearSolverOrderingType {
+  // Approximate Minimum Degree.
+  AMD,
+  // Nested Dissection.
+  NESDIS
+};
+
 enum DenseLinearAlgebraLibraryType {
   EIGEN,
   LAPACK,
+  CUDA,
 };
 
 // Logging options
@@ -466,6 +492,11 @@
 CERES_EXPORT bool StringToSparseLinearAlgebraLibraryType(
     std::string value, SparseLinearAlgebraLibraryType* type);
 
+CERES_EXPORT const char* LinearSolverOrderingTypeToString(
+    LinearSolverOrderingType type);
+CERES_EXPORT bool StringToLinearSolverOrderingType(
+    std::string value, LinearSolverOrderingType* type);
+
 CERES_EXPORT const char* DenseLinearAlgebraLibraryTypeToString(
     DenseLinearAlgebraLibraryType type);
 CERES_EXPORT bool StringToDenseLinearAlgebraLibraryType(
diff --git a/third_party/ceres/include/ceres/version.h b/third_party/ceres/include/ceres/version.h
index a76cc10..fe6c288 100644
--- a/third_party/ceres/include/ceres/version.h
+++ b/third_party/ceres/include/ceres/version.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -32,7 +32,7 @@
 #define CERES_PUBLIC_VERSION_H_
 
 #define CERES_VERSION_MAJOR 2
-#define CERES_VERSION_MINOR 0
+#define CERES_VERSION_MINOR 2
 #define CERES_VERSION_REVISION 0
 
 // Classic CPP stringifcation; the extra level of indirection allows the
@@ -40,10 +40,16 @@
 #define CERES_TO_STRING_HELPER(x) #x
 #define CERES_TO_STRING(x) CERES_TO_STRING_HELPER(x)
 
+// clang-format off
+#define CERES_SEMVER_VERSION(MAJOR, MINOR, PATCH) \
+  CERES_TO_STRING(MAJOR) "."                      \
+  CERES_TO_STRING(MINOR) "."                      \
+  CERES_TO_STRING(PATCH)
+// clang-format on
+
 // The Ceres version as a string; for example "1.9.0".
-#define CERES_VERSION_STRING                                    \
-  CERES_TO_STRING(CERES_VERSION_MAJOR)                          \
-  "." CERES_TO_STRING(CERES_VERSION_MINOR) "." CERES_TO_STRING( \
-      CERES_VERSION_REVISION)
+#define CERES_VERSION_STRING \
+  CERES_SEMVER_VERSION(      \
+      CERES_VERSION_MAJOR, CERES_VERSION_MINOR, CERES_VERSION_REVISION)
 
 #endif  // CERES_PUBLIC_VERSION_H_
diff --git a/third_party/ceres/internal/ceres/CMakeLists.txt b/third_party/ceres/internal/ceres/CMakeLists.txt
index 6dc7262..583757e 100644
--- a/third_party/ceres/internal/ceres/CMakeLists.txt
+++ b/third_party/ceres/internal/ceres/CMakeLists.txt
@@ -1,5 +1,5 @@
 # Ceres Solver - A fast non-linear least squares minimizer
-# Copyright 2015 Google Inc. All rights reserved.
+# Copyright 2022 Google Inc. All rights reserved.
 # http://ceres-solver.org/
 #
 # Redistribution and use in source and binary forms, with or without
@@ -7,7 +7,7 @@
 #
 # * 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,
+# * Redistributions in binary form %Cmust 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 Google Inc. nor the names of its contributors may be
@@ -28,124 +28,28 @@
 #
 # Author: keir@google.com (Keir Mierle)
 
+# Build the list of dependencies for Ceres based on the current configuration.
+
 # Avoid 'xxx.cc has no symbols' warnings from source files which are 'empty'
 # when their enclosing #ifdefs are disabled.
-if (CERES_THREADING_MODEL STREQUAL "CXX_THREADS")
-  set(CERES_PARALLEL_FOR_SRC parallel_for_cxx.cc thread_pool.cc)
-elseif (CERES_THREADING_MODEL STREQUAL "OPENMP")
-  set(CERES_PARALLEL_FOR_SRC parallel_for_openmp.cc)
-  if (CMAKE_COMPILER_IS_GNUCXX)
-    # OpenMP in GCC requires the GNU OpenMP library.
-    list(APPEND CERES_LIBRARY_PRIVATE_DEPENDENCIES gomp)
-  endif()
-elseif (CERES_THREADING_MODEL STREQUAL "NO_THREADS")
-  set(CERES_PARALLEL_FOR_SRC parallel_for_nothreads.cc)
-endif()
+find_package(Threads REQUIRED)
+list(APPEND CERES_LIBRARY_PRIVATE_DEPENDENCIES Threads::Threads)
+# Make dependency visible to the parent CMakeLists.txt
+set(Threads_DEPENDENCY "find_dependency (Threads)" PARENT_SCOPE)
 
-set(CERES_INTERNAL_SRC
-    ${CERES_PARALLEL_FOR_SRC}
-    accelerate_sparse.cc
-    array_utils.cc
-    blas.cc
-    block_evaluate_preparer.cc
-    block_jacobi_preconditioner.cc
-    block_jacobian_writer.cc
-    block_random_access_dense_matrix.cc
-    block_random_access_diagonal_matrix.cc
-    block_random_access_matrix.cc
-    block_random_access_sparse_matrix.cc
-    block_sparse_matrix.cc
-    block_structure.cc
+# Source files that contain public symbols and live in the ceres namespaces.
+# Such symbols are expected to be marked with CERES_EXPORT and the files below
+# sorted in lexicographical order.
+set(CERES_EXPORTED_SRCS
     c_api.cc
-    canonical_views_clustering.cc
-    cgnr_solver.cc
-    callbacks.cc
-    compressed_col_sparse_matrix_utils.cc
-    compressed_row_jacobian_writer.cc
-    compressed_row_sparse_matrix.cc
-    conditioned_cost_function.cc
-    conjugate_gradients_solver.cc
-    context.cc
-    context_impl.cc
-    coordinate_descent_minimizer.cc
-    corrector.cc
-    covariance.cc
-    covariance_impl.cc
-    cxsparse.cc
-    dense_normal_cholesky_solver.cc
-    dense_qr_solver.cc
-    dense_sparse_matrix.cc
-    detect_structure.cc
-    dogleg_strategy.cc
-    dynamic_compressed_row_jacobian_writer.cc
-    dynamic_compressed_row_sparse_matrix.cc
-    dynamic_sparse_normal_cholesky_solver.cc
-    evaluator.cc
-    eigensparse.cc
-    file.cc
-    float_suitesparse.cc
-    float_cxsparse.cc
-    function_sample.cc
     gradient_checker.cc
-    gradient_checking_cost_function.cc
     gradient_problem.cc
-    gradient_problem_solver.cc
-    implicit_schur_complement.cc
-    inner_product_computer.cc
-    is_close.cc
-    iterative_refiner.cc
-    iterative_schur_complement_solver.cc
-    levenberg_marquardt_strategy.cc
-    lapack.cc
-    line_search.cc
-    line_search_direction.cc
-    line_search_minimizer.cc
-    line_search_preprocessor.cc
-    linear_least_squares_problems.cc
-    linear_operator.cc
-    linear_solver.cc
-    local_parameterization.cc
     loss_function.cc
-    low_rank_inverse_hessian.cc
-    minimizer.cc
+    manifold.cc
     normal_prior.cc
-    parallel_utils.cc
-    parameter_block_ordering.cc
-    partitioned_matrix_view.cc
-    polynomial.cc
-    preconditioner.cc
-    preprocessor.cc
     problem.cc
-    problem_impl.cc
-    program.cc
-    reorder_program.cc
-    residual_block.cc
-    residual_block_utils.cc
-    schur_complement_solver.cc
-    schur_eliminator.cc
-    schur_jacobi_preconditioner.cc
-    schur_templates.cc
-    scratch_evaluate_preparer.cc
-    single_linkage_clustering.cc
     solver.cc
-    solver_utils.cc
-    sparse_matrix.cc
-    sparse_cholesky.cc
-    sparse_normal_cholesky_solver.cc
-    subset_preconditioner.cc
-    split.cc
-    stringprintf.cc
-    suitesparse.cc
-    thread_token_provider.cc
-    triplet_sparse_matrix.cc
-    trust_region_preprocessor.cc
-    trust_region_minimizer.cc
-    trust_region_step_evaluator.cc
-    trust_region_strategy.cc
     types.cc
-    visibility.cc
-    visibility_based_preconditioner.cc
-    wall_time.cc
 )
 
 # Also depend on the header files so that they appear in IDEs.
@@ -161,6 +65,8 @@
 # Depend also on public headers so they appear in IDEs.
 file(GLOB CERES_PUBLIC_HDRS ${Ceres_SOURCE_DIR}/include/ceres/*.h)
 file(GLOB CERES_PUBLIC_INTERNAL_HDRS ${Ceres_SOURCE_DIR}/include/ceres/internal/*.h)
+file(GLOB CERES_PUBLIC_INTERNAL_HDRS
+  ${Ceres_BINARY_DIR}/${CMAKE_INSTALL_INCLUDEDIR}/ceres/internal/*.h)
 
 # Include the specialized schur solvers.
 if (SCHUR_SPECIALIZATIONS)
@@ -170,9 +76,14 @@
   file(GLOB CERES_INTERNAL_SCHUR_FILES generated/*_d_d_d.cc)
 endif (SCHUR_SPECIALIZATIONS)
 
-# Build the list of dependencies for Ceres based on the current configuration.
-find_package(Threads QUIET)
-list(APPEND CERES_LIBRARY_PUBLIC_DEPENDENCIES Threads::Threads)
+# The generated specializations of the Schur eliminator include
+# schur_eliminator_impl.h which defines EIGEN_CACHEFRIENDLY_PRODUCT_THRESHOLD
+# to a different value than Eigen's default.  Depending on the order of files
+# in the unity build this can lead to clashes.  Additionally, these files are
+# already generated in a way which leads to fairly large compilation units,
+# so the gains from a unity build would be marginal.
+set_source_files_properties(${CERES_INTERNAL_SCHUR_FILES} PROPERTIES
+  SKIP_UNITY_BUILD_INCLUSION ON)
 
 if (NOT MINIGLOG AND GLOG_FOUND)
   list(APPEND CERES_LIBRARY_PUBLIC_DEPENDENCIES ${GLOG_LIBRARIES})
@@ -186,32 +97,160 @@
   endif()
 endif (NOT MINIGLOG AND GLOG_FOUND)
 
-if (SUITESPARSE AND SUITESPARSE_FOUND)
+if (SUITESPARSE AND SuiteSparse_FOUND)
   # Define version information for use in Solver::FullReport.
-  add_definitions(-DCERES_SUITESPARSE_VERSION="${SUITESPARSE_VERSION}")
-  list(APPEND CERES_LIBRARY_PRIVATE_DEPENDENCIES ${SUITESPARSE_LIBRARIES})
-endif (SUITESPARSE AND SUITESPARSE_FOUND)
+  add_definitions(-DCERES_SUITESPARSE_VERSION="${SuiteSparse_VERSION}")
+  list(APPEND CERES_LIBRARY_PRIVATE_DEPENDENCIES SuiteSparse::CHOLMOD
+    SuiteSparse::SPQR)
 
-if (CXSPARSE AND CXSPARSE_FOUND)
+  if (SuiteSparse_Partition_FOUND)
+    list(APPEND CERES_LIBRARY_PRIVATE_DEPENDENCIES SuiteSparse::Partition)
+  endif (SuiteSparse_Partition_FOUND)
+endif (SUITESPARSE AND SuiteSparse_FOUND)
+
+if (SuiteSparse_Partition_FOUND OR EIGENMETIS)
   # Define version information for use in Solver::FullReport.
-  add_definitions(-DCERES_CXSPARSE_VERSION="${CXSPARSE_VERSION}")
-  list(APPEND CERES_LIBRARY_PRIVATE_DEPENDENCIES ${CXSPARSE_LIBRARIES})
-endif (CXSPARSE AND CXSPARSE_FOUND)
+  add_definitions(-DCERES_METIS_VERSION="${METIS_VERSION}")
+  list(APPEND CERES_LIBRARY_PRIVATE_DEPENDENCIES METIS::METIS)
+endif (SuiteSparse_Partition_FOUND OR EIGENMETIS)
 
 if (ACCELERATESPARSE AND AccelerateSparse_FOUND)
   list(APPEND CERES_LIBRARY_PRIVATE_DEPENDENCIES ${AccelerateSparse_LIBRARIES})
 endif()
 
+if (USE_CUDA)
+  list(APPEND CERES_LIBRARY_PRIVATE_DEPENDENCIES ${CERES_CUDA_LIBRARIES})
+  set_source_files_properties(cuda_kernels_vector_ops.cu.cc PROPERTIES LANGUAGE CUDA)
+  set_source_files_properties(cuda_kernels_bsm_to_crs.cu.cc PROPERTIES LANGUAGE CUDA)
+  add_library(ceres_cuda_kernels STATIC cuda_kernels_vector_ops.cu.cc cuda_kernels_bsm_to_crs.cu.cc)
+  target_compile_features(ceres_cuda_kernels PRIVATE cxx_std_14)
+  target_compile_definitions(ceres_cuda_kernels PRIVATE CERES_STATIC_DEFINE)
+  # Enable __host__ / __device__ annotations in lambda declarations
+  target_compile_options(ceres_cuda_kernels PRIVATE --extended-lambda)
+  target_include_directories(ceres_cuda_kernels PRIVATE  ${Ceres_SOURCE_DIR}/include  ${Ceres_SOURCE_DIR}/internal ${Ceres_BINARY_DIR}/${CMAKE_INSTALL_INCLUDEDIR})
+  list(APPEND CERES_LIBRARY_PRIVATE_DEPENDENCIES ceres_cuda_kernels)
+endif (USE_CUDA)
+
 if (LAPACK_FOUND)
   list(APPEND CERES_LIBRARY_PRIVATE_DEPENDENCIES ${LAPACK_LIBRARIES})
 endif ()
 
+# Source files that contain private symbols and live in the ceres::internal
+# namespace. The corresponding symbols (classes, functions, etc.) are expected
+# to be marked with CERES_NO_EXPORT and the files below sorted in
+# lexicographical order.
+add_library(ceres_internal OBJECT
+    ${CERES_INTERNAL_SCHUR_FILES}
+    accelerate_sparse.cc
+    array_utils.cc
+    block_evaluate_preparer.cc
+    block_jacobi_preconditioner.cc
+    block_jacobian_writer.cc
+    block_random_access_dense_matrix.cc
+    block_random_access_diagonal_matrix.cc
+    block_random_access_matrix.cc
+    block_random_access_sparse_matrix.cc
+    block_sparse_matrix.cc
+    block_structure.cc
+    callbacks.cc
+    canonical_views_clustering.cc
+    cgnr_solver.cc
+    compressed_col_sparse_matrix_utils.cc
+    compressed_row_jacobian_writer.cc
+    compressed_row_sparse_matrix.cc
+    conditioned_cost_function.cc
+    context.cc
+    context_impl.cc
+    coordinate_descent_minimizer.cc
+    corrector.cc
+    cost_function.cc
+    covariance.cc
+    covariance_impl.cc
+    cuda_block_sparse_crs_view.cc
+    cuda_partitioned_block_sparse_crs_view.cc
+    cuda_block_structure.cc
+    cuda_sparse_matrix.cc
+    cuda_vector.cc
+    dense_cholesky.cc
+    dense_normal_cholesky_solver.cc
+    dense_qr.cc
+    dense_qr_solver.cc
+    dense_sparse_matrix.cc
+    detect_structure.cc
+    dogleg_strategy.cc
+    dynamic_compressed_row_jacobian_writer.cc
+    dynamic_compressed_row_sparse_matrix.cc
+    dynamic_sparse_normal_cholesky_solver.cc
+    eigensparse.cc
+    evaluation_callback.cc
+    evaluator.cc
+    fake_bundle_adjustment_jacobian.cc
+    file.cc
+    first_order_function.cc
+    float_suitesparse.cc
+    function_sample.cc
+    gradient_checking_cost_function.cc
+    gradient_problem_solver.cc
+    implicit_schur_complement.cc
+    inner_product_computer.cc
+    is_close.cc
+    iteration_callback.cc
+    iterative_refiner.cc
+    iterative_schur_complement_solver.cc
+    levenberg_marquardt_strategy.cc
+    line_search.cc
+    line_search_direction.cc
+    line_search_minimizer.cc
+    line_search_preprocessor.cc
+    linear_least_squares_problems.cc
+    linear_operator.cc
+    linear_solver.cc
+    low_rank_inverse_hessian.cc
+    minimizer.cc
+    parallel_invoke.cc
+    parallel_utils.cc
+    parallel_vector_ops.cc
+    parameter_block_ordering.cc
+    partitioned_matrix_view.cc
+    polynomial.cc
+    power_series_expansion_preconditioner.cc
+    preconditioner.cc
+    preprocessor.cc
+    problem_impl.cc
+    program.cc
+    reorder_program.cc
+    residual_block.cc
+    residual_block_utils.cc
+    schur_complement_solver.cc
+    schur_eliminator.cc
+    schur_jacobi_preconditioner.cc
+    schur_templates.cc
+    scratch_evaluate_preparer.cc
+    single_linkage_clustering.cc
+    solver_utils.cc
+    sparse_cholesky.cc
+    sparse_matrix.cc
+    sparse_normal_cholesky_solver.cc
+    stringprintf.cc
+    subset_preconditioner.cc
+    suitesparse.cc
+    thread_pool.cc
+    thread_token_provider.cc
+    triplet_sparse_matrix.cc
+    trust_region_minimizer.cc
+    trust_region_preprocessor.cc
+    trust_region_step_evaluator.cc
+    trust_region_strategy.cc
+    visibility.cc
+    visibility_based_preconditioner.cc
+    wall_time.cc
+)
+
 set(CERES_LIBRARY_SOURCE
-    ${CERES_INTERNAL_SRC}
+    ${CERES_EXPORTED_SRCS}
     ${CERES_INTERNAL_HDRS}
     ${CERES_PUBLIC_HDRS}
-    ${CERES_PUBLIC_INTERNAL_HDRS}
-    ${CERES_INTERNAL_SCHUR_FILES})
+    ${CERES_PUBLIC_INTERNAL_HDRS})
 
 # Primarily for Android, but optionally for others, compile the minimal
 # glog implementation into Ceres.
@@ -229,65 +268,55 @@
                APPEND_STRING PROPERTY COMPILE_FLAGS "-Wno-missing-declarations")
 endif()
 
-add_library(ceres ${CERES_LIBRARY_SOURCE})
+add_library(ceres $<TARGET_OBJECTS:ceres_internal> ${CERES_LIBRARY_SOURCE})
+
+if(BUILD_SHARED_LIBS)
+  # While building shared libraries, we additionally require a static variant to
+  # be able to access internal symbols which are not intended for general use.
+  # Therefore, create a static library from object files and apply all the
+  # compiler options from the main library to the static one.
+  add_library(ceres_static STATIC $<TARGET_OBJECTS:ceres_internal> ${CERES_LIBRARY_SOURCE})
+  target_include_directories(ceres_static PUBLIC $<TARGET_PROPERTY:ceres,INCLUDE_DIRECTORIES>)
+  target_compile_definitions(ceres_static PUBLIC $<TARGET_PROPERTY:ceres,COMPILE_DEFINITIONS>)
+  target_compile_features(ceres_static PUBLIC $<TARGET_PROPERTY:ceres,COMPILE_FEATURES>)
+  target_compile_options(ceres_static PUBLIC $<TARGET_PROPERTY:ceres,COMPILE_OPTIONS>)
+  target_link_libraries(ceres_static
+    INTERFACE $<TARGET_PROPERTY:ceres,INTERFACE_LINK_LIBRARIES>
+    PRIVATE ${CERES_LIBRARY_PRIVATE_DEPENDENCIES})
+  # CERES_STATIC_DEFINE is generated by the GenerateExportHeader CMake module
+  # used to autogerate export.h. The macro should not be renamed without
+  # updating the corresponding generate_export_header invocation.
+  target_compile_definitions(ceres_static PUBLIC CERES_STATIC_DEFINE)
+else()
+  # In a static library build, not additional access layer is necessary as all
+  # symbols are visible.
+  add_library(ceres_static ALIAS ceres)
+endif()
+
+# Create a local alias target that matches the expected installed target.
+add_library(Ceres::ceres ALIAS ceres)
+
+# Apply all compiler options from the main Ceres target. Compiler options should
+# be generally defined on the main target referenced by the ceres_target CMake
+# variable.
+target_include_directories(ceres_internal PUBLIC $<TARGET_PROPERTY:ceres,INCLUDE_DIRECTORIES>)
+target_compile_definitions(ceres_internal PUBLIC $<TARGET_PROPERTY:ceres,COMPILE_DEFINITIONS>)
+target_compile_options(ceres_internal PUBLIC $<TARGET_PROPERTY:ceres,COMPILE_OPTIONS>)
+target_compile_definitions(ceres_internal PRIVATE ceres_EXPORTS)
+target_compile_features(ceres_internal PRIVATE $<TARGET_PROPERTY:ceres,COMPILE_FEATURES>)
+
+# Ensure the minimum required C++ language version is fulfilled as our
+# requirement by downstream clients. Consumers can choose the same or a newer
+# language standard revision.
+target_compile_features(ceres PUBLIC cxx_std_17)
+
 set_target_properties(ceres PROPERTIES
   VERSION ${CERES_VERSION}
-  SOVERSION ${CERES_VERSION_MAJOR})
-if (BUILD_SHARED_LIBS)
-  set_target_properties(ceres PROPERTIES
-    # Set the default symbol visibility to hidden to unify the behavior among
-    # the various compilers and to get smaller binaries
-    C_VISIBILITY_PRESET hidden
-    CXX_VISIBILITY_PRESET hidden)
-endif()
+  SOVERSION 4)
 
-# When building as a shared libarary with testing enabled, we need to export
-# internal symbols needed by the unit tests
-if (BUILD_TESTING)
-  target_compile_definitions(ceres
-    PUBLIC
-      CERES_EXPORT_INTERNAL_SYMBOLS
-    )
-endif()
-
-
-# The ability to specify a minimum language version via cxx_std_[11,14,17]
-# requires CMake >= 3.8.  Prior to that we have to specify the compiler features
-# we require.
-if (CMAKE_VERSION VERSION_LESS 3.8)
-  set(REQUIRED_PUBLIC_CXX_FEATURES cxx_alignas cxx_alignof cxx_constexpr)
-else()
-  # Forward whatever C++ version Ceres was compiled with as our requirement
-  # for downstream clients.
-  set(REQUIRED_PUBLIC_CXX_FEATURES cxx_std_${CMAKE_CXX_STANDARD})
-endif()
-target_compile_features(ceres PUBLIC ${REQUIRED_PUBLIC_CXX_FEATURES})
-
-include(AppendTargetProperty)
-# Always build position-independent code (PIC), even when building Ceres as a
-# static library so that shared libraries can link against it, not just
-# executables (PIC does not apply on Windows).
-if (NOT WIN32 AND NOT BUILD_SHARED_LIBS)
-  # Use set_target_properties() not append_target_property() here as
-  # POSITION_INDEPENDENT_CODE is a binary ON/OFF switch.
-  set_target_properties(ceres PROPERTIES POSITION_INDEPENDENT_CODE ON)
-endif()
-
-if (BUILD_SHARED_LIBS)
-  # When building a shared library, mark all external libraries as
-  # PRIVATE so they don't show up as a dependency.
-  target_link_libraries(ceres
-        PUBLIC ${CERES_LIBRARY_PUBLIC_DEPENDENCIES}
-        PRIVATE ${CERES_LIBRARY_PRIVATE_DEPENDENCIES})
-else (BUILD_SHARED_LIBS)
-  # When building a static library, all external libraries are
-  # PUBLIC(default) since the user needs to link to them.
-  # They will be listed in CeresTargets.cmake.
-  set(CERES_LIBRARY_DEPENDENCIES
-        ${CERES_LIBRARY_PUBLIC_DEPENDENCIES}
-        ${CERES_LIBRARY_PRIVATE_DEPENDENCIES})
-  target_link_libraries(ceres PUBLIC ${CERES_LIBRARY_DEPENDENCIES})
-endif (BUILD_SHARED_LIBS)
+target_link_libraries(ceres
+  PUBLIC ${CERES_LIBRARY_PUBLIC_DEPENDENCIES}
+  PRIVATE ${CERES_LIBRARY_PRIVATE_DEPENDENCIES})
 
 # Add the Ceres headers to its target.
 #
@@ -296,16 +325,16 @@
 # that if the user has an installed version of Ceres in the same location as one
 # of the dependencies (e.g. /usr/local) that we find the config.h we just
 # configured, not the (older) installed config.h.
-target_include_directories(ceres BEFORE PUBLIC
-  $<BUILD_INTERFACE:${Ceres_BINARY_DIR}/config>)
-target_include_directories(ceres PRIVATE ${Ceres_SOURCE_DIR}/internal)
-target_include_directories(ceres PUBLIC
-  $<BUILD_INTERFACE:${Ceres_SOURCE_DIR}/include>
-  $<INSTALL_INTERFACE:include>)
+target_include_directories(ceres
+  BEFORE PUBLIC
+  $<BUILD_INTERFACE:${Ceres_BINARY_DIR}/${CMAKE_INSTALL_INCLUDEDIR}>
+  PRIVATE ${Ceres_SOURCE_DIR}/internal
+  PUBLIC $<BUILD_INTERFACE:${Ceres_SOURCE_DIR}/include>
+         $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
 
 # Eigen SparseQR generates various compiler warnings related to unused and
 # uninitialised local variables.  To avoid having to individually suppress these
-# warnings around the #include statments for Eigen headers across all GCC/Clang
+# warnings around the #include statements for Eigen headers across all GCC/Clang
 # versions, we tell CMake to treat Eigen headers as system headers.  This
 # results in all compiler warnings from them being suppressed.
 target_link_libraries(ceres PUBLIC Eigen3::Eigen)
@@ -327,21 +356,13 @@
   # themselves (intentionally or otherwise) and so break their build.
   target_include_directories(ceres BEFORE PUBLIC
     $<BUILD_INTERFACE:${Ceres_SOURCE_DIR}/internal/ceres/miniglog>
-    $<INSTALL_INTERFACE:include/ceres/internal/miniglog>)
+    $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/ceres/internal/miniglog>)
 elseif (NOT FOUND_INSTALLED_GLOG_CMAKE_CONFIGURATION)
   # Only append glog include directories if the glog found was not a CMake
   # exported target that already includes them.
   list(APPEND CERES_LIBRARY_PUBLIC_DEPENDENCIES_INCLUDE_DIRS
     ${GLOG_INCLUDE_DIRS})
 endif()
-if (SUITESPARSE)
-  list(APPEND CERES_LIBRARY_PRIVATE_DEPENDENCIES_INCLUDE_DIRS
-    ${SUITESPARSE_INCLUDE_DIRS})
-endif()
-if (CXSPARSE)
-  list(APPEND CERES_LIBRARY_PRIVATE_DEPENDENCIES_INCLUDE_DIRS
-    ${CXSPARSE_INCLUDE_DIRS})
-endif()
 if (ACCELERATESPARSE)
   list(APPEND CERES_LIBRARY_PRIVATE_DEPENDENCIES_INCLUDE_DIRS
     ${AccelerateSparse_INCLUDE_DIRS})
@@ -349,47 +370,45 @@
 # Add include locations for optional dependencies to the Ceres target without
 # duplication.
 list(REMOVE_DUPLICATES CERES_LIBRARY_PRIVATE_DEPENDENCIES_INCLUDE_DIRS)
-foreach(INC_DIR ${CERES_LIBRARY_PRIVATE_DEPENDENCIES_INCLUDE_DIRS})
-  target_include_directories(ceres PRIVATE ${INC_DIR})
-endforeach()
+target_include_directories(ceres PRIVATE ${CERES_LIBRARY_PRIVATE_DEPENDENCIES_INCLUDE_DIRS})
 list(REMOVE_DUPLICATES CERES_LIBRARY_PUBLIC_DEPENDENCIES_INCLUDE_DIRS)
-foreach(INC_DIR ${CERES_LIBRARY_PUBLIC_DEPENDENCIES_INCLUDE_DIRS})
-  target_include_directories(ceres PUBLIC ${INC_DIR})
-endforeach()
+target_include_directories(ceres PUBLIC ${CERES_LIBRARY_PUBLIC_DEPENDENCIES_INCLUDE_DIRS})
+
+# Generate an export header for annotating symbols visibility
+include(GenerateExportHeader)
+generate_export_header(ceres EXPORT_FILE_NAME
+  ${Ceres_BINARY_DIR}/${CMAKE_INSTALL_INCLUDEDIR}/ceres/internal/export.h)
+
+if (USE_CUDA)
+  install(TARGETS ceres_cuda_kernels
+          EXPORT  CeresExport
+          RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+          LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+          ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
+endif(USE_CUDA)
 
 install(TARGETS ceres
         EXPORT  CeresExport
-        RUNTIME DESTINATION bin
-        LIBRARY DESTINATION lib${LIB_SUFFIX}
-        ARCHIVE DESTINATION lib${LIB_SUFFIX})
-
-# Create a local alias target that matches the expected installed target.
-add_library(Ceres::ceres ALIAS ceres)
+        RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+        LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+        ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
 
 if (BUILD_TESTING AND GFLAGS)
-  add_library(gtest gmock_gtest_all.cc gmock_main.cc)
-  target_include_directories(gtest PUBLIC ${Ceres_SOURCE_DIR}/internal/ceres)
-  if (BUILD_SHARED_LIBS)
-    # Define gtest-specific shared library flags for compilation.
-    append_target_property(gtest COMPILE_DEFINITIONS
-      GTEST_CREATE_SHARED_LIBRARY)
-  endif()
+  add_library(gtest STATIC gmock_gtest_all.cc gmock_main.cc)
 
-  add_library(test_util
+  target_include_directories(gtest PRIVATE ${Ceres_SOURCE_DIR}/internal/ceres)
+  if (CMAKE_SYSTEM_NAME MATCHES "QNX")
+    target_link_libraries(gtest PUBLIC regex)
+  endif()
+  target_link_libraries(gtest PRIVATE Ceres::ceres gflags)
+
+  add_library(test_util STATIC
               evaluator_test_utils.cc
               numeric_diff_test_utils.cc
               test_util.cc)
-  target_include_directories(test_util PUBLIC ${Ceres_SOURCE_DIR}/internal)
 
-  if (MINIGLOG)
-    # When using miniglog, it is compiled into Ceres, thus Ceres becomes
-    # the library against which other libraries should link for logging.
-    target_link_libraries(gtest PUBLIC gflags Ceres::ceres)
-    target_link_libraries(test_util PUBLIC Ceres::ceres gtest)
-  else (MINIGLOG)
-    target_link_libraries(gtest PUBLIC gflags ${GLOG_LIBRARIES})
-    target_link_libraries(test_util PUBLIC Ceres::ceres gtest ${GLOG_LIBRARIES})
-  endif (MINIGLOG)
+  target_include_directories(test_util PUBLIC ${Ceres_SOURCE_DIR}/internal)
+  target_link_libraries (test_util PUBLIC ceres_static gflags gtest)
 
   macro (CERES_TEST NAME)
     add_executable(${NAME}_test ${NAME}_test.cc)
@@ -398,16 +417,21 @@
     # may be referenced without the 'ceres' path prefix and all private
     # dependencies that may be directly referenced.
     target_include_directories(${NAME}_test
-      PUBLIC ${CMAKE_CURRENT_LIST_DIR}
-             ${Ceres_SOURCE_DIR}/internal/ceres
-             ${CERES_LIBRARY_PRIVATE_DEPENDENCIES_INCLUDE_DIRS})
+      PRIVATE ${Ceres_SOURCE_DIR}/internal/ceres
+              ${CERES_LIBRARY_PRIVATE_DEPENDENCIES_INCLUDE_DIRS})
+    # Some tests include direct references/includes of private dependency
+    # headers which are not propagated via the ceres targets, so link them
+    # explicitly.
+    target_link_libraries(${NAME}_test PRIVATE gtest test_util ceres_static
+      ${CERES_LIBRARY_PRIVATE_DEPENDENCIES})
 
-    target_link_libraries(${NAME}_test PUBLIC test_util Ceres::ceres gtest)
-    if (BUILD_SHARED_LIBS)
-      # Define gtest-specific shared library flags for linking.
-      append_target_property(${NAME}_test COMPILE_DEFINITIONS
-        GTEST_LINKED_AS_SHARED_LIBRARY)
-    endif()
+    # covariance_test uses SuiteSparseQR.hpp. However, since SuiteSparse import
+    # targets are private (link only) dependencies not propagated to consumers,
+    # we need to link against the target explicitly here.
+    if (TARGET SuiteSparse::SPQR)
+      target_link_libraries (${NAME}_test PRIVATE SuiteSparse::SPQR)
+    endif (TARGET SuiteSparse::SPQR)
+
     add_test(NAME ${NAME}_test
              COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${NAME}_test
              --test_srcdir
@@ -419,7 +443,7 @@
   ceres_test(autodiff)
   ceres_test(autodiff_first_order_function)
   ceres_test(autodiff_cost_function)
-  ceres_test(autodiff_local_parameterization)
+  ceres_test(autodiff_manifold)
   ceres_test(block_jacobi_preconditioner)
   ceres_test(block_random_access_dense_matrix)
   ceres_test(block_random_access_diagonal_matrix)
@@ -436,7 +460,18 @@
   ceres_test(cost_function_to_functor)
   ceres_test(covariance)
   ceres_test(cubic_interpolation)
+  ceres_test(cuda_partitioned_block_sparse_crs_view)
+  ceres_test(cuda_block_sparse_crs_view)
+  ceres_test(cuda_block_structure)
+  ceres_test(cuda_dense_cholesky)
+  ceres_test(cuda_dense_qr)
+  ceres_test(cuda_kernels_vector_ops)
+  ceres_test(cuda_sparse_matrix)
+  ceres_test(cuda_streamed_buffer)
+  ceres_test(cuda_vector)
   ceres_test(dense_linear_solver)
+  ceres_test(dense_cholesky)
+  ceres_test(dense_qr)
   ceres_test(dense_sparse_matrix)
   ceres_test(detect_structure)
   ceres_test(dogleg_strategy)
@@ -463,14 +498,16 @@
   ceres_test(iterative_refiner)
   ceres_test(iterative_schur_complement_solver)
   ceres_test(jet)
+  ceres_test(jet_traits)
   ceres_test(levenberg_marquardt_strategy)
   ceres_test(line_search_minimizer)
   ceres_test(line_search_preprocessor)
-  ceres_test(local_parameterization)
   ceres_test(loss_function)
+  ceres_test(manifold)
   ceres_test(minimizer)
   ceres_test(normal_prior)
   ceres_test(numeric_diff_cost_function)
+  ceres_test(numeric_diff_first_order_function)
   ceres_test(ordered_groups)
   ceres_test(parallel_for)
   ceres_test(parallel_utils)
@@ -479,6 +516,7 @@
   ceres_test(parameter_dims)
   ceres_test(partitioned_matrix_view)
   ceres_test(polynomial)
+  ceres_test(power_series_expansion_preconditioner)
   ceres_test(problem)
   ceres_test(program)
   ceres_test(reorder_program)
@@ -509,14 +547,20 @@
 endif (BUILD_TESTING AND GFLAGS)
 
 macro(add_dependencies_to_benchmark BENCHMARK_TARGET)
-  target_link_libraries(${BENCHMARK_TARGET} PUBLIC Ceres::ceres benchmark::benchmark)
-  target_include_directories(${BENCHMARK_TARGET} PUBLIC
-                             ${Ceres_SOURCE_DIR}/internal
-                             ${Ceres_SOURCE_DIR}/internal/ceres
-                             ${CERES_LIBRARY_PRIVATE_DEPENDENCIES_INCLUDE_DIRS})
+  target_include_directories(${BENCHMARK_TARGET}
+    PRIVATE ${Ceres_SOURCE_DIR}/internal
+            ${CERES_LIBRARY_PRIVATE_DEPENDENCIES_INCLUDE_DIRS})
+  # Benchmarks include direct references/includes of private dependency headers
+  # which are not propagated via the ceres targets, so link them explicitly.
+  target_link_libraries(${BENCHMARK_TARGET}
+    PRIVATE benchmark::benchmark ceres_static
+            ${CERES_LIBRARY_PRIVATE_DEPENDENCIES})
 endmacro()
 
 if (BUILD_BENCHMARKS)
+  add_executable(evaluation_benchmark evaluation_benchmark.cc)
+  add_dependencies_to_benchmark(evaluation_benchmark)
+
   add_executable(small_blas_gemv_benchmark small_blas_gemv_benchmark.cc)
   add_dependencies_to_benchmark(small_blas_gemv_benchmark)
 
@@ -529,6 +573,24 @@
   add_executable(schur_eliminator_benchmark schur_eliminator_benchmark.cc)
   add_dependencies_to_benchmark(schur_eliminator_benchmark)
 
+  add_executable(jet_operator_benchmark jet_operator_benchmark.cc)
+  add_dependencies_to_benchmark(jet_operator_benchmark)
+
+  add_executable(dense_linear_solver_benchmark dense_linear_solver_benchmark.cc)
+  add_dependencies_to_benchmark(dense_linear_solver_benchmark)
+
+  add_executable(spmv_benchmark spmv_benchmark.cc)
+  add_dependencies_to_benchmark(spmv_benchmark)
+
+  add_executable(parallel_vector_operations_benchmark parallel_vector_operations_benchmark.cc)
+  add_dependencies_to_benchmark(parallel_vector_operations_benchmark)
+
+  add_executable(parallel_for_benchmark parallel_for_benchmark.cc)
+  add_dependencies_to_benchmark(parallel_for_benchmark)
+
+  add_executable(block_jacobi_preconditioner_benchmark
+    block_jacobi_preconditioner_benchmark.cc)
+  add_dependencies_to_benchmark(block_jacobi_preconditioner_benchmark)
+
   add_subdirectory(autodiff_benchmarks)
 endif (BUILD_BENCHMARKS)
-
diff --git a/third_party/ceres/internal/ceres/accelerate_sparse.cc b/third_party/ceres/internal/ceres/accelerate_sparse.cc
index d2b642b..0baadc0 100644
--- a/third_party/ceres/internal/ceres/accelerate_sparse.cc
+++ b/third_party/ceres/internal/ceres/accelerate_sparse.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -29,11 +29,12 @@
 // Author: alexs.mac@gmail.com (Alex Stewart)
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_NO_ACCELERATE_SPARSE
 
 #include <algorithm>
+#include <memory>
 #include <string>
 #include <vector>
 
@@ -60,7 +61,7 @@
     CASESTR(SparseParameterError);
     CASESTR(SparseStatusReleased);
     default:
-      return "UKNOWN";
+      return "UNKNOWN";
   }
 }
 }  // namespace.
@@ -113,12 +114,12 @@
   // Accelerate's columnStarts is a long*, not an int*.  These types might be
   // different (e.g. ARM on iOS) so always make a copy.
   column_starts_.resize(A->num_rows() + 1);  // +1 for final column length.
-  std::copy_n(A->rows(), column_starts_.size(), &column_starts_[0]);
+  std::copy_n(A->rows(), column_starts_.size(), column_starts_.data());
 
   ASSparseMatrix At;
   At.structure.rowCount = A->num_cols();
   At.structure.columnCount = A->num_rows();
-  At.structure.columnStarts = &column_starts_[0];
+  At.structure.columnStarts = column_starts_.data();
   At.structure.rowIndices = A->mutable_cols();
   At.structure.attributes.transpose = false;
   At.structure.attributes.triangle = SparseUpperTriangle;
@@ -126,8 +127,8 @@
   At.structure.attributes._reserved = 0;
   At.structure.attributes._allocatedBySparse = 0;
   At.structure.blockSize = 1;
-  if (std::is_same<Scalar, double>::value) {
-    At.data = reinterpret_cast<Scalar*>(A->mutable_values());
+  if constexpr (std::is_same_v<Scalar, double>) {
+    At.data = A->mutable_values();
   } else {
     values_ =
         ConstVectorRef(A->values(), A->num_nonzeros()).template cast<Scalar>();
@@ -138,8 +139,23 @@
 
 template <typename Scalar>
 typename AccelerateSparse<Scalar>::SymbolicFactorization
-AccelerateSparse<Scalar>::AnalyzeCholesky(ASSparseMatrix* A) {
-  return SparseFactor(SparseFactorizationCholesky, A->structure);
+AccelerateSparse<Scalar>::AnalyzeCholesky(OrderingType ordering_type,
+                                          ASSparseMatrix* A) {
+  SparseSymbolicFactorOptions sfoption;
+  sfoption.control = SparseDefaultControl;
+  sfoption.orderMethod = SparseOrderDefault;
+  sfoption.order = nullptr;
+  sfoption.ignoreRowsAndColumns = nullptr;
+  sfoption.malloc = malloc;
+  sfoption.free = free;
+  sfoption.reportError = nullptr;
+
+  if (ordering_type == OrderingType::AMD) {
+    sfoption.orderMethod = SparseOrderAMD;
+  } else if (ordering_type == OrderingType::NESDIS) {
+    sfoption.orderMethod = SparseOrderMetis;
+  }
+  return SparseFactor(SparseFactorizationCholesky, A->structure, sfoption);
 }
 
 template <typename Scalar>
@@ -189,37 +205,38 @@
 template <typename Scalar>
 CompressedRowSparseMatrix::StorageType
 AppleAccelerateCholesky<Scalar>::StorageType() const {
-  return CompressedRowSparseMatrix::LOWER_TRIANGULAR;
+  return CompressedRowSparseMatrix::StorageType::LOWER_TRIANGULAR;
 }
 
 template <typename Scalar>
 LinearSolverTerminationType AppleAccelerateCholesky<Scalar>::Factorize(
     CompressedRowSparseMatrix* lhs, std::string* message) {
   CHECK_EQ(lhs->storage_type(), StorageType());
-  if (lhs == NULL) {
-    *message = "Failure: Input lhs is NULL.";
-    return LINEAR_SOLVER_FATAL_ERROR;
+  if (lhs == nullptr) {
+    *message = "Failure: Input lhs is nullptr.";
+    return LinearSolverTerminationType::FATAL_ERROR;
   }
   typename SparseTypesTrait<Scalar>::SparseMatrix as_lhs =
       as_.CreateSparseMatrixTransposeView(lhs);
 
   if (!symbolic_factor_) {
-    symbolic_factor_.reset(
-        new typename SparseTypesTrait<Scalar>::SymbolicFactorization(
-            as_.AnalyzeCholesky(&as_lhs)));
+    symbolic_factor_ = std::make_unique<
+        typename SparseTypesTrait<Scalar>::SymbolicFactorization>(
+        as_.AnalyzeCholesky(ordering_type_, &as_lhs));
+
     if (symbolic_factor_->status != SparseStatusOK) {
       *message = StringPrintf(
           "Apple Accelerate Failure : Symbolic factorisation failed: %s",
           SparseStatusToString(symbolic_factor_->status));
       FreeSymbolicFactorization();
-      return LINEAR_SOLVER_FATAL_ERROR;
+      return LinearSolverTerminationType::FATAL_ERROR;
     }
   }
 
   if (!numeric_factor_) {
-    numeric_factor_.reset(
-        new typename SparseTypesTrait<Scalar>::NumericFactorization(
-            as_.Cholesky(&as_lhs, symbolic_factor_.get())));
+    numeric_factor_ = std::make_unique<
+        typename SparseTypesTrait<Scalar>::NumericFactorization>(
+        as_.Cholesky(&as_lhs, symbolic_factor_.get()));
   } else {
     // Recycle memory from previous numeric factorization.
     as_.Cholesky(&as_lhs, numeric_factor_.get());
@@ -229,10 +246,10 @@
         "Apple Accelerate Failure : Numeric factorisation failed: %s",
         SparseStatusToString(numeric_factor_->status));
     FreeNumericFactorization();
-    return LINEAR_SOLVER_FAILURE;
+    return LinearSolverTerminationType::FAILURE;
   }
 
-  return LINEAR_SOLVER_SUCCESS;
+  return LinearSolverTerminationType::SUCCESS;
 }
 
 template <typename Scalar>
@@ -245,8 +262,8 @@
 
   typename SparseTypesTrait<Scalar>::DenseVector as_rhs_and_solution;
   as_rhs_and_solution.count = num_cols;
-  if (std::is_same<Scalar, double>::value) {
-    as_rhs_and_solution.data = reinterpret_cast<Scalar*>(solution);
+  if constexpr (std::is_same_v<Scalar, double>) {
+    as_rhs_and_solution.data = solution;
     std::copy_n(rhs, num_cols, solution);
   } else {
     scalar_rhs_and_solution_ =
@@ -258,14 +275,14 @@
     VectorRef(solution, num_cols) =
         scalar_rhs_and_solution_.template cast<double>();
   }
-  return LINEAR_SOLVER_SUCCESS;
+  return LinearSolverTerminationType::SUCCESS;
 }
 
 template <typename Scalar>
 void AppleAccelerateCholesky<Scalar>::FreeSymbolicFactorization() {
   if (symbolic_factor_) {
     SparseCleanup(*symbolic_factor_);
-    symbolic_factor_.reset();
+    symbolic_factor_ = nullptr;
   }
 }
 
@@ -273,7 +290,7 @@
 void AppleAccelerateCholesky<Scalar>::FreeNumericFactorization() {
   if (numeric_factor_) {
     SparseCleanup(*numeric_factor_);
-    numeric_factor_.reset();
+    numeric_factor_ = nullptr;
   }
 }
 
diff --git a/third_party/ceres/internal/ceres/accelerate_sparse.h b/third_party/ceres/internal/ceres/accelerate_sparse.h
index e53758d..ef819b8 100644
--- a/third_party/ceres/internal/ceres/accelerate_sparse.h
+++ b/third_party/ceres/internal/ceres/accelerate_sparse.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -32,7 +32,7 @@
 #define CERES_INTERNAL_ACCELERATE_SPARSE_H_
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_NO_ACCELERATE_SPARSE
 
@@ -55,18 +55,18 @@
 
 template <>
 struct SparseTypesTrait<double> {
-  typedef DenseVector_Double DenseVector;
-  typedef SparseMatrix_Double SparseMatrix;
-  typedef SparseOpaqueSymbolicFactorization SymbolicFactorization;
-  typedef SparseOpaqueFactorization_Double NumericFactorization;
+  using DenseVector = DenseVector_Double;
+  using SparseMatrix = SparseMatrix_Double;
+  using SymbolicFactorization = SparseOpaqueSymbolicFactorization;
+  using NumericFactorization = SparseOpaqueFactorization_Double;
 };
 
 template <>
 struct SparseTypesTrait<float> {
-  typedef DenseVector_Float DenseVector;
-  typedef SparseMatrix_Float SparseMatrix;
-  typedef SparseOpaqueSymbolicFactorization SymbolicFactorization;
-  typedef SparseOpaqueFactorization_Float NumericFactorization;
+  using DenseVector = DenseVector_Float;
+  using SparseMatrix = SparseMatrix_Float;
+  using SymbolicFactorization = SparseOpaqueSymbolicFactorization;
+  using NumericFactorization = SparseOpaqueFactorization_Float;
 };
 
 template <typename Scalar>
@@ -91,7 +91,8 @@
   //       objects internally).
   ASSparseMatrix CreateSparseMatrixTransposeView(CompressedRowSparseMatrix* A);
   // Computes a symbolic factorisation of A that can be used in Solve().
-  SymbolicFactorization AnalyzeCholesky(ASSparseMatrix* A);
+  SymbolicFactorization AnalyzeCholesky(OrderingType ordering_type,
+                                        ASSparseMatrix* A);
   // Compute the numeric Cholesky factorization of A, given its
   // symbolic factorization.
   NumericFactorization Cholesky(ASSparseMatrix* A,
@@ -111,7 +112,7 @@
 // An implementation of SparseCholesky interface using Apple's Accelerate
 // framework.
 template <typename Scalar>
-class AppleAccelerateCholesky : public SparseCholesky {
+class AppleAccelerateCholesky final : public SparseCholesky {
  public:
   // Factory
   static std::unique_ptr<SparseCholesky> Create(OrderingType ordering_type);
diff --git a/third_party/ceres/internal/ceres/array_selector_test.cc b/third_party/ceres/internal/ceres/array_selector_test.cc
index f7fef3c..ff1bcd7 100644
--- a/third_party/ceres/internal/ceres/array_selector_test.cc
+++ b/third_party/ceres/internal/ceres/array_selector_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2020 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://code.google.com/p/ceres-solver/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -33,8 +33,7 @@
 
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // This test only checks, if the correct array implementations are selected. The
 // test for FixedArray is in fixed_array_test.cc. Tests for std::array and
@@ -42,38 +41,33 @@
 TEST(ArraySelector, FixedArray) {
   ArraySelector<int, DYNAMIC, 20> array1(10);
   static_assert(
-      std::is_base_of<internal::FixedArray<int, 20>, decltype(array1)>::value,
-      "");
+      std::is_base_of<internal::FixedArray<int, 20>, decltype(array1)>::value);
   EXPECT_EQ(array1.size(), 10);
 
   ArraySelector<int, DYNAMIC, 10> array2(20);
   static_assert(
-      std::is_base_of<internal::FixedArray<int, 10>, decltype(array2)>::value,
-      "");
+      std::is_base_of<internal::FixedArray<int, 10>, decltype(array2)>::value);
   EXPECT_EQ(array2.size(), 20);
 }
 
 TEST(ArraySelector, Array) {
   ArraySelector<int, 10, 20> array1(10);
-  static_assert(std::is_base_of<std::array<int, 10>, decltype(array1)>::value,
-                "");
+  static_assert(std::is_base_of<std::array<int, 10>, decltype(array1)>::value);
   EXPECT_EQ(array1.size(), 10);
 
   ArraySelector<int, 20, 20> array2(20);
-  static_assert(std::is_base_of<std::array<int, 20>, decltype(array2)>::value,
-                "");
+  static_assert(std::is_base_of<std::array<int, 20>, decltype(array2)>::value);
   EXPECT_EQ(array2.size(), 20);
 }
 
 TEST(ArraySelector, Vector) {
   ArraySelector<int, 20, 10> array1(20);
-  static_assert(std::is_base_of<std::vector<int>, decltype(array1)>::value, "");
+  static_assert(std::is_base_of<std::vector<int>, decltype(array1)>::value);
   EXPECT_EQ(array1.size(), 20);
 
   ArraySelector<int, 1, 0> array2(1);
-  static_assert(std::is_base_of<std::vector<int>, decltype(array2)>::value, "");
+  static_assert(std::is_base_of<std::vector<int>, decltype(array2)>::value);
   EXPECT_EQ(array2.size(), 1);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/array_utils.cc b/third_party/ceres/internal/ceres/array_utils.cc
index 6bffd84..a962f7f 100644
--- a/third_party/ceres/internal/ceres/array_utils.cc
+++ b/third_party/ceres/internal/ceres/array_utils.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -38,14 +38,12 @@
 
 #include "ceres/stringprintf.h"
 #include "ceres/types.h"
-namespace ceres {
-namespace internal {
 
-using std::string;
+namespace ceres::internal {
 
-bool IsArrayValid(const int size, const double* x) {
-  if (x != NULL) {
-    for (int i = 0; i < size; ++i) {
+bool IsArrayValid(const int64_t size, const double* x) {
+  if (x != nullptr) {
+    for (int64_t i = 0; i < size; ++i) {
       if (!std::isfinite(x[i]) || (x[i] == kImpossibleValue)) {
         return false;
       }
@@ -54,12 +52,12 @@
   return true;
 }
 
-int FindInvalidValue(const int size, const double* x) {
-  if (x == NULL) {
+int64_t FindInvalidValue(const int64_t size, const double* x) {
+  if (x == nullptr) {
     return size;
   }
 
-  for (int i = 0; i < size; ++i) {
+  for (int64_t i = 0; i < size; ++i) {
     if (!std::isfinite(x[i]) || (x[i] == kImpossibleValue)) {
       return i;
     }
@@ -68,17 +66,19 @@
   return size;
 }
 
-void InvalidateArray(const int size, double* x) {
-  if (x != NULL) {
-    for (int i = 0; i < size; ++i) {
+void InvalidateArray(const int64_t size, double* x) {
+  if (x != nullptr) {
+    for (int64_t i = 0; i < size; ++i) {
       x[i] = kImpossibleValue;
     }
   }
 }
 
-void AppendArrayToString(const int size, const double* x, string* result) {
-  for (int i = 0; i < size; ++i) {
-    if (x == NULL) {
+void AppendArrayToString(const int64_t size,
+                         const double* x,
+                         std::string* result) {
+  for (int64_t i = 0; i < size; ++i) {
+    if (x == nullptr) {
       StringAppendF(result, "Not Computed  ");
     } else {
       if (x[i] == kImpossibleValue) {
@@ -90,18 +90,17 @@
   }
 }
 
-void MapValuesToContiguousRange(const int size, int* array) {
+void MapValuesToContiguousRange(const int64_t size, int* array) {
   std::vector<int> unique_values(array, array + size);
   std::sort(unique_values.begin(), unique_values.end());
   unique_values.erase(std::unique(unique_values.begin(), unique_values.end()),
                       unique_values.end());
 
-  for (int i = 0; i < size; ++i) {
+  for (int64_t i = 0; i < size; ++i) {
     array[i] =
         std::lower_bound(unique_values.begin(), unique_values.end(), array[i]) -
         unique_values.begin();
   }
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/array_utils.h b/third_party/ceres/internal/ceres/array_utils.h
index 68feca5..bd51aa5 100644
--- a/third_party/ceres/internal/ceres/array_utils.h
+++ b/third_party/ceres/internal/ceres/array_utils.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -43,31 +43,32 @@
 #ifndef CERES_INTERNAL_ARRAY_UTILS_H_
 #define CERES_INTERNAL_ARRAY_UTILS_H_
 
+#include <cstdint>
 #include <string>
 
-#include "ceres/internal/port.h"
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // Fill the array x with an impossible value that the user code is
 // never expected to compute.
-CERES_EXPORT_INTERNAL void InvalidateArray(int size, double* x);
+CERES_NO_EXPORT void InvalidateArray(const int64_t size, double* x);
 
 // Check if all the entries of the array x are valid, i.e. all the
 // values in the array should be finite and none of them should be
 // equal to the "impossible" value used by InvalidateArray.
-CERES_EXPORT_INTERNAL bool IsArrayValid(int size, const double* x);
+CERES_NO_EXPORT bool IsArrayValid(const int64_t size, const double* x);
 
 // If the array contains an invalid value, return the index for it,
 // otherwise return size.
-CERES_EXPORT_INTERNAL int FindInvalidValue(const int size, const double* x);
+CERES_NO_EXPORT int64_t FindInvalidValue(const int64_t size, const double* x);
 
 // Utility routine to print an array of doubles to a string. If the
-// array pointer is NULL, it is treated as an array of zeros.
-CERES_EXPORT_INTERNAL void AppendArrayToString(const int size,
-                                               const double* x,
-                                               std::string* result);
+// array pointer is nullptr, it is treated as an array of zeros.
+CERES_NO_EXPORT void AppendArrayToString(const int64_t size,
+                                         const double* x,
+                                         std::string* result);
 
 // This routine takes an array of integer values, sorts and uniques
 // them and then maps each value in the array to its position in the
@@ -82,9 +83,10 @@
 // gets mapped to
 //
 // [1 0 2 3 0 1 3]
-CERES_EXPORT_INTERNAL void MapValuesToContiguousRange(int size, int* array);
+CERES_NO_EXPORT void MapValuesToContiguousRange(const int64_t size, int* array);
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_ARRAY_UTILS_H_
diff --git a/third_party/ceres/internal/ceres/array_utils_test.cc b/third_party/ceres/internal/ceres/array_utils_test.cc
index 6c0ea84..2661f57 100644
--- a/third_party/ceres/internal/ceres/array_utils_test.cc
+++ b/third_party/ceres/internal/ceres/array_utils_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -36,10 +36,7 @@
 
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
-
-using std::vector;
+namespace ceres::internal {
 
 TEST(ArrayUtils, IsArrayValid) {
   double x[3];
@@ -53,7 +50,7 @@
   EXPECT_FALSE(IsArrayValid(3, x));
   x[1] = std::numeric_limits<double>::signaling_NaN();
   EXPECT_FALSE(IsArrayValid(3, x));
-  EXPECT_TRUE(IsArrayValid(1, NULL));
+  EXPECT_TRUE(IsArrayValid(1, nullptr));
   InvalidateArray(3, x);
   EXPECT_FALSE(IsArrayValid(3, x));
 }
@@ -70,16 +67,16 @@
   EXPECT_EQ(FindInvalidValue(3, x), 1);
   x[1] = std::numeric_limits<double>::signaling_NaN();
   EXPECT_EQ(FindInvalidValue(3, x), 1);
-  EXPECT_EQ(FindInvalidValue(1, NULL), 1);
+  EXPECT_EQ(FindInvalidValue(1, nullptr), 1);
   InvalidateArray(3, x);
   EXPECT_EQ(FindInvalidValue(3, x), 0);
 }
 
 TEST(MapValuesToContiguousRange, ContiguousEntries) {
-  vector<int> array;
+  std::vector<int> array;
   array.push_back(0);
   array.push_back(1);
-  vector<int> expected = array;
+  std::vector<int> expected = array;
   MapValuesToContiguousRange(array.size(), &array[0]);
   EXPECT_EQ(array, expected);
   array.clear();
@@ -92,10 +89,10 @@
 }
 
 TEST(MapValuesToContiguousRange, NonContiguousEntries) {
-  vector<int> array;
+  std::vector<int> array;
   array.push_back(0);
   array.push_back(2);
-  vector<int> expected;
+  std::vector<int> expected;
   expected.push_back(0);
   expected.push_back(1);
   MapValuesToContiguousRange(array.size(), &array[0]);
@@ -103,14 +100,14 @@
 }
 
 TEST(MapValuesToContiguousRange, NonContiguousRepeatingEntries) {
-  vector<int> array;
+  std::vector<int> array;
   array.push_back(3);
   array.push_back(1);
   array.push_back(0);
   array.push_back(0);
   array.push_back(0);
   array.push_back(5);
-  vector<int> expected;
+  std::vector<int> expected;
   expected.push_back(2);
   expected.push_back(1);
   expected.push_back(0);
@@ -121,5 +118,4 @@
   EXPECT_EQ(array, expected);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/autodiff_benchmarks/CMakeLists.txt b/third_party/ceres/internal/ceres/autodiff_benchmarks/CMakeLists.txt
index 610ebc3..99af152 100644
--- a/third_party/ceres/internal/ceres/autodiff_benchmarks/CMakeLists.txt
+++ b/third_party/ceres/internal/ceres/autodiff_benchmarks/CMakeLists.txt
@@ -9,9 +9,3 @@
 add_executable(autodiff_benchmarks autodiff_benchmarks.cc)
 add_dependencies_to_benchmark(autodiff_benchmarks)
 target_compile_options(autodiff_benchmarks PRIVATE ${CERES_BENCHMARK_FLAGS})
-
-# All other flags + fast-math
-list(APPEND CERES_BENCHMARK_FAST_MATH_FLAGS ${CERES_BENCHMARK_FLAGS} "-ffast-math")
-add_executable(autodiff_benchmarks_fast_math autodiff_benchmarks.cc)
-add_dependencies_to_benchmark(autodiff_benchmarks_fast_math)
-target_compile_options(autodiff_benchmarks_fast_math PRIVATE ${CERES_BENCHMARK_FAST_MATH_FLAGS})
diff --git a/third_party/ceres/internal/ceres/autodiff_benchmarks/brdf_cost_function.h b/third_party/ceres/internal/ceres/autodiff_benchmarks/brdf_cost_function.h
index 9d7c0cc..41cfcfa 100644
--- a/third_party/ceres/internal/ceres/autodiff_benchmarks/brdf_cost_function.h
+++ b/third_party/ceres/internal/ceres/autodiff_benchmarks/brdf_cost_function.h
@@ -35,6 +35,8 @@
 #include <Eigen/Core>
 #include <cmath>
 
+#include "ceres/constants.h"
+
 namespace ceres {
 
 // The brdf is based on:
@@ -45,8 +47,6 @@
 // https://github.com/wdas/brdf/blob/master/src/brdfs/disney.brdf
 struct Brdf {
  public:
-  Brdf() {}
-
   template <typename T>
   inline bool operator()(const T* const material,
                          const T* const c_ptr,
@@ -141,7 +141,7 @@
     const T gr = cggxn_dot_l * cggxn_dot_v;
 
     const Vec3 result_no_cosine =
-        (T(1.0 / M_PI) * Lerp(fd, ss, subsurface) * c + f_sheen) *
+        (T(1.0 / constants::pi) * Lerp(fd, ss, subsurface) * c + f_sheen) *
             (T(1) - metallic) +
         gs * fs * ds +
         Vec3(T(0.25), T(0.25), T(0.25)) * clearcoat * gr * fr * dr;
@@ -179,11 +179,11 @@
     T result = T(0);
 
     if (a >= T(1)) {
-      result = T(1 / M_PI);
+      result = T(1 / constants::pi);
     } else {
       const T a2 = a * a;
       const T t = T(1) + (a2 - T(1)) * n_dot_h * n_dot_h;
-      result = (a2 - T(1)) / (T(M_PI) * T(log(a2) * t));
+      result = (a2 - T(1)) / (T(constants::pi) * T(log(a2) * t));
     }
     return result;
   }
@@ -194,7 +194,7 @@
                      const T& h_dot_y,
                      const T& ax,
                      const T& ay) const {
-    return T(1) / (T(M_PI) * ax * ay *
+    return T(1) / (T(constants::pi) * ax * ay *
                    Square(Square(h_dot_x / ax) + Square(h_dot_y / ay) +
                           n_dot_h * n_dot_h));
   }
diff --git a/third_party/ceres/internal/ceres/autodiff_benchmarks/relative_pose_error.h b/third_party/ceres/internal/ceres/autodiff_benchmarks/relative_pose_error.h
index b5c1a93..a54a92f 100644
--- a/third_party/ceres/internal/ceres/autodiff_benchmarks/relative_pose_error.h
+++ b/third_party/ceres/internal/ceres/autodiff_benchmarks/relative_pose_error.h
@@ -33,6 +33,7 @@
 #define CERES_INTERNAL_AUTODIFF_BENCHMARK_RELATIVE_POSE_ERROR_H_
 
 #include <Eigen/Dense>
+#include <utility>
 
 #include "ceres/rotation.h"
 
@@ -43,9 +44,8 @@
 // poses T_w_i and T_w_j. For the residual we use the log of the the residual
 // pose, in split representation SO(3) x R^3.
 struct RelativePoseError {
-  RelativePoseError(const Eigen::Quaterniond& q_i_j,
-                    const Eigen::Vector3d& t_i_j)
-      : meas_q_i_j_(q_i_j), meas_t_i_j_(t_i_j) {}
+  RelativePoseError(Eigen::Quaterniond q_i_j, Eigen::Vector3d t_i_j)
+      : meas_q_i_j_(std::move(q_i_j)), meas_t_i_j_(std::move(t_i_j)) {}
 
   template <typename T>
   inline bool operator()(const T* const pose_i_ptr,
diff --git a/third_party/ceres/internal/ceres/autodiff_benchmarks/snavely_reprojection_error.h b/third_party/ceres/internal/ceres/autodiff_benchmarks/snavely_reprojection_error.h
index 795342f..439ee9b 100644
--- a/third_party/ceres/internal/ceres/autodiff_benchmarks/snavely_reprojection_error.h
+++ b/third_party/ceres/internal/ceres/autodiff_benchmarks/snavely_reprojection_error.h
@@ -40,7 +40,6 @@
   SnavelyReprojectionError(double observed_x, double observed_y)
       : observed_x(observed_x), observed_y(observed_y) {}
 
-  SnavelyReprojectionError() = default;
   template <typename T>
   inline bool operator()(const T* const camera,
                          const T* const point,
diff --git a/third_party/ceres/internal/ceres/autodiff_cost_function_test.cc b/third_party/ceres/internal/ceres/autodiff_cost_function_test.cc
index cc340f6..dca67ba 100644
--- a/third_party/ceres/internal/ceres/autodiff_cost_function_test.cc
+++ b/third_party/ceres/internal/ceres/autodiff_cost_function_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2024 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -36,8 +36,7 @@
 #include "ceres/cost_function.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 class BinaryScalarCost {
  public:
@@ -57,7 +56,7 @@
       new AutoDiffCostFunction<BinaryScalarCost, 1, 2, 2>(
           new BinaryScalarCost(1.0));
 
-  double** parameters = new double*[2];
+  auto** parameters = new double*[2];
   parameters[0] = new double[2];
   parameters[1] = new double[2];
 
@@ -67,7 +66,7 @@
   parameters[1][0] = 3;
   parameters[1][1] = 4;
 
-  double** jacobians = new double*[2];
+  auto** jacobians = new double*[2];
   jacobians[0] = new double[2];
   jacobians[1] = new double[2];
 
@@ -126,8 +125,8 @@
                                1,
                                1>(new TenParameterCost);
 
-  double** parameters = new double*[10];
-  double** jacobians = new double*[10];
+  auto** parameters = new double*[10];
+  auto** jacobians = new double*[10];
   for (int i = 0; i < 10; ++i) {
     parameters[i] = new double[1];
     parameters[i][0] = i;
@@ -179,5 +178,24 @@
   EXPECT_FALSE(IsArrayValid(2, residuals));
 }
 
-}  // namespace internal
-}  // namespace ceres
+TEST(AutodiffCostFunction, ArgumentForwarding) {
+  // No narrowing conversion warning should be emitted
+  auto cost_function1 =
+      std::make_unique<AutoDiffCostFunction<BinaryScalarCost, 1, 2, 2>>(1);
+  auto cost_function2 =
+      std::make_unique<AutoDiffCostFunction<BinaryScalarCost, 1, 2, 2>>(2.0);
+  // Default constructible functor
+  auto cost_function3 =
+      std::make_unique<AutoDiffCostFunction<OnlyFillsOneOutputFunctor, 1, 1>>();
+}
+
+TEST(AutodiffCostFunction, UniquePtrCtor) {
+  auto cost_function1 =
+      std::make_unique<AutoDiffCostFunction<BinaryScalarCost, 1, 2, 2>>(
+          std::make_unique<BinaryScalarCost>(1));
+  auto cost_function2 =
+      std::make_unique<AutoDiffCostFunction<BinaryScalarCost, 1, 2, 2>>(
+          std::make_unique<BinaryScalarCost>(2.0));
+}
+
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/autodiff_first_order_function_test.cc b/third_party/ceres/internal/ceres/autodiff_first_order_function_test.cc
index 7db7835..e663f13 100644
--- a/third_party/ceres/internal/ceres/autodiff_first_order_function_test.cc
+++ b/third_party/ceres/internal/ceres/autodiff_first_order_function_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -44,7 +44,7 @@
   explicit QuadraticCostFunctor(double a) : a_(a) {}
   template <typename T>
   bool operator()(const T* const x, T* cost) const {
-    cost[0] = x[0] * x[1] + x[2] * x[3] - T(a_);
+    cost[0] = x[0] * x[1] + x[2] * x[3] - a_;
     return true;
   }
 
diff --git a/third_party/ceres/internal/ceres/autodiff_local_parameterization_test.cc b/third_party/ceres/internal/ceres/autodiff_local_parameterization_test.cc
deleted file mode 100644
index 36fd3c9..0000000
--- a/third_party/ceres/internal/ceres/autodiff_local_parameterization_test.cc
+++ /dev/null
@@ -1,227 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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 Google Inc. 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.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/autodiff_local_parameterization.h"
-
-#include <cmath>
-
-#include "ceres/local_parameterization.h"
-#include "ceres/rotation.h"
-#include "gtest/gtest.h"
-
-namespace ceres {
-namespace internal {
-
-struct IdentityPlus {
-  template <typename T>
-  bool operator()(const T* x, const T* delta, T* x_plus_delta) const {
-    for (int i = 0; i < 3; ++i) {
-      x_plus_delta[i] = x[i] + delta[i];
-    }
-    return true;
-  }
-};
-
-TEST(AutoDiffLocalParameterizationTest, IdentityParameterization) {
-  AutoDiffLocalParameterization<IdentityPlus, 3, 3> parameterization;
-
-  double x[3] = {1.0, 2.0, 3.0};
-  double delta[3] = {0.0, 1.0, 2.0};
-  double x_plus_delta[3] = {0.0, 0.0, 0.0};
-  parameterization.Plus(x, delta, x_plus_delta);
-
-  EXPECT_EQ(x_plus_delta[0], 1.0);
-  EXPECT_EQ(x_plus_delta[1], 3.0);
-  EXPECT_EQ(x_plus_delta[2], 5.0);
-
-  double jacobian[9];
-  parameterization.ComputeJacobian(x, jacobian);
-  int k = 0;
-  for (int i = 0; i < 3; ++i) {
-    for (int j = 0; j < 3; ++j, ++k) {
-      EXPECT_EQ(jacobian[k], (i == j) ? 1.0 : 0.0);
-    }
-  }
-}
-
-struct ScaledPlus {
-  explicit ScaledPlus(const double& scale_factor)
-      : scale_factor_(scale_factor) {}
-
-  template <typename T>
-  bool operator()(const T* x, const T* delta, T* x_plus_delta) const {
-    for (int i = 0; i < 3; ++i) {
-      x_plus_delta[i] = x[i] + T(scale_factor_) * delta[i];
-    }
-    return true;
-  }
-
-  const double scale_factor_;
-};
-
-TEST(AutoDiffLocalParameterizationTest, ScaledParameterization) {
-  const double kTolerance = 1e-14;
-
-  AutoDiffLocalParameterization<ScaledPlus, 3, 3> parameterization(
-      new ScaledPlus(1.2345));
-
-  double x[3] = {1.0, 2.0, 3.0};
-  double delta[3] = {0.0, 1.0, 2.0};
-  double x_plus_delta[3] = {0.0, 0.0, 0.0};
-  parameterization.Plus(x, delta, x_plus_delta);
-
-  EXPECT_NEAR(x_plus_delta[0], 1.0, kTolerance);
-  EXPECT_NEAR(x_plus_delta[1], 3.2345, kTolerance);
-  EXPECT_NEAR(x_plus_delta[2], 5.469, kTolerance);
-
-  double jacobian[9];
-  parameterization.ComputeJacobian(x, jacobian);
-  int k = 0;
-  for (int i = 0; i < 3; ++i) {
-    for (int j = 0; j < 3; ++j, ++k) {
-      EXPECT_NEAR(jacobian[k], (i == j) ? 1.2345 : 0.0, kTolerance);
-    }
-  }
-}
-
-struct QuaternionPlus {
-  template <typename T>
-  bool operator()(const T* x, const T* delta, T* x_plus_delta) const {
-    const T squared_norm_delta =
-        delta[0] * delta[0] + delta[1] * delta[1] + delta[2] * delta[2];
-
-    T q_delta[4];
-    if (squared_norm_delta > T(0.0)) {
-      T norm_delta = sqrt(squared_norm_delta);
-      const T sin_delta_by_delta = sin(norm_delta) / norm_delta;
-      q_delta[0] = cos(norm_delta);
-      q_delta[1] = sin_delta_by_delta * delta[0];
-      q_delta[2] = sin_delta_by_delta * delta[1];
-      q_delta[3] = sin_delta_by_delta * delta[2];
-    } else {
-      // We do not just use q_delta = [1,0,0,0] here because that is a
-      // constant and when used for automatic differentiation will
-      // lead to a zero derivative. Instead we take a first order
-      // approximation and evaluate it at zero.
-      q_delta[0] = T(1.0);
-      q_delta[1] = delta[0];
-      q_delta[2] = delta[1];
-      q_delta[3] = delta[2];
-    }
-
-    QuaternionProduct(q_delta, x, x_plus_delta);
-    return true;
-  }
-};
-
-static void QuaternionParameterizationTestHelper(const double* x,
-                                                 const double* delta) {
-  const double kTolerance = 1e-14;
-  double x_plus_delta_ref[4] = {0.0, 0.0, 0.0, 0.0};
-  double jacobian_ref[12];
-
-  QuaternionParameterization ref_parameterization;
-  ref_parameterization.Plus(x, delta, x_plus_delta_ref);
-  ref_parameterization.ComputeJacobian(x, jacobian_ref);
-
-  double x_plus_delta[4] = {0.0, 0.0, 0.0, 0.0};
-  double jacobian[12];
-  AutoDiffLocalParameterization<QuaternionPlus, 4, 3> parameterization;
-  parameterization.Plus(x, delta, x_plus_delta);
-  parameterization.ComputeJacobian(x, jacobian);
-
-  for (int i = 0; i < 4; ++i) {
-    EXPECT_NEAR(x_plus_delta[i], x_plus_delta_ref[i], kTolerance);
-  }
-
-  // clang-format off
-  const double x_plus_delta_norm =
-      sqrt(x_plus_delta[0] * x_plus_delta[0] +
-           x_plus_delta[1] * x_plus_delta[1] +
-           x_plus_delta[2] * x_plus_delta[2] +
-           x_plus_delta[3] * x_plus_delta[3]);
-  // clang-format on
-
-  EXPECT_NEAR(x_plus_delta_norm, 1.0, kTolerance);
-
-  for (int i = 0; i < 12; ++i) {
-    EXPECT_TRUE(std::isfinite(jacobian[i]));
-    EXPECT_NEAR(jacobian[i], jacobian_ref[i], kTolerance)
-        << "Jacobian mismatch: i = " << i << "\n Expected \n"
-        << ConstMatrixRef(jacobian_ref, 4, 3) << "\n Actual \n"
-        << ConstMatrixRef(jacobian, 4, 3);
-  }
-}
-
-TEST(AutoDiffLocalParameterization, QuaternionParameterizationZeroTest) {
-  double x[4] = {0.5, 0.5, 0.5, 0.5};
-  double delta[3] = {0.0, 0.0, 0.0};
-  QuaternionParameterizationTestHelper(x, delta);
-}
-
-TEST(AutoDiffLocalParameterization, QuaternionParameterizationNearZeroTest) {
-  double x[4] = {0.52, 0.25, 0.15, 0.45};
-  // clang-format off
-  double norm_x = sqrt(x[0] * x[0] +
-                       x[1] * x[1] +
-                       x[2] * x[2] +
-                       x[3] * x[3]);
-  // clang-format on
-  for (int i = 0; i < 4; ++i) {
-    x[i] = x[i] / norm_x;
-  }
-
-  double delta[3] = {0.24, 0.15, 0.10};
-  for (int i = 0; i < 3; ++i) {
-    delta[i] = delta[i] * 1e-14;
-  }
-
-  QuaternionParameterizationTestHelper(x, delta);
-}
-
-TEST(AutoDiffLocalParameterization, QuaternionParameterizationNonZeroTest) {
-  double x[4] = {0.52, 0.25, 0.15, 0.45};
-  // clang-format off
-  double norm_x = sqrt(x[0] * x[0] +
-                       x[1] * x[1] +
-                       x[2] * x[2] +
-                       x[3] * x[3]);
-  // clang-format on
-
-  for (int i = 0; i < 4; ++i) {
-    x[i] = x[i] / norm_x;
-  }
-
-  double delta[3] = {0.24, 0.15, 0.10};
-  QuaternionParameterizationTestHelper(x, delta);
-}
-
-}  // namespace internal
-}  // namespace ceres
diff --git a/third_party/ceres/internal/ceres/autodiff_manifold_test.cc b/third_party/ceres/internal/ceres/autodiff_manifold_test.cc
new file mode 100644
index 0000000..c687719
--- /dev/null
+++ b/third_party/ceres/internal/ceres/autodiff_manifold_test.cc
@@ -0,0 +1,295 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/autodiff_manifold.h"
+
+#include <cmath>
+
+#include "ceres/constants.h"
+#include "ceres/manifold.h"
+#include "ceres/manifold_test_utils.h"
+#include "ceres/rotation.h"
+#include "gtest/gtest.h"
+
+namespace ceres::internal {
+
+namespace {
+
+constexpr int kNumTrials = 1000;
+constexpr double kTolerance = 1e-9;
+
+Vector RandomQuaternion() {
+  Vector x = Vector::Random(4);
+  x.normalize();
+  return x;
+}
+
+}  // namespace
+
+struct EuclideanFunctor {
+  template <typename T>
+  bool Plus(const T* x, const T* delta, T* x_plus_delta) const {
+    for (int i = 0; i < 3; ++i) {
+      x_plus_delta[i] = x[i] + delta[i];
+    }
+    return true;
+  }
+
+  template <typename T>
+  bool Minus(const T* y, const T* x, T* y_minus_x) const {
+    for (int i = 0; i < 3; ++i) {
+      y_minus_x[i] = y[i] - x[i];
+    }
+    return true;
+  }
+};
+
+TEST(AutoDiffLManifoldTest, EuclideanManifold) {
+  AutoDiffManifold<EuclideanFunctor, 3, 3> manifold;
+  EXPECT_EQ(manifold.AmbientSize(), 3);
+  EXPECT_EQ(manifold.TangentSize(), 3);
+
+  for (int trial = 0; trial < kNumTrials; ++trial) {
+    const Vector x = Vector::Random(manifold.AmbientSize());
+    const Vector y = Vector::Random(manifold.AmbientSize());
+    Vector delta = Vector::Random(manifold.TangentSize());
+    Vector x_plus_delta = Vector::Zero(manifold.AmbientSize());
+
+    manifold.Plus(x.data(), delta.data(), x_plus_delta.data());
+    EXPECT_NEAR((x_plus_delta - x - delta).norm() / (x + delta).norm(),
+                0.0,
+                kTolerance);
+
+    EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
+  }
+}
+
+struct ScaledFunctor {
+  explicit ScaledFunctor(const double s) : s(s) {}
+
+  template <typename T>
+  bool Plus(const T* x, const T* delta, T* x_plus_delta) const {
+    for (int i = 0; i < 3; ++i) {
+      x_plus_delta[i] = x[i] + s * delta[i];
+    }
+    return true;
+  }
+
+  template <typename T>
+  bool Minus(const T* y, const T* x, T* y_minus_x) const {
+    for (int i = 0; i < 3; ++i) {
+      y_minus_x[i] = (y[i] - x[i]) / s;
+    }
+    return true;
+  }
+
+  const double s;
+};
+
+TEST(AutoDiffManifoldTest, ScaledManifold) {
+  constexpr double kScale = 1.2342;
+  AutoDiffManifold<ScaledFunctor, 3, 3> manifold(new ScaledFunctor(kScale));
+  EXPECT_EQ(manifold.AmbientSize(), 3);
+  EXPECT_EQ(manifold.TangentSize(), 3);
+
+  for (int trial = 0; trial < kNumTrials; ++trial) {
+    const Vector x = Vector::Random(manifold.AmbientSize());
+    const Vector y = Vector::Random(manifold.AmbientSize());
+    Vector delta = Vector::Random(manifold.TangentSize());
+    Vector x_plus_delta = Vector::Zero(manifold.AmbientSize());
+
+    manifold.Plus(x.data(), delta.data(), x_plus_delta.data());
+    EXPECT_NEAR((x_plus_delta - x - delta * kScale).norm() /
+                    (x + delta * kScale).norm(),
+                0.0,
+                kTolerance);
+
+    EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
+  }
+}
+
+// Templated functor that implements the Plus and Minus operations on the
+// Quaternion manifold.
+struct QuaternionFunctor {
+  template <typename T>
+  bool Plus(const T* x, const T* delta, T* x_plus_delta) const {
+    const T squared_norm_delta =
+        delta[0] * delta[0] + delta[1] * delta[1] + delta[2] * delta[2];
+
+    T q_delta[4];
+    if (squared_norm_delta > T(0.0)) {
+      T norm_delta = sqrt(squared_norm_delta);
+      const T sin_delta_by_delta = sin(norm_delta) / norm_delta;
+      q_delta[0] = cos(norm_delta);
+      q_delta[1] = sin_delta_by_delta * delta[0];
+      q_delta[2] = sin_delta_by_delta * delta[1];
+      q_delta[3] = sin_delta_by_delta * delta[2];
+    } else {
+      // We do not just use q_delta = [1,0,0,0] here because that is a
+      // constant and when used for automatic differentiation will
+      // lead to a zero derivative. Instead we take a first order
+      // approximation and evaluate it at zero.
+      q_delta[0] = T(1.0);
+      q_delta[1] = delta[0];
+      q_delta[2] = delta[1];
+      q_delta[3] = delta[2];
+    }
+
+    QuaternionProduct(q_delta, x, x_plus_delta);
+    return true;
+  }
+
+  template <typename T>
+  bool Minus(const T* y, const T* x, T* y_minus_x) const {
+    T minus_x[4] = {x[0], -x[1], -x[2], -x[3]};
+    T ambient_y_minus_x[4];
+    QuaternionProduct(y, minus_x, ambient_y_minus_x);
+    T u_norm = sqrt(ambient_y_minus_x[1] * ambient_y_minus_x[1] +
+                    ambient_y_minus_x[2] * ambient_y_minus_x[2] +
+                    ambient_y_minus_x[3] * ambient_y_minus_x[3]);
+    if (u_norm > 0.0) {
+      T theta = atan2(u_norm, ambient_y_minus_x[0]);
+      y_minus_x[0] = theta * ambient_y_minus_x[1] / u_norm;
+      y_minus_x[1] = theta * ambient_y_minus_x[2] / u_norm;
+      y_minus_x[2] = theta * ambient_y_minus_x[3] / u_norm;
+    } else {
+      // We do not use [0,0,0] here because even though the value part is
+      // a constant, the derivative part is not.
+      y_minus_x[0] = ambient_y_minus_x[1];
+      y_minus_x[1] = ambient_y_minus_x[2];
+      y_minus_x[2] = ambient_y_minus_x[3];
+    }
+    return true;
+  }
+};
+
+TEST(AutoDiffManifoldTest, QuaternionPlusPiBy2) {
+  AutoDiffManifold<QuaternionFunctor, 4, 3> manifold;
+
+  Vector x = Vector::Zero(4);
+  x[0] = 1.0;
+
+  for (int i = 0; i < 3; ++i) {
+    Vector delta = Vector::Zero(3);
+    delta[i] = constants::pi / 2;
+    Vector x_plus_delta = Vector::Zero(4);
+    EXPECT_TRUE(manifold.Plus(x.data(), delta.data(), x_plus_delta.data()));
+
+    // Expect that the element corresponding to pi/2 is +/- 1. All other
+    // elements should be zero.
+    for (int j = 0; j < 4; ++j) {
+      if (i == (j - 1)) {
+        EXPECT_LT(std::abs(x_plus_delta[j]) - 1,
+                  std::numeric_limits<double>::epsilon())
+            << "\ndelta = " << delta.transpose()
+            << "\nx_plus_delta = " << x_plus_delta.transpose()
+            << "\n expected the " << j
+            << "th element of x_plus_delta to be +/- 1.";
+      } else {
+        EXPECT_LT(std::abs(x_plus_delta[j]),
+                  std::numeric_limits<double>::epsilon())
+            << "\ndelta = " << delta.transpose()
+            << "\nx_plus_delta = " << x_plus_delta.transpose()
+            << "\n expected the " << j << "th element of x_plus_delta to be 0.";
+      }
+    }
+    EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(
+        manifold, x, delta, x_plus_delta, kTolerance);
+  }
+}
+
+// Compute the expected value of Quaternion::Plus via functions in rotation.h
+// and compares it to the one computed by Quaternion::Plus.
+MATCHER_P2(QuaternionPlusIsCorrectAt, x, delta, "") {
+  // This multiplication by 2 is needed because AngleAxisToQuaternion uses
+  // |delta|/2 as the angle of rotation where as in the implementation of
+  // Quaternion for historical reasons we use |delta|.
+  const Vector two_delta = delta * 2;
+  Vector delta_q(4);
+  AngleAxisToQuaternion(two_delta.data(), delta_q.data());
+
+  Vector expected(4);
+  QuaternionProduct(delta_q.data(), x.data(), expected.data());
+  Vector actual(4);
+  EXPECT_TRUE(arg.Plus(x.data(), delta.data(), actual.data()));
+
+  const double n = (actual - expected).norm();
+  const double d = expected.norm();
+  const double diffnorm = n / d;
+  if (diffnorm > kTolerance) {
+    *result_listener << "\nx: " << x.transpose()
+                     << "\ndelta: " << delta.transpose()
+                     << "\nexpected: " << expected.transpose()
+                     << "\nactual: " << actual.transpose()
+                     << "\ndiff: " << (expected - actual).transpose()
+                     << "\ndiffnorm : " << diffnorm;
+    return false;
+  }
+  return true;
+}
+
+TEST(AutoDiffManifoldTest, QuaternionGenericDelta) {
+  AutoDiffManifold<QuaternionFunctor, 4, 3> manifold;
+  for (int trial = 0; trial < kNumTrials; ++trial) {
+    const Vector x = RandomQuaternion();
+    const Vector y = RandomQuaternion();
+    Vector delta = Vector::Random(3);
+    EXPECT_THAT(manifold, QuaternionPlusIsCorrectAt(x, delta));
+    EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
+  }
+}
+
+TEST(AutoDiffManifoldTest, QuaternionSmallDelta) {
+  AutoDiffManifold<QuaternionFunctor, 4, 3> manifold;
+  for (int trial = 0; trial < kNumTrials; ++trial) {
+    const Vector x = RandomQuaternion();
+    const Vector y = RandomQuaternion();
+    Vector delta = Vector::Random(3);
+    delta.normalize();
+    delta *= 1e-6;
+    EXPECT_THAT(manifold, QuaternionPlusIsCorrectAt(x, delta));
+    EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
+  }
+}
+
+TEST(AutoDiffManifold, QuaternionDeltaJustBelowPi) {
+  AutoDiffManifold<QuaternionFunctor, 4, 3> manifold;
+  for (int trial = 0; trial < kNumTrials; ++trial) {
+    const Vector x = RandomQuaternion();
+    const Vector y = RandomQuaternion();
+    Vector delta = Vector::Random(3);
+    delta.normalize();
+    delta *= (constants::pi - 1e-6);
+    EXPECT_THAT(manifold, QuaternionPlusIsCorrectAt(x, delta));
+    EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
+  }
+}
+
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/autodiff_test.cc b/third_party/ceres/internal/ceres/autodiff_test.cc
index e42da58..19adcae 100644
--- a/third_party/ceres/internal/ceres/autodiff_test.cc
+++ b/third_party/ceres/internal/ceres/autodiff_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -30,11 +30,13 @@
 
 #include "ceres/internal/autodiff.h"
 
-#include "ceres/random.h"
+#include <algorithm>
+#include <iterator>
+#include <random>
+
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template <typename T>
 inline T& RowMajorAccess(T* base, int rows, int cols, int i, int j) {
@@ -163,18 +165,19 @@
 
 // Test projective camera model projector.
 TEST(AutoDiff, ProjectiveCameraModel) {
-  srand(5);
   double const tol = 1e-10;  // floating-point tolerance.
   double const del = 1e-4;   // finite-difference step.
   double const err = 1e-6;   // finite-difference tolerance.
 
   Projective b;
+  std::mt19937 prng;
+  std::uniform_real_distribution<double> uniform01(0.0, 1.0);
 
   // Make random P and X, in a single vector.
   double PX[12 + 4];
-  for (int i = 0; i < 12 + 4; ++i) {
-    PX[i] = RandDouble();
-  }
+  std::generate(std::begin(PX), std::end(PX), [&prng, &uniform01] {
+    return uniform01(prng);
+  });
 
   // Handy names for the P and X parts.
   double* P = PX + 0;
@@ -283,16 +286,20 @@
 
 // This test is similar in structure to the previous one.
 TEST(AutoDiff, Metric) {
-  srand(5);
   double const tol = 1e-10;  // floating-point tolerance.
   double const del = 1e-4;   // finite-difference step.
-  double const err = 1e-5;   // finite-difference tolerance.
+  double const err = 2e-5;   // finite-difference tolerance.
 
   Metric b;
 
   // Make random parameter vector.
   double qcX[4 + 3 + 3];
-  for (int i = 0; i < 4 + 3 + 3; ++i) qcX[i] = RandDouble();
+  std::mt19937 prng;
+  std::uniform_real_distribution<double> uniform01(0.0, 1.0);
+
+  std::generate(std::begin(qcX), std::end(qcX), [&prng, &uniform01] {
+    return uniform01(prng);
+  });
 
   // Handy names.
   double* q = qcX;
@@ -662,7 +669,7 @@
   // this function.
   y += 1;
 
-  typedef Jet<double, 2> JetT;
+  using JetT = Jet<double, 2>;
   FixedArray<JetT, (256 * 7) / sizeof(JetT)> x(3);
 
   // Need this to makes sure that x does not get optimized out.
@@ -672,5 +679,4 @@
 #pragma clang diagnostic pop
 #endif
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/blas.cc b/third_party/ceres/internal/ceres/blas.cc
deleted file mode 100644
index f8d006e..0000000
--- a/third_party/ceres/internal/ceres/blas.cc
+++ /dev/null
@@ -1,82 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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 Google Inc. 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.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/blas.h"
-
-#include "ceres/internal/port.h"
-#include "glog/logging.h"
-
-#ifndef CERES_NO_LAPACK
-extern "C" void dsyrk_(char* uplo,
-                       char* trans,
-                       int* n,
-                       int* k,
-                       double* alpha,
-                       double* a,
-                       int* lda,
-                       double* beta,
-                       double* c,
-                       int* ldc);
-#endif
-
-namespace ceres {
-namespace internal {
-
-void BLAS::SymmetricRankKUpdate(int num_rows,
-                                int num_cols,
-                                const double* a,
-                                bool transpose,
-                                double alpha,
-                                double beta,
-                                double* c) {
-#ifdef CERES_NO_LAPACK
-  LOG(FATAL) << "Ceres was built without a BLAS library.";
-#else
-  char uplo = 'L';
-  char trans = transpose ? 'T' : 'N';
-  int n = transpose ? num_cols : num_rows;
-  int k = transpose ? num_rows : num_cols;
-  int lda = k;
-  int ldc = n;
-  dsyrk_(&uplo,
-         &trans,
-         &n,
-         &k,
-         &alpha,
-         const_cast<double*>(a),
-         &lda,
-         &beta,
-         c,
-         &ldc);
-#endif
-}
-
-}  // namespace internal
-}  // namespace ceres
diff --git a/third_party/ceres/internal/ceres/blas.h b/third_party/ceres/internal/ceres/blas.h
deleted file mode 100644
index a43301c..0000000
--- a/third_party/ceres/internal/ceres/blas.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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 Google Inc. 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.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// Wrapper functions around BLAS functions.
-
-#ifndef CERES_INTERNAL_BLAS_H_
-#define CERES_INTERNAL_BLAS_H_
-
-namespace ceres {
-namespace internal {
-
-class BLAS {
- public:
-  // transpose = true  : c = alpha * a'a + beta * c;
-  // transpose = false : c = alpha * aa' + beta * c;
-  //
-  // Assumes column major matrices.
-  static void SymmetricRankKUpdate(int num_rows,
-                                   int num_cols,
-                                   const double* a,
-                                   bool transpose,
-                                   double alpha,
-                                   double beta,
-                                   double* c);
-};
-
-}  // namespace internal
-}  // namespace ceres
-
-#endif  // CERES_INTERNAL_BLAS_H_
diff --git a/third_party/ceres/internal/ceres/block_evaluate_preparer.cc b/third_party/ceres/internal/ceres/block_evaluate_preparer.cc
index 7db96d9..c8b8177 100644
--- a/third_party/ceres/internal/ceres/block_evaluate_preparer.cc
+++ b/third_party/ceres/internal/ceres/block_evaluate_preparer.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -38,8 +38,7 @@
 #include "ceres/residual_block.h"
 #include "ceres/sparse_matrix.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 void BlockEvaluatePreparer::Init(int const* const* jacobian_layout,
                                  int max_derivatives_per_residual_block) {
@@ -53,7 +52,7 @@
                                     SparseMatrix* jacobian,
                                     double** jacobians) {
   // If the overall jacobian is not available, use the scratch space.
-  if (jacobian == NULL) {
+  if (jacobian == nullptr) {
     scratch_evaluate_preparer_.Prepare(
         residual_block, residual_block_index, jacobian, jacobians);
     return;
@@ -73,10 +72,9 @@
       // parameters. Instead, bump the pointer for active parameters only.
       jacobian_block_offset++;
     } else {
-      jacobians[j] = NULL;
+      jacobians[j] = nullptr;
     }
   }
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/block_evaluate_preparer.h b/third_party/ceres/internal/ceres/block_evaluate_preparer.h
index 4378689..8febfac 100644
--- a/third_party/ceres/internal/ceres/block_evaluate_preparer.h
+++ b/third_party/ceres/internal/ceres/block_evaluate_preparer.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -36,15 +36,15 @@
 #ifndef CERES_INTERNAL_BLOCK_EVALUATE_PREPARER_H_
 #define CERES_INTERNAL_BLOCK_EVALUATE_PREPARER_H_
 
+#include "ceres/internal/export.h"
 #include "ceres/scratch_evaluate_preparer.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 class ResidualBlock;
 class SparseMatrix;
 
-class BlockEvaluatePreparer {
+class CERES_NO_EXPORT BlockEvaluatePreparer {
  public:
   // Using Init() instead of a constructor allows for allocating this structure
   // with new[]. This is because C++ doesn't allow passing arguments to objects
@@ -71,7 +71,6 @@
   ScratchEvaluatePreparer scratch_evaluate_preparer_;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_INTERNAL_BLOCK_EVALUATE_PREPARER_H_
diff --git a/third_party/ceres/internal/ceres/block_jacobi_preconditioner.cc b/third_party/ceres/internal/ceres/block_jacobi_preconditioner.cc
index 6f37aca..8f8893f 100644
--- a/third_party/ceres/internal/ceres/block_jacobi_preconditioner.cc
+++ b/third_party/ceres/internal/ceres/block_jacobi_preconditioner.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -30,72 +30,197 @@
 
 #include "ceres/block_jacobi_preconditioner.h"
 
+#include <memory>
+#include <mutex>
+#include <utility>
+#include <vector>
+
+#include "Eigen/Dense"
 #include "ceres/block_random_access_diagonal_matrix.h"
 #include "ceres/block_sparse_matrix.h"
 #include "ceres/block_structure.h"
 #include "ceres/casts.h"
 #include "ceres/internal/eigen.h"
+#include "ceres/parallel_for.h"
+#include "ceres/small_blas.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
-BlockJacobiPreconditioner::BlockJacobiPreconditioner(
-    const BlockSparseMatrix& A) {
-  const CompressedRowBlockStructure* bs = A.block_structure();
-  std::vector<int> blocks(bs->cols.size());
-  for (int i = 0; i < blocks.size(); ++i) {
-    blocks[i] = bs->cols[i].size;
-  }
-
-  m_.reset(new BlockRandomAccessDiagonalMatrix(blocks));
+BlockSparseJacobiPreconditioner::BlockSparseJacobiPreconditioner(
+    Preconditioner::Options options, const BlockSparseMatrix& A)
+    : options_(std::move(options)) {
+  m_ = std::make_unique<BlockRandomAccessDiagonalMatrix>(
+      A.block_structure()->cols, options_.context, options_.num_threads);
 }
 
-BlockJacobiPreconditioner::~BlockJacobiPreconditioner() {}
+BlockSparseJacobiPreconditioner::~BlockSparseJacobiPreconditioner() = default;
 
-bool BlockJacobiPreconditioner::UpdateImpl(const BlockSparseMatrix& A,
-                                           const double* D) {
+bool BlockSparseJacobiPreconditioner::UpdateImpl(const BlockSparseMatrix& A,
+                                                 const double* D) {
   const CompressedRowBlockStructure* bs = A.block_structure();
   const double* values = A.values();
   m_->SetZero();
-  for (int i = 0; i < bs->rows.size(); ++i) {
-    const int row_block_size = bs->rows[i].block.size;
-    const std::vector<Cell>& cells = bs->rows[i].cells;
-    for (int j = 0; j < cells.size(); ++j) {
-      const int block_id = cells[j].block_id;
-      const int col_block_size = bs->cols[block_id].size;
 
-      int r, c, row_stride, col_stride;
-      CellInfo* cell_info =
-          m_->GetCell(block_id, block_id, &r, &c, &row_stride, &col_stride);
-      MatrixRef m(cell_info->values, row_stride, col_stride);
-      ConstMatrixRef b(
-          values + cells[j].position, row_block_size, col_block_size);
-      m.block(r, c, col_block_size, col_block_size) += b.transpose() * b;
-    }
-  }
+  ParallelFor(options_.context,
+              0,
+              bs->rows.size(),
+              options_.num_threads,
+              [this, bs, values](int i) {
+                const int row_block_size = bs->rows[i].block.size;
+                const std::vector<Cell>& cells = bs->rows[i].cells;
+                for (const auto& cell : cells) {
+                  const int block_id = cell.block_id;
+                  const int col_block_size = bs->cols[block_id].size;
+                  int r, c, row_stride, col_stride;
+                  CellInfo* cell_info = m_->GetCell(
+                      block_id, block_id, &r, &c, &row_stride, &col_stride);
+                  MatrixRef m(cell_info->values, row_stride, col_stride);
+                  ConstMatrixRef b(
+                      values + cell.position, row_block_size, col_block_size);
+                  auto lock =
+                      MakeConditionalLock(options_.num_threads, cell_info->m);
+                  // clang-format off
+                  MatrixTransposeMatrixMultiply<Eigen::Dynamic, Eigen::Dynamic,
+                      Eigen::Dynamic,Eigen::Dynamic, 1>(
+                          values + cell.position, row_block_size,col_block_size,
+                          values + cell.position, row_block_size,col_block_size,
+                          cell_info->values,r, c,row_stride,col_stride);
+                  // clang-format on
+                }
+              });
 
-  if (D != NULL) {
+  if (D != nullptr) {
     // Add the diagonal.
-    int position = 0;
-    for (int i = 0; i < bs->cols.size(); ++i) {
-      const int block_size = bs->cols[i].size;
-      int r, c, row_stride, col_stride;
-      CellInfo* cell_info = m_->GetCell(i, i, &r, &c, &row_stride, &col_stride);
-      MatrixRef m(cell_info->values, row_stride, col_stride);
-      m.block(r, c, block_size, block_size).diagonal() +=
-          ConstVectorRef(D + position, block_size).array().square().matrix();
-      position += block_size;
-    }
+    ParallelFor(options_.context,
+                0,
+                bs->cols.size(),
+                options_.num_threads,
+                [this, bs, D](int i) {
+                  const int block_size = bs->cols[i].size;
+                  int r, c, row_stride, col_stride;
+                  CellInfo* cell_info =
+                      m_->GetCell(i, i, &r, &c, &row_stride, &col_stride);
+                  MatrixRef m(cell_info->values, row_stride, col_stride);
+                  m.block(r, c, block_size, block_size).diagonal() +=
+                      ConstVectorRef(D + bs->cols[i].position, block_size)
+                          .array()
+                          .square()
+                          .matrix();
+                });
   }
 
   m_->Invert();
   return true;
 }
 
-void BlockJacobiPreconditioner::RightMultiply(const double* x,
-                                              double* y) const {
-  m_->RightMultiply(x, y);
+BlockCRSJacobiPreconditioner::BlockCRSJacobiPreconditioner(
+    Preconditioner::Options options, const CompressedRowSparseMatrix& A)
+    : options_(std::move(options)), locks_(A.col_blocks().size()) {
+  auto& col_blocks = A.col_blocks();
+
+  // Compute the number of non-zeros in the preconditioner. This is needed so
+  // that we can construct the CompressedRowSparseMatrix.
+  const int m_nnz = SumSquaredSizes(col_blocks);
+  m_ = std::make_unique<CompressedRowSparseMatrix>(
+      A.num_cols(), A.num_cols(), m_nnz);
+
+  const int num_col_blocks = col_blocks.size();
+
+  // Populate the sparsity structure of the preconditioner matrix.
+  int* m_cols = m_->mutable_cols();
+  int* m_rows = m_->mutable_rows();
+  m_rows[0] = 0;
+  for (int i = 0, idx = 0; i < num_col_blocks; ++i) {
+    // For each column block populate a diagonal block in the preconditioner.
+    // Not that the because of the way the CompressedRowSparseMatrix format
+    // works, the entire diagonal block is laid out contiguously in memory as a
+    // row-major matrix. We will use this when updating the block.
+    auto& block = col_blocks[i];
+    for (int j = 0; j < block.size; ++j) {
+      for (int k = 0; k < block.size; ++k, ++idx) {
+        m_cols[idx] = block.position + k;
+      }
+      m_rows[block.position + j + 1] = idx;
+    }
+  }
+
+  // In reality we only need num_col_blocks locks, however that would require
+  // that in UpdateImpl we are able to look up the column block from the it
+  // first column. To save ourselves this map we will instead spend a few extra
+  // lock objects.
+  std::vector<std::mutex> locks(A.num_cols());
+  locks_.swap(locks);
+  CHECK_EQ(m_rows[A.num_cols()], m_nnz);
 }
 
-}  // namespace internal
-}  // namespace ceres
+BlockCRSJacobiPreconditioner::~BlockCRSJacobiPreconditioner() = default;
+
+bool BlockCRSJacobiPreconditioner::UpdateImpl(
+    const CompressedRowSparseMatrix& A, const double* D) {
+  const auto& col_blocks = A.col_blocks();
+  const auto& row_blocks = A.row_blocks();
+  const int num_col_blocks = col_blocks.size();
+  const int num_row_blocks = row_blocks.size();
+
+  const int* a_rows = A.rows();
+  const int* a_cols = A.cols();
+  const double* a_values = A.values();
+  double* m_values = m_->mutable_values();
+  const int* m_rows = m_->rows();
+
+  m_->SetZero();
+
+  ParallelFor(
+      options_.context,
+      0,
+      num_row_blocks,
+      options_.num_threads,
+      [this, row_blocks, a_rows, a_cols, a_values, m_values, m_rows](int i) {
+        const int row = row_blocks[i].position;
+        const int row_block_size = row_blocks[i].size;
+        const int row_nnz = a_rows[row + 1] - a_rows[row];
+        ConstMatrixRef row_block(
+            a_values + a_rows[row], row_block_size, row_nnz);
+        int c = 0;
+        while (c < row_nnz) {
+          const int idx = a_rows[row] + c;
+          const int col = a_cols[idx];
+          const int col_block_size = m_rows[col + 1] - m_rows[col];
+
+          // We make use of the fact that the entire diagonal block is
+          // stored contiguously in memory as a row-major matrix.
+          MatrixRef m(m_values + m_rows[col], col_block_size, col_block_size);
+          // We do not have a row_stride version of
+          // MatrixTransposeMatrixMultiply, otherwise we could use it
+          // here to further speed up the following expression.
+          auto b = row_block.middleCols(c, col_block_size);
+          auto lock = MakeConditionalLock(options_.num_threads, locks_[col]);
+          m.noalias() += b.transpose() * b;
+          c += col_block_size;
+        }
+      });
+
+  ParallelFor(
+      options_.context,
+      0,
+      num_col_blocks,
+      options_.num_threads,
+      [col_blocks, m_rows, m_values, D](int i) {
+        const int col = col_blocks[i].position;
+        const int col_block_size = col_blocks[i].size;
+        MatrixRef m(m_values + m_rows[col], col_block_size, col_block_size);
+
+        if (D != nullptr) {
+          m.diagonal() +=
+              ConstVectorRef(D + col, col_block_size).array().square().matrix();
+        }
+
+        // TODO(sameeragarwal): Deal with Cholesky inversion failure here and
+        // elsewhere.
+        m = m.llt().solve(Matrix::Identity(col_block_size, col_block_size));
+      });
+
+  return true;
+}
+
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/block_jacobi_preconditioner.h b/third_party/ceres/internal/ceres/block_jacobi_preconditioner.h
index 18f7495..d175802 100644
--- a/third_party/ceres/internal/ceres/block_jacobi_preconditioner.h
+++ b/third_party/ceres/internal/ceres/block_jacobi_preconditioner.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -34,37 +34,34 @@
 #include <memory>
 
 #include "ceres/block_random_access_diagonal_matrix.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 #include "ceres/preconditioner.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 class BlockSparseMatrix;
-struct CompressedRowBlockStructure;
+class CompressedRowSparseMatrix;
 
 // A block Jacobi preconditioner. This is intended for use with
-// conjugate gradients, or other iterative symmetric solvers. To use
-// the preconditioner, create one by passing a BlockSparseMatrix "A"
-// to the constructor. This fixes the sparsity pattern to the pattern
-// of the matrix A^TA.
+// conjugate gradients, or other iterative symmetric solvers.
+
+// This version of the preconditioner is for use with BlockSparseMatrix
+// Jacobians.
 //
-// Before each use of the preconditioner in a solve with conjugate gradients,
-// update the matrix by running Update(A, D). The values of the matrix A are
-// inspected to construct the preconditioner. The vector D is applied as the
-// D^TD diagonal term.
-class CERES_EXPORT_INTERNAL BlockJacobiPreconditioner
+// TODO(https://github.com/ceres-solver/ceres-solver/issues/936):
+// BlockSparseJacobiPreconditioner::RightMultiply will benefit from
+// multithreading
+class CERES_NO_EXPORT BlockSparseJacobiPreconditioner
     : public BlockSparseMatrixPreconditioner {
  public:
   // A must remain valid while the BlockJacobiPreconditioner is.
-  explicit BlockJacobiPreconditioner(const BlockSparseMatrix& A);
-  BlockJacobiPreconditioner(const BlockJacobiPreconditioner&) = delete;
-  void operator=(const BlockJacobiPreconditioner&) = delete;
-
-  virtual ~BlockJacobiPreconditioner();
-
-  // Preconditioner interface
-  void RightMultiply(const double* x, double* y) const final;
+  explicit BlockSparseJacobiPreconditioner(Preconditioner::Options,
+                                           const BlockSparseMatrix& A);
+  ~BlockSparseJacobiPreconditioner() override;
+  void RightMultiplyAndAccumulate(const double* x, double* y) const final {
+    return m_->RightMultiplyAndAccumulate(x, y);
+  }
   int num_rows() const final { return m_->num_rows(); }
   int num_cols() const final { return m_->num_rows(); }
   const BlockRandomAccessDiagonalMatrix& matrix() const { return *m_; }
@@ -72,10 +69,36 @@
  private:
   bool UpdateImpl(const BlockSparseMatrix& A, const double* D) final;
 
+  Preconditioner::Options options_;
   std::unique_ptr<BlockRandomAccessDiagonalMatrix> m_;
 };
 
-}  // namespace internal
-}  // namespace ceres
+// This version of the preconditioner is for use with CompressedRowSparseMatrix
+// Jacobians.
+class CERES_NO_EXPORT BlockCRSJacobiPreconditioner
+    : public CompressedRowSparseMatrixPreconditioner {
+ public:
+  // A must remain valid while the BlockJacobiPreconditioner is.
+  explicit BlockCRSJacobiPreconditioner(Preconditioner::Options options,
+                                        const CompressedRowSparseMatrix& A);
+  ~BlockCRSJacobiPreconditioner() override;
+  void RightMultiplyAndAccumulate(const double* x, double* y) const final {
+    m_->RightMultiplyAndAccumulate(x, y);
+  }
+  int num_rows() const final { return m_->num_rows(); }
+  int num_cols() const final { return m_->num_rows(); }
+  const CompressedRowSparseMatrix& matrix() const { return *m_; }
+
+ private:
+  bool UpdateImpl(const CompressedRowSparseMatrix& A, const double* D) final;
+
+  Preconditioner::Options options_;
+  std::vector<std::mutex> locks_;
+  std::unique_ptr<CompressedRowSparseMatrix> m_;
+};
+
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_BLOCK_JACOBI_PRECONDITIONER_H_
diff --git a/third_party/ceres/internal/ceres/block_jacobi_preconditioner_benchmark.cc b/third_party/ceres/internal/ceres/block_jacobi_preconditioner_benchmark.cc
new file mode 100644
index 0000000..e6571f3
--- /dev/null
+++ b/third_party/ceres/internal/ceres/block_jacobi_preconditioner_benchmark.cc
@@ -0,0 +1,177 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Authors: sameeragarwal@google.com (Sameer Agarwal)
+
+#include <memory>
+#include <random>
+
+#include "Eigen/Dense"
+#include "benchmark/benchmark.h"
+#include "ceres/block_jacobi_preconditioner.h"
+#include "ceres/block_sparse_matrix.h"
+#include "ceres/fake_bundle_adjustment_jacobian.h"
+#include "ceres/internal/config.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres::internal {
+
+constexpr int kNumCameras = 1000;
+constexpr int kNumPoints = 10000;
+constexpr int kCameraSize = 6;
+constexpr int kPointSize = 3;
+constexpr double kVisibility = 0.1;
+
+constexpr int kNumRowBlocks = 100000;
+constexpr int kNumColBlocks = 10000;
+constexpr int kMinRowBlockSize = 1;
+constexpr int kMaxRowBlockSize = 5;
+constexpr int kMinColBlockSize = 1;
+constexpr int kMaxColBlockSize = 15;
+constexpr double kBlockDensity = 5.0 / kNumColBlocks;
+
+static void BM_BlockSparseJacobiPreconditionerBA(benchmark::State& state) {
+  std::mt19937 prng;
+  auto jacobian = CreateFakeBundleAdjustmentJacobian(
+      kNumCameras, kNumPoints, kCameraSize, kPointSize, kVisibility, prng);
+
+  Preconditioner::Options preconditioner_options;
+  ContextImpl context;
+  preconditioner_options.context = &context;
+  preconditioner_options.num_threads = static_cast<int>(state.range(0));
+  context.EnsureMinimumThreads(preconditioner_options.num_threads);
+  BlockSparseJacobiPreconditioner p(preconditioner_options, *jacobian);
+
+  Vector d = Vector::Ones(jacobian->num_cols());
+  for (auto _ : state) {
+    p.Update(*jacobian, d.data());
+  }
+}
+
+BENCHMARK(BM_BlockSparseJacobiPreconditionerBA)
+    ->Arg(1)
+    ->Arg(2)
+    ->Arg(4)
+    ->Arg(8)
+    ->Arg(16);
+
+static void BM_BlockCRSJacobiPreconditionerBA(benchmark::State& state) {
+  std::mt19937 prng;
+  auto jacobian = CreateFakeBundleAdjustmentJacobian(
+      kNumCameras, kNumPoints, kCameraSize, kPointSize, kVisibility, prng);
+
+  auto jacobian_crs = jacobian->ToCompressedRowSparseMatrix();
+  Preconditioner::Options preconditioner_options;
+  ContextImpl context;
+  preconditioner_options.context = &context;
+  preconditioner_options.num_threads = static_cast<int>(state.range(0));
+  context.EnsureMinimumThreads(preconditioner_options.num_threads);
+  BlockCRSJacobiPreconditioner p(preconditioner_options, *jacobian_crs);
+
+  Vector d = Vector::Ones(jacobian_crs->num_cols());
+  for (auto _ : state) {
+    p.Update(*jacobian_crs, d.data());
+  }
+}
+
+BENCHMARK(BM_BlockCRSJacobiPreconditionerBA)
+    ->Arg(1)
+    ->Arg(2)
+    ->Arg(4)
+    ->Arg(8)
+    ->Arg(16);
+
+static void BM_BlockSparseJacobiPreconditionerUnstructured(
+    benchmark::State& state) {
+  BlockSparseMatrix::RandomMatrixOptions options;
+  options.num_row_blocks = kNumRowBlocks;
+  options.num_col_blocks = kNumColBlocks;
+  options.min_row_block_size = kMinRowBlockSize;
+  options.min_col_block_size = kMinColBlockSize;
+  options.max_row_block_size = kMaxRowBlockSize;
+  options.max_col_block_size = kMaxColBlockSize;
+  options.block_density = kBlockDensity;
+  std::mt19937 prng;
+
+  auto jacobian = BlockSparseMatrix::CreateRandomMatrix(options, prng);
+  Preconditioner::Options preconditioner_options;
+  ContextImpl context;
+  preconditioner_options.context = &context;
+  preconditioner_options.num_threads = static_cast<int>(state.range(0));
+  context.EnsureMinimumThreads(preconditioner_options.num_threads);
+  BlockSparseJacobiPreconditioner p(preconditioner_options, *jacobian);
+
+  Vector d = Vector::Ones(jacobian->num_cols());
+  for (auto _ : state) {
+    p.Update(*jacobian, d.data());
+  }
+}
+
+BENCHMARK(BM_BlockSparseJacobiPreconditionerUnstructured)
+    ->Arg(1)
+    ->Arg(2)
+    ->Arg(4)
+    ->Arg(8)
+    ->Arg(16);
+
+static void BM_BlockCRSJacobiPreconditionerUnstructured(
+    benchmark::State& state) {
+  BlockSparseMatrix::RandomMatrixOptions options;
+  options.num_row_blocks = kNumRowBlocks;
+  options.num_col_blocks = kNumColBlocks;
+  options.min_row_block_size = kMinRowBlockSize;
+  options.min_col_block_size = kMinColBlockSize;
+  options.max_row_block_size = kMaxRowBlockSize;
+  options.max_col_block_size = kMaxColBlockSize;
+  options.block_density = kBlockDensity;
+  std::mt19937 prng;
+
+  auto jacobian = BlockSparseMatrix::CreateRandomMatrix(options, prng);
+  auto jacobian_crs = jacobian->ToCompressedRowSparseMatrix();
+  Preconditioner::Options preconditioner_options;
+  ContextImpl context;
+  preconditioner_options.context = &context;
+  preconditioner_options.num_threads = static_cast<int>(state.range(0));
+  context.EnsureMinimumThreads(preconditioner_options.num_threads);
+  BlockCRSJacobiPreconditioner p(preconditioner_options, *jacobian_crs);
+
+  Vector d = Vector::Ones(jacobian_crs->num_cols());
+  for (auto _ : state) {
+    p.Update(*jacobian_crs, d.data());
+  }
+}
+BENCHMARK(BM_BlockCRSJacobiPreconditionerUnstructured)
+    ->Arg(1)
+    ->Arg(2)
+    ->Arg(4)
+    ->Arg(8)
+    ->Arg(16);
+
+}  // namespace ceres::internal
+
+BENCHMARK_MAIN();
diff --git a/third_party/ceres/internal/ceres/block_jacobi_preconditioner_test.cc b/third_party/ceres/internal/ceres/block_jacobi_preconditioner_test.cc
index cc582c6..ca19a0d 100644
--- a/third_party/ceres/internal/ceres/block_jacobi_preconditioner_test.cc
+++ b/third_party/ceres/internal/ceres/block_jacobi_preconditioner_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -31,6 +31,7 @@
 #include "ceres/block_jacobi_preconditioner.h"
 
 #include <memory>
+#include <random>
 #include <vector>
 
 #include "Eigen/Dense"
@@ -39,63 +40,118 @@
 #include "ceres/linear_least_squares_problems.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
-class BlockJacobiPreconditionerTest : public ::testing::Test {
- protected:
-  void SetUpFromProblemId(int problem_id) {
-    std::unique_ptr<LinearLeastSquaresProblem> problem(
-        CreateLinearLeastSquaresProblemFromId(problem_id));
+TEST(BlockSparseJacobiPreconditioner, _) {
+  constexpr int kNumtrials = 10;
+  BlockSparseMatrix::RandomMatrixOptions options;
+  options.num_col_blocks = 3;
+  options.min_col_block_size = 1;
+  options.max_col_block_size = 3;
 
-    CHECK(problem != nullptr);
-    A.reset(down_cast<BlockSparseMatrix*>(problem->A.release()));
-    D.reset(problem->D.release());
+  options.num_row_blocks = 5;
+  options.min_row_block_size = 1;
+  options.max_row_block_size = 4;
+  options.block_density = 0.25;
+  std::mt19937 prng;
 
-    Matrix dense_a;
-    A->ToDenseMatrix(&dense_a);
-    dense_ata = dense_a.transpose() * dense_a;
-    dense_ata += VectorRef(D.get(), A->num_cols())
-                     .array()
-                     .square()
-                     .matrix()
-                     .asDiagonal();
-  }
+  Preconditioner::Options preconditioner_options;
+  ContextImpl context;
+  preconditioner_options.context = &context;
 
-  void VerifyDiagonalBlocks(const int problem_id) {
-    SetUpFromProblemId(problem_id);
+  for (int trial = 0; trial < kNumtrials; ++trial) {
+    auto jacobian = BlockSparseMatrix::CreateRandomMatrix(options, prng);
+    Vector diagonal = Vector::Ones(jacobian->num_cols());
+    Matrix dense_jacobian;
+    jacobian->ToDenseMatrix(&dense_jacobian);
+    Matrix hessian = dense_jacobian.transpose() * dense_jacobian;
+    hessian.diagonal() += diagonal.array().square().matrix();
 
-    BlockJacobiPreconditioner pre(*A);
-    pre.Update(*A, D.get());
-    BlockRandomAccessDiagonalMatrix* m =
-        const_cast<BlockRandomAccessDiagonalMatrix*>(&pre.matrix());
-    EXPECT_EQ(m->num_rows(), A->num_cols());
-    EXPECT_EQ(m->num_cols(), A->num_cols());
+    BlockSparseJacobiPreconditioner pre(preconditioner_options, *jacobian);
+    pre.Update(*jacobian, diagonal.data());
 
-    const CompressedRowBlockStructure* bs = A->block_structure();
+    // The const_cast is needed to be able to call GetCell.
+    auto* m = const_cast<BlockRandomAccessDiagonalMatrix*>(&pre.matrix());
+    EXPECT_EQ(m->num_rows(), jacobian->num_cols());
+    EXPECT_EQ(m->num_cols(), jacobian->num_cols());
+
+    const CompressedRowBlockStructure* bs = jacobian->block_structure();
     for (int i = 0; i < bs->cols.size(); ++i) {
       const int block_size = bs->cols[i].size;
       int r, c, row_stride, col_stride;
       CellInfo* cell_info = m->GetCell(i, i, &r, &c, &row_stride, &col_stride);
-      MatrixRef m(cell_info->values, row_stride, col_stride);
-      Matrix actual_block_inverse = m.block(r, c, block_size, block_size);
-      Matrix expected_block = dense_ata.block(
+      Matrix actual_block_inverse =
+          MatrixRef(cell_info->values, row_stride, col_stride)
+              .block(r, c, block_size, block_size);
+      Matrix expected_block = hessian.block(
           bs->cols[i].position, bs->cols[i].position, block_size, block_size);
       const double residual = (actual_block_inverse * expected_block -
                                Matrix::Identity(block_size, block_size))
                                   .norm();
       EXPECT_NEAR(residual, 0.0, 1e-12) << "Block: " << i;
     }
+    options.num_col_blocks++;
+    options.num_row_blocks++;
   }
+}
 
-  std::unique_ptr<BlockSparseMatrix> A;
-  std::unique_ptr<double[]> D;
-  Matrix dense_ata;
-};
+TEST(CompressedRowSparseJacobiPreconditioner, _) {
+  constexpr int kNumtrials = 10;
+  CompressedRowSparseMatrix::RandomMatrixOptions options;
+  options.num_col_blocks = 3;
+  options.min_col_block_size = 1;
+  options.max_col_block_size = 3;
 
-TEST_F(BlockJacobiPreconditionerTest, SmallProblem) { VerifyDiagonalBlocks(2); }
+  options.num_row_blocks = 5;
+  options.min_row_block_size = 1;
+  options.max_row_block_size = 4;
+  options.block_density = 0.25;
+  std::mt19937 prng;
 
-TEST_F(BlockJacobiPreconditionerTest, LargeProblem) { VerifyDiagonalBlocks(3); }
+  Preconditioner::Options preconditioner_options;
+  ContextImpl context;
+  preconditioner_options.context = &context;
 
-}  // namespace internal
-}  // namespace ceres
+  for (int trial = 0; trial < kNumtrials; ++trial) {
+    auto jacobian =
+        CompressedRowSparseMatrix::CreateRandomMatrix(options, prng);
+    Vector diagonal = Vector::Ones(jacobian->num_cols());
+
+    Matrix dense_jacobian;
+    jacobian->ToDenseMatrix(&dense_jacobian);
+    Matrix hessian = dense_jacobian.transpose() * dense_jacobian;
+    hessian.diagonal() += diagonal.array().square().matrix();
+
+    BlockCRSJacobiPreconditioner pre(preconditioner_options, *jacobian);
+    pre.Update(*jacobian, diagonal.data());
+    auto& m = pre.matrix();
+
+    EXPECT_EQ(m.num_rows(), jacobian->num_cols());
+    EXPECT_EQ(m.num_cols(), jacobian->num_cols());
+
+    const auto& col_blocks = jacobian->col_blocks();
+    for (int i = 0, col = 0; i < col_blocks.size(); ++i) {
+      const int block_size = col_blocks[i].size;
+      int idx = m.rows()[col];
+      for (int j = 0; j < block_size; ++j) {
+        EXPECT_EQ(m.rows()[col + j + 1] - m.rows()[col + j], block_size);
+        for (int k = 0; k < block_size; ++k, ++idx) {
+          EXPECT_EQ(m.cols()[idx], col + k);
+        }
+      }
+
+      ConstMatrixRef actual_block_inverse(
+          m.values() + m.rows()[col], block_size, block_size);
+      Matrix expected_block = hessian.block(col, col, block_size, block_size);
+      const double residual = (actual_block_inverse * expected_block -
+                               Matrix::Identity(block_size, block_size))
+                                  .norm();
+      EXPECT_NEAR(residual, 0.0, 1e-12) << "Block: " << i;
+      col += block_size;
+    }
+    options.num_col_blocks++;
+    options.num_row_blocks++;
+  }
+}
+
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/block_jacobian_writer.cc b/third_party/ceres/internal/ceres/block_jacobian_writer.cc
index 17c157b..5a769cb 100644
--- a/third_party/ceres/internal/ceres/block_jacobian_writer.cc
+++ b/third_party/ceres/internal/ceres/block_jacobian_writer.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -30,18 +30,19 @@
 
 #include "ceres/block_jacobian_writer.h"
 
+#include <algorithm>
+#include <memory>
+#include <vector>
+
 #include "ceres/block_evaluate_preparer.h"
 #include "ceres/block_sparse_matrix.h"
 #include "ceres/internal/eigen.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 #include "ceres/parameter_block.h"
 #include "ceres/program.h"
 #include "ceres/residual_block.h"
 
-namespace ceres {
-namespace internal {
-
-using std::vector;
+namespace ceres::internal {
 
 namespace {
 
@@ -53,21 +54,28 @@
 // the first num_eliminate_blocks parameter blocks as indicated by the parameter
 // block ordering. The remaining parameter blocks are the F blocks.
 //
+// In order to simplify handling block-sparse to CRS conversion, cells within
+// the row-block of non-partitioned matrix are stored in memory sequentially in
+// the order of increasing column-block id. In case of partitioned matrices,
+// cells corresponding to F sub-matrix are stored sequentially in the order of
+// increasing column-block id (with cells corresponding to E sub-matrix stored
+// separately).
+//
 // TODO(keir): Consider if we should use a boolean for each parameter block
 // instead of num_eliminate_blocks.
-void BuildJacobianLayout(const Program& program,
+bool BuildJacobianLayout(const Program& program,
                          int num_eliminate_blocks,
-                         vector<int*>* jacobian_layout,
-                         vector<int>* jacobian_layout_storage) {
-  const vector<ResidualBlock*>& residual_blocks = program.residual_blocks();
+                         std::vector<int*>* jacobian_layout,
+                         std::vector<int>* jacobian_layout_storage) {
+  const std::vector<ResidualBlock*>& residual_blocks =
+      program.residual_blocks();
 
   // Iterate over all the active residual blocks and determine how many E blocks
   // are there. This will determine where the F blocks start in the jacobian
   // matrix. Also compute the number of jacobian blocks.
-  int f_block_pos = 0;
-  int num_jacobian_blocks = 0;
-  for (int i = 0; i < residual_blocks.size(); ++i) {
-    ResidualBlock* residual_block = residual_blocks[i];
+  unsigned int f_block_pos = 0;
+  unsigned int num_jacobian_blocks = 0;
+  for (auto* residual_block : residual_blocks) {
     const int num_residuals = residual_block->NumResiduals();
     const int num_parameter_blocks = residual_block->NumParameterBlocks();
 
@@ -78,10 +86,15 @@
         // Only count blocks for active parameters.
         num_jacobian_blocks++;
         if (parameter_block->index() < num_eliminate_blocks) {
-          f_block_pos += num_residuals * parameter_block->LocalSize();
+          f_block_pos += num_residuals * parameter_block->TangentSize();
         }
       }
     }
+    if (num_jacobian_blocks > std::numeric_limits<int>::max()) {
+      LOG(ERROR) << "Overlow error. Too many blocks in the jacobian matrix : "
+                 << num_jacobian_blocks;
+      return false;
+    }
   }
 
   // We now know that the E blocks are laid out starting at zero, and the F
@@ -93,65 +106,103 @@
   jacobian_layout_storage->resize(num_jacobian_blocks);
 
   int e_block_pos = 0;
-  int* jacobian_pos = &(*jacobian_layout_storage)[0];
+  int* jacobian_pos = jacobian_layout_storage->data();
+  std::vector<std::pair<int, int>> active_parameter_blocks;
   for (int i = 0; i < residual_blocks.size(); ++i) {
     const ResidualBlock* residual_block = residual_blocks[i];
     const int num_residuals = residual_block->NumResiduals();
     const int num_parameter_blocks = residual_block->NumParameterBlocks();
 
     (*jacobian_layout)[i] = jacobian_pos;
+    // Cells from F sub-matrix are to be stored sequentially with increasing
+    // column block id. For each non-constant parameter block, a pair of indices
+    // (index in the list of active parameter blocks and index in the list of
+    // all parameter blocks) is computed, and index pairs are sorted by the
+    // index of corresponding column block id.
+    active_parameter_blocks.clear();
+    active_parameter_blocks.reserve(num_parameter_blocks);
     for (int j = 0; j < num_parameter_blocks; ++j) {
       ParameterBlock* parameter_block = residual_block->parameter_blocks()[j];
-      const int parameter_block_index = parameter_block->index();
       if (parameter_block->IsConstant()) {
         continue;
       }
+      const int k = active_parameter_blocks.size();
+      active_parameter_blocks.emplace_back(k, j);
+    }
+    std::sort(active_parameter_blocks.begin(),
+              active_parameter_blocks.end(),
+              [&residual_block](const std::pair<int, int>& a,
+                                const std::pair<int, int>& b) {
+                return residual_block->parameter_blocks()[a.second]->index() <
+                       residual_block->parameter_blocks()[b.second]->index();
+              });
+    // Cell positions for each active parameter block are filled in the order of
+    // active parameter block indices sorted by columnd block index. This
+    // guarantees that cells are laid out sequentially with increasing column
+    // block indices.
+    for (const auto& indices : active_parameter_blocks) {
+      const auto [k, j] = indices;
+      ParameterBlock* parameter_block = residual_block->parameter_blocks()[j];
+      const int parameter_block_index = parameter_block->index();
       const int jacobian_block_size =
-          num_residuals * parameter_block->LocalSize();
+          num_residuals * parameter_block->TangentSize();
       if (parameter_block_index < num_eliminate_blocks) {
-        *jacobian_pos = e_block_pos;
+        jacobian_pos[k] = e_block_pos;
         e_block_pos += jacobian_block_size;
       } else {
-        *jacobian_pos = f_block_pos;
+        jacobian_pos[k] = static_cast<int>(f_block_pos);
         f_block_pos += jacobian_block_size;
+        if (f_block_pos > std::numeric_limits<int>::max()) {
+          LOG(ERROR)
+              << "Overlow error. Too many entries in the Jacobian matrix.";
+          return false;
+        }
       }
-      jacobian_pos++;
     }
+    jacobian_pos += active_parameter_blocks.size();
   }
+  return true;
 }
 
 }  // namespace
 
 BlockJacobianWriter::BlockJacobianWriter(const Evaluator::Options& options,
                                          Program* program)
-    : program_(program) {
+    : options_(options), program_(program) {
   CHECK_GE(options.num_eliminate_blocks, 0)
       << "num_eliminate_blocks must be greater than 0.";
 
-  BuildJacobianLayout(*program,
-                      options.num_eliminate_blocks,
-                      &jacobian_layout_,
-                      &jacobian_layout_storage_);
+  jacobian_layout_is_valid_ = BuildJacobianLayout(*program,
+                                                  options.num_eliminate_blocks,
+                                                  &jacobian_layout_,
+                                                  &jacobian_layout_storage_);
 }
 
-// Create evaluate prepareres that point directly into the final jacobian. This
+// Create evaluate preparers that point directly into the final jacobian. This
 // makes the final Write() a nop.
-BlockEvaluatePreparer* BlockJacobianWriter::CreateEvaluatePreparers(
-    int num_threads) {
-  int max_derivatives_per_residual_block =
+std::unique_ptr<BlockEvaluatePreparer[]>
+BlockJacobianWriter::CreateEvaluatePreparers(unsigned num_threads) {
+  const int max_derivatives_per_residual_block =
       program_->MaxDerivativesPerResidualBlock();
 
-  BlockEvaluatePreparer* preparers = new BlockEvaluatePreparer[num_threads];
-  for (int i = 0; i < num_threads; i++) {
-    preparers[i].Init(&jacobian_layout_[0], max_derivatives_per_residual_block);
+  auto preparers = std::make_unique<BlockEvaluatePreparer[]>(num_threads);
+  for (unsigned i = 0; i < num_threads; i++) {
+    preparers[i].Init(jacobian_layout_.data(),
+                      max_derivatives_per_residual_block);
   }
   return preparers;
 }
 
-SparseMatrix* BlockJacobianWriter::CreateJacobian() const {
-  CompressedRowBlockStructure* bs = new CompressedRowBlockStructure;
+std::unique_ptr<SparseMatrix> BlockJacobianWriter::CreateJacobian() const {
+  if (!jacobian_layout_is_valid_) {
+    LOG(ERROR) << "Unable to create Jacobian matrix. Too many entries in the "
+                  "Jacobian matrix.";
+    return nullptr;
+  }
 
-  const vector<ParameterBlock*>& parameter_blocks =
+  auto* bs = new CompressedRowBlockStructure;
+
+  const std::vector<ParameterBlock*>& parameter_blocks =
       program_->parameter_blocks();
 
   // Construct the column blocks.
@@ -159,13 +210,14 @@
   for (int i = 0, cursor = 0; i < parameter_blocks.size(); ++i) {
     CHECK_NE(parameter_blocks[i]->index(), -1);
     CHECK(!parameter_blocks[i]->IsConstant());
-    bs->cols[i].size = parameter_blocks[i]->LocalSize();
+    bs->cols[i].size = parameter_blocks[i]->TangentSize();
     bs->cols[i].position = cursor;
     cursor += bs->cols[i].size;
   }
 
   // Construct the cells in each row.
-  const vector<ResidualBlock*>& residual_blocks = program_->residual_blocks();
+  const std::vector<ResidualBlock*>& residual_blocks =
+      program_->residual_blocks();
   int row_block_position = 0;
   bs->rows.resize(residual_blocks.size());
   for (int i = 0; i < residual_blocks.size(); ++i) {
@@ -201,13 +253,11 @@
       }
     }
 
-    sort(row->cells.begin(), row->cells.end(), CellLessThan);
+    std::sort(row->cells.begin(), row->cells.end(), CellLessThan);
   }
 
-  BlockSparseMatrix* jacobian = new BlockSparseMatrix(bs);
-  CHECK(jacobian != nullptr);
-  return jacobian;
+  return std::make_unique<BlockSparseMatrix>(
+      bs, options_.sparse_linear_algebra_library_type == CUDA_SPARSE);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/block_jacobian_writer.h b/third_party/ceres/internal/ceres/block_jacobian_writer.h
index 8054d7b..a6d02e3 100644
--- a/third_party/ceres/internal/ceres/block_jacobian_writer.h
+++ b/third_party/ceres/internal/ceres/block_jacobian_writer.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -38,30 +38,42 @@
 #ifndef CERES_INTERNAL_BLOCK_JACOBIAN_WRITER_H_
 #define CERES_INTERNAL_BLOCK_JACOBIAN_WRITER_H_
 
+#include <memory>
 #include <vector>
 
 #include "ceres/evaluator.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 class BlockEvaluatePreparer;
 class Program;
 class SparseMatrix;
 
-// TODO(sameeragarwal): This class needs documemtation.
-class BlockJacobianWriter {
+// TODO(sameeragarwal): This class needs documentation.
+class CERES_NO_EXPORT BlockJacobianWriter {
  public:
+  // Pre-computes positions of cells in block-sparse jacobian.
+  // Two possible memory layouts are implemented:
+  //  - Non-partitioned case
+  //  - Partitioned case (for Schur type linear solver)
+  //
+  // In non-partitioned case, cells are stored sequentially in the
+  // lexicographic order of (row block id, column block id).
+  //
+  // In the case of partitoned matrix, cells of each sub-matrix (E and F) are
+  // stored sequentially in the lexicographic order of (row block id, column
+  // block id) and cells from E sub-matrix precede cells from F sub-matrix.
   BlockJacobianWriter(const Evaluator::Options& options, Program* program);
 
   // JacobianWriter interface.
 
-  // Create evaluate prepareres that point directly into the final jacobian.
+  // Create evaluate preparers that point directly into the final jacobian.
   // This makes the final Write() a nop.
-  BlockEvaluatePreparer* CreateEvaluatePreparers(int num_threads);
+  std::unique_ptr<BlockEvaluatePreparer[]> CreateEvaluatePreparers(
+      unsigned num_threads);
 
-  SparseMatrix* CreateJacobian() const;
+  std::unique_ptr<SparseMatrix> CreateJacobian() const;
 
   void Write(int /* residual_id */,
              int /* residual_offset */,
@@ -73,12 +85,13 @@
   }
 
  private:
+  Evaluator::Options options_;
   Program* program_;
 
   // Stores the position of each residual / parameter jacobian.
   //
   // The block sparse matrix that this writer writes to is stored as a set of
-  // contiguos dense blocks, one after each other; see BlockSparseMatrix. The
+  // contiguous dense blocks, one after each other; see BlockSparseMatrix. The
   // "double* values_" member of the block sparse matrix contains all of these
   // blocks. Given a pointer to the first element of a block and the size of
   // that block, it's possible to write to it.
@@ -120,9 +133,14 @@
 
   // The pointers in jacobian_layout_ point directly into this vector.
   std::vector<int> jacobian_layout_storage_;
+
+  // The constructor computes the layout of the Jacobian, and this bool keeps
+  // track of whether the computation of the layout completed successfully or
+  // not, if it is false, then jacobian_layout and jacobian_layout_storage are
+  // both in an invalid state.
+  bool jacobian_layout_is_valid_ = false;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_INTERNAL_BLOCK_JACOBIAN_WRITER_H_
diff --git a/third_party/ceres/internal/ceres/block_random_access_dense_matrix.cc b/third_party/ceres/internal/ceres/block_random_access_dense_matrix.cc
index 386f81e..b8be51b 100644
--- a/third_party/ceres/internal/ceres/block_random_access_dense_matrix.cc
+++ b/third_party/ceres/internal/ceres/block_random_access_dense_matrix.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -30,27 +30,22 @@
 
 #include "ceres/block_random_access_dense_matrix.h"
 
+#include <utility>
 #include <vector>
 
 #include "ceres/internal/eigen.h"
+#include "ceres/parallel_vector_ops.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 BlockRandomAccessDenseMatrix::BlockRandomAccessDenseMatrix(
-    const std::vector<int>& blocks) {
-  const int num_blocks = blocks.size();
-  block_layout_.resize(num_blocks, 0);
-  num_rows_ = 0;
-  for (int i = 0; i < num_blocks; ++i) {
-    block_layout_[i] = num_rows_;
-    num_rows_ += blocks[i];
-  }
-
-  values_.reset(new double[num_rows_ * num_rows_]);
-
-  cell_infos_.reset(new CellInfo[num_blocks * num_blocks]);
+    std::vector<Block> blocks, ContextImpl* context, int num_threads)
+    : blocks_(std::move(blocks)), context_(context), num_threads_(num_threads) {
+  const int num_blocks = blocks_.size();
+  num_rows_ = NumScalarEntries(blocks_);
+  values_ = std::make_unique<double[]>(num_rows_ * num_rows_);
+  cell_infos_ = std::make_unique<CellInfo[]>(num_blocks * num_blocks);
   for (int i = 0; i < num_blocks * num_blocks; ++i) {
     cell_infos_[i].values = values_.get();
   }
@@ -58,30 +53,23 @@
   SetZero();
 }
 
-// Assume that the user does not hold any locks on any cell blocks
-// when they are calling SetZero.
-BlockRandomAccessDenseMatrix::~BlockRandomAccessDenseMatrix() {}
-
 CellInfo* BlockRandomAccessDenseMatrix::GetCell(const int row_block_id,
                                                 const int col_block_id,
                                                 int* row,
                                                 int* col,
                                                 int* row_stride,
                                                 int* col_stride) {
-  *row = block_layout_[row_block_id];
-  *col = block_layout_[col_block_id];
+  *row = blocks_[row_block_id].position;
+  *col = blocks_[col_block_id].position;
   *row_stride = num_rows_;
   *col_stride = num_rows_;
-  return &cell_infos_[row_block_id * block_layout_.size() + col_block_id];
+  return &cell_infos_[row_block_id * blocks_.size() + col_block_id];
 }
 
 // Assume that the user does not hold any locks on any cell blocks
 // when they are calling SetZero.
 void BlockRandomAccessDenseMatrix::SetZero() {
-  if (num_rows_) {
-    VectorRef(values_.get(), num_rows_ * num_rows_).setZero();
-  }
+  ParallelSetZero(context_, num_threads_, values_.get(), num_rows_ * num_rows_);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/block_random_access_dense_matrix.h b/third_party/ceres/internal/ceres/block_random_access_dense_matrix.h
index 9e55524..9468249 100644
--- a/third_party/ceres/internal/ceres/block_random_access_dense_matrix.h
+++ b/third_party/ceres/internal/ceres/block_random_access_dense_matrix.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,10 +35,12 @@
 #include <vector>
 
 #include "ceres/block_random_access_matrix.h"
-#include "ceres/internal/port.h"
+#include "ceres/block_structure.h"
+#include "ceres/context_impl.h"
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // A square block random accessible matrix with the same row and
 // column block structure. All cells are stored in the same single
@@ -46,22 +48,20 @@
 // num_rows x num_cols.
 //
 // This class is NOT thread safe. Since all n^2 cells are stored,
-// GetCell never returns NULL for any (row_block_id, col_block_id)
+// GetCell never returns nullptr for any (row_block_id, col_block_id)
 // pair.
 //
 // ReturnCell is a nop.
-class CERES_EXPORT_INTERNAL BlockRandomAccessDenseMatrix
+class CERES_NO_EXPORT BlockRandomAccessDenseMatrix
     : public BlockRandomAccessMatrix {
  public:
   // blocks is a vector of block sizes. The resulting matrix has
   // blocks.size() * blocks.size() cells.
-  explicit BlockRandomAccessDenseMatrix(const std::vector<int>& blocks);
-  BlockRandomAccessDenseMatrix(const BlockRandomAccessDenseMatrix&) = delete;
-  void operator=(const BlockRandomAccessDenseMatrix&) = delete;
+  explicit BlockRandomAccessDenseMatrix(std::vector<Block> blocks,
+                                        ContextImpl* context,
+                                        int num_threads);
 
-  // The destructor is not thread safe. It assumes that no one is
-  // modifying any cells when the matrix is being destroyed.
-  virtual ~BlockRandomAccessDenseMatrix();
+  ~BlockRandomAccessDenseMatrix() override = default;
 
   // BlockRandomAccessMatrix interface.
   CellInfo* GetCell(int row_block_id,
@@ -71,8 +71,6 @@
                     int* row_stride,
                     int* col_stride) final;
 
-  // This is not a thread safe method, it assumes that no cell is
-  // locked.
   void SetZero() final;
 
   // Since the matrix is square with the same row and column block
@@ -85,13 +83,16 @@
   double* mutable_values() { return values_.get(); }
 
  private:
-  int num_rows_;
-  std::vector<int> block_layout_;
+  std::vector<Block> blocks_;
+  ContextImpl* context_ = nullptr;
+  int num_threads_ = -1;
+  int num_rows_ = -1;
   std::unique_ptr<double[]> values_;
   std::unique_ptr<CellInfo[]> cell_infos_;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_BLOCK_RANDOM_ACCESS_DENSE_MATRIX_H_
diff --git a/third_party/ceres/internal/ceres/block_random_access_dense_matrix_test.cc b/third_party/ceres/internal/ceres/block_random_access_dense_matrix_test.cc
index 0736d56..ba9c75d 100644
--- a/third_party/ceres/internal/ceres/block_random_access_dense_matrix_test.cc
+++ b/third_party/ceres/internal/ceres/block_random_access_dense_matrix_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,48 +35,51 @@
 #include "ceres/internal/eigen.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST(BlockRandomAccessDenseMatrix, GetCell) {
-  std::vector<int> blocks;
-  blocks.push_back(3);
-  blocks.push_back(4);
-  blocks.push_back(5);
-  const int num_rows = 3 + 4 + 5;
-  BlockRandomAccessDenseMatrix m(blocks);
+  ContextImpl context;
+  constexpr int num_threads = 1;
+
+  std::vector<Block> blocks;
+  blocks.emplace_back(3, 0);
+  blocks.emplace_back(4, 3);
+  blocks.emplace_back(5, 7);
+  constexpr int num_rows = 3 + 4 + 5;
+  BlockRandomAccessDenseMatrix m(blocks, &context, num_threads);
   EXPECT_EQ(m.num_rows(), num_rows);
   EXPECT_EQ(m.num_cols(), num_rows);
 
-  int row_idx = 0;
   for (int i = 0; i < blocks.size(); ++i) {
-    int col_idx = 0;
+    const int row_idx = blocks[i].position;
     for (int j = 0; j < blocks.size(); ++j) {
+      const int col_idx = blocks[j].position;
       int row;
       int col;
       int row_stride;
       int col_stride;
       CellInfo* cell = m.GetCell(i, j, &row, &col, &row_stride, &col_stride);
 
-      EXPECT_TRUE(cell != NULL);
+      EXPECT_TRUE(cell != nullptr);
       EXPECT_EQ(row, row_idx);
       EXPECT_EQ(col, col_idx);
       EXPECT_EQ(row_stride, 3 + 4 + 5);
       EXPECT_EQ(col_stride, 3 + 4 + 5);
-      col_idx += blocks[j];
     }
-    row_idx += blocks[i];
   }
 }
 
 TEST(BlockRandomAccessDenseMatrix, WriteCell) {
-  std::vector<int> blocks;
-  blocks.push_back(3);
-  blocks.push_back(4);
-  blocks.push_back(5);
-  const int num_rows = 3 + 4 + 5;
+  ContextImpl context;
+  constexpr int num_threads = 1;
 
-  BlockRandomAccessDenseMatrix m(blocks);
+  std::vector<Block> blocks;
+  blocks.emplace_back(3, 0);
+  blocks.emplace_back(4, 3);
+  blocks.emplace_back(5, 7);
+  constexpr int num_rows = 3 + 4 + 5;
+
+  BlockRandomAccessDenseMatrix m(blocks, &context, num_threads);
 
   // Fill the cell (i,j) with (i + 1) * (j + 1)
   for (int i = 0; i < blocks.size(); ++i) {
@@ -87,29 +90,26 @@
       int col_stride;
       CellInfo* cell = m.GetCell(i, j, &row, &col, &row_stride, &col_stride);
       MatrixRef(cell->values, row_stride, col_stride)
-          .block(row, col, blocks[i], blocks[j]) =
-          (i + 1) * (j + 1) * Matrix::Ones(blocks[i], blocks[j]);
+          .block(row, col, blocks[i].size, blocks[j].size) =
+          (i + 1) * (j + 1) * Matrix::Ones(blocks[i].size, blocks[j].size);
     }
   }
 
   // Check the values in the array are correct by going over the
   // entries of each block manually.
-  int row_idx = 0;
   for (int i = 0; i < blocks.size(); ++i) {
-    int col_idx = 0;
+    const int row_idx = blocks[i].position;
     for (int j = 0; j < blocks.size(); ++j) {
+      const int col_idx = blocks[j].position;
       // Check the values of this block.
-      for (int r = 0; r < blocks[i]; ++r) {
-        for (int c = 0; c < blocks[j]; ++c) {
+      for (int r = 0; r < blocks[i].size; ++r) {
+        for (int c = 0; c < blocks[j].size; ++c) {
           int pos = row_idx * num_rows + col_idx;
           EXPECT_EQ(m.values()[pos], (i + 1) * (j + 1));
         }
       }
-      col_idx += blocks[j];
     }
-    row_idx += blocks[i];
   }
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/block_random_access_diagonal_matrix.cc b/third_party/ceres/internal/ceres/block_random_access_diagonal_matrix.cc
index 08f6d7f..643dbf1 100644
--- a/third_party/ceres/internal/ceres/block_random_access_diagonal_matrix.cc
+++ b/third_party/ceres/internal/ceres/block_random_access_diagonal_matrix.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -31,65 +31,32 @@
 #include "ceres/block_random_access_diagonal_matrix.h"
 
 #include <algorithm>
+#include <memory>
 #include <set>
 #include <utility>
 #include <vector>
 
 #include "Eigen/Dense"
-#include "ceres/internal/port.h"
+#include "ceres/compressed_row_sparse_matrix.h"
+#include "ceres/internal/export.h"
+#include "ceres/parallel_for.h"
+#include "ceres/parallel_vector_ops.h"
 #include "ceres/stl_util.h"
-#include "ceres/triplet_sparse_matrix.h"
 #include "ceres/types.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
-
-using std::vector;
-
-// TODO(sameeragarwal): Drop the dependence on TripletSparseMatrix.
+namespace ceres::internal {
 
 BlockRandomAccessDiagonalMatrix::BlockRandomAccessDiagonalMatrix(
-    const vector<int>& blocks)
-    : blocks_(blocks) {
-  // Build the row/column layout vector and count the number of scalar
-  // rows/columns.
-  int num_cols = 0;
-  int num_nonzeros = 0;
-  vector<int> block_positions;
-  for (int i = 0; i < blocks_.size(); ++i) {
-    block_positions.push_back(num_cols);
-    num_cols += blocks_[i];
-    num_nonzeros += blocks_[i] * blocks_[i];
+    const std::vector<Block>& blocks, ContextImpl* context, int num_threads)
+    : context_(context), num_threads_(num_threads) {
+  m_ = CompressedRowSparseMatrix::CreateBlockDiagonalMatrix(nullptr, blocks);
+  double* values = m_->mutable_values();
+  layout_ = std::make_unique<CellInfo[]>(blocks.size());
+  for (int i = 0; i < blocks.size(); ++i) {
+    layout_[i].values = values;
+    values += blocks[i].size * blocks[i].size;
   }
-
-  VLOG(1) << "Matrix Size [" << num_cols << "," << num_cols << "] "
-          << num_nonzeros;
-
-  tsm_.reset(new TripletSparseMatrix(num_cols, num_cols, num_nonzeros));
-  tsm_->set_num_nonzeros(num_nonzeros);
-  int* rows = tsm_->mutable_rows();
-  int* cols = tsm_->mutable_cols();
-  double* values = tsm_->mutable_values();
-
-  int pos = 0;
-  for (int i = 0; i < blocks_.size(); ++i) {
-    const int block_size = blocks_[i];
-    layout_.push_back(new CellInfo(values + pos));
-    const int block_begin = block_positions[i];
-    for (int r = 0; r < block_size; ++r) {
-      for (int c = 0; c < block_size; ++c, ++pos) {
-        rows[pos] = block_begin + r;
-        cols[pos] = block_begin + c;
-      }
-    }
-  }
-}
-
-// Assume that the user does not hold any locks on any cell blocks
-// when they are calling SetZero.
-BlockRandomAccessDiagonalMatrix::~BlockRandomAccessDiagonalMatrix() {
-  STLDeleteContainerPointers(layout_.begin(), layout_.end());
 }
 
 CellInfo* BlockRandomAccessDiagonalMatrix::GetCell(int row_block_id,
@@ -99,51 +66,53 @@
                                                    int* row_stride,
                                                    int* col_stride) {
   if (row_block_id != col_block_id) {
-    return NULL;
+    return nullptr;
   }
-  const int stride = blocks_[row_block_id];
+
+  auto& blocks = m_->row_blocks();
+  const int stride = blocks[row_block_id].size;
 
   // Each cell is stored contiguously as its own little dense matrix.
   *row = 0;
   *col = 0;
   *row_stride = stride;
   *col_stride = stride;
-  return layout_[row_block_id];
+  return &layout_[row_block_id];
 }
 
 // Assume that the user does not hold any locks on any cell blocks
 // when they are calling SetZero.
 void BlockRandomAccessDiagonalMatrix::SetZero() {
-  if (tsm_->num_nonzeros()) {
-    VectorRef(tsm_->mutable_values(), tsm_->num_nonzeros()).setZero();
-  }
+  ParallelSetZero(
+      context_, num_threads_, m_->mutable_values(), m_->num_nonzeros());
 }
 
 void BlockRandomAccessDiagonalMatrix::Invert() {
-  double* values = tsm_->mutable_values();
-  for (int i = 0; i < blocks_.size(); ++i) {
-    const int block_size = blocks_[i];
-    MatrixRef block(values, block_size, block_size);
-    block = block.selfadjointView<Eigen::Upper>().llt().solve(
-        Matrix::Identity(block_size, block_size));
-    values += block_size * block_size;
-  }
+  auto& blocks = m_->row_blocks();
+  const int num_blocks = blocks.size();
+  ParallelFor(context_, 0, num_blocks, num_threads_, [this, blocks](int i) {
+    auto& cell_info = layout_[i];
+    auto& block = blocks[i];
+    MatrixRef b(cell_info.values, block.size, block.size);
+    b = b.selfadjointView<Eigen::Upper>().llt().solve(
+        Matrix::Identity(block.size, block.size));
+  });
 }
 
-void BlockRandomAccessDiagonalMatrix::RightMultiply(const double* x,
-                                                    double* y) const {
+void BlockRandomAccessDiagonalMatrix::RightMultiplyAndAccumulate(
+    const double* x, double* y) const {
   CHECK(x != nullptr);
   CHECK(y != nullptr);
-  const double* values = tsm_->values();
-  for (int i = 0; i < blocks_.size(); ++i) {
-    const int block_size = blocks_[i];
-    ConstMatrixRef block(values, block_size, block_size);
-    VectorRef(y, block_size).noalias() += block * ConstVectorRef(x, block_size);
-    x += block_size;
-    y += block_size;
-    values += block_size * block_size;
-  }
+  auto& blocks = m_->row_blocks();
+  const int num_blocks = blocks.size();
+  ParallelFor(
+      context_, 0, num_blocks, num_threads_, [this, blocks, x, y](int i) {
+        auto& cell_info = layout_[i];
+        auto& block = blocks[i];
+        ConstMatrixRef b(cell_info.values, block.size, block.size);
+        VectorRef(y + block.position, block.size).noalias() +=
+            b * ConstVectorRef(x + block.position, block.size);
+      });
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/block_random_access_diagonal_matrix.h b/third_party/ceres/internal/ceres/block_random_access_diagonal_matrix.h
index 3fe7c1e..9671f3e 100644
--- a/third_party/ceres/internal/ceres/block_random_access_diagonal_matrix.h
+++ b/third_party/ceres/internal/ceres/block_random_access_diagonal_matrix.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -32,32 +32,29 @@
 #define CERES_INTERNAL_BLOCK_RANDOM_ACCESS_DIAGONAL_MATRIX_H_
 
 #include <memory>
-#include <set>
 #include <utility>
-#include <vector>
 
 #include "ceres/block_random_access_matrix.h"
-#include "ceres/internal/port.h"
-#include "ceres/triplet_sparse_matrix.h"
+#include "ceres/block_structure.h"
+#include "ceres/compressed_row_sparse_matrix.h"
+#include "ceres/context_impl.h"
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 #include "ceres/types.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
-// A thread safe block diagonal matrix implementation of
-// BlockRandomAccessMatrix.
-class CERES_EXPORT_INTERNAL BlockRandomAccessDiagonalMatrix
+// A BlockRandomAccessMatrix which only stores the block diagonal.
+// BlockRandomAccessSparseMatrix can also be used to do this, but this class is
+// more efficient in time and in space.
+class CERES_NO_EXPORT BlockRandomAccessDiagonalMatrix
     : public BlockRandomAccessMatrix {
  public:
   // blocks is an array of block sizes.
-  explicit BlockRandomAccessDiagonalMatrix(const std::vector<int>& blocks);
-  BlockRandomAccessDiagonalMatrix(const BlockRandomAccessDiagonalMatrix&) =
-      delete;
-  void operator=(const BlockRandomAccessDiagonalMatrix&) = delete;
-
-  // The destructor is not thread safe. It assumes that no one is
-  // modifying any cells when the matrix is being destroyed.
-  virtual ~BlockRandomAccessDiagonalMatrix();
+  BlockRandomAccessDiagonalMatrix(const std::vector<Block>& blocks,
+                                  ContextImpl* context,
+                                  int num_threads);
+  ~BlockRandomAccessDiagonalMatrix() override = default;
 
   // BlockRandomAccessMatrix Interface.
   CellInfo* GetCell(int row_block_id,
@@ -67,35 +64,31 @@
                     int* row_stride,
                     int* col_stride) final;
 
-  // This is not a thread safe method, it assumes that no cell is
-  // locked.
+  // m = 0
   void SetZero() final;
 
-  // Invert the matrix assuming that each block is positive definite.
+  // m = m^{-1}
   void Invert();
 
-  // y += S * x
-  void RightMultiply(const double* x, double* y) const;
+  // y += m * x
+  void RightMultiplyAndAccumulate(const double* x, double* y) const;
 
   // Since the matrix is square, num_rows() == num_cols().
-  int num_rows() const final { return tsm_->num_rows(); }
-  int num_cols() const final { return tsm_->num_cols(); }
+  int num_rows() const final { return m_->num_rows(); }
+  int num_cols() const final { return m_->num_cols(); }
 
-  const TripletSparseMatrix* matrix() const { return tsm_.get(); }
-  TripletSparseMatrix* mutable_matrix() { return tsm_.get(); }
+  const CompressedRowSparseMatrix* matrix() const { return m_.get(); }
+  CompressedRowSparseMatrix* mutable_matrix() { return m_.get(); }
 
  private:
-  // row/column block sizes.
-  const std::vector<int> blocks_;
-  std::vector<CellInfo*> layout_;
-
-  // The underlying matrix object which actually stores the cells.
-  std::unique_ptr<TripletSparseMatrix> tsm_;
-
-  friend class BlockRandomAccessDiagonalMatrixTest;
+  ContextImpl* context_ = nullptr;
+  const int num_threads_ = 1;
+  std::unique_ptr<CompressedRowSparseMatrix> m_;
+  std::unique_ptr<CellInfo[]> layout_;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_BLOCK_RANDOM_ACCESS_DIAGONAL_MATRIX_H_
diff --git a/third_party/ceres/internal/ceres/block_random_access_diagonal_matrix_test.cc b/third_party/ceres/internal/ceres/block_random_access_diagonal_matrix_test.cc
index e384dac..f665bd8 100644
--- a/third_party/ceres/internal/ceres/block_random_access_diagonal_matrix_test.cc
+++ b/third_party/ceres/internal/ceres/block_random_access_diagonal_matrix_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -39,20 +39,21 @@
 #include "glog/logging.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 class BlockRandomAccessDiagonalMatrixTest : public ::testing::Test {
  public:
-  void SetUp() {
-    std::vector<int> blocks;
-    blocks.push_back(3);
-    blocks.push_back(4);
-    blocks.push_back(5);
+  void SetUp() override {
+    std::vector<Block> blocks;
+    blocks.emplace_back(3, 0);
+    blocks.emplace_back(4, 3);
+    blocks.emplace_back(5, 7);
+
     const int num_rows = 3 + 4 + 5;
     num_nonzeros_ = 3 * 3 + 4 * 4 + 5 * 5;
 
-    m_.reset(new BlockRandomAccessDiagonalMatrix(blocks));
+    m_ =
+        std::make_unique<BlockRandomAccessDiagonalMatrix>(blocks, &context_, 1);
 
     EXPECT_EQ(m_->num_rows(), num_rows);
     EXPECT_EQ(m_->num_cols(), num_rows);
@@ -71,38 +72,43 @@
             row_block_id, col_block_id, &row, &col, &row_stride, &col_stride);
         // Off diagonal entries are not present.
         if (i != j) {
-          EXPECT_TRUE(cell == NULL);
+          EXPECT_TRUE(cell == nullptr);
           continue;
         }
 
-        EXPECT_TRUE(cell != NULL);
+        EXPECT_TRUE(cell != nullptr);
         EXPECT_EQ(row, 0);
         EXPECT_EQ(col, 0);
-        EXPECT_EQ(row_stride, blocks[row_block_id]);
-        EXPECT_EQ(col_stride, blocks[col_block_id]);
+        EXPECT_EQ(row_stride, blocks[row_block_id].size);
+        EXPECT_EQ(col_stride, blocks[col_block_id].size);
 
         // Write into the block
         MatrixRef(cell->values, row_stride, col_stride)
-            .block(row, col, blocks[row_block_id], blocks[col_block_id]) =
+            .block(row,
+                   col,
+                   blocks[row_block_id].size,
+                   blocks[col_block_id].size) =
             (row_block_id + 1) * (col_block_id + 1) *
-                Matrix::Ones(blocks[row_block_id], blocks[col_block_id]) +
-            Matrix::Identity(blocks[row_block_id], blocks[row_block_id]);
+                Matrix::Ones(blocks[row_block_id].size,
+                             blocks[col_block_id].size) +
+            Matrix::Identity(blocks[row_block_id].size,
+                             blocks[row_block_id].size);
       }
     }
   }
 
  protected:
+  ContextImpl context_;
   int num_nonzeros_;
   std::unique_ptr<BlockRandomAccessDiagonalMatrix> m_;
 };
 
 TEST_F(BlockRandomAccessDiagonalMatrixTest, MatrixContents) {
-  const TripletSparseMatrix* tsm = m_->matrix();
-  EXPECT_EQ(tsm->num_nonzeros(), num_nonzeros_);
-  EXPECT_EQ(tsm->max_num_nonzeros(), num_nonzeros_);
+  auto* crsm = m_->matrix();
+  EXPECT_EQ(crsm->num_nonzeros(), num_nonzeros_);
 
   Matrix dense;
-  tsm->ToDenseMatrix(&dense);
+  crsm->ToDenseMatrix(&dense);
 
   double kTolerance = 1e-14;
 
@@ -134,31 +140,30 @@
       kTolerance);
 }
 
-TEST_F(BlockRandomAccessDiagonalMatrixTest, RightMultiply) {
+TEST_F(BlockRandomAccessDiagonalMatrixTest, RightMultiplyAndAccumulate) {
   double kTolerance = 1e-14;
-  const TripletSparseMatrix* tsm = m_->matrix();
+  auto* crsm = m_->matrix();
   Matrix dense;
-  tsm->ToDenseMatrix(&dense);
+  crsm->ToDenseMatrix(&dense);
   Vector x = Vector::Random(dense.rows());
   Vector expected_y = dense * x;
   Vector actual_y = Vector::Zero(dense.rows());
-  m_->RightMultiply(x.data(), actual_y.data());
+  m_->RightMultiplyAndAccumulate(x.data(), actual_y.data());
   EXPECT_NEAR((expected_y - actual_y).norm(), 0, kTolerance);
 }
 
 TEST_F(BlockRandomAccessDiagonalMatrixTest, Invert) {
   double kTolerance = 1e-14;
-  const TripletSparseMatrix* tsm = m_->matrix();
+  auto* crsm = m_->matrix();
   Matrix dense;
-  tsm->ToDenseMatrix(&dense);
+  crsm->ToDenseMatrix(&dense);
   Matrix expected_inverse =
       dense.llt().solve(Matrix::Identity(dense.rows(), dense.rows()));
 
   m_->Invert();
-  tsm->ToDenseMatrix(&dense);
+  crsm->ToDenseMatrix(&dense);
 
   EXPECT_NEAR((expected_inverse - dense).norm(), 0.0, kTolerance);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/block_random_access_matrix.cc b/third_party/ceres/internal/ceres/block_random_access_matrix.cc
index ea88855..cb3d9dc 100644
--- a/third_party/ceres/internal/ceres/block_random_access_matrix.cc
+++ b/third_party/ceres/internal/ceres/block_random_access_matrix.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -30,10 +30,8 @@
 
 #include "ceres/block_random_access_matrix.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
-BlockRandomAccessMatrix::~BlockRandomAccessMatrix() {}
+BlockRandomAccessMatrix::~BlockRandomAccessMatrix() = default;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/block_random_access_matrix.h b/third_party/ceres/internal/ceres/block_random_access_matrix.h
index f190622..66390d7 100644
--- a/third_party/ceres/internal/ceres/block_random_access_matrix.h
+++ b/third_party/ceres/internal/ceres/block_random_access_matrix.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,10 +35,9 @@
 
 #include <mutex>
 
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // A matrix implementing the BlockRandomAccessMatrix interface is a
 // matrix whose rows and columns are divided into blocks. For example
@@ -62,7 +61,7 @@
 //
 // There is no requirement that all cells be present, i.e. the matrix
 // itself can be block sparse. When a cell is not present, the GetCell
-// method will return a NULL pointer.
+// method will return a nullptr pointer.
 //
 // There is no requirement about how the cells are stored beyond that
 // form a dense submatrix of a larger dense matrix. Like everywhere
@@ -77,7 +76,7 @@
 //                              &row, &col,
 //                              &row_stride, &col_stride);
 //
-//  if (cell != NULL) {
+//  if (cell != nullptr) {
 //     MatrixRef m(cell->values, row_stride, col_stride);
 //     std::lock_guard<std::mutex> l(&cell->m);
 //     m.block(row, col, row_block_size, col_block_size) = ...
@@ -85,21 +84,21 @@
 
 // Structure to carry a pointer to the array containing a cell and the
 // mutex guarding it.
-struct CellInfo {
-  CellInfo() : values(nullptr) {}
+struct CERES_NO_EXPORT CellInfo {
+  CellInfo() = default;
   explicit CellInfo(double* values) : values(values) {}
 
-  double* values;
+  double* values{nullptr};
   std::mutex m;
 };
 
-class CERES_EXPORT_INTERNAL BlockRandomAccessMatrix {
+class CERES_NO_EXPORT BlockRandomAccessMatrix {
  public:
   virtual ~BlockRandomAccessMatrix();
 
   // If the cell (row_block_id, col_block_id) is present, then return
   // a CellInfo with a pointer to the dense matrix containing it,
-  // otherwise return NULL. The dense matrix containing this cell has
+  // otherwise return nullptr. The dense matrix containing this cell has
   // size row_stride, col_stride and the cell is located at position
   // (row, col) within this matrix.
   //
@@ -123,7 +122,6 @@
   virtual int num_cols() const = 0;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_INTERNAL_BLOCK_RANDOM_ACCESS_MATRIX_H_
diff --git a/third_party/ceres/internal/ceres/block_random_access_sparse_matrix.cc b/third_party/ceres/internal/ceres/block_random_access_sparse_matrix.cc
index c28b7ce..b9f8b36 100644
--- a/third_party/ceres/internal/ceres/block_random_access_sparse_matrix.cc
+++ b/third_party/ceres/internal/ceres/block_random_access_sparse_matrix.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -36,87 +36,63 @@
 #include <utility>
 #include <vector>
 
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
+#include "ceres/parallel_vector_ops.h"
 #include "ceres/triplet_sparse_matrix.h"
 #include "ceres/types.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
-
-using std::make_pair;
-using std::pair;
-using std::set;
-using std::vector;
+namespace ceres::internal {
 
 BlockRandomAccessSparseMatrix::BlockRandomAccessSparseMatrix(
-    const vector<int>& blocks, const set<pair<int, int>>& block_pairs)
-    : kMaxRowBlocks(10 * 1000 * 1000), blocks_(blocks) {
-  CHECK_LT(blocks.size(), kMaxRowBlocks);
+    const std::vector<Block>& blocks,
+    const std::set<std::pair<int, int>>& block_pairs,
+    ContextImpl* context,
+    int num_threads)
+    : blocks_(blocks), context_(context), num_threads_(num_threads) {
+  CHECK_LE(blocks.size(), std::numeric_limits<std::int32_t>::max());
 
-  // Build the row/column layout vector and count the number of scalar
-  // rows/columns.
-  int num_cols = 0;
-  block_positions_.reserve(blocks_.size());
-  for (int i = 0; i < blocks_.size(); ++i) {
-    block_positions_.push_back(num_cols);
-    num_cols += blocks_[i];
+  const int num_cols = NumScalarEntries(blocks);
+  const int num_blocks = blocks.size();
+
+  std::vector<int> num_cells_at_row(num_blocks);
+  for (auto& p : block_pairs) {
+    ++num_cells_at_row[p.first];
   }
-
-  // Count the number of scalar non-zero entries and build the layout
-  // object for looking into the values array of the
-  // TripletSparseMatrix.
+  auto block_structure_ = new CompressedRowBlockStructure;
+  block_structure_->cols = blocks;
+  block_structure_->rows.resize(num_blocks);
+  auto p = block_pairs.begin();
   int num_nonzeros = 0;
-  for (const auto& block_pair : block_pairs) {
-    const int row_block_size = blocks_[block_pair.first];
-    const int col_block_size = blocks_[block_pair.second];
-    num_nonzeros += row_block_size * col_block_size;
-  }
-
-  VLOG(1) << "Matrix Size [" << num_cols << "," << num_cols << "] "
-          << num_nonzeros;
-
-  tsm_.reset(new TripletSparseMatrix(num_cols, num_cols, num_nonzeros));
-  tsm_->set_num_nonzeros(num_nonzeros);
-  int* rows = tsm_->mutable_rows();
-  int* cols = tsm_->mutable_cols();
-  double* values = tsm_->mutable_values();
-
-  int pos = 0;
-  for (const auto& block_pair : block_pairs) {
-    const int row_block_size = blocks_[block_pair.first];
-    const int col_block_size = blocks_[block_pair.second];
-    cell_values_.push_back(make_pair(block_pair, values + pos));
-    layout_[IntPairToLong(block_pair.first, block_pair.second)] =
-        new CellInfo(values + pos);
-    pos += row_block_size * col_block_size;
-  }
-
-  // Fill the sparsity pattern of the underlying matrix.
-  for (const auto& block_pair : block_pairs) {
-    const int row_block_id = block_pair.first;
-    const int col_block_id = block_pair.second;
-    const int row_block_size = blocks_[row_block_id];
-    const int col_block_size = blocks_[col_block_id];
-    int pos =
-        layout_[IntPairToLong(row_block_id, col_block_id)]->values - values;
-    for (int r = 0; r < row_block_size; ++r) {
-      for (int c = 0; c < col_block_size; ++c, ++pos) {
-        rows[pos] = block_positions_[row_block_id] + r;
-        cols[pos] = block_positions_[col_block_id] + c;
-        values[pos] = 1.0;
-        DCHECK_LT(rows[pos], tsm_->num_rows());
-        DCHECK_LT(cols[pos], tsm_->num_rows());
-      }
+  // Pairs of block indices are sorted lexicographically, thus pairs
+  // corresponding to a single row-block are stored in segments of index pairs
+  // with constant row-block index and increasing column-block index.
+  // CompressedRowBlockStructure is created by traversing block_pairs set.
+  for (int row_block_id = 0; row_block_id < num_blocks; ++row_block_id) {
+    auto& row = block_structure_->rows[row_block_id];
+    row.block = blocks[row_block_id];
+    row.cells.reserve(num_cells_at_row[row_block_id]);
+    const int row_block_size = blocks[row_block_id].size;
+    // Process all index pairs corresponding to the current row block. Because
+    // index pairs are sorted lexicographically, cells are being appended to the
+    // current row-block till the first change in row-block index
+    for (; p != block_pairs.end() && row_block_id == p->first; ++p) {
+      const int col_block_id = p->second;
+      row.cells.emplace_back(col_block_id, num_nonzeros);
+      num_nonzeros += row_block_size * blocks[col_block_id].size;
     }
   }
-}
-
-// Assume that the user does not hold any locks on any cell blocks
-// when they are calling SetZero.
-BlockRandomAccessSparseMatrix::~BlockRandomAccessSparseMatrix() {
-  for (const auto& entry : layout_) {
-    delete entry.second;
+  bsm_ = std::make_unique<BlockSparseMatrix>(block_structure_);
+  VLOG(1) << "Matrix Size [" << num_cols << "," << num_cols << "] "
+          << num_nonzeros;
+  double* values = bsm_->mutable_values();
+  for (int row_block_id = 0; row_block_id < num_blocks; ++row_block_id) {
+    const auto& cells = block_structure_->rows[row_block_id].cells;
+    for (auto& c : cells) {
+      const int col_block_id = c.block_id;
+      double* const data = values + c.position;
+      layout_.emplace(IntPairToInt64(row_block_id, col_block_id), data);
+    }
   }
 }
 
@@ -126,53 +102,57 @@
                                                  int* col,
                                                  int* row_stride,
                                                  int* col_stride) {
-  const LayoutType::iterator it =
-      layout_.find(IntPairToLong(row_block_id, col_block_id));
+  const auto it = layout_.find(IntPairToInt64(row_block_id, col_block_id));
   if (it == layout_.end()) {
-    return NULL;
+    return nullptr;
   }
 
   // Each cell is stored contiguously as its own little dense matrix.
   *row = 0;
   *col = 0;
-  *row_stride = blocks_[row_block_id];
-  *col_stride = blocks_[col_block_id];
-  return it->second;
+  *row_stride = blocks_[row_block_id].size;
+  *col_stride = blocks_[col_block_id].size;
+  return &it->second;
 }
 
 // Assume that the user does not hold any locks on any cell blocks
 // when they are calling SetZero.
 void BlockRandomAccessSparseMatrix::SetZero() {
-  if (tsm_->num_nonzeros()) {
-    VectorRef(tsm_->mutable_values(), tsm_->num_nonzeros()).setZero();
-  }
+  bsm_->SetZero(context_, num_threads_);
 }
 
-void BlockRandomAccessSparseMatrix::SymmetricRightMultiply(const double* x,
-                                                           double* y) const {
-  for (const auto& cell_position_and_data : cell_values_) {
-    const int row = cell_position_and_data.first.first;
-    const int row_block_size = blocks_[row];
-    const int row_block_pos = block_positions_[row];
+void BlockRandomAccessSparseMatrix::SymmetricRightMultiplyAndAccumulate(
+    const double* x, double* y) const {
+  const auto bs = bsm_->block_structure();
+  const auto values = bsm_->values();
+  const int num_blocks = blocks_.size();
 
-    const int col = cell_position_and_data.first.second;
-    const int col_block_size = blocks_[col];
-    const int col_block_pos = block_positions_[col];
+  for (int row_block_id = 0; row_block_id < num_blocks; ++row_block_id) {
+    const auto& row_block = bs->rows[row_block_id];
+    const int row_block_size = row_block.block.size;
+    const int row_block_pos = row_block.block.position;
 
-    MatrixVectorMultiply<Eigen::Dynamic, Eigen::Dynamic, 1>(
-        cell_position_and_data.second,
-        row_block_size,
-        col_block_size,
-        x + col_block_pos,
-        y + row_block_pos);
+    for (auto& c : row_block.cells) {
+      const int col_block_id = c.block_id;
+      const int col_block_size = blocks_[col_block_id].size;
+      const int col_block_pos = blocks_[col_block_id].position;
 
-    // Since the matrix is symmetric, but only the upper triangular
-    // part is stored, if the block being accessed is not a diagonal
-    // block, then use the same block to do the corresponding lower
-    // triangular multiply also.
-    if (row != col) {
+      MatrixVectorMultiply<Eigen::Dynamic, Eigen::Dynamic, 1>(
+          values + c.position,
+          row_block_size,
+          col_block_size,
+          x + col_block_pos,
+          y + row_block_pos);
+      if (col_block_id == row_block_id) {
+        continue;
+      }
+
+      // Since the matrix is symmetric, but only the upper triangular
+      // part is stored, if the block being accessed is not a diagonal
+      // block, then use the same block to do the corresponding lower
+      // triangular multiply also
       MatrixTransposeVectorMultiply<Eigen::Dynamic, Eigen::Dynamic, 1>(
-          cell_position_and_data.second,
+          values + c.position,
           row_block_size,
           col_block_size,
           x + row_block_pos,
@@ -181,5 +161,4 @@
   }
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/block_random_access_sparse_matrix.h b/third_party/ceres/internal/ceres/block_random_access_sparse_matrix.h
index 0e58bbb..5121832 100644
--- a/third_party/ceres/internal/ceres/block_random_access_sparse_matrix.h
+++ b/third_party/ceres/internal/ceres/block_random_access_sparse_matrix.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -39,33 +39,35 @@
 #include <vector>
 
 #include "ceres/block_random_access_matrix.h"
-#include "ceres/internal/port.h"
+#include "ceres/block_sparse_matrix.h"
+#include "ceres/block_structure.h"
+#include "ceres/context_impl.h"
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 #include "ceres/small_blas.h"
-#include "ceres/triplet_sparse_matrix.h"
 #include "ceres/types.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // A thread safe square block sparse implementation of
-// BlockRandomAccessMatrix. Internally a TripletSparseMatrix is used
+// BlockRandomAccessMatrix. Internally a BlockSparseMatrix is used
 // for doing the actual storage. This class augments this matrix with
 // an unordered_map that allows random read/write access.
-class CERES_EXPORT_INTERNAL BlockRandomAccessSparseMatrix
+class CERES_NO_EXPORT BlockRandomAccessSparseMatrix
     : public BlockRandomAccessMatrix {
  public:
   // blocks is an array of block sizes. block_pairs is a set of
   // <row_block_id, col_block_id> pairs to identify the non-zero cells
   // of this matrix.
   BlockRandomAccessSparseMatrix(
-      const std::vector<int>& blocks,
-      const std::set<std::pair<int, int>>& block_pairs);
-  BlockRandomAccessSparseMatrix(const BlockRandomAccessSparseMatrix&) = delete;
-  void operator=(const BlockRandomAccessSparseMatrix&) = delete;
+      const std::vector<Block>& blocks,
+      const std::set<std::pair<int, int>>& block_pairs,
+      ContextImpl* context,
+      int num_threads);
 
   // The destructor is not thread safe. It assumes that no one is
   // modifying any cells when the matrix is being destroyed.
-  virtual ~BlockRandomAccessSparseMatrix();
+  ~BlockRandomAccessSparseMatrix() override = default;
 
   // BlockRandomAccessMatrix Interface.
   CellInfo* GetCell(int row_block_id,
@@ -79,52 +81,50 @@
   // locked.
   void SetZero() final;
 
-  // Assume that the matrix is symmetric and only one half of the
-  // matrix is stored.
+  // Assume that the matrix is symmetric and only one half of the matrix is
+  // stored.
   //
   // y += S * x
-  void SymmetricRightMultiply(const double* x, double* y) const;
+  void SymmetricRightMultiplyAndAccumulate(const double* x, double* y) const;
 
   // Since the matrix is square, num_rows() == num_cols().
-  int num_rows() const final { return tsm_->num_rows(); }
-  int num_cols() const final { return tsm_->num_cols(); }
+  int num_rows() const final { return bsm_->num_rows(); }
+  int num_cols() const final { return bsm_->num_cols(); }
 
   // Access to the underlying matrix object.
-  const TripletSparseMatrix* matrix() const { return tsm_.get(); }
-  TripletSparseMatrix* mutable_matrix() { return tsm_.get(); }
+  const BlockSparseMatrix* matrix() const { return bsm_.get(); }
+  BlockSparseMatrix* mutable_matrix() { return bsm_.get(); }
 
  private:
-  int64_t IntPairToLong(int row, int col) const {
-    return row * kMaxRowBlocks + col;
+  int64_t IntPairToInt64(int row, int col) const {
+    return row * kRowShift + col;
   }
 
-  void LongToIntPair(int64_t index, int* row, int* col) const {
-    *row = index / kMaxRowBlocks;
-    *col = index % kMaxRowBlocks;
+  void Int64ToIntPair(int64_t index, int* row, int* col) const {
+    *row = index / kRowShift;
+    *col = index % kRowShift;
   }
 
-  const int64_t kMaxRowBlocks;
+  constexpr static int64_t kRowShift{1ll << 32};
 
   // row/column block sizes.
-  const std::vector<int> blocks_;
-  std::vector<int> block_positions_;
+  const std::vector<Block> blocks_;
+  ContextImpl* context_ = nullptr;
+  const int num_threads_ = 1;
 
   // A mapping from <row_block_id, col_block_id> to the position in
-  // the values array of tsm_ where the block is stored.
-  typedef std::unordered_map<long int, CellInfo*> LayoutType;
+  // the values array of bsm_ where the block is stored.
+  using LayoutType = std::unordered_map<std::int64_t, CellInfo>;
   LayoutType layout_;
 
-  // In order traversal of contents of the matrix. This allows us to
-  // implement a matrix-vector which is 20% faster than using the
-  // iterator in the Layout object instead.
-  std::vector<std::pair<std::pair<int, int>, double*>> cell_values_;
   // The underlying matrix object which actually stores the cells.
-  std::unique_ptr<TripletSparseMatrix> tsm_;
+  std::unique_ptr<BlockSparseMatrix> bsm_;
 
   friend class BlockRandomAccessSparseMatrixTest;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_BLOCK_RANDOM_ACCESS_SPARSE_MATRIX_H_
diff --git a/third_party/ceres/internal/ceres/block_random_access_sparse_matrix_test.cc b/third_party/ceres/internal/ceres/block_random_access_sparse_matrix_test.cc
index 557b678..0bb39f1 100644
--- a/third_party/ceres/internal/ceres/block_random_access_sparse_matrix_test.cc
+++ b/third_party/ceres/internal/ceres/block_random_access_sparse_matrix_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -32,42 +32,40 @@
 
 #include <limits>
 #include <memory>
+#include <set>
+#include <utility>
 #include <vector>
 
 #include "ceres/internal/eigen.h"
 #include "glog/logging.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
-
-using std::make_pair;
-using std::pair;
-using std::set;
-using std::vector;
+namespace ceres::internal {
 
 TEST(BlockRandomAccessSparseMatrix, GetCell) {
-  vector<int> blocks;
-  blocks.push_back(3);
-  blocks.push_back(4);
-  blocks.push_back(5);
-  const int num_rows = 3 + 4 + 5;
+  ContextImpl context;
+  constexpr int num_threads = 1;
+  std::vector<Block> blocks;
+  blocks.emplace_back(3, 0);
+  blocks.emplace_back(4, 3);
+  blocks.emplace_back(5, 7);
+  constexpr int num_rows = 3 + 4 + 5;
 
-  set<pair<int, int>> block_pairs;
+  std::set<std::pair<int, int>> block_pairs;
   int num_nonzeros = 0;
-  block_pairs.insert(make_pair(0, 0));
-  num_nonzeros += blocks[0] * blocks[0];
+  block_pairs.emplace(0, 0);
+  num_nonzeros += blocks[0].size * blocks[0].size;
 
-  block_pairs.insert(make_pair(1, 1));
-  num_nonzeros += blocks[1] * blocks[1];
+  block_pairs.emplace(1, 1);
+  num_nonzeros += blocks[1].size * blocks[1].size;
 
-  block_pairs.insert(make_pair(1, 2));
-  num_nonzeros += blocks[1] * blocks[2];
+  block_pairs.emplace(1, 2);
+  num_nonzeros += blocks[1].size * blocks[2].size;
 
-  block_pairs.insert(make_pair(0, 2));
-  num_nonzeros += blocks[2] * blocks[0];
+  block_pairs.emplace(0, 2);
+  num_nonzeros += blocks[2].size * blocks[0].size;
 
-  BlockRandomAccessSparseMatrix m(blocks, block_pairs);
+  BlockRandomAccessSparseMatrix m(blocks, block_pairs, &context, num_threads);
   EXPECT_EQ(m.num_rows(), num_rows);
   EXPECT_EQ(m.num_cols(), num_rows);
 
@@ -80,25 +78,24 @@
     int col_stride;
     CellInfo* cell = m.GetCell(
         row_block_id, col_block_id, &row, &col, &row_stride, &col_stride);
-    EXPECT_TRUE(cell != NULL);
+    EXPECT_TRUE(cell != nullptr);
     EXPECT_EQ(row, 0);
     EXPECT_EQ(col, 0);
-    EXPECT_EQ(row_stride, blocks[row_block_id]);
-    EXPECT_EQ(col_stride, blocks[col_block_id]);
+    EXPECT_EQ(row_stride, blocks[row_block_id].size);
+    EXPECT_EQ(col_stride, blocks[col_block_id].size);
 
     // Write into the block
     MatrixRef(cell->values, row_stride, col_stride)
-        .block(row, col, blocks[row_block_id], blocks[col_block_id]) =
+        .block(row, col, blocks[row_block_id].size, blocks[col_block_id].size) =
         (row_block_id + 1) * (col_block_id + 1) *
-        Matrix::Ones(blocks[row_block_id], blocks[col_block_id]);
+        Matrix::Ones(blocks[row_block_id].size, blocks[col_block_id].size);
   }
 
-  const TripletSparseMatrix* tsm = m.matrix();
-  EXPECT_EQ(tsm->num_nonzeros(), num_nonzeros);
-  EXPECT_EQ(tsm->max_num_nonzeros(), num_nonzeros);
+  const BlockSparseMatrix* bsm = m.matrix();
+  EXPECT_EQ(bsm->num_nonzeros(), num_nonzeros);
 
   Matrix dense;
-  tsm->ToDenseMatrix(&dense);
+  bsm->ToDenseMatrix(&dense);
 
   double kTolerance = 1e-14;
 
@@ -127,39 +124,40 @@
   Vector expected_y = Vector::Zero(dense.rows());
 
   expected_y += dense.selfadjointView<Eigen::Upper>() * x;
-  m.SymmetricRightMultiply(x.data(), actual_y.data());
+  m.SymmetricRightMultiplyAndAccumulate(x.data(), actual_y.data());
   EXPECT_NEAR((expected_y - actual_y).norm(), 0.0, kTolerance)
       << "actual: " << actual_y.transpose() << "\n"
       << "expected: " << expected_y.transpose() << "matrix: \n " << dense;
 }
 
-// IntPairToLong is private, thus this fixture is needed to access and
+// IntPairToInt64 is private, thus this fixture is needed to access and
 // test it.
 class BlockRandomAccessSparseMatrixTest : public ::testing::Test {
  public:
   void SetUp() final {
-    vector<int> blocks;
-    blocks.push_back(1);
-    set<pair<int, int>> block_pairs;
-    block_pairs.insert(make_pair(0, 0));
-    m_.reset(new BlockRandomAccessSparseMatrix(blocks, block_pairs));
+    std::vector<Block> blocks;
+    blocks.emplace_back(1, 0);
+    std::set<std::pair<int, int>> block_pairs;
+    block_pairs.emplace(0, 0);
+    m_ = std::make_unique<BlockRandomAccessSparseMatrix>(
+        blocks, block_pairs, &context_, 1);
   }
 
-  void CheckIntPairToLong(int a, int b) {
-    int64_t value = m_->IntPairToLong(a, b);
+  void CheckIntPairToInt64(int a, int b) {
+    int64_t value = m_->IntPairToInt64(a, b);
     EXPECT_GT(value, 0) << "Overflow a = " << a << " b = " << b;
     EXPECT_GT(value, a) << "Overflow a = " << a << " b = " << b;
     EXPECT_GT(value, b) << "Overflow a = " << a << " b = " << b;
   }
 
-  void CheckLongToIntPair() {
-    uint64_t max_rows = m_->kMaxRowBlocks;
+  void CheckInt64ToIntPair() {
+    uint64_t max_rows = m_->kRowShift;
     for (int row = max_rows - 10; row < max_rows; ++row) {
       for (int col = 0; col < 10; ++col) {
         int row_computed;
         int col_computed;
-        m_->LongToIntPair(
-            m_->IntPairToLong(row, col), &row_computed, &col_computed);
+        m_->Int64ToIntPair(
+            m_->IntPairToInt64(row, col), &row_computed, &col_computed);
         EXPECT_EQ(row, row_computed);
         EXPECT_EQ(col, col_computed);
       }
@@ -167,17 +165,17 @@
   }
 
  private:
+  ContextImpl context_;
   std::unique_ptr<BlockRandomAccessSparseMatrix> m_;
 };
 
-TEST_F(BlockRandomAccessSparseMatrixTest, IntPairToLongOverflow) {
-  CheckIntPairToLong(std::numeric_limits<int>::max(),
-                     std::numeric_limits<int>::max());
+TEST_F(BlockRandomAccessSparseMatrixTest, IntPairToInt64Overflow) {
+  CheckIntPairToInt64(std::numeric_limits<int32_t>::max(),
+                      std::numeric_limits<int32_t>::max());
 }
 
-TEST_F(BlockRandomAccessSparseMatrixTest, LongToIntPair) {
-  CheckLongToIntPair();
+TEST_F(BlockRandomAccessSparseMatrixTest, Int64ToIntPair) {
+  CheckInt64ToIntPair();
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/block_sparse_matrix.cc b/third_party/ceres/internal/ceres/block_sparse_matrix.cc
index 5efd2e1..2efee39 100644
--- a/third_party/ceres/internal/ceres/block_sparse_matrix.cc
+++ b/third_party/ceres/internal/ceres/block_sparse_matrix.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -32,33 +32,159 @@
 
 #include <algorithm>
 #include <cstddef>
+#include <memory>
+#include <numeric>
+#include <random>
 #include <vector>
 
 #include "ceres/block_structure.h"
+#include "ceres/crs_matrix.h"
 #include "ceres/internal/eigen.h"
-#include "ceres/random.h"
+#include "ceres/parallel_for.h"
+#include "ceres/parallel_vector_ops.h"
 #include "ceres/small_blas.h"
 #include "ceres/triplet_sparse_matrix.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
+#ifndef CERES_NO_CUDA
+#include "cuda_runtime.h"
+#endif
 
-using std::vector;
+namespace ceres::internal {
 
-BlockSparseMatrix::~BlockSparseMatrix() {}
+namespace {
+void ComputeCumulativeNumberOfNonZeros(std::vector<CompressedList>& rows) {
+  if (rows.empty()) {
+    return;
+  }
+  rows[0].cumulative_nnz = rows[0].nnz;
+  for (int c = 1; c < rows.size(); ++c) {
+    const int curr_nnz = rows[c].nnz;
+    rows[c].cumulative_nnz = curr_nnz + rows[c - 1].cumulative_nnz;
+  }
+}
+
+template <bool transpose>
+std::unique_ptr<CompressedRowSparseMatrix>
+CreateStructureOfCompressedRowSparseMatrix(
+    int num_rows,
+    int num_cols,
+    int num_nonzeros,
+    const CompressedRowBlockStructure* block_structure) {
+  auto crs_matrix = std::make_unique<CompressedRowSparseMatrix>(
+      num_rows, num_cols, num_nonzeros);
+  auto crs_cols = crs_matrix->mutable_cols();
+  auto crs_rows = crs_matrix->mutable_rows();
+  int value_offset = 0;
+  const int num_row_blocks = block_structure->rows.size();
+  const auto& cols = block_structure->cols;
+  *crs_rows++ = 0;
+  for (int row_block_id = 0; row_block_id < num_row_blocks; ++row_block_id) {
+    const auto& row_block = block_structure->rows[row_block_id];
+    // Empty row block: only requires setting row offsets
+    if (row_block.cells.empty()) {
+      std::fill(crs_rows, crs_rows + row_block.block.size, value_offset);
+      crs_rows += row_block.block.size;
+      continue;
+    }
+
+    int row_nnz = 0;
+    if constexpr (transpose) {
+      // Transposed block structure comes with nnz in row-block filled-in
+      row_nnz = row_block.nnz / row_block.block.size;
+    } else {
+      // Nnz field of non-transposed block structure is not filled and it can
+      // have non-sequential structure (consider the case of jacobian for
+      // Schur-complement solver: E and F blocks are stored separately).
+      for (auto& c : row_block.cells) {
+        row_nnz += cols[c.block_id].size;
+      }
+    }
+
+    // Row-wise setup of matrix structure
+    for (int row = 0; row < row_block.block.size; ++row) {
+      value_offset += row_nnz;
+      *crs_rows++ = value_offset;
+      for (auto& c : row_block.cells) {
+        const int col_block_size = cols[c.block_id].size;
+        const int col_position = cols[c.block_id].position;
+        std::iota(crs_cols, crs_cols + col_block_size, col_position);
+        crs_cols += col_block_size;
+      }
+    }
+  }
+  return crs_matrix;
+}
+
+template <bool transpose>
+void UpdateCompressedRowSparseMatrixImpl(
+    CompressedRowSparseMatrix* crs_matrix,
+    const double* values,
+    const CompressedRowBlockStructure* block_structure) {
+  auto crs_values = crs_matrix->mutable_values();
+  auto crs_rows = crs_matrix->mutable_rows();
+  const int num_row_blocks = block_structure->rows.size();
+  const auto& cols = block_structure->cols;
+  for (int row_block_id = 0; row_block_id < num_row_blocks; ++row_block_id) {
+    const auto& row_block = block_structure->rows[row_block_id];
+    const int row_block_size = row_block.block.size;
+    const int row_nnz = crs_rows[1] - crs_rows[0];
+    crs_rows += row_block_size;
+
+    if (row_nnz == 0) {
+      continue;
+    }
+
+    MatrixRef crs_row_block(crs_values, row_block_size, row_nnz);
+    int col_offset = 0;
+    for (auto& c : row_block.cells) {
+      const int col_block_size = cols[c.block_id].size;
+      auto crs_cell =
+          crs_row_block.block(0, col_offset, row_block_size, col_block_size);
+      if constexpr (transpose) {
+        // Transposed matrix is filled using transposed block-strucutre
+        ConstMatrixRef cell(
+            values + c.position, col_block_size, row_block_size);
+        crs_cell = cell.transpose();
+      } else {
+        ConstMatrixRef cell(
+            values + c.position, row_block_size, col_block_size);
+        crs_cell = cell;
+      }
+      col_offset += col_block_size;
+    }
+    crs_values += row_nnz * row_block_size;
+  }
+}
+
+void SetBlockStructureOfCompressedRowSparseMatrix(
+    CompressedRowSparseMatrix* crs_matrix,
+    CompressedRowBlockStructure* block_structure) {
+  const int num_row_blocks = block_structure->rows.size();
+  auto& row_blocks = *crs_matrix->mutable_row_blocks();
+  row_blocks.resize(num_row_blocks);
+  for (int i = 0; i < num_row_blocks; ++i) {
+    row_blocks[i] = block_structure->rows[i].block;
+  }
+
+  auto& col_blocks = *crs_matrix->mutable_col_blocks();
+  col_blocks = block_structure->cols;
+}
+
+}  // namespace
 
 BlockSparseMatrix::BlockSparseMatrix(
-    CompressedRowBlockStructure* block_structure)
-    : num_rows_(0),
+    CompressedRowBlockStructure* block_structure, bool use_page_locked_memory)
+    : use_page_locked_memory_(use_page_locked_memory),
+      num_rows_(0),
       num_cols_(0),
       num_nonzeros_(0),
       block_structure_(block_structure) {
   CHECK(block_structure_ != nullptr);
 
   // Count the number of columns in the matrix.
-  for (int i = 0; i < block_structure_->cols.size(); ++i) {
-    num_cols_ += block_structure_->cols[i].size;
+  for (auto& col : block_structure_->cols) {
+    num_cols_ += col.size;
   }
 
   // Count the number of non-zero entries and the number of rows in
@@ -67,9 +193,9 @@
     int row_block_size = block_structure_->rows[i].block.size;
     num_rows_ += row_block_size;
 
-    const vector<Cell>& cells = block_structure_->rows[i].cells;
-    for (int j = 0; j < cells.size(); ++j) {
-      int col_block_id = cells[j].block_id;
+    const std::vector<Cell>& cells = block_structure_->rows[i].cells;
+    for (const auto& cell : cells) {
+      int col_block_id = cell.block_id;
       int col_block_size = block_structure_->cols[col_block_id].size;
       num_nonzeros_ += col_block_size * row_block_size;
     }
@@ -80,51 +206,138 @@
   CHECK_GE(num_nonzeros_, 0);
   VLOG(2) << "Allocating values array with " << num_nonzeros_ * sizeof(double)
           << " bytes.";  // NOLINT
-  values_.reset(new double[num_nonzeros_]);
+
+  values_ = AllocateValues(num_nonzeros_);
   max_num_nonzeros_ = num_nonzeros_;
   CHECK(values_ != nullptr);
+  AddTransposeBlockStructure();
 }
 
-void BlockSparseMatrix::SetZero() {
-  std::fill(values_.get(), values_.get() + num_nonzeros_, 0.0);
-}
+BlockSparseMatrix::~BlockSparseMatrix() { FreeValues(values_); }
 
-void BlockSparseMatrix::RightMultiply(const double* x, double* y) const {
-  CHECK(x != nullptr);
-  CHECK(y != nullptr);
-
-  for (int i = 0; i < block_structure_->rows.size(); ++i) {
-    int row_block_pos = block_structure_->rows[i].block.position;
-    int row_block_size = block_structure_->rows[i].block.size;
-    const vector<Cell>& cells = block_structure_->rows[i].cells;
-    for (int j = 0; j < cells.size(); ++j) {
-      int col_block_id = cells[j].block_id;
-      int col_block_size = block_structure_->cols[col_block_id].size;
-      int col_block_pos = block_structure_->cols[col_block_id].position;
-      MatrixVectorMultiply<Eigen::Dynamic, Eigen::Dynamic, 1>(
-          values_.get() + cells[j].position,
-          row_block_size,
-          col_block_size,
-          x + col_block_pos,
-          y + row_block_pos);
-    }
+void BlockSparseMatrix::AddTransposeBlockStructure() {
+  if (transpose_block_structure_ == nullptr) {
+    transpose_block_structure_ = CreateTranspose(*block_structure_);
   }
 }
 
-void BlockSparseMatrix::LeftMultiply(const double* x, double* y) const {
+void BlockSparseMatrix::SetZero() {
+  std::fill(values_, values_ + num_nonzeros_, 0.0);
+}
+
+void BlockSparseMatrix::SetZero(ContextImpl* context, int num_threads) {
+  ParallelSetZero(context, num_threads, values_, num_nonzeros_);
+}
+
+void BlockSparseMatrix::RightMultiplyAndAccumulate(const double* x,
+                                                   double* y) const {
+  RightMultiplyAndAccumulate(x, y, nullptr, 1);
+}
+
+void BlockSparseMatrix::RightMultiplyAndAccumulate(const double* x,
+                                                   double* y,
+                                                   ContextImpl* context,
+                                                   int num_threads) const {
   CHECK(x != nullptr);
   CHECK(y != nullptr);
 
+  const auto values = values_;
+  const auto block_structure = block_structure_.get();
+  const auto num_row_blocks = block_structure->rows.size();
+
+  ParallelFor(context,
+              0,
+              num_row_blocks,
+              num_threads,
+              [values, block_structure, x, y](int row_block_id) {
+                const int row_block_pos =
+                    block_structure->rows[row_block_id].block.position;
+                const int row_block_size =
+                    block_structure->rows[row_block_id].block.size;
+                const auto& cells = block_structure->rows[row_block_id].cells;
+                for (const auto& cell : cells) {
+                  const int col_block_id = cell.block_id;
+                  const int col_block_size =
+                      block_structure->cols[col_block_id].size;
+                  const int col_block_pos =
+                      block_structure->cols[col_block_id].position;
+                  MatrixVectorMultiply<Eigen::Dynamic, Eigen::Dynamic, 1>(
+                      values + cell.position,
+                      row_block_size,
+                      col_block_size,
+                      x + col_block_pos,
+                      y + row_block_pos);
+                }
+              });
+}
+
+// TODO(https://github.com/ceres-solver/ceres-solver/issues/933): This method
+// might benefit from caching column-block partition
+void BlockSparseMatrix::LeftMultiplyAndAccumulate(const double* x,
+                                                  double* y,
+                                                  ContextImpl* context,
+                                                  int num_threads) const {
+  // While utilizing transposed structure allows to perform parallel
+  // left-multiplication by dense vector, it makes access patterns to matrix
+  // elements scattered. Thus, multiplication using transposed structure
+  // is only useful for parallel execution
+  CHECK(x != nullptr);
+  CHECK(y != nullptr);
+  if (transpose_block_structure_ == nullptr || num_threads == 1) {
+    LeftMultiplyAndAccumulate(x, y);
+    return;
+  }
+
+  auto transpose_bs = transpose_block_structure_.get();
+  const auto values = values_;
+  const int num_col_blocks = transpose_bs->rows.size();
+  if (!num_col_blocks) {
+    return;
+  }
+
+  // Use non-zero count as iteration cost for guided parallel-for loop
+  ParallelFor(
+      context,
+      0,
+      num_col_blocks,
+      num_threads,
+      [values, transpose_bs, x, y](int row_block_id) {
+        int row_block_pos = transpose_bs->rows[row_block_id].block.position;
+        int row_block_size = transpose_bs->rows[row_block_id].block.size;
+        auto& cells = transpose_bs->rows[row_block_id].cells;
+
+        for (auto& cell : cells) {
+          const int col_block_id = cell.block_id;
+          const int col_block_size = transpose_bs->cols[col_block_id].size;
+          const int col_block_pos = transpose_bs->cols[col_block_id].position;
+          MatrixTransposeVectorMultiply<Eigen::Dynamic, Eigen::Dynamic, 1>(
+              values + cell.position,
+              col_block_size,
+              row_block_size,
+              x + col_block_pos,
+              y + row_block_pos);
+        }
+      },
+      transpose_bs->rows.data(),
+      [](const CompressedRow& row) { return row.cumulative_nnz; });
+}
+
+void BlockSparseMatrix::LeftMultiplyAndAccumulate(const double* x,
+                                                  double* y) const {
+  CHECK(x != nullptr);
+  CHECK(y != nullptr);
+  // Single-threaded left products are always computed using a non-transpose
+  // block structure, because it has linear acess pattern to matrix elements
   for (int i = 0; i < block_structure_->rows.size(); ++i) {
     int row_block_pos = block_structure_->rows[i].block.position;
     int row_block_size = block_structure_->rows[i].block.size;
-    const vector<Cell>& cells = block_structure_->rows[i].cells;
-    for (int j = 0; j < cells.size(); ++j) {
-      int col_block_id = cells[j].block_id;
+    const auto& cells = block_structure_->rows[i].cells;
+    for (const auto& cell : cells) {
+      int col_block_id = cell.block_id;
       int col_block_size = block_structure_->cols[col_block_id].size;
       int col_block_pos = block_structure_->cols[col_block_id].position;
       MatrixTransposeVectorMultiply<Eigen::Dynamic, Eigen::Dynamic, 1>(
-          values_.get() + cells[j].position,
+          values_ + cell.position,
           row_block_size,
           col_block_size,
           x + row_block_pos,
@@ -138,35 +351,144 @@
   VectorRef(x, num_cols_).setZero();
   for (int i = 0; i < block_structure_->rows.size(); ++i) {
     int row_block_size = block_structure_->rows[i].block.size;
-    const vector<Cell>& cells = block_structure_->rows[i].cells;
-    for (int j = 0; j < cells.size(); ++j) {
-      int col_block_id = cells[j].block_id;
+    auto& cells = block_structure_->rows[i].cells;
+    for (const auto& cell : cells) {
+      int col_block_id = cell.block_id;
       int col_block_size = block_structure_->cols[col_block_id].size;
       int col_block_pos = block_structure_->cols[col_block_id].position;
       const MatrixRef m(
-          values_.get() + cells[j].position, row_block_size, col_block_size);
+          values_ + cell.position, row_block_size, col_block_size);
       VectorRef(x + col_block_pos, col_block_size) += m.colwise().squaredNorm();
     }
   }
 }
 
+// TODO(https://github.com/ceres-solver/ceres-solver/issues/933): This method
+// might benefit from caching column-block partition
+void BlockSparseMatrix::SquaredColumnNorm(double* x,
+                                          ContextImpl* context,
+                                          int num_threads) const {
+  if (transpose_block_structure_ == nullptr || num_threads == 1) {
+    SquaredColumnNorm(x);
+    return;
+  }
+
+  CHECK(x != nullptr);
+  ParallelSetZero(context, num_threads, x, num_cols_);
+
+  auto transpose_bs = transpose_block_structure_.get();
+  const auto values = values_;
+  const int num_col_blocks = transpose_bs->rows.size();
+  ParallelFor(
+      context,
+      0,
+      num_col_blocks,
+      num_threads,
+      [values, transpose_bs, x](int row_block_id) {
+        const auto& row = transpose_bs->rows[row_block_id];
+
+        for (auto& cell : row.cells) {
+          const auto& col = transpose_bs->cols[cell.block_id];
+          const MatrixRef m(values + cell.position, col.size, row.block.size);
+          VectorRef(x + row.block.position, row.block.size) +=
+              m.colwise().squaredNorm();
+        }
+      },
+      transpose_bs->rows.data(),
+      [](const CompressedRow& row) { return row.cumulative_nnz; });
+}
+
 void BlockSparseMatrix::ScaleColumns(const double* scale) {
   CHECK(scale != nullptr);
 
   for (int i = 0; i < block_structure_->rows.size(); ++i) {
     int row_block_size = block_structure_->rows[i].block.size;
-    const vector<Cell>& cells = block_structure_->rows[i].cells;
-    for (int j = 0; j < cells.size(); ++j) {
-      int col_block_id = cells[j].block_id;
+    auto& cells = block_structure_->rows[i].cells;
+    for (const auto& cell : cells) {
+      int col_block_id = cell.block_id;
       int col_block_size = block_structure_->cols[col_block_id].size;
       int col_block_pos = block_structure_->cols[col_block_id].position;
-      MatrixRef m(
-          values_.get() + cells[j].position, row_block_size, col_block_size);
+      MatrixRef m(values_ + cell.position, row_block_size, col_block_size);
       m *= ConstVectorRef(scale + col_block_pos, col_block_size).asDiagonal();
     }
   }
 }
 
+// TODO(https://github.com/ceres-solver/ceres-solver/issues/933): This method
+// might benefit from caching column-block partition
+void BlockSparseMatrix::ScaleColumns(const double* scale,
+                                     ContextImpl* context,
+                                     int num_threads) {
+  if (transpose_block_structure_ == nullptr || num_threads == 1) {
+    ScaleColumns(scale);
+    return;
+  }
+
+  CHECK(scale != nullptr);
+  auto transpose_bs = transpose_block_structure_.get();
+  auto values = values_;
+  const int num_col_blocks = transpose_bs->rows.size();
+  ParallelFor(
+      context,
+      0,
+      num_col_blocks,
+      num_threads,
+      [values, transpose_bs, scale](int row_block_id) {
+        const auto& row = transpose_bs->rows[row_block_id];
+
+        for (auto& cell : row.cells) {
+          const auto& col = transpose_bs->cols[cell.block_id];
+          MatrixRef m(values + cell.position, col.size, row.block.size);
+          m *= ConstVectorRef(scale + row.block.position, row.block.size)
+                   .asDiagonal();
+        }
+      },
+      transpose_bs->rows.data(),
+      [](const CompressedRow& row) { return row.cumulative_nnz; });
+}
+std::unique_ptr<CompressedRowSparseMatrix>
+BlockSparseMatrix::ToCompressedRowSparseMatrixTranspose() const {
+  auto bs = transpose_block_structure_.get();
+  auto crs_matrix = CreateStructureOfCompressedRowSparseMatrix<true>(
+      num_cols_, num_rows_, num_nonzeros_, bs);
+
+  SetBlockStructureOfCompressedRowSparseMatrix(crs_matrix.get(), bs);
+
+  UpdateCompressedRowSparseMatrixTranspose(crs_matrix.get());
+  return crs_matrix;
+}
+
+std::unique_ptr<CompressedRowSparseMatrix>
+BlockSparseMatrix::ToCompressedRowSparseMatrix() const {
+  auto crs_matrix = CreateStructureOfCompressedRowSparseMatrix<false>(
+      num_rows_, num_cols_, num_nonzeros_, block_structure_.get());
+
+  SetBlockStructureOfCompressedRowSparseMatrix(crs_matrix.get(),
+                                               block_structure_.get());
+
+  UpdateCompressedRowSparseMatrix(crs_matrix.get());
+  return crs_matrix;
+}
+
+void BlockSparseMatrix::UpdateCompressedRowSparseMatrixTranspose(
+    CompressedRowSparseMatrix* crs_matrix) const {
+  CHECK(crs_matrix != nullptr);
+  CHECK_EQ(crs_matrix->num_rows(), num_cols_);
+  CHECK_EQ(crs_matrix->num_cols(), num_rows_);
+  CHECK_EQ(crs_matrix->num_nonzeros(), num_nonzeros_);
+  UpdateCompressedRowSparseMatrixImpl<true>(
+      crs_matrix, values(), transpose_block_structure_.get());
+}
+void BlockSparseMatrix::UpdateCompressedRowSparseMatrix(
+    CompressedRowSparseMatrix* crs_matrix) const {
+  CHECK(crs_matrix != nullptr);
+  CHECK_EQ(crs_matrix->num_rows(), num_rows_);
+  CHECK_EQ(crs_matrix->num_cols(), num_cols_);
+  CHECK_EQ(crs_matrix->num_nonzeros(), num_nonzeros_);
+  UpdateCompressedRowSparseMatrixImpl<false>(
+      crs_matrix, values(), block_structure_.get());
+}
+
 void BlockSparseMatrix::ToDenseMatrix(Matrix* dense_matrix) const {
   CHECK(dense_matrix != nullptr);
 
@@ -177,14 +499,14 @@
   for (int i = 0; i < block_structure_->rows.size(); ++i) {
     int row_block_pos = block_structure_->rows[i].block.position;
     int row_block_size = block_structure_->rows[i].block.size;
-    const vector<Cell>& cells = block_structure_->rows[i].cells;
-    for (int j = 0; j < cells.size(); ++j) {
-      int col_block_id = cells[j].block_id;
+    auto& cells = block_structure_->rows[i].cells;
+    for (const auto& cell : cells) {
+      int col_block_id = cell.block_id;
       int col_block_size = block_structure_->cols[col_block_id].size;
       int col_block_pos = block_structure_->cols[col_block_id].position;
-      int jac_pos = cells[j].position;
+      int jac_pos = cell.position;
       m.block(row_block_pos, col_block_pos, row_block_size, col_block_size) +=
-          MatrixRef(values_.get() + jac_pos, row_block_size, col_block_size);
+          MatrixRef(values_ + jac_pos, row_block_size, col_block_size);
     }
   }
 }
@@ -200,12 +522,12 @@
   for (int i = 0; i < block_structure_->rows.size(); ++i) {
     int row_block_pos = block_structure_->rows[i].block.position;
     int row_block_size = block_structure_->rows[i].block.size;
-    const vector<Cell>& cells = block_structure_->rows[i].cells;
-    for (int j = 0; j < cells.size(); ++j) {
-      int col_block_id = cells[j].block_id;
+    const auto& cells = block_structure_->rows[i].cells;
+    for (const auto& cell : cells) {
+      int col_block_id = cell.block_id;
       int col_block_size = block_structure_->cols[col_block_id].size;
       int col_block_pos = block_structure_->cols[col_block_id].position;
-      int jac_pos = cells[j].position;
+      int jac_pos = cell.position;
       for (int r = 0; r < row_block_size; ++r) {
         for (int c = 0; c < col_block_size; ++c, ++jac_pos) {
           matrix->mutable_rows()[jac_pos] = row_block_pos + r;
@@ -224,17 +546,24 @@
   return block_structure_.get();
 }
 
+// Return a pointer to the block structure of matrix transpose. We continue to
+// hold ownership of the object though.
+const CompressedRowBlockStructure*
+BlockSparseMatrix::transpose_block_structure() const {
+  return transpose_block_structure_.get();
+}
+
 void BlockSparseMatrix::ToTextFile(FILE* file) const {
   CHECK(file != nullptr);
   for (int i = 0; i < block_structure_->rows.size(); ++i) {
     const int row_block_pos = block_structure_->rows[i].block.position;
     const int row_block_size = block_structure_->rows[i].block.size;
-    const vector<Cell>& cells = block_structure_->rows[i].cells;
-    for (int j = 0; j < cells.size(); ++j) {
-      const int col_block_id = cells[j].block_id;
+    const auto& cells = block_structure_->rows[i].cells;
+    for (const auto& cell : cells) {
+      const int col_block_id = cell.block_id;
       const int col_block_size = block_structure_->cols[col_block_id].size;
       const int col_block_pos = block_structure_->cols[col_block_id].position;
-      int jac_pos = cells[j].position;
+      int jac_pos = cell.position;
       for (int r = 0; r < row_block_size; ++r) {
         for (int c = 0; c < col_block_size; ++c) {
           fprintf(file,
@@ -248,10 +577,10 @@
   }
 }
 
-BlockSparseMatrix* BlockSparseMatrix::CreateDiagonalMatrix(
+std::unique_ptr<BlockSparseMatrix> BlockSparseMatrix::CreateDiagonalMatrix(
     const double* diagonal, const std::vector<Block>& column_blocks) {
   // Create the block structure for the diagonal matrix.
-  CompressedRowBlockStructure* bs = new CompressedRowBlockStructure();
+  auto* bs = new CompressedRowBlockStructure();
   bs->cols = column_blocks;
   int position = 0;
   bs->rows.resize(column_blocks.size(), CompressedRow(1));
@@ -265,13 +594,13 @@
   }
 
   // Create the BlockSparseMatrix with the given block structure.
-  BlockSparseMatrix* matrix = new BlockSparseMatrix(bs);
+  auto matrix = std::make_unique<BlockSparseMatrix>(bs);
   matrix->SetZero();
 
   // Fill the values array of the block sparse matrix.
   double* values = matrix->mutable_values();
-  for (int i = 0; i < column_blocks.size(); ++i) {
-    const int size = column_blocks[i].size;
+  for (const auto& column_block : column_blocks) {
+    const int size = column_block.size;
     for (int j = 0; j < size; ++j) {
       // (j + 1) * size is compact way of accessing the (j,j) entry.
       values[j * (size + 1)] = diagonal[j];
@@ -294,33 +623,51 @@
 
   for (int i = 0; i < m_bs->rows.size(); ++i) {
     const CompressedRow& m_row = m_bs->rows[i];
-    CompressedRow& row = block_structure_->rows[old_num_row_blocks + i];
+    const int row_block_id = old_num_row_blocks + i;
+    CompressedRow& row = block_structure_->rows[row_block_id];
     row.block.size = m_row.block.size;
     row.block.position = num_rows_;
     num_rows_ += m_row.block.size;
     row.cells.resize(m_row.cells.size());
+    if (transpose_block_structure_) {
+      transpose_block_structure_->cols.emplace_back(row.block);
+    }
     for (int c = 0; c < m_row.cells.size(); ++c) {
       const int block_id = m_row.cells[c].block_id;
       row.cells[c].block_id = block_id;
       row.cells[c].position = num_nonzeros_;
-      num_nonzeros_ += m_row.block.size * m_bs->cols[block_id].size;
+
+      const int cell_nnz = m_row.block.size * m_bs->cols[block_id].size;
+      if (transpose_block_structure_) {
+        transpose_block_structure_->rows[block_id].cells.emplace_back(
+            row_block_id, num_nonzeros_);
+        transpose_block_structure_->rows[block_id].nnz += cell_nnz;
+      }
+
+      num_nonzeros_ += cell_nnz;
     }
   }
 
   if (num_nonzeros_ > max_num_nonzeros_) {
-    double* new_values = new double[num_nonzeros_];
-    std::copy(values_.get(), values_.get() + old_num_nonzeros, new_values);
-    values_.reset(new_values);
+    double* old_values = values_;
+    values_ = AllocateValues(num_nonzeros_);
+    std::copy_n(old_values, old_num_nonzeros, values_);
     max_num_nonzeros_ = num_nonzeros_;
+    FreeValues(old_values);
   }
 
-  std::copy(m.values(),
-            m.values() + m.num_nonzeros(),
-            values_.get() + old_num_nonzeros);
+  std::copy(
+      m.values(), m.values() + m.num_nonzeros(), values_ + old_num_nonzeros);
+
+  if (transpose_block_structure_ == nullptr) {
+    return;
+  }
+  ComputeCumulativeNumberOfNonZeros(transpose_block_structure_->rows);
 }
 
 void BlockSparseMatrix::DeleteRowBlocks(const int delta_row_blocks) {
   const int num_row_blocks = block_structure_->rows.size();
+  const int new_num_row_blocks = num_row_blocks - delta_row_blocks;
   int delta_num_nonzeros = 0;
   int delta_num_rows = 0;
   const std::vector<Block>& column_blocks = block_structure_->cols;
@@ -330,15 +677,40 @@
     for (int c = 0; c < row.cells.size(); ++c) {
       const Cell& cell = row.cells[c];
       delta_num_nonzeros += row.block.size * column_blocks[cell.block_id].size;
+
+      if (transpose_block_structure_) {
+        auto& col_cells = transpose_block_structure_->rows[cell.block_id].cells;
+        while (!col_cells.empty() &&
+               col_cells.back().block_id >= new_num_row_blocks) {
+          const int del_block_id = col_cells.back().block_id;
+          const int del_block_rows =
+              block_structure_->rows[del_block_id].block.size;
+          const int del_block_cols = column_blocks[cell.block_id].size;
+          const int del_cell_nnz = del_block_rows * del_block_cols;
+          transpose_block_structure_->rows[cell.block_id].nnz -= del_cell_nnz;
+          col_cells.pop_back();
+        }
+      }
     }
   }
   num_nonzeros_ -= delta_num_nonzeros;
   num_rows_ -= delta_num_rows;
-  block_structure_->rows.resize(num_row_blocks - delta_row_blocks);
+  block_structure_->rows.resize(new_num_row_blocks);
+
+  if (transpose_block_structure_ == nullptr) {
+    return;
+  }
+  for (int i = 0; i < delta_row_blocks; ++i) {
+    transpose_block_structure_->cols.pop_back();
+  }
+
+  ComputeCumulativeNumberOfNonZeros(transpose_block_structure_->rows);
 }
 
-BlockSparseMatrix* BlockSparseMatrix::CreateRandomMatrix(
-    const BlockSparseMatrix::RandomMatrixOptions& options) {
+std::unique_ptr<BlockSparseMatrix> BlockSparseMatrix::CreateRandomMatrix(
+    const BlockSparseMatrix::RandomMatrixOptions& options,
+    std::mt19937& prng,
+    bool use_page_locked_memory) {
   CHECK_GT(options.num_row_blocks, 0);
   CHECK_GT(options.min_row_block_size, 0);
   CHECK_GT(options.max_row_block_size, 0);
@@ -346,7 +718,11 @@
   CHECK_GT(options.block_density, 0.0);
   CHECK_LE(options.block_density, 1.0);
 
-  CompressedRowBlockStructure* bs = new CompressedRowBlockStructure();
+  std::uniform_int_distribution<int> col_distribution(
+      options.min_col_block_size, options.max_col_block_size);
+  std::uniform_int_distribution<int> row_distribution(
+      options.min_row_block_size, options.max_row_block_size);
+  auto bs = std::make_unique<CompressedRowBlockStructure>();
   if (options.col_blocks.empty()) {
     CHECK_GT(options.num_col_blocks, 0);
     CHECK_GT(options.min_col_block_size, 0);
@@ -356,11 +732,8 @@
     // Generate the col block structure.
     int col_block_position = 0;
     for (int i = 0; i < options.num_col_blocks; ++i) {
-      // Generate a random integer in [min_col_block_size, max_col_block_size]
-      const int delta_block_size =
-          Uniform(options.max_col_block_size - options.min_col_block_size);
-      const int col_block_size = options.min_col_block_size + delta_block_size;
-      bs->cols.push_back(Block(col_block_size, col_block_position));
+      const int col_block_size = col_distribution(prng);
+      bs->cols.emplace_back(col_block_size, col_block_position);
       col_block_position += col_block_size;
     }
   } else {
@@ -368,24 +741,23 @@
   }
 
   bool matrix_has_blocks = false;
+  std::uniform_real_distribution<double> uniform01(0.0, 1.0);
   while (!matrix_has_blocks) {
     VLOG(1) << "Clearing";
     bs->rows.clear();
     int row_block_position = 0;
     int value_position = 0;
     for (int r = 0; r < options.num_row_blocks; ++r) {
-      const int delta_block_size =
-          Uniform(options.max_row_block_size - options.min_row_block_size);
-      const int row_block_size = options.min_row_block_size + delta_block_size;
-      bs->rows.push_back(CompressedRow());
+      const int row_block_size = row_distribution(prng);
+      bs->rows.emplace_back();
       CompressedRow& row = bs->rows.back();
       row.block.size = row_block_size;
       row.block.position = row_block_position;
       row_block_position += row_block_size;
       for (int c = 0; c < bs->cols.size(); ++c) {
-        if (RandDouble() > options.block_density) continue;
+        if (uniform01(prng) > options.block_density) continue;
 
-        row.cells.push_back(Cell());
+        row.cells.emplace_back();
         Cell& cell = row.cells.back();
         cell.block_id = c;
         cell.position = value_position;
@@ -395,14 +767,76 @@
     }
   }
 
-  BlockSparseMatrix* matrix = new BlockSparseMatrix(bs);
+  auto matrix =
+      std::make_unique<BlockSparseMatrix>(bs.release(), use_page_locked_memory);
   double* values = matrix->mutable_values();
-  for (int i = 0; i < matrix->num_nonzeros(); ++i) {
-    values[i] = RandNormal();
-  }
+  std::normal_distribution<double> standard_normal_distribution;
+  std::generate_n(
+      values, matrix->num_nonzeros(), [&standard_normal_distribution, &prng] {
+        return standard_normal_distribution(prng);
+      });
 
   return matrix;
 }
 
-}  // namespace internal
-}  // namespace ceres
+std::unique_ptr<CompressedRowBlockStructure> CreateTranspose(
+    const CompressedRowBlockStructure& bs) {
+  auto transpose = std::make_unique<CompressedRowBlockStructure>();
+
+  transpose->rows.resize(bs.cols.size());
+  for (int i = 0; i < bs.cols.size(); ++i) {
+    transpose->rows[i].block = bs.cols[i];
+    transpose->rows[i].nnz = 0;
+  }
+
+  transpose->cols.resize(bs.rows.size());
+  for (int i = 0; i < bs.rows.size(); ++i) {
+    auto& row = bs.rows[i];
+    transpose->cols[i] = row.block;
+
+    const int nrows = row.block.size;
+    for (auto& cell : row.cells) {
+      transpose->rows[cell.block_id].cells.emplace_back(i, cell.position);
+      const int ncols = transpose->rows[cell.block_id].block.size;
+      transpose->rows[cell.block_id].nnz += nrows * ncols;
+    }
+  }
+  ComputeCumulativeNumberOfNonZeros(transpose->rows);
+  return transpose;
+}
+
+double* BlockSparseMatrix::AllocateValues(int size) {
+  if (!use_page_locked_memory_) {
+    return new double[size];
+  }
+
+#ifndef CERES_NO_CUDA
+
+  double* values = nullptr;
+  CHECK_EQ(cudaSuccess,
+           cudaHostAlloc(&values, sizeof(double) * size, cudaHostAllocDefault));
+  return values;
+#else
+  LOG(FATAL) << "Page locked memory requested when CUDA is not available. "
+             << "This is a Ceres bug; please contact the developers!";
+  return nullptr;
+#endif
+};
+
+void BlockSparseMatrix::FreeValues(double*& values) {
+  if (!use_page_locked_memory_) {
+    delete[] values;
+    values = nullptr;
+    return;
+  }
+
+#ifndef CERES_NO_CUDA
+  CHECK_EQ(cudaSuccess, cudaFreeHost(values));
+  values = nullptr;
+#else
+  LOG(FATAL) << "Page locked memory requested when CUDA is not available. "
+             << "This is a Ceres bug; please contact the developers!";
+#endif
+};
+
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/block_sparse_matrix.h b/third_party/ceres/internal/ceres/block_sparse_matrix.h
index e5b3634..2e45488 100644
--- a/third_party/ceres/internal/ceres/block_sparse_matrix.h
+++ b/third_party/ceres/internal/ceres/block_sparse_matrix.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,14 +35,17 @@
 #define CERES_INTERNAL_BLOCK_SPARSE_MATRIX_H_
 
 #include <memory>
+#include <random>
 
 #include "ceres/block_structure.h"
+#include "ceres/compressed_row_sparse_matrix.h"
+#include "ceres/context_impl.h"
+#include "ceres/internal/disable_warnings.h"
 #include "ceres/internal/eigen.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 #include "ceres/sparse_matrix.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 class TripletSparseMatrix;
 
@@ -54,7 +57,7 @@
 //
 //   internal/ceres/block_structure.h
 //
-class CERES_EXPORT_INTERNAL BlockSparseMatrix : public SparseMatrix {
+class CERES_NO_EXPORT BlockSparseMatrix final : public SparseMatrix {
  public:
   // Construct a block sparse matrix with a fully initialized
   // CompressedRowBlockStructure objected. The matrix takes over
@@ -62,33 +65,64 @@
   //
   // TODO(sameeragarwal): Add a function which will validate legal
   // CompressedRowBlockStructure objects.
-  explicit BlockSparseMatrix(CompressedRowBlockStructure* block_structure);
+  explicit BlockSparseMatrix(CompressedRowBlockStructure* block_structure,
+                             bool use_page_locked_memory = false);
+  ~BlockSparseMatrix();
 
-  BlockSparseMatrix();
   BlockSparseMatrix(const BlockSparseMatrix&) = delete;
   void operator=(const BlockSparseMatrix&) = delete;
 
-  virtual ~BlockSparseMatrix();
-
   // Implementation of SparseMatrix interface.
-  void SetZero() final;
-  void RightMultiply(const double* x, double* y) const final;
-  void LeftMultiply(const double* x, double* y) const final;
+  void SetZero() override final;
+  void SetZero(ContextImpl* context, int num_threads) override final;
+  void RightMultiplyAndAccumulate(const double* x, double* y) const final;
+  void RightMultiplyAndAccumulate(const double* x,
+                                  double* y,
+                                  ContextImpl* context,
+                                  int num_threads) const final;
+  void LeftMultiplyAndAccumulate(const double* x, double* y) const final;
+  void LeftMultiplyAndAccumulate(const double* x,
+                                 double* y,
+                                 ContextImpl* context,
+                                 int num_threads) const final;
   void SquaredColumnNorm(double* x) const final;
+  void SquaredColumnNorm(double* x,
+                         ContextImpl* context,
+                         int num_threads) const final;
   void ScaleColumns(const double* scale) final;
+  void ScaleColumns(const double* scale,
+                    ContextImpl* context,
+                    int num_threads) final;
+
+  // Convert to CompressedRowSparseMatrix
+  std::unique_ptr<CompressedRowSparseMatrix> ToCompressedRowSparseMatrix()
+      const;
+  // Create CompressedRowSparseMatrix corresponding to transposed matrix
+  std::unique_ptr<CompressedRowSparseMatrix>
+  ToCompressedRowSparseMatrixTranspose() const;
+  // Copy values to CompressedRowSparseMatrix that has compatible structure
+  void UpdateCompressedRowSparseMatrix(
+      CompressedRowSparseMatrix* crs_matrix) const;
+  // Copy values to CompressedRowSparseMatrix that has structure of transposed
+  // matrix
+  void UpdateCompressedRowSparseMatrixTranspose(
+      CompressedRowSparseMatrix* crs_matrix) const;
   void ToDenseMatrix(Matrix* dense_matrix) const final;
   void ToTextFile(FILE* file) const final;
 
+  void AddTransposeBlockStructure();
+
   // clang-format off
   int num_rows()         const final { return num_rows_;     }
   int num_cols()         const final { return num_cols_;     }
   int num_nonzeros()     const final { return num_nonzeros_; }
-  const double* values() const final { return values_.get(); }
-  double* mutable_values()     final { return values_.get(); }
+  const double* values() const final { return values_; }
+  double* mutable_values()     final { return values_; }
   // clang-format on
 
   void ToTripletSparseMatrix(TripletSparseMatrix* matrix) const;
   const CompressedRowBlockStructure* block_structure() const;
+  const CompressedRowBlockStructure* transpose_block_structure() const;
 
   // Append the contents of m to the bottom of this matrix. m must
   // have the same column blocks structure as this matrix.
@@ -97,7 +131,7 @@
   // Delete the bottom delta_rows_blocks.
   void DeleteRowBlocks(int delta_row_blocks);
 
-  static BlockSparseMatrix* CreateDiagonalMatrix(
+  static std::unique_ptr<BlockSparseMatrix> CreateDiagonalMatrix(
       const double* diagonal, const std::vector<Block>& column_blocks);
 
   struct RandomMatrixOptions {
@@ -122,18 +156,23 @@
   // Create a random BlockSparseMatrix whose entries are normally
   // distributed and whose structure is determined by
   // RandomMatrixOptions.
-  //
-  // Caller owns the result.
-  static BlockSparseMatrix* CreateRandomMatrix(
-      const RandomMatrixOptions& options);
+  static std::unique_ptr<BlockSparseMatrix> CreateRandomMatrix(
+      const RandomMatrixOptions& options,
+      std::mt19937& prng,
+      bool use_page_locked_memory = false);
 
  private:
+  double* AllocateValues(int size);
+  void FreeValues(double*& values);
+
+  const bool use_page_locked_memory_;
   int num_rows_;
   int num_cols_;
   int num_nonzeros_;
   int max_num_nonzeros_;
-  std::unique_ptr<double[]> values_;
+  double* values_;
   std::unique_ptr<CompressedRowBlockStructure> block_structure_;
+  std::unique_ptr<CompressedRowBlockStructure> transpose_block_structure_;
 };
 
 // A number of algorithms like the SchurEliminator do not need
@@ -142,9 +181,9 @@
 //
 // BlockSparseDataMatrix a struct that carries these two bits of
 // information
-class BlockSparseMatrixData {
+class CERES_NO_EXPORT BlockSparseMatrixData {
  public:
-  BlockSparseMatrixData(const BlockSparseMatrix& m)
+  explicit BlockSparseMatrixData(const BlockSparseMatrix& m)
       : block_structure_(m.block_structure()), values_(m.values()){};
 
   BlockSparseMatrixData(const CompressedRowBlockStructure* block_structure,
@@ -161,7 +200,11 @@
   const double* values_;
 };
 
-}  // namespace internal
-}  // namespace ceres
+std::unique_ptr<CompressedRowBlockStructure> CreateTranspose(
+    const CompressedRowBlockStructure& bs);
+
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_BLOCK_SPARSE_MATRIX_H_
diff --git a/third_party/ceres/internal/ceres/block_sparse_matrix_test.cc b/third_party/ceres/internal/ceres/block_sparse_matrix_test.cc
index 02d3fb1..4a524f9 100644
--- a/third_party/ceres/internal/ceres/block_sparse_matrix_test.cc
+++ b/third_party/ceres/internal/ceres/block_sparse_matrix_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -30,10 +30,14 @@
 
 #include "ceres/block_sparse_matrix.h"
 
+#include <algorithm>
 #include <memory>
+#include <random>
 #include <string>
+#include <vector>
 
 #include "ceres/casts.h"
+#include "ceres/crs_matrix.h"
 #include "ceres/internal/eigen.h"
 #include "ceres/linear_least_squares_problems.h"
 #include "ceres/triplet_sparse_matrix.h"
@@ -43,102 +47,371 @@
 namespace ceres {
 namespace internal {
 
+namespace {
+
+std::unique_ptr<BlockSparseMatrix> CreateTestMatrixFromId(int id) {
+  if (id == 0) {
+    // Create the following block sparse matrix:
+    // [ 1 2 0 0  0 0 ]
+    // [ 3 4 0 0  0 0 ]
+    // [ 0 0 5 6  7 0 ]
+    // [ 0 0 8 9 10 0 ]
+    CompressedRowBlockStructure* bs = new CompressedRowBlockStructure;
+    bs->cols = {
+        // Block size 2, position 0.
+        Block(2, 0),
+        // Block size 3, position 2.
+        Block(3, 2),
+        // Block size 1, position 5.
+        Block(1, 5),
+    };
+    bs->rows = {CompressedRow(1), CompressedRow(1)};
+    bs->rows[0].block = Block(2, 0);
+    bs->rows[0].cells = {Cell(0, 0)};
+
+    bs->rows[1].block = Block(2, 2);
+    bs->rows[1].cells = {Cell(1, 4)};
+    auto m = std::make_unique<BlockSparseMatrix>(bs);
+    EXPECT_NE(m, nullptr);
+    EXPECT_EQ(m->num_rows(), 4);
+    EXPECT_EQ(m->num_cols(), 6);
+    EXPECT_EQ(m->num_nonzeros(), 10);
+    double* values = m->mutable_values();
+    for (int i = 0; i < 10; ++i) {
+      values[i] = i + 1;
+    }
+    return m;
+  } else if (id == 1) {
+    // Create the following block sparse matrix:
+    // [ 1 2 0 5 6 0 ]
+    // [ 3 4 0 7 8 0 ]
+    // [ 0 0 9 0 0 0 ]
+    CompressedRowBlockStructure* bs = new CompressedRowBlockStructure;
+    bs->cols = {
+        // Block size 2, position 0.
+        Block(2, 0),
+        // Block size 1, position 2.
+        Block(1, 2),
+        // Block size 2, position 3.
+        Block(2, 3),
+        // Block size 1, position 5.
+        Block(1, 5),
+    };
+    bs->rows = {CompressedRow(2), CompressedRow(1)};
+    bs->rows[0].block = Block(2, 0);
+    bs->rows[0].cells = {Cell(0, 0), Cell(2, 4)};
+
+    bs->rows[1].block = Block(1, 2);
+    bs->rows[1].cells = {Cell(1, 8)};
+    auto m = std::make_unique<BlockSparseMatrix>(bs);
+    EXPECT_NE(m, nullptr);
+    EXPECT_EQ(m->num_rows(), 3);
+    EXPECT_EQ(m->num_cols(), 6);
+    EXPECT_EQ(m->num_nonzeros(), 9);
+    double* values = m->mutable_values();
+    for (int i = 0; i < 9; ++i) {
+      values[i] = i + 1;
+    }
+    return m;
+  } else if (id == 2) {
+    // Create the following block sparse matrix:
+    // [ 1 2 0 | 6 7 0 ]
+    // [ 3 4 0 | 8 9 0 ]
+    // [ 0 0 5 | 0 0 10]
+    // With cells of the left submatrix preceding cells of the right submatrix
+    CompressedRowBlockStructure* bs = new CompressedRowBlockStructure;
+    bs->cols = {
+        // Block size 2, position 0.
+        Block(2, 0),
+        // Block size 1, position 2.
+        Block(1, 2),
+        // Block size 2, position 3.
+        Block(2, 3),
+        // Block size 1, position 5.
+        Block(1, 5),
+    };
+    bs->rows = {CompressedRow(2), CompressedRow(1)};
+    bs->rows[0].block = Block(2, 0);
+    bs->rows[0].cells = {Cell(0, 0), Cell(2, 5)};
+
+    bs->rows[1].block = Block(1, 2);
+    bs->rows[1].cells = {Cell(1, 4), Cell(3, 9)};
+    auto m = std::make_unique<BlockSparseMatrix>(bs);
+    EXPECT_NE(m, nullptr);
+    EXPECT_EQ(m->num_rows(), 3);
+    EXPECT_EQ(m->num_cols(), 6);
+    EXPECT_EQ(m->num_nonzeros(), 10);
+    double* values = m->mutable_values();
+    for (int i = 0; i < 10; ++i) {
+      values[i] = i + 1;
+    }
+    return m;
+  }
+  return nullptr;
+}
+}  // namespace
+
+const int kNumThreads = 4;
+
 class BlockSparseMatrixTest : public ::testing::Test {
  protected:
   void SetUp() final {
-    std::unique_ptr<LinearLeastSquaresProblem> problem(
-        CreateLinearLeastSquaresProblemFromId(2));
+    std::unique_ptr<LinearLeastSquaresProblem> problem =
+        CreateLinearLeastSquaresProblemFromId(2);
     CHECK(problem != nullptr);
-    A_.reset(down_cast<BlockSparseMatrix*>(problem->A.release()));
+    a_.reset(down_cast<BlockSparseMatrix*>(problem->A.release()));
 
-    problem.reset(CreateLinearLeastSquaresProblemFromId(1));
+    problem = CreateLinearLeastSquaresProblemFromId(1);
     CHECK(problem != nullptr);
-    B_.reset(down_cast<TripletSparseMatrix*>(problem->A.release()));
+    b_.reset(down_cast<TripletSparseMatrix*>(problem->A.release()));
 
-    CHECK_EQ(A_->num_rows(), B_->num_rows());
-    CHECK_EQ(A_->num_cols(), B_->num_cols());
-    CHECK_EQ(A_->num_nonzeros(), B_->num_nonzeros());
+    CHECK_EQ(a_->num_rows(), b_->num_rows());
+    CHECK_EQ(a_->num_cols(), b_->num_cols());
+    CHECK_EQ(a_->num_nonzeros(), b_->num_nonzeros());
+    context_.EnsureMinimumThreads(kNumThreads);
+
+    BlockSparseMatrix::RandomMatrixOptions options;
+    options.num_row_blocks = 1000;
+    options.min_row_block_size = 1;
+    options.max_row_block_size = 8;
+    options.num_col_blocks = 100;
+    options.min_col_block_size = 1;
+    options.max_col_block_size = 8;
+    options.block_density = 0.05;
+
+    std::mt19937 rng;
+    c_ = BlockSparseMatrix::CreateRandomMatrix(options, rng);
   }
 
-  std::unique_ptr<BlockSparseMatrix> A_;
-  std::unique_ptr<TripletSparseMatrix> B_;
+  std::unique_ptr<BlockSparseMatrix> a_;
+  std::unique_ptr<TripletSparseMatrix> b_;
+  std::unique_ptr<BlockSparseMatrix> c_;
+  ContextImpl context_;
 };
 
 TEST_F(BlockSparseMatrixTest, SetZeroTest) {
-  A_->SetZero();
-  EXPECT_EQ(13, A_->num_nonzeros());
+  a_->SetZero();
+  EXPECT_EQ(13, a_->num_nonzeros());
 }
 
-TEST_F(BlockSparseMatrixTest, RightMultiplyTest) {
-  Vector y_a = Vector::Zero(A_->num_rows());
-  Vector y_b = Vector::Zero(A_->num_rows());
-  for (int i = 0; i < A_->num_cols(); ++i) {
-    Vector x = Vector::Zero(A_->num_cols());
+TEST_F(BlockSparseMatrixTest, RightMultiplyAndAccumulateTest) {
+  Vector y_a = Vector::Zero(a_->num_rows());
+  Vector y_b = Vector::Zero(a_->num_rows());
+  for (int i = 0; i < a_->num_cols(); ++i) {
+    Vector x = Vector::Zero(a_->num_cols());
     x[i] = 1.0;
-    A_->RightMultiply(x.data(), y_a.data());
-    B_->RightMultiply(x.data(), y_b.data());
+    a_->RightMultiplyAndAccumulate(x.data(), y_a.data());
+    b_->RightMultiplyAndAccumulate(x.data(), y_b.data());
     EXPECT_LT((y_a - y_b).norm(), 1e-12);
   }
 }
 
-TEST_F(BlockSparseMatrixTest, LeftMultiplyTest) {
-  Vector y_a = Vector::Zero(A_->num_cols());
-  Vector y_b = Vector::Zero(A_->num_cols());
-  for (int i = 0; i < A_->num_rows(); ++i) {
-    Vector x = Vector::Zero(A_->num_rows());
+TEST_F(BlockSparseMatrixTest, RightMultiplyAndAccumulateParallelTest) {
+  Vector y_0 = Vector::Random(a_->num_rows());
+  Vector y_s = y_0;
+  Vector y_p = y_0;
+
+  Vector x = Vector::Random(a_->num_cols());
+  a_->RightMultiplyAndAccumulate(x.data(), y_s.data());
+
+  a_->RightMultiplyAndAccumulate(x.data(), y_p.data(), &context_, kNumThreads);
+
+  // Current parallel implementation is expected to be bit-exact
+  EXPECT_EQ((y_s - y_p).norm(), 0.);
+}
+
+TEST_F(BlockSparseMatrixTest, LeftMultiplyAndAccumulateTest) {
+  Vector y_a = Vector::Zero(a_->num_cols());
+  Vector y_b = Vector::Zero(a_->num_cols());
+  for (int i = 0; i < a_->num_rows(); ++i) {
+    Vector x = Vector::Zero(a_->num_rows());
     x[i] = 1.0;
-    A_->LeftMultiply(x.data(), y_a.data());
-    B_->LeftMultiply(x.data(), y_b.data());
+    a_->LeftMultiplyAndAccumulate(x.data(), y_a.data());
+    b_->LeftMultiplyAndAccumulate(x.data(), y_b.data());
     EXPECT_LT((y_a - y_b).norm(), 1e-12);
   }
 }
 
+TEST_F(BlockSparseMatrixTest, LeftMultiplyAndAccumulateParallelTest) {
+  Vector y_0 = Vector::Random(a_->num_cols());
+  Vector y_s = y_0;
+  Vector y_p = y_0;
+
+  Vector x = Vector::Random(a_->num_rows());
+  a_->LeftMultiplyAndAccumulate(x.data(), y_s.data());
+
+  a_->LeftMultiplyAndAccumulate(x.data(), y_p.data(), &context_, kNumThreads);
+
+  // Parallel implementation for left products uses a different order of
+  // traversal, thus results might be different
+  EXPECT_LT((y_s - y_p).norm(), 1e-12);
+}
+
 TEST_F(BlockSparseMatrixTest, SquaredColumnNormTest) {
-  Vector y_a = Vector::Zero(A_->num_cols());
-  Vector y_b = Vector::Zero(A_->num_cols());
-  A_->SquaredColumnNorm(y_a.data());
-  B_->SquaredColumnNorm(y_b.data());
+  Vector y_a = Vector::Zero(a_->num_cols());
+  Vector y_b = Vector::Zero(a_->num_cols());
+  a_->SquaredColumnNorm(y_a.data());
+  b_->SquaredColumnNorm(y_b.data());
   EXPECT_LT((y_a - y_b).norm(), 1e-12);
 }
 
+TEST_F(BlockSparseMatrixTest, SquaredColumnNormParallelTest) {
+  Vector y_a = Vector::Zero(c_->num_cols());
+  Vector y_b = Vector::Zero(c_->num_cols());
+  c_->SquaredColumnNorm(y_a.data());
+
+  c_->SquaredColumnNorm(y_b.data(), &context_, kNumThreads);
+  EXPECT_LT((y_a - y_b).norm(), 1e-12);
+}
+
+TEST_F(BlockSparseMatrixTest, ScaleColumnsTest) {
+  const Vector scale = Vector::Random(c_->num_cols()).cwiseAbs();
+
+  const Vector x = Vector::Random(c_->num_rows());
+  Vector y_expected = Vector::Zero(c_->num_cols());
+  c_->LeftMultiplyAndAccumulate(x.data(), y_expected.data());
+  y_expected.array() *= scale.array();
+
+  c_->ScaleColumns(scale.data());
+  Vector y_observed = Vector::Zero(c_->num_cols());
+  c_->LeftMultiplyAndAccumulate(x.data(), y_observed.data());
+
+  EXPECT_GT(y_expected.norm(), 1.);
+  EXPECT_LT((y_observed - y_expected).norm(), 1e-12 * y_expected.norm());
+}
+
+TEST_F(BlockSparseMatrixTest, ScaleColumnsParallelTest) {
+  const Vector scale = Vector::Random(c_->num_cols()).cwiseAbs();
+
+  const Vector x = Vector::Random(c_->num_rows());
+  Vector y_expected = Vector::Zero(c_->num_cols());
+  c_->LeftMultiplyAndAccumulate(x.data(), y_expected.data());
+  y_expected.array() *= scale.array();
+
+  c_->ScaleColumns(scale.data(), &context_, kNumThreads);
+  Vector y_observed = Vector::Zero(c_->num_cols());
+  c_->LeftMultiplyAndAccumulate(x.data(), y_observed.data());
+
+  EXPECT_GT(y_expected.norm(), 1.);
+  EXPECT_LT((y_observed - y_expected).norm(), 1e-12 * y_expected.norm());
+}
+
 TEST_F(BlockSparseMatrixTest, ToDenseMatrixTest) {
   Matrix m_a;
   Matrix m_b;
-  A_->ToDenseMatrix(&m_a);
-  B_->ToDenseMatrix(&m_b);
+  a_->ToDenseMatrix(&m_a);
+  b_->ToDenseMatrix(&m_b);
   EXPECT_LT((m_a - m_b).norm(), 1e-12);
 }
 
 TEST_F(BlockSparseMatrixTest, AppendRows) {
-  std::unique_ptr<LinearLeastSquaresProblem> problem(
-      CreateLinearLeastSquaresProblemFromId(2));
+  std::unique_ptr<LinearLeastSquaresProblem> problem =
+      CreateLinearLeastSquaresProblemFromId(2);
   std::unique_ptr<BlockSparseMatrix> m(
       down_cast<BlockSparseMatrix*>(problem->A.release()));
-  A_->AppendRows(*m);
-  EXPECT_EQ(A_->num_rows(), 2 * m->num_rows());
-  EXPECT_EQ(A_->num_cols(), m->num_cols());
+  a_->AppendRows(*m);
+  EXPECT_EQ(a_->num_rows(), 2 * m->num_rows());
+  EXPECT_EQ(a_->num_cols(), m->num_cols());
 
-  problem.reset(CreateLinearLeastSquaresProblemFromId(1));
+  problem = CreateLinearLeastSquaresProblemFromId(1);
   std::unique_ptr<TripletSparseMatrix> m2(
       down_cast<TripletSparseMatrix*>(problem->A.release()));
-  B_->AppendRows(*m2);
+  b_->AppendRows(*m2);
 
-  Vector y_a = Vector::Zero(A_->num_rows());
-  Vector y_b = Vector::Zero(A_->num_rows());
-  for (int i = 0; i < A_->num_cols(); ++i) {
-    Vector x = Vector::Zero(A_->num_cols());
+  Vector y_a = Vector::Zero(a_->num_rows());
+  Vector y_b = Vector::Zero(a_->num_rows());
+  for (int i = 0; i < a_->num_cols(); ++i) {
+    Vector x = Vector::Zero(a_->num_cols());
     x[i] = 1.0;
     y_a.setZero();
     y_b.setZero();
 
-    A_->RightMultiply(x.data(), y_a.data());
-    B_->RightMultiply(x.data(), y_b.data());
+    a_->RightMultiplyAndAccumulate(x.data(), y_a.data());
+    b_->RightMultiplyAndAccumulate(x.data(), y_b.data());
     EXPECT_LT((y_a - y_b).norm(), 1e-12);
   }
 }
 
+TEST_F(BlockSparseMatrixTest, AppendDeleteRowsTransposedStructure) {
+  auto problem = CreateLinearLeastSquaresProblemFromId(2);
+  std::unique_ptr<BlockSparseMatrix> m(
+      down_cast<BlockSparseMatrix*>(problem->A.release()));
+
+  auto block_structure = a_->block_structure();
+
+  // Several AppendRows and DeleteRowBlocks operations are applied to matrix,
+  // with regular and transpose block structures being compared after each
+  // operation.
+  //
+  // Non-negative values encode number of row blocks to remove
+  // -1 encodes appending matrix m
+  const int num_row_blocks_to_delete[] = {0, -1, 1, -1, 8, -1, 10};
+  for (auto& t : num_row_blocks_to_delete) {
+    if (t == -1) {
+      a_->AppendRows(*m);
+    } else if (t > 0) {
+      CHECK_GE(block_structure->rows.size(), t);
+      a_->DeleteRowBlocks(t);
+    }
+
+    auto block_structure = a_->block_structure();
+    auto transpose_block_structure = a_->transpose_block_structure();
+    ASSERT_NE(block_structure, nullptr);
+    ASSERT_NE(transpose_block_structure, nullptr);
+
+    EXPECT_EQ(block_structure->rows.size(),
+              transpose_block_structure->cols.size());
+    EXPECT_EQ(block_structure->cols.size(),
+              transpose_block_structure->rows.size());
+
+    std::vector<int> nnz_col(transpose_block_structure->rows.size());
+    for (int i = 0; i < block_structure->cols.size(); ++i) {
+      EXPECT_EQ(block_structure->cols[i].position,
+                transpose_block_structure->rows[i].block.position);
+      const int col_size = transpose_block_structure->rows[i].block.size;
+      EXPECT_EQ(block_structure->cols[i].size, col_size);
+
+      for (auto& col_cell : transpose_block_structure->rows[i].cells) {
+        int matches = 0;
+        const int row_block_id = col_cell.block_id;
+        nnz_col[i] +=
+            col_size * transpose_block_structure->cols[row_block_id].size;
+        for (auto& row_cell : block_structure->rows[row_block_id].cells) {
+          if (row_cell.block_id != i) continue;
+          EXPECT_EQ(row_cell.position, col_cell.position);
+          ++matches;
+        }
+        EXPECT_EQ(matches, 1);
+      }
+      EXPECT_EQ(nnz_col[i], transpose_block_structure->rows[i].nnz);
+      if (i > 0) {
+        nnz_col[i] += nnz_col[i - 1];
+      }
+      EXPECT_EQ(nnz_col[i], transpose_block_structure->rows[i].cumulative_nnz);
+    }
+    for (int i = 0; i < block_structure->rows.size(); ++i) {
+      EXPECT_EQ(block_structure->rows[i].block.position,
+                transpose_block_structure->cols[i].position);
+      EXPECT_EQ(block_structure->rows[i].block.size,
+                transpose_block_structure->cols[i].size);
+
+      for (auto& row_cell : block_structure->rows[i].cells) {
+        int matches = 0;
+        const int col_block_id = row_cell.block_id;
+        for (auto& col_cell :
+             transpose_block_structure->rows[col_block_id].cells) {
+          if (col_cell.block_id != i) continue;
+          EXPECT_EQ(col_cell.position, row_cell.position);
+          ++matches;
+        }
+        EXPECT_EQ(matches, 1);
+      }
+    }
+  }
+}
+
 TEST_F(BlockSparseMatrixTest, AppendAndDeleteBlockDiagonalMatrix) {
-  const std::vector<Block>& column_blocks = A_->block_structure()->cols;
+  const std::vector<Block>& column_blocks = a_->block_structure()->cols;
   const int num_cols =
       column_blocks.back().size + column_blocks.back().position;
   Vector diagonal(num_cols);
@@ -148,48 +421,48 @@
   std::unique_ptr<BlockSparseMatrix> appendage(
       BlockSparseMatrix::CreateDiagonalMatrix(diagonal.data(), column_blocks));
 
-  A_->AppendRows(*appendage);
+  a_->AppendRows(*appendage);
   Vector y_a, y_b;
-  y_a.resize(A_->num_rows());
-  y_b.resize(A_->num_rows());
-  for (int i = 0; i < A_->num_cols(); ++i) {
-    Vector x = Vector::Zero(A_->num_cols());
+  y_a.resize(a_->num_rows());
+  y_b.resize(a_->num_rows());
+  for (int i = 0; i < a_->num_cols(); ++i) {
+    Vector x = Vector::Zero(a_->num_cols());
     x[i] = 1.0;
     y_a.setZero();
     y_b.setZero();
 
-    A_->RightMultiply(x.data(), y_a.data());
-    B_->RightMultiply(x.data(), y_b.data());
-    EXPECT_LT((y_a.head(B_->num_rows()) - y_b.head(B_->num_rows())).norm(),
+    a_->RightMultiplyAndAccumulate(x.data(), y_a.data());
+    b_->RightMultiplyAndAccumulate(x.data(), y_b.data());
+    EXPECT_LT((y_a.head(b_->num_rows()) - y_b.head(b_->num_rows())).norm(),
               1e-12);
-    Vector expected_tail = Vector::Zero(A_->num_cols());
+    Vector expected_tail = Vector::Zero(a_->num_cols());
     expected_tail(i) = diagonal(i);
-    EXPECT_LT((y_a.tail(A_->num_cols()) - expected_tail).norm(), 1e-12);
+    EXPECT_LT((y_a.tail(a_->num_cols()) - expected_tail).norm(), 1e-12);
   }
 
-  A_->DeleteRowBlocks(column_blocks.size());
-  EXPECT_EQ(A_->num_rows(), B_->num_rows());
-  EXPECT_EQ(A_->num_cols(), B_->num_cols());
+  a_->DeleteRowBlocks(column_blocks.size());
+  EXPECT_EQ(a_->num_rows(), b_->num_rows());
+  EXPECT_EQ(a_->num_cols(), b_->num_cols());
 
-  y_a.resize(A_->num_rows());
-  y_b.resize(A_->num_rows());
-  for (int i = 0; i < A_->num_cols(); ++i) {
-    Vector x = Vector::Zero(A_->num_cols());
+  y_a.resize(a_->num_rows());
+  y_b.resize(a_->num_rows());
+  for (int i = 0; i < a_->num_cols(); ++i) {
+    Vector x = Vector::Zero(a_->num_cols());
     x[i] = 1.0;
     y_a.setZero();
     y_b.setZero();
 
-    A_->RightMultiply(x.data(), y_a.data());
-    B_->RightMultiply(x.data(), y_b.data());
+    a_->RightMultiplyAndAccumulate(x.data(), y_a.data());
+    b_->RightMultiplyAndAccumulate(x.data(), y_b.data());
     EXPECT_LT((y_a - y_b).norm(), 1e-12);
   }
 }
 
 TEST(BlockSparseMatrix, CreateDiagonalMatrix) {
   std::vector<Block> column_blocks;
-  column_blocks.push_back(Block(2, 0));
-  column_blocks.push_back(Block(1, 2));
-  column_blocks.push_back(Block(3, 3));
+  column_blocks.emplace_back(2, 0);
+  column_blocks.emplace_back(1, 2);
+  column_blocks.emplace_back(3, 3);
   const int num_cols =
       column_blocks.back().size + column_blocks.back().position;
   Vector diagonal(num_cols);
@@ -208,11 +481,195 @@
   EXPECT_EQ(m->num_rows(), m->num_cols());
   Vector x = Vector::Ones(num_cols);
   Vector y = Vector::Zero(num_cols);
-  m->RightMultiply(x.data(), y.data());
+  m->RightMultiplyAndAccumulate(x.data(), y.data());
   for (int i = 0; i < num_cols; ++i) {
     EXPECT_NEAR(y[i], diagonal[i], std::numeric_limits<double>::epsilon());
   }
 }
 
+TEST(BlockSparseMatrix, ToDenseMatrix) {
+  {
+    std::unique_ptr<BlockSparseMatrix> m = CreateTestMatrixFromId(0);
+    Matrix m_dense;
+    m->ToDenseMatrix(&m_dense);
+    EXPECT_EQ(m_dense.rows(), 4);
+    EXPECT_EQ(m_dense.cols(), 6);
+    Matrix m_expected(4, 6);
+    m_expected << 1, 2, 0, 0, 0, 0, 3, 4, 0, 0, 0, 0, 0, 0, 5, 6, 7, 0, 0, 0, 8,
+        9, 10, 0;
+    EXPECT_EQ(m_dense, m_expected);
+  }
+
+  {
+    std::unique_ptr<BlockSparseMatrix> m = CreateTestMatrixFromId(1);
+    Matrix m_dense;
+    m->ToDenseMatrix(&m_dense);
+    EXPECT_EQ(m_dense.rows(), 3);
+    EXPECT_EQ(m_dense.cols(), 6);
+    Matrix m_expected(3, 6);
+    m_expected << 1, 2, 0, 5, 6, 0, 3, 4, 0, 7, 8, 0, 0, 0, 9, 0, 0, 0;
+    EXPECT_EQ(m_dense, m_expected);
+  }
+
+  {
+    std::unique_ptr<BlockSparseMatrix> m = CreateTestMatrixFromId(2);
+    Matrix m_dense;
+    m->ToDenseMatrix(&m_dense);
+    EXPECT_EQ(m_dense.rows(), 3);
+    EXPECT_EQ(m_dense.cols(), 6);
+    Matrix m_expected(3, 6);
+    m_expected << 1, 2, 0, 6, 7, 0, 3, 4, 0, 8, 9, 0, 0, 0, 5, 0, 0, 10;
+    EXPECT_EQ(m_dense, m_expected);
+  }
+}
+
+TEST(BlockSparseMatrix, ToCRSMatrix) {
+  {
+    std::unique_ptr<BlockSparseMatrix> m = CreateTestMatrixFromId(0);
+    auto m_crs = m->ToCompressedRowSparseMatrix();
+    std::vector<int> rows_expected = {0, 2, 4, 7, 10};
+    std::vector<int> cols_expected = {0, 1, 0, 1, 2, 3, 4, 2, 3, 4};
+    std::vector<double> values_expected = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+    for (int i = 0; i < rows_expected.size(); ++i) {
+      EXPECT_EQ(m_crs->rows()[i], rows_expected[i]);
+    }
+    for (int i = 0; i < cols_expected.size(); ++i) {
+      EXPECT_EQ(m_crs->cols()[i], cols_expected[i]);
+    }
+    for (int i = 0; i < values_expected.size(); ++i) {
+      EXPECT_EQ(m_crs->values()[i], values_expected[i]);
+    }
+  }
+  {
+    std::unique_ptr<BlockSparseMatrix> m = CreateTestMatrixFromId(1);
+    auto m_crs = m->ToCompressedRowSparseMatrix();
+    std::vector<int> rows_expected = {0, 4, 8, 9};
+    std::vector<int> cols_expected = {0, 1, 3, 4, 0, 1, 3, 4, 2};
+    std::vector<double> values_expected = {1, 2, 5, 6, 3, 4, 7, 8, 9};
+    for (int i = 0; i < rows_expected.size(); ++i) {
+      EXPECT_EQ(m_crs->rows()[i], rows_expected[i]);
+    }
+    for (int i = 0; i < cols_expected.size(); ++i) {
+      EXPECT_EQ(m_crs->cols()[i], cols_expected[i]);
+    }
+    for (int i = 0; i < values_expected.size(); ++i) {
+      EXPECT_EQ(m_crs->values()[i], values_expected[i]);
+    }
+  }
+  {
+    std::unique_ptr<BlockSparseMatrix> m = CreateTestMatrixFromId(2);
+    auto m_crs = m->ToCompressedRowSparseMatrix();
+    std::vector<int> rows_expected = {0, 4, 8, 10};
+    std::vector<int> cols_expected = {0, 1, 3, 4, 0, 1, 3, 4, 2, 5};
+    std::vector<double> values_expected = {1, 2, 6, 7, 3, 4, 8, 9, 5, 10};
+    for (int i = 0; i < rows_expected.size(); ++i) {
+      EXPECT_EQ(m_crs->rows()[i], rows_expected[i]);
+    }
+    for (int i = 0; i < cols_expected.size(); ++i) {
+      EXPECT_EQ(m_crs->cols()[i], cols_expected[i]);
+    }
+    for (int i = 0; i < values_expected.size(); ++i) {
+      EXPECT_EQ(m_crs->values()[i], values_expected[i]);
+    }
+  }
+}
+
+TEST(BlockSparseMatrix, ToCRSMatrixTranspose) {
+  {
+    std::unique_ptr<BlockSparseMatrix> m = CreateTestMatrixFromId(0);
+    auto m_crs_transpose = m->ToCompressedRowSparseMatrixTranspose();
+    std::vector<int> rows_expected = {0, 2, 4, 6, 8, 10, 10};
+    std::vector<int> cols_expected = {0, 1, 0, 1, 2, 3, 2, 3, 2, 3};
+    std::vector<double> values_expected = {1, 3, 2, 4, 5, 8, 6, 9, 7, 10};
+    EXPECT_EQ(m_crs_transpose->num_nonzeros(), cols_expected.size());
+    EXPECT_EQ(m_crs_transpose->num_rows(), rows_expected.size() - 1);
+    for (int i = 0; i < rows_expected.size(); ++i) {
+      EXPECT_EQ(m_crs_transpose->rows()[i], rows_expected[i]);
+    }
+    for (int i = 0; i < cols_expected.size(); ++i) {
+      EXPECT_EQ(m_crs_transpose->cols()[i], cols_expected[i]);
+    }
+    for (int i = 0; i < values_expected.size(); ++i) {
+      EXPECT_EQ(m_crs_transpose->values()[i], values_expected[i]);
+    }
+  }
+  {
+    std::unique_ptr<BlockSparseMatrix> m = CreateTestMatrixFromId(1);
+    auto m_crs_transpose = m->ToCompressedRowSparseMatrixTranspose();
+    std::vector<int> rows_expected = {0, 2, 4, 5, 7, 9, 9};
+    std::vector<int> cols_expected = {0, 1, 0, 1, 2, 0, 1, 0, 1};
+    std::vector<double> values_expected = {1, 3, 2, 4, 9, 5, 7, 6, 8};
+    EXPECT_EQ(m_crs_transpose->num_nonzeros(), cols_expected.size());
+    EXPECT_EQ(m_crs_transpose->num_rows(), rows_expected.size() - 1);
+    for (int i = 0; i < rows_expected.size(); ++i) {
+      EXPECT_EQ(m_crs_transpose->rows()[i], rows_expected[i]);
+    }
+    for (int i = 0; i < cols_expected.size(); ++i) {
+      EXPECT_EQ(m_crs_transpose->cols()[i], cols_expected[i]);
+    }
+    for (int i = 0; i < values_expected.size(); ++i) {
+      EXPECT_EQ(m_crs_transpose->values()[i], values_expected[i]);
+    }
+  }
+  {
+    std::unique_ptr<BlockSparseMatrix> m = CreateTestMatrixFromId(2);
+    auto m_crs_transpose = m->ToCompressedRowSparseMatrixTranspose();
+    std::vector<int> rows_expected = {0, 2, 4, 5, 7, 9, 10};
+    std::vector<int> cols_expected = {0, 1, 0, 1, 2, 0, 1, 0, 1, 2};
+    std::vector<double> values_expected = {1, 3, 2, 4, 5, 6, 8, 7, 9, 10};
+    EXPECT_EQ(m_crs_transpose->num_nonzeros(), cols_expected.size());
+    EXPECT_EQ(m_crs_transpose->num_rows(), rows_expected.size() - 1);
+    for (int i = 0; i < rows_expected.size(); ++i) {
+      EXPECT_EQ(m_crs_transpose->rows()[i], rows_expected[i]);
+    }
+    for (int i = 0; i < cols_expected.size(); ++i) {
+      EXPECT_EQ(m_crs_transpose->cols()[i], cols_expected[i]);
+    }
+    for (int i = 0; i < values_expected.size(); ++i) {
+      EXPECT_EQ(m_crs_transpose->values()[i], values_expected[i]);
+    }
+  }
+}
+
+TEST(BlockSparseMatrix, CreateTranspose) {
+  constexpr int kNumtrials = 10;
+  BlockSparseMatrix::RandomMatrixOptions options;
+  options.num_col_blocks = 10;
+  options.min_col_block_size = 1;
+  options.max_col_block_size = 3;
+
+  options.num_row_blocks = 20;
+  options.min_row_block_size = 1;
+  options.max_row_block_size = 4;
+  options.block_density = 0.25;
+  std::mt19937 prng;
+
+  for (int trial = 0; trial < kNumtrials; ++trial) {
+    auto a = BlockSparseMatrix::CreateRandomMatrix(options, prng);
+
+    auto ap_bs = std::make_unique<CompressedRowBlockStructure>();
+    *ap_bs = *a->block_structure();
+    BlockSparseMatrix ap(ap_bs.release());
+    std::copy_n(a->values(), a->num_nonzeros(), ap.mutable_values());
+
+    Vector x = Vector::Random(a->num_cols());
+    Vector y = Vector::Random(a->num_rows());
+    Vector a_x = Vector::Zero(a->num_rows());
+    Vector a_t_y = Vector::Zero(a->num_cols());
+    Vector ap_x = Vector::Zero(a->num_rows());
+    Vector ap_t_y = Vector::Zero(a->num_cols());
+    a->RightMultiplyAndAccumulate(x.data(), a_x.data());
+    ap.RightMultiplyAndAccumulate(x.data(), ap_x.data());
+    EXPECT_NEAR((a_x - ap_x).norm() / a_x.norm(),
+                0.0,
+                std::numeric_limits<double>::epsilon());
+    a->LeftMultiplyAndAccumulate(y.data(), a_t_y.data());
+    ap.LeftMultiplyAndAccumulate(y.data(), ap_t_y.data());
+    EXPECT_NEAR((a_t_y - ap_t_y).norm() / a_t_y.norm(),
+                0.0,
+                std::numeric_limits<double>::epsilon());
+  }
+}
+
 }  // namespace internal
 }  // namespace ceres
diff --git a/third_party/ceres/internal/ceres/block_structure.cc b/third_party/ceres/internal/ceres/block_structure.cc
index 39ba082..70f68b2 100644
--- a/third_party/ceres/internal/ceres/block_structure.cc
+++ b/third_party/ceres/internal/ceres/block_structure.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -30,8 +30,11 @@
 
 #include "ceres/block_structure.h"
 
-namespace ceres {
-namespace internal {
+#include <vector>
+
+#include "glog/logging.h"
+
+namespace ceres::internal {
 
 bool CellLessThan(const Cell& lhs, const Cell& rhs) {
   if (lhs.block_id == rhs.block_id) {
@@ -40,5 +43,28 @@
   return (lhs.block_id < rhs.block_id);
 }
 
-}  // namespace internal
-}  // namespace ceres
+std::vector<Block> Tail(const std::vector<Block>& blocks, int n) {
+  CHECK_LE(n, blocks.size());
+  std::vector<Block> tail;
+  const int num_blocks = blocks.size();
+  const int start = num_blocks - n;
+
+  int position = 0;
+  tail.reserve(n);
+  for (int i = start; i < num_blocks; ++i) {
+    tail.emplace_back(blocks[i].size, position);
+    position += blocks[i].size;
+  }
+
+  return tail;
+}
+
+int SumSquaredSizes(const std::vector<Block>& blocks) {
+  int sum = 0;
+  for (const auto& b : blocks) {
+    sum += b.size * b.size;
+  }
+  return sum;
+}
+
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/block_structure.h b/third_party/ceres/internal/ceres/block_structure.h
index d49d7d3..9500fbb 100644
--- a/third_party/ceres/internal/ceres/block_structure.h
+++ b/third_party/ceres/internal/ceres/block_structure.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -41,58 +41,158 @@
 #include <cstdint>
 #include <vector>
 
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 
+// This file is being included into source files that are compiled with nvcc.
+// nvcc shipped with ubuntu 20.04 does not support some features of c++17,
+// including nested namespace definitions
 namespace ceres {
 namespace internal {
 
-typedef int32_t BlockSize;
+using BlockSize = int32_t;
 
-struct Block {
-  Block() : size(-1), position(-1) {}
-  Block(int size_, int position_) : size(size_), position(position_) {}
+struct CERES_NO_EXPORT Block {
+  Block() = default;
+  Block(int size_, int position_) noexcept : size(size_), position(position_) {}
 
-  BlockSize size;
-  int position;  // Position along the row/column.
+  BlockSize size{-1};
+  int position{-1};  // Position along the row/column.
 };
 
-struct Cell {
-  Cell() : block_id(-1), position(-1) {}
-  Cell(int block_id_, int position_)
+inline bool operator==(const Block& left, const Block& right) noexcept {
+  return (left.size == right.size) && (left.position == right.position);
+}
+
+struct CERES_NO_EXPORT Cell {
+  Cell() = default;
+  Cell(int block_id_, int position_) noexcept
       : block_id(block_id_), position(position_) {}
 
   // Column or row block id as the case maybe.
-  int block_id;
+  int block_id{-1};
   // Where in the values array of the jacobian is this cell located.
-  int position;
+  int position{-1};
 };
 
 // Order cell by their block_id;
-bool CellLessThan(const Cell& lhs, const Cell& rhs);
+CERES_NO_EXPORT bool CellLessThan(const Cell& lhs, const Cell& rhs);
 
-struct CompressedList {
-  CompressedList() {}
+struct CERES_NO_EXPORT CompressedList {
+  CompressedList() = default;
 
   // Construct a CompressedList with the cells containing num_cells
   // entries.
-  CompressedList(int num_cells) : cells(num_cells) {}
+  explicit CompressedList(int num_cells) noexcept : cells(num_cells) {}
   Block block;
   std::vector<Cell> cells;
+  // Number of non-zeros in cells of this row block
+  int nnz{-1};
+  // Number of non-zeros in cells of this and every preceeding row block in
+  // block-sparse matrix
+  int cumulative_nnz{-1};
 };
 
-typedef CompressedList CompressedRow;
-typedef CompressedList CompressedColumn;
+using CompressedRow = CompressedList;
+using CompressedColumn = CompressedList;
 
-struct CompressedRowBlockStructure {
+// CompressedRowBlockStructure specifies the storage structure of a row block
+// sparse matrix.
+//
+// Consider the following matrix A:
+// A = [A_11 A_12 ...
+//      A_21 A_22 ...
+//      ...
+//      A_m1 A_m2 ... ]
+//
+// A row block sparse matrix is a matrix where the following properties hold:
+// 1. The number of rows in every block A_ij and A_ik are the same.
+// 2. The number of columns in every block A_ij and A_kj are the same.
+// 3. The number of rows in A_ij and A_kj may be different (i != k).
+// 4. The number of columns in A_ij and A_ik may be different (j != k).
+// 5. Any block A_ij may be all 0s, in which case the block is not stored.
+//
+// The structure of the matrix is stored as follows:
+//
+// The `rows' array contains the following information for each row block:
+// - rows[i].block.size: The number of rows in each block A_ij in the row block.
+// - rows[i].block.position: The starting row in the full matrix A of the
+//       row block i.
+// - rows[i].cells[j].block_id: The index into the `cols' array corresponding to
+//       the non-zero blocks A_ij.
+// - rows[i].cells[j].position: The index in the `values' array for the contents
+//       of block A_ij.
+//
+// The `cols' array contains the following information for block:
+// - cols[.].size: The number of columns spanned by the block.
+// - cols[.].position: The starting column in the full matrix A of the block.
+//
+//
+// Example of a row block sparse matrix:
+// block_id: | 0  |1|2  |3 |
+// rows[0]:  [ 1 2 0 3 4 0 ]
+//           [ 5 6 0 7 8 0 ]
+// rows[1]:  [ 0 0 9 0 0 0 ]
+//
+// This matrix is stored as follows:
+//
+// There are four column blocks:
+// cols[0].size = 2
+// cols[0].position = 0
+// cols[1].size = 1
+// cols[1].position = 2
+// cols[2].size = 2
+// cols[2].position = 3
+// cols[3].size = 1
+// cols[3].position = 5
+
+// The first row block spans two rows, starting at row 0:
+// rows[0].block.size = 2          // This row block spans two rows.
+// rows[0].block.position = 0      // It starts at row 0.
+// rows[0] has two cells, at column blocks 0 and 2:
+// rows[0].cells[0].block_id = 0   // This cell is in column block 0.
+// rows[0].cells[0].position = 0   // See below for an explanation of this.
+// rows[0].cells[1].block_id = 2   // This cell is in column block 2.
+// rows[0].cells[1].position = 4   // See below for an explanation of this.
+//
+// The second row block spans two rows, starting at row 2:
+// rows[1].block.size = 1          // This row block spans one row.
+// rows[1].block.position = 2      // It starts at row 2.
+// rows[1] has one cell at column block 1:
+// rows[1].cells[0].block_id = 1   // This cell is in column block 1.
+// rows[1].cells[0].position = 8   // See below for an explanation of this.
+//
+// The values in each blocks are stored contiguously in row major order.
+// However, there is no unique way to order the blocks -- it is usually
+// optimized to promote cache coherent access, e.g. ordering it so that
+// Jacobian blocks of parameters of the same type are stored nearby.
+// This is one possible way to store the values of the blocks in a values array:
+// values = { 1, 2, 5, 6, 3, 4, 7, 8, 9 }
+//           |           |          |   |    // The three blocks.
+//            ^ rows[0].cells[0].position = 0
+//                        ^ rows[0].cells[1].position = 4
+//                                    ^ rows[1].cells[0].position = 8
+struct CERES_NO_EXPORT CompressedRowBlockStructure {
   std::vector<Block> cols;
   std::vector<CompressedRow> rows;
 };
 
-struct CompressedColumnBlockStructure {
+struct CERES_NO_EXPORT CompressedColumnBlockStructure {
   std::vector<Block> rows;
   std::vector<CompressedColumn> cols;
 };
 
+inline int NumScalarEntries(const std::vector<Block>& blocks) {
+  if (blocks.empty()) {
+    return 0;
+  }
+
+  auto& block = blocks.back();
+  return block.position + block.size;
+}
+
+std::vector<Block> Tail(const std::vector<Block>& blocks, int n);
+int SumSquaredSizes(const std::vector<Block>& blocks);
+
 }  // namespace internal
 }  // namespace ceres
 
diff --git a/third_party/ceres/internal/ceres/bundle_adjustment_test_util.h b/third_party/ceres/internal/ceres/bundle_adjustment_test_util.h
index 818663f..785981a 100644
--- a/third_party/ceres/internal/ceres/bundle_adjustment_test_util.h
+++ b/third_party/ceres/internal/ceres/bundle_adjustment_test_util.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -38,7 +38,7 @@
 #include <string>
 
 #include "ceres/autodiff_cost_function.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 #include "ceres/ordered_groups.h"
 #include "ceres/problem.h"
 #include "ceres/rotation.h"
@@ -46,16 +46,11 @@
 #include "ceres/stringprintf.h"
 #include "ceres/test_util.h"
 #include "ceres/types.h"
-#include "gflags/gflags.h"
 #include "glog/logging.h"
-#include "gtest/gtest.h"
 
 namespace ceres {
 namespace internal {
 
-using std::string;
-using std::vector;
-
 const bool kAutomaticOrdering = true;
 const bool kUserOrdering = false;
 
@@ -65,8 +60,13 @@
 // problem is hard coded in the constructor.
 class BundleAdjustmentProblem {
  public:
+  BundleAdjustmentProblem(const std::string input_file) {
+    ReadData(input_file);
+    BuildProblem();
+  }
   BundleAdjustmentProblem() {
-    const string input_file = TestFileAbsolutePath("problem-16-22106-pre.txt");
+    const std::string input_file =
+        TestFileAbsolutePath("problem-16-22106-pre.txt");
     ReadData(input_file);
     BuildProblem();
   }
@@ -82,21 +82,23 @@
   Solver::Options* mutable_solver_options() { return &options_; }
 
   // clang-format off
-  int num_cameras()            const { return num_cameras_; }
-  int num_points()             const { return num_points_; }
-  int num_observations()       const { return num_observations_; }
-  const int* point_index()     const { return point_index_; }
-  const int* camera_index()    const { return camera_index_; }
-  const double* observations() const { return observations_; }
-  double* mutable_cameras()          { return parameters_; }
-  double* mutable_points()           { return parameters_ + 9 * num_cameras_; }
+  int num_cameras()                const { return num_cameras_; }
+  int num_points()                 const { return num_points_; }
+  int num_observations()           const { return num_observations_; }
+  const int* point_index()         const { return point_index_; }
+  const int* camera_index()        const { return camera_index_; }
+  const double* observations()     const { return observations_; }
+  double* mutable_cameras()              { return parameters_; }
+  double* mutable_points()               { return parameters_ + 9 * num_cameras_; }
+  const Solver::Options& options() const { return options_; }
   // clang-format on
 
   static double kResidualTolerance;
 
  private:
-  void ReadData(const string& filename) {
-    FILE* fptr = fopen((string("../com_google_ceres_solver/") + filename).c_str(), "r");
+  void ReadData(const std::string& filename) {
+    FILE* fptr = fopen(
+        (std::string("../com_google_ceres_solver/") + filename).c_str(), "r");
 
     if (!fptr) {
       LOG(FATAL) << "File Error: unable to open file " << filename;
@@ -149,10 +151,11 @@
       // point_index()[i] respectively.
       double* camera = cameras + 9 * camera_index_[i];
       double* point = points + 3 * point_index()[i];
-      problem_.AddResidualBlock(cost_function, NULL, camera, point);
+      problem_.AddResidualBlock(cost_function, nullptr, camera, point);
     }
 
-    options_.linear_solver_ordering.reset(new ParameterBlockOrdering);
+    options_.linear_solver_ordering =
+        std::make_shared<ParameterBlockOrdering>();
 
     // The points come before the cameras.
     for (int i = 0; i < num_points_; ++i) {
@@ -241,7 +244,7 @@
 };
 
 double BundleAdjustmentProblem::kResidualTolerance = 1e-4;
-typedef SystemTest<BundleAdjustmentProblem> BundleAdjustmentTest;
+using BundleAdjustmentTest = SystemTest<BundleAdjustmentProblem>;
 
 }  // namespace internal
 }  // namespace ceres
diff --git a/third_party/ceres/internal/ceres/c_api.cc b/third_party/ceres/internal/ceres/c_api.cc
index 251cde4..56e1324 100644
--- a/third_party/ceres/internal/ceres/c_api.cc
+++ b/third_party/ceres/internal/ceres/c_api.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,6 +35,7 @@
 #include "ceres/c_api.h"
 
 #include <iostream>
+#include <memory>
 #include <string>
 #include <vector>
 
@@ -64,7 +65,7 @@
 
 // This cost function wraps a C-level function pointer from the user, to bridge
 // between C and C++.
-class CallbackCostFunction : public ceres::CostFunction {
+class CERES_NO_EXPORT CallbackCostFunction final : public ceres::CostFunction {
  public:
   CallbackCostFunction(ceres_cost_function_t cost_function,
                        void* user_data,
@@ -78,8 +79,6 @@
     }
   }
 
-  virtual ~CallbackCostFunction() {}
-
   bool Evaluate(double const* const* parameters,
                 double* residuals,
                 double** jacobians) const final {
@@ -94,7 +93,7 @@
 
 // This loss function wraps a C-level function pointer from the user, to bridge
 // between C and C++.
-class CallbackLossFunction : public ceres::LossFunction {
+class CallbackLossFunction final : public ceres::LossFunction {
  public:
   explicit CallbackLossFunction(ceres_loss_function_t loss_function,
                                 void* user_data)
@@ -146,30 +145,31 @@
     int num_parameter_blocks,
     int* parameter_block_sizes,
     double** parameters) {
-  Problem* ceres_problem = reinterpret_cast<Problem*>(problem);
+  auto* ceres_problem = reinterpret_cast<Problem*>(problem);
 
-  ceres::CostFunction* callback_cost_function =
-      new CallbackCostFunction(cost_function,
-                               cost_function_data,
-                               num_residuals,
-                               num_parameter_blocks,
-                               parameter_block_sizes);
+  auto callback_cost_function =
+      std::make_unique<CallbackCostFunction>(cost_function,
+                                             cost_function_data,
+                                             num_residuals,
+                                             num_parameter_blocks,
+                                             parameter_block_sizes);
 
-  ceres::LossFunction* callback_loss_function = NULL;
-  if (loss_function != NULL) {
-    callback_loss_function =
-        new CallbackLossFunction(loss_function, loss_function_data);
+  std::unique_ptr<ceres::LossFunction> callback_loss_function;
+  if (loss_function != nullptr) {
+    callback_loss_function = std::make_unique<CallbackLossFunction>(
+        loss_function, loss_function_data);
   }
 
   std::vector<double*> parameter_blocks(parameters,
                                         parameters + num_parameter_blocks);
   return reinterpret_cast<ceres_residual_block_id_t*>(
-      ceres_problem->AddResidualBlock(
-          callback_cost_function, callback_loss_function, parameter_blocks));
+      ceres_problem->AddResidualBlock(callback_cost_function.release(),
+                                      callback_loss_function.release(),
+                                      parameter_blocks));
 }
 
 void ceres_solve(ceres_problem_t* c_problem) {
-  Problem* problem = reinterpret_cast<Problem*>(c_problem);
+  auto* problem = reinterpret_cast<Problem*>(c_problem);
 
   // TODO(keir): Obviously, this way of setting options won't scale or last.
   // Instead, figure out a way to specify some of the options without
diff --git a/third_party/ceres/internal/ceres/c_api_test.cc b/third_party/ceres/internal/ceres/c_api_test.cc
index 043f6ab..9386765 100644
--- a/third_party/ceres/internal/ceres/c_api_test.cc
+++ b/third_party/ceres/internal/ceres/c_api_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -114,20 +114,20 @@
                                 double** parameters,
                                 double* residuals,
                                 double** jacobians) {
-  double* measurement = (double*)user_data;
+  auto* measurement = static_cast<double*>(user_data);
   double x = measurement[0];
   double y = measurement[1];
   double m = parameters[0][0];
   double c = parameters[1][0];
 
   residuals[0] = y - exp(m * x + c);
-  if (jacobians == NULL) {
+  if (jacobians == nullptr) {
     return 1;
   }
-  if (jacobians[0] != NULL) {
+  if (jacobians[0] != nullptr) {
     jacobians[0][0] = -x * exp(m * x + c);  // dr/dm
   }
-  if (jacobians[1] != NULL) {
+  if (jacobians[1] != nullptr) {
     jacobians[1][0] = -exp(m * x + c);  // dr/dc
   }
   return 1;
@@ -148,8 +148,8 @@
         problem,
         exponential_residual,  // Cost function
         &data[2 * i],          // Points to the (x,y) measurement
-        NULL,                  // Loss function
-        NULL,                  // Loss function user data
+        nullptr,               // Loss function
+        nullptr,               // Loss function user data
         1,                     // Number of residuals
         2,                     // Number of parameter blocks
         parameter_sizes,
diff --git a/third_party/ceres/internal/ceres/callbacks.cc b/third_party/ceres/internal/ceres/callbacks.cc
index a2692cc..e6e0644 100644
--- a/third_party/ceres/internal/ceres/callbacks.cc
+++ b/third_party/ceres/internal/ceres/callbacks.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -30,25 +30,24 @@
 
 #include "ceres/callbacks.h"
 
+#include <algorithm>
 #include <iostream>  // NO LINT
+#include <string>
 
 #include "ceres/program.h"
 #include "ceres/stringprintf.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
-
-using std::string;
+namespace ceres::internal {
 
 StateUpdatingCallback::StateUpdatingCallback(Program* program,
                                              double* parameters)
     : program_(program), parameters_(parameters) {}
 
-StateUpdatingCallback::~StateUpdatingCallback() {}
+StateUpdatingCallback::~StateUpdatingCallback() = default;
 
 CallbackReturnType StateUpdatingCallback::operator()(
-    const IterationSummary& summary) {
+    const IterationSummary& /*summary*/) {
   program_->StateVectorToParameterBlocks(parameters_);
   program_->CopyParameterBlockStateToUserState();
   return SOLVER_CONTINUE;
@@ -64,14 +63,12 @@
       user_parameters_(user_parameters) {}
 
 GradientProblemSolverStateUpdatingCallback::
-    ~GradientProblemSolverStateUpdatingCallback() {}
+    ~GradientProblemSolverStateUpdatingCallback() = default;
 
 CallbackReturnType GradientProblemSolverStateUpdatingCallback::operator()(
     const IterationSummary& summary) {
   if (summary.step_is_successful) {
-    std::copy(internal_parameters_,
-              internal_parameters_ + num_parameters_,
-              user_parameters_);
+    std::copy_n(internal_parameters_, num_parameters_, user_parameters_);
   }
   return SOLVER_CONTINUE;
 }
@@ -80,11 +77,11 @@
                                  const bool log_to_stdout)
     : minimizer_type(minimizer_type), log_to_stdout_(log_to_stdout) {}
 
-LoggingCallback::~LoggingCallback() {}
+LoggingCallback::~LoggingCallback() = default;
 
 CallbackReturnType LoggingCallback::operator()(
     const IterationSummary& summary) {
-  string output;
+  std::string output;
   if (minimizer_type == LINE_SEARCH) {
     output = StringPrintf(
         "% 4d: f:% 8e d:% 3.2e g:% 3.2e h:% 3.2e s:% 3.2e e:% 3d it:% 3.2e "
@@ -128,5 +125,4 @@
   return SOLVER_CONTINUE;
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/callbacks.h b/third_party/ceres/internal/ceres/callbacks.h
index 47112b8..d3a7657 100644
--- a/third_party/ceres/internal/ceres/callbacks.h
+++ b/third_party/ceres/internal/ceres/callbacks.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -33,20 +33,19 @@
 
 #include <string>
 
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 #include "ceres/iteration_callback.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 class Program;
 
 // Callback for updating the externally visible state of parameter
 // blocks.
-class StateUpdatingCallback : public IterationCallback {
+class CERES_NO_EXPORT StateUpdatingCallback final : public IterationCallback {
  public:
   StateUpdatingCallback(Program* program, double* parameters);
-  virtual ~StateUpdatingCallback();
+  ~StateUpdatingCallback() override;
   CallbackReturnType operator()(const IterationSummary& summary) final;
 
  private:
@@ -56,12 +55,13 @@
 
 // Callback for updating the externally visible state of the
 // parameters vector for GradientProblemSolver.
-class GradientProblemSolverStateUpdatingCallback : public IterationCallback {
+class CERES_NO_EXPORT GradientProblemSolverStateUpdatingCallback final
+    : public IterationCallback {
  public:
   GradientProblemSolverStateUpdatingCallback(int num_parameters,
                                              const double* internal_parameters,
                                              double* user_parameters);
-  virtual ~GradientProblemSolverStateUpdatingCallback();
+  ~GradientProblemSolverStateUpdatingCallback() override;
   CallbackReturnType operator()(const IterationSummary& summary) final;
 
  private:
@@ -72,10 +72,10 @@
 
 // Callback for logging the state of the minimizer to STDERR or
 // STDOUT depending on the user's preferences and logging level.
-class LoggingCallback : public IterationCallback {
+class CERES_NO_EXPORT LoggingCallback final : public IterationCallback {
  public:
   LoggingCallback(MinimizerType minimizer_type, bool log_to_stdout);
-  virtual ~LoggingCallback();
+  ~LoggingCallback() override;
   CallbackReturnType operator()(const IterationSummary& summary) final;
 
  private:
@@ -83,7 +83,6 @@
   const bool log_to_stdout_;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_INTERNAL_CALLBACKS_H_
diff --git a/third_party/ceres/internal/ceres/canonical_views_clustering.cc b/third_party/ceres/internal/ceres/canonical_views_clustering.cc
index c193735..d74e570 100644
--- a/third_party/ceres/internal/ceres/canonical_views_clustering.cc
+++ b/third_party/ceres/internal/ceres/canonical_views_clustering.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -33,23 +33,20 @@
 
 #include <unordered_map>
 #include <unordered_set>
+#include <vector>
 
 #include "ceres/graph.h"
+#include "ceres/internal/export.h"
 #include "ceres/map_util.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
-using std::vector;
+using IntMap = std::unordered_map<int, int>;
+using IntSet = std::unordered_set<int>;
 
-typedef std::unordered_map<int, int> IntMap;
-typedef std::unordered_set<int> IntSet;
-
-class CanonicalViewsClustering {
+class CERES_NO_EXPORT CanonicalViewsClustering {
  public:
-  CanonicalViewsClustering() {}
-
   // Compute the canonical views clustering of the vertices of the
   // graph. centers will contain the vertices that are the identified
   // as the canonical views/cluster centers, and membership is a map
@@ -60,15 +57,15 @@
   // are assigned to a cluster with id = kInvalidClusterId.
   void ComputeClustering(const CanonicalViewsClusteringOptions& options,
                          const WeightedGraph<int>& graph,
-                         vector<int>* centers,
+                         std::vector<int>* centers,
                          IntMap* membership);
 
  private:
   void FindValidViews(IntSet* valid_views) const;
-  double ComputeClusteringQualityDifference(const int candidate,
-                                            const vector<int>& centers) const;
+  double ComputeClusteringQualityDifference(
+      int candidate, const std::vector<int>& centers) const;
   void UpdateCanonicalViewAssignments(const int canonical_view);
-  void ComputeClusterMembership(const vector<int>& centers,
+  void ComputeClusterMembership(const std::vector<int>& centers,
                                 IntMap* membership) const;
 
   CanonicalViewsClusteringOptions options_;
@@ -83,20 +80,20 @@
 void ComputeCanonicalViewsClustering(
     const CanonicalViewsClusteringOptions& options,
     const WeightedGraph<int>& graph,
-    vector<int>* centers,
+    std::vector<int>* centers,
     IntMap* membership) {
-  time_t start_time = time(NULL);
+  time_t start_time = time(nullptr);
   CanonicalViewsClustering cv;
   cv.ComputeClustering(options, graph, centers, membership);
   VLOG(2) << "Canonical views clustering time (secs): "
-          << time(NULL) - start_time;
+          << time(nullptr) - start_time;
 }
 
 // Implementation of CanonicalViewsClustering
 void CanonicalViewsClustering::ComputeClustering(
     const CanonicalViewsClusteringOptions& options,
     const WeightedGraph<int>& graph,
-    vector<int>* centers,
+    std::vector<int>* centers,
     IntMap* membership) {
   options_ = options;
   CHECK(centers != nullptr);
@@ -107,7 +104,7 @@
 
   IntSet valid_views;
   FindValidViews(&valid_views);
-  while (valid_views.size() > 0) {
+  while (!valid_views.empty()) {
     // Find the next best canonical view.
     double best_difference = -std::numeric_limits<double>::max();
     int best_view = 0;
@@ -152,7 +149,7 @@
 // Computes the difference in the quality score if 'candidate' were
 // added to the set of canonical views.
 double CanonicalViewsClustering::ComputeClusteringQualityDifference(
-    const int candidate, const vector<int>& centers) const {
+    const int candidate, const std::vector<int>& centers) const {
   // View score.
   double difference =
       options_.view_score_weight * graph_->VertexWeight(candidate);
@@ -174,9 +171,9 @@
   difference -= options_.size_penalty_weight;
 
   // Orthogonality.
-  for (int i = 0; i < centers.size(); ++i) {
+  for (int center : centers) {
     difference -= options_.similarity_penalty_weight *
-                  graph_->EdgeWeight(centers[i], candidate);
+                  graph_->EdgeWeight(center, candidate);
   }
 
   return difference;
@@ -199,7 +196,7 @@
 
 // Assign a cluster id to each view.
 void CanonicalViewsClustering::ComputeClusterMembership(
-    const vector<int>& centers, IntMap* membership) const {
+    const std::vector<int>& centers, IntMap* membership) const {
   CHECK(membership != nullptr);
   membership->clear();
 
@@ -223,5 +220,4 @@
   }
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/canonical_views_clustering.h b/third_party/ceres/internal/ceres/canonical_views_clustering.h
index 465233d..eb05a91 100644
--- a/third_party/ceres/internal/ceres/canonical_views_clustering.h
+++ b/third_party/ceres/internal/ceres/canonical_views_clustering.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -45,10 +45,10 @@
 #include <vector>
 
 #include "ceres/graph.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 struct CanonicalViewsClusteringOptions;
 
@@ -95,13 +95,13 @@
 // It is possible depending on the configuration of the clustering
 // algorithm that some of the vertices may not be assigned to any
 // cluster. In this case they are assigned to a cluster with id = -1;
-CERES_EXPORT_INTERNAL void ComputeCanonicalViewsClustering(
+CERES_NO_EXPORT void ComputeCanonicalViewsClustering(
     const CanonicalViewsClusteringOptions& options,
     const WeightedGraph<int>& graph,
     std::vector<int>* centers,
     std::unordered_map<int, int>* membership);
 
-struct CERES_EXPORT_INTERNAL CanonicalViewsClusteringOptions {
+struct CERES_NO_EXPORT CanonicalViewsClusteringOptions {
   // The minimum number of canonical views to compute.
   int min_views = 3;
 
@@ -119,7 +119,8 @@
   double view_score_weight = 0.0;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_CANONICAL_VIEWS_CLUSTERING_H_
diff --git a/third_party/ceres/internal/ceres/canonical_views_clustering_test.cc b/third_party/ceres/internal/ceres/canonical_views_clustering_test.cc
index 0593d65..fa79582 100644
--- a/third_party/ceres/internal/ceres/canonical_views_clustering_test.cc
+++ b/third_party/ceres/internal/ceres/canonical_views_clustering_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -36,8 +36,7 @@
 #include "ceres/graph.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 const int kVertexIds[] = {0, 1, 2, 3};
 class CanonicalViewsTest : public ::testing::Test {
@@ -139,5 +138,4 @@
   EXPECT_EQ(centers_[0], kVertexIds[1]);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/casts.h b/third_party/ceres/internal/ceres/casts.h
index d137071..af944520 100644
--- a/third_party/ceres/internal/ceres/casts.h
+++ b/third_party/ceres/internal/ceres/casts.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -32,14 +32,13 @@
 #define CERES_INTERNAL_CASTS_H_
 
 #include <cassert>
-#include <cstddef>  // For NULL.
 
 namespace ceres {
 
 // Identity metafunction.
 template <class T>
 struct identity_ {
-  typedef T type;
+  using type = T;
 };
 
 // Use implicit_cast as a safe version of static_cast or const_cast
@@ -86,6 +85,7 @@
 //    if (dynamic_cast<Subclass2>(foo)) HandleASubclass2Object(foo);
 // You should design the code some other way not to need this.
 
+// TODO(sameeragarwal): Modernize this.
 template <typename To, typename From>  // use like this: down_cast<T*>(foo);
 inline To down_cast(From* f) {         // so we only accept pointers
   // Ensures that To is a sub-type of From *.  This test is here only
@@ -95,11 +95,11 @@
 
   // TODO(csilvers): This should use COMPILE_ASSERT.
   if (false) {
-    implicit_cast<From*, To>(NULL);
+    implicit_cast<From*, To>(nullptr);
   }
 
   // uses RTTI in dbg and fastbuild. asserts are disabled in opt builds.
-  assert(f == NULL || dynamic_cast<To>(f) != NULL);  // NOLINT
+  assert(f == nullptr || dynamic_cast<To>(f) != nullptr);  // NOLINT
   return static_cast<To>(f);
 }
 
diff --git a/third_party/ceres/internal/ceres/cgnr_linear_operator.h b/third_party/ceres/internal/ceres/cgnr_linear_operator.h
deleted file mode 100644
index beb8bbc..0000000
--- a/third_party/ceres/internal/ceres/cgnr_linear_operator.h
+++ /dev/null
@@ -1,120 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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 Google Inc. 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.
-//
-// Author: keir@google.com (Keir Mierle)
-
-#ifndef CERES_INTERNAL_CGNR_LINEAR_OPERATOR_H_
-#define CERES_INTERNAL_CGNR_LINEAR_OPERATOR_H_
-
-#include <algorithm>
-#include <memory>
-
-#include "ceres/internal/eigen.h"
-#include "ceres/linear_operator.h"
-
-namespace ceres {
-namespace internal {
-
-class SparseMatrix;
-
-// A linear operator which takes a matrix A and a diagonal vector D and
-// performs products of the form
-//
-//   (A^T A + D^T D)x
-//
-// This is used to implement iterative general sparse linear solving with
-// conjugate gradients, where A is the Jacobian and D is a regularizing
-// parameter. A brief proof that D^T D is the correct regularizer:
-//
-// Given a regularized least squares problem:
-//
-//   min  ||Ax - b||^2 + ||Dx||^2
-//    x
-//
-// First expand into matrix notation:
-//
-//   (Ax - b)^T (Ax - b) + xD^TDx
-//
-// Then multiply out to get:
-//
-//   = xA^TAx - 2b^T Ax + b^Tb + xD^TDx
-//
-// Take the derivative:
-//
-//   0 = 2A^TAx - 2A^T b + 2 D^TDx
-//   0 = A^TAx - A^T b + D^TDx
-//   0 = (A^TA + D^TD)x - A^T b
-//
-// Thus, the symmetric system we need to solve for CGNR is
-//
-//   Sx = z
-//
-// with S = A^TA + D^TD
-//  and z = A^T b
-//
-// Note: This class is not thread safe, since it uses some temporary storage.
-class CgnrLinearOperator : public LinearOperator {
- public:
-  CgnrLinearOperator(const LinearOperator& A, const double* D)
-      : A_(A), D_(D), z_(new double[A.num_rows()]) {}
-  virtual ~CgnrLinearOperator() {}
-
-  void RightMultiply(const double* x, double* y) const final {
-    std::fill(z_.get(), z_.get() + A_.num_rows(), 0.0);
-
-    // z = Ax
-    A_.RightMultiply(x, z_.get());
-
-    // y = y + Atz
-    A_.LeftMultiply(z_.get(), y);
-
-    // y = y + DtDx
-    if (D_ != NULL) {
-      int n = A_.num_cols();
-      VectorRef(y, n).array() +=
-          ConstVectorRef(D_, n).array().square() * ConstVectorRef(x, n).array();
-    }
-  }
-
-  void LeftMultiply(const double* x, double* y) const final {
-    RightMultiply(x, y);
-  }
-
-  int num_rows() const final { return A_.num_cols(); }
-  int num_cols() const final { return A_.num_cols(); }
-
- private:
-  const LinearOperator& A_;
-  const double* D_;
-  std::unique_ptr<double[]> z_;
-};
-
-}  // namespace internal
-}  // namespace ceres
-
-#endif  // CERES_INTERNAL_CGNR_LINEAR_OPERATOR_H_
diff --git a/third_party/ceres/internal/ceres/cgnr_solver.cc b/third_party/ceres/internal/ceres/cgnr_solver.cc
index 9dba1cf..da63484 100644
--- a/third_party/ceres/internal/ceres/cgnr_solver.cc
+++ b/third_party/ceres/internal/ceres/cgnr_solver.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -30,20 +30,99 @@
 
 #include "ceres/cgnr_solver.h"
 
+#include <memory>
+#include <utility>
+
 #include "ceres/block_jacobi_preconditioner.h"
-#include "ceres/cgnr_linear_operator.h"
 #include "ceres/conjugate_gradients_solver.h"
+#include "ceres/cuda_sparse_matrix.h"
+#include "ceres/cuda_vector.h"
 #include "ceres/internal/eigen.h"
 #include "ceres/linear_solver.h"
 #include "ceres/subset_preconditioner.h"
 #include "ceres/wall_time.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
-CgnrSolver::CgnrSolver(const LinearSolver::Options& options)
-    : options_(options) {
+// A linear operator which takes a matrix A and a diagonal vector D and
+// performs products of the form
+//
+//   (A^T A + D^T D)x
+//
+// This is used to implement iterative general sparse linear solving with
+// conjugate gradients, where A is the Jacobian and D is a regularizing
+// parameter. A brief proof that D^T D is the correct regularizer:
+//
+// Given a regularized least squares problem:
+//
+//   min  ||Ax - b||^2 + ||Dx||^2
+//    x
+//
+// First expand into matrix notation:
+//
+//   (Ax - b)^T (Ax - b) + xD^TDx
+//
+// Then multiply out to get:
+//
+//   = xA^TAx - 2b^T Ax + b^Tb + xD^TDx
+//
+// Take the derivative:
+//
+//   0 = 2A^TAx - 2A^T b + 2 D^TDx
+//   0 = A^TAx - A^T b + D^TDx
+//   0 = (A^TA + D^TD)x - A^T b
+//
+// Thus, the symmetric system we need to solve for CGNR is
+//
+//   Sx = z
+//
+// with S = A^TA + D^TD
+//  and z = A^T b
+//
+// Note: This class is not thread safe, since it uses some temporary storage.
+class CERES_NO_EXPORT CgnrLinearOperator final
+    : public ConjugateGradientsLinearOperator<Vector> {
+ public:
+  CgnrLinearOperator(const LinearOperator& A,
+                     const double* D,
+                     ContextImpl* context,
+                     int num_threads)
+      : A_(A),
+        D_(D),
+        z_(Vector::Zero(A.num_rows())),
+        context_(context),
+        num_threads_(num_threads) {}
+
+  void RightMultiplyAndAccumulate(const Vector& x, Vector& y) final {
+    // z = Ax
+    // y = y + Atz
+    z_.setZero();
+    A_.RightMultiplyAndAccumulate(x, z_, context_, num_threads_);
+    A_.LeftMultiplyAndAccumulate(z_, y, context_, num_threads_);
+
+    // y = y + DtDx
+    if (D_ != nullptr) {
+      int n = A_.num_cols();
+      ParallelAssign(
+          context_,
+          num_threads_,
+          y,
+          y.array() + ConstVectorRef(D_, n).array().square() * x.array());
+    }
+  }
+
+ private:
+  const LinearOperator& A_;
+  const double* D_;
+  Vector z_;
+
+  ContextImpl* context_;
+  int num_threads_;
+};
+
+CgnrSolver::CgnrSolver(LinearSolver::Options options)
+    : options_(std::move(options)) {
   if (options_.preconditioner_type != JACOBI &&
       options_.preconditioner_type != IDENTITY &&
       options_.preconditioner_type != SUBSET) {
@@ -54,7 +133,14 @@
   }
 }
 
-CgnrSolver::~CgnrSolver() {}
+CgnrSolver::~CgnrSolver() {
+  for (int i = 0; i < 4; ++i) {
+    if (scratch_[i]) {
+      delete scratch_[i];
+      scratch_[i] = nullptr;
+    }
+  }
+}
 
 LinearSolver::Summary CgnrSolver::SolveImpl(
     BlockSparseMatrix* A,
@@ -62,48 +148,244 @@
     const LinearSolver::PerSolveOptions& per_solve_options,
     double* x) {
   EventLogger event_logger("CgnrSolver::Solve");
-
-  // Form z = Atb.
-  Vector z(A->num_cols());
-  z.setZero();
-  A->LeftMultiply(b, z.data());
-
   if (!preconditioner_) {
+    Preconditioner::Options preconditioner_options;
+    preconditioner_options.type = options_.preconditioner_type;
+    preconditioner_options.subset_preconditioner_start_row_block =
+        options_.subset_preconditioner_start_row_block;
+    preconditioner_options.sparse_linear_algebra_library_type =
+        options_.sparse_linear_algebra_library_type;
+    preconditioner_options.ordering_type = options_.ordering_type;
+    preconditioner_options.num_threads = options_.num_threads;
+    preconditioner_options.context = options_.context;
+
     if (options_.preconditioner_type == JACOBI) {
-      preconditioner_.reset(new BlockJacobiPreconditioner(*A));
+      preconditioner_ = std::make_unique<BlockSparseJacobiPreconditioner>(
+          preconditioner_options, *A);
     } else if (options_.preconditioner_type == SUBSET) {
-      Preconditioner::Options preconditioner_options;
-      preconditioner_options.type = SUBSET;
-      preconditioner_options.subset_preconditioner_start_row_block =
-          options_.subset_preconditioner_start_row_block;
-      preconditioner_options.sparse_linear_algebra_library_type =
-          options_.sparse_linear_algebra_library_type;
-      preconditioner_options.use_postordering = options_.use_postordering;
-      preconditioner_options.num_threads = options_.num_threads;
-      preconditioner_options.context = options_.context;
-      preconditioner_.reset(
-          new SubsetPreconditioner(preconditioner_options, *A));
+      preconditioner_ =
+          std::make_unique<SubsetPreconditioner>(preconditioner_options, *A);
+    } else {
+      preconditioner_ = std::make_unique<IdentityPreconditioner>(A->num_cols());
     }
   }
+  preconditioner_->Update(*A, per_solve_options.D);
 
-  if (preconditioner_) {
-    preconditioner_->Update(*A, per_solve_options.D);
+  ConjugateGradientsSolverOptions cg_options;
+  cg_options.min_num_iterations = options_.min_num_iterations;
+  cg_options.max_num_iterations = options_.max_num_iterations;
+  cg_options.residual_reset_period = options_.residual_reset_period;
+  cg_options.q_tolerance = per_solve_options.q_tolerance;
+  cg_options.r_tolerance = per_solve_options.r_tolerance;
+  cg_options.context = options_.context;
+  cg_options.num_threads = options_.num_threads;
+
+  // lhs = AtA + DtD
+  CgnrLinearOperator lhs(
+      *A, per_solve_options.D, options_.context, options_.num_threads);
+  // rhs = Atb.
+  Vector rhs(A->num_cols());
+  rhs.setZero();
+  A->LeftMultiplyAndAccumulate(
+      b, rhs.data(), options_.context, options_.num_threads);
+
+  cg_solution_ = Vector::Zero(A->num_cols());
+  for (int i = 0; i < 4; ++i) {
+    if (scratch_[i] == nullptr) {
+      scratch_[i] = new Vector(A->num_cols());
+    }
   }
-
-  LinearSolver::PerSolveOptions cg_per_solve_options = per_solve_options;
-  cg_per_solve_options.preconditioner = preconditioner_.get();
-
-  // Solve (AtA + DtD)x = z (= Atb).
-  VectorRef(x, A->num_cols()).setZero();
-  CgnrLinearOperator lhs(*A, per_solve_options.D);
   event_logger.AddEvent("Setup");
 
-  ConjugateGradientsSolver conjugate_gradient_solver(options_);
-  LinearSolver::Summary summary =
-      conjugate_gradient_solver.Solve(&lhs, z.data(), cg_per_solve_options, x);
+  LinearOperatorAdapter preconditioner(*preconditioner_);
+  auto summary = ConjugateGradientsSolver(
+      cg_options, lhs, rhs, preconditioner, scratch_, cg_solution_);
+  VectorRef(x, A->num_cols()) = cg_solution_;
   event_logger.AddEvent("Solve");
   return summary;
 }
 
-}  // namespace internal
-}  // namespace ceres
+#ifndef CERES_NO_CUDA
+
+// A linear operator which takes a matrix A and a diagonal vector D and
+// performs products of the form
+//
+//   (A^T A + D^T D)x
+//
+// This is used to implement iterative general sparse linear solving with
+// conjugate gradients, where A is the Jacobian and D is a regularizing
+// parameter. A brief proof is included in cgnr_linear_operator.h.
+class CERES_NO_EXPORT CudaCgnrLinearOperator final
+    : public ConjugateGradientsLinearOperator<CudaVector> {
+ public:
+  CudaCgnrLinearOperator(CudaSparseMatrix& A,
+                         const CudaVector& D,
+                         CudaVector* z)
+      : A_(A), D_(D), z_(z) {}
+
+  void RightMultiplyAndAccumulate(const CudaVector& x, CudaVector& y) final {
+    // z = Ax
+    z_->SetZero();
+    A_.RightMultiplyAndAccumulate(x, z_);
+
+    // y = y + Atz
+    //   = y + AtAx
+    A_.LeftMultiplyAndAccumulate(*z_, &y);
+
+    // y = y + DtDx
+    y.DtDxpy(D_, x);
+  }
+
+ private:
+  CudaSparseMatrix& A_;
+  const CudaVector& D_;
+  CudaVector* z_ = nullptr;
+};
+
+class CERES_NO_EXPORT CudaIdentityPreconditioner final
+    : public CudaPreconditioner {
+ public:
+  void Update(const CompressedRowSparseMatrix& A, const double* D) final {}
+  void RightMultiplyAndAccumulate(const CudaVector& x, CudaVector& y) final {
+    y.Axpby(1.0, x, 1.0);
+  }
+};
+
+// This class wraps the existing CPU Jacobi preconditioner, caches the structure
+// of the block diagonal, and for each CGNR solve updates the values on the CPU
+// and then copies them over to the GPU.
+class CERES_NO_EXPORT CudaJacobiPreconditioner final
+    : public CudaPreconditioner {
+ public:
+  explicit CudaJacobiPreconditioner(Preconditioner::Options options,
+                                    const CompressedRowSparseMatrix& A)
+      : options_(std::move(options)),
+        cpu_preconditioner_(options_, A),
+        m_(options_.context, cpu_preconditioner_.matrix()) {}
+  ~CudaJacobiPreconditioner() = default;
+
+  void Update(const CompressedRowSparseMatrix& A, const double* D) final {
+    cpu_preconditioner_.Update(A, D);
+    m_.CopyValuesFromCpu(cpu_preconditioner_.matrix());
+  }
+
+  void RightMultiplyAndAccumulate(const CudaVector& x, CudaVector& y) final {
+    m_.RightMultiplyAndAccumulate(x, &y);
+  }
+
+ private:
+  Preconditioner::Options options_;
+  BlockCRSJacobiPreconditioner cpu_preconditioner_;
+  CudaSparseMatrix m_;
+};
+
+CudaCgnrSolver::CudaCgnrSolver(LinearSolver::Options options)
+    : options_(std::move(options)) {}
+
+CudaCgnrSolver::~CudaCgnrSolver() {
+  for (int i = 0; i < 4; ++i) {
+    if (scratch_[i]) {
+      delete scratch_[i];
+      scratch_[i] = nullptr;
+    }
+  }
+}
+
+std::unique_ptr<CudaCgnrSolver> CudaCgnrSolver::Create(
+    LinearSolver::Options options, std::string* error) {
+  CHECK(error != nullptr);
+  if (options.preconditioner_type != IDENTITY &&
+      options.preconditioner_type != JACOBI) {
+    *error =
+        "CudaCgnrSolver does not support preconditioner type " +
+        std::string(PreconditionerTypeToString(options.preconditioner_type)) +
+        ". ";
+    return nullptr;
+  }
+  CHECK(options.context->IsCudaInitialized())
+      << "CudaCgnrSolver requires CUDA initialization.";
+  auto solver = std::make_unique<CudaCgnrSolver>(options);
+  return solver;
+}
+
+void CudaCgnrSolver::CpuToGpuTransfer(const CompressedRowSparseMatrix& A,
+                                      const double* b,
+                                      const double* D) {
+  if (A_ == nullptr) {
+    // Assume structure is not cached, do an initialization and structural copy.
+    A_ = std::make_unique<CudaSparseMatrix>(options_.context, A);
+    b_ = std::make_unique<CudaVector>(options_.context, A.num_rows());
+    x_ = std::make_unique<CudaVector>(options_.context, A.num_cols());
+    Atb_ = std::make_unique<CudaVector>(options_.context, A.num_cols());
+    Ax_ = std::make_unique<CudaVector>(options_.context, A.num_rows());
+    D_ = std::make_unique<CudaVector>(options_.context, A.num_cols());
+
+    Preconditioner::Options preconditioner_options;
+    preconditioner_options.type = options_.preconditioner_type;
+    preconditioner_options.subset_preconditioner_start_row_block =
+        options_.subset_preconditioner_start_row_block;
+    preconditioner_options.sparse_linear_algebra_library_type =
+        options_.sparse_linear_algebra_library_type;
+    preconditioner_options.ordering_type = options_.ordering_type;
+    preconditioner_options.num_threads = options_.num_threads;
+    preconditioner_options.context = options_.context;
+
+    if (options_.preconditioner_type == JACOBI) {
+      preconditioner_ =
+          std::make_unique<CudaJacobiPreconditioner>(preconditioner_options, A);
+    } else {
+      preconditioner_ = std::make_unique<CudaIdentityPreconditioner>();
+    }
+    for (int i = 0; i < 4; ++i) {
+      scratch_[i] = new CudaVector(options_.context, A.num_cols());
+    }
+  } else {
+    // Assume structure is cached, do a value copy.
+    A_->CopyValuesFromCpu(A);
+  }
+  b_->CopyFromCpu(ConstVectorRef(b, A.num_rows()));
+  D_->CopyFromCpu(ConstVectorRef(D, A.num_cols()));
+}
+
+LinearSolver::Summary CudaCgnrSolver::SolveImpl(
+    CompressedRowSparseMatrix* A,
+    const double* b,
+    const LinearSolver::PerSolveOptions& per_solve_options,
+    double* x) {
+  EventLogger event_logger("CudaCgnrSolver::Solve");
+  LinearSolver::Summary summary;
+  summary.num_iterations = 0;
+  summary.termination_type = LinearSolverTerminationType::FATAL_ERROR;
+
+  CpuToGpuTransfer(*A, b, per_solve_options.D);
+  event_logger.AddEvent("CPU to GPU Transfer");
+  preconditioner_->Update(*A, per_solve_options.D);
+  event_logger.AddEvent("Preconditioner Update");
+
+  // Form z = Atb.
+  Atb_->SetZero();
+  A_->LeftMultiplyAndAccumulate(*b_, Atb_.get());
+
+  // Solve (AtA + DtD)x = z (= Atb).
+  x_->SetZero();
+  CudaCgnrLinearOperator lhs(*A_, *D_, Ax_.get());
+
+  event_logger.AddEvent("Setup");
+
+  ConjugateGradientsSolverOptions cg_options;
+  cg_options.min_num_iterations = options_.min_num_iterations;
+  cg_options.max_num_iterations = options_.max_num_iterations;
+  cg_options.residual_reset_period = options_.residual_reset_period;
+  cg_options.q_tolerance = per_solve_options.q_tolerance;
+  cg_options.r_tolerance = per_solve_options.r_tolerance;
+
+  summary = ConjugateGradientsSolver(
+      cg_options, lhs, *Atb_, *preconditioner_, scratch_, *x_);
+  x_->CopyTo(x);
+  event_logger.AddEvent("Solve");
+  return summary;
+}
+
+#endif  // CERES_NO_CUDA
+
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/cgnr_solver.h b/third_party/ceres/internal/ceres/cgnr_solver.h
index bc701c0..c634538 100644
--- a/third_party/ceres/internal/ceres/cgnr_solver.h
+++ b/third_party/ceres/internal/ceres/cgnr_solver.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -33,10 +33,13 @@
 
 #include <memory>
 
+#include "ceres/conjugate_gradients_solver.h"
+#include "ceres/cuda_sparse_matrix.h"
+#include "ceres/cuda_vector.h"
+#include "ceres/internal/export.h"
 #include "ceres/linear_solver.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 class Preconditioner;
 
@@ -49,12 +52,12 @@
 //
 // as required for solving for x in the least squares sense. Currently only
 // block diagonal preconditioning is supported.
-class CgnrSolver : public BlockSparseMatrixSolver {
+class CERES_NO_EXPORT CgnrSolver final : public BlockSparseMatrixSolver {
  public:
-  explicit CgnrSolver(const LinearSolver::Options& options);
+  explicit CgnrSolver(LinearSolver::Options options);
   CgnrSolver(const CgnrSolver&) = delete;
   void operator=(const CgnrSolver&) = delete;
-  virtual ~CgnrSolver();
+  ~CgnrSolver() override;
 
   Summary SolveImpl(BlockSparseMatrix* A,
                     const double* b,
@@ -64,9 +67,50 @@
  private:
   const LinearSolver::Options options_;
   std::unique_ptr<Preconditioner> preconditioner_;
+  Vector cg_solution_;
+  Vector* scratch_[4] = {nullptr, nullptr, nullptr, nullptr};
 };
 
-}  // namespace internal
-}  // namespace ceres
+#ifndef CERES_NO_CUDA
+class CudaPreconditioner : public ConjugateGradientsLinearOperator<CudaVector> {
+ public:
+  virtual void Update(const CompressedRowSparseMatrix& A, const double* D) = 0;
+  virtual ~CudaPreconditioner() = default;
+};
+
+// A Cuda-accelerated version of CgnrSolver.
+// This solver assumes that the sparsity structure of A remains constant for its
+// lifetime.
+class CERES_NO_EXPORT CudaCgnrSolver final
+    : public CompressedRowSparseMatrixSolver {
+ public:
+  explicit CudaCgnrSolver(LinearSolver::Options options);
+  static std::unique_ptr<CudaCgnrSolver> Create(LinearSolver::Options options,
+                                                std::string* error);
+  ~CudaCgnrSolver() override;
+
+  Summary SolveImpl(CompressedRowSparseMatrix* A,
+                    const double* b,
+                    const LinearSolver::PerSolveOptions& per_solve_options,
+                    double* x) final;
+
+ private:
+  void CpuToGpuTransfer(const CompressedRowSparseMatrix& A,
+                        const double* b,
+                        const double* D);
+
+  LinearSolver::Options options_;
+  std::unique_ptr<CudaSparseMatrix> A_;
+  std::unique_ptr<CudaVector> b_;
+  std::unique_ptr<CudaVector> x_;
+  std::unique_ptr<CudaVector> Atb_;
+  std::unique_ptr<CudaVector> Ax_;
+  std::unique_ptr<CudaVector> D_;
+  std::unique_ptr<CudaPreconditioner> preconditioner_;
+  CudaVector* scratch_[4] = {nullptr, nullptr, nullptr, nullptr};
+};
+#endif  // CERES_NO_CUDA
+
+}  // namespace ceres::internal
 
 #endif  // CERES_INTERNAL_CGNR_SOLVER_H_
diff --git a/third_party/ceres/internal/ceres/compressed_col_sparse_matrix_utils.cc b/third_party/ceres/internal/ceres/compressed_col_sparse_matrix_utils.cc
index e1f6bb8..5a25e31 100644
--- a/third_party/ceres/internal/ceres/compressed_col_sparse_matrix_utils.cc
+++ b/third_party/ceres/internal/ceres/compressed_col_sparse_matrix_utils.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -33,33 +33,24 @@
 #include <algorithm>
 #include <vector>
 
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
-using std::vector;
-
-void CompressedColumnScalarMatrixToBlockMatrix(const int* scalar_rows,
-                                               const int* scalar_cols,
-                                               const vector<int>& row_blocks,
-                                               const vector<int>& col_blocks,
-                                               vector<int>* block_rows,
-                                               vector<int>* block_cols) {
+void CompressedColumnScalarMatrixToBlockMatrix(
+    const int* scalar_rows,
+    const int* scalar_cols,
+    const std::vector<Block>& row_blocks,
+    const std::vector<Block>& col_blocks,
+    std::vector<int>* block_rows,
+    std::vector<int>* block_cols) {
   CHECK(block_rows != nullptr);
   CHECK(block_cols != nullptr);
   block_rows->clear();
   block_cols->clear();
-  const int num_row_blocks = row_blocks.size();
   const int num_col_blocks = col_blocks.size();
 
-  vector<int> row_block_starts(num_row_blocks);
-  for (int i = 0, cursor = 0; i < num_row_blocks; ++i) {
-    row_block_starts[i] = cursor;
-    cursor += row_blocks[i];
-  }
-
   // This loop extracts the block sparsity of the scalar sparse matrix
   // It does so by iterating over the columns, but only considering
   // the columns corresponding to the first element of each column
@@ -71,52 +62,46 @@
   for (int col_block = 0; col_block < num_col_blocks; ++col_block) {
     int column_size = 0;
     for (int idx = scalar_cols[c]; idx < scalar_cols[c + 1]; ++idx) {
-      vector<int>::const_iterator it = std::lower_bound(
-          row_block_starts.begin(), row_block_starts.end(), scalar_rows[idx]);
-      // Since we are using lower_bound, it will return the row id
-      // where the row block starts. For everything but the first row
-      // of the block, where these values will be the same, we can
-      // skip, as we only need the first row to detect the presence of
-      // the block.
+      auto it = std::lower_bound(row_blocks.begin(),
+                                 row_blocks.end(),
+                                 scalar_rows[idx],
+                                 [](const Block& block, double value) {
+                                   return block.position < value;
+                                 });
+      // Since we are using lower_bound, it will return the row id where the row
+      // block starts. For everything but the first row of the block, where
+      // these values will be the same, we can skip, as we only need the first
+      // row to detect the presence of the block.
       //
-      // For rows all but the first row in the last row block,
-      // lower_bound will return row_block_starts.end(), but those can
-      // be skipped like the rows in other row blocks too.
-      if (it == row_block_starts.end() || *it != scalar_rows[idx]) {
+      // For rows all but the first row in the last row block, lower_bound will
+      // return row_blocks_.end(), but those can be skipped like the rows in
+      // other row blocks too.
+      if (it == row_blocks.end() || it->position != scalar_rows[idx]) {
         continue;
       }
 
-      block_rows->push_back(it - row_block_starts.begin());
+      block_rows->push_back(it - row_blocks.begin());
       ++column_size;
     }
     block_cols->push_back(block_cols->back() + column_size);
-    c += col_blocks[col_block];
+    c += col_blocks[col_block].size;
   }
 }
 
-void BlockOrderingToScalarOrdering(const vector<int>& blocks,
-                                   const vector<int>& block_ordering,
-                                   vector<int>* scalar_ordering) {
+void BlockOrderingToScalarOrdering(const std::vector<Block>& blocks,
+                                   const std::vector<int>& block_ordering,
+                                   std::vector<int>* scalar_ordering) {
   CHECK_EQ(blocks.size(), block_ordering.size());
   const int num_blocks = blocks.size();
-
-  // block_starts = [0, block1, block1 + block2 ..]
-  vector<int> block_starts(num_blocks);
-  for (int i = 0, cursor = 0; i < num_blocks; ++i) {
-    block_starts[i] = cursor;
-    cursor += blocks[i];
-  }
-
-  scalar_ordering->resize(block_starts.back() + blocks.back());
+  scalar_ordering->resize(NumScalarEntries(blocks));
   int cursor = 0;
   for (int i = 0; i < num_blocks; ++i) {
     const int block_id = block_ordering[i];
-    const int block_size = blocks[block_id];
-    int block_position = block_starts[block_id];
+    const int block_size = blocks[block_id].size;
+    int block_position = blocks[block_id].position;
     for (int j = 0; j < block_size; ++j) {
       (*scalar_ordering)[cursor++] = block_position++;
     }
   }
 }
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/compressed_col_sparse_matrix_utils.h b/third_party/ceres/internal/ceres/compressed_col_sparse_matrix_utils.h
index d442e1a..e9e067f 100644
--- a/third_party/ceres/internal/ceres/compressed_col_sparse_matrix_utils.h
+++ b/third_party/ceres/internal/ceres/compressed_col_sparse_matrix_utils.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -31,12 +31,14 @@
 #ifndef CERES_INTERNAL_COMPRESSED_COL_SPARSE_MATRIX_UTILS_H_
 #define CERES_INTERNAL_COMPRESSED_COL_SPARSE_MATRIX_UTILS_H_
 
+#include <algorithm>
 #include <vector>
 
-#include "ceres/internal/port.h"
+#include "ceres/block_structure.h"
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // Extract the block sparsity pattern of the scalar compressed columns
 // matrix and return it in compressed column form. The compressed
@@ -48,19 +50,19 @@
 // and column block j, then it is expected that A contains at least
 // one non-zero entry corresponding to the top left entry of c_ij,
 // as that entry is used to detect the presence of a non-zero c_ij.
-CERES_EXPORT_INTERNAL void CompressedColumnScalarMatrixToBlockMatrix(
+CERES_NO_EXPORT void CompressedColumnScalarMatrixToBlockMatrix(
     const int* scalar_rows,
     const int* scalar_cols,
-    const std::vector<int>& row_blocks,
-    const std::vector<int>& col_blocks,
+    const std::vector<Block>& row_blocks,
+    const std::vector<Block>& col_blocks,
     std::vector<int>* block_rows,
     std::vector<int>* block_cols);
 
 // Given a set of blocks and a permutation of these blocks, compute
 // the corresponding "scalar" ordering, where the scalar ordering of
 // size sum(blocks).
-CERES_EXPORT_INTERNAL void BlockOrderingToScalarOrdering(
-    const std::vector<int>& blocks,
+CERES_NO_EXPORT void BlockOrderingToScalarOrdering(
+    const std::vector<Block>& blocks,
     const std::vector<int>& block_ordering,
     std::vector<int>* scalar_ordering);
 
@@ -139,7 +141,8 @@
   SolveUpperTriangularInPlace(num_cols, rows, cols, values, solution);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_COMPRESSED_COL_SPARSE_MATRIX_UTILS_H_
diff --git a/third_party/ceres/internal/ceres/compressed_col_sparse_matrix_utils_test.cc b/third_party/ceres/internal/ceres/compressed_col_sparse_matrix_utils_test.cc
index 339c064..b1c8219 100644
--- a/third_party/ceres/internal/ceres/compressed_col_sparse_matrix_utils_test.cc
+++ b/third_party/ceres/internal/ceres/compressed_col_sparse_matrix_utils_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -32,53 +32,30 @@
 
 #include <algorithm>
 #include <numeric>
+#include <vector>
 
 #include "Eigen/SparseCore"
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 #include "ceres/triplet_sparse_matrix.h"
 #include "glog/logging.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
-
-using std::vector;
+namespace ceres::internal {
 
 TEST(_, BlockPermutationToScalarPermutation) {
-  vector<int> blocks;
   //  Block structure
   //  0  --1-  ---2---  ---3---  4
   // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
-  blocks.push_back(1);
-  blocks.push_back(2);
-  blocks.push_back(3);
-  blocks.push_back(3);
-  blocks.push_back(1);
-
+  std::vector<Block> blocks{{1, 0}, {2, 1}, {3, 3}, {3, 6}, {1, 9}};
   // Block ordering
   // [1, 0, 2, 4, 5]
-  vector<int> block_ordering;
-  block_ordering.push_back(1);
-  block_ordering.push_back(0);
-  block_ordering.push_back(2);
-  block_ordering.push_back(4);
-  block_ordering.push_back(3);
+  std::vector<int> block_ordering{{1, 0, 2, 4, 3}};
 
   // Expected ordering
   // [1, 2, 0, 3, 4, 5, 9, 6, 7, 8]
-  vector<int> expected_scalar_ordering;
-  expected_scalar_ordering.push_back(1);
-  expected_scalar_ordering.push_back(2);
-  expected_scalar_ordering.push_back(0);
-  expected_scalar_ordering.push_back(3);
-  expected_scalar_ordering.push_back(4);
-  expected_scalar_ordering.push_back(5);
-  expected_scalar_ordering.push_back(9);
-  expected_scalar_ordering.push_back(6);
-  expected_scalar_ordering.push_back(7);
-  expected_scalar_ordering.push_back(8);
+  std::vector<int> expected_scalar_ordering{{1, 2, 0, 3, 4, 5, 9, 6, 7, 8}};
 
-  vector<int> scalar_ordering;
+  std::vector<int> scalar_ordering;
   BlockOrderingToScalarOrdering(blocks, block_ordering, &scalar_ordering);
   EXPECT_EQ(scalar_ordering.size(), expected_scalar_ordering.size());
   for (int i = 0; i < expected_scalar_ordering.size(); ++i) {
@@ -86,19 +63,17 @@
   }
 }
 
-static void FillBlock(const vector<int>& row_blocks,
-                      const vector<int>& col_blocks,
+static void FillBlock(const std::vector<Block>& row_blocks,
+                      const std::vector<Block>& col_blocks,
                       const int row_block_id,
                       const int col_block_id,
-                      vector<Eigen::Triplet<double>>* triplets) {
-  const int row_offset =
-      std::accumulate(&row_blocks[0], &row_blocks[row_block_id], 0);
-  const int col_offset =
-      std::accumulate(&col_blocks[0], &col_blocks[col_block_id], 0);
-  for (int r = 0; r < row_blocks[row_block_id]; ++r) {
-    for (int c = 0; c < col_blocks[col_block_id]; ++c) {
+                      std::vector<Eigen::Triplet<double>>* triplets) {
+  for (int r = 0; r < row_blocks[row_block_id].size; ++r) {
+    for (int c = 0; c < col_blocks[col_block_id].size; ++c) {
       triplets->push_back(
-          Eigen::Triplet<double>(row_offset + r, col_offset + c, 1.0));
+          Eigen::Triplet<double>(row_blocks[row_block_id].position + r,
+                                 col_blocks[col_block_id].position + c,
+                                 1.0));
     }
   }
 }
@@ -112,23 +87,13 @@
   // [2]  x x
   // num_nonzeros = 1 + 3 + 4 + 4 + 1 + 2 = 15
 
-  vector<int> col_blocks;
-  col_blocks.push_back(1);
-  col_blocks.push_back(2);
-  col_blocks.push_back(3);
-  col_blocks.push_back(2);
+  std::vector<Block> col_blocks{{1, 0}, {2, 1}, {3, 3}, {2, 5}};
+  const int num_cols = NumScalarEntries(col_blocks);
 
-  vector<int> row_blocks;
-  row_blocks.push_back(1);
-  row_blocks.push_back(2);
-  row_blocks.push_back(2);
+  std::vector<Block> row_blocks{{1, 0}, {2, 1}, {2, 3}};
+  const int num_rows = NumScalarEntries(row_blocks);
 
-  const int num_rows =
-      std::accumulate(row_blocks.begin(), row_blocks.end(), 0.0);
-  const int num_cols =
-      std::accumulate(col_blocks.begin(), col_blocks.end(), 0.0);
-
-  vector<Eigen::Triplet<double>> triplets;
+  std::vector<Eigen::Triplet<double>> triplets;
   FillBlock(row_blocks, col_blocks, 0, 0, &triplets);
   FillBlock(row_blocks, col_blocks, 2, 0, &triplets);
   FillBlock(row_blocks, col_blocks, 1, 1, &triplets);
@@ -138,23 +103,11 @@
   Eigen::SparseMatrix<double> sparse_matrix(num_rows, num_cols);
   sparse_matrix.setFromTriplets(triplets.begin(), triplets.end());
 
-  vector<int> expected_compressed_block_rows;
-  expected_compressed_block_rows.push_back(0);
-  expected_compressed_block_rows.push_back(2);
-  expected_compressed_block_rows.push_back(1);
-  expected_compressed_block_rows.push_back(2);
-  expected_compressed_block_rows.push_back(0);
-  expected_compressed_block_rows.push_back(1);
+  const std::vector<int> expected_compressed_block_rows{{0, 2, 1, 2, 0, 1}};
+  const std::vector<int> expected_compressed_block_cols{{0, 2, 4, 5, 6}};
 
-  vector<int> expected_compressed_block_cols;
-  expected_compressed_block_cols.push_back(0);
-  expected_compressed_block_cols.push_back(2);
-  expected_compressed_block_cols.push_back(4);
-  expected_compressed_block_cols.push_back(5);
-  expected_compressed_block_cols.push_back(6);
-
-  vector<int> compressed_block_rows;
-  vector<int> compressed_block_cols;
+  std::vector<int> compressed_block_rows;
+  std::vector<int> compressed_block_cols;
   CompressedColumnScalarMatrixToBlockMatrix(sparse_matrix.innerIndexPtr(),
                                             sparse_matrix.outerIndexPtr(),
                                             row_blocks,
@@ -168,47 +121,26 @@
 
 class SolveUpperTriangularTest : public ::testing::Test {
  protected:
-  void SetUp() {
-    cols.resize(5);
-    rows.resize(7);
-    values.resize(7);
+  const std::vector<int>& cols() const { return cols_; }
+  const std::vector<int>& rows() const { return rows_; }
+  const std::vector<double>& values() const { return values_; }
 
-    cols[0] = 0;
-    rows[0] = 0;
-    values[0] = 0.50754;
-
-    cols[1] = 1;
-    rows[1] = 1;
-    values[1] = 0.80483;
-
-    cols[2] = 2;
-    rows[2] = 1;
-    values[2] = 0.14120;
-    rows[3] = 2;
-    values[3] = 0.3;
-
-    cols[3] = 4;
-    rows[4] = 0;
-    values[4] = 0.77696;
-    rows[5] = 1;
-    values[5] = 0.41860;
-    rows[6] = 3;
-    values[6] = 0.88979;
-
-    cols[4] = 7;
-  }
-
-  vector<int> cols;
-  vector<int> rows;
-  vector<double> values;
+ private:
+  const std::vector<int> cols_ = {0, 1, 2, 4, 7};
+  const std::vector<int> rows_ = {0, 1, 1, 2, 0, 1, 3};
+  const std::vector<double> values_ = {
+      0.50754, 0.80483, 0.14120, 0.3, 0.77696, 0.41860, 0.88979};
 };
 
 TEST_F(SolveUpperTriangularTest, SolveInPlace) {
   double rhs_and_solution[] = {1.0, 1.0, 2.0, 2.0};
   const double expected[] = {-1.4706, -1.0962, 6.6667, 2.2477};
 
-  SolveUpperTriangularInPlace<int>(
-      cols.size() - 1, &rows[0], &cols[0], &values[0], rhs_and_solution);
+  SolveUpperTriangularInPlace<int>(cols().size() - 1,
+                                   rows().data(),
+                                   cols().data(),
+                                   values().data(),
+                                   rhs_and_solution);
 
   for (int i = 0; i < 4; ++i) {
     EXPECT_NEAR(rhs_and_solution[i], expected[i], 1e-4) << i;
@@ -219,8 +151,11 @@
   double rhs_and_solution[] = {1.0, 1.0, 2.0, 2.0};
   double expected[] = {1.970288, 1.242498, 6.081864, -0.057255};
 
-  SolveUpperTriangularTransposeInPlace<int>(
-      cols.size() - 1, &rows[0], &cols[0], &values[0], rhs_and_solution);
+  SolveUpperTriangularTransposeInPlace<int>(cols().size() - 1,
+                                            rows().data(),
+                                            cols().data(),
+                                            values().data(),
+                                            rhs_and_solution);
 
   for (int i = 0; i < 4; ++i) {
     EXPECT_NEAR(rhs_and_solution[i], expected[i], 1e-4) << i;
@@ -237,13 +172,16 @@
   // clang-format on
 
   for (int i = 0; i < 4; ++i) {
-    SolveRTRWithSparseRHS<int>(
-        cols.size() - 1, &rows[0], &cols[0], &values[0], i, solution);
+    SolveRTRWithSparseRHS<int>(cols().size() - 1,
+                               rows().data(),
+                               cols().data(),
+                               values().data(),
+                               i,
+                               solution);
     for (int j = 0; j < 4; ++j) {
       EXPECT_NEAR(solution[j], expected[4 * i + j], 1e-3) << i;
     }
   }
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/compressed_row_jacobian_writer.cc b/third_party/ceres/internal/ceres/compressed_row_jacobian_writer.cc
index 8e7e3e7..007346d 100644
--- a/third_party/ceres/internal/ceres/compressed_row_jacobian_writer.cc
+++ b/third_party/ceres/internal/ceres/compressed_row_jacobian_writer.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -30,7 +30,10 @@
 
 #include "ceres/compressed_row_jacobian_writer.h"
 
+#include <algorithm>
 #include <iterator>
+#include <memory>
+#include <string>
 #include <utility>
 #include <vector>
 
@@ -41,65 +44,73 @@
 #include "ceres/residual_block.h"
 #include "ceres/scratch_evaluate_preparer.h"
 
-namespace ceres {
-namespace internal {
-
-using std::adjacent_find;
-using std::make_pair;
-using std::pair;
-using std::vector;
-
+namespace ceres::internal {
 void CompressedRowJacobianWriter::PopulateJacobianRowAndColumnBlockVectors(
     const Program* program, CompressedRowSparseMatrix* jacobian) {
-  const vector<ParameterBlock*>& parameter_blocks = program->parameter_blocks();
-  vector<int>& col_blocks = *(jacobian->mutable_col_blocks());
+  const auto& parameter_blocks = program->parameter_blocks();
+  auto& col_blocks = *(jacobian->mutable_col_blocks());
   col_blocks.resize(parameter_blocks.size());
+  int col_pos = 0;
   for (int i = 0; i < parameter_blocks.size(); ++i) {
-    col_blocks[i] = parameter_blocks[i]->LocalSize();
+    col_blocks[i].size = parameter_blocks[i]->TangentSize();
+    col_blocks[i].position = col_pos;
+    col_pos += col_blocks[i].size;
   }
 
-  const vector<ResidualBlock*>& residual_blocks = program->residual_blocks();
-  vector<int>& row_blocks = *(jacobian->mutable_row_blocks());
+  const auto& residual_blocks = program->residual_blocks();
+  auto& row_blocks = *(jacobian->mutable_row_blocks());
   row_blocks.resize(residual_blocks.size());
+  int row_pos = 0;
   for (int i = 0; i < residual_blocks.size(); ++i) {
-    row_blocks[i] = residual_blocks[i]->NumResiduals();
+    row_blocks[i].size = residual_blocks[i]->NumResiduals();
+    row_blocks[i].position = row_pos;
+    row_pos += row_blocks[i].size;
   }
 }
 
 void CompressedRowJacobianWriter::GetOrderedParameterBlocks(
     const Program* program,
     int residual_id,
-    vector<pair<int, int>>* evaluated_jacobian_blocks) {
-  const ResidualBlock* residual_block = program->residual_blocks()[residual_id];
+    std::vector<std::pair<int, int>>* evaluated_jacobian_blocks) {
+  auto residual_block = program->residual_blocks()[residual_id];
   const int num_parameter_blocks = residual_block->NumParameterBlocks();
 
   for (int j = 0; j < num_parameter_blocks; ++j) {
-    const ParameterBlock* parameter_block =
-        residual_block->parameter_blocks()[j];
+    auto parameter_block = residual_block->parameter_blocks()[j];
     if (!parameter_block->IsConstant()) {
       evaluated_jacobian_blocks->push_back(
-          make_pair(parameter_block->index(), j));
+          std::make_pair(parameter_block->index(), j));
     }
   }
-  sort(evaluated_jacobian_blocks->begin(), evaluated_jacobian_blocks->end());
+  std::sort(evaluated_jacobian_blocks->begin(),
+            evaluated_jacobian_blocks->end());
 }
 
-SparseMatrix* CompressedRowJacobianWriter::CreateJacobian() const {
-  const vector<ResidualBlock*>& residual_blocks = program_->residual_blocks();
+std::unique_ptr<SparseMatrix> CompressedRowJacobianWriter::CreateJacobian()
+    const {
+  const auto& residual_blocks = program_->residual_blocks();
 
-  int total_num_residuals = program_->NumResiduals();
-  int total_num_effective_parameters = program_->NumEffectiveParameters();
+  const int total_num_residuals = program_->NumResiduals();
+  const int total_num_effective_parameters = program_->NumEffectiveParameters();
 
   // Count the number of jacobian nonzeros.
-  int num_jacobian_nonzeros = 0;
-  for (int i = 0; i < residual_blocks.size(); ++i) {
-    ResidualBlock* residual_block = residual_blocks[i];
+  //
+  // We used an unsigned int here, so that we can compare it INT_MAX without
+  // triggering overflow behaviour.
+  unsigned int num_jacobian_nonzeros = total_num_effective_parameters;
+  for (auto* residual_block : residual_blocks) {
     const int num_residuals = residual_block->NumResiduals();
     const int num_parameter_blocks = residual_block->NumParameterBlocks();
     for (int j = 0; j < num_parameter_blocks; ++j) {
-      ParameterBlock* parameter_block = residual_block->parameter_blocks()[j];
+      auto parameter_block = residual_block->parameter_blocks()[j];
       if (!parameter_block->IsConstant()) {
-        num_jacobian_nonzeros += num_residuals * parameter_block->LocalSize();
+        num_jacobian_nonzeros += num_residuals * parameter_block->TangentSize();
+        if (num_jacobian_nonzeros > std::numeric_limits<int>::max()) {
+          LOG(ERROR) << "Unable to create Jacobian matrix: Too many entries in "
+                        "the Jacobian matrix. num_jacobian_nonzeros = "
+                     << num_jacobian_nonzeros;
+          return nullptr;
+        }
       }
     }
   }
@@ -108,41 +119,41 @@
   // Allocate more space than needed to store the jacobian so that when the LM
   // algorithm adds the diagonal, no reallocation is necessary. This reduces
   // peak memory usage significantly.
-  CompressedRowSparseMatrix* jacobian = new CompressedRowSparseMatrix(
+  auto jacobian = std::make_unique<CompressedRowSparseMatrix>(
       total_num_residuals,
       total_num_effective_parameters,
-      num_jacobian_nonzeros + total_num_effective_parameters);
+      static_cast<int>(num_jacobian_nonzeros));
 
-  // At this stage, the CompressedRowSparseMatrix is an invalid state. But this
-  // seems to be the only way to construct it without doing a memory copy.
+  // At this stage, the CompressedRowSparseMatrix is an invalid state. But
+  // this seems to be the only way to construct it without doing a memory
+  // copy.
   int* rows = jacobian->mutable_rows();
   int* cols = jacobian->mutable_cols();
 
   int row_pos = 0;
   rows[0] = 0;
-  for (int i = 0; i < residual_blocks.size(); ++i) {
-    const ResidualBlock* residual_block = residual_blocks[i];
+  for (auto* residual_block : residual_blocks) {
     const int num_parameter_blocks = residual_block->NumParameterBlocks();
 
     // Count the number of derivatives for a row of this residual block and
     // build a list of active parameter block indices.
     int num_derivatives = 0;
-    vector<int> parameter_indices;
+    std::vector<int> parameter_indices;
     for (int j = 0; j < num_parameter_blocks; ++j) {
-      ParameterBlock* parameter_block = residual_block->parameter_blocks()[j];
+      auto parameter_block = residual_block->parameter_blocks()[j];
       if (!parameter_block->IsConstant()) {
         parameter_indices.push_back(parameter_block->index());
-        num_derivatives += parameter_block->LocalSize();
+        num_derivatives += parameter_block->TangentSize();
       }
     }
 
     // Sort the parameters by their position in the state vector.
-    sort(parameter_indices.begin(), parameter_indices.end());
+    std::sort(parameter_indices.begin(), parameter_indices.end());
     if (adjacent_find(parameter_indices.begin(), parameter_indices.end()) !=
         parameter_indices.end()) {
       std::string parameter_block_description;
       for (int j = 0; j < num_parameter_blocks; ++j) {
-        ParameterBlock* parameter_block = residual_block->parameter_blocks()[j];
+        auto parameter_block = residual_block->parameter_blocks()[j];
         parameter_block_description += parameter_block->ToString() + "\n";
       }
       LOG(FATAL) << "Ceres internal error: "
@@ -163,16 +174,14 @@
     // parameter vector. This code mirrors that in Write(), where jacobian
     // values are updated.
     int col_pos = 0;
-    for (int j = 0; j < parameter_indices.size(); ++j) {
-      ParameterBlock* parameter_block =
-          program_->parameter_blocks()[parameter_indices[j]];
-      const int parameter_block_size = parameter_block->LocalSize();
+    for (int parameter_index : parameter_indices) {
+      auto parameter_block = program_->parameter_blocks()[parameter_index];
+      const int parameter_block_size = parameter_block->TangentSize();
 
       for (int r = 0; r < num_residuals; ++r) {
         // This is the position in the values array of the jacobian where this
         // row of the jacobian block should go.
         const int column_block_begin = rows[row_pos + r] + col_pos;
-
         for (int c = 0; c < parameter_block_size; ++c) {
           cols[column_block_begin + c] = parameter_block->delta_offset() + c;
         }
@@ -181,9 +190,10 @@
     }
     row_pos += num_residuals;
   }
-  CHECK_EQ(num_jacobian_nonzeros, rows[total_num_residuals]);
+  CHECK_EQ(num_jacobian_nonzeros - total_num_effective_parameters,
+           rows[total_num_residuals]);
 
-  PopulateJacobianRowAndColumnBlockVectors(program_, jacobian);
+  PopulateJacobianRowAndColumnBlockVectors(program_, jacobian.get());
 
   return jacobian;
 }
@@ -192,17 +202,15 @@
                                         int residual_offset,
                                         double** jacobians,
                                         SparseMatrix* base_jacobian) {
-  CompressedRowSparseMatrix* jacobian =
-      down_cast<CompressedRowSparseMatrix*>(base_jacobian);
+  auto* jacobian = down_cast<CompressedRowSparseMatrix*>(base_jacobian);
 
   double* jacobian_values = jacobian->mutable_values();
   const int* jacobian_rows = jacobian->rows();
 
-  const ResidualBlock* residual_block =
-      program_->residual_blocks()[residual_id];
+  auto residual_block = program_->residual_blocks()[residual_id];
   const int num_residuals = residual_block->NumResiduals();
 
-  vector<pair<int, int>> evaluated_jacobian_blocks;
+  std::vector<std::pair<int, int>> evaluated_jacobian_blocks;
   GetOrderedParameterBlocks(program_, residual_id, &evaluated_jacobian_blocks);
 
   // Where in the current row does the jacobian for a parameter block begin.
@@ -210,11 +218,11 @@
 
   // Iterate over the jacobian blocks in increasing order of their
   // positions in the reduced parameter vector.
-  for (int i = 0; i < evaluated_jacobian_blocks.size(); ++i) {
-    const ParameterBlock* parameter_block =
-        program_->parameter_blocks()[evaluated_jacobian_blocks[i].first];
-    const int argument = evaluated_jacobian_blocks[i].second;
-    const int parameter_block_size = parameter_block->LocalSize();
+  for (auto& evaluated_jacobian_block : evaluated_jacobian_blocks) {
+    auto parameter_block =
+        program_->parameter_blocks()[evaluated_jacobian_block.first];
+    const int argument = evaluated_jacobian_block.second;
+    const int parameter_block_size = parameter_block->TangentSize();
 
     // Copy one row of the jacobian block at a time.
     for (int r = 0; r < num_residuals; ++r) {
@@ -235,5 +243,4 @@
   }
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/compressed_row_jacobian_writer.h b/third_party/ceres/internal/ceres/compressed_row_jacobian_writer.h
index b1251ca..6fc40e9 100644
--- a/third_party/ceres/internal/ceres/compressed_row_jacobian_writer.h
+++ b/third_party/ceres/internal/ceres/compressed_row_jacobian_writer.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -33,20 +33,21 @@
 #ifndef CERES_INTERNAL_COMPRESSED_ROW_JACOBIAN_WRITER_H_
 #define CERES_INTERNAL_COMPRESSED_ROW_JACOBIAN_WRITER_H_
 
+#include <memory>
 #include <utility>
 #include <vector>
 
 #include "ceres/evaluator.h"
+#include "ceres/internal/export.h"
 #include "ceres/scratch_evaluate_preparer.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 class CompressedRowSparseMatrix;
 class Program;
 class SparseMatrix;
 
-class CompressedRowJacobianWriter {
+class CERES_NO_EXPORT CompressedRowJacobianWriter {
  public:
   CompressedRowJacobianWriter(Evaluator::Options /* ignored */,
                               Program* program)
@@ -89,11 +90,12 @@
   // assumed by the cost functions, use scratch space to store the
   // jacobians temporarily then copy them over to the larger jacobian
   // in the Write() function.
-  ScratchEvaluatePreparer* CreateEvaluatePreparers(int num_threads) {
+  std::unique_ptr<ScratchEvaluatePreparer[]> CreateEvaluatePreparers(
+      int num_threads) {
     return ScratchEvaluatePreparer::Create(*program_, num_threads);
   }
 
-  SparseMatrix* CreateJacobian() const;
+  std::unique_ptr<SparseMatrix> CreateJacobian() const;
 
   void Write(int residual_id,
              int residual_offset,
@@ -104,7 +106,6 @@
   Program* program_;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_INTERNAL_COMPRESSED_ROW_JACOBIAN_WRITER_H_
diff --git a/third_party/ceres/internal/ceres/compressed_row_sparse_matrix.cc b/third_party/ceres/internal/ceres/compressed_row_sparse_matrix.cc
index 900586c..21697f8 100644
--- a/third_party/ceres/internal/ceres/compressed_row_sparse_matrix.cc
+++ b/third_party/ceres/internal/ceres/compressed_row_sparse_matrix.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -31,24 +31,24 @@
 #include "ceres/compressed_row_sparse_matrix.h"
 
 #include <algorithm>
+#include <functional>
+#include <memory>
 #include <numeric>
+#include <random>
 #include <vector>
 
+#include "ceres/context_impl.h"
 #include "ceres/crs_matrix.h"
-#include "ceres/internal/port.h"
-#include "ceres/random.h"
+#include "ceres/internal/export.h"
+#include "ceres/parallel_for.h"
 #include "ceres/triplet_sparse_matrix.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
-
-using std::vector;
-
+namespace ceres::internal {
 namespace {
 
 // Helper functor used by the constructor for reordering the contents
-// of a TripletSparseMatrix. This comparator assumes thay there are no
+// of a TripletSparseMatrix. This comparator assumes that there are no
 // duplicates in the pair of arrays rows and cols, i.e., there is no
 // indices i and j (not equal to each other) s.t.
 //
@@ -104,7 +104,7 @@
       const int c = cols[idx];
       const int transpose_idx = transpose_rows[c]++;
       transpose_cols[transpose_idx] = r;
-      if (values != NULL && transpose_values != NULL) {
+      if (values != nullptr && transpose_values != nullptr) {
         transpose_values[transpose_idx] = values[idx];
       }
     }
@@ -118,10 +118,12 @@
   transpose_rows[0] = 0;
 }
 
+template <class RandomNormalFunctor>
 void AddRandomBlock(const int num_rows,
                     const int num_cols,
                     const int row_block_begin,
                     const int col_block_begin,
+                    RandomNormalFunctor&& randn,
                     std::vector<int>* rows,
                     std::vector<int>* cols,
                     std::vector<double>* values) {
@@ -129,19 +131,21 @@
     for (int c = 0; c < num_cols; ++c) {
       rows->push_back(row_block_begin + r);
       cols->push_back(col_block_begin + c);
-      values->push_back(RandNormal());
+      values->push_back(randn());
     }
   }
 }
 
+template <class RandomNormalFunctor>
 void AddSymmetricRandomBlock(const int num_rows,
                              const int row_block_begin,
+                             RandomNormalFunctor&& randn,
                              std::vector<int>* rows,
                              std::vector<int>* cols,
                              std::vector<double>* values) {
   for (int r = 0; r < num_rows; ++r) {
     for (int c = r; c < num_rows; ++c) {
-      const double v = RandNormal();
+      const double v = randn();
       rows->push_back(row_block_begin + r);
       cols->push_back(row_block_begin + c);
       values->push_back(v);
@@ -162,7 +166,7 @@
                                                      int max_num_nonzeros) {
   num_rows_ = num_rows;
   num_cols_ = num_cols;
-  storage_type_ = UNSYMMETRIC;
+  storage_type_ = StorageType::UNSYMMETRIC;
   rows_.resize(num_rows + 1, 0);
   cols_.resize(max_num_nonzeros, 0);
   values_.resize(max_num_nonzeros, 0.0);
@@ -174,18 +178,20 @@
                  cols_.size() * sizeof(double);  // NOLINT
 }
 
-CompressedRowSparseMatrix* CompressedRowSparseMatrix::FromTripletSparseMatrix(
+std::unique_ptr<CompressedRowSparseMatrix>
+CompressedRowSparseMatrix::FromTripletSparseMatrix(
     const TripletSparseMatrix& input) {
   return CompressedRowSparseMatrix::FromTripletSparseMatrix(input, false);
 }
 
-CompressedRowSparseMatrix*
+std::unique_ptr<CompressedRowSparseMatrix>
 CompressedRowSparseMatrix::FromTripletSparseMatrixTransposed(
     const TripletSparseMatrix& input) {
   return CompressedRowSparseMatrix::FromTripletSparseMatrix(input, true);
 }
 
-CompressedRowSparseMatrix* CompressedRowSparseMatrix::FromTripletSparseMatrix(
+std::unique_ptr<CompressedRowSparseMatrix>
+CompressedRowSparseMatrix::FromTripletSparseMatrix(
     const TripletSparseMatrix& input, bool transpose) {
   int num_rows = input.num_rows();
   int num_cols = input.num_cols();
@@ -199,7 +205,7 @@
   }
 
   // index is the list of indices into the TripletSparseMatrix input.
-  vector<int> index(input.num_nonzeros(), 0);
+  std::vector<int> index(input.num_nonzeros(), 0);
   for (int i = 0; i < input.num_nonzeros(); ++i) {
     index[i] = i;
   }
@@ -214,8 +220,8 @@
               input.num_nonzeros() * sizeof(int) +     // NOLINT
               input.num_nonzeros() * sizeof(double));  // NOLINT
 
-  CompressedRowSparseMatrix* output =
-      new CompressedRowSparseMatrix(num_rows, num_cols, input.num_nonzeros());
+  auto output = std::make_unique<CompressedRowSparseMatrix>(
+      num_rows, num_cols, input.num_nonzeros());
 
   if (num_rows == 0) {
     // No data to copy.
@@ -251,7 +257,7 @@
 
   num_rows_ = num_rows;
   num_cols_ = num_rows;
-  storage_type_ = UNSYMMETRIC;
+  storage_type_ = StorageType::UNSYMMETRIC;
   rows_.resize(num_rows + 1);
   cols_.resize(num_rows);
   values_.resize(num_rows);
@@ -266,28 +272,43 @@
   CHECK_EQ(num_nonzeros(), num_rows);
 }
 
-CompressedRowSparseMatrix::~CompressedRowSparseMatrix() {}
+CompressedRowSparseMatrix::~CompressedRowSparseMatrix() = default;
 
 void CompressedRowSparseMatrix::SetZero() {
   std::fill(values_.begin(), values_.end(), 0);
 }
 
-// TODO(sameeragarwal): Make RightMultiply and LeftMultiply
-// block-aware for higher performance.
-void CompressedRowSparseMatrix::RightMultiply(const double* x,
-                                              double* y) const {
+// TODO(sameeragarwal): Make RightMultiplyAndAccumulate and
+// LeftMultiplyAndAccumulate block-aware for higher performance.
+void CompressedRowSparseMatrix::RightMultiplyAndAccumulate(
+    const double* x, double* y, ContextImpl* context, int num_threads) const {
+  if (storage_type_ != StorageType::UNSYMMETRIC) {
+    RightMultiplyAndAccumulate(x, y);
+    return;
+  }
+
+  auto values = values_.data();
+  auto rows = rows_.data();
+  auto cols = cols_.data();
+
+  ParallelFor(
+      context, 0, num_rows_, num_threads, [values, rows, cols, x, y](int row) {
+        for (int idx = rows[row]; idx < rows[row + 1]; ++idx) {
+          const int c = cols[idx];
+          const double v = values[idx];
+          y[row] += v * x[c];
+        }
+      });
+}
+
+void CompressedRowSparseMatrix::RightMultiplyAndAccumulate(const double* x,
+                                                           double* y) const {
   CHECK(x != nullptr);
   CHECK(y != nullptr);
 
-  if (storage_type_ == UNSYMMETRIC) {
-    for (int r = 0; r < num_rows_; ++r) {
-      for (int idx = rows_[r]; idx < rows_[r + 1]; ++idx) {
-        const int c = cols_[idx];
-        const double v = values_[idx];
-        y[r] += v * x[c];
-      }
-    }
-  } else if (storage_type_ == UPPER_TRIANGULAR) {
+  if (storage_type_ == StorageType::UNSYMMETRIC) {
+    RightMultiplyAndAccumulate(x, y, nullptr, 1);
+  } else if (storage_type_ == StorageType::UPPER_TRIANGULAR) {
     // Because of their block structure, we will have entries that lie
     // above (below) the diagonal for lower (upper) triangular matrices,
     // so the loops below need to account for this.
@@ -313,7 +334,7 @@
         }
       }
     }
-  } else if (storage_type_ == LOWER_TRIANGULAR) {
+  } else if (storage_type_ == StorageType::LOWER_TRIANGULAR) {
     for (int r = 0; r < num_rows_; ++r) {
       int idx = rows_[r];
       const int idx_end = rows_[r + 1];
@@ -336,19 +357,21 @@
   }
 }
 
-void CompressedRowSparseMatrix::LeftMultiply(const double* x, double* y) const {
+void CompressedRowSparseMatrix::LeftMultiplyAndAccumulate(const double* x,
+                                                          double* y) const {
   CHECK(x != nullptr);
   CHECK(y != nullptr);
 
-  if (storage_type_ == UNSYMMETRIC) {
+  if (storage_type_ == StorageType::UNSYMMETRIC) {
     for (int r = 0; r < num_rows_; ++r) {
       for (int idx = rows_[r]; idx < rows_[r + 1]; ++idx) {
         y[cols_[idx]] += values_[idx] * x[r];
       }
     }
   } else {
-    // Since the matrix is symmetric, LeftMultiply = RightMultiply.
-    RightMultiply(x, y);
+    // Since the matrix is symmetric, LeftMultiplyAndAccumulate =
+    // RightMultiplyAndAccumulate.
+    RightMultiplyAndAccumulate(x, y);
   }
 }
 
@@ -356,11 +379,11 @@
   CHECK(x != nullptr);
 
   std::fill(x, x + num_cols_, 0.0);
-  if (storage_type_ == UNSYMMETRIC) {
+  if (storage_type_ == StorageType::UNSYMMETRIC) {
     for (int idx = 0; idx < rows_[num_rows_]; ++idx) {
       x[cols_[idx]] += values_[idx] * values_[idx];
     }
-  } else if (storage_type_ == UPPER_TRIANGULAR) {
+  } else if (storage_type_ == StorageType::UPPER_TRIANGULAR) {
     // Because of their block structure, we will have entries that lie
     // above (below) the diagonal for lower (upper) triangular
     // matrices, so the loops below need to account for this.
@@ -386,7 +409,7 @@
         }
       }
     }
-  } else if (storage_type_ == LOWER_TRIANGULAR) {
+  } else if (storage_type_ == StorageType::LOWER_TRIANGULAR) {
     for (int r = 0; r < num_rows_; ++r) {
       int idx = rows_[r];
       const int idx_end = rows_[r + 1];
@@ -431,7 +454,7 @@
 void CompressedRowSparseMatrix::DeleteRows(int delta_rows) {
   CHECK_GE(delta_rows, 0);
   CHECK_LE(delta_rows, num_rows_);
-  CHECK_EQ(storage_type_, UNSYMMETRIC);
+  CHECK_EQ(storage_type_, StorageType::UNSYMMETRIC);
 
   num_rows_ -= delta_rows;
   rows_.resize(num_rows_ + 1);
@@ -447,7 +470,7 @@
   int num_row_blocks = 0;
   int num_rows = 0;
   while (num_row_blocks < row_blocks_.size() && num_rows < num_rows_) {
-    num_rows += row_blocks_[num_row_blocks];
+    num_rows += row_blocks_[num_row_blocks].size;
     ++num_row_blocks;
   }
 
@@ -455,7 +478,7 @@
 }
 
 void CompressedRowSparseMatrix::AppendRows(const CompressedRowSparseMatrix& m) {
-  CHECK_EQ(storage_type_, UNSYMMETRIC);
+  CHECK_EQ(storage_type_, StorageType::UNSYMMETRIC);
   CHECK_EQ(m.num_cols(), num_cols_);
 
   CHECK((row_blocks_.empty() && m.row_blocks().empty()) ||
@@ -533,17 +556,17 @@
   values_.resize(num_nonzeros);
 }
 
-CompressedRowSparseMatrix* CompressedRowSparseMatrix::CreateBlockDiagonalMatrix(
-    const double* diagonal, const vector<int>& blocks) {
-  int num_rows = 0;
+std::unique_ptr<CompressedRowSparseMatrix>
+CompressedRowSparseMatrix::CreateBlockDiagonalMatrix(
+    const double* diagonal, const std::vector<Block>& blocks) {
+  const int num_rows = NumScalarEntries(blocks);
   int num_nonzeros = 0;
-  for (int i = 0; i < blocks.size(); ++i) {
-    num_rows += blocks[i];
-    num_nonzeros += blocks[i] * blocks[i];
+  for (auto& block : blocks) {
+    num_nonzeros += block.size * block.size;
   }
 
-  CompressedRowSparseMatrix* matrix =
-      new CompressedRowSparseMatrix(num_rows, num_rows, num_nonzeros);
+  auto matrix = std::make_unique<CompressedRowSparseMatrix>(
+      num_rows, num_rows, num_nonzeros);
 
   int* rows = matrix->mutable_rows();
   int* cols = matrix->mutable_cols();
@@ -552,16 +575,17 @@
 
   int idx_cursor = 0;
   int col_cursor = 0;
-  for (int i = 0; i < blocks.size(); ++i) {
-    const int block_size = blocks[i];
-    for (int r = 0; r < block_size; ++r) {
+  for (auto& block : blocks) {
+    for (int r = 0; r < block.size; ++r) {
       *(rows++) = idx_cursor;
-      values[idx_cursor + r] = diagonal[col_cursor + r];
-      for (int c = 0; c < block_size; ++c, ++idx_cursor) {
+      if (diagonal != nullptr) {
+        values[idx_cursor + r] = diagonal[col_cursor + r];
+      }
+      for (int c = 0; c < block.size; ++c, ++idx_cursor) {
         *(cols++) = col_cursor + c;
       }
     }
-    col_cursor += block_size;
+    col_cursor += block.size;
   }
   *rows = idx_cursor;
 
@@ -573,19 +597,20 @@
   return matrix;
 }
 
-CompressedRowSparseMatrix* CompressedRowSparseMatrix::Transpose() const {
-  CompressedRowSparseMatrix* transpose =
-      new CompressedRowSparseMatrix(num_cols_, num_rows_, num_nonzeros());
+std::unique_ptr<CompressedRowSparseMatrix>
+CompressedRowSparseMatrix::Transpose() const {
+  auto transpose = std::make_unique<CompressedRowSparseMatrix>(
+      num_cols_, num_rows_, num_nonzeros());
 
   switch (storage_type_) {
-    case UNSYMMETRIC:
-      transpose->set_storage_type(UNSYMMETRIC);
+    case StorageType::UNSYMMETRIC:
+      transpose->set_storage_type(StorageType::UNSYMMETRIC);
       break;
-    case LOWER_TRIANGULAR:
-      transpose->set_storage_type(UPPER_TRIANGULAR);
+    case StorageType::LOWER_TRIANGULAR:
+      transpose->set_storage_type(StorageType::UPPER_TRIANGULAR);
       break;
-    case UPPER_TRIANGULAR:
-      transpose->set_storage_type(LOWER_TRIANGULAR);
+    case StorageType::UPPER_TRIANGULAR:
+      transpose->set_storage_type(StorageType::LOWER_TRIANGULAR);
       break;
     default:
       LOG(FATAL) << "Unknown storage type: " << storage_type_;
@@ -612,14 +637,16 @@
   return transpose;
 }
 
-CompressedRowSparseMatrix* CompressedRowSparseMatrix::CreateRandomMatrix(
-    CompressedRowSparseMatrix::RandomMatrixOptions options) {
+std::unique_ptr<CompressedRowSparseMatrix>
+CompressedRowSparseMatrix::CreateRandomMatrix(
+    CompressedRowSparseMatrix::RandomMatrixOptions options,
+    std::mt19937& prng) {
   CHECK_GT(options.num_row_blocks, 0);
   CHECK_GT(options.min_row_block_size, 0);
   CHECK_GT(options.max_row_block_size, 0);
   CHECK_LE(options.min_row_block_size, options.max_row_block_size);
 
-  if (options.storage_type == UNSYMMETRIC) {
+  if (options.storage_type == StorageType::UNSYMMETRIC) {
     CHECK_GT(options.num_col_blocks, 0);
     CHECK_GT(options.min_col_block_size, 0);
     CHECK_GT(options.max_col_block_size, 0);
@@ -634,33 +661,42 @@
   CHECK_GT(options.block_density, 0.0);
   CHECK_LE(options.block_density, 1.0);
 
-  vector<int> row_blocks;
-  vector<int> col_blocks;
+  std::vector<Block> row_blocks;
+  row_blocks.reserve(options.num_row_blocks);
+  std::vector<Block> col_blocks;
+  col_blocks.reserve(options.num_col_blocks);
+
+  std::uniform_int_distribution<int> col_distribution(
+      options.min_col_block_size, options.max_col_block_size);
+  std::uniform_int_distribution<int> row_distribution(
+      options.min_row_block_size, options.max_row_block_size);
+  std::uniform_real_distribution<double> uniform01(0.0, 1.0);
+  std::normal_distribution<double> standard_normal_distribution;
 
   // Generate the row block structure.
+  int row_pos = 0;
   for (int i = 0; i < options.num_row_blocks; ++i) {
     // Generate a random integer in [min_row_block_size, max_row_block_size]
-    const int delta_block_size =
-        Uniform(options.max_row_block_size - options.min_row_block_size);
-    row_blocks.push_back(options.min_row_block_size + delta_block_size);
+    row_blocks.emplace_back(row_distribution(prng), row_pos);
+    row_pos += row_blocks.back().size;
   }
 
-  if (options.storage_type == UNSYMMETRIC) {
+  if (options.storage_type == StorageType::UNSYMMETRIC) {
     // Generate the col block structure.
+    int col_pos = 0;
     for (int i = 0; i < options.num_col_blocks; ++i) {
       // Generate a random integer in [min_col_block_size, max_col_block_size]
-      const int delta_block_size =
-          Uniform(options.max_col_block_size - options.min_col_block_size);
-      col_blocks.push_back(options.min_col_block_size + delta_block_size);
+      col_blocks.emplace_back(col_distribution(prng), col_pos);
+      col_pos += col_blocks.back().size;
     }
   } else {
     // Symmetric matrices (LOWER_TRIANGULAR or UPPER_TRIANGULAR);
     col_blocks = row_blocks;
   }
 
-  vector<int> tsm_rows;
-  vector<int> tsm_cols;
-  vector<double> tsm_values;
+  std::vector<int> tsm_rows;
+  std::vector<int> tsm_cols;
+  std::vector<double> tsm_values;
 
   // For ease of construction, we are going to generate the
   // CompressedRowSparseMatrix by generating it as a
@@ -679,51 +715,55 @@
     for (int r = 0; r < options.num_row_blocks; ++r) {
       int col_block_begin = 0;
       for (int c = 0; c < options.num_col_blocks; ++c) {
-        if (((options.storage_type == UPPER_TRIANGULAR) && (r > c)) ||
-            ((options.storage_type == LOWER_TRIANGULAR) && (r < c))) {
-          col_block_begin += col_blocks[c];
+        if (((options.storage_type == StorageType::UPPER_TRIANGULAR) &&
+             (r > c)) ||
+            ((options.storage_type == StorageType::LOWER_TRIANGULAR) &&
+             (r < c))) {
+          col_block_begin += col_blocks[c].size;
           continue;
         }
 
         // Randomly determine if this block is present or not.
-        if (RandDouble() <= options.block_density) {
+        if (uniform01(prng) <= options.block_density) {
+          auto randn = [&standard_normal_distribution, &prng] {
+            return standard_normal_distribution(prng);
+          };
           // If the matrix is symmetric, then we take care to generate
           // symmetric diagonal blocks.
-          if (options.storage_type == UNSYMMETRIC || r != c) {
-            AddRandomBlock(row_blocks[r],
-                           col_blocks[c],
+          if (options.storage_type == StorageType::UNSYMMETRIC || r != c) {
+            AddRandomBlock(row_blocks[r].size,
+                           col_blocks[c].size,
                            row_block_begin,
                            col_block_begin,
+                           randn,
                            &tsm_rows,
                            &tsm_cols,
                            &tsm_values);
           } else {
-            AddSymmetricRandomBlock(row_blocks[r],
+            AddSymmetricRandomBlock(row_blocks[r].size,
                                     row_block_begin,
+                                    randn,
                                     &tsm_rows,
                                     &tsm_cols,
                                     &tsm_values);
           }
         }
-        col_block_begin += col_blocks[c];
+        col_block_begin += col_blocks[c].size;
       }
-      row_block_begin += row_blocks[r];
+      row_block_begin += row_blocks[r].size;
     }
   }
 
-  const int num_rows = std::accumulate(row_blocks.begin(), row_blocks.end(), 0);
-  const int num_cols = std::accumulate(col_blocks.begin(), col_blocks.end(), 0);
+  const int num_rows = NumScalarEntries(row_blocks);
+  const int num_cols = NumScalarEntries(col_blocks);
   const bool kDoNotTranspose = false;
-  CompressedRowSparseMatrix* matrix =
-      CompressedRowSparseMatrix::FromTripletSparseMatrix(
-          TripletSparseMatrix(
-              num_rows, num_cols, tsm_rows, tsm_cols, tsm_values),
-          kDoNotTranspose);
+  auto matrix = CompressedRowSparseMatrix::FromTripletSparseMatrix(
+      TripletSparseMatrix(num_rows, num_cols, tsm_rows, tsm_cols, tsm_values),
+      kDoNotTranspose);
   (*matrix->mutable_row_blocks()) = row_blocks;
   (*matrix->mutable_col_blocks()) = col_blocks;
   matrix->set_storage_type(options.storage_type);
   return matrix;
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/compressed_row_sparse_matrix.h b/third_party/ceres/internal/ceres/compressed_row_sparse_matrix.h
index e4eb985..36c8895 100644
--- a/third_party/ceres/internal/ceres/compressed_row_sparse_matrix.h
+++ b/third_party/ceres/internal/ceres/compressed_row_sparse_matrix.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -31,9 +31,13 @@
 #ifndef CERES_INTERNAL_COMPRESSED_ROW_SPARSE_MATRIX_H_
 #define CERES_INTERNAL_COMPRESSED_ROW_SPARSE_MATRIX_H_
 
+#include <memory>
+#include <random>
 #include <vector>
 
-#include "ceres/internal/port.h"
+#include "ceres/block_structure.h"
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 #include "ceres/sparse_matrix.h"
 #include "ceres/types.h"
 #include "glog/logging.h"
@@ -44,11 +48,12 @@
 
 namespace internal {
 
+class ContextImpl;
 class TripletSparseMatrix;
 
-class CERES_EXPORT_INTERNAL CompressedRowSparseMatrix : public SparseMatrix {
+class CERES_NO_EXPORT CompressedRowSparseMatrix : public SparseMatrix {
  public:
-  enum StorageType {
+  enum class StorageType {
     UNSYMMETRIC,
     // Matrix is assumed to be symmetric but only the lower triangular
     // part of the matrix is stored.
@@ -63,9 +68,7 @@
   // entries.
   //
   // The storage type of the matrix is set to UNSYMMETRIC.
-  //
-  // Caller owns the result.
-  static CompressedRowSparseMatrix* FromTripletSparseMatrix(
+  static std::unique_ptr<CompressedRowSparseMatrix> FromTripletSparseMatrix(
       const TripletSparseMatrix& input);
 
   // Create a matrix with the same content as the TripletSparseMatrix
@@ -73,10 +76,8 @@
   // entries.
   //
   // The storage type of the matrix is set to UNSYMMETRIC.
-  //
-  // Caller owns the result.
-  static CompressedRowSparseMatrix* FromTripletSparseMatrixTransposed(
-      const TripletSparseMatrix& input);
+  static std::unique_ptr<CompressedRowSparseMatrix>
+  FromTripletSparseMatrixTransposed(const TripletSparseMatrix& input);
 
   // Use this constructor only if you know what you are doing. This
   // creates a "blank" matrix with the appropriate amount of memory
@@ -100,10 +101,14 @@
   CompressedRowSparseMatrix(const double* diagonal, int num_rows);
 
   // SparseMatrix interface.
-  virtual ~CompressedRowSparseMatrix();
+  ~CompressedRowSparseMatrix() override;
   void SetZero() final;
-  void RightMultiply(const double* x, double* y) const final;
-  void LeftMultiply(const double* x, double* y) const final;
+  void RightMultiplyAndAccumulate(const double* x, double* y) const final;
+  void RightMultiplyAndAccumulate(const double* x,
+                                  double* y,
+                                  ContextImpl* context,
+                                  int num_threads) const final;
+  void LeftMultiplyAndAccumulate(const double* x, double* y) const final;
   void SquaredColumnNorm(double* x) const final;
   void ScaleColumns(const double* scale) final;
   void ToDenseMatrix(Matrix* dense_matrix) const final;
@@ -111,8 +116,8 @@
   int num_rows() const final { return num_rows_; }
   int num_cols() const final { return num_cols_; }
   int num_nonzeros() const final { return rows_[num_rows_]; }
-  const double* values() const final { return &values_[0]; }
-  double* mutable_values() final { return &values_[0]; }
+  const double* values() const final { return values_.data(); }
+  double* mutable_values() final { return values_.data(); }
 
   // Delete the bottom delta_rows.
   // num_rows -= delta_rows
@@ -124,7 +129,7 @@
 
   void ToCRSMatrix(CRSMatrix* matrix) const;
 
-  CompressedRowSparseMatrix* Transpose() const;
+  std::unique_ptr<CompressedRowSparseMatrix> Transpose() const;
 
   // Destructive array resizing method.
   void SetMaxNumNonZeros(int num_nonzeros);
@@ -134,30 +139,28 @@
   void set_num_cols(const int num_cols) { num_cols_ = num_cols; }
 
   // Low level access methods that expose the structure of the matrix.
-  const int* cols() const { return &cols_[0]; }
-  int* mutable_cols() { return &cols_[0]; }
+  const int* cols() const { return cols_.data(); }
+  int* mutable_cols() { return cols_.data(); }
 
-  const int* rows() const { return &rows_[0]; }
-  int* mutable_rows() { return &rows_[0]; }
+  const int* rows() const { return rows_.data(); }
+  int* mutable_rows() { return rows_.data(); }
 
   StorageType storage_type() const { return storage_type_; }
   void set_storage_type(const StorageType storage_type) {
     storage_type_ = storage_type;
   }
 
-  const std::vector<int>& row_blocks() const { return row_blocks_; }
-  std::vector<int>* mutable_row_blocks() { return &row_blocks_; }
+  const std::vector<Block>& row_blocks() const { return row_blocks_; }
+  std::vector<Block>* mutable_row_blocks() { return &row_blocks_; }
 
-  const std::vector<int>& col_blocks() const { return col_blocks_; }
-  std::vector<int>* mutable_col_blocks() { return &col_blocks_; }
+  const std::vector<Block>& col_blocks() const { return col_blocks_; }
+  std::vector<Block>* mutable_col_blocks() { return &col_blocks_; }
 
   // Create a block diagonal CompressedRowSparseMatrix with the given
   // block structure. The individual blocks are assumed to be laid out
   // contiguously in the diagonal array, one block at a time.
-  //
-  // Caller owns the result.
-  static CompressedRowSparseMatrix* CreateBlockDiagonalMatrix(
-      const double* diagonal, const std::vector<int>& blocks);
+  static std::unique_ptr<CompressedRowSparseMatrix> CreateBlockDiagonalMatrix(
+      const double* diagonal, const std::vector<Block>& blocks);
 
   // Options struct to control the generation of random block sparse
   // matrices in compressed row sparse format.
@@ -169,7 +172,7 @@
   // given bounds.
   //
   // Then we walk the block structure of the resulting matrix, and with
-  // probability block_density detemine whether they are structurally
+  // probability block_density determine whether they are structurally
   // zero or not. If the answer is no, then we generate entries for the
   // block which are distributed normally.
   struct RandomMatrixOptions {
@@ -180,7 +183,7 @@
     // (lower triangular) part. In this case, num_col_blocks,
     // min_col_block_size and max_col_block_size will be ignored and
     // assumed to be equal to the corresponding row settings.
-    StorageType storage_type = UNSYMMETRIC;
+    StorageType storage_type = StorageType::UNSYMMETRIC;
 
     int num_row_blocks = 0;
     int min_row_block_size = 0;
@@ -198,13 +201,11 @@
   // Create a random CompressedRowSparseMatrix whose entries are
   // normally distributed and whose structure is determined by
   // RandomMatrixOptions.
-  //
-  // Caller owns the result.
-  static CompressedRowSparseMatrix* CreateRandomMatrix(
-      RandomMatrixOptions options);
+  static std::unique_ptr<CompressedRowSparseMatrix> CreateRandomMatrix(
+      RandomMatrixOptions options, std::mt19937& prng);
 
  private:
-  static CompressedRowSparseMatrix* FromTripletSparseMatrix(
+  static std::unique_ptr<CompressedRowSparseMatrix> FromTripletSparseMatrix(
       const TripletSparseMatrix& input, bool transpose);
 
   int num_rows_;
@@ -215,15 +216,34 @@
   StorageType storage_type_;
 
   // If the matrix has an underlying block structure, then it can also
-  // carry with it row and column block sizes. This is auxilliary and
+  // carry with it row and column block sizes. This is auxiliary and
   // optional information for use by algorithms operating on the
   // matrix. The class itself does not make use of this information in
   // any way.
-  std::vector<int> row_blocks_;
-  std::vector<int> col_blocks_;
+  std::vector<Block> row_blocks_;
+  std::vector<Block> col_blocks_;
 };
 
+inline std::ostream& operator<<(std::ostream& s,
+                                CompressedRowSparseMatrix::StorageType type) {
+  switch (type) {
+    case CompressedRowSparseMatrix::StorageType::UNSYMMETRIC:
+      s << "UNSYMMETRIC";
+      break;
+    case CompressedRowSparseMatrix::StorageType::UPPER_TRIANGULAR:
+      s << "UPPER_TRIANGULAR";
+      break;
+    case CompressedRowSparseMatrix::StorageType::LOWER_TRIANGULAR:
+      s << "LOWER_TRIANGULAR";
+      break;
+    default:
+      s << "UNKNOWN CompressedRowSparseMatrix::StorageType";
+  }
+  return s;
+}
 }  // namespace internal
 }  // namespace ceres
 
+#include "ceres/internal/reenable_warnings.h"
+
 #endif  // CERES_INTERNAL_COMPRESSED_ROW_SPARSE_MATRIX_H_
diff --git a/third_party/ceres/internal/ceres/compressed_row_sparse_matrix_test.cc b/third_party/ceres/internal/ceres/compressed_row_sparse_matrix_test.cc
index 91f3ba4..b6bcdb7 100644
--- a/third_party/ceres/internal/ceres/compressed_row_sparse_matrix_test.cc
+++ b/third_party/ceres/internal/ceres/compressed_row_sparse_matrix_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -30,23 +30,24 @@
 
 #include "ceres/compressed_row_sparse_matrix.h"
 
+#include <algorithm>
 #include <memory>
 #include <numeric>
+#include <random>
+#include <string>
+#include <vector>
 
 #include "Eigen/SparseCore"
 #include "ceres/casts.h"
+#include "ceres/context_impl.h"
 #include "ceres/crs_matrix.h"
 #include "ceres/internal/eigen.h"
 #include "ceres/linear_least_squares_problems.h"
-#include "ceres/random.h"
 #include "ceres/triplet_sparse_matrix.h"
 #include "glog/logging.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
-
-using std::vector;
+namespace ceres::internal {
 
 static void CompareMatrices(const SparseMatrix* a, const SparseMatrix* b) {
   EXPECT_EQ(a->num_rows(), b->num_rows());
@@ -62,9 +63,8 @@
     Vector y_a = Vector::Zero(num_rows);
     Vector y_b = Vector::Zero(num_rows);
 
-    a->RightMultiply(x.data(), y_a.data());
-    b->RightMultiply(x.data(), y_b.data());
-
+    a->RightMultiplyAndAccumulate(x.data(), y_a.data());
+    b->RightMultiplyAndAccumulate(x.data(), y_b.data());
     EXPECT_EQ((y_a - y_b).norm(), 0);
   }
 }
@@ -72,24 +72,26 @@
 class CompressedRowSparseMatrixTest : public ::testing::Test {
  protected:
   void SetUp() final {
-    std::unique_ptr<LinearLeastSquaresProblem> problem(
-        CreateLinearLeastSquaresProblemFromId(1));
+    auto problem = CreateLinearLeastSquaresProblemFromId(1);
 
     CHECK(problem != nullptr);
 
     tsm.reset(down_cast<TripletSparseMatrix*>(problem->A.release()));
-    crsm.reset(CompressedRowSparseMatrix::FromTripletSparseMatrix(*tsm));
+    crsm = CompressedRowSparseMatrix::FromTripletSparseMatrix(*tsm);
 
     num_rows = tsm->num_rows();
     num_cols = tsm->num_cols();
 
-    vector<int>* row_blocks = crsm->mutable_row_blocks();
+    std::vector<Block>* row_blocks = crsm->mutable_row_blocks();
     row_blocks->resize(num_rows);
-    std::fill(row_blocks->begin(), row_blocks->end(), 1);
-
-    vector<int>* col_blocks = crsm->mutable_col_blocks();
+    for (int i = 0; i < row_blocks->size(); ++i) {
+      (*row_blocks)[i] = Block(1, i);
+    }
+    std::vector<Block>* col_blocks = crsm->mutable_col_blocks();
     col_blocks->resize(num_cols);
-    std::fill(col_blocks->begin(), col_blocks->end(), 1);
+    for (int i = 0; i < col_blocks->size(); ++i) {
+      (*col_blocks)[i] = Block(1, i);
+    }
   }
 
   int num_rows;
@@ -132,8 +134,8 @@
     tsm_appendage.Resize(i, num_cols);
 
     tsm->AppendRows(tsm_appendage);
-    std::unique_ptr<CompressedRowSparseMatrix> crsm_appendage(
-        CompressedRowSparseMatrix::FromTripletSparseMatrix(tsm_appendage));
+    auto crsm_appendage =
+        CompressedRowSparseMatrix::FromTripletSparseMatrix(tsm_appendage);
 
     crsm->AppendRows(*crsm_appendage);
     CompareMatrices(tsm.get(), crsm.get());
@@ -143,34 +145,33 @@
 TEST_F(CompressedRowSparseMatrixTest, AppendAndDeleteBlockDiagonalMatrix) {
   int num_diagonal_rows = crsm->num_cols();
 
-  std::unique_ptr<double[]> diagonal(new double[num_diagonal_rows]);
+  auto diagonal = std::make_unique<double[]>(num_diagonal_rows);
   for (int i = 0; i < num_diagonal_rows; ++i) {
     diagonal[i] = i;
   }
 
-  vector<int> row_and_column_blocks;
-  row_and_column_blocks.push_back(1);
-  row_and_column_blocks.push_back(2);
-  row_and_column_blocks.push_back(2);
+  std::vector<Block> row_and_column_blocks;
+  row_and_column_blocks.emplace_back(1, 0);
+  row_and_column_blocks.emplace_back(2, 1);
+  row_and_column_blocks.emplace_back(2, 3);
 
-  const vector<int> pre_row_blocks = crsm->row_blocks();
-  const vector<int> pre_col_blocks = crsm->col_blocks();
+  const std::vector<Block> pre_row_blocks = crsm->row_blocks();
+  const std::vector<Block> pre_col_blocks = crsm->col_blocks();
 
-  std::unique_ptr<CompressedRowSparseMatrix> appendage(
-      CompressedRowSparseMatrix::CreateBlockDiagonalMatrix(
-          diagonal.get(), row_and_column_blocks));
+  auto appendage = CompressedRowSparseMatrix::CreateBlockDiagonalMatrix(
+      diagonal.get(), row_and_column_blocks);
 
   crsm->AppendRows(*appendage);
 
-  const vector<int> post_row_blocks = crsm->row_blocks();
-  const vector<int> post_col_blocks = crsm->col_blocks();
+  const std::vector<Block> post_row_blocks = crsm->row_blocks();
+  const std::vector<Block> post_col_blocks = crsm->col_blocks();
 
-  vector<int> expected_row_blocks = pre_row_blocks;
+  std::vector<Block> expected_row_blocks = pre_row_blocks;
   expected_row_blocks.insert(expected_row_blocks.end(),
                              row_and_column_blocks.begin(),
                              row_and_column_blocks.end());
 
-  vector<int> expected_col_blocks = pre_col_blocks;
+  std::vector<Block> expected_col_blocks = pre_col_blocks;
 
   EXPECT_EQ(expected_row_blocks, crsm->row_blocks());
   EXPECT_EQ(expected_col_blocks, crsm->col_blocks());
@@ -210,19 +211,18 @@
 }
 
 TEST(CompressedRowSparseMatrix, CreateBlockDiagonalMatrix) {
-  vector<int> blocks;
-  blocks.push_back(1);
-  blocks.push_back(2);
-  blocks.push_back(2);
+  std::vector<Block> blocks;
+  blocks.emplace_back(1, 0);
+  blocks.emplace_back(2, 1);
+  blocks.emplace_back(2, 3);
 
   Vector diagonal(5);
   for (int i = 0; i < 5; ++i) {
     diagonal(i) = i + 1;
   }
 
-  std::unique_ptr<CompressedRowSparseMatrix> matrix(
-      CompressedRowSparseMatrix::CreateBlockDiagonalMatrix(diagonal.data(),
-                                                           blocks));
+  auto matrix = CompressedRowSparseMatrix::CreateBlockDiagonalMatrix(
+      diagonal.data(), blocks);
 
   EXPECT_EQ(matrix->num_rows(), 5);
   EXPECT_EQ(matrix->num_cols(), 5);
@@ -235,13 +235,13 @@
 
   x.setOnes();
   y.setZero();
-  matrix->RightMultiply(x.data(), y.data());
+  matrix->RightMultiplyAndAccumulate(x.data(), y.data());
   for (int i = 0; i < diagonal.size(); ++i) {
     EXPECT_EQ(y[i], diagonal[i]);
   }
 
   y.setZero();
-  matrix->LeftMultiply(x.data(), y.data());
+  matrix->LeftMultiplyAndAccumulate(x.data(), y.data());
   for (int i = 0; i < diagonal.size(); ++i) {
     EXPECT_EQ(y[i], diagonal[i]);
   }
@@ -253,9 +253,9 @@
 
 TEST(CompressedRowSparseMatrix, Transpose) {
   //  0  1  0  2  3  0
-  //  4  6  7  0  0  8
-  //  9 10  0 11 12  0
-  // 13  0 14 15  9  0
+  //  4  5  6  0  0  7
+  //  8  9  0 10 11  0
+  // 12  0 13 14 15  0
   //  0 16 17  0  0  0
 
   // Block structure:
@@ -270,10 +270,10 @@
   int* rows = matrix.mutable_rows();
   int* cols = matrix.mutable_cols();
   double* values = matrix.mutable_values();
-  matrix.mutable_row_blocks()->push_back(3);
-  matrix.mutable_row_blocks()->push_back(3);
-  matrix.mutable_col_blocks()->push_back(4);
-  matrix.mutable_col_blocks()->push_back(2);
+  matrix.mutable_row_blocks()->emplace_back(3, 0);
+  matrix.mutable_row_blocks()->emplace_back(3, 3);
+  matrix.mutable_col_blocks()->emplace_back(4, 0);
+  matrix.mutable_col_blocks()->emplace_back(2, 4);
 
   rows[0] = 0;
   cols[0] = 1;
@@ -303,9 +303,9 @@
   cols[16] = 2;
   rows[5] = 17;
 
-  std::copy(values, values + 17, cols);
+  std::iota(values, values + 17, 1);
 
-  std::unique_ptr<CompressedRowSparseMatrix> transpose(matrix.Transpose());
+  auto transpose = matrix.Transpose();
 
   ASSERT_EQ(transpose->row_blocks().size(), matrix.col_blocks().size());
   for (int i = 0; i < transpose->row_blocks().size(); ++i) {
@@ -326,6 +326,7 @@
 }
 
 TEST(CompressedRowSparseMatrix, FromTripletSparseMatrix) {
+  std::mt19937 prng;
   TripletSparseMatrix::RandomMatrixOptions options;
   options.num_rows = 5;
   options.num_cols = 7;
@@ -333,10 +334,8 @@
 
   const int kNumTrials = 10;
   for (int i = 0; i < kNumTrials; ++i) {
-    std::unique_ptr<TripletSparseMatrix> tsm(
-        TripletSparseMatrix::CreateRandomMatrix(options));
-    std::unique_ptr<CompressedRowSparseMatrix> crsm(
-        CompressedRowSparseMatrix::FromTripletSparseMatrix(*tsm));
+    auto tsm = TripletSparseMatrix::CreateRandomMatrix(options, prng);
+    auto crsm = CompressedRowSparseMatrix::FromTripletSparseMatrix(*tsm);
 
     Matrix expected;
     tsm->ToDenseMatrix(&expected);
@@ -352,6 +351,7 @@
 }
 
 TEST(CompressedRowSparseMatrix, FromTripletSparseMatrixTransposed) {
+  std::mt19937 prng;
   TripletSparseMatrix::RandomMatrixOptions options;
   options.num_rows = 5;
   options.num_cols = 7;
@@ -359,10 +359,9 @@
 
   const int kNumTrials = 10;
   for (int i = 0; i < kNumTrials; ++i) {
-    std::unique_ptr<TripletSparseMatrix> tsm(
-        TripletSparseMatrix::CreateRandomMatrix(options));
-    std::unique_ptr<CompressedRowSparseMatrix> crsm(
-        CompressedRowSparseMatrix::FromTripletSparseMatrixTransposed(*tsm));
+    auto tsm = TripletSparseMatrix::CreateRandomMatrix(options, prng);
+    auto crsm =
+        CompressedRowSparseMatrix::FromTripletSparseMatrixTransposed(*tsm);
 
     Matrix tmp;
     tsm->ToDenseMatrix(&tmp);
@@ -378,31 +377,33 @@
   }
 }
 
-typedef ::testing::tuple<CompressedRowSparseMatrix::StorageType> Param;
+using Param = ::testing::tuple<CompressedRowSparseMatrix::StorageType>;
 
 static std::string ParamInfoToString(testing::TestParamInfo<Param> info) {
   if (::testing::get<0>(info.param) ==
-      CompressedRowSparseMatrix::UPPER_TRIANGULAR) {
+      CompressedRowSparseMatrix::StorageType::UPPER_TRIANGULAR) {
     return "UPPER";
   }
 
   if (::testing::get<0>(info.param) ==
-      CompressedRowSparseMatrix::LOWER_TRIANGULAR) {
+      CompressedRowSparseMatrix::StorageType::LOWER_TRIANGULAR) {
     return "LOWER";
   }
 
   return "UNSYMMETRIC";
 }
 
-class RightMultiplyTest : public ::testing::TestWithParam<Param> {};
+class RightMultiplyAndAccumulateTest : public ::testing::TestWithParam<Param> {
+};
 
-TEST_P(RightMultiplyTest, _) {
+TEST_P(RightMultiplyAndAccumulateTest, _) {
   const int kMinNumBlocks = 1;
   const int kMaxNumBlocks = 10;
   const int kMinBlockSize = 1;
   const int kMaxBlockSize = 5;
   const int kNumTrials = 10;
-
+  std::mt19937 prng;
+  std::uniform_real_distribution<double> uniform(0.5, 1.0);
   for (int num_blocks = kMinNumBlocks; num_blocks < kMaxNumBlocks;
        ++num_blocks) {
     for (int trial = 0; trial < kNumTrials; ++trial) {
@@ -414,10 +415,10 @@
       options.num_row_blocks = 2 * num_blocks;
       options.min_row_block_size = kMinBlockSize;
       options.max_row_block_size = kMaxBlockSize;
-      options.block_density = std::max(0.5, RandDouble());
+      options.block_density = uniform(prng);
       options.storage_type = ::testing::get<0>(param);
-      std::unique_ptr<CompressedRowSparseMatrix> matrix(
-          CompressedRowSparseMatrix::CreateRandomMatrix(options));
+      auto matrix =
+          CompressedRowSparseMatrix::CreateRandomMatrix(options, prng);
       const int num_rows = matrix->num_rows();
       const int num_cols = matrix->num_cols();
 
@@ -426,16 +427,16 @@
 
       Vector actual_y(num_rows);
       actual_y.setZero();
-      matrix->RightMultiply(x.data(), actual_y.data());
+      matrix->RightMultiplyAndAccumulate(x.data(), actual_y.data());
 
       Matrix dense;
       matrix->ToDenseMatrix(&dense);
       Vector expected_y;
       if (::testing::get<0>(param) ==
-          CompressedRowSparseMatrix::UPPER_TRIANGULAR) {
+          CompressedRowSparseMatrix::StorageType::UPPER_TRIANGULAR) {
         expected_y = dense.selfadjointView<Eigen::Upper>() * x;
       } else if (::testing::get<0>(param) ==
-                 CompressedRowSparseMatrix::LOWER_TRIANGULAR) {
+                 CompressedRowSparseMatrix::StorageType::LOWER_TRIANGULAR) {
         expected_y = dense.selfadjointView<Eigen::Lower>() * x;
       } else {
         expected_y = dense * x;
@@ -457,21 +458,22 @@
 
 INSTANTIATE_TEST_SUITE_P(
     CompressedRowSparseMatrix,
-    RightMultiplyTest,
-    ::testing::Values(CompressedRowSparseMatrix::LOWER_TRIANGULAR,
-                      CompressedRowSparseMatrix::UPPER_TRIANGULAR,
-                      CompressedRowSparseMatrix::UNSYMMETRIC),
+    RightMultiplyAndAccumulateTest,
+    ::testing::Values(CompressedRowSparseMatrix::StorageType::LOWER_TRIANGULAR,
+                      CompressedRowSparseMatrix::StorageType::UPPER_TRIANGULAR,
+                      CompressedRowSparseMatrix::StorageType::UNSYMMETRIC),
     ParamInfoToString);
 
-class LeftMultiplyTest : public ::testing::TestWithParam<Param> {};
+class LeftMultiplyAndAccumulateTest : public ::testing::TestWithParam<Param> {};
 
-TEST_P(LeftMultiplyTest, _) {
+TEST_P(LeftMultiplyAndAccumulateTest, _) {
   const int kMinNumBlocks = 1;
   const int kMaxNumBlocks = 10;
   const int kMinBlockSize = 1;
   const int kMaxBlockSize = 5;
   const int kNumTrials = 10;
-
+  std::mt19937 prng;
+  std::uniform_real_distribution<double> uniform(0.5, 1.0);
   for (int num_blocks = kMinNumBlocks; num_blocks < kMaxNumBlocks;
        ++num_blocks) {
     for (int trial = 0; trial < kNumTrials; ++trial) {
@@ -483,10 +485,10 @@
       options.num_row_blocks = 2 * num_blocks;
       options.min_row_block_size = kMinBlockSize;
       options.max_row_block_size = kMaxBlockSize;
-      options.block_density = std::max(0.5, RandDouble());
+      options.block_density = uniform(prng);
       options.storage_type = ::testing::get<0>(param);
-      std::unique_ptr<CompressedRowSparseMatrix> matrix(
-          CompressedRowSparseMatrix::CreateRandomMatrix(options));
+      auto matrix =
+          CompressedRowSparseMatrix::CreateRandomMatrix(options, prng);
       const int num_rows = matrix->num_rows();
       const int num_cols = matrix->num_cols();
 
@@ -495,16 +497,16 @@
 
       Vector actual_y(num_cols);
       actual_y.setZero();
-      matrix->LeftMultiply(x.data(), actual_y.data());
+      matrix->LeftMultiplyAndAccumulate(x.data(), actual_y.data());
 
       Matrix dense;
       matrix->ToDenseMatrix(&dense);
       Vector expected_y;
       if (::testing::get<0>(param) ==
-          CompressedRowSparseMatrix::UPPER_TRIANGULAR) {
+          CompressedRowSparseMatrix::StorageType::UPPER_TRIANGULAR) {
         expected_y = dense.selfadjointView<Eigen::Upper>() * x;
       } else if (::testing::get<0>(param) ==
-                 CompressedRowSparseMatrix::LOWER_TRIANGULAR) {
+                 CompressedRowSparseMatrix::StorageType::LOWER_TRIANGULAR) {
         expected_y = dense.selfadjointView<Eigen::Lower>() * x;
       } else {
         expected_y = dense.transpose() * x;
@@ -526,10 +528,10 @@
 
 INSTANTIATE_TEST_SUITE_P(
     CompressedRowSparseMatrix,
-    LeftMultiplyTest,
-    ::testing::Values(CompressedRowSparseMatrix::LOWER_TRIANGULAR,
-                      CompressedRowSparseMatrix::UPPER_TRIANGULAR,
-                      CompressedRowSparseMatrix::UNSYMMETRIC),
+    LeftMultiplyAndAccumulateTest,
+    ::testing::Values(CompressedRowSparseMatrix::StorageType::LOWER_TRIANGULAR,
+                      CompressedRowSparseMatrix::StorageType::UPPER_TRIANGULAR,
+                      CompressedRowSparseMatrix::StorageType::UNSYMMETRIC),
     ParamInfoToString);
 
 class SquaredColumnNormTest : public ::testing::TestWithParam<Param> {};
@@ -540,7 +542,8 @@
   const int kMinBlockSize = 1;
   const int kMaxBlockSize = 5;
   const int kNumTrials = 10;
-
+  std::mt19937 prng;
+  std::uniform_real_distribution<double> uniform(0.5, 1.0);
   for (int num_blocks = kMinNumBlocks; num_blocks < kMaxNumBlocks;
        ++num_blocks) {
     for (int trial = 0; trial < kNumTrials; ++trial) {
@@ -552,10 +555,10 @@
       options.num_row_blocks = 2 * num_blocks;
       options.min_row_block_size = kMinBlockSize;
       options.max_row_block_size = kMaxBlockSize;
-      options.block_density = std::max(0.5, RandDouble());
+      options.block_density = uniform(prng);
       options.storage_type = ::testing::get<0>(param);
-      std::unique_ptr<CompressedRowSparseMatrix> matrix(
-          CompressedRowSparseMatrix::CreateRandomMatrix(options));
+      auto matrix =
+          CompressedRowSparseMatrix::CreateRandomMatrix(options, prng);
       const int num_cols = matrix->num_cols();
 
       Vector actual(num_cols);
@@ -566,11 +569,11 @@
       matrix->ToDenseMatrix(&dense);
       Vector expected;
       if (::testing::get<0>(param) ==
-          CompressedRowSparseMatrix::UPPER_TRIANGULAR) {
+          CompressedRowSparseMatrix::StorageType::UPPER_TRIANGULAR) {
         const Matrix full = dense.selfadjointView<Eigen::Upper>();
         expected = full.colwise().squaredNorm();
       } else if (::testing::get<0>(param) ==
-                 CompressedRowSparseMatrix::LOWER_TRIANGULAR) {
+                 CompressedRowSparseMatrix::StorageType::LOWER_TRIANGULAR) {
         const Matrix full = dense.selfadjointView<Eigen::Lower>();
         expected = full.colwise().squaredNorm();
       } else {
@@ -592,12 +595,78 @@
 INSTANTIATE_TEST_SUITE_P(
     CompressedRowSparseMatrix,
     SquaredColumnNormTest,
-    ::testing::Values(CompressedRowSparseMatrix::LOWER_TRIANGULAR,
-                      CompressedRowSparseMatrix::UPPER_TRIANGULAR,
-                      CompressedRowSparseMatrix::UNSYMMETRIC),
+    ::testing::Values(CompressedRowSparseMatrix::StorageType::LOWER_TRIANGULAR,
+                      CompressedRowSparseMatrix::StorageType::UPPER_TRIANGULAR,
+                      CompressedRowSparseMatrix::StorageType::UNSYMMETRIC),
     ParamInfoToString);
 
+const int kMaxNumThreads = 8;
+class CompressedRowSparseMatrixParallelTest
+    : public ::testing::TestWithParam<int> {
+  void SetUp() final { context_.EnsureMinimumThreads(kMaxNumThreads); }
+
+ protected:
+  ContextImpl context_;
+};
+
+TEST_P(CompressedRowSparseMatrixParallelTest,
+       RightMultiplyAndAccumulateUnsymmetric) {
+  const int kMinNumBlocks = 1;
+  const int kMaxNumBlocks = 10;
+  const int kMinBlockSize = 1;
+  const int kMaxBlockSize = 5;
+  const int kNumTrials = 10;
+  const int kNumThreads = GetParam();
+  std::mt19937 prng;
+  std::uniform_real_distribution<double> uniform(0.5, 1.0);
+  for (int num_blocks = kMinNumBlocks; num_blocks < kMaxNumBlocks;
+       ++num_blocks) {
+    for (int trial = 0; trial < kNumTrials; ++trial) {
+      CompressedRowSparseMatrix::RandomMatrixOptions options;
+      options.num_col_blocks = num_blocks;
+      options.min_col_block_size = kMinBlockSize;
+      options.max_col_block_size = kMaxBlockSize;
+      options.num_row_blocks = 2 * num_blocks;
+      options.min_row_block_size = kMinBlockSize;
+      options.max_row_block_size = kMaxBlockSize;
+      options.block_density = uniform(prng);
+      options.storage_type =
+          CompressedRowSparseMatrix::StorageType::UNSYMMETRIC;
+      auto matrix =
+          CompressedRowSparseMatrix::CreateRandomMatrix(options, prng);
+      const int num_rows = matrix->num_rows();
+      const int num_cols = matrix->num_cols();
+
+      Vector x(num_cols);
+      x.setRandom();
+
+      Vector actual_y(num_rows);
+      actual_y.setZero();
+      matrix->RightMultiplyAndAccumulate(
+          x.data(), actual_y.data(), &context_, kNumThreads);
+
+      Matrix dense;
+      matrix->ToDenseMatrix(&dense);
+      Vector expected_y = dense * x;
+
+      ASSERT_NEAR((expected_y - actual_y).norm() / actual_y.norm(),
+                  0.0,
+                  std::numeric_limits<double>::epsilon() * 10)
+          << "\n"
+          << dense << "x:\n"
+          << x.transpose() << "\n"
+          << "expected: \n"
+          << expected_y.transpose() << "\n"
+          << "actual: \n"
+          << actual_y.transpose();
+    }
+  }
+}
+INSTANTIATE_TEST_SUITE_P(ParallelProducts,
+                         CompressedRowSparseMatrixParallelTest,
+                         ::testing::Values(1, 2, 4, 8),
+                         ::testing::PrintToStringParamName());
+
 // TODO(sameeragarwal) Add tests for the random matrix creation methods.
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/concurrent_queue.h b/third_party/ceres/internal/ceres/concurrent_queue.h
index a04d147..5f490ab 100644
--- a/third_party/ceres/internal/ceres/concurrent_queue.h
+++ b/third_party/ceres/internal/ceres/concurrent_queue.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -38,8 +38,7 @@
 
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // A thread-safe multi-producer, multi-consumer queue for queueing items that
 // are typically handled asynchronously by multiple threads. The ConcurrentQueue
@@ -78,7 +77,7 @@
 class ConcurrentQueue {
  public:
   // Defaults the queue to blocking on Wait calls.
-  ConcurrentQueue() : wait_(true) {}
+  ConcurrentQueue() = default;
 
   // Atomically push an element onto the queue.  If a thread was waiting for an
   // element, wake it up.
@@ -149,10 +148,9 @@
   std::queue<T> queue_;
   // If true, signals that callers of Wait will block waiting to pop an
   // element off the queue.
-  bool wait_;
+  bool wait_{true};
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_INTERNAL_CONCURRENT_QUEUE_H_
diff --git a/third_party/ceres/internal/ceres/concurrent_queue_test.cc b/third_party/ceres/internal/ceres/concurrent_queue_test.cc
index 430111a..db1446f 100644
--- a/third_party/ceres/internal/ceres/concurrent_queue_test.cc
+++ b/third_party/ceres/internal/ceres/concurrent_queue_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -28,20 +28,16 @@
 //
 // Author: vitus@google.com (Michael Vitus)
 
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifdef CERES_USE_CXX_THREADS
+#include "ceres/concurrent_queue.h"
 
 #include <chrono>
 #include <thread>
 
-#include "ceres/concurrent_queue.h"
+#include "ceres/internal/config.h"
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // A basic test of push and pop.
 TEST(ConcurrentQueue, PushPop) {
@@ -300,7 +296,4 @@
   EXPECT_EQ(13456, value);
 }
 
-}  // namespace internal
-}  // namespace ceres
-
-#endif  // CERES_USE_CXX_THREADS
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/conditioned_cost_function.cc b/third_party/ceres/internal/ceres/conditioned_cost_function.cc
index fb4c52a..5c826a9 100644
--- a/third_party/ceres/internal/ceres/conditioned_cost_function.cc
+++ b/third_party/ceres/internal/ceres/conditioned_cost_function.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -98,7 +98,7 @@
       double** conditioner_derivative_pointer2 =
           &conditioner_derivative_pointer;
       if (!jacobians) {
-        conditioner_derivative_pointer2 = NULL;
+        conditioner_derivative_pointer2 = nullptr;
       }
 
       double unconditioned_residual = residuals[r];
diff --git a/third_party/ceres/internal/ceres/conditioned_cost_function_test.cc b/third_party/ceres/internal/ceres/conditioned_cost_function_test.cc
index f21f84c..e5938bc 100644
--- a/third_party/ceres/internal/ceres/conditioned_cost_function_test.cc
+++ b/third_party/ceres/internal/ceres/conditioned_cost_function_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -85,7 +85,7 @@
   VectorRef v2_vector(v2, kTestCostFunctionSize, 1);
   Matrix identity(kTestCostFunctionSize, kTestCostFunctionSize);
   identity.setIdentity();
-  NormalPrior* difference_cost_function = new NormalPrior(identity, v2_vector);
+  auto* difference_cost_function = new NormalPrior(identity, v2_vector);
 
   std::vector<CostFunction*> conditioners;
   for (int i = 0; i < kTestCostFunctionSize; i++) {
@@ -127,7 +127,7 @@
   VectorRef v2_vector(v2, kTestCostFunctionSize, 1);
   Matrix identity =
       Matrix::Identity(kTestCostFunctionSize, kTestCostFunctionSize);
-  NormalPrior* difference_cost_function = new NormalPrior(identity, v2_vector);
+  auto* difference_cost_function = new NormalPrior(identity, v2_vector);
   CostFunction* conditioner = new LinearCostFunction(2, 7);
   std::vector<CostFunction*> conditioners;
   for (int i = 0; i < kTestCostFunctionSize; i++) {
diff --git a/third_party/ceres/internal/ceres/conjugate_gradients_solver.cc b/third_party/ceres/internal/ceres/conjugate_gradients_solver.cc
deleted file mode 100644
index 3019628..0000000
--- a/third_party/ceres/internal/ceres/conjugate_gradients_solver.cc
+++ /dev/null
@@ -1,252 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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 Google Inc. 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.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-//
-// A preconditioned conjugate gradients solver
-// (ConjugateGradientsSolver) for positive semidefinite linear
-// systems.
-//
-// We have also augmented the termination criterion used by this
-// solver to support not just residual based termination but also
-// termination based on decrease in the value of the quadratic model
-// that CG optimizes.
-
-#include "ceres/conjugate_gradients_solver.h"
-
-#include <cmath>
-#include <cstddef>
-
-#include "ceres/internal/eigen.h"
-#include "ceres/linear_operator.h"
-#include "ceres/stringprintf.h"
-#include "ceres/types.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-namespace {
-
-bool IsZeroOrInfinity(double x) { return ((x == 0.0) || std::isinf(x)); }
-
-}  // namespace
-
-ConjugateGradientsSolver::ConjugateGradientsSolver(
-    const LinearSolver::Options& options)
-    : options_(options) {}
-
-LinearSolver::Summary ConjugateGradientsSolver::Solve(
-    LinearOperator* A,
-    const double* b,
-    const LinearSolver::PerSolveOptions& per_solve_options,
-    double* x) {
-  CHECK(A != nullptr);
-  CHECK(x != nullptr);
-  CHECK(b != nullptr);
-  CHECK_EQ(A->num_rows(), A->num_cols());
-
-  LinearSolver::Summary summary;
-  summary.termination_type = LINEAR_SOLVER_NO_CONVERGENCE;
-  summary.message = "Maximum number of iterations reached.";
-  summary.num_iterations = 0;
-
-  const int num_cols = A->num_cols();
-  VectorRef xref(x, num_cols);
-  ConstVectorRef bref(b, num_cols);
-
-  const double norm_b = bref.norm();
-  if (norm_b == 0.0) {
-    xref.setZero();
-    summary.termination_type = LINEAR_SOLVER_SUCCESS;
-    summary.message = "Convergence. |b| = 0.";
-    return summary;
-  }
-
-  Vector r(num_cols);
-  Vector p(num_cols);
-  Vector z(num_cols);
-  Vector tmp(num_cols);
-
-  const double tol_r = per_solve_options.r_tolerance * norm_b;
-
-  tmp.setZero();
-  A->RightMultiply(x, tmp.data());
-  r = bref - tmp;
-  double norm_r = r.norm();
-  if (options_.min_num_iterations == 0 && norm_r <= tol_r) {
-    summary.termination_type = LINEAR_SOLVER_SUCCESS;
-    summary.message =
-        StringPrintf("Convergence. |r| = %e <= %e.", norm_r, tol_r);
-    return summary;
-  }
-
-  double rho = 1.0;
-
-  // Initial value of the quadratic model Q = x'Ax - 2 * b'x.
-  double Q0 = -1.0 * xref.dot(bref + r);
-
-  for (summary.num_iterations = 1;; ++summary.num_iterations) {
-    // Apply preconditioner
-    if (per_solve_options.preconditioner != NULL) {
-      z.setZero();
-      per_solve_options.preconditioner->RightMultiply(r.data(), z.data());
-    } else {
-      z = r;
-    }
-
-    double last_rho = rho;
-    rho = r.dot(z);
-    if (IsZeroOrInfinity(rho)) {
-      summary.termination_type = LINEAR_SOLVER_FAILURE;
-      summary.message = StringPrintf("Numerical failure. rho = r'z = %e.", rho);
-      break;
-    }
-
-    if (summary.num_iterations == 1) {
-      p = z;
-    } else {
-      double beta = rho / last_rho;
-      if (IsZeroOrInfinity(beta)) {
-        summary.termination_type = LINEAR_SOLVER_FAILURE;
-        summary.message = StringPrintf(
-            "Numerical failure. beta = rho_n / rho_{n-1} = %e, "
-            "rho_n = %e, rho_{n-1} = %e",
-            beta,
-            rho,
-            last_rho);
-        break;
-      }
-      p = z + beta * p;
-    }
-
-    Vector& q = z;
-    q.setZero();
-    A->RightMultiply(p.data(), q.data());
-    const double pq = p.dot(q);
-    if ((pq <= 0) || std::isinf(pq)) {
-      summary.termination_type = LINEAR_SOLVER_NO_CONVERGENCE;
-      summary.message = StringPrintf(
-          "Matrix is indefinite, no more progress can be made. "
-          "p'q = %e. |p| = %e, |q| = %e",
-          pq,
-          p.norm(),
-          q.norm());
-      break;
-    }
-
-    const double alpha = rho / pq;
-    if (std::isinf(alpha)) {
-      summary.termination_type = LINEAR_SOLVER_FAILURE;
-      summary.message = StringPrintf(
-          "Numerical failure. alpha = rho / pq = %e, rho = %e, pq = %e.",
-          alpha,
-          rho,
-          pq);
-      break;
-    }
-
-    xref = xref + alpha * p;
-
-    // Ideally we would just use the update r = r - alpha*q to keep
-    // track of the residual vector. However this estimate tends to
-    // drift over time due to round off errors. Thus every
-    // residual_reset_period iterations, we calculate the residual as
-    // r = b - Ax. We do not do this every iteration because this
-    // requires an additional matrix vector multiply which would
-    // double the complexity of the CG algorithm.
-    if (summary.num_iterations % options_.residual_reset_period == 0) {
-      tmp.setZero();
-      A->RightMultiply(x, tmp.data());
-      r = bref - tmp;
-    } else {
-      r = r - alpha * q;
-    }
-
-    // Quadratic model based termination.
-    //   Q1 = x'Ax - 2 * b' x.
-    const double Q1 = -1.0 * xref.dot(bref + r);
-
-    // For PSD matrices A, let
-    //
-    //   Q(x) = x'Ax - 2b'x
-    //
-    // be the cost of the quadratic function defined by A and b. Then,
-    // the solver terminates at iteration i if
-    //
-    //   i * (Q(x_i) - Q(x_i-1)) / Q(x_i) < q_tolerance.
-    //
-    // This termination criterion is more useful when using CG to
-    // solve the Newton step. This particular convergence test comes
-    // from Stephen Nash's work on truncated Newton
-    // methods. References:
-    //
-    //   1. Stephen G. Nash & Ariela Sofer, Assessing A Search
-    //   Direction Within A Truncated Newton Method, Operation
-    //   Research Letters 9(1990) 219-221.
-    //
-    //   2. Stephen G. Nash, A Survey of Truncated Newton Methods,
-    //   Journal of Computational and Applied Mathematics,
-    //   124(1-2), 45-59, 2000.
-    //
-    const double zeta = summary.num_iterations * (Q1 - Q0) / Q1;
-    if (zeta < per_solve_options.q_tolerance &&
-        summary.num_iterations >= options_.min_num_iterations) {
-      summary.termination_type = LINEAR_SOLVER_SUCCESS;
-      summary.message =
-          StringPrintf("Iteration: %d Convergence: zeta = %e < %e. |r| = %e",
-                       summary.num_iterations,
-                       zeta,
-                       per_solve_options.q_tolerance,
-                       r.norm());
-      break;
-    }
-    Q0 = Q1;
-
-    // Residual based termination.
-    norm_r = r.norm();
-    if (norm_r <= tol_r &&
-        summary.num_iterations >= options_.min_num_iterations) {
-      summary.termination_type = LINEAR_SOLVER_SUCCESS;
-      summary.message =
-          StringPrintf("Iteration: %d Convergence. |r| = %e <= %e.",
-                       summary.num_iterations,
-                       norm_r,
-                       tol_r);
-      break;
-    }
-
-    if (summary.num_iterations >= options_.max_num_iterations) {
-      break;
-    }
-  }
-
-  return summary;
-}
-
-}  // namespace internal
-}  // namespace ceres
diff --git a/third_party/ceres/internal/ceres/conjugate_gradients_solver.h b/third_party/ceres/internal/ceres/conjugate_gradients_solver.h
index f79ca49..84383ea 100644
--- a/third_party/ceres/internal/ceres/conjugate_gradients_solver.h
+++ b/third_party/ceres/internal/ceres/conjugate_gradients_solver.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -34,40 +34,278 @@
 #ifndef CERES_INTERNAL_CONJUGATE_GRADIENTS_SOLVER_H_
 #define CERES_INTERNAL_CONJUGATE_GRADIENTS_SOLVER_H_
 
-#include "ceres/internal/port.h"
+#include <cmath>
+#include <cstddef>
+#include <utility>
+
+#include "ceres/eigen_vector_ops.h"
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/export.h"
+#include "ceres/linear_operator.h"
 #include "ceres/linear_solver.h"
+#include "ceres/stringprintf.h"
+#include "ceres/types.h"
+#include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
-class LinearOperator;
-
-// This class implements the now classical Conjugate Gradients
-// algorithm of Hestenes & Stiefel for solving postive semidefinite
-// linear sytems. Optionally it can use a preconditioner also to
-// reduce the condition number of the linear system and improve the
-// convergence rate. Modern references for Conjugate Gradients are the
-// books by Yousef Saad and Trefethen & Bau. This implementation of CG
-// has been augmented with additional termination tests that are
-// needed for forcing early termination when used as part of an
-// inexact Newton solver.
-//
-// For more details see the documentation for
-// LinearSolver::PerSolveOptions::r_tolerance and
-// LinearSolver::PerSolveOptions::q_tolerance in linear_solver.h.
-class CERES_EXPORT_INTERNAL ConjugateGradientsSolver : public LinearSolver {
+// Interface for the linear operator used by ConjugateGradientsSolver.
+template <typename DenseVectorType>
+class ConjugateGradientsLinearOperator {
  public:
-  explicit ConjugateGradientsSolver(const LinearSolver::Options& options);
-  Summary Solve(LinearOperator* A,
-                const double* b,
-                const LinearSolver::PerSolveOptions& per_solve_options,
-                double* x) final;
-
- private:
-  const LinearSolver::Options options_;
+  ~ConjugateGradientsLinearOperator() = default;
+  virtual void RightMultiplyAndAccumulate(const DenseVectorType& x,
+                                          DenseVectorType& y) = 0;
 };
 
-}  // namespace internal
-}  // namespace ceres
+// Adapter class that makes LinearOperator appear like an instance of
+// ConjugateGradientsLinearOperator.
+class LinearOperatorAdapter : public ConjugateGradientsLinearOperator<Vector> {
+ public:
+  LinearOperatorAdapter(LinearOperator& linear_operator)
+      : linear_operator_(linear_operator) {}
+
+  void RightMultiplyAndAccumulate(const Vector& x, Vector& y) final {
+    linear_operator_.RightMultiplyAndAccumulate(x, y);
+  }
+
+ private:
+  LinearOperator& linear_operator_;
+};
+
+// Options to control the ConjugateGradientsSolver. For detailed documentation
+// for each of these options see linear_solver.h
+struct ConjugateGradientsSolverOptions {
+  int min_num_iterations = 1;
+  int max_num_iterations = 1;
+  int residual_reset_period = 10;
+  double r_tolerance = 0.0;
+  double q_tolerance = 0.0;
+  ContextImpl* context = nullptr;
+  int num_threads = 1;
+};
+
+// This function implements the now classical Conjugate Gradients algorithm of
+// Hestenes & Stiefel for solving positive semidefinite linear systems.
+// Optionally it can use a preconditioner also to reduce the condition number of
+// the linear system and improve the convergence rate. Modern references for
+// Conjugate Gradients are the books by Yousef Saad and Trefethen & Bau. This
+// implementation of CG has been augmented with additional termination tests
+// that are needed for forcing early termination when used as part of an inexact
+// Newton solver.
+//
+// This implementation is templated over DenseVectorType and then in turn on
+// ConjugateGradientsLinearOperator, which allows us to write an abstract
+// implementaion of the Conjugate Gradients algorithm without worrying about how
+// these objects are implemented or where they are stored. In particular it
+// allows us to have a single implementation that works on CPU and GPU based
+// matrices and vectors.
+//
+// scratch must contain pointers to four DenseVector objects of the same size as
+// rhs and solution. By asking the user for scratch space, we guarantee that we
+// will not perform any allocations inside this function.
+template <typename DenseVectorType>
+LinearSolver::Summary ConjugateGradientsSolver(
+    const ConjugateGradientsSolverOptions options,
+    ConjugateGradientsLinearOperator<DenseVectorType>& lhs,
+    const DenseVectorType& rhs,
+    ConjugateGradientsLinearOperator<DenseVectorType>& preconditioner,
+    DenseVectorType* scratch[4],
+    DenseVectorType& solution) {
+  auto IsZeroOrInfinity = [](double x) {
+    return ((x == 0.0) || std::isinf(x));
+  };
+
+  DenseVectorType& p = *scratch[0];
+  DenseVectorType& r = *scratch[1];
+  DenseVectorType& z = *scratch[2];
+  DenseVectorType& tmp = *scratch[3];
+
+  LinearSolver::Summary summary;
+  summary.termination_type = LinearSolverTerminationType::NO_CONVERGENCE;
+  summary.message = "Maximum number of iterations reached.";
+  summary.num_iterations = 0;
+
+  const double norm_rhs = Norm(rhs, options.context, options.num_threads);
+  if (norm_rhs == 0.0) {
+    SetZero(solution, options.context, options.num_threads);
+    summary.termination_type = LinearSolverTerminationType::SUCCESS;
+    summary.message = "Convergence. |b| = 0.";
+    return summary;
+  }
+
+  const double tol_r = options.r_tolerance * norm_rhs;
+
+  SetZero(tmp, options.context, options.num_threads);
+  lhs.RightMultiplyAndAccumulate(solution, tmp);
+
+  // r = rhs - tmp
+  Axpby(1.0, rhs, -1.0, tmp, r, options.context, options.num_threads);
+
+  double norm_r = Norm(r, options.context, options.num_threads);
+  if (options.min_num_iterations == 0 && norm_r <= tol_r) {
+    summary.termination_type = LinearSolverTerminationType::SUCCESS;
+    summary.message =
+        StringPrintf("Convergence. |r| = %e <= %e.", norm_r, tol_r);
+    return summary;
+  }
+
+  double rho = 1.0;
+
+  // Initial value of the quadratic model Q = x'Ax - 2 * b'x.
+  // double Q0 = -1.0 * solution.dot(rhs + r);
+  Axpby(1.0, rhs, 1.0, r, tmp, options.context, options.num_threads);
+  double Q0 = -Dot(solution, tmp, options.context, options.num_threads);
+
+  for (summary.num_iterations = 1;; ++summary.num_iterations) {
+    SetZero(z, options.context, options.num_threads);
+    preconditioner.RightMultiplyAndAccumulate(r, z);
+
+    const double last_rho = rho;
+    // rho = r.dot(z);
+    rho = Dot(r, z, options.context, options.num_threads);
+    if (IsZeroOrInfinity(rho)) {
+      summary.termination_type = LinearSolverTerminationType::FAILURE;
+      summary.message = StringPrintf("Numerical failure. rho = r'z = %e.", rho);
+      break;
+    }
+
+    if (summary.num_iterations == 1) {
+      Copy(z, p, options.context, options.num_threads);
+    } else {
+      const double beta = rho / last_rho;
+      if (IsZeroOrInfinity(beta)) {
+        summary.termination_type = LinearSolverTerminationType::FAILURE;
+        summary.message = StringPrintf(
+            "Numerical failure. beta = rho_n / rho_{n-1} = %e, "
+            "rho_n = %e, rho_{n-1} = %e",
+            beta,
+            rho,
+            last_rho);
+        break;
+      }
+      // p = z + beta * p;
+      Axpby(1.0, z, beta, p, p, options.context, options.num_threads);
+    }
+
+    DenseVectorType& q = z;
+    SetZero(q, options.context, options.num_threads);
+    lhs.RightMultiplyAndAccumulate(p, q);
+    const double pq = Dot(p, q, options.context, options.num_threads);
+    if ((pq <= 0) || std::isinf(pq)) {
+      summary.termination_type = LinearSolverTerminationType::NO_CONVERGENCE;
+      summary.message = StringPrintf(
+          "Matrix is indefinite, no more progress can be made. "
+          "p'q = %e. |p| = %e, |q| = %e",
+          pq,
+          Norm(p, options.context, options.num_threads),
+          Norm(q, options.context, options.num_threads));
+      break;
+    }
+
+    const double alpha = rho / pq;
+    if (std::isinf(alpha)) {
+      summary.termination_type = LinearSolverTerminationType::FAILURE;
+      summary.message = StringPrintf(
+          "Numerical failure. alpha = rho / pq = %e, rho = %e, pq = %e.",
+          alpha,
+          rho,
+          pq);
+      break;
+    }
+
+    // solution = solution + alpha * p;
+    Axpby(1.0,
+          solution,
+          alpha,
+          p,
+          solution,
+          options.context,
+          options.num_threads);
+
+    // Ideally we would just use the update r = r - alpha*q to keep
+    // track of the residual vector. However this estimate tends to
+    // drift over time due to round off errors. Thus every
+    // residual_reset_period iterations, we calculate the residual as
+    // r = b - Ax. We do not do this every iteration because this
+    // requires an additional matrix vector multiply which would
+    // double the complexity of the CG algorithm.
+    if (summary.num_iterations % options.residual_reset_period == 0) {
+      SetZero(tmp, options.context, options.num_threads);
+      lhs.RightMultiplyAndAccumulate(solution, tmp);
+      Axpby(1.0, rhs, -1.0, tmp, r, options.context, options.num_threads);
+      // r = rhs - tmp;
+    } else {
+      Axpby(1.0, r, -alpha, q, r, options.context, options.num_threads);
+      // r = r - alpha * q;
+    }
+
+    // Quadratic model based termination.
+    //   Q1 = x'Ax - 2 * b' x.
+    // const double Q1 = -1.0 * solution.dot(rhs + r);
+    Axpby(1.0, rhs, 1.0, r, tmp, options.context, options.num_threads);
+    const double Q1 = -Dot(solution, tmp, options.context, options.num_threads);
+
+    // For PSD matrices A, let
+    //
+    //   Q(x) = x'Ax - 2b'x
+    //
+    // be the cost of the quadratic function defined by A and b. Then,
+    // the solver terminates at iteration i if
+    //
+    //   i * (Q(x_i) - Q(x_i-1)) / Q(x_i) < q_tolerance.
+    //
+    // This termination criterion is more useful when using CG to
+    // solve the Newton step. This particular convergence test comes
+    // from Stephen Nash's work on truncated Newton
+    // methods. References:
+    //
+    //   1. Stephen G. Nash & Ariela Sofer, Assessing A Search
+    //   Direction Within A Truncated Newton Method, Operation
+    //   Research Letters 9(1990) 219-221.
+    //
+    //   2. Stephen G. Nash, A Survey of Truncated Newton Methods,
+    //   Journal of Computational and Applied Mathematics,
+    //   124(1-2), 45-59, 2000.
+    //
+    const double zeta = summary.num_iterations * (Q1 - Q0) / Q1;
+    if (zeta < options.q_tolerance &&
+        summary.num_iterations >= options.min_num_iterations) {
+      summary.termination_type = LinearSolverTerminationType::SUCCESS;
+      summary.message =
+          StringPrintf("Iteration: %d Convergence: zeta = %e < %e. |r| = %e",
+                       summary.num_iterations,
+                       zeta,
+                       options.q_tolerance,
+                       Norm(r, options.context, options.num_threads));
+      break;
+    }
+    Q0 = Q1;
+
+    // Residual based termination.
+    norm_r = Norm(r, options.context, options.num_threads);
+    if (norm_r <= tol_r &&
+        summary.num_iterations >= options.min_num_iterations) {
+      summary.termination_type = LinearSolverTerminationType::SUCCESS;
+      summary.message =
+          StringPrintf("Iteration: %d Convergence. |r| = %e <= %e.",
+                       summary.num_iterations,
+                       norm_r,
+                       tol_r);
+      break;
+    }
+
+    if (summary.num_iterations >= options.max_num_iterations) {
+      break;
+    }
+  }
+
+  return summary;
+}
+
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_CONJUGATE_GRADIENTS_SOLVER_H_
diff --git a/third_party/ceres/internal/ceres/conjugate_gradients_solver_test.cc b/third_party/ceres/internal/ceres/conjugate_gradients_solver_test.cc
index b11e522..4727564 100644
--- a/third_party/ceres/internal/ceres/conjugate_gradients_solver_test.cc
+++ b/third_party/ceres/internal/ceres/conjugate_gradients_solver_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -37,12 +37,12 @@
 
 #include "ceres/internal/eigen.h"
 #include "ceres/linear_solver.h"
+#include "ceres/preconditioner.h"
 #include "ceres/triplet_sparse_matrix.h"
 #include "ceres/types.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST(ConjugateGradientTest, Solves3x3IdentitySystem) {
   double diagonal[] = {1.0, 1.0, 1.0};
@@ -59,17 +59,27 @@
   x(1) = 1;
   x(2) = 1;
 
-  LinearSolver::Options options;
-  options.max_num_iterations = 10;
+  ConjugateGradientsSolverOptions cg_options;
+  cg_options.min_num_iterations = 1;
+  cg_options.max_num_iterations = 10;
+  cg_options.residual_reset_period = 20;
+  cg_options.q_tolerance = 0.0;
+  cg_options.r_tolerance = 1e-9;
 
-  LinearSolver::PerSolveOptions per_solve_options;
-  per_solve_options.r_tolerance = 1e-9;
+  Vector scratch[4];
+  for (int i = 0; i < 4; ++i) {
+    scratch[i] = Vector::Zero(A->num_cols());
+  }
 
-  ConjugateGradientsSolver solver(options);
-  LinearSolver::Summary summary =
-      solver.Solve(A.get(), b.data(), per_solve_options, x.data());
+  IdentityPreconditioner identity(A->num_cols());
+  LinearOperatorAdapter lhs(*A);
+  LinearOperatorAdapter preconditioner(identity);
+  Vector* scratch_array[4] = {
+      &scratch[0], &scratch[1], &scratch[2], &scratch[3]};
+  auto summary = ConjugateGradientsSolver(
+      cg_options, lhs, b, preconditioner, scratch_array, x);
 
-  EXPECT_EQ(summary.termination_type, LINEAR_SOLVER_SUCCESS);
+  EXPECT_EQ(summary.termination_type, LinearSolverTerminationType::SUCCESS);
   ASSERT_EQ(summary.num_iterations, 1);
 
   ASSERT_DOUBLE_EQ(1, x(0));
@@ -115,22 +125,31 @@
   x(1) = 1;
   x(2) = 1;
 
-  LinearSolver::Options options;
-  options.max_num_iterations = 10;
+  ConjugateGradientsSolverOptions cg_options;
+  cg_options.min_num_iterations = 1;
+  cg_options.max_num_iterations = 10;
+  cg_options.residual_reset_period = 20;
+  cg_options.q_tolerance = 0.0;
+  cg_options.r_tolerance = 1e-9;
 
-  LinearSolver::PerSolveOptions per_solve_options;
-  per_solve_options.r_tolerance = 1e-9;
+  Vector scratch[4];
+  for (int i = 0; i < 4; ++i) {
+    scratch[i] = Vector::Zero(A->num_cols());
+  }
+  Vector* scratch_array[4] = {
+      &scratch[0], &scratch[1], &scratch[2], &scratch[3]};
+  IdentityPreconditioner identity(A->num_cols());
+  LinearOperatorAdapter lhs(*A);
+  LinearOperatorAdapter preconditioner(identity);
 
-  ConjugateGradientsSolver solver(options);
-  LinearSolver::Summary summary =
-      solver.Solve(A.get(), b.data(), per_solve_options, x.data());
+  auto summary = ConjugateGradientsSolver(
+      cg_options, lhs, b, preconditioner, scratch_array, x);
 
-  EXPECT_EQ(summary.termination_type, LINEAR_SOLVER_SUCCESS);
+  EXPECT_EQ(summary.termination_type, LinearSolverTerminationType::SUCCESS);
 
   ASSERT_DOUBLE_EQ(0, x(0));
   ASSERT_DOUBLE_EQ(1, x(1));
   ASSERT_DOUBLE_EQ(2, x(2));
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/context.cc b/third_party/ceres/internal/ceres/context.cc
index 55e7635..e5d85f6 100644
--- a/third_party/ceres/internal/ceres/context.cc
+++ b/third_party/ceres/internal/ceres/context.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -34,6 +34,8 @@
 
 namespace ceres {
 
+Context::Context() = default;
 Context* Context::Create() { return new internal::ContextImpl(); }
+Context::~Context() = default;
 
 }  // namespace ceres
diff --git a/third_party/ceres/internal/ceres/context_impl.cc b/third_party/ceres/internal/ceres/context_impl.cc
index 20fe5cb..2b9d9cc 100644
--- a/third_party/ceres/internal/ceres/context_impl.cc
+++ b/third_party/ceres/internal/ceres/context_impl.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -30,13 +30,167 @@
 
 #include "ceres/context_impl.h"
 
-namespace ceres {
-namespace internal {
+#include <string>
+
+#include "ceres/internal/config.h"
+#include "ceres/stringprintf.h"
+#include "ceres/wall_time.h"
+
+#ifndef CERES_NO_CUDA
+#include "cublas_v2.h"
+#include "cuda_runtime.h"
+#include "cusolverDn.h"
+#endif  // CERES_NO_CUDA
+
+namespace ceres::internal {
+
+ContextImpl::ContextImpl() = default;
+
+#ifndef CERES_NO_CUDA
+void ContextImpl::TearDown() {
+  if (cusolver_handle_ != nullptr) {
+    cusolverDnDestroy(cusolver_handle_);
+    cusolver_handle_ = nullptr;
+  }
+  if (cublas_handle_ != nullptr) {
+    cublasDestroy(cublas_handle_);
+    cublas_handle_ = nullptr;
+  }
+  if (cusparse_handle_ != nullptr) {
+    cusparseDestroy(cusparse_handle_);
+    cusparse_handle_ = nullptr;
+  }
+  for (auto& s : streams_) {
+    if (s != nullptr) {
+      cudaStreamDestroy(s);
+      s = nullptr;
+    }
+  }
+  is_cuda_initialized_ = false;
+}
+
+std::string ContextImpl::CudaConfigAsString() const {
+  return ceres::internal::StringPrintf(
+      "======================= CUDA Device Properties ======================\n"
+      "Cuda version              : %d.%d\n"
+      "Device ID                 : %d\n"
+      "Device name               : %s\n"
+      "Total GPU memory          : %6.f MiB\n"
+      "GPU memory available      : %6.f MiB\n"
+      "Compute capability        : %d.%d\n"
+      "Warp size                 : %d\n"
+      "Max threads per block     : %d\n"
+      "Max threads per dim       : %d %d %d\n"
+      "Max grid size             : %d %d %d\n"
+      "Multiprocessor count      : %d\n"
+      "cudaMallocAsync supported : %s\n"
+      "====================================================================",
+      cuda_version_major_,
+      cuda_version_minor_,
+      gpu_device_id_in_use_,
+      gpu_device_properties_.name,
+      gpu_device_properties_.totalGlobalMem / 1024.0 / 1024.0,
+      GpuMemoryAvailable() / 1024.0 / 1024.0,
+      gpu_device_properties_.major,
+      gpu_device_properties_.minor,
+      gpu_device_properties_.warpSize,
+      gpu_device_properties_.maxThreadsPerBlock,
+      gpu_device_properties_.maxThreadsDim[0],
+      gpu_device_properties_.maxThreadsDim[1],
+      gpu_device_properties_.maxThreadsDim[2],
+      gpu_device_properties_.maxGridSize[0],
+      gpu_device_properties_.maxGridSize[1],
+      gpu_device_properties_.maxGridSize[2],
+      gpu_device_properties_.multiProcessorCount,
+      // In CUDA 12.0.0+ cudaDeviceProp has field memoryPoolsSupported, but it
+      // is not available in older versions
+      is_cuda_memory_pools_supported_ ? "Yes" : "No");
+}
+
+size_t ContextImpl::GpuMemoryAvailable() const {
+  size_t free, total;
+  cudaMemGetInfo(&free, &total);
+  return free;
+}
+
+bool ContextImpl::InitCuda(std::string* message) {
+  if (is_cuda_initialized_) {
+    return true;
+  }
+  CHECK_EQ(cudaGetDevice(&gpu_device_id_in_use_), cudaSuccess);
+  int cuda_version;
+  CHECK_EQ(cudaRuntimeGetVersion(&cuda_version), cudaSuccess);
+  cuda_version_major_ = cuda_version / 1000;
+  cuda_version_minor_ = (cuda_version % 1000) / 10;
+  CHECK_EQ(
+      cudaGetDeviceProperties(&gpu_device_properties_, gpu_device_id_in_use_),
+      cudaSuccess);
+#if CUDART_VERSION >= 11020
+  int is_cuda_memory_pools_supported;
+  CHECK_EQ(cudaDeviceGetAttribute(&is_cuda_memory_pools_supported,
+                                  cudaDevAttrMemoryPoolsSupported,
+                                  gpu_device_id_in_use_),
+           cudaSuccess);
+  is_cuda_memory_pools_supported_ = is_cuda_memory_pools_supported == 1;
+#endif
+  VLOG(3) << "\n" << CudaConfigAsString();
+  EventLogger event_logger("InitCuda");
+  if (cublasCreate(&cublas_handle_) != CUBLAS_STATUS_SUCCESS) {
+    *message =
+        "CUDA initialization failed because cuBLAS::cublasCreate failed.";
+    cublas_handle_ = nullptr;
+    return false;
+  }
+  event_logger.AddEvent("cublasCreate");
+  if (cusolverDnCreate(&cusolver_handle_) != CUSOLVER_STATUS_SUCCESS) {
+    *message =
+        "CUDA initialization failed because cuSolverDN::cusolverDnCreate "
+        "failed.";
+    TearDown();
+    return false;
+  }
+  event_logger.AddEvent("cusolverDnCreate");
+  if (cusparseCreate(&cusparse_handle_) != CUSPARSE_STATUS_SUCCESS) {
+    *message =
+        "CUDA initialization failed because cuSPARSE::cusparseCreate failed.";
+    TearDown();
+    return false;
+  }
+  event_logger.AddEvent("cusparseCreate");
+  for (auto& s : streams_) {
+    if (cudaStreamCreateWithFlags(&s, cudaStreamNonBlocking) != cudaSuccess) {
+      *message =
+          "CUDA initialization failed because CUDA::cudaStreamCreateWithFlags "
+          "failed.";
+      TearDown();
+      return false;
+    }
+  }
+  event_logger.AddEvent("cudaStreamCreateWithFlags");
+  if (cusolverDnSetStream(cusolver_handle_, DefaultStream()) !=
+          CUSOLVER_STATUS_SUCCESS ||
+      cublasSetStream(cublas_handle_, DefaultStream()) !=
+          CUBLAS_STATUS_SUCCESS ||
+      cusparseSetStream(cusparse_handle_, DefaultStream()) !=
+          CUSPARSE_STATUS_SUCCESS) {
+    *message = "CUDA initialization failed because SetStream failed.";
+    TearDown();
+    return false;
+  }
+  event_logger.AddEvent("SetStream");
+  is_cuda_initialized_ = true;
+  return true;
+}
+#endif  // CERES_NO_CUDA
+
+ContextImpl::~ContextImpl() {
+#ifndef CERES_NO_CUDA
+  TearDown();
+#endif  // CERES_NO_CUDA
+}
 
 void ContextImpl::EnsureMinimumThreads(int num_threads) {
-#ifdef CERES_USE_CXX_THREADS
   thread_pool.Resize(num_threads);
-#endif  // CERES_USE_CXX_THREADS
 }
-}  // namespace internal
-}  // namespace ceres
+
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/context_impl.h b/third_party/ceres/internal/ceres/context_impl.h
index 574d1ef..46692e6 100644
--- a/third_party/ceres/internal/ceres/context_impl.h
+++ b/third_party/ceres/internal/ceres/context_impl.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -33,37 +33,115 @@
 
 // This include must come before any #ifndef check on Ceres compile options.
 // clang-format off
-#include "ceres/internal/port.h"
-// clanf-format on
+#include "ceres/internal/config.h"
+// clang-format on
+
+#include <string>
 
 #include "ceres/context.h"
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 
-#ifdef CERES_USE_CXX_THREADS
+#ifndef CERES_NO_CUDA
+#include "cublas_v2.h"
+#include "cuda_runtime.h"
+#include "cusolverDn.h"
+#include "cusparse.h"
+#endif  // CERES_NO_CUDA
+
 #include "ceres/thread_pool.h"
-#endif  // CERES_USE_CXX_THREADS
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
-class CERES_EXPORT_INTERNAL ContextImpl : public Context {
+class CERES_NO_EXPORT ContextImpl final : public Context {
  public:
-  ContextImpl() {}
+  ContextImpl();
+  ~ContextImpl() override;
   ContextImpl(const ContextImpl&) = delete;
   void operator=(const ContextImpl&) = delete;
 
-  virtual ~ContextImpl() {}
-
   // When compiled with C++ threading support, resize the thread pool to have
   // at min(num_thread, num_hardware_threads) where num_hardware_threads is
   // defined by the hardware.  Otherwise this call is a no-op.
   void EnsureMinimumThreads(int num_threads);
 
-#ifdef CERES_USE_CXX_THREADS
   ThreadPool thread_pool;
-#endif  // CERES_USE_CXX_THREADS
+
+#ifndef CERES_NO_CUDA
+  // Note on Ceres' use of CUDA Devices on multi-GPU systems:
+  // 1. On a multi-GPU system, if nothing special is done, the "default" CUDA
+  //    device will be used, which is device 0.
+  // 2. If the user masks out GPUs using the  CUDA_VISIBLE_DEVICES  environment
+  //    variable, Ceres will still use device 0 visible to the program, but
+  //    device 0 will be the first GPU indicated in the environment variable.
+  // 3. If the user explicitly selects a GPU in the host process before calling
+  //    Ceres, Ceres will use that GPU.
+
+  // Note on Ceres' use of CUDA Streams:
+  // Most of operations on the GPU are performed using a single stream.  In
+  // those cases DefaultStream() should be used. This ensures that operations
+  // are stream-ordered, and might be concurrent with cpu processing with no
+  // additional efforts.
+  //
+  // a. Single-stream workloads
+  //  - Only use default stream
+  //  - Return control to the callee without synchronization whenever possible
+  //  - Stream synchronization occurs only after GPU to CPU transfers, and is
+  //  handled by CudaBuffer
+  //
+  // b. Multi-stream workloads
+  // Multi-stream workloads are more restricted in order to make it harder to
+  // get a race-condition.
+  //  - Should always synchronize the default stream on entry
+  //  - Should always synchronize all utilized streams on exit
+  //  - Should not make any assumptions on one of streams_[] being default
+  //
+  // With those rules in place
+  //  - All single-stream asynchronous workloads are serialized using default
+  //  stream
+  //  - Multiple-stream workloads always wait single-stream workloads to finish
+  //  and leave no running computations on exit.
+  //  This slightly penalizes multi-stream workloads, but makes it easier to
+  //  avoid race conditions when  multiple-stream workload depends on results of
+  //  any preceeding gpu computations.
+
+  // Initializes cuBLAS, cuSOLVER, and cuSPARSE contexts, creates an
+  // asynchronous CUDA stream, and associates the stream with the contexts.
+  // Returns true iff initialization was successful, else it returns false and a
+  // human-readable error message is returned.
+  bool InitCuda(std::string* message);
+  void TearDown();
+  inline bool IsCudaInitialized() const { return is_cuda_initialized_; }
+  // Returns a human-readable string describing the capabilities of the current
+  // CUDA device. CudaConfigAsString can only be called after InitCuda has been
+  // called.
+  std::string CudaConfigAsString() const;
+  // Returns the number of bytes of available global memory on the current CUDA
+  // device. If it is called before InitCuda, it returns 0.
+  size_t GpuMemoryAvailable() const;
+
+  cusolverDnHandle_t cusolver_handle_ = nullptr;
+  cublasHandle_t cublas_handle_ = nullptr;
+
+  // Default stream.
+  // Kernel invocations and memory copies on this stream can be left without
+  // synchronization.
+  cudaStream_t DefaultStream() { return streams_[0]; }
+  static constexpr int kNumCudaStreams = 2;
+  cudaStream_t streams_[kNumCudaStreams] = {0};
+
+  cusparseHandle_t cusparse_handle_ = nullptr;
+  bool is_cuda_initialized_ = false;
+  int gpu_device_id_in_use_ = -1;
+  cudaDeviceProp gpu_device_properties_;
+  bool is_cuda_memory_pools_supported_ = false;
+  int cuda_version_major_ = 0;
+  int cuda_version_minor_ = 0;
+#endif  // CERES_NO_CUDA
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_CONTEXT_IMPL_H_
diff --git a/third_party/ceres/internal/ceres/coordinate_descent_minimizer.cc b/third_party/ceres/internal/ceres/coordinate_descent_minimizer.cc
index 93096ac..53986ee 100644
--- a/third_party/ceres/internal/ceres/coordinate_descent_minimizer.cc
+++ b/third_party/ceres/internal/ceres/coordinate_descent_minimizer.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -32,8 +32,11 @@
 
 #include <algorithm>
 #include <iterator>
+#include <map>
 #include <memory>
 #include <numeric>
+#include <set>
+#include <string>
 #include <vector>
 
 #include "ceres/evaluator.h"
@@ -49,36 +52,32 @@
 #include "ceres/trust_region_minimizer.h"
 #include "ceres/trust_region_strategy.h"
 
-namespace ceres {
-namespace internal {
-
-using std::map;
-using std::max;
-using std::min;
-using std::set;
-using std::string;
-using std::vector;
+namespace ceres::internal {
 
 CoordinateDescentMinimizer::CoordinateDescentMinimizer(ContextImpl* context)
     : context_(context) {
   CHECK(context_ != nullptr);
 }
 
-CoordinateDescentMinimizer::~CoordinateDescentMinimizer() {}
+CoordinateDescentMinimizer::~CoordinateDescentMinimizer() = default;
 
 bool CoordinateDescentMinimizer::Init(
     const Program& program,
     const ProblemImpl::ParameterMap& parameter_map,
     const ParameterBlockOrdering& ordering,
-    string* error) {
+    std::string* /*error*/) {
   parameter_blocks_.clear();
   independent_set_offsets_.clear();
   independent_set_offsets_.push_back(0);
 
   // Serialize the OrderedGroups into a vector of parameter block
   // offsets for parallel access.
-  map<ParameterBlock*, int> parameter_block_index;
-  map<int, set<double*>> group_to_elements = ordering.group_to_elements();
+
+  // TODO(sameeragarwal): Investigate if parameter_block_index should be an
+  // ordered or an unordered container.
+  std::map<ParameterBlock*, int> parameter_block_index;
+  std::map<int, std::set<double*>> group_to_elements =
+      ordering.group_to_elements();
   for (const auto& g_t_e : group_to_elements) {
     const auto& elements = g_t_e.second;
     for (double* parameter_block : elements) {
@@ -93,10 +92,11 @@
   // The ordering does not have to contain all parameter blocks, so
   // assign zero offsets/empty independent sets to these parameter
   // blocks.
-  const vector<ParameterBlock*>& parameter_blocks = program.parameter_blocks();
-  for (int i = 0; i < parameter_blocks.size(); ++i) {
-    if (!ordering.IsMember(parameter_blocks[i]->mutable_user_state())) {
-      parameter_blocks_.push_back(parameter_blocks[i]);
+  const std::vector<ParameterBlock*>& parameter_blocks =
+      program.parameter_blocks();
+  for (auto* parameter_block : parameter_blocks) {
+    if (!ordering.IsMember(parameter_block->mutable_user_state())) {
+      parameter_blocks_.push_back(parameter_block);
       independent_set_offsets_.push_back(independent_set_offsets_.back());
     }
   }
@@ -104,9 +104,9 @@
   // Compute the set of residual blocks that depend on each parameter
   // block.
   residual_blocks_.resize(parameter_block_index.size());
-  const vector<ResidualBlock*>& residual_blocks = program.residual_blocks();
-  for (int i = 0; i < residual_blocks.size(); ++i) {
-    ResidualBlock* residual_block = residual_blocks[i];
+  const std::vector<ResidualBlock*>& residual_blocks =
+      program.residual_blocks();
+  for (auto* residual_block : residual_blocks) {
     const int num_parameter_blocks = residual_block->NumParameterBlocks();
     for (int j = 0; j < num_parameter_blocks; ++j) {
       ParameterBlock* parameter_block = residual_block->parameter_blocks()[j];
@@ -127,16 +127,15 @@
 
 void CoordinateDescentMinimizer::Minimize(const Minimizer::Options& options,
                                           double* parameters,
-                                          Solver::Summary* summary) {
+                                          Solver::Summary* /*summary*/) {
   // Set the state and mark all parameter blocks constant.
-  for (int i = 0; i < parameter_blocks_.size(); ++i) {
-    ParameterBlock* parameter_block = parameter_blocks_[i];
+  for (auto* parameter_block : parameter_blocks_) {
     parameter_block->SetState(parameters + parameter_block->state_offset());
     parameter_block->SetConstant();
   }
 
-  std::unique_ptr<LinearSolver*[]> linear_solvers(
-      new LinearSolver*[options.num_threads]);
+  std::vector<std::unique_ptr<LinearSolver>> linear_solvers(
+      options.num_threads);
 
   LinearSolver::Options linear_solver_options;
   linear_solver_options.type = DENSE_QR;
@@ -155,9 +154,9 @@
     }
 
     const int num_inner_iteration_threads =
-        min(options.num_threads, num_problems);
+        std::min(options.num_threads, num_problems);
     evaluator_options_.num_threads =
-        max(1, options.num_threads / num_inner_iteration_threads);
+        std::max(1, options.num_threads / num_inner_iteration_threads);
 
     // The parameter blocks in each independent set can be optimized
     // in parallel, since they do not co-occur in any residual block.
@@ -170,9 +169,11 @@
           ParameterBlock* parameter_block = parameter_blocks_[j];
           const int old_index = parameter_block->index();
           const int old_delta_offset = parameter_block->delta_offset();
+          const int old_state_offset = parameter_block->state_offset();
           parameter_block->SetVarying();
           parameter_block->set_index(0);
           parameter_block->set_delta_offset(0);
+          parameter_block->set_state_offset(0);
 
           Program inner_program;
           inner_program.mutable_parameter_blocks()->push_back(parameter_block);
@@ -188,24 +189,21 @@
           // we are fine.
           Solver::Summary inner_summary;
           Solve(&inner_program,
-                linear_solvers[thread_id],
-                parameters + parameter_block->state_offset(),
+                linear_solvers[thread_id].get(),
+                parameters + old_state_offset,
                 &inner_summary);
 
           parameter_block->set_index(old_index);
           parameter_block->set_delta_offset(old_delta_offset);
+          parameter_block->set_state_offset(old_state_offset);
           parameter_block->SetState(parameters +
                                     parameter_block->state_offset());
           parameter_block->SetConstant();
         });
   }
 
-  for (int i = 0; i < parameter_blocks_.size(); ++i) {
-    parameter_blocks_[i]->SetVarying();
-  }
-
-  for (int i = 0; i < options.num_threads; ++i) {
-    delete linear_solvers[i];
+  for (auto* parameter_block : parameter_blocks_) {
+    parameter_block->SetVarying();
   }
 }
 
@@ -218,20 +216,19 @@
   summary->initial_cost = 0.0;
   summary->fixed_cost = 0.0;
   summary->final_cost = 0.0;
-  string error;
+  std::string error;
 
   Minimizer::Options minimizer_options;
-  minimizer_options.evaluator.reset(
-      Evaluator::Create(evaluator_options_, program, &error));
+  minimizer_options.evaluator =
+      Evaluator::Create(evaluator_options_, program, &error);
   CHECK(minimizer_options.evaluator != nullptr);
-  minimizer_options.jacobian.reset(
-      minimizer_options.evaluator->CreateJacobian());
+  minimizer_options.jacobian = minimizer_options.evaluator->CreateJacobian();
   CHECK(minimizer_options.jacobian != nullptr);
 
   TrustRegionStrategy::Options trs_options;
   trs_options.linear_solver = linear_solver;
-  minimizer_options.trust_region_strategy.reset(
-      TrustRegionStrategy::Create(trs_options));
+  minimizer_options.trust_region_strategy =
+      TrustRegionStrategy::Create(trs_options);
   CHECK(minimizer_options.trust_region_strategy != nullptr);
   minimizer_options.is_silent = true;
 
@@ -242,8 +239,10 @@
 bool CoordinateDescentMinimizer::IsOrderingValid(
     const Program& program,
     const ParameterBlockOrdering& ordering,
-    string* message) {
-  const map<int, set<double*>>& group_to_elements =
+    std::string* message) {
+  // TODO(sameeragarwal): Investigate if this should be an ordered or an
+  // unordered group.
+  const std::map<int, std::set<double*>>& group_to_elements =
       ordering.group_to_elements();
 
   // Verify that each group is an independent set
@@ -263,13 +262,12 @@
 // of independent sets of decreasing size and invert it. This
 // seems to work better in practice, i.e., Cameras before
 // points.
-ParameterBlockOrdering* CoordinateDescentMinimizer::CreateOrdering(
-    const Program& program) {
-  std::unique_ptr<ParameterBlockOrdering> ordering(new ParameterBlockOrdering);
+std::shared_ptr<ParameterBlockOrdering>
+CoordinateDescentMinimizer::CreateOrdering(const Program& program) {
+  auto ordering = std::make_shared<ParameterBlockOrdering>();
   ComputeRecursiveIndependentSetOrdering(program, ordering.get());
   ordering->Reverse();
-  return ordering.release();
+  return ordering;
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/coordinate_descent_minimizer.h b/third_party/ceres/internal/ceres/coordinate_descent_minimizer.h
index 7d17d53..8fc5dd7 100644
--- a/third_party/ceres/internal/ceres/coordinate_descent_minimizer.h
+++ b/third_party/ceres/internal/ceres/coordinate_descent_minimizer.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -31,6 +31,7 @@
 #ifndef CERES_INTERNAL_COORDINATE_DESCENT_MINIMIZER_H_
 #define CERES_INTERNAL_COORDINATE_DESCENT_MINIMIZER_H_
 
+#include <memory>
 #include <string>
 #include <vector>
 
@@ -40,8 +41,7 @@
 #include "ceres/problem_impl.h"
 #include "ceres/solver.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 class Program;
 class LinearSolver;
@@ -56,7 +56,7 @@
 //
 // The minimizer assumes that none of the parameter blocks in the
 // program are constant.
-class CoordinateDescentMinimizer : public Minimizer {
+class CERES_NO_EXPORT CoordinateDescentMinimizer final : public Minimizer {
  public:
   explicit CoordinateDescentMinimizer(ContextImpl* context);
 
@@ -66,7 +66,7 @@
             std::string* error);
 
   // Minimizer interface.
-  virtual ~CoordinateDescentMinimizer();
+  ~CoordinateDescentMinimizer() override;
 
   void Minimize(const Minimizer::Options& options,
                 double* parameters,
@@ -81,7 +81,8 @@
   // of independent sets of decreasing size and invert it. This
   // seems to work better in practice, i.e., Cameras before
   // points.
-  static ParameterBlockOrdering* CreateOrdering(const Program& program);
+  static std::shared_ptr<ParameterBlockOrdering> CreateOrdering(
+      const Program& program);
 
  private:
   void Solve(Program* program,
@@ -102,7 +103,6 @@
   ContextImpl* context_;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_INTERNAL_COORDINATE_DESCENT_MINIMIZER_H_
diff --git a/third_party/ceres/internal/ceres/corrector.cc b/third_party/ceres/internal/ceres/corrector.cc
index 6a79a06..d9b80cd 100644
--- a/third_party/ceres/internal/ceres/corrector.cc
+++ b/third_party/ceres/internal/ceres/corrector.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -36,8 +36,7 @@
 #include "ceres/internal/eigen.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 Corrector::Corrector(const double sq_norm, const double rho[3]) {
   CHECK_GE(sq_norm, 0.0);
@@ -88,7 +87,7 @@
   // We now require that the first derivative of the loss function be
   // positive only if the second derivative is positive. This is
   // because when the second derivative is non-positive, we do not use
-  // the second order correction suggested by BANS and instead use a
+  // the second order correction suggested by BAMS and instead use a
   // simpler first order strategy which does not use a division by the
   // gradient of the loss function.
   CHECK_GT(rho[1], 0.0);
@@ -111,8 +110,8 @@
 }
 
 void Corrector::CorrectResiduals(const int num_rows, double* residuals) {
-  DCHECK(residuals != NULL);
-  // Equation 11 in BANS.
+  DCHECK(residuals != nullptr);
+  // Equation 11 in BAMS.
   VectorRef(residuals, num_rows) *= residual_scaling_;
 }
 
@@ -120,8 +119,8 @@
                                 const int num_cols,
                                 double* residuals,
                                 double* jacobian) {
-  DCHECK(residuals != NULL);
-  DCHECK(jacobian != NULL);
+  DCHECK(residuals != nullptr);
+  DCHECK(jacobian != nullptr);
 
   // The common case (rho[2] <= 0).
   if (alpha_sq_norm_ == 0.0) {
@@ -129,7 +128,7 @@
     return;
   }
 
-  // Equation 11 in BANS.
+  // Equation 11 in BAMS.
   //
   //  J = sqrt(rho) * (J - alpha^2 r * r' J)
   //
@@ -155,5 +154,4 @@
   }
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/corrector.h b/third_party/ceres/internal/ceres/corrector.h
index 3e11cdc..2216a96 100644
--- a/third_party/ceres/internal/ceres/corrector.h
+++ b/third_party/ceres/internal/ceres/corrector.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -30,15 +30,15 @@
 //
 // Class definition for the object that is responsible for applying a
 // second order correction to the Gauss-Newton based on the ideas in
-// BANS by Triggs et al.
+// BAMS by Triggs et al.
 
 #ifndef CERES_INTERNAL_CORRECTOR_H_
 #define CERES_INTERNAL_CORRECTOR_H_
 
-#include "ceres/internal/port.h"
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // Corrector is responsible for applying the second order correction
 // to the residual and jacobian of a least squares problem based on a
@@ -47,8 +47,8 @@
 // The key idea here is to look at the expressions for the robustified
 // gauss newton approximation and then take its square root to get the
 // corresponding corrections to the residual and jacobian.  For the
-// full expressions see Eq. 10 and 11 in BANS by Triggs et al.
-class CERES_EXPORT_INTERNAL Corrector {
+// full expressions see Eq. 10 and 11 in BAMS by Triggs et al.
+class CERES_NO_EXPORT Corrector {
  public:
   // The constructor takes the squared norm, the value, the first and
   // second derivatives of the LossFunction. It precalculates some of
@@ -86,7 +86,8 @@
   double residual_scaling_;
   double alpha_sq_norm_;
 };
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_CORRECTOR_H_
diff --git a/third_party/ceres/internal/ceres/corrector_test.cc b/third_party/ceres/internal/ceres/corrector_test.cc
index 951041e..0548336 100644
--- a/third_party/ceres/internal/ceres/corrector_test.cc
+++ b/third_party/ceres/internal/ceres/corrector_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -32,11 +32,10 @@
 
 #include <algorithm>
 #include <cmath>
-#include <cstdlib>
 #include <cstring>
+#include <random>
 
 #include "ceres/internal/eigen.h"
-#include "ceres/random.h"
 #include "gtest/gtest.h"
 
 namespace ceres {
@@ -160,18 +159,19 @@
   // and hessians.
   Matrix c_hess(2, 2);
   Vector c_grad(2);
-
-  srand(5);
+  std::mt19937 prng;
+  std::uniform_real_distribution<double> uniform01(0.0, 1.0);
   for (int iter = 0; iter < 10000; ++iter) {
     // Initialize the jacobian and residual.
-    for (int i = 0; i < 2 * 3; ++i) jacobian[i] = RandDouble();
-    for (int i = 0; i < 3; ++i) residuals[i] = RandDouble();
+    for (double& jacobian_entry : jacobian) jacobian_entry = uniform01(prng);
+    for (double& residual : residuals) residual = uniform01(prng);
 
     const double sq_norm = res.dot(res);
 
     rho[0] = sq_norm;
-    rho[1] = RandDouble();
-    rho[2] = 2.0 * RandDouble() - 1.0;
+    rho[1] = uniform01(prng);
+    rho[2] = uniform01(
+        prng, std::uniform_real_distribution<double>::param_type(-1, 1));
 
     // If rho[2] > 0, then the curvature correction to the correction
     // and the gauss newton approximation will match. Otherwise, we
@@ -227,10 +227,11 @@
   Matrix c_hess(2, 2);
   Vector c_grad(2);
 
-  srand(5);
+  std::mt19937 prng;
+  std::uniform_real_distribution<double> uniform01(0.0, 1.0);
   for (int iter = 0; iter < 10000; ++iter) {
     // Initialize the jacobian.
-    for (int i = 0; i < 2 * 3; ++i) jacobian[i] = RandDouble();
+    for (double& jacobian_entry : jacobian) jacobian_entry = uniform01(prng);
 
     // Zero residuals
     res.setZero();
@@ -238,8 +239,9 @@
     const double sq_norm = res.dot(res);
 
     rho[0] = sq_norm;
-    rho[1] = RandDouble();
-    rho[2] = 2 * RandDouble() - 1.0;
+    rho[1] = uniform01(prng);
+    rho[2] = uniform01(
+        prng, std::uniform_real_distribution<double>::param_type(-1, 1));
 
     // Ground truth values.
     g_res = sqrt(rho[1]) * res;
diff --git a/third_party/ceres/internal/ceres/cost_function.cc b/third_party/ceres/internal/ceres/cost_function.cc
new file mode 100644
index 0000000..543348f
--- /dev/null
+++ b/third_party/ceres/internal/ceres/cost_function.cc
@@ -0,0 +1,41 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2024 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+//         keir@google.m (Keir Mierle)
+
+#include "ceres/cost_function.h"
+
+namespace ceres {
+
+CostFunction::CostFunction(CostFunction&& other) noexcept = default;
+CostFunction& CostFunction::operator=(CostFunction&& other) noexcept = default;
+CostFunction::CostFunction() : num_residuals_(0) {}
+CostFunction::~CostFunction() = default;
+
+}  // namespace ceres
diff --git a/third_party/ceres/internal/ceres/cost_function_to_functor_test.cc b/third_party/ceres/internal/ceres/cost_function_to_functor_test.cc
index 11f47e3..bc081f4 100644
--- a/third_party/ceres/internal/ceres/cost_function_to_functor_test.cc
+++ b/third_party/ceres/internal/ceres/cost_function_to_functor_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -32,16 +32,16 @@
 
 #include <cstdint>
 #include <memory>
+#include <utility>
+#include <vector>
 
 #include "ceres/autodiff_cost_function.h"
 #include "ceres/dynamic_autodiff_cost_function.h"
 #include "ceres/dynamic_cost_function_to_functor.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
-using std::vector;
 const double kTolerance = 1e-18;
 
 static void ExpectCostFunctionsAreEqual(
@@ -50,9 +50,9 @@
   EXPECT_EQ(cost_function.num_residuals(),
             actual_cost_function.num_residuals());
   const int num_residuals = cost_function.num_residuals();
-  const vector<int32_t>& parameter_block_sizes =
+  const std::vector<int32_t>& parameter_block_sizes =
       cost_function.parameter_block_sizes();
-  const vector<int32_t>& actual_parameter_block_sizes =
+  const std::vector<int32_t>& actual_parameter_block_sizes =
       actual_cost_function.parameter_block_sizes();
   EXPECT_EQ(parameter_block_sizes.size(), actual_parameter_block_sizes.size());
 
@@ -92,9 +92,9 @@
   }
 
   EXPECT_TRUE(
-      cost_function.Evaluate(parameter_blocks.get(), residuals.get(), NULL));
+      cost_function.Evaluate(parameter_blocks.get(), residuals.get(), nullptr));
   EXPECT_TRUE(actual_cost_function.Evaluate(
-      parameter_blocks.get(), actual_residuals.get(), NULL));
+      parameter_blocks.get(), actual_residuals.get(), nullptr));
   for (int i = 0; i < num_residuals; ++i) {
     EXPECT_NEAR(residuals[i], actual_residuals[i], kTolerance)
         << "residual id: " << i;
@@ -302,11 +302,11 @@
 // Check that AutoDiff(Functor1) == AutoDiff(CostToFunctor(AutoDiff(Functor1)))
 #define TEST_BODY(Functor1)                                                    \
   TEST(CostFunctionToFunctor, Functor1) {                                      \
-    typedef AutoDiffCostFunction<Functor1, 2, PARAMETER_BLOCK_SIZES>           \
-        CostFunction1;                                                         \
-    typedef CostFunctionToFunctor<2, PARAMETER_BLOCK_SIZES> FunctionToFunctor; \
-    typedef AutoDiffCostFunction<FunctionToFunctor, 2, PARAMETER_BLOCK_SIZES>  \
-        CostFunction2;                                                         \
+    using CostFunction1 =                                                      \
+        AutoDiffCostFunction<Functor1, 2, PARAMETER_BLOCK_SIZES>;              \
+    using FunctionToFunctor = CostFunctionToFunctor<2, PARAMETER_BLOCK_SIZES>; \
+    using CostFunction2 =                                                      \
+        AutoDiffCostFunction<FunctionToFunctor, 2, PARAMETER_BLOCK_SIZES>;     \
                                                                                \
     std::unique_ptr<CostFunction> cost_function(new CostFunction2(             \
         new FunctionToFunctor(new CostFunction1(new Functor1))));              \
@@ -376,10 +376,9 @@
 }
 
 TEST(CostFunctionToFunctor, DynamicCostFunctionToFunctor) {
-  DynamicAutoDiffCostFunction<DynamicTwoParameterBlockFunctor>*
-      actual_cost_function(
-          new DynamicAutoDiffCostFunction<DynamicTwoParameterBlockFunctor>(
-              new DynamicTwoParameterBlockFunctor));
+  auto* actual_cost_function(
+      new DynamicAutoDiffCostFunction<DynamicTwoParameterBlockFunctor>(
+          new DynamicTwoParameterBlockFunctor));
   actual_cost_function->AddParameterBlock(2);
   actual_cost_function->AddParameterBlock(2);
   actual_cost_function->SetNumResiduals(2);
@@ -393,5 +392,39 @@
   ExpectCostFunctionsAreEqual(cost_function, *actual_cost_function);
 }
 
-}  // namespace internal
-}  // namespace ceres
+TEST(CostFunctionToFunctor, UniquePtrArgumentForwarding) {
+  auto cost_function = std::make_unique<
+      AutoDiffCostFunction<CostFunctionToFunctor<ceres::DYNAMIC, 2, 2>,
+                           ceres::DYNAMIC,
+                           2,
+                           2>>(
+      std::make_unique<CostFunctionToFunctor<ceres::DYNAMIC, 2, 2>>(
+          std::make_unique<
+              AutoDiffCostFunction<TwoParameterBlockFunctor, 2, 2, 2>>()),
+      2);
+
+  auto actual_cost_function = std::make_unique<
+      AutoDiffCostFunction<TwoParameterBlockFunctor, 2, 2, 2>>();
+  ExpectCostFunctionsAreEqual(*cost_function, *actual_cost_function);
+}
+
+TEST(CostFunctionToFunctor, DynamicCostFunctionToFunctorUniquePtr) {
+  auto actual_cost_function = std::make_unique<
+      DynamicAutoDiffCostFunction<DynamicTwoParameterBlockFunctor>>();
+  actual_cost_function->AddParameterBlock(2);
+  actual_cost_function->AddParameterBlock(2);
+  actual_cost_function->SetNumResiduals(2);
+
+  // Use deduction guides for a more compact variable definition
+  DynamicAutoDiffCostFunction cost_function(
+      std::make_unique<DynamicCostFunctionToFunctor>(
+          std::move(actual_cost_function)));
+  cost_function.AddParameterBlock(2);
+  cost_function.AddParameterBlock(2);
+  cost_function.SetNumResiduals(2);
+
+  ExpectCostFunctionsAreEqual(cost_function,
+                              *cost_function.functor().function());
+}
+
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/covariance.cc b/third_party/ceres/internal/ceres/covariance.cc
index 8e240ff..50da029 100644
--- a/third_party/ceres/internal/ceres/covariance.cc
+++ b/third_party/ceres/internal/ceres/covariance.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -39,25 +39,22 @@
 
 namespace ceres {
 
-using std::make_pair;
-using std::pair;
-using std::vector;
-
 Covariance::Covariance(const Covariance::Options& options) {
-  impl_.reset(new internal::CovarianceImpl(options));
+  impl_ = std::make_unique<internal::CovarianceImpl>(options);
 }
 
-Covariance::~Covariance() {}
+Covariance::~Covariance() = default;
 
 bool Covariance::Compute(
-    const vector<pair<const double*, const double*>>& covariance_blocks,
+    const std::vector<std::pair<const double*, const double*>>&
+        covariance_blocks,
     Problem* problem) {
-  return impl_->Compute(covariance_blocks, problem->impl_.get());
+  return impl_->Compute(covariance_blocks, problem->mutable_impl());
 }
 
-bool Covariance::Compute(const vector<const double*>& parameter_blocks,
+bool Covariance::Compute(const std::vector<const double*>& parameter_blocks,
                          Problem* problem) {
-  return impl_->Compute(parameter_blocks, problem->impl_.get());
+  return impl_->Compute(parameter_blocks, problem->mutable_impl());
 }
 
 bool Covariance::GetCovarianceBlock(const double* parameter_block1,
@@ -80,7 +77,7 @@
 }
 
 bool Covariance::GetCovarianceMatrix(
-    const vector<const double*>& parameter_blocks,
+    const std::vector<const double*>& parameter_blocks,
     double* covariance_matrix) const {
   return impl_->GetCovarianceMatrixInTangentOrAmbientSpace(parameter_blocks,
                                                            true,  // ambient
diff --git a/third_party/ceres/internal/ceres/covariance_impl.cc b/third_party/ceres/internal/ceres/covariance_impl.cc
index 1f86707..6e8362d 100644
--- a/third_party/ceres/internal/ceres/covariance_impl.cc
+++ b/third_party/ceres/internal/ceres/covariance_impl.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -57,35 +57,22 @@
 #include "ceres/wall_time.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
-
-using std::swap;
+namespace ceres::internal {
 
 using CovarianceBlocks = std::vector<std::pair<const double*, const double*>>;
 
 CovarianceImpl::CovarianceImpl(const Covariance::Options& options)
     : options_(options), is_computed_(false), is_valid_(false) {
-#ifdef CERES_NO_THREADS
-  if (options_.num_threads > 1) {
-    LOG(WARNING) << "No threading support is compiled into this binary; "
-                 << "only options.num_threads = 1 is supported. Switching "
-                 << "to single threaded mode.";
-    options_.num_threads = 1;
-  }
-#endif
-
   evaluate_options_.num_threads = options_.num_threads;
   evaluate_options_.apply_loss_function = options_.apply_loss_function;
 }
 
-CovarianceImpl::~CovarianceImpl() {}
+CovarianceImpl::~CovarianceImpl() = default;
 
 template <typename T>
 void CheckForDuplicates(std::vector<T> blocks) {
-  sort(blocks.begin(), blocks.end());
-  typename std::vector<T>::iterator it =
-      std::adjacent_find(blocks.begin(), blocks.end());
+  std::sort(blocks.begin(), blocks.end());
+  auto it = std::adjacent_find(blocks.begin(), blocks.end());
   if (it != blocks.end()) {
     // In case there are duplicates, we search for their location.
     std::map<T, std::vector<int>> blocks_map;
@@ -117,7 +104,7 @@
       covariance_blocks);
   problem_ = problem;
   parameter_block_to_row_index_.clear();
-  covariance_matrix_.reset(NULL);
+  covariance_matrix_ = nullptr;
   is_valid_ = (ComputeCovarianceSparsity(covariance_blocks, problem) &&
                ComputeCovarianceValues());
   is_computed_ = true;
@@ -162,10 +149,10 @@
 
     const int block1_size = block1->Size();
     const int block2_size = block2->Size();
-    const int block1_local_size = block1->LocalSize();
-    const int block2_local_size = block2->LocalSize();
+    const int block1_tangent_size = block1->TangentSize();
+    const int block2_tangent_size = block2->TangentSize();
     if (!lift_covariance_to_ambient_space) {
-      MatrixRef(covariance_block, block1_local_size, block2_local_size)
+      MatrixRef(covariance_block, block1_tangent_size, block2_tangent_size)
           .setZero();
     } else {
       MatrixRef(covariance_block, block1_size, block2_size).setZero();
@@ -177,7 +164,7 @@
   const double* parameter_block2 = original_parameter_block2;
   const bool transpose = parameter_block1 > parameter_block2;
   if (transpose) {
-    swap(parameter_block1, parameter_block2);
+    std::swap(parameter_block1, parameter_block2);
   }
 
   // Find where in the covariance matrix the block is located.
@@ -191,7 +178,7 @@
   const int* cols_begin = cols + rows[row_begin];
 
   // The only part that requires work is walking the compressed column
-  // vector to determine where the set of columns correspnding to the
+  // vector to determine where the set of columns corresponding to the
   // covariance block begin.
   int offset = 0;
   while (cols_begin[offset] != col_begin && offset < row_size) {
@@ -209,34 +196,34 @@
       FindOrDie(parameter_map, const_cast<double*>(parameter_block1));
   ParameterBlock* block2 =
       FindOrDie(parameter_map, const_cast<double*>(parameter_block2));
-  const LocalParameterization* local_param1 = block1->local_parameterization();
-  const LocalParameterization* local_param2 = block2->local_parameterization();
+  const Manifold* manifold1 = block1->manifold();
+  const Manifold* manifold2 = block2->manifold();
   const int block1_size = block1->Size();
-  const int block1_local_size = block1->LocalSize();
+  const int block1_tangent_size = block1->TangentSize();
   const int block2_size = block2->Size();
-  const int block2_local_size = block2->LocalSize();
+  const int block2_tangent_size = block2->TangentSize();
 
-  ConstMatrixRef cov(
-      covariance_matrix_->values() + rows[row_begin], block1_size, row_size);
+  ConstMatrixRef cov(covariance_matrix_->values() + rows[row_begin],
+                     block1_tangent_size,
+                     row_size);
 
-  // Fast path when there are no local parameterizations or if the
-  // user does not want it lifted to the ambient space.
-  if ((local_param1 == NULL && local_param2 == NULL) ||
+  // Fast path when there are no manifolds or if the user does not want it
+  // lifted to the ambient space.
+  if ((manifold1 == nullptr && manifold2 == nullptr) ||
       !lift_covariance_to_ambient_space) {
     if (transpose) {
-      MatrixRef(covariance_block, block2_local_size, block1_local_size) =
-          cov.block(0, offset, block1_local_size, block2_local_size)
+      MatrixRef(covariance_block, block2_tangent_size, block1_tangent_size) =
+          cov.block(0, offset, block1_tangent_size, block2_tangent_size)
               .transpose();
     } else {
-      MatrixRef(covariance_block, block1_local_size, block2_local_size) =
-          cov.block(0, offset, block1_local_size, block2_local_size);
+      MatrixRef(covariance_block, block1_tangent_size, block2_tangent_size) =
+          cov.block(0, offset, block1_tangent_size, block2_tangent_size);
     }
     return true;
   }
 
-  // If local parameterizations are used then the covariance that has
-  // been computed is in the tangent space and it needs to be lifted
-  // back to the ambient space.
+  // If manifolds are used then the covariance that has been computed is in the
+  // tangent space and it needs to be lifted back to the ambient space.
   //
   // This is given by the formula
   //
@@ -249,36 +236,37 @@
   // See Result 5.11 on page 142 of Hartley & Zisserman (2nd Edition)
   // for a proof.
   //
-  // TODO(sameeragarwal): Add caching of local parameterization, so
-  // that they are computed just once per parameter block.
-  Matrix block1_jacobian(block1_size, block1_local_size);
-  if (local_param1 == NULL) {
+  // TODO(sameeragarwal): Add caching the manifold plus_jacobian, so that they
+  // are computed just once per parameter block.
+  Matrix block1_jacobian(block1_size, block1_tangent_size);
+  if (manifold1 == nullptr) {
     block1_jacobian.setIdentity();
   } else {
-    local_param1->ComputeJacobian(parameter_block1, block1_jacobian.data());
+    manifold1->PlusJacobian(parameter_block1, block1_jacobian.data());
   }
 
-  Matrix block2_jacobian(block2_size, block2_local_size);
+  Matrix block2_jacobian(block2_size, block2_tangent_size);
   // Fast path if the user is requesting a diagonal block.
   if (parameter_block1 == parameter_block2) {
     block2_jacobian = block1_jacobian;
   } else {
-    if (local_param2 == NULL) {
+    if (manifold2 == nullptr) {
       block2_jacobian.setIdentity();
     } else {
-      local_param2->ComputeJacobian(parameter_block2, block2_jacobian.data());
+      manifold2->PlusJacobian(parameter_block2, block2_jacobian.data());
     }
   }
 
   if (transpose) {
     MatrixRef(covariance_block, block2_size, block1_size) =
         block2_jacobian *
-        cov.block(0, offset, block1_local_size, block2_local_size).transpose() *
+        cov.block(0, offset, block1_tangent_size, block2_tangent_size)
+            .transpose() *
         block1_jacobian.transpose();
   } else {
     MatrixRef(covariance_block, block1_size, block2_size) =
         block1_jacobian *
-        cov.block(0, offset, block1_local_size, block2_local_size) *
+        cov.block(0, offset, block1_tangent_size, block2_tangent_size) *
         block2_jacobian.transpose();
   }
 
@@ -309,7 +297,7 @@
     if (lift_covariance_to_ambient_space) {
       parameter_sizes.push_back(block->Size());
     } else {
-      parameter_sizes.push_back(block->LocalSize());
+      parameter_sizes.push_back(block->TangentSize());
     }
   }
   std::partial_sum(parameter_sizes.begin(),
@@ -322,9 +310,8 @@
   // Assemble the blocks in the covariance matrix.
   MatrixRef covariance(covariance_matrix, covariance_size, covariance_size);
   const int num_threads = options_.num_threads;
-  std::unique_ptr<double[]> workspace(
-      new double[num_threads * max_covariance_block_size *
-                 max_covariance_block_size]);
+  auto workspace = std::make_unique<double[]>(
+      num_threads * max_covariance_block_size * max_covariance_block_size);
 
   bool success = true;
 
@@ -383,8 +370,7 @@
   std::vector<ResidualBlock*> residual_blocks;
   problem->GetResidualBlocks(&residual_blocks);
 
-  for (int i = 0; i < residual_blocks.size(); ++i) {
-    ResidualBlock* residual_block = residual_blocks[i];
+  for (auto* residual_block : residual_blocks) {
     parameter_blocks_in_use.insert(residual_block->parameter_blocks(),
                                    residual_block->parameter_blocks() +
                                        residual_block->NumParameterBlocks());
@@ -394,8 +380,7 @@
   std::vector<double*>& active_parameter_blocks =
       evaluate_options_.parameter_blocks;
   active_parameter_blocks.clear();
-  for (int i = 0; i < all_parameter_blocks.size(); ++i) {
-    double* parameter_block = all_parameter_blocks[i];
+  for (auto* parameter_block : all_parameter_blocks) {
     ParameterBlock* block = FindOrDie(parameter_map, parameter_block);
     if (!block->IsConstant() && (parameter_blocks_in_use.count(block) > 0)) {
       active_parameter_blocks.push_back(parameter_block);
@@ -411,10 +396,9 @@
   // ordering of parameter blocks just constructed.
   int num_rows = 0;
   parameter_block_to_row_index_.clear();
-  for (int i = 0; i < active_parameter_blocks.size(); ++i) {
-    double* parameter_block = active_parameter_blocks[i];
+  for (auto* parameter_block : active_parameter_blocks) {
     const int parameter_block_size =
-        problem->ParameterBlockLocalSize(parameter_block);
+        problem->ParameterBlockTangentSize(parameter_block);
     parameter_block_to_row_index_[parameter_block] = num_rows;
     num_rows += parameter_block_size;
   }
@@ -424,9 +408,7 @@
   // triangular part of the matrix.
   int num_nonzeros = 0;
   CovarianceBlocks covariance_blocks;
-  for (int i = 0; i < original_covariance_blocks.size(); ++i) {
-    const std::pair<const double*, const double*>& block_pair =
-        original_covariance_blocks[i];
+  for (const auto& block_pair : original_covariance_blocks) {
     if (constant_parameter_blocks_.count(block_pair.first) > 0 ||
         constant_parameter_blocks_.count(block_pair.second) > 0) {
       continue;
@@ -434,8 +416,8 @@
 
     int index1 = FindOrDie(parameter_block_to_row_index_, block_pair.first);
     int index2 = FindOrDie(parameter_block_to_row_index_, block_pair.second);
-    const int size1 = problem->ParameterBlockLocalSize(block_pair.first);
-    const int size2 = problem->ParameterBlockLocalSize(block_pair.second);
+    const int size1 = problem->ParameterBlockTangentSize(block_pair.first);
+    const int size2 = problem->ParameterBlockTangentSize(block_pair.second);
     num_nonzeros += size1 * size2;
 
     // Make sure we are constructing a block upper triangular matrix.
@@ -447,9 +429,9 @@
     }
   }
 
-  if (covariance_blocks.size() == 0) {
+  if (covariance_blocks.empty()) {
     VLOG(2) << "No non-zero covariance blocks found";
-    covariance_matrix_.reset(NULL);
+    covariance_matrix_ = nullptr;
     return true;
   }
 
@@ -459,8 +441,8 @@
   std::sort(covariance_blocks.begin(), covariance_blocks.end());
 
   // Fill the sparsity pattern of the covariance matrix.
-  covariance_matrix_.reset(
-      new CompressedRowSparseMatrix(num_rows, num_rows, num_nonzeros));
+  covariance_matrix_ = std::make_unique<CompressedRowSparseMatrix>(
+      num_rows, num_rows, num_nonzeros);
 
   int* rows = covariance_matrix_->mutable_rows();
   int* cols = covariance_matrix_->mutable_cols();
@@ -480,20 +462,18 @@
   int cursor = 0;  // index into the covariance matrix.
   for (const auto& entry : parameter_block_to_row_index_) {
     const double* row_block = entry.first;
-    const int row_block_size = problem->ParameterBlockLocalSize(row_block);
+    const int row_block_size = problem->ParameterBlockTangentSize(row_block);
     int row_begin = entry.second;
 
     // Iterate over the covariance blocks contained in this row block
     // and count the number of columns in this row block.
     int num_col_blocks = 0;
-    int num_columns = 0;
     for (int j = i; j < covariance_blocks.size(); ++j, ++num_col_blocks) {
       const std::pair<const double*, const double*>& block_pair =
           covariance_blocks[j];
       if (block_pair.first != row_block) {
         break;
       }
-      num_columns += problem->ParameterBlockLocalSize(block_pair.second);
     }
 
     // Fill out all the compressed rows for this parameter block.
@@ -501,7 +481,8 @@
       rows[row_begin + r] = cursor;
       for (int c = 0; c < num_col_blocks; ++c) {
         const double* col_block = covariance_blocks[i + c].second;
-        const int col_block_size = problem->ParameterBlockLocalSize(col_block);
+        const int col_block_size =
+            problem->ParameterBlockTangentSize(col_block);
         int col_begin = FindOrDie(parameter_block_to_row_index_, col_block);
         for (int k = 0; k < col_block_size; ++k) {
           cols[cursor++] = col_begin++;
@@ -556,13 +537,13 @@
       "CovarianceImpl::ComputeCovarianceValuesUsingSparseQR");
 
 #ifndef CERES_NO_SUITESPARSE
-  if (covariance_matrix_.get() == NULL) {
+  if (covariance_matrix_ == nullptr) {
     // Nothing to do, all zeros covariance matrix.
     return true;
   }
 
   CRSMatrix jacobian;
-  problem_->Evaluate(evaluate_options_, NULL, NULL, NULL, &jacobian);
+  problem_->Evaluate(evaluate_options_, nullptr, nullptr, nullptr, &jacobian);
   event_logger.AddEvent("Evaluate");
 
   // Construct a compressed column form of the Jacobian.
@@ -601,11 +582,11 @@
   cholmod_jacobian.nrow = num_rows;
   cholmod_jacobian.ncol = num_cols;
   cholmod_jacobian.nzmax = num_nonzeros;
-  cholmod_jacobian.nz = NULL;
-  cholmod_jacobian.p = reinterpret_cast<void*>(&transpose_rows[0]);
-  cholmod_jacobian.i = reinterpret_cast<void*>(&transpose_cols[0]);
-  cholmod_jacobian.x = reinterpret_cast<void*>(&transpose_values[0]);
-  cholmod_jacobian.z = NULL;
+  cholmod_jacobian.nz = nullptr;
+  cholmod_jacobian.p = reinterpret_cast<void*>(transpose_rows.data());
+  cholmod_jacobian.i = reinterpret_cast<void*>(transpose_cols.data());
+  cholmod_jacobian.x = reinterpret_cast<void*>(transpose_values.data());
+  cholmod_jacobian.z = nullptr;
   cholmod_jacobian.stype = 0;  // Matrix is not symmetric.
   cholmod_jacobian.itype = CHOLMOD_LONG;
   cholmod_jacobian.xtype = CHOLMOD_REAL;
@@ -616,8 +597,8 @@
   cholmod_common cc;
   cholmod_l_start(&cc);
 
-  cholmod_sparse* R = NULL;
-  SuiteSparse_long* permutation = NULL;
+  cholmod_sparse* R = nullptr;
+  SuiteSparse_long* permutation = nullptr;
 
   // Compute a Q-less QR factorization of the Jacobian. Since we are
   // only interested in inverting J'J = R'R, we do not need Q. This
@@ -632,13 +613,15 @@
   // more efficient, both in runtime as well as the quality of
   // ordering computed. So, it maybe worth doing that analysis
   // separately.
-  const SuiteSparse_long rank = SuiteSparseQR<double>(SPQR_ORDERING_BESTAMD,
-                                                      SPQR_DEFAULT_TOL,
-                                                      cholmod_jacobian.ncol,
-                                                      &cholmod_jacobian,
-                                                      &R,
-                                                      &permutation,
-                                                      &cc);
+  const SuiteSparse_long rank = SuiteSparseQR<double>(
+      SPQR_ORDERING_BESTAMD,
+      options_.column_pivot_threshold < 0 ? SPQR_DEFAULT_TOL
+                                          : options_.column_pivot_threshold,
+      static_cast<int64_t>(cholmod_jacobian.ncol),
+      &cholmod_jacobian,
+      &R,
+      &permutation,
+      &cc);
   event_logger.AddEvent("Numeric Factorization");
   if (R == nullptr) {
     LOG(ERROR) << "Something is wrong. SuiteSparseQR returned R = nullptr.";
@@ -648,9 +631,9 @@
   }
 
   if (rank < cholmod_jacobian.ncol) {
-    LOG(ERROR) << "Jacobian matrix is rank deficient. "
-               << "Number of columns: " << cholmod_jacobian.ncol
-               << " rank: " << rank;
+    LOG(WARNING) << "Jacobian matrix is rank deficient. "
+                 << "Number of columns: " << cholmod_jacobian.ncol
+                 << " rank: " << rank;
     free(permutation);
     cholmod_l_free_sparse(&R, &cc);
     cholmod_l_finish(&cc);
@@ -682,7 +665,7 @@
   // Since the covariance matrix is symmetric, the i^th row and column
   // are equal.
   const int num_threads = options_.num_threads;
-  std::unique_ptr<double[]> workspace(new double[num_threads * num_cols]);
+  auto workspace = std::make_unique<double[]>(num_threads * num_cols);
 
   problem_->context()->EnsureMinimumThreads(num_threads);
   ParallelFor(
@@ -721,13 +704,13 @@
 bool CovarianceImpl::ComputeCovarianceValuesUsingDenseSVD() {
   EventLogger event_logger(
       "CovarianceImpl::ComputeCovarianceValuesUsingDenseSVD");
-  if (covariance_matrix_.get() == NULL) {
+  if (covariance_matrix_ == nullptr) {
     // Nothing to do, all zeros covariance matrix.
     return true;
   }
 
   CRSMatrix jacobian;
-  problem_->Evaluate(evaluate_options_, NULL, NULL, NULL, &jacobian);
+  problem_->Evaluate(evaluate_options_, nullptr, nullptr, nullptr, &jacobian);
   event_logger.AddEvent("Evaluate");
 
   Matrix dense_jacobian(jacobian.num_rows, jacobian.num_cols);
@@ -812,20 +795,20 @@
 bool CovarianceImpl::ComputeCovarianceValuesUsingEigenSparseQR() {
   EventLogger event_logger(
       "CovarianceImpl::ComputeCovarianceValuesUsingEigenSparseQR");
-  if (covariance_matrix_.get() == NULL) {
+  if (covariance_matrix_ == nullptr) {
     // Nothing to do, all zeros covariance matrix.
     return true;
   }
 
   CRSMatrix jacobian;
-  problem_->Evaluate(evaluate_options_, NULL, NULL, NULL, &jacobian);
+  problem_->Evaluate(evaluate_options_, nullptr, nullptr, nullptr, &jacobian);
   event_logger.AddEvent("Evaluate");
 
-  typedef Eigen::SparseMatrix<double, Eigen::ColMajor> EigenSparseMatrix;
+  using EigenSparseMatrix = Eigen::SparseMatrix<double, Eigen::ColMajor>;
 
   // Convert the matrix to column major order as required by SparseQR.
   EigenSparseMatrix sparse_jacobian =
-      Eigen::MappedSparseMatrix<double, Eigen::RowMajor>(
+      Eigen::Map<Eigen::SparseMatrix<double, Eigen::RowMajor>>(
           jacobian.num_rows,
           jacobian.num_cols,
           static_cast<int>(jacobian.values.size()),
@@ -834,19 +817,23 @@
           jacobian.values.data());
   event_logger.AddEvent("ConvertToSparseMatrix");
 
-  Eigen::SparseQR<EigenSparseMatrix, Eigen::COLAMDOrdering<int>> qr_solver(
-      sparse_jacobian);
+  Eigen::SparseQR<EigenSparseMatrix, Eigen::COLAMDOrdering<int>> qr;
+  if (options_.column_pivot_threshold > 0) {
+    qr.setPivotThreshold(options_.column_pivot_threshold);
+  }
+
+  qr.compute(sparse_jacobian);
   event_logger.AddEvent("QRDecomposition");
 
-  if (qr_solver.info() != Eigen::Success) {
+  if (qr.info() != Eigen::Success) {
     LOG(ERROR) << "Eigen::SparseQR decomposition failed.";
     return false;
   }
 
-  if (qr_solver.rank() < jacobian.num_cols) {
+  if (qr.rank() < jacobian.num_cols) {
     LOG(ERROR) << "Jacobian matrix is rank deficient. "
                << "Number of columns: " << jacobian.num_cols
-               << " rank: " << qr_solver.rank();
+               << " rank: " << qr.rank();
     return false;
   }
 
@@ -856,7 +843,7 @@
 
   // Compute the inverse column permutation used by QR factorization.
   Eigen::PermutationMatrix<Eigen::Dynamic, Eigen::Dynamic> inverse_permutation =
-      qr_solver.colsPermutation().inverse();
+      qr.colsPermutation().inverse();
 
   // The following loop exploits the fact that the i^th column of A^{-1}
   // is given by the solution to the linear system
@@ -869,7 +856,7 @@
   // are equal.
   const int num_cols = jacobian.num_cols;
   const int num_threads = options_.num_threads;
-  std::unique_ptr<double[]> workspace(new double[num_threads * num_cols]);
+  auto workspace = std::make_unique<double[]>(num_threads * num_cols);
 
   problem_->context()->EnsureMinimumThreads(num_threads);
   ParallelFor(
@@ -879,9 +866,9 @@
         if (row_end != row_begin) {
           double* solution = workspace.get() + thread_id * num_cols;
           SolveRTRWithSparseRHS<int>(num_cols,
-                                     qr_solver.matrixR().innerIndexPtr(),
-                                     qr_solver.matrixR().outerIndexPtr(),
-                                     &qr_solver.matrixR().data().value(0),
+                                     qr.matrixR().innerIndexPtr(),
+                                     qr.matrixR().outerIndexPtr(),
+                                     &qr.matrixR().data().value(0),
                                      inverse_permutation.indices().coeff(r),
                                      solution);
 
@@ -899,5 +886,4 @@
   return true;
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/covariance_impl.h b/third_party/ceres/internal/ceres/covariance_impl.h
index 394a04b..9ff7982 100644
--- a/third_party/ceres/internal/ceres/covariance_impl.h
+++ b/third_party/ceres/internal/ceres/covariance_impl.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -38,16 +38,16 @@
 #include <vector>
 
 #include "ceres/covariance.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 #include "ceres/problem_impl.h"
 #include "ceres/suitesparse.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 class CompressedRowSparseMatrix;
 
-class CERES_EXPORT_INTERNAL CovarianceImpl {
+class CERES_NO_EXPORT CovarianceImpl {
  public:
   explicit CovarianceImpl(const Covariance::Options& options);
   ~CovarianceImpl();
@@ -95,7 +95,8 @@
   std::unique_ptr<CompressedRowSparseMatrix> covariance_matrix_;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_COVARIANCE_IMPL_H_
diff --git a/third_party/ceres/internal/ceres/covariance_test.cc b/third_party/ceres/internal/ceres/covariance_test.cc
index 229173f..40d9b0e 100644
--- a/third_party/ceres/internal/ceres/covariance_test.cc
+++ b/third_party/ceres/internal/ceres/covariance_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -36,12 +36,14 @@
 #include <map>
 #include <memory>
 #include <utility>
+#include <vector>
 
 #include "ceres/autodiff_cost_function.h"
 #include "ceres/compressed_row_sparse_matrix.h"
 #include "ceres/cost_function.h"
 #include "ceres/covariance_impl.h"
-#include "ceres/local_parameterization.h"
+#include "ceres/internal/config.h"
+#include "ceres/manifold.h"
 #include "ceres/map_util.h"
 #include "ceres/problem_impl.h"
 #include "gtest/gtest.h"
@@ -49,11 +51,6 @@
 namespace ceres {
 namespace internal {
 
-using std::make_pair;
-using std::map;
-using std::pair;
-using std::vector;
-
 class UnaryCostFunction : public CostFunction {
  public:
   UnaryCostFunction(const int num_residuals,
@@ -71,19 +68,19 @@
       residuals[i] = 1;
     }
 
-    if (jacobians == NULL) {
+    if (jacobians == nullptr) {
       return true;
     }
 
-    if (jacobians[0] != NULL) {
-      copy(jacobian_.begin(), jacobian_.end(), jacobians[0]);
+    if (jacobians[0] != nullptr) {
+      std::copy(jacobian_.begin(), jacobian_.end(), jacobians[0]);
     }
 
     return true;
   }
 
  private:
-  vector<double> jacobian_;
+  std::vector<double> jacobian_;
 };
 
 class BinaryCostFunction : public CostFunction {
@@ -109,47 +106,24 @@
       residuals[i] = 2;
     }
 
-    if (jacobians == NULL) {
+    if (jacobians == nullptr) {
       return true;
     }
 
-    if (jacobians[0] != NULL) {
-      copy(jacobian1_.begin(), jacobian1_.end(), jacobians[0]);
+    if (jacobians[0] != nullptr) {
+      std::copy(jacobian1_.begin(), jacobian1_.end(), jacobians[0]);
     }
 
-    if (jacobians[1] != NULL) {
-      copy(jacobian2_.begin(), jacobian2_.end(), jacobians[1]);
+    if (jacobians[1] != nullptr) {
+      std::copy(jacobian2_.begin(), jacobian2_.end(), jacobians[1]);
     }
 
     return true;
   }
 
  private:
-  vector<double> jacobian1_;
-  vector<double> jacobian2_;
-};
-
-// x_plus_delta = delta * x;
-class PolynomialParameterization : public LocalParameterization {
- public:
-  virtual ~PolynomialParameterization() {}
-
-  bool Plus(const double* x,
-            const double* delta,
-            double* x_plus_delta) const final {
-    x_plus_delta[0] = delta[0] * x[0];
-    x_plus_delta[1] = delta[0] * x[1];
-    return true;
-  }
-
-  bool ComputeJacobian(const double* x, double* jacobian) const final {
-    jacobian[0] = x[0];
-    jacobian[1] = x[1];
-    return true;
-  }
-
-  int GlobalSize() const final { return 2; }
-  int LocalSize() const final { return 1; }
+  std::vector<double> jacobian1_;
+  std::vector<double> jacobian2_;
 };
 
 TEST(CovarianceImpl, ComputeCovarianceSparsity) {
@@ -165,13 +139,13 @@
   // Add in random order
   Vector junk_jacobian = Vector::Zero(10);
   problem.AddResidualBlock(
-      new UnaryCostFunction(1, 1, junk_jacobian.data()), NULL, block1);
+      new UnaryCostFunction(1, 1, junk_jacobian.data()), nullptr, block1);
   problem.AddResidualBlock(
-      new UnaryCostFunction(1, 4, junk_jacobian.data()), NULL, block4);
+      new UnaryCostFunction(1, 4, junk_jacobian.data()), nullptr, block4);
   problem.AddResidualBlock(
-      new UnaryCostFunction(1, 3, junk_jacobian.data()), NULL, block3);
+      new UnaryCostFunction(1, 3, junk_jacobian.data()), nullptr, block3);
   problem.AddResidualBlock(
-      new UnaryCostFunction(1, 2, junk_jacobian.data()), NULL, block2);
+      new UnaryCostFunction(1, 2, junk_jacobian.data()), nullptr, block2);
 
   // Sparsity pattern
   //
@@ -206,13 +180,13 @@
                          6, 7, 8, 9};
   // clang-format on
 
-  vector<pair<const double*, const double*>> covariance_blocks;
-  covariance_blocks.push_back(make_pair(block1, block1));
-  covariance_blocks.push_back(make_pair(block4, block4));
-  covariance_blocks.push_back(make_pair(block2, block2));
-  covariance_blocks.push_back(make_pair(block3, block3));
-  covariance_blocks.push_back(make_pair(block2, block3));
-  covariance_blocks.push_back(make_pair(block4, block1));  // reversed
+  std::vector<std::pair<const double*, const double*>> covariance_blocks;
+  covariance_blocks.emplace_back(block1, block1);
+  covariance_blocks.emplace_back(block4, block4);
+  covariance_blocks.emplace_back(block2, block2);
+  covariance_blocks.emplace_back(block3, block3);
+  covariance_blocks.emplace_back(block2, block3);
+  covariance_blocks.emplace_back(block4, block1);  // reversed
 
   Covariance::Options options;
   CovarianceImpl covariance_impl(options);
@@ -251,13 +225,13 @@
   // Add in random order
   Vector junk_jacobian = Vector::Zero(10);
   problem.AddResidualBlock(
-      new UnaryCostFunction(1, 1, junk_jacobian.data()), NULL, block1);
+      new UnaryCostFunction(1, 1, junk_jacobian.data()), nullptr, block1);
   problem.AddResidualBlock(
-      new UnaryCostFunction(1, 4, junk_jacobian.data()), NULL, block4);
+      new UnaryCostFunction(1, 4, junk_jacobian.data()), nullptr, block4);
   problem.AddResidualBlock(
-      new UnaryCostFunction(1, 3, junk_jacobian.data()), NULL, block3);
+      new UnaryCostFunction(1, 3, junk_jacobian.data()), nullptr, block3);
   problem.AddResidualBlock(
-      new UnaryCostFunction(1, 2, junk_jacobian.data()), NULL, block2);
+      new UnaryCostFunction(1, 2, junk_jacobian.data()), nullptr, block2);
   problem.SetParameterBlockConstant(block3);
 
   // Sparsity pattern
@@ -287,13 +261,13 @@
                          3, 4, 5, 6};
   // clang-format on
 
-  vector<pair<const double*, const double*>> covariance_blocks;
-  covariance_blocks.push_back(make_pair(block1, block1));
-  covariance_blocks.push_back(make_pair(block4, block4));
-  covariance_blocks.push_back(make_pair(block2, block2));
-  covariance_blocks.push_back(make_pair(block3, block3));
-  covariance_blocks.push_back(make_pair(block2, block3));
-  covariance_blocks.push_back(make_pair(block4, block1));  // reversed
+  std::vector<std::pair<const double*, const double*>> covariance_blocks;
+  covariance_blocks.emplace_back(block1, block1);
+  covariance_blocks.emplace_back(block4, block4);
+  covariance_blocks.emplace_back(block2, block2);
+  covariance_blocks.emplace_back(block3, block3);
+  covariance_blocks.emplace_back(block2, block3);
+  covariance_blocks.emplace_back(block4, block1);  // reversed
 
   Covariance::Options options;
   CovarianceImpl covariance_impl(options);
@@ -332,12 +306,12 @@
   // Add in random order
   Vector junk_jacobian = Vector::Zero(10);
   problem.AddResidualBlock(
-      new UnaryCostFunction(1, 1, junk_jacobian.data()), NULL, block1);
+      new UnaryCostFunction(1, 1, junk_jacobian.data()), nullptr, block1);
   problem.AddResidualBlock(
-      new UnaryCostFunction(1, 4, junk_jacobian.data()), NULL, block4);
+      new UnaryCostFunction(1, 4, junk_jacobian.data()), nullptr, block4);
   problem.AddParameterBlock(block3, 3);
   problem.AddResidualBlock(
-      new UnaryCostFunction(1, 2, junk_jacobian.data()), NULL, block2);
+      new UnaryCostFunction(1, 2, junk_jacobian.data()), nullptr, block2);
 
   // Sparsity pattern
   //
@@ -366,13 +340,13 @@
                          3, 4, 5, 6};
   // clang-format on
 
-  vector<pair<const double*, const double*>> covariance_blocks;
-  covariance_blocks.push_back(make_pair(block1, block1));
-  covariance_blocks.push_back(make_pair(block4, block4));
-  covariance_blocks.push_back(make_pair(block2, block2));
-  covariance_blocks.push_back(make_pair(block3, block3));
-  covariance_blocks.push_back(make_pair(block2, block3));
-  covariance_blocks.push_back(make_pair(block4, block1));  // reversed
+  std::vector<std::pair<const double*, const double*>> covariance_blocks;
+  covariance_blocks.emplace_back(block1, block1);
+  covariance_blocks.emplace_back(block4, block4);
+  covariance_blocks.emplace_back(block2, block2);
+  covariance_blocks.emplace_back(block3, block3);
+  covariance_blocks.emplace_back(block2, block3);
+  covariance_blocks.emplace_back(block4, block1);  // reversed
 
   Covariance::Options options;
   CovarianceImpl covariance_impl(options);
@@ -398,9 +372,42 @@
   }
 }
 
+// x_plus_delta = delta * x;
+class PolynomialManifold : public Manifold {
+ public:
+  bool Plus(const double* x,
+            const double* delta,
+            double* x_plus_delta) const final {
+    x_plus_delta[0] = delta[0] * x[0];
+    x_plus_delta[1] = delta[0] * x[1];
+    return true;
+  }
+
+  bool Minus(const double* y, const double* x, double* y_minus_x) const final {
+    LOG(FATAL) << "Should not be called";
+    return true;
+  }
+
+  bool PlusJacobian(const double* x, double* jacobian) const final {
+    jacobian[0] = x[0];
+    jacobian[1] = x[1];
+    return true;
+  }
+
+  bool MinusJacobian(const double* x, double* jacobian) const final {
+    LOG(FATAL) << "Should not be called";
+    return true;
+  }
+
+  int AmbientSize() const final { return 2; }
+  int TangentSize() const final { return 1; }
+};
+
 class CovarianceTest : public ::testing::Test {
  protected:
-  typedef map<const double*, pair<int, int>> BoundsMap;
+  // TODO(sameeragarwal): Investigate if this should be an ordered or an
+  // unordered map.
+  using BoundsMap = std::map<const double*, std::pair<int, int>>;
 
   void SetUp() override {
     double* x = parameters_;
@@ -416,44 +423,46 @@
 
     {
       double jacobian[] = {1.0, 0.0, 0.0, 1.0};
-      problem_.AddResidualBlock(new UnaryCostFunction(2, 2, jacobian), NULL, x);
+      problem_.AddResidualBlock(
+          new UnaryCostFunction(2, 2, jacobian), nullptr, x);
     }
 
     {
       double jacobian[] = {2.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 2.0};
-      problem_.AddResidualBlock(new UnaryCostFunction(3, 3, jacobian), NULL, y);
+      problem_.AddResidualBlock(
+          new UnaryCostFunction(3, 3, jacobian), nullptr, y);
     }
 
     {
       double jacobian = 5.0;
       problem_.AddResidualBlock(
-          new UnaryCostFunction(1, 1, &jacobian), NULL, z);
+          new UnaryCostFunction(1, 1, &jacobian), nullptr, z);
     }
 
     {
       double jacobian1[] = {1.0, 2.0, 3.0};
       double jacobian2[] = {-5.0, -6.0};
       problem_.AddResidualBlock(
-          new BinaryCostFunction(1, 3, 2, jacobian1, jacobian2), NULL, y, x);
+          new BinaryCostFunction(1, 3, 2, jacobian1, jacobian2), nullptr, y, x);
     }
 
     {
       double jacobian1[] = {2.0};
       double jacobian2[] = {3.0, -2.0};
       problem_.AddResidualBlock(
-          new BinaryCostFunction(1, 1, 2, jacobian1, jacobian2), NULL, z, x);
+          new BinaryCostFunction(1, 1, 2, jacobian1, jacobian2), nullptr, z, x);
     }
 
-    all_covariance_blocks_.push_back(make_pair(x, x));
-    all_covariance_blocks_.push_back(make_pair(y, y));
-    all_covariance_blocks_.push_back(make_pair(z, z));
-    all_covariance_blocks_.push_back(make_pair(x, y));
-    all_covariance_blocks_.push_back(make_pair(x, z));
-    all_covariance_blocks_.push_back(make_pair(y, z));
+    all_covariance_blocks_.emplace_back(x, x);
+    all_covariance_blocks_.emplace_back(y, y);
+    all_covariance_blocks_.emplace_back(z, z);
+    all_covariance_blocks_.emplace_back(x, y);
+    all_covariance_blocks_.emplace_back(x, z);
+    all_covariance_blocks_.emplace_back(y, z);
 
-    column_bounds_[x] = make_pair(0, 2);
-    column_bounds_[y] = make_pair(2, 5);
-    column_bounds_[z] = make_pair(5, 6);
+    column_bounds_[x] = std::make_pair(0, 2);
+    column_bounds_[y] = std::make_pair(2, 5);
+    column_bounds_[z] = std::make_pair(5, 6);
   }
 
   // Computes covariance in ambient space.
@@ -481,7 +490,7 @@
     // Generate all possible combination of block pairs and check if the
     // covariance computation is correct.
     for (int i = 0; i <= 64; ++i) {
-      vector<pair<const double*, const double*>> covariance_blocks;
+      std::vector<std::pair<const double*, const double*>> covariance_blocks;
       if (i & 1) {
         covariance_blocks.push_back(all_covariance_blocks_[0]);
       }
@@ -509,9 +518,9 @@
       Covariance covariance(options);
       EXPECT_TRUE(covariance.Compute(covariance_blocks, &problem_));
 
-      for (int i = 0; i < covariance_blocks.size(); ++i) {
-        const double* block1 = covariance_blocks[i].first;
-        const double* block2 = covariance_blocks[i].second;
+      for (auto& covariance_block : covariance_blocks) {
+        const double* block1 = covariance_block.first;
+        const double* block2 = covariance_block.second;
         // block1, block2
         GetCovarianceBlockAndCompare(block1,
                                      block2,
@@ -574,7 +583,7 @@
 
   double parameters_[6];
   Problem problem_;
-  vector<pair<const double*, const double*>> all_covariance_blocks_;
+  std::vector<std::pair<const double*, const double*>> all_covariance_blocks_;
   BoundsMap column_bounds_;
   BoundsMap local_column_bounds_;
 };
@@ -628,8 +637,6 @@
   ComputeAndCompareCovarianceBlocks(options, expected_covariance);
 }
 
-#ifdef CERES_USE_OPENMP
-
 TEST_F(CovarianceTest, ThreadedNormalBehavior) {
   // J
   //
@@ -680,8 +687,6 @@
   ComputeAndCompareCovarianceBlocks(options, expected_covariance);
 }
 
-#endif  // CERES_USE_OPENMP
-
 TEST_F(CovarianceTest, ConstantParameterBlock) {
   problem_.SetParameterBlockConstant(parameters_);
 
@@ -733,15 +738,15 @@
   ComputeAndCompareCovarianceBlocks(options, expected_covariance);
 }
 
-TEST_F(CovarianceTest, LocalParameterization) {
+TEST_F(CovarianceTest, Manifold) {
   double* x = parameters_;
   double* y = x + 2;
 
-  problem_.SetParameterization(x, new PolynomialParameterization);
+  problem_.SetManifold(x, new PolynomialManifold);
 
-  vector<int> subset;
+  std::vector<int> subset;
   subset.push_back(2);
-  problem_.SetParameterization(y, new SubsetParameterization(3, subset));
+  problem_.SetManifold(y, new SubsetManifold(3, subset));
 
   // Raw Jacobian: J
   //
@@ -792,20 +797,20 @@
   ComputeAndCompareCovarianceBlocks(options, expected_covariance);
 }
 
-TEST_F(CovarianceTest, LocalParameterizationInTangentSpace) {
+TEST_F(CovarianceTest, ManifoldInTangentSpace) {
   double* x = parameters_;
   double* y = x + 2;
   double* z = y + 3;
 
-  problem_.SetParameterization(x, new PolynomialParameterization);
+  problem_.SetManifold(x, new PolynomialManifold);
 
-  vector<int> subset;
+  std::vector<int> subset;
   subset.push_back(2);
-  problem_.SetParameterization(y, new SubsetParameterization(3, subset));
+  problem_.SetManifold(y, new SubsetManifold(3, subset));
 
-  local_column_bounds_[x] = make_pair(0, 1);
-  local_column_bounds_[y] = make_pair(1, 3);
-  local_column_bounds_[z] = make_pair(3, 4);
+  local_column_bounds_[x] = std::make_pair(0, 1);
+  local_column_bounds_[y] = std::make_pair(1, 3);
+  local_column_bounds_[z] = std::make_pair(3, 4);
 
   // Raw Jacobian: J
   //
@@ -855,22 +860,22 @@
   ComputeAndCompareCovarianceBlocksInTangentSpace(options, expected_covariance);
 }
 
-TEST_F(CovarianceTest, LocalParameterizationInTangentSpaceWithConstantBlocks) {
+TEST_F(CovarianceTest, ManifoldInTangentSpaceWithConstantBlocks) {
   double* x = parameters_;
   double* y = x + 2;
   double* z = y + 3;
 
-  problem_.SetParameterization(x, new PolynomialParameterization);
+  problem_.SetManifold(x, new PolynomialManifold);
   problem_.SetParameterBlockConstant(x);
 
-  vector<int> subset;
+  std::vector<int> subset;
   subset.push_back(2);
-  problem_.SetParameterization(y, new SubsetParameterization(3, subset));
+  problem_.SetManifold(y, new SubsetManifold(3, subset));
   problem_.SetParameterBlockConstant(y);
 
-  local_column_bounds_[x] = make_pair(0, 1);
-  local_column_bounds_[y] = make_pair(1, 3);
-  local_column_bounds_[z] = make_pair(3, 4);
+  local_column_bounds_[x] = std::make_pair(0, 1);
+  local_column_bounds_[y] = std::make_pair(1, 3);
+  local_column_bounds_[z] = std::make_pair(3, 4);
 
   // Raw Jacobian: J
   //
@@ -941,7 +946,7 @@
   //  -15 -18  3   6  13  0
   //    6  -4  0   0   0 29
 
-  // 3.4142 is the smallest eigen value of J'J. The following matrix
+  // 3.4142 is the smallest eigenvalue of J'J. The following matrix
   // was obtained by dropping the eigenvector corresponding to this
   // eigenvalue.
   // clang-format off
@@ -980,7 +985,7 @@
   double* x = parameters_;
   double* y = x + 2;
   double* z = y + 3;
-  vector<const double*> parameter_blocks;
+  std::vector<const double*> parameter_blocks;
   parameter_blocks.push_back(x);
   parameter_blocks.push_back(y);
   parameter_blocks.push_back(z);
@@ -1009,7 +1014,7 @@
   double* x = parameters_;
   double* y = x + 2;
   double* z = y + 3;
-  vector<const double*> parameter_blocks;
+  std::vector<const double*> parameter_blocks;
   parameter_blocks.push_back(x);
   parameter_blocks.push_back(y);
   parameter_blocks.push_back(z);
@@ -1038,17 +1043,17 @@
   double* y = x + 2;
   double* z = y + 3;
 
-  problem_.SetParameterization(x, new PolynomialParameterization);
+  problem_.SetManifold(x, new PolynomialManifold);
 
-  vector<int> subset;
+  std::vector<int> subset;
   subset.push_back(2);
-  problem_.SetParameterization(y, new SubsetParameterization(3, subset));
+  problem_.SetManifold(y, new SubsetManifold(3, subset));
 
-  local_column_bounds_[x] = make_pair(0, 1);
-  local_column_bounds_[y] = make_pair(1, 3);
-  local_column_bounds_[z] = make_pair(3, 4);
+  local_column_bounds_[x] = std::make_pair(0, 1);
+  local_column_bounds_[y] = std::make_pair(1, 3);
+  local_column_bounds_[z] = std::make_pair(3, 4);
 
-  vector<const double*> parameter_blocks;
+  std::vector<const double*> parameter_blocks;
   parameter_blocks.push_back(x);
   parameter_blocks.push_back(y);
   parameter_blocks.push_back(z);
@@ -1077,7 +1082,7 @@
   Covariance covariance(options);
   double* x = parameters_;
   double* y = x + 2;
-  vector<const double*> parameter_blocks;
+  std::vector<const double*> parameter_blocks;
   parameter_blocks.push_back(x);
   parameter_blocks.push_back(x);
   parameter_blocks.push_back(y);
@@ -1085,11 +1090,11 @@
   EXPECT_DEATH_IF_SUPPORTED(covariance.Compute(parameter_blocks, &problem_),
                             "Covariance::Compute called with duplicate blocks "
                             "at indices \\(0, 1\\) and \\(2, 3\\)");
-  vector<pair<const double*, const double*>> covariance_blocks;
-  covariance_blocks.push_back(make_pair(x, x));
-  covariance_blocks.push_back(make_pair(x, x));
-  covariance_blocks.push_back(make_pair(y, y));
-  covariance_blocks.push_back(make_pair(y, y));
+  std::vector<std::pair<const double*, const double*>> covariance_blocks;
+  covariance_blocks.emplace_back(x, x);
+  covariance_blocks.emplace_back(x, x);
+  covariance_blocks.emplace_back(y, y);
+  covariance_blocks.emplace_back(y, y);
   EXPECT_DEATH_IF_SUPPORTED(covariance.Compute(covariance_blocks, &problem_),
                             "Covariance::Compute called with duplicate blocks "
                             "at indices \\(0, 1\\) and \\(2, 3\\)");
@@ -1104,44 +1109,46 @@
 
     {
       double jacobian[] = {1.0, 0.0, 0.0, 1.0};
-      problem_.AddResidualBlock(new UnaryCostFunction(2, 2, jacobian), NULL, x);
+      problem_.AddResidualBlock(
+          new UnaryCostFunction(2, 2, jacobian), nullptr, x);
     }
 
     {
       double jacobian[] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
-      problem_.AddResidualBlock(new UnaryCostFunction(3, 3, jacobian), NULL, y);
+      problem_.AddResidualBlock(
+          new UnaryCostFunction(3, 3, jacobian), nullptr, y);
     }
 
     {
       double jacobian = 5.0;
       problem_.AddResidualBlock(
-          new UnaryCostFunction(1, 1, &jacobian), NULL, z);
+          new UnaryCostFunction(1, 1, &jacobian), nullptr, z);
     }
 
     {
       double jacobian1[] = {0.0, 0.0, 0.0};
       double jacobian2[] = {-5.0, -6.0};
       problem_.AddResidualBlock(
-          new BinaryCostFunction(1, 3, 2, jacobian1, jacobian2), NULL, y, x);
+          new BinaryCostFunction(1, 3, 2, jacobian1, jacobian2), nullptr, y, x);
     }
 
     {
       double jacobian1[] = {2.0};
       double jacobian2[] = {3.0, -2.0};
       problem_.AddResidualBlock(
-          new BinaryCostFunction(1, 1, 2, jacobian1, jacobian2), NULL, z, x);
+          new BinaryCostFunction(1, 1, 2, jacobian1, jacobian2), nullptr, z, x);
     }
 
-    all_covariance_blocks_.push_back(make_pair(x, x));
-    all_covariance_blocks_.push_back(make_pair(y, y));
-    all_covariance_blocks_.push_back(make_pair(z, z));
-    all_covariance_blocks_.push_back(make_pair(x, y));
-    all_covariance_blocks_.push_back(make_pair(x, z));
-    all_covariance_blocks_.push_back(make_pair(y, z));
+    all_covariance_blocks_.emplace_back(x, x);
+    all_covariance_blocks_.emplace_back(y, y);
+    all_covariance_blocks_.emplace_back(z, z);
+    all_covariance_blocks_.emplace_back(x, y);
+    all_covariance_blocks_.emplace_back(x, z);
+    all_covariance_blocks_.emplace_back(y, z);
 
-    column_bounds_[x] = make_pair(0, 2);
-    column_bounds_[y] = make_pair(2, 5);
-    column_bounds_[z] = make_pair(5, 6);
+    column_bounds_[x] = std::make_pair(0, 2);
+    column_bounds_[y] = std::make_pair(2, 5);
+    column_bounds_[z] = std::make_pair(5, 6);
   }
 };
 
@@ -1197,22 +1204,22 @@
   }
 };
 
-TEST(Covariance, ZeroSizedLocalParameterizationGetCovariance) {
+TEST(Covariance, ZeroSizedManifoldGetCovariance) {
   double x = 0.0;
   double y = 1.0;
   Problem problem;
   problem.AddResidualBlock(LinearCostFunction::Create(), nullptr, &x, &y);
-  problem.SetParameterization(&y, new SubsetParameterization(1, {0}));
+  problem.SetManifold(&y, new SubsetManifold(1, {0}));
   // J = [-1 0]
   //     [ 0 0]
   Covariance::Options options;
   options.algorithm_type = DENSE_SVD;
   Covariance covariance(options);
-  vector<pair<const double*, const double*>> covariance_blocks;
-  covariance_blocks.push_back(std::make_pair(&x, &x));
-  covariance_blocks.push_back(std::make_pair(&x, &y));
-  covariance_blocks.push_back(std::make_pair(&y, &x));
-  covariance_blocks.push_back(std::make_pair(&y, &y));
+  std::vector<std::pair<const double*, const double*>> covariance_blocks;
+  covariance_blocks.emplace_back(&x, &x);
+  covariance_blocks.emplace_back(&x, &y);
+  covariance_blocks.emplace_back(&y, &x);
+  covariance_blocks.emplace_back(&y, &y);
   EXPECT_TRUE(covariance.Compute(covariance_blocks, &problem));
 
   double value = -1;
@@ -1232,22 +1239,22 @@
   EXPECT_NEAR(value, 0.0, std::numeric_limits<double>::epsilon());
 }
 
-TEST(Covariance, ZeroSizedLocalParameterizationGetCovarianceInTangentSpace) {
+TEST(Covariance, ZeroSizedManifoldGetCovarianceInTangentSpace) {
   double x = 0.0;
   double y = 1.0;
   Problem problem;
   problem.AddResidualBlock(LinearCostFunction::Create(), nullptr, &x, &y);
-  problem.SetParameterization(&y, new SubsetParameterization(1, {0}));
+  problem.SetManifold(&y, new SubsetManifold(1, {0}));
   // J = [-1 0]
   //     [ 0 0]
   Covariance::Options options;
   options.algorithm_type = DENSE_SVD;
   Covariance covariance(options);
-  vector<pair<const double*, const double*>> covariance_blocks;
-  covariance_blocks.push_back(std::make_pair(&x, &x));
-  covariance_blocks.push_back(std::make_pair(&x, &y));
-  covariance_blocks.push_back(std::make_pair(&y, &x));
-  covariance_blocks.push_back(std::make_pair(&y, &y));
+  std::vector<std::pair<const double*, const double*>> covariance_blocks;
+  covariance_blocks.emplace_back(&x, &x);
+  covariance_blocks.emplace_back(&x, &y);
+  covariance_blocks.emplace_back(&y, &x);
+  covariance_blocks.emplace_back(&y, &y);
   EXPECT_TRUE(covariance.Compute(covariance_blocks, &problem));
 
   double value = -1;
@@ -1270,8 +1277,8 @@
   void SetUp() final {
     num_parameter_blocks_ = 2000;
     parameter_block_size_ = 5;
-    parameters_.reset(
-        new double[parameter_block_size_ * num_parameter_blocks_]);
+    parameters_ = std::make_unique<double[]>(parameter_block_size_ *
+                                             num_parameter_blocks_);
 
     Matrix jacobian(parameter_block_size_, parameter_block_size_);
     for (int i = 0; i < num_parameter_blocks_; ++i) {
@@ -1282,11 +1289,11 @@
       problem_.AddResidualBlock(
           new UnaryCostFunction(
               parameter_block_size_, parameter_block_size_, jacobian.data()),
-          NULL,
+          nullptr,
           block_i);
       for (int j = i; j < num_parameter_blocks_; ++j) {
         double* block_j = parameters_.get() + j * parameter_block_size_;
-        all_covariance_blocks_.push_back(make_pair(block_i, block_j));
+        all_covariance_blocks_.emplace_back(block_i, block_j);
       }
     }
   }
@@ -1339,16 +1346,16 @@
   int num_parameter_blocks_;
 
   Problem problem_;
-  vector<pair<const double*, const double*>> all_covariance_blocks_;
+  std::vector<std::pair<const double*, const double*>> all_covariance_blocks_;
 };
 
-#if !defined(CERES_NO_SUITESPARSE) && defined(CERES_USE_OPENMP)
+#if !defined(CERES_NO_SUITESPARSE)
 
 TEST_F(LargeScaleCovarianceTest, Parallel) {
   ComputeAndCompare(SPARSE_QR, SUITE_SPARSE, 4);
 }
 
-#endif  // !defined(CERES_NO_SUITESPARSE) && defined(CERES_USE_OPENMP)
+#endif  // !defined(CERES_NO_SUITESPARSE)
 
 }  // namespace internal
 }  // namespace ceres
diff --git a/third_party/ceres/internal/ceres/cubic_interpolation_test.cc b/third_party/ceres/internal/ceres/cubic_interpolation_test.cc
index 3907d22..c02951e 100644
--- a/third_party/ceres/internal/ceres/cubic_interpolation_test.cc
+++ b/third_party/ceres/internal/ceres/cubic_interpolation_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -36,8 +36,7 @@
 #include "glog/logging.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 static constexpr double kTolerance = 1e-12;
 
@@ -226,7 +225,7 @@
                                       const double b,
                                       const double c,
                                       const double d) {
-    values_.reset(new double[kDataDimension * kNumSamples]);
+    values_ = std::make_unique<double[]>(kDataDimension * kNumSamples);
 
     for (int x = 0; x < kNumSamples; ++x) {
       for (int dim = 0; dim < kDataDimension; ++dim) {
@@ -335,7 +334,7 @@
 
   template <int kDataDimension>
   void RunPolynomialInterpolationTest(const Eigen::Matrix3d& coeff) {
-    values_.reset(new double[kNumRows * kNumCols * kDataDimension]);
+    values_ = std::make_unique<double[]>(kNumRows * kNumCols * kDataDimension);
     coeff_ = coeff;
     double* v = values_.get();
     for (int r = 0; r < kNumRows; ++r) {
@@ -530,5 +529,4 @@
               kTolerance);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/cuda_block_sparse_crs_view.cc b/third_party/ceres/internal/ceres/cuda_block_sparse_crs_view.cc
new file mode 100644
index 0000000..7564d52
--- /dev/null
+++ b/third_party/ceres/internal/ceres/cuda_block_sparse_crs_view.cc
@@ -0,0 +1,103 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Authors: dmitriy.korchemkin@gmail.com (Dmitriy Korchemkin)
+
+#include "ceres/cuda_block_sparse_crs_view.h"
+
+#ifndef CERES_NO_CUDA
+
+#include "ceres/cuda_kernels_bsm_to_crs.h"
+
+namespace ceres::internal {
+
+CudaBlockSparseCRSView::CudaBlockSparseCRSView(const BlockSparseMatrix& bsm,
+                                               ContextImpl* context)
+    : context_(context) {
+  block_structure_ = std::make_unique<CudaBlockSparseStructure>(
+      *bsm.block_structure(), context);
+  CudaBuffer<int32_t> rows(context, bsm.num_rows() + 1);
+  CudaBuffer<int32_t> cols(context, bsm.num_nonzeros());
+  FillCRSStructure(block_structure_->num_row_blocks(),
+                   bsm.num_rows(),
+                   block_structure_->first_cell_in_row_block(),
+                   block_structure_->cells(),
+                   block_structure_->row_blocks(),
+                   block_structure_->col_blocks(),
+                   rows.data(),
+                   cols.data(),
+                   context->DefaultStream(),
+                   context->is_cuda_memory_pools_supported_);
+  is_crs_compatible_ = block_structure_->IsCrsCompatible();
+  // if matrix is crs-compatible - we can drop block-structure and don't need
+  // streamed_buffer_
+  if (is_crs_compatible_) {
+    VLOG(3) << "Block-sparse matrix is compatible with CRS, discarding "
+               "block-structure";
+    block_structure_ = nullptr;
+  } else {
+    streamed_buffer_ = std::make_unique<CudaStreamedBuffer<double>>(
+        context_, kMaxTemporaryArraySize);
+  }
+  crs_matrix_ = std::make_unique<CudaSparseMatrix>(
+      bsm.num_cols(), std::move(rows), std::move(cols), context);
+  UpdateValues(bsm);
+}
+
+void CudaBlockSparseCRSView::UpdateValues(const BlockSparseMatrix& bsm) {
+  if (is_crs_compatible_) {
+    // Values of CRS-compatible matrices can be copied as-is
+    CHECK_EQ(cudaSuccess,
+             cudaMemcpyAsync(crs_matrix_->mutable_values(),
+                             bsm.values(),
+                             bsm.num_nonzeros() * sizeof(double),
+                             cudaMemcpyHostToDevice,
+                             context_->DefaultStream()));
+    return;
+  }
+  streamed_buffer_->CopyToGpu(
+      bsm.values(),
+      bsm.num_nonzeros(),
+      [bs = block_structure_.get(), crs = crs_matrix_.get()](
+          const double* values, int num_values, int offset, auto stream) {
+        PermuteToCRS(offset,
+                     num_values,
+                     bs->num_row_blocks(),
+                     bs->first_cell_in_row_block(),
+                     bs->cells(),
+                     bs->row_blocks(),
+                     bs->col_blocks(),
+                     crs->rows(),
+                     values,
+                     crs->mutable_values(),
+                     stream);
+      });
+}
+
+}  // namespace ceres::internal
+#endif  // CERES_NO_CUDA
diff --git a/third_party/ceres/internal/ceres/cuda_block_sparse_crs_view.h b/third_party/ceres/internal/ceres/cuda_block_sparse_crs_view.h
new file mode 100644
index 0000000..58ef618
--- /dev/null
+++ b/third_party/ceres/internal/ceres/cuda_block_sparse_crs_view.h
@@ -0,0 +1,108 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Authors: dmitriy.korchemkin@gmail.com (Dmitriy Korchemkin)
+//
+
+#ifndef CERES_INTERNAL_CUDA_BLOCK_SPARSE_CRS_VIEW_H_
+#define CERES_INTERNAL_CUDA_BLOCK_SPARSE_CRS_VIEW_H_
+
+#include "ceres/internal/config.h"
+
+#ifndef CERES_NO_CUDA
+
+#include <memory>
+
+#include "ceres/block_sparse_matrix.h"
+#include "ceres/cuda_block_structure.h"
+#include "ceres/cuda_buffer.h"
+#include "ceres/cuda_sparse_matrix.h"
+#include "ceres/cuda_streamed_buffer.h"
+
+namespace ceres::internal {
+// We use cuSPARSE library for SpMV operations. However, it does not support
+// block-sparse format with varying size of the blocks. Thus, we perform the
+// following operations in order to compute products of block-sparse matrices
+// and dense vectors on gpu:
+//  - Once per block-sparse structure update:
+//    - Compute CRS structure from block-sparse structure and check if values of
+//    block-sparse matrix would have the same order as values of CRS matrix
+//  - Once per block-sparse values update:
+//    - Update values in CRS matrix with values of block-sparse matrix
+//
+// Only block-sparse matrices with sequential order of cells are supported.
+//
+// UpdateValues method updates values:
+//  - In a single host-to-device copy for matrices with CRS-compatible value
+//  layout
+//  - Simultaneously transferring and permuting values using CudaStreamedBuffer
+//  otherwise
+class CERES_NO_EXPORT CudaBlockSparseCRSView {
+ public:
+  // Initializes internal CRS matrix using structure and values of block-sparse
+  // matrix For block-sparse matrices that have value layout different from CRS
+  // block-sparse structure will be stored/
+  CudaBlockSparseCRSView(const BlockSparseMatrix& bsm, ContextImpl* context);
+
+  const CudaSparseMatrix* crs_matrix() const { return crs_matrix_.get(); }
+  CudaSparseMatrix* mutable_crs_matrix() { return crs_matrix_.get(); }
+
+  // Update values of crs_matrix_ using values of block-sparse matrix.
+  // Assumes that bsm has the same block-sparse structure as matrix that was
+  // used for construction.
+  void UpdateValues(const BlockSparseMatrix& bsm);
+
+  // Returns true if block-sparse matrix had CRS-compatible value layout
+  bool IsCrsCompatible() const { return is_crs_compatible_; }
+
+  void LeftMultiplyAndAccumulate(const CudaVector& x, CudaVector* y) const {
+    crs_matrix()->LeftMultiplyAndAccumulate(x, y);
+  }
+
+  void RightMultiplyAndAccumulate(const CudaVector& x, CudaVector* y) const {
+    crs_matrix()->RightMultiplyAndAccumulate(x, y);
+  }
+
+ private:
+  // Value permutation kernel performs a single element-wise operation per
+  // thread, thus performing permutation in blocks of 8 megabytes of
+  // block-sparse  values seems reasonable
+  static constexpr int kMaxTemporaryArraySize = 1 * 1024 * 1024;
+  std::unique_ptr<CudaSparseMatrix> crs_matrix_;
+  // Only created if block-sparse matrix has non-CRS value layout
+  std::unique_ptr<CudaStreamedBuffer<double>> streamed_buffer_;
+  // Only stored if block-sparse matrix has non-CRS value layout
+  std::unique_ptr<CudaBlockSparseStructure> block_structure_;
+  bool is_crs_compatible_;
+  ContextImpl* context_;
+};
+
+}  // namespace ceres::internal
+
+#endif  // CERES_NO_CUDA
+#endif  // CERES_INTERNAL_CUDA_BLOCK_SPARSE_CRS_VIEW_H_
diff --git a/third_party/ceres/internal/ceres/cuda_block_sparse_crs_view_test.cc b/third_party/ceres/internal/ceres/cuda_block_sparse_crs_view_test.cc
new file mode 100644
index 0000000..7d7d46c
--- /dev/null
+++ b/third_party/ceres/internal/ceres/cuda_block_sparse_crs_view_test.cc
@@ -0,0 +1,164 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Authors: dmitriy.korchemkin@gmail.com (Dmitriy Korchemkin)
+
+#include "ceres/cuda_block_sparse_crs_view.h"
+
+#include <glog/logging.h>
+#include <gtest/gtest.h>
+
+#include <numeric>
+
+#ifndef CERES_NO_CUDA
+
+namespace ceres::internal {
+class CudaBlockSparseCRSViewTest : public ::testing::Test {
+ protected:
+  void SetUp() final {
+    std::string message;
+    CHECK(context_.InitCuda(&message))
+        << "InitCuda() failed because: " << message;
+
+    BlockSparseMatrix::RandomMatrixOptions options;
+    options.num_row_blocks = 1234;
+    options.min_row_block_size = 1;
+    options.max_row_block_size = 10;
+    options.num_col_blocks = 567;
+    options.min_col_block_size = 1;
+    options.max_col_block_size = 10;
+    options.block_density = 0.2;
+    std::mt19937 rng;
+
+    // Block-sparse matrix with order of values different from CRS
+    block_sparse_non_crs_compatible_ =
+        BlockSparseMatrix::CreateRandomMatrix(options, rng, true);
+    std::iota(block_sparse_non_crs_compatible_->mutable_values(),
+              block_sparse_non_crs_compatible_->mutable_values() +
+                  block_sparse_non_crs_compatible_->num_nonzeros(),
+              1);
+
+    options.max_row_block_size = 1;
+    // Block-sparse matrix with CRS order of values (row-blocks are rows)
+    block_sparse_crs_compatible_rows_ =
+        BlockSparseMatrix::CreateRandomMatrix(options, rng, true);
+    std::iota(block_sparse_crs_compatible_rows_->mutable_values(),
+              block_sparse_crs_compatible_rows_->mutable_values() +
+                  block_sparse_crs_compatible_rows_->num_nonzeros(),
+              1);
+    // Block-sparse matrix with CRS order of values (single cell per row-block)
+    auto bs = std::make_unique<CompressedRowBlockStructure>(
+        *block_sparse_non_crs_compatible_->block_structure());
+
+    int num_nonzeros = 0;
+    for (auto& r : bs->rows) {
+      const int num_cells = r.cells.size();
+      if (num_cells > 1) {
+        std::uniform_int_distribution<int> uniform_cell(0, num_cells - 1);
+        const int selected_cell = uniform_cell(rng);
+        std::swap(r.cells[0], r.cells[selected_cell]);
+        r.cells.resize(1);
+      }
+      const int row_block_size = r.block.size;
+      for (auto& c : r.cells) {
+        c.position = num_nonzeros;
+        const int col_block_size = bs->cols[c.block_id].size;
+        num_nonzeros += col_block_size * row_block_size;
+      }
+    }
+    block_sparse_crs_compatible_single_cell_ =
+        std::make_unique<BlockSparseMatrix>(bs.release());
+    std::iota(block_sparse_crs_compatible_single_cell_->mutable_values(),
+              block_sparse_crs_compatible_single_cell_->mutable_values() +
+                  block_sparse_crs_compatible_single_cell_->num_nonzeros(),
+              1);
+  }
+
+  void Compare(const BlockSparseMatrix& bsm, const CudaSparseMatrix& csm) {
+    ASSERT_EQ(csm.num_cols(), bsm.num_cols());
+    ASSERT_EQ(csm.num_rows(), bsm.num_rows());
+    ASSERT_EQ(csm.num_nonzeros(), bsm.num_nonzeros());
+    const int num_rows = bsm.num_rows();
+    const int num_cols = bsm.num_cols();
+    Vector x(num_cols);
+    Vector y(num_rows);
+    CudaVector x_cuda(&context_, num_cols);
+    CudaVector y_cuda(&context_, num_rows);
+    Vector y_cuda_host(num_rows);
+
+    for (int i = 0; i < num_cols; ++i) {
+      x.setZero();
+      y.setZero();
+      y_cuda.SetZero();
+      x[i] = 1.;
+      x_cuda.CopyFromCpu(x);
+      csm.RightMultiplyAndAccumulate(x_cuda, &y_cuda);
+      bsm.RightMultiplyAndAccumulate(
+          x.data(), y.data(), &context_, std::thread::hardware_concurrency());
+      y_cuda.CopyTo(&y_cuda_host);
+      // There will be up to 1 non-zero product per row, thus we expect an exact
+      // match on 32-bit integer indices
+      EXPECT_EQ((y - y_cuda_host).squaredNorm(), 0.);
+    }
+  }
+
+  std::unique_ptr<BlockSparseMatrix> block_sparse_non_crs_compatible_;
+  std::unique_ptr<BlockSparseMatrix> block_sparse_crs_compatible_rows_;
+  std::unique_ptr<BlockSparseMatrix> block_sparse_crs_compatible_single_cell_;
+  ContextImpl context_;
+};
+
+TEST_F(CudaBlockSparseCRSViewTest, CreateUpdateValuesNonCompatible) {
+  auto view =
+      CudaBlockSparseCRSView(*block_sparse_non_crs_compatible_, &context_);
+  ASSERT_EQ(view.IsCrsCompatible(), false);
+
+  auto matrix = view.crs_matrix();
+  Compare(*block_sparse_non_crs_compatible_, *matrix);
+}
+
+TEST_F(CudaBlockSparseCRSViewTest, CreateUpdateValuesCompatibleRows) {
+  auto view =
+      CudaBlockSparseCRSView(*block_sparse_crs_compatible_rows_, &context_);
+  ASSERT_EQ(view.IsCrsCompatible(), true);
+
+  auto matrix = view.crs_matrix();
+  Compare(*block_sparse_crs_compatible_rows_, *matrix);
+}
+
+TEST_F(CudaBlockSparseCRSViewTest, CreateUpdateValuesCompatibleSingleCell) {
+  auto view = CudaBlockSparseCRSView(*block_sparse_crs_compatible_single_cell_,
+                                     &context_);
+  ASSERT_EQ(view.IsCrsCompatible(), true);
+
+  auto matrix = view.crs_matrix();
+  Compare(*block_sparse_crs_compatible_single_cell_, *matrix);
+}
+}  // namespace ceres::internal
+
+#endif  // CERES_NO_CUDA
diff --git a/third_party/ceres/internal/ceres/cuda_block_structure.cc b/third_party/ceres/internal/ceres/cuda_block_structure.cc
new file mode 100644
index 0000000..3685775
--- /dev/null
+++ b/third_party/ceres/internal/ceres/cuda_block_structure.cc
@@ -0,0 +1,234 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Authors: dmitriy.korchemkin@gmail.com (Dmitriy Korchemkin)
+
+#include "ceres/cuda_block_structure.h"
+
+#ifndef CERES_NO_CUDA
+
+namespace ceres::internal {
+namespace {
+// Dimension of a sorted array of blocks
+inline int Dimension(const std::vector<Block>& blocks) {
+  if (blocks.empty()) {
+    return 0;
+  }
+  const auto& last = blocks.back();
+  return last.size + last.position;
+}
+}  // namespace
+CudaBlockSparseStructure::CudaBlockSparseStructure(
+    const CompressedRowBlockStructure& block_structure, ContextImpl* context)
+    : CudaBlockSparseStructure(block_structure, 0, context) {}
+
+CudaBlockSparseStructure::CudaBlockSparseStructure(
+    const CompressedRowBlockStructure& block_structure,
+    const int num_col_blocks_e,
+    ContextImpl* context)
+    : first_cell_in_row_block_(context),
+      value_offset_row_block_f_(context),
+      cells_(context),
+      row_blocks_(context),
+      col_blocks_(context) {
+  // Row blocks extracted from CompressedRowBlockStructure::rows
+  std::vector<Block> row_blocks;
+  // Column blocks can be reused as-is
+  const auto& col_blocks = block_structure.cols;
+
+  // Row block offset is an index of the first cell corresponding to row block
+  std::vector<int> first_cell_in_row_block;
+  // Offset of the first value in the first non-empty row-block of F sub-matrix
+  std::vector<int> value_offset_row_block_f;
+  // Flat array of all cells from all row-blocks
+  std::vector<Cell> cells;
+
+  int f_values_offset = -1;
+  num_nonzeros_e_ = 0;
+  is_crs_compatible_ = true;
+  num_row_blocks_ = block_structure.rows.size();
+  num_col_blocks_ = col_blocks.size();
+
+  row_blocks.reserve(num_row_blocks_);
+  first_cell_in_row_block.reserve(num_row_blocks_ + 1);
+  value_offset_row_block_f.reserve(num_row_blocks_ + 1);
+  num_nonzeros_ = 0;
+  // Block-sparse matrices arising from block-jacobian writer are expected to
+  // have sequential layout (for partitioned matrices - it is expected that both
+  // E and F sub-matrices have sequential layout).
+  bool sequential_layout = true;
+  int row_block_id = 0;
+  num_row_blocks_e_ = 0;
+  for (; row_block_id < num_row_blocks_; ++row_block_id) {
+    const auto& r = block_structure.rows[row_block_id];
+    const int row_block_size = r.block.size;
+    const int num_cells = r.cells.size();
+
+    if (num_col_blocks_e == 0 || r.cells.size() == 0 ||
+        r.cells[0].block_id >= num_col_blocks_e) {
+      break;
+    }
+    num_row_blocks_e_ = row_block_id + 1;
+    // In E sub-matrix there is exactly a single E cell in the row
+    // since E cells are stored separately from F cells, crs-compatiblity of
+    // F sub-matrix only breaks if there are more than 2 cells in row (that
+    // is, more than 1 cell in F sub-matrix)
+    if (num_cells > 2 && row_block_size > 1) {
+      is_crs_compatible_ = false;
+    }
+    row_blocks.emplace_back(r.block);
+    first_cell_in_row_block.push_back(cells.size());
+
+    for (int cell_id = 0; cell_id < num_cells; ++cell_id) {
+      const auto& c = r.cells[cell_id];
+      const int col_block_size = col_blocks[c.block_id].size;
+      const int cell_size = col_block_size * row_block_size;
+      cells.push_back(c);
+      if (cell_id == 0) {
+        DCHECK(c.position == num_nonzeros_e_);
+        num_nonzeros_e_ += cell_size;
+      } else {
+        if (f_values_offset == -1) {
+          num_nonzeros_ = c.position;
+          f_values_offset = c.position;
+        }
+        sequential_layout &= c.position == num_nonzeros_;
+        num_nonzeros_ += cell_size;
+        if (cell_id == 1) {
+          // Correct value_offset_row_block_f for empty row-blocks of F
+          // preceding this one
+          for (auto it = value_offset_row_block_f.rbegin();
+               it != value_offset_row_block_f.rend();
+               ++it) {
+            if (*it != -1) break;
+            *it = c.position;
+          }
+          value_offset_row_block_f.push_back(c.position);
+        }
+      }
+    }
+    if (num_cells == 1) {
+      value_offset_row_block_f.push_back(-1);
+    }
+  }
+  for (; row_block_id < num_row_blocks_; ++row_block_id) {
+    const auto& r = block_structure.rows[row_block_id];
+    const int row_block_size = r.block.size;
+    const int num_cells = r.cells.size();
+    // After num_row_blocks_e_ row-blocks, there should be no cells in E
+    // sub-matrix. Thus crs-compatibility of F sub-matrix breaks if there are
+    // more than one cells in the row-block
+    if (num_cells > 1 && row_block_size > 1) {
+      is_crs_compatible_ = false;
+    }
+    row_blocks.emplace_back(r.block);
+    first_cell_in_row_block.push_back(cells.size());
+
+    if (r.cells.empty()) {
+      value_offset_row_block_f.push_back(-1);
+    } else {
+      for (auto it = value_offset_row_block_f.rbegin();
+           it != value_offset_row_block_f.rend();
+           --it) {
+        if (*it != -1) break;
+        *it = cells[0].position;
+      }
+      value_offset_row_block_f.push_back(r.cells[0].position);
+    }
+    for (const auto& c : r.cells) {
+      const int col_block_size = col_blocks[c.block_id].size;
+      const int cell_size = col_block_size * row_block_size;
+      cells.push_back(c);
+      DCHECK(c.block_id >= num_col_blocks_e);
+      if (f_values_offset == -1) {
+        num_nonzeros_ = c.position;
+        f_values_offset = c.position;
+      }
+      sequential_layout &= c.position == num_nonzeros_;
+      num_nonzeros_ += cell_size;
+    }
+  }
+
+  if (f_values_offset == -1) {
+    f_values_offset = num_nonzeros_e_;
+    num_nonzeros_ = num_nonzeros_e_;
+  }
+  // Fill non-zero offsets for the last rows of F submatrix
+  for (auto it = value_offset_row_block_f.rbegin();
+       it != value_offset_row_block_f.rend();
+       ++it) {
+    if (*it != -1) break;
+    *it = num_nonzeros_;
+  }
+  value_offset_row_block_f.push_back(num_nonzeros_);
+  CHECK_EQ(num_nonzeros_e_, f_values_offset);
+  first_cell_in_row_block.push_back(cells.size());
+  num_cells_ = cells.size();
+
+  num_rows_ = Dimension(row_blocks);
+  num_cols_ = Dimension(col_blocks);
+
+  CHECK(sequential_layout);
+
+  if (VLOG_IS_ON(3)) {
+    const size_t first_cell_in_row_block_size =
+        first_cell_in_row_block.size() * sizeof(int);
+    const size_t cells_size = cells.size() * sizeof(Cell);
+    const size_t row_blocks_size = row_blocks.size() * sizeof(Block);
+    const size_t col_blocks_size = col_blocks.size() * sizeof(Block);
+    const size_t total_size = first_cell_in_row_block_size + cells_size +
+                              col_blocks_size + row_blocks_size;
+    const double ratio =
+        (100. * total_size) / (num_nonzeros_ * (sizeof(int) + sizeof(double)) +
+                               num_rows_ * sizeof(int));
+    VLOG(3) << "\nCudaBlockSparseStructure:\n"
+               "\tRow block offsets: "
+            << first_cell_in_row_block_size
+            << " bytes\n"
+               "\tColumn blocks: "
+            << col_blocks_size
+            << " bytes\n"
+               "\tRow blocks: "
+            << row_blocks_size
+            << " bytes\n"
+               "\tCells: "
+            << cells_size << " bytes\n\tTotal: " << total_size
+            << " bytes of GPU memory (" << ratio << "% of CRS matrix size)";
+  }
+
+  first_cell_in_row_block_.CopyFromCpuVector(first_cell_in_row_block);
+  cells_.CopyFromCpuVector(cells);
+  row_blocks_.CopyFromCpuVector(row_blocks);
+  col_blocks_.CopyFromCpuVector(col_blocks);
+  if (num_col_blocks_e || num_row_blocks_e_) {
+    value_offset_row_block_f_.CopyFromCpuVector(value_offset_row_block_f);
+  }
+}
+}  // namespace ceres::internal
+
+#endif  // CERES_NO_CUDA
diff --git a/third_party/ceres/internal/ceres/cuda_block_structure.h b/third_party/ceres/internal/ceres/cuda_block_structure.h
new file mode 100644
index 0000000..6da6fdd
--- /dev/null
+++ b/third_party/ceres/internal/ceres/cuda_block_structure.h
@@ -0,0 +1,120 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Authors: dmitriy.korchemkin@gmail.com (Dmitriy Korchemkin)
+
+#ifndef CERES_INTERNAL_CUDA_BLOCK_STRUCTURE_H_
+#define CERES_INTERNAL_CUDA_BLOCK_STRUCTURE_H_
+
+#include "ceres/internal/config.h"
+
+#ifndef CERES_NO_CUDA
+
+#include "ceres/block_structure.h"
+#include "ceres/cuda_buffer.h"
+
+namespace ceres::internal {
+class CudaBlockStructureTest;
+
+// This class stores a read-only block-sparse structure in gpu memory.
+// Invariants are the same as those of CompressedRowBlockStructure.
+// In order to simplify allocation and copying data to gpu, cells from all
+// row-blocks are stored in a single array sequentially. Array
+// first_cell_in_row_block of size num_row_blocks + 1 allows to identify range
+// of cells corresponding to a row-block. Cells corresponding to i-th row-block
+// are stored in sub-array cells[first_cell_in_row_block[i]; ...
+// first_cell_in_row_block[i + 1] - 1], and their order is preserved.
+class CERES_NO_EXPORT CudaBlockSparseStructure {
+ public:
+  // CompressedRowBlockStructure is contains a vector of CompressedLists, with
+  // each CompressedList containing a vector of Cells. We precompute a flat
+  // array of cells on cpu and transfer it to the gpu.
+  CudaBlockSparseStructure(const CompressedRowBlockStructure& block_structure,
+                           ContextImpl* context);
+  // In the case of partitioned matrices, number of non-zeros in E and layout of
+  // F are computed
+  CudaBlockSparseStructure(const CompressedRowBlockStructure& block_structure,
+                           const int num_col_blocks_e,
+                           ContextImpl* context);
+
+  int num_rows() const { return num_rows_; }
+  int num_cols() const { return num_cols_; }
+  int num_cells() const { return num_cells_; }
+  int num_nonzeros() const { return num_nonzeros_; }
+  // When partitioned matrix constructor was used, returns number of non-zeros
+  // in E sub-matrix
+  int num_nonzeros_e() const { return num_nonzeros_e_; }
+  int num_row_blocks() const { return num_row_blocks_; }
+  int num_row_blocks_e() const { return num_row_blocks_e_; }
+  int num_col_blocks() const { return num_col_blocks_; }
+
+  // Returns true if values from block-sparse matrix (F sub-matrix in
+  // partitioned case) can be copied to CRS matrix as-is. This is possible if
+  // each row-block is stored in CRS order:
+  //  - Row-block consists of a single row
+  //  - Row-block contains a single cell
+  bool IsCrsCompatible() const { return is_crs_compatible_; }
+
+  // Device pointer to array of num_row_blocks + 1 indices of the first cell of
+  // row block
+  const int* first_cell_in_row_block() const {
+    return first_cell_in_row_block_.data();
+  }
+  // Device pointer to array of num_row_blocks + 1 indices of the first value in
+  // this or subsequent row-blocks of submatrix F
+  const int* value_offset_row_block_f() const {
+    return value_offset_row_block_f_.data();
+  }
+  // Device pointer to array of num_cells cells, sorted by row-block
+  const Cell* cells() const { return cells_.data(); }
+  // Device pointer to array of row blocks
+  const Block* row_blocks() const { return row_blocks_.data(); }
+  // Device pointer to array of column blocks
+  const Block* col_blocks() const { return col_blocks_.data(); }
+
+ private:
+  int num_rows_;
+  int num_cols_;
+  int num_cells_;
+  int num_nonzeros_;
+  int num_nonzeros_e_;
+  int num_row_blocks_;
+  int num_row_blocks_e_;
+  int num_col_blocks_;
+  bool is_crs_compatible_;
+  CudaBuffer<int> first_cell_in_row_block_;
+  CudaBuffer<int> value_offset_row_block_f_;
+  CudaBuffer<Cell> cells_;
+  CudaBuffer<Block> row_blocks_;
+  CudaBuffer<Block> col_blocks_;
+  friend class CudaBlockStructureTest;
+};
+}  // namespace ceres::internal
+
+#endif  // CERES_NO_CUDA
+#endif  // CERES_INTERNAL_CUDA_BLOCK_SPARSE_STRUCTURE_H_
diff --git a/third_party/ceres/internal/ceres/cuda_block_structure_test.cc b/third_party/ceres/internal/ceres/cuda_block_structure_test.cc
new file mode 100644
index 0000000..daff431
--- /dev/null
+++ b/third_party/ceres/internal/ceres/cuda_block_structure_test.cc
@@ -0,0 +1,144 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Authors: dmitriy.korchemkin@gmail.com (Dmitriy Korchemkin)
+
+#include "ceres/internal/config.h"
+
+#ifndef CERES_NO_CUDA
+
+#include <glog/logging.h>
+#include <gtest/gtest.h>
+
+#include <numeric>
+
+#include "ceres/block_sparse_matrix.h"
+#include "ceres/cuda_block_structure.h"
+
+namespace ceres::internal {
+
+class CudaBlockStructureTest : public ::testing::Test {
+ protected:
+  void SetUp() final {
+    std::string message;
+    CHECK(context_.InitCuda(&message))
+        << "InitCuda() failed because: " << message;
+
+    BlockSparseMatrix::RandomMatrixOptions options;
+    options.num_row_blocks = 1234;
+    options.min_row_block_size = 1;
+    options.max_row_block_size = 10;
+    options.num_col_blocks = 567;
+    options.min_col_block_size = 1;
+    options.max_col_block_size = 10;
+    options.block_density = 0.2;
+    std::mt19937 rng;
+    A_ = BlockSparseMatrix::CreateRandomMatrix(options, rng);
+    std::iota(
+        A_->mutable_values(), A_->mutable_values() + A_->num_nonzeros(), 1);
+  }
+
+  std::vector<Cell> GetCells(const CudaBlockSparseStructure& structure) {
+    const auto& cuda_buffer = structure.cells_;
+    std::vector<Cell> cells(cuda_buffer.size());
+    cuda_buffer.CopyToCpu(cells.data(), cells.size());
+    return cells;
+  }
+  std::vector<Block> GetRowBlocks(const CudaBlockSparseStructure& structure) {
+    const auto& cuda_buffer = structure.row_blocks_;
+    std::vector<Block> blocks(cuda_buffer.size());
+    cuda_buffer.CopyToCpu(blocks.data(), blocks.size());
+    return blocks;
+  }
+  std::vector<Block> GetColBlocks(const CudaBlockSparseStructure& structure) {
+    const auto& cuda_buffer = structure.col_blocks_;
+    std::vector<Block> blocks(cuda_buffer.size());
+    cuda_buffer.CopyToCpu(blocks.data(), blocks.size());
+    return blocks;
+  }
+  std::vector<int> GetRowBlockOffsets(
+      const CudaBlockSparseStructure& structure) {
+    const auto& cuda_buffer = structure.first_cell_in_row_block_;
+    std::vector<int> first_cell_in_row_block(cuda_buffer.size());
+    cuda_buffer.CopyToCpu(first_cell_in_row_block.data(),
+                          first_cell_in_row_block.size());
+    return first_cell_in_row_block;
+  }
+
+  std::unique_ptr<BlockSparseMatrix> A_;
+  ContextImpl context_;
+};
+
+TEST_F(CudaBlockStructureTest, StructureIdentity) {
+  auto block_structure = A_->block_structure();
+  const int num_row_blocks = block_structure->rows.size();
+  const int num_col_blocks = block_structure->cols.size();
+
+  CudaBlockSparseStructure cuda_block_structure(*block_structure, &context_);
+
+  ASSERT_EQ(cuda_block_structure.num_rows(), A_->num_rows());
+  ASSERT_EQ(cuda_block_structure.num_cols(), A_->num_cols());
+  ASSERT_EQ(cuda_block_structure.num_nonzeros(), A_->num_nonzeros());
+  ASSERT_EQ(cuda_block_structure.num_row_blocks(), num_row_blocks);
+  ASSERT_EQ(cuda_block_structure.num_col_blocks(), num_col_blocks);
+
+  std::vector<Block> blocks = GetColBlocks(cuda_block_structure);
+  ASSERT_EQ(blocks.size(), num_col_blocks);
+  for (int i = 0; i < num_col_blocks; ++i) {
+    EXPECT_EQ(block_structure->cols[i].position, blocks[i].position);
+    EXPECT_EQ(block_structure->cols[i].size, blocks[i].size);
+  }
+
+  std::vector<Cell> cells = GetCells(cuda_block_structure);
+  std::vector<int> first_cell_in_row_block =
+      GetRowBlockOffsets(cuda_block_structure);
+  blocks = GetRowBlocks(cuda_block_structure);
+
+  ASSERT_EQ(blocks.size(), num_row_blocks);
+  ASSERT_EQ(first_cell_in_row_block.size(), num_row_blocks + 1);
+  ASSERT_EQ(first_cell_in_row_block.back(), cells.size());
+
+  for (int i = 0; i < num_row_blocks; ++i) {
+    const int num_cells = block_structure->rows[i].cells.size();
+    EXPECT_EQ(blocks[i].position, block_structure->rows[i].block.position);
+    EXPECT_EQ(blocks[i].size, block_structure->rows[i].block.size);
+    const int first_cell = first_cell_in_row_block[i];
+    const int last_cell = first_cell_in_row_block[i + 1];
+    ASSERT_EQ(last_cell - first_cell, num_cells);
+    for (int j = 0; j < num_cells; ++j) {
+      EXPECT_EQ(cells[first_cell + j].block_id,
+                block_structure->rows[i].cells[j].block_id);
+      EXPECT_EQ(cells[first_cell + j].position,
+                block_structure->rows[i].cells[j].position);
+    }
+  }
+}
+
+}  // namespace ceres::internal
+
+#endif  // CERES_NO_CUDA
diff --git a/third_party/ceres/internal/ceres/cuda_buffer.h b/third_party/ceres/internal/ceres/cuda_buffer.h
new file mode 100644
index 0000000..40048fd
--- /dev/null
+++ b/third_party/ceres/internal/ceres/cuda_buffer.h
@@ -0,0 +1,172 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: joydeepb@cs.utexas.edu (Joydeep Biswas)
+
+#ifndef CERES_INTERNAL_CUDA_BUFFER_H_
+#define CERES_INTERNAL_CUDA_BUFFER_H_
+
+#include "ceres/context_impl.h"
+#include "ceres/internal/config.h"
+
+#ifndef CERES_NO_CUDA
+
+#include <vector>
+
+#include "cuda_runtime.h"
+#include "glog/logging.h"
+
+namespace ceres::internal {
+// An encapsulated buffer to maintain GPU memory, and handle transfers between
+// GPU and system memory. It is the responsibility of the user to ensure that
+// the appropriate GPU device is selected before each subroutine is called. This
+// is particularly important when using multiple GPU devices on different CPU
+// threads, since active Cuda devices are determined by the cuda runtime on a
+// per-thread basis.
+template <typename T>
+class CudaBuffer {
+ public:
+  explicit CudaBuffer(ContextImpl* context) : context_(context) {}
+  CudaBuffer(ContextImpl* context, int size) : context_(context) {
+    Reserve(size);
+  }
+
+  CudaBuffer(CudaBuffer&& other)
+      : data_(other.data_), size_(other.size_), context_(other.context_) {
+    other.data_ = nullptr;
+    other.size_ = 0;
+  }
+
+  CudaBuffer(const CudaBuffer&) = delete;
+  CudaBuffer& operator=(const CudaBuffer&) = delete;
+
+  ~CudaBuffer() {
+    if (data_ != nullptr) {
+      CHECK_EQ(cudaFree(data_), cudaSuccess);
+    }
+  }
+
+  // Grow the GPU memory buffer if needed to accommodate data of the specified
+  // size
+  void Reserve(const size_t size) {
+    if (size > size_) {
+      if (data_ != nullptr) {
+        CHECK_EQ(cudaFree(data_), cudaSuccess);
+      }
+      CHECK_EQ(cudaMalloc(&data_, size * sizeof(T)), cudaSuccess)
+          << "Failed to allocate " << size * sizeof(T)
+          << " bytes of GPU memory";
+      size_ = size;
+    }
+  }
+
+  // Perform an asynchronous copy from CPU memory to GPU memory managed by this
+  // CudaBuffer instance using the stream provided.
+  void CopyFromCpu(const T* data, const size_t size) {
+    Reserve(size);
+    CHECK_EQ(cudaMemcpyAsync(data_,
+                             data,
+                             size * sizeof(T),
+                             cudaMemcpyHostToDevice,
+                             context_->DefaultStream()),
+             cudaSuccess);
+  }
+
+  // Perform an asynchronous copy from a vector in CPU memory to GPU memory
+  // managed by this CudaBuffer instance.
+  void CopyFromCpuVector(const std::vector<T>& data) {
+    Reserve(data.size());
+    CHECK_EQ(cudaMemcpyAsync(data_,
+                             data.data(),
+                             data.size() * sizeof(T),
+                             cudaMemcpyHostToDevice,
+                             context_->DefaultStream()),
+             cudaSuccess);
+  }
+
+  // Perform an asynchronous copy from another GPU memory array to the GPU
+  // memory managed by this CudaBuffer instance using the stream provided.
+  void CopyFromGPUArray(const T* data, const size_t size) {
+    Reserve(size);
+    CHECK_EQ(cudaMemcpyAsync(data_,
+                             data,
+                             size * sizeof(T),
+                             cudaMemcpyDeviceToDevice,
+                             context_->DefaultStream()),
+             cudaSuccess);
+  }
+
+  // Copy data from the GPU memory managed by this CudaBuffer instance to CPU
+  // memory. It is the caller's responsibility to ensure that the CPU memory
+  // pointer is valid, i.e. it is not null, and that it points to memory of
+  // at least this->size() size. This method ensures all previously dispatched
+  // GPU operations on the specified stream have completed before copying the
+  // data to CPU memory.
+  void CopyToCpu(T* data, const size_t size) const {
+    CHECK(data_ != nullptr);
+    CHECK_EQ(cudaMemcpyAsync(data,
+                             data_,
+                             size * sizeof(T),
+                             cudaMemcpyDeviceToHost,
+                             context_->DefaultStream()),
+             cudaSuccess);
+    CHECK_EQ(cudaStreamSynchronize(context_->DefaultStream()), cudaSuccess);
+  }
+
+  // Copy N items from another GPU memory array to the GPU memory managed by
+  // this CudaBuffer instance, growing this buffer's size if needed. This copy
+  // is asynchronous, and operates on the stream provided.
+  void CopyNItemsFrom(int n, const CudaBuffer<T>& other) {
+    Reserve(n);
+    CHECK(other.data_ != nullptr);
+    CHECK(data_ != nullptr);
+    CHECK_EQ(cudaMemcpyAsync(data_,
+                             other.data_,
+                             size_ * sizeof(T),
+                             cudaMemcpyDeviceToDevice,
+                             context_->DefaultStream()),
+             cudaSuccess);
+  }
+
+  // Return a pointer to the GPU memory managed by this CudaBuffer instance.
+  T* data() { return data_; }
+  const T* data() const { return data_; }
+  // Return the number of items of type T that can fit in the GPU memory
+  // allocated so far by this CudaBuffer instance.
+  size_t size() const { return size_; }
+
+ private:
+  T* data_ = nullptr;
+  size_t size_ = 0;
+  ContextImpl* context_ = nullptr;
+};
+}  // namespace ceres::internal
+
+#endif  // CERES_NO_CUDA
+
+#endif  // CERES_INTERNAL_CUDA_BUFFER_H_
diff --git a/third_party/ceres/internal/ceres/cuda_dense_cholesky_test.cc b/third_party/ceres/internal/ceres/cuda_dense_cholesky_test.cc
new file mode 100644
index 0000000..b74a75a
--- /dev/null
+++ b/third_party/ceres/internal/ceres/cuda_dense_cholesky_test.cc
@@ -0,0 +1,332 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: joydeepb@cs.utexas.edu (Joydeep Biswas)
+
+#include <string>
+
+#include "ceres/dense_cholesky.h"
+#include "ceres/internal/config.h"
+#include "ceres/internal/eigen.h"
+#include "glog/logging.h"
+#include "gtest/gtest.h"
+
+namespace ceres::internal {
+
+#ifndef CERES_NO_CUDA
+
+TEST(CUDADenseCholesky, InvalidOptionOnCreate) {
+  LinearSolver::Options options;
+  ContextImpl context;
+  options.context = &context;
+  std::string error;
+  EXPECT_TRUE(context.InitCuda(&error)) << error;
+  auto dense_cuda_solver = CUDADenseCholesky::Create(options);
+  EXPECT_EQ(dense_cuda_solver, nullptr);
+}
+
+// Tests the CUDA Cholesky solver with a simple 4x4 matrix.
+TEST(CUDADenseCholesky, Cholesky4x4Matrix) {
+  Eigen::Matrix4d A;
+  // clang-format off
+  A <<  4,  12, -16, 0,
+       12,  37, -43, 0,
+      -16, -43,  98, 0,
+        0,   0,   0, 1;
+  // clang-format on
+
+  Vector b = Eigen::Vector4d::Ones();
+  LinearSolver::Options options;
+  ContextImpl context;
+  options.context = &context;
+  std::string error;
+  EXPECT_TRUE(context.InitCuda(&error)) << error;
+  options.dense_linear_algebra_library_type = CUDA;
+  auto dense_cuda_solver = CUDADenseCholesky::Create(options);
+  ASSERT_NE(dense_cuda_solver, nullptr);
+  std::string error_string;
+  ASSERT_EQ(dense_cuda_solver->Factorize(A.cols(), A.data(), &error_string),
+            LinearSolverTerminationType::SUCCESS);
+  Eigen::Vector4d x = Eigen::Vector4d::Zero();
+  ASSERT_EQ(dense_cuda_solver->Solve(b.data(), x.data(), &error_string),
+            LinearSolverTerminationType::SUCCESS);
+  static const double kEpsilon = std::numeric_limits<double>::epsilon() * 10;
+  const Eigen::Vector4d x_expected(113.75 / 3.0, -31.0 / 3.0, 5.0 / 3.0, 1.0);
+  EXPECT_NEAR((x[0] - x_expected[0]) / x_expected[0], 0.0, kEpsilon);
+  EXPECT_NEAR((x[1] - x_expected[1]) / x_expected[1], 0.0, kEpsilon);
+  EXPECT_NEAR((x[2] - x_expected[2]) / x_expected[2], 0.0, kEpsilon);
+  EXPECT_NEAR((x[3] - x_expected[3]) / x_expected[3], 0.0, kEpsilon);
+}
+
+TEST(CUDADenseCholesky, SingularMatrix) {
+  Eigen::Matrix3d A;
+  // clang-format off
+  A <<  1, 0, 0,
+        0, 1, 0,
+        0, 0, 0;
+  // clang-format on
+
+  LinearSolver::Options options;
+  ContextImpl context;
+  options.context = &context;
+  std::string error;
+  EXPECT_TRUE(context.InitCuda(&error)) << error;
+  options.dense_linear_algebra_library_type = CUDA;
+  auto dense_cuda_solver = CUDADenseCholesky::Create(options);
+  ASSERT_NE(dense_cuda_solver, nullptr);
+  std::string error_string;
+  ASSERT_EQ(dense_cuda_solver->Factorize(A.cols(), A.data(), &error_string),
+            LinearSolverTerminationType::FAILURE);
+}
+
+TEST(CUDADenseCholesky, NegativeMatrix) {
+  Eigen::Matrix3d A;
+  // clang-format off
+  A <<  1, 0, 0,
+        0, 1, 0,
+        0, 0, -1;
+  // clang-format on
+
+  LinearSolver::Options options;
+  ContextImpl context;
+  options.context = &context;
+  std::string error;
+  EXPECT_TRUE(context.InitCuda(&error)) << error;
+  options.dense_linear_algebra_library_type = CUDA;
+  auto dense_cuda_solver = CUDADenseCholesky::Create(options);
+  ASSERT_NE(dense_cuda_solver, nullptr);
+  std::string error_string;
+  ASSERT_EQ(dense_cuda_solver->Factorize(A.cols(), A.data(), &error_string),
+            LinearSolverTerminationType::FAILURE);
+}
+
+TEST(CUDADenseCholesky, MustFactorizeBeforeSolve) {
+  const Eigen::Vector3d b = Eigen::Vector3d::Ones();
+  LinearSolver::Options options;
+  ContextImpl context;
+  options.context = &context;
+  std::string error;
+  EXPECT_TRUE(context.InitCuda(&error)) << error;
+  options.dense_linear_algebra_library_type = CUDA;
+  auto dense_cuda_solver = CUDADenseCholesky::Create(options);
+  ASSERT_NE(dense_cuda_solver, nullptr);
+  std::string error_string;
+  ASSERT_EQ(dense_cuda_solver->Solve(b.data(), nullptr, &error_string),
+            LinearSolverTerminationType::FATAL_ERROR);
+}
+
+TEST(CUDADenseCholesky, Randomized1600x1600Tests) {
+  const int kNumCols = 1600;
+  using LhsType = Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>;
+  using RhsType = Eigen::Matrix<double, Eigen::Dynamic, 1>;
+  using SolutionType = Eigen::Matrix<double, Eigen::Dynamic, 1>;
+
+  LinearSolver::Options options;
+  ContextImpl context;
+  options.context = &context;
+  std::string error;
+  EXPECT_TRUE(context.InitCuda(&error)) << error;
+  options.dense_linear_algebra_library_type = ceres::CUDA;
+  std::unique_ptr<DenseCholesky> dense_cholesky =
+      CUDADenseCholesky::Create(options);
+
+  const int kNumTrials = 20;
+  for (int i = 0; i < kNumTrials; ++i) {
+    LhsType lhs = LhsType::Random(kNumCols, kNumCols);
+    lhs = lhs.transpose() * lhs;
+    lhs += 1e-3 * LhsType::Identity(kNumCols, kNumCols);
+    SolutionType x_expected = SolutionType::Random(kNumCols);
+    RhsType rhs = lhs * x_expected;
+    SolutionType x_computed = SolutionType::Zero(kNumCols);
+    // Sanity check the random matrix sizes.
+    EXPECT_EQ(lhs.rows(), kNumCols);
+    EXPECT_EQ(lhs.cols(), kNumCols);
+    EXPECT_EQ(rhs.rows(), kNumCols);
+    EXPECT_EQ(rhs.cols(), 1);
+    EXPECT_EQ(x_expected.rows(), kNumCols);
+    EXPECT_EQ(x_expected.cols(), 1);
+    EXPECT_EQ(x_computed.rows(), kNumCols);
+    EXPECT_EQ(x_computed.cols(), 1);
+    LinearSolver::Summary summary;
+    summary.termination_type = dense_cholesky->FactorAndSolve(
+        kNumCols, lhs.data(), rhs.data(), x_computed.data(), &summary.message);
+    ASSERT_EQ(summary.termination_type, LinearSolverTerminationType::SUCCESS);
+    static const double kEpsilon = std::numeric_limits<double>::epsilon() * 3e5;
+    ASSERT_NEAR(
+        (x_computed - x_expected).norm() / x_expected.norm(), 0.0, kEpsilon);
+  }
+}
+
+TEST(CUDADenseCholeskyMixedPrecision, InvalidOptionsOnCreate) {
+  {
+    // Did not ask for CUDA, and did not ask for mixed precision.
+    LinearSolver::Options options;
+    ContextImpl context;
+    options.context = &context;
+    std::string error;
+    EXPECT_TRUE(context.InitCuda(&error)) << error;
+    auto solver = CUDADenseCholeskyMixedPrecision::Create(options);
+    ASSERT_EQ(solver, nullptr);
+  }
+  {
+    // Asked for CUDA, but did not ask for mixed precision.
+    LinearSolver::Options options;
+    ContextImpl context;
+    options.context = &context;
+    std::string error;
+    EXPECT_TRUE(context.InitCuda(&error)) << error;
+    options.dense_linear_algebra_library_type = ceres::CUDA;
+    auto solver = CUDADenseCholeskyMixedPrecision::Create(options);
+    ASSERT_EQ(solver, nullptr);
+  }
+}
+
+// Tests the CUDA Cholesky solver with a simple 4x4 matrix.
+TEST(CUDADenseCholeskyMixedPrecision, Cholesky4x4Matrix1Step) {
+  Eigen::Matrix4d A;
+  // clang-format off
+  // A common test Cholesky decomposition test matrix, see :
+  // https://en.wikipedia.org/w/index.php?title=Cholesky_decomposition&oldid=1080607368#Example
+  A <<  4,  12, -16, 0,
+       12,  37, -43, 0,
+      -16, -43,  98, 0,
+        0,   0,   0, 1;
+  // clang-format on
+
+  const Eigen::Vector4d b = Eigen::Vector4d::Ones();
+  LinearSolver::Options options;
+  options.max_num_refinement_iterations = 0;
+  ContextImpl context;
+  options.context = &context;
+  std::string error;
+  EXPECT_TRUE(context.InitCuda(&error)) << error;
+  options.dense_linear_algebra_library_type = CUDA;
+  options.use_mixed_precision_solves = true;
+  auto solver = CUDADenseCholeskyMixedPrecision::Create(options);
+  ASSERT_NE(solver, nullptr);
+  std::string error_string;
+  ASSERT_EQ(solver->Factorize(A.cols(), A.data(), &error_string),
+            LinearSolverTerminationType::SUCCESS);
+  Eigen::Vector4d x = Eigen::Vector4d::Zero();
+  ASSERT_EQ(solver->Solve(b.data(), x.data(), &error_string),
+            LinearSolverTerminationType::SUCCESS);
+  // A single step of the mixed precision solver will be equivalent to solving
+  // in low precision (FP32). Hence the tolerance is defined w.r.t. FP32 epsilon
+  // instead of FP64 epsilon.
+  static const double kEpsilon = std::numeric_limits<float>::epsilon() * 10;
+  const Eigen::Vector4d x_expected(113.75 / 3.0, -31.0 / 3.0, 5.0 / 3.0, 1.0);
+  EXPECT_NEAR((x[0] - x_expected[0]) / x_expected[0], 0.0, kEpsilon);
+  EXPECT_NEAR((x[1] - x_expected[1]) / x_expected[1], 0.0, kEpsilon);
+  EXPECT_NEAR((x[2] - x_expected[2]) / x_expected[2], 0.0, kEpsilon);
+  EXPECT_NEAR((x[3] - x_expected[3]) / x_expected[3], 0.0, kEpsilon);
+}
+
+// Tests the CUDA Cholesky solver with a simple 4x4 matrix.
+TEST(CUDADenseCholeskyMixedPrecision, Cholesky4x4Matrix4Steps) {
+  Eigen::Matrix4d A;
+  // clang-format off
+  A <<  4,  12, -16, 0,
+       12,  37, -43, 0,
+      -16, -43,  98, 0,
+        0,   0,   0, 1;
+  // clang-format on
+
+  const Eigen::Vector4d b = Eigen::Vector4d::Ones();
+  LinearSolver::Options options;
+  options.max_num_refinement_iterations = 3;
+  ContextImpl context;
+  options.context = &context;
+  std::string error;
+  EXPECT_TRUE(context.InitCuda(&error)) << error;
+  options.dense_linear_algebra_library_type = CUDA;
+  options.use_mixed_precision_solves = true;
+  auto solver = CUDADenseCholeskyMixedPrecision::Create(options);
+  ASSERT_NE(solver, nullptr);
+  std::string error_string;
+  ASSERT_EQ(solver->Factorize(A.cols(), A.data(), &error_string),
+            LinearSolverTerminationType::SUCCESS);
+  Eigen::Vector4d x = Eigen::Vector4d::Zero();
+  ASSERT_EQ(solver->Solve(b.data(), x.data(), &error_string),
+            LinearSolverTerminationType::SUCCESS);
+  // The error does not reduce beyond four iterations, and stagnates at this
+  // level of precision.
+  static const double kEpsilon = std::numeric_limits<double>::epsilon() * 100;
+  const Eigen::Vector4d x_expected(113.75 / 3.0, -31.0 / 3.0, 5.0 / 3.0, 1.0);
+  EXPECT_NEAR((x[0] - x_expected[0]) / x_expected[0], 0.0, kEpsilon);
+  EXPECT_NEAR((x[1] - x_expected[1]) / x_expected[1], 0.0, kEpsilon);
+  EXPECT_NEAR((x[2] - x_expected[2]) / x_expected[2], 0.0, kEpsilon);
+  EXPECT_NEAR((x[3] - x_expected[3]) / x_expected[3], 0.0, kEpsilon);
+}
+
+TEST(CUDADenseCholeskyMixedPrecision, Randomized1600x1600Tests) {
+  const int kNumCols = 1600;
+  using LhsType = Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>;
+  using RhsType = Eigen::Matrix<double, Eigen::Dynamic, 1>;
+  using SolutionType = Eigen::Matrix<double, Eigen::Dynamic, 1>;
+
+  LinearSolver::Options options;
+  ContextImpl context;
+  options.context = &context;
+  std::string error;
+  EXPECT_TRUE(context.InitCuda(&error)) << error;
+  options.dense_linear_algebra_library_type = ceres::CUDA;
+  options.use_mixed_precision_solves = true;
+  options.max_num_refinement_iterations = 20;
+  std::unique_ptr<CUDADenseCholeskyMixedPrecision> dense_cholesky =
+      CUDADenseCholeskyMixedPrecision::Create(options);
+
+  const int kNumTrials = 20;
+  for (int i = 0; i < kNumTrials; ++i) {
+    LhsType lhs = LhsType::Random(kNumCols, kNumCols);
+    lhs = lhs.transpose() * lhs;
+    lhs += 1e-3 * LhsType::Identity(kNumCols, kNumCols);
+    SolutionType x_expected = SolutionType::Random(kNumCols);
+    RhsType rhs = lhs * x_expected;
+    SolutionType x_computed = SolutionType::Zero(kNumCols);
+    // Sanity check the random matrix sizes.
+    EXPECT_EQ(lhs.rows(), kNumCols);
+    EXPECT_EQ(lhs.cols(), kNumCols);
+    EXPECT_EQ(rhs.rows(), kNumCols);
+    EXPECT_EQ(rhs.cols(), 1);
+    EXPECT_EQ(x_expected.rows(), kNumCols);
+    EXPECT_EQ(x_expected.cols(), 1);
+    EXPECT_EQ(x_computed.rows(), kNumCols);
+    EXPECT_EQ(x_computed.cols(), 1);
+    LinearSolver::Summary summary;
+    summary.termination_type = dense_cholesky->FactorAndSolve(
+        kNumCols, lhs.data(), rhs.data(), x_computed.data(), &summary.message);
+    ASSERT_EQ(summary.termination_type, LinearSolverTerminationType::SUCCESS);
+    static const double kEpsilon = std::numeric_limits<double>::epsilon() * 1e6;
+    ASSERT_NEAR(
+        (x_computed - x_expected).norm() / x_expected.norm(), 0.0, kEpsilon);
+  }
+}
+
+#endif  // CERES_NO_CUDA
+
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/cuda_dense_qr_test.cc b/third_party/ceres/internal/ceres/cuda_dense_qr_test.cc
new file mode 100644
index 0000000..b1f25e2
--- /dev/null
+++ b/third_party/ceres/internal/ceres/cuda_dense_qr_test.cc
@@ -0,0 +1,177 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: joydeepb@cs.utexas.edu (Joydeep Biswas)
+
+#include <string>
+
+#include "ceres/dense_qr.h"
+#include "ceres/internal/eigen.h"
+#include "glog/logging.h"
+#include "gtest/gtest.h"
+
+namespace ceres::internal {
+
+#ifndef CERES_NO_CUDA
+
+TEST(CUDADenseQR, InvalidOptionOnCreate) {
+  LinearSolver::Options options;
+  ContextImpl context;
+  options.context = &context;
+  std::string error;
+  EXPECT_TRUE(context.InitCuda(&error)) << error;
+  auto dense_cuda_solver = CUDADenseQR::Create(options);
+  EXPECT_EQ(dense_cuda_solver, nullptr);
+}
+
+// Tests the CUDA QR solver with a simple 4x4 matrix.
+TEST(CUDADenseQR, QR4x4Matrix) {
+  Eigen::Matrix4d A;
+  // clang-format off
+  A <<  4,  12, -16, 0,
+       12,  37, -43, 0,
+      -16, -43,  98, 0,
+        0,   0,   0, 1;
+  // clang-format on
+  const Eigen::Vector4d b = Eigen::Vector4d::Ones();
+  LinearSolver::Options options;
+  ContextImpl context;
+  options.context = &context;
+  std::string error;
+  EXPECT_TRUE(context.InitCuda(&error)) << error;
+  options.dense_linear_algebra_library_type = CUDA;
+  auto dense_cuda_solver = CUDADenseQR::Create(options);
+  ASSERT_NE(dense_cuda_solver, nullptr);
+  std::string error_string;
+  ASSERT_EQ(
+      dense_cuda_solver->Factorize(A.rows(), A.cols(), A.data(), &error_string),
+      LinearSolverTerminationType::SUCCESS);
+  Eigen::Vector4d x = Eigen::Vector4d::Zero();
+  ASSERT_EQ(dense_cuda_solver->Solve(b.data(), x.data(), &error_string),
+            LinearSolverTerminationType::SUCCESS);
+  // Empirically observed accuracy of cuSolverDN's QR solver.
+  const double kEpsilon = std::numeric_limits<double>::epsilon() * 1500;
+  const Eigen::Vector4d x_expected(113.75 / 3.0, -31.0 / 3.0, 5.0 / 3.0, 1.0);
+  EXPECT_NEAR((x - x_expected).norm() / x_expected.norm(), 0.0, kEpsilon);
+}
+
+// Tests the CUDA QR solver with a simple 4x4 matrix.
+TEST(CUDADenseQR, QR4x2Matrix) {
+  Eigen::Matrix<double, 4, 2> A;
+  // clang-format off
+  A <<  4,  12,
+       12,  37,
+      -16, -43,
+        0,   0;
+  // clang-format on
+
+  const std::vector<double> b(4, 1.0);
+  LinearSolver::Options options;
+  ContextImpl context;
+  options.context = &context;
+  std::string error;
+  EXPECT_TRUE(context.InitCuda(&error)) << error;
+  options.dense_linear_algebra_library_type = CUDA;
+  auto dense_cuda_solver = CUDADenseQR::Create(options);
+  ASSERT_NE(dense_cuda_solver, nullptr);
+  std::string error_string;
+  ASSERT_EQ(
+      dense_cuda_solver->Factorize(A.rows(), A.cols(), A.data(), &error_string),
+      LinearSolverTerminationType::SUCCESS);
+  std::vector<double> x(2, 0);
+  ASSERT_EQ(dense_cuda_solver->Solve(b.data(), x.data(), &error_string),
+            LinearSolverTerminationType::SUCCESS);
+  // Empirically observed accuracy of cuSolverDN's QR solver.
+  const double kEpsilon = std::numeric_limits<double>::epsilon() * 10;
+  // Solution values computed with Octave.
+  const Eigen::Vector2d x_expected(-1.143410852713177, 0.4031007751937981);
+  EXPECT_NEAR((x[0] - x_expected[0]) / x_expected[0], 0.0, kEpsilon);
+  EXPECT_NEAR((x[1] - x_expected[1]) / x_expected[1], 0.0, kEpsilon);
+}
+
+TEST(CUDADenseQR, MustFactorizeBeforeSolve) {
+  const Eigen::Vector3d b = Eigen::Vector3d::Ones();
+  LinearSolver::Options options;
+  ContextImpl context;
+  options.context = &context;
+  std::string error;
+  EXPECT_TRUE(context.InitCuda(&error)) << error;
+  options.dense_linear_algebra_library_type = CUDA;
+  auto dense_cuda_solver = CUDADenseQR::Create(options);
+  ASSERT_NE(dense_cuda_solver, nullptr);
+  std::string error_string;
+  ASSERT_EQ(dense_cuda_solver->Solve(b.data(), nullptr, &error_string),
+            LinearSolverTerminationType::FATAL_ERROR);
+}
+
+TEST(CUDADenseQR, Randomized1600x100Tests) {
+  const int kNumRows = 1600;
+  const int kNumCols = 100;
+  using LhsType = Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>;
+  using RhsType = Eigen::Matrix<double, Eigen::Dynamic, 1>;
+  using SolutionType = Eigen::Matrix<double, Eigen::Dynamic, 1>;
+
+  LinearSolver::Options options;
+  ContextImpl context;
+  options.context = &context;
+  std::string error;
+  EXPECT_TRUE(context.InitCuda(&error)) << error;
+  options.dense_linear_algebra_library_type = ceres::CUDA;
+  std::unique_ptr<DenseQR> dense_qr = CUDADenseQR::Create(options);
+
+  const int kNumTrials = 20;
+  for (int i = 0; i < kNumTrials; ++i) {
+    LhsType lhs = LhsType::Random(kNumRows, kNumCols);
+    SolutionType x_expected = SolutionType::Random(kNumCols);
+    RhsType rhs = lhs * x_expected;
+    SolutionType x_computed = SolutionType::Zero(kNumCols);
+    // Sanity check the random matrix sizes.
+    EXPECT_EQ(lhs.rows(), kNumRows);
+    EXPECT_EQ(lhs.cols(), kNumCols);
+    EXPECT_EQ(rhs.rows(), kNumRows);
+    EXPECT_EQ(rhs.cols(), 1);
+    EXPECT_EQ(x_expected.rows(), kNumCols);
+    EXPECT_EQ(x_expected.cols(), 1);
+    EXPECT_EQ(x_computed.rows(), kNumCols);
+    EXPECT_EQ(x_computed.cols(), 1);
+    LinearSolver::Summary summary;
+    summary.termination_type = dense_qr->FactorAndSolve(kNumRows,
+                                                        kNumCols,
+                                                        lhs.data(),
+                                                        rhs.data(),
+                                                        x_computed.data(),
+                                                        &summary.message);
+    ASSERT_EQ(summary.termination_type, LinearSolverTerminationType::SUCCESS);
+    ASSERT_NEAR((x_computed - x_expected).norm() / x_expected.norm(),
+                0.0,
+                std::numeric_limits<double>::epsilon() * 400);
+  }
+}
+#endif  // CERES_NO_CUDA
+
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/cuda_kernels_bsm_to_crs.cu.cc b/third_party/ceres/internal/ceres/cuda_kernels_bsm_to_crs.cu.cc
new file mode 100644
index 0000000..ee574f0
--- /dev/null
+++ b/third_party/ceres/internal/ceres/cuda_kernels_bsm_to_crs.cu.cc
@@ -0,0 +1,477 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Authors: dmitriy.korchemkin@gmail.com (Dmitriy Korchemkin)
+
+#include "ceres/cuda_kernels_bsm_to_crs.h"
+
+#include <cuda_runtime.h>
+#include <thrust/execution_policy.h>
+#include <thrust/scan.h>
+
+#include "ceres/block_structure.h"
+#include "ceres/cuda_kernels_utils.h"
+
+namespace ceres {
+namespace internal {
+
+namespace {
+inline auto ThrustCudaStreamExecutionPolicy(cudaStream_t stream) {
+  // par_nosync execution policy was added in Thrust 1.16
+  // https://github.com/NVIDIA/thrust/blob/main/CHANGELOG.md#thrust-1160
+#if THRUST_VERSION < 101700
+  return thrust::cuda::par.on(stream);
+#else
+  return thrust::cuda::par_nosync.on(stream);
+#endif
+}
+
+void* CudaMalloc(size_t size,
+                 cudaStream_t stream,
+                 bool memory_pools_supported) {
+  void* data = nullptr;
+  // Stream-ordered alloaction API is available since CUDA 11.2, but might be
+  // not implemented by particular device
+#if CUDART_VERSION < 11020
+#warning \
+    "Stream-ordered allocations are unavailable, consider updating CUDA toolkit to version 11.2+"
+  cudaMalloc(&data, size);
+#else
+  if (memory_pools_supported) {
+    cudaMallocAsync(&data, size, stream);
+  } else {
+    cudaMalloc(&data, size);
+  }
+#endif
+  return data;
+}
+
+void CudaFree(void* data, cudaStream_t stream, bool memory_pools_supported) {
+  // Stream-ordered alloaction API is available since CUDA 11.2, but might be
+  // not implemented by particular device
+#if CUDART_VERSION < 11020
+#warning \
+    "Stream-ordered allocations are unavailable, consider updating CUDA toolkit to version 11.2+"
+  cudaSuccess, cudaFree(data);
+#else
+  if (memory_pools_supported) {
+    cudaFreeAsync(data, stream);
+  } else {
+    cudaFree(data);
+  }
+#endif
+}
+template <typename T>
+T* CudaAllocate(size_t num_elements,
+                cudaStream_t stream,
+                bool memory_pools_supported) {
+  T* data = static_cast<T*>(
+      CudaMalloc(num_elements * sizeof(T), stream, memory_pools_supported));
+  return data;
+}
+}  // namespace
+
+// Fill row block id and nnz for each row using block-sparse structure
+// represented by a set of flat arrays.
+// Inputs:
+// - num_row_blocks: number of row-blocks in block-sparse structure
+// - first_cell_in_row_block: index of the first cell of the row-block; size:
+// num_row_blocks + 1
+// - cells: cells of block-sparse structure as a continuous array
+// - row_blocks: row blocks of block-sparse structure stored sequentially
+// - col_blocks: column blocks of block-sparse structure stored sequentially
+// Outputs:
+// - rows: rows[i + 1] will contain number of non-zeros in i-th row, rows[0]
+// will be set to 0; rows are filled with a shift by one element in order
+// to obtain row-index array of CRS matrix with a inclusive scan afterwards
+// - row_block_ids: row_block_ids[i] will be set to index of row-block that
+// contains i-th row.
+// Computation is perform row-block-wise
+template <bool partitioned = false>
+__global__ void RowBlockIdAndNNZ(
+    const int num_row_blocks,
+    const int num_col_blocks_e,
+    const int num_row_blocks_e,
+    const int* __restrict__ first_cell_in_row_block,
+    const Cell* __restrict__ cells,
+    const Block* __restrict__ row_blocks,
+    const Block* __restrict__ col_blocks,
+    int* __restrict__ rows_e,
+    int* __restrict__ rows_f,
+    int* __restrict__ row_block_ids) {
+  const int row_block_id = blockIdx.x * blockDim.x + threadIdx.x;
+  if (row_block_id > num_row_blocks) {
+    // No synchronization is performed in this kernel, thus it is safe to return
+    return;
+  }
+  if (row_block_id == num_row_blocks) {
+    // one extra thread sets the first element
+    rows_f[0] = 0;
+    if constexpr (partitioned) {
+      rows_e[0] = 0;
+    }
+    return;
+  }
+  const auto& row_block = row_blocks[row_block_id];
+  auto first_cell = cells + first_cell_in_row_block[row_block_id];
+  const auto last_cell = cells + first_cell_in_row_block[row_block_id + 1];
+  [[maybe_unused]] int row_nnz_e = 0;
+  if (partitioned && row_block_id < num_row_blocks_e) {
+    // First cell is a cell from E
+    row_nnz_e = col_blocks[first_cell->block_id].size;
+    ++first_cell;
+  }
+  int row_nnz_f = 0;
+  for (auto cell = first_cell; cell < last_cell; ++cell) {
+    row_nnz_f += col_blocks[cell->block_id].size;
+  }
+  const int first_row = row_block.position;
+  const int last_row = first_row + row_block.size;
+  for (int i = first_row; i < last_row; ++i) {
+    if constexpr (partitioned) {
+      rows_e[i + 1] = row_nnz_e;
+    }
+    rows_f[i + 1] = row_nnz_f;
+    row_block_ids[i] = row_block_id;
+  }
+}
+
+// Row-wise creation of CRS structure
+// Inputs:
+// - num_rows: number of rows in matrix
+// - first_cell_in_row_block: index of the first cell of the row-block; size:
+// num_row_blocks + 1
+// - cells: cells of block-sparse structure as a continuous array
+// - row_blocks: row blocks of block-sparse structure stored sequentially
+// - col_blocks: column blocks of block-sparse structure stored sequentially
+// - row_block_ids: index of row-block that corresponds to row
+// - rows: row-index array of CRS structure
+// Outputs:
+// - cols: column-index array of CRS structure
+// Computaion is perform row-wise
+template <bool partitioned>
+__global__ void ComputeColumns(const int num_rows,
+                               const int num_row_blocks_e,
+                               const int num_col_blocks_e,
+                               const int* __restrict__ first_cell_in_row_block,
+                               const Cell* __restrict__ cells,
+                               const Block* __restrict__ row_blocks,
+                               const Block* __restrict__ col_blocks,
+                               const int* __restrict__ row_block_ids,
+                               const int* __restrict__ rows_e,
+                               int* __restrict__ cols_e,
+                               const int* __restrict__ rows_f,
+                               int* __restrict__ cols_f) {
+  const int row = blockIdx.x * blockDim.x + threadIdx.x;
+  if (row >= num_rows) {
+    // No synchronization is performed in this kernel, thus it is safe to return
+    return;
+  }
+  const int row_block_id = row_block_ids[row];
+  // position in crs matrix
+  auto first_cell = cells + first_cell_in_row_block[row_block_id];
+  const auto last_cell = cells + first_cell_in_row_block[row_block_id + 1];
+  const int num_cols_e = col_blocks[num_col_blocks_e].position;
+  // For reach cell of row-block only current row is being filled
+  if (partitioned && row_block_id < num_row_blocks_e) {
+    // The first cell is cell from E
+    const auto& col_block = col_blocks[first_cell->block_id];
+    const int col_block_size = col_block.size;
+    int column_idx = col_block.position;
+    int crs_position_e = rows_e[row];
+    // Column indices for each element of row_in_block row of current cell
+    for (int i = 0; i < col_block_size; ++i, ++crs_position_e) {
+      cols_e[crs_position_e] = column_idx++;
+    }
+    ++first_cell;
+  }
+  int crs_position_f = rows_f[row];
+  for (auto cell = first_cell; cell < last_cell; ++cell) {
+    const auto& col_block = col_blocks[cell->block_id];
+    const int col_block_size = col_block.size;
+    int column_idx = col_block.position - num_cols_e;
+    // Column indices for each element of row_in_block row of current cell
+    for (int i = 0; i < col_block_size; ++i, ++crs_position_f) {
+      cols_f[crs_position_f] = column_idx++;
+    }
+  }
+}
+
+void FillCRSStructure(const int num_row_blocks,
+                      const int num_rows,
+                      const int* first_cell_in_row_block,
+                      const Cell* cells,
+                      const Block* row_blocks,
+                      const Block* col_blocks,
+                      int* rows,
+                      int* cols,
+                      cudaStream_t stream,
+                      bool memory_pools_supported) {
+  // Set number of non-zeros per row in rows array and row to row-block map in
+  // row_block_ids array
+  int* row_block_ids =
+      CudaAllocate<int>(num_rows, stream, memory_pools_supported);
+  const int num_blocks_blockwise = NumBlocksInGrid(num_row_blocks + 1);
+  RowBlockIdAndNNZ<false><<<num_blocks_blockwise, kCudaBlockSize, 0, stream>>>(
+      num_row_blocks,
+      0,
+      0,
+      first_cell_in_row_block,
+      cells,
+      row_blocks,
+      col_blocks,
+      nullptr,
+      rows,
+      row_block_ids);
+  // Finalize row-index array of CRS strucure by computing prefix sum
+  thrust::inclusive_scan(
+      ThrustCudaStreamExecutionPolicy(stream), rows, rows + num_rows + 1, rows);
+
+  // Fill cols array of CRS structure
+  const int num_blocks_rowwise = NumBlocksInGrid(num_rows);
+  ComputeColumns<false><<<num_blocks_rowwise, kCudaBlockSize, 0, stream>>>(
+      num_rows,
+      0,
+      0,
+      first_cell_in_row_block,
+      cells,
+      row_blocks,
+      col_blocks,
+      row_block_ids,
+      nullptr,
+      nullptr,
+      rows,
+      cols);
+  CudaFree(row_block_ids, stream, memory_pools_supported);
+}
+
+void FillCRSStructurePartitioned(const int num_row_blocks,
+                                 const int num_rows,
+                                 const int num_row_blocks_e,
+                                 const int num_col_blocks_e,
+                                 const int num_nonzeros_e,
+                                 const int* first_cell_in_row_block,
+                                 const Cell* cells,
+                                 const Block* row_blocks,
+                                 const Block* col_blocks,
+                                 int* rows_e,
+                                 int* cols_e,
+                                 int* rows_f,
+                                 int* cols_f,
+                                 cudaStream_t stream,
+                                 bool memory_pools_supported) {
+  // Set number of non-zeros per row in rows array and row to row-block map in
+  // row_block_ids array
+  int* row_block_ids =
+      CudaAllocate<int>(num_rows, stream, memory_pools_supported);
+  const int num_blocks_blockwise = NumBlocksInGrid(num_row_blocks + 1);
+  RowBlockIdAndNNZ<true><<<num_blocks_blockwise, kCudaBlockSize, 0, stream>>>(
+      num_row_blocks,
+      num_col_blocks_e,
+      num_row_blocks_e,
+      first_cell_in_row_block,
+      cells,
+      row_blocks,
+      col_blocks,
+      rows_e,
+      rows_f,
+      row_block_ids);
+  // Finalize row-index array of CRS strucure by computing prefix sum
+  thrust::inclusive_scan(ThrustCudaStreamExecutionPolicy(stream),
+                         rows_e,
+                         rows_e + num_rows + 1,
+                         rows_e);
+  thrust::inclusive_scan(ThrustCudaStreamExecutionPolicy(stream),
+                         rows_f,
+                         rows_f + num_rows + 1,
+                         rows_f);
+
+  // Fill cols array of CRS structure
+  const int num_blocks_rowwise = NumBlocksInGrid(num_rows);
+  ComputeColumns<true><<<num_blocks_rowwise, kCudaBlockSize, 0, stream>>>(
+      num_rows,
+      num_row_blocks_e,
+      num_col_blocks_e,
+      first_cell_in_row_block,
+      cells,
+      row_blocks,
+      col_blocks,
+      row_block_ids,
+      rows_e,
+      cols_e,
+      rows_f,
+      cols_f);
+  CudaFree(row_block_ids, stream, memory_pools_supported);
+}
+
+template <typename T, typename Predicate>
+__device__ int PartitionPoint(const T* data,
+                              int first,
+                              int last,
+                              Predicate&& predicate) {
+  if (!predicate(data[first])) {
+    return first;
+  }
+  while (last - first > 1) {
+    const auto midpoint = first + (last - first) / 2;
+    if (predicate(data[midpoint])) {
+      first = midpoint;
+    } else {
+      last = midpoint;
+    }
+  }
+  return last;
+}
+
+// Element-wise reordering of block-sparse values
+// - first_cell_in_row_block - position of the first cell of row-block
+// - block_sparse_values - segment of block-sparse values starting from
+// block_sparse_offset, containing num_values
+template <bool partitioned>
+__global__ void PermuteToCrsKernel(
+    const int block_sparse_offset,
+    const int num_values,
+    const int num_row_blocks,
+    const int num_row_blocks_e,
+    const int* __restrict__ first_cell_in_row_block,
+    const int* __restrict__ value_offset_row_block_f,
+    const Cell* __restrict__ cells,
+    const Block* __restrict__ row_blocks,
+    const Block* __restrict__ col_blocks,
+    const int* __restrict__ crs_rows,
+    const double* __restrict__ block_sparse_values,
+    double* __restrict__ crs_values) {
+  const int value_id = blockIdx.x * blockDim.x + threadIdx.x;
+  if (value_id >= num_values) {
+    return;
+  }
+  const int block_sparse_value_id = value_id + block_sparse_offset;
+  // Find the corresponding row-block with a binary search
+  const int row_block_id =
+      (partitioned
+           ? PartitionPoint(value_offset_row_block_f,
+                            0,
+                            num_row_blocks,
+                            [block_sparse_value_id] __device__(
+                                const int row_block_offset) {
+                              return row_block_offset <= block_sparse_value_id;
+                            })
+           : PartitionPoint(first_cell_in_row_block,
+                            0,
+                            num_row_blocks,
+                            [cells, block_sparse_value_id] __device__(
+                                const int row_block_offset) {
+                              return cells[row_block_offset].position <=
+                                     block_sparse_value_id;
+                            })) -
+      1;
+  // Find cell and calculate offset within the row with a linear scan
+  const auto& row_block = row_blocks[row_block_id];
+  auto first_cell = cells + first_cell_in_row_block[row_block_id];
+  const auto last_cell = cells + first_cell_in_row_block[row_block_id + 1];
+  const int row_block_size = row_block.size;
+  int num_cols_before = 0;
+  if (partitioned && row_block_id < num_row_blocks_e) {
+    ++first_cell;
+  }
+  for (const Cell* cell = first_cell; cell < last_cell; ++cell) {
+    const auto& col_block = col_blocks[cell->block_id];
+    const int col_block_size = col_block.size;
+    const int cell_size = row_block_size * col_block_size;
+    if (cell->position + cell_size > block_sparse_value_id) {
+      const int pos_in_cell = block_sparse_value_id - cell->position;
+      const int row_in_cell = pos_in_cell / col_block_size;
+      const int col_in_cell = pos_in_cell % col_block_size;
+      const int row = row_in_cell + row_block.position;
+      crs_values[crs_rows[row] + num_cols_before + col_in_cell] =
+          block_sparse_values[value_id];
+      break;
+    }
+    num_cols_before += col_block_size;
+  }
+}
+
+void PermuteToCRS(const int block_sparse_offset,
+                  const int num_values,
+                  const int num_row_blocks,
+                  const int* first_cell_in_row_block,
+                  const Cell* cells,
+                  const Block* row_blocks,
+                  const Block* col_blocks,
+                  const int* crs_rows,
+                  const double* block_sparse_values,
+                  double* crs_values,
+                  cudaStream_t stream) {
+  const int num_blocks_valuewise = NumBlocksInGrid(num_values);
+  PermuteToCrsKernel<false>
+      <<<num_blocks_valuewise, kCudaBlockSize, 0, stream>>>(
+          block_sparse_offset,
+          num_values,
+          num_row_blocks,
+          0,
+          first_cell_in_row_block,
+          nullptr,
+          cells,
+          row_blocks,
+          col_blocks,
+          crs_rows,
+          block_sparse_values,
+          crs_values);
+}
+
+void PermuteToCRSPartitionedF(const int block_sparse_offset,
+                              const int num_values,
+                              const int num_row_blocks,
+                              const int num_row_blocks_e,
+                              const int* first_cell_in_row_block,
+                              const int* value_offset_row_block_f,
+                              const Cell* cells,
+                              const Block* row_blocks,
+                              const Block* col_blocks,
+                              const int* crs_rows,
+                              const double* block_sparse_values,
+                              double* crs_values,
+                              cudaStream_t stream) {
+  const int num_blocks_valuewise = NumBlocksInGrid(num_values);
+  PermuteToCrsKernel<true><<<num_blocks_valuewise, kCudaBlockSize, 0, stream>>>(
+      block_sparse_offset,
+      num_values,
+      num_row_blocks,
+      num_row_blocks_e,
+      first_cell_in_row_block,
+      value_offset_row_block_f,
+      cells,
+      row_blocks,
+      col_blocks,
+      crs_rows,
+      block_sparse_values,
+      crs_values);
+}
+
+}  // namespace internal
+}  // namespace ceres
diff --git a/third_party/ceres/internal/ceres/cuda_kernels_bsm_to_crs.h b/third_party/ceres/internal/ceres/cuda_kernels_bsm_to_crs.h
new file mode 100644
index 0000000..27f4a25
--- /dev/null
+++ b/third_party/ceres/internal/ceres/cuda_kernels_bsm_to_crs.h
@@ -0,0 +1,113 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Authors: dmitriy.korchemkin@gmail.com (Dmitriy Korchemkin)
+
+#ifndef CERES_INTERNAL_CUDA_KERNELS_BSM_TO_CRS_H_
+#define CERES_INTERNAL_CUDA_KERNELS_BSM_TO_CRS_H_
+
+#include "ceres/internal/config.h"
+
+#ifndef CERES_NO_CUDA
+
+#include "cuda_runtime.h"
+
+namespace ceres {
+namespace internal {
+struct Block;
+struct Cell;
+
+// Compute structure of CRS matrix using block-sparse structure.
+// Arrays corresponding to CRS matrix are to be allocated by caller
+void FillCRSStructure(const int num_row_blocks,
+                      const int num_rows,
+                      const int* first_cell_in_row_block,
+                      const Cell* cells,
+                      const Block* row_blocks,
+                      const Block* col_blocks,
+                      int* rows,
+                      int* cols,
+                      cudaStream_t stream,
+                      bool memory_pools_supported);
+
+// Compute structure of partitioned CRS matrix using block-sparse structure.
+// Arrays corresponding to CRS matrices are to be allocated by caller
+void FillCRSStructurePartitioned(const int num_row_blocks,
+                                 const int num_rows,
+                                 const int num_row_blocks_e,
+                                 const int num_col_blocks_e,
+                                 const int num_nonzeros_e,
+                                 const int* first_cell_in_row_block,
+                                 const Cell* cells,
+                                 const Block* row_blocks,
+                                 const Block* col_blocks,
+                                 int* rows_e,
+                                 int* cols_e,
+                                 int* rows_f,
+                                 int* cols_f,
+                                 cudaStream_t stream,
+                                 bool memory_pools_supported);
+
+// Permute segment of values from block-sparse matrix with sequential layout to
+// CRS order. Segment starts at block_sparse_offset and has length of num_values
+void PermuteToCRS(const int block_sparse_offset,
+                  const int num_values,
+                  const int num_row_blocks,
+                  const int* first_cell_in_row_block,
+                  const Cell* cells,
+                  const Block* row_blocks,
+                  const Block* col_blocks,
+                  const int* crs_rows,
+                  const double* block_sparse_values,
+                  double* crs_values,
+                  cudaStream_t stream);
+
+// Permute segment of values from F sub-matrix of block-sparse partitioned
+// matrix with sequential layout to CRS order. Segment starts at
+// block_sparse_offset (including the offset induced by values of E submatrix)
+// and has length of num_values
+void PermuteToCRSPartitionedF(const int block_sparse_offset,
+                              const int num_values,
+                              const int num_row_blocks,
+                              const int num_row_blocks_e,
+                              const int* first_cell_in_row_block,
+                              const int* value_offset_row_block_f,
+                              const Cell* cells,
+                              const Block* row_blocks,
+                              const Block* col_blocks,
+                              const int* crs_rows,
+                              const double* block_sparse_values,
+                              double* crs_values,
+                              cudaStream_t stream);
+
+}  // namespace internal
+}  // namespace ceres
+
+#endif  // CERES_NO_CUDA
+
+#endif  // CERES_INTERNAL_CUDA_KERNELS_BSM_TO_CRS_H_
diff --git a/third_party/ceres/internal/ceres/cuda_kernels_utils.h b/third_party/ceres/internal/ceres/cuda_kernels_utils.h
new file mode 100644
index 0000000..4a17bac
--- /dev/null
+++ b/third_party/ceres/internal/ceres/cuda_kernels_utils.h
@@ -0,0 +1,56 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: joydeepb@cs.utexas.edu (Joydeep Biswas)
+
+#ifndef CERES_INTERNAL_CUDA_KERNELS_UTILS_H_
+#define CERES_INTERNAL_CUDA_KERNELS_UTILS_H_
+
+namespace ceres {
+namespace internal {
+
+// Parallel execution on CUDA device requires splitting job into blocks of a
+// fixed size. We use block-size of kCudaBlockSize for all kernels that do not
+// require any specific block size. As the CUDA Toolkit documentation says,
+// "although arbitrary in this case, is a common choice". This is determined by
+// the warp size, max block size, and multiprocessor sizes of recent GPUs. For
+// complex kernels with significant register usage and unusual memory patterns,
+// the occupancy calculator API might provide better performance. See "Occupancy
+// Calculator" under the CUDA toolkit documentation.
+constexpr int kCudaBlockSize = 256;
+
+// Compute number of blocks of kCudaBlockSize that span over 1-d grid with
+// dimension size. Note that 1-d grid dimension is limited by 2^31-1 in CUDA,
+// thus a signed int is used as an argument.
+inline int NumBlocksInGrid(int size) {
+  return (size + kCudaBlockSize - 1) / kCudaBlockSize;
+}
+}  // namespace internal
+}  // namespace ceres
+
+#endif  // CERES_INTERNAL_CUDA_KERNELS_UTILS_H_
diff --git a/third_party/ceres/internal/ceres/cuda_kernels_vector_ops.cu.cc b/third_party/ceres/internal/ceres/cuda_kernels_vector_ops.cu.cc
new file mode 100644
index 0000000..3199ca6
--- /dev/null
+++ b/third_party/ceres/internal/ceres/cuda_kernels_vector_ops.cu.cc
@@ -0,0 +1,123 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: joydeepb@cs.utexas.edu (Joydeep Biswas)
+
+#include "ceres/cuda_kernels_vector_ops.h"
+
+#include <cuda_runtime.h>
+
+#include "ceres/cuda_kernels_utils.h"
+
+namespace ceres {
+namespace internal {
+
+template <typename SrcType, typename DstType>
+__global__ void TypeConversionKernel(const SrcType* __restrict__ input,
+                                     DstType* __restrict__ output,
+                                     const int size) {
+  const int i = blockIdx.x * blockDim.x + threadIdx.x;
+  if (i < size) {
+    output[i] = static_cast<DstType>(input[i]);
+  }
+}
+
+void CudaFP64ToFP32(const double* input,
+                    float* output,
+                    const int size,
+                    cudaStream_t stream) {
+  const int num_blocks = NumBlocksInGrid(size);
+  TypeConversionKernel<double, float>
+      <<<num_blocks, kCudaBlockSize, 0, stream>>>(input, output, size);
+}
+
+void CudaFP32ToFP64(const float* input,
+                    double* output,
+                    const int size,
+                    cudaStream_t stream) {
+  const int num_blocks = NumBlocksInGrid(size);
+  TypeConversionKernel<float, double>
+      <<<num_blocks, kCudaBlockSize, 0, stream>>>(input, output, size);
+}
+
+template <typename T>
+__global__ void SetZeroKernel(T* __restrict__ output, const int size) {
+  const int i = blockIdx.x * blockDim.x + threadIdx.x;
+  if (i < size) {
+    output[i] = T(0.0);
+  }
+}
+
+void CudaSetZeroFP32(float* output, const int size, cudaStream_t stream) {
+  const int num_blocks = NumBlocksInGrid(size);
+  SetZeroKernel<float><<<num_blocks, kCudaBlockSize, 0, stream>>>(output, size);
+}
+
+void CudaSetZeroFP64(double* output, const int size, cudaStream_t stream) {
+  const int num_blocks = NumBlocksInGrid(size);
+  SetZeroKernel<double>
+      <<<num_blocks, kCudaBlockSize, 0, stream>>>(output, size);
+}
+
+template <typename SrcType, typename DstType>
+__global__ void XPlusEqualsYKernel(DstType* __restrict__ x,
+                                   const SrcType* __restrict__ y,
+                                   const int size) {
+  const int i = blockIdx.x * blockDim.x + threadIdx.x;
+  if (i < size) {
+    x[i] = x[i] + DstType(y[i]);
+  }
+}
+
+void CudaDsxpy(double* x, float* y, const int size, cudaStream_t stream) {
+  const int num_blocks = NumBlocksInGrid(size);
+  XPlusEqualsYKernel<float, double>
+      <<<num_blocks, kCudaBlockSize, 0, stream>>>(x, y, size);
+}
+
+__global__ void CudaDtDxpyKernel(double* __restrict__ y,
+                                 const double* D,
+                                 const double* __restrict__ x,
+                                 const int size) {
+  const int i = blockIdx.x * blockDim.x + threadIdx.x;
+  if (i < size) {
+    y[i] = y[i] + D[i] * D[i] * x[i];
+  }
+}
+
+void CudaDtDxpy(double* y,
+                const double* D,
+                const double* x,
+                const int size,
+                cudaStream_t stream) {
+  const int num_blocks = NumBlocksInGrid(size);
+  CudaDtDxpyKernel<<<num_blocks, kCudaBlockSize, 0, stream>>>(y, D, x, size);
+}
+
+}  // namespace internal
+}  // namespace ceres
diff --git a/third_party/ceres/internal/ceres/cuda_kernels_vector_ops.h b/third_party/ceres/internal/ceres/cuda_kernels_vector_ops.h
new file mode 100644
index 0000000..9905657
--- /dev/null
+++ b/third_party/ceres/internal/ceres/cuda_kernels_vector_ops.h
@@ -0,0 +1,83 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: joydeepb@cs.utexas.edu (Joydeep Biswas)
+
+#ifndef CERES_INTERNAL_CUDA_KERNELS_VECTOR_OPS_H_
+#define CERES_INTERNAL_CUDA_KERNELS_VECTOR_OPS_H_
+
+#include "ceres/internal/config.h"
+
+#ifndef CERES_NO_CUDA
+
+#include "cuda_runtime.h"
+
+namespace ceres {
+namespace internal {
+class Block;
+class Cell;
+
+// Convert an array of double (FP64) values to float (FP32). Both arrays must
+// already be on GPU memory.
+void CudaFP64ToFP32(const double* input,
+                    float* output,
+                    const int size,
+                    cudaStream_t stream);
+
+// Convert an array of float (FP32) values to double (FP64). Both arrays must
+// already be on GPU memory.
+void CudaFP32ToFP64(const float* input,
+                    double* output,
+                    const int size,
+                    cudaStream_t stream);
+
+// Set all elements of the array to the FP32 value 0. The array must be in GPU
+// memory.
+void CudaSetZeroFP32(float* output, const int size, cudaStream_t stream);
+
+// Set all elements of the array to the FP64 value 0. The array must be in GPU
+// memory.
+void CudaSetZeroFP64(double* output, const int size, cudaStream_t stream);
+
+// Compute x = x + double(y). Input array is float (FP32), output array is
+// double (FP64). Both arrays must already be on GPU memory.
+void CudaDsxpy(double* x, float* y, const int size, cudaStream_t stream);
+
+// Compute y[i] = y[i] + d[i]^2 x[i]. All arrays must already be on GPU memory.
+void CudaDtDxpy(double* y,
+                const double* D,
+                const double* x,
+                const int size,
+                cudaStream_t stream);
+
+}  // namespace internal
+}  // namespace ceres
+
+#endif  // CERES_NO_CUDA
+
+#endif  // CERES_INTERNAL_CUDA_KERNELS_VECTOR_OPS_H_
diff --git a/third_party/ceres/internal/ceres/cuda_kernels_vector_ops_test.cc b/third_party/ceres/internal/ceres/cuda_kernels_vector_ops_test.cc
new file mode 100644
index 0000000..e6116f7
--- /dev/null
+++ b/third_party/ceres/internal/ceres/cuda_kernels_vector_ops_test.cc
@@ -0,0 +1,198 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: joydeepb@cs.utexas.edu (Joydeep Biswas)
+
+#include "ceres/cuda_kernels_vector_ops.h"
+
+#include <math.h>
+
+#include <limits>
+#include <string>
+#include <vector>
+
+#include "ceres/context_impl.h"
+#include "ceres/cuda_buffer.h"
+#include "ceres/internal/config.h"
+#include "ceres/internal/eigen.h"
+#include "glog/logging.h"
+#include "gtest/gtest.h"
+
+namespace ceres {
+namespace internal {
+
+#ifndef CERES_NO_CUDA
+
+TEST(CudaFP64ToFP32, SimpleConversions) {
+  ContextImpl context;
+  std::string cuda_error;
+  EXPECT_TRUE(context.InitCuda(&cuda_error)) << cuda_error;
+  std::vector<double> fp64_cpu = {1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0};
+  CudaBuffer<double> fp64_gpu(&context);
+  fp64_gpu.CopyFromCpuVector(fp64_cpu);
+  CudaBuffer<float> fp32_gpu(&context);
+  fp32_gpu.Reserve(fp64_cpu.size());
+  CudaFP64ToFP32(fp64_gpu.data(),
+                 fp32_gpu.data(),
+                 fp64_cpu.size(),
+                 context.DefaultStream());
+  std::vector<float> fp32_cpu(fp64_cpu.size());
+  fp32_gpu.CopyToCpu(fp32_cpu.data(), fp32_cpu.size());
+  for (int i = 0; i < fp32_cpu.size(); ++i) {
+    EXPECT_EQ(fp32_cpu[i], static_cast<float>(fp64_cpu[i]));
+  }
+}
+
+TEST(CudaFP64ToFP32, NumericallyExtremeValues) {
+  ContextImpl context;
+  std::string cuda_error;
+  EXPECT_TRUE(context.InitCuda(&cuda_error)) << cuda_error;
+  std::vector<double> fp64_cpu = {
+      DBL_MIN, 10.0 * DBL_MIN, DBL_MAX, 0.1 * DBL_MAX};
+  // First just make sure that the compiler has represented these values
+  // accurately as fp64.
+  EXPECT_GT(fp64_cpu[0], 0.0);
+  EXPECT_GT(fp64_cpu[1], 0.0);
+  EXPECT_TRUE(std::isfinite(fp64_cpu[2]));
+  EXPECT_TRUE(std::isfinite(fp64_cpu[3]));
+  CudaBuffer<double> fp64_gpu(&context);
+  fp64_gpu.CopyFromCpuVector(fp64_cpu);
+  CudaBuffer<float> fp32_gpu(&context);
+  fp32_gpu.Reserve(fp64_cpu.size());
+  CudaFP64ToFP32(fp64_gpu.data(),
+                 fp32_gpu.data(),
+                 fp64_cpu.size(),
+                 context.DefaultStream());
+  std::vector<float> fp32_cpu(fp64_cpu.size());
+  fp32_gpu.CopyToCpu(fp32_cpu.data(), fp32_cpu.size());
+  EXPECT_EQ(fp32_cpu[0], 0.0f);
+  EXPECT_EQ(fp32_cpu[1], 0.0f);
+  EXPECT_EQ(fp32_cpu[2], std::numeric_limits<float>::infinity());
+  EXPECT_EQ(fp32_cpu[3], std::numeric_limits<float>::infinity());
+}
+
+TEST(CudaFP32ToFP64, SimpleConversions) {
+  ContextImpl context;
+  std::string cuda_error;
+  EXPECT_TRUE(context.InitCuda(&cuda_error)) << cuda_error;
+  std::vector<float> fp32_cpu = {1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0};
+  CudaBuffer<float> fp32_gpu(&context);
+  fp32_gpu.CopyFromCpuVector(fp32_cpu);
+  CudaBuffer<double> fp64_gpu(&context);
+  fp64_gpu.Reserve(fp32_cpu.size());
+  CudaFP32ToFP64(fp32_gpu.data(),
+                 fp64_gpu.data(),
+                 fp32_cpu.size(),
+                 context.DefaultStream());
+  std::vector<double> fp64_cpu(fp32_cpu.size());
+  fp64_gpu.CopyToCpu(fp64_cpu.data(), fp64_cpu.size());
+  for (int i = 0; i < fp64_cpu.size(); ++i) {
+    EXPECT_EQ(fp64_cpu[i], static_cast<double>(fp32_cpu[i]));
+  }
+}
+
+TEST(CudaSetZeroFP32, NonZeroInput) {
+  ContextImpl context;
+  std::string cuda_error;
+  EXPECT_TRUE(context.InitCuda(&cuda_error)) << cuda_error;
+  std::vector<float> fp32_cpu = {1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0};
+  CudaBuffer<float> fp32_gpu(&context);
+  fp32_gpu.CopyFromCpuVector(fp32_cpu);
+  CudaSetZeroFP32(fp32_gpu.data(), fp32_cpu.size(), context.DefaultStream());
+  std::vector<float> fp32_cpu_zero(fp32_cpu.size());
+  fp32_gpu.CopyToCpu(fp32_cpu_zero.data(), fp32_cpu_zero.size());
+  for (int i = 0; i < fp32_cpu_zero.size(); ++i) {
+    EXPECT_EQ(fp32_cpu_zero[i], 0.0f);
+  }
+}
+
+TEST(CudaSetZeroFP64, NonZeroInput) {
+  ContextImpl context;
+  std::string cuda_error;
+  EXPECT_TRUE(context.InitCuda(&cuda_error)) << cuda_error;
+  std::vector<double> fp64_cpu = {1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0};
+  CudaBuffer<double> fp64_gpu(&context);
+  fp64_gpu.CopyFromCpuVector(fp64_cpu);
+  CudaSetZeroFP64(fp64_gpu.data(), fp64_cpu.size(), context.DefaultStream());
+  std::vector<double> fp64_cpu_zero(fp64_cpu.size());
+  fp64_gpu.CopyToCpu(fp64_cpu_zero.data(), fp64_cpu_zero.size());
+  for (int i = 0; i < fp64_cpu_zero.size(); ++i) {
+    EXPECT_EQ(fp64_cpu_zero[i], 0.0);
+  }
+}
+
+TEST(CudaDsxpy, DoubleValues) {
+  ContextImpl context;
+  std::string cuda_error;
+  EXPECT_TRUE(context.InitCuda(&cuda_error)) << cuda_error;
+  std::vector<float> fp32_cpu_a = {1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0};
+  std::vector<double> fp64_cpu_b = {
+      1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0};
+  CudaBuffer<float> fp32_gpu_a(&context);
+  fp32_gpu_a.CopyFromCpuVector(fp32_cpu_a);
+  CudaBuffer<double> fp64_gpu_b(&context);
+  fp64_gpu_b.CopyFromCpuVector(fp64_cpu_b);
+  CudaDsxpy(fp64_gpu_b.data(),
+            fp32_gpu_a.data(),
+            fp32_gpu_a.size(),
+            context.DefaultStream());
+  fp64_gpu_b.CopyToCpu(fp64_cpu_b.data(), fp64_cpu_b.size());
+  for (int i = 0; i < fp64_cpu_b.size(); ++i) {
+    EXPECT_DOUBLE_EQ(fp64_cpu_b[i], 2.0 * fp32_cpu_a[i]);
+  }
+}
+
+TEST(CudaDtDxpy, ComputeFourItems) {
+  ContextImpl context;
+  std::string cuda_error;
+  EXPECT_TRUE(context.InitCuda(&cuda_error)) << cuda_error;
+  std::vector<double> x_cpu = {1, 2, 3, 4};
+  std::vector<double> y_cpu = {4, 3, 2, 1};
+  std::vector<double> d_cpu = {10, 20, 30, 40};
+  CudaBuffer<double> x_gpu(&context);
+  x_gpu.CopyFromCpuVector(x_cpu);
+  CudaBuffer<double> y_gpu(&context);
+  y_gpu.CopyFromCpuVector(y_cpu);
+  CudaBuffer<double> d_gpu(&context);
+  d_gpu.CopyFromCpuVector(d_cpu);
+  CudaDtDxpy(y_gpu.data(),
+             d_gpu.data(),
+             x_gpu.data(),
+             y_gpu.size(),
+             context.DefaultStream());
+  y_gpu.CopyToCpu(y_cpu.data(), y_cpu.size());
+  EXPECT_DOUBLE_EQ(y_cpu[0], 4.0 + 10.0 * 10.0 * 1.0);
+  EXPECT_DOUBLE_EQ(y_cpu[1], 3.0 + 20.0 * 20.0 * 2.0);
+  EXPECT_DOUBLE_EQ(y_cpu[2], 2.0 + 30.0 * 30.0 * 3.0);
+  EXPECT_DOUBLE_EQ(y_cpu[3], 1.0 + 40.0 * 40.0 * 4.0);
+}
+
+#endif  // CERES_NO_CUDA
+
+}  // namespace internal
+}  // namespace ceres
diff --git a/third_party/ceres/internal/ceres/cuda_partitioned_block_sparse_crs_view.cc b/third_party/ceres/internal/ceres/cuda_partitioned_block_sparse_crs_view.cc
new file mode 100644
index 0000000..c0c1dc8
--- /dev/null
+++ b/third_party/ceres/internal/ceres/cuda_partitioned_block_sparse_crs_view.cc
@@ -0,0 +1,152 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Authors: dmitriy.korchemkin@gmail.com (Dmitriy Korchemkin)
+
+#include "ceres/cuda_partitioned_block_sparse_crs_view.h"
+
+#ifndef CERES_NO_CUDA
+
+#include "ceres/cuda_block_structure.h"
+#include "ceres/cuda_kernels_bsm_to_crs.h"
+
+namespace ceres::internal {
+
+CudaPartitionedBlockSparseCRSView::CudaPartitionedBlockSparseCRSView(
+    const BlockSparseMatrix& bsm,
+    const int num_col_blocks_e,
+    ContextImpl* context)
+    :
+
+      context_(context) {
+  const auto& bs = *bsm.block_structure();
+  block_structure_ =
+      std::make_unique<CudaBlockSparseStructure>(bs, num_col_blocks_e, context);
+  // Determine number of non-zeros in left submatrix
+  // Row-blocks are at least 1 row high, thus we can use a temporary array of
+  // num_rows for ComputeNonZerosInColumnBlockSubMatrix; and later reuse it for
+  // FillCRSStructurePartitioned
+  const int num_rows = bsm.num_rows();
+  const int num_nonzeros_e = block_structure_->num_nonzeros_e();
+  const int num_nonzeros_f = bsm.num_nonzeros() - num_nonzeros_e;
+
+  const int num_cols_e = num_col_blocks_e < bs.cols.size()
+                             ? bs.cols[num_col_blocks_e].position
+                             : bsm.num_cols();
+  const int num_cols_f = bsm.num_cols() - num_cols_e;
+
+  CudaBuffer<int32_t> rows_e(context, num_rows + 1);
+  CudaBuffer<int32_t> cols_e(context, num_nonzeros_e);
+  CudaBuffer<int32_t> rows_f(context, num_rows + 1);
+  CudaBuffer<int32_t> cols_f(context, num_nonzeros_f);
+
+  num_row_blocks_e_ = block_structure_->num_row_blocks_e();
+  FillCRSStructurePartitioned(block_structure_->num_row_blocks(),
+                              num_rows,
+                              num_row_blocks_e_,
+                              num_col_blocks_e,
+                              num_nonzeros_e,
+                              block_structure_->first_cell_in_row_block(),
+                              block_structure_->cells(),
+                              block_structure_->row_blocks(),
+                              block_structure_->col_blocks(),
+                              rows_e.data(),
+                              cols_e.data(),
+                              rows_f.data(),
+                              cols_f.data(),
+                              context->DefaultStream(),
+                              context->is_cuda_memory_pools_supported_);
+  f_is_crs_compatible_ = block_structure_->IsCrsCompatible();
+  if (f_is_crs_compatible_) {
+    block_structure_ = nullptr;
+  } else {
+    streamed_buffer_ = std::make_unique<CudaStreamedBuffer<double>>(
+        context, kMaxTemporaryArraySize);
+  }
+  matrix_e_ = std::make_unique<CudaSparseMatrix>(
+      num_cols_e, std::move(rows_e), std::move(cols_e), context);
+  matrix_f_ = std::make_unique<CudaSparseMatrix>(
+      num_cols_f, std::move(rows_f), std::move(cols_f), context);
+
+  CHECK_EQ(bsm.num_nonzeros(),
+           matrix_e_->num_nonzeros() + matrix_f_->num_nonzeros());
+
+  UpdateValues(bsm);
+}
+
+void CudaPartitionedBlockSparseCRSView::UpdateValues(
+    const BlockSparseMatrix& bsm) {
+  if (f_is_crs_compatible_) {
+    CHECK_EQ(cudaSuccess,
+             cudaMemcpyAsync(matrix_e_->mutable_values(),
+                             bsm.values(),
+                             matrix_e_->num_nonzeros() * sizeof(double),
+                             cudaMemcpyHostToDevice,
+                             context_->DefaultStream()));
+
+    CHECK_EQ(cudaSuccess,
+             cudaMemcpyAsync(matrix_f_->mutable_values(),
+                             bsm.values() + matrix_e_->num_nonzeros(),
+                             matrix_f_->num_nonzeros() * sizeof(double),
+                             cudaMemcpyHostToDevice,
+                             context_->DefaultStream()));
+    return;
+  }
+  streamed_buffer_->CopyToGpu(
+      bsm.values(),
+      bsm.num_nonzeros(),
+      [block_structure = block_structure_.get(),
+       num_nonzeros_e = matrix_e_->num_nonzeros(),
+       num_row_blocks_e = num_row_blocks_e_,
+       values_f = matrix_f_->mutable_values(),
+       rows_f = matrix_f_->rows()](
+          const double* values, int num_values, int offset, auto stream) {
+        PermuteToCRSPartitionedF(num_nonzeros_e + offset,
+                                 num_values,
+                                 block_structure->num_row_blocks(),
+                                 num_row_blocks_e,
+                                 block_structure->first_cell_in_row_block(),
+                                 block_structure->value_offset_row_block_f(),
+                                 block_structure->cells(),
+                                 block_structure->row_blocks(),
+                                 block_structure->col_blocks(),
+                                 rows_f,
+                                 values,
+                                 values_f,
+                                 stream);
+      });
+  CHECK_EQ(cudaSuccess,
+           cudaMemcpyAsync(matrix_e_->mutable_values(),
+                           bsm.values(),
+                           matrix_e_->num_nonzeros() * sizeof(double),
+                           cudaMemcpyHostToDevice,
+                           context_->DefaultStream()));
+}
+
+}  // namespace ceres::internal
+#endif  // CERES_NO_CUDA
diff --git a/third_party/ceres/internal/ceres/cuda_partitioned_block_sparse_crs_view.h b/third_party/ceres/internal/ceres/cuda_partitioned_block_sparse_crs_view.h
new file mode 100644
index 0000000..3072dea
--- /dev/null
+++ b/third_party/ceres/internal/ceres/cuda_partitioned_block_sparse_crs_view.h
@@ -0,0 +1,111 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Authors: dmitriy.korchemkin@gmail.com (Dmitriy Korchemkin)
+//
+
+#ifndef CERES_INTERNAL_CUDA_PARTITIONED_BLOCK_SPARSE_CRS_VIEW_H_
+#define CERES_INTERNAL_CUDA_PARTITIONED_BLOCK_SPARSE_CRS_VIEW_H_
+
+#include "ceres/internal/config.h"
+
+#ifndef CERES_NO_CUDA
+
+#include <memory>
+
+#include "ceres/block_sparse_matrix.h"
+#include "ceres/cuda_block_structure.h"
+#include "ceres/cuda_buffer.h"
+#include "ceres/cuda_sparse_matrix.h"
+#include "ceres/cuda_streamed_buffer.h"
+
+namespace ceres::internal {
+// We use cuSPARSE library for SpMV operations. However, it does not support
+// neither block-sparse format with varying size of the blocks nor
+// submatrix-vector products. Thus, we perform the following operations in order
+// to compute products of partitioned block-sparse matrices and dense vectors on
+// gpu:
+//  - Once per block-sparse structure update:
+//    - Compute CRS structures of left and right submatrices from block-sparse
+//    structure
+//    - Check if values of F sub-matrix can be copied without permutation
+//    matrices
+//  - Once per block-sparse values update:
+//    - Copy values of E sub-matrix
+//    - Permute or copy values of F sub-matrix
+//
+// It is assumed that cells of block-sparse matrix are laid out sequentially in
+// both of sub-matrices and there is exactly one cell in row-block of E
+// sub-matrix in the first num_row_blocks_e_ row blocks, and no cells in E
+// sub-matrix below num_row_blocks_e_ row blocks.
+//
+// This class avoids storing both CRS and block-sparse values in GPU memory.
+// Instead, block-sparse values are transferred to gpu memory as a disjoint set
+// of small continuous segments with simultaneous permutation of the values into
+// correct order using block-structure.
+class CERES_NO_EXPORT CudaPartitionedBlockSparseCRSView {
+ public:
+  // Initializes internal CRS matrix and block-sparse structure on GPU side
+  // values. The following objects are stored in gpu memory for the whole
+  // lifetime of the object
+  //  - matrix_e_: left CRS submatrix
+  //  - matrix_f_: right CRS submatrix
+  //  - block_structure_: copy of block-sparse structure on GPU
+  //  - streamed_buffer_: helper for value updating
+  CudaPartitionedBlockSparseCRSView(const BlockSparseMatrix& bsm,
+                                    const int num_col_blocks_e,
+                                    ContextImpl* context);
+
+  // Update values of CRS submatrices using values of block-sparse matrix.
+  // Assumes that bsm has the same block-sparse structure as matrix that was
+  // used for construction.
+  void UpdateValues(const BlockSparseMatrix& bsm);
+
+  const CudaSparseMatrix* matrix_e() const { return matrix_e_.get(); }
+  const CudaSparseMatrix* matrix_f() const { return matrix_f_.get(); }
+  CudaSparseMatrix* mutable_matrix_e() { return matrix_e_.get(); }
+  CudaSparseMatrix* mutable_matrix_f() { return matrix_f_.get(); }
+
+ private:
+  // Value permutation kernel performs a single element-wise operation per
+  // thread, thus performing permutation in blocks of 8 megabytes of
+  // block-sparse  values seems reasonable
+  static constexpr int kMaxTemporaryArraySize = 1 * 1024 * 1024;
+  std::unique_ptr<CudaSparseMatrix> matrix_e_;
+  std::unique_ptr<CudaSparseMatrix> matrix_f_;
+  std::unique_ptr<CudaStreamedBuffer<double>> streamed_buffer_;
+  std::unique_ptr<CudaBlockSparseStructure> block_structure_;
+  bool f_is_crs_compatible_;
+  int num_row_blocks_e_;
+  ContextImpl* context_;
+};
+
+}  // namespace ceres::internal
+
+#endif  // CERES_NO_CUDA
+#endif  // CERES_INTERNAL_CUDA_PARTITIONED_BLOCK_SPARSE_CRS_VIEW_H_
diff --git a/third_party/ceres/internal/ceres/cuda_partitioned_block_sparse_crs_view_test.cc b/third_party/ceres/internal/ceres/cuda_partitioned_block_sparse_crs_view_test.cc
new file mode 100644
index 0000000..ddfdeef
--- /dev/null
+++ b/third_party/ceres/internal/ceres/cuda_partitioned_block_sparse_crs_view_test.cc
@@ -0,0 +1,279 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Authors: dmitriy.korchemkin@gmail.com (Dmitriy Korchemkin)
+
+#include "ceres/cuda_partitioned_block_sparse_crs_view.h"
+
+#include <glog/logging.h>
+#include <gtest/gtest.h>
+
+#ifndef CERES_NO_CUDA
+
+namespace ceres::internal {
+
+namespace {
+struct RandomPartitionedMatrixOptions {
+  int num_row_blocks_e;
+  int num_row_blocks_f;
+  int num_col_blocks_e;
+  int num_col_blocks_f;
+  int min_row_block_size;
+  int max_row_block_size;
+  int min_col_block_size;
+  int max_col_block_size;
+  double empty_f_probability;
+  double cell_probability_f;
+  int max_cells_f;
+};
+
+std::unique_ptr<BlockSparseMatrix> CreateRandomPartitionedMatrix(
+    const RandomPartitionedMatrixOptions& options, std::mt19937& rng) {
+  const int num_row_blocks =
+      std::max(options.num_row_blocks_e, options.num_row_blocks_f);
+  const int num_col_blocks =
+      options.num_col_blocks_e + options.num_col_blocks_f;
+
+  CompressedRowBlockStructure* block_structure =
+      new CompressedRowBlockStructure;
+  block_structure->cols.reserve(num_col_blocks);
+  block_structure->rows.reserve(num_row_blocks);
+
+  // Create column blocks
+  std::uniform_int_distribution<int> col_size(options.min_col_block_size,
+                                              options.max_col_block_size);
+  int num_cols = 0;
+  for (int i = 0; i < num_col_blocks; ++i) {
+    const int size = col_size(rng);
+    block_structure->cols.emplace_back(size, num_cols);
+    num_cols += size;
+  }
+
+  // Prepare column-block indices of E cells
+  std::vector<int> e_col_block_idx;
+  e_col_block_idx.reserve(options.num_row_blocks_e);
+  std::uniform_int_distribution<int> col_e(0, options.num_col_blocks_e - 1);
+  for (int i = 0; i < options.num_row_blocks_e; ++i) {
+    e_col_block_idx.emplace_back(col_e(rng));
+  }
+  std::sort(e_col_block_idx.begin(), e_col_block_idx.end());
+
+  // Prepare cell structure
+  std::uniform_int_distribution<int> row_size(options.min_row_block_size,
+                                              options.max_row_block_size);
+  std::uniform_real_distribution<double> uniform;
+  int num_rows = 0;
+  for (int i = 0; i < num_row_blocks; ++i) {
+    const int size = row_size(rng);
+    block_structure->rows.emplace_back();
+    auto& row = block_structure->rows.back();
+    row.block.size = size;
+    row.block.position = num_rows;
+    num_rows += size;
+    if (i < options.num_row_blocks_e) {
+      row.cells.emplace_back(e_col_block_idx[i], -1);
+      if (uniform(rng) < options.empty_f_probability) {
+        continue;
+      }
+    }
+    if (i >= options.num_row_blocks_f) continue;
+    const int cells_before = row.cells.size();
+    for (int j = options.num_col_blocks_e; j < num_col_blocks; ++j) {
+      if (uniform(rng) > options.cell_probability_f) {
+        continue;
+      }
+      row.cells.emplace_back(j, -1);
+    }
+    if (row.cells.size() > cells_before + options.max_cells_f) {
+      std::shuffle(row.cells.begin() + cells_before, row.cells.end(), rng);
+      row.cells.resize(cells_before + options.max_cells_f);
+      std::sort(
+          row.cells.begin(), row.cells.end(), [](const auto& a, const auto& b) {
+            return a.block_id < b.block_id;
+          });
+    }
+  }
+
+  // Fill positions in E sub-matrix
+  int num_nonzeros = 0;
+  for (int i = 0; i < options.num_row_blocks_e; ++i) {
+    CHECK_GE(block_structure->rows[i].cells.size(), 1);
+    block_structure->rows[i].cells[0].position = num_nonzeros;
+    const int col_block_size =
+        block_structure->cols[block_structure->rows[i].cells[0].block_id].size;
+    const int row_block_size = block_structure->rows[i].block.size;
+    num_nonzeros += row_block_size * col_block_size;
+    CHECK_GE(num_nonzeros, 0);
+  }
+  // Fill positions in F sub-matrix
+  for (int i = 0; i < options.num_row_blocks_f; ++i) {
+    const int row_block_size = block_structure->rows[i].block.size;
+    for (auto& cell : block_structure->rows[i].cells) {
+      if (cell.position >= 0) continue;
+      cell.position = num_nonzeros;
+      const int col_block_size = block_structure->cols[cell.block_id].size;
+      num_nonzeros += row_block_size * col_block_size;
+      CHECK_GE(num_nonzeros, 0);
+    }
+  }
+  // Populate values
+  auto bsm = std::make_unique<BlockSparseMatrix>(block_structure, true);
+  for (int i = 0; i < num_nonzeros; ++i) {
+    bsm->mutable_values()[i] = i + 1;
+  }
+  return bsm;
+}
+}  // namespace
+
+class CudaPartitionedBlockSparseCRSViewTest : public ::testing::Test {
+  static constexpr int kNumColBlocksE = 456;
+
+ protected:
+  void SetUp() final {
+    std::string message;
+    CHECK(context_.InitCuda(&message))
+        << "InitCuda() failed because: " << message;
+
+    RandomPartitionedMatrixOptions options;
+    options.num_row_blocks_f = 123;
+    options.num_row_blocks_e = 456;
+    options.num_col_blocks_f = 123;
+    options.num_col_blocks_e = kNumColBlocksE;
+    options.min_row_block_size = 1;
+    options.max_row_block_size = 4;
+    options.min_col_block_size = 1;
+    options.max_col_block_size = 4;
+    options.empty_f_probability = .1;
+    options.cell_probability_f = .2;
+    options.max_cells_f = options.num_col_blocks_f;
+
+    std::mt19937 rng;
+    short_f_ = CreateRandomPartitionedMatrix(options, rng);
+
+    options.num_row_blocks_e = 123;
+    options.num_row_blocks_f = 456;
+    short_e_ = CreateRandomPartitionedMatrix(options, rng);
+
+    options.max_cells_f = 1;
+    options.num_row_blocks_e = options.num_row_blocks_f;
+    options.num_row_blocks_e = options.num_row_blocks_f;
+    f_crs_compatible_ = CreateRandomPartitionedMatrix(options, rng);
+  }
+
+  void TestMatrix(const BlockSparseMatrix& A_) {
+    const int num_col_blocks_e = 456;
+    CudaPartitionedBlockSparseCRSView view(A_, kNumColBlocksE, &context_);
+
+    const int num_rows = A_.num_rows();
+    const int num_cols = A_.num_cols();
+
+    const auto& bs = *A_.block_structure();
+    const int num_cols_e = bs.cols[num_col_blocks_e].position;
+    const int num_cols_f = num_cols - num_cols_e;
+
+    auto matrix_e = view.matrix_e();
+    auto matrix_f = view.matrix_f();
+    ASSERT_EQ(matrix_e->num_cols(), num_cols_e);
+    ASSERT_EQ(matrix_e->num_rows(), num_rows);
+    ASSERT_EQ(matrix_f->num_cols(), num_cols_f);
+    ASSERT_EQ(matrix_f->num_rows(), num_rows);
+
+    Vector x(num_cols);
+    Vector x_left(num_cols_e);
+    Vector x_right(num_cols_f);
+    Vector y(num_rows);
+    CudaVector x_cuda(&context_, num_cols);
+    CudaVector x_left_cuda(&context_, num_cols_e);
+    CudaVector x_right_cuda(&context_, num_cols_f);
+    CudaVector y_cuda(&context_, num_rows);
+    Vector y_cuda_host(num_rows);
+
+    for (int i = 0; i < num_cols_e; ++i) {
+      x.setZero();
+      x_left.setZero();
+      y.setZero();
+      y_cuda.SetZero();
+      x[i] = 1.;
+      x_left[i] = 1.;
+      x_left_cuda.CopyFromCpu(x_left);
+      A_.RightMultiplyAndAccumulate(
+          x.data(), y.data(), &context_, std::thread::hardware_concurrency());
+      matrix_e->RightMultiplyAndAccumulate(x_left_cuda, &y_cuda);
+      y_cuda.CopyTo(&y_cuda_host);
+      // There will be up to 1 non-zero product per row, thus we expect an exact
+      // match on 32-bit integer indices
+      EXPECT_EQ((y - y_cuda_host).squaredNorm(), 0.);
+    }
+    for (int i = num_cols_e; i < num_cols_f; ++i) {
+      x.setZero();
+      x_right.setZero();
+      y.setZero();
+      y_cuda.SetZero();
+      x[i] = 1.;
+      x_right[i - num_cols_e] = 1.;
+      x_right_cuda.CopyFromCpu(x_right);
+      A_.RightMultiplyAndAccumulate(
+          x.data(), y.data(), &context_, std::thread::hardware_concurrency());
+      matrix_f->RightMultiplyAndAccumulate(x_right_cuda, &y_cuda);
+      y_cuda.CopyTo(&y_cuda_host);
+      // There will be up to 1 non-zero product per row, thus we expect an exact
+      // match on 32-bit integer indices
+      EXPECT_EQ((y - y_cuda_host).squaredNorm(), 0.);
+    }
+  }
+
+  // E sub-matrix might have less row-blocks with cells than F sub-matrix. This
+  // test matrix checks if this case is handled properly
+  std::unique_ptr<BlockSparseMatrix> short_e_;
+  // In case of non-crs compatible F matrix, permuting values from block-order
+  // to crs order involves binary search over row-blocks of F. Having lots of
+  // row-blocks with no F cells is an edge case for this algorithm.
+  std::unique_ptr<BlockSparseMatrix> short_f_;
+  // With F matrix being CRS-compatible, update of the values of partitioned
+  // matrix view reduces to two host->device memcopies, and uses a separate code
+  // path
+  std::unique_ptr<BlockSparseMatrix> f_crs_compatible_;
+
+  ContextImpl context_;
+};
+
+TEST_F(CudaPartitionedBlockSparseCRSViewTest, CreateUpdateValuesShortE) {
+  TestMatrix(*short_e_);
+}
+
+TEST_F(CudaPartitionedBlockSparseCRSViewTest, CreateUpdateValuesShortF) {
+  TestMatrix(*short_f_);
+}
+
+TEST_F(CudaPartitionedBlockSparseCRSViewTest,
+       CreateUpdateValuesCrsCompatibleF) {
+  TestMatrix(*f_crs_compatible_);
+}
+}  // namespace ceres::internal
+
+#endif  // CERES_NO_CUDA
diff --git a/third_party/ceres/internal/ceres/cuda_sparse_matrix.cc b/third_party/ceres/internal/ceres/cuda_sparse_matrix.cc
new file mode 100644
index 0000000..33685a4
--- /dev/null
+++ b/third_party/ceres/internal/ceres/cuda_sparse_matrix.cc
@@ -0,0 +1,226 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: joydeepb@cs.utexas.edu (Joydeep Biswas)
+//
+// A CUDA sparse matrix linear operator.
+
+// This include must come before any #ifndef check on Ceres compile options.
+// clang-format off
+#include "ceres/internal/config.h"
+// clang-format on
+
+#include "ceres/cuda_sparse_matrix.h"
+
+#include <math.h>
+
+#include <memory>
+
+#include "ceres/block_sparse_matrix.h"
+#include "ceres/compressed_row_sparse_matrix.h"
+#include "ceres/context_impl.h"
+#include "ceres/crs_matrix.h"
+#include "ceres/internal/export.h"
+#include "ceres/types.h"
+#include "ceres/wall_time.h"
+
+#ifndef CERES_NO_CUDA
+
+#include "ceres/cuda_buffer.h"
+#include "ceres/cuda_kernels_vector_ops.h"
+#include "ceres/cuda_vector.h"
+#include "cuda_runtime_api.h"
+#include "cusparse.h"
+
+namespace ceres::internal {
+namespace {
+// Starting in CUDA 11.2.1, CUSPARSE_MV_ALG_DEFAULT was deprecated in favor of
+// CUSPARSE_SPMV_ALG_DEFAULT.
+#if CUDART_VERSION >= 11021
+const auto kSpMVAlgorithm = CUSPARSE_SPMV_ALG_DEFAULT;
+#else   // CUDART_VERSION >= 11021
+const auto kSpMVAlgorithm = CUSPARSE_MV_ALG_DEFAULT;
+#endif  // CUDART_VERSION >= 11021
+size_t GetTempBufferSizeForOp(const cusparseHandle_t& handle,
+                              const cusparseOperation_t op,
+                              const cusparseDnVecDescr_t& x,
+                              const cusparseDnVecDescr_t& y,
+                              const cusparseSpMatDescr_t& A) {
+  size_t buffer_size;
+  const double alpha = 1.0;
+  const double beta = 1.0;
+  CHECK_NE(A, nullptr);
+  CHECK_EQ(cusparseSpMV_bufferSize(handle,
+                                   op,
+                                   &alpha,
+                                   A,
+                                   x,
+                                   &beta,
+                                   y,
+                                   CUDA_R_64F,
+                                   kSpMVAlgorithm,
+                                   &buffer_size),
+           CUSPARSE_STATUS_SUCCESS);
+  return buffer_size;
+}
+
+size_t GetTempBufferSize(const cusparseHandle_t& handle,
+                         const cusparseDnVecDescr_t& left,
+                         const cusparseDnVecDescr_t& right,
+                         const cusparseSpMatDescr_t& A) {
+  CHECK_NE(A, nullptr);
+  return std::max(GetTempBufferSizeForOp(
+                      handle, CUSPARSE_OPERATION_NON_TRANSPOSE, right, left, A),
+                  GetTempBufferSizeForOp(
+                      handle, CUSPARSE_OPERATION_TRANSPOSE, left, right, A));
+}
+}  // namespace
+
+CudaSparseMatrix::CudaSparseMatrix(int num_cols,
+                                   CudaBuffer<int32_t>&& rows,
+                                   CudaBuffer<int32_t>&& cols,
+                                   ContextImpl* context)
+    : num_rows_(rows.size() - 1),
+      num_cols_(num_cols),
+      num_nonzeros_(cols.size()),
+      context_(context),
+      rows_(std::move(rows)),
+      cols_(std::move(cols)),
+      values_(context, num_nonzeros_),
+      spmv_buffer_(context) {
+  Initialize();
+}
+
+CudaSparseMatrix::CudaSparseMatrix(ContextImpl* context,
+                                   const CompressedRowSparseMatrix& crs_matrix)
+    : num_rows_(crs_matrix.num_rows()),
+      num_cols_(crs_matrix.num_cols()),
+      num_nonzeros_(crs_matrix.num_nonzeros()),
+      context_(context),
+      rows_(context, num_rows_ + 1),
+      cols_(context, num_nonzeros_),
+      values_(context, num_nonzeros_),
+      spmv_buffer_(context) {
+  rows_.CopyFromCpu(crs_matrix.rows(), num_rows_ + 1);
+  cols_.CopyFromCpu(crs_matrix.cols(), num_nonzeros_);
+  values_.CopyFromCpu(crs_matrix.values(), num_nonzeros_);
+  Initialize();
+}
+
+CudaSparseMatrix::~CudaSparseMatrix() {
+  CHECK_EQ(cusparseDestroySpMat(descr_), CUSPARSE_STATUS_SUCCESS);
+  descr_ = nullptr;
+  CHECK_EQ(CUSPARSE_STATUS_SUCCESS, cusparseDestroyDnVec(descr_vec_left_));
+  CHECK_EQ(CUSPARSE_STATUS_SUCCESS, cusparseDestroyDnVec(descr_vec_right_));
+}
+
+void CudaSparseMatrix::CopyValuesFromCpu(
+    const CompressedRowSparseMatrix& crs_matrix) {
+  // There is no quick and easy way to verify that the structure is unchanged,
+  // but at least we can check that the size of the matrix and the number of
+  // nonzeros is unchanged.
+  CHECK_EQ(num_rows_, crs_matrix.num_rows());
+  CHECK_EQ(num_cols_, crs_matrix.num_cols());
+  CHECK_EQ(num_nonzeros_, crs_matrix.num_nonzeros());
+  values_.CopyFromCpu(crs_matrix.values(), num_nonzeros_);
+}
+
+void CudaSparseMatrix::Initialize() {
+  CHECK(context_->IsCudaInitialized());
+  CHECK_EQ(CUSPARSE_STATUS_SUCCESS,
+           cusparseCreateCsr(&descr_,
+                             num_rows_,
+                             num_cols_,
+                             num_nonzeros_,
+                             rows_.data(),
+                             cols_.data(),
+                             values_.data(),
+                             CUSPARSE_INDEX_32I,
+                             CUSPARSE_INDEX_32I,
+                             CUSPARSE_INDEX_BASE_ZERO,
+                             CUDA_R_64F));
+
+  // Note: values_.data() is used as non-zero pointer to device memory
+  // When there is no non-zero values, data-pointer of values_ array will be a
+  // nullptr; but in this case left/right products are trivial and temporary
+  // buffer (and vector descriptors) is not required
+  if (!num_nonzeros_) return;
+
+  CHECK_EQ(CUSPARSE_STATUS_SUCCESS,
+           cusparseCreateDnVec(
+               &descr_vec_left_, num_rows_, values_.data(), CUDA_R_64F));
+  CHECK_EQ(CUSPARSE_STATUS_SUCCESS,
+           cusparseCreateDnVec(
+               &descr_vec_right_, num_cols_, values_.data(), CUDA_R_64F));
+  size_t buffer_size = GetTempBufferSize(
+      context_->cusparse_handle_, descr_vec_left_, descr_vec_right_, descr_);
+  spmv_buffer_.Reserve(buffer_size);
+}
+
+void CudaSparseMatrix::SpMv(cusparseOperation_t op,
+                            const cusparseDnVecDescr_t& x,
+                            const cusparseDnVecDescr_t& y) const {
+  const double alpha = 1.0;
+  const double beta = 1.0;
+
+  CHECK_EQ(cusparseSpMV(context_->cusparse_handle_,
+                        op,
+                        &alpha,
+                        descr_,
+                        x,
+                        &beta,
+                        y,
+                        CUDA_R_64F,
+                        kSpMVAlgorithm,
+                        spmv_buffer_.data()),
+           CUSPARSE_STATUS_SUCCESS);
+}
+
+void CudaSparseMatrix::RightMultiplyAndAccumulate(const CudaVector& x,
+                                                  CudaVector* y) const {
+  DCHECK(GetTempBufferSize(
+             context_->cusparse_handle_, y->descr(), x.descr(), descr_) <=
+         spmv_buffer_.size());
+  SpMv(CUSPARSE_OPERATION_NON_TRANSPOSE, x.descr(), y->descr());
+}
+
+void CudaSparseMatrix::LeftMultiplyAndAccumulate(const CudaVector& x,
+                                                 CudaVector* y) const {
+  // TODO(Joydeep Biswas): We should consider storing a transposed copy of the
+  // matrix by converting CSR to CSC. From the cuSPARSE documentation:
+  // "In general, opA == CUSPARSE_OPERATION_NON_TRANSPOSE is 3x faster than opA
+  // != CUSPARSE_OPERATION_NON_TRANSPOSE"
+  DCHECK(GetTempBufferSize(
+             context_->cusparse_handle_, x.descr(), y->descr(), descr_) <=
+         spmv_buffer_.size());
+  SpMv(CUSPARSE_OPERATION_TRANSPOSE, x.descr(), y->descr());
+}
+
+}  // namespace ceres::internal
+
+#endif  // CERES_NO_CUDA
diff --git a/third_party/ceres/internal/ceres/cuda_sparse_matrix.h b/third_party/ceres/internal/ceres/cuda_sparse_matrix.h
new file mode 100644
index 0000000..2940d1d
--- /dev/null
+++ b/third_party/ceres/internal/ceres/cuda_sparse_matrix.h
@@ -0,0 +1,143 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: joydeepb@cs.utexas.edu (Joydeep Biswas)
+//
+// A CUDA sparse matrix linear operator.
+
+#ifndef CERES_INTERNAL_CUDA_SPARSE_MATRIX_H_
+#define CERES_INTERNAL_CUDA_SPARSE_MATRIX_H_
+
+// This include must come before any #ifndef check on Ceres compile options.
+// clang-format off
+#include "ceres/internal/config.h"
+// clang-format on
+
+#include <cstdint>
+#include <memory>
+#include <string>
+
+#include "ceres/compressed_row_sparse_matrix.h"
+#include "ceres/context_impl.h"
+#include "ceres/internal/export.h"
+#include "ceres/types.h"
+
+#ifndef CERES_NO_CUDA
+#include "ceres/cuda_buffer.h"
+#include "ceres/cuda_vector.h"
+#include "cusparse.h"
+
+namespace ceres::internal {
+
+// A sparse matrix hosted on the GPU in compressed row sparse format, with
+// CUDA-accelerated operations.
+// The user of the class must ensure that ContextImpl::InitCuda() has already
+// been successfully called before using this class.
+class CERES_NO_EXPORT CudaSparseMatrix {
+ public:
+  // Create a GPU copy of the matrix provided.
+  CudaSparseMatrix(ContextImpl* context,
+                   const CompressedRowSparseMatrix& crs_matrix);
+
+  // Create matrix from existing row and column index buffers.
+  // Values are left uninitialized.
+  CudaSparseMatrix(int num_cols,
+                   CudaBuffer<int32_t>&& rows,
+                   CudaBuffer<int32_t>&& cols,
+                   ContextImpl* context);
+
+  ~CudaSparseMatrix();
+
+  // Left/right products are using internal buffer and are not thread-safe
+  // y = y + Ax;
+  void RightMultiplyAndAccumulate(const CudaVector& x, CudaVector* y) const;
+  // y = y + A'x;
+  void LeftMultiplyAndAccumulate(const CudaVector& x, CudaVector* y) const;
+
+  int num_rows() const { return num_rows_; }
+  int num_cols() const { return num_cols_; }
+  int num_nonzeros() const { return num_nonzeros_; }
+
+  const int32_t* rows() const { return rows_.data(); }
+  const int32_t* cols() const { return cols_.data(); }
+  const double* values() const { return values_.data(); }
+
+  int32_t* mutable_rows() { return rows_.data(); }
+  int32_t* mutable_cols() { return cols_.data(); }
+  double* mutable_values() { return values_.data(); }
+
+  // If subsequent uses of this matrix involve only numerical changes and no
+  // structural changes, then this method can be used to copy the updated
+  // non-zero values -- the row and column index arrays are kept  the same. It
+  // is the caller's responsibility to ensure that the sparsity structure of the
+  // matrix is unchanged.
+  void CopyValuesFromCpu(const CompressedRowSparseMatrix& crs_matrix);
+
+  const cusparseSpMatDescr_t& descr() const { return descr_; }
+
+ private:
+  // Disable copy and assignment.
+  CudaSparseMatrix(const CudaSparseMatrix&) = delete;
+  CudaSparseMatrix& operator=(const CudaSparseMatrix&) = delete;
+
+  // Allocate temporary buffer for left/right products, create cuSPARSE
+  // descriptors
+  void Initialize();
+
+  // y = y + op(M)x. op must be either CUSPARSE_OPERATION_NON_TRANSPOSE or
+  // CUSPARSE_OPERATION_TRANSPOSE.
+  void SpMv(cusparseOperation_t op,
+            const cusparseDnVecDescr_t& x,
+            const cusparseDnVecDescr_t& y) const;
+
+  int num_rows_ = 0;
+  int num_cols_ = 0;
+  int num_nonzeros_ = 0;
+
+  ContextImpl* context_ = nullptr;
+  // CSR row indices.
+  CudaBuffer<int32_t> rows_;
+  // CSR column indices.
+  CudaBuffer<int32_t> cols_;
+  // CSR values.
+  CudaBuffer<double> values_;
+
+  // CuSparse object that describes this matrix.
+  cusparseSpMatDescr_t descr_ = nullptr;
+
+  // Dense vector descriptors for pointer interface
+  cusparseDnVecDescr_t descr_vec_left_ = nullptr;
+  cusparseDnVecDescr_t descr_vec_right_ = nullptr;
+
+  mutable CudaBuffer<uint8_t> spmv_buffer_;
+};
+
+}  // namespace ceres::internal
+
+#endif  // CERES_NO_CUDA
+#endif  // CERES_INTERNAL_CUDA_SPARSE_MATRIX_H_
diff --git a/third_party/ceres/internal/ceres/cuda_sparse_matrix_test.cc b/third_party/ceres/internal/ceres/cuda_sparse_matrix_test.cc
new file mode 100644
index 0000000..774829b
--- /dev/null
+++ b/third_party/ceres/internal/ceres/cuda_sparse_matrix_test.cc
@@ -0,0 +1,286 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: joydeepb@cs.utexas.edu (Joydeep Biswas)
+
+#include "ceres/cuda_sparse_matrix.h"
+
+#include <string>
+
+#include "ceres/block_sparse_matrix.h"
+#include "ceres/casts.h"
+#include "ceres/cuda_vector.h"
+#include "ceres/internal/config.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/linear_least_squares_problems.h"
+#include "ceres/triplet_sparse_matrix.h"
+#include "glog/logging.h"
+#include "gtest/gtest.h"
+
+namespace ceres {
+namespace internal {
+
+#ifndef CERES_NO_CUDA
+
+class CudaSparseMatrixTest : public ::testing::Test {
+ protected:
+  void SetUp() final {
+    std::string message;
+    CHECK(context_.InitCuda(&message))
+        << "InitCuda() failed because: " << message;
+    std::unique_ptr<LinearLeastSquaresProblem> problem =
+        CreateLinearLeastSquaresProblemFromId(2);
+    CHECK(problem != nullptr);
+    A_.reset(down_cast<BlockSparseMatrix*>(problem->A.release()));
+    CHECK(A_ != nullptr);
+    CHECK(problem->b != nullptr);
+    CHECK(problem->x != nullptr);
+    b_.resize(A_->num_rows());
+    for (int i = 0; i < A_->num_rows(); ++i) {
+      b_[i] = problem->b[i];
+    }
+    x_.resize(A_->num_cols());
+    for (int i = 0; i < A_->num_cols(); ++i) {
+      x_[i] = problem->x[i];
+    }
+    CHECK_EQ(A_->num_rows(), b_.rows());
+    CHECK_EQ(A_->num_cols(), x_.rows());
+  }
+
+  std::unique_ptr<BlockSparseMatrix> A_;
+  Vector x_;
+  Vector b_;
+  ContextImpl context_;
+};
+
+TEST_F(CudaSparseMatrixTest, RightMultiplyAndAccumulate) {
+  std::string message;
+  auto A_crs = A_->ToCompressedRowSparseMatrix();
+  CudaSparseMatrix A_gpu(&context_, *A_crs);
+  CudaVector x_gpu(&context_, A_gpu.num_cols());
+  CudaVector res_gpu(&context_, A_gpu.num_rows());
+  x_gpu.CopyFromCpu(x_);
+
+  const Vector minus_b = -b_;
+  // res = -b
+  res_gpu.CopyFromCpu(minus_b);
+  // res += A * x
+  A_gpu.RightMultiplyAndAccumulate(x_gpu, &res_gpu);
+
+  Vector res;
+  res_gpu.CopyTo(&res);
+
+  Vector res_expected = minus_b;
+  A_->RightMultiplyAndAccumulate(x_.data(), res_expected.data());
+
+  EXPECT_LE((res - res_expected).norm(),
+            std::numeric_limits<double>::epsilon() * 1e3);
+}
+
+TEST(CudaSparseMatrix, CopyValuesFromCpu) {
+  // A1:
+  // [ 1 1 0 0
+  //   0 1 1 0]
+  // A2:
+  // [ 1 2 0 0
+  //   0 3 4 0]
+  // b: [1 2 3 4]'
+  // A1 * b = [3 5]'
+  // A2 * b = [5 18]'
+  TripletSparseMatrix A1(2, 4, {0, 0, 1, 1}, {0, 1, 1, 2}, {1, 1, 1, 1});
+  TripletSparseMatrix A2(2, 4, {0, 0, 1, 1}, {0, 1, 1, 2}, {1, 2, 3, 4});
+  Vector b(4);
+  b << 1, 2, 3, 4;
+
+  ContextImpl context;
+  std::string message;
+  CHECK(context.InitCuda(&message)) << "InitCuda() failed because: " << message;
+  auto A1_crs = CompressedRowSparseMatrix::FromTripletSparseMatrix(A1);
+  CudaSparseMatrix A_gpu(&context, *A1_crs);
+  CudaVector b_gpu(&context, A1.num_cols());
+  CudaVector x_gpu(&context, A1.num_rows());
+  b_gpu.CopyFromCpu(b);
+  x_gpu.SetZero();
+
+  Vector x_expected(2);
+  x_expected << 3, 5;
+  A_gpu.RightMultiplyAndAccumulate(b_gpu, &x_gpu);
+  Vector x_computed;
+  x_gpu.CopyTo(&x_computed);
+  EXPECT_EQ(x_computed, x_expected);
+
+  auto A2_crs = CompressedRowSparseMatrix::FromTripletSparseMatrix(A2);
+  A_gpu.CopyValuesFromCpu(*A2_crs);
+  x_gpu.SetZero();
+  x_expected << 5, 18;
+  A_gpu.RightMultiplyAndAccumulate(b_gpu, &x_gpu);
+  x_gpu.CopyTo(&x_computed);
+  EXPECT_EQ(x_computed, x_expected);
+}
+
+TEST(CudaSparseMatrix, RightMultiplyAndAccumulate) {
+  // A:
+  // [ 1 2 0 0
+  //   0 3 4 0]
+  // b: [1 2 3 4]'
+  // A * b = [5 18]'
+  TripletSparseMatrix A(2, 4, {0, 0, 1, 1}, {0, 1, 1, 2}, {1, 2, 3, 4});
+  Vector b(4);
+  b << 1, 2, 3, 4;
+  Vector x_expected(2);
+  x_expected << 5, 18;
+
+  ContextImpl context;
+  std::string message;
+  CHECK(context.InitCuda(&message)) << "InitCuda() failed because: " << message;
+  auto A_crs = CompressedRowSparseMatrix::FromTripletSparseMatrix(A);
+  CudaSparseMatrix A_gpu(&context, *A_crs);
+  CudaVector b_gpu(&context, A.num_cols());
+  CudaVector x_gpu(&context, A.num_rows());
+  b_gpu.CopyFromCpu(b);
+  x_gpu.SetZero();
+
+  A_gpu.RightMultiplyAndAccumulate(b_gpu, &x_gpu);
+
+  Vector x_computed;
+  x_gpu.CopyTo(&x_computed);
+
+  EXPECT_EQ(x_computed, x_expected);
+}
+
+TEST(CudaSparseMatrix, LeftMultiplyAndAccumulate) {
+  // A:
+  // [ 1 2 0 0
+  //   0 3 4 0]
+  // b: [1 2]'
+  // A'* b = [1 8 8 0]'
+  TripletSparseMatrix A(2, 4, {0, 0, 1, 1}, {0, 1, 1, 2}, {1, 2, 3, 4});
+  Vector b(2);
+  b << 1, 2;
+  Vector x_expected(4);
+  x_expected << 1, 8, 8, 0;
+
+  ContextImpl context;
+  std::string message;
+  CHECK(context.InitCuda(&message)) << "InitCuda() failed because: " << message;
+  auto A_crs = CompressedRowSparseMatrix::FromTripletSparseMatrix(A);
+  CudaSparseMatrix A_gpu(&context, *A_crs);
+  CudaVector b_gpu(&context, A.num_rows());
+  CudaVector x_gpu(&context, A.num_cols());
+  b_gpu.CopyFromCpu(b);
+  x_gpu.SetZero();
+
+  A_gpu.LeftMultiplyAndAccumulate(b_gpu, &x_gpu);
+
+  Vector x_computed;
+  x_gpu.CopyTo(&x_computed);
+
+  EXPECT_EQ(x_computed, x_expected);
+}
+
+// If there are numerical errors due to synchronization issues, they will show
+// up when testing with large matrices, since each operation will take
+// significant time, thus hopefully revealing any potential synchronization
+// issues.
+TEST(CudaSparseMatrix, LargeMultiplyAndAccumulate) {
+  // Create a large NxN matrix A that has the following structure:
+  // In row i, only columns i and i+1 are non-zero.
+  // A_{i, i} = A_{i, i+1} = 1.
+  // There will be 2 * N - 1 non-zero elements in A.
+  // X = [1:N]
+  // Right multiply test:
+  // b = A * X
+  // Left multiply test:
+  // b = A' * X
+
+  const int N = 10 * 1000 * 1000;
+  const int num_non_zeros = 2 * N - 1;
+  std::vector<int> row_indices(num_non_zeros);
+  std::vector<int> col_indices(num_non_zeros);
+  std::vector<double> values(num_non_zeros);
+
+  for (int i = 0; i < N; ++i) {
+    row_indices[2 * i] = i;
+    col_indices[2 * i] = i;
+    values[2 * i] = 1.0;
+    if (i + 1 < N) {
+      col_indices[2 * i + 1] = i + 1;
+      row_indices[2 * i + 1] = i;
+      values[2 * i + 1] = 1;
+    }
+  }
+  TripletSparseMatrix A(N, N, row_indices, col_indices, values);
+  Vector x(N);
+  for (int i = 0; i < N; ++i) {
+    x[i] = i + 1;
+  }
+
+  ContextImpl context;
+  std::string message;
+  CHECK(context.InitCuda(&message)) << "InitCuda() failed because: " << message;
+  auto A_crs = CompressedRowSparseMatrix::FromTripletSparseMatrix(A);
+  CudaSparseMatrix A_gpu(&context, *A_crs);
+  CudaVector b_gpu(&context, N);
+  CudaVector x_gpu(&context, N);
+  x_gpu.CopyFromCpu(x);
+
+  // First check RightMultiply.
+  {
+    b_gpu.SetZero();
+    A_gpu.RightMultiplyAndAccumulate(x_gpu, &b_gpu);
+    Vector b_computed;
+    b_gpu.CopyTo(&b_computed);
+    for (int i = 0; i < N; ++i) {
+      if (i + 1 < N) {
+        EXPECT_EQ(b_computed[i], 2 * (i + 1) + 1);
+      } else {
+        EXPECT_EQ(b_computed[i], i + 1);
+      }
+    }
+  }
+
+  // Next check LeftMultiply.
+  {
+    b_gpu.SetZero();
+    A_gpu.LeftMultiplyAndAccumulate(x_gpu, &b_gpu);
+    Vector b_computed;
+    b_gpu.CopyTo(&b_computed);
+    for (int i = 0; i < N; ++i) {
+      if (i > 0) {
+        EXPECT_EQ(b_computed[i], 2 * (i + 1) - 1);
+      } else {
+        EXPECT_EQ(b_computed[i], i + 1);
+      }
+    }
+  }
+}
+
+#endif  // CERES_NO_CUDA
+
+}  // namespace internal
+}  // namespace ceres
diff --git a/third_party/ceres/internal/ceres/cuda_streamed_buffer.h b/third_party/ceres/internal/ceres/cuda_streamed_buffer.h
new file mode 100644
index 0000000..37bcf4a
--- /dev/null
+++ b/third_party/ceres/internal/ceres/cuda_streamed_buffer.h
@@ -0,0 +1,338 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Authors: dmitriy.korchemkin@gmail.com (Dmitriy Korchemkin)
+
+#ifndef CERES_INTERNAL_CUDA_STREAMED_BUFFER_H_
+#define CERES_INTERNAL_CUDA_STREAMED_BUFFER_H_
+
+#include "ceres/internal/config.h"
+
+#ifndef CERES_NO_CUDA
+
+#include <algorithm>
+
+#include "ceres/cuda_buffer.h"
+
+namespace ceres::internal {
+
+// Most contemporary CUDA devices are capable of simultaneous code execution and
+// host-to-device transfer. This class copies batches of data to GPU memory and
+// executes processing of copied data in parallel (asynchronously).
+// Data is copied to a fixed-size buffer on GPU (containing at most
+// max_buffer_size values), and this memory is re-used when the previous
+// batch of values is processed by user-provided callback
+// Host-to-device copy uses a temporary buffer if required. Each batch of values
+// has size of kValuesPerBatch, except the last one.
+template <typename T>
+class CERES_NO_EXPORT CudaStreamedBuffer {
+ public:
+  // If hardware supports only one host-to-device copy or one host-to-device
+  // copy is able to reach peak bandwidth, two streams are sufficient to reach
+  // maximum efficiency:
+  //  - If transferring batch of values takes more time, than processing it on
+  //  gpu, then at every moment of time one of the streams will be transferring
+  //  data and other stream will be either processing data or idle; the whole
+  //  process will be bounded by host-to-device copy.
+  //  - If transferring batch of values takes less time, than processing it on
+  //  gpu, then at every moment of time one of the streams will be processing
+  //  data and other stream will be either performing computations or
+  //  transferring data, and the whole process will be bounded by computations.
+  static constexpr int kNumBatches = 2;
+  // max_buffer_size is the maximal size (in elements of type T) of array
+  // to be pre-allocated in gpu memory. The size of array determines size of
+  // batch of values for simultaneous copying and processing. It should be large
+  // enough to allow highly-parallel execution of user kernels; making it too
+  // large increases latency.
+  CudaStreamedBuffer(ContextImpl* context, const int max_buffer_size)
+      : kValuesPerBatch(max_buffer_size / kNumBatches),
+        context_(context),
+        values_gpu_(context, kValuesPerBatch * kNumBatches) {
+    static_assert(ContextImpl::kNumCudaStreams >= kNumBatches);
+    CHECK_GE(max_buffer_size, kNumBatches);
+    // Pre-allocate a buffer of page-locked memory for transfers from a regular
+    // cpu memory. Because we will be only writing into that buffer from cpu,
+    // memory is allocated with cudaHostAllocWriteCombined flag.
+    CHECK_EQ(cudaSuccess,
+             cudaHostAlloc(&values_cpu_pinned_,
+                           sizeof(T) * kValuesPerBatch * kNumBatches,
+                           cudaHostAllocWriteCombined));
+    for (auto& e : copy_finished_) {
+      CHECK_EQ(cudaSuccess,
+               cudaEventCreateWithFlags(&e, cudaEventDisableTiming));
+    }
+  }
+
+  CudaStreamedBuffer(const CudaStreamedBuffer&) = delete;
+
+  ~CudaStreamedBuffer() {
+    CHECK_EQ(cudaSuccess, cudaFreeHost(values_cpu_pinned_));
+    for (auto& e : copy_finished_) {
+      CHECK_EQ(cudaSuccess, cudaEventDestroy(e));
+    }
+  }
+
+  // Transfer num_values at host-memory pointer from, calling
+  // callback(device_pointer, size_of_batch, offset_of_batch, stream_to_use)
+  // after scheduling transfer of each batch of data. User-provided callback
+  // should perform processing of data at device_pointer only in
+  // stream_to_use stream (device_pointer will be re-used in the next
+  // callback invocation with the same stream).
+  //
+  // Two diagrams below describe operation in two possible scenarios, depending
+  // on input data being stored in page-locked memory. In this example we will
+  // have max_buffer_size = 2 * K, num_values = N * K and callback
+  // scheduling a single asynchronous launch of
+  // Kernel<<..., stream_to_use>>(device_pointer,
+  //                              size_of_batch,
+  //                              offset_of_batch)
+  //
+  // a. Copying from page-locked memory
+  // In this case no copy on the host-side is necessary, and this method just
+  // schedules a bunch of interleaved memory copies and callback invocations:
+  //
+  //  cudaStreamSynchronize(context->DefaultStream());
+  //  - Iteration #0:
+  //    - cudaMemcpyAsync(values_gpu_, from, K * sizeof(T), H->D, stream_0)
+  //    - callback(values_gpu_, K, 0, stream_0)
+  //  - Iteration #1:
+  //    - cudaMemcpyAsync(values_gpu_ + K, from + K, K * sizeof(T), H->D,
+  //    stream_1)
+  //    - callback(values_gpu_ + K, K, K, stream_1)
+  //  - Iteration #2:
+  //    - cudaMemcpyAsync(values_gpu_, from + 2 * K, K * sizeof(T), H->D,
+  //    stream_0)
+  //    - callback(values_gpu_, K, 2 * K, stream_0)
+  //  - Iteration #3:
+  //     - cudaMemcpyAsync(values_gpu_ + K, from + 3 * K, K * sizeof(T), H->D,
+  //     stream_1)
+  //     - callback(values_gpu_ + K, K, 3 * K, stream_1)
+  //  ...
+  //  - Iteration #i:
+  //     - cudaMemcpyAsync(values_gpu_ + (i % 2) * K, from + i * K, K *
+  //     sizeof(T), H->D, stream_(i % 2))
+  //     - callback(values_gpu_ + (i % 2) * K, K, i * K, stream_(i % 2)
+  //  ...
+  //  cudaStreamSynchronize(stream_0)
+  //  cudaStreamSynchronize(stream_1)
+  //
+  //  This sequence of calls results in following activity on gpu (assuming that
+  //  kernel invoked by callback takes less time than host-to-device copy):
+  //  +-------------------+-------------------+
+  //  | Stream #0         | Stream #1         |
+  //  +-------------------+-------------------+
+  //  | Copy host->device |                   |
+  //  |                   |                   |
+  //  |                   |                   |
+  //  +-------------------+-------------------+
+  //  | Kernel            | Copy host->device |
+  //  +-------------------+                   |
+  //  |                   |                   |
+  //  +-------------------+-------------------+
+  //  | Copy host->device | Kernel            |
+  //  |                   +-------------------+
+  //  |                   |                   |
+  //  +-------------------+-------------------+
+  //  | Kernel            | Copy host->device |
+  //  |                  ...                  |
+  //  +---------------------------------------+
+  //
+  // b. Copying from regular memory
+  // In this case a copy from regular memory to page-locked memory is required
+  // in order to get asynchrnonous operation. Because pinned memory on host-side
+  // is reused, additional synchronization is required. On each iteration method
+  // the following actions are performed:
+  //  - Wait till previous copy operation in stream is completed
+  //  - Copy batch of values from input array into pinned memory
+  //  - Asynchronously launch host-to-device copy
+  //  - Setup event for synchronization on copy completion
+  //  - Invoke callback (that launches kernel asynchronously)
+  //
+  //  Invocations are performed with the following arguments
+  //  cudaStreamSynchronize(context->DefaultStream());
+  //  - Iteration #0:
+  //    - cudaEventSynchronize(copy_finished_0)
+  //    - std::copy_n(from, K, values_cpu_pinned_)
+  //    - cudaMemcpyAsync(values_gpu_, values_cpu_pinned_, K * sizeof(T), H->D,
+  //    stream_0)
+  //    - cudaEventRecord(copy_finished_0, stream_0)
+  //    - callback(values_gpu_, K, 0, stream_0)
+  //  - Iteration #1:
+  //    - cudaEventSynchronize(copy_finished_1)
+  //    - std::copy_n(from + K, K, values_cpu_pinned_ + K)
+  //    - cudaMemcpyAsync(values_gpu_ + K, values_cpu_pinned_ + K, K *
+  //    sizeof(T), H->D, stream_1)
+  //    - cudaEventRecord(copy_finished_1, stream_1)
+  //    - callback(values_gpu_ + K, K, K, stream_1)
+  //  - Iteration #2:
+  //    - cudaEventSynchronize(copy_finished_0)
+  //    - std::copy_n(from + 2 * K, K, values_cpu_pinned_)
+  //    - cudaMemcpyAsync(values_gpu_, values_cpu_pinned_, K * sizeof(T), H->D,
+  //    stream_0)
+  //    - cudaEventRecord(copy_finished_0, stream_0)
+  //    - callback(values_gpu_, K, 2 * K, stream_0)
+  //  - Iteration #3:
+  //    - cudaEventSynchronize(copy_finished_1)
+  //    - std::copy_n(from + 3 * K, K, values_cpu_pinned_ + K)
+  //    - cudaMemcpyAsync(values_gpu_ + K, values_cpu_pinned_ + K, K *
+  //    sizeof(T), H->D, stream_1)
+  //    - cudaEventRecord(copy_finished_1, stream_1)
+  //    - callback(values_gpu_ + K, K, 3 * K, stream_1)
+  //  ...
+  //  - Iteration #i:
+  //    - cudaEventSynchronize(copy_finished_(i % 2))
+  //    - std::copy_n(from + i * K, K, values_cpu_pinned_ + (i % 2) * K)
+  //    - cudaMemcpyAsync(values_gpu_ + (i % 2) * K, values_cpu_pinned_ + (i %
+  //    2) * K, K * sizeof(T), H->D, stream_(i % 2))
+  //    - cudaEventRecord(copy_finished_(i % 2), stream_(i % 2))
+  //    - callback(values_gpu_ + (i % 2) * K, K, i * K, stream_(i % 2))
+  //  ...
+  //  cudaStreamSynchronize(stream_0)
+  //  cudaStreamSynchronize(stream_1)
+  //
+  //  This sequence of calls results in following activity on cpu and gpu
+  //  (assuming that kernel invoked by callback takes less time than
+  //  host-to-device copy and copy in cpu memory, and copy in cpu memory is
+  //  faster than host-to-device copy):
+  //  +----------------------------+-------------------+-------------------+
+  //  | Stream #0                  | Stream #0         | Stream #1         |
+  //  +----------------------------+-------------------+-------------------+
+  //  | Copy to pinned memory      |                   |                   |
+  //  |                            |                   |                   |
+  //  +----------------------------+-------------------|                   |
+  //  | Copy to pinned memory      | Copy host->device |                   |
+  //  |                            |                   |                   |
+  //  +----------------------------+                   |                   |
+  //  | Waiting previous h->d copy |                   |                   |
+  //  +----------------------------+-------------------+-------------------+
+  //  | Copy to pinned memory      | Kernel            | Copy host->device |
+  //  |                            +-------------------+                   |
+  //  +----------------------------+                   |                   |
+  //  | Waiting previous h->d copy |                   |                   |
+  //  +----------------------------+-------------------+-------------------+
+  //  | Copy to pinned memory      | Copy host->device | Kernel            |
+  //  |                            |                   +-------------------+
+  //  |                           ...                 ...                  |
+  //  +----------------------------+---------------------------------------+
+  //
+  template <typename Fun>
+  void CopyToGpu(const T* from, const int num_values, Fun&& callback) {
+    // This synchronization is not required in some cases, but we perform it in
+    // order to avoid situation when user callback depends on data that is
+    // still to be computed in default stream
+    CHECK_EQ(cudaSuccess, cudaStreamSynchronize(context_->DefaultStream()));
+
+    // If pointer to input data does not correspond to page-locked memory,
+    // host-to-device memory copy might be executed synchrnonously (with a copy
+    // to pinned memory happening inside the driver). In that case we perform
+    // copy to a pre-allocated array of page-locked memory.
+    const bool copy_to_pinned_memory = MemoryTypeResultsInSynchronousCopy(from);
+    T* batch_values_gpu[kNumBatches];
+    T* batch_values_cpu[kNumBatches];
+    auto streams = context_->streams_;
+    for (int i = 0; i < kNumBatches; ++i) {
+      batch_values_gpu[i] = values_gpu_.data() + kValuesPerBatch * i;
+      batch_values_cpu[i] = values_cpu_pinned_ + kValuesPerBatch * i;
+    }
+    int batch_id = 0;
+    for (int offset = 0; offset < num_values; offset += kValuesPerBatch) {
+      const int num_values_batch =
+          std::min(num_values - offset, kValuesPerBatch);
+      const T* batch_from = from + offset;
+      T* batch_to = batch_values_gpu[batch_id];
+      auto stream = streams[batch_id];
+      auto copy_finished = copy_finished_[batch_id];
+
+      if (copy_to_pinned_memory) {
+        // Copying values to a temporary buffer should be started only after the
+        // previous copy from temporary buffer to device is completed.
+        CHECK_EQ(cudaSuccess, cudaEventSynchronize(copy_finished));
+        std::copy_n(batch_from, num_values_batch, batch_values_cpu[batch_id]);
+        batch_from = batch_values_cpu[batch_id];
+      }
+      CHECK_EQ(cudaSuccess,
+               cudaMemcpyAsync(batch_to,
+                               batch_from,
+                               sizeof(T) * num_values_batch,
+                               cudaMemcpyHostToDevice,
+                               stream));
+      if (copy_to_pinned_memory) {
+        // Next copy to a temporary buffer can start straight after asynchronous
+        // copy is completed (and might be started before kernels asynchronously
+        // executed in stream by user-supplied callback are completed).
+        // No explicit synchronization is required when copying data from
+        // page-locked memory, because memory copy and user kernel execution
+        // with corresponding part of values_gpu_ array is serialized using
+        // stream
+        CHECK_EQ(cudaSuccess, cudaEventRecord(copy_finished, stream));
+      }
+      callback(batch_to, num_values_batch, offset, stream);
+      batch_id = (batch_id + 1) % kNumBatches;
+    }
+    // Explicitly synchronize on all CUDA streams that were utilized.
+    for (int i = 0; i < kNumBatches; ++i) {
+      CHECK_EQ(cudaSuccess, cudaStreamSynchronize(streams[i]));
+    }
+  }
+
+ private:
+  // It is necessary to have all host-to-device copies to be completely
+  // asynchronous. This requires source memory to be allocated in page-locked
+  // memory.
+  static bool MemoryTypeResultsInSynchronousCopy(const void* ptr) {
+    cudaPointerAttributes attributes;
+    auto status = cudaPointerGetAttributes(&attributes, ptr);
+#if CUDART_VERSION < 11000
+    // In CUDA versions prior 11 call to cudaPointerGetAttributes with host
+    // pointer will return  cudaErrorInvalidValue
+    if (status == cudaErrorInvalidValue) {
+      return true;
+    }
+#endif
+    CHECK_EQ(status, cudaSuccess);
+    // This class only supports cpu memory as a source
+    CHECK_NE(attributes.type, cudaMemoryTypeDevice);
+    // If host memory was allocated (or registered) with CUDA API, or is a
+    // managed memory, then call to cudaMemcpyAsync will be asynchrnous. In case
+    // of managed memory it might be slightly better to perform a single call of
+    // user-provided call-back (and hope that page migration will provide a
+    // similar throughput with zero efforts from our side).
+    return attributes.type == cudaMemoryTypeUnregistered;
+  }
+
+  const int kValuesPerBatch;
+  ContextImpl* context_ = nullptr;
+  CudaBuffer<T> values_gpu_;
+  T* values_cpu_pinned_ = nullptr;
+  cudaEvent_t copy_finished_[kNumBatches] = {nullptr};
+};
+
+}  // namespace ceres::internal
+
+#endif  // CERES_NO_CUDA
+#endif  // CERES_INTERNAL_CUDA_STREAMED_BUFFER_H_
diff --git a/third_party/ceres/internal/ceres/cuda_streamed_buffer_test.cc b/third_party/ceres/internal/ceres/cuda_streamed_buffer_test.cc
new file mode 100644
index 0000000..4837005
--- /dev/null
+++ b/third_party/ceres/internal/ceres/cuda_streamed_buffer_test.cc
@@ -0,0 +1,169 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Authors: dmitriy.korchemkin@gmail.com (Dmitriy Korchemkin)
+
+#include "ceres/internal/config.h"
+
+#ifndef CERES_NO_CUDA
+
+#include <glog/logging.h>
+#include <gtest/gtest.h>
+
+#include <numeric>
+
+#include "ceres/cuda_streamed_buffer.h"
+
+namespace ceres::internal {
+
+TEST(CudaStreamedBufferTest, IntegerCopy) {
+  // Offsets and sizes of batches supplied to callback
+  std::vector<std::pair<int, int>> batches;
+  const int kMaxTemporaryArraySize = 16;
+  const int kInputSize = kMaxTemporaryArraySize * 7 + 3;
+  ContextImpl context;
+  std::string message;
+  CHECK(context.InitCuda(&message)) << "InitCuda() failed because: " << message;
+
+  std::vector<int> inputs(kInputSize);
+  std::vector<int> outputs(kInputSize, -1);
+  std::iota(inputs.begin(), inputs.end(), 0);
+
+  CudaStreamedBuffer<int> streamed_buffer(&context, kMaxTemporaryArraySize);
+  streamed_buffer.CopyToGpu(inputs.data(),
+                            kInputSize,
+                            [&outputs, &batches](const int* device_pointer,
+                                                 int size,
+                                                 int offset,
+                                                 cudaStream_t stream) {
+                              batches.emplace_back(offset, size);
+                              CHECK_EQ(cudaSuccess,
+                                       cudaMemcpyAsync(outputs.data() + offset,
+                                                       device_pointer,
+                                                       sizeof(int) * size,
+                                                       cudaMemcpyDeviceToHost,
+                                                       stream));
+                            });
+  // All operations in all streams should be completed when CopyToGpu returns
+  // control to the callee
+  for (int i = 0; i < ContextImpl::kNumCudaStreams; ++i) {
+    CHECK_EQ(cudaSuccess, cudaStreamQuery(context.streams_[i]));
+  }
+
+  // Check if every element was visited
+  for (int i = 0; i < kInputSize; ++i) {
+    CHECK_EQ(outputs[i], i);
+  }
+
+  // Check if there is no overlap between batches
+  std::sort(batches.begin(), batches.end());
+  const int num_batches = batches.size();
+  for (int i = 0; i < num_batches; ++i) {
+    const auto [begin, size] = batches[i];
+    const int end = begin + size;
+    CHECK_GE(begin, 0);
+    CHECK_LT(begin, kInputSize);
+
+    CHECK_GT(size, 0);
+    CHECK_LE(end, kInputSize);
+
+    if (i + 1 == num_batches) continue;
+    CHECK_EQ(end, batches[i + 1].first);
+  }
+}
+
+TEST(CudaStreamedBufferTest, IntegerNoCopy) {
+  // Offsets and sizes of batches supplied to callback
+  std::vector<std::pair<int, int>> batches;
+  const int kMaxTemporaryArraySize = 16;
+  const int kInputSize = kMaxTemporaryArraySize * 7 + 3;
+  ContextImpl context;
+  std::string message;
+  CHECK(context.InitCuda(&message)) << "InitCuda() failed because: " << message;
+
+  int* inputs;
+  int* outputs;
+  CHECK_EQ(cudaSuccess,
+           cudaHostAlloc(
+               &inputs, sizeof(int) * kInputSize, cudaHostAllocWriteCombined));
+  CHECK_EQ(
+      cudaSuccess,
+      cudaHostAlloc(&outputs, sizeof(int) * kInputSize, cudaHostAllocDefault));
+
+  std::fill(outputs, outputs + kInputSize, -1);
+  std::iota(inputs, inputs + kInputSize, 0);
+
+  CudaStreamedBuffer<int> streamed_buffer(&context, kMaxTemporaryArraySize);
+  streamed_buffer.CopyToGpu(inputs,
+                            kInputSize,
+                            [outputs, &batches](const int* device_pointer,
+                                                int size,
+                                                int offset,
+                                                cudaStream_t stream) {
+                              batches.emplace_back(offset, size);
+                              CHECK_EQ(cudaSuccess,
+                                       cudaMemcpyAsync(outputs + offset,
+                                                       device_pointer,
+                                                       sizeof(int) * size,
+                                                       cudaMemcpyDeviceToHost,
+                                                       stream));
+                            });
+  // All operations in all streams should be completed when CopyToGpu returns
+  // control to the callee
+  for (int i = 0; i < ContextImpl::kNumCudaStreams; ++i) {
+    CHECK_EQ(cudaSuccess, cudaStreamQuery(context.streams_[i]));
+  }
+
+  // Check if every element was visited
+  for (int i = 0; i < kInputSize; ++i) {
+    CHECK_EQ(outputs[i], i);
+  }
+
+  // Check if there is no overlap between batches
+  std::sort(batches.begin(), batches.end());
+  const int num_batches = batches.size();
+  for (int i = 0; i < num_batches; ++i) {
+    const auto [begin, size] = batches[i];
+    const int end = begin + size;
+    CHECK_GE(begin, 0);
+    CHECK_LT(begin, kInputSize);
+
+    CHECK_GT(size, 0);
+    CHECK_LE(end, kInputSize);
+
+    if (i + 1 == num_batches) continue;
+    CHECK_EQ(end, batches[i + 1].first);
+  }
+
+  CHECK_EQ(cudaSuccess, cudaFreeHost(inputs));
+  CHECK_EQ(cudaSuccess, cudaFreeHost(outputs));
+}
+
+}  // namespace ceres::internal
+
+#endif  // CERES_NO_CUDA
diff --git a/third_party/ceres/internal/ceres/cuda_vector.cc b/third_party/ceres/internal/ceres/cuda_vector.cc
new file mode 100644
index 0000000..08217b2
--- /dev/null
+++ b/third_party/ceres/internal/ceres/cuda_vector.cc
@@ -0,0 +1,185 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: joydeepb@cs.utexas.edu (Joydeep Biswas)
+//
+// A simple CUDA vector class.
+
+// This include must come before any #ifndef check on Ceres compile options.
+// clang-format off
+#include "ceres/internal/config.h"
+// clang-format on
+
+#include <math.h>
+
+#include "ceres/context_impl.h"
+#include "ceres/internal/export.h"
+#include "ceres/types.h"
+
+#ifndef CERES_NO_CUDA
+
+#include "ceres/cuda_buffer.h"
+#include "ceres/cuda_kernels_vector_ops.h"
+#include "ceres/cuda_vector.h"
+#include "cublas_v2.h"
+
+namespace ceres::internal {
+
+CudaVector::CudaVector(ContextImpl* context, int size)
+    : context_(context), data_(context, size) {
+  DCHECK_NE(context, nullptr);
+  DCHECK(context->IsCudaInitialized());
+  Resize(size);
+}
+
+CudaVector::CudaVector(CudaVector&& other)
+    : num_rows_(other.num_rows_),
+      context_(other.context_),
+      data_(std::move(other.data_)),
+      descr_(other.descr_) {
+  other.num_rows_ = 0;
+  other.descr_ = nullptr;
+}
+
+CudaVector& CudaVector::operator=(const CudaVector& other) {
+  if (this != &other) {
+    Resize(other.num_rows());
+    data_.CopyFromGPUArray(other.data_.data(), num_rows_);
+  }
+  return *this;
+}
+
+void CudaVector::DestroyDescriptor() {
+  if (descr_ != nullptr) {
+    CHECK_EQ(cusparseDestroyDnVec(descr_), CUSPARSE_STATUS_SUCCESS);
+    descr_ = nullptr;
+  }
+}
+
+CudaVector::~CudaVector() { DestroyDescriptor(); }
+
+void CudaVector::Resize(int size) {
+  data_.Reserve(size);
+  num_rows_ = size;
+  DestroyDescriptor();
+  CHECK_EQ(cusparseCreateDnVec(&descr_, num_rows_, data_.data(), CUDA_R_64F),
+           CUSPARSE_STATUS_SUCCESS);
+}
+
+double CudaVector::Dot(const CudaVector& x) const {
+  double result = 0;
+  CHECK_EQ(cublasDdot(context_->cublas_handle_,
+                      num_rows_,
+                      data_.data(),
+                      1,
+                      x.data(),
+                      1,
+                      &result),
+           CUBLAS_STATUS_SUCCESS)
+      << "CuBLAS cublasDdot failed.";
+  return result;
+}
+
+double CudaVector::Norm() const {
+  double result = 0;
+  CHECK_EQ(cublasDnrm2(
+               context_->cublas_handle_, num_rows_, data_.data(), 1, &result),
+           CUBLAS_STATUS_SUCCESS)
+      << "CuBLAS cublasDnrm2 failed.";
+  return result;
+}
+
+void CudaVector::CopyFromCpu(const double* x) {
+  data_.CopyFromCpu(x, num_rows_);
+}
+
+void CudaVector::CopyFromCpu(const Vector& x) {
+  if (x.rows() != num_rows_) {
+    Resize(x.rows());
+  }
+  CopyFromCpu(x.data());
+}
+
+void CudaVector::CopyTo(Vector* x) const {
+  CHECK(x != nullptr);
+  x->resize(num_rows_);
+  data_.CopyToCpu(x->data(), num_rows_);
+}
+
+void CudaVector::CopyTo(double* x) const {
+  CHECK(x != nullptr);
+  data_.CopyToCpu(x, num_rows_);
+}
+
+void CudaVector::SetZero() {
+  // Allow empty vector to be zeroed
+  if (num_rows_ == 0) return;
+  CHECK(data_.data() != nullptr);
+  CudaSetZeroFP64(data_.data(), num_rows_, context_->DefaultStream());
+}
+
+void CudaVector::Axpby(double a, const CudaVector& x, double b) {
+  if (&x == this) {
+    Scale(a + b);
+    return;
+  }
+  CHECK_EQ(num_rows_, x.num_rows_);
+  if (b != 1.0) {
+    // First scale y by b.
+    CHECK_EQ(
+        cublasDscal(context_->cublas_handle_, num_rows_, &b, data_.data(), 1),
+        CUBLAS_STATUS_SUCCESS)
+        << "CuBLAS cublasDscal failed.";
+  }
+  // Then add a * x to y.
+  CHECK_EQ(cublasDaxpy(context_->cublas_handle_,
+                       num_rows_,
+                       &a,
+                       x.data(),
+                       1,
+                       data_.data(),
+                       1),
+           CUBLAS_STATUS_SUCCESS)
+      << "CuBLAS cublasDaxpy failed.";
+}
+
+void CudaVector::DtDxpy(const CudaVector& D, const CudaVector& x) {
+  CudaDtDxpy(
+      data_.data(), D.data(), x.data(), num_rows_, context_->DefaultStream());
+}
+
+void CudaVector::Scale(double s) {
+  CHECK_EQ(
+      cublasDscal(context_->cublas_handle_, num_rows_, &s, data_.data(), 1),
+      CUBLAS_STATUS_SUCCESS)
+      << "CuBLAS cublasDscal failed.";
+}
+
+}  // namespace ceres::internal
+
+#endif  // CERES_NO_CUDA
diff --git a/third_party/ceres/internal/ceres/cuda_vector.h b/third_party/ceres/internal/ceres/cuda_vector.h
new file mode 100644
index 0000000..8db5649
--- /dev/null
+++ b/third_party/ceres/internal/ceres/cuda_vector.h
@@ -0,0 +1,193 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: joydeepb@cs.utexas.edu (Joydeep Biswas)
+//
+// A simple CUDA vector class.
+
+#ifndef CERES_INTERNAL_CUDA_VECTOR_H_
+#define CERES_INTERNAL_CUDA_VECTOR_H_
+
+// This include must come before any #ifndef check on Ceres compile options.
+// clang-format off
+#include "ceres/internal/config.h"
+// clang-format on
+
+#include <math.h>
+
+#include <memory>
+#include <string>
+
+#include "ceres/context_impl.h"
+#include "ceres/internal/export.h"
+#include "ceres/types.h"
+
+#ifndef CERES_NO_CUDA
+
+#include "ceres/cuda_buffer.h"
+#include "ceres/cuda_kernels_vector_ops.h"
+#include "ceres/internal/eigen.h"
+#include "cublas_v2.h"
+#include "cusparse.h"
+
+namespace ceres::internal {
+
+// An Nx1 vector, denoted y hosted on the GPU, with CUDA-accelerated operations.
+class CERES_NO_EXPORT CudaVector {
+ public:
+  // Create a pre-allocated vector of size N and return a pointer to it. The
+  // caller must ensure that InitCuda() has already been successfully called on
+  // context before calling this method.
+  CudaVector(ContextImpl* context, int size);
+
+  CudaVector(CudaVector&& other);
+
+  ~CudaVector();
+
+  void Resize(int size);
+
+  // Perform a deep copy of the vector.
+  CudaVector& operator=(const CudaVector&);
+
+  // Return the inner product x' * y.
+  double Dot(const CudaVector& x) const;
+
+  // Return the L2 norm of the vector (||y||_2).
+  double Norm() const;
+
+  // Set all elements to zero.
+  void SetZero();
+
+  // Copy from Eigen vector.
+  void CopyFromCpu(const Vector& x);
+
+  // Copy from CPU memory array.
+  void CopyFromCpu(const double* x);
+
+  // Copy to Eigen vector.
+  void CopyTo(Vector* x) const;
+
+  // Copy to CPU memory array. It is the caller's responsibility to ensure
+  // that the array is large enough.
+  void CopyTo(double* x) const;
+
+  // y = a * x + b * y.
+  void Axpby(double a, const CudaVector& x, double b);
+
+  // y = diag(d)' * diag(d) * x + y.
+  void DtDxpy(const CudaVector& D, const CudaVector& x);
+
+  // y = s * y.
+  void Scale(double s);
+
+  int num_rows() const { return num_rows_; }
+  int num_cols() const { return 1; }
+
+  const double* data() const { return data_.data(); }
+  double* mutable_data() { return data_.data(); }
+
+  const cusparseDnVecDescr_t& descr() const { return descr_; }
+
+ private:
+  CudaVector(const CudaVector&) = delete;
+  void DestroyDescriptor();
+
+  int num_rows_ = 0;
+  ContextImpl* context_ = nullptr;
+  CudaBuffer<double> data_;
+  // CuSparse object that describes this dense vector.
+  cusparseDnVecDescr_t descr_ = nullptr;
+};
+
+// Blas1 operations on Cuda vectors. These functions are needed as an
+// abstraction layer so that we can use different versions of a vector style
+// object in the conjugate gradients linear solver.
+// Context and num_threads arguments are not used by CUDA implementation,
+// context embedded into CudaVector is used instead.
+inline double Norm(const CudaVector& x,
+                   ContextImpl* context = nullptr,
+                   int num_threads = 1) {
+  (void)context;
+  (void)num_threads;
+  return x.Norm();
+}
+inline void SetZero(CudaVector& x,
+                    ContextImpl* context = nullptr,
+                    int num_threads = 1) {
+  (void)context;
+  (void)num_threads;
+  x.SetZero();
+}
+inline void Axpby(double a,
+                  const CudaVector& x,
+                  double b,
+                  const CudaVector& y,
+                  CudaVector& z,
+                  ContextImpl* context = nullptr,
+                  int num_threads = 1) {
+  (void)context;
+  (void)num_threads;
+  if (&x == &y && &y == &z) {
+    // z = (a + b) * z;
+    z.Scale(a + b);
+  } else if (&x == &z) {
+    // x is aliased to z.
+    // z = x
+    //   = b * y + a * x;
+    z.Axpby(b, y, a);
+  } else if (&y == &z) {
+    // y is aliased to z.
+    // z = y = a * x + b * y;
+    z.Axpby(a, x, b);
+  } else {
+    // General case: all inputs and outputs are distinct.
+    z = y;
+    z.Axpby(a, x, b);
+  }
+}
+inline double Dot(const CudaVector& x,
+                  const CudaVector& y,
+                  ContextImpl* context = nullptr,
+                  int num_threads = 1) {
+  (void)context;
+  (void)num_threads;
+  return x.Dot(y);
+}
+inline void Copy(const CudaVector& from,
+                 CudaVector& to,
+                 ContextImpl* context = nullptr,
+                 int num_threads = 1) {
+  (void)context;
+  (void)num_threads;
+  to = from;
+}
+
+}  // namespace ceres::internal
+
+#endif  // CERES_NO_CUDA
+#endif  // CERES_INTERNAL_CUDA_SPARSE_LINEAR_OPERATOR_H_
diff --git a/third_party/ceres/internal/ceres/cuda_vector_test.cc b/third_party/ceres/internal/ceres/cuda_vector_test.cc
new file mode 100644
index 0000000..8dcb4b7
--- /dev/null
+++ b/third_party/ceres/internal/ceres/cuda_vector_test.cc
@@ -0,0 +1,423 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: joydeepb@cs.utexas.edu (Joydeep Biswas)
+
+#include "ceres/cuda_vector.h"
+
+#include <string>
+
+#include "ceres/internal/config.h"
+#include "ceres/internal/eigen.h"
+#include "glog/logging.h"
+#include "gtest/gtest.h"
+
+namespace ceres {
+namespace internal {
+
+#ifndef CERES_NO_CUDA
+
+TEST(CudaVector, Creation) {
+  ContextImpl context;
+  std::string message;
+  CHECK(context.InitCuda(&message)) << "InitCuda() failed because: " << message;
+  CudaVector x(&context, 1000);
+  EXPECT_EQ(x.num_rows(), 1000);
+  EXPECT_NE(x.data(), nullptr);
+}
+
+TEST(CudaVector, CopyVector) {
+  Vector x(3);
+  x << 1, 2, 3;
+  ContextImpl context;
+  std::string message;
+  CHECK(context.InitCuda(&message)) << "InitCuda() failed because: " << message;
+  CudaVector y(&context, 10);
+  y.CopyFromCpu(x);
+  EXPECT_EQ(y.num_rows(), 3);
+
+  Vector z(3);
+  z << 0, 0, 0;
+  y.CopyTo(&z);
+  EXPECT_EQ(x, z);
+}
+
+TEST(CudaVector, Move) {
+  ContextImpl context;
+  std::string message;
+  CHECK(context.InitCuda(&message)) << "InitCuda() failed because: " << message;
+  CudaVector y(&context, 10);
+  const auto y_data = y.data();
+  const auto y_descr = y.descr();
+  EXPECT_EQ(y.num_rows(), 10);
+  CudaVector z(std::move(y));
+  EXPECT_EQ(y.data(), nullptr);
+  EXPECT_EQ(y.descr(), nullptr);
+  EXPECT_EQ(y.num_rows(), 0);
+
+  EXPECT_EQ(z.data(), y_data);
+  EXPECT_EQ(z.descr(), y_descr);
+}
+
+TEST(CudaVector, DeepCopy) {
+  Vector x(3);
+  x << 1, 2, 3;
+  ContextImpl context;
+  std::string message;
+  CHECK(context.InitCuda(&message)) << "InitCuda() failed because: " << message;
+  CudaVector x_gpu(&context, 3);
+  x_gpu.CopyFromCpu(x);
+
+  CudaVector y_gpu(&context, 3);
+  y_gpu.SetZero();
+  EXPECT_EQ(y_gpu.Norm(), 0.0);
+
+  y_gpu = x_gpu;
+  Vector y(3);
+  y << 0, 0, 0;
+  y_gpu.CopyTo(&y);
+  EXPECT_EQ(x, y);
+}
+
+TEST(CudaVector, Dot) {
+  Vector x(3);
+  Vector y(3);
+  x << 1, 2, 3;
+  y << 100, 10, 1;
+  ContextImpl context;
+  std::string message;
+  CHECK(context.InitCuda(&message)) << "InitCuda() failed because: " << message;
+  CudaVector x_gpu(&context, 10);
+  CudaVector y_gpu(&context, 10);
+  x_gpu.CopyFromCpu(x);
+  y_gpu.CopyFromCpu(y);
+
+  EXPECT_EQ(x_gpu.Dot(y_gpu), 123.0);
+  EXPECT_EQ(Dot(x_gpu, y_gpu), 123.0);
+}
+
+TEST(CudaVector, Norm) {
+  Vector x(3);
+  x << 1, 2, 3;
+  ContextImpl context;
+  std::string message;
+  CHECK(context.InitCuda(&message)) << "InitCuda() failed because: " << message;
+  CudaVector x_gpu(&context, 10);
+  x_gpu.CopyFromCpu(x);
+
+  EXPECT_NEAR(x_gpu.Norm(),
+              sqrt(1.0 + 4.0 + 9.0),
+              std::numeric_limits<double>::epsilon());
+
+  EXPECT_NEAR(Norm(x_gpu),
+              sqrt(1.0 + 4.0 + 9.0),
+              std::numeric_limits<double>::epsilon());
+}
+
+TEST(CudaVector, SetZero) {
+  Vector x(4);
+  x << 1, 1, 1, 1;
+  ContextImpl context;
+  std::string message;
+  CHECK(context.InitCuda(&message)) << "InitCuda() failed because: " << message;
+  CudaVector x_gpu(&context, 10);
+  x_gpu.CopyFromCpu(x);
+
+  EXPECT_NEAR(x_gpu.Norm(), 2.0, std::numeric_limits<double>::epsilon());
+
+  x_gpu.SetZero();
+  EXPECT_NEAR(x_gpu.Norm(), 0.0, std::numeric_limits<double>::epsilon());
+
+  x_gpu.CopyFromCpu(x);
+  EXPECT_NEAR(x_gpu.Norm(), 2.0, std::numeric_limits<double>::epsilon());
+  SetZero(x_gpu);
+  EXPECT_NEAR(x_gpu.Norm(), 0.0, std::numeric_limits<double>::epsilon());
+}
+
+TEST(CudaVector, Resize) {
+  ContextImpl context;
+  std::string message;
+  CHECK(context.InitCuda(&message)) << "InitCuda() failed because: " << message;
+  CudaVector x_gpu(&context, 10);
+  EXPECT_EQ(x_gpu.num_rows(), 10);
+  x_gpu.Resize(4);
+  EXPECT_EQ(x_gpu.num_rows(), 4);
+}
+
+TEST(CudaVector, Axpy) {
+  Vector x(4);
+  Vector y(4);
+  x << 1, 1, 1, 1;
+  y << 100, 10, 1, 0;
+  ContextImpl context;
+  std::string message;
+  CHECK(context.InitCuda(&message)) << "InitCuda() failed because: " << message;
+  CudaVector x_gpu(&context, 4);
+  CudaVector y_gpu(&context, 4);
+  x_gpu.CopyFromCpu(x);
+  y_gpu.CopyFromCpu(y);
+
+  x_gpu.Axpby(2.0, y_gpu, 1.0);
+  Vector result;
+  Vector expected(4);
+  expected << 201, 21, 3, 1;
+  x_gpu.CopyTo(&result);
+  EXPECT_EQ(result, expected);
+}
+
+TEST(CudaVector, AxpbyBEquals1) {
+  Vector x(4);
+  Vector y(4);
+  x << 1, 1, 1, 1;
+  y << 100, 10, 1, 0;
+  ContextImpl context;
+  std::string message;
+  CHECK(context.InitCuda(&message)) << "InitCuda() failed because: " << message;
+  CudaVector x_gpu(&context, 4);
+  CudaVector y_gpu(&context, 4);
+  x_gpu.CopyFromCpu(x);
+  y_gpu.CopyFromCpu(y);
+
+  x_gpu.Axpby(2.0, y_gpu, 1.0);
+  Vector result;
+  Vector expected(4);
+  expected << 201, 21, 3, 1;
+  x_gpu.CopyTo(&result);
+  EXPECT_EQ(result, expected);
+}
+
+TEST(CudaVector, AxpbyMemberFunctionBNotEqual1) {
+  Vector x(4);
+  Vector y(4);
+  x << 1, 1, 1, 1;
+  y << 100, 10, 1, 0;
+  ContextImpl context;
+  std::string message;
+  CHECK(context.InitCuda(&message)) << "InitCuda() failed because: " << message;
+  CudaVector x_gpu(&context, 4);
+  CudaVector y_gpu(&context, 4);
+  x_gpu.CopyFromCpu(x);
+  y_gpu.CopyFromCpu(y);
+
+  x_gpu.Axpby(2.0, y_gpu, 3.0);
+  Vector result;
+  Vector expected(4);
+  expected << 203, 23, 5, 3;
+  x_gpu.CopyTo(&result);
+  EXPECT_EQ(result, expected);
+}
+
+TEST(CudaVector, AxpbyMemberFunctionBEqual1) {
+  Vector x(4);
+  Vector y(4);
+  x << 1, 1, 1, 1;
+  y << 100, 10, 1, 0;
+  ContextImpl context;
+  std::string message;
+  CHECK(context.InitCuda(&message)) << "InitCuda() failed because: " << message;
+  CudaVector x_gpu(&context, 4);
+  CudaVector y_gpu(&context, 4);
+  x_gpu.CopyFromCpu(x);
+  y_gpu.CopyFromCpu(y);
+
+  x_gpu.Axpby(2.0, y_gpu, 1.0);
+  Vector result;
+  Vector expected(4);
+  expected << 201, 21, 3, 1;
+  x_gpu.CopyTo(&result);
+  EXPECT_EQ(result, expected);
+}
+
+TEST(CudaVector, AxpbyMemberXAliasesY) {
+  Vector x(4);
+  x << 100, 10, 1, 0;
+  ContextImpl context;
+  std::string message;
+  CHECK(context.InitCuda(&message)) << "InitCuda() failed because: " << message;
+  CudaVector x_gpu(&context, 4);
+  CudaVector y_gpu(&context, 4);
+  x_gpu.CopyFromCpu(x);
+  y_gpu.SetZero();
+
+  x_gpu.Axpby(2.0, x_gpu, 1.0);
+  Vector result;
+  Vector expected(4);
+  expected << 300, 30, 3, 0;
+  x_gpu.CopyTo(&result);
+  EXPECT_EQ(result, expected);
+}
+
+TEST(CudaVector, AxpbyNonMemberMethodNoAliases) {
+  Vector x(4);
+  Vector y(4);
+  x << 1, 1, 1, 1;
+  y << 100, 10, 1, 0;
+  ContextImpl context;
+  std::string message;
+  CHECK(context.InitCuda(&message)) << "InitCuda() failed because: " << message;
+  CudaVector x_gpu(&context, 4);
+  CudaVector y_gpu(&context, 4);
+  CudaVector z_gpu(&context, 4);
+  x_gpu.CopyFromCpu(x);
+  y_gpu.CopyFromCpu(y);
+  z_gpu.Resize(4);
+  z_gpu.SetZero();
+
+  Axpby(2.0, x_gpu, 3.0, y_gpu, z_gpu);
+  Vector result;
+  Vector expected(4);
+  expected << 302, 32, 5, 2;
+  z_gpu.CopyTo(&result);
+  EXPECT_EQ(result, expected);
+}
+
+TEST(CudaVector, AxpbyNonMemberMethodXAliasesY) {
+  Vector x(4);
+  x << 100, 10, 1, 0;
+  ContextImpl context;
+  std::string message;
+  CHECK(context.InitCuda(&message)) << "InitCuda() failed because: " << message;
+  CudaVector x_gpu(&context, 4);
+  CudaVector z_gpu(&context, 4);
+  x_gpu.CopyFromCpu(x);
+  z_gpu.SetZero();
+
+  Axpby(2.0, x_gpu, 3.0, x_gpu, z_gpu);
+  Vector result;
+  Vector expected(4);
+  expected << 500, 50, 5, 0;
+  z_gpu.CopyTo(&result);
+  EXPECT_EQ(result, expected);
+}
+
+TEST(CudaVector, AxpbyNonMemberMethodXAliasesZ) {
+  Vector x(4);
+  Vector y(4);
+  x << 1, 1, 1, 1;
+  y << 100, 10, 1, 0;
+  ContextImpl context;
+  std::string message;
+  CHECK(context.InitCuda(&message)) << "InitCuda() failed because: " << message;
+  CudaVector x_gpu(&context, 10);
+  CudaVector y_gpu(&context, 10);
+  x_gpu.CopyFromCpu(x);
+  y_gpu.CopyFromCpu(y);
+
+  Axpby(2.0, x_gpu, 3.0, y_gpu, x_gpu);
+  Vector result;
+  Vector expected(4);
+  expected << 302, 32, 5, 2;
+  x_gpu.CopyTo(&result);
+  EXPECT_EQ(result, expected);
+}
+
+TEST(CudaVector, AxpbyNonMemberMethodYAliasesZ) {
+  Vector x(4);
+  Vector y(4);
+  x << 1, 1, 1, 1;
+  y << 100, 10, 1, 0;
+  ContextImpl context;
+  std::string message;
+  CHECK(context.InitCuda(&message)) << "InitCuda() failed because: " << message;
+  CudaVector x_gpu(&context, 4);
+  CudaVector y_gpu(&context, 4);
+  x_gpu.CopyFromCpu(x);
+  y_gpu.CopyFromCpu(y);
+
+  Axpby(2.0, x_gpu, 3.0, y_gpu, y_gpu);
+  Vector result;
+  Vector expected(4);
+  expected << 302, 32, 5, 2;
+  y_gpu.CopyTo(&result);
+  EXPECT_EQ(result, expected);
+}
+
+TEST(CudaVector, AxpbyNonMemberMethodXAliasesYAliasesZ) {
+  Vector x(4);
+  x << 100, 10, 1, 0;
+  ContextImpl context;
+  std::string message;
+  CHECK(context.InitCuda(&message)) << "InitCuda() failed because: " << message;
+  CudaVector x_gpu(&context, 10);
+  x_gpu.CopyFromCpu(x);
+
+  Axpby(2.0, x_gpu, 3.0, x_gpu, x_gpu);
+  Vector result;
+  Vector expected(4);
+  expected << 500, 50, 5, 0;
+  x_gpu.CopyTo(&result);
+  EXPECT_EQ(result, expected);
+}
+
+TEST(CudaVector, DtDxpy) {
+  Vector x(4);
+  Vector y(4);
+  Vector D(4);
+  x << 1, 2, 3, 4;
+  y << 100, 10, 1, 0;
+  D << 4, 3, 2, 1;
+  ContextImpl context;
+  std::string message;
+  CHECK(context.InitCuda(&message)) << "InitCuda() failed because: " << message;
+  CudaVector x_gpu(&context, 4);
+  CudaVector y_gpu(&context, 4);
+  CudaVector D_gpu(&context, 4);
+  x_gpu.CopyFromCpu(x);
+  y_gpu.CopyFromCpu(y);
+  D_gpu.CopyFromCpu(D);
+
+  y_gpu.DtDxpy(D_gpu, x_gpu);
+  Vector result;
+  Vector expected(4);
+  expected << 116, 28, 13, 4;
+  y_gpu.CopyTo(&result);
+  EXPECT_EQ(result, expected);
+}
+
+TEST(CudaVector, Scale) {
+  Vector x(4);
+  x << 1, 2, 3, 4;
+  ContextImpl context;
+  std::string message;
+  CHECK(context.InitCuda(&message)) << "InitCuda() failed because: " << message;
+  CudaVector x_gpu(&context, 4);
+  x_gpu.CopyFromCpu(x);
+
+  x_gpu.Scale(-3.0);
+
+  Vector result;
+  Vector expected(4);
+  expected << -3.0, -6.0, -9.0, -12.0;
+  x_gpu.CopyTo(&result);
+  EXPECT_EQ(result, expected);
+}
+
+#endif  // CERES_NO_CUDA
+
+}  // namespace internal
+}  // namespace ceres
diff --git a/third_party/ceres/internal/ceres/cxsparse.cc b/third_party/ceres/internal/ceres/cxsparse.cc
deleted file mode 100644
index 0167f98..0000000
--- a/third_party/ceres/internal/ceres/cxsparse.cc
+++ /dev/null
@@ -1,283 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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 Google Inc. 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.
-//
-// Author: strandmark@google.com (Petter Strandmark)
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_NO_CXSPARSE
-
-#include <string>
-#include <vector>
-
-#include "ceres/compressed_col_sparse_matrix_utils.h"
-#include "ceres/compressed_row_sparse_matrix.h"
-#include "ceres/cxsparse.h"
-#include "ceres/triplet_sparse_matrix.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-using std::vector;
-
-CXSparse::CXSparse() : scratch_(NULL), scratch_size_(0) {}
-
-CXSparse::~CXSparse() {
-  if (scratch_size_ > 0) {
-    cs_di_free(scratch_);
-  }
-}
-
-csn* CXSparse::Cholesky(cs_di* A, cs_dis* symbolic_factor) {
-  return cs_di_chol(A, symbolic_factor);
-}
-
-void CXSparse::Solve(cs_dis* symbolic_factor, csn* numeric_factor, double* b) {
-  // Make sure we have enough scratch space available.
-  const int num_cols = numeric_factor->L->n;
-  if (scratch_size_ < num_cols) {
-    if (scratch_size_ > 0) {
-      cs_di_free(scratch_);
-    }
-    scratch_ =
-        reinterpret_cast<CS_ENTRY*>(cs_di_malloc(num_cols, sizeof(CS_ENTRY)));
-    scratch_size_ = num_cols;
-  }
-
-  // When the Cholesky factor succeeded, these methods are
-  // guaranteed to succeeded as well. In the comments below, "x"
-  // refers to the scratch space.
-  //
-  // Set x = P * b.
-  CHECK(cs_di_ipvec(symbolic_factor->pinv, b, scratch_, num_cols));
-  // Set x = L \ x.
-  CHECK(cs_di_lsolve(numeric_factor->L, scratch_));
-  // Set x = L' \ x.
-  CHECK(cs_di_ltsolve(numeric_factor->L, scratch_));
-  // Set b = P' * x.
-  CHECK(cs_di_pvec(symbolic_factor->pinv, scratch_, b, num_cols));
-}
-
-bool CXSparse::SolveCholesky(cs_di* lhs, double* rhs_and_solution) {
-  return cs_cholsol(1, lhs, rhs_and_solution);
-}
-
-cs_dis* CXSparse::AnalyzeCholesky(cs_di* A) {
-  // order = 1 for Cholesky factor.
-  return cs_schol(1, A);
-}
-
-cs_dis* CXSparse::AnalyzeCholeskyWithNaturalOrdering(cs_di* A) {
-  // order = 0 for Natural ordering.
-  return cs_schol(0, A);
-}
-
-cs_dis* CXSparse::BlockAnalyzeCholesky(cs_di* A,
-                                       const vector<int>& row_blocks,
-                                       const vector<int>& col_blocks) {
-  const int num_row_blocks = row_blocks.size();
-  const int num_col_blocks = col_blocks.size();
-
-  vector<int> block_rows;
-  vector<int> block_cols;
-  CompressedColumnScalarMatrixToBlockMatrix(
-      A->i, A->p, row_blocks, col_blocks, &block_rows, &block_cols);
-  cs_di block_matrix;
-  block_matrix.m = num_row_blocks;
-  block_matrix.n = num_col_blocks;
-  block_matrix.nz = -1;
-  block_matrix.nzmax = block_rows.size();
-  block_matrix.p = &block_cols[0];
-  block_matrix.i = &block_rows[0];
-  block_matrix.x = NULL;
-
-  int* ordering = cs_amd(1, &block_matrix);
-  vector<int> block_ordering(num_row_blocks, -1);
-  std::copy(ordering, ordering + num_row_blocks, &block_ordering[0]);
-  cs_free(ordering);
-
-  vector<int> scalar_ordering;
-  BlockOrderingToScalarOrdering(row_blocks, block_ordering, &scalar_ordering);
-
-  cs_dis* symbolic_factor =
-      reinterpret_cast<cs_dis*>(cs_calloc(1, sizeof(cs_dis)));
-  symbolic_factor->pinv = cs_pinv(&scalar_ordering[0], A->n);
-  cs* permuted_A = cs_symperm(A, symbolic_factor->pinv, 0);
-
-  symbolic_factor->parent = cs_etree(permuted_A, 0);
-  int* postordering = cs_post(symbolic_factor->parent, A->n);
-  int* column_counts =
-      cs_counts(permuted_A, symbolic_factor->parent, postordering, 0);
-  cs_free(postordering);
-  cs_spfree(permuted_A);
-
-  symbolic_factor->cp = (int*)cs_malloc(A->n + 1, sizeof(int));
-  symbolic_factor->lnz = cs_cumsum(symbolic_factor->cp, column_counts, A->n);
-  symbolic_factor->unz = symbolic_factor->lnz;
-
-  cs_free(column_counts);
-
-  if (symbolic_factor->lnz < 0) {
-    cs_sfree(symbolic_factor);
-    symbolic_factor = NULL;
-  }
-
-  return symbolic_factor;
-}
-
-cs_di CXSparse::CreateSparseMatrixTransposeView(CompressedRowSparseMatrix* A) {
-  cs_di At;
-  At.m = A->num_cols();
-  At.n = A->num_rows();
-  At.nz = -1;
-  At.nzmax = A->num_nonzeros();
-  At.p = A->mutable_rows();
-  At.i = A->mutable_cols();
-  At.x = A->mutable_values();
-  return At;
-}
-
-cs_di* CXSparse::CreateSparseMatrix(TripletSparseMatrix* tsm) {
-  cs_di_sparse tsm_wrapper;
-  tsm_wrapper.nzmax = tsm->num_nonzeros();
-  tsm_wrapper.nz = tsm->num_nonzeros();
-  tsm_wrapper.m = tsm->num_rows();
-  tsm_wrapper.n = tsm->num_cols();
-  tsm_wrapper.p = tsm->mutable_cols();
-  tsm_wrapper.i = tsm->mutable_rows();
-  tsm_wrapper.x = tsm->mutable_values();
-
-  return cs_compress(&tsm_wrapper);
-}
-
-void CXSparse::ApproximateMinimumDegreeOrdering(cs_di* A, int* ordering) {
-  int* cs_ordering = cs_amd(1, A);
-  std::copy(cs_ordering, cs_ordering + A->m, ordering);
-  cs_free(cs_ordering);
-}
-
-cs_di* CXSparse::TransposeMatrix(cs_di* A) { return cs_di_transpose(A, 1); }
-
-cs_di* CXSparse::MatrixMatrixMultiply(cs_di* A, cs_di* B) {
-  return cs_di_multiply(A, B);
-}
-
-void CXSparse::Free(cs_di* sparse_matrix) { cs_di_spfree(sparse_matrix); }
-
-void CXSparse::Free(cs_dis* symbolic_factor) { cs_di_sfree(symbolic_factor); }
-
-void CXSparse::Free(csn* numeric_factor) { cs_di_nfree(numeric_factor); }
-
-std::unique_ptr<SparseCholesky> CXSparseCholesky::Create(
-    const OrderingType ordering_type) {
-  return std::unique_ptr<SparseCholesky>(new CXSparseCholesky(ordering_type));
-}
-
-CompressedRowSparseMatrix::StorageType CXSparseCholesky::StorageType() const {
-  return CompressedRowSparseMatrix::LOWER_TRIANGULAR;
-}
-
-CXSparseCholesky::CXSparseCholesky(const OrderingType ordering_type)
-    : ordering_type_(ordering_type),
-      symbolic_factor_(NULL),
-      numeric_factor_(NULL) {}
-
-CXSparseCholesky::~CXSparseCholesky() {
-  FreeSymbolicFactorization();
-  FreeNumericFactorization();
-}
-
-LinearSolverTerminationType CXSparseCholesky::Factorize(
-    CompressedRowSparseMatrix* lhs, std::string* message) {
-  CHECK_EQ(lhs->storage_type(), StorageType());
-  if (lhs == NULL) {
-    *message = "Failure: Input lhs is NULL.";
-    return LINEAR_SOLVER_FATAL_ERROR;
-  }
-
-  cs_di cs_lhs = cs_.CreateSparseMatrixTransposeView(lhs);
-
-  if (symbolic_factor_ == NULL) {
-    if (ordering_type_ == NATURAL) {
-      symbolic_factor_ = cs_.AnalyzeCholeskyWithNaturalOrdering(&cs_lhs);
-    } else {
-      if (!lhs->col_blocks().empty() && !(lhs->row_blocks().empty())) {
-        symbolic_factor_ = cs_.BlockAnalyzeCholesky(
-            &cs_lhs, lhs->col_blocks(), lhs->row_blocks());
-      } else {
-        symbolic_factor_ = cs_.AnalyzeCholesky(&cs_lhs);
-      }
-    }
-
-    if (symbolic_factor_ == NULL) {
-      *message = "CXSparse Failure : Symbolic factorization failed.";
-      return LINEAR_SOLVER_FATAL_ERROR;
-    }
-  }
-
-  FreeNumericFactorization();
-  numeric_factor_ = cs_.Cholesky(&cs_lhs, symbolic_factor_);
-  if (numeric_factor_ == NULL) {
-    *message = "CXSparse Failure : Numeric factorization failed.";
-    return LINEAR_SOLVER_FAILURE;
-  }
-
-  return LINEAR_SOLVER_SUCCESS;
-}
-
-LinearSolverTerminationType CXSparseCholesky::Solve(const double* rhs,
-                                                    double* solution,
-                                                    std::string* message) {
-  CHECK(numeric_factor_ != NULL)
-      << "Solve called without a call to Factorize first.";
-  const int num_cols = numeric_factor_->L->n;
-  memcpy(solution, rhs, num_cols * sizeof(*solution));
-  cs_.Solve(symbolic_factor_, numeric_factor_, solution);
-  return LINEAR_SOLVER_SUCCESS;
-}
-
-void CXSparseCholesky::FreeSymbolicFactorization() {
-  if (symbolic_factor_ != NULL) {
-    cs_.Free(symbolic_factor_);
-    symbolic_factor_ = NULL;
-  }
-}
-
-void CXSparseCholesky::FreeNumericFactorization() {
-  if (numeric_factor_ != NULL) {
-    cs_.Free(numeric_factor_);
-    numeric_factor_ = NULL;
-  }
-}
-
-}  // namespace internal
-}  // namespace ceres
-
-#endif  // CERES_NO_CXSPARSE
diff --git a/third_party/ceres/internal/ceres/cxsparse.h b/third_party/ceres/internal/ceres/cxsparse.h
deleted file mode 100644
index d3f76e0..0000000
--- a/third_party/ceres/internal/ceres/cxsparse.h
+++ /dev/null
@@ -1,179 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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 Google Inc. 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.
-//
-// Author: strandmark@google.com (Petter Strandmark)
-
-#ifndef CERES_INTERNAL_CXSPARSE_H_
-#define CERES_INTERNAL_CXSPARSE_H_
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifndef CERES_NO_CXSPARSE
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "ceres/linear_solver.h"
-#include "ceres/sparse_cholesky.h"
-#include "cs.h"
-
-namespace ceres {
-namespace internal {
-
-class CompressedRowSparseMatrix;
-class TripletSparseMatrix;
-
-// This object provides access to solving linear systems using Cholesky
-// factorization with a known symbolic factorization. This features does not
-// explicitly exist in CXSparse. The methods in the class are nonstatic because
-// the class manages internal scratch space.
-class CXSparse {
- public:
-  CXSparse();
-  ~CXSparse();
-
-  // Solve the system lhs * solution = rhs in place by using an
-  // approximate minimum degree fill reducing ordering.
-  bool SolveCholesky(cs_di* lhs, double* rhs_and_solution);
-
-  // Solves a linear system given its symbolic and numeric factorization.
-  void Solve(cs_dis* symbolic_factor,
-             csn* numeric_factor,
-             double* rhs_and_solution);
-
-  // Compute the numeric Cholesky factorization of A, given its
-  // symbolic factorization.
-  //
-  // Caller owns the result.
-  csn* Cholesky(cs_di* A, cs_dis* symbolic_factor);
-
-  // Creates a sparse matrix from a compressed-column form. No memory is
-  // allocated or copied; the structure A is filled out with info from the
-  // argument.
-  cs_di CreateSparseMatrixTransposeView(CompressedRowSparseMatrix* A);
-
-  // Creates a new matrix from a triplet form. Deallocate the returned matrix
-  // with Free. May return NULL if the compression or allocation fails.
-  cs_di* CreateSparseMatrix(TripletSparseMatrix* A);
-
-  // B = A'
-  //
-  // The returned matrix should be deallocated with Free when not used
-  // anymore.
-  cs_di* TransposeMatrix(cs_di* A);
-
-  // C = A * B
-  //
-  // The returned matrix should be deallocated with Free when not used
-  // anymore.
-  cs_di* MatrixMatrixMultiply(cs_di* A, cs_di* B);
-
-  // Computes a symbolic factorization of A that can be used in SolveCholesky.
-  //
-  // The returned matrix should be deallocated with Free when not used anymore.
-  cs_dis* AnalyzeCholesky(cs_di* A);
-
-  // Computes a symbolic factorization of A that can be used in
-  // SolveCholesky, but does not compute a fill-reducing ordering.
-  //
-  // The returned matrix should be deallocated with Free when not used anymore.
-  cs_dis* AnalyzeCholeskyWithNaturalOrdering(cs_di* A);
-
-  // Computes a symbolic factorization of A that can be used in
-  // SolveCholesky. The difference from AnalyzeCholesky is that this
-  // function first detects the block sparsity of the matrix using
-  // information about the row and column blocks and uses this block
-  // sparse matrix to find a fill-reducing ordering. This ordering is
-  // then used to find a symbolic factorization. This can result in a
-  // significant performance improvement AnalyzeCholesky on block
-  // sparse matrices.
-  //
-  // The returned matrix should be deallocated with Free when not used
-  // anymore.
-  cs_dis* BlockAnalyzeCholesky(cs_di* A,
-                               const std::vector<int>& row_blocks,
-                               const std::vector<int>& col_blocks);
-
-  // Compute an fill-reducing approximate minimum degree ordering of
-  // the matrix A. ordering should be non-NULL and should point to
-  // enough memory to hold the ordering for the rows of A.
-  void ApproximateMinimumDegreeOrdering(cs_di* A, int* ordering);
-
-  void Free(cs_di* sparse_matrix);
-  void Free(cs_dis* symbolic_factorization);
-  void Free(csn* numeric_factorization);
-
- private:
-  // Cached scratch space
-  CS_ENTRY* scratch_;
-  int scratch_size_;
-};
-
-// An implementation of SparseCholesky interface using the CXSparse
-// library.
-class CXSparseCholesky : public SparseCholesky {
- public:
-  // Factory
-  static std::unique_ptr<SparseCholesky> Create(OrderingType ordering_type);
-
-  // SparseCholesky interface.
-  virtual ~CXSparseCholesky();
-  CompressedRowSparseMatrix::StorageType StorageType() const final;
-  LinearSolverTerminationType Factorize(CompressedRowSparseMatrix* lhs,
-                                        std::string* message) final;
-  LinearSolverTerminationType Solve(const double* rhs,
-                                    double* solution,
-                                    std::string* message) final;
-
- private:
-  CXSparseCholesky(const OrderingType ordering_type);
-  void FreeSymbolicFactorization();
-  void FreeNumericFactorization();
-
-  const OrderingType ordering_type_;
-  CXSparse cs_;
-  cs_dis* symbolic_factor_;
-  csn* numeric_factor_;
-};
-
-}  // namespace internal
-}  // namespace ceres
-
-#else
-
-typedef void cs_dis;
-
-class CXSparse {
- public:
-  void Free(void* arg) {}
-};
-#endif  // CERES_NO_CXSPARSE
-
-#endif  // CERES_INTERNAL_CXSPARSE_H_
diff --git a/third_party/ceres/internal/ceres/dense_cholesky.cc b/third_party/ceres/internal/ceres/dense_cholesky.cc
new file mode 100644
index 0000000..5a3e7e2
--- /dev/null
+++ b/third_party/ceres/internal/ceres/dense_cholesky.cc
@@ -0,0 +1,645 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/dense_cholesky.h"
+
+#include <algorithm>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "ceres/internal/config.h"
+#include "ceres/iterative_refiner.h"
+
+#ifndef CERES_NO_CUDA
+#include "ceres/context_impl.h"
+#include "ceres/cuda_kernels_vector_ops.h"
+#include "cuda_runtime.h"
+#include "cusolverDn.h"
+#endif  // CERES_NO_CUDA
+
+#ifndef CERES_NO_LAPACK
+
+// C interface to the LAPACK Cholesky factorization and triangular solve.
+extern "C" void dpotrf_(
+    const char* uplo, const int* n, double* a, const int* lda, int* info);
+
+extern "C" void dpotrs_(const char* uplo,
+                        const int* n,
+                        const int* nrhs,
+                        const double* a,
+                        const int* lda,
+                        double* b,
+                        const int* ldb,
+                        int* info);
+
+extern "C" void spotrf_(
+    const char* uplo, const int* n, float* a, const int* lda, int* info);
+
+extern "C" void spotrs_(const char* uplo,
+                        const int* n,
+                        const int* nrhs,
+                        const float* a,
+                        const int* lda,
+                        float* b,
+                        const int* ldb,
+                        int* info);
+#endif
+
+namespace ceres::internal {
+
+DenseCholesky::~DenseCholesky() = default;
+
+std::unique_ptr<DenseCholesky> DenseCholesky::Create(
+    const LinearSolver::Options& options) {
+  std::unique_ptr<DenseCholesky> dense_cholesky;
+
+  switch (options.dense_linear_algebra_library_type) {
+    case EIGEN:
+      // Eigen mixed precision solver not yet implemented.
+      if (options.use_mixed_precision_solves) {
+        dense_cholesky = std::make_unique<FloatEigenDenseCholesky>();
+      } else {
+        dense_cholesky = std::make_unique<EigenDenseCholesky>();
+      }
+      break;
+
+    case LAPACK:
+#ifndef CERES_NO_LAPACK
+      // LAPACK mixed precision solver not yet implemented.
+      if (options.use_mixed_precision_solves) {
+        dense_cholesky = std::make_unique<FloatLAPACKDenseCholesky>();
+      } else {
+        dense_cholesky = std::make_unique<LAPACKDenseCholesky>();
+      }
+      break;
+#else
+      LOG(FATAL) << "Ceres was compiled without support for LAPACK.";
+#endif
+
+    case CUDA:
+#ifndef CERES_NO_CUDA
+      if (options.use_mixed_precision_solves) {
+        dense_cholesky = CUDADenseCholeskyMixedPrecision::Create(options);
+      } else {
+        dense_cholesky = CUDADenseCholesky::Create(options);
+      }
+      break;
+#else
+      LOG(FATAL) << "Ceres was compiled without support for CUDA.";
+#endif
+
+    default:
+      LOG(FATAL) << "Unknown dense linear algebra library type : "
+                 << DenseLinearAlgebraLibraryTypeToString(
+                        options.dense_linear_algebra_library_type);
+  }
+
+  if (options.max_num_refinement_iterations > 0) {
+    auto refiner = std::make_unique<DenseIterativeRefiner>(
+        options.max_num_refinement_iterations);
+    dense_cholesky = std::make_unique<RefinedDenseCholesky>(
+        std::move(dense_cholesky), std::move(refiner));
+  }
+
+  return dense_cholesky;
+}
+
+LinearSolverTerminationType DenseCholesky::FactorAndSolve(
+    int num_cols,
+    double* lhs,
+    const double* rhs,
+    double* solution,
+    std::string* message) {
+  LinearSolverTerminationType termination_type =
+      Factorize(num_cols, lhs, message);
+  if (termination_type == LinearSolverTerminationType::SUCCESS) {
+    termination_type = Solve(rhs, solution, message);
+  }
+  return termination_type;
+}
+
+LinearSolverTerminationType EigenDenseCholesky::Factorize(
+    int num_cols, double* lhs, std::string* message) {
+  Eigen::Map<Eigen::MatrixXd> m(lhs, num_cols, num_cols);
+  llt_ = std::make_unique<LLTType>(m);
+  if (llt_->info() != Eigen::Success) {
+    *message = "Eigen failure. Unable to perform dense Cholesky factorization.";
+    return LinearSolverTerminationType::FAILURE;
+  }
+
+  *message = "Success.";
+  return LinearSolverTerminationType::SUCCESS;
+}
+
+LinearSolverTerminationType EigenDenseCholesky::Solve(const double* rhs,
+                                                      double* solution,
+                                                      std::string* message) {
+  if (llt_->info() != Eigen::Success) {
+    *message = "Eigen failure. Unable to perform dense Cholesky factorization.";
+    return LinearSolverTerminationType::FAILURE;
+  }
+
+  VectorRef(solution, llt_->cols()) =
+      llt_->solve(ConstVectorRef(rhs, llt_->cols()));
+  *message = "Success.";
+  return LinearSolverTerminationType::SUCCESS;
+}
+
+LinearSolverTerminationType FloatEigenDenseCholesky::Factorize(
+    int num_cols, double* lhs, std::string* message) {
+  // TODO(sameeragarwal): Check if this causes a double allocation.
+  lhs_ = Eigen::Map<Eigen::MatrixXd>(lhs, num_cols, num_cols).cast<float>();
+  llt_ = std::make_unique<LLTType>(lhs_);
+  if (llt_->info() != Eigen::Success) {
+    *message = "Eigen failure. Unable to perform dense Cholesky factorization.";
+    return LinearSolverTerminationType::FAILURE;
+  }
+
+  *message = "Success.";
+  return LinearSolverTerminationType::SUCCESS;
+}
+
+LinearSolverTerminationType FloatEigenDenseCholesky::Solve(
+    const double* rhs, double* solution, std::string* message) {
+  if (llt_->info() != Eigen::Success) {
+    *message = "Eigen failure. Unable to perform dense Cholesky factorization.";
+    return LinearSolverTerminationType::FAILURE;
+  }
+
+  rhs_ = ConstVectorRef(rhs, llt_->cols()).cast<float>();
+  solution_ = llt_->solve(rhs_);
+  VectorRef(solution, llt_->cols()) = solution_.cast<double>();
+  *message = "Success.";
+  return LinearSolverTerminationType::SUCCESS;
+}
+
+#ifndef CERES_NO_LAPACK
+LinearSolverTerminationType LAPACKDenseCholesky::Factorize(
+    int num_cols, double* lhs, std::string* message) {
+  lhs_ = lhs;
+  num_cols_ = num_cols;
+
+  const char uplo = 'L';
+  int info = 0;
+  dpotrf_(&uplo, &num_cols_, lhs_, &num_cols_, &info);
+
+  if (info < 0) {
+    termination_type_ = LinearSolverTerminationType::FATAL_ERROR;
+    LOG(FATAL) << "Congratulations, you found a bug in Ceres. "
+               << "Please report it. "
+               << "LAPACK::dpotrf fatal error. "
+               << "Argument: " << -info << " is invalid.";
+  } else if (info > 0) {
+    termination_type_ = LinearSolverTerminationType::FAILURE;
+    *message = StringPrintf(
+        "LAPACK::dpotrf numerical failure. "
+        "The leading minor of order %d is not positive definite.",
+        info);
+  } else {
+    termination_type_ = LinearSolverTerminationType::SUCCESS;
+    *message = "Success.";
+  }
+  return termination_type_;
+}
+
+LinearSolverTerminationType LAPACKDenseCholesky::Solve(const double* rhs,
+                                                       double* solution,
+                                                       std::string* message) {
+  const char uplo = 'L';
+  const int nrhs = 1;
+  int info = 0;
+
+  VectorRef(solution, num_cols_) = ConstVectorRef(rhs, num_cols_);
+  dpotrs_(
+      &uplo, &num_cols_, &nrhs, lhs_, &num_cols_, solution, &num_cols_, &info);
+
+  if (info < 0) {
+    termination_type_ = LinearSolverTerminationType::FATAL_ERROR;
+    LOG(FATAL) << "Congratulations, you found a bug in Ceres. "
+               << "Please report it. "
+               << "LAPACK::dpotrs fatal error. "
+               << "Argument: " << -info << " is invalid.";
+  }
+
+  *message = "Success";
+  termination_type_ = LinearSolverTerminationType::SUCCESS;
+
+  return termination_type_;
+}
+
+LinearSolverTerminationType FloatLAPACKDenseCholesky::Factorize(
+    int num_cols, double* lhs, std::string* message) {
+  num_cols_ = num_cols;
+  lhs_ = Eigen::Map<Eigen::MatrixXd>(lhs, num_cols, num_cols).cast<float>();
+
+  const char uplo = 'L';
+  int info = 0;
+  spotrf_(&uplo, &num_cols_, lhs_.data(), &num_cols_, &info);
+
+  if (info < 0) {
+    termination_type_ = LinearSolverTerminationType::FATAL_ERROR;
+    LOG(FATAL) << "Congratulations, you found a bug in Ceres. "
+               << "Please report it. "
+               << "LAPACK::spotrf fatal error. "
+               << "Argument: " << -info << " is invalid.";
+  } else if (info > 0) {
+    termination_type_ = LinearSolverTerminationType::FAILURE;
+    *message = StringPrintf(
+        "LAPACK::spotrf numerical failure. "
+        "The leading minor of order %d is not positive definite.",
+        info);
+  } else {
+    termination_type_ = LinearSolverTerminationType::SUCCESS;
+    *message = "Success.";
+  }
+  return termination_type_;
+}
+
+LinearSolverTerminationType FloatLAPACKDenseCholesky::Solve(
+    const double* rhs, double* solution, std::string* message) {
+  const char uplo = 'L';
+  const int nrhs = 1;
+  int info = 0;
+  rhs_and_solution_ = ConstVectorRef(rhs, num_cols_).cast<float>();
+  spotrs_(&uplo,
+          &num_cols_,
+          &nrhs,
+          lhs_.data(),
+          &num_cols_,
+          rhs_and_solution_.data(),
+          &num_cols_,
+          &info);
+
+  if (info < 0) {
+    termination_type_ = LinearSolverTerminationType::FATAL_ERROR;
+    LOG(FATAL) << "Congratulations, you found a bug in Ceres. "
+               << "Please report it. "
+               << "LAPACK::dpotrs fatal error. "
+               << "Argument: " << -info << " is invalid.";
+  }
+
+  *message = "Success";
+  termination_type_ = LinearSolverTerminationType::SUCCESS;
+  VectorRef(solution, num_cols_) =
+      rhs_and_solution_.head(num_cols_).cast<double>();
+  return termination_type_;
+}
+
+#endif  // CERES_NO_LAPACK
+
+RefinedDenseCholesky::RefinedDenseCholesky(
+    std::unique_ptr<DenseCholesky> dense_cholesky,
+    std::unique_ptr<DenseIterativeRefiner> iterative_refiner)
+    : dense_cholesky_(std::move(dense_cholesky)),
+      iterative_refiner_(std::move(iterative_refiner)) {}
+
+RefinedDenseCholesky::~RefinedDenseCholesky() = default;
+
+LinearSolverTerminationType RefinedDenseCholesky::Factorize(
+    const int num_cols, double* lhs, std::string* message) {
+  lhs_ = lhs;
+  num_cols_ = num_cols;
+  return dense_cholesky_->Factorize(num_cols, lhs, message);
+}
+
+LinearSolverTerminationType RefinedDenseCholesky::Solve(const double* rhs,
+                                                        double* solution,
+                                                        std::string* message) {
+  CHECK(lhs_ != nullptr);
+  auto termination_type = dense_cholesky_->Solve(rhs, solution, message);
+  if (termination_type != LinearSolverTerminationType::SUCCESS) {
+    return termination_type;
+  }
+
+  iterative_refiner_->Refine(
+      num_cols_, lhs_, rhs, dense_cholesky_.get(), solution);
+  return LinearSolverTerminationType::SUCCESS;
+}
+
+#ifndef CERES_NO_CUDA
+
+CUDADenseCholesky::CUDADenseCholesky(ContextImpl* context)
+    : context_(context),
+      lhs_{context},
+      rhs_{context},
+      device_workspace_{context},
+      error_(context, 1) {}
+
+LinearSolverTerminationType CUDADenseCholesky::Factorize(int num_cols,
+                                                         double* lhs,
+                                                         std::string* message) {
+  factorize_result_ = LinearSolverTerminationType::FATAL_ERROR;
+  lhs_.Reserve(num_cols * num_cols);
+  num_cols_ = num_cols;
+  lhs_.CopyFromCpu(lhs, num_cols * num_cols);
+  int device_workspace_size = 0;
+  if (cusolverDnDpotrf_bufferSize(context_->cusolver_handle_,
+                                  CUBLAS_FILL_MODE_LOWER,
+                                  num_cols,
+                                  lhs_.data(),
+                                  num_cols,
+                                  &device_workspace_size) !=
+      CUSOLVER_STATUS_SUCCESS) {
+    *message = "cuSolverDN::cusolverDnDpotrf_bufferSize failed.";
+    return LinearSolverTerminationType::FATAL_ERROR;
+  }
+  device_workspace_.Reserve(device_workspace_size);
+  if (cusolverDnDpotrf(context_->cusolver_handle_,
+                       CUBLAS_FILL_MODE_LOWER,
+                       num_cols,
+                       lhs_.data(),
+                       num_cols,
+                       reinterpret_cast<double*>(device_workspace_.data()),
+                       device_workspace_.size(),
+                       error_.data()) != CUSOLVER_STATUS_SUCCESS) {
+    *message = "cuSolverDN::cusolverDnDpotrf failed.";
+    return LinearSolverTerminationType::FATAL_ERROR;
+  }
+  int error = 0;
+  error_.CopyToCpu(&error, 1);
+  if (error < 0) {
+    LOG(FATAL) << "Congratulations, you found a bug in Ceres - "
+               << "please report it. "
+               << "cuSolverDN::cusolverDnXpotrf fatal error. "
+               << "Argument: " << -error << " is invalid.";
+    // The following line is unreachable, but return failure just to be
+    // pedantic, since the compiler does not know that.
+    return LinearSolverTerminationType::FATAL_ERROR;
+  } else if (error > 0) {
+    *message = StringPrintf(
+        "cuSolverDN::cusolverDnDpotrf numerical failure. "
+        "The leading minor of order %d is not positive definite.",
+        error);
+    factorize_result_ = LinearSolverTerminationType::FAILURE;
+    return LinearSolverTerminationType::FAILURE;
+  }
+  *message = "Success";
+  factorize_result_ = LinearSolverTerminationType::SUCCESS;
+  return LinearSolverTerminationType::SUCCESS;
+}
+
+LinearSolverTerminationType CUDADenseCholesky::Solve(const double* rhs,
+                                                     double* solution,
+                                                     std::string* message) {
+  if (factorize_result_ != LinearSolverTerminationType::SUCCESS) {
+    *message = "Factorize did not complete successfully previously.";
+    return factorize_result_;
+  }
+  rhs_.CopyFromCpu(rhs, num_cols_);
+  if (cusolverDnDpotrs(context_->cusolver_handle_,
+                       CUBLAS_FILL_MODE_LOWER,
+                       num_cols_,
+                       1,
+                       lhs_.data(),
+                       num_cols_,
+                       rhs_.data(),
+                       num_cols_,
+                       error_.data()) != CUSOLVER_STATUS_SUCCESS) {
+    *message = "cuSolverDN::cusolverDnDpotrs failed.";
+    return LinearSolverTerminationType::FATAL_ERROR;
+  }
+  int error = 0;
+  error_.CopyToCpu(&error, 1);
+  if (error != 0) {
+    LOG(FATAL) << "Congratulations, you found a bug in Ceres. "
+               << "Please report it."
+               << "cuSolverDN::cusolverDnDpotrs fatal error. "
+               << "Argument: " << -error << " is invalid.";
+  }
+  rhs_.CopyToCpu(solution, num_cols_);
+  *message = "Success";
+  return LinearSolverTerminationType::SUCCESS;
+}
+
+std::unique_ptr<CUDADenseCholesky> CUDADenseCholesky::Create(
+    const LinearSolver::Options& options) {
+  if (options.dense_linear_algebra_library_type != CUDA ||
+      options.context == nullptr || !options.context->IsCudaInitialized()) {
+    return nullptr;
+  }
+  return std::unique_ptr<CUDADenseCholesky>(
+      new CUDADenseCholesky(options.context));
+}
+
+std::unique_ptr<CUDADenseCholeskyMixedPrecision>
+CUDADenseCholeskyMixedPrecision::Create(const LinearSolver::Options& options) {
+  if (options.dense_linear_algebra_library_type != CUDA ||
+      !options.use_mixed_precision_solves || options.context == nullptr ||
+      !options.context->IsCudaInitialized()) {
+    return nullptr;
+  }
+  return std::unique_ptr<CUDADenseCholeskyMixedPrecision>(
+      new CUDADenseCholeskyMixedPrecision(
+          options.context, options.max_num_refinement_iterations));
+}
+
+LinearSolverTerminationType
+CUDADenseCholeskyMixedPrecision::CudaCholeskyFactorize(std::string* message) {
+  int device_workspace_size = 0;
+  if (cusolverDnSpotrf_bufferSize(context_->cusolver_handle_,
+                                  CUBLAS_FILL_MODE_LOWER,
+                                  num_cols_,
+                                  lhs_fp32_.data(),
+                                  num_cols_,
+                                  &device_workspace_size) !=
+      CUSOLVER_STATUS_SUCCESS) {
+    *message = "cuSolverDN::cusolverDnSpotrf_bufferSize failed.";
+    return LinearSolverTerminationType::FATAL_ERROR;
+  }
+  device_workspace_.Reserve(device_workspace_size);
+  if (cusolverDnSpotrf(context_->cusolver_handle_,
+                       CUBLAS_FILL_MODE_LOWER,
+                       num_cols_,
+                       lhs_fp32_.data(),
+                       num_cols_,
+                       device_workspace_.data(),
+                       device_workspace_.size(),
+                       error_.data()) != CUSOLVER_STATUS_SUCCESS) {
+    *message = "cuSolverDN::cusolverDnSpotrf failed.";
+    return LinearSolverTerminationType::FATAL_ERROR;
+  }
+  int error = 0;
+  error_.CopyToCpu(&error, 1);
+  if (error < 0) {
+    LOG(FATAL) << "Congratulations, you found a bug in Ceres - "
+               << "please report it. "
+               << "cuSolverDN::cusolverDnSpotrf fatal error. "
+               << "Argument: " << -error << " is invalid.";
+    // The following line is unreachable, but return failure just to be
+    // pedantic, since the compiler does not know that.
+    return LinearSolverTerminationType::FATAL_ERROR;
+  }
+  if (error > 0) {
+    *message = StringPrintf(
+        "cuSolverDN::cusolverDnSpotrf numerical failure. "
+        "The leading minor of order %d is not positive definite.",
+        error);
+    factorize_result_ = LinearSolverTerminationType::FAILURE;
+    return LinearSolverTerminationType::FAILURE;
+  }
+  *message = "Success";
+  return LinearSolverTerminationType::SUCCESS;
+}
+
+LinearSolverTerminationType CUDADenseCholeskyMixedPrecision::CudaCholeskySolve(
+    std::string* message) {
+  CHECK_EQ(cudaMemcpyAsync(correction_fp32_.data(),
+                           residual_fp32_.data(),
+                           num_cols_ * sizeof(float),
+                           cudaMemcpyDeviceToDevice,
+                           context_->DefaultStream()),
+           cudaSuccess);
+  if (cusolverDnSpotrs(context_->cusolver_handle_,
+                       CUBLAS_FILL_MODE_LOWER,
+                       num_cols_,
+                       1,
+                       lhs_fp32_.data(),
+                       num_cols_,
+                       correction_fp32_.data(),
+                       num_cols_,
+                       error_.data()) != CUSOLVER_STATUS_SUCCESS) {
+    *message = "cuSolverDN::cusolverDnDpotrs failed.";
+    return LinearSolverTerminationType::FATAL_ERROR;
+  }
+  int error = 0;
+  error_.CopyToCpu(&error, 1);
+  if (error != 0) {
+    LOG(FATAL) << "Congratulations, you found a bug in Ceres. "
+               << "Please report it."
+               << "cuSolverDN::cusolverDnDpotrs fatal error. "
+               << "Argument: " << -error << " is invalid.";
+  }
+  *message = "Success";
+  return LinearSolverTerminationType::SUCCESS;
+}
+
+CUDADenseCholeskyMixedPrecision::CUDADenseCholeskyMixedPrecision(
+    ContextImpl* context, int max_num_refinement_iterations)
+    : context_(context),
+      lhs_fp64_{context},
+      rhs_fp64_{context},
+      lhs_fp32_{context},
+      device_workspace_{context},
+      error_(context, 1),
+      x_fp64_{context},
+      correction_fp32_{context},
+      residual_fp32_{context},
+      residual_fp64_{context},
+      max_num_refinement_iterations_(max_num_refinement_iterations) {}
+
+LinearSolverTerminationType CUDADenseCholeskyMixedPrecision::Factorize(
+    int num_cols, double* lhs, std::string* message) {
+  num_cols_ = num_cols;
+
+  // Copy fp64 version of lhs to GPU.
+  lhs_fp64_.Reserve(num_cols * num_cols);
+  lhs_fp64_.CopyFromCpu(lhs, num_cols * num_cols);
+
+  // Create an fp32 copy of lhs, lhs_fp32.
+  lhs_fp32_.Reserve(num_cols * num_cols);
+  CudaFP64ToFP32(lhs_fp64_.data(),
+                 lhs_fp32_.data(),
+                 num_cols * num_cols,
+                 context_->DefaultStream());
+
+  // Factorize lhs_fp32.
+  factorize_result_ = CudaCholeskyFactorize(message);
+  return factorize_result_;
+}
+
+LinearSolverTerminationType CUDADenseCholeskyMixedPrecision::Solve(
+    const double* rhs, double* solution, std::string* message) {
+  // If factorization failed, return failure.
+  if (factorize_result_ != LinearSolverTerminationType::SUCCESS) {
+    *message = "Factorize did not complete successfully previously.";
+    return factorize_result_;
+  }
+
+  // Reserve memory for all arrays.
+  rhs_fp64_.Reserve(num_cols_);
+  x_fp64_.Reserve(num_cols_);
+  correction_fp32_.Reserve(num_cols_);
+  residual_fp32_.Reserve(num_cols_);
+  residual_fp64_.Reserve(num_cols_);
+
+  // Initialize x = 0.
+  CudaSetZeroFP64(x_fp64_.data(), num_cols_, context_->DefaultStream());
+
+  // Initialize residual = rhs.
+  rhs_fp64_.CopyFromCpu(rhs, num_cols_);
+  residual_fp64_.CopyFromGPUArray(rhs_fp64_.data(), num_cols_);
+
+  for (int i = 0; i <= max_num_refinement_iterations_; ++i) {
+    // Cast residual from fp64 to fp32.
+    CudaFP64ToFP32(residual_fp64_.data(),
+                   residual_fp32_.data(),
+                   num_cols_,
+                   context_->DefaultStream());
+    // [fp32] c = lhs^-1 * residual.
+    auto result = CudaCholeskySolve(message);
+    if (result != LinearSolverTerminationType::SUCCESS) {
+      return result;
+    }
+    // [fp64] x += c.
+    CudaDsxpy(x_fp64_.data(),
+              correction_fp32_.data(),
+              num_cols_,
+              context_->DefaultStream());
+    if (i < max_num_refinement_iterations_) {
+      // [fp64] residual = rhs - lhs * x
+      // This is done in two steps:
+      // 1. [fp64] residual = rhs
+      residual_fp64_.CopyFromGPUArray(rhs_fp64_.data(), num_cols_);
+      // 2. [fp64] residual = residual - lhs * x
+      double alpha = -1.0;
+      double beta = 1.0;
+      cublasDsymv(context_->cublas_handle_,
+                  CUBLAS_FILL_MODE_LOWER,
+                  num_cols_,
+                  &alpha,
+                  lhs_fp64_.data(),
+                  num_cols_,
+                  x_fp64_.data(),
+                  1,
+                  &beta,
+                  residual_fp64_.data(),
+                  1);
+    }
+  }
+  x_fp64_.CopyToCpu(solution, num_cols_);
+  *message = "Success.";
+  return LinearSolverTerminationType::SUCCESS;
+}
+
+#endif  // CERES_NO_CUDA
+
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/dense_cholesky.h b/third_party/ceres/internal/ceres/dense_cholesky.h
new file mode 100644
index 0000000..04a5dd5
--- /dev/null
+++ b/third_party/ceres/internal/ceres/dense_cholesky.h
@@ -0,0 +1,308 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_DENSE_CHOLESKY_H_
+#define CERES_INTERNAL_DENSE_CHOLESKY_H_
+
+// This include must come before any #ifndef check on Ceres compile options.
+// clang-format off
+#include "ceres/internal/config.h"
+// clang-format on
+
+#include <memory>
+#include <vector>
+
+#include "Eigen/Dense"
+#include "ceres/context_impl.h"
+#include "ceres/cuda_buffer.h"
+#include "ceres/linear_solver.h"
+#include "glog/logging.h"
+#ifndef CERES_NO_CUDA
+#include "ceres/context_impl.h"
+#include "cuda_runtime.h"
+#include "cusolverDn.h"
+#endif  // CERES_NO_CUDA
+
+namespace ceres::internal {
+
+// An interface that abstracts away the internal details of various dense linear
+// algebra libraries and offers a simple API for solving dense symmetric
+// positive definite linear systems using a Cholesky factorization.
+class CERES_NO_EXPORT DenseCholesky {
+ public:
+  static std::unique_ptr<DenseCholesky> Create(
+      const LinearSolver::Options& options);
+
+  virtual ~DenseCholesky();
+
+  // Computes the Cholesky factorization of the given matrix.
+  //
+  // The input matrix lhs is assumed to be a column-major num_cols x num_cols
+  // matrix, that is symmetric positive definite with its lower triangular part
+  // containing the left hand side of the linear system being solved.
+  //
+  // The input matrix lhs may be modified by the implementation to store the
+  // factorization, irrespective of whether the factorization succeeds or not.
+  // As a result it is the user's responsibility to ensure that lhs is valid
+  // when Solve is called.
+  virtual LinearSolverTerminationType Factorize(int num_cols,
+                                                double* lhs,
+                                                std::string* message) = 0;
+
+  // Computes the solution to the equation
+  //
+  // lhs * solution = rhs
+  //
+  // Calling Solve without calling Factorize is undefined behaviour. It is the
+  // user's responsibility to ensure that the input matrix lhs passed to
+  // Factorize has not been freed/modified when Solve is called.
+  virtual LinearSolverTerminationType Solve(const double* rhs,
+                                            double* solution,
+                                            std::string* message) = 0;
+
+  // Convenience method which combines a call to Factorize and Solve. Solve is
+  // only called if Factorize returns LinearSolverTerminationType::SUCCESS.
+  //
+  // The input matrix lhs may be modified by the implementation to store the
+  // factorization, irrespective of whether the method succeeds or not. It is
+  // the user's responsibility to ensure that lhs is valid if and when Solve is
+  // called again after this call.
+  LinearSolverTerminationType FactorAndSolve(int num_cols,
+                                             double* lhs,
+                                             const double* rhs,
+                                             double* solution,
+                                             std::string* message);
+};
+
+class CERES_NO_EXPORT EigenDenseCholesky final : public DenseCholesky {
+ public:
+  LinearSolverTerminationType Factorize(int num_cols,
+                                        double* lhs,
+                                        std::string* message) override;
+  LinearSolverTerminationType Solve(const double* rhs,
+                                    double* solution,
+                                    std::string* message) override;
+
+ private:
+  using LLTType = Eigen::LLT<Eigen::Ref<Eigen::MatrixXd>, Eigen::Lower>;
+  std::unique_ptr<LLTType> llt_;
+};
+
+class CERES_NO_EXPORT FloatEigenDenseCholesky final : public DenseCholesky {
+ public:
+  LinearSolverTerminationType Factorize(int num_cols,
+                                        double* lhs,
+                                        std::string* message) override;
+  LinearSolverTerminationType Solve(const double* rhs,
+                                    double* solution,
+                                    std::string* message) override;
+
+ private:
+  Eigen::MatrixXf lhs_;
+  Eigen::VectorXf rhs_;
+  Eigen::VectorXf solution_;
+  using LLTType = Eigen::LLT<Eigen::MatrixXf, Eigen::Lower>;
+  std::unique_ptr<LLTType> llt_;
+};
+
+#ifndef CERES_NO_LAPACK
+class CERES_NO_EXPORT LAPACKDenseCholesky final : public DenseCholesky {
+ public:
+  LinearSolverTerminationType Factorize(int num_cols,
+                                        double* lhs,
+                                        std::string* message) override;
+  LinearSolverTerminationType Solve(const double* rhs,
+                                    double* solution,
+                                    std::string* message) override;
+
+ private:
+  double* lhs_ = nullptr;
+  int num_cols_ = -1;
+  LinearSolverTerminationType termination_type_ =
+      LinearSolverTerminationType::FATAL_ERROR;
+};
+
+class CERES_NO_EXPORT FloatLAPACKDenseCholesky final : public DenseCholesky {
+ public:
+  LinearSolverTerminationType Factorize(int num_cols,
+                                        double* lhs,
+                                        std::string* message) override;
+  LinearSolverTerminationType Solve(const double* rhs,
+                                    double* solution,
+                                    std::string* message) override;
+
+ private:
+  Eigen::MatrixXf lhs_;
+  Eigen::VectorXf rhs_and_solution_;
+  int num_cols_ = -1;
+  LinearSolverTerminationType termination_type_ =
+      LinearSolverTerminationType::FATAL_ERROR;
+};
+#endif  // CERES_NO_LAPACK
+
+class DenseIterativeRefiner;
+
+// Computes an initial solution using the given instance of
+// DenseCholesky, and then refines it using the DenseIterativeRefiner.
+class CERES_NO_EXPORT RefinedDenseCholesky final : public DenseCholesky {
+ public:
+  RefinedDenseCholesky(
+      std::unique_ptr<DenseCholesky> dense_cholesky,
+      std::unique_ptr<DenseIterativeRefiner> iterative_refiner);
+  ~RefinedDenseCholesky() override;
+
+  LinearSolverTerminationType Factorize(int num_cols,
+                                        double* lhs,
+                                        std::string* message) override;
+  LinearSolverTerminationType Solve(const double* rhs,
+                                    double* solution,
+                                    std::string* message) override;
+
+ private:
+  std::unique_ptr<DenseCholesky> dense_cholesky_;
+  std::unique_ptr<DenseIterativeRefiner> iterative_refiner_;
+  double* lhs_ = nullptr;
+  int num_cols_;
+};
+
+#ifndef CERES_NO_CUDA
+// CUDA implementation of DenseCholesky using the cuSolverDN library using the
+// 32-bit legacy interface for maximum compatibility.
+class CERES_NO_EXPORT CUDADenseCholesky final : public DenseCholesky {
+ public:
+  static std::unique_ptr<CUDADenseCholesky> Create(
+      const LinearSolver::Options& options);
+  CUDADenseCholesky(const CUDADenseCholesky&) = delete;
+  CUDADenseCholesky& operator=(const CUDADenseCholesky&) = delete;
+  LinearSolverTerminationType Factorize(int num_cols,
+                                        double* lhs,
+                                        std::string* message) override;
+  LinearSolverTerminationType Solve(const double* rhs,
+                                    double* solution,
+                                    std::string* message) override;
+
+ private:
+  explicit CUDADenseCholesky(ContextImpl* context);
+
+  ContextImpl* context_ = nullptr;
+  // Number of columns in the A matrix, to be cached between calls to *Factorize
+  // and *Solve.
+  size_t num_cols_ = 0;
+  // GPU memory allocated for the A matrix (lhs matrix).
+  CudaBuffer<double> lhs_;
+  // GPU memory allocated for the B matrix (rhs vector).
+  CudaBuffer<double> rhs_;
+  // Scratch space for cuSOLVER on the GPU.
+  CudaBuffer<double> device_workspace_;
+  // Required for error handling with cuSOLVER.
+  CudaBuffer<int> error_;
+  // Cache the result of Factorize to ensure that when Solve is called, the
+  // factorization of lhs is valid.
+  LinearSolverTerminationType factorize_result_ =
+      LinearSolverTerminationType::FATAL_ERROR;
+};
+
+// A mixed-precision iterative refinement dense Cholesky solver using FP32 CUDA
+// Dense Cholesky for inner iterations, and FP64 outer refinements.
+// This class implements a modified version of the  "Classical iterative
+// refinement" (Algorithm 4.1) from the following paper:
+// Haidar, Azzam, Harun Bayraktar, Stanimire Tomov, Jack Dongarra, and Nicholas
+// J. Higham. "Mixed-precision iterative refinement using tensor cores on GPUs
+// to accelerate solution of linear systems." Proceedings of the Royal Society A
+// 476, no. 2243 (2020): 20200110.
+//
+// The three key modifications from Algorithm 4.1 in the paper are:
+// 1. We use Cholesky factorization instead of LU factorization since our A is
+//    symmetric positive definite.
+// 2. During the solution update, the up-cast and accumulation is performed in
+//    one step with a custom kernel.
+class CERES_NO_EXPORT CUDADenseCholeskyMixedPrecision final
+    : public DenseCholesky {
+ public:
+  static std::unique_ptr<CUDADenseCholeskyMixedPrecision> Create(
+      const LinearSolver::Options& options);
+  CUDADenseCholeskyMixedPrecision(const CUDADenseCholeskyMixedPrecision&) =
+      delete;
+  CUDADenseCholeskyMixedPrecision& operator=(
+      const CUDADenseCholeskyMixedPrecision&) = delete;
+  LinearSolverTerminationType Factorize(int num_cols,
+                                        double* lhs,
+                                        std::string* message) override;
+  LinearSolverTerminationType Solve(const double* rhs,
+                                    double* solution,
+                                    std::string* message) override;
+
+ private:
+  CUDADenseCholeskyMixedPrecision(ContextImpl* context,
+                                  int max_num_refinement_iterations);
+
+  // Helper function to wrap Cuda boilerplate needed to call Spotrf.
+  LinearSolverTerminationType CudaCholeskyFactorize(std::string* message);
+  // Helper function to wrap Cuda boilerplate needed to call Spotrs.
+  LinearSolverTerminationType CudaCholeskySolve(std::string* message);
+  // Picks up the cuSolverDN and cuStream handles from the context in the
+  // options, and the number of refinement iterations from the options. If
+  // the context is unable to initialize CUDA, returns false with a
+  // human-readable message indicating the reason.
+  bool Init(const LinearSolver::Options& options, std::string* message);
+
+  ContextImpl* context_ = nullptr;
+  // Number of columns in the A matrix, to be cached between calls to *Factorize
+  // and *Solve.
+  size_t num_cols_ = 0;
+  CudaBuffer<double> lhs_fp64_;
+  CudaBuffer<double> rhs_fp64_;
+  CudaBuffer<float> lhs_fp32_;
+  // Scratch space for cuSOLVER on the GPU.
+  CudaBuffer<float> device_workspace_;
+  // Required for error handling with cuSOLVER.
+  CudaBuffer<int> error_;
+
+  // Solution to lhs * x = rhs.
+  CudaBuffer<double> x_fp64_;
+  // Incremental correction to x.
+  CudaBuffer<float> correction_fp32_;
+  // Residual to iterative refinement.
+  CudaBuffer<float> residual_fp32_;
+  CudaBuffer<double> residual_fp64_;
+
+  // Number of inner refinement iterations to perform.
+  int max_num_refinement_iterations_ = 0;
+  // Cache the result of Factorize to ensure that when Solve is called, the
+  // factorization of lhs is valid.
+  LinearSolverTerminationType factorize_result_ =
+      LinearSolverTerminationType::FATAL_ERROR;
+};
+
+#endif  // CERES_NO_CUDA
+
+}  // namespace ceres::internal
+
+#endif  // CERES_INTERNAL_DENSE_CHOLESKY_H_
diff --git a/third_party/ceres/internal/ceres/dense_cholesky_test.cc b/third_party/ceres/internal/ceres/dense_cholesky_test.cc
new file mode 100644
index 0000000..1b2e42d
--- /dev/null
+++ b/third_party/ceres/internal/ceres/dense_cholesky_test.cc
@@ -0,0 +1,221 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/dense_cholesky.h"
+
+#include <memory>
+#include <numeric>
+#include <sstream>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "Eigen/Dense"
+#include "ceres/internal/config.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/iterative_refiner.h"
+#include "ceres/linear_solver.h"
+#include "glog/logging.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace ceres::internal {
+
+using Param = ::testing::tuple<DenseLinearAlgebraLibraryType, bool>;
+constexpr bool kMixedPrecision = true;
+constexpr bool kFullPrecision = false;
+
+namespace {
+
+std::string ParamInfoToString(testing::TestParamInfo<Param> info) {
+  Param param = info.param;
+  std::stringstream ss;
+  ss << DenseLinearAlgebraLibraryTypeToString(::testing::get<0>(param)) << "_"
+     << (::testing::get<1>(param) ? "MixedPrecision" : "FullPrecision");
+  return ss.str();
+}
+}  // namespace
+
+class DenseCholeskyTest : public ::testing::TestWithParam<Param> {};
+
+TEST_P(DenseCholeskyTest, FactorAndSolve) {
+  // TODO(sameeragarwal): Convert these tests into type parameterized tests so
+  // that we can test the single and double precision solvers.
+
+  using Scalar = double;
+  using MatrixType = Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>;
+  using VectorType = Eigen::Matrix<Scalar, Eigen::Dynamic, 1>;
+
+  LinearSolver::Options options;
+  ContextImpl context;
+#ifndef CERES_NO_CUDA
+  options.context = &context;
+  std::string error;
+  CHECK(context.InitCuda(&error)) << error;
+#endif  // CERES_NO_CUDA
+  options.dense_linear_algebra_library_type = ::testing::get<0>(GetParam());
+  options.use_mixed_precision_solves = ::testing::get<1>(GetParam());
+  const int kNumRefinementSteps = 4;
+  if (options.use_mixed_precision_solves) {
+    options.max_num_refinement_iterations = kNumRefinementSteps;
+  }
+  auto dense_cholesky = DenseCholesky::Create(options);
+
+  const int kNumTrials = 10;
+  const int kMinNumCols = 1;
+  const int kMaxNumCols = 10;
+  for (int num_cols = kMinNumCols; num_cols < kMaxNumCols; ++num_cols) {
+    for (int trial = 0; trial < kNumTrials; ++trial) {
+      const MatrixType a = MatrixType::Random(num_cols, num_cols);
+      MatrixType lhs = a.transpose() * a;
+      lhs += VectorType::Ones(num_cols).asDiagonal();
+      Vector x = VectorType::Random(num_cols);
+      Vector rhs = lhs * x;
+      Vector actual = Vector::Random(num_cols);
+
+      LinearSolver::Summary summary;
+      summary.termination_type = dense_cholesky->FactorAndSolve(
+          num_cols, lhs.data(), rhs.data(), actual.data(), &summary.message);
+      EXPECT_EQ(summary.termination_type, LinearSolverTerminationType::SUCCESS);
+      EXPECT_NEAR((x - actual).norm() / x.norm(),
+                  0.0,
+                  std::numeric_limits<double>::epsilon() * 10)
+          << "\nexpected: " << x.transpose()
+          << "\nactual  : " << actual.transpose();
+    }
+  }
+}
+
+INSTANTIATE_TEST_SUITE_P(EigenCholesky,
+                         DenseCholeskyTest,
+                         ::testing::Combine(::testing::Values(EIGEN),
+                                            ::testing::Values(kMixedPrecision,
+                                                              kFullPrecision)),
+                         ParamInfoToString);
+#ifndef CERES_NO_LAPACK
+INSTANTIATE_TEST_SUITE_P(LapackCholesky,
+                         DenseCholeskyTest,
+                         ::testing::Combine(::testing::Values(LAPACK),
+                                            ::testing::Values(kMixedPrecision,
+                                                              kFullPrecision)),
+                         ParamInfoToString);
+#endif
+#ifndef CERES_NO_CUDA
+INSTANTIATE_TEST_SUITE_P(CudaCholesky,
+                         DenseCholeskyTest,
+                         ::testing::Combine(::testing::Values(CUDA),
+                                            ::testing::Values(kMixedPrecision,
+                                                              kFullPrecision)),
+                         ParamInfoToString);
+#endif
+
+class MockDenseCholesky : public DenseCholesky {
+ public:
+  MOCK_METHOD3(Factorize,
+               LinearSolverTerminationType(int num_cols,
+                                           double* lhs,
+                                           std::string* message));
+  MOCK_METHOD3(Solve,
+               LinearSolverTerminationType(const double* rhs,
+                                           double* solution,
+                                           std::string* message));
+};
+
+class MockDenseIterativeRefiner : public DenseIterativeRefiner {
+ public:
+  MockDenseIterativeRefiner() : DenseIterativeRefiner(1) {}
+  MOCK_METHOD5(Refine,
+               void(int num_cols,
+                    const double* lhs,
+                    const double* rhs,
+                    DenseCholesky* dense_cholesky,
+                    double* solution));
+};
+
+using testing::_;
+using testing::Return;
+
+TEST(RefinedDenseCholesky, Factorize) {
+  auto dense_cholesky = std::make_unique<MockDenseCholesky>();
+  auto iterative_refiner = std::make_unique<MockDenseIterativeRefiner>();
+  EXPECT_CALL(*dense_cholesky, Factorize(_, _, _))
+      .Times(1)
+      .WillRepeatedly(Return(LinearSolverTerminationType::SUCCESS));
+  EXPECT_CALL(*iterative_refiner, Refine(_, _, _, _, _)).Times(0);
+  RefinedDenseCholesky refined_dense_cholesky(std::move(dense_cholesky),
+                                              std::move(iterative_refiner));
+  double lhs;
+  std::string message;
+  EXPECT_EQ(refined_dense_cholesky.Factorize(1, &lhs, &message),
+            LinearSolverTerminationType::SUCCESS);
+};
+
+TEST(RefinedDenseCholesky, FactorAndSolveWithUnsuccessfulFactorization) {
+  auto dense_cholesky = std::make_unique<MockDenseCholesky>();
+  auto iterative_refiner = std::make_unique<MockDenseIterativeRefiner>();
+  EXPECT_CALL(*dense_cholesky, Factorize(_, _, _))
+      .Times(1)
+      .WillRepeatedly(Return(LinearSolverTerminationType::FAILURE));
+  EXPECT_CALL(*dense_cholesky, Solve(_, _, _)).Times(0);
+  EXPECT_CALL(*iterative_refiner, Refine(_, _, _, _, _)).Times(0);
+  RefinedDenseCholesky refined_dense_cholesky(std::move(dense_cholesky),
+                                              std::move(iterative_refiner));
+  double lhs;
+  std::string message;
+  double rhs;
+  double solution;
+  EXPECT_EQ(
+      refined_dense_cholesky.FactorAndSolve(1, &lhs, &rhs, &solution, &message),
+      LinearSolverTerminationType::FAILURE);
+};
+
+TEST(RefinedDenseCholesky, FactorAndSolveWithSuccess) {
+  auto dense_cholesky = std::make_unique<MockDenseCholesky>();
+  auto iterative_refiner = std::make_unique<MockDenseIterativeRefiner>();
+  EXPECT_CALL(*dense_cholesky, Factorize(_, _, _))
+      .Times(1)
+      .WillRepeatedly(Return(LinearSolverTerminationType::SUCCESS));
+  EXPECT_CALL(*dense_cholesky, Solve(_, _, _))
+      .Times(1)
+      .WillRepeatedly(Return(LinearSolverTerminationType::SUCCESS));
+  EXPECT_CALL(*iterative_refiner, Refine(_, _, _, _, _)).Times(1);
+
+  RefinedDenseCholesky refined_dense_cholesky(std::move(dense_cholesky),
+                                              std::move(iterative_refiner));
+  double lhs;
+  std::string message;
+  double rhs;
+  double solution;
+  EXPECT_EQ(
+      refined_dense_cholesky.FactorAndSolve(1, &lhs, &rhs, &solution, &message),
+      LinearSolverTerminationType::SUCCESS);
+};
+
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/dense_jacobian_writer.h b/third_party/ceres/internal/ceres/dense_jacobian_writer.h
index 28c60e2..d0f2c89 100644
--- a/third_party/ceres/internal/ceres/dense_jacobian_writer.h
+++ b/third_party/ceres/internal/ceres/dense_jacobian_writer.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -33,9 +33,13 @@
 #ifndef CERES_INTERNAL_DENSE_JACOBIAN_WRITER_H_
 #define CERES_INTERNAL_DENSE_JACOBIAN_WRITER_H_
 
+#include <memory>
+
 #include "ceres/casts.h"
 #include "ceres/dense_sparse_matrix.h"
+#include "ceres/internal/disable_warnings.h"
 #include "ceres/internal/eigen.h"
+#include "ceres/internal/export.h"
 #include "ceres/parameter_block.h"
 #include "ceres/program.h"
 #include "ceres/residual_block.h"
@@ -44,7 +48,7 @@
 namespace ceres {
 namespace internal {
 
-class DenseJacobianWriter {
+class CERES_NO_EXPORT DenseJacobianWriter {
  public:
   DenseJacobianWriter(Evaluator::Options /* ignored */, Program* program)
       : program_(program) {}
@@ -54,13 +58,14 @@
   // Since the dense matrix has different layout than that assumed by the cost
   // functions, use scratch space to store the jacobians temporarily then copy
   // them over to the larger jacobian later.
-  ScratchEvaluatePreparer* CreateEvaluatePreparers(int num_threads) {
+  std::unique_ptr<ScratchEvaluatePreparer[]> CreateEvaluatePreparers(
+      int num_threads) {
     return ScratchEvaluatePreparer::Create(*program_, num_threads);
   }
 
-  SparseMatrix* CreateJacobian() const {
-    return new DenseSparseMatrix(
-        program_->NumResiduals(), program_->NumEffectiveParameters(), true);
+  std::unique_ptr<SparseMatrix> CreateJacobian() const {
+    return std::make_unique<DenseSparseMatrix>(
+        program_->NumResiduals(), program_->NumEffectiveParameters());
   }
 
   void Write(int residual_id,
@@ -70,8 +75,8 @@
     DenseSparseMatrix* dense_jacobian = down_cast<DenseSparseMatrix*>(jacobian);
     const ResidualBlock* residual_block =
         program_->residual_blocks()[residual_id];
-    int num_parameter_blocks = residual_block->NumParameterBlocks();
-    int num_residuals = residual_block->NumResiduals();
+    const int num_parameter_blocks = residual_block->NumParameterBlocks();
+    const int num_residuals = residual_block->NumResiduals();
 
     // Now copy the jacobians for each parameter into the dense jacobian matrix.
     for (int j = 0; j < num_parameter_blocks; ++j) {
@@ -82,14 +87,14 @@
         continue;
       }
 
-      const int parameter_block_size = parameter_block->LocalSize();
+      const int parameter_block_size = parameter_block->TangentSize();
       ConstMatrixRef parameter_jacobian(
           jacobians[j], num_residuals, parameter_block_size);
 
-      dense_jacobian->mutable_matrix().block(residual_offset,
-                                             parameter_block->delta_offset(),
-                                             num_residuals,
-                                             parameter_block_size) =
+      dense_jacobian->mutable_matrix()->block(residual_offset,
+                                              parameter_block->delta_offset(),
+                                              num_residuals,
+                                              parameter_block_size) =
           parameter_jacobian;
     }
   }
@@ -101,4 +106,6 @@
 }  // namespace internal
 }  // namespace ceres
 
+#include "ceres/internal/reenable_warnings.h"
+
 #endif  // CERES_INTERNAL_DENSE_JACOBIAN_WRITER_H_
diff --git a/third_party/ceres/internal/ceres/dense_linear_solver_benchmark.cc b/third_party/ceres/internal/ceres/dense_linear_solver_benchmark.cc
new file mode 100644
index 0000000..0930b7b
--- /dev/null
+++ b/third_party/ceres/internal/ceres/dense_linear_solver_benchmark.cc
@@ -0,0 +1,108 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Authors: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "Eigen/Dense"
+#include "benchmark/benchmark.h"
+#include "ceres/context_impl.h"
+#include "ceres/dense_sparse_matrix.h"
+#include "ceres/internal/config.h"
+#include "ceres/linear_solver.h"
+
+namespace ceres::internal {
+
+template <ceres::DenseLinearAlgebraLibraryType kLibraryType,
+          ceres::LinearSolverType kSolverType>
+static void BM_DenseSolver(benchmark::State& state) {
+  const int num_rows = static_cast<int>(state.range(0));
+  const int num_cols = static_cast<int>(state.range(1));
+  DenseSparseMatrix jacobian(num_rows, num_cols);
+  *jacobian.mutable_matrix() = Eigen::MatrixXd::Random(num_rows, num_cols);
+  Eigen::VectorXd rhs = Eigen::VectorXd::Random(num_rows, 1);
+
+  Eigen::VectorXd solution(num_cols);
+
+  LinearSolver::Options options;
+  options.type = kSolverType;
+  options.dense_linear_algebra_library_type = kLibraryType;
+  ContextImpl context;
+  options.context = &context;
+  auto solver = LinearSolver::Create(options);
+
+  LinearSolver::PerSolveOptions per_solve_options;
+  Eigen::VectorXd diagonal = Eigen::VectorXd::Ones(num_cols) * 100;
+  per_solve_options.D = diagonal.data();
+  for (auto _ : state) {
+    solver->Solve(&jacobian, rhs.data(), per_solve_options, solution.data());
+  }
+}
+
+// Some reasonable matrix sizes. I picked them out of thin air.
+static void MatrixSizes(benchmark::internal::Benchmark* b) {
+  // {num_rows, num_cols}
+  b->Args({1, 1});
+  b->Args({2, 1});
+  b->Args({3, 1});
+  b->Args({6, 2});
+  b->Args({10, 3});
+  b->Args({12, 4});
+  b->Args({20, 5});
+  b->Args({40, 5});
+  b->Args({100, 10});
+  b->Args({150, 15});
+  b->Args({200, 16});
+  b->Args({225, 18});
+  b->Args({300, 20});
+  b->Args({400, 20});
+  b->Args({600, 22});
+  b->Args({800, 25});
+}
+
+BENCHMARK_TEMPLATE2(BM_DenseSolver, ceres::EIGEN, ceres::DENSE_QR)
+    ->Apply(MatrixSizes);
+BENCHMARK_TEMPLATE2(BM_DenseSolver, ceres::EIGEN, ceres::DENSE_NORMAL_CHOLESKY)
+    ->Apply(MatrixSizes);
+
+#ifndef CERES_NO_LAPACK
+BENCHMARK_TEMPLATE2(BM_DenseSolver, ceres::LAPACK, ceres::DENSE_QR)
+    ->Apply(MatrixSizes);
+BENCHMARK_TEMPLATE2(BM_DenseSolver, ceres::LAPACK, ceres::DENSE_NORMAL_CHOLESKY)
+    ->Apply(MatrixSizes);
+#endif  // CERES_NO_LAPACK
+
+#ifndef CERES_NO_CUDA
+BENCHMARK_TEMPLATE2(BM_DenseSolver, ceres::CUDA, ceres::DENSE_NORMAL_CHOLESKY)
+    ->Apply(MatrixSizes);
+BENCHMARK_TEMPLATE2(BM_DenseSolver, ceres::CUDA, ceres::DENSE_QR)
+    ->Apply(MatrixSizes);
+#endif  // CERES_NO_CUDA
+
+}  // namespace ceres::internal
+
+BENCHMARK_MAIN();
diff --git a/third_party/ceres/internal/ceres/dense_linear_solver_test.cc b/third_party/ceres/internal/ceres/dense_linear_solver_test.cc
index 3929a6f..79d2543 100644
--- a/third_party/ceres/internal/ceres/dense_linear_solver_test.cc
+++ b/third_party/ceres/internal/ceres/dense_linear_solver_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -32,6 +32,7 @@
 
 #include "ceres/casts.h"
 #include "ceres/context_impl.h"
+#include "ceres/internal/config.h"
 #include "ceres/linear_least_squares_problems.h"
 #include "ceres/linear_solver.h"
 #include "ceres/triplet_sparse_matrix.h"
@@ -39,12 +40,10 @@
 #include "glog/logging.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
-typedef ::testing::
-    tuple<LinearSolverType, DenseLinearAlgebraLibraryType, bool, int>
-        Param;
+using Param = ::testing::
+    tuple<LinearSolverType, DenseLinearAlgebraLibraryType, bool, int>;
 
 static std::string ParamInfoToString(testing::TestParamInfo<Param> info) {
   Param param = info.param;
@@ -62,8 +61,8 @@
   Param param = GetParam();
   const bool regularized = testing::get<2>(param);
 
-  std::unique_ptr<LinearLeastSquaresProblem> problem(
-      CreateLinearLeastSquaresProblemFromId(testing::get<3>(param)));
+  std::unique_ptr<LinearLeastSquaresProblem> problem =
+      CreateLinearLeastSquaresProblemFromId(testing::get<3>(param));
   DenseSparseMatrix lhs(*down_cast<TripletSparseMatrix*>(problem->A.get()));
 
   const int num_cols = lhs.num_cols();
@@ -87,25 +86,25 @@
   Vector solution(num_cols);
   LinearSolver::Summary summary =
       solver->Solve(&lhs, rhs.data(), per_solve_options, solution.data());
-  EXPECT_EQ(summary.termination_type, LINEAR_SOLVER_SUCCESS);
+  EXPECT_EQ(summary.termination_type, LinearSolverTerminationType::SUCCESS);
 
-  // If solving for the regularized solution, add the diagonal to the
-  // matrix. This makes subsequent computations simpler.
-  if (testing::get<2>(param)) {
-    lhs.AppendDiagonal(problem->D.get());
-  };
+  Vector normal_rhs = lhs.matrix().transpose() * rhs.head(num_rows);
+  Matrix normal_lhs = lhs.matrix().transpose() * lhs.matrix();
 
-  Vector tmp = Vector::Zero(num_rows + num_cols);
-  lhs.RightMultiply(solution.data(), tmp.data());
-  Vector actual_normal_rhs = Vector::Zero(num_cols);
-  lhs.LeftMultiply(tmp.data(), actual_normal_rhs.data());
+  if (regularized) {
+    ConstVectorRef diagonal(problem->D.get(), num_cols);
+    normal_lhs += diagonal.array().square().matrix().asDiagonal();
+  }
 
-  Vector expected_normal_rhs = Vector::Zero(num_cols);
-  lhs.LeftMultiply(rhs.data(), expected_normal_rhs.data());
-  const double residual = (expected_normal_rhs - actual_normal_rhs).norm() /
-                          expected_normal_rhs.norm();
+  Vector actual_normal_rhs = normal_lhs * solution;
 
-  EXPECT_NEAR(residual, 0.0, 10 * std::numeric_limits<double>::epsilon());
+  const double normalized_residual =
+      (normal_rhs - actual_normal_rhs).norm() / normal_rhs.norm();
+
+  EXPECT_NEAR(
+      normalized_residual, 0.0, 10 * std::numeric_limits<double>::epsilon())
+      << "\nexpected: " << normal_rhs.transpose()
+      << "\nactual: " << actual_normal_rhs.transpose();
 }
 
 namespace {
@@ -136,5 +135,4 @@
 
 #endif
 }  // namespace
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/dense_normal_cholesky_solver.cc b/third_party/ceres/internal/ceres/dense_normal_cholesky_solver.cc
index 51c6390..f6d5e5a 100644
--- a/third_party/ceres/internal/ceres/dense_normal_cholesky_solver.cc
+++ b/third_party/ceres/internal/ceres/dense_normal_cholesky_solver.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -30,47 +30,32 @@
 
 #include "ceres/dense_normal_cholesky_solver.h"
 
-#include <cstddef>
+#include <utility>
 
 #include "Eigen/Dense"
-#include "ceres/blas.h"
 #include "ceres/dense_sparse_matrix.h"
 #include "ceres/internal/eigen.h"
-#include "ceres/lapack.h"
 #include "ceres/linear_solver.h"
 #include "ceres/types.h"
 #include "ceres/wall_time.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 DenseNormalCholeskySolver::DenseNormalCholeskySolver(
-    const LinearSolver::Options& options)
-    : options_(options) {}
+    LinearSolver::Options options)
+    : options_(std::move(options)),
+      cholesky_(DenseCholesky::Create(options_)) {}
 
 LinearSolver::Summary DenseNormalCholeskySolver::SolveImpl(
     DenseSparseMatrix* A,
     const double* b,
     const LinearSolver::PerSolveOptions& per_solve_options,
     double* x) {
-  if (options_.dense_linear_algebra_library_type == EIGEN) {
-    return SolveUsingEigen(A, b, per_solve_options, x);
-  } else {
-    return SolveUsingLAPACK(A, b, per_solve_options, x);
-  }
-}
-
-LinearSolver::Summary DenseNormalCholeskySolver::SolveUsingEigen(
-    DenseSparseMatrix* A,
-    const double* b,
-    const LinearSolver::PerSolveOptions& per_solve_options,
-    double* x) {
   EventLogger event_logger("DenseNormalCholeskySolver::Solve");
 
   const int num_rows = A->num_rows();
   const int num_cols = A->num_cols();
 
-  ConstColMajorMatrixRef Aref = A->matrix();
   Matrix lhs(num_cols, num_cols);
   lhs.setZero();
 
@@ -81,12 +66,12 @@
   // Using rankUpdate instead of GEMM, exposes the fact that its the
   // same matrix being multiplied with itself and that the product is
   // symmetric.
-  lhs.selfadjointView<Eigen::Upper>().rankUpdate(Aref.transpose());
+  lhs.selfadjointView<Eigen::Upper>().rankUpdate(A->matrix().transpose());
 
   //   rhs = A'b
-  Vector rhs = Aref.transpose() * ConstVectorRef(b, num_rows);
+  Vector rhs = A->matrix().transpose() * ConstVectorRef(b, num_rows);
 
-  if (per_solve_options.D != NULL) {
+  if (per_solve_options.D != nullptr) {
     ConstVectorRef D(per_solve_options.D, num_cols);
     lhs += D.array().square().matrix().asDiagonal();
   }
@@ -94,64 +79,11 @@
 
   LinearSolver::Summary summary;
   summary.num_iterations = 1;
-  summary.termination_type = LINEAR_SOLVER_SUCCESS;
-  Eigen::LLT<Matrix, Eigen::Upper> llt =
-      lhs.selfadjointView<Eigen::Upper>().llt();
+  summary.termination_type = cholesky_->FactorAndSolve(
+      num_cols, lhs.data(), rhs.data(), x, &summary.message);
+  event_logger.AddEvent("FactorAndSolve");
 
-  if (llt.info() != Eigen::Success) {
-    summary.termination_type = LINEAR_SOLVER_FAILURE;
-    summary.message = "Eigen LLT decomposition failed.";
-  } else {
-    summary.termination_type = LINEAR_SOLVER_SUCCESS;
-    summary.message = "Success.";
-  }
-
-  VectorRef(x, num_cols) = llt.solve(rhs);
-  event_logger.AddEvent("Solve");
   return summary;
 }
 
-LinearSolver::Summary DenseNormalCholeskySolver::SolveUsingLAPACK(
-    DenseSparseMatrix* A,
-    const double* b,
-    const LinearSolver::PerSolveOptions& per_solve_options,
-    double* x) {
-  EventLogger event_logger("DenseNormalCholeskySolver::Solve");
-
-  if (per_solve_options.D != NULL) {
-    // Temporarily append a diagonal block to the A matrix, but undo
-    // it before returning the matrix to the user.
-    A->AppendDiagonal(per_solve_options.D);
-  }
-
-  const int num_cols = A->num_cols();
-  Matrix lhs(num_cols, num_cols);
-  event_logger.AddEvent("Setup");
-
-  // lhs = A'A
-  //
-  // Note: This is a bit delicate, it assumes that the stride on this
-  // matrix is the same as the number of rows.
-  BLAS::SymmetricRankKUpdate(
-      A->num_rows(), num_cols, A->values(), true, 1.0, 0.0, lhs.data());
-
-  if (per_solve_options.D != NULL) {
-    // Undo the modifications to the matrix A.
-    A->RemoveDiagonal();
-  }
-
-  // TODO(sameeragarwal): Replace this with a gemv call for true blasness.
-  //   rhs = A'b
-  VectorRef(x, num_cols) =
-      A->matrix().transpose() * ConstVectorRef(b, A->num_rows());
-  event_logger.AddEvent("Product");
-
-  LinearSolver::Summary summary;
-  summary.num_iterations = 1;
-  summary.termination_type = LAPACK::SolveInPlaceUsingCholesky(
-      num_cols, lhs.data(), x, &summary.message);
-  event_logger.AddEvent("Solve");
-  return summary;
-}
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/dense_normal_cholesky_solver.h b/third_party/ceres/internal/ceres/dense_normal_cholesky_solver.h
index 68ea611..c6aa2af 100644
--- a/third_party/ceres/internal/ceres/dense_normal_cholesky_solver.h
+++ b/third_party/ceres/internal/ceres/dense_normal_cholesky_solver.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -34,10 +34,14 @@
 #ifndef CERES_INTERNAL_DENSE_NORMAL_CHOLESKY_SOLVER_H_
 #define CERES_INTERNAL_DENSE_NORMAL_CHOLESKY_SOLVER_H_
 
+#include <memory>
+
+#include "ceres/dense_cholesky.h"
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 #include "ceres/linear_solver.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 class DenseSparseMatrix;
 
@@ -73,9 +77,10 @@
 // library. This solver always returns a solution, it is the user's
 // responsibility to judge if the solution is good enough for their
 // purposes.
-class DenseNormalCholeskySolver : public DenseSparseMatrixSolver {
+class CERES_NO_EXPORT DenseNormalCholeskySolver
+    : public DenseSparseMatrixSolver {
  public:
-  explicit DenseNormalCholeskySolver(const LinearSolver::Options& options);
+  explicit DenseNormalCholeskySolver(LinearSolver::Options options);
 
  private:
   LinearSolver::Summary SolveImpl(
@@ -84,22 +89,12 @@
       const LinearSolver::PerSolveOptions& per_solve_options,
       double* x) final;
 
-  LinearSolver::Summary SolveUsingLAPACK(
-      DenseSparseMatrix* A,
-      const double* b,
-      const LinearSolver::PerSolveOptions& per_solve_options,
-      double* x);
-
-  LinearSolver::Summary SolveUsingEigen(
-      DenseSparseMatrix* A,
-      const double* b,
-      const LinearSolver::PerSolveOptions& per_solve_options,
-      double* x);
-
   const LinearSolver::Options options_;
+  std::unique_ptr<DenseCholesky> cholesky_;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_DENSE_NORMAL_CHOLESKY_SOLVER_H_
diff --git a/third_party/ceres/internal/ceres/dense_qr.cc b/third_party/ceres/internal/ceres/dense_qr.cc
new file mode 100644
index 0000000..fbbcadc
--- /dev/null
+++ b/third_party/ceres/internal/ceres/dense_qr.cc
@@ -0,0 +1,456 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/dense_qr.h"
+
+#include <algorithm>
+#include <memory>
+#include <string>
+
+#ifndef CERES_NO_CUDA
+#include "ceres/context_impl.h"
+#include "cublas_v2.h"
+#include "cusolverDn.h"
+#endif  // CERES_NO_CUDA
+
+#ifndef CERES_NO_LAPACK
+
+// LAPACK routines for solving a linear least squares problem using QR
+// factorization. This is done in three stages:
+//
+// A * x     = b
+// Q * R * x = b               (dgeqrf)
+//     R * x = Q' * b          (dormqr)
+//         x = R^{-1} * Q'* b  (dtrtrs)
+
+// clang-format off
+
+// Compute the QR factorization of a.
+//
+// a is an m x n column major matrix (Denoted by "A" in the above description)
+// lda is the leading dimension of a. lda >= max(1, num_rows)
+// tau is an array of size min(m,n). It contains the scalar factors of the
+// elementary reflectors.
+// work is an array of size max(1,lwork). On exit, if info=0, work[0] contains
+// the optimal size of work.
+//
+// if lwork >= 1 it is the size of work. If lwork = -1, then a workspace query is assumed.
+// dgeqrf computes the optimal size of the work array and returns it as work[0].
+//
+// info = 0, successful exit.
+// info < 0, if info = -i, then the i^th argument had illegal value.
+extern "C" void dgeqrf_(const int* m, const int* n, double* a, const int* lda,
+                        double* tau, double* work, const int* lwork, int* info);
+
+// Apply Q or Q' to b.
+//
+// b is a m times n column major matrix.
+// size = 'L' applies Q or Q' on the left, size = 'R' applies Q or Q' on the right.
+// trans = 'N', applies Q, trans = 'T', applies Q'.
+// k is the number of elementary reflectors whose product defines the matrix Q.
+// If size = 'L', m >= k >= 0 and if side = 'R', n >= k >= 0.
+// a is an lda x k column major matrix containing the reflectors as returned by dgeqrf.
+// ldb is the leading dimension of b.
+// work is an array of size max(1, lwork)
+// lwork if positive is the size of work. If lwork = -1, then a
+// workspace query is assumed.
+//
+// info = 0, successful exit.
+// info < 0, if info = -i, then the i^th argument had illegal value.
+extern "C" void dormqr_(const char* side, const char* trans, const int* m,
+                        const int* n ,const int* k, double* a, const int* lda,
+                        double* tau, double* b, const int* ldb, double* work,
+                        const int* lwork, int* info);
+
+// Solve a triangular system of the form A * x = b
+//
+// uplo = 'U', A is upper triangular. uplo = 'L' is lower triangular.
+// trans = 'N', 'T', 'C' specifies the form  - A, A^T, A^H.
+// DIAG = 'N', A is not unit triangular. 'U' is unit triangular.
+// n is the order of the matrix A.
+// nrhs number of columns of b.
+// a is a column major lda x n.
+// b is a column major matrix of ldb x nrhs
+//
+// info = 0 successful.
+//      = -i < 0 i^th argument is an illegal value.
+//      = i > 0, i^th diagonal element of A is zero.
+extern "C" void dtrtrs_(const char* uplo, const char* trans, const char* diag,
+                        const int* n, const int* nrhs, double* a, const int* lda,
+                        double* b, const int* ldb, int* info);
+// clang-format on
+
+#endif
+
+namespace ceres::internal {
+
+DenseQR::~DenseQR() = default;
+
+std::unique_ptr<DenseQR> DenseQR::Create(const LinearSolver::Options& options) {
+  std::unique_ptr<DenseQR> dense_qr;
+
+  switch (options.dense_linear_algebra_library_type) {
+    case EIGEN:
+      dense_qr = std::make_unique<EigenDenseQR>();
+      break;
+
+    case LAPACK:
+#ifndef CERES_NO_LAPACK
+      dense_qr = std::make_unique<LAPACKDenseQR>();
+      break;
+#else
+      LOG(FATAL) << "Ceres was compiled without support for LAPACK.";
+#endif
+
+    case CUDA:
+#ifndef CERES_NO_CUDA
+      dense_qr = CUDADenseQR::Create(options);
+      break;
+#else
+      LOG(FATAL) << "Ceres was compiled without support for CUDA.";
+#endif
+
+    default:
+      LOG(FATAL) << "Unknown dense linear algebra library type : "
+                 << DenseLinearAlgebraLibraryTypeToString(
+                        options.dense_linear_algebra_library_type);
+  }
+  return dense_qr;
+}
+
+LinearSolverTerminationType DenseQR::FactorAndSolve(int num_rows,
+                                                    int num_cols,
+                                                    double* lhs,
+                                                    const double* rhs,
+                                                    double* solution,
+                                                    std::string* message) {
+  LinearSolverTerminationType termination_type =
+      Factorize(num_rows, num_cols, lhs, message);
+  if (termination_type == LinearSolverTerminationType::SUCCESS) {
+    termination_type = Solve(rhs, solution, message);
+  }
+  return termination_type;
+}
+
+LinearSolverTerminationType EigenDenseQR::Factorize(int num_rows,
+                                                    int num_cols,
+                                                    double* lhs,
+                                                    std::string* message) {
+  Eigen::Map<ColMajorMatrix> m(lhs, num_rows, num_cols);
+  qr_ = std::make_unique<QRType>(m);
+  *message = "Success.";
+  return LinearSolverTerminationType::SUCCESS;
+}
+
+LinearSolverTerminationType EigenDenseQR::Solve(const double* rhs,
+                                                double* solution,
+                                                std::string* message) {
+  VectorRef(solution, qr_->cols()) =
+      qr_->solve(ConstVectorRef(rhs, qr_->rows()));
+  *message = "Success.";
+  return LinearSolverTerminationType::SUCCESS;
+}
+
+#ifndef CERES_NO_LAPACK
+LinearSolverTerminationType LAPACKDenseQR::Factorize(int num_rows,
+                                                     int num_cols,
+                                                     double* lhs,
+                                                     std::string* message) {
+  int lwork = -1;
+  double work_size;
+  int info = 0;
+
+  // Compute the size of the temporary workspace needed to compute the QR
+  // factorization in the dgeqrf call below.
+  dgeqrf_(&num_rows,
+          &num_cols,
+          lhs_,
+          &num_rows,
+          tau_.data(),
+          &work_size,
+          &lwork,
+          &info);
+  if (info < 0) {
+    LOG(FATAL) << "Congratulations, you found a bug in Ceres."
+               << "Please report it."
+               << "LAPACK::dgels fatal error."
+               << "Argument: " << -info << " is invalid.";
+  }
+
+  lhs_ = lhs;
+  num_rows_ = num_rows;
+  num_cols_ = num_cols;
+
+  lwork = static_cast<int>(work_size);
+
+  if (work_.size() < lwork) {
+    work_.resize(lwork);
+  }
+  if (tau_.size() < num_cols) {
+    tau_.resize(num_cols);
+  }
+
+  if (q_transpose_rhs_.size() < num_rows) {
+    q_transpose_rhs_.resize(num_rows);
+  }
+
+  // Factorize the lhs_ using the workspace that we just constructed above.
+  dgeqrf_(&num_rows,
+          &num_cols,
+          lhs_,
+          &num_rows,
+          tau_.data(),
+          work_.data(),
+          &lwork,
+          &info);
+
+  if (info < 0) {
+    LOG(FATAL) << "Congratulations, you found a bug in Ceres."
+               << "Please report it. dgeqrf fatal error."
+               << "Argument: " << -info << " is invalid.";
+  }
+
+  termination_type_ = LinearSolverTerminationType::SUCCESS;
+  *message = "Success.";
+  return termination_type_;
+}
+
+LinearSolverTerminationType LAPACKDenseQR::Solve(const double* rhs,
+                                                 double* solution,
+                                                 std::string* message) {
+  if (termination_type_ != LinearSolverTerminationType::SUCCESS) {
+    *message = "QR factorization failed and solve called.";
+    return termination_type_;
+  }
+
+  std::copy_n(rhs, num_rows_, q_transpose_rhs_.data());
+
+  const char side = 'L';
+  char trans = 'T';
+  const int num_c_cols = 1;
+  const int lwork = work_.size();
+  int info = 0;
+  dormqr_(&side,
+          &trans,
+          &num_rows_,
+          &num_c_cols,
+          &num_cols_,
+          lhs_,
+          &num_rows_,
+          tau_.data(),
+          q_transpose_rhs_.data(),
+          &num_rows_,
+          work_.data(),
+          &lwork,
+          &info);
+  if (info < 0) {
+    LOG(FATAL) << "Congratulations, you found a bug in Ceres."
+               << "Please report it. dormr fatal error."
+               << "Argument: " << -info << " is invalid.";
+  }
+
+  const char uplo = 'U';
+  trans = 'N';
+  const char diag = 'N';
+  dtrtrs_(&uplo,
+          &trans,
+          &diag,
+          &num_cols_,
+          &num_c_cols,
+          lhs_,
+          &num_rows_,
+          q_transpose_rhs_.data(),
+          &num_rows_,
+          &info);
+
+  if (info < 0) {
+    LOG(FATAL) << "Congratulations, you found a bug in Ceres."
+               << "Please report it. dormr fatal error."
+               << "Argument: " << -info << " is invalid.";
+  } else if (info > 0) {
+    *message =
+        "QR factorization failure. The factorization is not full rank. R has "
+        "zeros on the diagonal.";
+    termination_type_ = LinearSolverTerminationType::FAILURE;
+  } else {
+    std::copy_n(q_transpose_rhs_.data(), num_cols_, solution);
+    termination_type_ = LinearSolverTerminationType::SUCCESS;
+  }
+
+  return termination_type_;
+}
+
+#endif  // CERES_NO_LAPACK
+
+#ifndef CERES_NO_CUDA
+
+CUDADenseQR::CUDADenseQR(ContextImpl* context)
+    : context_(context),
+      lhs_{context},
+      rhs_{context},
+      tau_{context},
+      device_workspace_{context},
+      error_(context, 1) {}
+
+LinearSolverTerminationType CUDADenseQR::Factorize(int num_rows,
+                                                   int num_cols,
+                                                   double* lhs,
+                                                   std::string* message) {
+  factorize_result_ = LinearSolverTerminationType::FATAL_ERROR;
+  lhs_.Reserve(num_rows * num_cols);
+  tau_.Reserve(std::min(num_rows, num_cols));
+  num_rows_ = num_rows;
+  num_cols_ = num_cols;
+  lhs_.CopyFromCpu(lhs, num_rows * num_cols);
+  int device_workspace_size = 0;
+  if (cusolverDnDgeqrf_bufferSize(context_->cusolver_handle_,
+                                  num_rows,
+                                  num_cols,
+                                  lhs_.data(),
+                                  num_rows,
+                                  &device_workspace_size) !=
+      CUSOLVER_STATUS_SUCCESS) {
+    *message = "cuSolverDN::cusolverDnDgeqrf_bufferSize failed.";
+    return LinearSolverTerminationType::FATAL_ERROR;
+  }
+  device_workspace_.Reserve(device_workspace_size);
+  if (cusolverDnDgeqrf(context_->cusolver_handle_,
+                       num_rows,
+                       num_cols,
+                       lhs_.data(),
+                       num_rows,
+                       tau_.data(),
+                       reinterpret_cast<double*>(device_workspace_.data()),
+                       device_workspace_.size(),
+                       error_.data()) != CUSOLVER_STATUS_SUCCESS) {
+    *message = "cuSolverDN::cusolverDnDgeqrf failed.";
+    return LinearSolverTerminationType::FATAL_ERROR;
+  }
+  int error = 0;
+  error_.CopyToCpu(&error, 1);
+  if (error < 0) {
+    LOG(FATAL) << "Congratulations, you found a bug in Ceres - "
+               << "please report it. "
+               << "cuSolverDN::cusolverDnDgeqrf fatal error. "
+               << "Argument: " << -error << " is invalid.";
+    // The following line is unreachable, but return failure just to be
+    // pedantic, since the compiler does not know that.
+    return LinearSolverTerminationType::FATAL_ERROR;
+  }
+
+  *message = "Success";
+  factorize_result_ = LinearSolverTerminationType::SUCCESS;
+  return LinearSolverTerminationType::SUCCESS;
+}
+
+LinearSolverTerminationType CUDADenseQR::Solve(const double* rhs,
+                                               double* solution,
+                                               std::string* message) {
+  if (factorize_result_ != LinearSolverTerminationType::SUCCESS) {
+    *message = "Factorize did not complete successfully previously.";
+    return factorize_result_;
+  }
+  rhs_.CopyFromCpu(rhs, num_rows_);
+  int device_workspace_size = 0;
+  if (cusolverDnDormqr_bufferSize(context_->cusolver_handle_,
+                                  CUBLAS_SIDE_LEFT,
+                                  CUBLAS_OP_T,
+                                  num_rows_,
+                                  1,
+                                  num_cols_,
+                                  lhs_.data(),
+                                  num_rows_,
+                                  tau_.data(),
+                                  rhs_.data(),
+                                  num_rows_,
+                                  &device_workspace_size) !=
+      CUSOLVER_STATUS_SUCCESS) {
+    *message = "cuSolverDN::cusolverDnDormqr_bufferSize failed.";
+    return LinearSolverTerminationType::FATAL_ERROR;
+  }
+  device_workspace_.Reserve(device_workspace_size);
+  // Compute rhs = Q^T * rhs, assuming that lhs has already been factorized.
+  // The result of factorization would have stored Q in a packed form in lhs_.
+  if (cusolverDnDormqr(context_->cusolver_handle_,
+                       CUBLAS_SIDE_LEFT,
+                       CUBLAS_OP_T,
+                       num_rows_,
+                       1,
+                       num_cols_,
+                       lhs_.data(),
+                       num_rows_,
+                       tau_.data(),
+                       rhs_.data(),
+                       num_rows_,
+                       reinterpret_cast<double*>(device_workspace_.data()),
+                       device_workspace_.size(),
+                       error_.data()) != CUSOLVER_STATUS_SUCCESS) {
+    *message = "cuSolverDN::cusolverDnDormqr failed.";
+    return LinearSolverTerminationType::FATAL_ERROR;
+  }
+  int error = 0;
+  error_.CopyToCpu(&error, 1);
+  if (error < 0) {
+    LOG(FATAL) << "Congratulations, you found a bug in Ceres. "
+               << "Please report it."
+               << "cuSolverDN::cusolverDnDormqr fatal error. "
+               << "Argument: " << -error << " is invalid.";
+  }
+  // Compute the solution vector as x = R \ (Q^T * rhs). Since the previous step
+  // replaced rhs by (Q^T * rhs), this is just x = R \ rhs.
+  if (cublasDtrsv(context_->cublas_handle_,
+                  CUBLAS_FILL_MODE_UPPER,
+                  CUBLAS_OP_N,
+                  CUBLAS_DIAG_NON_UNIT,
+                  num_cols_,
+                  lhs_.data(),
+                  num_rows_,
+                  rhs_.data(),
+                  1) != CUBLAS_STATUS_SUCCESS) {
+    *message = "cuBLAS::cublasDtrsv failed.";
+    return LinearSolverTerminationType::FATAL_ERROR;
+  }
+  rhs_.CopyToCpu(solution, num_cols_);
+  *message = "Success";
+  return LinearSolverTerminationType::SUCCESS;
+}
+
+std::unique_ptr<CUDADenseQR> CUDADenseQR::Create(
+    const LinearSolver::Options& options) {
+  if (options.dense_linear_algebra_library_type != CUDA ||
+      options.context == nullptr || !options.context->IsCudaInitialized()) {
+    return nullptr;
+  }
+  return std::unique_ptr<CUDADenseQR>(new CUDADenseQR(options.context));
+}
+
+#endif  // CERES_NO_CUDA
+
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/dense_qr.h b/third_party/ceres/internal/ceres/dense_qr.h
new file mode 100644
index 0000000..0ba17c4
--- /dev/null
+++ b/third_party/ceres/internal/ceres/dense_qr.h
@@ -0,0 +1,199 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_DENSE_QR_H_
+#define CERES_INTERNAL_DENSE_QR_H_
+
+// This include must come before any #ifndef check on Ceres compile options.
+// clang-format off
+#include "ceres/internal/config.h"
+// clang-format on
+
+#include <memory>
+#include <vector>
+
+#include "Eigen/Dense"
+#include "ceres/context_impl.h"
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/export.h"
+#include "ceres/linear_solver.h"
+#include "glog/logging.h"
+
+#ifndef CERES_NO_CUDA
+#include "ceres/context_impl.h"
+#include "ceres/cuda_buffer.h"
+#include "cublas_v2.h"
+#include "cuda_runtime.h"
+#include "cusolverDn.h"
+#endif  // CERES_NO_CUDA
+
+namespace ceres::internal {
+
+// An interface that abstracts away the internal details of various dense linear
+// algebra libraries and offers a simple API for solving dense linear systems
+// using a QR factorization.
+class CERES_NO_EXPORT DenseQR {
+ public:
+  static std::unique_ptr<DenseQR> Create(const LinearSolver::Options& options);
+
+  virtual ~DenseQR();
+
+  // Computes the QR factorization of the given matrix.
+  //
+  // The input matrix lhs is assumed to be a column-major num_rows x num_cols
+  // matrix.
+  //
+  // The input matrix lhs may be modified by the implementation to store the
+  // factorization, irrespective of whether the factorization succeeds or not.
+  // As a result it is the user's responsibility to ensure that lhs is valid
+  // when Solve is called.
+  virtual LinearSolverTerminationType Factorize(int num_rows,
+                                                int num_cols,
+                                                double* lhs,
+                                                std::string* message) = 0;
+
+  // Computes the solution to the equation
+  //
+  // lhs * solution = rhs
+  //
+  // Calling Solve without calling Factorize is undefined behaviour. It is the
+  // user's responsibility to ensure that the input matrix lhs passed to
+  // Factorize has not been freed/modified when Solve is called.
+  virtual LinearSolverTerminationType Solve(const double* rhs,
+                                            double* solution,
+                                            std::string* message) = 0;
+
+  // Convenience method which combines a call to Factorize and Solve. Solve is
+  // only called if Factorize returns LinearSolverTerminationType::SUCCESS.
+  //
+  // The input matrix lhs may be modified by the implementation to store the
+  // factorization, irrespective of whether the method succeeds or not. It is
+  // the user's responsibility to ensure that lhs is valid if and when Solve is
+  // called again after this call.
+  LinearSolverTerminationType FactorAndSolve(int num_rows,
+                                             int num_cols,
+                                             double* lhs,
+                                             const double* rhs,
+                                             double* solution,
+                                             std::string* message);
+};
+
+class CERES_NO_EXPORT EigenDenseQR final : public DenseQR {
+ public:
+  LinearSolverTerminationType Factorize(int num_rows,
+                                        int num_cols,
+                                        double* lhs,
+                                        std::string* message) override;
+  LinearSolverTerminationType Solve(const double* rhs,
+                                    double* solution,
+                                    std::string* message) override;
+
+ private:
+  using QRType = Eigen::HouseholderQR<Eigen::Ref<ColMajorMatrix>>;
+  std::unique_ptr<QRType> qr_;
+};
+
+#ifndef CERES_NO_LAPACK
+class CERES_NO_EXPORT LAPACKDenseQR final : public DenseQR {
+ public:
+  LinearSolverTerminationType Factorize(int num_rows,
+                                        int num_cols,
+                                        double* lhs,
+                                        std::string* message) override;
+  LinearSolverTerminationType Solve(const double* rhs,
+                                    double* solution,
+                                    std::string* message) override;
+
+ private:
+  double* lhs_ = nullptr;
+  int num_rows_;
+  int num_cols_;
+  LinearSolverTerminationType termination_type_ =
+      LinearSolverTerminationType::FATAL_ERROR;
+  Vector work_;
+  Vector tau_;
+  Vector q_transpose_rhs_;
+};
+#endif  // CERES_NO_LAPACK
+
+#ifndef CERES_NO_CUDA
+// Implementation of DenseQR using the 32-bit cuSolverDn interface. A
+// requirement for using this solver is that the lhs must not be rank deficient.
+// This is because cuSolverDn does not implement the singularity-checking
+// wrapper trtrs, hence this solver directly uses trsv from CUBLAS for the
+// backsubstitution.
+class CERES_NO_EXPORT CUDADenseQR final : public DenseQR {
+ public:
+  static std::unique_ptr<CUDADenseQR> Create(
+      const LinearSolver::Options& options);
+  CUDADenseQR(const CUDADenseQR&) = delete;
+  CUDADenseQR& operator=(const CUDADenseQR&) = delete;
+  LinearSolverTerminationType Factorize(int num_rows,
+                                        int num_cols,
+                                        double* lhs,
+                                        std::string* message) override;
+  LinearSolverTerminationType Solve(const double* rhs,
+                                    double* solution,
+                                    std::string* message) override;
+
+ private:
+  explicit CUDADenseQR(ContextImpl* context);
+
+  ContextImpl* context_ = nullptr;
+  // Number of rowns in the A matrix, to be cached between calls to *Factorize
+  // and *Solve.
+  size_t num_rows_ = 0;
+  // Number of columns in the A matrix, to be cached between calls to *Factorize
+  // and *Solve.
+  size_t num_cols_ = 0;
+  // GPU memory allocated for the A matrix (lhs matrix).
+  CudaBuffer<double> lhs_;
+  // GPU memory allocated for the B matrix (rhs vector).
+  CudaBuffer<double> rhs_;
+  // GPU memory allocated for the TAU matrix (scaling of householder vectors).
+  CudaBuffer<double> tau_;
+  // Scratch space for cuSOLVER on the GPU.
+  CudaBuffer<double> device_workspace_;
+  // Required for error handling with cuSOLVER.
+  CudaBuffer<int> error_;
+  // Cache the result of Factorize to ensure that when Solve is called, the
+  // factiorization of lhs is valid.
+  LinearSolverTerminationType factorize_result_ =
+      LinearSolverTerminationType::FATAL_ERROR;
+};
+
+#endif  // CERES_NO_CUDA
+
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
+
+#endif  // CERES_INTERNAL_DENSE_QR_H_
diff --git a/third_party/ceres/internal/ceres/dense_qr_solver.cc b/third_party/ceres/internal/ceres/dense_qr_solver.cc
index 44388f3..92652b4 100644
--- a/third_party/ceres/internal/ceres/dense_qr_solver.cc
+++ b/third_party/ceres/internal/ceres/dense_qr_solver.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -33,137 +33,51 @@
 #include <cstddef>
 
 #include "Eigen/Dense"
+#include "ceres/dense_qr.h"
 #include "ceres/dense_sparse_matrix.h"
 #include "ceres/internal/eigen.h"
-#include "ceres/lapack.h"
 #include "ceres/linear_solver.h"
 #include "ceres/types.h"
 #include "ceres/wall_time.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 DenseQRSolver::DenseQRSolver(const LinearSolver::Options& options)
-    : options_(options) {
-  work_.resize(1);
-}
+    : options_(options), dense_qr_(DenseQR::Create(options)) {}
 
 LinearSolver::Summary DenseQRSolver::SolveImpl(
     DenseSparseMatrix* A,
     const double* b,
     const LinearSolver::PerSolveOptions& per_solve_options,
     double* x) {
-  if (options_.dense_linear_algebra_library_type == EIGEN) {
-    return SolveUsingEigen(A, b, per_solve_options, x);
-  } else {
-    return SolveUsingLAPACK(A, b, per_solve_options, x);
-  }
-}
-
-LinearSolver::Summary DenseQRSolver::SolveUsingLAPACK(
-    DenseSparseMatrix* A,
-    const double* b,
-    const LinearSolver::PerSolveOptions& per_solve_options,
-    double* x) {
   EventLogger event_logger("DenseQRSolver::Solve");
 
   const int num_rows = A->num_rows();
   const int num_cols = A->num_cols();
+  const int num_augmented_rows =
+      num_rows + ((per_solve_options.D != nullptr) ? num_cols : 0);
 
-  if (per_solve_options.D != NULL) {
-    // Temporarily append a diagonal block to the A matrix, but undo
-    // it before returning the matrix to the user.
-    A->AppendDiagonal(per_solve_options.D);
+  if (lhs_.rows() != num_augmented_rows || lhs_.cols() != num_cols) {
+    lhs_.resize(num_augmented_rows, num_cols);
+    rhs_.resize(num_augmented_rows);
   }
 
-  // TODO(sameeragarwal): Since we are copying anyways, the diagonal
-  // can be appended to the matrix instead of doing it on A.
-  lhs_ = A->matrix();
-
-  if (per_solve_options.D != NULL) {
-    // Undo the modifications to the matrix A.
-    A->RemoveDiagonal();
-  }
-
-  // rhs = [b;0] to account for the additional rows in the lhs.
-  if (rhs_.rows() != lhs_.rows()) {
-    rhs_.resize(lhs_.rows());
-  }
-  rhs_.setZero();
+  lhs_.topRows(num_rows) = A->matrix();
   rhs_.head(num_rows) = ConstVectorRef(b, num_rows);
 
-  if (work_.rows() == 1) {
-    const int work_size =
-        LAPACK::EstimateWorkSizeForQR(lhs_.rows(), lhs_.cols());
-    VLOG(3) << "Working memory for Dense QR factorization: "
-            << work_size * sizeof(double);
-    work_.resize(work_size);
+  if (num_rows != num_augmented_rows) {
+    lhs_.bottomRows(num_cols) =
+        ConstVectorRef(per_solve_options.D, num_cols).asDiagonal();
+    rhs_.tail(num_cols).setZero();
   }
 
   LinearSolver::Summary summary;
+  summary.termination_type = dense_qr_->FactorAndSolve(
+      lhs_.rows(), lhs_.cols(), lhs_.data(), rhs_.data(), x, &summary.message);
   summary.num_iterations = 1;
-  summary.termination_type = LAPACK::SolveInPlaceUsingQR(lhs_.rows(),
-                                                         lhs_.cols(),
-                                                         lhs_.data(),
-                                                         work_.rows(),
-                                                         work_.data(),
-                                                         rhs_.data(),
-                                                         &summary.message);
   event_logger.AddEvent("Solve");
-  if (summary.termination_type == LINEAR_SOLVER_SUCCESS) {
-    VectorRef(x, num_cols) = rhs_.head(num_cols);
-  }
 
-  event_logger.AddEvent("TearDown");
   return summary;
 }
 
-LinearSolver::Summary DenseQRSolver::SolveUsingEigen(
-    DenseSparseMatrix* A,
-    const double* b,
-    const LinearSolver::PerSolveOptions& per_solve_options,
-    double* x) {
-  EventLogger event_logger("DenseQRSolver::Solve");
-
-  const int num_rows = A->num_rows();
-  const int num_cols = A->num_cols();
-
-  if (per_solve_options.D != NULL) {
-    // Temporarily append a diagonal block to the A matrix, but undo
-    // it before returning the matrix to the user.
-    A->AppendDiagonal(per_solve_options.D);
-  }
-
-  // rhs = [b;0] to account for the additional rows in the lhs.
-  const int augmented_num_rows =
-      num_rows + ((per_solve_options.D != NULL) ? num_cols : 0);
-  if (rhs_.rows() != augmented_num_rows) {
-    rhs_.resize(augmented_num_rows);
-    rhs_.setZero();
-  }
-  rhs_.head(num_rows) = ConstVectorRef(b, num_rows);
-  event_logger.AddEvent("Setup");
-
-  // Solve the system.
-  VectorRef(x, num_cols) = A->matrix().householderQr().solve(rhs_);
-  event_logger.AddEvent("Solve");
-
-  if (per_solve_options.D != NULL) {
-    // Undo the modifications to the matrix A.
-    A->RemoveDiagonal();
-  }
-
-  // We always succeed, since the QR solver returns the best solution
-  // it can. It is the job of the caller to determine if the solution
-  // is good enough or not.
-  LinearSolver::Summary summary;
-  summary.num_iterations = 1;
-  summary.termination_type = LINEAR_SOLVER_SUCCESS;
-  summary.message = "Success.";
-
-  event_logger.AddEvent("TearDown");
-  return summary;
-}
-
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/dense_qr_solver.h b/third_party/ceres/internal/ceres/dense_qr_solver.h
index 980243b..12db52f 100644
--- a/third_party/ceres/internal/ceres/dense_qr_solver.h
+++ b/third_party/ceres/internal/ceres/dense_qr_solver.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -32,12 +32,15 @@
 #ifndef CERES_INTERNAL_DENSE_QR_SOLVER_H_
 #define CERES_INTERNAL_DENSE_QR_SOLVER_H_
 
+#include <memory>
+
+#include "ceres/dense_qr.h"
+#include "ceres/internal/disable_warnings.h"
 #include "ceres/internal/eigen.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 #include "ceres/linear_solver.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 class DenseSparseMatrix;
 
@@ -79,7 +82,7 @@
 // library. This solver always returns a solution, it is the user's
 // responsibility to judge if the solution is good enough for their
 // purposes.
-class CERES_EXPORT_INTERNAL DenseQRSolver : public DenseSparseMatrixSolver {
+class CERES_NO_EXPORT DenseQRSolver final : public DenseSparseMatrixSolver {
  public:
   explicit DenseQRSolver(const LinearSolver::Options& options);
 
@@ -105,10 +108,11 @@
   const LinearSolver::Options options_;
   ColMajorMatrix lhs_;
   Vector rhs_;
-  Vector work_;
+  std::unique_ptr<DenseQR> dense_qr_;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_DENSE_QR_SOLVER_H_
diff --git a/third_party/ceres/internal/ceres/dense_qr_test.cc b/third_party/ceres/internal/ceres/dense_qr_test.cc
new file mode 100644
index 0000000..155570c
--- /dev/null
+++ b/third_party/ceres/internal/ceres/dense_qr_test.cc
@@ -0,0 +1,130 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/dense_qr.h"
+
+#include <memory>
+#include <numeric>
+#include <string>
+#include <tuple>
+#include <vector>
+
+#include "Eigen/Dense"
+#include "ceres/internal/eigen.h"
+#include "ceres/linear_solver.h"
+#include "glog/logging.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace ceres::internal {
+
+using Param = DenseLinearAlgebraLibraryType;
+
+namespace {
+
+std::string ParamInfoToString(testing::TestParamInfo<Param> info) {
+  return DenseLinearAlgebraLibraryTypeToString(info.param);
+}
+
+}  // namespace
+
+class DenseQRTest : public ::testing::TestWithParam<Param> {};
+
+TEST_P(DenseQRTest, FactorAndSolve) {
+  // TODO(sameeragarwal): Convert these tests into type parameterized tests so
+  // that we can test the single and double precision solvers.
+
+  using Scalar = double;
+  using MatrixType = Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>;
+  using VectorType = Eigen::Matrix<Scalar, Eigen::Dynamic, 1>;
+
+  LinearSolver::Options options;
+  ContextImpl context;
+#ifndef CERES_NO_CUDA
+  options.context = &context;
+  std::string error;
+  CHECK(context.InitCuda(&error)) << error;
+#endif  // CERES_NO_CUDA
+  options.dense_linear_algebra_library_type = GetParam();
+  const double kEpsilon = std::numeric_limits<double>::epsilon() * 1.5e4;
+  std::unique_ptr<DenseQR> dense_qr = DenseQR::Create(options);
+
+  const int kNumTrials = 10;
+  const int kMinNumCols = 1;
+  const int kMaxNumCols = 10;
+  const int kMinRowsFactor = 1;
+  const int kMaxRowsFactor = 3;
+  for (int num_cols = kMinNumCols; num_cols < kMaxNumCols; ++num_cols) {
+    for (int num_rows = kMinRowsFactor * num_cols;
+         num_rows < kMaxRowsFactor * num_cols;
+         ++num_rows) {
+      for (int trial = 0; trial < kNumTrials; ++trial) {
+        MatrixType lhs = MatrixType::Random(num_rows, num_cols);
+        Vector x = VectorType::Random(num_cols);
+        Vector rhs = lhs * x;
+        Vector actual = Vector::Random(num_cols);
+        LinearSolver::Summary summary;
+        summary.termination_type = dense_qr->FactorAndSolve(num_rows,
+                                                            num_cols,
+                                                            lhs.data(),
+                                                            rhs.data(),
+                                                            actual.data(),
+                                                            &summary.message);
+        ASSERT_EQ(summary.termination_type,
+                  LinearSolverTerminationType::SUCCESS);
+        ASSERT_NEAR((x - actual).norm() / x.norm(), 0.0, kEpsilon)
+            << "\nexpected: " << x.transpose()
+            << "\nactual  : " << actual.transpose();
+      }
+    }
+  }
+}
+
+namespace {
+
+// NOTE: preprocessor directives in a macro are not standard conforming
+decltype(auto) MakeValues() {
+  return ::testing::Values(EIGEN
+#ifndef CERES_NO_LAPACK
+                           ,
+                           LAPACK
+#endif
+#ifndef CERES_NO_CUDA
+                           ,
+                           CUDA
+#endif
+  );
+}
+
+}  // namespace
+
+INSTANTIATE_TEST_SUITE_P(_, DenseQRTest, MakeValues(), ParamInfoToString);
+
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/dense_sparse_matrix.cc b/third_party/ceres/internal/ceres/dense_sparse_matrix.cc
index 53207fe..e0c917c 100644
--- a/third_party/ceres/internal/ceres/dense_sparse_matrix.cc
+++ b/third_party/ceres/internal/ceres/dense_sparse_matrix.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -31,38 +31,20 @@
 #include "ceres/dense_sparse_matrix.h"
 
 #include <algorithm>
+#include <utility>
 
 #include "ceres/internal/eigen.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 #include "ceres/triplet_sparse_matrix.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 DenseSparseMatrix::DenseSparseMatrix(int num_rows, int num_cols)
-    : has_diagonal_appended_(false), has_diagonal_reserved_(false) {
-  m_.resize(num_rows, num_cols);
-  m_.setZero();
-}
-
-DenseSparseMatrix::DenseSparseMatrix(int num_rows,
-                                     int num_cols,
-                                     bool reserve_diagonal)
-    : has_diagonal_appended_(false), has_diagonal_reserved_(reserve_diagonal) {
-  if (reserve_diagonal) {
-    // Allocate enough space for the diagonal.
-    m_.resize(num_rows + num_cols, num_cols);
-  } else {
-    m_.resize(num_rows, num_cols);
-  }
-  m_.setZero();
-}
+    : m_(Matrix(num_rows, num_cols)) {}
 
 DenseSparseMatrix::DenseSparseMatrix(const TripletSparseMatrix& m)
-    : m_(Eigen::MatrixXd::Zero(m.num_rows(), m.num_cols())),
-      has_diagonal_appended_(false),
-      has_diagonal_reserved_(false) {
+    : m_(Matrix::Zero(m.num_rows(), m.num_cols())) {
   const double* values = m.values();
   const int* rows = m.rows();
   const int* cols = m.cols();
@@ -73,22 +55,35 @@
   }
 }
 
-DenseSparseMatrix::DenseSparseMatrix(const ColMajorMatrix& m)
-    : m_(m), has_diagonal_appended_(false), has_diagonal_reserved_(false) {}
+DenseSparseMatrix::DenseSparseMatrix(Matrix m) : m_(std::move(m)) {}
 
 void DenseSparseMatrix::SetZero() { m_.setZero(); }
 
-void DenseSparseMatrix::RightMultiply(const double* x, double* y) const {
-  VectorRef(y, num_rows()) += matrix() * ConstVectorRef(x, num_cols());
+void DenseSparseMatrix::RightMultiplyAndAccumulate(const double* x,
+                                                   double* y) const {
+  VectorRef(y, num_rows()).noalias() += m_ * ConstVectorRef(x, num_cols());
 }
 
-void DenseSparseMatrix::LeftMultiply(const double* x, double* y) const {
-  VectorRef(y, num_cols()) +=
-      matrix().transpose() * ConstVectorRef(x, num_rows());
+void DenseSparseMatrix::LeftMultiplyAndAccumulate(const double* x,
+                                                  double* y) const {
+  VectorRef(y, num_cols()).noalias() +=
+      m_.transpose() * ConstVectorRef(x, num_rows());
 }
 
 void DenseSparseMatrix::SquaredColumnNorm(double* x) const {
-  VectorRef(x, num_cols()) = m_.colwise().squaredNorm();
+  // This implementation is 3x faster than the naive version
+  // x = m_.colwise().square().sum(), likely because m_
+  // is a row major matrix.
+
+  const int num_rows = m_.rows();
+  const int num_cols = m_.cols();
+  std::fill_n(x, num_cols, 0.0);
+  const double* m = m_.data();
+  for (int i = 0; i < num_rows; ++i) {
+    for (int j = 0; j < num_cols; ++j, ++m) {
+      x[j] += (*m) * (*m);
+    }
+  }
 }
 
 void DenseSparseMatrix::ScaleColumns(const double* scale) {
@@ -96,77 +91,26 @@
 }
 
 void DenseSparseMatrix::ToDenseMatrix(Matrix* dense_matrix) const {
-  *dense_matrix = m_.block(0, 0, num_rows(), num_cols());
+  *dense_matrix = m_;
 }
 
-void DenseSparseMatrix::AppendDiagonal(double* d) {
-  CHECK(!has_diagonal_appended_);
-  if (!has_diagonal_reserved_) {
-    ColMajorMatrix tmp = m_;
-    m_.resize(m_.rows() + m_.cols(), m_.cols());
-    m_.setZero();
-    m_.block(0, 0, tmp.rows(), tmp.cols()) = tmp;
-    has_diagonal_reserved_ = true;
-  }
-
-  m_.bottomLeftCorner(m_.cols(), m_.cols()) =
-      ConstVectorRef(d, m_.cols()).asDiagonal();
-  has_diagonal_appended_ = true;
-}
-
-void DenseSparseMatrix::RemoveDiagonal() {
-  CHECK(has_diagonal_appended_);
-  has_diagonal_appended_ = false;
-  // Leave the diagonal reserved.
-}
-
-int DenseSparseMatrix::num_rows() const {
-  if (has_diagonal_reserved_ && !has_diagonal_appended_) {
-    return m_.rows() - m_.cols();
-  }
-  return m_.rows();
-}
+int DenseSparseMatrix::num_rows() const { return m_.rows(); }
 
 int DenseSparseMatrix::num_cols() const { return m_.cols(); }
 
-int DenseSparseMatrix::num_nonzeros() const {
-  if (has_diagonal_reserved_ && !has_diagonal_appended_) {
-    return (m_.rows() - m_.cols()) * m_.cols();
-  }
-  return m_.rows() * m_.cols();
-}
+int DenseSparseMatrix::num_nonzeros() const { return m_.rows() * m_.cols(); }
 
-ConstColMajorMatrixRef DenseSparseMatrix::matrix() const {
-  return ConstColMajorMatrixRef(
-      m_.data(),
-      ((has_diagonal_reserved_ && !has_diagonal_appended_)
-           ? m_.rows() - m_.cols()
-           : m_.rows()),
-      m_.cols(),
-      Eigen::Stride<Eigen::Dynamic, 1>(m_.rows(), 1));
-}
+const Matrix& DenseSparseMatrix::matrix() const { return m_; }
 
-ColMajorMatrixRef DenseSparseMatrix::mutable_matrix() {
-  return ColMajorMatrixRef(m_.data(),
-                           ((has_diagonal_reserved_ && !has_diagonal_appended_)
-                                ? m_.rows() - m_.cols()
-                                : m_.rows()),
-                           m_.cols(),
-                           Eigen::Stride<Eigen::Dynamic, 1>(m_.rows(), 1));
-}
+Matrix* DenseSparseMatrix::mutable_matrix() { return &m_; }
 
 void DenseSparseMatrix::ToTextFile(FILE* file) const {
   CHECK(file != nullptr);
-  const int active_rows = (has_diagonal_reserved_ && !has_diagonal_appended_)
-                              ? (m_.rows() - m_.cols())
-                              : m_.rows();
-
-  for (int r = 0; r < active_rows; ++r) {
+  for (int r = 0; r < m_.rows(); ++r) {
     for (int c = 0; c < m_.cols(); ++c) {
       fprintf(file, "% 10d % 10d %17f\n", r, c, m_(r, c));
     }
   }
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/dense_sparse_matrix.h b/third_party/ceres/internal/ceres/dense_sparse_matrix.h
index 94064b3..dc066d5 100644
--- a/third_party/ceres/internal/ceres/dense_sparse_matrix.h
+++ b/third_party/ceres/internal/ceres/dense_sparse_matrix.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -33,32 +33,28 @@
 #ifndef CERES_INTERNAL_DENSE_SPARSE_MATRIX_H_
 #define CERES_INTERNAL_DENSE_SPARSE_MATRIX_H_
 
+#include "ceres/internal/disable_warnings.h"
 #include "ceres/internal/eigen.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 #include "ceres/sparse_matrix.h"
 #include "ceres/types.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 class TripletSparseMatrix;
 
-class CERES_EXPORT_INTERNAL DenseSparseMatrix : public SparseMatrix {
+class CERES_NO_EXPORT DenseSparseMatrix final : public SparseMatrix {
  public:
   // Build a matrix with the same content as the TripletSparseMatrix
   // m. This assumes that m does not have any repeated entries.
   explicit DenseSparseMatrix(const TripletSparseMatrix& m);
-  explicit DenseSparseMatrix(const ColMajorMatrix& m);
-
+  explicit DenseSparseMatrix(Matrix m);
   DenseSparseMatrix(int num_rows, int num_cols);
-  DenseSparseMatrix(int num_rows, int num_cols, bool reserve_diagonal);
-
-  virtual ~DenseSparseMatrix() {}
 
   // SparseMatrix interface.
   void SetZero() final;
-  void RightMultiply(const double* x, double* y) const final;
-  void LeftMultiply(const double* x, double* y) const final;
+  void RightMultiplyAndAccumulate(const double* x, double* y) const final;
+  void LeftMultiplyAndAccumulate(const double* x, double* y) const final;
   void SquaredColumnNorm(double* x) const final;
   void ScaleColumns(const double* scale) final;
   void ToDenseMatrix(Matrix* dense_matrix) const final;
@@ -69,40 +65,15 @@
   const double* values() const final { return m_.data(); }
   double* mutable_values() final { return m_.data(); }
 
-  ConstColMajorMatrixRef matrix() const;
-  ColMajorMatrixRef mutable_matrix();
-
-  // Only one diagonal can be appended at a time. The diagonal is appended to
-  // as a new set of rows, e.g.
-  //
-  // Original matrix:
-  //
-  //   x x x
-  //   x x x
-  //   x x x
-  //
-  // After append diagonal (1, 2, 3):
-  //
-  //   x x x
-  //   x x x
-  //   x x x
-  //   1 0 0
-  //   0 2 0
-  //   0 0 3
-  //
-  // Calling RemoveDiagonal removes the block. It is a fatal error to append a
-  // diagonal to a matrix that already has an appended diagonal, and it is also
-  // a fatal error to remove a diagonal from a matrix that has none.
-  void AppendDiagonal(double* d);
-  void RemoveDiagonal();
+  const Matrix& matrix() const;
+  Matrix* mutable_matrix();
 
  private:
-  ColMajorMatrix m_;
-  bool has_diagonal_appended_;
-  bool has_diagonal_reserved_;
+  Matrix m_;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_DENSE_SPARSE_MATRIX_H_
diff --git a/third_party/ceres/internal/ceres/dense_sparse_matrix_test.cc b/third_party/ceres/internal/ceres/dense_sparse_matrix_test.cc
index 2fa7216..0e50b62 100644
--- a/third_party/ceres/internal/ceres/dense_sparse_matrix_test.cc
+++ b/third_party/ceres/internal/ceres/dense_sparse_matrix_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -43,8 +43,7 @@
 #include "glog/logging.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 static void CompareMatrices(const SparseMatrix* a, const SparseMatrix* b) {
   EXPECT_EQ(a->num_rows(), b->num_rows());
@@ -60,8 +59,8 @@
     Vector y_a = Vector::Zero(num_rows);
     Vector y_b = Vector::Zero(num_rows);
 
-    a->RightMultiply(x.data(), y_a.data());
-    b->RightMultiply(x.data(), y_b.data());
+    a->RightMultiplyAndAccumulate(x.data(), y_a.data());
+    b->RightMultiplyAndAccumulate(x.data(), y_b.data());
 
     EXPECT_EQ((y_a - y_b).norm(), 0);
   }
@@ -70,13 +69,13 @@
 class DenseSparseMatrixTest : public ::testing::Test {
  protected:
   void SetUp() final {
-    std::unique_ptr<LinearLeastSquaresProblem> problem(
-        CreateLinearLeastSquaresProblemFromId(1));
+    std::unique_ptr<LinearLeastSquaresProblem> problem =
+        CreateLinearLeastSquaresProblemFromId(1);
 
     CHECK(problem != nullptr);
 
     tsm.reset(down_cast<TripletSparseMatrix*>(problem->A.release()));
-    dsm.reset(new DenseSparseMatrix(*tsm));
+    dsm = std::make_unique<DenseSparseMatrix>(*tsm);
 
     num_rows = tsm->num_rows();
     num_cols = tsm->num_cols();
@@ -89,7 +88,7 @@
   std::unique_ptr<DenseSparseMatrix> dsm;
 };
 
-TEST_F(DenseSparseMatrixTest, RightMultiply) {
+TEST_F(DenseSparseMatrixTest, RightMultiplyAndAccumulate) {
   CompareMatrices(tsm.get(), dsm.get());
 
   // Try with a not entirely zero vector to verify column interactions, which
@@ -101,13 +100,13 @@
   Vector b1 = Vector::Zero(num_rows);
   Vector b2 = Vector::Zero(num_rows);
 
-  tsm->RightMultiply(a.data(), b1.data());
-  dsm->RightMultiply(a.data(), b2.data());
+  tsm->RightMultiplyAndAccumulate(a.data(), b1.data());
+  dsm->RightMultiplyAndAccumulate(a.data(), b2.data());
 
   EXPECT_EQ((b1 - b2).norm(), 0);
 }
 
-TEST_F(DenseSparseMatrixTest, LeftMultiply) {
+TEST_F(DenseSparseMatrixTest, LeftMultiplyAndAccumulate) {
   for (int i = 0; i < num_rows; ++i) {
     Vector a = Vector::Zero(num_rows);
     a(i) = 1.0;
@@ -115,8 +114,8 @@
     Vector b1 = Vector::Zero(num_cols);
     Vector b2 = Vector::Zero(num_cols);
 
-    tsm->LeftMultiply(a.data(), b1.data());
-    dsm->LeftMultiply(a.data(), b2.data());
+    tsm->LeftMultiplyAndAccumulate(a.data(), b1.data());
+    dsm->LeftMultiplyAndAccumulate(a.data(), b2.data());
 
     EXPECT_EQ((b1 - b2).norm(), 0);
   }
@@ -130,8 +129,8 @@
   Vector b1 = Vector::Zero(num_cols);
   Vector b2 = Vector::Zero(num_cols);
 
-  tsm->LeftMultiply(a.data(), b1.data());
-  dsm->LeftMultiply(a.data(), b2.data());
+  tsm->LeftMultiplyAndAccumulate(a.data(), b1.data());
+  dsm->LeftMultiplyAndAccumulate(a.data(), b2.data());
 
   EXPECT_EQ((b1 - b2).norm(), 0);
 }
@@ -166,5 +165,4 @@
   EXPECT_EQ((tsm_dense - dsm_dense).norm(), 0.0);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/detect_structure.cc b/third_party/ceres/internal/ceres/detect_structure.cc
index 4aac445..e82d70f 100644
--- a/third_party/ceres/internal/ceres/detect_structure.cc
+++ b/third_party/ceres/internal/ceres/detect_structure.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -33,8 +33,7 @@
 #include "ceres/internal/eigen.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 void DetectStructure(const CompressedRowBlockStructure& bs,
                      const int num_eliminate_blocks,
@@ -119,5 +118,4 @@
   // clang-format on
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/detect_structure.h b/third_party/ceres/internal/ceres/detect_structure.h
index 0624230..3237d10 100644
--- a/third_party/ceres/internal/ceres/detect_structure.h
+++ b/third_party/ceres/internal/ceres/detect_structure.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -32,10 +32,10 @@
 #define CERES_INTERNAL_DETECT_STRUCTURE_H_
 
 #include "ceres/block_structure.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // Detect static blocks in the problem sparsity. For rows containing
 // e_blocks, we are interested in detecting if the size of the row
@@ -56,13 +56,14 @@
 // Note: The structure of rows without any e-blocks has no effect on
 // the values returned by this function. It is entirely possible that
 // the f_block_size and row_blocks_size is not constant in such rows.
-void CERES_EXPORT DetectStructure(const CompressedRowBlockStructure& bs,
-                                  const int num_eliminate_blocks,
-                                  int* row_block_size,
-                                  int* e_block_size,
-                                  int* f_block_size);
+void CERES_NO_EXPORT DetectStructure(const CompressedRowBlockStructure& bs,
+                                     const int num_eliminate_blocks,
+                                     int* row_block_size,
+                                     int* e_block_size,
+                                     int* f_block_size);
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_DETECT_STRUCTURE_H_
diff --git a/third_party/ceres/internal/ceres/detect_structure_test.cc b/third_party/ceres/internal/ceres/detect_structure_test.cc
index 8f9c5ed..e4e3f1d 100644
--- a/third_party/ceres/internal/ceres/detect_structure_test.cc
+++ b/third_party/ceres/internal/ceres/detect_structure_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -45,34 +45,34 @@
 
   CompressedRowBlockStructure bs;
 
-  bs.cols.push_back(Block());
+  bs.cols.emplace_back();
   bs.cols.back().size = 3;
   bs.cols.back().position = 0;
 
-  bs.cols.push_back(Block());
+  bs.cols.emplace_back();
   bs.cols.back().size = 4;
   bs.cols.back().position = 3;
 
-  bs.cols.push_back(Block());
+  bs.cols.emplace_back();
   bs.cols.back().size = 4;
   bs.cols.back().position = 7;
 
   {
-    bs.rows.push_back(CompressedRow());
+    bs.rows.emplace_back();
     CompressedRow& row = bs.rows.back();
     row.block.size = 2;
     row.block.position = 0;
-    row.cells.push_back(Cell(0, 0));
-    row.cells.push_back(Cell(1, 0));
+    row.cells.emplace_back(0, 0);
+    row.cells.emplace_back(1, 0);
   }
 
   {
-    bs.rows.push_back(CompressedRow());
+    bs.rows.emplace_back();
     CompressedRow& row = bs.rows.back();
     row.block.size = 2;
     row.block.position = 2;
-    row.cells.push_back(Cell(0, 0));
-    row.cells.push_back(Cell(2, 0));
+    row.cells.emplace_back(0, 0);
+    row.cells.emplace_back(2, 0);
   }
 
   int row_block_size = 0;
@@ -94,34 +94,34 @@
 
   CompressedRowBlockStructure bs;
 
-  bs.cols.push_back(Block());
+  bs.cols.emplace_back();
   bs.cols.back().size = 3;
   bs.cols.back().position = 0;
 
-  bs.cols.push_back(Block());
+  bs.cols.emplace_back();
   bs.cols.back().size = 4;
   bs.cols.back().position = 3;
 
-  bs.cols.push_back(Block());
+  bs.cols.emplace_back();
   bs.cols.back().size = 4;
   bs.cols.back().position = 7;
 
   {
-    bs.rows.push_back(CompressedRow());
+    bs.rows.emplace_back();
     CompressedRow& row = bs.rows.back();
     row.block.size = 2;
     row.block.position = 0;
-    row.cells.push_back(Cell(0, 0));
-    row.cells.push_back(Cell(1, 0));
+    row.cells.emplace_back(0, 0);
+    row.cells.emplace_back(1, 0);
   }
 
   {
-    bs.rows.push_back(CompressedRow());
+    bs.rows.emplace_back();
     CompressedRow& row = bs.rows.back();
     row.block.size = 1;
     row.block.position = 2;
-    row.cells.push_back(Cell(0, 0));
-    row.cells.push_back(Cell(2, 0));
+    row.cells.emplace_back(0, 0);
+    row.cells.emplace_back(2, 0);
   }
 
   int row_block_size = 0;
@@ -143,34 +143,34 @@
 
   CompressedRowBlockStructure bs;
 
-  bs.cols.push_back(Block());
+  bs.cols.emplace_back();
   bs.cols.back().size = 3;
   bs.cols.back().position = 0;
 
-  bs.cols.push_back(Block());
+  bs.cols.emplace_back();
   bs.cols.back().size = 4;
   bs.cols.back().position = 3;
 
-  bs.cols.push_back(Block());
+  bs.cols.emplace_back();
   bs.cols.back().size = 3;
   bs.cols.back().position = 7;
 
   {
-    bs.rows.push_back(CompressedRow());
+    bs.rows.emplace_back();
     CompressedRow& row = bs.rows.back();
     row.block.size = 2;
     row.block.position = 0;
-    row.cells.push_back(Cell(0, 0));
-    row.cells.push_back(Cell(1, 0));
+    row.cells.emplace_back(0, 0);
+    row.cells.emplace_back(1, 0);
   }
 
   {
-    bs.rows.push_back(CompressedRow());
+    bs.rows.emplace_back();
     CompressedRow& row = bs.rows.back();
     row.block.size = 2;
     row.block.position = 2;
-    row.cells.push_back(Cell(0, 0));
-    row.cells.push_back(Cell(2, 0));
+    row.cells.emplace_back(0, 0);
+    row.cells.emplace_back(2, 0);
   }
 
   int row_block_size = 0;
@@ -192,34 +192,34 @@
 
   CompressedRowBlockStructure bs;
 
-  bs.cols.push_back(Block());
+  bs.cols.emplace_back();
   bs.cols.back().size = 3;
   bs.cols.back().position = 0;
 
-  bs.cols.push_back(Block());
+  bs.cols.emplace_back();
   bs.cols.back().size = 4;
   bs.cols.back().position = 3;
 
-  bs.cols.push_back(Block());
+  bs.cols.emplace_back();
   bs.cols.back().size = 3;
   bs.cols.back().position = 7;
 
   {
-    bs.rows.push_back(CompressedRow());
+    bs.rows.emplace_back();
     CompressedRow& row = bs.rows.back();
     row.block.size = 2;
     row.block.position = 0;
-    row.cells.push_back(Cell(0, 0));
-    row.cells.push_back(Cell(2, 0));
+    row.cells.emplace_back(0, 0);
+    row.cells.emplace_back(2, 0);
   }
 
   {
-    bs.rows.push_back(CompressedRow());
+    bs.rows.emplace_back();
     CompressedRow& row = bs.rows.back();
     row.block.size = 2;
     row.block.position = 2;
-    row.cells.push_back(Cell(1, 0));
-    row.cells.push_back(Cell(2, 0));
+    row.cells.emplace_back(1, 0);
+    row.cells.emplace_back(2, 0);
   }
 
   int row_block_size = 0;
@@ -241,26 +241,26 @@
 
   CompressedRowBlockStructure bs;
 
-  bs.cols.push_back(Block());
+  bs.cols.emplace_back();
   bs.cols.back().size = 3;
   bs.cols.back().position = 0;
 
-  bs.cols.push_back(Block());
+  bs.cols.emplace_back();
   bs.cols.back().size = 4;
   bs.cols.back().position = 3;
 
-  bs.cols.push_back(Block());
+  bs.cols.emplace_back();
   bs.cols.back().size = 3;
   bs.cols.back().position = 7;
 
   {
-    bs.rows.push_back(CompressedRow());
+    bs.rows.emplace_back();
     CompressedRow& row = bs.rows.back();
     row.block.size = 2;
     row.block.position = 0;
-    row.cells.push_back(Cell(0, 0));
-    row.cells.push_back(Cell(1, 0));
-    row.cells.push_back(Cell(2, 0));
+    row.cells.emplace_back(0, 0);
+    row.cells.emplace_back(1, 0);
+    row.cells.emplace_back(2, 0);
   }
 
   int row_block_size = 0;
diff --git a/third_party/ceres/internal/ceres/dogleg_strategy.cc b/third_party/ceres/internal/ceres/dogleg_strategy.cc
index 03ae22f..877d8d9 100644
--- a/third_party/ceres/internal/ceres/dogleg_strategy.cc
+++ b/third_party/ceres/internal/ceres/dogleg_strategy.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -44,8 +44,7 @@
 #include "ceres/types.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 namespace {
 const double kMaxMu = 1.0;
 const double kMinMu = 1e-8;
@@ -101,7 +100,7 @@
     }
     TrustRegionStrategy::Summary summary;
     summary.num_iterations = 0;
-    summary.termination_type = LINEAR_SOLVER_SUCCESS;
+    summary.termination_type = LinearSolverTerminationType::SUCCESS;
     return summary;
   }
 
@@ -138,11 +137,13 @@
   summary.num_iterations = linear_solver_summary.num_iterations;
   summary.termination_type = linear_solver_summary.termination_type;
 
-  if (linear_solver_summary.termination_type == LINEAR_SOLVER_FATAL_ERROR) {
+  if (linear_solver_summary.termination_type ==
+      LinearSolverTerminationType::FATAL_ERROR) {
     return summary;
   }
 
-  if (linear_solver_summary.termination_type != LINEAR_SOLVER_FAILURE) {
+  if (linear_solver_summary.termination_type !=
+      LinearSolverTerminationType::FAILURE) {
     switch (dogleg_type_) {
       // Interpolate the Cauchy point and the Gauss-Newton step.
       case TRADITIONAL_DOGLEG:
@@ -153,7 +154,7 @@
       // Cauchy point and the (Gauss-)Newton step.
       case SUBSPACE_DOGLEG:
         if (!ComputeSubspaceModel(jacobian)) {
-          summary.termination_type = LINEAR_SOLVER_FAILURE;
+          summary.termination_type = LinearSolverTerminationType::FAILURE;
           break;
         }
         ComputeSubspaceDoglegStep(step);
@@ -174,7 +175,7 @@
 void DoglegStrategy::ComputeGradient(SparseMatrix* jacobian,
                                      const double* residuals) {
   gradient_.setZero();
-  jacobian->LeftMultiply(residuals, gradient_.data());
+  jacobian->LeftMultiplyAndAccumulate(residuals, gradient_.data());
   gradient_.array() /= diagonal_.array();
 }
 
@@ -187,7 +188,7 @@
   // The Jacobian is scaled implicitly by computing J * (D^-1 * (D^-1 * g))
   // instead of (J * D^-1) * (D^-1 * g).
   Vector scaled_gradient = (gradient_.array() / diagonal_.array()).matrix();
-  jacobian->RightMultiply(scaled_gradient.data(), Jg.data());
+  jacobian->RightMultiplyAndAccumulate(scaled_gradient.data(), Jg.data());
   alpha_ = gradient_.squaredNorm() / Jg.squaredNorm();
 }
 
@@ -480,7 +481,7 @@
 
   // Find the real parts y_i of its roots (not only the real roots).
   Vector roots_real;
-  if (!FindPolynomialRoots(polynomial, &roots_real, NULL)) {
+  if (!FindPolynomialRoots(polynomial, &roots_real, nullptr)) {
     // Failed to find the roots of the polynomial, i.e. the candidate
     // solutions of the constrained problem. Report this back to the caller.
     return false;
@@ -518,7 +519,7 @@
     const double* residuals) {
   const int n = jacobian->num_cols();
   LinearSolver::Summary linear_solver_summary;
-  linear_solver_summary.termination_type = LINEAR_SOLVER_FAILURE;
+  linear_solver_summary.termination_type = LinearSolverTerminationType::FAILURE;
 
   // The Jacobian matrix is often quite poorly conditioned. Thus it is
   // necessary to add a diagonal matrix at the bottom to prevent the
@@ -531,7 +532,7 @@
   // If the solve fails, the multiplier to the diagonal is increased
   // up to max_mu_ by a factor of mu_increase_factor_ every time. If
   // the linear solver is still not successful, the strategy returns
-  // with LINEAR_SOLVER_FAILURE.
+  // with LinearSolverTerminationType::FAILURE.
   //
   // Next time when a new Gauss-Newton step is requested, the
   // multiplier starts out from the last successful solve.
@@ -582,21 +583,25 @@
       }
     }
 
-    if (linear_solver_summary.termination_type == LINEAR_SOLVER_FATAL_ERROR) {
+    if (linear_solver_summary.termination_type ==
+        LinearSolverTerminationType::FATAL_ERROR) {
       return linear_solver_summary;
     }
 
-    if (linear_solver_summary.termination_type == LINEAR_SOLVER_FAILURE ||
+    if (linear_solver_summary.termination_type ==
+            LinearSolverTerminationType::FAILURE ||
         !IsArrayValid(n, gauss_newton_step_.data())) {
       mu_ *= mu_increase_factor_;
       VLOG(2) << "Increasing mu " << mu_;
-      linear_solver_summary.termination_type = LINEAR_SOLVER_FAILURE;
+      linear_solver_summary.termination_type =
+          LinearSolverTerminationType::FAILURE;
       continue;
     }
     break;
   }
 
-  if (linear_solver_summary.termination_type != LINEAR_SOLVER_FAILURE) {
+  if (linear_solver_summary.termination_type !=
+      LinearSolverTerminationType::FAILURE) {
     // The scaled Gauss-Newton step is D * GN:
     //
     //     - (D^-1 J^T J D^-1)^-1 (D^-1 g)
@@ -627,7 +632,7 @@
   reuse_ = false;
 }
 
-void DoglegStrategy::StepRejected(double step_quality) {
+void DoglegStrategy::StepRejected(double /*step_quality*/) {
   radius_ *= 0.5;
   reuse_ = true;
 }
@@ -701,14 +706,13 @@
 
   Vector tmp;
   tmp = (subspace_basis_.col(0).array() / diagonal_.array()).matrix();
-  jacobian->RightMultiply(tmp.data(), Jb.row(0).data());
+  jacobian->RightMultiplyAndAccumulate(tmp.data(), Jb.row(0).data());
   tmp = (subspace_basis_.col(1).array() / diagonal_.array()).matrix();
-  jacobian->RightMultiply(tmp.data(), Jb.row(1).data());
+  jacobian->RightMultiplyAndAccumulate(tmp.data(), Jb.row(1).data());
 
   subspace_B_ = Jb * Jb.transpose();
 
   return true;
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/dogleg_strategy.h b/third_party/ceres/internal/ceres/dogleg_strategy.h
index cc3778e..b4d29c9 100644
--- a/third_party/ceres/internal/ceres/dogleg_strategy.h
+++ b/third_party/ceres/internal/ceres/dogleg_strategy.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -31,12 +31,12 @@
 #ifndef CERES_INTERNAL_DOGLEG_STRATEGY_H_
 #define CERES_INTERNAL_DOGLEG_STRATEGY_H_
 
-#include "ceres/internal/port.h"
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 #include "ceres/linear_solver.h"
 #include "ceres/trust_region_strategy.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // Dogleg step computation and trust region sizing strategy based on
 // on "Methods for Nonlinear Least Squares" by K. Madsen, H.B. Nielsen
@@ -53,10 +53,9 @@
 // DoglegStrategy follows the approach by Shultz, Schnabel, Byrd.
 // This finds the exact optimum over the two-dimensional subspace
 // spanned by the two Dogleg vectors.
-class CERES_EXPORT_INTERNAL DoglegStrategy : public TrustRegionStrategy {
+class CERES_NO_EXPORT DoglegStrategy final : public TrustRegionStrategy {
  public:
   explicit DoglegStrategy(const TrustRegionStrategy::Options& options);
-  virtual ~DoglegStrategy() {}
 
   // TrustRegionStrategy interface
   Summary ComputeStep(const PerSolveOptions& per_solve_options,
@@ -65,7 +64,7 @@
                       double* step) final;
   void StepAccepted(double step_quality) final;
   void StepRejected(double step_quality) final;
-  void StepIsInvalid();
+  void StepIsInvalid() override;
   double Radius() const final;
 
   // These functions are predominantly for testing.
@@ -76,8 +75,8 @@
   Matrix subspace_B() const { return subspace_B_; }
 
  private:
-  typedef Eigen::Matrix<double, 2, 1, Eigen::DontAlign> Vector2d;
-  typedef Eigen::Matrix<double, 2, 2, Eigen::DontAlign> Matrix2d;
+  using Vector2d = Eigen::Matrix<double, 2, 1, Eigen::DontAlign>;
+  using Matrix2d = Eigen::Matrix<double, 2, 2, Eigen::DontAlign>;
 
   LinearSolver::Summary ComputeGaussNewtonStep(
       const PerSolveOptions& per_solve_options,
@@ -159,7 +158,8 @@
   Matrix2d subspace_B_;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_DOGLEG_STRATEGY_H_
diff --git a/third_party/ceres/internal/ceres/dogleg_strategy_test.cc b/third_party/ceres/internal/ceres/dogleg_strategy_test.cc
index 0c20f25..b256f3e 100644
--- a/third_party/ceres/internal/ceres/dogleg_strategy_test.cc
+++ b/third_party/ceres/internal/ceres/dogleg_strategy_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,8 +40,7 @@
 #include "glog/logging.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 namespace {
 
 class Fixture : public testing::Test {
@@ -79,7 +78,7 @@
 
     Matrix sqrtD = Ddiag.array().sqrt().matrix().asDiagonal();
     Matrix jacobian = sqrtD * basis;
-    jacobian_.reset(new DenseSparseMatrix(jacobian));
+    jacobian_ = std::make_unique<DenseSparseMatrix>(jacobian);
 
     Vector minimum(6);
     minimum << 1.0, 1.0, 1.0, 1.0, 1.0, 1.0;
@@ -107,7 +106,7 @@
     Ddiag << 1.0, 2.0, 4.0, 8.0, 16.0, 32.0;
 
     Matrix jacobian = Ddiag.asDiagonal();
-    jacobian_.reset(new DenseSparseMatrix(jacobian));
+    jacobian_ = std::make_unique<DenseSparseMatrix>(jacobian);
 
     Vector minimum(6);
     minimum << 0.0, 0.0, 1.0, 0.0, 0.0, 0.0;
@@ -146,7 +145,7 @@
   TrustRegionStrategy::Summary summary =
       strategy.ComputeStep(pso, jacobian_.get(), residual_.data(), x_.data());
 
-  EXPECT_NE(summary.termination_type, LINEAR_SOLVER_FAILURE);
+  EXPECT_NE(summary.termination_type, LinearSolverTerminationType::FAILURE);
   EXPECT_LE(x_.norm(), options_.initial_radius * (1.0 + 4.0 * kEpsilon));
 }
 
@@ -164,7 +163,7 @@
   TrustRegionStrategy::Summary summary =
       strategy.ComputeStep(pso, jacobian_.get(), residual_.data(), x_.data());
 
-  EXPECT_NE(summary.termination_type, LINEAR_SOLVER_FAILURE);
+  EXPECT_NE(summary.termination_type, LinearSolverTerminationType::FAILURE);
   EXPECT_LE(x_.norm(), options_.initial_radius * (1.0 + 4.0 * kEpsilon));
 }
 
@@ -182,7 +181,7 @@
   TrustRegionStrategy::Summary summary =
       strategy.ComputeStep(pso, jacobian_.get(), residual_.data(), x_.data());
 
-  EXPECT_NE(summary.termination_type, LINEAR_SOLVER_FAILURE);
+  EXPECT_NE(summary.termination_type, LinearSolverTerminationType::FAILURE);
   EXPECT_NEAR(x_(0), 1.0, kToleranceLoose);
   EXPECT_NEAR(x_(1), 1.0, kToleranceLoose);
   EXPECT_NEAR(x_(2), 1.0, kToleranceLoose);
@@ -240,7 +239,7 @@
   TrustRegionStrategy::Summary summary =
       strategy.ComputeStep(pso, jacobian_.get(), residual_.data(), x_.data());
 
-  EXPECT_NE(summary.termination_type, LINEAR_SOLVER_FAILURE);
+  EXPECT_NE(summary.termination_type, LinearSolverTerminationType::FAILURE);
   EXPECT_NEAR(x_(0), 0.0, kToleranceLoose);
   EXPECT_NEAR(x_(1), 0.0, kToleranceLoose);
   EXPECT_NEAR(x_(2), options_.initial_radius, kToleranceLoose);
@@ -266,7 +265,7 @@
   TrustRegionStrategy::Summary summary =
       strategy.ComputeStep(pso, jacobian_.get(), residual_.data(), x_.data());
 
-  EXPECT_NE(summary.termination_type, LINEAR_SOLVER_FAILURE);
+  EXPECT_NE(summary.termination_type, LinearSolverTerminationType::FAILURE);
   EXPECT_NEAR(x_(0), 0.0, kToleranceLoose);
   EXPECT_NEAR(x_(1), 0.0, kToleranceLoose);
   EXPECT_NEAR(x_(2), 1.0, kToleranceLoose);
@@ -275,5 +274,4 @@
   EXPECT_NEAR(x_(5), 0.0, kToleranceLoose);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/dynamic_autodiff_cost_function_test.cc b/third_party/ceres/internal/ceres/dynamic_autodiff_cost_function_test.cc
index 55d3fe1..51366c6 100644
--- a/third_party/ceres/internal/ceres/dynamic_autodiff_cost_function_test.cc
+++ b/third_party/ceres/internal/ceres/dynamic_autodiff_cost_function_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2024 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -34,13 +34,12 @@
 
 #include <cstddef>
 #include <memory>
+#include <vector>
 
+#include "ceres/types.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
-
-using std::vector;
+namespace ceres::internal {
 
 // Takes 2 parameter blocks:
 //     parameters[0] is size 10.
@@ -75,8 +74,8 @@
 };
 
 TEST(DynamicAutodiffCostFunctionTest, TestResiduals) {
-  vector<double> param_block_0(10, 0.0);
-  vector<double> param_block_1(5, 0.0);
+  std::vector<double> param_block_0(10, 0.0);
+  std::vector<double> param_block_1(5, 0.0);
   DynamicAutoDiffCostFunction<MyCostFunctor, 3> cost_function(
       new MyCostFunctor());
   cost_function.AddParameterBlock(param_block_0.size());
@@ -84,12 +83,12 @@
   cost_function.SetNumResiduals(21);
 
   // Test residual computation.
-  vector<double> residuals(21, -100000);
-  vector<double*> parameter_blocks(2);
+  std::vector<double> residuals(21, -100000);
+  std::vector<double*> parameter_blocks(2);
   parameter_blocks[0] = &param_block_0[0];
   parameter_blocks[1] = &param_block_1[0];
   EXPECT_TRUE(
-      cost_function.Evaluate(&parameter_blocks[0], residuals.data(), NULL));
+      cost_function.Evaluate(&parameter_blocks[0], residuals.data(), nullptr));
   for (int r = 0; r < 10; ++r) {
     EXPECT_EQ(1.0 * r, residuals.at(r * 2));
     EXPECT_EQ(-1.0 * r, residuals.at(r * 2 + 1));
@@ -99,11 +98,11 @@
 
 TEST(DynamicAutodiffCostFunctionTest, TestJacobian) {
   // Test the residual counting.
-  vector<double> param_block_0(10, 0.0);
+  std::vector<double> param_block_0(10, 0.0);
   for (int i = 0; i < 10; ++i) {
     param_block_0[i] = 2 * i;
   }
-  vector<double> param_block_1(5, 0.0);
+  std::vector<double> param_block_1(5, 0.0);
   DynamicAutoDiffCostFunction<MyCostFunctor, 3> cost_function(
       new MyCostFunctor());
   cost_function.AddParameterBlock(param_block_0.size());
@@ -111,18 +110,18 @@
   cost_function.SetNumResiduals(21);
 
   // Prepare the residuals.
-  vector<double> residuals(21, -100000);
+  std::vector<double> residuals(21, -100000);
 
   // Prepare the parameters.
-  vector<double*> parameter_blocks(2);
+  std::vector<double*> parameter_blocks(2);
   parameter_blocks[0] = &param_block_0[0];
   parameter_blocks[1] = &param_block_1[0];
 
   // Prepare the jacobian.
-  vector<vector<double>> jacobian_vect(2);
+  std::vector<std::vector<double>> jacobian_vect(2);
   jacobian_vect[0].resize(21 * 10, -100000);
   jacobian_vect[1].resize(21 * 5, -100000);
-  vector<double*> jacobian;
+  std::vector<double*> jacobian;
   jacobian.push_back(jacobian_vect[0].data());
   jacobian.push_back(jacobian_vect[1].data());
 
@@ -149,8 +148,8 @@
     EXPECT_EQ(4 * p - 8, jacobian_vect[0][20 * 10 + p]);
     jacobian_vect[0][20 * 10 + p] = 0.0;
   }
-  for (int i = 0; i < jacobian_vect[0].size(); ++i) {
-    EXPECT_EQ(0.0, jacobian_vect[0][i]);
+  for (double entry : jacobian_vect[0]) {
+    EXPECT_EQ(0.0, entry);
   }
 
   // Check "C" Jacobian for second parameter block.
@@ -158,18 +157,18 @@
     EXPECT_EQ(1.0, jacobian_vect[1][20 * 5 + p]);
     jacobian_vect[1][20 * 5 + p] = 0.0;
   }
-  for (int i = 0; i < jacobian_vect[1].size(); ++i) {
-    EXPECT_EQ(0.0, jacobian_vect[1][i]);
+  for (double entry : jacobian_vect[1]) {
+    EXPECT_EQ(0.0, entry);
   }
 }
 
 TEST(DynamicAutodiffCostFunctionTest, JacobianWithFirstParameterBlockConstant) {
   // Test the residual counting.
-  vector<double> param_block_0(10, 0.0);
+  std::vector<double> param_block_0(10, 0.0);
   for (int i = 0; i < 10; ++i) {
     param_block_0[i] = 2 * i;
   }
-  vector<double> param_block_1(5, 0.0);
+  std::vector<double> param_block_1(5, 0.0);
   DynamicAutoDiffCostFunction<MyCostFunctor, 3> cost_function(
       new MyCostFunctor());
   cost_function.AddParameterBlock(param_block_0.size());
@@ -177,19 +176,19 @@
   cost_function.SetNumResiduals(21);
 
   // Prepare the residuals.
-  vector<double> residuals(21, -100000);
+  std::vector<double> residuals(21, -100000);
 
   // Prepare the parameters.
-  vector<double*> parameter_blocks(2);
+  std::vector<double*> parameter_blocks(2);
   parameter_blocks[0] = &param_block_0[0];
   parameter_blocks[1] = &param_block_1[0];
 
   // Prepare the jacobian.
-  vector<vector<double>> jacobian_vect(2);
+  std::vector<std::vector<double>> jacobian_vect(2);
   jacobian_vect[0].resize(21 * 10, -100000);
   jacobian_vect[1].resize(21 * 5, -100000);
-  vector<double*> jacobian;
-  jacobian.push_back(NULL);
+  std::vector<double*> jacobian;
+  jacobian.push_back(nullptr);
   jacobian.push_back(jacobian_vect[1].data());
 
   // Test jacobian computation.
@@ -207,19 +206,19 @@
     EXPECT_EQ(1.0, jacobian_vect[1][20 * 5 + p]);
     jacobian_vect[1][20 * 5 + p] = 0.0;
   }
-  for (int i = 0; i < jacobian_vect[1].size(); ++i) {
-    EXPECT_EQ(0.0, jacobian_vect[1][i]);
+  for (double& i : jacobian_vect[1]) {
+    EXPECT_EQ(0.0, i);
   }
 }
 
 TEST(DynamicAutodiffCostFunctionTest,
      JacobianWithSecondParameterBlockConstant) {  // NOLINT
   // Test the residual counting.
-  vector<double> param_block_0(10, 0.0);
+  std::vector<double> param_block_0(10, 0.0);
   for (int i = 0; i < 10; ++i) {
     param_block_0[i] = 2 * i;
   }
-  vector<double> param_block_1(5, 0.0);
+  std::vector<double> param_block_1(5, 0.0);
   DynamicAutoDiffCostFunction<MyCostFunctor, 3> cost_function(
       new MyCostFunctor());
   cost_function.AddParameterBlock(param_block_0.size());
@@ -227,20 +226,20 @@
   cost_function.SetNumResiduals(21);
 
   // Prepare the residuals.
-  vector<double> residuals(21, -100000);
+  std::vector<double> residuals(21, -100000);
 
   // Prepare the parameters.
-  vector<double*> parameter_blocks(2);
+  std::vector<double*> parameter_blocks(2);
   parameter_blocks[0] = &param_block_0[0];
   parameter_blocks[1] = &param_block_1[0];
 
   // Prepare the jacobian.
-  vector<vector<double>> jacobian_vect(2);
+  std::vector<std::vector<double>> jacobian_vect(2);
   jacobian_vect[0].resize(21 * 10, -100000);
   jacobian_vect[1].resize(21 * 5, -100000);
-  vector<double*> jacobian;
+  std::vector<double*> jacobian;
   jacobian.push_back(jacobian_vect[0].data());
-  jacobian.push_back(NULL);
+  jacobian.push_back(nullptr);
 
   // Test jacobian computation.
   EXPECT_TRUE(cost_function.Evaluate(
@@ -265,8 +264,8 @@
     EXPECT_EQ(4 * p - 8, jacobian_vect[0][20 * 10 + p]);
     jacobian_vect[0][20 * 10 + p] = 0.0;
   }
-  for (int i = 0; i < jacobian_vect[0].size(); ++i) {
-    EXPECT_EQ(0.0, jacobian_vect[0][i]);
+  for (double& i : jacobian_vect[0]) {
+    EXPECT_EQ(0.0, i);
   }
 }
 
@@ -327,17 +326,16 @@
     parameter_blocks_[2] = &z_[0];
 
     // Prepare the cost function.
-    typedef DynamicAutoDiffCostFunction<MyThreeParameterCostFunctor, 3>
-        DynamicMyThreeParameterCostFunction;
-    DynamicMyThreeParameterCostFunction* cost_function =
-        new DynamicMyThreeParameterCostFunction(
-            new MyThreeParameterCostFunctor());
+    using DynamicMyThreeParameterCostFunction =
+        DynamicAutoDiffCostFunction<MyThreeParameterCostFunctor, 3>;
+    auto cost_function = std::make_unique<DynamicMyThreeParameterCostFunction>(
+        new MyThreeParameterCostFunctor());
     cost_function->AddParameterBlock(1);
     cost_function->AddParameterBlock(2);
     cost_function->AddParameterBlock(3);
     cost_function->SetNumResiduals(7);
 
-    cost_function_.reset(cost_function);
+    cost_function_ = std::move(cost_function);
 
     // Setup jacobian data.
     jacobian_vect_.resize(3);
@@ -410,36 +408,36 @@
   }
 
  protected:
-  vector<double> x_;
-  vector<double> y_;
-  vector<double> z_;
+  std::vector<double> x_;
+  std::vector<double> y_;
+  std::vector<double> z_;
 
-  vector<double*> parameter_blocks_;
+  std::vector<double*> parameter_blocks_;
 
   std::unique_ptr<CostFunction> cost_function_;
 
-  vector<vector<double>> jacobian_vect_;
+  std::vector<std::vector<double>> jacobian_vect_;
 
-  vector<double> expected_residuals_;
+  std::vector<double> expected_residuals_;
 
-  vector<double> expected_jacobian_x_;
-  vector<double> expected_jacobian_y_;
-  vector<double> expected_jacobian_z_;
+  std::vector<double> expected_jacobian_x_;
+  std::vector<double> expected_jacobian_y_;
+  std::vector<double> expected_jacobian_z_;
 };
 
 TEST_F(ThreeParameterCostFunctorTest, TestThreeParameterResiduals) {
-  vector<double> residuals(7, -100000);
+  std::vector<double> residuals(7, -100000);
   EXPECT_TRUE(cost_function_->Evaluate(
-      parameter_blocks_.data(), residuals.data(), NULL));
+      parameter_blocks_.data(), residuals.data(), nullptr));
   for (int i = 0; i < 7; ++i) {
     EXPECT_EQ(expected_residuals_[i], residuals[i]);
   }
 }
 
 TEST_F(ThreeParameterCostFunctorTest, TestThreeParameterJacobian) {
-  vector<double> residuals(7, -100000);
+  std::vector<double> residuals(7, -100000);
 
-  vector<double*> jacobian;
+  std::vector<double*> jacobian;
   jacobian.push_back(jacobian_vect_[0].data());
   jacobian.push_back(jacobian_vect_[1].data());
   jacobian.push_back(jacobian_vect_[2].data());
@@ -466,12 +464,12 @@
 
 TEST_F(ThreeParameterCostFunctorTest,
        ThreeParameterJacobianWithFirstAndLastParameterBlockConstant) {
-  vector<double> residuals(7, -100000);
+  std::vector<double> residuals(7, -100000);
 
-  vector<double*> jacobian;
-  jacobian.push_back(NULL);
+  std::vector<double*> jacobian;
+  jacobian.push_back(nullptr);
   jacobian.push_back(jacobian_vect_[1].data());
-  jacobian.push_back(NULL);
+  jacobian.push_back(nullptr);
 
   EXPECT_TRUE(cost_function_->Evaluate(
       parameter_blocks_.data(), residuals.data(), jacobian.data()));
@@ -487,11 +485,11 @@
 
 TEST_F(ThreeParameterCostFunctorTest,
        ThreeParameterJacobianWithSecondParameterBlockConstant) {
-  vector<double> residuals(7, -100000);
+  std::vector<double> residuals(7, -100000);
 
-  vector<double*> jacobian;
+  std::vector<double*> jacobian;
   jacobian.push_back(jacobian_vect_[0].data());
-  jacobian.push_back(NULL);
+  jacobian.push_back(nullptr);
   jacobian.push_back(jacobian_vect_[2].data());
 
   EXPECT_TRUE(cost_function_->Evaluate(
@@ -560,16 +558,16 @@
     parameter_blocks_[5] = &z2_;
 
     // Prepare the cost function.
-    typedef DynamicAutoDiffCostFunction<MySixParameterCostFunctor, 3>
-        DynamicMySixParameterCostFunction;
-    DynamicMySixParameterCostFunction* cost_function =
-        new DynamicMySixParameterCostFunction(new MySixParameterCostFunctor());
+    using DynamicMySixParameterCostFunction =
+        DynamicAutoDiffCostFunction<MySixParameterCostFunctor, 3>;
+    auto cost_function = std::make_unique<DynamicMySixParameterCostFunction>(
+        new MySixParameterCostFunctor());
     for (int i = 0; i < 6; ++i) {
       cost_function->AddParameterBlock(1);
     }
     cost_function->SetNumResiduals(7);
 
-    cost_function_.reset(cost_function);
+    cost_function_ = std::move(cost_function);
 
     // Setup jacobian data.
     jacobian_vect_.resize(6);
@@ -656,29 +654,29 @@
   double z1_;
   double z2_;
 
-  vector<double*> parameter_blocks_;
+  std::vector<double*> parameter_blocks_;
 
   std::unique_ptr<CostFunction> cost_function_;
 
-  vector<vector<double>> jacobian_vect_;
+  std::vector<std::vector<double>> jacobian_vect_;
 
-  vector<double> expected_residuals_;
-  vector<vector<double>> expected_jacobians_;
+  std::vector<double> expected_residuals_;
+  std::vector<std::vector<double>> expected_jacobians_;
 };
 
 TEST_F(SixParameterCostFunctorTest, TestSixParameterResiduals) {
-  vector<double> residuals(7, -100000);
+  std::vector<double> residuals(7, -100000);
   EXPECT_TRUE(cost_function_->Evaluate(
-      parameter_blocks_.data(), residuals.data(), NULL));
+      parameter_blocks_.data(), residuals.data(), nullptr));
   for (int i = 0; i < 7; ++i) {
     EXPECT_EQ(expected_residuals_[i], residuals[i]);
   }
 }
 
 TEST_F(SixParameterCostFunctorTest, TestSixParameterJacobian) {
-  vector<double> residuals(7, -100000);
+  std::vector<double> residuals(7, -100000);
 
-  vector<double*> jacobian;
+  std::vector<double*> jacobian;
   jacobian.push_back(jacobian_vect_[0].data());
   jacobian.push_back(jacobian_vect_[1].data());
   jacobian.push_back(jacobian_vect_[2].data());
@@ -701,15 +699,15 @@
 }
 
 TEST_F(SixParameterCostFunctorTest, TestSixParameterJacobianVVCVVC) {
-  vector<double> residuals(7, -100000);
+  std::vector<double> residuals(7, -100000);
 
-  vector<double*> jacobian;
+  std::vector<double*> jacobian;
   jacobian.push_back(jacobian_vect_[0].data());
   jacobian.push_back(jacobian_vect_[1].data());
-  jacobian.push_back(NULL);
+  jacobian.push_back(nullptr);
   jacobian.push_back(jacobian_vect_[3].data());
   jacobian.push_back(jacobian_vect_[4].data());
-  jacobian.push_back(NULL);
+  jacobian.push_back(nullptr);
 
   EXPECT_TRUE(cost_function_->Evaluate(
       parameter_blocks_.data(), residuals.data(), jacobian.data()));
@@ -731,14 +729,14 @@
 }
 
 TEST_F(SixParameterCostFunctorTest, TestSixParameterJacobianVCCVCV) {
-  vector<double> residuals(7, -100000);
+  std::vector<double> residuals(7, -100000);
 
-  vector<double*> jacobian;
+  std::vector<double*> jacobian;
   jacobian.push_back(jacobian_vect_[0].data());
-  jacobian.push_back(NULL);
-  jacobian.push_back(NULL);
+  jacobian.push_back(nullptr);
+  jacobian.push_back(nullptr);
   jacobian.push_back(jacobian_vect_[3].data());
-  jacobian.push_back(NULL);
+  jacobian.push_back(nullptr);
   jacobian.push_back(jacobian_vect_[5].data());
 
   EXPECT_TRUE(cost_function_->Evaluate(
@@ -806,5 +804,19 @@
   EXPECT_EQ(residual, target_value);
 }
 
-}  // namespace internal
-}  // namespace ceres
+TEST(DynamicAutoDiffCostFunctionTest, DeductionTemplateCompilationTest) {
+  // Ensure deduction guide to be working
+  (void)DynamicAutoDiffCostFunction(new MyCostFunctor());
+  (void)DynamicAutoDiffCostFunction(new MyCostFunctor(), TAKE_OWNERSHIP);
+  (void)DynamicAutoDiffCostFunction(std::make_unique<MyCostFunctor>());
+}
+
+TEST(DynamicAutoDiffCostFunctionTest, ArgumentForwarding) {
+  (void)DynamicAutoDiffCostFunction<MyCostFunctor>();
+}
+
+TEST(DynamicAutoDiffCostFunctionTest, UniquePtr) {
+  (void)DynamicAutoDiffCostFunction(std::make_unique<MyCostFunctor>());
+}
+
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/dynamic_compressed_row_finalizer.h b/third_party/ceres/internal/ceres/dynamic_compressed_row_finalizer.h
index 30c98d8..9da73c0 100644
--- a/third_party/ceres/internal/ceres/dynamic_compressed_row_finalizer.h
+++ b/third_party/ceres/internal/ceres/dynamic_compressed_row_finalizer.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -28,24 +28,23 @@
 //
 // Author: richie.stebbing@gmail.com (Richard Stebbing)
 
-#ifndef CERES_INTERNAL_DYNAMIC_COMPRESED_ROW_FINALIZER_H_
-#define CERES_INTERNAL_DYNAMIC_COMPRESED_ROW_FINALIZER_H_
+#ifndef CERES_INTERNAL_DYNAMIC_COMPRESSED_ROW_FINALIZER_H_
+#define CERES_INTERNAL_DYNAMIC_COMPRESSED_ROW_FINALIZER_H_
 
 #include "ceres/casts.h"
 #include "ceres/dynamic_compressed_row_sparse_matrix.h"
+#include "ceres/internal/export.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
-struct DynamicCompressedRowJacobianFinalizer {
+struct CERES_NO_EXPORT DynamicCompressedRowJacobianFinalizer {
   void operator()(SparseMatrix* base_jacobian, int num_parameters) {
-    DynamicCompressedRowSparseMatrix* jacobian =
+    auto* jacobian =
         down_cast<DynamicCompressedRowSparseMatrix*>(base_jacobian);
     jacobian->Finalize(num_parameters);
   }
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
-#endif  // CERES_INTERNAL_DYNAMIC_COMPRESED_ROW_FINALISER_H_
+#endif  // CERES_INTERNAL_DYNAMIC_COMPRESSED_ROW_FINALISER_H_
diff --git a/third_party/ceres/internal/ceres/dynamic_compressed_row_jacobian_writer.cc b/third_party/ceres/internal/ceres/dynamic_compressed_row_jacobian_writer.cc
index 1749449..790a5fb 100644
--- a/third_party/ceres/internal/ceres/dynamic_compressed_row_jacobian_writer.cc
+++ b/third_party/ceres/internal/ceres/dynamic_compressed_row_jacobian_writer.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -30,6 +30,10 @@
 
 #include "ceres/dynamic_compressed_row_jacobian_writer.h"
 
+#include <memory>
+#include <utility>
+#include <vector>
+
 #include "ceres/casts.h"
 #include "ceres/compressed_row_jacobian_writer.h"
 #include "ceres/dynamic_compressed_row_sparse_matrix.h"
@@ -37,38 +41,33 @@
 #include "ceres/program.h"
 #include "ceres/residual_block.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
-using std::pair;
-using std::vector;
-
-ScratchEvaluatePreparer*
+std::unique_ptr<ScratchEvaluatePreparer[]>
 DynamicCompressedRowJacobianWriter::CreateEvaluatePreparers(int num_threads) {
   return ScratchEvaluatePreparer::Create(*program_, num_threads);
 }
 
-SparseMatrix* DynamicCompressedRowJacobianWriter::CreateJacobian() const {
-  DynamicCompressedRowSparseMatrix* jacobian =
-      new DynamicCompressedRowSparseMatrix(program_->NumResiduals(),
-                                           program_->NumEffectiveParameters(),
-                                           0 /* max_num_nonzeros */);
-  return jacobian;
+std::unique_ptr<SparseMatrix>
+DynamicCompressedRowJacobianWriter::CreateJacobian() const {
+  return std::make_unique<DynamicCompressedRowSparseMatrix>(
+      program_->NumResiduals(),
+      program_->NumEffectiveParameters(),
+      0 /* max_num_nonzeros */);
 }
 
 void DynamicCompressedRowJacobianWriter::Write(int residual_id,
                                                int residual_offset,
                                                double** jacobians,
                                                SparseMatrix* base_jacobian) {
-  DynamicCompressedRowSparseMatrix* jacobian =
-      down_cast<DynamicCompressedRowSparseMatrix*>(base_jacobian);
+  auto* jacobian = down_cast<DynamicCompressedRowSparseMatrix*>(base_jacobian);
 
   // Get the `residual_block` of interest.
   const ResidualBlock* residual_block =
       program_->residual_blocks()[residual_id];
   const int num_residuals = residual_block->NumResiduals();
 
-  vector<pair<int, int>> evaluated_jacobian_blocks;
+  std::vector<std::pair<int, int>> evaluated_jacobian_blocks;
   CompressedRowJacobianWriter::GetOrderedParameterBlocks(
       program_, residual_id, &evaluated_jacobian_blocks);
 
@@ -77,12 +76,11 @@
   jacobian->ClearRows(residual_offset, num_residuals);
 
   // Iterate over each parameter block.
-  for (int i = 0; i < evaluated_jacobian_blocks.size(); ++i) {
+  for (const auto& evaluated_jacobian_block : evaluated_jacobian_blocks) {
     const ParameterBlock* parameter_block =
-        program_->parameter_blocks()[evaluated_jacobian_blocks[i].first];
-    const int parameter_block_jacobian_index =
-        evaluated_jacobian_blocks[i].second;
-    const int parameter_block_size = parameter_block->LocalSize();
+        program_->parameter_blocks()[evaluated_jacobian_block.first];
+    const int parameter_block_jacobian_index = evaluated_jacobian_block.second;
+    const int parameter_block_size = parameter_block->TangentSize();
     const double* parameter_jacobian =
         jacobians[parameter_block_jacobian_index];
 
@@ -100,5 +98,4 @@
   }
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/dynamic_compressed_row_jacobian_writer.h b/third_party/ceres/internal/ceres/dynamic_compressed_row_jacobian_writer.h
index ef8fa25..489197f 100644
--- a/third_party/ceres/internal/ceres/dynamic_compressed_row_jacobian_writer.h
+++ b/third_party/ceres/internal/ceres/dynamic_compressed_row_jacobian_writer.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -34,16 +34,18 @@
 #ifndef CERES_INTERNAL_DYNAMIC_COMPRESSED_ROW_JACOBIAN_WRITER_H_
 #define CERES_INTERNAL_DYNAMIC_COMPRESSED_ROW_JACOBIAN_WRITER_H_
 
+#include <memory>
+
 #include "ceres/evaluator.h"
+#include "ceres/internal/export.h"
 #include "ceres/scratch_evaluate_preparer.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 class Program;
 class SparseMatrix;
 
-class DynamicCompressedRowJacobianWriter {
+class CERES_NO_EXPORT DynamicCompressedRowJacobianWriter {
  public:
   DynamicCompressedRowJacobianWriter(Evaluator::Options /* ignored */,
                                      Program* program)
@@ -55,16 +57,17 @@
   // the cost functions. The scratch space is therefore used to store
   // the jacobians (including zeros) temporarily before only the non-zero
   // entries are copied over to the larger jacobian in `Write`.
-  ScratchEvaluatePreparer* CreateEvaluatePreparers(int num_threads);
+  std::unique_ptr<ScratchEvaluatePreparer[]> CreateEvaluatePreparers(
+      int num_threads);
 
   // Return a `DynamicCompressedRowSparseMatrix` which is filled by
   // `Write`. Note that `Finalize` must be called to make the
   // `CompressedRowSparseMatrix` interface valid.
-  SparseMatrix* CreateJacobian() const;
+  std::unique_ptr<SparseMatrix> CreateJacobian() const;
 
   // Write only the non-zero jacobian entries for a residual block
   // (specified by `residual_id`) into `base_jacobian`, starting at the row
-  // specifed by `residual_offset`.
+  // specified by `residual_offset`.
   //
   // This method is thread-safe over residual blocks (each `residual_id`).
   void Write(int residual_id,
@@ -76,7 +79,6 @@
   Program* program_;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_INTERNAL_DYNAMIC_COMPRESSED_ROW_JACOBIAN_WRITER_H_
diff --git a/third_party/ceres/internal/ceres/dynamic_compressed_row_sparse_matrix.cc b/third_party/ceres/internal/ceres/dynamic_compressed_row_sparse_matrix.cc
index 936e682..4081c9c 100644
--- a/third_party/ceres/internal/ceres/dynamic_compressed_row_sparse_matrix.cc
+++ b/third_party/ceres/internal/ceres/dynamic_compressed_row_sparse_matrix.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -32,8 +32,7 @@
 
 #include <cstring>
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 DynamicCompressedRowSparseMatrix::DynamicCompressedRowSparseMatrix(
     int num_rows, int num_cols, int initial_max_num_nonzeros)
@@ -70,8 +69,8 @@
 
   // Count the number of non-zeros and resize `cols_` and `values_`.
   int num_jacobian_nonzeros = 0;
-  for (int i = 0; i < dynamic_cols_.size(); ++i) {
-    num_jacobian_nonzeros += dynamic_cols_[i].size();
+  for (const auto& dynamic_col : dynamic_cols_) {
+    num_jacobian_nonzeros += dynamic_col.size();
   }
 
   SetMaxNumNonZeros(num_jacobian_nonzeros + num_additional_elements);
@@ -99,5 +98,4 @@
       << "the number of jacobian nonzeros. Please contact the developers!";
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/dynamic_compressed_row_sparse_matrix.h b/third_party/ceres/internal/ceres/dynamic_compressed_row_sparse_matrix.h
index d06c36e..6dafe59 100644
--- a/third_party/ceres/internal/ceres/dynamic_compressed_row_sparse_matrix.h
+++ b/third_party/ceres/internal/ceres/dynamic_compressed_row_sparse_matrix.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -44,15 +44,15 @@
 #include <vector>
 
 #include "ceres/compressed_row_sparse_matrix.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
-class CERES_EXPORT_INTERNAL DynamicCompressedRowSparseMatrix
+class CERES_NO_EXPORT DynamicCompressedRowSparseMatrix final
     : public CompressedRowSparseMatrix {
  public:
-  // Set the number of rows and columns for the underlyig
+  // Set the number of rows and columns for the underlying
   // `CompressedRowSparseMatrix` and set the initial number of maximum non-zero
   // entries. Note that following the insertion of entries, when `Finalize`
   // is called the number of non-zeros is determined and all internal
@@ -73,7 +73,7 @@
 
   // Insert an entry at a given row and column position. This method is
   // thread-safe across rows i.e. different threads can insert values
-  // simultaneously into different rows. It should be emphasised that this
+  // simultaneously into different rows. It should be emphasized that this
   // method always inserts a new entry and does not check for existing
   // entries at the specified row and column position. Duplicate entries
   // for a given row and column position will result in undefined
@@ -97,7 +97,8 @@
   std::vector<std::vector<double>> dynamic_values_;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_DYNAMIC_COMPRESSED_ROW_SPARSE_MATRIX_H_
diff --git a/third_party/ceres/internal/ceres/dynamic_compressed_row_sparse_matrix_test.cc b/third_party/ceres/internal/ceres/dynamic_compressed_row_sparse_matrix_test.cc
index 95dc807..47d86f2 100644
--- a/third_party/ceres/internal/ceres/dynamic_compressed_row_sparse_matrix_test.cc
+++ b/third_party/ceres/internal/ceres/dynamic_compressed_row_sparse_matrix_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -31,6 +31,7 @@
 #include "ceres/dynamic_compressed_row_sparse_matrix.h"
 
 #include <memory>
+#include <vector>
 
 #include "ceres/casts.h"
 #include "ceres/compressed_row_sparse_matrix.h"
@@ -42,9 +43,6 @@
 namespace ceres {
 namespace internal {
 
-using std::copy;
-using std::vector;
-
 class DynamicCompressedRowSparseMatrixTest : public ::testing::Test {
  protected:
   void SetUp() final {
@@ -61,7 +59,8 @@
     InitialiseDenseReference();
     InitialiseSparseMatrixReferences();
 
-    dcrsm.reset(new DynamicCompressedRowSparseMatrix(num_rows, num_cols, 0));
+    dcrsm = std::make_unique<DynamicCompressedRowSparseMatrix>(
+        num_rows, num_cols, 0);
   }
 
   void Finalize() { dcrsm->Finalize(num_additional_elements); }
@@ -81,8 +80,8 @@
   }
 
   void InitialiseSparseMatrixReferences() {
-    vector<int> rows, cols;
-    vector<double> values;
+    std::vector<int> rows, cols;
+    std::vector<double> values;
     for (int i = 0; i < (num_rows * num_cols); ++i) {
       const int r = i / num_cols, c = i % num_cols;
       if (r != c) {
@@ -93,18 +92,18 @@
     }
     ASSERT_EQ(values.size(), expected_num_nonzeros);
 
-    tsm.reset(
-        new TripletSparseMatrix(num_rows, num_cols, expected_num_nonzeros));
-    copy(rows.begin(), rows.end(), tsm->mutable_rows());
-    copy(cols.begin(), cols.end(), tsm->mutable_cols());
-    copy(values.begin(), values.end(), tsm->mutable_values());
+    tsm = std::make_unique<TripletSparseMatrix>(
+        num_rows, num_cols, expected_num_nonzeros);
+    std::copy(rows.begin(), rows.end(), tsm->mutable_rows());
+    std::copy(cols.begin(), cols.end(), tsm->mutable_cols());
+    std::copy(values.begin(), values.end(), tsm->mutable_values());
     tsm->set_num_nonzeros(values.size());
 
     Matrix dense_from_tsm;
     tsm->ToDenseMatrix(&dense_from_tsm);
     ASSERT_TRUE((dense.array() == dense_from_tsm.array()).all());
 
-    crsm.reset(CompressedRowSparseMatrix::FromTripletSparseMatrix(*tsm));
+    crsm = CompressedRowSparseMatrix::FromTripletSparseMatrix(*tsm);
     Matrix dense_from_crsm;
     crsm->ToDenseMatrix(&dense_from_crsm);
     ASSERT_TRUE((dense.array() == dense_from_crsm.array()).all());
@@ -140,7 +139,7 @@
   }
 
   void ExpectEqualToCompressedRowSparseMatrixReference() {
-    typedef Eigen::Map<const Eigen::VectorXi> ConstIntVectorRef;
+    using ConstIntVectorRef = Eigen::Map<const Eigen::VectorXi>;
 
     ConstIntVectorRef crsm_rows(crsm->rows(), crsm->num_rows() + 1);
     ConstIntVectorRef dcrsm_rows(dcrsm->rows(), dcrsm->num_rows() + 1);
diff --git a/third_party/ceres/internal/ceres/dynamic_numeric_diff_cost_function_test.cc b/third_party/ceres/internal/ceres/dynamic_numeric_diff_cost_function_test.cc
index 0150f5e..aec7819 100644
--- a/third_party/ceres/internal/ceres/dynamic_numeric_diff_cost_function_test.cc
+++ b/third_party/ceres/internal/ceres/dynamic_numeric_diff_cost_function_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2024 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -33,13 +33,13 @@
 
 #include <cstddef>
 #include <memory>
+#include <vector>
 
+#include "ceres/numeric_diff_options.h"
+#include "ceres/types.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
-
-using std::vector;
+namespace ceres::internal {
 
 const double kTolerance = 1e-6;
 
@@ -75,8 +75,8 @@
 };
 
 TEST(DynamicNumericdiffCostFunctionTest, TestResiduals) {
-  vector<double> param_block_0(10, 0.0);
-  vector<double> param_block_1(5, 0.0);
+  std::vector<double> param_block_0(10, 0.0);
+  std::vector<double> param_block_1(5, 0.0);
   DynamicNumericDiffCostFunction<MyCostFunctor> cost_function(
       new MyCostFunctor());
   cost_function.AddParameterBlock(param_block_0.size());
@@ -84,12 +84,12 @@
   cost_function.SetNumResiduals(21);
 
   // Test residual computation.
-  vector<double> residuals(21, -100000);
-  vector<double*> parameter_blocks(2);
+  std::vector<double> residuals(21, -100000);
+  std::vector<double*> parameter_blocks(2);
   parameter_blocks[0] = &param_block_0[0];
   parameter_blocks[1] = &param_block_1[0];
   EXPECT_TRUE(
-      cost_function.Evaluate(&parameter_blocks[0], residuals.data(), NULL));
+      cost_function.Evaluate(&parameter_blocks[0], residuals.data(), nullptr));
   for (int r = 0; r < 10; ++r) {
     EXPECT_EQ(1.0 * r, residuals.at(r * 2));
     EXPECT_EQ(-1.0 * r, residuals.at(r * 2 + 1));
@@ -99,11 +99,11 @@
 
 TEST(DynamicNumericdiffCostFunctionTest, TestJacobian) {
   // Test the residual counting.
-  vector<double> param_block_0(10, 0.0);
+  std::vector<double> param_block_0(10, 0.0);
   for (int i = 0; i < 10; ++i) {
     param_block_0[i] = 2 * i;
   }
-  vector<double> param_block_1(5, 0.0);
+  std::vector<double> param_block_1(5, 0.0);
   DynamicNumericDiffCostFunction<MyCostFunctor> cost_function(
       new MyCostFunctor());
   cost_function.AddParameterBlock(param_block_0.size());
@@ -111,18 +111,18 @@
   cost_function.SetNumResiduals(21);
 
   // Prepare the residuals.
-  vector<double> residuals(21, -100000);
+  std::vector<double> residuals(21, -100000);
 
   // Prepare the parameters.
-  vector<double*> parameter_blocks(2);
+  std::vector<double*> parameter_blocks(2);
   parameter_blocks[0] = &param_block_0[0];
   parameter_blocks[1] = &param_block_1[0];
 
   // Prepare the jacobian.
-  vector<vector<double>> jacobian_vect(2);
+  std::vector<std::vector<double>> jacobian_vect(2);
   jacobian_vect[0].resize(21 * 10, -100000);
   jacobian_vect[1].resize(21 * 5, -100000);
-  vector<double*> jacobian;
+  std::vector<double*> jacobian;
   jacobian.push_back(jacobian_vect[0].data());
   jacobian.push_back(jacobian_vect[1].data());
 
@@ -149,8 +149,8 @@
     EXPECT_NEAR(4 * p - 8, jacobian_vect[0][20 * 10 + p], kTolerance);
     jacobian_vect[0][20 * 10 + p] = 0.0;
   }
-  for (int i = 0; i < jacobian_vect[0].size(); ++i) {
-    EXPECT_NEAR(0.0, jacobian_vect[0][i], kTolerance);
+  for (double entry : jacobian_vect[0]) {
+    EXPECT_NEAR(0.0, entry, kTolerance);
   }
 
   // Check "C" Jacobian for second parameter block.
@@ -158,19 +158,19 @@
     EXPECT_NEAR(1.0, jacobian_vect[1][20 * 5 + p], kTolerance);
     jacobian_vect[1][20 * 5 + p] = 0.0;
   }
-  for (int i = 0; i < jacobian_vect[1].size(); ++i) {
-    EXPECT_NEAR(0.0, jacobian_vect[1][i], kTolerance);
+  for (double entry : jacobian_vect[1]) {
+    EXPECT_NEAR(0.0, entry, kTolerance);
   }
 }
 
 TEST(DynamicNumericdiffCostFunctionTest,
      JacobianWithFirstParameterBlockConstant) {  // NOLINT
   // Test the residual counting.
-  vector<double> param_block_0(10, 0.0);
+  std::vector<double> param_block_0(10, 0.0);
   for (int i = 0; i < 10; ++i) {
     param_block_0[i] = 2 * i;
   }
-  vector<double> param_block_1(5, 0.0);
+  std::vector<double> param_block_1(5, 0.0);
   DynamicNumericDiffCostFunction<MyCostFunctor> cost_function(
       new MyCostFunctor());
   cost_function.AddParameterBlock(param_block_0.size());
@@ -178,19 +178,19 @@
   cost_function.SetNumResiduals(21);
 
   // Prepare the residuals.
-  vector<double> residuals(21, -100000);
+  std::vector<double> residuals(21, -100000);
 
   // Prepare the parameters.
-  vector<double*> parameter_blocks(2);
+  std::vector<double*> parameter_blocks(2);
   parameter_blocks[0] = &param_block_0[0];
   parameter_blocks[1] = &param_block_1[0];
 
   // Prepare the jacobian.
-  vector<vector<double>> jacobian_vect(2);
+  std::vector<std::vector<double>> jacobian_vect(2);
   jacobian_vect[0].resize(21 * 10, -100000);
   jacobian_vect[1].resize(21 * 5, -100000);
-  vector<double*> jacobian;
-  jacobian.push_back(NULL);
+  std::vector<double*> jacobian;
+  jacobian.push_back(nullptr);
   jacobian.push_back(jacobian_vect[1].data());
 
   // Test jacobian computation.
@@ -208,19 +208,19 @@
     EXPECT_NEAR(1.0, jacobian_vect[1][20 * 5 + p], kTolerance);
     jacobian_vect[1][20 * 5 + p] = 0.0;
   }
-  for (int i = 0; i < jacobian_vect[1].size(); ++i) {
-    EXPECT_EQ(0.0, jacobian_vect[1][i]);
+  for (double& i : jacobian_vect[1]) {
+    EXPECT_EQ(0.0, i);
   }
 }
 
 TEST(DynamicNumericdiffCostFunctionTest,
      JacobianWithSecondParameterBlockConstant) {  // NOLINT
   // Test the residual counting.
-  vector<double> param_block_0(10, 0.0);
+  std::vector<double> param_block_0(10, 0.0);
   for (int i = 0; i < 10; ++i) {
     param_block_0[i] = 2 * i;
   }
-  vector<double> param_block_1(5, 0.0);
+  std::vector<double> param_block_1(5, 0.0);
   DynamicNumericDiffCostFunction<MyCostFunctor> cost_function(
       new MyCostFunctor());
   cost_function.AddParameterBlock(param_block_0.size());
@@ -228,20 +228,20 @@
   cost_function.SetNumResiduals(21);
 
   // Prepare the residuals.
-  vector<double> residuals(21, -100000);
+  std::vector<double> residuals(21, -100000);
 
   // Prepare the parameters.
-  vector<double*> parameter_blocks(2);
+  std::vector<double*> parameter_blocks(2);
   parameter_blocks[0] = &param_block_0[0];
   parameter_blocks[1] = &param_block_1[0];
 
   // Prepare the jacobian.
-  vector<vector<double>> jacobian_vect(2);
+  std::vector<std::vector<double>> jacobian_vect(2);
   jacobian_vect[0].resize(21 * 10, -100000);
   jacobian_vect[1].resize(21 * 5, -100000);
-  vector<double*> jacobian;
+  std::vector<double*> jacobian;
   jacobian.push_back(jacobian_vect[0].data());
-  jacobian.push_back(NULL);
+  jacobian.push_back(nullptr);
 
   // Test jacobian computation.
   EXPECT_TRUE(cost_function.Evaluate(
@@ -266,8 +266,8 @@
     EXPECT_NEAR(4 * p - 8, jacobian_vect[0][20 * 10 + p], kTolerance);
     jacobian_vect[0][20 * 10 + p] = 0.0;
   }
-  for (int i = 0; i < jacobian_vect[0].size(); ++i) {
-    EXPECT_EQ(0.0, jacobian_vect[0][i]);
+  for (double& i : jacobian_vect[0]) {
+    EXPECT_EQ(0.0, i);
   }
 }
 
@@ -328,17 +328,16 @@
     parameter_blocks_[2] = &z_[0];
 
     // Prepare the cost function.
-    typedef DynamicNumericDiffCostFunction<MyThreeParameterCostFunctor>
-        DynamicMyThreeParameterCostFunction;
-    DynamicMyThreeParameterCostFunction* cost_function =
-        new DynamicMyThreeParameterCostFunction(
-            new MyThreeParameterCostFunctor());
+    using DynamicMyThreeParameterCostFunction =
+        DynamicNumericDiffCostFunction<MyThreeParameterCostFunctor>;
+    auto cost_function = std::make_unique<DynamicMyThreeParameterCostFunction>(
+        new MyThreeParameterCostFunctor());
     cost_function->AddParameterBlock(1);
     cost_function->AddParameterBlock(2);
     cost_function->AddParameterBlock(3);
     cost_function->SetNumResiduals(7);
 
-    cost_function_.reset(cost_function);
+    cost_function_ = std::move(cost_function);
 
     // Setup jacobian data.
     jacobian_vect_.resize(3);
@@ -411,36 +410,36 @@
   }
 
  protected:
-  vector<double> x_;
-  vector<double> y_;
-  vector<double> z_;
+  std::vector<double> x_;
+  std::vector<double> y_;
+  std::vector<double> z_;
 
-  vector<double*> parameter_blocks_;
+  std::vector<double*> parameter_blocks_;
 
   std::unique_ptr<CostFunction> cost_function_;
 
-  vector<vector<double>> jacobian_vect_;
+  std::vector<std::vector<double>> jacobian_vect_;
 
-  vector<double> expected_residuals_;
+  std::vector<double> expected_residuals_;
 
-  vector<double> expected_jacobian_x_;
-  vector<double> expected_jacobian_y_;
-  vector<double> expected_jacobian_z_;
+  std::vector<double> expected_jacobian_x_;
+  std::vector<double> expected_jacobian_y_;
+  std::vector<double> expected_jacobian_z_;
 };
 
 TEST_F(ThreeParameterCostFunctorTest, TestThreeParameterResiduals) {
-  vector<double> residuals(7, -100000);
+  std::vector<double> residuals(7, -100000);
   EXPECT_TRUE(cost_function_->Evaluate(
-      parameter_blocks_.data(), residuals.data(), NULL));
+      parameter_blocks_.data(), residuals.data(), nullptr));
   for (int i = 0; i < 7; ++i) {
     EXPECT_EQ(expected_residuals_[i], residuals[i]);
   }
 }
 
 TEST_F(ThreeParameterCostFunctorTest, TestThreeParameterJacobian) {
-  vector<double> residuals(7, -100000);
+  std::vector<double> residuals(7, -100000);
 
-  vector<double*> jacobian;
+  std::vector<double*> jacobian;
   jacobian.push_back(jacobian_vect_[0].data());
   jacobian.push_back(jacobian_vect_[1].data());
   jacobian.push_back(jacobian_vect_[2].data());
@@ -467,12 +466,12 @@
 
 TEST_F(ThreeParameterCostFunctorTest,
        ThreeParameterJacobianWithFirstAndLastParameterBlockConstant) {
-  vector<double> residuals(7, -100000);
+  std::vector<double> residuals(7, -100000);
 
-  vector<double*> jacobian;
-  jacobian.push_back(NULL);
+  std::vector<double*> jacobian;
+  jacobian.push_back(nullptr);
   jacobian.push_back(jacobian_vect_[1].data());
-  jacobian.push_back(NULL);
+  jacobian.push_back(nullptr);
 
   EXPECT_TRUE(cost_function_->Evaluate(
       parameter_blocks_.data(), residuals.data(), jacobian.data()));
@@ -488,11 +487,11 @@
 
 TEST_F(ThreeParameterCostFunctorTest,
        ThreeParameterJacobianWithSecondParameterBlockConstant) {
-  vector<double> residuals(7, -100000);
+  std::vector<double> residuals(7, -100000);
 
-  vector<double*> jacobian;
+  std::vector<double*> jacobian;
   jacobian.push_back(jacobian_vect_[0].data());
-  jacobian.push_back(NULL);
+  jacobian.push_back(nullptr);
   jacobian.push_back(jacobian_vect_[2].data());
 
   EXPECT_TRUE(cost_function_->Evaluate(
@@ -511,5 +510,24 @@
   }
 }
 
-}  // namespace internal
-}  // namespace ceres
+TEST(DynamicNumericdiffCostFunctionTest, DeductionTemplateCompilationTest) {
+  // Ensure deduction guide to be working
+  (void)DynamicNumericDiffCostFunction{std::make_unique<MyCostFunctor>()};
+  (void)DynamicNumericDiffCostFunction{std::make_unique<MyCostFunctor>(),
+                                       NumericDiffOptions{}};
+  (void)DynamicNumericDiffCostFunction{new MyCostFunctor};
+  (void)DynamicNumericDiffCostFunction{new MyCostFunctor, TAKE_OWNERSHIP};
+  (void)DynamicNumericDiffCostFunction{
+      new MyCostFunctor, TAKE_OWNERSHIP, NumericDiffOptions{}};
+}
+
+TEST(DynamicNumericdiffCostFunctionTest, ArgumentForwarding) {
+  (void)DynamicNumericDiffCostFunction<MyCostFunctor>();
+}
+
+TEST(DynamicAutoDiffCostFunctionTest, UniquePtr) {
+  (void)DynamicNumericDiffCostFunction<MyCostFunctor>(
+      std::make_unique<MyCostFunctor>());
+}
+
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/dynamic_sparse_normal_cholesky_solver.cc b/third_party/ceres/internal/ceres/dynamic_sparse_normal_cholesky_solver.cc
index d31c422..d77d7f7 100644
--- a/third_party/ceres/internal/ceres/dynamic_sparse_normal_cholesky_solver.cc
+++ b/third_party/ceres/internal/ceres/dynamic_sparse_normal_cholesky_solver.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,10 +35,11 @@
 #include <ctime>
 #include <memory>
 #include <sstream>
+#include <utility>
 
 #include "Eigen/SparseCore"
 #include "ceres/compressed_row_sparse_matrix.h"
-#include "ceres/cxsparse.h"
+#include "ceres/internal/config.h"
 #include "ceres/internal/eigen.h"
 #include "ceres/linear_solver.h"
 #include "ceres/suitesparse.h"
@@ -50,12 +51,11 @@
 #include "Eigen/SparseCholesky"
 #endif
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 DynamicSparseNormalCholeskySolver::DynamicSparseNormalCholeskySolver(
-    const LinearSolver::Options& options)
-    : options_(options) {}
+    LinearSolver::Options options)
+    : options_(std::move(options)) {}
 
 LinearSolver::Summary DynamicSparseNormalCholeskySolver::SolveImpl(
     CompressedRowSparseMatrix* A,
@@ -64,18 +64,18 @@
     double* x) {
   const int num_cols = A->num_cols();
   VectorRef(x, num_cols).setZero();
-  A->LeftMultiply(b, x);
+  A->LeftMultiplyAndAccumulate(b, x);
 
   if (per_solve_options.D != nullptr) {
     // Temporarily append a diagonal block to the A matrix, but undo
     // it before returning the matrix to the user.
     std::unique_ptr<CompressedRowSparseMatrix> regularizer;
     if (!A->col_blocks().empty()) {
-      regularizer.reset(CompressedRowSparseMatrix::CreateBlockDiagonalMatrix(
-          per_solve_options.D, A->col_blocks()));
+      regularizer = CompressedRowSparseMatrix::CreateBlockDiagonalMatrix(
+          per_solve_options.D, A->col_blocks());
     } else {
-      regularizer.reset(
-          new CompressedRowSparseMatrix(per_solve_options.D, num_cols));
+      regularizer = std::make_unique<CompressedRowSparseMatrix>(
+          per_solve_options.D, num_cols);
     }
     A->AppendRows(*regularizer);
   }
@@ -85,9 +85,6 @@
     case SUITE_SPARSE:
       summary = SolveImplUsingSuiteSparse(A, x);
       break;
-    case CX_SPARSE:
-      summary = SolveImplUsingCXSparse(A, x);
-      break;
     case EIGEN_SPARSE:
       summary = SolveImplUsingEigen(A, x);
       break;
@@ -111,7 +108,7 @@
 
   LinearSolver::Summary summary;
   summary.num_iterations = 0;
-  summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
+  summary.termination_type = LinearSolverTerminationType::FATAL_ERROR;
   summary.message =
       "SPARSE_NORMAL_CHOLESKY cannot be used with EIGEN_SPARSE "
       "because Ceres was not built with support for "
@@ -123,19 +120,20 @@
 
   EventLogger event_logger("DynamicSparseNormalCholeskySolver::Eigen::Solve");
 
-  Eigen::MappedSparseMatrix<double, Eigen::RowMajor> a(A->num_rows(),
-                                                       A->num_cols(),
-                                                       A->num_nonzeros(),
-                                                       A->mutable_rows(),
-                                                       A->mutable_cols(),
-                                                       A->mutable_values());
+  Eigen::Map<Eigen::SparseMatrix<double, Eigen::RowMajor>> a(
+      A->num_rows(),
+      A->num_cols(),
+      A->num_nonzeros(),
+      A->mutable_rows(),
+      A->mutable_cols(),
+      A->mutable_values());
 
   Eigen::SparseMatrix<double> lhs = a.transpose() * a;
   Eigen::SimplicialLDLT<Eigen::SparseMatrix<double>> solver;
 
   LinearSolver::Summary summary;
   summary.num_iterations = 1;
-  summary.termination_type = LINEAR_SOLVER_SUCCESS;
+  summary.termination_type = LinearSolverTerminationType::SUCCESS;
   summary.message = "Success.";
 
   solver.analyzePattern(lhs);
@@ -147,7 +145,7 @@
 
   event_logger.AddEvent("Analyze");
   if (solver.info() != Eigen::Success) {
-    summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
+    summary.termination_type = LinearSolverTerminationType::FATAL_ERROR;
     summary.message = "Eigen failure. Unable to find symbolic factorization.";
     return summary;
   }
@@ -155,7 +153,7 @@
   solver.factorize(lhs);
   event_logger.AddEvent("Factorize");
   if (solver.info() != Eigen::Success) {
-    summary.termination_type = LINEAR_SOLVER_FAILURE;
+    summary.termination_type = LinearSolverTerminationType::FAILURE;
     summary.message = "Eigen failure. Unable to find numeric factorization.";
     return summary;
   }
@@ -164,7 +162,7 @@
   VectorRef(rhs_and_solution, lhs.cols()) = solver.solve(rhs);
   event_logger.AddEvent("Solve");
   if (solver.info() != Eigen::Success) {
-    summary.termination_type = LINEAR_SOLVER_FAILURE;
+    summary.termination_type = LinearSolverTerminationType::FAILURE;
     summary.message = "Eigen failure. Unable to do triangular solve.";
     return summary;
   }
@@ -173,66 +171,16 @@
 #endif  // CERES_USE_EIGEN_SPARSE
 }
 
-LinearSolver::Summary DynamicSparseNormalCholeskySolver::SolveImplUsingCXSparse(
-    CompressedRowSparseMatrix* A, double* rhs_and_solution) {
-#ifdef CERES_NO_CXSPARSE
-
-  LinearSolver::Summary summary;
-  summary.num_iterations = 0;
-  summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
-  summary.message =
-      "SPARSE_NORMAL_CHOLESKY cannot be used with CX_SPARSE "
-      "because Ceres was not built with support for CXSparse. "
-      "This requires enabling building with -DCXSPARSE=ON.";
-
-  return summary;
-
-#else
-  EventLogger event_logger(
-      "DynamicSparseNormalCholeskySolver::CXSparse::Solve");
-
-  LinearSolver::Summary summary;
-  summary.num_iterations = 1;
-  summary.termination_type = LINEAR_SOLVER_SUCCESS;
-  summary.message = "Success.";
-
-  CXSparse cxsparse;
-
-  // Wrap the augmented Jacobian in a compressed sparse column matrix.
-  cs_di a_transpose = cxsparse.CreateSparseMatrixTransposeView(A);
-
-  // Compute the normal equations. J'J delta = J'f and solve them
-  // using a sparse Cholesky factorization. Notice that when compared
-  // to SuiteSparse we have to explicitly compute the transpose of Jt,
-  // and then the normal equations before they can be
-  // factorized. CHOLMOD/SuiteSparse on the other hand can just work
-  // off of Jt to compute the Cholesky factorization of the normal
-  // equations.
-  cs_di* a = cxsparse.TransposeMatrix(&a_transpose);
-  cs_di* lhs = cxsparse.MatrixMatrixMultiply(&a_transpose, a);
-  cxsparse.Free(a);
-  event_logger.AddEvent("NormalEquations");
-
-  if (!cxsparse.SolveCholesky(lhs, rhs_and_solution)) {
-    summary.termination_type = LINEAR_SOLVER_FAILURE;
-    summary.message = "CXSparse::SolveCholesky failed";
-  }
-  event_logger.AddEvent("Solve");
-
-  cxsparse.Free(lhs);
-  event_logger.AddEvent("TearDown");
-  return summary;
-#endif
-}
-
 LinearSolver::Summary
 DynamicSparseNormalCholeskySolver::SolveImplUsingSuiteSparse(
     CompressedRowSparseMatrix* A, double* rhs_and_solution) {
 #ifdef CERES_NO_SUITESPARSE
+  (void)A;
+  (void)rhs_and_solution;
 
   LinearSolver::Summary summary;
   summary.num_iterations = 0;
-  summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
+  summary.termination_type = LinearSolverTerminationType::FATAL_ERROR;
   summary.message =
       "SPARSE_NORMAL_CHOLESKY cannot be used with SUITE_SPARSE "
       "because Ceres was not built with support for SuiteSparse. "
@@ -244,7 +192,7 @@
   EventLogger event_logger(
       "DynamicSparseNormalCholeskySolver::SuiteSparse::Solve");
   LinearSolver::Summary summary;
-  summary.termination_type = LINEAR_SOLVER_SUCCESS;
+  summary.termination_type = LinearSolverTerminationType::SUCCESS;
   summary.num_iterations = 1;
   summary.message = "Success.";
 
@@ -252,16 +200,17 @@
   const int num_cols = A->num_cols();
   cholmod_sparse lhs = ss.CreateSparseMatrixTransposeView(A);
   event_logger.AddEvent("Setup");
-  cholmod_factor* factor = ss.AnalyzeCholesky(&lhs, &summary.message);
+  cholmod_factor* factor =
+      ss.AnalyzeCholesky(&lhs, options_.ordering_type, &summary.message);
   event_logger.AddEvent("Analysis");
 
   if (factor == nullptr) {
-    summary.termination_type = LINEAR_SOLVER_FATAL_ERROR;
+    summary.termination_type = LinearSolverTerminationType::FATAL_ERROR;
     return summary;
   }
 
   summary.termination_type = ss.Cholesky(&lhs, factor, &summary.message);
-  if (summary.termination_type == LINEAR_SOLVER_SUCCESS) {
+  if (summary.termination_type == LinearSolverTerminationType::SUCCESS) {
     cholmod_dense cholmod_rhs =
         ss.CreateDenseVectorView(rhs_and_solution, num_cols);
     cholmod_dense* solution = ss.Solve(factor, &cholmod_rhs, &summary.message);
@@ -271,7 +220,7 @@
           rhs_and_solution, solution->x, num_cols * sizeof(*rhs_and_solution));
       ss.Free(solution);
     } else {
-      summary.termination_type = LINEAR_SOLVER_FAILURE;
+      summary.termination_type = LinearSolverTerminationType::FAILURE;
     }
   }
 
@@ -282,5 +231,4 @@
 #endif
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/dynamic_sparse_normal_cholesky_solver.h b/third_party/ceres/internal/ceres/dynamic_sparse_normal_cholesky_solver.h
index 36118ba..394ba2a 100644
--- a/third_party/ceres/internal/ceres/dynamic_sparse_normal_cholesky_solver.h
+++ b/third_party/ceres/internal/ceres/dynamic_sparse_normal_cholesky_solver.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -36,13 +36,13 @@
 
 // This include must come before any #ifndef check on Ceres compile options.
 // clang-format off
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 // clang-format on
 
+#include "ceres/internal/export.h"
 #include "ceres/linear_solver.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 class CompressedRowSparseMatrix;
 
@@ -53,12 +53,10 @@
 //
 // TODO(alex): Add support for Accelerate sparse solvers:
 // https://github.com/ceres-solver/ceres-solver/issues/397
-class DynamicSparseNormalCholeskySolver
+class CERES_NO_EXPORT DynamicSparseNormalCholeskySolver
     : public CompressedRowSparseMatrixSolver {
  public:
-  explicit DynamicSparseNormalCholeskySolver(
-      const LinearSolver::Options& options);
-  virtual ~DynamicSparseNormalCholeskySolver() {}
+  explicit DynamicSparseNormalCholeskySolver(LinearSolver::Options options);
 
  private:
   LinearSolver::Summary SolveImpl(CompressedRowSparseMatrix* A,
@@ -69,16 +67,12 @@
   LinearSolver::Summary SolveImplUsingSuiteSparse(CompressedRowSparseMatrix* A,
                                                   double* rhs_and_solution);
 
-  LinearSolver::Summary SolveImplUsingCXSparse(CompressedRowSparseMatrix* A,
-                                               double* rhs_and_solution);
-
   LinearSolver::Summary SolveImplUsingEigen(CompressedRowSparseMatrix* A,
                                             double* rhs_and_solution);
 
   const LinearSolver::Options options_;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_INTERNAL_DYNAMIC_SPARSE_NORMAL_CHOLESKY_SOLVER_H_
diff --git a/third_party/ceres/internal/ceres/dynamic_sparse_normal_cholesky_solver_test.cc b/third_party/ceres/internal/ceres/dynamic_sparse_normal_cholesky_solver_test.cc
index 8bf609e..4afd372 100644
--- a/third_party/ceres/internal/ceres/dynamic_sparse_normal_cholesky_solver_test.cc
+++ b/third_party/ceres/internal/ceres/dynamic_sparse_normal_cholesky_solver_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -34,6 +34,7 @@
 #include "ceres/casts.h"
 #include "ceres/compressed_row_sparse_matrix.h"
 #include "ceres/context_impl.h"
+#include "ceres/internal/config.h"
 #include "ceres/linear_least_squares_problems.h"
 #include "ceres/linear_solver.h"
 #include "ceres/triplet_sparse_matrix.h"
@@ -50,19 +51,19 @@
 class DynamicSparseNormalCholeskySolverTest : public ::testing::Test {
  protected:
   void SetUp() final {
-    std::unique_ptr<LinearLeastSquaresProblem> problem(
-        CreateLinearLeastSquaresProblemFromId(1));
-    A_.reset(CompressedRowSparseMatrix::FromTripletSparseMatrix(
-        *down_cast<TripletSparseMatrix*>(problem->A.get())));
-    b_.reset(problem->b.release());
-    D_.reset(problem->D.release());
+    std::unique_ptr<LinearLeastSquaresProblem> problem =
+        CreateLinearLeastSquaresProblemFromId(1);
+    A_ = CompressedRowSparseMatrix::FromTripletSparseMatrix(
+        *down_cast<TripletSparseMatrix*>(problem->A.get()));
+    b_ = std::move(problem->b);
+    D_ = std::move(problem->D);
   }
 
   void TestSolver(const LinearSolver::Options& options, double* D) {
     Matrix dense_A;
     A_->ToDenseMatrix(&dense_A);
     Matrix lhs = dense_A.transpose() * dense_A;
-    if (D != NULL) {
+    if (D != nullptr) {
       lhs += (ConstVectorRef(D, A_->num_cols()).array() *
               ConstVectorRef(D, A_->num_cols()).array())
                  .matrix()
@@ -71,7 +72,7 @@
 
     Vector rhs(A_->num_cols());
     rhs.setZero();
-    A_->LeftMultiply(b_.get(), rhs.data());
+    A_->LeftMultiplyAndAccumulate(b_.get(), rhs.data());
     Vector expected_solution = lhs.llt().solve(rhs);
 
     std::unique_ptr<LinearSolver> solver(LinearSolver::Create(options));
@@ -82,7 +83,7 @@
     summary = solver->Solve(
         A_.get(), b_.get(), per_solve_options, actual_solution.data());
 
-    EXPECT_EQ(summary.termination_type, LINEAR_SOLVER_SUCCESS);
+    EXPECT_EQ(summary.termination_type, LinearSolverTerminationType::SUCCESS);
 
     for (int i = 0; i < A_->num_cols(); ++i) {
       EXPECT_NEAR(expected_solution(i), actual_solution(i), 1e-8)
@@ -92,15 +93,17 @@
   }
 
   void TestSolver(
-      const SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type) {
+      const SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type,
+      const OrderingType ordering_type) {
     LinearSolver::Options options;
     options.type = SPARSE_NORMAL_CHOLESKY;
     options.dynamic_sparsity = true;
     options.sparse_linear_algebra_library_type =
         sparse_linear_algebra_library_type;
+    options.ordering_type = ordering_type;
     ContextImpl context;
     options.context = &context;
-    TestSolver(options, NULL);
+    TestSolver(options, nullptr);
     TestSolver(options, D_.get());
   }
 
@@ -110,21 +113,27 @@
 };
 
 #ifndef CERES_NO_SUITESPARSE
-TEST_F(DynamicSparseNormalCholeskySolverTest, SuiteSparse) {
-  TestSolver(SUITE_SPARSE);
+TEST_F(DynamicSparseNormalCholeskySolverTest, SuiteSparseAMD) {
+  TestSolver(SUITE_SPARSE, OrderingType::AMD);
+}
+
+#ifndef CERES_NO_CHOLMOD_PARTITION
+TEST_F(DynamicSparseNormalCholeskySolverTest, SuiteSparseNESDIS) {
+  TestSolver(SUITE_SPARSE, OrderingType::NESDIS);
 }
 #endif
-
-#ifndef CERES_NO_CXSPARSE
-TEST_F(DynamicSparseNormalCholeskySolverTest, CXSparse) {
-  TestSolver(CX_SPARSE);
-}
 #endif
 
 #ifdef CERES_USE_EIGEN_SPARSE
-TEST_F(DynamicSparseNormalCholeskySolverTest, Eigen) {
-  TestSolver(EIGEN_SPARSE);
+TEST_F(DynamicSparseNormalCholeskySolverTest, EigenAMD) {
+  TestSolver(EIGEN_SPARSE, OrderingType::AMD);
 }
+
+#ifndef CERES_NO_EIGEN_METIS
+TEST_F(DynamicSparseNormalCholeskySolverTest, EigenNESDIS) {
+  TestSolver(EIGEN_SPARSE, OrderingType::NESDIS);
+}
+#endif
 #endif  // CERES_USE_EIGEN_SPARSE
 
 }  // namespace internal
diff --git a/third_party/ceres/internal/ceres/dynamic_sparsity_test.cc b/third_party/ceres/internal/ceres/dynamic_sparsity_test.cc
index 12e62ef..0c29595 100644
--- a/third_party/ceres/internal/ceres/dynamic_sparsity_test.cc
+++ b/third_party/ceres/internal/ceres/dynamic_sparsity_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -32,14 +32,14 @@
 // Based on examples/ellipse_approximation.cc
 
 #include <cmath>
+#include <utility>
 #include <vector>
 
 #include "ceres/ceres.h"
 #include "glog/logging.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // Data generated with the following Python code.
 //   import numpy as np
@@ -280,8 +280,8 @@
   EIGEN_MAKE_ALIGNED_OPERATOR_NEW
 
   PointToLineSegmentContourCostFunction(const int num_segments,
-                                        const Eigen::Vector2d& y)
-      : num_segments_(num_segments), y_(y) {
+                                        Eigen::Vector2d y)
+      : num_segments_(num_segments), y_(std::move(y)) {
     // The first parameter is the preimage position.
     mutable_parameter_block_sizes()->push_back(1);
     // The next parameters are the control points for the line segment contour.
@@ -307,16 +307,16 @@
     residuals[0] = y_[0] - ((1.0 - u) * x[1 + i0][0] + u * x[1 + i1][0]);
     residuals[1] = y_[1] - ((1.0 - u) * x[1 + i0][1] + u * x[1 + i1][1]);
 
-    if (jacobians == NULL) {
+    if (jacobians == nullptr) {
       return true;
     }
 
-    if (jacobians[0] != NULL) {
+    if (jacobians[0] != nullptr) {
       jacobians[0][0] = x[1 + i0][0] - x[1 + i1][0];
       jacobians[0][1] = x[1 + i0][1] - x[1 + i1][1];
     }
     for (int i = 0; i < num_segments_; ++i) {
-      if (jacobians[i + 1] != NULL) {
+      if (jacobians[i + 1] != nullptr) {
         MatrixRef(jacobians[i + 1], 2, 2).setZero();
         if (i == i0) {
           jacobians[i + 1][0] = -(1.0 - u);
@@ -366,9 +366,9 @@
 };
 
 TEST(DynamicSparsity, StaticAndDynamicSparsityProduceSameSolution) {
-  // Skip test if there is no sparse linear algebra library.
+  // Skip test if there is no sparse linear algebra library that
+  // supports dynamic sparsity.
   if (!IsSparseLinearAlgebraLibraryTypeAvailable(SUITE_SPARSE) &&
-      !IsSparseLinearAlgebraLibraryTypeAvailable(CX_SPARSE) &&
       !IsSparseLinearAlgebraLibraryTypeAvailable(EIGEN_SPARSE)) {
     return;
   }
@@ -383,7 +383,7 @@
   //
   // Initialize `X` to points on the unit circle.
   Vector w(num_segments + 1);
-  w.setLinSpaced(num_segments + 1, 0.0, 2.0 * M_PI);
+  w.setLinSpaced(num_segments + 1, 0.0, 2.0 * constants::pi);
   w.conservativeResize(num_segments);
   Matrix X(num_segments, 2);
   X.col(0) = w.array().cos();
@@ -403,7 +403,7 @@
   // For each data point add a residual which measures its distance to its
   // corresponding position on the line segment contour.
   std::vector<double*> parameter_blocks(1 + num_segments);
-  parameter_blocks[0] = NULL;
+  parameter_blocks[0] = nullptr;
   for (int i = 0; i < num_segments; ++i) {
     parameter_blocks[i + 1] = X.data() + 2 * i;
   }
@@ -411,7 +411,7 @@
     parameter_blocks[0] = &t[i];
     problem.AddResidualBlock(
         PointToLineSegmentContourCostFunction::Create(num_segments, kY.row(i)),
-        NULL,
+        nullptr,
         parameter_blocks);
   }
 
@@ -419,7 +419,7 @@
   for (int i = 0; i < num_segments; ++i) {
     problem.AddResidualBlock(
         EuclideanDistanceFunctor::Create(sqrt(regularization_weight)),
-        NULL,
+        nullptr,
         X.data() + 2 * i,
         X.data() + 2 * ((i + 1) % num_segments));
   }
@@ -427,6 +427,13 @@
   Solver::Options options;
   options.max_num_iterations = 100;
   options.linear_solver_type = SPARSE_NORMAL_CHOLESKY;
+  // Only SuiteSparse & EigenSparse currently support dynamic sparsity.
+  options.sparse_linear_algebra_library_type =
+#if !defined(CERES_NO_SUITESPARSE)
+      ceres::SUITE_SPARSE;
+#elif defined(CERES_USE_EIGEN_SPARSE)
+      ceres::EIGEN_SPARSE;
+#endif
 
   // First, solve `X` and `t` jointly with dynamic_sparsity = true.
   Matrix X0 = X;
@@ -453,5 +460,4 @@
       << dynamic_summary.FullReport();
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/eigen_vector_ops.h b/third_party/ceres/internal/ceres/eigen_vector_ops.h
new file mode 100644
index 0000000..6ebff88
--- /dev/null
+++ b/third_party/ceres/internal/ceres/eigen_vector_ops.h
@@ -0,0 +1,105 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_EIGEN_VECTOR_OPS_H_
+#define CERES_INTERNAL_EIGEN_VECTOR_OPS_H_
+
+#include <numeric>
+
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/fixed_array.h"
+#include "ceres/parallel_for.h"
+#include "ceres/parallel_vector_ops.h"
+
+namespace ceres::internal {
+
+// Blas1 operations on Eigen vectors. These functions are needed as an
+// abstraction layer so that we can use different versions of a vector style
+// object in the conjugate gradients linear solver.
+template <typename Derived>
+inline double Norm(const Eigen::DenseBase<Derived>& x,
+                   ContextImpl* context,
+                   int num_threads) {
+  FixedArray<double> norms(num_threads, 0.);
+  ParallelFor(
+      context,
+      0,
+      x.rows(),
+      num_threads,
+      [&x, &norms](int thread_id, std::tuple<int, int> range) {
+        auto [start, end] = range;
+        norms[thread_id] += x.segment(start, end - start).squaredNorm();
+      },
+      kMinBlockSizeParallelVectorOps);
+  return std::sqrt(std::accumulate(norms.begin(), norms.end(), 0.));
+}
+inline void SetZero(Vector& x, ContextImpl* context, int num_threads) {
+  ParallelSetZero(context, num_threads, x);
+}
+inline void Axpby(double a,
+                  const Vector& x,
+                  double b,
+                  const Vector& y,
+                  Vector& z,
+                  ContextImpl* context,
+                  int num_threads) {
+  ParallelAssign(context, num_threads, z, a * x + b * y);
+}
+template <typename VectorLikeX, typename VectorLikeY>
+inline double Dot(const VectorLikeX& x,
+                  const VectorLikeY& y,
+                  ContextImpl* context,
+                  int num_threads) {
+  FixedArray<double> dots(num_threads, 0.);
+  ParallelFor(
+      context,
+      0,
+      x.rows(),
+      num_threads,
+      [&x, &y, &dots](int thread_id, std::tuple<int, int> range) {
+        auto [start, end] = range;
+        const int block_size = end - start;
+        const auto& x_block = x.segment(start, block_size);
+        const auto& y_block = y.segment(start, block_size);
+        dots[thread_id] += x_block.dot(y_block);
+      },
+      kMinBlockSizeParallelVectorOps);
+  return std::accumulate(dots.begin(), dots.end(), 0.);
+}
+inline void Copy(const Vector& from,
+                 Vector& to,
+                 ContextImpl* context,
+                 int num_threads) {
+  ParallelAssign(context, num_threads, to, from);
+}
+
+}  // namespace ceres::internal
+
+#endif  // CERES_INTERNAL_EIGEN_VECTOR_OPS_H_
diff --git a/third_party/ceres/internal/ceres/eigensparse.cc b/third_party/ceres/internal/ceres/eigensparse.cc
index 22ed2c4..7ed401d 100644
--- a/third_party/ceres/internal/ceres/eigensparse.cc
+++ b/third_party/ceres/internal/ceres/eigensparse.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -30,27 +30,31 @@
 
 #include "ceres/eigensparse.h"
 
+#include <memory>
+
 #ifdef CERES_USE_EIGEN_SPARSE
 
 #include <sstream>
 
+#ifndef CERES_NO_EIGEN_METIS
+#include <iostream>  // This is needed because MetisSupport depends on iostream.
+
+#include "Eigen/MetisSupport"
+#endif
+
 #include "Eigen/SparseCholesky"
 #include "Eigen/SparseCore"
 #include "ceres/compressed_row_sparse_matrix.h"
 #include "ceres/linear_solver.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
-// TODO(sameeragarwal): Use enable_if to clean up the implementations
-// for when Scalar == double.
 template <typename Solver>
-class EigenSparseCholeskyTemplate : public SparseCholesky {
+class EigenSparseCholeskyTemplate final : public SparseCholesky {
  public:
-  EigenSparseCholeskyTemplate() : analyzed_(false) {}
-  virtual ~EigenSparseCholeskyTemplate() {}
+  EigenSparseCholeskyTemplate() = default;
   CompressedRowSparseMatrix::StorageType StorageType() const final {
-    return CompressedRowSparseMatrix::LOWER_TRIANGULAR;
+    return CompressedRowSparseMatrix::StorageType::LOWER_TRIANGULAR;
   }
 
   LinearSolverTerminationType Factorize(
@@ -67,7 +71,7 @@
 
       if (solver_.info() != Eigen::Success) {
         *message = "Eigen failure. Unable to find symbolic factorization.";
-        return LINEAR_SOLVER_FATAL_ERROR;
+        return LinearSolverTerminationType::FATAL_ERROR;
       }
 
       analyzed_ = true;
@@ -76,43 +80,42 @@
     solver_.factorize(lhs);
     if (solver_.info() != Eigen::Success) {
       *message = "Eigen failure. Unable to find numeric factorization.";
-      return LINEAR_SOLVER_FAILURE;
+      return LinearSolverTerminationType::FAILURE;
     }
-    return LINEAR_SOLVER_SUCCESS;
+    return LinearSolverTerminationType::SUCCESS;
   }
 
   LinearSolverTerminationType Solve(const double* rhs_ptr,
                                     double* solution_ptr,
-                                    std::string* message) {
+                                    std::string* message) override {
     CHECK(analyzed_) << "Solve called without a call to Factorize first.";
 
-    scalar_rhs_ = ConstVectorRef(rhs_ptr, solver_.cols())
-                      .template cast<typename Solver::Scalar>();
-
-    // The two casts are needed if the Scalar in this class is not
-    // double. For code simplicity we are going to assume that Eigen
-    // is smart enough to figure out that casting a double Vector to a
-    // double Vector is a straight copy. If this turns into a
-    // performance bottleneck (unlikely), we can revisit this.
-    scalar_solution_ = solver_.solve(scalar_rhs_);
-    VectorRef(solution_ptr, solver_.cols()) =
-        scalar_solution_.template cast<double>();
+    // Avoid copying when the scalar type is double
+    if constexpr (std::is_same_v<typename Solver::Scalar, double>) {
+      ConstVectorRef scalar_rhs(rhs_ptr, solver_.cols());
+      VectorRef(solution_ptr, solver_.cols()) = solver_.solve(scalar_rhs);
+    } else {
+      auto scalar_rhs = ConstVectorRef(rhs_ptr, solver_.cols())
+                            .template cast<typename Solver::Scalar>();
+      auto scalar_solution = solver_.solve(scalar_rhs);
+      VectorRef(solution_ptr, solver_.cols()) =
+          scalar_solution.template cast<double>();
+    }
 
     if (solver_.info() != Eigen::Success) {
       *message = "Eigen failure. Unable to do triangular solve.";
-      return LINEAR_SOLVER_FAILURE;
+      return LinearSolverTerminationType::FAILURE;
     }
-    return LINEAR_SOLVER_SUCCESS;
+    return LinearSolverTerminationType::SUCCESS;
   }
 
   LinearSolverTerminationType Factorize(CompressedRowSparseMatrix* lhs,
                                         std::string* message) final {
     CHECK_EQ(lhs->storage_type(), StorageType());
 
-    typename Solver::Scalar* values_ptr = NULL;
-    if (std::is_same<typename Solver::Scalar, double>::value) {
-      values_ptr =
-          reinterpret_cast<typename Solver::Scalar*>(lhs->mutable_values());
+    typename Solver::Scalar* values_ptr = nullptr;
+    if constexpr (std::is_same_v<typename Solver::Scalar, double>) {
+      values_ptr = lhs->mutable_values();
     } else {
       // In the case where the scalar used in this class is not
       // double. In that case, make a copy of the values array in the
@@ -122,69 +125,83 @@
       values_ptr = values_.data();
     }
 
-    Eigen::MappedSparseMatrix<typename Solver::Scalar, Eigen::ColMajor>
+    Eigen::Map<
+        const Eigen::SparseMatrix<typename Solver::Scalar, Eigen::ColMajor>>
         eigen_lhs(lhs->num_rows(),
                   lhs->num_rows(),
                   lhs->num_nonzeros(),
-                  lhs->mutable_rows(),
-                  lhs->mutable_cols(),
+                  lhs->rows(),
+                  lhs->cols(),
                   values_ptr);
     return Factorize(eigen_lhs, message);
   }
 
  private:
-  Eigen::Matrix<typename Solver::Scalar, Eigen::Dynamic, 1> values_,
-      scalar_rhs_, scalar_solution_;
-  bool analyzed_;
+  Eigen::Matrix<typename Solver::Scalar, Eigen::Dynamic, 1> values_;
+
+  bool analyzed_{false};
   Solver solver_;
 };
 
 std::unique_ptr<SparseCholesky> EigenSparseCholesky::Create(
     const OrderingType ordering_type) {
-  std::unique_ptr<SparseCholesky> sparse_cholesky;
+  using WithAMDOrdering = Eigen::SimplicialLDLT<Eigen::SparseMatrix<double>,
+                                                Eigen::Upper,
+                                                Eigen::AMDOrdering<int>>;
+  using WithNaturalOrdering =
+      Eigen::SimplicialLDLT<Eigen::SparseMatrix<double>,
+                            Eigen::Upper,
+                            Eigen::NaturalOrdering<int>>;
 
-  typedef Eigen::SimplicialLDLT<Eigen::SparseMatrix<double>,
-                                Eigen::Upper,
-                                Eigen::AMDOrdering<int>>
-      WithAMDOrdering;
-  typedef Eigen::SimplicialLDLT<Eigen::SparseMatrix<double>,
-                                Eigen::Upper,
-                                Eigen::NaturalOrdering<int>>
-      WithNaturalOrdering;
-  if (ordering_type == AMD) {
-    sparse_cholesky.reset(new EigenSparseCholeskyTemplate<WithAMDOrdering>());
-  } else {
-    sparse_cholesky.reset(
-        new EigenSparseCholeskyTemplate<WithNaturalOrdering>());
+  if (ordering_type == OrderingType::AMD) {
+    return std::make_unique<EigenSparseCholeskyTemplate<WithAMDOrdering>>();
+  } else if (ordering_type == OrderingType::NESDIS) {
+#ifndef CERES_NO_EIGEN_METIS
+    using WithMetisOrdering = Eigen::SimplicialLDLT<Eigen::SparseMatrix<double>,
+                                                    Eigen::Upper,
+                                                    Eigen::MetisOrdering<int>>;
+    return std::make_unique<EigenSparseCholeskyTemplate<WithMetisOrdering>>();
+#else
+    LOG(FATAL)
+        << "Congratulations you have found a bug in Ceres Solver. Please "
+           "report it to the Ceres Solver developers.";
+    return nullptr;
+#endif  // CERES_NO_EIGEN_METIS
   }
-  return sparse_cholesky;
+  return std::make_unique<EigenSparseCholeskyTemplate<WithNaturalOrdering>>();
 }
 
-EigenSparseCholesky::~EigenSparseCholesky() {}
+EigenSparseCholesky::~EigenSparseCholesky() = default;
 
 std::unique_ptr<SparseCholesky> FloatEigenSparseCholesky::Create(
     const OrderingType ordering_type) {
-  std::unique_ptr<SparseCholesky> sparse_cholesky;
-  typedef Eigen::SimplicialLDLT<Eigen::SparseMatrix<float>,
-                                Eigen::Upper,
-                                Eigen::AMDOrdering<int>>
-      WithAMDOrdering;
-  typedef Eigen::SimplicialLDLT<Eigen::SparseMatrix<float>,
-                                Eigen::Upper,
-                                Eigen::NaturalOrdering<int>>
-      WithNaturalOrdering;
-  if (ordering_type == AMD) {
-    sparse_cholesky.reset(new EigenSparseCholeskyTemplate<WithAMDOrdering>());
-  } else {
-    sparse_cholesky.reset(
-        new EigenSparseCholeskyTemplate<WithNaturalOrdering>());
+  using WithAMDOrdering = Eigen::SimplicialLDLT<Eigen::SparseMatrix<float>,
+                                                Eigen::Upper,
+                                                Eigen::AMDOrdering<int>>;
+  using WithNaturalOrdering =
+      Eigen::SimplicialLDLT<Eigen::SparseMatrix<float>,
+                            Eigen::Upper,
+                            Eigen::NaturalOrdering<int>>;
+  if (ordering_type == OrderingType::AMD) {
+    return std::make_unique<EigenSparseCholeskyTemplate<WithAMDOrdering>>();
+  } else if (ordering_type == OrderingType::NESDIS) {
+#ifndef CERES_NO_EIGEN_METIS
+    using WithMetisOrdering = Eigen::SimplicialLDLT<Eigen::SparseMatrix<float>,
+                                                    Eigen::Upper,
+                                                    Eigen::MetisOrdering<int>>;
+    return std::make_unique<EigenSparseCholeskyTemplate<WithMetisOrdering>>();
+#else
+    LOG(FATAL)
+        << "Congratulations you have found a bug in Ceres Solver. Please "
+           "report it to the Ceres Solver developers.";
+    return nullptr;
+#endif  // CERES_NO_EIGEN_METIS
   }
-  return sparse_cholesky;
+  return std::make_unique<EigenSparseCholeskyTemplate<WithNaturalOrdering>>();
 }
 
-FloatEigenSparseCholesky::~FloatEigenSparseCholesky() {}
+FloatEigenSparseCholesky::~FloatEigenSparseCholesky() = default;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_USE_EIGEN_SPARSE
diff --git a/third_party/ceres/internal/ceres/eigensparse.h b/third_party/ceres/internal/ceres/eigensparse.h
index bb89c2c..f16e8f2 100644
--- a/third_party/ceres/internal/ceres/eigensparse.h
+++ b/third_party/ceres/internal/ceres/eigensparse.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -34,7 +34,7 @@
 #define CERES_INTERNAL_EIGENSPARSE_H_
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifdef CERES_USE_EIGEN_SPARSE
 
@@ -42,48 +42,69 @@
 #include <string>
 
 #include "Eigen/SparseCore"
+#include "ceres/internal/export.h"
 #include "ceres/linear_solver.h"
 #include "ceres/sparse_cholesky.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
-class EigenSparseCholesky : public SparseCholesky {
+class EigenSparse {
+ public:
+  static constexpr bool IsNestedDissectionAvailable() noexcept {
+#ifdef CERES_NO_EIGEN_METIS
+    return false;
+#else
+    return true;
+#endif
+  }
+};
+
+class CERES_NO_EXPORT EigenSparseCholesky : public SparseCholesky {
  public:
   // Factory
   static std::unique_ptr<SparseCholesky> Create(
       const OrderingType ordering_type);
 
   // SparseCholesky interface.
-  virtual ~EigenSparseCholesky();
-  virtual LinearSolverTerminationType Factorize(CompressedRowSparseMatrix* lhs,
-                                                std::string* message) = 0;
-  virtual CompressedRowSparseMatrix::StorageType StorageType() const = 0;
-  virtual LinearSolverTerminationType Solve(const double* rhs,
-                                            double* solution,
-                                            std::string* message) = 0;
+  ~EigenSparseCholesky() override;
+  LinearSolverTerminationType Factorize(CompressedRowSparseMatrix* lhs,
+                                        std::string* message) override = 0;
+  CompressedRowSparseMatrix::StorageType StorageType() const override = 0;
+  LinearSolverTerminationType Solve(const double* rhs,
+                                    double* solution,
+                                    std::string* message) override = 0;
 };
 
 // Even though the input is double precision linear system, this class
 // solves it by computing a single precision Cholesky factorization.
-class FloatEigenSparseCholesky : public SparseCholesky {
+class CERES_NO_EXPORT FloatEigenSparseCholesky : public SparseCholesky {
  public:
   // Factory
   static std::unique_ptr<SparseCholesky> Create(
       const OrderingType ordering_type);
 
   // SparseCholesky interface.
-  virtual ~FloatEigenSparseCholesky();
-  virtual LinearSolverTerminationType Factorize(CompressedRowSparseMatrix* lhs,
-                                                std::string* message) = 0;
-  virtual CompressedRowSparseMatrix::StorageType StorageType() const = 0;
-  virtual LinearSolverTerminationType Solve(const double* rhs,
-                                            double* solution,
-                                            std::string* message) = 0;
+  ~FloatEigenSparseCholesky() override;
+  LinearSolverTerminationType Factorize(CompressedRowSparseMatrix* lhs,
+                                        std::string* message) override = 0;
+  CompressedRowSparseMatrix::StorageType StorageType() const override = 0;
+  LinearSolverTerminationType Solve(const double* rhs,
+                                    double* solution,
+                                    std::string* message) override = 0;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#else
+
+namespace ceres::internal {
+
+class EigenSparse {
+ public:
+  static constexpr bool IsNestedDissectionAvailable() noexcept { return false; }
+};
+
+}  // namespace ceres::internal
 
 #endif  // CERES_USE_EIGEN_SPARSE
 
diff --git a/third_party/ceres/internal/ceres/evaluation_benchmark.cc b/third_party/ceres/internal/ceres/evaluation_benchmark.cc
new file mode 100644
index 0000000..c679885
--- /dev/null
+++ b/third_party/ceres/internal/ceres/evaluation_benchmark.cc
@@ -0,0 +1,1094 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Authors: dmitriy.korchemkin@gmail.com (Dmitriy Korchemkin)
+
+#include <memory>
+#include <random>
+#include <string>
+#include <vector>
+
+#include "benchmark/benchmark.h"
+#include "ceres/block_sparse_matrix.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/cuda_block_sparse_crs_view.h"
+#include "ceres/cuda_partitioned_block_sparse_crs_view.h"
+#include "ceres/cuda_sparse_matrix.h"
+#include "ceres/cuda_vector.h"
+#include "ceres/evaluator.h"
+#include "ceres/implicit_schur_complement.h"
+#include "ceres/partitioned_matrix_view.h"
+#include "ceres/power_series_expansion_preconditioner.h"
+#include "ceres/preprocessor.h"
+#include "ceres/problem.h"
+#include "ceres/problem_impl.h"
+#include "ceres/program.h"
+#include "ceres/sparse_matrix.h"
+
+namespace ceres::internal {
+
+template <typename Derived, typename Base>
+std::unique_ptr<Derived> downcast_unique_ptr(std::unique_ptr<Base>& base) {
+  return std::unique_ptr<Derived>(dynamic_cast<Derived*>(base.release()));
+}
+
+// Benchmark library might invoke benchmark function multiple times.
+// In order to save time required to parse BAL data, we ensure that
+// each dataset is being loaded at most once.
+// Each type of jacobians is also cached after first creation
+struct BALData {
+  using PartitionedView = PartitionedMatrixView<2, 3, 9>;
+  explicit BALData(const std::string& path) {
+    bal_problem = std::make_unique<BundleAdjustmentProblem>(path);
+    CHECK(bal_problem != nullptr);
+
+    auto problem_impl = bal_problem->mutable_problem()->mutable_impl();
+    auto preprocessor = Preprocessor::Create(MinimizerType::TRUST_REGION);
+
+    preprocessed_problem = std::make_unique<PreprocessedProblem>();
+    Solver::Options options = bal_problem->options();
+    options.linear_solver_type = ITERATIVE_SCHUR;
+    CHECK(preprocessor->Preprocess(
+        options, problem_impl, preprocessed_problem.get()));
+
+    auto program = preprocessed_problem->reduced_program.get();
+
+    parameters.resize(program->NumParameters());
+    program->ParameterBlocksToStateVector(parameters.data());
+
+    const int num_residuals = program->NumResiduals();
+    b.resize(num_residuals);
+
+    std::mt19937 rng;
+    std::normal_distribution<double> rnorm;
+    for (int i = 0; i < num_residuals; ++i) {
+      b[i] = rnorm(rng);
+    }
+
+    const int num_parameters = program->NumParameters();
+    D.resize(num_parameters);
+    for (int i = 0; i < num_parameters; ++i) {
+      D[i] = rnorm(rng);
+    }
+  }
+
+  std::unique_ptr<BlockSparseMatrix> CreateBlockSparseJacobian(
+      ContextImpl* context, bool sequential) {
+    auto problem = bal_problem->mutable_problem();
+    auto problem_impl = problem->mutable_impl();
+    CHECK(problem_impl != nullptr);
+
+    Evaluator::Options options;
+    options.linear_solver_type = ITERATIVE_SCHUR;
+    options.num_threads = 1;
+    options.context = context;
+    options.num_eliminate_blocks = bal_problem->num_points();
+
+    std::string error;
+    auto program = preprocessed_problem->reduced_program.get();
+    auto evaluator = Evaluator::Create(options, program, &error);
+    CHECK(evaluator != nullptr);
+
+    auto jacobian = evaluator->CreateJacobian();
+    auto block_sparse = downcast_unique_ptr<BlockSparseMatrix>(jacobian);
+    CHECK(block_sparse != nullptr);
+
+    if (sequential) {
+      auto block_structure_sequential =
+          std::make_unique<CompressedRowBlockStructure>(
+              *block_sparse->block_structure());
+      int num_nonzeros = 0;
+      for (auto& row_block : block_structure_sequential->rows) {
+        const int row_block_size = row_block.block.size;
+        for (auto& cell : row_block.cells) {
+          const int col_block_size =
+              block_structure_sequential->cols[cell.block_id].size;
+          cell.position = num_nonzeros;
+          num_nonzeros += col_block_size * row_block_size;
+        }
+      }
+      block_sparse = std::make_unique<BlockSparseMatrix>(
+          block_structure_sequential.release(),
+#ifndef CERES_NO_CUDA
+          true
+#else
+          false
+#endif
+      );
+    }
+
+    std::mt19937 rng;
+    std::normal_distribution<double> rnorm;
+    const int nnz = block_sparse->num_nonzeros();
+    auto values = block_sparse->mutable_values();
+    for (int i = 0; i < nnz; ++i) {
+      values[i] = rnorm(rng);
+    }
+
+    return block_sparse;
+  }
+
+  std::unique_ptr<CompressedRowSparseMatrix> CreateCompressedRowSparseJacobian(
+      ContextImpl* context) {
+    auto block_sparse = BlockSparseJacobian(context);
+    return block_sparse->ToCompressedRowSparseMatrix();
+  }
+
+  const BlockSparseMatrix* BlockSparseJacobian(ContextImpl* context) {
+    if (!block_sparse_jacobian) {
+      block_sparse_jacobian = CreateBlockSparseJacobian(context, true);
+    }
+    return block_sparse_jacobian.get();
+  }
+
+  const BlockSparseMatrix* BlockSparseJacobianPartitioned(
+      ContextImpl* context) {
+    if (!block_sparse_jacobian_partitioned) {
+      block_sparse_jacobian_partitioned =
+          CreateBlockSparseJacobian(context, false);
+    }
+    return block_sparse_jacobian_partitioned.get();
+  }
+
+  const CompressedRowSparseMatrix* CompressedRowSparseJacobian(
+      ContextImpl* context) {
+    if (!crs_jacobian) {
+      crs_jacobian = CreateCompressedRowSparseJacobian(context);
+    }
+    return crs_jacobian.get();
+  }
+
+  std::unique_ptr<PartitionedView> PartitionedMatrixViewJacobian(
+      const LinearSolver::Options& options) {
+    auto block_sparse = BlockSparseJacobianPartitioned(options.context);
+    return std::make_unique<PartitionedView>(options, *block_sparse);
+  }
+
+  BlockSparseMatrix* BlockDiagonalEtE(const LinearSolver::Options& options) {
+    if (!block_diagonal_ete) {
+      auto partitioned_view = PartitionedMatrixViewJacobian(options);
+      block_diagonal_ete = partitioned_view->CreateBlockDiagonalEtE();
+    }
+    return block_diagonal_ete.get();
+  }
+
+  BlockSparseMatrix* BlockDiagonalFtF(const LinearSolver::Options& options) {
+    if (!block_diagonal_ftf) {
+      auto partitioned_view = PartitionedMatrixViewJacobian(options);
+      block_diagonal_ftf = partitioned_view->CreateBlockDiagonalFtF();
+    }
+    return block_diagonal_ftf.get();
+  }
+
+  const ImplicitSchurComplement* ImplicitSchurComplementWithoutDiagonal(
+      const LinearSolver::Options& options) {
+    auto block_sparse = BlockSparseJacobianPartitioned(options.context);
+    implicit_schur_complement =
+        std::make_unique<ImplicitSchurComplement>(options);
+    implicit_schur_complement->Init(*block_sparse, nullptr, b.data());
+    return implicit_schur_complement.get();
+  }
+
+  const ImplicitSchurComplement* ImplicitSchurComplementWithDiagonal(
+      const LinearSolver::Options& options) {
+    auto block_sparse = BlockSparseJacobianPartitioned(options.context);
+    implicit_schur_complement_diag =
+        std::make_unique<ImplicitSchurComplement>(options);
+    implicit_schur_complement_diag->Init(*block_sparse, D.data(), b.data());
+    return implicit_schur_complement_diag.get();
+  }
+
+  Vector parameters;
+  Vector D;
+  Vector b;
+  std::unique_ptr<BundleAdjustmentProblem> bal_problem;
+  std::unique_ptr<PreprocessedProblem> preprocessed_problem;
+  std::unique_ptr<BlockSparseMatrix> block_sparse_jacobian_partitioned;
+  std::unique_ptr<BlockSparseMatrix> block_sparse_jacobian;
+  std::unique_ptr<CompressedRowSparseMatrix> crs_jacobian;
+  std::unique_ptr<BlockSparseMatrix> block_diagonal_ete;
+  std::unique_ptr<BlockSparseMatrix> block_diagonal_ftf;
+  std::unique_ptr<ImplicitSchurComplement> implicit_schur_complement;
+  std::unique_ptr<ImplicitSchurComplement> implicit_schur_complement_diag;
+};
+
+static void Residuals(benchmark::State& state,
+                      BALData* data,
+                      ContextImpl* context) {
+  const int num_threads = static_cast<int>(state.range(0));
+
+  Evaluator::Options options;
+  options.linear_solver_type = SPARSE_NORMAL_CHOLESKY;
+  options.num_threads = num_threads;
+  options.context = context;
+  options.num_eliminate_blocks = 0;
+
+  std::string error;
+  CHECK(data->preprocessed_problem != nullptr);
+  auto program = data->preprocessed_problem->reduced_program.get();
+  CHECK(program != nullptr);
+  auto evaluator = Evaluator::Create(options, program, &error);
+  CHECK(evaluator != nullptr);
+
+  double cost = 0.;
+  Vector residuals = Vector::Zero(program->NumResiduals());
+
+  Evaluator::EvaluateOptions eval_options;
+  for (auto _ : state) {
+    CHECK(evaluator->Evaluate(eval_options,
+                              data->parameters.data(),
+                              &cost,
+                              residuals.data(),
+                              nullptr,
+                              nullptr));
+  }
+}
+
+static void ResidualsAndJacobian(benchmark::State& state,
+                                 BALData* data,
+                                 ContextImpl* context) {
+  const int num_threads = static_cast<int>(state.range(0));
+
+  Evaluator::Options options;
+  options.linear_solver_type = SPARSE_NORMAL_CHOLESKY;
+  options.num_threads = num_threads;
+  options.context = context;
+  options.num_eliminate_blocks = 0;
+
+  std::string error;
+  CHECK(data->preprocessed_problem != nullptr);
+  auto program = data->preprocessed_problem->reduced_program.get();
+  CHECK(program != nullptr);
+  auto evaluator = Evaluator::Create(options, program, &error);
+  CHECK(evaluator != nullptr);
+
+  double cost = 0.;
+  Vector residuals = Vector::Zero(program->NumResiduals());
+  auto jacobian = evaluator->CreateJacobian();
+
+  Evaluator::EvaluateOptions eval_options;
+  for (auto _ : state) {
+    CHECK(evaluator->Evaluate(eval_options,
+                              data->parameters.data(),
+                              &cost,
+                              residuals.data(),
+                              nullptr,
+                              jacobian.get()));
+  }
+}
+
+static void Plus(benchmark::State& state, BALData* data, ContextImpl* context) {
+  const int num_threads = static_cast<int>(state.range(0));
+
+  Evaluator::Options options;
+  options.linear_solver_type = SPARSE_NORMAL_CHOLESKY;
+  options.num_threads = num_threads;
+  options.context = context;
+  options.num_eliminate_blocks = 0;
+
+  std::string error;
+  CHECK(data->preprocessed_problem != nullptr);
+  auto program = data->preprocessed_problem->reduced_program.get();
+  CHECK(program != nullptr);
+  auto evaluator = Evaluator::Create(options, program, &error);
+  CHECK(evaluator != nullptr);
+
+  Vector state_plus_delta = Vector::Zero(program->NumParameters());
+  Vector delta = Vector::Random(program->NumEffectiveParameters());
+
+  for (auto _ : state) {
+    CHECK(evaluator->Plus(
+        data->parameters.data(), delta.data(), state_plus_delta.data()));
+  }
+  CHECK_GT(state_plus_delta.squaredNorm(), 0.);
+}
+
+static void PSEPreconditioner(benchmark::State& state,
+                              BALData* data,
+                              ContextImpl* context) {
+  LinearSolver::Options options;
+  options.num_threads = static_cast<int>(state.range(0));
+  options.elimination_groups.push_back(data->bal_problem->num_points());
+  options.context = context;
+
+  auto jacobian = data->ImplicitSchurComplementWithDiagonal(options);
+  Preconditioner::Options preconditioner_options(options);
+
+  PowerSeriesExpansionPreconditioner preconditioner(
+      jacobian, 10, 0, preconditioner_options);
+
+  Vector y = Vector::Zero(jacobian->num_cols());
+  Vector x = Vector::Random(jacobian->num_cols());
+
+  for (auto _ : state) {
+    preconditioner.RightMultiplyAndAccumulate(x.data(), y.data());
+  }
+  CHECK_GT(y.squaredNorm(), 0.);
+}
+
+static void PMVRightMultiplyAndAccumulateF(benchmark::State& state,
+                                           BALData* data,
+                                           ContextImpl* context) {
+  LinearSolver::Options options;
+  options.num_threads = static_cast<int>(state.range(0));
+  options.elimination_groups.push_back(data->bal_problem->num_points());
+  options.context = context;
+  auto jacobian = data->PartitionedMatrixViewJacobian(options);
+
+  Vector y = Vector::Zero(jacobian->num_rows());
+  Vector x = Vector::Random(jacobian->num_cols_f());
+
+  for (auto _ : state) {
+    jacobian->RightMultiplyAndAccumulateF(x.data(), y.data());
+  }
+  CHECK_GT(y.squaredNorm(), 0.);
+}
+
+static void PMVLeftMultiplyAndAccumulateF(benchmark::State& state,
+                                          BALData* data,
+                                          ContextImpl* context) {
+  LinearSolver::Options options;
+  options.num_threads = static_cast<int>(state.range(0));
+  options.elimination_groups.push_back(data->bal_problem->num_points());
+  options.context = context;
+  auto jacobian = data->PartitionedMatrixViewJacobian(options);
+
+  Vector y = Vector::Zero(jacobian->num_cols_f());
+  Vector x = Vector::Random(jacobian->num_rows());
+
+  for (auto _ : state) {
+    jacobian->LeftMultiplyAndAccumulateF(x.data(), y.data());
+  }
+  CHECK_GT(y.squaredNorm(), 0.);
+}
+
+static void PMVRightMultiplyAndAccumulateE(benchmark::State& state,
+                                           BALData* data,
+                                           ContextImpl* context) {
+  LinearSolver::Options options;
+  options.num_threads = static_cast<int>(state.range(0));
+  options.elimination_groups.push_back(data->bal_problem->num_points());
+  options.context = context;
+  auto jacobian = data->PartitionedMatrixViewJacobian(options);
+
+  Vector y = Vector::Zero(jacobian->num_rows());
+  Vector x = Vector::Random(jacobian->num_cols_e());
+
+  for (auto _ : state) {
+    jacobian->RightMultiplyAndAccumulateE(x.data(), y.data());
+  }
+  CHECK_GT(y.squaredNorm(), 0.);
+}
+
+static void PMVLeftMultiplyAndAccumulateE(benchmark::State& state,
+                                          BALData* data,
+                                          ContextImpl* context) {
+  LinearSolver::Options options;
+  options.num_threads = static_cast<int>(state.range(0));
+  options.elimination_groups.push_back(data->bal_problem->num_points());
+  options.context = context;
+  auto jacobian = data->PartitionedMatrixViewJacobian(options);
+
+  Vector y = Vector::Zero(jacobian->num_cols_e());
+  Vector x = Vector::Random(jacobian->num_rows());
+
+  for (auto _ : state) {
+    jacobian->LeftMultiplyAndAccumulateE(x.data(), y.data());
+  }
+  CHECK_GT(y.squaredNorm(), 0.);
+}
+
+static void PMVUpdateBlockDiagonalEtE(benchmark::State& state,
+                                      BALData* data,
+                                      ContextImpl* context) {
+  LinearSolver::Options options;
+  options.num_threads = static_cast<int>(state.range(0));
+  options.elimination_groups.push_back(data->bal_problem->num_points());
+  options.context = context;
+  auto jacobian = data->PartitionedMatrixViewJacobian(options);
+  auto block_diagonal_ete = data->BlockDiagonalEtE(options);
+
+  for (auto _ : state) {
+    jacobian->UpdateBlockDiagonalEtE(block_diagonal_ete);
+  }
+}
+
+static void PMVUpdateBlockDiagonalFtF(benchmark::State& state,
+                                      BALData* data,
+                                      ContextImpl* context) {
+  LinearSolver::Options options;
+  options.num_threads = static_cast<int>(state.range(0));
+  options.elimination_groups.push_back(data->bal_problem->num_points());
+  options.context = context;
+  auto jacobian = data->PartitionedMatrixViewJacobian(options);
+  auto block_diagonal_ftf = data->BlockDiagonalFtF(options);
+
+  for (auto _ : state) {
+    jacobian->UpdateBlockDiagonalFtF(block_diagonal_ftf);
+  }
+}
+
+static void ISCRightMultiplyNoDiag(benchmark::State& state,
+                                   BALData* data,
+                                   ContextImpl* context) {
+  LinearSolver::Options options;
+  options.num_threads = static_cast<int>(state.range(0));
+  options.elimination_groups.push_back(data->bal_problem->num_points());
+  options.context = context;
+  auto jacobian = data->ImplicitSchurComplementWithoutDiagonal(options);
+
+  Vector y = Vector::Zero(jacobian->num_rows());
+  Vector x = Vector::Random(jacobian->num_cols());
+  for (auto _ : state) {
+    jacobian->RightMultiplyAndAccumulate(x.data(), y.data());
+  }
+  CHECK_GT(y.squaredNorm(), 0.);
+}
+
+static void ISCRightMultiplyDiag(benchmark::State& state,
+                                 BALData* data,
+                                 ContextImpl* context) {
+  LinearSolver::Options options;
+  options.num_threads = static_cast<int>(state.range(0));
+  options.elimination_groups.push_back(data->bal_problem->num_points());
+  options.context = context;
+
+  auto jacobian = data->ImplicitSchurComplementWithDiagonal(options);
+
+  Vector y = Vector::Zero(jacobian->num_rows());
+  Vector x = Vector::Random(jacobian->num_cols());
+  for (auto _ : state) {
+    jacobian->RightMultiplyAndAccumulate(x.data(), y.data());
+  }
+  CHECK_GT(y.squaredNorm(), 0.);
+}
+
+static void JacobianToCRS(benchmark::State& state,
+                          BALData* data,
+                          ContextImpl* context) {
+  auto jacobian = data->BlockSparseJacobian(context);
+
+  std::unique_ptr<CompressedRowSparseMatrix> matrix;
+  for (auto _ : state) {
+    matrix = jacobian->ToCompressedRowSparseMatrix();
+  }
+  CHECK(matrix != nullptr);
+}
+
+#ifndef CERES_NO_CUDA
+static void PMVRightMultiplyAndAccumulateFCuda(benchmark::State& state,
+                                               BALData* data,
+                                               ContextImpl* context) {
+  LinearSolver::Options options;
+  options.elimination_groups.push_back(data->bal_problem->num_points());
+  options.context = context;
+  options.num_threads = 1;
+  auto jacobian = data->PartitionedMatrixViewJacobian(options);
+  auto underlying_matrix = data->BlockSparseJacobianPartitioned(context);
+  CudaPartitionedBlockSparseCRSView view(
+      *underlying_matrix, jacobian->num_col_blocks_e(), context);
+
+  Vector x = Vector::Random(jacobian->num_cols_f());
+  CudaVector cuda_x(context, x.size());
+  CudaVector cuda_y(context, jacobian->num_rows());
+
+  cuda_x.CopyFromCpu(x);
+  cuda_y.SetZero();
+
+  auto matrix = view.matrix_f();
+  for (auto _ : state) {
+    matrix->RightMultiplyAndAccumulate(cuda_x, &cuda_y);
+  }
+  CHECK_GT(cuda_y.Norm(), 0.);
+}
+
+static void PMVLeftMultiplyAndAccumulateFCuda(benchmark::State& state,
+                                              BALData* data,
+                                              ContextImpl* context) {
+  LinearSolver::Options options;
+  options.elimination_groups.push_back(data->bal_problem->num_points());
+  options.context = context;
+  options.num_threads = 1;
+  auto jacobian = data->PartitionedMatrixViewJacobian(options);
+  auto underlying_matrix = data->BlockSparseJacobianPartitioned(context);
+  CudaPartitionedBlockSparseCRSView view(
+      *underlying_matrix, jacobian->num_col_blocks_e(), context);
+
+  Vector x = Vector::Random(jacobian->num_rows());
+  CudaVector cuda_x(context, x.size());
+  CudaVector cuda_y(context, jacobian->num_cols_f());
+
+  cuda_x.CopyFromCpu(x);
+  cuda_y.SetZero();
+
+  auto matrix = view.matrix_f();
+  for (auto _ : state) {
+    matrix->LeftMultiplyAndAccumulate(cuda_x, &cuda_y);
+  }
+  CHECK_GT(cuda_y.Norm(), 0.);
+}
+
+static void PMVRightMultiplyAndAccumulateECuda(benchmark::State& state,
+                                               BALData* data,
+                                               ContextImpl* context) {
+  LinearSolver::Options options;
+  options.elimination_groups.push_back(data->bal_problem->num_points());
+  options.context = context;
+  options.num_threads = 1;
+  auto jacobian = data->PartitionedMatrixViewJacobian(options);
+  auto underlying_matrix = data->BlockSparseJacobianPartitioned(context);
+  CudaPartitionedBlockSparseCRSView view(
+      *underlying_matrix, jacobian->num_col_blocks_e(), context);
+
+  Vector x = Vector::Random(jacobian->num_cols_e());
+  CudaVector cuda_x(context, x.size());
+  CudaVector cuda_y(context, jacobian->num_rows());
+
+  cuda_x.CopyFromCpu(x);
+  cuda_y.SetZero();
+
+  auto matrix = view.matrix_e();
+  for (auto _ : state) {
+    matrix->RightMultiplyAndAccumulate(cuda_x, &cuda_y);
+  }
+  CHECK_GT(cuda_y.Norm(), 0.);
+}
+
+static void PMVLeftMultiplyAndAccumulateECuda(benchmark::State& state,
+                                              BALData* data,
+                                              ContextImpl* context) {
+  LinearSolver::Options options;
+  options.elimination_groups.push_back(data->bal_problem->num_points());
+  options.context = context;
+  options.num_threads = 1;
+  auto jacobian = data->PartitionedMatrixViewJacobian(options);
+  auto underlying_matrix = data->BlockSparseJacobianPartitioned(context);
+  CudaPartitionedBlockSparseCRSView view(
+      *underlying_matrix, jacobian->num_col_blocks_e(), context);
+
+  Vector x = Vector::Random(jacobian->num_rows());
+  CudaVector cuda_x(context, x.size());
+  CudaVector cuda_y(context, jacobian->num_cols_e());
+
+  cuda_x.CopyFromCpu(x);
+  cuda_y.SetZero();
+
+  auto matrix = view.matrix_e();
+  for (auto _ : state) {
+    matrix->LeftMultiplyAndAccumulate(cuda_x, &cuda_y);
+  }
+  CHECK_GT(cuda_y.Norm(), 0.);
+}
+
+// We want CudaBlockSparseCRSView to be not slower than explicit conversion to
+// CRS on CPU
+static void JacobianToCRSView(benchmark::State& state,
+                              BALData* data,
+                              ContextImpl* context) {
+  auto jacobian = data->BlockSparseJacobian(context);
+
+  std::unique_ptr<CudaBlockSparseCRSView> matrix;
+  for (auto _ : state) {
+    matrix = std::make_unique<CudaBlockSparseCRSView>(*jacobian, context);
+  }
+  CHECK(matrix != nullptr);
+}
+static void JacobianToCRSMatrix(benchmark::State& state,
+                                BALData* data,
+                                ContextImpl* context) {
+  auto jacobian = data->BlockSparseJacobian(context);
+
+  std::unique_ptr<CudaSparseMatrix> matrix;
+  std::unique_ptr<CompressedRowSparseMatrix> matrix_cpu;
+  for (auto _ : state) {
+    matrix_cpu = jacobian->ToCompressedRowSparseMatrix();
+    matrix = std::make_unique<CudaSparseMatrix>(context, *matrix_cpu);
+  }
+  CHECK(matrix != nullptr);
+}
+// Updating values in CudaBlockSparseCRSView should be +- as fast as just
+// copying values (time spent in value permutation has to be hidden by PCIe
+// transfer)
+static void JacobianToCRSViewUpdate(benchmark::State& state,
+                                    BALData* data,
+                                    ContextImpl* context) {
+  auto jacobian = data->BlockSparseJacobian(context);
+
+  auto matrix = CudaBlockSparseCRSView(*jacobian, context);
+  for (auto _ : state) {
+    matrix.UpdateValues(*jacobian);
+  }
+}
+static void JacobianToCRSMatrixUpdate(benchmark::State& state,
+                                      BALData* data,
+                                      ContextImpl* context) {
+  auto jacobian = data->BlockSparseJacobian(context);
+
+  auto matrix_cpu = jacobian->ToCompressedRowSparseMatrix();
+  auto matrix = std::make_unique<CudaSparseMatrix>(context, *matrix_cpu);
+  for (auto _ : state) {
+    CHECK_EQ(cudaSuccess,
+             cudaMemcpy(matrix->mutable_values(),
+                        matrix_cpu->values(),
+                        matrix->num_nonzeros() * sizeof(double),
+                        cudaMemcpyHostToDevice));
+  }
+}
+#endif
+
+static void JacobianSquaredColumnNorm(benchmark::State& state,
+                                      BALData* data,
+                                      ContextImpl* context) {
+  const int num_threads = static_cast<int>(state.range(0));
+
+  auto jacobian = data->BlockSparseJacobian(context);
+
+  Vector x = Vector::Zero(jacobian->num_cols());
+
+  for (auto _ : state) {
+    jacobian->SquaredColumnNorm(x.data(), context, num_threads);
+  }
+  CHECK_GT(x.squaredNorm(), 0.);
+}
+
+static void JacobianScaleColumns(benchmark::State& state,
+                                 BALData* data,
+                                 ContextImpl* context) {
+  const int num_threads = static_cast<int>(state.range(0));
+
+  auto jacobian_const = data->BlockSparseJacobian(context);
+  auto jacobian = const_cast<BlockSparseMatrix*>(jacobian_const);
+
+  Vector x = Vector::Ones(jacobian->num_cols());
+
+  for (auto _ : state) {
+    jacobian->ScaleColumns(x.data(), context, num_threads);
+  }
+}
+
+static void JacobianRightMultiplyAndAccumulate(benchmark::State& state,
+                                               BALData* data,
+                                               ContextImpl* context) {
+  const int num_threads = static_cast<int>(state.range(0));
+
+  auto jacobian = data->BlockSparseJacobian(context);
+
+  Vector y = Vector::Zero(jacobian->num_rows());
+  Vector x = Vector::Random(jacobian->num_cols());
+
+  for (auto _ : state) {
+    jacobian->RightMultiplyAndAccumulate(
+        x.data(), y.data(), context, num_threads);
+  }
+  CHECK_GT(y.squaredNorm(), 0.);
+}
+
+static void JacobianLeftMultiplyAndAccumulate(benchmark::State& state,
+                                              BALData* data,
+                                              ContextImpl* context) {
+  const int num_threads = static_cast<int>(state.range(0));
+
+  auto jacobian = data->BlockSparseJacobian(context);
+
+  Vector y = Vector::Zero(jacobian->num_cols());
+  Vector x = Vector::Random(jacobian->num_rows());
+
+  for (auto _ : state) {
+    jacobian->LeftMultiplyAndAccumulate(
+        x.data(), y.data(), context, num_threads);
+  }
+  CHECK_GT(y.squaredNorm(), 0.);
+}
+
+#ifndef CERES_NO_CUDA
+static void JacobianRightMultiplyAndAccumulateCuda(benchmark::State& state,
+                                                   BALData* data,
+                                                   ContextImpl* context) {
+  auto crs_jacobian = data->CompressedRowSparseJacobian(context);
+  CudaSparseMatrix cuda_jacobian(context, *crs_jacobian);
+  CudaVector cuda_x(context, 0);
+  CudaVector cuda_y(context, 0);
+
+  Vector x(crs_jacobian->num_cols());
+  Vector y(crs_jacobian->num_rows());
+  x.setRandom();
+  y.setRandom();
+
+  cuda_x.CopyFromCpu(x);
+  cuda_y.CopyFromCpu(y);
+  double sum = 0;
+  for (auto _ : state) {
+    cuda_jacobian.RightMultiplyAndAccumulate(cuda_x, &cuda_y);
+    sum += cuda_y.Norm();
+    CHECK_EQ(cudaDeviceSynchronize(), cudaSuccess);
+  }
+  CHECK_NE(sum, 0.0);
+}
+
+static void JacobianLeftMultiplyAndAccumulateCuda(benchmark::State& state,
+                                                  BALData* data,
+                                                  ContextImpl* context) {
+  auto crs_jacobian = data->CompressedRowSparseJacobian(context);
+  CudaSparseMatrix cuda_jacobian(context, *crs_jacobian);
+  CudaVector cuda_x(context, 0);
+  CudaVector cuda_y(context, 0);
+
+  Vector x(crs_jacobian->num_rows());
+  Vector y(crs_jacobian->num_cols());
+  x.setRandom();
+  y.setRandom();
+
+  cuda_x.CopyFromCpu(x);
+  cuda_y.CopyFromCpu(y);
+  double sum = 0;
+  for (auto _ : state) {
+    cuda_jacobian.LeftMultiplyAndAccumulate(cuda_x, &cuda_y);
+    sum += cuda_y.Norm();
+    CHECK_EQ(cudaDeviceSynchronize(), cudaSuccess);
+  }
+  CHECK_NE(sum, 0.0);
+}
+#endif
+
+}  // namespace ceres::internal
+
+// Older versions of benchmark library might come without ::benchmark::Shutdown
+// function. We provide an empty fallback variant of Shutdown function in
+// order to support both older and newer versions
+namespace benchmark_shutdown_fallback {
+template <typename... Args>
+void Shutdown(Args... args) {}
+};  // namespace benchmark_shutdown_fallback
+
+int main(int argc, char** argv) {
+  ::benchmark::Initialize(&argc, argv);
+
+  std::vector<std::unique_ptr<ceres::internal::BALData>> benchmark_data;
+  if (argc == 1) {
+    LOG(FATAL) << "No input datasets specified. Usage: " << argv[0]
+               << " [benchmark flags] path_to_BAL_data_1.txt ... "
+                  "path_to_BAL_data_N.txt";
+    return -1;
+  }
+
+  ceres::internal::ContextImpl context;
+  context.EnsureMinimumThreads(16);
+#ifndef CERES_NO_CUDA
+  std::string message;
+  context.InitCuda(&message);
+#endif
+
+  for (int i = 1; i < argc; ++i) {
+    const std::string path(argv[i]);
+    const std::string name_residuals = "Residuals<" + path + ">";
+    benchmark_data.emplace_back(
+        std::make_unique<ceres::internal::BALData>(path));
+    auto data = benchmark_data.back().get();
+    ::benchmark::RegisterBenchmark(
+        name_residuals.c_str(), ceres::internal::Residuals, data, &context)
+        ->Arg(1)
+        ->Arg(2)
+        ->Arg(4)
+        ->Arg(8)
+        ->Arg(16);
+
+    const std::string name_jacobians = "ResidualsAndJacobian<" + path + ">";
+    ::benchmark::RegisterBenchmark(name_jacobians.c_str(),
+                                   ceres::internal::ResidualsAndJacobian,
+                                   data,
+                                   &context)
+        ->Arg(1)
+        ->Arg(2)
+        ->Arg(4)
+        ->Arg(8)
+        ->Arg(16);
+
+    const std::string name_plus = "Plus<" + path + ">";
+    ::benchmark::RegisterBenchmark(
+        name_plus.c_str(), ceres::internal::Plus, data, &context)
+        ->Arg(1)
+        ->Arg(2)
+        ->Arg(4)
+        ->Arg(8)
+        ->Arg(16);
+
+    const std::string name_right_product =
+        "JacobianRightMultiplyAndAccumulate<" + path + ">";
+    ::benchmark::RegisterBenchmark(
+        name_right_product.c_str(),
+        ceres::internal::JacobianRightMultiplyAndAccumulate,
+        data,
+        &context)
+        ->Arg(1)
+        ->Arg(2)
+        ->Arg(4)
+        ->Arg(8)
+        ->Arg(16);
+
+    const std::string name_right_product_partitioned_f =
+        "PMVRightMultiplyAndAccumulateF<" + path + ">";
+    ::benchmark::RegisterBenchmark(
+        name_right_product_partitioned_f.c_str(),
+        ceres::internal::PMVRightMultiplyAndAccumulateF,
+        data,
+        &context)
+        ->Arg(1)
+        ->Arg(2)
+        ->Arg(4)
+        ->Arg(8)
+        ->Arg(16);
+
+#ifndef CERES_NO_CUDA
+    const std::string name_right_product_partitioned_f_cuda =
+        "PMVRightMultiplyAndAccumulateFCuda<" + path + ">";
+    ::benchmark::RegisterBenchmark(
+        name_right_product_partitioned_f_cuda.c_str(),
+        ceres::internal::PMVRightMultiplyAndAccumulateFCuda,
+        data,
+        &context);
+#endif
+
+    const std::string name_right_product_partitioned_e =
+        "PMVRightMultiplyAndAccumulateE<" + path + ">";
+    ::benchmark::RegisterBenchmark(
+        name_right_product_partitioned_e.c_str(),
+        ceres::internal::PMVRightMultiplyAndAccumulateE,
+        data,
+        &context)
+        ->Arg(1)
+        ->Arg(2)
+        ->Arg(4)
+        ->Arg(8)
+        ->Arg(16);
+
+#ifndef CERES_NO_CUDA
+    const std::string name_right_product_partitioned_e_cuda =
+        "PMVRightMultiplyAndAccumulateECuda<" + path + ">";
+    ::benchmark::RegisterBenchmark(
+        name_right_product_partitioned_e_cuda.c_str(),
+        ceres::internal::PMVRightMultiplyAndAccumulateECuda,
+        data,
+        &context);
+#endif
+
+    const std::string name_update_block_diagonal_ftf =
+        "PMVUpdateBlockDiagonalFtF<" + path + ">";
+    ::benchmark::RegisterBenchmark(name_update_block_diagonal_ftf.c_str(),
+                                   ceres::internal::PMVUpdateBlockDiagonalFtF,
+                                   data,
+                                   &context)
+        ->Arg(1)
+        ->Arg(2)
+        ->Arg(4)
+        ->Arg(8)
+        ->Arg(16);
+
+    const std::string name_pse =
+        "PSEPreconditionerRightMultiplyAndAccumulate<" + path + ">";
+    ::benchmark::RegisterBenchmark(
+        name_pse.c_str(), ceres::internal::PSEPreconditioner, data, &context)
+        ->Arg(1)
+        ->Arg(2)
+        ->Arg(4)
+        ->Arg(8)
+        ->Arg(16);
+
+    const std::string name_isc_no_diag =
+        "ISCRightMultiplyAndAccumulate<" + path + ">";
+    ::benchmark::RegisterBenchmark(name_isc_no_diag.c_str(),
+                                   ceres::internal::ISCRightMultiplyNoDiag,
+                                   data,
+                                   &context)
+        ->Arg(1)
+        ->Arg(2)
+        ->Arg(4)
+        ->Arg(8)
+        ->Arg(16);
+
+    const std::string name_update_block_diagonal_ete =
+        "PMVUpdateBlockDiagonalEtE<" + path + ">";
+    ::benchmark::RegisterBenchmark(name_update_block_diagonal_ete.c_str(),
+                                   ceres::internal::PMVUpdateBlockDiagonalEtE,
+                                   data,
+                                   &context)
+        ->Arg(1)
+        ->Arg(2)
+        ->Arg(4)
+        ->Arg(8)
+        ->Arg(16);
+    const std::string name_isc_diag =
+        "ISCRightMultiplyAndAccumulateDiag<" + path + ">";
+    ::benchmark::RegisterBenchmark(name_isc_diag.c_str(),
+                                   ceres::internal::ISCRightMultiplyDiag,
+                                   data,
+                                   &context)
+        ->Arg(1)
+        ->Arg(2)
+        ->Arg(4)
+        ->Arg(8)
+        ->Arg(16);
+
+#ifndef CERES_NO_CUDA
+    const std::string name_right_product_cuda =
+        "JacobianRightMultiplyAndAccumulateCuda<" + path + ">";
+    ::benchmark::RegisterBenchmark(
+        name_right_product_cuda.c_str(),
+        ceres::internal::JacobianRightMultiplyAndAccumulateCuda,
+        data,
+        &context)
+        ->Arg(1);
+#endif
+
+    const std::string name_left_product =
+        "JacobianLeftMultiplyAndAccumulate<" + path + ">";
+    ::benchmark::RegisterBenchmark(
+        name_left_product.c_str(),
+        ceres::internal::JacobianLeftMultiplyAndAccumulate,
+        data,
+        &context)
+        ->Arg(1)
+        ->Arg(2)
+        ->Arg(4)
+        ->Arg(8)
+        ->Arg(16);
+
+    const std::string name_left_product_partitioned_f =
+        "PMVLeftMultiplyAndAccumulateF<" + path + ">";
+    ::benchmark::RegisterBenchmark(
+        name_left_product_partitioned_f.c_str(),
+        ceres::internal::PMVLeftMultiplyAndAccumulateF,
+        data,
+        &context)
+        ->Arg(1)
+        ->Arg(2)
+        ->Arg(4)
+        ->Arg(8)
+        ->Arg(16);
+
+#ifndef CERES_NO_CUDA
+    const std::string name_left_product_partitioned_f_cuda =
+        "PMVLeftMultiplyAndAccumulateFCuda<" + path + ">";
+    ::benchmark::RegisterBenchmark(
+        name_left_product_partitioned_f_cuda.c_str(),
+        ceres::internal::PMVLeftMultiplyAndAccumulateFCuda,
+        data,
+        &context);
+#endif
+
+    const std::string name_left_product_partitioned_e =
+        "PMVLeftMultiplyAndAccumulateE<" + path + ">";
+    ::benchmark::RegisterBenchmark(
+        name_left_product_partitioned_e.c_str(),
+        ceres::internal::PMVLeftMultiplyAndAccumulateE,
+        data,
+        &context)
+        ->Arg(1)
+        ->Arg(2)
+        ->Arg(4)
+        ->Arg(8)
+        ->Arg(16);
+
+#ifndef CERES_NO_CUDA
+    const std::string name_left_product_partitioned_e_cuda =
+        "PMVLeftMultiplyAndAccumulateECuda<" + path + ">";
+    ::benchmark::RegisterBenchmark(
+        name_left_product_partitioned_e_cuda.c_str(),
+        ceres::internal::PMVLeftMultiplyAndAccumulateECuda,
+        data,
+        &context);
+#endif
+
+#ifndef CERES_NO_CUDA
+    const std::string name_left_product_cuda =
+        "JacobianLeftMultiplyAndAccumulateCuda<" + path + ">";
+    ::benchmark::RegisterBenchmark(
+        name_left_product_cuda.c_str(),
+        ceres::internal::JacobianLeftMultiplyAndAccumulateCuda,
+        data,
+        &context)
+        ->Arg(1);
+#endif
+
+    const std::string name_squared_column_norm =
+        "JacobianSquaredColumnNorm<" + path + ">";
+    ::benchmark::RegisterBenchmark(name_squared_column_norm.c_str(),
+                                   ceres::internal::JacobianSquaredColumnNorm,
+                                   data,
+                                   &context)
+        ->Arg(1)
+        ->Arg(2)
+        ->Arg(4)
+        ->Arg(8)
+        ->Arg(16);
+
+    const std::string name_scale_columns = "JacobianScaleColumns<" + path + ">";
+    ::benchmark::RegisterBenchmark(name_scale_columns.c_str(),
+                                   ceres::internal::JacobianScaleColumns,
+                                   data,
+                                   &context)
+        ->Arg(1)
+        ->Arg(2)
+        ->Arg(4)
+        ->Arg(8)
+        ->Arg(16);
+
+    const std::string name_to_crs = "JacobianToCRS<" + path + ">";
+    ::benchmark::RegisterBenchmark(
+        name_to_crs.c_str(), ceres::internal::JacobianToCRS, data, &context);
+#ifndef CERES_NO_CUDA
+    const std::string name_to_crs_view = "JacobianToCRSView<" + path + ">";
+    ::benchmark::RegisterBenchmark(name_to_crs_view.c_str(),
+                                   ceres::internal::JacobianToCRSView,
+                                   data,
+                                   &context);
+    const std::string name_to_crs_matrix = "JacobianToCRSMatrix<" + path + ">";
+    ::benchmark::RegisterBenchmark(name_to_crs_matrix.c_str(),
+                                   ceres::internal::JacobianToCRSMatrix,
+                                   data,
+                                   &context);
+    const std::string name_to_crs_view_update =
+        "JacobianToCRSViewUpdate<" + path + ">";
+    ::benchmark::RegisterBenchmark(name_to_crs_view_update.c_str(),
+                                   ceres::internal::JacobianToCRSViewUpdate,
+                                   data,
+                                   &context);
+    const std::string name_to_crs_matrix_update =
+        "JacobianToCRSMatrixUpdate<" + path + ">";
+    ::benchmark::RegisterBenchmark(name_to_crs_matrix_update.c_str(),
+                                   ceres::internal::JacobianToCRSMatrixUpdate,
+                                   data,
+                                   &context);
+#endif
+  }
+  ::benchmark::RunSpecifiedBenchmarks();
+
+  using namespace ::benchmark;
+  using namespace benchmark_shutdown_fallback;
+  Shutdown();
+  return 0;
+}
diff --git a/third_party/ceres/internal/ceres/evaluation_callback.cc b/third_party/ceres/internal/ceres/evaluation_callback.cc
new file mode 100644
index 0000000..5ac6645
--- /dev/null
+++ b/third_party/ceres/internal/ceres/evaluation_callback.cc
@@ -0,0 +1,37 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: mierle@gmail.com (Keir Mierle)
+
+#include "ceres/evaluation_callback.h"
+
+namespace ceres {
+
+EvaluationCallback::~EvaluationCallback() = default;
+
+}  // namespace ceres
diff --git a/third_party/ceres/internal/ceres/evaluation_callback_test.cc b/third_party/ceres/internal/ceres/evaluation_callback_test.cc
index 19a7eb5..7ce110c 100644
--- a/third_party/ceres/internal/ceres/evaluation_callback_test.cc
+++ b/third_party/ceres/internal/ceres/evaluation_callback_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -32,6 +32,7 @@
 
 #include <cmath>
 #include <limits>
+#include <memory>
 #include <vector>
 
 #include "ceres/autodiff_cost_function.h"
@@ -41,15 +42,14 @@
 #include "ceres/solver.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // Use an inline hash function to avoid portability wrangling. Algorithm from
 // Daniel Bernstein, known as the "djb2" hash.
 template <typename T>
 uint64_t Djb2Hash(const T* data, const int size) {
   uint64_t hash = 5381;
-  const uint8_t* data_as_bytes = reinterpret_cast<const uint8_t*>(data);
+  const auto* data_as_bytes = reinterpret_cast<const uint8_t*>(data);
   for (int i = 0; i < sizeof(*data) * size; ++i) {
     hash = hash * 33 + data_as_bytes[i];
   }
@@ -72,8 +72,6 @@
         evaluate_num_calls(0),
         evaluate_last_parameter_hash(kUninitialized) {}
 
-  virtual ~WigglyBowlCostFunctionAndEvaluationCallback() {}
-
   // Evaluation callback interface. This checks that all the preconditions are
   // met at the point that Ceres calls into it.
   void PrepareForEvaluation(bool evaluate_jacobians,
@@ -132,7 +130,7 @@
     double y = (*parameters)[1];
     residuals[0] = y - a * sin(x);
     residuals[1] = x;
-    if (jacobians != NULL) {
+    if (jacobians != nullptr) {
       (*jacobians)[2 * 0 + 0] = -a * cos(x);  // df1/dx
       (*jacobians)[2 * 0 + 1] = 1.0;          // df1/dy
       (*jacobians)[2 * 1 + 0] = 1.0;          // df2/dx
@@ -157,7 +155,7 @@
     EXPECT_EQ(prepare_parameter_hash, incoming_parameter_hash);
 
     // Check: jacobians are requested if they were in PrepareForEvaluation().
-    EXPECT_EQ(prepare_requested_jacobians, jacobians != NULL);
+    EXPECT_EQ(prepare_requested_jacobians, jacobians != nullptr);
 
     evaluate_num_calls++;
     evaluate_last_parameter_hash = incoming_parameter_hash;
@@ -196,7 +194,7 @@
   problem_options.evaluation_callback = &cost_function;
   problem_options.cost_function_ownership = DO_NOT_TAKE_OWNERSHIP;
   Problem problem(problem_options);
-  problem.AddResidualBlock(&cost_function, NULL, parameters);
+  problem.AddResidualBlock(&cost_function, nullptr, parameters);
 
   Solver::Options options;
   options.linear_solver_type = DENSE_QR;
@@ -322,7 +320,7 @@
   problem_options.evaluation_callback = &cost_function;
   problem_options.cost_function_ownership = DO_NOT_TAKE_OWNERSHIP;
   Problem problem(problem_options);
-  problem.AddResidualBlock(&cost_function, NULL, parameters);
+  problem.AddResidualBlock(&cost_function, nullptr, parameters);
 
   Solver::Options options;
   options.linear_solver_type = DENSE_QR;
@@ -387,5 +385,4 @@
   WithLineSearchMinimizerImpl(ARMIJO, NONLINEAR_CONJUGATE_GRADIENT, QUADRATIC);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/evaluator.cc b/third_party/ceres/internal/ceres/evaluator.cc
index 5168741..64eb4c5 100644
--- a/third_party/ceres/internal/ceres/evaluator.cc
+++ b/third_party/ceres/internal/ceres/evaluator.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -30,6 +30,7 @@
 
 #include "ceres/evaluator.h"
 
+#include <memory>
 #include <vector>
 
 #include "ceres/block_evaluate_preparer.h"
@@ -40,48 +41,57 @@
 #include "ceres/dense_jacobian_writer.h"
 #include "ceres/dynamic_compressed_row_finalizer.h"
 #include "ceres/dynamic_compressed_row_jacobian_writer.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 #include "ceres/program_evaluator.h"
 #include "ceres/scratch_evaluate_preparer.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
-Evaluator::~Evaluator() {}
+Evaluator::~Evaluator() = default;
 
-Evaluator* Evaluator::Create(const Evaluator::Options& options,
-                             Program* program,
-                             std::string* error) {
-  CHECK(options.context != NULL);
+std::unique_ptr<Evaluator> Evaluator::Create(const Evaluator::Options& options,
+                                             Program* program,
+                                             std::string* error) {
+  CHECK(options.context != nullptr);
 
   switch (options.linear_solver_type) {
     case DENSE_QR:
     case DENSE_NORMAL_CHOLESKY:
-      return new ProgramEvaluator<ScratchEvaluatePreparer, DenseJacobianWriter>(
+      return std::make_unique<
+          ProgramEvaluator<ScratchEvaluatePreparer, DenseJacobianWriter>>(
           options, program);
     case DENSE_SCHUR:
     case SPARSE_SCHUR:
     case ITERATIVE_SCHUR:
-    case CGNR:
-      return new ProgramEvaluator<BlockEvaluatePreparer, BlockJacobianWriter>(
-          options, program);
-    case SPARSE_NORMAL_CHOLESKY:
-      if (options.dynamic_sparsity) {
-        return new ProgramEvaluator<ScratchEvaluatePreparer,
-                                    DynamicCompressedRowJacobianWriter,
-                                    DynamicCompressedRowJacobianFinalizer>(
+    case CGNR: {
+      if (options.sparse_linear_algebra_library_type == CUDA_SPARSE) {
+        return std::make_unique<ProgramEvaluator<ScratchEvaluatePreparer,
+                                                 CompressedRowJacobianWriter>>(
             options, program);
       } else {
-        return new ProgramEvaluator<BlockEvaluatePreparer, BlockJacobianWriter>(
+        return std::make_unique<
+            ProgramEvaluator<BlockEvaluatePreparer, BlockJacobianWriter>>(
+            options, program);
+      }
+    }
+    case SPARSE_NORMAL_CHOLESKY:
+      if (options.dynamic_sparsity) {
+        return std::make_unique<
+            ProgramEvaluator<ScratchEvaluatePreparer,
+                             DynamicCompressedRowJacobianWriter,
+                             DynamicCompressedRowJacobianFinalizer>>(options,
+                                                                     program);
+      } else {
+        return std::make_unique<
+            ProgramEvaluator<BlockEvaluatePreparer, BlockJacobianWriter>>(
             options, program);
       }
 
     default:
       *error = "Invalid Linear Solver Type. Unable to create evaluator.";
-      return NULL;
+      return nullptr;
   }
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/evaluator.h b/third_party/ceres/internal/ceres/evaluator.h
index 9cf4259..dcb3cf6 100644
--- a/third_party/ceres/internal/ceres/evaluator.h
+++ b/third_party/ceres/internal/ceres/evaluator.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -33,12 +33,14 @@
 #define CERES_INTERNAL_EVALUATOR_H_
 
 #include <map>
+#include <memory>
 #include <string>
 #include <vector>
 
 #include "ceres/context_impl.h"
 #include "ceres/execution_summary.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 #include "ceres/types.h"
 
 namespace ceres {
@@ -54,8 +56,8 @@
 // The Evaluator interface offers a way to interact with a least squares cost
 // function that is useful for an optimizer that wants to minimize the least
 // squares objective. This insulates the optimizer from issues like Jacobian
-// storage, parameterization, etc.
-class CERES_EXPORT_INTERNAL Evaluator {
+// storage, manifolds, etc.
+class CERES_NO_EXPORT Evaluator {
  public:
   virtual ~Evaluator();
 
@@ -63,14 +65,16 @@
     int num_threads = 1;
     int num_eliminate_blocks = -1;
     LinearSolverType linear_solver_type = DENSE_QR;
+    SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type =
+        NO_SPARSE;
     bool dynamic_sparsity = false;
     ContextImpl* context = nullptr;
     EvaluationCallback* evaluation_callback = nullptr;
   };
 
-  static Evaluator* Create(const Options& options,
-                           Program* program,
-                           std::string* error);
+  static std::unique_ptr<Evaluator> Create(const Options& options,
+                                           Program* program,
+                                           std::string* error);
 
   // Build and return a sparse matrix for storing and working with the Jacobian
   // of the objective function. The jacobian has dimensions
@@ -88,7 +92,7 @@
   // the jacobian for use with CHOLMOD, where as BlockOptimizationProblem
   // creates a BlockSparseMatrix representation of the jacobian for use in the
   // Schur complement based methods.
-  virtual SparseMatrix* CreateJacobian() const = 0;
+  virtual std::unique_ptr<SparseMatrix> CreateJacobian() const = 0;
 
   // Options struct to control Evaluator::Evaluate;
   struct EvaluateOptions {
@@ -102,10 +106,10 @@
 
   // Evaluate the cost function for the given state. Returns the cost,
   // residuals, and jacobian in the corresponding arguments. Both residuals and
-  // jacobian are optional; to avoid computing them, pass NULL.
+  // jacobian are optional; to avoid computing them, pass nullptr.
   //
-  // If non-NULL, the Jacobian must have a suitable sparsity pattern; only the
-  // values array of the jacobian is modified.
+  // If non-nullptr, the Jacobian must have a suitable sparsity pattern; only
+  // the values array of the jacobian is modified.
   //
   // state is an array of size NumParameters(), cost is a pointer to a single
   // double, and residuals is an array of doubles of size NumResiduals().
@@ -131,13 +135,13 @@
   // Make a change delta (of size NumEffectiveParameters()) to state (of size
   // NumParameters()) and store the result in state_plus_delta.
   //
-  // In the case that there are no parameterizations used, this is equivalent to
+  // In the case that there are no manifolds used, this is equivalent to
   //
   //   state_plus_delta[i] = state[i] + delta[i] ;
   //
-  // however, the mapping is more complicated in the case of parameterizations
+  // however, the mapping is more complicated in the case of manifolds
   // like quaternions. This is the same as the "Plus()" operation in
-  // local_parameterization.h, but operating over the entire state vector for a
+  // manifold.h, but operating over the entire state vector for a
   // problem.
   virtual bool Plus(const double* state,
                     const double* delta,
@@ -147,7 +151,7 @@
   virtual int NumParameters() const = 0;
 
   // This is the effective number of parameters that the optimizer may adjust.
-  // This applies when there are parameterizations on some of the parameters.
+  // This applies when there are manifolds on some of the parameters.
   virtual int NumEffectiveParameters() const = 0;
 
   // The number of residuals in the optimization problem.
@@ -158,11 +162,13 @@
   // life time issues. Further, these calls are not expected to be
   // frequent or performance sensitive.
   virtual std::map<std::string, CallStatistics> Statistics() const {
-    return std::map<std::string, CallStatistics>();
+    return {};
   }
 };
 
 }  // namespace internal
 }  // namespace ceres
 
+#include "ceres/internal/reenable_warnings.h"
+
 #endif  // CERES_INTERNAL_EVALUATOR_H_
diff --git a/third_party/ceres/internal/ceres/evaluator_test.cc b/third_party/ceres/internal/ceres/evaluator_test.cc
index 5ddb733..43e8872 100644
--- a/third_party/ceres/internal/ceres/evaluator_test.cc
+++ b/third_party/ceres/internal/ceres/evaluator_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -34,13 +34,15 @@
 #include "ceres/evaluator.h"
 
 #include <memory>
+#include <string>
+#include <vector>
 
 #include "ceres/casts.h"
 #include "ceres/cost_function.h"
 #include "ceres/crs_matrix.h"
 #include "ceres/evaluator_test_utils.h"
 #include "ceres/internal/eigen.h"
-#include "ceres/local_parameterization.h"
+#include "ceres/manifold.h"
 #include "ceres/problem_impl.h"
 #include "ceres/program.h"
 #include "ceres/sized_cost_function.h"
@@ -52,14 +54,11 @@
 namespace ceres {
 namespace internal {
 
-using std::string;
-using std::vector;
-
 // TODO(keir): Consider pushing this into a common test utils file.
 template <int kFactor, int kNumResiduals, int... Ns>
 class ParameterIgnoringCostFunction
     : public SizedCostFunction<kNumResiduals, Ns...> {
-  typedef SizedCostFunction<kNumResiduals, Ns...> Base;
+  using Base = SizedCostFunction<kNumResiduals, Ns...>;
 
  public:
   explicit ParameterIgnoringCostFunction(bool succeeds = true)
@@ -75,9 +74,9 @@
       for (int k = 0; k < Base::parameter_block_sizes().size(); ++k) {
         // The jacobians here are full sized, but they are transformed in the
         // evaluator into the "local" jacobian. In the tests, the "subset
-        // constant" parameterization is used, which should pick out columns
-        // from these jacobians. Put values in the jacobian that make this
-        // obvious; in particular, make the jacobians like this:
+        // constant" manifold is used, which should pick out columns from these
+        // jacobians. Put values in the jacobian that make this obvious; in
+        // particular, make the jacobians like this:
         //
         //   1 2 3 4 ...
         //   1 2 3 4 ...   .*  kFactor
@@ -116,13 +115,13 @@
 };
 
 struct EvaluatorTest : public ::testing::TestWithParam<EvaluatorTestOptions> {
-  Evaluator* CreateEvaluator(Program* program) {
+  std::unique_ptr<Evaluator> CreateEvaluator(Program* program) {
     // This program is straight from the ProblemImpl, and so has no index/offset
     // yet; compute it here as required by the evaluator implementations.
     program->SetParameterOffsetsAndIndex();
 
     if (VLOG_IS_ON(1)) {
-      string report;
+      std::string report;
       StringAppendF(&report,
                     "Creating evaluator with type: %d",
                     GetParam().linear_solver_type);
@@ -140,7 +139,7 @@
     options.num_eliminate_blocks = GetParam().num_eliminate_blocks;
     options.dynamic_sparsity = GetParam().dynamic_sparsity;
     options.context = problem.context();
-    string error;
+    std::string error;
     return Evaluator::Create(options, program, &error);
   }
 
@@ -151,8 +150,8 @@
                           const double* expected_residuals,
                           const double* expected_gradient,
                           const double* expected_jacobian) {
-    std::unique_ptr<Evaluator> evaluator(
-        CreateEvaluator(problem->mutable_program()));
+    std::unique_ptr<Evaluator> evaluator =
+        CreateEvaluator(problem->mutable_program());
     int num_residuals = expected_num_rows;
     int num_parameters = expected_num_cols;
 
@@ -171,7 +170,7 @@
     ASSERT_EQ(expected_num_rows, jacobian->num_rows());
     ASSERT_EQ(expected_num_cols, jacobian->num_cols());
 
-    vector<double> state(evaluator->NumParameters());
+    std::vector<double> state(evaluator->NumParameters());
 
     // clang-format off
     ASSERT_TRUE(evaluator->Evaluate(
@@ -394,19 +393,19 @@
   CheckAllEvaluationCombinations(expected);
 }
 
-TEST_P(EvaluatorTest, MultipleResidualsWithLocalParameterizations) {
+TEST_P(EvaluatorTest, MultipleResidualsWithManifolds) {
   // Add the parameters in explicit order to force the ordering in the program.
   problem.AddParameterBlock(x, 2);
 
   // Fix y's first dimension.
-  vector<int> y_fixed;
+  std::vector<int> y_fixed;
   y_fixed.push_back(0);
-  problem.AddParameterBlock(y, 3, new SubsetParameterization(3, y_fixed));
+  problem.AddParameterBlock(y, 3, new SubsetManifold(3, y_fixed));
 
   // Fix z's second dimension.
-  vector<int> z_fixed;
+  std::vector<int> z_fixed;
   z_fixed.push_back(1);
-  problem.AddParameterBlock(z, 4, new SubsetParameterization(4, z_fixed));
+  problem.AddParameterBlock(z, 4, new SubsetManifold(4, z_fixed));
 
   // f(x, y) in R^2
   problem.AddResidualBlock(
@@ -486,7 +485,7 @@
   // Normally, the preprocessing of the program that happens in solver_impl
   // takes care of this, but we don't want to invoke the solver here.
   Program reduced_program;
-  vector<ParameterBlock*>* parameter_blocks =
+  std::vector<ParameterBlock*>* parameter_blocks =
       problem.mutable_program()->mutable_parameter_blocks();
 
   // "z" is the last parameter; save it for later and pop it off temporarily.
@@ -545,8 +544,8 @@
   // The values are ignored.
   double state[9];
 
-  std::unique_ptr<Evaluator> evaluator(
-      CreateEvaluator(problem.mutable_program()));
+  std::unique_ptr<Evaluator> evaluator =
+      CreateEvaluator(problem.mutable_program());
   std::unique_ptr<SparseMatrix> jacobian(evaluator->CreateJacobian());
   double cost;
   EXPECT_FALSE(evaluator->Evaluate(state, &cost, nullptr, nullptr, nullptr));
@@ -620,7 +619,7 @@
   options.linear_solver_type = DENSE_QR;
   options.num_eliminate_blocks = 0;
   options.context = problem.context();
-  string error;
+  std::string error;
   std::unique_ptr<Evaluator> evaluator(
       Evaluator::Create(options, program, &error));
   std::unique_ptr<SparseMatrix> jacobian(evaluator->CreateJacobian());
@@ -677,5 +676,51 @@
   }
 }
 
+class HugeCostFunction : public SizedCostFunction<46341, 46345> {
+  bool Evaluate(double const* const* parameters,
+                double* residuals,
+                double** jacobians) const override {
+    return true;
+  }
+};
+
+TEST(Evaluator, LargeProblemDoesNotCauseCrashBlockJacobianWriter) {
+  ProblemImpl problem;
+  std::vector<double> x(46345);
+
+  problem.AddResidualBlock(new HugeCostFunction, nullptr, x.data());
+  Evaluator::Options options;
+  options.linear_solver_type = SPARSE_NORMAL_CHOLESKY;
+  options.context = problem.context();
+  options.num_eliminate_blocks = 0;
+  options.dynamic_sparsity = false;
+  std::string error;
+  auto program = problem.mutable_program();
+  program->SetParameterOffsetsAndIndex();
+  auto evaluator = Evaluator::Create(options, program, &error);
+  auto jacobian = evaluator->CreateJacobian();
+  EXPECT_EQ(jacobian, nullptr);
+}
+
+TEST(Evaluator, LargeProblemDoesNotCauseCrashCompressedRowJacobianWriter) {
+  ProblemImpl problem;
+  std::vector<double> x(46345);
+
+  problem.AddResidualBlock(new HugeCostFunction, nullptr, x.data());
+  Evaluator::Options options;
+  // CGNR on CUDA_SPARSE is the only combination that triggers a
+  // CompressedRowJacobianWriter.
+  options.linear_solver_type = CGNR;
+  options.sparse_linear_algebra_library_type = CUDA_SPARSE;
+  options.context = problem.context();
+  options.num_eliminate_blocks = 0;
+  std::string error;
+  auto program = problem.mutable_program();
+  program->SetParameterOffsetsAndIndex();
+  auto evaluator = Evaluator::Create(options, program, &error);
+  auto jacobian = evaluator->CreateJacobian();
+  EXPECT_EQ(jacobian, nullptr);
+}
+
 }  // namespace internal
 }  // namespace ceres
diff --git a/third_party/ceres/internal/ceres/evaluator_test_utils.cc b/third_party/ceres/internal/ceres/evaluator_test_utils.cc
index 25801db..904635b 100644
--- a/third_party/ceres/internal/ceres/evaluator_test_utils.cc
+++ b/third_party/ceres/internal/ceres/evaluator_test_utils.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -34,8 +34,7 @@
 #include "ceres/internal/eigen.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 void CompareEvaluations(int expected_num_rows,
                         int expected_num_cols,
@@ -49,7 +48,7 @@
                         const double* actual_jacobian) {
   EXPECT_EQ(expected_cost, actual_cost);
 
-  if (expected_residuals != NULL) {
+  if (expected_residuals != nullptr) {
     ConstVectorRef expected_residuals_vector(expected_residuals,
                                              expected_num_rows);
     ConstVectorRef actual_residuals_vector(actual_residuals, expected_num_rows);
@@ -61,7 +60,7 @@
         << expected_residuals_vector;
   }
 
-  if (expected_gradient != NULL) {
+  if (expected_gradient != nullptr) {
     ConstVectorRef expected_gradient_vector(expected_gradient,
                                             expected_num_cols);
     ConstVectorRef actual_gradient_vector(actual_gradient, expected_num_cols);
@@ -74,7 +73,7 @@
         << expected_gradient_vector.transpose();
   }
 
-  if (expected_jacobian != NULL) {
+  if (expected_jacobian != nullptr) {
     ConstMatrixRef expected_jacobian_matrix(
         expected_jacobian, expected_num_rows, expected_num_cols);
     ConstMatrixRef actual_jacobian_matrix(
@@ -88,5 +87,4 @@
   }
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/evaluator_test_utils.h b/third_party/ceres/internal/ceres/evaluator_test_utils.h
index d47b6fa..e98dfb6 100644
--- a/third_party/ceres/internal/ceres/evaluator_test_utils.h
+++ b/third_party/ceres/internal/ceres/evaluator_test_utils.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -31,13 +31,12 @@
 //
 // Test utils used for evaluation testing.
 
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // Fixed sized struct for storing an evaluation.
-struct ExpectedEvaluation {
+struct CERES_NO_EXPORT ExpectedEvaluation {
   int num_rows;
   int num_cols;
   double cost;
@@ -47,16 +46,15 @@
 };
 
 // Compare two evaluations.
-CERES_EXPORT_INTERNAL void CompareEvaluations(int expected_num_rows,
-                                              int expected_num_cols,
-                                              double expected_cost,
-                                              const double* expected_residuals,
-                                              const double* expected_gradient,
-                                              const double* expected_jacobian,
-                                              const double actual_cost,
-                                              const double* actual_residuals,
-                                              const double* actual_gradient,
-                                              const double* actual_jacobian);
+CERES_NO_EXPORT void CompareEvaluations(int expected_num_rows,
+                                        int expected_num_cols,
+                                        double expected_cost,
+                                        const double* expected_residuals,
+                                        const double* expected_gradient,
+                                        const double* expected_jacobian,
+                                        const double actual_cost,
+                                        const double* actual_residuals,
+                                        const double* actual_gradient,
+                                        const double* actual_jacobian);
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/execution_summary.h b/third_party/ceres/internal/ceres/execution_summary.h
index 17fd882..accc5e4 100644
--- a/third_party/ceres/internal/ceres/execution_summary.h
+++ b/third_party/ceres/internal/ceres/execution_summary.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -34,17 +34,17 @@
 #include <map>
 #include <mutex>
 #include <string>
+#include <utility>
 
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 #include "ceres/wall_time.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 struct CallStatistics {
-  CallStatistics() : time(0.), calls(0) {}
-  double time;
-  int calls;
+  CallStatistics() = default;
+  double time{0.};
+  int calls{0};
 };
 
 // Struct used by various objects to report statistics about their
@@ -69,8 +69,10 @@
 
 class ScopedExecutionTimer {
  public:
-  ScopedExecutionTimer(const std::string& name, ExecutionSummary* summary)
-      : start_time_(WallTimeInSeconds()), name_(name), summary_(summary) {}
+  ScopedExecutionTimer(std::string name, ExecutionSummary* summary)
+      : start_time_(WallTimeInSeconds()),
+        name_(std::move(name)),
+        summary_(summary) {}
 
   ~ScopedExecutionTimer() {
     summary_->IncrementTimeBy(name_, WallTimeInSeconds() - start_time_);
@@ -82,7 +84,6 @@
   ExecutionSummary* summary_;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_INTERNAL_EXECUTION_SUMMARY_H_
diff --git a/third_party/ceres/internal/ceres/fake_bundle_adjustment_jacobian.cc b/third_party/ceres/internal/ceres/fake_bundle_adjustment_jacobian.cc
new file mode 100644
index 0000000..22f3405
--- /dev/null
+++ b/third_party/ceres/internal/ceres/fake_bundle_adjustment_jacobian.cc
@@ -0,0 +1,99 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Authors: joydeepb@cs.utexas.edu (Joydeep Biswas)
+
+#include "ceres/fake_bundle_adjustment_jacobian.h"
+
+#include <memory>
+#include <random>
+#include <string>
+#include <utility>
+
+#include "Eigen/Dense"
+#include "ceres/block_sparse_matrix.h"
+#include "ceres/internal/eigen.h"
+
+namespace ceres::internal {
+
+std::unique_ptr<BlockSparseMatrix> CreateFakeBundleAdjustmentJacobian(
+    int num_cameras,
+    int num_points,
+    int camera_size,
+    int point_size,
+    double visibility,
+    std::mt19937& prng) {
+  constexpr int kResidualSize = 2;
+
+  CompressedRowBlockStructure* bs = new CompressedRowBlockStructure;
+  int c = 0;
+  // Add column blocks for each point
+  for (int i = 0; i < num_points; ++i) {
+    bs->cols.push_back(Block(point_size, c));
+    c += point_size;
+  }
+
+  // Add column blocks for each camera.
+  for (int i = 0; i < num_cameras; ++i) {
+    bs->cols.push_back(Block(camera_size, c));
+    c += camera_size;
+  }
+
+  std::bernoulli_distribution visibility_distribution(visibility);
+  int row_pos = 0;
+  int cell_pos = 0;
+  for (int i = 0; i < num_points; ++i) {
+    for (int j = 0; j < num_cameras; ++j) {
+      if (!visibility_distribution(prng)) {
+        continue;
+      }
+      bs->rows.emplace_back();
+      auto& row = bs->rows.back();
+      row.block.position = row_pos;
+      row.block.size = kResidualSize;
+      auto& cells = row.cells;
+      cells.resize(2);
+
+      cells[0].block_id = i;
+      cells[0].position = cell_pos;
+      cell_pos += kResidualSize * point_size;
+
+      cells[1].block_id = num_points + j;
+      cells[1].position = cell_pos;
+      cell_pos += kResidualSize * camera_size;
+
+      row_pos += kResidualSize;
+    }
+  }
+
+  auto jacobian = std::make_unique<BlockSparseMatrix>(bs);
+  VectorRef(jacobian->mutable_values(), jacobian->num_nonzeros()).setRandom();
+  return jacobian;
+}
+
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/fake_bundle_adjustment_jacobian.h b/third_party/ceres/internal/ceres/fake_bundle_adjustment_jacobian.h
new file mode 100644
index 0000000..0448dbf
--- /dev/null
+++ b/third_party/ceres/internal/ceres/fake_bundle_adjustment_jacobian.h
@@ -0,0 +1,52 @@
+
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#ifndef CERES_INTERNAL_FAKE_BUNDLE_ADJUSTMENT_JACOBIAN
+#define CERES_INTERNAL_FAKE_BUNDLE_ADJUSTMENT_JACOBIAN
+
+#include <memory>
+#include <random>
+
+#include "ceres/block_sparse_matrix.h"
+#include "ceres/partitioned_matrix_view.h"
+
+namespace ceres::internal {
+std::unique_ptr<BlockSparseMatrix> CreateFakeBundleAdjustmentJacobian(
+    int num_cameras,
+    int num_points,
+    int camera_size,
+    int point_size,
+    double visibility,
+    std::mt19937& prng);
+
+}  // namespace ceres::internal
+
+#endif  // CERES_INTERNAL_FAKE_BUNDLE_ADJUSTMENT_JACOBIAN
diff --git a/third_party/ceres/internal/ceres/file.cc b/third_party/ceres/internal/ceres/file.cc
index 94f2135..60d35fa 100644
--- a/third_party/ceres/internal/ceres/file.cc
+++ b/third_party/ceres/internal/ceres/file.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -33,15 +33,14 @@
 #include "ceres/file.h"
 
 #include <cstdio>
+#include <string>
 
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
-using std::string;
-
-void WriteStringToFileOrDie(const string& data, const string& filename) {
+void WriteStringToFileOrDie(const std::string& data,
+                            const std::string& filename) {
   FILE* file_descriptor = fopen(filename.c_str(), "wb");
   if (!file_descriptor) {
     LOG(FATAL) << "Couldn't write to file: " << filename;
@@ -50,7 +49,7 @@
   fclose(file_descriptor);
 }
 
-void ReadFileToStringOrDie(const string& filename, string* data) {
+void ReadFileToStringOrDie(const std::string& filename, std::string* data) {
   FILE* file_descriptor = fopen(filename.c_str(), "r");
 
   if (!file_descriptor) {
@@ -59,12 +58,12 @@
 
   // Resize the input buffer appropriately.
   fseek(file_descriptor, 0L, SEEK_END);
-  int num_bytes = ftell(file_descriptor);
+  int64_t num_bytes = ftell(file_descriptor);
   data->resize(num_bytes);
 
   // Read the data.
   fseek(file_descriptor, 0L, SEEK_SET);
-  int num_read =
+  int64_t num_read =
       fread(&((*data)[0]), sizeof((*data)[0]), num_bytes, file_descriptor);
   if (num_read != num_bytes) {
     LOG(FATAL) << "Couldn't read all of " << filename
@@ -74,7 +73,7 @@
   fclose(file_descriptor);
 }
 
-string JoinPath(const string& dirname, const string& basename) {
+std::string JoinPath(const std::string& dirname, const std::string& basename) {
 #ifdef _WIN32
   static const char separator = '\\';
 #else
@@ -86,9 +85,8 @@
   } else if (dirname[dirname.size() - 1] == separator) {
     return dirname + basename;
   } else {
-    return dirname + string(&separator, 1) + basename;
+    return dirname + std::string(&separator, 1) + basename;
   }
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/file.h b/third_party/ceres/internal/ceres/file.h
index c0015df..b21f1ca 100644
--- a/third_party/ceres/internal/ceres/file.h
+++ b/third_party/ceres/internal/ceres/file.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,21 +35,24 @@
 
 #include <string>
 
-#include "ceres/internal/port.h"
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
+CERES_NO_EXPORT
 void WriteStringToFileOrDie(const std::string& data,
                             const std::string& filename);
+CERES_NO_EXPORT
 void ReadFileToStringOrDie(const std::string& filename, std::string* data);
 
 // Join two path components, adding a slash if necessary.  If basename is an
 // absolute path then JoinPath ignores dirname and simply returns basename.
-CERES_EXPORT_INTERNAL std::string JoinPath(const std::string& dirname,
-                                           const std::string& basename);
+CERES_NO_EXPORT
+std::string JoinPath(const std::string& dirname, const std::string& basename);
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_FILE_H_
diff --git a/third_party/ceres/internal/ceres/first_order_function.cc b/third_party/ceres/internal/ceres/first_order_function.cc
new file mode 100644
index 0000000..267b8ef
--- /dev/null
+++ b/third_party/ceres/internal/ceres/first_order_function.cc
@@ -0,0 +1,37 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/first_order_function.h"
+
+namespace ceres {
+
+FirstOrderFunction::~FirstOrderFunction() = default;
+
+}  // namespace ceres
diff --git a/third_party/ceres/internal/ceres/fixed_array_test.cc b/third_party/ceres/internal/ceres/fixed_array_test.cc
index d418786..66b3fbf 100644
--- a/third_party/ceres/internal/ceres/fixed_array_test.cc
+++ b/third_party/ceres/internal/ceres/fixed_array_test.cc
@@ -14,8 +14,7 @@
 
 #include "ceres/internal/fixed_array.h"
 
-#include <stdio.h>
-
+#include <cstdio>
 #include <cstring>
 #include <list>
 #include <memory>
@@ -54,7 +53,7 @@
 
 class ConstructionTester {
  public:
-  ConstructionTester() : self_ptr_(this), value_(0) { constructions++; }
+  ConstructionTester() : self_ptr_(this) { constructions++; }
   ~ConstructionTester() {
     assert(self_ptr_ == this);
     self_ptr_ = nullptr;
@@ -75,7 +74,7 @@
   // self_ptr_ should always point to 'this' -- that's how we can be sure the
   // constructor has been called.
   ConstructionTester* self_ptr_;
-  int value_;
+  int value_{0};
 };
 
 int ConstructionTester::constructions = 0;
@@ -117,7 +116,7 @@
 TEST(FixedArrayTest, MoveCtor) {
   ceres::internal::FixedArray<std::unique_ptr<int>, 10> on_stack(5);
   for (int i = 0; i < 5; ++i) {
-    on_stack[i] = std::unique_ptr<int>(new int(i));
+    on_stack[i] = std::make_unique<int>(i);
   }
 
   ceres::internal::FixedArray<std::unique_ptr<int>, 10> stack_copy =
@@ -127,7 +126,7 @@
 
   ceres::internal::FixedArray<std::unique_ptr<int>, 10> allocated(15);
   for (int i = 0; i < 15; ++i) {
-    allocated[i] = std::unique_ptr<int>(new int(i));
+    allocated[i] = std::make_unique<int>(i);
   }
 
   ceres::internal::FixedArray<std::unique_ptr<int>, 10> alloced_copy =
@@ -467,7 +466,7 @@
 //     will always overflow destination buffer [-Werror]
 TEST(FixedArrayTest, AvoidParanoidDiagnostics) {
   ceres::internal::FixedArray<char, 32> buf(32);
-  sprintf(buf.data(), "foo");  // NOLINT(runtime/printf)
+  snprintf(buf.data(), 32, "foo");
 }
 
 TEST(FixedArrayTest, TooBigInlinedSpace) {
@@ -500,8 +499,6 @@
 
 // PickyDelete EXPECTs its class-scope deallocation funcs are unused.
 struct PickyDelete {
-  PickyDelete() {}
-  ~PickyDelete() {}
   void operator delete(void* p) {
     EXPECT_TRUE(false) << __FUNCTION__;
     ::operator delete(p);
@@ -655,12 +652,10 @@
 class CountingAllocator : public std::allocator<T> {
  public:
   using Alloc = std::allocator<T>;
-  using pointer = typename Alloc::pointer;
   using size_type = typename Alloc::size_type;
 
-  CountingAllocator() : bytes_used_(nullptr), instance_count_(nullptr) {}
-  explicit CountingAllocator(int64_t* b)
-      : bytes_used_(b), instance_count_(nullptr) {}
+  CountingAllocator() = default;
+  explicit CountingAllocator(int64_t* b) : bytes_used_(b) {}
   CountingAllocator(int64_t* b, int64_t* a)
       : bytes_used_(b), instance_count_(a) {}
 
@@ -670,41 +665,20 @@
         bytes_used_(x.bytes_used_),
         instance_count_(x.instance_count_) {}
 
-  pointer allocate(size_type n, const void* const hint = nullptr) {
+  T* allocate(size_type n) {
     assert(bytes_used_ != nullptr);
     *bytes_used_ += n * sizeof(T);
-    return Alloc::allocate(n, hint);
+    return Alloc::allocate(n);
   }
 
-  void deallocate(pointer p, size_type n) {
+  void deallocate(T* p, size_type n) {
     Alloc::deallocate(p, n);
     assert(bytes_used_ != nullptr);
     *bytes_used_ -= n * sizeof(T);
   }
 
-  template <typename... Args>
-  void construct(pointer p, Args&&... args) {
-    Alloc::construct(p, std::forward<Args>(args)...);
-    if (instance_count_) {
-      *instance_count_ += 1;
-    }
-  }
-
-  void destroy(pointer p) {
-    Alloc::destroy(p);
-    if (instance_count_) {
-      *instance_count_ -= 1;
-    }
-  }
-
-  template <typename U>
-  class rebind {
-   public:
-    using other = CountingAllocator<U>;
-  };
-
-  int64_t* bytes_used_;
-  int64_t* instance_count_;
+  int64_t* bytes_used_{nullptr};
+  int64_t* instance_count_{nullptr};
 };
 
 TEST(AllocatorSupportTest, CountInlineAllocations) {
diff --git a/third_party/ceres/internal/ceres/float_cxsparse.cc b/third_party/ceres/internal/ceres/float_cxsparse.cc
deleted file mode 100644
index 6c68830..0000000
--- a/third_party/ceres/internal/ceres/float_cxsparse.cc
+++ /dev/null
@@ -1,47 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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 Google Inc. 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.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/float_cxsparse.h"
-
-#if !defined(CERES_NO_CXSPARSE)
-
-namespace ceres {
-namespace internal {
-
-std::unique_ptr<SparseCholesky> FloatCXSparseCholesky::Create(
-    OrderingType ordering_type) {
-  LOG(FATAL) << "FloatCXSparseCholesky is not available.";
-  return std::unique_ptr<SparseCholesky>();
-}
-
-}  // namespace internal
-}  // namespace ceres
-
-#endif  // !defined(CERES_NO_CXSPARSE)
diff --git a/third_party/ceres/internal/ceres/float_cxsparse.h b/third_party/ceres/internal/ceres/float_cxsparse.h
deleted file mode 100644
index 9a274c2..0000000
--- a/third_party/ceres/internal/ceres/float_cxsparse.h
+++ /dev/null
@@ -1,58 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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 Google Inc. 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.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_INTERNAL_FLOAT_CXSPARSE_H_
-#define CERES_INTERNAL_FLOAT_CXSPARSE_H_
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#if !defined(CERES_NO_CXSPARSE)
-
-#include <memory>
-
-#include "ceres/sparse_cholesky.h"
-
-namespace ceres {
-namespace internal {
-
-// Fake implementation of a single precision Sparse Cholesky using
-// CXSparse.
-class FloatCXSparseCholesky : public SparseCholesky {
- public:
-  static std::unique_ptr<SparseCholesky> Create(OrderingType ordering_type);
-};
-
-}  // namespace internal
-}  // namespace ceres
-
-#endif  // !defined(CERES_NO_CXSPARSE)
-
-#endif  // CERES_INTERNAL_FLOAT_CXSPARSE_H_
diff --git a/third_party/ceres/internal/ceres/float_suitesparse.cc b/third_party/ceres/internal/ceres/float_suitesparse.cc
index 0360457..6016bad 100644
--- a/third_party/ceres/internal/ceres/float_suitesparse.cc
+++ b/third_party/ceres/internal/ceres/float_suitesparse.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -30,18 +30,18 @@
 
 #include "ceres/float_suitesparse.h"
 
+#include <memory>
+
 #if !defined(CERES_NO_SUITESPARSE)
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 std::unique_ptr<SparseCholesky> FloatSuiteSparseCholesky::Create(
     OrderingType ordering_type) {
   LOG(FATAL) << "FloatSuiteSparseCholesky is not available.";
-  return std::unique_ptr<SparseCholesky>();
+  return {};
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // !defined(CERES_NO_SUITESPARSE)
diff --git a/third_party/ceres/internal/ceres/float_suitesparse.h b/third_party/ceres/internal/ceres/float_suitesparse.h
index c436da4..b9d298e 100644
--- a/third_party/ceres/internal/ceres/float_suitesparse.h
+++ b/third_party/ceres/internal/ceres/float_suitesparse.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -33,27 +33,26 @@
 
 // This include must come before any #ifndef check on Ceres compile options.
 // clang-format off
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 // clang-format on
 
 #include <memory>
 
+#include "ceres/internal/export.h"
 #include "ceres/sparse_cholesky.h"
 
 #if !defined(CERES_NO_SUITESPARSE)
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // Fake implementation of a single precision Sparse Cholesky using
 // SuiteSparse.
-class FloatSuiteSparseCholesky : public SparseCholesky {
+class CERES_NO_EXPORT FloatSuiteSparseCholesky : public SparseCholesky {
  public:
   static std::unique_ptr<SparseCholesky> Create(OrderingType ordering_type);
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // !defined(CERES_NO_SUITESPARSE)
 
diff --git a/third_party/ceres/internal/ceres/function_sample.cc b/third_party/ceres/internal/ceres/function_sample.cc
index 3e0ae60..bb4bcff 100644
--- a/third_party/ceres/internal/ceres/function_sample.cc
+++ b/third_party/ceres/internal/ceres/function_sample.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -32,8 +32,7 @@
 
 #include "ceres/stringprintf.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 FunctionSample::FunctionSample()
     : x(0.0),
@@ -75,5 +74,4 @@
       gradient_is_valid);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/function_sample.h b/third_party/ceres/internal/ceres/function_sample.h
index 3bcea1b..0582769 100644
--- a/third_party/ceres/internal/ceres/function_sample.h
+++ b/third_party/ceres/internal/ceres/function_sample.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -33,11 +33,11 @@
 
 #include <string>
 
+#include "ceres/internal/disable_warnings.h"
 #include "ceres/internal/eigen.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // FunctionSample is used by the line search routines to store and
 // communicate the value and (optionally) the gradient of the function
@@ -47,7 +47,7 @@
 // line/direction. FunctionSample contains the information in two
 // ways. Information in the ambient space and information along the
 // direction of search.
-struct CERES_EXPORT_INTERNAL FunctionSample {
+struct CERES_NO_EXPORT FunctionSample {
   FunctionSample();
   FunctionSample(double x, double value);
   FunctionSample(double x, double value, double gradient);
@@ -82,12 +82,13 @@
   //
   // where d is the search direction.
   double gradient;
-  // True if the evaluation of the gradient was sucessful and the
+  // True if the evaluation of the gradient was successful and the
   // value is a finite number.
   bool gradient_is_valid;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_FUNCTION_SAMPLE_H_
diff --git a/third_party/ceres/internal/ceres/generate_bundle_adjustment_tests.py b/third_party/ceres/internal/ceres/generate_bundle_adjustment_tests.py
index 7b0caa3..ac83bc3 100644
--- a/third_party/ceres/internal/ceres/generate_bundle_adjustment_tests.py
+++ b/third_party/ceres/internal/ceres/generate_bundle_adjustment_tests.py
@@ -1,5 +1,5 @@
 # Ceres Solver - A fast non-linear least squares minimizer
-# Copyright 2018 Google Inc. All rights reserved.
+# Copyright 2023 Google Inc. All rights reserved.
 # http://ceres-solver.org/
 #
 # Redistribution and use in source and binary forms, with or without
@@ -41,27 +41,34 @@
 MULTI_THREADED = "4"
 THREAD_CONFIGS = [SINGLE_THREADED, MULTI_THREADED]
 
-SOLVER_CONFIGS = [
-  # Linear solver            Sparse backend      Preconditioner
-  ('DENSE_SCHUR',            'NO_SPARSE',        'IDENTITY'),
-  ('ITERATIVE_SCHUR',        'NO_SPARSE',        'JACOBI'),
-  ('ITERATIVE_SCHUR',        'NO_SPARSE',        'SCHUR_JACOBI'),
-  ('ITERATIVE_SCHUR',        'SUITE_SPARSE',     'CLUSTER_JACOBI'),
-  ('ITERATIVE_SCHUR',        'EIGEN_SPARSE',     'CLUSTER_JACOBI'),
-  ('ITERATIVE_SCHUR',        'CX_SPARSE',        'CLUSTER_JACOBI'),
-  ('ITERATIVE_SCHUR',        'ACCELERATE_SPARSE','CLUSTER_JACOBI'),
-  ('ITERATIVE_SCHUR',        'SUITE_SPARSE',     'CLUSTER_TRIDIAGONAL'),
-  ('ITERATIVE_SCHUR',        'EIGEN_SPARSE',     'CLUSTER_TRIDIAGONAL'),
-  ('ITERATIVE_SCHUR',        'CX_SPARSE',        'CLUSTER_TRIDIAGONAL'),
-  ('ITERATIVE_SCHUR',        'ACCELERATE_SPARSE','CLUSTER_TRIDIAGONAL'),
-  ('SPARSE_NORMAL_CHOLESKY', 'SUITE_SPARSE',     'IDENTITY'),
-  ('SPARSE_NORMAL_CHOLESKY', 'EIGEN_SPARSE',     'IDENTITY'),
-  ('SPARSE_NORMAL_CHOLESKY', 'CX_SPARSE',        'IDENTITY'),
-  ('SPARSE_NORMAL_CHOLESKY', 'ACCELERATE_SPARSE','IDENTITY'),
-  ('SPARSE_SCHUR',           'SUITE_SPARSE',     'IDENTITY'),
-  ('SPARSE_SCHUR',           'EIGEN_SPARSE',     'IDENTITY'),
-  ('SPARSE_SCHUR',           'CX_SPARSE',        'IDENTITY'),
-  ('SPARSE_SCHUR',           'ACCELERATE_SPARSE','IDENTITY'),
+DENSE_SOLVER_CONFIGS = [
+    # Linear solver  Dense backend
+    ('DENSE_SCHUR',  'EIGEN'),
+    ('DENSE_SCHUR',  'LAPACK'),
+    ('DENSE_SCHUR',  'CUDA'),
+]
+
+SPARSE_SOLVER_CONFIGS = [
+    # Linear solver            Sparse backend
+    ('SPARSE_NORMAL_CHOLESKY', 'SUITE_SPARSE'),
+    ('SPARSE_NORMAL_CHOLESKY', 'EIGEN_SPARSE'),
+    ('SPARSE_NORMAL_CHOLESKY', 'ACCELERATE_SPARSE'),
+    ('SPARSE_SCHUR',           'SUITE_SPARSE'),
+    ('SPARSE_SCHUR',           'EIGEN_SPARSE'),
+    ('SPARSE_SCHUR',           'ACCELERATE_SPARSE'),
+]
+
+ITERATIVE_SOLVER_CONFIGS = [
+    # Linear solver            Sparse backend      Preconditioner
+    ('ITERATIVE_SCHUR',        'NO_SPARSE',        'JACOBI'),
+    ('ITERATIVE_SCHUR',        'NO_SPARSE',        'SCHUR_JACOBI'),
+    ('ITERATIVE_SCHUR',        'NO_SPARSE',        'SCHUR_POWER_SERIES_EXPANSION'),
+    ('ITERATIVE_SCHUR',        'SUITE_SPARSE',     'CLUSTER_JACOBI'),
+    ('ITERATIVE_SCHUR',        'EIGEN_SPARSE',     'CLUSTER_JACOBI'),
+    ('ITERATIVE_SCHUR',        'ACCELERATE_SPARSE','CLUSTER_JACOBI'),
+    ('ITERATIVE_SCHUR',        'SUITE_SPARSE',     'CLUSTER_TRIDIAGONAL'),
+    ('ITERATIVE_SCHUR',        'EIGEN_SPARSE',     'CLUSTER_TRIDIAGONAL'),
+    ('ITERATIVE_SCHUR',        'ACCELERATE_SPARSE','CLUSTER_TRIDIAGONAL'),
 ]
 
 FILENAME_SHORTENING_MAP = dict(
@@ -69,23 +76,26 @@
   ITERATIVE_SCHUR='iterschur',
   SPARSE_NORMAL_CHOLESKY='sparsecholesky',
   SPARSE_SCHUR='sparseschur',
+  EIGEN='eigen',
+  LAPACK='lapack',
+  CUDA='cuda',
   NO_SPARSE='',  # Omit sparse reference entirely for dense tests.
   SUITE_SPARSE='suitesparse',
   EIGEN_SPARSE='eigensparse',
-  CX_SPARSE='cxsparse',
   ACCELERATE_SPARSE='acceleratesparse',
   IDENTITY='identity',
   JACOBI='jacobi',
   SCHUR_JACOBI='schurjacobi',
   CLUSTER_JACOBI='clustjacobi',
   CLUSTER_TRIDIAGONAL='clusttri',
+  SCHUR_POWER_SERIES_EXPANSION='spse',
   kAutomaticOrdering='auto',
   kUserOrdering='user',
 )
 
 COPYRIGHT_HEADER = (
 """// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -123,28 +133,30 @@
 
 BUNDLE_ADJUSTMENT_TEST_TEMPLATE = (COPYRIGHT_HEADER + """
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 %(preprocessor_conditions_begin)s
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        %(test_class_name)s) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = %(num_threads)s;
   options->linear_solver_type = %(linear_solver)s;
+  options->dense_linear_algebra_library_type = %(dense_backend)s;
   options->sparse_linear_algebra_library_type = %(sparse_backend)s;
   options->preconditioner_type = %(preconditioner)s;
   if (%(ordering)s) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 %(preprocessor_conditions_end)s""")
 
 def camelcasify(token):
@@ -153,6 +165,7 @@
 
 
 def generate_bundle_test(linear_solver,
+                         dense_backend,
                          sparse_backend,
                          preconditioner,
                          ordering,
@@ -164,6 +177,10 @@
   if linear_solver != 'ITERATIVE_SCHUR':
     preconditioner_tag = ''
 
+  dense_backend_tag = dense_backend
+  if linear_solver != 'DENSE_SCHUR':
+    dense_backend_tag=''
+
   # Omit references to the sparse backend when one is not in use.
   sparse_backend_tag = sparse_backend
   if sparse_backend == 'NO_SPARSE':
@@ -172,6 +189,7 @@
   # Use a double underscore; otherwise the names are harder to understand.
   test_class_name = '_'.join(filter(lambda x: x, [
       camelcasify(linear_solver),
+      camelcasify(dense_backend_tag),
       camelcasify(sparse_backend_tag),
       camelcasify(preconditioner_tag),
       ordering[1:],  # Strip 'k'
@@ -180,6 +198,7 @@
   # Initial template parameters (augmented more below).
   template_parameters = dict(
           linear_solver=linear_solver,
+          dense_backend=dense_backend,
           sparse_backend=sparse_backend,
           preconditioner=preconditioner,
           ordering=ordering,
@@ -192,9 +211,6 @@
   if sparse_backend == 'SUITE_SPARSE':
     preprocessor_conditions_begin.append('#ifndef CERES_NO_SUITESPARSE')
     preprocessor_conditions_end.insert(0, '#endif  // CERES_NO_SUITESPARSE')
-  elif sparse_backend == 'CX_SPARSE':
-    preprocessor_conditions_begin.append('#ifndef CERES_NO_CXSPARSE')
-    preprocessor_conditions_end.insert(0, '#endif  // CERES_NO_CXSPARSE')
   elif sparse_backend == 'ACCELERATE_SPARSE':
     preprocessor_conditions_begin.append('#ifndef CERES_NO_ACCELERATE_SPARSE')
     preprocessor_conditions_end.insert(0, '#endif  // CERES_NO_ACCELERATE_SPARSE')
@@ -202,10 +218,12 @@
     preprocessor_conditions_begin.append('#ifdef CERES_USE_EIGEN_SPARSE')
     preprocessor_conditions_end.insert(0, '#endif  // CERES_USE_EIGEN_SPARSE')
 
-  # Accumulate appropriate #ifdef/#ifndefs for threading conditions.
-  if thread_config == MULTI_THREADED:
-    preprocessor_conditions_begin.append('#ifndef CERES_NO_THREADS')
-    preprocessor_conditions_end.insert(0, '#endif  // CERES_NO_THREADS')
+  if dense_backend == "LAPACK":
+    preprocessor_conditions_begin.append('#ifndef CERES_NO_LAPACK')
+    preprocessor_conditions_end.insert(0, '#endif  // CERES_NO_LAPACK')
+  elif dense_backend == "CUDA":
+    preprocessor_conditions_begin.append('#ifndef CERES_NO_CUDA')
+    preprocessor_conditions_end.insert(0, '#endif  // CERES_NO_CUDA')
 
   # If there are #ifdefs, put newlines around them.
   if preprocessor_conditions_begin:
@@ -223,10 +241,12 @@
   # Substitute variables into the test template, and write the result to a file.
   filename_tag = '_'.join(FILENAME_SHORTENING_MAP.get(x) for x in [
       linear_solver,
+      dense_backend_tag,
       sparse_backend_tag,
       preconditioner_tag,
       ordering]
       if FILENAME_SHORTENING_MAP.get(x))
+
   if (thread_config == MULTI_THREADED):
     filename_tag += '_threads'
 
@@ -236,7 +256,7 @@
     fd.write(BUNDLE_ADJUSTMENT_TEST_TEMPLATE % template_parameters)
 
   # All done.
-  print 'Generated', filename
+  print('Generated', filename)
 
   return filename
 
@@ -244,16 +264,37 @@
 if __name__ == '__main__':
   # Iterate over all the possible configurations and generate the tests.
   generated_files = []
-  for linear_solver, sparse_backend, preconditioner in SOLVER_CONFIGS:
-    for ordering in ORDERINGS:
-      for thread_config in THREAD_CONFIGS:
+
+  for ordering in ORDERINGS:
+    for thread_config in THREAD_CONFIGS:
+      for linear_solver, dense_backend in DENSE_SOLVER_CONFIGS:
         generated_files.append(
             generate_bundle_test(linear_solver,
+                                 dense_backend,
+                                 'NO_SPARSE',
+                                 'IDENTITY',
+                                 ordering,
+                                 thread_config))
+
+      for linear_solver, sparse_backend, in SPARSE_SOLVER_CONFIGS:
+        generated_files.append(
+            generate_bundle_test(linear_solver,
+                                 'EIGEN',
+                                 sparse_backend,
+                                 'IDENTITY',
+                                 ordering,
+                                 thread_config))
+
+      for linear_solver, sparse_backend, preconditioner, in ITERATIVE_SOLVER_CONFIGS:
+        generated_files.append(
+            generate_bundle_test(linear_solver,
+                                 'EIGEN',
                                  sparse_backend,
                                  preconditioner,
                                  ordering,
                                  thread_config))
 
+
   # Generate the CMakeLists.txt as well.
   with open('generated_bundle_adjustment_tests/CMakeLists.txt', 'w') as fd:
     fd.write(COPYRIGHT_HEADER.replace('//', '#').replace('http:#', 'http://'))
diff --git a/third_party/ceres/internal/ceres/generate_template_specializations.py b/third_party/ceres/internal/ceres/generate_template_specializations.py
index 74e46c2..12cf0b0 100644
--- a/third_party/ceres/internal/ceres/generate_template_specializations.py
+++ b/third_party/ceres/internal/ceres/generate_template_specializations.py
@@ -1,5 +1,5 @@
 # Ceres Solver - A fast non-linear least squares minimizer
-# Copyright 2015 Google Inc. All rights reserved.
+# Copyright 2023 Google Inc. All rights reserved.
 # http://ceres-solver.org/
 #
 # Redistribution and use in source and binary forms, with or without
@@ -85,9 +85,9 @@
   return str(size)
 
 def SpecializationFilename(prefix, row_block_size, e_block_size, f_block_size):
-  return "_".join([prefix] + map(SuffixForSize, (row_block_size,
+  return "_".join([prefix] + list(map(SuffixForSize, (row_block_size,
                                                  e_block_size,
-                                                 f_block_size)))
+                                                 f_block_size))))
 
 def GenerateFactoryConditional(row_block_size, e_block_size, f_block_size):
   conditionals = []
@@ -144,7 +144,7 @@
     f.write(data["FACTORY_FOOTER"])
 
 QUERY_HEADER = """// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
diff --git a/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_2.cc b/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_2.cc
index f5753be..c37dbf0 100644
--- a/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_2.cc
+++ b/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_2.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,18 +40,16 @@
 // This file is generated using generate_template_specializations.py.
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
 
 #include "ceres/partitioned_matrix_view_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class PartitionedMatrixView<2, 2, 2>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_3.cc b/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_3.cc
index a7a9b52..d856df6 100644
--- a/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_3.cc
+++ b/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_3.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,18 +40,16 @@
 // This file is generated using generate_template_specializations.py.
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
 
 #include "ceres/partitioned_matrix_view_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class PartitionedMatrixView<2, 2, 3>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_4.cc b/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_4.cc
index faf6c4a..a62a436 100644
--- a/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_4.cc
+++ b/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_4.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,18 +40,16 @@
 // This file is generated using generate_template_specializations.py.
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
 
 #include "ceres/partitioned_matrix_view_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class PartitionedMatrixView<2, 2, 4>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_d.cc b/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_d.cc
index 92fd4cd..f8b7089 100644
--- a/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_d.cc
+++ b/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_2_d.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,18 +40,16 @@
 // This file is generated using generate_template_specializations.py.
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
 
 #include "ceres/partitioned_matrix_view_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class PartitionedMatrixView<2, 2, Eigen::Dynamic>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_3.cc b/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_3.cc
index 2df314f..cd5bb91 100644
--- a/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_3.cc
+++ b/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_3.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,18 +40,16 @@
 // This file is generated using generate_template_specializations.py.
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
 
 #include "ceres/partitioned_matrix_view_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class PartitionedMatrixView<2, 3, 3>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_4.cc b/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_4.cc
index ff1ca3e..51af0f7 100644
--- a/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_4.cc
+++ b/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_4.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,18 +40,16 @@
 // This file is generated using generate_template_specializations.py.
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
 
 #include "ceres/partitioned_matrix_view_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class PartitionedMatrixView<2, 3, 4>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_6.cc b/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_6.cc
index 5041df9..39b920a 100644
--- a/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_6.cc
+++ b/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_6.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,18 +40,16 @@
 // This file is generated using generate_template_specializations.py.
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
 
 #include "ceres/partitioned_matrix_view_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class PartitionedMatrixView<2, 3, 6>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_9.cc b/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_9.cc
index c0b72fe..3f211b9 100644
--- a/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_9.cc
+++ b/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_9.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,18 +40,16 @@
 // This file is generated using generate_template_specializations.py.
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
 
 #include "ceres/partitioned_matrix_view_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class PartitionedMatrixView<2, 3, 9>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_d.cc b/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_d.cc
index 8a3c162..a33d2e3 100644
--- a/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_d.cc
+++ b/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_3_d.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,18 +40,16 @@
 // This file is generated using generate_template_specializations.py.
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
 
 #include "ceres/partitioned_matrix_view_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class PartitionedMatrixView<2, 3, Eigen::Dynamic>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_3.cc b/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_3.cc
index 0e69ca6..14b91b3 100644
--- a/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_3.cc
+++ b/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_3.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,18 +40,16 @@
 // This file is generated using generate_template_specializations.py.
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
 
 #include "ceres/partitioned_matrix_view_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class PartitionedMatrixView<2, 4, 3>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_4.cc b/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_4.cc
index ba9bb61..be1c234 100644
--- a/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_4.cc
+++ b/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_4.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,18 +40,16 @@
 // This file is generated using generate_template_specializations.py.
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
 
 #include "ceres/partitioned_matrix_view_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class PartitionedMatrixView<2, 4, 4>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_6.cc b/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_6.cc
index 1acdb9b..b4ad615 100644
--- a/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_6.cc
+++ b/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_6.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,18 +40,16 @@
 // This file is generated using generate_template_specializations.py.
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
 
 #include "ceres/partitioned_matrix_view_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class PartitionedMatrixView<2, 4, 6>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_8.cc b/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_8.cc
index 888ff99..b505f56 100644
--- a/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_8.cc
+++ b/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_8.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,18 +40,16 @@
 // This file is generated using generate_template_specializations.py.
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
 
 #include "ceres/partitioned_matrix_view_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class PartitionedMatrixView<2, 4, 8>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_9.cc b/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_9.cc
index bd4dde3..f2f1469 100644
--- a/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_9.cc
+++ b/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_9.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,18 +40,16 @@
 // This file is generated using generate_template_specializations.py.
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
 
 #include "ceres/partitioned_matrix_view_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class PartitionedMatrixView<2, 4, 9>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_d.cc b/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_d.cc
index 6d3516f..a0e250c 100644
--- a/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_d.cc
+++ b/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_4_d.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,18 +40,16 @@
 // This file is generated using generate_template_specializations.py.
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
 
 #include "ceres/partitioned_matrix_view_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class PartitionedMatrixView<2, 4, Eigen::Dynamic>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_d_d.cc b/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_d_d.cc
index 77d22ed..6878963 100644
--- a/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_d_d.cc
+++ b/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_2_d_d.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,18 +40,16 @@
 // This file is generated using generate_template_specializations.py.
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
 
 #include "ceres/partitioned_matrix_view_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class PartitionedMatrixView<2, Eigen::Dynamic, Eigen::Dynamic>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_3_3_3.cc b/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_3_3_3.cc
index aeb456c..2e6b81a 100644
--- a/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_3_3_3.cc
+++ b/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_3_3_3.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,18 +40,16 @@
 // This file is generated using generate_template_specializations.py.
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
 
 #include "ceres/partitioned_matrix_view_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class PartitionedMatrixView<3, 3, 3>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_2.cc b/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_2.cc
index bb240b9..8b09f75 100644
--- a/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_2.cc
+++ b/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_2.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,18 +40,16 @@
 // This file is generated using generate_template_specializations.py.
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
 
 #include "ceres/partitioned_matrix_view_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class PartitionedMatrixView<4, 4, 2>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_3.cc b/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_3.cc
index 5d47543..e857daa 100644
--- a/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_3.cc
+++ b/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_3.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,18 +40,16 @@
 // This file is generated using generate_template_specializations.py.
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
 
 #include "ceres/partitioned_matrix_view_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class PartitionedMatrixView<4, 4, 3>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_4.cc b/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_4.cc
index e14f980..f51a642 100644
--- a/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_4.cc
+++ b/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_4.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,18 +40,16 @@
 // This file is generated using generate_template_specializations.py.
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
 
 #include "ceres/partitioned_matrix_view_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class PartitionedMatrixView<4, 4, 4>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_d.cc b/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_d.cc
index 9ec5056..5e27e2e 100644
--- a/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_d.cc
+++ b/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_4_4_d.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,18 +40,16 @@
 // This file is generated using generate_template_specializations.py.
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
 
 #include "ceres/partitioned_matrix_view_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class PartitionedMatrixView<4, 4, Eigen::Dynamic>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_d_d_d.cc b/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_d_d_d.cc
index 1e12479..6e788ad 100644
--- a/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_d_d_d.cc
+++ b/third_party/ceres/internal/ceres/generated/partitioned_matrix_view_d_d_d.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -41,12 +41,10 @@
 
 #include "ceres/partitioned_matrix_view_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class PartitionedMatrixView<Eigen::Dynamic,
                                      Eigen::Dynamic,
                                      Eigen::Dynamic>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/generated/schur_eliminator_2_2_2.cc b/third_party/ceres/internal/ceres/generated/schur_eliminator_2_2_2.cc
index 289a809..de29abe 100644
--- a/third_party/ceres/internal/ceres/generated/schur_eliminator_2_2_2.cc
+++ b/third_party/ceres/internal/ceres/generated/schur_eliminator_2_2_2.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,18 +40,16 @@
 // This file is generated using generate_template_specializations.py.
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
 
 #include "ceres/schur_eliminator_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class SchurEliminator<2, 2, 2>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/third_party/ceres/internal/ceres/generated/schur_eliminator_2_2_3.cc b/third_party/ceres/internal/ceres/generated/schur_eliminator_2_2_3.cc
index 20311ba..38e2402 100644
--- a/third_party/ceres/internal/ceres/generated/schur_eliminator_2_2_3.cc
+++ b/third_party/ceres/internal/ceres/generated/schur_eliminator_2_2_3.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,18 +40,16 @@
 // This file is generated using generate_template_specializations.py.
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
 
 #include "ceres/schur_eliminator_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class SchurEliminator<2, 2, 3>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/third_party/ceres/internal/ceres/generated/schur_eliminator_2_2_4.cc b/third_party/ceres/internal/ceres/generated/schur_eliminator_2_2_4.cc
index 1f6a8ae..edf48ee 100644
--- a/third_party/ceres/internal/ceres/generated/schur_eliminator_2_2_4.cc
+++ b/third_party/ceres/internal/ceres/generated/schur_eliminator_2_2_4.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,18 +40,16 @@
 // This file is generated using generate_template_specializations.py.
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
 
 #include "ceres/schur_eliminator_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class SchurEliminator<2, 2, 4>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/third_party/ceres/internal/ceres/generated/schur_eliminator_2_2_d.cc b/third_party/ceres/internal/ceres/generated/schur_eliminator_2_2_d.cc
index 08b18d3..48a8301 100644
--- a/third_party/ceres/internal/ceres/generated/schur_eliminator_2_2_d.cc
+++ b/third_party/ceres/internal/ceres/generated/schur_eliminator_2_2_d.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,18 +40,16 @@
 // This file is generated using generate_template_specializations.py.
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
 
 #include "ceres/schur_eliminator_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class SchurEliminator<2, 2, Eigen::Dynamic>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/third_party/ceres/internal/ceres/generated/schur_eliminator_2_3_3.cc b/third_party/ceres/internal/ceres/generated/schur_eliminator_2_3_3.cc
index 115b4c8..49a450d 100644
--- a/third_party/ceres/internal/ceres/generated/schur_eliminator_2_3_3.cc
+++ b/third_party/ceres/internal/ceres/generated/schur_eliminator_2_3_3.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,18 +40,16 @@
 // This file is generated using generate_template_specializations.py.
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
 
 #include "ceres/schur_eliminator_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class SchurEliminator<2, 3, 3>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/third_party/ceres/internal/ceres/generated/schur_eliminator_2_3_4.cc b/third_party/ceres/internal/ceres/generated/schur_eliminator_2_3_4.cc
index c703537..730d2b1 100644
--- a/third_party/ceres/internal/ceres/generated/schur_eliminator_2_3_4.cc
+++ b/third_party/ceres/internal/ceres/generated/schur_eliminator_2_3_4.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,18 +40,16 @@
 // This file is generated using generate_template_specializations.py.
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
 
 #include "ceres/schur_eliminator_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class SchurEliminator<2, 3, 4>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/third_party/ceres/internal/ceres/generated/schur_eliminator_2_3_6.cc b/third_party/ceres/internal/ceres/generated/schur_eliminator_2_3_6.cc
index edb9afe..84b83af 100644
--- a/third_party/ceres/internal/ceres/generated/schur_eliminator_2_3_6.cc
+++ b/third_party/ceres/internal/ceres/generated/schur_eliminator_2_3_6.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,18 +40,16 @@
 // This file is generated using generate_template_specializations.py.
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
 
 #include "ceres/schur_eliminator_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class SchurEliminator<2, 3, 6>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/third_party/ceres/internal/ceres/generated/schur_eliminator_2_3_9.cc b/third_party/ceres/internal/ceres/generated/schur_eliminator_2_3_9.cc
index faa5c19..bfb903f 100644
--- a/third_party/ceres/internal/ceres/generated/schur_eliminator_2_3_9.cc
+++ b/third_party/ceres/internal/ceres/generated/schur_eliminator_2_3_9.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,18 +40,16 @@
 // This file is generated using generate_template_specializations.py.
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
 
 #include "ceres/schur_eliminator_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class SchurEliminator<2, 3, 9>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/third_party/ceres/internal/ceres/generated/schur_eliminator_2_3_d.cc b/third_party/ceres/internal/ceres/generated/schur_eliminator_2_3_d.cc
index 81b6f97..041b7ac 100644
--- a/third_party/ceres/internal/ceres/generated/schur_eliminator_2_3_d.cc
+++ b/third_party/ceres/internal/ceres/generated/schur_eliminator_2_3_d.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,18 +40,16 @@
 // This file is generated using generate_template_specializations.py.
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
 
 #include "ceres/schur_eliminator_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class SchurEliminator<2, 3, Eigen::Dynamic>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_3.cc b/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_3.cc
index 2cb2d15..c7827d1 100644
--- a/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_3.cc
+++ b/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_3.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,18 +40,16 @@
 // This file is generated using generate_template_specializations.py.
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
 
 #include "ceres/schur_eliminator_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class SchurEliminator<2, 4, 3>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_4.cc b/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_4.cc
index a78eff3..9429d4c 100644
--- a/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_4.cc
+++ b/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_4.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,18 +40,16 @@
 // This file is generated using generate_template_specializations.py.
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
 
 #include "ceres/schur_eliminator_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class SchurEliminator<2, 4, 4>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_6.cc b/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_6.cc
index e2534f2..ba14b08 100644
--- a/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_6.cc
+++ b/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_6.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,18 +40,16 @@
 // This file is generated using generate_template_specializations.py.
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
 
 #include "ceres/schur_eliminator_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class SchurEliminator<2, 4, 6>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_8.cc b/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_8.cc
index 296a462..9210d9d 100644
--- a/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_8.cc
+++ b/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_8.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,18 +40,16 @@
 // This file is generated using generate_template_specializations.py.
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
 
 #include "ceres/schur_eliminator_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class SchurEliminator<2, 4, 8>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_9.cc b/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_9.cc
index 0d0b04e..ea45d0f 100644
--- a/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_9.cc
+++ b/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_9.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,18 +40,16 @@
 // This file is generated using generate_template_specializations.py.
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
 
 #include "ceres/schur_eliminator_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class SchurEliminator<2, 4, 9>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_d.cc b/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_d.cc
index 7979926..8ba7c8c 100644
--- a/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_d.cc
+++ b/third_party/ceres/internal/ceres/generated/schur_eliminator_2_4_d.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,18 +40,16 @@
 // This file is generated using generate_template_specializations.py.
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
 
 #include "ceres/schur_eliminator_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class SchurEliminator<2, 4, Eigen::Dynamic>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/third_party/ceres/internal/ceres/generated/schur_eliminator_2_d_d.cc b/third_party/ceres/internal/ceres/generated/schur_eliminator_2_d_d.cc
index 189be04..1f40787 100644
--- a/third_party/ceres/internal/ceres/generated/schur_eliminator_2_d_d.cc
+++ b/third_party/ceres/internal/ceres/generated/schur_eliminator_2_d_d.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,18 +40,16 @@
 // This file is generated using generate_template_specializations.py.
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
 
 #include "ceres/schur_eliminator_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class SchurEliminator<2, Eigen::Dynamic, Eigen::Dynamic>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/third_party/ceres/internal/ceres/generated/schur_eliminator_3_3_3.cc b/third_party/ceres/internal/ceres/generated/schur_eliminator_3_3_3.cc
index 35c14a8..909fb79 100644
--- a/third_party/ceres/internal/ceres/generated/schur_eliminator_3_3_3.cc
+++ b/third_party/ceres/internal/ceres/generated/schur_eliminator_3_3_3.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,18 +40,16 @@
 // This file is generated using generate_template_specializations.py.
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
 
 #include "ceres/schur_eliminator_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class SchurEliminator<3, 3, 3>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/third_party/ceres/internal/ceres/generated/schur_eliminator_4_4_2.cc b/third_party/ceres/internal/ceres/generated/schur_eliminator_4_4_2.cc
index 878500a..5ca6fca 100644
--- a/third_party/ceres/internal/ceres/generated/schur_eliminator_4_4_2.cc
+++ b/third_party/ceres/internal/ceres/generated/schur_eliminator_4_4_2.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,18 +40,16 @@
 // This file is generated using generate_template_specializations.py.
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
 
 #include "ceres/schur_eliminator_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class SchurEliminator<4, 4, 2>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/third_party/ceres/internal/ceres/generated/schur_eliminator_4_4_3.cc b/third_party/ceres/internal/ceres/generated/schur_eliminator_4_4_3.cc
index c4b0959..9d0862a 100644
--- a/third_party/ceres/internal/ceres/generated/schur_eliminator_4_4_3.cc
+++ b/third_party/ceres/internal/ceres/generated/schur_eliminator_4_4_3.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,18 +40,16 @@
 // This file is generated using generate_template_specializations.py.
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
 
 #include "ceres/schur_eliminator_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class SchurEliminator<4, 4, 3>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/third_party/ceres/internal/ceres/generated/schur_eliminator_4_4_4.cc b/third_party/ceres/internal/ceres/generated/schur_eliminator_4_4_4.cc
index 20df534..b04ab66 100644
--- a/third_party/ceres/internal/ceres/generated/schur_eliminator_4_4_4.cc
+++ b/third_party/ceres/internal/ceres/generated/schur_eliminator_4_4_4.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,18 +40,16 @@
 // This file is generated using generate_template_specializations.py.
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
 
 #include "ceres/schur_eliminator_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class SchurEliminator<4, 4, 4>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/third_party/ceres/internal/ceres/generated/schur_eliminator_4_4_d.cc b/third_party/ceres/internal/ceres/generated/schur_eliminator_4_4_d.cc
index 17368dc..8e75543 100644
--- a/third_party/ceres/internal/ceres/generated/schur_eliminator_4_4_d.cc
+++ b/third_party/ceres/internal/ceres/generated/schur_eliminator_4_4_d.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,18 +40,16 @@
 // This file is generated using generate_template_specializations.py.
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
 
 #include "ceres/schur_eliminator_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class SchurEliminator<4, 4, Eigen::Dynamic>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
diff --git a/third_party/ceres/internal/ceres/generated/schur_eliminator_d_d_d.cc b/third_party/ceres/internal/ceres/generated/schur_eliminator_d_d_d.cc
index ca598fe..49c40e8 100644
--- a/third_party/ceres/internal/ceres/generated/schur_eliminator_d_d_d.cc
+++ b/third_party/ceres/internal/ceres/generated/schur_eliminator_d_d_d.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -41,10 +41,8 @@
 
 #include "ceres/schur_eliminator_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class SchurEliminator<Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/CMakeLists.txt b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/CMakeLists.txt
index db2d233..5f4f65e 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/CMakeLists.txt
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/CMakeLists.txt
@@ -1,5 +1,5 @@
 # Ceres Solver - A fast non-linear least squares minimizer
-# Copyright 2018 Google Inc. All rights reserved.
+# Copyright 2023 Google Inc. All rights reserved.
 # http://ceres-solver.org/
 #
 # Redistribution and use in source and binary forms, with or without
@@ -35,79 +35,75 @@
 #
 # This file is generated using generate_bundle_adjustment_tests.py.
 
-ceres_test(ba_denseschur_auto)
-ceres_test(ba_denseschur_auto_threads)
-ceres_test(ba_denseschur_user)
-ceres_test(ba_denseschur_user_threads)
-ceres_test(ba_iterschur_jacobi_auto)
-ceres_test(ba_iterschur_jacobi_auto_threads)
-ceres_test(ba_iterschur_jacobi_user)
-ceres_test(ba_iterschur_jacobi_user_threads)
-ceres_test(ba_iterschur_schurjacobi_auto)
-ceres_test(ba_iterschur_schurjacobi_auto_threads)
-ceres_test(ba_iterschur_schurjacobi_user)
-ceres_test(ba_iterschur_schurjacobi_user_threads)
-ceres_test(ba_iterschur_suitesparse_clustjacobi_auto)
-ceres_test(ba_iterschur_suitesparse_clustjacobi_auto_threads)
-ceres_test(ba_iterschur_suitesparse_clustjacobi_user)
-ceres_test(ba_iterschur_suitesparse_clustjacobi_user_threads)
-ceres_test(ba_iterschur_eigensparse_clustjacobi_auto)
-ceres_test(ba_iterschur_eigensparse_clustjacobi_auto_threads)
-ceres_test(ba_iterschur_eigensparse_clustjacobi_user)
-ceres_test(ba_iterschur_eigensparse_clustjacobi_user_threads)
-ceres_test(ba_iterschur_cxsparse_clustjacobi_auto)
-ceres_test(ba_iterschur_cxsparse_clustjacobi_auto_threads)
-ceres_test(ba_iterschur_cxsparse_clustjacobi_user)
-ceres_test(ba_iterschur_cxsparse_clustjacobi_user_threads)
-ceres_test(ba_iterschur_acceleratesparse_clustjacobi_auto)
-ceres_test(ba_iterschur_acceleratesparse_clustjacobi_auto_threads)
-ceres_test(ba_iterschur_acceleratesparse_clustjacobi_user)
-ceres_test(ba_iterschur_acceleratesparse_clustjacobi_user_threads)
-ceres_test(ba_iterschur_suitesparse_clusttri_auto)
-ceres_test(ba_iterschur_suitesparse_clusttri_auto_threads)
-ceres_test(ba_iterschur_suitesparse_clusttri_user)
-ceres_test(ba_iterschur_suitesparse_clusttri_user_threads)
-ceres_test(ba_iterschur_eigensparse_clusttri_auto)
-ceres_test(ba_iterschur_eigensparse_clusttri_auto_threads)
-ceres_test(ba_iterschur_eigensparse_clusttri_user)
-ceres_test(ba_iterschur_eigensparse_clusttri_user_threads)
-ceres_test(ba_iterschur_cxsparse_clusttri_auto)
-ceres_test(ba_iterschur_cxsparse_clusttri_auto_threads)
-ceres_test(ba_iterschur_cxsparse_clusttri_user)
-ceres_test(ba_iterschur_cxsparse_clusttri_user_threads)
-ceres_test(ba_iterschur_acceleratesparse_clusttri_auto)
-ceres_test(ba_iterschur_acceleratesparse_clusttri_auto_threads)
-ceres_test(ba_iterschur_acceleratesparse_clusttri_user)
-ceres_test(ba_iterschur_acceleratesparse_clusttri_user_threads)
+ceres_test(ba_denseschur_eigen_auto)
+ceres_test(ba_denseschur_lapack_auto)
+ceres_test(ba_denseschur_cuda_auto)
 ceres_test(ba_sparsecholesky_suitesparse_auto)
-ceres_test(ba_sparsecholesky_suitesparse_auto_threads)
-ceres_test(ba_sparsecholesky_suitesparse_user)
-ceres_test(ba_sparsecholesky_suitesparse_user_threads)
 ceres_test(ba_sparsecholesky_eigensparse_auto)
-ceres_test(ba_sparsecholesky_eigensparse_auto_threads)
-ceres_test(ba_sparsecholesky_eigensparse_user)
-ceres_test(ba_sparsecholesky_eigensparse_user_threads)
-ceres_test(ba_sparsecholesky_cxsparse_auto)
-ceres_test(ba_sparsecholesky_cxsparse_auto_threads)
-ceres_test(ba_sparsecholesky_cxsparse_user)
-ceres_test(ba_sparsecholesky_cxsparse_user_threads)
 ceres_test(ba_sparsecholesky_acceleratesparse_auto)
-ceres_test(ba_sparsecholesky_acceleratesparse_auto_threads)
-ceres_test(ba_sparsecholesky_acceleratesparse_user)
-ceres_test(ba_sparsecholesky_acceleratesparse_user_threads)
 ceres_test(ba_sparseschur_suitesparse_auto)
-ceres_test(ba_sparseschur_suitesparse_auto_threads)
-ceres_test(ba_sparseschur_suitesparse_user)
-ceres_test(ba_sparseschur_suitesparse_user_threads)
 ceres_test(ba_sparseschur_eigensparse_auto)
-ceres_test(ba_sparseschur_eigensparse_auto_threads)
-ceres_test(ba_sparseschur_eigensparse_user)
-ceres_test(ba_sparseschur_eigensparse_user_threads)
-ceres_test(ba_sparseschur_cxsparse_auto)
-ceres_test(ba_sparseschur_cxsparse_auto_threads)
-ceres_test(ba_sparseschur_cxsparse_user)
-ceres_test(ba_sparseschur_cxsparse_user_threads)
 ceres_test(ba_sparseschur_acceleratesparse_auto)
+ceres_test(ba_iterschur_jacobi_auto)
+ceres_test(ba_iterschur_schurjacobi_auto)
+ceres_test(ba_iterschur_spse_auto)
+ceres_test(ba_iterschur_suitesparse_clustjacobi_auto)
+ceres_test(ba_iterschur_eigensparse_clustjacobi_auto)
+ceres_test(ba_iterschur_acceleratesparse_clustjacobi_auto)
+ceres_test(ba_iterschur_suitesparse_clusttri_auto)
+ceres_test(ba_iterschur_eigensparse_clusttri_auto)
+ceres_test(ba_iterschur_acceleratesparse_clusttri_auto)
+ceres_test(ba_denseschur_eigen_auto_threads)
+ceres_test(ba_denseschur_lapack_auto_threads)
+ceres_test(ba_denseschur_cuda_auto_threads)
+ceres_test(ba_sparsecholesky_suitesparse_auto_threads)
+ceres_test(ba_sparsecholesky_eigensparse_auto_threads)
+ceres_test(ba_sparsecholesky_acceleratesparse_auto_threads)
+ceres_test(ba_sparseschur_suitesparse_auto_threads)
+ceres_test(ba_sparseschur_eigensparse_auto_threads)
 ceres_test(ba_sparseschur_acceleratesparse_auto_threads)
+ceres_test(ba_iterschur_jacobi_auto_threads)
+ceres_test(ba_iterschur_schurjacobi_auto_threads)
+ceres_test(ba_iterschur_spse_auto_threads)
+ceres_test(ba_iterschur_suitesparse_clustjacobi_auto_threads)
+ceres_test(ba_iterschur_eigensparse_clustjacobi_auto_threads)
+ceres_test(ba_iterschur_acceleratesparse_clustjacobi_auto_threads)
+ceres_test(ba_iterschur_suitesparse_clusttri_auto_threads)
+ceres_test(ba_iterschur_eigensparse_clusttri_auto_threads)
+ceres_test(ba_iterschur_acceleratesparse_clusttri_auto_threads)
+ceres_test(ba_denseschur_eigen_user)
+ceres_test(ba_denseschur_lapack_user)
+ceres_test(ba_denseschur_cuda_user)
+ceres_test(ba_sparsecholesky_suitesparse_user)
+ceres_test(ba_sparsecholesky_eigensparse_user)
+ceres_test(ba_sparsecholesky_acceleratesparse_user)
+ceres_test(ba_sparseschur_suitesparse_user)
+ceres_test(ba_sparseschur_eigensparse_user)
 ceres_test(ba_sparseschur_acceleratesparse_user)
+ceres_test(ba_iterschur_jacobi_user)
+ceres_test(ba_iterschur_schurjacobi_user)
+ceres_test(ba_iterschur_spse_user)
+ceres_test(ba_iterschur_suitesparse_clustjacobi_user)
+ceres_test(ba_iterschur_eigensparse_clustjacobi_user)
+ceres_test(ba_iterschur_acceleratesparse_clustjacobi_user)
+ceres_test(ba_iterschur_suitesparse_clusttri_user)
+ceres_test(ba_iterschur_eigensparse_clusttri_user)
+ceres_test(ba_iterschur_acceleratesparse_clusttri_user)
+ceres_test(ba_denseschur_eigen_user_threads)
+ceres_test(ba_denseschur_lapack_user_threads)
+ceres_test(ba_denseschur_cuda_user_threads)
+ceres_test(ba_sparsecholesky_suitesparse_user_threads)
+ceres_test(ba_sparsecholesky_eigensparse_user_threads)
+ceres_test(ba_sparsecholesky_acceleratesparse_user_threads)
+ceres_test(ba_sparseschur_suitesparse_user_threads)
+ceres_test(ba_sparseschur_eigensparse_user_threads)
 ceres_test(ba_sparseschur_acceleratesparse_user_threads)
+ceres_test(ba_iterschur_jacobi_user_threads)
+ceres_test(ba_iterschur_schurjacobi_user_threads)
+ceres_test(ba_iterschur_spse_user_threads)
+ceres_test(ba_iterschur_suitesparse_clustjacobi_user_threads)
+ceres_test(ba_iterschur_eigensparse_clustjacobi_user_threads)
+ceres_test(ba_iterschur_acceleratesparse_clustjacobi_user_threads)
+ceres_test(ba_iterschur_suitesparse_clusttri_user_threads)
+ceres_test(ba_iterschur_eigensparse_clusttri_user_threads)
+ceres_test(ba_iterschur_acceleratesparse_clusttri_user_threads)
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_auto_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_auto_test.cc
deleted file mode 100644
index c0585e8..0000000
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_auto_test.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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 Google Inc. 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 IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// ========================================
-//
-// This file is generated using generate_bundle_adjustment_tests.py.
-
-#include "bundle_adjustment_test_util.h"
-
-namespace ceres {
-namespace internal {
-
-TEST_F(BundleAdjustmentTest,
-       DenseSchur_AutomaticOrdering) {  // NOLINT
-  BundleAdjustmentProblem bundle_adjustment_problem;
-  Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
-  options->num_threads = 1;
-  options->linear_solver_type = DENSE_SCHUR;
-  options->sparse_linear_algebra_library_type = NO_SPARSE;
-  options->preconditioner_type = IDENTITY;
-  if (kAutomaticOrdering) {
-    options->linear_solver_ordering.reset();
-  }
-  Problem* problem = bundle_adjustment_problem.mutable_problem();
-  RunSolverForConfigAndExpectResidualsMatch(*options, problem);
-}
-
-}  // namespace internal
-}  // namespace ceres
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_auto_threads_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_auto_threads_test.cc
deleted file mode 100644
index 2ece1b4..0000000
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_auto_threads_test.cc
+++ /dev/null
@@ -1,63 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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 Google Inc. 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 IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// ========================================
-//
-// This file is generated using generate_bundle_adjustment_tests.py.
-
-#include "bundle_adjustment_test_util.h"
-
-#ifndef CERES_NO_THREADS
-
-namespace ceres {
-namespace internal {
-
-TEST_F(BundleAdjustmentTest,
-       DenseSchur_AutomaticOrdering_Threads) {  // NOLINT
-  BundleAdjustmentProblem bundle_adjustment_problem;
-  Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
-  options->num_threads = 4;
-  options->linear_solver_type = DENSE_SCHUR;
-  options->sparse_linear_algebra_library_type = NO_SPARSE;
-  options->preconditioner_type = IDENTITY;
-  if (kAutomaticOrdering) {
-    options->linear_solver_ordering.reset();
-  }
-  Problem* problem = bundle_adjustment_problem.mutable_problem();
-  RunSolverForConfigAndExpectResidualsMatch(*options, problem);
-}
-
-}  // namespace internal
-}  // namespace ceres
-
-#endif  // CERES_NO_THREADS
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_cuda_auto_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_cuda_auto_test.cc
new file mode 100644
index 0000000..e48f646
--- /dev/null
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_cuda_auto_test.cc
@@ -0,0 +1,65 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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 IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// ========================================
+//
+// This file is generated using generate_bundle_adjustment_tests.py.
+
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
+
+#ifndef CERES_NO_CUDA
+
+namespace ceres::internal {
+
+TEST_F(BundleAdjustmentTest,
+       DenseSchur_Cuda_AutomaticOrdering) {  // NOLINT
+  BundleAdjustmentProblem bundle_adjustment_problem;
+  Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
+  options->num_threads = 1;
+  options->linear_solver_type = DENSE_SCHUR;
+  options->dense_linear_algebra_library_type = CUDA;
+  options->sparse_linear_algebra_library_type = NO_SPARSE;
+  options->preconditioner_type = IDENTITY;
+  if (kAutomaticOrdering) {
+    options->linear_solver_ordering = nullptr;
+  }
+  Problem* problem = bundle_adjustment_problem.mutable_problem();
+  RunSolverForConfigAndExpectResidualsMatch(*options, problem);
+}
+
+}  // namespace ceres::internal
+
+#endif  // CERES_NO_CUDA
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_cuda_auto_threads_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_cuda_auto_threads_test.cc
new file mode 100644
index 0000000..336066e
--- /dev/null
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_cuda_auto_threads_test.cc
@@ -0,0 +1,65 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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 IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// ========================================
+//
+// This file is generated using generate_bundle_adjustment_tests.py.
+
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
+
+#ifndef CERES_NO_CUDA
+
+namespace ceres::internal {
+
+TEST_F(BundleAdjustmentTest,
+       DenseSchur_Cuda_AutomaticOrdering_Threads) {  // NOLINT
+  BundleAdjustmentProblem bundle_adjustment_problem;
+  Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
+  options->num_threads = 4;
+  options->linear_solver_type = DENSE_SCHUR;
+  options->dense_linear_algebra_library_type = CUDA;
+  options->sparse_linear_algebra_library_type = NO_SPARSE;
+  options->preconditioner_type = IDENTITY;
+  if (kAutomaticOrdering) {
+    options->linear_solver_ordering = nullptr;
+  }
+  Problem* problem = bundle_adjustment_problem.mutable_problem();
+  RunSolverForConfigAndExpectResidualsMatch(*options, problem);
+}
+
+}  // namespace ceres::internal
+
+#endif  // CERES_NO_CUDA
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_cuda_user_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_cuda_user_test.cc
new file mode 100644
index 0000000..86df64d
--- /dev/null
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_cuda_user_test.cc
@@ -0,0 +1,65 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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 IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// ========================================
+//
+// This file is generated using generate_bundle_adjustment_tests.py.
+
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
+
+#ifndef CERES_NO_CUDA
+
+namespace ceres::internal {
+
+TEST_F(BundleAdjustmentTest,
+       DenseSchur_Cuda_UserOrdering) {  // NOLINT
+  BundleAdjustmentProblem bundle_adjustment_problem;
+  Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
+  options->num_threads = 1;
+  options->linear_solver_type = DENSE_SCHUR;
+  options->dense_linear_algebra_library_type = CUDA;
+  options->sparse_linear_algebra_library_type = NO_SPARSE;
+  options->preconditioner_type = IDENTITY;
+  if (kUserOrdering) {
+    options->linear_solver_ordering = nullptr;
+  }
+  Problem* problem = bundle_adjustment_problem.mutable_problem();
+  RunSolverForConfigAndExpectResidualsMatch(*options, problem);
+}
+
+}  // namespace ceres::internal
+
+#endif  // CERES_NO_CUDA
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_cuda_user_threads_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_cuda_user_threads_test.cc
new file mode 100644
index 0000000..5e752e4
--- /dev/null
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_cuda_user_threads_test.cc
@@ -0,0 +1,65 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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 IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// ========================================
+//
+// This file is generated using generate_bundle_adjustment_tests.py.
+
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
+
+#ifndef CERES_NO_CUDA
+
+namespace ceres::internal {
+
+TEST_F(BundleAdjustmentTest,
+       DenseSchur_Cuda_UserOrdering_Threads) {  // NOLINT
+  BundleAdjustmentProblem bundle_adjustment_problem;
+  Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
+  options->num_threads = 4;
+  options->linear_solver_type = DENSE_SCHUR;
+  options->dense_linear_algebra_library_type = CUDA;
+  options->sparse_linear_algebra_library_type = NO_SPARSE;
+  options->preconditioner_type = IDENTITY;
+  if (kUserOrdering) {
+    options->linear_solver_ordering = nullptr;
+  }
+  Problem* problem = bundle_adjustment_problem.mutable_problem();
+  RunSolverForConfigAndExpectResidualsMatch(*options, problem);
+}
+
+}  // namespace ceres::internal
+
+#endif  // CERES_NO_CUDA
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_eigen_auto_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_eigen_auto_test.cc
new file mode 100644
index 0000000..faca44e
--- /dev/null
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_eigen_auto_test.cc
@@ -0,0 +1,61 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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 IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// ========================================
+//
+// This file is generated using generate_bundle_adjustment_tests.py.
+
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
+
+namespace ceres::internal {
+
+TEST_F(BundleAdjustmentTest,
+       DenseSchur_Eigen_AutomaticOrdering) {  // NOLINT
+  BundleAdjustmentProblem bundle_adjustment_problem;
+  Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
+  options->num_threads = 1;
+  options->linear_solver_type = DENSE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
+  options->sparse_linear_algebra_library_type = NO_SPARSE;
+  options->preconditioner_type = IDENTITY;
+  if (kAutomaticOrdering) {
+    options->linear_solver_ordering = nullptr;
+  }
+  Problem* problem = bundle_adjustment_problem.mutable_problem();
+  RunSolverForConfigAndExpectResidualsMatch(*options, problem);
+}
+
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_eigen_auto_threads_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_eigen_auto_threads_test.cc
new file mode 100644
index 0000000..c4db182
--- /dev/null
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_eigen_auto_threads_test.cc
@@ -0,0 +1,61 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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 IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// ========================================
+//
+// This file is generated using generate_bundle_adjustment_tests.py.
+
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
+
+namespace ceres::internal {
+
+TEST_F(BundleAdjustmentTest,
+       DenseSchur_Eigen_AutomaticOrdering_Threads) {  // NOLINT
+  BundleAdjustmentProblem bundle_adjustment_problem;
+  Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
+  options->num_threads = 4;
+  options->linear_solver_type = DENSE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
+  options->sparse_linear_algebra_library_type = NO_SPARSE;
+  options->preconditioner_type = IDENTITY;
+  if (kAutomaticOrdering) {
+    options->linear_solver_ordering = nullptr;
+  }
+  Problem* problem = bundle_adjustment_problem.mutable_problem();
+  RunSolverForConfigAndExpectResidualsMatch(*options, problem);
+}
+
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_eigen_user_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_eigen_user_test.cc
new file mode 100644
index 0000000..7fe05d1
--- /dev/null
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_eigen_user_test.cc
@@ -0,0 +1,61 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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 IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// ========================================
+//
+// This file is generated using generate_bundle_adjustment_tests.py.
+
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
+
+namespace ceres::internal {
+
+TEST_F(BundleAdjustmentTest,
+       DenseSchur_Eigen_UserOrdering) {  // NOLINT
+  BundleAdjustmentProblem bundle_adjustment_problem;
+  Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
+  options->num_threads = 1;
+  options->linear_solver_type = DENSE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
+  options->sparse_linear_algebra_library_type = NO_SPARSE;
+  options->preconditioner_type = IDENTITY;
+  if (kUserOrdering) {
+    options->linear_solver_ordering = nullptr;
+  }
+  Problem* problem = bundle_adjustment_problem.mutable_problem();
+  RunSolverForConfigAndExpectResidualsMatch(*options, problem);
+}
+
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_eigen_user_threads_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_eigen_user_threads_test.cc
new file mode 100644
index 0000000..7c34e20
--- /dev/null
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_eigen_user_threads_test.cc
@@ -0,0 +1,61 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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 IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// ========================================
+//
+// This file is generated using generate_bundle_adjustment_tests.py.
+
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
+
+namespace ceres::internal {
+
+TEST_F(BundleAdjustmentTest,
+       DenseSchur_Eigen_UserOrdering_Threads) {  // NOLINT
+  BundleAdjustmentProblem bundle_adjustment_problem;
+  Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
+  options->num_threads = 4;
+  options->linear_solver_type = DENSE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
+  options->sparse_linear_algebra_library_type = NO_SPARSE;
+  options->preconditioner_type = IDENTITY;
+  if (kUserOrdering) {
+    options->linear_solver_ordering = nullptr;
+  }
+  Problem* problem = bundle_adjustment_problem.mutable_problem();
+  RunSolverForConfigAndExpectResidualsMatch(*options, problem);
+}
+
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_lapack_auto_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_lapack_auto_test.cc
new file mode 100644
index 0000000..79ec5ce
--- /dev/null
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_lapack_auto_test.cc
@@ -0,0 +1,65 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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 IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// ========================================
+//
+// This file is generated using generate_bundle_adjustment_tests.py.
+
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
+
+#ifndef CERES_NO_LAPACK
+
+namespace ceres::internal {
+
+TEST_F(BundleAdjustmentTest,
+       DenseSchur_Lapack_AutomaticOrdering) {  // NOLINT
+  BundleAdjustmentProblem bundle_adjustment_problem;
+  Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
+  options->num_threads = 1;
+  options->linear_solver_type = DENSE_SCHUR;
+  options->dense_linear_algebra_library_type = LAPACK;
+  options->sparse_linear_algebra_library_type = NO_SPARSE;
+  options->preconditioner_type = IDENTITY;
+  if (kAutomaticOrdering) {
+    options->linear_solver_ordering = nullptr;
+  }
+  Problem* problem = bundle_adjustment_problem.mutable_problem();
+  RunSolverForConfigAndExpectResidualsMatch(*options, problem);
+}
+
+}  // namespace ceres::internal
+
+#endif  // CERES_NO_LAPACK
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_lapack_auto_threads_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_lapack_auto_threads_test.cc
new file mode 100644
index 0000000..ee74420
--- /dev/null
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_lapack_auto_threads_test.cc
@@ -0,0 +1,65 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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 IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// ========================================
+//
+// This file is generated using generate_bundle_adjustment_tests.py.
+
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
+
+#ifndef CERES_NO_LAPACK
+
+namespace ceres::internal {
+
+TEST_F(BundleAdjustmentTest,
+       DenseSchur_Lapack_AutomaticOrdering_Threads) {  // NOLINT
+  BundleAdjustmentProblem bundle_adjustment_problem;
+  Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
+  options->num_threads = 4;
+  options->linear_solver_type = DENSE_SCHUR;
+  options->dense_linear_algebra_library_type = LAPACK;
+  options->sparse_linear_algebra_library_type = NO_SPARSE;
+  options->preconditioner_type = IDENTITY;
+  if (kAutomaticOrdering) {
+    options->linear_solver_ordering = nullptr;
+  }
+  Problem* problem = bundle_adjustment_problem.mutable_problem();
+  RunSolverForConfigAndExpectResidualsMatch(*options, problem);
+}
+
+}  // namespace ceres::internal
+
+#endif  // CERES_NO_LAPACK
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_lapack_user_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_lapack_user_test.cc
new file mode 100644
index 0000000..205de87
--- /dev/null
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_lapack_user_test.cc
@@ -0,0 +1,65 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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 IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// ========================================
+//
+// This file is generated using generate_bundle_adjustment_tests.py.
+
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
+
+#ifndef CERES_NO_LAPACK
+
+namespace ceres::internal {
+
+TEST_F(BundleAdjustmentTest,
+       DenseSchur_Lapack_UserOrdering) {  // NOLINT
+  BundleAdjustmentProblem bundle_adjustment_problem;
+  Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
+  options->num_threads = 1;
+  options->linear_solver_type = DENSE_SCHUR;
+  options->dense_linear_algebra_library_type = LAPACK;
+  options->sparse_linear_algebra_library_type = NO_SPARSE;
+  options->preconditioner_type = IDENTITY;
+  if (kUserOrdering) {
+    options->linear_solver_ordering = nullptr;
+  }
+  Problem* problem = bundle_adjustment_problem.mutable_problem();
+  RunSolverForConfigAndExpectResidualsMatch(*options, problem);
+}
+
+}  // namespace ceres::internal
+
+#endif  // CERES_NO_LAPACK
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_lapack_user_threads_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_lapack_user_threads_test.cc
new file mode 100644
index 0000000..03a0a73
--- /dev/null
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_lapack_user_threads_test.cc
@@ -0,0 +1,65 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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 IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// ========================================
+//
+// This file is generated using generate_bundle_adjustment_tests.py.
+
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
+
+#ifndef CERES_NO_LAPACK
+
+namespace ceres::internal {
+
+TEST_F(BundleAdjustmentTest,
+       DenseSchur_Lapack_UserOrdering_Threads) {  // NOLINT
+  BundleAdjustmentProblem bundle_adjustment_problem;
+  Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
+  options->num_threads = 4;
+  options->linear_solver_type = DENSE_SCHUR;
+  options->dense_linear_algebra_library_type = LAPACK;
+  options->sparse_linear_algebra_library_type = NO_SPARSE;
+  options->preconditioner_type = IDENTITY;
+  if (kUserOrdering) {
+    options->linear_solver_ordering = nullptr;
+  }
+  Problem* problem = bundle_adjustment_problem.mutable_problem();
+  RunSolverForConfigAndExpectResidualsMatch(*options, problem);
+}
+
+}  // namespace ceres::internal
+
+#endif  // CERES_NO_LAPACK
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_user_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_user_test.cc
deleted file mode 100644
index 983c09e..0000000
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_user_test.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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 Google Inc. 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 IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// ========================================
-//
-// This file is generated using generate_bundle_adjustment_tests.py.
-
-#include "bundle_adjustment_test_util.h"
-
-namespace ceres {
-namespace internal {
-
-TEST_F(BundleAdjustmentTest,
-       DenseSchur_UserOrdering) {  // NOLINT
-  BundleAdjustmentProblem bundle_adjustment_problem;
-  Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
-  options->num_threads = 1;
-  options->linear_solver_type = DENSE_SCHUR;
-  options->sparse_linear_algebra_library_type = NO_SPARSE;
-  options->preconditioner_type = IDENTITY;
-  if (kUserOrdering) {
-    options->linear_solver_ordering.reset();
-  }
-  Problem* problem = bundle_adjustment_problem.mutable_problem();
-  RunSolverForConfigAndExpectResidualsMatch(*options, problem);
-}
-
-}  // namespace internal
-}  // namespace ceres
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_user_threads_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_user_threads_test.cc
deleted file mode 100644
index 5b739f9..0000000
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_denseschur_user_threads_test.cc
+++ /dev/null
@@ -1,63 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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 Google Inc. 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 IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// ========================================
-//
-// This file is generated using generate_bundle_adjustment_tests.py.
-
-#include "bundle_adjustment_test_util.h"
-
-#ifndef CERES_NO_THREADS
-
-namespace ceres {
-namespace internal {
-
-TEST_F(BundleAdjustmentTest,
-       DenseSchur_UserOrdering_Threads) {  // NOLINT
-  BundleAdjustmentProblem bundle_adjustment_problem;
-  Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
-  options->num_threads = 4;
-  options->linear_solver_type = DENSE_SCHUR;
-  options->sparse_linear_algebra_library_type = NO_SPARSE;
-  options->preconditioner_type = IDENTITY;
-  if (kUserOrdering) {
-    options->linear_solver_ordering.reset();
-  }
-  Problem* problem = bundle_adjustment_problem.mutable_problem();
-  RunSolverForConfigAndExpectResidualsMatch(*options, problem);
-}
-
-}  // namespace internal
-}  // namespace ceres
-
-#endif  // CERES_NO_THREADS
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_acceleratesparse_clustjacobi_auto_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_acceleratesparse_clustjacobi_auto_test.cc
index f2a6661..8ab6a9b 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_acceleratesparse_clustjacobi_auto_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_acceleratesparse_clustjacobi_auto_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,29 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifndef CERES_NO_ACCELERATE_SPARSE
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        IterativeSchur_AccelerateSparse_ClusterJacobi_AutomaticOrdering) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 1;
   options->linear_solver_type = ITERATIVE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = ACCELERATE_SPARSE;
   options->preconditioner_type = CLUSTER_JACOBI;
   if (kAutomaticOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_NO_ACCELERATE_SPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_acceleratesparse_clustjacobi_auto_threads_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_acceleratesparse_clustjacobi_auto_threads_test.cc
index 0178c67..cf6be8d 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_acceleratesparse_clustjacobi_auto_threads_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_acceleratesparse_clustjacobi_auto_threads_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,31 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifndef CERES_NO_ACCELERATE_SPARSE
-#ifndef CERES_NO_THREADS
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        IterativeSchur_AccelerateSparse_ClusterJacobi_AutomaticOrdering_Threads) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 4;
   options->linear_solver_type = ITERATIVE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = ACCELERATE_SPARSE;
   options->preconditioner_type = CLUSTER_JACOBI;
   if (kAutomaticOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
-#endif  // CERES_NO_THREADS
 #endif  // CERES_NO_ACCELERATE_SPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_acceleratesparse_clustjacobi_user_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_acceleratesparse_clustjacobi_user_test.cc
index 6f29df5..b6ca30f 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_acceleratesparse_clustjacobi_user_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_acceleratesparse_clustjacobi_user_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,29 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifndef CERES_NO_ACCELERATE_SPARSE
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        IterativeSchur_AccelerateSparse_ClusterJacobi_UserOrdering) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 1;
   options->linear_solver_type = ITERATIVE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = ACCELERATE_SPARSE;
   options->preconditioner_type = CLUSTER_JACOBI;
   if (kUserOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_NO_ACCELERATE_SPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_acceleratesparse_clustjacobi_user_threads_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_acceleratesparse_clustjacobi_user_threads_test.cc
index c92b364..2ef6aa1 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_acceleratesparse_clustjacobi_user_threads_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_acceleratesparse_clustjacobi_user_threads_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,31 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifndef CERES_NO_ACCELERATE_SPARSE
-#ifndef CERES_NO_THREADS
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        IterativeSchur_AccelerateSparse_ClusterJacobi_UserOrdering_Threads) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 4;
   options->linear_solver_type = ITERATIVE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = ACCELERATE_SPARSE;
   options->preconditioner_type = CLUSTER_JACOBI;
   if (kUserOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
-#endif  // CERES_NO_THREADS
 #endif  // CERES_NO_ACCELERATE_SPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_acceleratesparse_clusttri_auto_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_acceleratesparse_clusttri_auto_test.cc
index 576a251..ea24955 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_acceleratesparse_clusttri_auto_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_acceleratesparse_clusttri_auto_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,29 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifndef CERES_NO_ACCELERATE_SPARSE
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        IterativeSchur_AccelerateSparse_ClusterTridiagonal_AutomaticOrdering) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 1;
   options->linear_solver_type = ITERATIVE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = ACCELERATE_SPARSE;
   options->preconditioner_type = CLUSTER_TRIDIAGONAL;
   if (kAutomaticOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_NO_ACCELERATE_SPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_acceleratesparse_clusttri_auto_threads_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_acceleratesparse_clusttri_auto_threads_test.cc
index 363c92a..217edc3 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_acceleratesparse_clusttri_auto_threads_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_acceleratesparse_clusttri_auto_threads_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,31 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifndef CERES_NO_ACCELERATE_SPARSE
-#ifndef CERES_NO_THREADS
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        IterativeSchur_AccelerateSparse_ClusterTridiagonal_AutomaticOrdering_Threads) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 4;
   options->linear_solver_type = ITERATIVE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = ACCELERATE_SPARSE;
   options->preconditioner_type = CLUSTER_TRIDIAGONAL;
   if (kAutomaticOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
-#endif  // CERES_NO_THREADS
 #endif  // CERES_NO_ACCELERATE_SPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_acceleratesparse_clusttri_user_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_acceleratesparse_clusttri_user_test.cc
index 7444a77..4b66d17 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_acceleratesparse_clusttri_user_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_acceleratesparse_clusttri_user_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,29 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifndef CERES_NO_ACCELERATE_SPARSE
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        IterativeSchur_AccelerateSparse_ClusterTridiagonal_UserOrdering) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 1;
   options->linear_solver_type = ITERATIVE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = ACCELERATE_SPARSE;
   options->preconditioner_type = CLUSTER_TRIDIAGONAL;
   if (kUserOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_NO_ACCELERATE_SPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_acceleratesparse_clusttri_user_threads_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_acceleratesparse_clusttri_user_threads_test.cc
index f258e6b..3e84734 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_acceleratesparse_clusttri_user_threads_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_acceleratesparse_clusttri_user_threads_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,31 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifndef CERES_NO_ACCELERATE_SPARSE
-#ifndef CERES_NO_THREADS
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        IterativeSchur_AccelerateSparse_ClusterTridiagonal_UserOrdering_Threads) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 4;
   options->linear_solver_type = ITERATIVE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = ACCELERATE_SPARSE;
   options->preconditioner_type = CLUSTER_TRIDIAGONAL;
   if (kUserOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
-#endif  // CERES_NO_THREADS
 #endif  // CERES_NO_ACCELERATE_SPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_cxsparse_clustjacobi_auto_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_cxsparse_clustjacobi_auto_test.cc
deleted file mode 100644
index 9f7032b..0000000
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_cxsparse_clustjacobi_auto_test.cc
+++ /dev/null
@@ -1,63 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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 Google Inc. 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 IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// ========================================
-//
-// This file is generated using generate_bundle_adjustment_tests.py.
-
-#include "bundle_adjustment_test_util.h"
-
-#ifndef CERES_NO_CXSPARSE
-
-namespace ceres {
-namespace internal {
-
-TEST_F(BundleAdjustmentTest,
-       IterativeSchur_CxSparse_ClusterJacobi_AutomaticOrdering) {  // NOLINT
-  BundleAdjustmentProblem bundle_adjustment_problem;
-  Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
-  options->num_threads = 1;
-  options->linear_solver_type = ITERATIVE_SCHUR;
-  options->sparse_linear_algebra_library_type = CX_SPARSE;
-  options->preconditioner_type = CLUSTER_JACOBI;
-  if (kAutomaticOrdering) {
-    options->linear_solver_ordering.reset();
-  }
-  Problem* problem = bundle_adjustment_problem.mutable_problem();
-  RunSolverForConfigAndExpectResidualsMatch(*options, problem);
-}
-
-}  // namespace internal
-}  // namespace ceres
-
-#endif  // CERES_NO_CXSPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_cxsparse_clustjacobi_auto_threads_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_cxsparse_clustjacobi_auto_threads_test.cc
deleted file mode 100644
index 3d807cf..0000000
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_cxsparse_clustjacobi_auto_threads_test.cc
+++ /dev/null
@@ -1,65 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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 Google Inc. 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 IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// ========================================
-//
-// This file is generated using generate_bundle_adjustment_tests.py.
-
-#include "bundle_adjustment_test_util.h"
-
-#ifndef CERES_NO_CXSPARSE
-#ifndef CERES_NO_THREADS
-
-namespace ceres {
-namespace internal {
-
-TEST_F(BundleAdjustmentTest,
-       IterativeSchur_CxSparse_ClusterJacobi_AutomaticOrdering_Threads) {  // NOLINT
-  BundleAdjustmentProblem bundle_adjustment_problem;
-  Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
-  options->num_threads = 4;
-  options->linear_solver_type = ITERATIVE_SCHUR;
-  options->sparse_linear_algebra_library_type = CX_SPARSE;
-  options->preconditioner_type = CLUSTER_JACOBI;
-  if (kAutomaticOrdering) {
-    options->linear_solver_ordering.reset();
-  }
-  Problem* problem = bundle_adjustment_problem.mutable_problem();
-  RunSolverForConfigAndExpectResidualsMatch(*options, problem);
-}
-
-}  // namespace internal
-}  // namespace ceres
-
-#endif  // CERES_NO_THREADS
-#endif  // CERES_NO_CXSPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_cxsparse_clustjacobi_user_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_cxsparse_clustjacobi_user_test.cc
deleted file mode 100644
index 5883d12..0000000
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_cxsparse_clustjacobi_user_test.cc
+++ /dev/null
@@ -1,63 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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 Google Inc. 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 IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// ========================================
-//
-// This file is generated using generate_bundle_adjustment_tests.py.
-
-#include "bundle_adjustment_test_util.h"
-
-#ifndef CERES_NO_CXSPARSE
-
-namespace ceres {
-namespace internal {
-
-TEST_F(BundleAdjustmentTest,
-       IterativeSchur_CxSparse_ClusterJacobi_UserOrdering) {  // NOLINT
-  BundleAdjustmentProblem bundle_adjustment_problem;
-  Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
-  options->num_threads = 1;
-  options->linear_solver_type = ITERATIVE_SCHUR;
-  options->sparse_linear_algebra_library_type = CX_SPARSE;
-  options->preconditioner_type = CLUSTER_JACOBI;
-  if (kUserOrdering) {
-    options->linear_solver_ordering.reset();
-  }
-  Problem* problem = bundle_adjustment_problem.mutable_problem();
-  RunSolverForConfigAndExpectResidualsMatch(*options, problem);
-}
-
-}  // namespace internal
-}  // namespace ceres
-
-#endif  // CERES_NO_CXSPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_cxsparse_clustjacobi_user_threads_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_cxsparse_clustjacobi_user_threads_test.cc
deleted file mode 100644
index b98933d..0000000
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_cxsparse_clustjacobi_user_threads_test.cc
+++ /dev/null
@@ -1,65 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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 Google Inc. 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 IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// ========================================
-//
-// This file is generated using generate_bundle_adjustment_tests.py.
-
-#include "bundle_adjustment_test_util.h"
-
-#ifndef CERES_NO_CXSPARSE
-#ifndef CERES_NO_THREADS
-
-namespace ceres {
-namespace internal {
-
-TEST_F(BundleAdjustmentTest,
-       IterativeSchur_CxSparse_ClusterJacobi_UserOrdering_Threads) {  // NOLINT
-  BundleAdjustmentProblem bundle_adjustment_problem;
-  Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
-  options->num_threads = 4;
-  options->linear_solver_type = ITERATIVE_SCHUR;
-  options->sparse_linear_algebra_library_type = CX_SPARSE;
-  options->preconditioner_type = CLUSTER_JACOBI;
-  if (kUserOrdering) {
-    options->linear_solver_ordering.reset();
-  }
-  Problem* problem = bundle_adjustment_problem.mutable_problem();
-  RunSolverForConfigAndExpectResidualsMatch(*options, problem);
-}
-
-}  // namespace internal
-}  // namespace ceres
-
-#endif  // CERES_NO_THREADS
-#endif  // CERES_NO_CXSPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_cxsparse_clusttri_auto_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_cxsparse_clusttri_auto_test.cc
deleted file mode 100644
index f29e939..0000000
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_cxsparse_clusttri_auto_test.cc
+++ /dev/null
@@ -1,63 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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 Google Inc. 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 IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// ========================================
-//
-// This file is generated using generate_bundle_adjustment_tests.py.
-
-#include "bundle_adjustment_test_util.h"
-
-#ifndef CERES_NO_CXSPARSE
-
-namespace ceres {
-namespace internal {
-
-TEST_F(BundleAdjustmentTest,
-       IterativeSchur_CxSparse_ClusterTridiagonal_AutomaticOrdering) {  // NOLINT
-  BundleAdjustmentProblem bundle_adjustment_problem;
-  Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
-  options->num_threads = 1;
-  options->linear_solver_type = ITERATIVE_SCHUR;
-  options->sparse_linear_algebra_library_type = CX_SPARSE;
-  options->preconditioner_type = CLUSTER_TRIDIAGONAL;
-  if (kAutomaticOrdering) {
-    options->linear_solver_ordering.reset();
-  }
-  Problem* problem = bundle_adjustment_problem.mutable_problem();
-  RunSolverForConfigAndExpectResidualsMatch(*options, problem);
-}
-
-}  // namespace internal
-}  // namespace ceres
-
-#endif  // CERES_NO_CXSPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_cxsparse_clusttri_auto_threads_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_cxsparse_clusttri_auto_threads_test.cc
deleted file mode 100644
index b45d65c..0000000
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_cxsparse_clusttri_auto_threads_test.cc
+++ /dev/null
@@ -1,65 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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 Google Inc. 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 IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// ========================================
-//
-// This file is generated using generate_bundle_adjustment_tests.py.
-
-#include "bundle_adjustment_test_util.h"
-
-#ifndef CERES_NO_CXSPARSE
-#ifndef CERES_NO_THREADS
-
-namespace ceres {
-namespace internal {
-
-TEST_F(BundleAdjustmentTest,
-       IterativeSchur_CxSparse_ClusterTridiagonal_AutomaticOrdering_Threads) {  // NOLINT
-  BundleAdjustmentProblem bundle_adjustment_problem;
-  Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
-  options->num_threads = 4;
-  options->linear_solver_type = ITERATIVE_SCHUR;
-  options->sparse_linear_algebra_library_type = CX_SPARSE;
-  options->preconditioner_type = CLUSTER_TRIDIAGONAL;
-  if (kAutomaticOrdering) {
-    options->linear_solver_ordering.reset();
-  }
-  Problem* problem = bundle_adjustment_problem.mutable_problem();
-  RunSolverForConfigAndExpectResidualsMatch(*options, problem);
-}
-
-}  // namespace internal
-}  // namespace ceres
-
-#endif  // CERES_NO_THREADS
-#endif  // CERES_NO_CXSPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_cxsparse_clusttri_user_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_cxsparse_clusttri_user_test.cc
deleted file mode 100644
index 35a68e8..0000000
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_cxsparse_clusttri_user_test.cc
+++ /dev/null
@@ -1,63 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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 Google Inc. 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 IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// ========================================
-//
-// This file is generated using generate_bundle_adjustment_tests.py.
-
-#include "bundle_adjustment_test_util.h"
-
-#ifndef CERES_NO_CXSPARSE
-
-namespace ceres {
-namespace internal {
-
-TEST_F(BundleAdjustmentTest,
-       IterativeSchur_CxSparse_ClusterTridiagonal_UserOrdering) {  // NOLINT
-  BundleAdjustmentProblem bundle_adjustment_problem;
-  Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
-  options->num_threads = 1;
-  options->linear_solver_type = ITERATIVE_SCHUR;
-  options->sparse_linear_algebra_library_type = CX_SPARSE;
-  options->preconditioner_type = CLUSTER_TRIDIAGONAL;
-  if (kUserOrdering) {
-    options->linear_solver_ordering.reset();
-  }
-  Problem* problem = bundle_adjustment_problem.mutable_problem();
-  RunSolverForConfigAndExpectResidualsMatch(*options, problem);
-}
-
-}  // namespace internal
-}  // namespace ceres
-
-#endif  // CERES_NO_CXSPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_cxsparse_clusttri_user_threads_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_cxsparse_clusttri_user_threads_test.cc
deleted file mode 100644
index ac3dc25..0000000
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_cxsparse_clusttri_user_threads_test.cc
+++ /dev/null
@@ -1,65 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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 Google Inc. 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 IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// ========================================
-//
-// This file is generated using generate_bundle_adjustment_tests.py.
-
-#include "bundle_adjustment_test_util.h"
-
-#ifndef CERES_NO_CXSPARSE
-#ifndef CERES_NO_THREADS
-
-namespace ceres {
-namespace internal {
-
-TEST_F(BundleAdjustmentTest,
-       IterativeSchur_CxSparse_ClusterTridiagonal_UserOrdering_Threads) {  // NOLINT
-  BundleAdjustmentProblem bundle_adjustment_problem;
-  Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
-  options->num_threads = 4;
-  options->linear_solver_type = ITERATIVE_SCHUR;
-  options->sparse_linear_algebra_library_type = CX_SPARSE;
-  options->preconditioner_type = CLUSTER_TRIDIAGONAL;
-  if (kUserOrdering) {
-    options->linear_solver_ordering.reset();
-  }
-  Problem* problem = bundle_adjustment_problem.mutable_problem();
-  RunSolverForConfigAndExpectResidualsMatch(*options, problem);
-}
-
-}  // namespace internal
-}  // namespace ceres
-
-#endif  // CERES_NO_THREADS
-#endif  // CERES_NO_CXSPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_eigensparse_clustjacobi_auto_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_eigensparse_clustjacobi_auto_test.cc
index 92b3021..c1ceb9f 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_eigensparse_clustjacobi_auto_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_eigensparse_clustjacobi_auto_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,29 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifdef CERES_USE_EIGEN_SPARSE
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        IterativeSchur_EigenSparse_ClusterJacobi_AutomaticOrdering) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 1;
   options->linear_solver_type = ITERATIVE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = EIGEN_SPARSE;
   options->preconditioner_type = CLUSTER_JACOBI;
   if (kAutomaticOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_USE_EIGEN_SPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_eigensparse_clustjacobi_auto_threads_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_eigensparse_clustjacobi_auto_threads_test.cc
index dc72edf..35760db 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_eigensparse_clustjacobi_auto_threads_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_eigensparse_clustjacobi_auto_threads_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,31 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifdef CERES_USE_EIGEN_SPARSE
-#ifndef CERES_NO_THREADS
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        IterativeSchur_EigenSparse_ClusterJacobi_AutomaticOrdering_Threads) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 4;
   options->linear_solver_type = ITERATIVE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = EIGEN_SPARSE;
   options->preconditioner_type = CLUSTER_JACOBI;
   if (kAutomaticOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
-#endif  // CERES_NO_THREADS
 #endif  // CERES_USE_EIGEN_SPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_eigensparse_clustjacobi_user_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_eigensparse_clustjacobi_user_test.cc
index 576b8be..6b35e6b 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_eigensparse_clustjacobi_user_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_eigensparse_clustjacobi_user_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,29 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifdef CERES_USE_EIGEN_SPARSE
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        IterativeSchur_EigenSparse_ClusterJacobi_UserOrdering) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 1;
   options->linear_solver_type = ITERATIVE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = EIGEN_SPARSE;
   options->preconditioner_type = CLUSTER_JACOBI;
   if (kUserOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_USE_EIGEN_SPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_eigensparse_clustjacobi_user_threads_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_eigensparse_clustjacobi_user_threads_test.cc
index 786c19a..9b36562 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_eigensparse_clustjacobi_user_threads_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_eigensparse_clustjacobi_user_threads_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,31 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifdef CERES_USE_EIGEN_SPARSE
-#ifndef CERES_NO_THREADS
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        IterativeSchur_EigenSparse_ClusterJacobi_UserOrdering_Threads) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 4;
   options->linear_solver_type = ITERATIVE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = EIGEN_SPARSE;
   options->preconditioner_type = CLUSTER_JACOBI;
   if (kUserOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
-#endif  // CERES_NO_THREADS
 #endif  // CERES_USE_EIGEN_SPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_eigensparse_clusttri_auto_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_eigensparse_clusttri_auto_test.cc
index cb3c958..a62c8ba 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_eigensparse_clusttri_auto_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_eigensparse_clusttri_auto_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,29 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifdef CERES_USE_EIGEN_SPARSE
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        IterativeSchur_EigenSparse_ClusterTridiagonal_AutomaticOrdering) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 1;
   options->linear_solver_type = ITERATIVE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = EIGEN_SPARSE;
   options->preconditioner_type = CLUSTER_TRIDIAGONAL;
   if (kAutomaticOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_USE_EIGEN_SPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_eigensparse_clusttri_auto_threads_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_eigensparse_clusttri_auto_threads_test.cc
index 3851bfc..f306f81 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_eigensparse_clusttri_auto_threads_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_eigensparse_clusttri_auto_threads_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,31 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifdef CERES_USE_EIGEN_SPARSE
-#ifndef CERES_NO_THREADS
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        IterativeSchur_EigenSparse_ClusterTridiagonal_AutomaticOrdering_Threads) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 4;
   options->linear_solver_type = ITERATIVE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = EIGEN_SPARSE;
   options->preconditioner_type = CLUSTER_TRIDIAGONAL;
   if (kAutomaticOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
-#endif  // CERES_NO_THREADS
 #endif  // CERES_USE_EIGEN_SPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_eigensparse_clusttri_user_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_eigensparse_clusttri_user_test.cc
index 0df51c2..62d60b1 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_eigensparse_clusttri_user_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_eigensparse_clusttri_user_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,29 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifdef CERES_USE_EIGEN_SPARSE
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        IterativeSchur_EigenSparse_ClusterTridiagonal_UserOrdering) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 1;
   options->linear_solver_type = ITERATIVE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = EIGEN_SPARSE;
   options->preconditioner_type = CLUSTER_TRIDIAGONAL;
   if (kUserOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_USE_EIGEN_SPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_eigensparse_clusttri_user_threads_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_eigensparse_clusttri_user_threads_test.cc
index 33c6bb8..223a76a 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_eigensparse_clusttri_user_threads_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_eigensparse_clusttri_user_threads_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,31 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifdef CERES_USE_EIGEN_SPARSE
-#ifndef CERES_NO_THREADS
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        IterativeSchur_EigenSparse_ClusterTridiagonal_UserOrdering_Threads) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 4;
   options->linear_solver_type = ITERATIVE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = EIGEN_SPARSE;
   options->preconditioner_type = CLUSTER_TRIDIAGONAL;
   if (kUserOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
-#endif  // CERES_NO_THREADS
 #endif  // CERES_USE_EIGEN_SPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_jacobi_auto_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_jacobi_auto_test.cc
index 78d8d44..8e9afa1 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_jacobi_auto_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_jacobi_auto_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,25 +35,27 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        IterativeSchur_Jacobi_AutomaticOrdering) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 1;
   options->linear_solver_type = ITERATIVE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = NO_SPARSE;
   options->preconditioner_type = JACOBI;
   if (kAutomaticOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_jacobi_auto_threads_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_jacobi_auto_threads_test.cc
index 98fa68b..433bf76 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_jacobi_auto_threads_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_jacobi_auto_threads_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,29 +35,27 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
-#ifndef CERES_NO_THREADS
-
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        IterativeSchur_Jacobi_AutomaticOrdering_Threads) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 4;
   options->linear_solver_type = ITERATIVE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = NO_SPARSE;
   options->preconditioner_type = JACOBI;
   if (kAutomaticOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
-
-#endif  // CERES_NO_THREADS
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_jacobi_user_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_jacobi_user_test.cc
index 07fa0a0..8e740da 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_jacobi_user_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_jacobi_user_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,25 +35,27 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        IterativeSchur_Jacobi_UserOrdering) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 1;
   options->linear_solver_type = ITERATIVE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = NO_SPARSE;
   options->preconditioner_type = JACOBI;
   if (kUserOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_jacobi_user_threads_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_jacobi_user_threads_test.cc
index 3244173..705bfe2 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_jacobi_user_threads_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_jacobi_user_threads_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,29 +35,27 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
-#ifndef CERES_NO_THREADS
-
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        IterativeSchur_Jacobi_UserOrdering_Threads) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 4;
   options->linear_solver_type = ITERATIVE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = NO_SPARSE;
   options->preconditioner_type = JACOBI;
   if (kUserOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
-
-#endif  // CERES_NO_THREADS
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_schurjacobi_auto_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_schurjacobi_auto_test.cc
index 61f2c51..6b46f3d 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_schurjacobi_auto_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_schurjacobi_auto_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,25 +35,27 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        IterativeSchur_SchurJacobi_AutomaticOrdering) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 1;
   options->linear_solver_type = ITERATIVE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = NO_SPARSE;
   options->preconditioner_type = SCHUR_JACOBI;
   if (kAutomaticOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_schurjacobi_auto_threads_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_schurjacobi_auto_threads_test.cc
index 3bfb35c..a74efa8 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_schurjacobi_auto_threads_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_schurjacobi_auto_threads_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,29 +35,27 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
-#ifndef CERES_NO_THREADS
-
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        IterativeSchur_SchurJacobi_AutomaticOrdering_Threads) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 4;
   options->linear_solver_type = ITERATIVE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = NO_SPARSE;
   options->preconditioner_type = SCHUR_JACOBI;
   if (kAutomaticOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
-
-#endif  // CERES_NO_THREADS
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_schurjacobi_user_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_schurjacobi_user_test.cc
index f84b561..d0fa244 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_schurjacobi_user_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_schurjacobi_user_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,25 +35,27 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        IterativeSchur_SchurJacobi_UserOrdering) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 1;
   options->linear_solver_type = ITERATIVE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = NO_SPARSE;
   options->preconditioner_type = SCHUR_JACOBI;
   if (kUserOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_schurjacobi_user_threads_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_schurjacobi_user_threads_test.cc
index 9206290..e5418c9 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_schurjacobi_user_threads_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_schurjacobi_user_threads_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,29 +35,27 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
-#ifndef CERES_NO_THREADS
-
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        IterativeSchur_SchurJacobi_UserOrdering_Threads) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 4;
   options->linear_solver_type = ITERATIVE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = NO_SPARSE;
   options->preconditioner_type = SCHUR_JACOBI;
   if (kUserOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
-
-#endif  // CERES_NO_THREADS
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_spse_auto_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_spse_auto_test.cc
new file mode 100644
index 0000000..1287a61
--- /dev/null
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_spse_auto_test.cc
@@ -0,0 +1,61 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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 IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// ========================================
+//
+// This file is generated using generate_bundle_adjustment_tests.py.
+
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
+
+namespace ceres::internal {
+
+TEST_F(BundleAdjustmentTest,
+       IterativeSchur_SchurPowerSeriesExpansion_AutomaticOrdering) {  // NOLINT
+  BundleAdjustmentProblem bundle_adjustment_problem;
+  Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
+  options->num_threads = 1;
+  options->linear_solver_type = ITERATIVE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
+  options->sparse_linear_algebra_library_type = NO_SPARSE;
+  options->preconditioner_type = SCHUR_POWER_SERIES_EXPANSION;
+  if (kAutomaticOrdering) {
+    options->linear_solver_ordering = nullptr;
+  }
+  Problem* problem = bundle_adjustment_problem.mutable_problem();
+  RunSolverForConfigAndExpectResidualsMatch(*options, problem);
+}
+
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_spse_auto_threads_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_spse_auto_threads_test.cc
new file mode 100644
index 0000000..739d7bf
--- /dev/null
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_spse_auto_threads_test.cc
@@ -0,0 +1,61 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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 IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// ========================================
+//
+// This file is generated using generate_bundle_adjustment_tests.py.
+
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
+
+namespace ceres::internal {
+
+TEST_F(BundleAdjustmentTest,
+       IterativeSchur_SchurPowerSeriesExpansion_AutomaticOrdering_Threads) {  // NOLINT
+  BundleAdjustmentProblem bundle_adjustment_problem;
+  Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
+  options->num_threads = 4;
+  options->linear_solver_type = ITERATIVE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
+  options->sparse_linear_algebra_library_type = NO_SPARSE;
+  options->preconditioner_type = SCHUR_POWER_SERIES_EXPANSION;
+  if (kAutomaticOrdering) {
+    options->linear_solver_ordering = nullptr;
+  }
+  Problem* problem = bundle_adjustment_problem.mutable_problem();
+  RunSolverForConfigAndExpectResidualsMatch(*options, problem);
+}
+
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_spse_user_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_spse_user_test.cc
new file mode 100644
index 0000000..38b8d36
--- /dev/null
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_spse_user_test.cc
@@ -0,0 +1,61 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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 IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// ========================================
+//
+// This file is generated using generate_bundle_adjustment_tests.py.
+
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
+
+namespace ceres::internal {
+
+TEST_F(BundleAdjustmentTest,
+       IterativeSchur_SchurPowerSeriesExpansion_UserOrdering) {  // NOLINT
+  BundleAdjustmentProblem bundle_adjustment_problem;
+  Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
+  options->num_threads = 1;
+  options->linear_solver_type = ITERATIVE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
+  options->sparse_linear_algebra_library_type = NO_SPARSE;
+  options->preconditioner_type = SCHUR_POWER_SERIES_EXPANSION;
+  if (kUserOrdering) {
+    options->linear_solver_ordering = nullptr;
+  }
+  Problem* problem = bundle_adjustment_problem.mutable_problem();
+  RunSolverForConfigAndExpectResidualsMatch(*options, problem);
+}
+
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_spse_user_threads_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_spse_user_threads_test.cc
new file mode 100644
index 0000000..2a715cc
--- /dev/null
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_spse_user_threads_test.cc
@@ -0,0 +1,61 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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 IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
+// ========================================
+//
+// This file is generated using generate_bundle_adjustment_tests.py.
+
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
+
+namespace ceres::internal {
+
+TEST_F(BundleAdjustmentTest,
+       IterativeSchur_SchurPowerSeriesExpansion_UserOrdering_Threads) {  // NOLINT
+  BundleAdjustmentProblem bundle_adjustment_problem;
+  Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
+  options->num_threads = 4;
+  options->linear_solver_type = ITERATIVE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
+  options->sparse_linear_algebra_library_type = NO_SPARSE;
+  options->preconditioner_type = SCHUR_POWER_SERIES_EXPANSION;
+  if (kUserOrdering) {
+    options->linear_solver_ordering = nullptr;
+  }
+  Problem* problem = bundle_adjustment_problem.mutable_problem();
+  RunSolverForConfigAndExpectResidualsMatch(*options, problem);
+}
+
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_suitesparse_clustjacobi_auto_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_suitesparse_clustjacobi_auto_test.cc
index ec63ae1..d25a7e7 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_suitesparse_clustjacobi_auto_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_suitesparse_clustjacobi_auto_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,29 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifndef CERES_NO_SUITESPARSE
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        IterativeSchur_SuiteSparse_ClusterJacobi_AutomaticOrdering) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 1;
   options->linear_solver_type = ITERATIVE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = SUITE_SPARSE;
   options->preconditioner_type = CLUSTER_JACOBI;
   if (kAutomaticOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_NO_SUITESPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_suitesparse_clustjacobi_auto_threads_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_suitesparse_clustjacobi_auto_threads_test.cc
index de40b81..38d65b1 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_suitesparse_clustjacobi_auto_threads_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_suitesparse_clustjacobi_auto_threads_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,31 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifndef CERES_NO_SUITESPARSE
-#ifndef CERES_NO_THREADS
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        IterativeSchur_SuiteSparse_ClusterJacobi_AutomaticOrdering_Threads) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 4;
   options->linear_solver_type = ITERATIVE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = SUITE_SPARSE;
   options->preconditioner_type = CLUSTER_JACOBI;
   if (kAutomaticOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
-#endif  // CERES_NO_THREADS
 #endif  // CERES_NO_SUITESPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_suitesparse_clustjacobi_user_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_suitesparse_clustjacobi_user_test.cc
index 5406840..40b7451 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_suitesparse_clustjacobi_user_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_suitesparse_clustjacobi_user_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,29 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifndef CERES_NO_SUITESPARSE
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        IterativeSchur_SuiteSparse_ClusterJacobi_UserOrdering) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 1;
   options->linear_solver_type = ITERATIVE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = SUITE_SPARSE;
   options->preconditioner_type = CLUSTER_JACOBI;
   if (kUserOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_NO_SUITESPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_suitesparse_clustjacobi_user_threads_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_suitesparse_clustjacobi_user_threads_test.cc
index 9e8aeec..d12b524 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_suitesparse_clustjacobi_user_threads_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_suitesparse_clustjacobi_user_threads_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,31 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifndef CERES_NO_SUITESPARSE
-#ifndef CERES_NO_THREADS
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        IterativeSchur_SuiteSparse_ClusterJacobi_UserOrdering_Threads) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 4;
   options->linear_solver_type = ITERATIVE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = SUITE_SPARSE;
   options->preconditioner_type = CLUSTER_JACOBI;
   if (kUserOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
-#endif  // CERES_NO_THREADS
 #endif  // CERES_NO_SUITESPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_suitesparse_clusttri_auto_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_suitesparse_clusttri_auto_test.cc
index fc80339..7206132 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_suitesparse_clusttri_auto_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_suitesparse_clusttri_auto_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,29 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifndef CERES_NO_SUITESPARSE
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        IterativeSchur_SuiteSparse_ClusterTridiagonal_AutomaticOrdering) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 1;
   options->linear_solver_type = ITERATIVE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = SUITE_SPARSE;
   options->preconditioner_type = CLUSTER_TRIDIAGONAL;
   if (kAutomaticOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_NO_SUITESPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_suitesparse_clusttri_auto_threads_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_suitesparse_clusttri_auto_threads_test.cc
index f4962ab..61efa20 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_suitesparse_clusttri_auto_threads_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_suitesparse_clusttri_auto_threads_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,31 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifndef CERES_NO_SUITESPARSE
-#ifndef CERES_NO_THREADS
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        IterativeSchur_SuiteSparse_ClusterTridiagonal_AutomaticOrdering_Threads) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 4;
   options->linear_solver_type = ITERATIVE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = SUITE_SPARSE;
   options->preconditioner_type = CLUSTER_TRIDIAGONAL;
   if (kAutomaticOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
-#endif  // CERES_NO_THREADS
 #endif  // CERES_NO_SUITESPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_suitesparse_clusttri_user_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_suitesparse_clusttri_user_test.cc
index 7f99834..b750cbb 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_suitesparse_clusttri_user_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_suitesparse_clusttri_user_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,29 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifndef CERES_NO_SUITESPARSE
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        IterativeSchur_SuiteSparse_ClusterTridiagonal_UserOrdering) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 1;
   options->linear_solver_type = ITERATIVE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = SUITE_SPARSE;
   options->preconditioner_type = CLUSTER_TRIDIAGONAL;
   if (kUserOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_NO_SUITESPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_suitesparse_clusttri_user_threads_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_suitesparse_clusttri_user_threads_test.cc
index 041b77a..f704e32 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_suitesparse_clusttri_user_threads_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_iterschur_suitesparse_clusttri_user_threads_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,31 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifndef CERES_NO_SUITESPARSE
-#ifndef CERES_NO_THREADS
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        IterativeSchur_SuiteSparse_ClusterTridiagonal_UserOrdering_Threads) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 4;
   options->linear_solver_type = ITERATIVE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = SUITE_SPARSE;
   options->preconditioner_type = CLUSTER_TRIDIAGONAL;
   if (kUserOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
-#endif  // CERES_NO_THREADS
 #endif  // CERES_NO_SUITESPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_acceleratesparse_auto_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_acceleratesparse_auto_test.cc
index 95d6259..05caf3c 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_acceleratesparse_auto_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_acceleratesparse_auto_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,29 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifndef CERES_NO_ACCELERATE_SPARSE
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        SparseNormalCholesky_AccelerateSparse_AutomaticOrdering) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 1;
   options->linear_solver_type = SPARSE_NORMAL_CHOLESKY;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = ACCELERATE_SPARSE;
   options->preconditioner_type = IDENTITY;
   if (kAutomaticOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_NO_ACCELERATE_SPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_acceleratesparse_auto_threads_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_acceleratesparse_auto_threads_test.cc
index cf525bc..bfd1d4b 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_acceleratesparse_auto_threads_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_acceleratesparse_auto_threads_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,31 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifndef CERES_NO_ACCELERATE_SPARSE
-#ifndef CERES_NO_THREADS
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        SparseNormalCholesky_AccelerateSparse_AutomaticOrdering_Threads) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 4;
   options->linear_solver_type = SPARSE_NORMAL_CHOLESKY;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = ACCELERATE_SPARSE;
   options->preconditioner_type = IDENTITY;
   if (kAutomaticOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
-#endif  // CERES_NO_THREADS
 #endif  // CERES_NO_ACCELERATE_SPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_acceleratesparse_user_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_acceleratesparse_user_test.cc
index 01c86f8..0017874 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_acceleratesparse_user_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_acceleratesparse_user_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,29 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifndef CERES_NO_ACCELERATE_SPARSE
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        SparseNormalCholesky_AccelerateSparse_UserOrdering) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 1;
   options->linear_solver_type = SPARSE_NORMAL_CHOLESKY;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = ACCELERATE_SPARSE;
   options->preconditioner_type = IDENTITY;
   if (kUserOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_NO_ACCELERATE_SPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_acceleratesparse_user_threads_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_acceleratesparse_user_threads_test.cc
index b562b99..7bb7f0b 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_acceleratesparse_user_threads_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_acceleratesparse_user_threads_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,31 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifndef CERES_NO_ACCELERATE_SPARSE
-#ifndef CERES_NO_THREADS
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        SparseNormalCholesky_AccelerateSparse_UserOrdering_Threads) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 4;
   options->linear_solver_type = SPARSE_NORMAL_CHOLESKY;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = ACCELERATE_SPARSE;
   options->preconditioner_type = IDENTITY;
   if (kUserOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
-#endif  // CERES_NO_THREADS
 #endif  // CERES_NO_ACCELERATE_SPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_cxsparse_auto_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_cxsparse_auto_test.cc
deleted file mode 100644
index aa0dc2c..0000000
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_cxsparse_auto_test.cc
+++ /dev/null
@@ -1,63 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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 Google Inc. 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 IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// ========================================
-//
-// This file is generated using generate_bundle_adjustment_tests.py.
-
-#include "bundle_adjustment_test_util.h"
-
-#ifndef CERES_NO_CXSPARSE
-
-namespace ceres {
-namespace internal {
-
-TEST_F(BundleAdjustmentTest,
-       SparseNormalCholesky_CxSparse_AutomaticOrdering) {  // NOLINT
-  BundleAdjustmentProblem bundle_adjustment_problem;
-  Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
-  options->num_threads = 1;
-  options->linear_solver_type = SPARSE_NORMAL_CHOLESKY;
-  options->sparse_linear_algebra_library_type = CX_SPARSE;
-  options->preconditioner_type = IDENTITY;
-  if (kAutomaticOrdering) {
-    options->linear_solver_ordering.reset();
-  }
-  Problem* problem = bundle_adjustment_problem.mutable_problem();
-  RunSolverForConfigAndExpectResidualsMatch(*options, problem);
-}
-
-}  // namespace internal
-}  // namespace ceres
-
-#endif  // CERES_NO_CXSPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_cxsparse_auto_threads_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_cxsparse_auto_threads_test.cc
deleted file mode 100644
index 367c4fb..0000000
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_cxsparse_auto_threads_test.cc
+++ /dev/null
@@ -1,65 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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 Google Inc. 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 IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// ========================================
-//
-// This file is generated using generate_bundle_adjustment_tests.py.
-
-#include "bundle_adjustment_test_util.h"
-
-#ifndef CERES_NO_CXSPARSE
-#ifndef CERES_NO_THREADS
-
-namespace ceres {
-namespace internal {
-
-TEST_F(BundleAdjustmentTest,
-       SparseNormalCholesky_CxSparse_AutomaticOrdering_Threads) {  // NOLINT
-  BundleAdjustmentProblem bundle_adjustment_problem;
-  Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
-  options->num_threads = 4;
-  options->linear_solver_type = SPARSE_NORMAL_CHOLESKY;
-  options->sparse_linear_algebra_library_type = CX_SPARSE;
-  options->preconditioner_type = IDENTITY;
-  if (kAutomaticOrdering) {
-    options->linear_solver_ordering.reset();
-  }
-  Problem* problem = bundle_adjustment_problem.mutable_problem();
-  RunSolverForConfigAndExpectResidualsMatch(*options, problem);
-}
-
-}  // namespace internal
-}  // namespace ceres
-
-#endif  // CERES_NO_THREADS
-#endif  // CERES_NO_CXSPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_cxsparse_user_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_cxsparse_user_test.cc
deleted file mode 100644
index 523e031..0000000
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_cxsparse_user_test.cc
+++ /dev/null
@@ -1,63 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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 Google Inc. 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 IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// ========================================
-//
-// This file is generated using generate_bundle_adjustment_tests.py.
-
-#include "bundle_adjustment_test_util.h"
-
-#ifndef CERES_NO_CXSPARSE
-
-namespace ceres {
-namespace internal {
-
-TEST_F(BundleAdjustmentTest,
-       SparseNormalCholesky_CxSparse_UserOrdering) {  // NOLINT
-  BundleAdjustmentProblem bundle_adjustment_problem;
-  Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
-  options->num_threads = 1;
-  options->linear_solver_type = SPARSE_NORMAL_CHOLESKY;
-  options->sparse_linear_algebra_library_type = CX_SPARSE;
-  options->preconditioner_type = IDENTITY;
-  if (kUserOrdering) {
-    options->linear_solver_ordering.reset();
-  }
-  Problem* problem = bundle_adjustment_problem.mutable_problem();
-  RunSolverForConfigAndExpectResidualsMatch(*options, problem);
-}
-
-}  // namespace internal
-}  // namespace ceres
-
-#endif  // CERES_NO_CXSPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_cxsparse_user_threads_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_cxsparse_user_threads_test.cc
deleted file mode 100644
index e1923ee..0000000
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_cxsparse_user_threads_test.cc
+++ /dev/null
@@ -1,65 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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 Google Inc. 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 IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// ========================================
-//
-// This file is generated using generate_bundle_adjustment_tests.py.
-
-#include "bundle_adjustment_test_util.h"
-
-#ifndef CERES_NO_CXSPARSE
-#ifndef CERES_NO_THREADS
-
-namespace ceres {
-namespace internal {
-
-TEST_F(BundleAdjustmentTest,
-       SparseNormalCholesky_CxSparse_UserOrdering_Threads) {  // NOLINT
-  BundleAdjustmentProblem bundle_adjustment_problem;
-  Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
-  options->num_threads = 4;
-  options->linear_solver_type = SPARSE_NORMAL_CHOLESKY;
-  options->sparse_linear_algebra_library_type = CX_SPARSE;
-  options->preconditioner_type = IDENTITY;
-  if (kUserOrdering) {
-    options->linear_solver_ordering.reset();
-  }
-  Problem* problem = bundle_adjustment_problem.mutable_problem();
-  RunSolverForConfigAndExpectResidualsMatch(*options, problem);
-}
-
-}  // namespace internal
-}  // namespace ceres
-
-#endif  // CERES_NO_THREADS
-#endif  // CERES_NO_CXSPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_eigensparse_auto_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_eigensparse_auto_test.cc
index e9202e9..a15553c 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_eigensparse_auto_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_eigensparse_auto_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,29 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifdef CERES_USE_EIGEN_SPARSE
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        SparseNormalCholesky_EigenSparse_AutomaticOrdering) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 1;
   options->linear_solver_type = SPARSE_NORMAL_CHOLESKY;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = EIGEN_SPARSE;
   options->preconditioner_type = IDENTITY;
   if (kAutomaticOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_USE_EIGEN_SPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_eigensparse_auto_threads_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_eigensparse_auto_threads_test.cc
index 769e3c8..2134295 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_eigensparse_auto_threads_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_eigensparse_auto_threads_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,31 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifdef CERES_USE_EIGEN_SPARSE
-#ifndef CERES_NO_THREADS
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        SparseNormalCholesky_EigenSparse_AutomaticOrdering_Threads) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 4;
   options->linear_solver_type = SPARSE_NORMAL_CHOLESKY;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = EIGEN_SPARSE;
   options->preconditioner_type = IDENTITY;
   if (kAutomaticOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
-#endif  // CERES_NO_THREADS
 #endif  // CERES_USE_EIGEN_SPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_eigensparse_user_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_eigensparse_user_test.cc
index 87763c5..de00ccb 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_eigensparse_user_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_eigensparse_user_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,29 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifdef CERES_USE_EIGEN_SPARSE
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        SparseNormalCholesky_EigenSparse_UserOrdering) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 1;
   options->linear_solver_type = SPARSE_NORMAL_CHOLESKY;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = EIGEN_SPARSE;
   options->preconditioner_type = IDENTITY;
   if (kUserOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_USE_EIGEN_SPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_eigensparse_user_threads_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_eigensparse_user_threads_test.cc
index 38e10d9..f4ad5e0 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_eigensparse_user_threads_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_eigensparse_user_threads_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,31 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifdef CERES_USE_EIGEN_SPARSE
-#ifndef CERES_NO_THREADS
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        SparseNormalCholesky_EigenSparse_UserOrdering_Threads) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 4;
   options->linear_solver_type = SPARSE_NORMAL_CHOLESKY;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = EIGEN_SPARSE;
   options->preconditioner_type = IDENTITY;
   if (kUserOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
-#endif  // CERES_NO_THREADS
 #endif  // CERES_USE_EIGEN_SPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_suitesparse_auto_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_suitesparse_auto_test.cc
index fd9b6e7..f72ca55 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_suitesparse_auto_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_suitesparse_auto_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,29 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifndef CERES_NO_SUITESPARSE
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        SparseNormalCholesky_SuiteSparse_AutomaticOrdering) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 1;
   options->linear_solver_type = SPARSE_NORMAL_CHOLESKY;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = SUITE_SPARSE;
   options->preconditioner_type = IDENTITY;
   if (kAutomaticOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_NO_SUITESPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_suitesparse_auto_threads_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_suitesparse_auto_threads_test.cc
index 476087b..d301e5e 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_suitesparse_auto_threads_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_suitesparse_auto_threads_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,31 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifndef CERES_NO_SUITESPARSE
-#ifndef CERES_NO_THREADS
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        SparseNormalCholesky_SuiteSparse_AutomaticOrdering_Threads) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 4;
   options->linear_solver_type = SPARSE_NORMAL_CHOLESKY;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = SUITE_SPARSE;
   options->preconditioner_type = IDENTITY;
   if (kAutomaticOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
-#endif  // CERES_NO_THREADS
 #endif  // CERES_NO_SUITESPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_suitesparse_user_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_suitesparse_user_test.cc
index be64ae8..db22d6c 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_suitesparse_user_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_suitesparse_user_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,29 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifndef CERES_NO_SUITESPARSE
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        SparseNormalCholesky_SuiteSparse_UserOrdering) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 1;
   options->linear_solver_type = SPARSE_NORMAL_CHOLESKY;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = SUITE_SPARSE;
   options->preconditioner_type = IDENTITY;
   if (kUserOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_NO_SUITESPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_suitesparse_user_threads_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_suitesparse_user_threads_test.cc
index d6a2653..8b97820 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_suitesparse_user_threads_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparsecholesky_suitesparse_user_threads_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,31 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifndef CERES_NO_SUITESPARSE
-#ifndef CERES_NO_THREADS
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        SparseNormalCholesky_SuiteSparse_UserOrdering_Threads) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 4;
   options->linear_solver_type = SPARSE_NORMAL_CHOLESKY;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = SUITE_SPARSE;
   options->preconditioner_type = IDENTITY;
   if (kUserOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
-#endif  // CERES_NO_THREADS
 #endif  // CERES_NO_SUITESPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_acceleratesparse_auto_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_acceleratesparse_auto_test.cc
index 923eca4..d4b8dd2 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_acceleratesparse_auto_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_acceleratesparse_auto_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,29 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifndef CERES_NO_ACCELERATE_SPARSE
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        SparseSchur_AccelerateSparse_AutomaticOrdering) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 1;
   options->linear_solver_type = SPARSE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = ACCELERATE_SPARSE;
   options->preconditioner_type = IDENTITY;
   if (kAutomaticOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_NO_ACCELERATE_SPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_acceleratesparse_auto_threads_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_acceleratesparse_auto_threads_test.cc
index 8b1a613..8f7aacf 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_acceleratesparse_auto_threads_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_acceleratesparse_auto_threads_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,31 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifndef CERES_NO_ACCELERATE_SPARSE
-#ifndef CERES_NO_THREADS
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        SparseSchur_AccelerateSparse_AutomaticOrdering_Threads) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 4;
   options->linear_solver_type = SPARSE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = ACCELERATE_SPARSE;
   options->preconditioner_type = IDENTITY;
   if (kAutomaticOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
-#endif  // CERES_NO_THREADS
 #endif  // CERES_NO_ACCELERATE_SPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_acceleratesparse_user_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_acceleratesparse_user_test.cc
index b107c68..257cf0d 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_acceleratesparse_user_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_acceleratesparse_user_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,29 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifndef CERES_NO_ACCELERATE_SPARSE
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        SparseSchur_AccelerateSparse_UserOrdering) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 1;
   options->linear_solver_type = SPARSE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = ACCELERATE_SPARSE;
   options->preconditioner_type = IDENTITY;
   if (kUserOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_NO_ACCELERATE_SPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_acceleratesparse_user_threads_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_acceleratesparse_user_threads_test.cc
index a765e8a..dea1a28 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_acceleratesparse_user_threads_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_acceleratesparse_user_threads_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,31 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifndef CERES_NO_ACCELERATE_SPARSE
-#ifndef CERES_NO_THREADS
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        SparseSchur_AccelerateSparse_UserOrdering_Threads) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 4;
   options->linear_solver_type = SPARSE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = ACCELERATE_SPARSE;
   options->preconditioner_type = IDENTITY;
   if (kUserOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
-#endif  // CERES_NO_THREADS
 #endif  // CERES_NO_ACCELERATE_SPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_cxsparse_auto_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_cxsparse_auto_test.cc
deleted file mode 100644
index 5f2d3d9..0000000
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_cxsparse_auto_test.cc
+++ /dev/null
@@ -1,63 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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 Google Inc. 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 IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// ========================================
-//
-// This file is generated using generate_bundle_adjustment_tests.py.
-
-#include "bundle_adjustment_test_util.h"
-
-#ifndef CERES_NO_CXSPARSE
-
-namespace ceres {
-namespace internal {
-
-TEST_F(BundleAdjustmentTest,
-       SparseSchur_CxSparse_AutomaticOrdering) {  // NOLINT
-  BundleAdjustmentProblem bundle_adjustment_problem;
-  Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
-  options->num_threads = 1;
-  options->linear_solver_type = SPARSE_SCHUR;
-  options->sparse_linear_algebra_library_type = CX_SPARSE;
-  options->preconditioner_type = IDENTITY;
-  if (kAutomaticOrdering) {
-    options->linear_solver_ordering.reset();
-  }
-  Problem* problem = bundle_adjustment_problem.mutable_problem();
-  RunSolverForConfigAndExpectResidualsMatch(*options, problem);
-}
-
-}  // namespace internal
-}  // namespace ceres
-
-#endif  // CERES_NO_CXSPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_cxsparse_auto_threads_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_cxsparse_auto_threads_test.cc
deleted file mode 100644
index 791e8af..0000000
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_cxsparse_auto_threads_test.cc
+++ /dev/null
@@ -1,65 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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 Google Inc. 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 IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// ========================================
-//
-// This file is generated using generate_bundle_adjustment_tests.py.
-
-#include "bundle_adjustment_test_util.h"
-
-#ifndef CERES_NO_CXSPARSE
-#ifndef CERES_NO_THREADS
-
-namespace ceres {
-namespace internal {
-
-TEST_F(BundleAdjustmentTest,
-       SparseSchur_CxSparse_AutomaticOrdering_Threads) {  // NOLINT
-  BundleAdjustmentProblem bundle_adjustment_problem;
-  Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
-  options->num_threads = 4;
-  options->linear_solver_type = SPARSE_SCHUR;
-  options->sparse_linear_algebra_library_type = CX_SPARSE;
-  options->preconditioner_type = IDENTITY;
-  if (kAutomaticOrdering) {
-    options->linear_solver_ordering.reset();
-  }
-  Problem* problem = bundle_adjustment_problem.mutable_problem();
-  RunSolverForConfigAndExpectResidualsMatch(*options, problem);
-}
-
-}  // namespace internal
-}  // namespace ceres
-
-#endif  // CERES_NO_THREADS
-#endif  // CERES_NO_CXSPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_cxsparse_user_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_cxsparse_user_test.cc
deleted file mode 100644
index 260d2d7..0000000
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_cxsparse_user_test.cc
+++ /dev/null
@@ -1,63 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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 Google Inc. 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 IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// ========================================
-//
-// This file is generated using generate_bundle_adjustment_tests.py.
-
-#include "bundle_adjustment_test_util.h"
-
-#ifndef CERES_NO_CXSPARSE
-
-namespace ceres {
-namespace internal {
-
-TEST_F(BundleAdjustmentTest,
-       SparseSchur_CxSparse_UserOrdering) {  // NOLINT
-  BundleAdjustmentProblem bundle_adjustment_problem;
-  Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
-  options->num_threads = 1;
-  options->linear_solver_type = SPARSE_SCHUR;
-  options->sparse_linear_algebra_library_type = CX_SPARSE;
-  options->preconditioner_type = IDENTITY;
-  if (kUserOrdering) {
-    options->linear_solver_ordering.reset();
-  }
-  Problem* problem = bundle_adjustment_problem.mutable_problem();
-  RunSolverForConfigAndExpectResidualsMatch(*options, problem);
-}
-
-}  // namespace internal
-}  // namespace ceres
-
-#endif  // CERES_NO_CXSPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_cxsparse_user_threads_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_cxsparse_user_threads_test.cc
deleted file mode 100644
index bf01577..0000000
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_cxsparse_user_threads_test.cc
+++ /dev/null
@@ -1,65 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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 Google Inc. 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 IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// THIS FILE IS AUTOGENERATED. DO NOT EDIT.
-// ========================================
-//
-// This file is generated using generate_bundle_adjustment_tests.py.
-
-#include "bundle_adjustment_test_util.h"
-
-#ifndef CERES_NO_CXSPARSE
-#ifndef CERES_NO_THREADS
-
-namespace ceres {
-namespace internal {
-
-TEST_F(BundleAdjustmentTest,
-       SparseSchur_CxSparse_UserOrdering_Threads) {  // NOLINT
-  BundleAdjustmentProblem bundle_adjustment_problem;
-  Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
-  options->num_threads = 4;
-  options->linear_solver_type = SPARSE_SCHUR;
-  options->sparse_linear_algebra_library_type = CX_SPARSE;
-  options->preconditioner_type = IDENTITY;
-  if (kUserOrdering) {
-    options->linear_solver_ordering.reset();
-  }
-  Problem* problem = bundle_adjustment_problem.mutable_problem();
-  RunSolverForConfigAndExpectResidualsMatch(*options, problem);
-}
-
-}  // namespace internal
-}  // namespace ceres
-
-#endif  // CERES_NO_THREADS
-#endif  // CERES_NO_CXSPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_eigensparse_auto_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_eigensparse_auto_test.cc
index eeac03c..bcc2cc4 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_eigensparse_auto_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_eigensparse_auto_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,29 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifdef CERES_USE_EIGEN_SPARSE
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        SparseSchur_EigenSparse_AutomaticOrdering) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 1;
   options->linear_solver_type = SPARSE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = EIGEN_SPARSE;
   options->preconditioner_type = IDENTITY;
   if (kAutomaticOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_USE_EIGEN_SPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_eigensparse_auto_threads_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_eigensparse_auto_threads_test.cc
index 86d4ce4..e70f9ee 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_eigensparse_auto_threads_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_eigensparse_auto_threads_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,31 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifdef CERES_USE_EIGEN_SPARSE
-#ifndef CERES_NO_THREADS
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        SparseSchur_EigenSparse_AutomaticOrdering_Threads) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 4;
   options->linear_solver_type = SPARSE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = EIGEN_SPARSE;
   options->preconditioner_type = IDENTITY;
   if (kAutomaticOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
-#endif  // CERES_NO_THREADS
 #endif  // CERES_USE_EIGEN_SPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_eigensparse_user_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_eigensparse_user_test.cc
index 434b466..cb408af 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_eigensparse_user_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_eigensparse_user_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,29 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifdef CERES_USE_EIGEN_SPARSE
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        SparseSchur_EigenSparse_UserOrdering) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 1;
   options->linear_solver_type = SPARSE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = EIGEN_SPARSE;
   options->preconditioner_type = IDENTITY;
   if (kUserOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_USE_EIGEN_SPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_eigensparse_user_threads_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_eigensparse_user_threads_test.cc
index db6e0cf..8902146 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_eigensparse_user_threads_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_eigensparse_user_threads_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,31 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifdef CERES_USE_EIGEN_SPARSE
-#ifndef CERES_NO_THREADS
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        SparseSchur_EigenSparse_UserOrdering_Threads) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 4;
   options->linear_solver_type = SPARSE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = EIGEN_SPARSE;
   options->preconditioner_type = IDENTITY;
   if (kUserOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
-#endif  // CERES_NO_THREADS
 #endif  // CERES_USE_EIGEN_SPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_suitesparse_auto_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_suitesparse_auto_test.cc
index 8dd0117..aaa38c0 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_suitesparse_auto_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_suitesparse_auto_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,29 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifndef CERES_NO_SUITESPARSE
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        SparseSchur_SuiteSparse_AutomaticOrdering) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 1;
   options->linear_solver_type = SPARSE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = SUITE_SPARSE;
   options->preconditioner_type = IDENTITY;
   if (kAutomaticOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_NO_SUITESPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_suitesparse_auto_threads_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_suitesparse_auto_threads_test.cc
index b497938..a3f4ad0 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_suitesparse_auto_threads_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_suitesparse_auto_threads_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,31 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifndef CERES_NO_SUITESPARSE
-#ifndef CERES_NO_THREADS
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        SparseSchur_SuiteSparse_AutomaticOrdering_Threads) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 4;
   options->linear_solver_type = SPARSE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = SUITE_SPARSE;
   options->preconditioner_type = IDENTITY;
   if (kAutomaticOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
-#endif  // CERES_NO_THREADS
 #endif  // CERES_NO_SUITESPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_suitesparse_user_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_suitesparse_user_test.cc
index 1a38e9e..53cad2d 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_suitesparse_user_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_suitesparse_user_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,29 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifndef CERES_NO_SUITESPARSE
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        SparseSchur_SuiteSparse_UserOrdering) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 1;
   options->linear_solver_type = SPARSE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = SUITE_SPARSE;
   options->preconditioner_type = IDENTITY;
   if (kUserOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_NO_SUITESPARSE
diff --git a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_suitesparse_user_threads_test.cc b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_suitesparse_user_threads_test.cc
index 05f28af..d23a277 100644
--- a/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_suitesparse_user_threads_test.cc
+++ b/third_party/ceres/internal/ceres/generated_bundle_adjustment_tests/ba_sparseschur_suitesparse_user_threads_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,31 +35,31 @@
 //
 // This file is generated using generate_bundle_adjustment_tests.py.
 
-#include "bundle_adjustment_test_util.h"
+#include "ceres/bundle_adjustment_test_util.h"
+#include "ceres/internal/config.h"
+#include "gtest/gtest.h"
 
 #ifndef CERES_NO_SUITESPARSE
-#ifndef CERES_NO_THREADS
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST_F(BundleAdjustmentTest,
        SparseSchur_SuiteSparse_UserOrdering_Threads) {  // NOLINT
   BundleAdjustmentProblem bundle_adjustment_problem;
   Solver::Options* options = bundle_adjustment_problem.mutable_solver_options();
+  options->eta = 0.01;
   options->num_threads = 4;
   options->linear_solver_type = SPARSE_SCHUR;
+  options->dense_linear_algebra_library_type = EIGEN;
   options->sparse_linear_algebra_library_type = SUITE_SPARSE;
   options->preconditioner_type = IDENTITY;
   if (kUserOrdering) {
-    options->linear_solver_ordering.reset();
+    options->linear_solver_ordering = nullptr;
   }
   Problem* problem = bundle_adjustment_problem.mutable_problem();
   RunSolverForConfigAndExpectResidualsMatch(*options, problem);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
-#endif  // CERES_NO_THREADS
 #endif  // CERES_NO_SUITESPARSE
diff --git a/third_party/ceres/internal/ceres/gmock/gmock.h b/third_party/ceres/internal/ceres/gmock/gmock.h
index baea10d..9bb49d0 100644
--- a/third_party/ceres/internal/ceres/gmock/gmock.h
+++ b/third_party/ceres/internal/ceres/gmock/gmock.h
@@ -34,19 +34,19 @@
 
 // GOOGLETEST_CM0002 DO NOT DELETE
 
-#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_H_
-#define GMOCK_INCLUDE_GMOCK_GMOCK_H_
+#ifndef GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_H_
+#define GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_H_
 
 // This file implements the following syntax:
 //
-//   ON_CALL(mock_object.Method(...))
+//   ON_CALL(mock_object, Method(...))
 //     .With(...) ?
 //     .WillByDefault(...);
 //
 // where With() is optional and WillByDefault() must appear exactly
 // once.
 //
-//   EXPECT_CALL(mock_object.Method(...))
+//   EXPECT_CALL(mock_object, Method(...))
 //     .With(...) ?
 //     .Times(...) ?
 //     .InSequence(...) *
@@ -88,12 +88,105 @@
 
 // Google Mock - a framework for writing C++ mock classes.
 //
-// This file implements some commonly used actions.
+// The ACTION* family of macros can be used in a namespace scope to
+// define custom actions easily.  The syntax:
+//
+//   ACTION(name) { statements; }
+//
+// will define an action with the given name that executes the
+// statements.  The value returned by the statements will be used as
+// the return value of the action.  Inside the statements, you can
+// refer to the K-th (0-based) argument of the mock function by
+// 'argK', and refer to its type by 'argK_type'.  For example:
+//
+//   ACTION(IncrementArg1) {
+//     arg1_type temp = arg1;
+//     return ++(*temp);
+//   }
+//
+// allows you to write
+//
+//   ...WillOnce(IncrementArg1());
+//
+// You can also refer to the entire argument tuple and its type by
+// 'args' and 'args_type', and refer to the mock function type and its
+// return type by 'function_type' and 'return_type'.
+//
+// Note that you don't need to specify the types of the mock function
+// arguments.  However rest assured that your code is still type-safe:
+// you'll get a compiler error if *arg1 doesn't support the ++
+// operator, or if the type of ++(*arg1) isn't compatible with the
+// mock function's return type, for example.
+//
+// Sometimes you'll want to parameterize the action.   For that you can use
+// another macro:
+//
+//   ACTION_P(name, param_name) { statements; }
+//
+// For example:
+//
+//   ACTION_P(Add, n) { return arg0 + n; }
+//
+// will allow you to write:
+//
+//   ...WillOnce(Add(5));
+//
+// Note that you don't need to provide the type of the parameter
+// either.  If you need to reference the type of a parameter named
+// 'foo', you can write 'foo_type'.  For example, in the body of
+// ACTION_P(Add, n) above, you can write 'n_type' to refer to the type
+// of 'n'.
+//
+// We also provide ACTION_P2, ACTION_P3, ..., up to ACTION_P10 to support
+// multi-parameter actions.
+//
+// For the purpose of typing, you can view
+//
+//   ACTION_Pk(Foo, p1, ..., pk) { ... }
+//
+// as shorthand for
+//
+//   template <typename p1_type, ..., typename pk_type>
+//   FooActionPk<p1_type, ..., pk_type> Foo(p1_type p1, ..., pk_type pk) { ... }
+//
+// In particular, you can provide the template type arguments
+// explicitly when invoking Foo(), as in Foo<long, bool>(5, false);
+// although usually you can rely on the compiler to infer the types
+// for you automatically.  You can assign the result of expression
+// Foo(p1, ..., pk) to a variable of type FooActionPk<p1_type, ...,
+// pk_type>.  This can be useful when composing actions.
+//
+// You can also overload actions with different numbers of parameters:
+//
+//   ACTION_P(Plus, a) { ... }
+//   ACTION_P2(Plus, a, b) { ... }
+//
+// While it's tempting to always use the ACTION* macros when defining
+// a new action, you should also consider implementing ActionInterface
+// or using MakePolymorphicAction() instead, especially if you need to
+// use the action a lot.  While these approaches require more work,
+// they give you more control on the types of the mock function
+// arguments and the action parameters, which in general leads to
+// better compiler error messages that pay off in the long run.  They
+// also allow overloading actions based on parameter types (as opposed
+// to just based on the number of parameters).
+//
+// CAVEAT:
+//
+// ACTION*() can only be used in a namespace scope as templates cannot be
+// declared inside of a local class.
+// Users can, however, define any local functors (e.g. a lambda) that
+// can be used as actions.
+//
+// MORE INFORMATION:
+//
+// To learn more about using these macros, please search for 'ACTION' on
+// https://github.com/google/googletest/blob/master/docs/gmock_cook_book.md
 
 // GOOGLETEST_CM0002 DO NOT DELETE
 
-#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_ACTIONS_H_
-#define GMOCK_INCLUDE_GMOCK_GMOCK_ACTIONS_H_
+#ifndef GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_ACTIONS_H_
+#define GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_ACTIONS_H_
 
 #ifndef _WIN32_WCE
 # include <errno.h>
@@ -103,6 +196,7 @@
 #include <functional>
 #include <memory>
 #include <string>
+#include <tuple>
 #include <type_traits>
 #include <utility>
 
@@ -144,8 +238,8 @@
 
 // GOOGLETEST_CM0002 DO NOT DELETE
 
-#ifndef GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_INTERNAL_UTILS_H_
-#define GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_INTERNAL_UTILS_H_
+#ifndef GOOGLEMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_INTERNAL_UTILS_H_
+#define GOOGLEMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_INTERNAL_UTILS_H_
 
 #include <stdio.h>
 #include <ostream>  // NOLINT
@@ -190,11 +284,12 @@
 
 // GOOGLETEST_CM0002 DO NOT DELETE
 
-#ifndef GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_PORT_H_
-#define GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_PORT_H_
+#ifndef GOOGLEMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_PORT_H_
+#define GOOGLEMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_PORT_H_
 
 #include <assert.h>
 #include <stdlib.h>
+#include <cstdint>
 #include <iostream>
 
 // Most of the utilities needed for porting Google Mock are also
@@ -241,10 +336,10 @@
 
 // GOOGLETEST_CM0002 DO NOT DELETE
 
-#ifndef GMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_GMOCK_PORT_H_
-#define GMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_GMOCK_PORT_H_
+#ifndef GOOGLEMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_GMOCK_PORT_H_
+#define GOOGLEMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_GMOCK_PORT_H_
 
-#endif  // GMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_GMOCK_PORT_H_
+#endif  // GOOGLEMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_GMOCK_PORT_H_
 
 // For MS Visual C++, check the compiler version. At least VS 2015 is
 // required to compile Google Mock.
@@ -260,8 +355,7 @@
 
 // Macros for declaring flags.
 # define GMOCK_DECLARE_bool_(name) extern GTEST_API_ bool GMOCK_FLAG(name)
-# define GMOCK_DECLARE_int32_(name) \
-    extern GTEST_API_ ::testing::internal::Int32 GMOCK_FLAG(name)
+# define GMOCK_DECLARE_int32_(name) extern GTEST_API_ int32_t GMOCK_FLAG(name)
 # define GMOCK_DECLARE_string_(name) \
     extern GTEST_API_ ::std::string GMOCK_FLAG(name)
 
@@ -269,13 +363,13 @@
 # define GMOCK_DEFINE_bool_(name, default_val, doc) \
     GTEST_API_ bool GMOCK_FLAG(name) = (default_val)
 # define GMOCK_DEFINE_int32_(name, default_val, doc) \
-    GTEST_API_ ::testing::internal::Int32 GMOCK_FLAG(name) = (default_val)
+    GTEST_API_ int32_t GMOCK_FLAG(name) = (default_val)
 # define GMOCK_DEFINE_string_(name, default_val, doc) \
     GTEST_API_ ::std::string GMOCK_FLAG(name) = (default_val)
 
 #endif  // !defined(GMOCK_DECLARE_bool_)
 
-#endif  // GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_PORT_H_
+#endif  // GOOGLEMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_PORT_H_
 
 namespace testing {
 
@@ -302,20 +396,6 @@
 // "foo_bar_123" are converted to "foo bar 123".
 GTEST_API_ std::string ConvertIdentifierNameToWords(const char* id_name);
 
-// PointeeOf<Pointer>::type is the type of a value pointed to by a
-// Pointer, which can be either a smart pointer or a raw pointer.  The
-// following default implementation is for the case where Pointer is a
-// smart pointer.
-template <typename Pointer>
-struct PointeeOf {
-  // Smart pointer classes define type element_type as the type of
-  // their pointees.
-  typedef typename Pointer::element_type type;
-};
-// This specialization is for the raw pointer case.
-template <typename T>
-struct PointeeOf<T*> { typedef T type; };  // NOLINT
-
 // GetRawPointer(p) returns the raw pointer underlying p when p is a
 // smart pointer, or returns p itself when p is already a raw pointer.
 // The following default implementation is for the smart pointer case.
@@ -337,22 +417,6 @@
 # define GMOCK_WCHAR_T_IS_NATIVE_ 1
 #endif
 
-// signed wchar_t and unsigned wchar_t are NOT in the C++ standard.
-// Using them is a bad practice and not portable.  So DON'T use them.
-//
-// Still, Google Mock is designed to work even if the user uses signed
-// wchar_t or unsigned wchar_t (obviously, assuming the compiler
-// supports them).
-//
-// To gcc,
-//   wchar_t == signed wchar_t != unsigned wchar_t == unsigned int
-#ifdef __GNUC__
-#if !defined(__WCHAR_UNSIGNED__)
-// signed/unsigned wchar_t are valid types.
-# define GMOCK_HAS_SIGNED_WCHAR_T_ 1
-#endif
-#endif
-
 // In what follows, we use the term "kind" to indicate whether a type
 // is bool, an integer type (excluding bool), a floating-point type,
 // or none of them.  This categorization is useful for determining
@@ -383,15 +447,13 @@
 GMOCK_DECLARE_KIND_(unsigned int, kInteger);
 GMOCK_DECLARE_KIND_(long, kInteger);  // NOLINT
 GMOCK_DECLARE_KIND_(unsigned long, kInteger);  // NOLINT
+GMOCK_DECLARE_KIND_(long long, kInteger);  // NOLINT
+GMOCK_DECLARE_KIND_(unsigned long long, kInteger);  // NOLINT
 
 #if GMOCK_WCHAR_T_IS_NATIVE_
 GMOCK_DECLARE_KIND_(wchar_t, kInteger);
 #endif
 
-// Non-standard integer types.
-GMOCK_DECLARE_KIND_(Int64, kInteger);
-GMOCK_DECLARE_KIND_(UInt64, kInteger);
-
 // All standard floating-point types.
 GMOCK_DECLARE_KIND_(float, kFloatingPoint);
 GMOCK_DECLARE_KIND_(double, kFloatingPoint);
@@ -404,11 +466,8 @@
   static_cast< ::testing::internal::TypeKind>( \
       ::testing::internal::KindOf<type>::value)
 
-// Evaluates to true iff integer type T is signed.
-#define GMOCK_IS_SIGNED_(T) (static_cast<T>(-1) < 0)
-
 // LosslessArithmeticConvertibleImpl<kFromKind, From, kToKind, To>::value
-// is true iff arithmetic type From can be losslessly converted to
+// is true if and only if arithmetic type From can be losslessly converted to
 // arithmetic type To.
 //
 // It's the user's responsibility to ensure that both From and To are
@@ -417,77 +476,42 @@
 // From, and kToKind is the kind of To; the value is
 // implementation-defined when the above pre-condition is violated.
 template <TypeKind kFromKind, typename From, TypeKind kToKind, typename To>
-struct LosslessArithmeticConvertibleImpl : public false_type {};
+using LosslessArithmeticConvertibleImpl = std::integral_constant<
+    bool,
+    // clang-format off
+      // Converting from bool is always lossless
+      (kFromKind == kBool) ? true
+      // Converting between any other type kinds will be lossy if the type
+      // kinds are not the same.
+    : (kFromKind != kToKind) ? false
+    : (kFromKind == kInteger &&
+       // Converting between integers of different widths is allowed so long
+       // as the conversion does not go from signed to unsigned.
+      (((sizeof(From) < sizeof(To)) &&
+        !(std::is_signed<From>::value && !std::is_signed<To>::value)) ||
+       // Converting between integers of the same width only requires the
+       // two types to have the same signedness.
+       ((sizeof(From) == sizeof(To)) &&
+        (std::is_signed<From>::value == std::is_signed<To>::value)))
+       ) ? true
+      // Floating point conversions are lossless if and only if `To` is at least
+      // as wide as `From`.
+    : (kFromKind == kFloatingPoint && (sizeof(From) <= sizeof(To))) ? true
+    : false
+    // clang-format on
+    >;
 
-// Converting bool to bool is lossless.
-template <>
-struct LosslessArithmeticConvertibleImpl<kBool, bool, kBool, bool>
-    : public true_type {};  // NOLINT
-
-// Converting bool to any integer type is lossless.
-template <typename To>
-struct LosslessArithmeticConvertibleImpl<kBool, bool, kInteger, To>
-    : public true_type {};  // NOLINT
-
-// Converting bool to any floating-point type is lossless.
-template <typename To>
-struct LosslessArithmeticConvertibleImpl<kBool, bool, kFloatingPoint, To>
-    : public true_type {};  // NOLINT
-
-// Converting an integer to bool is lossy.
-template <typename From>
-struct LosslessArithmeticConvertibleImpl<kInteger, From, kBool, bool>
-    : public false_type {};  // NOLINT
-
-// Converting an integer to another non-bool integer is lossless iff
-// the target type's range encloses the source type's range.
-template <typename From, typename To>
-struct LosslessArithmeticConvertibleImpl<kInteger, From, kInteger, To>
-    : public bool_constant<
-      // When converting from a smaller size to a larger size, we are
-      // fine as long as we are not converting from signed to unsigned.
-      ((sizeof(From) < sizeof(To)) &&
-       (!GMOCK_IS_SIGNED_(From) || GMOCK_IS_SIGNED_(To))) ||
-      // When converting between the same size, the signedness must match.
-      ((sizeof(From) == sizeof(To)) &&
-       (GMOCK_IS_SIGNED_(From) == GMOCK_IS_SIGNED_(To)))> {};  // NOLINT
-
-#undef GMOCK_IS_SIGNED_
-
-// Converting an integer to a floating-point type may be lossy, since
-// the format of a floating-point number is implementation-defined.
-template <typename From, typename To>
-struct LosslessArithmeticConvertibleImpl<kInteger, From, kFloatingPoint, To>
-    : public false_type {};  // NOLINT
-
-// Converting a floating-point to bool is lossy.
-template <typename From>
-struct LosslessArithmeticConvertibleImpl<kFloatingPoint, From, kBool, bool>
-    : public false_type {};  // NOLINT
-
-// Converting a floating-point to an integer is lossy.
-template <typename From, typename To>
-struct LosslessArithmeticConvertibleImpl<kFloatingPoint, From, kInteger, To>
-    : public false_type {};  // NOLINT
-
-// Converting a floating-point to another floating-point is lossless
-// iff the target type is at least as big as the source type.
-template <typename From, typename To>
-struct LosslessArithmeticConvertibleImpl<
-  kFloatingPoint, From, kFloatingPoint, To>
-    : public bool_constant<sizeof(From) <= sizeof(To)> {};  // NOLINT
-
-// LosslessArithmeticConvertible<From, To>::value is true iff arithmetic
-// type From can be losslessly converted to arithmetic type To.
+// LosslessArithmeticConvertible<From, To>::value is true if and only if
+// arithmetic type From can be losslessly converted to arithmetic type To.
 //
 // It's the user's responsibility to ensure that both From and To are
 // raw (i.e. has no CV modifier, is not a pointer, and is not a
 // reference) built-in arithmetic types; the value is
 // implementation-defined when the above pre-condition is violated.
 template <typename From, typename To>
-struct LosslessArithmeticConvertible
-    : public LosslessArithmeticConvertibleImpl<
-  GMOCK_KIND_OF_(From), From, GMOCK_KIND_OF_(To), To> {};  // NOLINT
+using LosslessArithmeticConvertible =
+    LosslessArithmeticConvertibleImpl<GMOCK_KIND_OF_(From), From,
+                                      GMOCK_KIND_OF_(To), To>;
 
 // This interface knows how to report a Google Mock failure (either
 // non-fatal or fatal).
@@ -552,11 +576,11 @@
 // No logs are printed.
 const char kErrorVerbosity[] = "error";
 
-// Returns true iff a log with the given severity is visible according
-// to the --gmock_verbose flag.
+// Returns true if and only if a log with the given severity is visible
+// according to the --gmock_verbose flag.
 GTEST_API_ bool LogIsVisible(LogSeverity severity);
 
-// Prints the given message to stdout iff 'severity' >= the level
+// Prints the given message to stdout if and only if 'severity' >= the level
 // specified by the --gmock_verbose flag.  If stack_frames_to_skip >=
 // 0, also prints the stack trace excluding the top
 // stack_frames_to_skip frames.  In opt mode, any positive
@@ -581,33 +605,6 @@
 // Internal use only: access the singleton instance of WithoutMatchers.
 GTEST_API_ WithoutMatchers GetWithoutMatchers();
 
-// Type traits.
-
-// is_reference<T>::value is non-zero iff T is a reference type.
-template <typename T> struct is_reference : public false_type {};
-template <typename T> struct is_reference<T&> : public true_type {};
-
-// type_equals<T1, T2>::value is non-zero iff T1 and T2 are the same type.
-template <typename T1, typename T2> struct type_equals : public false_type {};
-template <typename T> struct type_equals<T, T> : public true_type {};
-
-// remove_reference<T>::type removes the reference from type T, if any.
-template <typename T> struct remove_reference { typedef T type; };  // NOLINT
-template <typename T> struct remove_reference<T&> { typedef T type; }; // NOLINT
-
-// DecayArray<T>::type turns an array type U[N] to const U* and preserves
-// other types.  Useful for saving a copy of a function argument.
-template <typename T> struct DecayArray { typedef T type; };  // NOLINT
-template <typename T, size_t N> struct DecayArray<T[N]> {
-  typedef const T* type;
-};
-// Sometimes people use arrays whose size is not available at the use site
-// (e.g. extern const char kNamePrefix[]).  This specialization covers that
-// case.
-template <typename T> struct DecayArray<T[]> {
-  typedef const T* type;
-};
-
 // Disable MSVC warnings for infinite recursion, since in this case the
 // the recursion is unreachable.
 #ifdef _MSC_VER
@@ -656,9 +653,8 @@
   typedef const type& const_reference;
 
   static const_reference ConstReference(const RawContainer& container) {
-    // Ensures that RawContainer is not a const type.
-    testing::StaticAssertTypeEq<RawContainer,
-        GTEST_REMOVE_CONST_(RawContainer)>();
+    static_assert(!std::is_const<RawContainer>::value,
+                  "RawContainer type must not be const");
     return container;
   }
   static type Copy(const RawContainer& container) { return container; }
@@ -668,7 +664,7 @@
 template <typename Element, size_t N>
 class StlContainerView<Element[N]> {
  public:
-  typedef GTEST_REMOVE_CONST_(Element) RawElement;
+  typedef typename std::remove_const<Element>::type RawElement;
   typedef internal::NativeArray<RawElement> type;
   // NativeArray<T> can represent a native array either by value or by
   // reference (selected by a constructor argument), so 'const type'
@@ -678,8 +674,8 @@
   typedef const type const_reference;
 
   static const_reference ConstReference(const Element (&array)[N]) {
-    // Ensures that Element is not a const type.
-    testing::StaticAssertTypeEq<Element, RawElement>();
+    static_assert(std::is_same<Element, RawElement>::value,
+                  "Element type must not be const");
     return type(array, N, RelationToSourceReference());
   }
   static type Copy(const Element (&array)[N]) {
@@ -692,8 +688,9 @@
 template <typename ElementPointer, typename Size>
 class StlContainerView< ::std::tuple<ElementPointer, Size> > {
  public:
-  typedef GTEST_REMOVE_CONST_(
-      typename internal::PointeeOf<ElementPointer>::type) RawElement;
+  typedef typename std::remove_const<
+      typename std::pointer_traits<ElementPointer>::element_type>::type
+      RawElement;
   typedef internal::NativeArray<RawElement> type;
   typedef const type const_reference;
 
@@ -725,39 +722,25 @@
   typedef std::pair<K, V> type;
 };
 
-// Mapping from booleans to types. Similar to boost::bool_<kValue> and
-// std::integral_constant<bool, kValue>.
-template <bool kValue>
-struct BooleanConstant {};
-
 // Emit an assertion failure due to incorrect DoDefault() usage. Out-of-lined to
 // reduce code size.
 GTEST_API_ void IllegalDoDefault(const char* file, int line);
 
-// Helper types for Apply() below.
-template <size_t... Is> struct int_pack { typedef int_pack type; };
-
-template <class Pack, size_t I> struct append;
-template <size_t... Is, size_t I>
-struct append<int_pack<Is...>, I> : int_pack<Is..., I> {};
-
-template <size_t C>
-struct make_int_pack : append<typename make_int_pack<C - 1>::type, C - 1> {};
-template <> struct make_int_pack<0> : int_pack<> {};
-
 template <typename F, typename Tuple, size_t... Idx>
-auto ApplyImpl(F&& f, Tuple&& args, int_pack<Idx...>) -> decltype(
+auto ApplyImpl(F&& f, Tuple&& args, IndexSequence<Idx...>) -> decltype(
     std::forward<F>(f)(std::get<Idx>(std::forward<Tuple>(args))...)) {
   return std::forward<F>(f)(std::get<Idx>(std::forward<Tuple>(args))...);
 }
 
 // Apply the function to a tuple of arguments.
 template <typename F, typename Tuple>
-auto Apply(F&& f, Tuple&& args)
-    -> decltype(ApplyImpl(std::forward<F>(f), std::forward<Tuple>(args),
-                          make_int_pack<std::tuple_size<Tuple>::value>())) {
+auto Apply(F&& f, Tuple&& args) -> decltype(
+    ApplyImpl(std::forward<F>(f), std::forward<Tuple>(args),
+              MakeIndexSequence<std::tuple_size<
+                  typename std::remove_reference<Tuple>::type>::value>())) {
   return ApplyImpl(std::forward<F>(f), std::forward<Tuple>(args),
-                   make_int_pack<std::tuple_size<Tuple>::value>());
+                   MakeIndexSequence<std::tuple_size<
+                       typename std::remove_reference<Tuple>::type>::value>());
 }
 
 // Template struct Function<F>, where F must be a function type, contains
@@ -781,8 +764,7 @@
   using Result = R;
   static constexpr size_t ArgumentCount = sizeof...(Args);
   template <size_t I>
-  using Arg = ElemFromList<I, typename MakeIndexSequence<sizeof...(Args)>::type,
-                           Args...>;
+  using Arg = ElemFromList<I, Args...>;
   using ArgumentTuple = std::tuple<Args...>;
   using ArgumentMatcherTuple = std::tuple<Matcher<Args>...>;
   using MakeResultVoid = void(Args...);
@@ -799,7 +781,286 @@
 }  // namespace internal
 }  // namespace testing
 
-#endif  // GMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_INTERNAL_UTILS_H_
+#endif  // GOOGLEMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_INTERNAL_UTILS_H_
+#ifndef GOOGLEMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_PP_H_
+#define GOOGLEMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_PP_H_
+
+// Expands and concatenates the arguments. Constructed macros reevaluate.
+#define GMOCK_PP_CAT(_1, _2) GMOCK_PP_INTERNAL_CAT(_1, _2)
+
+// Expands and stringifies the only argument.
+#define GMOCK_PP_STRINGIZE(...) GMOCK_PP_INTERNAL_STRINGIZE(__VA_ARGS__)
+
+// Returns empty. Given a variadic number of arguments.
+#define GMOCK_PP_EMPTY(...)
+
+// Returns a comma. Given a variadic number of arguments.
+#define GMOCK_PP_COMMA(...) ,
+
+// Returns the only argument.
+#define GMOCK_PP_IDENTITY(_1) _1
+
+// Evaluates to the number of arguments after expansion.
+//
+//   #define PAIR x, y
+//
+//   GMOCK_PP_NARG() => 1
+//   GMOCK_PP_NARG(x) => 1
+//   GMOCK_PP_NARG(x, y) => 2
+//   GMOCK_PP_NARG(PAIR) => 2
+//
+// Requires: the number of arguments after expansion is at most 15.
+#define GMOCK_PP_NARG(...) \
+  GMOCK_PP_INTERNAL_16TH(  \
+      (__VA_ARGS__, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0))
+
+// Returns 1 if the expansion of arguments has an unprotected comma. Otherwise
+// returns 0. Requires no more than 15 unprotected commas.
+#define GMOCK_PP_HAS_COMMA(...) \
+  GMOCK_PP_INTERNAL_16TH(       \
+      (__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0))
+
+// Returns the first argument.
+#define GMOCK_PP_HEAD(...) GMOCK_PP_INTERNAL_HEAD((__VA_ARGS__, unusedArg))
+
+// Returns the tail. A variadic list of all arguments minus the first. Requires
+// at least one argument.
+#define GMOCK_PP_TAIL(...) GMOCK_PP_INTERNAL_TAIL((__VA_ARGS__))
+
+// Calls CAT(_Macro, NARG(__VA_ARGS__))(__VA_ARGS__)
+#define GMOCK_PP_VARIADIC_CALL(_Macro, ...) \
+  GMOCK_PP_IDENTITY(                        \
+      GMOCK_PP_CAT(_Macro, GMOCK_PP_NARG(__VA_ARGS__))(__VA_ARGS__))
+
+// If the arguments after expansion have no tokens, evaluates to `1`. Otherwise
+// evaluates to `0`.
+//
+// Requires: * the number of arguments after expansion is at most 15.
+//           * If the argument is a macro, it must be able to be called with one
+//             argument.
+//
+// Implementation details:
+//
+// There is one case when it generates a compile error: if the argument is macro
+// that cannot be called with one argument.
+//
+//   #define M(a, b)  // it doesn't matter what it expands to
+//
+//   // Expected: expands to `0`.
+//   // Actual: compile error.
+//   GMOCK_PP_IS_EMPTY(M)
+//
+// There are 4 cases tested:
+//
+// * __VA_ARGS__ possible expansion has no unparen'd commas. Expected 0.
+// * __VA_ARGS__ possible expansion is not enclosed in parenthesis. Expected 0.
+// * __VA_ARGS__ possible expansion is not a macro that ()-evaluates to a comma.
+//   Expected 0
+// * __VA_ARGS__ is empty, or has unparen'd commas, or is enclosed in
+//   parenthesis, or is a macro that ()-evaluates to comma. Expected 1.
+//
+// We trigger detection on '0001', i.e. on empty.
+#define GMOCK_PP_IS_EMPTY(...)                                               \
+  GMOCK_PP_INTERNAL_IS_EMPTY(GMOCK_PP_HAS_COMMA(__VA_ARGS__),                \
+                             GMOCK_PP_HAS_COMMA(GMOCK_PP_COMMA __VA_ARGS__), \
+                             GMOCK_PP_HAS_COMMA(__VA_ARGS__()),              \
+                             GMOCK_PP_HAS_COMMA(GMOCK_PP_COMMA __VA_ARGS__()))
+
+// Evaluates to _Then if _Cond is 1 and _Else if _Cond is 0.
+#define GMOCK_PP_IF(_Cond, _Then, _Else) \
+  GMOCK_PP_CAT(GMOCK_PP_INTERNAL_IF_, _Cond)(_Then, _Else)
+
+// Similar to GMOCK_PP_IF but takes _Then and _Else in parentheses.
+//
+// GMOCK_PP_GENERIC_IF(1, (a, b, c), (d, e, f)) => a, b, c
+// GMOCK_PP_GENERIC_IF(0, (a, b, c), (d, e, f)) => d, e, f
+//
+#define GMOCK_PP_GENERIC_IF(_Cond, _Then, _Else) \
+  GMOCK_PP_REMOVE_PARENS(GMOCK_PP_IF(_Cond, _Then, _Else))
+
+// Evaluates to the number of arguments after expansion. Identifies 'empty' as
+// 0.
+//
+//   #define PAIR x, y
+//
+//   GMOCK_PP_NARG0() => 0
+//   GMOCK_PP_NARG0(x) => 1
+//   GMOCK_PP_NARG0(x, y) => 2
+//   GMOCK_PP_NARG0(PAIR) => 2
+//
+// Requires: * the number of arguments after expansion is at most 15.
+//           * If the argument is a macro, it must be able to be called with one
+//             argument.
+#define GMOCK_PP_NARG0(...) \
+  GMOCK_PP_IF(GMOCK_PP_IS_EMPTY(__VA_ARGS__), 0, GMOCK_PP_NARG(__VA_ARGS__))
+
+// Expands to 1 if the first argument starts with something in parentheses,
+// otherwise to 0.
+#define GMOCK_PP_IS_BEGIN_PARENS(...)                              \
+  GMOCK_PP_HEAD(GMOCK_PP_CAT(GMOCK_PP_INTERNAL_IBP_IS_VARIADIC_R_, \
+                             GMOCK_PP_INTERNAL_IBP_IS_VARIADIC_C __VA_ARGS__))
+
+// Expands to 1 is there is only one argument and it is enclosed in parentheses.
+#define GMOCK_PP_IS_ENCLOSED_PARENS(...)             \
+  GMOCK_PP_IF(GMOCK_PP_IS_BEGIN_PARENS(__VA_ARGS__), \
+              GMOCK_PP_IS_EMPTY(GMOCK_PP_EMPTY __VA_ARGS__), 0)
+
+// Remove the parens, requires GMOCK_PP_IS_ENCLOSED_PARENS(args) => 1.
+#define GMOCK_PP_REMOVE_PARENS(...) GMOCK_PP_INTERNAL_REMOVE_PARENS __VA_ARGS__
+
+// Expands to _Macro(0, _Data, e1) _Macro(1, _Data, e2) ... _Macro(K -1, _Data,
+// eK) as many of GMOCK_INTERNAL_NARG0 _Tuple.
+// Requires: * |_Macro| can be called with 3 arguments.
+//           * |_Tuple| expansion has no more than 15 elements.
+#define GMOCK_PP_FOR_EACH(_Macro, _Data, _Tuple)                        \
+  GMOCK_PP_CAT(GMOCK_PP_INTERNAL_FOR_EACH_IMPL_, GMOCK_PP_NARG0 _Tuple) \
+  (0, _Macro, _Data, _Tuple)
+
+// Expands to _Macro(0, _Data, ) _Macro(1, _Data, ) ... _Macro(K - 1, _Data, )
+// Empty if _K = 0.
+// Requires: * |_Macro| can be called with 3 arguments.
+//           * |_K| literal between 0 and 15
+#define GMOCK_PP_REPEAT(_Macro, _Data, _N)           \
+  GMOCK_PP_CAT(GMOCK_PP_INTERNAL_FOR_EACH_IMPL_, _N) \
+  (0, _Macro, _Data, GMOCK_PP_INTENRAL_EMPTY_TUPLE)
+
+// Increments the argument, requires the argument to be between 0 and 15.
+#define GMOCK_PP_INC(_i) GMOCK_PP_CAT(GMOCK_PP_INTERNAL_INC_, _i)
+
+// Returns comma if _i != 0. Requires _i to be between 0 and 15.
+#define GMOCK_PP_COMMA_IF(_i) GMOCK_PP_CAT(GMOCK_PP_INTERNAL_COMMA_IF_, _i)
+
+// Internal details follow. Do not use any of these symbols outside of this
+// file or we will break your code.
+#define GMOCK_PP_INTENRAL_EMPTY_TUPLE (, , , , , , , , , , , , , , , )
+#define GMOCK_PP_INTERNAL_CAT(_1, _2) _1##_2
+#define GMOCK_PP_INTERNAL_STRINGIZE(...) #__VA_ARGS__
+#define GMOCK_PP_INTERNAL_CAT_5(_1, _2, _3, _4, _5) _1##_2##_3##_4##_5
+#define GMOCK_PP_INTERNAL_IS_EMPTY(_1, _2, _3, _4)                             \
+  GMOCK_PP_HAS_COMMA(GMOCK_PP_INTERNAL_CAT_5(GMOCK_PP_INTERNAL_IS_EMPTY_CASE_, \
+                                             _1, _2, _3, _4))
+#define GMOCK_PP_INTERNAL_IS_EMPTY_CASE_0001 ,
+#define GMOCK_PP_INTERNAL_IF_1(_Then, _Else) _Then
+#define GMOCK_PP_INTERNAL_IF_0(_Then, _Else) _Else
+
+// Because of MSVC treating a token with a comma in it as a single token when
+// passed to another macro, we need to force it to evaluate it as multiple
+// tokens. We do that by using a "IDENTITY(MACRO PARENTHESIZED_ARGS)" macro. We
+// define one per possible macro that relies on this behavior. Note "_Args" must
+// be parenthesized.
+#define GMOCK_PP_INTERNAL_INTERNAL_16TH(_1, _2, _3, _4, _5, _6, _7, _8, _9, \
+                                        _10, _11, _12, _13, _14, _15, _16,  \
+                                        ...)                                \
+  _16
+#define GMOCK_PP_INTERNAL_16TH(_Args) \
+  GMOCK_PP_IDENTITY(GMOCK_PP_INTERNAL_INTERNAL_16TH _Args)
+#define GMOCK_PP_INTERNAL_INTERNAL_HEAD(_1, ...) _1
+#define GMOCK_PP_INTERNAL_HEAD(_Args) \
+  GMOCK_PP_IDENTITY(GMOCK_PP_INTERNAL_INTERNAL_HEAD _Args)
+#define GMOCK_PP_INTERNAL_INTERNAL_TAIL(_1, ...) __VA_ARGS__
+#define GMOCK_PP_INTERNAL_TAIL(_Args) \
+  GMOCK_PP_IDENTITY(GMOCK_PP_INTERNAL_INTERNAL_TAIL _Args)
+
+#define GMOCK_PP_INTERNAL_IBP_IS_VARIADIC_C(...) 1 _
+#define GMOCK_PP_INTERNAL_IBP_IS_VARIADIC_R_1 1,
+#define GMOCK_PP_INTERNAL_IBP_IS_VARIADIC_R_GMOCK_PP_INTERNAL_IBP_IS_VARIADIC_C \
+  0,
+#define GMOCK_PP_INTERNAL_REMOVE_PARENS(...) __VA_ARGS__
+#define GMOCK_PP_INTERNAL_INC_0 1
+#define GMOCK_PP_INTERNAL_INC_1 2
+#define GMOCK_PP_INTERNAL_INC_2 3
+#define GMOCK_PP_INTERNAL_INC_3 4
+#define GMOCK_PP_INTERNAL_INC_4 5
+#define GMOCK_PP_INTERNAL_INC_5 6
+#define GMOCK_PP_INTERNAL_INC_6 7
+#define GMOCK_PP_INTERNAL_INC_7 8
+#define GMOCK_PP_INTERNAL_INC_8 9
+#define GMOCK_PP_INTERNAL_INC_9 10
+#define GMOCK_PP_INTERNAL_INC_10 11
+#define GMOCK_PP_INTERNAL_INC_11 12
+#define GMOCK_PP_INTERNAL_INC_12 13
+#define GMOCK_PP_INTERNAL_INC_13 14
+#define GMOCK_PP_INTERNAL_INC_14 15
+#define GMOCK_PP_INTERNAL_INC_15 16
+#define GMOCK_PP_INTERNAL_COMMA_IF_0
+#define GMOCK_PP_INTERNAL_COMMA_IF_1 ,
+#define GMOCK_PP_INTERNAL_COMMA_IF_2 ,
+#define GMOCK_PP_INTERNAL_COMMA_IF_3 ,
+#define GMOCK_PP_INTERNAL_COMMA_IF_4 ,
+#define GMOCK_PP_INTERNAL_COMMA_IF_5 ,
+#define GMOCK_PP_INTERNAL_COMMA_IF_6 ,
+#define GMOCK_PP_INTERNAL_COMMA_IF_7 ,
+#define GMOCK_PP_INTERNAL_COMMA_IF_8 ,
+#define GMOCK_PP_INTERNAL_COMMA_IF_9 ,
+#define GMOCK_PP_INTERNAL_COMMA_IF_10 ,
+#define GMOCK_PP_INTERNAL_COMMA_IF_11 ,
+#define GMOCK_PP_INTERNAL_COMMA_IF_12 ,
+#define GMOCK_PP_INTERNAL_COMMA_IF_13 ,
+#define GMOCK_PP_INTERNAL_COMMA_IF_14 ,
+#define GMOCK_PP_INTERNAL_COMMA_IF_15 ,
+#define GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, _element) \
+  _Macro(_i, _Data, _element)
+#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_0(_i, _Macro, _Data, _Tuple)
+#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_1(_i, _Macro, _Data, _Tuple) \
+  GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple)
+#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_2(_i, _Macro, _Data, _Tuple)    \
+  GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
+  GMOCK_PP_INTERNAL_FOR_EACH_IMPL_1(GMOCK_PP_INC(_i), _Macro, _Data,    \
+                                    (GMOCK_PP_TAIL _Tuple))
+#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_3(_i, _Macro, _Data, _Tuple)    \
+  GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
+  GMOCK_PP_INTERNAL_FOR_EACH_IMPL_2(GMOCK_PP_INC(_i), _Macro, _Data,    \
+                                    (GMOCK_PP_TAIL _Tuple))
+#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_4(_i, _Macro, _Data, _Tuple)    \
+  GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
+  GMOCK_PP_INTERNAL_FOR_EACH_IMPL_3(GMOCK_PP_INC(_i), _Macro, _Data,    \
+                                    (GMOCK_PP_TAIL _Tuple))
+#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_5(_i, _Macro, _Data, _Tuple)    \
+  GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
+  GMOCK_PP_INTERNAL_FOR_EACH_IMPL_4(GMOCK_PP_INC(_i), _Macro, _Data,    \
+                                    (GMOCK_PP_TAIL _Tuple))
+#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_6(_i, _Macro, _Data, _Tuple)    \
+  GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
+  GMOCK_PP_INTERNAL_FOR_EACH_IMPL_5(GMOCK_PP_INC(_i), _Macro, _Data,    \
+                                    (GMOCK_PP_TAIL _Tuple))
+#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_7(_i, _Macro, _Data, _Tuple)    \
+  GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
+  GMOCK_PP_INTERNAL_FOR_EACH_IMPL_6(GMOCK_PP_INC(_i), _Macro, _Data,    \
+                                    (GMOCK_PP_TAIL _Tuple))
+#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_8(_i, _Macro, _Data, _Tuple)    \
+  GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
+  GMOCK_PP_INTERNAL_FOR_EACH_IMPL_7(GMOCK_PP_INC(_i), _Macro, _Data,    \
+                                    (GMOCK_PP_TAIL _Tuple))
+#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_9(_i, _Macro, _Data, _Tuple)    \
+  GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
+  GMOCK_PP_INTERNAL_FOR_EACH_IMPL_8(GMOCK_PP_INC(_i), _Macro, _Data,    \
+                                    (GMOCK_PP_TAIL _Tuple))
+#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_10(_i, _Macro, _Data, _Tuple)   \
+  GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
+  GMOCK_PP_INTERNAL_FOR_EACH_IMPL_9(GMOCK_PP_INC(_i), _Macro, _Data,    \
+                                    (GMOCK_PP_TAIL _Tuple))
+#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_11(_i, _Macro, _Data, _Tuple)   \
+  GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
+  GMOCK_PP_INTERNAL_FOR_EACH_IMPL_10(GMOCK_PP_INC(_i), _Macro, _Data,   \
+                                     (GMOCK_PP_TAIL _Tuple))
+#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_12(_i, _Macro, _Data, _Tuple)   \
+  GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
+  GMOCK_PP_INTERNAL_FOR_EACH_IMPL_11(GMOCK_PP_INC(_i), _Macro, _Data,   \
+                                     (GMOCK_PP_TAIL _Tuple))
+#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_13(_i, _Macro, _Data, _Tuple)   \
+  GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
+  GMOCK_PP_INTERNAL_FOR_EACH_IMPL_12(GMOCK_PP_INC(_i), _Macro, _Data,   \
+                                     (GMOCK_PP_TAIL _Tuple))
+#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_14(_i, _Macro, _Data, _Tuple)   \
+  GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
+  GMOCK_PP_INTERNAL_FOR_EACH_IMPL_13(GMOCK_PP_INC(_i), _Macro, _Data,   \
+                                     (GMOCK_PP_TAIL _Tuple))
+#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_15(_i, _Macro, _Data, _Tuple)   \
+  GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
+  GMOCK_PP_INTERNAL_FOR_EACH_IMPL_14(GMOCK_PP_INC(_i), _Macro, _Data,   \
+                                     (GMOCK_PP_TAIL _Tuple))
+
+#endif  // GOOGLEMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_PP_H_
 
 #ifdef _MSC_VER
 # pragma warning(push)
@@ -849,7 +1110,8 @@
 template <typename T>
 class BuiltInDefaultValue {
  public:
-  // This function returns true iff type T has a built-in default value.
+  // This function returns true if and only if type T has a built-in default
+  // value.
   static bool Exists() {
     return ::std::is_default_constructible<T>::value;
   }
@@ -889,9 +1151,6 @@
   }
 
 GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(void, );  // NOLINT
-#if GTEST_HAS_GLOBAL_STRING
-GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(::string, "");
-#endif  // GTEST_HAS_GLOBAL_STRING
 GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(::std::string, "");
 GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(bool, false);
 GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned char, '\0');
@@ -914,13 +1173,17 @@
 GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(signed int, 0);
 GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned long, 0UL);  // NOLINT
 GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(signed long, 0L);     // NOLINT
-GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(UInt64, 0);
-GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(Int64, 0);
+GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(unsigned long long, 0);  // NOLINT
+GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(signed long long, 0);  // NOLINT
 GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(float, 0);
 GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_(double, 0);
 
 #undef GMOCK_DEFINE_DEFAULT_ACTION_FOR_RETURN_TYPE_
 
+// Simple two-arg form of std::disjunction.
+template <typename P, typename Q>
+using disjunction = typename ::std::conditional<P::value, P, Q>::type;
+
 }  // namespace internal
 
 // When an unexpected function call is encountered, Google Mock will
@@ -961,7 +1224,7 @@
     producer_ = nullptr;
   }
 
-  // Returns true iff the user has set the default value for type T.
+  // Returns true if and only if the user has set the default value for type T.
   static bool IsSet() { return producer_ != nullptr; }
 
   // Returns true if T has a default return value set by the user or there
@@ -1022,7 +1285,7 @@
   // Unsets the default value for type T&.
   static void Clear() { address_ = nullptr; }
 
-  // Returns true iff the user has set the default value for type T&.
+  // Returns true if and only if the user has set the default value for type T&.
   static bool IsSet() { return address_ != nullptr; }
 
   // Returns true if T has a default return value set by the user or there
@@ -1102,6 +1365,9 @@
     }
   };
 
+  template <typename G>
+  using IsCompatibleFunctor = std::is_constructible<std::function<F>, G>;
+
  public:
   typedef typename internal::Function<F>::Result Result;
   typedef typename internal::Function<F>::ArgumentTuple ArgumentTuple;
@@ -1113,10 +1379,14 @@
   // Construct an Action from a specified callable.
   // This cannot take std::function directly, because then Action would not be
   // directly constructible from lambda (it would require two conversions).
-  template <typename G,
-            typename = typename ::std::enable_if<
-                ::std::is_constructible<::std::function<F>, G>::value>::type>
-  Action(G&& fun) : fun_(::std::forward<G>(fun)) {}  // NOLINT
+  template <
+      typename G,
+      typename = typename std::enable_if<internal::disjunction<
+          IsCompatibleFunctor<G>, std::is_constructible<std::function<Result()>,
+                                                        G>>::value>::type>
+  Action(G&& fun) {  // NOLINT
+    Init(::std::forward<G>(fun), IsCompatibleFunctor<G>());
+  }
 
   // Constructs an Action from its implementation.
   explicit Action(ActionInterface<F>* impl)
@@ -1128,7 +1398,7 @@
   template <typename Func>
   explicit Action(const Action<Func>& action) : fun_(action.fun_) {}
 
-  // Returns true iff this is the DoDefault() action.
+  // Returns true if and only if this is the DoDefault() action.
   bool IsDoDefault() const { return fun_ == nullptr; }
 
   // Performs the action.  Note that this method is const even though
@@ -1148,7 +1418,27 @@
   template <typename G>
   friend class Action;
 
-  // fun_ is an empty function iff this is the DoDefault() action.
+  template <typename G>
+  void Init(G&& g, ::std::true_type) {
+    fun_ = ::std::forward<G>(g);
+  }
+
+  template <typename G>
+  void Init(G&& g, ::std::false_type) {
+    fun_ = IgnoreArgs<typename ::std::decay<G>::type>{::std::forward<G>(g)};
+  }
+
+  template <typename FunctionImpl>
+  struct IgnoreArgs {
+    template <typename... Args>
+    Result operator()(const Args&...) const {
+      return function_impl();
+    }
+
+    FunctionImpl function_impl;
+  };
+
+  // fun_ is an empty function if and only if this is the DoDefault() action.
   ::std::function<F> fun_;
 };
 
@@ -1281,7 +1571,7 @@
     // in the Impl class. But both definitions must be the same.
     typedef typename Function<F>::Result Result;
     GTEST_COMPILE_ASSERT_(
-        !is_reference<Result>::value,
+        !std::is_reference<Result>::value,
         use_ReturnRef_instead_of_Return_to_return_a_reference);
     static_assert(!std::is_void<Result>::value,
                   "Can't use Return() on an action expected to return `void`.");
@@ -1310,7 +1600,7 @@
     Result Perform(const ArgumentTuple&) override { return value_; }
 
    private:
-    GTEST_COMPILE_ASSERT_(!is_reference<Result>::value,
+    GTEST_COMPILE_ASSERT_(!std::is_reference<Result>::value,
                           Result_cannot_be_a_reference_type);
     // We save the value before casting just in case it is being cast to a
     // wrapper type.
@@ -1364,7 +1654,7 @@
   // Allows Return() to be used in any void-returning function.
   template <typename Result, typename ArgumentTuple>
   static void Perform(const ArgumentTuple&) {
-    CompileAssertTypesEqual<void, Result>();
+    static_assert(std::is_void<Result>::value, "Result should be void.");
   }
 };
 
@@ -1385,7 +1675,7 @@
     // Asserts that the function return type is a reference.  This
     // catches the user error of using ReturnRef(x) when Return(x)
     // should be used, and generates some helpful error message.
-    GTEST_COMPILE_ASSERT_(internal::is_reference<Result>::value,
+    GTEST_COMPILE_ASSERT_(std::is_reference<Result>::value,
                           use_Return_instead_of_ReturnRef_to_return_a_value);
     return Action<F>(new Impl<F>(ref_));
   }
@@ -1428,7 +1718,7 @@
     // catches the user error of using ReturnRefOfCopy(x) when Return(x)
     // should be used, and generates some helpful error message.
     GTEST_COMPILE_ASSERT_(
-        internal::is_reference<Result>::value,
+        std::is_reference<Result>::value,
         use_Return_instead_of_ReturnRefOfCopy_to_return_a_value);
     return Action<F>(new Impl<F>(value_));
   }
@@ -1452,6 +1742,36 @@
   const T value_;
 };
 
+// Implements the polymorphic ReturnRoundRobin(v) action, which can be
+// used in any function that returns the element_type of v.
+template <typename T>
+class ReturnRoundRobinAction {
+ public:
+  explicit ReturnRoundRobinAction(std::vector<T> values) {
+    GTEST_CHECK_(!values.empty())
+        << "ReturnRoundRobin requires at least one element.";
+    state_->values = std::move(values);
+  }
+
+  template <typename... Args>
+  T operator()(Args&&...) const {
+     return state_->Next();
+  }
+
+ private:
+  struct State {
+    T Next() {
+      T ret_val = values[i++];
+      if (i == values.size()) i = 0;
+      return ret_val;
+    }
+
+    std::vector<T> values;
+    size_t i = 0;
+  };
+  std::shared_ptr<State> state_ = std::make_shared<State>();
+};
+
 // Implements the polymorphic DoDefault() action.
 class DoDefaultAction {
  public:
@@ -1502,45 +1822,15 @@
 #endif  // !GTEST_OS_WINDOWS_MOBILE
 
 // Implements the SetArgumentPointee<N>(x) action for any function
-// whose N-th argument (0-based) is a pointer to x's type.  The
-// template parameter kIsProto is true iff type A is ProtocolMessage,
-// proto2::Message, or a sub-class of those.
-template <size_t N, typename A, bool kIsProto>
-class SetArgumentPointeeAction {
- public:
-  // Constructs an action that sets the variable pointed to by the
-  // N-th function argument to 'value'.
-  explicit SetArgumentPointeeAction(const A& value) : value_(value) {}
+// whose N-th argument (0-based) is a pointer to x's type.
+template <size_t N, typename A, typename = void>
+struct SetArgumentPointeeAction {
+  A value;
 
-  template <typename Result, typename ArgumentTuple>
-  void Perform(const ArgumentTuple& args) const {
-    CompileAssertTypesEqual<void, Result>();
-    *::std::get<N>(args) = value_;
+  template <typename... Args>
+  void operator()(const Args&... args) const {
+    *::std::get<N>(std::tie(args...)) = value;
   }
-
- private:
-  const A value_;
-};
-
-template <size_t N, typename Proto>
-class SetArgumentPointeeAction<N, Proto, true> {
- public:
-  // Constructs an action that sets the variable pointed to by the
-  // N-th function argument to 'proto'.  Both ProtocolMessage and
-  // proto2::Message have the CopyFrom() method, so the same
-  // implementation works for both.
-  explicit SetArgumentPointeeAction(const Proto& proto) : proto_(new Proto) {
-    proto_->CopyFrom(proto);
-  }
-
-  template <typename Result, typename ArgumentTuple>
-  void Perform(const ArgumentTuple& args) const {
-    CompileAssertTypesEqual<void, Result>();
-    ::std::get<N>(args)->CopyFrom(*proto_);
-  }
-
- private:
-  const std::shared_ptr<Proto> proto_;
 };
 
 // Implements the Invoke(object_ptr, &Class::Method) action.
@@ -1578,7 +1868,8 @@
   Class* const obj_ptr;
   const MethodPtr method_ptr;
 
-  using ReturnType = typename std::result_of<MethodPtr(Class*)>::type;
+  using ReturnType =
+      decltype((std::declval<Class*>()->*std::declval<MethodPtr>())());
 
   template <typename... Args>
   ReturnType operator()(const Args&...) const {
@@ -1605,7 +1896,7 @@
     typedef typename internal::Function<F>::Result Result;
 
     // Asserts at compile time that F returns void.
-    CompileAssertTypesEqual<void, Result>();
+    static_assert(std::is_void<Result>::value, "Result type should be void.");
 
     return Action<F>(new Impl<F>(action_));
   }
@@ -1644,7 +1935,8 @@
   // We use the conversion operator to detect the signature of the inner Action.
   template <typename R, typename... Args>
   operator Action<R(Args...)>() const {  // NOLINT
-    Action<R(typename std::tuple_element<I, std::tuple<Args...>>::type...)>
+    using TupleType = std::tuple<Args...>;
+    Action<R(typename std::tuple_element<I, TupleType>::type...)>
         converted(action);
 
     return [converted](Args... args) -> R {
@@ -1657,9 +1949,13 @@
 template <typename... Actions>
 struct DoAllAction {
  private:
-  template <typename... Args, size_t... I>
-  std::vector<Action<void(Args...)>> Convert(IndexSequence<I...>) const {
-    return {std::get<I>(actions)...};
+  template <typename T>
+  using NonFinalType =
+      typename std::conditional<std::is_scalar<T>::value, T, const T&>::type;
+
+  template <typename ActionT, size_t... I>
+  std::vector<ActionT> Convert(IndexSequence<I...>) const {
+    return {ActionT(std::get<I>(actions))...};
   }
 
  public:
@@ -1668,21 +1964,121 @@
   template <typename R, typename... Args>
   operator Action<R(Args...)>() const {  // NOLINT
     struct Op {
-      std::vector<Action<void(Args...)>> converted;
+      std::vector<Action<void(NonFinalType<Args>...)>> converted;
       Action<R(Args...)> last;
       R operator()(Args... args) const {
         auto tuple_args = std::forward_as_tuple(std::forward<Args>(args)...);
         for (auto& a : converted) {
           a.Perform(tuple_args);
         }
-        return last.Perform(tuple_args);
+        return last.Perform(std::move(tuple_args));
       }
     };
-    return Op{Convert<Args...>(MakeIndexSequence<sizeof...(Actions) - 1>()),
+    return Op{Convert<Action<void(NonFinalType<Args>...)>>(
+                  MakeIndexSequence<sizeof...(Actions) - 1>()),
               std::get<sizeof...(Actions) - 1>(actions)};
   }
 };
 
+template <typename T, typename... Params>
+struct ReturnNewAction {
+  T* operator()() const {
+    return internal::Apply(
+        [](const Params&... unpacked_params) {
+          return new T(unpacked_params...);
+        },
+        params);
+  }
+  std::tuple<Params...> params;
+};
+
+template <size_t k>
+struct ReturnArgAction {
+  template <typename... Args>
+  auto operator()(const Args&... args) const ->
+      typename std::tuple_element<k, std::tuple<Args...>>::type {
+    return std::get<k>(std::tie(args...));
+  }
+};
+
+template <size_t k, typename Ptr>
+struct SaveArgAction {
+  Ptr pointer;
+
+  template <typename... Args>
+  void operator()(const Args&... args) const {
+    *pointer = std::get<k>(std::tie(args...));
+  }
+};
+
+template <size_t k, typename Ptr>
+struct SaveArgPointeeAction {
+  Ptr pointer;
+
+  template <typename... Args>
+  void operator()(const Args&... args) const {
+    *pointer = *std::get<k>(std::tie(args...));
+  }
+};
+
+template <size_t k, typename T>
+struct SetArgRefereeAction {
+  T value;
+
+  template <typename... Args>
+  void operator()(Args&&... args) const {
+    using argk_type =
+        typename ::std::tuple_element<k, std::tuple<Args...>>::type;
+    static_assert(std::is_lvalue_reference<argk_type>::value,
+                  "Argument must be a reference type.");
+    std::get<k>(std::tie(args...)) = value;
+  }
+};
+
+template <size_t k, typename I1, typename I2>
+struct SetArrayArgumentAction {
+  I1 first;
+  I2 last;
+
+  template <typename... Args>
+  void operator()(const Args&... args) const {
+    auto value = std::get<k>(std::tie(args...));
+    for (auto it = first; it != last; ++it, (void)++value) {
+      *value = *it;
+    }
+  }
+};
+
+template <size_t k>
+struct DeleteArgAction {
+  template <typename... Args>
+  void operator()(const Args&... args) const {
+    delete std::get<k>(std::tie(args...));
+  }
+};
+
+template <typename Ptr>
+struct ReturnPointeeAction {
+  Ptr pointer;
+  template <typename... Args>
+  auto operator()(const Args&...) const -> decltype(*pointer) {
+    return *pointer;
+  }
+};
+
+#if GTEST_HAS_EXCEPTIONS
+template <typename T>
+struct ThrowAction {
+  T exception;
+  // We use a conversion operator to adapt to any return type.
+  template <typename R, typename... Args>
+  operator Action<R(Args...)>() const {  // NOLINT
+    T copy = exception;
+    return [copy](Args...) -> R { throw copy; };
+  }
+};
+#endif  // GTEST_HAS_EXCEPTIONS
+
 }  // namespace internal
 
 // An Unused object can be implicitly constructed from ANY value.
@@ -1718,7 +2114,8 @@
 typedef internal::IgnoredValue Unused;
 
 // Creates an action that does actions a1, a2, ..., sequentially in
-// each invocation.
+// each invocation. All but the last action will have a readonly view of the
+// arguments.
 template <typename... Action>
 internal::DoAllAction<typename std::decay<Action>::type...> DoAll(
     Action&&... action) {
@@ -1780,6 +2177,10 @@
   return internal::ReturnRefAction<R>(x);
 }
 
+// Prevent using ReturnRef on reference to temporary.
+template <typename R, R* = nullptr>
+internal::ReturnRefAction<R> ReturnRef(R&&) = delete;
+
 // Creates an action that returns the reference to a copy of the
 // argument.  The copy is created when the action is constructed and
 // lives as long as the action.
@@ -1797,6 +2198,23 @@
   return internal::ByMoveWrapper<R>(std::move(x));
 }
 
+// Creates an action that returns an element of `vals`. Calling this action will
+// repeatedly return the next value from `vals` until it reaches the end and
+// will restart from the beginning.
+template <typename T>
+internal::ReturnRoundRobinAction<T> ReturnRoundRobin(std::vector<T> vals) {
+  return internal::ReturnRoundRobinAction<T>(std::move(vals));
+}
+
+// Creates an action that returns an element of `vals`. Calling this action will
+// repeatedly return the next value from `vals` until it reaches the end and
+// will restart from the beginning.
+template <typename T>
+internal::ReturnRoundRobinAction<T> ReturnRoundRobin(
+    std::initializer_list<T> vals) {
+  return internal::ReturnRoundRobinAction<T>(std::vector<T>(vals));
+}
+
 // Creates an action that does the default action for the give mock function.
 inline internal::DoDefaultAction DoDefault() {
   return internal::DoDefaultAction();
@@ -1805,38 +2223,14 @@
 // Creates an action that sets the variable pointed by the N-th
 // (0-based) function argument to 'value'.
 template <size_t N, typename T>
-PolymorphicAction<
-  internal::SetArgumentPointeeAction<
-    N, T, internal::IsAProtocolMessage<T>::value> >
-SetArgPointee(const T& x) {
-  return MakePolymorphicAction(internal::SetArgumentPointeeAction<
-      N, T, internal::IsAProtocolMessage<T>::value>(x));
-}
-
-template <size_t N>
-PolymorphicAction<
-  internal::SetArgumentPointeeAction<N, const char*, false> >
-SetArgPointee(const char* p) {
-  return MakePolymorphicAction(internal::SetArgumentPointeeAction<
-      N, const char*, false>(p));
-}
-
-template <size_t N>
-PolymorphicAction<
-  internal::SetArgumentPointeeAction<N, const wchar_t*, false> >
-SetArgPointee(const wchar_t* p) {
-  return MakePolymorphicAction(internal::SetArgumentPointeeAction<
-      N, const wchar_t*, false>(p));
+internal::SetArgumentPointeeAction<N, T> SetArgPointee(T value) {
+  return {std::move(value)};
 }
 
 // The following version is DEPRECATED.
 template <size_t N, typename T>
-PolymorphicAction<
-  internal::SetArgumentPointeeAction<
-    N, T, internal::IsAProtocolMessage<T>::value> >
-SetArgumentPointee(const T& x) {
-  return MakePolymorphicAction(internal::SetArgumentPointeeAction<
-      N, T, internal::IsAProtocolMessage<T>::value>(x));
+internal::SetArgumentPointeeAction<N, T> SetArgumentPointee(T value) {
+  return {std::move(value)};
 }
 
 // Creates an action that sets a pointer referent to a given value.
@@ -1914,14 +2308,299 @@
   return ::std::reference_wrapper<T>(l_value);
 }
 
+// The ReturnNew<T>(a1, a2, ..., a_k) action returns a pointer to a new
+// instance of type T, constructed on the heap with constructor arguments
+// a1, a2, ..., and a_k. The caller assumes ownership of the returned value.
+template <typename T, typename... Params>
+internal::ReturnNewAction<T, typename std::decay<Params>::type...> ReturnNew(
+    Params&&... params) {
+  return {std::forward_as_tuple(std::forward<Params>(params)...)};
+}
+
+// Action ReturnArg<k>() returns the k-th argument of the mock function.
+template <size_t k>
+internal::ReturnArgAction<k> ReturnArg() {
+  return {};
+}
+
+// Action SaveArg<k>(pointer) saves the k-th (0-based) argument of the
+// mock function to *pointer.
+template <size_t k, typename Ptr>
+internal::SaveArgAction<k, Ptr> SaveArg(Ptr pointer) {
+  return {pointer};
+}
+
+// Action SaveArgPointee<k>(pointer) saves the value pointed to
+// by the k-th (0-based) argument of the mock function to *pointer.
+template <size_t k, typename Ptr>
+internal::SaveArgPointeeAction<k, Ptr> SaveArgPointee(Ptr pointer) {
+  return {pointer};
+}
+
+// Action SetArgReferee<k>(value) assigns 'value' to the variable
+// referenced by the k-th (0-based) argument of the mock function.
+template <size_t k, typename T>
+internal::SetArgRefereeAction<k, typename std::decay<T>::type> SetArgReferee(
+    T&& value) {
+  return {std::forward<T>(value)};
+}
+
+// Action SetArrayArgument<k>(first, last) copies the elements in
+// source range [first, last) to the array pointed to by the k-th
+// (0-based) argument, which can be either a pointer or an
+// iterator. The action does not take ownership of the elements in the
+// source range.
+template <size_t k, typename I1, typename I2>
+internal::SetArrayArgumentAction<k, I1, I2> SetArrayArgument(I1 first,
+                                                             I2 last) {
+  return {first, last};
+}
+
+// Action DeleteArg<k>() deletes the k-th (0-based) argument of the mock
+// function.
+template <size_t k>
+internal::DeleteArgAction<k> DeleteArg() {
+  return {};
+}
+
+// This action returns the value pointed to by 'pointer'.
+template <typename Ptr>
+internal::ReturnPointeeAction<Ptr> ReturnPointee(Ptr pointer) {
+  return {pointer};
+}
+
+// Action Throw(exception) can be used in a mock function of any type
+// to throw the given exception.  Any copyable value can be thrown.
+#if GTEST_HAS_EXCEPTIONS
+template <typename T>
+internal::ThrowAction<typename std::decay<T>::type> Throw(T&& exception) {
+  return {std::forward<T>(exception)};
+}
+#endif  // GTEST_HAS_EXCEPTIONS
+
+namespace internal {
+
+// A macro from the ACTION* family (defined later in gmock-generated-actions.h)
+// defines an action that can be used in a mock function.  Typically,
+// these actions only care about a subset of the arguments of the mock
+// function.  For example, if such an action only uses the second
+// argument, it can be used in any mock function that takes >= 2
+// arguments where the type of the second argument is compatible.
+//
+// Therefore, the action implementation must be prepared to take more
+// arguments than it needs.  The ExcessiveArg type is used to
+// represent those excessive arguments.  In order to keep the compiler
+// error messages tractable, we define it in the testing namespace
+// instead of testing::internal.  However, this is an INTERNAL TYPE
+// and subject to change without notice, so a user MUST NOT USE THIS
+// TYPE DIRECTLY.
+struct ExcessiveArg {};
+
+// Builds an implementation of an Action<> for some particular signature, using
+// a class defined by an ACTION* macro.
+template <typename F, typename Impl> struct ActionImpl;
+
+template <typename Impl>
+struct ImplBase {
+  struct Holder {
+    // Allows each copy of the Action<> to get to the Impl.
+    explicit operator const Impl&() const { return *ptr; }
+    std::shared_ptr<Impl> ptr;
+  };
+  using type = typename std::conditional<std::is_constructible<Impl>::value,
+                                         Impl, Holder>::type;
+};
+
+template <typename R, typename... Args, typename Impl>
+struct ActionImpl<R(Args...), Impl> : ImplBase<Impl>::type {
+  using Base = typename ImplBase<Impl>::type;
+  using function_type = R(Args...);
+  using args_type = std::tuple<Args...>;
+
+  ActionImpl() = default;  // Only defined if appropriate for Base.
+  explicit ActionImpl(std::shared_ptr<Impl> impl) : Base{std::move(impl)} { }
+
+  R operator()(Args&&... arg) const {
+    static constexpr size_t kMaxArgs =
+        sizeof...(Args) <= 10 ? sizeof...(Args) : 10;
+    return Apply(MakeIndexSequence<kMaxArgs>{},
+                 MakeIndexSequence<10 - kMaxArgs>{},
+                 args_type{std::forward<Args>(arg)...});
+  }
+
+  template <std::size_t... arg_id, std::size_t... excess_id>
+  R Apply(IndexSequence<arg_id...>, IndexSequence<excess_id...>,
+          const args_type& args) const {
+    // Impl need not be specific to the signature of action being implemented;
+    // only the implementing function body needs to have all of the specific
+    // types instantiated.  Up to 10 of the args that are provided by the
+    // args_type get passed, followed by a dummy of unspecified type for the
+    // remainder up to 10 explicit args.
+    static constexpr ExcessiveArg kExcessArg{};
+    return static_cast<const Impl&>(*this).template gmock_PerformImpl<
+        /*function_type=*/function_type, /*return_type=*/R,
+        /*args_type=*/args_type,
+        /*argN_type=*/typename std::tuple_element<arg_id, args_type>::type...>(
+        /*args=*/args, std::get<arg_id>(args)...,
+        ((void)excess_id, kExcessArg)...);
+  }
+};
+
+// Stores a default-constructed Impl as part of the Action<>'s
+// std::function<>. The Impl should be trivial to copy.
+template <typename F, typename Impl>
+::testing::Action<F> MakeAction() {
+  return ::testing::Action<F>(ActionImpl<F, Impl>());
+}
+
+// Stores just the one given instance of Impl.
+template <typename F, typename Impl>
+::testing::Action<F> MakeAction(std::shared_ptr<Impl> impl) {
+  return ::testing::Action<F>(ActionImpl<F, Impl>(std::move(impl)));
+}
+
+#define GMOCK_INTERNAL_ARG_UNUSED(i, data, el) \
+  , const arg##i##_type& arg##i GTEST_ATTRIBUTE_UNUSED_
+#define GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_           \
+  const args_type& args GTEST_ATTRIBUTE_UNUSED_ GMOCK_PP_REPEAT( \
+      GMOCK_INTERNAL_ARG_UNUSED, , 10)
+
+#define GMOCK_INTERNAL_ARG(i, data, el) , const arg##i##_type& arg##i
+#define GMOCK_ACTION_ARG_TYPES_AND_NAMES_ \
+  const args_type& args GMOCK_PP_REPEAT(GMOCK_INTERNAL_ARG, , 10)
+
+#define GMOCK_INTERNAL_TEMPLATE_ARG(i, data, el) , typename arg##i##_type
+#define GMOCK_ACTION_TEMPLATE_ARGS_NAMES_ \
+  GMOCK_PP_TAIL(GMOCK_PP_REPEAT(GMOCK_INTERNAL_TEMPLATE_ARG, , 10))
+
+#define GMOCK_INTERNAL_TYPENAME_PARAM(i, data, param) , typename param##_type
+#define GMOCK_ACTION_TYPENAME_PARAMS_(params) \
+  GMOCK_PP_TAIL(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_TYPENAME_PARAM, , params))
+
+#define GMOCK_INTERNAL_TYPE_PARAM(i, data, param) , param##_type
+#define GMOCK_ACTION_TYPE_PARAMS_(params) \
+  GMOCK_PP_TAIL(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_TYPE_PARAM, , params))
+
+#define GMOCK_INTERNAL_TYPE_GVALUE_PARAM(i, data, param) \
+  , param##_type gmock_p##i
+#define GMOCK_ACTION_TYPE_GVALUE_PARAMS_(params) \
+  GMOCK_PP_TAIL(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_TYPE_GVALUE_PARAM, , params))
+
+#define GMOCK_INTERNAL_GVALUE_PARAM(i, data, param) \
+  , std::forward<param##_type>(gmock_p##i)
+#define GMOCK_ACTION_GVALUE_PARAMS_(params) \
+  GMOCK_PP_TAIL(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_GVALUE_PARAM, , params))
+
+#define GMOCK_INTERNAL_INIT_PARAM(i, data, param) \
+  , param(::std::forward<param##_type>(gmock_p##i))
+#define GMOCK_ACTION_INIT_PARAMS_(params) \
+  GMOCK_PP_TAIL(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_INIT_PARAM, , params))
+
+#define GMOCK_INTERNAL_FIELD_PARAM(i, data, param) param##_type param;
+#define GMOCK_ACTION_FIELD_PARAMS_(params) \
+  GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_FIELD_PARAM, , params)
+
+#define GMOCK_INTERNAL_ACTION(name, full_name, params)                        \
+  template <GMOCK_ACTION_TYPENAME_PARAMS_(params)>                            \
+  class full_name {                                                           \
+   public:                                                                    \
+    explicit full_name(GMOCK_ACTION_TYPE_GVALUE_PARAMS_(params))              \
+        : impl_(std::make_shared<gmock_Impl>(                                 \
+                GMOCK_ACTION_GVALUE_PARAMS_(params))) { }                     \
+    full_name(const full_name&) = default;                                    \
+    full_name(full_name&&) noexcept = default;                                \
+    template <typename F>                                                     \
+    operator ::testing::Action<F>() const {                                   \
+      return ::testing::internal::MakeAction<F>(impl_);                       \
+    }                                                                         \
+   private:                                                                   \
+    class gmock_Impl {                                                        \
+     public:                                                                  \
+      explicit gmock_Impl(GMOCK_ACTION_TYPE_GVALUE_PARAMS_(params))           \
+          : GMOCK_ACTION_INIT_PARAMS_(params) {}                              \
+      template <typename function_type, typename return_type,                 \
+                typename args_type, GMOCK_ACTION_TEMPLATE_ARGS_NAMES_>        \
+      return_type gmock_PerformImpl(GMOCK_ACTION_ARG_TYPES_AND_NAMES_) const; \
+      GMOCK_ACTION_FIELD_PARAMS_(params)                                      \
+    };                                                                        \
+    std::shared_ptr<const gmock_Impl> impl_;                                  \
+  };                                                                          \
+  template <GMOCK_ACTION_TYPENAME_PARAMS_(params)>                            \
+  inline full_name<GMOCK_ACTION_TYPE_PARAMS_(params)> name(                   \
+      GMOCK_ACTION_TYPE_GVALUE_PARAMS_(params)) {                             \
+    return full_name<GMOCK_ACTION_TYPE_PARAMS_(params)>(                      \
+        GMOCK_ACTION_GVALUE_PARAMS_(params));                                 \
+  }                                                                           \
+  template <GMOCK_ACTION_TYPENAME_PARAMS_(params)>                            \
+  template <typename function_type, typename return_type, typename args_type, \
+            GMOCK_ACTION_TEMPLATE_ARGS_NAMES_>                                \
+  return_type full_name<GMOCK_ACTION_TYPE_PARAMS_(params)>::gmock_Impl::      \
+  gmock_PerformImpl(GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const
+
+}  // namespace internal
+
+// Similar to GMOCK_INTERNAL_ACTION, but no bound parameters are stored.
+#define ACTION(name)                                                          \
+  class name##Action {                                                        \
+   public:                                                                    \
+   explicit name##Action() noexcept {}                                        \
+   name##Action(const name##Action&) noexcept {}                              \
+    template <typename F>                                                     \
+    operator ::testing::Action<F>() const {                                   \
+      return ::testing::internal::MakeAction<F, gmock_Impl>();                \
+    }                                                                         \
+   private:                                                                   \
+    class gmock_Impl {                                                        \
+     public:                                                                  \
+      template <typename function_type, typename return_type,                 \
+                typename args_type, GMOCK_ACTION_TEMPLATE_ARGS_NAMES_>        \
+      return_type gmock_PerformImpl(GMOCK_ACTION_ARG_TYPES_AND_NAMES_) const; \
+    };                                                                        \
+  };                                                                          \
+  inline name##Action name() GTEST_MUST_USE_RESULT_;                          \
+  inline name##Action name() { return name##Action(); }                       \
+  template <typename function_type, typename return_type, typename args_type, \
+            GMOCK_ACTION_TEMPLATE_ARGS_NAMES_>                                \
+  return_type name##Action::gmock_Impl::gmock_PerformImpl(                    \
+      GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const
+
+#define ACTION_P(name, ...) \
+  GMOCK_INTERNAL_ACTION(name, name##ActionP, (__VA_ARGS__))
+
+#define ACTION_P2(name, ...) \
+  GMOCK_INTERNAL_ACTION(name, name##ActionP2, (__VA_ARGS__))
+
+#define ACTION_P3(name, ...) \
+  GMOCK_INTERNAL_ACTION(name, name##ActionP3, (__VA_ARGS__))
+
+#define ACTION_P4(name, ...) \
+  GMOCK_INTERNAL_ACTION(name, name##ActionP4, (__VA_ARGS__))
+
+#define ACTION_P5(name, ...) \
+  GMOCK_INTERNAL_ACTION(name, name##ActionP5, (__VA_ARGS__))
+
+#define ACTION_P6(name, ...) \
+  GMOCK_INTERNAL_ACTION(name, name##ActionP6, (__VA_ARGS__))
+
+#define ACTION_P7(name, ...) \
+  GMOCK_INTERNAL_ACTION(name, name##ActionP7, (__VA_ARGS__))
+
+#define ACTION_P8(name, ...) \
+  GMOCK_INTERNAL_ACTION(name, name##ActionP8, (__VA_ARGS__))
+
+#define ACTION_P9(name, ...) \
+  GMOCK_INTERNAL_ACTION(name, name##ActionP9, (__VA_ARGS__))
+
+#define ACTION_P10(name, ...) \
+  GMOCK_INTERNAL_ACTION(name, name##ActionP10, (__VA_ARGS__))
+
 }  // namespace testing
 
 #ifdef _MSC_VER
 # pragma warning(pop)
 #endif
 
-
-#endif  // GMOCK_INCLUDE_GMOCK_GMOCK_ACTIONS_H_
+#endif  // GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_ACTIONS_H_
 // Copyright 2007, Google Inc.
 // All rights reserved.
 //
@@ -1960,8 +2639,8 @@
 
 // GOOGLETEST_CM0002 DO NOT DELETE
 
-#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_CARDINALITIES_H_
-#define GMOCK_INCLUDE_GMOCK_GMOCK_CARDINALITIES_H_
+#ifndef GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_CARDINALITIES_H_
+#define GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_CARDINALITIES_H_
 
 #include <limits.h>
 #include <memory>
@@ -1992,10 +2671,12 @@
   virtual int ConservativeLowerBound() const { return 0; }
   virtual int ConservativeUpperBound() const { return INT_MAX; }
 
-  // Returns true iff call_count calls will satisfy this cardinality.
+  // Returns true if and only if call_count calls will satisfy this
+  // cardinality.
   virtual bool IsSatisfiedByCallCount(int call_count) const = 0;
 
-  // Returns true iff call_count calls will saturate this cardinality.
+  // Returns true if and only if call_count calls will saturate this
+  // cardinality.
   virtual bool IsSaturatedByCallCount(int call_count) const = 0;
 
   // Describes self to an ostream.
@@ -2020,17 +2701,19 @@
   int ConservativeLowerBound() const { return impl_->ConservativeLowerBound(); }
   int ConservativeUpperBound() const { return impl_->ConservativeUpperBound(); }
 
-  // Returns true iff call_count calls will satisfy this cardinality.
+  // Returns true if and only if call_count calls will satisfy this
+  // cardinality.
   bool IsSatisfiedByCallCount(int call_count) const {
     return impl_->IsSatisfiedByCallCount(call_count);
   }
 
-  // Returns true iff call_count calls will saturate this cardinality.
+  // Returns true if and only if call_count calls will saturate this
+  // cardinality.
   bool IsSaturatedByCallCount(int call_count) const {
     return impl_->IsSaturatedByCallCount(call_count);
   }
 
-  // Returns true iff call_count calls will over-saturate this
+  // Returns true if and only if call_count calls will over-saturate this
   // cardinality, i.e. exceed the maximum number of allowed calls.
   bool IsOverSaturatedByCallCount(int call_count) const {
     return impl_->IsSaturatedByCallCount(call_count) &&
@@ -2072,14 +2755,7 @@
 
 GTEST_DISABLE_MSC_WARNINGS_POP_()  //  4251
 
-#endif  // GMOCK_INCLUDE_GMOCK_GMOCK_CARDINALITIES_H_
-#ifndef THIRD_PARTY_GOOGLETEST_GOOGLEMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_FUNCTION_MOCKER_H_  // NOLINT
-#define THIRD_PARTY_GOOGLETEST_GOOGLEMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_FUNCTION_MOCKER_H_  // NOLINT
-
-// This file was GENERATED by command:
-//     pump.py gmock-generated-function-mockers.h.pump
-// DO NOT EDIT BY HAND!!!
-
+#endif  // GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_CARDINALITIES_H_
 // Copyright 2007, Google Inc.
 // All rights reserved.
 //
@@ -2109,18 +2785,17 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-
 // Google Mock - a framework for writing C++ mock classes.
 //
-// This file implements function mockers of various arities.
+// This file implements MOCK_METHOD.
 
 // GOOGLETEST_CM0002 DO NOT DELETE
 
-#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_
-#define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_
+#ifndef GOOGLEMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_FUNCTION_MOCKER_H_  // NOLINT
+#define GOOGLEMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_FUNCTION_MOCKER_H_  // NOLINT
 
-#include <functional>
-#include <utility>
+#include <type_traits>  // IWYU pragma: keep
+#include <utility>      // IWYU pragma: keep
 
 // Copyright 2007, Google Inc.
 // All rights reserved.
@@ -2182,14 +2857,16 @@
 
 // GOOGLETEST_CM0002 DO NOT DELETE
 
-#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_SPEC_BUILDERS_H_
-#define GMOCK_INCLUDE_GMOCK_GMOCK_SPEC_BUILDERS_H_
+#ifndef GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_SPEC_BUILDERS_H_
+#define GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_SPEC_BUILDERS_H_
 
+#include <functional>
 #include <map>
 #include <memory>
 #include <set>
 #include <sstream>
 #include <string>
+#include <type_traits>
 #include <utility>
 #include <vector>
 // Copyright 2007, Google Inc.
@@ -2224,7 +2901,220 @@
 
 // Google Mock - a framework for writing C++ mock classes.
 //
-// This file implements some commonly used argument matchers.  More
+// The MATCHER* family of macros can be used in a namespace scope to
+// define custom matchers easily.
+//
+// Basic Usage
+// ===========
+//
+// The syntax
+//
+//   MATCHER(name, description_string) { statements; }
+//
+// defines a matcher with the given name that executes the statements,
+// which must return a bool to indicate if the match succeeds.  Inside
+// the statements, you can refer to the value being matched by 'arg',
+// and refer to its type by 'arg_type'.
+//
+// The description string documents what the matcher does, and is used
+// to generate the failure message when the match fails.  Since a
+// MATCHER() is usually defined in a header file shared by multiple
+// C++ source files, we require the description to be a C-string
+// literal to avoid possible side effects.  It can be empty, in which
+// case we'll use the sequence of words in the matcher name as the
+// description.
+//
+// For example:
+//
+//   MATCHER(IsEven, "") { return (arg % 2) == 0; }
+//
+// allows you to write
+//
+//   // Expects mock_foo.Bar(n) to be called where n is even.
+//   EXPECT_CALL(mock_foo, Bar(IsEven()));
+//
+// or,
+//
+//   // Verifies that the value of some_expression is even.
+//   EXPECT_THAT(some_expression, IsEven());
+//
+// If the above assertion fails, it will print something like:
+//
+//   Value of: some_expression
+//   Expected: is even
+//     Actual: 7
+//
+// where the description "is even" is automatically calculated from the
+// matcher name IsEven.
+//
+// Argument Type
+// =============
+//
+// Note that the type of the value being matched (arg_type) is
+// determined by the context in which you use the matcher and is
+// supplied to you by the compiler, so you don't need to worry about
+// declaring it (nor can you).  This allows the matcher to be
+// polymorphic.  For example, IsEven() can be used to match any type
+// where the value of "(arg % 2) == 0" can be implicitly converted to
+// a bool.  In the "Bar(IsEven())" example above, if method Bar()
+// takes an int, 'arg_type' will be int; if it takes an unsigned long,
+// 'arg_type' will be unsigned long; and so on.
+//
+// Parameterizing Matchers
+// =======================
+//
+// Sometimes you'll want to parameterize the matcher.  For that you
+// can use another macro:
+//
+//   MATCHER_P(name, param_name, description_string) { statements; }
+//
+// For example:
+//
+//   MATCHER_P(HasAbsoluteValue, value, "") { return abs(arg) == value; }
+//
+// will allow you to write:
+//
+//   EXPECT_THAT(Blah("a"), HasAbsoluteValue(n));
+//
+// which may lead to this message (assuming n is 10):
+//
+//   Value of: Blah("a")
+//   Expected: has absolute value 10
+//     Actual: -9
+//
+// Note that both the matcher description and its parameter are
+// printed, making the message human-friendly.
+//
+// In the matcher definition body, you can write 'foo_type' to
+// reference the type of a parameter named 'foo'.  For example, in the
+// body of MATCHER_P(HasAbsoluteValue, value) above, you can write
+// 'value_type' to refer to the type of 'value'.
+//
+// We also provide MATCHER_P2, MATCHER_P3, ..., up to MATCHER_P$n to
+// support multi-parameter matchers.
+//
+// Describing Parameterized Matchers
+// =================================
+//
+// The last argument to MATCHER*() is a string-typed expression.  The
+// expression can reference all of the matcher's parameters and a
+// special bool-typed variable named 'negation'.  When 'negation' is
+// false, the expression should evaluate to the matcher's description;
+// otherwise it should evaluate to the description of the negation of
+// the matcher.  For example,
+//
+//   using testing::PrintToString;
+//
+//   MATCHER_P2(InClosedRange, low, hi,
+//       std::string(negation ? "is not" : "is") + " in range [" +
+//       PrintToString(low) + ", " + PrintToString(hi) + "]") {
+//     return low <= arg && arg <= hi;
+//   }
+//   ...
+//   EXPECT_THAT(3, InClosedRange(4, 6));
+//   EXPECT_THAT(3, Not(InClosedRange(2, 4)));
+//
+// would generate two failures that contain the text:
+//
+//   Expected: is in range [4, 6]
+//   ...
+//   Expected: is not in range [2, 4]
+//
+// If you specify "" as the description, the failure message will
+// contain the sequence of words in the matcher name followed by the
+// parameter values printed as a tuple.  For example,
+//
+//   MATCHER_P2(InClosedRange, low, hi, "") { ... }
+//   ...
+//   EXPECT_THAT(3, InClosedRange(4, 6));
+//   EXPECT_THAT(3, Not(InClosedRange(2, 4)));
+//
+// would generate two failures that contain the text:
+//
+//   Expected: in closed range (4, 6)
+//   ...
+//   Expected: not (in closed range (2, 4))
+//
+// Types of Matcher Parameters
+// ===========================
+//
+// For the purpose of typing, you can view
+//
+//   MATCHER_Pk(Foo, p1, ..., pk, description_string) { ... }
+//
+// as shorthand for
+//
+//   template <typename p1_type, ..., typename pk_type>
+//   FooMatcherPk<p1_type, ..., pk_type>
+//   Foo(p1_type p1, ..., pk_type pk) { ... }
+//
+// When you write Foo(v1, ..., vk), the compiler infers the types of
+// the parameters v1, ..., and vk for you.  If you are not happy with
+// the result of the type inference, you can specify the types by
+// explicitly instantiating the template, as in Foo<long, bool>(5,
+// false).  As said earlier, you don't get to (or need to) specify
+// 'arg_type' as that's determined by the context in which the matcher
+// is used.  You can assign the result of expression Foo(p1, ..., pk)
+// to a variable of type FooMatcherPk<p1_type, ..., pk_type>.  This
+// can be useful when composing matchers.
+//
+// While you can instantiate a matcher template with reference types,
+// passing the parameters by pointer usually makes your code more
+// readable.  If, however, you still want to pass a parameter by
+// reference, be aware that in the failure message generated by the
+// matcher you will see the value of the referenced object but not its
+// address.
+//
+// Explaining Match Results
+// ========================
+//
+// Sometimes the matcher description alone isn't enough to explain why
+// the match has failed or succeeded.  For example, when expecting a
+// long string, it can be very helpful to also print the diff between
+// the expected string and the actual one.  To achieve that, you can
+// optionally stream additional information to a special variable
+// named result_listener, whose type is a pointer to class
+// MatchResultListener:
+//
+//   MATCHER_P(EqualsLongString, str, "") {
+//     if (arg == str) return true;
+//
+//     *result_listener << "the difference: "
+///                     << DiffStrings(str, arg);
+//     return false;
+//   }
+//
+// Overloading Matchers
+// ====================
+//
+// You can overload matchers with different numbers of parameters:
+//
+//   MATCHER_P(Blah, a, description_string1) { ... }
+//   MATCHER_P2(Blah, a, b, description_string2) { ... }
+//
+// Caveats
+// =======
+//
+// When defining a new matcher, you should also consider implementing
+// MatcherInterface or using MakePolymorphicMatcher().  These
+// approaches require more work than the MATCHER* macros, but also
+// give you more control on the types of the value being matched and
+// the matcher parameters, which may leads to better compiler error
+// messages when the matcher is used wrong.  They also allow
+// overloading matchers based on parameter types (as opposed to just
+// based on the number of parameters).
+//
+// MATCHER*() can only be used in a namespace scope as templates cannot be
+// declared inside of a local class.
+//
+// More Information
+// ================
+//
+// To learn more about using these macros, please search for 'MATCHER'
+// on
+// https://github.com/google/googletest/blob/master/docs/gmock_cook_book.md
+//
+// This file also implements some commonly used argument matchers.  More
 // matchers can be defined by the user implementing the
 // MatcherInterface<T> interface if necessary.
 //
@@ -2233,11 +3123,11 @@
 
 // GOOGLETEST_CM0002 DO NOT DELETE
 
-#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_MATCHERS_H_
-#define GMOCK_INCLUDE_GMOCK_GMOCK_MATCHERS_H_
+#ifndef GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_MATCHERS_H_
+#define GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_MATCHERS_H_
 
-#include <math.h>
 #include <algorithm>
+#include <cmath>
 #include <initializer_list>
 #include <iterator>
 #include <limits>
@@ -2249,9 +3139,17 @@
 #include <utility>
 #include <vector>
 
+
+// MSVC warning C5046 is new as of VS2017 version 15.8.
+#if defined(_MSC_VER) && _MSC_VER >= 1915
+#define GMOCK_MAYBE_5046_ 5046
+#else
+#define GMOCK_MAYBE_5046_
+#endif
+
 GTEST_DISABLE_MSC_WARNINGS_PUSH_(
-    4251 5046 /* class A needs to have dll-interface to be used by clients of
-                 class B */
+    4251 GMOCK_MAYBE_5046_ /* class A needs to have dll-interface to be used by
+                              clients of class B */
     /* Symbol involving type with internal linkage not defined */)
 
 namespace testing {
@@ -2312,23 +3210,20 @@
     // constructor from M (this usually happens when T has an implicit
     // constructor from any type).
     //
-    // It won't work to unconditionally implict_cast
+    // It won't work to unconditionally implicit_cast
     // polymorphic_matcher_or_value to Matcher<T> because it won't trigger
     // a user-defined conversion from M to T if one exists (assuming M is
     // a value).
-    return CastImpl(
-        polymorphic_matcher_or_value,
-        BooleanConstant<
-            std::is_convertible<M, Matcher<T> >::value>(),
-        BooleanConstant<
-            std::is_convertible<M, T>::value>());
+    return CastImpl(polymorphic_matcher_or_value,
+                    std::is_convertible<M, Matcher<T>>{},
+                    std::is_convertible<M, T>{});
   }
 
  private:
   template <bool Ignore>
   static Matcher<T> CastImpl(const M& polymorphic_matcher_or_value,
-                             BooleanConstant<true> /* convertible_to_matcher */,
-                             BooleanConstant<Ignore>) {
+                             std::true_type /* convertible_to_matcher */,
+                             std::integral_constant<bool, Ignore>) {
     // M is implicitly convertible to Matcher<T>, which means that either
     // M is a polymorphic matcher or Matcher<T> has an implicit constructor
     // from M.  In both cases using the implicit conversion will produce a
@@ -2343,9 +3238,9 @@
   // M can't be implicitly converted to Matcher<T>, so M isn't a polymorphic
   // matcher. It's a value of a type implicitly convertible to T. Use direct
   // initialization to create a matcher.
-  static Matcher<T> CastImpl(
-      const M& value, BooleanConstant<false> /* convertible_to_matcher */,
-      BooleanConstant<true> /* convertible_to_T */) {
+  static Matcher<T> CastImpl(const M& value,
+                             std::false_type /* convertible_to_matcher */,
+                             std::true_type /* convertible_to_T */) {
     return Matcher<T>(ImplicitCast_<T>(value));
   }
 
@@ -2359,9 +3254,9 @@
   // (e.g. std::pair<const int, int> vs. std::pair<int, int>).
   //
   // We don't define this method inline as we need the declaration of Eq().
-  static Matcher<T> CastImpl(
-      const M& value, BooleanConstant<false> /* convertible_to_matcher */,
-      BooleanConstant<false> /* convertible_to_T */);
+  static Matcher<T> CastImpl(const M& value,
+                             std::false_type /* convertible_to_matcher */,
+                             std::false_type /* convertible_to_T */);
 };
 
 // This more specialized version is used when MatcherCast()'s argument
@@ -2396,7 +3291,14 @@
               !std::is_base_of<FromType, ToType>::value,
           "Can't implicitly convert from <base> to <derived>");
 
-      return source_matcher_.MatchAndExplain(static_cast<U>(x), listener);
+      // Do the cast to `U` explicitly if necessary.
+      // Otherwise, let implicit conversions do the trick.
+      using CastType =
+          typename std::conditional<std::is_convertible<T&, const U&>::value,
+                                    T&, U>::type;
+
+      return source_matcher_.MatchAndExplain(static_cast<CastType>(x),
+                                             listener);
     }
 
     void DescribeTo(::std::ostream* os) const override {
@@ -2420,6 +3322,50 @@
   static Matcher<T> Cast(const Matcher<T>& matcher) { return matcher; }
 };
 
+// Template specialization for parameterless Matcher.
+template <typename Derived>
+class MatcherBaseImpl {
+ public:
+  MatcherBaseImpl() = default;
+
+  template <typename T>
+  operator ::testing::Matcher<T>() const {  // NOLINT(runtime/explicit)
+    return ::testing::Matcher<T>(new
+                                 typename Derived::template gmock_Impl<T>());
+  }
+};
+
+// Template specialization for Matcher with parameters.
+template <template <typename...> class Derived, typename... Ts>
+class MatcherBaseImpl<Derived<Ts...>> {
+ public:
+  // Mark the constructor explicit for single argument T to avoid implicit
+  // conversions.
+  template <typename E = std::enable_if<sizeof...(Ts) == 1>,
+            typename E::type* = nullptr>
+  explicit MatcherBaseImpl(Ts... params)
+      : params_(std::forward<Ts>(params)...) {}
+  template <typename E = std::enable_if<sizeof...(Ts) != 1>,
+            typename = typename E::type>
+  MatcherBaseImpl(Ts... params)  // NOLINT
+      : params_(std::forward<Ts>(params)...) {}
+
+  template <typename F>
+  operator ::testing::Matcher<F>() const {  // NOLINT(runtime/explicit)
+    return Apply<F>(MakeIndexSequence<sizeof...(Ts)>{});
+  }
+
+ private:
+  template <typename F, std::size_t... tuple_ids>
+  ::testing::Matcher<F> Apply(IndexSequence<tuple_ids...>) const {
+    return ::testing::Matcher<F>(
+        new typename Derived<Ts...>::template gmock_Impl<F>(
+            std::get<tuple_ids>(params_)...));
+  }
+
+  const std::tuple<Ts...> params_;
+};
+
 }  // namespace internal
 
 // In order to be safe and clear, casting between different matcher
@@ -2431,56 +3377,43 @@
   return internal::MatcherCastImpl<T, M>::Cast(matcher);
 }
 
-// Implements SafeMatcherCast().
-//
-// FIXME: The intermediate SafeMatcherCastImpl class was introduced as a
-// workaround for a compiler bug, and can now be removed.
-template <typename T>
-class SafeMatcherCastImpl {
- public:
-  // This overload handles polymorphic matchers and values only since
-  // monomorphic matchers are handled by the next one.
-  template <typename M>
-  static inline Matcher<T> Cast(const M& polymorphic_matcher_or_value) {
-    return internal::MatcherCastImpl<T, M>::Cast(polymorphic_matcher_or_value);
-  }
-
-  // This overload handles monomorphic matchers.
-  //
-  // In general, if type T can be implicitly converted to type U, we can
-  // safely convert a Matcher<U> to a Matcher<T> (i.e. Matcher is
-  // contravariant): just keep a copy of the original Matcher<U>, convert the
-  // argument from type T to U, and then pass it to the underlying Matcher<U>.
-  // The only exception is when U is a reference and T is not, as the
-  // underlying Matcher<U> may be interested in the argument's address, which
-  // is not preserved in the conversion from T to U.
-  template <typename U>
-  static inline Matcher<T> Cast(const Matcher<U>& matcher) {
-    // Enforce that T can be implicitly converted to U.
-    GTEST_COMPILE_ASSERT_((std::is_convertible<T, U>::value),
-                          "T must be implicitly convertible to U");
-    // Enforce that we are not converting a non-reference type T to a reference
-    // type U.
-    GTEST_COMPILE_ASSERT_(
-        internal::is_reference<T>::value || !internal::is_reference<U>::value,
-        cannot_convert_non_reference_arg_to_reference);
-    // In case both T and U are arithmetic types, enforce that the
-    // conversion is not lossy.
-    typedef GTEST_REMOVE_REFERENCE_AND_CONST_(T) RawT;
-    typedef GTEST_REMOVE_REFERENCE_AND_CONST_(U) RawU;
-    const bool kTIsOther = GMOCK_KIND_OF_(RawT) == internal::kOther;
-    const bool kUIsOther = GMOCK_KIND_OF_(RawU) == internal::kOther;
-    GTEST_COMPILE_ASSERT_(
-        kTIsOther || kUIsOther ||
-        (internal::LosslessArithmeticConvertible<RawT, RawU>::value),
-        conversion_of_arithmetic_types_must_be_lossless);
-    return MatcherCast<T>(matcher);
-  }
-};
-
+// This overload handles polymorphic matchers and values only since
+// monomorphic matchers are handled by the next one.
 template <typename T, typename M>
-inline Matcher<T> SafeMatcherCast(const M& polymorphic_matcher) {
-  return SafeMatcherCastImpl<T>::Cast(polymorphic_matcher);
+inline Matcher<T> SafeMatcherCast(const M& polymorphic_matcher_or_value) {
+  return MatcherCast<T>(polymorphic_matcher_or_value);
+}
+
+// This overload handles monomorphic matchers.
+//
+// In general, if type T can be implicitly converted to type U, we can
+// safely convert a Matcher<U> to a Matcher<T> (i.e. Matcher is
+// contravariant): just keep a copy of the original Matcher<U>, convert the
+// argument from type T to U, and then pass it to the underlying Matcher<U>.
+// The only exception is when U is a reference and T is not, as the
+// underlying Matcher<U> may be interested in the argument's address, which
+// is not preserved in the conversion from T to U.
+template <typename T, typename U>
+inline Matcher<T> SafeMatcherCast(const Matcher<U>& matcher) {
+  // Enforce that T can be implicitly converted to U.
+  static_assert(std::is_convertible<const T&, const U&>::value,
+                "T must be implicitly convertible to U");
+  // Enforce that we are not converting a non-reference type T to a reference
+  // type U.
+  GTEST_COMPILE_ASSERT_(
+      std::is_reference<T>::value || !std::is_reference<U>::value,
+      cannot_convert_non_reference_arg_to_reference);
+  // In case both T and U are arithmetic types, enforce that the
+  // conversion is not lossy.
+  typedef GTEST_REMOVE_REFERENCE_AND_CONST_(T) RawT;
+  typedef GTEST_REMOVE_REFERENCE_AND_CONST_(U) RawU;
+  constexpr bool kTIsOther = GMOCK_KIND_OF_(RawT) == internal::kOther;
+  constexpr bool kUIsOther = GMOCK_KIND_OF_(RawU) == internal::kOther;
+  GTEST_COMPILE_ASSERT_(
+      kTIsOther || kUIsOther ||
+      (internal::LosslessArithmeticConvertible<RawT, RawU>::value),
+      conversion_of_arithmetic_types_must_be_lossless);
+  return MatcherCast<T>(matcher);
 }
 
 // A<T>() returns a matcher that matches any value of type T.
@@ -2543,8 +3476,8 @@
 class TuplePrefix {
  public:
   // TuplePrefix<N>::Matches(matcher_tuple, value_tuple) returns true
-  // iff the first N fields of matcher_tuple matches the first N
-  // fields of value_tuple, respectively.
+  // if and only if the first N fields of matcher_tuple matches
+  // the first N fields of value_tuple, respectively.
   template <typename MatcherTuple, typename ValueTuple>
   static bool Matches(const MatcherTuple& matcher_tuple,
                       const ValueTuple& value_tuple) {
@@ -2602,8 +3535,8 @@
                                      ::std::ostream* /* os */) {}
 };
 
-// TupleMatches(matcher_tuple, value_tuple) returns true iff all
-// matchers in matcher_tuple match the corresponding fields in
+// TupleMatches(matcher_tuple, value_tuple) returns true if and only if
+// all matchers in matcher_tuple match the corresponding fields in
 // value_tuple.  It is a compiler error if matcher_tuple and
 // value_tuple have different number of fields or incompatible field
 // types.
@@ -2669,31 +3602,25 @@
   return TransformTupleValuesHelper<Tuple, Func, OutIter>::Run(f, t, out);
 }
 
-// Implements A<T>().
-template <typename T>
-class AnyMatcherImpl : public MatcherInterface<const T&> {
- public:
-  bool MatchAndExplain(const T& /* x */,
-                       MatchResultListener* /* listener */) const override {
-    return true;
-  }
-  void DescribeTo(::std::ostream* os) const override { *os << "is anything"; }
-  void DescribeNegationTo(::std::ostream* os) const override {
-    // This is mostly for completeness' safe, as it's not very useful
-    // to write Not(A<bool>()).  However we cannot completely rule out
-    // such a possibility, and it doesn't hurt to be prepared.
-    *os << "never matches";
-  }
-};
-
 // Implements _, a matcher that matches any value of any
 // type.  This is a polymorphic matcher, so we need a template type
 // conversion operator to make it appearing as a Matcher<T> for any
 // type T.
 class AnythingMatcher {
  public:
+  using is_gtest_matcher = void;
+
   template <typename T>
-  operator Matcher<T>() const { return A<T>(); }
+  bool MatchAndExplain(const T& /* x */, std::ostream* /* listener */) const {
+    return true;
+  }
+  void DescribeTo(std::ostream* os) const { *os << "is anything"; }
+  void DescribeNegationTo(::std::ostream* os) const {
+    // This is mostly for completeness' sake, as it's not very useful
+    // to write Not(A<bool>()).  However we cannot completely rule out
+    // such a possibility, and it doesn't hurt to be prepared.
+    *os << "never matches";
+  }
 };
 
 // Implements the polymorphic IsNull() matcher, which matches any raw or smart
@@ -2837,19 +3764,20 @@
 template <typename StringType>
 class StrEqualityMatcher {
  public:
-  StrEqualityMatcher(const StringType& str, bool expect_eq,
-                     bool case_sensitive)
-      : string_(str), expect_eq_(expect_eq), case_sensitive_(case_sensitive) {}
+  StrEqualityMatcher(StringType str, bool expect_eq, bool case_sensitive)
+      : string_(std::move(str)),
+        expect_eq_(expect_eq),
+        case_sensitive_(case_sensitive) {}
 
-#if GTEST_HAS_ABSL
-  bool MatchAndExplain(const absl::string_view& s,
+#if GTEST_INTERNAL_HAS_STRING_VIEW
+  bool MatchAndExplain(const internal::StringView& s,
                        MatchResultListener* listener) const {
-    // This should fail to compile if absl::string_view is used with wide
+    // This should fail to compile if StringView is used with wide
     // strings.
-    const StringType& str = string(s);
+    const StringType& str = std::string(s);
     return MatchAndExplain(str, listener);
   }
-#endif  // GTEST_HAS_ABSL
+#endif  // GTEST_INTERNAL_HAS_STRING_VIEW
 
   // Accepts pointer types, particularly:
   //   const char*
@@ -2867,11 +3795,11 @@
   // Matches anything that can convert to StringType.
   //
   // This is a template, not just a plain function with const StringType&,
-  // because absl::string_view has some interfering non-explicit constructors.
+  // because StringView has some interfering non-explicit constructors.
   template <typename MatcheeStringType>
   bool MatchAndExplain(const MatcheeStringType& s,
                        MatchResultListener* /* listener */) const {
-    const StringType& s2(s);
+    const StringType s2(s);
     const bool eq = case_sensitive_ ? s2 == string_ :
         CaseInsensitiveStringEquals(s2, string_);
     return expect_eq_ == eq;
@@ -2909,15 +3837,15 @@
   explicit HasSubstrMatcher(const StringType& substring)
       : substring_(substring) {}
 
-#if GTEST_HAS_ABSL
-  bool MatchAndExplain(const absl::string_view& s,
+#if GTEST_INTERNAL_HAS_STRING_VIEW
+  bool MatchAndExplain(const internal::StringView& s,
                        MatchResultListener* listener) const {
-    // This should fail to compile if absl::string_view is used with wide
+    // This should fail to compile if StringView is used with wide
     // strings.
-    const StringType& str = string(s);
+    const StringType& str = std::string(s);
     return MatchAndExplain(str, listener);
   }
-#endif  // GTEST_HAS_ABSL
+#endif  // GTEST_INTERNAL_HAS_STRING_VIEW
 
   // Accepts pointer types, particularly:
   //   const char*
@@ -2932,12 +3860,11 @@
   // Matches anything that can convert to StringType.
   //
   // This is a template, not just a plain function with const StringType&,
-  // because absl::string_view has some interfering non-explicit constructors.
+  // because StringView has some interfering non-explicit constructors.
   template <typename MatcheeStringType>
   bool MatchAndExplain(const MatcheeStringType& s,
                        MatchResultListener* /* listener */) const {
-    const StringType& s2(s);
-    return s2.find(substring_) != StringType::npos;
+    return StringType(s).find(substring_) != StringType::npos;
   }
 
   // Describes what this matcher matches.
@@ -2964,15 +3891,15 @@
   explicit StartsWithMatcher(const StringType& prefix) : prefix_(prefix) {
   }
 
-#if GTEST_HAS_ABSL
-  bool MatchAndExplain(const absl::string_view& s,
+#if GTEST_INTERNAL_HAS_STRING_VIEW
+  bool MatchAndExplain(const internal::StringView& s,
                        MatchResultListener* listener) const {
-    // This should fail to compile if absl::string_view is used with wide
+    // This should fail to compile if StringView is used with wide
     // strings.
-    const StringType& str = string(s);
+    const StringType& str = std::string(s);
     return MatchAndExplain(str, listener);
   }
-#endif  // GTEST_HAS_ABSL
+#endif  // GTEST_INTERNAL_HAS_STRING_VIEW
 
   // Accepts pointer types, particularly:
   //   const char*
@@ -2987,7 +3914,7 @@
   // Matches anything that can convert to StringType.
   //
   // This is a template, not just a plain function with const StringType&,
-  // because absl::string_view has some interfering non-explicit constructors.
+  // because StringView has some interfering non-explicit constructors.
   template <typename MatcheeStringType>
   bool MatchAndExplain(const MatcheeStringType& s,
                        MatchResultListener* /* listener */) const {
@@ -3018,15 +3945,15 @@
  public:
   explicit EndsWithMatcher(const StringType& suffix) : suffix_(suffix) {}
 
-#if GTEST_HAS_ABSL
-  bool MatchAndExplain(const absl::string_view& s,
+#if GTEST_INTERNAL_HAS_STRING_VIEW
+  bool MatchAndExplain(const internal::StringView& s,
                        MatchResultListener* listener) const {
-    // This should fail to compile if absl::string_view is used with wide
+    // This should fail to compile if StringView is used with wide
     // strings.
-    const StringType& str = string(s);
+    const StringType& str = std::string(s);
     return MatchAndExplain(str, listener);
   }
-#endif  // GTEST_HAS_ABSL
+#endif  // GTEST_INTERNAL_HAS_STRING_VIEW
 
   // Accepts pointer types, particularly:
   //   const char*
@@ -3041,7 +3968,7 @@
   // Matches anything that can convert to StringType.
   //
   // This is a template, not just a plain function with const StringType&,
-  // because absl::string_view has some interfering non-explicit constructors.
+  // because StringView has some interfering non-explicit constructors.
   template <typename MatcheeStringType>
   bool MatchAndExplain(const MatcheeStringType& s,
                        MatchResultListener* /* listener */) const {
@@ -3387,7 +4314,7 @@
   // interested in the address of the argument.
   template <typename T>
   bool MatchAndExplain(T& x,  // NOLINT
-                       MatchResultListener* /* listener */) const {
+                       MatchResultListener* listener) const {
     // Without the if-statement, MSVC sometimes warns about converting
     // a value to bool (warning 4800).
     //
@@ -3396,6 +4323,7 @@
     // having no operator!().
     if (predicate_(x))
       return true;
+    *listener << "didn't satisfy the given predicate";
     return false;
   }
 
@@ -3483,7 +4411,7 @@
        << "Expected: ";
     matcher.DescribeTo(&ss);
 
-    // Rerun the matcher to "PrintAndExain" the failure.
+    // Rerun the matcher to "PrintAndExplain" the failure.
     StringMatchResultListener listener;
     if (MatchPrintAndExplain(x, matcher, &listener)) {
       ss << "\n  The matcher failed on the initial attempt; but passed when "
@@ -3507,6 +4435,22 @@
   return PredicateFormatterFromMatcher<M>(std::move(matcher));
 }
 
+// Implements the polymorphic IsNan() matcher, which matches any floating type
+// value that is Nan.
+class IsNanMatcher {
+ public:
+  template <typename FloatType>
+  bool MatchAndExplain(const FloatType& f,
+                       MatchResultListener* /* listener */) const {
+    return (::std::isnan)(f);
+  }
+
+  void DescribeTo(::std::ostream* os) const { *os << "is NaN"; }
+  void DescribeNegationTo(::std::ostream* os) const {
+    *os << "isn't NaN";
+  }
+};
+
 // Implements the polymorphic floating point equality matcher, which matches
 // two float values using ULP-based approximation or, optionally, a
 // user-specified epsilon.  The template is meant to be instantiated with
@@ -3567,7 +4511,7 @@
         }
 
         const FloatType diff = value - expected_;
-        if (fabs(diff) <= max_abs_error_) {
+        if (::std::fabs(diff) <= max_abs_error_) {
           return true;
         }
 
@@ -3635,9 +4579,6 @@
   // The following 3 type conversion operators allow FloatEq(expected) and
   // NanSensitiveFloatEq(expected) to be used as a Matcher<float>, a
   // Matcher<const float&>, or a Matcher<float&>, but nothing else.
-  // (While Google's C++ coding style doesn't allow arguments passed
-  // by non-const reference, we may see them in code not conforming to
-  // the style.  Therefore Google Mock needs to support them.)
   operator Matcher<FloatType>() const {
     return MakeMatcher(
         new Impl<FloatType>(expected_, nan_eq_nan_, max_abs_error_));
@@ -3761,8 +4702,9 @@
   template <typename Pointer>
   class Impl : public MatcherInterface<Pointer> {
    public:
-    typedef typename PointeeOf<GTEST_REMOVE_CONST_(  // NOLINT
-        GTEST_REMOVE_REFERENCE_(Pointer))>::type Pointee;
+    using Pointee =
+        typename std::pointer_traits<GTEST_REMOVE_REFERENCE_AND_CONST_(
+            Pointer)>::element_type;
 
     explicit Impl(const InnerMatcher& matcher)
         : matcher_(MatcherCast<const Pointee&>(matcher)) {}
@@ -3792,6 +4734,64 @@
   const InnerMatcher matcher_;
 };
 
+// Implements the Pointer(m) matcher
+// Implements the Pointer(m) matcher for matching a pointer that matches matcher
+// m.  The pointer can be either raw or smart, and will match `m` against the
+// raw pointer.
+template <typename InnerMatcher>
+class PointerMatcher {
+ public:
+  explicit PointerMatcher(const InnerMatcher& matcher) : matcher_(matcher) {}
+
+  // This type conversion operator template allows Pointer(m) to be
+  // used as a matcher for any pointer type whose pointer type is
+  // compatible with the inner matcher, where type PointerType can be
+  // either a raw pointer or a smart pointer.
+  //
+  // The reason we do this instead of relying on
+  // MakePolymorphicMatcher() is that the latter is not flexible
+  // enough for implementing the DescribeTo() method of Pointer().
+  template <typename PointerType>
+  operator Matcher<PointerType>() const {  // NOLINT
+    return Matcher<PointerType>(new Impl<const PointerType&>(matcher_));
+  }
+
+ private:
+  // The monomorphic implementation that works for a particular pointer type.
+  template <typename PointerType>
+  class Impl : public MatcherInterface<PointerType> {
+   public:
+    using Pointer =
+        const typename std::pointer_traits<GTEST_REMOVE_REFERENCE_AND_CONST_(
+            PointerType)>::element_type*;
+
+    explicit Impl(const InnerMatcher& matcher)
+        : matcher_(MatcherCast<Pointer>(matcher)) {}
+
+    void DescribeTo(::std::ostream* os) const override {
+      *os << "is a pointer that ";
+      matcher_.DescribeTo(os);
+    }
+
+    void DescribeNegationTo(::std::ostream* os) const override {
+      *os << "is not a pointer that ";
+      matcher_.DescribeTo(os);
+    }
+
+    bool MatchAndExplain(PointerType pointer,
+                         MatchResultListener* listener) const override {
+      *listener << "which is a pointer that ";
+      Pointer p = GetRawPointer(pointer);
+      return MatchPrintAndExplain(p, matcher_, listener);
+    }
+
+   private:
+    Matcher<Pointer> matcher_;
+  };
+
+  const InnerMatcher matcher_;
+};
+
 #if GTEST_HAS_RTTI
 // Implements the WhenDynamicCastTo<T>(m) matcher that matches a pointer or
 // reference that matches inner_matcher when dynamic_cast<T> is applied.
@@ -3894,8 +4894,8 @@
     // FIXME: The dispatch on std::is_pointer was introduced as a workaround for
     // a compiler bug, and can now be removed.
     return MatchAndExplainImpl(
-        typename std::is_pointer<GTEST_REMOVE_CONST_(T)>::type(), value,
-        listener);
+        typename std::is_pointer<typename std::remove_const<T>::type>::type(),
+        value, listener);
   }
 
  private:
@@ -3959,8 +4959,8 @@
   template <typename T>
   bool MatchAndExplain(const T&value, MatchResultListener* listener) const {
     return MatchAndExplainImpl(
-        typename std::is_pointer<GTEST_REMOVE_CONST_(T)>::type(), value,
-        listener);
+        typename std::is_pointer<typename std::remove_const<T>::type>::type(),
+        value, listener);
   }
 
  private:
@@ -4002,7 +5002,9 @@
   static void CheckIsValid(Functor /* functor */) {}
 
   template <typename T>
-  static auto Invoke(Functor f, T arg) -> decltype(f(arg)) { return f(arg); }
+  static auto Invoke(Functor f, const T& arg) -> decltype(f(arg)) {
+    return f(arg);
+  }
 };
 
 // Specialization for function pointers.
@@ -4033,7 +5035,7 @@
 
   template <typename T>
   operator Matcher<T>() const {
-    return Matcher<T>(new Impl<T>(callable_, matcher_));
+    return Matcher<T>(new Impl<const T&>(callable_, matcher_));
   }
 
  private:
@@ -4204,15 +5206,15 @@
   typedef typename View::type StlContainer;
   typedef typename View::const_reference StlContainerReference;
 
+  static_assert(!std::is_const<Container>::value,
+                "Container type must not be const");
+  static_assert(!std::is_reference<Container>::value,
+                "Container type must not be a reference");
+
   // We make a copy of expected in case the elements in it are modified
   // after this matcher is created.
   explicit ContainerEqMatcher(const Container& expected)
-      : expected_(View::Copy(expected)) {
-    // Makes sure the user doesn't instantiate this class template
-    // with a const or reference type.
-    (void)testing::StaticAssertTypeEq<Container,
-        GTEST_REMOVE_REFERENCE_AND_CONST_(Container)>();
-  }
+      : expected_(View::Copy(expected)) {}
 
   void DescribeTo(::std::ostream* os) const {
     *os << "equals ";
@@ -4226,9 +5228,8 @@
   template <typename LhsContainer>
   bool MatchAndExplain(const LhsContainer& lhs,
                        MatchResultListener* listener) const {
-    // GTEST_REMOVE_CONST_() is needed to work around an MSVC 8.0 bug
-    // that causes LhsContainer to be a const type sometimes.
-    typedef internal::StlContainerView<GTEST_REMOVE_CONST_(LhsContainer)>
+    typedef internal::StlContainerView<
+        typename std::remove_const<LhsContainer>::type>
         LhsView;
     typedef typename LhsView::type LhsStlContainer;
     StlContainerReference lhs_stl_container = LhsView::ConstReference(lhs);
@@ -4376,15 +5377,15 @@
   typedef typename RhsView::type RhsStlContainer;
   typedef typename RhsStlContainer::value_type RhsValue;
 
+  static_assert(!std::is_const<RhsContainer>::value,
+                "RhsContainer type must not be const");
+  static_assert(!std::is_reference<RhsContainer>::value,
+                "RhsContainer type must not be a reference");
+
   // Like ContainerEq, we make a copy of rhs in case the elements in
   // it are modified after this matcher is created.
   PointwiseMatcher(const TupleMatcher& tuple_matcher, const RhsContainer& rhs)
-      : tuple_matcher_(tuple_matcher), rhs_(RhsView::Copy(rhs)) {
-    // Makes sure the user doesn't instantiate this class template
-    // with a const or reference type.
-    (void)testing::StaticAssertTypeEq<RhsContainer,
-        GTEST_REMOVE_REFERENCE_AND_CONST_(RhsContainer)>();
-  }
+      : tuple_matcher_(tuple_matcher), rhs_(RhsView::Copy(rhs)) {}
 
   template <typename LhsContainer>
   operator Matcher<LhsContainer>() const {
@@ -4647,7 +5648,8 @@
           testing::SafeMatcherCast<const KeyType&>(inner_matcher)) {
   }
 
-  // Returns true iff 'key_value.first' (the key) matches the inner matcher.
+  // Returns true if and only if 'key_value.first' (the key) matches the inner
+  // matcher.
   bool MatchAndExplain(PairType key_value,
                        MatchResultListener* listener) const override {
     StringMatchResultListener inner_listener;
@@ -4692,6 +5694,49 @@
   const M matcher_for_key_;
 };
 
+// Implements polymorphic Address(matcher_for_address).
+template <typename InnerMatcher>
+class AddressMatcher {
+ public:
+  explicit AddressMatcher(InnerMatcher m) : matcher_(m) {}
+
+  template <typename Type>
+  operator Matcher<Type>() const {  // NOLINT
+    return Matcher<Type>(new Impl<const Type&>(matcher_));
+  }
+
+ private:
+  // The monomorphic implementation that works for a particular object type.
+  template <typename Type>
+  class Impl : public MatcherInterface<Type> {
+   public:
+    using Address = const GTEST_REMOVE_REFERENCE_AND_CONST_(Type) *;
+    explicit Impl(const InnerMatcher& matcher)
+        : matcher_(MatcherCast<Address>(matcher)) {}
+
+    void DescribeTo(::std::ostream* os) const override {
+      *os << "has address that ";
+      matcher_.DescribeTo(os);
+    }
+
+    void DescribeNegationTo(::std::ostream* os) const override {
+      *os << "does not have address that ";
+      matcher_.DescribeTo(os);
+    }
+
+    bool MatchAndExplain(Type object,
+                         MatchResultListener* listener) const override {
+      *listener << "which has address ";
+      Address address = std::addressof(object);
+      return MatchPrintAndExplain(address, matcher_, listener);
+    }
+
+   private:
+    const Matcher<Address> matcher_;
+  };
+  const InnerMatcher matcher_;
+};
+
 // Implements Pair(first_matcher, second_matcher) for the given argument pair
 // type with its two matchers. See Pair() function below.
 template <typename PairType>
@@ -4725,8 +5770,8 @@
     second_matcher_.DescribeNegationTo(os);
   }
 
-  // Returns true iff 'a_pair.first' matches first_matcher and 'a_pair.second'
-  // matches second_matcher.
+  // Returns true if and only if 'a_pair.first' matches first_matcher and
+  // 'a_pair.second' matches second_matcher.
   bool MatchAndExplain(PairType a_pair,
                        MatchResultListener* listener) const override {
     if (!listener->IsInterested()) {
@@ -4795,6 +5840,203 @@
   const SecondMatcher second_matcher_;
 };
 
+template <typename T, size_t... I>
+auto UnpackStructImpl(const T& t, IndexSequence<I...>, int)
+    -> decltype(std::tie(get<I>(t)...)) {
+  static_assert(std::tuple_size<T>::value == sizeof...(I),
+                "Number of arguments doesn't match the number of fields.");
+  return std::tie(get<I>(t)...);
+}
+
+#if defined(__cpp_structured_bindings) && __cpp_structured_bindings >= 201606
+template <typename T>
+auto UnpackStructImpl(const T& t, MakeIndexSequence<1>, char) {
+  const auto& [a] = t;
+  return std::tie(a);
+}
+template <typename T>
+auto UnpackStructImpl(const T& t, MakeIndexSequence<2>, char) {
+  const auto& [a, b] = t;
+  return std::tie(a, b);
+}
+template <typename T>
+auto UnpackStructImpl(const T& t, MakeIndexSequence<3>, char) {
+  const auto& [a, b, c] = t;
+  return std::tie(a, b, c);
+}
+template <typename T>
+auto UnpackStructImpl(const T& t, MakeIndexSequence<4>, char) {
+  const auto& [a, b, c, d] = t;
+  return std::tie(a, b, c, d);
+}
+template <typename T>
+auto UnpackStructImpl(const T& t, MakeIndexSequence<5>, char) {
+  const auto& [a, b, c, d, e] = t;
+  return std::tie(a, b, c, d, e);
+}
+template <typename T>
+auto UnpackStructImpl(const T& t, MakeIndexSequence<6>, char) {
+  const auto& [a, b, c, d, e, f] = t;
+  return std::tie(a, b, c, d, e, f);
+}
+template <typename T>
+auto UnpackStructImpl(const T& t, MakeIndexSequence<7>, char) {
+  const auto& [a, b, c, d, e, f, g] = t;
+  return std::tie(a, b, c, d, e, f, g);
+}
+template <typename T>
+auto UnpackStructImpl(const T& t, MakeIndexSequence<8>, char) {
+  const auto& [a, b, c, d, e, f, g, h] = t;
+  return std::tie(a, b, c, d, e, f, g, h);
+}
+template <typename T>
+auto UnpackStructImpl(const T& t, MakeIndexSequence<9>, char) {
+  const auto& [a, b, c, d, e, f, g, h, i] = t;
+  return std::tie(a, b, c, d, e, f, g, h, i);
+}
+template <typename T>
+auto UnpackStructImpl(const T& t, MakeIndexSequence<10>, char) {
+  const auto& [a, b, c, d, e, f, g, h, i, j] = t;
+  return std::tie(a, b, c, d, e, f, g, h, i, j);
+}
+template <typename T>
+auto UnpackStructImpl(const T& t, MakeIndexSequence<11>, char) {
+  const auto& [a, b, c, d, e, f, g, h, i, j, k] = t;
+  return std::tie(a, b, c, d, e, f, g, h, i, j, k);
+}
+template <typename T>
+auto UnpackStructImpl(const T& t, MakeIndexSequence<12>, char) {
+  const auto& [a, b, c, d, e, f, g, h, i, j, k, l] = t;
+  return std::tie(a, b, c, d, e, f, g, h, i, j, k, l);
+}
+template <typename T>
+auto UnpackStructImpl(const T& t, MakeIndexSequence<13>, char) {
+  const auto& [a, b, c, d, e, f, g, h, i, j, k, l, m] = t;
+  return std::tie(a, b, c, d, e, f, g, h, i, j, k, l, m);
+}
+template <typename T>
+auto UnpackStructImpl(const T& t, MakeIndexSequence<14>, char) {
+  const auto& [a, b, c, d, e, f, g, h, i, j, k, l, m, n] = t;
+  return std::tie(a, b, c, d, e, f, g, h, i, j, k, l, m, n);
+}
+template <typename T>
+auto UnpackStructImpl(const T& t, MakeIndexSequence<15>, char) {
+  const auto& [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o] = t;
+  return std::tie(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o);
+}
+template <typename T>
+auto UnpackStructImpl(const T& t, MakeIndexSequence<16>, char) {
+  const auto& [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p] = t;
+  return std::tie(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p);
+}
+#endif  // defined(__cpp_structured_bindings)
+
+template <size_t I, typename T>
+auto UnpackStruct(const T& t)
+    -> decltype((UnpackStructImpl)(t, MakeIndexSequence<I>{}, 0)) {
+  return (UnpackStructImpl)(t, MakeIndexSequence<I>{}, 0);
+}
+
+// Helper function to do comma folding in C++11.
+// The array ensures left-to-right order of evaluation.
+// Usage: VariadicExpand({expr...});
+template <typename T, size_t N>
+void VariadicExpand(const T (&)[N]) {}
+
+template <typename Struct, typename StructSize>
+class FieldsAreMatcherImpl;
+
+template <typename Struct, size_t... I>
+class FieldsAreMatcherImpl<Struct, IndexSequence<I...>>
+    : public MatcherInterface<Struct> {
+  using UnpackedType =
+      decltype(UnpackStruct<sizeof...(I)>(std::declval<const Struct&>()));
+  using MatchersType = std::tuple<
+      Matcher<const typename std::tuple_element<I, UnpackedType>::type&>...>;
+
+ public:
+  template <typename Inner>
+  explicit FieldsAreMatcherImpl(const Inner& matchers)
+      : matchers_(testing::SafeMatcherCast<
+                  const typename std::tuple_element<I, UnpackedType>::type&>(
+            std::get<I>(matchers))...) {}
+
+  void DescribeTo(::std::ostream* os) const override {
+    const char* separator = "";
+    VariadicExpand(
+        {(*os << separator << "has field #" << I << " that ",
+          std::get<I>(matchers_).DescribeTo(os), separator = ", and ")...});
+  }
+
+  void DescribeNegationTo(::std::ostream* os) const override {
+    const char* separator = "";
+    VariadicExpand({(*os << separator << "has field #" << I << " that ",
+                     std::get<I>(matchers_).DescribeNegationTo(os),
+                     separator = ", or ")...});
+  }
+
+  bool MatchAndExplain(Struct t, MatchResultListener* listener) const override {
+    return MatchInternal((UnpackStruct<sizeof...(I)>)(t), listener);
+  }
+
+ private:
+  bool MatchInternal(UnpackedType tuple, MatchResultListener* listener) const {
+    if (!listener->IsInterested()) {
+      // If the listener is not interested, we don't need to construct the
+      // explanation.
+      bool good = true;
+      VariadicExpand({good = good && std::get<I>(matchers_).Matches(
+                                         std::get<I>(tuple))...});
+      return good;
+    }
+
+    size_t failed_pos = ~size_t{};
+
+    std::vector<StringMatchResultListener> inner_listener(sizeof...(I));
+
+    VariadicExpand(
+        {failed_pos == ~size_t{} && !std::get<I>(matchers_).MatchAndExplain(
+                                        std::get<I>(tuple), &inner_listener[I])
+             ? failed_pos = I
+             : 0 ...});
+    if (failed_pos != ~size_t{}) {
+      *listener << "whose field #" << failed_pos << " does not match";
+      PrintIfNotEmpty(inner_listener[failed_pos].str(), listener->stream());
+      return false;
+    }
+
+    *listener << "whose all elements match";
+    const char* separator = ", where";
+    for (size_t index = 0; index < sizeof...(I); ++index) {
+      const std::string str = inner_listener[index].str();
+      if (!str.empty()) {
+        *listener << separator << " field #" << index << " is a value " << str;
+        separator = ", and";
+      }
+    }
+
+    return true;
+  }
+
+  MatchersType matchers_;
+};
+
+template <typename... Inner>
+class FieldsAreMatcher {
+ public:
+  explicit FieldsAreMatcher(Inner... inner) : matchers_(std::move(inner)...) {}
+
+  template <typename Struct>
+  operator Matcher<Struct>() const {  // NOLINT
+    return Matcher<Struct>(
+        new FieldsAreMatcherImpl<const Struct&, IndexSequenceFor<Inner...>>(
+            matchers_));
+  }
+
+ private:
+  std::tuple<Inner...> matchers_;
+};
+
 // Implements ElementsAre() and ElementsAreArray().
 template <typename Container>
 class ElementsAreMatcherImpl : public MatcherInterface<Container> {
@@ -5062,7 +6304,9 @@
       : UnorderedElementsAreMatcherImplBase(matcher_flags) {
     for (; first != last; ++first) {
       matchers_.push_back(MatcherCast<const Element&>(*first));
-      matcher_describers().push_back(matchers_.back().GetDescriber());
+    }
+    for (const auto& m : matchers_) {
+      matcher_describers().push_back(m.GetDescriber());
     }
   }
 
@@ -5113,12 +6357,14 @@
     element_printouts->clear();
     ::std::vector<char> did_match;
     size_t num_elements = 0;
+    DummyMatchResultListener dummy;
     for (; elem_first != elem_last; ++num_elements, ++elem_first) {
       if (listener->IsInterested()) {
         element_printouts->push_back(PrintToString(*elem_first));
       }
       for (size_t irhs = 0; irhs != matchers_.size(); ++irhs) {
-        did_match.push_back(Matches(matchers_[irhs])(*elem_first));
+        did_match.push_back(
+            matchers_[irhs].MatchAndExplain(*elem_first, &dummy));
       }
     }
 
@@ -5245,8 +6491,8 @@
 
 // Given a 2-tuple matcher tm of type Tuple2Matcher and a value second
 // of type Second, BoundSecondMatcher<Tuple2Matcher, Second>(tm,
-// second) is a polymorphic matcher that matches a value x iff tm
-// matches tuple (x, second).  Useful for implementing
+// second) is a polymorphic matcher that matches a value x if and only if
+// tm matches tuple (x, second).  Useful for implementing
 // UnorderedPointwise() in terms of UnorderedElementsAreArray().
 //
 // BoundSecondMatcher is copyable and assignable, as we need to put
@@ -5258,6 +6504,8 @@
   BoundSecondMatcher(const Tuple2Matcher& tm, const Second& second)
       : tuple2_matcher_(tm), second_value_(second) {}
 
+  BoundSecondMatcher(const BoundSecondMatcher& other) = default;
+
   template <typename T>
   operator Matcher<T>() const {
     return MakeMatcher(new Impl<T>(tuple2_matcher_, second_value_));
@@ -5308,8 +6556,8 @@
 
 // Given a 2-tuple matcher tm and a value second,
 // MatcherBindSecond(tm, second) returns a matcher that matches a
-// value x iff tm matches tuple (x, second).  Useful for implementing
-// UnorderedPointwise() in terms of UnorderedElementsAreArray().
+// value x if and only if tm matches tuple (x, second).  Useful for
+// implementing UnorderedPointwise() in terms of UnorderedElementsAreArray().
 template <typename Tuple2Matcher, typename Second>
 BoundSecondMatcher<Tuple2Matcher, Second> MatcherBindSecond(
     const Tuple2Matcher& tm, const Second& second) {
@@ -5683,18 +6931,19 @@
 // Creates a matcher that matches any value of the given type T.
 template <typename T>
 inline Matcher<T> A() {
-  return Matcher<T>(new internal::AnyMatcherImpl<T>());
+  return _;
 }
 
 // Creates a matcher that matches any value of the given type T.
 template <typename T>
-inline Matcher<T> An() { return A<T>(); }
+inline Matcher<T> An() {
+  return _;
+}
 
 template <typename T, typename M>
 Matcher<T> internal::MatcherCastImpl<T, M>::CastImpl(
-    const M& value,
-    internal::BooleanConstant<false> /* convertible_to_matcher */,
-    internal::BooleanConstant<false> /* convertible_to_T */) {
+    const M& value, std::false_type /* convertible_to_matcher */,
+    std::false_type /* convertible_to_T */) {
   return Eq(value);
 }
 
@@ -5717,6 +6966,11 @@
   return internal::RefMatcher<T&>(x);
 }
 
+// Creates a polymorphic matcher that matches any NaN floating point.
+inline PolymorphicMatcher<internal::IsNanMatcher> IsNan() {
+  return MakePolymorphicMatcher(internal::IsNanMatcher());
+}
+
 // Creates a matcher that matches any double argument approximately
 // equal to rhs, where two NANs are considered unequal.
 inline internal::FloatingEqMatcher<double> DoubleEq(double rhs) {
@@ -5799,7 +7053,7 @@
 // Creates a matcher that matches an object whose given field matches
 // 'matcher'.  For example,
 //   Field(&Foo::number, Ge(5))
-// matches a Foo object x iff x.number >= 5.
+// matches a Foo object x if and only if x.number >= 5.
 template <typename Class, typename FieldType, typename FieldMatcher>
 inline PolymorphicMatcher<
   internal::FieldMatcher<Class, FieldType> > Field(
@@ -5826,7 +7080,7 @@
 // Creates a matcher that matches an object whose given property
 // matches 'matcher'.  For example,
 //   Property(&Foo::str, StartsWith("hi"))
-// matches a Foo object x iff x.str() starts with "hi".
+// matches a Foo object x if and only if x.str() starts with "hi".
 template <typename Class, typename PropertyType, typename PropertyMatcher>
 inline PolymorphicMatcher<internal::PropertyMatcher<
     Class, PropertyType, PropertyType (Class::*)() const> >
@@ -5881,11 +7135,10 @@
           property_name, property, MatcherCast<const PropertyType&>(matcher)));
 }
 
-// Creates a matcher that matches an object iff the result of applying
-// a callable to x matches 'matcher'.
-// For example,
+// Creates a matcher that matches an object if and only if the result of
+// applying a callable to x matches 'matcher'. For example,
 //   ResultOf(f, StartsWith("hi"))
-// matches a Foo object x iff f(x) starts with "hi".
+// matches a Foo object x if and only if f(x) starts with "hi".
 // `callable` parameter can be a function, function pointer, or a functor. It is
 // required to keep no state affecting the results of the calls on it and make
 // no assumptions about how many calls will be made. Any state it keeps must be
@@ -5900,55 +7153,63 @@
 // String matchers.
 
 // Matches a string equal to str.
-inline PolymorphicMatcher<internal::StrEqualityMatcher<std::string> > StrEq(
-    const std::string& str) {
+template <typename T = std::string>
+PolymorphicMatcher<internal::StrEqualityMatcher<std::string> > StrEq(
+    const internal::StringLike<T>& str) {
   return MakePolymorphicMatcher(
-      internal::StrEqualityMatcher<std::string>(str, true, true));
+      internal::StrEqualityMatcher<std::string>(std::string(str), true, true));
 }
 
 // Matches a string not equal to str.
-inline PolymorphicMatcher<internal::StrEqualityMatcher<std::string> > StrNe(
-    const std::string& str) {
+template <typename T = std::string>
+PolymorphicMatcher<internal::StrEqualityMatcher<std::string> > StrNe(
+    const internal::StringLike<T>& str) {
   return MakePolymorphicMatcher(
-      internal::StrEqualityMatcher<std::string>(str, false, true));
+      internal::StrEqualityMatcher<std::string>(std::string(str), false, true));
 }
 
 // Matches a string equal to str, ignoring case.
-inline PolymorphicMatcher<internal::StrEqualityMatcher<std::string> > StrCaseEq(
-    const std::string& str) {
+template <typename T = std::string>
+PolymorphicMatcher<internal::StrEqualityMatcher<std::string> > StrCaseEq(
+    const internal::StringLike<T>& str) {
   return MakePolymorphicMatcher(
-      internal::StrEqualityMatcher<std::string>(str, true, false));
+      internal::StrEqualityMatcher<std::string>(std::string(str), true, false));
 }
 
 // Matches a string not equal to str, ignoring case.
-inline PolymorphicMatcher<internal::StrEqualityMatcher<std::string> > StrCaseNe(
-    const std::string& str) {
-  return MakePolymorphicMatcher(
-      internal::StrEqualityMatcher<std::string>(str, false, false));
+template <typename T = std::string>
+PolymorphicMatcher<internal::StrEqualityMatcher<std::string> > StrCaseNe(
+    const internal::StringLike<T>& str) {
+  return MakePolymorphicMatcher(internal::StrEqualityMatcher<std::string>(
+      std::string(str), false, false));
 }
 
 // Creates a matcher that matches any string, std::string, or C string
 // that contains the given substring.
-inline PolymorphicMatcher<internal::HasSubstrMatcher<std::string> > HasSubstr(
-    const std::string& substring) {
+template <typename T = std::string>
+PolymorphicMatcher<internal::HasSubstrMatcher<std::string> > HasSubstr(
+    const internal::StringLike<T>& substring) {
   return MakePolymorphicMatcher(
-      internal::HasSubstrMatcher<std::string>(substring));
+      internal::HasSubstrMatcher<std::string>(std::string(substring)));
 }
 
 // Matches a string that starts with 'prefix' (case-sensitive).
-inline PolymorphicMatcher<internal::StartsWithMatcher<std::string> > StartsWith(
-    const std::string& prefix) {
+template <typename T = std::string>
+PolymorphicMatcher<internal::StartsWithMatcher<std::string> > StartsWith(
+    const internal::StringLike<T>& prefix) {
   return MakePolymorphicMatcher(
-      internal::StartsWithMatcher<std::string>(prefix));
+      internal::StartsWithMatcher<std::string>(std::string(prefix)));
 }
 
 // Matches a string that ends with 'suffix' (case-sensitive).
-inline PolymorphicMatcher<internal::EndsWithMatcher<std::string> > EndsWith(
-    const std::string& suffix) {
-  return MakePolymorphicMatcher(internal::EndsWithMatcher<std::string>(suffix));
+template <typename T = std::string>
+PolymorphicMatcher<internal::EndsWithMatcher<std::string> > EndsWith(
+    const internal::StringLike<T>& suffix) {
+  return MakePolymorphicMatcher(
+      internal::EndsWithMatcher<std::string>(std::string(suffix)));
 }
 
-#if GTEST_HAS_GLOBAL_WSTRING || GTEST_HAS_STD_WSTRING
+#if GTEST_HAS_STD_WSTRING
 // Wide string matchers.
 
 // Matches a string equal to str.
@@ -6001,7 +7262,7 @@
       internal::EndsWithMatcher<std::wstring>(suffix));
 }
 
-#endif  // GTEST_HAS_GLOBAL_WSTRING || GTEST_HAS_STD_WSTRING
+#endif  // GTEST_HAS_STD_WSTRING
 
 // Creates a polymorphic matcher that matches a 2-tuple where the
 // first field == the second field.
@@ -6123,14 +7384,10 @@
 // values that are included in one container but not the other. (Duplicate
 // values and order differences are not explained.)
 template <typename Container>
-inline PolymorphicMatcher<internal::ContainerEqMatcher<  // NOLINT
-                            GTEST_REMOVE_CONST_(Container)> >
-    ContainerEq(const Container& rhs) {
-  // This following line is for working around a bug in MSVC 8.0,
-  // which causes Container to be a const type sometimes.
-  typedef GTEST_REMOVE_CONST_(Container) RawContainer;
-  return MakePolymorphicMatcher(
-      internal::ContainerEqMatcher<RawContainer>(rhs));
+inline PolymorphicMatcher<internal::ContainerEqMatcher<
+    typename std::remove_const<Container>::type>>
+ContainerEq(const Container& rhs) {
+  return MakePolymorphicMatcher(internal::ContainerEqMatcher<Container>(rhs));
 }
 
 // Returns a matcher that matches a container that, when sorted using
@@ -6161,14 +7418,10 @@
 // LHS container and the RHS container respectively.
 template <typename TupleMatcher, typename Container>
 inline internal::PointwiseMatcher<TupleMatcher,
-                                  GTEST_REMOVE_CONST_(Container)>
+                                  typename std::remove_const<Container>::type>
 Pointwise(const TupleMatcher& tuple_matcher, const Container& rhs) {
-  // This following line is for working around a bug in MSVC 8.0,
-  // which causes Container to be a const type sometimes (e.g. when
-  // rhs is a const int[])..
-  typedef GTEST_REMOVE_CONST_(Container) RawContainer;
-  return internal::PointwiseMatcher<TupleMatcher, RawContainer>(
-      tuple_matcher, rhs);
+  return internal::PointwiseMatcher<TupleMatcher, Container>(tuple_matcher,
+                                                             rhs);
 }
 
 
@@ -6194,18 +7447,14 @@
 template <typename Tuple2Matcher, typename RhsContainer>
 inline internal::UnorderedElementsAreArrayMatcher<
     typename internal::BoundSecondMatcher<
-        Tuple2Matcher, typename internal::StlContainerView<GTEST_REMOVE_CONST_(
-                           RhsContainer)>::type::value_type> >
+        Tuple2Matcher,
+        typename internal::StlContainerView<
+            typename std::remove_const<RhsContainer>::type>::type::value_type>>
 UnorderedPointwise(const Tuple2Matcher& tuple2_matcher,
                    const RhsContainer& rhs_container) {
-  // This following line is for working around a bug in MSVC 8.0,
-  // which causes RhsContainer to be a const type sometimes (e.g. when
-  // rhs_container is a const int[]).
-  typedef GTEST_REMOVE_CONST_(RhsContainer) RawRhsContainer;
-
   // RhsView allows the same code to handle RhsContainer being a
   // STL-style container and it being a native C-style array.
-  typedef typename internal::StlContainerView<RawRhsContainer> RhsView;
+  typedef typename internal::StlContainerView<RhsContainer> RhsView;
   typedef typename RhsView::type RhsStlContainer;
   typedef typename RhsStlContainer::value_type Second;
   const RhsStlContainer& rhs_stl_container =
@@ -6427,6 +7676,35 @@
       first_matcher, second_matcher);
 }
 
+namespace no_adl {
+// FieldsAre(matchers...) matches piecewise the fields of compatible structs.
+// These include those that support `get<I>(obj)`, and when structured bindings
+// are enabled any class that supports them.
+// In particular, `std::tuple`, `std::pair`, `std::array` and aggregate types.
+template <typename... M>
+internal::FieldsAreMatcher<typename std::decay<M>::type...> FieldsAre(
+    M&&... matchers) {
+  return internal::FieldsAreMatcher<typename std::decay<M>::type...>(
+      std::forward<M>(matchers)...);
+}
+
+// Creates a matcher that matches a pointer (raw or smart) that matches
+// inner_matcher.
+template <typename InnerMatcher>
+inline internal::PointerMatcher<InnerMatcher> Pointer(
+    const InnerMatcher& inner_matcher) {
+  return internal::PointerMatcher<InnerMatcher>(inner_matcher);
+}
+
+// Creates a matcher that matches an object that has an address that matches
+// inner_matcher.
+template <typename InnerMatcher>
+inline internal::AddressMatcher<InnerMatcher> Address(
+    const InnerMatcher& inner_matcher) {
+  return internal::AddressMatcher<InnerMatcher>(inner_matcher);
+}
+}  // namespace no_adl
+
 // Returns a predicate that is satisfied by anything that matches the
 // given matcher.
 template <typename M>
@@ -6434,7 +7712,7 @@
   return internal::MatcherAsPredicate<M>(matcher);
 }
 
-// Returns true iff the value matches the matcher.
+// Returns true if and only if the value matches the matcher.
 template <typename T, typename M>
 inline bool Value(const T& value, M matcher) {
   return testing::Matches(matcher)(value);
@@ -6611,7 +7889,7 @@
 // and is printable using 'PrintToString'. It is compatible with
 // std::optional/std::experimental::optional.
 // Note that to compare an optional type variable against nullopt you should
-// use Eq(nullopt) and not Optional(Eq(nullopt)). The latter implies that the
+// use Eq(nullopt) and not Eq(Optional(nullopt)). The latter implies that the
 // optional value contains an optional itself.
 template <typename ValueMatcher>
 inline internal::OptionalMatcher<ValueMatcher> Optional(
@@ -6638,15 +7916,337 @@
       internal::variant_matcher::VariantMatcher<T>(matcher));
 }
 
+#if GTEST_HAS_EXCEPTIONS
+
+// Anything inside the `internal` namespace is internal to the implementation
+// and must not be used in user code!
+namespace internal {
+
+class WithWhatMatcherImpl {
+ public:
+  WithWhatMatcherImpl(Matcher<std::string> matcher)
+      : matcher_(std::move(matcher)) {}
+
+  void DescribeTo(std::ostream* os) const {
+    *os << "contains .what() that ";
+    matcher_.DescribeTo(os);
+  }
+
+  void DescribeNegationTo(std::ostream* os) const {
+    *os << "contains .what() that does not ";
+    matcher_.DescribeTo(os);
+  }
+
+  template <typename Err>
+  bool MatchAndExplain(const Err& err, MatchResultListener* listener) const {
+    *listener << "which contains .what() that ";
+    return matcher_.MatchAndExplain(err.what(), listener);
+  }
+
+ private:
+  const Matcher<std::string> matcher_;
+};
+
+inline PolymorphicMatcher<WithWhatMatcherImpl> WithWhat(
+    Matcher<std::string> m) {
+  return MakePolymorphicMatcher(WithWhatMatcherImpl(std::move(m)));
+}
+
+template <typename Err>
+class ExceptionMatcherImpl {
+  class NeverThrown {
+   public:
+    const char* what() const noexcept {
+      return "this exception should never be thrown";
+    }
+  };
+
+  // If the matchee raises an exception of a wrong type, we'd like to
+  // catch it and print its message and type. To do that, we add an additional
+  // catch clause:
+  //
+  //     try { ... }
+  //     catch (const Err&) { /* an expected exception */ }
+  //     catch (const std::exception&) { /* exception of a wrong type */ }
+  //
+  // However, if the `Err` itself is `std::exception`, we'd end up with two
+  // identical `catch` clauses:
+  //
+  //     try { ... }
+  //     catch (const std::exception&) { /* an expected exception */ }
+  //     catch (const std::exception&) { /* exception of a wrong type */ }
+  //
+  // This can cause a warning or an error in some compilers. To resolve
+  // the issue, we use a fake error type whenever `Err` is `std::exception`:
+  //
+  //     try { ... }
+  //     catch (const std::exception&) { /* an expected exception */ }
+  //     catch (const NeverThrown&) { /* exception of a wrong type */ }
+  using DefaultExceptionType = typename std::conditional<
+      std::is_same<typename std::remove_cv<
+                       typename std::remove_reference<Err>::type>::type,
+                   std::exception>::value,
+      const NeverThrown&, const std::exception&>::type;
+
+ public:
+  ExceptionMatcherImpl(Matcher<const Err&> matcher)
+      : matcher_(std::move(matcher)) {}
+
+  void DescribeTo(std::ostream* os) const {
+    *os << "throws an exception which is a " << GetTypeName<Err>();
+    *os << " which ";
+    matcher_.DescribeTo(os);
+  }
+
+  void DescribeNegationTo(std::ostream* os) const {
+    *os << "throws an exception which is not a " << GetTypeName<Err>();
+    *os << " which ";
+    matcher_.DescribeNegationTo(os);
+  }
+
+  template <typename T>
+  bool MatchAndExplain(T&& x, MatchResultListener* listener) const {
+    try {
+      (void)(std::forward<T>(x)());
+    } catch (const Err& err) {
+      *listener << "throws an exception which is a " << GetTypeName<Err>();
+      *listener << " ";
+      return matcher_.MatchAndExplain(err, listener);
+    } catch (DefaultExceptionType err) {
+#if GTEST_HAS_RTTI
+      *listener << "throws an exception of type " << GetTypeName(typeid(err));
+      *listener << " ";
+#else
+      *listener << "throws an std::exception-derived type ";
+#endif
+      *listener << "with description \"" << err.what() << "\"";
+      return false;
+    } catch (...) {
+      *listener << "throws an exception of an unknown type";
+      return false;
+    }
+
+    *listener << "does not throw any exception";
+    return false;
+  }
+
+ private:
+  const Matcher<const Err&> matcher_;
+};
+
+}  // namespace internal
+
+// Throws()
+// Throws(exceptionMatcher)
+// ThrowsMessage(messageMatcher)
+//
+// This matcher accepts a callable and verifies that when invoked, it throws
+// an exception with the given type and properties.
+//
+// Examples:
+//
+//   EXPECT_THAT(
+//       []() { throw std::runtime_error("message"); },
+//       Throws<std::runtime_error>());
+//
+//   EXPECT_THAT(
+//       []() { throw std::runtime_error("message"); },
+//       ThrowsMessage<std::runtime_error>(HasSubstr("message")));
+//
+//   EXPECT_THAT(
+//       []() { throw std::runtime_error("message"); },
+//       Throws<std::runtime_error>(
+//           Property(&std::runtime_error::what, HasSubstr("message"))));
+
+template <typename Err>
+PolymorphicMatcher<internal::ExceptionMatcherImpl<Err>> Throws() {
+  return MakePolymorphicMatcher(
+      internal::ExceptionMatcherImpl<Err>(A<const Err&>()));
+}
+
+template <typename Err, typename ExceptionMatcher>
+PolymorphicMatcher<internal::ExceptionMatcherImpl<Err>> Throws(
+    const ExceptionMatcher& exception_matcher) {
+  // Using matcher cast allows users to pass a matcher of a more broad type.
+  // For example user may want to pass Matcher<std::exception>
+  // to Throws<std::runtime_error>, or Matcher<int64> to Throws<int32>.
+  return MakePolymorphicMatcher(internal::ExceptionMatcherImpl<Err>(
+      SafeMatcherCast<const Err&>(exception_matcher)));
+}
+
+template <typename Err, typename MessageMatcher>
+PolymorphicMatcher<internal::ExceptionMatcherImpl<Err>> ThrowsMessage(
+    MessageMatcher&& message_matcher) {
+  static_assert(std::is_base_of<std::exception, Err>::value,
+                "expected an std::exception-derived type");
+  return Throws<Err>(internal::WithWhat(
+      MatcherCast<std::string>(std::forward<MessageMatcher>(message_matcher))));
+}
+
+#endif  // GTEST_HAS_EXCEPTIONS
+
 // These macros allow using matchers to check values in Google Test
 // tests.  ASSERT_THAT(value, matcher) and EXPECT_THAT(value, matcher)
-// succeed iff the value matches the matcher.  If the assertion fails,
-// the value and the description of the matcher will be printed.
+// succeed if and only if the value matches the matcher.  If the assertion
+// fails, the value and the description of the matcher will be printed.
 #define ASSERT_THAT(value, matcher) ASSERT_PRED_FORMAT1(\
     ::testing::internal::MakePredicateFormatterFromMatcher(matcher), value)
 #define EXPECT_THAT(value, matcher) EXPECT_PRED_FORMAT1(\
     ::testing::internal::MakePredicateFormatterFromMatcher(matcher), value)
 
+// MATCHER* macroses itself are listed below.
+#define MATCHER(name, description)                                             \
+  class name##Matcher                                                          \
+      : public ::testing::internal::MatcherBaseImpl<name##Matcher> {           \
+   public:                                                                     \
+    template <typename arg_type>                                               \
+    class gmock_Impl : public ::testing::MatcherInterface<const arg_type&> {   \
+     public:                                                                   \
+      gmock_Impl() {}                                                          \
+      bool MatchAndExplain(                                                    \
+          const arg_type& arg,                                                 \
+          ::testing::MatchResultListener* result_listener) const override;     \
+      void DescribeTo(::std::ostream* gmock_os) const override {               \
+        *gmock_os << FormatDescription(false);                                 \
+      }                                                                        \
+      void DescribeNegationTo(::std::ostream* gmock_os) const override {       \
+        *gmock_os << FormatDescription(true);                                  \
+      }                                                                        \
+                                                                               \
+     private:                                                                  \
+      ::std::string FormatDescription(bool negation) const {                   \
+        ::std::string gmock_description = (description);                       \
+        if (!gmock_description.empty()) {                                      \
+          return gmock_description;                                            \
+        }                                                                      \
+        return ::testing::internal::FormatMatcherDescription(negation, #name,  \
+                                                             {});              \
+      }                                                                        \
+    };                                                                         \
+  };                                                                           \
+  GTEST_ATTRIBUTE_UNUSED_ inline name##Matcher name() { return {}; }           \
+  template <typename arg_type>                                                 \
+  bool name##Matcher::gmock_Impl<arg_type>::MatchAndExplain(                   \
+      const arg_type& arg,                                                     \
+      ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_) \
+      const
+
+#define MATCHER_P(name, p0, description) \
+  GMOCK_INTERNAL_MATCHER(name, name##MatcherP, description, (p0))
+#define MATCHER_P2(name, p0, p1, description) \
+  GMOCK_INTERNAL_MATCHER(name, name##MatcherP2, description, (p0, p1))
+#define MATCHER_P3(name, p0, p1, p2, description) \
+  GMOCK_INTERNAL_MATCHER(name, name##MatcherP3, description, (p0, p1, p2))
+#define MATCHER_P4(name, p0, p1, p2, p3, description) \
+  GMOCK_INTERNAL_MATCHER(name, name##MatcherP4, description, (p0, p1, p2, p3))
+#define MATCHER_P5(name, p0, p1, p2, p3, p4, description)    \
+  GMOCK_INTERNAL_MATCHER(name, name##MatcherP5, description, \
+                         (p0, p1, p2, p3, p4))
+#define MATCHER_P6(name, p0, p1, p2, p3, p4, p5, description) \
+  GMOCK_INTERNAL_MATCHER(name, name##MatcherP6, description,  \
+                         (p0, p1, p2, p3, p4, p5))
+#define MATCHER_P7(name, p0, p1, p2, p3, p4, p5, p6, description) \
+  GMOCK_INTERNAL_MATCHER(name, name##MatcherP7, description,      \
+                         (p0, p1, p2, p3, p4, p5, p6))
+#define MATCHER_P8(name, p0, p1, p2, p3, p4, p5, p6, p7, description) \
+  GMOCK_INTERNAL_MATCHER(name, name##MatcherP8, description,          \
+                         (p0, p1, p2, p3, p4, p5, p6, p7))
+#define MATCHER_P9(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, description) \
+  GMOCK_INTERNAL_MATCHER(name, name##MatcherP9, description,              \
+                         (p0, p1, p2, p3, p4, p5, p6, p7, p8))
+#define MATCHER_P10(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, description) \
+  GMOCK_INTERNAL_MATCHER(name, name##MatcherP10, description,                  \
+                         (p0, p1, p2, p3, p4, p5, p6, p7, p8, p9))
+
+#define GMOCK_INTERNAL_MATCHER(name, full_name, description, args)             \
+  template <GMOCK_INTERNAL_MATCHER_TEMPLATE_PARAMS(args)>                      \
+  class full_name : public ::testing::internal::MatcherBaseImpl<               \
+                        full_name<GMOCK_INTERNAL_MATCHER_TYPE_PARAMS(args)>> { \
+   public:                                                                     \
+    using full_name::MatcherBaseImpl::MatcherBaseImpl;                         \
+    template <typename arg_type>                                               \
+    class gmock_Impl : public ::testing::MatcherInterface<const arg_type&> {   \
+     public:                                                                   \
+      explicit gmock_Impl(GMOCK_INTERNAL_MATCHER_FUNCTION_ARGS(args))          \
+          : GMOCK_INTERNAL_MATCHER_FORWARD_ARGS(args) {}                       \
+      bool MatchAndExplain(                                                    \
+          const arg_type& arg,                                                 \
+          ::testing::MatchResultListener* result_listener) const override;     \
+      void DescribeTo(::std::ostream* gmock_os) const override {               \
+        *gmock_os << FormatDescription(false);                                 \
+      }                                                                        \
+      void DescribeNegationTo(::std::ostream* gmock_os) const override {       \
+        *gmock_os << FormatDescription(true);                                  \
+      }                                                                        \
+      GMOCK_INTERNAL_MATCHER_MEMBERS(args)                                     \
+                                                                               \
+     private:                                                                  \
+      ::std::string FormatDescription(bool negation) const {                   \
+        ::std::string gmock_description = (description);                       \
+        if (!gmock_description.empty()) {                                      \
+          return gmock_description;                                            \
+        }                                                                      \
+        return ::testing::internal::FormatMatcherDescription(                  \
+            negation, #name,                                                   \
+            ::testing::internal::UniversalTersePrintTupleFieldsToStrings(      \
+                ::std::tuple<GMOCK_INTERNAL_MATCHER_TYPE_PARAMS(args)>(        \
+                    GMOCK_INTERNAL_MATCHER_MEMBERS_USAGE(args))));             \
+      }                                                                        \
+    };                                                                         \
+  };                                                                           \
+  template <GMOCK_INTERNAL_MATCHER_TEMPLATE_PARAMS(args)>                      \
+  inline full_name<GMOCK_INTERNAL_MATCHER_TYPE_PARAMS(args)> name(             \
+      GMOCK_INTERNAL_MATCHER_FUNCTION_ARGS(args)) {                            \
+    return full_name<GMOCK_INTERNAL_MATCHER_TYPE_PARAMS(args)>(                \
+        GMOCK_INTERNAL_MATCHER_ARGS_USAGE(args));                              \
+  }                                                                            \
+  template <GMOCK_INTERNAL_MATCHER_TEMPLATE_PARAMS(args)>                      \
+  template <typename arg_type>                                                 \
+  bool full_name<GMOCK_INTERNAL_MATCHER_TYPE_PARAMS(args)>::gmock_Impl<        \
+      arg_type>::MatchAndExplain(const arg_type& arg,                          \
+                                 ::testing::MatchResultListener*               \
+                                     result_listener GTEST_ATTRIBUTE_UNUSED_)  \
+      const
+
+#define GMOCK_INTERNAL_MATCHER_TEMPLATE_PARAMS(args) \
+  GMOCK_PP_TAIL(                                     \
+      GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_MATCHER_TEMPLATE_PARAM, , args))
+#define GMOCK_INTERNAL_MATCHER_TEMPLATE_PARAM(i_unused, data_unused, arg) \
+  , typename arg##_type
+
+#define GMOCK_INTERNAL_MATCHER_TYPE_PARAMS(args) \
+  GMOCK_PP_TAIL(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_MATCHER_TYPE_PARAM, , args))
+#define GMOCK_INTERNAL_MATCHER_TYPE_PARAM(i_unused, data_unused, arg) \
+  , arg##_type
+
+#define GMOCK_INTERNAL_MATCHER_FUNCTION_ARGS(args) \
+  GMOCK_PP_TAIL(dummy_first GMOCK_PP_FOR_EACH(     \
+      GMOCK_INTERNAL_MATCHER_FUNCTION_ARG, , args))
+#define GMOCK_INTERNAL_MATCHER_FUNCTION_ARG(i, data_unused, arg) \
+  , arg##_type gmock_p##i
+
+#define GMOCK_INTERNAL_MATCHER_FORWARD_ARGS(args) \
+  GMOCK_PP_TAIL(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_MATCHER_FORWARD_ARG, , args))
+#define GMOCK_INTERNAL_MATCHER_FORWARD_ARG(i, data_unused, arg) \
+  , arg(::std::forward<arg##_type>(gmock_p##i))
+
+#define GMOCK_INTERNAL_MATCHER_MEMBERS(args) \
+  GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_MATCHER_MEMBER, , args)
+#define GMOCK_INTERNAL_MATCHER_MEMBER(i_unused, data_unused, arg) \
+  const arg##_type arg;
+
+#define GMOCK_INTERNAL_MATCHER_MEMBERS_USAGE(args) \
+  GMOCK_PP_TAIL(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_MATCHER_MEMBER_USAGE, , args))
+#define GMOCK_INTERNAL_MATCHER_MEMBER_USAGE(i_unused, data_unused, arg) , arg
+
+#define GMOCK_INTERNAL_MATCHER_ARGS_USAGE(args) \
+  GMOCK_PP_TAIL(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_MATCHER_ARG_USAGE, , args))
+#define GMOCK_INTERNAL_MATCHER_ARG_USAGE(i, data_unused, arg_unused) \
+  , gmock_p##i
+
+// To prevent ADL on certain functions we put them on a separate namespace.
+using namespace no_adl;  // NOLINT
+
 }  // namespace testing
 
 GTEST_DISABLE_MSC_WARNINGS_POP_()  //  4251 5046
@@ -6687,11 +8287,11 @@
 //
 // GOOGLETEST_CM0002 DO NOT DELETE
 
-#ifndef GMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_GMOCK_MATCHERS_H_
-#define GMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_GMOCK_MATCHERS_H_
-#endif  // GMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_GMOCK_MATCHERS_H_
+#ifndef GOOGLEMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_GMOCK_MATCHERS_H_
+#define GOOGLEMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_GMOCK_MATCHERS_H_
+#endif  // GOOGLEMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_GMOCK_MATCHERS_H_
 
-#endif  // GMOCK_INCLUDE_GMOCK_GMOCK_MATCHERS_H_
+#endif  // GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_MATCHERS_H_
 
 #if GTEST_HAS_EXCEPTIONS
 # include <stdexcept>  // NOLINT
@@ -6724,6 +8324,14 @@
 // Helper class for testing the Expectation class template.
 class ExpectationTester;
 
+// Helper classes for implementing NiceMock, StrictMock, and NaggyMock.
+template <typename MockClass>
+class NiceMockImpl;
+template <typename MockClass>
+class StrictMockImpl;
+template <typename MockClass>
+class NaggyMockImpl;
+
 // Protects the mock object registry (in class Mock), all function
 // mockers, and all expectations.
 //
@@ -6948,7 +8556,7 @@
     return *this;
   }
 
-  // Returns true iff the given arguments match the matchers.
+  // Returns true if and only if the given arguments match the matchers.
   bool Matches(const ArgumentTuple& args) const {
     return TupleMatches(matchers_, args) && extra_matcher_.Matches(args);
   }
@@ -7006,7 +8614,7 @@
       GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex);
 
   // Verifies all expectations on the given mock object and clears its
-  // default actions and expectations.  Returns true iff the
+  // default actions and expectations.  Returns true if and only if the
   // verification was successful.
   static bool VerifyAndClear(void* mock_obj)
       GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex);
@@ -7029,14 +8637,12 @@
   template <typename F>
   friend class internal::FunctionMocker;
 
-  template <typename M>
-  friend class NiceMock;
-
-  template <typename M>
-  friend class NaggyMock;
-
-  template <typename M>
-  friend class StrictMock;
+  template <typename MockClass>
+  friend class internal::NiceMockImpl;
+  template <typename MockClass>
+  friend class internal::NaggyMockImpl;
+  template <typename MockClass>
+  friend class internal::StrictMockImpl;
 
   // Tells Google Mock to allow uninteresting calls on the given mock
   // object.
@@ -7135,7 +8741,8 @@
   // The compiler-generated copy ctor and operator= work exactly as
   // intended, so we don't need to define our own.
 
-  // Returns true iff rhs references the same expectation as this object does.
+  // Returns true if and only if rhs references the same expectation as this
+  // object does.
   bool operator==(const Expectation& rhs) const {
     return expectation_base_ == rhs.expectation_base_;
   }
@@ -7217,8 +8824,8 @@
   // The compiler-generator ctor and operator= works exactly as
   // intended, so we don't need to define our own.
 
-  // Returns true iff rhs contains the same set of Expectation objects
-  // as this does.
+  // Returns true if and only if rhs contains the same set of Expectation
+  // objects as this does.
   bool operator==(const ExpectationSet& rhs) const {
     return expectations_ == rhs.expectations_;
   }
@@ -7379,8 +8986,8 @@
   // by the subclasses to implement the .Times() clause.
   void SpecifyCardinality(const Cardinality& cardinality);
 
-  // Returns true iff the user specified the cardinality explicitly
-  // using a .Times().
+  // Returns true if and only if the user specified the cardinality
+  // explicitly using a .Times().
   bool cardinality_specified() const { return cardinality_specified_; }
 
   // Sets the cardinality of this expectation spec.
@@ -7396,7 +9003,7 @@
   void RetireAllPreRequisites()
       GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex);
 
-  // Returns true iff this expectation is retired.
+  // Returns true if and only if this expectation is retired.
   bool is_retired() const
       GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
     g_gmock_mutex.AssertHeld();
@@ -7410,28 +9017,29 @@
     retired_ = true;
   }
 
-  // Returns true iff this expectation is satisfied.
+  // Returns true if and only if this expectation is satisfied.
   bool IsSatisfied() const
       GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
     g_gmock_mutex.AssertHeld();
     return cardinality().IsSatisfiedByCallCount(call_count_);
   }
 
-  // Returns true iff this expectation is saturated.
+  // Returns true if and only if this expectation is saturated.
   bool IsSaturated() const
       GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
     g_gmock_mutex.AssertHeld();
     return cardinality().IsSaturatedByCallCount(call_count_);
   }
 
-  // Returns true iff this expectation is over-saturated.
+  // Returns true if and only if this expectation is over-saturated.
   bool IsOverSaturated() const
       GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
     g_gmock_mutex.AssertHeld();
     return cardinality().IsOverSaturatedByCallCount(call_count_);
   }
 
-  // Returns true iff all pre-requisites of this expectation are satisfied.
+  // Returns true if and only if all pre-requisites of this expectation are
+  // satisfied.
   bool AllPrerequisitesAreSatisfied() const
       GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex);
 
@@ -7474,7 +9082,7 @@
   const char* file_;          // The file that contains the expectation.
   int line_;                  // The line number of the expectation.
   const std::string source_text_;  // The EXPECT_CALL(...) source text.
-  // True iff the cardinality is specified explicitly.
+  // True if and only if the cardinality is specified explicitly.
   bool cardinality_specified_;
   Cardinality cardinality_;            // The cardinality of the expectation.
   // The immediate pre-requisites (i.e. expectations that must be
@@ -7488,7 +9096,7 @@
   // This group of fields are the current state of the expectation,
   // and can change as the mock function is called.
   int call_count_;  // How many times this expectation has been invoked.
-  bool retired_;    // True iff this expectation has retired.
+  bool retired_;    // True if and only if this expectation has retired.
   UntypedActions untyped_actions_;
   bool extra_matcher_specified_;
   bool repeated_action_specified_;  // True if a WillRepeatedly() was specified.
@@ -7704,14 +9312,15 @@
   // statement finishes and when the current thread holds
   // g_gmock_mutex.
 
-  // Returns true iff this expectation matches the given arguments.
+  // Returns true if and only if this expectation matches the given arguments.
   bool Matches(const ArgumentTuple& args) const
       GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
     g_gmock_mutex.AssertHeld();
     return TupleMatches(matchers_, args) && extra_matcher_.Matches(args);
   }
 
-  // Returns true iff this expectation should handle the given arguments.
+  // Returns true if and only if this expectation should handle the given
+  // arguments.
   bool ShouldHandleArguments(const ArgumentTuple& args) const
       GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
     g_gmock_mutex.AssertHeld();
@@ -7935,8 +9544,8 @@
 
   // Provides nondestructive access to the underlying value/reference.
   // Always returns a const reference (more precisely,
-  // const RemoveReference<T>&). The behavior of calling this after
-  // calling Unwrap on the same object is unspecified.
+  // const std::add_lvalue_reference<T>::type). The behavior of calling this
+  // after calling Unwrap on the same object is unspecified.
   const T& Peek() const {
     return value_;
   }
@@ -7962,12 +9571,6 @@
   T* value_ptr_;
 };
 
-// MSVC warns about using 'this' in base member initializer list, so
-// we need to temporarily disable the warning.  We have to do it for
-// the entire class to suppress the warning, even though it's about
-// the constructor only.
-GTEST_DISABLE_MSC_WARNINGS_PUSH_(4355)
-
 // C++ treats the void type specially.  For example, you cannot define
 // a void-typed variable or pass a void value to a function.
 // ActionResultHolder<T> holds a value of type T, where T must be a
@@ -8269,9 +9872,8 @@
     const OnCallSpec<F>* const spec = FindOnCallSpec(args);
 
     if (spec == nullptr) {
-      *os << (internal::type_equals<Result, void>::value ?
-              "returning directly.\n" :
-              "returning default value.\n");
+      *os << (std::is_void<Result>::value ? "returning directly.\n"
+                                          : "returning default value.\n");
     } else {
       *os << "taking default action specified at:\n"
           << FormatFileLocation(spec->file(), spec->line()) << "\n";
@@ -8399,18 +10001,87 @@
   }
 };  // class FunctionMocker
 
-GTEST_DISABLE_MSC_WARNINGS_POP_()  //  4355
-
 // Reports an uninteresting call (whose description is in msg) in the
 // manner specified by 'reaction'.
 void ReportUninterestingCall(CallReaction reaction, const std::string& msg);
 
 }  // namespace internal
 
-// A MockFunction<F> class has one mock method whose type is F.  It is
-// useful when you just want your test code to emit some messages and
-// have Google Mock verify the right messages are sent (and perhaps at
-// the right times).  For example, if you are exercising code:
+namespace internal {
+
+template <typename F>
+class MockFunction;
+
+template <typename R, typename... Args>
+class MockFunction<R(Args...)> {
+ public:
+  MockFunction(const MockFunction&) = delete;
+  MockFunction& operator=(const MockFunction&) = delete;
+
+  std::function<R(Args...)> AsStdFunction() {
+    return [this](Args... args) -> R {
+      return this->Call(std::forward<Args>(args)...);
+    };
+  }
+
+  // Implementation detail: the expansion of the MOCK_METHOD macro.
+  R Call(Args... args) {
+    mock_.SetOwnerAndName(this, "Call");
+    return mock_.Invoke(std::forward<Args>(args)...);
+  }
+
+  MockSpec<R(Args...)> gmock_Call(Matcher<Args>... m) {
+    mock_.RegisterOwner(this);
+    return mock_.With(std::move(m)...);
+  }
+
+  MockSpec<R(Args...)> gmock_Call(const WithoutMatchers&, R (*)(Args...)) {
+    return this->gmock_Call(::testing::A<Args>()...);
+  }
+
+ protected:
+  MockFunction() = default;
+  ~MockFunction() = default;
+
+ private:
+  FunctionMocker<R(Args...)> mock_;
+};
+
+/*
+The SignatureOf<F> struct is a meta-function returning function signature
+corresponding to the provided F argument.
+
+It makes use of MockFunction easier by allowing it to accept more F arguments
+than just function signatures.
+
+Specializations provided here cover a signature type itself and any template
+that can be parameterized with a signature, including std::function and
+boost::function.
+*/
+
+template <typename F, typename = void>
+struct SignatureOf;
+
+template <typename R, typename... Args>
+struct SignatureOf<R(Args...)> {
+  using type = R(Args...);
+};
+
+template <template <typename> class C, typename F>
+struct SignatureOf<C<F>,
+                   typename std::enable_if<std::is_function<F>::value>::type>
+    : SignatureOf<F> {};
+
+template <typename F>
+using SignatureOfT = typename SignatureOf<F>::type;
+
+}  // namespace internal
+
+// A MockFunction<F> type has one mock method whose type is
+// internal::SignatureOfT<F>.  It is useful when you just want your
+// test code to emit some messages and have Google Mock verify the
+// right messages are sent (and perhaps at the right times).  For
+// example, if you are exercising code:
 //
 //   Foo(1);
 //   Foo(2);
@@ -8444,49 +10115,34 @@
 // Bar("a") is called by which call to Foo().
 //
 // MockFunction<F> can also be used to exercise code that accepts
-// std::function<F> callbacks. To do so, use AsStdFunction() method
-// to create std::function proxy forwarding to original object's Call.
-// Example:
+// std::function<internal::SignatureOfT<F>> callbacks. To do so, use
+// AsStdFunction() method to create std::function proxy forwarding to
+// original object's Call. Example:
 //
 // TEST(FooTest, RunsCallbackWithBarArgument) {
 //   MockFunction<int(string)> callback;
 //   EXPECT_CALL(callback, Call("bar")).WillOnce(Return(1));
 //   Foo(callback.AsStdFunction());
 // }
+//
+// The internal::SignatureOfT<F> indirection allows to use other types
+// than just function signature type. This is typically useful when
+// providing a mock for a predefined std::function type. Example:
+//
+// using FilterPredicate = std::function<bool(string)>;
+// void MyFilterAlgorithm(FilterPredicate predicate);
+//
+// TEST(FooTest, FilterPredicateAlwaysAccepts) {
+//   MockFunction<FilterPredicate> predicateMock;
+//   EXPECT_CALL(predicateMock, Call(_)).WillRepeatedly(Return(true));
+//   MyFilterAlgorithm(predicateMock.AsStdFunction());
+// }
 template <typename F>
-class MockFunction;
+class MockFunction : public internal::MockFunction<internal::SignatureOfT<F>> {
+  using Base = internal::MockFunction<internal::SignatureOfT<F>>;
 
-template <typename R, typename... Args>
-class MockFunction<R(Args...)> {
  public:
-  MockFunction() {}
-  MockFunction(const MockFunction&) = delete;
-  MockFunction& operator=(const MockFunction&) = delete;
-
-  std::function<R(Args...)> AsStdFunction() {
-    return [this](Args... args) -> R {
-      return this->Call(std::forward<Args>(args)...);
-    };
-  }
-
-  // Implementation detail: the expansion of the MOCK_METHOD macro.
-  R Call(Args... args) {
-    mock_.SetOwnerAndName(this, "Call");
-    return mock_.Invoke(std::forward<Args>(args)...);
-  }
-
-  internal::MockSpec<R(Args...)> gmock_Call(Matcher<Args>... m) {
-    mock_.RegisterOwner(this);
-    return mock_.With(std::move(m)...);
-  }
-
-  internal::MockSpec<R(Args...)> gmock_Call(const internal::WithoutMatchers&,
-                                            R (*)(Args...)) {
-    return this->gmock_Call(::testing::A<Args>()...);
-  }
-
- private:
-  mutable internal::FunctionMocker<R(Args...)> mock_;
+  using Base::Base;
 };
 
 // The style guide prohibits "using" statements in a namespace scope
@@ -8595,61 +10251,28 @@
 #define EXPECT_CALL(obj, call) \
   GMOCK_ON_CALL_IMPL_(obj, InternalExpectedAt, call)
 
-#endif  // GMOCK_INCLUDE_GMOCK_GMOCK_SPEC_BUILDERS_H_
+#endif  // GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_SPEC_BUILDERS_H_
 
 namespace testing {
 namespace internal {
-// Removes the given pointer; this is a helper for the expectation setter method
-// for parameterless matchers.
-//
-// We want to make sure that the user cannot set a parameterless expectation on
-// overloaded methods, including methods which are overloaded on const. Example:
-//
-//   class MockClass {
-//     MOCK_METHOD0(GetName, string&());
-//     MOCK_CONST_METHOD0(GetName, const string&());
-//   };
-//
-//   TEST() {
-//     // This should be an error, as it's not clear which overload is expected.
-//     EXPECT_CALL(mock, GetName).WillOnce(ReturnRef(value));
-//   }
-//
-// Here are the generated expectation-setter methods:
-//
-//   class MockClass {
-//     // Overload 1
-//     MockSpec<string&()> gmock_GetName() { ... }
-//     // Overload 2. Declared const so that the compiler will generate an
-//     // error when trying to resolve between this and overload 4 in
-//     // 'gmock_GetName(WithoutMatchers(), nullptr)'.
-//     MockSpec<string&()> gmock_GetName(
-//         const WithoutMatchers&, const Function<string&()>*) const {
-//       // Removes const from this, calls overload 1
-//       return AdjustConstness_(this)->gmock_GetName();
-//     }
-//
-//     // Overload 3
-//     const string& gmock_GetName() const { ... }
-//     // Overload 4
-//     MockSpec<const string&()> gmock_GetName(
-//         const WithoutMatchers&, const Function<const string&()>*) const {
-//       // Does not remove const, calls overload 3
-//       return AdjustConstness_const(this)->gmock_GetName();
-//     }
-//   }
-//
-template <typename MockType>
-const MockType* AdjustConstness_const(const MockType* mock) {
-  return mock;
-}
+template <typename T>
+using identity_t = T;
 
-// Removes const from and returns the given pointer; this is a helper for the
-// expectation setter method for parameterless matchers.
-template <typename MockType>
-MockType* AdjustConstness_(const MockType* mock) {
-  return const_cast<MockType*>(mock);
-}
+template <typename Pattern>
+struct ThisRefAdjuster {
+  template <typename T>
+  using AdjustT = typename std::conditional<
+      std::is_const<typename std::remove_reference<Pattern>::type>::value,
+      typename std::conditional<std::is_lvalue_reference<Pattern>::value,
+                                const T&, const T&&>::type,
+      typename std::conditional<std::is_lvalue_reference<Pattern>::value, T&,
+                                T&&>::type>::type;
+
+  template <typename MockType>
+  static AdjustT<MockType> Adjust(const MockType& mock) {
+    return static_cast<AdjustT<MockType>>(const_cast<MockType&>(mock));
+  }
+};
 
 }  // namespace internal
 
@@ -8659,965 +10282,8 @@
 // line is just a trick for working around a bug in MSVC 8.0, which
 // cannot handle it if we define FunctionMocker in ::testing.
 using internal::FunctionMocker;
-
-// GMOCK_RESULT_(tn, F) expands to the result type of function type F.
-// We define this as a variadic macro in case F contains unprotected
-// commas (the same reason that we use variadic macros in other places
-// in this file).
-// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
-#define GMOCK_RESULT_(tn, ...) \
-    tn ::testing::internal::Function<__VA_ARGS__>::Result
-
-// The type of argument N of the given function type.
-// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
-#define GMOCK_ARG_(tn, N, ...) \
-    tn ::testing::internal::Function<__VA_ARGS__>::template Arg<N-1>::type
-
-// The matcher type for argument N of the given function type.
-// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
-#define GMOCK_MATCHER_(tn, N, ...) \
-    const ::testing::Matcher<GMOCK_ARG_(tn, N, __VA_ARGS__)>&
-
-// The variable for mocking the given method.
-// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
-#define GMOCK_MOCKER_(arity, constness, Method) \
-    GTEST_CONCAT_TOKEN_(gmock##constness##arity##_##Method##_, __LINE__)
-
-// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
-#define GMOCK_METHOD0_(tn, constness, ct, Method, ...) \
-  static_assert(0 == \
-      ::testing::internal::Function<__VA_ARGS__>::ArgumentCount, \
-      "MOCK_METHOD<N> must match argument count.");\
-  GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \
-      ) constness { \
-    GMOCK_MOCKER_(0, constness, Method).SetOwnerAndName(this, #Method); \
-    return GMOCK_MOCKER_(0, constness, Method).Invoke(); \
-  } \
-  ::testing::MockSpec<__VA_ARGS__> \
-      gmock_##Method() constness { \
-    GMOCK_MOCKER_(0, constness, Method).RegisterOwner(this); \
-    return GMOCK_MOCKER_(0, constness, Method).With(); \
-  } \
-  ::testing::MockSpec<__VA_ARGS__> gmock_##Method( \
-      const ::testing::internal::WithoutMatchers&, \
-      constness ::testing::internal::Function<__VA_ARGS__>* ) const { \
-        return ::testing::internal::AdjustConstness_##constness(this)-> \
-            gmock_##Method(); \
-      } \
-  mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(0, constness, \
-      Method)
-
-// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
-#define GMOCK_METHOD1_(tn, constness, ct, Method, ...) \
-  static_assert(1 == \
-      ::testing::internal::Function<__VA_ARGS__>::ArgumentCount, \
-      "MOCK_METHOD<N> must match argument count.");\
-  GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \
-      GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1) constness { \
-    GMOCK_MOCKER_(1, constness, Method).SetOwnerAndName(this, #Method); \
-    return GMOCK_MOCKER_(1, constness, \
-        Method).Invoke(::std::forward<GMOCK_ARG_(tn, 1, \
-        __VA_ARGS__)>(gmock_a1)); \
-  } \
-  ::testing::MockSpec<__VA_ARGS__> \
-      gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1) constness { \
-    GMOCK_MOCKER_(1, constness, Method).RegisterOwner(this); \
-    return GMOCK_MOCKER_(1, constness, Method).With(gmock_a1); \
-  } \
-  ::testing::MockSpec<__VA_ARGS__> gmock_##Method( \
-      const ::testing::internal::WithoutMatchers&, \
-      constness ::testing::internal::Function<__VA_ARGS__>* ) const { \
-        return ::testing::internal::AdjustConstness_##constness(this)-> \
-            gmock_##Method(::testing::A<GMOCK_ARG_(tn, 1, __VA_ARGS__)>()); \
-      } \
-  mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(1, constness, \
-      Method)
-
-// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
-#define GMOCK_METHOD2_(tn, constness, ct, Method, ...) \
-  static_assert(2 == \
-      ::testing::internal::Function<__VA_ARGS__>::ArgumentCount, \
-      "MOCK_METHOD<N> must match argument count.");\
-  GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \
-      GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, GMOCK_ARG_(tn, 2, \
-          __VA_ARGS__) gmock_a2) constness { \
-    GMOCK_MOCKER_(2, constness, Method).SetOwnerAndName(this, #Method); \
-    return GMOCK_MOCKER_(2, constness, \
-        Method).Invoke(::std::forward<GMOCK_ARG_(tn, 1, \
-        __VA_ARGS__)>(gmock_a1), \
-  ::std::forward<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(gmock_a2)); \
-  } \
-  ::testing::MockSpec<__VA_ARGS__> \
-      gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \
-                     GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2) constness { \
-    GMOCK_MOCKER_(2, constness, Method).RegisterOwner(this); \
-    return GMOCK_MOCKER_(2, constness, Method).With(gmock_a1, gmock_a2); \
-  } \
-  ::testing::MockSpec<__VA_ARGS__> gmock_##Method( \
-      const ::testing::internal::WithoutMatchers&, \
-      constness ::testing::internal::Function<__VA_ARGS__>* ) const { \
-        return ::testing::internal::AdjustConstness_##constness(this)-> \
-            gmock_##Method(::testing::A<GMOCK_ARG_(tn, 1, __VA_ARGS__)>(), \
-                     ::testing::A<GMOCK_ARG_(tn, 2, __VA_ARGS__)>()); \
-      } \
-  mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(2, constness, \
-      Method)
-
-// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
-#define GMOCK_METHOD3_(tn, constness, ct, Method, ...) \
-  static_assert(3 == \
-      ::testing::internal::Function<__VA_ARGS__>::ArgumentCount, \
-      "MOCK_METHOD<N> must match argument count.");\
-  GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \
-      GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, GMOCK_ARG_(tn, 2, \
-          __VA_ARGS__) gmock_a2, GMOCK_ARG_(tn, 3, \
-          __VA_ARGS__) gmock_a3) constness { \
-    GMOCK_MOCKER_(3, constness, Method).SetOwnerAndName(this, #Method); \
-    return GMOCK_MOCKER_(3, constness, \
-        Method).Invoke(::std::forward<GMOCK_ARG_(tn, 1, \
-        __VA_ARGS__)>(gmock_a1), \
-  ::std::forward<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(gmock_a2), \
-  ::std::forward<GMOCK_ARG_(tn, 3, __VA_ARGS__)>(gmock_a3)); \
-  } \
-  ::testing::MockSpec<__VA_ARGS__> \
-      gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \
-                     GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \
-                     GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3) constness { \
-    GMOCK_MOCKER_(3, constness, Method).RegisterOwner(this); \
-    return GMOCK_MOCKER_(3, constness, Method).With(gmock_a1, gmock_a2, \
-        gmock_a3); \
-  } \
-  ::testing::MockSpec<__VA_ARGS__> gmock_##Method( \
-      const ::testing::internal::WithoutMatchers&, \
-      constness ::testing::internal::Function<__VA_ARGS__>* ) const { \
-        return ::testing::internal::AdjustConstness_##constness(this)-> \
-            gmock_##Method(::testing::A<GMOCK_ARG_(tn, 1, __VA_ARGS__)>(), \
-                     ::testing::A<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(), \
-                     ::testing::A<GMOCK_ARG_(tn, 3, __VA_ARGS__)>()); \
-      } \
-  mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(3, constness, \
-      Method)
-
-// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
-#define GMOCK_METHOD4_(tn, constness, ct, Method, ...) \
-  static_assert(4 == \
-      ::testing::internal::Function<__VA_ARGS__>::ArgumentCount, \
-      "MOCK_METHOD<N> must match argument count.");\
-  GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \
-      GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, GMOCK_ARG_(tn, 2, \
-          __VA_ARGS__) gmock_a2, GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \
-          GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4) constness { \
-    GMOCK_MOCKER_(4, constness, Method).SetOwnerAndName(this, #Method); \
-    return GMOCK_MOCKER_(4, constness, \
-        Method).Invoke(::std::forward<GMOCK_ARG_(tn, 1, \
-        __VA_ARGS__)>(gmock_a1), \
-  ::std::forward<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(gmock_a2), \
-  ::std::forward<GMOCK_ARG_(tn, 3, __VA_ARGS__)>(gmock_a3), \
-  ::std::forward<GMOCK_ARG_(tn, 4, __VA_ARGS__)>(gmock_a4)); \
-  } \
-  ::testing::MockSpec<__VA_ARGS__> \
-      gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \
-                     GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \
-                     GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \
-                     GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4) constness { \
-    GMOCK_MOCKER_(4, constness, Method).RegisterOwner(this); \
-    return GMOCK_MOCKER_(4, constness, Method).With(gmock_a1, gmock_a2, \
-        gmock_a3, gmock_a4); \
-  } \
-  ::testing::MockSpec<__VA_ARGS__> gmock_##Method( \
-      const ::testing::internal::WithoutMatchers&, \
-      constness ::testing::internal::Function<__VA_ARGS__>* ) const { \
-        return ::testing::internal::AdjustConstness_##constness(this)-> \
-            gmock_##Method(::testing::A<GMOCK_ARG_(tn, 1, __VA_ARGS__)>(), \
-                     ::testing::A<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(), \
-                     ::testing::A<GMOCK_ARG_(tn, 3, __VA_ARGS__)>(), \
-                     ::testing::A<GMOCK_ARG_(tn, 4, __VA_ARGS__)>()); \
-      } \
-  mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(4, constness, \
-      Method)
-
-// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
-#define GMOCK_METHOD5_(tn, constness, ct, Method, ...) \
-  static_assert(5 == \
-      ::testing::internal::Function<__VA_ARGS__>::ArgumentCount, \
-      "MOCK_METHOD<N> must match argument count.");\
-  GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \
-      GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, GMOCK_ARG_(tn, 2, \
-          __VA_ARGS__) gmock_a2, GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \
-          GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, GMOCK_ARG_(tn, 5, \
-          __VA_ARGS__) gmock_a5) constness { \
-    GMOCK_MOCKER_(5, constness, Method).SetOwnerAndName(this, #Method); \
-    return GMOCK_MOCKER_(5, constness, \
-        Method).Invoke(::std::forward<GMOCK_ARG_(tn, 1, \
-        __VA_ARGS__)>(gmock_a1), \
-  ::std::forward<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(gmock_a2), \
-  ::std::forward<GMOCK_ARG_(tn, 3, __VA_ARGS__)>(gmock_a3), \
-  ::std::forward<GMOCK_ARG_(tn, 4, __VA_ARGS__)>(gmock_a4), \
-  ::std::forward<GMOCK_ARG_(tn, 5, __VA_ARGS__)>(gmock_a5)); \
-  } \
-  ::testing::MockSpec<__VA_ARGS__> \
-      gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \
-                     GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \
-                     GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \
-                     GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4, \
-                     GMOCK_MATCHER_(tn, 5, __VA_ARGS__) gmock_a5) constness { \
-    GMOCK_MOCKER_(5, constness, Method).RegisterOwner(this); \
-    return GMOCK_MOCKER_(5, constness, Method).With(gmock_a1, gmock_a2, \
-        gmock_a3, gmock_a4, gmock_a5); \
-  } \
-  ::testing::MockSpec<__VA_ARGS__> gmock_##Method( \
-      const ::testing::internal::WithoutMatchers&, \
-      constness ::testing::internal::Function<__VA_ARGS__>* ) const { \
-        return ::testing::internal::AdjustConstness_##constness(this)-> \
-            gmock_##Method(::testing::A<GMOCK_ARG_(tn, 1, __VA_ARGS__)>(), \
-                     ::testing::A<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(), \
-                     ::testing::A<GMOCK_ARG_(tn, 3, __VA_ARGS__)>(), \
-                     ::testing::A<GMOCK_ARG_(tn, 4, __VA_ARGS__)>(), \
-                     ::testing::A<GMOCK_ARG_(tn, 5, __VA_ARGS__)>()); \
-      } \
-  mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(5, constness, \
-      Method)
-
-// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
-#define GMOCK_METHOD6_(tn, constness, ct, Method, ...) \
-  static_assert(6 == \
-      ::testing::internal::Function<__VA_ARGS__>::ArgumentCount, \
-      "MOCK_METHOD<N> must match argument count.");\
-  GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \
-      GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, GMOCK_ARG_(tn, 2, \
-          __VA_ARGS__) gmock_a2, GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \
-          GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, GMOCK_ARG_(tn, 5, \
-          __VA_ARGS__) gmock_a5, GMOCK_ARG_(tn, 6, \
-          __VA_ARGS__) gmock_a6) constness { \
-    GMOCK_MOCKER_(6, constness, Method).SetOwnerAndName(this, #Method); \
-    return GMOCK_MOCKER_(6, constness, \
-        Method).Invoke(::std::forward<GMOCK_ARG_(tn, 1, \
-        __VA_ARGS__)>(gmock_a1), \
-  ::std::forward<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(gmock_a2), \
-  ::std::forward<GMOCK_ARG_(tn, 3, __VA_ARGS__)>(gmock_a3), \
-  ::std::forward<GMOCK_ARG_(tn, 4, __VA_ARGS__)>(gmock_a4), \
-  ::std::forward<GMOCK_ARG_(tn, 5, __VA_ARGS__)>(gmock_a5), \
-  ::std::forward<GMOCK_ARG_(tn, 6, __VA_ARGS__)>(gmock_a6)); \
-  } \
-  ::testing::MockSpec<__VA_ARGS__> \
-      gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \
-                     GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \
-                     GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \
-                     GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4, \
-                     GMOCK_MATCHER_(tn, 5, __VA_ARGS__) gmock_a5, \
-                     GMOCK_MATCHER_(tn, 6, __VA_ARGS__) gmock_a6) constness { \
-    GMOCK_MOCKER_(6, constness, Method).RegisterOwner(this); \
-    return GMOCK_MOCKER_(6, constness, Method).With(gmock_a1, gmock_a2, \
-        gmock_a3, gmock_a4, gmock_a5, gmock_a6); \
-  } \
-  ::testing::MockSpec<__VA_ARGS__> gmock_##Method( \
-      const ::testing::internal::WithoutMatchers&, \
-      constness ::testing::internal::Function<__VA_ARGS__>* ) const { \
-        return ::testing::internal::AdjustConstness_##constness(this)-> \
-            gmock_##Method(::testing::A<GMOCK_ARG_(tn, 1, __VA_ARGS__)>(), \
-                     ::testing::A<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(), \
-                     ::testing::A<GMOCK_ARG_(tn, 3, __VA_ARGS__)>(), \
-                     ::testing::A<GMOCK_ARG_(tn, 4, __VA_ARGS__)>(), \
-                     ::testing::A<GMOCK_ARG_(tn, 5, __VA_ARGS__)>(), \
-                     ::testing::A<GMOCK_ARG_(tn, 6, __VA_ARGS__)>()); \
-      } \
-  mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(6, constness, \
-      Method)
-
-// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
-#define GMOCK_METHOD7_(tn, constness, ct, Method, ...) \
-  static_assert(7 == \
-      ::testing::internal::Function<__VA_ARGS__>::ArgumentCount, \
-      "MOCK_METHOD<N> must match argument count.");\
-  GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \
-      GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, GMOCK_ARG_(tn, 2, \
-          __VA_ARGS__) gmock_a2, GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \
-          GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, GMOCK_ARG_(tn, 5, \
-          __VA_ARGS__) gmock_a5, GMOCK_ARG_(tn, 6, __VA_ARGS__) gmock_a6, \
-          GMOCK_ARG_(tn, 7, __VA_ARGS__) gmock_a7) constness { \
-    GMOCK_MOCKER_(7, constness, Method).SetOwnerAndName(this, #Method); \
-    return GMOCK_MOCKER_(7, constness, \
-        Method).Invoke(::std::forward<GMOCK_ARG_(tn, 1, \
-        __VA_ARGS__)>(gmock_a1), \
-  ::std::forward<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(gmock_a2), \
-  ::std::forward<GMOCK_ARG_(tn, 3, __VA_ARGS__)>(gmock_a3), \
-  ::std::forward<GMOCK_ARG_(tn, 4, __VA_ARGS__)>(gmock_a4), \
-  ::std::forward<GMOCK_ARG_(tn, 5, __VA_ARGS__)>(gmock_a5), \
-  ::std::forward<GMOCK_ARG_(tn, 6, __VA_ARGS__)>(gmock_a6), \
-  ::std::forward<GMOCK_ARG_(tn, 7, __VA_ARGS__)>(gmock_a7)); \
-  } \
-  ::testing::MockSpec<__VA_ARGS__> \
-      gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \
-                     GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \
-                     GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \
-                     GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4, \
-                     GMOCK_MATCHER_(tn, 5, __VA_ARGS__) gmock_a5, \
-                     GMOCK_MATCHER_(tn, 6, __VA_ARGS__) gmock_a6, \
-                     GMOCK_MATCHER_(tn, 7, __VA_ARGS__) gmock_a7) constness { \
-    GMOCK_MOCKER_(7, constness, Method).RegisterOwner(this); \
-    return GMOCK_MOCKER_(7, constness, Method).With(gmock_a1, gmock_a2, \
-        gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7); \
-  } \
-  ::testing::MockSpec<__VA_ARGS__> gmock_##Method( \
-      const ::testing::internal::WithoutMatchers&, \
-      constness ::testing::internal::Function<__VA_ARGS__>* ) const { \
-        return ::testing::internal::AdjustConstness_##constness(this)-> \
-            gmock_##Method(::testing::A<GMOCK_ARG_(tn, 1, __VA_ARGS__)>(), \
-                     ::testing::A<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(), \
-                     ::testing::A<GMOCK_ARG_(tn, 3, __VA_ARGS__)>(), \
-                     ::testing::A<GMOCK_ARG_(tn, 4, __VA_ARGS__)>(), \
-                     ::testing::A<GMOCK_ARG_(tn, 5, __VA_ARGS__)>(), \
-                     ::testing::A<GMOCK_ARG_(tn, 6, __VA_ARGS__)>(), \
-                     ::testing::A<GMOCK_ARG_(tn, 7, __VA_ARGS__)>()); \
-      } \
-  mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(7, constness, \
-      Method)
-
-// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
-#define GMOCK_METHOD8_(tn, constness, ct, Method, ...) \
-  static_assert(8 == \
-      ::testing::internal::Function<__VA_ARGS__>::ArgumentCount, \
-      "MOCK_METHOD<N> must match argument count.");\
-  GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \
-      GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, GMOCK_ARG_(tn, 2, \
-          __VA_ARGS__) gmock_a2, GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \
-          GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, GMOCK_ARG_(tn, 5, \
-          __VA_ARGS__) gmock_a5, GMOCK_ARG_(tn, 6, __VA_ARGS__) gmock_a6, \
-          GMOCK_ARG_(tn, 7, __VA_ARGS__) gmock_a7, GMOCK_ARG_(tn, 8, \
-          __VA_ARGS__) gmock_a8) constness { \
-    GMOCK_MOCKER_(8, constness, Method).SetOwnerAndName(this, #Method); \
-    return GMOCK_MOCKER_(8, constness, \
-        Method).Invoke(::std::forward<GMOCK_ARG_(tn, 1, \
-        __VA_ARGS__)>(gmock_a1), \
-  ::std::forward<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(gmock_a2), \
-  ::std::forward<GMOCK_ARG_(tn, 3, __VA_ARGS__)>(gmock_a3), \
-  ::std::forward<GMOCK_ARG_(tn, 4, __VA_ARGS__)>(gmock_a4), \
-  ::std::forward<GMOCK_ARG_(tn, 5, __VA_ARGS__)>(gmock_a5), \
-  ::std::forward<GMOCK_ARG_(tn, 6, __VA_ARGS__)>(gmock_a6), \
-  ::std::forward<GMOCK_ARG_(tn, 7, __VA_ARGS__)>(gmock_a7), \
-  ::std::forward<GMOCK_ARG_(tn, 8, __VA_ARGS__)>(gmock_a8)); \
-  } \
-  ::testing::MockSpec<__VA_ARGS__> \
-      gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \
-                     GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \
-                     GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \
-                     GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4, \
-                     GMOCK_MATCHER_(tn, 5, __VA_ARGS__) gmock_a5, \
-                     GMOCK_MATCHER_(tn, 6, __VA_ARGS__) gmock_a6, \
-                     GMOCK_MATCHER_(tn, 7, __VA_ARGS__) gmock_a7, \
-                     GMOCK_MATCHER_(tn, 8, __VA_ARGS__) gmock_a8) constness { \
-    GMOCK_MOCKER_(8, constness, Method).RegisterOwner(this); \
-    return GMOCK_MOCKER_(8, constness, Method).With(gmock_a1, gmock_a2, \
-        gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8); \
-  } \
-  ::testing::MockSpec<__VA_ARGS__> gmock_##Method( \
-      const ::testing::internal::WithoutMatchers&, \
-      constness ::testing::internal::Function<__VA_ARGS__>* ) const { \
-        return ::testing::internal::AdjustConstness_##constness(this)-> \
-            gmock_##Method(::testing::A<GMOCK_ARG_(tn, 1, __VA_ARGS__)>(), \
-                     ::testing::A<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(), \
-                     ::testing::A<GMOCK_ARG_(tn, 3, __VA_ARGS__)>(), \
-                     ::testing::A<GMOCK_ARG_(tn, 4, __VA_ARGS__)>(), \
-                     ::testing::A<GMOCK_ARG_(tn, 5, __VA_ARGS__)>(), \
-                     ::testing::A<GMOCK_ARG_(tn, 6, __VA_ARGS__)>(), \
-                     ::testing::A<GMOCK_ARG_(tn, 7, __VA_ARGS__)>(), \
-                     ::testing::A<GMOCK_ARG_(tn, 8, __VA_ARGS__)>()); \
-      } \
-  mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(8, constness, \
-      Method)
-
-// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
-#define GMOCK_METHOD9_(tn, constness, ct, Method, ...) \
-  static_assert(9 == \
-      ::testing::internal::Function<__VA_ARGS__>::ArgumentCount, \
-      "MOCK_METHOD<N> must match argument count.");\
-  GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \
-      GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, GMOCK_ARG_(tn, 2, \
-          __VA_ARGS__) gmock_a2, GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \
-          GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, GMOCK_ARG_(tn, 5, \
-          __VA_ARGS__) gmock_a5, GMOCK_ARG_(tn, 6, __VA_ARGS__) gmock_a6, \
-          GMOCK_ARG_(tn, 7, __VA_ARGS__) gmock_a7, GMOCK_ARG_(tn, 8, \
-          __VA_ARGS__) gmock_a8, GMOCK_ARG_(tn, 9, \
-          __VA_ARGS__) gmock_a9) constness { \
-    GMOCK_MOCKER_(9, constness, Method).SetOwnerAndName(this, #Method); \
-    return GMOCK_MOCKER_(9, constness, \
-        Method).Invoke(::std::forward<GMOCK_ARG_(tn, 1, \
-        __VA_ARGS__)>(gmock_a1), \
-  ::std::forward<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(gmock_a2), \
-  ::std::forward<GMOCK_ARG_(tn, 3, __VA_ARGS__)>(gmock_a3), \
-  ::std::forward<GMOCK_ARG_(tn, 4, __VA_ARGS__)>(gmock_a4), \
-  ::std::forward<GMOCK_ARG_(tn, 5, __VA_ARGS__)>(gmock_a5), \
-  ::std::forward<GMOCK_ARG_(tn, 6, __VA_ARGS__)>(gmock_a6), \
-  ::std::forward<GMOCK_ARG_(tn, 7, __VA_ARGS__)>(gmock_a7), \
-  ::std::forward<GMOCK_ARG_(tn, 8, __VA_ARGS__)>(gmock_a8), \
-  ::std::forward<GMOCK_ARG_(tn, 9, __VA_ARGS__)>(gmock_a9)); \
-  } \
-  ::testing::MockSpec<__VA_ARGS__> \
-      gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \
-                     GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \
-                     GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \
-                     GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4, \
-                     GMOCK_MATCHER_(tn, 5, __VA_ARGS__) gmock_a5, \
-                     GMOCK_MATCHER_(tn, 6, __VA_ARGS__) gmock_a6, \
-                     GMOCK_MATCHER_(tn, 7, __VA_ARGS__) gmock_a7, \
-                     GMOCK_MATCHER_(tn, 8, __VA_ARGS__) gmock_a8, \
-                     GMOCK_MATCHER_(tn, 9, __VA_ARGS__) gmock_a9) constness { \
-    GMOCK_MOCKER_(9, constness, Method).RegisterOwner(this); \
-    return GMOCK_MOCKER_(9, constness, Method).With(gmock_a1, gmock_a2, \
-        gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, \
-        gmock_a9); \
-  } \
-  ::testing::MockSpec<__VA_ARGS__> gmock_##Method( \
-      const ::testing::internal::WithoutMatchers&, \
-      constness ::testing::internal::Function<__VA_ARGS__>* ) const { \
-        return ::testing::internal::AdjustConstness_##constness(this)-> \
-            gmock_##Method(::testing::A<GMOCK_ARG_(tn, 1, __VA_ARGS__)>(), \
-                     ::testing::A<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(), \
-                     ::testing::A<GMOCK_ARG_(tn, 3, __VA_ARGS__)>(), \
-                     ::testing::A<GMOCK_ARG_(tn, 4, __VA_ARGS__)>(), \
-                     ::testing::A<GMOCK_ARG_(tn, 5, __VA_ARGS__)>(), \
-                     ::testing::A<GMOCK_ARG_(tn, 6, __VA_ARGS__)>(), \
-                     ::testing::A<GMOCK_ARG_(tn, 7, __VA_ARGS__)>(), \
-                     ::testing::A<GMOCK_ARG_(tn, 8, __VA_ARGS__)>(), \
-                     ::testing::A<GMOCK_ARG_(tn, 9, __VA_ARGS__)>()); \
-      } \
-  mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(9, constness, \
-      Method)
-
-// INTERNAL IMPLEMENTATION - DON'T USE IN USER CODE!!!
-#define GMOCK_METHOD10_(tn, constness, ct, Method, ...) \
-  static_assert(10 == \
-      ::testing::internal::Function<__VA_ARGS__>::ArgumentCount, \
-      "MOCK_METHOD<N> must match argument count.");\
-  GMOCK_RESULT_(tn, __VA_ARGS__) ct Method( \
-      GMOCK_ARG_(tn, 1, __VA_ARGS__) gmock_a1, GMOCK_ARG_(tn, 2, \
-          __VA_ARGS__) gmock_a2, GMOCK_ARG_(tn, 3, __VA_ARGS__) gmock_a3, \
-          GMOCK_ARG_(tn, 4, __VA_ARGS__) gmock_a4, GMOCK_ARG_(tn, 5, \
-          __VA_ARGS__) gmock_a5, GMOCK_ARG_(tn, 6, __VA_ARGS__) gmock_a6, \
-          GMOCK_ARG_(tn, 7, __VA_ARGS__) gmock_a7, GMOCK_ARG_(tn, 8, \
-          __VA_ARGS__) gmock_a8, GMOCK_ARG_(tn, 9, __VA_ARGS__) gmock_a9, \
-          GMOCK_ARG_(tn, 10, __VA_ARGS__) gmock_a10) constness { \
-    GMOCK_MOCKER_(10, constness, Method).SetOwnerAndName(this, #Method); \
-    return GMOCK_MOCKER_(10, constness, \
-        Method).Invoke(::std::forward<GMOCK_ARG_(tn, 1, \
-        __VA_ARGS__)>(gmock_a1), \
-  ::std::forward<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(gmock_a2), \
-  ::std::forward<GMOCK_ARG_(tn, 3, __VA_ARGS__)>(gmock_a3), \
-  ::std::forward<GMOCK_ARG_(tn, 4, __VA_ARGS__)>(gmock_a4), \
-  ::std::forward<GMOCK_ARG_(tn, 5, __VA_ARGS__)>(gmock_a5), \
-  ::std::forward<GMOCK_ARG_(tn, 6, __VA_ARGS__)>(gmock_a6), \
-  ::std::forward<GMOCK_ARG_(tn, 7, __VA_ARGS__)>(gmock_a7), \
-  ::std::forward<GMOCK_ARG_(tn, 8, __VA_ARGS__)>(gmock_a8), \
-  ::std::forward<GMOCK_ARG_(tn, 9, __VA_ARGS__)>(gmock_a9), \
-  ::std::forward<GMOCK_ARG_(tn, 10, __VA_ARGS__)>(gmock_a10)); \
-  } \
-  ::testing::MockSpec<__VA_ARGS__> \
-      gmock_##Method(GMOCK_MATCHER_(tn, 1, __VA_ARGS__) gmock_a1, \
-                     GMOCK_MATCHER_(tn, 2, __VA_ARGS__) gmock_a2, \
-                     GMOCK_MATCHER_(tn, 3, __VA_ARGS__) gmock_a3, \
-                     GMOCK_MATCHER_(tn, 4, __VA_ARGS__) gmock_a4, \
-                     GMOCK_MATCHER_(tn, 5, __VA_ARGS__) gmock_a5, \
-                     GMOCK_MATCHER_(tn, 6, __VA_ARGS__) gmock_a6, \
-                     GMOCK_MATCHER_(tn, 7, __VA_ARGS__) gmock_a7, \
-                     GMOCK_MATCHER_(tn, 8, __VA_ARGS__) gmock_a8, \
-                     GMOCK_MATCHER_(tn, 9, __VA_ARGS__) gmock_a9, \
-                     GMOCK_MATCHER_(tn, 10, \
-                         __VA_ARGS__) gmock_a10) constness { \
-    GMOCK_MOCKER_(10, constness, Method).RegisterOwner(this); \
-    return GMOCK_MOCKER_(10, constness, Method).With(gmock_a1, gmock_a2, \
-        gmock_a3, gmock_a4, gmock_a5, gmock_a6, gmock_a7, gmock_a8, gmock_a9, \
-        gmock_a10); \
-  } \
-  ::testing::MockSpec<__VA_ARGS__> gmock_##Method( \
-      const ::testing::internal::WithoutMatchers&, \
-      constness ::testing::internal::Function<__VA_ARGS__>* ) const { \
-        return ::testing::internal::AdjustConstness_##constness(this)-> \
-            gmock_##Method(::testing::A<GMOCK_ARG_(tn, 1, __VA_ARGS__)>(), \
-                     ::testing::A<GMOCK_ARG_(tn, 2, __VA_ARGS__)>(), \
-                     ::testing::A<GMOCK_ARG_(tn, 3, __VA_ARGS__)>(), \
-                     ::testing::A<GMOCK_ARG_(tn, 4, __VA_ARGS__)>(), \
-                     ::testing::A<GMOCK_ARG_(tn, 5, __VA_ARGS__)>(), \
-                     ::testing::A<GMOCK_ARG_(tn, 6, __VA_ARGS__)>(), \
-                     ::testing::A<GMOCK_ARG_(tn, 7, __VA_ARGS__)>(), \
-                     ::testing::A<GMOCK_ARG_(tn, 8, __VA_ARGS__)>(), \
-                     ::testing::A<GMOCK_ARG_(tn, 9, __VA_ARGS__)>(), \
-                     ::testing::A<GMOCK_ARG_(tn, 10, __VA_ARGS__)>()); \
-      } \
-  mutable ::testing::FunctionMocker<__VA_ARGS__> GMOCK_MOCKER_(10, constness, \
-      Method)
-
-#define MOCK_METHOD0(m, ...) GMOCK_METHOD0_(, , , m, __VA_ARGS__)
-#define MOCK_METHOD1(m, ...) GMOCK_METHOD1_(, , , m, __VA_ARGS__)
-#define MOCK_METHOD2(m, ...) GMOCK_METHOD2_(, , , m, __VA_ARGS__)
-#define MOCK_METHOD3(m, ...) GMOCK_METHOD3_(, , , m, __VA_ARGS__)
-#define MOCK_METHOD4(m, ...) GMOCK_METHOD4_(, , , m, __VA_ARGS__)
-#define MOCK_METHOD5(m, ...) GMOCK_METHOD5_(, , , m, __VA_ARGS__)
-#define MOCK_METHOD6(m, ...) GMOCK_METHOD6_(, , , m, __VA_ARGS__)
-#define MOCK_METHOD7(m, ...) GMOCK_METHOD7_(, , , m, __VA_ARGS__)
-#define MOCK_METHOD8(m, ...) GMOCK_METHOD8_(, , , m, __VA_ARGS__)
-#define MOCK_METHOD9(m, ...) GMOCK_METHOD9_(, , , m, __VA_ARGS__)
-#define MOCK_METHOD10(m, ...) GMOCK_METHOD10_(, , , m, __VA_ARGS__)
-
-#define MOCK_CONST_METHOD0(m, ...) GMOCK_METHOD0_(, const, , m, __VA_ARGS__)
-#define MOCK_CONST_METHOD1(m, ...) GMOCK_METHOD1_(, const, , m, __VA_ARGS__)
-#define MOCK_CONST_METHOD2(m, ...) GMOCK_METHOD2_(, const, , m, __VA_ARGS__)
-#define MOCK_CONST_METHOD3(m, ...) GMOCK_METHOD3_(, const, , m, __VA_ARGS__)
-#define MOCK_CONST_METHOD4(m, ...) GMOCK_METHOD4_(, const, , m, __VA_ARGS__)
-#define MOCK_CONST_METHOD5(m, ...) GMOCK_METHOD5_(, const, , m, __VA_ARGS__)
-#define MOCK_CONST_METHOD6(m, ...) GMOCK_METHOD6_(, const, , m, __VA_ARGS__)
-#define MOCK_CONST_METHOD7(m, ...) GMOCK_METHOD7_(, const, , m, __VA_ARGS__)
-#define MOCK_CONST_METHOD8(m, ...) GMOCK_METHOD8_(, const, , m, __VA_ARGS__)
-#define MOCK_CONST_METHOD9(m, ...) GMOCK_METHOD9_(, const, , m, __VA_ARGS__)
-#define MOCK_CONST_METHOD10(m, ...) GMOCK_METHOD10_(, const, , m, __VA_ARGS__)
-
-#define MOCK_METHOD0_T(m, ...) GMOCK_METHOD0_(typename, , , m, __VA_ARGS__)
-#define MOCK_METHOD1_T(m, ...) GMOCK_METHOD1_(typename, , , m, __VA_ARGS__)
-#define MOCK_METHOD2_T(m, ...) GMOCK_METHOD2_(typename, , , m, __VA_ARGS__)
-#define MOCK_METHOD3_T(m, ...) GMOCK_METHOD3_(typename, , , m, __VA_ARGS__)
-#define MOCK_METHOD4_T(m, ...) GMOCK_METHOD4_(typename, , , m, __VA_ARGS__)
-#define MOCK_METHOD5_T(m, ...) GMOCK_METHOD5_(typename, , , m, __VA_ARGS__)
-#define MOCK_METHOD6_T(m, ...) GMOCK_METHOD6_(typename, , , m, __VA_ARGS__)
-#define MOCK_METHOD7_T(m, ...) GMOCK_METHOD7_(typename, , , m, __VA_ARGS__)
-#define MOCK_METHOD8_T(m, ...) GMOCK_METHOD8_(typename, , , m, __VA_ARGS__)
-#define MOCK_METHOD9_T(m, ...) GMOCK_METHOD9_(typename, , , m, __VA_ARGS__)
-#define MOCK_METHOD10_T(m, ...) GMOCK_METHOD10_(typename, , , m, __VA_ARGS__)
-
-#define MOCK_CONST_METHOD0_T(m, ...) \
-    GMOCK_METHOD0_(typename, const, , m, __VA_ARGS__)
-#define MOCK_CONST_METHOD1_T(m, ...) \
-    GMOCK_METHOD1_(typename, const, , m, __VA_ARGS__)
-#define MOCK_CONST_METHOD2_T(m, ...) \
-    GMOCK_METHOD2_(typename, const, , m, __VA_ARGS__)
-#define MOCK_CONST_METHOD3_T(m, ...) \
-    GMOCK_METHOD3_(typename, const, , m, __VA_ARGS__)
-#define MOCK_CONST_METHOD4_T(m, ...) \
-    GMOCK_METHOD4_(typename, const, , m, __VA_ARGS__)
-#define MOCK_CONST_METHOD5_T(m, ...) \
-    GMOCK_METHOD5_(typename, const, , m, __VA_ARGS__)
-#define MOCK_CONST_METHOD6_T(m, ...) \
-    GMOCK_METHOD6_(typename, const, , m, __VA_ARGS__)
-#define MOCK_CONST_METHOD7_T(m, ...) \
-    GMOCK_METHOD7_(typename, const, , m, __VA_ARGS__)
-#define MOCK_CONST_METHOD8_T(m, ...) \
-    GMOCK_METHOD8_(typename, const, , m, __VA_ARGS__)
-#define MOCK_CONST_METHOD9_T(m, ...) \
-    GMOCK_METHOD9_(typename, const, , m, __VA_ARGS__)
-#define MOCK_CONST_METHOD10_T(m, ...) \
-    GMOCK_METHOD10_(typename, const, , m, __VA_ARGS__)
-
-#define MOCK_METHOD0_WITH_CALLTYPE(ct, m, ...) \
-    GMOCK_METHOD0_(, , ct, m, __VA_ARGS__)
-#define MOCK_METHOD1_WITH_CALLTYPE(ct, m, ...) \
-    GMOCK_METHOD1_(, , ct, m, __VA_ARGS__)
-#define MOCK_METHOD2_WITH_CALLTYPE(ct, m, ...) \
-    GMOCK_METHOD2_(, , ct, m, __VA_ARGS__)
-#define MOCK_METHOD3_WITH_CALLTYPE(ct, m, ...) \
-    GMOCK_METHOD3_(, , ct, m, __VA_ARGS__)
-#define MOCK_METHOD4_WITH_CALLTYPE(ct, m, ...) \
-    GMOCK_METHOD4_(, , ct, m, __VA_ARGS__)
-#define MOCK_METHOD5_WITH_CALLTYPE(ct, m, ...) \
-    GMOCK_METHOD5_(, , ct, m, __VA_ARGS__)
-#define MOCK_METHOD6_WITH_CALLTYPE(ct, m, ...) \
-    GMOCK_METHOD6_(, , ct, m, __VA_ARGS__)
-#define MOCK_METHOD7_WITH_CALLTYPE(ct, m, ...) \
-    GMOCK_METHOD7_(, , ct, m, __VA_ARGS__)
-#define MOCK_METHOD8_WITH_CALLTYPE(ct, m, ...) \
-    GMOCK_METHOD8_(, , ct, m, __VA_ARGS__)
-#define MOCK_METHOD9_WITH_CALLTYPE(ct, m, ...) \
-    GMOCK_METHOD9_(, , ct, m, __VA_ARGS__)
-#define MOCK_METHOD10_WITH_CALLTYPE(ct, m, ...) \
-    GMOCK_METHOD10_(, , ct, m, __VA_ARGS__)
-
-#define MOCK_CONST_METHOD0_WITH_CALLTYPE(ct, m, ...) \
-    GMOCK_METHOD0_(, const, ct, m, __VA_ARGS__)
-#define MOCK_CONST_METHOD1_WITH_CALLTYPE(ct, m, ...) \
-    GMOCK_METHOD1_(, const, ct, m, __VA_ARGS__)
-#define MOCK_CONST_METHOD2_WITH_CALLTYPE(ct, m, ...) \
-    GMOCK_METHOD2_(, const, ct, m, __VA_ARGS__)
-#define MOCK_CONST_METHOD3_WITH_CALLTYPE(ct, m, ...) \
-    GMOCK_METHOD3_(, const, ct, m, __VA_ARGS__)
-#define MOCK_CONST_METHOD4_WITH_CALLTYPE(ct, m, ...) \
-    GMOCK_METHOD4_(, const, ct, m, __VA_ARGS__)
-#define MOCK_CONST_METHOD5_WITH_CALLTYPE(ct, m, ...) \
-    GMOCK_METHOD5_(, const, ct, m, __VA_ARGS__)
-#define MOCK_CONST_METHOD6_WITH_CALLTYPE(ct, m, ...) \
-    GMOCK_METHOD6_(, const, ct, m, __VA_ARGS__)
-#define MOCK_CONST_METHOD7_WITH_CALLTYPE(ct, m, ...) \
-    GMOCK_METHOD7_(, const, ct, m, __VA_ARGS__)
-#define MOCK_CONST_METHOD8_WITH_CALLTYPE(ct, m, ...) \
-    GMOCK_METHOD8_(, const, ct, m, __VA_ARGS__)
-#define MOCK_CONST_METHOD9_WITH_CALLTYPE(ct, m, ...) \
-    GMOCK_METHOD9_(, const, ct, m, __VA_ARGS__)
-#define MOCK_CONST_METHOD10_WITH_CALLTYPE(ct, m, ...) \
-    GMOCK_METHOD10_(, const, ct, m, __VA_ARGS__)
-
-#define MOCK_METHOD0_T_WITH_CALLTYPE(ct, m, ...) \
-    GMOCK_METHOD0_(typename, , ct, m, __VA_ARGS__)
-#define MOCK_METHOD1_T_WITH_CALLTYPE(ct, m, ...) \
-    GMOCK_METHOD1_(typename, , ct, m, __VA_ARGS__)
-#define MOCK_METHOD2_T_WITH_CALLTYPE(ct, m, ...) \
-    GMOCK_METHOD2_(typename, , ct, m, __VA_ARGS__)
-#define MOCK_METHOD3_T_WITH_CALLTYPE(ct, m, ...) \
-    GMOCK_METHOD3_(typename, , ct, m, __VA_ARGS__)
-#define MOCK_METHOD4_T_WITH_CALLTYPE(ct, m, ...) \
-    GMOCK_METHOD4_(typename, , ct, m, __VA_ARGS__)
-#define MOCK_METHOD5_T_WITH_CALLTYPE(ct, m, ...) \
-    GMOCK_METHOD5_(typename, , ct, m, __VA_ARGS__)
-#define MOCK_METHOD6_T_WITH_CALLTYPE(ct, m, ...) \
-    GMOCK_METHOD6_(typename, , ct, m, __VA_ARGS__)
-#define MOCK_METHOD7_T_WITH_CALLTYPE(ct, m, ...) \
-    GMOCK_METHOD7_(typename, , ct, m, __VA_ARGS__)
-#define MOCK_METHOD8_T_WITH_CALLTYPE(ct, m, ...) \
-    GMOCK_METHOD8_(typename, , ct, m, __VA_ARGS__)
-#define MOCK_METHOD9_T_WITH_CALLTYPE(ct, m, ...) \
-    GMOCK_METHOD9_(typename, , ct, m, __VA_ARGS__)
-#define MOCK_METHOD10_T_WITH_CALLTYPE(ct, m, ...) \
-    GMOCK_METHOD10_(typename, , ct, m, __VA_ARGS__)
-
-#define MOCK_CONST_METHOD0_T_WITH_CALLTYPE(ct, m, ...) \
-    GMOCK_METHOD0_(typename, const, ct, m, __VA_ARGS__)
-#define MOCK_CONST_METHOD1_T_WITH_CALLTYPE(ct, m, ...) \
-    GMOCK_METHOD1_(typename, const, ct, m, __VA_ARGS__)
-#define MOCK_CONST_METHOD2_T_WITH_CALLTYPE(ct, m, ...) \
-    GMOCK_METHOD2_(typename, const, ct, m, __VA_ARGS__)
-#define MOCK_CONST_METHOD3_T_WITH_CALLTYPE(ct, m, ...) \
-    GMOCK_METHOD3_(typename, const, ct, m, __VA_ARGS__)
-#define MOCK_CONST_METHOD4_T_WITH_CALLTYPE(ct, m, ...) \
-    GMOCK_METHOD4_(typename, const, ct, m, __VA_ARGS__)
-#define MOCK_CONST_METHOD5_T_WITH_CALLTYPE(ct, m, ...) \
-    GMOCK_METHOD5_(typename, const, ct, m, __VA_ARGS__)
-#define MOCK_CONST_METHOD6_T_WITH_CALLTYPE(ct, m, ...) \
-    GMOCK_METHOD6_(typename, const, ct, m, __VA_ARGS__)
-#define MOCK_CONST_METHOD7_T_WITH_CALLTYPE(ct, m, ...) \
-    GMOCK_METHOD7_(typename, const, ct, m, __VA_ARGS__)
-#define MOCK_CONST_METHOD8_T_WITH_CALLTYPE(ct, m, ...) \
-    GMOCK_METHOD8_(typename, const, ct, m, __VA_ARGS__)
-#define MOCK_CONST_METHOD9_T_WITH_CALLTYPE(ct, m, ...) \
-    GMOCK_METHOD9_(typename, const, ct, m, __VA_ARGS__)
-#define MOCK_CONST_METHOD10_T_WITH_CALLTYPE(ct, m, ...) \
-    GMOCK_METHOD10_(typename, const, ct, m, __VA_ARGS__)
-
 }  // namespace testing
 
-#endif  // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_FUNCTION_MOCKERS_H_
-#ifndef THIRD_PARTY_GOOGLETEST_GOOGLEMOCK_INCLUDE_GMOCK_PP_H_
-#define THIRD_PARTY_GOOGLETEST_GOOGLEMOCK_INCLUDE_GMOCK_PP_H_
-
-#undef GMOCK_PP_INTERNAL_USE_MSVC
-#if defined(__clang__)
-#define GMOCK_PP_INTERNAL_USE_MSVC 0
-#elif defined(_MSC_VER)
-// TODO(iserna): Also verify tradional versus comformant preprocessor.
-static_assert(
-    _MSC_VER >= 1900,
-    "MSVC version not supported. There is support for MSVC 14.0 and above.");
-#define GMOCK_PP_INTERNAL_USE_MSVC 1
-#else
-#define GMOCK_PP_INTERNAL_USE_MSVC 0
-#endif
-
-// Expands and concatenates the arguments. Constructed macros reevaluate.
-#define GMOCK_PP_CAT(_1, _2) GMOCK_PP_INTERNAL_CAT(_1, _2)
-
-// Expands and stringifies the only argument.
-#define GMOCK_PP_STRINGIZE(...) GMOCK_PP_INTERNAL_STRINGIZE(__VA_ARGS__)
-
-// Returns empty. Given a variadic number of arguments.
-#define GMOCK_PP_EMPTY(...)
-
-// Returns a comma. Given a variadic number of arguments.
-#define GMOCK_PP_COMMA(...) ,
-
-// Returns the only argument.
-#define GMOCK_PP_IDENTITY(_1) _1
-
-// MSVC preprocessor collapses __VA_ARGS__ in a single argument, we use a
-// CAT-like directive to force correct evaluation. Each macro has its own.
-#if GMOCK_PP_INTERNAL_USE_MSVC
-
-// Evaluates to the number of arguments after expansion.
-//
-//   #define PAIR x, y
-//
-//   GMOCK_PP_NARG() => 1
-//   GMOCK_PP_NARG(x) => 1
-//   GMOCK_PP_NARG(x, y) => 2
-//   GMOCK_PP_NARG(PAIR) => 2
-//
-// Requires: the number of arguments after expansion is at most 15.
-#define GMOCK_PP_NARG(...)                                                    \
-  GMOCK_PP_INTERNAL_NARG_CAT(                                                 \
-      GMOCK_PP_INTERNAL_INTERNAL_16TH(__VA_ARGS__, 15, 14, 13, 12, 11, 10, 9, \
-                                      8, 7, 6, 5, 4, 3, 2, 1), )
-
-// Returns 1 if the expansion of arguments has an unprotected comma. Otherwise
-// returns 0. Requires no more than 15 unprotected commas.
-#define GMOCK_PP_HAS_COMMA(...)                                               \
-  GMOCK_PP_INTERNAL_HAS_COMMA_CAT(                                            \
-      GMOCK_PP_INTERNAL_INTERNAL_16TH(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
-                                      1, 1, 1, 1, 1, 0), )
-// Returns the first argument.
-#define GMOCK_PP_HEAD(...) \
-  GMOCK_PP_INTERNAL_HEAD_CAT(GMOCK_PP_INTERNAL_HEAD(__VA_ARGS__), )
-
-// Returns the tail. A variadic list of all arguments minus the first. Requires
-// at least one argument.
-#define GMOCK_PP_TAIL(...) \
-  GMOCK_PP_INTERNAL_TAIL_CAT(GMOCK_PP_INTERNAL_TAIL(__VA_ARGS__), )
-
-// Calls CAT(_Macro, NARG(__VA_ARGS__))(__VA_ARGS__)
-#define GMOCK_PP_VARIADIC_CALL(_Macro, ...) \
-  GMOCK_PP_INTERNAL_VARIADIC_CALL_CAT(      \
-      GMOCK_PP_CAT(_Macro, GMOCK_PP_NARG(__VA_ARGS__))(__VA_ARGS__), )
-
-#else  // GMOCK_PP_INTERNAL_USE_MSVC
-
-#define GMOCK_PP_NARG(...)                                                   \
-  GMOCK_PP_INTERNAL_INTERNAL_16TH(__VA_ARGS__, 15, 14, 13, 12, 11, 10, 9, 8, \
-                                  7, 6, 5, 4, 3, 2, 1)
-#define GMOCK_PP_HAS_COMMA(...)                                              \
-  GMOCK_PP_INTERNAL_INTERNAL_16TH(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
-                                  1, 1, 1, 1, 0)
-#define GMOCK_PP_HEAD(...) GMOCK_PP_INTERNAL_HEAD(__VA_ARGS__)
-#define GMOCK_PP_TAIL(...) GMOCK_PP_INTERNAL_TAIL(__VA_ARGS__)
-#define GMOCK_PP_VARIADIC_CALL(_Macro, ...) \
-  GMOCK_PP_CAT(_Macro, GMOCK_PP_NARG(__VA_ARGS__))(__VA_ARGS__)
-
-#endif  // GMOCK_PP_INTERNAL_USE_MSVC
-
-// If the arguments after expansion have no tokens, evaluates to `1`. Otherwise
-// evaluates to `0`.
-//
-// Requires: * the number of arguments after expansion is at most 15.
-//           * If the argument is a macro, it must be able to be called with one
-//             argument.
-//
-// Implementation details:
-//
-// There is one case when it generates a compile error: if the argument is macro
-// that cannot be called with one argument.
-//
-//   #define M(a, b)  // it doesn't matter what it expands to
-//
-//   // Expected: expands to `0`.
-//   // Actual: compile error.
-//   GMOCK_PP_IS_EMPTY(M)
-//
-// There are 4 cases tested:
-//
-// * __VA_ARGS__ possible expansion has no unparen'd commas. Expected 0.
-// * __VA_ARGS__ possible expansion is not enclosed in parenthesis. Expected 0.
-// * __VA_ARGS__ possible expansion is not a macro that ()-evaluates to a comma.
-//   Expected 0
-// * __VA_ARGS__ is empty, or has unparen'd commas, or is enclosed in
-//   parenthesis, or is a macro that ()-evaluates to comma. Expected 1.
-//
-// We trigger detection on '0001', i.e. on empty.
-#define GMOCK_PP_IS_EMPTY(...)                                               \
-  GMOCK_PP_INTERNAL_IS_EMPTY(GMOCK_PP_HAS_COMMA(__VA_ARGS__),                \
-                             GMOCK_PP_HAS_COMMA(GMOCK_PP_COMMA __VA_ARGS__), \
-                             GMOCK_PP_HAS_COMMA(__VA_ARGS__()),              \
-                             GMOCK_PP_HAS_COMMA(GMOCK_PP_COMMA __VA_ARGS__()))
-
-// Evaluates to _Then if _Cond is 1 and _Else if _Cond is 0.
-#define GMOCK_PP_IF(_Cond, _Then, _Else) \
-  GMOCK_PP_CAT(GMOCK_PP_INTERNAL_IF_, _Cond)(_Then, _Else)
-
-// Evaluates to the number of arguments after expansion. Identifies 'empty' as
-// 0.
-//
-//   #define PAIR x, y
-//
-//   GMOCK_PP_NARG0() => 0
-//   GMOCK_PP_NARG0(x) => 1
-//   GMOCK_PP_NARG0(x, y) => 2
-//   GMOCK_PP_NARG0(PAIR) => 2
-//
-// Requires: * the number of arguments after expansion is at most 15.
-//           * If the argument is a macro, it must be able to be called with one
-//             argument.
-#define GMOCK_PP_NARG0(...) \
-  GMOCK_PP_IF(GMOCK_PP_IS_EMPTY(__VA_ARGS__), 0, GMOCK_PP_NARG(__VA_ARGS__))
-
-// Expands to 1 if the first argument starts with something in parentheses,
-// otherwise to 0.
-#define GMOCK_PP_IS_BEGIN_PARENS(...)                    \
-  GMOCK_PP_INTERNAL_ALTERNATE_HEAD(                      \
-      GMOCK_PP_CAT(GMOCK_PP_INTERNAL_IBP_IS_VARIADIC_R_, \
-                   GMOCK_PP_INTERNAL_IBP_IS_VARIADIC_C __VA_ARGS__))
-
-// Expands to 1 is there is only one argument and it is enclosed in parentheses.
-#define GMOCK_PP_IS_ENCLOSED_PARENS(...)             \
-  GMOCK_PP_IF(GMOCK_PP_IS_BEGIN_PARENS(__VA_ARGS__), \
-              GMOCK_PP_IS_EMPTY(GMOCK_PP_EMPTY __VA_ARGS__), 0)
-
-// Remove the parens, requires GMOCK_PP_IS_ENCLOSED_PARENS(args) => 1.
-#define GMOCK_PP_REMOVE_PARENS(...) GMOCK_PP_INTERNAL_REMOVE_PARENS __VA_ARGS__
-
-// Expands to _Macro(0, _Data, e1) _Macro(1, _Data, e2) ... _Macro(K -1, _Data,
-// eK) as many of GMOCK_INTERNAL_NARG0 _Tuple.
-// Requires: * |_Macro| can be called with 3 arguments.
-//           * |_Tuple| expansion has no more than 15 elements.
-#define GMOCK_PP_FOR_EACH(_Macro, _Data, _Tuple)                        \
-  GMOCK_PP_CAT(GMOCK_PP_INTERNAL_FOR_EACH_IMPL_, GMOCK_PP_NARG0 _Tuple) \
-  (0, _Macro, _Data, _Tuple)
-
-// Expands to _Macro(0, _Data, ) _Macro(1, _Data, ) ... _Macro(K - 1, _Data, )
-// Empty if _K = 0.
-// Requires: * |_Macro| can be called with 3 arguments.
-//           * |_K| literal between 0 and 15
-#define GMOCK_PP_REPEAT(_Macro, _Data, _N)           \
-  GMOCK_PP_CAT(GMOCK_PP_INTERNAL_FOR_EACH_IMPL_, _N) \
-  (0, _Macro, _Data, GMOCK_PP_INTENRAL_EMPTY_TUPLE)
-
-// Increments the argument, requires the argument to be between 0 and 15.
-#define GMOCK_PP_INC(_i) GMOCK_PP_CAT(GMOCK_PP_INTERNAL_INC_, _i)
-
-// Returns comma if _i != 0. Requires _i to be between 0 and 15.
-#define GMOCK_PP_COMMA_IF(_i) GMOCK_PP_CAT(GMOCK_PP_INTERNAL_COMMA_IF_, _i)
-
-// Internal details follow. Do not use any of these symbols outside of this
-// file or we will break your code.
-#define GMOCK_PP_INTENRAL_EMPTY_TUPLE (, , , , , , , , , , , , , , , )
-#define GMOCK_PP_INTERNAL_CAT(_1, _2) _1##_2
-#define GMOCK_PP_INTERNAL_STRINGIZE(...) #__VA_ARGS__
-#define GMOCK_PP_INTERNAL_INTERNAL_16TH(_1, _2, _3, _4, _5, _6, _7, _8, _9, \
-                                        _10, _11, _12, _13, _14, _15, _16,  \
-                                        ...)                                \
-  _16
-#define GMOCK_PP_INTERNAL_CAT_5(_1, _2, _3, _4, _5) _1##_2##_3##_4##_5
-#define GMOCK_PP_INTERNAL_IS_EMPTY(_1, _2, _3, _4)                             \
-  GMOCK_PP_HAS_COMMA(GMOCK_PP_INTERNAL_CAT_5(GMOCK_PP_INTERNAL_IS_EMPTY_CASE_, \
-                                             _1, _2, _3, _4))
-#define GMOCK_PP_INTERNAL_IS_EMPTY_CASE_0001 ,
-#define GMOCK_PP_INTERNAL_IF_1(_Then, _Else) _Then
-#define GMOCK_PP_INTERNAL_IF_0(_Then, _Else) _Else
-#define GMOCK_PP_INTERNAL_HEAD(_1, ...) _1
-#define GMOCK_PP_INTERNAL_TAIL(_1, ...) __VA_ARGS__
-
-#if GMOCK_PP_INTERNAL_USE_MSVC
-#define GMOCK_PP_INTERNAL_NARG_CAT(_1, _2) GMOCK_PP_INTERNAL_NARG_CAT_I(_1, _2)
-#define GMOCK_PP_INTERNAL_HEAD_CAT(_1, _2) GMOCK_PP_INTERNAL_HEAD_CAT_I(_1, _2)
-#define GMOCK_PP_INTERNAL_HAS_COMMA_CAT(_1, _2) \
-  GMOCK_PP_INTERNAL_HAS_COMMA_CAT_I(_1, _2)
-#define GMOCK_PP_INTERNAL_TAIL_CAT(_1, _2) GMOCK_PP_INTERNAL_TAIL_CAT_I(_1, _2)
-#define GMOCK_PP_INTERNAL_VARIADIC_CALL_CAT(_1, _2) \
-  GMOCK_PP_INTERNAL_VARIADIC_CALL_CAT_I(_1, _2)
-#define GMOCK_PP_INTERNAL_NARG_CAT_I(_1, _2) _1##_2
-#define GMOCK_PP_INTERNAL_HEAD_CAT_I(_1, _2) _1##_2
-#define GMOCK_PP_INTERNAL_HAS_COMMA_CAT_I(_1, _2) _1##_2
-#define GMOCK_PP_INTERNAL_TAIL_CAT_I(_1, _2) _1##_2
-#define GMOCK_PP_INTERNAL_VARIADIC_CALL_CAT_I(_1, _2) _1##_2
-#define GMOCK_PP_INTERNAL_ALTERNATE_HEAD(...) \
-  GMOCK_PP_INTERNAL_ALTERNATE_HEAD_CAT(GMOCK_PP_HEAD(__VA_ARGS__), )
-#define GMOCK_PP_INTERNAL_ALTERNATE_HEAD_CAT(_1, _2) \
-  GMOCK_PP_INTERNAL_ALTERNATE_HEAD_CAT_I(_1, _2)
-#define GMOCK_PP_INTERNAL_ALTERNATE_HEAD_CAT_I(_1, _2) _1##_2
-#else  // GMOCK_PP_INTERNAL_USE_MSVC
-#define GMOCK_PP_INTERNAL_ALTERNATE_HEAD(...) GMOCK_PP_HEAD(__VA_ARGS__)
-#endif  // GMOCK_PP_INTERNAL_USE_MSVC
-
-#define GMOCK_PP_INTERNAL_IBP_IS_VARIADIC_C(...) 1 _
-#define GMOCK_PP_INTERNAL_IBP_IS_VARIADIC_R_1 1,
-#define GMOCK_PP_INTERNAL_IBP_IS_VARIADIC_R_GMOCK_PP_INTERNAL_IBP_IS_VARIADIC_C \
-  0,
-#define GMOCK_PP_INTERNAL_REMOVE_PARENS(...) __VA_ARGS__
-#define GMOCK_PP_INTERNAL_INC_0 1
-#define GMOCK_PP_INTERNAL_INC_1 2
-#define GMOCK_PP_INTERNAL_INC_2 3
-#define GMOCK_PP_INTERNAL_INC_3 4
-#define GMOCK_PP_INTERNAL_INC_4 5
-#define GMOCK_PP_INTERNAL_INC_5 6
-#define GMOCK_PP_INTERNAL_INC_6 7
-#define GMOCK_PP_INTERNAL_INC_7 8
-#define GMOCK_PP_INTERNAL_INC_8 9
-#define GMOCK_PP_INTERNAL_INC_9 10
-#define GMOCK_PP_INTERNAL_INC_10 11
-#define GMOCK_PP_INTERNAL_INC_11 12
-#define GMOCK_PP_INTERNAL_INC_12 13
-#define GMOCK_PP_INTERNAL_INC_13 14
-#define GMOCK_PP_INTERNAL_INC_14 15
-#define GMOCK_PP_INTERNAL_INC_15 16
-#define GMOCK_PP_INTERNAL_COMMA_IF_0
-#define GMOCK_PP_INTERNAL_COMMA_IF_1 ,
-#define GMOCK_PP_INTERNAL_COMMA_IF_2 ,
-#define GMOCK_PP_INTERNAL_COMMA_IF_3 ,
-#define GMOCK_PP_INTERNAL_COMMA_IF_4 ,
-#define GMOCK_PP_INTERNAL_COMMA_IF_5 ,
-#define GMOCK_PP_INTERNAL_COMMA_IF_6 ,
-#define GMOCK_PP_INTERNAL_COMMA_IF_7 ,
-#define GMOCK_PP_INTERNAL_COMMA_IF_8 ,
-#define GMOCK_PP_INTERNAL_COMMA_IF_9 ,
-#define GMOCK_PP_INTERNAL_COMMA_IF_10 ,
-#define GMOCK_PP_INTERNAL_COMMA_IF_11 ,
-#define GMOCK_PP_INTERNAL_COMMA_IF_12 ,
-#define GMOCK_PP_INTERNAL_COMMA_IF_13 ,
-#define GMOCK_PP_INTERNAL_COMMA_IF_14 ,
-#define GMOCK_PP_INTERNAL_COMMA_IF_15 ,
-#define GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, _element) \
-  _Macro(_i, _Data, _element)
-#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_0(_i, _Macro, _Data, _Tuple)
-#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_1(_i, _Macro, _Data, _Tuple) \
-  GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple)
-#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_2(_i, _Macro, _Data, _Tuple)    \
-  GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
-  GMOCK_PP_INTERNAL_FOR_EACH_IMPL_1(GMOCK_PP_INC(_i), _Macro, _Data,    \
-                                    (GMOCK_PP_TAIL _Tuple))
-#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_3(_i, _Macro, _Data, _Tuple)    \
-  GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
-  GMOCK_PP_INTERNAL_FOR_EACH_IMPL_2(GMOCK_PP_INC(_i), _Macro, _Data,    \
-                                    (GMOCK_PP_TAIL _Tuple))
-#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_4(_i, _Macro, _Data, _Tuple)    \
-  GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
-  GMOCK_PP_INTERNAL_FOR_EACH_IMPL_3(GMOCK_PP_INC(_i), _Macro, _Data,    \
-                                    (GMOCK_PP_TAIL _Tuple))
-#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_5(_i, _Macro, _Data, _Tuple)    \
-  GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
-  GMOCK_PP_INTERNAL_FOR_EACH_IMPL_4(GMOCK_PP_INC(_i), _Macro, _Data,    \
-                                    (GMOCK_PP_TAIL _Tuple))
-#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_6(_i, _Macro, _Data, _Tuple)    \
-  GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
-  GMOCK_PP_INTERNAL_FOR_EACH_IMPL_5(GMOCK_PP_INC(_i), _Macro, _Data,    \
-                                    (GMOCK_PP_TAIL _Tuple))
-#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_7(_i, _Macro, _Data, _Tuple)    \
-  GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
-  GMOCK_PP_INTERNAL_FOR_EACH_IMPL_6(GMOCK_PP_INC(_i), _Macro, _Data,    \
-                                    (GMOCK_PP_TAIL _Tuple))
-#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_8(_i, _Macro, _Data, _Tuple)    \
-  GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
-  GMOCK_PP_INTERNAL_FOR_EACH_IMPL_7(GMOCK_PP_INC(_i), _Macro, _Data,    \
-                                    (GMOCK_PP_TAIL _Tuple))
-#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_9(_i, _Macro, _Data, _Tuple)    \
-  GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
-  GMOCK_PP_INTERNAL_FOR_EACH_IMPL_8(GMOCK_PP_INC(_i), _Macro, _Data,    \
-                                    (GMOCK_PP_TAIL _Tuple))
-#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_10(_i, _Macro, _Data, _Tuple)   \
-  GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
-  GMOCK_PP_INTERNAL_FOR_EACH_IMPL_9(GMOCK_PP_INC(_i), _Macro, _Data,    \
-                                    (GMOCK_PP_TAIL _Tuple))
-#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_11(_i, _Macro, _Data, _Tuple)   \
-  GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
-  GMOCK_PP_INTERNAL_FOR_EACH_IMPL_10(GMOCK_PP_INC(_i), _Macro, _Data,   \
-                                     (GMOCK_PP_TAIL _Tuple))
-#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_12(_i, _Macro, _Data, _Tuple)   \
-  GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
-  GMOCK_PP_INTERNAL_FOR_EACH_IMPL_11(GMOCK_PP_INC(_i), _Macro, _Data,   \
-                                     (GMOCK_PP_TAIL _Tuple))
-#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_13(_i, _Macro, _Data, _Tuple)   \
-  GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
-  GMOCK_PP_INTERNAL_FOR_EACH_IMPL_12(GMOCK_PP_INC(_i), _Macro, _Data,   \
-                                     (GMOCK_PP_TAIL _Tuple))
-#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_14(_i, _Macro, _Data, _Tuple)   \
-  GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
-  GMOCK_PP_INTERNAL_FOR_EACH_IMPL_13(GMOCK_PP_INC(_i), _Macro, _Data,   \
-                                     (GMOCK_PP_TAIL _Tuple))
-#define GMOCK_PP_INTERNAL_FOR_EACH_IMPL_15(_i, _Macro, _Data, _Tuple)   \
-  GMOCK_PP_INTERNAL_CALL_MACRO(_Macro, _i, _Data, GMOCK_PP_HEAD _Tuple) \
-  GMOCK_PP_INTERNAL_FOR_EACH_IMPL_14(GMOCK_PP_INC(_i), _Macro, _Data,   \
-                                     (GMOCK_PP_TAIL _Tuple))
-
-#endif  // THIRD_PARTY_GOOGLETEST_GOOGLEMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_PP_H_
-
 #define MOCK_METHOD(...) \
   GMOCK_PP_VARIADIC_CALL(GMOCK_INTERNAL_MOCK_METHOD_ARG_, __VA_ARGS__)
 
@@ -9639,7 +10305,8 @@
   GMOCK_INTERNAL_MOCK_METHOD_IMPL(                                            \
       GMOCK_PP_NARG0 _Args, _MethodName, GMOCK_INTERNAL_HAS_CONST(_Spec),     \
       GMOCK_INTERNAL_HAS_OVERRIDE(_Spec), GMOCK_INTERNAL_HAS_FINAL(_Spec),    \
-      GMOCK_INTERNAL_HAS_NOEXCEPT(_Spec), GMOCK_INTERNAL_GET_CALLTYPE(_Spec), \
+      GMOCK_INTERNAL_GET_NOEXCEPT_SPEC(_Spec),                                \
+      GMOCK_INTERNAL_GET_CALLTYPE(_Spec), GMOCK_INTERNAL_GET_REF_SPEC(_Spec), \
       (GMOCK_INTERNAL_SIGNATURE(_Ret, _Args)))
 
 #define GMOCK_INTERNAL_MOCK_METHOD_ARG_5(...) \
@@ -9673,21 +10340,20 @@
       ::testing::tuple_size<typename ::testing::internal::Function<    \
               __VA_ARGS__>::ArgumentTuple>::value == _N,               \
       "This method does not take " GMOCK_PP_STRINGIZE(                 \
-          _N) " arguments. Parenthesize all types with unproctected commas.")
+          _N) " arguments. Parenthesize all types with unprotected commas.")
 
 #define GMOCK_INTERNAL_ASSERT_VALID_SPEC(_Spec) \
   GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_ASSERT_VALID_SPEC_ELEMENT, ~, _Spec)
 
 #define GMOCK_INTERNAL_MOCK_METHOD_IMPL(_N, _MethodName, _Constness,           \
-                                        _Override, _Final, _Noexcept,          \
-                                        _CallType, _Signature)                 \
+                                        _Override, _Final, _NoexceptSpec,      \
+                                        _CallType, _RefSpec, _Signature)       \
   typename ::testing::internal::Function<GMOCK_PP_REMOVE_PARENS(               \
       _Signature)>::Result                                                     \
   GMOCK_INTERNAL_EXPAND(_CallType)                                             \
       _MethodName(GMOCK_PP_REPEAT(GMOCK_INTERNAL_PARAMETER, _Signature, _N))   \
-          GMOCK_PP_IF(_Constness, const, ) GMOCK_PP_IF(_Noexcept, noexcept, )  \
-              GMOCK_PP_IF(_Override, override, )                               \
-                  GMOCK_PP_IF(_Final, final, ) {                               \
+          GMOCK_PP_IF(_Constness, const, ) _RefSpec _NoexceptSpec              \
+          GMOCK_PP_IF(_Override, override, ) GMOCK_PP_IF(_Final, final, ) {    \
     GMOCK_MOCKER_(_N, _Constness, _MethodName)                                 \
         .SetOwnerAndName(this, #_MethodName);                                  \
     return GMOCK_MOCKER_(_N, _Constness, _MethodName)                          \
@@ -9695,7 +10361,7 @@
   }                                                                            \
   ::testing::MockSpec<GMOCK_PP_REMOVE_PARENS(_Signature)> gmock_##_MethodName( \
       GMOCK_PP_REPEAT(GMOCK_INTERNAL_MATCHER_PARAMETER, _Signature, _N))       \
-      GMOCK_PP_IF(_Constness, const, ) {                                       \
+      GMOCK_PP_IF(_Constness, const, ) _RefSpec {                              \
     GMOCK_MOCKER_(_N, _Constness, _MethodName).RegisterOwner(this);            \
     return GMOCK_MOCKER_(_N, _Constness, _MethodName)                          \
         .With(GMOCK_PP_REPEAT(GMOCK_INTERNAL_MATCHER_ARGUMENT, , _N));         \
@@ -9703,11 +10369,10 @@
   ::testing::MockSpec<GMOCK_PP_REMOVE_PARENS(_Signature)> gmock_##_MethodName( \
       const ::testing::internal::WithoutMatchers&,                             \
       GMOCK_PP_IF(_Constness, const, )::testing::internal::Function<           \
-          GMOCK_PP_REMOVE_PARENS(_Signature)>*)                                \
-      const GMOCK_PP_IF(_Noexcept, noexcept, ) {                               \
-    return GMOCK_PP_CAT(::testing::internal::AdjustConstness_,                 \
-                        GMOCK_PP_IF(_Constness, const, ))(this)                \
-        ->gmock_##_MethodName(GMOCK_PP_REPEAT(                                 \
+          GMOCK_PP_REMOVE_PARENS(_Signature)>*) const _RefSpec _NoexceptSpec { \
+    return ::testing::internal::ThisRefAdjuster<GMOCK_PP_IF(                   \
+        _Constness, const, ) int _RefSpec>::Adjust(*this)                      \
+        .gmock_##_MethodName(GMOCK_PP_REPEAT(                                  \
             GMOCK_INTERNAL_A_MATCHER_ARGUMENT, _Signature, _N));               \
   }                                                                            \
   mutable ::testing::FunctionMocker<GMOCK_PP_REMOVE_PARENS(_Signature)>        \
@@ -9726,9 +10391,20 @@
 #define GMOCK_INTERNAL_HAS_FINAL(_Tuple) \
   GMOCK_PP_HAS_COMMA(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_DETECT_FINAL, ~, _Tuple))
 
-#define GMOCK_INTERNAL_HAS_NOEXCEPT(_Tuple) \
-  GMOCK_PP_HAS_COMMA(                       \
-      GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_DETECT_NOEXCEPT, ~, _Tuple))
+#define GMOCK_INTERNAL_GET_NOEXCEPT_SPEC(_Tuple) \
+  GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_NOEXCEPT_SPEC_IF_NOEXCEPT, ~, _Tuple)
+
+#define GMOCK_INTERNAL_NOEXCEPT_SPEC_IF_NOEXCEPT(_i, _, _elem)          \
+  GMOCK_PP_IF(                                                          \
+      GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_NOEXCEPT(_i, _, _elem)), \
+      _elem, )
+
+#define GMOCK_INTERNAL_GET_REF_SPEC(_Tuple) \
+  GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_REF_SPEC_IF_REF, ~, _Tuple)
+
+#define GMOCK_INTERNAL_REF_SPEC_IF_REF(_i, _, _elem)                       \
+  GMOCK_PP_IF(GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_REF(_i, _, _elem)), \
+              GMOCK_PP_CAT(GMOCK_INTERNAL_UNPACK_, _elem), )
 
 #define GMOCK_INTERNAL_GET_CALLTYPE(_Tuple) \
   GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_GET_CALLTYPE_IMPL, ~, _Tuple)
@@ -9739,6 +10415,7 @@
        GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_OVERRIDE(_i, _, _elem)) + \
        GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_FINAL(_i, _, _elem)) +    \
        GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_NOEXCEPT(_i, _, _elem)) + \
+       GMOCK_PP_HAS_COMMA(GMOCK_INTERNAL_DETECT_REF(_i, _, _elem)) +      \
        GMOCK_INTERNAL_IS_CALLTYPE(_elem)) == 1,                           \
       GMOCK_PP_STRINGIZE(                                                 \
           _elem) " cannot be recognized as a valid specification modifier.");
@@ -9759,12 +10436,18 @@
 
 #define GMOCK_INTERNAL_DETECT_FINAL_I_final ,
 
-// TODO(iserna): Maybe noexcept should accept an argument here as well.
 #define GMOCK_INTERNAL_DETECT_NOEXCEPT(_i, _, _elem) \
   GMOCK_PP_CAT(GMOCK_INTERNAL_DETECT_NOEXCEPT_I_, _elem)
 
 #define GMOCK_INTERNAL_DETECT_NOEXCEPT_I_noexcept ,
 
+#define GMOCK_INTERNAL_DETECT_REF(_i, _, _elem) \
+  GMOCK_PP_CAT(GMOCK_INTERNAL_DETECT_REF_I_, _elem)
+
+#define GMOCK_INTERNAL_DETECT_REF_I_ref ,
+
+#define GMOCK_INTERNAL_UNPACK_ref(x) x
+
 #define GMOCK_INTERNAL_GET_CALLTYPE_IMPL(_i, _, _elem)           \
   GMOCK_PP_IF(GMOCK_INTERNAL_IS_CALLTYPE(_elem),                 \
               GMOCK_INTERNAL_GET_VALUE_CALLTYPE, GMOCK_PP_EMPTY) \
@@ -9782,14 +10465,28 @@
   GMOCK_INTERNAL_GET_VALUE_CALLTYPE_I(          \
       GMOCK_PP_CAT(GMOCK_INTERNAL_IS_CALLTYPE_HELPER_, _arg))
 #define GMOCK_INTERNAL_GET_VALUE_CALLTYPE_I(_arg) \
-  GMOCK_PP_CAT(GMOCK_PP_IDENTITY, _arg)
+  GMOCK_PP_IDENTITY _arg
 
 #define GMOCK_INTERNAL_IS_CALLTYPE_HELPER_Calltype
 
-#define GMOCK_INTERNAL_SIGNATURE(_Ret, _Args)                         \
-  GMOCK_PP_IF(GMOCK_PP_IS_BEGIN_PARENS(_Ret), GMOCK_PP_REMOVE_PARENS, \
-              GMOCK_PP_IDENTITY)                                      \
-  (_Ret)(GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_GET_TYPE, _, _Args))
+// Note: The use of `identity_t` here allows _Ret to represent return types that
+// would normally need to be specified in a different way. For example, a method
+// returning a function pointer must be written as
+//
+// fn_ptr_return_t (*method(method_args_t...))(fn_ptr_args_t...)
+//
+// But we only support placing the return type at the beginning. To handle this,
+// we wrap all calls in identity_t, so that a declaration will be expanded to
+//
+// identity_t<fn_ptr_return_t (*)(fn_ptr_args_t...)> method(method_args_t...)
+//
+// This allows us to work around the syntactic oddities of function/method
+// types.
+#define GMOCK_INTERNAL_SIGNATURE(_Ret, _Args)                                 \
+  ::testing::internal::identity_t<GMOCK_PP_IF(GMOCK_PP_IS_BEGIN_PARENS(_Ret), \
+                                              GMOCK_PP_REMOVE_PARENS,         \
+                                              GMOCK_PP_IDENTITY)(_Ret)>(      \
+      GMOCK_PP_FOR_EACH(GMOCK_INTERNAL_GET_TYPE, _, _Args))
 
 #define GMOCK_INTERNAL_GET_TYPE(_i, _, _elem)                          \
   GMOCK_PP_COMMA_IF(_i)                                                \
@@ -9797,43 +10494,199 @@
               GMOCK_PP_IDENTITY)                                       \
   (_elem)
 
-#define GMOCK_INTERNAL_PARAMETER(_i, _Signature, _)        \
-  GMOCK_PP_COMMA_IF(_i)                                    \
-  GMOCK_INTERNAL_ARG_O(typename, GMOCK_PP_INC(_i),         \
-                       GMOCK_PP_REMOVE_PARENS(_Signature)) \
+#define GMOCK_INTERNAL_PARAMETER(_i, _Signature, _)            \
+  GMOCK_PP_COMMA_IF(_i)                                        \
+  GMOCK_INTERNAL_ARG_O(_i, GMOCK_PP_REMOVE_PARENS(_Signature)) \
   gmock_a##_i
 
-#define GMOCK_INTERNAL_FORWARD_ARG(_i, _Signature, _)                       \
-  GMOCK_PP_COMMA_IF(_i)                                                     \
-  ::std::forward<GMOCK_INTERNAL_ARG_O(typename, GMOCK_PP_INC(_i),           \
-                                      GMOCK_PP_REMOVE_PARENS(_Signature))>( \
-      gmock_a##_i)
+#define GMOCK_INTERNAL_FORWARD_ARG(_i, _Signature, _) \
+  GMOCK_PP_COMMA_IF(_i)                               \
+  ::std::forward<GMOCK_INTERNAL_ARG_O(                \
+      _i, GMOCK_PP_REMOVE_PARENS(_Signature))>(gmock_a##_i)
 
-#define GMOCK_INTERNAL_MATCHER_PARAMETER(_i, _Signature, _)    \
-  GMOCK_PP_COMMA_IF(_i)                                        \
-  GMOCK_INTERNAL_MATCHER_O(typename, GMOCK_PP_INC(_i),         \
-                           GMOCK_PP_REMOVE_PARENS(_Signature)) \
+#define GMOCK_INTERNAL_MATCHER_PARAMETER(_i, _Signature, _)        \
+  GMOCK_PP_COMMA_IF(_i)                                            \
+  GMOCK_INTERNAL_MATCHER_O(_i, GMOCK_PP_REMOVE_PARENS(_Signature)) \
   gmock_a##_i
 
 #define GMOCK_INTERNAL_MATCHER_ARGUMENT(_i, _1, _2) \
   GMOCK_PP_COMMA_IF(_i)                             \
   gmock_a##_i
 
-#define GMOCK_INTERNAL_A_MATCHER_ARGUMENT(_i, _Signature, _)    \
-  GMOCK_PP_COMMA_IF(_i)                                         \
-  ::testing::A<GMOCK_INTERNAL_ARG_O(typename, GMOCK_PP_INC(_i), \
-                                    GMOCK_PP_REMOVE_PARENS(_Signature))>()
+#define GMOCK_INTERNAL_A_MATCHER_ARGUMENT(_i, _Signature, _) \
+  GMOCK_PP_COMMA_IF(_i)                                      \
+  ::testing::A<GMOCK_INTERNAL_ARG_O(_i, GMOCK_PP_REMOVE_PARENS(_Signature))>()
 
-#define GMOCK_INTERNAL_ARG_O(_tn, _i, ...) GMOCK_ARG_(_tn, _i, __VA_ARGS__)
+#define GMOCK_INTERNAL_ARG_O(_i, ...) \
+  typename ::testing::internal::Function<__VA_ARGS__>::template Arg<_i>::type
 
-#define GMOCK_INTERNAL_MATCHER_O(_tn, _i, ...) \
-  GMOCK_MATCHER_(_tn, _i, __VA_ARGS__)
+#define GMOCK_INTERNAL_MATCHER_O(_i, ...)                          \
+  const ::testing::Matcher<typename ::testing::internal::Function< \
+      __VA_ARGS__>::template Arg<_i>::type>&
 
-#endif  // THIRD_PARTY_GOOGLETEST_GOOGLEMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_FUNCTION_MOCKER_H_
-// This file was GENERATED by command:
-//     pump.py gmock-generated-actions.h.pump
-// DO NOT EDIT BY HAND!!!
+#define MOCK_METHOD0(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 0, __VA_ARGS__)
+#define MOCK_METHOD1(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 1, __VA_ARGS__)
+#define MOCK_METHOD2(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 2, __VA_ARGS__)
+#define MOCK_METHOD3(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 3, __VA_ARGS__)
+#define MOCK_METHOD4(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 4, __VA_ARGS__)
+#define MOCK_METHOD5(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 5, __VA_ARGS__)
+#define MOCK_METHOD6(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 6, __VA_ARGS__)
+#define MOCK_METHOD7(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 7, __VA_ARGS__)
+#define MOCK_METHOD8(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 8, __VA_ARGS__)
+#define MOCK_METHOD9(m, ...) GMOCK_INTERNAL_MOCK_METHODN(, , m, 9, __VA_ARGS__)
+#define MOCK_METHOD10(m, ...) \
+  GMOCK_INTERNAL_MOCK_METHODN(, , m, 10, __VA_ARGS__)
 
+#define MOCK_CONST_METHOD0(m, ...) \
+  GMOCK_INTERNAL_MOCK_METHODN(const, , m, 0, __VA_ARGS__)
+#define MOCK_CONST_METHOD1(m, ...) \
+  GMOCK_INTERNAL_MOCK_METHODN(const, , m, 1, __VA_ARGS__)
+#define MOCK_CONST_METHOD2(m, ...) \
+  GMOCK_INTERNAL_MOCK_METHODN(const, , m, 2, __VA_ARGS__)
+#define MOCK_CONST_METHOD3(m, ...) \
+  GMOCK_INTERNAL_MOCK_METHODN(const, , m, 3, __VA_ARGS__)
+#define MOCK_CONST_METHOD4(m, ...) \
+  GMOCK_INTERNAL_MOCK_METHODN(const, , m, 4, __VA_ARGS__)
+#define MOCK_CONST_METHOD5(m, ...) \
+  GMOCK_INTERNAL_MOCK_METHODN(const, , m, 5, __VA_ARGS__)
+#define MOCK_CONST_METHOD6(m, ...) \
+  GMOCK_INTERNAL_MOCK_METHODN(const, , m, 6, __VA_ARGS__)
+#define MOCK_CONST_METHOD7(m, ...) \
+  GMOCK_INTERNAL_MOCK_METHODN(const, , m, 7, __VA_ARGS__)
+#define MOCK_CONST_METHOD8(m, ...) \
+  GMOCK_INTERNAL_MOCK_METHODN(const, , m, 8, __VA_ARGS__)
+#define MOCK_CONST_METHOD9(m, ...) \
+  GMOCK_INTERNAL_MOCK_METHODN(const, , m, 9, __VA_ARGS__)
+#define MOCK_CONST_METHOD10(m, ...) \
+  GMOCK_INTERNAL_MOCK_METHODN(const, , m, 10, __VA_ARGS__)
+
+#define MOCK_METHOD0_T(m, ...) MOCK_METHOD0(m, __VA_ARGS__)
+#define MOCK_METHOD1_T(m, ...) MOCK_METHOD1(m, __VA_ARGS__)
+#define MOCK_METHOD2_T(m, ...) MOCK_METHOD2(m, __VA_ARGS__)
+#define MOCK_METHOD3_T(m, ...) MOCK_METHOD3(m, __VA_ARGS__)
+#define MOCK_METHOD4_T(m, ...) MOCK_METHOD4(m, __VA_ARGS__)
+#define MOCK_METHOD5_T(m, ...) MOCK_METHOD5(m, __VA_ARGS__)
+#define MOCK_METHOD6_T(m, ...) MOCK_METHOD6(m, __VA_ARGS__)
+#define MOCK_METHOD7_T(m, ...) MOCK_METHOD7(m, __VA_ARGS__)
+#define MOCK_METHOD8_T(m, ...) MOCK_METHOD8(m, __VA_ARGS__)
+#define MOCK_METHOD9_T(m, ...) MOCK_METHOD9(m, __VA_ARGS__)
+#define MOCK_METHOD10_T(m, ...) MOCK_METHOD10(m, __VA_ARGS__)
+
+#define MOCK_CONST_METHOD0_T(m, ...) MOCK_CONST_METHOD0(m, __VA_ARGS__)
+#define MOCK_CONST_METHOD1_T(m, ...) MOCK_CONST_METHOD1(m, __VA_ARGS__)
+#define MOCK_CONST_METHOD2_T(m, ...) MOCK_CONST_METHOD2(m, __VA_ARGS__)
+#define MOCK_CONST_METHOD3_T(m, ...) MOCK_CONST_METHOD3(m, __VA_ARGS__)
+#define MOCK_CONST_METHOD4_T(m, ...) MOCK_CONST_METHOD4(m, __VA_ARGS__)
+#define MOCK_CONST_METHOD5_T(m, ...) MOCK_CONST_METHOD5(m, __VA_ARGS__)
+#define MOCK_CONST_METHOD6_T(m, ...) MOCK_CONST_METHOD6(m, __VA_ARGS__)
+#define MOCK_CONST_METHOD7_T(m, ...) MOCK_CONST_METHOD7(m, __VA_ARGS__)
+#define MOCK_CONST_METHOD8_T(m, ...) MOCK_CONST_METHOD8(m, __VA_ARGS__)
+#define MOCK_CONST_METHOD9_T(m, ...) MOCK_CONST_METHOD9(m, __VA_ARGS__)
+#define MOCK_CONST_METHOD10_T(m, ...) MOCK_CONST_METHOD10(m, __VA_ARGS__)
+
+#define MOCK_METHOD0_WITH_CALLTYPE(ct, m, ...) \
+  GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 0, __VA_ARGS__)
+#define MOCK_METHOD1_WITH_CALLTYPE(ct, m, ...) \
+  GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 1, __VA_ARGS__)
+#define MOCK_METHOD2_WITH_CALLTYPE(ct, m, ...) \
+  GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 2, __VA_ARGS__)
+#define MOCK_METHOD3_WITH_CALLTYPE(ct, m, ...) \
+  GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 3, __VA_ARGS__)
+#define MOCK_METHOD4_WITH_CALLTYPE(ct, m, ...) \
+  GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 4, __VA_ARGS__)
+#define MOCK_METHOD5_WITH_CALLTYPE(ct, m, ...) \
+  GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 5, __VA_ARGS__)
+#define MOCK_METHOD6_WITH_CALLTYPE(ct, m, ...) \
+  GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 6, __VA_ARGS__)
+#define MOCK_METHOD7_WITH_CALLTYPE(ct, m, ...) \
+  GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 7, __VA_ARGS__)
+#define MOCK_METHOD8_WITH_CALLTYPE(ct, m, ...) \
+  GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 8, __VA_ARGS__)
+#define MOCK_METHOD9_WITH_CALLTYPE(ct, m, ...) \
+  GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 9, __VA_ARGS__)
+#define MOCK_METHOD10_WITH_CALLTYPE(ct, m, ...) \
+  GMOCK_INTERNAL_MOCK_METHODN(, ct, m, 10, __VA_ARGS__)
+
+#define MOCK_CONST_METHOD0_WITH_CALLTYPE(ct, m, ...) \
+  GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 0, __VA_ARGS__)
+#define MOCK_CONST_METHOD1_WITH_CALLTYPE(ct, m, ...) \
+  GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 1, __VA_ARGS__)
+#define MOCK_CONST_METHOD2_WITH_CALLTYPE(ct, m, ...) \
+  GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 2, __VA_ARGS__)
+#define MOCK_CONST_METHOD3_WITH_CALLTYPE(ct, m, ...) \
+  GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 3, __VA_ARGS__)
+#define MOCK_CONST_METHOD4_WITH_CALLTYPE(ct, m, ...) \
+  GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 4, __VA_ARGS__)
+#define MOCK_CONST_METHOD5_WITH_CALLTYPE(ct, m, ...) \
+  GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 5, __VA_ARGS__)
+#define MOCK_CONST_METHOD6_WITH_CALLTYPE(ct, m, ...) \
+  GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 6, __VA_ARGS__)
+#define MOCK_CONST_METHOD7_WITH_CALLTYPE(ct, m, ...) \
+  GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 7, __VA_ARGS__)
+#define MOCK_CONST_METHOD8_WITH_CALLTYPE(ct, m, ...) \
+  GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 8, __VA_ARGS__)
+#define MOCK_CONST_METHOD9_WITH_CALLTYPE(ct, m, ...) \
+  GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 9, __VA_ARGS__)
+#define MOCK_CONST_METHOD10_WITH_CALLTYPE(ct, m, ...) \
+  GMOCK_INTERNAL_MOCK_METHODN(const, ct, m, 10, __VA_ARGS__)
+
+#define MOCK_METHOD0_T_WITH_CALLTYPE(ct, m, ...) \
+  MOCK_METHOD0_WITH_CALLTYPE(ct, m, __VA_ARGS__)
+#define MOCK_METHOD1_T_WITH_CALLTYPE(ct, m, ...) \
+  MOCK_METHOD1_WITH_CALLTYPE(ct, m, __VA_ARGS__)
+#define MOCK_METHOD2_T_WITH_CALLTYPE(ct, m, ...) \
+  MOCK_METHOD2_WITH_CALLTYPE(ct, m, __VA_ARGS__)
+#define MOCK_METHOD3_T_WITH_CALLTYPE(ct, m, ...) \
+  MOCK_METHOD3_WITH_CALLTYPE(ct, m, __VA_ARGS__)
+#define MOCK_METHOD4_T_WITH_CALLTYPE(ct, m, ...) \
+  MOCK_METHOD4_WITH_CALLTYPE(ct, m, __VA_ARGS__)
+#define MOCK_METHOD5_T_WITH_CALLTYPE(ct, m, ...) \
+  MOCK_METHOD5_WITH_CALLTYPE(ct, m, __VA_ARGS__)
+#define MOCK_METHOD6_T_WITH_CALLTYPE(ct, m, ...) \
+  MOCK_METHOD6_WITH_CALLTYPE(ct, m, __VA_ARGS__)
+#define MOCK_METHOD7_T_WITH_CALLTYPE(ct, m, ...) \
+  MOCK_METHOD7_WITH_CALLTYPE(ct, m, __VA_ARGS__)
+#define MOCK_METHOD8_T_WITH_CALLTYPE(ct, m, ...) \
+  MOCK_METHOD8_WITH_CALLTYPE(ct, m, __VA_ARGS__)
+#define MOCK_METHOD9_T_WITH_CALLTYPE(ct, m, ...) \
+  MOCK_METHOD9_WITH_CALLTYPE(ct, m, __VA_ARGS__)
+#define MOCK_METHOD10_T_WITH_CALLTYPE(ct, m, ...) \
+  MOCK_METHOD10_WITH_CALLTYPE(ct, m, __VA_ARGS__)
+
+#define MOCK_CONST_METHOD0_T_WITH_CALLTYPE(ct, m, ...) \
+  MOCK_CONST_METHOD0_WITH_CALLTYPE(ct, m, __VA_ARGS__)
+#define MOCK_CONST_METHOD1_T_WITH_CALLTYPE(ct, m, ...) \
+  MOCK_CONST_METHOD1_WITH_CALLTYPE(ct, m, __VA_ARGS__)
+#define MOCK_CONST_METHOD2_T_WITH_CALLTYPE(ct, m, ...) \
+  MOCK_CONST_METHOD2_WITH_CALLTYPE(ct, m, __VA_ARGS__)
+#define MOCK_CONST_METHOD3_T_WITH_CALLTYPE(ct, m, ...) \
+  MOCK_CONST_METHOD3_WITH_CALLTYPE(ct, m, __VA_ARGS__)
+#define MOCK_CONST_METHOD4_T_WITH_CALLTYPE(ct, m, ...) \
+  MOCK_CONST_METHOD4_WITH_CALLTYPE(ct, m, __VA_ARGS__)
+#define MOCK_CONST_METHOD5_T_WITH_CALLTYPE(ct, m, ...) \
+  MOCK_CONST_METHOD5_WITH_CALLTYPE(ct, m, __VA_ARGS__)
+#define MOCK_CONST_METHOD6_T_WITH_CALLTYPE(ct, m, ...) \
+  MOCK_CONST_METHOD6_WITH_CALLTYPE(ct, m, __VA_ARGS__)
+#define MOCK_CONST_METHOD7_T_WITH_CALLTYPE(ct, m, ...) \
+  MOCK_CONST_METHOD7_WITH_CALLTYPE(ct, m, __VA_ARGS__)
+#define MOCK_CONST_METHOD8_T_WITH_CALLTYPE(ct, m, ...) \
+  MOCK_CONST_METHOD8_WITH_CALLTYPE(ct, m, __VA_ARGS__)
+#define MOCK_CONST_METHOD9_T_WITH_CALLTYPE(ct, m, ...) \
+  MOCK_CONST_METHOD9_WITH_CALLTYPE(ct, m, __VA_ARGS__)
+#define MOCK_CONST_METHOD10_T_WITH_CALLTYPE(ct, m, ...) \
+  MOCK_CONST_METHOD10_WITH_CALLTYPE(ct, m, __VA_ARGS__)
+
+#define GMOCK_INTERNAL_MOCK_METHODN(constness, ct, Method, args_num, ...) \
+  GMOCK_INTERNAL_ASSERT_VALID_SIGNATURE(                                  \
+      args_num, ::testing::internal::identity_t<__VA_ARGS__>);            \
+  GMOCK_INTERNAL_MOCK_METHOD_IMPL(                                        \
+      args_num, Method, GMOCK_PP_NARG0(constness), 0, 0, , ct, ,          \
+      (::testing::internal::identity_t<__VA_ARGS__>))
+
+#define GMOCK_MOCKER_(arity, constness, Method) \
+  GTEST_CONCAT_TOKEN_(gmock##constness##arity##_##Method##_, __LINE__)
+
+#endif  // GOOGLEMOCK_INCLUDE_GMOCK_INTERNAL_GMOCK_FUNCTION_MOCKER_H_
 // Copyright 2007, Google Inc.
 // All rights reserved.
 //
@@ -9870,249 +10723,20 @@
 
 // GOOGLETEST_CM0002 DO NOT DELETE
 
-#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_
-#define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_
+#ifndef GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_MORE_ACTIONS_H_
+#define GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_MORE_ACTIONS_H_
 
 #include <memory>
 #include <utility>
 
 
-namespace testing {
-namespace internal {
+// Include any custom callback actions added by the local installation.
+// GOOGLETEST_CM0002 DO NOT DELETE
 
-// A macro from the ACTION* family (defined later in this file)
-// defines an action that can be used in a mock function.  Typically,
-// these actions only care about a subset of the arguments of the mock
-// function.  For example, if such an action only uses the second
-// argument, it can be used in any mock function that takes >= 2
-// arguments where the type of the second argument is compatible.
-//
-// Therefore, the action implementation must be prepared to take more
-// arguments than it needs.  The ExcessiveArg type is used to
-// represent those excessive arguments.  In order to keep the compiler
-// error messages tractable, we define it in the testing namespace
-// instead of testing::internal.  However, this is an INTERNAL TYPE
-// and subject to change without notice, so a user MUST NOT USE THIS
-// TYPE DIRECTLY.
-struct ExcessiveArg {};
+#ifndef GOOGLEMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_GMOCK_GENERATED_ACTIONS_H_
+#define GOOGLEMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_GMOCK_GENERATED_ACTIONS_H_
 
-// A helper class needed for implementing the ACTION* macros.
-template <typename Result, class Impl>
-class ActionHelper {
- public:
-  static Result Perform(Impl* impl, const ::std::tuple<>& args) {
-    return impl->template gmock_PerformImpl<>(args, ExcessiveArg(),
-        ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(),
-        ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(),
-        ExcessiveArg());
-  }
-
-  template <typename A0>
-  static Result Perform(Impl* impl, const ::std::tuple<A0>& args) {
-    return impl->template gmock_PerformImpl<A0>(args, std::get<0>(args),
-        ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(),
-        ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(),
-        ExcessiveArg());
-  }
-
-  template <typename A0, typename A1>
-  static Result Perform(Impl* impl, const ::std::tuple<A0, A1>& args) {
-    return impl->template gmock_PerformImpl<A0, A1>(args, std::get<0>(args),
-        std::get<1>(args), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(),
-        ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(),
-        ExcessiveArg());
-  }
-
-  template <typename A0, typename A1, typename A2>
-  static Result Perform(Impl* impl, const ::std::tuple<A0, A1, A2>& args) {
-    return impl->template gmock_PerformImpl<A0, A1, A2>(args,
-        std::get<0>(args), std::get<1>(args), std::get<2>(args),
-        ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(),
-        ExcessiveArg(), ExcessiveArg(), ExcessiveArg());
-  }
-
-  template <typename A0, typename A1, typename A2, typename A3>
-  static Result Perform(Impl* impl, const ::std::tuple<A0, A1, A2, A3>& args) {
-    return impl->template gmock_PerformImpl<A0, A1, A2, A3>(args,
-        std::get<0>(args), std::get<1>(args), std::get<2>(args),
-        std::get<3>(args), ExcessiveArg(), ExcessiveArg(), ExcessiveArg(),
-        ExcessiveArg(), ExcessiveArg(), ExcessiveArg());
-  }
-
-  template <typename A0, typename A1, typename A2, typename A3, typename A4>
-  static Result Perform(Impl* impl, const ::std::tuple<A0, A1, A2, A3,
-      A4>& args) {
-    return impl->template gmock_PerformImpl<A0, A1, A2, A3, A4>(args,
-        std::get<0>(args), std::get<1>(args), std::get<2>(args),
-        std::get<3>(args), std::get<4>(args), ExcessiveArg(), ExcessiveArg(),
-        ExcessiveArg(), ExcessiveArg(), ExcessiveArg());
-  }
-
-  template <typename A0, typename A1, typename A2, typename A3, typename A4,
-      typename A5>
-  static Result Perform(Impl* impl, const ::std::tuple<A0, A1, A2, A3, A4,
-      A5>& args) {
-    return impl->template gmock_PerformImpl<A0, A1, A2, A3, A4, A5>(args,
-        std::get<0>(args), std::get<1>(args), std::get<2>(args),
-        std::get<3>(args), std::get<4>(args), std::get<5>(args),
-        ExcessiveArg(), ExcessiveArg(), ExcessiveArg(), ExcessiveArg());
-  }
-
-  template <typename A0, typename A1, typename A2, typename A3, typename A4,
-      typename A5, typename A6>
-  static Result Perform(Impl* impl, const ::std::tuple<A0, A1, A2, A3, A4, A5,
-      A6>& args) {
-    return impl->template gmock_PerformImpl<A0, A1, A2, A3, A4, A5, A6>(args,
-        std::get<0>(args), std::get<1>(args), std::get<2>(args),
-        std::get<3>(args), std::get<4>(args), std::get<5>(args),
-        std::get<6>(args), ExcessiveArg(), ExcessiveArg(), ExcessiveArg());
-  }
-
-  template <typename A0, typename A1, typename A2, typename A3, typename A4,
-      typename A5, typename A6, typename A7>
-  static Result Perform(Impl* impl, const ::std::tuple<A0, A1, A2, A3, A4, A5,
-      A6, A7>& args) {
-    return impl->template gmock_PerformImpl<A0, A1, A2, A3, A4, A5, A6,
-        A7>(args, std::get<0>(args), std::get<1>(args), std::get<2>(args),
-        std::get<3>(args), std::get<4>(args), std::get<5>(args),
-        std::get<6>(args), std::get<7>(args), ExcessiveArg(), ExcessiveArg());
-  }
-
-  template <typename A0, typename A1, typename A2, typename A3, typename A4,
-      typename A5, typename A6, typename A7, typename A8>
-  static Result Perform(Impl* impl, const ::std::tuple<A0, A1, A2, A3, A4, A5,
-      A6, A7, A8>& args) {
-    return impl->template gmock_PerformImpl<A0, A1, A2, A3, A4, A5, A6, A7,
-        A8>(args, std::get<0>(args), std::get<1>(args), std::get<2>(args),
-        std::get<3>(args), std::get<4>(args), std::get<5>(args),
-        std::get<6>(args), std::get<7>(args), std::get<8>(args),
-        ExcessiveArg());
-  }
-
-  template <typename A0, typename A1, typename A2, typename A3, typename A4,
-      typename A5, typename A6, typename A7, typename A8, typename A9>
-  static Result Perform(Impl* impl, const ::std::tuple<A0, A1, A2, A3, A4, A5,
-      A6, A7, A8, A9>& args) {
-    return impl->template gmock_PerformImpl<A0, A1, A2, A3, A4, A5, A6, A7, A8,
-        A9>(args, std::get<0>(args), std::get<1>(args), std::get<2>(args),
-        std::get<3>(args), std::get<4>(args), std::get<5>(args),
-        std::get<6>(args), std::get<7>(args), std::get<8>(args),
-        std::get<9>(args));
-  }
-};
-
-}  // namespace internal
-}  // namespace testing
-
-// The ACTION* family of macros can be used in a namespace scope to
-// define custom actions easily.  The syntax:
-//
-//   ACTION(name) { statements; }
-//
-// will define an action with the given name that executes the
-// statements.  The value returned by the statements will be used as
-// the return value of the action.  Inside the statements, you can
-// refer to the K-th (0-based) argument of the mock function by
-// 'argK', and refer to its type by 'argK_type'.  For example:
-//
-//   ACTION(IncrementArg1) {
-//     arg1_type temp = arg1;
-//     return ++(*temp);
-//   }
-//
-// allows you to write
-//
-//   ...WillOnce(IncrementArg1());
-//
-// You can also refer to the entire argument tuple and its type by
-// 'args' and 'args_type', and refer to the mock function type and its
-// return type by 'function_type' and 'return_type'.
-//
-// Note that you don't need to specify the types of the mock function
-// arguments.  However rest assured that your code is still type-safe:
-// you'll get a compiler error if *arg1 doesn't support the ++
-// operator, or if the type of ++(*arg1) isn't compatible with the
-// mock function's return type, for example.
-//
-// Sometimes you'll want to parameterize the action.   For that you can use
-// another macro:
-//
-//   ACTION_P(name, param_name) { statements; }
-//
-// For example:
-//
-//   ACTION_P(Add, n) { return arg0 + n; }
-//
-// will allow you to write:
-//
-//   ...WillOnce(Add(5));
-//
-// Note that you don't need to provide the type of the parameter
-// either.  If you need to reference the type of a parameter named
-// 'foo', you can write 'foo_type'.  For example, in the body of
-// ACTION_P(Add, n) above, you can write 'n_type' to refer to the type
-// of 'n'.
-//
-// We also provide ACTION_P2, ACTION_P3, ..., up to ACTION_P10 to support
-// multi-parameter actions.
-//
-// For the purpose of typing, you can view
-//
-//   ACTION_Pk(Foo, p1, ..., pk) { ... }
-//
-// as shorthand for
-//
-//   template <typename p1_type, ..., typename pk_type>
-//   FooActionPk<p1_type, ..., pk_type> Foo(p1_type p1, ..., pk_type pk) { ... }
-//
-// In particular, you can provide the template type arguments
-// explicitly when invoking Foo(), as in Foo<long, bool>(5, false);
-// although usually you can rely on the compiler to infer the types
-// for you automatically.  You can assign the result of expression
-// Foo(p1, ..., pk) to a variable of type FooActionPk<p1_type, ...,
-// pk_type>.  This can be useful when composing actions.
-//
-// You can also overload actions with different numbers of parameters:
-//
-//   ACTION_P(Plus, a) { ... }
-//   ACTION_P2(Plus, a, b) { ... }
-//
-// While it's tempting to always use the ACTION* macros when defining
-// a new action, you should also consider implementing ActionInterface
-// or using MakePolymorphicAction() instead, especially if you need to
-// use the action a lot.  While these approaches require more work,
-// they give you more control on the types of the mock function
-// arguments and the action parameters, which in general leads to
-// better compiler error messages that pay off in the long run.  They
-// also allow overloading actions based on parameter types (as opposed
-// to just based on the number of parameters).
-//
-// CAVEAT:
-//
-// ACTION*() can only be used in a namespace scope.  The reason is
-// that C++ doesn't yet allow function-local types to be used to
-// instantiate templates.  The up-coming C++0x standard will fix this.
-// Once that's done, we'll consider supporting using ACTION*() inside
-// a function.
-//
-// MORE INFORMATION:
-//
-// To learn more about using these macros, please search for 'ACTION' on
-// https://github.com/google/googletest/blob/master/googlemock/docs/CookBook.md
-
-// An internal macro needed for implementing ACTION*().
-#define GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_\
-    const args_type& args GTEST_ATTRIBUTE_UNUSED_, \
-    arg0_type arg0 GTEST_ATTRIBUTE_UNUSED_, \
-    arg1_type arg1 GTEST_ATTRIBUTE_UNUSED_, \
-    arg2_type arg2 GTEST_ATTRIBUTE_UNUSED_, \
-    arg3_type arg3 GTEST_ATTRIBUTE_UNUSED_, \
-    arg4_type arg4 GTEST_ATTRIBUTE_UNUSED_, \
-    arg5_type arg5 GTEST_ATTRIBUTE_UNUSED_, \
-    arg6_type arg6 GTEST_ATTRIBUTE_UNUSED_, \
-    arg7_type arg7 GTEST_ATTRIBUTE_UNUSED_, \
-    arg8_type arg8 GTEST_ATTRIBUTE_UNUSED_, \
-    arg9_type arg9 GTEST_ATTRIBUTE_UNUSED_
+#endif  // GOOGLEMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_GMOCK_GENERATED_ACTIONS_H_
 
 // Sometimes you want to give an action explicit template parameters
 // that cannot be inferred from its value parameters.  ACTION() and
@@ -10358,6 +10982,20 @@
         p7(::std::move(gmock_p7)), p8(::std::move(gmock_p8)), \
         p9(::std::move(gmock_p9))
 
+// Defines the copy constructor
+#define GMOCK_INTERNAL_DEFN_COPY_AND_0_VALUE_PARAMS() \
+    {}  // Avoid https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82134
+#define GMOCK_INTERNAL_DEFN_COPY_AND_1_VALUE_PARAMS(...) = default;
+#define GMOCK_INTERNAL_DEFN_COPY_AND_2_VALUE_PARAMS(...) = default;
+#define GMOCK_INTERNAL_DEFN_COPY_AND_3_VALUE_PARAMS(...) = default;
+#define GMOCK_INTERNAL_DEFN_COPY_AND_4_VALUE_PARAMS(...) = default;
+#define GMOCK_INTERNAL_DEFN_COPY_AND_5_VALUE_PARAMS(...) = default;
+#define GMOCK_INTERNAL_DEFN_COPY_AND_6_VALUE_PARAMS(...) = default;
+#define GMOCK_INTERNAL_DEFN_COPY_AND_7_VALUE_PARAMS(...) = default;
+#define GMOCK_INTERNAL_DEFN_COPY_AND_8_VALUE_PARAMS(...) = default;
+#define GMOCK_INTERNAL_DEFN_COPY_AND_9_VALUE_PARAMS(...) = default;
+#define GMOCK_INTERNAL_DEFN_COPY_AND_10_VALUE_PARAMS(...) = default;
+
 // Declares the fields for storing the value parameters.
 #define GMOCK_INTERNAL_DEFN_AND_0_VALUE_PARAMS()
 #define GMOCK_INTERNAL_DEFN_AND_1_VALUE_PARAMS(p0) p0##_type p0;
@@ -10479,874 +11117,70 @@
 #define GMOCK_ACTION_CLASS_(name, value_params)\
     GTEST_CONCAT_TOKEN_(name##Action, GMOCK_INTERNAL_COUNT_##value_params)
 
-#define ACTION_TEMPLATE(name, template_params, value_params)\
-  template <GMOCK_INTERNAL_DECL_##template_params\
-            GMOCK_INTERNAL_DECL_TYPE_##value_params>\
-  class GMOCK_ACTION_CLASS_(name, value_params) {\
-   public:\
-    explicit GMOCK_ACTION_CLASS_(name, value_params)\
-        GMOCK_INTERNAL_INIT_##value_params {}\
-    template <typename F>\
-    class gmock_Impl : public ::testing::ActionInterface<F> {\
-     public:\
-      typedef F function_type;\
-      typedef typename ::testing::internal::Function<F>::Result return_type;\
-      typedef typename ::testing::internal::Function<F>::ArgumentTuple\
-          args_type;\
-      explicit gmock_Impl GMOCK_INTERNAL_INIT_##value_params {}\
-      virtual return_type Perform(const args_type& args) {\
-        return ::testing::internal::ActionHelper<return_type, gmock_Impl>::\
-            Perform(this, args);\
-      }\
-      template <typename arg0_type, typename arg1_type, typename arg2_type, \
-          typename arg3_type, typename arg4_type, typename arg5_type, \
-          typename arg6_type, typename arg7_type, typename arg8_type, \
-          typename arg9_type>\
-      return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \
-          arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \
-          arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \
-          arg9_type arg9) const;\
-      GMOCK_INTERNAL_DEFN_##value_params\
-    };\
-    template <typename F> operator ::testing::Action<F>() const {\
-      return ::testing::Action<F>(\
-          new gmock_Impl<F>(GMOCK_INTERNAL_LIST_##value_params));\
-    }\
-    GMOCK_INTERNAL_DEFN_##value_params\
-  };\
-  template <GMOCK_INTERNAL_DECL_##template_params\
-            GMOCK_INTERNAL_DECL_TYPE_##value_params>\
-  inline GMOCK_ACTION_CLASS_(name, value_params)<\
-      GMOCK_INTERNAL_LIST_##template_params\
-      GMOCK_INTERNAL_LIST_TYPE_##value_params> name(\
-          GMOCK_INTERNAL_DECL_##value_params) {\
-    return GMOCK_ACTION_CLASS_(name, value_params)<\
-        GMOCK_INTERNAL_LIST_##template_params\
-        GMOCK_INTERNAL_LIST_TYPE_##value_params>(\
-            GMOCK_INTERNAL_LIST_##value_params);\
-  }\
-  template <GMOCK_INTERNAL_DECL_##template_params\
-            GMOCK_INTERNAL_DECL_TYPE_##value_params>\
-  template <typename F>\
-  template <typename arg0_type, typename arg1_type, typename arg2_type, \
-      typename arg3_type, typename arg4_type, typename arg5_type, \
-      typename arg6_type, typename arg7_type, typename arg8_type, \
-      typename arg9_type>\
-  typename ::testing::internal::Function<F>::Result\
-      GMOCK_ACTION_CLASS_(name, value_params)<\
-          GMOCK_INTERNAL_LIST_##template_params\
-          GMOCK_INTERNAL_LIST_TYPE_##value_params>::gmock_Impl<F>::\
-              gmock_PerformImpl(\
-          GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const
-
-#define ACTION(name)\
-  class name##Action {\
-   public:\
-    name##Action() {}\
-    template <typename F>\
-    class gmock_Impl : public ::testing::ActionInterface<F> {\
-     public:\
-      typedef F function_type;\
-      typedef typename ::testing::internal::Function<F>::Result return_type;\
-      typedef typename ::testing::internal::Function<F>::ArgumentTuple\
-          args_type;\
-      gmock_Impl() {}\
-      virtual return_type Perform(const args_type& args) {\
-        return ::testing::internal::ActionHelper<return_type, gmock_Impl>::\
-            Perform(this, args);\
-      }\
-      template <typename arg0_type, typename arg1_type, typename arg2_type, \
-          typename arg3_type, typename arg4_type, typename arg5_type, \
-          typename arg6_type, typename arg7_type, typename arg8_type, \
-          typename arg9_type>\
-      return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \
-          arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \
-          arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \
-          arg9_type arg9) const;\
-    };\
-    template <typename F> operator ::testing::Action<F>() const {\
-      return ::testing::Action<F>(new gmock_Impl<F>());\
-    }\
-  };\
-  inline name##Action name() {\
-    return name##Action();\
-  }\
-  template <typename F>\
-  template <typename arg0_type, typename arg1_type, typename arg2_type, \
-      typename arg3_type, typename arg4_type, typename arg5_type, \
-      typename arg6_type, typename arg7_type, typename arg8_type, \
-      typename arg9_type>\
-  typename ::testing::internal::Function<F>::Result\
-      name##Action::gmock_Impl<F>::gmock_PerformImpl(\
-          GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const
-
-#define ACTION_P(name, p0)\
-  template <typename p0##_type>\
-  class name##ActionP {\
-   public:\
-    explicit name##ActionP(p0##_type gmock_p0) : \
-        p0(::std::forward<p0##_type>(gmock_p0)) {}\
-    template <typename F>\
-    class gmock_Impl : public ::testing::ActionInterface<F> {\
-     public:\
-      typedef F function_type;\
-      typedef typename ::testing::internal::Function<F>::Result return_type;\
-      typedef typename ::testing::internal::Function<F>::ArgumentTuple\
-          args_type;\
-      explicit gmock_Impl(p0##_type gmock_p0) : \
-          p0(::std::forward<p0##_type>(gmock_p0)) {}\
-      virtual return_type Perform(const args_type& args) {\
-        return ::testing::internal::ActionHelper<return_type, gmock_Impl>::\
-            Perform(this, args);\
-      }\
-      template <typename arg0_type, typename arg1_type, typename arg2_type, \
-          typename arg3_type, typename arg4_type, typename arg5_type, \
-          typename arg6_type, typename arg7_type, typename arg8_type, \
-          typename arg9_type>\
-      return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \
-          arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \
-          arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \
-          arg9_type arg9) const;\
-      p0##_type p0;\
-    };\
-    template <typename F> operator ::testing::Action<F>() const {\
-      return ::testing::Action<F>(new gmock_Impl<F>(p0));\
-    }\
-    p0##_type p0;\
-  };\
-  template <typename p0##_type>\
-  inline name##ActionP<p0##_type> name(p0##_type p0) {\
-    return name##ActionP<p0##_type>(p0);\
-  }\
-  template <typename p0##_type>\
-  template <typename F>\
-  template <typename arg0_type, typename arg1_type, typename arg2_type, \
-      typename arg3_type, typename arg4_type, typename arg5_type, \
-      typename arg6_type, typename arg7_type, typename arg8_type, \
-      typename arg9_type>\
-  typename ::testing::internal::Function<F>::Result\
-      name##ActionP<p0##_type>::gmock_Impl<F>::gmock_PerformImpl(\
-          GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const
-
-#define ACTION_P2(name, p0, p1)\
-  template <typename p0##_type, typename p1##_type>\
-  class name##ActionP2 {\
-   public:\
-    name##ActionP2(p0##_type gmock_p0, \
-        p1##_type gmock_p1) : p0(::std::forward<p0##_type>(gmock_p0)), \
-        p1(::std::forward<p1##_type>(gmock_p1)) {}\
-    template <typename F>\
-    class gmock_Impl : public ::testing::ActionInterface<F> {\
-     public:\
-      typedef F function_type;\
-      typedef typename ::testing::internal::Function<F>::Result return_type;\
-      typedef typename ::testing::internal::Function<F>::ArgumentTuple\
-          args_type;\
-      gmock_Impl(p0##_type gmock_p0, \
-          p1##_type gmock_p1) : p0(::std::forward<p0##_type>(gmock_p0)), \
-          p1(::std::forward<p1##_type>(gmock_p1)) {}\
-      virtual return_type Perform(const args_type& args) {\
-        return ::testing::internal::ActionHelper<return_type, gmock_Impl>::\
-            Perform(this, args);\
-      }\
-      template <typename arg0_type, typename arg1_type, typename arg2_type, \
-          typename arg3_type, typename arg4_type, typename arg5_type, \
-          typename arg6_type, typename arg7_type, typename arg8_type, \
-          typename arg9_type>\
-      return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \
-          arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \
-          arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \
-          arg9_type arg9) const;\
-      p0##_type p0;\
-      p1##_type p1;\
-    };\
-    template <typename F> operator ::testing::Action<F>() const {\
-      return ::testing::Action<F>(new gmock_Impl<F>(p0, p1));\
-    }\
-    p0##_type p0;\
-    p1##_type p1;\
-  };\
-  template <typename p0##_type, typename p1##_type>\
-  inline name##ActionP2<p0##_type, p1##_type> name(p0##_type p0, \
-      p1##_type p1) {\
-    return name##ActionP2<p0##_type, p1##_type>(p0, p1);\
-  }\
-  template <typename p0##_type, typename p1##_type>\
-  template <typename F>\
-  template <typename arg0_type, typename arg1_type, typename arg2_type, \
-      typename arg3_type, typename arg4_type, typename arg5_type, \
-      typename arg6_type, typename arg7_type, typename arg8_type, \
-      typename arg9_type>\
-  typename ::testing::internal::Function<F>::Result\
-      name##ActionP2<p0##_type, p1##_type>::gmock_Impl<F>::gmock_PerformImpl(\
-          GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const
-
-#define ACTION_P3(name, p0, p1, p2)\
-  template <typename p0##_type, typename p1##_type, typename p2##_type>\
-  class name##ActionP3 {\
-   public:\
-    name##ActionP3(p0##_type gmock_p0, p1##_type gmock_p1, \
-        p2##_type gmock_p2) : p0(::std::forward<p0##_type>(gmock_p0)), \
-        p1(::std::forward<p1##_type>(gmock_p1)), \
-        p2(::std::forward<p2##_type>(gmock_p2)) {}\
-    template <typename F>\
-    class gmock_Impl : public ::testing::ActionInterface<F> {\
-     public:\
-      typedef F function_type;\
-      typedef typename ::testing::internal::Function<F>::Result return_type;\
-      typedef typename ::testing::internal::Function<F>::ArgumentTuple\
-          args_type;\
-      gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, \
-          p2##_type gmock_p2) : p0(::std::forward<p0##_type>(gmock_p0)), \
-          p1(::std::forward<p1##_type>(gmock_p1)), \
-          p2(::std::forward<p2##_type>(gmock_p2)) {}\
-      virtual return_type Perform(const args_type& args) {\
-        return ::testing::internal::ActionHelper<return_type, gmock_Impl>::\
-            Perform(this, args);\
-      }\
-      template <typename arg0_type, typename arg1_type, typename arg2_type, \
-          typename arg3_type, typename arg4_type, typename arg5_type, \
-          typename arg6_type, typename arg7_type, typename arg8_type, \
-          typename arg9_type>\
-      return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \
-          arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \
-          arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \
-          arg9_type arg9) const;\
-      p0##_type p0;\
-      p1##_type p1;\
-      p2##_type p2;\
-    };\
-    template <typename F> operator ::testing::Action<F>() const {\
-      return ::testing::Action<F>(new gmock_Impl<F>(p0, p1, p2));\
-    }\
-    p0##_type p0;\
-    p1##_type p1;\
-    p2##_type p2;\
-  };\
-  template <typename p0##_type, typename p1##_type, typename p2##_type>\
-  inline name##ActionP3<p0##_type, p1##_type, p2##_type> name(p0##_type p0, \
-      p1##_type p1, p2##_type p2) {\
-    return name##ActionP3<p0##_type, p1##_type, p2##_type>(p0, p1, p2);\
-  }\
-  template <typename p0##_type, typename p1##_type, typename p2##_type>\
-  template <typename F>\
-  template <typename arg0_type, typename arg1_type, typename arg2_type, \
-      typename arg3_type, typename arg4_type, typename arg5_type, \
-      typename arg6_type, typename arg7_type, typename arg8_type, \
-      typename arg9_type>\
-  typename ::testing::internal::Function<F>::Result\
-      name##ActionP3<p0##_type, p1##_type, \
-          p2##_type>::gmock_Impl<F>::gmock_PerformImpl(\
-          GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const
-
-#define ACTION_P4(name, p0, p1, p2, p3)\
-  template <typename p0##_type, typename p1##_type, typename p2##_type, \
-      typename p3##_type>\
-  class name##ActionP4 {\
-   public:\
-    name##ActionP4(p0##_type gmock_p0, p1##_type gmock_p1, \
-        p2##_type gmock_p2, \
-        p3##_type gmock_p3) : p0(::std::forward<p0##_type>(gmock_p0)), \
-        p1(::std::forward<p1##_type>(gmock_p1)), \
-        p2(::std::forward<p2##_type>(gmock_p2)), \
-        p3(::std::forward<p3##_type>(gmock_p3)) {}\
-    template <typename F>\
-    class gmock_Impl : public ::testing::ActionInterface<F> {\
-     public:\
-      typedef F function_type;\
-      typedef typename ::testing::internal::Function<F>::Result return_type;\
-      typedef typename ::testing::internal::Function<F>::ArgumentTuple\
-          args_type;\
-      gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
-          p3##_type gmock_p3) : p0(::std::forward<p0##_type>(gmock_p0)), \
-          p1(::std::forward<p1##_type>(gmock_p1)), \
-          p2(::std::forward<p2##_type>(gmock_p2)), \
-          p3(::std::forward<p3##_type>(gmock_p3)) {}\
-      virtual return_type Perform(const args_type& args) {\
-        return ::testing::internal::ActionHelper<return_type, gmock_Impl>::\
-            Perform(this, args);\
-      }\
-      template <typename arg0_type, typename arg1_type, typename arg2_type, \
-          typename arg3_type, typename arg4_type, typename arg5_type, \
-          typename arg6_type, typename arg7_type, typename arg8_type, \
-          typename arg9_type>\
-      return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \
-          arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \
-          arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \
-          arg9_type arg9) const;\
-      p0##_type p0;\
-      p1##_type p1;\
-      p2##_type p2;\
-      p3##_type p3;\
-    };\
-    template <typename F> operator ::testing::Action<F>() const {\
-      return ::testing::Action<F>(new gmock_Impl<F>(p0, p1, p2, p3));\
-    }\
-    p0##_type p0;\
-    p1##_type p1;\
-    p2##_type p2;\
-    p3##_type p3;\
-  };\
-  template <typename p0##_type, typename p1##_type, typename p2##_type, \
-      typename p3##_type>\
-  inline name##ActionP4<p0##_type, p1##_type, p2##_type, \
-      p3##_type> name(p0##_type p0, p1##_type p1, p2##_type p2, \
-      p3##_type p3) {\
-    return name##ActionP4<p0##_type, p1##_type, p2##_type, p3##_type>(p0, p1, \
-        p2, p3);\
-  }\
-  template <typename p0##_type, typename p1##_type, typename p2##_type, \
-      typename p3##_type>\
-  template <typename F>\
-  template <typename arg0_type, typename arg1_type, typename arg2_type, \
-      typename arg3_type, typename arg4_type, typename arg5_type, \
-      typename arg6_type, typename arg7_type, typename arg8_type, \
-      typename arg9_type>\
-  typename ::testing::internal::Function<F>::Result\
-      name##ActionP4<p0##_type, p1##_type, p2##_type, \
-          p3##_type>::gmock_Impl<F>::gmock_PerformImpl(\
-          GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const
-
-#define ACTION_P5(name, p0, p1, p2, p3, p4)\
-  template <typename p0##_type, typename p1##_type, typename p2##_type, \
-      typename p3##_type, typename p4##_type>\
-  class name##ActionP5 {\
-   public:\
-    name##ActionP5(p0##_type gmock_p0, p1##_type gmock_p1, \
-        p2##_type gmock_p2, p3##_type gmock_p3, \
-        p4##_type gmock_p4) : p0(::std::forward<p0##_type>(gmock_p0)), \
-        p1(::std::forward<p1##_type>(gmock_p1)), \
-        p2(::std::forward<p2##_type>(gmock_p2)), \
-        p3(::std::forward<p3##_type>(gmock_p3)), \
-        p4(::std::forward<p4##_type>(gmock_p4)) {}\
-    template <typename F>\
-    class gmock_Impl : public ::testing::ActionInterface<F> {\
-     public:\
-      typedef F function_type;\
-      typedef typename ::testing::internal::Function<F>::Result return_type;\
-      typedef typename ::testing::internal::Function<F>::ArgumentTuple\
-          args_type;\
-      gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
-          p3##_type gmock_p3, \
-          p4##_type gmock_p4) : p0(::std::forward<p0##_type>(gmock_p0)), \
-          p1(::std::forward<p1##_type>(gmock_p1)), \
-          p2(::std::forward<p2##_type>(gmock_p2)), \
-          p3(::std::forward<p3##_type>(gmock_p3)), \
-          p4(::std::forward<p4##_type>(gmock_p4)) {}\
-      virtual return_type Perform(const args_type& args) {\
-        return ::testing::internal::ActionHelper<return_type, gmock_Impl>::\
-            Perform(this, args);\
-      }\
-      template <typename arg0_type, typename arg1_type, typename arg2_type, \
-          typename arg3_type, typename arg4_type, typename arg5_type, \
-          typename arg6_type, typename arg7_type, typename arg8_type, \
-          typename arg9_type>\
-      return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \
-          arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \
-          arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \
-          arg9_type arg9) const;\
-      p0##_type p0;\
-      p1##_type p1;\
-      p2##_type p2;\
-      p3##_type p3;\
-      p4##_type p4;\
-    };\
-    template <typename F> operator ::testing::Action<F>() const {\
-      return ::testing::Action<F>(new gmock_Impl<F>(p0, p1, p2, p3, p4));\
-    }\
-    p0##_type p0;\
-    p1##_type p1;\
-    p2##_type p2;\
-    p3##_type p3;\
-    p4##_type p4;\
-  };\
-  template <typename p0##_type, typename p1##_type, typename p2##_type, \
-      typename p3##_type, typename p4##_type>\
-  inline name##ActionP5<p0##_type, p1##_type, p2##_type, p3##_type, \
-      p4##_type> name(p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \
-      p4##_type p4) {\
-    return name##ActionP5<p0##_type, p1##_type, p2##_type, p3##_type, \
-        p4##_type>(p0, p1, p2, p3, p4);\
-  }\
-  template <typename p0##_type, typename p1##_type, typename p2##_type, \
-      typename p3##_type, typename p4##_type>\
-  template <typename F>\
-  template <typename arg0_type, typename arg1_type, typename arg2_type, \
-      typename arg3_type, typename arg4_type, typename arg5_type, \
-      typename arg6_type, typename arg7_type, typename arg8_type, \
-      typename arg9_type>\
-  typename ::testing::internal::Function<F>::Result\
-      name##ActionP5<p0##_type, p1##_type, p2##_type, p3##_type, \
-          p4##_type>::gmock_Impl<F>::gmock_PerformImpl(\
-          GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const
-
-#define ACTION_P6(name, p0, p1, p2, p3, p4, p5)\
-  template <typename p0##_type, typename p1##_type, typename p2##_type, \
-      typename p3##_type, typename p4##_type, typename p5##_type>\
-  class name##ActionP6 {\
-   public:\
-    name##ActionP6(p0##_type gmock_p0, p1##_type gmock_p1, \
-        p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \
-        p5##_type gmock_p5) : p0(::std::forward<p0##_type>(gmock_p0)), \
-        p1(::std::forward<p1##_type>(gmock_p1)), \
-        p2(::std::forward<p2##_type>(gmock_p2)), \
-        p3(::std::forward<p3##_type>(gmock_p3)), \
-        p4(::std::forward<p4##_type>(gmock_p4)), \
-        p5(::std::forward<p5##_type>(gmock_p5)) {}\
-    template <typename F>\
-    class gmock_Impl : public ::testing::ActionInterface<F> {\
-     public:\
-      typedef F function_type;\
-      typedef typename ::testing::internal::Function<F>::Result return_type;\
-      typedef typename ::testing::internal::Function<F>::ArgumentTuple\
-          args_type;\
-      gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
-          p3##_type gmock_p3, p4##_type gmock_p4, \
-          p5##_type gmock_p5) : p0(::std::forward<p0##_type>(gmock_p0)), \
-          p1(::std::forward<p1##_type>(gmock_p1)), \
-          p2(::std::forward<p2##_type>(gmock_p2)), \
-          p3(::std::forward<p3##_type>(gmock_p3)), \
-          p4(::std::forward<p4##_type>(gmock_p4)), \
-          p5(::std::forward<p5##_type>(gmock_p5)) {}\
-      virtual return_type Perform(const args_type& args) {\
-        return ::testing::internal::ActionHelper<return_type, gmock_Impl>::\
-            Perform(this, args);\
-      }\
-      template <typename arg0_type, typename arg1_type, typename arg2_type, \
-          typename arg3_type, typename arg4_type, typename arg5_type, \
-          typename arg6_type, typename arg7_type, typename arg8_type, \
-          typename arg9_type>\
-      return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \
-          arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \
-          arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \
-          arg9_type arg9) const;\
-      p0##_type p0;\
-      p1##_type p1;\
-      p2##_type p2;\
-      p3##_type p3;\
-      p4##_type p4;\
-      p5##_type p5;\
-    };\
-    template <typename F> operator ::testing::Action<F>() const {\
-      return ::testing::Action<F>(new gmock_Impl<F>(p0, p1, p2, p3, p4, p5));\
-    }\
-    p0##_type p0;\
-    p1##_type p1;\
-    p2##_type p2;\
-    p3##_type p3;\
-    p4##_type p4;\
-    p5##_type p5;\
-  };\
-  template <typename p0##_type, typename p1##_type, typename p2##_type, \
-      typename p3##_type, typename p4##_type, typename p5##_type>\
-  inline name##ActionP6<p0##_type, p1##_type, p2##_type, p3##_type, \
-      p4##_type, p5##_type> name(p0##_type p0, p1##_type p1, p2##_type p2, \
-      p3##_type p3, p4##_type p4, p5##_type p5) {\
-    return name##ActionP6<p0##_type, p1##_type, p2##_type, p3##_type, \
-        p4##_type, p5##_type>(p0, p1, p2, p3, p4, p5);\
-  }\
-  template <typename p0##_type, typename p1##_type, typename p2##_type, \
-      typename p3##_type, typename p4##_type, typename p5##_type>\
-  template <typename F>\
-  template <typename arg0_type, typename arg1_type, typename arg2_type, \
-      typename arg3_type, typename arg4_type, typename arg5_type, \
-      typename arg6_type, typename arg7_type, typename arg8_type, \
-      typename arg9_type>\
-  typename ::testing::internal::Function<F>::Result\
-      name##ActionP6<p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, \
-          p5##_type>::gmock_Impl<F>::gmock_PerformImpl(\
-          GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const
-
-#define ACTION_P7(name, p0, p1, p2, p3, p4, p5, p6)\
-  template <typename p0##_type, typename p1##_type, typename p2##_type, \
-      typename p3##_type, typename p4##_type, typename p5##_type, \
-      typename p6##_type>\
-  class name##ActionP7 {\
-   public:\
-    name##ActionP7(p0##_type gmock_p0, p1##_type gmock_p1, \
-        p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \
-        p5##_type gmock_p5, \
-        p6##_type gmock_p6) : p0(::std::forward<p0##_type>(gmock_p0)), \
-        p1(::std::forward<p1##_type>(gmock_p1)), \
-        p2(::std::forward<p2##_type>(gmock_p2)), \
-        p3(::std::forward<p3##_type>(gmock_p3)), \
-        p4(::std::forward<p4##_type>(gmock_p4)), \
-        p5(::std::forward<p5##_type>(gmock_p5)), \
-        p6(::std::forward<p6##_type>(gmock_p6)) {}\
-    template <typename F>\
-    class gmock_Impl : public ::testing::ActionInterface<F> {\
-     public:\
-      typedef F function_type;\
-      typedef typename ::testing::internal::Function<F>::Result return_type;\
-      typedef typename ::testing::internal::Function<F>::ArgumentTuple\
-          args_type;\
-      gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
-          p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \
-          p6##_type gmock_p6) : p0(::std::forward<p0##_type>(gmock_p0)), \
-          p1(::std::forward<p1##_type>(gmock_p1)), \
-          p2(::std::forward<p2##_type>(gmock_p2)), \
-          p3(::std::forward<p3##_type>(gmock_p3)), \
-          p4(::std::forward<p4##_type>(gmock_p4)), \
-          p5(::std::forward<p5##_type>(gmock_p5)), \
-          p6(::std::forward<p6##_type>(gmock_p6)) {}\
-      virtual return_type Perform(const args_type& args) {\
-        return ::testing::internal::ActionHelper<return_type, gmock_Impl>::\
-            Perform(this, args);\
-      }\
-      template <typename arg0_type, typename arg1_type, typename arg2_type, \
-          typename arg3_type, typename arg4_type, typename arg5_type, \
-          typename arg6_type, typename arg7_type, typename arg8_type, \
-          typename arg9_type>\
-      return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \
-          arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \
-          arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \
-          arg9_type arg9) const;\
-      p0##_type p0;\
-      p1##_type p1;\
-      p2##_type p2;\
-      p3##_type p3;\
-      p4##_type p4;\
-      p5##_type p5;\
-      p6##_type p6;\
-    };\
-    template <typename F> operator ::testing::Action<F>() const {\
-      return ::testing::Action<F>(new gmock_Impl<F>(p0, p1, p2, p3, p4, p5, \
-          p6));\
-    }\
-    p0##_type p0;\
-    p1##_type p1;\
-    p2##_type p2;\
-    p3##_type p3;\
-    p4##_type p4;\
-    p5##_type p5;\
-    p6##_type p6;\
-  };\
-  template <typename p0##_type, typename p1##_type, typename p2##_type, \
-      typename p3##_type, typename p4##_type, typename p5##_type, \
-      typename p6##_type>\
-  inline name##ActionP7<p0##_type, p1##_type, p2##_type, p3##_type, \
-      p4##_type, p5##_type, p6##_type> name(p0##_type p0, p1##_type p1, \
-      p2##_type p2, p3##_type p3, p4##_type p4, p5##_type p5, \
-      p6##_type p6) {\
-    return name##ActionP7<p0##_type, p1##_type, p2##_type, p3##_type, \
-        p4##_type, p5##_type, p6##_type>(p0, p1, p2, p3, p4, p5, p6);\
-  }\
-  template <typename p0##_type, typename p1##_type, typename p2##_type, \
-      typename p3##_type, typename p4##_type, typename p5##_type, \
-      typename p6##_type>\
-  template <typename F>\
-  template <typename arg0_type, typename arg1_type, typename arg2_type, \
-      typename arg3_type, typename arg4_type, typename arg5_type, \
-      typename arg6_type, typename arg7_type, typename arg8_type, \
-      typename arg9_type>\
-  typename ::testing::internal::Function<F>::Result\
-      name##ActionP7<p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, \
-          p5##_type, p6##_type>::gmock_Impl<F>::gmock_PerformImpl(\
-          GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const
-
-#define ACTION_P8(name, p0, p1, p2, p3, p4, p5, p6, p7)\
-  template <typename p0##_type, typename p1##_type, typename p2##_type, \
-      typename p3##_type, typename p4##_type, typename p5##_type, \
-      typename p6##_type, typename p7##_type>\
-  class name##ActionP8 {\
-   public:\
-    name##ActionP8(p0##_type gmock_p0, p1##_type gmock_p1, \
-        p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \
-        p5##_type gmock_p5, p6##_type gmock_p6, \
-        p7##_type gmock_p7) : p0(::std::forward<p0##_type>(gmock_p0)), \
-        p1(::std::forward<p1##_type>(gmock_p1)), \
-        p2(::std::forward<p2##_type>(gmock_p2)), \
-        p3(::std::forward<p3##_type>(gmock_p3)), \
-        p4(::std::forward<p4##_type>(gmock_p4)), \
-        p5(::std::forward<p5##_type>(gmock_p5)), \
-        p6(::std::forward<p6##_type>(gmock_p6)), \
-        p7(::std::forward<p7##_type>(gmock_p7)) {}\
-    template <typename F>\
-    class gmock_Impl : public ::testing::ActionInterface<F> {\
-     public:\
-      typedef F function_type;\
-      typedef typename ::testing::internal::Function<F>::Result return_type;\
-      typedef typename ::testing::internal::Function<F>::ArgumentTuple\
-          args_type;\
-      gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
-          p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \
-          p6##_type gmock_p6, \
-          p7##_type gmock_p7) : p0(::std::forward<p0##_type>(gmock_p0)), \
-          p1(::std::forward<p1##_type>(gmock_p1)), \
-          p2(::std::forward<p2##_type>(gmock_p2)), \
-          p3(::std::forward<p3##_type>(gmock_p3)), \
-          p4(::std::forward<p4##_type>(gmock_p4)), \
-          p5(::std::forward<p5##_type>(gmock_p5)), \
-          p6(::std::forward<p6##_type>(gmock_p6)), \
-          p7(::std::forward<p7##_type>(gmock_p7)) {}\
-      virtual return_type Perform(const args_type& args) {\
-        return ::testing::internal::ActionHelper<return_type, gmock_Impl>::\
-            Perform(this, args);\
-      }\
-      template <typename arg0_type, typename arg1_type, typename arg2_type, \
-          typename arg3_type, typename arg4_type, typename arg5_type, \
-          typename arg6_type, typename arg7_type, typename arg8_type, \
-          typename arg9_type>\
-      return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \
-          arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \
-          arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \
-          arg9_type arg9) const;\
-      p0##_type p0;\
-      p1##_type p1;\
-      p2##_type p2;\
-      p3##_type p3;\
-      p4##_type p4;\
-      p5##_type p5;\
-      p6##_type p6;\
-      p7##_type p7;\
-    };\
-    template <typename F> operator ::testing::Action<F>() const {\
-      return ::testing::Action<F>(new gmock_Impl<F>(p0, p1, p2, p3, p4, p5, \
-          p6, p7));\
-    }\
-    p0##_type p0;\
-    p1##_type p1;\
-    p2##_type p2;\
-    p3##_type p3;\
-    p4##_type p4;\
-    p5##_type p5;\
-    p6##_type p6;\
-    p7##_type p7;\
-  };\
-  template <typename p0##_type, typename p1##_type, typename p2##_type, \
-      typename p3##_type, typename p4##_type, typename p5##_type, \
-      typename p6##_type, typename p7##_type>\
-  inline name##ActionP8<p0##_type, p1##_type, p2##_type, p3##_type, \
-      p4##_type, p5##_type, p6##_type, p7##_type> name(p0##_type p0, \
-      p1##_type p1, p2##_type p2, p3##_type p3, p4##_type p4, p5##_type p5, \
-      p6##_type p6, p7##_type p7) {\
-    return name##ActionP8<p0##_type, p1##_type, p2##_type, p3##_type, \
-        p4##_type, p5##_type, p6##_type, p7##_type>(p0, p1, p2, p3, p4, p5, \
-        p6, p7);\
-  }\
-  template <typename p0##_type, typename p1##_type, typename p2##_type, \
-      typename p3##_type, typename p4##_type, typename p5##_type, \
-      typename p6##_type, typename p7##_type>\
-  template <typename F>\
-  template <typename arg0_type, typename arg1_type, typename arg2_type, \
-      typename arg3_type, typename arg4_type, typename arg5_type, \
-      typename arg6_type, typename arg7_type, typename arg8_type, \
-      typename arg9_type>\
-  typename ::testing::internal::Function<F>::Result\
-      name##ActionP8<p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, \
-          p5##_type, p6##_type, \
-          p7##_type>::gmock_Impl<F>::gmock_PerformImpl(\
-          GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const
-
-#define ACTION_P9(name, p0, p1, p2, p3, p4, p5, p6, p7, p8)\
-  template <typename p0##_type, typename p1##_type, typename p2##_type, \
-      typename p3##_type, typename p4##_type, typename p5##_type, \
-      typename p6##_type, typename p7##_type, typename p8##_type>\
-  class name##ActionP9 {\
-   public:\
-    name##ActionP9(p0##_type gmock_p0, p1##_type gmock_p1, \
-        p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \
-        p5##_type gmock_p5, p6##_type gmock_p6, p7##_type gmock_p7, \
-        p8##_type gmock_p8) : p0(::std::forward<p0##_type>(gmock_p0)), \
-        p1(::std::forward<p1##_type>(gmock_p1)), \
-        p2(::std::forward<p2##_type>(gmock_p2)), \
-        p3(::std::forward<p3##_type>(gmock_p3)), \
-        p4(::std::forward<p4##_type>(gmock_p4)), \
-        p5(::std::forward<p5##_type>(gmock_p5)), \
-        p6(::std::forward<p6##_type>(gmock_p6)), \
-        p7(::std::forward<p7##_type>(gmock_p7)), \
-        p8(::std::forward<p8##_type>(gmock_p8)) {}\
-    template <typename F>\
-    class gmock_Impl : public ::testing::ActionInterface<F> {\
-     public:\
-      typedef F function_type;\
-      typedef typename ::testing::internal::Function<F>::Result return_type;\
-      typedef typename ::testing::internal::Function<F>::ArgumentTuple\
-          args_type;\
-      gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
-          p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \
-          p6##_type gmock_p6, p7##_type gmock_p7, \
-          p8##_type gmock_p8) : p0(::std::forward<p0##_type>(gmock_p0)), \
-          p1(::std::forward<p1##_type>(gmock_p1)), \
-          p2(::std::forward<p2##_type>(gmock_p2)), \
-          p3(::std::forward<p3##_type>(gmock_p3)), \
-          p4(::std::forward<p4##_type>(gmock_p4)), \
-          p5(::std::forward<p5##_type>(gmock_p5)), \
-          p6(::std::forward<p6##_type>(gmock_p6)), \
-          p7(::std::forward<p7##_type>(gmock_p7)), \
-          p8(::std::forward<p8##_type>(gmock_p8)) {}\
-      virtual return_type Perform(const args_type& args) {\
-        return ::testing::internal::ActionHelper<return_type, gmock_Impl>::\
-            Perform(this, args);\
-      }\
-      template <typename arg0_type, typename arg1_type, typename arg2_type, \
-          typename arg3_type, typename arg4_type, typename arg5_type, \
-          typename arg6_type, typename arg7_type, typename arg8_type, \
-          typename arg9_type>\
-      return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \
-          arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \
-          arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \
-          arg9_type arg9) const;\
-      p0##_type p0;\
-      p1##_type p1;\
-      p2##_type p2;\
-      p3##_type p3;\
-      p4##_type p4;\
-      p5##_type p5;\
-      p6##_type p6;\
-      p7##_type p7;\
-      p8##_type p8;\
-    };\
-    template <typename F> operator ::testing::Action<F>() const {\
-      return ::testing::Action<F>(new gmock_Impl<F>(p0, p1, p2, p3, p4, p5, \
-          p6, p7, p8));\
-    }\
-    p0##_type p0;\
-    p1##_type p1;\
-    p2##_type p2;\
-    p3##_type p3;\
-    p4##_type p4;\
-    p5##_type p5;\
-    p6##_type p6;\
-    p7##_type p7;\
-    p8##_type p8;\
-  };\
-  template <typename p0##_type, typename p1##_type, typename p2##_type, \
-      typename p3##_type, typename p4##_type, typename p5##_type, \
-      typename p6##_type, typename p7##_type, typename p8##_type>\
-  inline name##ActionP9<p0##_type, p1##_type, p2##_type, p3##_type, \
-      p4##_type, p5##_type, p6##_type, p7##_type, \
-      p8##_type> name(p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \
-      p4##_type p4, p5##_type p5, p6##_type p6, p7##_type p7, \
-      p8##_type p8) {\
-    return name##ActionP9<p0##_type, p1##_type, p2##_type, p3##_type, \
-        p4##_type, p5##_type, p6##_type, p7##_type, p8##_type>(p0, p1, p2, \
-        p3, p4, p5, p6, p7, p8);\
-  }\
-  template <typename p0##_type, typename p1##_type, typename p2##_type, \
-      typename p3##_type, typename p4##_type, typename p5##_type, \
-      typename p6##_type, typename p7##_type, typename p8##_type>\
-  template <typename F>\
-  template <typename arg0_type, typename arg1_type, typename arg2_type, \
-      typename arg3_type, typename arg4_type, typename arg5_type, \
-      typename arg6_type, typename arg7_type, typename arg8_type, \
-      typename arg9_type>\
-  typename ::testing::internal::Function<F>::Result\
-      name##ActionP9<p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, \
-          p5##_type, p6##_type, p7##_type, \
-          p8##_type>::gmock_Impl<F>::gmock_PerformImpl(\
-          GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const
-
-#define ACTION_P10(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9)\
-  template <typename p0##_type, typename p1##_type, typename p2##_type, \
-      typename p3##_type, typename p4##_type, typename p5##_type, \
-      typename p6##_type, typename p7##_type, typename p8##_type, \
-      typename p9##_type>\
-  class name##ActionP10 {\
-   public:\
-    name##ActionP10(p0##_type gmock_p0, p1##_type gmock_p1, \
-        p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \
-        p5##_type gmock_p5, p6##_type gmock_p6, p7##_type gmock_p7, \
-        p8##_type gmock_p8, \
-        p9##_type gmock_p9) : p0(::std::forward<p0##_type>(gmock_p0)), \
-        p1(::std::forward<p1##_type>(gmock_p1)), \
-        p2(::std::forward<p2##_type>(gmock_p2)), \
-        p3(::std::forward<p3##_type>(gmock_p3)), \
-        p4(::std::forward<p4##_type>(gmock_p4)), \
-        p5(::std::forward<p5##_type>(gmock_p5)), \
-        p6(::std::forward<p6##_type>(gmock_p6)), \
-        p7(::std::forward<p7##_type>(gmock_p7)), \
-        p8(::std::forward<p8##_type>(gmock_p8)), \
-        p9(::std::forward<p9##_type>(gmock_p9)) {}\
-    template <typename F>\
-    class gmock_Impl : public ::testing::ActionInterface<F> {\
-     public:\
-      typedef F function_type;\
-      typedef typename ::testing::internal::Function<F>::Result return_type;\
-      typedef typename ::testing::internal::Function<F>::ArgumentTuple\
-          args_type;\
-      gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
-          p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \
-          p6##_type gmock_p6, p7##_type gmock_p7, p8##_type gmock_p8, \
-          p9##_type gmock_p9) : p0(::std::forward<p0##_type>(gmock_p0)), \
-          p1(::std::forward<p1##_type>(gmock_p1)), \
-          p2(::std::forward<p2##_type>(gmock_p2)), \
-          p3(::std::forward<p3##_type>(gmock_p3)), \
-          p4(::std::forward<p4##_type>(gmock_p4)), \
-          p5(::std::forward<p5##_type>(gmock_p5)), \
-          p6(::std::forward<p6##_type>(gmock_p6)), \
-          p7(::std::forward<p7##_type>(gmock_p7)), \
-          p8(::std::forward<p8##_type>(gmock_p8)), \
-          p9(::std::forward<p9##_type>(gmock_p9)) {}\
-      virtual return_type Perform(const args_type& args) {\
-        return ::testing::internal::ActionHelper<return_type, gmock_Impl>::\
-            Perform(this, args);\
-      }\
-      template <typename arg0_type, typename arg1_type, typename arg2_type, \
-          typename arg3_type, typename arg4_type, typename arg5_type, \
-          typename arg6_type, typename arg7_type, typename arg8_type, \
-          typename arg9_type>\
-      return_type gmock_PerformImpl(const args_type& args, arg0_type arg0, \
-          arg1_type arg1, arg2_type arg2, arg3_type arg3, arg4_type arg4, \
-          arg5_type arg5, arg6_type arg6, arg7_type arg7, arg8_type arg8, \
-          arg9_type arg9) const;\
-      p0##_type p0;\
-      p1##_type p1;\
-      p2##_type p2;\
-      p3##_type p3;\
-      p4##_type p4;\
-      p5##_type p5;\
-      p6##_type p6;\
-      p7##_type p7;\
-      p8##_type p8;\
-      p9##_type p9;\
-    };\
-    template <typename F> operator ::testing::Action<F>() const {\
-      return ::testing::Action<F>(new gmock_Impl<F>(p0, p1, p2, p3, p4, p5, \
-          p6, p7, p8, p9));\
-    }\
-    p0##_type p0;\
-    p1##_type p1;\
-    p2##_type p2;\
-    p3##_type p3;\
-    p4##_type p4;\
-    p5##_type p5;\
-    p6##_type p6;\
-    p7##_type p7;\
-    p8##_type p8;\
-    p9##_type p9;\
-  };\
-  template <typename p0##_type, typename p1##_type, typename p2##_type, \
-      typename p3##_type, typename p4##_type, typename p5##_type, \
-      typename p6##_type, typename p7##_type, typename p8##_type, \
-      typename p9##_type>\
-  inline name##ActionP10<p0##_type, p1##_type, p2##_type, p3##_type, \
-      p4##_type, p5##_type, p6##_type, p7##_type, p8##_type, \
-      p9##_type> name(p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \
-      p4##_type p4, p5##_type p5, p6##_type p6, p7##_type p7, p8##_type p8, \
-      p9##_type p9) {\
-    return name##ActionP10<p0##_type, p1##_type, p2##_type, p3##_type, \
-        p4##_type, p5##_type, p6##_type, p7##_type, p8##_type, p9##_type>(p0, \
-        p1, p2, p3, p4, p5, p6, p7, p8, p9);\
-  }\
-  template <typename p0##_type, typename p1##_type, typename p2##_type, \
-      typename p3##_type, typename p4##_type, typename p5##_type, \
-      typename p6##_type, typename p7##_type, typename p8##_type, \
-      typename p9##_type>\
-  template <typename F>\
-  template <typename arg0_type, typename arg1_type, typename arg2_type, \
-      typename arg3_type, typename arg4_type, typename arg5_type, \
-      typename arg6_type, typename arg7_type, typename arg8_type, \
-      typename arg9_type>\
-  typename ::testing::internal::Function<F>::Result\
-      name##ActionP10<p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, \
-          p5##_type, p6##_type, p7##_type, p8##_type, \
-          p9##_type>::gmock_Impl<F>::gmock_PerformImpl(\
+#define ACTION_TEMPLATE(name, template_params, value_params)                   \
+  template <GMOCK_INTERNAL_DECL_##template_params                              \
+            GMOCK_INTERNAL_DECL_TYPE_##value_params>                           \
+  class GMOCK_ACTION_CLASS_(name, value_params) {                              \
+   public:                                                                     \
+    explicit GMOCK_ACTION_CLASS_(name, value_params)(                          \
+        GMOCK_INTERNAL_DECL_##value_params)                                    \
+        GMOCK_PP_IF(GMOCK_PP_IS_EMPTY(GMOCK_INTERNAL_COUNT_##value_params),    \
+                    = default; ,                                               \
+                    : impl_(std::make_shared<gmock_Impl>(                      \
+                                GMOCK_INTERNAL_LIST_##value_params)) { })      \
+    GMOCK_ACTION_CLASS_(name, value_params)(                                   \
+        const GMOCK_ACTION_CLASS_(name, value_params)&) noexcept               \
+        GMOCK_INTERNAL_DEFN_COPY_##value_params                                \
+    GMOCK_ACTION_CLASS_(name, value_params)(                                   \
+        GMOCK_ACTION_CLASS_(name, value_params)&&) noexcept                    \
+        GMOCK_INTERNAL_DEFN_COPY_##value_params                                \
+    template <typename F>                                                      \
+    operator ::testing::Action<F>() const {                                    \
+      return GMOCK_PP_IF(                                                      \
+          GMOCK_PP_IS_EMPTY(GMOCK_INTERNAL_COUNT_##value_params),              \
+                      (::testing::internal::MakeAction<F, gmock_Impl>()),      \
+                      (::testing::internal::MakeAction<F>(impl_)));            \
+    }                                                                          \
+   private:                                                                    \
+    class gmock_Impl {                                                         \
+     public:                                                                   \
+      explicit gmock_Impl GMOCK_INTERNAL_INIT_##value_params {}                \
+      template <typename function_type, typename return_type,                  \
+                typename args_type, GMOCK_ACTION_TEMPLATE_ARGS_NAMES_>         \
+      return_type gmock_PerformImpl(GMOCK_ACTION_ARG_TYPES_AND_NAMES_) const;  \
+      GMOCK_INTERNAL_DEFN_##value_params                                       \
+    };                                                                         \
+    GMOCK_PP_IF(GMOCK_PP_IS_EMPTY(GMOCK_INTERNAL_COUNT_##value_params),        \
+                , std::shared_ptr<const gmock_Impl> impl_;)                    \
+  };                                                                           \
+  template <GMOCK_INTERNAL_DECL_##template_params                              \
+            GMOCK_INTERNAL_DECL_TYPE_##value_params>                           \
+  GMOCK_ACTION_CLASS_(name, value_params)<                                     \
+      GMOCK_INTERNAL_LIST_##template_params                                    \
+      GMOCK_INTERNAL_LIST_TYPE_##value_params> name(                           \
+          GMOCK_INTERNAL_DECL_##value_params) GTEST_MUST_USE_RESULT_;          \
+  template <GMOCK_INTERNAL_DECL_##template_params                              \
+            GMOCK_INTERNAL_DECL_TYPE_##value_params>                           \
+  inline GMOCK_ACTION_CLASS_(name, value_params)<                              \
+      GMOCK_INTERNAL_LIST_##template_params                                    \
+      GMOCK_INTERNAL_LIST_TYPE_##value_params> name(                           \
+          GMOCK_INTERNAL_DECL_##value_params) {                                \
+    return GMOCK_ACTION_CLASS_(name, value_params)<                            \
+        GMOCK_INTERNAL_LIST_##template_params                                  \
+        GMOCK_INTERNAL_LIST_TYPE_##value_params>(                              \
+            GMOCK_INTERNAL_LIST_##value_params);                               \
+  }                                                                            \
+  template <GMOCK_INTERNAL_DECL_##template_params                              \
+            GMOCK_INTERNAL_DECL_TYPE_##value_params>                           \
+  template <typename function_type, typename return_type, typename args_type,  \
+            GMOCK_ACTION_TEMPLATE_ARGS_NAMES_>                                 \
+  return_type GMOCK_ACTION_CLASS_(name, value_params)<                         \
+      GMOCK_INTERNAL_LIST_##template_params                                    \
+      GMOCK_INTERNAL_LIST_TYPE_##value_params>::gmock_Impl::gmock_PerformImpl( \
           GMOCK_ACTION_ARG_TYPES_AND_NAMES_UNUSED_) const
 
 namespace testing {
 
-
 // The ACTION*() macros trigger warning C4100 (unreferenced formal
 // parameter) in MSVC with -W4.  Unfortunately they cannot be fixed in
 // the macro definition, as the warnings are generated when the macro
@@ -11357,8 +11191,37 @@
 # pragma warning(disable:4100)
 #endif
 
-// Various overloads for InvokeArgument<N>().
-//
+namespace internal {
+
+// internal::InvokeArgument - a helper for InvokeArgument action.
+// The basic overloads are provided here for generic functors.
+// Overloads for other custom-callables are provided in the
+// internal/custom/gmock-generated-actions.h header.
+template <typename F, typename... Args>
+auto InvokeArgument(F f, Args... args) -> decltype(f(args...)) {
+  return f(args...);
+}
+
+template <std::size_t index, typename... Params>
+struct InvokeArgumentAction {
+  template <typename... Args>
+  auto operator()(Args&&... args) const -> decltype(internal::InvokeArgument(
+      std::get<index>(std::forward_as_tuple(std::forward<Args>(args)...)),
+      std::declval<const Params&>()...)) {
+    internal::FlatTuple<Args&&...> args_tuple(FlatTupleConstructTag{},
+                                              std::forward<Args>(args)...);
+    return params.Apply([&](const Params&... unpacked_params) {
+      auto&& callable = args_tuple.template Get<index>();
+      return internal::InvokeArgument(
+          std::forward<decltype(callable)>(callable), unpacked_params...);
+    });
+  }
+
+  internal::FlatTuple<Params...> params;
+};
+
+}  // namespace internal
+
 // The InvokeArgument<N>(a1, a2, ..., a_k) action invokes the N-th
 // (0-based) argument, which must be a k-ary callable, of the mock
 // function, with arguments a1, a2, ..., a_k.
@@ -11366,15 +11229,15 @@
 // Notes:
 //
 //   1. The arguments are passed by value by default.  If you need to
-//   pass an argument by reference, wrap it inside ByRef().  For
+//   pass an argument by reference, wrap it inside std::ref().  For
 //   example,
 //
-//     InvokeArgument<1>(5, string("Hello"), ByRef(foo))
+//     InvokeArgument<1>(5, string("Hello"), std::ref(foo))
 //
 //   passes 5 and string("Hello") by value, and passes foo by
 //   reference.
 //
-//   2. If the callable takes an argument by reference but ByRef() is
+//   2. If the callable takes an argument by reference but std::ref() is
 //   not used, it will receive the reference to a copy of the value,
 //   instead of the original value.  For example, when the 0-th
 //   argument of the mock function takes a const string&, the action
@@ -11386,247 +11249,11 @@
 //   to the callable.  This makes it easy for a user to define an
 //   InvokeArgument action from temporary values and have it performed
 //   later.
-
-namespace internal {
-namespace invoke_argument {
-
-// Appears in InvokeArgumentAdl's argument list to help avoid
-// accidental calls to user functions of the same name.
-struct AdlTag {};
-
-// InvokeArgumentAdl - a helper for InvokeArgument.
-// The basic overloads are provided here for generic functors.
-// Overloads for other custom-callables are provided in the
-// internal/custom/callback-actions.h header.
-
-template <typename R, typename F>
-R InvokeArgumentAdl(AdlTag, F f) {
-  return f();
-}
-template <typename R, typename F, typename A1>
-R InvokeArgumentAdl(AdlTag, F f, A1 a1) {
-  return f(a1);
-}
-template <typename R, typename F, typename A1, typename A2>
-R InvokeArgumentAdl(AdlTag, F f, A1 a1, A2 a2) {
-  return f(a1, a2);
-}
-template <typename R, typename F, typename A1, typename A2, typename A3>
-R InvokeArgumentAdl(AdlTag, F f, A1 a1, A2 a2, A3 a3) {
-  return f(a1, a2, a3);
-}
-template <typename R, typename F, typename A1, typename A2, typename A3,
-    typename A4>
-R InvokeArgumentAdl(AdlTag, F f, A1 a1, A2 a2, A3 a3, A4 a4) {
-  return f(a1, a2, a3, a4);
-}
-template <typename R, typename F, typename A1, typename A2, typename A3,
-    typename A4, typename A5>
-R InvokeArgumentAdl(AdlTag, F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) {
-  return f(a1, a2, a3, a4, a5);
-}
-template <typename R, typename F, typename A1, typename A2, typename A3,
-    typename A4, typename A5, typename A6>
-R InvokeArgumentAdl(AdlTag, F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) {
-  return f(a1, a2, a3, a4, a5, a6);
-}
-template <typename R, typename F, typename A1, typename A2, typename A3,
-    typename A4, typename A5, typename A6, typename A7>
-R InvokeArgumentAdl(AdlTag, F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6,
-    A7 a7) {
-  return f(a1, a2, a3, a4, a5, a6, a7);
-}
-template <typename R, typename F, typename A1, typename A2, typename A3,
-    typename A4, typename A5, typename A6, typename A7, typename A8>
-R InvokeArgumentAdl(AdlTag, F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6,
-    A7 a7, A8 a8) {
-  return f(a1, a2, a3, a4, a5, a6, a7, a8);
-}
-template <typename R, typename F, typename A1, typename A2, typename A3,
-    typename A4, typename A5, typename A6, typename A7, typename A8,
-    typename A9>
-R InvokeArgumentAdl(AdlTag, F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6,
-    A7 a7, A8 a8, A9 a9) {
-  return f(a1, a2, a3, a4, a5, a6, a7, a8, a9);
-}
-template <typename R, typename F, typename A1, typename A2, typename A3,
-    typename A4, typename A5, typename A6, typename A7, typename A8,
-    typename A9, typename A10>
-R InvokeArgumentAdl(AdlTag, F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6,
-    A7 a7, A8 a8, A9 a9, A10 a10) {
-  return f(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);
-}
-}  // namespace invoke_argument
-}  // namespace internal
-
-ACTION_TEMPLATE(InvokeArgument,
-                HAS_1_TEMPLATE_PARAMS(int, k),
-                AND_0_VALUE_PARAMS()) {
-  using internal::invoke_argument::InvokeArgumentAdl;
-  return InvokeArgumentAdl<return_type>(
-      internal::invoke_argument::AdlTag(),
-      ::std::get<k>(args));
-}
-
-ACTION_TEMPLATE(InvokeArgument,
-                HAS_1_TEMPLATE_PARAMS(int, k),
-                AND_1_VALUE_PARAMS(p0)) {
-  using internal::invoke_argument::InvokeArgumentAdl;
-  return InvokeArgumentAdl<return_type>(
-      internal::invoke_argument::AdlTag(),
-      ::std::get<k>(args), p0);
-}
-
-ACTION_TEMPLATE(InvokeArgument,
-                HAS_1_TEMPLATE_PARAMS(int, k),
-                AND_2_VALUE_PARAMS(p0, p1)) {
-  using internal::invoke_argument::InvokeArgumentAdl;
-  return InvokeArgumentAdl<return_type>(
-      internal::invoke_argument::AdlTag(),
-      ::std::get<k>(args), p0, p1);
-}
-
-ACTION_TEMPLATE(InvokeArgument,
-                HAS_1_TEMPLATE_PARAMS(int, k),
-                AND_3_VALUE_PARAMS(p0, p1, p2)) {
-  using internal::invoke_argument::InvokeArgumentAdl;
-  return InvokeArgumentAdl<return_type>(
-      internal::invoke_argument::AdlTag(),
-      ::std::get<k>(args), p0, p1, p2);
-}
-
-ACTION_TEMPLATE(InvokeArgument,
-                HAS_1_TEMPLATE_PARAMS(int, k),
-                AND_4_VALUE_PARAMS(p0, p1, p2, p3)) {
-  using internal::invoke_argument::InvokeArgumentAdl;
-  return InvokeArgumentAdl<return_type>(
-      internal::invoke_argument::AdlTag(),
-      ::std::get<k>(args), p0, p1, p2, p3);
-}
-
-ACTION_TEMPLATE(InvokeArgument,
-                HAS_1_TEMPLATE_PARAMS(int, k),
-                AND_5_VALUE_PARAMS(p0, p1, p2, p3, p4)) {
-  using internal::invoke_argument::InvokeArgumentAdl;
-  return InvokeArgumentAdl<return_type>(
-      internal::invoke_argument::AdlTag(),
-      ::std::get<k>(args), p0, p1, p2, p3, p4);
-}
-
-ACTION_TEMPLATE(InvokeArgument,
-                HAS_1_TEMPLATE_PARAMS(int, k),
-                AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, p5)) {
-  using internal::invoke_argument::InvokeArgumentAdl;
-  return InvokeArgumentAdl<return_type>(
-      internal::invoke_argument::AdlTag(),
-      ::std::get<k>(args), p0, p1, p2, p3, p4, p5);
-}
-
-ACTION_TEMPLATE(InvokeArgument,
-                HAS_1_TEMPLATE_PARAMS(int, k),
-                AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6)) {
-  using internal::invoke_argument::InvokeArgumentAdl;
-  return InvokeArgumentAdl<return_type>(
-      internal::invoke_argument::AdlTag(),
-      ::std::get<k>(args), p0, p1, p2, p3, p4, p5, p6);
-}
-
-ACTION_TEMPLATE(InvokeArgument,
-                HAS_1_TEMPLATE_PARAMS(int, k),
-                AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7)) {
-  using internal::invoke_argument::InvokeArgumentAdl;
-  return InvokeArgumentAdl<return_type>(
-      internal::invoke_argument::AdlTag(),
-      ::std::get<k>(args), p0, p1, p2, p3, p4, p5, p6, p7);
-}
-
-ACTION_TEMPLATE(InvokeArgument,
-                HAS_1_TEMPLATE_PARAMS(int, k),
-                AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7, p8)) {
-  using internal::invoke_argument::InvokeArgumentAdl;
-  return InvokeArgumentAdl<return_type>(
-      internal::invoke_argument::AdlTag(),
-      ::std::get<k>(args), p0, p1, p2, p3, p4, p5, p6, p7, p8);
-}
-
-ACTION_TEMPLATE(InvokeArgument,
-                HAS_1_TEMPLATE_PARAMS(int, k),
-                AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9)) {
-  using internal::invoke_argument::InvokeArgumentAdl;
-  return InvokeArgumentAdl<return_type>(
-      internal::invoke_argument::AdlTag(),
-      ::std::get<k>(args), p0, p1, p2, p3, p4, p5, p6, p7, p8, p9);
-}
-
-// Various overloads for ReturnNew<T>().
-//
-// The ReturnNew<T>(a1, a2, ..., a_k) action returns a pointer to a new
-// instance of type T, constructed on the heap with constructor arguments
-// a1, a2, ..., and a_k. The caller assumes ownership of the returned value.
-ACTION_TEMPLATE(ReturnNew,
-                HAS_1_TEMPLATE_PARAMS(typename, T),
-                AND_0_VALUE_PARAMS()) {
-  return new T();
-}
-
-ACTION_TEMPLATE(ReturnNew,
-                HAS_1_TEMPLATE_PARAMS(typename, T),
-                AND_1_VALUE_PARAMS(p0)) {
-  return new T(p0);
-}
-
-ACTION_TEMPLATE(ReturnNew,
-                HAS_1_TEMPLATE_PARAMS(typename, T),
-                AND_2_VALUE_PARAMS(p0, p1)) {
-  return new T(p0, p1);
-}
-
-ACTION_TEMPLATE(ReturnNew,
-                HAS_1_TEMPLATE_PARAMS(typename, T),
-                AND_3_VALUE_PARAMS(p0, p1, p2)) {
-  return new T(p0, p1, p2);
-}
-
-ACTION_TEMPLATE(ReturnNew,
-                HAS_1_TEMPLATE_PARAMS(typename, T),
-                AND_4_VALUE_PARAMS(p0, p1, p2, p3)) {
-  return new T(p0, p1, p2, p3);
-}
-
-ACTION_TEMPLATE(ReturnNew,
-                HAS_1_TEMPLATE_PARAMS(typename, T),
-                AND_5_VALUE_PARAMS(p0, p1, p2, p3, p4)) {
-  return new T(p0, p1, p2, p3, p4);
-}
-
-ACTION_TEMPLATE(ReturnNew,
-                HAS_1_TEMPLATE_PARAMS(typename, T),
-                AND_6_VALUE_PARAMS(p0, p1, p2, p3, p4, p5)) {
-  return new T(p0, p1, p2, p3, p4, p5);
-}
-
-ACTION_TEMPLATE(ReturnNew,
-                HAS_1_TEMPLATE_PARAMS(typename, T),
-                AND_7_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6)) {
-  return new T(p0, p1, p2, p3, p4, p5, p6);
-}
-
-ACTION_TEMPLATE(ReturnNew,
-                HAS_1_TEMPLATE_PARAMS(typename, T),
-                AND_8_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7)) {
-  return new T(p0, p1, p2, p3, p4, p5, p6, p7);
-}
-
-ACTION_TEMPLATE(ReturnNew,
-                HAS_1_TEMPLATE_PARAMS(typename, T),
-                AND_9_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7, p8)) {
-  return new T(p0, p1, p2, p3, p4, p5, p6, p7, p8);
-}
-
-ACTION_TEMPLATE(ReturnNew,
-                HAS_1_TEMPLATE_PARAMS(typename, T),
-                AND_10_VALUE_PARAMS(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9)) {
-  return new T(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9);
+template <std::size_t index, typename... Params>
+internal::InvokeArgumentAction<index, typename std::decay<Params>::type...>
+InvokeArgument(Params&&... params) {
+  return {internal::FlatTuple<typename std::decay<Params>::type...>(
+      internal::FlatTupleConstructTag{}, std::forward<Params>(params)...)};
 }
 
 #ifdef _MSC_VER
@@ -11635,1281 +11262,7 @@
 
 }  // namespace testing
 
-// Include any custom callback actions added by the local installation.
-// We must include this header at the end to make sure it can use the
-// declarations from this file.
-// This file was GENERATED by command:
-//     pump.py gmock-generated-actions.h.pump
-// DO NOT EDIT BY HAND!!!
-
-// GOOGLETEST_CM0002 DO NOT DELETE
-
-#ifndef GMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_GMOCK_GENERATED_ACTIONS_H_
-#define GMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_GMOCK_GENERATED_ACTIONS_H_
-
-#endif  // GMOCK_INCLUDE_GMOCK_INTERNAL_CUSTOM_GMOCK_GENERATED_ACTIONS_H_
-
-#endif  // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_
-// This file was GENERATED by command:
-//     pump.py gmock-generated-matchers.h.pump
-// DO NOT EDIT BY HAND!!!
-
-// Copyright 2008, Google Inc.
-// All rights reserved.
-//
-// 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 Google Inc. 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.
-
-// Google Mock - a framework for writing C++ mock classes.
-//
-// This file implements some commonly used variadic matchers.
-
-// GOOGLETEST_CM0002 DO NOT DELETE
-
-#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_
-#define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_
-
-#include <iterator>
-#include <sstream>
-#include <string>
-#include <utility>
-#include <vector>
-
-// The MATCHER* family of macros can be used in a namespace scope to
-// define custom matchers easily.
-//
-// Basic Usage
-// ===========
-//
-// The syntax
-//
-//   MATCHER(name, description_string) { statements; }
-//
-// defines a matcher with the given name that executes the statements,
-// which must return a bool to indicate if the match succeeds.  Inside
-// the statements, you can refer to the value being matched by 'arg',
-// and refer to its type by 'arg_type'.
-//
-// The description string documents what the matcher does, and is used
-// to generate the failure message when the match fails.  Since a
-// MATCHER() is usually defined in a header file shared by multiple
-// C++ source files, we require the description to be a C-string
-// literal to avoid possible side effects.  It can be empty, in which
-// case we'll use the sequence of words in the matcher name as the
-// description.
-//
-// For example:
-//
-//   MATCHER(IsEven, "") { return (arg % 2) == 0; }
-//
-// allows you to write
-//
-//   // Expects mock_foo.Bar(n) to be called where n is even.
-//   EXPECT_CALL(mock_foo, Bar(IsEven()));
-//
-// or,
-//
-//   // Verifies that the value of some_expression is even.
-//   EXPECT_THAT(some_expression, IsEven());
-//
-// If the above assertion fails, it will print something like:
-//
-//   Value of: some_expression
-//   Expected: is even
-//     Actual: 7
-//
-// where the description "is even" is automatically calculated from the
-// matcher name IsEven.
-//
-// Argument Type
-// =============
-//
-// Note that the type of the value being matched (arg_type) is
-// determined by the context in which you use the matcher and is
-// supplied to you by the compiler, so you don't need to worry about
-// declaring it (nor can you).  This allows the matcher to be
-// polymorphic.  For example, IsEven() can be used to match any type
-// where the value of "(arg % 2) == 0" can be implicitly converted to
-// a bool.  In the "Bar(IsEven())" example above, if method Bar()
-// takes an int, 'arg_type' will be int; if it takes an unsigned long,
-// 'arg_type' will be unsigned long; and so on.
-//
-// Parameterizing Matchers
-// =======================
-//
-// Sometimes you'll want to parameterize the matcher.  For that you
-// can use another macro:
-//
-//   MATCHER_P(name, param_name, description_string) { statements; }
-//
-// For example:
-//
-//   MATCHER_P(HasAbsoluteValue, value, "") { return abs(arg) == value; }
-//
-// will allow you to write:
-//
-//   EXPECT_THAT(Blah("a"), HasAbsoluteValue(n));
-//
-// which may lead to this message (assuming n is 10):
-//
-//   Value of: Blah("a")
-//   Expected: has absolute value 10
-//     Actual: -9
-//
-// Note that both the matcher description and its parameter are
-// printed, making the message human-friendly.
-//
-// In the matcher definition body, you can write 'foo_type' to
-// reference the type of a parameter named 'foo'.  For example, in the
-// body of MATCHER_P(HasAbsoluteValue, value) above, you can write
-// 'value_type' to refer to the type of 'value'.
-//
-// We also provide MATCHER_P2, MATCHER_P3, ..., up to MATCHER_P10 to
-// support multi-parameter matchers.
-//
-// Describing Parameterized Matchers
-// =================================
-//
-// The last argument to MATCHER*() is a string-typed expression.  The
-// expression can reference all of the matcher's parameters and a
-// special bool-typed variable named 'negation'.  When 'negation' is
-// false, the expression should evaluate to the matcher's description;
-// otherwise it should evaluate to the description of the negation of
-// the matcher.  For example,
-//
-//   using testing::PrintToString;
-//
-//   MATCHER_P2(InClosedRange, low, hi,
-//       std::string(negation ? "is not" : "is") + " in range [" +
-//       PrintToString(low) + ", " + PrintToString(hi) + "]") {
-//     return low <= arg && arg <= hi;
-//   }
-//   ...
-//   EXPECT_THAT(3, InClosedRange(4, 6));
-//   EXPECT_THAT(3, Not(InClosedRange(2, 4)));
-//
-// would generate two failures that contain the text:
-//
-//   Expected: is in range [4, 6]
-//   ...
-//   Expected: is not in range [2, 4]
-//
-// If you specify "" as the description, the failure message will
-// contain the sequence of words in the matcher name followed by the
-// parameter values printed as a tuple.  For example,
-//
-//   MATCHER_P2(InClosedRange, low, hi, "") { ... }
-//   ...
-//   EXPECT_THAT(3, InClosedRange(4, 6));
-//   EXPECT_THAT(3, Not(InClosedRange(2, 4)));
-//
-// would generate two failures that contain the text:
-//
-//   Expected: in closed range (4, 6)
-//   ...
-//   Expected: not (in closed range (2, 4))
-//
-// Types of Matcher Parameters
-// ===========================
-//
-// For the purpose of typing, you can view
-//
-//   MATCHER_Pk(Foo, p1, ..., pk, description_string) { ... }
-//
-// as shorthand for
-//
-//   template <typename p1_type, ..., typename pk_type>
-//   FooMatcherPk<p1_type, ..., pk_type>
-//   Foo(p1_type p1, ..., pk_type pk) { ... }
-//
-// When you write Foo(v1, ..., vk), the compiler infers the types of
-// the parameters v1, ..., and vk for you.  If you are not happy with
-// the result of the type inference, you can specify the types by
-// explicitly instantiating the template, as in Foo<long, bool>(5,
-// false).  As said earlier, you don't get to (or need to) specify
-// 'arg_type' as that's determined by the context in which the matcher
-// is used.  You can assign the result of expression Foo(p1, ..., pk)
-// to a variable of type FooMatcherPk<p1_type, ..., pk_type>.  This
-// can be useful when composing matchers.
-//
-// While you can instantiate a matcher template with reference types,
-// passing the parameters by pointer usually makes your code more
-// readable.  If, however, you still want to pass a parameter by
-// reference, be aware that in the failure message generated by the
-// matcher you will see the value of the referenced object but not its
-// address.
-//
-// Explaining Match Results
-// ========================
-//
-// Sometimes the matcher description alone isn't enough to explain why
-// the match has failed or succeeded.  For example, when expecting a
-// long string, it can be very helpful to also print the diff between
-// the expected string and the actual one.  To achieve that, you can
-// optionally stream additional information to a special variable
-// named result_listener, whose type is a pointer to class
-// MatchResultListener:
-//
-//   MATCHER_P(EqualsLongString, str, "") {
-//     if (arg == str) return true;
-//
-//     *result_listener << "the difference: "
-///                     << DiffStrings(str, arg);
-//     return false;
-//   }
-//
-// Overloading Matchers
-// ====================
-//
-// You can overload matchers with different numbers of parameters:
-//
-//   MATCHER_P(Blah, a, description_string1) { ... }
-//   MATCHER_P2(Blah, a, b, description_string2) { ... }
-//
-// Caveats
-// =======
-//
-// When defining a new matcher, you should also consider implementing
-// MatcherInterface or using MakePolymorphicMatcher().  These
-// approaches require more work than the MATCHER* macros, but also
-// give you more control on the types of the value being matched and
-// the matcher parameters, which may leads to better compiler error
-// messages when the matcher is used wrong.  They also allow
-// overloading matchers based on parameter types (as opposed to just
-// based on the number of parameters).
-//
-// MATCHER*() can only be used in a namespace scope.  The reason is
-// that C++ doesn't yet allow function-local types to be used to
-// instantiate templates.  The up-coming C++0x standard will fix this.
-// Once that's done, we'll consider supporting using MATCHER*() inside
-// a function.
-//
-// More Information
-// ================
-//
-// To learn more about using these macros, please search for 'MATCHER'
-// on
-// https://github.com/google/googletest/blob/master/googlemock/docs/CookBook.md
-
-#define MATCHER(name, description)\
-  class name##Matcher {\
-   public:\
-    template <typename arg_type>\
-    class gmock_Impl : public ::testing::MatcherInterface<\
-        GTEST_REFERENCE_TO_CONST_(arg_type)> {\
-     public:\
-      gmock_Impl()\
-           {}\
-      virtual bool MatchAndExplain(\
-          GTEST_REFERENCE_TO_CONST_(arg_type) arg,\
-          ::testing::MatchResultListener* result_listener) const;\
-      virtual void DescribeTo(::std::ostream* gmock_os) const {\
-        *gmock_os << FormatDescription(false);\
-      }\
-      virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\
-        *gmock_os << FormatDescription(true);\
-      }\
-     private:\
-      ::std::string FormatDescription(bool negation) const {\
-        ::std::string gmock_description = (description);\
-        if (!gmock_description.empty()) {\
-          return gmock_description;\
-        }\
-        return ::testing::internal::FormatMatcherDescription(\
-            negation, #name, \
-            ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\
-                ::std::tuple<>()));\
-      }\
-    };\
-    template <typename arg_type>\
-    operator ::testing::Matcher<arg_type>() const {\
-      return ::testing::Matcher<arg_type>(\
-          new gmock_Impl<arg_type>());\
-    }\
-    name##Matcher() {\
-    }\
-   private:\
-  };\
-  inline name##Matcher name() {\
-    return name##Matcher();\
-  }\
-  template <typename arg_type>\
-  bool name##Matcher::gmock_Impl<arg_type>::MatchAndExplain(\
-      GTEST_REFERENCE_TO_CONST_(arg_type) arg,\
-      ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\
-          const
-
-#define MATCHER_P(name, p0, description)\
-  template <typename p0##_type>\
-  class name##MatcherP {\
-   public:\
-    template <typename arg_type>\
-    class gmock_Impl : public ::testing::MatcherInterface<\
-        GTEST_REFERENCE_TO_CONST_(arg_type)> {\
-     public:\
-      explicit gmock_Impl(p0##_type gmock_p0)\
-           : p0(::std::move(gmock_p0)) {}\
-      virtual bool MatchAndExplain(\
-          GTEST_REFERENCE_TO_CONST_(arg_type) arg,\
-          ::testing::MatchResultListener* result_listener) const;\
-      virtual void DescribeTo(::std::ostream* gmock_os) const {\
-        *gmock_os << FormatDescription(false);\
-      }\
-      virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\
-        *gmock_os << FormatDescription(true);\
-      }\
-      p0##_type const p0;\
-     private:\
-      ::std::string FormatDescription(bool negation) const {\
-        ::std::string gmock_description = (description);\
-        if (!gmock_description.empty()) {\
-          return gmock_description;\
-        }\
-        return ::testing::internal::FormatMatcherDescription(\
-            negation, #name, \
-            ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\
-                ::std::tuple<p0##_type>(p0)));\
-      }\
-    };\
-    template <typename arg_type>\
-    operator ::testing::Matcher<arg_type>() const {\
-      return ::testing::Matcher<arg_type>(\
-          new gmock_Impl<arg_type>(p0));\
-    }\
-    explicit name##MatcherP(p0##_type gmock_p0) : p0(::std::move(gmock_p0)) {\
-    }\
-    p0##_type const p0;\
-   private:\
-  };\
-  template <typename p0##_type>\
-  inline name##MatcherP<p0##_type> name(p0##_type p0) {\
-    return name##MatcherP<p0##_type>(p0);\
-  }\
-  template <typename p0##_type>\
-  template <typename arg_type>\
-  bool name##MatcherP<p0##_type>::gmock_Impl<arg_type>::MatchAndExplain(\
-      GTEST_REFERENCE_TO_CONST_(arg_type) arg,\
-      ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\
-          const
-
-#define MATCHER_P2(name, p0, p1, description)\
-  template <typename p0##_type, typename p1##_type>\
-  class name##MatcherP2 {\
-   public:\
-    template <typename arg_type>\
-    class gmock_Impl : public ::testing::MatcherInterface<\
-        GTEST_REFERENCE_TO_CONST_(arg_type)> {\
-     public:\
-      gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1)\
-           : p0(::std::move(gmock_p0)), p1(::std::move(gmock_p1)) {}\
-      virtual bool MatchAndExplain(\
-          GTEST_REFERENCE_TO_CONST_(arg_type) arg,\
-          ::testing::MatchResultListener* result_listener) const;\
-      virtual void DescribeTo(::std::ostream* gmock_os) const {\
-        *gmock_os << FormatDescription(false);\
-      }\
-      virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\
-        *gmock_os << FormatDescription(true);\
-      }\
-      p0##_type const p0;\
-      p1##_type const p1;\
-     private:\
-      ::std::string FormatDescription(bool negation) const {\
-        ::std::string gmock_description = (description);\
-        if (!gmock_description.empty()) {\
-          return gmock_description;\
-        }\
-        return ::testing::internal::FormatMatcherDescription(\
-            negation, #name, \
-            ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\
-                ::std::tuple<p0##_type, p1##_type>(p0, p1)));\
-      }\
-    };\
-    template <typename arg_type>\
-    operator ::testing::Matcher<arg_type>() const {\
-      return ::testing::Matcher<arg_type>(\
-          new gmock_Impl<arg_type>(p0, p1));\
-    }\
-    name##MatcherP2(p0##_type gmock_p0, \
-        p1##_type gmock_p1) : p0(::std::move(gmock_p0)), \
-        p1(::std::move(gmock_p1)) {\
-    }\
-    p0##_type const p0;\
-    p1##_type const p1;\
-   private:\
-  };\
-  template <typename p0##_type, typename p1##_type>\
-  inline name##MatcherP2<p0##_type, p1##_type> name(p0##_type p0, \
-      p1##_type p1) {\
-    return name##MatcherP2<p0##_type, p1##_type>(p0, p1);\
-  }\
-  template <typename p0##_type, typename p1##_type>\
-  template <typename arg_type>\
-  bool name##MatcherP2<p0##_type, \
-      p1##_type>::gmock_Impl<arg_type>::MatchAndExplain(\
-      GTEST_REFERENCE_TO_CONST_(arg_type) arg,\
-      ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\
-          const
-
-#define MATCHER_P3(name, p0, p1, p2, description)\
-  template <typename p0##_type, typename p1##_type, typename p2##_type>\
-  class name##MatcherP3 {\
-   public:\
-    template <typename arg_type>\
-    class gmock_Impl : public ::testing::MatcherInterface<\
-        GTEST_REFERENCE_TO_CONST_(arg_type)> {\
-     public:\
-      gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2)\
-           : p0(::std::move(gmock_p0)), p1(::std::move(gmock_p1)), \
-               p2(::std::move(gmock_p2)) {}\
-      virtual bool MatchAndExplain(\
-          GTEST_REFERENCE_TO_CONST_(arg_type) arg,\
-          ::testing::MatchResultListener* result_listener) const;\
-      virtual void DescribeTo(::std::ostream* gmock_os) const {\
-        *gmock_os << FormatDescription(false);\
-      }\
-      virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\
-        *gmock_os << FormatDescription(true);\
-      }\
-      p0##_type const p0;\
-      p1##_type const p1;\
-      p2##_type const p2;\
-     private:\
-      ::std::string FormatDescription(bool negation) const {\
-        ::std::string gmock_description = (description);\
-        if (!gmock_description.empty()) {\
-          return gmock_description;\
-        }\
-        return ::testing::internal::FormatMatcherDescription(\
-            negation, #name, \
-            ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\
-                ::std::tuple<p0##_type, p1##_type, p2##_type>(p0, p1, p2)));\
-      }\
-    };\
-    template <typename arg_type>\
-    operator ::testing::Matcher<arg_type>() const {\
-      return ::testing::Matcher<arg_type>(\
-          new gmock_Impl<arg_type>(p0, p1, p2));\
-    }\
-    name##MatcherP3(p0##_type gmock_p0, p1##_type gmock_p1, \
-        p2##_type gmock_p2) : p0(::std::move(gmock_p0)), \
-        p1(::std::move(gmock_p1)), p2(::std::move(gmock_p2)) {\
-    }\
-    p0##_type const p0;\
-    p1##_type const p1;\
-    p2##_type const p2;\
-   private:\
-  };\
-  template <typename p0##_type, typename p1##_type, typename p2##_type>\
-  inline name##MatcherP3<p0##_type, p1##_type, p2##_type> name(p0##_type p0, \
-      p1##_type p1, p2##_type p2) {\
-    return name##MatcherP3<p0##_type, p1##_type, p2##_type>(p0, p1, p2);\
-  }\
-  template <typename p0##_type, typename p1##_type, typename p2##_type>\
-  template <typename arg_type>\
-  bool name##MatcherP3<p0##_type, p1##_type, \
-      p2##_type>::gmock_Impl<arg_type>::MatchAndExplain(\
-      GTEST_REFERENCE_TO_CONST_(arg_type) arg,\
-      ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\
-          const
-
-#define MATCHER_P4(name, p0, p1, p2, p3, description)\
-  template <typename p0##_type, typename p1##_type, typename p2##_type, \
-      typename p3##_type>\
-  class name##MatcherP4 {\
-   public:\
-    template <typename arg_type>\
-    class gmock_Impl : public ::testing::MatcherInterface<\
-        GTEST_REFERENCE_TO_CONST_(arg_type)> {\
-     public:\
-      gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
-          p3##_type gmock_p3)\
-           : p0(::std::move(gmock_p0)), p1(::std::move(gmock_p1)), \
-               p2(::std::move(gmock_p2)), p3(::std::move(gmock_p3)) {}\
-      virtual bool MatchAndExplain(\
-          GTEST_REFERENCE_TO_CONST_(arg_type) arg,\
-          ::testing::MatchResultListener* result_listener) const;\
-      virtual void DescribeTo(::std::ostream* gmock_os) const {\
-        *gmock_os << FormatDescription(false);\
-      }\
-      virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\
-        *gmock_os << FormatDescription(true);\
-      }\
-      p0##_type const p0;\
-      p1##_type const p1;\
-      p2##_type const p2;\
-      p3##_type const p3;\
-     private:\
-      ::std::string FormatDescription(bool negation) const {\
-        ::std::string gmock_description = (description);\
-        if (!gmock_description.empty()) {\
-          return gmock_description;\
-        }\
-        return ::testing::internal::FormatMatcherDescription(\
-            negation, #name, \
-            ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\
-                ::std::tuple<p0##_type, p1##_type, p2##_type, p3##_type>(p0, \
-                    p1, p2, p3)));\
-      }\
-    };\
-    template <typename arg_type>\
-    operator ::testing::Matcher<arg_type>() const {\
-      return ::testing::Matcher<arg_type>(\
-          new gmock_Impl<arg_type>(p0, p1, p2, p3));\
-    }\
-    name##MatcherP4(p0##_type gmock_p0, p1##_type gmock_p1, \
-        p2##_type gmock_p2, p3##_type gmock_p3) : p0(::std::move(gmock_p0)), \
-        p1(::std::move(gmock_p1)), p2(::std::move(gmock_p2)), \
-        p3(::std::move(gmock_p3)) {\
-    }\
-    p0##_type const p0;\
-    p1##_type const p1;\
-    p2##_type const p2;\
-    p3##_type const p3;\
-   private:\
-  };\
-  template <typename p0##_type, typename p1##_type, typename p2##_type, \
-      typename p3##_type>\
-  inline name##MatcherP4<p0##_type, p1##_type, p2##_type, \
-      p3##_type> name(p0##_type p0, p1##_type p1, p2##_type p2, \
-      p3##_type p3) {\
-    return name##MatcherP4<p0##_type, p1##_type, p2##_type, p3##_type>(p0, \
-        p1, p2, p3);\
-  }\
-  template <typename p0##_type, typename p1##_type, typename p2##_type, \
-      typename p3##_type>\
-  template <typename arg_type>\
-  bool name##MatcherP4<p0##_type, p1##_type, p2##_type, \
-      p3##_type>::gmock_Impl<arg_type>::MatchAndExplain(\
-      GTEST_REFERENCE_TO_CONST_(arg_type) arg,\
-      ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\
-          const
-
-#define MATCHER_P5(name, p0, p1, p2, p3, p4, description)\
-  template <typename p0##_type, typename p1##_type, typename p2##_type, \
-      typename p3##_type, typename p4##_type>\
-  class name##MatcherP5 {\
-   public:\
-    template <typename arg_type>\
-    class gmock_Impl : public ::testing::MatcherInterface<\
-        GTEST_REFERENCE_TO_CONST_(arg_type)> {\
-     public:\
-      gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
-          p3##_type gmock_p3, p4##_type gmock_p4)\
-           : p0(::std::move(gmock_p0)), p1(::std::move(gmock_p1)), \
-               p2(::std::move(gmock_p2)), p3(::std::move(gmock_p3)), \
-               p4(::std::move(gmock_p4)) {}\
-      virtual bool MatchAndExplain(\
-          GTEST_REFERENCE_TO_CONST_(arg_type) arg,\
-          ::testing::MatchResultListener* result_listener) const;\
-      virtual void DescribeTo(::std::ostream* gmock_os) const {\
-        *gmock_os << FormatDescription(false);\
-      }\
-      virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\
-        *gmock_os << FormatDescription(true);\
-      }\
-      p0##_type const p0;\
-      p1##_type const p1;\
-      p2##_type const p2;\
-      p3##_type const p3;\
-      p4##_type const p4;\
-     private:\
-      ::std::string FormatDescription(bool negation) const {\
-        ::std::string gmock_description = (description);\
-        if (!gmock_description.empty()) {\
-          return gmock_description;\
-        }\
-        return ::testing::internal::FormatMatcherDescription(\
-            negation, #name, \
-            ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\
-                ::std::tuple<p0##_type, p1##_type, p2##_type, p3##_type, \
-                    p4##_type>(p0, p1, p2, p3, p4)));\
-      }\
-    };\
-    template <typename arg_type>\
-    operator ::testing::Matcher<arg_type>() const {\
-      return ::testing::Matcher<arg_type>(\
-          new gmock_Impl<arg_type>(p0, p1, p2, p3, p4));\
-    }\
-    name##MatcherP5(p0##_type gmock_p0, p1##_type gmock_p1, \
-        p2##_type gmock_p2, p3##_type gmock_p3, \
-        p4##_type gmock_p4) : p0(::std::move(gmock_p0)), \
-        p1(::std::move(gmock_p1)), p2(::std::move(gmock_p2)), \
-        p3(::std::move(gmock_p3)), p4(::std::move(gmock_p4)) {\
-    }\
-    p0##_type const p0;\
-    p1##_type const p1;\
-    p2##_type const p2;\
-    p3##_type const p3;\
-    p4##_type const p4;\
-   private:\
-  };\
-  template <typename p0##_type, typename p1##_type, typename p2##_type, \
-      typename p3##_type, typename p4##_type>\
-  inline name##MatcherP5<p0##_type, p1##_type, p2##_type, p3##_type, \
-      p4##_type> name(p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \
-      p4##_type p4) {\
-    return name##MatcherP5<p0##_type, p1##_type, p2##_type, p3##_type, \
-        p4##_type>(p0, p1, p2, p3, p4);\
-  }\
-  template <typename p0##_type, typename p1##_type, typename p2##_type, \
-      typename p3##_type, typename p4##_type>\
-  template <typename arg_type>\
-  bool name##MatcherP5<p0##_type, p1##_type, p2##_type, p3##_type, \
-      p4##_type>::gmock_Impl<arg_type>::MatchAndExplain(\
-      GTEST_REFERENCE_TO_CONST_(arg_type) arg,\
-      ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\
-          const
-
-#define MATCHER_P6(name, p0, p1, p2, p3, p4, p5, description)\
-  template <typename p0##_type, typename p1##_type, typename p2##_type, \
-      typename p3##_type, typename p4##_type, typename p5##_type>\
-  class name##MatcherP6 {\
-   public:\
-    template <typename arg_type>\
-    class gmock_Impl : public ::testing::MatcherInterface<\
-        GTEST_REFERENCE_TO_CONST_(arg_type)> {\
-     public:\
-      gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
-          p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5)\
-           : p0(::std::move(gmock_p0)), p1(::std::move(gmock_p1)), \
-               p2(::std::move(gmock_p2)), p3(::std::move(gmock_p3)), \
-               p4(::std::move(gmock_p4)), p5(::std::move(gmock_p5)) {}\
-      virtual bool MatchAndExplain(\
-          GTEST_REFERENCE_TO_CONST_(arg_type) arg,\
-          ::testing::MatchResultListener* result_listener) const;\
-      virtual void DescribeTo(::std::ostream* gmock_os) const {\
-        *gmock_os << FormatDescription(false);\
-      }\
-      virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\
-        *gmock_os << FormatDescription(true);\
-      }\
-      p0##_type const p0;\
-      p1##_type const p1;\
-      p2##_type const p2;\
-      p3##_type const p3;\
-      p4##_type const p4;\
-      p5##_type const p5;\
-     private:\
-      ::std::string FormatDescription(bool negation) const {\
-        ::std::string gmock_description = (description);\
-        if (!gmock_description.empty()) {\
-          return gmock_description;\
-        }\
-        return ::testing::internal::FormatMatcherDescription(\
-            negation, #name, \
-            ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\
-                ::std::tuple<p0##_type, p1##_type, p2##_type, p3##_type, \
-                    p4##_type, p5##_type>(p0, p1, p2, p3, p4, p5)));\
-      }\
-    };\
-    template <typename arg_type>\
-    operator ::testing::Matcher<arg_type>() const {\
-      return ::testing::Matcher<arg_type>(\
-          new gmock_Impl<arg_type>(p0, p1, p2, p3, p4, p5));\
-    }\
-    name##MatcherP6(p0##_type gmock_p0, p1##_type gmock_p1, \
-        p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \
-        p5##_type gmock_p5) : p0(::std::move(gmock_p0)), \
-        p1(::std::move(gmock_p1)), p2(::std::move(gmock_p2)), \
-        p3(::std::move(gmock_p3)), p4(::std::move(gmock_p4)), \
-        p5(::std::move(gmock_p5)) {\
-    }\
-    p0##_type const p0;\
-    p1##_type const p1;\
-    p2##_type const p2;\
-    p3##_type const p3;\
-    p4##_type const p4;\
-    p5##_type const p5;\
-   private:\
-  };\
-  template <typename p0##_type, typename p1##_type, typename p2##_type, \
-      typename p3##_type, typename p4##_type, typename p5##_type>\
-  inline name##MatcherP6<p0##_type, p1##_type, p2##_type, p3##_type, \
-      p4##_type, p5##_type> name(p0##_type p0, p1##_type p1, p2##_type p2, \
-      p3##_type p3, p4##_type p4, p5##_type p5) {\
-    return name##MatcherP6<p0##_type, p1##_type, p2##_type, p3##_type, \
-        p4##_type, p5##_type>(p0, p1, p2, p3, p4, p5);\
-  }\
-  template <typename p0##_type, typename p1##_type, typename p2##_type, \
-      typename p3##_type, typename p4##_type, typename p5##_type>\
-  template <typename arg_type>\
-  bool name##MatcherP6<p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, \
-      p5##_type>::gmock_Impl<arg_type>::MatchAndExplain(\
-      GTEST_REFERENCE_TO_CONST_(arg_type) arg,\
-      ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\
-          const
-
-#define MATCHER_P7(name, p0, p1, p2, p3, p4, p5, p6, description)\
-  template <typename p0##_type, typename p1##_type, typename p2##_type, \
-      typename p3##_type, typename p4##_type, typename p5##_type, \
-      typename p6##_type>\
-  class name##MatcherP7 {\
-   public:\
-    template <typename arg_type>\
-    class gmock_Impl : public ::testing::MatcherInterface<\
-        GTEST_REFERENCE_TO_CONST_(arg_type)> {\
-     public:\
-      gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
-          p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \
-          p6##_type gmock_p6)\
-           : p0(::std::move(gmock_p0)), p1(::std::move(gmock_p1)), \
-               p2(::std::move(gmock_p2)), p3(::std::move(gmock_p3)), \
-               p4(::std::move(gmock_p4)), p5(::std::move(gmock_p5)), \
-               p6(::std::move(gmock_p6)) {}\
-      virtual bool MatchAndExplain(\
-          GTEST_REFERENCE_TO_CONST_(arg_type) arg,\
-          ::testing::MatchResultListener* result_listener) const;\
-      virtual void DescribeTo(::std::ostream* gmock_os) const {\
-        *gmock_os << FormatDescription(false);\
-      }\
-      virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\
-        *gmock_os << FormatDescription(true);\
-      }\
-      p0##_type const p0;\
-      p1##_type const p1;\
-      p2##_type const p2;\
-      p3##_type const p3;\
-      p4##_type const p4;\
-      p5##_type const p5;\
-      p6##_type const p6;\
-     private:\
-      ::std::string FormatDescription(bool negation) const {\
-        ::std::string gmock_description = (description);\
-        if (!gmock_description.empty()) {\
-          return gmock_description;\
-        }\
-        return ::testing::internal::FormatMatcherDescription(\
-            negation, #name, \
-            ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\
-                ::std::tuple<p0##_type, p1##_type, p2##_type, p3##_type, \
-                    p4##_type, p5##_type, p6##_type>(p0, p1, p2, p3, p4, p5, \
-                    p6)));\
-      }\
-    };\
-    template <typename arg_type>\
-    operator ::testing::Matcher<arg_type>() const {\
-      return ::testing::Matcher<arg_type>(\
-          new gmock_Impl<arg_type>(p0, p1, p2, p3, p4, p5, p6));\
-    }\
-    name##MatcherP7(p0##_type gmock_p0, p1##_type gmock_p1, \
-        p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \
-        p5##_type gmock_p5, p6##_type gmock_p6) : p0(::std::move(gmock_p0)), \
-        p1(::std::move(gmock_p1)), p2(::std::move(gmock_p2)), \
-        p3(::std::move(gmock_p3)), p4(::std::move(gmock_p4)), \
-        p5(::std::move(gmock_p5)), p6(::std::move(gmock_p6)) {\
-    }\
-    p0##_type const p0;\
-    p1##_type const p1;\
-    p2##_type const p2;\
-    p3##_type const p3;\
-    p4##_type const p4;\
-    p5##_type const p5;\
-    p6##_type const p6;\
-   private:\
-  };\
-  template <typename p0##_type, typename p1##_type, typename p2##_type, \
-      typename p3##_type, typename p4##_type, typename p5##_type, \
-      typename p6##_type>\
-  inline name##MatcherP7<p0##_type, p1##_type, p2##_type, p3##_type, \
-      p4##_type, p5##_type, p6##_type> name(p0##_type p0, p1##_type p1, \
-      p2##_type p2, p3##_type p3, p4##_type p4, p5##_type p5, \
-      p6##_type p6) {\
-    return name##MatcherP7<p0##_type, p1##_type, p2##_type, p3##_type, \
-        p4##_type, p5##_type, p6##_type>(p0, p1, p2, p3, p4, p5, p6);\
-  }\
-  template <typename p0##_type, typename p1##_type, typename p2##_type, \
-      typename p3##_type, typename p4##_type, typename p5##_type, \
-      typename p6##_type>\
-  template <typename arg_type>\
-  bool name##MatcherP7<p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, \
-      p5##_type, p6##_type>::gmock_Impl<arg_type>::MatchAndExplain(\
-      GTEST_REFERENCE_TO_CONST_(arg_type) arg,\
-      ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\
-          const
-
-#define MATCHER_P8(name, p0, p1, p2, p3, p4, p5, p6, p7, description)\
-  template <typename p0##_type, typename p1##_type, typename p2##_type, \
-      typename p3##_type, typename p4##_type, typename p5##_type, \
-      typename p6##_type, typename p7##_type>\
-  class name##MatcherP8 {\
-   public:\
-    template <typename arg_type>\
-    class gmock_Impl : public ::testing::MatcherInterface<\
-        GTEST_REFERENCE_TO_CONST_(arg_type)> {\
-     public:\
-      gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
-          p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \
-          p6##_type gmock_p6, p7##_type gmock_p7)\
-           : p0(::std::move(gmock_p0)), p1(::std::move(gmock_p1)), \
-               p2(::std::move(gmock_p2)), p3(::std::move(gmock_p3)), \
-               p4(::std::move(gmock_p4)), p5(::std::move(gmock_p5)), \
-               p6(::std::move(gmock_p6)), p7(::std::move(gmock_p7)) {}\
-      virtual bool MatchAndExplain(\
-          GTEST_REFERENCE_TO_CONST_(arg_type) arg,\
-          ::testing::MatchResultListener* result_listener) const;\
-      virtual void DescribeTo(::std::ostream* gmock_os) const {\
-        *gmock_os << FormatDescription(false);\
-      }\
-      virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\
-        *gmock_os << FormatDescription(true);\
-      }\
-      p0##_type const p0;\
-      p1##_type const p1;\
-      p2##_type const p2;\
-      p3##_type const p3;\
-      p4##_type const p4;\
-      p5##_type const p5;\
-      p6##_type const p6;\
-      p7##_type const p7;\
-     private:\
-      ::std::string FormatDescription(bool negation) const {\
-        ::std::string gmock_description = (description);\
-        if (!gmock_description.empty()) {\
-          return gmock_description;\
-        }\
-        return ::testing::internal::FormatMatcherDescription(\
-            negation, #name, \
-            ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\
-                ::std::tuple<p0##_type, p1##_type, p2##_type, p3##_type, \
-                    p4##_type, p5##_type, p6##_type, p7##_type>(p0, p1, p2, \
-                    p3, p4, p5, p6, p7)));\
-      }\
-    };\
-    template <typename arg_type>\
-    operator ::testing::Matcher<arg_type>() const {\
-      return ::testing::Matcher<arg_type>(\
-          new gmock_Impl<arg_type>(p0, p1, p2, p3, p4, p5, p6, p7));\
-    }\
-    name##MatcherP8(p0##_type gmock_p0, p1##_type gmock_p1, \
-        p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \
-        p5##_type gmock_p5, p6##_type gmock_p6, \
-        p7##_type gmock_p7) : p0(::std::move(gmock_p0)), \
-        p1(::std::move(gmock_p1)), p2(::std::move(gmock_p2)), \
-        p3(::std::move(gmock_p3)), p4(::std::move(gmock_p4)), \
-        p5(::std::move(gmock_p5)), p6(::std::move(gmock_p6)), \
-        p7(::std::move(gmock_p7)) {\
-    }\
-    p0##_type const p0;\
-    p1##_type const p1;\
-    p2##_type const p2;\
-    p3##_type const p3;\
-    p4##_type const p4;\
-    p5##_type const p5;\
-    p6##_type const p6;\
-    p7##_type const p7;\
-   private:\
-  };\
-  template <typename p0##_type, typename p1##_type, typename p2##_type, \
-      typename p3##_type, typename p4##_type, typename p5##_type, \
-      typename p6##_type, typename p7##_type>\
-  inline name##MatcherP8<p0##_type, p1##_type, p2##_type, p3##_type, \
-      p4##_type, p5##_type, p6##_type, p7##_type> name(p0##_type p0, \
-      p1##_type p1, p2##_type p2, p3##_type p3, p4##_type p4, p5##_type p5, \
-      p6##_type p6, p7##_type p7) {\
-    return name##MatcherP8<p0##_type, p1##_type, p2##_type, p3##_type, \
-        p4##_type, p5##_type, p6##_type, p7##_type>(p0, p1, p2, p3, p4, p5, \
-        p6, p7);\
-  }\
-  template <typename p0##_type, typename p1##_type, typename p2##_type, \
-      typename p3##_type, typename p4##_type, typename p5##_type, \
-      typename p6##_type, typename p7##_type>\
-  template <typename arg_type>\
-  bool name##MatcherP8<p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, \
-      p5##_type, p6##_type, \
-      p7##_type>::gmock_Impl<arg_type>::MatchAndExplain(\
-      GTEST_REFERENCE_TO_CONST_(arg_type) arg,\
-      ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\
-          const
-
-#define MATCHER_P9(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, description)\
-  template <typename p0##_type, typename p1##_type, typename p2##_type, \
-      typename p3##_type, typename p4##_type, typename p5##_type, \
-      typename p6##_type, typename p7##_type, typename p8##_type>\
-  class name##MatcherP9 {\
-   public:\
-    template <typename arg_type>\
-    class gmock_Impl : public ::testing::MatcherInterface<\
-        GTEST_REFERENCE_TO_CONST_(arg_type)> {\
-     public:\
-      gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
-          p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \
-          p6##_type gmock_p6, p7##_type gmock_p7, p8##_type gmock_p8)\
-           : p0(::std::move(gmock_p0)), p1(::std::move(gmock_p1)), \
-               p2(::std::move(gmock_p2)), p3(::std::move(gmock_p3)), \
-               p4(::std::move(gmock_p4)), p5(::std::move(gmock_p5)), \
-               p6(::std::move(gmock_p6)), p7(::std::move(gmock_p7)), \
-               p8(::std::move(gmock_p8)) {}\
-      virtual bool MatchAndExplain(\
-          GTEST_REFERENCE_TO_CONST_(arg_type) arg,\
-          ::testing::MatchResultListener* result_listener) const;\
-      virtual void DescribeTo(::std::ostream* gmock_os) const {\
-        *gmock_os << FormatDescription(false);\
-      }\
-      virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\
-        *gmock_os << FormatDescription(true);\
-      }\
-      p0##_type const p0;\
-      p1##_type const p1;\
-      p2##_type const p2;\
-      p3##_type const p3;\
-      p4##_type const p4;\
-      p5##_type const p5;\
-      p6##_type const p6;\
-      p7##_type const p7;\
-      p8##_type const p8;\
-     private:\
-      ::std::string FormatDescription(bool negation) const {\
-        ::std::string gmock_description = (description);\
-        if (!gmock_description.empty()) {\
-          return gmock_description;\
-        }\
-        return ::testing::internal::FormatMatcherDescription(\
-            negation, #name, \
-            ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\
-                ::std::tuple<p0##_type, p1##_type, p2##_type, p3##_type, \
-                    p4##_type, p5##_type, p6##_type, p7##_type, \
-                    p8##_type>(p0, p1, p2, p3, p4, p5, p6, p7, p8)));\
-      }\
-    };\
-    template <typename arg_type>\
-    operator ::testing::Matcher<arg_type>() const {\
-      return ::testing::Matcher<arg_type>(\
-          new gmock_Impl<arg_type>(p0, p1, p2, p3, p4, p5, p6, p7, p8));\
-    }\
-    name##MatcherP9(p0##_type gmock_p0, p1##_type gmock_p1, \
-        p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \
-        p5##_type gmock_p5, p6##_type gmock_p6, p7##_type gmock_p7, \
-        p8##_type gmock_p8) : p0(::std::move(gmock_p0)), \
-        p1(::std::move(gmock_p1)), p2(::std::move(gmock_p2)), \
-        p3(::std::move(gmock_p3)), p4(::std::move(gmock_p4)), \
-        p5(::std::move(gmock_p5)), p6(::std::move(gmock_p6)), \
-        p7(::std::move(gmock_p7)), p8(::std::move(gmock_p8)) {\
-    }\
-    p0##_type const p0;\
-    p1##_type const p1;\
-    p2##_type const p2;\
-    p3##_type const p3;\
-    p4##_type const p4;\
-    p5##_type const p5;\
-    p6##_type const p6;\
-    p7##_type const p7;\
-    p8##_type const p8;\
-   private:\
-  };\
-  template <typename p0##_type, typename p1##_type, typename p2##_type, \
-      typename p3##_type, typename p4##_type, typename p5##_type, \
-      typename p6##_type, typename p7##_type, typename p8##_type>\
-  inline name##MatcherP9<p0##_type, p1##_type, p2##_type, p3##_type, \
-      p4##_type, p5##_type, p6##_type, p7##_type, \
-      p8##_type> name(p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \
-      p4##_type p4, p5##_type p5, p6##_type p6, p7##_type p7, \
-      p8##_type p8) {\
-    return name##MatcherP9<p0##_type, p1##_type, p2##_type, p3##_type, \
-        p4##_type, p5##_type, p6##_type, p7##_type, p8##_type>(p0, p1, p2, \
-        p3, p4, p5, p6, p7, p8);\
-  }\
-  template <typename p0##_type, typename p1##_type, typename p2##_type, \
-      typename p3##_type, typename p4##_type, typename p5##_type, \
-      typename p6##_type, typename p7##_type, typename p8##_type>\
-  template <typename arg_type>\
-  bool name##MatcherP9<p0##_type, p1##_type, p2##_type, p3##_type, p4##_type, \
-      p5##_type, p6##_type, p7##_type, \
-      p8##_type>::gmock_Impl<arg_type>::MatchAndExplain(\
-      GTEST_REFERENCE_TO_CONST_(arg_type) arg,\
-      ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\
-          const
-
-#define MATCHER_P10(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, description)\
-  template <typename p0##_type, typename p1##_type, typename p2##_type, \
-      typename p3##_type, typename p4##_type, typename p5##_type, \
-      typename p6##_type, typename p7##_type, typename p8##_type, \
-      typename p9##_type>\
-  class name##MatcherP10 {\
-   public:\
-    template <typename arg_type>\
-    class gmock_Impl : public ::testing::MatcherInterface<\
-        GTEST_REFERENCE_TO_CONST_(arg_type)> {\
-     public:\
-      gmock_Impl(p0##_type gmock_p0, p1##_type gmock_p1, p2##_type gmock_p2, \
-          p3##_type gmock_p3, p4##_type gmock_p4, p5##_type gmock_p5, \
-          p6##_type gmock_p6, p7##_type gmock_p7, p8##_type gmock_p8, \
-          p9##_type gmock_p9)\
-           : p0(::std::move(gmock_p0)), p1(::std::move(gmock_p1)), \
-               p2(::std::move(gmock_p2)), p3(::std::move(gmock_p3)), \
-               p4(::std::move(gmock_p4)), p5(::std::move(gmock_p5)), \
-               p6(::std::move(gmock_p6)), p7(::std::move(gmock_p7)), \
-               p8(::std::move(gmock_p8)), p9(::std::move(gmock_p9)) {}\
-      virtual bool MatchAndExplain(\
-          GTEST_REFERENCE_TO_CONST_(arg_type) arg,\
-          ::testing::MatchResultListener* result_listener) const;\
-      virtual void DescribeTo(::std::ostream* gmock_os) const {\
-        *gmock_os << FormatDescription(false);\
-      }\
-      virtual void DescribeNegationTo(::std::ostream* gmock_os) const {\
-        *gmock_os << FormatDescription(true);\
-      }\
-      p0##_type const p0;\
-      p1##_type const p1;\
-      p2##_type const p2;\
-      p3##_type const p3;\
-      p4##_type const p4;\
-      p5##_type const p5;\
-      p6##_type const p6;\
-      p7##_type const p7;\
-      p8##_type const p8;\
-      p9##_type const p9;\
-     private:\
-      ::std::string FormatDescription(bool negation) const {\
-        ::std::string gmock_description = (description);\
-        if (!gmock_description.empty()) {\
-          return gmock_description;\
-        }\
-        return ::testing::internal::FormatMatcherDescription(\
-            negation, #name, \
-            ::testing::internal::UniversalTersePrintTupleFieldsToStrings(\
-                ::std::tuple<p0##_type, p1##_type, p2##_type, p3##_type, \
-                    p4##_type, p5##_type, p6##_type, p7##_type, p8##_type, \
-                    p9##_type>(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9)));\
-      }\
-    };\
-    template <typename arg_type>\
-    operator ::testing::Matcher<arg_type>() const {\
-      return ::testing::Matcher<arg_type>(\
-          new gmock_Impl<arg_type>(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9));\
-    }\
-    name##MatcherP10(p0##_type gmock_p0, p1##_type gmock_p1, \
-        p2##_type gmock_p2, p3##_type gmock_p3, p4##_type gmock_p4, \
-        p5##_type gmock_p5, p6##_type gmock_p6, p7##_type gmock_p7, \
-        p8##_type gmock_p8, p9##_type gmock_p9) : p0(::std::move(gmock_p0)), \
-        p1(::std::move(gmock_p1)), p2(::std::move(gmock_p2)), \
-        p3(::std::move(gmock_p3)), p4(::std::move(gmock_p4)), \
-        p5(::std::move(gmock_p5)), p6(::std::move(gmock_p6)), \
-        p7(::std::move(gmock_p7)), p8(::std::move(gmock_p8)), \
-        p9(::std::move(gmock_p9)) {\
-    }\
-    p0##_type const p0;\
-    p1##_type const p1;\
-    p2##_type const p2;\
-    p3##_type const p3;\
-    p4##_type const p4;\
-    p5##_type const p5;\
-    p6##_type const p6;\
-    p7##_type const p7;\
-    p8##_type const p8;\
-    p9##_type const p9;\
-   private:\
-  };\
-  template <typename p0##_type, typename p1##_type, typename p2##_type, \
-      typename p3##_type, typename p4##_type, typename p5##_type, \
-      typename p6##_type, typename p7##_type, typename p8##_type, \
-      typename p9##_type>\
-  inline name##MatcherP10<p0##_type, p1##_type, p2##_type, p3##_type, \
-      p4##_type, p5##_type, p6##_type, p7##_type, p8##_type, \
-      p9##_type> name(p0##_type p0, p1##_type p1, p2##_type p2, p3##_type p3, \
-      p4##_type p4, p5##_type p5, p6##_type p6, p7##_type p7, p8##_type p8, \
-      p9##_type p9) {\
-    return name##MatcherP10<p0##_type, p1##_type, p2##_type, p3##_type, \
-        p4##_type, p5##_type, p6##_type, p7##_type, p8##_type, p9##_type>(p0, \
-        p1, p2, p3, p4, p5, p6, p7, p8, p9);\
-  }\
-  template <typename p0##_type, typename p1##_type, typename p2##_type, \
-      typename p3##_type, typename p4##_type, typename p5##_type, \
-      typename p6##_type, typename p7##_type, typename p8##_type, \
-      typename p9##_type>\
-  template <typename arg_type>\
-  bool name##MatcherP10<p0##_type, p1##_type, p2##_type, p3##_type, \
-      p4##_type, p5##_type, p6##_type, p7##_type, p8##_type, \
-      p9##_type>::gmock_Impl<arg_type>::MatchAndExplain(\
-      GTEST_REFERENCE_TO_CONST_(arg_type) arg,\
-      ::testing::MatchResultListener* result_listener GTEST_ATTRIBUTE_UNUSED_)\
-          const
-
-#endif  // GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_MATCHERS_H_
-// Copyright 2007, Google Inc.
-// All rights reserved.
-//
-// 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 Google Inc. 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.
-
-
-// Google Mock - a framework for writing C++ mock classes.
-//
-// This file implements some actions that depend on gmock-generated-actions.h.
-
-// GOOGLETEST_CM0002 DO NOT DELETE
-
-#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_MORE_ACTIONS_H_
-#define GMOCK_INCLUDE_GMOCK_GMOCK_MORE_ACTIONS_H_
-
-#include <algorithm>
-#include <type_traits>
-
-
-namespace testing {
-namespace internal {
-
-// An internal replacement for std::copy which mimics its behavior. This is
-// necessary because Visual Studio deprecates ::std::copy, issuing warning 4996.
-// However Visual Studio 2010 and later do not honor #pragmas which disable that
-// warning.
-template<typename InputIterator, typename OutputIterator>
-inline OutputIterator CopyElements(InputIterator first,
-                                   InputIterator last,
-                                   OutputIterator output) {
-  for (; first != last; ++first, ++output) {
-    *output = *first;
-  }
-  return output;
-}
-
-}  // namespace internal
-
-// Various overloads for Invoke().
-
-// The ACTION*() macros trigger warning C4100 (unreferenced formal
-// parameter) in MSVC with -W4.  Unfortunately they cannot be fixed in
-// the macro definition, as the warnings are generated when the macro
-// is expanded and macro expansion cannot contain #pragma.  Therefore
-// we suppress them here.
-#ifdef _MSC_VER
-# pragma warning(push)
-# pragma warning(disable:4100)
-#endif
-
-// Action ReturnArg<k>() returns the k-th argument of the mock function.
-ACTION_TEMPLATE(ReturnArg,
-                HAS_1_TEMPLATE_PARAMS(int, k),
-                AND_0_VALUE_PARAMS()) {
-  return ::std::get<k>(args);
-}
-
-// Action SaveArg<k>(pointer) saves the k-th (0-based) argument of the
-// mock function to *pointer.
-ACTION_TEMPLATE(SaveArg,
-                HAS_1_TEMPLATE_PARAMS(int, k),
-                AND_1_VALUE_PARAMS(pointer)) {
-  *pointer = ::std::get<k>(args);
-}
-
-// Action SaveArgPointee<k>(pointer) saves the value pointed to
-// by the k-th (0-based) argument of the mock function to *pointer.
-ACTION_TEMPLATE(SaveArgPointee,
-                HAS_1_TEMPLATE_PARAMS(int, k),
-                AND_1_VALUE_PARAMS(pointer)) {
-  *pointer = *::std::get<k>(args);
-}
-
-// Action SetArgReferee<k>(value) assigns 'value' to the variable
-// referenced by the k-th (0-based) argument of the mock function.
-ACTION_TEMPLATE(SetArgReferee,
-                HAS_1_TEMPLATE_PARAMS(int, k),
-                AND_1_VALUE_PARAMS(value)) {
-  typedef typename ::std::tuple_element<k, args_type>::type argk_type;
-  // Ensures that argument #k is a reference.  If you get a compiler
-  // error on the next line, you are using SetArgReferee<k>(value) in
-  // a mock function whose k-th (0-based) argument is not a reference.
-  GTEST_COMPILE_ASSERT_(internal::is_reference<argk_type>::value,
-                        SetArgReferee_must_be_used_with_a_reference_argument);
-  ::std::get<k>(args) = value;
-}
-
-// Action SetArrayArgument<k>(first, last) copies the elements in
-// source range [first, last) to the array pointed to by the k-th
-// (0-based) argument, which can be either a pointer or an
-// iterator. The action does not take ownership of the elements in the
-// source range.
-ACTION_TEMPLATE(SetArrayArgument,
-                HAS_1_TEMPLATE_PARAMS(int, k),
-                AND_2_VALUE_PARAMS(first, last)) {
-  // Visual Studio deprecates ::std::copy, so we use our own copy in that case.
-#ifdef _MSC_VER
-  internal::CopyElements(first, last, ::std::get<k>(args));
-#else
-  ::std::copy(first, last, ::std::get<k>(args));
-#endif
-}
-
-// Action DeleteArg<k>() deletes the k-th (0-based) argument of the mock
-// function.
-ACTION_TEMPLATE(DeleteArg,
-                HAS_1_TEMPLATE_PARAMS(int, k),
-                AND_0_VALUE_PARAMS()) {
-  delete ::std::get<k>(args);
-}
-
-// This action returns the value pointed to by 'pointer'.
-ACTION_P(ReturnPointee, pointer) { return *pointer; }
-
-// Action Throw(exception) can be used in a mock function of any type
-// to throw the given exception.  Any copyable value can be thrown.
-#if GTEST_HAS_EXCEPTIONS
-
-// Suppresses the 'unreachable code' warning that VC generates in opt modes.
-# ifdef _MSC_VER
-#  pragma warning(push)          // Saves the current warning state.
-#  pragma warning(disable:4702)  // Temporarily disables warning 4702.
-# endif
-ACTION_P(Throw, exception) { throw exception; }
-# ifdef _MSC_VER
-#  pragma warning(pop)           // Restores the warning state.
-# endif
-
-#endif  // GTEST_HAS_EXCEPTIONS
-
-#ifdef _MSC_VER
-# pragma warning(pop)
-#endif
-
-}  // namespace testing
-
-#endif  // GMOCK_INCLUDE_GMOCK_GMOCK_MORE_ACTIONS_H_
+#endif  // GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_MORE_ACTIONS_H_
 // Copyright 2013, Google Inc.
 // All rights reserved.
 //
@@ -12942,15 +11295,15 @@
 
 // Google Mock - a framework for writing C++ mock classes.
 //
-// This file implements some matchers that depend on gmock-generated-matchers.h.
+// This file implements some matchers that depend on gmock-matchers.h.
 //
 // Note that tests are implemented in gmock-matchers_test.cc rather than
 // gmock-more-matchers-test.cc.
 
 // GOOGLETEST_CM0002 DO NOT DELETE
 
-#ifndef GMOCK_INCLUDE_GMOCK_MORE_MATCHERS_H_
-#define GMOCK_INCLUDE_GMOCK_MORE_MATCHERS_H_
+#ifndef GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_MORE_MATCHERS_H_
+#define GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_MORE_MATCHERS_H_
 
 
 namespace testing {
@@ -13000,7 +11353,7 @@
 
 }  // namespace testing
 
-#endif  // GMOCK_INCLUDE_GMOCK_MORE_MATCHERS_H_
+#endif  // GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_MORE_MATCHERS_H_
 // Copyright 2008, Google Inc.
 // All rights reserved.
 //
@@ -13063,18 +11416,89 @@
 
 // GOOGLETEST_CM0002 DO NOT DELETE
 
-#ifndef GMOCK_INCLUDE_GMOCK_GMOCK_NICE_STRICT_H_
-#define GMOCK_INCLUDE_GMOCK_GMOCK_NICE_STRICT_H_
+#ifndef GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_NICE_STRICT_H_
+#define GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_NICE_STRICT_H_
+
+#include <type_traits>
 
 
 namespace testing {
+template <class MockClass>
+class NiceMock;
+template <class MockClass>
+class NaggyMock;
+template <class MockClass>
+class StrictMock;
+
+namespace internal {
+template <typename T>
+std::true_type StrictnessModifierProbe(const NiceMock<T>&);
+template <typename T>
+std::true_type StrictnessModifierProbe(const NaggyMock<T>&);
+template <typename T>
+std::true_type StrictnessModifierProbe(const StrictMock<T>&);
+std::false_type StrictnessModifierProbe(...);
+
+template <typename T>
+constexpr bool HasStrictnessModifier() {
+  return decltype(StrictnessModifierProbe(std::declval<const T&>()))::value;
+}
+
+// Base classes that register and deregister with testing::Mock to alter the
+// default behavior around uninteresting calls. Inheriting from one of these
+// classes first and then MockClass ensures the MockClass constructor is run
+// after registration, and that the MockClass destructor runs before
+// deregistration. This guarantees that MockClass's constructor and destructor
+// run with the same level of strictness as its instance methods.
+
+#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MINGW && \
+    (defined(_MSC_VER) || defined(__clang__))
+// We need to mark these classes with this declspec to ensure that
+// the empty base class optimization is performed.
+#define GTEST_INTERNAL_EMPTY_BASE_CLASS __declspec(empty_bases)
+#else
+#define GTEST_INTERNAL_EMPTY_BASE_CLASS
+#endif
+
+template <typename Base>
+class NiceMockImpl {
+ public:
+  NiceMockImpl() { ::testing::Mock::AllowUninterestingCalls(this); }
+
+  ~NiceMockImpl() { ::testing::Mock::UnregisterCallReaction(this); }
+};
+
+template <typename Base>
+class NaggyMockImpl {
+ public:
+  NaggyMockImpl() { ::testing::Mock::WarnUninterestingCalls(this); }
+
+  ~NaggyMockImpl() { ::testing::Mock::UnregisterCallReaction(this); }
+};
+
+template <typename Base>
+class StrictMockImpl {
+ public:
+  StrictMockImpl() { ::testing::Mock::FailUninterestingCalls(this); }
+
+  ~StrictMockImpl() { ::testing::Mock::UnregisterCallReaction(this); }
+};
+
+}  // namespace internal
 
 template <class MockClass>
-class NiceMock : public MockClass {
+class GTEST_INTERNAL_EMPTY_BASE_CLASS NiceMock
+    : private internal::NiceMockImpl<MockClass>,
+      public MockClass {
  public:
+  static_assert(!internal::HasStrictnessModifier<MockClass>(),
+                "Can't apply NiceMock to a class hierarchy that already has a "
+                "strictness modifier. See "
+                "https://google.github.io/googletest/"
+                "gmock_cook_book.html#NiceStrictNaggy");
   NiceMock() : MockClass() {
-    ::testing::Mock::AllowUninterestingCalls(
-        internal::ImplicitCast_<MockClass*>(this));
+    static_assert(sizeof(*this) == sizeof(MockClass),
+                  "The impl subclass shouldn't introduce any padding");
   }
 
   // Ideally, we would inherit base class's constructors through a using
@@ -13086,21 +11510,16 @@
   // made explicit.
   template <typename A>
   explicit NiceMock(A&& arg) : MockClass(std::forward<A>(arg)) {
-    ::testing::Mock::AllowUninterestingCalls(
-        internal::ImplicitCast_<MockClass*>(this));
+    static_assert(sizeof(*this) == sizeof(MockClass),
+                  "The impl subclass shouldn't introduce any padding");
   }
 
-  template <typename A1, typename A2, typename... An>
-  NiceMock(A1&& arg1, A2&& arg2, An&&... args)
-      : MockClass(std::forward<A1>(arg1), std::forward<A2>(arg2),
+  template <typename TArg1, typename TArg2, typename... An>
+  NiceMock(TArg1&& arg1, TArg2&& arg2, An&&... args)
+      : MockClass(std::forward<TArg1>(arg1), std::forward<TArg2>(arg2),
                   std::forward<An>(args)...) {
-    ::testing::Mock::AllowUninterestingCalls(
-        internal::ImplicitCast_<MockClass*>(this));
-  }
-
-  ~NiceMock() {  // NOLINT
-    ::testing::Mock::UnregisterCallReaction(
-        internal::ImplicitCast_<MockClass*>(this));
+    static_assert(sizeof(*this) == sizeof(MockClass),
+                  "The impl subclass shouldn't introduce any padding");
   }
 
  private:
@@ -13108,11 +11527,19 @@
 };
 
 template <class MockClass>
-class NaggyMock : public MockClass {
+class GTEST_INTERNAL_EMPTY_BASE_CLASS NaggyMock
+    : private internal::NaggyMockImpl<MockClass>,
+      public MockClass {
+  static_assert(!internal::HasStrictnessModifier<MockClass>(),
+                "Can't apply NaggyMock to a class hierarchy that already has a "
+                "strictness modifier. See "
+                "https://google.github.io/googletest/"
+                "gmock_cook_book.html#NiceStrictNaggy");
+
  public:
   NaggyMock() : MockClass() {
-    ::testing::Mock::WarnUninterestingCalls(
-        internal::ImplicitCast_<MockClass*>(this));
+    static_assert(sizeof(*this) == sizeof(MockClass),
+                  "The impl subclass shouldn't introduce any padding");
   }
 
   // Ideally, we would inherit base class's constructors through a using
@@ -13124,21 +11551,16 @@
   // made explicit.
   template <typename A>
   explicit NaggyMock(A&& arg) : MockClass(std::forward<A>(arg)) {
-    ::testing::Mock::WarnUninterestingCalls(
-        internal::ImplicitCast_<MockClass*>(this));
+    static_assert(sizeof(*this) == sizeof(MockClass),
+                  "The impl subclass shouldn't introduce any padding");
   }
 
-  template <typename A1, typename A2, typename... An>
-  NaggyMock(A1&& arg1, A2&& arg2, An&&... args)
-      : MockClass(std::forward<A1>(arg1), std::forward<A2>(arg2),
+  template <typename TArg1, typename TArg2, typename... An>
+  NaggyMock(TArg1&& arg1, TArg2&& arg2, An&&... args)
+      : MockClass(std::forward<TArg1>(arg1), std::forward<TArg2>(arg2),
                   std::forward<An>(args)...) {
-    ::testing::Mock::WarnUninterestingCalls(
-        internal::ImplicitCast_<MockClass*>(this));
-  }
-
-  ~NaggyMock() {  // NOLINT
-    ::testing::Mock::UnregisterCallReaction(
-        internal::ImplicitCast_<MockClass*>(this));
+    static_assert(sizeof(*this) == sizeof(MockClass),
+                  "The impl subclass shouldn't introduce any padding");
   }
 
  private:
@@ -13146,11 +11568,19 @@
 };
 
 template <class MockClass>
-class StrictMock : public MockClass {
+class GTEST_INTERNAL_EMPTY_BASE_CLASS StrictMock
+    : private internal::StrictMockImpl<MockClass>,
+      public MockClass {
  public:
+  static_assert(
+      !internal::HasStrictnessModifier<MockClass>(),
+      "Can't apply StrictMock to a class hierarchy that already has a "
+      "strictness modifier. See "
+      "https://google.github.io/googletest/"
+      "gmock_cook_book.html#NiceStrictNaggy");
   StrictMock() : MockClass() {
-    ::testing::Mock::FailUninterestingCalls(
-        internal::ImplicitCast_<MockClass*>(this));
+    static_assert(sizeof(*this) == sizeof(MockClass),
+                  "The impl subclass shouldn't introduce any padding");
   }
 
   // Ideally, we would inherit base class's constructors through a using
@@ -13162,58 +11592,27 @@
   // made explicit.
   template <typename A>
   explicit StrictMock(A&& arg) : MockClass(std::forward<A>(arg)) {
-    ::testing::Mock::FailUninterestingCalls(
-        internal::ImplicitCast_<MockClass*>(this));
+    static_assert(sizeof(*this) == sizeof(MockClass),
+                  "The impl subclass shouldn't introduce any padding");
   }
 
-  template <typename A1, typename A2, typename... An>
-  StrictMock(A1&& arg1, A2&& arg2, An&&... args)
-      : MockClass(std::forward<A1>(arg1), std::forward<A2>(arg2),
+  template <typename TArg1, typename TArg2, typename... An>
+  StrictMock(TArg1&& arg1, TArg2&& arg2, An&&... args)
+      : MockClass(std::forward<TArg1>(arg1), std::forward<TArg2>(arg2),
                   std::forward<An>(args)...) {
-    ::testing::Mock::FailUninterestingCalls(
-        internal::ImplicitCast_<MockClass*>(this));
-  }
-
-  ~StrictMock() {  // NOLINT
-    ::testing::Mock::UnregisterCallReaction(
-        internal::ImplicitCast_<MockClass*>(this));
+    static_assert(sizeof(*this) == sizeof(MockClass),
+                  "The impl subclass shouldn't introduce any padding");
   }
 
  private:
   GTEST_DISALLOW_COPY_AND_ASSIGN_(StrictMock);
 };
 
-// The following specializations catch some (relatively more common)
-// user errors of nesting nice and strict mocks.  They do NOT catch
-// all possible errors.
-
-// These specializations are declared but not defined, as NiceMock,
-// NaggyMock, and StrictMock cannot be nested.
-
-template <typename MockClass>
-class NiceMock<NiceMock<MockClass> >;
-template <typename MockClass>
-class NiceMock<NaggyMock<MockClass> >;
-template <typename MockClass>
-class NiceMock<StrictMock<MockClass> >;
-
-template <typename MockClass>
-class NaggyMock<NiceMock<MockClass> >;
-template <typename MockClass>
-class NaggyMock<NaggyMock<MockClass> >;
-template <typename MockClass>
-class NaggyMock<StrictMock<MockClass> >;
-
-template <typename MockClass>
-class StrictMock<NiceMock<MockClass> >;
-template <typename MockClass>
-class StrictMock<NaggyMock<MockClass> >;
-template <typename MockClass>
-class StrictMock<StrictMock<MockClass> >;
+#undef GTEST_INTERNAL_EMPTY_BASE_CLASS
 
 }  // namespace testing
 
-#endif  // GMOCK_INCLUDE_GMOCK_GMOCK_NICE_STRICT_H_
+#endif  // GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_NICE_STRICT_H_
 
 namespace testing {
 
@@ -13245,4 +11644,4 @@
 
 }  // namespace testing
 
-#endif  // GMOCK_INCLUDE_GMOCK_GMOCK_H_
+#endif  // GOOGLEMOCK_INCLUDE_GMOCK_GMOCK_H_
diff --git a/third_party/ceres/internal/ceres/gmock/mock-log.h b/third_party/ceres/internal/ceres/gmock/mock-log.h
index 54669b7..91b5939 100644
--- a/third_party/ceres/internal/ceres/gmock/mock-log.h
+++ b/third_party/ceres/internal/ceres/gmock/mock-log.h
@@ -71,7 +71,7 @@
   ScopedMockLog() { AddLogSink(this); }
 
   // When the object is destructed, it stops intercepting logs.
-  virtual ~ScopedMockLog() { RemoveLogSink(this); }
+  ~ScopedMockLog() override { RemoveLogSink(this); }
 
   // Implements the mock method:
   //
@@ -112,10 +112,10 @@
   // be running simultaneously, we ensure thread-safety of the exchange between
   // send() and WaitTillSent(), and that for each message, LOG(), send(),
   // WaitTillSent() and Log() are executed in the same thread.
-  virtual void send(google::LogSeverity severity,
+  void send(google::LogSeverity severity,
                     const char* full_filename,
                     const char* base_filename, int line, const tm* tm_time,
-                    const char* message, size_t message_len) {
+                    const char* message, size_t message_len) override {
     // We are only interested in the log severity, full file name, and
     // log message.
     message_info_.severity = severity;
@@ -130,7 +130,7 @@
   //
   // LOG(), send(), WaitTillSent() and Log() will occur in the same thread for
   // a given log message.
-  virtual void WaitTillSent() {
+  void WaitTillSent() override {
     // First, and very importantly, we save a copy of the message being
     // processed before calling Log(), since Log() may indirectly call send()
     // and WaitTillSent() in the same thread again.
diff --git a/third_party/ceres/internal/ceres/gmock_gtest_all.cc b/third_party/ceres/internal/ceres/gmock_gtest_all.cc
index dd43444..9ea7029 100644
--- a/third_party/ceres/internal/ceres/gmock_gtest_all.cc
+++ b/third_party/ceres/internal/ceres/gmock_gtest_all.cc
@@ -105,8 +105,8 @@
 
 // GOOGLETEST_CM0004 DO NOT DELETE
 
-#ifndef GTEST_INCLUDE_GTEST_GTEST_SPI_H_
-#define GTEST_INCLUDE_GTEST_GTEST_SPI_H_
+#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_SPI_H_
+#define GOOGLETEST_INCLUDE_GTEST_GTEST_SPI_H_
 
 
 GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \
@@ -306,10 +306,9 @@
     }\
   } while (::testing::internal::AlwaysFalse())
 
-#endif  // GTEST_INCLUDE_GTEST_GTEST_SPI_H_
+#endif  // GOOGLETEST_INCLUDE_GTEST_GTEST_SPI_H_
 
 #include <ctype.h>
-#include <math.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -318,6 +317,9 @@
 #include <wctype.h>
 
 #include <algorithm>
+#include <chrono>  // NOLINT
+#include <cmath>
+#include <cstdint>
 #include <iomanip>
 #include <limits>
 #include <list>
@@ -328,8 +330,6 @@
 
 #if GTEST_OS_LINUX
 
-# define GTEST_HAS_GETTIMEOFDAY_ 1
-
 # include <fcntl.h>  // NOLINT
 # include <limits.h>  // NOLINT
 # include <sched.h>  // NOLINT
@@ -341,7 +341,6 @@
 # include <string>
 
 #elif GTEST_OS_ZOS
-# define GTEST_HAS_GETTIMEOFDAY_ 1
 # include <sys/time.h>  // NOLINT
 
 // On z/OS we additionally need strings.h for strcasecmp.
@@ -354,27 +353,24 @@
 
 #elif GTEST_OS_WINDOWS  // We are on Windows proper.
 
+# include <windows.h>  // NOLINT
+# undef min
+
+#ifdef _MSC_VER
+# include <crtdbg.h>  // NOLINT
+#endif
+
 # include <io.h>  // NOLINT
 # include <sys/timeb.h>  // NOLINT
 # include <sys/types.h>  // NOLINT
 # include <sys/stat.h>  // NOLINT
 
 # if GTEST_OS_WINDOWS_MINGW
-// MinGW has gettimeofday() but not _ftime64().
-#  define GTEST_HAS_GETTIMEOFDAY_ 1
 #  include <sys/time.h>  // NOLINT
 # endif  // GTEST_OS_WINDOWS_MINGW
 
-// cpplint thinks that the header is already included, so we want to
-// silence it.
-# include <windows.h>  // NOLINT
-# undef min
-
 #else
 
-// Assume other platforms have gettimeofday().
-# define GTEST_HAS_GETTIMEOFDAY_ 1
-
 // cpplint thinks that the header is already included, so we want to
 // silence it.
 # include <sys/time.h>  // NOLINT
@@ -426,8 +422,8 @@
 // This file contains purely Google Test's internal implementation.  Please
 // DO NOT #INCLUDE IT IN A USER PROGRAM.
 
-#ifndef GTEST_SRC_GTEST_INTERNAL_INL_H_
-#define GTEST_SRC_GTEST_INTERNAL_INL_H_
+#ifndef GOOGLETEST_SRC_GTEST_INTERNAL_INL_H_
+#define GOOGLETEST_SRC_GTEST_INTERNAL_INL_H_
 
 #ifndef _WIN32_WCE
 # include <errno.h>
@@ -437,6 +433,7 @@
 #include <string.h>  // For memmove.
 
 #include <algorithm>
+#include <cstdint>
 #include <memory>
 #include <string>
 #include <vector>
@@ -475,9 +472,11 @@
 const char kBreakOnFailureFlag[] = "break_on_failure";
 const char kCatchExceptionsFlag[] = "catch_exceptions";
 const char kColorFlag[] = "color";
+const char kFailFast[] = "fail_fast";
 const char kFilterFlag[] = "filter";
 const char kListTestsFlag[] = "list_tests";
 const char kOutputFlag[] = "output";
+const char kBriefFlag[] = "brief";
 const char kPrintTimeFlag[] = "print_time";
 const char kPrintUTF8Flag[] = "print_utf8";
 const char kRandomSeedFlag[] = "random_seed";
@@ -491,14 +490,14 @@
 // A valid random seed must be in [1, kMaxRandomSeed].
 const int kMaxRandomSeed = 99999;
 
-// g_help_flag is true iff the --help flag or an equivalent form is
-// specified on the command line.
+// g_help_flag is true if and only if the --help flag or an equivalent form
+// is specified on the command line.
 GTEST_API_ extern bool g_help_flag;
 
 // Returns the current time in milliseconds.
 GTEST_API_ TimeInMillis GetTimeInMillis();
 
-// Returns true iff Google Test should use colors in the output.
+// Returns true if and only if Google Test should use colors in the output.
 GTEST_API_ bool ShouldUseColor(bool stdout_is_tty);
 
 // Formats the given time in milliseconds as seconds.
@@ -515,11 +514,11 @@
 // On success, stores the value of the flag in *value, and returns
 // true.  On failure, returns false without changing *value.
 GTEST_API_ bool ParseInt32Flag(
-    const char* str, const char* flag, Int32* value);
+    const char* str, const char* flag, int32_t* value);
 
 // Returns a random seed in range [1, kMaxRandomSeed] based on the
 // given --gtest_random_seed flag value.
-inline int GetRandomSeedFromFlag(Int32 random_seed_flag) {
+inline int GetRandomSeedFromFlag(int32_t random_seed_flag) {
   const unsigned int raw_seed = (random_seed_flag == 0) ?
       static_cast<unsigned int>(GetTimeInMillis()) :
       static_cast<unsigned int>(random_seed_flag);
@@ -555,10 +554,12 @@
     color_ = GTEST_FLAG(color);
     death_test_style_ = GTEST_FLAG(death_test_style);
     death_test_use_fork_ = GTEST_FLAG(death_test_use_fork);
+    fail_fast_ = GTEST_FLAG(fail_fast);
     filter_ = GTEST_FLAG(filter);
     internal_run_death_test_ = GTEST_FLAG(internal_run_death_test);
     list_tests_ = GTEST_FLAG(list_tests);
     output_ = GTEST_FLAG(output);
+    brief_ = GTEST_FLAG(brief);
     print_time_ = GTEST_FLAG(print_time);
     print_utf8_ = GTEST_FLAG(print_utf8);
     random_seed_ = GTEST_FLAG(random_seed);
@@ -578,9 +579,11 @@
     GTEST_FLAG(death_test_style) = death_test_style_;
     GTEST_FLAG(death_test_use_fork) = death_test_use_fork_;
     GTEST_FLAG(filter) = filter_;
+    GTEST_FLAG(fail_fast) = fail_fast_;
     GTEST_FLAG(internal_run_death_test) = internal_run_death_test_;
     GTEST_FLAG(list_tests) = list_tests_;
     GTEST_FLAG(output) = output_;
+    GTEST_FLAG(brief) = brief_;
     GTEST_FLAG(print_time) = print_time_;
     GTEST_FLAG(print_utf8) = print_utf8_;
     GTEST_FLAG(random_seed) = random_seed_;
@@ -599,16 +602,18 @@
   std::string color_;
   std::string death_test_style_;
   bool death_test_use_fork_;
+  bool fail_fast_;
   std::string filter_;
   std::string internal_run_death_test_;
   bool list_tests_;
   std::string output_;
+  bool brief_;
   bool print_time_;
   bool print_utf8_;
-  internal::Int32 random_seed_;
-  internal::Int32 repeat_;
+  int32_t random_seed_;
+  int32_t repeat_;
   bool shuffle_;
-  internal::Int32 stack_trace_depth_;
+  int32_t stack_trace_depth_;
   std::string stream_result_to_;
   bool throw_on_failure_;
 } GTEST_ATTRIBUTE_UNUSED_;
@@ -619,7 +624,7 @@
 // If the code_point is not a valid Unicode code point
 // (i.e. outside of Unicode range U+0 to U+10FFFF) it will be converted
 // to "(Invalid Unicode 0xXXXXXXXX)".
-GTEST_API_ std::string CodePointToUtf8(UInt32 code_point);
+GTEST_API_ std::string CodePointToUtf8(uint32_t code_point);
 
 // Converts a wide string to a narrow string in UTF-8 encoding.
 // The wide string is assumed to have the following encoding:
@@ -652,14 +657,14 @@
                             const char* shard_index_str,
                             bool in_subprocess_for_death_test);
 
-// Parses the environment variable var as an Int32. If it is unset,
-// returns default_val. If it is not an Int32, prints an error and
+// Parses the environment variable var as a 32-bit integer. If it is unset,
+// returns default_val. If it is not a 32-bit integer, prints an error and
 // and aborts.
-GTEST_API_ Int32 Int32FromEnvOrDie(const char* env_var, Int32 default_val);
+GTEST_API_ int32_t Int32FromEnvOrDie(const char* env_var, int32_t default_val);
 
 // Given the total number of shards, the shard index, and the test id,
-// returns true iff the test should be run on this shard. The test id is
-// some arbitrary but unique non-negative integer assigned to each test
+// returns true if and only if the test should be run on this shard. The test id
+// is some arbitrary but unique non-negative integer assigned to each test
 // method. Assumes that 0 <= shard_index < total_shards.
 GTEST_API_ bool ShouldRunTestOnShard(
     int total_shards, int shard_index, int test_id);
@@ -690,7 +695,8 @@
 // in range [0, v.size()).
 template <typename E>
 inline E GetElementOr(const std::vector<E>& v, int i, E default_value) {
-  return (i < 0 || i >= static_cast<int>(v.size())) ? default_value : v[i];
+  return (i < 0 || i >= static_cast<int>(v.size())) ? default_value
+                                                    : v[static_cast<size_t>(i)];
 }
 
 // Performs an in-place shuffle of a range of the vector's elements.
@@ -712,8 +718,11 @@
   // http://en.wikipedia.org/wiki/Fisher-Yates_shuffle
   for (int range_width = end - begin; range_width >= 2; range_width--) {
     const int last_in_range = begin + range_width - 1;
-    const int selected = begin + random->Generate(range_width);
-    std::swap((*v)[selected], (*v)[last_in_range]);
+    const int selected =
+        begin +
+        static_cast<int>(random->Generate(static_cast<uint32_t>(range_width)));
+    std::swap((*v)[static_cast<size_t>(selected)],
+              (*v)[static_cast<size_t>(last_in_range)]);
   }
 }
 
@@ -740,7 +749,7 @@
   // TestPropertyKeyIs has NO default constructor.
   explicit TestPropertyKeyIs(const std::string& key) : key_(key) {}
 
-  // Returns true iff the test name of test property matches on key_.
+  // Returns true if and only if the test name of test property matches on key_.
   bool operator()(const TestProperty& test_property) const {
     return test_property.key() == key_;
   }
@@ -773,15 +782,8 @@
 
   // Functions for processing the gtest_filter flag.
 
-  // Returns true iff the wildcard pattern matches the string.  The
-  // first ':' or '\0' character in pattern marks the end of it.
-  //
-  // This recursive algorithm isn't very efficient, but is clear and
-  // works well enough for matching test names, which are short.
-  static bool PatternMatchesString(const char *pattern, const char *str);
-
-  // Returns true iff the user-specified filter matches the test suite
-  // name and the test name.
+  // Returns true if and only if the user-specified filter matches the test
+  // suite name and the test name.
   static bool FilterMatchesTest(const std::string& test_suite_name,
                                 const std::string& test_name);
 
@@ -965,11 +967,12 @@
   // Gets the elapsed time, in milliseconds.
   TimeInMillis elapsed_time() const { return elapsed_time_; }
 
-  // Returns true iff the unit test passed (i.e. all test suites passed).
+  // Returns true if and only if the unit test passed (i.e. all test suites
+  // passed).
   bool Passed() const { return !Failed(); }
 
-  // Returns true iff the unit test failed (i.e. some test suite failed
-  // or something outside of all tests failed).
+  // Returns true if and only if the unit test failed (i.e. some test suite
+  // failed or something outside of all tests failed).
   bool Failed() const {
     return failed_test_suite_count() > 0 || ad_hoc_test_result()->Failed();
   }
@@ -978,7 +981,7 @@
   // total_test_suite_count() - 1. If i is not in that range, returns NULL.
   const TestSuite* GetTestSuite(int i) const {
     const int index = GetElementOr(test_suite_indices_, i, -1);
-    return index < 0 ? nullptr : test_suites_[i];
+    return index < 0 ? nullptr : test_suites_[static_cast<size_t>(i)];
   }
 
   //  Legacy API is deprecated but still available
@@ -990,7 +993,7 @@
   // total_test_suite_count() - 1. If i is not in that range, returns NULL.
   TestSuite* GetMutableSuiteCase(int i) {
     const int index = GetElementOr(test_suite_indices_, i, -1);
-    return index < 0 ? nullptr : test_suites_[index];
+    return index < 0 ? nullptr : test_suites_[static_cast<size_t>(index)];
   }
 
   // Provides access to the event listener list.
@@ -1033,10 +1036,10 @@
   // Arguments:
   //
   //   test_suite_name: name of the test suite
-  //   type_param:     the name of the test's type parameter, or NULL if
-  //                   this is not a typed or a type-parameterized test.
-  //   set_up_tc:      pointer to the function that sets up the test suite
-  //   tear_down_tc:   pointer to the function that tears down the test suite
+  //   type_param:      the name of the test's type parameter, or NULL if
+  //                    this is not a typed or a type-parameterized test.
+  //   set_up_tc:       pointer to the function that sets up the test suite
+  //   tear_down_tc:    pointer to the function that tears down the test suite
   TestSuite* GetTestSuite(const char* test_suite_name, const char* type_param,
                           internal::SetUpTestSuiteFunc set_up_tc,
                           internal::TearDownTestSuiteFunc tear_down_tc);
@@ -1060,6 +1063,7 @@
   void AddTestInfo(internal::SetUpTestSuiteFunc set_up_tc,
                    internal::TearDownTestSuiteFunc tear_down_tc,
                    TestInfo* test_info) {
+#if GTEST_HAS_DEATH_TEST
     // In order to support thread-safe death tests, we need to
     // remember the original working directory when the test program
     // was first invoked.  We cannot do this in RUN_ALL_TESTS(), as
@@ -1072,6 +1076,7 @@
       GTEST_CHECK_(!original_working_dir_.IsEmpty())
           << "Failed to get the current working directory.";
     }
+#endif  // GTEST_HAS_DEATH_TEST
 
     GetTestSuite(test_info->test_suite_name(), test_info->type_param(),
                  set_up_tc, tear_down_tc)
@@ -1084,6 +1089,17 @@
     return parameterized_test_registry_;
   }
 
+  std::set<std::string>* ignored_parameterized_test_suites() {
+    return &ignored_parameterized_test_suites_;
+  }
+
+  // Returns TypeParameterizedTestSuiteRegistry object used to keep track of
+  // type-parameterized tests and instantiations of them.
+  internal::TypeParameterizedTestSuiteRegistry&
+  type_parameterized_test_registry() {
+    return type_parameterized_test_registry_;
+  }
+
   // Sets the TestSuite object for the test that's currently running.
   void set_current_test_suite(TestSuite* a_current_test_suite) {
     current_test_suite_ = a_current_test_suite;
@@ -1260,6 +1276,12 @@
   // ParameterizedTestRegistry object used to register value-parameterized
   // tests.
   internal::ParameterizedTestSuiteRegistry parameterized_test_registry_;
+  internal::TypeParameterizedTestSuiteRegistry
+      type_parameterized_test_registry_;
+
+  // The set holding the name of parameterized
+  // test suites that may go uninstantiated.
+  std::set<std::string> ignored_parameterized_test_suites_;
 
   // Indicates whether RegisterParameterizedTests() has been called already.
   bool parameterized_tests_registered_;
@@ -1299,7 +1321,7 @@
   // desired.
   OsStackTraceGetterInterface* os_stack_trace_getter_;
 
-  // True iff PostFlagParsingInit() has been called.
+  // True if and only if PostFlagParsingInit() has been called.
   bool post_flag_parse_init_performed_;
 
   // The random number seed used at the beginning of the test run.
@@ -1386,20 +1408,9 @@
   char* end;
   // BiggestConvertible is the largest integer type that system-provided
   // string-to-number conversion routines can return.
+  using BiggestConvertible = unsigned long long;  // NOLINT
 
-# if GTEST_OS_WINDOWS && !defined(__GNUC__)
-
-  // MSVC and C++ Builder define __int64 instead of the standard long long.
-  typedef unsigned __int64 BiggestConvertible;
-  const BiggestConvertible parsed = _strtoui64(str.c_str(), &end, 10);
-
-# else
-
-  typedef unsigned long long BiggestConvertible;  // NOLINT
-  const BiggestConvertible parsed = strtoull(str.c_str(), &end, 10);
-
-# endif  // GTEST_OS_WINDOWS && !defined(__GNUC__)
-
+  const BiggestConvertible parsed = strtoull(str.c_str(), &end, 10);  // NOLINT
   const bool parse_success = *end == '\0' && errno == 0;
 
   GTEST_CHECK_(sizeof(Integer) <= sizeof(parsed));
@@ -1475,8 +1486,8 @@
       GTEST_CHECK_(sockfd_ != -1)
           << "Send() can be called only when there is a connection.";
 
-      const int len = static_cast<int>(message.length());
-      if (write(sockfd_, message.c_str(), len) != len) {
+      const auto len = static_cast<size_t>(message.length());
+      if (write(sockfd_, message.c_str(), len) != static_cast<ssize_t>(len)) {
         GTEST_LOG_(WARNING)
             << "stream_result_to: failed to stream to "
             << host_name_ << ":" << port_num_;
@@ -1541,13 +1552,13 @@
   }
 
   // Note that "event=TestCaseStart" is a wire format and has to remain
-  // "case" for compatibilty
+  // "case" for compatibility
   void OnTestCaseStart(const TestCase& test_case) override {
     SendLn(std::string("event=TestCaseStart&name=") + test_case.name());
   }
 
   // Note that "event=TestCaseEnd" is a wire format and has to remain
-  // "case" for compatibilty
+  // "case" for compatibility
   void OnTestCaseEnd(const TestCase& test_case) override {
     SendLn("event=TestCaseEnd&passed=" + FormatBool(test_case.Passed()) +
            "&elapsed_time=" + StreamableToString(test_case.elapsed_time()) +
@@ -1595,7 +1606,7 @@
 
 GTEST_DISABLE_MSC_WARNINGS_POP_()  //  4251
 
-#endif  // GTEST_SRC_GTEST_INTERNAL_INL_H_
+#endif  // GOOGLETEST_SRC_GTEST_INTERNAL_INL_H_
 
 #if GTEST_OS_WINDOWS
 # define vsnprintf _vsnprintf
@@ -1653,8 +1664,8 @@
 // stack trace.
 const char kStackTraceMarker[] = "\nStack trace:\n";
 
-// g_help_flag is true iff the --help flag or an equivalent form is
-// specified on the command line.
+// g_help_flag is true if and only if the --help flag or an equivalent form
+// is specified on the command line.
 bool g_help_flag = false;
 
 // Utilty function to Open File for Writing
@@ -1685,21 +1696,35 @@
   return kUniversalFilter;
 }
 
+// Bazel passes in the argument to '--test_runner_fail_fast' via the
+// TESTBRIDGE_TEST_RUNNER_FAIL_FAST environment variable.
+static bool GetDefaultFailFast() {
+  const char* const testbridge_test_runner_fail_fast =
+      internal::posix::GetEnv("TESTBRIDGE_TEST_RUNNER_FAIL_FAST");
+  if (testbridge_test_runner_fail_fast != nullptr) {
+    return strcmp(testbridge_test_runner_fail_fast, "1") == 0;
+  }
+  return false;
+}
+
+GTEST_DEFINE_bool_(
+    fail_fast, internal::BoolFromGTestEnv("fail_fast", GetDefaultFailFast()),
+    "True if and only if a test failure should stop further test execution.");
+
 GTEST_DEFINE_bool_(
     also_run_disabled_tests,
     internal::BoolFromGTestEnv("also_run_disabled_tests", false),
     "Run disabled tests too, in addition to the tests normally being run.");
 
 GTEST_DEFINE_bool_(
-    break_on_failure,
-    internal::BoolFromGTestEnv("break_on_failure", false),
-    "True iff a failed assertion should be a debugger break-point.");
+    break_on_failure, internal::BoolFromGTestEnv("break_on_failure", false),
+    "True if and only if a failed assertion should be a debugger "
+    "break-point.");
 
-GTEST_DEFINE_bool_(
-    catch_exceptions,
-    internal::BoolFromGTestEnv("catch_exceptions", true),
-    "True iff " GTEST_NAME_
-    " should catch exceptions and treat them as test failures.");
+GTEST_DEFINE_bool_(catch_exceptions,
+                   internal::BoolFromGTestEnv("catch_exceptions", true),
+                   "True if and only if " GTEST_NAME_
+                   " should catch exceptions and treat them as test failures.");
 
 GTEST_DEFINE_string_(
     color,
@@ -1747,16 +1772,16 @@
     "digits.");
 
 GTEST_DEFINE_bool_(
-    print_time,
-    internal::BoolFromGTestEnv("print_time", true),
-    "True iff " GTEST_NAME_
-    " should display elapsed time in text output.");
+    brief, internal::BoolFromGTestEnv("brief", false),
+    "True if only test failures should be displayed in text output.");
 
-GTEST_DEFINE_bool_(
-    print_utf8,
-    internal::BoolFromGTestEnv("print_utf8", true),
-    "True iff " GTEST_NAME_
-    " prints UTF8 characters as text.");
+GTEST_DEFINE_bool_(print_time, internal::BoolFromGTestEnv("print_time", true),
+                   "True if and only if " GTEST_NAME_
+                   " should display elapsed time in text output.");
+
+GTEST_DEFINE_bool_(print_utf8, internal::BoolFromGTestEnv("print_utf8", true),
+                   "True if and only if " GTEST_NAME_
+                   " prints UTF8 characters as text.");
 
 GTEST_DEFINE_int32_(
     random_seed,
@@ -1770,16 +1795,14 @@
     "How many times to repeat each test.  Specify a negative number "
     "for repeating forever.  Useful for shaking out flaky tests.");
 
-GTEST_DEFINE_bool_(
-    show_internal_stack_frames, false,
-    "True iff " GTEST_NAME_ " should include internal stack frames when "
-    "printing test failure stack traces.");
+GTEST_DEFINE_bool_(show_internal_stack_frames, false,
+                   "True if and only if " GTEST_NAME_
+                   " should include internal stack frames when "
+                   "printing test failure stack traces.");
 
-GTEST_DEFINE_bool_(
-    shuffle,
-    internal::BoolFromGTestEnv("shuffle", false),
-    "True iff " GTEST_NAME_
-    " should randomize tests' order on every run.");
+GTEST_DEFINE_bool_(shuffle, internal::BoolFromGTestEnv("shuffle", false),
+                   "True if and only if " GTEST_NAME_
+                   " should randomize tests' order on every run.");
 
 GTEST_DEFINE_int32_(
     stack_trace_depth,
@@ -1813,10 +1836,10 @@
 // Generates a random number from [0, range), using a Linear
 // Congruential Generator (LCG).  Crashes if 'range' is 0 or greater
 // than kMaxRange.
-UInt32 Random::Generate(UInt32 range) {
+uint32_t Random::Generate(uint32_t range) {
   // These constants are the same as are used in glibc's rand(3).
   // Use wider types than necessary to prevent unsigned overflow diagnostics.
-  state_ = static_cast<UInt32>(1103515245ULL*state_ + 12345U) % kMaxRange;
+  state_ = static_cast<uint32_t>(1103515245ULL*state_ + 12345U) % kMaxRange;
 
   GTEST_CHECK_(range > 0)
       << "Cannot generate a number in the range [0, 0).";
@@ -1830,7 +1853,7 @@
   return state_ % range;
 }
 
-// GTestIsInitialized() returns true iff the user has initialized
+// GTestIsInitialized() returns true if and only if the user has initialized
 // Google Test.  Useful for catching the user mistake of not initializing
 // Google Test before calling RUN_ALL_TESTS().
 static bool GTestIsInitialized() { return GetArgvs().size() > 0; }
@@ -1847,18 +1870,18 @@
   return sum;
 }
 
-// Returns true iff the test suite passed.
+// Returns true if and only if the test suite passed.
 static bool TestSuitePassed(const TestSuite* test_suite) {
   return test_suite->should_run() && test_suite->Passed();
 }
 
-// Returns true iff the test suite failed.
+// Returns true if and only if the test suite failed.
 static bool TestSuiteFailed(const TestSuite* test_suite) {
   return test_suite->should_run() && test_suite->Failed();
 }
 
-// Returns true iff test_suite contains at least one test that should
-// run.
+// Returns true if and only if test_suite contains at least one test that
+// should run.
 static bool ShouldRunTestSuite(const TestSuite* test_suite) {
   return test_suite->should_run();
 }
@@ -1886,6 +1909,162 @@
                       );  // NOLINT
 }
 
+namespace {
+
+// When TEST_P is found without a matching INSTANTIATE_TEST_SUITE_P
+// to creates test cases for it, a syntetic test case is
+// inserted to report ether an error or a log message.
+//
+// This configuration bit will likely be removed at some point.
+constexpr bool kErrorOnUninstantiatedParameterizedTest = true;
+constexpr bool kErrorOnUninstantiatedTypeParameterizedTest = true;
+
+// A test that fails at a given file/line location with a given message.
+class FailureTest : public Test {
+ public:
+  explicit FailureTest(const CodeLocation& loc, std::string error_message,
+                       bool as_error)
+      : loc_(loc),
+        error_message_(std::move(error_message)),
+        as_error_(as_error) {}
+
+  void TestBody() override {
+    if (as_error_) {
+      AssertHelper(TestPartResult::kNonFatalFailure, loc_.file.c_str(),
+                   loc_.line, "") = Message() << error_message_;
+    } else {
+      std::cout << error_message_ << std::endl;
+    }
+  }
+
+ private:
+  const CodeLocation loc_;
+  const std::string error_message_;
+  const bool as_error_;
+};
+
+
+}  // namespace
+
+std::set<std::string>* GetIgnoredParameterizedTestSuites() {
+  return UnitTest::GetInstance()->impl()->ignored_parameterized_test_suites();
+}
+
+// Add a given test_suit to the list of them allow to go un-instantiated.
+MarkAsIgnored::MarkAsIgnored(const char* test_suite) {
+  GetIgnoredParameterizedTestSuites()->insert(test_suite);
+}
+
+// If this parameterized test suite has no instantiations (and that
+// has not been marked as okay), emit a test case reporting that.
+void InsertSyntheticTestCase(const std::string& name, CodeLocation location,
+                             bool has_test_p) {
+  const auto& ignored = *GetIgnoredParameterizedTestSuites();
+  if (ignored.find(name) != ignored.end()) return;
+
+  const char kMissingInstantiation[] =  //
+      " is defined via TEST_P, but never instantiated. None of the test cases "
+      "will run. Either no INSTANTIATE_TEST_SUITE_P is provided or the only "
+      "ones provided expand to nothing."
+      "\n\n"
+      "Ideally, TEST_P definitions should only ever be included as part of "
+      "binaries that intend to use them. (As opposed to, for example, being "
+      "placed in a library that may be linked in to get other utilities.)";
+
+  const char kMissingTestCase[] =  //
+      " is instantiated via INSTANTIATE_TEST_SUITE_P, but no tests are "
+      "defined via TEST_P . No test cases will run."
+      "\n\n"
+      "Ideally, INSTANTIATE_TEST_SUITE_P should only ever be invoked from "
+      "code that always depend on code that provides TEST_P. Failing to do "
+      "so is often an indication of dead code, e.g. the last TEST_P was "
+      "removed but the rest got left behind.";
+
+  std::string message =
+      "Parameterized test suite " + name +
+      (has_test_p ? kMissingInstantiation : kMissingTestCase) +
+      "\n\n"
+      "To suppress this error for this test suite, insert the following line "
+      "(in a non-header) in the namespace it is defined in:"
+      "\n\n"
+      "GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(" + name + ");";
+
+  std::string full_name = "UninstantiatedParameterizedTestSuite<" + name + ">";
+  RegisterTest(  //
+      "GoogleTestVerification", full_name.c_str(),
+      nullptr,  // No type parameter.
+      nullptr,  // No value parameter.
+      location.file.c_str(), location.line, [message, location] {
+        return new FailureTest(location, message,
+                               kErrorOnUninstantiatedParameterizedTest);
+      });
+}
+
+void RegisterTypeParameterizedTestSuite(const char* test_suite_name,
+                                        CodeLocation code_location) {
+  GetUnitTestImpl()->type_parameterized_test_registry().RegisterTestSuite(
+      test_suite_name, code_location);
+}
+
+void RegisterTypeParameterizedTestSuiteInstantiation(const char* case_name) {
+  GetUnitTestImpl()
+      ->type_parameterized_test_registry()
+      .RegisterInstantiation(case_name);
+}
+
+void TypeParameterizedTestSuiteRegistry::RegisterTestSuite(
+    const char* test_suite_name, CodeLocation code_location) {
+  suites_.emplace(std::string(test_suite_name),
+                 TypeParameterizedTestSuiteInfo(code_location));
+}
+
+void TypeParameterizedTestSuiteRegistry::RegisterInstantiation(
+        const char* test_suite_name) {
+  auto it = suites_.find(std::string(test_suite_name));
+  if (it != suites_.end()) {
+    it->second.instantiated = true;
+  } else {
+    GTEST_LOG_(ERROR) << "Unknown type parameterized test suit '"
+                      << test_suite_name << "'";
+  }
+}
+
+void TypeParameterizedTestSuiteRegistry::CheckForInstantiations() {
+  const auto& ignored = *GetIgnoredParameterizedTestSuites();
+  for (const auto& testcase : suites_) {
+    if (testcase.second.instantiated) continue;
+    if (ignored.find(testcase.first) != ignored.end()) continue;
+
+    std::string message =
+        "Type parameterized test suite " + testcase.first +
+        " is defined via REGISTER_TYPED_TEST_SUITE_P, but never instantiated "
+        "via INSTANTIATE_TYPED_TEST_SUITE_P. None of the test cases will run."
+        "\n\n"
+        "Ideally, TYPED_TEST_P definitions should only ever be included as "
+        "part of binaries that intend to use them. (As opposed to, for "
+        "example, being placed in a library that may be linked in to get other "
+        "utilities.)"
+        "\n\n"
+        "To suppress this error for this test suite, insert the following line "
+        "(in a non-header) in the namespace it is defined in:"
+        "\n\n"
+        "GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(" +
+        testcase.first + ");";
+
+    std::string full_name =
+        "UninstantiatedTypeParameterizedTestSuite<" + testcase.first + ">";
+    RegisterTest(  //
+        "GoogleTestVerification", full_name.c_str(),
+        nullptr,  // No type parameter.
+        nullptr,  // No value parameter.
+        testcase.second.code_location.file.c_str(),
+        testcase.second.code_location.line, [message, testcase] {
+          return new FailureTest(testcase.second.code_location, message,
+                                 kErrorOnUninstantiatedTypeParameterizedTest);
+        });
+  }
+}
+
 // A copy of all command line arguments.  Set by InitGoogleTest().
 static ::std::vector<std::string> g_argvs;
 
@@ -1922,7 +2101,8 @@
   const char* const colon = strchr(gtest_output_flag, ':');
   return (colon == nullptr)
              ? std::string(gtest_output_flag)
-             : std::string(gtest_output_flag, colon - gtest_output_flag);
+             : std::string(gtest_output_flag,
+                           static_cast<size_t>(colon - gtest_output_flag));
 }
 
 // Returns the name of the requested output file, or the default if none
@@ -1957,51 +2137,86 @@
   return result.string();
 }
 
-// Returns true iff the wildcard pattern matches the string.  The
-// first ':' or '\0' character in pattern marks the end of it.
+// Returns true if and only if the wildcard pattern matches the string. Each
+// pattern consists of regular characters, single-character wildcards (?), and
+// multi-character wildcards (*).
 //
-// This recursive algorithm isn't very efficient, but is clear and
-// works well enough for matching test names, which are short.
-bool UnitTestOptions::PatternMatchesString(const char *pattern,
-                                           const char *str) {
-  switch (*pattern) {
-    case '\0':
-    case ':':  // Either ':' or '\0' marks the end of the pattern.
-      return *str == '\0';
-    case '?':  // Matches any single character.
-      return *str != '\0' && PatternMatchesString(pattern + 1, str + 1);
-    case '*':  // Matches any string (possibly empty) of characters.
-      return (*str != '\0' && PatternMatchesString(pattern, str + 1)) ||
-          PatternMatchesString(pattern + 1, str);
-    default:  // Non-special character.  Matches itself.
-      return *pattern == *str &&
-          PatternMatchesString(pattern + 1, str + 1);
+// This function implements a linear-time string globbing algorithm based on
+// https://research.swtch.com/glob.
+static bool PatternMatchesString(const std::string& name_str,
+                                 const char* pattern, const char* pattern_end) {
+  const char* name = name_str.c_str();
+  const char* const name_begin = name;
+  const char* const name_end = name + name_str.size();
+
+  const char* pattern_next = pattern;
+  const char* name_next = name;
+
+  while (pattern < pattern_end || name < name_end) {
+    if (pattern < pattern_end) {
+      switch (*pattern) {
+        default:  // Match an ordinary character.
+          if (name < name_end && *name == *pattern) {
+            ++pattern;
+            ++name;
+            continue;
+          }
+          break;
+        case '?':  // Match any single character.
+          if (name < name_end) {
+            ++pattern;
+            ++name;
+            continue;
+          }
+          break;
+        case '*':
+          // Match zero or more characters. Start by skipping over the wildcard
+          // and matching zero characters from name. If that fails, restart and
+          // match one more character than the last attempt.
+          pattern_next = pattern;
+          name_next = name + 1;
+          ++pattern;
+          continue;
+      }
+    }
+    // Failed to match a character. Restart if possible.
+    if (name_begin < name_next && name_next <= name_end) {
+      pattern = pattern_next;
+      name = name_next;
+      continue;
+    }
+    return false;
   }
+  return true;
 }
 
-bool UnitTestOptions::MatchesFilter(
-    const std::string& name, const char* filter) {
-  const char *cur_pattern = filter;
-  for (;;) {
-    if (PatternMatchesString(cur_pattern, name.c_str())) {
+bool UnitTestOptions::MatchesFilter(const std::string& name_str,
+                                    const char* filter) {
+  // The filter is a list of patterns separated by colons (:).
+  const char* pattern = filter;
+  while (true) {
+    // Find the bounds of this pattern.
+    const char* const next_sep = strchr(pattern, ':');
+    const char* const pattern_end =
+        next_sep != nullptr ? next_sep : pattern + strlen(pattern);
+
+    // Check if this pattern matches name_str.
+    if (PatternMatchesString(name_str, pattern, pattern_end)) {
       return true;
     }
 
-    // Finds the next pattern in the filter.
-    cur_pattern = strchr(cur_pattern, ':');
-
-    // Returns if no more pattern can be found.
-    if (cur_pattern == nullptr) {
+    // Give up on this pattern. However, if we found a pattern separator (:),
+    // advance to the next pattern (skipping over the separator) and restart.
+    if (next_sep == nullptr) {
       return false;
     }
-
-    // Skips the pattern separater (the ':' character).
-    cur_pattern++;
+    pattern = next_sep + 1;
   }
+  return true;
 }
 
-// Returns true iff the user-specified filter matches the test suite
-// name and the test name.
+// Returns true if and only if the user-specified filter matches the test
+// suite name and the test name.
 bool UnitTestOptions::FilterMatchesTest(const std::string& test_suite_name,
                                         const std::string& test_name) {
   const std::string& full_name = test_suite_name + "." + test_name.c_str();
@@ -2307,44 +2522,30 @@
       );  // NOLINT
 }
 
-// Returns the current time in milliseconds.
-TimeInMillis GetTimeInMillis() {
-#if GTEST_OS_WINDOWS_MOBILE || defined(__BORLANDC__)
-  // Difference between 1970-01-01 and 1601-01-01 in milliseconds.
-  // http://analogous.blogspot.com/2005/04/epoch.html
-  const TimeInMillis kJavaEpochToWinFileTimeDelta =
-    static_cast<TimeInMillis>(116444736UL) * 100000UL;
-  const DWORD kTenthMicrosInMilliSecond = 10000;
+// A helper class for measuring elapsed times.
+class Timer {
+ public:
+  Timer() : start_(std::chrono::steady_clock::now()) {}
 
-  SYSTEMTIME now_systime;
-  FILETIME now_filetime;
-  ULARGE_INTEGER now_int64;
-  GetSystemTime(&now_systime);
-  if (SystemTimeToFileTime(&now_systime, &now_filetime)) {
-    now_int64.LowPart = now_filetime.dwLowDateTime;
-    now_int64.HighPart = now_filetime.dwHighDateTime;
-    now_int64.QuadPart = (now_int64.QuadPart / kTenthMicrosInMilliSecond) -
-      kJavaEpochToWinFileTimeDelta;
-    return now_int64.QuadPart;
+  // Return time elapsed in milliseconds since the timer was created.
+  TimeInMillis Elapsed() {
+    return std::chrono::duration_cast<std::chrono::milliseconds>(
+               std::chrono::steady_clock::now() - start_)
+        .count();
   }
-  return 0;
-#elif GTEST_OS_WINDOWS && !GTEST_HAS_GETTIMEOFDAY_
-  __timeb64 now;
 
-  // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996
-  // (deprecated function) there.
-  GTEST_DISABLE_MSC_DEPRECATED_PUSH_()
-  _ftime64(&now);
-  GTEST_DISABLE_MSC_DEPRECATED_POP_()
+ private:
+  std::chrono::steady_clock::time_point start_;
+};
 
-  return static_cast<TimeInMillis>(now.time) * 1000 + now.millitm;
-#elif GTEST_HAS_GETTIMEOFDAY_
-  struct timeval now;
-  gettimeofday(&now, nullptr);
-  return static_cast<TimeInMillis>(now.tv_sec) * 1000 + now.tv_usec / 1000;
-#else
-# error "Don't know how to get the current time on your system."
-#endif
+// Returns a timestamp as milliseconds since the epoch. Note this time may jump
+// around subject to adjustments by the system, to measure elapsed time use
+// Timer instead.
+TimeInMillis GetTimeInMillis() {
+  return std::chrono::duration_cast<std::chrono::milliseconds>(
+             std::chrono::system_clock::now() -
+             std::chrono::system_clock::from_time_t(0))
+      .count();
 }
 
 // Utilities
@@ -2385,7 +2586,8 @@
 
 #endif  // GTEST_OS_WINDOWS_MOBILE
 
-// Compares two C strings.  Returns true iff they have the same content.
+// Compares two C strings.  Returns true if and only if they have the same
+// content.
 //
 // Unlike strcmp(), this function can handle NULL argument(s).  A NULL
 // C string is considered different to any non-NULL C string,
@@ -2398,7 +2600,7 @@
   return strcmp(lhs, rhs) == 0;
 }
 
-#if GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING
+#if GTEST_HAS_STD_WSTRING
 
 // Converts an array of wide chars to a narrow string using the UTF-8
 // encoding, and streams the result to the given Message object.
@@ -2416,7 +2618,7 @@
   }
 }
 
-#endif  // GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING
+#endif  // GTEST_HAS_STD_WSTRING
 
 void SplitString(const ::std::string& str, char delimiter,
                  ::std::vector< ::std::string>* dest) {
@@ -2466,15 +2668,6 @@
 }
 #endif  // GTEST_HAS_STD_WSTRING
 
-#if GTEST_HAS_GLOBAL_WSTRING
-// Converts the given wide string to a narrow string using the UTF-8
-// encoding, and streams the result to this Message object.
-Message& Message::operator <<(const ::wstring& wstr) {
-  internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this);
-  return *this;
-}
-#endif  // GTEST_HAS_GLOBAL_WSTRING
-
 // Gets the text streamed to this object so far as an std::string.
 // Each '\0' character in the buffer is replaced with "\\0".
 std::string Message::GetString() const {
@@ -2725,9 +2918,10 @@
     for (; edit_i < edits.size(); ++edit_i) {
       if (n_suffix >= context) {
         // Continue only if the next hunk is very close.
-        std::vector<EditType>::const_iterator it = edits.begin() + edit_i;
+        auto it = edits.begin() + static_cast<int>(edit_i);
         while (it != edits.end() && *it == kMatch) ++it;
-        if (it == edits.end() || (it - edits.begin()) - edit_i >= context) {
+        if (it == edits.end() ||
+            static_cast<size_t>(it - edits.begin()) - edit_i >= context) {
           // There is no next edit or it is too far away.
           break;
         }
@@ -2803,7 +2997,7 @@
 //   lhs_value:      "5"
 //   rhs_value:      "6"
 //
-// The ignoring_case parameter is true iff the assertion is a
+// The ignoring_case parameter is true if and only if the assertion is a
 // *_STRCASEEQ*.  When it's true, the string "Ignoring case" will
 // be inserted into the message.
 AssertionResult EqFailure(const char* lhs_expression,
@@ -2866,6 +3060,31 @@
   const double diff = fabs(val1 - val2);
   if (diff <= abs_error) return AssertionSuccess();
 
+  // Find the value which is closest to zero.
+  const double min_abs = std::min(fabs(val1), fabs(val2));
+  // Find the distance to the next double from that value.
+  const double epsilon =
+      nextafter(min_abs, std::numeric_limits<double>::infinity()) - min_abs;
+  // Detect the case where abs_error is so small that EXPECT_NEAR is
+  // effectively the same as EXPECT_EQUAL, and give an informative error
+  // message so that the situation can be more easily understood without
+  // requiring exotic floating-point knowledge.
+  // Don't do an epsilon check if abs_error is zero because that implies
+  // that an equality check was actually intended.
+  if (!(std::isnan)(val1) && !(std::isnan)(val2) && abs_error > 0 &&
+      abs_error < epsilon) {
+    return AssertionFailure()
+           << "The difference between " << expr1 << " and " << expr2 << " is "
+           << diff << ", where\n"
+           << expr1 << " evaluates to " << val1 << ",\n"
+           << expr2 << " evaluates to " << val2 << ".\nThe abs_error parameter "
+           << abs_error_expr << " evaluates to " << abs_error
+           << " which is smaller than the minimum distance between doubles for "
+              "numbers of this magnitude which is "
+           << epsilon
+           << ", thus making this EXPECT_NEAR check equivalent to "
+              "EXPECT_EQUAL. Consider using EXPECT_DOUBLE_EQ instead.";
+  }
   return AssertionFailure()
       << "The difference between " << expr1 << " and " << expr2
       << " is " << diff << ", which exceeds " << abs_error_expr << ", where\n"
@@ -2928,57 +3147,6 @@
 
 namespace internal {
 
-// The helper function for {ASSERT|EXPECT}_EQ with int or enum
-// arguments.
-AssertionResult CmpHelperEQ(const char* lhs_expression,
-                            const char* rhs_expression,
-                            BiggestInt lhs,
-                            BiggestInt rhs) {
-  if (lhs == rhs) {
-    return AssertionSuccess();
-  }
-
-  return EqFailure(lhs_expression,
-                   rhs_expression,
-                   FormatForComparisonFailureMessage(lhs, rhs),
-                   FormatForComparisonFailureMessage(rhs, lhs),
-                   false);
-}
-
-// A macro for implementing the helper functions needed to implement
-// ASSERT_?? and EXPECT_?? with integer or enum arguments.  It is here
-// just to avoid copy-and-paste of similar code.
-#define GTEST_IMPL_CMP_HELPER_(op_name, op)\
-AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \
-                                   BiggestInt val1, BiggestInt val2) {\
-  if (val1 op val2) {\
-    return AssertionSuccess();\
-  } else {\
-    return AssertionFailure() \
-        << "Expected: (" << expr1 << ") " #op " (" << expr2\
-        << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\
-        << " vs " << FormatForComparisonFailureMessage(val2, val1);\
-  }\
-}
-
-// Implements the helper function for {ASSERT|EXPECT}_NE with int or
-// enum arguments.
-GTEST_IMPL_CMP_HELPER_(NE, !=)
-// Implements the helper function for {ASSERT|EXPECT}_LE with int or
-// enum arguments.
-GTEST_IMPL_CMP_HELPER_(LE, <=)
-// Implements the helper function for {ASSERT|EXPECT}_LT with int or
-// enum arguments.
-GTEST_IMPL_CMP_HELPER_(LT, < )
-// Implements the helper function for {ASSERT|EXPECT}_GE with int or
-// enum arguments.
-GTEST_IMPL_CMP_HELPER_(GE, >=)
-// Implements the helper function for {ASSERT|EXPECT}_GT with int or
-// enum arguments.
-GTEST_IMPL_CMP_HELPER_(GT, > )
-
-#undef GTEST_IMPL_CMP_HELPER_
-
 // The helper function for {ASSERT|EXPECT}_STREQ.
 AssertionResult CmpHelperSTREQ(const char* lhs_expression,
                                const char* rhs_expression,
@@ -3046,9 +3214,9 @@
 
 // Helper functions for implementing IsSubString() and IsNotSubstring().
 
-// This group of overloaded functions return true iff needle is a
-// substring of haystack.  NULL is considered a substring of itself
-// only.
+// This group of overloaded functions return true if and only if needle
+// is a substring of haystack.  NULL is considered a substring of
+// itself only.
 
 bool IsSubstringPred(const char* needle, const char* haystack) {
   if (needle == nullptr || haystack == nullptr) return needle == haystack;
@@ -3174,7 +3342,7 @@
   char error_text[kBufSize] = { '\0' };
   DWORD message_length = ::FormatMessageA(kFlags,
                                           0,   // no source, we're asking system
-                                          hr,  // the error
+                                          static_cast<DWORD>(hr),  // the error
                                           0,   // no line width restrictions
                                           error_text,  // output buffer
                                           kBufSize,    // buf size
@@ -3224,35 +3392,35 @@
 //  17 - 21 bits       11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
 
 // The maximum code-point a one-byte UTF-8 sequence can represent.
-const UInt32 kMaxCodePoint1 = (static_cast<UInt32>(1) <<  7) - 1;
+constexpr uint32_t kMaxCodePoint1 = (static_cast<uint32_t>(1) <<  7) - 1;
 
 // The maximum code-point a two-byte UTF-8 sequence can represent.
-const UInt32 kMaxCodePoint2 = (static_cast<UInt32>(1) << (5 + 6)) - 1;
+constexpr uint32_t kMaxCodePoint2 = (static_cast<uint32_t>(1) << (5 + 6)) - 1;
 
 // The maximum code-point a three-byte UTF-8 sequence can represent.
-const UInt32 kMaxCodePoint3 = (static_cast<UInt32>(1) << (4 + 2*6)) - 1;
+constexpr uint32_t kMaxCodePoint3 = (static_cast<uint32_t>(1) << (4 + 2*6)) - 1;
 
 // The maximum code-point a four-byte UTF-8 sequence can represent.
-const UInt32 kMaxCodePoint4 = (static_cast<UInt32>(1) << (3 + 3*6)) - 1;
+constexpr uint32_t kMaxCodePoint4 = (static_cast<uint32_t>(1) << (3 + 3*6)) - 1;
 
 // Chops off the n lowest bits from a bit pattern.  Returns the n
 // lowest bits.  As a side effect, the original bit pattern will be
 // shifted to the right by n bits.
-inline UInt32 ChopLowBits(UInt32* bits, int n) {
-  const UInt32 low_bits = *bits & ((static_cast<UInt32>(1) << n) - 1);
+inline uint32_t ChopLowBits(uint32_t* bits, int n) {
+  const uint32_t low_bits = *bits & ((static_cast<uint32_t>(1) << n) - 1);
   *bits >>= n;
   return low_bits;
 }
 
 // Converts a Unicode code point to a narrow string in UTF-8 encoding.
-// code_point parameter is of type UInt32 because wchar_t may not be
+// code_point parameter is of type uint32_t because wchar_t may not be
 // wide enough to contain a code point.
 // If the code_point is not a valid Unicode code point
 // (i.e. outside of Unicode range U+0 to U+10FFFF) it will be converted
 // to "(Invalid Unicode 0xXXXXXXXX)".
-std::string CodePointToUtf8(UInt32 code_point) {
+std::string CodePointToUtf8(uint32_t code_point) {
   if (code_point > kMaxCodePoint4) {
-    return "(Invalid Unicode 0x" + String::FormatHexInt(code_point) + ")";
+    return "(Invalid Unicode 0x" + String::FormatHexUInt32(code_point) + ")";
   }
 
   char str[5];  // Big enough for the largest valid code point.
@@ -3291,14 +3459,17 @@
 }
 
 // Creates a Unicode code point from UTF16 surrogate pair.
-inline UInt32 CreateCodePointFromUtf16SurrogatePair(wchar_t first,
-                                                    wchar_t second) {
-  const UInt32 mask = (1 << 10) - 1;
-  return (sizeof(wchar_t) == 2) ?
-      (((first & mask) << 10) | (second & mask)) + 0x10000 :
-      // This function should not be called when the condition is
-      // false, but we provide a sensible default in case it is.
-      static_cast<UInt32>(first);
+inline uint32_t CreateCodePointFromUtf16SurrogatePair(wchar_t first,
+                                                      wchar_t second) {
+  const auto first_u = static_cast<uint32_t>(first);
+  const auto second_u = static_cast<uint32_t>(second);
+  const uint32_t mask = (1 << 10) - 1;
+  return (sizeof(wchar_t) == 2)
+             ? (((first_u & mask) << 10) | (second_u & mask)) + 0x10000
+             :
+             // This function should not be called when the condition is
+             // false, but we provide a sensible default in case it is.
+             first_u;
 }
 
 // Converts a wide string to a narrow string in UTF-8 encoding.
@@ -3320,7 +3491,7 @@
 
   ::std::stringstream stream;
   for (int i = 0; i < num_chars; ++i) {
-    UInt32 unicode_code_point;
+    uint32_t unicode_code_point;
 
     if (str[i] == L'\0') {
       break;
@@ -3329,7 +3500,7 @@
                                                                  str[i + 1]);
       i++;
     } else {
-      unicode_code_point = static_cast<UInt32>(str[i]);
+      unicode_code_point = static_cast<uint32_t>(str[i]);
     }
 
     stream << CodePointToUtf8(unicode_code_point);
@@ -3345,8 +3516,8 @@
   return internal::WideStringToUtf8(wide_c_str, -1);
 }
 
-// Compares two wide C strings.  Returns true iff they have the same
-// content.
+// Compares two wide C strings.  Returns true if and only if they have the
+// same content.
 //
 // Unlike wcscmp(), this function can handle NULL argument(s).  A NULL
 // C string is considered different to any non-NULL C string,
@@ -3390,7 +3561,7 @@
                             << " vs " << PrintToString(s2);
 }
 
-// Compares two C strings, ignoring case.  Returns true iff they have
+// Compares two C strings, ignoring case.  Returns true if and only if they have
 // the same content.
 //
 // Unlike strcasecmp(), this function can handle NULL argument(s).  A
@@ -3402,18 +3573,18 @@
   return posix::StrCaseCmp(lhs, rhs) == 0;
 }
 
-  // Compares two wide C strings, ignoring case.  Returns true iff they
-  // have the same content.
-  //
-  // Unlike wcscasecmp(), this function can handle NULL argument(s).
-  // A NULL C string is considered different to any non-NULL wide C string,
-  // including the empty string.
-  // NB: The implementations on different platforms slightly differ.
-  // On windows, this method uses _wcsicmp which compares according to LC_CTYPE
-  // environment variable. On GNU platform this method uses wcscasecmp
-  // which compares according to LC_CTYPE category of the current locale.
-  // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the
-  // current locale.
+// Compares two wide C strings, ignoring case.  Returns true if and only if they
+// have the same content.
+//
+// Unlike wcscasecmp(), this function can handle NULL argument(s).
+// A NULL C string is considered different to any non-NULL wide C string,
+// including the empty string.
+// NB: The implementations on different platforms slightly differ.
+// On windows, this method uses _wcsicmp which compares according to LC_CTYPE
+// environment variable. On GNU platform this method uses wcscasecmp
+// which compares according to LC_CTYPE category of the current locale.
+// On MacOS X, it uses towlower, which also uses LC_CTYPE category of the
+// current locale.
 bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs,
                                               const wchar_t* rhs) {
   if (lhs == nullptr) return rhs == nullptr;
@@ -3429,14 +3600,14 @@
   // Other unknown OSes may not define it either.
   wint_t left, right;
   do {
-    left = towlower(*lhs++);
-    right = towlower(*rhs++);
+    left = towlower(static_cast<wint_t>(*lhs++));
+    right = towlower(static_cast<wint_t>(*rhs++));
   } while (left && left == right);
   return left == right;
 #endif  // OS selector
 }
 
-// Returns true iff str ends with the given suffix, ignoring case.
+// Returns true if and only if str ends with the given suffix, ignoring case.
 // Any string is considered to end with an empty suffix.
 bool String::EndsWithCaseInsensitive(
     const std::string& str, const std::string& suffix) {
@@ -3449,16 +3620,26 @@
 
 // Formats an int value as "%02d".
 std::string String::FormatIntWidth2(int value) {
+  return FormatIntWidthN(value, 2);
+}
+
+// Formats an int value to given width with leading zeros.
+std::string String::FormatIntWidthN(int value, int width) {
   std::stringstream ss;
-  ss << std::setfill('0') << std::setw(2) << value;
+  ss << std::setfill('0') << std::setw(width) << value;
+  return ss.str();
+}
+
+// Formats an int value as "%X".
+std::string String::FormatHexUInt32(uint32_t value) {
+  std::stringstream ss;
+  ss << std::hex << std::uppercase << value;
   return ss.str();
 }
 
 // Formats an int value as "%X".
 std::string String::FormatHexInt(int value) {
-  std::stringstream ss;
-  ss << std::hex << std::uppercase << value;
-  return ss.str();
+  return FormatHexUInt32(static_cast<uint32_t>(value));
 }
 
 // Formats a byte as "%02X".
@@ -3477,7 +3658,7 @@
   const char* const end = start + str.length();
 
   std::string result;
-  result.reserve(2 * (end - start));
+  result.reserve(static_cast<size_t>(2 * (end - start)));
   for (const char* ch = start; ch != end; ++ch) {
     if (*ch == '\0') {
       result += "\\0";  // Replaces NUL with "\\0";
@@ -3497,7 +3678,9 @@
   if (user_msg_string.empty()) {
     return gtest_msg;
   }
-
+  if (gtest_msg.empty()) {
+    return user_msg_string;
+  }
   return gtest_msg + "\n" + user_msg_string;
 }
 
@@ -3507,9 +3690,7 @@
 
 // Creates an empty TestResult.
 TestResult::TestResult()
-    : death_test_count_(0),
-      elapsed_time_(0) {
-}
+    : death_test_count_(0), start_timestamp_(0), elapsed_time_(0) {}
 
 // D'tor.
 TestResult::~TestResult() {
@@ -3521,7 +3702,7 @@
 const TestPartResult& TestResult::GetTestPartResult(int i) const {
   if (i < 0 || i >= total_part_count())
     internal::posix::Abort();
-  return test_part_results_.at(i);
+  return test_part_results_.at(static_cast<size_t>(i));
 }
 
 // Returns the i-th test property. i can range from 0 to
@@ -3530,7 +3711,7 @@
 const TestProperty& TestResult::GetTestProperty(int i) const {
   if (i < 0 || i >= test_property_count())
     internal::posix::Abort();
-  return test_properties_.at(i);
+  return test_properties_.at(static_cast<size_t>(i));
 }
 
 // Clears the test part results.
@@ -3551,7 +3732,7 @@
   if (!ValidateTestProperty(xml_element, test_property)) {
     return;
   }
-  internal::MutexLock lock(&test_properites_mutex_);
+  internal::MutexLock lock(&test_properties_mutex_);
   const std::vector<TestProperty>::iterator property_with_matching_key =
       std::find_if(test_properties_.begin(), test_properties_.end(),
                    internal::TestPropertyKeyIs(test_property.key()));
@@ -3578,20 +3759,21 @@
 // The list of reserved attributes used in the <testsuite> element of XML
 // output.
 static const char* const kReservedTestSuiteAttributes[] = {
-  "disabled",
-  "errors",
-  "failures",
-  "name",
-  "tests",
-  "time"
-};
+    "disabled", "errors", "failures",  "name",
+    "tests",    "time",   "timestamp", "skipped"};
 
 // The list of reserved attributes used in the <testcase> element of XML output.
 static const char* const kReservedTestCaseAttributes[] = {
-    "classname",  "name",        "status", "time",
-    "type_param", "value_param", "file",   "line"};
+    "classname",   "name", "status", "time",  "type_param",
+    "value_param", "file", "line"};
 
-template <int kSize>
+// Use a slightly different set for allowed output to ensure existing tests can
+// still RecordProperty("result") or "RecordProperty(timestamp")
+static const char* const kReservedOutputTestCaseAttributes[] = {
+    "classname",   "name", "status", "time",   "type_param",
+    "value_param", "file", "line",   "result", "timestamp"};
+
+template <size_t kSize>
 std::vector<std::string> ArrayAsVector(const char* const (&array)[kSize]) {
   return std::vector<std::string>(array, array + kSize);
 }
@@ -3611,6 +3793,22 @@
   return std::vector<std::string>();
 }
 
+// TODO(jdesprez): Merge the two getReserved attributes once skip is improved
+static std::vector<std::string> GetReservedOutputAttributesForElement(
+    const std::string& xml_element) {
+  if (xml_element == "testsuites") {
+    return ArrayAsVector(kReservedTestSuitesAttributes);
+  } else if (xml_element == "testsuite") {
+    return ArrayAsVector(kReservedTestSuiteAttributes);
+  } else if (xml_element == "testcase") {
+    return ArrayAsVector(kReservedOutputTestCaseAttributes);
+  } else {
+    GTEST_CHECK_(false) << "Unrecognized xml_element provided: " << xml_element;
+  }
+  // This code is unreachable but some compilers may not realizes that.
+  return std::vector<std::string>();
+}
+
 static std::string FormatWordList(const std::vector<std::string>& words) {
   Message word_list;
   for (size_t i = 0; i < words.size(); ++i) {
@@ -3659,12 +3857,12 @@
   return result.skipped();
 }
 
-// Returns true iff the test was skipped.
+// Returns true if and only if the test was skipped.
 bool TestResult::Skipped() const {
   return !Failed() && CountIf(test_part_results_, TestPartSkipped) > 0;
 }
 
-// Returns true iff the test failed.
+// Returns true if and only if the test failed.
 bool TestResult::Failed() const {
   for (int i = 0; i < total_part_count(); ++i) {
     if (GetTestPartResult(i).failed())
@@ -3673,22 +3871,22 @@
   return false;
 }
 
-// Returns true iff the test part fatally failed.
+// Returns true if and only if the test part fatally failed.
 static bool TestPartFatallyFailed(const TestPartResult& result) {
   return result.fatally_failed();
 }
 
-// Returns true iff the test fatally failed.
+// Returns true if and only if the test fatally failed.
 bool TestResult::HasFatalFailure() const {
   return CountIf(test_part_results_, TestPartFatallyFailed) > 0;
 }
 
-// Returns true iff the test part non-fatally failed.
+// Returns true if and only if the test part non-fatally failed.
 static bool TestPartNonfatallyFailed(const TestPartResult& result) {
   return result.nonfatally_failed();
 }
 
-// Returns true iff the test has a non-fatal failure.
+// Returns true if and only if the test has a non-fatal failure.
 bool TestResult::HasNonfatalFailure() const {
   return CountIf(test_part_results_, TestPartNonfatallyFailed) > 0;
 }
@@ -3984,18 +4182,18 @@
       this, &Test::TearDown, "TearDown()");
 }
 
-// Returns true iff the current test has a fatal failure.
+// Returns true if and only if the current test has a fatal failure.
 bool Test::HasFatalFailure() {
   return internal::GetUnitTestImpl()->current_test_result()->HasFatalFailure();
 }
 
-// Returns true iff the current test has a non-fatal failure.
+// Returns true if and only if the current test has a non-fatal failure.
 bool Test::HasNonfatalFailure() {
   return internal::GetUnitTestImpl()->current_test_result()->
       HasNonfatalFailure();
 }
 
-// Returns true iff the current test was skipped.
+// Returns true if and only if the current test was skipped.
 bool Test::IsSkipped() {
   return internal::GetUnitTestImpl()->current_test_result()->Skipped();
 }
@@ -4019,6 +4217,7 @@
       should_run_(false),
       is_disabled_(false),
       matches_filter_(false),
+      is_in_another_shard_(false),
       factory_(factory),
       result_() {}
 
@@ -4032,7 +4231,7 @@
 //
 // Arguments:
 //
-//   test_suite_name:   name of the test suite
+//   test_suite_name:  name of the test suite
 //   name:             name of the test
 //   type_param:       the name of the test's type parameter, or NULL if
 //                     this is not a typed or a type-parameterized test.
@@ -4094,7 +4293,7 @@
   explicit TestNameIs(const char* name)
       : name_(name) {}
 
-  // Returns true iff the test name of test_info matches name_.
+  // Returns true if and only if the test name of test_info matches name_.
   bool operator()(const TestInfo * test_info) const {
     return test_info && test_info->name() == name_;
   }
@@ -4113,6 +4312,7 @@
 void UnitTestImpl::RegisterParameterizedTests() {
   if (!parameterized_tests_registered_) {
     parameterized_test_registry_.RegisterTests();
+    type_parameterized_test_registry_.CheckForInstantiations();
     parameterized_tests_registered_ = true;
   }
 }
@@ -4133,7 +4333,8 @@
   // Notifies the unit test event listeners that a test is about to start.
   repeater->OnTestStart(*this);
 
-  const TimeInMillis start = internal::GetTimeInMillis();
+  result_.set_start_timestamp(internal::GetTimeInMillis());
+  internal::Timer timer;
 
   impl->os_stack_trace_getter()->UponLeavingGTest();
 
@@ -4158,7 +4359,7 @@
         test, &Test::DeleteSelf_, "the test fixture's destructor");
   }
 
-  result_.set_elapsed_time(internal::GetTimeInMillis() - start);
+  result_.set_elapsed_time(timer.Elapsed());
 
   // Notifies the unit test event listener that a test has just finished.
   repeater->OnTestEnd(*this);
@@ -4168,6 +4369,28 @@
   impl->set_current_test_info(nullptr);
 }
 
+// Skip and records a skipped test result for this object.
+void TestInfo::Skip() {
+  if (!should_run_) return;
+
+  internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+  impl->set_current_test_info(this);
+
+  TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater();
+
+  // Notifies the unit test event listeners that a test is about to start.
+  repeater->OnTestStart(*this);
+
+  const TestPartResult test_part_result =
+      TestPartResult(TestPartResult::kSkip, this->file(), this->line(), "");
+  impl->GetTestPartResultReporterForCurrentThread()->ReportTestPartResult(
+      test_part_result);
+
+  // Notifies the unit test event listener that a test has just finished.
+  repeater->OnTestEnd(*this);
+  impl->set_current_test_info(nullptr);
+}
+
 // class TestSuite
 
 // Gets the number of successful tests in this test suite.
@@ -4214,7 +4437,7 @@
 //
 // Arguments:
 //
-//   name:         name of the test suite
+//   a_name:       name of the test suite
 //   a_type_param: the name of the test suite's type parameter, or NULL if
 //                 this is not a typed or a type-parameterized test suite.
 //   set_up_tc:    pointer to the function that sets up the test suite
@@ -4227,6 +4450,7 @@
       set_up_tc_(set_up_tc),
       tear_down_tc_(tear_down_tc),
       should_run_(false),
+      start_timestamp_(0),
       elapsed_time_(0) {}
 
 // Destructor of TestSuite.
@@ -4239,14 +4463,14 @@
 // total_test_count() - 1. If i is not in that range, returns NULL.
 const TestInfo* TestSuite::GetTestInfo(int i) const {
   const int index = GetElementOr(test_indices_, i, -1);
-  return index < 0 ? nullptr : test_info_list_[index];
+  return index < 0 ? nullptr : test_info_list_[static_cast<size_t>(index)];
 }
 
 // Returns the i-th test among all the tests. i can range from 0 to
 // total_test_count() - 1. If i is not in that range, returns NULL.
 TestInfo* TestSuite::GetMutableTestInfo(int i) {
   const int index = GetElementOr(test_indices_, i, -1);
-  return index < 0 ? nullptr : test_info_list_[index];
+  return index < 0 ? nullptr : test_info_list_[static_cast<size_t>(index)];
 }
 
 // Adds a test to this test suite.  Will delete the test upon
@@ -4268,19 +4492,26 @@
   // Call both legacy and the new API
   repeater->OnTestSuiteStart(*this);
 //  Legacy API is deprecated but still available
-#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
   repeater->OnTestCaseStart(*this);
-#endif  //  GTEST_REMOVE_LEGACY_TEST_CASEAPI
+#endif  //  GTEST_REMOVE_LEGACY_TEST_CASEAPI_
 
   impl->os_stack_trace_getter()->UponLeavingGTest();
   internal::HandleExceptionsInMethodIfSupported(
       this, &TestSuite::RunSetUpTestSuite, "SetUpTestSuite()");
 
-  const internal::TimeInMillis start = internal::GetTimeInMillis();
+  start_timestamp_ = internal::GetTimeInMillis();
+  internal::Timer timer;
   for (int i = 0; i < total_test_count(); i++) {
     GetMutableTestInfo(i)->Run();
+    if (GTEST_FLAG(fail_fast) && GetMutableTestInfo(i)->result()->Failed()) {
+      for (int j = i + 1; j < total_test_count(); j++) {
+        GetMutableTestInfo(j)->Skip();
+      }
+      break;
+    }
   }
-  elapsed_time_ = internal::GetTimeInMillis() - start;
+  elapsed_time_ = timer.Elapsed();
 
   impl->os_stack_trace_getter()->UponLeavingGTest();
   internal::HandleExceptionsInMethodIfSupported(
@@ -4289,9 +4520,39 @@
   // Call both legacy and the new API
   repeater->OnTestSuiteEnd(*this);
 //  Legacy API is deprecated but still available
-#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
   repeater->OnTestCaseEnd(*this);
-#endif  //  GTEST_REMOVE_LEGACY_TEST_CASEAPI
+#endif  //  GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+  impl->set_current_test_suite(nullptr);
+}
+
+// Skips all tests under this TestSuite.
+void TestSuite::Skip() {
+  if (!should_run_) return;
+
+  internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+  impl->set_current_test_suite(this);
+
+  TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater();
+
+  // Call both legacy and the new API
+  repeater->OnTestSuiteStart(*this);
+//  Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+  repeater->OnTestCaseStart(*this);
+#endif  //  GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+  for (int i = 0; i < total_test_count(); i++) {
+    GetMutableTestInfo(i)->Skip();
+  }
+
+  // Call both legacy and the new API
+  repeater->OnTestSuiteEnd(*this);
+  // Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+  repeater->OnTestCaseEnd(*this);
+#endif  //  GTEST_REMOVE_LEGACY_TEST_CASEAPI_
 
   impl->set_current_test_suite(nullptr);
 }
@@ -4343,7 +4604,7 @@
 static const char * TestPartResultTypeToString(TestPartResult::Type type) {
   switch (type) {
     case TestPartResult::kSkip:
-      return "Skipped";
+      return "Skipped\n";
     case TestPartResult::kSuccess:
       return "Success";
 
@@ -4360,6 +4621,9 @@
 }
 
 namespace internal {
+namespace {
+enum class GTestColor { kDefault, kRed, kGreen, kYellow };
+}  // namespace
 
 // Prints a TestPartResult to an std::string.
 static std::string PrintTestPartResultToString(
@@ -4397,9 +4661,12 @@
 // Returns the character attribute for the given color.
 static WORD GetColorAttribute(GTestColor color) {
   switch (color) {
-    case COLOR_RED:    return FOREGROUND_RED;
-    case COLOR_GREEN:  return FOREGROUND_GREEN;
-    case COLOR_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN;
+    case GTestColor::kRed:
+      return FOREGROUND_RED;
+    case GTestColor::kGreen:
+      return FOREGROUND_GREEN;
+    case GTestColor::kYellow:
+      return FOREGROUND_RED | FOREGROUND_GREEN;
     default:           return 0;
   }
 }
@@ -4437,21 +4704,24 @@
 
 #else
 
-// Returns the ANSI color code for the given color.  COLOR_DEFAULT is
+// Returns the ANSI color code for the given color. GTestColor::kDefault is
 // an invalid input.
 static const char* GetAnsiColorCode(GTestColor color) {
   switch (color) {
-    case COLOR_RED:     return "1";
-    case COLOR_GREEN:   return "2";
-    case COLOR_YELLOW:  return "3";
+    case GTestColor::kRed:
+      return "1";
+    case GTestColor::kGreen:
+      return "2";
+    case GTestColor::kYellow:
+      return "3";
     default:
       return nullptr;
-  };
+  }
 }
 
 #endif  // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE
 
-// Returns true iff Google Test should use colors in the output.
+// Returns true if and only if Google Test should use colors in the output.
 bool ShouldUseColor(bool stdout_is_tty) {
   const char* const gtest_color = GTEST_FLAG(color).c_str();
 
@@ -4492,17 +4762,19 @@
 // cannot simply emit special characters and have the terminal change colors.
 // This routine must actually emit the characters rather than return a string
 // that would be colored when printed, as can be done on Linux.
-void ColoredPrintf(GTestColor color, const char* fmt, ...) {
+
+GTEST_ATTRIBUTE_PRINTF_(2, 3)
+static void ColoredPrintf(GTestColor color, const char *fmt, ...) {
   va_list args;
   va_start(args, fmt);
 
 #if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_ZOS || GTEST_OS_IOS || \
-    GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT
+    GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT || defined(ESP_PLATFORM)
   const bool use_color = AlwaysFalse();
 #else
   static const bool in_color_mode =
       ShouldUseColor(posix::IsATTY(posix::FileNo(stdout)) != 0);
-  const bool use_color = in_color_mode && (color != COLOR_DEFAULT);
+  const bool use_color = in_color_mode && (color != GTestColor::kDefault);
 #endif  // GTEST_OS_WINDOWS_MOBILE || GTEST_OS_ZOS
 
   if (!use_color) {
@@ -4576,11 +4848,22 @@
   void OnTestIterationStart(const UnitTest& unit_test, int iteration) override;
   void OnEnvironmentsSetUpStart(const UnitTest& unit_test) override;
   void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) override {}
-  void OnTestCaseStart(const TestSuite& test_suite) override;
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+  void OnTestCaseStart(const TestCase& test_case) override;
+#else
+  void OnTestSuiteStart(const TestSuite& test_suite) override;
+#endif  // OnTestCaseStart
+
   void OnTestStart(const TestInfo& test_info) override;
+
   void OnTestPartResult(const TestPartResult& result) override;
   void OnTestEnd(const TestInfo& test_info) override;
-  void OnTestCaseEnd(const TestSuite& test_suite) override;
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+  void OnTestCaseEnd(const TestCase& test_case) override;
+#else
+  void OnTestSuiteEnd(const TestSuite& test_suite) override;
+#endif  // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
   void OnEnvironmentsTearDownStart(const UnitTest& unit_test) override;
   void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) override {}
   void OnTestIterationEnd(const UnitTest& unit_test, int iteration) override;
@@ -4588,6 +4871,7 @@
 
  private:
   static void PrintFailedTests(const UnitTest& unit_test);
+  static void PrintFailedTestSuites(const UnitTest& unit_test);
   static void PrintSkippedTests(const UnitTest& unit_test);
 };
 
@@ -4602,25 +4886,24 @@
   // Prints the filter if it's not *.  This reminds the user that some
   // tests may be skipped.
   if (!String::CStringEquals(filter, kUniversalFilter)) {
-    ColoredPrintf(COLOR_YELLOW,
-                  "Note: %s filter = %s\n", GTEST_NAME_, filter);
+    ColoredPrintf(GTestColor::kYellow, "Note: %s filter = %s\n", GTEST_NAME_,
+                  filter);
   }
 
   if (internal::ShouldShard(kTestTotalShards, kTestShardIndex, false)) {
-    const Int32 shard_index = Int32FromEnvOrDie(kTestShardIndex, -1);
-    ColoredPrintf(COLOR_YELLOW,
-                  "Note: This is test shard %d of %s.\n",
+    const int32_t shard_index = Int32FromEnvOrDie(kTestShardIndex, -1);
+    ColoredPrintf(GTestColor::kYellow, "Note: This is test shard %d of %s.\n",
                   static_cast<int>(shard_index) + 1,
                   internal::posix::GetEnv(kTestTotalShards));
   }
 
   if (GTEST_FLAG(shuffle)) {
-    ColoredPrintf(COLOR_YELLOW,
+    ColoredPrintf(GTestColor::kYellow,
                   "Note: Randomizing tests' orders with a seed of %d .\n",
                   unit_test.random_seed());
   }
 
-  ColoredPrintf(COLOR_GREEN,  "[==========] ");
+  ColoredPrintf(GTestColor::kGreen, "[==========] ");
   printf("Running %s from %s.\n",
          FormatTestCount(unit_test.test_to_run_count()).c_str(),
          FormatTestSuiteCount(unit_test.test_suite_to_run_count()).c_str());
@@ -4629,15 +4912,30 @@
 
 void PrettyUnitTestResultPrinter::OnEnvironmentsSetUpStart(
     const UnitTest& /*unit_test*/) {
-  ColoredPrintf(COLOR_GREEN,  "[----------] ");
+  ColoredPrintf(GTestColor::kGreen, "[----------] ");
   printf("Global test environment set-up.\n");
   fflush(stdout);
 }
 
-void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestSuite& test_suite) {
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) {
+  const std::string counts =
+      FormatCountableNoun(test_case.test_to_run_count(), "test", "tests");
+  ColoredPrintf(GTestColor::kGreen, "[----------] ");
+  printf("%s from %s", counts.c_str(), test_case.name());
+  if (test_case.type_param() == nullptr) {
+    printf("\n");
+  } else {
+    printf(", where %s = %s\n", kTypeParamLabel, test_case.type_param());
+  }
+  fflush(stdout);
+}
+#else
+void PrettyUnitTestResultPrinter::OnTestSuiteStart(
+    const TestSuite& test_suite) {
   const std::string counts =
       FormatCountableNoun(test_suite.test_to_run_count(), "test", "tests");
-  ColoredPrintf(COLOR_GREEN, "[----------] ");
+  ColoredPrintf(GTestColor::kGreen, "[----------] ");
   printf("%s from %s", counts.c_str(), test_suite.name());
   if (test_suite.type_param() == nullptr) {
     printf("\n");
@@ -4646,9 +4944,10 @@
   }
   fflush(stdout);
 }
+#endif  // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
 
 void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) {
-  ColoredPrintf(COLOR_GREEN,  "[ RUN      ] ");
+  ColoredPrintf(GTestColor::kGreen, "[ RUN      ] ");
   PrintTestName(test_info.test_suite_name(), test_info.name());
   printf("\n");
   fflush(stdout);
@@ -4658,9 +4957,7 @@
 void PrettyUnitTestResultPrinter::OnTestPartResult(
     const TestPartResult& result) {
   switch (result.type()) {
-    // If the test part succeeded, or was skipped,
-    // we don't need to do anything.
-    case TestPartResult::kSkip:
+    // If the test part succeeded, we don't need to do anything.
     case TestPartResult::kSuccess:
       return;
     default:
@@ -4673,11 +4970,11 @@
 
 void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) {
   if (test_info.result()->Passed()) {
-    ColoredPrintf(COLOR_GREEN, "[       OK ] ");
+    ColoredPrintf(GTestColor::kGreen, "[       OK ] ");
   } else if (test_info.result()->Skipped()) {
-    ColoredPrintf(COLOR_GREEN, "[  SKIPPED ] ");
+    ColoredPrintf(GTestColor::kGreen, "[  SKIPPED ] ");
   } else {
-    ColoredPrintf(COLOR_RED, "[  FAILED  ] ");
+    ColoredPrintf(GTestColor::kRed, "[  FAILED  ] ");
   }
   PrintTestName(test_info.test_suite_name(), test_info.name());
   if (test_info.result()->Failed())
@@ -4692,20 +4989,33 @@
   fflush(stdout);
 }
 
-void PrettyUnitTestResultPrinter::OnTestCaseEnd(const TestSuite& test_suite) {
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+void PrettyUnitTestResultPrinter::OnTestCaseEnd(const TestCase& test_case) {
+  if (!GTEST_FLAG(print_time)) return;
+
+  const std::string counts =
+      FormatCountableNoun(test_case.test_to_run_count(), "test", "tests");
+  ColoredPrintf(GTestColor::kGreen, "[----------] ");
+  printf("%s from %s (%s ms total)\n\n", counts.c_str(), test_case.name(),
+         internal::StreamableToString(test_case.elapsed_time()).c_str());
+  fflush(stdout);
+}
+#else
+void PrettyUnitTestResultPrinter::OnTestSuiteEnd(const TestSuite& test_suite) {
   if (!GTEST_FLAG(print_time)) return;
 
   const std::string counts =
       FormatCountableNoun(test_suite.test_to_run_count(), "test", "tests");
-  ColoredPrintf(COLOR_GREEN, "[----------] ");
+  ColoredPrintf(GTestColor::kGreen, "[----------] ");
   printf("%s from %s (%s ms total)\n\n", counts.c_str(), test_suite.name(),
          internal::StreamableToString(test_suite.elapsed_time()).c_str());
   fflush(stdout);
 }
+#endif  // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
 
 void PrettyUnitTestResultPrinter::OnEnvironmentsTearDownStart(
     const UnitTest& /*unit_test*/) {
-  ColoredPrintf(COLOR_GREEN,  "[----------] ");
+  ColoredPrintf(GTestColor::kGreen, "[----------] ");
   printf("Global test environment tear-down\n");
   fflush(stdout);
 }
@@ -4713,9 +5023,8 @@
 // Internal helper for printing the list of failed tests.
 void PrettyUnitTestResultPrinter::PrintFailedTests(const UnitTest& unit_test) {
   const int failed_test_count = unit_test.failed_test_count();
-  if (failed_test_count == 0) {
-    return;
-  }
+  ColoredPrintf(GTestColor::kRed, "[  FAILED  ] ");
+  printf("%s, listed below:\n", FormatTestCount(failed_test_count).c_str());
 
   for (int i = 0; i < unit_test.total_test_suite_count(); ++i) {
     const TestSuite& test_suite = *unit_test.GetTestSuite(i);
@@ -4727,12 +5036,36 @@
       if (!test_info.should_run() || !test_info.result()->Failed()) {
         continue;
       }
-      ColoredPrintf(COLOR_RED, "[  FAILED  ] ");
+      ColoredPrintf(GTestColor::kRed, "[  FAILED  ] ");
       printf("%s.%s", test_suite.name(), test_info.name());
       PrintFullTestCommentIfPresent(test_info);
       printf("\n");
     }
   }
+  printf("\n%2d FAILED %s\n", failed_test_count,
+         failed_test_count == 1 ? "TEST" : "TESTS");
+}
+
+// Internal helper for printing the list of test suite failures not covered by
+// PrintFailedTests.
+void PrettyUnitTestResultPrinter::PrintFailedTestSuites(
+    const UnitTest& unit_test) {
+  int suite_failure_count = 0;
+  for (int i = 0; i < unit_test.total_test_suite_count(); ++i) {
+    const TestSuite& test_suite = *unit_test.GetTestSuite(i);
+    if (!test_suite.should_run()) {
+      continue;
+    }
+    if (test_suite.ad_hoc_test_result().Failed()) {
+      ColoredPrintf(GTestColor::kRed, "[  FAILED  ] ");
+      printf("%s: SetUpTestSuite or TearDownTestSuite\n", test_suite.name());
+      ++suite_failure_count;
+    }
+  }
+  if (suite_failure_count > 0) {
+    printf("\n%2d FAILED TEST %s\n", suite_failure_count,
+           suite_failure_count == 1 ? "SUITE" : "SUITES");
+  }
 }
 
 // Internal helper for printing the list of skipped tests.
@@ -4752,7 +5085,7 @@
       if (!test_info.should_run() || !test_info.result()->Skipped()) {
         continue;
       }
-      ColoredPrintf(COLOR_GREEN, "[  SKIPPED ] ");
+      ColoredPrintf(GTestColor::kGreen, "[  SKIPPED ] ");
       printf("%s.%s", test_suite.name(), test_info.name());
       printf("\n");
     }
@@ -4761,7 +5094,7 @@
 
 void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test,
                                                      int /*iteration*/) {
-  ColoredPrintf(COLOR_GREEN,  "[==========] ");
+  ColoredPrintf(GTestColor::kGreen, "[==========] ");
   printf("%s from %s ran.",
          FormatTestCount(unit_test.test_to_run_count()).c_str(),
          FormatTestSuiteCount(unit_test.test_suite_to_run_count()).c_str());
@@ -4770,35 +5103,28 @@
            internal::StreamableToString(unit_test.elapsed_time()).c_str());
   }
   printf("\n");
-  ColoredPrintf(COLOR_GREEN,  "[  PASSED  ] ");
+  ColoredPrintf(GTestColor::kGreen, "[  PASSED  ] ");
   printf("%s.\n", FormatTestCount(unit_test.successful_test_count()).c_str());
 
   const int skipped_test_count = unit_test.skipped_test_count();
   if (skipped_test_count > 0) {
-    ColoredPrintf(COLOR_GREEN, "[  SKIPPED ] ");
+    ColoredPrintf(GTestColor::kGreen, "[  SKIPPED ] ");
     printf("%s, listed below:\n", FormatTestCount(skipped_test_count).c_str());
     PrintSkippedTests(unit_test);
   }
 
-  int num_failures = unit_test.failed_test_count();
   if (!unit_test.Passed()) {
-    const int failed_test_count = unit_test.failed_test_count();
-    ColoredPrintf(COLOR_RED,  "[  FAILED  ] ");
-    printf("%s, listed below:\n", FormatTestCount(failed_test_count).c_str());
     PrintFailedTests(unit_test);
-    printf("\n%2d FAILED %s\n", num_failures,
-                        num_failures == 1 ? "TEST" : "TESTS");
+    PrintFailedTestSuites(unit_test);
   }
 
   int num_disabled = unit_test.reportable_disabled_test_count();
   if (num_disabled && !GTEST_FLAG(also_run_disabled_tests)) {
-    if (!num_failures) {
+    if (unit_test.Passed()) {
       printf("\n");  // Add a spacer if no FAILURE banner is displayed.
     }
-    ColoredPrintf(COLOR_YELLOW,
-                  "  YOU HAVE %d DISABLED %s\n\n",
-                  num_disabled,
-                  num_disabled == 1 ? "TEST" : "TESTS");
+    ColoredPrintf(GTestColor::kYellow, "  YOU HAVE %d DISABLED %s\n\n",
+                  num_disabled, num_disabled == 1 ? "TEST" : "TESTS");
   }
   // Ensure that Google Test output is printed before, e.g., heapchecker output.
   fflush(stdout);
@@ -4806,6 +5132,110 @@
 
 // End PrettyUnitTestResultPrinter
 
+// This class implements the TestEventListener interface.
+//
+// Class BriefUnitTestResultPrinter is copyable.
+class BriefUnitTestResultPrinter : public TestEventListener {
+ public:
+  BriefUnitTestResultPrinter() {}
+  static void PrintTestName(const char* test_suite, const char* test) {
+    printf("%s.%s", test_suite, test);
+  }
+
+  // The following methods override what's in the TestEventListener class.
+  void OnTestProgramStart(const UnitTest& /*unit_test*/) override {}
+  void OnTestIterationStart(const UnitTest& /*unit_test*/,
+                            int /*iteration*/) override {}
+  void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) override {}
+  void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) override {}
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+  void OnTestCaseStart(const TestCase& /*test_case*/) override {}
+#else
+  void OnTestSuiteStart(const TestSuite& /*test_suite*/) override {}
+#endif  // OnTestCaseStart
+
+  void OnTestStart(const TestInfo& /*test_info*/) override {}
+
+  void OnTestPartResult(const TestPartResult& result) override;
+  void OnTestEnd(const TestInfo& test_info) override;
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+  void OnTestCaseEnd(const TestCase& /*test_case*/) override {}
+#else
+  void OnTestSuiteEnd(const TestSuite& /*test_suite*/) override {}
+#endif  // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+  void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) override {}
+  void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) override {}
+  void OnTestIterationEnd(const UnitTest& unit_test, int iteration) override;
+  void OnTestProgramEnd(const UnitTest& /*unit_test*/) override {}
+};
+
+// Called after an assertion failure.
+void BriefUnitTestResultPrinter::OnTestPartResult(
+    const TestPartResult& result) {
+  switch (result.type()) {
+    // If the test part succeeded, we don't need to do anything.
+    case TestPartResult::kSuccess:
+      return;
+    default:
+      // Print failure message from the assertion
+      // (e.g. expected this and got that).
+      PrintTestPartResult(result);
+      fflush(stdout);
+  }
+}
+
+void BriefUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) {
+  if (test_info.result()->Failed()) {
+    ColoredPrintf(GTestColor::kRed, "[  FAILED  ] ");
+    PrintTestName(test_info.test_suite_name(), test_info.name());
+    PrintFullTestCommentIfPresent(test_info);
+
+    if (GTEST_FLAG(print_time)) {
+      printf(" (%s ms)\n",
+             internal::StreamableToString(test_info.result()->elapsed_time())
+                 .c_str());
+    } else {
+      printf("\n");
+    }
+    fflush(stdout);
+  }
+}
+
+void BriefUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test,
+                                                    int /*iteration*/) {
+  ColoredPrintf(GTestColor::kGreen, "[==========] ");
+  printf("%s from %s ran.",
+         FormatTestCount(unit_test.test_to_run_count()).c_str(),
+         FormatTestSuiteCount(unit_test.test_suite_to_run_count()).c_str());
+  if (GTEST_FLAG(print_time)) {
+    printf(" (%s ms total)",
+           internal::StreamableToString(unit_test.elapsed_time()).c_str());
+  }
+  printf("\n");
+  ColoredPrintf(GTestColor::kGreen, "[  PASSED  ] ");
+  printf("%s.\n", FormatTestCount(unit_test.successful_test_count()).c_str());
+
+  const int skipped_test_count = unit_test.skipped_test_count();
+  if (skipped_test_count > 0) {
+    ColoredPrintf(GTestColor::kGreen, "[  SKIPPED ] ");
+    printf("%s.\n", FormatTestCount(skipped_test_count).c_str());
+  }
+
+  int num_disabled = unit_test.reportable_disabled_test_count();
+  if (num_disabled && !GTEST_FLAG(also_run_disabled_tests)) {
+    if (unit_test.Passed()) {
+      printf("\n");  // Add a spacer if no FAILURE banner is displayed.
+    }
+    ColoredPrintf(GTestColor::kYellow, "  YOU HAVE %d DISABLED %s\n\n",
+                  num_disabled, num_disabled == 1 ? "TEST" : "TESTS");
+  }
+  // Ensure that Google Test output is printed before, e.g., heapchecker output.
+  fflush(stdout);
+}
+
+// End BriefUnitTestResultPrinter
+
 // class TestEventRepeater
 //
 // This class forwards events to other event listeners.
@@ -4826,17 +5256,17 @@
   void OnEnvironmentsSetUpStart(const UnitTest& unit_test) override;
   void OnEnvironmentsSetUpEnd(const UnitTest& unit_test) override;
 //  Legacy API is deprecated but still available
-#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
   void OnTestCaseStart(const TestSuite& parameter) override;
-#endif  //  GTEST_REMOVE_LEGACY_TEST_CASEAPI
+#endif  //  GTEST_REMOVE_LEGACY_TEST_CASEAPI_
   void OnTestSuiteStart(const TestSuite& parameter) override;
   void OnTestStart(const TestInfo& test_info) override;
   void OnTestPartResult(const TestPartResult& result) override;
   void OnTestEnd(const TestInfo& test_info) override;
 //  Legacy API is deprecated but still available
-#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI
-  void OnTestCaseEnd(const TestSuite& parameter) override;
-#endif  //  GTEST_REMOVE_LEGACY_TEST_CASEAPI
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+  void OnTestCaseEnd(const TestCase& parameter) override;
+#endif  //  GTEST_REMOVE_LEGACY_TEST_CASEAPI_
   void OnTestSuiteEnd(const TestSuite& parameter) override;
   void OnEnvironmentsTearDownStart(const UnitTest& unit_test) override;
   void OnEnvironmentsTearDownEnd(const UnitTest& unit_test) override;
@@ -4864,7 +5294,7 @@
 TestEventListener* TestEventRepeater::Release(TestEventListener *listener) {
   for (size_t i = 0; i < listeners_.size(); ++i) {
     if (listeners_[i] == listener) {
-      listeners_.erase(listeners_.begin() + i);
+      listeners_.erase(listeners_.begin() + static_cast<int>(i));
       return listener;
     }
   }
@@ -4884,14 +5314,14 @@
 }
 // This defines a member that forwards the call to all listeners in reverse
 // order.
-#define GTEST_REVERSE_REPEATER_METHOD_(Name, Type) \
-void TestEventRepeater::Name(const Type& parameter) { \
-  if (forwarding_enabled_) { \
-    for (int i = static_cast<int>(listeners_.size()) - 1; i >= 0; i--) { \
-      listeners_[i]->Name(parameter); \
-    } \
-  } \
-}
+#define GTEST_REVERSE_REPEATER_METHOD_(Name, Type)      \
+  void TestEventRepeater::Name(const Type& parameter) { \
+    if (forwarding_enabled_) {                          \
+      for (size_t i = listeners_.size(); i != 0; i--) { \
+        listeners_[i - 1]->Name(parameter);             \
+      }                                                 \
+    }                                                   \
+  }
 
 GTEST_REPEATER_METHOD_(OnTestProgramStart, UnitTest)
 GTEST_REPEATER_METHOD_(OnEnvironmentsSetUpStart, UnitTest)
@@ -4928,8 +5358,8 @@
 void TestEventRepeater::OnTestIterationEnd(const UnitTest& unit_test,
                                            int iteration) {
   if (forwarding_enabled_) {
-    for (int i = static_cast<int>(listeners_.size()) - 1; i >= 0; i--) {
-      listeners_[i]->OnTestIterationEnd(unit_test, iteration);
+    for (size_t i = listeners_.size(); i > 0; i--) {
+      listeners_[i - 1]->OnTestIterationEnd(unit_test, iteration);
     }
   }
 }
@@ -4989,6 +5419,16 @@
   // Streams an XML CDATA section, escaping invalid CDATA sequences as needed.
   static void OutputXmlCDataSection(::std::ostream* stream, const char* data);
 
+  // Streams a test suite XML stanza containing the given test result.
+  //
+  // Requires: result.Failed()
+  static void OutputXmlTestSuiteForTestResult(::std::ostream* stream,
+                                              const TestResult& result);
+
+  // Streams an XML representation of a TestResult object.
+  static void OutputXmlTestResult(::std::ostream* stream,
+                                  const TestResult& result);
+
   // Streams an XML representation of a TestInfo object.
   static void OutputXmlTestInfo(::std::ostream* stream,
                                 const char* test_suite_name,
@@ -5147,6 +5587,10 @@
   if (tm_ptr == nullptr) return false;
   *out = *tm_ptr;
   return true;
+#elif defined(__STDC_LIB_EXT1__)
+  // Uses localtime_s when available as localtime_r is only available from
+  // C23 standard.
+  return localtime_s(&seconds, out) != nullptr;
 #else
   return localtime_r(&seconds, out) != nullptr;
 #endif
@@ -5158,13 +5602,14 @@
   struct tm time_struct;
   if (!PortableLocaltime(static_cast<time_t>(ms / 1000), &time_struct))
     return "";
-  // YYYY-MM-DDThh:mm:ss
+  // YYYY-MM-DDThh:mm:ss.sss
   return StreamableToString(time_struct.tm_year + 1900) + "-" +
       String::FormatIntWidth2(time_struct.tm_mon + 1) + "-" +
       String::FormatIntWidth2(time_struct.tm_mday) + "T" +
       String::FormatIntWidth2(time_struct.tm_hour) + ":" +
       String::FormatIntWidth2(time_struct.tm_min) + ":" +
-      String::FormatIntWidth2(time_struct.tm_sec);
+      String::FormatIntWidth2(time_struct.tm_sec) + "." +
+      String::FormatIntWidthN(static_cast<int>(ms % 1000), 3);
 }
 
 // Streams an XML CDATA section, escaping invalid CDATA sequences as needed.
@@ -5193,7 +5638,7 @@
     const std::string& name,
     const std::string& value) {
   const std::vector<std::string>& allowed_names =
-      GetReservedAttributesForElement(element_name);
+      GetReservedOutputAttributesForElement(element_name);
 
   GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) !=
                    allowed_names.end())
@@ -5203,6 +5648,43 @@
   *stream << " " << name << "=\"" << EscapeXmlAttribute(value) << "\"";
 }
 
+// Streams a test suite XML stanza containing the given test result.
+void XmlUnitTestResultPrinter::OutputXmlTestSuiteForTestResult(
+    ::std::ostream* stream, const TestResult& result) {
+  // Output the boilerplate for a minimal test suite with one test.
+  *stream << "  <testsuite";
+  OutputXmlAttribute(stream, "testsuite", "name", "NonTestSuiteFailure");
+  OutputXmlAttribute(stream, "testsuite", "tests", "1");
+  OutputXmlAttribute(stream, "testsuite", "failures", "1");
+  OutputXmlAttribute(stream, "testsuite", "disabled", "0");
+  OutputXmlAttribute(stream, "testsuite", "skipped", "0");
+  OutputXmlAttribute(stream, "testsuite", "errors", "0");
+  OutputXmlAttribute(stream, "testsuite", "time",
+                     FormatTimeInMillisAsSeconds(result.elapsed_time()));
+  OutputXmlAttribute(
+      stream, "testsuite", "timestamp",
+      FormatEpochTimeInMillisAsIso8601(result.start_timestamp()));
+  *stream << ">";
+
+  // Output the boilerplate for a minimal test case with a single test.
+  *stream << "    <testcase";
+  OutputXmlAttribute(stream, "testcase", "name", "");
+  OutputXmlAttribute(stream, "testcase", "status", "run");
+  OutputXmlAttribute(stream, "testcase", "result", "completed");
+  OutputXmlAttribute(stream, "testcase", "classname", "");
+  OutputXmlAttribute(stream, "testcase", "time",
+                     FormatTimeInMillisAsSeconds(result.elapsed_time()));
+  OutputXmlAttribute(
+      stream, "testcase", "timestamp",
+      FormatEpochTimeInMillisAsIso8601(result.start_timestamp()));
+
+  // Output the actual test result.
+  OutputXmlTestResult(stream, result);
+
+  // Complete the test suite.
+  *stream << "  </testsuite>\n";
+}
+
 // Prints an XML representation of a TestInfo object.
 void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream,
                                                  const char* test_suite_name,
@@ -5233,18 +5715,30 @@
     return;
   }
 
-  OutputXmlAttribute(
-      stream, kTestsuite, "status",
-      result.Skipped() ? "skipped" : test_info.should_run() ? "run" : "notrun");
+  OutputXmlAttribute(stream, kTestsuite, "status",
+                     test_info.should_run() ? "run" : "notrun");
+  OutputXmlAttribute(stream, kTestsuite, "result",
+                     test_info.should_run()
+                         ? (result.Skipped() ? "skipped" : "completed")
+                         : "suppressed");
   OutputXmlAttribute(stream, kTestsuite, "time",
                      FormatTimeInMillisAsSeconds(result.elapsed_time()));
+  OutputXmlAttribute(
+      stream, kTestsuite, "timestamp",
+      FormatEpochTimeInMillisAsIso8601(result.start_timestamp()));
   OutputXmlAttribute(stream, kTestsuite, "classname", test_suite_name);
 
+  OutputXmlTestResult(stream, result);
+}
+
+void XmlUnitTestResultPrinter::OutputXmlTestResult(::std::ostream* stream,
+                                                   const TestResult& result) {
   int failures = 0;
+  int skips = 0;
   for (int i = 0; i < result.total_part_count(); ++i) {
     const TestPartResult& part = result.GetTestPartResult(i);
     if (part.failed()) {
-      if (++failures == 1) {
+      if (++failures == 1 && skips == 0) {
         *stream << ">\n";
       }
       const std::string location =
@@ -5252,18 +5746,31 @@
                                                           part.line_number());
       const std::string summary = location + "\n" + part.summary();
       *stream << "      <failure message=\""
-              << EscapeXmlAttribute(summary.c_str())
+              << EscapeXmlAttribute(summary)
               << "\" type=\"\">";
       const std::string detail = location + "\n" + part.message();
       OutputXmlCDataSection(stream, RemoveInvalidXmlCharacters(detail).c_str());
       *stream << "</failure>\n";
+    } else if (part.skipped()) {
+      if (++skips == 1 && failures == 0) {
+        *stream << ">\n";
+      }
+      const std::string location =
+          internal::FormatCompilerIndependentFileLocation(part.file_name(),
+                                                          part.line_number());
+      const std::string summary = location + "\n" + part.summary();
+      *stream << "      <skipped message=\""
+              << EscapeXmlAttribute(summary.c_str()) << "\">";
+      const std::string detail = location + "\n" + part.message();
+      OutputXmlCDataSection(stream, RemoveInvalidXmlCharacters(detail).c_str());
+      *stream << "</skipped>\n";
     }
   }
 
-  if (failures == 0 && result.test_property_count() == 0) {
+  if (failures == 0 && skips == 0 && result.test_property_count() == 0) {
     *stream << " />\n";
   } else {
-    if (failures == 0) {
+    if (failures == 0 && skips == 0) {
       *stream << ">\n";
     }
     OutputXmlTestProperties(stream, result);
@@ -5285,9 +5792,16 @@
     OutputXmlAttribute(
         stream, kTestsuite, "disabled",
         StreamableToString(test_suite.reportable_disabled_test_count()));
+    OutputXmlAttribute(stream, kTestsuite, "skipped",
+                       StreamableToString(test_suite.skipped_test_count()));
+
     OutputXmlAttribute(stream, kTestsuite, "errors", "0");
+
     OutputXmlAttribute(stream, kTestsuite, "time",
                        FormatTimeInMillisAsSeconds(test_suite.elapsed_time()));
+    OutputXmlAttribute(
+        stream, kTestsuite, "timestamp",
+        FormatEpochTimeInMillisAsIso8601(test_suite.start_timestamp()));
     *stream << TestPropertiesAsXmlAttributes(test_suite.ad_hoc_test_result());
   }
   *stream << ">\n";
@@ -5314,11 +5828,11 @@
       stream, kTestsuites, "disabled",
       StreamableToString(unit_test.reportable_disabled_test_count()));
   OutputXmlAttribute(stream, kTestsuites, "errors", "0");
+  OutputXmlAttribute(stream, kTestsuites, "time",
+                     FormatTimeInMillisAsSeconds(unit_test.elapsed_time()));
   OutputXmlAttribute(
       stream, kTestsuites, "timestamp",
       FormatEpochTimeInMillisAsIso8601(unit_test.start_timestamp()));
-  OutputXmlAttribute(stream, kTestsuites, "time",
-                     FormatTimeInMillisAsSeconds(unit_test.elapsed_time()));
 
   if (GTEST_FLAG(shuffle)) {
     OutputXmlAttribute(stream, kTestsuites, "random_seed",
@@ -5333,6 +5847,13 @@
     if (unit_test.GetTestSuite(i)->reportable_test_count() > 0)
       PrintXmlTestSuite(stream, *unit_test.GetTestSuite(i));
   }
+
+  // If there was a test failure outside of one of the test suites (like in a
+  // test environment) include that in the output.
+  if (unit_test.ad_hoc_test_result().Failed()) {
+    OutputXmlTestSuiteForTestResult(stream, unit_test.ad_hoc_test_result());
+  }
+
   *stream << "</" << kTestsuites << ">\n";
 }
 
@@ -5423,6 +5944,16 @@
                             const std::string& indent,
                             bool comma = true);
 
+  // Streams a test suite JSON stanza containing the given test result.
+  //
+  // Requires: result.Failed()
+  static void OutputJsonTestSuiteForTestResult(::std::ostream* stream,
+                                               const TestResult& result);
+
+  // Streams a JSON representation of a TestResult object.
+  static void OutputJsonTestResult(::std::ostream* stream,
+                                   const TestResult& result);
+
   // Streams a JSON representation of a TestInfo object.
   static void OutputJsonTestInfo(::std::ostream* stream,
                                  const char* test_suite_name,
@@ -5529,7 +6060,7 @@
       String::FormatIntWidth2(time_struct.tm_sec) + "Z";
 }
 
-static inline std::string Indent(int width) {
+static inline std::string Indent(size_t width) {
   return std::string(width, ' ');
 }
 
@@ -5541,7 +6072,7 @@
     const std::string& indent,
     bool comma) {
   const std::vector<std::string>& allowed_names =
-      GetReservedAttributesForElement(element_name);
+      GetReservedOutputAttributesForElement(element_name);
 
   GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) !=
                    allowed_names.end())
@@ -5561,7 +6092,7 @@
     const std::string& indent,
     bool comma) {
   const std::vector<std::string>& allowed_names =
-      GetReservedAttributesForElement(element_name);
+      GetReservedOutputAttributesForElement(element_name);
 
   GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) !=
                    allowed_names.end())
@@ -5573,6 +6104,48 @@
     *stream << ",\n";
 }
 
+// Streams a test suite JSON stanza containing the given test result.
+void JsonUnitTestResultPrinter::OutputJsonTestSuiteForTestResult(
+    ::std::ostream* stream, const TestResult& result) {
+  // Output the boilerplate for a new test suite.
+  *stream << Indent(4) << "{\n";
+  OutputJsonKey(stream, "testsuite", "name", "NonTestSuiteFailure", Indent(6));
+  OutputJsonKey(stream, "testsuite", "tests", 1, Indent(6));
+  if (!GTEST_FLAG(list_tests)) {
+    OutputJsonKey(stream, "testsuite", "failures", 1, Indent(6));
+    OutputJsonKey(stream, "testsuite", "disabled", 0, Indent(6));
+    OutputJsonKey(stream, "testsuite", "skipped", 0, Indent(6));
+    OutputJsonKey(stream, "testsuite", "errors", 0, Indent(6));
+    OutputJsonKey(stream, "testsuite", "time",
+                  FormatTimeInMillisAsDuration(result.elapsed_time()),
+                  Indent(6));
+    OutputJsonKey(stream, "testsuite", "timestamp",
+                  FormatEpochTimeInMillisAsRFC3339(result.start_timestamp()),
+                  Indent(6));
+  }
+  *stream << Indent(6) << "\"testsuite\": [\n";
+
+  // Output the boilerplate for a new test case.
+  *stream << Indent(8) << "{\n";
+  OutputJsonKey(stream, "testcase", "name", "", Indent(10));
+  OutputJsonKey(stream, "testcase", "status", "RUN", Indent(10));
+  OutputJsonKey(stream, "testcase", "result", "COMPLETED", Indent(10));
+  OutputJsonKey(stream, "testcase", "timestamp",
+                FormatEpochTimeInMillisAsRFC3339(result.start_timestamp()),
+                Indent(10));
+  OutputJsonKey(stream, "testcase", "time",
+                FormatTimeInMillisAsDuration(result.elapsed_time()),
+                Indent(10));
+  OutputJsonKey(stream, "testcase", "classname", "", Indent(10), false);
+  *stream << TestPropertiesAsJson(result, Indent(10));
+
+  // Output the actual test result.
+  OutputJsonTestResult(stream, result);
+
+  // Finish the test suite.
+  *stream << "\n" << Indent(6) << "]\n" << Indent(4) << "}";
+}
+
 // Prints a JSON representation of a TestInfo object.
 void JsonUnitTestResultPrinter::OutputJsonTestInfo(::std::ostream* stream,
                                                    const char* test_suite_name,
@@ -5599,16 +6172,29 @@
     return;
   }
 
-  OutputJsonKey(
-      stream, kTestsuite, "status",
-      result.Skipped() ? "SKIPPED" : test_info.should_run() ? "RUN" : "NOTRUN",
-      kIndent);
+  OutputJsonKey(stream, kTestsuite, "status",
+                test_info.should_run() ? "RUN" : "NOTRUN", kIndent);
+  OutputJsonKey(stream, kTestsuite, "result",
+                test_info.should_run()
+                    ? (result.Skipped() ? "SKIPPED" : "COMPLETED")
+                    : "SUPPRESSED",
+                kIndent);
+  OutputJsonKey(stream, kTestsuite, "timestamp",
+                FormatEpochTimeInMillisAsRFC3339(result.start_timestamp()),
+                kIndent);
   OutputJsonKey(stream, kTestsuite, "time",
                 FormatTimeInMillisAsDuration(result.elapsed_time()), kIndent);
   OutputJsonKey(stream, kTestsuite, "classname", test_suite_name, kIndent,
                 false);
   *stream << TestPropertiesAsJson(result, kIndent);
 
+  OutputJsonTestResult(stream, result);
+}
+
+void JsonUnitTestResultPrinter::OutputJsonTestResult(::std::ostream* stream,
+                                                     const TestResult& result) {
+  const std::string kIndent = Indent(10);
+
   int failures = 0;
   for (int i = 0; i < result.total_part_count(); ++i) {
     const TestPartResult& part = result.GetTestPartResult(i);
@@ -5649,6 +6235,10 @@
     OutputJsonKey(stream, kTestsuite, "disabled",
                   test_suite.reportable_disabled_test_count(), kIndent);
     OutputJsonKey(stream, kTestsuite, "errors", 0, kIndent);
+    OutputJsonKey(
+        stream, kTestsuite, "timestamp",
+        FormatEpochTimeInMillisAsRFC3339(test_suite.start_timestamp()),
+        kIndent);
     OutputJsonKey(stream, kTestsuite, "time",
                   FormatTimeInMillisAsDuration(test_suite.elapsed_time()),
                   kIndent, false);
@@ -5715,6 +6305,12 @@
     }
   }
 
+  // If there was a test failure outside of one of the test suites (like in a
+  // test environment) include that in the output.
+  if (unit_test.ad_hoc_test_result().Failed()) {
+    OutputJsonTestSuiteForTestResult(stream, unit_test.ad_hoc_test_result());
+  }
+
   *stream << "\n" << kIndent << "]\n" << "}\n";
 }
 
@@ -5914,6 +6510,7 @@
   }
 
   ~ScopedPrematureExitFile() {
+#if !defined GTEST_OS_ESP8266
     if (!premature_exit_filepath_.empty()) {
       int retval = remove(premature_exit_filepath_.c_str());
       if (retval) {
@@ -5922,6 +6519,7 @@
                           << retval;
       }
     }
+#endif
   }
 
  private:
@@ -6109,11 +6707,12 @@
   return impl()->elapsed_time();
 }
 
-// Returns true iff the unit test passed (i.e. all test suites passed).
+// Returns true if and only if the unit test passed (i.e. all test suites
+// passed).
 bool UnitTest::Passed() const { return impl()->Passed(); }
 
-// Returns true iff the unit test failed (i.e. some test suite failed
-// or something outside of all tests failed).
+// Returns true if and only if the unit test failed (i.e. some test suite
+// failed or something outside of all tests failed).
 bool UnitTest::Failed() const { return impl()->Failed(); }
 
 // Gets the i-th test suite among all the test suites. i can range from 0 to
@@ -6183,8 +6782,7 @@
   if (impl_->gtest_trace_stack().size() > 0) {
     msg << "\n" << GTEST_NAME_ << " trace:";
 
-    for (int i = static_cast<int>(impl_->gtest_trace_stack().size());
-         i > 0; --i) {
+    for (size_t i = impl_->gtest_trace_stack().size(); i > 0; --i) {
       const internal::TraceInfo& trace = impl_->gtest_trace_stack()[i - 1];
       msg << "\n" << internal::FormatFileLocation(trace.file, trace.line)
           << " " << trace.message;
@@ -6314,6 +6912,16 @@
       _set_abort_behavior(
           0x0,                                    // Clear the following flags:
           _WRITE_ABORT_MSG | _CALL_REPORTFAULT);  // pop-up window, core dump.
+
+    // In debug mode, the Windows CRT can crash with an assertion over invalid
+    // input (e.g. passing an invalid file descriptor).  The default handling
+    // for these assertions is to pop up a dialog and wait for user input.
+    // Instead ask the CRT to dump such assertions to stderr non-interactively.
+    if (!IsDebuggerPresent()) {
+      (void)_CrtSetReportMode(_CRT_ASSERT,
+                              _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
+      (void)_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
+    }
 # endif
   }
 #endif  // GTEST_OS_WINDOWS
@@ -6525,6 +7133,10 @@
     // to shut down the default XML output before invoking RUN_ALL_TESTS.
     ConfigureXmlOutput();
 
+    if (GTEST_FLAG(brief)) {
+      listeners()->SetDefaultResultPrinter(new BriefUnitTestResultPrinter);
+    }
+
 #if GTEST_CAN_STREAM_RESULTS_
     // Configures listeners for streaming test results to the specified server.
     ConfigureStreamingOutput();
@@ -6552,7 +7164,7 @@
   // Constructor.
   explicit TestSuiteNameIs(const std::string& name) : name_(name) {}
 
-  // Returns true iff the name of test_suite matches name_.
+  // Returns true if and only if the name of test_suite matches name_.
   bool operator()(const TestSuite* test_suite) const {
     return test_suite != nullptr &&
            strcmp(test_suite->name(), name_.c_str()) == 0;
@@ -6570,10 +7182,10 @@
 // Arguments:
 //
 //   test_suite_name: name of the test suite
-//   type_param:     the name of the test suite's type parameter, or NULL if
-//                   this is not a typed or a type-parameterized test suite.
-//   set_up_tc:      pointer to the function that sets up the test suite
-//   tear_down_tc:   pointer to the function that tears down the test suite
+//   type_param:      the name of the test suite's type parameter, or NULL if
+//                    this is not a typed or a type-parameterized test suite.
+//   set_up_tc:       pointer to the function that sets up the test suite
+//   tear_down_tc:    pointer to the function that tears down the test suite
 TestSuite* UnitTestImpl::GetTestSuite(
     const char* test_suite_name, const char* type_param,
     internal::SetUpTestSuiteFunc set_up_tc,
@@ -6623,7 +7235,8 @@
 // All other functions called from RunAllTests() may safely assume that
 // parameterized tests are ready to be counted and run.
 bool UnitTestImpl::RunAllTests() {
-  // True iff Google Test is initialized before RUN_ALL_TESTS() is called.
+  // True if and only if Google Test is initialized before RUN_ALL_TESTS() is
+  // called.
   const bool gtest_is_initialized_before_run_all_tests = GTestIsInitialized();
 
   // Do not run any test if the --help flag was specified.
@@ -6639,7 +7252,7 @@
   // protocol.
   internal::WriteToShardStatusFileIfNeeded();
 
-  // True iff we are in a subprocess for running a thread-safe-style
+  // True if and only if we are in a subprocess for running a thread-safe-style
   // death test.
   bool in_subprocess_for_death_test = false;
 
@@ -6672,7 +7285,7 @@
   random_seed_ = GTEST_FLAG(shuffle) ?
       GetRandomSeedFromFlag(GTEST_FLAG(random_seed)) : 0;
 
-  // True iff at least one test has failed.
+  // True if and only if at least one test has failed.
   bool failed = false;
 
   TestEventListener* repeater = listeners()->repeater();
@@ -6684,17 +7297,17 @@
   // when we are inside the subprocess of a death test.
   const int repeat = in_subprocess_for_death_test ? 1 : GTEST_FLAG(repeat);
   // Repeats forever if the repeat count is negative.
-  const bool forever = repeat < 0;
-  for (int i = 0; forever || i != repeat; i++) {
+  const bool gtest_repeat_forever = repeat < 0;
+  for (int i = 0; gtest_repeat_forever || i != repeat; i++) {
     // We want to preserve failures generated by ad-hoc test
     // assertions executed before RUN_ALL_TESTS().
     ClearNonAdHocTestResult();
 
-    const TimeInMillis start = GetTimeInMillis();
+    Timer timer;
 
     // Shuffles test suites and tests if requested.
     if (has_tests_to_run && GTEST_FLAG(shuffle)) {
-      random()->Reseed(random_seed_);
+      random()->Reseed(static_cast<uint32_t>(random_seed_));
       // This should be done before calling OnTestIterationStart(),
       // such that a test event listener can see the actual test order
       // in the event.
@@ -6711,12 +7324,41 @@
       ForEach(environments_, SetUpEnvironment);
       repeater->OnEnvironmentsSetUpEnd(*parent_);
 
-      // Runs the tests only if there was no fatal failure during global
-      // set-up.
-      if (!Test::HasFatalFailure()) {
+      // Runs the tests only if there was no fatal failure or skip triggered
+      // during global set-up.
+      if (Test::IsSkipped()) {
+        // Emit diagnostics when global set-up calls skip, as it will not be
+        // emitted by default.
+        TestResult& test_result =
+            *internal::GetUnitTestImpl()->current_test_result();
+        for (int j = 0; j < test_result.total_part_count(); ++j) {
+          const TestPartResult& test_part_result =
+              test_result.GetTestPartResult(j);
+          if (test_part_result.type() == TestPartResult::kSkip) {
+            const std::string& result = test_part_result.message();
+            printf("%s\n", result.c_str());
+          }
+        }
+        fflush(stdout);
+      } else if (!Test::HasFatalFailure()) {
         for (int test_index = 0; test_index < total_test_suite_count();
              test_index++) {
           GetMutableSuiteCase(test_index)->Run();
+          if (GTEST_FLAG(fail_fast) &&
+              GetMutableSuiteCase(test_index)->Failed()) {
+            for (int j = test_index + 1; j < total_test_suite_count(); j++) {
+              GetMutableSuiteCase(j)->Skip();
+            }
+            break;
+          }
+        }
+      } else if (Test::HasFatalFailure()) {
+        // If there was a fatal failure during the global setup then we know we
+        // aren't going to run any tests. Explicitly mark all of the tests as
+        // skipped to make this obvious in the output.
+        for (int test_index = 0; test_index < total_test_suite_count();
+             test_index++) {
+          GetMutableSuiteCase(test_index)->Skip();
         }
       }
 
@@ -6727,7 +7369,7 @@
       repeater->OnEnvironmentsTearDownEnd(*parent_);
     }
 
-    elapsed_time_ = GetTimeInMillis() - start;
+    elapsed_time_ = timer.Elapsed();
 
     // Tells the unit test event listener that the tests have just finished.
     repeater->OnTestIterationEnd(*parent_, i);
@@ -6755,14 +7397,14 @@
 
   if (!gtest_is_initialized_before_run_all_tests) {
     ColoredPrintf(
-        COLOR_RED,
+        GTestColor::kRed,
         "\nIMPORTANT NOTICE - DO NOT IGNORE:\n"
         "This test program did NOT call " GTEST_INIT_GOOGLE_TEST_NAME_
         "() before calling RUN_ALL_TESTS(). This is INVALID. Soon " GTEST_NAME_
         " will start to enforce the valid usage. "
         "Please fix it ASAP, or IT WILL START TO FAIL.\n");  // NOLINT
 #if GTEST_FOR_GOOGLE_
-    ColoredPrintf(COLOR_RED,
+    ColoredPrintf(GTestColor::kRed,
                   "For more details, see http://wiki/Main/ValidGUnitMain.\n");
 #endif  // GTEST_FOR_GOOGLE_
   }
@@ -6779,7 +7421,7 @@
   if (test_shard_file != nullptr) {
     FILE* const file = posix::FOpen(test_shard_file, "w");
     if (file == nullptr) {
-      ColoredPrintf(COLOR_RED,
+      ColoredPrintf(GTestColor::kRed,
                     "Could not write to the test shard status file \"%s\" "
                     "specified by the %s environment variable.\n",
                     test_shard_file, kTestShardStatusFile);
@@ -6803,8 +7445,8 @@
     return false;
   }
 
-  const Int32 total_shards = Int32FromEnvOrDie(total_shards_env, -1);
-  const Int32 shard_index = Int32FromEnvOrDie(shard_index_env, -1);
+  const int32_t total_shards = Int32FromEnvOrDie(total_shards_env, -1);
+  const int32_t shard_index = Int32FromEnvOrDie(shard_index_env, -1);
 
   if (total_shards == -1 && shard_index == -1) {
     return false;
@@ -6813,7 +7455,7 @@
       << "Invalid environment variables: you have "
       << kTestShardIndex << " = " << shard_index
       << ", but have left " << kTestTotalShards << " unset.\n";
-    ColoredPrintf(COLOR_RED, "%s", msg.GetString().c_str());
+    ColoredPrintf(GTestColor::kRed, "%s", msg.GetString().c_str());
     fflush(stdout);
     exit(EXIT_FAILURE);
   } else if (total_shards != -1 && shard_index == -1) {
@@ -6821,7 +7463,7 @@
       << "Invalid environment variables: you have "
       << kTestTotalShards << " = " << total_shards
       << ", but have left " << kTestShardIndex << " unset.\n";
-    ColoredPrintf(COLOR_RED, "%s", msg.GetString().c_str());
+    ColoredPrintf(GTestColor::kRed, "%s", msg.GetString().c_str());
     fflush(stdout);
     exit(EXIT_FAILURE);
   } else if (shard_index < 0 || shard_index >= total_shards) {
@@ -6830,7 +7472,7 @@
       << kTestShardIndex << " < " << kTestTotalShards
       << ", but you have " << kTestShardIndex << "=" << shard_index
       << ", " << kTestTotalShards << "=" << total_shards << ".\n";
-    ColoredPrintf(COLOR_RED, "%s", msg.GetString().c_str());
+    ColoredPrintf(GTestColor::kRed, "%s", msg.GetString().c_str());
     fflush(stdout);
     exit(EXIT_FAILURE);
   }
@@ -6841,13 +7483,13 @@
 // Parses the environment variable var as an Int32. If it is unset,
 // returns default_val. If it is not an Int32, prints an error
 // and aborts.
-Int32 Int32FromEnvOrDie(const char* var, Int32 default_val) {
+int32_t Int32FromEnvOrDie(const char* var, int32_t default_val) {
   const char* str_val = posix::GetEnv(var);
   if (str_val == nullptr) {
     return default_val;
   }
 
-  Int32 result;
+  int32_t result;
   if (!ParseInt32(Message() << "The value of environment variable " << var,
                   str_val, &result)) {
     exit(EXIT_FAILURE);
@@ -6856,8 +7498,8 @@
 }
 
 // Given the total number of shards, the shard index, and the test id,
-// returns true iff the test should be run on this shard. The test id is
-// some arbitrary but unique non-negative integer assigned to each test
+// returns true if and only if the test should be run on this shard. The test id
+// is some arbitrary but unique non-negative integer assigned to each test
 // method. Assumes that 0 <= shard_index < total_shards.
 bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) {
   return (test_id % total_shards) == shard_index;
@@ -6871,9 +7513,9 @@
 // https://github.com/google/googletest/blob/master/googletest/docs/advanced.md
 // . Returns the number of tests that should run.
 int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) {
-  const Int32 total_shards = shard_tests == HONOR_SHARDING_PROTOCOL ?
+  const int32_t total_shards = shard_tests == HONOR_SHARDING_PROTOCOL ?
       Int32FromEnvOrDie(kTestTotalShards, -1) : -1;
-  const Int32 shard_index = shard_tests == HONOR_SHARDING_PROTOCOL ?
+  const int32_t shard_index = shard_tests == HONOR_SHARDING_PROTOCOL ?
       Int32FromEnvOrDie(kTestShardIndex, -1) : -1;
 
   // num_runnable_tests are the number of tests that will
@@ -7162,12 +7804,11 @@
   return true;
 }
 
-// Parses a string for an Int32 flag, in the form of
-// "--flag=value".
+// Parses a string for an int32_t flag, in the form of "--flag=value".
 //
 // On success, stores the value of the flag in *value, and returns
 // true.  On failure, returns false without changing *value.
-bool ParseInt32Flag(const char* str, const char* flag, Int32* value) {
+bool ParseInt32Flag(const char* str, const char* flag, int32_t* value) {
   // Gets the value of the flag as a string.
   const char* const value_str = ParseFlagValue(str, flag, false);
 
@@ -7179,8 +7820,7 @@
                     value_str, value);
 }
 
-// Parses a string for a string flag, in the form of
-// "--flag=value".
+// Parses a string for a string flag, in the form of "--flag=value".
 //
 // On success, stores the value of the flag in *value, and returns
 // true.  On failure, returns false without changing *value.
@@ -7222,7 +7862,7 @@
 //   @D    changes to the default terminal text color.
 //
 static void PrintColorEncoded(const char* str) {
-  GTestColor color = COLOR_DEFAULT;  // The current color.
+  GTestColor color = GTestColor::kDefault;  // The current color.
 
   // Conceptually, we split the string into segments divided by escape
   // sequences.  Then we print one segment at a time.  At the end of
@@ -7242,13 +7882,13 @@
     if (ch == '@') {
       ColoredPrintf(color, "@");
     } else if (ch == 'D') {
-      color = COLOR_DEFAULT;
+      color = GTestColor::kDefault;
     } else if (ch == 'R') {
-      color = COLOR_RED;
+      color = GTestColor::kRed;
     } else if (ch == 'G') {
-      color = COLOR_GREEN;
+      color = GTestColor::kGreen;
     } else if (ch == 'Y') {
-      color = COLOR_YELLOW;
+      color = GTestColor::kYellow;
     } else {
       --str;
     }
@@ -7256,98 +7896,126 @@
 }
 
 static const char kColorEncodedHelpMessage[] =
-"This program contains tests written using " GTEST_NAME_ ". You can use the\n"
-"following command line flags to control its behavior:\n"
-"\n"
-"Test Selection:\n"
-"  @G--" GTEST_FLAG_PREFIX_ "list_tests@D\n"
-"      List the names of all tests instead of running them. The name of\n"
-"      TEST(Foo, Bar) is \"Foo.Bar\".\n"
-"  @G--" GTEST_FLAG_PREFIX_ "filter=@YPOSTIVE_PATTERNS"
+    "This program contains tests written using " GTEST_NAME_
+    ". You can use the\n"
+    "following command line flags to control its behavior:\n"
+    "\n"
+    "Test Selection:\n"
+    "  @G--" GTEST_FLAG_PREFIX_
+    "list_tests@D\n"
+    "      List the names of all tests instead of running them. The name of\n"
+    "      TEST(Foo, Bar) is \"Foo.Bar\".\n"
+    "  @G--" GTEST_FLAG_PREFIX_
+    "filter=@YPOSITIVE_PATTERNS"
     "[@G-@YNEGATIVE_PATTERNS]@D\n"
-"      Run only the tests whose name matches one of the positive patterns but\n"
-"      none of the negative patterns. '?' matches any single character; '*'\n"
-"      matches any substring; ':' separates two patterns.\n"
-"  @G--" GTEST_FLAG_PREFIX_ "also_run_disabled_tests@D\n"
-"      Run all disabled tests too.\n"
-"\n"
-"Test Execution:\n"
-"  @G--" GTEST_FLAG_PREFIX_ "repeat=@Y[COUNT]@D\n"
-"      Run the tests repeatedly; use a negative count to repeat forever.\n"
-"  @G--" GTEST_FLAG_PREFIX_ "shuffle@D\n"
-"      Randomize tests' orders on every iteration.\n"
-"  @G--" GTEST_FLAG_PREFIX_ "random_seed=@Y[NUMBER]@D\n"
-"      Random number seed to use for shuffling test orders (between 1 and\n"
-"      99999, or 0 to use a seed based on the current time).\n"
-"\n"
-"Test Output:\n"
-"  @G--" GTEST_FLAG_PREFIX_ "color=@Y(@Gyes@Y|@Gno@Y|@Gauto@Y)@D\n"
-"      Enable/disable colored output. The default is @Gauto@D.\n"
-"  -@G-" GTEST_FLAG_PREFIX_ "print_time=0@D\n"
-"      Don't print the elapsed time of each test.\n"
-"  @G--" GTEST_FLAG_PREFIX_ "output=@Y(@Gjson@Y|@Gxml@Y)[@G:@YDIRECTORY_PATH@G"
-    GTEST_PATH_SEP_ "@Y|@G:@YFILE_PATH]@D\n"
-"      Generate a JSON or XML report in the given directory or with the given\n"
-"      file name. @YFILE_PATH@D defaults to @Gtest_detail.xml@D.\n"
+    "      Run only the tests whose name matches one of the positive patterns "
+    "but\n"
+    "      none of the negative patterns. '?' matches any single character; "
+    "'*'\n"
+    "      matches any substring; ':' separates two patterns.\n"
+    "  @G--" GTEST_FLAG_PREFIX_
+    "also_run_disabled_tests@D\n"
+    "      Run all disabled tests too.\n"
+    "\n"
+    "Test Execution:\n"
+    "  @G--" GTEST_FLAG_PREFIX_
+    "repeat=@Y[COUNT]@D\n"
+    "      Run the tests repeatedly; use a negative count to repeat forever.\n"
+    "  @G--" GTEST_FLAG_PREFIX_
+    "shuffle@D\n"
+    "      Randomize tests' orders on every iteration.\n"
+    "  @G--" GTEST_FLAG_PREFIX_
+    "random_seed=@Y[NUMBER]@D\n"
+    "      Random number seed to use for shuffling test orders (between 1 and\n"
+    "      99999, or 0 to use a seed based on the current time).\n"
+    "\n"
+    "Test Output:\n"
+    "  @G--" GTEST_FLAG_PREFIX_
+    "color=@Y(@Gyes@Y|@Gno@Y|@Gauto@Y)@D\n"
+    "      Enable/disable colored output. The default is @Gauto@D.\n"
+    "  @G--" GTEST_FLAG_PREFIX_
+    "brief=1@D\n"
+    "      Only print test failures.\n"
+    "  @G--" GTEST_FLAG_PREFIX_
+    "print_time=0@D\n"
+    "      Don't print the elapsed time of each test.\n"
+    "  @G--" GTEST_FLAG_PREFIX_
+    "output=@Y(@Gjson@Y|@Gxml@Y)[@G:@YDIRECTORY_PATH@G" GTEST_PATH_SEP_
+    "@Y|@G:@YFILE_PATH]@D\n"
+    "      Generate a JSON or XML report in the given directory or with the "
+    "given\n"
+    "      file name. @YFILE_PATH@D defaults to @Gtest_detail.xml@D.\n"
 # if GTEST_CAN_STREAM_RESULTS_
-"  @G--" GTEST_FLAG_PREFIX_ "stream_result_to=@YHOST@G:@YPORT@D\n"
-"      Stream test results to the given server.\n"
+    "  @G--" GTEST_FLAG_PREFIX_
+    "stream_result_to=@YHOST@G:@YPORT@D\n"
+    "      Stream test results to the given server.\n"
 # endif  // GTEST_CAN_STREAM_RESULTS_
-"\n"
-"Assertion Behavior:\n"
+    "\n"
+    "Assertion Behavior:\n"
 # if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS
-"  @G--" GTEST_FLAG_PREFIX_ "death_test_style=@Y(@Gfast@Y|@Gthreadsafe@Y)@D\n"
-"      Set the default death test style.\n"
+    "  @G--" GTEST_FLAG_PREFIX_
+    "death_test_style=@Y(@Gfast@Y|@Gthreadsafe@Y)@D\n"
+    "      Set the default death test style.\n"
 # endif  // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS
-"  @G--" GTEST_FLAG_PREFIX_ "break_on_failure@D\n"
-"      Turn assertion failures into debugger break-points.\n"
-"  @G--" GTEST_FLAG_PREFIX_ "throw_on_failure@D\n"
-"      Turn assertion failures into C++ exceptions for use by an external\n"
-"      test framework.\n"
-"  @G--" GTEST_FLAG_PREFIX_ "catch_exceptions=0@D\n"
-"      Do not report exceptions as test failures. Instead, allow them\n"
-"      to crash the program or throw a pop-up (on Windows).\n"
-"\n"
-"Except for @G--" GTEST_FLAG_PREFIX_ "list_tests@D, you can alternatively set "
+    "  @G--" GTEST_FLAG_PREFIX_
+    "break_on_failure@D\n"
+    "      Turn assertion failures into debugger break-points.\n"
+    "  @G--" GTEST_FLAG_PREFIX_
+    "throw_on_failure@D\n"
+    "      Turn assertion failures into C++ exceptions for use by an external\n"
+    "      test framework.\n"
+    "  @G--" GTEST_FLAG_PREFIX_
+    "catch_exceptions=0@D\n"
+    "      Do not report exceptions as test failures. Instead, allow them\n"
+    "      to crash the program or throw a pop-up (on Windows).\n"
+    "\n"
+    "Except for @G--" GTEST_FLAG_PREFIX_
+    "list_tests@D, you can alternatively set "
     "the corresponding\n"
-"environment variable of a flag (all letters in upper-case). For example, to\n"
-"disable colored text output, you can either specify @G--" GTEST_FLAG_PREFIX_
+    "environment variable of a flag (all letters in upper-case). For example, "
+    "to\n"
+    "disable colored text output, you can either specify "
+    "@G--" GTEST_FLAG_PREFIX_
     "color=no@D or set\n"
-"the @G" GTEST_FLAG_PREFIX_UPPER_ "COLOR@D environment variable to @Gno@D.\n"
-"\n"
-"For more information, please read the " GTEST_NAME_ " documentation at\n"
-"@G" GTEST_PROJECT_URL_ "@D. If you find a bug in " GTEST_NAME_ "\n"
-"(not one in your own code or tests), please report it to\n"
-"@G<" GTEST_DEV_EMAIL_ ">@D.\n";
+    "the @G" GTEST_FLAG_PREFIX_UPPER_
+    "COLOR@D environment variable to @Gno@D.\n"
+    "\n"
+    "For more information, please read the " GTEST_NAME_
+    " documentation at\n"
+    "@G" GTEST_PROJECT_URL_ "@D. If you find a bug in " GTEST_NAME_
+    "\n"
+    "(not one in your own code or tests), please report it to\n"
+    "@G<" GTEST_DEV_EMAIL_ ">@D.\n";
 
 static bool ParseGoogleTestFlag(const char* const arg) {
   return ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag,
                        &GTEST_FLAG(also_run_disabled_tests)) ||
-      ParseBoolFlag(arg, kBreakOnFailureFlag,
-                    &GTEST_FLAG(break_on_failure)) ||
-      ParseBoolFlag(arg, kCatchExceptionsFlag,
-                    &GTEST_FLAG(catch_exceptions)) ||
-      ParseStringFlag(arg, kColorFlag, &GTEST_FLAG(color)) ||
-      ParseStringFlag(arg, kDeathTestStyleFlag,
-                      &GTEST_FLAG(death_test_style)) ||
-      ParseBoolFlag(arg, kDeathTestUseFork,
-                    &GTEST_FLAG(death_test_use_fork)) ||
-      ParseStringFlag(arg, kFilterFlag, &GTEST_FLAG(filter)) ||
-      ParseStringFlag(arg, kInternalRunDeathTestFlag,
-                      &GTEST_FLAG(internal_run_death_test)) ||
-      ParseBoolFlag(arg, kListTestsFlag, &GTEST_FLAG(list_tests)) ||
-      ParseStringFlag(arg, kOutputFlag, &GTEST_FLAG(output)) ||
-      ParseBoolFlag(arg, kPrintTimeFlag, &GTEST_FLAG(print_time)) ||
-      ParseBoolFlag(arg, kPrintUTF8Flag, &GTEST_FLAG(print_utf8)) ||
-      ParseInt32Flag(arg, kRandomSeedFlag, &GTEST_FLAG(random_seed)) ||
-      ParseInt32Flag(arg, kRepeatFlag, &GTEST_FLAG(repeat)) ||
-      ParseBoolFlag(arg, kShuffleFlag, &GTEST_FLAG(shuffle)) ||
-      ParseInt32Flag(arg, kStackTraceDepthFlag,
-                     &GTEST_FLAG(stack_trace_depth)) ||
-      ParseStringFlag(arg, kStreamResultToFlag,
-                      &GTEST_FLAG(stream_result_to)) ||
-      ParseBoolFlag(arg, kThrowOnFailureFlag,
-                    &GTEST_FLAG(throw_on_failure));
+         ParseBoolFlag(arg, kBreakOnFailureFlag,
+                       &GTEST_FLAG(break_on_failure)) ||
+         ParseBoolFlag(arg, kCatchExceptionsFlag,
+                       &GTEST_FLAG(catch_exceptions)) ||
+         ParseStringFlag(arg, kColorFlag, &GTEST_FLAG(color)) ||
+         ParseStringFlag(arg, kDeathTestStyleFlag,
+                         &GTEST_FLAG(death_test_style)) ||
+         ParseBoolFlag(arg, kDeathTestUseFork,
+                       &GTEST_FLAG(death_test_use_fork)) ||
+         ParseBoolFlag(arg, kFailFast, &GTEST_FLAG(fail_fast)) ||
+         ParseStringFlag(arg, kFilterFlag, &GTEST_FLAG(filter)) ||
+         ParseStringFlag(arg, kInternalRunDeathTestFlag,
+                         &GTEST_FLAG(internal_run_death_test)) ||
+         ParseBoolFlag(arg, kListTestsFlag, &GTEST_FLAG(list_tests)) ||
+         ParseStringFlag(arg, kOutputFlag, &GTEST_FLAG(output)) ||
+         ParseBoolFlag(arg, kBriefFlag, &GTEST_FLAG(brief)) ||
+         ParseBoolFlag(arg, kPrintTimeFlag, &GTEST_FLAG(print_time)) ||
+         ParseBoolFlag(arg, kPrintUTF8Flag, &GTEST_FLAG(print_utf8)) ||
+         ParseInt32Flag(arg, kRandomSeedFlag, &GTEST_FLAG(random_seed)) ||
+         ParseInt32Flag(arg, kRepeatFlag, &GTEST_FLAG(repeat)) ||
+         ParseBoolFlag(arg, kShuffleFlag, &GTEST_FLAG(shuffle)) ||
+         ParseInt32Flag(arg, kStackTraceDepthFlag,
+                        &GTEST_FLAG(stack_trace_depth)) ||
+         ParseStringFlag(arg, kStreamResultToFlag,
+                         &GTEST_FLAG(stream_result_to)) ||
+         ParseBoolFlag(arg, kThrowOnFailureFlag, &GTEST_FLAG(throw_on_failure));
 }
 
 #if GTEST_USE_OWN_FLAGFILE_FLAG_
@@ -7430,7 +8098,7 @@
 void ParseGoogleTestFlagsOnly(int* argc, char** argv) {
   ParseGoogleTestFlagsOnlyImpl(argc, argv);
 
-  // Fix the value of *_NSGetArgc() on macOS, but iff
+  // Fix the value of *_NSGetArgc() on macOS, but if and only if
   // *_NSGetArgv() == argv
   // Only applicable to char** version of argv
 #if GTEST_OS_MAC
@@ -7517,20 +8185,31 @@
 std::string TempDir() {
 #if defined(GTEST_CUSTOM_TEMPDIR_FUNCTION_)
   return GTEST_CUSTOM_TEMPDIR_FUNCTION_();
-#endif
-
-#if GTEST_OS_WINDOWS_MOBILE
+#elif GTEST_OS_WINDOWS_MOBILE
   return "\\temp\\";
 #elif GTEST_OS_WINDOWS
   const char* temp_dir = internal::posix::GetEnv("TEMP");
-  if (temp_dir == nullptr || temp_dir[0] == '\0')
+  if (temp_dir == nullptr || temp_dir[0] == '\0') {
     return "\\temp\\";
-  else if (temp_dir[strlen(temp_dir) - 1] == '\\')
+  } else if (temp_dir[strlen(temp_dir) - 1] == '\\') {
     return temp_dir;
-  else
+  } else {
     return std::string(temp_dir) + "\\";
+  }
 #elif GTEST_OS_LINUX_ANDROID
-  return "/sdcard/";
+  const char* temp_dir = internal::posix::GetEnv("TEST_TMPDIR");
+  if (temp_dir == nullptr || temp_dir[0] == '\0') {
+    return "/data/local/tmp/";
+  } else {
+    return temp_dir;
+  }
+#elif GTEST_OS_LINUX
+  const char* temp_dir = internal::posix::GetEnv("TEST_TMPDIR");
+  if (temp_dir == nullptr || temp_dir[0] == '\0') {
+    return "/tmp/";
+  } else {
+    return temp_dir;
+  }
 #else
   return "/tmp/";
 #endif  // GTEST_OS_WINDOWS_MOBILE
@@ -7589,6 +8268,7 @@
 // This file implements death tests.
 
 
+#include <functional>
 #include <utility>
 
 
@@ -7623,6 +8303,7 @@
 #  include <lib/fdio/fd.h>
 #  include <lib/fdio/io.h>
 #  include <lib/fdio/spawn.h>
+#  include <lib/zx/channel.h>
 #  include <lib/zx/port.h>
 #  include <lib/zx/process.h>
 #  include <lib/zx/socket.h>
@@ -7673,8 +8354,8 @@
     "Indicates the file, line number, temporal index of "
     "the single death test to run, and a file descriptor to "
     "which a success code may be sent, all separated by "
-    "the '|' characters.  This flag is specified if and only if the current "
-    "process is a sub-process launched for running a thread-safe "
+    "the '|' characters.  This flag is specified if and only if the "
+    "current process is a sub-process launched for running a thread-safe "
     "death test.  FOR INTERNAL USE ONLY.");
 }  // namespace internal
 
@@ -7798,7 +8479,7 @@
     msg << "detected " << thread_count << " threads.";
   }
   msg << " See "
-         "https://github.com/google/googletest/blob/master/googletest/docs/"
+         "https://github.com/google/googletest/blob/master/docs/"
          "advanced.md#death-tests-and-threads"
       << " for more explanation and suggested solutions, especially if"
       << " this is the last message you see before your test times out.";
@@ -8114,8 +8795,8 @@
 //   status_ok: true if exit_status is acceptable in the context of
 //              this particular death test, which fails if it is false
 //
-// Returns true iff all of the above conditions are met.  Otherwise, the
-// first failing condition, in the order given above, is the one that is
+// Returns true if and only if all of the above conditions are met.  Otherwise,
+// the first failing condition, in the order given above, is the one that is
 // reported. Also sets the last death test message string.
 bool DeathTestImpl::Passed(bool status_ok) {
   if (!spawned())
@@ -8383,7 +9064,7 @@
   std::string captured_stderr_;
 
   zx::process child_process_;
-  zx::port port_;
+  zx::channel exception_channel_;
   zx::socket stderr_socket_;
 };
 
@@ -8415,7 +9096,7 @@
   }
 
   int size() {
-    return args_.size() - 1;
+    return static_cast<int>(args_.size()) - 1;
   }
 
  private:
@@ -8428,43 +9109,52 @@
 int FuchsiaDeathTest::Wait() {
   const int kProcessKey = 0;
   const int kSocketKey = 1;
+  const int kExceptionKey = 2;
 
   if (!spawned())
     return 0;
 
-  // Register to wait for the child process to terminate.
+  // Create a port to wait for socket/task/exception events.
   zx_status_t status_zx;
-  status_zx = child_process_.wait_async(
-      port_, kProcessKey, ZX_PROCESS_TERMINATED, ZX_WAIT_ASYNC_ONCE);
+  zx::port port;
+  status_zx = zx::port::create(0, &port);
   GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
+
+  // Register to wait for the child process to terminate.
+  status_zx = child_process_.wait_async(
+      port, kProcessKey, ZX_PROCESS_TERMINATED, 0);
+  GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
+
   // Register to wait for the socket to be readable or closed.
   status_zx = stderr_socket_.wait_async(
-      port_, kSocketKey, ZX_SOCKET_READABLE | ZX_SOCKET_PEER_CLOSED,
-      ZX_WAIT_ASYNC_REPEATING);
+      port, kSocketKey, ZX_SOCKET_READABLE | ZX_SOCKET_PEER_CLOSED, 0);
+  GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
+
+  // Register to wait for an exception.
+  status_zx = exception_channel_.wait_async(
+      port, kExceptionKey, ZX_CHANNEL_READABLE, 0);
   GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
 
   bool process_terminated = false;
   bool socket_closed = false;
   do {
     zx_port_packet_t packet = {};
-    status_zx = port_.wait(zx::time::infinite(), &packet);
+    status_zx = port.wait(zx::time::infinite(), &packet);
     GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
 
-    if (packet.key == kProcessKey) {
-      if (ZX_PKT_IS_EXCEPTION(packet.type)) {
-        // Process encountered an exception. Kill it directly rather than
-        // letting other handlers process the event. We will get a second
-        // kProcessKey event when the process actually terminates.
-        status_zx = child_process_.kill();
-        GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
-      } else {
-        // Process terminated.
-        GTEST_DEATH_TEST_CHECK_(ZX_PKT_IS_SIGNAL_ONE(packet.type));
-        GTEST_DEATH_TEST_CHECK_(packet.signal.observed & ZX_PROCESS_TERMINATED);
-        process_terminated = true;
-      }
+    if (packet.key == kExceptionKey) {
+      // Process encountered an exception. Kill it directly rather than
+      // letting other handlers process the event. We will get a kProcessKey
+      // event when the process actually terminates.
+      status_zx = child_process_.kill();
+      GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
+    } else if (packet.key == kProcessKey) {
+      // Process terminated.
+      GTEST_DEATH_TEST_CHECK_(ZX_PKT_IS_SIGNAL_ONE(packet.type));
+      GTEST_DEATH_TEST_CHECK_(packet.signal.observed & ZX_PROCESS_TERMINATED);
+      process_terminated = true;
     } else if (packet.key == kSocketKey) {
-      GTEST_DEATH_TEST_CHECK_(ZX_PKT_IS_SIGNAL_REP(packet.type));
+      GTEST_DEATH_TEST_CHECK_(ZX_PKT_IS_SIGNAL_ONE(packet.type));
       if (packet.signal.observed & ZX_SOCKET_READABLE) {
         // Read data from the socket.
         constexpr size_t kBufferSize = 1024;
@@ -8481,6 +9171,9 @@
           socket_closed = true;
         } else {
           GTEST_DEATH_TEST_CHECK_(status_zx == ZX_ERR_SHOULD_WAIT);
+          status_zx = stderr_socket_.wait_async(
+              port, kSocketKey, ZX_SOCKET_READABLE | ZX_SOCKET_PEER_CLOSED, 0);
+          GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
         }
       } else {
         GTEST_DEATH_TEST_CHECK_(packet.signal.observed & ZX_SOCKET_PEER_CLOSED);
@@ -8492,12 +9185,12 @@
   ReadAndInterpretStatusByte();
 
   zx_info_process_t buffer;
-  status_zx = child_process_.get_info(
-      ZX_INFO_PROCESS, &buffer, sizeof(buffer), nullptr, nullptr);
+  status_zx = child_process_.get_info(ZX_INFO_PROCESS, &buffer, sizeof(buffer),
+                                      nullptr, nullptr);
   GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
 
-  GTEST_DEATH_TEST_CHECK_(buffer.exited);
-  set_status(buffer.return_code);
+  GTEST_DEATH_TEST_CHECK_(buffer.flags & ZX_INFO_PROCESS_FLAG_EXITED);
+  set_status(static_cast<int>(buffer.return_code));
   return status();
 }
 
@@ -8540,16 +9233,16 @@
   // Build the pipe for communication with the child.
   zx_status_t status;
   zx_handle_t child_pipe_handle;
-  uint32_t type;
-  status = fdio_pipe_half(&child_pipe_handle, &type);
-  GTEST_DEATH_TEST_CHECK_(status >= 0);
-  set_read_fd(status);
+  int child_pipe_fd;
+  status = fdio_pipe_half(&child_pipe_fd, &child_pipe_handle);
+  GTEST_DEATH_TEST_CHECK_(status == ZX_OK);
+  set_read_fd(child_pipe_fd);
 
   // Set the pipe handle for the child.
   fdio_spawn_action_t spawn_actions[2] = {};
   fdio_spawn_action_t* add_handle_action = &spawn_actions[0];
   add_handle_action->action = FDIO_SPAWN_ACTION_ADD_HANDLE;
-  add_handle_action->h.id = PA_HND(type, kFuchsiaReadPipeFd);
+  add_handle_action->h.id = PA_HND(PA_FD, kFuchsiaReadPipeFd);
   add_handle_action->h.handle = child_pipe_handle;
 
   // Create a socket pair will be used to receive the child process' stderr.
@@ -8581,12 +9274,11 @@
       child_job, ZX_JOB_POL_RELATIVE, ZX_JOB_POL_BASIC, &policy, 1);
   GTEST_DEATH_TEST_CHECK_(status == ZX_OK);
 
-  // Create an exception port and attach it to the |child_job|, to allow
+  // Create an exception channel attached to the |child_job|, to allow
   // us to suppress the system default exception handler from firing.
-  status = zx::port::create(0, &port_);
-  GTEST_DEATH_TEST_CHECK_(status == ZX_OK);
-  status = zx_task_bind_exception_port(
-      child_job, port_.get(), 0 /* key */, 0 /*options */);
+  status =
+      zx_task_create_exception_channel(
+          child_job, 0, exception_channel_.reset_and_get_address());
   GTEST_DEATH_TEST_CHECK_(status == ZX_OK);
 
   // Spawn the child process.
@@ -8763,21 +9455,9 @@
   int close_fd;       // File descriptor to close; the read end of a pipe
 };
 
-#  if GTEST_OS_MAC
-inline char** GetEnviron() {
-  // When Google Test is built as a framework on MacOS X, the environ variable
-  // is unavailable. Apple's documentation (man environ) recommends using
-  // _NSGetEnviron() instead.
-  return *_NSGetEnviron();
-}
-#  else
-// Some POSIX platforms expect you to declare environ. extern "C" makes
-// it reside in the global namespace.
+#  if GTEST_OS_QNX
 extern "C" char** environ;
-inline char** GetEnviron() { return environ; }
-#  endif  // GTEST_OS_MAC
-
-#  if !GTEST_OS_QNX
+#  else  // GTEST_OS_QNX
 // The main function for a threadsafe-style death test child process.
 // This function is called in a clone()-ed process and thus must avoid
 // any potentially unsafe operations like malloc or libc functions.
@@ -8797,18 +9477,18 @@
     return EXIT_FAILURE;
   }
 
-  // We can safely call execve() as it's a direct system call.  We
+  // We can safely call execv() as it's almost a direct system call. We
   // cannot use execvp() as it's a libc function and thus potentially
-  // unsafe.  Since execve() doesn't search the PATH, the user must
+  // unsafe.  Since execv() doesn't search the PATH, the user must
   // invoke the test program via a valid path that contains at least
   // one path separator.
-  execve(args->argv[0], args->argv, GetEnviron());
-  DeathTestAbort(std::string("execve(") + args->argv[0] + ", ...) in " +
+  execv(args->argv[0], args->argv);
+  DeathTestAbort(std::string("execv(") + args->argv[0] + ", ...) in " +
                  original_dir + " failed: " +
                  GetLastErrnoDescription());
   return EXIT_FAILURE;
 }
-#  endif  // !GTEST_OS_QNX
+#  endif  // GTEST_OS_QNX
 
 #  if GTEST_HAS_CLONE
 // Two utility routines that together determine the direction the stack
@@ -8822,15 +9502,24 @@
 // correct answer.
 static void StackLowerThanAddress(const void* ptr,
                                   bool* result) GTEST_NO_INLINE_;
+// Make sure sanitizers do not tamper with the stack here.
+// Ideally, we want to use `__builtin_frame_address` instead of a local variable
+// address with sanitizer disabled, but it does not work when the
+// compiler optimizes the stack frame out, which happens on PowerPC targets.
+// HWAddressSanitizer add a random tag to the MSB of the local variable address,
+// making comparison result unpredictable.
+GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
+GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_
 static void StackLowerThanAddress(const void* ptr, bool* result) {
-  int dummy;
-  *result = (&dummy < ptr);
+  int dummy = 0;
+  *result = std::less<const void*>()(&dummy, ptr);
 }
 
 // Make sure AddressSanitizer does not tamper with the stack here.
 GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
+GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_
 static bool StackGrowsDown() {
-  int dummy;
+  int dummy = 0;
   bool result;
   StackLowerThanAddress(&dummy, &result);
   return result;
@@ -8873,8 +9562,7 @@
                                         fd_flags | FD_CLOEXEC));
   struct inheritance inherit = {0};
   // spawn is a system call.
-  child_pid =
-      spawn(args.argv[0], 0, nullptr, &inherit, args.argv, GetEnviron());
+  child_pid = spawn(args.argv[0], 0, nullptr, &inherit, args.argv, environ);
   // Restores the current working directory.
   GTEST_DEATH_TEST_CHECK_(fchdir(cwd_fd) != -1);
   GTEST_DEATH_TEST_CHECK_SYSCALL_(close(cwd_fd));
@@ -8898,7 +9586,7 @@
 
   if (!use_fork) {
     static const bool stack_grows_down = StackGrowsDown();
-    const size_t stack_size = getpagesize();
+    const auto stack_size = static_cast<size_t>(getpagesize() * 2);
     // MMAP_ANONYMOUS is not defined on Mac, so we use MAP_ANON instead.
     void* const stack = mmap(nullptr, stack_size, PROT_READ | PROT_WRITE,
                              MAP_ANON | MAP_PRIVATE, -1, 0);
@@ -8914,8 +9602,9 @@
     void* const stack_top =
         static_cast<char*>(stack) +
             (stack_grows_down ? stack_size - kMaxStackAlignment : 0);
-    GTEST_DEATH_TEST_CHECK_(stack_size > kMaxStackAlignment &&
-        reinterpret_cast<intptr_t>(stack_top) % kMaxStackAlignment == 0);
+    GTEST_DEATH_TEST_CHECK_(
+        static_cast<size_t>(stack_size) > kMaxStackAlignment &&
+        reinterpret_cast<uintptr_t>(stack_top) % kMaxStackAlignment == 0);
 
     child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args);
 
@@ -9274,9 +9963,10 @@
 
 // Returns the current working directory, or "" if unsuccessful.
 FilePath FilePath::GetCurrentDir() {
-#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || \
-    GTEST_OS_WINDOWS_RT || ARDUINO
-  // Windows CE and Arduino don't have a current directory, so we just return
+#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE ||         \
+    GTEST_OS_WINDOWS_RT || GTEST_OS_ESP8266 || GTEST_OS_ESP32 || \
+    GTEST_OS_XTENSA
+  // These platforms do not have a current directory, so we just return
   // something reasonable.
   return FilePath(kCurrentDirectoryString);
 #elif GTEST_OS_WINDOWS
@@ -9345,7 +10035,7 @@
   const char* const last_sep = FindLastPathSeparator();
   std::string dir;
   if (last_sep) {
-    dir = std::string(c_str(), last_sep + 1 - c_str());
+    dir = std::string(c_str(), static_cast<size_t>(last_sep + 1 - c_str()));
   } else {
     dir = kCurrentDirectoryString;
   }
@@ -9391,7 +10081,7 @@
   delete [] unicode;
   return attributes != kInvalidFileAttributes;
 #else
-  posix::StatStruct file_stat;
+  posix::StatStruct file_stat{};
   return posix::Stat(pathname_.c_str(), &file_stat) == 0;
 #endif  // GTEST_OS_WINDOWS_MOBILE
 }
@@ -9418,7 +10108,7 @@
     result = true;
   }
 #else
-  posix::StatStruct file_stat;
+  posix::StatStruct file_stat{};
   result = posix::Stat(path.c_str(), &file_stat) == 0 &&
       posix::IsDir(file_stat);
 #endif  // GTEST_OS_WINDOWS_MOBILE
@@ -9505,6 +10195,9 @@
   delete [] unicode;
 #elif GTEST_OS_WINDOWS
   int result = _mkdir(pathname_.c_str());
+#elif GTEST_OS_ESP8266 || GTEST_OS_XTENSA
+  // do nothing
+  int result = 0;
 #else
   int result = mkdir(pathname_.c_str(), 0777);
 #endif  // GTEST_OS_WINDOWS_MOBILE
@@ -9528,33 +10221,19 @@
 // For example, "bar///foo" becomes "bar/foo". Does not eliminate other
 // redundancies that might be in a pathname involving "." or "..".
 void FilePath::Normalize() {
-  if (pathname_.c_str() == nullptr) {
-    pathname_ = "";
-    return;
-  }
-  const char* src = pathname_.c_str();
-  char* const dest = new char[pathname_.length() + 1];
-  char* dest_ptr = dest;
-  memset(dest_ptr, 0, pathname_.length() + 1);
+  auto out = pathname_.begin();
 
-  while (*src != '\0') {
-    *dest_ptr = *src;
-    if (!IsPathSeparator(*src)) {
-      src++;
+  for (const char character : pathname_) {
+    if (!IsPathSeparator(character)) {
+      *(out++) = character;
+    } else if (out == pathname_.begin() || *std::prev(out) != kPathSeparator) {
+      *(out++) = kPathSeparator;
     } else {
-#if GTEST_HAS_ALT_PATH_SEP_
-      if (*dest_ptr == kAlternatePathSeparator) {
-        *dest_ptr = kPathSeparator;
-      }
-#endif
-      while (IsPathSeparator(*src))
-        src++;
+      continue;
     }
-    dest_ptr++;
   }
-  *dest_ptr = '\0';
-  pathname_ = dest;
-  delete[] dest;
+
+  pathname_.erase(out, pathname_.end());
 }
 
 }  // namespace internal
@@ -9602,14 +10281,6 @@
 // equal to s.
 Matcher<const std::string&>::Matcher(const std::string& s) { *this = Eq(s); }
 
-#if GTEST_HAS_GLOBAL_STRING
-// Constructs a matcher that matches a const std::string& whose value is
-// equal to s.
-Matcher<const std::string&>::Matcher(const ::string& s) {
-  *this = Eq(static_cast<std::string>(s));
-}
-#endif  // GTEST_HAS_GLOBAL_STRING
-
 // Constructs a matcher that matches a const std::string& whose value is
 // equal to s.
 Matcher<const std::string&>::Matcher(const char* s) {
@@ -9620,92 +10291,45 @@
 // s.
 Matcher<std::string>::Matcher(const std::string& s) { *this = Eq(s); }
 
-#if GTEST_HAS_GLOBAL_STRING
-// Constructs a matcher that matches a std::string whose value is equal to
-// s.
-Matcher<std::string>::Matcher(const ::string& s) {
-  *this = Eq(static_cast<std::string>(s));
-}
-#endif  // GTEST_HAS_GLOBAL_STRING
-
 // Constructs a matcher that matches a std::string whose value is equal to
 // s.
 Matcher<std::string>::Matcher(const char* s) { *this = Eq(std::string(s)); }
 
-#if GTEST_HAS_GLOBAL_STRING
-// Constructs a matcher that matches a const ::string& whose value is
+#if GTEST_INTERNAL_HAS_STRING_VIEW
+// Constructs a matcher that matches a const StringView& whose value is
 // equal to s.
-Matcher<const ::string&>::Matcher(const std::string& s) {
-  *this = Eq(static_cast<::string>(s));
-}
-
-// Constructs a matcher that matches a const ::string& whose value is
-// equal to s.
-Matcher<const ::string&>::Matcher(const ::string& s) { *this = Eq(s); }
-
-// Constructs a matcher that matches a const ::string& whose value is
-// equal to s.
-Matcher<const ::string&>::Matcher(const char* s) { *this = Eq(::string(s)); }
-
-// Constructs a matcher that matches a ::string whose value is equal to s.
-Matcher<::string>::Matcher(const std::string& s) {
-  *this = Eq(static_cast<::string>(s));
-}
-
-// Constructs a matcher that matches a ::string whose value is equal to s.
-Matcher<::string>::Matcher(const ::string& s) { *this = Eq(s); }
-
-// Constructs a matcher that matches a string whose value is equal to s.
-Matcher<::string>::Matcher(const char* s) { *this = Eq(::string(s)); }
-#endif  // GTEST_HAS_GLOBAL_STRING
-
-#if GTEST_HAS_ABSL
-// Constructs a matcher that matches a const absl::string_view& whose value is
-// equal to s.
-Matcher<const absl::string_view&>::Matcher(const std::string& s) {
+Matcher<const internal::StringView&>::Matcher(const std::string& s) {
   *this = Eq(s);
 }
 
-#if GTEST_HAS_GLOBAL_STRING
-// Constructs a matcher that matches a const absl::string_view& whose value is
+// Constructs a matcher that matches a const StringView& whose value is
 // equal to s.
-Matcher<const absl::string_view&>::Matcher(const ::string& s) { *this = Eq(s); }
-#endif  // GTEST_HAS_GLOBAL_STRING
+Matcher<const internal::StringView&>::Matcher(const char* s) {
+  *this = Eq(std::string(s));
+}
 
-// Constructs a matcher that matches a const absl::string_view& whose value is
+// Constructs a matcher that matches a const StringView& whose value is
 // equal to s.
-Matcher<const absl::string_view&>::Matcher(const char* s) {
+Matcher<const internal::StringView&>::Matcher(internal::StringView s) {
   *this = Eq(std::string(s));
 }
 
-// Constructs a matcher that matches a const absl::string_view& whose value is
-// equal to s.
-Matcher<const absl::string_view&>::Matcher(absl::string_view s) {
+// Constructs a matcher that matches a StringView whose value is equal to
+// s.
+Matcher<internal::StringView>::Matcher(const std::string& s) { *this = Eq(s); }
+
+// Constructs a matcher that matches a StringView whose value is equal to
+// s.
+Matcher<internal::StringView>::Matcher(const char* s) {
   *this = Eq(std::string(s));
 }
 
-// Constructs a matcher that matches a absl::string_view whose value is equal to
+// Constructs a matcher that matches a StringView whose value is equal to
 // s.
-Matcher<absl::string_view>::Matcher(const std::string& s) { *this = Eq(s); }
-
-#if GTEST_HAS_GLOBAL_STRING
-// Constructs a matcher that matches a absl::string_view whose value is equal to
-// s.
-Matcher<absl::string_view>::Matcher(const ::string& s) { *this = Eq(s); }
-#endif  // GTEST_HAS_GLOBAL_STRING
-
-// Constructs a matcher that matches a absl::string_view whose value is equal to
-// s.
-Matcher<absl::string_view>::Matcher(const char* s) {
+Matcher<internal::StringView>::Matcher(internal::StringView s) {
   *this = Eq(std::string(s));
 }
-
-// Constructs a matcher that matches a absl::string_view whose value is equal to
-// s.
-Matcher<absl::string_view>::Matcher(absl::string_view s) {
-  *this = Eq(std::string(s));
-}
-#endif  // GTEST_HAS_ABSL
+#endif  // GTEST_INTERNAL_HAS_STRING_VIEW
 
 }  // namespace testing
 // Copyright 2008, Google Inc.
@@ -9743,6 +10367,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <cstdint>
 #include <fstream>
 #include <memory>
 
@@ -9821,7 +10446,7 @@
 size_t GetThreadCount() {
   const std::string filename =
       (Message() << "/proc/" << getpid() << "/stat").GetString();
-  return ReadProcFileField<int>(filename, 19);
+  return ReadProcFileField<size_t>(filename, 19);
 }
 
 #elif GTEST_OS_MAC
@@ -9879,7 +10504,7 @@
   if (sysctl(mib, miblen, &info, &size, NULL, 0)) {
     return 0;
   }
-  return KP_NLWP(info);
+  return static_cast<size_t>(KP_NLWP(info));
 }
 #elif GTEST_OS_OPENBSD
 
@@ -9901,7 +10526,8 @@
   if (sysctl(mib, miblen, NULL, &size, NULL, 0)) {
     return 0;
   }
-  mib[5] = size / mib[4];
+
+  mib[5] = static_cast<int>(size / static_cast<size_t>(mib[4]));
 
   // populate array of structs
   struct kinfo_proc info[mib[5]];
@@ -9910,8 +10536,8 @@
   }
 
   // exclude empty members
-  int nthreads = 0;
-  for (int i = 0; i < size / mib[4]; i++) {
+  size_t nthreads = 0;
+  for (size_t i = 0; i < size / static_cast<size_t>(mib[4]); i++) {
     if (info[i].p_tid != -1)
       nthreads++;
   }
@@ -9983,7 +10609,7 @@
 #if GTEST_IS_THREADSAFE && GTEST_OS_WINDOWS
 
 void SleepMilliseconds(int n) {
-  ::Sleep(n);
+  ::Sleep(static_cast<DWORD>(n));
 }
 
 AutoHandle::AutoHandle()
@@ -10084,6 +10710,7 @@
 
 namespace {
 
+#ifdef _MSC_VER
 // Use the RAII idiom to flag mem allocs that are intentionally never
 // deallocated. The motivation is to silence the false positive mem leaks
 // that are reported by the debug version of MS's CRT which can only detect
@@ -10096,19 +10723,15 @@
 {
  public:
   MemoryIsNotDeallocated() : old_crtdbg_flag_(0) {
-#ifdef _MSC_VER
     old_crtdbg_flag_ = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
     // Set heap allocation block type to _IGNORE_BLOCK so that MS debug CRT
     // doesn't report mem leak if there's no matching deallocation.
     _CrtSetDbgFlag(old_crtdbg_flag_ & ~_CRTDBG_ALLOC_MEM_DF);
-#endif  //  _MSC_VER
   }
 
   ~MemoryIsNotDeallocated() {
-#ifdef _MSC_VER
     // Restore the original _CRTDBG_ALLOC_MEM_DF flag
     _CrtSetDbgFlag(old_crtdbg_flag_);
-#endif  //  _MSC_VER
   }
 
  private:
@@ -10116,6 +10739,7 @@
 
   GTEST_DISALLOW_COPY_AND_ASSIGN_(MemoryIsNotDeallocated);
 };
+#endif  // _MSC_VER
 
 }  // namespace
 
@@ -10131,7 +10755,9 @@
         owner_thread_id_ = 0;
         {
           // Use RAII to flag that following mem alloc is never deallocated.
+#ifdef _MSC_VER
           MemoryIsNotDeallocated memory_is_not_deallocated;
+#endif  // _MSC_VER
           critical_section_ = new CRITICAL_SECTION;
         }
         ::InitializeCriticalSection(critical_section_);
@@ -10240,6 +10866,9 @@
   // Returns a value that can be used to identify the thread from other threads.
   static ThreadLocalValueHolderBase* GetValueOnCurrentThread(
       const ThreadLocalBase* thread_local_instance) {
+#ifdef _MSC_VER
+    MemoryIsNotDeallocated memory_is_not_deallocated;
+#endif  // _MSC_VER
     DWORD current_thread = ::GetCurrentThreadId();
     MutexLock lock(&mutex_);
     ThreadIdToThreadLocals* const thread_to_thread_locals =
@@ -10374,7 +11003,9 @@
   // Returns map of thread local instances.
   static ThreadIdToThreadLocals* GetThreadLocalsMapLocked() {
     mutex_.AssertHeld();
+#ifdef _MSC_VER
     MemoryIsNotDeallocated memory_is_not_deallocated;
+#endif  // _MSC_VER
     static ThreadIdToThreadLocals* map = new ThreadIdToThreadLocals();
     return map;
   }
@@ -10385,8 +11016,8 @@
   static Mutex thread_map_mutex_;
 };
 
-Mutex ThreadLocalRegistryImpl::mutex_(Mutex::kStaticMutex);
-Mutex ThreadLocalRegistryImpl::thread_map_mutex_(Mutex::kStaticMutex);
+Mutex ThreadLocalRegistryImpl::mutex_(Mutex::kStaticMutex);  // NOLINT
+Mutex ThreadLocalRegistryImpl::thread_map_mutex_(Mutex::kStaticMutex);  // NOLINT
 
 ThreadLocalValueHolderBase* ThreadLocalRegistry::GetValueOnCurrentThread(
       const ThreadLocalBase* thread_local_instance) {
@@ -10417,7 +11048,7 @@
   free(const_cast<char*>(pattern_));
 }
 
-// Returns true iff regular expression re matches the entire str.
+// Returns true if and only if regular expression re matches the entire str.
 bool RE::FullMatch(const char* str, const RE& re) {
   if (!re.is_valid_) return false;
 
@@ -10425,8 +11056,8 @@
   return regexec(&re.full_regex_, str, 1, &match, 0) == 0;
 }
 
-// Returns true iff regular expression re matches a substring of str
-// (including str itself).
+// Returns true if and only if regular expression re matches a substring of
+// str (including str itself).
 bool RE::PartialMatch(const char* str, const RE& re) {
   if (!re.is_valid_) return false;
 
@@ -10466,14 +11097,14 @@
 
 #elif GTEST_USES_SIMPLE_RE
 
-// Returns true iff ch appears anywhere in str (excluding the
+// Returns true if and only if ch appears anywhere in str (excluding the
 // terminating '\0' character).
 bool IsInSet(char ch, const char* str) {
   return ch != '\0' && strchr(str, ch) != nullptr;
 }
 
-// Returns true iff ch belongs to the given classification.  Unlike
-// similar functions in <ctype.h>, these aren't affected by the
+// Returns true if and only if ch belongs to the given classification.
+// Unlike similar functions in <ctype.h>, these aren't affected by the
 // current locale.
 bool IsAsciiDigit(char ch) { return '0' <= ch && ch <= '9'; }
 bool IsAsciiPunct(char ch) {
@@ -10486,13 +11117,13 @@
       ('0' <= ch && ch <= '9') || ch == '_';
 }
 
-// Returns true iff "\\c" is a supported escape sequence.
+// Returns true if and only if "\\c" is a supported escape sequence.
 bool IsValidEscape(char c) {
   return (IsAsciiPunct(c) || IsInSet(c, "dDfnrsStvwW"));
 }
 
-// Returns true iff the given atom (specified by escaped and pattern)
-// matches ch.  The result is undefined if the atom is invalid.
+// Returns true if and only if the given atom (specified by escaped and
+// pattern) matches ch.  The result is undefined if the atom is invalid.
 bool AtomMatchesChar(bool escaped, char pattern_char, char ch) {
   if (escaped) {  // "\\p" where p is pattern_char.
     switch (pattern_char) {
@@ -10530,7 +11161,7 @@
 
   bool is_valid = true;
 
-  // True iff ?, *, or + can follow the previous atom.
+  // True if and only if ?, *, or + can follow the previous atom.
   bool prev_repeatable = false;
   for (int i = 0; regex[i]; i++) {
     if (regex[i] == '\\') {  // An escape sequence
@@ -10606,8 +11237,8 @@
   return false;
 }
 
-// Returns true iff regex matches a prefix of str.  regex must be a
-// valid simple regular expression and not start with "^", or the
+// Returns true if and only if regex matches a prefix of str. regex must
+// be a valid simple regular expression and not start with "^", or the
 // result is undefined.
 bool MatchRegexAtHead(const char* regex, const char* str) {
   if (*regex == '\0')  // An empty regex matches a prefix of anything.
@@ -10637,8 +11268,8 @@
   }
 }
 
-// Returns true iff regex matches any substring of str.  regex must be
-// a valid simple regular expression, or the result is undefined.
+// Returns true if and only if regex matches any substring of str.  regex must
+// be a valid simple regular expression, or the result is undefined.
 //
 // The algorithm is recursive, but the recursion depth doesn't exceed
 // the regex length, so we won't need to worry about running out of
@@ -10666,13 +11297,13 @@
   free(const_cast<char*>(full_pattern_));
 }
 
-// Returns true iff regular expression re matches the entire str.
+// Returns true if and only if regular expression re matches the entire str.
 bool RE::FullMatch(const char* str, const RE& re) {
   return re.is_valid_ && MatchRegexAnywhere(re.full_pattern_, str);
 }
 
-// Returns true iff regular expression re matches a substring of str
-// (including str itself).
+// Returns true if and only if regular expression re matches a substring of
+// str (including str itself).
 bool RE::PartialMatch(const char* str, const RE& re) {
   return re.is_valid_ && MatchRegexAnywhere(re.pattern_, str);
 }
@@ -10792,9 +11423,9 @@
     filename_ = temp_file_path;
 # else
     // There's no guarantee that a test has write access to the current
-    // directory, so we create the temporary file in the /tmp directory
-    // instead. We use /tmp on most systems, and /sdcard on Android.
-    // That's because Android doesn't have /tmp.
+    // directory, so we create the temporary file in a temporary directory.
+    std::string name_template;
+
 #  if GTEST_OS_LINUX_ANDROID
     // Note: Android applications are expected to call the framework's
     // Context.getExternalStorageDirectory() method through JNI to get
@@ -10804,18 +11435,49 @@
     // code as part of a regular standalone executable, which doesn't
     // run in a Dalvik process (e.g. when running it through 'adb shell').
     //
-    // The location /sdcard is directly accessible from native code
-    // and is the only location (unofficially) supported by the Android
-    // team. It's generally a symlink to the real SD Card mount point
-    // which can be /mnt/sdcard, /mnt/sdcard0, /system/media/sdcard, or
-    // other OEM-customized locations. Never rely on these, and always
-    // use /sdcard.
-    char name_template[] = "/sdcard/gtest_captured_stream.XXXXXX";
+    // The location /data/local/tmp is directly accessible from native code.
+    // '/sdcard' and other variants cannot be relied on, as they are not
+    // guaranteed to be mounted, or may have a delay in mounting.
+    name_template = "/data/local/tmp/";
+#  elif GTEST_OS_IOS
+    char user_temp_dir[PATH_MAX + 1];
+
+    // Documented alternative to NSTemporaryDirectory() (for obtaining creating
+    // a temporary directory) at
+    // https://developer.apple.com/library/archive/documentation/Security/Conceptual/SecureCodingGuide/Articles/RaceConditions.html#//apple_ref/doc/uid/TP40002585-SW10
+    //
+    // _CS_DARWIN_USER_TEMP_DIR (as well as _CS_DARWIN_USER_CACHE_DIR) is not
+    // documented in the confstr() man page at
+    // https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/confstr.3.html#//apple_ref/doc/man/3/confstr
+    // but are still available, according to the WebKit patches at
+    // https://trac.webkit.org/changeset/262004/webkit
+    // https://trac.webkit.org/changeset/263705/webkit
+    //
+    // The confstr() implementation falls back to getenv("TMPDIR"). See
+    // https://opensource.apple.com/source/Libc/Libc-1439.100.3/gen/confstr.c.auto.html
+    ::confstr(_CS_DARWIN_USER_TEMP_DIR, user_temp_dir, sizeof(user_temp_dir));
+
+    name_template = user_temp_dir;
+    if (name_template.back() != GTEST_PATH_SEP_[0])
+      name_template.push_back(GTEST_PATH_SEP_[0]);
 #  else
-    char name_template[] = "/tmp/captured_stream.XXXXXX";
-#  endif  // GTEST_OS_LINUX_ANDROID
-    const int captured_fd = mkstemp(name_template);
-    filename_ = name_template;
+    name_template = "/tmp/";
+#  endif
+    name_template.append("gtest_captured_stream.XXXXXX");
+
+    // mkstemp() modifies the string bytes in place, and does not go beyond the
+    // string's length. This results in well-defined behavior in C++17.
+    //
+    // The const_cast is needed below C++17. The constraints on std::string
+    // implementations in C++11 and above make assumption behind the const_cast
+    // fairly safe.
+    const int captured_fd = ::mkstemp(const_cast<char*>(name_template.data()));
+    if (captured_fd == -1) {
+      GTEST_LOG_(WARNING)
+          << "Failed to create tmp file " << name_template
+          << " for test; does the test have access to the /tmp directory?";
+    }
+    filename_ = std::move(name_template);
 # endif  // GTEST_OS_WINDOWS
     fflush(nullptr);
     dup2(captured_fd, fd_);
@@ -10836,6 +11498,10 @@
     }
 
     FILE* const file = posix::FOpen(filename_.c_str(), "r");
+    if (file == nullptr) {
+      GTEST_LOG_(FATAL) << "Failed to open tmp file " << filename_
+                        << " for capturing stream.";
+    }
     const std::string content = ReadEntireFile(file);
     posix::FClose(file);
     return content;
@@ -10949,13 +11615,6 @@
       new std::vector<std::string>(new_argvs.begin(), new_argvs.end()));
 }
 
-#if GTEST_HAS_GLOBAL_STRING
-void SetInjectableArgvs(const std::vector< ::string>& new_argvs) {
-  SetInjectableArgvs(
-      new std::vector<std::string>(new_argvs.begin(), new_argvs.end()));
-}
-#endif  // GTEST_HAS_GLOBAL_STRING
-
 void ClearInjectableArgvs() {
   delete g_injected_test_argvs;
   g_injected_test_argvs = nullptr;
@@ -10989,7 +11648,7 @@
 // Parses 'str' for a 32-bit signed integer.  If successful, writes
 // the result to *value and returns true; otherwise leaves *value
 // unchanged and returns false.
-bool ParseInt32(const Message& src_text, const char* str, Int32* value) {
+bool ParseInt32(const Message& src_text, const char* str, int32_t* value) {
   // Parses the environment variable as a decimal integer.
   char* end = nullptr;
   const long long_value = strtol(str, &end, 10);  // NOLINT
@@ -11006,13 +11665,13 @@
     return false;
   }
 
-  // Is the parsed value in the range of an Int32?
-  const Int32 result = static_cast<Int32>(long_value);
+  // Is the parsed value in the range of an int32_t?
+  const auto result = static_cast<int32_t>(long_value);
   if (long_value == LONG_MAX || long_value == LONG_MIN ||
       // The parsed value overflows as a long.  (strtol() returns
       // LONG_MAX or LONG_MIN when the input overflows.)
       result != long_value
-      // The parsed value overflows as an Int32.
+      // The parsed value overflows as an int32_t.
       ) {
     Message msg;
     msg << "WARNING: " << src_text
@@ -11030,7 +11689,7 @@
 // Reads and returns the Boolean environment variable corresponding to
 // the given flag; if it's not set, returns default_value.
 //
-// The value is considered true iff it's not "0".
+// The value is considered true if and only if it's not "0".
 bool BoolFromGTestEnv(const char* flag, bool default_value) {
 #if defined(GTEST_GET_BOOL_FROM_ENV_)
   return GTEST_GET_BOOL_FROM_ENV_(flag, default_value);
@@ -11045,7 +11704,7 @@
 // Reads and returns a 32-bit integer stored in the environment
 // variable corresponding to the given flag; if it isn't set or
 // doesn't represent a valid 32-bit integer, returns default_value.
-Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) {
+int32_t Int32FromGTestEnv(const char* flag, int32_t default_value) {
 #if defined(GTEST_GET_INT32_FROM_ENV_)
   return GTEST_GET_INT32_FROM_ENV_(flag, default_value);
 #else
@@ -11056,7 +11715,7 @@
     return default_value;
   }
 
-  Int32 result = default_value;
+  int32_t result = default_value;
   if (!ParseInt32(Message() << "Environment variable " << env_var,
                   string_value, &result)) {
     printf("The default value %s is used.\n",
@@ -11143,11 +11802,16 @@
 // or void PrintTo(const Foo&, ::std::ostream*) in the namespace that
 // defines Foo.
 
+
 #include <stdio.h>
+
 #include <cctype>
+#include <cstdint>
 #include <cwchar>
 #include <ostream>  // NOLINT
 #include <string>
+#include <type_traits>
+
 
 namespace testing {
 
@@ -11158,6 +11822,7 @@
 // Prints a segment of bytes in the given object.
 GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_
 GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
+GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_
 GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_
 void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start,
                                 size_t count, ostream* os) {
@@ -11200,9 +11865,19 @@
   *os << ">";
 }
 
+// Helpers for widening a character to char32_t. Since the standard does not
+// specify if char / wchar_t is signed or unsigned, it is important to first
+// convert it to the unsigned type of the same width before widening it to
+// char32_t.
+template <typename CharType>
+char32_t ToChar32(CharType in) {
+  return static_cast<char32_t>(
+      static_cast<typename std::make_unsigned<CharType>::type>(in));
+}
+
 }  // namespace
 
-namespace internal2 {
+namespace internal {
 
 // Delegates to PrintBytesInObjectToImpl() to print the bytes in the
 // given object.  The delegation simplifies the implementation, which
@@ -11214,10 +11889,6 @@
   PrintBytesInObjectToImpl(obj_bytes, count, os);
 }
 
-}  // namespace internal2
-
-namespace internal {
-
 // Depending on the value of a char (or wchar_t), we print it in one
 // of three formats:
 //   - as is if it's a printable ASCII (e.g. 'a', '2', ' '),
@@ -11232,17 +11903,15 @@
 // Returns true if c is a printable ASCII character.  We test the
 // value of c directly instead of calling isprint(), which is buggy on
 // Windows Mobile.
-inline bool IsPrintableAscii(wchar_t c) {
-  return 0x20 <= c && c <= 0x7E;
-}
+inline bool IsPrintableAscii(char32_t c) { return 0x20 <= c && c <= 0x7E; }
 
-// Prints a wide or narrow char c as a character literal without the
-// quotes, escaping it when necessary; returns how c was formatted.
-// The template argument UnsignedChar is the unsigned version of Char,
-// which is the type of c.
-template <typename UnsignedChar, typename Char>
+// Prints c (of type char, char8_t, char16_t, char32_t, or wchar_t) as a
+// character literal without the quotes, escaping it when necessary; returns how
+// c was formatted.
+template <typename Char>
 static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) {
-  switch (static_cast<wchar_t>(c)) {
+  const char32_t u_c = ToChar32(c);
+  switch (u_c) {
     case L'\0':
       *os << "\\0";
       break;
@@ -11274,13 +11943,12 @@
       *os << "\\v";
       break;
     default:
-      if (IsPrintableAscii(c)) {
+      if (IsPrintableAscii(u_c)) {
         *os << static_cast<char>(c);
         return kAsIs;
       } else {
         ostream::fmtflags flags = os->flags();
-        *os << "\\x" << std::hex << std::uppercase
-            << static_cast<int>(static_cast<UnsignedChar>(c));
+        *os << "\\x" << std::hex << std::uppercase << static_cast<int>(u_c);
         os->flags(flags);
         return kHexEscape;
       }
@@ -11288,9 +11956,9 @@
   return kSpecialEscape;
 }
 
-// Prints a wchar_t c as if it's part of a string literal, escaping it when
+// Prints a char32_t c as if it's part of a string literal, escaping it when
 // necessary; returns how c was formatted.
-static CharFormat PrintAsStringLiteralTo(wchar_t c, ostream* os) {
+static CharFormat PrintAsStringLiteralTo(char32_t c, ostream* os) {
   switch (c) {
     case L'\'':
       *os << "'";
@@ -11299,26 +11967,68 @@
       *os << "\\\"";
       return kSpecialEscape;
     default:
-      return PrintAsCharLiteralTo<wchar_t>(c, os);
+      return PrintAsCharLiteralTo(c, os);
   }
 }
 
+static const char* GetCharWidthPrefix(char) {
+  return "";
+}
+
+static const char* GetCharWidthPrefix(signed char) {
+  return "";
+}
+
+static const char* GetCharWidthPrefix(unsigned char) {
+  return "";
+}
+
+#ifdef __cpp_char8_t
+static const char* GetCharWidthPrefix(char8_t) {
+  return "u8";
+}
+#endif
+
+static const char* GetCharWidthPrefix(char16_t) {
+  return "u";
+}
+
+static const char* GetCharWidthPrefix(char32_t) {
+  return "U";
+}
+
+static const char* GetCharWidthPrefix(wchar_t) {
+  return "L";
+}
+
 // Prints a char c as if it's part of a string literal, escaping it when
 // necessary; returns how c was formatted.
 static CharFormat PrintAsStringLiteralTo(char c, ostream* os) {
-  return PrintAsStringLiteralTo(
-      static_cast<wchar_t>(static_cast<unsigned char>(c)), os);
+  return PrintAsStringLiteralTo(ToChar32(c), os);
 }
 
-// Prints a wide or narrow character c and its code.  '\0' is printed
-// as "'\\0'", other unprintable characters are also properly escaped
-// using the standard C++ escape sequence.  The template argument
-// UnsignedChar is the unsigned version of Char, which is the type of c.
-template <typename UnsignedChar, typename Char>
+#ifdef __cpp_char8_t
+static CharFormat PrintAsStringLiteralTo(char8_t c, ostream* os) {
+  return PrintAsStringLiteralTo(ToChar32(c), os);
+}
+#endif
+
+static CharFormat PrintAsStringLiteralTo(char16_t c, ostream* os) {
+  return PrintAsStringLiteralTo(ToChar32(c), os);
+}
+
+static CharFormat PrintAsStringLiteralTo(wchar_t c, ostream* os) {
+  return PrintAsStringLiteralTo(ToChar32(c), os);
+}
+
+// Prints a character c (of type char, char8_t, char16_t, char32_t, or wchar_t)
+// and its code. '\0' is printed as "'\\0'", other unprintable characters are
+// also properly escaped using the standard C++ escape sequence.
+template <typename Char>
 void PrintCharAndCodeTo(Char c, ostream* os) {
   // First, print c as a literal in the most readable form we can find.
-  *os << ((sizeof(c) > 1) ? "L'" : "'");
-  const CharFormat format = PrintAsCharLiteralTo<UnsignedChar>(c, os);
+  *os << GetCharWidthPrefix(c) << "'";
+  const CharFormat format = PrintAsCharLiteralTo(c, os);
   *os << "'";
 
   // To aid user debugging, we also print c's code in decimal, unless
@@ -11334,36 +12044,37 @@
   if (format == kHexEscape || (1 <= c && c <= 9)) {
     // Do nothing.
   } else {
-    *os << ", 0x" << String::FormatHexInt(static_cast<UnsignedChar>(c));
+    *os << ", 0x" << String::FormatHexInt(static_cast<int>(c));
   }
   *os << ")";
 }
 
-void PrintTo(unsigned char c, ::std::ostream* os) {
-  PrintCharAndCodeTo<unsigned char>(c, os);
-}
-void PrintTo(signed char c, ::std::ostream* os) {
-  PrintCharAndCodeTo<unsigned char>(c, os);
-}
+void PrintTo(unsigned char c, ::std::ostream* os) { PrintCharAndCodeTo(c, os); }
+void PrintTo(signed char c, ::std::ostream* os) { PrintCharAndCodeTo(c, os); }
 
 // Prints a wchar_t as a symbol if it is printable or as its internal
 // code otherwise and also as its code.  L'\0' is printed as "L'\\0'".
-void PrintTo(wchar_t wc, ostream* os) {
-  PrintCharAndCodeTo<wchar_t>(wc, os);
+void PrintTo(wchar_t wc, ostream* os) { PrintCharAndCodeTo(wc, os); }
+
+// TODO(dcheng): Consider making this delegate to PrintCharAndCodeTo() as well.
+void PrintTo(char32_t c, ::std::ostream* os) {
+  *os << std::hex << "U+" << std::uppercase << std::setfill('0') << std::setw(4)
+      << static_cast<uint32_t>(c);
 }
 
 // Prints the given array of characters to the ostream.  CharType must be either
-// char or wchar_t.
+// char, char8_t, char16_t, char32_t, or wchar_t.
 // The array starts at begin, the length is len, it may include '\0' characters
 // and may not be NUL-terminated.
 template <typename CharType>
 GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_
 GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
+GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_
 GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_
 static CharFormat PrintCharsAsStringTo(
     const CharType* begin, size_t len, ostream* os) {
-  const char* const kQuoteBegin = sizeof(CharType) == 1 ? "\"" : "L\"";
-  *os << kQuoteBegin;
+  const char* const quote_prefix = GetCharWidthPrefix(*begin);
+  *os << quote_prefix << "\"";
   bool is_previous_hex = false;
   CharFormat print_format = kAsIs;
   for (size_t index = 0; index < len; ++index) {
@@ -11372,7 +12083,7 @@
       // Previous character is of '\x..' form and this character can be
       // interpreted as another hexadecimal digit in its number. Break string to
       // disambiguate.
-      *os << "\" " << kQuoteBegin;
+      *os << "\" " << quote_prefix << "\"";
     }
     is_previous_hex = PrintAsStringLiteralTo(cur, os) == kHexEscape;
     // Remember if any characters required hex escaping.
@@ -11389,6 +12100,7 @@
 template <typename CharType>
 GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_
 GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
+GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_
 GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_
 static void UniversalPrintCharArray(
     const CharType* begin, size_t len, ostream* os) {
@@ -11417,22 +12129,57 @@
   UniversalPrintCharArray(begin, len, os);
 }
 
+#ifdef __cpp_char8_t
+// Prints a (const) char8_t array of 'len' elements, starting at address
+// 'begin'.
+void UniversalPrintArray(const char8_t* begin, size_t len, ostream* os) {
+  UniversalPrintCharArray(begin, len, os);
+}
+#endif
+
+// Prints a (const) char16_t array of 'len' elements, starting at address
+// 'begin'.
+void UniversalPrintArray(const char16_t* begin, size_t len, ostream* os) {
+  UniversalPrintCharArray(begin, len, os);
+}
+
+// Prints a (const) char32_t array of 'len' elements, starting at address
+// 'begin'.
+void UniversalPrintArray(const char32_t* begin, size_t len, ostream* os) {
+  UniversalPrintCharArray(begin, len, os);
+}
+
 // Prints a (const) wchar_t array of 'len' elements, starting at address
 // 'begin'.
 void UniversalPrintArray(const wchar_t* begin, size_t len, ostream* os) {
   UniversalPrintCharArray(begin, len, os);
 }
 
-// Prints the given C string to the ostream.
-void PrintTo(const char* s, ostream* os) {
+namespace {
+
+// Prints a null-terminated C-style string to the ostream.
+template <typename Char>
+void PrintCStringTo(const Char* s, ostream* os) {
   if (s == nullptr) {
     *os << "NULL";
   } else {
     *os << ImplicitCast_<const void*>(s) << " pointing to ";
-    PrintCharsAsStringTo(s, strlen(s), os);
+    PrintCharsAsStringTo(s, std::char_traits<Char>::length(s), os);
   }
 }
 
+}  // anonymous namespace
+
+void PrintTo(const char* s, ostream* os) { PrintCStringTo(s, os); }
+
+#ifdef __cpp_char8_t
+void PrintTo(const char8_t* s, ostream* os) { PrintCStringTo(s, os); }
+#endif
+
+void PrintTo(const char16_t* s, ostream* os) { PrintCStringTo(s, os); }
+
+void PrintTo(const char32_t* s, ostream* os) { PrintCStringTo(s, os); }
+
 // MSVC compiler can be configured to define whar_t as a typedef
 // of unsigned short. Defining an overload for const wchar_t* in that case
 // would cause pointers to unsigned shorts be printed as wide strings,
@@ -11441,14 +12188,7 @@
 // wchar_t is implemented as a native type.
 #if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
 // Prints the given wide C string to the ostream.
-void PrintTo(const wchar_t* s, ostream* os) {
-  if (s == nullptr) {
-    *os << "NULL";
-  } else {
-    *os << ImplicitCast_<const void*>(s) << " pointing to ";
-    PrintCharsAsStringTo(s, wcslen(s), os);
-  }
-}
+void PrintTo(const wchar_t* s, ostream* os) { PrintCStringTo(s, os); }
 #endif  // wchar_t is native
 
 namespace {
@@ -11518,17 +12258,6 @@
 
 }  // anonymous namespace
 
-// Prints a ::string object.
-#if GTEST_HAS_GLOBAL_STRING
-void PrintStringTo(const ::string& s, ostream* os) {
-  if (PrintCharsAsStringTo(s.data(), s.size(), os) == kHexEscape) {
-    if (GTEST_FLAG(print_utf8)) {
-      ConditionalPrintAsText(s.data(), s.size(), os);
-    }
-  }
-}
-#endif  // GTEST_HAS_GLOBAL_STRING
-
 void PrintStringTo(const ::std::string& s, ostream* os) {
   if (PrintCharsAsStringTo(s.data(), s.size(), os) == kHexEscape) {
     if (GTEST_FLAG(print_utf8)) {
@@ -11537,12 +12266,19 @@
   }
 }
 
-// Prints a ::wstring object.
-#if GTEST_HAS_GLOBAL_WSTRING
-void PrintWideStringTo(const ::wstring& s, ostream* os) {
+#ifdef __cpp_char8_t
+void PrintU8StringTo(const ::std::u8string& s, ostream* os) {
   PrintCharsAsStringTo(s.data(), s.size(), os);
 }
-#endif  // GTEST_HAS_GLOBAL_WSTRING
+#endif
+
+void PrintU16StringTo(const ::std::u16string& s, ostream* os) {
+  PrintCharsAsStringTo(s.data(), s.size(), os);
+}
+
+void PrintU32StringTo(const ::std::u32string& s, ostream* os) {
+  PrintCharsAsStringTo(s.data(), s.size(), os);
+}
 
 #if GTEST_HAS_STD_WSTRING
 void PrintWideStringTo(const ::std::wstring& s, ostream* os) {
@@ -11586,6 +12322,7 @@
 // The Google C++ Testing and Mocking Framework (Google Test)
 
 
+
 namespace testing {
 
 using internal::GetUnitTestImpl;
@@ -11599,7 +12336,9 @@
 
 // Prints a TestPartResult object.
 std::ostream& operator<<(std::ostream& os, const TestPartResult& result) {
-  return os << result.file_name() << ":" << result.line_number() << ": "
+  return os << internal::FormatFileLocation(result.file_name(),
+                                            result.line_number())
+            << " "
             << (result.type() == TestPartResult::kSuccess
                     ? "Success"
                     : result.type() == TestPartResult::kSkip
@@ -11623,7 +12362,7 @@
     internal::posix::Abort();
   }
 
-  return array_[index];
+  return array_[static_cast<size_t>(index)];
 }
 
 // Returns the number of TestPartResult objects in the array.
@@ -11655,7 +12394,7 @@
 }  // namespace internal
 
 }  // namespace testing
-// Copyright 2008 Google Inc.
+// Copyright 2023 Google Inc.
 // All Rights Reserved.
 //
 // Redistribution and use in source and binary forms, with or without
@@ -11690,8 +12429,6 @@
 namespace testing {
 namespace internal {
 
-#if GTEST_HAS_TYPED_TEST_P
-
 // Skips to the first non-space char in str. Returns an empty string if str
 // contains only whitespace characters.
 static const char* SkipSpaces(const char* str) {
@@ -11713,7 +12450,10 @@
 // registered_tests_; returns registered_tests if successful, or
 // aborts the program otherwise.
 const char* TypedTestSuitePState::VerifyRegisteredTestNames(
-    const char* file, int line, const char* registered_tests) {
+    const char* test_suite_name, const char* file, int line,
+    const char* registered_tests) {
+  RegisterTypeParameterizedTestSuite(test_suite_name, CodeLocation(file, line));
+
   typedef RegisteredTestsMap::const_iterator RegisteredTestIter;
   registered_ = true;
 
@@ -11730,17 +12470,7 @@
       continue;
     }
 
-    bool found = false;
-    for (RegisteredTestIter it = registered_tests_.begin();
-         it != registered_tests_.end();
-         ++it) {
-      if (name == it->first) {
-        found = true;
-        break;
-      }
-    }
-
-    if (found) {
+    if (registered_tests_.count(name) != 0) {
       tests.insert(name);
     } else {
       errors << "No test named " << name
@@ -11767,8 +12497,6 @@
   return registered_tests;
 }
 
-#endif  // GTEST_HAS_TYPED_TEST_P
-
 }  // namespace internal
 }  // namespace testing
 // Copyright 2008, Google Inc.
@@ -12085,8 +12813,8 @@
 // Protects global resources (stdout in particular) used by Log().
 static GTEST_DEFINE_STATIC_MUTEX_(g_log_mutex);
 
-// Returns true iff a log with the given severity is visible according
-// to the --gmock_verbose flag.
+// Returns true if and only if a log with the given severity is visible
+// according to the --gmock_verbose flag.
 GTEST_API_ bool LogIsVisible(LogSeverity severity) {
   if (GMOCK_FLAG(verbose) == kInfoVerbosity) {
     // Always show the log if --gmock_verbose=info.
@@ -12101,7 +12829,7 @@
   }
 }
 
-// Prints the given message to stdout iff 'severity' >= the level
+// Prints the given message to stdout if and only if 'severity' >= the level
 // specified by the --gmock_verbose flag.  If stack_frames_to_skip >=
 // 0, also prints the stack trace excluding the top
 // stack_frames_to_skip frames.  In opt mode, any positive
@@ -12379,8 +13107,6 @@
   // right_[left_[i]] = i.
   ::std::vector<size_t> left_;
   ::std::vector<size_t> right_;
-
-  GTEST_DISALLOW_ASSIGN_(MaxBipartiteMatchState);
 };
 
 const size_t MaxBipartiteMatchState::kUnused;
@@ -12657,6 +13383,7 @@
 
 
 #include <stdlib.h>
+
 #include <iostream>  // NOLINT
 #include <map>
 #include <memory>
@@ -12664,6 +13391,7 @@
 #include <string>
 #include <vector>
 
+
 #if GTEST_OS_CYGWIN || GTEST_OS_LINUX || GTEST_OS_MAC
 # include <unistd.h>  // NOLINT
 #endif
@@ -12689,7 +13417,8 @@
                                 const char* file, int line,
                                 const std::string& message) {
   ::std::ostringstream s;
-  s << file << ":" << line << ": " << message << ::std::endl;
+  s << internal::FormatFileLocation(file, line) << " " << message
+    << ::std::endl;
   Log(severity, s.str(), 0);
 }
 
@@ -12745,8 +13474,8 @@
   }
 }
 
-// Returns true iff all pre-requisites of this expectation have been
-// satisfied.
+// Returns true if and only if all pre-requisites of this expectation
+// have been satisfied.
 bool ExpectationBase::AllPrerequisitesAreSatisfied() const
     GTEST_EXCLUSIVE_LOCK_REQUIRED_(g_gmock_mutex) {
   g_gmock_mutex.AssertHeld();
@@ -12910,8 +13639,8 @@
               "call should not happen.  Do not suppress it by blindly adding "
               "an EXPECT_CALL() if you don't mean to enforce the call.  "
               "See "
-              "https://github.com/google/googletest/blob/master/googlemock/"
-              "docs/CookBook.md#"
+              "https://github.com/google/googletest/blob/master/docs/"
+              "gmock_cook_book.md#"
               "knowing-when-to-expect for details.\n",
           stack_frames_to_skip);
       break;
@@ -13003,7 +13732,7 @@
     const CallReaction reaction =
         Mock::GetReactionOnUninterestingCalls(MockObject());
 
-    // True iff we need to print this call's arguments and return
+    // True if and only if we need to print this call's arguments and return
     // value.  This definition must be kept in sync with
     // the behavior of ReportUninterestingCall().
     const bool need_to_report_uninteresting_call =
@@ -13048,13 +13777,14 @@
 
   // The UntypedFindMatchingExpectation() function acquires and
   // releases g_gmock_mutex.
+
   const ExpectationBase* const untyped_expectation =
-      this->UntypedFindMatchingExpectation(
-          untyped_args, &untyped_action, &is_excessive,
-          &ss, &why);
+      this->UntypedFindMatchingExpectation(untyped_args, &untyped_action,
+                                           &is_excessive, &ss, &why);
   const bool found = untyped_expectation != nullptr;
 
-  // True iff we need to print the call's arguments and return value.
+  // True if and only if we need to print the call's arguments
+  // and return value.
   // This definition must be kept in sync with the uses of Expect()
   // and Log() in this function.
   const bool need_to_report_call =
@@ -13075,26 +13805,42 @@
     untyped_expectation->DescribeLocationTo(&loc);
   }
 
-  UntypedActionResultHolderBase* const result =
-      untyped_action == nullptr
-          ? this->UntypedPerformDefaultAction(untyped_args, ss.str())
-          : this->UntypedPerformAction(untyped_action, untyped_args);
-  if (result != nullptr) result->PrintAsActionResult(&ss);
-  ss << "\n" << why.str();
+  UntypedActionResultHolderBase* result = nullptr;
 
-  if (!found) {
-    // No expectation matches this call - reports a failure.
-    Expect(false, nullptr, -1, ss.str());
-  } else if (is_excessive) {
-    // We had an upper-bound violation and the failure message is in ss.
-    Expect(false, untyped_expectation->file(),
-           untyped_expectation->line(), ss.str());
-  } else {
-    // We had an expected call and the matching expectation is
-    // described in ss.
-    Log(kInfo, loc.str() + ss.str(), 2);
+  auto perform_action = [&] {
+    return untyped_action == nullptr
+               ? this->UntypedPerformDefaultAction(untyped_args, ss.str())
+               : this->UntypedPerformAction(untyped_action, untyped_args);
+  };
+  auto handle_failures = [&] {
+    ss << "\n" << why.str();
+
+    if (!found) {
+      // No expectation matches this call - reports a failure.
+      Expect(false, nullptr, -1, ss.str());
+    } else if (is_excessive) {
+      // We had an upper-bound violation and the failure message is in ss.
+      Expect(false, untyped_expectation->file(), untyped_expectation->line(),
+             ss.str());
+    } else {
+      // We had an expected call and the matching expectation is
+      // described in ss.
+      Log(kInfo, loc.str() + ss.str(), 2);
+    }
+  };
+#if GTEST_HAS_EXCEPTIONS
+  try {
+    result = perform_action();
+  } catch (...) {
+    handle_failures();
+    throw;
   }
+#else
+  result = perform_action();
+#endif
 
+  if (result != nullptr) result->PrintAsActionResult(&ss);
+  handle_failures();
   return result;
 }
 
@@ -13193,7 +13939,7 @@
   int first_used_line;
   ::std::string first_used_test_suite;
   ::std::string first_used_test;
-  bool leakable;  // true iff it's OK to leak the object.
+  bool leakable;  // true if and only if it's OK to leak the object.
   FunctionMockers function_mockers;  // All registered methods of the object.
 };
 
@@ -13238,7 +13984,7 @@
     if (leaked_count > 0) {
       std::cout << "\nERROR: " << leaked_count << " leaked mock "
                 << (leaked_count == 1 ? "object" : "objects")
-                << " found at program exit. Expectations on a mock object is "
+                << " found at program exit. Expectations on a mock object are "
                    "verified when the object is destructed. Leaking a mock "
                    "means that its expectations aren't verified, which is "
                    "usually a test bug. If you really intend to leak a mock, "
@@ -13337,7 +14083,7 @@
 }
 
 // Verifies all expectations on the given mock object and clears its
-// default actions and expectations.  Returns true iff the
+// default actions and expectations.  Returns true if and only if the
 // verification was successful.
 bool Mock::VerifyAndClear(void* mock_obj)
     GTEST_LOCK_EXCLUDED_(internal::g_gmock_mutex) {
@@ -13538,8 +14284,8 @@
 namespace testing {
 
 GMOCK_DEFINE_bool_(catch_leaked_mocks, true,
-                   "true iff Google Mock should report leaked mock objects "
-                   "as failures.");
+                   "true if and only if Google Mock should report leaked "
+                   "mock objects as failures.");
 
 GMOCK_DEFINE_string_(verbose, internal::kWarningVerbosity,
                      "Controls how verbose Google Mock's output is."
@@ -13628,7 +14374,7 @@
 }
 
 static bool ParseGoogleMockIntFlag(const char* str, const char* flag,
-                                   int* value) {
+                                   int32_t* value) {
   // Gets the value of the flag as a string.
   const char* const value_str = ParseGoogleMockFlagValue(str, flag, true);
 
diff --git a/third_party/ceres/internal/ceres/gradient_checker.cc b/third_party/ceres/internal/ceres/gradient_checker.cc
index dadaaa0..f49803c 100644
--- a/third_party/ceres/internal/ceres/gradient_checker.cc
+++ b/third_party/ceres/internal/ceres/gradient_checker.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2016 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -48,43 +48,39 @@
 using internal::IsClose;
 using internal::StringAppendF;
 using internal::StringPrintf;
-using std::string;
-using std::vector;
 
 namespace {
 // Evaluate the cost function and transform the returned Jacobians to
-// the local space of the respective local parameterizations.
-bool EvaluateCostFunction(
-    const ceres::CostFunction* function,
-    double const* const* parameters,
-    const std::vector<const ceres::LocalParameterization*>&
-        local_parameterizations,
-    Vector* residuals,
-    std::vector<Matrix>* jacobians,
-    std::vector<Matrix>* local_jacobians) {
+// the tangent space of the respective local parameterizations.
+bool EvaluateCostFunction(const CostFunction* function,
+                          double const* const* parameters,
+                          const std::vector<const Manifold*>& manifolds,
+                          Vector* residuals,
+                          std::vector<Matrix>* jacobians,
+                          std::vector<Matrix>* local_jacobians) {
   CHECK(residuals != nullptr);
   CHECK(jacobians != nullptr);
   CHECK(local_jacobians != nullptr);
 
-  const vector<int32_t>& block_sizes = function->parameter_block_sizes();
+  const std::vector<int32_t>& block_sizes = function->parameter_block_sizes();
   const int num_parameter_blocks = block_sizes.size();
 
-  // Allocate Jacobian matrices in local space.
+  // Allocate Jacobian matrices in tangent space.
   local_jacobians->resize(num_parameter_blocks);
-  vector<double*> local_jacobian_data(num_parameter_blocks);
+  std::vector<double*> local_jacobian_data(num_parameter_blocks);
   for (int i = 0; i < num_parameter_blocks; ++i) {
     int block_size = block_sizes.at(i);
-    if (local_parameterizations.at(i) != NULL) {
-      block_size = local_parameterizations.at(i)->LocalSize();
+    if (manifolds.at(i) != nullptr) {
+      block_size = manifolds.at(i)->TangentSize();
     }
     local_jacobians->at(i).resize(function->num_residuals(), block_size);
     local_jacobians->at(i).setZero();
     local_jacobian_data.at(i) = local_jacobians->at(i).data();
   }
 
-  // Allocate Jacobian matrices in global space.
+  // Allocate Jacobian matrices in ambient space.
   jacobians->resize(num_parameter_blocks);
-  vector<double*> jacobian_data(num_parameter_blocks);
+  std::vector<double*> jacobian_data(num_parameter_blocks);
   for (int i = 0; i < num_parameter_blocks; ++i) {
     jacobians->at(i).resize(function->num_residuals(), block_sizes.at(i));
     jacobians->at(i).setZero();
@@ -100,49 +96,46 @@
     return false;
   }
 
-  // Convert Jacobians from global to local space.
+  // Convert Jacobians from ambient to local space.
   for (size_t i = 0; i < local_jacobians->size(); ++i) {
-    if (local_parameterizations.at(i) == NULL) {
+    if (manifolds.at(i) == nullptr) {
       local_jacobians->at(i) = jacobians->at(i);
     } else {
-      int global_size = local_parameterizations.at(i)->GlobalSize();
-      int local_size = local_parameterizations.at(i)->LocalSize();
-      CHECK_EQ(jacobians->at(i).cols(), global_size);
-      Matrix global_J_local(global_size, local_size);
-      local_parameterizations.at(i)->ComputeJacobian(parameters[i],
-                                                     global_J_local.data());
-      local_jacobians->at(i).noalias() = jacobians->at(i) * global_J_local;
+      int ambient_size = manifolds.at(i)->AmbientSize();
+      int tangent_size = manifolds.at(i)->TangentSize();
+      CHECK_EQ(jacobians->at(i).cols(), ambient_size);
+      Matrix ambient_J_tangent(ambient_size, tangent_size);
+      manifolds.at(i)->PlusJacobian(parameters[i], ambient_J_tangent.data());
+      local_jacobians->at(i).noalias() = jacobians->at(i) * ambient_J_tangent;
     }
   }
   return true;
 }
 }  // namespace
 
-GradientChecker::GradientChecker(
-    const CostFunction* function,
-    const vector<const LocalParameterization*>* local_parameterizations,
-    const NumericDiffOptions& options)
+GradientChecker::GradientChecker(const CostFunction* function,
+                                 const std::vector<const Manifold*>* manifolds,
+                                 const NumericDiffOptions& options)
     : function_(function) {
   CHECK(function != nullptr);
-  if (local_parameterizations != NULL) {
-    local_parameterizations_ = *local_parameterizations;
+  if (manifolds != nullptr) {
+    manifolds_ = *manifolds;
   } else {
-    local_parameterizations_.resize(function->parameter_block_sizes().size(),
-                                    NULL);
+    manifolds_.resize(function->parameter_block_sizes().size(), nullptr);
   }
-  DynamicNumericDiffCostFunction<CostFunction, RIDDERS>*
-      finite_diff_cost_function =
-          new DynamicNumericDiffCostFunction<CostFunction, RIDDERS>(
-              function, DO_NOT_TAKE_OWNERSHIP, options);
-  finite_diff_cost_function_.reset(finite_diff_cost_function);
 
-  const vector<int32_t>& parameter_block_sizes =
+  auto finite_diff_cost_function =
+      std::make_unique<DynamicNumericDiffCostFunction<CostFunction, RIDDERS>>(
+          function, DO_NOT_TAKE_OWNERSHIP, options);
+  const std::vector<int32_t>& parameter_block_sizes =
       function->parameter_block_sizes();
   const int num_parameter_blocks = parameter_block_sizes.size();
   for (int i = 0; i < num_parameter_blocks; ++i) {
     finite_diff_cost_function->AddParameterBlock(parameter_block_sizes[i]);
   }
   finite_diff_cost_function->SetNumResiduals(function->num_residuals());
+
+  finite_diff_cost_function_ = std::move(finite_diff_cost_function);
 }
 
 bool GradientChecker::Probe(double const* const* parameters,
@@ -154,7 +147,7 @@
   // provided an output argument.
   ProbeResults* results;
   ProbeResults results_local;
-  if (results_param != NULL) {
+  if (results_param != nullptr) {
     results = results_param;
     results->residuals.resize(0);
     results->jacobians.clear();
@@ -169,11 +162,11 @@
   results->return_value = true;
 
   // Evaluate the derivative using the user supplied code.
-  vector<Matrix>& jacobians = results->jacobians;
-  vector<Matrix>& local_jacobians = results->local_jacobians;
+  std::vector<Matrix>& jacobians = results->jacobians;
+  std::vector<Matrix>& local_jacobians = results->local_jacobians;
   if (!EvaluateCostFunction(function_,
                             parameters,
-                            local_parameterizations_,
+                            manifolds_,
                             &results->residuals,
                             &jacobians,
                             &local_jacobians)) {
@@ -182,12 +175,13 @@
   }
 
   // Evaluate the derivative using numeric derivatives.
-  vector<Matrix>& numeric_jacobians = results->numeric_jacobians;
-  vector<Matrix>& local_numeric_jacobians = results->local_numeric_jacobians;
+  std::vector<Matrix>& numeric_jacobians = results->numeric_jacobians;
+  std::vector<Matrix>& local_numeric_jacobians =
+      results->local_numeric_jacobians;
   Vector finite_diff_residuals;
   if (!EvaluateCostFunction(finite_diff_cost_function_.get(),
                             parameters,
-                            local_parameterizations_,
+                            manifolds_,
                             &finite_diff_residuals,
                             &numeric_jacobians,
                             &local_numeric_jacobians)) {
@@ -205,8 +199,8 @@
     if (!IsClose(results->residuals[i],
                  finite_diff_residuals[i],
                  relative_precision,
-                 NULL,
-                 NULL)) {
+                 nullptr,
+                 nullptr)) {
       results->error_log =
           "Function evaluation with and without Jacobians "
           "resulted in different residuals.";
@@ -223,7 +217,7 @@
 
   // Accumulate the error message for all the jacobians, since it won't get
   // output if there are no bad jacobian components.
-  string error_log;
+  std::string error_log;
   for (int k = 0; k < function_->parameter_block_sizes().size(); k++) {
     StringAppendF(&error_log,
                   "========== "
@@ -277,7 +271,7 @@
 
   // Since there were some bad errors, dump comprehensive debug info.
   if (num_bad_jacobian_components) {
-    string header = StringPrintf(
+    std::string header = StringPrintf(
         "\nDetected %d bad Jacobian component(s). "
         "Worst relative error was %g.\n",
         num_bad_jacobian_components,
diff --git a/third_party/ceres/internal/ceres/gradient_checker_test.cc b/third_party/ceres/internal/ceres/gradient_checker_test.cc
index 31dc97b..2a20470 100644
--- a/third_party/ceres/internal/ceres/gradient_checker_test.cc
+++ b/third_party/ceres/internal/ceres/gradient_checker_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2016 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -33,21 +33,19 @@
 #include "ceres/gradient_checker.h"
 
 #include <cmath>
-#include <cstdlib>
+#include <random>
+#include <utility>
 #include <vector>
 
 #include "ceres/cost_function.h"
 #include "ceres/problem.h"
-#include "ceres/random.h"
 #include "ceres/solver.h"
 #include "ceres/test_util.h"
 #include "glog/logging.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
-using std::vector;
 const double kTolerance = 1e-12;
 
 // We pick a (non-quadratic) function whose derivative are easy:
@@ -59,13 +57,16 @@
 // version, they are both block vectors, of course.
 class GoodTestTerm : public CostFunction {
  public:
-  GoodTestTerm(int arity, int const* dim) : arity_(arity), return_value_(true) {
+  template <class UniformRandomFunctor>
+  GoodTestTerm(int arity, int const* dim, UniformRandomFunctor&& randu)
+      : arity_(arity), return_value_(true) {
+    std::uniform_real_distribution<double> distribution(-1.0, 1.0);
     // Make 'arity' random vectors.
     a_.resize(arity_);
     for (int j = 0; j < arity_; ++j) {
       a_[j].resize(dim[j]);
       for (int u = 0; u < dim[j]; ++u) {
-        a_[j][u] = 2.0 * RandDouble() - 1.0;
+        a_[j][u] = randu();
       }
     }
 
@@ -77,7 +78,7 @@
 
   bool Evaluate(double const* const* parameters,
                 double* residuals,
-                double** jacobians) const {
+                double** jacobians) const override {
     if (!return_value_) {
       return false;
     }
@@ -113,18 +114,20 @@
  private:
   int arity_;
   bool return_value_;
-  vector<vector<double>> a_;  // our vectors.
+  std::vector<std::vector<double>> a_;  // our vectors.
 };
 
 class BadTestTerm : public CostFunction {
  public:
-  BadTestTerm(int arity, int const* dim) : arity_(arity) {
+  template <class UniformRandomFunctor>
+  BadTestTerm(int arity, int const* dim, UniformRandomFunctor&& randu)
+      : arity_(arity) {
     // Make 'arity' random vectors.
     a_.resize(arity_);
     for (int j = 0; j < arity_; ++j) {
       a_[j].resize(dim[j]);
       for (int u = 0; u < dim[j]; ++u) {
-        a_[j][u] = 2.0 * RandDouble() - 1.0;
+        a_[j][u] = randu();
       }
     }
 
@@ -136,7 +139,7 @@
 
   bool Evaluate(double const* const* parameters,
                 double* residuals,
-                double** jacobians) const {
+                double** jacobians) const override {
     // Compute a . x.
     double ax = 0;
     for (int j = 0; j < arity_; ++j) {
@@ -166,7 +169,7 @@
 
  private:
   int arity_;
-  vector<vector<double>> a_;  // our vectors.
+  std::vector<std::vector<double>> a_;  // our vectors.
 };
 
 static void CheckDimensions(const GradientChecker::ProbeResults& results,
@@ -194,8 +197,6 @@
 }
 
 TEST(GradientChecker, SmokeTest) {
-  srand(5);
-
   // Test with 3 blocks of size 2, 3 and 4.
   int const num_parameters = 3;
   std::vector<int> parameter_sizes(3);
@@ -205,10 +206,13 @@
 
   // Make a random set of blocks.
   FixedArray<double*> parameters(num_parameters);
+  std::mt19937 prng;
+  std::uniform_real_distribution<double> distribution(-1.0, 1.0);
+  auto randu = [&prng, &distribution] { return distribution(prng); };
   for (int j = 0; j < num_parameters; ++j) {
     parameters[j] = new double[parameter_sizes[j]];
     for (int u = 0; u < parameter_sizes[j]; ++u) {
-      parameters[j][u] = 2.0 * RandDouble() - 1.0;
+      parameters[j][u] = randu();
     }
   }
 
@@ -216,9 +220,12 @@
   GradientChecker::ProbeResults results;
 
   // Test that Probe returns true for correct Jacobians.
-  GoodTestTerm good_term(num_parameters, parameter_sizes.data());
-  GradientChecker good_gradient_checker(&good_term, NULL, numeric_diff_options);
-  EXPECT_TRUE(good_gradient_checker.Probe(parameters.data(), kTolerance, NULL));
+  GoodTestTerm good_term(num_parameters, parameter_sizes.data(), randu);
+  std::vector<const Manifold*>* manifolds = nullptr;
+  GradientChecker good_gradient_checker(
+      &good_term, manifolds, numeric_diff_options);
+  EXPECT_TRUE(
+      good_gradient_checker.Probe(parameters.data(), kTolerance, nullptr));
   EXPECT_TRUE(
       good_gradient_checker.Probe(parameters.data(), kTolerance, &results))
       << results.error_log;
@@ -233,7 +240,7 @@
   // Test that if the cost function return false, Probe should return false.
   good_term.SetReturnValue(false);
   EXPECT_FALSE(
-      good_gradient_checker.Probe(parameters.data(), kTolerance, NULL));
+      good_gradient_checker.Probe(parameters.data(), kTolerance, nullptr));
   EXPECT_FALSE(
       good_gradient_checker.Probe(parameters.data(), kTolerance, &results))
       << results.error_log;
@@ -250,9 +257,11 @@
   EXPECT_FALSE(results.error_log.empty());
 
   // Test that Probe returns false for incorrect Jacobians.
-  BadTestTerm bad_term(num_parameters, parameter_sizes.data());
-  GradientChecker bad_gradient_checker(&bad_term, NULL, numeric_diff_options);
-  EXPECT_FALSE(bad_gradient_checker.Probe(parameters.data(), kTolerance, NULL));
+  BadTestTerm bad_term(num_parameters, parameter_sizes.data(), randu);
+  GradientChecker bad_gradient_checker(
+      &bad_term, manifolds, numeric_diff_options);
+  EXPECT_FALSE(
+      bad_gradient_checker.Probe(parameters.data(), kTolerance, nullptr));
   EXPECT_FALSE(
       bad_gradient_checker.Probe(parameters.data(), kTolerance, &results));
 
@@ -284,8 +293,8 @@
  */
 class LinearCostFunction : public CostFunction {
  public:
-  explicit LinearCostFunction(const Vector& residuals_offset)
-      : residuals_offset_(residuals_offset) {
+  explicit LinearCostFunction(Vector residuals_offset)
+      : residuals_offset_(std::move(residuals_offset)) {
     set_num_residuals(residuals_offset_.size());
   }
 
@@ -305,7 +314,7 @@
       residuals += residual_J_param * param;
 
       // Return Jacobian.
-      if (residual_J_params != NULL && residual_J_params[i] != NULL) {
+      if (residual_J_params != nullptr && residual_J_params[i] != nullptr) {
         Eigen::Map<Matrix> residual_J_param_out(residual_J_params[i],
                                                 residual_J_param.rows(),
                                                 residual_J_param.cols());
@@ -326,7 +335,7 @@
   }
 
   /// Add offset to the given Jacobian before returning it from Evaluate(),
-  /// thus introducing an error in the comutation.
+  /// thus introducing an error in the computation.
   void SetJacobianOffset(size_t index, Matrix offset) {
     CHECK_LT(index, residual_J_params_.size());
     CHECK_EQ(residual_J_params_[index].rows(), offset.rows());
@@ -340,32 +349,6 @@
   Vector residuals_offset_;
 };
 
-/**
- * Helper local parameterization that multiplies the delta vector by the given
- * jacobian and adds it to the parameter.
- */
-class MatrixParameterization : public LocalParameterization {
- public:
-  bool Plus(const double* x,
-            const double* delta,
-            double* x_plus_delta) const final {
-    VectorRef(x_plus_delta, GlobalSize()) =
-        ConstVectorRef(x, GlobalSize()) +
-        (global_J_local * ConstVectorRef(delta, LocalSize()));
-    return true;
-  }
-
-  bool ComputeJacobian(const double* /*x*/, double* jacobian) const final {
-    MatrixRef(jacobian, GlobalSize(), LocalSize()) = global_J_local;
-    return true;
-  }
-
-  int GlobalSize() const final { return global_J_local.rows(); }
-  int LocalSize() const final { return global_J_local.cols(); }
-
-  Matrix global_J_local;
-};
-
 // Helper function to compare two Eigen matrices (used in the test below).
 static void ExpectMatricesClose(Matrix p, Matrix q, double tolerance) {
   ASSERT_EQ(p.rows(), q.rows());
@@ -373,7 +356,41 @@
   ExpectArraysClose(p.size(), p.data(), q.data(), tolerance);
 }
 
-TEST(GradientChecker, TestCorrectnessWithLocalParameterizations) {
+// Helper manifold that multiplies the delta vector by the given
+// jacobian and adds it to the parameter.
+class MatrixManifold : public Manifold {
+ public:
+  bool Plus(const double* x,
+            const double* delta,
+            double* x_plus_delta) const final {
+    VectorRef(x_plus_delta, AmbientSize()) =
+        ConstVectorRef(x, AmbientSize()) +
+        (global_to_local_ * ConstVectorRef(delta, TangentSize()));
+    return true;
+  }
+
+  bool PlusJacobian(const double* /*x*/, double* jacobian) const final {
+    MatrixRef(jacobian, AmbientSize(), TangentSize()) = global_to_local_;
+    return true;
+  }
+
+  bool Minus(const double* y, const double* x, double* y_minus_x) const final {
+    LOG(FATAL) << "Should not be called";
+    return true;
+  }
+
+  bool MinusJacobian(const double* x, double* jacobian) const final {
+    LOG(FATAL) << "Should not be called";
+    return true;
+  }
+
+  int AmbientSize() const final { return global_to_local_.rows(); }
+  int TangentSize() const final { return global_to_local_.cols(); }
+
+  Matrix global_to_local_;
+};
+
+TEST(GradientChecker, TestCorrectnessWithManifolds) {
   // Create cost function.
   Eigen::Vector3d residual_offset(100.0, 200.0, 300.0);
   LinearCostFunction cost_function(residual_offset);
@@ -395,9 +412,9 @@
   std::vector<int> parameter_sizes(2);
   parameter_sizes[0] = 3;
   parameter_sizes[1] = 2;
-  std::vector<int> local_parameter_sizes(2);
-  local_parameter_sizes[0] = 2;
-  local_parameter_sizes[1] = 2;
+  std::vector<int> tangent_sizes(2);
+  tangent_sizes[0] = 2;
+  tangent_sizes[1] = 2;
 
   // Test cost function for correctness.
   Eigen::Matrix<double, 3, 3, Eigen::RowMajor> j1_out;
@@ -417,57 +434,52 @@
   ExpectMatricesClose(j2_out, j1, std::numeric_limits<double>::epsilon());
   ExpectMatricesClose(residual, residual_expected, kTolerance);
 
-  // Create local parameterization.
-  Eigen::Matrix<double, 3, 2, Eigen::RowMajor> global_J_local;
-  global_J_local.row(0) << 1.5, 2.5;
-  global_J_local.row(1) << 3.5, 4.5;
-  global_J_local.row(2) << 5.5, 6.5;
+  // Create manifold.
+  Eigen::Matrix<double, 3, 2, Eigen::RowMajor> global_to_local;
+  global_to_local.row(0) << 1.5, 2.5;
+  global_to_local.row(1) << 3.5, 4.5;
+  global_to_local.row(2) << 5.5, 6.5;
 
-  MatrixParameterization parameterization;
-  parameterization.global_J_local = global_J_local;
+  MatrixManifold manifold;
+  manifold.global_to_local_ = global_to_local;
 
-  // Test local parameterization for correctness.
+  // Test manifold for correctness.
   Eigen::Vector3d x(7.0, 8.0, 9.0);
   Eigen::Vector2d delta(10.0, 11.0);
 
-  Eigen::Matrix<double, 3, 2, Eigen::RowMajor> global_J_local_out;
-  parameterization.ComputeJacobian(x.data(), global_J_local_out.data());
-  ExpectMatricesClose(global_J_local_out,
-                      global_J_local,
+  Eigen::Matrix<double, 3, 2, Eigen::RowMajor> global_to_local_out;
+  manifold.PlusJacobian(x.data(), global_to_local_out.data());
+  ExpectMatricesClose(global_to_local_out,
+                      global_to_local,
                       std::numeric_limits<double>::epsilon());
 
   Eigen::Vector3d x_plus_delta;
-  parameterization.Plus(x.data(), delta.data(), x_plus_delta.data());
-  Eigen::Vector3d x_plus_delta_expected = x + (global_J_local * delta);
+  manifold.Plus(x.data(), delta.data(), x_plus_delta.data());
+  Eigen::Vector3d x_plus_delta_expected = x + (global_to_local * delta);
   ExpectMatricesClose(x_plus_delta, x_plus_delta_expected, kTolerance);
 
   // Now test GradientChecker.
-  std::vector<const LocalParameterization*> parameterizations(2);
-  parameterizations[0] = &parameterization;
-  parameterizations[1] = NULL;
+  std::vector<const Manifold*> manifolds(2);
+  manifolds[0] = &manifold;
+  manifolds[1] = nullptr;
   NumericDiffOptions numeric_diff_options;
   GradientChecker::ProbeResults results;
   GradientChecker gradient_checker(
-      &cost_function, &parameterizations, numeric_diff_options);
+      &cost_function, &manifolds, numeric_diff_options);
 
   Problem::Options problem_options;
   problem_options.cost_function_ownership = DO_NOT_TAKE_OWNERSHIP;
-  problem_options.local_parameterization_ownership = DO_NOT_TAKE_OWNERSHIP;
+  problem_options.manifold_ownership = DO_NOT_TAKE_OWNERSHIP;
   Problem problem(problem_options);
   Eigen::Vector3d param0_solver;
   Eigen::Vector2d param1_solver;
-  problem.AddParameterBlock(param0_solver.data(), 3, &parameterization);
+  problem.AddParameterBlock(param0_solver.data(), 3, &manifold);
   problem.AddParameterBlock(param1_solver.data(), 2);
   problem.AddResidualBlock(
-      &cost_function, NULL, param0_solver.data(), param1_solver.data());
-  Solver::Options solver_options;
-  solver_options.check_gradients = true;
-  solver_options.initial_trust_region_radius = 1e10;
-  Solver solver;
-  Solver::Summary summary;
+      &cost_function, nullptr, param0_solver.data(), param1_solver.data());
 
   // First test case: everything is correct.
-  EXPECT_TRUE(gradient_checker.Probe(parameters.data(), kTolerance, NULL));
+  EXPECT_TRUE(gradient_checker.Probe(parameters.data(), kTolerance, nullptr));
   EXPECT_TRUE(gradient_checker.Probe(parameters.data(), kTolerance, &results))
       << results.error_log;
 
@@ -475,14 +487,14 @@
   ASSERT_EQ(results.return_value, true);
   ExpectMatricesClose(
       results.residuals, residual, std::numeric_limits<double>::epsilon());
-  CheckDimensions(results, parameter_sizes, local_parameter_sizes, 3);
+  CheckDimensions(results, parameter_sizes, tangent_sizes, 3);
   ExpectMatricesClose(
-      results.local_jacobians.at(0), j0 * global_J_local, kTolerance);
+      results.local_jacobians.at(0), j0 * global_to_local, kTolerance);
   ExpectMatricesClose(results.local_jacobians.at(1),
                       j1,
                       std::numeric_limits<double>::epsilon());
   ExpectMatricesClose(
-      results.local_numeric_jacobians.at(0), j0 * global_J_local, kTolerance);
+      results.local_numeric_jacobians.at(0), j0 * global_to_local, kTolerance);
   ExpectMatricesClose(results.local_numeric_jacobians.at(1), j1, kTolerance);
   ExpectMatricesClose(
       results.jacobians.at(0), j0, std::numeric_limits<double>::epsilon());
@@ -494,6 +506,13 @@
   EXPECT_TRUE(results.error_log.empty());
 
   // Test interaction with the 'check_gradients' option in Solver.
+  Solver::Options solver_options;
+  solver_options.linear_solver_type = DENSE_QR;
+  solver_options.check_gradients = true;
+  solver_options.initial_trust_region_radius = 1e10;
+  Solver solver;
+  Solver::Summary summary;
+
   param0_solver = param0;
   param1_solver = param1;
   solver.Solve(solver_options, &problem, &summary);
@@ -506,7 +525,7 @@
   j0_offset.setZero();
   j0_offset.col(2).setConstant(0.001);
   cost_function.SetJacobianOffset(0, j0_offset);
-  EXPECT_FALSE(gradient_checker.Probe(parameters.data(), kTolerance, NULL));
+  EXPECT_FALSE(gradient_checker.Probe(parameters.data(), kTolerance, nullptr));
   EXPECT_FALSE(gradient_checker.Probe(parameters.data(), kTolerance, &results))
       << results.error_log;
 
@@ -514,17 +533,17 @@
   ASSERT_EQ(results.return_value, true);
   ExpectMatricesClose(
       results.residuals, residual, std::numeric_limits<double>::epsilon());
-  CheckDimensions(results, parameter_sizes, local_parameter_sizes, 3);
+  CheckDimensions(results, parameter_sizes, tangent_sizes, 3);
   ASSERT_EQ(results.local_jacobians.size(), 2);
   ASSERT_EQ(results.local_numeric_jacobians.size(), 2);
   ExpectMatricesClose(results.local_jacobians.at(0),
-                      (j0 + j0_offset) * global_J_local,
+                      (j0 + j0_offset) * global_to_local,
                       kTolerance);
   ExpectMatricesClose(results.local_jacobians.at(1),
                       j1,
                       std::numeric_limits<double>::epsilon());
   ExpectMatricesClose(
-      results.local_numeric_jacobians.at(0), j0 * global_J_local, kTolerance);
+      results.local_numeric_jacobians.at(0), j0 * global_to_local, kTolerance);
   ExpectMatricesClose(results.local_numeric_jacobians.at(1), j1, kTolerance);
   ExpectMatricesClose(results.jacobians.at(0), j0 + j0_offset, kTolerance);
   ExpectMatricesClose(
@@ -540,10 +559,10 @@
   solver.Solve(solver_options, &problem, &summary);
   EXPECT_EQ(FAILURE, summary.termination_type);
 
-  // Now, zero out the local parameterization Jacobian of the 1st parameter
-  // with respect to the 3rd component. This makes the combination of
-  // cost function and local parameterization return correct values again.
-  parameterization.global_J_local.row(2).setZero();
+  // Now, zero out the manifold Jacobian with respect to the 3rd component of
+  // the 1st parameter. This makes the combination of cost function and manifold
+  // return correct values again.
+  manifold.global_to_local_.row(2).setZero();
 
   // Verify that the gradient checker does not treat this as an error.
   EXPECT_TRUE(gradient_checker.Probe(parameters.data(), kTolerance, &results))
@@ -553,17 +572,17 @@
   ASSERT_EQ(results.return_value, true);
   ExpectMatricesClose(
       results.residuals, residual, std::numeric_limits<double>::epsilon());
-  CheckDimensions(results, parameter_sizes, local_parameter_sizes, 3);
+  CheckDimensions(results, parameter_sizes, tangent_sizes, 3);
   ASSERT_EQ(results.local_jacobians.size(), 2);
   ASSERT_EQ(results.local_numeric_jacobians.size(), 2);
   ExpectMatricesClose(results.local_jacobians.at(0),
-                      (j0 + j0_offset) * parameterization.global_J_local,
+                      (j0 + j0_offset) * manifold.global_to_local_,
                       kTolerance);
   ExpectMatricesClose(results.local_jacobians.at(1),
                       j1,
                       std::numeric_limits<double>::epsilon());
   ExpectMatricesClose(results.local_numeric_jacobians.at(0),
-                      j0 * parameterization.global_J_local,
+                      j0 * manifold.global_to_local_,
                       kTolerance);
   ExpectMatricesClose(results.local_numeric_jacobians.at(1), j1, kTolerance);
   ExpectMatricesClose(results.jacobians.at(0), j0 + j0_offset, kTolerance);
@@ -581,6 +600,4 @@
   EXPECT_EQ(CONVERGENCE, summary.termination_type);
   EXPECT_LE(summary.final_cost, 1e-12);
 }
-
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/gradient_checking_cost_function.cc b/third_party/ceres/internal/ceres/gradient_checking_cost_function.cc
index 2eb6d62..8ca449b 100644
--- a/third_party/ceres/internal/ceres/gradient_checking_cost_function.cc
+++ b/third_party/ceres/internal/ceres/gradient_checking_cost_function.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -34,8 +34,10 @@
 #include <algorithm>
 #include <cmath>
 #include <cstdint>
+#include <memory>
 #include <numeric>
 #include <string>
+#include <utility>
 #include <vector>
 
 #include "ceres/dynamic_numeric_diff_cost_function.h"
@@ -50,45 +52,36 @@
 #include "ceres/types.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
-
-using std::abs;
-using std::max;
-using std::string;
-using std::vector;
+namespace ceres::internal {
 
 namespace {
 
-class GradientCheckingCostFunction : public CostFunction {
+class GradientCheckingCostFunction final : public CostFunction {
  public:
-  GradientCheckingCostFunction(
-      const CostFunction* function,
-      const std::vector<const LocalParameterization*>* local_parameterizations,
-      const NumericDiffOptions& options,
-      double relative_precision,
-      const string& extra_info,
-      GradientCheckingIterationCallback* callback)
+  GradientCheckingCostFunction(const CostFunction* function,
+                               const std::vector<const Manifold*>* manifolds,
+                               const NumericDiffOptions& options,
+                               double relative_precision,
+                               std::string extra_info,
+                               GradientCheckingIterationCallback* callback)
       : function_(function),
-        gradient_checker_(function, local_parameterizations, options),
+        gradient_checker_(function, manifolds, options),
         relative_precision_(relative_precision),
-        extra_info_(extra_info),
+        extra_info_(std::move(extra_info)),
         callback_(callback) {
     CHECK(callback_ != nullptr);
-    const vector<int32_t>& parameter_block_sizes =
+    const std::vector<int32_t>& parameter_block_sizes =
         function->parameter_block_sizes();
     *mutable_parameter_block_sizes() = parameter_block_sizes;
     set_num_residuals(function->num_residuals());
   }
 
-  virtual ~GradientCheckingCostFunction() {}
-
   bool Evaluate(double const* const* parameters,
                 double* residuals,
                 double** jacobians) const final {
     if (!jacobians) {
       // Nothing to check in this case; just forward.
-      return function_->Evaluate(parameters, residuals, NULL);
+      return function_->Evaluate(parameters, residuals, nullptr);
     }
 
     GradientChecker::ProbeResults results;
@@ -106,9 +99,10 @@
     MatrixRef(residuals, num_residuals, 1) = results.residuals;
 
     // Copy the original jacobian blocks into the jacobians array.
-    const vector<int32_t>& block_sizes = function_->parameter_block_sizes();
+    const std::vector<int32_t>& block_sizes =
+        function_->parameter_block_sizes();
     for (int k = 0; k < block_sizes.size(); k++) {
-      if (jacobians[k] != NULL) {
+      if (jacobians[k] != nullptr) {
         MatrixRef(jacobians[k],
                   results.jacobians[k].rows(),
                   results.jacobians[k].cols()) = results.jacobians[k];
@@ -128,7 +122,7 @@
   const CostFunction* function_;
   GradientChecker gradient_checker_;
   double relative_precision_;
-  string extra_info_;
+  std::string extra_info_;
   GradientCheckingIterationCallback* callback_;
 };
 
@@ -138,13 +132,14 @@
     : gradient_error_detected_(false) {}
 
 CallbackReturnType GradientCheckingIterationCallback::operator()(
-    const IterationSummary& summary) {
+    const IterationSummary& /*summary*/) {
   if (gradient_error_detected_) {
     LOG(ERROR) << "Gradient error detected. Terminating solver.";
     return SOLVER_ABORT;
   }
   return SOLVER_CONTINUE;
 }
+
 void GradientCheckingIterationCallback::SetGradientErrorDetected(
     std::string& error_log) {
   std::lock_guard<std::mutex> l(mutex_);
@@ -152,9 +147,9 @@
   error_log_ += "\n" + error_log;
 }
 
-CostFunction* CreateGradientCheckingCostFunction(
+std::unique_ptr<CostFunction> CreateGradientCheckingCostFunction(
     const CostFunction* cost_function,
-    const std::vector<const LocalParameterization*>* local_parameterizations,
+    const std::vector<const Manifold*>* manifolds,
     double relative_step_size,
     double relative_precision,
     const std::string& extra_info,
@@ -162,51 +157,49 @@
   NumericDiffOptions numeric_diff_options;
   numeric_diff_options.relative_step_size = relative_step_size;
 
-  return new GradientCheckingCostFunction(cost_function,
-                                          local_parameterizations,
-                                          numeric_diff_options,
-                                          relative_precision,
-                                          extra_info,
-                                          callback);
+  return std::make_unique<GradientCheckingCostFunction>(cost_function,
+                                                        manifolds,
+                                                        numeric_diff_options,
+                                                        relative_precision,
+                                                        extra_info,
+                                                        callback);
 }
 
-ProblemImpl* CreateGradientCheckingProblemImpl(
+std::unique_ptr<ProblemImpl> CreateGradientCheckingProblemImpl(
     ProblemImpl* problem_impl,
     double relative_step_size,
     double relative_precision,
     GradientCheckingIterationCallback* callback) {
   CHECK(callback != nullptr);
-  // We create new CostFunctions by wrapping the original CostFunction
-  // in a gradient checking CostFunction. So its okay for the
-  // ProblemImpl to take ownership of it and destroy it. The
-  // LossFunctions and LocalParameterizations are reused and since
-  // they are owned by problem_impl, gradient_checking_problem_impl
+  // We create new CostFunctions by wrapping the original CostFunction in a
+  // gradient checking CostFunction. So its okay for the ProblemImpl to take
+  // ownership of it and destroy it. The LossFunctions and Manifolds are reused
+  // and since they are owned by problem_impl, gradient_checking_problem_impl
   // should not take ownership of it.
   Problem::Options gradient_checking_problem_options;
   gradient_checking_problem_options.cost_function_ownership = TAKE_OWNERSHIP;
   gradient_checking_problem_options.loss_function_ownership =
       DO_NOT_TAKE_OWNERSHIP;
-  gradient_checking_problem_options.local_parameterization_ownership =
-      DO_NOT_TAKE_OWNERSHIP;
+  gradient_checking_problem_options.manifold_ownership = DO_NOT_TAKE_OWNERSHIP;
   gradient_checking_problem_options.context = problem_impl->context();
 
   NumericDiffOptions numeric_diff_options;
   numeric_diff_options.relative_step_size = relative_step_size;
 
-  ProblemImpl* gradient_checking_problem_impl =
-      new ProblemImpl(gradient_checking_problem_options);
+  auto gradient_checking_problem_impl =
+      std::make_unique<ProblemImpl>(gradient_checking_problem_options);
 
   Program* program = problem_impl->mutable_program();
 
-  // For every ParameterBlock in problem_impl, create a new parameter
-  // block with the same local parameterization and constancy.
-  const vector<ParameterBlock*>& parameter_blocks = program->parameter_blocks();
-  for (int i = 0; i < parameter_blocks.size(); ++i) {
-    ParameterBlock* parameter_block = parameter_blocks[i];
+  // For every ParameterBlock in problem_impl, create a new parameter block with
+  // the same manifold and constancy.
+  const std::vector<ParameterBlock*>& parameter_blocks =
+      program->parameter_blocks();
+  for (auto* parameter_block : parameter_blocks) {
     gradient_checking_problem_impl->AddParameterBlock(
         parameter_block->mutable_user_state(),
         parameter_block->Size(),
-        parameter_block->mutable_local_parameterization());
+        parameter_block->mutable_manifold());
 
     if (parameter_block->IsConstant()) {
       gradient_checking_problem_impl->SetParameterBlockConstant(
@@ -228,32 +221,33 @@
   // For every ResidualBlock in problem_impl, create a new
   // ResidualBlock by wrapping its CostFunction inside a
   // GradientCheckingCostFunction.
-  const vector<ResidualBlock*>& residual_blocks = program->residual_blocks();
+  const std::vector<ResidualBlock*>& residual_blocks =
+      program->residual_blocks();
   for (int i = 0; i < residual_blocks.size(); ++i) {
     ResidualBlock* residual_block = residual_blocks[i];
 
     // Build a human readable string which identifies the
     // ResidualBlock. This is used by the GradientCheckingCostFunction
     // when logging debugging information.
-    string extra_info =
+    std::string extra_info =
         StringPrintf("Residual block id %d; depends on parameters [", i);
-    vector<double*> parameter_blocks;
-    vector<const LocalParameterization*> local_parameterizations;
+    std::vector<double*> parameter_blocks;
+    std::vector<const Manifold*> manifolds;
     parameter_blocks.reserve(residual_block->NumParameterBlocks());
-    local_parameterizations.reserve(residual_block->NumParameterBlocks());
+    manifolds.reserve(residual_block->NumParameterBlocks());
     for (int j = 0; j < residual_block->NumParameterBlocks(); ++j) {
       ParameterBlock* parameter_block = residual_block->parameter_blocks()[j];
       parameter_blocks.push_back(parameter_block->mutable_user_state());
       StringAppendF(&extra_info, "%p", parameter_block->mutable_user_state());
       extra_info += (j < residual_block->NumParameterBlocks() - 1) ? ", " : "]";
-      local_parameterizations.push_back(problem_impl->GetParameterization(
-          parameter_block->mutable_user_state()));
+      manifolds.push_back(
+          problem_impl->GetManifold(parameter_block->mutable_user_state()));
     }
 
     // Wrap the original CostFunction in a GradientCheckingCostFunction.
     CostFunction* gradient_checking_cost_function =
         new GradientCheckingCostFunction(residual_block->cost_function(),
-                                         &local_parameterizations,
+                                         &manifolds,
                                          numeric_diff_options,
                                          relative_precision,
                                          extra_info,
@@ -283,5 +277,4 @@
   return gradient_checking_problem_impl;
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/gradient_checking_cost_function.h b/third_party/ceres/internal/ceres/gradient_checking_cost_function.h
index ea6e9b3..4ad3b6c 100644
--- a/third_party/ceres/internal/ceres/gradient_checking_cost_function.h
+++ b/third_party/ceres/internal/ceres/gradient_checking_cost_function.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -32,22 +32,23 @@
 #ifndef CERES_INTERNAL_GRADIENT_CHECKING_COST_FUNCTION_H_
 #define CERES_INTERNAL_GRADIENT_CHECKING_COST_FUNCTION_H_
 
+#include <memory>
 #include <mutex>
 #include <string>
 
 #include "ceres/cost_function.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 #include "ceres/iteration_callback.h"
-#include "ceres/local_parameterization.h"
+#include "ceres/manifold.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 class ProblemImpl;
 
 // Callback that collects information about gradient checking errors, and
 // will abort the solve as soon as an error occurs.
-class CERES_EXPORT_INTERNAL GradientCheckingIterationCallback
+class CERES_NO_EXPORT GradientCheckingIterationCallback
     : public IterationCallback {
  public:
   GradientCheckingIterationCallback();
@@ -73,9 +74,10 @@
 // with finite differences. This API is only intended for unit tests that intend
 // to  check the functionality of the GradientCheckingCostFunction
 // implementation directly.
-CERES_EXPORT_INTERNAL CostFunction* CreateGradientCheckingCostFunction(
+CERES_NO_EXPORT std::unique_ptr<CostFunction>
+CreateGradientCheckingCostFunction(
     const CostFunction* cost_function,
-    const std::vector<const LocalParameterization*>* local_parameterizations,
+    const std::vector<const Manifold*>* manifolds,
     double relative_step_size,
     double relative_precision,
     const std::string& extra_info,
@@ -92,8 +94,6 @@
 // iteration, the respective cost function will notify the
 // GradientCheckingIterationCallback.
 //
-// The caller owns the returned ProblemImpl object.
-//
 // Note: This is quite inefficient and is intended only for debugging.
 //
 // relative_step_size and relative_precision are parameters to control
@@ -102,13 +102,14 @@
 // jacobians obtained by numerically differentiating them. See the
 // documentation of 'numeric_derivative_relative_step_size' in solver.h for a
 // better explanation.
-CERES_EXPORT_INTERNAL ProblemImpl* CreateGradientCheckingProblemImpl(
+CERES_NO_EXPORT std::unique_ptr<ProblemImpl> CreateGradientCheckingProblemImpl(
     ProblemImpl* problem_impl,
     double relative_step_size,
     double relative_precision,
     GradientCheckingIterationCallback* callback);
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_GRADIENT_CHECKING_COST_FUNCTION_H_
diff --git a/third_party/ceres/internal/ceres/gradient_checking_cost_function_test.cc b/third_party/ceres/internal/ceres/gradient_checking_cost_function_test.cc
index 9ca51f8..545fcd2 100644
--- a/third_party/ceres/internal/ceres/gradient_checking_cost_function_test.cc
+++ b/third_party/ceres/internal/ceres/gradient_checking_cost_function_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -33,15 +33,15 @@
 #include <cmath>
 #include <cstdint>
 #include <memory>
+#include <random>
 #include <vector>
 
 #include "ceres/cost_function.h"
-#include "ceres/local_parameterization.h"
 #include "ceres/loss_function.h"
+#include "ceres/manifold.h"
 #include "ceres/parameter_block.h"
 #include "ceres/problem_impl.h"
 #include "ceres/program.h"
-#include "ceres/random.h"
 #include "ceres/residual_block.h"
 #include "ceres/sized_cost_function.h"
 #include "ceres/types.h"
@@ -49,10 +49,8 @@
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
-using std::vector;
 using testing::_;
 using testing::AllOf;
 using testing::AnyNumber;
@@ -70,13 +68,15 @@
  public:
   // The constructor of this function needs to know the number
   // of blocks desired, and the size of each block.
-  TestTerm(int arity, int const* dim) : arity_(arity) {
+  template <class UniformRandomFunctor>
+  TestTerm(int arity, int const* dim, UniformRandomFunctor&& randu)
+      : arity_(arity) {
     // Make 'arity' random vectors.
     a_.resize(arity_);
     for (int j = 0; j < arity_; ++j) {
       a_[j].resize(dim[j]);
       for (int u = 0; u < dim[j]; ++u) {
-        a_[j][u] = 2.0 * RandDouble() - 1.0;
+        a_[j][u] = randu();
       }
     }
 
@@ -88,7 +88,7 @@
 
   bool Evaluate(double const* const* parameters,
                 double* residuals,
-                double** jacobians) const {
+                double** jacobians) const override {
     // Compute a . x.
     double ax = 0;
     for (int j = 0; j < arity_; ++j) {
@@ -127,29 +127,30 @@
 
  private:
   int arity_;
-  vector<vector<double>> a_;
+  std::vector<std::vector<double>> a_;
 };
 
 TEST(GradientCheckingCostFunction, ResidualsAndJacobiansArePreservedTest) {
-  srand(5);
-
   // Test with 3 blocks of size 2, 3 and 4.
   int const arity = 3;
   int const dim[arity] = {2, 3, 4};
 
   // Make a random set of blocks.
-  vector<double*> parameters(arity);
+  std::vector<double*> parameters(arity);
+  std::mt19937 prng;
+  std::uniform_real_distribution<double> distribution(-1.0, 1.0);
+  auto randu = [&prng, &distribution] { return distribution(prng); };
   for (int j = 0; j < arity; ++j) {
     parameters[j] = new double[dim[j]];
     for (int u = 0; u < dim[j]; ++u) {
-      parameters[j][u] = 2.0 * RandDouble() - 1.0;
+      parameters[j][u] = randu();
     }
   }
 
   double original_residual;
   double residual;
-  vector<double*> original_jacobians(arity);
-  vector<double*> jacobians(arity);
+  std::vector<double*> original_jacobians(arity);
+  std::vector<double*> jacobians(arity);
 
   for (int j = 0; j < arity; ++j) {
     // Since residual is one dimensional the jacobians have the same
@@ -161,15 +162,15 @@
   const double kRelativeStepSize = 1e-6;
   const double kRelativePrecision = 1e-4;
 
-  TestTerm<-1, -1> term(arity, dim);
+  TestTerm<-1, -1> term(arity, dim, randu);
   GradientCheckingIterationCallback callback;
-  std::unique_ptr<CostFunction> gradient_checking_cost_function(
+  auto gradient_checking_cost_function =
       CreateGradientCheckingCostFunction(&term,
-                                         NULL,
+                                         nullptr,
                                          kRelativeStepSize,
                                          kRelativePrecision,
                                          "Ignored.",
-                                         &callback));
+                                         &callback);
   term.Evaluate(&parameters[0], &original_residual, &original_jacobians[0]);
 
   gradient_checking_cost_function->Evaluate(
@@ -188,23 +189,24 @@
 }
 
 TEST(GradientCheckingCostFunction, SmokeTest) {
-  srand(5);
-
   // Test with 3 blocks of size 2, 3 and 4.
   int const arity = 3;
   int const dim[arity] = {2, 3, 4};
 
   // Make a random set of blocks.
-  vector<double*> parameters(arity);
+  std::vector<double*> parameters(arity);
+  std::mt19937 prng;
+  std::uniform_real_distribution<double> distribution(-1.0, 1.0);
+  auto randu = [&prng, &distribution] { return distribution(prng); };
   for (int j = 0; j < arity; ++j) {
     parameters[j] = new double[dim[j]];
     for (int u = 0; u < dim[j]; ++u) {
-      parameters[j][u] = 2.0 * RandDouble() - 1.0;
+      parameters[j][u] = randu();
     }
   }
 
   double residual;
-  vector<double*> jacobians(arity);
+  std::vector<double*> jacobians(arity);
   for (int j = 0; j < arity; ++j) {
     // Since residual is one dimensional the jacobians have the same size as the
     // parameter blocks.
@@ -217,15 +219,15 @@
   // Should have one term that's bad, causing everything to get dumped.
   LOG(INFO) << "Bad gradient";
   {
-    TestTerm<1, 2> term(arity, dim);
+    TestTerm<1, 2> term(arity, dim, randu);
     GradientCheckingIterationCallback callback;
-    std::unique_ptr<CostFunction> gradient_checking_cost_function(
+    auto gradient_checking_cost_function =
         CreateGradientCheckingCostFunction(&term,
-                                           NULL,
+                                           nullptr,
                                            kRelativeStepSize,
                                            kRelativePrecision,
                                            "Fuzzy banana",
-                                           &callback));
+                                           &callback);
     EXPECT_TRUE(gradient_checking_cost_function->Evaluate(
         &parameters[0], &residual, &jacobians[0]));
     EXPECT_TRUE(callback.gradient_error_detected());
@@ -237,15 +239,15 @@
   // The gradient is correct, so no errors are reported.
   LOG(INFO) << "Good gradient";
   {
-    TestTerm<-1, -1> term(arity, dim);
+    TestTerm<-1, -1> term(arity, dim, randu);
     GradientCheckingIterationCallback callback;
-    std::unique_ptr<CostFunction> gradient_checking_cost_function(
+    auto gradient_checking_cost_function =
         CreateGradientCheckingCostFunction(&term,
-                                           NULL,
+                                           nullptr,
                                            kRelativeStepSize,
                                            kRelativePrecision,
                                            "Fuzzy banana",
-                                           &callback));
+                                           &callback);
     EXPECT_TRUE(gradient_checking_cost_function->Evaluate(
         &parameters[0], &residual, &jacobians[0]));
     EXPECT_FALSE(callback.gradient_error_detected());
@@ -267,7 +269,6 @@
     set_num_residuals(num_residuals);
     mutable_parameter_block_sizes()->push_back(parameter_block_size);
   }
-  virtual ~UnaryCostFunction() {}
 
   bool Evaluate(double const* const* parameters,
                 double* residuals,
@@ -324,7 +325,7 @@
 };
 
 // Verify that the two ParameterBlocks are formed from the same user
-// array and have the same LocalParameterization object.
+// array and have the same Manifold objects.
 static void ParameterBlocksAreEquivalent(const ParameterBlock* left,
                                          const ParameterBlock* right) {
   CHECK(left != nullptr);
@@ -332,8 +333,8 @@
   EXPECT_EQ(left->user_state(), right->user_state());
   EXPECT_EQ(left->Size(), right->Size());
   EXPECT_EQ(left->Size(), right->Size());
-  EXPECT_EQ(left->LocalSize(), right->LocalSize());
-  EXPECT_EQ(left->local_parameterization(), right->local_parameterization());
+  EXPECT_EQ(left->TangentSize(), right->TangentSize());
+  EXPECT_EQ(left->manifold(), right->manifold());
   EXPECT_EQ(left->IsConstant(), right->IsConstant());
 }
 
@@ -349,23 +350,23 @@
   problem_impl.AddParameterBlock(y, 4);
   problem_impl.SetParameterBlockConstant(y);
   problem_impl.AddParameterBlock(z, 5);
-  problem_impl.AddParameterBlock(w, 4, new QuaternionParameterization);
+  problem_impl.AddParameterBlock(w, 4, new QuaternionManifold);
   // clang-format off
   problem_impl.AddResidualBlock(new UnaryCostFunction(2, 3),
-                                NULL, x);
+                                nullptr, x);
   problem_impl.AddResidualBlock(new BinaryCostFunction(6, 5, 4),
-                                NULL, z, y);
+                                nullptr, z, y);
   problem_impl.AddResidualBlock(new BinaryCostFunction(3, 3, 5),
                                 new TrivialLoss, x, z);
   problem_impl.AddResidualBlock(new BinaryCostFunction(7, 5, 3),
-                                NULL, z, x);
+                                nullptr, z, x);
   problem_impl.AddResidualBlock(new TernaryCostFunction(1, 5, 3, 4),
-                                NULL, z, x, y);
+                                nullptr, z, x, y);
   // clang-format on
 
   GradientCheckingIterationCallback callback;
-  std::unique_ptr<ProblemImpl> gradient_checking_problem_impl(
-      CreateGradientCheckingProblemImpl(&problem_impl, 1.0, 1.0, &callback));
+  auto gradient_checking_problem_impl =
+      CreateGradientCheckingProblemImpl(&problem_impl, 1.0, 1.0, &callback);
 
   // The dimensions of the two problems match.
   EXPECT_EQ(problem_impl.NumParameterBlocks(),
@@ -420,13 +421,13 @@
   double x[] = {1.0, 2.0, 3.0};
   ProblemImpl problem_impl;
   problem_impl.AddParameterBlock(x, 3);
-  problem_impl.AddResidualBlock(new UnaryCostFunction(2, 3), NULL, x);
+  problem_impl.AddResidualBlock(new UnaryCostFunction(2, 3), nullptr, x);
   problem_impl.SetParameterLowerBound(x, 0, 0.9);
   problem_impl.SetParameterUpperBound(x, 1, 2.5);
 
   GradientCheckingIterationCallback callback;
-  std::unique_ptr<ProblemImpl> gradient_checking_problem_impl(
-      CreateGradientCheckingProblemImpl(&problem_impl, 1.0, 1.0, &callback));
+  auto gradient_checking_problem_impl =
+      CreateGradientCheckingProblemImpl(&problem_impl, 1.0, 1.0, &callback);
 
   // The dimensions of the two problems match.
   EXPECT_EQ(problem_impl.NumParameterBlocks(),
@@ -447,5 +448,4 @@
   }
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/gradient_problem.cc b/third_party/ceres/internal/ceres/gradient_problem.cc
index ba33fbc..ee228b8 100644
--- a/third_party/ceres/internal/ceres/gradient_problem.cc
+++ b/third_party/ceres/internal/ceres/gradient_problem.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -30,49 +30,57 @@
 
 #include "ceres/gradient_problem.h"
 
-#include "ceres/local_parameterization.h"
+#include <memory>
+
 #include "glog/logging.h"
 
 namespace ceres {
 
 GradientProblem::GradientProblem(FirstOrderFunction* function)
     : function_(function),
-      parameterization_(
-          new IdentityParameterization(function_->NumParameters())),
-      scratch_(new double[function_->NumParameters()]) {}
+      manifold_(std::make_unique<EuclideanManifold<DYNAMIC>>(
+          function_->NumParameters())),
+      scratch_(new double[function_->NumParameters()]) {
+  CHECK(function != nullptr);
+}
 
 GradientProblem::GradientProblem(FirstOrderFunction* function,
-                                 LocalParameterization* parameterization)
-    : function_(function),
-      parameterization_(parameterization),
-      scratch_(new double[function_->NumParameters()]) {
-  CHECK_EQ(function_->NumParameters(), parameterization_->GlobalSize());
+                                 Manifold* manifold)
+    : function_(function), scratch_(new double[function_->NumParameters()]) {
+  CHECK(function != nullptr);
+  if (manifold != nullptr) {
+    manifold_.reset(manifold);
+  } else {
+    manifold_ = std::make_unique<EuclideanManifold<DYNAMIC>>(
+        function_->NumParameters());
+  }
+  CHECK_EQ(function_->NumParameters(), manifold_->AmbientSize());
 }
 
 int GradientProblem::NumParameters() const {
   return function_->NumParameters();
 }
 
-int GradientProblem::NumLocalParameters() const {
-  return parameterization_->LocalSize();
+int GradientProblem::NumTangentParameters() const {
+  return manifold_->TangentSize();
 }
 
 bool GradientProblem::Evaluate(const double* parameters,
                                double* cost,
                                double* gradient) const {
-  if (gradient == NULL) {
-    return function_->Evaluate(parameters, cost, NULL);
+  if (gradient == nullptr) {
+    return function_->Evaluate(parameters, cost, nullptr);
   }
 
   return (function_->Evaluate(parameters, cost, scratch_.get()) &&
-          parameterization_->MultiplyByJacobian(
+          manifold_->RightMultiplyByPlusJacobian(
               parameters, 1, scratch_.get(), gradient));
 }
 
 bool GradientProblem::Plus(const double* x,
                            const double* delta,
                            double* x_plus_delta) const {
-  return parameterization_->Plus(x, delta, x_plus_delta);
+  return manifold_->Plus(x, delta, x_plus_delta);
 }
 
 }  // namespace ceres
diff --git a/third_party/ceres/internal/ceres/gradient_problem_evaluator.h b/third_party/ceres/internal/ceres/gradient_problem_evaluator.h
index d224dbe..fe99767 100644
--- a/third_party/ceres/internal/ceres/gradient_problem_evaluator.h
+++ b/third_party/ceres/internal/ceres/gradient_problem_evaluator.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -32,30 +32,33 @@
 #define CERES_INTERNAL_GRADIENT_PROBLEM_EVALUATOR_H_
 
 #include <map>
+#include <memory>
 #include <string>
 
 #include "ceres/evaluator.h"
 #include "ceres/execution_summary.h"
 #include "ceres/gradient_problem.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
+#include "ceres/sparse_matrix.h"
 #include "ceres/wall_time.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
-class GradientProblemEvaluator : public Evaluator {
+class CERES_NO_EXPORT GradientProblemEvaluator final : public Evaluator {
  public:
   explicit GradientProblemEvaluator(const GradientProblem& problem)
       : problem_(problem) {}
-  virtual ~GradientProblemEvaluator() {}
-  SparseMatrix* CreateJacobian() const final { return nullptr; }
-  bool Evaluate(const EvaluateOptions& evaluate_options,
+
+  std::unique_ptr<SparseMatrix> CreateJacobian() const final { return nullptr; }
+
+  bool Evaluate(const EvaluateOptions& /*evaluate_options*/,
                 const double* state,
                 double* cost,
-                double* residuals,
+                double* /*residuals*/,
                 double* gradient,
                 SparseMatrix* jacobian) final {
-    CHECK(jacobian == NULL);
+    CHECK(jacobian == nullptr);
     ScopedExecutionTimer total_timer("Evaluator::Total", &execution_summary_);
     // The reason we use Residual and Jacobian here even when we are
     // only computing the cost and gradient has to do with the fact
@@ -65,7 +68,7 @@
     // to be consistent across the code base for the time accounting
     // to work.
     ScopedExecutionTimer call_type_timer(
-        gradient == NULL ? "Evaluator::Residual" : "Evaluator::Jacobian",
+        gradient == nullptr ? "Evaluator::Residual" : "Evaluator::Jacobian",
         &execution_summary_);
     return problem_.Evaluate(state, cost, gradient);
   }
@@ -79,7 +82,7 @@
   int NumParameters() const final { return problem_.NumParameters(); }
 
   int NumEffectiveParameters() const final {
-    return problem_.NumLocalParameters();
+    return problem_.NumTangentParameters();
   }
 
   int NumResiduals() const final { return 1; }
@@ -93,7 +96,8 @@
   ::ceres::internal::ExecutionSummary execution_summary_;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_GRADIENT_PROBLEM_EVALUATOR_H_
diff --git a/third_party/ceres/internal/ceres/gradient_problem_solver.cc b/third_party/ceres/internal/ceres/gradient_problem_solver.cc
index b72fad9..ad2ea13 100644
--- a/third_party/ceres/internal/ceres/gradient_problem_solver.cc
+++ b/third_party/ceres/internal/ceres/gradient_problem_solver.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -30,13 +30,15 @@
 
 #include "ceres/gradient_problem_solver.h"
 
+#include <map>
 #include <memory>
+#include <string>
 
 #include "ceres/callbacks.h"
 #include "ceres/gradient_problem.h"
 #include "ceres/gradient_problem_evaluator.h"
 #include "ceres/internal/eigen.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 #include "ceres/map_util.h"
 #include "ceres/minimizer.h"
 #include "ceres/solver.h"
@@ -48,7 +50,6 @@
 namespace ceres {
 using internal::StringAppendF;
 using internal::StringPrintf;
-using std::string;
 
 namespace {
 
@@ -92,7 +93,7 @@
   return solver_options.IsValid(error);
 }
 
-GradientProblemSolver::~GradientProblemSolver() {}
+GradientProblemSolver::~GradientProblemSolver() = default;
 
 void GradientProblemSolver::Solve(const GradientProblemSolver::Options& options,
                                   const GradientProblem& problem,
@@ -112,7 +113,7 @@
   *summary = Summary();
   // clang-format off
   summary->num_parameters                    = problem.NumParameters();
-  summary->num_local_parameters              = problem.NumLocalParameters();
+  summary->num_tangent_parameters            = problem.NumTangentParameters();
   summary->line_search_direction_type        = options.line_search_direction_type;         //  NOLINT
   summary->line_search_interpolation_type    = options.line_search_interpolation_type;     //  NOLINT
   summary->line_search_type                  = options.line_search_type;
@@ -135,21 +136,22 @@
   // now.
   Minimizer::Options minimizer_options =
       Minimizer::Options(GradientProblemSolverOptionsToSolverOptions(options));
-  minimizer_options.evaluator.reset(new GradientProblemEvaluator(problem));
+  minimizer_options.evaluator =
+      std::make_unique<GradientProblemEvaluator>(problem);
 
   std::unique_ptr<IterationCallback> logging_callback;
   if (options.logging_type != SILENT) {
-    logging_callback.reset(
-        new LoggingCallback(LINE_SEARCH, options.minimizer_progress_to_stdout));
+    logging_callback = std::make_unique<LoggingCallback>(
+        LINE_SEARCH, options.minimizer_progress_to_stdout);
     minimizer_options.callbacks.insert(minimizer_options.callbacks.begin(),
                                        logging_callback.get());
   }
 
   std::unique_ptr<IterationCallback> state_updating_callback;
   if (options.update_state_every_iteration) {
-    state_updating_callback.reset(
-        new GradientProblemSolverStateUpdatingCallback(
-            problem.NumParameters(), solution.data(), parameters_ptr));
+    state_updating_callback =
+        std::make_unique<GradientProblemSolverStateUpdatingCallback>(
+            problem.NumParameters(), solution.data(), parameters_ptr);
     minimizer_options.callbacks.insert(minimizer_options.callbacks.begin(),
                                        state_updating_callback.get());
   }
@@ -179,7 +181,7 @@
     SetSummaryFinalCost(summary);
   }
 
-  const std::map<string, CallStatistics>& evaluator_statistics =
+  const std::map<std::string, CallStatistics>& evaluator_statistics =
       minimizer_options.evaluator->Statistics();
   {
     const CallStatistics& call_stats = FindWithDefault(
@@ -202,7 +204,7 @@
   return internal::IsSolutionUsable(*this);
 }
 
-string GradientProblemSolver::Summary::BriefReport() const {
+std::string GradientProblemSolver::Summary::BriefReport() const {
   return StringPrintf(
       "Ceres GradientProblemSolver Report: "
       "Iterations: %d, "
@@ -215,17 +217,20 @@
       TerminationTypeToString(termination_type));
 }
 
-string GradientProblemSolver::Summary::FullReport() const {
+std::string GradientProblemSolver::Summary::FullReport() const {
   using internal::VersionString;
 
-  string report = string("\nSolver Summary (v " + VersionString() + ")\n\n");
+  // NOTE operator+ is not usable for concatenating a string and a string_view.
+  std::string report =
+      std::string{"\nSolver Summary (v "}.append(VersionString()) + ")\n\n";
 
   StringAppendF(&report, "Parameters          % 25d\n", num_parameters);
-  if (num_local_parameters != num_parameters) {
-    StringAppendF(&report, "Local parameters    % 25d\n", num_local_parameters);
+  if (num_tangent_parameters != num_parameters) {
+    StringAppendF(
+        &report, "Tangent parameters   % 25d\n", num_tangent_parameters);
   }
 
-  string line_search_direction_string;
+  std::string line_search_direction_string;
   if (line_search_direction_type == LBFGS) {
     line_search_direction_string = StringPrintf("LBFGS (%d)", max_lbfgs_rank);
   } else if (line_search_direction_type == NONLINEAR_CONJUGATE_GRADIENT) {
@@ -240,7 +245,7 @@
                 "Line search direction     %19s\n",
                 line_search_direction_string.c_str());
 
-  const string line_search_type_string = StringPrintf(
+  const std::string line_search_type_string = StringPrintf(
       "%s %s",
       LineSearchInterpolationTypeToString(line_search_interpolation_type),
       LineSearchTypeToString(line_search_type));
diff --git a/third_party/ceres/internal/ceres/gradient_problem_solver_test.cc b/third_party/ceres/internal/ceres/gradient_problem_solver_test.cc
index f01d206..f8eabf6 100644
--- a/third_party/ceres/internal/ceres/gradient_problem_solver_test.cc
+++ b/third_party/ceres/internal/ceres/gradient_problem_solver_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -33,14 +33,11 @@
 #include "ceres/gradient_problem.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // Rosenbrock function; see http://en.wikipedia.org/wiki/Rosenbrock_function .
 class Rosenbrock : public ceres::FirstOrderFunction {
  public:
-  virtual ~Rosenbrock() {}
-
   bool Evaluate(const double* parameters,
                 double* cost,
                 double* gradient) const final {
@@ -48,7 +45,7 @@
     const double y = parameters[1];
 
     cost[0] = (1.0 - x) * (1.0 - x) + 100.0 * (y - x * x) * (y - x * x);
-    if (gradient != NULL) {
+    if (gradient != nullptr) {
       gradient[0] = -2.0 * (1.0 - x) - 200.0 * (y - x * x) * 2.0 * x;
       gradient[1] = 200.0 * (y - x * x);
     }
@@ -73,13 +70,12 @@
 }
 
 class QuadraticFunction : public ceres::FirstOrderFunction {
-  virtual ~QuadraticFunction() {}
   bool Evaluate(const double* parameters,
                 double* cost,
                 double* gradient) const final {
     const double x = parameters[0];
     *cost = 0.5 * (5.0 - x) * (5.0 - x);
-    if (gradient != NULL) {
+    if (gradient != nullptr) {
       gradient[0] = x - 5.0;
     }
 
@@ -90,7 +86,6 @@
 
 struct RememberingCallback : public IterationCallback {
   explicit RememberingCallback(double* x) : calls(0), x(x) {}
-  virtual ~RememberingCallback() {}
   CallbackReturnType operator()(const IterationSummary& summary) final {
     x_values.push_back(*x);
     return SOLVER_CONTINUE;
@@ -116,8 +111,8 @@
   ceres::Solve(options, problem, &x, &summary);
   num_iterations = summary.iterations.size() - 1;
   EXPECT_GT(num_iterations, 1);
-  for (int i = 0; i < callback.x_values.size(); ++i) {
-    EXPECT_EQ(50.0, callback.x_values[i]);
+  for (double value : callback.x_values) {
+    EXPECT_EQ(50.0, value);
   }
 
   // Second try: with updating
@@ -131,5 +126,4 @@
   EXPECT_NE(original_x, callback.x_values[1]);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/gradient_problem_test.cc b/third_party/ceres/internal/ceres/gradient_problem_test.cc
index 8934138..52757a3 100644
--- a/third_party/ceres/internal/ceres/gradient_problem_test.cc
+++ b/third_party/ceres/internal/ceres/gradient_problem_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -32,15 +32,14 @@
 
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 class QuadraticTestFunction : public ceres::FirstOrderFunction {
  public:
-  explicit QuadraticTestFunction(bool* flag_to_set_on_destruction = NULL)
+  explicit QuadraticTestFunction(bool* flag_to_set_on_destruction = nullptr)
       : flag_to_set_on_destruction_(flag_to_set_on_destruction) {}
 
-  virtual ~QuadraticTestFunction() {
+  ~QuadraticTestFunction() override {
     if (flag_to_set_on_destruction_) {
       *flag_to_set_on_destruction_ = true;
     }
@@ -51,7 +50,7 @@
                 double* gradient) const final {
     const double x = parameters[0];
     cost[0] = x * x;
-    if (gradient != NULL) {
+    if (gradient != nullptr) {
       gradient[0] = 2.0 * x;
     }
     return true;
@@ -69,24 +68,16 @@
   EXPECT_TRUE(is_destructed);
 }
 
-TEST(GradientProblem, EvaluationWithoutParameterizationOrGradient) {
-  ceres::GradientProblem problem(new QuadraticTestFunction());
-  double x = 7.0;
-  double cost = 0;
-  problem.Evaluate(&x, &cost, NULL);
-  EXPECT_EQ(x * x, cost);
-}
-
-TEST(GradientProblem, EvalutaionWithParameterizationAndNoGradient) {
+TEST(GradientProblem, EvaluationWithManifoldAndNoGradient) {
   ceres::GradientProblem problem(new QuadraticTestFunction(),
-                                 new IdentityParameterization(1));
+                                 new EuclideanManifold<1>);
   double x = 7.0;
   double cost = 0;
-  problem.Evaluate(&x, &cost, NULL);
+  problem.Evaluate(&x, &cost, nullptr);
   EXPECT_EQ(x * x, cost);
 }
 
-TEST(GradientProblem, EvaluationWithoutParameterizationAndWithGradient) {
+TEST(GradientProblem, EvaluationWithoutManifoldAndWithGradient) {
   ceres::GradientProblem problem(new QuadraticTestFunction());
   double x = 7.0;
   double cost = 0;
@@ -95,9 +86,9 @@
   EXPECT_EQ(2.0 * x, gradient);
 }
 
-TEST(GradientProblem, EvaluationWithParameterizationAndWithGradient) {
+TEST(GradientProblem, EvaluationWithManifoldAndWithGradient) {
   ceres::GradientProblem problem(new QuadraticTestFunction(),
-                                 new IdentityParameterization(1));
+                                 new EuclideanManifold<1>);
   double x = 7.0;
   double cost = 0;
   double gradient = 0;
@@ -105,5 +96,4 @@
   EXPECT_EQ(2.0 * x, gradient);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/graph.h b/third_party/ceres/internal/ceres/graph.h
index 9b26158..4f8dfb9 100644
--- a/third_party/ceres/internal/ceres/graph.h
+++ b/third_party/ceres/internal/ceres/graph.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -36,21 +36,19 @@
 #include <unordered_set>
 #include <utility>
 
+#include "ceres/internal/export.h"
 #include "ceres/map_util.h"
 #include "ceres/pair_hash.h"
 #include "ceres/types.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // A unweighted undirected graph templated over the vertex ids. Vertex
 // should be hashable.
 template <typename Vertex>
-class Graph {
+class CERES_NO_EXPORT Graph {
  public:
-  Graph() {}
-
   // Add a vertex.
   void AddVertex(const Vertex& vertex) {
     if (vertices_.insert(vertex).second) {
@@ -106,8 +104,6 @@
 template <typename Vertex>
 class WeightedGraph {
  public:
-  WeightedGraph() {}
-
   // Add a weighted vertex. If the vertex already exists in the graph,
   // its weight is set to the new weight.
   void AddVertex(const Vertex& vertex, double weight) {
@@ -209,7 +205,6 @@
       edge_weights_;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_INTERNAL_GRAPH_H_
diff --git a/third_party/ceres/internal/ceres/graph_algorithms.h b/third_party/ceres/internal/ceres/graph_algorithms.h
index 7d63b33..4ebc8b3 100644
--- a/third_party/ceres/internal/ceres/graph_algorithms.h
+++ b/third_party/ceres/internal/ceres/graph_algorithms.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -34,22 +34,23 @@
 #define CERES_INTERNAL_GRAPH_ALGORITHMS_H_
 
 #include <algorithm>
+#include <memory>
 #include <unordered_map>
 #include <unordered_set>
 #include <utility>
 #include <vector>
 
 #include "ceres/graph.h"
+#include "ceres/internal/export.h"
 #include "ceres/wall_time.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // Compare two vertices of a graph by their degrees, if the degrees
 // are equal then order them by their ids.
 template <typename Vertex>
-class VertexTotalOrdering {
+class CERES_NO_EXPORT VertexTotalOrdering {
  public:
   explicit VertexTotalOrdering(const Graph<Vertex>& graph) : graph_(graph) {}
 
@@ -257,11 +258,11 @@
 // spanning forest, or a collection of linear paths that span the
 // graph G.
 template <typename Vertex>
-WeightedGraph<Vertex>* Degree2MaximumSpanningForest(
+std::unique_ptr<WeightedGraph<Vertex>> Degree2MaximumSpanningForest(
     const WeightedGraph<Vertex>& graph) {
   // Array of edges sorted in decreasing order of their weights.
   std::vector<std::pair<double, std::pair<Vertex, Vertex>>> weighted_edges;
-  WeightedGraph<Vertex>* forest = new WeightedGraph<Vertex>();
+  auto forest = std::make_unique<WeightedGraph<Vertex>>();
 
   // Disjoint-set to keep track of the connected components in the
   // maximum spanning tree.
@@ -338,7 +339,6 @@
   return forest;
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_INTERNAL_GRAPH_ALGORITHMS_H_
diff --git a/third_party/ceres/internal/ceres/graph_algorithms_test.cc b/third_party/ceres/internal/ceres/graph_algorithms_test.cc
index d5dd02e..6c86668 100644
--- a/third_party/ceres/internal/ceres/graph_algorithms_test.cc
+++ b/third_party/ceres/internal/ceres/graph_algorithms_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -33,15 +33,13 @@
 #include <algorithm>
 #include <memory>
 #include <unordered_set>
+#include <vector>
 
 #include "ceres/graph.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
-
-using std::vector;
+namespace ceres::internal {
 
 TEST(IndependentSetOrdering, Chain) {
   Graph<int> graph;
@@ -58,7 +56,7 @@
 
   // 0-1-2-3-4
   // 0, 2, 4 should be in the independent set.
-  vector<int> ordering;
+  std::vector<int> ordering;
   int independent_set_size = IndependentSetOrdering(graph, &ordering);
 
   sort(ordering.begin(), ordering.begin() + 3);
@@ -92,7 +90,7 @@
   //      |
   //      3
   // 1, 2, 3, 4 should be in the independent set.
-  vector<int> ordering;
+  std::vector<int> ordering;
   int independent_set_size = IndependentSetOrdering(graph, &ordering);
   EXPECT_EQ(independent_set_size, 4);
   EXPECT_EQ(ordering.size(), 5);
@@ -220,7 +218,7 @@
   // guarantees that it will always be the first vertex in the
   // ordering vector.
   {
-    vector<int> ordering;
+    std::vector<int> ordering;
     ordering.push_back(0);
     ordering.push_back(1);
     ordering.push_back(2);
@@ -232,7 +230,7 @@
   }
 
   {
-    vector<int> ordering;
+    std::vector<int> ordering;
     ordering.push_back(1);
     ordering.push_back(0);
     ordering.push_back(2);
@@ -244,5 +242,4 @@
   }
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/graph_test.cc b/third_party/ceres/internal/ceres/graph_test.cc
index 2154a06..8c8afc6 100644
--- a/third_party/ceres/internal/ceres/graph_test.cc
+++ b/third_party/ceres/internal/ceres/graph_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -34,8 +34,7 @@
 
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST(Graph, EmptyGraph) {
   Graph<int> graph;
@@ -148,5 +147,4 @@
   EXPECT_EQ(graph.EdgeWeight(2, 3), 0);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/gtest/gtest.h b/third_party/ceres/internal/ceres/gtest/gtest.h
index a034077..e749057 100644
--- a/third_party/ceres/internal/ceres/gtest/gtest.h
+++ b/third_party/ceres/internal/ceres/gtest/gtest.h
@@ -49,12 +49,14 @@
 
 // GOOGLETEST_CM0001 DO NOT DELETE
 
-#ifndef GTEST_INCLUDE_GTEST_GTEST_H_
-#define GTEST_INCLUDE_GTEST_GTEST_H_
+#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_H_
+#define GOOGLETEST_INCLUDE_GTEST_GTEST_H_
 
+#include <cstddef>
 #include <limits>
 #include <memory>
 #include <ostream>
+#include <type_traits>
 #include <vector>
 
 // Copyright 2005, Google Inc.
@@ -93,8 +95,8 @@
 
 // GOOGLETEST_CM0001 DO NOT DELETE
 
-#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
-#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
+#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
+#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
 
 // Copyright 2005, Google Inc.
 // All rights reserved.
@@ -138,8 +140,8 @@
 
 // GOOGLETEST_CM0001 DO NOT DELETE
 
-#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
-#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
+#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
+#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
 
 // Environment-describing macros
 // -----------------------------
@@ -170,10 +172,6 @@
 //                              is/isn't available.
 //   GTEST_HAS_EXCEPTIONS     - Define it to 1/0 to indicate that exceptions
 //                              are enabled.
-//   GTEST_HAS_GLOBAL_STRING  - Define it to 1/0 to indicate that ::string
-//                              is/isn't available
-//   GTEST_HAS_GLOBAL_WSTRING - Define it to 1/0 to indicate that ::wstring
-//                              is/isn't available
 //   GTEST_HAS_POSIX_RE       - Define it to 1/0 to indicate that POSIX regular
 //                              expressions are/aren't available.
 //   GTEST_HAS_PTHREAD        - Define it to 1/0 to indicate that <pthread.h>
@@ -219,6 +217,7 @@
 //   GTEST_OS_FREEBSD  - FreeBSD
 //   GTEST_OS_FUCHSIA  - Fuchsia
 //   GTEST_OS_GNU_KFREEBSD - GNU/kFreeBSD
+//   GTEST_OS_HAIKU    - Haiku
 //   GTEST_OS_HPUX     - HP-UX
 //   GTEST_OS_LINUX    - Linux
 //     GTEST_OS_LINUX_ANDROID - Google Android
@@ -238,7 +237,7 @@
 //     GTEST_OS_WINDOWS_RT       - Windows Store App/WinRT
 //   GTEST_OS_ZOS      - z/OS
 //
-// Among the platforms, Cygwin, Linux, Max OS X, and Windows have the
+// Among the platforms, Cygwin, Linux, Mac OS X, and Windows have the
 // most stable support.  Since core members of the Google Test project
 // don't have access to other platforms, support for them may be less
 // stable.  If you notice any problems on your platform, please notify
@@ -291,23 +290,32 @@
 //   GTEST_AMBIGUOUS_ELSE_BLOCKER_ - for disabling a gcc warning.
 //   GTEST_ATTRIBUTE_UNUSED_  - declares that a class' instances or a
 //                              variable don't have to be used.
-//   GTEST_DISALLOW_ASSIGN_   - disables operator=.
+//   GTEST_DISALLOW_ASSIGN_   - disables copy operator=.
 //   GTEST_DISALLOW_COPY_AND_ASSIGN_ - disables copy ctor and operator=.
+//   GTEST_DISALLOW_MOVE_ASSIGN_   - disables move operator=.
+//   GTEST_DISALLOW_MOVE_AND_ASSIGN_ - disables move ctor and operator=.
 //   GTEST_MUST_USE_RESULT_   - declares that a function's result must be used.
 //   GTEST_INTENTIONAL_CONST_COND_PUSH_ - start code section where MSVC C4127 is
 //                                        suppressed (constant conditional).
 //   GTEST_INTENTIONAL_CONST_COND_POP_  - finish code section where MSVC C4127
 //                                        is suppressed.
+//   GTEST_INTERNAL_HAS_ANY - for enabling UniversalPrinter<std::any> or
+//                            UniversalPrinter<absl::any> specializations.
+//   GTEST_INTERNAL_HAS_OPTIONAL - for enabling UniversalPrinter<std::optional>
+//   or
+//                                 UniversalPrinter<absl::optional>
+//                                 specializations.
+//   GTEST_INTERNAL_HAS_STRING_VIEW - for enabling Matcher<std::string_view> or
+//                                    Matcher<absl::string_view>
+//                                    specializations.
+//   GTEST_INTERNAL_HAS_VARIANT - for enabling UniversalPrinter<std::variant> or
+//                                UniversalPrinter<absl::variant>
+//                                specializations.
 //
 // Synchronization:
 //   Mutex, MutexLock, ThreadLocal, GetThreadCount()
 //                            - synchronization primitives.
 //
-// Template meta programming:
-//   IteratorTraits - partial implementation of std::iterator_traits, which
-//                    is not available in libCstd when compiled with Sun C++.
-//
-//
 // Regular expressions:
 //   RE             - a simple regular expression class using the POSIX
 //                    Extended Regular Expression syntax on UNIX-like platforms
@@ -329,8 +337,7 @@
 //
 // Integer types:
 //   TypeWithSize   - maps an integer to a int type.
-//   Int32, UInt32, Int64, UInt64, TimeInMillis
-//                  - integers of known sizes.
+//   TimeInMillis   - integers of known sizes.
 //   BiggestInt     - the biggest signed integer type.
 //
 // Command-line utilities:
@@ -341,7 +348,7 @@
 // Environment variable utilities:
 //   GetEnv()             - gets the value of an environment variable.
 //   BoolFromGTestEnv()   - parses a bool environment variable.
-//   Int32FromGTestEnv()  - parses an Int32 environment variable.
+//   Int32FromGTestEnv()  - parses an int32_t environment variable.
 //   StringFromGTestEnv() - parses a string environment variable.
 //
 // Deprecation warnings:
@@ -354,7 +361,10 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <memory>
+
+#include <cerrno>
+#include <cstdint>
+#include <limits>
 #include <type_traits>
 
 #ifndef _WIN32_WCE
@@ -367,14 +377,11 @@
 # include <TargetConditionals.h>
 #endif
 
-// Brings in the definition of HAS_GLOBAL_STRING.  This must be done
-// BEFORE we test HAS_GLOBAL_STRING.
-#include <string>     // NOLINT
-#include <algorithm>  // NOLINT
-#include <iostream>   // NOLINT
-#include <sstream>    // NOLINT
+#include <iostream>  // NOLINT
+#include <locale>
+#include <memory>
+#include <string>  // NOLINT
 #include <tuple>
-#include <utility>
 #include <vector>  // NOLINT
 
 // Copyright 2015, Google Inc.
@@ -406,13 +413,50 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 //
+// Injection point for custom user configurations. See README for details
+//
+// ** Custom implementation starts here **
+
+#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_
+#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_
+
+#endif  // GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// 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 Google Inc. 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.
+//
 // The Google C++ Testing and Mocking Framework (Google Test)
 //
 // This header file defines the GTEST_OS_* macro.
 // It is separate from gtest-port.h so that custom/gtest-port.h can include it.
 
-#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_
-#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_
+#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_
+#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_
 
 // Determines the platform on which Google Test is compiled.
 #ifdef __CYGWIN__
@@ -447,6 +491,7 @@
 # define GTEST_OS_OS2 1
 #elif defined __APPLE__
 # define GTEST_OS_MAC 1
+# include <TargetConditionals.h>
 # if TARGET_OS_IPHONE
 #  define GTEST_OS_IOS 1
 # endif
@@ -479,46 +524,17 @@
 # define GTEST_OS_OPENBSD 1
 #elif defined __QNX__
 # define GTEST_OS_QNX 1
+#elif defined(__HAIKU__)
+#define GTEST_OS_HAIKU 1
+#elif defined ESP8266
+#define GTEST_OS_ESP8266 1
+#elif defined ESP32
+#define GTEST_OS_ESP32 1
+#elif defined(__XTENSA__)
+#define GTEST_OS_XTENSA 1
 #endif  // __CYGWIN__
 
-#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_
-// Copyright 2015, Google Inc.
-// All rights reserved.
-//
-// 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 Google Inc. 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.
-//
-// Injection point for custom user configurations. See README for details
-//
-// ** Custom implementation starts here **
-
-#ifndef GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_
-#define GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_
-
-#endif  // GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_
+#endif  // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_
 
 #if !defined(GTEST_DEV_EMAIL_)
 # define GTEST_DEV_EMAIL_ "googletestframework@@googlegroups.com"
@@ -592,6 +608,10 @@
 // WindowsTypesTest.CRITICAL_SECTIONIs_RTL_CRITICAL_SECTION.
 typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION;
 #endif
+#elif GTEST_OS_XTENSA
+#include <unistd.h>
+// Xtensa toolchains define strcasecmp in the string.h header instead of
+// strings.h. string.h is already included.
 #else
 // This assumes that non-Windows OSes provide unistd.h. For OSes where this
 // is not the case, we need to include headers that provide the functions
@@ -605,13 +625,14 @@
 #  include <android/api-level.h>  // NOLINT
 #endif
 
-// Defines this to true iff Google Test can use POSIX regular expressions.
+// Defines this to true if and only if Google Test can use POSIX regular
+// expressions.
 #ifndef GTEST_HAS_POSIX_RE
 # if GTEST_OS_LINUX_ANDROID
 // On Android, <regex.h> is only available starting with Gingerbread.
 #  define GTEST_HAS_POSIX_RE (__ANDROID_API__ >= 9)
 # else
-#  define GTEST_HAS_POSIX_RE (!GTEST_OS_WINDOWS)
+#define GTEST_HAS_POSIX_RE (!GTEST_OS_WINDOWS && !GTEST_OS_XTENSA)
 # endif
 #endif
 
@@ -646,7 +667,7 @@
 // The user didn't tell us whether exceptions are enabled, so we need
 // to figure it out.
 # if defined(_MSC_VER) && defined(_CPPUNWIND)
-// MSVC defines _CPPUNWIND to 1 iff exceptions are enabled.
+// MSVC defines _CPPUNWIND to 1 if and only if exceptions are enabled.
 #  define GTEST_HAS_EXCEPTIONS 1
 # elif defined(__BORLANDC__)
 // C++Builder's implementation of the STL uses the _HAS_EXCEPTIONS
@@ -657,16 +678,17 @@
 #  endif  // _HAS_EXCEPTIONS
 #  define GTEST_HAS_EXCEPTIONS _HAS_EXCEPTIONS
 # elif defined(__clang__)
-// clang defines __EXCEPTIONS iff exceptions are enabled before clang 220714,
-// but iff cleanups are enabled after that. In Obj-C++ files, there can be
-// cleanups for ObjC exceptions which also need cleanups, even if C++ exceptions
-// are disabled. clang has __has_feature(cxx_exceptions) which checks for C++
-// exceptions starting at clang r206352, but which checked for cleanups prior to
-// that. To reliably check for C++ exception availability with clang, check for
+// clang defines __EXCEPTIONS if and only if exceptions are enabled before clang
+// 220714, but if and only if cleanups are enabled after that. In Obj-C++ files,
+// there can be cleanups for ObjC exceptions which also need cleanups, even if
+// C++ exceptions are disabled. clang has __has_feature(cxx_exceptions) which
+// checks for C++ exceptions starting at clang r206352, but which checked for
+// cleanups prior to that. To reliably check for C++ exception availability with
+// clang, check for
 // __EXCEPTIONS && __has_feature(cxx_exceptions).
 #  define GTEST_HAS_EXCEPTIONS (__EXCEPTIONS && __has_feature(cxx_exceptions))
 # elif defined(__GNUC__) && __EXCEPTIONS
-// gcc defines __EXCEPTIONS to 1 iff exceptions are enabled.
+// gcc defines __EXCEPTIONS to 1 if and only if exceptions are enabled.
 #  define GTEST_HAS_EXCEPTIONS 1
 # elif defined(__SUNPRO_CC)
 // Sun Pro CC supports exceptions.  However, there is no compile-time way of
@@ -674,7 +696,7 @@
 // they are enabled unless the user tells us otherwise.
 #  define GTEST_HAS_EXCEPTIONS 1
 # elif defined(__IBMCPP__) && __EXCEPTIONS
-// xlC defines __EXCEPTIONS to 1 iff exceptions are enabled.
+// xlC defines __EXCEPTIONS to 1 if and only if exceptions are enabled.
 #  define GTEST_HAS_EXCEPTIONS 1
 # elif defined(__HP_aCC)
 // Exception handling is in effect by default in HP aCC compiler. It has to
@@ -687,37 +709,18 @@
 # endif  // defined(_MSC_VER) || defined(__BORLANDC__)
 #endif  // GTEST_HAS_EXCEPTIONS
 
-#if !defined(GTEST_HAS_STD_STRING)
-// Even though we don't use this macro any longer, we keep it in case
-// some clients still depend on it.
-# define GTEST_HAS_STD_STRING 1
-#elif !GTEST_HAS_STD_STRING
-// The user told us that ::std::string isn't available.
-# error "::std::string isn't available."
-#endif  // !defined(GTEST_HAS_STD_STRING)
-
-#ifndef GTEST_HAS_GLOBAL_STRING
-# define GTEST_HAS_GLOBAL_STRING 0
-#endif  // GTEST_HAS_GLOBAL_STRING
-
 #ifndef GTEST_HAS_STD_WSTRING
 // The user didn't tell us whether ::std::wstring is available, so we need
 // to figure it out.
 // Cygwin 1.7 and below doesn't support ::std::wstring.
 // Solaris' libc++ doesn't support it either.  Android has
 // no support for it at least as recent as Froyo (2.2).
-# define GTEST_HAS_STD_WSTRING \
-    (!(GTEST_OS_LINUX_ANDROID || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS))
+#define GTEST_HAS_STD_WSTRING                                         \
+  (!(GTEST_OS_LINUX_ANDROID || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \
+     GTEST_OS_HAIKU || GTEST_OS_ESP32 || GTEST_OS_ESP8266 || GTEST_OS_XTENSA))
 
 #endif  // GTEST_HAS_STD_WSTRING
 
-#ifndef GTEST_HAS_GLOBAL_WSTRING
-// The user didn't tell us whether ::wstring is available, so we need
-// to figure it out.
-# define GTEST_HAS_GLOBAL_WSTRING \
-    (GTEST_HAS_STD_WSTRING && GTEST_HAS_GLOBAL_STRING)
-#endif  // GTEST_HAS_GLOBAL_WSTRING
-
 // Determines whether RTTI is available.
 #ifndef GTEST_HAS_RTTI
 // The user didn't tell us whether RTTI is enabled, so we need to
@@ -725,13 +728,14 @@
 
 # ifdef _MSC_VER
 
-#  ifdef _CPPRTTI  // MSVC defines this macro iff RTTI is enabled.
+#ifdef _CPPRTTI  // MSVC defines this macro if and only if RTTI is enabled.
 #   define GTEST_HAS_RTTI 1
 #  else
 #   define GTEST_HAS_RTTI 0
 #  endif
 
-// Starting with version 4.3.2, gcc defines __GXX_RTTI iff RTTI is enabled.
+// Starting with version 4.3.2, gcc defines __GXX_RTTI if and only if RTTI is
+// enabled.
 # elif defined(__GNUC__)
 
 #  ifdef __GXX_RTTI
@@ -788,10 +792,11 @@
 //
 // To disable threading support in Google Test, add -DGTEST_HAS_PTHREAD=0
 // to your compiler flags.
-#define GTEST_HAS_PTHREAD                                             \
-  (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_HPUX || GTEST_OS_QNX || \
+#define GTEST_HAS_PTHREAD                                                      \
+  (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_HPUX || GTEST_OS_QNX ||          \
    GTEST_OS_FREEBSD || GTEST_OS_NACL || GTEST_OS_NETBSD || GTEST_OS_FUCHSIA || \
-   GTEST_OS_DRAGONFLY || GTEST_OS_GNU_KFREEBSD || GTEST_OS_OPENBSD)
+   GTEST_OS_DRAGONFLY || GTEST_OS_GNU_KFREEBSD || GTEST_OS_OPENBSD ||          \
+   GTEST_OS_HAIKU)
 #endif  // GTEST_HAS_PTHREAD
 
 #if GTEST_HAS_PTHREAD
@@ -836,7 +841,8 @@
 #ifndef GTEST_HAS_STREAM_REDIRECTION
 // By default, we assume that stream redirection is supported on all
 // platforms except known mobile ones.
-# if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT
+#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || \
+    GTEST_OS_WINDOWS_RT || GTEST_OS_ESP8266 || GTEST_OS_XTENSA
 #  define GTEST_HAS_STREAM_REDIRECTION 0
 # else
 #  define GTEST_HAS_STREAM_REDIRECTION 1
@@ -845,13 +851,12 @@
 
 // Determines whether to support death tests.
 // pops up a dialog window that cannot be suppressed programmatically.
-#if (GTEST_OS_LINUX || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS ||   \
-     (GTEST_OS_MAC && !GTEST_OS_IOS) ||                         \
-     (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER) ||                  \
-     GTEST_OS_WINDOWS_MINGW || GTEST_OS_AIX || GTEST_OS_HPUX || \
-     GTEST_OS_OPENBSD || GTEST_OS_QNX || GTEST_OS_FREEBSD || \
-     GTEST_OS_NETBSD || GTEST_OS_FUCHSIA || GTEST_OS_DRAGONFLY || \
-     GTEST_OS_GNU_KFREEBSD)
+#if (GTEST_OS_LINUX || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS ||             \
+     (GTEST_OS_MAC && !GTEST_OS_IOS) ||                                   \
+     (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER) || GTEST_OS_WINDOWS_MINGW ||  \
+     GTEST_OS_AIX || GTEST_OS_HPUX || GTEST_OS_OPENBSD || GTEST_OS_QNX || \
+     GTEST_OS_FREEBSD || GTEST_OS_NETBSD || GTEST_OS_FUCHSIA ||           \
+     GTEST_OS_DRAGONFLY || GTEST_OS_GNU_KFREEBSD || GTEST_OS_HAIKU)
 # define GTEST_HAS_DEATH_TEST 1
 #endif
 
@@ -931,17 +936,28 @@
 #endif
 
 
-// A macro to disallow operator=
+// A macro to disallow copy operator=
 // This should be used in the private: declarations for a class.
 #define GTEST_DISALLOW_ASSIGN_(type) \
-  void operator=(type const &) = delete
+  type& operator=(type const &) = delete
 
 // A macro to disallow copy constructor and operator=
 // This should be used in the private: declarations for a class.
 #define GTEST_DISALLOW_COPY_AND_ASSIGN_(type) \
-  type(type const&) = delete; \
+  type(type const&) = delete;                 \
   type& operator=(type const&) = delete
 
+// A macro to disallow move operator=
+// This should be used in the private: declarations for a class.
+#define GTEST_DISALLOW_MOVE_ASSIGN_(type) \
+  type& operator=(type &&) noexcept = delete
+
+// A macro to disallow move constructor and operator=
+// This should be used in the private: declarations for a class.
+#define GTEST_DISALLOW_MOVE_AND_ASSIGN_(type) \
+  type(type&&) noexcept = delete;             \
+  type& operator=(type&&) noexcept = delete
+
 // Tell the compiler to warn about unused return values for functions declared
 // with this macro.  The macro should be used on function declarations
 // following the argument list:
@@ -1057,6 +1073,18 @@
 # define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
 #endif  // __clang__
 
+// A function level attribute to disable HWAddressSanitizer instrumentation.
+#if defined(__clang__)
+# if __has_feature(hwaddress_sanitizer)
+#  define GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ \
+       __attribute__((no_sanitize("hwaddress")))
+# else
+#  define GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_
+# endif  // __has_feature(hwaddress_sanitizer)
+#else
+# define GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_
+#endif  // __clang__
+
 // A function level attribute to disable ThreadSanitizer instrumentation.
 #if defined(__clang__)
 # if __has_feature(thread_sanitizer)
@@ -1099,42 +1127,6 @@
 // expression is false, compiler will issue an error containing this identifier.
 #define GTEST_COMPILE_ASSERT_(expr, msg) static_assert(expr, #msg)
 
-// StaticAssertTypeEqHelper is used by StaticAssertTypeEq defined in gtest.h.
-//
-// This template is declared, but intentionally undefined.
-template <typename T1, typename T2>
-struct StaticAssertTypeEqHelper;
-
-template <typename T>
-struct StaticAssertTypeEqHelper<T, T> {
-  enum { value = true };
-};
-
-// Same as std::is_same<>.
-template <typename T, typename U>
-struct IsSame {
-  enum { value = false };
-};
-template <typename T>
-struct IsSame<T, T> {
-  enum { value = true };
-};
-
-// Evaluates to the number of elements in 'array'.
-#define GTEST_ARRAY_SIZE_(array) (sizeof(array) / sizeof(array[0]))
-
-#if GTEST_HAS_GLOBAL_STRING
-typedef ::string string;
-#else
-typedef ::std::string string;
-#endif  // GTEST_HAS_GLOBAL_STRING
-
-#if GTEST_HAS_GLOBAL_WSTRING
-typedef ::wstring wstring;
-#elif GTEST_HAS_STD_WSTRING
-typedef ::std::wstring wstring;
-#endif  // GTEST_HAS_GLOBAL_WSTRING
-
 // A helper for suppressing warnings on constant condition.  It just
 // returns 'condition'.
 GTEST_API_ bool IsTrue(bool condition);
@@ -1156,21 +1148,15 @@
   // Constructs an RE from a string.
   RE(const ::std::string& regex) { Init(regex.c_str()); }  // NOLINT
 
-# if GTEST_HAS_GLOBAL_STRING
-
-  RE(const ::string& regex) { Init(regex.c_str()); }  // NOLINT
-
-# endif  // GTEST_HAS_GLOBAL_STRING
-
   RE(const char* regex) { Init(regex); }  // NOLINT
   ~RE();
 
   // Returns the string representation of the regex.
   const char* pattern() const { return pattern_; }
 
-  // FullMatch(str, re) returns true iff regular expression re matches
-  // the entire str.
-  // PartialMatch(str, re) returns true iff regular expression re
+  // FullMatch(str, re) returns true if and only if regular expression re
+  // matches the entire str.
+  // PartialMatch(str, re) returns true if and only if regular expression re
   // matches a substring of str (including str itself).
   static bool FullMatch(const ::std::string& str, const RE& re) {
     return FullMatch(str.c_str(), re);
@@ -1179,17 +1165,6 @@
     return PartialMatch(str.c_str(), re);
   }
 
-# if GTEST_HAS_GLOBAL_STRING
-
-  static bool FullMatch(const ::string& str, const RE& re) {
-    return FullMatch(str.c_str(), re);
-  }
-  static bool PartialMatch(const ::string& str, const RE& re) {
-    return PartialMatch(str.c_str(), re);
-  }
-
-# endif  // GTEST_HAS_GLOBAL_STRING
-
   static bool FullMatch(const char* str, const RE& re);
   static bool PartialMatch(const char* str, const RE& re);
 
@@ -1297,19 +1272,6 @@
     GTEST_LOG_(FATAL) << #posix_call << "failed with error " \
                       << gtest_error
 
-// Adds reference to a type if it is not a reference type,
-// otherwise leaves it unchanged.  This is the same as
-// tr1::add_reference, which is not widely available yet.
-template <typename T>
-struct AddReference { typedef T& type; };  // NOLINT
-template <typename T>
-struct AddReference<T&> { typedef T& type; };  // NOLINT
-
-// A handy wrapper around AddReference that works when the argument T
-// depends on template parameters.
-#define GTEST_ADD_REFERENCE_(T) \
-    typename ::testing::internal::AddReference<T>::type
-
 // Transforms "T" into "const T&" according to standard reference collapsing
 // rules (this is only needed as a backport for C++98 compilers that do not
 // support reference collapsing). Specifically, it transforms:
@@ -1443,9 +1405,6 @@
 // Deprecated: pass the args vector by value instead.
 void SetInjectableArgvs(const std::vector<std::string>* new_argvs);
 void SetInjectableArgvs(const std::vector<std::string>& new_argvs);
-#if GTEST_HAS_GLOBAL_STRING
-void SetInjectableArgvs(const std::vector< ::string>& new_argvs);
-#endif  // GTEST_HAS_GLOBAL_STRING
 void ClearInjectableArgvs();
 
 #endif  // GTEST_HAS_DEATH_TEST
@@ -1537,7 +1496,8 @@
   void Reset(Handle handle);
 
  private:
-  // Returns true iff the handle is a valid handle object that can be closed.
+  // Returns true if and only if the handle is a valid handle object that can be
+  // closed.
   bool IsCloseable() const;
 
   Handle handle_;
@@ -1639,7 +1599,8 @@
   // When non-NULL, used to block execution until the controller thread
   // notifies.
   Notification* const thread_can_start_;
-  bool finished_;  // true iff we know that the thread function has finished.
+  bool finished_;  // true if and only if we know that the thread function has
+                   // finished.
   pthread_t thread_;  // The native thread object.
 
   GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam);
@@ -1904,7 +1865,7 @@
   class DefaultValueHolderFactory : public ValueHolderFactory {
    public:
     DefaultValueHolderFactory() {}
-    virtual ValueHolder* MakeNewHolder() const { return new ValueHolder(); }
+    ValueHolder* MakeNewHolder() const override { return new ValueHolder(); }
 
    private:
     GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultValueHolderFactory);
@@ -1913,7 +1874,7 @@
   class InstanceValueHolderFactory : public ValueHolderFactory {
    public:
     explicit InstanceValueHolderFactory(const T& value) : value_(value) {}
-    virtual ValueHolder* MakeNewHolder() const {
+    ValueHolder* MakeNewHolder() const override {
       return new ValueHolder(value_);
     }
 
@@ -2113,7 +2074,7 @@
   class DefaultValueHolderFactory : public ValueHolderFactory {
    public:
     DefaultValueHolderFactory() {}
-    virtual ValueHolder* MakeNewHolder() const { return new ValueHolder(); }
+    ValueHolder* MakeNewHolder() const override { return new ValueHolder(); }
 
    private:
     GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultValueHolderFactory);
@@ -2122,7 +2083,7 @@
   class InstanceValueHolderFactory : public ValueHolderFactory {
    public:
     explicit InstanceValueHolderFactory(const T& value) : value_(value) {}
-    virtual ValueHolder* MakeNewHolder() const {
+    ValueHolder* MakeNewHolder() const override {
       return new ValueHolder(value_);
     }
 
@@ -2192,47 +2153,12 @@
 // we cannot detect it.
 GTEST_API_ size_t GetThreadCount();
 
-template <bool bool_value>
-struct bool_constant {
-  typedef bool_constant<bool_value> type;
-  static const bool value = bool_value;
-};
-template <bool bool_value> const bool bool_constant<bool_value>::value;
-
-typedef bool_constant<false> false_type;
-typedef bool_constant<true> true_type;
-
-template <typename T, typename U>
-struct is_same : public false_type {};
-
-template <typename T>
-struct is_same<T, T> : public true_type {};
-
-template <typename Iterator>
-struct IteratorTraits {
-  typedef typename Iterator::value_type value_type;
-};
-
-
-template <typename T>
-struct IteratorTraits<T*> {
-  typedef T value_type;
-};
-
-template <typename T>
-struct IteratorTraits<const T*> {
-  typedef T value_type;
-};
-
 #if GTEST_OS_WINDOWS
 # define GTEST_PATH_SEP_ "\\"
 # define GTEST_HAS_ALT_PATH_SEP_ 1
-// The biggest signed integer type the compiler supports.
-typedef __int64 BiggestInt;
 #else
 # define GTEST_PATH_SEP_ "/"
 # define GTEST_HAS_ALT_PATH_SEP_ 0
-typedef long long BiggestInt;  // NOLINT
 #endif  // GTEST_OS_WINDOWS
 
 // Utilities for char.
@@ -2263,6 +2189,19 @@
 inline bool IsXDigit(char ch) {
   return isxdigit(static_cast<unsigned char>(ch)) != 0;
 }
+#ifdef __cpp_char8_t
+inline bool IsXDigit(char8_t ch) {
+  return isxdigit(static_cast<unsigned char>(ch)) != 0;
+}
+#endif
+inline bool IsXDigit(char16_t ch) {
+  const unsigned char low_byte = static_cast<unsigned char>(ch);
+  return ch == low_byte && isxdigit(low_byte) != 0;
+}
+inline bool IsXDigit(char32_t ch) {
+  const unsigned char low_byte = static_cast<unsigned char>(ch);
+  return ch == low_byte && isxdigit(low_byte) != 0;
+}
 inline bool IsXDigit(wchar_t ch) {
   const unsigned char low_byte = static_cast<unsigned char>(ch);
   return ch == low_byte && isxdigit(low_byte) != 0;
@@ -2297,16 +2236,16 @@
 typedef struct _stat StatStruct;
 
 # ifdef __BORLANDC__
-inline int IsATTY(int fd) { return isatty(fd); }
+inline int DoIsATTY(int fd) { return isatty(fd); }
 inline int StrCaseCmp(const char* s1, const char* s2) {
   return stricmp(s1, s2);
 }
 inline char* StrDup(const char* src) { return strdup(src); }
 # else  // !__BORLANDC__
 #  if GTEST_OS_WINDOWS_MOBILE
-inline int IsATTY(int /* fd */) { return 0; }
+inline int DoIsATTY(int /* fd */) { return 0; }
 #  else
-inline int IsATTY(int fd) { return _isatty(fd); }
+inline int DoIsATTY(int fd) { return _isatty(fd); }
 #  endif  // GTEST_OS_WINDOWS_MOBILE
 inline int StrCaseCmp(const char* s1, const char* s2) {
   return _stricmp(s1, s2);
@@ -2327,12 +2266,28 @@
 }
 # endif  // GTEST_OS_WINDOWS_MOBILE
 
+#elif GTEST_OS_ESP8266
+typedef struct stat StatStruct;
+
+inline int FileNo(FILE* file) { return fileno(file); }
+inline int DoIsATTY(int fd) { return isatty(fd); }
+inline int Stat(const char* path, StatStruct* buf) {
+  // stat function not implemented on ESP8266
+  return 0;
+}
+inline int StrCaseCmp(const char* s1, const char* s2) {
+  return strcasecmp(s1, s2);
+}
+inline char* StrDup(const char* src) { return strdup(src); }
+inline int RmDir(const char* dir) { return rmdir(dir); }
+inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); }
+
 #else
 
 typedef struct stat StatStruct;
 
 inline int FileNo(FILE* file) { return fileno(file); }
-inline int IsATTY(int fd) { return isatty(fd); }
+inline int DoIsATTY(int fd) { return isatty(fd); }
 inline int Stat(const char* path, StatStruct* buf) { return stat(path, buf); }
 inline int StrCaseCmp(const char* s1, const char* s2) {
   return strcasecmp(s1, s2);
@@ -2343,23 +2298,39 @@
 
 #endif  // GTEST_OS_WINDOWS
 
+inline int IsATTY(int fd) {
+  // DoIsATTY might change errno (for example ENOTTY in case you redirect stdout
+  // to a file on Linux), which is unexpected, so save the previous value, and
+  // restore it after the call.
+  int savedErrno = errno;
+  int isAttyValue = DoIsATTY(fd);
+  errno = savedErrno;
+
+  return isAttyValue;
+}
+
 // Functions deprecated by MSVC 8.0.
 
 GTEST_DISABLE_MSC_DEPRECATED_PUSH_()
 
-inline const char* StrNCpy(char* dest, const char* src, size_t n) {
-  return strncpy(dest, src, n);
-}
-
 // ChDir(), FReopen(), FDOpen(), Read(), Write(), Close(), and
 // StrError() aren't needed on Windows CE at this time and thus not
 // defined there.
 
-#if !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT
+#if !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_WINDOWS_PHONE && \
+    !GTEST_OS_WINDOWS_RT && !GTEST_OS_ESP8266 && !GTEST_OS_XTENSA
 inline int ChDir(const char* dir) { return chdir(dir); }
 #endif
 inline FILE* FOpen(const char* path, const char* mode) {
+#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MINGW
+  struct wchar_codecvt : public std::codecvt<wchar_t, char, std::mbstate_t> {};
+  std::wstring_convert<wchar_codecvt> converter;
+  std::wstring wide_path = converter.from_bytes(path);
+  std::wstring wide_mode = converter.from_bytes(mode);
+  return _wfopen(wide_path.c_str(), wide_mode.c_str());
+#else  // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MINGW
   return fopen(path, mode);
+#endif  // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MINGW
 }
 #if !GTEST_OS_WINDOWS_MOBILE
 inline FILE *FReopen(const char* path, const char* mode, FILE* stream) {
@@ -2379,8 +2350,9 @@
 inline const char* StrError(int errnum) { return strerror(errnum); }
 #endif
 inline const char* GetEnv(const char* name) {
-#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT
-  // We are on Windows CE, which has no environment variables.
+#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || \
+    GTEST_OS_WINDOWS_RT || GTEST_OS_ESP8266 || GTEST_OS_XTENSA
+  // We are on an embedded platform, which has no environment variables.
   static_cast<void>(name);  // To prevent 'unused argument' warning.
   return nullptr;
 #elif defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9)
@@ -2422,15 +2394,13 @@
 # define GTEST_SNPRINTF_ snprintf
 #endif
 
-// The maximum number a BiggestInt can represent.  This definition
-// works no matter BiggestInt is represented in one's complement or
-// two's complement.
+// The biggest signed integer type the compiler supports.
 //
-// We cannot rely on numeric_limits in STL, as __int64 and long long
-// are not part of standard C++ and numeric_limits doesn't need to be
-// defined for them.
-const BiggestInt kMaxBiggestInt =
-    ~(static_cast<BiggestInt>(1) << (8*sizeof(BiggestInt) - 1));
+// long long is guaranteed to be at least 64-bits in C++11.
+using BiggestInt = long long;  // NOLINT
+
+// The maximum number a BiggestInt can represent.
+constexpr BiggestInt kMaxBiggestInt = (std::numeric_limits<BiggestInt>::max)();
 
 // This template class serves as a compile-time function from size to
 // type.  It maps a size in bytes to a primitive type with that
@@ -2455,40 +2425,27 @@
  public:
   // This prevents the user from using TypeWithSize<N> with incorrect
   // values of N.
-  typedef void UInt;
+  using UInt = void;
 };
 
 // The specialization for size 4.
 template <>
 class TypeWithSize<4> {
  public:
-  // unsigned int has size 4 in both gcc and MSVC.
-  //
-  // As base/basictypes.h doesn't compile on Windows, we cannot use
-  // uint32, uint64, and etc here.
-  typedef int Int;
-  typedef unsigned int UInt;
+  using Int = std::int32_t;
+  using UInt = std::uint32_t;
 };
 
 // The specialization for size 8.
 template <>
 class TypeWithSize<8> {
  public:
-#if GTEST_OS_WINDOWS
-  typedef __int64 Int;
-  typedef unsigned __int64 UInt;
-#else
-  typedef long long Int;  // NOLINT
-  typedef unsigned long long UInt;  // NOLINT
-#endif  // GTEST_OS_WINDOWS
+  using Int = std::int64_t;
+  using UInt = std::uint64_t;
 };
 
 // Integer types of known sizes.
-typedef TypeWithSize<4>::Int Int32;
-typedef TypeWithSize<4>::UInt UInt32;
-typedef TypeWithSize<8>::Int Int64;
-typedef TypeWithSize<8>::UInt UInt64;
-typedef TypeWithSize<8>::Int TimeInMillis;  // Represents time in milliseconds.
+using TimeInMillis = int64_t;  // Represents time in milliseconds.
 
 // Utilities for command line flags and environment variables.
 
@@ -2507,7 +2464,7 @@
 // Macros for declaring flags.
 # define GTEST_DECLARE_bool_(name) GTEST_API_ extern bool GTEST_FLAG(name)
 # define GTEST_DECLARE_int32_(name) \
-    GTEST_API_ extern ::testing::internal::Int32 GTEST_FLAG(name)
+    GTEST_API_ extern std::int32_t GTEST_FLAG(name)
 # define GTEST_DECLARE_string_(name) \
     GTEST_API_ extern ::std::string GTEST_FLAG(name)
 
@@ -2515,7 +2472,7 @@
 # define GTEST_DEFINE_bool_(name, default_val, doc) \
     GTEST_API_ bool GTEST_FLAG(name) = (default_val)
 # define GTEST_DEFINE_int32_(name, default_val, doc) \
-    GTEST_API_ ::testing::internal::Int32 GTEST_FLAG(name) = (default_val)
+    GTEST_API_ std::int32_t GTEST_FLAG(name) = (default_val)
 # define GTEST_DEFINE_string_(name, default_val, doc) \
     GTEST_API_ ::std::string GTEST_FLAG(name) = (default_val)
 
@@ -2530,12 +2487,13 @@
 // Parses 'str' for a 32-bit signed integer.  If successful, writes the result
 // to *value and returns true; otherwise leaves *value unchanged and returns
 // false.
-bool ParseInt32(const Message& src_text, const char* str, Int32* value);
+GTEST_API_ bool ParseInt32(const Message& src_text, const char* str,
+                           int32_t* value);
 
-// Parses a bool/Int32/string from the environment variable
+// Parses a bool/int32_t/string from the environment variable
 // corresponding to the given Google Test flag.
 bool BoolFromGTestEnv(const char* flag, bool default_val);
-GTEST_API_ Int32 Int32FromGTestEnv(const char* flag, Int32 default_val);
+GTEST_API_ int32_t Int32FromGTestEnv(const char* flag, int32_t default_val);
 std::string OutputFlagAlsoCheckEnvVar();
 const char* StringFromGTestEnv(const char* flag, const char* default_val);
 
@@ -2562,7 +2520,122 @@
 
 #endif  // !defined(GTEST_INTERNAL_DEPRECATED)
 
-#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
+#if GTEST_HAS_ABSL
+// Always use absl::any for UniversalPrinter<> specializations if googletest
+// is built with absl support.
+#define GTEST_INTERNAL_HAS_ANY 1
+#include "absl/types/any.h"
+namespace testing {
+namespace internal {
+using Any = ::absl::any;
+}  // namespace internal
+}  // namespace testing
+#else
+#ifdef __has_include
+#if __has_include(<any>) && __cplusplus >= 201703L
+// Otherwise for C++17 and higher use std::any for UniversalPrinter<>
+// specializations.
+#define GTEST_INTERNAL_HAS_ANY 1
+#include <any>
+namespace testing {
+namespace internal {
+using Any = ::std::any;
+}  // namespace internal
+}  // namespace testing
+// The case where absl is configured NOT to alias std::any is not
+// supported.
+#endif  // __has_include(<any>) && __cplusplus >= 201703L
+#endif  // __has_include
+#endif  // GTEST_HAS_ABSL
+
+#if GTEST_HAS_ABSL
+// Always use absl::optional for UniversalPrinter<> specializations if
+// googletest is built with absl support.
+#define GTEST_INTERNAL_HAS_OPTIONAL 1
+#include "absl/types/optional.h"
+namespace testing {
+namespace internal {
+template <typename T>
+using Optional = ::absl::optional<T>;
+}  // namespace internal
+}  // namespace testing
+#else
+#ifdef __has_include
+#if __has_include(<optional>) && __cplusplus >= 201703L
+// Otherwise for C++17 and higher use std::optional for UniversalPrinter<>
+// specializations.
+#define GTEST_INTERNAL_HAS_OPTIONAL 1
+#include <optional>
+namespace testing {
+namespace internal {
+template <typename T>
+using Optional = ::std::optional<T>;
+}  // namespace internal
+}  // namespace testing
+// The case where absl is configured NOT to alias std::optional is not
+// supported.
+#endif  // __has_include(<optional>) && __cplusplus >= 201703L
+#endif  // __has_include
+#endif  // GTEST_HAS_ABSL
+
+#if GTEST_HAS_ABSL
+// Always use absl::string_view for Matcher<> specializations if googletest
+// is built with absl support.
+# define GTEST_INTERNAL_HAS_STRING_VIEW 1
+#include "absl/strings/string_view.h"
+namespace testing {
+namespace internal {
+using StringView = ::absl::string_view;
+}  // namespace internal
+}  // namespace testing
+#else
+# ifdef __has_include
+#   if __has_include(<string_view>) && __cplusplus >= 201703L
+// Otherwise for C++17 and higher use std::string_view for Matcher<>
+// specializations.
+#   define GTEST_INTERNAL_HAS_STRING_VIEW 1
+#include <string_view>
+namespace testing {
+namespace internal {
+using StringView = ::std::string_view;
+}  // namespace internal
+}  // namespace testing
+// The case where absl is configured NOT to alias std::string_view is not
+// supported.
+#  endif  // __has_include(<string_view>) && __cplusplus >= 201703L
+# endif  // __has_include
+#endif  // GTEST_HAS_ABSL
+
+#if GTEST_HAS_ABSL
+// Always use absl::variant for UniversalPrinter<> specializations if googletest
+// is built with absl support.
+#define GTEST_INTERNAL_HAS_VARIANT 1
+#include "absl/types/variant.h"
+namespace testing {
+namespace internal {
+template <typename... T>
+using Variant = ::absl::variant<T...>;
+}  // namespace internal
+}  // namespace testing
+#else
+#ifdef __has_include
+#if __has_include(<variant>) && __cplusplus >= 201703L
+// Otherwise for C++17 and higher use std::variant for UniversalPrinter<>
+// specializations.
+#define GTEST_INTERNAL_HAS_VARIANT 1
+#include <variant>
+namespace testing {
+namespace internal {
+template <typename... T>
+using Variant = ::std::variant<T...>;
+}  // namespace internal
+}  // namespace testing
+// The case where absl is configured NOT to alias std::variant is not supported.
+#endif  // __has_include(<variant>) && __cplusplus >= 201703L
+#endif  // __has_include
+#endif  // GTEST_HAS_ABSL
+
+#endif  // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
 
 #if GTEST_OS_LINUX
 # include <stdlib.h>
@@ -2578,6 +2651,7 @@
 #include <ctype.h>
 #include <float.h>
 #include <string.h>
+#include <cstdint>
 #include <iomanip>
 #include <limits>
 #include <map>
@@ -2632,11 +2706,12 @@
 
 // GOOGLETEST_CM0001 DO NOT DELETE
 
-#ifndef GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
-#define GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
+#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
+#define GOOGLETEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
 
 #include <limits>
 #include <memory>
+#include <sstream>
 
 
 GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \
@@ -2766,12 +2841,6 @@
   Message& operator <<(const ::std::wstring& wstr);
 #endif  // GTEST_HAS_STD_WSTRING
 
-#if GTEST_HAS_GLOBAL_WSTRING
-  // Converts the given wide string to a narrow string using the UTF-8
-  // encoding, and streams the result to this Message object.
-  Message& operator <<(const ::wstring& wstr);
-#endif  // GTEST_HAS_GLOBAL_WSTRING
-
   // Gets the text streamed to this object so far as an std::string.
   // Each '\0' character in the buffer is replaced with "\\0".
   //
@@ -2808,7 +2877,7 @@
 
 GTEST_DISABLE_MSC_WARNINGS_POP_()  //  4251
 
-#endif  // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
+#endif  // GOOGLETEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
 // Copyright 2008, Google Inc.
 // All rights reserved.
 //
@@ -2848,8 +2917,8 @@
 
 // GOOGLETEST_CM0001 DO NOT DELETE
 
-#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
-#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
+#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
+#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
 
 // Copyright 2005, Google Inc.
 // All rights reserved.
@@ -2891,8 +2960,8 @@
 
 // GOOGLETEST_CM0001 DO NOT DELETE
 
-#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
-#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
+#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
+#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
 
 #ifdef __BORLANDC__
 // string.h is not guaranteed to provide strcpy on C++ Builder.
@@ -2900,6 +2969,7 @@
 #endif
 
 #include <string.h>
+#include <cstdint>
 #include <string>
 
 
@@ -2946,7 +3016,8 @@
   static const char* Utf16ToAnsi(LPCWSTR utf16_str);
 #endif
 
-  // Compares two C strings.  Returns true iff they have the same content.
+  // Compares two C strings.  Returns true if and only if they have the same
+  // content.
   //
   // Unlike strcmp(), this function can handle NULL argument(s).  A
   // NULL C string is considered different to any non-NULL C string,
@@ -2959,16 +3030,16 @@
   // returned.
   static std::string ShowWideCString(const wchar_t* wide_c_str);
 
-  // Compares two wide C strings.  Returns true iff they have the same
-  // content.
+  // Compares two wide C strings.  Returns true if and only if they have the
+  // same content.
   //
   // Unlike wcscmp(), this function can handle NULL argument(s).  A
   // NULL C string is considered different to any non-NULL C string,
   // including the empty string.
   static bool WideCStringEquals(const wchar_t* lhs, const wchar_t* rhs);
 
-  // Compares two C strings, ignoring case.  Returns true iff they
-  // have the same content.
+  // Compares two C strings, ignoring case.  Returns true if and only if
+  // they have the same content.
   //
   // Unlike strcasecmp(), this function can handle NULL argument(s).
   // A NULL C string is considered different to any non-NULL C string,
@@ -2976,8 +3047,8 @@
   static bool CaseInsensitiveCStringEquals(const char* lhs,
                                            const char* rhs);
 
-  // Compares two wide C strings, ignoring case.  Returns true iff they
-  // have the same content.
+  // Compares two wide C strings, ignoring case.  Returns true if and only if
+  // they have the same content.
   //
   // Unlike wcscasecmp(), this function can handle NULL argument(s).
   // A NULL C string is considered different to any non-NULL wide C string,
@@ -2991,17 +3062,23 @@
   static bool CaseInsensitiveWideCStringEquals(const wchar_t* lhs,
                                                const wchar_t* rhs);
 
-  // Returns true iff the given string ends with the given suffix, ignoring
-  // case. Any string is considered to end with an empty suffix.
+  // Returns true if and only if the given string ends with the given suffix,
+  // ignoring case. Any string is considered to end with an empty suffix.
   static bool EndsWithCaseInsensitive(
       const std::string& str, const std::string& suffix);
 
   // Formats an int value as "%02d".
   static std::string FormatIntWidth2(int value);  // "%02d" for width == 2
 
+  // Formats an int value to given width with leading zeros.
+  static std::string FormatIntWidthN(int value, int width);
+
   // Formats an int value as "%X".
   static std::string FormatHexInt(int value);
 
+  // Formats an int value as "%X".
+  static std::string FormatHexUInt32(uint32_t value);
+
   // Formats a byte as "%02X".
   static std::string FormatByte(unsigned char value);
 
@@ -3016,7 +3093,7 @@
 }  // namespace internal
 }  // namespace testing
 
-#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
+#endif  // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
 
 GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \
 /* class A needs to have dll-interface to be used by clients of class B */)
@@ -3086,7 +3163,7 @@
                                          const FilePath& base_name,
                                          const char* extension);
 
-  // Returns true iff the path is "".
+  // Returns true if and only if the path is "".
   bool IsEmpty() const { return pathname_.empty(); }
 
   // If input name has a trailing separator character, removes it and returns
@@ -3171,7 +3248,7 @@
 
   void Normalize();
 
-  // Returns a pointer to the last occurence of a valid path separator in
+  // Returns a pointer to the last occurrence of a valid path separator in
   // the FilePath. On Windows, for example, both '/' and '\' are valid path
   // separators. Returns NULL if no path separator was found.
   const char* FindLastPathSeparator() const;
@@ -3184,11 +3261,7 @@
 
 GTEST_DISABLE_MSC_WARNINGS_POP_()  //  4251
 
-#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
-// This file was GENERATED by command:
-//     pump.py gtest-type-util.h.pump
-// DO NOT EDIT BY HAND!!!
-
+#endif  // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
 // Copyright 2008 Google Inc.
 // All Rights Reserved.
 //
@@ -3219,17 +3292,12 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 // Type utilities needed for implementing typed and type-parameterized
-// tests.  This file is generated by a SCRIPT.  DO NOT EDIT BY HAND!
-//
-// Currently we support at most 50 types in a list, and at most 50
-// type-parameterized tests in one type-parameterized test suite.
-// Please contact googletestframework@googlegroups.com if you need
-// more.
+// tests.
 
 // GOOGLETEST_CM0001 DO NOT DELETE
 
-#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
-#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
+#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
+#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
 
 
 // #ifdef __GNUC__ is too general here.  It is possible to use gcc without using
@@ -3259,1568 +3327,43 @@
   return s;
 }
 
-// GetTypeName<T>() returns a human-readable name of type T.
-// NB: This function is also used in Google Mock, so don't move it inside of
-// the typed-test-only section below.
-template <typename T>
-std::string GetTypeName() {
-# if GTEST_HAS_RTTI
-
-  const char* const name = typeid(T).name();
-#  if GTEST_HAS_CXXABI_H_ || defined(__HP_aCC)
+#if GTEST_HAS_RTTI
+// GetTypeName(const std::type_info&) returns a human-readable name of type T.
+inline std::string GetTypeName(const std::type_info& type) {
+  const char* const name = type.name();
+#if GTEST_HAS_CXXABI_H_ || defined(__HP_aCC)
   int status = 0;
   // gcc's implementation of typeid(T).name() mangles the type name,
   // so we have to demangle it.
-#   if GTEST_HAS_CXXABI_H_
+#if GTEST_HAS_CXXABI_H_
   using abi::__cxa_demangle;
-#   endif  // GTEST_HAS_CXXABI_H_
+#endif  // GTEST_HAS_CXXABI_H_
   char* const readable_name = __cxa_demangle(name, nullptr, nullptr, &status);
   const std::string name_str(status == 0 ? readable_name : name);
   free(readable_name);
   return CanonicalizeForStdLibVersioning(name_str);
-#  else
+#else
   return name;
-#  endif  // GTEST_HAS_CXXABI_H_ || __HP_aCC
+#endif  // GTEST_HAS_CXXABI_H_ || __HP_aCC
+}
+#endif  // GTEST_HAS_RTTI
 
-# else
-
+// GetTypeName<T>() returns a human-readable name of type T if and only if
+// RTTI is enabled, otherwise it returns a dummy type name.
+// NB: This function is also used in Google Mock, so don't move it inside of
+// the typed-test-only section below.
+template <typename T>
+std::string GetTypeName() {
+#if GTEST_HAS_RTTI
+  return GetTypeName(typeid(T));
+#else
   return "<type>";
-
-# endif  // GTEST_HAS_RTTI
+#endif  // GTEST_HAS_RTTI
 }
 
-#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
-
-// AssertyTypeEq<T1, T2>::type is defined iff T1 and T2 are the same
-// type.  This can be used as a compile-time assertion to ensure that
-// two types are equal.
-
-template <typename T1, typename T2>
-struct AssertTypeEq;
-
-template <typename T>
-struct AssertTypeEq<T, T> {
-  typedef bool type;
-};
-
-// A unique type used as the default value for the arguments of class
-// template Types.  This allows us to simulate variadic templates
-// (e.g. Types<int>, Type<int, double>, and etc), which C++ doesn't
-// support directly.
+// A unique type indicating an empty node
 struct None {};
 
-// The following family of struct and struct templates are used to
-// represent type lists.  In particular, TypesN<T1, T2, ..., TN>
-// represents a type list with N types (T1, T2, ..., and TN) in it.
-// Except for Types0, every struct in the family has two member types:
-// Head for the first type in the list, and Tail for the rest of the
-// list.
-
-// The empty type list.
-struct Types0 {};
-
-// Type lists of length 1, 2, 3, and so on.
-
-template <typename T1>
-struct Types1 {
-  typedef T1 Head;
-  typedef Types0 Tail;
-};
-template <typename T1, typename T2>
-struct Types2 {
-  typedef T1 Head;
-  typedef Types1<T2> Tail;
-};
-
-template <typename T1, typename T2, typename T3>
-struct Types3 {
-  typedef T1 Head;
-  typedef Types2<T2, T3> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4>
-struct Types4 {
-  typedef T1 Head;
-  typedef Types3<T2, T3, T4> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5>
-struct Types5 {
-  typedef T1 Head;
-  typedef Types4<T2, T3, T4, T5> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6>
-struct Types6 {
-  typedef T1 Head;
-  typedef Types5<T2, T3, T4, T5, T6> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7>
-struct Types7 {
-  typedef T1 Head;
-  typedef Types6<T2, T3, T4, T5, T6, T7> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8>
-struct Types8 {
-  typedef T1 Head;
-  typedef Types7<T2, T3, T4, T5, T6, T7, T8> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9>
-struct Types9 {
-  typedef T1 Head;
-  typedef Types8<T2, T3, T4, T5, T6, T7, T8, T9> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10>
-struct Types10 {
-  typedef T1 Head;
-  typedef Types9<T2, T3, T4, T5, T6, T7, T8, T9, T10> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11>
-struct Types11 {
-  typedef T1 Head;
-  typedef Types10<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12>
-struct Types12 {
-  typedef T1 Head;
-  typedef Types11<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13>
-struct Types13 {
-  typedef T1 Head;
-  typedef Types12<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14>
-struct Types14 {
-  typedef T1 Head;
-  typedef Types13<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15>
-struct Types15 {
-  typedef T1 Head;
-  typedef Types14<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-      T15> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16>
-struct Types16 {
-  typedef T1 Head;
-  typedef Types15<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-      T16> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17>
-struct Types17 {
-  typedef T1 Head;
-  typedef Types16<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-      T16, T17> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18>
-struct Types18 {
-  typedef T1 Head;
-  typedef Types17<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-      T16, T17, T18> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19>
-struct Types19 {
-  typedef T1 Head;
-  typedef Types18<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-      T16, T17, T18, T19> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20>
-struct Types20 {
-  typedef T1 Head;
-  typedef Types19<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-      T16, T17, T18, T19, T20> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21>
-struct Types21 {
-  typedef T1 Head;
-  typedef Types20<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-      T16, T17, T18, T19, T20, T21> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22>
-struct Types22 {
-  typedef T1 Head;
-  typedef Types21<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-      T16, T17, T18, T19, T20, T21, T22> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23>
-struct Types23 {
-  typedef T1 Head;
-  typedef Types22<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-      T16, T17, T18, T19, T20, T21, T22, T23> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24>
-struct Types24 {
-  typedef T1 Head;
-  typedef Types23<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-      T16, T17, T18, T19, T20, T21, T22, T23, T24> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25>
-struct Types25 {
-  typedef T1 Head;
-  typedef Types24<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26>
-struct Types26 {
-  typedef T1 Head;
-  typedef Types25<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27>
-struct Types27 {
-  typedef T1 Head;
-  typedef Types26<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27, typename T28>
-struct Types28 {
-  typedef T1 Head;
-  typedef Types27<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27, typename T28, typename T29>
-struct Types29 {
-  typedef T1 Head;
-  typedef Types28<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
-      T29> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27, typename T28, typename T29, typename T30>
-struct Types30 {
-  typedef T1 Head;
-  typedef Types29<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
-      T30> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27, typename T28, typename T29, typename T30,
-    typename T31>
-struct Types31 {
-  typedef T1 Head;
-  typedef Types30<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
-      T30, T31> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27, typename T28, typename T29, typename T30,
-    typename T31, typename T32>
-struct Types32 {
-  typedef T1 Head;
-  typedef Types31<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
-      T30, T31, T32> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27, typename T28, typename T29, typename T30,
-    typename T31, typename T32, typename T33>
-struct Types33 {
-  typedef T1 Head;
-  typedef Types32<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
-      T30, T31, T32, T33> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27, typename T28, typename T29, typename T30,
-    typename T31, typename T32, typename T33, typename T34>
-struct Types34 {
-  typedef T1 Head;
-  typedef Types33<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
-      T30, T31, T32, T33, T34> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27, typename T28, typename T29, typename T30,
-    typename T31, typename T32, typename T33, typename T34, typename T35>
-struct Types35 {
-  typedef T1 Head;
-  typedef Types34<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
-      T30, T31, T32, T33, T34, T35> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27, typename T28, typename T29, typename T30,
-    typename T31, typename T32, typename T33, typename T34, typename T35,
-    typename T36>
-struct Types36 {
-  typedef T1 Head;
-  typedef Types35<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
-      T30, T31, T32, T33, T34, T35, T36> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27, typename T28, typename T29, typename T30,
-    typename T31, typename T32, typename T33, typename T34, typename T35,
-    typename T36, typename T37>
-struct Types37 {
-  typedef T1 Head;
-  typedef Types36<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
-      T30, T31, T32, T33, T34, T35, T36, T37> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27, typename T28, typename T29, typename T30,
-    typename T31, typename T32, typename T33, typename T34, typename T35,
-    typename T36, typename T37, typename T38>
-struct Types38 {
-  typedef T1 Head;
-  typedef Types37<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
-      T30, T31, T32, T33, T34, T35, T36, T37, T38> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27, typename T28, typename T29, typename T30,
-    typename T31, typename T32, typename T33, typename T34, typename T35,
-    typename T36, typename T37, typename T38, typename T39>
-struct Types39 {
-  typedef T1 Head;
-  typedef Types38<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
-      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27, typename T28, typename T29, typename T30,
-    typename T31, typename T32, typename T33, typename T34, typename T35,
-    typename T36, typename T37, typename T38, typename T39, typename T40>
-struct Types40 {
-  typedef T1 Head;
-  typedef Types39<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
-      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27, typename T28, typename T29, typename T30,
-    typename T31, typename T32, typename T33, typename T34, typename T35,
-    typename T36, typename T37, typename T38, typename T39, typename T40,
-    typename T41>
-struct Types41 {
-  typedef T1 Head;
-  typedef Types40<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
-      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27, typename T28, typename T29, typename T30,
-    typename T31, typename T32, typename T33, typename T34, typename T35,
-    typename T36, typename T37, typename T38, typename T39, typename T40,
-    typename T41, typename T42>
-struct Types42 {
-  typedef T1 Head;
-  typedef Types41<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
-      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27, typename T28, typename T29, typename T30,
-    typename T31, typename T32, typename T33, typename T34, typename T35,
-    typename T36, typename T37, typename T38, typename T39, typename T40,
-    typename T41, typename T42, typename T43>
-struct Types43 {
-  typedef T1 Head;
-  typedef Types42<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
-      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
-      T43> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27, typename T28, typename T29, typename T30,
-    typename T31, typename T32, typename T33, typename T34, typename T35,
-    typename T36, typename T37, typename T38, typename T39, typename T40,
-    typename T41, typename T42, typename T43, typename T44>
-struct Types44 {
-  typedef T1 Head;
-  typedef Types43<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
-      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
-      T44> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27, typename T28, typename T29, typename T30,
-    typename T31, typename T32, typename T33, typename T34, typename T35,
-    typename T36, typename T37, typename T38, typename T39, typename T40,
-    typename T41, typename T42, typename T43, typename T44, typename T45>
-struct Types45 {
-  typedef T1 Head;
-  typedef Types44<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
-      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
-      T44, T45> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27, typename T28, typename T29, typename T30,
-    typename T31, typename T32, typename T33, typename T34, typename T35,
-    typename T36, typename T37, typename T38, typename T39, typename T40,
-    typename T41, typename T42, typename T43, typename T44, typename T45,
-    typename T46>
-struct Types46 {
-  typedef T1 Head;
-  typedef Types45<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
-      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
-      T44, T45, T46> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27, typename T28, typename T29, typename T30,
-    typename T31, typename T32, typename T33, typename T34, typename T35,
-    typename T36, typename T37, typename T38, typename T39, typename T40,
-    typename T41, typename T42, typename T43, typename T44, typename T45,
-    typename T46, typename T47>
-struct Types47 {
-  typedef T1 Head;
-  typedef Types46<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
-      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
-      T44, T45, T46, T47> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27, typename T28, typename T29, typename T30,
-    typename T31, typename T32, typename T33, typename T34, typename T35,
-    typename T36, typename T37, typename T38, typename T39, typename T40,
-    typename T41, typename T42, typename T43, typename T44, typename T45,
-    typename T46, typename T47, typename T48>
-struct Types48 {
-  typedef T1 Head;
-  typedef Types47<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
-      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
-      T44, T45, T46, T47, T48> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27, typename T28, typename T29, typename T30,
-    typename T31, typename T32, typename T33, typename T34, typename T35,
-    typename T36, typename T37, typename T38, typename T39, typename T40,
-    typename T41, typename T42, typename T43, typename T44, typename T45,
-    typename T46, typename T47, typename T48, typename T49>
-struct Types49 {
-  typedef T1 Head;
-  typedef Types48<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
-      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
-      T44, T45, T46, T47, T48, T49> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27, typename T28, typename T29, typename T30,
-    typename T31, typename T32, typename T33, typename T34, typename T35,
-    typename T36, typename T37, typename T38, typename T39, typename T40,
-    typename T41, typename T42, typename T43, typename T44, typename T45,
-    typename T46, typename T47, typename T48, typename T49, typename T50>
-struct Types50 {
-  typedef T1 Head;
-  typedef Types49<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-      T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
-      T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
-      T44, T45, T46, T47, T48, T49, T50> Tail;
-};
-
-
-}  // namespace internal
-
-// We don't want to require the users to write TypesN<...> directly,
-// as that would require them to count the length.  Types<...> is much
-// easier to write, but generates horrible messages when there is a
-// compiler error, as gcc insists on printing out each template
-// argument, even if it has the default value (this means Types<int>
-// will appear as Types<int, None, None, ..., None> in the compiler
-// errors).
-//
-// Our solution is to combine the best part of the two approaches: a
-// user would write Types<T1, ..., TN>, and Google Test will translate
-// that to TypesN<T1, ..., TN> internally to make error messages
-// readable.  The translation is done by the 'type' member of the
-// Types template.
-template <typename T1 = internal::None, typename T2 = internal::None,
-    typename T3 = internal::None, typename T4 = internal::None,
-    typename T5 = internal::None, typename T6 = internal::None,
-    typename T7 = internal::None, typename T8 = internal::None,
-    typename T9 = internal::None, typename T10 = internal::None,
-    typename T11 = internal::None, typename T12 = internal::None,
-    typename T13 = internal::None, typename T14 = internal::None,
-    typename T15 = internal::None, typename T16 = internal::None,
-    typename T17 = internal::None, typename T18 = internal::None,
-    typename T19 = internal::None, typename T20 = internal::None,
-    typename T21 = internal::None, typename T22 = internal::None,
-    typename T23 = internal::None, typename T24 = internal::None,
-    typename T25 = internal::None, typename T26 = internal::None,
-    typename T27 = internal::None, typename T28 = internal::None,
-    typename T29 = internal::None, typename T30 = internal::None,
-    typename T31 = internal::None, typename T32 = internal::None,
-    typename T33 = internal::None, typename T34 = internal::None,
-    typename T35 = internal::None, typename T36 = internal::None,
-    typename T37 = internal::None, typename T38 = internal::None,
-    typename T39 = internal::None, typename T40 = internal::None,
-    typename T41 = internal::None, typename T42 = internal::None,
-    typename T43 = internal::None, typename T44 = internal::None,
-    typename T45 = internal::None, typename T46 = internal::None,
-    typename T47 = internal::None, typename T48 = internal::None,
-    typename T49 = internal::None, typename T50 = internal::None>
-struct Types {
-  typedef internal::Types50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
-      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
-      T41, T42, T43, T44, T45, T46, T47, T48, T49, T50> type;
-};
-
-template <>
-struct Types<internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None> {
-  typedef internal::Types0 type;
-};
-template <typename T1>
-struct Types<T1, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None> {
-  typedef internal::Types1<T1> type;
-};
-template <typename T1, typename T2>
-struct Types<T1, T2, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None> {
-  typedef internal::Types2<T1, T2> type;
-};
-template <typename T1, typename T2, typename T3>
-struct Types<T1, T2, T3, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None> {
-  typedef internal::Types3<T1, T2, T3> type;
-};
-template <typename T1, typename T2, typename T3, typename T4>
-struct Types<T1, T2, T3, T4, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None> {
-  typedef internal::Types4<T1, T2, T3, T4> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5>
-struct Types<T1, T2, T3, T4, T5, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None> {
-  typedef internal::Types5<T1, T2, T3, T4, T5> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6>
-struct Types<T1, T2, T3, T4, T5, T6, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None> {
-  typedef internal::Types6<T1, T2, T3, T4, T5, T6> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7>
-struct Types<T1, T2, T3, T4, T5, T6, T7, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None> {
-  typedef internal::Types7<T1, T2, T3, T4, T5, T6, T7> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None> {
-  typedef internal::Types8<T1, T2, T3, T4, T5, T6, T7, T8> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None> {
-  typedef internal::Types9<T1, T2, T3, T4, T5, T6, T7, T8, T9> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None> {
-  typedef internal::Types10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None> {
-  typedef internal::Types11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None> {
-  typedef internal::Types12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
-      T12> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None> {
-  typedef internal::Types13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
-      T13> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None> {
-  typedef internal::Types14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
-      T13, T14> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None> {
-  typedef internal::Types15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
-      T13, T14, T15> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-    T16, internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None> {
-  typedef internal::Types16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
-      T13, T14, T15, T16> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-    T16, T17, internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None> {
-  typedef internal::Types17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
-      T13, T14, T15, T16, T17> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-    T16, T17, T18, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None> {
-  typedef internal::Types18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
-      T13, T14, T15, T16, T17, T18> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-    T16, T17, T18, T19, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None> {
-  typedef internal::Types19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
-      T13, T14, T15, T16, T17, T18, T19> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-    T16, T17, T18, T19, T20, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None> {
-  typedef internal::Types20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
-      T13, T14, T15, T16, T17, T18, T19, T20> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-    T16, T17, T18, T19, T20, T21, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None> {
-  typedef internal::Types21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
-      T13, T14, T15, T16, T17, T18, T19, T20, T21> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-    T16, T17, T18, T19, T20, T21, T22, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None> {
-  typedef internal::Types22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-    T16, T17, T18, T19, T20, T21, T22, T23, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None> {
-  typedef internal::Types23<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-    T16, T17, T18, T19, T20, T21, T22, T23, T24, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None> {
-  typedef internal::Types24<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None> {
-  typedef internal::Types25<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None> {
-  typedef internal::Types26<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
-      T26> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None> {
-  typedef internal::Types27<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
-      T27> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27, typename T28>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None> {
-  typedef internal::Types28<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
-      T27, T28> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27, typename T28, typename T29>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None> {
-  typedef internal::Types29<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
-      T27, T28, T29> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27, typename T28, typename T29, typename T30>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None> {
-  typedef internal::Types30<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
-      T27, T28, T29, T30> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27, typename T28, typename T29, typename T30,
-    typename T31>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
-    T31, internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None> {
-  typedef internal::Types31<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
-      T27, T28, T29, T30, T31> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27, typename T28, typename T29, typename T30,
-    typename T31, typename T32>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
-    T31, T32, internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None> {
-  typedef internal::Types32<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
-      T27, T28, T29, T30, T31, T32> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27, typename T28, typename T29, typename T30,
-    typename T31, typename T32, typename T33>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
-    T31, T32, T33, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None> {
-  typedef internal::Types33<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
-      T27, T28, T29, T30, T31, T32, T33> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27, typename T28, typename T29, typename T30,
-    typename T31, typename T32, typename T33, typename T34>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
-    T31, T32, T33, T34, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None> {
-  typedef internal::Types34<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
-      T27, T28, T29, T30, T31, T32, T33, T34> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27, typename T28, typename T29, typename T30,
-    typename T31, typename T32, typename T33, typename T34, typename T35>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
-    T31, T32, T33, T34, T35, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None> {
-  typedef internal::Types35<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
-      T27, T28, T29, T30, T31, T32, T33, T34, T35> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27, typename T28, typename T29, typename T30,
-    typename T31, typename T32, typename T33, typename T34, typename T35,
-    typename T36>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
-    T31, T32, T33, T34, T35, T36, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None> {
-  typedef internal::Types36<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
-      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27, typename T28, typename T29, typename T30,
-    typename T31, typename T32, typename T33, typename T34, typename T35,
-    typename T36, typename T37>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
-    T31, T32, T33, T34, T35, T36, T37, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None> {
-  typedef internal::Types37<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
-      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27, typename T28, typename T29, typename T30,
-    typename T31, typename T32, typename T33, typename T34, typename T35,
-    typename T36, typename T37, typename T38>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
-    T31, T32, T33, T34, T35, T36, T37, T38, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None> {
-  typedef internal::Types38<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
-      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27, typename T28, typename T29, typename T30,
-    typename T31, typename T32, typename T33, typename T34, typename T35,
-    typename T36, typename T37, typename T38, typename T39>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
-    T31, T32, T33, T34, T35, T36, T37, T38, T39, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None> {
-  typedef internal::Types39<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
-      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27, typename T28, typename T29, typename T30,
-    typename T31, typename T32, typename T33, typename T34, typename T35,
-    typename T36, typename T37, typename T38, typename T39, typename T40>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
-    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None> {
-  typedef internal::Types40<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
-      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
-      T40> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27, typename T28, typename T29, typename T30,
-    typename T31, typename T32, typename T33, typename T34, typename T35,
-    typename T36, typename T37, typename T38, typename T39, typename T40,
-    typename T41>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
-    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None, internal::None> {
-  typedef internal::Types41<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
-      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
-      T41> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27, typename T28, typename T29, typename T30,
-    typename T31, typename T32, typename T33, typename T34, typename T35,
-    typename T36, typename T37, typename T38, typename T39, typename T40,
-    typename T41, typename T42>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
-    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, internal::None,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None> {
-  typedef internal::Types42<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
-      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
-      T41, T42> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27, typename T28, typename T29, typename T30,
-    typename T31, typename T32, typename T33, typename T34, typename T35,
-    typename T36, typename T37, typename T38, typename T39, typename T40,
-    typename T41, typename T42, typename T43>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
-    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None, internal::None> {
-  typedef internal::Types43<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
-      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
-      T41, T42, T43> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27, typename T28, typename T29, typename T30,
-    typename T31, typename T32, typename T33, typename T34, typename T35,
-    typename T36, typename T37, typename T38, typename T39, typename T40,
-    typename T41, typename T42, typename T43, typename T44>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
-    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None, internal::None> {
-  typedef internal::Types44<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
-      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
-      T41, T42, T43, T44> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27, typename T28, typename T29, typename T30,
-    typename T31, typename T32, typename T33, typename T34, typename T35,
-    typename T36, typename T37, typename T38, typename T39, typename T40,
-    typename T41, typename T42, typename T43, typename T44, typename T45>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
-    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
-    internal::None, internal::None, internal::None, internal::None,
-    internal::None> {
-  typedef internal::Types45<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
-      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
-      T41, T42, T43, T44, T45> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27, typename T28, typename T29, typename T30,
-    typename T31, typename T32, typename T33, typename T34, typename T35,
-    typename T36, typename T37, typename T38, typename T39, typename T40,
-    typename T41, typename T42, typename T43, typename T44, typename T45,
-    typename T46>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
-    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
-    T46, internal::None, internal::None, internal::None, internal::None> {
-  typedef internal::Types46<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
-      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
-      T41, T42, T43, T44, T45, T46> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27, typename T28, typename T29, typename T30,
-    typename T31, typename T32, typename T33, typename T34, typename T35,
-    typename T36, typename T37, typename T38, typename T39, typename T40,
-    typename T41, typename T42, typename T43, typename T44, typename T45,
-    typename T46, typename T47>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
-    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
-    T46, T47, internal::None, internal::None, internal::None> {
-  typedef internal::Types47<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
-      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
-      T41, T42, T43, T44, T45, T46, T47> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27, typename T28, typename T29, typename T30,
-    typename T31, typename T32, typename T33, typename T34, typename T35,
-    typename T36, typename T37, typename T38, typename T39, typename T40,
-    typename T41, typename T42, typename T43, typename T44, typename T45,
-    typename T46, typename T47, typename T48>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
-    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
-    T46, T47, T48, internal::None, internal::None> {
-  typedef internal::Types48<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
-      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
-      T41, T42, T43, T44, T45, T46, T47, T48> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27, typename T28, typename T29, typename T30,
-    typename T31, typename T32, typename T33, typename T34, typename T35,
-    typename T36, typename T37, typename T38, typename T39, typename T40,
-    typename T41, typename T42, typename T43, typename T44, typename T45,
-    typename T46, typename T47, typename T48, typename T49>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
-    T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
-    T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
-    T46, T47, T48, T49, internal::None> {
-  typedef internal::Types49<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
-      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
-      T41, T42, T43, T44, T45, T46, T47, T48, T49> type;
-};
-
-namespace internal {
-
 # define GTEST_TEMPLATE_ template <typename T> class
 
 // The template "selector" struct TemplateSel<Tmpl> is used to
@@ -4842,1695 +3385,65 @@
 # define GTEST_BIND_(TmplSel, T) \
   TmplSel::template Bind<T>::type
 
-// A unique struct template used as the default value for the
-// arguments of class template Templates.  This allows us to simulate
-// variadic templates (e.g. Templates<int>, Templates<int, double>,
-// and etc), which C++ doesn't support directly.
-template <typename T>
-struct NoneT {};
-
-// The following family of struct and struct templates are used to
-// represent template lists.  In particular, TemplatesN<T1, T2, ...,
-// TN> represents a list of N templates (T1, T2, ..., and TN).  Except
-// for Templates0, every struct in the family has two member types:
-// Head for the selector of the first template in the list, and Tail
-// for the rest of the list.
-
-// The empty template list.
-struct Templates0 {};
-
-// Template lists of length 1, 2, 3, and so on.
-
-template <GTEST_TEMPLATE_ T1>
-struct Templates1 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates0 Tail;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2>
-struct Templates2 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates1<T2> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3>
-struct Templates3 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates2<T2, T3> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4>
-struct Templates4 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates3<T2, T3, T4> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5>
-struct Templates5 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates4<T2, T3, T4, T5> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6>
-struct Templates6 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates5<T2, T3, T4, T5, T6> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7>
-struct Templates7 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates6<T2, T3, T4, T5, T6, T7> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8>
-struct Templates8 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates7<T2, T3, T4, T5, T6, T7, T8> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9>
-struct Templates9 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates8<T2, T3, T4, T5, T6, T7, T8, T9> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10>
-struct Templates10 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates9<T2, T3, T4, T5, T6, T7, T8, T9, T10> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11>
-struct Templates11 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates10<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12>
-struct Templates12 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates11<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13>
-struct Templates13 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates12<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14>
-struct Templates14 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates13<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
-      T14> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15>
-struct Templates15 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates14<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-      T15> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16>
-struct Templates16 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates15<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-      T15, T16> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17>
-struct Templates17 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates16<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-      T15, T16, T17> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18>
-struct Templates18 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates17<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-      T15, T16, T17, T18> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19>
-struct Templates19 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates18<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-      T15, T16, T17, T18, T19> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20>
-struct Templates20 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates19<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-      T15, T16, T17, T18, T19, T20> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21>
-struct Templates21 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates20<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-      T15, T16, T17, T18, T19, T20, T21> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22>
-struct Templates22 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates21<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-      T15, T16, T17, T18, T19, T20, T21, T22> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23>
-struct Templates23 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates22<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-      T15, T16, T17, T18, T19, T20, T21, T22, T23> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24>
-struct Templates24 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates23<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25>
-struct Templates25 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates24<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26>
-struct Templates26 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates25<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27>
-struct Templates27 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates26<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
-    GTEST_TEMPLATE_ T28>
-struct Templates28 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates27<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
-      T28> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29>
-struct Templates29 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates28<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
-      T29> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30>
-struct Templates30 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates29<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
-      T29, T30> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
-    GTEST_TEMPLATE_ T31>
-struct Templates31 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates30<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
-      T29, T30, T31> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32>
-struct Templates32 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates31<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
-      T29, T30, T31, T32> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33>
-struct Templates33 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates32<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
-      T29, T30, T31, T32, T33> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
-    GTEST_TEMPLATE_ T34>
-struct Templates34 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates33<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
-      T29, T30, T31, T32, T33, T34> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35>
-struct Templates35 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates34<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
-      T29, T30, T31, T32, T33, T34, T35> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36>
-struct Templates36 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates35<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
-      T29, T30, T31, T32, T33, T34, T35, T36> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
-    GTEST_TEMPLATE_ T37>
-struct Templates37 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates36<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
-      T29, T30, T31, T32, T33, T34, T35, T36, T37> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38>
-struct Templates38 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates37<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
-      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39>
-struct Templates39 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates38<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
-      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
-    GTEST_TEMPLATE_ T40>
-struct Templates40 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates39<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
-      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
-    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41>
-struct Templates41 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates40<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
-      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
-    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42>
-struct Templates42 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates41<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
-      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
-      T42> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
-    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
-    GTEST_TEMPLATE_ T43>
-struct Templates43 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates42<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
-      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
-      T43> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
-    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
-    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44>
-struct Templates44 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates43<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
-      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
-      T43, T44> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
-    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
-    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45>
-struct Templates45 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates44<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
-      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
-      T43, T44, T45> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
-    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
-    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
-    GTEST_TEMPLATE_ T46>
-struct Templates46 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates45<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
-      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
-      T43, T44, T45, T46> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
-    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
-    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
-    GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47>
-struct Templates47 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates46<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
-      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
-      T43, T44, T45, T46, T47> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
-    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
-    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
-    GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48>
-struct Templates48 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates47<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
-      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
-      T43, T44, T45, T46, T47, T48> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
-    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
-    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
-    GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48,
-    GTEST_TEMPLATE_ T49>
-struct Templates49 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates48<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
-      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
-      T43, T44, T45, T46, T47, T48, T49> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
-    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
-    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
-    GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48,
-    GTEST_TEMPLATE_ T49, GTEST_TEMPLATE_ T50>
-struct Templates50 {
-  typedef TemplateSel<T1> Head;
-  typedef Templates49<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-      T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
-      T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
-      T43, T44, T45, T46, T47, T48, T49, T50> Tail;
-};
-
-
-// We don't want to require the users to write TemplatesN<...> directly,
-// as that would require them to count the length.  Templates<...> is much
-// easier to write, but generates horrible messages when there is a
-// compiler error, as gcc insists on printing out each template
-// argument, even if it has the default value (this means Templates<list>
-// will appear as Templates<list, NoneT, NoneT, ..., NoneT> in the compiler
-// errors).
-//
-// Our solution is to combine the best part of the two approaches: a
-// user would write Templates<T1, ..., TN>, and Google Test will translate
-// that to TemplatesN<T1, ..., TN> internally to make error messages
-// readable.  The translation is done by the 'type' member of the
-// Templates template.
-template <GTEST_TEMPLATE_ T1 = NoneT, GTEST_TEMPLATE_ T2 = NoneT,
-    GTEST_TEMPLATE_ T3 = NoneT, GTEST_TEMPLATE_ T4 = NoneT,
-    GTEST_TEMPLATE_ T5 = NoneT, GTEST_TEMPLATE_ T6 = NoneT,
-    GTEST_TEMPLATE_ T7 = NoneT, GTEST_TEMPLATE_ T8 = NoneT,
-    GTEST_TEMPLATE_ T9 = NoneT, GTEST_TEMPLATE_ T10 = NoneT,
-    GTEST_TEMPLATE_ T11 = NoneT, GTEST_TEMPLATE_ T12 = NoneT,
-    GTEST_TEMPLATE_ T13 = NoneT, GTEST_TEMPLATE_ T14 = NoneT,
-    GTEST_TEMPLATE_ T15 = NoneT, GTEST_TEMPLATE_ T16 = NoneT,
-    GTEST_TEMPLATE_ T17 = NoneT, GTEST_TEMPLATE_ T18 = NoneT,
-    GTEST_TEMPLATE_ T19 = NoneT, GTEST_TEMPLATE_ T20 = NoneT,
-    GTEST_TEMPLATE_ T21 = NoneT, GTEST_TEMPLATE_ T22 = NoneT,
-    GTEST_TEMPLATE_ T23 = NoneT, GTEST_TEMPLATE_ T24 = NoneT,
-    GTEST_TEMPLATE_ T25 = NoneT, GTEST_TEMPLATE_ T26 = NoneT,
-    GTEST_TEMPLATE_ T27 = NoneT, GTEST_TEMPLATE_ T28 = NoneT,
-    GTEST_TEMPLATE_ T29 = NoneT, GTEST_TEMPLATE_ T30 = NoneT,
-    GTEST_TEMPLATE_ T31 = NoneT, GTEST_TEMPLATE_ T32 = NoneT,
-    GTEST_TEMPLATE_ T33 = NoneT, GTEST_TEMPLATE_ T34 = NoneT,
-    GTEST_TEMPLATE_ T35 = NoneT, GTEST_TEMPLATE_ T36 = NoneT,
-    GTEST_TEMPLATE_ T37 = NoneT, GTEST_TEMPLATE_ T38 = NoneT,
-    GTEST_TEMPLATE_ T39 = NoneT, GTEST_TEMPLATE_ T40 = NoneT,
-    GTEST_TEMPLATE_ T41 = NoneT, GTEST_TEMPLATE_ T42 = NoneT,
-    GTEST_TEMPLATE_ T43 = NoneT, GTEST_TEMPLATE_ T44 = NoneT,
-    GTEST_TEMPLATE_ T45 = NoneT, GTEST_TEMPLATE_ T46 = NoneT,
-    GTEST_TEMPLATE_ T47 = NoneT, GTEST_TEMPLATE_ T48 = NoneT,
-    GTEST_TEMPLATE_ T49 = NoneT, GTEST_TEMPLATE_ T50 = NoneT>
+template <GTEST_TEMPLATE_ Head_, GTEST_TEMPLATE_... Tail_>
 struct Templates {
-  typedef Templates50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
-      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
-      T42, T43, T44, T45, T46, T47, T48, T49, T50> type;
+  using Head = TemplateSel<Head_>;
+  using Tail = Templates<Tail_...>;
 };
 
-template <>
-struct Templates<NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT> {
-  typedef Templates0 type;
-};
-template <GTEST_TEMPLATE_ T1>
-struct Templates<T1, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT> {
-  typedef Templates1<T1> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2>
-struct Templates<T1, T2, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT> {
-  typedef Templates2<T1, T2> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3>
-struct Templates<T1, T2, T3, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
-  typedef Templates3<T1, T2, T3> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4>
-struct Templates<T1, T2, T3, T4, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
-  typedef Templates4<T1, T2, T3, T4> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5>
-struct Templates<T1, T2, T3, T4, T5, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
-  typedef Templates5<T1, T2, T3, T4, T5> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6>
-struct Templates<T1, T2, T3, T4, T5, T6, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
-  typedef Templates6<T1, T2, T3, T4, T5, T6> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
-  typedef Templates7<T1, T2, T3, T4, T5, T6, T7> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
-  typedef Templates8<T1, T2, T3, T4, T5, T6, T7, T8> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
-  typedef Templates9<T1, T2, T3, T4, T5, T6, T7, T8, T9> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
-  typedef Templates10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
-  typedef Templates11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
-  typedef Templates12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
-  typedef Templates13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
-      T13> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
-  typedef Templates14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
-      T14> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-    T15, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT> {
-  typedef Templates15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
-      T14, T15> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-    T15, T16, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT> {
-  typedef Templates16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
-      T14, T15, T16> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-    T15, T16, T17, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT> {
-  typedef Templates17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
-      T14, T15, T16, T17> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-    T15, T16, T17, T18, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT> {
-  typedef Templates18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
-      T14, T15, T16, T17, T18> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-    T15, T16, T17, T18, T19, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT> {
-  typedef Templates19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
-      T14, T15, T16, T17, T18, T19> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-    T15, T16, T17, T18, T19, T20, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT> {
-  typedef Templates20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
-      T14, T15, T16, T17, T18, T19, T20> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-    T15, T16, T17, T18, T19, T20, T21, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT> {
-  typedef Templates21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
-      T14, T15, T16, T17, T18, T19, T20, T21> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-    T15, T16, T17, T18, T19, T20, T21, T22, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT> {
-  typedef Templates22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
-      T14, T15, T16, T17, T18, T19, T20, T21, T22> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-    T15, T16, T17, T18, T19, T20, T21, T22, T23, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT> {
-  typedef Templates23<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT> {
-  typedef Templates24<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT> {
-  typedef Templates25<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT> {
-  typedef Templates26<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT> {
-  typedef Templates27<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
-      T27> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
-    GTEST_TEMPLATE_ T28>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT> {
-  typedef Templates28<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
-      T28> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT> {
-  typedef Templates29<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
-      T28, T29> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
-    T30, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
-  typedef Templates30<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
-      T28, T29, T30> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
-    GTEST_TEMPLATE_ T31>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
-    T30, T31, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
-  typedef Templates31<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
-      T28, T29, T30, T31> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
-    T30, T31, T32, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
-  typedef Templates32<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
-      T28, T29, T30, T31, T32> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
-    T30, T31, T32, T33, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
-  typedef Templates33<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
-      T28, T29, T30, T31, T32, T33> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
-    GTEST_TEMPLATE_ T34>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
-    T30, T31, T32, T33, T34, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
-  typedef Templates34<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
-      T28, T29, T30, T31, T32, T33, T34> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
-    T30, T31, T32, T33, T34, T35, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
-  typedef Templates35<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
-      T28, T29, T30, T31, T32, T33, T34, T35> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
-    T30, T31, T32, T33, T34, T35, T36, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
-  typedef Templates36<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
-      T28, T29, T30, T31, T32, T33, T34, T35, T36> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
-    GTEST_TEMPLATE_ T37>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
-    T30, T31, T32, T33, T34, T35, T36, T37, NoneT, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
-  typedef Templates37<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
-      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
-    T30, T31, T32, T33, T34, T35, T36, T37, T38, NoneT, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
-  typedef Templates38<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
-      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
-    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
-  typedef Templates39<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
-      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
-    GTEST_TEMPLATE_ T40>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
-    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, NoneT, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
-  typedef Templates40<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
-      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
-    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
-    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, NoneT, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
-  typedef Templates41<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
-      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
-      T41> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
-    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
-    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, NoneT,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
-  typedef Templates42<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
-      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
-      T42> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
-    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
-    GTEST_TEMPLATE_ T43>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
-    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
-  typedef Templates43<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
-      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
-      T42, T43> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
-    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
-    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
-    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
-    NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
-  typedef Templates44<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
-      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
-      T42, T43, T44> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
-    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
-    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
-    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
-    T45, NoneT, NoneT, NoneT, NoneT, NoneT> {
-  typedef Templates45<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
-      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
-      T42, T43, T44, T45> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
-    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
-    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
-    GTEST_TEMPLATE_ T46>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
-    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
-    T45, T46, NoneT, NoneT, NoneT, NoneT> {
-  typedef Templates46<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
-      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
-      T42, T43, T44, T45, T46> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
-    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
-    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
-    GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
-    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
-    T45, T46, T47, NoneT, NoneT, NoneT> {
-  typedef Templates47<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
-      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
-      T42, T43, T44, T45, T46, T47> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
-    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
-    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
-    GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
-    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
-    T45, T46, T47, T48, NoneT, NoneT> {
-  typedef Templates48<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
-      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
-      T42, T43, T44, T45, T46, T47, T48> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
-    GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
-    GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
-    GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
-    GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
-    GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
-    GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
-    GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
-    GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
-    GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
-    GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
-    GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
-    GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
-    GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
-    GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
-    GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48,
-    GTEST_TEMPLATE_ T49>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
-    T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
-    T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
-    T45, T46, T47, T48, T49, NoneT> {
-  typedef Templates49<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
-      T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
-      T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
-      T42, T43, T44, T45, T46, T47, T48, T49> type;
+template <GTEST_TEMPLATE_ Head_>
+struct Templates<Head_> {
+  using Head = TemplateSel<Head_>;
+  using Tail = None;
 };
 
-// The TypeList template makes it possible to use either a single type
-// or a Types<...> list in TYPED_TEST_SUITE() and
-// INSTANTIATE_TYPED_TEST_SUITE_P().
+// Tuple-like type lists
+template <typename Head_, typename... Tail_>
+struct Types {
+  using Head = Head_;
+  using Tail = Types<Tail_...>;
+};
 
+template <typename Head_>
+struct Types<Head_> {
+  using Head = Head_;
+  using Tail = None;
+};
+
+// Helper metafunctions to tell apart a single type from types
+// generated by ::testing::Types
+template <typename... Ts>
+struct ProxyTypeList {
+  using type = Types<Ts...>;
+};
+
+template <typename>
+struct is_proxy_type_list : std::false_type {};
+
+template <typename... Ts>
+struct is_proxy_type_list<ProxyTypeList<Ts...>> : std::true_type {};
+
+// Generator which conditionally creates type lists.
+// It recognizes if a requested type list should be created
+// and prevents creating a new type list nested within another one.
 template <typename T>
-struct TypeList {
-  typedef Types1<T> type;
-};
+struct GenerateTypeList {
+ private:
+  using proxy = typename std::conditional<is_proxy_type_list<T>::value, T,
+                                          ProxyTypeList<T>>::type;
 
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
-    typename T6, typename T7, typename T8, typename T9, typename T10,
-    typename T11, typename T12, typename T13, typename T14, typename T15,
-    typename T16, typename T17, typename T18, typename T19, typename T20,
-    typename T21, typename T22, typename T23, typename T24, typename T25,
-    typename T26, typename T27, typename T28, typename T29, typename T30,
-    typename T31, typename T32, typename T33, typename T34, typename T35,
-    typename T36, typename T37, typename T38, typename T39, typename T40,
-    typename T41, typename T42, typename T43, typename T44, typename T45,
-    typename T46, typename T47, typename T48, typename T49, typename T50>
-struct TypeList<Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
-    T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
-    T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
-    T44, T45, T46, T47, T48, T49, T50> > {
-  typedef typename Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
-      T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
-      T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
-      T41, T42, T43, T44, T45, T46, T47, T48, T49, T50>::type type;
+ public:
+  using type = typename proxy::type;
 };
 
-#endif  // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
-
 }  // namespace internal
+
+template <typename... Ts>
+using Types = internal::ProxyTypeList<Ts...>;
+
 }  // namespace testing
 
-#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
+#endif  // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
 
 // Due to C++ preprocessor weirdness, we need double indirection to
 // concatenate two tokens when one of them is __LINE__.  Writing
@@ -6544,10 +3457,20 @@
 #define GTEST_CONCAT_TOKEN_IMPL_(foo, bar) foo ## bar
 
 // Stringifies its argument.
-#define GTEST_STRINGIFY_(name) #name
+// Work around a bug in visual studio which doesn't accept code like this:
+//
+//   #define GTEST_STRINGIFY_(name) #name
+//   #define MACRO(a, b, c) ... GTEST_STRINGIFY_(a) ...
+//   MACRO(, x, y)
+//
+// Complaining about the argument to GTEST_STRINGIFY_ being empty.
+// This is allowed by the spec.
+#define GTEST_STRINGIFY_HELPER_(name, ...) #name
+#define GTEST_STRINGIFY_(...) GTEST_STRINGIFY_HELPER_(__VA_ARGS__, )
 
-class ProtocolMessage;
-namespace proto2 { class Message; }
+namespace proto2 {
+class MessageLite;
+}
 
 namespace testing {
 
@@ -6590,37 +3513,6 @@
   IgnoredValue(const T& /* ignored */) {}  // NOLINT(runtime/explicit)
 };
 
-// The only type that should be convertible to Secret* is nullptr.
-// The other null pointer constants are not of a type that is convertible to
-// Secret*. Only the literal with the right value is.
-template <typename T>
-using TypeIsValidNullptrConstant = std::integral_constant<
-    bool, std::is_same<typename std::decay<T>::type, std::nullptr_t>::value ||
-              !std::is_convertible<T, Secret*>::value>;
-
-// Two overloaded helpers for checking at compile time whether an
-// expression is a null pointer literal (i.e. NULL or any 0-valued
-// compile-time integral constant).  These helpers have no
-// implementations, as we only need their signatures.
-//
-// Given IsNullLiteralHelper(x), the compiler will pick the first
-// version if x can be implicitly converted to Secret*, and pick the
-// second version otherwise.  Since Secret is a secret and incomplete
-// type, the only expression a user can write that has type Secret* is
-// a null pointer literal.  Therefore, we know that x is a null
-// pointer literal if and only if the first version is picked by the
-// compiler.
-std::true_type IsNullLiteralHelper(Secret*, std::true_type);
-std::false_type IsNullLiteralHelper(IgnoredValue, std::false_type);
-std::false_type IsNullLiteralHelper(IgnoredValue, std::true_type);
-
-// A compile-time bool constant that is true if and only if x is a null pointer
-// literal (i.e. nullptr, NULL or any 0-valued compile-time integral constant).
-#define GTEST_IS_NULL_LITERAL_(x)                    \
-  decltype(::testing::internal::IsNullLiteralHelper( \
-      x,                                             \
-      ::testing::internal::TypeIsValidNullptrConstant<decltype(x)>()))::value
-
 // Appends the user-supplied message to the Google-Test-generated message.
 GTEST_API_ std::string AppendUserMessage(
     const std::string& gtest_msg, const Message& user_msg);
@@ -6687,7 +3579,7 @@
 //   expected_value:      "5"
 //   actual_value:        "6"
 //
-// The ignoring_case parameter is true iff the assertion is a
+// The ignoring_case parameter is true if and only if the assertion is a
 // *_STRCASEEQ*.  When it's true, the string " (ignoring case)" will
 // be inserted into the message.
 GTEST_API_ AssertionResult EqFailure(const char* expected_expression,
@@ -6773,7 +3665,7 @@
   //
   // See the following article for more details on ULP:
   // http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
-  static const size_t kMaxUlps = 4;
+  static const uint32_t kMaxUlps = 4;
 
   // Constructs a FloatingPoint from a raw floating-point number.
   //
@@ -6816,15 +3708,15 @@
   // Returns the sign bit of this number.
   Bits sign_bit() const { return kSignBitMask & u_.bits_; }
 
-  // Returns true iff this is NAN (not a number).
+  // Returns true if and only if this is NAN (not a number).
   bool is_nan() const {
     // It's a NAN if the exponent bits are all ones and the fraction
     // bits are not entirely zeros.
     return (exponent_bits() == kExponentBitMask) && (fraction_bits() != 0);
   }
 
-  // Returns true iff this number is at most kMaxUlps ULP's away from
-  // rhs.  In particular, this function:
+  // Returns true if and only if this number is at most kMaxUlps ULP's away
+  // from rhs.  In particular, this function:
   //
   //   - returns false if either number is (or both are) NAN.
   //   - treats really large numbers as almost equal to infinity.
@@ -7004,7 +3896,9 @@
   using Test =
       typename std::conditional<sizeof(T) != 0, ::testing::Test, void>::type;
 
-  static SetUpTearDownSuiteFuncType GetSetUpCaseOrSuite() {
+  static SetUpTearDownSuiteFuncType GetSetUpCaseOrSuite(const char* filename,
+                                                        int line_num) {
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
     SetUpTearDownSuiteFuncType test_case_fp =
         GetNotDefaultOrNull(&T::SetUpTestCase, &Test::SetUpTestCase);
     SetUpTearDownSuiteFuncType test_suite_fp =
@@ -7012,12 +3906,20 @@
 
     GTEST_CHECK_(!test_case_fp || !test_suite_fp)
         << "Test can not provide both SetUpTestSuite and SetUpTestCase, please "
-           "make sure there is only one present ";
+           "make sure there is only one present at "
+        << filename << ":" << line_num;
 
     return test_case_fp != nullptr ? test_case_fp : test_suite_fp;
+#else
+    (void)(filename);
+    (void)(line_num);
+    return &T::SetUpTestSuite;
+#endif
   }
 
-  static SetUpTearDownSuiteFuncType GetTearDownCaseOrSuite() {
+  static SetUpTearDownSuiteFuncType GetTearDownCaseOrSuite(const char* filename,
+                                                           int line_num) {
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
     SetUpTearDownSuiteFuncType test_case_fp =
         GetNotDefaultOrNull(&T::TearDownTestCase, &Test::TearDownTestCase);
     SetUpTearDownSuiteFuncType test_suite_fp =
@@ -7025,9 +3927,15 @@
 
     GTEST_CHECK_(!test_case_fp || !test_suite_fp)
         << "Test can not provide both TearDownTestSuite and TearDownTestCase,"
-           " please make sure there is only one present ";
+           " please make sure there is only one present at"
+        << filename << ":" << line_num;
 
     return test_case_fp != nullptr ? test_case_fp : test_suite_fp;
+#else
+    (void)(filename);
+    (void)(line_num);
+    return &T::TearDownTestSuite;
+#endif
   }
 };
 
@@ -7036,11 +3944,11 @@
 //
 // Arguments:
 //
-//   test_suite_name:   name of the test suite
+//   test_suite_name:  name of the test suite
 //   name:             name of the test
-//   type_param        the name of the test's type parameter, or NULL if
+//   type_param:       the name of the test's type parameter, or NULL if
 //                     this is not a typed or a type-parameterized test.
-//   value_param       text representation of the test's value parameter,
+//   value_param:      text representation of the test's value parameter,
 //                     or NULL if this is not a type-parameterized test.
 //   code_location:    code location where the test is defined
 //   fixture_class_id: ID of the test fixture class
@@ -7060,8 +3968,6 @@
 // and returns false.  None of pstr, *pstr, and prefix can be NULL.
 GTEST_API_ bool SkipPrefix(const char* prefix, const char** pstr);
 
-#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
-
 GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \
 /* class A needs to have dll-interface to be used by clients of class B */)
 
@@ -7101,8 +4007,9 @@
   // Verifies that registered_tests match the test names in
   // defined_test_names_; returns registered_tests if successful, or
   // aborts the program otherwise.
-  const char* VerifyRegisteredTestNames(
-      const char* file, int line, const char* registered_tests);
+  const char* VerifyRegisteredTestNames(const char* test_suite_name,
+                                        const char* file, int line,
+                                        const char* registered_tests);
 
  private:
   typedef ::std::map<std::string, CodeLocation> RegisteredTestsMap;
@@ -7156,7 +4063,7 @@
 };
 
 template <typename NameGenerator>
-void GenerateNamesRecursively(Types0, std::vector<std::string>*, int) {}
+void GenerateNamesRecursively(internal::None, std::vector<std::string>*, int) {}
 
 template <typename NameGenerator, typename Types>
 void GenerateNamesRecursively(Types, std::vector<std::string>* result, int i) {
@@ -7198,14 +4105,16 @@
     // list.
     MakeAndRegisterTestInfo(
         (std::string(prefix) + (prefix[0] == '\0' ? "" : "/") + case_name +
-         "/" + type_names[index])
+         "/" + type_names[static_cast<size_t>(index)])
             .c_str(),
         StripTrailingSpaces(GetPrefixUntilComma(test_names)).c_str(),
         GetTypeName<Type>().c_str(),
         nullptr,  // No value parameter.
         code_location, GetTypeId<FixtureClass>(),
-        SuiteApiResolver<TestClass>::GetSetUpCaseOrSuite(),
-        SuiteApiResolver<TestClass>::GetTearDownCaseOrSuite(),
+        SuiteApiResolver<TestClass>::GetSetUpCaseOrSuite(
+            code_location.file.c_str(), code_location.line),
+        SuiteApiResolver<TestClass>::GetTearDownCaseOrSuite(
+            code_location.file.c_str(), code_location.line),
         new TestFactoryImpl<TestClass>);
 
     // Next, recurses (at compile time) with the tail of the type list.
@@ -7221,7 +4130,7 @@
 
 // The base case for the compile time recursion.
 template <GTEST_TEMPLATE_ Fixture, class TestSel>
-class TypeParameterizedTest<Fixture, TestSel, Types0> {
+class TypeParameterizedTest<Fixture, TestSel, internal::None> {
  public:
   static bool Register(const char* /*prefix*/, const CodeLocation&,
                        const char* /*case_name*/, const char* /*test_names*/,
@@ -7232,6 +4141,11 @@
   }
 };
 
+GTEST_API_ void RegisterTypeParameterizedTestSuite(const char* test_suite_name,
+                                                   CodeLocation code_location);
+GTEST_API_ void RegisterTypeParameterizedTestSuiteInstantiation(
+    const char* case_name);
+
 // TypeParameterizedTestSuite<Fixture, Tests, Types>::Register()
 // registers *all combinations* of 'Tests' and 'Types' with Google
 // Test.  The return value is insignificant - we just need to return
@@ -7244,6 +4158,7 @@
                        const char* test_names,
                        const std::vector<std::string>& type_names =
                            GenerateNames<DefaultNameGenerator, Types>()) {
+    RegisterTypeParameterizedTestSuiteInstantiation(case_name);
     std::string test_name = StripTrailingSpaces(
         GetPrefixUntilComma(test_names));
     if (!state->TestExists(test_name)) {
@@ -7273,7 +4188,7 @@
 
 // The base case for the compile time recursion.
 template <GTEST_TEMPLATE_ Fixture, typename Types>
-class TypeParameterizedTestSuite<Fixture, Templates0, Types> {
+class TypeParameterizedTestSuite<Fixture, internal::None, Types> {
  public:
   static bool Register(const char* /*prefix*/, const CodeLocation&,
                        const TypedTestSuitePState* /*state*/,
@@ -7284,8 +4199,6 @@
   }
 };
 
-#endif  // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
-
 // Returns the current OS stack trace as an std::string.
 //
 // The maximum number of stack frames to be included is specified by
@@ -7317,6 +4230,16 @@
   const char* value;
 };
 
+// Helper for declaring std::string within 'if' statement
+// in pre C++17 build environment.
+struct TrueWithString {
+  TrueWithString() = default;
+  explicit TrueWithString(const char* str) : value(str) {}
+  explicit TrueWithString(const std::string& str) : value(str) {}
+  explicit operator bool() const { return true; }
+  std::string value;
+};
+
 // A simple Linear Congruential Generator for generating random
 // numbers with a uniform distribution.  Unlike rand() and srand(), it
 // doesn't use global state (and therefore can't interfere with user
@@ -7324,78 +4247,54 @@
 // but it's good enough for our purposes.
 class GTEST_API_ Random {
  public:
-  static const UInt32 kMaxRange = 1u << 31;
+  static const uint32_t kMaxRange = 1u << 31;
 
-  explicit Random(UInt32 seed) : state_(seed) {}
+  explicit Random(uint32_t seed) : state_(seed) {}
 
-  void Reseed(UInt32 seed) { state_ = seed; }
+  void Reseed(uint32_t seed) { state_ = seed; }
 
   // Generates a random number from [0, range).  Crashes if 'range' is
   // 0 or greater than kMaxRange.
-  UInt32 Generate(UInt32 range);
+  uint32_t Generate(uint32_t range);
 
  private:
-  UInt32 state_;
+  uint32_t state_;
   GTEST_DISALLOW_COPY_AND_ASSIGN_(Random);
 };
 
-// Defining a variable of type CompileAssertTypesEqual<T1, T2> will cause a
-// compiler error iff T1 and T2 are different types.
-template <typename T1, typename T2>
-struct CompileAssertTypesEqual;
-
-template <typename T>
-struct CompileAssertTypesEqual<T, T> {
-};
-
-// Removes the reference from a type if it is a reference type,
-// otherwise leaves it unchanged.  This is the same as
-// tr1::remove_reference, which is not widely available yet.
-template <typename T>
-struct RemoveReference { typedef T type; };  // NOLINT
-template <typename T>
-struct RemoveReference<T&> { typedef T type; };  // NOLINT
-
-// A handy wrapper around RemoveReference that works when the argument
-// T depends on template parameters.
-#define GTEST_REMOVE_REFERENCE_(T) \
-    typename ::testing::internal::RemoveReference<T>::type
-
-// Removes const from a type if it is a const type, otherwise leaves
-// it unchanged.  This is the same as tr1::remove_const, which is not
-// widely available yet.
-template <typename T>
-struct RemoveConst { typedef T type; };  // NOLINT
-template <typename T>
-struct RemoveConst<const T> { typedef T type; };  // NOLINT
-
-// MSVC 8.0, Sun C++, and IBM XL C++ have a bug which causes the above
-// definition to fail to remove the const in 'const int[3]' and 'const
-// char[3][4]'.  The following specialization works around the bug.
-template <typename T, size_t N>
-struct RemoveConst<const T[N]> {
-  typedef typename RemoveConst<T>::type type[N];
-};
-
-// A handy wrapper around RemoveConst that works when the argument
-// T depends on template parameters.
-#define GTEST_REMOVE_CONST_(T) \
-    typename ::testing::internal::RemoveConst<T>::type
-
 // Turns const U&, U&, const U, and U all into U.
 #define GTEST_REMOVE_REFERENCE_AND_CONST_(T) \
-    GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(T))
+  typename std::remove_const<typename std::remove_reference<T>::type>::type
 
-// IsAProtocolMessage<T>::value is a compile-time bool constant that's
-// true iff T is type ProtocolMessage, proto2::Message, or a subclass
-// of those.
+// HasDebugStringAndShortDebugString<T>::value is a compile-time bool constant
+// that's true if and only if T has methods DebugString() and ShortDebugString()
+// that return std::string.
 template <typename T>
-struct IsAProtocolMessage
-    : public bool_constant<
-  std::is_convertible<const T*, const ::ProtocolMessage*>::value ||
-  std::is_convertible<const T*, const ::proto2::Message*>::value> {
+class HasDebugStringAndShortDebugString {
+ private:
+  template <typename C>
+  static auto CheckDebugString(C*) -> typename std::is_same<
+      std::string, decltype(std::declval<const C>().DebugString())>::type;
+  template <typename>
+  static std::false_type CheckDebugString(...);
+
+  template <typename C>
+  static auto CheckShortDebugString(C*) -> typename std::is_same<
+      std::string, decltype(std::declval<const C>().ShortDebugString())>::type;
+  template <typename>
+  static std::false_type CheckShortDebugString(...);
+
+  using HasDebugStringType = decltype(CheckDebugString<T>(nullptr));
+  using HasShortDebugStringType = decltype(CheckShortDebugString<T>(nullptr));
+
+ public:
+  static constexpr bool value =
+      HasDebugStringType::value && HasShortDebugStringType::value;
 };
 
+template <typename T>
+constexpr bool HasDebugStringAndShortDebugString<T>::value;
+
 // When the compiler sees expression IsContainerTest<C>(0), if C is an
 // STL-style container class, the first overload of IsContainerTest
 // will be viable (since both C::iterator* and C::const_iterator* are
@@ -7461,7 +4360,7 @@
 struct IsRecursiveContainerImpl;
 
 template <typename C>
-struct IsRecursiveContainerImpl<C, false> : public false_type {};
+struct IsRecursiveContainerImpl<C, false> : public std::false_type {};
 
 // Since the IsRecursiveContainerImpl depends on the IsContainerTest we need to
 // obey the same inconsistencies as the IsContainerTest, namely check if
@@ -7471,9 +4370,9 @@
 struct IsRecursiveContainerImpl<C, true> {
   using value_type = decltype(*std::declval<typename C::const_iterator>());
   using type =
-      is_same<typename std::remove_const<
-                  typename std::remove_reference<value_type>::type>::type,
-              C>;
+      std::is_same<typename std::remove_const<
+                       typename std::remove_reference<value_type>::type>::type,
+                   C>;
 };
 
 // IsRecursiveContainer<Type> is a unary compile-time predicate that
@@ -7485,13 +4384,6 @@
 template <typename C>
 struct IsRecursiveContainer : public IsRecursiveContainerImpl<C>::type {};
 
-// EnableIf<condition>::type is void when 'Cond' is true, and
-// undefined when 'Cond' is false.  To use SFINAE to make a function
-// overload only apply when a particular expression is true, add
-// "typename EnableIf<expression>::type* = 0" as the last parameter.
-template<bool> struct EnableIf;
-template<> struct EnableIf<true> { typedef void type; };  // NOLINT
-
 // Utilities for native arrays.
 
 // ArrayEq() compares two k-dimensional native arrays using the
@@ -7614,10 +4506,9 @@
   }
 
  private:
-  enum {
-    kCheckTypeIsNotConstOrAReference = StaticAssertTypeEqHelper<
-        Element, GTEST_REMOVE_REFERENCE_AND_CONST_(Element)>::value
-  };
+  static_assert(!std::is_const<Element>::value, "Type must not be const");
+  static_assert(!std::is_reference<Element>::value,
+                "Type must not be a reference");
 
   // Initializes this object with a copy of the input.
   void InitCopy(const Element* array, size_t a_size) {
@@ -7661,32 +4552,44 @@
 // Backport of std::make_index_sequence.
 // It uses O(ln(N)) instantiation depth.
 template <size_t N>
-struct MakeIndexSequence
-    : DoubleSequence<N % 2 == 1, typename MakeIndexSequence<N / 2>::type,
+struct MakeIndexSequenceImpl
+    : DoubleSequence<N % 2 == 1, typename MakeIndexSequenceImpl<N / 2>::type,
                      N / 2>::type {};
 
 template <>
-struct MakeIndexSequence<0> : IndexSequence<> {};
+struct MakeIndexSequenceImpl<0> : IndexSequence<> {};
 
-// FIXME: This implementation of ElemFromList is O(1) in instantiation depth,
-// but it is O(N^2) in total instantiations. Not sure if this is the best
-// tradeoff, as it will make it somewhat slow to compile.
-template <typename T, size_t, size_t>
-struct ElemFromListImpl {};
+template <size_t N>
+using MakeIndexSequence = typename MakeIndexSequenceImpl<N>::type;
 
-template <typename T, size_t I>
-struct ElemFromListImpl<T, I, I> {
-  using type = T;
+template <typename... T>
+using IndexSequenceFor = typename MakeIndexSequence<sizeof...(T)>::type;
+
+template <size_t>
+struct Ignore {
+  Ignore(...);  // NOLINT
 };
 
-// Get the Nth element from T...
-// It uses O(1) instantiation depth.
-template <size_t N, typename I, typename... T>
-struct ElemFromList;
+template <typename>
+struct ElemFromListImpl;
+template <size_t... I>
+struct ElemFromListImpl<IndexSequence<I...>> {
+  // We make Ignore a template to solve a problem with MSVC.
+  // A non-template Ignore would work fine with `decltype(Ignore(I))...`, but
+  // MSVC doesn't understand how to deal with that pack expansion.
+  // Use `0 * I` to have a single instantiation of Ignore.
+  template <typename R>
+  static R Apply(Ignore<0 * I>..., R (*)(), ...);
+};
 
-template <size_t N, size_t... I, typename... T>
-struct ElemFromList<N, IndexSequence<I...>, T...>
-    : ElemFromListImpl<T, N, I>... {};
+template <size_t N, typename... T>
+struct ElemFromList {
+  using type =
+      decltype(ElemFromListImpl<typename MakeIndexSequence<N>::type>::Apply(
+          static_cast<T (*)()>(nullptr)...));
+};
+
+struct FlatTupleConstructTag {};
 
 template <typename... T>
 class FlatTuple;
@@ -7696,11 +4599,11 @@
 
 template <typename... T, size_t I>
 struct FlatTupleElemBase<FlatTuple<T...>, I> {
-  using value_type =
-      typename ElemFromList<I, typename MakeIndexSequence<sizeof...(T)>::type,
-                            T...>::type;
+  using value_type = typename ElemFromList<I, T...>::type;
   FlatTupleElemBase() = default;
-  explicit FlatTupleElemBase(value_type t) : value(std::move(t)) {}
+  template <typename Arg>
+  explicit FlatTupleElemBase(FlatTupleConstructTag, Arg&& t)
+      : value(std::forward<Arg>(t)) {}
   value_type value;
 };
 
@@ -7712,13 +4615,35 @@
     : FlatTupleElemBase<FlatTuple<T...>, Idx>... {
   using Indices = IndexSequence<Idx...>;
   FlatTupleBase() = default;
-  explicit FlatTupleBase(T... t)
-      : FlatTupleElemBase<FlatTuple<T...>, Idx>(std::move(t))... {}
+  template <typename... Args>
+  explicit FlatTupleBase(FlatTupleConstructTag, Args&&... args)
+      : FlatTupleElemBase<FlatTuple<T...>, Idx>(FlatTupleConstructTag{},
+                                                std::forward<Args>(args))... {}
+
+  template <size_t I>
+  const typename ElemFromList<I, T...>::type& Get() const {
+    return FlatTupleElemBase<FlatTuple<T...>, I>::value;
+  }
+
+  template <size_t I>
+  typename ElemFromList<I, T...>::type& Get() {
+    return FlatTupleElemBase<FlatTuple<T...>, I>::value;
+  }
+
+  template <typename F>
+  auto Apply(F&& f) -> decltype(std::forward<F>(f)(this->Get<Idx>()...)) {
+    return std::forward<F>(f)(Get<Idx>()...);
+  }
+
+  template <typename F>
+  auto Apply(F&& f) const -> decltype(std::forward<F>(f)(this->Get<Idx>()...)) {
+    return std::forward<F>(f)(Get<Idx>()...);
+  }
 };
 
 // Analog to std::tuple but with different tradeoffs.
 // This class minimizes the template instantiation depth, thus allowing more
-// elements that std::tuple would. std::tuple has been seen to require an
+// elements than std::tuple would. std::tuple has been seen to require an
 // instantiation depth of more than 10x the number of elements in some
 // implementations.
 // FlatTuple and ElemFromList are not recursive and have a fixed depth
@@ -7729,21 +4654,17 @@
 class FlatTuple
     : private FlatTupleBase<FlatTuple<T...>,
                             typename MakeIndexSequence<sizeof...(T)>::type> {
-  using Indices = typename FlatTuple::FlatTupleBase::Indices;
+  using Indices = typename FlatTupleBase<
+      FlatTuple<T...>, typename MakeIndexSequence<sizeof...(T)>::type>::Indices;
 
  public:
   FlatTuple() = default;
-  explicit FlatTuple(T... t) : FlatTuple::FlatTupleBase(std::move(t)...) {}
+  template <typename... Args>
+  explicit FlatTuple(FlatTupleConstructTag tag, Args&&... args)
+      : FlatTuple::FlatTupleBase(tag, std::forward<Args>(args)...) {}
 
-  template <size_t I>
-  const typename ElemFromList<I, Indices, T...>::type& Get() const {
-    return static_cast<const FlatTupleElemBase<FlatTuple, I>*>(this)->value;
-  }
-
-  template <size_t I>
-  typename ElemFromList<I, Indices, T...>::type& Get() {
-    return static_cast<FlatTupleElemBase<FlatTuple, I>*>(this)->value;
-  }
+  using FlatTuple::FlatTupleBase::Apply;
+  using FlatTuple::FlatTupleBase::Get;
 };
 
 // Utility functions to be called with static_assert to induce deprecation
@@ -7776,6 +4697,22 @@
 }  // namespace internal
 }  // namespace testing
 
+namespace std {
+// Some standard library implementations use `struct tuple_size` and some use
+// `class tuple_size`. Clang warns about the mismatch.
+// https://reviews.llvm.org/D55466
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wmismatched-tags"
+#endif
+template <typename... Ts>
+struct tuple_size<testing::internal::FlatTuple<Ts...>>
+    : std::integral_constant<size_t, sizeof...(Ts)> {};
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+}  // namespace std
+
 #define GTEST_MESSAGE_AT_(file, line, message, result_type) \
   ::testing::internal::AssertHelper(result_type, file, line, message) \
     = ::testing::Message()
@@ -7798,48 +4735,122 @@
 // Suppress MSVC warning 4072 (unreachable code) for the code following
 // statement if it returns or throws (or doesn't return or throw in some
 // situations).
+// NOTE: The "else" is important to keep this expansion to prevent a top-level
+// "else" from attaching to our "if".
 #define GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) \
-  if (::testing::internal::AlwaysTrue()) { statement; }
+  if (::testing::internal::AlwaysTrue()) {                        \
+    statement;                                                    \
+  } else                     /* NOLINT */                         \
+    static_assert(true, "")  // User must have a semicolon after expansion.
 
-#define GTEST_TEST_THROW_(statement, expected_exception, fail) \
-  GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
-  if (::testing::internal::ConstCharPtr gtest_msg = "") { \
-    bool gtest_caught_expected = false; \
-    try { \
-      GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
-    } \
-    catch (expected_exception const&) { \
-      gtest_caught_expected = true; \
-    } \
-    catch (...) { \
-      gtest_msg.value = \
-          "Expected: " #statement " throws an exception of type " \
-          #expected_exception ".\n  Actual: it throws a different type."; \
-      goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
-    } \
-    if (!gtest_caught_expected) { \
-      gtest_msg.value = \
-          "Expected: " #statement " throws an exception of type " \
-          #expected_exception ".\n  Actual: it throws nothing."; \
-      goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
-    } \
-  } else \
-    GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \
-      fail(gtest_msg.value)
+#if GTEST_HAS_EXCEPTIONS
+
+namespace testing {
+namespace internal {
+
+class NeverThrown {
+ public:
+  const char* what() const noexcept {
+    return "this exception should never be thrown";
+  }
+};
+
+}  // namespace internal
+}  // namespace testing
+
+#if GTEST_HAS_RTTI
+
+#define GTEST_EXCEPTION_TYPE_(e) ::testing::internal::GetTypeName(typeid(e))
+
+#else  // GTEST_HAS_RTTI
+
+#define GTEST_EXCEPTION_TYPE_(e) \
+  std::string { "an std::exception-derived error" }
+
+#endif  // GTEST_HAS_RTTI
+
+#define GTEST_TEST_THROW_CATCH_STD_EXCEPTION_(statement, expected_exception)   \
+  catch (typename std::conditional<                                            \
+         std::is_same<typename std::remove_cv<typename std::remove_reference<  \
+                          expected_exception>::type>::type,                    \
+                      std::exception>::value,                                  \
+         const ::testing::internal::NeverThrown&, const std::exception&>::type \
+             e) {                                                              \
+    gtest_msg.value = "Expected: " #statement                                  \
+                      " throws an exception of type " #expected_exception      \
+                      ".\n  Actual: it throws ";                               \
+    gtest_msg.value += GTEST_EXCEPTION_TYPE_(e);                               \
+    gtest_msg.value += " with description \"";                                 \
+    gtest_msg.value += e.what();                                               \
+    gtest_msg.value += "\".";                                                  \
+    goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__);                \
+  }
+
+#else  // GTEST_HAS_EXCEPTIONS
+
+#define GTEST_TEST_THROW_CATCH_STD_EXCEPTION_(statement, expected_exception)
+
+#endif  // GTEST_HAS_EXCEPTIONS
+
+#define GTEST_TEST_THROW_(statement, expected_exception, fail)              \
+  GTEST_AMBIGUOUS_ELSE_BLOCKER_                                             \
+  if (::testing::internal::TrueWithString gtest_msg{}) {                    \
+    bool gtest_caught_expected = false;                                     \
+    try {                                                                   \
+      GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement);            \
+    } catch (expected_exception const&) {                                   \
+      gtest_caught_expected = true;                                         \
+    }                                                                       \
+    GTEST_TEST_THROW_CATCH_STD_EXCEPTION_(statement, expected_exception)    \
+    catch (...) {                                                           \
+      gtest_msg.value = "Expected: " #statement                             \
+                        " throws an exception of type " #expected_exception \
+                        ".\n  Actual: it throws a different type.";         \
+      goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__);           \
+    }                                                                       \
+    if (!gtest_caught_expected) {                                           \
+      gtest_msg.value = "Expected: " #statement                             \
+                        " throws an exception of type " #expected_exception \
+                        ".\n  Actual: it throws nothing.";                  \
+      goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__);           \
+    }                                                                       \
+  } else /*NOLINT*/                                                         \
+    GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__)                   \
+        : fail(gtest_msg.value.c_str())
+
+#if GTEST_HAS_EXCEPTIONS
+
+#define GTEST_TEST_NO_THROW_CATCH_STD_EXCEPTION_()                \
+  catch (std::exception const& e) {                               \
+    gtest_msg.value = "it throws ";                               \
+    gtest_msg.value += GTEST_EXCEPTION_TYPE_(e);                  \
+    gtest_msg.value += " with description \"";                    \
+    gtest_msg.value += e.what();                                  \
+    gtest_msg.value += "\".";                                     \
+    goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \
+  }
+
+#else  // GTEST_HAS_EXCEPTIONS
+
+#define GTEST_TEST_NO_THROW_CATCH_STD_EXCEPTION_()
+
+#endif  // GTEST_HAS_EXCEPTIONS
 
 #define GTEST_TEST_NO_THROW_(statement, fail) \
   GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
-  if (::testing::internal::AlwaysTrue()) { \
+  if (::testing::internal::TrueWithString gtest_msg{}) { \
     try { \
       GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
     } \
+    GTEST_TEST_NO_THROW_CATCH_STD_EXCEPTION_() \
     catch (...) { \
+      gtest_msg.value = "it throws."; \
       goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \
     } \
   } else \
     GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__): \
-      fail("Expected: " #statement " doesn't throw an exception.\n" \
-           "  Actual: it throws.")
+      fail(("Expected: " #statement " doesn't throw an exception.\n" \
+            "  Actual: " + gtest_msg.value).c_str())
 
 #define GTEST_TEST_ANY_THROW_(statement, fail) \
   GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
@@ -7862,7 +4873,7 @@
 
 // Implements Boolean test assertions such as EXPECT_TRUE. expression can be
 // either a boolean expression or an AssertionResult. text is a textual
-// represenation of expression as it was passed into the EXPECT_TRUE.
+// representation of expression as it was passed into the EXPECT_TRUE.
 #define GTEST_TEST_BOOLEAN_(expression, text, actual, expected, fail) \
   GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
   if (const ::testing::AssertionResult gtest_ar_ = \
@@ -7892,16 +4903,23 @@
 
 // Helper macro for defining tests.
 #define GTEST_TEST_(test_suite_name, test_name, parent_class, parent_id)      \
+  static_assert(sizeof(GTEST_STRINGIFY_(test_suite_name)) > 1,                \
+                "test_suite_name must not be empty");                         \
+  static_assert(sizeof(GTEST_STRINGIFY_(test_name)) > 1,                      \
+                "test_name must not be empty");                               \
   class GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)                    \
       : public parent_class {                                                 \
    public:                                                                    \
-    GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)() {}                   \
-                                                                              \
-   private:                                                                   \
-    virtual void TestBody();                                                  \
-    static ::testing::TestInfo* const test_info_ GTEST_ATTRIBUTE_UNUSED_;     \
+    GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)() = default;           \
+    ~GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)() override = default; \
     GTEST_DISALLOW_COPY_AND_ASSIGN_(GTEST_TEST_CLASS_NAME_(test_suite_name,   \
                                                            test_name));       \
+    GTEST_DISALLOW_MOVE_AND_ASSIGN_(GTEST_TEST_CLASS_NAME_(test_suite_name,   \
+                                                           test_name));       \
+                                                                              \
+   private:                                                                   \
+    void TestBody() override;                                                 \
+    static ::testing::TestInfo* const test_info_ GTEST_ATTRIBUTE_UNUSED_;     \
   };                                                                          \
                                                                               \
   ::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_suite_name,          \
@@ -7910,14 +4928,14 @@
           #test_suite_name, #test_name, nullptr, nullptr,                     \
           ::testing::internal::CodeLocation(__FILE__, __LINE__), (parent_id), \
           ::testing::internal::SuiteApiResolver<                              \
-              parent_class>::GetSetUpCaseOrSuite(),                           \
+              parent_class>::GetSetUpCaseOrSuite(__FILE__, __LINE__),         \
           ::testing::internal::SuiteApiResolver<                              \
-              parent_class>::GetTearDownCaseOrSuite(),                        \
+              parent_class>::GetTearDownCaseOrSuite(__FILE__, __LINE__),      \
           new ::testing::internal::TestFactoryImpl<GTEST_TEST_CLASS_NAME_(    \
               test_suite_name, test_name)>);                                  \
   void GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)::TestBody()
 
-#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
+#endif  // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
 // Copyright 2005, Google Inc.
 // All rights reserved.
 //
@@ -7955,8 +4973,8 @@
 // directly.
 // GOOGLETEST_CM0001 DO NOT DELETE
 
-#ifndef GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
-#define GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
+#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
+#define GOOGLETEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
 
 // Copyright 2005, Google Inc.
 // All rights reserved.
@@ -7993,8 +5011,8 @@
 // death tests.  They are subject to change without notice.
 // GOOGLETEST_CM0001 DO NOT DELETE
 
-#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
-#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
+#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
+#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
 
 // Copyright 2007, Google Inc.
 // All rights reserved.
@@ -8030,16 +5048,14 @@
 // This file implements just enough of the matcher interface to allow
 // EXPECT_DEATH and friends to accept a matcher argument.
 
-// IWYU pragma: private, include "testing/base/public/gunit.h"
-// IWYU pragma: friend third_party/googletest/googlemock/.*
-// IWYU pragma: friend third_party/googletest/googletest/.*
+#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_MATCHERS_H_
+#define GOOGLETEST_INCLUDE_GTEST_GTEST_MATCHERS_H_
 
-#ifndef GTEST_INCLUDE_GTEST_GTEST_MATCHERS_H_
-#define GTEST_INCLUDE_GTEST_GTEST_MATCHERS_H_
-
+#include <atomic>
 #include <memory>
 #include <ostream>
 #include <string>
+#include <type_traits>
 
 // Copyright 2007, Google Inc.
 // All rights reserved.
@@ -8140,10 +5156,11 @@
 
 // GOOGLETEST_CM0001 DO NOT DELETE
 
-#ifndef GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_
-#define GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_
+#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_PRINTERS_H_
+#define GOOGLETEST_INCLUDE_GTEST_GTEST_PRINTERS_H_
 
 #include <functional>
+#include <memory>
 #include <ostream>  // NOLINT
 #include <sstream>
 #include <string>
@@ -8152,60 +5169,121 @@
 #include <utility>
 #include <vector>
 
-#if GTEST_HAS_ABSL
-#include "absl/strings/string_view.h"
-#include "absl/types/optional.h"
-#include "absl/types/variant.h"
-#endif  // GTEST_HAS_ABSL
 
 namespace testing {
 
-// Definitions in the 'internal' and 'internal2' name spaces are
-// subject to change without notice.  DO NOT USE THEM IN USER CODE!
-namespace internal2 {
+// Definitions in the internal* namespaces are subject to change without notice.
+// DO NOT USE THEM IN USER CODE!
+namespace internal {
 
-// Prints the given number of bytes in the given object to the given
-// ostream.
-GTEST_API_ void PrintBytesInObjectTo(const unsigned char* obj_bytes,
-                                     size_t count,
-                                     ::std::ostream* os);
+template <typename T>
+void UniversalPrint(const T& value, ::std::ostream* os);
 
-// For selecting which printer to use when a given type has neither <<
-// nor PrintTo().
-enum TypeKind {
-  kProtobuf,              // a protobuf type
-  kConvertibleToInteger,  // a type implicitly convertible to BiggestInt
-                          // (e.g. a named or unnamed enum type)
-#if GTEST_HAS_ABSL
-  kConvertibleToStringView,  // a type implicitly convertible to
-                             // absl::string_view
-#endif
-  kOtherType  // anything else
-};
+// Used to print an STL-style container when the user doesn't define
+// a PrintTo() for it.
+struct ContainerPrinter {
+  template <typename T,
+            typename = typename std::enable_if<
+                (sizeof(IsContainerTest<T>(0)) == sizeof(IsContainer)) &&
+                !IsRecursiveContainer<T>::value>::type>
+  static void PrintValue(const T& container, std::ostream* os) {
+    const size_t kMaxCount = 32;  // The maximum number of elements to print.
+    *os << '{';
+    size_t count = 0;
+    for (auto&& elem : container) {
+      if (count > 0) {
+        *os << ',';
+        if (count == kMaxCount) {  // Enough has been printed.
+          *os << " ...";
+          break;
+        }
+      }
+      *os << ' ';
+      // We cannot call PrintTo(elem, os) here as PrintTo() doesn't
+      // handle `elem` being a native array.
+      internal::UniversalPrint(elem, os);
+      ++count;
+    }
 
-// TypeWithoutFormatter<T, kTypeKind>::PrintValue(value, os) is called
-// by the universal printer to print a value of type T when neither
-// operator<< nor PrintTo() is defined for T, where kTypeKind is the
-// "kind" of T as defined by enum TypeKind.
-template <typename T, TypeKind kTypeKind>
-class TypeWithoutFormatter {
- public:
-  // This default version is called when kTypeKind is kOtherType.
-  static void PrintValue(const T& value, ::std::ostream* os) {
-    PrintBytesInObjectTo(static_cast<const unsigned char*>(
-                             reinterpret_cast<const void*>(&value)),
-                         sizeof(value), os);
+    if (count > 0) {
+      *os << ' ';
+    }
+    *os << '}';
   }
 };
 
-// We print a protobuf using its ShortDebugString() when the string
-// doesn't exceed this many characters; otherwise we print it using
-// DebugString() for better readability.
-const size_t kProtobufOneLinerMaxLength = 50;
+// Used to print a pointer that is neither a char pointer nor a member
+// pointer, when the user doesn't define PrintTo() for it.  (A member
+// variable pointer or member function pointer doesn't really point to
+// a location in the address space.  Their representation is
+// implementation-defined.  Therefore they will be printed as raw
+// bytes.)
+struct FunctionPointerPrinter {
+  template <typename T, typename = typename std::enable_if<
+                            std::is_function<T>::value>::type>
+  static void PrintValue(T* p, ::std::ostream* os) {
+    if (p == nullptr) {
+      *os << "NULL";
+    } else {
+      // T is a function type, so '*os << p' doesn't do what we want
+      // (it just prints p as bool).  We want to print p as a const
+      // void*.
+      *os << reinterpret_cast<const void*>(p);
+    }
+  }
+};
 
-template <typename T>
-class TypeWithoutFormatter<T, kProtobuf> {
- public:
+struct PointerPrinter {
+  template <typename T>
+  static void PrintValue(T* p, ::std::ostream* os) {
+    if (p == nullptr) {
+      *os << "NULL";
+    } else {
+      // T is not a function type.  We just call << to print p,
+      // relying on ADL to pick up user-defined << for their pointer
+      // types, if any.
+      *os << p;
+    }
+  }
+};
+
+namespace internal_stream_operator_without_lexical_name_lookup {
+
+// The presence of an operator<< here will terminate lexical scope lookup
+// straight away (even though it cannot be a match because of its argument
+// types). Thus, the two operator<< calls in StreamPrinter will find only ADL
+// candidates.
+struct LookupBlocker {};
+void operator<<(LookupBlocker, LookupBlocker);
+
+struct StreamPrinter {
+  template <typename T,
+            // Don't accept member pointers here. We'd print them via implicit
+            // conversion to bool, which isn't useful.
+            typename = typename std::enable_if<
+                !std::is_member_pointer<T>::value>::type,
+            // Only accept types for which we can find a streaming operator via
+            // ADL (possibly involving implicit conversions).
+            typename = decltype(std::declval<std::ostream&>()
+                                << std::declval<const T&>())>
+  static void PrintValue(const T& value, ::std::ostream* os) {
+    // Call streaming operator found by ADL, possibly with implicit conversions
+    // of the arguments.
+    *os << value;
+  }
+};
+
+}  // namespace internal_stream_operator_without_lexical_name_lookup
+
+struct ProtobufPrinter {
+  // We print a protobuf using its ShortDebugString() when the string
+  // doesn't exceed this many characters; otherwise we print it using
+  // DebugString() for better readability.
+  static const size_t kProtobufOneLinerMaxLength = 50;
+
+  template <typename T,
+            typename = typename std::enable_if<
+                internal::HasDebugStringAndShortDebugString<T>::value>::type>
   static void PrintValue(const T& value, ::std::ostream* os) {
     std::string pretty_str = value.ShortDebugString();
     if (pretty_str.length() > kProtobufOneLinerMaxLength) {
@@ -8215,9 +5293,7 @@
   }
 };
 
-template <typename T>
-class TypeWithoutFormatter<T, kConvertibleToInteger> {
- public:
+struct ConvertibleToIntegerPrinter {
   // Since T has no << operator or PrintTo() but can be implicitly
   // converted to BiggestInt, we print it as a BiggestInt.
   //
@@ -8225,113 +5301,74 @@
   // case printing it as an integer is the desired behavior.  In case
   // T is not an enum, printing it as an integer is the best we can do
   // given that it has no user-defined printer.
-  static void PrintValue(const T& value, ::std::ostream* os) {
-    const internal::BiggestInt kBigInt = value;
-    *os << kBigInt;
+  static void PrintValue(internal::BiggestInt value, ::std::ostream* os) {
+    *os << value;
   }
 };
 
-#if GTEST_HAS_ABSL
-template <typename T>
-class TypeWithoutFormatter<T, kConvertibleToStringView> {
- public:
-  // Since T has neither operator<< nor PrintTo() but can be implicitly
-  // converted to absl::string_view, we print it as a absl::string_view.
-  //
-  // Note: the implementation is further below, as it depends on
-  // internal::PrintTo symbol which is defined later in the file.
-  static void PrintValue(const T& value, ::std::ostream* os);
+struct ConvertibleToStringViewPrinter {
+#if GTEST_INTERNAL_HAS_STRING_VIEW
+  static void PrintValue(internal::StringView value, ::std::ostream* os) {
+    internal::UniversalPrint(value, os);
+  }
+#endif
 };
-#endif
 
-// Prints the given value to the given ostream.  If the value is a
-// protocol message, its debug string is printed; if it's an enum or
-// of a type implicitly convertible to BiggestInt, it's printed as an
-// integer; otherwise the bytes in the value are printed.  This is
-// what UniversalPrinter<T>::Print() does when it knows nothing about
-// type T and T has neither << operator nor PrintTo().
-//
-// A user can override this behavior for a class type Foo by defining
-// a << operator in the namespace where Foo is defined.
-//
-// We put this operator in namespace 'internal2' instead of 'internal'
-// to simplify the implementation, as much code in 'internal' needs to
-// use << in STL, which would conflict with our own << were it defined
-// in 'internal'.
-//
-// Note that this operator<< takes a generic std::basic_ostream<Char,
-// CharTraits> type instead of the more restricted std::ostream.  If
-// we define it to take an std::ostream instead, we'll get an
-// "ambiguous overloads" compiler error when trying to print a type
-// Foo that supports streaming to std::basic_ostream<Char,
-// CharTraits>, as the compiler cannot tell whether
-// operator<<(std::ostream&, const T&) or
-// operator<<(std::basic_stream<Char, CharTraits>, const Foo&) is more
-// specific.
-template <typename Char, typename CharTraits, typename T>
-::std::basic_ostream<Char, CharTraits>& operator<<(
-    ::std::basic_ostream<Char, CharTraits>& os, const T& x) {
-  TypeWithoutFormatter<T, (internal::IsAProtocolMessage<T>::value
-                               ? kProtobuf
-                               : std::is_convertible<
-                                     const T&, internal::BiggestInt>::value
-                                     ? kConvertibleToInteger
-                                     :
-#if GTEST_HAS_ABSL
-                                     std::is_convertible<
-                                         const T&, absl::string_view>::value
-                                         ? kConvertibleToStringView
-                                         :
-#endif
-                                         kOtherType)>::PrintValue(x, &os);
-  return os;
-}
 
-}  // namespace internal2
-}  // namespace testing
+// Prints the given number of bytes in the given object to the given
+// ostream.
+GTEST_API_ void PrintBytesInObjectTo(const unsigned char* obj_bytes,
+                                     size_t count,
+                                     ::std::ostream* os);
+struct RawBytesPrinter {
+  // SFINAE on `sizeof` to make sure we have a complete type.
+  template <typename T, size_t = sizeof(T)>
+  static void PrintValue(const T& value, ::std::ostream* os) {
+    PrintBytesInObjectTo(
+        static_cast<const unsigned char*>(
+            // Load bearing cast to void* to support iOS
+            reinterpret_cast<const void*>(std::addressof(value))),
+        sizeof(value), os);
+  }
+};
 
-// This namespace MUST NOT BE NESTED IN ::testing, or the name look-up
-// magic needed for implementing UniversalPrinter won't work.
-namespace testing_internal {
+struct FallbackPrinter {
+  template <typename T>
+  static void PrintValue(const T&, ::std::ostream* os) {
+    *os << "(incomplete type)";
+  }
+};
 
-// Used to print a value that is not an STL-style container when the
-// user doesn't define PrintTo() for it.
+// Try every printer in order and return the first one that works.
+template <typename T, typename E, typename Printer, typename... Printers>
+struct FindFirstPrinter : FindFirstPrinter<T, E, Printers...> {};
+
+template <typename T, typename Printer, typename... Printers>
+struct FindFirstPrinter<
+    T, decltype(Printer::PrintValue(std::declval<const T&>(), nullptr)),
+    Printer, Printers...> {
+  using type = Printer;
+};
+
+// Select the best printer in the following order:
+//  - Print containers (they have begin/end/etc).
+//  - Print function pointers.
+//  - Print object pointers.
+//  - Use the stream operator, if available.
+//  - Print protocol buffers.
+//  - Print types convertible to BiggestInt.
+//  - Print types convertible to StringView, if available.
+//  - Fallback to printing the raw bytes of the object.
 template <typename T>
-void DefaultPrintNonContainerTo(const T& value, ::std::ostream* os) {
-  // With the following statement, during unqualified name lookup,
-  // testing::internal2::operator<< appears as if it was declared in
-  // the nearest enclosing namespace that contains both
-  // ::testing_internal and ::testing::internal2, i.e. the global
-  // namespace.  For more details, refer to the C++ Standard section
-  // 7.3.4-1 [namespace.udir].  This allows us to fall back onto
-  // testing::internal2::operator<< in case T doesn't come with a <<
-  // operator.
-  //
-  // We cannot write 'using ::testing::internal2::operator<<;', which
-  // gcc 3.3 fails to compile due to a compiler bug.
-  using namespace ::testing::internal2;  // NOLINT
-
-  // Assuming T is defined in namespace foo, in the next statement,
-  // the compiler will consider all of:
-  //
-  //   1. foo::operator<< (thanks to Koenig look-up),
-  //   2. ::operator<< (as the current namespace is enclosed in ::),
-  //   3. testing::internal2::operator<< (thanks to the using statement above).
-  //
-  // The operator<< whose type matches T best will be picked.
-  //
-  // We deliberately allow #2 to be a candidate, as sometimes it's
-  // impossible to define #1 (e.g. when foo is ::std, defining
-  // anything in it is undefined behavior unless you are a compiler
-  // vendor.).
-  *os << value;
+void PrintWithFallback(const T& value, ::std::ostream* os) {
+  using Printer = typename FindFirstPrinter<
+      T, void, ContainerPrinter, FunctionPointerPrinter, PointerPrinter,
+      internal_stream_operator_without_lexical_name_lookup::StreamPrinter,
+      ProtobufPrinter, ConvertibleToIntegerPrinter,
+      ConvertibleToStringViewPrinter, RawBytesPrinter, FallbackPrinter>::type;
+  Printer::PrintValue(value, os);
 }
 
-}  // namespace testing_internal
-
-namespace testing {
-namespace internal {
-
 // FormatForComparison<ToPrint, OtherOperand>::Format(value) formats a
 // value of type ToPrint that is an operand of a comparison assertion
 // (e.g. ASSERT_EQ).  OtherOperand is the type of the other operand in
@@ -8380,6 +5417,14 @@
 GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char);
 GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(wchar_t);
 GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const wchar_t);
+#ifdef __cpp_char8_t
+GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char8_t);
+GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char8_t);
+#endif
+GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char16_t);
+GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char16_t);
+GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char32_t);
+GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char32_t);
 
 #undef GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_
 
@@ -8397,16 +5442,14 @@
 
 GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::std::string);
 GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::std::string);
-
-#if GTEST_HAS_GLOBAL_STRING
-GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::string);
-GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::string);
+#ifdef __cpp_char8_t
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char8_t, ::std::u8string);
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char8_t, ::std::u8string);
 #endif
-
-#if GTEST_HAS_GLOBAL_WSTRING
-GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::wstring);
-GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::wstring);
-#endif
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char16_t, ::std::u16string);
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char16_t, ::std::u16string);
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char32_t, ::std::u32string);
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char32_t, ::std::u32string);
 
 #if GTEST_HAS_STD_WSTRING
 GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::std::wstring);
@@ -8439,85 +5482,6 @@
 template <typename T>
 class UniversalPrinter;
 
-template <typename T>
-void UniversalPrint(const T& value, ::std::ostream* os);
-
-enum DefaultPrinterType {
-  kPrintContainer,
-  kPrintPointer,
-  kPrintFunctionPointer,
-  kPrintOther,
-};
-template <DefaultPrinterType type> struct WrapPrinterType {};
-
-// Used to print an STL-style container when the user doesn't define
-// a PrintTo() for it.
-template <typename C>
-void DefaultPrintTo(WrapPrinterType<kPrintContainer> /* dummy */,
-                    const C& container, ::std::ostream* os) {
-  const size_t kMaxCount = 32;  // The maximum number of elements to print.
-  *os << '{';
-  size_t count = 0;
-  for (typename C::const_iterator it = container.begin();
-       it != container.end(); ++it, ++count) {
-    if (count > 0) {
-      *os << ',';
-      if (count == kMaxCount) {  // Enough has been printed.
-        *os << " ...";
-        break;
-      }
-    }
-    *os << ' ';
-    // We cannot call PrintTo(*it, os) here as PrintTo() doesn't
-    // handle *it being a native array.
-    internal::UniversalPrint(*it, os);
-  }
-
-  if (count > 0) {
-    *os << ' ';
-  }
-  *os << '}';
-}
-
-// Used to print a pointer that is neither a char pointer nor a member
-// pointer, when the user doesn't define PrintTo() for it.  (A member
-// variable pointer or member function pointer doesn't really point to
-// a location in the address space.  Their representation is
-// implementation-defined.  Therefore they will be printed as raw
-// bytes.)
-template <typename T>
-void DefaultPrintTo(WrapPrinterType<kPrintPointer> /* dummy */,
-                    T* p, ::std::ostream* os) {
-  if (p == nullptr) {
-    *os << "NULL";
-  } else {
-    // T is not a function type.  We just call << to print p,
-    // relying on ADL to pick up user-defined << for their pointer
-    // types, if any.
-    *os << p;
-  }
-}
-template <typename T>
-void DefaultPrintTo(WrapPrinterType<kPrintFunctionPointer> /* dummy */,
-                    T* p, ::std::ostream* os) {
-  if (p == nullptr) {
-    *os << "NULL";
-  } else {
-    // T is a function type, so '*os << p' doesn't do what we want
-    // (it just prints p as bool).  We want to print p as a const
-    // void*.
-    *os << reinterpret_cast<const void*>(p);
-  }
-}
-
-// Used to print a non-container, non-pointer value when the user
-// doesn't define PrintTo() for it.
-template <typename T>
-void DefaultPrintTo(WrapPrinterType<kPrintOther> /* dummy */,
-                    const T& value, ::std::ostream* os) {
-  ::testing_internal::DefaultPrintNonContainerTo(value, os);
-}
-
 // Prints the given value using the << operator if it has one;
 // otherwise prints the bytes in it.  This is what
 // UniversalPrinter<T>::Print() does when PrintTo() is not specialized
@@ -8531,36 +5495,7 @@
 // wants).
 template <typename T>
 void PrintTo(const T& value, ::std::ostream* os) {
-  // DefaultPrintTo() is overloaded.  The type of its first argument
-  // determines which version will be picked.
-  //
-  // Note that we check for container types here, prior to we check
-  // for protocol message types in our operator<<.  The rationale is:
-  //
-  // For protocol messages, we want to give people a chance to
-  // override Google Mock's format by defining a PrintTo() or
-  // operator<<.  For STL containers, other formats can be
-  // incompatible with Google Mock's format for the container
-  // elements; therefore we check for container types here to ensure
-  // that our format is used.
-  //
-  // Note that MSVC and clang-cl do allow an implicit conversion from
-  // pointer-to-function to pointer-to-object, but clang-cl warns on it.
-  // So don't use ImplicitlyConvertible if it can be helped since it will
-  // cause this warning, and use a separate overload of DefaultPrintTo for
-  // function pointers so that the `*os << p` in the object pointer overload
-  // doesn't cause that warning either.
-  DefaultPrintTo(
-      WrapPrinterType <
-                  (sizeof(IsContainerTest<T>(0)) == sizeof(IsContainer)) &&
-              !IsRecursiveContainer<T>::value
-          ? kPrintContainer
-          : !std::is_pointer<T>::value
-                ? kPrintOther
-                : std::is_function<typename std::remove_pointer<T>::type>::value
-                      ? kPrintFunctionPointer
-                      : kPrintPointer > (),
-      value, os);
+  internal::PrintWithFallback(value, os);
 }
 
 // The following list of PrintTo() overloads tells
@@ -8591,6 +5526,16 @@
 // is implemented as an unsigned type.
 GTEST_API_ void PrintTo(wchar_t wc, ::std::ostream* os);
 
+GTEST_API_ void PrintTo(char32_t c, ::std::ostream* os);
+inline void PrintTo(char16_t c, ::std::ostream* os) {
+  PrintTo(ImplicitCast_<char32_t>(c), os);
+}
+#ifdef __cpp_char8_t
+inline void PrintTo(char8_t c, ::std::ostream* os) {
+  PrintTo(ImplicitCast_<char32_t>(c), os);
+}
+#endif
+
 // Overloads for C strings.
 GTEST_API_ void PrintTo(const char* s, ::std::ostream* os);
 inline void PrintTo(char* s, ::std::ostream* os) {
@@ -8611,6 +5556,23 @@
 inline void PrintTo(unsigned char* s, ::std::ostream* os) {
   PrintTo(ImplicitCast_<const void*>(s), os);
 }
+#ifdef __cpp_char8_t
+// Overloads for u8 strings.
+GTEST_API_ void PrintTo(const char8_t* s, ::std::ostream* os);
+inline void PrintTo(char8_t* s, ::std::ostream* os) {
+  PrintTo(ImplicitCast_<const char8_t*>(s), os);
+}
+#endif
+// Overloads for u16 strings.
+GTEST_API_ void PrintTo(const char16_t* s, ::std::ostream* os);
+inline void PrintTo(char16_t* s, ::std::ostream* os) {
+  PrintTo(ImplicitCast_<const char16_t*>(s), os);
+}
+// Overloads for u32 strings.
+GTEST_API_ void PrintTo(const char32_t* s, ::std::ostream* os);
+inline void PrintTo(char32_t* s, ::std::ostream* os) {
+  PrintTo(ImplicitCast_<const char32_t*>(s), os);
+}
 
 // MSVC can be configured to define wchar_t as a typedef of unsigned
 // short.  It defines _NATIVE_WCHAR_T_DEFINED when wchar_t is a native
@@ -8639,27 +5601,33 @@
   }
 }
 
-// Overloads for ::string and ::std::string.
-#if GTEST_HAS_GLOBAL_STRING
-GTEST_API_ void PrintStringTo(const ::string&s, ::std::ostream* os);
-inline void PrintTo(const ::string& s, ::std::ostream* os) {
-  PrintStringTo(s, os);
-}
-#endif  // GTEST_HAS_GLOBAL_STRING
-
+// Overloads for ::std::string.
 GTEST_API_ void PrintStringTo(const ::std::string&s, ::std::ostream* os);
 inline void PrintTo(const ::std::string& s, ::std::ostream* os) {
   PrintStringTo(s, os);
 }
 
-// Overloads for ::wstring and ::std::wstring.
-#if GTEST_HAS_GLOBAL_WSTRING
-GTEST_API_ void PrintWideStringTo(const ::wstring&s, ::std::ostream* os);
-inline void PrintTo(const ::wstring& s, ::std::ostream* os) {
-  PrintWideStringTo(s, os);
+// Overloads for ::std::u8string
+#ifdef __cpp_char8_t
+GTEST_API_ void PrintU8StringTo(const ::std::u8string& s, ::std::ostream* os);
+inline void PrintTo(const ::std::u8string& s, ::std::ostream* os) {
+  PrintU8StringTo(s, os);
 }
-#endif  // GTEST_HAS_GLOBAL_WSTRING
+#endif
 
+// Overloads for ::std::u16string
+GTEST_API_ void PrintU16StringTo(const ::std::u16string& s, ::std::ostream* os);
+inline void PrintTo(const ::std::u16string& s, ::std::ostream* os) {
+  PrintU16StringTo(s, os);
+}
+
+// Overloads for ::std::u32string
+GTEST_API_ void PrintU32StringTo(const ::std::u32string& s, ::std::ostream* os);
+inline void PrintTo(const ::std::u32string& s, ::std::ostream* os) {
+  PrintU32StringTo(s, os);
+}
+
+// Overloads for ::std::wstring.
 #if GTEST_HAS_STD_WSTRING
 GTEST_API_ void PrintWideStringTo(const ::std::wstring&s, ::std::ostream* os);
 inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) {
@@ -8667,12 +5635,12 @@
 }
 #endif  // GTEST_HAS_STD_WSTRING
 
-#if GTEST_HAS_ABSL
-// Overload for absl::string_view.
-inline void PrintTo(absl::string_view sp, ::std::ostream* os) {
+#if GTEST_INTERNAL_HAS_STRING_VIEW
+// Overload for internal::StringView.
+inline void PrintTo(internal::StringView sp, ::std::ostream* os) {
   PrintTo(::std::string(sp), os);
 }
-#endif  // GTEST_HAS_ABSL
+#endif  // GTEST_INTERNAL_HAS_STRING_VIEW
 
 inline void PrintTo(std::nullptr_t, ::std::ostream* os) { *os << "(nullptr)"; }
 
@@ -8681,6 +5649,43 @@
   UniversalPrinter<T&>::Print(ref.get(), os);
 }
 
+inline const void* VoidifyPointer(const void* p) { return p; }
+inline const void* VoidifyPointer(volatile const void* p) {
+  return const_cast<const void*>(p);
+}
+
+template <typename T, typename Ptr>
+void PrintSmartPointer(const Ptr& ptr, std::ostream* os, char) {
+  if (ptr == nullptr) {
+    *os << "(nullptr)";
+  } else {
+    // We can't print the value. Just print the pointer..
+    *os << "(" << (VoidifyPointer)(ptr.get()) << ")";
+  }
+}
+template <typename T, typename Ptr,
+          typename = typename std::enable_if<!std::is_void<T>::value &&
+                                             !std::is_array<T>::value>::type>
+void PrintSmartPointer(const Ptr& ptr, std::ostream* os, int) {
+  if (ptr == nullptr) {
+    *os << "(nullptr)";
+  } else {
+    *os << "(ptr = " << (VoidifyPointer)(ptr.get()) << ", value = ";
+    UniversalPrinter<T>::Print(*ptr, os);
+    *os << ")";
+  }
+}
+
+template <typename T, typename D>
+void PrintTo(const std::unique_ptr<T, D>& ptr, std::ostream* os) {
+  (PrintSmartPointer<T>)(ptr, os, 0);
+}
+
+template <typename T>
+void PrintTo(const std::shared_ptr<T>& ptr, std::ostream* os) {
+  (PrintSmartPointer<T>)(ptr, os, 0);
+}
+
 // Helper function for printing a tuple.  T must be instantiated with
 // a tuple type.
 template <typename T>
@@ -8746,14 +5751,46 @@
   GTEST_DISABLE_MSC_WARNINGS_POP_()
 };
 
-#if GTEST_HAS_ABSL
+// Remove any const-qualifiers before passing a type to UniversalPrinter.
+template <typename T>
+class UniversalPrinter<const T> : public UniversalPrinter<T> {};
 
-// Printer for absl::optional
+#if GTEST_INTERNAL_HAS_ANY
+
+// Printer for std::any / absl::any
+
+template <>
+class UniversalPrinter<Any> {
+ public:
+  static void Print(const Any& value, ::std::ostream* os) {
+    if (value.has_value()) {
+      *os << "value of type " << GetTypeName(value);
+    } else {
+      *os << "no value";
+    }
+  }
+
+ private:
+  static std::string GetTypeName(const Any& value) {
+#if GTEST_HAS_RTTI
+    return internal::GetTypeName(value.type());
+#else
+    static_cast<void>(value);  // possibly unused
+    return "<unknown_type>";
+#endif  // GTEST_HAS_RTTI
+  }
+};
+
+#endif  // GTEST_INTERNAL_HAS_ANY
+
+#if GTEST_INTERNAL_HAS_OPTIONAL
+
+// Printer for std::optional / absl::optional
 
 template <typename T>
-class UniversalPrinter<::absl::optional<T>> {
+class UniversalPrinter<Optional<T>> {
  public:
-  static void Print(const ::absl::optional<T>& value, ::std::ostream* os) {
+  static void Print(const Optional<T>& value, ::std::ostream* os) {
     *os << '(';
     if (!value) {
       *os << "nullopt";
@@ -8764,14 +5801,22 @@
   }
 };
 
-// Printer for absl::variant
+#endif  // GTEST_INTERNAL_HAS_OPTIONAL
+
+#if GTEST_INTERNAL_HAS_VARIANT
+
+// Printer for std::variant / absl::variant
 
 template <typename... T>
-class UniversalPrinter<::absl::variant<T...>> {
+class UniversalPrinter<Variant<T...>> {
  public:
-  static void Print(const ::absl::variant<T...>& value, ::std::ostream* os) {
+  static void Print(const Variant<T...>& value, ::std::ostream* os) {
     *os << '(';
-    absl::visit(Visitor{os}, value);
+#if GTEST_HAS_ABSL
+    absl::visit(Visitor{os, value.index()}, value);
+#else
+    std::visit(Visitor{os, value.index()}, value);
+#endif  // GTEST_HAS_ABSL
     *os << ')';
   }
 
@@ -8779,14 +5824,16 @@
   struct Visitor {
     template <typename U>
     void operator()(const U& u) const {
-      *os << "'" << GetTypeName<U>() << "' with value ";
+      *os << "'" << GetTypeName<U>() << "(index = " << index
+          << ")' with value ";
       UniversalPrint(u, os);
     }
     ::std::ostream* os;
+    std::size_t index;
   };
 };
 
-#endif  // GTEST_HAS_ABSL
+#endif  // GTEST_INTERNAL_HAS_VARIANT
 
 // UniversalPrintArray(begin, len, os) prints an array of 'len'
 // elements, starting at address 'begin'.
@@ -8815,6 +5862,20 @@
 GTEST_API_ void UniversalPrintArray(
     const char* begin, size_t len, ::std::ostream* os);
 
+#ifdef __cpp_char8_t
+// This overload prints a (const) char8_t array compactly.
+GTEST_API_ void UniversalPrintArray(const char8_t* begin, size_t len,
+                                    ::std::ostream* os);
+#endif
+
+// This overload prints a (const) char16_t array compactly.
+GTEST_API_ void UniversalPrintArray(const char16_t* begin, size_t len,
+                                    ::std::ostream* os);
+
+// This overload prints a (const) char32_t array compactly.
+GTEST_API_ void UniversalPrintArray(const char32_t* begin, size_t len,
+                                    ::std::ostream* os);
+
 // This overload prints a (const) wchar_t array compactly.
 GTEST_API_ void UniversalPrintArray(
     const wchar_t* begin, size_t len, ::std::ostream* os);
@@ -8887,12 +5948,55 @@
   }
 };
 template <>
-class UniversalTersePrinter<char*> {
+class UniversalTersePrinter<char*> : public UniversalTersePrinter<const char*> {
+};
+
+#ifdef __cpp_char8_t
+template <>
+class UniversalTersePrinter<const char8_t*> {
  public:
-  static void Print(char* str, ::std::ostream* os) {
-    UniversalTersePrinter<const char*>::Print(str, os);
+  static void Print(const char8_t* str, ::std::ostream* os) {
+    if (str == nullptr) {
+      *os << "NULL";
+    } else {
+      UniversalPrint(::std::u8string(str), os);
+    }
   }
 };
+template <>
+class UniversalTersePrinter<char8_t*>
+    : public UniversalTersePrinter<const char8_t*> {};
+#endif
+
+template <>
+class UniversalTersePrinter<const char16_t*> {
+ public:
+  static void Print(const char16_t* str, ::std::ostream* os) {
+    if (str == nullptr) {
+      *os << "NULL";
+    } else {
+      UniversalPrint(::std::u16string(str), os);
+    }
+  }
+};
+template <>
+class UniversalTersePrinter<char16_t*>
+    : public UniversalTersePrinter<const char16_t*> {};
+
+template <>
+class UniversalTersePrinter<const char32_t*> {
+ public:
+  static void Print(const char32_t* str, ::std::ostream* os) {
+    if (str == nullptr) {
+      *os << "NULL";
+    } else {
+      UniversalPrint(::std::u32string(str), os);
+    }
+  }
+};
+template <>
+class UniversalTersePrinter<char32_t*>
+    : public UniversalTersePrinter<const char32_t*> {};
 
 #if GTEST_HAS_STD_WSTRING
 template <>
@@ -8965,16 +6069,6 @@
 
 }  // namespace internal
 
-#if GTEST_HAS_ABSL
-namespace internal2 {
-template <typename T>
-void TypeWithoutFormatter<T, kConvertibleToStringView>::PrintValue(
-    const T& value, ::std::ostream* os) {
-  internal::PrintTo(absl::string_view(value), os);
-}
-}  // namespace internal2
-#endif
-
 template <typename T>
 ::std::string PrintToString(const T& value) {
   ::std::stringstream ss;
@@ -9025,35 +6119,38 @@
 //
 // ** Custom implementation starts here **
 
-#ifndef GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_
-#define GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_
+#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_
+#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_
 
-#endif  // GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_
+#endif  // GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_
 
-#endif  // GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_
+#endif  // GOOGLETEST_INCLUDE_GTEST_GTEST_PRINTERS_H_
+
+// MSVC warning C5046 is new as of VS2017 version 15.8.
+#if defined(_MSC_VER) && _MSC_VER >= 1915
+#define GTEST_MAYBE_5046_ 5046
+#else
+#define GTEST_MAYBE_5046_
+#endif
 
 GTEST_DISABLE_MSC_WARNINGS_PUSH_(
-    4251 5046 /* class A needs to have dll-interface to be used by clients of
-                 class B */
+    4251 GTEST_MAYBE_5046_ /* class A needs to have dll-interface to be used by
+                              clients of class B */
     /* Symbol involving type with internal linkage not defined */)
 
 namespace testing {
 
 // To implement a matcher Foo for type T, define:
-//   1. a class FooMatcherImpl that implements the
-//      MatcherInterface<T> interface, and
+//   1. a class FooMatcherMatcher that implements the matcher interface:
+//     using is_gtest_matcher = void;
+//     bool MatchAndExplain(const T&, std::ostream*);
+//       (MatchResultListener* can also be used instead of std::ostream*)
+//     void DescribeTo(std::ostream*);
+//     void DescribeNegationTo(std::ostream*);
+//
 //   2. a factory function that creates a Matcher<T> object from a
-//      FooMatcherImpl*.
-//
-// The two-level delegation design makes it possible to allow a user
-// to write "v" instead of "Eq(v)" where a Matcher is expected, which
-// is impossible if we pass matchers by pointers.  It also eases
-// ownership management as Matcher objects can now be copied like
-// plain values.
+//      FooMatcherMatcher.
 
-// MatchResultListener is an abstract class.  Its << operator can be
-// used by a matcher to explain why a value matches or doesn't match.
-//
 class MatchResultListener {
  public:
   // Creates a listener object with the given underlying ostream.  The
@@ -9073,8 +6170,8 @@
   // Returns the underlying ostream.
   ::std::ostream* stream() { return stream_; }
 
-  // Returns true iff the listener is interested in an explanation of
-  // the match result.  A matcher's MatchAndExplain() method can use
+  // Returns true if and only if the listener is interested in an explanation
+  // of the match result.  A matcher's MatchAndExplain() method can use
   // this information to avoid generating the explanation when no one
   // intends to hear it.
   bool IsInterested() const { return stream_ != nullptr; }
@@ -9090,7 +6187,7 @@
 
 // An instance of a subclass of this knows how to describe itself as a
 // matcher.
-class MatcherDescriberInterface {
+class GTEST_API_ MatcherDescriberInterface {
  public:
   virtual ~MatcherDescriberInterface() {}
 
@@ -9118,8 +6215,8 @@
 template <typename T>
 class MatcherInterface : public MatcherDescriberInterface {
  public:
-  // Returns true iff the matcher matches x; also explains the match
-  // result to 'listener' if necessary (see the next paragraph), in
+  // Returns true if and only if the matcher matches x; also explains the
+  // match result to 'listener' if necessary (see the next paragraph), in
   // the form of a non-restrictive relative clause ("which ...",
   // "whose ...", etc) that describes x.  For example, the
   // MatchAndExplain() method of the Pointee(...) matcher should
@@ -9158,31 +6255,6 @@
 
 namespace internal {
 
-// Converts a MatcherInterface<T> to a MatcherInterface<const T&>.
-template <typename T>
-class MatcherInterfaceAdapter : public MatcherInterface<const T&> {
- public:
-  explicit MatcherInterfaceAdapter(const MatcherInterface<T>* impl)
-      : impl_(impl) {}
-  ~MatcherInterfaceAdapter() override { delete impl_; }
-
-  void DescribeTo(::std::ostream* os) const override { impl_->DescribeTo(os); }
-
-  void DescribeNegationTo(::std::ostream* os) const override {
-    impl_->DescribeNegationTo(os);
-  }
-
-  bool MatchAndExplain(const T& x,
-                       MatchResultListener* listener) const override {
-    return impl_->MatchAndExplain(x, listener);
-  }
-
- private:
-  const MatcherInterface<T>* const impl_;
-
-  GTEST_DISALLOW_COPY_AND_ASSIGN_(MatcherInterfaceAdapter);
-};
-
 struct AnyEq {
   template <typename A, typename B>
   bool operator()(const A& a, const B& b) const { return a == b; }
@@ -9229,30 +6301,53 @@
   GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamMatchResultListener);
 };
 
+struct SharedPayloadBase {
+  std::atomic<int> ref{1};
+  void Ref() { ref.fetch_add(1, std::memory_order_relaxed); }
+  bool Unref() { return ref.fetch_sub(1, std::memory_order_acq_rel) == 1; }
+};
+
+template <typename T>
+struct SharedPayload : SharedPayloadBase {
+  explicit SharedPayload(const T& v) : value(v) {}
+  explicit SharedPayload(T&& v) : value(std::move(v)) {}
+
+  static void Destroy(SharedPayloadBase* shared) {
+    delete static_cast<SharedPayload*>(shared);
+  }
+
+  T value;
+};
+
 // An internal class for implementing Matcher<T>, which will derive
 // from it.  We put functionalities common to all Matcher<T>
 // specializations here to avoid code duplication.
 template <typename T>
-class MatcherBase {
+class MatcherBase : private MatcherDescriberInterface {
  public:
-  // Returns true iff the matcher matches x; also explains the match
-  // result to 'listener'.
+  // Returns true if and only if the matcher matches x; also explains the
+  // match result to 'listener'.
   bool MatchAndExplain(const T& x, MatchResultListener* listener) const {
-    return impl_->MatchAndExplain(x, listener);
+    GTEST_CHECK_(vtable_ != nullptr);
+    return vtable_->match_and_explain(*this, x, listener);
   }
 
-  // Returns true iff this matcher matches x.
+  // Returns true if and only if this matcher matches x.
   bool Matches(const T& x) const {
     DummyMatchResultListener dummy;
     return MatchAndExplain(x, &dummy);
   }
 
   // Describes this matcher to an ostream.
-  void DescribeTo(::std::ostream* os) const { impl_->DescribeTo(os); }
+  void DescribeTo(::std::ostream* os) const final {
+    GTEST_CHECK_(vtable_ != nullptr);
+    vtable_->describe(*this, os, false);
+  }
 
   // Describes the negation of this matcher to an ostream.
-  void DescribeNegationTo(::std::ostream* os) const {
-    impl_->DescribeNegationTo(os);
+  void DescribeNegationTo(::std::ostream* os) const final {
+    GTEST_CHECK_(vtable_ != nullptr);
+    vtable_->describe(*this, os, true);
   }
 
   // Explains why x matches, or doesn't match, the matcher.
@@ -9265,31 +6360,194 @@
   // of the describer, which is only guaranteed to be alive when
   // this matcher object is alive.
   const MatcherDescriberInterface* GetDescriber() const {
-    return impl_.get();
+    if (vtable_ == nullptr) return nullptr;
+    return vtable_->get_describer(*this);
   }
 
  protected:
-  MatcherBase() {}
+  MatcherBase() : vtable_(nullptr) {}
 
   // Constructs a matcher from its implementation.
-  explicit MatcherBase(const MatcherInterface<const T&>* impl) : impl_(impl) {}
-
   template <typename U>
-  explicit MatcherBase(
-      const MatcherInterface<U>* impl,
-      typename internal::EnableIf<
-          !internal::IsSame<U, const U&>::value>::type* = nullptr)
-      : impl_(new internal::MatcherInterfaceAdapter<U>(impl)) {}
+  explicit MatcherBase(const MatcherInterface<U>* impl) {
+    Init(impl);
+  }
 
-  MatcherBase(const MatcherBase&) = default;
-  MatcherBase& operator=(const MatcherBase&) = default;
-  MatcherBase(MatcherBase&&) = default;
-  MatcherBase& operator=(MatcherBase&&) = default;
+  template <typename M, typename = typename std::remove_reference<
+                            M>::type::is_gtest_matcher>
+  MatcherBase(M&& m) {  // NOLINT
+    Init(std::forward<M>(m));
+  }
 
-  virtual ~MatcherBase() {}
+  MatcherBase(const MatcherBase& other)
+      : vtable_(other.vtable_), buffer_(other.buffer_) {
+    if (IsShared()) buffer_.shared->Ref();
+  }
+
+  MatcherBase& operator=(const MatcherBase& other) {
+    if (this == &other) return *this;
+    Destroy();
+    vtable_ = other.vtable_;
+    buffer_ = other.buffer_;
+    if (IsShared()) buffer_.shared->Ref();
+    return *this;
+  }
+
+  MatcherBase(MatcherBase&& other)
+      : vtable_(other.vtable_), buffer_(other.buffer_) {
+    other.vtable_ = nullptr;
+  }
+
+  MatcherBase& operator=(MatcherBase&& other) {
+    if (this == &other) return *this;
+    Destroy();
+    vtable_ = other.vtable_;
+    buffer_ = other.buffer_;
+    other.vtable_ = nullptr;
+    return *this;
+  }
+
+  ~MatcherBase() override { Destroy(); }
 
  private:
-  std::shared_ptr<const MatcherInterface<const T&>> impl_;
+  struct VTable {
+    bool (*match_and_explain)(const MatcherBase&, const T&,
+                              MatchResultListener*);
+    void (*describe)(const MatcherBase&, std::ostream*, bool negation);
+    // Returns the captured object if it implements the interface, otherwise
+    // returns the MatcherBase itself.
+    const MatcherDescriberInterface* (*get_describer)(const MatcherBase&);
+    // Called on shared instances when the reference count reaches 0.
+    void (*shared_destroy)(SharedPayloadBase*);
+  };
+
+  bool IsShared() const {
+    return vtable_ != nullptr && vtable_->shared_destroy != nullptr;
+  }
+
+  // If the implementation uses a listener, call that.
+  template <typename P>
+  static auto MatchAndExplainImpl(const MatcherBase& m, const T& value,
+                                  MatchResultListener* listener)
+      -> decltype(P::Get(m).MatchAndExplain(value, listener->stream())) {
+    return P::Get(m).MatchAndExplain(value, listener->stream());
+  }
+
+  template <typename P>
+  static auto MatchAndExplainImpl(const MatcherBase& m, const T& value,
+                                  MatchResultListener* listener)
+      -> decltype(P::Get(m).MatchAndExplain(value, listener)) {
+    return P::Get(m).MatchAndExplain(value, listener);
+  }
+
+  template <typename P>
+  static void DescribeImpl(const MatcherBase& m, std::ostream* os,
+                           bool negation) {
+    if (negation) {
+      P::Get(m).DescribeNegationTo(os);
+    } else {
+      P::Get(m).DescribeTo(os);
+    }
+  }
+
+  template <typename P>
+  static const MatcherDescriberInterface* GetDescriberImpl(
+      const MatcherBase& m) {
+    // If the impl is a MatcherDescriberInterface, then return it.
+    // Otherwise use MatcherBase itself.
+    // This allows us to implement the GetDescriber() function without support
+    // from the impl, but some users really want to get their impl back when
+    // they call GetDescriber().
+    // We use std::get on a tuple as a workaround of not having `if constexpr`.
+    return std::get<(
+        std::is_convertible<decltype(&P::Get(m)),
+                            const MatcherDescriberInterface*>::value
+            ? 1
+            : 0)>(std::make_tuple(&m, &P::Get(m)));
+  }
+
+  template <typename P>
+  const VTable* GetVTable() {
+    static constexpr VTable kVTable = {&MatchAndExplainImpl<P>,
+                                       &DescribeImpl<P>, &GetDescriberImpl<P>,
+                                       P::shared_destroy};
+    return &kVTable;
+  }
+
+  union Buffer {
+    // Add some types to give Buffer some common alignment/size use cases.
+    void* ptr;
+    double d;
+    int64_t i;
+    // And add one for the out-of-line cases.
+    SharedPayloadBase* shared;
+  };
+
+  void Destroy() {
+    if (IsShared() && buffer_.shared->Unref()) {
+      vtable_->shared_destroy(buffer_.shared);
+    }
+  }
+
+  template <typename M>
+  static constexpr bool IsInlined() {
+    return sizeof(M) <= sizeof(Buffer) && alignof(M) <= alignof(Buffer) &&
+           std::is_trivially_copy_constructible<M>::value &&
+           std::is_trivially_destructible<M>::value;
+  }
+
+  template <typename M, bool = MatcherBase::IsInlined<M>()>
+  struct ValuePolicy {
+    static const M& Get(const MatcherBase& m) {
+      // When inlined along with Init, need to be explicit to avoid violating
+      // strict aliasing rules.
+      const M *ptr = static_cast<const M*>(
+          static_cast<const void*>(&m.buffer_));
+      return *ptr;
+    }
+    static void Init(MatcherBase& m, M impl) {
+      ::new (static_cast<void*>(&m.buffer_)) M(impl);
+    }
+    static constexpr auto shared_destroy = nullptr;
+  };
+
+  template <typename M>
+  struct ValuePolicy<M, false> {
+    using Shared = SharedPayload<M>;
+    static const M& Get(const MatcherBase& m) {
+      return static_cast<Shared*>(m.buffer_.shared)->value;
+    }
+    template <typename Arg>
+    static void Init(MatcherBase& m, Arg&& arg) {
+      m.buffer_.shared = new Shared(std::forward<Arg>(arg));
+    }
+    static constexpr auto shared_destroy = &Shared::Destroy;
+  };
+
+  template <typename U, bool B>
+  struct ValuePolicy<const MatcherInterface<U>*, B> {
+    using M = const MatcherInterface<U>;
+    using Shared = SharedPayload<std::unique_ptr<M>>;
+    static const M& Get(const MatcherBase& m) {
+      return *static_cast<Shared*>(m.buffer_.shared)->value;
+    }
+    static void Init(MatcherBase& m, M* impl) {
+      m.buffer_.shared = new Shared(std::unique_ptr<M>(impl));
+    }
+
+    static constexpr auto shared_destroy = &Shared::Destroy;
+  };
+
+  template <typename M>
+  void Init(M&& m) {
+    using MM = typename std::decay<M>::type;
+    using Policy = ValuePolicy<MM>;
+    vtable_ = GetVTable<Policy>();
+    Policy::Init(*this, std::forward<M>(m));
+  }
+
+  const VTable* vtable_;
+  Buffer buffer_;
 };
 
 }  // namespace internal
@@ -9311,11 +6569,16 @@
       : internal::MatcherBase<T>(impl) {}
 
   template <typename U>
-  explicit Matcher(const MatcherInterface<U>* impl,
-                   typename internal::EnableIf<
-                       !internal::IsSame<U, const U&>::value>::type* = nullptr)
+  explicit Matcher(
+      const MatcherInterface<U>* impl,
+      typename std::enable_if<!std::is_same<U, const U&>::value>::type* =
+          nullptr)
       : internal::MatcherBase<T>(impl) {}
 
+  template <typename M, typename = typename std::remove_reference<
+                            M>::type::is_gtest_matcher>
+  Matcher(M&& m) : internal::MatcherBase<T>(std::forward<M>(m)) {}  // NOLINT
+
   // Implicit constructor here allows people to write
   // EXPECT_CALL(foo, Bar(5)) instead of EXPECT_CALL(foo, Bar(Eq(5))) sometimes
   Matcher(T value);  // NOLINT
@@ -9333,16 +6596,15 @@
   explicit Matcher(const MatcherInterface<const std::string&>* impl)
       : internal::MatcherBase<const std::string&>(impl) {}
 
+  template <typename M, typename = typename std::remove_reference<
+                            M>::type::is_gtest_matcher>
+  Matcher(M&& m)  // NOLINT
+      : internal::MatcherBase<const std::string&>(std::forward<M>(m)) {}
+
   // Allows the user to write str instead of Eq(str) sometimes, where
   // str is a std::string object.
   Matcher(const std::string& s);  // NOLINT
 
-#if GTEST_HAS_GLOBAL_STRING
-  // Allows the user to write str instead of Eq(str) sometimes, where
-  // str is a ::string object.
-  Matcher(const ::string& s);  // NOLINT
-#endif                         // GTEST_HAS_GLOBAL_STRING
-
   // Allows the user to write "foo" instead of Eq("foo") sometimes.
   Matcher(const char* s);  // NOLINT
 };
@@ -9358,127 +6620,76 @@
   explicit Matcher(const MatcherInterface<std::string>* impl)
       : internal::MatcherBase<std::string>(impl) {}
 
+  template <typename M, typename = typename std::remove_reference<
+                            M>::type::is_gtest_matcher>
+  Matcher(M&& m)  // NOLINT
+      : internal::MatcherBase<std::string>(std::forward<M>(m)) {}
+
   // Allows the user to write str instead of Eq(str) sometimes, where
   // str is a string object.
   Matcher(const std::string& s);  // NOLINT
 
-#if GTEST_HAS_GLOBAL_STRING
-  // Allows the user to write str instead of Eq(str) sometimes, where
-  // str is a ::string object.
-  Matcher(const ::string& s);  // NOLINT
-#endif                         // GTEST_HAS_GLOBAL_STRING
-
   // Allows the user to write "foo" instead of Eq("foo") sometimes.
   Matcher(const char* s);  // NOLINT
 };
 
-#if GTEST_HAS_GLOBAL_STRING
-// The following two specializations allow the user to write str
-// instead of Eq(str) and "foo" instead of Eq("foo") when a ::string
-// matcher is expected.
-template <>
-class GTEST_API_ Matcher<const ::string&>
-    : public internal::MatcherBase<const ::string&> {
- public:
-  Matcher() {}
-
-  explicit Matcher(const MatcherInterface<const ::string&>* impl)
-      : internal::MatcherBase<const ::string&>(impl) {}
-
-  // Allows the user to write str instead of Eq(str) sometimes, where
-  // str is a std::string object.
-  Matcher(const std::string& s);  // NOLINT
-
-  // Allows the user to write str instead of Eq(str) sometimes, where
-  // str is a ::string object.
-  Matcher(const ::string& s);  // NOLINT
-
-  // Allows the user to write "foo" instead of Eq("foo") sometimes.
-  Matcher(const char* s);  // NOLINT
-};
-
-template <>
-class GTEST_API_ Matcher< ::string>
-    : public internal::MatcherBase< ::string> {
- public:
-  Matcher() {}
-
-  explicit Matcher(const MatcherInterface<const ::string&>* impl)
-      : internal::MatcherBase< ::string>(impl) {}
-  explicit Matcher(const MatcherInterface< ::string>* impl)
-      : internal::MatcherBase< ::string>(impl) {}
-
-  // Allows the user to write str instead of Eq(str) sometimes, where
-  // str is a std::string object.
-  Matcher(const std::string& s);  // NOLINT
-
-  // Allows the user to write str instead of Eq(str) sometimes, where
-  // str is a ::string object.
-  Matcher(const ::string& s);  // NOLINT
-
-  // Allows the user to write "foo" instead of Eq("foo") sometimes.
-  Matcher(const char* s);  // NOLINT
-};
-#endif  // GTEST_HAS_GLOBAL_STRING
-
-#if GTEST_HAS_ABSL
+#if GTEST_INTERNAL_HAS_STRING_VIEW
 // The following two specializations allow the user to write str
 // instead of Eq(str) and "foo" instead of Eq("foo") when a absl::string_view
 // matcher is expected.
 template <>
-class GTEST_API_ Matcher<const absl::string_view&>
-    : public internal::MatcherBase<const absl::string_view&> {
+class GTEST_API_ Matcher<const internal::StringView&>
+    : public internal::MatcherBase<const internal::StringView&> {
  public:
   Matcher() {}
 
-  explicit Matcher(const MatcherInterface<const absl::string_view&>* impl)
-      : internal::MatcherBase<const absl::string_view&>(impl) {}
+  explicit Matcher(const MatcherInterface<const internal::StringView&>* impl)
+      : internal::MatcherBase<const internal::StringView&>(impl) {}
+
+  template <typename M, typename = typename std::remove_reference<
+                            M>::type::is_gtest_matcher>
+  Matcher(M&& m)  // NOLINT
+      : internal::MatcherBase<const internal::StringView&>(std::forward<M>(m)) {
+  }
 
   // Allows the user to write str instead of Eq(str) sometimes, where
   // str is a std::string object.
   Matcher(const std::string& s);  // NOLINT
 
-#if GTEST_HAS_GLOBAL_STRING
-  // Allows the user to write str instead of Eq(str) sometimes, where
-  // str is a ::string object.
-  Matcher(const ::string& s);  // NOLINT
-#endif                         // GTEST_HAS_GLOBAL_STRING
-
   // Allows the user to write "foo" instead of Eq("foo") sometimes.
   Matcher(const char* s);  // NOLINT
 
-  // Allows the user to pass absl::string_views directly.
-  Matcher(absl::string_view s);  // NOLINT
+  // Allows the user to pass absl::string_views or std::string_views directly.
+  Matcher(internal::StringView s);  // NOLINT
 };
 
 template <>
-class GTEST_API_ Matcher<absl::string_view>
-    : public internal::MatcherBase<absl::string_view> {
+class GTEST_API_ Matcher<internal::StringView>
+    : public internal::MatcherBase<internal::StringView> {
  public:
   Matcher() {}
 
-  explicit Matcher(const MatcherInterface<const absl::string_view&>* impl)
-      : internal::MatcherBase<absl::string_view>(impl) {}
-  explicit Matcher(const MatcherInterface<absl::string_view>* impl)
-      : internal::MatcherBase<absl::string_view>(impl) {}
+  explicit Matcher(const MatcherInterface<const internal::StringView&>* impl)
+      : internal::MatcherBase<internal::StringView>(impl) {}
+  explicit Matcher(const MatcherInterface<internal::StringView>* impl)
+      : internal::MatcherBase<internal::StringView>(impl) {}
+
+  template <typename M, typename = typename std::remove_reference<
+                            M>::type::is_gtest_matcher>
+  Matcher(M&& m)  // NOLINT
+      : internal::MatcherBase<internal::StringView>(std::forward<M>(m)) {}
 
   // Allows the user to write str instead of Eq(str) sometimes, where
   // str is a std::string object.
   Matcher(const std::string& s);  // NOLINT
 
-#if GTEST_HAS_GLOBAL_STRING
-  // Allows the user to write str instead of Eq(str) sometimes, where
-  // str is a ::string object.
-  Matcher(const ::string& s);  // NOLINT
-#endif                         // GTEST_HAS_GLOBAL_STRING
-
   // Allows the user to write "foo" instead of Eq("foo") sometimes.
   Matcher(const char* s);  // NOLINT
 
-  // Allows the user to pass absl::string_views directly.
-  Matcher(absl::string_view s);  // NOLINT
+  // Allows the user to pass absl::string_views or std::string_views directly.
+  Matcher(internal::StringView s);  // NOLINT
 };
-#endif  // GTEST_HAS_ABSL
+#endif  // GTEST_INTERNAL_HAS_STRING_VIEW
 
 // Prints a matcher in a human-readable format.
 template <typename T>
@@ -9523,13 +6734,13 @@
    public:
     explicit MonomorphicImpl(const Impl& impl) : impl_(impl) {}
 
-    virtual void DescribeTo(::std::ostream* os) const { impl_.DescribeTo(os); }
+    void DescribeTo(::std::ostream* os) const override { impl_.DescribeTo(os); }
 
-    virtual void DescribeNegationTo(::std::ostream* os) const {
+    void DescribeNegationTo(::std::ostream* os) const override {
       impl_.DescribeNegationTo(os);
     }
 
-    virtual bool MatchAndExplain(T x, MatchResultListener* listener) const {
+    bool MatchAndExplain(T x, MatchResultListener* listener) const override {
       return impl_.MatchAndExplain(x, listener);
     }
 
@@ -9578,37 +6789,32 @@
 class ComparisonBase {
  public:
   explicit ComparisonBase(const Rhs& rhs) : rhs_(rhs) {}
+
+  using is_gtest_matcher = void;
+
   template <typename Lhs>
-  operator Matcher<Lhs>() const {
-    return Matcher<Lhs>(new Impl<const Lhs&>(rhs_));
+  bool MatchAndExplain(const Lhs& lhs, std::ostream*) const {
+    return Op()(lhs, Unwrap(rhs_));
+  }
+  void DescribeTo(std::ostream* os) const {
+    *os << D::Desc() << " ";
+    UniversalPrint(Unwrap(rhs_), os);
+  }
+  void DescribeNegationTo(std::ostream* os) const {
+    *os << D::NegatedDesc() << " ";
+    UniversalPrint(Unwrap(rhs_), os);
   }
 
  private:
   template <typename T>
-  static const T& Unwrap(const T& v) { return v; }
+  static const T& Unwrap(const T& v) {
+    return v;
+  }
   template <typename T>
-  static const T& Unwrap(std::reference_wrapper<T> v) { return v; }
+  static const T& Unwrap(std::reference_wrapper<T> v) {
+    return v;
+  }
 
-  template <typename Lhs, typename = Rhs>
-  class Impl : public MatcherInterface<Lhs> {
-   public:
-    explicit Impl(const Rhs& rhs) : rhs_(rhs) {}
-    bool MatchAndExplain(Lhs lhs,
-                         MatchResultListener* /* listener */) const override {
-      return Op()(lhs, Unwrap(rhs_));
-    }
-    void DescribeTo(::std::ostream* os) const override {
-      *os << D::Desc() << " ";
-      UniversalPrint(Unwrap(rhs_), os);
-    }
-    void DescribeNegationTo(::std::ostream* os) const override {
-      *os << D::NegatedDesc() <<  " ";
-      UniversalPrint(Unwrap(rhs_), os);
-    }
-
-   private:
-    Rhs rhs_;
-  };
   Rhs rhs_;
 };
 
@@ -9661,6 +6867,10 @@
   static const char* NegatedDesc() { return "isn't >="; }
 };
 
+template <typename T, typename = typename std::enable_if<
+                          std::is_constructible<std::string, T>::value>::type>
+using StringLike = T;
+
 // Implements polymorphic matchers MatchesRegex(regex) and
 // ContainsRegex(regex), which can be used as a Matcher<T> as long as
 // T can be converted to a string.
@@ -9669,12 +6879,12 @@
   MatchesRegexMatcher(const RE* regex, bool full_match)
       : regex_(regex), full_match_(full_match) {}
 
-#if GTEST_HAS_ABSL
-  bool MatchAndExplain(const absl::string_view& s,
+#if GTEST_INTERNAL_HAS_STRING_VIEW
+  bool MatchAndExplain(const internal::StringView& s,
                        MatchResultListener* listener) const {
-    return MatchAndExplain(string(s), listener);
+    return MatchAndExplain(std::string(s), listener);
   }
-#endif  // GTEST_HAS_ABSL
+#endif  // GTEST_INTERNAL_HAS_STRING_VIEW
 
   // Accepts pointer types, particularly:
   //   const char*
@@ -9721,9 +6931,10 @@
     const internal::RE* regex) {
   return MakePolymorphicMatcher(internal::MatchesRegexMatcher(regex, true));
 }
-inline PolymorphicMatcher<internal::MatchesRegexMatcher> MatchesRegex(
-    const std::string& regex) {
-  return MatchesRegex(new internal::RE(regex));
+template <typename T = std::string>
+PolymorphicMatcher<internal::MatchesRegexMatcher> MatchesRegex(
+    const internal::StringLike<T>& regex) {
+  return MatchesRegex(new internal::RE(std::string(regex)));
 }
 
 // Matches a string that contains regular expression 'regex'.
@@ -9732,9 +6943,10 @@
     const internal::RE* regex) {
   return MakePolymorphicMatcher(internal::MatchesRegexMatcher(regex, false));
 }
-inline PolymorphicMatcher<internal::MatchesRegexMatcher> ContainsRegex(
-    const std::string& regex) {
-  return ContainsRegex(new internal::RE(regex));
+template <typename T = std::string>
+PolymorphicMatcher<internal::MatchesRegexMatcher> ContainsRegex(
+    const internal::StringLike<T>& regex) {
+  return ContainsRegex(new internal::RE(std::string(regex)));
 }
 
 // Creates a polymorphic matcher that matches anything equal to x.
@@ -9796,7 +7008,7 @@
 
 GTEST_DISABLE_MSC_WARNINGS_POP_()  //  4251 5046
 
-#endif  // GTEST_INCLUDE_GTEST_GTEST_MATCHERS_H_
+#endif  // GOOGLETEST_INCLUDE_GTEST_GTEST_MATCHERS_H_
 
 #include <stdio.h>
 #include <memory>
@@ -9935,12 +7147,6 @@
     const ::std::string& regex) {
   return ContainsRegex(regex);
 }
-#if GTEST_HAS_GLOBAL_STRING
-inline Matcher<const ::std::string&> MakeDeathTestMatcher(
-    const ::string& regex) {
-  return ContainsRegex(regex);
-}
-#endif
 
 // If a Matcher<const ::std::string&> is passed to EXPECT_DEATH (etc.), it's
 // used directly.
@@ -10066,7 +7272,7 @@
 }  // namespace internal
 }  // namespace testing
 
-#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
+#endif  // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
 
 namespace testing {
 
@@ -10125,6 +7331,10 @@
 //
 //   ASSERT_EXIT(client.HangUpServer(), KilledBySIGHUP, "Hanging up!");
 //
+// The final parameter to each of these macros is a matcher applied to any data
+// the sub-process wrote to stderr.  For compatibility with existing tests, a
+// bare string is interpreted as a regular expression matcher.
+//
 // On the regular expressions used in death tests:
 //
 //   GOOGLETEST_CM0005 DO NOT DELETE
@@ -10190,27 +7400,27 @@
 //   directory in PATH.
 //
 
-// Asserts that a given statement causes the program to exit, with an
-// integer exit status that satisfies predicate, and emitting error output
-// that matches regex.
-# define ASSERT_EXIT(statement, predicate, regex) \
-    GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_FATAL_FAILURE_)
+// Asserts that a given `statement` causes the program to exit, with an
+// integer exit status that satisfies `predicate`, and emitting error output
+// that matches `matcher`.
+# define ASSERT_EXIT(statement, predicate, matcher) \
+    GTEST_DEATH_TEST_(statement, predicate, matcher, GTEST_FATAL_FAILURE_)
 
-// Like ASSERT_EXIT, but continues on to successive tests in the
+// Like `ASSERT_EXIT`, but continues on to successive tests in the
 // test suite, if any:
-# define EXPECT_EXIT(statement, predicate, regex) \
-    GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_NONFATAL_FAILURE_)
+# define EXPECT_EXIT(statement, predicate, matcher) \
+    GTEST_DEATH_TEST_(statement, predicate, matcher, GTEST_NONFATAL_FAILURE_)
 
-// Asserts that a given statement causes the program to exit, either by
+// Asserts that a given `statement` causes the program to exit, either by
 // explicitly exiting with a nonzero exit code or being killed by a
-// signal, and emitting error output that matches regex.
-# define ASSERT_DEATH(statement, regex) \
-    ASSERT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex)
+// signal, and emitting error output that matches `matcher`.
+# define ASSERT_DEATH(statement, matcher) \
+    ASSERT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, matcher)
 
-// Like ASSERT_DEATH, but continues on to successive tests in the
+// Like `ASSERT_DEATH`, but continues on to successive tests in the
 // test suite, if any:
-# define EXPECT_DEATH(statement, regex) \
-    EXPECT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex)
+# define EXPECT_DEATH(statement, matcher) \
+    EXPECT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, matcher)
 
 // Two predicate classes that can be used in {ASSERT,EXPECT}_EXIT*:
 
@@ -10218,11 +7428,10 @@
 class GTEST_API_ ExitedWithCode {
  public:
   explicit ExitedWithCode(int exit_code);
+  ExitedWithCode(const ExitedWithCode&) = default;
+  void operator=(const ExitedWithCode& other) = delete;
   bool operator()(int exit_status) const;
  private:
-  // No implementation - assignment is unsupported.
-  void operator=(const ExitedWithCode& other);
-
   const int exit_code_;
 };
 
@@ -10304,20 +7513,20 @@
 // This macro is used for implementing macros such as
 // EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED on systems where
 // death tests are not supported. Those macros must compile on such systems
-// iff EXPECT_DEATH and ASSERT_DEATH compile with the same parameters on
-// systems that support death tests. This allows one to write such a macro
-// on a system that does not support death tests and be sure that it will
-// compile on a death-test supporting system. It is exposed publicly so that
-// systems that have death-tests with stricter requirements than
-// GTEST_HAS_DEATH_TEST can write their own equivalent of
-// EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED.
+// if and only if EXPECT_DEATH and ASSERT_DEATH compile with the same parameters
+// on systems that support death tests. This allows one to write such a macro on
+// a system that does not support death tests and be sure that it will compile
+// on a death-test supporting system. It is exposed publicly so that systems
+// that have death-tests with stricter requirements than GTEST_HAS_DEATH_TEST
+// can write their own equivalent of EXPECT_DEATH_IF_SUPPORTED and
+// ASSERT_DEATH_IF_SUPPORTED.
 //
 // Parameters:
 //   statement -  A statement that a macro such as EXPECT_DEATH would test
 //                for program termination. This macro has to make sure this
 //                statement is compiled but not executed, to ensure that
 //                EXPECT_DEATH_IF_SUPPORTED compiles with a certain
-//                parameter iff EXPECT_DEATH compiles with it.
+//                parameter if and only if EXPECT_DEATH compiles with it.
 //   regex     -  A regex that a macro such as EXPECT_DEATH would use to test
 //                the output of statement.  This parameter has to be
 //                compiled but not evaluated by this macro, to ensure that
@@ -10368,7 +7577,7 @@
 
 }  // namespace testing
 
-#endif  // GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
+#endif  // GOOGLETEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
 // Copyright 2008, Google Inc.
 // All rights reserved.
 //
@@ -10401,12 +7610,9 @@
 // Macros and functions for implementing parameterized tests
 // in Google C++ Testing and Mocking Framework (Google Test)
 //
-// This file is generated by a SCRIPT.  DO NOT EDIT BY HAND!
-//
 // GOOGLETEST_CM0001 DO NOT DELETE
-#ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
-#define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
-
+#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
+#define GOOGLETEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
 
 // Value-parameterized tests allow you to test your code with different
 // parameters without writing multiple copies of the same test.
@@ -10471,7 +7677,7 @@
                          Values("meeny", "miny", "moe"));
 
 // To distinguish different instances of the pattern, (yes, you
-// can instantiate it more then once) the first argument to the
+// can instantiate it more than once) the first argument to the
 // INSTANTIATE_TEST_SUITE_P macro is a prefix that will be added to the
 // actual test suite name. Remember to pick unique prefixes for different
 // instantiations. The tests from the instantiation above will have
@@ -10545,6 +7751,7 @@
 
 #endif  // 0
 
+#include <iterator>
 #include <utility>
 
 // Copyright 2008 Google Inc.
@@ -10581,8 +7788,8 @@
 
 // GOOGLETEST_CM0001 DO NOT DELETE
 
-#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
-#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
+#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
+#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
 
 #include <ctype.h>
 
@@ -10591,9 +7798,192 @@
 #include <memory>
 #include <set>
 #include <tuple>
+#include <type_traits>
 #include <utility>
 #include <vector>
 
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// 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 Google Inc. 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.
+//
+// GOOGLETEST_CM0001 DO NOT DELETE
+
+#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
+#define GOOGLETEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
+
+#include <iosfwd>
+#include <vector>
+
+GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \
+/* class A needs to have dll-interface to be used by clients of class B */)
+
+namespace testing {
+
+// A copyable object representing the result of a test part (i.e. an
+// assertion or an explicit FAIL(), ADD_FAILURE(), or SUCCESS()).
+//
+// Don't inherit from TestPartResult as its destructor is not virtual.
+class GTEST_API_ TestPartResult {
+ public:
+  // The possible outcomes of a test part (i.e. an assertion or an
+  // explicit SUCCEED(), FAIL(), or ADD_FAILURE()).
+  enum Type {
+    kSuccess,          // Succeeded.
+    kNonFatalFailure,  // Failed but the test can continue.
+    kFatalFailure,     // Failed and the test should be terminated.
+    kSkip              // Skipped.
+  };
+
+  // C'tor.  TestPartResult does NOT have a default constructor.
+  // Always use this constructor (with parameters) to create a
+  // TestPartResult object.
+  TestPartResult(Type a_type, const char* a_file_name, int a_line_number,
+                 const char* a_message)
+      : type_(a_type),
+        file_name_(a_file_name == nullptr ? "" : a_file_name),
+        line_number_(a_line_number),
+        summary_(ExtractSummary(a_message)),
+        message_(a_message) {}
+
+  // Gets the outcome of the test part.
+  Type type() const { return type_; }
+
+  // Gets the name of the source file where the test part took place, or
+  // NULL if it's unknown.
+  const char* file_name() const {
+    return file_name_.empty() ? nullptr : file_name_.c_str();
+  }
+
+  // Gets the line in the source file where the test part took place,
+  // or -1 if it's unknown.
+  int line_number() const { return line_number_; }
+
+  // Gets the summary of the failure message.
+  const char* summary() const { return summary_.c_str(); }
+
+  // Gets the message associated with the test part.
+  const char* message() const { return message_.c_str(); }
+
+  // Returns true if and only if the test part was skipped.
+  bool skipped() const { return type_ == kSkip; }
+
+  // Returns true if and only if the test part passed.
+  bool passed() const { return type_ == kSuccess; }
+
+  // Returns true if and only if the test part non-fatally failed.
+  bool nonfatally_failed() const { return type_ == kNonFatalFailure; }
+
+  // Returns true if and only if the test part fatally failed.
+  bool fatally_failed() const { return type_ == kFatalFailure; }
+
+  // Returns true if and only if the test part failed.
+  bool failed() const { return fatally_failed() || nonfatally_failed(); }
+
+ private:
+  Type type_;
+
+  // Gets the summary of the failure message by omitting the stack
+  // trace in it.
+  static std::string ExtractSummary(const char* message);
+
+  // The name of the source file where the test part took place, or
+  // "" if the source file is unknown.
+  std::string file_name_;
+  // The line in the source file where the test part took place, or -1
+  // if the line number is unknown.
+  int line_number_;
+  std::string summary_;  // The test failure summary.
+  std::string message_;  // The test failure message.
+};
+
+// Prints a TestPartResult object.
+std::ostream& operator<<(std::ostream& os, const TestPartResult& result);
+
+// An array of TestPartResult objects.
+//
+// Don't inherit from TestPartResultArray as its destructor is not
+// virtual.
+class GTEST_API_ TestPartResultArray {
+ public:
+  TestPartResultArray() {}
+
+  // Appends the given TestPartResult to the array.
+  void Append(const TestPartResult& result);
+
+  // Returns the TestPartResult at the given index (0-based).
+  const TestPartResult& GetTestPartResult(int index) const;
+
+  // Returns the number of TestPartResult objects in the array.
+  int size() const;
+
+ private:
+  std::vector<TestPartResult> array_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(TestPartResultArray);
+};
+
+// This interface knows how to report a test part result.
+class GTEST_API_ TestPartResultReporterInterface {
+ public:
+  virtual ~TestPartResultReporterInterface() {}
+
+  virtual void ReportTestPartResult(const TestPartResult& result) = 0;
+};
+
+namespace internal {
+
+// This helper class is used by {ASSERT|EXPECT}_NO_FATAL_FAILURE to check if a
+// statement generates new fatal failures. To do so it registers itself as the
+// current test part result reporter. Besides checking if fatal failures were
+// reported, it only delegates the reporting to the former result reporter.
+// The original result reporter is restored in the destructor.
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+class GTEST_API_ HasNewFatalFailureHelper
+    : public TestPartResultReporterInterface {
+ public:
+  HasNewFatalFailureHelper();
+  ~HasNewFatalFailureHelper() override;
+  void ReportTestPartResult(const TestPartResult& result) override;
+  bool has_new_fatal_failure() const { return has_new_fatal_failure_; }
+ private:
+  bool has_new_fatal_failure_;
+  TestPartResultReporterInterface* original_reporter_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(HasNewFatalFailureHelper);
+};
+
+}  // namespace internal
+
+}  // namespace testing
+
+GTEST_DISABLE_MSC_WARNINGS_POP_()  //  4251
+
+#endif  // GOOGLETEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
 
 namespace testing {
 // Input to a parameterized test name generator, describing a test parameter.
@@ -11003,11 +8393,11 @@
 
   // Base part of test suite name for display purposes.
   virtual const std::string& GetTestSuiteName() const = 0;
-  // Test case id to verify identity.
+  // Test suite id to verify identity.
   virtual TypeId GetTestSuiteTypeId() const = 0;
   // UnitTest class invokes this method to register tests in this
   // test suite right before running them in RUN_ALL_TESTS macro.
-  // This method should not be called more then once on any single
+  // This method should not be called more than once on any single
   // instance of a ParameterizedTestSuiteInfoBase derived class.
   virtual void RegisterTests() = 0;
 
@@ -11020,6 +8410,17 @@
 
 // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
 //
+// Report a the name of a test_suit as safe to ignore
+// as the side effect of construction of this type.
+struct GTEST_API_ MarkAsIgnored {
+  explicit MarkAsIgnored(const char* test_suite);
+};
+
+GTEST_API_ void InsertSyntheticTestCase(const std::string& name,
+                                        CodeLocation location, bool has_test_p);
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
 // ParameterizedTestSuiteInfo accumulates tests obtained from TEST_P
 // macro invocations for a particular test suite and generators
 // obtained from INSTANTIATE_TEST_SUITE_P macro invocations for that
@@ -11040,11 +8441,11 @@
                                       CodeLocation code_location)
       : test_suite_name_(name), code_location_(code_location) {}
 
-  // Test case base name for display purposes.
+  // Test suite base name for display purposes.
   const std::string& GetTestSuiteName() const override {
     return test_suite_name_;
   }
-  // Test case id to verify identity.
+  // Test suite id to verify identity.
   TypeId GetTestSuiteTypeId() const override { return GetTypeId<TestSuite>(); }
   // TEST_P macro uses AddTestPattern() to record information
   // about a single test in a LocalTestInfo structure.
@@ -11053,9 +8454,10 @@
   // parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is
   // test suite base name and DoBar is test base name.
   void AddTestPattern(const char* test_suite_name, const char* test_base_name,
-                      TestMetaFactoryBase<ParamType>* meta_factory) {
-    tests_.push_back(std::shared_ptr<TestInfo>(
-        new TestInfo(test_suite_name, test_base_name, meta_factory)));
+                      TestMetaFactoryBase<ParamType>* meta_factory,
+                      CodeLocation code_location) {
+    tests_.push_back(std::shared_ptr<TestInfo>(new TestInfo(
+        test_suite_name, test_base_name, meta_factory, code_location)));
   }
   // INSTANTIATE_TEST_SUITE_P macro uses AddGenerator() to record information
   // about a generator.
@@ -11068,11 +8470,13 @@
     return 0;  // Return value used only to run this method in namespace scope.
   }
   // UnitTest class invokes this method to register tests in this test suite
-  // test suites right before running tests in RUN_ALL_TESTS macro.
-  // This method should not be called more then once on any single
+  // right before running tests in RUN_ALL_TESTS macro.
+  // This method should not be called more than once on any single
   // instance of a ParameterizedTestSuiteInfoBase derived class.
-  // UnitTest has a guard to prevent from calling this method more then once.
+  // UnitTest has a guard to prevent from calling this method more than once.
   void RegisterTests() override {
+    bool generated_instantiations = false;
+
     for (typename TestInfoContainer::iterator test_it = tests_.begin();
          test_it != tests_.end(); ++test_it) {
       std::shared_ptr<TestInfo> test_info = *test_it;
@@ -11095,6 +8499,8 @@
         for (typename ParamGenerator<ParamType>::iterator param_it =
                  generator.begin();
              param_it != generator.end(); ++param_it, ++i) {
+          generated_instantiations = true;
+
           Message test_name_stream;
 
           std::string param_name = name_func(
@@ -11111,18 +8517,27 @@
 
           test_param_names.insert(param_name);
 
-          test_name_stream << test_info->test_base_name << "/" << param_name;
+          if (!test_info->test_base_name.empty()) {
+            test_name_stream << test_info->test_base_name << "/";
+          }
+          test_name_stream << param_name;
           MakeAndRegisterTestInfo(
               test_suite_name.c_str(), test_name_stream.GetString().c_str(),
               nullptr,  // No type parameter.
-              PrintToString(*param_it).c_str(), code_location_,
+              PrintToString(*param_it).c_str(), test_info->code_location,
               GetTestSuiteTypeId(),
-              SuiteApiResolver<TestSuite>::GetSetUpCaseOrSuite(),
-              SuiteApiResolver<TestSuite>::GetTearDownCaseOrSuite(),
+              SuiteApiResolver<TestSuite>::GetSetUpCaseOrSuite(file, line),
+              SuiteApiResolver<TestSuite>::GetTearDownCaseOrSuite(file, line),
               test_info->test_meta_factory->CreateTestFactory(*param_it));
         }  // for param_it
       }  // for gen_it
     }  // for test_it
+
+    if (!generated_instantiations) {
+      // There are no generaotrs, or they all generate nothing ...
+      InsertSyntheticTestCase(GetTestSuiteName(), code_location_,
+                              !tests_.empty());
+    }
   }    // RegisterTests
 
  private:
@@ -11130,14 +8545,17 @@
   // with TEST_P macro.
   struct TestInfo {
     TestInfo(const char* a_test_suite_base_name, const char* a_test_base_name,
-             TestMetaFactoryBase<ParamType>* a_test_meta_factory)
+             TestMetaFactoryBase<ParamType>* a_test_meta_factory,
+             CodeLocation a_code_location)
         : test_suite_base_name(a_test_suite_base_name),
           test_base_name(a_test_base_name),
-          test_meta_factory(a_test_meta_factory) {}
+          test_meta_factory(a_test_meta_factory),
+          code_location(a_code_location) {}
 
     const std::string test_suite_base_name;
     const std::string test_base_name;
     const std::unique_ptr<TestMetaFactoryBase<ParamType> > test_meta_factory;
+    const CodeLocation code_location;
   };
   using TestInfoContainer = ::std::vector<std::shared_ptr<TestInfo> >;
   // Records data received from INSTANTIATE_TEST_SUITE_P macros:
@@ -11170,7 +8588,7 @@
 
     // Check for invalid characters
     for (std::string::size_type index = 0; index < name.size(); ++index) {
-      if (!isalnum(name[index]) && name[index] != '_')
+      if (!IsAlNum(name[index]) && name[index] != '_')
         return false;
     }
 
@@ -11260,6 +8678,34 @@
   GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestSuiteRegistry);
 };
 
+// Keep track of what type-parameterized test suite are defined and
+// where as well as which are intatiated. This allows susequently
+// identifying suits that are defined but never used.
+class TypeParameterizedTestSuiteRegistry {
+ public:
+  // Add a suite definition
+  void RegisterTestSuite(const char* test_suite_name,
+                         CodeLocation code_location);
+
+  // Add an instantiation of a suit.
+  void RegisterInstantiation(const char* test_suite_name);
+
+  // For each suit repored as defined but not reported as instantiation,
+  // emit a test that reports that fact (configurably, as an error).
+  void CheckForInstantiations();
+
+ private:
+  struct TypeParameterizedTestSuiteInfo {
+    explicit TypeParameterizedTestSuiteInfo(CodeLocation c)
+        : code_location(c), instantiated(false) {}
+
+    CodeLocation code_location;
+    bool instantiated;
+  };
+
+  std::map<std::string, TypeParameterizedTestSuiteInfo> suites_;
+};
+
 }  // namespace internal
 
 // Forward declarations of ValuesIn(), which is implemented in
@@ -11271,10 +8717,15 @@
 namespace internal {
 // Used in the Values() function to provide polymorphic capabilities.
 
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4100)
+#endif
+
 template <typename... Ts>
 class ValueArray {
  public:
-  ValueArray(Ts... v) : v_{std::move(v)...} {}
+  explicit ValueArray(Ts... v) : v_(FlatTupleConstructTag{}, std::move(v)...) {}
 
   template <typename T>
   operator ParamGenerator<T>() const {  // NOLINT
@@ -11290,6 +8741,10 @@
   FlatTuple<Ts...> v_;
 };
 
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
 template <typename... T>
 class CartesianProductGenerator
     : public ParamGeneratorInterface<::std::tuple<T...>> {
@@ -11423,7 +8878,7 @@
 }  // namespace internal
 }  // namespace testing
 
-#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
+#endif  // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
 
 namespace testing {
 
@@ -11537,10 +8992,9 @@
 //
 template <typename ForwardIterator>
 internal::ParamGenerator<
-  typename ::testing::internal::IteratorTraits<ForwardIterator>::value_type>
+    typename std::iterator_traits<ForwardIterator>::value_type>
 ValuesIn(ForwardIterator begin, ForwardIterator end) {
-  typedef typename ::testing::internal::IteratorTraits<ForwardIterator>
-      ::value_type ParamType;
+  typedef typename std::iterator_traits<ForwardIterator>::value_type ParamType;
   return internal::ParamGenerator<ParamType>(
       new internal::ValuesInIteratorRangeGenerator<ParamType>(begin, end));
 }
@@ -11616,8 +9070,6 @@
 //     std::tuple<T1, T2, ..., TN> where T1, T2, ..., TN are the types
 //     of elements from sequences produces by gen1, gen2, ..., genN.
 //
-// Combine can have up to 10 arguments.
-//
 // Example:
 //
 // This will instantiate tests in test suite AnimalTest each one with
@@ -11661,19 +9113,20 @@
       : public test_suite_name {                                               \
    public:                                                                     \
     GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)() {}                    \
-    virtual void TestBody();                                                   \
+    void TestBody() override;                                                  \
                                                                                \
    private:                                                                    \
     static int AddToRegistry() {                                               \
       ::testing::UnitTest::GetInstance()                                       \
           ->parameterized_test_registry()                                      \
           .GetTestSuitePatternHolder<test_suite_name>(                         \
-              #test_suite_name,                                                \
+              GTEST_STRINGIFY_(test_suite_name),                               \
               ::testing::internal::CodeLocation(__FILE__, __LINE__))           \
           ->AddTestPattern(                                                    \
               GTEST_STRINGIFY_(test_suite_name), GTEST_STRINGIFY_(test_name),  \
               new ::testing::internal::TestMetaFactory<GTEST_TEST_CLASS_NAME_( \
-                  test_suite_name, test_name)>());                             \
+                  test_suite_name, test_name)>(),                              \
+              ::testing::internal::CodeLocation(__FILE__, __LINE__));          \
       return 0;                                                                \
     }                                                                          \
     static int gtest_registering_dummy_ GTEST_ATTRIBUTE_UNUSED_;               \
@@ -11728,13 +9181,21 @@
           ::testing::UnitTest::GetInstance()                                  \
               ->parameterized_test_registry()                                 \
               .GetTestSuitePatternHolder<test_suite_name>(                    \
-                  #test_suite_name,                                           \
+                  GTEST_STRINGIFY_(test_suite_name),                          \
                   ::testing::internal::CodeLocation(__FILE__, __LINE__))      \
               ->AddTestSuiteInstantiation(                                    \
-                  #prefix, &gtest_##prefix##test_suite_name##_EvalGenerator_, \
+                  GTEST_STRINGIFY_(prefix),                                   \
+                  &gtest_##prefix##test_suite_name##_EvalGenerator_,          \
                   &gtest_##prefix##test_suite_name##_EvalGenerateName_,       \
                   __FILE__, __LINE__)
 
+
+// Allow Marking a Parameterized test class as not needing to be instantiated.
+#define GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(T)                   \
+  namespace gtest_do_not_use_outside_namespace_scope {}                   \
+  static const ::testing::internal::MarkAsIgnored gtest_allow_ignore_##T( \
+      GTEST_STRINGIFY_(T))
+
 // Legacy API is deprecated but still available
 #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
 #define INSTANTIATE_TEST_CASE_P                                            \
@@ -11745,7 +9206,7 @@
 
 }  // namespace testing
 
-#endif  // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
+#endif  // GOOGLETEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
 // Copyright 2006, Google Inc.
 // All rights reserved.
 //
@@ -11779,8 +9240,8 @@
 // Google C++ Testing and Mocking Framework definitions useful in production code.
 // GOOGLETEST_CM0003 DO NOT DELETE
 
-#ifndef GTEST_INCLUDE_GTEST_GTEST_PROD_H_
-#define GTEST_INCLUDE_GTEST_GTEST_PROD_H_
+#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_PROD_H_
+#define GOOGLETEST_INCLUDE_GTEST_GTEST_PROD_H_
 
 // When you need to test the private or protected members of a class,
 // use the FRIEND_TEST macro to declare your tests as friends of the
@@ -11806,189 +9267,7 @@
 #define FRIEND_TEST(test_case_name, test_name)\
 friend class test_case_name##_##test_name##_Test
 
-#endif  // GTEST_INCLUDE_GTEST_GTEST_PROD_H_
-// Copyright 2008, Google Inc.
-// All rights reserved.
-//
-// 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 Google Inc. 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.
-//
-// GOOGLETEST_CM0001 DO NOT DELETE
-
-#ifndef GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
-#define GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
-
-#include <iosfwd>
-#include <vector>
-
-GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \
-/* class A needs to have dll-interface to be used by clients of class B */)
-
-namespace testing {
-
-// A copyable object representing the result of a test part (i.e. an
-// assertion or an explicit FAIL(), ADD_FAILURE(), or SUCCESS()).
-//
-// Don't inherit from TestPartResult as its destructor is not virtual.
-class GTEST_API_ TestPartResult {
- public:
-  // The possible outcomes of a test part (i.e. an assertion or an
-  // explicit SUCCEED(), FAIL(), or ADD_FAILURE()).
-  enum Type {
-    kSuccess,          // Succeeded.
-    kNonFatalFailure,  // Failed but the test can continue.
-    kFatalFailure,     // Failed and the test should be terminated.
-    kSkip              // Skipped.
-  };
-
-  // C'tor.  TestPartResult does NOT have a default constructor.
-  // Always use this constructor (with parameters) to create a
-  // TestPartResult object.
-  TestPartResult(Type a_type, const char* a_file_name, int a_line_number,
-                 const char* a_message)
-      : type_(a_type),
-        file_name_(a_file_name == nullptr ? "" : a_file_name),
-        line_number_(a_line_number),
-        summary_(ExtractSummary(a_message)),
-        message_(a_message) {}
-
-  // Gets the outcome of the test part.
-  Type type() const { return type_; }
-
-  // Gets the name of the source file where the test part took place, or
-  // NULL if it's unknown.
-  const char* file_name() const {
-    return file_name_.empty() ? nullptr : file_name_.c_str();
-  }
-
-  // Gets the line in the source file where the test part took place,
-  // or -1 if it's unknown.
-  int line_number() const { return line_number_; }
-
-  // Gets the summary of the failure message.
-  const char* summary() const { return summary_.c_str(); }
-
-  // Gets the message associated with the test part.
-  const char* message() const { return message_.c_str(); }
-
-  // Returns true iff the test part was skipped.
-  bool skipped() const { return type_ == kSkip; }
-
-  // Returns true iff the test part passed.
-  bool passed() const { return type_ == kSuccess; }
-
-  // Returns true iff the test part non-fatally failed.
-  bool nonfatally_failed() const { return type_ == kNonFatalFailure; }
-
-  // Returns true iff the test part fatally failed.
-  bool fatally_failed() const { return type_ == kFatalFailure; }
-
-  // Returns true iff the test part failed.
-  bool failed() const { return fatally_failed() || nonfatally_failed(); }
-
- private:
-  Type type_;
-
-  // Gets the summary of the failure message by omitting the stack
-  // trace in it.
-  static std::string ExtractSummary(const char* message);
-
-  // The name of the source file where the test part took place, or
-  // "" if the source file is unknown.
-  std::string file_name_;
-  // The line in the source file where the test part took place, or -1
-  // if the line number is unknown.
-  int line_number_;
-  std::string summary_;  // The test failure summary.
-  std::string message_;  // The test failure message.
-};
-
-// Prints a TestPartResult object.
-std::ostream& operator<<(std::ostream& os, const TestPartResult& result);
-
-// An array of TestPartResult objects.
-//
-// Don't inherit from TestPartResultArray as its destructor is not
-// virtual.
-class GTEST_API_ TestPartResultArray {
- public:
-  TestPartResultArray() {}
-
-  // Appends the given TestPartResult to the array.
-  void Append(const TestPartResult& result);
-
-  // Returns the TestPartResult at the given index (0-based).
-  const TestPartResult& GetTestPartResult(int index) const;
-
-  // Returns the number of TestPartResult objects in the array.
-  int size() const;
-
- private:
-  std::vector<TestPartResult> array_;
-
-  GTEST_DISALLOW_COPY_AND_ASSIGN_(TestPartResultArray);
-};
-
-// This interface knows how to report a test part result.
-class GTEST_API_ TestPartResultReporterInterface {
- public:
-  virtual ~TestPartResultReporterInterface() {}
-
-  virtual void ReportTestPartResult(const TestPartResult& result) = 0;
-};
-
-namespace internal {
-
-// This helper class is used by {ASSERT|EXPECT}_NO_FATAL_FAILURE to check if a
-// statement generates new fatal failures. To do so it registers itself as the
-// current test part result reporter. Besides checking if fatal failures were
-// reported, it only delegates the reporting to the former result reporter.
-// The original result reporter is restored in the destructor.
-// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
-class GTEST_API_ HasNewFatalFailureHelper
-    : public TestPartResultReporterInterface {
- public:
-  HasNewFatalFailureHelper();
-  ~HasNewFatalFailureHelper() override;
-  void ReportTestPartResult(const TestPartResult& result) override;
-  bool has_new_fatal_failure() const { return has_new_fatal_failure_; }
- private:
-  bool has_new_fatal_failure_;
-  TestPartResultReporterInterface* original_reporter_;
-
-  GTEST_DISALLOW_COPY_AND_ASSIGN_(HasNewFatalFailureHelper);
-};
-
-}  // namespace internal
-
-}  // namespace testing
-
-GTEST_DISABLE_MSC_WARNINGS_POP_()  //  4251
-
-#endif  // GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
+#endif  // GOOGLETEST_INCLUDE_GTEST_GTEST_PROD_H_
 // Copyright 2008 Google Inc.
 // All Rights Reserved.
 //
@@ -12018,11 +9297,10 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-
 // GOOGLETEST_CM0001 DO NOT DELETE
 
-#ifndef GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
-#define GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
+#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
+#define GOOGLETEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
 
 // This header implements typed tests and type-parameterized tests.
 
@@ -12056,9 +9334,9 @@
 // Then, use TYPED_TEST() instead of TEST_F() to define as many typed
 // tests for this test suite as you want.
 TYPED_TEST(FooTest, DoesBlah) {
-  // Inside a test, refer to TypeParam to get the type parameter.
-  // Since we are inside a derived class template, C++ requires use to
-  // visit the members of FooTest via 'this'.
+  // Inside a test, refer to the special name TypeParam to get the type
+  // parameter.  Since we are inside a derived class template, C++ requires
+  // us to visit the members of FooTest via 'this'.
   TypeParam n = this->value_;
 
   // To visit static members of the fixture, add the TestFixture::
@@ -12164,8 +9442,6 @@
 
 // Implements typed tests.
 
-#if GTEST_HAS_TYPED_TEST
-
 // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
 //
 // Expands to the name of the typedef for the type parameters of the
@@ -12177,27 +9453,25 @@
 #define GTEST_NAME_GENERATOR_(TestSuiteName) \
   gtest_type_params_##TestSuiteName##_NameGenerator
 
-// The 'Types' template argument below must have spaces around it
-// since some compilers may choke on '>>' when passing a template
-// instance (e.g. Types<int>)
-#define TYPED_TEST_SUITE(CaseName, Types, ...)                           \
-  typedef ::testing::internal::TypeList<Types>::type GTEST_TYPE_PARAMS_( \
-      CaseName);                                                         \
-  typedef ::testing::internal::NameGeneratorSelector<__VA_ARGS__>::type  \
+#define TYPED_TEST_SUITE(CaseName, Types, ...)                          \
+  typedef ::testing::internal::GenerateTypeList<Types>::type            \
+      GTEST_TYPE_PARAMS_(CaseName);                                     \
+  typedef ::testing::internal::NameGeneratorSelector<__VA_ARGS__>::type \
       GTEST_NAME_GENERATOR_(CaseName)
 
-# define TYPED_TEST(CaseName, TestName)                                       \
+#define TYPED_TEST(CaseName, TestName)                                        \
+  static_assert(sizeof(GTEST_STRINGIFY_(TestName)) > 1,                       \
+                "test-name must not be empty");                               \
   template <typename gtest_TypeParam_>                                        \
   class GTEST_TEST_CLASS_NAME_(CaseName, TestName)                            \
       : public CaseName<gtest_TypeParam_> {                                   \
    private:                                                                   \
     typedef CaseName<gtest_TypeParam_> TestFixture;                           \
     typedef gtest_TypeParam_ TypeParam;                                       \
-    virtual void TestBody();                                                  \
+    void TestBody() override;                                                 \
   };                                                                          \
   static bool gtest_##CaseName##_##TestName##_registered_                     \
-        GTEST_ATTRIBUTE_UNUSED_ =                                             \
-      ::testing::internal::TypeParameterizedTest<                             \
+      GTEST_ATTRIBUTE_UNUSED_ = ::testing::internal::TypeParameterizedTest<   \
           CaseName,                                                           \
           ::testing::internal::TemplateSel<GTEST_TEST_CLASS_NAME_(CaseName,   \
                                                                   TestName)>, \
@@ -12205,7 +9479,8 @@
               CaseName)>::Register("",                                        \
                                    ::testing::internal::CodeLocation(         \
                                        __FILE__, __LINE__),                   \
-                                   #CaseName, #TestName, 0,                   \
+                                   GTEST_STRINGIFY_(CaseName),                \
+                                   GTEST_STRINGIFY_(TestName), 0,             \
                                    ::testing::internal::GenerateNames<        \
                                        GTEST_NAME_GENERATOR_(CaseName),       \
                                        GTEST_TYPE_PARAMS_(CaseName)>());      \
@@ -12220,12 +9495,8 @@
   TYPED_TEST_SUITE
 #endif  // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
 
-#endif  // GTEST_HAS_TYPED_TEST
-
 // Implements type-parameterized tests.
 
-#if GTEST_HAS_TYPED_TEST_P
-
 // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
 //
 // Expands to the namespace name that the type-parameterized tests for
@@ -12268,24 +9539,26 @@
      private:                                                         \
       typedef SuiteName<gtest_TypeParam_> TestFixture;                \
       typedef gtest_TypeParam_ TypeParam;                             \
-      virtual void TestBody();                                        \
+      void TestBody() override;                                       \
     };                                                                \
     static bool gtest_##TestName##_defined_ GTEST_ATTRIBUTE_UNUSED_ = \
         GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName).AddTestName(       \
-            __FILE__, __LINE__, #SuiteName, #TestName);               \
+            __FILE__, __LINE__, GTEST_STRINGIFY_(SuiteName),          \
+            GTEST_STRINGIFY_(TestName));                              \
   }                                                                   \
   template <typename gtest_TypeParam_>                                \
   void GTEST_SUITE_NAMESPACE_(                                        \
       SuiteName)::TestName<gtest_TypeParam_>::TestBody()
 
-#define REGISTER_TYPED_TEST_SUITE_P(SuiteName, ...)                            \
-  namespace GTEST_SUITE_NAMESPACE_(SuiteName) {                                \
-    typedef ::testing::internal::Templates<__VA_ARGS__>::type gtest_AllTests_; \
-  }                                                                            \
-  static const char* const GTEST_REGISTERED_TEST_NAMES_(                       \
-      SuiteName) GTEST_ATTRIBUTE_UNUSED_ =                                     \
-      GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName).VerifyRegisteredTestNames(    \
-          __FILE__, __LINE__, #__VA_ARGS__)
+// Note: this won't work correctly if the trailing arguments are macros.
+#define REGISTER_TYPED_TEST_SUITE_P(SuiteName, ...)                         \
+  namespace GTEST_SUITE_NAMESPACE_(SuiteName) {                             \
+    typedef ::testing::internal::Templates<__VA_ARGS__> gtest_AllTests_;    \
+  }                                                                         \
+  static const char* const GTEST_REGISTERED_TEST_NAMES_(                    \
+      SuiteName) GTEST_ATTRIBUTE_UNUSED_ =                                  \
+      GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName).VerifyRegisteredTestNames( \
+          GTEST_STRINGIFY_(SuiteName), __FILE__, __LINE__, #__VA_ARGS__)
 
 // Legacy API is deprecated but still available
 #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
@@ -12295,22 +9568,22 @@
   REGISTER_TYPED_TEST_SUITE_P
 #endif  // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
 
-// The 'Types' template argument below must have spaces around it
-// since some compilers may choke on '>>' when passing a template
-// instance (e.g. Types<int>)
 #define INSTANTIATE_TYPED_TEST_SUITE_P(Prefix, SuiteName, Types, ...)       \
+  static_assert(sizeof(GTEST_STRINGIFY_(Prefix)) > 1,                       \
+                "test-suit-prefix must not be empty");                      \
   static bool gtest_##Prefix##_##SuiteName GTEST_ATTRIBUTE_UNUSED_ =        \
       ::testing::internal::TypeParameterizedTestSuite<                      \
           SuiteName, GTEST_SUITE_NAMESPACE_(SuiteName)::gtest_AllTests_,    \
-          ::testing::internal::TypeList<Types>::type>::                     \
-          Register(#Prefix,                                                 \
+          ::testing::internal::GenerateTypeList<Types>::type>::             \
+          Register(GTEST_STRINGIFY_(Prefix),                                \
                    ::testing::internal::CodeLocation(__FILE__, __LINE__),   \
-                   &GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName), #SuiteName, \
+                   &GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName),             \
+                   GTEST_STRINGIFY_(SuiteName),                             \
                    GTEST_REGISTERED_TEST_NAMES_(SuiteName),                 \
                    ::testing::internal::GenerateNames<                      \
                        ::testing::internal::NameGeneratorSelector<          \
                            __VA_ARGS__>::type,                              \
-                       ::testing::internal::TypeList<Types>::type>())
+                       ::testing::internal::GenerateTypeList<Types>::type>())
 
 // Legacy API is deprecated but still available
 #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
@@ -12320,28 +9593,11 @@
   INSTANTIATE_TYPED_TEST_SUITE_P
 #endif  // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
 
-#endif  // GTEST_HAS_TYPED_TEST_P
-
-#endif  // GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
+#endif  // GOOGLETEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
 
 GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \
 /* class A needs to have dll-interface to be used by clients of class B */)
 
-// Depending on the platform, different string classes are available.
-// On Linux, in addition to ::std::string, Google also makes use of
-// class ::string, which has the same interface as ::std::string, but
-// has a different implementation.
-//
-// You can define GTEST_HAS_GLOBAL_STRING to 1 to indicate that
-// ::string is available AND is a distinct type to ::std::string, or
-// define it to 0 to indicate otherwise.
-//
-// If ::std::string and ::string are the same class on your platform
-// due to aliasing, you should define GTEST_HAS_GLOBAL_STRING to 0.
-//
-// If you do not define GTEST_HAS_GLOBAL_STRING, it is defined
-// heuristically.
-
 namespace testing {
 
 // Silence C4100 (unreferenced formal parameter) and 4805
@@ -12370,6 +9626,10 @@
 // to let Google Test decide.
 GTEST_DECLARE_string_(color);
 
+// This flag controls whether the test runner should continue execution past
+// first failure.
+GTEST_DECLARE_bool_(fail_fast);
+
 // This flag sets up the filter to select by name using a glob pattern
 // the tests to run. If the filter is not given all tests are executed.
 GTEST_DECLARE_string_(filter);
@@ -12386,6 +9646,9 @@
 // in addition to its normal textual output.
 GTEST_DECLARE_string_(output);
 
+// This flags control whether Google Test prints only test failures.
+GTEST_DECLARE_bool_(brief);
+
 // This flags control whether Google Test prints the elapsed time for each
 // test.
 GTEST_DECLARE_bool_(print_time);
@@ -12446,6 +9709,7 @@
 class UnitTestImpl* GetUnitTestImpl();
 void ReportFailureInUnknownLocation(TestPartResult::Type result_type,
                                     const std::string& message);
+std::set<std::string>* GetIgnoredParameterizedTestSuites();
 
 }  // namespace internal
 
@@ -12547,7 +9811,11 @@
   // Used in EXPECT_TRUE/FALSE(assertion_result).
   AssertionResult(const AssertionResult& other);
 
-#if defined(_MSC_VER) && _MSC_VER < 1910
+// C4800 is a level 3 warning in Visual Studio 2015 and earlier.
+// This warning is not emitted in Visual Studio 2017.
+// This warning is off by default starting in Visual Studio 2019 but can be
+// enabled with command-line options.
+#if defined(_MSC_VER) && (_MSC_VER < 1910 || _MSC_VER >= 1920)
   GTEST_DISABLE_MSC_WARNINGS_PUSH_(4800 /* forcing value to bool */)
 #endif
 
@@ -12561,13 +9829,13 @@
   template <typename T>
   explicit AssertionResult(
       const T& success,
-      typename internal::EnableIf<
+      typename std::enable_if<
           !std::is_convertible<T, AssertionResult>::value>::type*
       /*enabler*/
       = nullptr)
       : success_(success) {}
 
-#if defined(_MSC_VER) && _MSC_VER < 1910
+#if defined(_MSC_VER) && (_MSC_VER < 1910 || _MSC_VER >= 1920)
   GTEST_DISABLE_MSC_WARNINGS_POP_()
 #endif
 
@@ -12577,7 +9845,7 @@
     return *this;
   }
 
-  // Returns true iff the assertion succeeded.
+  // Returns true if and only if the assertion succeeded.
   operator bool() const { return success_; }  // NOLINT
 
   // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE.
@@ -12676,8 +9944,8 @@
 // Implements a family of generic predicate assertion macros.
 // GOOGLETEST_CM0001 DO NOT DELETE
 
-#ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
-#define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
+#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
+#define GOOGLETEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
 
 
 namespace testing {
@@ -12998,7 +10266,7 @@
 
 }  // namespace testing
 
-#endif  // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
+#endif  // GOOGLETEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
 
 namespace testing {
 
@@ -13032,38 +10300,39 @@
   // The d'tor is virtual as we intend to inherit from Test.
   virtual ~Test();
 
-  // Sets up the stuff shared by all tests in this test case.
+  // Sets up the stuff shared by all tests in this test suite.
   //
   // Google Test will call Foo::SetUpTestSuite() before running the first
-  // test in test case Foo.  Hence a sub-class can define its own
+  // test in test suite Foo.  Hence a sub-class can define its own
   // SetUpTestSuite() method to shadow the one defined in the super
   // class.
   static void SetUpTestSuite() {}
 
-  // Tears down the stuff shared by all tests in this test case.
+  // Tears down the stuff shared by all tests in this test suite.
   //
   // Google Test will call Foo::TearDownTestSuite() after running the last
-  // test in test case Foo.  Hence a sub-class can define its own
+  // test in test suite Foo.  Hence a sub-class can define its own
   // TearDownTestSuite() method to shadow the one defined in the super
   // class.
   static void TearDownTestSuite() {}
 
-  // Legacy API is deprecated but still available
+  // Legacy API is deprecated but still available. Use SetUpTestSuite and
+  // TearDownTestSuite instead.
 #ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
   static void TearDownTestCase() {}
   static void SetUpTestCase() {}
 #endif  // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
 
-  // Returns true iff the current test has a fatal failure.
+  // Returns true if and only if the current test has a fatal failure.
   static bool HasFatalFailure();
 
-  // Returns true iff the current test has a non-fatal failure.
+  // Returns true if and only if the current test has a non-fatal failure.
   static bool HasNonfatalFailure();
 
-  // Returns true iff the current test was skipped.
+  // Returns true if and only if the current test was skipped.
   static bool IsSkipped();
 
-  // Returns true iff the current test has a (either fatal or
+  // Returns true if and only if the current test has a (either fatal or
   // non-fatal) failure.
   static bool HasFailure() { return HasFatalFailure() || HasNonfatalFailure(); }
 
@@ -13094,8 +10363,8 @@
   virtual void TearDown();
 
  private:
-  // Returns true iff the current test has the same fixture class as
-  // the first test in the current test suite.
+  // Returns true if and only if the current test has the same fixture class
+  // as the first test in the current test suite.
   static bool HasSameFixtureClass();
 
   // Runs the test after the test fixture has been set up.
@@ -13196,24 +10465,28 @@
   // Returns the number of the test properties.
   int test_property_count() const;
 
-  // Returns true iff the test passed (i.e. no test part failed).
+  // Returns true if and only if the test passed (i.e. no test part failed).
   bool Passed() const { return !Skipped() && !Failed(); }
 
-  // Returns true iff the test was skipped.
+  // Returns true if and only if the test was skipped.
   bool Skipped() const;
 
-  // Returns true iff the test failed.
+  // Returns true if and only if the test failed.
   bool Failed() const;
 
-  // Returns true iff the test fatally failed.
+  // Returns true if and only if the test fatally failed.
   bool HasFatalFailure() const;
 
-  // Returns true iff the test has a non-fatal failure.
+  // Returns true if and only if the test has a non-fatal failure.
   bool HasNonfatalFailure() const;
 
   // Returns the elapsed time, in milliseconds.
   TimeInMillis elapsed_time() const { return elapsed_time_; }
 
+  // Gets the time of the test case start, in ms from the start of the
+  // UNIX epoch.
+  TimeInMillis start_timestamp() const { return start_timestamp_; }
+
   // Returns the i-th test part result among all the results. i can range from 0
   // to total_part_count() - 1. If i is not in that range, aborts the program.
   const TestPartResult& GetTestPartResult(int i) const;
@@ -13244,6 +10517,9 @@
     return test_properties_;
   }
 
+  // Sets the start time.
+  void set_start_timestamp(TimeInMillis start) { start_timestamp_ = start; }
+
   // Sets the elapsed time.
   void set_elapsed_time(TimeInMillis elapsed) { elapsed_time_ = elapsed; }
 
@@ -13279,7 +10555,7 @@
 
   // Protects mutable state of the property vector and of owned
   // properties, whose values may be updated.
-  internal::Mutex test_properites_mutex_;
+  internal::Mutex test_properties_mutex_;
 
   // The vector of TestPartResults
   std::vector<TestPartResult> test_part_results_;
@@ -13287,6 +10563,8 @@
   std::vector<TestProperty> test_properties_;
   // Running count of death tests.
   int death_test_count_;
+  // The start time, in milliseconds since UNIX Epoch.
+  TimeInMillis start_timestamp_;
   // The elapsed time, in milliseconds.
   TimeInMillis elapsed_time_;
 
@@ -13363,7 +10641,7 @@
   // contains the character 'A' or starts with "Foo.".
   bool should_run() const { return should_run_; }
 
-  // Returns true iff this test will appear in the XML report.
+  // Returns true if and only if this test will appear in the XML report.
   bool is_reportable() const {
     // The XML report includes tests matching the filter, excluding those
     // run in other shards.
@@ -13407,6 +10685,9 @@
   // deletes it.
   void Run();
 
+  // Skip and records the test result for this object.
+  void Skip();
+
   static void ClearTestResult(TestInfo* test_info) {
     test_info->result_.Clear();
   }
@@ -13421,12 +10702,12 @@
   // value-parameterized test.
   const std::unique_ptr<const ::std::string> value_param_;
   internal::CodeLocation location_;
-  const internal::TypeId fixture_class_id_;   // ID of the test fixture class
-  bool should_run_;                 // True iff this test should run
-  bool is_disabled_;                // True iff this test is disabled
-  bool matches_filter_;             // True if this test matches the
-                                    // user-specified filter.
-  bool is_in_another_shard_;        // Will be run in another shard.
+  const internal::TypeId fixture_class_id_;  // ID of the test fixture class
+  bool should_run_;           // True if and only if this test should run
+  bool is_disabled_;          // True if and only if this test is disabled
+  bool matches_filter_;       // True if this test matches the
+                              // user-specified filter.
+  bool is_in_another_shard_;  // Will be run in another shard.
   internal::TestFactoryBase* const factory_;  // The factory that creates
                                               // the test object
 
@@ -13498,15 +10779,21 @@
   // Gets the number of all tests in this test suite.
   int total_test_count() const;
 
-  // Returns true iff the test suite passed.
+  // Returns true if and only if the test suite passed.
   bool Passed() const { return !Failed(); }
 
-  // Returns true iff the test suite failed.
-  bool Failed() const { return failed_test_count() > 0; }
+  // Returns true if and only if the test suite failed.
+  bool Failed() const {
+    return failed_test_count() > 0 || ad_hoc_test_result().Failed();
+  }
 
   // Returns the elapsed time, in milliseconds.
   TimeInMillis elapsed_time() const { return elapsed_time_; }
 
+  // Gets the time of the test suite start, in ms from the start of the
+  // UNIX epoch.
+  TimeInMillis start_timestamp() const { return start_timestamp_; }
+
   // Returns the i-th test among all the tests. i can range from 0 to
   // total_test_count() - 1. If i is not in that range, returns NULL.
   const TestInfo* GetTestInfo(int i) const;
@@ -13549,6 +10836,9 @@
   // Runs every test in this TestSuite.
   void Run();
 
+  // Skips the execution of tests under this TestSuite
+  void Skip();
+
   // Runs SetUpTestSuite() for this TestSuite.  This wrapper is needed
   // for catching exceptions thrown from SetUpTestSuite().
   void RunSetUpTestSuite() {
@@ -13565,33 +10855,33 @@
     }
   }
 
-  // Returns true iff test passed.
+  // Returns true if and only if test passed.
   static bool TestPassed(const TestInfo* test_info) {
     return test_info->should_run() && test_info->result()->Passed();
   }
 
-  // Returns true iff test skipped.
+  // Returns true if and only if test skipped.
   static bool TestSkipped(const TestInfo* test_info) {
     return test_info->should_run() && test_info->result()->Skipped();
   }
 
-  // Returns true iff test failed.
+  // Returns true if and only if test failed.
   static bool TestFailed(const TestInfo* test_info) {
     return test_info->should_run() && test_info->result()->Failed();
   }
 
-  // Returns true iff the test is disabled and will be reported in the XML
-  // report.
+  // Returns true if and only if the test is disabled and will be reported in
+  // the XML report.
   static bool TestReportableDisabled(const TestInfo* test_info) {
     return test_info->is_reportable() && test_info->is_disabled_;
   }
 
-  // Returns true iff test is disabled.
+  // Returns true if and only if test is disabled.
   static bool TestDisabled(const TestInfo* test_info) {
     return test_info->is_disabled_;
   }
 
-  // Returns true iff this test will appear in the XML report.
+  // Returns true if and only if this test will appear in the XML report.
   static bool TestReportable(const TestInfo* test_info) {
     return test_info->is_reportable();
   }
@@ -13623,8 +10913,10 @@
   internal::SetUpTestSuiteFunc set_up_tc_;
   // Pointer to the function that tears down the test suite.
   internal::TearDownTestSuiteFunc tear_down_tc_;
-  // True iff any test in this test suite should run.
+  // True if and only if any test in this test suite should run.
   bool should_run_;
+  // The start time, in milliseconds since UNIX Epoch.
+  TimeInMillis start_timestamp_;
   // Elapsed time, in milliseconds.
   TimeInMillis elapsed_time_;
   // Holds test properties recorded during execution of SetUpTestSuite and
@@ -13923,7 +11215,7 @@
   int failed_test_case_count() const;
   int total_test_case_count() const;
   int test_case_to_run_count() const;
-#endif  //  EMOVE_LEGACY_TEST_CASEAPI
+#endif  //  GTEST_REMOVE_LEGACY_TEST_CASEAPI_
 
   // Gets the number of successful tests.
   int successful_test_count() const;
@@ -13956,11 +11248,12 @@
   // Gets the elapsed time, in milliseconds.
   TimeInMillis elapsed_time() const;
 
-  // Returns true iff the unit test passed (i.e. all test suites passed).
+  // Returns true if and only if the unit test passed (i.e. all test suites
+  // passed).
   bool Passed() const;
 
-  // Returns true iff the unit test failed (i.e. some test suite failed
-  // or something outside of all tests failed).
+  // Returns true if and only if the unit test failed (i.e. some test suite
+  // failed or something outside of all tests failed).
   bool Failed() const;
 
   // Gets the i-th test suite among all the test suites. i can range from 0 to
@@ -14026,6 +11319,7 @@
   friend class internal::StreamingListenerTest;
   friend class internal::UnitTestRecordPropertyTestHelper;
   friend Environment* AddGlobalTestEnvironment(Environment* env);
+  friend std::set<std::string>* internal::GetIgnoredParameterizedTestSuites();
   friend internal::UnitTestImpl* internal::GetUnitTestImpl();
   friend void internal::ReportFailureInUnknownLocation(
       TestPartResult::Type result_type,
@@ -14137,26 +11431,17 @@
   return CmpHelperEQFailure(lhs_expression, rhs_expression, lhs, rhs);
 }
 
-// With this overloaded version, we allow anonymous enums to be used
-// in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous enums
-// can be implicitly cast to BiggestInt.
-GTEST_API_ AssertionResult CmpHelperEQ(const char* lhs_expression,
-                                       const char* rhs_expression,
-                                       BiggestInt lhs,
-                                       BiggestInt rhs);
-
-// The helper class for {ASSERT|EXPECT}_EQ.  The template argument
-// lhs_is_null_literal is true iff the first argument to ASSERT_EQ()
-// is a null pointer literal.  The following default implementation is
-// for lhs_is_null_literal being false.
-template <bool lhs_is_null_literal>
 class EqHelper {
  public:
   // This templatized version is for the general case.
-  template <typename T1, typename T2>
+  template <
+      typename T1, typename T2,
+      // Disable this overload for cases where one argument is a pointer
+      // and the other is the null pointer constant.
+      typename std::enable_if<!std::is_integral<T1>::value ||
+                              !std::is_pointer<T2>::value>::type* = nullptr>
   static AssertionResult Compare(const char* lhs_expression,
-                                 const char* rhs_expression,
-                                 const T1& lhs,
+                                 const char* rhs_expression, const T1& lhs,
                                  const T2& rhs) {
     return CmpHelperEQ(lhs_expression, rhs_expression, lhs, rhs);
   }
@@ -14173,44 +11458,12 @@
                                  BiggestInt rhs) {
     return CmpHelperEQ(lhs_expression, rhs_expression, lhs, rhs);
   }
-};
 
-// This specialization is used when the first argument to ASSERT_EQ()
-// is a null pointer literal, like NULL, false, or 0.
-template <>
-class EqHelper<true> {
- public:
-  // We define two overloaded versions of Compare().  The first
-  // version will be picked when the second argument to ASSERT_EQ() is
-  // NOT a pointer, e.g. ASSERT_EQ(0, AnIntFunction()) or
-  // EXPECT_EQ(false, a_bool).
-  template <typename T1, typename T2>
-  static AssertionResult Compare(
-      const char* lhs_expression, const char* rhs_expression, const T1& lhs,
-      const T2& rhs,
-      // The following line prevents this overload from being considered if T2
-      // is not a pointer type.  We need this because ASSERT_EQ(NULL, my_ptr)
-      // expands to Compare("", "", NULL, my_ptr), which requires a conversion
-      // to match the Secret* in the other overload, which would otherwise make
-      // this template match better.
-      typename EnableIf<!std::is_pointer<T2>::value>::type* = nullptr) {
-    return CmpHelperEQ(lhs_expression, rhs_expression, lhs, rhs);
-  }
-
-  // This version will be picked when the second argument to ASSERT_EQ() is a
-  // pointer, e.g. ASSERT_EQ(NULL, a_pointer).
   template <typename T>
   static AssertionResult Compare(
-      const char* lhs_expression,
-      const char* rhs_expression,
-      // We used to have a second template parameter instead of Secret*.  That
-      // template parameter would deduce to 'long', making this a better match
-      // than the first overload even without the first overload's EnableIf.
-      // Unfortunately, gcc with -Wconversion-null warns when "passing NULL to
-      // non-pointer argument" (even a deduced integral argument), so the old
-      // implementation caused warnings in user code.
-      Secret* /* lhs (NULL) */,
-      T* rhs) {
+      const char* lhs_expression, const char* rhs_expression,
+      // Handle cases where '0' is used as a null pointer literal.
+      std::nullptr_t /* lhs */, T* rhs) {
     // We already know that 'lhs' is a null pointer.
     return CmpHelperEQ(lhs_expression, rhs_expression, static_cast<T*>(nullptr),
                        rhs);
@@ -14234,11 +11487,6 @@
 // ASSERT_?? and EXPECT_??.  It is here just to avoid copy-and-paste
 // of similar code.
 //
-// For each templatized helper function, we also define an overloaded
-// version for BiggestInt in order to reduce code bloat and allow
-// anonymous enums to be used with {ASSERT|EXPECT}_?? when compiled
-// with gcc 4.
-//
 // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
 
 #define GTEST_IMPL_CMP_HELPER_(op_name, op)\
@@ -14250,22 +11498,20 @@
   } else {\
     return CmpHelperOpFailure(expr1, expr2, val1, val2, #op);\
   }\
-}\
-GTEST_API_ AssertionResult CmpHelper##op_name(\
-    const char* expr1, const char* expr2, BiggestInt val1, BiggestInt val2)
+}
 
 // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
 
 // Implements the helper function for {ASSERT|EXPECT}_NE
-GTEST_IMPL_CMP_HELPER_(NE, !=);
+GTEST_IMPL_CMP_HELPER_(NE, !=)
 // Implements the helper function for {ASSERT|EXPECT}_LE
-GTEST_IMPL_CMP_HELPER_(LE, <=);
+GTEST_IMPL_CMP_HELPER_(LE, <=)
 // Implements the helper function for {ASSERT|EXPECT}_LT
-GTEST_IMPL_CMP_HELPER_(LT, <);
+GTEST_IMPL_CMP_HELPER_(LT, <)
 // Implements the helper function for {ASSERT|EXPECT}_GE
-GTEST_IMPL_CMP_HELPER_(GE, >=);
+GTEST_IMPL_CMP_HELPER_(GE, >=)
 // Implements the helper function for {ASSERT|EXPECT}_GT
-GTEST_IMPL_CMP_HELPER_(GT, >);
+GTEST_IMPL_CMP_HELPER_(GT, >)
 
 #undef GTEST_IMPL_CMP_HELPER_
 
@@ -14442,12 +11688,6 @@
   GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelper);
 };
 
-enum GTestColor { COLOR_DEFAULT, COLOR_RED, COLOR_GREEN, COLOR_YELLOW };
-
-GTEST_API_ GTEST_ATTRIBUTE_PRINTF_(2, 3) void ColoredPrintf(GTestColor color,
-                                                            const char* fmt,
-                                                            ...);
-
 }  // namespace internal
 
 // The pure interface class that all value-parameterized tests inherit from.
@@ -14528,7 +11768,7 @@
 // Skips test in runtime.
 // Skipping test aborts current function.
 // Skipped tests are neither successful nor failed.
-#define GTEST_SKIP() GTEST_SKIP_("Skipped")
+#define GTEST_SKIP() GTEST_SKIP_("")
 
 // ADD_FAILURE unconditionally adds a failure to the current test.
 // SUCCEED generates a success - it doesn't automatically make the
@@ -14559,6 +11799,11 @@
 // Generates a fatal failure with a generic message.
 #define GTEST_FAIL() GTEST_FATAL_FAILURE_("Failed")
 
+// Like GTEST_FAIL(), but at the given source file location.
+#define GTEST_FAIL_AT(file, line)         \
+  GTEST_MESSAGE_AT_(file, line, "Failed", \
+                    ::testing::TestPartResult::kFatalFailure)
+
 // Define this macro to 1 to omit the definition of FAIL(), which is a
 // generic name and clashes with some other libraries.
 #if !GTEST_DONT_DEFINE_FAIL
@@ -14599,19 +11844,38 @@
 // Boolean assertions. Condition can be either a Boolean expression or an
 // AssertionResult. For more information on how to use AssertionResult with
 // these macros see comments on that class.
-#define EXPECT_TRUE(condition) \
+#define GTEST_EXPECT_TRUE(condition) \
   GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \
                       GTEST_NONFATAL_FAILURE_)
-#define EXPECT_FALSE(condition) \
+#define GTEST_EXPECT_FALSE(condition) \
   GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \
                       GTEST_NONFATAL_FAILURE_)
-#define ASSERT_TRUE(condition) \
+#define GTEST_ASSERT_TRUE(condition) \
   GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \
                       GTEST_FATAL_FAILURE_)
-#define ASSERT_FALSE(condition) \
+#define GTEST_ASSERT_FALSE(condition) \
   GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \
                       GTEST_FATAL_FAILURE_)
 
+// Define these macros to 1 to omit the definition of the corresponding
+// EXPECT or ASSERT, which clashes with some users' own code.
+
+#if !GTEST_DONT_DEFINE_EXPECT_TRUE
+#define EXPECT_TRUE(condition) GTEST_EXPECT_TRUE(condition)
+#endif
+
+#if !GTEST_DONT_DEFINE_EXPECT_FALSE
+#define EXPECT_FALSE(condition) GTEST_EXPECT_FALSE(condition)
+#endif
+
+#if !GTEST_DONT_DEFINE_ASSERT_TRUE
+#define ASSERT_TRUE(condition) GTEST_ASSERT_TRUE(condition)
+#endif
+
+#if !GTEST_DONT_DEFINE_ASSERT_FALSE
+#define ASSERT_FALSE(condition) GTEST_ASSERT_FALSE(condition)
+#endif
+
 // Macros for testing equalities and inequalities.
 //
 //    * {ASSERT|EXPECT}_EQ(v1, v2): Tests that v1 == v2
@@ -14659,9 +11923,7 @@
 //   ASSERT_GT(records.size(), 0) << "There is no record left.";
 
 #define EXPECT_EQ(val1, val2) \
-  EXPECT_PRED_FORMAT2(::testing::internal:: \
-                      EqHelper<GTEST_IS_NULL_LITERAL_(val1)>::Compare, \
-                      val1, val2)
+  EXPECT_PRED_FORMAT2(::testing::internal::EqHelper::Compare, val1, val2)
 #define EXPECT_NE(val1, val2) \
   EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2)
 #define EXPECT_LE(val1, val2) \
@@ -14674,9 +11936,7 @@
   EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2)
 
 #define GTEST_ASSERT_EQ(val1, val2) \
-  ASSERT_PRED_FORMAT2(::testing::internal:: \
-                      EqHelper<GTEST_IS_NULL_LITERAL_(val1)>::Compare, \
-                      val1, val2)
+  ASSERT_PRED_FORMAT2(::testing::internal::EqHelper::Compare, val1, val2)
 #define GTEST_ASSERT_NE(val1, val2) \
   ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2)
 #define GTEST_ASSERT_LE(val1, val2) \
@@ -14867,12 +12127,6 @@
     PushTrace(file, line, message ? message : "(null)");
   }
 
-#if GTEST_HAS_GLOBAL_STRING
-  ScopedTrace(const char* file, int line, const ::string& message) {
-    PushTrace(file, line, message);
-  }
-#endif
-
   ScopedTrace(const char* file, int line, const std::string& message) {
     PushTrace(file, line, message);
   }
@@ -14910,10 +12164,9 @@
   ::testing::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\
     __FILE__, __LINE__, (message))
 
-
 // Compile-time assertion for type equality.
-// StaticAssertTypeEq<type1, type2>() compiles iff type1 and type2 are
-// the same type.  The value it returns is not interesting.
+// StaticAssertTypeEq<type1, type2>() compiles if and only if type1 and type2
+// are the same type.  The value it returns is not interesting.
 //
 // Instead of making StaticAssertTypeEq a class template, we make it a
 // function template that invokes a helper class template.  This
@@ -14942,8 +12195,8 @@
 //
 // to cause a compiler error.
 template <typename T1, typename T2>
-bool StaticAssertTypeEq() {
-  (void)internal::StaticAssertTypeEqHelper<T1, T2>();
+constexpr bool StaticAssertTypeEq() noexcept {
+  static_assert(std::is_same<T1, T2>::value, "T1 and T2 are not the same type");
   return true;
 }
 
@@ -15009,9 +12262,11 @@
 //   }
 //
 // GOOGLETEST_CM0011 DO NOT DELETE
+#if !GTEST_DONT_DEFINE_TEST
 #define TEST_F(test_fixture, test_name)\
   GTEST_TEST_(test_fixture, test_name, test_fixture, \
               ::testing::internal::GetTypeId<test_fixture>())
+#endif  // !GTEST_DONT_DEFINE_TEST
 
 // Returns a path to temporary directory.
 // Tries to determine an appropriate directory for the platform.
@@ -15096,8 +12351,8 @@
   return internal::MakeAndRegisterTestInfo(
       test_suite_name, test_name, type_param, value_param,
       internal::CodeLocation(file, line), internal::GetTypeId<TestT>(),
-      internal::SuiteApiResolver<TestT>::GetSetUpCaseOrSuite(),
-      internal::SuiteApiResolver<TestT>::GetTearDownCaseOrSuite(),
+      internal::SuiteApiResolver<TestT>::GetSetUpCaseOrSuite(file, line),
+      internal::SuiteApiResolver<TestT>::GetTearDownCaseOrSuite(file, line),
       new FactoryImpl{std::move(factory)});
 }
 
@@ -15119,4 +12374,4 @@
 
 GTEST_DISABLE_MSC_WARNINGS_POP_()  //  4251
 
-#endif  // GTEST_INCLUDE_GTEST_GTEST_H_
+#endif  // GOOGLETEST_INCLUDE_GTEST_GTEST_H_
diff --git a/third_party/ceres/internal/ceres/householder_vector_test.cc b/third_party/ceres/internal/ceres/householder_vector_test.cc
index 6f3b172..7d69789 100644
--- a/third_party/ceres/internal/ceres/householder_vector_test.cc
+++ b/third_party/ceres/internal/ceres/householder_vector_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://code.google.com/p/ceres-solver/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -34,8 +34,7 @@
 #include "glog/logging.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 static void HouseholderTestHelper(const Vector& x) {
   const double kTolerance = 1e-14;
@@ -116,5 +115,4 @@
   HouseholderTestHelper(x);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/implicit_schur_complement.cc b/third_party/ceres/internal/ceres/implicit_schur_complement.cc
index f2196d4..a633529 100644
--- a/third_party/ceres/internal/ceres/implicit_schur_complement.cc
+++ b/third_party/ceres/internal/ceres/implicit_schur_complement.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,36 +35,40 @@
 #include "ceres/block_structure.h"
 #include "ceres/internal/eigen.h"
 #include "ceres/linear_solver.h"
+#include "ceres/parallel_for.h"
+#include "ceres/parallel_vector_ops.h"
 #include "ceres/types.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 ImplicitSchurComplement::ImplicitSchurComplement(
     const LinearSolver::Options& options)
-    : options_(options), D_(NULL), b_(NULL) {}
-
-ImplicitSchurComplement::~ImplicitSchurComplement() {}
+    : options_(options) {}
 
 void ImplicitSchurComplement::Init(const BlockSparseMatrix& A,
                                    const double* D,
                                    const double* b) {
   // Since initialization is reasonably heavy, perhaps we can save on
   // constructing a new object everytime.
-  if (A_ == NULL) {
-    A_.reset(PartitionedMatrixViewBase::Create(options_, A));
+  if (A_ == nullptr) {
+    A_ = PartitionedMatrixViewBase::Create(options_, A);
   }
 
   D_ = D;
   b_ = b;
 
+  compute_ftf_inverse_ =
+      options_.use_spse_initialization ||
+      options_.preconditioner_type == JACOBI ||
+      options_.preconditioner_type == SCHUR_POWER_SERIES_EXPANSION;
+
   // Initialize temporary storage and compute the block diagonals of
   // E'E and F'E.
-  if (block_diagonal_EtE_inverse_ == NULL) {
-    block_diagonal_EtE_inverse_.reset(A_->CreateBlockDiagonalEtE());
-    if (options_.preconditioner_type == JACOBI) {
-      block_diagonal_FtF_inverse_.reset(A_->CreateBlockDiagonalFtF());
+  if (block_diagonal_EtE_inverse_ == nullptr) {
+    block_diagonal_EtE_inverse_ = A_->CreateBlockDiagonalEtE();
+    if (compute_ftf_inverse_) {
+      block_diagonal_FtF_inverse_ = A_->CreateBlockDiagonalFtF();
     }
     rhs_.resize(A_->num_cols_f());
     rhs_.setZero();
@@ -74,7 +78,7 @@
     tmp_f_cols_.resize(A_->num_cols_f());
   } else {
     A_->UpdateBlockDiagonalEtE(block_diagonal_EtE_inverse_.get());
-    if (options_.preconditioner_type == JACOBI) {
+    if (compute_ftf_inverse_) {
       A_->UpdateBlockDiagonalFtF(block_diagonal_FtF_inverse_.get());
     }
   }
@@ -83,8 +87,8 @@
   // contributions from the diagonal D if it is non-null. Add that to
   // the block diagonals and invert them.
   AddDiagonalAndInvert(D_, block_diagonal_EtE_inverse_.get());
-  if (options_.preconditioner_type == JACOBI) {
-    AddDiagonalAndInvert((D_ == NULL) ? NULL : D_ + A_->num_cols_e(),
+  if (compute_ftf_inverse_) {
+    AddDiagonalAndInvert((D_ == nullptr) ? nullptr : D_ + A_->num_cols_e(),
                          block_diagonal_FtF_inverse_.get());
   }
 
@@ -99,36 +103,74 @@
 // By breaking it down into individual matrix vector products
 // involving the matrices E and F. This is implemented using a
 // PartitionedMatrixView of the input matrix A.
-void ImplicitSchurComplement::RightMultiply(const double* x, double* y) const {
+void ImplicitSchurComplement::RightMultiplyAndAccumulate(const double* x,
+                                                         double* y) const {
   // y1 = F x
-  tmp_rows_.setZero();
-  A_->RightMultiplyF(x, tmp_rows_.data());
+  ParallelSetZero(options_.context, options_.num_threads, tmp_rows_);
+  A_->RightMultiplyAndAccumulateF(x, tmp_rows_.data());
 
   // y2 = E' y1
-  tmp_e_cols_.setZero();
-  A_->LeftMultiplyE(tmp_rows_.data(), tmp_e_cols_.data());
+  ParallelSetZero(options_.context, options_.num_threads, tmp_e_cols_);
+  A_->LeftMultiplyAndAccumulateE(tmp_rows_.data(), tmp_e_cols_.data());
 
   // y3 = -(E'E)^-1 y2
-  tmp_e_cols_2_.setZero();
-  block_diagonal_EtE_inverse_->RightMultiply(tmp_e_cols_.data(),
-                                             tmp_e_cols_2_.data());
-  tmp_e_cols_2_ *= -1.0;
+  ParallelSetZero(options_.context, options_.num_threads, tmp_e_cols_2_);
+  block_diagonal_EtE_inverse_->RightMultiplyAndAccumulate(tmp_e_cols_.data(),
+                                                          tmp_e_cols_2_.data(),
+                                                          options_.context,
+                                                          options_.num_threads);
+
+  ParallelAssign(
+      options_.context, options_.num_threads, tmp_e_cols_2_, -tmp_e_cols_2_);
 
   // y1 = y1 + E y3
-  A_->RightMultiplyE(tmp_e_cols_2_.data(), tmp_rows_.data());
+  A_->RightMultiplyAndAccumulateE(tmp_e_cols_2_.data(), tmp_rows_.data());
 
   // y5 = D * x
-  if (D_ != NULL) {
+  if (D_ != nullptr) {
     ConstVectorRef Dref(D_ + A_->num_cols_e(), num_cols());
-    VectorRef(y, num_cols()) =
-        (Dref.array().square() * ConstVectorRef(x, num_cols()).array())
-            .matrix();
+    VectorRef y_cols(y, num_cols());
+    ParallelAssign(
+        options_.context,
+        options_.num_threads,
+        y_cols,
+        (Dref.array().square() * ConstVectorRef(x, num_cols()).array()));
   } else {
-    VectorRef(y, num_cols()).setZero();
+    ParallelSetZero(options_.context, options_.num_threads, y, num_cols());
   }
 
   // y = y5 + F' y1
-  A_->LeftMultiplyF(tmp_rows_.data(), y);
+  A_->LeftMultiplyAndAccumulateF(tmp_rows_.data(), y);
+}
+
+void ImplicitSchurComplement::InversePowerSeriesOperatorRightMultiplyAccumulate(
+    const double* x, double* y) const {
+  CHECK(compute_ftf_inverse_);
+  // y1 = F x
+  ParallelSetZero(options_.context, options_.num_threads, tmp_rows_);
+  A_->RightMultiplyAndAccumulateF(x, tmp_rows_.data());
+
+  // y2 = E' y1
+  ParallelSetZero(options_.context, options_.num_threads, tmp_e_cols_);
+  A_->LeftMultiplyAndAccumulateE(tmp_rows_.data(), tmp_e_cols_.data());
+
+  // y3 = (E'E)^-1 y2
+  ParallelSetZero(options_.context, options_.num_threads, tmp_e_cols_2_);
+  block_diagonal_EtE_inverse_->RightMultiplyAndAccumulate(tmp_e_cols_.data(),
+                                                          tmp_e_cols_2_.data(),
+                                                          options_.context,
+                                                          options_.num_threads);
+  // y1 = E y3
+  ParallelSetZero(options_.context, options_.num_threads, tmp_rows_);
+  A_->RightMultiplyAndAccumulateE(tmp_e_cols_2_.data(), tmp_rows_.data());
+
+  // y4 = F' y1
+  ParallelSetZero(options_.context, options_.num_threads, tmp_f_cols_);
+  A_->LeftMultiplyAndAccumulateF(tmp_rows_.data(), tmp_f_cols_.data());
+
+  // y += (F'F)^-1 y4
+  block_diagonal_FtF_inverse_->RightMultiplyAndAccumulate(
+      tmp_f_cols_.data(), y, options_.context, options_.num_threads);
 }
 
 // Given a block diagonal matrix and an optional array of diagonal
@@ -138,26 +180,31 @@
     const double* D, BlockSparseMatrix* block_diagonal) {
   const CompressedRowBlockStructure* block_diagonal_structure =
       block_diagonal->block_structure();
-  for (int r = 0; r < block_diagonal_structure->rows.size(); ++r) {
-    const int row_block_pos = block_diagonal_structure->rows[r].block.position;
-    const int row_block_size = block_diagonal_structure->rows[r].block.size;
-    const Cell& cell = block_diagonal_structure->rows[r].cells[0];
-    MatrixRef m(block_diagonal->mutable_values() + cell.position,
-                row_block_size,
-                row_block_size);
+  ParallelFor(options_.context,
+              0,
+              block_diagonal_structure->rows.size(),
+              options_.num_threads,
+              [block_diagonal_structure, D, block_diagonal](int row_block_id) {
+                auto& row = block_diagonal_structure->rows[row_block_id];
+                const int row_block_pos = row.block.position;
+                const int row_block_size = row.block.size;
+                const Cell& cell = row.cells[0];
+                MatrixRef m(block_diagonal->mutable_values() + cell.position,
+                            row_block_size,
+                            row_block_size);
 
-    if (D != NULL) {
-      ConstVectorRef d(D + row_block_pos, row_block_size);
-      m += d.array().square().matrix().asDiagonal();
-    }
+                if (D != nullptr) {
+                  ConstVectorRef d(D + row_block_pos, row_block_size);
+                  m += d.array().square().matrix().asDiagonal();
+                }
 
-    m = m.selfadjointView<Eigen::Upper>().llt().solve(
-        Matrix::Identity(row_block_size, row_block_size));
-  }
+                m = m.selfadjointView<Eigen::Upper>().llt().solve(
+                    Matrix::Identity(row_block_size, row_block_size));
+              });
 }
 
-// Similar to RightMultiply, use the block structure of the matrix A
-// to compute y = (E'E)^-1 (E'b - E'F x).
+// Similar to RightMultiplyAndAccumulate, use the block structure of the matrix
+// A to compute y = (E'E)^-1 (E'b - E'F x).
 void ImplicitSchurComplement::BackSubstitute(const double* x, double* y) {
   const int num_cols_e = A_->num_cols_e();
   const int num_cols_f = A_->num_cols_f();
@@ -165,26 +212,34 @@
   const int num_rows = A_->num_rows();
 
   // y1 = F x
-  tmp_rows_.setZero();
-  A_->RightMultiplyF(x, tmp_rows_.data());
+  ParallelSetZero(options_.context, options_.num_threads, tmp_rows_);
+  A_->RightMultiplyAndAccumulateF(x, tmp_rows_.data());
 
   // y2 = b - y1
-  tmp_rows_ = ConstVectorRef(b_, num_rows) - tmp_rows_;
+  ParallelAssign(options_.context,
+                 options_.num_threads,
+                 tmp_rows_,
+                 ConstVectorRef(b_, num_rows) - tmp_rows_);
 
   // y3 = E' y2
-  tmp_e_cols_.setZero();
-  A_->LeftMultiplyE(tmp_rows_.data(), tmp_e_cols_.data());
+  ParallelSetZero(options_.context, options_.num_threads, tmp_e_cols_);
+  A_->LeftMultiplyAndAccumulateE(tmp_rows_.data(), tmp_e_cols_.data());
 
   // y = (E'E)^-1 y3
-  VectorRef(y, num_cols).setZero();
-  block_diagonal_EtE_inverse_->RightMultiply(tmp_e_cols_.data(), y);
+  ParallelSetZero(options_.context, options_.num_threads, y, num_cols);
+  block_diagonal_EtE_inverse_->RightMultiplyAndAccumulate(
+      tmp_e_cols_.data(), y, options_.context, options_.num_threads);
 
   // The full solution vector y has two blocks. The first block of
   // variables corresponds to the eliminated variables, which we just
   // computed via back substitution. The second block of variables
   // corresponds to the Schur complement system, so we just copy those
   // values from the solution to the Schur complement.
-  VectorRef(y + num_cols_e, num_cols_f) = ConstVectorRef(x, num_cols_f);
+  VectorRef y_cols_f(y + num_cols_e, num_cols_f);
+  ParallelAssign(options_.context,
+                 options_.num_threads,
+                 y_cols_f,
+                 ConstVectorRef(x, num_cols_f));
 }
 
 // Compute the RHS of the Schur complement system.
@@ -195,24 +250,29 @@
 // this using a series of matrix vector products.
 void ImplicitSchurComplement::UpdateRhs() {
   // y1 = E'b
-  tmp_e_cols_.setZero();
-  A_->LeftMultiplyE(b_, tmp_e_cols_.data());
+  ParallelSetZero(options_.context, options_.num_threads, tmp_e_cols_);
+  A_->LeftMultiplyAndAccumulateE(b_, tmp_e_cols_.data());
 
   // y2 = (E'E)^-1 y1
-  Vector y2 = Vector::Zero(A_->num_cols_e());
-  block_diagonal_EtE_inverse_->RightMultiply(tmp_e_cols_.data(), y2.data());
+  ParallelSetZero(options_.context, options_.num_threads, tmp_e_cols_2_);
+  block_diagonal_EtE_inverse_->RightMultiplyAndAccumulate(tmp_e_cols_.data(),
+                                                          tmp_e_cols_2_.data(),
+                                                          options_.context,
+                                                          options_.num_threads);
 
   // y3 = E y2
-  tmp_rows_.setZero();
-  A_->RightMultiplyE(y2.data(), tmp_rows_.data());
+  ParallelSetZero(options_.context, options_.num_threads, tmp_rows_);
+  A_->RightMultiplyAndAccumulateE(tmp_e_cols_2_.data(), tmp_rows_.data());
 
   // y3 = b - y3
-  tmp_rows_ = ConstVectorRef(b_, A_->num_rows()) - tmp_rows_;
+  ParallelAssign(options_.context,
+                 options_.num_threads,
+                 tmp_rows_,
+                 ConstVectorRef(b_, A_->num_rows()) - tmp_rows_);
 
   // rhs = F' y3
-  rhs_.setZero();
-  A_->LeftMultiplyF(tmp_rows_.data(), rhs_.data());
+  ParallelSetZero(options_.context, options_.num_threads, rhs_);
+  A_->LeftMultiplyAndAccumulateF(tmp_rows_.data(), rhs_.data());
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/implicit_schur_complement.h b/third_party/ceres/internal/ceres/implicit_schur_complement.h
index e83892a..b4eb0b0 100644
--- a/third_party/ceres/internal/ceres/implicit_schur_complement.h
+++ b/third_party/ceres/internal/ceres/implicit_schur_complement.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -36,15 +36,15 @@
 
 #include <memory>
 
+#include "ceres/internal/disable_warnings.h"
 #include "ceres/internal/eigen.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 #include "ceres/linear_operator.h"
 #include "ceres/linear_solver.h"
 #include "ceres/partitioned_matrix_view.h"
 #include "ceres/types.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 class BlockSparseMatrix;
 
@@ -81,14 +81,14 @@
 // (which for our purposes is an easily inverted block diagonal
 // matrix), it can be done in terms of matrix vector products with E,
 // F and (E'E)^-1. This class implements this functionality and other
-// auxilliary bits needed to implement a CG solver on the Schur
+// auxiliary bits needed to implement a CG solver on the Schur
 // complement using the PartitionedMatrixView object.
 //
-// THREAD SAFETY: This class is nqot thread safe. In particular, the
-// RightMultiply (and the LeftMultiply) methods are not thread safe as
-// they depend on mutable arrays used for the temporaries needed to
-// compute the product y += Sx;
-class CERES_EXPORT_INTERNAL ImplicitSchurComplement : public LinearOperator {
+// THREAD SAFETY: This class is not thread safe. In particular, the
+// RightMultiplyAndAccumulate (and the LeftMultiplyAndAccumulate) methods are
+// not thread safe as they depend on mutable arrays used for the temporaries
+// needed to compute the product y += Sx;
+class CERES_NO_EXPORT ImplicitSchurComplement final : public LinearOperator {
  public:
   // num_eliminate_blocks is the number of E blocks in the matrix
   // A.
@@ -100,7 +100,6 @@
   // TODO(sameeragarwal): Get rid of the two bools below and replace
   // them with enums.
   explicit ImplicitSchurComplement(const LinearSolver::Options& options);
-  virtual ~ImplicitSchurComplement();
 
   // Initialize the Schur complement for a linear least squares
   // problem of the form
@@ -115,14 +114,20 @@
   void Init(const BlockSparseMatrix& A, const double* D, const double* b);
 
   // y += Sx, where S is the Schur complement.
-  void RightMultiply(const double* x, double* y) const final;
+  void RightMultiplyAndAccumulate(const double* x, double* y) const final;
 
   // The Schur complement is a symmetric positive definite matrix,
   // thus the left and right multiply operators are the same.
-  void LeftMultiply(const double* x, double* y) const final {
-    RightMultiply(x, y);
+  void LeftMultiplyAndAccumulate(const double* x, double* y) const final {
+    RightMultiplyAndAccumulate(x, y);
   }
 
+  // Following is useful for approximation of S^-1 via power series expansion.
+  // Z = (F'F)^-1 F'E (E'E)^-1 E'F
+  // y += Zx
+  void InversePowerSeriesOperatorRightMultiplyAccumulate(const double* x,
+                                                         double* y) const;
+
   // y = (E'E)^-1 (E'b - E'F x). Given an estimate of the solution to
   // the Schur complement system, this method computes the value of
   // the e_block variables that were eliminated to form the Schur
@@ -138,6 +143,7 @@
   }
 
   const BlockSparseMatrix* block_diagonal_FtF_inverse() const {
+    CHECK(compute_ftf_inverse_);
     return block_diagonal_FtF_inverse_.get();
   }
 
@@ -146,24 +152,25 @@
   void UpdateRhs();
 
   const LinearSolver::Options& options_;
-
+  bool compute_ftf_inverse_ = false;
   std::unique_ptr<PartitionedMatrixViewBase> A_;
-  const double* D_;
-  const double* b_;
+  const double* D_ = nullptr;
+  const double* b_ = nullptr;
 
   std::unique_ptr<BlockSparseMatrix> block_diagonal_EtE_inverse_;
   std::unique_ptr<BlockSparseMatrix> block_diagonal_FtF_inverse_;
 
   Vector rhs_;
 
-  // Temporary storage vectors used to implement RightMultiply.
+  // Temporary storage vectors used to implement RightMultiplyAndAccumulate.
   mutable Vector tmp_rows_;
   mutable Vector tmp_e_cols_;
   mutable Vector tmp_e_cols_2_;
   mutable Vector tmp_f_cols_;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_IMPLICIT_SCHUR_COMPLEMENT_H_
diff --git a/third_party/ceres/internal/ceres/implicit_schur_complement_test.cc b/third_party/ceres/internal/ceres/implicit_schur_complement_test.cc
index b6d886f..35519fc 100644
--- a/third_party/ceres/internal/ceres/implicit_schur_complement_test.cc
+++ b/third_party/ceres/internal/ceres/implicit_schur_complement_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -47,8 +47,7 @@
 #include "glog/logging.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 using testing::AssertionResult;
 
@@ -57,13 +56,12 @@
 class ImplicitSchurComplementTest : public ::testing::Test {
  protected:
   void SetUp() final {
-    std::unique_ptr<LinearLeastSquaresProblem> problem(
-        CreateLinearLeastSquaresProblemFromId(2));
+    auto problem = CreateLinearLeastSquaresProblemFromId(2);
 
     CHECK(problem != nullptr);
     A_.reset(down_cast<BlockSparseMatrix*>(problem->A.release()));
-    b_.reset(problem->b.release());
-    D_.reset(problem->D.release());
+    b_ = std::move(problem->b);
+    D_ = std::move(problem->D);
 
     num_cols_ = A_->num_cols();
     num_rows_ = A_->num_rows();
@@ -76,12 +74,8 @@
                                       Vector* solution) {
     const CompressedRowBlockStructure* bs = A_->block_structure();
     const int num_col_blocks = bs->cols.size();
-    std::vector<int> blocks(num_col_blocks - num_eliminate_blocks_, 0);
-    for (int i = num_eliminate_blocks_; i < num_col_blocks; ++i) {
-      blocks[i - num_eliminate_blocks_] = bs->cols[i].size;
-    }
-
-    BlockRandomAccessDenseMatrix blhs(blocks);
+    auto blocks = Tail(bs->cols, num_col_blocks - num_eliminate_blocks_);
+    BlockRandomAccessDenseMatrix blhs(blocks, &context_, 1);
     const int num_schur_rows = blhs.num_rows();
 
     LinearSolver::Options options;
@@ -90,8 +84,8 @@
     ContextImpl context;
     options.context = &context;
 
-    std::unique_ptr<SchurEliminatorBase> eliminator(
-        SchurEliminatorBase::Create(options));
+    std::unique_ptr<SchurEliminatorBase> eliminator =
+        SchurEliminatorBase::Create(options);
     CHECK(eliminator != nullptr);
     const bool kFullRankETE = true;
     eliminator->Init(num_eliminate_blocks_, kFullRankETE, bs);
@@ -137,18 +131,38 @@
     ImplicitSchurComplement isc(options);
     isc.Init(*A_, D, b_.get());
 
-    int num_sc_cols = lhs.cols();
+    const int num_f_cols = lhs.cols();
+    const int num_e_cols = num_cols_ - num_f_cols;
 
-    for (int i = 0; i < num_sc_cols; ++i) {
-      Vector x(num_sc_cols);
+    Matrix A_dense, E, F, DE, DF;
+    A_->ToDenseMatrix(&A_dense);
+    E = A_dense.leftCols(A_->num_cols() - num_f_cols);
+    F = A_dense.rightCols(num_f_cols);
+    if (D) {
+      DE = VectorRef(D, num_e_cols).asDiagonal();
+      DF = VectorRef(D + num_e_cols, num_f_cols).asDiagonal();
+    } else {
+      DE = Matrix::Zero(num_e_cols, num_e_cols);
+      DF = Matrix::Zero(num_f_cols, num_f_cols);
+    }
+
+    // Z = (block_diagonal(F'F))^-1 F'E (E'E)^-1 E'F
+    // Here, assuming that block_diagonal(F'F) == diagonal(F'F)
+    Matrix Z_reference =
+        (F.transpose() * F + DF).diagonal().asDiagonal().inverse() *
+        F.transpose() * E * (E.transpose() * E + DE).inverse() * E.transpose() *
+        F;
+
+    for (int i = 0; i < num_f_cols; ++i) {
+      Vector x(num_f_cols);
       x.setZero();
       x(i) = 1.0;
 
-      Vector y(num_sc_cols);
+      Vector y(num_f_cols);
       y = lhs * x;
 
-      Vector z(num_sc_cols);
-      isc.RightMultiply(x.data(), z.data());
+      Vector z(num_f_cols);
+      isc.RightMultiplyAndAccumulate(x.data(), z.data());
 
       // The i^th column of the implicit schur complement is the same as
       // the explicit schur complement.
@@ -158,6 +172,22 @@
                << "column " << i << ". explicit: " << y.transpose()
                << " implicit: " << z.transpose();
       }
+
+      y.setZero();
+      y = Z_reference * x;
+      z.setZero();
+      isc.InversePowerSeriesOperatorRightMultiplyAccumulate(x.data(), z.data());
+
+      // The i^th column of operator Z stored implicitly is the same as its
+      // explicit version.
+      if ((y - z).norm() > kEpsilon) {
+        return testing::AssertionFailure()
+               << "Explicit and Implicit operators used to approximate the "
+                  "inversion of schur complement via power series expansion "
+                  "differ in column "
+               << i << ". explicit: " << y.transpose()
+               << " implicit: " << z.transpose();
+      }
     }
 
     // Compare the rhs of the reduced linear system
@@ -186,6 +216,7 @@
     return testing::AssertionSuccess();
   }
 
+  ContextImpl context_;
   int num_rows_;
   int num_cols_;
   int num_eliminate_blocks_;
@@ -202,9 +233,8 @@
 // We do this with and without regularization to check that the
 // support for the LM diagonal is correct.
 TEST_F(ImplicitSchurComplementTest, SchurMatrixValuesTest) {
-  EXPECT_TRUE(TestImplicitSchurComplement(NULL));
+  EXPECT_TRUE(TestImplicitSchurComplement(nullptr));
   EXPECT_TRUE(TestImplicitSchurComplement(D_.get()));
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/inner_product_computer.cc b/third_party/ceres/internal/ceres/inner_product_computer.cc
index ef38b7b..59b5d94 100644
--- a/third_party/ceres/internal/ceres/inner_product_computer.cc
+++ b/third_party/ceres/internal/ceres/inner_product_computer.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -31,11 +31,11 @@
 #include "ceres/inner_product_computer.h"
 
 #include <algorithm>
+#include <memory>
 
 #include "ceres/small_blas.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // Create the CompressedRowSparseMatrix matrix that will contain the
 // inner product.
@@ -44,22 +44,16 @@
 // or the lower triangular part of the product.
 //
 // num_nonzeros is the number of non-zeros in the result matrix.
-CompressedRowSparseMatrix* InnerProductComputer::CreateResultMatrix(
+std::unique_ptr<CompressedRowSparseMatrix>
+InnerProductComputer::CreateResultMatrix(
     const CompressedRowSparseMatrix::StorageType storage_type,
     const int num_nonzeros) {
-  CompressedRowSparseMatrix* matrix =
-      new CompressedRowSparseMatrix(m_.num_cols(), m_.num_cols(), num_nonzeros);
+  auto matrix = std::make_unique<CompressedRowSparseMatrix>(
+      m_.num_cols(), m_.num_cols(), num_nonzeros);
   matrix->set_storage_type(storage_type);
-
   const CompressedRowBlockStructure* bs = m_.block_structure();
-  const std::vector<Block>& blocks = bs->cols;
-  matrix->mutable_row_blocks()->resize(blocks.size());
-  matrix->mutable_col_blocks()->resize(blocks.size());
-  for (int i = 0; i < blocks.size(); ++i) {
-    (*(matrix->mutable_row_blocks()))[i] = blocks[i].size;
-    (*(matrix->mutable_col_blocks()))[i] = blocks[i].size;
-  }
-
+  *matrix->mutable_row_blocks() = bs->cols;
+  *matrix->mutable_col_blocks() = bs->cols;
   return matrix;
 }
 
@@ -76,6 +70,10 @@
   row_nnz->resize(blocks.size());
   std::fill(row_nnz->begin(), row_nnz->end(), 0);
 
+  if (product_terms.empty()) {
+    return 0;
+  }
+
   // First product term.
   (*row_nnz)[product_terms[0].row] = blocks[product_terms[0].col].size;
   int num_nonzeros =
@@ -116,24 +114,26 @@
 //
 // product_storage_type controls the form of the output matrix. It
 // can be LOWER_TRIANGULAR or UPPER_TRIANGULAR.
-InnerProductComputer* InnerProductComputer::Create(
+std::unique_ptr<InnerProductComputer> InnerProductComputer::Create(
     const BlockSparseMatrix& m,
     CompressedRowSparseMatrix::StorageType product_storage_type) {
   return InnerProductComputer::Create(
       m, 0, m.block_structure()->rows.size(), product_storage_type);
 }
 
-InnerProductComputer* InnerProductComputer::Create(
+std::unique_ptr<InnerProductComputer> InnerProductComputer::Create(
     const BlockSparseMatrix& m,
     const int start_row_block,
     const int end_row_block,
     CompressedRowSparseMatrix::StorageType product_storage_type) {
-  CHECK(product_storage_type == CompressedRowSparseMatrix::LOWER_TRIANGULAR ||
-        product_storage_type == CompressedRowSparseMatrix::UPPER_TRIANGULAR);
+  CHECK(product_storage_type ==
+            CompressedRowSparseMatrix::StorageType::LOWER_TRIANGULAR ||
+        product_storage_type ==
+            CompressedRowSparseMatrix::StorageType::UPPER_TRIANGULAR);
   CHECK_GT(m.num_nonzeros(), 0)
       << "Congratulations, you found a bug in Ceres. Please report it.";
-  InnerProductComputer* inner_product_computer =
-      new InnerProductComputer(m, start_row_block, end_row_block);
+  std::unique_ptr<InnerProductComputer> inner_product_computer(
+      new InnerProductComputer(m, start_row_block, end_row_block));
   inner_product_computer->Init(product_storage_type);
   return inner_product_computer;
 }
@@ -155,7 +155,8 @@
     for (int c1 = 0; c1 < row.cells.size(); ++c1) {
       const Cell& cell1 = row.cells[c1];
       int c2_begin, c2_end;
-      if (product_storage_type == CompressedRowSparseMatrix::LOWER_TRIANGULAR) {
+      if (product_storage_type ==
+          CompressedRowSparseMatrix::StorageType::LOWER_TRIANGULAR) {
         c2_begin = 0;
         c2_end = c1 + 1;
       } else {
@@ -165,8 +166,8 @@
 
       for (int c2 = c2_begin; c2 < c2_end; ++c2) {
         const Cell& cell2 = row.cells[c2];
-        product_terms.push_back(InnerProductComputer::ProductTerm(
-            cell1.block_id, cell2.block_id, product_terms.size()));
+        product_terms.emplace_back(
+            cell1.block_id, cell2.block_id, product_terms.size());
       }
     }
   }
@@ -183,7 +184,7 @@
   std::vector<int> row_block_nnz;
   const int num_nonzeros = ComputeNonzeros(product_terms, &row_block_nnz);
 
-  result_.reset(CreateResultMatrix(product_storage_type, num_nonzeros));
+  result_ = CreateResultMatrix(product_storage_type, num_nonzeros);
 
   // Populate the row non-zero counts in the result matrix.
   int* crsm_rows = result_->mutable_rows();
@@ -193,6 +194,10 @@
       *(crsm_rows + 1) = *crsm_rows + row_block_nnz[i];
     }
   }
+  result_offsets_.resize(product_terms.size());
+  if (num_nonzeros == 0) {
+    return;
+  }
 
   // The following macro FILL_CRSM_COL_BLOCK is key to understanding
   // how this class works.
@@ -239,12 +244,11 @@
     }                                                      \
   }
 
-  result_offsets_.resize(product_terms.size());
   int col_nnz = 0;
   int nnz = 0;
 
   // Process the first term.
-  const InnerProductComputer::ProductTerm* current = &product_terms[0];
+  const InnerProductComputer::ProductTerm* current = product_terms.data();
   FILL_CRSM_COL_BLOCK;
 
   // Process the rest of the terms.
@@ -262,7 +266,7 @@
     if (previous->row == current->row) {
       // if the current and previous terms are in the same row block,
       // then they differ in the column block, in which case advance
-      // col_nnz by the column size of the prevous term.
+      // col_nnz by the column size of the previous term.
       col_nnz += col_blocks[previous->col].size;
     } else {
       // If we have moved to a new row-block , then col_nnz is zero,
@@ -300,7 +304,8 @@
                           rows[bs->cols[cell1.block_id].position];
 
       int c2_begin, c2_end;
-      if (storage_type == CompressedRowSparseMatrix::LOWER_TRIANGULAR) {
+      if (storage_type ==
+          CompressedRowSparseMatrix::StorageType::LOWER_TRIANGULAR) {
         c2_begin = 0;
         c2_end = c1 + 1;
       } else {
@@ -328,5 +333,4 @@
   CHECK_EQ(cursor, result_offsets_.size());
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/inner_product_computer.h b/third_party/ceres/internal/ceres/inner_product_computer.h
index 04ec1d1..c1c0a34 100644
--- a/third_party/ceres/internal/ceres/inner_product_computer.h
+++ b/third_party/ceres/internal/ceres/inner_product_computer.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -36,10 +36,10 @@
 
 #include "ceres/block_sparse_matrix.h"
 #include "ceres/compressed_row_sparse_matrix.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // This class is used to repeatedly compute the inner product
 //
@@ -61,7 +61,7 @@
 // This is not a problem as sparse linear algebra libraries can ignore
 // these entries with ease and the space used is minimal/linear in the
 // size of the matrices.
-class CERES_EXPORT_INTERNAL InnerProductComputer {
+class CERES_NO_EXPORT InnerProductComputer {
  public:
   // Factory
   //
@@ -74,7 +74,7 @@
   //
   // The user must ensure that the matrix m is valid for the life time
   // of this object.
-  static InnerProductComputer* Create(
+  static std::unique_ptr<InnerProductComputer> Create(
       const BlockSparseMatrix& m,
       CompressedRowSparseMatrix::StorageType storage_type);
 
@@ -83,7 +83,7 @@
   //
   // a = m(start_row_block : end_row_block, :);
   // result = a' * a;
-  static InnerProductComputer* Create(
+  static std::unique_ptr<InnerProductComputer> Create(
       const BlockSparseMatrix& m,
       int start_row_block,
       int end_row_block,
@@ -127,7 +127,7 @@
 
   void Init(CompressedRowSparseMatrix::StorageType storage_type);
 
-  CompressedRowSparseMatrix* CreateResultMatrix(
+  std::unique_ptr<CompressedRowSparseMatrix> CreateResultMatrix(
       const CompressedRowSparseMatrix::StorageType storage_type,
       int num_nonzeros);
 
@@ -152,7 +152,8 @@
   std::vector<int> result_offsets_;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_INNER_PRODUCT_COMPUTER_H_
diff --git a/third_party/ceres/internal/ceres/inner_product_computer_test.cc b/third_party/ceres/internal/ceres/inner_product_computer_test.cc
index ac564f4..89fe518 100644
--- a/third_party/ceres/internal/ceres/inner_product_computer_test.cc
+++ b/third_party/ceres/internal/ceres/inner_product_computer_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -32,11 +32,11 @@
 
 #include <memory>
 #include <numeric>
+#include <random>
 
 #include "Eigen/SparseCore"
 #include "ceres/block_sparse_matrix.h"
 #include "ceres/internal/eigen.h"
-#include "ceres/random.h"
 #include "ceres/triplet_sparse_matrix.h"
 #include "glog/logging.h"
 #include "gtest/gtest.h"
@@ -44,44 +44,44 @@
 namespace ceres {
 namespace internal {
 
-#define COMPUTE_AND_COMPARE                                                  \
-  {                                                                          \
-    inner_product_computer->Compute();                                       \
-    CompressedRowSparseMatrix* actual_product_crsm =                         \
-        inner_product_computer->mutable_result();                            \
-    Matrix actual_inner_product =                                            \
-        Eigen::MappedSparseMatrix<double, Eigen::ColMajor>(                  \
-            actual_product_crsm->num_rows(),                                 \
-            actual_product_crsm->num_rows(),                                 \
-            actual_product_crsm->num_nonzeros(),                             \
-            actual_product_crsm->mutable_rows(),                             \
-            actual_product_crsm->mutable_cols(),                             \
-            actual_product_crsm->mutable_values());                          \
-    EXPECT_EQ(actual_inner_product.rows(), actual_inner_product.cols());     \
-    EXPECT_EQ(expected_inner_product.rows(), expected_inner_product.cols()); \
-    EXPECT_EQ(actual_inner_product.rows(), expected_inner_product.rows());   \
-    Matrix expected_t, actual_t;                                             \
-    if (actual_product_crsm->storage_type() ==                               \
-        CompressedRowSparseMatrix::LOWER_TRIANGULAR) {                       \
-      expected_t = expected_inner_product.triangularView<Eigen::Upper>();    \
-      actual_t = actual_inner_product.triangularView<Eigen::Upper>();        \
-    } else {                                                                 \
-      expected_t = expected_inner_product.triangularView<Eigen::Lower>();    \
-      actual_t = actual_inner_product.triangularView<Eigen::Lower>();        \
-    }                                                                        \
-    EXPECT_LE((expected_t - actual_t).norm() / actual_t.norm(),              \
-              100 * std::numeric_limits<double>::epsilon())                  \
-        << "expected: \n"                                                    \
-        << expected_t << "\nactual: \n"                                      \
-        << actual_t;                                                         \
+#define COMPUTE_AND_COMPARE                                                   \
+  {                                                                           \
+    inner_product_computer->Compute();                                        \
+    CompressedRowSparseMatrix* actual_product_crsm =                          \
+        inner_product_computer->mutable_result();                             \
+    Matrix actual_inner_product =                                             \
+        Eigen::Map<Eigen::SparseMatrix<double, Eigen::ColMajor>>(             \
+            actual_product_crsm->num_rows(),                                  \
+            actual_product_crsm->num_rows(),                                  \
+            actual_product_crsm->num_nonzeros(),                              \
+            actual_product_crsm->mutable_rows(),                              \
+            actual_product_crsm->mutable_cols(),                              \
+            actual_product_crsm->mutable_values());                           \
+    EXPECT_EQ(actual_inner_product.rows(), actual_inner_product.cols());      \
+    EXPECT_EQ(expected_inner_product.rows(), expected_inner_product.cols());  \
+    EXPECT_EQ(actual_inner_product.rows(), expected_inner_product.rows());    \
+    Matrix expected_t, actual_t;                                              \
+    if (actual_product_crsm->storage_type() ==                                \
+        CompressedRowSparseMatrix::StorageType::LOWER_TRIANGULAR) {           \
+      expected_t = expected_inner_product.triangularView<Eigen::Upper>();     \
+      actual_t = actual_inner_product.triangularView<Eigen::Upper>();         \
+    } else {                                                                  \
+      expected_t = expected_inner_product.triangularView<Eigen::Lower>();     \
+      actual_t = actual_inner_product.triangularView<Eigen::Lower>();         \
+    }                                                                         \
+    EXPECT_LE((expected_t - actual_t).norm(),                                 \
+              100 * std::numeric_limits<double>::epsilon() * actual_t.norm()) \
+        << "expected: \n"                                                     \
+        << expected_t << "\nactual: \n"                                       \
+        << actual_t;                                                          \
   }
 
 TEST(InnerProductComputer, NormalOperation) {
-  // "Randomly generated seed."
-  SetRandomState(29823);
   const int kMaxNumRowBlocks = 10;
   const int kMaxNumColBlocks = 10;
   const int kNumTrials = 10;
+  std::mt19937 prng;
+  std::uniform_real_distribution<double> distribution(0.01, 1.0);
 
   // Create a random matrix, compute its outer product using Eigen and
   // ComputeOuterProduct. Convert both matrices to dense matrices and
@@ -98,7 +98,7 @@
         options.max_row_block_size = 5;
         options.min_col_block_size = 1;
         options.max_col_block_size = 10;
-        options.block_density = std::max(0.1, RandDouble());
+        options.block_density = distribution(prng);
 
         VLOG(2) << "num row blocks: " << options.num_row_blocks;
         VLOG(2) << "num col blocks: " << options.num_col_blocks;
@@ -109,7 +109,7 @@
         VLOG(2) << "block density: " << options.block_density;
 
         std::unique_ptr<BlockSparseMatrix> random_matrix(
-            BlockSparseMatrix::CreateRandomMatrix(options));
+            BlockSparseMatrix::CreateRandomMatrix(options, prng));
 
         TripletSparseMatrix tsm(random_matrix->num_rows(),
                                 random_matrix->num_cols(),
@@ -117,8 +117,7 @@
         random_matrix->ToTripletSparseMatrix(&tsm);
         std::vector<Eigen::Triplet<double>> triplets;
         for (int i = 0; i < tsm.num_nonzeros(); ++i) {
-          triplets.push_back(Eigen::Triplet<double>(
-              tsm.rows()[i], tsm.cols()[i], tsm.values()[i]));
+          triplets.emplace_back(tsm.rows()[i], tsm.cols()[i], tsm.values()[i]);
         }
         Eigen::SparseMatrix<double> eigen_random_matrix(
             random_matrix->num_rows(), random_matrix->num_cols());
@@ -128,11 +127,13 @@
 
         std::unique_ptr<InnerProductComputer> inner_product_computer;
 
-        inner_product_computer.reset(InnerProductComputer::Create(
-            *random_matrix, CompressedRowSparseMatrix::LOWER_TRIANGULAR));
+        inner_product_computer = InnerProductComputer::Create(
+            *random_matrix,
+            CompressedRowSparseMatrix::StorageType::LOWER_TRIANGULAR);
         COMPUTE_AND_COMPARE;
-        inner_product_computer.reset(InnerProductComputer::Create(
-            *random_matrix, CompressedRowSparseMatrix::UPPER_TRIANGULAR));
+        inner_product_computer = InnerProductComputer::Create(
+            *random_matrix,
+            CompressedRowSparseMatrix::StorageType::UPPER_TRIANGULAR);
         COMPUTE_AND_COMPARE;
       }
     }
@@ -140,11 +141,11 @@
 }
 
 TEST(InnerProductComputer, SubMatrix) {
-  // "Randomly generated seed."
-  SetRandomState(29823);
   const int kNumRowBlocks = 10;
   const int kNumColBlocks = 20;
   const int kNumTrials = 5;
+  std::mt19937 prng;
+  std::uniform_real_distribution<double> distribution(0.01, 1.0);
 
   // Create a random matrix, compute its outer product using Eigen and
   // ComputeInnerProductComputer. Convert both matrices to dense matrices and
@@ -157,7 +158,7 @@
     options.max_row_block_size = 5;
     options.min_col_block_size = 1;
     options.max_col_block_size = 10;
-    options.block_density = std::max(0.1, RandDouble());
+    options.block_density = distribution(prng);
 
     VLOG(2) << "num row blocks: " << options.num_row_blocks;
     VLOG(2) << "num col blocks: " << options.num_col_blocks;
@@ -168,7 +169,7 @@
     VLOG(2) << "block density: " << options.block_density;
 
     std::unique_ptr<BlockSparseMatrix> random_matrix(
-        BlockSparseMatrix::CreateRandomMatrix(options));
+        BlockSparseMatrix::CreateRandomMatrix(options, prng));
 
     const std::vector<CompressedRow>& row_blocks =
         random_matrix->block_structure()->rows;
@@ -189,8 +190,8 @@
         std::vector<Eigen::Triplet<double>> triplets;
         for (int i = 0; i < tsm.num_nonzeros(); ++i) {
           if (tsm.rows()[i] >= start_row && tsm.rows()[i] < end_row) {
-            triplets.push_back(Eigen::Triplet<double>(
-                tsm.rows()[i], tsm.cols()[i], tsm.values()[i]));
+            triplets.emplace_back(
+                tsm.rows()[i], tsm.cols()[i], tsm.values()[i]);
           }
         }
 
@@ -202,17 +203,17 @@
             eigen_random_matrix.transpose() * eigen_random_matrix;
 
         std::unique_ptr<InnerProductComputer> inner_product_computer;
-        inner_product_computer.reset(InnerProductComputer::Create(
+        inner_product_computer = InnerProductComputer::Create(
             *random_matrix,
             start_row_block,
             end_row_block,
-            CompressedRowSparseMatrix::LOWER_TRIANGULAR));
+            CompressedRowSparseMatrix::StorageType::LOWER_TRIANGULAR);
         COMPUTE_AND_COMPARE;
-        inner_product_computer.reset(InnerProductComputer::Create(
+        inner_product_computer = InnerProductComputer::Create(
             *random_matrix,
             start_row_block,
             end_row_block,
-            CompressedRowSparseMatrix::UPPER_TRIANGULAR));
+            CompressedRowSparseMatrix::StorageType::UPPER_TRIANGULAR);
         COMPUTE_AND_COMPARE;
       }
     }
diff --git a/third_party/ceres/internal/ceres/integer_sequence_algorithm_test.cc b/third_party/ceres/internal/ceres/integer_sequence_algorithm_test.cc
index af42a91..9666375 100644
--- a/third_party/ceres/internal/ceres/integer_sequence_algorithm_test.cc
+++ b/third_party/ceres/internal/ceres/integer_sequence_algorithm_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -27,28 +27,16 @@
 // POSSIBILITY OF SUCH DAMAGE.
 //
 // Author: jodebo_beck@gmx.de (Johannes Beck)
+//         sergiu.deitsch@gmail.com (Sergiu Deitsch)
 
 #include "ceres/internal/integer_sequence_algorithm.h"
 
 #include <type_traits>
 #include <utility>
 
-namespace ceres {
-namespace internal {
+#include "ceres/internal/jet_traits.h"
 
-// Unit tests for summation of integer sequence.
-static_assert(Sum<std::integer_sequence<int>>::Value == 0,
-              "Unit test of summing up an integer sequence failed.");
-static_assert(Sum<std::integer_sequence<int, 2>>::Value == 2,
-              "Unit test of summing up an integer sequence failed.");
-static_assert(Sum<std::integer_sequence<int, 2, 3>>::Value == 5,
-              "Unit test of summing up an integer sequence failed.");
-static_assert(Sum<std::integer_sequence<int, 2, 3, 10>>::Value == 15,
-              "Unit test of summing up an integer sequence failed.");
-static_assert(Sum<std::integer_sequence<int, 2, 3, 10, 4>>::Value == 19,
-              "Unit test of summing up an integer sequence failed.");
-static_assert(Sum<std::integer_sequence<int, 2, 3, 10, 4, 1>>::Value == 20,
-              "Unit test of summing up an integer sequence failed.");
+namespace ceres::internal {
 
 // Unit tests for exclusive scan of integer sequence.
 static_assert(std::is_same<ExclusiveScan<std::integer_sequence<int>>,
@@ -68,5 +56,83 @@
               "Unit test of calculating the exclusive scan of an integer "
               "sequence failed.");
 
-}  // namespace internal
-}  // namespace ceres
+using Ranks001 = Ranks_t<Jet<double, 0>, double, Jet<double, 1>>;
+using Ranks1 = Ranks_t<Jet<double, 1>>;
+using Ranks110 = Ranks_t<Jet<double, 1>, Jet<double, 1>, double>;
+using Ranks023 = Ranks_t<double, Jet<double, 2>, Jet<double, 3>>;
+using EmptyRanks = Ranks_t<>;
+
+// Remove zero from the ranks integer sequence
+using NonZeroRanks001 = RemoveValue_t<Ranks001, 0>;
+using NonZeroRanks1 = RemoveValue_t<Ranks1, 0>;
+using NonZeroRanks110 = RemoveValue_t<Ranks110, 0>;
+using NonZeroRanks023 = RemoveValue_t<Ranks023, 0>;
+
+static_assert(std::is_same<RemoveValue_t<EmptyRanks, 0>,
+                           std::integer_sequence<int>>::value,
+              "filtered sequence does not match an empty one");
+static_assert(std::is_same<RemoveValue_t<std::integer_sequence<int, 2, 2>, 2>,
+                           std::integer_sequence<int>>::value,
+              "filtered sequence does not match an empty one");
+static_assert(
+    std::is_same<RemoveValue_t<std::integer_sequence<int, 0, 0, 2>, 2>,
+                 std::integer_sequence<int, 0, 0>>::value,
+    "filtered sequence does not match the expected one");
+static_assert(
+    std::is_same<RemoveValue_t<std::make_integer_sequence<int, 6>, 7>,
+                 std::make_integer_sequence<int, 6>>::value,
+    "sequence not containing the element to remove must not be transformed");
+static_assert(
+    std::is_same<NonZeroRanks001, std::integer_sequence<int, 1>>::value,
+    "sequences do not match");
+static_assert(std::is_same<NonZeroRanks1, std::integer_sequence<int, 1>>::value,
+              "sequences do not match");
+static_assert(
+    std::is_same<NonZeroRanks110, std::integer_sequence<int, 1, 1>>::value,
+    "sequences do not match");
+static_assert(
+    std::is_same<NonZeroRanks023, std::integer_sequence<int, 2, 3>>::value,
+    "sequences do not match");
+static_assert(std::is_same<RemoveValue_t<std::integer_sequence<long>, -1>,
+                           std::integer_sequence<long>>::value,
+              "sequences do not match");
+static_assert(
+    std::is_same<RemoveValue_t<std::integer_sequence<short, -2, -3, -1>, -1>,
+                 std::integer_sequence<short, -2, -3>>::value,
+    "sequences do not match");
+
+using J = Jet<double, 2>;
+template <typename T>
+using J0 = Jet<T, 0>;
+using J0d = J0<double>;
+
+// Ensure all types match
+static_assert(AreAllSame_v<int, int>, "types must be the same");
+static_assert(AreAllSame_v<long, long, long>, "types must be the same");
+static_assert(AreAllSame_v<J0d, J0d, J0d>, "types must be the same");
+static_assert(!AreAllSame_v<double, int>, "types must not be the same");
+static_assert(!AreAllSame_v<int, short, char>, "types must not be the same");
+
+// Ensure all values in the integer sequence match
+static_assert(AreAllEqual_v<int, 1, 1>,
+              "integer sequence must contain same values");
+static_assert(AreAllEqual_v<long, 2>,
+              "integer sequence must contain one value");
+static_assert(!AreAllEqual_v<short, 3, 4>,
+              "integer sequence must not contain the same values");
+static_assert(!AreAllEqual_v<unsigned, 3, 4, 3>,
+              "integer sequence must not contain the same values");
+static_assert(!AreAllEqual_v<int, 4, 4, 3>,
+              "integer sequence must not contain the same values");
+
+static_assert(IsEmptyOrAreAllEqual_v<std::integer_sequence<short>>,
+              "expected empty sequence is not");
+static_assert(IsEmptyOrAreAllEqual_v<std::integer_sequence<unsigned, 7, 7, 7>>,
+              "expected all equal sequence is not");
+static_assert(IsEmptyOrAreAllEqual_v<std::integer_sequence<int, 1>>,
+              "expected all equal sequence is not");
+static_assert(
+    IsEmptyOrAreAllEqual_v<std::integer_sequence<long, 111, 111, 111, 111>>,
+    "expected all equal sequence is not");
+
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/invert_psd_matrix.h b/third_party/ceres/internal/ceres/invert_psd_matrix.h
index ac8808b..bc74900 100644
--- a/third_party/ceres/internal/ceres/invert_psd_matrix.h
+++ b/third_party/ceres/internal/ceres/invert_psd_matrix.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,8 +35,7 @@
 #include "ceres/internal/eigen.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // Helper routine to compute the inverse or pseudo-inverse of a
 // symmetric positive semi-definite matrix.
@@ -73,7 +72,6 @@
   return svd.solve(MType::Identity(size, size));
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_INTERNAL_INVERT_PSD_MATRIX_H_
diff --git a/third_party/ceres/internal/ceres/invert_psd_matrix_benchmark.cc b/third_party/ceres/internal/ceres/invert_psd_matrix_benchmark.cc
index 02a19f3..16c3671 100644
--- a/third_party/ceres/internal/ceres/invert_psd_matrix_benchmark.cc
+++ b/third_party/ceres/internal/ceres/invert_psd_matrix_benchmark.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -9,7 +9,7 @@
 //   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 materils provided with the distribution.
+//   and/or other materials provided with the distribution.
 // * Neither the name of Google Inc. nor the names of its contributors may be
 //   used to endorse or promote products derived from this software without
 //   specific prior written permission.
@@ -32,8 +32,7 @@
 #include "benchmark/benchmark.h"
 #include "ceres/invert_psd_matrix.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template <int kSize>
 void BenchmarkFixedSizedInvertPSDMatrix(benchmark::State& state) {
@@ -62,10 +61,10 @@
 BENCHMARK_TEMPLATE(BenchmarkFixedSizedInvertPSDMatrix, 11);
 BENCHMARK_TEMPLATE(BenchmarkFixedSizedInvertPSDMatrix, 12);
 
-void BenchmarkDynamicallyInvertPSDMatrix(benchmark::State& state) {
+static void BenchmarkDynamicallyInvertPSDMatrix(benchmark::State& state) {
   using MatrixType =
       typename EigenTypes<Eigen::Dynamic, Eigen::Dynamic>::Matrix;
-  const int size = state.range(0);
+  const int size = static_cast<int>(state.range(0));
   MatrixType input = MatrixType::Random(size, size);
   input += input.transpose() + MatrixType::Identity(size, size);
 
@@ -84,7 +83,6 @@
       }
     });
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 BENCHMARK_MAIN();
diff --git a/third_party/ceres/internal/ceres/invert_psd_matrix_test.cc b/third_party/ceres/internal/ceres/invert_psd_matrix_test.cc
index 279eeab..22ec439 100644
--- a/third_party/ceres/internal/ceres/invert_psd_matrix_test.cc
+++ b/third_party/ceres/internal/ceres/invert_psd_matrix_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -33,8 +33,7 @@
 #include "ceres/internal/eigen.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 static constexpr bool kFullRank = true;
 static constexpr bool kRankDeficient = false;
@@ -109,5 +108,4 @@
               10 * std::numeric_limits<double>::epsilon());
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/is_close.cc b/third_party/ceres/internal/ceres/is_close.cc
index 0becf55..575918b 100644
--- a/third_party/ceres/internal/ceres/is_close.cc
+++ b/third_party/ceres/internal/ceres/is_close.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2016 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -33,8 +33,7 @@
 #include <algorithm>
 #include <cmath>
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 bool IsClose(double x,
              double y,
              double relative_precision,
@@ -57,5 +56,4 @@
   }
   return *relative_error < std::fabs(relative_precision);
 }
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/is_close.h b/third_party/ceres/internal/ceres/is_close.h
index b781a44..1f6c82f 100644
--- a/third_party/ceres/internal/ceres/is_close.h
+++ b/third_party/ceres/internal/ceres/is_close.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2016 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -33,21 +33,22 @@
 #ifndef CERES_INTERNAL_IS_CLOSE_H_
 #define CERES_INTERNAL_IS_CLOSE_H_
 
-#include "ceres/internal/port.h"
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 // Returns true if x and y have a relative (unsigned) difference less than
 // relative_precision and false otherwise. Stores the relative and absolute
-// difference in relative/absolute_error if non-NULL. If one of the two values
-// is exactly zero, the absolute difference will be compared, and relative_error
-// will be set to the absolute difference.
-CERES_EXPORT_INTERNAL bool IsClose(double x,
-                                   double y,
-                                   double relative_precision,
-                                   double* relative_error,
-                                   double* absolute_error);
-}  // namespace internal
-}  // namespace ceres
+// difference in relative/absolute_error if non-nullptr. If one of the two
+// values is exactly zero, the absolute difference will be compared, and
+// relative_error will be set to the absolute difference.
+CERES_NO_EXPORT bool IsClose(double x,
+                             double y,
+                             double relative_precision,
+                             double* relative_error,
+                             double* absolute_error);
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_IS_CLOSE_H_
diff --git a/third_party/ceres/internal/ceres/is_close_test.cc b/third_party/ceres/internal/ceres/is_close_test.cc
index 12d6236..7b071af 100644
--- a/third_party/ceres/internal/ceres/is_close_test.cc
+++ b/third_party/ceres/internal/ceres/is_close_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -34,8 +34,7 @@
 
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 const double kTolerance = 1e-9;
 
@@ -174,5 +173,4 @@
   EXPECT_NEAR(relative_error, 0.0, kTolerance);
   EXPECT_NEAR(absolute_error, 0.0, kTolerance);
 }
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/iteration_callback.cc b/third_party/ceres/internal/ceres/iteration_callback.cc
new file mode 100644
index 0000000..0cec071
--- /dev/null
+++ b/third_party/ceres/internal/ceres/iteration_callback.cc
@@ -0,0 +1,37 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/iteration_callback.h"
+
+namespace ceres {
+
+IterationCallback::~IterationCallback() = default;
+
+}  // namespace ceres
diff --git a/third_party/ceres/internal/ceres/iterative_refiner.cc b/third_party/ceres/internal/ceres/iterative_refiner.cc
index 5f0bfdd..54d48f3 100644
--- a/third_party/ceres/internal/ceres/iterative_refiner.cc
+++ b/third_party/ceres/internal/ceres/iterative_refiner.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -33,43 +33,69 @@
 #include <string>
 
 #include "Eigen/Core"
+#include "ceres/dense_cholesky.h"
 #include "ceres/sparse_cholesky.h"
 #include "ceres/sparse_matrix.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
-IterativeRefiner::IterativeRefiner(const int max_num_iterations)
+SparseIterativeRefiner::SparseIterativeRefiner(const int max_num_iterations)
     : max_num_iterations_(max_num_iterations) {}
 
-IterativeRefiner::~IterativeRefiner() {}
+SparseIterativeRefiner::~SparseIterativeRefiner() = default;
 
-void IterativeRefiner::Allocate(int num_cols) {
+void SparseIterativeRefiner::Allocate(int num_cols) {
   residual_.resize(num_cols);
   correction_.resize(num_cols);
   lhs_x_solution_.resize(num_cols);
 }
 
-void IterativeRefiner::Refine(const SparseMatrix& lhs,
-                              const double* rhs_ptr,
-                              SparseCholesky* sparse_cholesky,
-                              double* solution_ptr) {
+void SparseIterativeRefiner::Refine(const SparseMatrix& lhs,
+                                    const double* rhs_ptr,
+                                    SparseCholesky* cholesky,
+                                    double* solution_ptr) {
   const int num_cols = lhs.num_cols();
   Allocate(num_cols);
   ConstVectorRef rhs(rhs_ptr, num_cols);
   VectorRef solution(solution_ptr, num_cols);
+  std::string ignored_message;
   for (int i = 0; i < max_num_iterations_; ++i) {
     // residual = rhs - lhs * solution
     lhs_x_solution_.setZero();
-    lhs.RightMultiply(solution_ptr, lhs_x_solution_.data());
+    lhs.RightMultiplyAndAccumulate(solution_ptr, lhs_x_solution_.data());
     residual_ = rhs - lhs_x_solution_;
     // solution += lhs^-1 residual
-    std::string ignored_message;
-    sparse_cholesky->Solve(
-        residual_.data(), correction_.data(), &ignored_message);
+    cholesky->Solve(residual_.data(), correction_.data(), &ignored_message);
     solution += correction_;
   }
 };
 
-}  // namespace internal
-}  // namespace ceres
+DenseIterativeRefiner::DenseIterativeRefiner(const int max_num_iterations)
+    : max_num_iterations_(max_num_iterations) {}
+
+DenseIterativeRefiner::~DenseIterativeRefiner() = default;
+
+void DenseIterativeRefiner::Allocate(int num_cols) {
+  residual_.resize(num_cols);
+  correction_.resize(num_cols);
+}
+
+void DenseIterativeRefiner::Refine(const int num_cols,
+                                   const double* lhs_ptr,
+                                   const double* rhs_ptr,
+                                   DenseCholesky* cholesky,
+                                   double* solution_ptr) {
+  Allocate(num_cols);
+  ConstMatrixRef lhs(lhs_ptr, num_cols, num_cols);
+  ConstVectorRef rhs(rhs_ptr, num_cols);
+  VectorRef solution(solution_ptr, num_cols);
+  std::string ignored_message;
+  for (int i = 0; i < max_num_iterations_; ++i) {
+    residual_ = rhs - lhs * solution;
+    // solution += lhs^-1 residual
+    cholesky->Solve(residual_.data(), correction_.data(), &ignored_message);
+    solution += correction_;
+  }
+};
+
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/iterative_refiner.h b/third_party/ceres/internal/ceres/iterative_refiner.h
index 08f8d67..6607268 100644
--- a/third_party/ceres/internal/ceres/iterative_refiner.h
+++ b/third_party/ceres/internal/ceres/iterative_refiner.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -33,14 +33,15 @@
 
 // This include must come before any #ifndef check on Ceres compile options.
 // clang-format off
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 // clang-format on
 
 #include "ceres/internal/eigen.h"
+#include "ceres/internal/export.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
+class DenseCholesky;
 class SparseCholesky;
 class SparseMatrix;
 
@@ -57,20 +58,20 @@
 // Definite linear systems.
 //
 // The above iterative loop is run until max_num_iterations is reached.
-class CERES_EXPORT_INTERNAL IterativeRefiner {
+class CERES_NO_EXPORT SparseIterativeRefiner {
  public:
   // max_num_iterations is the number of refinement iterations to
   // perform.
-  IterativeRefiner(int max_num_iterations);
+  explicit SparseIterativeRefiner(int max_num_iterations);
 
   // Needed for mocking.
-  virtual ~IterativeRefiner();
+  virtual ~SparseIterativeRefiner();
 
   // Given an initial estimate of the solution of lhs * x = rhs, use
   // max_num_iterations rounds of iterative refinement to improve it.
   //
-  // sparse_cholesky is assumed to contain an already computed
-  // factorization (or approximation thereof) of lhs.
+  // cholesky is assumed to contain an already computed factorization (or
+  // an approximation thereof) of lhs.
   //
   // solution is expected to contain a approximation to the solution
   // to lhs * x = rhs. It can be zero.
@@ -78,7 +79,7 @@
   // This method is virtual to facilitate mocking.
   virtual void Refine(const SparseMatrix& lhs,
                       const double* rhs,
-                      SparseCholesky* sparse_cholesky,
+                      SparseCholesky* cholesky,
                       double* solution);
 
  private:
@@ -90,7 +91,39 @@
   Vector lhs_x_solution_;
 };
 
-}  // namespace internal
-}  // namespace ceres
+class CERES_NO_EXPORT DenseIterativeRefiner {
+ public:
+  // max_num_iterations is the number of refinement iterations to
+  // perform.
+  explicit DenseIterativeRefiner(int max_num_iterations);
+
+  // Needed for mocking.
+  virtual ~DenseIterativeRefiner();
+
+  // Given an initial estimate of the solution of lhs * x = rhs, use
+  // max_num_iterations rounds of iterative refinement to improve it.
+  //
+  // cholesky is assumed to contain an already computed factorization (or
+  // an approximation thereof) of lhs.
+  //
+  // solution is expected to contain a approximation to the solution
+  // to lhs * x = rhs. It can be zero.
+  //
+  // This method is virtual to facilitate mocking.
+  virtual void Refine(int num_cols,
+                      const double* lhs,
+                      const double* rhs,
+                      DenseCholesky* cholesky,
+                      double* solution);
+
+ private:
+  void Allocate(int num_cols);
+
+  int max_num_iterations_;
+  Vector residual_;
+  Vector correction_;
+};
+
+}  // namespace ceres::internal
 
 #endif  // CERES_INTERNAL_ITERATIVE_REFINER_H_
diff --git a/third_party/ceres/internal/ceres/iterative_refiner_test.cc b/third_party/ceres/internal/ceres/iterative_refiner_test.cc
index 49887c6..3b7bfd2 100644
--- a/third_party/ceres/internal/ceres/iterative_refiner_test.cc
+++ b/third_party/ceres/internal/ceres/iterative_refiner_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -30,15 +30,17 @@
 
 #include "ceres/iterative_refiner.h"
 
+#include <utility>
+
 #include "Eigen/Dense"
+#include "ceres/dense_cholesky.h"
 #include "ceres/internal/eigen.h"
 #include "ceres/sparse_cholesky.h"
 #include "ceres/sparse_matrix.h"
 #include "glog/logging.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // Macros to help us define virtual methods which we do not expect to
 // use/call in this test.
@@ -53,17 +55,16 @@
 // A fake SparseMatrix, which uses an Eigen matrix to do the real work.
 class FakeSparseMatrix : public SparseMatrix {
  public:
-  FakeSparseMatrix(const Matrix& m) : m_(m) {}
-  virtual ~FakeSparseMatrix() {}
+  explicit FakeSparseMatrix(Matrix m) : m_(std::move(m)) {}
 
   // y += Ax
-  void RightMultiply(const double* x, double* y) const final {
+  void RightMultiplyAndAccumulate(const double* x, double* y) const final {
     VectorRef(y, m_.cols()) += m_ * ConstVectorRef(x, m_.cols());
   }
   // y += A'x
-  void LeftMultiply(const double* x, double* y) const final {
+  void LeftMultiplyAndAccumulate(const double* x, double* y) const final {
     // We will assume that this is a symmetric matrix.
-    RightMultiply(x, y);
+    RightMultiplyAndAccumulate(x, y);
   }
 
   double* mutable_values() final { return m_.data(); }
@@ -89,8 +90,39 @@
 template <typename Scalar>
 class FakeSparseCholesky : public SparseCholesky {
  public:
-  FakeSparseCholesky(const Matrix& lhs) { lhs_ = lhs.cast<Scalar>(); }
-  virtual ~FakeSparseCholesky() {}
+  explicit FakeSparseCholesky(const Matrix& lhs) { lhs_ = lhs.cast<Scalar>(); }
+
+  LinearSolverTerminationType Solve(const double* rhs_ptr,
+                                    double* solution_ptr,
+                                    std::string* message) final {
+    const int num_cols = lhs_.cols();
+    VectorRef solution(solution_ptr, num_cols);
+    ConstVectorRef rhs(rhs_ptr, num_cols);
+    auto llt = lhs_.llt();
+    CHECK_EQ(llt.info(), Eigen::Success);
+    solution = llt.solve(rhs.cast<Scalar>()).template cast<double>();
+    return LinearSolverTerminationType::SUCCESS;
+  }
+
+  // The following methods are not needed for tests in this file.
+  CompressedRowSparseMatrix::StorageType StorageType() const final
+      DO_NOT_CALL_WITH_RETURN(
+          CompressedRowSparseMatrix::StorageType::UPPER_TRIANGULAR);
+  LinearSolverTerminationType Factorize(CompressedRowSparseMatrix* lhs,
+                                        std::string* message) final
+      DO_NOT_CALL_WITH_RETURN(LinearSolverTerminationType::FAILURE);
+
+ private:
+  Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic> lhs_;
+};
+
+// A fake DenseCholesky which uses Eigen's Cholesky factorization to
+// do the real work. The template parameter allows us to work in
+// doubles or floats, even though the source matrix is double.
+template <typename Scalar>
+class FakeDenseCholesky : public DenseCholesky {
+ public:
+  explicit FakeDenseCholesky(const Matrix& lhs) { lhs_ = lhs.cast<Scalar>(); }
 
   LinearSolverTerminationType Solve(const double* rhs_ptr,
                                     double* solution_ptr,
@@ -99,21 +131,13 @@
     VectorRef solution(solution_ptr, num_cols);
     ConstVectorRef rhs(rhs_ptr, num_cols);
     solution = lhs_.llt().solve(rhs.cast<Scalar>()).template cast<double>();
-    return LINEAR_SOLVER_SUCCESS;
+    return LinearSolverTerminationType::SUCCESS;
   }
 
-  // The following methods are not needed for tests in this file.
-  CompressedRowSparseMatrix::StorageType StorageType() const final
-      DO_NOT_CALL_WITH_RETURN(CompressedRowSparseMatrix::UPPER_TRIANGULAR);
-  LinearSolverTerminationType Factorize(CompressedRowSparseMatrix* lhs,
+  LinearSolverTerminationType Factorize(int num_cols,
+                                        double* lhs,
                                         std::string* message) final
-      DO_NOT_CALL_WITH_RETURN(LINEAR_SOLVER_FAILURE);
-
-  LinearSolverTerminationType FactorAndSolve(CompressedRowSparseMatrix* lhs,
-                                             const double* rhs,
-                                             double* solution,
-                                             std::string* message) final
-      DO_NOT_CALL_WITH_RETURN(LINEAR_SOLVER_FAILURE);
+      DO_NOT_CALL_WITH_RETURN(LinearSolverTerminationType::FAILURE);
 
  private:
   Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic> lhs_;
@@ -122,9 +146,9 @@
 #undef DO_NOT_CALL
 #undef DO_NOT_CALL_WITH_RETURN
 
-class IterativeRefinerTest : public ::testing::Test {
+class SparseIterativeRefinerTest : public ::testing::Test {
  public:
-  void SetUp() {
+  void SetUp() override {
     num_cols_ = 5;
     max_num_iterations_ = 30;
     Matrix m(num_cols_, num_cols_);
@@ -142,10 +166,11 @@
   Vector rhs_, solution_;
 };
 
-TEST_F(IterativeRefinerTest, RandomSolutionWithExactFactorizationConverges) {
+TEST_F(SparseIterativeRefinerTest,
+       RandomSolutionWithExactFactorizationConverges) {
   FakeSparseMatrix lhs(lhs_);
   FakeSparseCholesky<double> sparse_cholesky(lhs_);
-  IterativeRefiner refiner(max_num_iterations_);
+  SparseIterativeRefiner refiner(max_num_iterations_);
   Vector refined_solution(num_cols_);
   refined_solution.setRandom();
   refiner.Refine(lhs, rhs_.data(), &sparse_cholesky, refined_solution.data());
@@ -154,13 +179,13 @@
               std::numeric_limits<double>::epsilon() * 10);
 }
 
-TEST_F(IterativeRefinerTest,
+TEST_F(SparseIterativeRefinerTest,
        RandomSolutionWithApproximationFactorizationConverges) {
   FakeSparseMatrix lhs(lhs_);
   // Use a single precision Cholesky factorization of the double
   // precision matrix. This will give us an approximate factorization.
   FakeSparseCholesky<float> sparse_cholesky(lhs_);
-  IterativeRefiner refiner(max_num_iterations_);
+  SparseIterativeRefiner refiner(max_num_iterations_);
   Vector refined_solution(num_cols_);
   refined_solution.setRandom();
   refiner.Refine(lhs, rhs_.data(), &sparse_cholesky, refined_solution.data());
@@ -169,5 +194,60 @@
               std::numeric_limits<double>::epsilon() * 10);
 }
 
-}  // namespace internal
-}  // namespace ceres
+class DenseIterativeRefinerTest : public ::testing::Test {
+ public:
+  void SetUp() override {
+    num_cols_ = 5;
+    max_num_iterations_ = 30;
+    Matrix m(num_cols_, num_cols_);
+    m.setRandom();
+    lhs_ = m * m.transpose();
+    solution_.resize(num_cols_);
+    solution_.setRandom();
+    rhs_ = lhs_ * solution_;
+  };
+
+ protected:
+  int num_cols_;
+  int max_num_iterations_;
+  Matrix lhs_;
+  Vector rhs_, solution_;
+};
+
+TEST_F(DenseIterativeRefinerTest,
+       RandomSolutionWithExactFactorizationConverges) {
+  Matrix lhs = lhs_;
+  FakeDenseCholesky<double> dense_cholesky(lhs);
+  DenseIterativeRefiner refiner(max_num_iterations_);
+  Vector refined_solution(num_cols_);
+  refined_solution.setRandom();
+  refiner.Refine(lhs.cols(),
+                 lhs.data(),
+                 rhs_.data(),
+                 &dense_cholesky,
+                 refined_solution.data());
+  EXPECT_NEAR((lhs_ * refined_solution - rhs_).norm(),
+              0.0,
+              std::numeric_limits<double>::epsilon() * 10);
+}
+
+TEST_F(DenseIterativeRefinerTest,
+       RandomSolutionWithApproximationFactorizationConverges) {
+  Matrix lhs = lhs_;
+  // Use a single precision Cholesky factorization of the double
+  // precision matrix. This will give us an approximate factorization.
+  FakeDenseCholesky<float> dense_cholesky(lhs_);
+  DenseIterativeRefiner refiner(max_num_iterations_);
+  Vector refined_solution(num_cols_);
+  refined_solution.setRandom();
+  refiner.Refine(lhs.cols(),
+                 lhs.data(),
+                 rhs_.data(),
+                 &dense_cholesky,
+                 refined_solution.data());
+  EXPECT_NEAR((lhs_ * refined_solution - rhs_).norm(),
+              0.0,
+              std::numeric_limits<double>::epsilon() * 10);
+}
+
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/iterative_schur_complement_solver.cc b/third_party/ceres/internal/ceres/iterative_schur_complement_solver.cc
index 143df5e..bcfb6e4 100644
--- a/third_party/ceres/internal/ceres/iterative_schur_complement_solver.cc
+++ b/third_party/ceres/internal/ceres/iterative_schur_complement_solver.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -32,6 +32,7 @@
 
 #include <algorithm>
 #include <cstring>
+#include <utility>
 #include <vector>
 
 #include "Eigen/Dense"
@@ -42,6 +43,7 @@
 #include "ceres/implicit_schur_complement.h"
 #include "ceres/internal/eigen.h"
 #include "ceres/linear_solver.h"
+#include "ceres/power_series_expansion_preconditioner.h"
 #include "ceres/preconditioner.h"
 #include "ceres/schur_jacobi_preconditioner.h"
 #include "ceres/triplet_sparse_matrix.h"
@@ -50,14 +52,13 @@
 #include "ceres/wall_time.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 IterativeSchurComplementSolver::IterativeSchurComplementSolver(
-    const LinearSolver::Options& options)
-    : options_(options) {}
+    LinearSolver::Options options)
+    : options_(std::move(options)) {}
 
-IterativeSchurComplementSolver::~IterativeSchurComplementSolver() {}
+IterativeSchurComplementSolver::~IterativeSchurComplementSolver() = default;
 
 LinearSolver::Summary IterativeSchurComplementSolver::SolveImpl(
     BlockSparseMatrix* A,
@@ -67,15 +68,17 @@
   EventLogger event_logger("IterativeSchurComplementSolver::Solve");
 
   CHECK(A->block_structure() != nullptr);
+  CHECK(A->transpose_block_structure() != nullptr);
+
   const int num_eliminate_blocks = options_.elimination_groups[0];
   // Initialize a ImplicitSchurComplement object.
-  if (schur_complement_ == NULL) {
+  if (schur_complement_ == nullptr) {
     DetectStructure(*(A->block_structure()),
                     num_eliminate_blocks,
                     &options_.row_block_size,
                     &options_.e_block_size,
                     &options_.f_block_size);
-    schur_complement_.reset(new ImplicitSchurComplement(options_));
+    schur_complement_ = std::make_unique<ImplicitSchurComplement>(options_);
   }
   schur_complement_->Init(*A, per_solve_options.D, b);
 
@@ -85,45 +88,66 @@
     VLOG(2) << "No parameter blocks left in the schur complement.";
     LinearSolver::Summary summary;
     summary.num_iterations = 0;
-    summary.termination_type = LINEAR_SOLVER_SUCCESS;
-    schur_complement_->BackSubstitute(NULL, x);
+    summary.termination_type = LinearSolverTerminationType::SUCCESS;
+    schur_complement_->BackSubstitute(nullptr, x);
     return summary;
   }
 
-  // Initialize the solution to the Schur complement system to zero.
+  // Initialize the solution to the Schur complement system.
   reduced_linear_system_solution_.resize(schur_complement_->num_rows());
   reduced_linear_system_solution_.setZero();
-
-  LinearSolver::Options cg_options;
-  cg_options.min_num_iterations = options_.min_num_iterations;
-  cg_options.max_num_iterations = options_.max_num_iterations;
-  ConjugateGradientsSolver cg_solver(cg_options);
-
-  LinearSolver::PerSolveOptions cg_per_solve_options;
-  cg_per_solve_options.r_tolerance = per_solve_options.r_tolerance;
-  cg_per_solve_options.q_tolerance = per_solve_options.q_tolerance;
+  if (options_.use_spse_initialization) {
+    Preconditioner::Options preconditioner_options(options_);
+    preconditioner_options.type = SCHUR_POWER_SERIES_EXPANSION;
+    PowerSeriesExpansionPreconditioner pse_solver(
+        schur_complement_.get(),
+        options_.max_num_spse_iterations,
+        options_.spse_tolerance,
+        preconditioner_options);
+    pse_solver.RightMultiplyAndAccumulate(
+        schur_complement_->rhs().data(),
+        reduced_linear_system_solution_.data());
+  }
 
   CreatePreconditioner(A);
-  if (preconditioner_.get() != NULL) {
+  if (preconditioner_ != nullptr) {
     if (!preconditioner_->Update(*A, per_solve_options.D)) {
       LinearSolver::Summary summary;
       summary.num_iterations = 0;
-      summary.termination_type = LINEAR_SOLVER_FAILURE;
+      summary.termination_type = LinearSolverTerminationType::FAILURE;
       summary.message = "Preconditioner update failed.";
       return summary;
     }
-
-    cg_per_solve_options.preconditioner = preconditioner_.get();
   }
 
+  ConjugateGradientsSolverOptions cg_options;
+  cg_options.min_num_iterations = options_.min_num_iterations;
+  cg_options.max_num_iterations = options_.max_num_iterations;
+  cg_options.residual_reset_period = options_.residual_reset_period;
+  cg_options.q_tolerance = per_solve_options.q_tolerance;
+  cg_options.r_tolerance = per_solve_options.r_tolerance;
+
+  LinearOperatorAdapter lhs(*schur_complement_);
+  LinearOperatorAdapter preconditioner(*preconditioner_);
+
+  Vector scratch[4];
+  for (int i = 0; i < 4; ++i) {
+    scratch[i].resize(schur_complement_->num_cols());
+  }
+  Vector* scratch_ptr[4] = {&scratch[0], &scratch[1], &scratch[2], &scratch[3]};
+
   event_logger.AddEvent("Setup");
+
   LinearSolver::Summary summary =
-      cg_solver.Solve(schur_complement_.get(),
-                      schur_complement_->rhs().data(),
-                      cg_per_solve_options,
-                      reduced_linear_system_solution_.data());
-  if (summary.termination_type != LINEAR_SOLVER_FAILURE &&
-      summary.termination_type != LINEAR_SOLVER_FATAL_ERROR) {
+      ConjugateGradientsSolver(cg_options,
+                               lhs,
+                               schur_complement_->rhs(),
+                               preconditioner,
+                               scratch_ptr,
+                               reduced_linear_system_solution_);
+
+  if (summary.termination_type != LinearSolverTerminationType::FAILURE &&
+      summary.termination_type != LinearSolverTerminationType::FATAL_ERROR) {
     schur_complement_->BackSubstitute(reduced_linear_system_solution_.data(),
                                       x);
   }
@@ -133,43 +157,44 @@
 
 void IterativeSchurComplementSolver::CreatePreconditioner(
     BlockSparseMatrix* A) {
-  if (options_.preconditioner_type == IDENTITY ||
-      preconditioner_.get() != NULL) {
+  if (preconditioner_ != nullptr) {
     return;
   }
 
-  Preconditioner::Options preconditioner_options;
-  preconditioner_options.type = options_.preconditioner_type;
-  preconditioner_options.visibility_clustering_type =
-      options_.visibility_clustering_type;
-  preconditioner_options.sparse_linear_algebra_library_type =
-      options_.sparse_linear_algebra_library_type;
-  preconditioner_options.num_threads = options_.num_threads;
-  preconditioner_options.row_block_size = options_.row_block_size;
-  preconditioner_options.e_block_size = options_.e_block_size;
-  preconditioner_options.f_block_size = options_.f_block_size;
-  preconditioner_options.elimination_groups = options_.elimination_groups;
-  CHECK(options_.context != NULL);
-  preconditioner_options.context = options_.context;
+  Preconditioner::Options preconditioner_options(options_);
+  CHECK(options_.context != nullptr);
 
   switch (options_.preconditioner_type) {
+    case IDENTITY:
+      preconditioner_ = std::make_unique<IdentityPreconditioner>(
+          schur_complement_->num_cols());
+      break;
     case JACOBI:
-      preconditioner_.reset(new SparseMatrixPreconditionerWrapper(
-          schur_complement_->block_diagonal_FtF_inverse()));
+      preconditioner_ = std::make_unique<SparseMatrixPreconditionerWrapper>(
+          schur_complement_->block_diagonal_FtF_inverse(),
+          preconditioner_options);
+      break;
+    case SCHUR_POWER_SERIES_EXPANSION:
+      // Ignoring the value of spse_tolerance to ensure preconditioner stays
+      // fixed during the iterations of cg.
+      preconditioner_ = std::make_unique<PowerSeriesExpansionPreconditioner>(
+          schur_complement_.get(),
+          options_.max_num_spse_iterations,
+          0,
+          preconditioner_options);
       break;
     case SCHUR_JACOBI:
-      preconditioner_.reset(new SchurJacobiPreconditioner(
-          *A->block_structure(), preconditioner_options));
+      preconditioner_ = std::make_unique<SchurJacobiPreconditioner>(
+          *A->block_structure(), preconditioner_options);
       break;
     case CLUSTER_JACOBI:
     case CLUSTER_TRIDIAGONAL:
-      preconditioner_.reset(new VisibilityBasedPreconditioner(
-          *A->block_structure(), preconditioner_options));
+      preconditioner_ = std::make_unique<VisibilityBasedPreconditioner>(
+          *A->block_structure(), preconditioner_options);
       break;
     default:
       LOG(FATAL) << "Unknown Preconditioner Type";
   }
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/iterative_schur_complement_solver.h b/third_party/ceres/internal/ceres/iterative_schur_complement_solver.h
index 37606b3..a4b6b53 100644
--- a/third_party/ceres/internal/ceres/iterative_schur_complement_solver.h
+++ b/third_party/ceres/internal/ceres/iterative_schur_complement_solver.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -33,13 +33,13 @@
 
 #include <memory>
 
+#include "ceres/internal/disable_warnings.h"
 #include "ceres/internal/eigen.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 #include "ceres/linear_solver.h"
 #include "ceres/types.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 class BlockSparseMatrix;
 class ImplicitSchurComplement;
@@ -52,7 +52,7 @@
 // The algorithm used by this solver was developed in a series of
 // papers - "Agarwal et al, Bundle Adjustment in the Large, ECCV 2010"
 // and "Wu et al, Multicore Bundle Adjustment, submitted to CVPR
-// 2011" at the Univeristy of Washington.
+// 2011" at the University of Washington.
 //
 // The key idea is that one can run Conjugate Gradients on the Schur
 // Complement system without explicitly forming the Schur Complement
@@ -69,15 +69,15 @@
 // a proof of this fact and others related to this solver please see
 // the section on Domain Decomposition Methods in Saad's book
 // "Iterative Methods for Sparse Linear Systems".
-class CERES_EXPORT_INTERNAL IterativeSchurComplementSolver
+class CERES_NO_EXPORT IterativeSchurComplementSolver final
     : public BlockSparseMatrixSolver {
  public:
-  explicit IterativeSchurComplementSolver(const LinearSolver::Options& options);
+  explicit IterativeSchurComplementSolver(LinearSolver::Options options);
   IterativeSchurComplementSolver(const IterativeSchurComplementSolver&) =
       delete;
   void operator=(const IterativeSchurComplementSolver&) = delete;
 
-  virtual ~IterativeSchurComplementSolver();
+  ~IterativeSchurComplementSolver() override;
 
  private:
   LinearSolver::Summary SolveImpl(BlockSparseMatrix* A,
@@ -93,7 +93,8 @@
   Vector reduced_linear_system_solution_;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_ITERATIVE_SCHUR_COMPLEMENT_SOLVER_H_
diff --git a/third_party/ceres/internal/ceres/iterative_schur_complement_solver_test.cc b/third_party/ceres/internal/ceres/iterative_schur_complement_solver_test.cc
index fdd65c7..c5d67de 100644
--- a/third_party/ceres/internal/ceres/iterative_schur_complement_solver_test.cc
+++ b/third_party/ceres/internal/ceres/iterative_schur_complement_solver_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -61,20 +61,22 @@
 class IterativeSchurComplementSolverTest : public ::testing::Test {
  protected:
   void SetUpProblem(int problem_id) {
-    std::unique_ptr<LinearLeastSquaresProblem> problem(
-        CreateLinearLeastSquaresProblemFromId(problem_id));
+    std::unique_ptr<LinearLeastSquaresProblem> problem =
+        CreateLinearLeastSquaresProblemFromId(problem_id);
 
     CHECK(problem != nullptr);
     A_.reset(down_cast<BlockSparseMatrix*>(problem->A.release()));
-    b_.reset(problem->b.release());
-    D_.reset(problem->D.release());
+    b_ = std::move(problem->b);
+    D_ = std::move(problem->D);
 
     num_cols_ = A_->num_cols();
     num_rows_ = A_->num_rows();
     num_eliminate_blocks_ = problem->num_eliminate_blocks;
   }
 
-  AssertionResult TestSolver(double* D) {
+  AssertionResult TestSolver(double* D,
+                             PreconditionerType preconditioner_type,
+                             bool use_spse_initialization) {
     TripletSparseMatrix triplet_A(
         A_->num_rows(), A_->num_cols(), A_->num_nonzeros());
     A_->ToTripletSparseMatrix(&triplet_A);
@@ -95,7 +97,9 @@
     options.elimination_groups.push_back(num_eliminate_blocks_);
     options.elimination_groups.push_back(0);
     options.max_num_iterations = num_cols_;
-    options.preconditioner_type = SCHUR_JACOBI;
+    options.max_num_spse_iterations = 1;
+    options.use_spse_initialization = use_spse_initialization;
+    options.preconditioner_type = preconditioner_type;
     IterativeSchurComplementSolver isc(options);
 
     Vector isc_sol(num_cols_);
@@ -119,16 +123,30 @@
   std::unique_ptr<double[]> D_;
 };
 
-TEST_F(IterativeSchurComplementSolverTest, NormalProblem) {
+TEST_F(IterativeSchurComplementSolverTest, NormalProblemSchurJacobi) {
   SetUpProblem(2);
-  EXPECT_TRUE(TestSolver(NULL));
-  EXPECT_TRUE(TestSolver(D_.get()));
+  EXPECT_TRUE(TestSolver(nullptr, SCHUR_JACOBI, false));
+  EXPECT_TRUE(TestSolver(D_.get(), SCHUR_JACOBI, false));
+}
+
+TEST_F(IterativeSchurComplementSolverTest,
+       NormalProblemSchurJacobiWithPowerSeriesExpansionInitialization) {
+  SetUpProblem(2);
+  EXPECT_TRUE(TestSolver(nullptr, SCHUR_JACOBI, true));
+  EXPECT_TRUE(TestSolver(D_.get(), SCHUR_JACOBI, true));
+}
+
+TEST_F(IterativeSchurComplementSolverTest,
+       NormalProblemPowerSeriesExpansionPreconditioner) {
+  SetUpProblem(5);
+  EXPECT_TRUE(TestSolver(nullptr, SCHUR_POWER_SERIES_EXPANSION, false));
+  EXPECT_TRUE(TestSolver(D_.get(), SCHUR_POWER_SERIES_EXPANSION, false));
 }
 
 TEST_F(IterativeSchurComplementSolverTest, ProblemWithNoFBlocks) {
   SetUpProblem(3);
-  EXPECT_TRUE(TestSolver(NULL));
-  EXPECT_TRUE(TestSolver(D_.get()));
+  EXPECT_TRUE(TestSolver(nullptr, SCHUR_JACOBI, false));
+  EXPECT_TRUE(TestSolver(D_.get(), SCHUR_JACOBI, false));
 }
 
 }  // namespace internal
diff --git a/third_party/ceres/internal/ceres/jet_operator_benchmark.cc b/third_party/ceres/internal/ceres/jet_operator_benchmark.cc
new file mode 100644
index 0000000..94b0308
--- /dev/null
+++ b/third_party/ceres/internal/ceres/jet_operator_benchmark.cc
@@ -0,0 +1,289 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: alex@karatarakis.com (Alexander Karatarakis)
+
+#include <array>
+
+#include "benchmark/benchmark.h"
+#include "ceres/jet.h"
+
+namespace ceres {
+
+// Cycle the Jets to avoid caching effects in the benchmark.
+template <class JetType>
+class JetInputData {
+  using T = typename JetType::Scalar;
+  static constexpr std::size_t SIZE = 20;
+
+ public:
+  JetInputData() {
+    for (int i = 0; i < static_cast<int>(SIZE); i++) {
+      const T ti = static_cast<T>(i + 1);
+
+      a_[i].a = T(1.1) * ti;
+      a_[i].v.setRandom();
+
+      b_[i].a = T(2.2) * ti;
+      b_[i].v.setRandom();
+
+      c_[i].a = T(3.3) * ti;
+      c_[i].v.setRandom();
+
+      d_[i].a = T(4.4) * ti;
+      d_[i].v.setRandom();
+
+      e_[i].a = T(5.5) * ti;
+      e_[i].v.setRandom();
+
+      scalar_a_[i] = T(1.1) * ti;
+      scalar_b_[i] = T(2.2) * ti;
+      scalar_c_[i] = T(3.3) * ti;
+      scalar_d_[i] = T(4.4) * ti;
+      scalar_e_[i] = T(5.5) * ti;
+    }
+  }
+
+  void advance() { index_ = (index_ + 1) % SIZE; }
+
+  const JetType& a() const { return a_[index_]; }
+  const JetType& b() const { return b_[index_]; }
+  const JetType& c() const { return c_[index_]; }
+  const JetType& d() const { return d_[index_]; }
+  const JetType& e() const { return e_[index_]; }
+  T scalar_a() const { return scalar_a_[index_]; }
+  T scalar_b() const { return scalar_b_[index_]; }
+  T scalar_c() const { return scalar_c_[index_]; }
+  T scalar_d() const { return scalar_d_[index_]; }
+  T scalar_e() const { return scalar_e_[index_]; }
+
+ private:
+  std::size_t index_{0};
+  std::array<JetType, SIZE> a_{};
+  std::array<JetType, SIZE> b_{};
+  std::array<JetType, SIZE> c_{};
+  std::array<JetType, SIZE> d_{};
+  std::array<JetType, SIZE> e_{};
+  std::array<T, SIZE> scalar_a_;
+  std::array<T, SIZE> scalar_b_;
+  std::array<T, SIZE> scalar_c_;
+  std::array<T, SIZE> scalar_d_;
+  std::array<T, SIZE> scalar_e_;
+};
+
+template <std::size_t JET_SIZE, class Function>
+static void JetBenchmarkHelper(benchmark::State& state, const Function& func) {
+  using JetType = Jet<double, JET_SIZE>;
+  JetInputData<JetType> data{};
+  JetType out{};
+  const int iterations = static_cast<int>(state.range(0));
+  for (auto _ : state) {
+    for (int i = 0; i < iterations; i++) {
+      func(data, out);
+      data.advance();
+    }
+  }
+  benchmark::DoNotOptimize(out);
+}
+
+template <std::size_t JET_SIZE>
+static void Addition(benchmark::State& state) {
+  using JetType = Jet<double, JET_SIZE>;
+  JetBenchmarkHelper<JET_SIZE>(
+      state, [](const JetInputData<JetType>& d, JetType& out) {
+        out += +d.a() + d.b() + d.c() + d.d() + d.e();
+      });
+}
+BENCHMARK_TEMPLATE(Addition, 3)->Arg(1000);
+BENCHMARK_TEMPLATE(Addition, 10)->Arg(1000);
+BENCHMARK_TEMPLATE(Addition, 15)->Arg(1000);
+BENCHMARK_TEMPLATE(Addition, 25)->Arg(1000);
+BENCHMARK_TEMPLATE(Addition, 32)->Arg(1000);
+BENCHMARK_TEMPLATE(Addition, 200)->Arg(160);
+
+template <std::size_t JET_SIZE>
+static void AdditionScalar(benchmark::State& state) {
+  using JetType = Jet<double, JET_SIZE>;
+  JetBenchmarkHelper<JET_SIZE>(
+      state, [](const JetInputData<JetType>& d, JetType& out) {
+        out +=
+            d.scalar_a() + d.scalar_b() + d.c() + d.scalar_d() + d.scalar_e();
+      });
+}
+BENCHMARK_TEMPLATE(AdditionScalar, 3)->Arg(1000);
+BENCHMARK_TEMPLATE(AdditionScalar, 10)->Arg(1000);
+BENCHMARK_TEMPLATE(AdditionScalar, 15)->Arg(1000);
+BENCHMARK_TEMPLATE(AdditionScalar, 25)->Arg(1000);
+BENCHMARK_TEMPLATE(AdditionScalar, 32)->Arg(1000);
+BENCHMARK_TEMPLATE(AdditionScalar, 200)->Arg(160);
+
+template <std::size_t JET_SIZE>
+static void Subtraction(benchmark::State& state) {
+  using JetType = Jet<double, JET_SIZE>;
+  JetBenchmarkHelper<JET_SIZE>(
+      state, [](const JetInputData<JetType>& d, JetType& out) {
+        out -= -d.a() - d.b() - d.c() - d.d() - d.e();
+      });
+}
+BENCHMARK_TEMPLATE(Subtraction, 3)->Arg(1000);
+BENCHMARK_TEMPLATE(Subtraction, 10)->Arg(1000);
+BENCHMARK_TEMPLATE(Subtraction, 15)->Arg(1000);
+BENCHMARK_TEMPLATE(Subtraction, 25)->Arg(1000);
+BENCHMARK_TEMPLATE(Subtraction, 32)->Arg(1000);
+BENCHMARK_TEMPLATE(Subtraction, 200)->Arg(160);
+
+template <std::size_t JET_SIZE>
+static void SubtractionScalar(benchmark::State& state) {
+  using JetType = Jet<double, JET_SIZE>;
+  JetBenchmarkHelper<JET_SIZE>(
+      state, [](const JetInputData<JetType>& d, JetType& out) {
+        out -=
+            -d.scalar_a() - d.scalar_b() - d.c() - d.scalar_d() - d.scalar_e();
+      });
+}
+BENCHMARK_TEMPLATE(SubtractionScalar, 3)->Arg(1000);
+BENCHMARK_TEMPLATE(SubtractionScalar, 10)->Arg(1000);
+BENCHMARK_TEMPLATE(SubtractionScalar, 15)->Arg(1000);
+BENCHMARK_TEMPLATE(SubtractionScalar, 25)->Arg(1000);
+BENCHMARK_TEMPLATE(SubtractionScalar, 32)->Arg(1000);
+BENCHMARK_TEMPLATE(SubtractionScalar, 200)->Arg(160);
+
+template <std::size_t JET_SIZE>
+static void Multiplication(benchmark::State& state) {
+  using JetType = Jet<double, JET_SIZE>;
+  JetBenchmarkHelper<JET_SIZE>(
+      state, [](const JetInputData<JetType>& d, JetType& out) {
+        out *= d.a() * d.b() * d.c() * d.d() * d.e();
+      });
+}
+BENCHMARK_TEMPLATE(Multiplication, 3)->Arg(1000);
+BENCHMARK_TEMPLATE(Multiplication, 10)->Arg(1000);
+BENCHMARK_TEMPLATE(Multiplication, 15)->Arg(1000);
+BENCHMARK_TEMPLATE(Multiplication, 25)->Arg(1000);
+BENCHMARK_TEMPLATE(Multiplication, 32)->Arg(1000);
+BENCHMARK_TEMPLATE(Multiplication, 200)->Arg(160);
+
+template <std::size_t JET_SIZE>
+static void MultiplicationLeftScalar(benchmark::State& state) {
+  using JetType = Jet<double, JET_SIZE>;
+  JetBenchmarkHelper<JET_SIZE>(
+      state, [](const JetInputData<JetType>& d, JetType& out) {
+        out += d.scalar_a() *
+               (d.scalar_b() * (d.scalar_c() * (d.scalar_d() * d.e())));
+      });
+}
+BENCHMARK_TEMPLATE(MultiplicationLeftScalar, 3)->Arg(1000);
+BENCHMARK_TEMPLATE(MultiplicationLeftScalar, 10)->Arg(1000);
+BENCHMARK_TEMPLATE(MultiplicationLeftScalar, 15)->Arg(1000);
+BENCHMARK_TEMPLATE(MultiplicationLeftScalar, 25)->Arg(1000);
+BENCHMARK_TEMPLATE(MultiplicationLeftScalar, 32)->Arg(1000);
+BENCHMARK_TEMPLATE(MultiplicationLeftScalar, 200)->Arg(160);
+
+template <std::size_t JET_SIZE>
+static void MultiplicationRightScalar(benchmark::State& state) {
+  using JetType = Jet<double, JET_SIZE>;
+  JetBenchmarkHelper<JET_SIZE>(
+      state, [](const JetInputData<JetType>& d, JetType& out) {
+        out += (((d.a() * d.scalar_b()) * d.scalar_c()) * d.scalar_d()) *
+               d.scalar_e();
+      });
+}
+BENCHMARK_TEMPLATE(MultiplicationRightScalar, 3)->Arg(1000);
+BENCHMARK_TEMPLATE(MultiplicationRightScalar, 10)->Arg(1000);
+BENCHMARK_TEMPLATE(MultiplicationRightScalar, 15)->Arg(1000);
+BENCHMARK_TEMPLATE(MultiplicationRightScalar, 25)->Arg(1000);
+BENCHMARK_TEMPLATE(MultiplicationRightScalar, 32)->Arg(1000);
+BENCHMARK_TEMPLATE(MultiplicationRightScalar, 200)->Arg(160);
+
+template <std::size_t JET_SIZE>
+static void Division(benchmark::State& state) {
+  using JetType = Jet<double, JET_SIZE>;
+  JetBenchmarkHelper<JET_SIZE>(
+      state, [](const JetInputData<JetType>& d, JetType& out) {
+        out /= d.a() / d.b() / d.c() / d.d() / d.e();
+      });
+}
+BENCHMARK_TEMPLATE(Division, 3)->Arg(1000);
+BENCHMARK_TEMPLATE(Division, 10)->Arg(1000);
+BENCHMARK_TEMPLATE(Division, 15)->Arg(1000);
+BENCHMARK_TEMPLATE(Division, 25)->Arg(1000);
+BENCHMARK_TEMPLATE(Division, 32)->Arg(1000);
+BENCHMARK_TEMPLATE(Division, 200)->Arg(160);
+
+template <std::size_t JET_SIZE>
+static void DivisionLeftScalar(benchmark::State& state) {
+  using JetType = Jet<double, JET_SIZE>;
+  JetBenchmarkHelper<JET_SIZE>(
+      state, [](const JetInputData<JetType>& d, JetType& out) {
+        out += d.scalar_a() /
+               (d.scalar_b() / (d.scalar_c() / (d.scalar_d() / d.e())));
+      });
+}
+BENCHMARK_TEMPLATE(DivisionLeftScalar, 3)->Arg(1000);
+BENCHMARK_TEMPLATE(DivisionLeftScalar, 10)->Arg(1000);
+BENCHMARK_TEMPLATE(DivisionLeftScalar, 15)->Arg(1000);
+BENCHMARK_TEMPLATE(DivisionLeftScalar, 25)->Arg(1000);
+BENCHMARK_TEMPLATE(DivisionLeftScalar, 32)->Arg(1000);
+BENCHMARK_TEMPLATE(DivisionLeftScalar, 200)->Arg(160);
+
+template <std::size_t JET_SIZE>
+static void DivisionRightScalar(benchmark::State& state) {
+  using JetType = Jet<double, JET_SIZE>;
+  JetBenchmarkHelper<JET_SIZE>(
+      state, [](const JetInputData<JetType>& d, JetType& out) {
+        out += (((d.a() / d.scalar_b()) / d.scalar_c()) / d.scalar_d()) /
+               d.scalar_e();
+      });
+}
+BENCHMARK_TEMPLATE(DivisionRightScalar, 3)->Arg(1000);
+BENCHMARK_TEMPLATE(DivisionRightScalar, 10)->Arg(1000);
+BENCHMARK_TEMPLATE(DivisionRightScalar, 15)->Arg(1000);
+BENCHMARK_TEMPLATE(DivisionRightScalar, 25)->Arg(1000);
+BENCHMARK_TEMPLATE(DivisionRightScalar, 32)->Arg(1000);
+BENCHMARK_TEMPLATE(DivisionRightScalar, 200)->Arg(160);
+
+template <std::size_t JET_SIZE>
+static void MultiplyAndAdd(benchmark::State& state) {
+  using JetType = Jet<double, JET_SIZE>;
+  JetBenchmarkHelper<JET_SIZE>(
+      state, [](const JetInputData<JetType>& d, JetType& out) {
+        out += d.scalar_a() * d.a() + d.scalar_b() * d.b() +
+               d.scalar_c() * d.c() + d.scalar_d() * d.d() +
+               d.scalar_e() * d.e();
+      });
+}
+BENCHMARK_TEMPLATE(MultiplyAndAdd, 3)->Arg(1000);
+BENCHMARK_TEMPLATE(MultiplyAndAdd, 10)->Arg(1000);
+BENCHMARK_TEMPLATE(MultiplyAndAdd, 15)->Arg(1000);
+BENCHMARK_TEMPLATE(MultiplyAndAdd, 25)->Arg(1000);
+BENCHMARK_TEMPLATE(MultiplyAndAdd, 32)->Arg(1000);
+BENCHMARK_TEMPLATE(MultiplyAndAdd, 200)->Arg(160);
+
+}  // namespace ceres
+
+BENCHMARK_MAIN();
diff --git a/third_party/ceres/internal/ceres/jet_test.cc b/third_party/ceres/internal/ceres/jet_test.cc
index 36f279d..7f67bd6 100644
--- a/third_party/ceres/internal/ceres/jet_test.cc
+++ b/third_party/ceres/internal/ceres/jet_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2024 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -32,23 +32,39 @@
 
 #include <Eigen/Dense>
 #include <algorithm>
+#include <cfenv>
 #include <cmath>
 
 #include "ceres/stringprintf.h"
 #include "ceres/test_util.h"
 #include "glog/logging.h"
+#include "gmock/gmock.h"
 #include "gtest/gtest.h"
 
-#define VL VLOG(1)
+// The floating-point environment access and modification is only meaningful
+// with the following pragma.
+#ifdef _MSC_VER
+#pragma float_control(precise, on, push)
+#pragma fenv_access(on)
+#elif !(defined(__ARM_ARCH) && __ARM_ARCH >= 8) && !defined(__MINGW32__)
+// NOTE: FENV_ACCESS cannot be set to ON when targeting arm(v8) and MinGW
+#pragma STDC FENV_ACCESS ON
+#else
+#define CERES_NO_FENV_ACCESS
+#endif
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 namespace {
 
-const double kE = 2.71828182845904523536;
+constexpr double kE = 2.71828182845904523536;
 
-typedef Jet<double, 2> J;
+using J = Jet<double, 2>;
+// Don't care about the dual part for scalar part categorization and comparison
+// tests
+template <typename T>
+using J0 = Jet<T, 0>;
+using J0d = J0<double>;
 
 // Convenient shorthand for making a jet.
 J MakeJet(double a, double v0, double v1) {
@@ -59,13 +75,63 @@
   return z;
 }
 
-// On a 32-bit optimized build, the mismatch is about 1.4e-14.
-double const kTolerance = 1e-13;
+constexpr double kTolerance = 1e-13;
 
-void ExpectJetsClose(const J& x, const J& y) {
-  ExpectClose(x.a, y.a, kTolerance);
-  ExpectClose(x.v[0], y.v[0], kTolerance);
-  ExpectClose(x.v[1], y.v[1], kTolerance);
+// Stores the floating-point environment containing active floating-point
+// exceptions, rounding mode, etc., and restores it upon destruction.
+//
+// Useful for avoiding side-effects.
+class Fenv {
+ public:
+  Fenv() { std::fegetenv(&e); }
+  ~Fenv() { std::fesetenv(&e); }
+
+  Fenv(const Fenv&) = delete;
+  Fenv& operator=(const Fenv&) = delete;
+
+ private:
+  std::fenv_t e;
+};
+
+bool AreAlmostEqual(double x, double y, double max_abs_relative_difference) {
+  if (std::isnan(x) && std::isnan(y)) {
+    return true;
+  }
+
+  if (std::isinf(x) && std::isinf(y)) {
+    return (std::signbit(x) == std::signbit(y));
+  }
+
+  Fenv env;  // Do not leak floating-point exceptions to the caller
+  double absolute_difference = std::abs(x - y);
+  double relative_difference =
+      absolute_difference / std::max(std::abs(x), std::abs(y));
+
+  if (std::fpclassify(x) == FP_ZERO || std::fpclassify(y) == FP_ZERO) {
+    // If x or y is exactly zero, then relative difference doesn't have any
+    // meaning. Take the absolute difference instead.
+    relative_difference = absolute_difference;
+  }
+  return std::islessequal(relative_difference, max_abs_relative_difference);
+}
+
+MATCHER_P2(IsAlmostEqualToWithTolerance,
+           y,
+           tolerance,
+           "is almost equal to " + testing::PrintToString(y) +
+               " with tolerance " + testing::PrintToString(tolerance)) {
+  const bool result = (AreAlmostEqual(arg.a, y.a, tolerance) &&
+                       AreAlmostEqual(arg.v[0], y.v[0], tolerance) &&
+                       AreAlmostEqual(arg.v[1], y.v[1], tolerance));
+  if (!result) {
+    *result_listener << "\nexpected - actual : " << y - arg;
+  }
+  return result;
+}
+
+MATCHER_P(IsAlmostEqualTo, y, "") {
+  return ExplainMatchResult(
+      IsAlmostEqualToWithTolerance(y, kTolerance), arg, result_listener);
 }
 
 const double kStep = 1e-8;
@@ -77,8 +143,8 @@
   const double exact_dx = f(MakeJet(x, 1.0, 0.0)).v[0];
   const double estimated_dx =
       (f(J(x + kStep)).a - f(J(x - kStep)).a) / (2.0 * kStep);
-  VL << name << "(" << x << "), exact dx: " << exact_dx
-     << ", estimated dx: " << estimated_dx;
+  VLOG(1) << name << "(" << x << "), exact dx: " << exact_dx
+          << ", estimated dx: " << estimated_dx;
   ExpectClose(exact_dx, estimated_dx, kNumericalTolerance);
 }
 
@@ -102,478 +168,211 @@
       (f(J(x + kStep), J(y)).a - f(J(x - kStep), J(y)).a) / (2.0 * kStep);
   const double estimated_dy =
       (f(J(x), J(y + kStep)).a - f(J(x), J(y - kStep)).a) / (2.0 * kStep);
-  VL << name << "(" << x << ", " << y << "), exact dx: " << exact_dx
-     << ", estimated dx: " << estimated_dx;
+  VLOG(1) << name << "(" << x << ", " << y << "), exact dx: " << exact_dx
+          << ", estimated dx: " << estimated_dx;
   ExpectClose(exact_dx, estimated_dx, kNumericalTolerance);
-  VL << name << "(" << x << ", " << y << "), exact dy: " << exact_dy
-     << ", estimated dy: " << estimated_dy;
+  VLOG(1) << name << "(" << x << ", " << y << "), exact dy: " << exact_dy
+          << ", estimated dy: " << estimated_dy;
   ExpectClose(exact_dy, estimated_dy, kNumericalTolerance);
 }
 
 }  // namespace
 
-TEST(Jet, Jet) {
-  // Pick arbitrary values for x and y.
-  J x = MakeJet(2.3, -2.7, 1e-3);
-  J y = MakeJet(1.7, 0.5, 1e+2);
+// Pick arbitrary values for x and y.
+const J x = MakeJet(2.3, -2.7, 1e-3);
+const J y = MakeJet(1.7, 0.5, 1e+2);
+const J z = MakeJet(1e-6, 1e-4, 1e-2);
 
-  VL << "x = " << x;
-  VL << "y = " << y;
-
-  {  // Check that log(exp(x)) == x.
-    J z = exp(x);
-    J w = log(z);
-    VL << "z = " << z;
-    VL << "w = " << w;
-    ExpectJetsClose(w, x);
-  }
-
-  {  // Check that (x * y) / x == y.
-    J z = x * y;
-    J w = z / x;
-    VL << "z = " << z;
-    VL << "w = " << w;
-    ExpectJetsClose(w, y);
-  }
-
-  {  // Check that sqrt(x * x) == x.
-    J z = x * x;
-    J w = sqrt(z);
-    VL << "z = " << z;
-    VL << "w = " << w;
-    ExpectJetsClose(w, x);
-  }
-
-  {  // Check that sqrt(y) * sqrt(y) == y.
-    J z = sqrt(y);
-    J w = z * z;
-    VL << "z = " << z;
-    VL << "w = " << w;
-    ExpectJetsClose(w, y);
-  }
+TEST(Jet, Elementary) {
+  EXPECT_THAT((x * y) / x, IsAlmostEqualTo(y));
+  EXPECT_THAT(sqrt(x * x), IsAlmostEqualTo(x));
+  EXPECT_THAT(sqrt(y) * sqrt(y), IsAlmostEqualTo(y));
 
   NumericalTest("sqrt", sqrt<double, 2>, 0.00001);
   NumericalTest("sqrt", sqrt<double, 2>, 1.0);
 
-  {  // Check that cos(2*x) = cos(x)^2 - sin(x)^2
-    J z = cos(J(2.0) * x);
-    J w = cos(x) * cos(x) - sin(x) * sin(x);
-    VL << "z = " << z;
-    VL << "w = " << w;
-    ExpectJetsClose(w, z);
-  }
-
-  {  // Check that sin(2*x) = 2*cos(x)*sin(x)
-    J z = sin(J(2.0) * x);
-    J w = J(2.0) * cos(x) * sin(x);
-    VL << "z = " << z;
-    VL << "w = " << w;
-    ExpectJetsClose(w, z);
-  }
-
-  {  // Check that cos(x)*cos(x) + sin(x)*sin(x) = 1
-    J z = cos(x) * cos(x);
-    J w = sin(x) * sin(x);
-    VL << "z = " << z;
-    VL << "w = " << w;
-    ExpectJetsClose(z + w, J(1.0));
-  }
-
-  {  // Check that atan2(r*sin(t), r*cos(t)) = t.
-    J t = MakeJet(0.7, -0.3, +1.5);
-    J r = MakeJet(2.3, 0.13, -2.4);
-    VL << "t = " << t;
-    VL << "r = " << r;
-
-    J u = atan2(r * sin(t), r * cos(t));
-    VL << "u = " << u;
-
-    ExpectJetsClose(u, t);
-  }
-
-  {  // Check that tan(x) = sin(x) / cos(x).
-    J z = tan(x);
-    J w = sin(x) / cos(x);
-    VL << "z = " << z;
-    VL << "w = " << w;
-    ExpectJetsClose(z, w);
-  }
-
-  {  // Check that tan(atan(x)) = x.
-    J z = tan(atan(x));
-    J w = x;
-    VL << "z = " << z;
-    VL << "w = " << w;
-    ExpectJetsClose(z, w);
-  }
-
-  {  // Check that cosh(x)*cosh(x) - sinh(x)*sinh(x) = 1
-    J z = cosh(x) * cosh(x);
-    J w = sinh(x) * sinh(x);
-    VL << "z = " << z;
-    VL << "w = " << w;
-    ExpectJetsClose(z - w, J(1.0));
-  }
-
-  {  // Check that tanh(x + y) = (tanh(x) + tanh(y)) / (1 + tanh(x) tanh(y))
-    J z = tanh(x + y);
-    J w = (tanh(x) + tanh(y)) / (J(1.0) + tanh(x) * tanh(y));
-    VL << "z = " << z;
-    VL << "w = " << w;
-    ExpectJetsClose(z, w);
-  }
-
-  {  // Check that pow(x, 1) == x.
-    VL << "x = " << x;
-
-    J u = pow(x, 1.);
-    VL << "u = " << u;
-
-    ExpectJetsClose(x, u);
-  }
-
-  {  // Check that pow(x, 1) == x.
-    J y = MakeJet(1, 0.0, 0.0);
-    VL << "x = " << x;
-    VL << "y = " << y;
-
-    J u = pow(x, y);
-    VL << "u = " << u;
-
-    ExpectJetsClose(x, u);
-  }
-
-  {  // Check that pow(e, log(x)) == x.
-    J logx = log(x);
-
-    VL << "x = " << x;
-    VL << "y = " << y;
-
-    J u = pow(kE, logx);
-    VL << "u = " << u;
-
-    ExpectJetsClose(x, u);
-  }
-
-  {  // Check that pow(e, log(x)) == x.
-    J logx = log(x);
-    J e = MakeJet(kE, 0., 0.);
-    VL << "x = " << x;
-    VL << "log(x) = " << logx;
-
-    J u = pow(e, logx);
-    VL << "u = " << u;
-
-    ExpectJetsClose(x, u);
-  }
-
-  {  // Check that pow(e, log(x)) == x.
-    J logx = log(x);
-    J e = MakeJet(kE, 0., 0.);
-    VL << "x = " << x;
-    VL << "logx = " << logx;
-
-    J u = pow(e, logx);
-    VL << "u = " << u;
-
-    ExpectJetsClose(x, u);
-  }
-
-  {  // Check that pow(x,y) = exp(y*log(x)).
-    J logx = log(x);
-    J e = MakeJet(kE, 0., 0.);
-    VL << "x = " << x;
-    VL << "logx = " << logx;
-
-    J u = pow(e, y * logx);
-    J v = pow(x, y);
-    VL << "u = " << u;
-    VL << "v = " << v;
-
-    ExpectJetsClose(v, u);
-  }
-
-  {  // Check that pow(0, y) == 0 for y > 1, with both arguments Jets.
-    // This tests special case handling inside pow().
-    J a = MakeJet(0, 1, 2);
-    J b = MakeJet(2, 3, 4);
-    VL << "a = " << a;
-    VL << "b = " << b;
-
-    J c = pow(a, b);
-    VL << "a^b = " << c;
-    ExpectJetsClose(c, MakeJet(0, 0, 0));
-  }
-
-  {  // Check that pow(0, y) == 0 for y == 1, with both arguments Jets.
-    // This tests special case handling inside pow().
-    J a = MakeJet(0, 1, 2);
-    J b = MakeJet(1, 3, 4);
-    VL << "a = " << a;
-    VL << "b = " << b;
-
-    J c = pow(a, b);
-    VL << "a^b = " << c;
-    ExpectJetsClose(c, MakeJet(0, 1, 2));
-  }
-
-  {  // Check that pow(0, <1) is not finite, with both arguments Jets.
-    for (int i = 1; i < 10; i++) {
-      J a = MakeJet(0, 1, 2);
-      J b = MakeJet(i * 0.1, 3, 4);  // b = 0.1 ... 0.9
-      VL << "a = " << a;
-      VL << "b = " << b;
-
-      J c = pow(a, b);
-      VL << "a^b = " << c;
-      EXPECT_EQ(c.a, 0.0);
-      EXPECT_FALSE(IsFinite(c.v[0]));
-      EXPECT_FALSE(IsFinite(c.v[1]));
-    }
-    for (int i = -10; i < 0; i++) {
-      J a = MakeJet(0, 1, 2);
-      J b = MakeJet(i * 0.1, 3, 4);  // b = -1,-0.9 ... -0.1
-      VL << "a = " << a;
-      VL << "b = " << b;
-
-      J c = pow(a, b);
-      VL << "a^b = " << c;
-      EXPECT_FALSE(IsFinite(c.a));
-      EXPECT_FALSE(IsFinite(c.v[0]));
-      EXPECT_FALSE(IsFinite(c.v[1]));
-    }
-
-    {
-      // The special case of 0^0 = 1 defined by the C standard.
-      J a = MakeJet(0, 1, 2);
-      J b = MakeJet(0, 3, 4);
-      VL << "a = " << a;
-      VL << "b = " << b;
-
-      J c = pow(a, b);
-      VL << "a^b = " << c;
-      EXPECT_EQ(c.a, 1.0);
-      EXPECT_FALSE(IsFinite(c.v[0]));
-      EXPECT_FALSE(IsFinite(c.v[1]));
-    }
-  }
-
-  {  // Check that pow(<0, b) is correct for integer b.
-    // This tests special case handling inside pow().
-    J a = MakeJet(-1.5, 3, 4);
-
-    // b integer:
-    for (int i = -10; i <= 10; i++) {
-      J b = MakeJet(i, 0, 5);
-      VL << "a = " << a;
-      VL << "b = " << b;
-
-      J c = pow(a, b);
-      VL << "a^b = " << c;
-      ExpectClose(c.a, pow(-1.5, i), kTolerance);
-      EXPECT_TRUE(IsFinite(c.v[0]));
-      EXPECT_FALSE(IsFinite(c.v[1]));
-      ExpectClose(c.v[0], i * pow(-1.5, i - 1) * 3.0, kTolerance);
-    }
-  }
-
-  {  // Check that pow(<0, b) is correct for noninteger b.
-    // This tests special case handling inside pow().
-    J a = MakeJet(-1.5, 3, 4);
-    J b = MakeJet(-2.5, 0, 5);
-    VL << "a = " << a;
-    VL << "b = " << b;
-
-    J c = pow(a, b);
-    VL << "a^b = " << c;
-    EXPECT_FALSE(IsFinite(c.a));
-    EXPECT_FALSE(IsFinite(c.v[0]));
-    EXPECT_FALSE(IsFinite(c.v[1]));
-  }
-
+  EXPECT_THAT(x + 1.0, IsAlmostEqualTo(1.0 + x));
   {
-    // Check that pow(0,y) == 0 for y == 2, with the second argument a
-    // Jet.  This tests special case handling inside pow().
-    double a = 0;
-    J b = MakeJet(2, 3, 4);
-    VL << "a = " << a;
-    VL << "b = " << b;
-
-    J c = pow(a, b);
-    VL << "a^b = " << c;
-    ExpectJetsClose(c, MakeJet(0, 0, 0));
-  }
-
-  {
-    // Check that pow(<0,y) is correct for integer y. This tests special case
-    // handling inside pow().
-    double a = -1.5;
-    for (int i = -10; i <= 10; i++) {
-      J b = MakeJet(i, 3, 0);
-      VL << "a = " << a;
-      VL << "b = " << b;
-
-      J c = pow(a, b);
-      VL << "a^b = " << c;
-      ExpectClose(c.a, pow(-1.5, i), kTolerance);
-      EXPECT_FALSE(IsFinite(c.v[0]));
-      EXPECT_TRUE(IsFinite(c.v[1]));
-      ExpectClose(c.v[1], 0, kTolerance);
-    }
-  }
-
-  {
-    // Check that pow(<0,y) is correct for noninteger y. This tests special
-    // case handling inside pow().
-    double a = -1.5;
-    J b = MakeJet(-3.14, 3, 0);
-    VL << "a = " << a;
-    VL << "b = " << b;
-
-    J c = pow(a, b);
-    VL << "a^b = " << c;
-    EXPECT_FALSE(IsFinite(c.a));
-    EXPECT_FALSE(IsFinite(c.v[0]));
-    EXPECT_FALSE(IsFinite(c.v[1]));
-  }
-
-  {  // Check that 1 + x == x + 1.
-    J a = x + 1.0;
-    J b = 1.0 + x;
     J c = x;
     c += 1.0;
-
-    ExpectJetsClose(a, b);
-    ExpectJetsClose(a, c);
+    EXPECT_THAT(c, IsAlmostEqualTo(1.0 + x));
   }
 
-  {  // Check that 1 - x == -(x - 1).
-    J a = 1.0 - x;
-    J b = -(x - 1.0);
+  EXPECT_THAT(-(x - 1.0), IsAlmostEqualTo(1.0 - x));
+  {
     J c = x;
     c -= 1.0;
-
-    ExpectJetsClose(a, b);
-    ExpectJetsClose(a, -c);
+    EXPECT_THAT(c, IsAlmostEqualTo(x - 1.0));
   }
 
-  {  // Check that (x/s)*s == (x*s)/s.
-    J a = x / 5.0;
-    J b = x * 5.0;
+  EXPECT_THAT((x * 5.0) / 5.0, IsAlmostEqualTo((x / 5.0) * 5.0));
+  EXPECT_THAT((x * 5.0) / 5.0, IsAlmostEqualTo(x));
+  EXPECT_THAT((x / 5.0) * 5.0, IsAlmostEqualTo(x));
+
+  {
     J c = x;
     c /= 5.0;
     J d = x;
     d *= 5.0;
-
-    ExpectJetsClose(5.0 * a, b / 5.0);
-    ExpectJetsClose(a, c);
-    ExpectJetsClose(b, d);
+    EXPECT_THAT(c, IsAlmostEqualTo(x / 5.0));
+    EXPECT_THAT(d, IsAlmostEqualTo(5.0 * x));
   }
 
-  {  // Check that x / y == 1 / (y / x).
-    J a = x / y;
-    J b = 1.0 / (y / x);
-    VL << "a = " << a;
-    VL << "b = " << b;
+  EXPECT_THAT(1.0 / (y / x), IsAlmostEqualTo(x / y));
+}
 
-    ExpectJetsClose(a, b);
+TEST(Jet, Trigonometric) {
+  EXPECT_THAT(cos(2.0 * x), IsAlmostEqualTo(cos(x) * cos(x) - sin(x) * sin(x)));
+  EXPECT_THAT(sin(2.0 * x), IsAlmostEqualTo(2.0 * sin(x) * cos(x)));
+  EXPECT_THAT(sin(x) * sin(x) + cos(x) * cos(x), IsAlmostEqualTo(J(1.0)));
+
+  {
+    J t = MakeJet(0.7, -0.3, +1.5);
+    J r = MakeJet(2.3, 0.13, -2.4);
+    EXPECT_THAT(atan2(r * sin(t), r * cos(t)), IsAlmostEqualTo(t));
   }
 
-  {  // Check that abs(-x * x) == sqrt(x * x).
-    ExpectJetsClose(abs(-x), sqrt(x * x));
-  }
+  EXPECT_THAT(sin(x) / cos(x), IsAlmostEqualTo(tan(x)));
+  EXPECT_THAT(tan(atan(x)), IsAlmostEqualTo(x));
 
-  {  // Check that cos(acos(x)) == x.
+  {
     J a = MakeJet(0.1, -2.7, 1e-3);
-    ExpectJetsClose(cos(acos(a)), a);
-    ExpectJetsClose(acos(cos(a)), a);
+    EXPECT_THAT(cos(acos(a)), IsAlmostEqualTo(a));
+    EXPECT_THAT(acos(cos(a)), IsAlmostEqualTo(a));
 
     J b = MakeJet(0.6, 0.5, 1e+2);
-    ExpectJetsClose(cos(acos(b)), b);
-    ExpectJetsClose(acos(cos(b)), b);
-  }
-
-  {  // Check that sin(asin(x)) == x.
-    J a = MakeJet(0.1, -2.7, 1e-3);
-    ExpectJetsClose(sin(asin(a)), a);
-    ExpectJetsClose(asin(sin(a)), a);
-
-    J b = MakeJet(0.4, 0.5, 1e+2);
-    ExpectJetsClose(sin(asin(b)), b);
-    ExpectJetsClose(asin(sin(b)), b);
+    EXPECT_THAT(cos(acos(b)), IsAlmostEqualTo(b));
+    EXPECT_THAT(acos(cos(b)), IsAlmostEqualTo(b));
   }
 
   {
-    J zero = J(0.0);
+    J a = MakeJet(0.1, -2.7, 1e-3);
+    EXPECT_THAT(sin(asin(a)), IsAlmostEqualTo(a));
+    EXPECT_THAT(asin(sin(a)), IsAlmostEqualTo(a));
 
-    // Check that J0(0) == 1.
-    ExpectJetsClose(BesselJ0(zero), J(1.0));
-
-    // Check that J1(0) == 0.
-    ExpectJetsClose(BesselJ1(zero), zero);
-
-    // Check that J2(0) == 0.
-    ExpectJetsClose(BesselJn(2, zero), zero);
-
-    // Check that J3(0) == 0.
-    ExpectJetsClose(BesselJn(3, zero), zero);
-
-    J z = MakeJet(0.1, -2.7, 1e-3);
-
-    // Check that J0(z) == Jn(0,z).
-    ExpectJetsClose(BesselJ0(z), BesselJn(0, z));
-
-    // Check that J1(z) == Jn(1,z).
-    ExpectJetsClose(BesselJ1(z), BesselJn(1, z));
-
-    // Check that J0(z)+J2(z) == (2/z)*J1(z).
-    // See formula http://dlmf.nist.gov/10.6.E1
-    ExpectJetsClose(BesselJ0(z) + BesselJn(2, z), (2.0 / z) * BesselJ1(z));
+    J b = MakeJet(0.4, 0.5, 1e+2);
+    EXPECT_THAT(sin(asin(b)), IsAlmostEqualTo(b));
+    EXPECT_THAT(asin(sin(b)), IsAlmostEqualTo(b));
   }
+}
 
-  {  // Check that floor of a positive number works.
+TEST(Jet, Hyperbolic) {
+  // cosh(x)*cosh(x) - sinh(x)*sinh(x) = 1
+  EXPECT_THAT(cosh(x) * cosh(x) - sinh(x) * sinh(x), IsAlmostEqualTo(J(1.0)));
+
+  // tanh(x + y) = (tanh(x) + tanh(y)) / (1 + tanh(x) tanh(y))
+  EXPECT_THAT(
+      tanh(x + y),
+      IsAlmostEqualTo((tanh(x) + tanh(y)) / (J(1.0) + tanh(x) * tanh(y))));
+}
+
+TEST(Jet, Abs) {
+  EXPECT_THAT(abs(-x * x), IsAlmostEqualTo(x * x));
+  EXPECT_THAT(abs(-x), IsAlmostEqualTo(sqrt(x * x)));
+
+  {
+    J a = MakeJet(-std::numeric_limits<double>::quiet_NaN(), 2.0, 4.0);
+    J b = abs(a);
+    EXPECT_TRUE(std::signbit(b.v[0]));
+    EXPECT_TRUE(std::signbit(b.v[1]));
+  }
+}
+
+#if defined(CERES_HAS_POSIX_BESSEL_FUNCTIONS) || \
+    defined(CERES_HAS_CPP17_BESSEL_FUNCTIONS)
+TEST(Jet, Bessel) {
+  J zero = J(0.0);
+  J z = MakeJet(0.1, -2.7, 1e-3);
+
+#ifdef CERES_HAS_POSIX_BESSEL_FUNCTIONS
+  EXPECT_THAT(BesselJ0(zero), IsAlmostEqualTo(J(1.0)));
+  EXPECT_THAT(BesselJ1(zero), IsAlmostEqualTo(zero));
+  EXPECT_THAT(BesselJn(2, zero), IsAlmostEqualTo(zero));
+  EXPECT_THAT(BesselJn(3, zero), IsAlmostEqualTo(zero));
+
+  EXPECT_THAT(BesselJ0(z), IsAlmostEqualTo(BesselJn(0, z)));
+  EXPECT_THAT(BesselJ1(z), IsAlmostEqualTo(BesselJn(1, z)));
+
+  // See formula http://dlmf.nist.gov/10.6.E1
+  EXPECT_THAT(BesselJ0(z) + BesselJn(2, z),
+              IsAlmostEqualTo((2.0 / z) * BesselJ1(z)));
+#endif  // CERES_HAS_POSIX_BESSEL_FUNCTIONS
+
+#ifdef CERES_HAS_CPP17_BESSEL_FUNCTIONS
+  EXPECT_THAT(cyl_bessel_j(0, zero), IsAlmostEqualTo(J(1.0)));
+  EXPECT_THAT(cyl_bessel_j(1, zero), IsAlmostEqualTo(zero));
+  EXPECT_THAT(cyl_bessel_j(2, zero), IsAlmostEqualTo(zero));
+  EXPECT_THAT(cyl_bessel_j(3, zero), IsAlmostEqualTo(zero));
+
+  EXPECT_THAT(cyl_bessel_j(0, z), IsAlmostEqualTo(BesselJn(0, z)));
+  EXPECT_THAT(cyl_bessel_j(1, z), IsAlmostEqualTo(BesselJn(1, z)));
+
+  // MSVC Bessel functions and their derivatives produce errors slightly above
+  // kTolerance. Provide an alternative variant with a relaxed threshold.
+  constexpr double kRelaxedTolerance = 10 * kTolerance;
+
+  // See formula http://dlmf.nist.gov/10.6.E1
+  EXPECT_THAT(cyl_bessel_j(0, z) + cyl_bessel_j(2, z),
+              IsAlmostEqualToWithTolerance((2.0 / z) * cyl_bessel_j(1, z),
+                                           kRelaxedTolerance));
+
+  // MSVC does not throw an exception on invalid first argument
+#ifndef _MSC_VER
+  EXPECT_THROW(cyl_bessel_j(-1, zero), std::domain_error);
+#endif  // defined(_MSC_VER)
+#endif  // defined(CERES_HAS_CPP17_BESSEL_FUNCTIONS)
+}
+#endif  // defined(CERES_HAS_POSIX_BESSEL_FUNCTIONS) ||
+        // defined(CERES_HAS_CPP17_BESSEL_FUNCTIONS)
+
+TEST(Jet, Floor) {
+  {  // floor of a positive number works.
     J a = MakeJet(0.1, -2.7, 1e-3);
     J b = floor(a);
     J expected = MakeJet(floor(a.a), 0.0, 0.0);
     EXPECT_EQ(expected, b);
   }
 
-  {  // Check that floor of a negative number works.
+  {  // floor of a negative number works.
     J a = MakeJet(-1.1, -2.7, 1e-3);
     J b = floor(a);
     J expected = MakeJet(floor(a.a), 0.0, 0.0);
     EXPECT_EQ(expected, b);
   }
 
-  {  // Check that floor of a positive number works.
+  {  // floor of a positive number works.
     J a = MakeJet(10.123, -2.7, 1e-3);
     J b = floor(a);
     J expected = MakeJet(floor(a.a), 0.0, 0.0);
     EXPECT_EQ(expected, b);
   }
+}
 
-  {  // Check that ceil of a positive number works.
+TEST(Jet, Ceil) {
+  {  // ceil of a positive number works.
     J a = MakeJet(0.1, -2.7, 1e-3);
     J b = ceil(a);
     J expected = MakeJet(ceil(a.a), 0.0, 0.0);
     EXPECT_EQ(expected, b);
   }
 
-  {  // Check that ceil of a negative number works.
+  {  // ceil of a negative number works.
     J a = MakeJet(-1.1, -2.7, 1e-3);
     J b = ceil(a);
     J expected = MakeJet(ceil(a.a), 0.0, 0.0);
     EXPECT_EQ(expected, b);
   }
 
-  {  // Check that ceil of a positive number works.
+  {  // ceil of a positive number works.
     J a = MakeJet(10.123, -2.7, 1e-3);
     J b = ceil(a);
     J expected = MakeJet(ceil(a.a), 0.0, 0.0);
     EXPECT_EQ(expected, b);
   }
+}
 
-  {  // Check that erf works.
+TEST(Jet, Erf) {
+  {  // erf works.
     J a = MakeJet(10.123, -2.7, 1e-3);
     J b = erf(a);
     J expected = MakeJet(erf(a.a), 0.0, 0.0);
@@ -583,8 +382,10 @@
   NumericalTest("erf", erf<double, 2>, 1e-5);
   NumericalTest("erf", erf<double, 2>, 0.5);
   NumericalTest("erf", erf<double, 2>, 100.0);
+}
 
-  {  // Check that erfc works.
+TEST(Jet, Erfc) {
+  {  // erfc works.
     J a = MakeJet(10.123, -2.7, 1e-3);
     J b = erfc(a);
     J expected = MakeJet(erfc(a.a), 0.0, 0.0);
@@ -594,42 +395,48 @@
   NumericalTest("erfc", erfc<double, 2>, 1e-5);
   NumericalTest("erfc", erfc<double, 2>, 0.5);
   NumericalTest("erfc", erfc<double, 2>, 100.0);
+}
 
-  {  // Check that cbrt(x * x * x) == x.
-    J z = x * x * x;
-    J w = cbrt(z);
-    VL << "z = " << z;
-    VL << "w = " << w;
-    ExpectJetsClose(w, x);
-  }
+TEST(Jet, Cbrt) {
+  EXPECT_THAT(cbrt(x * x * x), IsAlmostEqualTo(x));
+  EXPECT_THAT(cbrt(y) * cbrt(y) * cbrt(y), IsAlmostEqualTo(y));
+  EXPECT_THAT(cbrt(x), IsAlmostEqualTo(pow(x, 1.0 / 3.0)));
 
-  {  // Check that cbrt(y) * cbrt(y) * cbrt(y) == y.
-    J z = cbrt(y);
-    J w = z * z * z;
-    VL << "z = " << z;
-    VL << "w = " << w;
-    ExpectJetsClose(w, y);
-  }
-
-  {  // Check that cbrt(x) == pow(x, 1/3).
-    J z = cbrt(x);
-    J w = pow(x, 1.0 / 3.0);
-    VL << "z = " << z;
-    VL << "w = " << w;
-    ExpectJetsClose(z, w);
-  }
   NumericalTest("cbrt", cbrt<double, 2>, -1.0);
   NumericalTest("cbrt", cbrt<double, 2>, -1e-5);
   NumericalTest("cbrt", cbrt<double, 2>, 1e-5);
   NumericalTest("cbrt", cbrt<double, 2>, 1.0);
+}
 
-  {  // Check that exp2(x) == exp(x * log(2))
-    J z = exp2(x);
-    J w = exp(x * log(2.0));
-    VL << "z = " << z;
-    VL << "w = " << w;
-    ExpectJetsClose(z, w);
+TEST(Jet, Log1p) {
+  EXPECT_THAT(log1p(expm1(x)), IsAlmostEqualTo(x));
+  EXPECT_THAT(log1p(x), IsAlmostEqualTo(log(J{1} + x)));
+
+  {  // log1p(x) does not loose precision for small x
+    J x = MakeJet(1e-16, 1e-8, 1e-4);
+    EXPECT_THAT(log1p(x),
+                IsAlmostEqualTo(MakeJet(9.9999999999999998e-17, 1e-8, 1e-4)));
+    // log(1 + x) collapses to 0
+    J v = log(J{1} + x);
+    EXPECT_TRUE(v.a == 0);
   }
+}
+
+TEST(Jet, Expm1) {
+  EXPECT_THAT(expm1(log1p(x)), IsAlmostEqualTo(x));
+  EXPECT_THAT(expm1(x), IsAlmostEqualTo(exp(x) - 1.0));
+
+  {  // expm1(x) does not loose precision for small x
+    J x = MakeJet(9.9999999999999998e-17, 1e-8, 1e-4);
+    EXPECT_THAT(expm1(x), IsAlmostEqualTo(MakeJet(1e-16, 1e-8, 1e-4)));
+    // exp(x) - 1 collapses to 0
+    J v = exp(x) - J{1};
+    EXPECT_TRUE(v.a == 0);
+  }
+}
+
+TEST(Jet, Exp2) {
+  EXPECT_THAT(exp2(x), IsAlmostEqualTo(exp(x * log(2.0))));
   NumericalTest("exp2", exp2<double, 2>, -1.0);
   NumericalTest("exp2", exp2<double, 2>, -1e-5);
   NumericalTest("exp2", exp2<double, 2>, -1e-200);
@@ -637,92 +444,514 @@
   NumericalTest("exp2", exp2<double, 2>, 1e-200);
   NumericalTest("exp2", exp2<double, 2>, 1e-5);
   NumericalTest("exp2", exp2<double, 2>, 1.0);
+}
 
-  {  // Check that log2(x) == log(x) / log(2)
-    J z = log2(x);
-    J w = log(x) / log(2.0);
-    VL << "z = " << z;
-    VL << "w = " << w;
-    ExpectJetsClose(z, w);
-  }
+TEST(Jet, Log) { EXPECT_THAT(log(exp(x)), IsAlmostEqualTo(x)); }
+
+TEST(Jet, Log10) {
+  EXPECT_THAT(log10(x), IsAlmostEqualTo(log(x) / log(10)));
+  NumericalTest("log10", log10<double, 2>, 1e-5);
+  NumericalTest("log10", log10<double, 2>, 1.0);
+  NumericalTest("log10", log10<double, 2>, 98.76);
+}
+
+TEST(Jet, Log2) {
+  EXPECT_THAT(log2(x), IsAlmostEqualTo(log(x) / log(2)));
   NumericalTest("log2", log2<double, 2>, 1e-5);
   NumericalTest("log2", log2<double, 2>, 1.0);
   NumericalTest("log2", log2<double, 2>, 100.0);
+}
 
-  {  // Check that hypot(x, y) == sqrt(x^2 + y^2)
-    J h = hypot(x, y);
-    J s = sqrt(x * x + y * y);
-    VL << "h = " << h;
-    VL << "s = " << s;
-    ExpectJetsClose(h, s);
+TEST(Jet, Norm) {
+  EXPECT_THAT(norm(x), IsAlmostEqualTo(x * x));
+  EXPECT_THAT(norm(-x), IsAlmostEqualTo(x * x));
+}
+
+TEST(Jet, Pow) {
+  EXPECT_THAT(pow(x, 1.0), IsAlmostEqualTo(x));
+  EXPECT_THAT(pow(x, MakeJet(1.0, 0.0, 0.0)), IsAlmostEqualTo(x));
+  EXPECT_THAT(pow(kE, log(x)), IsAlmostEqualTo(x));
+  EXPECT_THAT(pow(MakeJet(kE, 0., 0.), log(x)), IsAlmostEqualTo(x));
+  EXPECT_THAT(pow(x, y),
+              IsAlmostEqualTo(pow(MakeJet(kE, 0.0, 0.0), y * log(x))));
+
+  // Specially cases
+
+  // pow(0, y) == 0 for y > 1, with both arguments Jets.
+  EXPECT_THAT(pow(MakeJet(0, 1, 2), MakeJet(2, 3, 4)),
+              IsAlmostEqualTo(MakeJet(0, 0, 0)));
+
+  // pow(0, y) == 0 for y == 1, with both arguments Jets.
+  EXPECT_THAT(pow(MakeJet(0, 1, 2), MakeJet(1, 3, 4)),
+              IsAlmostEqualTo(MakeJet(0, 1, 2)));
+
+  // pow(0, <1) is not finite, with both arguments Jets.
+  {
+    for (int i = 1; i < 10; i++) {
+      J a = MakeJet(0, 1, 2);
+      J b = MakeJet(i * 0.1, 3, 4);  // b = 0.1 ... 0.9
+      J c = pow(a, b);
+      EXPECT_EQ(c.a, 0.0) << "\na: " << a << "\nb: " << b << "\na^b: " << c;
+      EXPECT_FALSE(isfinite(c.v[0]))
+          << "\na: " << a << "\nb: " << b << "\na^b: " << c;
+      EXPECT_FALSE(isfinite(c.v[1]))
+          << "\na: " << a << "\nb: " << b << "\na^b: " << c;
+    }
+
+    for (int i = -10; i < 0; i++) {
+      J a = MakeJet(0, 1, 2);
+      J b = MakeJet(i * 0.1, 3, 4);  // b = -1,-0.9 ... -0.1
+      J c = pow(a, b);
+      EXPECT_FALSE(isfinite(c.a))
+          << "\na: " << a << "\nb: " << b << "\na^b: " << c;
+      EXPECT_FALSE(isfinite(c.v[0]))
+          << "\na: " << a << "\nb: " << b << "\na^b: " << c;
+      EXPECT_FALSE(isfinite(c.v[1]))
+          << "\na: " << a << "\nb: " << b << "\na^b: " << c;
+    }
+
+    // The special case of 0^0 = 1 defined by the C standard.
+    {
+      J a = MakeJet(0, 1, 2);
+      J b = MakeJet(0, 3, 4);
+      J c = pow(a, b);
+      EXPECT_EQ(c.a, 1.0) << "\na: " << a << "\nb: " << b << "\na^b: " << c;
+      EXPECT_FALSE(isfinite(c.v[0]))
+          << "\na: " << a << "\nb: " << b << "\na^b: " << c;
+      EXPECT_FALSE(isfinite(c.v[1]))
+          << "\na: " << a << "\nb: " << b << "\na^b: " << c;
+    }
   }
 
-  {  // Check that hypot(x, x) == sqrt(2) * abs(x)
-    J h = hypot(x, x);
-    J s = sqrt(2.0) * abs(x);
-    VL << "h = " << h;
-    VL << "s = " << s;
-    ExpectJetsClose(h, s);
+  // pow(<0, b) is correct for integer b.
+  {
+    J a = MakeJet(-1.5, 3, 4);
+
+    // b integer:
+    for (int i = -10; i <= 10; i++) {
+      J b = MakeJet(i, 0, 5);
+      J c = pow(a, b);
+
+      EXPECT_TRUE(AreAlmostEqual(c.a, pow(-1.5, i), kTolerance))
+          << "\na: " << a << "\nb: " << b << "\na^b: " << c;
+      EXPECT_TRUE(isfinite(c.v[0]))
+          << "\na: " << a << "\nb: " << b << "\na^b: " << c;
+      EXPECT_FALSE(isfinite(c.v[1]))
+          << "\na: " << a << "\nb: " << b << "\na^b: " << c;
+      EXPECT_TRUE(
+          AreAlmostEqual(c.v[0], i * pow(-1.5, i - 1) * 3.0, kTolerance))
+          << "\na: " << a << "\nb: " << b << "\na^b: " << c;
+    }
   }
 
-  {  // Check that the derivative is zero tangentially to the circle:
-    J h = hypot(MakeJet(2.0, 1.0, 1.0), MakeJet(2.0, 1.0, -1.0));
-    VL << "h = " << h;
-    ExpectJetsClose(h, MakeJet(sqrt(8.0), std::sqrt(2.0), 0.0));
+  // pow(<0, b) is correct for noninteger b.
+  {
+    J a = MakeJet(-1.5, 3, 4);
+    J b = MakeJet(-2.5, 0, 5);
+    J c = pow(a, b);
+    EXPECT_FALSE(isfinite(c.a))
+        << "\na: " << a << "\nb: " << b << "\na^b: " << c;
+    EXPECT_FALSE(isfinite(c.v[0]))
+        << "\na: " << a << "\nb: " << b << "\na^b: " << c;
+    EXPECT_FALSE(isfinite(c.v[1]))
+        << "\na: " << a << "\nb: " << b << "\na^b: " << c;
   }
 
-  {  // Check that hypot(x, 0) == x
-    J zero = MakeJet(0.0, 2.0, 3.14);
-    J h = hypot(x, zero);
-    VL << "h = " << h;
-    ExpectJetsClose(x, h);
+  // pow(0,y) == 0 for y == 2, with the second argument a Jet.
+  EXPECT_THAT(pow(0.0, MakeJet(2, 3, 4)), IsAlmostEqualTo(MakeJet(0, 0, 0)));
+
+  // pow(<0,y) is correct for integer y.
+  {
+    double a = -1.5;
+    for (int i = -10; i <= 10; i++) {
+      J b = MakeJet(i, 3, 0);
+      J c = pow(a, b);
+      ExpectClose(c.a, pow(-1.5, i), kTolerance);
+      EXPECT_FALSE(isfinite(c.v[0]))
+          << "\na: " << a << "\nb: " << b << "\na^b: " << c;
+      EXPECT_TRUE(isfinite(c.v[1]))
+          << "\na: " << a << "\nb: " << b << "\na^b: " << c;
+      ExpectClose(c.v[1], 0, kTolerance);
+    }
   }
 
-  {  // Check that hypot(0, y) == y
-    J zero = MakeJet(0.0, 2.0, 3.14);
-    J h = hypot(zero, y);
-    VL << "h = " << h;
-    ExpectJetsClose(y, h);
+  // pow(<0,y) is correct for noninteger y.
+  {
+    double a = -1.5;
+    J b = MakeJet(-3.14, 3, 0);
+    J c = pow(a, b);
+    EXPECT_FALSE(isfinite(c.a))
+        << "\na: " << a << "\nb: " << b << "\na^b: " << c;
+    EXPECT_FALSE(isfinite(c.v[0]))
+        << "\na: " << a << "\nb: " << b << "\na^b: " << c;
+    EXPECT_FALSE(isfinite(c.v[1]))
+        << "\na: " << a << "\nb: " << b << "\na^b: " << c;
   }
+}
 
-  {  // Check that hypot(x, 0) == sqrt(x * x) == x, even when x * x underflows:
-    EXPECT_EQ(DBL_MIN * DBL_MIN, 0.0);  // Make sure it underflows
-    J huge = MakeJet(DBL_MIN, 2.0, 3.14);
-    J h = hypot(huge, J(0.0));
-    VL << "h = " << h;
-    ExpectJetsClose(h, huge);
-  }
-
-  {  // Check that hypot(x, 0) == sqrt(x * x) == x, even when x * x overflows:
-    EXPECT_EQ(DBL_MAX * DBL_MAX, std::numeric_limits<double>::infinity());
-    J huge = MakeJet(DBL_MAX, 2.0, 3.14);
-    J h = hypot(huge, J(0.0));
-    VL << "h = " << h;
-    ExpectJetsClose(h, huge);
-  }
+TEST(Jet, Hypot2) {
+  // Resolve the ambiguity between two and three argument hypot overloads
+  using Hypot2 = J(const J&, const J&);
+  auto* const hypot2 = static_cast<Hypot2*>(&hypot<double, 2>);
 
   // clang-format off
-  NumericalTest2("hypot", hypot<double, 2>,  0.0,   1e-5);
-  NumericalTest2("hypot", hypot<double, 2>, -1e-5,  0.0);
-  NumericalTest2("hypot", hypot<double, 2>,  1e-5,  1e-5);
-  NumericalTest2("hypot", hypot<double, 2>,  0.0,   1.0);
-  NumericalTest2("hypot", hypot<double, 2>,  1e-3,  1.0);
-  NumericalTest2("hypot", hypot<double, 2>,  1e-3, -1.0);
-  NumericalTest2("hypot", hypot<double, 2>, -1e-3,  1.0);
-  NumericalTest2("hypot", hypot<double, 2>, -1e-3, -1.0);
-  NumericalTest2("hypot", hypot<double, 2>,  1.0,   2.0);
+  NumericalTest2("hypot2", hypot2,  0.0,   1e-5);
+  NumericalTest2("hypot2", hypot2, -1e-5,  0.0);
+  NumericalTest2("hypot2", hypot2,  1e-5,  1e-5);
+  NumericalTest2("hypot2", hypot2,  0.0,   1.0);
+  NumericalTest2("hypot2", hypot2,  1e-3,  1.0);
+  NumericalTest2("hypot2", hypot2,  1e-3, -1.0);
+  NumericalTest2("hypot2", hypot2, -1e-3,  1.0);
+  NumericalTest2("hypot2", hypot2, -1e-3, -1.0);
+  NumericalTest2("hypot2", hypot2,  1.0,   2.0);
   // clang-format on
 
+  J zero = MakeJet(0.0, 2.0, 3.14);
+  EXPECT_THAT(hypot(x, y), IsAlmostEqualTo(sqrt(x * x + y * y)));
+  EXPECT_THAT(hypot(x, x), IsAlmostEqualTo(sqrt(2.0) * abs(x)));
+
+  // The derivative is zero tangentially to the circle:
+  EXPECT_THAT(hypot(MakeJet(2.0, 1.0, 1.0), MakeJet(2.0, 1.0, -1.0)),
+              IsAlmostEqualTo(MakeJet(sqrt(8.0), std::sqrt(2.0), 0.0)));
+
+  EXPECT_THAT(hypot(zero, x), IsAlmostEqualTo(x));
+  EXPECT_THAT(hypot(y, zero), IsAlmostEqualTo(y));
+
+  // hypot(x, 0, 0) == x, even when x * x underflows:
+  EXPECT_EQ(
+      std::numeric_limits<double>::min() * std::numeric_limits<double>::min(),
+      0.0);  // Make sure it underflows
+  J tiny = MakeJet(std::numeric_limits<double>::min(), 2.0, 3.14);
+  EXPECT_THAT(hypot(tiny, J{0}), IsAlmostEqualTo(tiny));
+
+  // hypot(x, 0, 0) == x, even when x * x overflows:
+  EXPECT_EQ(
+      std::numeric_limits<double>::max() * std::numeric_limits<double>::max(),
+      std::numeric_limits<double>::infinity());
+  J huge = MakeJet(std::numeric_limits<double>::max(), 2.0, 3.14);
+  EXPECT_THAT(hypot(huge, J{0}), IsAlmostEqualTo(huge));
+}
+
+TEST(Jet, Hypot3) {
+  J zero = MakeJet(0.0, 2.0, 3.14);
+
+  // hypot(x, y, z) == sqrt(x^2 + y^2 + z^2)
+  EXPECT_THAT(hypot(x, y, z), IsAlmostEqualTo(sqrt(x * x + y * y + z * z)));
+
+  // hypot(x, x) == sqrt(3) * abs(x)
+  EXPECT_THAT(hypot(x, x, x), IsAlmostEqualTo(sqrt(3.0) * abs(x)));
+
+  // The derivative is zero tangentially to the circle:
+  EXPECT_THAT(hypot(MakeJet(2.0, 1.0, 1.0),
+                    MakeJet(2.0, 1.0, -1.0),
+                    MakeJet(2.0, -1.0, 0.0)),
+              IsAlmostEqualTo(MakeJet(sqrt(12.0), 1.0 / std::sqrt(3.0), 0.0)));
+
+  EXPECT_THAT(hypot(x, zero, zero), IsAlmostEqualTo(x));
+  EXPECT_THAT(hypot(zero, y, zero), IsAlmostEqualTo(y));
+  EXPECT_THAT(hypot(zero, zero, z), IsAlmostEqualTo(z));
+  EXPECT_THAT(hypot(x, y, z), IsAlmostEqualTo(hypot(hypot(x, y), z)));
+  EXPECT_THAT(hypot(x, y, z), IsAlmostEqualTo(hypot(x, hypot(y, z))));
+
+  // The following two tests are disabled because the three argument hypot is
+  // broken in the libc++ shipped with CLANG as of January 2022.
+
+#if !defined(_LIBCPP_VERSION)
+  // hypot(x, 0, 0) == x, even when x * x underflows:
+  EXPECT_EQ(
+      std::numeric_limits<double>::min() * std::numeric_limits<double>::min(),
+      0.0);  // Make sure it underflows
+  J tiny = MakeJet(std::numeric_limits<double>::min(), 2.0, 3.14);
+  EXPECT_THAT(hypot(tiny, J{0}, J{0}), IsAlmostEqualTo(tiny));
+
+  // hypot(x, 0, 0) == x, even when x * x overflows:
+  EXPECT_EQ(
+      std::numeric_limits<double>::max() * std::numeric_limits<double>::max(),
+      std::numeric_limits<double>::infinity());
+  J huge = MakeJet(std::numeric_limits<double>::max(), 2.0, 3.14);
+  EXPECT_THAT(hypot(huge, J{0}, J{0}), IsAlmostEqualTo(huge));
+#endif
+}
+
+#ifdef CERES_HAS_CPP20
+
+TEST(Jet, Lerp) {
+  EXPECT_THAT(lerp(x, y, J{0}), IsAlmostEqualTo(x));
+  EXPECT_THAT(lerp(x, y, J{1}), IsAlmostEqualTo(y));
+  EXPECT_THAT(lerp(x, x, J{1}), IsAlmostEqualTo(x));
+  EXPECT_THAT(lerp(y, y, J{0}), IsAlmostEqualTo(y));
+  EXPECT_THAT(lerp(x, y, J{0.5}), IsAlmostEqualTo((x + y) / J{2.0}));
+  EXPECT_THAT(lerp(x, y, J{2}), IsAlmostEqualTo(J{2.0} * y - x));
+  EXPECT_THAT(lerp(x, y, J{-2}), IsAlmostEqualTo(J{3.0} * x - J{2} * y));
+}
+
+TEST(Jet, Midpoint) {
+  EXPECT_THAT(midpoint(x, y), IsAlmostEqualTo((x + y) / J{2}));
+  EXPECT_THAT(midpoint(x, x), IsAlmostEqualTo(x));
+
   {
-    J z = fmax(x, y);
-    VL << "z = " << z;
-    ExpectJetsClose(x, z);
+    // midpoint(x, y) = (x + y) / 2 while avoiding overflow
+    J x = MakeJet(std::numeric_limits<double>::min(), 1, 2);
+    J y = MakeJet(std::numeric_limits<double>::max(), 3, 4);
+    EXPECT_THAT(midpoint(x, y), IsAlmostEqualTo(x + (y - x) / J{2}));
   }
 
   {
-    J z = fmin(x, y);
-    VL << "z = " << z;
-    ExpectJetsClose(y, z);
+    // midpoint(x, x) = x while avoiding overflow
+    J x = MakeJet(std::numeric_limits<double>::max(),
+                  std::numeric_limits<double>::max(),
+                  std::numeric_limits<double>::max());
+    EXPECT_THAT(midpoint(x, x), IsAlmostEqualTo(x));
+  }
+
+  {  // midpoint does not overflow for very large values
+    constexpr double a = 0.75 * std::numeric_limits<double>::max();
+    J x = MakeJet(a, a, -a);
+    J y = MakeJet(a, a, a);
+    EXPECT_THAT(midpoint(x, y), IsAlmostEqualTo(MakeJet(a, a, 0)));
+  }
+}
+
+#endif  // defined(CERES_HAS_CPP20)
+
+TEST(Jet, Fma) {
+  J v = fma(x, y, z);
+  J w = x * y + z;
+  EXPECT_THAT(v, IsAlmostEqualTo(w));
+}
+
+TEST(Jet, FmaxJetWithJet) {
+  Fenv env;
+  // Clear all exceptions to ensure none are set by the following function
+  // calls.
+  std::feclearexcept(FE_ALL_EXCEPT);
+
+  EXPECT_THAT(fmax(x, y), IsAlmostEqualTo(x));
+  EXPECT_THAT(fmax(y, x), IsAlmostEqualTo(x));
+
+  // Average the Jets on equality (of scalar parts).
+  const J scalar_part_only_equal_to_x = J(x.a, 2 * x.v);
+  const J average = (x + scalar_part_only_equal_to_x) * 0.5;
+  EXPECT_THAT(fmax(x, scalar_part_only_equal_to_x), IsAlmostEqualTo(average));
+  EXPECT_THAT(fmax(scalar_part_only_equal_to_x, x), IsAlmostEqualTo(average));
+
+  // Follow convention of fmax(): treat NANs as missing values.
+  const J nan_scalar_part(std::numeric_limits<double>::quiet_NaN(), 2 * x.v);
+  EXPECT_THAT(fmax(x, nan_scalar_part), IsAlmostEqualTo(x));
+  EXPECT_THAT(fmax(nan_scalar_part, x), IsAlmostEqualTo(x));
+
+#ifndef CERES_NO_FENV_ACCESS
+  EXPECT_EQ(std::fetestexcept(FE_ALL_EXCEPT & ~FE_INEXACT), 0);
+#endif
+}
+
+TEST(Jet, FmaxJetWithScalar) {
+  Fenv env;
+  // Clear all exceptions to ensure none are set by the following function
+  // calls.
+  std::feclearexcept(FE_ALL_EXCEPT);
+
+  EXPECT_THAT(fmax(x, y.a), IsAlmostEqualTo(x));
+  EXPECT_THAT(fmax(y.a, x), IsAlmostEqualTo(x));
+  EXPECT_THAT(fmax(y, x.a), IsAlmostEqualTo(J{x.a}));
+  EXPECT_THAT(fmax(x.a, y), IsAlmostEqualTo(J{x.a}));
+
+  // Average the Jet and scalar cast to a Jet on equality (of scalar parts).
+  const J average = (x + J{x.a}) * 0.5;
+  EXPECT_THAT(fmax(x, x.a), IsAlmostEqualTo(average));
+  EXPECT_THAT(fmax(x.a, x), IsAlmostEqualTo(average));
+
+  // Follow convention of fmax(): treat NANs as missing values.
+  EXPECT_THAT(fmax(x, std::numeric_limits<double>::quiet_NaN()),
+              IsAlmostEqualTo(x));
+  EXPECT_THAT(fmax(std::numeric_limits<double>::quiet_NaN(), x),
+              IsAlmostEqualTo(x));
+  const J nan_scalar_part(std::numeric_limits<double>::quiet_NaN(), 2 * x.v);
+  EXPECT_THAT(fmax(nan_scalar_part, x.a), IsAlmostEqualTo(J{x.a}));
+  EXPECT_THAT(fmax(x.a, nan_scalar_part), IsAlmostEqualTo(J{x.a}));
+
+#ifndef CERES_NO_FENV_ACCESS
+  EXPECT_EQ(std::fetestexcept(FE_ALL_EXCEPT & ~FE_INEXACT), 0);
+#endif
+}
+
+TEST(Jet, FminJetWithJet) {
+  Fenv env;
+  // Clear all exceptions to ensure none are set by the following function
+  // calls.
+  std::feclearexcept(FE_ALL_EXCEPT);
+
+  EXPECT_THAT(fmin(x, y), IsAlmostEqualTo(y));
+  EXPECT_THAT(fmin(y, x), IsAlmostEqualTo(y));
+
+  // Average the Jets on equality (of scalar parts).
+  const J scalar_part_only_equal_to_x = J(x.a, 2 * x.v);
+  const J average = (x + scalar_part_only_equal_to_x) * 0.5;
+  EXPECT_THAT(fmin(x, scalar_part_only_equal_to_x), IsAlmostEqualTo(average));
+  EXPECT_THAT(fmin(scalar_part_only_equal_to_x, x), IsAlmostEqualTo(average));
+
+  // Follow convention of fmin(): treat NANs as missing values.
+  const J nan_scalar_part(std::numeric_limits<double>::quiet_NaN(), 2 * x.v);
+  EXPECT_THAT(fmin(x, nan_scalar_part), IsAlmostEqualTo(x));
+  EXPECT_THAT(fmin(nan_scalar_part, x), IsAlmostEqualTo(x));
+
+#ifndef CERES_NO_FENV_ACCESS
+  EXPECT_EQ(std::fetestexcept(FE_ALL_EXCEPT & ~FE_INEXACT), 0);
+#endif
+}
+
+TEST(Jet, FminJetWithScalar) {
+  Fenv env;
+  // Clear all exceptions to ensure none are set by the following function
+  // calls.
+  std::feclearexcept(FE_ALL_EXCEPT);
+
+  EXPECT_THAT(fmin(x, y.a), IsAlmostEqualTo(J{y.a}));
+  EXPECT_THAT(fmin(y.a, x), IsAlmostEqualTo(J{y.a}));
+  EXPECT_THAT(fmin(y, x.a), IsAlmostEqualTo(y));
+  EXPECT_THAT(fmin(x.a, y), IsAlmostEqualTo(y));
+
+  // Average the Jet and scalar cast to a Jet on equality (of scalar parts).
+  const J average = (x + J{x.a}) * 0.5;
+  EXPECT_THAT(fmin(x, x.a), IsAlmostEqualTo(average));
+  EXPECT_THAT(fmin(x.a, x), IsAlmostEqualTo(average));
+
+  // Follow convention of fmin(): treat NANs as missing values.
+  EXPECT_THAT(fmin(x, std::numeric_limits<double>::quiet_NaN()),
+              IsAlmostEqualTo(x));
+  EXPECT_THAT(fmin(std::numeric_limits<double>::quiet_NaN(), x),
+              IsAlmostEqualTo(x));
+  const J nan_scalar_part(std::numeric_limits<double>::quiet_NaN(), 2 * x.v);
+  EXPECT_THAT(fmin(nan_scalar_part, x.a), IsAlmostEqualTo(J{x.a}));
+  EXPECT_THAT(fmin(x.a, nan_scalar_part), IsAlmostEqualTo(J{x.a}));
+
+#ifndef CERES_NO_FENV_ACCESS
+  EXPECT_EQ(std::fetestexcept(FE_ALL_EXCEPT & ~FE_INEXACT), 0);
+#endif
+}
+
+TEST(Jet, Fdim) {
+  Fenv env;
+  // Clear all exceptions to ensure none are set by the following function
+  // calls.
+  std::feclearexcept(FE_ALL_EXCEPT);
+
+  const J zero{};
+  const J diff = x - y;
+  const J diffx = x - J{y.a};
+  const J diffy = J{x.a} - y;
+
+  EXPECT_THAT(fdim(x, y), IsAlmostEqualTo(diff));
+  EXPECT_THAT(fdim(y, x), IsAlmostEqualTo(zero));
+  EXPECT_THAT(fdim(x, y.a), IsAlmostEqualTo(diffx));
+  EXPECT_THAT(fdim(y.a, x), IsAlmostEqualTo(J{zero.a}));
+  EXPECT_THAT(fdim(x.a, y), IsAlmostEqualTo(diffy));
+  EXPECT_THAT(fdim(y, x.a), IsAlmostEqualTo(zero));
+  EXPECT_TRUE(isnan(fdim(x, std::numeric_limits<J>::quiet_NaN())));
+  EXPECT_TRUE(isnan(fdim(std::numeric_limits<J>::quiet_NaN(), x)));
+  EXPECT_TRUE(isnan(fdim(x, std::numeric_limits<double>::quiet_NaN())));
+  EXPECT_TRUE(isnan(fdim(std::numeric_limits<double>::quiet_NaN(), x)));
+
+#ifndef CERES_NO_FENV_ACCESS
+  EXPECT_EQ(std::fetestexcept(FE_ALL_EXCEPT & ~FE_INEXACT), 0);
+#endif
+}
+
+TEST(Jet, CopySign) {
+  {  // copysign(x, +1)
+    J z = copysign(x, J{+1});
+    EXPECT_THAT(z, IsAlmostEqualTo(x));
+    EXPECT_TRUE(isfinite(z.v[0])) << z;
+    EXPECT_TRUE(isfinite(z.v[1])) << z;
+  }
+  {  // copysign(x, -1)
+    J z = copysign(x, J{-1});
+    EXPECT_THAT(z, IsAlmostEqualTo(-x));
+    EXPECT_TRUE(isfinite(z.v[0])) << z;
+    EXPECT_TRUE(isfinite(z.v[1])) << z;
+  }
+  {  // copysign(-x, +1)
+
+    J z = copysign(-x, J{+1});
+    EXPECT_THAT(z, IsAlmostEqualTo(x));
+    EXPECT_TRUE(isfinite(z.v[0])) << z;
+    EXPECT_TRUE(isfinite(z.v[1])) << z;
+  }
+  {  // copysign(-x, -1)
+    J z = copysign(-x, J{-1});
+    EXPECT_THAT(z, IsAlmostEqualTo(-x));
+    EXPECT_TRUE(isfinite(z.v[0])) << z;
+    EXPECT_TRUE(isfinite(z.v[1])) << z;
+  }
+  {  // copysign(-0, +1)
+    J z = copysign(MakeJet(-0, 1, 2), J{+1});
+    EXPECT_THAT(z, IsAlmostEqualTo(MakeJet(+0, 1, 2)));
+    EXPECT_FALSE(std::signbit(z.a)) << z;
+    EXPECT_TRUE(isfinite(z.v[0])) << z;
+    EXPECT_TRUE(isfinite(z.v[1])) << z;
+  }
+  {  // copysign(-0, -1)
+    J z = copysign(MakeJet(-0, 1, 2), J{-1});
+    EXPECT_THAT(z, IsAlmostEqualTo(MakeJet(-0, -1, -2)));
+    EXPECT_TRUE(std::signbit(z.a)) << z;
+    EXPECT_TRUE(isfinite(z.v[0])) << z;
+    EXPECT_TRUE(isfinite(z.v[1])) << z;
+  }
+  {  // copysign(+0, -1)
+    J z = copysign(MakeJet(+0, 1, 2), J{-1});
+    EXPECT_THAT(z, IsAlmostEqualTo(MakeJet(-0, -1, -2)));
+    EXPECT_TRUE(std::signbit(z.a)) << z;
+    EXPECT_TRUE(isfinite(z.v[0])) << z;
+    EXPECT_TRUE(isfinite(z.v[1])) << z;
+  }
+  {  // copysign(+0, +1)
+    J z = copysign(MakeJet(+0, 1, 2), J{+1});
+    EXPECT_THAT(z, IsAlmostEqualTo(MakeJet(+0, 1, 2)));
+    EXPECT_FALSE(std::signbit(z.a)) << z;
+    EXPECT_TRUE(isfinite(z.v[0])) << z;
+    EXPECT_TRUE(isfinite(z.v[1])) << z;
+  }
+  {  // copysign(+0, +0)
+    J z = copysign(MakeJet(+0, 1, 2), J{+0});
+    EXPECT_FALSE(std::signbit(z.a)) << z;
+    EXPECT_TRUE(isnan(z.v[0])) << z;
+    EXPECT_TRUE(isnan(z.v[1])) << z;
+  }
+  {  // copysign(+0, -0)
+    J z = copysign(MakeJet(+0, 1, 2), J{-0});
+    EXPECT_FALSE(std::signbit(z.a)) << z;
+    EXPECT_TRUE(isnan(z.v[0])) << z;
+    EXPECT_TRUE(isnan(z.v[1])) << z;
+  }
+  {  // copysign(-0, +0)
+    J z = copysign(MakeJet(-0, 1, 2), J{+0});
+    EXPECT_FALSE(std::signbit(z.a)) << z;
+    EXPECT_TRUE(isnan(z.v[0])) << z;
+    EXPECT_TRUE(isnan(z.v[1])) << z;
+  }
+  {  // copysign(-0, -0)
+    J z = copysign(MakeJet(-0, 1, 2), J{-0});
+    EXPECT_FALSE(std::signbit(z.a)) << z;
+    EXPECT_TRUE(isnan(z.v[0])) << z;
+    EXPECT_TRUE(isnan(z.v[1])) << z;
+  }
+  {  // copysign(1, -nan)
+    J z = copysign(MakeJet(1, 2, 3),
+                   -J{std::numeric_limits<double>::quiet_NaN()});
+    EXPECT_TRUE(std::signbit(z.a)) << z;
+    EXPECT_TRUE(std::signbit(z.v[0])) << z;
+    EXPECT_TRUE(std::signbit(z.v[1])) << z;
+    EXPECT_FALSE(isnan(z.v[0])) << z;
+    EXPECT_FALSE(isnan(z.v[1])) << z;
+  }
+  {  // copysign(1, +nan)
+    J z = copysign(MakeJet(1, 2, 3),
+                   +J{std::numeric_limits<double>::quiet_NaN()});
+    EXPECT_FALSE(std::signbit(z.a)) << z;
+    EXPECT_FALSE(std::signbit(z.v[0])) << z;
+    EXPECT_FALSE(std::signbit(z.v[1])) << z;
+    EXPECT_FALSE(isnan(z.v[0])) << z;
+    EXPECT_FALSE(isnan(z.v[1])) << z;
   }
 }
 
@@ -738,56 +967,188 @@
   M << x, y, z, w;
   v << x, z;
 
-  // Check that M * v == (v^T * M^T)^T
+  // M * v == (v^T * M^T)^T
   r1 = M * v;
   r2 = (v.transpose() * M.transpose()).transpose();
 
-  ExpectJetsClose(r1(0), r2(0));
-  ExpectJetsClose(r1(1), r2(1));
+  EXPECT_THAT(r1(0), IsAlmostEqualTo(r2(0)));
+  EXPECT_THAT(r1(1), IsAlmostEqualTo(r2(1)));
 }
 
-TEST(JetTraitsTest, ClassificationMixed) {
-  Jet<double, 3> a(5.5, 0);
-  a.v[0] = std::numeric_limits<double>::quiet_NaN();
-  a.v[1] = std::numeric_limits<double>::infinity();
-  a.v[2] = -std::numeric_limits<double>::infinity();
-  EXPECT_FALSE(IsFinite(a));
-  EXPECT_FALSE(IsNormal(a));
-  EXPECT_TRUE(IsInfinite(a));
-  EXPECT_TRUE(IsNaN(a));
+TEST(Jet, ScalarComparison) {
+  Jet<double, 1> zero{0.0};
+  zero.v << std::numeric_limits<double>::infinity();
+
+  Jet<double, 1> one{1.0};
+  one.v << std::numeric_limits<double>::quiet_NaN();
+
+  Jet<double, 1> two{2.0};
+  two.v << std::numeric_limits<double>::min() / 2;
+
+  Jet<double, 1> three{3.0};
+
+  auto inf = std::numeric_limits<Jet<double, 1>>::infinity();
+  auto nan = std::numeric_limits<Jet<double, 1>>::quiet_NaN();
+  inf.v << 1.2;
+  nan.v << 3.4;
+
+  std::feclearexcept(FE_ALL_EXCEPT);
+
+  EXPECT_FALSE(islessgreater(zero, zero));
+  EXPECT_FALSE(islessgreater(zero, zero.a));
+  EXPECT_FALSE(islessgreater(zero.a, zero));
+
+  EXPECT_TRUE(isgreaterequal(three, three));
+  EXPECT_TRUE(isgreaterequal(three, three.a));
+  EXPECT_TRUE(isgreaterequal(three.a, three));
+
+  EXPECT_TRUE(isgreater(three, two));
+  EXPECT_TRUE(isgreater(three, two.a));
+  EXPECT_TRUE(isgreater(three.a, two));
+
+  EXPECT_TRUE(islessequal(one, one));
+  EXPECT_TRUE(islessequal(one, one.a));
+  EXPECT_TRUE(islessequal(one.a, one));
+
+  EXPECT_TRUE(isless(one, two));
+  EXPECT_TRUE(isless(one, two.a));
+  EXPECT_TRUE(isless(one.a, two));
+
+  EXPECT_FALSE(isunordered(inf, one));
+  EXPECT_FALSE(isunordered(inf, one.a));
+  EXPECT_FALSE(isunordered(inf.a, one));
+
+  EXPECT_TRUE(isunordered(nan, two));
+  EXPECT_TRUE(isunordered(nan, two.a));
+  EXPECT_TRUE(isunordered(nan.a, two));
+
+  EXPECT_TRUE(isunordered(inf, nan));
+  EXPECT_TRUE(isunordered(inf, nan.a));
+  EXPECT_TRUE(isunordered(inf.a, nan.a));
+
+  EXPECT_EQ(std::fetestexcept(FE_ALL_EXCEPT & ~FE_INEXACT), 0);
+}
+
+TEST(Jet, Nested2XScalarComparison) {
+  Jet<J0d, 1> zero{J0d{0.0}};
+  zero.v << std::numeric_limits<J0d>::infinity();
+
+  Jet<J0d, 1> one{J0d{1.0}};
+  one.v << std::numeric_limits<J0d>::quiet_NaN();
+
+  Jet<J0d, 1> two{J0d{2.0}};
+  two.v << std::numeric_limits<J0d>::min() / J0d{2};
+
+  Jet<J0d, 1> three{J0d{3.0}};
+
+  auto inf = std::numeric_limits<Jet<J0d, 1>>::infinity();
+  auto nan = std::numeric_limits<Jet<J0d, 1>>::quiet_NaN();
+  inf.v << J0d{1.2};
+  nan.v << J0d{3.4};
+
+  std::feclearexcept(FE_ALL_EXCEPT);
+
+  EXPECT_FALSE(islessgreater(zero, zero));
+  EXPECT_FALSE(islessgreater(zero, zero.a));
+  EXPECT_FALSE(islessgreater(zero.a, zero));
+  EXPECT_FALSE(islessgreater(zero, zero.a.a));
+  EXPECT_FALSE(islessgreater(zero.a.a, zero));
+
+  EXPECT_TRUE(isgreaterequal(three, three));
+  EXPECT_TRUE(isgreaterequal(three, three.a));
+  EXPECT_TRUE(isgreaterequal(three.a, three));
+  EXPECT_TRUE(isgreaterequal(three, three.a.a));
+  EXPECT_TRUE(isgreaterequal(three.a.a, three));
+
+  EXPECT_TRUE(isgreater(three, two));
+  EXPECT_TRUE(isgreater(three, two.a));
+  EXPECT_TRUE(isgreater(three.a, two));
+  EXPECT_TRUE(isgreater(three, two.a.a));
+  EXPECT_TRUE(isgreater(three.a.a, two));
+
+  EXPECT_TRUE(islessequal(one, one));
+  EXPECT_TRUE(islessequal(one, one.a));
+  EXPECT_TRUE(islessequal(one.a, one));
+  EXPECT_TRUE(islessequal(one, one.a.a));
+  EXPECT_TRUE(islessequal(one.a.a, one));
+
+  EXPECT_TRUE(isless(one, two));
+  EXPECT_TRUE(isless(one, two.a));
+  EXPECT_TRUE(isless(one.a, two));
+  EXPECT_TRUE(isless(one, two.a.a));
+  EXPECT_TRUE(isless(one.a.a, two));
+
+  EXPECT_FALSE(isunordered(inf, one));
+  EXPECT_FALSE(isunordered(inf, one.a));
+  EXPECT_FALSE(isunordered(inf.a, one));
+  EXPECT_FALSE(isunordered(inf, one.a.a));
+  EXPECT_FALSE(isunordered(inf.a.a, one));
+
+  EXPECT_TRUE(isunordered(nan, two));
+  EXPECT_TRUE(isunordered(nan, two.a));
+  EXPECT_TRUE(isunordered(nan.a, two));
+  EXPECT_TRUE(isunordered(nan, two.a.a));
+  EXPECT_TRUE(isunordered(nan.a.a, two));
+
+  EXPECT_TRUE(isunordered(inf, nan));
+  EXPECT_TRUE(isunordered(inf, nan.a));
+  EXPECT_TRUE(isunordered(inf.a, nan));
+  EXPECT_TRUE(isunordered(inf, nan.a.a));
+  EXPECT_TRUE(isunordered(inf.a.a, nan));
+
+  EXPECT_EQ(std::fetestexcept(FE_ALL_EXCEPT & ~FE_INEXACT), 0);
 }
 
 TEST(JetTraitsTest, ClassificationNaN) {
-  Jet<double, 3> a(5.5, 0);
-  a.v[0] = std::numeric_limits<double>::quiet_NaN();
-  a.v[1] = 0.0;
-  a.v[2] = 0.0;
-  EXPECT_FALSE(IsFinite(a));
-  EXPECT_FALSE(IsNormal(a));
-  EXPECT_FALSE(IsInfinite(a));
-  EXPECT_TRUE(IsNaN(a));
+  Jet<double, 1> a(std::numeric_limits<double>::quiet_NaN());
+  a.v << std::numeric_limits<double>::infinity();
+  EXPECT_EQ(fpclassify(a), FP_NAN);
+  EXPECT_FALSE(isfinite(a));
+  EXPECT_FALSE(isinf(a));
+  EXPECT_FALSE(isnormal(a));
+  EXPECT_FALSE(signbit(a));
+  EXPECT_TRUE(isnan(a));
 }
 
 TEST(JetTraitsTest, ClassificationInf) {
-  Jet<double, 3> a(5.5, 0);
-  a.v[0] = std::numeric_limits<double>::infinity();
-  a.v[1] = 0.0;
-  a.v[2] = 0.0;
-  EXPECT_FALSE(IsFinite(a));
-  EXPECT_FALSE(IsNormal(a));
-  EXPECT_TRUE(IsInfinite(a));
-  EXPECT_FALSE(IsNaN(a));
+  Jet<double, 1> a(-std::numeric_limits<double>::infinity());
+  a.v << std::numeric_limits<double>::quiet_NaN();
+  EXPECT_EQ(fpclassify(a), FP_INFINITE);
+  EXPECT_FALSE(isfinite(a));
+  EXPECT_FALSE(isnan(a));
+  EXPECT_FALSE(isnormal(a));
+  EXPECT_TRUE(signbit(a));
+  EXPECT_TRUE(isinf(a));
 }
 
 TEST(JetTraitsTest, ClassificationFinite) {
-  Jet<double, 3> a(5.5, 0);
-  a.v[0] = 100.0;
-  a.v[1] = 1.0;
-  a.v[2] = 3.14159;
-  EXPECT_TRUE(IsFinite(a));
-  EXPECT_TRUE(IsNormal(a));
-  EXPECT_FALSE(IsInfinite(a));
-  EXPECT_FALSE(IsNaN(a));
+  Jet<double, 1> a(-5.5);
+  a.v << std::numeric_limits<double>::quiet_NaN();
+  EXPECT_EQ(fpclassify(a), FP_NORMAL);
+  EXPECT_FALSE(isinf(a));
+  EXPECT_FALSE(isnan(a));
+  EXPECT_TRUE(signbit(a));
+  EXPECT_TRUE(isfinite(a));
+  EXPECT_TRUE(isnormal(a));
+}
+
+TEST(JetTraitsTest, ClassificationScalar) {
+  EXPECT_EQ(fpclassify(J0d{+0.0}), FP_ZERO);
+  EXPECT_EQ(fpclassify(J0d{-0.0}), FP_ZERO);
+  EXPECT_EQ(fpclassify(J0d{1.234}), FP_NORMAL);
+  EXPECT_EQ(fpclassify(J0d{std::numeric_limits<double>::min() / 2}),
+            FP_SUBNORMAL);
+  EXPECT_EQ(fpclassify(J0d{std::numeric_limits<double>::quiet_NaN()}), FP_NAN);
+}
+
+TEST(JetTraitsTest, Nested2XClassificationScalar) {
+  EXPECT_EQ(fpclassify(J0<J0d>{J0d{+0.0}}), FP_ZERO);
+  EXPECT_EQ(fpclassify(J0<J0d>{J0d{-0.0}}), FP_ZERO);
+  EXPECT_EQ(fpclassify(J0<J0d>{J0d{1.234}}), FP_NORMAL);
+  EXPECT_EQ(fpclassify(J0<J0d>{J0d{std::numeric_limits<double>::min() / 2}}),
+            FP_SUBNORMAL);
+  EXPECT_EQ(fpclassify(J0<J0d>{J0d{std::numeric_limits<double>::quiet_NaN()}}),
+            FP_NAN);
 }
 
 // The following test ensures that Jets have all the appropriate Eigen
@@ -854,7 +1215,7 @@
 
   const J sum = a.sum();
   const J sum2 = a(0) + a(1);
-  ExpectJetsClose(sum, sum2);
+  EXPECT_THAT(sum, IsAlmostEqualTo(sum2));
 }
 
 TEST(JetTraitsTest, MatrixScalarBinaryOps) {
@@ -869,22 +1230,22 @@
   M << x, y, z, w;
   v << 0.6, -2.1;
 
-  // Check that M * v == M * v.cast<J>().
+  // M * v == M * v.cast<J>().
   const Eigen::Matrix<J, 2, 1> r1 = M * v;
   const Eigen::Matrix<J, 2, 1> r2 = M * v.cast<J>();
 
-  ExpectJetsClose(r1(0), r2(0));
-  ExpectJetsClose(r1(1), r2(1));
+  EXPECT_THAT(r1(0), IsAlmostEqualTo(r2(0)));
+  EXPECT_THAT(r1(1), IsAlmostEqualTo(r2(1)));
 
-  // Check that M * a == M * T(a).
+  // M * a == M * T(a).
   const double a = 3.1;
   const Eigen::Matrix<J, 2, 2> r3 = M * a;
   const Eigen::Matrix<J, 2, 2> r4 = M * J(a);
 
-  ExpectJetsClose(r3(0, 0), r4(0, 0));
-  ExpectJetsClose(r3(1, 0), r4(1, 0));
-  ExpectJetsClose(r3(0, 1), r4(0, 1));
-  ExpectJetsClose(r3(1, 1), r4(1, 1));
+  EXPECT_THAT(r3(0, 0), IsAlmostEqualTo(r4(0, 0)));
+  EXPECT_THAT(r3(0, 1), IsAlmostEqualTo(r4(0, 1)));
+  EXPECT_THAT(r3(1, 0), IsAlmostEqualTo(r4(1, 0)));
+  EXPECT_THAT(r3(1, 1), IsAlmostEqualTo(r4(1, 1)));
 }
 
 TEST(JetTraitsTest, ArrayScalarUnaryOps) {
@@ -895,7 +1256,7 @@
 
   const J sum = a.sum();
   const J sum2 = a(0) + a(1);
-  ExpectJetsClose(sum, sum2);
+  EXPECT_THAT(sum, sum2);
 }
 
 TEST(JetTraitsTest, ArrayScalarBinaryOps) {
@@ -908,25 +1269,25 @@
   a << x, y;
   b << 0.6, -2.1;
 
-  // Check that a * b == a * b.cast<T>()
+  // a * b == a * b.cast<T>()
   const Eigen::Array<J, 2, 1> r1 = a * b;
   const Eigen::Array<J, 2, 1> r2 = a * b.cast<J>();
 
-  ExpectJetsClose(r1(0), r2(0));
-  ExpectJetsClose(r1(1), r2(1));
+  EXPECT_THAT(r1(0), r2(0));
+  EXPECT_THAT(r1(1), r2(1));
 
-  // Check that a * c == a * T(c).
+  // a * c == a * T(c).
   const double c = 3.1;
   const Eigen::Array<J, 2, 1> r3 = a * c;
   const Eigen::Array<J, 2, 1> r4 = a * J(c);
 
-  ExpectJetsClose(r3(0), r3(0));
-  ExpectJetsClose(r4(1), r4(1));
+  EXPECT_THAT(r3(0), r3(0));
+  EXPECT_THAT(r4(1), r4(1));
 }
 
-TEST(Jet, nested3x) {
-  typedef Jet<J, 2> JJ;
-  typedef Jet<JJ, 2> JJJ;
+TEST(Jet, Nested3X) {
+  using JJ = Jet<J, 2>;
+  using JJJ = Jet<JJ, 2>;
 
   JJJ x;
   x.a = JJ(J(1, 0), 0);
@@ -947,5 +1308,92 @@
   ExpectClose(e.v[0].v[0].v[0], kE, kTolerance);
 }
 
-}  // namespace internal
-}  // namespace ceres
+#if GTEST_HAS_TYPED_TEST
+
+using Types = testing::Types<std::int16_t,
+                             std::uint16_t,
+                             std::int32_t,
+                             std::uint32_t,
+                             std::int64_t,
+                             std::uint64_t,
+                             float,
+                             double,
+                             long double>;
+
+template <typename T>
+class JetTest : public testing::Test {};
+
+TYPED_TEST_SUITE(JetTest, Types);
+
+TYPED_TEST(JetTest, Comparison) {
+  using Scalar = TypeParam;
+
+  EXPECT_EQ(J0<Scalar>{0}, J0<Scalar>{0});
+  EXPECT_GE(J0<Scalar>{3}, J0<Scalar>{3});
+  EXPECT_GT(J0<Scalar>{3}, J0<Scalar>{2});
+  EXPECT_LE(J0<Scalar>{1}, J0<Scalar>{1});
+  EXPECT_LT(J0<Scalar>{1}, J0<Scalar>{2});
+  EXPECT_NE(J0<Scalar>{1}, J0<Scalar>{2});
+}
+
+TYPED_TEST(JetTest, ScalarComparison) {
+  using Scalar = TypeParam;
+
+  EXPECT_EQ(J0d{0.0}, Scalar{0});
+  EXPECT_GE(J0d{3.0}, Scalar{3});
+  EXPECT_GT(J0d{3.0}, Scalar{2});
+  EXPECT_LE(J0d{1.0}, Scalar{1});
+  EXPECT_LT(J0d{1.0}, Scalar{2});
+  EXPECT_NE(J0d{1.0}, Scalar{2});
+
+  EXPECT_EQ(Scalar{0}, J0d{0.0});
+  EXPECT_GE(Scalar{1}, J0d{1.0});
+  EXPECT_GT(Scalar{2}, J0d{1.0});
+  EXPECT_LE(Scalar{3}, J0d{3.0});
+  EXPECT_LT(Scalar{2}, J0d{3.0});
+  EXPECT_NE(Scalar{2}, J0d{1.0});
+}
+
+TYPED_TEST(JetTest, Nested2XComparison) {
+  using Scalar = TypeParam;
+
+  EXPECT_EQ(J0<J0d>{J0d{0.0}}, Scalar{0});
+  EXPECT_GE(J0<J0d>{J0d{3.0}}, Scalar{3});
+  EXPECT_GT(J0<J0d>{J0d{3.0}}, Scalar{2});
+  EXPECT_LE(J0<J0d>{J0d{1.0}}, Scalar{1});
+  EXPECT_LT(J0<J0d>{J0d{1.0}}, Scalar{2});
+  EXPECT_NE(J0<J0d>{J0d{1.0}}, Scalar{2});
+
+  EXPECT_EQ(Scalar{0}, J0<J0d>{J0d{0.0}});
+  EXPECT_GE(Scalar{1}, J0<J0d>{J0d{1.0}});
+  EXPECT_GT(Scalar{2}, J0<J0d>{J0d{1.0}});
+  EXPECT_LE(Scalar{3}, J0<J0d>{J0d{3.0}});
+  EXPECT_LT(Scalar{2}, J0<J0d>{J0d{3.0}});
+  EXPECT_NE(Scalar{2}, J0<J0d>{J0d{1.0}});
+}
+
+TYPED_TEST(JetTest, Nested3XComparison) {
+  using Scalar = TypeParam;
+
+  EXPECT_EQ(J0<J0<J0d>>{J0<J0d>{J0d{0.0}}}, Scalar{0});
+  EXPECT_GE(J0<J0<J0d>>{J0<J0d>{J0d{3.0}}}, Scalar{3});
+  EXPECT_GT(J0<J0<J0d>>{J0<J0d>{J0d{3.0}}}, Scalar{2});
+  EXPECT_LE(J0<J0<J0d>>{J0<J0d>{J0d{1.0}}}, Scalar{1});
+  EXPECT_LT(J0<J0<J0d>>{J0<J0d>{J0d{1.0}}}, Scalar{2});
+  EXPECT_NE(J0<J0<J0d>>{J0<J0d>{J0d{1.0}}}, Scalar{2});
+
+  EXPECT_EQ(Scalar{0}, J0<J0<J0d>>{J0<J0d>{J0d{0.0}}});
+  EXPECT_GE(Scalar{1}, J0<J0<J0d>>{J0<J0d>{J0d{1.0}}});
+  EXPECT_GT(Scalar{2}, J0<J0<J0d>>{J0<J0d>{J0d{1.0}}});
+  EXPECT_LE(Scalar{3}, J0<J0<J0d>>{J0<J0d>{J0d{3.0}}});
+  EXPECT_LT(Scalar{2}, J0<J0<J0d>>{J0<J0d>{J0d{3.0}}});
+  EXPECT_NE(Scalar{2}, J0<J0<J0d>>{J0<J0d>{J0d{1.0}}});
+}
+
+#endif  // GTEST_HAS_TYPED_TEST
+
+}  // namespace ceres::internal
+
+#ifdef _MSC_VER
+#pragma float_control(pop)
+#endif
diff --git a/third_party/ceres/internal/ceres/jet_traits_test.cc b/third_party/ceres/internal/ceres/jet_traits_test.cc
new file mode 100644
index 0000000..0631784
--- /dev/null
+++ b/third_party/ceres/internal/ceres/jet_traits_test.cc
@@ -0,0 +1,106 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: sergiu.deitsch@gmail.com (Sergiu Deitsch)
+
+#include "ceres/internal/jet_traits.h"
+
+#include <Eigen/Core>
+#include <type_traits>
+#include <utility>
+
+namespace ceres::internal {
+
+using J = Jet<double, 2>;
+// Don't care about the dual part for scalar part categorization and comparison
+// tests
+template <typename T>
+using J0 = Jet<T, 0>;
+using J0d = J0<double>;
+
+// Extract the ranks of given types
+using Ranks001 = Ranks_t<Jet<double, 0>, double, Jet<double, 1>>;
+using Ranks1 = Ranks_t<Jet<double, 1>>;
+using Ranks110 = Ranks_t<Jet<double, 1>, Jet<double, 1>, double>;
+using Ranks023 = Ranks_t<double, Jet<double, 2>, Jet<double, 3>>;
+using EmptyRanks = Ranks_t<>;
+
+// Ensure extracted ranks match the expected integer sequence
+static_assert(
+    std::is_same<Ranks001, std::integer_sequence<int, 0, 0, 1>>::value,
+    "ranks do not match");
+static_assert(std::is_same<Ranks1, std::integer_sequence<int, 1>>::value,
+              "ranks do not match");
+static_assert(
+    std::is_same<Ranks110, std::integer_sequence<int, 1, 1, 0>>::value,
+    "ranks do not match");
+static_assert(
+    std::is_same<Ranks023, std::integer_sequence<int, 0, 2, 3>>::value,
+    "ranks do not match");
+static_assert(std::is_same<EmptyRanks, std::integer_sequence<int>>::value,
+              "ranks sequence is not empty");
+
+// Extract the underlying floating-point type
+static_assert(std::is_same<UnderlyingScalar_t<double>, double>::value,
+              "underlying type is not a double");
+static_assert(std::is_same<UnderlyingScalar_t<J0d>, double>::value,
+              "underlying type is not a double");
+static_assert(std::is_same<UnderlyingScalar_t<J0<J0d>>, double>::value,
+              "underlying type is not a double");
+static_assert(std::is_same<UnderlyingScalar_t<J0<J0<J0d>>>, double>::value,
+              "underlying type is not a double");
+
+static_assert(CompatibleJetOperands_v<Jet<double, 1>, Jet<double, 1>>,
+              "Jets must be compatible");
+static_assert(CompatibleJetOperands_v<Jet<double, 1>, double>,
+              "Jet and scalar must be compatible");
+static_assert(CompatibleJetOperands_v<Jet<double, 2>>,
+              "single Jet must be compatible");
+static_assert(!CompatibleJetOperands_v<Jet<double, 1>, double, Jet<double, 2>>,
+              "Jets and scalar must not be compatible");
+static_assert(!CompatibleJetOperands_v<double, double>,
+              "scalars must not be compatible");
+static_assert(!CompatibleJetOperands_v<double>,
+              "single scalar must not be compatible");
+static_assert(!CompatibleJetOperands_v<>,
+              "empty arguments must not be compatible");
+
+static_assert(!PromotableJetOperands_v<double>,
+              "single scalar must not be Jet promotable");
+static_assert(!PromotableJetOperands_v<double, float, int>,
+              "multiple scalars must not be Jet promotable");
+static_assert(PromotableJetOperands_v<J0d, float, int>,
+              "Jet and several scalars must be promotable");
+static_assert(PromotableJetOperands_v<J0<J0d>, float, int>,
+              "nested Jet and several scalars must be promotable");
+static_assert(!PromotableJetOperands_v<Eigen::Array<double, 2, 3>, float, int>,
+              "Eigen::Array must not be Jet promotable");
+static_assert(!PromotableJetOperands_v<Eigen::Matrix<double, 3, 2>, float, int>,
+              "Eigen::Matrix must not be Jet promotable");
+
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/lapack.cc b/third_party/ceres/internal/ceres/lapack.cc
deleted file mode 100644
index a159ec7..0000000
--- a/third_party/ceres/internal/ceres/lapack.cc
+++ /dev/null
@@ -1,190 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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 Google Inc. 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.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/lapack.h"
-
-#include "ceres/internal/port.h"
-#include "ceres/linear_solver.h"
-#include "glog/logging.h"
-
-#ifndef CERES_NO_LAPACK
-// C interface to the LAPACK Cholesky factorization and triangular solve.
-extern "C" void dpotrf_(char* uplo, int* n, double* a, int* lda, int* info);
-
-extern "C" void dpotrs_(char* uplo,
-                        int* n,
-                        int* nrhs,
-                        double* a,
-                        int* lda,
-                        double* b,
-                        int* ldb,
-                        int* info);
-
-extern "C" void dgels_(char* uplo,
-                       int* m,
-                       int* n,
-                       int* nrhs,
-                       double* a,
-                       int* lda,
-                       double* b,
-                       int* ldb,
-                       double* work,
-                       int* lwork,
-                       int* info);
-#endif
-
-namespace ceres {
-namespace internal {
-
-LinearSolverTerminationType LAPACK::SolveInPlaceUsingCholesky(
-    int num_rows,
-    const double* in_lhs,
-    double* rhs_and_solution,
-    std::string* message) {
-#ifdef CERES_NO_LAPACK
-  LOG(FATAL) << "Ceres was built without a BLAS library.";
-  return LINEAR_SOLVER_FATAL_ERROR;
-#else
-  char uplo = 'L';
-  int n = num_rows;
-  int info = 0;
-  int nrhs = 1;
-  double* lhs = const_cast<double*>(in_lhs);
-
-  dpotrf_(&uplo, &n, lhs, &n, &info);
-  if (info < 0) {
-    LOG(FATAL) << "Congratulations, you found a bug in Ceres."
-               << "Please report it."
-               << "LAPACK::dpotrf fatal error."
-               << "Argument: " << -info << " is invalid.";
-    return LINEAR_SOLVER_FATAL_ERROR;
-  }
-
-  if (info > 0) {
-    *message = StringPrintf(
-        "LAPACK::dpotrf numerical failure. "
-        "The leading minor of order %d is not positive definite.",
-        info);
-    return LINEAR_SOLVER_FAILURE;
-  }
-
-  dpotrs_(&uplo, &n, &nrhs, lhs, &n, rhs_and_solution, &n, &info);
-  if (info < 0) {
-    LOG(FATAL) << "Congratulations, you found a bug in Ceres."
-               << "Please report it."
-               << "LAPACK::dpotrs fatal error."
-               << "Argument: " << -info << " is invalid.";
-    return LINEAR_SOLVER_FATAL_ERROR;
-  }
-
-  *message = "Success";
-  return LINEAR_SOLVER_SUCCESS;
-#endif
-}
-
-int LAPACK::EstimateWorkSizeForQR(int num_rows, int num_cols) {
-#ifdef CERES_NO_LAPACK
-  LOG(FATAL) << "Ceres was built without a LAPACK library.";
-  return -1;
-#else
-  char trans = 'N';
-  int nrhs = 1;
-  int lwork = -1;
-  double work;
-  int info = 0;
-  dgels_(&trans,
-         &num_rows,
-         &num_cols,
-         &nrhs,
-         NULL,
-         &num_rows,
-         NULL,
-         &num_rows,
-         &work,
-         &lwork,
-         &info);
-
-  if (info < 0) {
-    LOG(FATAL) << "Congratulations, you found a bug in Ceres."
-               << "Please report it."
-               << "LAPACK::dgels fatal error."
-               << "Argument: " << -info << " is invalid.";
-  }
-  return static_cast<int>(work);
-#endif
-}
-
-LinearSolverTerminationType LAPACK::SolveInPlaceUsingQR(
-    int num_rows,
-    int num_cols,
-    const double* in_lhs,
-    int work_size,
-    double* work,
-    double* rhs_and_solution,
-    std::string* message) {
-#ifdef CERES_NO_LAPACK
-  LOG(FATAL) << "Ceres was built without a LAPACK library.";
-  return LINEAR_SOLVER_FATAL_ERROR;
-#else
-  char trans = 'N';
-  int m = num_rows;
-  int n = num_cols;
-  int nrhs = 1;
-  int lda = num_rows;
-  int ldb = num_rows;
-  int info = 0;
-  double* lhs = const_cast<double*>(in_lhs);
-
-  dgels_(&trans,
-         &m,
-         &n,
-         &nrhs,
-         lhs,
-         &lda,
-         rhs_and_solution,
-         &ldb,
-         work,
-         &work_size,
-         &info);
-
-  if (info < 0) {
-    LOG(FATAL) << "Congratulations, you found a bug in Ceres."
-               << "Please report it."
-               << "LAPACK::dgels fatal error."
-               << "Argument: " << -info << " is invalid.";
-  }
-
-  *message = "Success.";
-  return LINEAR_SOLVER_SUCCESS;
-#endif
-}
-
-}  // namespace internal
-}  // namespace ceres
diff --git a/third_party/ceres/internal/ceres/lapack.h b/third_party/ceres/internal/ceres/lapack.h
deleted file mode 100644
index 5c5bf8b..0000000
--- a/third_party/ceres/internal/ceres/lapack.h
+++ /dev/null
@@ -1,101 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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 Google Inc. 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.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_INTERNAL_LAPACK_H_
-#define CERES_INTERNAL_LAPACK_H_
-
-#include <string>
-
-#include "ceres/internal/port.h"
-#include "ceres/linear_solver.h"
-
-namespace ceres {
-namespace internal {
-
-class LAPACK {
- public:
-  // Solve
-  //
-  //  lhs * solution = rhs
-  //
-  // using a Cholesky factorization. Here
-  // lhs is a symmetric positive definite matrix. It is assumed to be
-  // column major and only the lower triangular part of the matrix is
-  // referenced.
-  //
-  // This function uses the LAPACK dpotrf and dpotrs routines.
-  //
-  // The return value and the message string together describe whether
-  // the solver terminated successfully or not and if so, what was the
-  // reason for failure.
-  static LinearSolverTerminationType SolveInPlaceUsingCholesky(
-      int num_rows,
-      const double* lhs,
-      double* rhs_and_solution,
-      std::string* message);
-
-  // The SolveUsingQR function requires a buffer for its temporary
-  // computation. This function given the size of the lhs matrix will
-  // return the size of the buffer needed.
-  static int EstimateWorkSizeForQR(int num_rows, int num_cols);
-
-  // Solve
-  //
-  //  lhs * solution = rhs
-  //
-  // using a dense QR factorization. lhs is an arbitrary (possibly
-  // rectangular) matrix with full column rank.
-  //
-  // work is an array of size work_size that this routine uses for its
-  // temporary storage. The optimal size of this array can be obtained
-  // by calling EstimateWorkSizeForQR.
-  //
-  // When calling, rhs_and_solution contains the rhs, and upon return
-  // the first num_col entries are the solution.
-  //
-  // This function uses the LAPACK dgels routine.
-  //
-  // The return value and the message string together describe whether
-  // the solver terminated successfully or not and if so, what was the
-  // reason for failure.
-  static LinearSolverTerminationType SolveInPlaceUsingQR(
-      int num_rows,
-      int num_cols,
-      const double* lhs,
-      int work_size,
-      double* work,
-      double* rhs_and_solution,
-      std::string* message);
-};
-
-}  // namespace internal
-}  // namespace ceres
-
-#endif  // CERES_INTERNAL_LAPACK_H_
diff --git a/third_party/ceres/internal/ceres/levenberg_marquardt_strategy.cc b/third_party/ceres/internal/ceres/levenberg_marquardt_strategy.cc
index cb0e937..37bc6f4 100644
--- a/third_party/ceres/internal/ceres/levenberg_marquardt_strategy.cc
+++ b/third_party/ceres/internal/ceres/levenberg_marquardt_strategy.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -38,13 +38,13 @@
 #include "ceres/internal/eigen.h"
 #include "ceres/linear_least_squares_problems.h"
 #include "ceres/linear_solver.h"
+#include "ceres/parallel_vector_ops.h"
 #include "ceres/sparse_matrix.h"
 #include "ceres/trust_region_strategy.h"
 #include "ceres/types.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 LevenbergMarquardtStrategy::LevenbergMarquardtStrategy(
     const TrustRegionStrategy::Options& options)
@@ -54,14 +54,16 @@
       min_diagonal_(options.min_lm_diagonal),
       max_diagonal_(options.max_lm_diagonal),
       decrease_factor_(2.0),
-      reuse_diagonal_(false) {
+      reuse_diagonal_(false),
+      context_(options.context),
+      num_threads_(options.num_threads) {
   CHECK(linear_solver_ != nullptr);
   CHECK_GT(min_diagonal_, 0.0);
   CHECK_LE(min_diagonal_, max_diagonal_);
   CHECK_GT(max_radius_, 0.0);
 }
 
-LevenbergMarquardtStrategy::~LevenbergMarquardtStrategy() {}
+LevenbergMarquardtStrategy::~LevenbergMarquardtStrategy() = default;
 
 TrustRegionStrategy::Summary LevenbergMarquardtStrategy::ComputeStep(
     const TrustRegionStrategy::PerSolveOptions& per_solve_options,
@@ -78,14 +80,18 @@
       diagonal_.resize(num_parameters, 1);
     }
 
-    jacobian->SquaredColumnNorm(diagonal_.data());
-    for (int i = 0; i < num_parameters; ++i) {
-      diagonal_[i] =
-          std::min(std::max(diagonal_[i], min_diagonal_), max_diagonal_);
-    }
+    jacobian->SquaredColumnNorm(diagonal_.data(), context_, num_threads_);
+    ParallelAssign(context_,
+                   num_threads_,
+                   diagonal_,
+                   diagonal_.array().max(min_diagonal_).min(max_diagonal_));
   }
 
-  lm_diagonal_ = (diagonal_ / radius_).array().sqrt();
+  if (lm_diagonal_.size() == 0) {
+    lm_diagonal_.resize(num_parameters);
+  }
+  ParallelAssign(
+      context_, num_threads_, lm_diagonal_, (diagonal_ / radius_).cwiseSqrt());
 
   LinearSolver::PerSolveOptions solve_options;
   solve_options.D = lm_diagonal_.data();
@@ -99,7 +105,7 @@
   // Invalidate the output array lm_step, so that we can detect if
   // the linear solver generated numerical garbage.  This is known
   // to happen for the DENSE_QR and then DENSE_SCHUR solver when
-  // the Jacobin is severely rank deficient and mu is too small.
+  // the Jacobian is severely rank deficient and mu is too small.
   InvalidateArray(num_parameters, step);
 
   // Instead of solving Jx = -r, solve Jy = r.
@@ -108,17 +114,21 @@
   LinearSolver::Summary linear_solver_summary =
       linear_solver_->Solve(jacobian, residuals, solve_options, step);
 
-  if (linear_solver_summary.termination_type == LINEAR_SOLVER_FATAL_ERROR) {
+  if (linear_solver_summary.termination_type ==
+      LinearSolverTerminationType::FATAL_ERROR) {
     LOG(WARNING) << "Linear solver fatal error: "
                  << linear_solver_summary.message;
-  } else if (linear_solver_summary.termination_type == LINEAR_SOLVER_FAILURE) {
+  } else if (linear_solver_summary.termination_type ==
+             LinearSolverTerminationType::FAILURE) {
     LOG(WARNING) << "Linear solver failure. Failed to compute a step: "
                  << linear_solver_summary.message;
   } else if (!IsArrayValid(num_parameters, step)) {
     LOG(WARNING) << "Linear solver failure. Failed to compute a finite step.";
-    linear_solver_summary.termination_type = LINEAR_SOLVER_FAILURE;
+    linear_solver_summary.termination_type =
+        LinearSolverTerminationType::FAILURE;
   } else {
-    VectorRef(step, num_parameters) *= -1.0;
+    VectorRef step_vec(step, num_parameters);
+    ParallelAssign(context_, num_threads_, step_vec, -step_vec);
   }
   reuse_diagonal_ = true;
 
@@ -153,7 +163,7 @@
   reuse_diagonal_ = false;
 }
 
-void LevenbergMarquardtStrategy::StepRejected(double step_quality) {
+void LevenbergMarquardtStrategy::StepRejected(double /*step_quality*/) {
   radius_ = radius_ / decrease_factor_;
   decrease_factor_ *= 2.0;
   reuse_diagonal_ = true;
@@ -161,5 +171,4 @@
 
 double LevenbergMarquardtStrategy::Radius() const { return radius_; }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/levenberg_marquardt_strategy.h b/third_party/ceres/internal/ceres/levenberg_marquardt_strategy.h
index 12cd463..1b341c1 100644
--- a/third_party/ceres/internal/ceres/levenberg_marquardt_strategy.h
+++ b/third_party/ceres/internal/ceres/levenberg_marquardt_strategy.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -31,24 +31,26 @@
 #ifndef CERES_INTERNAL_LEVENBERG_MARQUARDT_STRATEGY_H_
 #define CERES_INTERNAL_LEVENBERG_MARQUARDT_STRATEGY_H_
 
+#include "ceres/internal/disable_warnings.h"
 #include "ceres/internal/eigen.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 #include "ceres/trust_region_strategy.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
+
+class ContextImpl;
 
 // Levenberg-Marquardt step computation and trust region sizing
 // strategy based on on "Methods for Nonlinear Least Squares" by
 // K. Madsen, H.B. Nielsen and O. Tingleff. Available to download from
 //
 // http://www2.imm.dtu.dk/pubdb/views/edoc_download.php/3215/pdf/imm3215.pdf
-class CERES_EXPORT_INTERNAL LevenbergMarquardtStrategy
+class CERES_NO_EXPORT LevenbergMarquardtStrategy final
     : public TrustRegionStrategy {
  public:
   explicit LevenbergMarquardtStrategy(
       const TrustRegionStrategy::Options& options);
-  virtual ~LevenbergMarquardtStrategy();
+  ~LevenbergMarquardtStrategy() override;
 
   // TrustRegionStrategy interface
   TrustRegionStrategy::Summary ComputeStep(
@@ -81,9 +83,12 @@
   // allocations in every iteration and reuse when a step fails and
   // ComputeStep is called again.
   Vector lm_diagonal_;  // lm_diagonal_ = sqrt(diagonal_ / radius_);
+  ContextImpl* context_;
+  int num_threads_;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_LEVENBERG_MARQUARDT_STRATEGY_H_
diff --git a/third_party/ceres/internal/ceres/levenberg_marquardt_strategy_test.cc b/third_party/ceres/internal/ceres/levenberg_marquardt_strategy_test.cc
index 500f269..ca69f28 100644
--- a/third_party/ceres/internal/ceres/levenberg_marquardt_strategy_test.cc
+++ b/third_party/ceres/internal/ceres/levenberg_marquardt_strategy_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -58,8 +58,6 @@
   RegularizationCheckingLinearSolver(const int num_cols, const double* diagonal)
       : num_cols_(num_cols), diagonal_(diagonal) {}
 
-  virtual ~RegularizationCheckingLinearSolver() {}
-
  private:
   LinearSolver::Summary SolveImpl(
       DenseSparseMatrix* A,
@@ -71,7 +69,7 @@
       EXPECT_NEAR(per_solve_options.D[i], diagonal_[i], kTolerance)
           << i << " " << per_solve_options.D[i] << " " << diagonal_[i];
     }
-    return LinearSolver::Summary();
+    return {};
   }
 
   const int num_cols_;
@@ -87,7 +85,7 @@
 
   // We need a non-null pointer here, so anything should do.
   std::unique_ptr<LinearSolver> linear_solver(
-      new RegularizationCheckingLinearSolver(0, NULL));
+      new RegularizationCheckingLinearSolver(0, nullptr));
   options.linear_solver = linear_solver.get();
 
   LevenbergMarquardtStrategy lms(options);
@@ -132,8 +130,8 @@
   diagonal[0] = options.min_lm_diagonal;
   diagonal[1] = 2.0;
   diagonal[2] = options.max_lm_diagonal;
-  for (int i = 0; i < 3; ++i) {
-    diagonal[i] = sqrt(diagonal[i] / options.initial_radius);
+  for (double& diagonal_entry : diagonal) {
+    diagonal_entry = sqrt(diagonal_entry / options.initial_radius);
   }
 
   RegularizationCheckingLinearSolver linear_solver(3, diagonal);
@@ -149,7 +147,7 @@
     // are versions of glog which are not in the google namespace.
     using namespace google;
 
-#if defined(_MSC_VER)
+#if defined(GLOG_NO_ABBREVIATED_SEVERITIES)
     // Use GLOG_WARNING to support MSVC if GLOG_NO_ABBREVIATED_SEVERITIES
     // is defined.
     EXPECT_CALL(log,
@@ -161,7 +159,7 @@
 
     TrustRegionStrategy::Summary summary =
         lms.ComputeStep(pso, &dsm, &residual, x);
-    EXPECT_EQ(summary.termination_type, LINEAR_SOLVER_FAILURE);
+    EXPECT_EQ(summary.termination_type, LinearSolverTerminationType::FAILURE);
   }
 }
 
diff --git a/third_party/ceres/internal/ceres/line_search.cc b/third_party/ceres/internal/ceres/line_search.cc
index 7e871a2..eb2c7c9 100644
--- a/third_party/ceres/internal/ceres/line_search.cc
+++ b/third_party/ceres/internal/ceres/line_search.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -33,7 +33,11 @@
 #include <algorithm>
 #include <cmath>
 #include <iomanip>
-#include <iostream>  // NOLINT
+#include <map>
+#include <memory>
+#include <ostream>  // NOLINT
+#include <string>
+#include <vector>
 
 #include "ceres/evaluator.h"
 #include "ceres/function_sample.h"
@@ -44,48 +48,41 @@
 #include "ceres/wall_time.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
-
-using std::map;
-using std::ostream;
-using std::string;
-using std::vector;
+namespace ceres::internal {
 
 namespace {
 // Precision used for floating point values in error message output.
 const int kErrorMessageNumericPrecision = 8;
 }  // namespace
 
-ostream& operator<<(ostream& os, const FunctionSample& sample);
+std::ostream& operator<<(std::ostream& os, const FunctionSample& sample);
 
 // Convenience stream operator for pushing FunctionSamples into log messages.
-ostream& operator<<(ostream& os, const FunctionSample& sample) {
+std::ostream& operator<<(std::ostream& os, const FunctionSample& sample) {
   os << sample.ToDebugString();
   return os;
 }
 
+LineSearch::~LineSearch() = default;
+
 LineSearch::LineSearch(const LineSearch::Options& options)
     : options_(options) {}
 
-LineSearch* LineSearch::Create(const LineSearchType line_search_type,
-                               const LineSearch::Options& options,
-                               string* error) {
-  LineSearch* line_search = NULL;
+std::unique_ptr<LineSearch> LineSearch::Create(
+    const LineSearchType line_search_type,
+    const LineSearch::Options& options,
+    std::string* error) {
   switch (line_search_type) {
     case ceres::ARMIJO:
-      line_search = new ArmijoLineSearch(options);
-      break;
+      return std::make_unique<ArmijoLineSearch>(options);
     case ceres::WOLFE:
-      line_search = new WolfeLineSearch(options);
-      break;
+      return std::make_unique<WolfeLineSearch>(options);
     default:
-      *error = string("Invalid line search algorithm type: ") +
+      *error = std::string("Invalid line search algorithm type: ") +
                LineSearchTypeToString(line_search_type) +
-               string(", unable to create line search.");
-      return NULL;
+               std::string(", unable to create line search.");
   }
-  return line_search;
+  return nullptr;
 }
 
 LineSearchFunction::LineSearchFunction(Evaluator* evaluator)
@@ -119,13 +116,13 @@
   }
   output->vector_x_is_valid = true;
 
-  double* gradient = NULL;
+  double* gradient = nullptr;
   if (evaluate_gradient) {
     output->vector_gradient.resize(direction_.rows(), 1);
     gradient = output->vector_gradient.data();
   }
   const bool eval_status = evaluator_->Evaluate(
-      output->vector_x.data(), &(output->value), NULL, gradient, NULL);
+      output->vector_x.data(), &(output->value), nullptr, gradient, nullptr);
 
   if (!eval_status || !std::isfinite(output->value)) {
     return;
@@ -150,7 +147,7 @@
 }
 
 void LineSearchFunction::ResetTimeStatistics() {
-  const map<string, CallStatistics> evaluator_statistics =
+  const std::map<std::string, CallStatistics> evaluator_statistics =
       evaluator_->Statistics();
 
   initial_evaluator_residual_time_in_seconds =
@@ -166,7 +163,7 @@
 void LineSearchFunction::TimeStatistics(
     double* cost_evaluation_time_in_seconds,
     double* gradient_evaluation_time_in_seconds) const {
-  const map<string, CallStatistics> evaluator_time_statistics =
+  const std::map<std::string, CallStatistics> evaluator_time_statistics =
       evaluator_->Statistics();
   *cost_evaluation_time_in_seconds =
       FindWithDefault(
@@ -243,18 +240,18 @@
 
   // Select step size by interpolating the function and gradient values
   // and minimizing the corresponding polynomial.
-  vector<FunctionSample> samples;
+  std::vector<FunctionSample> samples;
   samples.push_back(lowerbound);
 
   if (interpolation_type == QUADRATIC) {
     // Two point interpolation using function values and the
     // gradient at the lower bound.
-    samples.push_back(FunctionSample(current.x, current.value));
+    samples.emplace_back(current.x, current.value);
 
     if (previous.value_is_valid) {
       // Three point interpolation, using function values and the
       // gradient at the lower bound.
-      samples.push_back(FunctionSample(previous.x, previous.value));
+      samples.emplace_back(previous.x, previous.value);
     }
   } else if (interpolation_type == CUBIC) {
     // Two point interpolation using the function values and the gradients.
@@ -427,7 +424,7 @@
     // shrank the bracket width until it was below our minimum tolerance.
     // As these are 'artificial' constraints, and we would otherwise fail to
     // produce a valid point when ArmijoLineSearch would succeed, we return the
-    // point with the lowest cost found thus far which satsifies the Armijo
+    // point with the lowest cost found thus far which satisfies the Armijo
     // condition (but not the Wolfe conditions).
     summary->optimal_point = bracket_low;
     summary->success = true;
@@ -449,8 +446,8 @@
   // defined by bracket_low & bracket_high, which satisfy:
   //
   //   1. The interval bounded by step sizes: bracket_low.x & bracket_high.x
-  //      contains step sizes that satsify the strong Wolfe conditions.
-  //   2. bracket_low.x is of all the step sizes evaluated *which satisifed the
+  //      contains step sizes that satisfy the strong Wolfe conditions.
+  //   2. bracket_low.x is of all the step sizes evaluated *which satisfied the
   //      Armijo sufficient decrease condition*, the one which generated the
   //      smallest function value, i.e. bracket_low.value <
   //      f(all other steps satisfying Armijo).
@@ -494,7 +491,7 @@
 // Or, searching was stopped due to an 'artificial' constraint, i.e. not
 // a condition imposed / required by the underlying algorithm, but instead an
 // engineering / implementation consideration. But a step which exceeds the
-// minimum step size, and satsifies the Armijo condition was still found,
+// minimum step size, and satisfies the Armijo condition was still found,
 // and should thus be used [zoom not required].
 //
 // Returns false if no step size > minimum step size was found which
@@ -518,7 +515,7 @@
   // As we require the gradient to evaluate the Wolfe condition, we always
   // calculate it together with the value, irrespective of the interpolation
   // type.  As opposed to only calculating the gradient after the Armijo
-  // condition is satisifed, as the computational saving from this approach
+  // condition is satisfied, as the computational saving from this approach
   // would be slight (perhaps even negative due to the extra call).  Also,
   // always calculating the value & gradient together protects against us
   // reporting invalid solutions if the cost function returns slightly different
@@ -821,7 +818,7 @@
     // As we require the gradient to evaluate the Wolfe condition, we always
     // calculate it together with the value, irrespective of the interpolation
     // type.  As opposed to only calculating the gradient after the Armijo
-    // condition is satisifed, as the computational saving from this approach
+    // condition is satisfied, as the computational saving from this approach
     // would be slight (perhaps even negative due to the extra call).  Also,
     // always calculating the value & gradient together protects against us
     // reporting invalid solutions if the cost function returns slightly
@@ -883,5 +880,4 @@
   return true;
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/line_search.h b/third_party/ceres/internal/ceres/line_search.h
index 634c971..acf85c0 100644
--- a/third_party/ceres/internal/ceres/line_search.h
+++ b/third_party/ceres/internal/ceres/line_search.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -33,16 +33,16 @@
 #ifndef CERES_INTERNAL_LINE_SEARCH_H_
 #define CERES_INTERNAL_LINE_SEARCH_H_
 
+#include <memory>
 #include <string>
 #include <vector>
 
 #include "ceres/function_sample.h"
 #include "ceres/internal/eigen.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 #include "ceres/types.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 class Evaluator;
 class LineSearchFunction;
@@ -57,11 +57,11 @@
 // sufficient decrease condition. Depending on the particular
 // condition used, we get a variety of different line search
 // algorithms, e.g., Armijo, Wolfe etc.
-class LineSearch {
+class CERES_NO_EXPORT LineSearch {
  public:
   struct Summary;
 
-  struct Options {
+  struct CERES_NO_EXPORT Options {
     // Degree of the polynomial used to approximate the objective
     // function.
     LineSearchInterpolationType interpolation_type = CUBIC;
@@ -161,11 +161,12 @@
   };
 
   explicit LineSearch(const LineSearch::Options& options);
-  virtual ~LineSearch() {}
+  virtual ~LineSearch();
 
-  static LineSearch* Create(const LineSearchType line_search_type,
-                            const LineSearch::Options& options,
-                            std::string* error);
+  static std::unique_ptr<LineSearch> Create(
+      const LineSearchType line_search_type,
+      const LineSearch::Options& options,
+      std::string* error);
 
   // Perform the line search.
   //
@@ -208,7 +209,7 @@
 // In practice, this object provides access to the objective
 // function value and the directional derivative of the underlying
 // optimization problem along a specific search direction.
-class LineSearchFunction {
+class CERES_NO_EXPORT LineSearchFunction {
  public:
   explicit LineSearchFunction(Evaluator* evaluator);
   void Init(const Vector& position, const Vector& direction);
@@ -257,10 +258,9 @@
 // minFunc package by Mark Schmidt.
 //
 // For more details: http://www.di.ens.fr/~mschmidt/Software/minFunc.html
-class ArmijoLineSearch : public LineSearch {
+class CERES_NO_EXPORT ArmijoLineSearch final : public LineSearch {
  public:
   explicit ArmijoLineSearch(const LineSearch::Options& options);
-  virtual ~ArmijoLineSearch() {}
 
  private:
   void DoSearch(double step_size_estimate,
@@ -276,10 +276,9 @@
 //
 // [1] Nocedal J., Wright S., Numerical Optimization, 2nd Ed., Springer, 1999.
 // [2] http://www.di.ens.fr/~mschmidt/Software/minFunc.html.
-class WolfeLineSearch : public LineSearch {
+class CERES_NO_EXPORT WolfeLineSearch final : public LineSearch {
  public:
   explicit WolfeLineSearch(const LineSearch::Options& options);
-  virtual ~WolfeLineSearch() {}
 
   // Returns true iff either a valid point, or valid bracket are found.
   bool BracketingPhase(const FunctionSample& initial_position,
@@ -302,7 +301,6 @@
                 Summary* summary) const final;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_INTERNAL_LINE_SEARCH_H_
diff --git a/third_party/ceres/internal/ceres/line_search_direction.cc b/third_party/ceres/internal/ceres/line_search_direction.cc
index 48e6c98..62fcc81 100644
--- a/third_party/ceres/internal/ceres/line_search_direction.cc
+++ b/third_party/ceres/internal/ceres/line_search_direction.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -30,26 +30,28 @@
 
 #include "ceres/line_search_direction.h"
 
+#include <memory>
+
 #include "ceres/internal/eigen.h"
+#include "ceres/internal/export.h"
 #include "ceres/line_search_minimizer.h"
 #include "ceres/low_rank_inverse_hessian.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
-class SteepestDescent : public LineSearchDirection {
+class CERES_NO_EXPORT SteepestDescent final : public LineSearchDirection {
  public:
-  virtual ~SteepestDescent() {}
-  bool NextDirection(const LineSearchMinimizer::State& previous,
+  bool NextDirection(const LineSearchMinimizer::State& /*previous*/,
                      const LineSearchMinimizer::State& current,
-                     Vector* search_direction) {
+                     Vector* search_direction) override {
     *search_direction = -current.gradient;
     return true;
   }
 };
 
-class NonlinearConjugateGradient : public LineSearchDirection {
+class CERES_NO_EXPORT NonlinearConjugateGradient final
+    : public LineSearchDirection {
  public:
   NonlinearConjugateGradient(const NonlinearConjugateGradientType type,
                              const double function_tolerance)
@@ -57,7 +59,7 @@
 
   bool NextDirection(const LineSearchMinimizer::State& previous,
                      const LineSearchMinimizer::State& current,
-                     Vector* search_direction) {
+                     Vector* search_direction) override {
     double beta = 0.0;
     Vector gradient_change;
     switch (type_) {
@@ -95,7 +97,7 @@
   const double function_tolerance_;
 };
 
-class LBFGS : public LineSearchDirection {
+class CERES_NO_EXPORT LBFGS final : public LineSearchDirection {
  public:
   LBFGS(const int num_parameters,
         const int max_lbfgs_rank,
@@ -105,11 +107,9 @@
                                   use_approximate_eigenvalue_bfgs_scaling),
         is_positive_definite_(true) {}
 
-  virtual ~LBFGS() {}
-
   bool NextDirection(const LineSearchMinimizer::State& previous,
                      const LineSearchMinimizer::State& current,
-                     Vector* search_direction) {
+                     Vector* search_direction) override {
     CHECK(is_positive_definite_)
         << "Ceres bug: NextDirection() called on L-BFGS after inverse Hessian "
         << "approximation has become indefinite, please contact the "
@@ -120,8 +120,8 @@
         current.gradient - previous.gradient);
 
     search_direction->setZero();
-    low_rank_inverse_hessian_.RightMultiply(current.gradient.data(),
-                                            search_direction->data());
+    low_rank_inverse_hessian_.RightMultiplyAndAccumulate(
+        current.gradient.data(), search_direction->data());
     *search_direction *= -1.0;
 
     if (search_direction->dot(current.gradient) >= 0.0) {
@@ -141,7 +141,7 @@
   bool is_positive_definite_;
 };
 
-class BFGS : public LineSearchDirection {
+class CERES_NO_EXPORT BFGS final : public LineSearchDirection {
  public:
   BFGS(const int num_parameters, const bool use_approximate_eigenvalue_scaling)
       : num_parameters_(num_parameters),
@@ -161,11 +161,9 @@
     inverse_hessian_ = Matrix::Identity(num_parameters, num_parameters);
   }
 
-  virtual ~BFGS() {}
-
   bool NextDirection(const LineSearchMinimizer::State& previous,
                      const LineSearchMinimizer::State& current,
-                     Vector* search_direction) {
+                     Vector* search_direction) override {
     CHECK(is_positive_definite_)
         << "Ceres bug: NextDirection() called on BFGS after inverse Hessian "
         << "approximation has become indefinite, please contact the "
@@ -243,7 +241,7 @@
         //
         // The original origin of this rescaling trick is somewhat unclear, the
         // earliest reference appears to be Oren [1], however it is widely
-        // discussed without specific attributation in various texts including
+        // discussed without specific attribution in various texts including
         // [2] (p143).
         //
         // [1] Oren S.S., Self-scaling variable metric (SSVM) algorithms
@@ -338,33 +336,34 @@
   bool is_positive_definite_;
 };
 
-LineSearchDirection* LineSearchDirection::Create(
+LineSearchDirection::~LineSearchDirection() = default;
+
+std::unique_ptr<LineSearchDirection> LineSearchDirection::Create(
     const LineSearchDirection::Options& options) {
   if (options.type == STEEPEST_DESCENT) {
-    return new SteepestDescent;
+    return std::make_unique<SteepestDescent>();
   }
 
   if (options.type == NONLINEAR_CONJUGATE_GRADIENT) {
-    return new NonlinearConjugateGradient(
+    return std::make_unique<NonlinearConjugateGradient>(
         options.nonlinear_conjugate_gradient_type, options.function_tolerance);
   }
 
   if (options.type == ceres::LBFGS) {
-    return new ceres::internal::LBFGS(
+    return std::make_unique<ceres::internal::LBFGS>(
         options.num_parameters,
         options.max_lbfgs_rank,
         options.use_approximate_eigenvalue_bfgs_scaling);
   }
 
   if (options.type == ceres::BFGS) {
-    return new ceres::internal::BFGS(
+    return std::make_unique<ceres::internal::BFGS>(
         options.num_parameters,
         options.use_approximate_eigenvalue_bfgs_scaling);
   }
 
   LOG(ERROR) << "Unknown line search direction type: " << options.type;
-  return NULL;
+  return nullptr;
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/line_search_direction.h b/third_party/ceres/internal/ceres/line_search_direction.h
index 2fcf472..6716840 100644
--- a/third_party/ceres/internal/ceres/line_search_direction.h
+++ b/third_party/ceres/internal/ceres/line_search_direction.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -31,41 +31,35 @@
 #ifndef CERES_INTERNAL_LINE_SEARCH_DIRECTION_H_
 #define CERES_INTERNAL_LINE_SEARCH_DIRECTION_H_
 
+#include <memory>
+
 #include "ceres/internal/eigen.h"
+#include "ceres/internal/export.h"
 #include "ceres/line_search_minimizer.h"
 #include "ceres/types.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
-class LineSearchDirection {
+class CERES_NO_EXPORT LineSearchDirection {
  public:
   struct Options {
-    Options()
-        : num_parameters(0),
-          type(LBFGS),
-          nonlinear_conjugate_gradient_type(FLETCHER_REEVES),
-          function_tolerance(1e-12),
-          max_lbfgs_rank(20),
-          use_approximate_eigenvalue_bfgs_scaling(true) {}
-
-    int num_parameters;
-    LineSearchDirectionType type;
-    NonlinearConjugateGradientType nonlinear_conjugate_gradient_type;
-    double function_tolerance;
-    int max_lbfgs_rank;
-    bool use_approximate_eigenvalue_bfgs_scaling;
+    int num_parameters{0};
+    LineSearchDirectionType type{LBFGS};
+    NonlinearConjugateGradientType nonlinear_conjugate_gradient_type{
+        FLETCHER_REEVES};
+    double function_tolerance{1e-12};
+    int max_lbfgs_rank{20};
+    bool use_approximate_eigenvalue_bfgs_scaling{true};
   };
 
-  static LineSearchDirection* Create(const Options& options);
+  static std::unique_ptr<LineSearchDirection> Create(const Options& options);
 
-  virtual ~LineSearchDirection() {}
+  virtual ~LineSearchDirection();
   virtual bool NextDirection(const LineSearchMinimizer::State& previous,
                              const LineSearchMinimizer::State& current,
                              Vector* search_direction) = 0;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_INTERNAL_LINE_SEARCH_DIRECTION_H_
diff --git a/third_party/ceres/internal/ceres/line_search_minimizer.cc b/third_party/ceres/internal/ceres/line_search_minimizer.cc
index ea1c507..58a4bf9 100644
--- a/third_party/ceres/internal/ceres/line_search_minimizer.cc
+++ b/third_party/ceres/internal/ceres/line_search_minimizer.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -30,7 +30,7 @@
 //
 // Generic loop for line search based optimization algorithms.
 //
-// This is primarily inpsired by the minFunc packaged written by Mark
+// This is primarily inspired by the minFunc packaged written by Mark
 // Schmidt.
 //
 // http://www.di.ens.fr/~mschmidt/Software/minFunc.html
@@ -51,7 +51,7 @@
 #include "ceres/array_utils.h"
 #include "ceres/evaluator.h"
 #include "ceres/internal/eigen.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 #include "ceres/line_search.h"
 #include "ceres/line_search_direction.h"
 #include "ceres/stringprintf.h"
@@ -59,8 +59,7 @@
 #include "ceres/wall_time.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 namespace {
 
 bool EvaluateGradientNorms(Evaluator* evaluator,
@@ -171,8 +170,8 @@
   line_search_direction_options.max_lbfgs_rank = options.max_lbfgs_rank;
   line_search_direction_options.use_approximate_eigenvalue_bfgs_scaling =
       options.use_approximate_eigenvalue_bfgs_scaling;
-  std::unique_ptr<LineSearchDirection> line_search_direction(
-      LineSearchDirection::Create(line_search_direction_options));
+  std::unique_ptr<LineSearchDirection> line_search_direction =
+      LineSearchDirection::Create(line_search_direction_options);
 
   LineSearchFunction line_search_function(evaluator);
 
@@ -280,8 +279,8 @@
                      << options.max_num_line_search_direction_restarts
                      << " [max].";
       }
-      line_search_direction.reset(
-          LineSearchDirection::Create(line_search_direction_options));
+      line_search_direction =
+          LineSearchDirection::Create(line_search_direction_options);
       current_state.search_direction = -current_state.gradient;
     }
 
@@ -473,5 +472,4 @@
   }
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/line_search_minimizer.h b/third_party/ceres/internal/ceres/line_search_minimizer.h
index 79e8dc9..f3621d9 100644
--- a/third_party/ceres/internal/ceres/line_search_minimizer.h
+++ b/third_party/ceres/internal/ceres/line_search_minimizer.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -32,21 +32,21 @@
 #define CERES_INTERNAL_LINE_SEARCH_MINIMIZER_H_
 
 #include "ceres/internal/eigen.h"
+#include "ceres/internal/export.h"
 #include "ceres/minimizer.h"
 #include "ceres/solver.h"
 #include "ceres/types.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // Generic line search minimization algorithm.
 //
 // For example usage, see SolverImpl::Minimize.
-class LineSearchMinimizer : public Minimizer {
+class CERES_NO_EXPORT LineSearchMinimizer final : public Minimizer {
  public:
   struct State {
-    State(int num_parameters, int num_effective_parameters)
+    State(int /*num_parameters*/, int num_effective_parameters)
         : cost(0.0),
           gradient(num_effective_parameters),
           gradient_squared_norm(0.0),
@@ -63,13 +63,11 @@
     double step_size;
   };
 
-  ~LineSearchMinimizer() {}
   void Minimize(const Minimizer::Options& options,
                 double* parameters,
                 Solver::Summary* summary) final;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_INTERNAL_LINE_SEARCH_MINIMIZER_H_
diff --git a/third_party/ceres/internal/ceres/line_search_minimizer_test.cc b/third_party/ceres/internal/ceres/line_search_minimizer_test.cc
index 2ef27b9..3b15ae8 100644
--- a/third_party/ceres/internal/ceres/line_search_minimizer_test.cc
+++ b/third_party/ceres/internal/ceres/line_search_minimizer_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,8 +35,7 @@
 #include "glog/logging.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 class QuadraticFirstOrderFunction : public ceres::FirstOrderFunction {
  public:
@@ -44,7 +43,7 @@
                 double* cost,
                 double* gradient) const final {
     cost[0] = parameters[0] * parameters[0];
-    if (gradient != NULL) {
+    if (gradient != nullptr) {
       gradient[0] = 2.0 * parameters[0];
     }
     return true;
@@ -62,5 +61,4 @@
   EXPECT_NEAR(summary.final_cost, 0.0, std::numeric_limits<double>::epsilon());
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/line_search_preprocessor.cc b/third_party/ceres/internal/ceres/line_search_preprocessor.cc
index 6a69425..3109c48 100644
--- a/third_party/ceres/internal/ceres/line_search_preprocessor.cc
+++ b/third_party/ceres/internal/ceres/line_search_preprocessor.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -41,8 +41,7 @@
 #include "ceres/program.h"
 #include "ceres/wall_time.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 namespace {
 
 bool IsProgramValid(const Program& program, std::string* error) {
@@ -63,15 +62,13 @@
   pp->evaluator_options.context = pp->problem->context();
   pp->evaluator_options.evaluation_callback =
       pp->reduced_program->mutable_evaluation_callback();
-  pp->evaluator.reset(Evaluator::Create(
-      pp->evaluator_options, pp->reduced_program.get(), &pp->error));
-  return (pp->evaluator.get() != NULL);
+  pp->evaluator = Evaluator::Create(
+      pp->evaluator_options, pp->reduced_program.get(), &pp->error);
+  return (pp->evaluator.get() != nullptr);
 }
 
 }  // namespace
 
-LineSearchPreprocessor::~LineSearchPreprocessor() {}
-
 bool LineSearchPreprocessor::Preprocess(const Solver::Options& options,
                                         ProblemImpl* problem,
                                         PreprocessedProblem* pp) {
@@ -85,10 +82,10 @@
     return false;
   }
 
-  pp->reduced_program.reset(program->CreateReducedProgram(
-      &pp->removed_parameter_blocks, &pp->fixed_cost, &pp->error));
+  pp->reduced_program = program->CreateReducedProgram(
+      &pp->removed_parameter_blocks, &pp->fixed_cost, &pp->error);
 
-  if (pp->reduced_program.get() == NULL) {
+  if (pp->reduced_program.get() == nullptr) {
     return false;
   }
 
@@ -104,5 +101,4 @@
   return true;
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/line_search_preprocessor.h b/third_party/ceres/internal/ceres/line_search_preprocessor.h
index bd426c7..0ffdba1 100644
--- a/third_party/ceres/internal/ceres/line_search_preprocessor.h
+++ b/third_party/ceres/internal/ceres/line_search_preprocessor.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -31,21 +31,21 @@
 #ifndef CERES_INTERNAL_LINE_SEARCH_PREPROCESSOR_H_
 #define CERES_INTERNAL_LINE_SEARCH_PREPROCESSOR_H_
 
-#include "ceres/internal/port.h"
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 #include "ceres/preprocessor.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
-class CERES_EXPORT_INTERNAL LineSearchPreprocessor : public Preprocessor {
+class CERES_NO_EXPORT LineSearchPreprocessor final : public Preprocessor {
  public:
-  virtual ~LineSearchPreprocessor();
   bool Preprocess(const Solver::Options& options,
                   ProblemImpl* problem,
                   PreprocessedProblem* preprocessed_problem) final;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_LINE_SEARCH_PREPROCESSOR_H_
diff --git a/third_party/ceres/internal/ceres/line_search_preprocessor_test.cc b/third_party/ceres/internal/ceres/line_search_preprocessor_test.cc
index 68860c5..e002a4b 100644
--- a/third_party/ceres/internal/ceres/line_search_preprocessor_test.cc
+++ b/third_party/ceres/internal/ceres/line_search_preprocessor_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,7 @@
 #include "ceres/solver.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST(LineSearchPreprocessor, ZeroProblem) {
   ProblemImpl problem;
@@ -77,7 +76,7 @@
  public:
   bool Evaluate(double const* const* parameters,
                 double* residuals,
-                double** jacobians) const {
+                double** jacobians) const override {
     return false;
   }
 };
@@ -85,7 +84,7 @@
 TEST(LineSearchPreprocessor, RemoveParameterBlocksFailed) {
   ProblemImpl problem;
   double x = 3.0;
-  problem.AddResidualBlock(new FailingCostFunction, NULL, &x);
+  problem.AddResidualBlock(new FailingCostFunction, nullptr, &x);
   problem.SetParameterBlockConstant(&x);
   Solver::Options options;
   options.minimizer_type = LINE_SEARCH;
@@ -111,7 +110,7 @@
  public:
   bool Evaluate(double const* const* parameters,
                 double* residuals,
-                double** jacobians) const {
+                double** jacobians) const override {
     return true;
   }
 };
@@ -121,8 +120,8 @@
   double x = 1.0;
   double y = 1.0;
   double z = 1.0;
-  problem.AddResidualBlock(new DummyCostFunction<1, 1, 1>, NULL, &x, &y);
-  problem.AddResidualBlock(new DummyCostFunction<1, 1, 1>, NULL, &y, &z);
+  problem.AddResidualBlock(new DummyCostFunction<1, 1, 1>, nullptr, &x, &y);
+  problem.AddResidualBlock(new DummyCostFunction<1, 1, 1>, nullptr, &y, &z);
 
   Solver::Options options;
   options.minimizer_type = LINE_SEARCH;
@@ -131,8 +130,7 @@
   PreprocessedProblem pp;
   EXPECT_TRUE(preprocessor.Preprocess(options, &problem, &pp));
   EXPECT_EQ(pp.evaluator_options.linear_solver_type, CGNR);
-  EXPECT_TRUE(pp.evaluator.get() != NULL);
+  EXPECT_TRUE(pp.evaluator.get() != nullptr);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/linear_least_squares_problems.cc b/third_party/ceres/internal/ceres/linear_least_squares_problems.cc
index 299051c..36cffec 100644
--- a/third_party/ceres/internal/ceres/linear_least_squares_problems.cc
+++ b/third_party/ceres/internal/ceres/linear_least_squares_problems.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -44,12 +44,10 @@
 #include "ceres/types.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
-using std::string;
-
-LinearLeastSquaresProblem* CreateLinearLeastSquaresProblemFromId(int id) {
+std::unique_ptr<LinearLeastSquaresProblem>
+CreateLinearLeastSquaresProblemFromId(int id) {
   switch (id) {
     case 0:
       return LinearLeastSquaresProblem0();
@@ -61,10 +59,14 @@
       return LinearLeastSquaresProblem3();
     case 4:
       return LinearLeastSquaresProblem4();
+    case 5:
+      return LinearLeastSquaresProblem5();
+    case 6:
+      return LinearLeastSquaresProblem6();
     default:
       LOG(FATAL) << "Unknown problem id requested " << id;
   }
-  return NULL;
+  return nullptr;
 }
 
 /*
@@ -85,15 +87,15 @@
 x_D = [1.78448275;
        2.82327586;]
  */
-LinearLeastSquaresProblem* LinearLeastSquaresProblem0() {
-  LinearLeastSquaresProblem* problem = new LinearLeastSquaresProblem;
+std::unique_ptr<LinearLeastSquaresProblem> LinearLeastSquaresProblem0() {
+  auto problem = std::make_unique<LinearLeastSquaresProblem>();
 
-  TripletSparseMatrix* A = new TripletSparseMatrix(3, 2, 6);
-  problem->b.reset(new double[3]);
-  problem->D.reset(new double[2]);
+  auto A = std::make_unique<TripletSparseMatrix>(3, 2, 6);
+  problem->b = std::make_unique<double[]>(3);
+  problem->D = std::make_unique<double[]>(2);
 
-  problem->x.reset(new double[2]);
-  problem->x_D.reset(new double[2]);
+  problem->x = std::make_unique<double[]>(2);
+  problem->x_D = std::make_unique<double[]>(2);
 
   int* Ai = A->mutable_rows();
   int* Aj = A->mutable_cols();
@@ -115,7 +117,7 @@
   Ax[4] = 6;
   Ax[5] = -10;
   A->set_num_nonzeros(6);
-  problem->A.reset(A);
+  problem->A = std::move(A);
 
   problem->b[0] = 8;
   problem->b[1] = 18;
@@ -159,13 +161,15 @@
              12    0    1   17   1
               0   30    1    1  37]
 
+      cond(A'A) = 200.36
+
       S = [ 42.3419  -1.4000  -11.5806
             -1.4000   2.6000    1.0000
-            11.5806   1.0000   31.1935]
+           -11.5806   1.0000   31.1935]
 
       r = [ 4.3032
             5.4000
-            5.0323]
+            4.0323]
 
       S\r = [ 0.2102
               2.1367
@@ -181,17 +185,25 @@
 // BlockSparseMatrix version of this problem.
 
 // TripletSparseMatrix version.
-LinearLeastSquaresProblem* LinearLeastSquaresProblem1() {
+std::unique_ptr<LinearLeastSquaresProblem> LinearLeastSquaresProblem1() {
   int num_rows = 6;
   int num_cols = 5;
 
-  LinearLeastSquaresProblem* problem = new LinearLeastSquaresProblem;
-  TripletSparseMatrix* A =
-      new TripletSparseMatrix(num_rows, num_cols, num_rows * num_cols);
-  problem->b.reset(new double[num_rows]);
-  problem->D.reset(new double[num_cols]);
+  auto problem = std::make_unique<LinearLeastSquaresProblem>();
+
+  auto A = std::make_unique<TripletSparseMatrix>(
+      num_rows, num_cols, num_rows * num_cols);
+  problem->b = std::make_unique<double[]>(num_rows);
+  problem->D = std::make_unique<double[]>(num_cols);
   problem->num_eliminate_blocks = 2;
 
+  problem->x = std::make_unique<double[]>(num_cols);
+  problem->x[0] = -2.3061;
+  problem->x[1] = 0.3172;
+  problem->x[2] = 0.2102;
+  problem->x[3] = 2.1367;
+  problem->x[4] = 0.1388;
+
   int* rows = A->mutable_rows();
   int* cols = A->mutable_cols();
   double* values = A->mutable_values();
@@ -271,7 +283,7 @@
   A->set_num_nonzeros(nnz);
   CHECK(A->IsValid());
 
-  problem->A.reset(A);
+  problem->A = std::move(A);
 
   for (int i = 0; i < num_cols; ++i) {
     problem->D.get()[i] = 1;
@@ -285,21 +297,28 @@
 }
 
 // BlockSparseMatrix version
-LinearLeastSquaresProblem* LinearLeastSquaresProblem2() {
+std::unique_ptr<LinearLeastSquaresProblem> LinearLeastSquaresProblem2() {
   int num_rows = 6;
   int num_cols = 5;
 
-  LinearLeastSquaresProblem* problem = new LinearLeastSquaresProblem;
+  auto problem = std::make_unique<LinearLeastSquaresProblem>();
 
-  problem->b.reset(new double[num_rows]);
-  problem->D.reset(new double[num_cols]);
+  problem->b = std::make_unique<double[]>(num_rows);
+  problem->D = std::make_unique<double[]>(num_cols);
   problem->num_eliminate_blocks = 2;
 
-  CompressedRowBlockStructure* bs = new CompressedRowBlockStructure;
-  std::unique_ptr<double[]> values(new double[num_rows * num_cols]);
+  problem->x = std::make_unique<double[]>(num_cols);
+  problem->x[0] = -2.3061;
+  problem->x[1] = 0.3172;
+  problem->x[2] = 0.2102;
+  problem->x[3] = 2.1367;
+  problem->x[4] = 0.1388;
+
+  auto* bs = new CompressedRowBlockStructure;
+  auto values = std::make_unique<double[]>(num_rows * num_cols);
 
   for (int c = 0; c < num_cols; ++c) {
-    bs->cols.push_back(Block());
+    bs->cols.emplace_back();
     bs->cols.back().size = 1;
     bs->cols.back().position = c;
   }
@@ -311,12 +330,12 @@
     values[nnz++] = 1;
     values[nnz++] = 2;
 
-    bs->rows.push_back(CompressedRow());
+    bs->rows.emplace_back();
     CompressedRow& row = bs->rows.back();
     row.block.size = 1;
     row.block.position = 0;
-    row.cells.push_back(Cell(0, 0));
-    row.cells.push_back(Cell(2, 1));
+    row.cells.emplace_back(0, 0);
+    row.cells.emplace_back(2, 1);
   }
 
   // Row 2
@@ -324,12 +343,12 @@
     values[nnz++] = 3;
     values[nnz++] = 4;
 
-    bs->rows.push_back(CompressedRow());
+    bs->rows.emplace_back();
     CompressedRow& row = bs->rows.back();
     row.block.size = 1;
     row.block.position = 1;
-    row.cells.push_back(Cell(0, 2));
-    row.cells.push_back(Cell(3, 3));
+    row.cells.emplace_back(0, 2);
+    row.cells.emplace_back(3, 3);
   }
 
   // Row 3
@@ -337,12 +356,12 @@
     values[nnz++] = 5;
     values[nnz++] = 6;
 
-    bs->rows.push_back(CompressedRow());
+    bs->rows.emplace_back();
     CompressedRow& row = bs->rows.back();
     row.block.size = 1;
     row.block.position = 2;
-    row.cells.push_back(Cell(1, 4));
-    row.cells.push_back(Cell(4, 5));
+    row.cells.emplace_back(1, 4);
+    row.cells.emplace_back(4, 5);
   }
 
   // Row 4
@@ -350,12 +369,12 @@
     values[nnz++] = 7;
     values[nnz++] = 8;
 
-    bs->rows.push_back(CompressedRow());
+    bs->rows.emplace_back();
     CompressedRow& row = bs->rows.back();
     row.block.size = 1;
     row.block.position = 3;
-    row.cells.push_back(Cell(1, 6));
-    row.cells.push_back(Cell(2, 7));
+    row.cells.emplace_back(1, 6);
+    row.cells.emplace_back(2, 7);
   }
 
   // Row 5
@@ -363,12 +382,12 @@
     values[nnz++] = 9;
     values[nnz++] = 1;
 
-    bs->rows.push_back(CompressedRow());
+    bs->rows.emplace_back();
     CompressedRow& row = bs->rows.back();
     row.block.size = 1;
     row.block.position = 4;
-    row.cells.push_back(Cell(1, 8));
-    row.cells.push_back(Cell(2, 9));
+    row.cells.emplace_back(1, 8);
+    row.cells.emplace_back(2, 9);
   }
 
   // Row 6
@@ -377,16 +396,16 @@
     values[nnz++] = 1;
     values[nnz++] = 1;
 
-    bs->rows.push_back(CompressedRow());
+    bs->rows.emplace_back();
     CompressedRow& row = bs->rows.back();
     row.block.size = 1;
     row.block.position = 5;
-    row.cells.push_back(Cell(2, 10));
-    row.cells.push_back(Cell(3, 11));
-    row.cells.push_back(Cell(4, 12));
+    row.cells.emplace_back(2, 10);
+    row.cells.emplace_back(3, 11);
+    row.cells.emplace_back(4, 12);
   }
 
-  BlockSparseMatrix* A = new BlockSparseMatrix(bs);
+  auto A = std::make_unique<BlockSparseMatrix>(bs);
   memcpy(A->mutable_values(), values.get(), nnz * sizeof(*A->values()));
 
   for (int i = 0; i < num_cols; ++i) {
@@ -397,7 +416,7 @@
     problem->b.get()[i] = i;
   }
 
-  problem->A.reset(A);
+  problem->A = std::move(A);
 
   return problem;
 }
@@ -418,21 +437,21 @@
            5]
 */
 // BlockSparseMatrix version
-LinearLeastSquaresProblem* LinearLeastSquaresProblem3() {
+std::unique_ptr<LinearLeastSquaresProblem> LinearLeastSquaresProblem3() {
   int num_rows = 5;
   int num_cols = 2;
 
-  LinearLeastSquaresProblem* problem = new LinearLeastSquaresProblem;
+  auto problem = std::make_unique<LinearLeastSquaresProblem>();
 
-  problem->b.reset(new double[num_rows]);
-  problem->D.reset(new double[num_cols]);
+  problem->b = std::make_unique<double[]>(num_rows);
+  problem->D = std::make_unique<double[]>(num_cols);
   problem->num_eliminate_blocks = 2;
 
-  CompressedRowBlockStructure* bs = new CompressedRowBlockStructure;
-  std::unique_ptr<double[]> values(new double[num_rows * num_cols]);
+  auto* bs = new CompressedRowBlockStructure;
+  auto values = std::make_unique<double[]>(num_rows * num_cols);
 
   for (int c = 0; c < num_cols; ++c) {
-    bs->cols.push_back(Block());
+    bs->cols.emplace_back();
     bs->cols.back().size = 1;
     bs->cols.back().position = c;
   }
@@ -442,54 +461,54 @@
   // Row 1
   {
     values[nnz++] = 1;
-    bs->rows.push_back(CompressedRow());
+    bs->rows.emplace_back();
     CompressedRow& row = bs->rows.back();
     row.block.size = 1;
     row.block.position = 0;
-    row.cells.push_back(Cell(0, 0));
+    row.cells.emplace_back(0, 0);
   }
 
   // Row 2
   {
     values[nnz++] = 3;
-    bs->rows.push_back(CompressedRow());
+    bs->rows.emplace_back();
     CompressedRow& row = bs->rows.back();
     row.block.size = 1;
     row.block.position = 1;
-    row.cells.push_back(Cell(0, 1));
+    row.cells.emplace_back(0, 1);
   }
 
   // Row 3
   {
     values[nnz++] = 5;
-    bs->rows.push_back(CompressedRow());
+    bs->rows.emplace_back();
     CompressedRow& row = bs->rows.back();
     row.block.size = 1;
     row.block.position = 2;
-    row.cells.push_back(Cell(1, 2));
+    row.cells.emplace_back(1, 2);
   }
 
   // Row 4
   {
     values[nnz++] = 7;
-    bs->rows.push_back(CompressedRow());
+    bs->rows.emplace_back();
     CompressedRow& row = bs->rows.back();
     row.block.size = 1;
     row.block.position = 3;
-    row.cells.push_back(Cell(1, 3));
+    row.cells.emplace_back(1, 3);
   }
 
   // Row 5
   {
     values[nnz++] = 9;
-    bs->rows.push_back(CompressedRow());
+    bs->rows.emplace_back();
     CompressedRow& row = bs->rows.back();
     row.block.size = 1;
     row.block.position = 4;
-    row.cells.push_back(Cell(1, 4));
+    row.cells.emplace_back(1, 4);
   }
 
-  BlockSparseMatrix* A = new BlockSparseMatrix(bs);
+  auto A = std::make_unique<BlockSparseMatrix>(bs);
   memcpy(A->mutable_values(), values.get(), nnz * sizeof(*A->values()));
 
   for (int i = 0; i < num_cols; ++i) {
@@ -500,7 +519,7 @@
     problem->b.get()[i] = i;
   }
 
-  problem->A.reset(A);
+  problem->A = std::move(A);
 
   return problem;
 }
@@ -525,29 +544,29 @@
 //
 // NOTE: This problem is too small and rank deficient to be solved without
 // the diagonal regularization.
-LinearLeastSquaresProblem* LinearLeastSquaresProblem4() {
+std::unique_ptr<LinearLeastSquaresProblem> LinearLeastSquaresProblem4() {
   int num_rows = 3;
   int num_cols = 7;
 
-  LinearLeastSquaresProblem* problem = new LinearLeastSquaresProblem;
+  auto problem = std::make_unique<LinearLeastSquaresProblem>();
 
-  problem->b.reset(new double[num_rows]);
-  problem->D.reset(new double[num_cols]);
+  problem->b = std::make_unique<double[]>(num_rows);
+  problem->D = std::make_unique<double[]>(num_cols);
   problem->num_eliminate_blocks = 1;
 
-  CompressedRowBlockStructure* bs = new CompressedRowBlockStructure;
-  std::unique_ptr<double[]> values(new double[num_rows * num_cols]);
+  auto* bs = new CompressedRowBlockStructure;
+  auto values = std::make_unique<double[]>(num_rows * num_cols);
 
   // Column block structure
-  bs->cols.push_back(Block());
+  bs->cols.emplace_back();
   bs->cols.back().size = 2;
   bs->cols.back().position = 0;
 
-  bs->cols.push_back(Block());
+  bs->cols.emplace_back();
   bs->cols.back().size = 3;
   bs->cols.back().position = 2;
 
-  bs->cols.push_back(Block());
+  bs->cols.emplace_back();
   bs->cols.back().size = 2;
   bs->cols.back().position = 5;
 
@@ -555,18 +574,18 @@
 
   // Row 1 & 2
   {
-    bs->rows.push_back(CompressedRow());
+    bs->rows.emplace_back();
     CompressedRow& row = bs->rows.back();
     row.block.size = 2;
     row.block.position = 0;
 
-    row.cells.push_back(Cell(0, nnz));
+    row.cells.emplace_back(0, nnz);
     values[nnz++] = 1;
     values[nnz++] = 2;
     values[nnz++] = 1;
     values[nnz++] = 4;
 
-    row.cells.push_back(Cell(2, nnz));
+    row.cells.emplace_back(2, nnz);
     values[nnz++] = 1;
     values[nnz++] = 1;
     values[nnz++] = 5;
@@ -575,22 +594,22 @@
 
   // Row 3
   {
-    bs->rows.push_back(CompressedRow());
+    bs->rows.emplace_back();
     CompressedRow& row = bs->rows.back();
     row.block.size = 1;
     row.block.position = 2;
 
-    row.cells.push_back(Cell(1, nnz));
+    row.cells.emplace_back(1, nnz);
     values[nnz++] = 9;
     values[nnz++] = 0;
     values[nnz++] = 0;
 
-    row.cells.push_back(Cell(2, nnz));
+    row.cells.emplace_back(2, nnz);
     values[nnz++] = 3;
     values[nnz++] = 1;
   }
 
-  BlockSparseMatrix* A = new BlockSparseMatrix(bs);
+  auto A = std::make_unique<BlockSparseMatrix>(bs);
   memcpy(A->mutable_values(), values.get(), nnz * sizeof(*A->values()));
 
   for (int i = 0; i < num_cols; ++i) {
@@ -601,7 +620,308 @@
     problem->b.get()[i] = i;
   }
 
-  problem->A.reset(A);
+  problem->A = std::move(A);
+  return problem;
+}
+
+/*
+A problem with block-diagonal F'F.
+
+      A = [1  0 | 0 0 2
+           3  0 | 0 0 4
+           0 -1 | 0 1 0
+           0 -3 | 0 1 0
+           0 -1 | 3 0 0
+           0 -2 | 1 0 0]
+
+      b = [0
+           1
+           2
+           3
+           4
+           5]
+
+      c = A'* b = [ 22
+                   -25
+                    17
+                     7
+                     4]
+
+      A'A = [10    0    0    0   10
+              0   15   -5   -4    0
+              0   -5   10    0    0
+              0   -4    0    2    0
+             10    0    0    0   20]
+
+      cond(A'A) = 41.402
+
+      S = [ 8.3333   -1.3333         0
+           -1.3333    0.9333         0
+                 0         0   10.0000]
+
+      r = [ 8.6667
+           -1.6667
+            1.0000]
+
+      S\r = [  0.9778
+              -0.3889
+               0.1000]
+
+      A\b = [  0.2
+              -1.4444
+               0.9777
+              -0.3888
+               0.1]
+*/
+
+std::unique_ptr<LinearLeastSquaresProblem> LinearLeastSquaresProblem5() {
+  int num_rows = 6;
+  int num_cols = 5;
+
+  auto problem = std::make_unique<LinearLeastSquaresProblem>();
+  problem->b = std::make_unique<double[]>(num_rows);
+  problem->D = std::make_unique<double[]>(num_cols);
+  problem->num_eliminate_blocks = 2;
+
+  // TODO: add x
+  problem->x = std::make_unique<double[]>(num_cols);
+  problem->x[0] = 0.2;
+  problem->x[1] = -1.4444;
+  problem->x[2] = 0.9777;
+  problem->x[3] = -0.3888;
+  problem->x[4] = 0.1;
+
+  auto* bs = new CompressedRowBlockStructure;
+  auto values = std::make_unique<double[]>(num_rows * num_cols);
+
+  for (int c = 0; c < num_cols; ++c) {
+    bs->cols.emplace_back();
+    bs->cols.back().size = 1;
+    bs->cols.back().position = c;
+  }
+
+  int nnz = 0;
+
+  // Row 1
+  {
+    values[nnz++] = -1;
+    values[nnz++] = 2;
+
+    bs->rows.emplace_back();
+    CompressedRow& row = bs->rows.back();
+    row.block.size = 1;
+    row.block.position = 0;
+    row.cells.emplace_back(0, 0);
+    row.cells.emplace_back(4, 1);
+  }
+
+  // Row 2
+  {
+    values[nnz++] = 3;
+    values[nnz++] = 4;
+
+    bs->rows.emplace_back();
+    CompressedRow& row = bs->rows.back();
+    row.block.size = 1;
+    row.block.position = 1;
+    row.cells.emplace_back(0, 2);
+    row.cells.emplace_back(4, 3);
+  }
+
+  // Row 3
+  {
+    values[nnz++] = -1;
+    values[nnz++] = 1;
+
+    bs->rows.emplace_back();
+    CompressedRow& row = bs->rows.back();
+    row.block.size = 1;
+    row.block.position = 2;
+    row.cells.emplace_back(1, 4);
+    row.cells.emplace_back(3, 5);
+  }
+
+  // Row 4
+  {
+    values[nnz++] = -3;
+    values[nnz++] = 1;
+
+    bs->rows.emplace_back();
+    CompressedRow& row = bs->rows.back();
+    row.block.size = 1;
+    row.block.position = 3;
+    row.cells.emplace_back(1, 6);
+    row.cells.emplace_back(3, 7);
+  }
+
+  // Row 5
+  {
+    values[nnz++] = -1;
+    values[nnz++] = 3;
+
+    bs->rows.emplace_back();
+    CompressedRow& row = bs->rows.back();
+    row.block.size = 1;
+    row.block.position = 4;
+    row.cells.emplace_back(1, 8);
+    row.cells.emplace_back(2, 9);
+  }
+
+  // Row 6
+  {
+    // values[nnz++] = 2;
+    values[nnz++] = -2;
+    values[nnz++] = 1;
+
+    bs->rows.emplace_back();
+    CompressedRow& row = bs->rows.back();
+    row.block.size = 1;
+    row.block.position = 5;
+    // row.cells.emplace_back(0, 10);
+    row.cells.emplace_back(1, 10);
+    row.cells.emplace_back(2, 11);
+  }
+
+  auto A = std::make_unique<BlockSparseMatrix>(bs);
+  memcpy(A->mutable_values(), values.get(), nnz * sizeof(*A->values()));
+
+  for (int i = 0; i < num_cols; ++i) {
+    problem->D.get()[i] = 1;
+  }
+
+  for (int i = 0; i < num_rows; ++i) {
+    problem->b.get()[i] = i;
+  }
+
+  problem->A = std::move(A);
+
+  return problem;
+}
+
+/*
+      A = [1 2 0 0 0 1 1
+           1 4 0 0 0 5 6
+           3 4 0 0 0 7 8
+           5 6 0 0 0 9 0
+           0 0 9 0 0 3 1]
+
+      b = [0
+           1
+           2
+           3
+           4]
+*/
+// BlockSparseMatrix version
+//
+// This problem has the unique property that it has two different
+// sized f-blocks, but only one of them occurs in the rows involving
+// the one e-block. So performing Schur elimination on this problem
+// tests the Schur Eliminator's ability to handle non-e-block rows
+// correctly when their structure does not conform to the static
+// structure determined by DetectStructure.
+//
+// Additionally, this problem has the first row of the last row block of E being
+// larger than number of row blocks in E
+//
+// NOTE: This problem is too small and rank deficient to be solved without
+// the diagonal regularization.
+std::unique_ptr<LinearLeastSquaresProblem> LinearLeastSquaresProblem6() {
+  int num_rows = 5;
+  int num_cols = 7;
+
+  auto problem = std::make_unique<LinearLeastSquaresProblem>();
+
+  problem->b = std::make_unique<double[]>(num_rows);
+  problem->D = std::make_unique<double[]>(num_cols);
+  problem->num_eliminate_blocks = 1;
+
+  auto* bs = new CompressedRowBlockStructure;
+  auto values = std::make_unique<double[]>(num_rows * num_cols);
+
+  // Column block structure
+  bs->cols.emplace_back();
+  bs->cols.back().size = 2;
+  bs->cols.back().position = 0;
+
+  bs->cols.emplace_back();
+  bs->cols.back().size = 3;
+  bs->cols.back().position = 2;
+
+  bs->cols.emplace_back();
+  bs->cols.back().size = 2;
+  bs->cols.back().position = 5;
+
+  int nnz = 0;
+
+  // Row 1 & 2
+  {
+    bs->rows.emplace_back();
+    CompressedRow& row = bs->rows.back();
+    row.block.size = 2;
+    row.block.position = 0;
+
+    row.cells.emplace_back(0, nnz);
+    values[nnz++] = 1;
+    values[nnz++] = 2;
+    values[nnz++] = 1;
+    values[nnz++] = 4;
+
+    row.cells.emplace_back(2, nnz);
+    values[nnz++] = 1;
+    values[nnz++] = 1;
+    values[nnz++] = 5;
+    values[nnz++] = 6;
+  }
+
+  // Row 3 & 4
+  {
+    bs->rows.emplace_back();
+    CompressedRow& row = bs->rows.back();
+    row.block.size = 2;
+    row.block.position = 2;
+
+    row.cells.emplace_back(0, nnz);
+    values[nnz++] = 3;
+    values[nnz++] = 4;
+    values[nnz++] = 5;
+    values[nnz++] = 6;
+
+    row.cells.emplace_back(2, nnz);
+    values[nnz++] = 7;
+    values[nnz++] = 8;
+    values[nnz++] = 9;
+    values[nnz++] = 0;
+  }
+
+  // Row 5
+  {
+    bs->rows.emplace_back();
+    CompressedRow& row = bs->rows.back();
+    row.block.size = 1;
+    row.block.position = 4;
+
+    row.cells.emplace_back(1, nnz);
+    values[nnz++] = 9;
+    values[nnz++] = 0;
+    values[nnz++] = 0;
+
+    row.cells.emplace_back(2, nnz);
+    values[nnz++] = 3;
+    values[nnz++] = 1;
+  }
+
+  auto A = std::make_unique<BlockSparseMatrix>(bs);
+  memcpy(A->mutable_values(), values.get(), nnz * sizeof(*A->values()));
+
+  for (int i = 0; i < num_cols; ++i) {
+    problem->D.get()[i] = (i + 1) * 100;
+  }
+
+  for (int i = 0; i < num_rows; ++i) {
+    problem->b.get()[i] = i;
+  }
+
+  problem->A = std::move(A);
   return problem;
 }
 
@@ -610,27 +930,27 @@
                                             const double* D,
                                             const double* b,
                                             const double* x,
-                                            int num_eliminate_blocks) {
+                                            int /*num_eliminate_blocks*/) {
   CHECK(A != nullptr);
   Matrix AA;
   A->ToDenseMatrix(&AA);
   LOG(INFO) << "A^T: \n" << AA.transpose();
 
-  if (D != NULL) {
+  if (D != nullptr) {
     LOG(INFO) << "A's appended diagonal:\n" << ConstVectorRef(D, A->num_cols());
   }
 
-  if (b != NULL) {
+  if (b != nullptr) {
     LOG(INFO) << "b: \n" << ConstVectorRef(b, A->num_rows());
   }
 
-  if (x != NULL) {
+  if (x != nullptr) {
     LOG(INFO) << "x: \n" << ConstVectorRef(x, A->num_cols());
   }
   return true;
 }
 
-void WriteArrayToFileOrDie(const string& filename,
+void WriteArrayToFileOrDie(const std::string& filename,
                            const double* x,
                            const int size) {
   CHECK(x != nullptr);
@@ -643,23 +963,23 @@
   fclose(fptr);
 }
 
-bool DumpLinearLeastSquaresProblemToTextFile(const string& filename_base,
+bool DumpLinearLeastSquaresProblemToTextFile(const std::string& filename_base,
                                              const SparseMatrix* A,
                                              const double* D,
                                              const double* b,
                                              const double* x,
-                                             int num_eliminate_blocks) {
+                                             int /*num_eliminate_blocks*/) {
   CHECK(A != nullptr);
   LOG(INFO) << "writing to: " << filename_base << "*";
 
-  string matlab_script;
+  std::string matlab_script;
   StringAppendF(&matlab_script,
                 "function lsqp = load_trust_region_problem()\n");
   StringAppendF(&matlab_script, "lsqp.num_rows = %d;\n", A->num_rows());
   StringAppendF(&matlab_script, "lsqp.num_cols = %d;\n", A->num_cols());
 
   {
-    string filename = filename_base + "_A.txt";
+    std::string filename = filename_base + "_A.txt";
     FILE* fptr = fopen(filename.c_str(), "w");
     CHECK(fptr != nullptr);
     A->ToTextFile(fptr);
@@ -673,34 +993,34 @@
         A->num_cols());
   }
 
-  if (D != NULL) {
-    string filename = filename_base + "_D.txt";
+  if (D != nullptr) {
+    std::string filename = filename_base + "_D.txt";
     WriteArrayToFileOrDie(filename, D, A->num_cols());
     StringAppendF(
         &matlab_script, "lsqp.D = load('%s', '-ascii');\n", filename.c_str());
   }
 
-  if (b != NULL) {
-    string filename = filename_base + "_b.txt";
+  if (b != nullptr) {
+    std::string filename = filename_base + "_b.txt";
     WriteArrayToFileOrDie(filename, b, A->num_rows());
     StringAppendF(
         &matlab_script, "lsqp.b = load('%s', '-ascii');\n", filename.c_str());
   }
 
-  if (x != NULL) {
-    string filename = filename_base + "_x.txt";
+  if (x != nullptr) {
+    std::string filename = filename_base + "_x.txt";
     WriteArrayToFileOrDie(filename, x, A->num_cols());
     StringAppendF(
         &matlab_script, "lsqp.x = load('%s', '-ascii');\n", filename.c_str());
   }
 
-  string matlab_filename = filename_base + ".m";
+  std::string matlab_filename = filename_base + ".m";
   WriteStringToFileOrDie(matlab_script, matlab_filename);
   return true;
 }
 }  // namespace
 
-bool DumpLinearLeastSquaresProblem(const string& filename_base,
+bool DumpLinearLeastSquaresProblem(const std::string& filename_base,
                                    DumpFormatType dump_format_type,
                                    const SparseMatrix* A,
                                    const double* D,
@@ -721,5 +1041,4 @@
   return true;
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/linear_least_squares_problems.h b/third_party/ceres/internal/ceres/linear_least_squares_problems.h
index cddaa9f..9d01add 100644
--- a/third_party/ceres/internal/ceres/linear_least_squares_problems.h
+++ b/third_party/ceres/internal/ceres/linear_least_squares_problems.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,23 +35,23 @@
 #include <string>
 #include <vector>
 
-#include "ceres/internal/port.h"
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 #include "ceres/sparse_matrix.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // Structure defining a linear least squares problem and if possible
 // ground truth solutions. To be used by various LinearSolver tests.
-struct CERES_EXPORT_INTERNAL LinearLeastSquaresProblem {
-  LinearLeastSquaresProblem() : num_eliminate_blocks(0) {}
+struct CERES_NO_EXPORT LinearLeastSquaresProblem {
+  LinearLeastSquaresProblem() = default;
 
   std::unique_ptr<SparseMatrix> A;
   std::unique_ptr<double[]> b;
   std::unique_ptr<double[]> D;
   // If using the schur eliminator then how many of the variable
   // blocks are e_type blocks.
-  int num_eliminate_blocks;
+  int num_eliminate_blocks{0};
 
   // Solution to min_x |Ax - b|^2
   std::unique_ptr<double[]> x;
@@ -60,17 +60,27 @@
 };
 
 // Factories for linear least squares problem.
-CERES_EXPORT_INTERNAL LinearLeastSquaresProblem*
+CERES_NO_EXPORT std::unique_ptr<LinearLeastSquaresProblem>
 CreateLinearLeastSquaresProblemFromId(int id);
 
-LinearLeastSquaresProblem* LinearLeastSquaresProblem0();
-LinearLeastSquaresProblem* LinearLeastSquaresProblem1();
-LinearLeastSquaresProblem* LinearLeastSquaresProblem2();
-LinearLeastSquaresProblem* LinearLeastSquaresProblem3();
-LinearLeastSquaresProblem* LinearLeastSquaresProblem4();
+CERES_NO_EXPORT
+std::unique_ptr<LinearLeastSquaresProblem> LinearLeastSquaresProblem0();
+CERES_NO_EXPORT
+std::unique_ptr<LinearLeastSquaresProblem> LinearLeastSquaresProblem1();
+CERES_NO_EXPORT
+std::unique_ptr<LinearLeastSquaresProblem> LinearLeastSquaresProblem2();
+CERES_NO_EXPORT
+std::unique_ptr<LinearLeastSquaresProblem> LinearLeastSquaresProblem3();
+CERES_NO_EXPORT
+std::unique_ptr<LinearLeastSquaresProblem> LinearLeastSquaresProblem4();
+CERES_NO_EXPORT
+std::unique_ptr<LinearLeastSquaresProblem> LinearLeastSquaresProblem5();
+CERES_NO_EXPORT
+std::unique_ptr<LinearLeastSquaresProblem> LinearLeastSquaresProblem6();
 
 // Write the linear least squares problem to disk. The exact format
 // depends on dump_format_type.
+CERES_NO_EXPORT
 bool DumpLinearLeastSquaresProblem(const std::string& filename_base,
                                    DumpFormatType dump_format_type,
                                    const SparseMatrix* A,
@@ -78,7 +88,8 @@
                                    const double* b,
                                    const double* x,
                                    int num_eliminate_blocks);
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_LINEAR_LEAST_SQUARES_PROBLEMS_H_
diff --git a/third_party/ceres/internal/ceres/linear_operator.cc b/third_party/ceres/internal/ceres/linear_operator.cc
index 548c724..f4c2c5e 100644
--- a/third_party/ceres/internal/ceres/linear_operator.cc
+++ b/third_party/ceres/internal/ceres/linear_operator.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -30,10 +30,34 @@
 
 #include "ceres/linear_operator.h"
 
-namespace ceres {
-namespace internal {
+#include <glog/logging.h>
 
-LinearOperator::~LinearOperator() {}
+namespace ceres::internal {
 
-}  // namespace internal
-}  // namespace ceres
+void LinearOperator::RightMultiplyAndAccumulate(const double* x,
+                                                double* y,
+                                                ContextImpl* context,
+                                                int num_threads) const {
+  (void)context;
+  if (num_threads != 1) {
+    VLOG(3) << "Parallel right product is not supported by linear operator "
+               "implementation";
+  }
+  RightMultiplyAndAccumulate(x, y);
+}
+
+void LinearOperator::LeftMultiplyAndAccumulate(const double* x,
+                                               double* y,
+                                               ContextImpl* context,
+                                               int num_threads) const {
+  (void)context;
+  if (num_threads != 1) {
+    VLOG(3) << "Parallel left product is not supported by linear operator "
+               "implementation";
+  }
+  LeftMultiplyAndAccumulate(x, y);
+}
+
+LinearOperator::~LinearOperator() = default;
+
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/linear_operator.h b/third_party/ceres/internal/ceres/linear_operator.h
index 9c59fc3..aafc584 100644
--- a/third_party/ceres/internal/ceres/linear_operator.h
+++ b/third_party/ceres/internal/ceres/linear_operator.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -33,28 +33,59 @@
 #ifndef CERES_INTERNAL_LINEAR_OPERATOR_H_
 #define CERES_INTERNAL_LINEAR_OPERATOR_H_
 
-#include "ceres/internal/port.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/export.h"
 #include "ceres/types.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
+
+class ContextImpl;
 
 // This is an abstract base class for linear operators. It supports
 // access to size information and left and right multiply operators.
-class CERES_EXPORT_INTERNAL LinearOperator {
+class CERES_NO_EXPORT LinearOperator {
  public:
   virtual ~LinearOperator();
 
   // y = y + Ax;
-  virtual void RightMultiply(const double* x, double* y) const = 0;
+  virtual void RightMultiplyAndAccumulate(const double* x, double* y) const = 0;
+  virtual void RightMultiplyAndAccumulate(const double* x,
+                                          double* y,
+                                          ContextImpl* context,
+                                          int num_threads) const;
   // y = y + A'x;
-  virtual void LeftMultiply(const double* x, double* y) const = 0;
+  virtual void LeftMultiplyAndAccumulate(const double* x, double* y) const = 0;
+  virtual void LeftMultiplyAndAccumulate(const double* x,
+                                         double* y,
+                                         ContextImpl* context,
+                                         int num_threads) const;
+
+  virtual void RightMultiplyAndAccumulate(const Vector& x, Vector& y) const {
+    RightMultiplyAndAccumulate(x.data(), y.data());
+  }
+
+  virtual void LeftMultiplyAndAccumulate(const Vector& x, Vector& y) const {
+    LeftMultiplyAndAccumulate(x.data(), y.data());
+  }
+
+  virtual void RightMultiplyAndAccumulate(const Vector& x,
+                                          Vector& y,
+                                          ContextImpl* context,
+                                          int num_threads) const {
+    RightMultiplyAndAccumulate(x.data(), y.data(), context, num_threads);
+  }
+
+  virtual void LeftMultiplyAndAccumulate(const Vector& x,
+                                         Vector& y,
+                                         ContextImpl* context,
+                                         int num_threads) const {
+    LeftMultiplyAndAccumulate(x.data(), y.data(), context, num_threads);
+  }
 
   virtual int num_rows() const = 0;
   virtual int num_cols() const = 0;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_INTERNAL_LINEAR_OPERATOR_H_
diff --git a/third_party/ceres/internal/ceres/linear_solver.cc b/third_party/ceres/internal/ceres/linear_solver.cc
index 6cae248..4ba0b75 100644
--- a/third_party/ceres/internal/ceres/linear_solver.cc
+++ b/third_party/ceres/internal/ceres/linear_solver.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -30,20 +30,22 @@
 
 #include "ceres/linear_solver.h"
 
+#include <memory>
+
 #include "ceres/cgnr_solver.h"
 #include "ceres/dense_normal_cholesky_solver.h"
 #include "ceres/dense_qr_solver.h"
 #include "ceres/dynamic_sparse_normal_cholesky_solver.h"
+#include "ceres/internal/config.h"
 #include "ceres/iterative_schur_complement_solver.h"
 #include "ceres/schur_complement_solver.h"
 #include "ceres/sparse_normal_cholesky_solver.h"
 #include "ceres/types.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
-LinearSolver::~LinearSolver() {}
+LinearSolver::~LinearSolver() = default;
 
 LinearSolverType LinearSolver::LinearSolverForZeroEBlocks(
     LinearSolverType linear_solver_type) {
@@ -69,52 +71,59 @@
   return linear_solver_type;
 }
 
-LinearSolver* LinearSolver::Create(const LinearSolver::Options& options) {
-  CHECK(options.context != NULL);
+std::unique_ptr<LinearSolver> LinearSolver::Create(
+    const LinearSolver::Options& options) {
+  CHECK(options.context != nullptr);
 
   switch (options.type) {
-    case CGNR:
-      return new CgnrSolver(options);
+    case CGNR: {
+#ifndef CERES_NO_CUDA
+      if (options.sparse_linear_algebra_library_type == CUDA_SPARSE) {
+        std::string error;
+        return CudaCgnrSolver::Create(options, &error);
+      }
+#endif
+      return std::make_unique<CgnrSolver>(options);
+    } break;
 
     case SPARSE_NORMAL_CHOLESKY:
 #if defined(CERES_NO_SPARSE)
-      return NULL;
+      return nullptr;
 #else
       if (options.dynamic_sparsity) {
-        return new DynamicSparseNormalCholeskySolver(options);
+        return std::make_unique<DynamicSparseNormalCholeskySolver>(options);
       }
 
-      return new SparseNormalCholeskySolver(options);
+      return std::make_unique<SparseNormalCholeskySolver>(options);
 #endif
 
     case SPARSE_SCHUR:
 #if defined(CERES_NO_SPARSE)
-      return NULL;
+      return nullptr;
 #else
-      return new SparseSchurComplementSolver(options);
+      return std::make_unique<SparseSchurComplementSolver>(options);
 #endif
 
     case DENSE_SCHUR:
-      return new DenseSchurComplementSolver(options);
+      return std::make_unique<DenseSchurComplementSolver>(options);
 
     case ITERATIVE_SCHUR:
       if (options.use_explicit_schur_complement) {
-        return new SparseSchurComplementSolver(options);
+        return std::make_unique<SparseSchurComplementSolver>(options);
       } else {
-        return new IterativeSchurComplementSolver(options);
+        return std::make_unique<IterativeSchurComplementSolver>(options);
       }
 
     case DENSE_QR:
-      return new DenseQRSolver(options);
+      return std::make_unique<DenseQRSolver>(options);
 
     case DENSE_NORMAL_CHOLESKY:
-      return new DenseNormalCholeskySolver(options);
+      return std::make_unique<DenseNormalCholeskySolver>(options);
 
     default:
       LOG(FATAL) << "Unknown linear solver type :" << options.type;
-      return NULL;  // MSVC doesn't understand that LOG(FATAL) never returns.
+      return nullptr;  // MSVC doesn't understand that LOG(FATAL) never returns.
   }
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/linear_solver.h b/third_party/ceres/internal/ceres/linear_solver.h
index 49c6527..1d5338f 100644
--- a/third_party/ceres/internal/ceres/linear_solver.h
+++ b/third_party/ceres/internal/ceres/linear_solver.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -36,6 +36,7 @@
 
 #include <cstddef>
 #include <map>
+#include <memory>
 #include <string>
 #include <vector>
 
@@ -45,44 +46,87 @@
 #include "ceres/context_impl.h"
 #include "ceres/dense_sparse_matrix.h"
 #include "ceres/execution_summary.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 #include "ceres/triplet_sparse_matrix.h"
 #include "ceres/types.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
-enum LinearSolverTerminationType {
+enum class LinearSolverTerminationType {
   // Termination criterion was met.
-  LINEAR_SOLVER_SUCCESS,
+  SUCCESS,
 
   // Solver ran for max_num_iterations and terminated before the
   // termination tolerance could be satisfied.
-  LINEAR_SOLVER_NO_CONVERGENCE,
+  NO_CONVERGENCE,
 
   // Solver was terminated due to numerical problems, generally due to
   // the linear system being poorly conditioned.
-  LINEAR_SOLVER_FAILURE,
+  FAILURE,
 
   // Solver failed with a fatal error that cannot be recovered from,
   // e.g. CHOLMOD ran out of memory when computing the symbolic or
   // numeric factorization or an underlying library was called with
   // the wrong arguments.
-  LINEAR_SOLVER_FATAL_ERROR
+  FATAL_ERROR
 };
 
+inline std::ostream& operator<<(std::ostream& s,
+                                LinearSolverTerminationType type) {
+  switch (type) {
+    case LinearSolverTerminationType::SUCCESS:
+      s << "LINEAR_SOLVER_SUCCESS";
+      break;
+    case LinearSolverTerminationType::NO_CONVERGENCE:
+      s << "LINEAR_SOLVER_NO_CONVERGENCE";
+      break;
+    case LinearSolverTerminationType::FAILURE:
+      s << "LINEAR_SOLVER_FAILURE";
+      break;
+    case LinearSolverTerminationType::FATAL_ERROR:
+      s << "LINEAR_SOLVER_FATAL_ERROR";
+      break;
+    default:
+      s << "UNKNOWN LinearSolverTerminationType";
+  }
+  return s;
+}
+
 // This enum controls the fill-reducing ordering a sparse linear
 // algebra library should use before computing a sparse factorization
 // (usually Cholesky).
-enum OrderingType {
+//
+// TODO(sameeragarwal): Add support for nested dissection
+enum class OrderingType {
   NATURAL,  // Do not re-order the matrix. This is useful when the
             // matrix has been ordered using a fill-reducing ordering
             // already.
-  AMD       // Use the Approximate Minimum Degree algorithm to re-order
-            // the matrix.
+
+  AMD,  // Use the Approximate Minimum Degree algorithm to re-order
+        // the matrix.
+
+  NESDIS,  // Use the Nested Dissection algorithm to re-order the matrix.
 };
 
+inline std::ostream& operator<<(std::ostream& s, OrderingType type) {
+  switch (type) {
+    case OrderingType::NATURAL:
+      s << "NATURAL";
+      break;
+    case OrderingType::AMD:
+      s << "AMD";
+      break;
+    case OrderingType::NESDIS:
+      s << "NESDIS";
+      break;
+    default:
+      s << "UNKNOWN OrderingType";
+  }
+  return s;
+}
+
 class LinearOperator;
 
 // Abstract base class for objects that implement algorithms for
@@ -101,7 +145,7 @@
 // The Options struct configures the LinearSolver object for its
 // lifetime. The PerSolveOptions struct is used to specify options for
 // a particular Solve call.
-class CERES_EXPORT_INTERNAL LinearSolver {
+class CERES_NO_EXPORT LinearSolver {
  public:
   struct Options {
     LinearSolverType type = SPARSE_NORMAL_CHOLESKY;
@@ -110,9 +154,9 @@
     DenseLinearAlgebraLibraryType dense_linear_algebra_library_type = EIGEN;
     SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type =
         SUITE_SPARSE;
+    OrderingType ordering_type = OrderingType::NATURAL;
 
     // See solver.h for information about these flags.
-    bool use_postordering = false;
     bool dynamic_sparsity = false;
     bool use_explicit_schur_complement = false;
 
@@ -121,6 +165,23 @@
     int min_num_iterations = 1;
     int max_num_iterations = 1;
 
+    // Maximum number of iterations performed by SCHUR_POWER_SERIES_EXPANSION.
+    // This value controls the maximum number of iterations whether it is used
+    // as a preconditioner or just to initialize the solution for
+    // ITERATIVE_SCHUR.
+    int max_num_spse_iterations = 5;
+
+    // Use SCHUR_POWER_SERIES_EXPANSION to initialize the solution for
+    // ITERATIVE_SCHUR. This option can be set true regardless of what
+    // preconditioner is being used.
+    bool use_spse_initialization = false;
+
+    // When use_spse_initialization is true, this parameter along with
+    // max_num_spse_iterations controls the number of
+    // SCHUR_POWER_SERIES_EXPANSION iterations performed for initialization. It
+    // is not used to control the preconditioner.
+    double spse_tolerance = 0.1;
+
     // If possible, how many threads can the solver use.
     int num_threads = 1;
 
@@ -259,7 +320,8 @@
   struct Summary {
     double residual_norm = -1.0;
     int num_iterations = -1;
-    LinearSolverTerminationType termination_type = LINEAR_SOLVER_FAILURE;
+    LinearSolverTerminationType termination_type =
+        LinearSolverTerminationType::FAILURE;
     std::string message;
   };
 
@@ -284,11 +346,11 @@
   // issues. Further, this calls are not expected to be frequent or
   // performance sensitive.
   virtual std::map<std::string, CallStatistics> Statistics() const {
-    return std::map<std::string, CallStatistics>();
+    return {};
   }
 
   // Factory
-  static LinearSolver* Create(const Options& options);
+  static std::unique_ptr<LinearSolver> Create(const Options& options);
 };
 
 // This templated subclass of LinearSolver serves as a base class for
@@ -301,12 +363,11 @@
 template <typename MatrixType>
 class TypedLinearSolver : public LinearSolver {
  public:
-  virtual ~TypedLinearSolver() {}
-  virtual LinearSolver::Summary Solve(
+  LinearSolver::Summary Solve(
       LinearOperator* A,
       const double* b,
       const LinearSolver::PerSolveOptions& per_solve_options,
-      double* x) {
+      double* x) override {
     ScopedExecutionTimer total_time("LinearSolver::Solve", &execution_summary_);
     CHECK(A != nullptr);
     CHECK(b != nullptr);
@@ -314,7 +375,7 @@
     return SolveImpl(down_cast<MatrixType*>(A), b, per_solve_options, x);
   }
 
-  virtual std::map<std::string, CallStatistics> Statistics() const {
+  std::map<std::string, CallStatistics> Statistics() const override {
     return execution_summary_.statistics();
   }
 
@@ -328,16 +389,17 @@
   ExecutionSummary execution_summary_;
 };
 
-// Linear solvers that depend on acccess to the low level structure of
+// Linear solvers that depend on access to the low level structure of
 // a SparseMatrix.
 // clang-format off
-typedef TypedLinearSolver<BlockSparseMatrix>         BlockSparseMatrixSolver;          // NOLINT
-typedef TypedLinearSolver<CompressedRowSparseMatrix> CompressedRowSparseMatrixSolver;  // NOLINT
-typedef TypedLinearSolver<DenseSparseMatrix>         DenseSparseMatrixSolver;          // NOLINT
-typedef TypedLinearSolver<TripletSparseMatrix>       TripletSparseMatrixSolver;        // NOLINT
+using BlockSparseMatrixSolver = TypedLinearSolver<BlockSparseMatrix>;                  // NOLINT
+using CompressedRowSparseMatrixSolver = TypedLinearSolver<CompressedRowSparseMatrix>;  // NOLINT
+using DenseSparseMatrixSolver = TypedLinearSolver<DenseSparseMatrix>;                  // NOLINT
+using TripletSparseMatrixSolver = TypedLinearSolver<TripletSparseMatrix>;              // NOLINT
 // clang-format on
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_LINEAR_SOLVER_H_
diff --git a/third_party/ceres/internal/ceres/local_parameterization.cc b/third_party/ceres/internal/ceres/local_parameterization.cc
deleted file mode 100644
index 62947f0..0000000
--- a/third_party/ceres/internal/ceres/local_parameterization.cc
+++ /dev/null
@@ -1,349 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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 Google Inc. 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.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/local_parameterization.h"
-
-#include <algorithm>
-
-#include "Eigen/Geometry"
-#include "ceres/internal/eigen.h"
-#include "ceres/internal/fixed_array.h"
-#include "ceres/internal/householder_vector.h"
-#include "ceres/rotation.h"
-#include "glog/logging.h"
-
-namespace ceres {
-
-using std::vector;
-
-LocalParameterization::~LocalParameterization() {}
-
-bool LocalParameterization::MultiplyByJacobian(const double* x,
-                                               const int num_rows,
-                                               const double* global_matrix,
-                                               double* local_matrix) const {
-  if (LocalSize() == 0) {
-    return true;
-  }
-
-  Matrix jacobian(GlobalSize(), LocalSize());
-  if (!ComputeJacobian(x, jacobian.data())) {
-    return false;
-  }
-
-  MatrixRef(local_matrix, num_rows, LocalSize()) =
-      ConstMatrixRef(global_matrix, num_rows, GlobalSize()) * jacobian;
-  return true;
-}
-
-IdentityParameterization::IdentityParameterization(const int size)
-    : size_(size) {
-  CHECK_GT(size, 0);
-}
-
-bool IdentityParameterization::Plus(const double* x,
-                                    const double* delta,
-                                    double* x_plus_delta) const {
-  VectorRef(x_plus_delta, size_) =
-      ConstVectorRef(x, size_) + ConstVectorRef(delta, size_);
-  return true;
-}
-
-bool IdentityParameterization::ComputeJacobian(const double* x,
-                                               double* jacobian) const {
-  MatrixRef(jacobian, size_, size_).setIdentity();
-  return true;
-}
-
-bool IdentityParameterization::MultiplyByJacobian(const double* x,
-                                                  const int num_cols,
-                                                  const double* global_matrix,
-                                                  double* local_matrix) const {
-  std::copy(
-      global_matrix, global_matrix + num_cols * GlobalSize(), local_matrix);
-  return true;
-}
-
-SubsetParameterization::SubsetParameterization(
-    int size, const vector<int>& constant_parameters)
-    : local_size_(size - constant_parameters.size()), constancy_mask_(size, 0) {
-  if (constant_parameters.empty()) {
-    return;
-  }
-
-  vector<int> constant = constant_parameters;
-  std::sort(constant.begin(), constant.end());
-  CHECK_GE(constant.front(), 0) << "Indices indicating constant parameter must "
-                                   "be greater than equal to zero.";
-  CHECK_LT(constant.back(), size)
-      << "Indices indicating constant parameter must be less than the size "
-      << "of the parameter block.";
-  CHECK(std::adjacent_find(constant.begin(), constant.end()) == constant.end())
-      << "The set of constant parameters cannot contain duplicates";
-  for (int i = 0; i < constant_parameters.size(); ++i) {
-    constancy_mask_[constant_parameters[i]] = 1;
-  }
-}
-
-bool SubsetParameterization::Plus(const double* x,
-                                  const double* delta,
-                                  double* x_plus_delta) const {
-  const int global_size = GlobalSize();
-  for (int i = 0, j = 0; i < global_size; ++i) {
-    if (constancy_mask_[i]) {
-      x_plus_delta[i] = x[i];
-    } else {
-      x_plus_delta[i] = x[i] + delta[j++];
-    }
-  }
-  return true;
-}
-
-bool SubsetParameterization::ComputeJacobian(const double* x,
-                                             double* jacobian) const {
-  if (local_size_ == 0) {
-    return true;
-  }
-
-  const int global_size = GlobalSize();
-  MatrixRef m(jacobian, global_size, local_size_);
-  m.setZero();
-  for (int i = 0, j = 0; i < global_size; ++i) {
-    if (!constancy_mask_[i]) {
-      m(i, j++) = 1.0;
-    }
-  }
-  return true;
-}
-
-bool SubsetParameterization::MultiplyByJacobian(const double* x,
-                                                const int num_cols,
-                                                const double* global_matrix,
-                                                double* local_matrix) const {
-  if (local_size_ == 0) {
-    return true;
-  }
-
-  const int global_size = GlobalSize();
-  for (int col = 0; col < num_cols; ++col) {
-    for (int i = 0, j = 0; i < global_size; ++i) {
-      if (!constancy_mask_[i]) {
-        local_matrix[col * local_size_ + j++] =
-            global_matrix[col * global_size + i];
-      }
-    }
-  }
-  return true;
-}
-
-bool QuaternionParameterization::Plus(const double* x,
-                                      const double* delta,
-                                      double* x_plus_delta) const {
-  const double norm_delta =
-      sqrt(delta[0] * delta[0] + delta[1] * delta[1] + delta[2] * delta[2]);
-  if (norm_delta > 0.0) {
-    const double sin_delta_by_delta = (sin(norm_delta) / norm_delta);
-    double q_delta[4];
-    q_delta[0] = cos(norm_delta);
-    q_delta[1] = sin_delta_by_delta * delta[0];
-    q_delta[2] = sin_delta_by_delta * delta[1];
-    q_delta[3] = sin_delta_by_delta * delta[2];
-    QuaternionProduct(q_delta, x, x_plus_delta);
-  } else {
-    for (int i = 0; i < 4; ++i) {
-      x_plus_delta[i] = x[i];
-    }
-  }
-  return true;
-}
-
-bool QuaternionParameterization::ComputeJacobian(const double* x,
-                                                 double* jacobian) const {
-  // clang-format off
-  jacobian[0] = -x[1];  jacobian[1]  = -x[2];   jacobian[2]  = -x[3];
-  jacobian[3] =  x[0];  jacobian[4]  =  x[3];   jacobian[5]  = -x[2];
-  jacobian[6] = -x[3];  jacobian[7]  =  x[0];   jacobian[8]  =  x[1];
-  jacobian[9] =  x[2];  jacobian[10] = -x[1];   jacobian[11] =  x[0];
-  // clang-format on
-  return true;
-}
-
-bool EigenQuaternionParameterization::Plus(const double* x_ptr,
-                                           const double* delta,
-                                           double* x_plus_delta_ptr) const {
-  Eigen::Map<Eigen::Quaterniond> x_plus_delta(x_plus_delta_ptr);
-  Eigen::Map<const Eigen::Quaterniond> x(x_ptr);
-
-  const double norm_delta =
-      sqrt(delta[0] * delta[0] + delta[1] * delta[1] + delta[2] * delta[2]);
-  if (norm_delta > 0.0) {
-    const double sin_delta_by_delta = sin(norm_delta) / norm_delta;
-
-    // Note, in the constructor w is first.
-    Eigen::Quaterniond delta_q(cos(norm_delta),
-                               sin_delta_by_delta * delta[0],
-                               sin_delta_by_delta * delta[1],
-                               sin_delta_by_delta * delta[2]);
-    x_plus_delta = delta_q * x;
-  } else {
-    x_plus_delta = x;
-  }
-
-  return true;
-}
-
-bool EigenQuaternionParameterization::ComputeJacobian(const double* x,
-                                                      double* jacobian) const {
-  // clang-format off
-  jacobian[0] =  x[3];  jacobian[1]  =  x[2];  jacobian[2]  = -x[1];
-  jacobian[3] = -x[2];  jacobian[4]  =  x[3];  jacobian[5]  =  x[0];
-  jacobian[6] =  x[1];  jacobian[7]  = -x[0];  jacobian[8]  =  x[3];
-  jacobian[9] = -x[0];  jacobian[10] = -x[1];  jacobian[11] = -x[2];
-  // clang-format on
-  return true;
-}
-
-HomogeneousVectorParameterization::HomogeneousVectorParameterization(int size)
-    : size_(size) {
-  CHECK_GT(size_, 1) << "The size of the homogeneous vector needs to be "
-                     << "greater than 1.";
-}
-
-bool HomogeneousVectorParameterization::Plus(const double* x_ptr,
-                                             const double* delta_ptr,
-                                             double* x_plus_delta_ptr) const {
-  ConstVectorRef x(x_ptr, size_);
-  ConstVectorRef delta(delta_ptr, size_ - 1);
-  VectorRef x_plus_delta(x_plus_delta_ptr, size_);
-
-  const double norm_delta = delta.norm();
-
-  if (norm_delta == 0.0) {
-    x_plus_delta = x;
-    return true;
-  }
-
-  // Map the delta from the minimum representation to the over parameterized
-  // homogeneous vector. See section A6.9.2 on page 624 of Hartley & Zisserman
-  // (2nd Edition) for a detailed description.  Note there is a typo on Page
-  // 625, line 4 so check the book errata.
-  const double norm_delta_div_2 = 0.5 * norm_delta;
-  const double sin_delta_by_delta =
-      std::sin(norm_delta_div_2) / norm_delta_div_2;
-
-  Vector y(size_);
-  y.head(size_ - 1) = 0.5 * sin_delta_by_delta * delta;
-  y(size_ - 1) = std::cos(norm_delta_div_2);
-
-  Vector v(size_);
-  double beta;
-
-  // NOTE: The explicit template arguments are needed here because
-  // ComputeHouseholderVector is templated and some versions of MSVC
-  // have trouble deducing the type of v automatically.
-  internal::ComputeHouseholderVector<ConstVectorRef, double, Eigen::Dynamic>(
-      x, &v, &beta);
-
-  // Apply the delta update to remain on the unit sphere. See section A6.9.3
-  // on page 625 of Hartley & Zisserman (2nd Edition) for a detailed
-  // description.
-  x_plus_delta = x.norm() * (y - v * (beta * (v.transpose() * y)));
-
-  return true;
-}
-
-bool HomogeneousVectorParameterization::ComputeJacobian(
-    const double* x_ptr, double* jacobian_ptr) const {
-  ConstVectorRef x(x_ptr, size_);
-  MatrixRef jacobian(jacobian_ptr, size_, size_ - 1);
-
-  Vector v(size_);
-  double beta;
-
-  // NOTE: The explicit template arguments are needed here because
-  // ComputeHouseholderVector is templated and some versions of MSVC
-  // have trouble deducing the type of v automatically.
-  internal::ComputeHouseholderVector<ConstVectorRef, double, Eigen::Dynamic>(
-      x, &v, &beta);
-
-  // The Jacobian is equal to J = 0.5 * H.leftCols(size_ - 1) where H is the
-  // Householder matrix (H = I - beta * v * v').
-  for (int i = 0; i < size_ - 1; ++i) {
-    jacobian.col(i) = -0.5 * beta * v(i) * v;
-    jacobian.col(i)(i) += 0.5;
-  }
-  jacobian *= x.norm();
-
-  return true;
-}
-
-bool ProductParameterization::Plus(const double* x,
-                                   const double* delta,
-                                   double* x_plus_delta) const {
-  int x_cursor = 0;
-  int delta_cursor = 0;
-  for (const auto& param : local_params_) {
-    if (!param->Plus(
-            x + x_cursor, delta + delta_cursor, x_plus_delta + x_cursor)) {
-      return false;
-    }
-    delta_cursor += param->LocalSize();
-    x_cursor += param->GlobalSize();
-  }
-
-  return true;
-}
-
-bool ProductParameterization::ComputeJacobian(const double* x,
-                                              double* jacobian_ptr) const {
-  MatrixRef jacobian(jacobian_ptr, GlobalSize(), LocalSize());
-  jacobian.setZero();
-  internal::FixedArray<double> buffer(buffer_size_);
-
-  int x_cursor = 0;
-  int delta_cursor = 0;
-  for (const auto& param : local_params_) {
-    const int local_size = param->LocalSize();
-    const int global_size = param->GlobalSize();
-
-    if (!param->ComputeJacobian(x + x_cursor, buffer.data())) {
-      return false;
-    }
-    jacobian.block(x_cursor, delta_cursor, global_size, local_size) =
-        MatrixRef(buffer.data(), global_size, local_size);
-
-    delta_cursor += local_size;
-    x_cursor += global_size;
-  }
-
-  return true;
-}
-
-}  // namespace ceres
diff --git a/third_party/ceres/internal/ceres/local_parameterization_test.cc b/third_party/ceres/internal/ceres/local_parameterization_test.cc
deleted file mode 100644
index ec8e660..0000000
--- a/third_party/ceres/internal/ceres/local_parameterization_test.cc
+++ /dev/null
@@ -1,953 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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 Google Inc. 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.
-//
-// Author: sameeragarwal@google.com (Sameer Agarwal)
-
-#include "ceres/local_parameterization.h"
-
-#include <cmath>
-#include <limits>
-#include <memory>
-
-#include "Eigen/Geometry"
-#include "ceres/autodiff_local_parameterization.h"
-#include "ceres/internal/autodiff.h"
-#include "ceres/internal/eigen.h"
-#include "ceres/internal/householder_vector.h"
-#include "ceres/random.h"
-#include "ceres/rotation.h"
-#include "gtest/gtest.h"
-
-namespace ceres {
-namespace internal {
-
-TEST(IdentityParameterization, EverythingTest) {
-  IdentityParameterization parameterization(3);
-  EXPECT_EQ(parameterization.GlobalSize(), 3);
-  EXPECT_EQ(parameterization.LocalSize(), 3);
-
-  double x[3] = {1.0, 2.0, 3.0};
-  double delta[3] = {0.0, 1.0, 2.0};
-  double x_plus_delta[3] = {0.0, 0.0, 0.0};
-  parameterization.Plus(x, delta, x_plus_delta);
-  EXPECT_EQ(x_plus_delta[0], 1.0);
-  EXPECT_EQ(x_plus_delta[1], 3.0);
-  EXPECT_EQ(x_plus_delta[2], 5.0);
-
-  double jacobian[9];
-  parameterization.ComputeJacobian(x, jacobian);
-  int k = 0;
-  for (int i = 0; i < 3; ++i) {
-    for (int j = 0; j < 3; ++j, ++k) {
-      EXPECT_EQ(jacobian[k], (i == j) ? 1.0 : 0.0);
-    }
-  }
-
-  Matrix global_matrix = Matrix::Ones(10, 3);
-  Matrix local_matrix = Matrix::Zero(10, 3);
-  parameterization.MultiplyByJacobian(
-      x, 10, global_matrix.data(), local_matrix.data());
-  EXPECT_EQ((local_matrix - global_matrix).norm(), 0.0);
-}
-
-TEST(SubsetParameterization, EmptyConstantParameters) {
-  std::vector<int> constant_parameters;
-  SubsetParameterization parameterization(3, constant_parameters);
-  EXPECT_EQ(parameterization.GlobalSize(), 3);
-  EXPECT_EQ(parameterization.LocalSize(), 3);
-  double x[3] = {1, 2, 3};
-  double delta[3] = {4, 5, 6};
-  double x_plus_delta[3] = {-1, -2, -3};
-  parameterization.Plus(x, delta, x_plus_delta);
-  EXPECT_EQ(x_plus_delta[0], x[0] + delta[0]);
-  EXPECT_EQ(x_plus_delta[1], x[1] + delta[1]);
-  EXPECT_EQ(x_plus_delta[2], x[2] + delta[2]);
-
-  Matrix jacobian(3, 3);
-  Matrix expected_jacobian(3, 3);
-  expected_jacobian.setIdentity();
-  parameterization.ComputeJacobian(x, jacobian.data());
-  EXPECT_EQ(jacobian, expected_jacobian);
-
-  Matrix global_matrix(3, 5);
-  global_matrix.setRandom();
-  Matrix local_matrix(3, 5);
-  parameterization.MultiplyByJacobian(
-      x, 5, global_matrix.data(), local_matrix.data());
-  EXPECT_EQ(global_matrix, local_matrix);
-}
-
-TEST(SubsetParameterization, NegativeParameterIndexDeathTest) {
-  std::vector<int> constant_parameters;
-  constant_parameters.push_back(-1);
-  EXPECT_DEATH_IF_SUPPORTED(
-      SubsetParameterization parameterization(2, constant_parameters),
-      "greater than equal to zero");
-}
-
-TEST(SubsetParameterization, GreaterThanSizeParameterIndexDeathTest) {
-  std::vector<int> constant_parameters;
-  constant_parameters.push_back(2);
-  EXPECT_DEATH_IF_SUPPORTED(
-      SubsetParameterization parameterization(2, constant_parameters),
-      "less than the size");
-}
-
-TEST(SubsetParameterization, DuplicateParametersDeathTest) {
-  std::vector<int> constant_parameters;
-  constant_parameters.push_back(1);
-  constant_parameters.push_back(1);
-  EXPECT_DEATH_IF_SUPPORTED(
-      SubsetParameterization parameterization(2, constant_parameters),
-      "duplicates");
-}
-
-TEST(SubsetParameterization,
-     ProductParameterizationWithZeroLocalSizeSubsetParameterization1) {
-  std::vector<int> constant_parameters;
-  constant_parameters.push_back(0);
-  LocalParameterization* subset_param =
-      new SubsetParameterization(1, constant_parameters);
-  LocalParameterization* identity_param = new IdentityParameterization(2);
-  ProductParameterization product_param(subset_param, identity_param);
-  EXPECT_EQ(product_param.GlobalSize(), 3);
-  EXPECT_EQ(product_param.LocalSize(), 2);
-  double x[] = {1.0, 1.0, 1.0};
-  double delta[] = {2.0, 3.0};
-  double x_plus_delta[] = {0.0, 0.0, 0.0};
-  EXPECT_TRUE(product_param.Plus(x, delta, x_plus_delta));
-  EXPECT_EQ(x_plus_delta[0], x[0]);
-  EXPECT_EQ(x_plus_delta[1], x[1] + delta[0]);
-  EXPECT_EQ(x_plus_delta[2], x[2] + delta[1]);
-
-  Matrix actual_jacobian(3, 2);
-  EXPECT_TRUE(product_param.ComputeJacobian(x, actual_jacobian.data()));
-}
-
-TEST(SubsetParameterization,
-     ProductParameterizationWithZeroLocalSizeSubsetParameterization2) {
-  std::vector<int> constant_parameters;
-  constant_parameters.push_back(0);
-  LocalParameterization* subset_param =
-      new SubsetParameterization(1, constant_parameters);
-  LocalParameterization* identity_param = new IdentityParameterization(2);
-  ProductParameterization product_param(identity_param, subset_param);
-  EXPECT_EQ(product_param.GlobalSize(), 3);
-  EXPECT_EQ(product_param.LocalSize(), 2);
-  double x[] = {1.0, 1.0, 1.0};
-  double delta[] = {2.0, 3.0};
-  double x_plus_delta[] = {0.0, 0.0, 0.0};
-  EXPECT_TRUE(product_param.Plus(x, delta, x_plus_delta));
-  EXPECT_EQ(x_plus_delta[0], x[0] + delta[0]);
-  EXPECT_EQ(x_plus_delta[1], x[1] + delta[1]);
-  EXPECT_EQ(x_plus_delta[2], x[2]);
-
-  Matrix actual_jacobian(3, 2);
-  EXPECT_TRUE(product_param.ComputeJacobian(x, actual_jacobian.data()));
-}
-
-TEST(SubsetParameterization, NormalFunctionTest) {
-  const int kGlobalSize = 4;
-  const int kLocalSize = 3;
-
-  double x[kGlobalSize] = {1.0, 2.0, 3.0, 4.0};
-  for (int i = 0; i < kGlobalSize; ++i) {
-    std::vector<int> constant_parameters;
-    constant_parameters.push_back(i);
-    SubsetParameterization parameterization(kGlobalSize, constant_parameters);
-    double delta[kLocalSize] = {1.0, 2.0, 3.0};
-    double x_plus_delta[kGlobalSize] = {0.0, 0.0, 0.0};
-
-    parameterization.Plus(x, delta, x_plus_delta);
-    int k = 0;
-    for (int j = 0; j < kGlobalSize; ++j) {
-      if (j == i) {
-        EXPECT_EQ(x_plus_delta[j], x[j]);
-      } else {
-        EXPECT_EQ(x_plus_delta[j], x[j] + delta[k++]);
-      }
-    }
-
-    double jacobian[kGlobalSize * kLocalSize];
-    parameterization.ComputeJacobian(x, jacobian);
-    int delta_cursor = 0;
-    int jacobian_cursor = 0;
-    for (int j = 0; j < kGlobalSize; ++j) {
-      if (j != i) {
-        for (int k = 0; k < kLocalSize; ++k, jacobian_cursor++) {
-          EXPECT_EQ(jacobian[jacobian_cursor], delta_cursor == k ? 1.0 : 0.0);
-        }
-        ++delta_cursor;
-      } else {
-        for (int k = 0; k < kLocalSize; ++k, jacobian_cursor++) {
-          EXPECT_EQ(jacobian[jacobian_cursor], 0.0);
-        }
-      }
-    }
-
-    Matrix global_matrix = Matrix::Ones(10, kGlobalSize);
-    for (int row = 0; row < kGlobalSize; ++row) {
-      for (int col = 0; col < kGlobalSize; ++col) {
-        global_matrix(row, col) = col;
-      }
-    }
-
-    Matrix local_matrix = Matrix::Zero(10, kLocalSize);
-    parameterization.MultiplyByJacobian(
-        x, 10, global_matrix.data(), local_matrix.data());
-    Matrix expected_local_matrix =
-        global_matrix * MatrixRef(jacobian, kGlobalSize, kLocalSize);
-    EXPECT_EQ((local_matrix - expected_local_matrix).norm(), 0.0);
-  }
-}
-
-// Functor needed to implement automatically differentiated Plus for
-// quaternions.
-struct QuaternionPlus {
-  template <typename T>
-  bool operator()(const T* x, const T* delta, T* x_plus_delta) const {
-    const T squared_norm_delta =
-        delta[0] * delta[0] + delta[1] * delta[1] + delta[2] * delta[2];
-
-    T q_delta[4];
-    if (squared_norm_delta > T(0.0)) {
-      T norm_delta = sqrt(squared_norm_delta);
-      const T sin_delta_by_delta = sin(norm_delta) / norm_delta;
-      q_delta[0] = cos(norm_delta);
-      q_delta[1] = sin_delta_by_delta * delta[0];
-      q_delta[2] = sin_delta_by_delta * delta[1];
-      q_delta[3] = sin_delta_by_delta * delta[2];
-    } else {
-      // We do not just use q_delta = [1,0,0,0] here because that is a
-      // constant and when used for automatic differentiation will
-      // lead to a zero derivative. Instead we take a first order
-      // approximation and evaluate it at zero.
-      q_delta[0] = T(1.0);
-      q_delta[1] = delta[0];
-      q_delta[2] = delta[1];
-      q_delta[3] = delta[2];
-    }
-
-    QuaternionProduct(q_delta, x, x_plus_delta);
-    return true;
-  }
-};
-
-template <typename Parameterization, typename Plus>
-void QuaternionParameterizationTestHelper(const double* x,
-                                          const double* delta,
-                                          const double* x_plus_delta_ref) {
-  const int kGlobalSize = 4;
-  const int kLocalSize = 3;
-
-  const double kTolerance = 1e-14;
-
-  double x_plus_delta[kGlobalSize] = {0.0, 0.0, 0.0, 0.0};
-  Parameterization parameterization;
-  parameterization.Plus(x, delta, x_plus_delta);
-  for (int i = 0; i < kGlobalSize; ++i) {
-    EXPECT_NEAR(x_plus_delta[i], x_plus_delta[i], kTolerance);
-  }
-
-  const double x_plus_delta_norm = sqrt(
-      x_plus_delta[0] * x_plus_delta[0] + x_plus_delta[1] * x_plus_delta[1] +
-      x_plus_delta[2] * x_plus_delta[2] + x_plus_delta[3] * x_plus_delta[3]);
-
-  EXPECT_NEAR(x_plus_delta_norm, 1.0, kTolerance);
-
-  double jacobian_ref[12];
-  double zero_delta[kLocalSize] = {0.0, 0.0, 0.0};
-  const double* parameters[2] = {x, zero_delta};
-  double* jacobian_array[2] = {NULL, jacobian_ref};
-
-  // Autodiff jacobian at delta_x = 0.
-  internal::AutoDifferentiate<kGlobalSize,
-                              StaticParameterDims<kGlobalSize, kLocalSize>>(
-      Plus(), parameters, kGlobalSize, x_plus_delta, jacobian_array);
-
-  double jacobian[12];
-  parameterization.ComputeJacobian(x, jacobian);
-  for (int i = 0; i < 12; ++i) {
-    EXPECT_TRUE(IsFinite(jacobian[i]));
-    EXPECT_NEAR(jacobian[i], jacobian_ref[i], kTolerance)
-        << "Jacobian mismatch: i = " << i << "\n Expected \n"
-        << ConstMatrixRef(jacobian_ref, kGlobalSize, kLocalSize)
-        << "\n Actual \n"
-        << ConstMatrixRef(jacobian, kGlobalSize, kLocalSize);
-  }
-
-  Matrix global_matrix = Matrix::Random(10, kGlobalSize);
-  Matrix local_matrix = Matrix::Zero(10, kLocalSize);
-  parameterization.MultiplyByJacobian(
-      x, 10, global_matrix.data(), local_matrix.data());
-  Matrix expected_local_matrix =
-      global_matrix * MatrixRef(jacobian, kGlobalSize, kLocalSize);
-  EXPECT_NEAR((local_matrix - expected_local_matrix).norm(),
-              0.0,
-              10.0 * std::numeric_limits<double>::epsilon());
-}
-
-template <int N>
-void Normalize(double* x) {
-  VectorRef(x, N).normalize();
-}
-
-TEST(QuaternionParameterization, ZeroTest) {
-  double x[4] = {0.5, 0.5, 0.5, 0.5};
-  double delta[3] = {0.0, 0.0, 0.0};
-  double q_delta[4] = {1.0, 0.0, 0.0, 0.0};
-  double x_plus_delta[4] = {0.0, 0.0, 0.0, 0.0};
-  QuaternionProduct(q_delta, x, x_plus_delta);
-  QuaternionParameterizationTestHelper<QuaternionParameterization,
-                                       QuaternionPlus>(x, delta, x_plus_delta);
-}
-
-TEST(QuaternionParameterization, NearZeroTest) {
-  double x[4] = {0.52, 0.25, 0.15, 0.45};
-  Normalize<4>(x);
-
-  double delta[3] = {0.24, 0.15, 0.10};
-  for (int i = 0; i < 3; ++i) {
-    delta[i] = delta[i] * 1e-14;
-  }
-
-  double q_delta[4];
-  q_delta[0] = 1.0;
-  q_delta[1] = delta[0];
-  q_delta[2] = delta[1];
-  q_delta[3] = delta[2];
-
-  double x_plus_delta[4] = {0.0, 0.0, 0.0, 0.0};
-  QuaternionProduct(q_delta, x, x_plus_delta);
-  QuaternionParameterizationTestHelper<QuaternionParameterization,
-                                       QuaternionPlus>(x, delta, x_plus_delta);
-}
-
-TEST(QuaternionParameterization, AwayFromZeroTest) {
-  double x[4] = {0.52, 0.25, 0.15, 0.45};
-  Normalize<4>(x);
-
-  double delta[3] = {0.24, 0.15, 0.10};
-  const double delta_norm =
-      sqrt(delta[0] * delta[0] + delta[1] * delta[1] + delta[2] * delta[2]);
-  double q_delta[4];
-  q_delta[0] = cos(delta_norm);
-  q_delta[1] = sin(delta_norm) / delta_norm * delta[0];
-  q_delta[2] = sin(delta_norm) / delta_norm * delta[1];
-  q_delta[3] = sin(delta_norm) / delta_norm * delta[2];
-
-  double x_plus_delta[4] = {0.0, 0.0, 0.0, 0.0};
-  QuaternionProduct(q_delta, x, x_plus_delta);
-  QuaternionParameterizationTestHelper<QuaternionParameterization,
-                                       QuaternionPlus>(x, delta, x_plus_delta);
-}
-
-// Functor needed to implement automatically differentiated Plus for
-// Eigen's quaternion.
-struct EigenQuaternionPlus {
-  template <typename T>
-  bool operator()(const T* x, const T* delta, T* x_plus_delta) const {
-    const T norm_delta =
-        sqrt(delta[0] * delta[0] + delta[1] * delta[1] + delta[2] * delta[2]);
-
-    Eigen::Quaternion<T> q_delta;
-    if (norm_delta > T(0.0)) {
-      const T sin_delta_by_delta = sin(norm_delta) / norm_delta;
-      q_delta.coeffs() << sin_delta_by_delta * delta[0],
-          sin_delta_by_delta * delta[1], sin_delta_by_delta * delta[2],
-          cos(norm_delta);
-    } else {
-      // We do not just use q_delta = [0,0,0,1] here because that is a
-      // constant and when used for automatic differentiation will
-      // lead to a zero derivative. Instead we take a first order
-      // approximation and evaluate it at zero.
-      q_delta.coeffs() << delta[0], delta[1], delta[2], T(1.0);
-    }
-
-    Eigen::Map<Eigen::Quaternion<T>> x_plus_delta_ref(x_plus_delta);
-    Eigen::Map<const Eigen::Quaternion<T>> x_ref(x);
-    x_plus_delta_ref = q_delta * x_ref;
-    return true;
-  }
-};
-
-TEST(EigenQuaternionParameterization, ZeroTest) {
-  Eigen::Quaterniond x(0.5, 0.5, 0.5, 0.5);
-  double delta[3] = {0.0, 0.0, 0.0};
-  Eigen::Quaterniond q_delta(1.0, 0.0, 0.0, 0.0);
-  Eigen::Quaterniond x_plus_delta = q_delta * x;
-  QuaternionParameterizationTestHelper<EigenQuaternionParameterization,
-                                       EigenQuaternionPlus>(
-      x.coeffs().data(), delta, x_plus_delta.coeffs().data());
-}
-
-TEST(EigenQuaternionParameterization, NearZeroTest) {
-  Eigen::Quaterniond x(0.52, 0.25, 0.15, 0.45);
-  x.normalize();
-
-  double delta[3] = {0.24, 0.15, 0.10};
-  for (int i = 0; i < 3; ++i) {
-    delta[i] = delta[i] * 1e-14;
-  }
-
-  // Note: w is first in the constructor.
-  Eigen::Quaterniond q_delta(1.0, delta[0], delta[1], delta[2]);
-
-  Eigen::Quaterniond x_plus_delta = q_delta * x;
-  QuaternionParameterizationTestHelper<EigenQuaternionParameterization,
-                                       EigenQuaternionPlus>(
-      x.coeffs().data(), delta, x_plus_delta.coeffs().data());
-}
-
-TEST(EigenQuaternionParameterization, AwayFromZeroTest) {
-  Eigen::Quaterniond x(0.52, 0.25, 0.15, 0.45);
-  x.normalize();
-
-  double delta[3] = {0.24, 0.15, 0.10};
-  const double delta_norm =
-      sqrt(delta[0] * delta[0] + delta[1] * delta[1] + delta[2] * delta[2]);
-
-  // Note: w is first in the constructor.
-  Eigen::Quaterniond q_delta(cos(delta_norm),
-                             sin(delta_norm) / delta_norm * delta[0],
-                             sin(delta_norm) / delta_norm * delta[1],
-                             sin(delta_norm) / delta_norm * delta[2]);
-
-  Eigen::Quaterniond x_plus_delta = q_delta * x;
-  QuaternionParameterizationTestHelper<EigenQuaternionParameterization,
-                                       EigenQuaternionPlus>(
-      x.coeffs().data(), delta, x_plus_delta.coeffs().data());
-}
-
-// Functor needed to implement automatically differentiated Plus for
-// homogeneous vectors.
-template <int Dim>
-struct HomogeneousVectorParameterizationPlus {
-  template <typename Scalar>
-  bool operator()(const Scalar* p_x,
-                  const Scalar* p_delta,
-                  Scalar* p_x_plus_delta) const {
-    Eigen::Map<const Eigen::Matrix<Scalar, Dim, 1>> x(p_x);
-    Eigen::Map<const Eigen::Matrix<Scalar, Dim - 1, 1>> delta(p_delta);
-    Eigen::Map<Eigen::Matrix<Scalar, Dim, 1>> x_plus_delta(p_x_plus_delta);
-
-    const Scalar squared_norm_delta = delta.squaredNorm();
-
-    Eigen::Matrix<Scalar, Dim, 1> y;
-    Scalar one_half(0.5);
-    if (squared_norm_delta > Scalar(0.0)) {
-      Scalar norm_delta = sqrt(squared_norm_delta);
-      Scalar norm_delta_div_2 = 0.5 * norm_delta;
-      const Scalar sin_delta_by_delta =
-          sin(norm_delta_div_2) / norm_delta_div_2;
-      y.template head<Dim - 1>() = sin_delta_by_delta * one_half * delta;
-      y[Dim - 1] = cos(norm_delta_div_2);
-
-    } else {
-      // We do not just use y = [0,0,0,1] here because that is a
-      // constant and when used for automatic differentiation will
-      // lead to a zero derivative. Instead we take a first order
-      // approximation and evaluate it at zero.
-      y.template head<Dim - 1>() = delta * one_half;
-      y[Dim - 1] = Scalar(1.0);
-    }
-
-    Eigen::Matrix<Scalar, Dim, 1> v;
-    Scalar beta;
-
-    // NOTE: The explicit template arguments are needed here because
-    // ComputeHouseholderVector is templated and some versions of MSVC
-    // have trouble deducing the type of v automatically.
-    internal::ComputeHouseholderVector<
-        Eigen::Map<const Eigen::Matrix<Scalar, Dim, 1>>,
-        Scalar,
-        Dim>(x, &v, &beta);
-
-    x_plus_delta = x.norm() * (y - v * (beta * v.dot(y)));
-
-    return true;
-  }
-};
-
-static void HomogeneousVectorParameterizationHelper(const double* x,
-                                                    const double* delta) {
-  const double kTolerance = 1e-14;
-
-  HomogeneousVectorParameterization homogeneous_vector_parameterization(4);
-
-  // Ensure the update maintains the norm.
-  double x_plus_delta[4] = {0.0, 0.0, 0.0, 0.0};
-  homogeneous_vector_parameterization.Plus(x, delta, x_plus_delta);
-
-  const double x_plus_delta_norm = sqrt(
-      x_plus_delta[0] * x_plus_delta[0] + x_plus_delta[1] * x_plus_delta[1] +
-      x_plus_delta[2] * x_plus_delta[2] + x_plus_delta[3] * x_plus_delta[3]);
-
-  const double x_norm =
-      sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2] + x[3] * x[3]);
-
-  EXPECT_NEAR(x_plus_delta_norm, x_norm, kTolerance);
-
-  // Autodiff jacobian at delta_x = 0.
-  AutoDiffLocalParameterization<HomogeneousVectorParameterizationPlus<4>, 4, 3>
-      autodiff_jacobian;
-
-  double jacobian_autodiff[12];
-  double jacobian_analytic[12];
-
-  homogeneous_vector_parameterization.ComputeJacobian(x, jacobian_analytic);
-  autodiff_jacobian.ComputeJacobian(x, jacobian_autodiff);
-
-  for (int i = 0; i < 12; ++i) {
-    EXPECT_TRUE(ceres::IsFinite(jacobian_analytic[i]));
-    EXPECT_NEAR(jacobian_analytic[i], jacobian_autodiff[i], kTolerance)
-        << "Jacobian mismatch: i = " << i << ", " << jacobian_analytic[i] << " "
-        << jacobian_autodiff[i];
-  }
-}
-
-TEST(HomogeneousVectorParameterization, ZeroTest) {
-  double x[4] = {0.0, 0.0, 0.0, 1.0};
-  Normalize<4>(x);
-  double delta[3] = {0.0, 0.0, 0.0};
-
-  HomogeneousVectorParameterizationHelper(x, delta);
-}
-
-TEST(HomogeneousVectorParameterization, NearZeroTest1) {
-  double x[4] = {1e-5, 1e-5, 1e-5, 1.0};
-  Normalize<4>(x);
-  double delta[3] = {0.0, 1.0, 0.0};
-
-  HomogeneousVectorParameterizationHelper(x, delta);
-}
-
-TEST(HomogeneousVectorParameterization, NearZeroTest2) {
-  double x[4] = {0.001, 0.0, 0.0, 0.0};
-  double delta[3] = {0.0, 1.0, 0.0};
-
-  HomogeneousVectorParameterizationHelper(x, delta);
-}
-
-TEST(HomogeneousVectorParameterization, AwayFromZeroTest1) {
-  double x[4] = {0.52, 0.25, 0.15, 0.45};
-  Normalize<4>(x);
-  double delta[3] = {0.0, 1.0, -0.5};
-
-  HomogeneousVectorParameterizationHelper(x, delta);
-}
-
-TEST(HomogeneousVectorParameterization, AwayFromZeroTest2) {
-  double x[4] = {0.87, -0.25, -0.34, 0.45};
-  Normalize<4>(x);
-  double delta[3] = {0.0, 0.0, -0.5};
-
-  HomogeneousVectorParameterizationHelper(x, delta);
-}
-
-TEST(HomogeneousVectorParameterization, AwayFromZeroTest3) {
-  double x[4] = {0.0, 0.0, 0.0, 2.0};
-  double delta[3] = {0.0, 0.0, 0};
-
-  HomogeneousVectorParameterizationHelper(x, delta);
-}
-
-TEST(HomogeneousVectorParameterization, AwayFromZeroTest4) {
-  double x[4] = {0.2, -1.0, 0.0, 2.0};
-  double delta[3] = {1.4, 0.0, -0.5};
-
-  HomogeneousVectorParameterizationHelper(x, delta);
-}
-
-TEST(HomogeneousVectorParameterization, AwayFromZeroTest5) {
-  double x[4] = {2.0, 0.0, 0.0, 0.0};
-  double delta[3] = {1.4, 0.0, -0.5};
-
-  HomogeneousVectorParameterizationHelper(x, delta);
-}
-
-TEST(HomogeneousVectorParameterization, DeathTests) {
-  EXPECT_DEATH_IF_SUPPORTED(HomogeneousVectorParameterization x(1), "size");
-}
-
-// Functor needed to implement automatically differentiated Plus for
-// line parameterization.
-template <int AmbientSpaceDim>
-struct LineParameterizationPlus {
-  template <typename Scalar>
-  bool operator()(const Scalar* p_x,
-                  const Scalar* p_delta,
-                  Scalar* p_x_plus_delta) const {
-    static constexpr int kTangetSpaceDim = AmbientSpaceDim - 1;
-    Eigen::Map<const Eigen::Matrix<Scalar, AmbientSpaceDim, 1>> origin_point(
-        p_x);
-    Eigen::Map<const Eigen::Matrix<Scalar, AmbientSpaceDim, 1>> dir(
-        p_x + AmbientSpaceDim);
-    Eigen::Map<const Eigen::Matrix<Scalar, kTangetSpaceDim, 1>>
-        delta_origin_point(p_delta);
-    Eigen::Map<Eigen::Matrix<Scalar, AmbientSpaceDim, 1>>
-        origin_point_plus_delta(p_x_plus_delta);
-
-    HomogeneousVectorParameterizationPlus<AmbientSpaceDim> dir_plus;
-    dir_plus(dir.data(),
-             p_delta + kTangetSpaceDim,
-             p_x_plus_delta + AmbientSpaceDim);
-
-    Eigen::Matrix<Scalar, AmbientSpaceDim, 1> v;
-    Scalar beta;
-
-    // NOTE: The explicit template arguments are needed here because
-    // ComputeHouseholderVector is templated and some versions of MSVC
-    // have trouble deducing the type of v automatically.
-    internal::ComputeHouseholderVector<
-        Eigen::Map<const Eigen::Matrix<Scalar, AmbientSpaceDim, 1>>,
-        Scalar,
-        AmbientSpaceDim>(dir, &v, &beta);
-
-    Eigen::Matrix<Scalar, AmbientSpaceDim, 1> y;
-    y << 0.5 * delta_origin_point, Scalar(0.0);
-    origin_point_plus_delta = origin_point + y - v * (beta * v.dot(y));
-
-    return true;
-  }
-};
-
-template <int AmbientSpaceDim>
-static void LineParameterizationHelper(const double* x_ptr,
-                                       const double* delta) {
-  const double kTolerance = 1e-14;
-
-  static constexpr int ParameterDim = 2 * AmbientSpaceDim;
-  static constexpr int TangientParameterDim = 2 * (AmbientSpaceDim - 1);
-
-  LineParameterization<AmbientSpaceDim> line_parameterization;
-
-  using ParameterVector = Eigen::Matrix<double, ParameterDim, 1>;
-  ParameterVector x_plus_delta = ParameterVector::Zero();
-  line_parameterization.Plus(x_ptr, delta, x_plus_delta.data());
-
-  // Ensure the update maintains the norm for the line direction.
-  Eigen::Map<const ParameterVector> x(x_ptr);
-  const double dir_plus_delta_norm =
-      x_plus_delta.template tail<AmbientSpaceDim>().norm();
-  const double dir_norm = x.template tail<AmbientSpaceDim>().norm();
-  EXPECT_NEAR(dir_plus_delta_norm, dir_norm, kTolerance);
-
-  // Ensure the update of the origin point is perpendicular to the line
-  // direction.
-  const double dot_prod_val = x.template tail<AmbientSpaceDim>().dot(
-      x_plus_delta.template head<AmbientSpaceDim>() -
-      x.template head<AmbientSpaceDim>());
-  EXPECT_NEAR(dot_prod_val, 0.0, kTolerance);
-
-  // Autodiff jacobian at delta_x = 0.
-  AutoDiffLocalParameterization<LineParameterizationPlus<AmbientSpaceDim>,
-                                ParameterDim,
-                                TangientParameterDim>
-      autodiff_jacobian;
-
-  using JacobianMatrix = Eigen::
-      Matrix<double, ParameterDim, TangientParameterDim, Eigen::RowMajor>;
-  constexpr double kNaN = std::numeric_limits<double>::quiet_NaN();
-  JacobianMatrix jacobian_autodiff = JacobianMatrix::Constant(kNaN);
-  JacobianMatrix jacobian_analytic = JacobianMatrix::Constant(kNaN);
-
-  autodiff_jacobian.ComputeJacobian(x_ptr, jacobian_autodiff.data());
-  line_parameterization.ComputeJacobian(x_ptr, jacobian_analytic.data());
-
-  EXPECT_FALSE(jacobian_autodiff.hasNaN());
-  EXPECT_FALSE(jacobian_analytic.hasNaN());
-  EXPECT_TRUE(jacobian_autodiff.isApprox(jacobian_analytic))
-      << "auto diff:\n"
-      << jacobian_autodiff << "\n"
-      << "analytic diff:\n"
-      << jacobian_analytic;
-}
-
-TEST(LineParameterization, ZeroTest3D) {
-  double x[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 1.0};
-  double delta[4] = {0.0, 0.0, 0.0, 0.0};
-
-  LineParameterizationHelper<3>(x, delta);
-}
-
-TEST(LineParameterization, ZeroTest4D) {
-  double x[8] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0};
-  double delta[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
-
-  LineParameterizationHelper<4>(x, delta);
-}
-
-TEST(LineParameterization, ZeroOriginPointTest3D) {
-  double x[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 1.0};
-  double delta[4] = {0.0, 0.0, 1.0, 2.0};
-
-  LineParameterizationHelper<3>(x, delta);
-}
-
-TEST(LineParameterization, ZeroOriginPointTest4D) {
-  double x[8] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0};
-  double delta[6] = {0.0, 0.0, 0.0, 1.0, 2.0, 3.0};
-
-  LineParameterizationHelper<4>(x, delta);
-}
-
-TEST(LineParameterization, ZeroDirTest3D) {
-  double x[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 1.0};
-  double delta[4] = {3.0, 2.0, 0.0, 0.0};
-
-  LineParameterizationHelper<3>(x, delta);
-}
-
-TEST(LineParameterization, ZeroDirTest4D) {
-  double x[8] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0};
-  double delta[6] = {3.0, 2.0, 1.0, 0.0, 0.0, 0.0};
-
-  LineParameterizationHelper<4>(x, delta);
-}
-
-TEST(LineParameterization, AwayFromZeroTest3D1) {
-  Eigen::Matrix<double, 6, 1> x;
-  x.head<3>() << 1.54, 2.32, 1.34;
-  x.tail<3>() << 0.52, 0.25, 0.15;
-  x.tail<3>().normalize();
-
-  double delta[4] = {4.0, 7.0, 1.0, -0.5};
-
-  LineParameterizationHelper<3>(x.data(), delta);
-}
-
-TEST(LineParameterization, AwayFromZeroTest4D1) {
-  Eigen::Matrix<double, 8, 1> x;
-  x.head<4>() << 1.54, 2.32, 1.34, 3.23;
-  x.tail<4>() << 0.52, 0.25, 0.15, 0.45;
-  x.tail<4>().normalize();
-
-  double delta[6] = {4.0, 7.0, -3.0, 0.0, 1.0, -0.5};
-
-  LineParameterizationHelper<4>(x.data(), delta);
-}
-
-TEST(LineParameterization, AwayFromZeroTest3D2) {
-  Eigen::Matrix<double, 6, 1> x;
-  x.head<3>() << 7.54, -2.81, 8.63;
-  x.tail<3>() << 2.52, 5.25, 4.15;
-
-  double delta[4] = {4.0, 7.0, 1.0, -0.5};
-
-  LineParameterizationHelper<3>(x.data(), delta);
-}
-
-TEST(LineParameterization, AwayFromZeroTest4D2) {
-  Eigen::Matrix<double, 8, 1> x;
-  x.head<4>() << 7.54, -2.81, 8.63, 6.93;
-  x.tail<4>() << 2.52, 5.25, 4.15, 1.45;
-
-  double delta[6] = {4.0, 7.0, -3.0, 2.0, 1.0, -0.5};
-
-  LineParameterizationHelper<4>(x.data(), delta);
-}
-
-class ProductParameterizationTest : public ::testing::Test {
- protected:
-  void SetUp() final {
-    const int global_size1 = 5;
-    std::vector<int> constant_parameters1;
-    constant_parameters1.push_back(2);
-    param1_.reset(
-        new SubsetParameterization(global_size1, constant_parameters1));
-
-    const int global_size2 = 3;
-    std::vector<int> constant_parameters2;
-    constant_parameters2.push_back(0);
-    constant_parameters2.push_back(1);
-    param2_.reset(
-        new SubsetParameterization(global_size2, constant_parameters2));
-
-    const int global_size3 = 4;
-    std::vector<int> constant_parameters3;
-    constant_parameters3.push_back(1);
-    param3_.reset(
-        new SubsetParameterization(global_size3, constant_parameters3));
-
-    const int global_size4 = 2;
-    std::vector<int> constant_parameters4;
-    constant_parameters4.push_back(1);
-    param4_.reset(
-        new SubsetParameterization(global_size4, constant_parameters4));
-  }
-
-  std::unique_ptr<LocalParameterization> param1_;
-  std::unique_ptr<LocalParameterization> param2_;
-  std::unique_ptr<LocalParameterization> param3_;
-  std::unique_ptr<LocalParameterization> param4_;
-};
-
-TEST_F(ProductParameterizationTest, LocalAndGlobalSize2) {
-  LocalParameterization* param1 = param1_.release();
-  LocalParameterization* param2 = param2_.release();
-
-  ProductParameterization product_param(param1, param2);
-  EXPECT_EQ(product_param.LocalSize(),
-            param1->LocalSize() + param2->LocalSize());
-  EXPECT_EQ(product_param.GlobalSize(),
-            param1->GlobalSize() + param2->GlobalSize());
-}
-
-TEST_F(ProductParameterizationTest, LocalAndGlobalSize3) {
-  LocalParameterization* param1 = param1_.release();
-  LocalParameterization* param2 = param2_.release();
-  LocalParameterization* param3 = param3_.release();
-
-  ProductParameterization product_param(param1, param2, param3);
-  EXPECT_EQ(product_param.LocalSize(),
-            param1->LocalSize() + param2->LocalSize() + param3->LocalSize());
-  EXPECT_EQ(product_param.GlobalSize(),
-            param1->GlobalSize() + param2->GlobalSize() + param3->GlobalSize());
-}
-
-TEST_F(ProductParameterizationTest, LocalAndGlobalSize4) {
-  LocalParameterization* param1 = param1_.release();
-  LocalParameterization* param2 = param2_.release();
-  LocalParameterization* param3 = param3_.release();
-  LocalParameterization* param4 = param4_.release();
-
-  ProductParameterization product_param(param1, param2, param3, param4);
-  EXPECT_EQ(product_param.LocalSize(),
-            param1->LocalSize() + param2->LocalSize() + param3->LocalSize() +
-                param4->LocalSize());
-  EXPECT_EQ(product_param.GlobalSize(),
-            param1->GlobalSize() + param2->GlobalSize() + param3->GlobalSize() +
-                param4->GlobalSize());
-}
-
-TEST_F(ProductParameterizationTest, Plus) {
-  LocalParameterization* param1 = param1_.release();
-  LocalParameterization* param2 = param2_.release();
-  LocalParameterization* param3 = param3_.release();
-  LocalParameterization* param4 = param4_.release();
-
-  ProductParameterization product_param(param1, param2, param3, param4);
-  std::vector<double> x(product_param.GlobalSize(), 0.0);
-  std::vector<double> delta(product_param.LocalSize(), 0.0);
-  std::vector<double> x_plus_delta_expected(product_param.GlobalSize(), 0.0);
-  std::vector<double> x_plus_delta(product_param.GlobalSize(), 0.0);
-
-  for (int i = 0; i < product_param.GlobalSize(); ++i) {
-    x[i] = RandNormal();
-  }
-
-  for (int i = 0; i < product_param.LocalSize(); ++i) {
-    delta[i] = RandNormal();
-  }
-
-  EXPECT_TRUE(product_param.Plus(&x[0], &delta[0], &x_plus_delta_expected[0]));
-  int x_cursor = 0;
-  int delta_cursor = 0;
-
-  EXPECT_TRUE(param1->Plus(
-      &x[x_cursor], &delta[delta_cursor], &x_plus_delta[x_cursor]));
-  x_cursor += param1->GlobalSize();
-  delta_cursor += param1->LocalSize();
-
-  EXPECT_TRUE(param2->Plus(
-      &x[x_cursor], &delta[delta_cursor], &x_plus_delta[x_cursor]));
-  x_cursor += param2->GlobalSize();
-  delta_cursor += param2->LocalSize();
-
-  EXPECT_TRUE(param3->Plus(
-      &x[x_cursor], &delta[delta_cursor], &x_plus_delta[x_cursor]));
-  x_cursor += param3->GlobalSize();
-  delta_cursor += param3->LocalSize();
-
-  EXPECT_TRUE(param4->Plus(
-      &x[x_cursor], &delta[delta_cursor], &x_plus_delta[x_cursor]));
-  x_cursor += param4->GlobalSize();
-  delta_cursor += param4->LocalSize();
-
-  for (int i = 0; i < x.size(); ++i) {
-    EXPECT_EQ(x_plus_delta[i], x_plus_delta_expected[i]);
-  }
-}
-
-TEST_F(ProductParameterizationTest, ComputeJacobian) {
-  LocalParameterization* param1 = param1_.release();
-  LocalParameterization* param2 = param2_.release();
-  LocalParameterization* param3 = param3_.release();
-  LocalParameterization* param4 = param4_.release();
-
-  ProductParameterization product_param(param1, param2, param3, param4);
-  std::vector<double> x(product_param.GlobalSize(), 0.0);
-
-  for (int i = 0; i < product_param.GlobalSize(); ++i) {
-    x[i] = RandNormal();
-  }
-
-  Matrix jacobian =
-      Matrix::Random(product_param.GlobalSize(), product_param.LocalSize());
-  EXPECT_TRUE(product_param.ComputeJacobian(&x[0], jacobian.data()));
-  int x_cursor = 0;
-  int delta_cursor = 0;
-
-  Matrix jacobian1(param1->GlobalSize(), param1->LocalSize());
-  EXPECT_TRUE(param1->ComputeJacobian(&x[x_cursor], jacobian1.data()));
-  jacobian.block(
-      x_cursor, delta_cursor, param1->GlobalSize(), param1->LocalSize()) -=
-      jacobian1;
-  x_cursor += param1->GlobalSize();
-  delta_cursor += param1->LocalSize();
-
-  Matrix jacobian2(param2->GlobalSize(), param2->LocalSize());
-  EXPECT_TRUE(param2->ComputeJacobian(&x[x_cursor], jacobian2.data()));
-  jacobian.block(
-      x_cursor, delta_cursor, param2->GlobalSize(), param2->LocalSize()) -=
-      jacobian2;
-  x_cursor += param2->GlobalSize();
-  delta_cursor += param2->LocalSize();
-
-  Matrix jacobian3(param3->GlobalSize(), param3->LocalSize());
-  EXPECT_TRUE(param3->ComputeJacobian(&x[x_cursor], jacobian3.data()));
-  jacobian.block(
-      x_cursor, delta_cursor, param3->GlobalSize(), param3->LocalSize()) -=
-      jacobian3;
-  x_cursor += param3->GlobalSize();
-  delta_cursor += param3->LocalSize();
-
-  Matrix jacobian4(param4->GlobalSize(), param4->LocalSize());
-  EXPECT_TRUE(param4->ComputeJacobian(&x[x_cursor], jacobian4.data()));
-  jacobian.block(
-      x_cursor, delta_cursor, param4->GlobalSize(), param4->LocalSize()) -=
-      jacobian4;
-  x_cursor += param4->GlobalSize();
-  delta_cursor += param4->LocalSize();
-
-  EXPECT_NEAR(jacobian.norm(), 0.0, std::numeric_limits<double>::epsilon());
-}
-
-}  // namespace internal
-}  // namespace ceres
diff --git a/third_party/ceres/internal/ceres/loss_function.cc b/third_party/ceres/internal/ceres/loss_function.cc
index 353f29a..82563c8 100644
--- a/third_party/ceres/internal/ceres/loss_function.cc
+++ b/third_party/ceres/internal/ceres/loss_function.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -39,6 +39,8 @@
 
 namespace ceres {
 
+LossFunction::~LossFunction() = default;
+
 void TrivialLoss::Evaluate(double s, double rho[3]) const {
   rho[0] = s;
   rho[1] = 1.0;
@@ -161,7 +163,7 @@
 }
 
 void ScaledLoss::Evaluate(double s, double rho[3]) const {
-  if (rho_.get() == NULL) {
+  if (rho_.get() == nullptr) {
     rho[0] = a_ * s;
     rho[1] = a_;
     rho[2] = 0.0;
diff --git a/third_party/ceres/internal/ceres/loss_function_test.cc b/third_party/ceres/internal/ceres/loss_function_test.cc
index 638c0c9..1fd492b 100644
--- a/third_party/ceres/internal/ceres/loss_function_test.cc
+++ b/third_party/ceres/internal/ceres/loss_function_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -195,7 +195,7 @@
   // construction with the call to AssertLossFunctionIsValid() because Apple's
   // GCC is unable to eliminate the copy of ScaledLoss, which is not copyable.
   {
-    ScaledLoss scaled_loss(NULL, 6, TAKE_OWNERSHIP);
+    ScaledLoss scaled_loss(nullptr, 6, TAKE_OWNERSHIP);
     AssertLossFunctionIsValid(scaled_loss, 0.323);
   }
   {
@@ -265,17 +265,17 @@
     EXPECT_NEAR(rho[i], rho_gold[i], 1e-12);
   }
 
-  // Set to NULL
+  // Set to nullptr
   TrivialLoss loss_function4;
-  loss_function_wrapper.Reset(NULL, TAKE_OWNERSHIP);
+  loss_function_wrapper.Reset(nullptr, TAKE_OWNERSHIP);
   loss_function_wrapper.Evaluate(s, rho);
   loss_function4.Evaluate(s, rho_gold);
   for (int i = 0; i < 3; ++i) {
     EXPECT_NEAR(rho[i], rho_gold[i], 1e-12);
   }
 
-  // Set to NULL, not taking ownership
-  loss_function_wrapper.Reset(NULL, DO_NOT_TAKE_OWNERSHIP);
+  // Set to nullptr, not taking ownership
+  loss_function_wrapper.Reset(nullptr, DO_NOT_TAKE_OWNERSHIP);
   loss_function_wrapper.Evaluate(s, rho);
   loss_function4.Evaluate(s, rho_gold);
   for (int i = 0; i < 3; ++i) {
diff --git a/third_party/ceres/internal/ceres/low_rank_inverse_hessian.cc b/third_party/ceres/internal/ceres/low_rank_inverse_hessian.cc
index c73e5db..14559b6 100644
--- a/third_party/ceres/internal/ceres/low_rank_inverse_hessian.cc
+++ b/third_party/ceres/internal/ceres/low_rank_inverse_hessian.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,10 +35,7 @@
 #include "ceres/internal/eigen.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
-
-using std::list;
+namespace ceres::internal {
 
 // The (L)BFGS algorithm explicitly requires that the secant equation:
 //
@@ -117,8 +114,8 @@
   return true;
 }
 
-void LowRankInverseHessian::RightMultiply(const double* x_ptr,
-                                          double* y_ptr) const {
+void LowRankInverseHessian::RightMultiplyAndAccumulate(const double* x_ptr,
+                                                       double* y_ptr) const {
   ConstVectorRef gradient(x_ptr, num_parameters_);
   VectorRef search_direction(y_ptr, num_parameters_);
 
@@ -127,9 +124,7 @@
   const int num_corrections = indices_.size();
   Vector alpha(num_corrections);
 
-  for (list<int>::const_reverse_iterator it = indices_.rbegin();
-       it != indices_.rend();
-       ++it) {
+  for (auto it = indices_.rbegin(); it != indices_.rend(); ++it) {
     const double alpha_i = delta_x_history_.col(*it).dot(search_direction) /
                            delta_x_dot_delta_gradient_(*it);
     search_direction -= alpha_i * delta_gradient_history_.col(*it);
@@ -161,7 +156,7 @@
     //
     // The original origin of this rescaling trick is somewhat unclear, the
     // earliest reference appears to be Oren [1], however it is widely discussed
-    // without specific attributation in various texts including [2] (p143/178).
+    // without specific attribution in various texts including [2] (p143/178).
     //
     // [1] Oren S.S., Self-scaling variable metric (SSVM) algorithms Part II:
     //     Implementation and experiments, Management Science,
@@ -181,5 +176,4 @@
   }
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/low_rank_inverse_hessian.h b/third_party/ceres/internal/ceres/low_rank_inverse_hessian.h
index 0028a98..72f6f65 100644
--- a/third_party/ceres/internal/ceres/low_rank_inverse_hessian.h
+++ b/third_party/ceres/internal/ceres/low_rank_inverse_hessian.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -37,10 +37,10 @@
 #include <list>
 
 #include "ceres/internal/eigen.h"
+#include "ceres/internal/export.h"
 #include "ceres/linear_operator.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // LowRankInverseHessian is a positive definite approximation to the
 // Hessian using the limited memory variant of the
@@ -59,12 +59,12 @@
 // Byrd, R. H.; Nocedal, J.; Schnabel, R. B. (1994).
 // "Representations of Quasi-Newton Matrices and their use in
 // Limited Memory Methods". Mathematical Programming 63 (4):
-class LowRankInverseHessian : public LinearOperator {
+class CERES_NO_EXPORT LowRankInverseHessian final : public LinearOperator {
  public:
   // num_parameters is the row/column size of the Hessian.
   // max_num_corrections is the rank of the Hessian approximation.
   // use_approximate_eigenvalue_scaling controls whether the initial
-  // inverse Hessian used during Right/LeftMultiply() is scaled by
+  // inverse Hessian used during Right/LeftMultiplyAndAccumulate() is scaled by
   // the approximate eigenvalue of the true inverse Hessian at the
   // current operating point.
   // The approximation uses:
@@ -73,7 +73,6 @@
   LowRankInverseHessian(int num_parameters,
                         int max_num_corrections,
                         bool use_approximate_eigenvalue_scaling);
-  virtual ~LowRankInverseHessian() {}
 
   // Update the low rank approximation. delta_x is the change in the
   // domain of Hessian, and delta_gradient is the change in the
@@ -84,9 +83,9 @@
   bool Update(const Vector& delta_x, const Vector& delta_gradient);
 
   // LinearOperator interface
-  void RightMultiply(const double* x, double* y) const final;
-  void LeftMultiply(const double* x, double* y) const final {
-    RightMultiply(x, y);
+  void RightMultiplyAndAccumulate(const double* x, double* y) const final;
+  void LeftMultiplyAndAccumulate(const double* x, double* y) const final {
+    RightMultiplyAndAccumulate(x, y);
   }
   int num_rows() const final { return num_parameters_; }
   int num_cols() const final { return num_parameters_; }
@@ -102,7 +101,6 @@
   std::list<int> indices_;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_INTERNAL_LOW_RANK_INVERSE_HESSIAN_H_
diff --git a/third_party/ceres/internal/ceres/manifold.cc b/third_party/ceres/internal/ceres/manifold.cc
new file mode 100644
index 0000000..c4895fd
--- /dev/null
+++ b/third_party/ceres/internal/ceres/manifold.cc
@@ -0,0 +1,316 @@
+#include "ceres/manifold.h"
+
+#include <algorithm>
+#include <cmath>
+
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/fixed_array.h"
+#include "glog/logging.h"
+
+namespace ceres {
+namespace {
+
+struct CeresQuaternionOrder {
+  static constexpr int kW = 0;
+  static constexpr int kX = 1;
+  static constexpr int kY = 2;
+  static constexpr int kZ = 3;
+};
+
+struct EigenQuaternionOrder {
+  static constexpr int kW = 3;
+  static constexpr int kX = 0;
+  static constexpr int kY = 1;
+  static constexpr int kZ = 2;
+};
+
+template <typename Order>
+inline void QuaternionPlusImpl(const double* x,
+                               const double* delta,
+                               double* x_plus_delta) {
+  // x_plus_delta = QuaternionProduct(q_delta, x), where q_delta is the
+  // quaternion constructed from delta.
+  const double norm_delta = std::hypot(delta[0], delta[1], delta[2]);
+
+  if (std::fpclassify(norm_delta) == FP_ZERO) {
+    // No change in rotation: return the quaternion as is.
+    std::copy_n(x, 4, x_plus_delta);
+    return;
+  }
+
+  const double sin_delta_by_delta = (std::sin(norm_delta) / norm_delta);
+  double q_delta[4];
+  q_delta[Order::kW] = std::cos(norm_delta);
+  q_delta[Order::kX] = sin_delta_by_delta * delta[0];
+  q_delta[Order::kY] = sin_delta_by_delta * delta[1];
+  q_delta[Order::kZ] = sin_delta_by_delta * delta[2];
+
+  x_plus_delta[Order::kW] =
+      q_delta[Order::kW] * x[Order::kW] - q_delta[Order::kX] * x[Order::kX] -
+      q_delta[Order::kY] * x[Order::kY] - q_delta[Order::kZ] * x[Order::kZ];
+  x_plus_delta[Order::kX] =
+      q_delta[Order::kW] * x[Order::kX] + q_delta[Order::kX] * x[Order::kW] +
+      q_delta[Order::kY] * x[Order::kZ] - q_delta[Order::kZ] * x[Order::kY];
+  x_plus_delta[Order::kY] =
+      q_delta[Order::kW] * x[Order::kY] - q_delta[Order::kX] * x[Order::kZ] +
+      q_delta[Order::kY] * x[Order::kW] + q_delta[Order::kZ] * x[Order::kX];
+  x_plus_delta[Order::kZ] =
+      q_delta[Order::kW] * x[Order::kZ] + q_delta[Order::kX] * x[Order::kY] -
+      q_delta[Order::kY] * x[Order::kX] + q_delta[Order::kZ] * x[Order::kW];
+}
+
+template <typename Order>
+inline void QuaternionPlusJacobianImpl(const double* x, double* jacobian_ptr) {
+  Eigen::Map<Eigen::Matrix<double, 4, 3, Eigen::RowMajor>> jacobian(
+      jacobian_ptr);
+
+  jacobian(Order::kW, 0) = -x[Order::kX];
+  jacobian(Order::kW, 1) = -x[Order::kY];
+  jacobian(Order::kW, 2) = -x[Order::kZ];
+  jacobian(Order::kX, 0) = x[Order::kW];
+  jacobian(Order::kX, 1) = x[Order::kZ];
+  jacobian(Order::kX, 2) = -x[Order::kY];
+  jacobian(Order::kY, 0) = -x[Order::kZ];
+  jacobian(Order::kY, 1) = x[Order::kW];
+  jacobian(Order::kY, 2) = x[Order::kX];
+  jacobian(Order::kZ, 0) = x[Order::kY];
+  jacobian(Order::kZ, 1) = -x[Order::kX];
+  jacobian(Order::kZ, 2) = x[Order::kW];
+}
+
+template <typename Order>
+inline void QuaternionMinusImpl(const double* y,
+                                const double* x,
+                                double* y_minus_x) {
+  // ambient_y_minus_x = QuaternionProduct(y, -x) where -x is the conjugate of
+  // x.
+  double ambient_y_minus_x[4];
+  ambient_y_minus_x[Order::kW] =
+      y[Order::kW] * x[Order::kW] + y[Order::kX] * x[Order::kX] +
+      y[Order::kY] * x[Order::kY] + y[Order::kZ] * x[Order::kZ];
+  ambient_y_minus_x[Order::kX] =
+      -y[Order::kW] * x[Order::kX] + y[Order::kX] * x[Order::kW] -
+      y[Order::kY] * x[Order::kZ] + y[Order::kZ] * x[Order::kY];
+  ambient_y_minus_x[Order::kY] =
+      -y[Order::kW] * x[Order::kY] + y[Order::kX] * x[Order::kZ] +
+      y[Order::kY] * x[Order::kW] - y[Order::kZ] * x[Order::kX];
+  ambient_y_minus_x[Order::kZ] =
+      -y[Order::kW] * x[Order::kZ] - y[Order::kX] * x[Order::kY] +
+      y[Order::kY] * x[Order::kX] + y[Order::kZ] * x[Order::kW];
+
+  const double u_norm = std::hypot(ambient_y_minus_x[Order::kX],
+                                   ambient_y_minus_x[Order::kY],
+                                   ambient_y_minus_x[Order::kZ]);
+  if (std::fpclassify(u_norm) != FP_ZERO) {
+    const double theta = std::atan2(u_norm, ambient_y_minus_x[Order::kW]);
+    y_minus_x[0] = theta * ambient_y_minus_x[Order::kX] / u_norm;
+    y_minus_x[1] = theta * ambient_y_minus_x[Order::kY] / u_norm;
+    y_minus_x[2] = theta * ambient_y_minus_x[Order::kZ] / u_norm;
+  } else {
+    std::fill_n(y_minus_x, 3, 0.0);
+  }
+}
+
+template <typename Order>
+inline void QuaternionMinusJacobianImpl(const double* x, double* jacobian_ptr) {
+  Eigen::Map<Eigen::Matrix<double, 3, 4, Eigen::RowMajor>> jacobian(
+      jacobian_ptr);
+
+  jacobian(0, Order::kW) = -x[Order::kX];
+  jacobian(0, Order::kX) = x[Order::kW];
+  jacobian(0, Order::kY) = -x[Order::kZ];
+  jacobian(0, Order::kZ) = x[Order::kY];
+  jacobian(1, Order::kW) = -x[Order::kY];
+  jacobian(1, Order::kX) = x[Order::kZ];
+  jacobian(1, Order::kY) = x[Order::kW];
+  jacobian(1, Order::kZ) = -x[Order::kX];
+  jacobian(2, Order::kW) = -x[Order::kZ];
+  jacobian(2, Order::kX) = -x[Order::kY];
+  jacobian(2, Order::kY) = x[Order::kX];
+  jacobian(2, Order::kZ) = x[Order::kW];
+}
+
+}  // namespace
+
+Manifold::~Manifold() = default;
+
+bool Manifold::RightMultiplyByPlusJacobian(const double* x,
+                                           const int num_rows,
+                                           const double* ambient_matrix,
+                                           double* tangent_matrix) const {
+  const int tangent_size = TangentSize();
+  if (tangent_size == 0) {
+    return true;
+  }
+
+  const int ambient_size = AmbientSize();
+  Matrix plus_jacobian(ambient_size, tangent_size);
+  if (!PlusJacobian(x, plus_jacobian.data())) {
+    return false;
+  }
+
+  MatrixRef(tangent_matrix, num_rows, tangent_size) =
+      ConstMatrixRef(ambient_matrix, num_rows, ambient_size) * plus_jacobian;
+  return true;
+}
+
+SubsetManifold::SubsetManifold(const int size,
+                               const std::vector<int>& constant_parameters)
+
+    : tangent_size_(size - constant_parameters.size()),
+      constancy_mask_(size, false) {
+  if (constant_parameters.empty()) {
+    return;
+  }
+
+  std::vector<int> constant = constant_parameters;
+  std::sort(constant.begin(), constant.end());
+  CHECK_GE(constant.front(), 0) << "Indices indicating constant parameter must "
+                                   "be greater than equal to zero.";
+  CHECK_LT(constant.back(), size)
+      << "Indices indicating constant parameter must be less than the size "
+      << "of the parameter block.";
+  CHECK(std::adjacent_find(constant.begin(), constant.end()) == constant.end())
+      << "The set of constant parameters cannot contain duplicates";
+
+  for (auto index : constant_parameters) {
+    constancy_mask_[index] = true;
+  }
+}
+
+int SubsetManifold::AmbientSize() const { return constancy_mask_.size(); }
+
+int SubsetManifold::TangentSize() const { return tangent_size_; }
+
+bool SubsetManifold::Plus(const double* x,
+                          const double* delta,
+                          double* x_plus_delta) const {
+  const int ambient_size = AmbientSize();
+  for (int i = 0, j = 0; i < ambient_size; ++i) {
+    if (constancy_mask_[i]) {
+      x_plus_delta[i] = x[i];
+    } else {
+      x_plus_delta[i] = x[i] + delta[j++];
+    }
+  }
+  return true;
+}
+
+bool SubsetManifold::PlusJacobian(const double* /*x*/,
+                                  double* plus_jacobian) const {
+  if (tangent_size_ == 0) {
+    return true;
+  }
+
+  const int ambient_size = AmbientSize();
+  MatrixRef m(plus_jacobian, ambient_size, tangent_size_);
+  m.setZero();
+  for (int r = 0, c = 0; r < ambient_size; ++r) {
+    if (!constancy_mask_[r]) {
+      m(r, c++) = 1.0;
+    }
+  }
+  return true;
+}
+
+bool SubsetManifold::RightMultiplyByPlusJacobian(const double* /*x*/,
+                                                 const int num_rows,
+                                                 const double* ambient_matrix,
+                                                 double* tangent_matrix) const {
+  if (tangent_size_ == 0) {
+    return true;
+  }
+
+  const int ambient_size = AmbientSize();
+  for (int r = 0; r < num_rows; ++r) {
+    for (int idx = 0, c = 0; idx < ambient_size; ++idx) {
+      if (!constancy_mask_[idx]) {
+        tangent_matrix[r * tangent_size_ + c++] =
+            ambient_matrix[r * ambient_size + idx];
+      }
+    }
+  }
+  return true;
+}
+
+bool SubsetManifold::Minus(const double* y,
+                           const double* x,
+                           double* y_minus_x) const {
+  if (tangent_size_ == 0) {
+    return true;
+  }
+
+  const int ambient_size = AmbientSize();
+  for (int i = 0, j = 0; i < ambient_size; ++i) {
+    if (!constancy_mask_[i]) {
+      y_minus_x[j++] = y[i] - x[i];
+    }
+  }
+  return true;
+}
+
+bool SubsetManifold::MinusJacobian(const double* /*x*/,
+                                   double* minus_jacobian) const {
+  const int ambient_size = AmbientSize();
+  MatrixRef m(minus_jacobian, tangent_size_, ambient_size);
+  m.setZero();
+  for (int c = 0, r = 0; c < ambient_size; ++c) {
+    if (!constancy_mask_[c]) {
+      m(r++, c) = 1.0;
+    }
+  }
+  return true;
+}
+
+bool QuaternionManifold::Plus(const double* x,
+                              const double* delta,
+                              double* x_plus_delta) const {
+  QuaternionPlusImpl<CeresQuaternionOrder>(x, delta, x_plus_delta);
+  return true;
+}
+
+bool QuaternionManifold::PlusJacobian(const double* x, double* jacobian) const {
+  QuaternionPlusJacobianImpl<CeresQuaternionOrder>(x, jacobian);
+  return true;
+}
+
+bool QuaternionManifold::Minus(const double* y,
+                               const double* x,
+                               double* y_minus_x) const {
+  QuaternionMinusImpl<CeresQuaternionOrder>(y, x, y_minus_x);
+  return true;
+}
+
+bool QuaternionManifold::MinusJacobian(const double* x,
+                                       double* jacobian) const {
+  QuaternionMinusJacobianImpl<CeresQuaternionOrder>(x, jacobian);
+  return true;
+}
+
+bool EigenQuaternionManifold::Plus(const double* x,
+                                   const double* delta,
+                                   double* x_plus_delta) const {
+  QuaternionPlusImpl<EigenQuaternionOrder>(x, delta, x_plus_delta);
+  return true;
+}
+
+bool EigenQuaternionManifold::PlusJacobian(const double* x,
+                                           double* jacobian) const {
+  QuaternionPlusJacobianImpl<EigenQuaternionOrder>(x, jacobian);
+  return true;
+}
+
+bool EigenQuaternionManifold::Minus(const double* y,
+                                    const double* x,
+                                    double* y_minus_x) const {
+  QuaternionMinusImpl<EigenQuaternionOrder>(y, x, y_minus_x);
+  return true;
+}
+
+bool EigenQuaternionManifold::MinusJacobian(const double* x,
+                                            double* jacobian) const {
+  QuaternionMinusJacobianImpl<EigenQuaternionOrder>(x, jacobian);
+  return true;
+}
+
+}  // namespace ceres
diff --git a/third_party/ceres/internal/ceres/manifold_test.cc b/third_party/ceres/internal/ceres/manifold_test.cc
new file mode 100644
index 0000000..788e865
--- /dev/null
+++ b/third_party/ceres/internal/ceres/manifold_test.cc
@@ -0,0 +1,1055 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/manifold.h"
+
+#include <cmath>
+#include <limits>
+#include <memory>
+#include <utility>
+
+#include "Eigen/Geometry"
+#include "ceres/constants.h"
+#include "ceres/dynamic_numeric_diff_cost_function.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/port.h"
+#include "ceres/line_manifold.h"
+#include "ceres/manifold_test_utils.h"
+#include "ceres/numeric_diff_options.h"
+#include "ceres/product_manifold.h"
+#include "ceres/rotation.h"
+#include "ceres/sphere_manifold.h"
+#include "ceres/types.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace ceres::internal {
+
+constexpr int kNumTrials = 1000;
+constexpr double kTolerance = 1e-9;
+
+TEST(EuclideanManifold, StaticNormalFunctionTest) {
+  EuclideanManifold<3> manifold;
+  EXPECT_EQ(manifold.AmbientSize(), 3);
+  EXPECT_EQ(manifold.TangentSize(), 3);
+
+  Vector zero_tangent = Vector::Zero(manifold.TangentSize());
+  for (int trial = 0; trial < kNumTrials; ++trial) {
+    const Vector x = Vector::Random(manifold.AmbientSize());
+    const Vector y = Vector::Random(manifold.AmbientSize());
+    Vector delta = Vector::Random(manifold.TangentSize());
+    Vector x_plus_delta = Vector::Zero(manifold.AmbientSize());
+
+    manifold.Plus(x.data(), delta.data(), x_plus_delta.data());
+    EXPECT_NEAR((x_plus_delta - x - delta).norm() / (x + delta).norm(),
+                0.0,
+                kTolerance);
+
+    EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
+  }
+}
+
+TEST(EuclideanManifold, DynamicNormalFunctionTest) {
+  EuclideanManifold<DYNAMIC> manifold(3);
+  EXPECT_EQ(manifold.AmbientSize(), 3);
+  EXPECT_EQ(manifold.TangentSize(), 3);
+
+  Vector zero_tangent = Vector::Zero(manifold.TangentSize());
+  for (int trial = 0; trial < kNumTrials; ++trial) {
+    const Vector x = Vector::Random(manifold.AmbientSize());
+    const Vector y = Vector::Random(manifold.AmbientSize());
+    Vector delta = Vector::Random(manifold.TangentSize());
+    Vector x_plus_delta = Vector::Zero(manifold.AmbientSize());
+
+    manifold.Plus(x.data(), delta.data(), x_plus_delta.data());
+    EXPECT_NEAR((x_plus_delta - x - delta).norm() / (x + delta).norm(),
+                0.0,
+                kTolerance);
+
+    EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
+  }
+}
+
+TEST(SubsetManifold, EmptyConstantParameters) {
+  SubsetManifold manifold(3, {});
+  for (int trial = 0; trial < kNumTrials; ++trial) {
+    const Vector x = Vector::Random(3);
+    const Vector y = Vector::Random(3);
+    Vector delta = Vector::Random(3);
+    Vector x_plus_delta = Vector::Zero(3);
+
+    manifold.Plus(x.data(), delta.data(), x_plus_delta.data());
+    EXPECT_NEAR((x_plus_delta - x - delta).norm() / (x + delta).norm(),
+                0.0,
+                kTolerance);
+    EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
+  }
+}
+
+TEST(SubsetManifold, NegativeParameterIndexDeathTest) {
+  EXPECT_DEATH_IF_SUPPORTED(SubsetManifold manifold(2, {-1}),
+                            "greater than equal to zero");
+}
+
+TEST(SubsetManifold, GreaterThanSizeParameterIndexDeathTest) {
+  EXPECT_DEATH_IF_SUPPORTED(SubsetManifold manifold(2, {2}),
+                            "less than the size");
+}
+
+TEST(SubsetManifold, DuplicateParametersDeathTest) {
+  EXPECT_DEATH_IF_SUPPORTED(SubsetManifold manifold(2, {1, 1}), "duplicates");
+}
+
+TEST(SubsetManifold, NormalFunctionTest) {
+  const int kAmbientSize = 4;
+  const int kTangentSize = 3;
+
+  for (int i = 0; i < kAmbientSize; ++i) {
+    SubsetManifold manifold_with_ith_parameter_constant(kAmbientSize, {i});
+    for (int trial = 0; trial < kNumTrials; ++trial) {
+      const Vector x = Vector::Random(kAmbientSize);
+      Vector y = Vector::Random(kAmbientSize);
+      // x and y must have the same i^th coordinate to be on the manifold.
+      y[i] = x[i];
+      Vector delta = Vector::Random(kTangentSize);
+      Vector x_plus_delta = Vector::Zero(kAmbientSize);
+
+      x_plus_delta.setZero();
+      manifold_with_ith_parameter_constant.Plus(
+          x.data(), delta.data(), x_plus_delta.data());
+      int k = 0;
+      for (int j = 0; j < kAmbientSize; ++j) {
+        if (j == i) {
+          EXPECT_EQ(x_plus_delta[j], x[j]);
+        } else {
+          EXPECT_EQ(x_plus_delta[j], x[j] + delta[k++]);
+        }
+      }
+
+      EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(
+          manifold_with_ith_parameter_constant, x, delta, y, kTolerance);
+    }
+  }
+}
+
+TEST(ProductManifold, Size2) {
+  SubsetManifold manifold1(5, {2});
+  SubsetManifold manifold2(3, {0, 1});
+  ProductManifold<SubsetManifold, SubsetManifold> manifold(manifold1,
+                                                           manifold2);
+
+  EXPECT_EQ(manifold.AmbientSize(),
+            manifold1.AmbientSize() + manifold2.AmbientSize());
+  EXPECT_EQ(manifold.TangentSize(),
+            manifold1.TangentSize() + manifold2.TangentSize());
+}
+
+TEST(ProductManifold, Size3) {
+  SubsetManifold manifold1(5, {2});
+  SubsetManifold manifold2(3, {0, 1});
+  SubsetManifold manifold3(4, {1});
+
+  ProductManifold<SubsetManifold, SubsetManifold, SubsetManifold> manifold(
+      manifold1, manifold2, manifold3);
+
+  EXPECT_EQ(manifold.AmbientSize(),
+            manifold1.AmbientSize() + manifold2.AmbientSize() +
+                manifold3.AmbientSize());
+  EXPECT_EQ(manifold.TangentSize(),
+            manifold1.TangentSize() + manifold2.TangentSize() +
+                manifold3.TangentSize());
+}
+
+TEST(ProductManifold, Size4) {
+  SubsetManifold manifold1(5, {2});
+  SubsetManifold manifold2(3, {0, 1});
+  SubsetManifold manifold3(4, {1});
+  SubsetManifold manifold4(2, {0});
+
+  ProductManifold<SubsetManifold,
+                  SubsetManifold,
+                  SubsetManifold,
+                  SubsetManifold>
+      manifold(manifold1, manifold2, manifold3, manifold4);
+
+  EXPECT_EQ(manifold.AmbientSize(),
+            manifold1.AmbientSize() + manifold2.AmbientSize() +
+                manifold3.AmbientSize() + manifold4.AmbientSize());
+  EXPECT_EQ(manifold.TangentSize(),
+            manifold1.TangentSize() + manifold2.TangentSize() +
+                manifold3.TangentSize() + manifold4.TangentSize());
+}
+
+TEST(ProductManifold, NormalFunctionTest) {
+  SubsetManifold manifold1(5, {2});
+  SubsetManifold manifold2(3, {0, 1});
+  SubsetManifold manifold3(4, {1});
+  SubsetManifold manifold4(2, {0});
+
+  ProductManifold<SubsetManifold,
+                  SubsetManifold,
+                  SubsetManifold,
+                  SubsetManifold>
+      manifold(manifold1, manifold2, manifold3, manifold4);
+
+  for (int trial = 0; trial < kNumTrials; ++trial) {
+    const Vector x = Vector::Random(manifold.AmbientSize());
+    Vector delta = Vector::Random(manifold.TangentSize());
+    Vector x_plus_delta = Vector::Zero(manifold.AmbientSize());
+    Vector x_plus_delta_expected = Vector::Zero(manifold.AmbientSize());
+
+    EXPECT_TRUE(manifold.Plus(x.data(), delta.data(), x_plus_delta.data()));
+
+    int ambient_cursor = 0;
+    int tangent_cursor = 0;
+
+    EXPECT_TRUE(manifold1.Plus(&x[ambient_cursor],
+                               &delta[tangent_cursor],
+                               &x_plus_delta_expected[ambient_cursor]));
+    ambient_cursor += manifold1.AmbientSize();
+    tangent_cursor += manifold1.TangentSize();
+
+    EXPECT_TRUE(manifold2.Plus(&x[ambient_cursor],
+                               &delta[tangent_cursor],
+                               &x_plus_delta_expected[ambient_cursor]));
+    ambient_cursor += manifold2.AmbientSize();
+    tangent_cursor += manifold2.TangentSize();
+
+    EXPECT_TRUE(manifold3.Plus(&x[ambient_cursor],
+                               &delta[tangent_cursor],
+                               &x_plus_delta_expected[ambient_cursor]));
+    ambient_cursor += manifold3.AmbientSize();
+    tangent_cursor += manifold3.TangentSize();
+
+    EXPECT_TRUE(manifold4.Plus(&x[ambient_cursor],
+                               &delta[tangent_cursor],
+                               &x_plus_delta_expected[ambient_cursor]));
+    ambient_cursor += manifold4.AmbientSize();
+    tangent_cursor += manifold4.TangentSize();
+
+    for (int i = 0; i < x.size(); ++i) {
+      EXPECT_EQ(x_plus_delta[i], x_plus_delta_expected[i]);
+    }
+
+    EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(
+        manifold, x, delta, x_plus_delta, kTolerance);
+  }
+}
+
+TEST(ProductManifold, ZeroTangentSizeAndEuclidean) {
+  SubsetManifold subset_manifold(1, {0});
+  EuclideanManifold<2> euclidean_manifold;
+  ProductManifold<SubsetManifold, EuclideanManifold<2>> manifold(
+      subset_manifold, euclidean_manifold);
+  EXPECT_EQ(manifold.AmbientSize(), 3);
+  EXPECT_EQ(manifold.TangentSize(), 2);
+
+  for (int trial = 0; trial < kNumTrials; ++trial) {
+    const Vector x = Vector::Random(3);
+    Vector y = Vector::Random(3);
+    y[0] = x[0];
+    Vector delta = Vector::Random(2);
+    Vector x_plus_delta = Vector::Zero(3);
+
+    EXPECT_TRUE(manifold.Plus(x.data(), delta.data(), x_plus_delta.data()));
+
+    EXPECT_EQ(x_plus_delta[0], x[0]);
+    EXPECT_EQ(x_plus_delta[1], x[1] + delta[0]);
+    EXPECT_EQ(x_plus_delta[2], x[2] + delta[1]);
+
+    EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
+  }
+}
+
+TEST(ProductManifold, EuclideanAndZeroTangentSize) {
+  SubsetManifold subset_manifold(1, {0});
+  EuclideanManifold<2> euclidean_manifold;
+  ProductManifold<EuclideanManifold<2>, SubsetManifold> manifold(
+      euclidean_manifold, subset_manifold);
+  EXPECT_EQ(manifold.AmbientSize(), 3);
+  EXPECT_EQ(manifold.TangentSize(), 2);
+
+  for (int trial = 0; trial < kNumTrials; ++trial) {
+    const Vector x = Vector::Random(3);
+    Vector y = Vector::Random(3);
+    y[2] = x[2];
+    Vector delta = Vector::Random(2);
+    Vector x_plus_delta = Vector::Zero(3);
+
+    EXPECT_TRUE(manifold.Plus(x.data(), delta.data(), x_plus_delta.data()));
+    EXPECT_EQ(x_plus_delta[0], x[0] + delta[0]);
+    EXPECT_EQ(x_plus_delta[1], x[1] + delta[1]);
+    EXPECT_EQ(x_plus_delta[2], x[2]);
+    EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
+  }
+}
+
+struct CopyableManifold : ceres::Manifold {
+  CopyableManifold() = default;
+  CopyableManifold(const CopyableManifold&) = default;
+  // Do not care about copy-assignment
+  CopyableManifold& operator=(const CopyableManifold&) = delete;
+  // Not moveable
+  CopyableManifold(CopyableManifold&&) = delete;
+  CopyableManifold& operator=(CopyableManifold&&) = delete;
+
+  int AmbientSize() const override { return 3; }
+  int TangentSize() const override { return 2; }
+
+  bool Plus(const double* x,
+            const double* delta,
+            double* x_plus_delta) const override {
+    return true;
+  }
+
+  bool PlusJacobian(const double* x, double* jacobian) const override {
+    return true;
+  }
+
+  bool RightMultiplyByPlusJacobian(const double* x,
+                                   const int num_rows,
+                                   const double* ambient_matrix,
+                                   double* tangent_matrix) const override {
+    return true;
+  }
+
+  bool Minus(const double* y,
+             const double* x,
+             double* y_minus_x) const override {
+    return true;
+  }
+
+  bool MinusJacobian(const double* x, double* jacobian) const override {
+    return true;
+  }
+};
+
+struct MoveableManifold : ceres::Manifold {
+  MoveableManifold() = default;
+  MoveableManifold(MoveableManifold&&) = default;
+  // Do not care about move-assignment
+  MoveableManifold& operator=(MoveableManifold&&) = delete;
+  // Not copyable
+  MoveableManifold(const MoveableManifold&) = delete;
+  MoveableManifold& operator=(const MoveableManifold&) = delete;
+
+  int AmbientSize() const override { return 3; }
+  int TangentSize() const override { return 2; }
+
+  bool Plus(const double* x,
+            const double* delta,
+            double* x_plus_delta) const override {
+    return true;
+  }
+
+  bool PlusJacobian(const double* x, double* jacobian) const override {
+    return true;
+  }
+
+  bool RightMultiplyByPlusJacobian(const double* x,
+                                   const int num_rows,
+                                   const double* ambient_matrix,
+                                   double* tangent_matrix) const override {
+    return true;
+  }
+
+  bool Minus(const double* y,
+             const double* x,
+             double* y_minus_x) const override {
+    return true;
+  }
+
+  bool MinusJacobian(const double* x, double* jacobian) const override {
+    return true;
+  }
+};
+
+TEST(ProductManifold, CopyableOnly) {
+  ProductManifold<CopyableManifold, EuclideanManifold<3>> manifold1{
+      CopyableManifold{}, EuclideanManifold<3>{}};
+
+  CopyableManifold inner2;
+  ProductManifold<CopyableManifold, EuclideanManifold<3>> manifold2{
+      inner2, EuclideanManifold<3>{}};
+
+  EXPECT_EQ(manifold1.AmbientSize(), manifold2.AmbientSize());
+  EXPECT_EQ(manifold1.TangentSize(), manifold2.TangentSize());
+}
+
+TEST(ProductManifold, MoveableOnly) {
+  ProductManifold<MoveableManifold, EuclideanManifold<3>> manifold1{
+      MoveableManifold{}, EuclideanManifold<3>{}};
+
+  MoveableManifold inner2;
+  ProductManifold<MoveableManifold, EuclideanManifold<3>> manifold2{
+      std::move(inner2), EuclideanManifold<3>{}};
+
+  EXPECT_EQ(manifold1.AmbientSize(), manifold2.AmbientSize());
+  EXPECT_EQ(manifold1.TangentSize(), manifold2.TangentSize());
+}
+
+TEST(ProductManifold, CopyableOrMoveable) {
+  const CopyableManifold inner12{};
+  ProductManifold<MoveableManifold, CopyableManifold> manifold1{
+      MoveableManifold{}, inner12};
+
+  MoveableManifold inner21;
+  CopyableManifold inner22;
+  ProductManifold<MoveableManifold, CopyableManifold> manifold2{
+      std::move(inner21), inner22};
+
+  EXPECT_EQ(manifold1.AmbientSize(), manifold2.AmbientSize());
+  EXPECT_EQ(manifold1.TangentSize(), manifold2.TangentSize());
+}
+
+struct NonDefaultConstructibleManifold : ceres::Manifold {
+  NonDefaultConstructibleManifold(int, int) {}
+  int AmbientSize() const override { return 4; }
+  int TangentSize() const override { return 3; }
+
+  bool Plus(const double* x,
+            const double* delta,
+            double* x_plus_delta) const override {
+    return true;
+  }
+
+  bool PlusJacobian(const double* x, double* jacobian) const override {
+    return true;
+  }
+
+  bool RightMultiplyByPlusJacobian(const double* x,
+                                   const int num_rows,
+                                   const double* ambient_matrix,
+                                   double* tangent_matrix) const override {
+    return true;
+  }
+
+  bool Minus(const double* y,
+             const double* x,
+             double* y_minus_x) const override {
+    return true;
+  }
+
+  bool MinusJacobian(const double* x, double* jacobian) const override {
+    return true;
+  }
+};
+
+TEST(ProductManifold, NonDefaultConstructible) {
+  ProductManifold<NonDefaultConstructibleManifold, QuaternionManifold>
+      manifold1{NonDefaultConstructibleManifold{1, 2}, QuaternionManifold{}};
+  ProductManifold<QuaternionManifold, NonDefaultConstructibleManifold>
+      manifold2{QuaternionManifold{}, NonDefaultConstructibleManifold{1, 2}};
+
+  EXPECT_EQ(manifold1.AmbientSize(), manifold2.AmbientSize());
+  EXPECT_EQ(manifold1.TangentSize(), manifold2.TangentSize());
+}
+
+TEST(ProductManifold, DefaultConstructible) {
+  ProductManifold<EuclideanManifold<3>, SphereManifold<4>> manifold1;
+  ProductManifold<SphereManifold<4>, EuclideanManifold<3>> manifold2;
+
+  EXPECT_EQ(manifold1.AmbientSize(), manifold2.AmbientSize());
+  EXPECT_EQ(manifold1.TangentSize(), manifold2.TangentSize());
+}
+
+TEST(ProductManifold, Pointers) {
+  auto p = std::make_unique<QuaternionManifold>();
+  auto q = std::make_shared<EuclideanManifold<3>>();
+
+  ProductManifold<std::unique_ptr<Manifold>,
+                  EuclideanManifold<3>,
+                  std::shared_ptr<EuclideanManifold<3>>>
+      manifold1{
+          std::make_unique<QuaternionManifold>(), EuclideanManifold<3>{}, q};
+  ProductManifold<QuaternionManifold*,
+                  EuclideanManifold<3>,
+                  std::shared_ptr<EuclideanManifold<3>>>
+      manifold2{p.get(), EuclideanManifold<3>{}, q};
+
+  EXPECT_EQ(manifold1.AmbientSize(), manifold2.AmbientSize());
+  EXPECT_EQ(manifold1.TangentSize(), manifold2.TangentSize());
+}
+
+TEST(QuaternionManifold, PlusPiBy2) {
+  QuaternionManifold manifold;
+  Vector x = Vector::Zero(4);
+  x[0] = 1.0;
+
+  for (int i = 0; i < 3; ++i) {
+    Vector delta = Vector::Zero(3);
+    delta[i] = constants::pi / 2;
+    Vector x_plus_delta = Vector::Zero(4);
+    EXPECT_TRUE(manifold.Plus(x.data(), delta.data(), x_plus_delta.data()));
+
+    // Expect that the element corresponding to pi/2 is +/- 1. All other
+    // elements should be zero.
+    for (int j = 0; j < 4; ++j) {
+      if (i == (j - 1)) {
+        EXPECT_LT(std::abs(x_plus_delta[j]) - 1,
+                  std::numeric_limits<double>::epsilon())
+            << "\ndelta = " << delta.transpose()
+            << "\nx_plus_delta = " << x_plus_delta.transpose()
+            << "\n expected the " << j
+            << "th element of x_plus_delta to be +/- 1.";
+      } else {
+        EXPECT_LT(std::abs(x_plus_delta[j]),
+                  std::numeric_limits<double>::epsilon())
+            << "\ndelta = " << delta.transpose()
+            << "\nx_plus_delta = " << x_plus_delta.transpose()
+            << "\n expected the " << j << "th element of x_plus_delta to be 0.";
+      }
+    }
+    EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(
+        manifold, x, delta, x_plus_delta, kTolerance);
+  }
+}
+
+// Compute the expected value of QuaternionManifold::Plus via functions in
+// rotation.h and compares it to the one computed by QuaternionManifold::Plus.
+MATCHER_P2(QuaternionManifoldPlusIsCorrectAt, x, delta, "") {
+  // This multiplication by 2 is needed because AngleAxisToQuaternion uses
+  // |delta|/2 as the angle of rotation where as in the implementation of
+  // QuaternionManifold for historical reasons we use |delta|.
+  const Vector two_delta = delta * 2;
+  Vector delta_q(4);
+  AngleAxisToQuaternion(two_delta.data(), delta_q.data());
+
+  Vector expected(4);
+  QuaternionProduct(delta_q.data(), x.data(), expected.data());
+  Vector actual(4);
+  EXPECT_TRUE(arg.Plus(x.data(), delta.data(), actual.data()));
+
+  const double n = (actual - expected).norm();
+  const double d = expected.norm();
+  const double diffnorm = n / d;
+  if (diffnorm > kTolerance) {
+    *result_listener << "\nx: " << x.transpose()
+                     << "\ndelta: " << delta.transpose()
+                     << "\nexpected: " << expected.transpose()
+                     << "\nactual: " << actual.transpose()
+                     << "\ndiff: " << (expected - actual).transpose()
+                     << "\ndiffnorm : " << diffnorm;
+    return false;
+  }
+  return true;
+}
+
+static Vector RandomQuaternion() {
+  Vector x = Vector::Random(4);
+  x.normalize();
+  return x;
+}
+
+TEST(QuaternionManifold, GenericDelta) {
+  QuaternionManifold manifold;
+  for (int trial = 0; trial < kNumTrials; ++trial) {
+    const Vector x = RandomQuaternion();
+    const Vector y = RandomQuaternion();
+    Vector delta = Vector::Random(3);
+    EXPECT_THAT(manifold, QuaternionManifoldPlusIsCorrectAt(x, delta));
+    EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
+  }
+}
+
+TEST(QuaternionManifold, SmallDelta) {
+  QuaternionManifold manifold;
+  for (int trial = 0; trial < kNumTrials; ++trial) {
+    const Vector x = RandomQuaternion();
+    const Vector y = RandomQuaternion();
+    Vector delta = Vector::Random(3);
+    delta.normalize();
+    delta *= 1e-6;
+    EXPECT_THAT(manifold, QuaternionManifoldPlusIsCorrectAt(x, delta));
+    EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
+  }
+}
+
+TEST(QuaternionManifold, DeltaJustBelowPi) {
+  QuaternionManifold manifold;
+  for (int trial = 0; trial < kNumTrials; ++trial) {
+    const Vector x = RandomQuaternion();
+    const Vector y = RandomQuaternion();
+    Vector delta = Vector::Random(3);
+    delta.normalize();
+    delta *= (constants::pi - 1e-6);
+    EXPECT_THAT(manifold, QuaternionManifoldPlusIsCorrectAt(x, delta));
+    EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
+  }
+}
+
+// Compute the expected value of EigenQuaternionManifold::Plus using Eigen and
+// compares it to the one computed by QuaternionManifold::Plus.
+MATCHER_P2(EigenQuaternionManifoldPlusIsCorrectAt, x, delta, "") {
+  // This multiplication by 2 is needed because AngleAxisToQuaternion uses
+  // |delta|/2 as the angle of rotation where as in the implementation of
+  // Quaternion for historical reasons we use |delta|.
+  const Vector two_delta = delta * 2;
+  Vector delta_q(4);
+  AngleAxisToQuaternion(two_delta.data(), delta_q.data());
+  Eigen::Quaterniond delta_eigen_q(
+      delta_q[0], delta_q[1], delta_q[2], delta_q[3]);
+
+  Eigen::Map<const Eigen::Quaterniond> x_eigen_q(x.data());
+
+  Eigen::Quaterniond expected = delta_eigen_q * x_eigen_q;
+  double actual[4];
+  EXPECT_TRUE(arg.Plus(x.data(), delta.data(), actual));
+  Eigen::Map<Eigen::Quaterniond> actual_eigen_q(actual);
+
+  const double n = (actual_eigen_q.coeffs() - expected.coeffs()).norm();
+  const double d = expected.norm();
+  const double diffnorm = n / d;
+  if (diffnorm > kTolerance) {
+    *result_listener
+        << "\nx: " << x.transpose() << "\ndelta: " << delta.transpose()
+        << "\nexpected: " << expected.coeffs().transpose()
+        << "\nactual: " << actual_eigen_q.coeffs().transpose() << "\ndiff: "
+        << (expected.coeffs() - actual_eigen_q.coeffs()).transpose()
+        << "\ndiffnorm : " << diffnorm;
+    return false;
+  }
+  return true;
+}
+
+TEST(EigenQuaternionManifold, GenericDelta) {
+  EigenQuaternionManifold manifold;
+  for (int trial = 0; trial < kNumTrials; ++trial) {
+    const Vector x = RandomQuaternion();
+    const Vector y = RandomQuaternion();
+    Vector delta = Vector::Random(3);
+    EXPECT_THAT(manifold, EigenQuaternionManifoldPlusIsCorrectAt(x, delta));
+    EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
+  }
+}
+
+TEST(EigenQuaternionManifold, SmallDelta) {
+  EigenQuaternionManifold manifold;
+  for (int trial = 0; trial < kNumTrials; ++trial) {
+    const Vector x = RandomQuaternion();
+    const Vector y = RandomQuaternion();
+    Vector delta = Vector::Random(3);
+    delta.normalize();
+    delta *= 1e-6;
+    EXPECT_THAT(manifold, EigenQuaternionManifoldPlusIsCorrectAt(x, delta));
+    EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
+  }
+}
+
+TEST(EigenQuaternionManifold, DeltaJustBelowPi) {
+  EigenQuaternionManifold manifold;
+  for (int trial = 0; trial < kNumTrials; ++trial) {
+    const Vector x = RandomQuaternion();
+    const Vector y = RandomQuaternion();
+    Vector delta = Vector::Random(3);
+    delta.normalize();
+    delta *= (constants::pi - 1e-6);
+    EXPECT_THAT(manifold, EigenQuaternionManifoldPlusIsCorrectAt(x, delta));
+    EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
+  }
+}
+
+using Eigen::Vector2d;
+using Eigen::Vector3d;
+using Vector6d = Eigen::Matrix<double, 6, 1>;
+using Eigen::Vector4d;
+using Vector8d = Eigen::Matrix<double, 8, 1>;
+
+TEST(SphereManifold, ZeroTest) {
+  Vector4d x{0.0, 0.0, 0.0, 1.0};
+  Vector3d delta = Vector3d::Zero();
+  Vector4d y = Vector4d::Zero();
+
+  SphereManifold<4> manifold;
+  manifold.Plus(x.data(), delta.data(), y.data());
+  EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
+}
+
+TEST(SphereManifold, NearZeroTest1) {
+  Vector4d x{1e-5, 1e-5, 1e-5, 1.0};
+  x.normalize();
+  Vector3d delta{0.0, 1.0, 0.0};
+  Vector4d y = Vector4d::Zero();
+
+  SphereManifold<4> manifold;
+  manifold.Plus(x.data(), delta.data(), y.data());
+  EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
+}
+
+TEST(SphereManifold, NearZeroTest2) {
+  Vector4d x{0.01, 0.0, 0.0, 0.0};
+  Vector3d delta{0.0, 1.0, 0.0};
+  Vector4d y = Vector4d::Zero();
+  SphereManifold<4> manifold;
+  manifold.Plus(x.data(), delta.data(), y.data());
+  EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
+}
+
+TEST(SphereManifold, Plus2DTest) {
+  Eigen::Vector2d x{0.0, 1.0};
+  SphereManifold<2> manifold;
+
+  {
+    double delta[1]{constants::pi / 4};
+    Eigen::Vector2d y = Eigen::Vector2d::Zero();
+    EXPECT_TRUE(manifold.Plus(x.data(), delta, y.data()));
+    const Eigen::Vector2d gtY(std::sqrt(2.0) / 2.0, std::sqrt(2.0) / 2.0);
+    EXPECT_LT((y - gtY).norm(), kTolerance);
+  }
+
+  {
+    double delta[1]{constants::pi / 2};
+    Eigen::Vector2d y = Eigen::Vector2d::Zero();
+    EXPECT_TRUE(manifold.Plus(x.data(), delta, y.data()));
+    const Eigen::Vector2d gtY = Eigen::Vector2d::UnitX();
+    EXPECT_LT((y - gtY).norm(), kTolerance);
+  }
+
+  {
+    double delta[1]{constants::pi};
+    Eigen::Vector2d y = Eigen::Vector2d::Zero();
+    EXPECT_TRUE(manifold.Plus(x.data(), delta, y.data()));
+    const Eigen::Vector2d gtY = -Eigen::Vector2d::UnitY();
+    EXPECT_LT((y - gtY).norm(), kTolerance);
+  }
+
+  {
+    double delta[1]{2.0 * constants::pi};
+    Eigen::Vector2d y = Eigen::Vector2d::Zero();
+    EXPECT_TRUE(manifold.Plus(x.data(), delta, y.data()));
+    const Eigen::Vector2d gtY = Eigen::Vector2d::UnitY();
+    EXPECT_LT((y - gtY).norm(), kTolerance);
+  }
+}
+
+TEST(SphereManifold, Plus3DTest) {
+  Eigen::Vector3d x{0.0, 0.0, 1.0};
+  SphereManifold<3> manifold;
+
+  {
+    Eigen::Vector2d delta{constants::pi / 2, 0.0};
+    Eigen::Vector3d y = Eigen::Vector3d::Zero();
+    EXPECT_TRUE(manifold.Plus(x.data(), delta.data(), y.data()));
+    const Eigen::Vector3d gtY = Eigen::Vector3d::UnitX();
+    EXPECT_LT((y - gtY).norm(), kTolerance);
+  }
+
+  {
+    Eigen::Vector2d delta{constants::pi, 0.0};
+    Eigen::Vector3d y = Eigen::Vector3d::Zero();
+    EXPECT_TRUE(manifold.Plus(x.data(), delta.data(), y.data()));
+    const Eigen::Vector3d gtY = -Eigen::Vector3d::UnitZ();
+    EXPECT_LT((y - gtY).norm(), kTolerance);
+  }
+
+  {
+    Eigen::Vector2d delta{2.0 * constants::pi, 0.0};
+    Eigen::Vector3d y = Eigen::Vector3d::Zero();
+    EXPECT_TRUE(manifold.Plus(x.data(), delta.data(), y.data()));
+    const Eigen::Vector3d gtY = Eigen::Vector3d::UnitZ();
+    EXPECT_LT((y - gtY).norm(), kTolerance);
+  }
+
+  {
+    Eigen::Vector2d delta{0.0, constants::pi / 2};
+    Eigen::Vector3d y = Eigen::Vector3d::Zero();
+    EXPECT_TRUE(manifold.Plus(x.data(), delta.data(), y.data()));
+    const Eigen::Vector3d gtY = Eigen::Vector3d::UnitY();
+    EXPECT_LT((y - gtY).norm(), kTolerance);
+  }
+
+  {
+    Eigen::Vector2d delta{0.0, constants::pi};
+    Eigen::Vector3d y = Eigen::Vector3d::Zero();
+    EXPECT_TRUE(manifold.Plus(x.data(), delta.data(), y.data()));
+    const Eigen::Vector3d gtY = -Eigen::Vector3d::UnitZ();
+    EXPECT_LT((y - gtY).norm(), kTolerance);
+  }
+
+  {
+    Eigen::Vector2d delta{0.0, 2.0 * constants::pi};
+    Eigen::Vector3d y = Eigen::Vector3d::Zero();
+    EXPECT_TRUE(manifold.Plus(x.data(), delta.data(), y.data()));
+    const Eigen::Vector3d gtY = Eigen::Vector3d::UnitZ();
+    EXPECT_LT((y - gtY).norm(), kTolerance);
+  }
+
+  {
+    Eigen::Vector2d delta =
+        Eigen::Vector2d(1, 1).normalized() * constants::pi / 2;
+    Eigen::Vector3d y = Eigen::Vector3d::Zero();
+    EXPECT_TRUE(manifold.Plus(x.data(), delta.data(), y.data()));
+    const Eigen::Vector3d gtY(std::sqrt(2.0) / 2.0, std::sqrt(2.0) / 2.0, 0.0);
+    EXPECT_LT((y - gtY).norm(), kTolerance);
+  }
+
+  {
+    Eigen::Vector2d delta = Eigen::Vector2d(1, 1).normalized() * constants::pi;
+    Eigen::Vector3d y = Eigen::Vector3d::Zero();
+    EXPECT_TRUE(manifold.Plus(x.data(), delta.data(), y.data()));
+    const Eigen::Vector3d gtY = -Eigen::Vector3d::UnitZ();
+    EXPECT_LT((y - gtY).norm(), kTolerance);
+  }
+}
+
+TEST(SphereManifold, Minus2DTest) {
+  Eigen::Vector2d x{1.0, 0.0};
+  SphereManifold<2> manifold;
+
+  {
+    double delta[1];
+    const Eigen::Vector2d y(std::sqrt(2.0) / 2.0, std::sqrt(2.0) / 2.0);
+    const double gtDelta{constants::pi / 4};
+    EXPECT_TRUE(manifold.Minus(y.data(), x.data(), delta));
+    EXPECT_LT(std::abs(delta[0] - gtDelta), kTolerance);
+  }
+
+  {
+    double delta[1];
+    const Eigen::Vector2d y(-1, 0);
+    const double gtDelta{constants::pi};
+    EXPECT_TRUE(manifold.Minus(y.data(), x.data(), delta));
+    EXPECT_LT(std::abs(delta[0] - gtDelta), kTolerance);
+  }
+}
+
+TEST(SphereManifold, Minus3DTest) {
+  Eigen::Vector3d x{1.0, 0.0, 0.0};
+  SphereManifold<3> manifold;
+
+  {
+    Eigen::Vector2d delta;
+    const Eigen::Vector3d y(std::sqrt(2.0) / 2.0, 0.0, std::sqrt(2.0) / 2.0);
+    const Eigen::Vector2d gtDelta(constants::pi / 4, 0.0);
+    EXPECT_TRUE(manifold.Minus(y.data(), x.data(), delta.data()));
+    EXPECT_LT((delta - gtDelta).norm(), kTolerance);
+  }
+
+  {
+    Eigen::Vector2d delta;
+    const Eigen::Vector3d y(-1, 0, 0);
+    const Eigen::Vector2d gtDelta(0.0, constants::pi);
+    EXPECT_TRUE(manifold.Minus(y.data(), x.data(), delta.data()));
+    EXPECT_LT((delta - gtDelta).norm(), kTolerance);
+  }
+}
+
+TEST(SphereManifold, DeathTests) {
+  EXPECT_DEATH_IF_SUPPORTED(SphereManifold<Eigen::Dynamic> x(1), "size");
+}
+
+TEST(SphereManifold, NormalFunctionTest) {
+  SphereManifold<4> manifold;
+  EXPECT_EQ(manifold.AmbientSize(), 4);
+  EXPECT_EQ(manifold.TangentSize(), 3);
+
+  Vector zero_tangent = Vector::Zero(manifold.TangentSize());
+  for (int trial = 0; trial < kNumTrials; ++trial) {
+    const Vector x = Vector::Random(manifold.AmbientSize());
+    Vector y = Vector::Random(manifold.AmbientSize());
+    Vector delta = Vector::Random(manifold.TangentSize());
+
+    if (x.norm() == 0.0 || y.norm() == 0.0) {
+      continue;
+    }
+
+    // X and y need to have the same length.
+    y *= x.norm() / y.norm();
+
+    EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
+  }
+}
+
+TEST(SphereManifold, NormalFunctionTestDynamic) {
+  SphereManifold<ceres::DYNAMIC> manifold(5);
+  EXPECT_EQ(manifold.AmbientSize(), 5);
+  EXPECT_EQ(manifold.TangentSize(), 4);
+
+  Vector zero_tangent = Vector::Zero(manifold.TangentSize());
+  for (int trial = 0; trial < kNumTrials; ++trial) {
+    const Vector x = Vector::Random(manifold.AmbientSize());
+    Vector y = Vector::Random(manifold.AmbientSize());
+    Vector delta = Vector::Random(manifold.TangentSize());
+
+    if (x.norm() == 0.0 || y.norm() == 0.0) {
+      continue;
+    }
+
+    // X and y need to have the same length.
+    y *= x.norm() / y.norm();
+
+    EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
+  }
+}
+
+TEST(LineManifold, ZeroTest3D) {
+  const Vector6d x = Vector6d::Unit(5);
+  const Vector4d delta = Vector4d::Zero();
+  Vector6d y = Vector6d::Zero();
+
+  LineManifold<3> manifold;
+  EXPECT_TRUE(manifold.Plus(x.data(), delta.data(), y.data()));
+  EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
+}
+
+TEST(LineManifold, ZeroTest4D) {
+  const Vector8d x = Vector8d::Unit(7);
+  const Vector6d delta = Vector6d::Zero();
+  Vector8d y = Vector8d::Zero();
+
+  LineManifold<4> manifold;
+  EXPECT_TRUE(manifold.Plus(x.data(), delta.data(), y.data()));
+  EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
+}
+
+TEST(LineManifold, ZeroOriginPointTest3D) {
+  const Vector6d x = Vector6d::Unit(5);
+  Vector4d delta;
+  delta << 0.0, 0.0, 1.0, 2.0;
+  Vector6d y = Vector6d::Zero();
+
+  LineManifold<3> manifold;
+  EXPECT_TRUE(manifold.Plus(x.data(), delta.data(), y.data()));
+  EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
+}
+
+TEST(LineManifold, ZeroOriginPointTest4D) {
+  const Vector8d x = Vector8d::Unit(7);
+  Vector6d delta;
+  delta << 0.0, 0.0, 0.0, 0.5, 1.0, 1.5;
+  Vector8d y = Vector8d::Zero();
+
+  LineManifold<4> manifold;
+  EXPECT_TRUE(manifold.Plus(x.data(), delta.data(), y.data()));
+  EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
+}
+
+TEST(LineManifold, ZeroDirTest3D) {
+  Vector6d x = Vector6d::Unit(5);
+  Vector4d delta;
+  delta << 3.0, 2.0, 0.0, 0.0;
+  Vector6d y = Vector6d::Zero();
+
+  LineManifold<3> manifold;
+  EXPECT_TRUE(manifold.Plus(x.data(), delta.data(), y.data()));
+  EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
+}
+
+TEST(LineManifold, ZeroDirTest4D) {
+  Vector8d x = Vector8d::Unit(7);
+  Vector6d delta;
+  delta << 3.0, 2.0, 1.0, 0.0, 0.0, 0.0;
+  Vector8d y = Vector8d::Zero();
+
+  LineManifold<4> manifold;
+  EXPECT_TRUE(manifold.Plus(x.data(), delta.data(), y.data()));
+  EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
+}
+
+TEST(LineManifold, Plus) {
+  Vector6d x = Vector6d::Unit(5);
+  LineManifold<3> manifold;
+
+  {
+    Vector4d delta{0.0, 2.0, constants::pi / 2, 0.0};
+    Vector6d y = Vector6d::Random();
+    EXPECT_TRUE(manifold.Plus(x.data(), delta.data(), y.data()));
+    Vector6d gtY;
+    gtY << 2.0 * Vector3d::UnitY(), Vector3d::UnitX();
+    EXPECT_LT((y - gtY).norm(), kTolerance);
+  }
+
+  {
+    Vector4d delta{3.0, 0.0, 0.0, constants::pi / 2};
+    Vector6d y = Vector6d::Zero();
+    EXPECT_TRUE(manifold.Plus(x.data(), delta.data(), y.data()));
+    Vector6d gtY;
+    gtY << 3.0 * Vector3d::UnitX(), Vector3d::UnitY();
+    EXPECT_LT((y - gtY).norm(), kTolerance);
+  }
+
+  {
+    Vector4d delta;
+    delta << Vector2d(1.0, 2.0),
+        Vector2d(1, 1).normalized() * constants::pi / 2;
+    Vector6d y = Vector6d::Zero();
+    EXPECT_TRUE(manifold.Plus(x.data(), delta.data(), y.data()));
+    Vector6d gtY;
+    gtY << Vector3d(1.0, 2.0, 0.0),
+        Vector3d(std::sqrt(2.0) / 2.0, std::sqrt(2.0) / 2.0, 0.0);
+    EXPECT_LT((y - gtY).norm(), kTolerance);
+  }
+}
+
+TEST(LineManifold, NormalFunctionTest) {
+  LineManifold<3> manifold;
+  EXPECT_EQ(manifold.AmbientSize(), 6);
+  EXPECT_EQ(manifold.TangentSize(), 4);
+
+  Vector zero_tangent = Vector::Zero(manifold.TangentSize());
+  for (int trial = 0; trial < kNumTrials; ++trial) {
+    Vector x = Vector::Random(manifold.AmbientSize());
+    Vector y = Vector::Random(manifold.AmbientSize());
+    Vector delta = Vector::Random(manifold.TangentSize());
+
+    if (x.tail<3>().norm() == 0.0) {
+      continue;
+    }
+
+    x.tail<3>().normalize();
+    manifold.Plus(x.data(), delta.data(), y.data());
+
+    EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
+  }
+}
+
+TEST(LineManifold, NormalFunctionTestDynamic) {
+  LineManifold<ceres::DYNAMIC> manifold(3);
+  EXPECT_EQ(manifold.AmbientSize(), 6);
+  EXPECT_EQ(manifold.TangentSize(), 4);
+
+  Vector zero_tangent = Vector::Zero(manifold.TangentSize());
+  for (int trial = 0; trial < kNumTrials; ++trial) {
+    Vector x = Vector::Random(manifold.AmbientSize());
+    Vector y = Vector::Random(manifold.AmbientSize());
+    Vector delta = Vector::Random(manifold.TangentSize());
+
+    if (x.tail<3>().norm() == 0.0) {
+      continue;
+    }
+
+    x.tail<3>().normalize();
+    manifold.Plus(x.data(), delta.data(), y.data());
+
+    EXPECT_THAT_MANIFOLD_INVARIANTS_HOLD(manifold, x, delta, y, kTolerance);
+  }
+}
+
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/map_util.h b/third_party/ceres/internal/ceres/map_util.h
index 6e310f8..aee2bf5 100644
--- a/third_party/ceres/internal/ceres/map_util.h
+++ b/third_party/ceres/internal/ceres/map_util.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,7 +35,7 @@
 
 #include <utility>
 
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 #include "glog/logging.h"
 
 namespace ceres {
@@ -121,7 +121,7 @@
 void InsertOrDie(Collection* const collection,
                  const typename Collection::value_type::first_type& key,
                  const typename Collection::value_type::second_type& data) {
-  typedef typename Collection::value_type value_type;
+  using value_type = typename Collection::value_type;
   CHECK(collection->insert(value_type(key, data)).second)
       << "duplicate key: " << key;
 }
diff --git a/third_party/ceres/internal/ceres/miniglog/glog/logging.h b/third_party/ceres/internal/ceres/miniglog/glog/logging.h
index 98d2b68..5604bd4 100644
--- a/third_party/ceres/internal/ceres/miniglog/glog/logging.h
+++ b/third_party/ceres/internal/ceres/miniglog/glog/logging.h
@@ -69,7 +69,7 @@
 // The following CHECK macros are defined:
 //
 //   CHECK(condition)        - fails if condition is false and logs condition.
-//   CHECK_NOTNULL(variable) - fails if the variable is NULL.
+//   CHECK_NOTNULL(variable) - fails if the variable is nullptr.
 //
 // The following binary check macros are also defined :
 //
@@ -105,12 +105,8 @@
 #include <string>
 #include <vector>
 
-// For appropriate definition of CERES_EXPORT macro.
-// clang-format off
-#include "ceres/internal/port.h"
-// clang-format on
-
 #include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 
 // Log severity level constants.
 // clang-format off
@@ -124,7 +120,7 @@
 
 namespace google {
 
-typedef int LogSeverity;
+using LogSeverity = int;
 // clang-format off
 const int INFO    = ::INFO;
 const int WARNING = ::WARNING;
@@ -138,7 +134,7 @@
 // This implementation is not thread safe.
 class CERES_EXPORT LogSink {
  public:
-  virtual ~LogSink() {}
+  virtual ~LogSink() = default;
   virtual void send(LogSeverity severity,
                     const char* full_filename,
                     const char* base_filename,
@@ -152,7 +148,7 @@
 // Global set of log sinks. The actual object is defined in logging.cc.
 extern CERES_EXPORT std::set<LogSink*> log_sinks_global;
 
-inline void InitGoogleLogging(char* argv) {
+inline void InitGoogleLogging(const char* /* argv */) {
   // Do nothing; this is ignored.
 }
 
@@ -294,7 +290,6 @@
 // is not used" and "statement has no effect".
 class CERES_EXPORT LoggerVoidify {
  public:
-  LoggerVoidify() {}
   // This has to be an operator with a precedence lower than << but
   // higher than ?:
   void operator&(const std::ostream& s) {}
@@ -407,7 +402,7 @@
 // and smart pointers.
 template <typename T>
 T& CheckNotNullCommon(const char* file, int line, const char* names, T& t) {
-  if (t == NULL) {
+  if (t == nullptr) {
     LogMessageFatal(file, line, std::string(names));
   }
   return t;
@@ -425,17 +420,17 @@
 
 // Check that a pointer is not null.
 #define CHECK_NOTNULL(val) \
-  CheckNotNull(__FILE__, __LINE__, "'" #val "' Must be non NULL", (val))
+  CheckNotNull(__FILE__, __LINE__, "'" #val "' Must be non nullptr", (val))
 
 #ifndef NDEBUG
 // Debug only version of CHECK_NOTNULL
 #define DCHECK_NOTNULL(val) \
-  CheckNotNull(__FILE__, __LINE__, "'" #val "' Must be non NULL", (val))
+  CheckNotNull(__FILE__, __LINE__, "'" #val "' Must be non nullptr", (val))
 #else
 // Optimized version - generates no code.
 #define DCHECK_NOTNULL(val) \
   if (false)                \
-  CheckNotNull(__FILE__, __LINE__, "'" #val "' Must be non NULL", (val))
+  CheckNotNull(__FILE__, __LINE__, "'" #val "' Must be non nullptr", (val))
 #endif  // NDEBUG
 
 #include "ceres/internal/reenable_warnings.h"
diff --git a/third_party/ceres/internal/ceres/minimizer.cc b/third_party/ceres/internal/ceres/minimizer.cc
index b96e0c9..5317388 100644
--- a/third_party/ceres/internal/ceres/minimizer.cc
+++ b/third_party/ceres/internal/ceres/minimizer.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -30,28 +30,29 @@
 
 #include "ceres/minimizer.h"
 
+#include <memory>
+
 #include "ceres/line_search_minimizer.h"
 #include "ceres/trust_region_minimizer.h"
 #include "ceres/types.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
-Minimizer* Minimizer::Create(MinimizerType minimizer_type) {
+std::unique_ptr<Minimizer> Minimizer::Create(MinimizerType minimizer_type) {
   if (minimizer_type == TRUST_REGION) {
-    return new TrustRegionMinimizer;
+    return std::make_unique<TrustRegionMinimizer>();
   }
 
   if (minimizer_type == LINE_SEARCH) {
-    return new LineSearchMinimizer;
+    return std::make_unique<LineSearchMinimizer>();
   }
 
   LOG(FATAL) << "Unknown minimizer_type: " << minimizer_type;
-  return NULL;
+  return nullptr;
 }
 
-Minimizer::~Minimizer() {}
+Minimizer::~Minimizer() = default;
 
 bool Minimizer::RunCallbacks(const Minimizer::Options& options,
                              const IterationSummary& iteration_summary,
@@ -87,5 +88,4 @@
   return false;
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/minimizer.h b/third_party/ceres/internal/ceres/minimizer.h
index 246550d..be7290e 100644
--- a/third_party/ceres/internal/ceres/minimizer.h
+++ b/third_party/ceres/internal/ceres/minimizer.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,21 +35,22 @@
 #include <string>
 #include <vector>
 
-#include "ceres/internal/port.h"
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 #include "ceres/iteration_callback.h"
 #include "ceres/solver.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 class Evaluator;
 class SparseMatrix;
 class TrustRegionStrategy;
 class CoordinateDescentMinimizer;
 class LinearSolver;
+class ContextImpl;
 
 // Interface for non-linear least squares solvers.
-class CERES_EXPORT_INTERNAL Minimizer {
+class CERES_NO_EXPORT Minimizer {
  public:
   // Options struct to control the behaviour of the Minimizer. Please
   // see solver.h for detailed information about the meaning and
@@ -113,6 +114,7 @@
     int max_num_iterations;
     double max_solver_time_in_seconds;
     int num_threads;
+    ContextImpl* context = nullptr;
 
     // Number of times the linear solver should be retried in case of
     // numerical failure. The retries are done by exponentially scaling up
@@ -178,7 +180,7 @@
     std::shared_ptr<CoordinateDescentMinimizer> inner_iteration_minimizer;
   };
 
-  static Minimizer* Create(MinimizerType minimizer_type);
+  static std::unique_ptr<Minimizer> Create(MinimizerType minimizer_type);
   static bool RunCallbacks(const Options& options,
                            const IterationSummary& iteration_summary,
                            Solver::Summary* summary);
@@ -192,7 +194,8 @@
                         Solver::Summary* summary) = 0;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_MINIMIZER_H_
diff --git a/third_party/ceres/internal/ceres/minimizer_test.cc b/third_party/ceres/internal/ceres/minimizer_test.cc
index 3de4abe..10fb9e5 100644
--- a/third_party/ceres/internal/ceres/minimizer_test.cc
+++ b/third_party/ceres/internal/ceres/minimizer_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -34,12 +34,10 @@
 #include "ceres/solver.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 class FakeIterationCallback : public IterationCallback {
  public:
-  virtual ~FakeIterationCallback() {}
   CallbackReturnType operator()(const IterationSummary& summary) final {
     return SOLVER_CONTINUE;
   }
@@ -62,7 +60,6 @@
 
 class AbortingIterationCallback : public IterationCallback {
  public:
-  virtual ~AbortingIterationCallback() {}
   CallbackReturnType operator()(const IterationSummary& summary) final {
     return SOLVER_ABORT;
   }
@@ -80,7 +77,6 @@
 
 class SucceedingIterationCallback : public IterationCallback {
  public:
-  virtual ~SucceedingIterationCallback() {}
   CallbackReturnType operator()(const IterationSummary& summary) final {
     return SOLVER_TERMINATE_SUCCESSFULLY;
   }
@@ -97,5 +93,4 @@
             "User callback returned SOLVER_TERMINATE_SUCCESSFULLY.");
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/normal_prior.cc b/third_party/ceres/internal/ceres/normal_prior.cc
index 4a62132..c8a7a27 100644
--- a/third_party/ceres/internal/ceres/normal_prior.cc
+++ b/third_party/ceres/internal/ceres/normal_prior.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -31,6 +31,7 @@
 #include "ceres/normal_prior.h"
 
 #include <cstddef>
+#include <utility>
 #include <vector>
 
 #include "ceres/internal/eigen.h"
@@ -39,7 +40,7 @@
 
 namespace ceres {
 
-NormalPrior::NormalPrior(const Matrix& A, const Vector& b) : A_(A), b_(b) {
+NormalPrior::NormalPrior(const Matrix& A, Vector b) : A_(A), b_(std::move(b)) {
   CHECK_GT(b_.rows(), 0);
   CHECK_GT(A_.rows(), 0);
   CHECK_EQ(b_.rows(), A.cols());
@@ -54,9 +55,9 @@
   VectorRef r(residuals, num_residuals());
   // The following line should read
   // r = A_ * (p - b_);
-  // The extra eval is to get around a bug in the eigen library.
+  // The extra eval is to get around a bug in the Eigen library.
   r = A_ * (p - b_).eval();
-  if ((jacobians != NULL) && (jacobians[0] != NULL)) {
+  if ((jacobians != nullptr) && (jacobians[0] != nullptr)) {
     MatrixRef(jacobians[0], num_residuals(), parameter_block_sizes()[0]) = A_;
   }
   return true;
diff --git a/third_party/ceres/internal/ceres/normal_prior_test.cc b/third_party/ceres/internal/ceres/normal_prior_test.cc
index 518c18e..369ff27 100644
--- a/third_party/ceres/internal/ceres/normal_prior_test.cc
+++ b/third_party/ceres/internal/ceres/normal_prior_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -30,46 +30,31 @@
 
 #include "ceres/normal_prior.h"
 
+#include <algorithm>
 #include <cstddef>
+#include <random>
 
 #include "ceres/internal/eigen.h"
-#include "ceres/random.h"
 #include "gtest/gtest.h"
 
 namespace ceres {
 namespace internal {
 
-namespace {
-
-void RandomVector(Vector* v) {
-  for (int r = 0; r < v->rows(); ++r) (*v)[r] = 2 * RandDouble() - 1;
-}
-
-void RandomMatrix(Matrix* m) {
-  for (int r = 0; r < m->rows(); ++r) {
-    for (int c = 0; c < m->cols(); ++c) {
-      (*m)(r, c) = 2 * RandDouble() - 1;
-    }
-  }
-}
-
-}  // namespace
-
 TEST(NormalPriorTest, ResidualAtRandomPosition) {
-  srand(5);
-
+  std::mt19937 prng;
+  std::uniform_real_distribution<double> distribution(-1.0, 1.0);
+  auto randu = [&distribution, &prng] { return distribution(prng); };
   for (int num_rows = 1; num_rows < 5; ++num_rows) {
     for (int num_cols = 1; num_cols < 5; ++num_cols) {
       Vector b(num_cols);
-      RandomVector(&b);
-
+      b.setRandom();
       Matrix A(num_rows, num_cols);
-      RandomMatrix(&A);
+      A.setRandom();
 
-      double* x = new double[num_cols];
-      for (int i = 0; i < num_cols; ++i) x[i] = 2 * RandDouble() - 1;
+      auto* x = new double[num_cols];
+      std::generate_n(x, num_cols, randu);
 
-      double* jacobian = new double[num_rows * num_cols];
+      auto* jacobian = new double[num_rows * num_cols];
       Vector residuals(num_rows);
 
       NormalPrior prior(A, b);
@@ -92,21 +77,21 @@
 }
 
 TEST(NormalPriorTest, ResidualAtRandomPositionNullJacobians) {
-  srand(5);
-
+  std::mt19937 prng;
+  std::uniform_real_distribution<double> distribution(-1.0, 1.0);
+  auto randu = [&distribution, &prng] { return distribution(prng); };
   for (int num_rows = 1; num_rows < 5; ++num_rows) {
     for (int num_cols = 1; num_cols < 5; ++num_cols) {
       Vector b(num_cols);
-      RandomVector(&b);
-
+      b.setRandom();
       Matrix A(num_rows, num_cols);
-      RandomMatrix(&A);
+      A.setRandom();
 
-      double* x = new double[num_cols];
-      for (int i = 0; i < num_cols; ++i) x[i] = 2 * RandDouble() - 1;
+      auto* x = new double[num_cols];
+      std::generate_n(x, num_cols, randu);
 
       double* jacobians[1];
-      jacobians[0] = NULL;
+      jacobians[0] = nullptr;
 
       Vector residuals(num_rows);
 
@@ -118,7 +103,7 @@
           (residuals - A * (VectorRef(x, num_cols) - b)).squaredNorm();
       EXPECT_NEAR(residual_diff_norm, 0, 1e-10);
 
-      prior.Evaluate(&x, residuals.data(), NULL);
+      prior.Evaluate(&x, residuals.data(), nullptr);
       // Compare the norm of the residual
       residual_diff_norm =
           (residuals - A * (VectorRef(x, num_cols) - b)).squaredNorm();
diff --git a/third_party/ceres/internal/ceres/numeric_diff_cost_function_test.cc b/third_party/ceres/internal/ceres/numeric_diff_cost_function_test.cc
index a5f7a15..0c9074a 100644
--- a/third_party/ceres/internal/ceres/numeric_diff_cost_function_test.cc
+++ b/third_party/ceres/internal/ceres/numeric_diff_cost_function_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2024 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,6 +35,7 @@
 #include <array>
 #include <cmath>
 #include <memory>
+#include <random>
 #include <string>
 #include <vector>
 
@@ -45,104 +46,105 @@
 #include "glog/logging.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST(NumericDiffCostFunction, EasyCaseFunctorCentralDifferences) {
-  std::unique_ptr<CostFunction> cost_function;
-  cost_function.reset(new NumericDiffCostFunction<EasyFunctor,
-                                                  CENTRAL,
-                                                  3,  // number of residuals
-                                                  5,  // size of x1
-                                                  5   // size of x2
-                                                  >(new EasyFunctor));
+  auto cost_function =
+      std::make_unique<NumericDiffCostFunction<EasyFunctor,
+                                               CENTRAL,
+                                               3,  // number of residuals
+                                               5,  // size of x1
+                                               5   // size of x2
+                                               >>(new EasyFunctor);
   EasyFunctor functor;
   functor.ExpectCostFunctionEvaluationIsNearlyCorrect(*cost_function, CENTRAL);
 }
 
 TEST(NumericDiffCostFunction, EasyCaseFunctorForwardDifferences) {
-  std::unique_ptr<CostFunction> cost_function;
-  cost_function.reset(new NumericDiffCostFunction<EasyFunctor,
-                                                  FORWARD,
-                                                  3,  // number of residuals
-                                                  5,  // size of x1
-                                                  5   // size of x2
-                                                  >(new EasyFunctor));
+  auto cost_function =
+      std::make_unique<NumericDiffCostFunction<EasyFunctor,
+                                               FORWARD,
+                                               3,  // number of residuals
+                                               5,  // size of x1
+                                               5   // size of x2
+                                               >>(new EasyFunctor);
   EasyFunctor functor;
   functor.ExpectCostFunctionEvaluationIsNearlyCorrect(*cost_function, FORWARD);
 }
 
 TEST(NumericDiffCostFunction, EasyCaseFunctorRidders) {
-  std::unique_ptr<CostFunction> cost_function;
-  cost_function.reset(new NumericDiffCostFunction<EasyFunctor,
-                                                  RIDDERS,
-                                                  3,  // number of residuals
-                                                  5,  // size of x1
-                                                  5   // size of x2
-                                                  >(new EasyFunctor));
+  auto cost_function =
+      std::make_unique<NumericDiffCostFunction<EasyFunctor,
+                                               RIDDERS,
+                                               3,  // number of residuals
+                                               5,  // size of x1
+                                               5   // size of x2
+                                               >>(new EasyFunctor);
   EasyFunctor functor;
   functor.ExpectCostFunctionEvaluationIsNearlyCorrect(*cost_function, RIDDERS);
 }
 
 TEST(NumericDiffCostFunction, EasyCaseCostFunctionCentralDifferences) {
-  std::unique_ptr<CostFunction> cost_function;
-  cost_function.reset(
-      new NumericDiffCostFunction<EasyCostFunction,
-                                  CENTRAL,
-                                  3,  // number of residuals
-                                  5,  // size of x1
-                                  5   // size of x2
-                                  >(new EasyCostFunction, TAKE_OWNERSHIP));
+  auto cost_function =
+      std::make_unique<NumericDiffCostFunction<EasyCostFunction,
+                                               CENTRAL,
+                                               3,  // number of residuals
+                                               5,  // size of x1
+                                               5   // size of x2
+                                               >>(new EasyCostFunction,
+                                                  TAKE_OWNERSHIP);
   EasyFunctor functor;
   functor.ExpectCostFunctionEvaluationIsNearlyCorrect(*cost_function, CENTRAL);
 }
 
 TEST(NumericDiffCostFunction, EasyCaseCostFunctionForwardDifferences) {
-  std::unique_ptr<CostFunction> cost_function;
-  cost_function.reset(
-      new NumericDiffCostFunction<EasyCostFunction,
-                                  FORWARD,
-                                  3,  // number of residuals
-                                  5,  // size of x1
-                                  5   // size of x2
-                                  >(new EasyCostFunction, TAKE_OWNERSHIP));
+  auto cost_function =
+      std::make_unique<NumericDiffCostFunction<EasyCostFunction,
+                                               FORWARD,
+                                               3,  // number of residuals
+                                               5,  // size of x1
+                                               5   // size of x2
+                                               >>(new EasyCostFunction,
+                                                  TAKE_OWNERSHIP);
   EasyFunctor functor;
   functor.ExpectCostFunctionEvaluationIsNearlyCorrect(*cost_function, FORWARD);
 }
 
 TEST(NumericDiffCostFunction, EasyCaseCostFunctionRidders) {
-  std::unique_ptr<CostFunction> cost_function;
-  cost_function.reset(
-      new NumericDiffCostFunction<EasyCostFunction,
-                                  RIDDERS,
-                                  3,  // number of residuals
-                                  5,  // size of x1
-                                  5   // size of x2
-                                  >(new EasyCostFunction, TAKE_OWNERSHIP));
+  auto cost_function =
+      std::make_unique<NumericDiffCostFunction<EasyCostFunction,
+                                               RIDDERS,
+                                               3,  // number of residuals
+                                               5,  // size of x1
+                                               5   // size of x2
+                                               >>(new EasyCostFunction,
+                                                  TAKE_OWNERSHIP);
+
   EasyFunctor functor;
   functor.ExpectCostFunctionEvaluationIsNearlyCorrect(*cost_function, RIDDERS);
 }
 
 TEST(NumericDiffCostFunction, TranscendentalCaseFunctorCentralDifferences) {
-  std::unique_ptr<CostFunction> cost_function;
-  cost_function.reset(new NumericDiffCostFunction<TranscendentalFunctor,
-                                                  CENTRAL,
-                                                  2,  // number of residuals
-                                                  5,  // size of x1
-                                                  5   // size of x2
-                                                  >(new TranscendentalFunctor));
+  auto cost_function =
+      std::make_unique<NumericDiffCostFunction<TranscendentalFunctor,
+                                               CENTRAL,
+                                               2,  // number of residuals
+                                               5,  // size of x1
+                                               5   // size of x2
+                                               >>(new TranscendentalFunctor);
   TranscendentalFunctor functor;
   functor.ExpectCostFunctionEvaluationIsNearlyCorrect(*cost_function, CENTRAL);
 }
 
 TEST(NumericDiffCostFunction, TranscendentalCaseFunctorForwardDifferences) {
-  std::unique_ptr<CostFunction> cost_function;
-  cost_function.reset(new NumericDiffCostFunction<TranscendentalFunctor,
-                                                  FORWARD,
-                                                  2,  // number of residuals
-                                                  5,  // size of x1
-                                                  5   // size of x2
-                                                  >(new TranscendentalFunctor));
+  auto cost_function =
+      std::make_unique<NumericDiffCostFunction<TranscendentalFunctor,
+                                               FORWARD,
+                                               2,  // number of residuals
+                                               5,  // size of x1
+                                               5   // size of x2
+                                               >>(new TranscendentalFunctor);
+
   TranscendentalFunctor functor;
   functor.ExpectCostFunctionEvaluationIsNearlyCorrect(*cost_function, FORWARD);
 }
@@ -153,43 +155,43 @@
   // Using a smaller initial step size to overcome oscillatory function
   // behavior.
   options.ridders_relative_initial_step_size = 1e-3;
+  auto cost_function =
+      std::make_unique<NumericDiffCostFunction<TranscendentalFunctor,
+                                               RIDDERS,
+                                               2,  // number of residuals
+                                               5,  // size of x1
+                                               5   // size of x2
+                                               >>(
+          new TranscendentalFunctor, TAKE_OWNERSHIP, 2, options);
 
-  std::unique_ptr<CostFunction> cost_function;
-  cost_function.reset(new NumericDiffCostFunction<TranscendentalFunctor,
-                                                  RIDDERS,
-                                                  2,  // number of residuals
-                                                  5,  // size of x1
-                                                  5   // size of x2
-                                                  >(
-      new TranscendentalFunctor, TAKE_OWNERSHIP, 2, options));
   TranscendentalFunctor functor;
   functor.ExpectCostFunctionEvaluationIsNearlyCorrect(*cost_function, RIDDERS);
 }
 
 TEST(NumericDiffCostFunction,
      TranscendentalCaseCostFunctionCentralDifferences) {
-  std::unique_ptr<CostFunction> cost_function;
-  cost_function.reset(new NumericDiffCostFunction<TranscendentalCostFunction,
-                                                  CENTRAL,
-                                                  2,  // number of residuals
-                                                  5,  // size of x1
-                                                  5   // size of x2
-                                                  >(
-      new TranscendentalCostFunction, TAKE_OWNERSHIP));
+  auto cost_function =
+      std::make_unique<NumericDiffCostFunction<TranscendentalCostFunction,
+                                               CENTRAL,
+                                               2,  // number of residuals
+                                               5,  // size of x1
+                                               5   // size of x2
+                                               >>(
+          new TranscendentalCostFunction, TAKE_OWNERSHIP);
   TranscendentalFunctor functor;
   functor.ExpectCostFunctionEvaluationIsNearlyCorrect(*cost_function, CENTRAL);
 }
 
 TEST(NumericDiffCostFunction,
      TranscendentalCaseCostFunctionForwardDifferences) {
-  std::unique_ptr<CostFunction> cost_function;
-  cost_function.reset(new NumericDiffCostFunction<TranscendentalCostFunction,
-                                                  FORWARD,
-                                                  2,  // number of residuals
-                                                  5,  // size of x1
-                                                  5   // size of x2
-                                                  >(
-      new TranscendentalCostFunction, TAKE_OWNERSHIP));
+  auto cost_function =
+      std::make_unique<NumericDiffCostFunction<TranscendentalCostFunction,
+                                               FORWARD,
+                                               2,  // number of residuals
+                                               5,  // size of x1
+                                               5   // size of x2
+                                               >>(
+          new TranscendentalCostFunction, TAKE_OWNERSHIP);
   TranscendentalFunctor functor;
   functor.ExpectCostFunctionEvaluationIsNearlyCorrect(*cost_function, FORWARD);
 }
@@ -201,14 +203,14 @@
   // behavior.
   options.ridders_relative_initial_step_size = 1e-3;
 
-  std::unique_ptr<CostFunction> cost_function;
-  cost_function.reset(new NumericDiffCostFunction<TranscendentalCostFunction,
-                                                  RIDDERS,
-                                                  2,  // number of residuals
-                                                  5,  // size of x1
-                                                  5   // size of x2
-                                                  >(
-      new TranscendentalCostFunction, TAKE_OWNERSHIP, 2, options));
+  auto cost_function =
+      std::make_unique<NumericDiffCostFunction<TranscendentalCostFunction,
+                                               RIDDERS,
+                                               2,  // number of residuals
+                                               5,  // size of x1
+                                               5   // size of x2
+                                               >>(
+          new TranscendentalCostFunction, TAKE_OWNERSHIP, 2, options);
   TranscendentalFunctor functor;
   functor.ExpectCostFunctionEvaluationIsNearlyCorrect(*cost_function, RIDDERS);
 }
@@ -230,122 +232,123 @@
 // templates are instantiated for various shapes of the Jacobian
 // matrix.
 TEST(NumericDiffCostFunction, EigenRowMajorColMajorTest) {
-  std::unique_ptr<CostFunction> cost_function;
-  cost_function.reset(
-      new NumericDiffCostFunction<SizeTestingCostFunction<1, 1>, CENTRAL, 1, 1>(
-          new SizeTestingCostFunction<1, 1>, ceres::TAKE_OWNERSHIP));
+  std::unique_ptr<CostFunction> cost_function = std::make_unique<
+      NumericDiffCostFunction<SizeTestingCostFunction<1, 1>, CENTRAL, 1, 1>>(
+      new SizeTestingCostFunction<1, 1>, ceres::TAKE_OWNERSHIP);
 
-  cost_function.reset(
-      new NumericDiffCostFunction<SizeTestingCostFunction<2, 1>, CENTRAL, 2, 1>(
-          new SizeTestingCostFunction<2, 1>, ceres::TAKE_OWNERSHIP));
+  cost_function = std::make_unique<
+      NumericDiffCostFunction<SizeTestingCostFunction<2, 1>, CENTRAL, 2, 1>>(
+      new SizeTestingCostFunction<2, 1>, ceres::TAKE_OWNERSHIP);
 
-  cost_function.reset(
-      new NumericDiffCostFunction<SizeTestingCostFunction<1, 2>, CENTRAL, 1, 2>(
-          new SizeTestingCostFunction<1, 2>, ceres::TAKE_OWNERSHIP));
+  cost_function = std::make_unique<
+      NumericDiffCostFunction<SizeTestingCostFunction<1, 2>, CENTRAL, 1, 2>>(
+      new SizeTestingCostFunction<1, 2>, ceres::TAKE_OWNERSHIP);
 
-  cost_function.reset(
-      new NumericDiffCostFunction<SizeTestingCostFunction<2, 2>, CENTRAL, 2, 2>(
-          new SizeTestingCostFunction<2, 2>, ceres::TAKE_OWNERSHIP));
+  cost_function = std::make_unique<
+      NumericDiffCostFunction<SizeTestingCostFunction<2, 2>, CENTRAL, 2, 2>>(
+      new SizeTestingCostFunction<2, 2>, ceres::TAKE_OWNERSHIP);
 
-  cost_function.reset(
-      new NumericDiffCostFunction<EasyFunctor, CENTRAL, ceres::DYNAMIC, 1, 1>(
-          new EasyFunctor, TAKE_OWNERSHIP, 1));
+  cost_function = std::make_unique<
+      NumericDiffCostFunction<EasyFunctor, CENTRAL, ceres::DYNAMIC, 1, 1>>(
+      new EasyFunctor, TAKE_OWNERSHIP, 1);
 
-  cost_function.reset(
-      new NumericDiffCostFunction<EasyFunctor, CENTRAL, ceres::DYNAMIC, 1, 1>(
-          new EasyFunctor, TAKE_OWNERSHIP, 2));
+  cost_function = std::make_unique<
+      NumericDiffCostFunction<EasyFunctor, CENTRAL, ceres::DYNAMIC, 1, 1>>(
+      new EasyFunctor, TAKE_OWNERSHIP, 2);
 
-  cost_function.reset(
-      new NumericDiffCostFunction<EasyFunctor, CENTRAL, ceres::DYNAMIC, 1, 2>(
-          new EasyFunctor, TAKE_OWNERSHIP, 1));
+  cost_function = std::make_unique<
+      NumericDiffCostFunction<EasyFunctor, CENTRAL, ceres::DYNAMIC, 1, 2>>(
+      new EasyFunctor, TAKE_OWNERSHIP, 1);
 
-  cost_function.reset(
-      new NumericDiffCostFunction<EasyFunctor, CENTRAL, ceres::DYNAMIC, 1, 2>(
-          new EasyFunctor, TAKE_OWNERSHIP, 2));
+  cost_function = std::make_unique<
+      NumericDiffCostFunction<EasyFunctor, CENTRAL, ceres::DYNAMIC, 1, 2>>(
+      new EasyFunctor, TAKE_OWNERSHIP, 2);
 
-  cost_function.reset(
-      new NumericDiffCostFunction<EasyFunctor, CENTRAL, ceres::DYNAMIC, 2, 1>(
-          new EasyFunctor, TAKE_OWNERSHIP, 1));
+  cost_function = std::make_unique<
+      NumericDiffCostFunction<EasyFunctor, CENTRAL, ceres::DYNAMIC, 2, 1>>(
+      new EasyFunctor, TAKE_OWNERSHIP, 1);
 
-  cost_function.reset(
-      new NumericDiffCostFunction<EasyFunctor, CENTRAL, ceres::DYNAMIC, 2, 1>(
-          new EasyFunctor, TAKE_OWNERSHIP, 2));
+  cost_function = std::make_unique<
+      NumericDiffCostFunction<EasyFunctor, CENTRAL, ceres::DYNAMIC, 2, 1>>(
+      new EasyFunctor, TAKE_OWNERSHIP, 2);
 }
 
 TEST(NumericDiffCostFunction,
      EasyCaseFunctorCentralDifferencesAndDynamicNumResiduals) {
-  std::unique_ptr<CostFunction> cost_function;
-  cost_function.reset(
-      new NumericDiffCostFunction<EasyFunctor,
-                                  CENTRAL,
-                                  ceres::DYNAMIC,
-                                  5,  // size of x1
-                                  5   // size of x2
-                                  >(new EasyFunctor, TAKE_OWNERSHIP, 3));
+  auto cost_function =
+      std::make_unique<NumericDiffCostFunction<EasyFunctor,
+                                               CENTRAL,
+                                               ceres::DYNAMIC,
+                                               5,  // size of x1
+                                               5   // size of x2
+                                               >>(
+          new EasyFunctor, TAKE_OWNERSHIP, 3);
   EasyFunctor functor;
   functor.ExpectCostFunctionEvaluationIsNearlyCorrect(*cost_function, CENTRAL);
 }
 
 TEST(NumericDiffCostFunction, ExponentialFunctorRidders) {
-  std::unique_ptr<CostFunction> cost_function;
-  cost_function.reset(new NumericDiffCostFunction<ExponentialFunctor,
-                                                  RIDDERS,
-                                                  1,  // number of residuals
-                                                  1   // size of x1
-                                                  >(new ExponentialFunctor));
+  auto cost_function =
+      std::make_unique<NumericDiffCostFunction<ExponentialFunctor,
+                                               RIDDERS,
+                                               1,  // number of residuals
+                                               1   // size of x1
+                                               >>(new ExponentialFunctor);
   ExponentialFunctor functor;
   functor.ExpectCostFunctionEvaluationIsNearlyCorrect(*cost_function);
 }
 
 TEST(NumericDiffCostFunction, ExponentialCostFunctionRidders) {
-  std::unique_ptr<CostFunction> cost_function;
-  cost_function.reset(
-      new NumericDiffCostFunction<ExponentialCostFunction,
-                                  RIDDERS,
-                                  1,  // number of residuals
-                                  1   // size of x1
-                                  >(new ExponentialCostFunction));
+  auto cost_function =
+      std::make_unique<NumericDiffCostFunction<ExponentialCostFunction,
+                                               RIDDERS,
+                                               1,  // number of residuals
+                                               1   // size of x1
+                                               >>(new ExponentialCostFunction);
   ExponentialFunctor functor;
   functor.ExpectCostFunctionEvaluationIsNearlyCorrect(*cost_function);
 }
 
 TEST(NumericDiffCostFunction, RandomizedFunctorRidders) {
-  std::unique_ptr<CostFunction> cost_function;
+  std::mt19937 prng;
   NumericDiffOptions options;
   // Larger initial step size is chosen to produce robust results in the
   // presence of random noise.
   options.ridders_relative_initial_step_size = 10.0;
 
-  cost_function.reset(new NumericDiffCostFunction<RandomizedFunctor,
-                                                  RIDDERS,
-                                                  1,  // number of residuals
-                                                  1   // size of x1
-                                                  >(
-      new RandomizedFunctor(kNoiseFactor, kRandomSeed),
-      TAKE_OWNERSHIP,
-      1,
-      options));
-  RandomizedFunctor functor(kNoiseFactor, kRandomSeed);
+  auto cost_function =
+      std::make_unique<NumericDiffCostFunction<RandomizedFunctor,
+                                               RIDDERS,
+                                               1,  // number of residuals
+                                               1   // size of x1
+                                               >>(
+          new RandomizedFunctor(kNoiseFactor, prng),
+          TAKE_OWNERSHIP,
+          1,
+          options);
+  RandomizedFunctor functor(kNoiseFactor, prng);
   functor.ExpectCostFunctionEvaluationIsNearlyCorrect(*cost_function);
 }
 
 TEST(NumericDiffCostFunction, RandomizedCostFunctionRidders) {
-  std::unique_ptr<CostFunction> cost_function;
+  std::mt19937 prng;
   NumericDiffOptions options;
   // Larger initial step size is chosen to produce robust results in the
   // presence of random noise.
   options.ridders_relative_initial_step_size = 10.0;
 
-  cost_function.reset(new NumericDiffCostFunction<RandomizedCostFunction,
-                                                  RIDDERS,
-                                                  1,  // number of residuals
-                                                  1   // size of x1
-                                                  >(
-      new RandomizedCostFunction(kNoiseFactor, kRandomSeed),
-      TAKE_OWNERSHIP,
-      1,
-      options));
-  RandomizedFunctor functor(kNoiseFactor, kRandomSeed);
+  auto cost_function =
+      std::make_unique<NumericDiffCostFunction<RandomizedCostFunction,
+                                               RIDDERS,
+                                               1,  // number of residuals
+                                               1   // size of x1
+                                               >>(
+          new RandomizedCostFunction(kNoiseFactor, prng),
+          TAKE_OWNERSHIP,
+          1,
+          options);
+
+  RandomizedFunctor functor(kNoiseFactor, prng);
   functor.ExpectCostFunctionEvaluationIsNearlyCorrect(*cost_function);
 }
 
@@ -363,15 +366,15 @@
   double* parameters[] = {&parameter};
   double* jacobians[] = {jacobian};
 
-  std::unique_ptr<CostFunction> cost_function(
-      new NumericDiffCostFunction<OnlyFillsOneOutputFunctor, CENTRAL, 2, 1>(
-          new OnlyFillsOneOutputFunctor));
+  auto cost_function = std::make_unique<
+      NumericDiffCostFunction<OnlyFillsOneOutputFunctor, CENTRAL, 2, 1>>(
+      new OnlyFillsOneOutputFunctor);
   InvalidateArray(2, jacobian);
   InvalidateArray(2, residuals);
   EXPECT_TRUE(cost_function->Evaluate(parameters, residuals, jacobians));
   EXPECT_FALSE(IsArrayValid(2, residuals));
   InvalidateArray(2, residuals);
-  EXPECT_TRUE(cost_function->Evaluate(parameters, residuals, NULL));
+  EXPECT_TRUE(cost_function->Evaluate(parameters, residuals, nullptr));
   // We are only testing residuals here, because the Jacobians are
   // computed using finite differencing from the residuals, so unless
   // we introduce a validation step after every evaluation of
@@ -385,12 +388,9 @@
   constexpr int kX1 = 5;
   constexpr int kX2 = 5;
 
-  std::unique_ptr<CostFunction> cost_function;
-  cost_function.reset(new NumericDiffCostFunction<EasyFunctor,
-                                                  CENTRAL,
-                                                  kNumResiduals,
-                                                  kX1,
-                                                  kX2>(new EasyFunctor));
+  auto cost_function = std::make_unique<
+      NumericDiffCostFunction<EasyFunctor, CENTRAL, kNumResiduals, kX1, kX2>>(
+      new EasyFunctor);
 
   // Prepare the parameters and residuals.
   std::array<double, kX1> x1{1e-64, 2.0, 3.0, 4.0, 5.0};
@@ -437,5 +437,28 @@
   }
 }
 
-}  // namespace internal
-}  // namespace ceres
+struct MultiArgFunctor {
+  explicit MultiArgFunctor(int a, double c) {}
+  template <class T>
+  bool operator()(const T* params, T* residuals) const noexcept {
+    return false;
+  }
+};
+
+TEST(NumericDiffCostFunction, ArgumentForwarding) {
+  auto cost_function1 = std::make_unique<
+      NumericDiffCostFunction<EasyFunctor, CENTRAL, 3, 5, 5>>();
+  auto cost_function2 =
+      std::make_unique<NumericDiffCostFunction<MultiArgFunctor, CENTRAL, 1, 1>>(
+          1, 2);
+}
+
+TEST(NumericDiffCostFunction, UniquePtrCtor) {
+  auto cost_function1 =
+      std::make_unique<NumericDiffCostFunction<EasyFunctor, CENTRAL, 3, 5, 5>>(
+          std::make_unique<EasyFunctor>());
+  auto cost_function2 = std::make_unique<
+      NumericDiffCostFunction<EasyFunctor, CENTRAL, 3, 5, 5>>();
+}
+
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/numeric_diff_first_order_function_test.cc b/third_party/ceres/internal/ceres/numeric_diff_first_order_function_test.cc
new file mode 100644
index 0000000..ff57e2d
--- /dev/null
+++ b/third_party/ceres/internal/ceres/numeric_diff_first_order_function_test.cc
@@ -0,0 +1,101 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: sameeragarwal@google.com (Sameer Agarwal)
+
+#include "ceres/numeric_diff_first_order_function.h"
+
+#include <memory>
+
+#include "ceres/array_utils.h"
+#include "ceres/first_order_function.h"
+#include "gtest/gtest.h"
+
+namespace ceres::internal {
+
+class QuadraticCostFunctor {
+ public:
+  explicit QuadraticCostFunctor(double a) : a_(a) {}
+  bool operator()(const double* const x, double* cost) const {
+    cost[0] = x[0] * x[1] + x[2] * x[3] - a_;
+    return true;
+  }
+
+ private:
+  double a_;
+};
+
+TEST(NumericDiffFirstOrderFunction, BilinearDifferentiationTestStatic) {
+  auto function = std::make_unique<
+      NumericDiffFirstOrderFunction<QuadraticCostFunctor, CENTRAL, 4>>(
+      new QuadraticCostFunctor(1.0));
+
+  double parameters[4] = {1.0, 2.0, 3.0, 4.0};
+  double gradient[4];
+  double cost;
+
+  function->Evaluate(parameters, &cost, nullptr);
+  EXPECT_EQ(cost, 13.0);
+
+  cost = -1.0;
+  function->Evaluate(parameters, &cost, gradient);
+
+  EXPECT_EQ(cost, 13.0);
+
+  const double kTolerance = 1e-9;
+  EXPECT_NEAR(gradient[0], parameters[1], kTolerance);
+  EXPECT_NEAR(gradient[1], parameters[0], kTolerance);
+  EXPECT_NEAR(gradient[2], parameters[3], kTolerance);
+  EXPECT_NEAR(gradient[3], parameters[2], kTolerance);
+}
+
+TEST(NumericDiffFirstOrderFunction, BilinearDifferentiationTestDynamic) {
+  auto function = std::make_unique<
+      NumericDiffFirstOrderFunction<QuadraticCostFunctor, CENTRAL>>(
+      new QuadraticCostFunctor(1.0), 4);
+
+  double parameters[4] = {1.0, 2.0, 3.0, 4.0};
+  double gradient[4];
+  double cost;
+
+  function->Evaluate(parameters, &cost, nullptr);
+  EXPECT_EQ(cost, 13.0);
+
+  cost = -1.0;
+  function->Evaluate(parameters, &cost, gradient);
+
+  EXPECT_EQ(cost, 13.0);
+
+  const double kTolerance = 1e-9;
+  EXPECT_NEAR(gradient[0], parameters[1], kTolerance);
+  EXPECT_NEAR(gradient[1], parameters[0], kTolerance);
+  EXPECT_NEAR(gradient[2], parameters[3], kTolerance);
+  EXPECT_NEAR(gradient[3], parameters[2], kTolerance);
+}
+
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/numeric_diff_test_utils.cc b/third_party/ceres/internal/ceres/numeric_diff_test_utils.cc
index d833bbb..0aa1778 100644
--- a/third_party/ceres/internal/ceres/numeric_diff_test_utils.cc
+++ b/third_party/ceres/internal/ceres/numeric_diff_test_utils.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -39,8 +39,7 @@
 #include "ceres/types.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 bool EasyFunctor::operator()(const double* x1,
                              const double* x2,
@@ -149,9 +148,9 @@
   };
   // clang-format on
 
-  for (int k = 0; k < kTests.size(); ++k) {
-    double* x1 = &(kTests[k].x1[0]);
-    double* x2 = &(kTests[k].x2[0]);
+  for (auto& test : kTests) {
+    double* x1 = &(test.x1[0]);
+    double* x2 = &(test.x2[0]);
     double* parameters[] = {x1, x2};
 
     double dydx1[10];
@@ -207,8 +206,8 @@
   // Minimal tolerance w.r.t. the cost function and the tests.
   const double kTolerance = 2e-14;
 
-  for (int k = 0; k < kTests.size(); ++k) {
-    double* parameters[] = {&kTests[k]};
+  for (double& test : kTests) {
+    double* parameters[] = {&test};
     double dydx;
     double* jacobians[1] = {&dydx};
     double residual;
@@ -216,7 +215,7 @@
     ASSERT_TRUE(
         cost_function.Evaluate(&parameters[0], &residual, &jacobians[0]));
 
-    double expected_result = exp(kTests[k]);
+    double expected_result = exp(test);
 
     // Expect residual to be close to exp(x).
     ExpectClose(residual, expected_result, kTolerance);
@@ -227,14 +226,7 @@
 }
 
 bool RandomizedFunctor::operator()(const double* x1, double* residuals) const {
-  double random_value =
-      static_cast<double>(rand()) / static_cast<double>(RAND_MAX);
-
-  // Normalize noise to [-factor, factor].
-  random_value *= 2.0;
-  random_value -= 1.0;
-  random_value *= noise_factor_;
-
+  double random_value = uniform_distribution_(*prng_);
   residuals[0] = x1[0] * x1[0] + random_value;
   return true;
 }
@@ -245,11 +237,8 @@
 
   const double kTolerance = 2e-4;
 
-  // Initialize random number generator with given seed.
-  srand(random_seed_);
-
-  for (int k = 0; k < kTests.size(); ++k) {
-    double* parameters[] = {&kTests[k]};
+  for (double& test : kTests) {
+    double* parameters[] = {&test};
     double dydx;
     double* jacobians[1] = {&dydx};
     double residual;
@@ -258,12 +247,11 @@
         cost_function.Evaluate(&parameters[0], &residual, &jacobians[0]));
 
     // Expect residual to be close to x^2 w.r.t. noise factor.
-    ExpectClose(residual, kTests[k] * kTests[k], noise_factor_);
+    ExpectClose(residual, test * test, noise_factor_);
 
     // Check evaluated differences. (dy/dx = ~2x)
-    ExpectClose(dydx, 2 * kTests[k], kTolerance);
+    ExpectClose(dydx, 2 * test, kTolerance);
   }
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/numeric_diff_test_utils.h b/third_party/ceres/internal/ceres/numeric_diff_test_utils.h
index 392636e..e258ceb 100644
--- a/third_party/ceres/internal/ceres/numeric_diff_test_utils.h
+++ b/third_party/ceres/internal/ceres/numeric_diff_test_utils.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -31,13 +31,14 @@
 #ifndef CERES_INTERNAL_NUMERIC_DIFF_TEST_UTILS_H_
 #define CERES_INTERNAL_NUMERIC_DIFF_TEST_UTILS_H_
 
+#include <random>
+
 #include "ceres/cost_function.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 #include "ceres/sized_cost_function.h"
 #include "ceres/types.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // Noise factor for randomized cost function.
 static constexpr double kNoiseFactor = 0.01;
@@ -48,7 +49,7 @@
 // y1 = x1'x2      -> dy1/dx1 = x2,               dy1/dx2 = x1
 // y2 = (x1'x2)^2  -> dy2/dx1 = 2 * x2 * (x1'x2), dy2/dx2 = 2 * x1 * (x1'x2)
 // y3 = x2'x2      -> dy3/dx1 = 0,                dy3/dx2 = 2 * x2
-class CERES_EXPORT_INTERNAL EasyFunctor {
+class CERES_NO_EXPORT EasyFunctor {
  public:
   bool operator()(const double* x1, const double* x2, double* residuals) const;
   void ExpectCostFunctionEvaluationIsNearlyCorrect(
@@ -72,14 +73,14 @@
 //
 // dy1/dx1 =  x2 * cos(x1'x2),            dy1/dx2 =  x1 * cos(x1'x2)
 // dy2/dx1 = -x2 * exp(-x1'x2 / 10) / 10, dy2/dx2 = -x2 * exp(-x1'x2 / 10) / 10
-class CERES_EXPORT TranscendentalFunctor {
+class CERES_NO_EXPORT TranscendentalFunctor {
  public:
   bool operator()(const double* x1, const double* x2, double* residuals) const;
   void ExpectCostFunctionEvaluationIsNearlyCorrect(
       const CostFunction& cost_function, NumericDiffMethodType method) const;
 };
 
-class CERES_EXPORT_INTERNAL TranscendentalCostFunction
+class CERES_NO_EXPORT TranscendentalCostFunction
     : public SizedCostFunction<2, 5, 5> {
  public:
   bool Evaluate(double const* const* parameters,
@@ -93,7 +94,7 @@
 };
 
 // y = exp(x), dy/dx = exp(x)
-class CERES_EXPORT_INTERNAL ExponentialFunctor {
+class CERES_NO_EXPORT ExponentialFunctor {
  public:
   bool operator()(const double* x1, double* residuals) const;
   void ExpectCostFunctionEvaluationIsNearlyCorrect(
@@ -115,10 +116,12 @@
 // Test adaptive numeric differentiation by synthetically adding random noise
 // to a functor.
 // y = x^2 + [random noise], dy/dx ~ 2x
-class CERES_EXPORT_INTERNAL RandomizedFunctor {
+class CERES_NO_EXPORT RandomizedFunctor {
  public:
-  RandomizedFunctor(double noise_factor, unsigned int random_seed)
-      : noise_factor_(noise_factor), random_seed_(random_seed) {}
+  RandomizedFunctor(double noise_factor, std::mt19937& prng)
+      : noise_factor_(noise_factor),
+        prng_(&prng),
+        uniform_distribution_{-noise_factor, noise_factor} {}
 
   bool operator()(const double* x1, double* residuals) const;
   void ExpectCostFunctionEvaluationIsNearlyCorrect(
@@ -126,14 +129,16 @@
 
  private:
   double noise_factor_;
-  unsigned int random_seed_;
+  // Store the generator as a pointer to be able to modify the instance the
+  // pointer is pointing to.
+  std::mt19937* prng_;
+  mutable std::uniform_real_distribution<> uniform_distribution_;
 };
 
-class CERES_EXPORT_INTERNAL RandomizedCostFunction
-    : public SizedCostFunction<1, 1> {
+class CERES_NO_EXPORT RandomizedCostFunction : public SizedCostFunction<1, 1> {
  public:
-  RandomizedCostFunction(double noise_factor, unsigned int random_seed)
-      : functor_(noise_factor, random_seed) {}
+  RandomizedCostFunction(double noise_factor, std::mt19937& prng)
+      : functor_(noise_factor, prng) {}
 
   bool Evaluate(double const* const* parameters,
                 double* residuals,
@@ -145,7 +150,6 @@
   RandomizedFunctor functor_;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_INTERNAL_NUMERIC_DIFF_TEST_UTILS_H_
diff --git a/third_party/ceres/internal/ceres/ordered_groups_test.cc b/third_party/ceres/internal/ceres/ordered_groups_test.cc
index d613a41..d376b4d 100644
--- a/third_party/ceres/internal/ceres/ordered_groups_test.cc
+++ b/third_party/ceres/internal/ceres/ordered_groups_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,8 +35,7 @@
 
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST(OrderedGroups, EmptyOrderedGroupBehavesCorrectly) {
   ParameterBlockOrdering ordering;
@@ -229,5 +228,4 @@
   // No non-zero groups left.
   EXPECT_DEATH_IF_SUPPORTED(ordering.MinNonZeroGroup(), "NumGroups");
 }
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/pair_hash.h b/third_party/ceres/internal/ceres/pair_hash.h
index abbedcc..64882cd 100644
--- a/third_party/ceres/internal/ceres/pair_hash.h
+++ b/third_party/ceres/internal/ceres/pair_hash.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -33,13 +33,14 @@
 #ifndef CERES_INTERNAL_PAIR_HASH_H_
 #define CERES_INTERNAL_PAIR_HASH_H_
 
+#include <cstddef>
 #include <cstdint>
+#include <functional>
 #include <utility>
 
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 #if defined(_WIN32) && !defined(__MINGW64__) && !defined(__MINGW32__)
 #define GG_LONGLONG(x) x##I64
@@ -110,7 +111,6 @@
   }
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_INTERNAL_PAIR_HASH_H_
diff --git a/third_party/ceres/internal/ceres/parallel_for.h b/third_party/ceres/internal/ceres/parallel_for.h
index b64bd31..11db1fb 100644
--- a/third_party/ceres/internal/ceres/parallel_for.h
+++ b/third_party/ceres/internal/ceres/parallel_for.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -26,45 +26,161 @@
 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 // POSSIBILITY OF SUCH DAMAGE.
 //
-// Author: vitus@google.com (Michael Vitus)
+// Authors: vitus@google.com (Michael Vitus),
+//          dmitriy.korchemkin@gmail.com (Dmitriy Korchemkin)
 
-#ifndef CERES_INTERNAL_PARALLEL_FOR_
-#define CERES_INTERNAL_PARALLEL_FOR_
+#ifndef CERES_INTERNAL_PARALLEL_FOR_H_
+#define CERES_INTERNAL_PARALLEL_FOR_H_
 
-#include <functional>
+#include <mutex>
+#include <vector>
 
 #include "ceres/context_impl.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/export.h"
+#include "ceres/parallel_invoke.h"
+#include "ceres/partition_range_for_parallel_for.h"
+#include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
-// Returns the maximum number of threads supported by the threading backend
-// Ceres was compiled with.
-int MaxNumThreadsAvailable();
+// Use a dummy mutex if num_threads = 1.
+inline decltype(auto) MakeConditionalLock(const int num_threads,
+                                          std::mutex& m) {
+  return (num_threads == 1) ? std::unique_lock<std::mutex>{}
+                            : std::unique_lock<std::mutex>{m};
+}
 
 // Execute the function for every element in the range [start, end) with at most
 // num_threads. It will execute all the work on the calling thread if
-// num_threads is 1.
-CERES_EXPORT_INTERNAL void ParallelFor(
-    ContextImpl* context,
-    int start,
-    int end,
-    int num_threads,
-    const std::function<void(int)>& function);
+// num_threads or (end - start) is equal to 1.
+// Depending on function signature, it will be supplied with either loop index
+// or a range of loop indicies; function can also be supplied with thread_id.
+// The following function signatures are supported:
+//  - Functions accepting a single loop index:
+//     - [](int index) { ... }
+//     - [](int thread_id, int index) { ... }
+//  - Functions accepting a range of loop index:
+//     - [](std::tuple<int, int> index) { ... }
+//     - [](int thread_id, std::tuple<int, int> index) { ... }
+//
+// When distributing workload between threads, it is assumed that each loop
+// iteration takes approximately equal time to complete.
+template <typename F>
+void ParallelFor(ContextImpl* context,
+                 int start,
+                 int end,
+                 int num_threads,
+                 F&& function,
+                 int min_block_size = 1) {
+  CHECK_GT(num_threads, 0);
+  if (start >= end) {
+    return;
+  }
 
-// Execute the function for every element in the range [start, end) with at most
-// num_threads. It will execute all the work on the calling thread if
-// num_threads is 1.  Each invocation of function() will be passed a thread_id
-// in [0, num_threads) that is guaranteed to be distinct from the value passed
-// to any concurrent execution of function().
-CERES_EXPORT_INTERNAL void ParallelFor(
-    ContextImpl* context,
-    int start,
-    int end,
-    int num_threads,
-    const std::function<void(int thread_id, int i)>& function);
-}  // namespace internal
-}  // namespace ceres
+  if (num_threads == 1 || end - start < min_block_size * 2) {
+    InvokeOnSegment(0, std::make_tuple(start, end), std::forward<F>(function));
+    return;
+  }
+
+  CHECK(context != nullptr);
+  ParallelInvoke(context,
+                 start,
+                 end,
+                 num_threads,
+                 std::forward<F>(function),
+                 min_block_size);
+}
+
+// Execute function for every element in the range [start, end) with at most
+// num_threads, using user-provided partitions array.
+// When distributing workload between threads, it is assumed that each segment
+// bounded by adjacent elements of partitions array takes approximately equal
+// time to process.
+template <typename F>
+void ParallelFor(ContextImpl* context,
+                 int start,
+                 int end,
+                 int num_threads,
+                 F&& function,
+                 const std::vector<int>& partitions) {
+  CHECK_GT(num_threads, 0);
+  if (start >= end) {
+    return;
+  }
+  CHECK_EQ(partitions.front(), start);
+  CHECK_EQ(partitions.back(), end);
+  if (num_threads == 1 || end - start <= num_threads) {
+    ParallelFor(context, start, end, num_threads, std::forward<F>(function));
+    return;
+  }
+  CHECK_GT(partitions.size(), 1);
+  const int num_partitions = partitions.size() - 1;
+  ParallelFor(context,
+              0,
+              num_partitions,
+              num_threads,
+              [&function, &partitions](int thread_id,
+                                       std::tuple<int, int> partition_ids) {
+                // partition_ids is a range of partition indices
+                const auto [partition_start, partition_end] = partition_ids;
+                // Execution over several adjacent segments is equivalent
+                // to execution over union of those segments (which is also a
+                // contiguous segment)
+                const int range_start = partitions[partition_start];
+                const int range_end = partitions[partition_end];
+                // Range of original loop indices
+                const auto range = std::make_tuple(range_start, range_end);
+                InvokeOnSegment(thread_id, range, function);
+              });
+}
+
+// Execute function for every element in the range [start, end) with at most
+// num_threads, taking into account user-provided integer cumulative costs of
+// iterations. Cumulative costs of iteration for indices in range [0, end) are
+// stored in objects from cumulative_cost_data. User-provided
+// cumulative_cost_fun returns non-decreasing integer values corresponding to
+// inclusive cumulative cost of loop iterations, provided with a reference to
+// user-defined object. Only indices from [start, end) will be referenced. This
+// routine assumes that cumulative_cost_fun is non-decreasing (in other words,
+// all costs are non-negative);
+// When distributing workload between threads, input range of loop indices will
+// be partitioned into disjoint contiguous intervals, with the maximal cost
+// being minimized.
+// For example, with iteration costs of [1, 1, 5, 3, 1, 4] cumulative_cost_fun
+// should return [1, 2, 7, 10, 11, 15], and with num_threads = 4 this range
+// will be split into segments [0, 2) [2, 3) [3, 5) [5, 6) with costs
+// [2, 5, 4, 4].
+template <typename F, typename CumulativeCostData, typename CumulativeCostFun>
+void ParallelFor(ContextImpl* context,
+                 int start,
+                 int end,
+                 int num_threads,
+                 F&& function,
+                 const CumulativeCostData* cumulative_cost_data,
+                 CumulativeCostFun&& cumulative_cost_fun) {
+  CHECK_GT(num_threads, 0);
+  if (start >= end) {
+    return;
+  }
+  if (num_threads == 1 || end - start <= num_threads) {
+    ParallelFor(context, start, end, num_threads, std::forward<F>(function));
+    return;
+  }
+  // Creating several partitions allows us to tolerate imperfections of
+  // partitioning and user-supplied iteration costs up to a certain extent
+  constexpr int kNumPartitionsPerThread = 4;
+  const int kMaxPartitions = num_threads * kNumPartitionsPerThread;
+  const auto& partitions = PartitionRangeForParallelFor(
+      start,
+      end,
+      kMaxPartitions,
+      cumulative_cost_data,
+      std::forward<CumulativeCostFun>(cumulative_cost_fun));
+  CHECK_GT(partitions.size(), 1);
+  ParallelFor(
+      context, start, end, num_threads, std::forward<F>(function), partitions);
+}
+}  // namespace ceres::internal
 
 #endif  // CERES_INTERNAL_PARALLEL_FOR_H_
diff --git a/third_party/ceres/internal/ceres/parallel_for_benchmark.cc b/third_party/ceres/internal/ceres/parallel_for_benchmark.cc
new file mode 100644
index 0000000..3bfdb87
--- /dev/null
+++ b/third_party/ceres/internal/ceres/parallel_for_benchmark.cc
@@ -0,0 +1,76 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+
+#include "benchmark/benchmark.h"
+#include "ceres/context_impl.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/parallel_for.h"
+#include "glog/logging.h"
+
+namespace ceres::internal {
+
+// Parallel for with very small amount of work per iteration and small amount of
+// iterations benchmarks performance of task scheduling
+static void SchedulerBenchmark(benchmark::State& state) {
+  const int vector_size = static_cast<int>(state.range(0));
+  const int num_threads = static_cast<int>(state.range(1));
+  ContextImpl context;
+  context.EnsureMinimumThreads(num_threads);
+
+  Vector x = Vector::Random(vector_size);
+  for (auto _ : state) {
+    ParallelFor(
+        &context, 0, vector_size, num_threads, [&x](int id) { x[id] = 0.; });
+  }
+  CHECK_EQ(x.squaredNorm(), 0.);
+}
+BENCHMARK(SchedulerBenchmark)
+    ->Args({128, 1})
+    ->Args({128, 2})
+    ->Args({128, 4})
+    ->Args({128, 8})
+    ->Args({128, 16})
+    ->Args({256, 1})
+    ->Args({256, 2})
+    ->Args({256, 4})
+    ->Args({256, 8})
+    ->Args({256, 16})
+    ->Args({1024, 1})
+    ->Args({1024, 2})
+    ->Args({1024, 4})
+    ->Args({1024, 8})
+    ->Args({1024, 16})
+    ->Args({4096, 1})
+    ->Args({4096, 2})
+    ->Args({4096, 4})
+    ->Args({4096, 8})
+    ->Args({4096, 16});
+
+}  // namespace ceres::internal
+
+BENCHMARK_MAIN();
diff --git a/third_party/ceres/internal/ceres/parallel_for_cxx.cc b/third_party/ceres/internal/ceres/parallel_for_cxx.cc
deleted file mode 100644
index 4da40c0..0000000
--- a/third_party/ceres/internal/ceres/parallel_for_cxx.cc
+++ /dev/null
@@ -1,245 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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 Google Inc. 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.
-//
-// Author: vitus@google.com (Michael Vitus)
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifdef CERES_USE_CXX_THREADS
-
-#include <cmath>
-#include <condition_variable>
-#include <memory>
-#include <mutex>
-
-#include "ceres/concurrent_queue.h"
-#include "ceres/parallel_for.h"
-#include "ceres/scoped_thread_token.h"
-#include "ceres/thread_token_provider.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-namespace {
-// This class creates a thread safe barrier which will block until a
-// pre-specified number of threads call Finished.  This allows us to block the
-// main thread until all the parallel threads are finished processing all the
-// work.
-class BlockUntilFinished {
- public:
-  explicit BlockUntilFinished(int num_total)
-      : num_finished_(0), num_total_(num_total) {}
-
-  // Increment the number of jobs that have finished and signal the blocking
-  // thread if all jobs have finished.
-  void Finished() {
-    std::lock_guard<std::mutex> lock(mutex_);
-    ++num_finished_;
-    CHECK_LE(num_finished_, num_total_);
-    if (num_finished_ == num_total_) {
-      condition_.notify_one();
-    }
-  }
-
-  // Block until all threads have signaled they are finished.
-  void Block() {
-    std::unique_lock<std::mutex> lock(mutex_);
-    condition_.wait(lock, [&]() { return num_finished_ == num_total_; });
-  }
-
- private:
-  std::mutex mutex_;
-  std::condition_variable condition_;
-  // The current number of jobs finished.
-  int num_finished_;
-  // The total number of jobs.
-  int num_total_;
-};
-
-// Shared state between the parallel tasks. Each thread will use this
-// information to get the next block of work to be performed.
-struct SharedState {
-  SharedState(int start, int end, int num_work_items)
-      : start(start),
-        end(end),
-        num_work_items(num_work_items),
-        i(0),
-        thread_token_provider(num_work_items),
-        block_until_finished(num_work_items) {}
-
-  // The start and end index of the for loop.
-  const int start;
-  const int end;
-  // The number of blocks that need to be processed.
-  const int num_work_items;
-
-  // The next block of work to be assigned to a worker.  The parallel for loop
-  // range is split into num_work_items blocks of work, i.e. a single block of
-  // work is:
-  //  for (int j = start + i; j < end; j += num_work_items) { ... }.
-  int i;
-  std::mutex mutex_i;
-
-  // Provides a unique thread ID among all active threads working on the same
-  // group of tasks.  Thread-safe.
-  ThreadTokenProvider thread_token_provider;
-
-  // Used to signal when all the work has been completed.  Thread safe.
-  BlockUntilFinished block_until_finished;
-};
-
-}  // namespace
-
-int MaxNumThreadsAvailable() { return ThreadPool::MaxNumThreadsAvailable(); }
-
-// See ParallelFor (below) for more details.
-void ParallelFor(ContextImpl* context,
-                 int start,
-                 int end,
-                 int num_threads,
-                 const std::function<void(int)>& function) {
-  CHECK_GT(num_threads, 0);
-  CHECK(context != NULL);
-  if (end <= start) {
-    return;
-  }
-
-  // Fast path for when it is single threaded.
-  if (num_threads == 1) {
-    for (int i = start; i < end; ++i) {
-      function(i);
-    }
-    return;
-  }
-
-  ParallelFor(
-      context, start, end, num_threads, [&function](int /*thread_id*/, int i) {
-        function(i);
-      });
-}
-
-// This implementation uses a fixed size max worker pool with a shared task
-// queue. The problem of executing the function for the interval of [start, end)
-// is broken up into at most num_threads blocks and added to the thread pool. To
-// avoid deadlocks, the calling thread is allowed to steal work from the worker
-// pool. This is implemented via a shared state between the tasks. In order for
-// the calling thread or thread pool to get a block of work, it will query the
-// shared state for the next block of work to be done. If there is nothing left,
-// it will return. We will exit the ParallelFor call when all of the work has
-// been done, not when all of the tasks have been popped off the task queue.
-//
-// A unique thread ID among all active tasks will be acquired once for each
-// block of work.  This avoids the significant performance penalty for acquiring
-// it on every iteration of the for loop. The thread ID is guaranteed to be in
-// [0, num_threads).
-//
-// A performance analysis has shown this implementation is onpar with OpenMP and
-// TBB.
-void ParallelFor(ContextImpl* context,
-                 int start,
-                 int end,
-                 int num_threads,
-                 const std::function<void(int thread_id, int i)>& function) {
-  CHECK_GT(num_threads, 0);
-  CHECK(context != NULL);
-  if (end <= start) {
-    return;
-  }
-
-  // Fast path for when it is single threaded.
-  if (num_threads == 1) {
-    // Even though we only have one thread, use the thread token provider to
-    // guarantee the exact same behavior when running with multiple threads.
-    ThreadTokenProvider thread_token_provider(num_threads);
-    const ScopedThreadToken scoped_thread_token(&thread_token_provider);
-    const int thread_id = scoped_thread_token.token();
-    for (int i = start; i < end; ++i) {
-      function(thread_id, i);
-    }
-    return;
-  }
-
-  // We use a std::shared_ptr because the main thread can finish all
-  // the work before the tasks have been popped off the queue.  So the
-  // shared state needs to exist for the duration of all the tasks.
-  const int num_work_items = std::min((end - start), num_threads);
-  std::shared_ptr<SharedState> shared_state(
-      new SharedState(start, end, num_work_items));
-
-  // A function which tries to perform a chunk of work. This returns false if
-  // there is no work to be done.
-  auto task_function = [shared_state, &function]() {
-    int i = 0;
-    {
-      // Get the next available chunk of work to be performed. If there is no
-      // work, return false.
-      std::lock_guard<std::mutex> lock(shared_state->mutex_i);
-      if (shared_state->i >= shared_state->num_work_items) {
-        return false;
-      }
-      i = shared_state->i;
-      ++shared_state->i;
-    }
-
-    const ScopedThreadToken scoped_thread_token(
-        &shared_state->thread_token_provider);
-    const int thread_id = scoped_thread_token.token();
-
-    // Perform each task.
-    for (int j = shared_state->start + i; j < shared_state->end;
-         j += shared_state->num_work_items) {
-      function(thread_id, j);
-    }
-    shared_state->block_until_finished.Finished();
-    return true;
-  };
-
-  // Add all the tasks to the thread pool.
-  for (int i = 0; i < num_work_items; ++i) {
-    // Note we are taking the task_function as value so the shared_state
-    // shared pointer is copied and the ref count is increased. This is to
-    // prevent it from being deleted when the main thread finishes all the
-    // work and exits before the threads finish.
-    context->thread_pool.AddTask([task_function]() { task_function(); });
-  }
-
-  // Try to do any available work on the main thread. This may steal work from
-  // the thread pool, but when there is no work left the thread pool tasks
-  // will be no-ops.
-  while (task_function()) {
-  }
-
-  // Wait until all tasks have finished.
-  shared_state->block_until_finished.Block();
-}
-
-}  // namespace internal
-}  // namespace ceres
-
-#endif  // CERES_USE_CXX_THREADS
diff --git a/third_party/ceres/internal/ceres/parallel_for_nothreads.cc b/third_party/ceres/internal/ceres/parallel_for_nothreads.cc
deleted file mode 100644
index d036569..0000000
--- a/third_party/ceres/internal/ceres/parallel_for_nothreads.cc
+++ /dev/null
@@ -1,78 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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 Google Inc. 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.
-//
-// Author: alexs.mac@gmail.com (Alex Stewart)
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifdef CERES_NO_THREADS
-
-#include "ceres/parallel_for.h"
-#include "glog/logging.h"
-
-namespace ceres {
-namespace internal {
-
-int MaxNumThreadsAvailable() { return 1; }
-
-void ParallelFor(ContextImpl* context,
-                 int start,
-                 int end,
-                 int num_threads,
-                 const std::function<void(int)>& function) {
-  CHECK_GT(num_threads, 0);
-  CHECK(context != NULL);
-  if (end <= start) {
-    return;
-  }
-  for (int i = start; i < end; ++i) {
-    function(i);
-  }
-}
-
-void ParallelFor(ContextImpl* context,
-                 int start,
-                 int end,
-                 int num_threads,
-                 const std::function<void(int thread_id, int i)>& function) {
-  CHECK_GT(num_threads, 0);
-  CHECK(context != NULL);
-  if (end <= start) {
-    return;
-  }
-  const int thread_id = 0;
-  for (int i = start; i < end; ++i) {
-    function(thread_id, i);
-  }
-}
-
-}  // namespace internal
-}  // namespace ceres
-
-#endif  // CERES_NO_THREADS
diff --git a/third_party/ceres/internal/ceres/parallel_for_openmp.cc b/third_party/ceres/internal/ceres/parallel_for_openmp.cc
deleted file mode 100644
index eb9d905..0000000
--- a/third_party/ceres/internal/ceres/parallel_for_openmp.cc
+++ /dev/null
@@ -1,85 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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 Google Inc. 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.
-//
-// Author: vitus@google.com (Michael Vitus)
-
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#if defined(CERES_USE_OPENMP)
-
-#include "ceres/parallel_for.h"
-#include "ceres/scoped_thread_token.h"
-#include "ceres/thread_token_provider.h"
-#include "glog/logging.h"
-#include "omp.h"
-
-namespace ceres {
-namespace internal {
-
-int MaxNumThreadsAvailable() { return omp_get_max_threads(); }
-
-void ParallelFor(ContextImpl* context,
-                 int start,
-                 int end,
-                 int num_threads,
-                 const std::function<void(int)>& function) {
-  CHECK_GT(num_threads, 0);
-  CHECK(context != NULL);
-  if (end <= start) {
-    return;
-  }
-
-#ifdef CERES_USE_OPENMP
-#pragma omp parallel for num_threads(num_threads) \
-    schedule(dynamic) if (num_threads > 1)
-#endif  // CERES_USE_OPENMP
-  for (int i = start; i < end; ++i) {
-    function(i);
-  }
-}
-
-void ParallelFor(ContextImpl* context,
-                 int start,
-                 int end,
-                 int num_threads,
-                 const std::function<void(int thread_id, int i)>& function) {
-  CHECK(context != NULL);
-
-  ThreadTokenProvider thread_token_provider(num_threads);
-  ParallelFor(context, start, end, num_threads, [&](int i) {
-    const ScopedThreadToken scoped_thread_token(&thread_token_provider);
-    const int thread_id = scoped_thread_token.token();
-    function(thread_id, i);
-  });
-}
-
-}  // namespace internal
-}  // namespace ceres
-
-#endif  // defined(CERES_USE_OPENMP)
diff --git a/third_party/ceres/internal/ceres/parallel_for_test.cc b/third_party/ceres/internal/ceres/parallel_for_test.cc
index 434f993..46f5a0f 100644
--- a/third_party/ceres/internal/ceres/parallel_for_test.cc
+++ b/third_party/ceres/internal/ceres/parallel_for_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -28,26 +28,26 @@
 //
 // Author: vitus@google.com (Michael Vitus)
 
-// This include must come before any #ifndef check on Ceres compile options.
-// clang-format off
-#include "ceres/internal/port.h"
-// clang-format on
-
 #include "ceres/parallel_for.h"
 
+#include <atomic>
 #include <cmath>
 #include <condition_variable>
 #include <mutex>
+#include <numeric>
+#include <random>
 #include <thread>
+#include <tuple>
 #include <vector>
 
 #include "ceres/context_impl.h"
+#include "ceres/internal/config.h"
+#include "ceres/parallel_vector_ops.h"
 #include "glog/logging.h"
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 using testing::ElementsAreArray;
 using testing::UnorderedElementsAreArray;
@@ -73,6 +73,51 @@
   }
 }
 
+// Tests parallel for loop with ranges
+TEST(ParallelForWithRange, NumThreads) {
+  ContextImpl context;
+  context.EnsureMinimumThreads(/*num_threads=*/2);
+
+  const int size = 16;
+  std::vector<int> expected_results(size, 0);
+  for (int i = 0; i < size; ++i) {
+    expected_results[i] = std::sqrt(i);
+  }
+
+  for (int num_threads = 1; num_threads <= 8; ++num_threads) {
+    std::vector<int> values(size, 0);
+    ParallelFor(
+        &context, 0, size, num_threads, [&values](std::tuple<int, int> range) {
+          auto [start, end] = range;
+          for (int i = start; i < end; ++i) values[i] = std::sqrt(i);
+        });
+    EXPECT_THAT(values, ElementsAreArray(expected_results));
+  }
+}
+
+// Tests parallel for loop with ranges and lower bound on minimal range size
+TEST(ParallelForWithRange, MinimalSize) {
+  ContextImpl context;
+  constexpr int kNumThreads = 4;
+  constexpr int kMinBlockSize = 5;
+  context.EnsureMinimumThreads(kNumThreads);
+
+  for (int size = kMinBlockSize; size <= 25; ++size) {
+    std::atomic<bool> failed(false);
+    ParallelFor(
+        &context,
+        0,
+        size,
+        kNumThreads,
+        [&failed, kMinBlockSize](std::tuple<int, int> range) {
+          auto [start, end] = range;
+          if (end - start < kMinBlockSize) failed = true;
+        },
+        kMinBlockSize);
+    EXPECT_EQ(failed, false);
+  }
+}
+
 // Tests the parallel for loop with the thread ID interface computes the correct
 // result for various number of threads.
 TEST(ParallelForWithThreadId, NumThreads) {
@@ -132,8 +177,6 @@
   }
 }
 
-// This test is only valid when multithreading support is enabled.
-#ifndef CERES_NO_THREADS
 TEST(ParallelForWithThreadId, UniqueThreadIds) {
   // Ensure the hardware supports more than 1 thread to ensure the test will
   // pass.
@@ -165,7 +208,289 @@
 
   EXPECT_THAT(x, UnorderedElementsAreArray({0, 1}));
 }
-#endif  // CERES_NO_THREADS
 
-}  // namespace internal
-}  // namespace ceres
+// Helper function for partition tests
+bool BruteForcePartition(
+    int* costs, int start, int end, int max_partitions, int max_cost);
+// Basic test if MaxPartitionCostIsFeasible and BruteForcePartition agree on
+// simple test-cases
+TEST(GuidedParallelFor, MaxPartitionCostIsFeasible) {
+  std::vector<int> costs, cumulative_costs, partition;
+  costs = {1, 2, 3, 5, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0};
+  cumulative_costs.resize(costs.size());
+  std::partial_sum(costs.begin(), costs.end(), cumulative_costs.begin());
+  const auto dummy_getter = [](const int v) { return v; };
+
+  // [1, 2, 3] [5], [0 ... 0, 7, 0, ... 0]
+  EXPECT_TRUE(MaxPartitionCostIsFeasible(0,
+                                         costs.size(),
+                                         3,
+                                         7,
+                                         0,
+                                         cumulative_costs.data(),
+                                         dummy_getter,
+                                         &partition));
+  EXPECT_TRUE(BruteForcePartition(costs.data(), 0, costs.size(), 3, 7));
+  // [1, 2, 3, 5, 0 ... 0, 7, 0, ... 0]
+  EXPECT_TRUE(MaxPartitionCostIsFeasible(0,
+                                         costs.size(),
+                                         3,
+                                         18,
+                                         0,
+                                         cumulative_costs.data(),
+                                         dummy_getter,
+                                         &partition));
+  EXPECT_TRUE(BruteForcePartition(costs.data(), 0, costs.size(), 3, 18));
+  // Impossible since there is item of cost 7
+  EXPECT_FALSE(MaxPartitionCostIsFeasible(0,
+                                          costs.size(),
+                                          3,
+                                          6,
+                                          0,
+                                          cumulative_costs.data(),
+                                          dummy_getter,
+                                          &partition));
+  EXPECT_FALSE(BruteForcePartition(costs.data(), 0, costs.size(), 3, 6));
+  // Impossible
+  EXPECT_FALSE(MaxPartitionCostIsFeasible(0,
+                                          costs.size(),
+                                          2,
+                                          10,
+                                          0,
+                                          cumulative_costs.data(),
+                                          dummy_getter,
+                                          &partition));
+  EXPECT_FALSE(BruteForcePartition(costs.data(), 0, costs.size(), 2, 10));
+}
+
+// Randomized tests for MaxPartitionCostIsFeasible
+TEST(GuidedParallelFor, MaxPartitionCostIsFeasibleRandomized) {
+  std::vector<int> costs, cumulative_costs, partition;
+  const auto dummy_getter = [](const int v) { return v; };
+
+  // Random tests
+  const int kNumTests = 1000;
+  const int kMaxElements = 32;
+  const int kMaxPartitions = 16;
+  const int kMaxElCost = 8;
+  std::mt19937 rng;
+  std::uniform_int_distribution<int> rng_N(1, kMaxElements);
+  std::uniform_int_distribution<int> rng_M(1, kMaxPartitions);
+  std::uniform_int_distribution<int> rng_e(0, kMaxElCost);
+  for (int t = 0; t < kNumTests; ++t) {
+    const int N = rng_N(rng);
+    const int M = rng_M(rng);
+    int total = 0;
+    costs.clear();
+    for (int i = 0; i < N; ++i) {
+      costs.push_back(rng_e(rng));
+      total += costs.back();
+    }
+
+    cumulative_costs.resize(N);
+    std::partial_sum(costs.begin(), costs.end(), cumulative_costs.begin());
+
+    std::uniform_int_distribution<int> rng_seg(0, N - 1);
+    int start = rng_seg(rng);
+    int end = rng_seg(rng);
+    if (start > end) std::swap(start, end);
+    ++end;
+
+    int first_admissible = 0;
+    for (int threshold = 1; threshold <= total; ++threshold) {
+      const bool bruteforce =
+          BruteForcePartition(costs.data(), start, end, M, threshold);
+      if (bruteforce && !first_admissible) {
+        first_admissible = threshold;
+      }
+      const bool binary_search =
+          MaxPartitionCostIsFeasible(start,
+                                     end,
+                                     M,
+                                     threshold,
+                                     start ? cumulative_costs[start - 1] : 0,
+                                     cumulative_costs.data(),
+                                     dummy_getter,
+                                     &partition);
+      EXPECT_EQ(bruteforce, binary_search);
+      EXPECT_LE(partition.size(), M + 1);
+      // check partition itself
+      if (binary_search) {
+        ASSERT_GT(partition.size(), 1);
+        EXPECT_EQ(partition.front(), start);
+        EXPECT_EQ(partition.back(), end);
+
+        const int num_partitions = partition.size() - 1;
+        EXPECT_LE(num_partitions, M);
+        for (int j = 0; j < num_partitions; ++j) {
+          int total = 0;
+          for (int k = partition[j]; k < partition[j + 1]; ++k) {
+            EXPECT_LT(k, end);
+            EXPECT_GE(k, start);
+            total += costs[k];
+          }
+          EXPECT_LE(total, threshold);
+        }
+      }
+    }
+  }
+}
+
+TEST(GuidedParallelFor, PartitionRangeForParallelFor) {
+  std::vector<int> costs, cumulative_costs, partition;
+  const auto dummy_getter = [](const int v) { return v; };
+
+  // Random tests
+  const int kNumTests = 1000;
+  const int kMaxElements = 32;
+  const int kMaxPartitions = 16;
+  const int kMaxElCost = 8;
+  std::mt19937 rng;
+  std::uniform_int_distribution<int> rng_N(1, kMaxElements);
+  std::uniform_int_distribution<int> rng_M(1, kMaxPartitions);
+  std::uniform_int_distribution<int> rng_e(0, kMaxElCost);
+  for (int t = 0; t < kNumTests; ++t) {
+    const int N = rng_N(rng);
+    const int M = rng_M(rng);
+    int total = 0;
+    costs.clear();
+    for (int i = 0; i < N; ++i) {
+      costs.push_back(rng_e(rng));
+      total += costs.back();
+    }
+
+    cumulative_costs.resize(N);
+    std::partial_sum(costs.begin(), costs.end(), cumulative_costs.begin());
+
+    std::uniform_int_distribution<int> rng_seg(0, N - 1);
+    int start = rng_seg(rng);
+    int end = rng_seg(rng);
+    if (start > end) std::swap(start, end);
+    ++end;
+
+    int first_admissible = 0;
+    for (int threshold = 1; threshold <= total; ++threshold) {
+      const bool bruteforce =
+          BruteForcePartition(costs.data(), start, end, M, threshold);
+      if (bruteforce) {
+        first_admissible = threshold;
+        break;
+      }
+    }
+    EXPECT_TRUE(first_admissible != 0 || total == 0);
+    partition = PartitionRangeForParallelFor(
+        start, end, M, cumulative_costs.data(), dummy_getter);
+    ASSERT_GT(partition.size(), 1);
+    EXPECT_EQ(partition.front(), start);
+    EXPECT_EQ(partition.back(), end);
+
+    const int num_partitions = partition.size() - 1;
+    EXPECT_LE(num_partitions, M);
+    for (int j = 0; j < num_partitions; ++j) {
+      int total = 0;
+      for (int k = partition[j]; k < partition[j + 1]; ++k) {
+        EXPECT_LT(k, end);
+        EXPECT_GE(k, start);
+        total += costs[k];
+      }
+      EXPECT_LE(total, first_admissible);
+    }
+  }
+}
+
+// Recursively try to partition range into segements of total cost
+// less than max_cost
+bool BruteForcePartition(
+    int* costs, int start, int end, int max_partitions, int max_cost) {
+  if (start == end) return true;
+  if (start < end && max_partitions == 0) return false;
+  int total_cost = 0;
+  for (int last_curr = start + 1; last_curr <= end; ++last_curr) {
+    total_cost += costs[last_curr - 1];
+    if (total_cost > max_cost) break;
+    if (BruteForcePartition(
+            costs, last_curr, end, max_partitions - 1, max_cost))
+      return true;
+  }
+  return false;
+}
+
+// Tests if guided parallel for loop computes the correct result for various
+// number of threads.
+TEST(GuidedParallelFor, NumThreads) {
+  ContextImpl context;
+  context.EnsureMinimumThreads(/*num_threads=*/2);
+
+  const int size = 16;
+  std::vector<int> expected_results(size, 0);
+  for (int i = 0; i < size; ++i) {
+    expected_results[i] = std::sqrt(i);
+  }
+
+  std::vector<int> costs, cumulative_costs;
+  for (int i = 1; i <= size; ++i) {
+    int cost = i * i;
+    costs.push_back(cost);
+    if (i == 1) {
+      cumulative_costs.push_back(cost);
+    } else {
+      cumulative_costs.push_back(cost + cumulative_costs.back());
+    }
+  }
+
+  for (int num_threads = 1; num_threads <= 8; ++num_threads) {
+    std::vector<int> values(size, 0);
+    ParallelFor(
+        &context,
+        0,
+        size,
+        num_threads,
+        [&values](int i) { values[i] = std::sqrt(i); },
+        cumulative_costs.data(),
+        [](const int v) { return v; });
+    EXPECT_THAT(values, ElementsAreArray(expected_results));
+  }
+}
+
+TEST(ParallelAssign, D2MulX) {
+  const int kVectorSize = 1024 * 1024;
+  const int kMaxNumThreads = 8;
+  const double kEpsilon = 1e-16;
+
+  const Vector D_full = Vector::Random(kVectorSize * 2);
+  const ConstVectorRef D(D_full.data() + kVectorSize, kVectorSize);
+  const Vector x = Vector::Random(kVectorSize);
+  const Vector y_expected = D.array().square() * x.array();
+  ContextImpl context;
+  context.EnsureMinimumThreads(kMaxNumThreads);
+
+  for (int num_threads = 1; num_threads <= kMaxNumThreads; ++num_threads) {
+    Vector y_observed(kVectorSize);
+    ParallelAssign(
+        &context, num_threads, y_observed, D.array().square() * x.array());
+
+    // We might get non-bit-exact result due to different precision in scalar
+    // and vector code. For example, in x86 mode mingw might emit x87
+    // instructions for scalar code, thus making bit-exact check fail
+    EXPECT_NEAR((y_expected - y_observed).squaredNorm(),
+                0.,
+                kEpsilon * y_expected.squaredNorm());
+  }
+}
+
+TEST(ParallelAssign, SetZero) {
+  const int kVectorSize = 1024 * 1024;
+  const int kMaxNumThreads = 8;
+
+  ContextImpl context;
+  context.EnsureMinimumThreads(kMaxNumThreads);
+
+  for (int num_threads = 1; num_threads <= kMaxNumThreads; ++num_threads) {
+    Vector x = Vector::Random(kVectorSize);
+    ParallelSetZero(&context, num_threads, x);
+
+    CHECK_EQ(x.squaredNorm(), 0.);
+  }
+}
+
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/parallel_invoke.cc b/third_party/ceres/internal/ceres/parallel_invoke.cc
new file mode 100644
index 0000000..0e387c5
--- /dev/null
+++ b/third_party/ceres/internal/ceres/parallel_invoke.cc
@@ -0,0 +1,77 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: vitus@google.com (Michael Vitus)
+
+#include <algorithm>
+#include <atomic>
+#include <cmath>
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+#include <tuple>
+
+#include "ceres/internal/config.h"
+#include "ceres/parallel_for.h"
+#include "ceres/parallel_vector_ops.h"
+#include "glog/logging.h"
+
+namespace ceres::internal {
+
+BlockUntilFinished::BlockUntilFinished(int num_total_jobs)
+    : num_total_jobs_finished_(0), num_total_jobs_(num_total_jobs) {}
+
+void BlockUntilFinished::Finished(int num_jobs_finished) {
+  if (num_jobs_finished == 0) return;
+  std::lock_guard<std::mutex> lock(mutex_);
+  num_total_jobs_finished_ += num_jobs_finished;
+  CHECK_LE(num_total_jobs_finished_, num_total_jobs_);
+  if (num_total_jobs_finished_ == num_total_jobs_) {
+    condition_.notify_one();
+  }
+}
+
+void BlockUntilFinished::Block() {
+  std::unique_lock<std::mutex> lock(mutex_);
+  condition_.wait(
+      lock, [this]() { return num_total_jobs_finished_ == num_total_jobs_; });
+}
+
+ParallelInvokeState::ParallelInvokeState(int start,
+                                         int end,
+                                         int num_work_blocks)
+    : start(start),
+      end(end),
+      num_work_blocks(num_work_blocks),
+      base_block_size((end - start) / num_work_blocks),
+      num_base_p1_sized_blocks((end - start) % num_work_blocks),
+      block_id(0),
+      thread_id(0),
+      block_until_finished(num_work_blocks) {}
+
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/parallel_invoke.h b/third_party/ceres/internal/ceres/parallel_invoke.h
new file mode 100644
index 0000000..398f8f2
--- /dev/null
+++ b/third_party/ceres/internal/ceres/parallel_invoke.h
@@ -0,0 +1,272 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Authors: vitus@google.com (Michael Vitus),
+//          dmitriy.korchemkin@gmail.com (Dmitriy Korchemkin)
+
+#ifndef CERES_INTERNAL_PARALLEL_INVOKE_H_
+#define CERES_INTERNAL_PARALLEL_INVOKE_H_
+
+#include <atomic>
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+#include <tuple>
+#include <type_traits>
+
+namespace ceres::internal {
+
+// InvokeWithThreadId handles passing thread_id to the function
+template <typename F, typename... Args>
+void InvokeWithThreadId(int thread_id, F&& function, Args&&... args) {
+  constexpr bool kPassThreadId = std::is_invocable_v<F, int, Args...>;
+
+  if constexpr (kPassThreadId) {
+    function(thread_id, std::forward<Args>(args)...);
+  } else {
+    function(std::forward<Args>(args)...);
+  }
+}
+
+// InvokeOnSegment either runs a loop over segment indices or passes it to the
+// function
+template <typename F>
+void InvokeOnSegment(int thread_id, std::tuple<int, int> range, F&& function) {
+  constexpr bool kExplicitLoop =
+      std::is_invocable_v<F, int> || std::is_invocable_v<F, int, int>;
+
+  if constexpr (kExplicitLoop) {
+    const auto [start, end] = range;
+    for (int i = start; i != end; ++i) {
+      InvokeWithThreadId(thread_id, std::forward<F>(function), i);
+    }
+  } else {
+    InvokeWithThreadId(thread_id, std::forward<F>(function), range);
+  }
+}
+
+// This class creates a thread safe barrier which will block until a
+// pre-specified number of threads call Finished.  This allows us to block the
+// main thread until all the parallel threads are finished processing all the
+// work.
+class BlockUntilFinished {
+ public:
+  explicit BlockUntilFinished(int num_total_jobs);
+
+  // Increment the number of jobs that have been processed by the number of
+  // jobs processed by caller and signal the blocking thread if all jobs
+  // have finished.
+  void Finished(int num_jobs_finished);
+
+  // Block until receiving confirmation of all jobs being finished.
+  void Block();
+
+ private:
+  std::mutex mutex_;
+  std::condition_variable condition_;
+  int num_total_jobs_finished_;
+  const int num_total_jobs_;
+};
+
+// Shared state between the parallel tasks. Each thread will use this
+// information to get the next block of work to be performed.
+struct ParallelInvokeState {
+  // The entire range [start, end) is split into num_work_blocks contiguous
+  // disjoint intervals (blocks), which are as equal as possible given
+  // total index count and requested number of  blocks.
+  //
+  // Those num_work_blocks blocks are then processed in parallel.
+  //
+  // Total number of integer indices in interval [start, end) is
+  // end - start, and when splitting them into num_work_blocks blocks
+  // we can either
+  //  - Split into equal blocks when (end - start) is divisible by
+  //    num_work_blocks
+  //  - Split into blocks with size difference at most 1:
+  //     - Size of the smallest block(s) is (end - start) / num_work_blocks
+  //     - (end - start) % num_work_blocks will need to be 1 index larger
+  //
+  // Note that this splitting is optimal in the sense of maximal difference
+  // between block sizes, since splitting into equal blocks is possible
+  // if and only if number of indices is divisible by number of blocks.
+  ParallelInvokeState(int start, int end, int num_work_blocks);
+
+  // The start and end index of the for loop.
+  const int start;
+  const int end;
+  // The number of blocks that need to be processed.
+  const int num_work_blocks;
+  // Size of the smallest block
+  const int base_block_size;
+  // Number of blocks of size base_block_size + 1
+  const int num_base_p1_sized_blocks;
+
+  // The next block of work to be assigned to a worker.  The parallel for loop
+  // range is split into num_work_blocks blocks of work, with a single block of
+  // work being of size
+  //  - base_block_size + 1 for the first num_base_p1_sized_blocks blocks
+  //  - base_block_size for the rest of the blocks
+  //  blocks of indices are contiguous and disjoint
+  std::atomic<int> block_id;
+
+  // Provides a unique thread ID among all active threads
+  // We do not schedule more than num_threads threads via thread pool
+  // and caller thread might steal one ID
+  std::atomic<int> thread_id;
+
+  // Used to signal when all the work has been completed.  Thread safe.
+  BlockUntilFinished block_until_finished;
+};
+
+// This implementation uses a fixed size max worker pool with a shared task
+// queue. The problem of executing the function for the interval of [start, end)
+// is broken up into at most num_threads * kWorkBlocksPerThread blocks (each of
+// size at least min_block_size) and added to the thread pool. To avoid
+// deadlocks, the calling thread is allowed to steal work from the worker pool.
+// This is implemented via a shared state between the tasks. In order for
+// the calling thread or thread pool to get a block of work, it will query the
+// shared state for the next block of work to be done. If there is nothing left,
+// it will return. We will exit the ParallelFor call when all of the work has
+// been done, not when all of the tasks have been popped off the task queue.
+//
+// A unique thread ID among all active tasks will be acquired once for each
+// block of work.  This avoids the significant performance penalty for acquiring
+// it on every iteration of the for loop. The thread ID is guaranteed to be in
+// [0, num_threads).
+//
+// A performance analysis has shown this implementation is on par with OpenMP
+// and TBB.
+template <typename F>
+void ParallelInvoke(ContextImpl* context,
+                    int start,
+                    int end,
+                    int num_threads,
+                    F&& function,
+                    int min_block_size) {
+  CHECK(context != nullptr);
+
+  // Maximal number of work items scheduled for a single thread
+  //  - Lower number of work items results in larger runtimes on unequal tasks
+  //  - Higher number of work items results in larger losses for synchronization
+  constexpr int kWorkBlocksPerThread = 4;
+
+  // Interval [start, end) is being split into
+  // num_threads * kWorkBlocksPerThread contiguous disjoint blocks.
+  //
+  // In order to avoid creating empty blocks of work, we need to limit
+  // number of work blocks by a total number of indices.
+  const int num_work_blocks = std::min((end - start) / min_block_size,
+                                       num_threads * kWorkBlocksPerThread);
+
+  // We use a std::shared_ptr because the main thread can finish all
+  // the work before the tasks have been popped off the queue.  So the
+  // shared state needs to exist for the duration of all the tasks.
+  auto shared_state =
+      std::make_shared<ParallelInvokeState>(start, end, num_work_blocks);
+
+  // A function which tries to schedule another task in the thread pool and
+  // perform several chunks of work. Function expects itself as the argument in
+  // order to schedule next task in the thread pool.
+  auto task = [context, shared_state, num_threads, &function](auto& task_copy) {
+    int num_jobs_finished = 0;
+    const int thread_id = shared_state->thread_id.fetch_add(1);
+    // In order to avoid dead-locks in nested parallel for loops, task() will be
+    // invoked num_threads + 1 times:
+    //  - num_threads times via enqueueing task into thread pool
+    //  - one more time in the main thread
+    //  Tasks enqueued to thread pool might take some time before execution, and
+    //  the last task being executed will be terminated here in order to avoid
+    //  having more than num_threads active threads
+    if (thread_id >= num_threads) return;
+    const int num_work_blocks = shared_state->num_work_blocks;
+    if (thread_id + 1 < num_threads &&
+        shared_state->block_id < num_work_blocks) {
+      // Add another thread to the thread pool.
+      // Note we are taking the task as value so the copy of shared_state shared
+      // pointer (captured by value at declaration of task lambda-function) is
+      // copied and the ref count is increased. This is to prevent it from being
+      // deleted when the main thread finishes all the work and exits before the
+      // threads finish.
+      context->thread_pool.AddTask([task_copy]() { task_copy(task_copy); });
+    }
+
+    const int start = shared_state->start;
+    const int base_block_size = shared_state->base_block_size;
+    const int num_base_p1_sized_blocks = shared_state->num_base_p1_sized_blocks;
+
+    while (true) {
+      // Get the next available chunk of work to be performed. If there is no
+      // work, return.
+      int block_id = shared_state->block_id.fetch_add(1);
+      if (block_id >= num_work_blocks) {
+        break;
+      }
+      ++num_jobs_finished;
+
+      // For-loop interval [start, end) was split into num_work_blocks,
+      // with num_base_p1_sized_blocks of size base_block_size + 1 and remaining
+      // num_work_blocks - num_base_p1_sized_blocks of size base_block_size
+      //
+      // Then, start index of the block #block_id is given by a total
+      // length of preceeding blocks:
+      //  * Total length of preceeding blocks of size base_block_size + 1:
+      //     min(block_id, num_base_p1_sized_blocks) * (base_block_size + 1)
+      //
+      //  * Total length of preceeding blocks of size base_block_size:
+      //     (block_id - min(block_id, num_base_p1_sized_blocks)) *
+      //     base_block_size
+      //
+      // Simplifying sum of those quantities yields a following
+      // expression for start index of the block #block_id
+      const int curr_start = start + block_id * base_block_size +
+                             std::min(block_id, num_base_p1_sized_blocks);
+      // First num_base_p1_sized_blocks have size base_block_size + 1
+      //
+      // Note that it is guaranteed that all blocks are within
+      // [start, end) interval
+      const int curr_end = curr_start + base_block_size +
+                           (block_id < num_base_p1_sized_blocks ? 1 : 0);
+      // Perform each task in current block
+      const auto range = std::make_tuple(curr_start, curr_end);
+      InvokeOnSegment(thread_id, range, function);
+    }
+    shared_state->block_until_finished.Finished(num_jobs_finished);
+  };
+
+  // Start scheduling threads and doing work. We might end up with less threads
+  // scheduled than expected, if scheduling overhead is larger than the amount
+  // of work to be done.
+  task(task);
+
+  // Wait until all tasks have finished.
+  shared_state->block_until_finished.Block();
+}
+
+}  // namespace ceres::internal
+
+#endif
diff --git a/third_party/ceres/internal/ceres/parallel_utils.cc b/third_party/ceres/internal/ceres/parallel_utils.cc
index e1cb5f9..2e6ee13 100644
--- a/third_party/ceres/internal/ceres/parallel_utils.cc
+++ b/third_party/ceres/internal/ceres/parallel_utils.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -30,8 +30,7 @@
 
 #include "ceres/parallel_utils.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 void LinearIndexToUpperTriangularIndex(int k, int n, int* i, int* j) {
   // This works by unfolding a rectangle into a triangle.
@@ -86,5 +85,4 @@
   }
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/parallel_utils.h b/third_party/ceres/internal/ceres/parallel_utils.h
index 89d2110..2a7925f 100644
--- a/third_party/ceres/internal/ceres/parallel_utils.h
+++ b/third_party/ceres/internal/ceres/parallel_utils.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -31,10 +31,9 @@
 #ifndef CERES_INTERNAL_PARALLEL_UTILS_H_
 #define CERES_INTERNAL_PARALLEL_UTILS_H_
 
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // Converts a linear iteration order into a triangular iteration order.
 // Suppose you have nested loops that look like
@@ -61,12 +60,11 @@
 //    });
 // which in each iteration will produce i and j satisfying
 // 0 <= i <= j < n
-CERES_EXPORT_INTERNAL void LinearIndexToUpperTriangularIndex(int k,
-                                                             int n,
-                                                             int* i,
-                                                             int* j);
+CERES_NO_EXPORT void LinearIndexToUpperTriangularIndex(int k,
+                                                       int n,
+                                                       int* i,
+                                                       int* j);
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_INTERNAL_PARALLEL_UTILS_H_
diff --git a/third_party/ceres/internal/ceres/parallel_utils_test.cc b/third_party/ceres/internal/ceres/parallel_utils_test.cc
index 53870bb..bea6f0d 100644
--- a/third_party/ceres/internal/ceres/parallel_utils_test.cc
+++ b/third_party/ceres/internal/ceres/parallel_utils_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -28,18 +28,13 @@
 //
 // Author: wjr@google.com (William Rucklidge)
 
-// This include must come before any #ifndef check on Ceres compile options.
-// clang-format off
-#include "ceres/internal/port.h"
-// clang-format on
-
 #include "ceres/parallel_utils.h"
 
+#include "ceres/internal/config.h"
 #include "glog/logging.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // Tests that unfolding linear iterations to triangular iterations produces
 // indices that are in-range and unique.
@@ -60,5 +55,4 @@
   }
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/parallel_vector_operations_benchmark.cc b/third_party/ceres/internal/ceres/parallel_vector_operations_benchmark.cc
new file mode 100644
index 0000000..8b55def
--- /dev/null
+++ b/third_party/ceres/internal/ceres/parallel_vector_operations_benchmark.cc
@@ -0,0 +1,326 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+
+#include <algorithm>
+
+#include "benchmark/benchmark.h"
+#include "ceres/eigen_vector_ops.h"
+#include "ceres/parallel_for.h"
+
+namespace ceres::internal {
+// Older versions of benchmark library (for example, one shipped with
+// ubuntu 20.04) do not support range generation and range products
+#define VECTOR_SIZES(num_threads)    \
+      Args({1 << 7, num_threads})    \
+      ->Args({1 << 8, num_threads})  \
+      ->Args({1 << 9, num_threads})  \
+      ->Args({1 << 10, num_threads}) \
+      ->Args({1 << 11, num_threads}) \
+      ->Args({1 << 12, num_threads}) \
+      ->Args({1 << 13, num_threads}) \
+      ->Args({1 << 14, num_threads}) \
+      ->Args({1 << 15, num_threads}) \
+      ->Args({1 << 16, num_threads}) \
+      ->Args({1 << 17, num_threads}) \
+      ->Args({1 << 18, num_threads}) \
+      ->Args({1 << 19, num_threads}) \
+      ->Args({1 << 20, num_threads}) \
+      ->Args({1 << 21, num_threads}) \
+      ->Args({1 << 22, num_threads}) \
+      ->Args({1 << 23, num_threads})
+
+#define VECTOR_SIZE_THREADS \
+  VECTOR_SIZES(1)           \
+      ->VECTOR_SIZES(2)     \
+      ->VECTOR_SIZES(4)     \
+      ->VECTOR_SIZES(8)     \
+      ->VECTOR_SIZES(16)
+
+static void SetZero(benchmark::State& state) {
+  const int kVectorSize = static_cast<int>(state.range(0));
+  Vector x = Vector::Random(kVectorSize);
+  for (auto _ : state) {
+    x.setZero();
+  }
+  CHECK_EQ(x.squaredNorm(), 0.);
+}
+BENCHMARK(SetZero)->VECTOR_SIZES(1);
+
+static void SetZeroParallel(benchmark::State& state) {
+  const int kVectorSize = static_cast<int>(state.range(0));
+  const int num_threads = static_cast<int>(state.range(1));
+  ContextImpl context;
+  context.EnsureMinimumThreads(num_threads);
+
+  Vector x = Vector::Random(kVectorSize);
+  for (auto _ : state) {
+    ParallelSetZero(&context, num_threads, x);
+  }
+  CHECK_EQ(x.squaredNorm(), 0.);
+}
+BENCHMARK(SetZeroParallel)->VECTOR_SIZE_THREADS;
+
+static void Negate(benchmark::State& state) {
+  const int kVectorSize = static_cast<int>(state.range(0));
+  Vector x = Vector::Random(kVectorSize).normalized();
+  const Vector x_init = x;
+
+  for (auto _ : state) {
+    x = -x;
+  }
+  CHECK((x - x_init).squaredNorm() == 0. || (x + x_init).squaredNorm() == 0);
+}
+BENCHMARK(Negate)->VECTOR_SIZES(1);
+
+static void NegateParallel(benchmark::State& state) {
+  const int kVectorSize = static_cast<int>(state.range(0));
+  const int num_threads = static_cast<int>(state.range(1));
+  ContextImpl context;
+  context.EnsureMinimumThreads(num_threads);
+
+  Vector x = Vector::Random(kVectorSize).normalized();
+  const Vector x_init = x;
+
+  for (auto _ : state) {
+    ParallelAssign(&context, num_threads, x, -x);
+  }
+  CHECK((x - x_init).squaredNorm() == 0. || (x + x_init).squaredNorm() == 0);
+}
+BENCHMARK(NegateParallel)->VECTOR_SIZE_THREADS;
+
+static void Assign(benchmark::State& state) {
+  const int kVectorSize = static_cast<int>(state.range(0));
+  Vector x = Vector::Random(kVectorSize);
+  Vector y = Vector(kVectorSize);
+  for (auto _ : state) {
+    y.block(0, 0, kVectorSize, 1) = x.block(0, 0, kVectorSize, 1);
+  }
+  CHECK_EQ((y - x).squaredNorm(), 0.);
+}
+BENCHMARK(Assign)->VECTOR_SIZES(1);
+
+static void AssignParallel(benchmark::State& state) {
+  const int kVectorSize = static_cast<int>(state.range(0));
+  const int num_threads = static_cast<int>(state.range(1));
+  ContextImpl context;
+  context.EnsureMinimumThreads(num_threads);
+
+  Vector x = Vector::Random(kVectorSize);
+  Vector y = Vector(kVectorSize);
+
+  for (auto _ : state) {
+    ParallelAssign(&context, num_threads, y, x);
+  }
+  CHECK_EQ((y - x).squaredNorm(), 0.);
+}
+BENCHMARK(AssignParallel)->VECTOR_SIZE_THREADS;
+
+static void D2X(benchmark::State& state) {
+  const int kVectorSize = static_cast<int>(state.range(0));
+  const Vector x = Vector::Random(kVectorSize);
+  const Vector D = Vector::Random(kVectorSize);
+  Vector y = Vector::Zero(kVectorSize);
+  for (auto _ : state) {
+    y = D.array().square() * x.array();
+  }
+  CHECK_GT(y.squaredNorm(), 0.);
+}
+BENCHMARK(D2X)->VECTOR_SIZES(1);
+
+static void D2XParallel(benchmark::State& state) {
+  const int kVectorSize = static_cast<int>(state.range(0));
+  const int num_threads = static_cast<int>(state.range(1));
+  ContextImpl context;
+  context.EnsureMinimumThreads(num_threads);
+
+  const Vector x = Vector::Random(kVectorSize);
+  const Vector D = Vector::Random(kVectorSize);
+  Vector y = Vector(kVectorSize);
+
+  for (auto _ : state) {
+    ParallelAssign(&context, num_threads, y, D.array().square() * x.array());
+  }
+  CHECK_GT(y.squaredNorm(), 0.);
+}
+BENCHMARK(D2XParallel)->VECTOR_SIZE_THREADS;
+
+static void DivideSqrt(benchmark::State& state) {
+  const int kVectorSize = static_cast<int>(state.range(0));
+  Vector diagonal = Vector::Random(kVectorSize).array().abs();
+  const double radius = 0.5;
+  for (auto _ : state) {
+    diagonal = (diagonal / radius).array().sqrt();
+  }
+  CHECK_GT(diagonal.squaredNorm(), 0.);
+}
+BENCHMARK(DivideSqrt)->VECTOR_SIZES(1);
+
+static void DivideSqrtParallel(benchmark::State& state) {
+  const int kVectorSize = static_cast<int>(state.range(0));
+  const int num_threads = static_cast<int>(state.range(1));
+  ContextImpl context;
+  context.EnsureMinimumThreads(num_threads);
+
+  Vector diagonal = Vector::Random(kVectorSize).array().abs();
+  const double radius = 0.5;
+  for (auto _ : state) {
+    ParallelAssign(
+        &context, num_threads, diagonal, (diagonal / radius).cwiseSqrt());
+  }
+  CHECK_GT(diagonal.squaredNorm(), 0.);
+}
+BENCHMARK(DivideSqrtParallel)->VECTOR_SIZE_THREADS;
+
+static void Clamp(benchmark::State& state) {
+  const int kVectorSize = static_cast<int>(state.range(0));
+  Vector diagonal = Vector::Random(kVectorSize);
+  const double min = -0.5;
+  const double max = 0.5;
+  for (auto _ : state) {
+    for (int i = 0; i < kVectorSize; ++i) {
+      diagonal[i] = std::min(std::max(diagonal[i], min), max);
+    }
+  }
+  CHECK_LE(diagonal.maxCoeff(), 0.5);
+  CHECK_GE(diagonal.minCoeff(), -0.5);
+}
+BENCHMARK(Clamp)->VECTOR_SIZES(1);
+
+static void ClampParallel(benchmark::State& state) {
+  const int kVectorSize = static_cast<int>(state.range(0));
+  const int num_threads = static_cast<int>(state.range(1));
+  ContextImpl context;
+  context.EnsureMinimumThreads(num_threads);
+
+  Vector diagonal = Vector::Random(kVectorSize);
+  const double min = -0.5;
+  const double max = 0.5;
+  for (auto _ : state) {
+    ParallelAssign(
+        &context, num_threads, diagonal, diagonal.array().max(min).min(max));
+  }
+  CHECK_LE(diagonal.maxCoeff(), 0.5);
+  CHECK_GE(diagonal.minCoeff(), -0.5);
+}
+BENCHMARK(ClampParallel)->VECTOR_SIZE_THREADS;
+
+static void Norm(benchmark::State& state) {
+  const int kVectorSize = static_cast<int>(state.range(0));
+  const Vector x = Vector::Random(kVectorSize);
+
+  double total = 0.;
+  for (auto _ : state) {
+    total += x.norm();
+  }
+  CHECK_GT(total, 0.);
+}
+BENCHMARK(Norm)->VECTOR_SIZES(1);
+
+static void NormParallel(benchmark::State& state) {
+  const int kVectorSize = static_cast<int>(state.range(0));
+  const int num_threads = static_cast<int>(state.range(1));
+  ContextImpl context;
+  context.EnsureMinimumThreads(num_threads);
+
+  const Vector x = Vector::Random(kVectorSize);
+
+  double total = 0.;
+  for (auto _ : state) {
+    total += Norm(x, &context, num_threads);
+  }
+  CHECK_GT(total, 0.);
+}
+BENCHMARK(NormParallel)->VECTOR_SIZE_THREADS;
+
+static void Dot(benchmark::State& state) {
+  const int kVectorSize = static_cast<int>(state.range(0));
+  const Vector x = Vector::Random(kVectorSize);
+  const Vector y = Vector::Random(kVectorSize);
+
+  double total = 0.;
+  for (auto _ : state) {
+    total += x.dot(y);
+  }
+  CHECK_NE(total, 0.);
+}
+BENCHMARK(Dot)->VECTOR_SIZES(1);
+
+static void DotParallel(benchmark::State& state) {
+  const int kVectorSize = static_cast<int>(state.range(0));
+  const int num_threads = static_cast<int>(state.range(1));
+  ContextImpl context;
+  context.EnsureMinimumThreads(num_threads);
+
+  const Vector x = Vector::Random(kVectorSize);
+  const Vector y = Vector::Random(kVectorSize);
+
+  double total = 0.;
+  for (auto _ : state) {
+    total += Dot(x, y, &context, num_threads);
+  }
+  CHECK_NE(total, 0.);
+}
+BENCHMARK(DotParallel)->VECTOR_SIZE_THREADS;
+
+static void Axpby(benchmark::State& state) {
+  const int kVectorSize = static_cast<int>(state.range(0));
+  const Vector x = Vector::Random(kVectorSize);
+  const Vector y = Vector::Random(kVectorSize);
+  Vector z = Vector::Zero(kVectorSize);
+  const double a = 3.1415;
+  const double b = 1.2345;
+
+  for (auto _ : state) {
+    z = a * x + b * y;
+  }
+  CHECK_GT(z.squaredNorm(), 0.);
+}
+BENCHMARK(Axpby)->VECTOR_SIZES(1);
+
+static void AxpbyParallel(benchmark::State& state) {
+  const int kVectorSize = static_cast<int>(state.range(0));
+  const int num_threads = static_cast<int>(state.range(1));
+  ContextImpl context;
+  context.EnsureMinimumThreads(num_threads);
+
+  const Vector x = Vector::Random(kVectorSize);
+  const Vector y = Vector::Random(kVectorSize);
+  Vector z = Vector::Zero(kVectorSize);
+  const double a = 3.1415;
+  const double b = 1.2345;
+
+  for (auto _ : state) {
+    Axpby(a, x, b, y, z, &context, num_threads);
+  }
+  CHECK_GT(z.squaredNorm(), 0.);
+}
+BENCHMARK(AxpbyParallel)->VECTOR_SIZE_THREADS;
+
+}  // namespace ceres::internal
+
+BENCHMARK_MAIN();
diff --git a/third_party/ceres/internal/ceres/parallel_vector_ops.cc b/third_party/ceres/internal/ceres/parallel_vector_ops.cc
new file mode 100644
index 0000000..9ebce29
--- /dev/null
+++ b/third_party/ceres/internal/ceres/parallel_vector_ops.cc
@@ -0,0 +1,54 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+
+#include "ceres/parallel_vector_ops.h"
+
+#include <algorithm>
+#include <tuple>
+
+#include "ceres/context_impl.h"
+#include "ceres/parallel_for.h"
+
+namespace ceres::internal {
+void ParallelSetZero(ContextImpl* context,
+                     int num_threads,
+                     double* values,
+                     int num_values) {
+  ParallelFor(
+      context,
+      0,
+      num_values,
+      num_threads,
+      [values](std::tuple<int, int> range) {
+        auto [start, end] = range;
+        std::fill(values + start, values + end, 0.);
+      },
+      kMinBlockSizeParallelVectorOps);
+}
+
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/parallel_vector_ops.h b/third_party/ceres/internal/ceres/parallel_vector_ops.h
new file mode 100644
index 0000000..812950a
--- /dev/null
+++ b/third_party/ceres/internal/ceres/parallel_vector_ops.h
@@ -0,0 +1,90 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Authors: vitus@google.com (Michael Vitus),
+//          dmitriy.korchemkin@gmail.com (Dmitriy Korchemkin)
+
+#ifndef CERES_INTERNAL_PARALLEL_VECTOR_OPS_H_
+#define CERES_INTERNAL_PARALLEL_VECTOR_OPS_H_
+
+#include <mutex>
+#include <vector>
+
+#include "ceres/context_impl.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/export.h"
+#include "ceres/parallel_for.h"
+
+namespace ceres::internal {
+
+// Lower bound on block size for parallel vector operations.
+// Operations with vectors of less than kMinBlockSizeParallelVectorOps elements
+// will be executed in a single thread.
+constexpr int kMinBlockSizeParallelVectorOps = 1 << 16;
+// Evaluate vector expression in parallel
+// Assuming LhsExpression and RhsExpression are some sort of column-vector
+// expression, assignment lhs = rhs is eavluated over a set of contiguous blocks
+// in parallel. This is expected to work well in the case of vector-based
+// expressions (since they typically do not result into temporaries). This
+// method expects lhs to be size-compatible with rhs
+template <typename LhsExpression, typename RhsExpression>
+void ParallelAssign(ContextImpl* context,
+                    int num_threads,
+                    LhsExpression& lhs,
+                    const RhsExpression& rhs) {
+  static_assert(LhsExpression::ColsAtCompileTime == 1);
+  static_assert(RhsExpression::ColsAtCompileTime == 1);
+  CHECK_EQ(lhs.rows(), rhs.rows());
+  const int num_rows = lhs.rows();
+  ParallelFor(
+      context,
+      0,
+      num_rows,
+      num_threads,
+      [&lhs, &rhs](const std::tuple<int, int>& range) {
+        auto [start, end] = range;
+        lhs.segment(start, end - start) = rhs.segment(start, end - start);
+      },
+      kMinBlockSizeParallelVectorOps);
+}
+
+// Set vector to zero using num_threads
+template <typename VectorType>
+void ParallelSetZero(ContextImpl* context,
+                     int num_threads,
+                     VectorType& vector) {
+  ParallelSetZero(context, num_threads, vector.data(), vector.rows());
+}
+void ParallelSetZero(ContextImpl* context,
+                     int num_threads,
+                     double* values,
+                     int num_values);
+
+}  // namespace ceres::internal
+
+#endif  // CERES_INTERNAL_PARALLEL_FOR_H_
diff --git a/third_party/ceres/internal/ceres/parameter_block.h b/third_party/ceres/internal/ceres/parameter_block.h
index 88943df..925d1c4 100644
--- a/third_party/ceres/internal/ceres/parameter_block.h
+++ b/third_party/ceres/internal/ceres/parameter_block.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,14 +40,14 @@
 #include <unordered_set>
 
 #include "ceres/array_utils.h"
+#include "ceres/internal/disable_warnings.h"
 #include "ceres/internal/eigen.h"
-#include "ceres/internal/port.h"
-#include "ceres/local_parameterization.h"
+#include "ceres/internal/export.h"
+#include "ceres/manifold.h"
 #include "ceres/stringprintf.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 class ProblemImpl;
 class ResidualBlock;
@@ -58,12 +58,12 @@
 // methods are performance sensitive.
 //
 // The class is not thread-safe, unless only const methods are called. The
-// parameter block may also hold a pointer to a local parameterization; the
-// parameter block does not take ownership of this pointer, so the user is
-// responsible for the proper disposal of the local parameterization.
-class ParameterBlock {
+// parameter block may also hold a pointer to a manifold; the parameter block
+// does not take ownership of this pointer, so the user is responsible for the
+// proper disposal of the manifold.
+class CERES_NO_EXPORT ParameterBlock {
  public:
-  typedef std::unordered_set<ResidualBlock*> ResidualBlockSet;
+  using ResidualBlockSet = std::unordered_set<ResidualBlock*>;
 
   // Create a parameter block with the user state, size, and index specified.
   // The size is the size of the parameter block and the index is the position
@@ -74,16 +74,13 @@
         state_(user_state),
         index_(index) {}
 
-  ParameterBlock(double* user_state,
-                 int size,
-                 int index,
-                 LocalParameterization* local_parameterization)
+  ParameterBlock(double* user_state, int size, int index, Manifold* manifold)
       : user_state_(user_state),
         size_(size),
         state_(user_state),
         index_(index) {
-    if (local_parameterization != nullptr) {
-      SetParameterization(local_parameterization);
+    if (manifold != nullptr) {
+      SetManifold(manifold);
     }
   }
 
@@ -98,7 +95,7 @@
                          << "with user location " << user_state_;
 
     state_ = x;
-    return UpdateLocalParameterizationJacobian();
+    return UpdatePlusJacobian();
   }
 
   // Copy the current parameter state out to x. This is "GetState()" rather than
@@ -114,17 +111,13 @@
   const double* state() const { return state_; }
   const double* user_state() const { return user_state_; }
   double* mutable_user_state() { return user_state_; }
-  const LocalParameterization* local_parameterization() const {
-    return local_parameterization_;
-  }
-  LocalParameterization* mutable_local_parameterization() {
-    return local_parameterization_;
-  }
+  const Manifold* manifold() const { return manifold_; }
+  Manifold* mutable_manifold() { return manifold_; }
 
   // Set this parameter block to vary or not.
   void SetConstant() { is_set_constant_ = true; }
   void SetVarying() { is_set_constant_ = false; }
-  bool IsConstant() const { return (is_set_constant_ || LocalSize() == 0); }
+  bool IsConstant() const { return (is_set_constant_ || TangentSize() == 0); }
 
   double UpperBound(int index) const {
     return (upper_bounds_ ? upper_bounds_[index]
@@ -151,51 +144,46 @@
   int delta_offset() const { return delta_offset_; }
   void set_delta_offset(int delta_offset) { delta_offset_ = delta_offset; }
 
-  // Methods relating to the parameter block's parameterization.
+  // Methods relating to the parameter block's manifold.
 
-  // The local to global jacobian. Returns nullptr if there is no local
-  // parameterization for this parameter block. The returned matrix is row-major
-  // and has Size() rows and  LocalSize() columns.
-  const double* LocalParameterizationJacobian() const {
-    return local_parameterization_jacobian_.get();
+  // The local to global jacobian. Returns nullptr if there is no manifold for
+  // this parameter block. The returned matrix is row-major and has Size() rows
+  // and TangentSize() columns.
+  const double* PlusJacobian() const { return plus_jacobian_.get(); }
+
+  int TangentSize() const {
+    return (manifold_ == nullptr) ? size_ : manifold_->TangentSize();
   }
 
-  int LocalSize() const {
-    return (local_parameterization_ == nullptr)
-               ? size_
-               : local_parameterization_->LocalSize();
-  }
-
-  // Set the parameterization. The parameter block does not take
-  // ownership of the parameterization.
-  void SetParameterization(LocalParameterization* new_parameterization) {
-    // Nothing to do if the new parameterization is the same as the
-    // old parameterization.
-    if (new_parameterization == local_parameterization_) {
+  // Set the manifold. The parameter block does not take ownership of
+  // the manifold.
+  void SetManifold(Manifold* new_manifold) {
+    // Nothing to do if the new manifold is the same as the old
+    // manifold.
+    if (new_manifold == manifold_) {
       return;
     }
 
-    if (new_parameterization == nullptr) {
-      local_parameterization_ = nullptr;
+    if (new_manifold == nullptr) {
+      manifold_ = nullptr;
+      plus_jacobian_ = nullptr;
       return;
     }
 
-    CHECK(new_parameterization->GlobalSize() == size_)
-        << "Invalid parameterization for parameter block. The parameter block "
-        << "has size " << size_ << " while the parameterization has a global "
-        << "size of " << new_parameterization->GlobalSize() << ". Did you "
-        << "accidentally use the wrong parameter block or parameterization?";
+    CHECK_EQ(new_manifold->AmbientSize(), size_)
+        << "The parameter block has size = " << size_
+        << " while the manifold has ambient size = "
+        << new_manifold->AmbientSize();
 
-    CHECK_GE(new_parameterization->LocalSize(), 0)
-        << "Invalid parameterization. Parameterizations must have a "
+    CHECK_GE(new_manifold->TangentSize(), 0)
+        << "Invalid Manifold. Manifolds must have a "
         << "non-negative dimensional tangent space.";
 
-    local_parameterization_ = new_parameterization;
-    local_parameterization_jacobian_.reset(
-        new double[local_parameterization_->GlobalSize() *
-                   local_parameterization_->LocalSize()]);
-    CHECK(UpdateLocalParameterizationJacobian())
-        << "Local parameterization Jacobian computation failed for x: "
+    manifold_ = new_manifold;
+    plus_jacobian_ = std::make_unique<double[]>(manifold_->AmbientSize() *
+                                                manifold_->TangentSize());
+    CHECK(UpdatePlusJacobian())
+        << "Manifold::PlusJacobian computation failed for x: "
         << ConstVectorRef(state_, Size()).transpose();
   }
 
@@ -207,7 +195,7 @@
     }
 
     if (!upper_bounds_) {
-      upper_bounds_.reset(new double[size_]);
+      upper_bounds_ = std::make_unique<double[]>(size_);
       std::fill(upper_bounds_.get(),
                 upper_bounds_.get() + size_,
                 std::numeric_limits<double>::max());
@@ -224,7 +212,7 @@
     }
 
     if (!lower_bounds_) {
-      lower_bounds_.reset(new double[size_]);
+      lower_bounds_ = std::make_unique<double[]>(size_);
       std::fill(lower_bounds_.get(),
                 lower_bounds_.get() + size_,
                 -std::numeric_limits<double>::max());
@@ -234,11 +222,11 @@
   }
 
   // Generalization of the addition operation. This is the same as
-  // LocalParameterization::Plus() followed by projection onto the
+  // Manifold::Plus() followed by projection onto the
   // hyper cube implied by the bounds constraints.
   bool Plus(const double* x, const double* delta, double* x_plus_delta) {
-    if (local_parameterization_ != nullptr) {
-      if (!local_parameterization_->Plus(x, delta, x_plus_delta)) {
+    if (manifold_ != nullptr) {
+      if (!manifold_->Plus(x, delta, x_plus_delta)) {
         return false;
       }
     } else {
@@ -281,7 +269,7 @@
     CHECK(residual_blocks_.get() == nullptr)
         << "Ceres bug: There is already a residual block collection "
         << "for parameter block: " << ToString();
-    residual_blocks_.reset(new ResidualBlockSet);
+    residual_blocks_ = std::make_unique<ResidualBlockSet>();
   }
 
   void AddResidualBlock(ResidualBlock* residual_block) {
@@ -321,33 +309,30 @@
   }
 
  private:
-  bool UpdateLocalParameterizationJacobian() {
-    if (local_parameterization_ == nullptr) {
+  bool UpdatePlusJacobian() {
+    if (manifold_ == nullptr) {
       return true;
     }
 
-    // Update the local to global Jacobian. In some cases this is
+    // Update the Plus Jacobian. In some cases this is
     // wasted effort; if this is a bottleneck, we will find a solution
     // at that time.
-
-    const int jacobian_size = Size() * LocalSize();
-    InvalidateArray(jacobian_size, local_parameterization_jacobian_.get());
-    if (!local_parameterization_->ComputeJacobian(
-            state_, local_parameterization_jacobian_.get())) {
-      LOG(WARNING) << "Local parameterization Jacobian computation failed"
+    const int jacobian_size = Size() * TangentSize();
+    InvalidateArray(jacobian_size, plus_jacobian_.get());
+    if (!manifold_->PlusJacobian(state_, plus_jacobian_.get())) {
+      LOG(WARNING) << "Manifold::PlusJacobian computation failed"
                       "for x: "
                    << ConstVectorRef(state_, Size()).transpose();
       return false;
     }
 
-    if (!IsArrayValid(jacobian_size, local_parameterization_jacobian_.get())) {
-      LOG(WARNING) << "Local parameterization Jacobian computation returned"
+    if (!IsArrayValid(jacobian_size, plus_jacobian_.get())) {
+      LOG(WARNING) << "Manifold::PlusJacobian computation returned "
                    << "an invalid matrix for x: "
                    << ConstVectorRef(state_, Size()).transpose()
                    << "\n Jacobian matrix : "
-                   << ConstMatrixRef(local_parameterization_jacobian_.get(),
-                                     Size(),
-                                     LocalSize());
+                   << ConstMatrixRef(
+                          plus_jacobian_.get(), Size(), TangentSize());
       return false;
     }
     return true;
@@ -356,14 +341,14 @@
   double* user_state_ = nullptr;
   int size_ = -1;
   bool is_set_constant_ = false;
-  LocalParameterization* local_parameterization_ = nullptr;
+  Manifold* manifold_ = nullptr;
 
   // The "state" of the parameter. These fields are only needed while the
   // solver is running. While at first glance using mutable is a bad idea, this
   // ends up simplifying the internals of Ceres enough to justify the potential
   // pitfalls of using "mutable."
   mutable const double* state_ = nullptr;
-  mutable std::unique_ptr<double[]> local_parameterization_jacobian_;
+  mutable std::unique_ptr<double[]> plus_jacobian_;
 
   // The index of the parameter. This is used by various other parts of Ceres to
   // permit switching from a ParameterBlock* to an index in another array.
@@ -392,11 +377,12 @@
   std::unique_ptr<double[]> upper_bounds_;
   std::unique_ptr<double[]> lower_bounds_;
 
-  // Necessary so ProblemImpl can clean up the parameterizations.
+  // Necessary so ProblemImpl can clean up the manifolds.
   friend class ProblemImpl;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_PARAMETER_BLOCK_H_
diff --git a/third_party/ceres/internal/ceres/parameter_block_ordering.cc b/third_party/ceres/internal/ceres/parameter_block_ordering.cc
index 9899c24..2b8bf6e 100644
--- a/third_party/ceres/internal/ceres/parameter_block_ordering.cc
+++ b/third_party/ceres/internal/ceres/parameter_block_ordering.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -30,8 +30,11 @@
 
 #include "ceres/parameter_block_ordering.h"
 
+#include <map>
 #include <memory>
+#include <set>
 #include <unordered_set>
+#include <vector>
 
 #include "ceres/graph.h"
 #include "ceres/graph_algorithms.h"
@@ -42,26 +45,22 @@
 #include "ceres/wall_time.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
-
-using std::map;
-using std::set;
-using std::vector;
+namespace ceres::internal {
 
 int ComputeStableSchurOrdering(const Program& program,
-                               vector<ParameterBlock*>* ordering) {
+                               std::vector<ParameterBlock*>* ordering) {
   CHECK(ordering != nullptr);
   ordering->clear();
   EventLogger event_logger("ComputeStableSchurOrdering");
-  std::unique_ptr<Graph<ParameterBlock*>> graph(CreateHessianGraph(program));
+  auto graph = CreateHessianGraph(program);
   event_logger.AddEvent("CreateHessianGraph");
 
-  const vector<ParameterBlock*>& parameter_blocks = program.parameter_blocks();
+  const std::vector<ParameterBlock*>& parameter_blocks =
+      program.parameter_blocks();
   const std::unordered_set<ParameterBlock*>& vertices = graph->vertices();
-  for (int i = 0; i < parameter_blocks.size(); ++i) {
-    if (vertices.count(parameter_blocks[i]) > 0) {
-      ordering->push_back(parameter_blocks[i]);
+  for (auto* parameter_block : parameter_blocks) {
+    if (vertices.count(parameter_block) > 0) {
+      ordering->push_back(parameter_block);
     }
   }
   event_logger.AddEvent("Preordering");
@@ -70,8 +69,7 @@
   event_logger.AddEvent("StableIndependentSet");
 
   // Add the excluded blocks to back of the ordering vector.
-  for (int i = 0; i < parameter_blocks.size(); ++i) {
-    ParameterBlock* parameter_block = parameter_blocks[i];
+  for (auto* parameter_block : parameter_blocks) {
     if (parameter_block->IsConstant()) {
       ordering->push_back(parameter_block);
     }
@@ -82,17 +80,17 @@
 }
 
 int ComputeSchurOrdering(const Program& program,
-                         vector<ParameterBlock*>* ordering) {
+                         std::vector<ParameterBlock*>* ordering) {
   CHECK(ordering != nullptr);
   ordering->clear();
 
-  std::unique_ptr<Graph<ParameterBlock*>> graph(CreateHessianGraph(program));
+  auto graph = CreateHessianGraph(program);
   int independent_set_size = IndependentSetOrdering(*graph, ordering);
-  const vector<ParameterBlock*>& parameter_blocks = program.parameter_blocks();
+  const std::vector<ParameterBlock*>& parameter_blocks =
+      program.parameter_blocks();
 
   // Add the excluded blocks to back of the ordering vector.
-  for (int i = 0; i < parameter_blocks.size(); ++i) {
-    ParameterBlock* parameter_block = parameter_blocks[i];
+  for (auto* parameter_block : parameter_blocks) {
     if (parameter_block->IsConstant()) {
       ordering->push_back(parameter_block);
     }
@@ -105,13 +103,14 @@
                                             ParameterBlockOrdering* ordering) {
   CHECK(ordering != nullptr);
   ordering->Clear();
-  const vector<ParameterBlock*> parameter_blocks = program.parameter_blocks();
-  std::unique_ptr<Graph<ParameterBlock*>> graph(CreateHessianGraph(program));
+  const std::vector<ParameterBlock*> parameter_blocks =
+      program.parameter_blocks();
+  auto graph = CreateHessianGraph(program);
 
   int num_covered = 0;
   int round = 0;
   while (num_covered < parameter_blocks.size()) {
-    vector<ParameterBlock*> independent_set_ordering;
+    std::vector<ParameterBlock*> independent_set_ordering;
     const int independent_set_size =
         IndependentSetOrdering(*graph, &independent_set_ordering);
     for (int i = 0; i < independent_set_size; ++i) {
@@ -124,20 +123,21 @@
   }
 }
 
-Graph<ParameterBlock*>* CreateHessianGraph(const Program& program) {
-  Graph<ParameterBlock*>* graph = new Graph<ParameterBlock*>;
+std::unique_ptr<Graph<ParameterBlock*>> CreateHessianGraph(
+    const Program& program) {
+  auto graph = std::make_unique<Graph<ParameterBlock*>>();
   CHECK(graph != nullptr);
-  const vector<ParameterBlock*>& parameter_blocks = program.parameter_blocks();
-  for (int i = 0; i < parameter_blocks.size(); ++i) {
-    ParameterBlock* parameter_block = parameter_blocks[i];
+  const std::vector<ParameterBlock*>& parameter_blocks =
+      program.parameter_blocks();
+  for (auto* parameter_block : parameter_blocks) {
     if (!parameter_block->IsConstant()) {
       graph->AddVertex(parameter_block);
     }
   }
 
-  const vector<ResidualBlock*>& residual_blocks = program.residual_blocks();
-  for (int i = 0; i < residual_blocks.size(); ++i) {
-    const ResidualBlock* residual_block = residual_blocks[i];
+  const std::vector<ResidualBlock*>& residual_blocks =
+      program.residual_blocks();
+  for (auto* residual_block : residual_blocks) {
     const int num_parameter_blocks = residual_block->NumParameterBlocks();
     ParameterBlock* const* parameter_blocks =
         residual_block->parameter_blocks();
@@ -160,19 +160,20 @@
 }
 
 void OrderingToGroupSizes(const ParameterBlockOrdering* ordering,
-                          vector<int>* group_sizes) {
+                          std::vector<int>* group_sizes) {
   CHECK(group_sizes != nullptr);
   group_sizes->clear();
-  if (ordering == NULL) {
+  if (ordering == nullptr) {
     return;
   }
 
-  const map<int, set<double*>>& group_to_elements =
+  // TODO(sameeragarwal): Investigate if this should be a set or an
+  // unordered_set.
+  const std::map<int, std::set<double*>>& group_to_elements =
       ordering->group_to_elements();
   for (const auto& g_t_e : group_to_elements) {
     group_sizes->push_back(g_t_e.second.size());
   }
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/parameter_block_ordering.h b/third_party/ceres/internal/ceres/parameter_block_ordering.h
index 82ab75d..2ec3db7 100644
--- a/third_party/ceres/internal/ceres/parameter_block_ordering.h
+++ b/third_party/ceres/internal/ceres/parameter_block_ordering.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -31,22 +31,23 @@
 #ifndef CERES_INTERNAL_PARAMETER_BLOCK_ORDERING_H_
 #define CERES_INTERNAL_PARAMETER_BLOCK_ORDERING_H_
 
+#include <memory>
 #include <vector>
 
 #include "ceres/graph.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 #include "ceres/ordered_groups.h"
 #include "ceres/types.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 class Program;
 class ParameterBlock;
 
 // Uses an approximate independent set ordering to order the parameter
-// blocks of a problem so that it is suitable for use with Schur
-// complement based solvers. The output variable ordering contains an
+// blocks of a problem so that it is suitable for use with Schur-
+// complement-based solvers. The output variable ordering contains an
 // ordering of the parameter blocks and the return value is size of
 // the independent set or the number of e_blocks (see
 // schur_complement_solver.h for an explanation). Constant parameters
@@ -57,20 +58,20 @@
 // ordering = [independent set,
 //             complement of the independent set,
 //             fixed blocks]
-CERES_EXPORT_INTERNAL int ComputeSchurOrdering(
+CERES_NO_EXPORT int ComputeSchurOrdering(
     const Program& program, std::vector<ParameterBlock*>* ordering);
 
 // Same as above, except that ties while computing the independent set
 // ordering are resolved in favour of the order in which the parameter
 // blocks occur in the program.
-CERES_EXPORT_INTERNAL int ComputeStableSchurOrdering(
+CERES_NO_EXPORT int ComputeStableSchurOrdering(
     const Program& program, std::vector<ParameterBlock*>* ordering);
 
 // Use an approximate independent set ordering to decompose the
 // parameter blocks of a problem in a sequence of independent
 // sets. The ordering covers all the non-constant parameter blocks in
 // the program.
-CERES_EXPORT_INTERNAL void ComputeRecursiveIndependentSetOrdering(
+CERES_NO_EXPORT void ComputeRecursiveIndependentSetOrdering(
     const Program& program, ParameterBlockOrdering* ordering);
 
 // Builds a graph on the parameter blocks of a Problem, whose
@@ -78,15 +79,16 @@
 // vertex corresponds to a parameter block in the Problem except for
 // parameter blocks that are marked constant. An edge connects two
 // parameter blocks, if they co-occur in a residual block.
-CERES_EXPORT_INTERNAL Graph<ParameterBlock*>* CreateHessianGraph(
+CERES_NO_EXPORT std::unique_ptr<Graph<ParameterBlock*>> CreateHessianGraph(
     const Program& program);
 
 // Iterate over each of the groups in order of their priority and fill
 // summary with their sizes.
-CERES_EXPORT_INTERNAL void OrderingToGroupSizes(
+CERES_NO_EXPORT void OrderingToGroupSizes(
     const ParameterBlockOrdering* ordering, std::vector<int>* group_sizes);
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_PARAMETER_BLOCK_ORDERING_H_
diff --git a/third_party/ceres/internal/ceres/parameter_block_ordering_test.cc b/third_party/ceres/internal/ceres/parameter_block_ordering_test.cc
index 1078893..459a055 100644
--- a/third_party/ceres/internal/ceres/parameter_block_ordering_test.cc
+++ b/third_party/ceres/internal/ceres/parameter_block_ordering_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -43,13 +43,9 @@
 #include "ceres/stl_util.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
-using std::vector;
-
-typedef Graph<ParameterBlock*> HessianGraph;
-typedef std::unordered_set<ParameterBlock*> VertexSet;
+using VertexSet = std::unordered_set<ParameterBlock*>;
 
 template <int M, int... Ns>
 class DummyCostFunction : public SizedCostFunction<M, Ns...> {
@@ -71,12 +67,12 @@
     problem_.AddParameterBlock(z_, 5);
     problem_.AddParameterBlock(w_, 6);
 
-    problem_.AddResidualBlock(new DummyCostFunction<2, 3>, NULL, x_);
-    problem_.AddResidualBlock(new DummyCostFunction<6, 5, 4>, NULL, z_, y_);
-    problem_.AddResidualBlock(new DummyCostFunction<3, 3, 5>, NULL, x_, z_);
-    problem_.AddResidualBlock(new DummyCostFunction<7, 5, 3>, NULL, z_, x_);
+    problem_.AddResidualBlock(new DummyCostFunction<2, 3>, nullptr, x_);
+    problem_.AddResidualBlock(new DummyCostFunction<6, 5, 4>, nullptr, z_, y_);
+    problem_.AddResidualBlock(new DummyCostFunction<3, 3, 5>, nullptr, x_, z_);
+    problem_.AddResidualBlock(new DummyCostFunction<7, 5, 3>, nullptr, z_, x_);
     problem_.AddResidualBlock(
-        new DummyCostFunction<1, 5, 3, 6>, NULL, z_, x_, w_);
+        new DummyCostFunction<1, 5, 3, 6>, nullptr, z_, x_, w_);
   }
 
   ProblemImpl problem_;
@@ -85,8 +81,9 @@
 
 TEST_F(SchurOrderingTest, NoFixed) {
   const Program& program = problem_.program();
-  const vector<ParameterBlock*>& parameter_blocks = program.parameter_blocks();
-  std::unique_ptr<HessianGraph> graph(CreateHessianGraph(program));
+  const std::vector<ParameterBlock*>& parameter_blocks =
+      program.parameter_blocks();
+  auto graph = CreateHessianGraph(program);
 
   const VertexSet& vertices = graph->vertices();
   EXPECT_EQ(vertices.size(), 4);
@@ -131,7 +128,7 @@
   problem_.SetParameterBlockConstant(w_);
 
   const Program& program = problem_.program();
-  std::unique_ptr<HessianGraph> graph(CreateHessianGraph(program));
+  auto graph = CreateHessianGraph(program);
   EXPECT_EQ(graph->vertices().size(), 0);
 }
 
@@ -139,8 +136,9 @@
   problem_.SetParameterBlockConstant(x_);
 
   const Program& program = problem_.program();
-  const vector<ParameterBlock*>& parameter_blocks = program.parameter_blocks();
-  std::unique_ptr<HessianGraph> graph(CreateHessianGraph(program));
+  const std::vector<ParameterBlock*>& parameter_blocks =
+      program.parameter_blocks();
+  auto graph = CreateHessianGraph(program);
 
   const VertexSet& vertices = graph->vertices();
 
@@ -171,10 +169,9 @@
   }
 
   // The constant parameter block is at the end.
-  vector<ParameterBlock*> ordering;
+  std::vector<ParameterBlock*> ordering;
   ComputeSchurOrdering(program, &ordering);
   EXPECT_EQ(ordering.back(), parameter_blocks[0]);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/parameter_block_test.cc b/third_party/ceres/internal/ceres/parameter_block_test.cc
index a5a4230..0bb9b40 100644
--- a/third_party/ceres/internal/ceres/parameter_block_test.cc
+++ b/third_party/ceres/internal/ceres/parameter_block_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -36,70 +36,69 @@
 namespace ceres {
 namespace internal {
 
-TEST(ParameterBlock, SetParameterizationDiesOnSizeMismatch) {
+TEST(ParameterBlock, SetManifoldDiesOnSizeMismatch) {
   double x[3] = {1.0, 2.0, 3.0};
   ParameterBlock parameter_block(x, 3, -1);
   std::vector<int> indices;
   indices.push_back(1);
-  SubsetParameterization subset_wrong_size(4, indices);
-  EXPECT_DEATH_IF_SUPPORTED(
-      parameter_block.SetParameterization(&subset_wrong_size), "global");
+  SubsetManifold subset_wrong_size(4, indices);
+  EXPECT_DEATH_IF_SUPPORTED(parameter_block.SetManifold(&subset_wrong_size),
+                            "ambient");
 }
 
-TEST(ParameterBlock, SetParameterizationWithSameExistingParameterization) {
+TEST(ParameterBlock, SetManifoldWithSameExistingManifold) {
   double x[3] = {1.0, 2.0, 3.0};
   ParameterBlock parameter_block(x, 3, -1);
   std::vector<int> indices;
   indices.push_back(1);
-  SubsetParameterization subset(3, indices);
-  parameter_block.SetParameterization(&subset);
-  parameter_block.SetParameterization(&subset);
+  SubsetManifold subset(3, indices);
+  parameter_block.SetManifold(&subset);
+  parameter_block.SetManifold(&subset);
 }
 
-TEST(ParameterBlock, SetParameterizationAllowsResettingToNull) {
+TEST(ParameterBlock, SetManifoldAllowsResettingToNull) {
   double x[3] = {1.0, 2.0, 3.0};
   ParameterBlock parameter_block(x, 3, -1);
   std::vector<int> indices;
   indices.push_back(1);
-  SubsetParameterization subset(3, indices);
-  parameter_block.SetParameterization(&subset);
-  EXPECT_EQ(parameter_block.local_parameterization(), &subset);
-  parameter_block.SetParameterization(nullptr);
-  EXPECT_EQ(parameter_block.local_parameterization(), nullptr);
+  SubsetManifold subset(3, indices);
+  parameter_block.SetManifold(&subset);
+  EXPECT_EQ(parameter_block.manifold(), &subset);
+  parameter_block.SetManifold(nullptr);
+  EXPECT_EQ(parameter_block.manifold(), nullptr);
+  EXPECT_EQ(parameter_block.PlusJacobian(), nullptr);
 }
 
-TEST(ParameterBlock,
-     SetParameterizationAllowsResettingToDifferentParameterization) {
+TEST(ParameterBlock, SetManifoldAllowsResettingToDifferentManifold) {
   double x[3] = {1.0, 2.0, 3.0};
   ParameterBlock parameter_block(x, 3, -1);
   std::vector<int> indices;
   indices.push_back(1);
-  SubsetParameterization subset(3, indices);
-  parameter_block.SetParameterization(&subset);
-  EXPECT_EQ(parameter_block.local_parameterization(), &subset);
+  SubsetManifold subset(3, indices);
+  parameter_block.SetManifold(&subset);
+  EXPECT_EQ(parameter_block.manifold(), &subset);
 
-  SubsetParameterization subset_different(3, indices);
-  parameter_block.SetParameterization(&subset_different);
-  EXPECT_EQ(parameter_block.local_parameterization(), &subset_different);
+  SubsetManifold subset_different(3, indices);
+  parameter_block.SetManifold(&subset_different);
+  EXPECT_EQ(parameter_block.manifold(), &subset_different);
 }
 
-TEST(ParameterBlock, SetParameterizationAndNormalOperation) {
+TEST(ParameterBlock, SetManifoldAndNormalOperation) {
   double x[3] = {1.0, 2.0, 3.0};
   ParameterBlock parameter_block(x, 3, -1);
   std::vector<int> indices;
   indices.push_back(1);
-  SubsetParameterization subset(3, indices);
-  parameter_block.SetParameterization(&subset);
+  SubsetManifold subset(3, indices);
+  parameter_block.SetManifold(&subset);
 
-  // Ensure the local parameterization jacobian result is correctly computed.
-  ConstMatrixRef local_parameterization_jacobian(
-      parameter_block.LocalParameterizationJacobian(), 3, 2);
-  ASSERT_EQ(1.0, local_parameterization_jacobian(0, 0));
-  ASSERT_EQ(0.0, local_parameterization_jacobian(0, 1));
-  ASSERT_EQ(0.0, local_parameterization_jacobian(1, 0));
-  ASSERT_EQ(0.0, local_parameterization_jacobian(1, 1));
-  ASSERT_EQ(0.0, local_parameterization_jacobian(2, 0));
-  ASSERT_EQ(1.0, local_parameterization_jacobian(2, 1));
+  // Ensure the manifold plus jacobian result is correctly computed.
+  ConstMatrixRef manifold_jacobian(parameter_block.PlusJacobian(), 3, 2);
+  ASSERT_EQ(1.0, manifold_jacobian(0, 0));
+  ASSERT_EQ(0.0, manifold_jacobian(0, 1));
+  ASSERT_EQ(0.0, manifold_jacobian(1, 0));
+  ASSERT_EQ(0.0, manifold_jacobian(1, 1));
+  ASSERT_EQ(0.0, manifold_jacobian(2, 0));
+  ASSERT_EQ(1.0, manifold_jacobian(2, 1));
 
   // Check that updating works as expected.
   double x_plus_delta[3];
@@ -110,37 +109,47 @@
   ASSERT_EQ(3.3, x_plus_delta[2]);
 }
 
-struct TestParameterization : public LocalParameterization {
+struct TestManifold : public Manifold {
  public:
-  virtual ~TestParameterization() {}
   bool Plus(const double* x,
             const double* delta,
             double* x_plus_delta) const final {
     LOG(FATAL) << "Shouldn't get called.";
     return true;
   }
-  bool ComputeJacobian(const double* x, double* jacobian) const final {
+
+  bool PlusJacobian(const double* x, double* jacobian) const final {
     jacobian[0] = *x * 2;
     return true;
   }
 
-  int GlobalSize() const final { return 1; }
-  int LocalSize() const final { return 1; }
+  bool Minus(const double* y, const double* x, double* y_minus_x) const final {
+    LOG(FATAL) << "Shouldn't get called";
+    return true;
+  }
+
+  bool MinusJacobian(const double* x, double* jacobian) const final {
+    jacobian[0] = *x * 2;
+    return true;
+  }
+
+  int AmbientSize() const final { return 1; }
+  int TangentSize() const final { return 1; }
 };
 
-TEST(ParameterBlock, SetStateUpdatesLocalParameterizationJacobian) {
-  TestParameterization test_parameterization;
+TEST(ParameterBlock, SetStateUpdatesPlusJacobian) {
+  TestManifold test_manifold;
   double x[1] = {1.0};
-  ParameterBlock parameter_block(x, 1, -1, &test_parameterization);
+  ParameterBlock parameter_block(x, 1, -1, &test_manifold);
 
-  EXPECT_EQ(2.0, *parameter_block.LocalParameterizationJacobian());
+  EXPECT_EQ(2.0, *parameter_block.PlusJacobian());
 
   x[0] = 5.5;
   parameter_block.SetState(x);
-  EXPECT_EQ(11.0, *parameter_block.LocalParameterizationJacobian());
+  EXPECT_EQ(11.0, *parameter_block.PlusJacobian());
 }
 
-TEST(ParameterBlock, PlusWithNoLocalParameterization) {
+TEST(ParameterBlock, PlusWithNoManifold) {
   double x[2] = {1.0, 2.0};
   ParameterBlock parameter_block(x, 2, -1);
 
@@ -151,12 +160,11 @@
   EXPECT_EQ(2.3, x_plus_delta[1]);
 }
 
-// Stops computing the jacobian after the first time.
-class BadLocalParameterization : public LocalParameterization {
+// Stops computing the plus_jacobian after the first time.
+class BadManifold : public Manifold {
  public:
-  BadLocalParameterization() : calls_(0) {}
+  BadManifold() = default;
 
-  virtual ~BadLocalParameterization() {}
   bool Plus(const double* x,
             const double* delta,
             double* x_plus_delta) const final {
@@ -164,7 +172,7 @@
     return true;
   }
 
-  bool ComputeJacobian(const double* x, double* jacobian) const final {
+  bool PlusJacobian(const double* x, double* jacobian) const final {
     if (calls_ == 0) {
       jacobian[0] = 0;
     }
@@ -172,17 +180,27 @@
     return true;
   }
 
-  int GlobalSize() const final { return 1; }
-  int LocalSize() const final { return 1; }
+  bool Minus(const double* y, const double* x, double* y_minus_x) const final {
+    LOG(FATAL) << "Shouldn't get called";
+    return true;
+  }
+
+  bool MinusJacobian(const double* x, double* jacobian) const final {
+    jacobian[0] = *x * 2;
+    return true;
+  }
+
+  int AmbientSize() const final { return 1; }
+  int TangentSize() const final { return 1; }
 
  private:
-  mutable int calls_;
+  mutable int calls_{0};
 };
 
-TEST(ParameterBlock, DetectBadLocalParameterization) {
+TEST(ParameterBlock, DetectBadManifold) {
   double x = 1;
-  BadLocalParameterization bad_parameterization;
-  ParameterBlock parameter_block(&x, 1, -1, &bad_parameterization);
+  BadManifold bad_manifold;
+  ParameterBlock parameter_block(&x, 1, -1, &bad_manifold);
   double y = 2;
   EXPECT_FALSE(parameter_block.SetState(&y));
 }
@@ -227,39 +245,39 @@
   EXPECT_EQ(x_plus_delta[1], -1.0);
 }
 
-TEST(ParameterBlock, ResetLocalParameterizationToNull) {
+TEST(ParameterBlock, ResetManifoldToNull) {
   double x[3] = {1.0, 2.0, 3.0};
   ParameterBlock parameter_block(x, 3, -1);
   std::vector<int> indices;
   indices.push_back(1);
-  SubsetParameterization subset(3, indices);
-  parameter_block.SetParameterization(&subset);
-  EXPECT_EQ(parameter_block.local_parameterization(), &subset);
-  parameter_block.SetParameterization(nullptr);
-  EXPECT_EQ(parameter_block.local_parameterization(), nullptr);
+  SubsetManifold subset(3, indices);
+  parameter_block.SetManifold(&subset);
+  EXPECT_EQ(parameter_block.manifold(), &subset);
+  parameter_block.SetManifold(nullptr);
+  EXPECT_EQ(parameter_block.manifold(), nullptr);
 }
 
-TEST(ParameterBlock, ResetLocalParameterizationToNotNull) {
+TEST(ParameterBlock, ResetManifoldToNotNull) {
   double x[3] = {1.0, 2.0, 3.0};
   ParameterBlock parameter_block(x, 3, -1);
   std::vector<int> indices;
   indices.push_back(1);
-  SubsetParameterization subset(3, indices);
-  parameter_block.SetParameterization(&subset);
-  EXPECT_EQ(parameter_block.local_parameterization(), &subset);
+  SubsetManifold subset(3, indices);
+  parameter_block.SetManifold(&subset);
+  EXPECT_EQ(parameter_block.manifold(), &subset);
 
-  SubsetParameterization subset_different(3, indices);
-  parameter_block.SetParameterization(&subset_different);
-  EXPECT_EQ(parameter_block.local_parameterization(), &subset_different);
+  SubsetManifold subset_different(3, indices);
+  parameter_block.SetManifold(&subset_different);
+  EXPECT_EQ(parameter_block.manifold(), &subset_different);
 }
 
-TEST(ParameterBlock, SetNullLocalParameterization) {
+TEST(ParameterBlock, SetNullManifold) {
   double x[3] = {1.0, 2.0, 3.0};
   ParameterBlock parameter_block(x, 3, -1);
-  EXPECT_EQ(parameter_block.local_parameterization(), nullptr);
+  EXPECT_EQ(parameter_block.manifold(), nullptr);
 
-  parameter_block.SetParameterization(nullptr);
-  EXPECT_EQ(parameter_block.local_parameterization(), nullptr);
+  parameter_block.SetManifold(nullptr);
+  EXPECT_EQ(parameter_block.manifold(), nullptr);
 }
 
 }  // namespace internal
diff --git a/third_party/ceres/internal/ceres/parameter_dims_test.cc b/third_party/ceres/internal/ceres/parameter_dims_test.cc
index ee3be8f..58d2500 100644
--- a/third_party/ceres/internal/ceres/parameter_dims_test.cc
+++ b/third_party/ceres/internal/ceres/parameter_dims_test.cc
@@ -32,20 +32,6 @@
 namespace ceres {
 namespace internal {
 
-// Is valid parameter dims unit test
-static_assert(IsValidParameterDimensionSequence(std::integer_sequence<int>()) ==
-                  true,
-              "Unit test of is valid parameter dimension sequence failed.");
-static_assert(IsValidParameterDimensionSequence(
-                  std::integer_sequence<int, 2, 1>()) == true,
-              "Unit test of is valid parameter dimension sequence failed.");
-static_assert(IsValidParameterDimensionSequence(
-                  std::integer_sequence<int, 0, 1>()) == false,
-              "Unit test of is valid parameter dimension sequence failed.");
-static_assert(IsValidParameterDimensionSequence(
-                  std::integer_sequence<int, 3, 0>()) == false,
-              "Unit test of is valid parameter dimension sequence failed.");
-
 // Static parameter dims unit test
 static_assert(
     std::is_same<StaticParameterDims<4, 2, 1>::Parameters,
diff --git a/third_party/ceres/internal/ceres/partition_range_for_parallel_for.h b/third_party/ceres/internal/ceres/partition_range_for_parallel_for.h
new file mode 100644
index 0000000..309d7a8
--- /dev/null
+++ b/third_party/ceres/internal/ceres/partition_range_for_parallel_for.h
@@ -0,0 +1,150 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Authors: vitus@google.com (Michael Vitus),
+//          dmitriy.korchemkin@gmail.com (Dmitriy Korchemkin)
+
+#ifndef CERES_INTERNAL_PARTITION_RANGE_FOR_PARALLEL_FOR_H_
+#define CERES_INTERNAL_PARTITION_RANGE_FOR_PARALLEL_FOR_H_
+
+#include <algorithm>
+#include <vector>
+
+namespace ceres::internal {
+// Check if it is possible to split range [start; end) into at most
+// max_num_partitions  contiguous partitions of cost not greater than
+// max_partition_cost. Inclusive integer cumulative costs are provided by
+// cumulative_cost_data objects, with cumulative_cost_offset being a total cost
+// of all indices (starting from zero) preceding start element. Cumulative costs
+// are returned by cumulative_cost_fun called with a reference to
+// cumulative_cost_data element with index from range[start; end), and should be
+// non-decreasing. Partition of the range is returned via partition argument
+template <typename CumulativeCostData, typename CumulativeCostFun>
+bool MaxPartitionCostIsFeasible(int start,
+                                int end,
+                                int max_num_partitions,
+                                int max_partition_cost,
+                                int cumulative_cost_offset,
+                                const CumulativeCostData* cumulative_cost_data,
+                                CumulativeCostFun&& cumulative_cost_fun,
+                                std::vector<int>* partition) {
+  partition->clear();
+  partition->push_back(start);
+  int partition_start = start;
+  int cost_offset = cumulative_cost_offset;
+
+  while (partition_start < end) {
+    // Already have max_num_partitions
+    if (partition->size() > max_num_partitions) {
+      return false;
+    }
+    const int target = max_partition_cost + cost_offset;
+    const int partition_end =
+        std::partition_point(
+            cumulative_cost_data + partition_start,
+            cumulative_cost_data + end,
+            [&cumulative_cost_fun, target](const CumulativeCostData& item) {
+              return cumulative_cost_fun(item) <= target;
+            }) -
+        cumulative_cost_data;
+    // Unable to make a partition from a single element
+    if (partition_end == partition_start) {
+      return false;
+    }
+
+    const int cost_last =
+        cumulative_cost_fun(cumulative_cost_data[partition_end - 1]);
+    partition->push_back(partition_end);
+    partition_start = partition_end;
+    cost_offset = cost_last;
+  }
+  return true;
+}
+
+// Split integer interval [start, end) into at most max_num_partitions
+// contiguous intervals, minimizing maximal total cost of a single interval.
+// Inclusive integer cumulative costs for each (zero-based) index are provided
+// by cumulative_cost_data objects, and are returned by cumulative_cost_fun call
+// with a reference to one of the objects from range [start, end)
+template <typename CumulativeCostData, typename CumulativeCostFun>
+std::vector<int> PartitionRangeForParallelFor(
+    int start,
+    int end,
+    int max_num_partitions,
+    const CumulativeCostData* cumulative_cost_data,
+    CumulativeCostFun&& cumulative_cost_fun) {
+  // Given maximal partition cost, it is possible to verify if it is admissible
+  // and obtain corresponding partition using MaxPartitionCostIsFeasible
+  // function. In order to find the lowest admissible value, a binary search
+  // over all potentially optimal cost values is being performed
+  const int cumulative_cost_last =
+      cumulative_cost_fun(cumulative_cost_data[end - 1]);
+  const int cumulative_cost_offset =
+      start ? cumulative_cost_fun(cumulative_cost_data[start - 1]) : 0;
+  const int total_cost = cumulative_cost_last - cumulative_cost_offset;
+
+  // Minimal maximal partition cost is not smaller than the average
+  // We will use non-inclusive lower bound
+  int partition_cost_lower_bound = total_cost / max_num_partitions - 1;
+  // Minimal maximal partition cost is not larger than the total cost
+  // Upper bound is inclusive
+  int partition_cost_upper_bound = total_cost;
+
+  std::vector<int> partition;
+  // Range partition corresponding to the latest evaluated upper bound.
+  // A single segment covering the whole input interval [start, end) corresponds
+  // to minimal maximal partition cost of total_cost.
+  std::vector<int> partition_upper_bound = {start, end};
+  // Binary search over partition cost, returning the lowest admissible cost
+  while (partition_cost_upper_bound - partition_cost_lower_bound > 1) {
+    partition.reserve(max_num_partitions + 1);
+    const int partition_cost =
+        partition_cost_lower_bound +
+        (partition_cost_upper_bound - partition_cost_lower_bound) / 2;
+    bool admissible = MaxPartitionCostIsFeasible(
+        start,
+        end,
+        max_num_partitions,
+        partition_cost,
+        cumulative_cost_offset,
+        cumulative_cost_data,
+        std::forward<CumulativeCostFun>(cumulative_cost_fun),
+        &partition);
+    if (admissible) {
+      partition_cost_upper_bound = partition_cost;
+      std::swap(partition, partition_upper_bound);
+    } else {
+      partition_cost_lower_bound = partition_cost;
+    }
+  }
+
+  return partition_upper_bound;
+}
+}  // namespace ceres::internal
+
+#endif
diff --git a/third_party/ceres/internal/ceres/partitioned_matrix_view.cc b/third_party/ceres/internal/ceres/partitioned_matrix_view.cc
index b67bc90..cffdbc5 100644
--- a/third_party/ceres/internal/ceres/partitioned_matrix_view.cc
+++ b/third_party/ceres/internal/ceres/partitioned_matrix_view.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -39,145 +39,147 @@
 //
 // This file is generated using generate_template_specializations.py.
 
+#include <memory>
+
 #include "ceres/linear_solver.h"
 #include "ceres/partitioned_matrix_view.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
-PartitionedMatrixViewBase* PartitionedMatrixViewBase::Create(
+PartitionedMatrixViewBase::~PartitionedMatrixViewBase() = default;
+
+std::unique_ptr<PartitionedMatrixViewBase> PartitionedMatrixViewBase::Create(
     const LinearSolver::Options& options, const BlockSparseMatrix& matrix) {
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
   if ((options.row_block_size == 2) &&
      (options.e_block_size == 2) &&
      (options.f_block_size == 2)) {
-    return new PartitionedMatrixView<2, 2, 2>(matrix,
-                                              options.elimination_groups[0]);
+    return std::make_unique<PartitionedMatrixView<2,2, 2>>(
+                   options, matrix);
   }
   if ((options.row_block_size == 2) &&
      (options.e_block_size == 2) &&
      (options.f_block_size == 3)) {
-    return new PartitionedMatrixView<2, 2, 3>(matrix,
-                                              options.elimination_groups[0]);
+    return std::make_unique<PartitionedMatrixView<2,2, 3>>(
+                   options, matrix);
   }
   if ((options.row_block_size == 2) &&
      (options.e_block_size == 2) &&
      (options.f_block_size == 4)) {
-    return new PartitionedMatrixView<2, 2, 4>(matrix,
-                                              options.elimination_groups[0]);
+    return std::make_unique<PartitionedMatrixView<2,2, 4>>(
+                   options, matrix);
   }
   if ((options.row_block_size == 2) &&
      (options.e_block_size == 2)) {
-    return new PartitionedMatrixView<2, 2, Eigen::Dynamic>(matrix,
-                                              options.elimination_groups[0]);
+    return std::make_unique<PartitionedMatrixView<2,2, Eigen::Dynamic>>(
+                   options, matrix);
   }
   if ((options.row_block_size == 2) &&
      (options.e_block_size == 3) &&
      (options.f_block_size == 3)) {
-    return new PartitionedMatrixView<2, 3, 3>(matrix,
-                                              options.elimination_groups[0]);
+    return std::make_unique<PartitionedMatrixView<2,3, 3>>(
+                   options, matrix);
   }
   if ((options.row_block_size == 2) &&
      (options.e_block_size == 3) &&
      (options.f_block_size == 4)) {
-    return new PartitionedMatrixView<2, 3, 4>(matrix,
-                                              options.elimination_groups[0]);
+    return std::make_unique<PartitionedMatrixView<2,3, 4>>(
+                   options, matrix);
   }
   if ((options.row_block_size == 2) &&
      (options.e_block_size == 3) &&
      (options.f_block_size == 6)) {
-    return new PartitionedMatrixView<2, 3, 6>(matrix,
-                                              options.elimination_groups[0]);
+    return std::make_unique<PartitionedMatrixView<2,3, 6>>(
+                   options, matrix);
   }
   if ((options.row_block_size == 2) &&
      (options.e_block_size == 3) &&
      (options.f_block_size == 9)) {
-    return new PartitionedMatrixView<2, 3, 9>(matrix,
-                                              options.elimination_groups[0]);
+    return std::make_unique<PartitionedMatrixView<2,3, 9>>(
+                   options, matrix);
   }
   if ((options.row_block_size == 2) &&
      (options.e_block_size == 3)) {
-    return new PartitionedMatrixView<2, 3, Eigen::Dynamic>(matrix,
-                                              options.elimination_groups[0]);
+    return std::make_unique<PartitionedMatrixView<2,3, Eigen::Dynamic>>(
+                   options, matrix);
   }
   if ((options.row_block_size == 2) &&
      (options.e_block_size == 4) &&
      (options.f_block_size == 3)) {
-    return new PartitionedMatrixView<2, 4, 3>(matrix,
-                                              options.elimination_groups[0]);
+    return std::make_unique<PartitionedMatrixView<2,4, 3>>(
+                   options, matrix);
   }
   if ((options.row_block_size == 2) &&
      (options.e_block_size == 4) &&
      (options.f_block_size == 4)) {
-    return new PartitionedMatrixView<2, 4, 4>(matrix,
-                                              options.elimination_groups[0]);
+    return std::make_unique<PartitionedMatrixView<2,4, 4>>(
+                   options, matrix);
   }
   if ((options.row_block_size == 2) &&
      (options.e_block_size == 4) &&
      (options.f_block_size == 6)) {
-    return new PartitionedMatrixView<2, 4, 6>(matrix,
-                                              options.elimination_groups[0]);
+    return std::make_unique<PartitionedMatrixView<2,4, 6>>(
+                   options, matrix);
   }
   if ((options.row_block_size == 2) &&
      (options.e_block_size == 4) &&
      (options.f_block_size == 8)) {
-    return new PartitionedMatrixView<2, 4, 8>(matrix,
-                                              options.elimination_groups[0]);
+    return std::make_unique<PartitionedMatrixView<2,4, 8>>(
+                   options, matrix);
   }
   if ((options.row_block_size == 2) &&
      (options.e_block_size == 4) &&
      (options.f_block_size == 9)) {
-    return new PartitionedMatrixView<2, 4, 9>(matrix,
-                                              options.elimination_groups[0]);
+    return std::make_unique<PartitionedMatrixView<2,4, 9>>(
+                   options, matrix);
   }
   if ((options.row_block_size == 2) &&
      (options.e_block_size == 4)) {
-    return new PartitionedMatrixView<2, 4, Eigen::Dynamic>(matrix,
-                                              options.elimination_groups[0]);
+    return std::make_unique<PartitionedMatrixView<2,4, Eigen::Dynamic>>(
+                   options, matrix);
   }
   if (options.row_block_size == 2) {
-    return new PartitionedMatrixView<2, Eigen::Dynamic, Eigen::Dynamic>(matrix,
-                                              options.elimination_groups[0]);
+    return std::make_unique<PartitionedMatrixView<2,Eigen::Dynamic, Eigen::Dynamic>>(
+                   options, matrix);
   }
   if ((options.row_block_size == 3) &&
      (options.e_block_size == 3) &&
      (options.f_block_size == 3)) {
-    return new PartitionedMatrixView<3, 3, 3>(matrix,
-                                              options.elimination_groups[0]);
+    return std::make_unique<PartitionedMatrixView<3,3, 3>>(
+                   options, matrix);
   }
   if ((options.row_block_size == 4) &&
      (options.e_block_size == 4) &&
      (options.f_block_size == 2)) {
-    return new PartitionedMatrixView<4, 4, 2>(matrix,
-                                              options.elimination_groups[0]);
+    return std::make_unique<PartitionedMatrixView<4,4, 2>>(
+                   options, matrix);
   }
   if ((options.row_block_size == 4) &&
      (options.e_block_size == 4) &&
      (options.f_block_size == 3)) {
-    return new PartitionedMatrixView<4, 4, 3>(matrix,
-                                              options.elimination_groups[0]);
+    return std::make_unique<PartitionedMatrixView<4,4, 3>>(
+                   options, matrix);
   }
   if ((options.row_block_size == 4) &&
      (options.e_block_size == 4) &&
      (options.f_block_size == 4)) {
-    return new PartitionedMatrixView<4, 4, 4>(matrix,
-                                              options.elimination_groups[0]);
+    return std::make_unique<PartitionedMatrixView<4,4, 4>>(
+                   options, matrix);
   }
   if ((options.row_block_size == 4) &&
      (options.e_block_size == 4)) {
-    return new PartitionedMatrixView<4, 4, Eigen::Dynamic>(matrix,
-                                              options.elimination_groups[0]);
+    return std::make_unique<PartitionedMatrixView<4,4, Eigen::Dynamic>>(
+                   options, matrix);
   }
 
 #endif
   VLOG(1) << "Template specializations not found for <"
           << options.row_block_size << "," << options.e_block_size << ","
           << options.f_block_size << ">";
-  return new PartitionedMatrixView<Eigen::Dynamic,
-                                   Eigen::Dynamic,
-                                   Eigen::Dynamic>(
-      matrix, options.elimination_groups[0]);
+  return std::make_unique<PartitionedMatrixView<Eigen::Dynamic,
+                                                Eigen::Dynamic,
+                                                Eigen::Dynamic>>(
+      options, matrix);
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/partitioned_matrix_view.h b/third_party/ceres/internal/ceres/partitioned_matrix_view.h
index 9f204ee..8589a3b 100644
--- a/third_party/ceres/internal/ceres/partitioned_matrix_view.h
+++ b/third_party/ceres/internal/ceres/partitioned_matrix_view.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -38,21 +38,25 @@
 
 #include <algorithm>
 #include <cstring>
+#include <memory>
 #include <vector>
 
 #include "ceres/block_structure.h"
+#include "ceres/internal/config.h"
+#include "ceres/internal/disable_warnings.h"
 #include "ceres/internal/eigen.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 #include "ceres/linear_solver.h"
 #include "ceres/small_blas.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
+
+class ContextImpl;
 
 // Given generalized bi-partite matrix A = [E F], with the same block
 // structure as required by the Schur complement based solver, found
-// in explicit_schur_complement_solver.h, provide access to the
+// in schur_complement_solver.h, provide access to the
 // matrices E and F and their outer products E'E and F'F with
 // themselves.
 //
@@ -60,28 +64,38 @@
 // block structure of the matrix does not satisfy the requirements of
 // the Schur complement solver it will result in unpredictable and
 // wrong output.
-class CERES_EXPORT_INTERNAL PartitionedMatrixViewBase {
+class CERES_NO_EXPORT PartitionedMatrixViewBase {
  public:
-  virtual ~PartitionedMatrixViewBase() {}
+  virtual ~PartitionedMatrixViewBase();
 
   // y += E'x
-  virtual void LeftMultiplyE(const double* x, double* y) const = 0;
+  virtual void LeftMultiplyAndAccumulateE(const double* x, double* y) const = 0;
+  virtual void LeftMultiplyAndAccumulateESingleThreaded(const double* x,
+                                                        double* y) const = 0;
+  virtual void LeftMultiplyAndAccumulateEMultiThreaded(const double* x,
+                                                       double* y) const = 0;
 
   // y += F'x
-  virtual void LeftMultiplyF(const double* x, double* y) const = 0;
+  virtual void LeftMultiplyAndAccumulateF(const double* x, double* y) const = 0;
+  virtual void LeftMultiplyAndAccumulateFSingleThreaded(const double* x,
+                                                        double* y) const = 0;
+  virtual void LeftMultiplyAndAccumulateFMultiThreaded(const double* x,
+                                                       double* y) const = 0;
 
   // y += Ex
-  virtual void RightMultiplyE(const double* x, double* y) const = 0;
+  virtual void RightMultiplyAndAccumulateE(const double* x,
+                                           double* y) const = 0;
 
   // y += Fx
-  virtual void RightMultiplyF(const double* x, double* y) const = 0;
+  virtual void RightMultiplyAndAccumulateF(const double* x,
+                                           double* y) const = 0;
 
   // Create and return the block diagonal of the matrix E'E.
-  virtual BlockSparseMatrix* CreateBlockDiagonalEtE() const = 0;
+  virtual std::unique_ptr<BlockSparseMatrix> CreateBlockDiagonalEtE() const = 0;
 
   // Create and return the block diagonal of the matrix F'F. Caller
   // owns the result.
-  virtual BlockSparseMatrix* CreateBlockDiagonalFtF() const = 0;
+  virtual std::unique_ptr<BlockSparseMatrix> CreateBlockDiagonalFtF() const = 0;
 
   // Compute the block diagonal of the matrix E'E and store it in
   // block_diagonal. The matrix block_diagonal is expected to have a
@@ -106,30 +120,61 @@
   virtual int num_cols_f()       const = 0;
   virtual int num_rows()         const = 0;
   virtual int num_cols()         const = 0;
+  virtual const std::vector<int>& e_cols_partition() const = 0;
+  virtual const std::vector<int>& f_cols_partition() const = 0;
   // clang-format on
 
-  static PartitionedMatrixViewBase* Create(const LinearSolver::Options& options,
-                                           const BlockSparseMatrix& matrix);
+  static std::unique_ptr<PartitionedMatrixViewBase> Create(
+      const LinearSolver::Options& options, const BlockSparseMatrix& matrix);
 };
 
 template <int kRowBlockSize = Eigen::Dynamic,
           int kEBlockSize = Eigen::Dynamic,
           int kFBlockSize = Eigen::Dynamic>
-class PartitionedMatrixView : public PartitionedMatrixViewBase {
+class CERES_NO_EXPORT PartitionedMatrixView final
+    : public PartitionedMatrixViewBase {
  public:
   // matrix = [E F], where the matrix E contains the first
-  // num_col_blocks_a column blocks.
-  PartitionedMatrixView(const BlockSparseMatrix& matrix, int num_col_blocks_e);
+  // options.elimination_groups[0] column blocks.
+  PartitionedMatrixView(const LinearSolver::Options& options,
+                        const BlockSparseMatrix& matrix);
 
-  virtual ~PartitionedMatrixView();
-  void LeftMultiplyE(const double* x, double* y) const final;
-  void LeftMultiplyF(const double* x, double* y) const final;
-  void RightMultiplyE(const double* x, double* y) const final;
-  void RightMultiplyF(const double* x, double* y) const final;
-  BlockSparseMatrix* CreateBlockDiagonalEtE() const final;
-  BlockSparseMatrix* CreateBlockDiagonalFtF() const final;
+  // y += E'x
+  virtual void LeftMultiplyAndAccumulateE(const double* x,
+                                          double* y) const final;
+  virtual void LeftMultiplyAndAccumulateESingleThreaded(const double* x,
+                                                        double* y) const final;
+  virtual void LeftMultiplyAndAccumulateEMultiThreaded(const double* x,
+                                                       double* y) const final;
+
+  // y += F'x
+  virtual void LeftMultiplyAndAccumulateF(const double* x,
+                                          double* y) const final;
+  virtual void LeftMultiplyAndAccumulateFSingleThreaded(const double* x,
+                                                        double* y) const final;
+  virtual void LeftMultiplyAndAccumulateFMultiThreaded(const double* x,
+                                                       double* y) const final;
+
+  // y += Ex
+  virtual void RightMultiplyAndAccumulateE(const double* x,
+                                           double* y) const final;
+
+  // y += Fx
+  virtual void RightMultiplyAndAccumulateF(const double* x,
+                                           double* y) const final;
+
+  std::unique_ptr<BlockSparseMatrix> CreateBlockDiagonalEtE() const final;
+  std::unique_ptr<BlockSparseMatrix> CreateBlockDiagonalFtF() const final;
   void UpdateBlockDiagonalEtE(BlockSparseMatrix* block_diagonal) const final;
+  void UpdateBlockDiagonalEtESingleThreaded(
+      BlockSparseMatrix* block_diagonal) const;
+  void UpdateBlockDiagonalEtEMultiThreaded(
+      BlockSparseMatrix* block_diagonal) const;
   void UpdateBlockDiagonalFtF(BlockSparseMatrix* block_diagonal) const final;
+  void UpdateBlockDiagonalFtFSingleThreaded(
+      BlockSparseMatrix* block_diagonal) const;
+  void UpdateBlockDiagonalFtFMultiThreaded(
+      BlockSparseMatrix* block_diagonal) const;
   // clang-format off
   int num_col_blocks_e() const final { return num_col_blocks_e_;  }
   int num_col_blocks_f() const final { return num_col_blocks_f_;  }
@@ -138,20 +183,30 @@
   int num_rows()         const final { return matrix_.num_rows(); }
   int num_cols()         const final { return matrix_.num_cols(); }
   // clang-format on
+  const std::vector<int>& e_cols_partition() const final {
+    return e_cols_partition_;
+  }
+  const std::vector<int>& f_cols_partition() const final {
+    return f_cols_partition_;
+  }
 
  private:
-  BlockSparseMatrix* CreateBlockDiagonalMatrixLayout(int start_col_block,
-                                                     int end_col_block) const;
+  std::unique_ptr<BlockSparseMatrix> CreateBlockDiagonalMatrixLayout(
+      int start_col_block, int end_col_block) const;
 
+  const LinearSolver::Options options_;
   const BlockSparseMatrix& matrix_;
   int num_row_blocks_e_;
   int num_col_blocks_e_;
   int num_col_blocks_f_;
   int num_cols_e_;
   int num_cols_f_;
+  std::vector<int> e_cols_partition_;
+  std::vector<int> f_cols_partition_;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_PARTITIONED_MATRIX_VIEW_H_
diff --git a/third_party/ceres/internal/ceres/partitioned_matrix_view_impl.h b/third_party/ceres/internal/ceres/partitioned_matrix_view_impl.h
index 0b6a57f..bd02439 100644
--- a/third_party/ceres/internal/ceres/partitioned_matrix_view_impl.h
+++ b/third_party/ceres/internal/ceres/partitioned_matrix_view_impl.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -30,35 +30,40 @@
 
 #include <algorithm>
 #include <cstring>
+#include <memory>
 #include <vector>
 
 #include "ceres/block_sparse_matrix.h"
 #include "ceres/block_structure.h"
 #include "ceres/internal/eigen.h"
+#include "ceres/parallel_for.h"
+#include "ceres/partition_range_for_parallel_for.h"
 #include "ceres/partitioned_matrix_view.h"
 #include "ceres/small_blas.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
 PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
-    PartitionedMatrixView(const BlockSparseMatrix& matrix, int num_col_blocks_e)
-    : matrix_(matrix), num_col_blocks_e_(num_col_blocks_e) {
+    PartitionedMatrixView(const LinearSolver::Options& options,
+                          const BlockSparseMatrix& matrix)
+
+    : options_(options), matrix_(matrix) {
   const CompressedRowBlockStructure* bs = matrix_.block_structure();
   CHECK(bs != nullptr);
 
+  num_col_blocks_e_ = options_.elimination_groups[0];
   num_col_blocks_f_ = bs->cols.size() - num_col_blocks_e_;
 
   // Compute the number of row blocks in E. The number of row blocks
   // in E maybe less than the number of row blocks in the input matrix
   // as some of the row blocks at the bottom may not have any
   // e_blocks. For a definition of what an e_block is, please see
-  // explicit_schur_complement_solver.h
+  // schur_complement_solver.h
   num_row_blocks_e_ = 0;
-  for (int r = 0; r < bs->rows.size(); ++r) {
-    const std::vector<Cell>& cells = bs->rows[r].cells;
+  for (const auto& row : bs->rows) {
+    const std::vector<Cell>& cells = row.cells;
     if (cells[0].block_id < num_col_blocks_e_) {
       ++num_row_blocks_e_;
     }
@@ -78,11 +83,26 @@
   }
 
   CHECK_EQ(num_cols_e_ + num_cols_f_, matrix_.num_cols());
-}
 
-template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
-PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
-    ~PartitionedMatrixView() {}
+  auto transpose_bs = matrix_.transpose_block_structure();
+  const int num_threads = options_.num_threads;
+  if (transpose_bs != nullptr && num_threads > 1) {
+    int kMaxPartitions = num_threads * 4;
+    e_cols_partition_ = PartitionRangeForParallelFor(
+        0,
+        num_col_blocks_e_,
+        kMaxPartitions,
+        transpose_bs->rows.data(),
+        [](const CompressedRow& row) { return row.cumulative_nnz; });
+
+    f_cols_partition_ = PartitionRangeForParallelFor(
+        num_col_blocks_e_,
+        num_col_blocks_e_ + num_col_blocks_f_,
+        kMaxPartitions,
+        transpose_bs->rows.data(),
+        [](const CompressedRow& row) { return row.cumulative_nnz; });
+  }
+}
 
 // The next four methods don't seem to be particularly cache
 // friendly. This is an artifact of how the BlockStructure of the
@@ -91,77 +111,101 @@
 
 template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
 void PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
-    RightMultiplyE(const double* x, double* y) const {
-  const CompressedRowBlockStructure* bs = matrix_.block_structure();
-
+    RightMultiplyAndAccumulateE(const double* x, double* y) const {
   // Iterate over the first num_row_blocks_e_ row blocks, and multiply
   // by the first cell in each row block.
+  auto bs = matrix_.block_structure();
   const double* values = matrix_.values();
-  for (int r = 0; r < num_row_blocks_e_; ++r) {
-    const Cell& cell = bs->rows[r].cells[0];
-    const int row_block_pos = bs->rows[r].block.position;
-    const int row_block_size = bs->rows[r].block.size;
-    const int col_block_id = cell.block_id;
-    const int col_block_pos = bs->cols[col_block_id].position;
-    const int col_block_size = bs->cols[col_block_id].size;
-    // clang-format off
-    MatrixVectorMultiply<kRowBlockSize, kEBlockSize, 1>(
-        values + cell.position, row_block_size, col_block_size,
-        x + col_block_pos,
-        y + row_block_pos);
-    // clang-format on
-  }
+  ParallelFor(options_.context,
+              0,
+              num_row_blocks_e_,
+              options_.num_threads,
+              [values, bs, x, y](int row_block_id) {
+                const Cell& cell = bs->rows[row_block_id].cells[0];
+                const int row_block_pos = bs->rows[row_block_id].block.position;
+                const int row_block_size = bs->rows[row_block_id].block.size;
+                const int col_block_id = cell.block_id;
+                const int col_block_pos = bs->cols[col_block_id].position;
+                const int col_block_size = bs->cols[col_block_id].size;
+                // clang-format off
+                MatrixVectorMultiply<kRowBlockSize, kEBlockSize, 1>(
+                    values + cell.position, row_block_size, col_block_size,
+                    x + col_block_pos,
+                    y + row_block_pos);
+                // clang-format on
+              });
 }
 
 template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
 void PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
-    RightMultiplyF(const double* x, double* y) const {
-  const CompressedRowBlockStructure* bs = matrix_.block_structure();
-
+    RightMultiplyAndAccumulateF(const double* x, double* y) const {
   // Iterate over row blocks, and if the row block is in E, then
   // multiply by all the cells except the first one which is of type
   // E. If the row block is not in E (i.e its in the bottom
   // num_row_blocks - num_row_blocks_e row blocks), then all the cells
   // are of type F and multiply by them all.
+  const CompressedRowBlockStructure* bs = matrix_.block_structure();
+  const int num_row_blocks = bs->rows.size();
+  const int num_cols_e = num_cols_e_;
   const double* values = matrix_.values();
-  for (int r = 0; r < num_row_blocks_e_; ++r) {
-    const int row_block_pos = bs->rows[r].block.position;
-    const int row_block_size = bs->rows[r].block.size;
-    const std::vector<Cell>& cells = bs->rows[r].cells;
-    for (int c = 1; c < cells.size(); ++c) {
-      const int col_block_id = cells[c].block_id;
-      const int col_block_pos = bs->cols[col_block_id].position;
-      const int col_block_size = bs->cols[col_block_id].size;
-      // clang-format off
-      MatrixVectorMultiply<kRowBlockSize, kFBlockSize, 1>(
-          values + cells[c].position, row_block_size, col_block_size,
-          x + col_block_pos - num_cols_e_,
-          y + row_block_pos);
-      // clang-format on
-    }
-  }
+  ParallelFor(options_.context,
+              0,
+              num_row_blocks_e_,
+              options_.num_threads,
+              [values, bs, num_cols_e, x, y](int row_block_id) {
+                const int row_block_pos = bs->rows[row_block_id].block.position;
+                const int row_block_size = bs->rows[row_block_id].block.size;
+                const auto& cells = bs->rows[row_block_id].cells;
+                for (int c = 1; c < cells.size(); ++c) {
+                  const int col_block_id = cells[c].block_id;
+                  const int col_block_pos = bs->cols[col_block_id].position;
+                  const int col_block_size = bs->cols[col_block_id].size;
+                  // clang-format off
+                  MatrixVectorMultiply<kRowBlockSize, kFBlockSize, 1>(
+                      values + cells[c].position, row_block_size, col_block_size,
+                      x + col_block_pos - num_cols_e,
+                      y + row_block_pos);
+                  // clang-format on
+                }
+              });
+  ParallelFor(options_.context,
+              num_row_blocks_e_,
+              num_row_blocks,
+              options_.num_threads,
+              [values, bs, num_cols_e, x, y](int row_block_id) {
+                const int row_block_pos = bs->rows[row_block_id].block.position;
+                const int row_block_size = bs->rows[row_block_id].block.size;
+                const auto& cells = bs->rows[row_block_id].cells;
+                for (const auto& cell : cells) {
+                  const int col_block_id = cell.block_id;
+                  const int col_block_pos = bs->cols[col_block_id].position;
+                  const int col_block_size = bs->cols[col_block_id].size;
+                  // clang-format off
+                  MatrixVectorMultiply<Eigen::Dynamic, Eigen::Dynamic, 1>(
+                      values + cell.position, row_block_size, col_block_size,
+                      x + col_block_pos - num_cols_e,
+                      y + row_block_pos);
+                  // clang-format on
+                }
+              });
+}
 
-  for (int r = num_row_blocks_e_; r < bs->rows.size(); ++r) {
-    const int row_block_pos = bs->rows[r].block.position;
-    const int row_block_size = bs->rows[r].block.size;
-    const std::vector<Cell>& cells = bs->rows[r].cells;
-    for (int c = 0; c < cells.size(); ++c) {
-      const int col_block_id = cells[c].block_id;
-      const int col_block_pos = bs->cols[col_block_id].position;
-      const int col_block_size = bs->cols[col_block_id].size;
-      // clang-format off
-      MatrixVectorMultiply<Eigen::Dynamic, Eigen::Dynamic, 1>(
-          values + cells[c].position, row_block_size, col_block_size,
-          x + col_block_pos - num_cols_e_,
-          y + row_block_pos);
-      // clang-format on
-    }
+template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
+void PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
+    LeftMultiplyAndAccumulateE(const double* x, double* y) const {
+  if (!num_col_blocks_e_) return;
+  if (!num_row_blocks_e_) return;
+  if (options_.num_threads == 1) {
+    LeftMultiplyAndAccumulateESingleThreaded(x, y);
+  } else {
+    CHECK(options_.context != nullptr);
+    LeftMultiplyAndAccumulateEMultiThreaded(x, y);
   }
 }
 
 template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
 void PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
-    LeftMultiplyE(const double* x, double* y) const {
+    LeftMultiplyAndAccumulateESingleThreaded(const double* x, double* y) const {
   const CompressedRowBlockStructure* bs = matrix_.block_structure();
 
   // Iterate over the first num_row_blocks_e_ row blocks, and multiply
@@ -185,7 +229,55 @@
 
 template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
 void PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
-    LeftMultiplyF(const double* x, double* y) const {
+    LeftMultiplyAndAccumulateEMultiThreaded(const double* x, double* y) const {
+  auto transpose_bs = matrix_.transpose_block_structure();
+  CHECK(transpose_bs != nullptr);
+
+  // Local copies of class members in order to avoid capturing pointer to the
+  // whole object in lambda function
+  auto values = matrix_.values();
+  const int num_row_blocks_e = num_row_blocks_e_;
+  ParallelFor(
+      options_.context,
+      0,
+      num_col_blocks_e_,
+      options_.num_threads,
+      [values, transpose_bs, num_row_blocks_e, x, y](int row_block_id) {
+        int row_block_pos = transpose_bs->rows[row_block_id].block.position;
+        int row_block_size = transpose_bs->rows[row_block_id].block.size;
+        auto& cells = transpose_bs->rows[row_block_id].cells;
+
+        for (auto& cell : cells) {
+          const int col_block_id = cell.block_id;
+          const int col_block_size = transpose_bs->cols[col_block_id].size;
+          const int col_block_pos = transpose_bs->cols[col_block_id].position;
+          if (col_block_id >= num_row_blocks_e) break;
+          MatrixTransposeVectorMultiply<kRowBlockSize, kEBlockSize, 1>(
+              values + cell.position,
+              col_block_size,
+              row_block_size,
+              x + col_block_pos,
+              y + row_block_pos);
+        }
+      },
+      e_cols_partition());
+}
+
+template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
+void PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
+    LeftMultiplyAndAccumulateF(const double* x, double* y) const {
+  if (!num_col_blocks_f_) return;
+  if (options_.num_threads == 1) {
+    LeftMultiplyAndAccumulateFSingleThreaded(x, y);
+  } else {
+    CHECK(options_.context != nullptr);
+    LeftMultiplyAndAccumulateFMultiThreaded(x, y);
+  }
+}
+
+template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
+void PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
+    LeftMultiplyAndAccumulateFSingleThreaded(const double* x, double* y) const {
   const CompressedRowBlockStructure* bs = matrix_.block_structure();
 
   // Iterate over row blocks, and if the row block is in E, then
@@ -215,13 +307,13 @@
     const int row_block_pos = bs->rows[r].block.position;
     const int row_block_size = bs->rows[r].block.size;
     const std::vector<Cell>& cells = bs->rows[r].cells;
-    for (int c = 0; c < cells.size(); ++c) {
-      const int col_block_id = cells[c].block_id;
+    for (const auto& cell : cells) {
+      const int col_block_id = cell.block_id;
       const int col_block_pos = bs->cols[col_block_id].position;
       const int col_block_size = bs->cols[col_block_id].size;
       // clang-format off
       MatrixTransposeVectorMultiply<Eigen::Dynamic, Eigen::Dynamic, 1>(
-        values + cells[c].position, row_block_size, col_block_size,
+        values + cell.position, row_block_size, col_block_size,
         x + row_block_pos,
         y + col_block_pos - num_cols_e_);
       // clang-format on
@@ -229,19 +321,71 @@
   }
 }
 
+template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
+void PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
+    LeftMultiplyAndAccumulateFMultiThreaded(const double* x, double* y) const {
+  auto transpose_bs = matrix_.transpose_block_structure();
+  CHECK(transpose_bs != nullptr);
+  // Local copies of class members  in order to avoid capturing pointer to the
+  // whole object in lambda function
+  auto values = matrix_.values();
+  const int num_row_blocks_e = num_row_blocks_e_;
+  const int num_cols_e = num_cols_e_;
+  ParallelFor(
+      options_.context,
+      num_col_blocks_e_,
+      num_col_blocks_e_ + num_col_blocks_f_,
+      options_.num_threads,
+      [values, transpose_bs, num_row_blocks_e, num_cols_e, x, y](
+          int row_block_id) {
+        int row_block_pos = transpose_bs->rows[row_block_id].block.position;
+        int row_block_size = transpose_bs->rows[row_block_id].block.size;
+        auto& cells = transpose_bs->rows[row_block_id].cells;
+
+        const int num_cells = cells.size();
+        int cell_idx = 0;
+        for (; cell_idx < num_cells; ++cell_idx) {
+          auto& cell = cells[cell_idx];
+          const int col_block_id = cell.block_id;
+          const int col_block_size = transpose_bs->cols[col_block_id].size;
+          const int col_block_pos = transpose_bs->cols[col_block_id].position;
+          if (col_block_id >= num_row_blocks_e) break;
+
+          MatrixTransposeVectorMultiply<kRowBlockSize, kFBlockSize, 1>(
+              values + cell.position,
+              col_block_size,
+              row_block_size,
+              x + col_block_pos,
+              y + row_block_pos - num_cols_e);
+        }
+        for (; cell_idx < num_cells; ++cell_idx) {
+          auto& cell = cells[cell_idx];
+          const int col_block_id = cell.block_id;
+          const int col_block_size = transpose_bs->cols[col_block_id].size;
+          const int col_block_pos = transpose_bs->cols[col_block_id].position;
+          MatrixTransposeVectorMultiply<Eigen::Dynamic, Eigen::Dynamic, 1>(
+              values + cell.position,
+              col_block_size,
+              row_block_size,
+              x + col_block_pos,
+              y + row_block_pos - num_cols_e);
+        }
+      },
+      f_cols_partition());
+}
+
 // Given a range of columns blocks of a matrix m, compute the block
 // structure of the block diagonal of the matrix m(:,
 // start_col_block:end_col_block)'m(:, start_col_block:end_col_block)
-// and return a BlockSparseMatrix with the this block structure. The
+// and return a BlockSparseMatrix with this block structure. The
 // caller owns the result.
 template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
-BlockSparseMatrix*
+std::unique_ptr<BlockSparseMatrix>
 PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
     CreateBlockDiagonalMatrixLayout(int start_col_block,
                                     int end_col_block) const {
   const CompressedRowBlockStructure* bs = matrix_.block_structure();
-  CompressedRowBlockStructure* block_diagonal_structure =
-      new CompressedRowBlockStructure;
+  auto* block_diagonal_structure = new CompressedRowBlockStructure;
 
   int block_position = 0;
   int diagonal_cell_position = 0;
@@ -250,16 +394,16 @@
   // each column block.
   for (int c = start_col_block; c < end_col_block; ++c) {
     const Block& block = bs->cols[c];
-    block_diagonal_structure->cols.push_back(Block());
+    block_diagonal_structure->cols.emplace_back();
     Block& diagonal_block = block_diagonal_structure->cols.back();
     diagonal_block.size = block.size;
     diagonal_block.position = block_position;
 
-    block_diagonal_structure->rows.push_back(CompressedRow());
+    block_diagonal_structure->rows.emplace_back();
     CompressedRow& row = block_diagonal_structure->rows.back();
     row.block = diagonal_block;
 
-    row.cells.push_back(Cell());
+    row.cells.emplace_back();
     Cell& cell = row.cells.back();
     cell.block_id = c - start_col_block;
     cell.position = diagonal_cell_position;
@@ -270,42 +414,41 @@
 
   // Build a BlockSparseMatrix with the just computed block
   // structure.
-  return new BlockSparseMatrix(block_diagonal_structure);
+  return std::make_unique<BlockSparseMatrix>(block_diagonal_structure);
 }
 
 template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
-BlockSparseMatrix* PartitionedMatrixView<kRowBlockSize,
-                                         kEBlockSize,
-                                         kFBlockSize>::CreateBlockDiagonalEtE()
-    const {
-  BlockSparseMatrix* block_diagonal =
+std::unique_ptr<BlockSparseMatrix>
+PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
+    CreateBlockDiagonalEtE() const {
+  std::unique_ptr<BlockSparseMatrix> block_diagonal =
       CreateBlockDiagonalMatrixLayout(0, num_col_blocks_e_);
-  UpdateBlockDiagonalEtE(block_diagonal);
+  UpdateBlockDiagonalEtE(block_diagonal.get());
   return block_diagonal;
 }
 
 template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
-BlockSparseMatrix* PartitionedMatrixView<kRowBlockSize,
-                                         kEBlockSize,
-                                         kFBlockSize>::CreateBlockDiagonalFtF()
-    const {
-  BlockSparseMatrix* block_diagonal = CreateBlockDiagonalMatrixLayout(
-      num_col_blocks_e_, num_col_blocks_e_ + num_col_blocks_f_);
-  UpdateBlockDiagonalFtF(block_diagonal);
+std::unique_ptr<BlockSparseMatrix>
+PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
+    CreateBlockDiagonalFtF() const {
+  std::unique_ptr<BlockSparseMatrix> block_diagonal =
+      CreateBlockDiagonalMatrixLayout(num_col_blocks_e_,
+                                      num_col_blocks_e_ + num_col_blocks_f_);
+  UpdateBlockDiagonalFtF(block_diagonal.get());
   return block_diagonal;
 }
 
-// Similar to the code in RightMultiplyE, except instead of the matrix
-// vector multiply its an outer product.
+// Similar to the code in RightMultiplyAndAccumulateE, except instead of the
+// matrix vector multiply its an outer product.
 //
 //    block_diagonal = block_diagonal(E'E)
 //
 template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
 void PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
-    UpdateBlockDiagonalEtE(BlockSparseMatrix* block_diagonal) const {
-  const CompressedRowBlockStructure* bs = matrix_.block_structure();
-  const CompressedRowBlockStructure* block_diagonal_structure =
-      block_diagonal->block_structure();
+    UpdateBlockDiagonalEtESingleThreaded(
+        BlockSparseMatrix* block_diagonal) const {
+  auto bs = matrix_.block_structure();
+  auto block_diagonal_structure = block_diagonal->block_structure();
 
   block_diagonal->SetZero();
   const double* values = matrix_.values();
@@ -328,17 +471,68 @@
   }
 }
 
-// Similar to the code in RightMultiplyF, except instead of the matrix
-// vector multiply its an outer product.
+template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
+void PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
+    UpdateBlockDiagonalEtEMultiThreaded(
+        BlockSparseMatrix* block_diagonal) const {
+  auto transpose_block_structure = matrix_.transpose_block_structure();
+  CHECK(transpose_block_structure != nullptr);
+  auto block_diagonal_structure = block_diagonal->block_structure();
+
+  const double* values = matrix_.values();
+  double* values_diagonal = block_diagonal->mutable_values();
+  ParallelFor(
+      options_.context,
+      0,
+      num_col_blocks_e_,
+      options_.num_threads,
+      [values,
+       transpose_block_structure,
+       values_diagonal,
+       block_diagonal_structure](int col_block_id) {
+        int cell_position =
+            block_diagonal_structure->rows[col_block_id].cells[0].position;
+        double* cell_values = values_diagonal + cell_position;
+        int col_block_size =
+            transpose_block_structure->rows[col_block_id].block.size;
+        auto& cells = transpose_block_structure->rows[col_block_id].cells;
+        MatrixRef(cell_values, col_block_size, col_block_size).setZero();
+
+        for (auto& c : cells) {
+          int row_block_size = transpose_block_structure->cols[c.block_id].size;
+          // clang-format off
+          MatrixTransposeMatrixMultiply<kRowBlockSize, kEBlockSize, kRowBlockSize, kEBlockSize, 1>(
+            values + c.position, row_block_size, col_block_size,
+            values + c.position, row_block_size, col_block_size,
+            cell_values, 0, 0, col_block_size, col_block_size);
+          // clang-format on
+        }
+      },
+      e_cols_partition_);
+}
+
+template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
+void PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
+    UpdateBlockDiagonalEtE(BlockSparseMatrix* block_diagonal) const {
+  if (options_.num_threads == 1) {
+    UpdateBlockDiagonalEtESingleThreaded(block_diagonal);
+  } else {
+    CHECK(options_.context != nullptr);
+    UpdateBlockDiagonalEtEMultiThreaded(block_diagonal);
+  }
+}
+
+// Similar to the code in RightMultiplyAndAccumulateF, except instead of the
+// matrix vector multiply its an outer product.
 //
 //   block_diagonal = block_diagonal(F'F)
 //
 template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
 void PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
-    UpdateBlockDiagonalFtF(BlockSparseMatrix* block_diagonal) const {
-  const CompressedRowBlockStructure* bs = matrix_.block_structure();
-  const CompressedRowBlockStructure* block_diagonal_structure =
-      block_diagonal->block_structure();
+    UpdateBlockDiagonalFtFSingleThreaded(
+        BlockSparseMatrix* block_diagonal) const {
+  auto bs = matrix_.block_structure();
+  auto block_diagonal_structure = block_diagonal->block_structure();
 
   block_diagonal->SetZero();
   const double* values = matrix_.values();
@@ -366,8 +560,8 @@
   for (int r = num_row_blocks_e_; r < bs->rows.size(); ++r) {
     const int row_block_size = bs->rows[r].block.size;
     const std::vector<Cell>& cells = bs->rows[r].cells;
-    for (int c = 0; c < cells.size(); ++c) {
-      const int col_block_id = cells[c].block_id;
+    for (const auto& cell : cells) {
+      const int col_block_id = cell.block_id;
       const int col_block_size = bs->cols[col_block_id].size;
       const int diagonal_block_id = col_block_id - num_col_blocks_e_;
       const int cell_position =
@@ -376,8 +570,8 @@
       // clang-format off
       MatrixTransposeMatrixMultiply
           <Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic, 1>(
-              values + cells[c].position, row_block_size, col_block_size,
-              values + cells[c].position, row_block_size, col_block_size,
+              values + cell.position, row_block_size, col_block_size,
+              values + cell.position, row_block_size, col_block_size,
               block_diagonal->mutable_values() + cell_position,
               0, 0, col_block_size, col_block_size);
       // clang-format on
@@ -385,5 +579,82 @@
   }
 }
 
-}  // namespace internal
-}  // namespace ceres
+template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
+void PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
+    UpdateBlockDiagonalFtFMultiThreaded(
+        BlockSparseMatrix* block_diagonal) const {
+  auto transpose_block_structure = matrix_.transpose_block_structure();
+  CHECK(transpose_block_structure != nullptr);
+  auto block_diagonal_structure = block_diagonal->block_structure();
+
+  const double* values = matrix_.values();
+  double* values_diagonal = block_diagonal->mutable_values();
+
+  const int num_col_blocks_e = num_col_blocks_e_;
+  const int num_row_blocks_e = num_row_blocks_e_;
+  ParallelFor(
+      options_.context,
+      num_col_blocks_e_,
+      num_col_blocks_e + num_col_blocks_f_,
+      options_.num_threads,
+      [transpose_block_structure,
+       block_diagonal_structure,
+       num_col_blocks_e,
+       num_row_blocks_e,
+       values,
+       values_diagonal](int col_block_id) {
+        const int col_block_size =
+            transpose_block_structure->rows[col_block_id].block.size;
+        const int diagonal_block_id = col_block_id - num_col_blocks_e;
+        const int cell_position =
+            block_diagonal_structure->rows[diagonal_block_id].cells[0].position;
+        double* cell_values = values_diagonal + cell_position;
+
+        MatrixRef(cell_values, col_block_size, col_block_size).setZero();
+
+        auto& cells = transpose_block_structure->rows[col_block_id].cells;
+        const int num_cells = cells.size();
+        int i = 0;
+        for (; i < num_cells; ++i) {
+          auto& cell = cells[i];
+          const int row_block_id = cell.block_id;
+          if (row_block_id >= num_row_blocks_e) break;
+          const int row_block_size =
+              transpose_block_structure->cols[row_block_id].size;
+          // clang-format off
+          MatrixTransposeMatrixMultiply
+              <kRowBlockSize, kFBlockSize, kRowBlockSize, kFBlockSize, 1>(
+                  values + cell.position, row_block_size, col_block_size,
+                  values + cell.position, row_block_size, col_block_size,
+                  cell_values, 0, 0, col_block_size, col_block_size);
+          // clang-format on
+        }
+        for (; i < num_cells; ++i) {
+          auto& cell = cells[i];
+          const int row_block_id = cell.block_id;
+          const int row_block_size =
+              transpose_block_structure->cols[row_block_id].size;
+          // clang-format off
+          MatrixTransposeMatrixMultiply
+              <Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic, 1>(
+                  values + cell.position, row_block_size, col_block_size,
+                  values + cell.position, row_block_size, col_block_size,
+                  cell_values, 0, 0, col_block_size, col_block_size);
+          // clang-format on
+        }
+      },
+      f_cols_partition_);
+}
+
+template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
+void PartitionedMatrixView<kRowBlockSize, kEBlockSize, kFBlockSize>::
+    UpdateBlockDiagonalFtF(BlockSparseMatrix* block_diagonal) const {
+  if (options_.num_threads == 1) {
+    UpdateBlockDiagonalFtFSingleThreaded(block_diagonal);
+  } else {
+    CHECK(options_.context != nullptr);
+    UpdateBlockDiagonalFtFMultiThreaded(block_diagonal);
+  }
+}
+
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/partitioned_matrix_view_template.py b/third_party/ceres/internal/ceres/partitioned_matrix_view_template.py
index 05a25bf..9af4c0e 100644
--- a/third_party/ceres/internal/ceres/partitioned_matrix_view_template.py
+++ b/third_party/ceres/internal/ceres/partitioned_matrix_view_template.py
@@ -1,5 +1,5 @@
 # Ceres Solver - A fast non-linear least squares minimizer
-# Copyright 2015 Google Inc. All rights reserved.
+# Copyright 2023 Google Inc. All rights reserved.
 # http://ceres-solver.org/
 #
 # Redistribution and use in source and binary forms, with or without
@@ -47,7 +47,7 @@
 # specializations that is generated.
 
 HEADER = """// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -91,61 +91,59 @@
 DYNAMIC_FILE = """
 #include "ceres/partitioned_matrix_view_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class PartitionedMatrixView<%s,
                                      %s,
                                      %s>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 """
 
 SPECIALIZATION_FILE = """
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
 
 #include "ceres/partitioned_matrix_view_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class PartitionedMatrixView<%s, %s, %s>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
 """
 
 FACTORY_FILE_HEADER = """
+#include <memory>
+
 #include "ceres/linear_solver.h"
 #include "ceres/partitioned_matrix_view.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
-PartitionedMatrixViewBase* PartitionedMatrixViewBase::Create(
+PartitionedMatrixViewBase::~PartitionedMatrixViewBase() = default;
+
+std::unique_ptr<PartitionedMatrixViewBase> PartitionedMatrixViewBase::Create(
     const LinearSolver::Options& options, const BlockSparseMatrix& matrix) {
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
 """
-FACTORY = """  return new PartitionedMatrixView<%s, %s, %s>(matrix,
-                                              options.elimination_groups[0]);"""
+FACTORY = """  return std::make_unique<PartitionedMatrixView<%s,%s, %s>>(
+                   options, matrix);"""
 
 FACTORY_FOOTER = """
 #endif
   VLOG(1) << "Template specializations not found for <"
           << options.row_block_size << "," << options.e_block_size << ","
           << options.f_block_size << ">";
-  return new PartitionedMatrixView<Eigen::Dynamic,
-                                   Eigen::Dynamic,
-                                   Eigen::Dynamic>(
-      matrix, options.elimination_groups[0]);
+  return std::make_unique<PartitionedMatrixView<Eigen::Dynamic,
+                                                Eigen::Dynamic,
+                                                Eigen::Dynamic>>(
+      options, matrix);
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 """
diff --git a/third_party/ceres/internal/ceres/partitioned_matrix_view_test.cc b/third_party/ceres/internal/ceres/partitioned_matrix_view_test.cc
index b66d0b8..3addba6 100644
--- a/third_party/ceres/internal/ceres/partitioned_matrix_view_test.cc
+++ b/third_party/ceres/internal/ceres/partitioned_matrix_view_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -31,13 +31,15 @@
 #include "ceres/partitioned_matrix_view.h"
 
 #include <memory>
+#include <random>
+#include <sstream>
+#include <string>
 #include <vector>
 
 #include "ceres/block_structure.h"
 #include "ceres/casts.h"
 #include "ceres/internal/eigen.h"
 #include "ceres/linear_least_squares_problems.h"
-#include "ceres/random.h"
 #include "ceres/sparse_matrix.h"
 #include "glog/logging.h"
 #include "gtest/gtest.h"
@@ -47,41 +49,58 @@
 
 const double kEpsilon = 1e-14;
 
-class PartitionedMatrixViewTest : public ::testing::Test {
- protected:
-  void SetUp() final {
-    srand(5);
-    std::unique_ptr<LinearLeastSquaresProblem> problem(
-        CreateLinearLeastSquaresProblemFromId(2));
-    CHECK(problem != nullptr);
-    A_.reset(problem->A.release());
+// Param = <problem_id, num_threads>
+using Param = ::testing::tuple<int, int>;
 
-    num_cols_ = A_->num_cols();
-    num_rows_ = A_->num_rows();
-    num_eliminate_blocks_ = problem->num_eliminate_blocks;
-    LinearSolver::Options options;
-    options.elimination_groups.push_back(num_eliminate_blocks_);
-    pmv_.reset(PartitionedMatrixViewBase::Create(
-        options, *down_cast<BlockSparseMatrix*>(A_.get())));
-  }
-
-  int num_rows_;
-  int num_cols_;
-  int num_eliminate_blocks_;
-  std::unique_ptr<SparseMatrix> A_;
-  std::unique_ptr<PartitionedMatrixViewBase> pmv_;
-};
-
-TEST_F(PartitionedMatrixViewTest, DimensionsTest) {
-  EXPECT_EQ(pmv_->num_col_blocks_e(), num_eliminate_blocks_);
-  EXPECT_EQ(pmv_->num_col_blocks_f(), num_cols_ - num_eliminate_blocks_);
-  EXPECT_EQ(pmv_->num_cols_e(), num_eliminate_blocks_);
-  EXPECT_EQ(pmv_->num_cols_f(), num_cols_ - num_eliminate_blocks_);
-  EXPECT_EQ(pmv_->num_cols(), A_->num_cols());
-  EXPECT_EQ(pmv_->num_rows(), A_->num_rows());
+static std::string ParamInfoToString(testing::TestParamInfo<Param> info) {
+  Param param = info.param;
+  std::stringstream ss;
+  ss << ::testing::get<0>(param) << "_" << ::testing::get<1>(param);
+  return ss.str();
 }
 
-TEST_F(PartitionedMatrixViewTest, RightMultiplyE) {
+class PartitionedMatrixViewTest : public ::testing::TestWithParam<Param> {
+ protected:
+  void SetUp() final {
+    const int problem_id = ::testing::get<0>(GetParam());
+    const int num_threads = ::testing::get<1>(GetParam());
+    auto problem = CreateLinearLeastSquaresProblemFromId(problem_id);
+    CHECK(problem != nullptr);
+    A_ = std::move(problem->A);
+    auto block_sparse = down_cast<BlockSparseMatrix*>(A_.get());
+
+    options_.num_threads = num_threads;
+    options_.context = &context_;
+    options_.elimination_groups.push_back(problem->num_eliminate_blocks);
+    pmv_ = PartitionedMatrixViewBase::Create(options_, *block_sparse);
+
+    LinearSolver::Options options_single_threaded = options_;
+    options_single_threaded.num_threads = 1;
+    pmv_single_threaded_ =
+        PartitionedMatrixViewBase::Create(options_, *block_sparse);
+
+    EXPECT_EQ(pmv_->num_col_blocks_e(), problem->num_eliminate_blocks);
+    EXPECT_EQ(pmv_->num_col_blocks_f(),
+              block_sparse->block_structure()->cols.size() -
+                  problem->num_eliminate_blocks);
+    EXPECT_EQ(pmv_->num_cols(), A_->num_cols());
+    EXPECT_EQ(pmv_->num_rows(), A_->num_rows());
+  }
+
+  double RandDouble() { return distribution_(prng_); }
+
+  LinearSolver::Options options_;
+  ContextImpl context_;
+  std::unique_ptr<LinearLeastSquaresProblem> problem_;
+  std::unique_ptr<SparseMatrix> A_;
+  std::unique_ptr<PartitionedMatrixViewBase> pmv_;
+  std::unique_ptr<PartitionedMatrixViewBase> pmv_single_threaded_;
+  std::mt19937 prng_;
+  std::uniform_real_distribution<double> distribution_ =
+      std::uniform_real_distribution<double>(0.0, 1.0);
+};
+
+TEST_P(PartitionedMatrixViewTest, RightMultiplyAndAccumulateE) {
   Vector x1(pmv_->num_cols_e());
   Vector x2(pmv_->num_cols());
   x2.setZero();
@@ -90,85 +109,164 @@
     x1(i) = x2(i) = RandDouble();
   }
 
-  Vector y1 = Vector::Zero(pmv_->num_rows());
-  pmv_->RightMultiplyE(x1.data(), y1.data());
+  Vector expected = Vector::Zero(pmv_->num_rows());
+  A_->RightMultiplyAndAccumulate(x2.data(), expected.data());
 
-  Vector y2 = Vector::Zero(pmv_->num_rows());
-  A_->RightMultiply(x2.data(), y2.data());
+  Vector actual = Vector::Zero(pmv_->num_rows());
+  pmv_->RightMultiplyAndAccumulateE(x1.data(), actual.data());
 
   for (int i = 0; i < pmv_->num_rows(); ++i) {
-    EXPECT_NEAR(y1(i), y2(i), kEpsilon);
+    EXPECT_NEAR(actual(i), expected(i), kEpsilon);
   }
 }
 
-TEST_F(PartitionedMatrixViewTest, RightMultiplyF) {
+TEST_P(PartitionedMatrixViewTest, RightMultiplyAndAccumulateF) {
   Vector x1(pmv_->num_cols_f());
-  Vector x2 = Vector::Zero(pmv_->num_cols());
+  Vector x2(pmv_->num_cols());
+  x2.setZero();
 
   for (int i = 0; i < pmv_->num_cols_f(); ++i) {
-    x1(i) = RandDouble();
-    x2(i + pmv_->num_cols_e()) = x1(i);
+    x1(i) = x2(i + pmv_->num_cols_e()) = RandDouble();
   }
 
-  Vector y1 = Vector::Zero(pmv_->num_rows());
-  pmv_->RightMultiplyF(x1.data(), y1.data());
+  Vector actual = Vector::Zero(pmv_->num_rows());
+  pmv_->RightMultiplyAndAccumulateF(x1.data(), actual.data());
 
-  Vector y2 = Vector::Zero(pmv_->num_rows());
-  A_->RightMultiply(x2.data(), y2.data());
+  Vector expected = Vector::Zero(pmv_->num_rows());
+  A_->RightMultiplyAndAccumulate(x2.data(), expected.data());
 
   for (int i = 0; i < pmv_->num_rows(); ++i) {
-    EXPECT_NEAR(y1(i), y2(i), kEpsilon);
+    EXPECT_NEAR(actual(i), expected(i), kEpsilon);
   }
 }
 
-TEST_F(PartitionedMatrixViewTest, LeftMultiply) {
+TEST_P(PartitionedMatrixViewTest, LeftMultiplyAndAccumulate) {
   Vector x = Vector::Zero(pmv_->num_rows());
   for (int i = 0; i < pmv_->num_rows(); ++i) {
     x(i) = RandDouble();
   }
+  Vector x_pre = x;
 
-  Vector y = Vector::Zero(pmv_->num_cols());
-  Vector y1 = Vector::Zero(pmv_->num_cols_e());
-  Vector y2 = Vector::Zero(pmv_->num_cols_f());
+  Vector expected = Vector::Zero(pmv_->num_cols());
+  Vector e_actual = Vector::Zero(pmv_->num_cols_e());
+  Vector f_actual = Vector::Zero(pmv_->num_cols_f());
 
-  A_->LeftMultiply(x.data(), y.data());
-  pmv_->LeftMultiplyE(x.data(), y1.data());
-  pmv_->LeftMultiplyF(x.data(), y2.data());
+  A_->LeftMultiplyAndAccumulate(x.data(), expected.data());
+  pmv_->LeftMultiplyAndAccumulateE(x.data(), e_actual.data());
+  pmv_->LeftMultiplyAndAccumulateF(x.data(), f_actual.data());
 
   for (int i = 0; i < pmv_->num_cols(); ++i) {
-    EXPECT_NEAR(y(i),
-                (i < pmv_->num_cols_e()) ? y1(i) : y2(i - pmv_->num_cols_e()),
+    EXPECT_NEAR(expected(i),
+                (i < pmv_->num_cols_e()) ? e_actual(i)
+                                         : f_actual(i - pmv_->num_cols_e()),
                 kEpsilon);
   }
 }
 
-TEST_F(PartitionedMatrixViewTest, BlockDiagonalEtE) {
+TEST_P(PartitionedMatrixViewTest, BlockDiagonalFtF) {
+  std::unique_ptr<BlockSparseMatrix> block_diagonal_ff(
+      pmv_->CreateBlockDiagonalFtF());
+  const auto bs_diagonal = block_diagonal_ff->block_structure();
+  const int num_rows = pmv_->num_rows();
+  const int num_cols_f = pmv_->num_cols_f();
+  const int num_cols_e = pmv_->num_cols_e();
+  const int num_col_blocks_f = pmv_->num_col_blocks_f();
+  const int num_col_blocks_e = pmv_->num_col_blocks_e();
+
+  CHECK_EQ(block_diagonal_ff->num_rows(), num_cols_f);
+  CHECK_EQ(block_diagonal_ff->num_cols(), num_cols_f);
+
+  EXPECT_EQ(bs_diagonal->cols.size(), num_col_blocks_f);
+  EXPECT_EQ(bs_diagonal->rows.size(), num_col_blocks_f);
+
+  Matrix EF;
+  A_->ToDenseMatrix(&EF);
+  const auto F = EF.topRightCorner(num_rows, num_cols_f);
+
+  Matrix expected_FtF = F.transpose() * F;
+  Matrix actual_FtF;
+  block_diagonal_ff->ToDenseMatrix(&actual_FtF);
+
+  // FtF might be not block-diagonal
+  auto bs = down_cast<BlockSparseMatrix*>(A_.get())->block_structure();
+  for (int i = 0; i < num_col_blocks_f; ++i) {
+    const auto col_block_f = bs->cols[num_col_blocks_e + i];
+    const int block_size = col_block_f.size;
+    const int block_pos = col_block_f.position - num_cols_e;
+    const auto cell_expected =
+        expected_FtF.block(block_pos, block_pos, block_size, block_size);
+    auto cell_actual =
+        actual_FtF.block(block_pos, block_pos, block_size, block_size);
+    cell_actual -= cell_expected;
+    EXPECT_NEAR(cell_actual.norm(), 0., kEpsilon);
+  }
+  // There should be nothing remaining outside block-diagonal
+  EXPECT_NEAR(actual_FtF.norm(), 0., kEpsilon);
+}
+
+TEST_P(PartitionedMatrixViewTest, BlockDiagonalEtE) {
   std::unique_ptr<BlockSparseMatrix> block_diagonal_ee(
       pmv_->CreateBlockDiagonalEtE());
   const CompressedRowBlockStructure* bs = block_diagonal_ee->block_structure();
+  const int num_rows = pmv_->num_rows();
+  const int num_cols_e = pmv_->num_cols_e();
+  const int num_col_blocks_e = pmv_->num_col_blocks_e();
 
-  EXPECT_EQ(block_diagonal_ee->num_rows(), 2);
-  EXPECT_EQ(block_diagonal_ee->num_cols(), 2);
-  EXPECT_EQ(bs->cols.size(), 2);
-  EXPECT_EQ(bs->rows.size(), 2);
+  CHECK_EQ(block_diagonal_ee->num_rows(), num_cols_e);
+  CHECK_EQ(block_diagonal_ee->num_cols(), num_cols_e);
 
-  EXPECT_NEAR(block_diagonal_ee->values()[0], 10.0, kEpsilon);
-  EXPECT_NEAR(block_diagonal_ee->values()[1], 155.0, kEpsilon);
+  EXPECT_EQ(bs->cols.size(), num_col_blocks_e);
+  EXPECT_EQ(bs->rows.size(), num_col_blocks_e);
+
+  Matrix EF;
+  A_->ToDenseMatrix(&EF);
+  const auto E = EF.topLeftCorner(num_rows, num_cols_e);
+
+  Matrix expected_EtE = E.transpose() * E;
+  Matrix actual_EtE;
+  block_diagonal_ee->ToDenseMatrix(&actual_EtE);
+
+  EXPECT_NEAR((expected_EtE - actual_EtE).norm(), 0., kEpsilon);
 }
 
-TEST_F(PartitionedMatrixViewTest, BlockDiagonalFtF) {
-  std::unique_ptr<BlockSparseMatrix> block_diagonal_ff(
+TEST_P(PartitionedMatrixViewTest, UpdateBlockDiagonalEtE) {
+  std::unique_ptr<BlockSparseMatrix> block_diagonal_ete(
+      pmv_->CreateBlockDiagonalEtE());
+  const int num_cols = pmv_->num_cols_e();
+
+  Matrix multi_threaded(num_cols, num_cols);
+  pmv_->UpdateBlockDiagonalEtE(block_diagonal_ete.get());
+  block_diagonal_ete->ToDenseMatrix(&multi_threaded);
+
+  Matrix single_threaded(num_cols, num_cols);
+  pmv_single_threaded_->UpdateBlockDiagonalEtE(block_diagonal_ete.get());
+  block_diagonal_ete->ToDenseMatrix(&single_threaded);
+
+  EXPECT_NEAR((multi_threaded - single_threaded).norm(), 0., kEpsilon);
+}
+
+TEST_P(PartitionedMatrixViewTest, UpdateBlockDiagonalFtF) {
+  std::unique_ptr<BlockSparseMatrix> block_diagonal_ftf(
       pmv_->CreateBlockDiagonalFtF());
-  const CompressedRowBlockStructure* bs = block_diagonal_ff->block_structure();
+  const int num_cols = pmv_->num_cols_f();
 
-  EXPECT_EQ(block_diagonal_ff->num_rows(), 3);
-  EXPECT_EQ(block_diagonal_ff->num_cols(), 3);
-  EXPECT_EQ(bs->cols.size(), 3);
-  EXPECT_EQ(bs->rows.size(), 3);
-  EXPECT_NEAR(block_diagonal_ff->values()[0], 70.0, kEpsilon);
-  EXPECT_NEAR(block_diagonal_ff->values()[1], 17.0, kEpsilon);
-  EXPECT_NEAR(block_diagonal_ff->values()[2], 37.0, kEpsilon);
+  Matrix multi_threaded(num_cols, num_cols);
+  pmv_->UpdateBlockDiagonalFtF(block_diagonal_ftf.get());
+  block_diagonal_ftf->ToDenseMatrix(&multi_threaded);
+
+  Matrix single_threaded(num_cols, num_cols);
+  pmv_single_threaded_->UpdateBlockDiagonalFtF(block_diagonal_ftf.get());
+  block_diagonal_ftf->ToDenseMatrix(&single_threaded);
+
+  EXPECT_NEAR((multi_threaded - single_threaded).norm(), 0., kEpsilon);
 }
 
+INSTANTIATE_TEST_SUITE_P(
+    ParallelProducts,
+    PartitionedMatrixViewTest,
+    ::testing::Combine(::testing::Values(2, 4, 6),
+                       ::testing::Values(1, 2, 3, 4, 5, 6, 7, 8)),
+    ParamInfoToString);
+
 }  // namespace internal
 }  // namespace ceres
diff --git a/third_party/ceres/internal/ceres/polynomial.cc b/third_party/ceres/internal/ceres/polynomial.cc
index 20812f4..8e99e34 100644
--- a/third_party/ceres/internal/ceres/polynomial.cc
+++ b/third_party/ceres/internal/ceres/polynomial.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -37,13 +37,10 @@
 
 #include "Eigen/Dense"
 #include "ceres/function_sample.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
-
-using std::vector;
+namespace ceres::internal {
 
 namespace {
 
@@ -128,12 +125,12 @@
                                Vector* real,
                                Vector* imaginary) {
   CHECK_EQ(polynomial.size(), 2);
-  if (real != NULL) {
+  if (real != nullptr) {
     real->resize(1);
     (*real)(0) = -polynomial(1) / polynomial(0);
   }
 
-  if (imaginary != NULL) {
+  if (imaginary != nullptr) {
     imaginary->setZero(1);
   }
 }
@@ -147,16 +144,16 @@
   const double c = polynomial(2);
   const double D = b * b - 4 * a * c;
   const double sqrt_D = sqrt(fabs(D));
-  if (real != NULL) {
+  if (real != nullptr) {
     real->setZero(2);
   }
-  if (imaginary != NULL) {
+  if (imaginary != nullptr) {
     imaginary->setZero(2);
   }
 
   // Real roots.
   if (D >= 0) {
-    if (real != NULL) {
+    if (real != nullptr) {
       // Stable quadratic roots according to BKP Horn.
       // http://people.csail.mit.edu/bkph/articles/Quadratics.pdf
       if (b >= 0) {
@@ -171,11 +168,11 @@
   }
 
   // Use the normal quadratic formula for the complex case.
-  if (real != NULL) {
+  if (real != nullptr) {
     (*real)(0) = -b / (2.0 * a);
     (*real)(1) = -b / (2.0 * a);
   }
-  if (imaginary != NULL) {
+  if (imaginary != nullptr) {
     (*imaginary)(0) = sqrt_D / (2.0 * a);
     (*imaginary)(1) = -sqrt_D / (2.0 * a);
   }
@@ -240,14 +237,14 @@
   }
 
   // Output roots
-  if (real != NULL) {
+  if (real != nullptr) {
     *real = solver.eigenvalues().real();
   } else {
-    LOG(WARNING) << "NULL pointer passed as real argument to "
+    LOG(WARNING) << "nullptr pointer passed as real argument to "
                  << "FindPolynomialRoots. Real parts of the roots will not "
                  << "be returned.";
   }
-  if (imaginary != NULL) {
+  if (imaginary != nullptr) {
     *imaginary = solver.eigenvalues().imag();
   }
   return true;
@@ -304,7 +301,7 @@
 
   const Vector derivative = DifferentiatePolynomial(polynomial);
   Vector roots_real;
-  if (!FindPolynomialRoots(derivative, &roots_real, NULL)) {
+  if (!FindPolynomialRoots(derivative, &roots_real, nullptr)) {
     LOG(WARNING) << "Unable to find the critical points of "
                  << "the interpolating polynomial.";
     return;
@@ -326,7 +323,7 @@
   }
 }
 
-Vector FindInterpolatingPolynomial(const vector<FunctionSample>& samples) {
+Vector FindInterpolatingPolynomial(const std::vector<FunctionSample>& samples) {
   const int num_samples = samples.size();
   int num_constraints = 0;
   for (int i = 0; i < num_samples; ++i) {
@@ -369,15 +366,14 @@
   return lu.setThreshold(0.0).solve(rhs);
 }
 
-void MinimizeInterpolatingPolynomial(const vector<FunctionSample>& samples,
+void MinimizeInterpolatingPolynomial(const std::vector<FunctionSample>& samples,
                                      double x_min,
                                      double x_max,
                                      double* optimal_x,
                                      double* optimal_value) {
   const Vector polynomial = FindInterpolatingPolynomial(samples);
   MinimizePolynomial(polynomial, x_min, x_max, optimal_x, optimal_value);
-  for (int i = 0; i < samples.size(); ++i) {
-    const FunctionSample& sample = samples[i];
+  for (const auto& sample : samples) {
     if ((sample.x < x_min) || (sample.x > x_max)) {
       continue;
     }
@@ -390,5 +386,4 @@
   }
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/polynomial.h b/third_party/ceres/internal/ceres/polynomial.h
index 20071f2..8c40628 100644
--- a/third_party/ceres/internal/ceres/polynomial.h
+++ b/third_party/ceres/internal/ceres/polynomial.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -34,11 +34,11 @@
 
 #include <vector>
 
+#include "ceres/internal/disable_warnings.h"
 #include "ceres/internal/eigen.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 struct FunctionSample;
 
@@ -49,6 +49,7 @@
 // and are given by a vector of coefficients of size N + 1.
 
 // Evaluate the polynomial at x using the Horner scheme.
+CERES_NO_EXPORT
 inline double EvaluatePolynomial(const Vector& polynomial, double x) {
   double v = 0.0;
   for (int i = 0; i < polynomial.size(); ++i) {
@@ -64,15 +65,16 @@
 // Failure indicates that the polynomial is invalid (of size 0) or
 // that the eigenvalues of the companion matrix could not be computed.
 // On failure, a more detailed message will be written to LOG(ERROR).
-// If real is not NULL, the real parts of the roots will be returned in it.
-// Likewise, if imaginary is not NULL, imaginary parts will be returned in it.
-CERES_EXPORT_INTERNAL bool FindPolynomialRoots(const Vector& polynomial,
-                                               Vector* real,
-                                               Vector* imaginary);
+// If real is not nullptr, the real parts of the roots will be returned in it.
+// Likewise, if imaginary is not nullptr, imaginary parts will be returned in
+// it.
+CERES_NO_EXPORT bool FindPolynomialRoots(const Vector& polynomial,
+                                         Vector* real,
+                                         Vector* imaginary);
 
 // Return the derivative of the given polynomial. It is assumed that
 // the input polynomial is at least of degree zero.
-CERES_EXPORT_INTERNAL Vector DifferentiatePolynomial(const Vector& polynomial);
+CERES_NO_EXPORT Vector DifferentiatePolynomial(const Vector& polynomial);
 
 // Find the minimum value of the polynomial in the interval [x_min,
 // x_max]. The minimum is obtained by computing all the roots of the
@@ -80,11 +82,11 @@
 // interval [x_min, x_max] are considered as well as the end points
 // x_min and x_max. Since polynomials are differentiable functions,
 // this ensures that the true minimum is found.
-CERES_EXPORT_INTERNAL void MinimizePolynomial(const Vector& polynomial,
-                                              double x_min,
-                                              double x_max,
-                                              double* optimal_x,
-                                              double* optimal_value);
+CERES_NO_EXPORT void MinimizePolynomial(const Vector& polynomial,
+                                        double x_min,
+                                        double x_max,
+                                        double* optimal_x,
+                                        double* optimal_value);
 
 // Given a set of function value and/or gradient samples, find a
 // polynomial whose value and gradients are exactly equal to the ones
@@ -97,7 +99,7 @@
 // Of course its possible to sample a polynomial any number of times,
 // in which case, generally speaking the spurious higher order
 // coefficients will be zero.
-CERES_EXPORT_INTERNAL Vector
+CERES_NO_EXPORT Vector
 FindInterpolatingPolynomial(const std::vector<FunctionSample>& samples);
 
 // Interpolate the function described by samples with a polynomial,
@@ -106,14 +108,15 @@
 // finding algorithms may fail due to numerical difficulties. But the
 // function is guaranteed to return its best guess of an answer, by
 // considering the samples and the end points as possible solutions.
-CERES_EXPORT_INTERNAL void MinimizeInterpolatingPolynomial(
+CERES_NO_EXPORT void MinimizeInterpolatingPolynomial(
     const std::vector<FunctionSample>& samples,
     double x_min,
     double x_max,
     double* optimal_x,
     double* optimal_value);
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_POLYNOMIAL_SOLVER_H_
diff --git a/third_party/ceres/internal/ceres/polynomial_test.cc b/third_party/ceres/internal/ceres/polynomial_test.cc
index 0ff73ea..a87ea46 100644
--- a/third_party/ceres/internal/ceres/polynomial_test.cc
+++ b/third_party/ceres/internal/ceres/polynomial_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,15 +35,13 @@
 #include <cmath>
 #include <cstddef>
 #include <limits>
+#include <vector>
 
 #include "ceres/function_sample.h"
 #include "ceres/test_util.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
-
-using std::vector;
+namespace ceres::internal {
 
 namespace {
 
@@ -88,8 +86,8 @@
 }
 
 // Run a test with the polynomial defined by the N real roots in roots_real.
-// If use_real is false, NULL is passed as the real argument to
-// FindPolynomialRoots. If use_imaginary is false, NULL is passed as the
+// If use_real is false, nullptr is passed as the real argument to
+// FindPolynomialRoots. If use_imaginary is false, nullptr is passed as the
 // imaginary argument to FindPolynomialRoots.
 template <int N>
 void RunPolynomialTestRealRoots(const double (&real_roots)[N],
@@ -102,8 +100,8 @@
   for (int i = 0; i < N; ++i) {
     poly = AddRealRoot(poly, real_roots[i]);
   }
-  Vector* const real_ptr = use_real ? &real : NULL;
-  Vector* const imaginary_ptr = use_imaginary ? &imaginary : NULL;
+  Vector* const real_ptr = use_real ? &real : nullptr;
+  Vector* const imaginary_ptr = use_imaginary ? &imaginary : nullptr;
   bool success = FindPolynomialRoots(poly, real_ptr, imaginary_ptr);
 
   EXPECT_EQ(success, true);
@@ -315,7 +313,7 @@
   Vector true_polynomial(1);
   true_polynomial << 1.0;
 
-  vector<FunctionSample> samples;
+  std::vector<FunctionSample> samples;
   FunctionSample sample;
   sample.x = 1.0;
   sample.value = 1.0;
@@ -331,7 +329,7 @@
   Vector true_polynomial(2);
   true_polynomial << 2.0, -1.0;
 
-  vector<FunctionSample> samples;
+  std::vector<FunctionSample> samples;
   FunctionSample sample;
   sample.x = 1.0;
   sample.value = 1.0;
@@ -349,7 +347,7 @@
   Vector true_polynomial(3);
   true_polynomial << 2.0, 3.0, 2.0;
 
-  vector<FunctionSample> samples;
+  std::vector<FunctionSample> samples;
   {
     FunctionSample sample;
     sample.x = 1.0;
@@ -377,7 +375,7 @@
   Vector true_polynomial(4);
   true_polynomial << 0.0, 2.0, 3.0, 2.0;
 
-  vector<FunctionSample> samples;
+  std::vector<FunctionSample> samples;
   {
     FunctionSample sample;
     sample.x = 1.0;
@@ -407,7 +405,7 @@
   Vector true_polynomial(4);
   true_polynomial << 1.0, 2.0, 3.0, 2.0;
 
-  vector<FunctionSample> samples;
+  std::vector<FunctionSample> samples;
   {
     FunctionSample sample;
     sample.x = 1.0;
@@ -450,7 +448,7 @@
   true_polynomial << 1.0, 2.0, 3.0, 2.0;
   Vector true_gradient_polynomial = DifferentiatePolynomial(true_polynomial);
 
-  vector<FunctionSample> samples;
+  std::vector<FunctionSample> samples;
   {
     FunctionSample sample;
     sample.x = 1.0;
@@ -487,7 +485,7 @@
   true_polynomial << 1.0, 2.0, 3.0, 2.0;
   Vector true_gradient_polynomial = DifferentiatePolynomial(true_polynomial);
 
-  vector<FunctionSample> samples;
+  std::vector<FunctionSample> samples;
   {
     FunctionSample sample;
     sample.x = -3.0;
@@ -512,5 +510,4 @@
   EXPECT_NEAR((true_polynomial - polynomial).norm(), 0.0, 1e-14);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/power_series_expansion_preconditioner.cc b/third_party/ceres/internal/ceres/power_series_expansion_preconditioner.cc
new file mode 100644
index 0000000..af98646
--- /dev/null
+++ b/third_party/ceres/internal/ceres/power_series_expansion_preconditioner.cc
@@ -0,0 +1,88 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: markshachkov@gmail.com (Mark Shachkov)
+
+#include "ceres/power_series_expansion_preconditioner.h"
+
+#include "ceres/eigen_vector_ops.h"
+#include "ceres/parallel_vector_ops.h"
+#include "ceres/preconditioner.h"
+
+namespace ceres::internal {
+
+PowerSeriesExpansionPreconditioner::PowerSeriesExpansionPreconditioner(
+    const ImplicitSchurComplement* isc,
+    const int max_num_spse_iterations,
+    const double spse_tolerance,
+    const Preconditioner::Options& options)
+    : isc_(isc),
+      max_num_spse_iterations_(max_num_spse_iterations),
+      spse_tolerance_(spse_tolerance),
+      options_(options) {}
+
+PowerSeriesExpansionPreconditioner::~PowerSeriesExpansionPreconditioner() =
+    default;
+
+bool PowerSeriesExpansionPreconditioner::Update(const LinearOperator& /*A*/,
+                                                const double* /*D*/) {
+  return true;
+}
+
+void PowerSeriesExpansionPreconditioner::RightMultiplyAndAccumulate(
+    const double* x, double* y) const {
+  VectorRef yref(y, num_rows());
+  Vector series_term(num_rows());
+  Vector previous_series_term(num_rows());
+  ParallelSetZero(options_.context, options_.num_threads, yref);
+  isc_->block_diagonal_FtF_inverse()->RightMultiplyAndAccumulate(
+      x, y, options_.context, options_.num_threads);
+  ParallelAssign(
+      options_.context, options_.num_threads, previous_series_term, yref);
+
+  const double norm_threshold =
+      spse_tolerance_ * Norm(yref, options_.context, options_.num_threads);
+
+  for (int i = 1;; i++) {
+    ParallelSetZero(options_.context, options_.num_threads, series_term);
+    isc_->InversePowerSeriesOperatorRightMultiplyAccumulate(
+        previous_series_term.data(), series_term.data());
+    ParallelAssign(
+        options_.context, options_.num_threads, yref, yref + series_term);
+    if (i >= max_num_spse_iterations_ || series_term.norm() < norm_threshold) {
+      break;
+    }
+    std::swap(previous_series_term, series_term);
+  }
+}
+
+int PowerSeriesExpansionPreconditioner::num_rows() const {
+  return isc_->num_rows();
+}
+
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/power_series_expansion_preconditioner.h b/third_party/ceres/internal/ceres/power_series_expansion_preconditioner.h
new file mode 100644
index 0000000..9a993cf
--- /dev/null
+++ b/third_party/ceres/internal/ceres/power_series_expansion_preconditioner.h
@@ -0,0 +1,71 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: markshachkov@gmail.com (Mark Shachkov)
+
+#ifndef CERES_INTERNAL_POWER_SERIES_EXPANSION_PRECONDITIONER_H_
+#define CERES_INTERNAL_POWER_SERIES_EXPANSION_PRECONDITIONER_H_
+
+#include "ceres/implicit_schur_complement.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/internal/export.h"
+#include "ceres/preconditioner.h"
+
+namespace ceres::internal {
+
+// This is a preconditioner via power series expansion of Schur
+// complement inverse based on "Weber et al, Power Bundle Adjustment for
+// Large-Scale 3D Reconstruction".
+class CERES_NO_EXPORT PowerSeriesExpansionPreconditioner
+    : public Preconditioner {
+ public:
+  // TODO: Consider moving max_num_spse_iterations and spse_tolerance to
+  // Preconditioner::Options
+  PowerSeriesExpansionPreconditioner(const ImplicitSchurComplement* isc,
+                                     const int max_num_spse_iterations,
+                                     const double spse_tolerance,
+                                     const Preconditioner::Options& options);
+  PowerSeriesExpansionPreconditioner(
+      const PowerSeriesExpansionPreconditioner&) = delete;
+  void operator=(const PowerSeriesExpansionPreconditioner&) = delete;
+  ~PowerSeriesExpansionPreconditioner() override;
+
+  void RightMultiplyAndAccumulate(const double* x, double* y) const final;
+  bool Update(const LinearOperator& A, const double* D) final;
+  int num_rows() const final;
+
+ private:
+  const ImplicitSchurComplement* isc_;
+  const int max_num_spse_iterations_;
+  const double spse_tolerance_;
+  const Preconditioner::Options options_;
+};
+
+}  // namespace ceres::internal
+
+#endif  // CERES_INTERNAL_POWER_SERIES_EXPANSION_PRECONDITIONER_H_
diff --git a/third_party/ceres/internal/ceres/power_series_expansion_preconditioner_test.cc b/third_party/ceres/internal/ceres/power_series_expansion_preconditioner_test.cc
new file mode 100644
index 0000000..1c04162
--- /dev/null
+++ b/third_party/ceres/internal/ceres/power_series_expansion_preconditioner_test.cc
@@ -0,0 +1,175 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Author: markshachkov@gmail.com (Mark Shachkov)
+
+#include "ceres/power_series_expansion_preconditioner.h"
+
+#include <memory>
+
+#include "Eigen/Dense"
+#include "ceres/linear_least_squares_problems.h"
+#include "gtest/gtest.h"
+
+namespace ceres::internal {
+
+const double kEpsilon = 1e-14;
+
+class PowerSeriesExpansionPreconditionerTest : public ::testing::Test {
+ protected:
+  void SetUp() final {
+    problem_ = CreateLinearLeastSquaresProblemFromId(5);
+    const auto A = down_cast<BlockSparseMatrix*>(problem_->A.get());
+    const auto D = problem_->D.get();
+
+    options_.elimination_groups.push_back(problem_->num_eliminate_blocks);
+    options_.preconditioner_type = SCHUR_POWER_SERIES_EXPANSION;
+    preconditioner_options_ = Preconditioner::Options(options_);
+    isc_ = std::make_unique<ImplicitSchurComplement>(options_);
+    isc_->Init(*A, D, problem_->b.get());
+    num_f_cols_ = isc_->rhs().rows();
+    const int num_rows = A->num_rows(), num_cols = A->num_cols(),
+              num_e_cols = num_cols - num_f_cols_;
+
+    // Using predefined linear operator with schur structure and block-diagonal
+    // F'F to explicitly construct schur complement and to calculate its inverse
+    // to be used as a reference.
+    Matrix A_dense, E, F, DE, DF;
+    problem_->A->ToDenseMatrix(&A_dense);
+    E = A_dense.leftCols(num_e_cols);
+    F = A_dense.rightCols(num_f_cols_);
+    DE = VectorRef(D, num_e_cols).asDiagonal();
+    DF = VectorRef(D + num_e_cols, num_f_cols_).asDiagonal();
+
+    sc_inverse_expected_ =
+        (F.transpose() *
+             (Matrix::Identity(num_rows, num_rows) -
+              E * (E.transpose() * E + DE).inverse() * E.transpose()) *
+             F +
+         DF)
+            .inverse();
+  }
+  std::unique_ptr<LinearLeastSquaresProblem> problem_;
+  std::unique_ptr<ImplicitSchurComplement> isc_;
+  int num_f_cols_;
+  Matrix sc_inverse_expected_;
+  LinearSolver::Options options_;
+  Preconditioner::Options preconditioner_options_;
+};
+
+TEST_F(PowerSeriesExpansionPreconditionerTest,
+       InverseValidPreconditionerToleranceReached) {
+  const double spse_tolerance = kEpsilon;
+  const int max_num_iterations = 50;
+  PowerSeriesExpansionPreconditioner preconditioner(
+      isc_.get(), max_num_iterations, spse_tolerance, preconditioner_options_);
+
+  Vector x(num_f_cols_), y(num_f_cols_);
+  for (int i = 0; i < num_f_cols_; i++) {
+    x.setZero();
+    x(i) = 1.0;
+
+    y.setZero();
+    preconditioner.RightMultiplyAndAccumulate(x.data(), y.data());
+    EXPECT_LT((y - sc_inverse_expected_.col(i)).norm(), kEpsilon)
+        << "Reference Schur complement inverse and its estimate via "
+           "PowerSeriesExpansionPreconditioner differs in "
+        << i
+        << " column.\nreference : " << sc_inverse_expected_.col(i).transpose()
+        << "\nestimated: " << y.transpose();
+  }
+}
+
+TEST_F(PowerSeriesExpansionPreconditionerTest,
+       InverseValidPreconditionerMaxIterations) {
+  const double spse_tolerance = 0;
+  const int max_num_iterations = 50;
+  PowerSeriesExpansionPreconditioner preconditioner_fixed_n_iterations(
+      isc_.get(), max_num_iterations, spse_tolerance, preconditioner_options_);
+
+  Vector x(num_f_cols_), y(num_f_cols_);
+  for (int i = 0; i < num_f_cols_; i++) {
+    x.setZero();
+    x(i) = 1.0;
+
+    y.setZero();
+    preconditioner_fixed_n_iterations.RightMultiplyAndAccumulate(x.data(),
+                                                                 y.data());
+    EXPECT_LT((y - sc_inverse_expected_.col(i)).norm(), kEpsilon)
+        << "Reference Schur complement inverse and its estimate via "
+           "PowerSeriesExpansionPreconditioner differs in "
+        << i
+        << " column.\nreference : " << sc_inverse_expected_.col(i).transpose()
+        << "\nestimated: " << y.transpose();
+  }
+}
+
+TEST_F(PowerSeriesExpansionPreconditionerTest,
+       InverseInvalidBadPreconditionerTolerance) {
+  const double spse_tolerance = 1 / kEpsilon;
+  const int max_num_iterations = 50;
+  PowerSeriesExpansionPreconditioner preconditioner_bad_tolerance(
+      isc_.get(), max_num_iterations, spse_tolerance, preconditioner_options_);
+
+  Vector x(num_f_cols_), y(num_f_cols_);
+  for (int i = 0; i < num_f_cols_; i++) {
+    x.setZero();
+    x(i) = 1.0;
+
+    y.setZero();
+    preconditioner_bad_tolerance.RightMultiplyAndAccumulate(x.data(), y.data());
+    EXPECT_GT((y - sc_inverse_expected_.col(i)).norm(), kEpsilon)
+        << "Reference Schur complement inverse and its estimate via "
+           "PowerSeriesExpansionPreconditioner are too similar, tolerance "
+           "stopping criteria failed.";
+  }
+}
+
+TEST_F(PowerSeriesExpansionPreconditionerTest,
+       InverseInvalidBadPreconditionerMaxIterations) {
+  const double spse_tolerance = kEpsilon;
+  const int max_num_iterations = 1;
+  PowerSeriesExpansionPreconditioner preconditioner_bad_iterations_limit(
+      isc_.get(), max_num_iterations, spse_tolerance, preconditioner_options_);
+
+  Vector x(num_f_cols_), y(num_f_cols_);
+  for (int i = 0; i < num_f_cols_; i++) {
+    x.setZero();
+    x(i) = 1.0;
+
+    y.setZero();
+    preconditioner_bad_iterations_limit.RightMultiplyAndAccumulate(x.data(),
+                                                                   y.data());
+    EXPECT_GT((y - sc_inverse_expected_.col(i)).norm(), kEpsilon)
+        << "Reference Schur complement inverse and its estimate via "
+           "PowerSeriesExpansionPreconditioner are too similar, maximum "
+           "iterations stopping criteria failed.";
+  }
+}
+
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/preconditioner.cc b/third_party/ceres/internal/ceres/preconditioner.cc
index 69ba04d..0b9ce96 100644
--- a/third_party/ceres/internal/ceres/preconditioner.cc
+++ b/third_party/ceres/internal/ceres/preconditioner.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -32,10 +32,9 @@
 
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
-Preconditioner::~Preconditioner() {}
+Preconditioner::~Preconditioner() = default;
 
 PreconditionerType Preconditioner::PreconditionerForZeroEBlocks(
     PreconditionerType preconditioner_type) {
@@ -48,26 +47,27 @@
 }
 
 SparseMatrixPreconditionerWrapper::SparseMatrixPreconditionerWrapper(
-    const SparseMatrix* matrix)
-    : matrix_(matrix) {
+    const SparseMatrix* matrix, const Preconditioner::Options& options)
+    : matrix_(matrix), options_(options) {
   CHECK(matrix != nullptr);
 }
 
-SparseMatrixPreconditionerWrapper::~SparseMatrixPreconditionerWrapper() {}
+SparseMatrixPreconditionerWrapper::~SparseMatrixPreconditionerWrapper() =
+    default;
 
-bool SparseMatrixPreconditionerWrapper::UpdateImpl(const SparseMatrix& A,
-                                                   const double* D) {
+bool SparseMatrixPreconditionerWrapper::UpdateImpl(const SparseMatrix& /*A*/,
+                                                   const double* /*D*/) {
   return true;
 }
 
-void SparseMatrixPreconditionerWrapper::RightMultiply(const double* x,
-                                                      double* y) const {
-  matrix_->RightMultiply(x, y);
+void SparseMatrixPreconditionerWrapper::RightMultiplyAndAccumulate(
+    const double* x, double* y) const {
+  matrix_->RightMultiplyAndAccumulate(
+      x, y, options_.context, options_.num_threads);
 }
 
 int SparseMatrixPreconditionerWrapper::num_rows() const {
   return matrix_->num_rows();
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/preconditioner.h b/third_party/ceres/internal/ceres/preconditioner.h
index dd843b0..42dc6cc 100644
--- a/third_party/ceres/internal/ceres/preconditioner.h
+++ b/third_party/ceres/internal/ceres/preconditioner.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -36,24 +36,40 @@
 #include "ceres/casts.h"
 #include "ceres/compressed_row_sparse_matrix.h"
 #include "ceres/context_impl.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 #include "ceres/linear_operator.h"
+#include "ceres/linear_solver.h"
 #include "ceres/sparse_matrix.h"
 #include "ceres/types.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 class BlockSparseMatrix;
 class SparseMatrix;
 
-class CERES_EXPORT_INTERNAL Preconditioner : public LinearOperator {
+class CERES_NO_EXPORT Preconditioner : public LinearOperator {
  public:
   struct Options {
+    Options() = default;
+    Options(const LinearSolver::Options& linear_solver_options)
+        : type(linear_solver_options.preconditioner_type),
+          visibility_clustering_type(
+              linear_solver_options.visibility_clustering_type),
+          sparse_linear_algebra_library_type(
+              linear_solver_options.sparse_linear_algebra_library_type),
+          num_threads(linear_solver_options.num_threads),
+          elimination_groups(linear_solver_options.elimination_groups),
+          row_block_size(linear_solver_options.row_block_size),
+          e_block_size(linear_solver_options.e_block_size),
+          f_block_size(linear_solver_options.f_block_size),
+          context(linear_solver_options.context) {}
+
     PreconditionerType type = JACOBI;
     VisibilityClusteringType visibility_clustering_type = CANONICAL_VIEWS;
     SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type =
         SUITE_SPARSE;
+    OrderingType ordering_type = OrderingType::NATURAL;
 
     // When using the subset preconditioner, all row blocks starting
     // from this row block are used to construct the preconditioner.
@@ -67,9 +83,6 @@
     // and the preconditioner is the inverse of the matrix Q'Q.
     int subset_preconditioner_start_row_block = -1;
 
-    // See solver.h for information about these flags.
-    bool use_postordering = false;
-
     // If possible, how many threads the preconditioner can use.
     int num_threads = 1;
 
@@ -115,7 +128,7 @@
   static PreconditionerType PreconditionerForZeroEBlocks(
       PreconditionerType preconditioner_type);
 
-  virtual ~Preconditioner();
+  ~Preconditioner() override;
 
   // Update the numerical value of the preconditioner for the linear
   // system:
@@ -126,30 +139,48 @@
   // for some vector b. It is important that the matrix A have the
   // same block structure as the one used to construct this object.
   //
-  // D can be NULL, in which case its interpreted as a diagonal matrix
+  // D can be nullptr, in which case its interpreted as a diagonal matrix
   // of size zero.
   virtual bool Update(const LinearOperator& A, const double* D) = 0;
 
   // LinearOperator interface. Since the operator is symmetric,
-  // LeftMultiply and num_cols are just calls to RightMultiply and
-  // num_rows respectively. Update() must be called before
-  // RightMultiply can be called.
-  void RightMultiply(const double* x, double* y) const override = 0;
-  void LeftMultiply(const double* x, double* y) const override {
-    return RightMultiply(x, y);
+  // LeftMultiplyAndAccumulate and num_cols are just calls to
+  // RightMultiplyAndAccumulate and num_rows respectively. Update() must be
+  // called before RightMultiplyAndAccumulate can be called.
+  void RightMultiplyAndAccumulate(const double* x,
+                                  double* y) const override = 0;
+  void LeftMultiplyAndAccumulate(const double* x, double* y) const override {
+    return RightMultiplyAndAccumulate(x, y);
   }
 
   int num_rows() const override = 0;
   int num_cols() const override { return num_rows(); }
 };
 
+class CERES_NO_EXPORT IdentityPreconditioner : public Preconditioner {
+ public:
+  IdentityPreconditioner(int num_rows) : num_rows_(num_rows) {}
+
+  bool Update(const LinearOperator& /*A*/, const double* /*D*/) final {
+    return true;
+  }
+
+  void RightMultiplyAndAccumulate(const double* x, double* y) const final {
+    VectorRef(y, num_rows_) += ConstVectorRef(x, num_rows_);
+  }
+
+  int num_rows() const final { return num_rows_; }
+
+ private:
+  int num_rows_ = -1;
+};
+
 // This templated subclass of Preconditioner serves as a base class for
 // other preconditioners that depend on the particular matrix layout of
 // the underlying linear operator.
 template <typename MatrixType>
-class TypedPreconditioner : public Preconditioner {
+class CERES_NO_EXPORT TypedPreconditioner : public Preconditioner {
  public:
-  virtual ~TypedPreconditioner() {}
   bool Update(const LinearOperator& A, const double* D) final {
     return UpdateImpl(*down_cast<const MatrixType*>(&A), D);
   }
@@ -161,28 +192,32 @@
 // Preconditioners that depend on access to the low level structure
 // of a SparseMatrix.
 // clang-format off
-typedef TypedPreconditioner<SparseMatrix>              SparseMatrixPreconditioner;
-typedef TypedPreconditioner<BlockSparseMatrix>         BlockSparseMatrixPreconditioner;
-typedef TypedPreconditioner<CompressedRowSparseMatrix> CompressedRowSparseMatrixPreconditioner;
+using SparseMatrixPreconditioner = TypedPreconditioner<SparseMatrix>;
+using BlockSparseMatrixPreconditioner = TypedPreconditioner<BlockSparseMatrix>;
+using CompressedRowSparseMatrixPreconditioner = TypedPreconditioner<CompressedRowSparseMatrix>;
 // clang-format on
 
 // Wrap a SparseMatrix object as a preconditioner.
-class SparseMatrixPreconditionerWrapper : public SparseMatrixPreconditioner {
+class CERES_NO_EXPORT SparseMatrixPreconditionerWrapper final
+    : public SparseMatrixPreconditioner {
  public:
   // Wrapper does NOT take ownership of the matrix pointer.
-  explicit SparseMatrixPreconditionerWrapper(const SparseMatrix* matrix);
-  virtual ~SparseMatrixPreconditionerWrapper();
+  explicit SparseMatrixPreconditionerWrapper(
+      const SparseMatrix* matrix, const Preconditioner::Options& options);
+  ~SparseMatrixPreconditionerWrapper() override;
 
   // Preconditioner interface
-  virtual void RightMultiply(const double* x, double* y) const;
-  virtual int num_rows() const;
+  void RightMultiplyAndAccumulate(const double* x, double* y) const override;
+  int num_rows() const override;
 
  private:
-  virtual bool UpdateImpl(const SparseMatrix& A, const double* D);
+  bool UpdateImpl(const SparseMatrix& A, const double* D) override;
   const SparseMatrix* matrix_;
+  const Preconditioner::Options options_;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_PRECONDITIONER_H_
diff --git a/third_party/ceres/internal/ceres/preprocessor.cc b/third_party/ceres/internal/ceres/preprocessor.cc
index 6a67d38..83c05d4 100644
--- a/third_party/ceres/internal/ceres/preprocessor.cc
+++ b/third_party/ceres/internal/ceres/preprocessor.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -30,34 +30,39 @@
 
 #include "ceres/preprocessor.h"
 
+#include <memory>
+
 #include "ceres/callbacks.h"
 #include "ceres/gradient_checking_cost_function.h"
 #include "ceres/line_search_preprocessor.h"
-#include "ceres/parallel_for.h"
 #include "ceres/problem_impl.h"
 #include "ceres/solver.h"
+#include "ceres/thread_pool.h"
 #include "ceres/trust_region_preprocessor.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
-Preprocessor* Preprocessor::Create(MinimizerType minimizer_type) {
+std::unique_ptr<Preprocessor> Preprocessor::Create(
+    MinimizerType minimizer_type) {
   if (minimizer_type == TRUST_REGION) {
-    return new TrustRegionPreprocessor;
+    return std::make_unique<TrustRegionPreprocessor>();
   }
 
   if (minimizer_type == LINE_SEARCH) {
-    return new LineSearchPreprocessor;
+    return std::make_unique<LineSearchPreprocessor>();
   }
 
   LOG(FATAL) << "Unknown minimizer_type: " << minimizer_type;
-  return NULL;
+  return nullptr;
 }
 
-Preprocessor::~Preprocessor() {}
+Preprocessor::~Preprocessor() = default;
 
 void ChangeNumThreadsIfNeeded(Solver::Options* options) {
-  const int num_threads_available = MaxNumThreadsAvailable();
+  if (options->num_threads == 1) {
+    return;
+  }
+  const int num_threads_available = ThreadPool::MaxNumThreadsAvailable();
   if (options->num_threads > num_threads_available) {
     LOG(WARNING) << "Specified options.num_threads: " << options->num_threads
                  << " exceeds maximum available from the threading model Ceres "
@@ -77,20 +82,22 @@
   double* reduced_parameters = pp->reduced_parameters.data();
   program->ParameterBlocksToStateVector(reduced_parameters);
 
+  auto context = pp->problem->context();
   Minimizer::Options& minimizer_options = pp->minimizer_options;
   minimizer_options = Minimizer::Options(options);
   minimizer_options.evaluator = pp->evaluator;
+  minimizer_options.context = context;
 
   if (options.logging_type != SILENT) {
-    pp->logging_callback.reset(new LoggingCallback(
-        options.minimizer_type, options.minimizer_progress_to_stdout));
+    pp->logging_callback = std::make_unique<LoggingCallback>(
+        options.minimizer_type, options.minimizer_progress_to_stdout);
     minimizer_options.callbacks.insert(minimizer_options.callbacks.begin(),
                                        pp->logging_callback.get());
   }
 
   if (options.update_state_every_iteration) {
-    pp->state_updating_callback.reset(
-        new StateUpdatingCallback(program, reduced_parameters));
+    pp->state_updating_callback =
+        std::make_unique<StateUpdatingCallback>(program, reduced_parameters);
     // This must get pushed to the front of the callbacks so that it
     // is run before any of the user callbacks.
     minimizer_options.callbacks.insert(minimizer_options.callbacks.begin(),
@@ -98,5 +105,4 @@
   }
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/preprocessor.h b/third_party/ceres/internal/ceres/preprocessor.h
index ec56c6e..ed031f6 100644
--- a/third_party/ceres/internal/ceres/preprocessor.h
+++ b/third_party/ceres/internal/ceres/preprocessor.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -37,8 +37,9 @@
 
 #include "ceres/coordinate_descent_minimizer.h"
 #include "ceres/evaluator.h"
+#include "ceres/internal/disable_warnings.h"
 #include "ceres/internal/eigen.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 #include "ceres/iteration_callback.h"
 #include "ceres/linear_solver.h"
 #include "ceres/minimizer.h"
@@ -46,8 +47,7 @@
 #include "ceres/program.h"
 #include "ceres/solver.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 struct PreprocessedProblem;
 
@@ -67,10 +67,10 @@
 //
 // The output of the Preprocessor is stored in a PreprocessedProblem
 // object.
-class CERES_EXPORT_INTERNAL Preprocessor {
+class CERES_NO_EXPORT Preprocessor {
  public:
   // Factory.
-  static Preprocessor* Create(MinimizerType minimizer_type);
+  static std::unique_ptr<Preprocessor> Create(MinimizerType minimizer_type);
   virtual ~Preprocessor();
   virtual bool Preprocess(const Solver::Options& options,
                           ProblemImpl* problem,
@@ -79,8 +79,8 @@
 
 // A PreprocessedProblem is the result of running the Preprocessor on
 // a Problem and Solver::Options object.
-struct PreprocessedProblem {
-  PreprocessedProblem() : fixed_cost(0.0) {}
+struct CERES_NO_EXPORT PreprocessedProblem {
+  PreprocessedProblem() = default;
 
   std::string error;
   Solver::Options options;
@@ -100,7 +100,7 @@
 
   std::vector<double*> removed_parameter_blocks;
   Vector reduced_parameters;
-  double fixed_cost;
+  double fixed_cost{0.0};
 };
 
 // Common functions used by various preprocessors.
@@ -108,14 +108,17 @@
 // If the user has specified a num_threads > the maximum number of threads
 // available from the compiled threading model, bound the number of threads
 // to the maximum.
+CERES_NO_EXPORT
 void ChangeNumThreadsIfNeeded(Solver::Options* options);
 
 // Extract the effective parameter vector from the preprocessed
 // problem and setup bits of the Minimizer::Options object that are
 // common to all Preprocessors.
+CERES_NO_EXPORT
 void SetupCommonMinimizerOptions(PreprocessedProblem* pp);
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_PREPROCESSOR_H_
diff --git a/third_party/ceres/internal/ceres/problem.cc b/third_party/ceres/internal/ceres/problem.cc
index f3ffd54..00c1786 100644
--- a/third_party/ceres/internal/ceres/problem.cc
+++ b/third_party/ceres/internal/ceres/problem.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -31,6 +31,7 @@
 
 #include "ceres/problem.h"
 
+#include <memory>
 #include <vector>
 
 #include "ceres/crs_matrix.h"
@@ -38,20 +39,18 @@
 
 namespace ceres {
 
-using std::vector;
-
 Problem::Problem() : impl_(new internal::ProblemImpl) {}
 Problem::Problem(const Problem::Options& options)
     : impl_(new internal::ProblemImpl(options)) {}
 // Not inline defaulted in declaration due to use of std::unique_ptr.
 Problem::Problem(Problem&&) = default;
 Problem& Problem::operator=(Problem&&) = default;
-Problem::~Problem() {}
+Problem::~Problem() = default;
 
 ResidualBlockId Problem::AddResidualBlock(
     CostFunction* cost_function,
     LossFunction* loss_function,
-    const vector<double*>& parameter_blocks) {
+    const std::vector<double*>& parameter_blocks) {
   return impl_->AddResidualBlock(cost_function,
                                  loss_function,
                                  parameter_blocks.data(),
@@ -70,10 +69,8 @@
   impl_->AddParameterBlock(values, size);
 }
 
-void Problem::AddParameterBlock(double* values,
-                                int size,
-                                LocalParameterization* local_parameterization) {
-  impl_->AddParameterBlock(values, size, local_parameterization);
+void Problem::AddParameterBlock(double* values, int size, Manifold* manifold) {
+  impl_->AddParameterBlock(values, size, manifold);
 }
 
 void Problem::RemoveResidualBlock(ResidualBlockId residual_block) {
@@ -96,14 +93,16 @@
   return impl_->IsParameterBlockConstant(values);
 }
 
-void Problem::SetParameterization(
-    double* values, LocalParameterization* local_parameterization) {
-  impl_->SetParameterization(values, local_parameterization);
+void Problem::SetManifold(double* values, Manifold* manifold) {
+  impl_->SetManifold(values, manifold);
 }
 
-const LocalParameterization* Problem::GetParameterization(
-    const double* values) const {
-  return impl_->GetParameterization(values);
+const Manifold* Problem::GetManifold(const double* values) const {
+  return impl_->GetManifold(values);
+}
+
+bool Problem::HasManifold(const double* values) const {
+  return impl_->HasManifold(values);
 }
 
 void Problem::SetParameterLowerBound(double* values,
@@ -128,8 +127,8 @@
 
 bool Problem::Evaluate(const EvaluateOptions& evaluate_options,
                        double* cost,
-                       vector<double>* residuals,
-                       vector<double>* gradient,
+                       std::vector<double>* residuals,
+                       std::vector<double>* gradient,
                        CRSMatrix* jacobian) {
   return impl_->Evaluate(evaluate_options, cost, residuals, gradient, jacobian);
 }
@@ -169,30 +168,30 @@
 
 int Problem::NumResiduals() const { return impl_->NumResiduals(); }
 
-int Problem::ParameterBlockSize(const double* parameter_block) const {
-  return impl_->ParameterBlockSize(parameter_block);
+int Problem::ParameterBlockSize(const double* values) const {
+  return impl_->ParameterBlockSize(values);
 }
 
-int Problem::ParameterBlockLocalSize(const double* parameter_block) const {
-  return impl_->ParameterBlockLocalSize(parameter_block);
+int Problem::ParameterBlockTangentSize(const double* values) const {
+  return impl_->ParameterBlockTangentSize(values);
 }
 
 bool Problem::HasParameterBlock(const double* values) const {
   return impl_->HasParameterBlock(values);
 }
 
-void Problem::GetParameterBlocks(vector<double*>* parameter_blocks) const {
+void Problem::GetParameterBlocks(std::vector<double*>* parameter_blocks) const {
   impl_->GetParameterBlocks(parameter_blocks);
 }
 
 void Problem::GetResidualBlocks(
-    vector<ResidualBlockId>* residual_blocks) const {
+    std::vector<ResidualBlockId>* residual_blocks) const {
   impl_->GetResidualBlocks(residual_blocks);
 }
 
 void Problem::GetParameterBlocksForResidualBlock(
     const ResidualBlockId residual_block,
-    vector<double*>* parameter_blocks) const {
+    std::vector<double*>* parameter_blocks) const {
   impl_->GetParameterBlocksForResidualBlock(residual_block, parameter_blocks);
 }
 
@@ -207,8 +206,12 @@
 }
 
 void Problem::GetResidualBlocksForParameterBlock(
-    const double* values, vector<ResidualBlockId>* residual_blocks) const {
+    const double* values, std::vector<ResidualBlockId>* residual_blocks) const {
   impl_->GetResidualBlocksForParameterBlock(values, residual_blocks);
 }
 
+const Problem::Options& Problem::options() const { return impl_->options(); }
+
+internal::ProblemImpl* Problem::mutable_impl() { return impl_.get(); }
+
 }  // namespace ceres
diff --git a/third_party/ceres/internal/ceres/problem_impl.cc b/third_party/ceres/internal/ceres/problem_impl.cc
index 3155bc3..52575ee 100644
--- a/third_party/ceres/internal/ceres/problem_impl.cc
+++ b/third_party/ceres/internal/ceres/problem_impl.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -49,9 +49,10 @@
 #include "ceres/crs_matrix.h"
 #include "ceres/evaluation_callback.h"
 #include "ceres/evaluator.h"
+#include "ceres/internal/export.h"
 #include "ceres/internal/fixed_array.h"
-#include "ceres/internal/port.h"
 #include "ceres/loss_function.h"
+#include "ceres/manifold.h"
 #include "ceres/map_util.h"
 #include "ceres/parameter_block.h"
 #include "ceres/program.h"
@@ -62,13 +63,7 @@
 #include "ceres/stringprintf.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
-
-using std::map;
-using std::string;
-using std::vector;
-
+namespace ceres::internal {
 namespace {
 // Returns true if two regions of memory, a and b, with sizes size_a and size_b
 // respectively, overlap.
@@ -130,7 +125,7 @@
                            << "for a parameter with size " << size;
 
   // Ignore the request if there is a block for the given pointer already.
-  ParameterMap::iterator it = parameter_block_map_.find(values);
+  auto it = parameter_block_map_.find(values);
   if (it != parameter_block_map_.end()) {
     if (!options_.disable_all_safety_checks) {
       int existing_size = it->second->Size();
@@ -146,11 +141,11 @@
     // Before adding the parameter block, also check that it doesn't alias any
     // other parameter blocks.
     if (!parameter_block_map_.empty()) {
-      ParameterMap::iterator lb = parameter_block_map_.lower_bound(values);
+      auto lb = parameter_block_map_.lower_bound(values);
 
       // If lb is not the first block, check the previous block for aliasing.
       if (lb != parameter_block_map_.begin()) {
-        ParameterMap::iterator previous = lb;
+        auto previous = lb;
         --previous;
         CheckForNoAliasing(
             previous->first, previous->second->Size(), values, size);
@@ -165,7 +160,7 @@
 
   // Pass the index of the new parameter block as well to keep the index in
   // sync with the position of the parameter in the program's parameter vector.
-  ParameterBlock* new_parameter_block =
+  auto* new_parameter_block =
       new ParameterBlock(values, size, program_->parameter_blocks_.size());
 
   // For dynamic problems, add the list of dependent residual blocks, which is
@@ -192,7 +187,7 @@
           residual_block);
     }
 
-    ResidualBlockSet::iterator it = residual_block_set_.find(residual_block);
+    auto it = residual_block_set_.find(residual_block);
     residual_block_set_.erase(it);
   }
   DeleteBlockInVector(program_->mutable_residual_blocks(), residual_block);
@@ -207,13 +202,13 @@
   // The const casts here are legit, since ResidualBlock holds these
   // pointers as const pointers but we have ownership of them and
   // have the right to destroy them when the destructor is called.
-  CostFunction* cost_function =
+  auto* cost_function =
       const_cast<CostFunction*>(residual_block->cost_function());
   if (options_.cost_function_ownership == TAKE_OWNERSHIP) {
     DecrementValueOrDeleteKey(cost_function, &cost_function_ref_count_);
   }
 
-  LossFunction* loss_function =
+  auto* loss_function =
       const_cast<LossFunction*>(residual_block->loss_function());
   if (options_.loss_function_ownership == TAKE_OWNERSHIP &&
       loss_function != nullptr) {
@@ -225,15 +220,7 @@
 
 // Deletes the parameter block in question, assuming there are no other
 // references to it inside the problem (e.g. by any residual blocks).
-// Referenced parameterizations are tucked away for future deletion, since it
-// is not possible to know whether other parts of the problem depend on them
-// without doing a full scan.
 void ProblemImpl::DeleteBlock(ParameterBlock* parameter_block) {
-  if (options_.local_parameterization_ownership == TAKE_OWNERSHIP &&
-      parameter_block->local_parameterization() != nullptr) {
-    local_parameterizations_to_delete_.push_back(
-        parameter_block->mutable_local_parameterization());
-  }
   parameter_block_map_.erase(parameter_block->mutable_user_state());
   delete parameter_block;
 }
@@ -264,13 +251,13 @@
   }
 
   // Collect the unique parameterizations and delete the parameters.
-  for (int i = 0; i < program_->parameter_blocks_.size(); ++i) {
-    DeleteBlock(program_->parameter_blocks_[i]);
+  for (auto* parameter_block : program_->parameter_blocks_) {
+    DeleteBlock(parameter_block);
   }
 
-  // Delete the owned parameterizations.
-  STLDeleteUniqueContainerPointers(local_parameterizations_to_delete_.begin(),
-                                   local_parameterizations_to_delete_.end());
+  // Delete the owned manifolds.
+  STLDeleteUniqueContainerPointers(manifolds_to_delete_.begin(),
+                                   manifolds_to_delete_.end());
 
   if (context_impl_owned_) {
     delete context_impl_;
@@ -286,7 +273,7 @@
   CHECK_EQ(num_parameter_blocks, cost_function->parameter_block_sizes().size());
 
   // Check the sizes match.
-  const vector<int32_t>& parameter_block_sizes =
+  const std::vector<int32_t>& parameter_block_sizes =
       cost_function->parameter_block_sizes();
 
   if (!options_.disable_all_safety_checks) {
@@ -295,15 +282,15 @@
         << "that the cost function expects.";
 
     // Check for duplicate parameter blocks.
-    vector<double*> sorted_parameter_blocks(
+    std::vector<double*> sorted_parameter_blocks(
         parameter_blocks, parameter_blocks + num_parameter_blocks);
-    sort(sorted_parameter_blocks.begin(), sorted_parameter_blocks.end());
+    std::sort(sorted_parameter_blocks.begin(), sorted_parameter_blocks.end());
     const bool has_duplicate_items =
         (std::adjacent_find(sorted_parameter_blocks.begin(),
                             sorted_parameter_blocks.end()) !=
          sorted_parameter_blocks.end());
     if (has_duplicate_items) {
-      string blocks;
+      std::string blocks;
       for (int i = 0; i < num_parameter_blocks; ++i) {
         blocks += StringPrintf(" %p ", parameter_blocks[i]);
       }
@@ -315,7 +302,7 @@
   }
 
   // Add parameter blocks and convert the double*'s to parameter blocks.
-  vector<ParameterBlock*> parameter_block_ptrs(num_parameter_blocks);
+  std::vector<ParameterBlock*> parameter_block_ptrs(num_parameter_blocks);
   for (int i = 0; i < num_parameter_blocks; ++i) {
     parameter_block_ptrs[i] = InternalAddParameterBlock(
         parameter_blocks[i], parameter_block_sizes[i]);
@@ -334,7 +321,7 @@
     }
   }
 
-  ResidualBlock* new_residual_block =
+  auto* new_residual_block =
       new ResidualBlock(cost_function,
                         loss_function,
                         parameter_block_ptrs,
@@ -372,12 +359,20 @@
   InternalAddParameterBlock(values, size);
 }
 
-void ProblemImpl::AddParameterBlock(
-    double* values, int size, LocalParameterization* local_parameterization) {
-  ParameterBlock* parameter_block = InternalAddParameterBlock(values, size);
-  if (local_parameterization != nullptr) {
-    parameter_block->SetParameterization(local_parameterization);
+void ProblemImpl::InternalSetManifold(double* /*values*/,
+                                      ParameterBlock* parameter_block,
+                                      Manifold* manifold) {
+  if (manifold != nullptr && options_.manifold_ownership == TAKE_OWNERSHIP) {
+    manifolds_to_delete_.push_back(manifold);
   }
+  parameter_block->SetManifold(manifold);
+}
+
+void ProblemImpl::AddParameterBlock(double* values,
+                                    int size,
+                                    Manifold* manifold) {
+  ParameterBlock* parameter_block = InternalAddParameterBlock(values, size);
+  InternalSetManifold(values, parameter_block, manifold);
 }
 
 // Delete a block from a vector of blocks, maintaining the indexing invariant.
@@ -385,7 +380,7 @@
 // vector over the element to remove, then popping the last element. It
 // destroys the ordering in the interest of speed.
 template <typename Block>
-void ProblemImpl::DeleteBlockInVector(vector<Block*>* mutable_blocks,
+void ProblemImpl::DeleteBlockInVector(std::vector<Block*>* mutable_blocks,
                                       Block* block_to_remove) {
   CHECK_EQ((*mutable_blocks)[block_to_remove->index()], block_to_remove)
       << "You found a Ceres bug! \n"
@@ -411,7 +406,7 @@
   CHECK(residual_block != nullptr);
 
   // Verify that residual_block identifies a residual in the current problem.
-  const string residual_not_found_message = StringPrintf(
+  const std::string residual_not_found_message = StringPrintf(
       "Residual block to remove: %p not found. This usually means "
       "one of three things have happened:\n"
       " 1) residual_block is uninitialised and points to a random "
@@ -449,11 +444,11 @@
   if (options_.enable_fast_removal) {
     // Copy the dependent residuals from the parameter block because the set of
     // dependents will change after each call to RemoveResidualBlock().
-    vector<ResidualBlock*> residual_blocks_to_remove(
+    std::vector<ResidualBlock*> residual_blocks_to_remove(
         parameter_block->mutable_residual_blocks()->begin(),
         parameter_block->mutable_residual_blocks()->end());
-    for (int i = 0; i < residual_blocks_to_remove.size(); ++i) {
-      InternalRemoveResidualBlock(residual_blocks_to_remove[i]);
+    for (auto* residual_block : residual_blocks_to_remove) {
+      InternalRemoveResidualBlock(residual_block);
     }
   } else {
     // Scan all the residual blocks to remove ones that depend on the parameter
@@ -508,39 +503,32 @@
   parameter_block->SetVarying();
 }
 
-void ProblemImpl::SetParameterization(
-    double* values, LocalParameterization* local_parameterization) {
+void ProblemImpl::SetManifold(double* values, Manifold* manifold) {
   ParameterBlock* parameter_block =
       FindWithDefault(parameter_block_map_, values, nullptr);
   if (parameter_block == nullptr) {
     LOG(FATAL) << "Parameter block not found: " << values
                << ". You must add the parameter block to the problem before "
-               << "you can set its local parameterization.";
+               << "you can set its manifold.";
   }
 
-  // If the parameter block already has a local parameterization and
-  // we are to take ownership of local parameterizations, then add it
-  // to local_parameterizations_to_delete_ for eventual deletion.
-  if (parameter_block->local_parameterization_ &&
-      options_.local_parameterization_ownership == TAKE_OWNERSHIP) {
-    local_parameterizations_to_delete_.push_back(
-        parameter_block->local_parameterization_);
-  }
-
-  parameter_block->SetParameterization(local_parameterization);
+  InternalSetManifold(values, parameter_block, manifold);
 }
 
-const LocalParameterization* ProblemImpl::GetParameterization(
-    const double* values) const {
+const Manifold* ProblemImpl::GetManifold(const double* values) const {
   ParameterBlock* parameter_block = FindWithDefault(
       parameter_block_map_, const_cast<double*>(values), nullptr);
   if (parameter_block == nullptr) {
     LOG(FATAL) << "Parameter block not found: " << values
                << ". You must add the parameter block to the problem before "
-               << "you can get its local parameterization.";
+               << "you can get its manifold.";
   }
 
-  return parameter_block->local_parameterization();
+  return parameter_block->manifold();
+}
+
+bool ProblemImpl::HasManifold(const double* values) const {
+  return GetManifold(values) != nullptr;
 }
 
 void ProblemImpl::SetParameterLowerBound(double* values,
@@ -596,8 +584,8 @@
 
 bool ProblemImpl::Evaluate(const Problem::EvaluateOptions& evaluate_options,
                            double* cost,
-                           vector<double>* residuals,
-                           vector<double>* gradient,
+                           std::vector<double>* residuals,
+                           std::vector<double>* gradient,
                            CRSMatrix* jacobian) {
   if (cost == nullptr && residuals == nullptr && gradient == nullptr &&
       jacobian == nullptr) {
@@ -612,11 +600,11 @@
            ? evaluate_options.residual_blocks
            : program_->residual_blocks());
 
-  const vector<double*>& parameter_block_ptrs =
+  const std::vector<double*>& parameter_block_ptrs =
       evaluate_options.parameter_blocks;
 
-  vector<ParameterBlock*> variable_parameter_blocks;
-  vector<ParameterBlock*>& parameter_blocks =
+  std::vector<ParameterBlock*> variable_parameter_blocks;
+  std::vector<ParameterBlock*>& parameter_blocks =
       *program.mutable_parameter_blocks();
 
   if (parameter_block_ptrs.size() == 0) {
@@ -649,13 +637,15 @@
     // columns of the jacobian, we need to make sure that they are
     // constant during evaluation and then make them variable again
     // after we are done.
-    vector<ParameterBlock*> all_parameter_blocks(program_->parameter_blocks());
-    vector<ParameterBlock*> included_parameter_blocks(
+    std::vector<ParameterBlock*> all_parameter_blocks(
+        program_->parameter_blocks());
+    std::vector<ParameterBlock*> included_parameter_blocks(
         program.parameter_blocks());
 
-    vector<ParameterBlock*> excluded_parameter_blocks;
-    sort(all_parameter_blocks.begin(), all_parameter_blocks.end());
-    sort(included_parameter_blocks.begin(), included_parameter_blocks.end());
+    std::vector<ParameterBlock*> excluded_parameter_blocks;
+    std::sort(all_parameter_blocks.begin(), all_parameter_blocks.end());
+    std::sort(included_parameter_blocks.begin(),
+              included_parameter_blocks.end());
     set_difference(all_parameter_blocks.begin(),
                    all_parameter_blocks.end(),
                    included_parameter_blocks.begin(),
@@ -663,8 +653,7 @@
                    back_inserter(excluded_parameter_blocks));
 
     variable_parameter_blocks.reserve(excluded_parameter_blocks.size());
-    for (int i = 0; i < excluded_parameter_blocks.size(); ++i) {
-      ParameterBlock* parameter_block = excluded_parameter_blocks[i];
+    for (auto* parameter_block : excluded_parameter_blocks) {
       if (!parameter_block->IsConstant()) {
         variable_parameter_blocks.push_back(parameter_block);
         parameter_block->SetConstant();
@@ -678,23 +667,13 @@
 
   Evaluator::Options evaluator_options;
 
-  // Even though using SPARSE_NORMAL_CHOLESKY requires SuiteSparse or
-  // CXSparse, here it just being used for telling the evaluator to
-  // use a SparseRowCompressedMatrix for the jacobian. This is because
-  // the Evaluator decides the storage for the Jacobian based on the
-  // type of linear solver being used.
+  // Even though using SPARSE_NORMAL_CHOLESKY requires a sparse linear algebra
+  // library here it just being used for telling the evaluator to use a
+  // SparseRowCompressedMatrix for the jacobian. This is because the Evaluator
+  // decides the storage for the Jacobian based on the type of linear solver
+  // being used.
   evaluator_options.linear_solver_type = SPARSE_NORMAL_CHOLESKY;
-#ifdef CERES_NO_THREADS
-  if (evaluate_options.num_threads > 1) {
-    LOG(WARNING)
-        << "No threading support is compiled into this binary; "
-        << "only evaluate_options.num_threads = 1 is supported. Switching "
-        << "to single threaded mode.";
-  }
-  evaluator_options.num_threads = 1;
-#else
   evaluator_options.num_threads = evaluate_options.num_threads;
-#endif  // CERES_NO_THREADS
 
   // The main thread also does work so we only need to launch num_threads - 1.
   context_impl_->EnsureMinimumThreads(evaluator_options.num_threads - 1);
@@ -716,8 +695,8 @@
 
   std::unique_ptr<CompressedRowSparseMatrix> tmp_jacobian;
   if (jacobian != nullptr) {
-    tmp_jacobian.reset(
-        down_cast<CompressedRowSparseMatrix*>(evaluator->CreateJacobian()));
+    tmp_jacobian.reset(down_cast<CompressedRowSparseMatrix*>(
+        evaluator->CreateJacobian().release()));
   }
 
   // Point the state pointers to the user state pointers. This is
@@ -749,8 +728,8 @@
 
   // Make the parameter blocks that were temporarily marked constant,
   // variable again.
-  for (int i = 0; i < variable_parameter_blocks.size(); ++i) {
-    variable_parameter_blocks[i]->SetVarying();
+  for (auto* parameter_block : variable_parameter_blocks) {
+    parameter_block->SetVarying();
   }
 
   if (status) {
@@ -829,24 +808,25 @@
   return parameter_block->Size();
 }
 
-int ProblemImpl::ParameterBlockLocalSize(const double* values) const {
+int ProblemImpl::ParameterBlockTangentSize(const double* values) const {
   ParameterBlock* parameter_block = FindWithDefault(
       parameter_block_map_, const_cast<double*>(values), nullptr);
   if (parameter_block == nullptr) {
     LOG(FATAL) << "Parameter block not found: " << values
                << ". You must add the parameter block to the problem before "
-               << "you can get its local size.";
+               << "you can get its tangent size.";
   }
 
-  return parameter_block->LocalSize();
+  return parameter_block->TangentSize();
 }
 
-bool ProblemImpl::HasParameterBlock(const double* parameter_block) const {
-  return (parameter_block_map_.find(const_cast<double*>(parameter_block)) !=
+bool ProblemImpl::HasParameterBlock(const double* values) const {
+  return (parameter_block_map_.find(const_cast<double*>(values)) !=
           parameter_block_map_.end());
 }
 
-void ProblemImpl::GetParameterBlocks(vector<double*>* parameter_blocks) const {
+void ProblemImpl::GetParameterBlocks(
+    std::vector<double*>* parameter_blocks) const {
   CHECK(parameter_blocks != nullptr);
   parameter_blocks->resize(0);
   parameter_blocks->reserve(parameter_block_map_.size());
@@ -856,14 +836,14 @@
 }
 
 void ProblemImpl::GetResidualBlocks(
-    vector<ResidualBlockId>* residual_blocks) const {
+    std::vector<ResidualBlockId>* residual_blocks) const {
   CHECK(residual_blocks != nullptr);
   *residual_blocks = program().residual_blocks();
 }
 
 void ProblemImpl::GetParameterBlocksForResidualBlock(
     const ResidualBlockId residual_block,
-    vector<double*>* parameter_blocks) const {
+    std::vector<double*>* parameter_blocks) const {
   int num_parameter_blocks = residual_block->NumParameterBlocks();
   CHECK(parameter_blocks != nullptr);
   parameter_blocks->resize(num_parameter_blocks);
@@ -884,7 +864,7 @@
 }
 
 void ProblemImpl::GetResidualBlocksForParameterBlock(
-    const double* values, vector<ResidualBlockId>* residual_blocks) const {
+    const double* values, std::vector<ResidualBlockId>* residual_blocks) const {
   ParameterBlock* parameter_block = FindWithDefault(
       parameter_block_map_, const_cast<double*>(values), nullptr);
   if (parameter_block == nullptr) {
@@ -921,5 +901,4 @@
   }
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/problem_impl.h b/third_party/ceres/internal/ceres/problem_impl.h
index 9abff3f..733f26e 100644
--- a/third_party/ceres/internal/ceres/problem_impl.h
+++ b/third_party/ceres/internal/ceres/problem_impl.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -42,11 +42,15 @@
 #include <array>
 #include <map>
 #include <memory>
+#include <unordered_map>
 #include <unordered_set>
 #include <vector>
 
 #include "ceres/context_impl.h"
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 #include "ceres/internal/port.h"
+#include "ceres/manifold.h"
 #include "ceres/problem.h"
 #include "ceres/types.h"
 
@@ -55,7 +59,6 @@
 class CostFunction;
 class EvaluationCallback;
 class LossFunction;
-class LocalParameterization;
 struct CRSMatrix;
 
 namespace internal {
@@ -63,12 +66,12 @@
 class Program;
 class ResidualBlock;
 
-class CERES_EXPORT_INTERNAL ProblemImpl {
+class CERES_NO_EXPORT ProblemImpl {
  public:
-  typedef std::map<double*, ParameterBlock*> ParameterMap;
-  typedef std::unordered_set<ResidualBlock*> ResidualBlockSet;
-  typedef std::map<CostFunction*, int> CostFunctionRefCount;
-  typedef std::map<LossFunction*, int> LossFunctionRefCount;
+  using ParameterMap = std::map<double*, ParameterBlock*>;
+  using ResidualBlockSet = std::unordered_set<ResidualBlock*>;
+  using CostFunctionRefCount = std::map<CostFunction*, int>;
+  using LossFunctionRefCount = std::map<LossFunction*, int>;
 
   ProblemImpl();
   explicit ProblemImpl(const Problem::Options& options);
@@ -96,9 +99,7 @@
   }
 
   void AddParameterBlock(double* values, int size);
-  void AddParameterBlock(double* values,
-                         int size,
-                         LocalParameterization* local_parameterization);
+  void AddParameterBlock(double* values, int size, Manifold* manifold);
 
   void RemoveResidualBlock(ResidualBlock* residual_block);
   void RemoveParameterBlock(const double* values);
@@ -107,9 +108,9 @@
   void SetParameterBlockVariable(double* values);
   bool IsParameterBlockConstant(const double* values) const;
 
-  void SetParameterization(double* values,
-                           LocalParameterization* local_parameterization);
-  const LocalParameterization* GetParameterization(const double* values) const;
+  void SetManifold(double* values, Manifold* manifold);
+  const Manifold* GetManifold(const double* values) const;
+  bool HasManifold(const double* values) const;
 
   void SetParameterLowerBound(double* values, int index, double lower_bound);
   void SetParameterUpperBound(double* values, int index, double upper_bound);
@@ -134,10 +135,10 @@
   int NumResidualBlocks() const;
   int NumResiduals() const;
 
-  int ParameterBlockSize(const double* parameter_block) const;
-  int ParameterBlockLocalSize(const double* parameter_block) const;
+  int ParameterBlockSize(const double* values) const;
+  int ParameterBlockTangentSize(const double* values) const;
 
-  bool HasParameterBlock(const double* parameter_block) const;
+  bool HasParameterBlock(const double* values) const;
 
   void GetParameterBlocks(std::vector<double*>* parameter_blocks) const;
   void GetResidualBlocks(std::vector<ResidualBlockId>* residual_blocks) const;
@@ -165,10 +166,16 @@
     return residual_block_set_;
   }
 
+  const Problem::Options& options() const { return options_; }
+
   ContextImpl* context() { return context_impl_; }
 
  private:
   ParameterBlock* InternalAddParameterBlock(double* values, int size);
+  void InternalSetManifold(double* values,
+                           ParameterBlock* parameter_block,
+                           Manifold* manifold);
+
   void InternalRemoveResidualBlock(ResidualBlock* residual_block);
 
   // Delete the arguments in question. These differ from the Remove* functions
@@ -194,13 +201,15 @@
   // The actual parameter and residual blocks.
   std::unique_ptr<internal::Program> program_;
 
-  // When removing parameter blocks, parameterizations have ambiguous
+  // TODO(sameeragarwal): Unify the shared object handling across object types.
+  // Right now we are using vectors for Manifold objects and reference counting
+  // for CostFunctions and LossFunctions. Ideally this should be done uniformly.
+
+  // When removing parameter blocks, manifolds have ambiguous
   // ownership. Instead of scanning the entire problem to see if the
-  // parameterization is shared with other parameter blocks, buffer
+  // manifold is shared with other parameter blocks, buffer
   // them until destruction.
-  //
-  // TODO(keir): See if it makes sense to use sets instead.
-  std::vector<LocalParameterization*> local_parameterizations_to_delete_;
+  std::vector<Manifold*> manifolds_to_delete_;
 
   // For each cost function and loss function in the problem, a count
   // of the number of residual blocks that refer to them. When the
@@ -213,4 +222,6 @@
 }  // namespace internal
 }  // namespace ceres
 
+#include "ceres/internal/reenable_warnings.h"
+
 #endif  // CERES_PUBLIC_PROBLEM_IMPL_H_
diff --git a/third_party/ceres/internal/ceres/problem_test.cc b/third_party/ceres/internal/ceres/problem_test.cc
index 9f129df..ebf15cd 100644
--- a/third_party/ceres/internal/ceres/problem_test.cc
+++ b/third_party/ceres/internal/ceres/problem_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -32,6 +32,8 @@
 #include "ceres/problem.h"
 
 #include <memory>
+#include <string>
+#include <vector>
 
 #include "ceres/autodiff_cost_function.h"
 #include "ceres/casts.h"
@@ -39,7 +41,6 @@
 #include "ceres/crs_matrix.h"
 #include "ceres/evaluator_test_utils.h"
 #include "ceres/internal/eigen.h"
-#include "ceres/local_parameterization.h"
 #include "ceres/loss_function.h"
 #include "ceres/map_util.h"
 #include "ceres/parameter_block.h"
@@ -51,10 +52,7 @@
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
-
-using std::vector;
+namespace ceres::internal {
 
 // The following three classes are for the purposes of defining
 // function signatures. They have dummy Evaluate functions.
@@ -67,8 +65,6 @@
     mutable_parameter_block_sizes()->push_back(parameter_block_size);
   }
 
-  virtual ~UnaryCostFunction() {}
-
   bool Evaluate(double const* const* parameters,
                 double* residuals,
                 double** jacobians) const final {
@@ -148,7 +144,7 @@
   problem.AddParameterBlock(y, 4);
   problem.AddParameterBlock(z, 5);
 
-  EXPECT_DEATH_IF_SUPPORTED(problem.AddResidualBlock(NULL, NULL, x),
+  EXPECT_DEATH_IF_SUPPORTED(problem.AddResidualBlock(nullptr, nullptr, x),
                             "cost_function != nullptr");
 }
 
@@ -162,7 +158,7 @@
 
   // UnaryCostFunction takes only one parameter, but two are passed.
   EXPECT_DEATH_IF_SUPPORTED(
-      problem.AddResidualBlock(new UnaryCostFunction(2, 3), NULL, x, y),
+      problem.AddResidualBlock(new UnaryCostFunction(2, 3), nullptr, x, y),
       "num_parameter_blocks");
 }
 
@@ -170,10 +166,10 @@
   double x[3];
 
   Problem problem;
-  problem.AddResidualBlock(new UnaryCostFunction(2, 3), NULL, x);
+  problem.AddResidualBlock(new UnaryCostFunction(2, 3), nullptr, x);
   EXPECT_DEATH_IF_SUPPORTED(
       problem.AddResidualBlock(
-          new UnaryCostFunction(2, 4 /* 4 != 3 */), NULL, x),
+          new UnaryCostFunction(2, 4 /* 4 != 3 */), nullptr, x),
       "different block sizes");
 }
 
@@ -182,11 +178,11 @@
 
   Problem problem;
   EXPECT_DEATH_IF_SUPPORTED(
-      problem.AddResidualBlock(new BinaryCostFunction(2, 3, 3), NULL, x, x),
+      problem.AddResidualBlock(new BinaryCostFunction(2, 3, 3), nullptr, x, x),
       "Duplicate parameter blocks");
   EXPECT_DEATH_IF_SUPPORTED(
       problem.AddResidualBlock(
-          new TernaryCostFunction(1, 5, 3, 5), NULL, z, x, z),
+          new TernaryCostFunction(1, 5, 3, 5), nullptr, z, x, z),
       "Duplicate parameter blocks");
 }
 
@@ -201,7 +197,7 @@
   // The cost function expects the size of the second parameter, z, to be 4
   // instead of 5 as declared above. This is fatal.
   EXPECT_DEATH_IF_SUPPORTED(
-      problem.AddResidualBlock(new BinaryCostFunction(2, 3, 4), NULL, x, z),
+      problem.AddResidualBlock(new BinaryCostFunction(2, 3, 4), nullptr, x, z),
       "different block sizes");
 }
 
@@ -209,10 +205,10 @@
   double x[3], y[4], z[5];
 
   Problem problem;
-  problem.AddResidualBlock(new UnaryCostFunction(2, 3), NULL, x);
-  problem.AddResidualBlock(new UnaryCostFunction(2, 3), NULL, x);
-  problem.AddResidualBlock(new UnaryCostFunction(2, 4), NULL, y);
-  problem.AddResidualBlock(new UnaryCostFunction(2, 5), NULL, z);
+  problem.AddResidualBlock(new UnaryCostFunction(2, 3), nullptr, x);
+  problem.AddResidualBlock(new UnaryCostFunction(2, 3), nullptr, x);
+  problem.AddResidualBlock(new UnaryCostFunction(2, 4), nullptr, y);
+  problem.AddResidualBlock(new UnaryCostFunction(2, 5), nullptr, z);
 
   EXPECT_EQ(3, problem.NumParameterBlocks());
   EXPECT_EQ(12, problem.NumParameters());
@@ -278,62 +274,26 @@
 
   // Creating parameter blocks multiple times is ignored.
   problem.AddParameterBlock(x, 3);
-  problem.AddResidualBlock(new UnaryCostFunction(2, 3), NULL, x);
+  problem.AddResidualBlock(new UnaryCostFunction(2, 3), nullptr, x);
 
   // ... even repeatedly.
   problem.AddParameterBlock(x, 3);
-  problem.AddResidualBlock(new UnaryCostFunction(2, 3), NULL, x);
+  problem.AddResidualBlock(new UnaryCostFunction(2, 3), nullptr, x);
 
   // More parameters are fine.
   problem.AddParameterBlock(y, 4);
-  problem.AddResidualBlock(new UnaryCostFunction(2, 4), NULL, y);
+  problem.AddResidualBlock(new UnaryCostFunction(2, 4), nullptr, y);
 
   EXPECT_EQ(2, problem.NumParameterBlocks());
   EXPECT_EQ(7, problem.NumParameters());
 }
 
-TEST(Problem, AddingParametersAndResidualsResultsInExpectedProblem) {
-  double x[3], y[4], z[5], w[4];
-
-  Problem problem;
-  problem.AddParameterBlock(x, 3);
-  EXPECT_EQ(1, problem.NumParameterBlocks());
-  EXPECT_EQ(3, problem.NumParameters());
-
-  problem.AddParameterBlock(y, 4);
-  EXPECT_EQ(2, problem.NumParameterBlocks());
-  EXPECT_EQ(7, problem.NumParameters());
-
-  problem.AddParameterBlock(z, 5);
-  EXPECT_EQ(3, problem.NumParameterBlocks());
-  EXPECT_EQ(12, problem.NumParameters());
-
-  // Add a parameter that has a local parameterization.
-  w[0] = 1.0;
-  w[1] = 0.0;
-  w[2] = 0.0;
-  w[3] = 0.0;
-  problem.AddParameterBlock(w, 4, new QuaternionParameterization);
-  EXPECT_EQ(4, problem.NumParameterBlocks());
-  EXPECT_EQ(16, problem.NumParameters());
-
-  problem.AddResidualBlock(new UnaryCostFunction(2, 3), NULL, x);
-  problem.AddResidualBlock(new BinaryCostFunction(6, 5, 4), NULL, z, y);
-  problem.AddResidualBlock(new BinaryCostFunction(3, 3, 5), NULL, x, z);
-  problem.AddResidualBlock(new BinaryCostFunction(7, 5, 3), NULL, z, x);
-  problem.AddResidualBlock(new TernaryCostFunction(1, 5, 3, 4), NULL, z, x, y);
-
-  const int total_residuals = 2 + 6 + 3 + 7 + 1;
-  EXPECT_EQ(problem.NumResidualBlocks(), 5);
-  EXPECT_EQ(problem.NumResiduals(), total_residuals);
-}
-
 class DestructorCountingCostFunction : public SizedCostFunction<3, 4, 5> {
  public:
   explicit DestructorCountingCostFunction(int* num_destructions)
       : num_destructions_(num_destructions) {}
 
-  virtual ~DestructorCountingCostFunction() { *num_destructions_ += 1; }
+  ~DestructorCountingCostFunction() override { *num_destructions_ += 1; }
 
   bool Evaluate(double const* const* parameters,
                 double* residuals,
@@ -357,9 +317,9 @@
     problem.AddParameterBlock(z, 5);
 
     CostFunction* cost = new DestructorCountingCostFunction(&num_destructions);
-    problem.AddResidualBlock(cost, NULL, y, z);
-    problem.AddResidualBlock(cost, NULL, y, z);
-    problem.AddResidualBlock(cost, NULL, y, z);
+    problem.AddResidualBlock(cost, nullptr, y, z);
+    problem.AddResidualBlock(cost, nullptr, y, z);
+    problem.AddResidualBlock(cost, nullptr, y, z);
     EXPECT_EQ(3, problem.NumResidualBlocks());
   }
 
@@ -372,10 +332,11 @@
   Problem problem;
   CostFunction* cost_function = new UnaryCostFunction(2, 3);
   const ResidualBlockId residual_block =
-      problem.AddResidualBlock(cost_function, NULL, x);
+      problem.AddResidualBlock(cost_function, nullptr, x);
   EXPECT_EQ(problem.GetCostFunctionForResidualBlock(residual_block),
             cost_function);
-  EXPECT_TRUE(problem.GetLossFunctionForResidualBlock(residual_block) == NULL);
+  EXPECT_TRUE(problem.GetLossFunctionForResidualBlock(residual_block) ==
+              nullptr);
 }
 
 TEST(Problem, GetLossFunctionForResidualBlock) {
@@ -403,8 +364,8 @@
         new DestructorCountingCostFunction(&num_destructions);
     CostFunction* cost_wz =
         new DestructorCountingCostFunction(&num_destructions);
-    ResidualBlock* r_yz = problem.AddResidualBlock(cost_yz, NULL, y, z);
-    ResidualBlock* r_wz = problem.AddResidualBlock(cost_wz, NULL, w, z);
+    ResidualBlock* r_yz = problem.AddResidualBlock(cost_yz, nullptr, y, z);
+    ResidualBlock* r_wz = problem.AddResidualBlock(cost_wz, nullptr, w, z);
     EXPECT_EQ(2, problem.NumResidualBlocks());
 
     problem.RemoveResidualBlock(r_yz);
@@ -427,7 +388,7 @@
   DynamicProblem() {
     Problem::Options options;
     options.enable_fast_removal = GetParam();
-    problem.reset(new ProblemImpl(options));
+    problem = std::make_unique<ProblemImpl>(options);
   }
 
   ParameterBlock* GetParameterBlock(int block) {
@@ -575,16 +536,15 @@
                             "Parameter block not found:");
 }
 
-TEST(Problem, SetLocalParameterizationWithUnknownPtrDies) {
+TEST(Problem, SetManifoldWithUnknownPtrDies) {
   double x[3];
   double y[2];
 
   Problem problem;
   problem.AddParameterBlock(x, 3);
 
-  EXPECT_DEATH_IF_SUPPORTED(
-      problem.SetParameterization(y, new IdentityParameterization(3)),
-      "Parameter block not found:");
+  EXPECT_DEATH_IF_SUPPORTED(problem.SetManifold(y, new EuclideanManifold<3>),
+                            "Parameter block not found:");
 }
 
 TEST(Problem, RemoveParameterBlockWithUnknownPtrDies) {
@@ -598,7 +558,7 @@
                             "Parameter block not found:");
 }
 
-TEST(Problem, GetParameterization) {
+TEST(Problem, GetManifold) {
   double x[3];
   double y[2];
 
@@ -606,10 +566,84 @@
   problem.AddParameterBlock(x, 3);
   problem.AddParameterBlock(y, 2);
 
-  LocalParameterization* parameterization = new IdentityParameterization(3);
-  problem.SetParameterization(x, parameterization);
-  EXPECT_EQ(problem.GetParameterization(x), parameterization);
-  EXPECT_TRUE(problem.GetParameterization(y) == NULL);
+  Manifold* manifold = new EuclideanManifold<3>;
+  problem.SetManifold(x, manifold);
+  EXPECT_EQ(problem.GetManifold(x), manifold);
+  EXPECT_TRUE(problem.GetManifold(y) == nullptr);
+}
+
+TEST(Problem, HasManifold) {
+  double x[3];
+  double y[2];
+
+  Problem problem;
+  problem.AddParameterBlock(x, 3);
+  problem.AddParameterBlock(y, 2);
+
+  Manifold* manifold = new EuclideanManifold<3>;
+  problem.SetManifold(x, manifold);
+  EXPECT_TRUE(problem.HasManifold(x));
+  EXPECT_FALSE(problem.HasManifold(y));
+}
+
+TEST(Problem, RepeatedAddParameterBlockResetsManifold) {
+  double x[4];
+  double y[2];
+
+  Problem problem;
+  problem.AddParameterBlock(x, 4, new SubsetManifold(4, {0, 1}));
+  problem.AddParameterBlock(y, 2);
+
+  EXPECT_FALSE(problem.HasManifold(y));
+
+  EXPECT_TRUE(problem.HasManifold(x));
+  EXPECT_EQ(problem.ParameterBlockSize(x), 4);
+  EXPECT_EQ(problem.ParameterBlockTangentSize(x), 2);
+  EXPECT_EQ(problem.GetManifold(x)->AmbientSize(), 4);
+  EXPECT_EQ(problem.GetManifold(x)->TangentSize(), 2);
+
+  problem.AddParameterBlock(x, 4, static_cast<Manifold*>(nullptr));
+  EXPECT_FALSE(problem.HasManifold(x));
+  EXPECT_EQ(problem.ParameterBlockSize(x), 4);
+  EXPECT_EQ(problem.ParameterBlockTangentSize(x), 4);
+  EXPECT_EQ(problem.GetManifold(x), nullptr);
+
+  problem.AddParameterBlock(x, 4, new SubsetManifold(4, {0, 1, 2}));
+  problem.AddParameterBlock(y, 2);
+  EXPECT_TRUE(problem.HasManifold(x));
+  EXPECT_EQ(problem.ParameterBlockSize(x), 4);
+  EXPECT_EQ(problem.ParameterBlockTangentSize(x), 1);
+  EXPECT_EQ(problem.GetManifold(x)->AmbientSize(), 4);
+  EXPECT_EQ(problem.GetManifold(x)->TangentSize(), 1);
+}
+
+TEST(Problem, ParameterBlockQueryTestUsingManifold) {
+  double x[3];
+  double y[4];
+  Problem problem;
+  problem.AddParameterBlock(x, 3);
+  problem.AddParameterBlock(y, 4);
+
+  std::vector<int> constant_parameters;
+  constant_parameters.push_back(0);
+  problem.SetManifold(x, new SubsetManifold(3, constant_parameters));
+  EXPECT_EQ(problem.ParameterBlockSize(x), 3);
+  EXPECT_EQ(problem.ParameterBlockTangentSize(x), 2);
+  EXPECT_EQ(problem.ParameterBlockTangentSize(y), 4);
+
+  std::vector<double*> parameter_blocks;
+  problem.GetParameterBlocks(&parameter_blocks);
+  EXPECT_EQ(parameter_blocks.size(), 2);
+  EXPECT_NE(parameter_blocks[0], parameter_blocks[1]);
+  EXPECT_TRUE(parameter_blocks[0] == x || parameter_blocks[0] == y);
+  EXPECT_TRUE(parameter_blocks[1] == x || parameter_blocks[1] == y);
+
+  EXPECT_TRUE(problem.HasParameterBlock(x));
+  problem.RemoveParameterBlock(x);
+  EXPECT_FALSE(problem.HasParameterBlock(x));
+  problem.GetParameterBlocks(&parameter_blocks);
+  EXPECT_EQ(parameter_blocks.size(), 1);
+  EXPECT_TRUE(parameter_blocks[0] == y);
 }
 
 TEST(Problem, ParameterBlockQueryTest) {
@@ -619,15 +653,14 @@
   problem.AddParameterBlock(x, 3);
   problem.AddParameterBlock(y, 4);
 
-  vector<int> constant_parameters;
+  std::vector<int> constant_parameters;
   constant_parameters.push_back(0);
-  problem.SetParameterization(
-      x, new SubsetParameterization(3, constant_parameters));
+  problem.SetManifold(x, new SubsetManifold(3, constant_parameters));
   EXPECT_EQ(problem.ParameterBlockSize(x), 3);
-  EXPECT_EQ(problem.ParameterBlockLocalSize(x), 2);
-  EXPECT_EQ(problem.ParameterBlockLocalSize(y), 4);
+  EXPECT_EQ(problem.ParameterBlockTangentSize(x), 2);
+  EXPECT_EQ(problem.ParameterBlockTangentSize(y), 4);
 
-  vector<double*> parameter_blocks;
+  std::vector<double*> parameter_blocks;
   problem.GetParameterBlocks(&parameter_blocks);
   EXPECT_EQ(parameter_blocks.size(), 2);
   EXPECT_NE(parameter_blocks[0], parameter_blocks[1]);
@@ -720,13 +753,13 @@
   CostFunction* cost_z   = new UnaryCostFunction  (1, 5);
   CostFunction* cost_w   = new UnaryCostFunction  (1, 3);
 
-  ResidualBlock* r_yzw = problem->AddResidualBlock(cost_yzw, NULL, y, z, w);
-  ResidualBlock* r_yz  = problem->AddResidualBlock(cost_yz,  NULL, y, z);
-  ResidualBlock* r_yw  = problem->AddResidualBlock(cost_yw,  NULL, y, w);
-  ResidualBlock* r_zw  = problem->AddResidualBlock(cost_zw,  NULL, z, w);
-  ResidualBlock* r_y   = problem->AddResidualBlock(cost_y,   NULL, y);
-  ResidualBlock* r_z   = problem->AddResidualBlock(cost_z,   NULL, z);
-  ResidualBlock* r_w   = problem->AddResidualBlock(cost_w,   NULL, w);
+  ResidualBlock* r_yzw = problem->AddResidualBlock(cost_yzw, nullptr, y, z, w);
+  ResidualBlock* r_yz  = problem->AddResidualBlock(cost_yz,  nullptr, y, z);
+  ResidualBlock* r_yw  = problem->AddResidualBlock(cost_yw,  nullptr, y, w);
+  ResidualBlock* r_zw  = problem->AddResidualBlock(cost_zw,  nullptr, z, w);
+  ResidualBlock* r_y   = problem->AddResidualBlock(cost_y,   nullptr, y);
+  ResidualBlock* r_z   = problem->AddResidualBlock(cost_z,   nullptr, z);
+  ResidualBlock* r_w   = problem->AddResidualBlock(cost_w,   nullptr, w);
 
   EXPECT_EQ(3, problem->NumParameterBlocks());
   EXPECT_EQ(7, NumResidualBlocks());
@@ -781,13 +814,13 @@
   CostFunction* cost_z   = new UnaryCostFunction  (1, 5);
   CostFunction* cost_w   = new UnaryCostFunction  (1, 3);
 
-  ResidualBlock* r_yzw = problem->AddResidualBlock(cost_yzw, NULL, y, z, w);
-  ResidualBlock* r_yz  = problem->AddResidualBlock(cost_yz,  NULL, y, z);
-  ResidualBlock* r_yw  = problem->AddResidualBlock(cost_yw,  NULL, y, w);
-  ResidualBlock* r_zw  = problem->AddResidualBlock(cost_zw,  NULL, z, w);
-  ResidualBlock* r_y   = problem->AddResidualBlock(cost_y,   NULL, y);
-  ResidualBlock* r_z   = problem->AddResidualBlock(cost_z,   NULL, z);
-  ResidualBlock* r_w   = problem->AddResidualBlock(cost_w,   NULL, w);
+  ResidualBlock* r_yzw = problem->AddResidualBlock(cost_yzw, nullptr, y, z, w);
+  ResidualBlock* r_yz  = problem->AddResidualBlock(cost_yz,  nullptr, y, z);
+  ResidualBlock* r_yw  = problem->AddResidualBlock(cost_yw,  nullptr, y, w);
+  ResidualBlock* r_zw  = problem->AddResidualBlock(cost_zw,  nullptr, z, w);
+  ResidualBlock* r_y   = problem->AddResidualBlock(cost_y,   nullptr, y);
+  ResidualBlock* r_z   = problem->AddResidualBlock(cost_z,   nullptr, z);
+  ResidualBlock* r_w   = problem->AddResidualBlock(cost_w,   nullptr, w);
 
   if (GetParam()) {
     // In this test parameterization, there should be back-pointers from the
@@ -797,9 +830,9 @@
     ExpectParameterBlockContains(w, r_yzw, r_yw, r_zw, r_w);
   } else {
     // Otherwise, nothing.
-    EXPECT_TRUE(GetParameterBlock(0)->mutable_residual_blocks() == NULL);
-    EXPECT_TRUE(GetParameterBlock(1)->mutable_residual_blocks() == NULL);
-    EXPECT_TRUE(GetParameterBlock(2)->mutable_residual_blocks() == NULL);
+    EXPECT_TRUE(GetParameterBlock(0)->mutable_residual_blocks() == nullptr);
+    EXPECT_TRUE(GetParameterBlock(1)->mutable_residual_blocks() == nullptr);
+    EXPECT_TRUE(GetParameterBlock(2)->mutable_residual_blocks() == nullptr);
   }
   EXPECT_EQ(3, problem->NumParameterBlocks());
   EXPECT_EQ(7, NumResidualBlocks());
@@ -906,13 +939,13 @@
   CostFunction* cost_z   = new UnaryCostFunction  (1, 5);
   CostFunction* cost_w   = new UnaryCostFunction  (1, 3);
 
-  ResidualBlock* r_yzw = problem->AddResidualBlock(cost_yzw, NULL, y, z, w);
-  ResidualBlock* r_yz  = problem->AddResidualBlock(cost_yz,  NULL, y, z);
-  ResidualBlock* r_yw  = problem->AddResidualBlock(cost_yw,  NULL, y, w);
-  ResidualBlock* r_zw  = problem->AddResidualBlock(cost_zw,  NULL, z, w);
-  ResidualBlock* r_y   = problem->AddResidualBlock(cost_y,   NULL, y);
-  ResidualBlock* r_z   = problem->AddResidualBlock(cost_z,   NULL, z);
-  ResidualBlock* r_w   = problem->AddResidualBlock(cost_w,   NULL, w);
+  ResidualBlock* r_yzw = problem->AddResidualBlock(cost_yzw, nullptr, y, z, w);
+  ResidualBlock* r_yz  = problem->AddResidualBlock(cost_yz,  nullptr, y, z);
+  ResidualBlock* r_yw  = problem->AddResidualBlock(cost_yw,  nullptr, y, w);
+  ResidualBlock* r_zw  = problem->AddResidualBlock(cost_zw,  nullptr, z, w);
+  ResidualBlock* r_y   = problem->AddResidualBlock(cost_y,   nullptr, y);
+  ResidualBlock* r_z   = problem->AddResidualBlock(cost_z,   nullptr, z);
+  ResidualBlock* r_w   = problem->AddResidualBlock(cost_w,   nullptr, w);
 
   // clang-format on
 
@@ -925,8 +958,7 @@
 
   // Attempt to remove a cast pointer never added as a residual.
   int trash_memory = 1234;
-  ResidualBlock* invalid_residual =
-      reinterpret_cast<ResidualBlock*>(&trash_memory);
+  auto* invalid_residual = reinterpret_cast<ResidualBlock*>(&trash_memory);
   EXPECT_DEATH_IF_SUPPORTED(problem->RemoveResidualBlock(invalid_residual),
                             "not found");
 
@@ -946,7 +978,7 @@
 
 // Check that a null-terminated array, a, has the same elements as b.
 template <typename T>
-void ExpectVectorContainsUnordered(const T* a, const vector<T>& b) {
+void ExpectVectorContainsUnordered(const T* a, const std::vector<T>& b) {
   // Compute the size of a.
   int size = 0;
   while (a[size]) {
@@ -955,12 +987,12 @@
   ASSERT_EQ(size, b.size());
 
   // Sort a.
-  vector<T> a_sorted(size);
+  std::vector<T> a_sorted(size);
   copy(a, a + size, a_sorted.begin());
   sort(a_sorted.begin(), a_sorted.end());
 
   // Sort b.
-  vector<T> b_sorted(b);
+  std::vector<T> b_sorted(b);
   sort(b_sorted.begin(), b_sorted.end());
 
   // Compare.
@@ -972,7 +1004,7 @@
 static void ExpectProblemHasResidualBlocks(
     const ProblemImpl& problem,
     const ResidualBlockId* expected_residual_blocks) {
-  vector<ResidualBlockId> residual_blocks;
+  std::vector<ResidualBlockId> residual_blocks;
   problem.GetResidualBlocks(&residual_blocks);
   ExpectVectorContainsUnordered(expected_residual_blocks, residual_blocks);
 }
@@ -993,48 +1025,48 @@
   CostFunction* cost_z   = new UnaryCostFunction  (1, 5);
   CostFunction* cost_w   = new UnaryCostFunction  (1, 3);
 
-  ResidualBlock* r_yzw = problem->AddResidualBlock(cost_yzw, NULL, y, z, w);
+  ResidualBlock* r_yzw = problem->AddResidualBlock(cost_yzw, nullptr, y, z, w);
   {
-    ResidualBlockId expected_residuals[] = {r_yzw, 0};
+    ResidualBlockId expected_residuals[] = {r_yzw, nullptr};
     ExpectProblemHasResidualBlocks(*problem, expected_residuals);
   }
-  ResidualBlock* r_yz  = problem->AddResidualBlock(cost_yz,  NULL, y, z);
+  ResidualBlock* r_yz  = problem->AddResidualBlock(cost_yz,  nullptr, y, z);
   {
-    ResidualBlockId expected_residuals[] = {r_yzw, r_yz, 0};
+    ResidualBlockId expected_residuals[] = {r_yzw, r_yz, nullptr};
     ExpectProblemHasResidualBlocks(*problem, expected_residuals);
   }
-  ResidualBlock* r_yw  = problem->AddResidualBlock(cost_yw,  NULL, y, w);
+  ResidualBlock* r_yw  = problem->AddResidualBlock(cost_yw,  nullptr, y, w);
   {
-    ResidualBlock *expected_residuals[] = {r_yzw, r_yz, r_yw, 0};
+    ResidualBlock *expected_residuals[] = {r_yzw, r_yz, r_yw, nullptr};
     ExpectProblemHasResidualBlocks(*problem, expected_residuals);
   }
-  ResidualBlock* r_zw  = problem->AddResidualBlock(cost_zw,  NULL, z, w);
+  ResidualBlock* r_zw  = problem->AddResidualBlock(cost_zw,  nullptr, z, w);
   {
-    ResidualBlock *expected_residuals[] = {r_yzw, r_yz, r_yw, r_zw, 0};
+    ResidualBlock *expected_residuals[] = {r_yzw, r_yz, r_yw, r_zw, nullptr};
     ExpectProblemHasResidualBlocks(*problem, expected_residuals);
   }
-  ResidualBlock* r_y   = problem->AddResidualBlock(cost_y,   NULL, y);
+  ResidualBlock* r_y   = problem->AddResidualBlock(cost_y,   nullptr, y);
   {
-    ResidualBlock *expected_residuals[] = {r_yzw, r_yz, r_yw, r_zw, r_y, 0};
+    ResidualBlock *expected_residuals[] = {r_yzw, r_yz, r_yw, r_zw, r_y, nullptr};
     ExpectProblemHasResidualBlocks(*problem, expected_residuals);
   }
-  ResidualBlock* r_z   = problem->AddResidualBlock(cost_z,   NULL, z);
+  ResidualBlock* r_z   = problem->AddResidualBlock(cost_z,   nullptr, z);
   {
     ResidualBlock *expected_residuals[] = {
-      r_yzw, r_yz, r_yw, r_zw, r_y, r_z, 0
+      r_yzw, r_yz, r_yw, r_zw, r_y, r_z, nullptr
     };
     ExpectProblemHasResidualBlocks(*problem, expected_residuals);
   }
-  ResidualBlock* r_w   = problem->AddResidualBlock(cost_w,   NULL, w);
+  ResidualBlock* r_w   = problem->AddResidualBlock(cost_w,   nullptr, w);
   {
     ResidualBlock *expected_residuals[] = {
-      r_yzw, r_yz, r_yw, r_zw, r_y, r_z, r_w, 0
+      r_yzw, r_yz, r_yw, r_zw, r_y, r_z, r_w, nullptr
     };
     ExpectProblemHasResidualBlocks(*problem, expected_residuals);
   }
 
-  vector<double*> parameter_blocks;
-  vector<ResidualBlockId> residual_blocks;
+  std::vector<double*> parameter_blocks;
+  std::vector<ResidualBlockId> residual_blocks;
 
   // Check GetResidualBlocksForParameterBlock() for all parameter blocks.
   struct GetResidualBlocksForParameterBlockTestCase {
@@ -1042,10 +1074,10 @@
     ResidualBlockId expected_residual_blocks[10];
   };
   GetResidualBlocksForParameterBlockTestCase get_residual_blocks_cases[] = {
-    { y, { r_yzw, r_yz, r_yw, r_y, NULL} },
-    { z, { r_yzw, r_yz, r_zw, r_z, NULL} },
-    { w, { r_yzw, r_yw, r_zw, r_w, NULL} },
-    { NULL, { NULL } }
+    { y, { r_yzw, r_yz, r_yw, r_y, nullptr} },
+    { z, { r_yzw, r_yz, r_zw, r_z, nullptr} },
+    { w, { r_yzw, r_yw, r_zw, r_w, nullptr} },
+    { nullptr, { nullptr } }
   };
   for (int i = 0; get_residual_blocks_cases[i].parameter_block; ++i) {
     problem->GetResidualBlocksForParameterBlock(
@@ -1062,14 +1094,14 @@
     double* expected_parameter_blocks[10];
   };
   GetParameterBlocksForResidualBlockTestCase get_parameter_blocks_cases[] = {
-    { r_yzw, { y, z, w, NULL } },
-    { r_yz , { y, z, NULL } },
-    { r_yw , { y, w, NULL } },
-    { r_zw , { z, w, NULL } },
-    { r_y  , { y, NULL } },
-    { r_z  , { z, NULL } },
-    { r_w  , { w, NULL } },
-    { NULL, { NULL } }
+    { r_yzw, { y, z, w, nullptr } },
+    { r_yz , { y, z, nullptr } },
+    { r_yw , { y, w, nullptr } },
+    { r_zw , { z, w, nullptr } },
+    { r_y  , { y, nullptr } },
+    { r_z  , { z, nullptr } },
+    { r_w  , { w, nullptr } },
+    { nullptr, { nullptr } }
   };
   for (int i = 0; get_parameter_blocks_cases[i].residual_block; ++i) {
     problem->GetParameterBlocksForResidualBlock(
@@ -1112,12 +1144,12 @@
       }
     }
 
-    if (jacobians == NULL) {
+    if (jacobians == nullptr) {
       return true;
     }
 
     for (int j = 0; j < kNumParameterBlocks; ++j) {
-      if (jacobians[j] != NULL) {
+      if (jacobians[j] != nullptr) {
         MatrixRef(jacobians[j], kNumResiduals, kNumResiduals) =
             (-2.0 * (j + 1.0) * ConstVectorRef(parameters[j], kNumResiduals))
                 .asDiagonal();
@@ -1144,7 +1176,7 @@
 
 class ProblemEvaluateTest : public ::testing::Test {
  protected:
-  void SetUp() {
+  void SetUp() override {
     for (int i = 0; i < 6; ++i) {
       parameters_[i] = static_cast<double>(i + 1);
     }
@@ -1157,16 +1189,16 @@
 
     // f(x, y)
     residual_blocks_.push_back(problem_.AddResidualBlock(
-        cost_function, NULL, parameters_, parameters_ + 2));
+        cost_function, nullptr, parameters_, parameters_ + 2));
     // g(y, z)
     residual_blocks_.push_back(problem_.AddResidualBlock(
-        cost_function, NULL, parameters_ + 2, parameters_ + 4));
+        cost_function, nullptr, parameters_ + 2, parameters_ + 4));
     // h(z, x)
     residual_blocks_.push_back(problem_.AddResidualBlock(
-        cost_function, NULL, parameters_ + 4, parameters_));
+        cost_function, nullptr, parameters_ + 4, parameters_));
   }
 
-  void TearDown() { EXPECT_TRUE(problem_.program().IsValid()); }
+  void TearDown() override { EXPECT_TRUE(problem_.program().IsValid()); }
 
   void EvaluateAndCompare(const Problem::EvaluateOptions& options,
                           const int expected_num_rows,
@@ -1176,32 +1208,32 @@
                           const double* expected_gradient,
                           const double* expected_jacobian) {
     double cost;
-    vector<double> residuals;
-    vector<double> gradient;
+    std::vector<double> residuals;
+    std::vector<double> gradient;
     CRSMatrix jacobian;
 
     EXPECT_TRUE(
         problem_.Evaluate(options,
                           &cost,
-                          expected_residuals != NULL ? &residuals : NULL,
-                          expected_gradient != NULL ? &gradient : NULL,
-                          expected_jacobian != NULL ? &jacobian : NULL));
+                          expected_residuals != nullptr ? &residuals : nullptr,
+                          expected_gradient != nullptr ? &gradient : nullptr,
+                          expected_jacobian != nullptr ? &jacobian : nullptr));
 
-    if (expected_residuals != NULL) {
+    if (expected_residuals != nullptr) {
       EXPECT_EQ(residuals.size(), expected_num_rows);
     }
 
-    if (expected_gradient != NULL) {
+    if (expected_gradient != nullptr) {
       EXPECT_EQ(gradient.size(), expected_num_cols);
     }
 
-    if (expected_jacobian != NULL) {
+    if (expected_jacobian != nullptr) {
       EXPECT_EQ(jacobian.num_rows, expected_num_rows);
       EXPECT_EQ(jacobian.num_cols, expected_num_cols);
     }
 
     Matrix dense_jacobian;
-    if (expected_jacobian != NULL) {
+    if (expected_jacobian != nullptr) {
       CRSToDenseMatrix(jacobian, &dense_jacobian);
     }
 
@@ -1212,8 +1244,8 @@
                        expected_gradient,
                        expected_jacobian,
                        cost,
-                       residuals.size() > 0 ? &residuals[0] : NULL,
-                       gradient.size() > 0 ? &gradient[0] : NULL,
+                       !residuals.empty() ? &residuals[0] : nullptr,
+                       !gradient.empty() ? &gradient[0] : nullptr,
                        dense_jacobian.data());
   }
 
@@ -1224,16 +1256,16 @@
                          expected.num_rows,
                          expected.num_cols,
                          expected.cost,
-                         (i & 1) ? expected.residuals : NULL,
-                         (i & 2) ? expected.gradient : NULL,
-                         (i & 4) ? expected.jacobian : NULL);
+                         (i & 1) ? expected.residuals : nullptr,
+                         (i & 2) ? expected.gradient : nullptr,
+                         (i & 4) ? expected.jacobian : nullptr);
     }
   }
 
   ProblemImpl problem_;
   double parameters_[6];
-  vector<double*> parameter_blocks_;
-  vector<ResidualBlockId> residual_blocks_;
+  std::vector<double*> parameter_blocks_;
+  std::vector<ResidualBlockId> residual_blocks_;
 };
 
 TEST_F(ProblemEvaluateTest, MultipleParameterAndResidualBlocks) {
@@ -1530,7 +1562,7 @@
   CheckAllEvaluationCombinations(evaluate_options, expected);
 }
 
-TEST_F(ProblemEvaluateTest, LocalParameterization) {
+TEST_F(ProblemEvaluateTest, Manifold) {
   // clang-format off
   ExpectedEvaluation expected = {
     // Rows/columns
@@ -1544,7 +1576,7 @@
     },
     // Gradient
     {  146.0,  484.0,  // x
-      1256.0,          // y with SubsetParameterization
+      1256.0,          // y with SubsetManifold
       1450.0, 2604.0,  // z
     },
     // Jacobian
@@ -1559,10 +1591,10 @@
   };
   // clang-format on
 
-  vector<int> constant_parameters;
+  std::vector<int> constant_parameters;
   constant_parameters.push_back(0);
-  problem_.SetParameterization(
-      parameters_ + 2, new SubsetParameterization(2, constant_parameters));
+  problem_.SetManifold(parameters_ + 2,
+                       new SubsetManifold(2, constant_parameters));
 
   CheckAllEvaluationCombinations(Problem::EvaluateOptions(), expected);
 }
@@ -1849,11 +1881,10 @@
       << actual_dfdy;
 }
 
-TEST_F(ProblemEvaluateResidualBlockTest,
-       OneResidualBlockWithOneLocalParameterization) {
+TEST_F(ProblemEvaluateResidualBlockTest, OneResidualBlockWithOneManifold) {
   ResidualBlockId residual_block_id =
       problem_.AddResidualBlock(IdentityFunctor::Create(), nullptr, x_, y_);
-  problem_.SetParameterization(x_, new SubsetParameterization(2, {1}));
+  problem_.SetManifold(x_, new SubsetManifold(2, {1}));
 
   Vector expected_f(5);
   expected_f << 1, 2, 1, 2, 3;
@@ -1893,12 +1924,11 @@
       << actual_dfdy;
 }
 
-TEST_F(ProblemEvaluateResidualBlockTest,
-       OneResidualBlockWithTwoLocalParameterizations) {
+TEST_F(ProblemEvaluateResidualBlockTest, OneResidualBlockWithTwoManifolds) {
   ResidualBlockId residual_block_id =
       problem_.AddResidualBlock(IdentityFunctor::Create(), nullptr, x_, y_);
-  problem_.SetParameterization(x_, new SubsetParameterization(2, {1}));
-  problem_.SetParameterization(y_, new SubsetParameterization(3, {2}));
+  problem_.SetManifold(x_, new SubsetManifold(2, {1}));
+  problem_.SetManifold(y_, new SubsetManifold(3, {2}));
 
   Vector expected_f(5);
   expected_f << 1, 2, 1, 2, 3;
@@ -2139,39 +2169,39 @@
             std::numeric_limits<double>::max());
 }
 
-TEST(Problem, SetParameterizationTwice) {
+TEST(Problem, SetManifoldTwice) {
   Problem problem;
   double x[] = {1.0, 2.0, 3.0};
   problem.AddParameterBlock(x, 3);
-  problem.SetParameterization(x, new SubsetParameterization(3, {1}));
-  EXPECT_EQ(problem.GetParameterization(x)->GlobalSize(), 3);
-  EXPECT_EQ(problem.GetParameterization(x)->LocalSize(), 2);
+  problem.SetManifold(x, new SubsetManifold(3, {1}));
+  EXPECT_EQ(problem.GetManifold(x)->AmbientSize(), 3);
+  EXPECT_EQ(problem.GetManifold(x)->TangentSize(), 2);
 
-  problem.SetParameterization(x, new SubsetParameterization(3, {0, 1}));
-  EXPECT_EQ(problem.GetParameterization(x)->GlobalSize(), 3);
-  EXPECT_EQ(problem.GetParameterization(x)->LocalSize(), 1);
+  problem.SetManifold(x, new SubsetManifold(3, {0, 1}));
+  EXPECT_EQ(problem.GetManifold(x)->AmbientSize(), 3);
+  EXPECT_EQ(problem.GetManifold(x)->TangentSize(), 1);
 }
 
-TEST(Problem, SetParameterizationAndThenClearItWithNull) {
+TEST(Problem, SetManifoldAndThenClearItWithNull) {
   Problem problem;
   double x[] = {1.0, 2.0, 3.0};
   problem.AddParameterBlock(x, 3);
-  problem.SetParameterization(x, new SubsetParameterization(3, {1}));
-  EXPECT_EQ(problem.GetParameterization(x)->GlobalSize(), 3);
-  EXPECT_EQ(problem.GetParameterization(x)->LocalSize(), 2);
+  problem.SetManifold(x, new SubsetManifold(3, {1}));
+  EXPECT_EQ(problem.GetManifold(x)->AmbientSize(), 3);
+  EXPECT_EQ(problem.GetManifold(x)->TangentSize(), 2);
 
-  problem.SetParameterization(x, nullptr);
-  EXPECT_EQ(problem.GetParameterization(x), nullptr);
-  EXPECT_EQ(problem.ParameterBlockLocalSize(x), 3);
+  problem.SetManifold(x, nullptr);
+  EXPECT_EQ(problem.GetManifold(x), nullptr);
+  EXPECT_EQ(problem.ParameterBlockTangentSize(x), 3);
   EXPECT_EQ(problem.ParameterBlockSize(x), 3);
 }
 
-TEST(Solver, ZeroSizedLocalParameterizationMeansParameterBlockIsConstant) {
+TEST(Solver, ZeroTangentSizedManifoldMeansParameterBlockIsConstant) {
   double x = 0.0;
   double y = 1.0;
   Problem problem;
   problem.AddResidualBlock(new BinaryCostFunction(1, 1, 1), nullptr, &x, &y);
-  problem.SetParameterization(&y, new SubsetParameterization(1, {0}));
+  problem.SetManifold(&y, new SubsetManifold(1, {0}));
   EXPECT_TRUE(problem.IsParameterBlockConstant(&y));
 }
 
@@ -2279,5 +2309,4 @@
                                             jacobians));
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/program.cc b/third_party/ceres/internal/ceres/program.cc
index f1ded2e..a5a243d 100644
--- a/third_party/ceres/internal/ceres/program.cc
+++ b/third_party/ceres/internal/ceres/program.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -33,6 +33,7 @@
 #include <algorithm>
 #include <map>
 #include <memory>
+#include <string>
 #include <vector>
 
 #include "ceres/array_utils.h"
@@ -40,44 +41,32 @@
 #include "ceres/compressed_row_sparse_matrix.h"
 #include "ceres/cost_function.h"
 #include "ceres/evaluator.h"
-#include "ceres/internal/port.h"
-#include "ceres/local_parameterization.h"
+#include "ceres/internal/export.h"
 #include "ceres/loss_function.h"
+#include "ceres/manifold.h"
 #include "ceres/map_util.h"
+#include "ceres/parallel_for.h"
 #include "ceres/parameter_block.h"
 #include "ceres/problem.h"
 #include "ceres/residual_block.h"
 #include "ceres/stl_util.h"
 #include "ceres/triplet_sparse_matrix.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
-using std::max;
-using std::set;
-using std::string;
-using std::vector;
-
-Program::Program() {}
-
-Program::Program(const Program& program)
-    : parameter_blocks_(program.parameter_blocks_),
-      residual_blocks_(program.residual_blocks_),
-      evaluation_callback_(program.evaluation_callback_) {}
-
-const vector<ParameterBlock*>& Program::parameter_blocks() const {
+const std::vector<ParameterBlock*>& Program::parameter_blocks() const {
   return parameter_blocks_;
 }
 
-const vector<ResidualBlock*>& Program::residual_blocks() const {
+const std::vector<ResidualBlock*>& Program::residual_blocks() const {
   return residual_blocks_;
 }
 
-vector<ParameterBlock*>* Program::mutable_parameter_blocks() {
+std::vector<ParameterBlock*>* Program::mutable_parameter_blocks() {
   return &parameter_blocks_;
 }
 
-vector<ResidualBlock*>* Program::mutable_residual_blocks() {
+std::vector<ResidualBlock*>* Program::mutable_residual_blocks() {
   return &residual_blocks_;
 }
 
@@ -86,33 +75,32 @@
 }
 
 bool Program::StateVectorToParameterBlocks(const double* state) {
-  for (int i = 0; i < parameter_blocks_.size(); ++i) {
-    if (!parameter_blocks_[i]->IsConstant() &&
-        !parameter_blocks_[i]->SetState(state)) {
+  for (auto* parameter_block : parameter_blocks_) {
+    if (!parameter_block->IsConstant() && !parameter_block->SetState(state)) {
       return false;
     }
-    state += parameter_blocks_[i]->Size();
+    state += parameter_block->Size();
   }
   return true;
 }
 
 void Program::ParameterBlocksToStateVector(double* state) const {
-  for (int i = 0; i < parameter_blocks_.size(); ++i) {
-    parameter_blocks_[i]->GetState(state);
-    state += parameter_blocks_[i]->Size();
+  for (auto* parameter_block : parameter_blocks_) {
+    parameter_block->GetState(state);
+    state += parameter_block->Size();
   }
 }
 
 void Program::CopyParameterBlockStateToUserState() {
-  for (int i = 0; i < parameter_blocks_.size(); ++i) {
-    parameter_blocks_[i]->GetState(parameter_blocks_[i]->mutable_user_state());
+  for (auto* parameter_block : parameter_blocks_) {
+    parameter_block->GetState(parameter_block->mutable_user_state());
   }
 }
 
 bool Program::SetParameterBlockStatePtrsToUserStatePtrs() {
-  for (int i = 0; i < parameter_blocks_.size(); ++i) {
-    if (!parameter_blocks_[i]->IsConstant() &&
-        !parameter_blocks_[i]->SetState(parameter_blocks_[i]->user_state())) {
+  for (auto* parameter_block : parameter_blocks_) {
+    if (!parameter_block->IsConstant() &&
+        !parameter_block->SetState(parameter_block->user_state())) {
       return false;
     }
   }
@@ -121,23 +109,38 @@
 
 bool Program::Plus(const double* state,
                    const double* delta,
-                   double* state_plus_delta) const {
-  for (int i = 0; i < parameter_blocks_.size(); ++i) {
-    if (!parameter_blocks_[i]->Plus(state, delta, state_plus_delta)) {
-      return false;
-    }
-    state += parameter_blocks_[i]->Size();
-    delta += parameter_blocks_[i]->LocalSize();
-    state_plus_delta += parameter_blocks_[i]->Size();
-  }
-  return true;
+                   double* state_plus_delta,
+                   ContextImpl* context,
+                   int num_threads) const {
+  std::atomic<bool> abort(false);
+  auto* parameter_blocks = parameter_blocks_.data();
+  ParallelFor(
+      context,
+      0,
+      parameter_blocks_.size(),
+      num_threads,
+      [&abort, state, delta, state_plus_delta, parameter_blocks](int block_id) {
+        if (abort) {
+          return;
+        }
+        auto parameter_block = parameter_blocks[block_id];
+
+        auto block_state = state + parameter_block->state_offset();
+        auto block_delta = delta + parameter_block->delta_offset();
+        auto block_state_plus_delta =
+            state_plus_delta + parameter_block->state_offset();
+        if (!parameter_block->Plus(
+                block_state, block_delta, block_state_plus_delta)) {
+          abort = true;
+        }
+      });
+  return abort == false;
 }
 
 void Program::SetParameterOffsetsAndIndex() {
   // Set positions for all parameters appearing as arguments to residuals to one
   // past the end of the parameter block array.
-  for (int i = 0; i < residual_blocks_.size(); ++i) {
-    ResidualBlock* residual_block = residual_blocks_[i];
+  for (auto* residual_block : residual_blocks_) {
     for (int j = 0; j < residual_block->NumParameterBlocks(); ++j) {
       residual_block->parameter_blocks()[j]->set_index(-1);
     }
@@ -150,7 +153,7 @@
     parameter_blocks_[i]->set_state_offset(state_offset);
     parameter_blocks_[i]->set_delta_offset(delta_offset);
     state_offset += parameter_blocks_[i]->Size();
-    delta_offset += parameter_blocks_[i]->LocalSize();
+    delta_offset += parameter_blocks_[i]->TangentSize();
   }
 }
 
@@ -178,16 +181,15 @@
     }
 
     state_offset += parameter_blocks_[i]->Size();
-    delta_offset += parameter_blocks_[i]->LocalSize();
+    delta_offset += parameter_blocks_[i]->TangentSize();
   }
 
   return true;
 }
 
-bool Program::ParameterBlocksAreFinite(string* message) const {
+bool Program::ParameterBlocksAreFinite(std::string* message) const {
   CHECK(message != nullptr);
-  for (int i = 0; i < parameter_blocks_.size(); ++i) {
-    const ParameterBlock* parameter_block = parameter_blocks_[i];
+  for (auto* parameter_block : parameter_blocks_) {
     const double* array = parameter_block->user_state();
     const int size = parameter_block->Size();
     const int invalid_index = FindInvalidValue(size, array);
@@ -207,8 +209,7 @@
 }
 
 bool Program::IsBoundsConstrained() const {
-  for (int i = 0; i < parameter_blocks_.size(); ++i) {
-    const ParameterBlock* parameter_block = parameter_blocks_[i];
+  for (auto* parameter_block : parameter_blocks_) {
     if (parameter_block->IsConstant()) {
       continue;
     }
@@ -225,10 +226,9 @@
   return false;
 }
 
-bool Program::IsFeasible(string* message) const {
+bool Program::IsFeasible(std::string* message) const {
   CHECK(message != nullptr);
-  for (int i = 0; i < parameter_blocks_.size(); ++i) {
-    const ParameterBlock* parameter_block = parameter_blocks_[i];
+  for (auto* parameter_block : parameter_blocks_) {
     const double* parameters = parameter_block->user_state();
     const int size = parameter_block->Size();
     if (parameter_block->IsConstant()) {
@@ -284,42 +284,42 @@
   return true;
 }
 
-Program* Program::CreateReducedProgram(
-    vector<double*>* removed_parameter_blocks,
+std::unique_ptr<Program> Program::CreateReducedProgram(
+    std::vector<double*>* removed_parameter_blocks,
     double* fixed_cost,
-    string* error) const {
+    std::string* error) const {
   CHECK(removed_parameter_blocks != nullptr);
   CHECK(fixed_cost != nullptr);
   CHECK(error != nullptr);
 
-  std::unique_ptr<Program> reduced_program(new Program(*this));
+  std::unique_ptr<Program> reduced_program = std::make_unique<Program>(*this);
   if (!reduced_program->RemoveFixedBlocks(
           removed_parameter_blocks, fixed_cost, error)) {
     return nullptr;
   }
 
   reduced_program->SetParameterOffsetsAndIndex();
-  return reduced_program.release();
+  return reduced_program;
 }
 
-bool Program::RemoveFixedBlocks(vector<double*>* removed_parameter_blocks,
+bool Program::RemoveFixedBlocks(std::vector<double*>* removed_parameter_blocks,
                                 double* fixed_cost,
-                                string* error) {
+                                std::string* error) {
   CHECK(removed_parameter_blocks != nullptr);
   CHECK(fixed_cost != nullptr);
   CHECK(error != nullptr);
 
   std::unique_ptr<double[]> residual_block_evaluate_scratch;
-  residual_block_evaluate_scratch.reset(
-      new double[MaxScratchDoublesNeededForEvaluate()]);
+  residual_block_evaluate_scratch =
+      std::make_unique<double[]>(MaxScratchDoublesNeededForEvaluate());
   *fixed_cost = 0.0;
 
   bool need_to_call_prepare_for_evaluation = evaluation_callback_ != nullptr;
 
   // Mark all the parameters as unused. Abuse the index member of the
   // parameter blocks for the marking.
-  for (int i = 0; i < parameter_blocks_.size(); ++i) {
-    parameter_blocks_[i]->set_index(-1);
+  for (auto* parameter_block : parameter_blocks_) {
+    parameter_block->set_index(-1);
   }
 
   // Filter out residual that have all-constant parameters, and mark
@@ -391,8 +391,7 @@
   // Filter out unused or fixed parameter blocks.
   int num_active_parameter_blocks = 0;
   removed_parameter_blocks->clear();
-  for (int i = 0; i < parameter_blocks_.size(); ++i) {
-    ParameterBlock* parameter_block = parameter_blocks_[i];
+  for (auto* parameter_block : parameter_blocks_) {
     if (parameter_block->index() == -1) {
       removed_parameter_blocks->push_back(
           parameter_block->mutable_user_state());
@@ -412,7 +411,7 @@
 }
 
 bool Program::IsParameterBlockSetIndependent(
-    const set<double*>& independent_set) const {
+    const std::set<double*>& independent_set) const {
   // Loop over each residual block and ensure that no two parameter
   // blocks in the same residual block are part of
   // parameter_block_ptrs as that would violate the assumption that it
@@ -483,24 +482,24 @@
 
 int Program::NumResiduals() const {
   int num_residuals = 0;
-  for (int i = 0; i < residual_blocks_.size(); ++i) {
-    num_residuals += residual_blocks_[i]->NumResiduals();
+  for (auto* residual_block : residual_blocks_) {
+    num_residuals += residual_block->NumResiduals();
   }
   return num_residuals;
 }
 
 int Program::NumParameters() const {
   int num_parameters = 0;
-  for (int i = 0; i < parameter_blocks_.size(); ++i) {
-    num_parameters += parameter_blocks_[i]->Size();
+  for (auto* parameter_block : parameter_blocks_) {
+    num_parameters += parameter_block->Size();
   }
   return num_parameters;
 }
 
 int Program::NumEffectiveParameters() const {
   int num_parameters = 0;
-  for (int i = 0; i < parameter_blocks_.size(); ++i) {
-    num_parameters += parameter_blocks_[i]->LocalSize();
+  for (auto* parameter_block : parameter_blocks_) {
+    num_parameters += parameter_block->TangentSize();
   }
   return num_parameters;
 }
@@ -511,48 +510,47 @@
 int Program::MaxScratchDoublesNeededForEvaluate() const {
   // Compute the scratch space needed for evaluate.
   int max_scratch_bytes_for_evaluate = 0;
-  for (int i = 0; i < residual_blocks_.size(); ++i) {
+  for (auto* residual_block : residual_blocks_) {
     max_scratch_bytes_for_evaluate =
-        max(max_scratch_bytes_for_evaluate,
-            residual_blocks_[i]->NumScratchDoublesForEvaluate());
+        std::max(max_scratch_bytes_for_evaluate,
+                 residual_block->NumScratchDoublesForEvaluate());
   }
   return max_scratch_bytes_for_evaluate;
 }
 
 int Program::MaxDerivativesPerResidualBlock() const {
   int max_derivatives = 0;
-  for (int i = 0; i < residual_blocks_.size(); ++i) {
+  for (auto* residual_block : residual_blocks_) {
     int derivatives = 0;
-    ResidualBlock* residual_block = residual_blocks_[i];
     int num_parameters = residual_block->NumParameterBlocks();
     for (int j = 0; j < num_parameters; ++j) {
       derivatives += residual_block->NumResiduals() *
-                     residual_block->parameter_blocks()[j]->LocalSize();
+                     residual_block->parameter_blocks()[j]->TangentSize();
     }
-    max_derivatives = max(max_derivatives, derivatives);
+    max_derivatives = std::max(max_derivatives, derivatives);
   }
   return max_derivatives;
 }
 
 int Program::MaxParametersPerResidualBlock() const {
   int max_parameters = 0;
-  for (int i = 0; i < residual_blocks_.size(); ++i) {
+  for (auto* residual_block : residual_blocks_) {
     max_parameters =
-        max(max_parameters, residual_blocks_[i]->NumParameterBlocks());
+        std::max(max_parameters, residual_block->NumParameterBlocks());
   }
   return max_parameters;
 }
 
 int Program::MaxResidualsPerResidualBlock() const {
   int max_residuals = 0;
-  for (int i = 0; i < residual_blocks_.size(); ++i) {
-    max_residuals = max(max_residuals, residual_blocks_[i]->NumResiduals());
+  for (auto* residual_block : residual_blocks_) {
+    max_residuals = std::max(max_residuals, residual_block->NumResiduals());
   }
   return max_residuals;
 }
 
-string Program::ToString() const {
-  string ret = "Program dump\n";
+std::string Program::ToString() const {
+  std::string ret = "Program dump\n";
   ret += StringPrintf("Number of parameter blocks: %d\n", NumParameterBlocks());
   ret += StringPrintf("Number of parameters: %d\n", NumParameters());
   ret += "Parameters:\n";
@@ -563,5 +561,4 @@
   return ret;
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/program.h b/third_party/ceres/internal/ceres/program.h
index ca29d31..e2b9bd7 100644
--- a/third_party/ceres/internal/ceres/program.h
+++ b/third_party/ceres/internal/ceres/program.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -37,15 +37,16 @@
 #include <vector>
 
 #include "ceres/evaluation_callback.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 class ParameterBlock;
 class ProblemImpl;
 class ResidualBlock;
 class TripletSparseMatrix;
+class ContextImpl;
 
 // A nonlinear least squares optimization problem. This is different from the
 // similarly-named "Problem" object, which offers a mutation interface for
@@ -57,11 +58,8 @@
 // another; for example, the first stage of solving involves stripping all
 // constant parameters and residuals. This is in contrast with Problem, which is
 // not built for transformation.
-class CERES_EXPORT_INTERNAL Program {
+class CERES_NO_EXPORT Program {
  public:
-  Program();
-  explicit Program(const Program& program);
-
   // The ordered parameter and residual blocks for the program.
   const std::vector<ParameterBlock*>& parameter_blocks() const;
   const std::vector<ResidualBlock*>& residual_blocks() const;
@@ -72,9 +70,9 @@
   // Serialize to/from the program and update states.
   //
   // NOTE: Setting the state of a parameter block can trigger the
-  // computation of the Jacobian of its local parameterization. If
-  // this computation fails for some reason, then this method returns
-  // false and the state of the parameter blocks cannot be trusted.
+  // computation of the Jacobian of its manifold. If this computation fails for
+  // some reason, then this method returns false and the state of the parameter
+  // blocks cannot be trusted.
   bool StateVectorToParameterBlocks(const double* state);
   void ParameterBlocksToStateVector(double* state) const;
 
@@ -82,14 +80,16 @@
   void CopyParameterBlockStateToUserState();
 
   // Set the parameter block pointers to the user pointers. Since this
-  // runs parameter block set state internally, which may call local
-  // parameterizations, this can fail. False is returned on failure.
+  // runs parameter block set state internally, which may call manifold, this
+  // can fail. False is returned on failure.
   bool SetParameterBlockStatePtrsToUserStatePtrs();
 
   // Update a state vector for the program given a delta.
   bool Plus(const double* state,
             const double* delta,
-            double* state_plus_delta) const;
+            double* state_plus_delta,
+            ContextImpl* context,
+            int num_threads) const;
 
   // Set the parameter indices and offsets. This permits mapping backward
   // from a ParameterBlock* to an index in the parameter_blocks() vector. For
@@ -146,12 +146,13 @@
   // fixed_cost will be equal to the sum of the costs of the residual
   // blocks that were removed.
   //
-  // If there was a problem, then the function will return a NULL
+  // If there was a problem, then the function will return a nullptr
   // pointer and error will contain a human readable description of
   // the problem.
-  Program* CreateReducedProgram(std::vector<double*>* removed_parameter_blocks,
-                                double* fixed_cost,
-                                std::string* error) const;
+  std::unique_ptr<Program> CreateReducedProgram(
+      std::vector<double*>* removed_parameter_blocks,
+      double* fixed_cost,
+      std::string* error) const;
 
   // See problem.h for what these do.
   int NumParameterBlocks() const;
@@ -193,7 +194,8 @@
   friend class ProblemImpl;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_PROGRAM_H_
diff --git a/third_party/ceres/internal/ceres/program_evaluator.h b/third_party/ceres/internal/ceres/program_evaluator.h
index 36c9c64..5d549a7 100644
--- a/third_party/ceres/internal/ceres/program_evaluator.h
+++ b/third_party/ceres/internal/ceres/program_evaluator.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -43,7 +43,7 @@
 // residual jacobians are written directly into their final position in the
 // block sparse matrix by the user's CostFunction; there is no copying.
 //
-// The evaluation is threaded with OpenMP or C++ threads.
+// The evaluation is threaded with C++ threads.
 //
 // The EvaluatePreparer and JacobianWriter interfaces are as follows:
 //
@@ -59,11 +59,13 @@
 //   class JacobianWriter {
 //     // Create a jacobian that this writer can write. Same as
 //     // Evaluator::CreateJacobian.
-//     SparseMatrix* CreateJacobian() const;
+//     std::unique_ptr<SparseMatrix> CreateJacobian() const;
 //
-//     // Create num_threads evaluate preparers. Caller owns result which must
-//     // be freed with delete[]. Resulting preparers are valid while *this is.
-//     EvaluatePreparer* CreateEvaluatePreparers(int num_threads);
+//     // Create num_threads evaluate preparers.Resulting preparers are valid
+//     // while *this is.
+//
+//     std::unique_ptr<EvaluatePreparer[]> CreateEvaluatePreparers(
+//                                           int num_threads);
 //
 //     // Write the block jacobians from a residual block evaluation to the
 //     // larger sparse jacobian.
@@ -81,7 +83,7 @@
 
 // This include must come before any #ifndef check on Ceres compile options.
 // clang-format off
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 // clang-format on
 
 #include <atomic>
@@ -94,6 +96,7 @@
 #include "ceres/execution_summary.h"
 #include "ceres/internal/eigen.h"
 #include "ceres/parallel_for.h"
+#include "ceres/parallel_vector_ops.h"
 #include "ceres/parameter_block.h"
 #include "ceres/program.h"
 #include "ceres/residual_block.h"
@@ -103,36 +106,28 @@
 namespace internal {
 
 struct NullJacobianFinalizer {
-  void operator()(SparseMatrix* jacobian, int num_parameters) {}
+  void operator()(SparseMatrix* /*jacobian*/, int /*num_parameters*/) {}
 };
 
 template <typename EvaluatePreparer,
           typename JacobianWriter,
           typename JacobianFinalizer = NullJacobianFinalizer>
-class ProgramEvaluator : public Evaluator {
+class ProgramEvaluator final : public Evaluator {
  public:
   ProgramEvaluator(const Evaluator::Options& options, Program* program)
       : options_(options),
         program_(program),
         jacobian_writer_(options, program),
-        evaluate_preparers_(
-            jacobian_writer_.CreateEvaluatePreparers(options.num_threads)) {
-#ifdef CERES_NO_THREADS
-    if (options_.num_threads > 1) {
-      LOG(WARNING) << "No threading support is compiled into this binary; "
-                   << "only options.num_threads = 1 is supported. Switching "
-                   << "to single threaded mode.";
-      options_.num_threads = 1;
-    }
-#endif  // CERES_NO_THREADS
-
+        evaluate_preparers_(std::move(
+            jacobian_writer_.CreateEvaluatePreparers(options.num_threads))),
+        num_parameters_(program->NumEffectiveParameters()) {
     BuildResidualLayout(*program, &residual_layout_);
-    evaluate_scratch_.reset(
-        CreateEvaluatorScratch(*program, options.num_threads));
+    evaluate_scratch_ = std::move(CreateEvaluatorScratch(
+        *program, static_cast<unsigned>(options.num_threads)));
   }
 
   // Implementation of Evaluator interface.
-  SparseMatrix* CreateJacobian() const final {
+  std::unique_ptr<SparseMatrix> CreateJacobian() const final {
     return jacobian_writer_.CreateJacobian();
   }
 
@@ -162,20 +157,24 @@
     }
 
     if (residuals != nullptr) {
-      VectorRef(residuals, program_->NumResiduals()).setZero();
+      ParallelSetZero(options_.context,
+                      options_.num_threads,
+                      residuals,
+                      program_->NumResiduals());
     }
 
     if (jacobian != nullptr) {
-      jacobian->SetZero();
+      jacobian->SetZero(options_.context, options_.num_threads);
     }
 
     // Each thread gets it's own cost and evaluate scratch space.
     for (int i = 0; i < options_.num_threads; ++i) {
       evaluate_scratch_[i].cost = 0.0;
       if (gradient != nullptr) {
-        VectorRef(evaluate_scratch_[i].gradient.get(),
-                  program_->NumEffectiveParameters())
-            .setZero();
+        ParallelSetZero(options_.context,
+                        options_.num_threads,
+                        evaluate_scratch_[i].gradient.get(),
+                        num_parameters_);
       }
     }
 
@@ -250,45 +249,62 @@
               MatrixTransposeVectorMultiply<Eigen::Dynamic, Eigen::Dynamic, 1>(
                   block_jacobians[j],
                   num_residuals,
-                  parameter_block->LocalSize(),
+                  parameter_block->TangentSize(),
                   block_residuals,
                   scratch->gradient.get() + parameter_block->delta_offset());
             }
           }
         });
 
-    if (!abort) {
-      const int num_parameters = program_->NumEffectiveParameters();
+    if (abort) {
+      return false;
+    }
 
-      // Sum the cost and gradient (if requested) from each thread.
-      (*cost) = 0.0;
+    // Sum the cost and gradient (if requested) from each thread.
+    (*cost) = 0.0;
+    if (gradient != nullptr) {
+      auto gradient_vector = VectorRef(gradient, num_parameters_);
+      ParallelSetZero(options_.context, options_.num_threads, gradient_vector);
+    }
+
+    for (int i = 0; i < options_.num_threads; ++i) {
+      (*cost) += evaluate_scratch_[i].cost;
       if (gradient != nullptr) {
-        VectorRef(gradient, num_parameters).setZero();
-      }
-      for (int i = 0; i < options_.num_threads; ++i) {
-        (*cost) += evaluate_scratch_[i].cost;
-        if (gradient != nullptr) {
-          VectorRef(gradient, num_parameters) +=
-              VectorRef(evaluate_scratch_[i].gradient.get(), num_parameters);
-        }
-      }
-
-      // Finalize the Jacobian if it is available.
-      // `num_parameters` is passed to the finalizer so that additional
-      // storage can be reserved for additional diagonal elements if
-      // necessary.
-      if (jacobian != nullptr) {
-        JacobianFinalizer f;
-        f(jacobian, num_parameters);
+        auto gradient_vector = VectorRef(gradient, num_parameters_);
+        ParallelAssign(
+            options_.context,
+            options_.num_threads,
+            gradient_vector,
+            gradient_vector + VectorRef(evaluate_scratch_[i].gradient.get(),
+                                        num_parameters_));
       }
     }
-    return !abort;
+
+    // It is possible that after accumulation that the cost has become infinite
+    // or a nan.
+    if (!std::isfinite(*cost)) {
+      LOG(ERROR) << "Accumulated cost = " << *cost
+                 << " is not a finite number. Evaluation failed.";
+      return false;
+    }
+
+    // Finalize the Jacobian if it is available.
+    // `num_parameters` is passed to the finalizer so that additional
+    // storage can be reserved for additional diagonal elements if
+    // necessary.
+    if (jacobian != nullptr) {
+      JacobianFinalizer f;
+      f(jacobian, num_parameters_);
+    }
+
+    return true;
   }
 
   bool Plus(const double* state,
             const double* delta,
             double* state_plus_delta) const final {
-    return program_->Plus(state, delta, state_plus_delta);
+    return program_->Plus(
+        state, delta, state_plus_delta, options_.context, options_.num_threads);
   }
 
   int NumParameters() const final { return program_->NumParameters(); }
@@ -309,18 +325,19 @@
               int max_scratch_doubles_needed_for_evaluate,
               int max_residuals_per_residual_block,
               int num_parameters) {
-      residual_block_evaluate_scratch.reset(
-          new double[max_scratch_doubles_needed_for_evaluate]);
-      gradient.reset(new double[num_parameters]);
+      residual_block_evaluate_scratch =
+          std::make_unique<double[]>(max_scratch_doubles_needed_for_evaluate);
+      gradient = std::make_unique<double[]>(num_parameters);
       VectorRef(gradient.get(), num_parameters).setZero();
-      residual_block_residuals.reset(
-          new double[max_residuals_per_residual_block]);
-      jacobian_block_ptrs.reset(new double*[max_parameters_per_residual_block]);
+      residual_block_residuals =
+          std::make_unique<double[]>(max_residuals_per_residual_block);
+      jacobian_block_ptrs =
+          std::make_unique<double*[]>(max_parameters_per_residual_block);
     }
 
     double cost;
     std::unique_ptr<double[]> residual_block_evaluate_scratch;
-    // The gradient in the local parameterization.
+    // The gradient on the manifold.
     std::unique_ptr<double[]> gradient;
     // Enough space to store the residual for the largest residual block.
     std::unique_ptr<double[]> residual_block_residuals;
@@ -341,8 +358,8 @@
   }
 
   // Create scratch space for each thread evaluating the program.
-  static EvaluateScratch* CreateEvaluatorScratch(const Program& program,
-                                                 int num_threads) {
+  static std::unique_ptr<EvaluateScratch[]> CreateEvaluatorScratch(
+      const Program& program, unsigned num_threads) {
     int max_parameters_per_residual_block =
         program.MaxParametersPerResidualBlock();
     int max_scratch_doubles_needed_for_evaluate =
@@ -351,7 +368,7 @@
         program.MaxResidualsPerResidualBlock();
     int num_parameters = program.NumEffectiveParameters();
 
-    EvaluateScratch* evaluate_scratch = new EvaluateScratch[num_threads];
+    auto evaluate_scratch = std::make_unique<EvaluateScratch[]>(num_threads);
     for (int i = 0; i < num_threads; i++) {
       evaluate_scratch[i].Init(max_parameters_per_residual_block,
                                max_scratch_doubles_needed_for_evaluate,
@@ -367,6 +384,7 @@
   std::unique_ptr<EvaluatePreparer[]> evaluate_preparers_;
   std::unique_ptr<EvaluateScratch[]> evaluate_scratch_;
   std::vector<int> residual_layout_;
+  int num_parameters_;
   ::ceres::internal::ExecutionSummary execution_summary_;
 };
 
diff --git a/third_party/ceres/internal/ceres/program_test.cc b/third_party/ceres/internal/ceres/program_test.cc
index 1d9f49c..9c51ff9 100644
--- a/third_party/ceres/internal/ceres/program_test.cc
+++ b/third_party/ceres/internal/ceres/program_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -33,6 +33,7 @@
 #include <cmath>
 #include <limits>
 #include <memory>
+#include <string>
 #include <utility>
 #include <vector>
 
@@ -46,9 +47,6 @@
 namespace ceres {
 namespace internal {
 
-using std::string;
-using std::vector;
-
 // A cost function that simply returns its argument.
 class UnaryIdentityCostFunction : public SizedCostFunction<1, 1> {
  public:
@@ -70,7 +68,7 @@
   bool Evaluate(double const* const* parameters,
                 double* residuals,
                 double** jacobians) const final {
-    const int kNumParameters = Sum<std::integer_sequence<int, Ns...>>::Value;
+    constexpr int kNumParameters = (Ns + ... + 0);
 
     for (int i = 0; i < kNumResiduals; ++i) {
       residuals[i] = kNumResiduals + kNumParameters;
@@ -96,9 +94,9 @@
   problem.AddResidualBlock(new BinaryCostFunction(), nullptr, &x, &y);
   problem.AddResidualBlock(new TernaryCostFunction(), nullptr, &x, &y, &z);
 
-  vector<double*> removed_parameter_blocks;
+  std::vector<double*> removed_parameter_blocks;
   double fixed_cost = 0.0;
-  string message;
+  std::string message;
   std::unique_ptr<Program> reduced_program(
       problem.program().CreateReducedProgram(
           &removed_parameter_blocks, &fixed_cost, &message));
@@ -117,9 +115,9 @@
   problem.AddResidualBlock(new UnaryCostFunction(), nullptr, &x);
   problem.SetParameterBlockConstant(&x);
 
-  vector<double*> removed_parameter_blocks;
+  std::vector<double*> removed_parameter_blocks;
   double fixed_cost = 0.0;
-  string message;
+  std::string message;
   std::unique_ptr<Program> reduced_program(
       problem.program().CreateReducedProgram(
           &removed_parameter_blocks, &fixed_cost, &message));
@@ -141,9 +139,9 @@
   problem.AddParameterBlock(&y, 1);
   problem.AddParameterBlock(&z, 1);
 
-  vector<double*> removed_parameter_blocks;
+  std::vector<double*> removed_parameter_blocks;
   double fixed_cost = 0.0;
-  string message;
+  std::string message;
   std::unique_ptr<Program> reduced_program(
       problem.program().CreateReducedProgram(
           &removed_parameter_blocks, &fixed_cost, &message));
@@ -167,9 +165,9 @@
   problem.AddResidualBlock(new BinaryCostFunction(), nullptr, &x, &y);
   problem.SetParameterBlockConstant(&x);
 
-  vector<double*> removed_parameter_blocks;
+  std::vector<double*> removed_parameter_blocks;
   double fixed_cost = 0.0;
-  string message;
+  std::string message;
   std::unique_ptr<Program> reduced_program(
       problem.program().CreateReducedProgram(
           &removed_parameter_blocks, &fixed_cost, &message));
@@ -191,9 +189,9 @@
   problem.AddResidualBlock(new BinaryCostFunction(), nullptr, &x, &y);
   problem.SetParameterBlockConstant(&x);
 
-  vector<double*> removed_parameter_blocks;
+  std::vector<double*> removed_parameter_blocks;
   double fixed_cost = 0.0;
-  string message;
+  std::string message;
   std::unique_ptr<Program> reduced_program(
       problem.program().CreateReducedProgram(
           &removed_parameter_blocks, &fixed_cost, &message));
@@ -223,9 +221,9 @@
   expected_removed_block->Evaluate(
       true, &expected_fixed_cost, nullptr, nullptr, scratch.get());
 
-  vector<double*> removed_parameter_blocks;
+  std::vector<double*> removed_parameter_blocks;
   double fixed_cost = 0.0;
-  string message;
+  std::string message;
   std::unique_ptr<Program> reduced_program(
       problem.program().CreateReducedProgram(
           &removed_parameter_blocks, &fixed_cost, &message));
@@ -331,8 +329,6 @@
     }
   }
 
-  virtual ~NumParameterBlocksCostFunction() {}
-
   bool Evaluate(double const* const* parameters,
                 double* residuals,
                 double** jacobians) const final {
@@ -349,7 +345,7 @@
   ProblemImpl problem;
   double x[20];
 
-  vector<double*> parameter_blocks;
+  std::vector<double*> parameter_blocks;
   for (int i = 0; i < 20; ++i) {
     problem.AddParameterBlock(x + i, 1);
     parameter_blocks.push_back(x + i);
@@ -394,9 +390,9 @@
   x[0] = 1.0;
   x[1] = std::numeric_limits<double>::quiet_NaN();
   problem.AddResidualBlock(new MockCostFunctionBase<1, 2>(), nullptr, x);
-  string error;
+  std::string error;
   EXPECT_FALSE(problem.program().ParameterBlocksAreFinite(&error));
-  EXPECT_NE(error.find("has at least one invalid value"), string::npos)
+  EXPECT_NE(error.find("has at least one invalid value"), std::string::npos)
       << error;
 }
 
@@ -406,9 +402,9 @@
   problem.AddResidualBlock(new MockCostFunctionBase<1, 2>(), nullptr, x);
   problem.SetParameterLowerBound(x, 0, 2.0);
   problem.SetParameterUpperBound(x, 0, 1.0);
-  string error;
+  std::string error;
   EXPECT_FALSE(problem.program().IsFeasible(&error));
-  EXPECT_NE(error.find("infeasible bound"), string::npos) << error;
+  EXPECT_NE(error.find("infeasible bound"), std::string::npos) << error;
 }
 
 TEST(Program, InfeasibleConstantParameterBlock) {
@@ -418,9 +414,9 @@
   problem.SetParameterLowerBound(x, 0, 1.0);
   problem.SetParameterUpperBound(x, 0, 2.0);
   problem.SetParameterBlockConstant(x);
-  string error;
+  std::string error;
   EXPECT_FALSE(problem.program().IsFeasible(&error));
-  EXPECT_NE(error.find("infeasible value"), string::npos) << error;
+  EXPECT_NE(error.find("infeasible value"), std::string::npos) << error;
 }
 
 }  // namespace internal
diff --git a/third_party/ceres/internal/ceres/random.h b/third_party/ceres/internal/ceres/random.h
deleted file mode 100644
index 6b280f9..0000000
--- a/third_party/ceres/internal/ceres/random.h
+++ /dev/null
@@ -1,73 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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 Google Inc. 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.
-//
-// Author: keir@google.com (Keir Mierle)
-//         sameeragarwal@google.com (Sameer Agarwal)
-
-#ifndef CERES_INTERNAL_RANDOM_H_
-#define CERES_INTERNAL_RANDOM_H_
-
-#include <cmath>
-#include <cstdlib>
-
-#include "ceres/internal/port.h"
-
-namespace ceres {
-
-inline void SetRandomState(int state) { srand(state); }
-
-inline int Uniform(int n) {
-  if (n) {
-    return rand() % n;
-  } else {
-    return 0;
-  }
-}
-
-inline double RandDouble() {
-  double r = static_cast<double>(rand());
-  return r / RAND_MAX;
-}
-
-// Box-Muller algorithm for normal random number generation.
-// http://en.wikipedia.org/wiki/Box-Muller_transform
-inline double RandNormal() {
-  double x1, x2, w;
-  do {
-    x1 = 2.0 * RandDouble() - 1.0;
-    x2 = 2.0 * RandDouble() - 1.0;
-    w = x1 * x1 + x2 * x2;
-  } while (w >= 1.0 || w == 0.0);
-
-  w = sqrt((-2.0 * log(w)) / w);
-  return x1 * w;
-}
-
-}  // namespace ceres
-
-#endif  // CERES_INTERNAL_RANDOM_H_
diff --git a/third_party/ceres/internal/ceres/reorder_program.cc b/third_party/ceres/internal/ceres/reorder_program.cc
index 5d80236..44c4e46 100644
--- a/third_party/ceres/internal/ceres/reorder_program.cc
+++ b/third_party/ceres/internal/ceres/reorder_program.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -31,13 +31,16 @@
 #include "ceres/reorder_program.h"
 
 #include <algorithm>
+#include <map>
 #include <memory>
 #include <numeric>
+#include <set>
+#include <string>
 #include <vector>
 
 #include "Eigen/SparseCore"
-#include "ceres/cxsparse.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
+#include "ceres/internal/export.h"
 #include "ceres/ordered_groups.h"
 #include "ceres/parameter_block.h"
 #include "ceres/parameter_block_ordering.h"
@@ -50,18 +53,19 @@
 #include "ceres/types.h"
 
 #ifdef CERES_USE_EIGEN_SPARSE
+
+#ifndef CERES_NO_EIGEN_METIS
+#include <iostream>  // Need this because MetisSupport refers to std::cerr.
+
+#include "Eigen/MetisSupport"
+#endif
+
 #include "Eigen/OrderingMethods"
 #endif
 
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
-
-using std::map;
-using std::set;
-using std::string;
-using std::vector;
+namespace ceres::internal {
 
 namespace {
 
@@ -85,19 +89,18 @@
   return min_parameter_block_position;
 }
 
-#if defined(CERES_USE_EIGEN_SPARSE)
 Eigen::SparseMatrix<int> CreateBlockJacobian(
     const TripletSparseMatrix& block_jacobian_transpose) {
-  typedef Eigen::SparseMatrix<int> SparseMatrix;
-  typedef Eigen::Triplet<int> Triplet;
+  using SparseMatrix = Eigen::SparseMatrix<int>;
+  using Triplet = Eigen::Triplet<int>;
 
   const int* rows = block_jacobian_transpose.rows();
   const int* cols = block_jacobian_transpose.cols();
   int num_nonzeros = block_jacobian_transpose.num_nonzeros();
-  vector<Triplet> triplets;
+  std::vector<Triplet> triplets;
   triplets.reserve(num_nonzeros);
   for (int i = 0; i < num_nonzeros; ++i) {
-    triplets.push_back(Triplet(cols[i], rows[i], 1));
+    triplets.emplace_back(cols[i], rows[i], 1);
   }
 
   SparseMatrix block_jacobian(block_jacobian_transpose.num_cols(),
@@ -105,14 +108,20 @@
   block_jacobian.setFromTriplets(triplets.begin(), triplets.end());
   return block_jacobian;
 }
-#endif
 
 void OrderingForSparseNormalCholeskyUsingSuiteSparse(
+    const LinearSolverOrderingType linear_solver_ordering_type,
     const TripletSparseMatrix& tsm_block_jacobian_transpose,
-    const vector<ParameterBlock*>& parameter_blocks,
+    const std::vector<ParameterBlock*>& parameter_blocks,
     const ParameterBlockOrdering& parameter_block_ordering,
     int* ordering) {
 #ifdef CERES_NO_SUITESPARSE
+  // "Void"ing values to avoid compiler warnings about unused parameters
+  (void)linear_solver_ordering_type;
+  (void)tsm_block_jacobian_transpose;
+  (void)parameter_blocks;
+  (void)parameter_block_ordering;
+  (void)ordering;
   LOG(FATAL) << "Congratulations, you found a Ceres bug! "
              << "Please report this error to the developers.";
 #else
@@ -120,61 +129,47 @@
   cholmod_sparse* block_jacobian_transpose = ss.CreateSparseMatrix(
       const_cast<TripletSparseMatrix*>(&tsm_block_jacobian_transpose));
 
-  // No CAMD or the user did not supply a useful ordering, then just
-  // use regular AMD.
-  if (parameter_block_ordering.NumGroups() <= 1 ||
-      !SuiteSparse::IsConstrainedApproximateMinimumDegreeOrderingAvailable()) {
-    ss.ApproximateMinimumDegreeOrdering(block_jacobian_transpose, &ordering[0]);
-  } else {
-    vector<int> constraints;
-    for (int i = 0; i < parameter_blocks.size(); ++i) {
-      constraints.push_back(parameter_block_ordering.GroupId(
-          parameter_blocks[i]->mutable_user_state()));
+  if (linear_solver_ordering_type == ceres::AMD) {
+    if (parameter_block_ordering.NumGroups() <= 1) {
+      // The user did not supply a useful ordering so just go ahead
+      // and use AMD.
+      ss.Ordering(block_jacobian_transpose, OrderingType::AMD, ordering);
+    } else {
+      // The user supplied an ordering, so use CAMD.
+      std::vector<int> constraints;
+      constraints.reserve(parameter_blocks.size());
+      for (auto* parameter_block : parameter_blocks) {
+        constraints.push_back(parameter_block_ordering.GroupId(
+            parameter_block->mutable_user_state()));
+      }
+
+      // Renumber the entries of constraints to be contiguous integers
+      // as CAMD requires that the group ids be in the range [0,
+      // parameter_blocks.size() - 1].
+      MapValuesToContiguousRange(constraints.size(), constraints.data());
+      ss.ConstrainedApproximateMinimumDegreeOrdering(
+          block_jacobian_transpose, constraints.data(), ordering);
     }
-
-    // Renumber the entries of constraints to be contiguous integers
-    // as CAMD requires that the group ids be in the range [0,
-    // parameter_blocks.size() - 1].
-    MapValuesToContiguousRange(constraints.size(), &constraints[0]);
-    ss.ConstrainedApproximateMinimumDegreeOrdering(
-        block_jacobian_transpose, &constraints[0], ordering);
+  } else if (linear_solver_ordering_type == ceres::NESDIS) {
+    // If nested dissection is chosen as an ordering algorithm, then
+    // ignore any user provided linear_solver_ordering.
+    CHECK(SuiteSparse::IsNestedDissectionAvailable())
+        << "Congratulations, you found a Ceres bug! "
+        << "Please report this error to the developers.";
+    ss.Ordering(block_jacobian_transpose, OrderingType::NESDIS, ordering);
+  } else {
+    LOG(FATAL) << "Congratulations, you found a Ceres bug! "
+               << "Please report this error to the developers.";
   }
 
-  VLOG(2) << "Block ordering stats: "
-          << " flops: " << ss.mutable_cc()->fl
-          << " lnz  : " << ss.mutable_cc()->lnz
-          << " anz  : " << ss.mutable_cc()->anz;
-
   ss.Free(block_jacobian_transpose);
 #endif  // CERES_NO_SUITESPARSE
 }
 
-void OrderingForSparseNormalCholeskyUsingCXSparse(
-    const TripletSparseMatrix& tsm_block_jacobian_transpose, int* ordering) {
-#ifdef CERES_NO_CXSPARSE
-  LOG(FATAL) << "Congratulations, you found a Ceres bug! "
-             << "Please report this error to the developers.";
-#else
-  // CXSparse works with J'J instead of J'. So compute the block
-  // sparsity for J'J and compute an approximate minimum degree
-  // ordering.
-  CXSparse cxsparse;
-  cs_di* block_jacobian_transpose;
-  block_jacobian_transpose = cxsparse.CreateSparseMatrix(
-      const_cast<TripletSparseMatrix*>(&tsm_block_jacobian_transpose));
-  cs_di* block_jacobian = cxsparse.TransposeMatrix(block_jacobian_transpose);
-  cs_di* block_hessian =
-      cxsparse.MatrixMatrixMultiply(block_jacobian_transpose, block_jacobian);
-  cxsparse.Free(block_jacobian);
-  cxsparse.Free(block_jacobian_transpose);
-
-  cxsparse.ApproximateMinimumDegreeOrdering(block_hessian, ordering);
-  cxsparse.Free(block_hessian);
-#endif  // CERES_NO_CXSPARSE
-}
-
 void OrderingForSparseNormalCholeskyUsingEigenSparse(
-    const TripletSparseMatrix& tsm_block_jacobian_transpose, int* ordering) {
+    const LinearSolverOrderingType linear_solver_ordering_type,
+    const TripletSparseMatrix& tsm_block_jacobian_transpose,
+    int* ordering) {
 #ifndef CERES_USE_EIGEN_SPARSE
   LOG(FATAL) << "SPARSE_NORMAL_CHOLESKY cannot be used with EIGEN_SPARSE "
                 "because Ceres was not built with support for "
@@ -182,22 +177,32 @@
                 "This requires enabling building with -DEIGENSPARSE=ON.";
 #else
 
-  // This conversion from a TripletSparseMatrix to a Eigen::Triplet
-  // matrix is unfortunate, but unavoidable for now. It is not a
-  // significant performance penalty in the grand scheme of
-  // things. The right thing to do here would be to get a compressed
-  // row sparse matrix representation of the jacobian and go from
-  // there. But that is a project for another day.
-  typedef Eigen::SparseMatrix<int> SparseMatrix;
+  // TODO(sameeragarwal): This conversion from a TripletSparseMatrix
+  // to a Eigen::Triplet matrix is unfortunate, but unavoidable for
+  // now. It is not a significant performance penalty in the grand
+  // scheme of things. The right thing to do here would be to get a
+  // compressed row sparse matrix representation of the jacobian and
+  // go from there. But that is a project for another day.
+  using SparseMatrix = Eigen::SparseMatrix<int>;
 
   const SparseMatrix block_jacobian =
       CreateBlockJacobian(tsm_block_jacobian_transpose);
   const SparseMatrix block_hessian =
       block_jacobian.transpose() * block_jacobian;
 
-  Eigen::AMDOrdering<int> amd_ordering;
   Eigen::PermutationMatrix<Eigen::Dynamic, Eigen::Dynamic, int> perm;
-  amd_ordering(block_hessian, perm);
+  if (linear_solver_ordering_type == ceres::AMD) {
+    Eigen::AMDOrdering<int> amd_ordering;
+    amd_ordering(block_hessian, perm);
+  } else {
+#ifndef CERES_NO_EIGEN_METIS
+    Eigen::MetisOrdering<int> metis_ordering;
+    metis_ordering(block_hessian, perm);
+#else
+    perm.setIdentity(block_hessian.rows());
+#endif
+  }
+
   for (int i = 0; i < block_hessian.rows(); ++i) {
     ordering[i] = perm.indices()[i];
   }
@@ -209,7 +214,7 @@
 bool ApplyOrdering(const ProblemImpl::ParameterMap& parameter_map,
                    const ParameterBlockOrdering& ordering,
                    Program* program,
-                   string* error) {
+                   std::string* error) {
   const int num_parameter_blocks = program->NumParameterBlocks();
   if (ordering.NumElements() != num_parameter_blocks) {
     *error = StringPrintf(
@@ -221,13 +226,15 @@
     return false;
   }
 
-  vector<ParameterBlock*>* parameter_blocks =
+  std::vector<ParameterBlock*>* parameter_blocks =
       program->mutable_parameter_blocks();
   parameter_blocks->clear();
 
-  const map<int, set<double*>>& groups = ordering.group_to_elements();
+  // TODO(sameeragarwal): Investigate whether this should be a set or an
+  // unordered_set.
+  const std::map<int, std::set<double*>>& groups = ordering.group_to_elements();
   for (const auto& p : groups) {
-    const set<double*>& group = p.second;
+    const std::set<double*>& group = p.second;
     for (double* parameter_block_ptr : group) {
       auto it = parameter_map.find(parameter_block_ptr);
       if (it == parameter_map.end()) {
@@ -247,16 +254,18 @@
 bool LexicographicallyOrderResidualBlocks(
     const int size_of_first_elimination_group,
     Program* program,
-    string* error) {
+    std::string* /*error*/) {
   CHECK_GE(size_of_first_elimination_group, 1)
       << "Congratulations, you found a Ceres bug! Please report this error "
       << "to the developers.";
 
   // Create a histogram of the number of residuals for each E block. There is an
   // extra bucket at the end to catch all non-eliminated F blocks.
-  vector<int> residual_blocks_per_e_block(size_of_first_elimination_group + 1);
-  vector<ResidualBlock*>* residual_blocks = program->mutable_residual_blocks();
-  vector<int> min_position_per_residual(residual_blocks->size());
+  std::vector<int> residual_blocks_per_e_block(size_of_first_elimination_group +
+                                               1);
+  std::vector<ResidualBlock*>* residual_blocks =
+      program->mutable_residual_blocks();
+  std::vector<int> min_position_per_residual(residual_blocks->size());
   for (int i = 0; i < residual_blocks->size(); ++i) {
     ResidualBlock* residual_block = (*residual_blocks)[i];
     int position =
@@ -269,7 +278,7 @@
   // Run a cumulative sum on the histogram, to obtain offsets to the start of
   // each histogram bucket (where each bucket is for the residuals for that
   // E-block).
-  vector<int> offsets(size_of_first_elimination_group + 1);
+  std::vector<int> offsets(size_of_first_elimination_group + 1);
   std::partial_sum(residual_blocks_per_e_block.begin(),
                    residual_blocks_per_e_block.end(),
                    offsets.begin());
@@ -277,9 +286,9 @@
       << "Congratulations, you found a Ceres bug! Please report this error "
       << "to the developers.";
 
-  CHECK(find(residual_blocks_per_e_block.begin(),
-             residual_blocks_per_e_block.end() - 1,
-             0) != residual_blocks_per_e_block.end())
+  CHECK(std::find(residual_blocks_per_e_block.begin(),
+                  residual_blocks_per_e_block.end() - 1,
+                  0) == residual_blocks_per_e_block.end() - 1)
       << "Congratulations, you found a Ceres bug! Please report this error "
       << "to the developers.";
 
@@ -288,10 +297,10 @@
   // of the bucket. The filling order among the buckets is dictated by the
   // residual blocks. This loop uses the offsets as counters; subtracting one
   // from each offset as a residual block is placed in the bucket. When the
-  // filling is finished, the offset pointerts should have shifted down one
+  // filling is finished, the offset pointers should have shifted down one
   // entry (this is verified below).
-  vector<ResidualBlock*> reordered_residual_blocks(
-      (*residual_blocks).size(), static_cast<ResidualBlock*>(NULL));
+  std::vector<ResidualBlock*> reordered_residual_blocks(
+      (*residual_blocks).size(), static_cast<ResidualBlock*>(nullptr));
   for (int i = 0; i < residual_blocks->size(); ++i) {
     int bucket = min_position_per_residual[i];
 
@@ -299,7 +308,7 @@
     offsets[bucket]--;
 
     // Sanity.
-    CHECK(reordered_residual_blocks[offsets[bucket]] == NULL)
+    CHECK(reordered_residual_blocks[offsets[bucket]] == nullptr)
         << "Congratulations, you found a Ceres bug! Please report this error "
         << "to the developers.";
 
@@ -313,9 +322,9 @@
         << "Congratulations, you found a Ceres bug! Please report this error "
         << "to the developers.";
   }
-  // Sanity check #2: No NULL's left behind.
-  for (int i = 0; i < reordered_residual_blocks.size(); ++i) {
-    CHECK(reordered_residual_blocks[i] != NULL)
+  // Sanity check #2: No nullptr's left behind.
+  for (auto* residual_block : reordered_residual_blocks) {
+    CHECK(residual_block != nullptr)
         << "Congratulations, you found a Ceres bug! Please report this error "
         << "to the developers.";
   }
@@ -325,29 +334,29 @@
   return true;
 }
 
-// Pre-order the columns corresponding to the schur complement if
+// Pre-order the columns corresponding to the Schur complement if
 // possible.
-static void MaybeReorderSchurComplementColumnsUsingSuiteSparse(
+static void ReorderSchurComplementColumnsUsingSuiteSparse(
     const ParameterBlockOrdering& parameter_block_ordering, Program* program) {
-#ifndef CERES_NO_SUITESPARSE
+#ifdef CERES_NO_SUITESPARSE
+  // "Void"ing values to avoid compiler warnings about unused parameters
+  (void)parameter_block_ordering;
+  (void)program;
+#else
   SuiteSparse ss;
-  if (!SuiteSparse::IsConstrainedApproximateMinimumDegreeOrderingAvailable()) {
-    return;
-  }
-
-  vector<int> constraints;
-  vector<ParameterBlock*>& parameter_blocks =
+  std::vector<int> constraints;
+  std::vector<ParameterBlock*>& parameter_blocks =
       *(program->mutable_parameter_blocks());
 
-  for (int i = 0; i < parameter_blocks.size(); ++i) {
+  for (auto* parameter_block : parameter_blocks) {
     constraints.push_back(parameter_block_ordering.GroupId(
-        parameter_blocks[i]->mutable_user_state()));
+        parameter_block->mutable_user_state()));
   }
 
   // Renumber the entries of constraints to be contiguous integers as
   // CAMD requires that the group ids be in the range [0,
   // parameter_blocks.size() - 1].
-  MapValuesToContiguousRange(constraints.size(), &constraints[0]);
+  MapValuesToContiguousRange(constraints.size(), constraints.data());
 
   // Compute a block sparse presentation of J'.
   std::unique_ptr<TripletSparseMatrix> tsm_block_jacobian_transpose(
@@ -356,12 +365,12 @@
   cholmod_sparse* block_jacobian_transpose =
       ss.CreateSparseMatrix(tsm_block_jacobian_transpose.get());
 
-  vector<int> ordering(parameter_blocks.size(), 0);
+  std::vector<int> ordering(parameter_blocks.size(), 0);
   ss.ConstrainedApproximateMinimumDegreeOrdering(
-      block_jacobian_transpose, &constraints[0], &ordering[0]);
+      block_jacobian_transpose, constraints.data(), ordering.data());
   ss.Free(block_jacobian_transpose);
 
-  const vector<ParameterBlock*> parameter_blocks_copy(parameter_blocks);
+  const std::vector<ParameterBlock*> parameter_blocks_copy(parameter_blocks);
   for (int i = 0; i < program->NumParameterBlocks(); ++i) {
     parameter_blocks[i] = parameter_blocks_copy[ordering[i]];
   }
@@ -370,15 +379,15 @@
 #endif
 }
 
-static void MaybeReorderSchurComplementColumnsUsingEigen(
+static void ReorderSchurComplementColumnsUsingEigen(
+    LinearSolverOrderingType ordering_type,
     const int size_of_first_elimination_group,
-    const ProblemImpl::ParameterMap& parameter_map,
+    const ProblemImpl::ParameterMap& /*parameter_map*/,
     Program* program) {
 #if defined(CERES_USE_EIGEN_SPARSE)
   std::unique_ptr<TripletSparseMatrix> tsm_block_jacobian_transpose(
       program->CreateJacobianBlockSparsityTranspose());
-
-  typedef Eigen::SparseMatrix<int> SparseMatrix;
+  using SparseMatrix = Eigen::SparseMatrix<int>;
   const SparseMatrix block_jacobian =
       CreateBlockJacobian(*tsm_block_jacobian_transpose);
   const int num_rows = block_jacobian.rows();
@@ -398,12 +407,22 @@
   const SparseMatrix block_schur_complement =
       F.transpose() * F - F.transpose() * E * E.transpose() * F;
 
-  Eigen::AMDOrdering<int> amd_ordering;
   Eigen::PermutationMatrix<Eigen::Dynamic, Eigen::Dynamic, int> perm;
-  amd_ordering(block_schur_complement, perm);
+  if (ordering_type == ceres::AMD) {
+    Eigen::AMDOrdering<int> amd_ordering;
+    amd_ordering(block_schur_complement, perm);
+  } else {
+#ifndef CERES_NO_EIGEN_METIS
+    Eigen::MetisOrdering<int> metis_ordering;
+    metis_ordering(block_schur_complement, perm);
+#else
+    perm.setIdentity(block_schur_complement.rows());
+#endif
+  }
 
-  const vector<ParameterBlock*>& parameter_blocks = program->parameter_blocks();
-  vector<ParameterBlock*> ordering(num_cols);
+  const std::vector<ParameterBlock*>& parameter_blocks =
+      program->parameter_blocks();
+  std::vector<ParameterBlock*> ordering(num_cols);
 
   // The ordering of the first size_of_first_elimination_group does
   // not matter, so we preserve the existing ordering.
@@ -425,10 +444,11 @@
 bool ReorderProgramForSchurTypeLinearSolver(
     const LinearSolverType linear_solver_type,
     const SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type,
+    const LinearSolverOrderingType linear_solver_ordering_type,
     const ProblemImpl::ParameterMap& parameter_map,
     ParameterBlockOrdering* parameter_block_ordering,
     Program* program,
-    string* error) {
+    std::string* error) {
   if (parameter_block_ordering->NumElements() !=
       program->NumParameterBlocks()) {
     *error = StringPrintf(
@@ -441,12 +461,12 @@
 
   if (parameter_block_ordering->NumGroups() == 1) {
     // If the user supplied an parameter_block_ordering with just one
-    // group, it is equivalent to the user supplying NULL as an
+    // group, it is equivalent to the user supplying nullptr as an
     // parameter_block_ordering. Ceres is completely free to choose the
     // parameter block ordering as it sees fit. For Schur type solvers,
     // this means that the user wishes for Ceres to identify the
     // e_blocks, which we do by computing a maximal independent set.
-    vector<ParameterBlock*> schur_ordering;
+    std::vector<ParameterBlock*> schur_ordering;
     const int size_of_first_elimination_group =
         ComputeStableSchurOrdering(*program, &schur_ordering);
 
@@ -469,7 +489,10 @@
     // group.
 
     // Verify that the first elimination group is an independent set.
-    const set<double*>& first_elimination_group =
+
+    // TODO(sameeragarwal): Investigate if this should be a set or an
+    // unordered_set.
+    const std::set<double*>& first_elimination_group =
         parameter_block_ordering->group_to_elements().begin()->second;
     if (!program->IsParameterBlockSetIndependent(first_elimination_group)) {
       *error = StringPrintf(
@@ -491,12 +514,20 @@
       parameter_block_ordering->group_to_elements().begin()->second.size();
 
   if (linear_solver_type == SPARSE_SCHUR) {
-    if (sparse_linear_algebra_library_type == SUITE_SPARSE) {
-      MaybeReorderSchurComplementColumnsUsingSuiteSparse(
-          *parameter_block_ordering, program);
+    if (sparse_linear_algebra_library_type == SUITE_SPARSE &&
+        linear_solver_ordering_type == ceres::AMD) {
+      // Preordering support for schur complement only works with AMD
+      // for now, since we are using CAMD.
+      //
+      // TODO(sameeragarwal): It maybe worth adding pre-ordering support for
+      // nested dissection too.
+      ReorderSchurComplementColumnsUsingSuiteSparse(*parameter_block_ordering,
+                                                    program);
     } else if (sparse_linear_algebra_library_type == EIGEN_SPARSE) {
-      MaybeReorderSchurComplementColumnsUsingEigen(
-          size_of_first_elimination_group, parameter_map, program);
+      ReorderSchurComplementColumnsUsingEigen(linear_solver_ordering_type,
+                                              size_of_first_elimination_group,
+                                              parameter_map,
+                                              program);
     }
   }
 
@@ -508,10 +539,11 @@
 
 bool ReorderProgramForSparseCholesky(
     const SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type,
+    const LinearSolverOrderingType linear_solver_ordering_type,
     const ParameterBlockOrdering& parameter_block_ordering,
     int start_row_block,
     Program* program,
-    string* error) {
+    std::string* error) {
   if (parameter_block_ordering.NumElements() != program->NumParameterBlocks()) {
     *error = StringPrintf(
         "The program has %d parameter blocks, but the parameter block "
@@ -525,19 +557,17 @@
   std::unique_ptr<TripletSparseMatrix> tsm_block_jacobian_transpose(
       program->CreateJacobianBlockSparsityTranspose(start_row_block));
 
-  vector<int> ordering(program->NumParameterBlocks(), 0);
-  vector<ParameterBlock*>& parameter_blocks =
+  std::vector<int> ordering(program->NumParameterBlocks(), 0);
+  std::vector<ParameterBlock*>& parameter_blocks =
       *(program->mutable_parameter_blocks());
 
   if (sparse_linear_algebra_library_type == SUITE_SPARSE) {
     OrderingForSparseNormalCholeskyUsingSuiteSparse(
+        linear_solver_ordering_type,
         *tsm_block_jacobian_transpose,
         parameter_blocks,
         parameter_block_ordering,
-        &ordering[0]);
-  } else if (sparse_linear_algebra_library_type == CX_SPARSE) {
-    OrderingForSparseNormalCholeskyUsingCXSparse(*tsm_block_jacobian_transpose,
-                                                 &ordering[0]);
+        ordering.data());
   } else if (sparse_linear_algebra_library_type == ACCELERATE_SPARSE) {
     // Accelerate does not provide a function to perform reordering without
     // performing a full symbolic factorisation.  As such, we have nothing
@@ -549,11 +579,13 @@
 
   } else if (sparse_linear_algebra_library_type == EIGEN_SPARSE) {
     OrderingForSparseNormalCholeskyUsingEigenSparse(
-        *tsm_block_jacobian_transpose, &ordering[0]);
+        linear_solver_ordering_type,
+        *tsm_block_jacobian_transpose,
+        ordering.data());
   }
 
   // Apply ordering.
-  const vector<ParameterBlock*> parameter_blocks_copy(parameter_blocks);
+  const std::vector<ParameterBlock*> parameter_blocks_copy(parameter_blocks);
   for (int i = 0; i < program->NumParameterBlocks(); ++i) {
     parameter_blocks[i] = parameter_blocks_copy[ordering[i]];
   }
@@ -574,5 +606,39 @@
   return it - residual_blocks->begin();
 }
 
-}  // namespace internal
-}  // namespace ceres
+bool AreJacobianColumnsOrdered(
+    const LinearSolverType linear_solver_type,
+    const PreconditionerType preconditioner_type,
+    const SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type,
+    const LinearSolverOrderingType linear_solver_ordering_type) {
+  if (sparse_linear_algebra_library_type == SUITE_SPARSE) {
+    if (linear_solver_type == SPARSE_NORMAL_CHOLESKY ||
+        (linear_solver_type == CGNR && preconditioner_type == SUBSET)) {
+      return true;
+    }
+    if (linear_solver_type == SPARSE_SCHUR &&
+        linear_solver_ordering_type == ceres::AMD) {
+      return true;
+    }
+    return false;
+  }
+
+  if (sparse_linear_algebra_library_type == ceres::EIGEN_SPARSE) {
+    if (linear_solver_type == SPARSE_NORMAL_CHOLESKY ||
+        linear_solver_type == SPARSE_SCHUR ||
+        (linear_solver_type == CGNR && preconditioner_type == SUBSET)) {
+      return true;
+    }
+    return false;
+  }
+
+  if (sparse_linear_algebra_library_type == ceres::ACCELERATE_SPARSE) {
+    // Apple's accelerate framework does not allow direct access to
+    // ordering algorithms, so jacobian columns are never pre-ordered.
+    return false;
+  }
+
+  return false;
+}
+
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/reorder_program.h b/third_party/ceres/internal/ceres/reorder_program.h
index 2e0c326..368a6ed 100644
--- a/third_party/ceres/internal/ceres/reorder_program.h
+++ b/third_party/ceres/internal/ceres/reorder_program.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -33,18 +33,19 @@
 
 #include <string>
 
-#include "ceres/internal/port.h"
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
+#include "ceres/linear_solver.h"
 #include "ceres/parameter_block_ordering.h"
 #include "ceres/problem_impl.h"
 #include "ceres/types.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 class Program;
 
 // Reorder the parameter blocks in program using the ordering
-CERES_EXPORT_INTERNAL bool ApplyOrdering(
+CERES_NO_EXPORT bool ApplyOrdering(
     const ProblemImpl::ParameterMap& parameter_map,
     const ParameterBlockOrdering& ordering,
     Program* program,
@@ -53,7 +54,7 @@
 // Reorder the residuals for program, if necessary, so that the residuals
 // involving each E block occur together. This is a necessary condition for the
 // Schur eliminator, which works on these "row blocks" in the jacobian.
-CERES_EXPORT_INTERNAL bool LexicographicallyOrderResidualBlocks(
+CERES_NO_EXPORT bool LexicographicallyOrderResidualBlocks(
     int size_of_first_elimination_group, Program* program, std::string* error);
 
 // Schur type solvers require that all parameter blocks eliminated
@@ -72,9 +73,10 @@
 //
 // Upon return, ordering contains the parameter block ordering that
 // was used to order the program.
-CERES_EXPORT_INTERNAL bool ReorderProgramForSchurTypeLinearSolver(
+CERES_NO_EXPORT bool ReorderProgramForSchurTypeLinearSolver(
     LinearSolverType linear_solver_type,
     SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type,
+    LinearSolverOrderingType linear_solver_ordering_type,
     const ProblemImpl::ParameterMap& parameter_map,
     ParameterBlockOrdering* parameter_block_ordering,
     Program* program,
@@ -90,8 +92,9 @@
 // fill-reducing ordering is available in the sparse linear algebra
 // library (SuiteSparse version >= 4.2.0) then the fill reducing
 // ordering will take it into account, otherwise it will be ignored.
-CERES_EXPORT_INTERNAL bool ReorderProgramForSparseCholesky(
+CERES_NO_EXPORT bool ReorderProgramForSparseCholesky(
     SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type,
+    LinearSolverOrderingType linear_solver_ordering_type,
     const ParameterBlockOrdering& parameter_block_ordering,
     int start_row_block,
     Program* program,
@@ -107,11 +110,20 @@
 // bottom_residual_blocks.size() because we allow
 // bottom_residual_blocks to contain residual blocks not present in
 // the Program.
-CERES_EXPORT_INTERNAL int ReorderResidualBlocksByPartition(
+CERES_NO_EXPORT int ReorderResidualBlocksByPartition(
     const std::unordered_set<ResidualBlockId>& bottom_residual_blocks,
     Program* program);
 
-}  // namespace internal
-}  // namespace ceres
+// The return value of this function indicates whether the columns of
+// the Jacobian can be reordered using a fill reducing ordering.
+CERES_NO_EXPORT bool AreJacobianColumnsOrdered(
+    LinearSolverType linear_solver_type,
+    PreconditionerType preconditioner_type,
+    SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type,
+    LinearSolverOrderingType linear_solver_ordering_type);
 
-#endif  // CERES_INTERNAL_REORDER_PROGRAM_
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
+
+#endif  // CERES_INTERNAL_REORDER_PROGRAM_H_
diff --git a/third_party/ceres/internal/ceres/reorder_program_test.cc b/third_party/ceres/internal/ceres/reorder_program_test.cc
index 83c867a..a8db314 100644
--- a/third_party/ceres/internal/ceres/reorder_program_test.cc
+++ b/third_party/ceres/internal/ceres/reorder_program_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -31,7 +31,9 @@
 #include "ceres/reorder_program.h"
 
 #include <random>
+#include <vector>
 
+#include "ceres/internal/config.h"
 #include "ceres/parameter_block.h"
 #include "ceres/problem_impl.h"
 #include "ceres/program.h"
@@ -43,8 +45,6 @@
 namespace ceres {
 namespace internal {
 
-using std::vector;
-
 // Templated base class for the CostFunction signatures.
 template <int kNumResiduals, int... Ns>
 class MockCostFunctionBase : public SizedCostFunction<kNumResiduals, Ns...> {
@@ -78,19 +78,19 @@
   problem.AddResidualBlock(new BinaryCostFunction(), nullptr, &x, &y);
   problem.AddResidualBlock(new UnaryCostFunction(), nullptr, &y);
 
-  ParameterBlockOrdering* linear_solver_ordering = new ParameterBlockOrdering;
+  auto linear_solver_ordering = std::make_shared<ParameterBlockOrdering>();
   linear_solver_ordering->AddElementToGroup(&x, 0);
   linear_solver_ordering->AddElementToGroup(&y, 0);
   linear_solver_ordering->AddElementToGroup(&z, 1);
 
   Solver::Options options;
   options.linear_solver_type = DENSE_SCHUR;
-  options.linear_solver_ordering.reset(linear_solver_ordering);
+  options.linear_solver_ordering = linear_solver_ordering;
 
-  const vector<ResidualBlock*>& residual_blocks =
+  const std::vector<ResidualBlock*>& residual_blocks =
       problem.program().residual_blocks();
 
-  vector<ResidualBlock*> expected_residual_blocks;
+  std::vector<ResidualBlock*> expected_residual_blocks;
 
   // This is a bit fragile, but it serves the purpose. We know the
   // bucketing algorithm that the reordering function uses, so we
@@ -155,7 +155,8 @@
 
   EXPECT_TRUE(ApplyOrdering(
       problem.parameter_map(), linear_solver_ordering, program, &message));
-  const vector<ParameterBlock*>& parameter_blocks = program->parameter_blocks();
+  const std::vector<ParameterBlock*>& parameter_blocks =
+      program->parameter_blocks();
 
   EXPECT_EQ(parameter_blocks.size(), 3);
   EXPECT_EQ(parameter_blocks[0]->user_state(), &x);
@@ -164,10 +165,10 @@
 }
 
 #ifndef CERES_NO_SUITESPARSE
-class ReorderProgramFoSparseCholeskyUsingSuiteSparseTest
+class ReorderProgramForSparseCholeskyUsingSuiteSparseTest
     : public ::testing::Test {
  protected:
-  void SetUp() {
+  void SetUp() override {
     problem_.AddResidualBlock(new UnaryCostFunction(), nullptr, &x_);
     problem_.AddResidualBlock(new BinaryCostFunction(), nullptr, &z_, &x_);
     problem_.AddResidualBlock(new BinaryCostFunction(), nullptr, &z_, &y_);
@@ -179,16 +180,17 @@
   void ComputeAndValidateOrdering(
       const ParameterBlockOrdering& linear_solver_ordering) {
     Program* program = problem_.mutable_program();
-    vector<ParameterBlock*> unordered_parameter_blocks =
+    std::vector<ParameterBlock*> unordered_parameter_blocks =
         program->parameter_blocks();
 
     std::string error;
     EXPECT_TRUE(ReorderProgramForSparseCholesky(ceres::SUITE_SPARSE,
+                                                ceres::AMD,
                                                 linear_solver_ordering,
                                                 0, /* use all rows */
                                                 program,
                                                 &error));
-    const vector<ParameterBlock*>& ordered_parameter_blocks =
+    const std::vector<ParameterBlock*>& ordered_parameter_blocks =
         program->parameter_blocks();
     EXPECT_EQ(ordered_parameter_blocks.size(),
               unordered_parameter_blocks.size());
@@ -203,7 +205,7 @@
   double z_;
 };
 
-TEST_F(ReorderProgramFoSparseCholeskyUsingSuiteSparseTest,
+TEST_F(ReorderProgramForSparseCholeskyUsingSuiteSparseTest,
        EverythingInGroupZero) {
   ParameterBlockOrdering linear_solver_ordering;
   linear_solver_ordering.AddElementToGroup(&x_, 0);
@@ -213,7 +215,7 @@
   ComputeAndValidateOrdering(linear_solver_ordering);
 }
 
-TEST_F(ReorderProgramFoSparseCholeskyUsingSuiteSparseTest, ContiguousGroups) {
+TEST_F(ReorderProgramForSparseCholeskyUsingSuiteSparseTest, ContiguousGroups) {
   ParameterBlockOrdering linear_solver_ordering;
   linear_solver_ordering.AddElementToGroup(&x_, 0);
   linear_solver_ordering.AddElementToGroup(&y_, 1);
@@ -222,7 +224,7 @@
   ComputeAndValidateOrdering(linear_solver_ordering);
 }
 
-TEST_F(ReorderProgramFoSparseCholeskyUsingSuiteSparseTest, GroupsWithGaps) {
+TEST_F(ReorderProgramForSparseCholeskyUsingSuiteSparseTest, GroupsWithGaps) {
   ParameterBlockOrdering linear_solver_ordering;
   linear_solver_ordering.AddElementToGroup(&x_, 0);
   linear_solver_ordering.AddElementToGroup(&y_, 2);
@@ -231,7 +233,7 @@
   ComputeAndValidateOrdering(linear_solver_ordering);
 }
 
-TEST_F(ReorderProgramFoSparseCholeskyUsingSuiteSparseTest,
+TEST_F(ReorderProgramForSparseCholeskyUsingSuiteSparseTest,
        NonContiguousStartingAtTwo) {
   ParameterBlockOrdering linear_solver_ordering;
   linear_solver_ordering.AddElementToGroup(&x_, 2);
@@ -263,7 +265,7 @@
   problem.GetResidualBlocks(&residual_block_ids);
   std::vector<ResidualBlock*> residual_blocks =
       problem.program().residual_blocks();
-  auto rng = std::default_random_engine{};
+  auto rng = std::mt19937{};
   for (int i = 1; i < 6; ++i) {
     std::shuffle(
         std::begin(residual_block_ids), std::end(residual_block_ids), rng);
diff --git a/third_party/ceres/internal/ceres/residual_block.cc b/third_party/ceres/internal/ceres/residual_block.cc
index 067c9ef..f5ad125 100644
--- a/third_party/ceres/internal/ceres/residual_block.cc
+++ b/third_party/ceres/internal/ceres/residual_block.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -39,16 +39,15 @@
 #include "ceres/cost_function.h"
 #include "ceres/internal/eigen.h"
 #include "ceres/internal/fixed_array.h"
-#include "ceres/local_parameterization.h"
 #include "ceres/loss_function.h"
+#include "ceres/manifold.h"
 #include "ceres/parameter_block.h"
 #include "ceres/residual_block_utils.h"
 #include "ceres/small_blas.h"
 
 using Eigen::Dynamic;
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 ResidualBlock::ResidualBlock(
     const CostFunction* cost_function,
@@ -87,7 +86,7 @@
     for (int i = 0; i < num_parameter_blocks; ++i) {
       const ParameterBlock* parameter_block = parameter_blocks_[i];
       if (jacobians[i] != nullptr &&
-          parameter_block->LocalParameterizationJacobian() != nullptr) {
+          parameter_block->PlusJacobian() != nullptr) {
         global_jacobians[i] = scratch;
         scratch += num_residuals * parameter_block->Size();
       } else {
@@ -114,8 +113,7 @@
     return false;
   }
 
-  if (!IsEvaluationValid(
-          *this, parameters.data(), cost, residuals, eval_jacobians)) {
+  if (!IsEvaluationValid(*this, parameters.data(), residuals, eval_jacobians)) {
     // clang-format off
     std::string message =
         "\n\n"
@@ -132,27 +130,27 @@
 
   double squared_norm = VectorRef(residuals, num_residuals).squaredNorm();
 
-  // Update the jacobians with the local parameterizations.
+  // Update the plus_jacobian for the manifolds.
   if (jacobians != nullptr) {
     for (int i = 0; i < num_parameter_blocks; ++i) {
       if (jacobians[i] != nullptr) {
         const ParameterBlock* parameter_block = parameter_blocks_[i];
 
-        // Apply local reparameterization to the jacobians.
-        if (parameter_block->LocalParameterizationJacobian() != nullptr) {
+        // Apply the Manifold::PlusJacobian to the ambient jacobians.
+        if (parameter_block->PlusJacobian() != nullptr) {
           // jacobians[i] = global_jacobians[i] * global_to_local_jacobian.
           MatrixMatrixMultiply<Dynamic, Dynamic, Dynamic, Dynamic, 0>(
               global_jacobians[i],
               num_residuals,
               parameter_block->Size(),
-              parameter_block->LocalParameterizationJacobian(),
+              parameter_block->PlusJacobian(),
               parameter_block->Size(),
-              parameter_block->LocalSize(),
+              parameter_block->TangentSize(),
               jacobians[i],
               0,
               0,
               num_residuals,
-              parameter_block->LocalSize());
+              parameter_block->TangentSize());
         }
       }
     }
@@ -183,7 +181,7 @@
 
         // Correct the jacobians for the loss function.
         correct.CorrectJacobian(num_residuals,
-                                parameter_block->LocalSize(),
+                                parameter_block->TangentSize(),
                                 residuals,
                                 jacobians[i]);
       }
@@ -199,16 +197,16 @@
 
 int ResidualBlock::NumScratchDoublesForEvaluate() const {
   // Compute the amount of scratch space needed to store the full-sized
-  // jacobians. For parameters that have no local parameterization  no storage
-  // is needed and the passed-in jacobian array is used directly. Also include
-  // space to store the residuals, which is needed for cost-only evaluations.
-  // This is slightly pessimistic, since both won't be needed all the time, but
-  // the amount of excess should not cause problems for the caller.
+  // jacobians. For parameters that have no manifold no storage is needed and
+  // the passed-in jacobian array is used directly. Also include space to store
+  // the residuals, which is needed for cost-only evaluations.  This is slightly
+  // pessimistic, since both won't be needed all the time, but the amount of
+  // excess should not cause problems for the caller.
   int num_parameters = NumParameterBlocks();
   int scratch_doubles = 1;
   for (int i = 0; i < num_parameters; ++i) {
     const ParameterBlock* parameter_block = parameter_blocks_[i];
-    if (parameter_block->LocalParameterizationJacobian() != nullptr) {
+    if (parameter_block->PlusJacobian() != nullptr) {
       scratch_doubles += parameter_block->Size();
     }
   }
@@ -216,5 +214,4 @@
   return scratch_doubles;
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/residual_block.h b/third_party/ceres/internal/ceres/residual_block.h
index f28fd42..62460c7 100644
--- a/third_party/ceres/internal/ceres/residual_block.h
+++ b/third_party/ceres/internal/ceres/residual_block.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,7 +40,8 @@
 #include <vector>
 
 #include "ceres/cost_function.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 #include "ceres/stringprintf.h"
 #include "ceres/types.h"
 
@@ -65,7 +66,7 @@
 //
 // The residual block stores pointers to but does not own the cost functions,
 // loss functions, and parameter blocks.
-class CERES_EXPORT_INTERNAL ResidualBlock {
+class CERES_NO_EXPORT ResidualBlock {
  public:
   // Construct the residual block with the given cost/loss functions. Loss may
   // be null. The index is the index of the residual block in the Program's
@@ -77,10 +78,10 @@
 
   // Evaluates the residual term, storing the scalar cost in *cost, the residual
   // components in *residuals, and the jacobians between the parameters and
-  // residuals in jacobians[i], in row-major order. If residuals is NULL, the
-  // residuals are not computed. If jacobians is NULL, no jacobians are
-  // computed. If jacobians[i] is NULL, then the jacobian for that parameter is
-  // not computed.
+  // residuals in jacobians[i], in row-major order. If residuals is nullptr, the
+  // residuals are not computed. If jacobians is nullptr, no jacobians are
+  // computed. If jacobians[i] is nullptr, then the jacobian for that parameter
+  // is not computed.
   //
   // cost must not be null.
   //
@@ -92,10 +93,10 @@
   // false, the caller should expect the output memory locations to have
   // been modified.
   //
-  // The returned cost and jacobians have had robustification and local
-  // parameterizations applied already; for example, the jacobian for a
-  // 4-dimensional quaternion parameter using the "QuaternionParameterization"
-  // is num_residuals by 3 instead of num_residuals by 4.
+  // The returned cost and jacobians have had robustification and manifold
+  // projection applied already; for example, the jacobian for a 4-dimensional
+  // quaternion parameter using the "Quaternion" manifold is num_residuals by 3
+  // instead of num_residuals by 4.
   //
   // apply_loss_function as the name implies allows the user to switch
   // the application of the loss function on and off.
@@ -147,4 +148,6 @@
 }  // namespace internal
 }  // namespace ceres
 
+#include "ceres/internal/reenable_warnings.h"
+
 #endif  // CERES_INTERNAL_RESIDUAL_BLOCK_H_
diff --git a/third_party/ceres/internal/ceres/residual_block_test.cc b/third_party/ceres/internal/ceres/residual_block_test.cc
index 3c05f48..8040136 100644
--- a/third_party/ceres/internal/ceres/residual_block_test.cc
+++ b/third_party/ceres/internal/ceres/residual_block_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -31,17 +31,16 @@
 #include "ceres/residual_block.h"
 
 #include <cstdint>
+#include <string>
+#include <vector>
 
 #include "ceres/internal/eigen.h"
-#include "ceres/local_parameterization.h"
+#include "ceres/manifold.h"
 #include "ceres/parameter_block.h"
 #include "ceres/sized_cost_function.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
-
-using std::vector;
+namespace ceres::internal {
 
 // Trivial cost function that accepts three arguments.
 class TernaryCostFunction : public CostFunction {
@@ -64,7 +63,7 @@
     }
     if (jacobians) {
       for (int k = 0; k < 3; ++k) {
-        if (jacobians[k] != NULL) {
+        if (jacobians[k] != nullptr) {
           MatrixRef jacobian(
               jacobians[k], num_residuals(), parameter_block_sizes()[k]);
           jacobian.setConstant(k);
@@ -75,7 +74,7 @@
   }
 };
 
-TEST(ResidualBlock, EvaluteWithNoLossFunctionOrLocalParameterizations) {
+TEST(ResidualBlock, EvaluateWithNoLossFunctionOrManifolds) {
   double scratch[64];
 
   // Prepare the parameter blocks.
@@ -88,7 +87,7 @@
   double values_z[4];
   ParameterBlock z(values_z, 4, -1);
 
-  vector<ParameterBlock*> parameters;
+  std::vector<ParameterBlock*> parameters;
   parameters.push_back(&x);
   parameters.push_back(&y);
   parameters.push_back(&z);
@@ -96,11 +95,11 @@
   TernaryCostFunction cost_function(3, 2, 3, 4);
 
   // Create the object under tests.
-  ResidualBlock residual_block(&cost_function, NULL, parameters, -1);
+  ResidualBlock residual_block(&cost_function, nullptr, parameters, -1);
 
   // Verify getters.
   EXPECT_EQ(&cost_function, residual_block.cost_function());
-  EXPECT_EQ(NULL, residual_block.loss_function());
+  EXPECT_EQ(nullptr, residual_block.loss_function());
   EXPECT_EQ(parameters[0], residual_block.parameter_blocks()[0]);
   EXPECT_EQ(parameters[1], residual_block.parameter_blocks()[1]);
   EXPECT_EQ(parameters[2], residual_block.parameter_blocks()[2]);
@@ -108,12 +107,12 @@
 
   // Verify cost-only evaluation.
   double cost;
-  residual_block.Evaluate(true, &cost, NULL, NULL, scratch);
+  residual_block.Evaluate(true, &cost, nullptr, nullptr, scratch);
   EXPECT_EQ(0.5 * (0 * 0 + 1 * 1 + 2 * 2), cost);
 
   // Verify cost and residual evaluation.
   double residuals[3];
-  residual_block.Evaluate(true, &cost, residuals, NULL, scratch);
+  residual_block.Evaluate(true, &cost, residuals, nullptr, scratch);
   EXPECT_EQ(0.5 * (0 * 0 + 1 * 1 + 2 * 2), cost);
   EXPECT_EQ(0.0, residuals[0]);
   EXPECT_EQ(1.0, residuals[1]);
@@ -151,7 +150,7 @@
   jacobian_ry.setConstant(-1.0);
   jacobian_rz.setConstant(-1.0);
 
-  jacobian_ptrs[1] = NULL;  // Don't compute the jacobian for y.
+  jacobian_ptrs[1] = nullptr;  // Don't compute the jacobian for y.
 
   residual_block.Evaluate(true, &cost, residuals, jacobian_ptrs, scratch);
   EXPECT_EQ(0.5 * (0 * 0 + 1 * 1 + 2 * 2), cost);
@@ -178,16 +177,16 @@
     if (jacobians) {
       for (int k = 0; k < 3; ++k) {
         // The jacobians here are full sized, but they are transformed in the
-        // evaluator into the "local" jacobian. In the tests, the "subset
-        // constant" parameterization is used, which should pick out columns
-        // from these jacobians. Put values in the jacobian that make this
-        // obvious; in particular, make the jacobians like this:
+        // evaluator into the "local" jacobian. In the tests, the
+        // "SubsetManifold" is used, which should pick out columns from these
+        // jacobians. Put values in the jacobian that make this obvious; in
+        // particular, make the jacobians like this:
         //
         //   0 1 2 3 4 ...
         //   0 1 2 3 4 ...
         //   0 1 2 3 4 ...
         //
-        if (jacobians[k] != NULL) {
+        if (jacobians[k] != nullptr) {
           MatrixRef jacobian(
               jacobians[k], num_residuals(), parameter_block_sizes()[k]);
           for (int j = 0; j < k + 2; ++j) {
@@ -200,7 +199,7 @@
   }
 };
 
-TEST(ResidualBlock, EvaluteWithLocalParameterizations) {
+TEST(ResidualBlock, EvaluateWithManifolds) {
   double scratch[64];
 
   // Prepare the parameter blocks.
@@ -213,31 +212,31 @@
   double values_z[4];
   ParameterBlock z(values_z, 4, -1);
 
-  vector<ParameterBlock*> parameters;
+  std::vector<ParameterBlock*> parameters;
   parameters.push_back(&x);
   parameters.push_back(&y);
   parameters.push_back(&z);
 
   // Make x have the first component fixed.
-  vector<int> x_fixed;
+  std::vector<int> x_fixed;
   x_fixed.push_back(0);
-  SubsetParameterization x_parameterization(2, x_fixed);
-  x.SetParameterization(&x_parameterization);
+  SubsetManifold x_manifold(2, x_fixed);
+  x.SetManifold(&x_manifold);
 
   // Make z have the last and last component fixed.
-  vector<int> z_fixed;
+  std::vector<int> z_fixed;
   z_fixed.push_back(2);
-  SubsetParameterization z_parameterization(4, z_fixed);
-  z.SetParameterization(&z_parameterization);
+  SubsetManifold z_manifold(4, z_fixed);
+  z.SetManifold(&z_manifold);
 
   LocallyParameterizedCostFunction cost_function;
 
   // Create the object under tests.
-  ResidualBlock residual_block(&cost_function, NULL, parameters, -1);
+  ResidualBlock residual_block(&cost_function, nullptr, parameters, -1);
 
   // Verify getters.
   EXPECT_EQ(&cost_function, residual_block.cost_function());
-  EXPECT_EQ(NULL, residual_block.loss_function());
+  EXPECT_EQ(nullptr, residual_block.loss_function());
   EXPECT_EQ(parameters[0], residual_block.parameter_blocks()[0]);
   EXPECT_EQ(parameters[1], residual_block.parameter_blocks()[1]);
   EXPECT_EQ(parameters[2], residual_block.parameter_blocks()[2]);
@@ -245,12 +244,12 @@
 
   // Verify cost-only evaluation.
   double cost;
-  residual_block.Evaluate(true, &cost, NULL, NULL, scratch);
+  residual_block.Evaluate(true, &cost, nullptr, nullptr, scratch);
   EXPECT_EQ(0.5 * (0 * 0 + 1 * 1 + 2 * 2), cost);
 
   // Verify cost and residual evaluation.
   double residuals[3];
-  residual_block.Evaluate(true, &cost, residuals, NULL, scratch);
+  residual_block.Evaluate(true, &cost, residuals, nullptr, scratch);
   EXPECT_EQ(0.5 * (0 * 0 + 1 * 1 + 2 * 2), cost);
   EXPECT_EQ(0.0, residuals[0]);
   EXPECT_EQ(1.0, residuals[1]);
@@ -311,7 +310,7 @@
   jacobian_ry.setConstant(-1.0);
   jacobian_rz.setConstant(-1.0);
 
-  jacobian_ptrs[1] = NULL;  // Don't compute the jacobian for y.
+  jacobian_ptrs[1] = nullptr;  // Don't compute the jacobian for y.
 
   residual_block.Evaluate(true, &cost, residuals, jacobian_ptrs, scratch);
   EXPECT_EQ(0.5 * (0 * 0 + 1 * 1 + 2 * 2), cost);
@@ -324,5 +323,4 @@
   EXPECT_EQ(expected_jacobian_rz, jacobian_rz);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/residual_block_utils.cc b/third_party/ceres/internal/ceres/residual_block_utils.cc
index d5b3fa1..91370d8 100644
--- a/third_party/ceres/internal/ceres/residual_block_utils.cc
+++ b/third_party/ceres/internal/ceres/residual_block_utils.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -33,19 +33,17 @@
 #include <cmath>
 #include <cstddef>
 #include <limits>
+#include <string>
 
 #include "ceres/array_utils.h"
 #include "ceres/internal/eigen.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 #include "ceres/parameter_block.h"
 #include "ceres/residual_block.h"
 #include "ceres/stringprintf.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
-
-using std::string;
+namespace ceres::internal {
 
 void InvalidateEvaluation(const ResidualBlock& block,
                           double* cost,
@@ -56,7 +54,7 @@
 
   InvalidateArray(1, cost);
   InvalidateArray(num_residuals, residuals);
-  if (jacobians != NULL) {
+  if (jacobians != nullptr) {
     for (int i = 0; i < num_parameter_blocks; ++i) {
       const int parameter_block_size = block.parameter_blocks()[i]->Size();
       InvalidateArray(num_residuals * parameter_block_size, jacobians[i]);
@@ -64,17 +62,17 @@
   }
 }
 
-string EvaluationToString(const ResidualBlock& block,
-                          double const* const* parameters,
-                          double* cost,
-                          double* residuals,
-                          double** jacobians) {
+std::string EvaluationToString(const ResidualBlock& block,
+                               double const* const* parameters,
+                               double* cost,
+                               double* residuals,
+                               double** jacobians) {
   CHECK(cost != nullptr);
   CHECK(residuals != nullptr);
 
   const int num_parameter_blocks = block.NumParameterBlocks();
   const int num_residuals = block.NumResiduals();
-  string result = "";
+  std::string result = "";
 
   // clang-format off
   StringAppendF(&result,
@@ -89,7 +87,7 @@
       "to Inf or NaN is also an error.  \n\n"; // NOLINT
   // clang-format on
 
-  string space = "Residuals:     ";
+  std::string space = "Residuals:     ";
   result += space;
   AppendArrayToString(num_residuals, residuals, &result);
   StringAppendF(&result, "\n\n");
@@ -104,9 +102,9 @@
       StringAppendF(&result, "| ");
       for (int k = 0; k < num_residuals; ++k) {
         AppendArrayToString(1,
-                            (jacobians != NULL && jacobians[i] != NULL)
+                            (jacobians != nullptr && jacobians[i] != nullptr)
                                 ? jacobians[i] + k * parameter_block_size + j
-                                : NULL,
+                                : nullptr,
                             &result);
       }
       StringAppendF(&result, "\n");
@@ -117,9 +115,11 @@
   return result;
 }
 
+// TODO(sameeragarwal) Check cost value validness here
+// Cost value is a part of evaluation but not checked here since according to
+// residual_block.cc cost is not valid at the time this method is called
 bool IsEvaluationValid(const ResidualBlock& block,
-                       double const* const* parameters,
-                       double* cost,
+                       double const* const* /*parameters*/,
                        double* residuals,
                        double** jacobians) {
   const int num_parameter_blocks = block.NumParameterBlocks();
@@ -129,7 +129,7 @@
     return false;
   }
 
-  if (jacobians != NULL) {
+  if (jacobians != nullptr) {
     for (int i = 0; i < num_parameter_blocks; ++i) {
       const int parameter_block_size = block.parameter_blocks()[i]->Size();
       if (!IsArrayValid(num_residuals * parameter_block_size, jacobians[i])) {
@@ -141,5 +141,4 @@
   return true;
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/residual_block_utils.h b/third_party/ceres/internal/ceres/residual_block_utils.h
index 41ae81a..1bf1ca1 100644
--- a/third_party/ceres/internal/ceres/residual_block_utils.h
+++ b/third_party/ceres/internal/ceres/residual_block_utils.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -45,14 +45,14 @@
 
 #include <string>
 
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 class ResidualBlock;
 
-// Invalidate cost, resdual and jacobian arrays (if not NULL).
+// Invalidate cost, resdual and jacobian arrays (if not nullptr).
+CERES_NO_EXPORT
 void InvalidateEvaluation(const ResidualBlock& block,
                           double* cost,
                           double* residuals,
@@ -60,22 +60,22 @@
 
 // Check if any of the arrays cost, residuals or jacobians contains an
 // NaN, return true if it does.
+CERES_NO_EXPORT
 bool IsEvaluationValid(const ResidualBlock& block,
                        double const* const* parameters,
-                       double* cost,
                        double* residuals,
                        double** jacobians);
 
 // Create a string representation of the Residual block containing the
 // value of the parameters, residuals and jacobians if present.
 // Useful for debugging output.
+CERES_NO_EXPORT
 std::string EvaluationToString(const ResidualBlock& block,
                                double const* const* parameters,
                                double* cost,
                                double* residuals,
                                double** jacobians);
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_INTERNAL_RESIDUAL_BLOCK_UTILS_H_
diff --git a/third_party/ceres/internal/ceres/residual_block_utils_test.cc b/third_party/ceres/internal/ceres/residual_block_utils_test.cc
index 331f5ab..6fc8aa0 100644
--- a/third_party/ceres/internal/ceres/residual_block_utils_test.cc
+++ b/third_party/ceres/internal/ceres/residual_block_utils_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -51,7 +51,7 @@
   std::vector<ParameterBlock*> parameter_blocks;
   parameter_blocks.push_back(&parameter_block);
 
-  ResidualBlock residual_block(&cost_function, NULL, parameter_blocks, -1);
+  ResidualBlock residual_block(&cost_function, nullptr, parameter_blocks, -1);
 
   std::unique_ptr<double[]> scratch(
       new double[residual_block.NumScratchDoublesForEvaluate()]);
@@ -66,7 +66,7 @@
             is_good);
 }
 
-// A CostFunction that behaves normaly, i.e., it computes numerically
+// A CostFunction that behaves normally, i.e., it computes numerically
 // valid residuals and jacobians.
 class GoodCostFunction : public SizedCostFunction<1, 1> {
  public:
@@ -74,7 +74,7 @@
                 double* residuals,
                 double** jacobians) const final {
     residuals[0] = 1;
-    if (jacobians != NULL && jacobians[0] != NULL) {
+    if (jacobians != nullptr && jacobians[0] != nullptr) {
       jacobians[0][0] = 0.0;
     }
     return true;
@@ -90,7 +90,7 @@
                 double** jacobians) const final {
     // Forget to update the residuals.
     // residuals[0] = 1;
-    if (jacobians != NULL && jacobians[0] != NULL) {
+    if (jacobians != nullptr && jacobians[0] != nullptr) {
       jacobians[0][0] = 0.0;
     }
     return true;
@@ -103,7 +103,7 @@
                 double* residuals,
                 double** jacobians) const final {
     residuals[0] = 1;
-    if (jacobians != NULL && jacobians[0] != NULL) {
+    if (jacobians != nullptr && jacobians[0] != nullptr) {
       // Forget to update the jacobians.
       // jacobians[0][0] = 0.0;
     }
@@ -117,7 +117,7 @@
                 double* residuals,
                 double** jacobians) const final {
     residuals[0] = std::numeric_limits<double>::infinity();
-    if (jacobians != NULL && jacobians[0] != NULL) {
+    if (jacobians != nullptr && jacobians[0] != nullptr) {
       jacobians[0][0] = 0.0;
     }
     return true;
@@ -130,7 +130,7 @@
                 double* residuals,
                 double** jacobians) const final {
     residuals[0] = 1.0;
-    if (jacobians != NULL && jacobians[0] != NULL) {
+    if (jacobians != nullptr && jacobians[0] != nullptr) {
       jacobians[0][0] = std::numeric_limits<double>::quiet_NaN();
     }
     return true;
diff --git a/third_party/ceres/internal/ceres/rotation_test.cc b/third_party/ceres/internal/ceres/rotation_test.cc
index c2f5e83..f1ea071 100644
--- a/third_party/ceres/internal/ceres/rotation_test.cc
+++ b/third_party/ceres/internal/ceres/rotation_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -30,12 +30,18 @@
 
 #include "ceres/rotation.h"
 
+#include <algorithm>
+#include <array>
 #include <cmath>
 #include <limits>
+#include <random>
 #include <string>
+#include <utility>
 
+#include "ceres/constants.h"
 #include "ceres/internal/eigen.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/euler_angles.h"
+#include "ceres/internal/export.h"
 #include "ceres/is_close.h"
 #include "ceres/jet.h"
 #include "ceres/stringprintf.h"
@@ -47,22 +53,11 @@
 namespace ceres {
 namespace internal {
 
-using std::max;
-using std::min;
-using std::numeric_limits;
-using std::string;
-using std::swap;
-
-const double kPi = 3.14159265358979323846;
+inline constexpr double kPi = constants::pi;
 const double kHalfSqrt2 = 0.707106781186547524401;
 
-static double RandDouble() {
-  double r = rand();
-  return r / RAND_MAX;
-}
-
 // A tolerance value for floating-point comparisons.
-static double const kTolerance = numeric_limits<double>::epsilon() * 10;
+static double const kTolerance = std::numeric_limits<double>::epsilon() * 10;
 
 // Looser tolerance used for numerically unstable conversions.
 static double const kLooseTolerance = 1e-9;
@@ -88,27 +83,29 @@
 MATCHER_P(IsNearQuaternion, expected, "") {
   // Quaternions are equivalent upto a sign change. So we will compare
   // both signs before declaring failure.
-  bool near = true;
+  bool is_near = true;
+  // NOTE: near (and far) can be defined as macros on the Windows platform (for
+  // ancient pascal calling convention). Do not use these identifiers.
   for (int i = 0; i < 4; i++) {
     if (fabs(arg[i] - expected[i]) > kTolerance) {
-      near = false;
+      is_near = false;
       break;
     }
   }
 
-  if (near) {
+  if (is_near) {
     return true;
   }
 
-  near = true;
+  is_near = true;
   for (int i = 0; i < 4; i++) {
     if (fabs(arg[i] + expected[i]) > kTolerance) {
-      near = false;
+      is_near = false;
       break;
     }
   }
 
-  if (near) {
+  if (is_near) {
     return true;
   }
 
@@ -136,12 +133,12 @@
   Eigen::Vector3d e(expected[0], expected[1], expected[2]);
   const double e_norm = e.norm();
 
-  double delta_norm = numeric_limits<double>::max();
+  double delta_norm = std::numeric_limits<double>::max();
   if (e_norm > 0) {
     // Deal with the sign ambiguity near PI. Since the sign can flip,
     // we take the smaller of the two differences.
     if (fabs(e_norm - kPi) < kLooseTolerance) {
-      delta_norm = min((a - e).norm(), (a + e).norm()) / e_norm;
+      delta_norm = std::min((a - e).norm(), (a + e).norm()) / e_norm;
     } else {
       delta_norm = (a - e).norm() / e_norm;
     }
@@ -229,7 +226,7 @@
 // Test that approximate conversion works for very small angles.
 TEST(Rotation, TinyAngleAxisToQuaternion) {
   // Very small value that could potentially cause underflow.
-  double theta = pow(numeric_limits<double>::min(), 0.75);
+  double theta = pow(std::numeric_limits<double>::min(), 0.75);
   double axis_angle[3] = {theta, 0, 0};
   double quaternion[4];
   double expected[4] = {cos(theta / 2), sin(theta / 2.0), 0, 0};
@@ -290,7 +287,7 @@
 // Test that approximate conversion works for very small angles.
 TEST(Rotation, TinyQuaternionToAngleAxis) {
   // Very small value that could potentially cause underflow.
-  double theta = pow(numeric_limits<double>::min(), 0.75);
+  double theta = pow(std::numeric_limits<double>::min(), 0.75);
   double quaternion[4] = {cos(theta / 2), sin(theta / 2.0), 0, 0};
   double axis_angle[3];
   double expected[3] = {theta, 0, 0};
@@ -309,9 +306,7 @@
   quaternion[2] = 0.0;
   quaternion[3] = 0.0;
   QuaternionToAngleAxis(quaternion, angle_axis);
-  const double angle =
-      sqrt(angle_axis[0] * angle_axis[0] + angle_axis[1] * angle_axis[1] +
-           angle_axis[2] * angle_axis[2]);
+  const double angle = std::hypot(angle_axis[0], angle_axis[1], angle_axis[2]);
   EXPECT_LE(angle, kPi);
 }
 
@@ -320,22 +315,24 @@
 // Takes a bunch of random axis/angle values, converts them to quaternions,
 // and back again.
 TEST(Rotation, AngleAxisToQuaterionAndBack) {
-  srand(5);
+  std::mt19937 prng;
+  std::uniform_real_distribution<double> uniform_distribution{-1.0, 1.0};
   for (int i = 0; i < kNumTrials; i++) {
     double axis_angle[3];
     // Make an axis by choosing three random numbers in [-1, 1) and
     // normalizing.
     double norm = 0;
-    for (int i = 0; i < 3; i++) {
-      axis_angle[i] = RandDouble() * 2 - 1;
-      norm += axis_angle[i] * axis_angle[i];
+    for (double& coeff : axis_angle) {
+      coeff = uniform_distribution(prng);
+      norm += coeff * coeff;
     }
     norm = sqrt(norm);
 
     // Angle in [-pi, pi).
-    double theta = kPi * 2 * RandDouble() - kPi;
-    for (int i = 0; i < 3; i++) {
-      axis_angle[i] = axis_angle[i] * theta / norm;
+    double theta = uniform_distribution(
+        prng, std::uniform_real_distribution<double>::param_type{-kPi, kPi});
+    for (double& coeff : axis_angle) {
+      coeff = coeff * theta / norm;
     }
 
     double quaternion[4];
@@ -353,19 +350,20 @@
 // Takes a bunch of random quaternions, converts them to axis/angle,
 // and back again.
 TEST(Rotation, QuaterionToAngleAxisAndBack) {
-  srand(5);
+  std::mt19937 prng;
+  std::uniform_real_distribution<double> uniform_distribution{-1.0, 1.0};
   for (int i = 0; i < kNumTrials; i++) {
     double quaternion[4];
     // Choose four random numbers in [-1, 1) and normalize.
     double norm = 0;
-    for (int i = 0; i < 4; i++) {
-      quaternion[i] = RandDouble() * 2 - 1;
-      norm += quaternion[i] * quaternion[i];
+    for (double& coeff : quaternion) {
+      coeff = uniform_distribution(prng);
+      norm += coeff * coeff;
     }
     norm = sqrt(norm);
 
-    for (int i = 0; i < 4; i++) {
-      quaternion[i] = quaternion[i] / norm;
+    for (double& coeff : quaternion) {
+      coeff = coeff / norm;
     }
 
     double axis_angle[3];
@@ -430,23 +428,27 @@
   double matrix[9];
   double out_axis_angle[3];
 
-  srand(5);
+  std::mt19937 prng;
+  std::uniform_real_distribution<double> uniform_distribution{-1.0, 1.0};
   for (int i = 0; i < kNumTrials; i++) {
     // Make an axis by choosing three random numbers in [-1, 1) and
     // normalizing.
     double norm = 0;
-    for (int i = 0; i < 3; i++) {
-      in_axis_angle[i] = RandDouble() * 2 - 1;
-      norm += in_axis_angle[i] * in_axis_angle[i];
+    for (double& coeff : in_axis_angle) {
+      coeff = uniform_distribution(prng);
+      norm += coeff * coeff;
     }
     norm = sqrt(norm);
 
     // Angle in [pi - kMaxSmallAngle, pi).
-    const double kMaxSmallAngle = 1e-8;
-    double theta = kPi - kMaxSmallAngle * RandDouble();
+    constexpr double kMaxSmallAngle = 1e-8;
+    double theta =
+        uniform_distribution(prng,
+                             std::uniform_real_distribution<double>::param_type{
+                                 kPi - kMaxSmallAngle, kPi});
 
-    for (int i = 0; i < 3; i++) {
-      in_axis_angle[i] *= (theta / norm);
+    for (double& coeff : in_axis_angle) {
+      coeff *= (theta / norm);
     }
     AngleAxisToRotationMatrix(in_axis_angle, matrix);
     RotationMatrixToAngleAxis(matrix, out_axis_angle);
@@ -491,7 +493,7 @@
   LOG(INFO) << "Rotation:";
   LOG(INFO) << "EXPECTED        |        ACTUAL";
   for (int i = 0; i < 3; ++i) {
-    string line;
+    std::string line;
     for (int j = 0; j < 3; ++j) {
       StringAppendF(&line, "%g ", kMatrix[i][j]);
     }
@@ -529,22 +531,24 @@
 // Takes a bunch of random axis/angle values, converts them to rotation
 // matrices, and back again.
 TEST(Rotation, AngleAxisToRotationMatrixAndBack) {
-  srand(5);
+  std::mt19937 prng;
+  std::uniform_real_distribution<double> uniform_distribution{-1.0, 1.0};
   for (int i = 0; i < kNumTrials; i++) {
     double axis_angle[3];
     // Make an axis by choosing three random numbers in [-1, 1) and
     // normalizing.
     double norm = 0;
-    for (int i = 0; i < 3; i++) {
-      axis_angle[i] = RandDouble() * 2 - 1;
-      norm += axis_angle[i] * axis_angle[i];
+    for (double& i : axis_angle) {
+      i = uniform_distribution(prng);
+      norm += i * i;
     }
     norm = sqrt(norm);
 
     // Angle in [-pi, pi).
-    double theta = kPi * 2 * RandDouble() - kPi;
-    for (int i = 0; i < 3; i++) {
-      axis_angle[i] = axis_angle[i] * theta / norm;
+    double theta = uniform_distribution(
+        prng, std::uniform_real_distribution<double>::param_type{-kPi, kPi});
+    for (double& i : axis_angle) {
+      i = i * theta / norm;
     }
 
     double matrix[9];
@@ -562,22 +566,27 @@
 // Takes a bunch of random axis/angle values near zero, converts them
 // to rotation matrices, and back again.
 TEST(Rotation, AngleAxisToRotationMatrixAndBackNearZero) {
-  srand(5);
+  std::mt19937 prng;
+  std::uniform_real_distribution<double> uniform_distribution{-1.0, 1.0};
   for (int i = 0; i < kNumTrials; i++) {
     double axis_angle[3];
     // Make an axis by choosing three random numbers in [-1, 1) and
     // normalizing.
     double norm = 0;
-    for (int i = 0; i < 3; i++) {
-      axis_angle[i] = RandDouble() * 2 - 1;
-      norm += axis_angle[i] * axis_angle[i];
+    for (double& i : axis_angle) {
+      i = uniform_distribution(prng);
+      norm += i * i;
     }
     norm = sqrt(norm);
 
     // Tiny theta.
-    double theta = 1e-16 * (kPi * 2 * RandDouble() - kPi);
-    for (int i = 0; i < 3; i++) {
-      axis_angle[i] = axis_angle[i] * theta / norm;
+    constexpr double kScale = 1e-16;
+    double theta =
+        uniform_distribution(prng,
+                             std::uniform_real_distribution<double>::param_type{
+                                 -kScale * kPi, kScale * kPi});
+    for (double& i : axis_angle) {
+      i = i * theta / norm;
     }
 
     double matrix[9];
@@ -588,16 +597,16 @@
 
     for (int i = 0; i < 3; ++i) {
       EXPECT_NEAR(
-          round_trip[i], axis_angle[i], numeric_limits<double>::epsilon());
+          round_trip[i], axis_angle[i], std::numeric_limits<double>::epsilon());
     }
   }
 }
 
 // Transposes a 3x3 matrix.
 static void Transpose3x3(double m[9]) {
-  swap(m[1], m[3]);
-  swap(m[2], m[6]);
-  swap(m[5], m[7]);
+  std::swap(m[1], m[3]);
+  std::swap(m[2], m[6]);
+  std::swap(m[5], m[7]);
 }
 
 // Convert Euler angles from radians to degrees.
@@ -645,11 +654,12 @@
 // Test that a random rotation produces an orthonormal rotation
 // matrix.
 TEST(EulerAnglesToRotationMatrix, IsOrthonormal) {
-  srand(5);
+  std::mt19937 prng;
+  std::uniform_real_distribution<double> uniform_distribution{-180.0, 180.0};
   for (int trial = 0; trial < kNumTrials; ++trial) {
     double euler_angles_degrees[3];
-    for (int i = 0; i < 3; ++i) {
-      euler_angles_degrees[i] = RandDouble() * 360.0 - 180.0;
+    for (double& euler_angles_degree : euler_angles_degrees) {
+      euler_angles_degree = uniform_distribution(prng);
     }
     double rotation_matrix[9];
     EulerAnglesToRotationMatrix(euler_angles_degrees, 3, rotation_matrix);
@@ -657,14 +667,271 @@
   }
 }
 
+static double sample_euler[][3] = {{0.5235988, 1.047198, 0.7853982},
+                                   {0.5235988, 1.047198, 0.5235988},
+                                   {0.7853982, 0.5235988, 1.047198}};
+
+// ZXY Intrinsic Euler Angle to rotation matrix conversion test from
+// scipy/spatial/transform/test/test_rotation.py
+TEST(EulerAngles, IntrinsicEulerSequence312ToRotationMatrixCanned) {
+  // clang-format off
+  double const expected[][9] =
+      {{0.306186083320088, -0.249999816228639,  0.918558748402491,
+        0.883883627842492,  0.433012359189203, -0.176776777947208,
+       -0.353553128699351,  0.866025628186053,  0.353553102817459},
+      { 0.533493553519713, -0.249999816228639,  0.808012821828067,
+        0.808012821828067,  0.433012359189203, -0.399519181705765,
+       -0.249999816228639,  0.866025628186053,  0.433012359189203},
+      { 0.047366781483451, -0.612372449482883,  0.789149143778432,
+        0.659739427618959,  0.612372404654096,  0.435596057905909,
+       -0.750000183771249,  0.500000021132493,  0.433012359189203}};
+  // clang-format on
+
+  for (int i = 0; i < 3; ++i) {
+    double results[9];
+    EulerAnglesToRotation<IntrinsicZXY>(sample_euler[i], results);
+    ASSERT_THAT(results, IsNear3x3Matrix(expected[i]));
+  }
+}
+
+// ZXY Extrinsic Euler Angle to rotation matrix conversion test from
+// scipy/spatial/transform/test/test_rotation.py
+TEST(EulerAngles, ExtrinsicEulerSequence312ToRotationMatrix) {
+  // clang-format off
+  double const expected[][9] =
+      {{0.918558725988105,  0.176776842651999,  0.353553128699352,
+        0.249999816228639,  0.433012359189203, -0.866025628186053,
+       -0.306186150563275,  0.883883614901527,  0.353553102817459},
+      { 0.966506404215301, -0.058012606358071,  0.249999816228639,
+        0.249999816228639,  0.433012359189203, -0.866025628186053,
+       -0.058012606358071,  0.899519223970752,  0.433012359189203},
+      { 0.659739424151467, -0.047366829779744,  0.750000183771249,
+        0.612372449482883,  0.612372404654096, -0.500000021132493,
+       -0.435596000136163,  0.789149175666285,  0.433012359189203}};
+  // clang-format on
+
+  for (int i = 0; i < 3; ++i) {
+    double results[9];
+    EulerAnglesToRotation<ExtrinsicZXY>(sample_euler[i], results);
+    ASSERT_THAT(results, IsNear3x3Matrix(expected[i]));
+  }
+}
+
+// ZXZ Intrinsic Euler Angle to rotation matrix conversion test from
+// scipy/spatial/transform/test/test_rotation.py
+TEST(EulerAngles, IntrinsicEulerSequence313ToRotationMatrix) {
+  // clang-format off
+  double expected[][9] =
+      {{0.435595832832961, -0.789149008363071,  0.433012832394307,
+        0.659739379322704, -0.047367454164077, -0.750000183771249,
+        0.612372616786097,  0.612372571957297,  0.499999611324802},
+      { 0.625000065470068, -0.649518902838302,  0.433012832394307,
+        0.649518902838302,  0.124999676794869, -0.750000183771249,
+        0.433012832394307,  0.750000183771249,  0.499999611324802},
+      {-0.176777132429787, -0.918558558684756,  0.353553418477159,
+        0.883883325123719, -0.306186652473014, -0.353553392595246,
+        0.433012832394307,  0.249999816228639,  0.866025391583588}};
+  // clang-format on
+  for (int i = 0; i < 3; ++i) {
+    double results[9];
+    EulerAnglesToRotation<IntrinsicZXZ>(sample_euler[i], results);
+    ASSERT_THAT(results, IsNear3x3Matrix(expected[i]));
+  }
+}
+
+// ZXZ Extrinsic Euler Angle to rotation matrix conversion test from
+// scipy/spatial/transform/test/test_rotation.py
+TEST(EulerAngles, ExtrinsicEulerSequence313ToRotationMatrix) {
+  // clang-format off
+  double expected[][9] =
+      {{0.435595832832961, -0.659739379322704,  0.612372616786097,
+        0.789149008363071, -0.047367454164077, -0.612372571957297,
+        0.433012832394307,  0.750000183771249,  0.499999611324802},
+      { 0.625000065470068, -0.649518902838302,  0.433012832394307,
+        0.649518902838302,  0.124999676794869, -0.750000183771249,
+        0.433012832394307,  0.750000183771249,  0.499999611324802},
+      {-0.176777132429787, -0.883883325123719,  0.433012832394307,
+        0.918558558684756, -0.306186652473014, -0.249999816228639,
+        0.353553418477159,  0.353553392595246,  0.866025391583588}};
+  // clang-format on
+  for (int i = 0; i < 3; ++i) {
+    double results[9];
+    EulerAnglesToRotation<ExtrinsicZXZ>(sample_euler[i], results);
+    ASSERT_THAT(results, IsNear3x3Matrix(expected[i]));
+  }
+}
+
+template <typename T>
+struct GeneralEulerAngles : public ::testing::Test {
+ public:
+  static constexpr bool kIsParityOdd = T::kIsParityOdd;
+  static constexpr bool kIsProperEuler = T::kIsProperEuler;
+  static constexpr bool kIsIntrinsic = T::kIsIntrinsic;
+
+  template <typename URBG>
+  static void RandomEulerAngles(double* euler, URBG& prng) {
+    using ParamType = std::uniform_real_distribution<double>::param_type;
+    std::uniform_real_distribution<double> uniform_distribution{-kPi, kPi};
+    // Euler angles should be in
+    //   [-pi,pi) x [0,pi) x [-pi,pi])
+    // if the outer axes are repeated and
+    //   [-pi,pi) x [-pi/2,pi/2) x [-pi,pi])
+    // otherwise
+    euler[0] = uniform_distribution(prng);
+    euler[2] = uniform_distribution(prng);
+    if constexpr (kIsProperEuler) {
+      euler[1] = uniform_distribution(prng, ParamType{0, kPi});
+    } else {
+      euler[1] = uniform_distribution(prng, ParamType{-kPi / 2, kPi / 2});
+    }
+  }
+
+  static void CheckPrincipalRotationMatrixProduct(double angles[3]) {
+    // Convert Shoemake's Euler angle convention into 'apparent' rotation axes
+    // sequences, i.e. the alphabetic code (ZYX, ZYZ, etc.) indicates in what
+    // sequence rotations about different axes are applied
+    constexpr int i = T::kAxes[0];
+    constexpr int j = (3 + (kIsParityOdd ? (i - 1) % 3 : (i + 1) % 3)) % 3;
+    constexpr int k = kIsProperEuler ? i : 3 ^ i ^ j;
+    constexpr auto kSeq =
+        kIsIntrinsic ? std::array{k, j, i} : std::array{i, j, k};
+
+    double aa_matrix[9];
+    Eigen::Map<Eigen::Matrix3d, 0, Eigen::Stride<1, 3>> aa(aa_matrix);
+    aa.setIdentity();
+    for (int i = 0; i < 3; ++i) {
+      Eigen::Vector3d angle_axis;
+      if constexpr (kIsIntrinsic) {
+        angle_axis = -angles[i] * Eigen::Vector3d::Unit(kSeq[i]);
+      } else {
+        angle_axis = angles[i] * Eigen::Vector3d::Unit(kSeq[i]);
+      }
+      Eigen::Matrix3d m;
+      AngleAxisToRotationMatrix(angle_axis.data(), m.data());
+      aa = m * aa;
+    }
+    if constexpr (kIsIntrinsic) {
+      aa.transposeInPlace();
+    }
+
+    double ea_matrix[9];
+    EulerAnglesToRotation<T>(angles, ea_matrix);
+
+    EXPECT_THAT(aa_matrix, IsOrthonormal());
+    EXPECT_THAT(ea_matrix, IsOrthonormal());
+    EXPECT_THAT(ea_matrix, IsNear3x3Matrix(aa_matrix));
+  }
+};
+
+using EulerSystemList = ::testing::Types<ExtrinsicXYZ,
+                                         ExtrinsicXYX,
+                                         ExtrinsicXZY,
+                                         ExtrinsicXZX,
+                                         ExtrinsicYZX,
+                                         ExtrinsicYZY,
+                                         ExtrinsicYXZ,
+                                         ExtrinsicYXY,
+                                         ExtrinsicZXY,
+                                         ExtrinsicZXZ,
+                                         ExtrinsicZYX,
+                                         ExtrinsicZYZ,
+                                         IntrinsicZYX,
+                                         IntrinsicXYX,
+                                         IntrinsicYZX,
+                                         IntrinsicXZX,
+                                         IntrinsicXZY,
+                                         IntrinsicYZY,
+                                         IntrinsicZXY,
+                                         IntrinsicYXY,
+                                         IntrinsicYXZ,
+                                         IntrinsicZXZ,
+                                         IntrinsicXYZ,
+                                         IntrinsicZYZ>;
+TYPED_TEST_SUITE(GeneralEulerAngles, EulerSystemList);
+
+TYPED_TEST(GeneralEulerAngles, EulerAnglesToRotationMatrixAndBack) {
+  std::mt19937 prng;
+  std::uniform_real_distribution<double> uniform_distribution{-1.0, 1.0};
+  for (int i = 0; i < kNumTrials; ++i) {
+    double euler[3];
+    TestFixture::RandomEulerAngles(euler, prng);
+
+    double matrix[9];
+    double round_trip[3];
+    EulerAnglesToRotation<TypeParam>(euler, matrix);
+    ASSERT_THAT(matrix, IsOrthonormal());
+    RotationMatrixToEulerAngles<TypeParam>(matrix, round_trip);
+    for (int j = 0; j < 3; ++j)
+      ASSERT_NEAR(euler[j], round_trip[j], 128.0 * kLooseTolerance);
+  }
+}
+
+// Check that the rotation matrix converted from euler angles is equivalent to
+// product of three principal axis rotation matrices
+//     R_euler = R_a2(euler_2) * R_a1(euler_1) * R_a0(euler_0)
+TYPED_TEST(GeneralEulerAngles, PrincipalRotationMatrixProduct) {
+  std::mt19937 prng;
+  double euler[3];
+  for (int i = 0; i < kNumTrials; ++i) {
+    TestFixture::RandomEulerAngles(euler, prng);
+    TestFixture::CheckPrincipalRotationMatrixProduct(euler);
+  }
+}
+
+// Gimbal lock (euler[1] == +/-pi) handling test. If a rotation matrix
+// represents a gimbal-locked configuration, then converting this rotation
+// matrix to euler angles and back must produce the same rotation matrix.
+//
+// From scipy/spatial/transform/test/test_rotation.py, but additionally covers
+// gimbal lock handling for proper euler angles, which scipy appears to fail to
+// do properly.
+TYPED_TEST(GeneralEulerAngles, GimbalLocked) {
+  constexpr auto kBoundaryAngles = TestFixture::kIsProperEuler
+                                       ? std::array{0.0, kPi}
+                                       : std::array{-kPi / 2, kPi / 2};
+  constexpr double gimbal_locked_configurations[4][3] = {
+      {0.78539816, kBoundaryAngles[1], 0.61086524},
+      {0.61086524, kBoundaryAngles[0], 0.34906585},
+      {0.61086524, kBoundaryAngles[1], 0.43633231},
+      {0.43633231, kBoundaryAngles[0], 0.26179939}};
+  double angle_estimates[3];
+  double mat_expected[9];
+  double mat_estimated[9];
+  for (const auto& euler_angles : gimbal_locked_configurations) {
+    EulerAnglesToRotation<TypeParam>(euler_angles, mat_expected);
+    RotationMatrixToEulerAngles<TypeParam>(mat_expected, angle_estimates);
+    EulerAnglesToRotation<TypeParam>(angle_estimates, mat_estimated);
+    ASSERT_THAT(mat_expected, IsNear3x3Matrix(mat_estimated));
+  }
+}
+
 // Tests using Jets for specific behavior involving auto differentiation
 // near singularity points.
 
-typedef Jet<double, 3> J3;
-typedef Jet<double, 4> J4;
+using J3 = Jet<double, 3>;
+using J4 = Jet<double, 4>;
 
 namespace {
 
+// Converts an array of N real numbers (doubles) to an array of jets
+template <int N>
+void ArrayToArrayOfJets(double const* const src, Jet<double, N>* dst) {
+  for (int i = 0; i < N; ++i) {
+    dst[i] = Jet<double, N>(src[i], i);
+  }
+}
+
+// Generically initializes a Jet with type T and a N-dimensional dual part
+// N is explicitly given (instead of inferred from sizeof...(Ts)) so that the
+// dual part can be initialized from Eigen expressions
+template <int N, typename T, typename... Ts>
+Jet<T, N> MakeJet(T a, const T& v0, Ts&&... v) {
+  Jet<T, N> j;
+  j.a = a;                                  // Real part
+  ((j.v << v0), ..., std::forward<Ts>(v));  // Fill dual part with N components
+  return j;
+}
+
 J3 MakeJ3(double a, double v0, double v1, double v2) {
   J3 j;
   j.a = a;
@@ -684,52 +951,57 @@
   return j;
 }
 
-bool IsClose(double x, double y) {
-  EXPECT_FALSE(IsNaN(x));
-  EXPECT_FALSE(IsNaN(y));
-  return internal::IsClose(x, y, kTolerance, NULL, NULL);
-}
-
 }  // namespace
 
-template <int N>
-bool IsClose(const Jet<double, N>& x, const Jet<double, N>& y) {
-  if (!IsClose(x.a, y.a)) {
+// Use EXPECT_THAT(x, testing::PointWise(JetClose(prec), y); to achieve Jet
+// array comparison
+MATCHER_P(JetClose, relative_precision, "") {
+  using internal::IsClose;
+  using LHSJetType = std::remove_reference_t<std::tuple_element_t<0, arg_type>>;
+  using RHSJetType = std::remove_reference_t<std::tuple_element_t<1, arg_type>>;
+
+  constexpr int kDualPartDimension = LHSJetType::DIMENSION;
+  static_assert(
+      kDualPartDimension == RHSJetType::DIMENSION,
+      "Can only compare Jets with dual parts having equal dimensions");
+  auto&& [x, y] = arg;
+  double relative_error;
+  double absolute_error;
+  if (!IsClose(
+          x.a, y.a, relative_precision, &relative_error, &absolute_error)) {
+    *result_listener << "Real part mismatch: x.a = " << x.a
+                     << " and y.a = " << y.a
+                     << " where the relative error between them is "
+                     << relative_error
+                     << " and the absolute error between them is "
+                     << absolute_error;
     return false;
   }
-  for (int i = 0; i < N; i++) {
-    if (!IsClose(x.v[i], y.v[i])) {
+  for (int i = 0; i < kDualPartDimension; i++) {
+    if (!IsClose(x.v[i],
+                 y.v[i],
+                 relative_precision,
+                 &relative_error,
+                 &absolute_error)) {
+      *result_listener << "Dual part mismatch: x.v[" << i << "] = " << x.v[i]
+                       << " and y.v[" << i << "] = " << y.v[i]
+                       << " where the relative error between them is "
+                       << relative_error
+                       << " and the absolute error between them is "
+                       << absolute_error;
       return false;
     }
   }
   return true;
 }
 
-template <int M, int N>
-void ExpectJetArraysClose(const Jet<double, N>* x, const Jet<double, N>* y) {
-  for (int i = 0; i < M; i++) {
-    if (!IsClose(x[i], y[i])) {
-      LOG(ERROR) << "Jet " << i << "/" << M << " not equal";
-      LOG(ERROR) << "x[" << i << "]: " << x[i];
-      LOG(ERROR) << "y[" << i << "]: " << y[i];
-      Jet<double, N> d, zero;
-      d.a = y[i].a - x[i].a;
-      for (int j = 0; j < N; j++) {
-        d.v[j] = y[i].v[j] - x[i].v[j];
-      }
-      LOG(ERROR) << "diff: " << d;
-      EXPECT_TRUE(IsClose(x[i], y[i]));
-    }
-  }
-}
-
 // Log-10 of a value well below machine precision.
-static const int kSmallTinyCutoff =
-    static_cast<int>(2 * log(numeric_limits<double>::epsilon()) / log(10.0));
+static const int kSmallTinyCutoff = static_cast<int>(
+    2 * log(std::numeric_limits<double>::epsilon()) / log(10.0));
 
 // Log-10 of a value just below values representable by double.
 static const int kTinyZeroLimit =
-    static_cast<int>(1 + log(numeric_limits<double>::min()) / log(10.0));
+    static_cast<int>(1 + log(std::numeric_limits<double>::min()) / log(10.0));
 
 // Test that exact conversion works for small angles when jets are used.
 TEST(Rotation, SmallAngleAxisToQuaternionForJets) {
@@ -746,7 +1018,7 @@
         MakeJ3(0, 0, 0, sin(theta / 2) / theta),
     };
     AngleAxisToQuaternion(axis_angle, quaternion);
-    ExpectJetArraysClose<4, 3>(quaternion, expected);
+    EXPECT_THAT(quaternion, testing::Pointwise(JetClose(kTolerance), expected));
   }
 }
 
@@ -768,7 +1040,7 @@
         MakeJ3(0, 0, 0, 0.5),
     };
     AngleAxisToQuaternion(axis_angle, quaternion);
-    ExpectJetArraysClose<4, 3>(quaternion, expected);
+    EXPECT_THAT(quaternion, testing::Pointwise(JetClose(kTolerance), expected));
   }
 }
 
@@ -783,7 +1055,7 @@
       MakeJ3(0, 0, 0, 0.5),
   };
   AngleAxisToQuaternion(axis_angle, quaternion);
-  ExpectJetArraysClose<4, 3>(quaternion, expected);
+  EXPECT_THAT(quaternion, testing::Pointwise(JetClose(kTolerance), expected));
 }
 
 // Test that exact conversion works for small angles.
@@ -804,7 +1076,7 @@
     };
     // clang-format on
     QuaternionToAngleAxis(quaternion, axis_angle);
-    ExpectJetArraysClose<3, 4>(axis_angle, expected);
+    EXPECT_THAT(axis_angle, testing::Pointwise(JetClose(kTolerance), expected));
   }
 }
 
@@ -829,7 +1101,7 @@
     };
     // clang-format on
     QuaternionToAngleAxis(quaternion, axis_angle);
-    ExpectJetArraysClose<3, 4>(axis_angle, expected);
+    EXPECT_THAT(axis_angle, testing::Pointwise(JetClose(kTolerance), expected));
   }
 }
 
@@ -843,7 +1115,508 @@
       MakeJ4(0, 0, 0, 0, 2.0),
   };
   QuaternionToAngleAxis(quaternion, axis_angle);
-  ExpectJetArraysClose<3, 4>(axis_angle, expected);
+  EXPECT_THAT(axis_angle, testing::Pointwise(JetClose(kTolerance), expected));
+}
+
+// The following 4 test cases cover the conversion of Euler Angles to rotation
+// matrices for Jets
+//
+// The dual parts (with dimension 3) of the resultant matrix of Jets contain the
+// derivative of each matrix element w.r.t. the input Euler Angles. In other
+// words, for each element in R = EulerAnglesToRotationMatrix(angles), we have
+// R_ij.v = jacobian(R_ij, angles)
+//
+// The test data (dual parts of the Jets) is generated by analytically
+// differentiating the formulas for Euler Angle to Rotation Matrix conversion
+
+// Test ZXY/312 Intrinsic Euler Angles to rotation matrix conversion using Jets
+// The two ZXY test cases specifically cover handling of Tait-Bryan angles
+// i.e. last axis of rotation is different from the first
+TEST(EulerAngles, Intrinsic312EulerSequenceToRotationMatrixForJets) {
+  J3 euler_angles[3];
+  J3 rotation_matrix[9];
+
+  ArrayToArrayOfJets(sample_euler[0], euler_angles);
+  EulerAnglesToRotation<IntrinsicZXY>(euler_angles, rotation_matrix);
+  {
+    // clang-format off
+    const J3 expected[] = {
+      MakeJ3( 0.306186083320, -0.883883627842, -0.176776571821, -0.918558748402),  // NOLINT
+      MakeJ3(-0.249999816229, -0.433012359189,  0.433012832394,  0.000000000000),  // NOLINT
+      MakeJ3( 0.918558748402,  0.176776777947,  0.176776558880,  0.306186083320),  // NOLINT
+      MakeJ3( 0.883883627842,  0.306186083320,  0.306185986727,  0.176776777947),  // NOLINT
+      MakeJ3( 0.433012359189, -0.249999816229, -0.750000183771,  0.000000000000),  // NOLINT
+      MakeJ3(-0.176776777947,  0.918558748402, -0.306185964313,  0.883883627842),  // NOLINT
+      MakeJ3(-0.353553128699,  0.000000000000,  0.612372616786, -0.353553102817),  // NOLINT
+      MakeJ3( 0.866025628186,  0.000000000000,  0.499999611325,  0.000000000000),  // NOLINT
+      MakeJ3( 0.353553102817,  0.000000000000, -0.612372571957, -0.353553128699)   // NOLINT
+    };
+    // clang-format on
+    EXPECT_THAT(rotation_matrix,
+                testing::Pointwise(JetClose(kLooseTolerance), expected));
+  }
+
+  ArrayToArrayOfJets(sample_euler[1], euler_angles);
+  EulerAnglesToRotation<IntrinsicZXY>(euler_angles, rotation_matrix);
+  {
+    // clang-format off
+    const J3 expected[] = {
+      MakeJ3( 0.533493553520, -0.808012821828, -0.124999913397, -0.808012821828),  // NOLINT
+      MakeJ3(-0.249999816229, -0.433012359189,  0.433012832394,  0.000000000000),  // NOLINT
+      MakeJ3( 0.808012821828,  0.399519181706,  0.216506188745,  0.533493553520),  // NOLINT
+      MakeJ3( 0.808012821828,  0.533493553520,  0.216506188745,  0.399519181706),  // NOLINT
+      MakeJ3( 0.433012359189, -0.249999816229, -0.750000183771,  0.000000000000),  // NOLINT
+      MakeJ3(-0.399519181706,  0.808012821828, -0.374999697927,  0.808012821828),  // NOLINT
+      MakeJ3(-0.249999816229,  0.000000000000,  0.433012832394, -0.433012359189),  // NOLINT
+      MakeJ3( 0.866025628186,  0.000000000000,  0.499999611325,  0.000000000000),  // NOLINT
+      MakeJ3( 0.433012359189,  0.000000000000, -0.750000183771, -0.249999816229)   // NOLINT
+    };
+    // clang-format on
+    EXPECT_THAT(rotation_matrix,
+                testing::Pointwise(JetClose(kLooseTolerance), expected));
+  }
+
+  ArrayToArrayOfJets(sample_euler[2], euler_angles);
+  EulerAnglesToRotation<IntrinsicZXY>(euler_angles, rotation_matrix);
+  {
+    // clang-format off
+    const J3 expected[] = {
+      MakeJ3( 0.047366781483, -0.659739427619, -0.530330235247, -0.789149143778),  // NOLINT
+      MakeJ3(-0.612372449483, -0.612372404654,  0.353553418477,  0.000000000000),  // NOLINT
+      MakeJ3( 0.789149143778, -0.435596057906,  0.306185986727,  0.047366781483),  // NOLINT
+      MakeJ3( 0.659739427619,  0.047366781483,  0.530330196424, -0.435596057906),  // NOLINT
+      MakeJ3( 0.612372404654, -0.612372449483, -0.353553392595,  0.000000000000),  // NOLINT
+      MakeJ3( 0.435596057906,  0.789149143778, -0.306185964313,  0.659739427619),  // NOLINT
+      MakeJ3(-0.750000183771,  0.000000000000,  0.433012832394, -0.433012359189),  // NOLINT
+      MakeJ3( 0.500000021132,  0.000000000000,  0.866025391584,  0.000000000000),  // NOLINT
+      MakeJ3( 0.433012359189,  0.000000000000, -0.249999816229, -0.750000183771)   // NOLINT
+    };
+    // clang-format on
+    EXPECT_THAT(rotation_matrix,
+                testing::Pointwise(JetClose(kLooseTolerance), expected));
+  }
+}
+
+// Test ZXY/312 Extrinsic Euler Angles to rotation matrix conversion using Jets
+TEST(EulerAngles, Extrinsic312EulerSequenceToRotationMatrixForJets) {
+  J3 euler_angles[3];
+  J3 rotation_matrix[9];
+
+  ArrayToArrayOfJets(sample_euler[0], euler_angles);
+  EulerAnglesToRotation<ExtrinsicZXY>(euler_angles, rotation_matrix);
+  {
+    // clang-format off
+    const J3 expected[] = {
+      MakeJ3( 0.918558725988,  0.176776842652,  0.176776571821, -0.306186150563),  // NOLINT
+      MakeJ3( 0.176776842652, -0.918558725988,  0.306185986727,  0.883883614902),  // NOLINT
+      MakeJ3( 0.353553128699,  0.000000000000, -0.612372616786,  0.353553102817),  // NOLINT
+      MakeJ3( 0.249999816229,  0.433012359189, -0.433012832394,  0.000000000000),  // NOLINT
+      MakeJ3( 0.433012359189, -0.249999816229, -0.750000183771,  0.000000000000),  // NOLINT
+      MakeJ3(-0.866025628186,  0.000000000000, -0.499999611325,  0.000000000000),  // NOLINT
+      MakeJ3(-0.306186150563,  0.883883614902,  0.176776558880, -0.918558725988),  // NOLINT
+      MakeJ3( 0.883883614902,  0.306186150563,  0.306185964313, -0.176776842652),  // NOLINT
+      MakeJ3( 0.353553102817,  0.000000000000, -0.612372571957, -0.353553128699)   // NOLINT
+    };
+    // clang-format on
+    EXPECT_THAT(rotation_matrix,
+                testing::Pointwise(JetClose(kLooseTolerance), expected));
+  }
+
+  ArrayToArrayOfJets(sample_euler[1], euler_angles);
+  EulerAnglesToRotation<ExtrinsicZXY>(euler_angles, rotation_matrix);
+  {
+    // clang-format off
+    const J3 expected[] = {
+      MakeJ3( 0.966506404215, -0.058012606358,  0.124999913397, -0.058012606358),  // NOLINT
+      MakeJ3(-0.058012606358, -0.966506404215,  0.216506188745,  0.899519223971),  // NOLINT
+      MakeJ3( 0.249999816229,  0.000000000000, -0.433012832394,  0.433012359189),  // NOLINT
+      MakeJ3( 0.249999816229,  0.433012359189, -0.433012832394,  0.000000000000),  // NOLINT
+      MakeJ3( 0.433012359189, -0.249999816229, -0.750000183771,  0.000000000000),  // NOLINT
+      MakeJ3(-0.866025628186,  0.000000000000, -0.499999611325,  0.000000000000),  // NOLINT
+      MakeJ3(-0.058012606358,  0.899519223971,  0.216506188745, -0.966506404215),  // NOLINT
+      MakeJ3( 0.899519223971,  0.058012606358,  0.374999697927,  0.058012606358),  // NOLINT
+      MakeJ3( 0.433012359189,  0.000000000000, -0.750000183771, -0.249999816229)   // NOLINT
+    };
+    // clang-format on
+    EXPECT_THAT(rotation_matrix,
+                testing::Pointwise(JetClose(kLooseTolerance), expected));
+  }
+
+  ArrayToArrayOfJets(sample_euler[2], euler_angles);
+  EulerAnglesToRotation<ExtrinsicZXY>(euler_angles, rotation_matrix);
+  {
+    // clang-format off
+    const J3 expected[] = {
+      MakeJ3( 0.659739424151, -0.047366829780,  0.530330235247, -0.435596000136),  // NOLINT
+      MakeJ3(-0.047366829780, -0.659739424151,  0.530330196424,  0.789149175666),  // NOLINT
+      MakeJ3( 0.750000183771,  0.000000000000, -0.433012832394,  0.433012359189),  // NOLINT
+      MakeJ3( 0.612372449483,  0.612372404654, -0.353553418477,  0.000000000000),  // NOLINT
+      MakeJ3( 0.612372404654, -0.612372449483, -0.353553392595,  0.000000000000),  // NOLINT
+      MakeJ3(-0.500000021132,  0.000000000000, -0.866025391584,  0.000000000000),  // NOLINT
+      MakeJ3(-0.435596000136,  0.789149175666,  0.306185986727, -0.659739424151),  // NOLINT
+      MakeJ3( 0.789149175666,  0.435596000136,  0.306185964313,  0.047366829780),  // NOLINT
+      MakeJ3( 0.433012359189,  0.000000000000, -0.249999816229, -0.750000183771)   // NOLINT
+    };
+    // clang-format on
+    EXPECT_THAT(rotation_matrix,
+                testing::Pointwise(JetClose(kLooseTolerance), expected));
+  }
+}
+
+// Test ZXZ/313 Intrinsic Euler Angles to rotation matrix conversion using Jets
+// The two ZXZ test cases specifically cover handling of proper Euler Sequences
+// i.e. last axis of rotation is same as the first
+TEST(EulerAngles, Intrinsic313EulerSequenceToRotationMatrixForJets) {
+  J3 euler_angles[3];
+  J3 rotation_matrix[9];
+
+  ArrayToArrayOfJets(sample_euler[0], euler_angles);
+  EulerAnglesToRotation<IntrinsicZXZ>(euler_angles, rotation_matrix);
+  {
+    // clang-format off
+    const J3 expected[] = {
+      MakeJ3( 0.435595832833, -0.659739379323,  0.306186321334, -0.789149008363),  // NOLINT
+      MakeJ3(-0.789149008363,  0.047367454164,  0.306186298920, -0.435595832833),  // NOLINT
+      MakeJ3( 0.433012832394,  0.750000183771,  0.249999816229,  0.000000000000),  // NOLINT
+      MakeJ3( 0.659739379323,  0.435595832833, -0.530330235247, -0.047367454164),  // NOLINT
+      MakeJ3(-0.047367454164, -0.789149008363, -0.530330196424, -0.659739379323),  // NOLINT
+      MakeJ3(-0.750000183771,  0.433012832394, -0.433012359189,  0.000000000000),  // NOLINT
+      MakeJ3( 0.612372616786,  0.000000000000,  0.353553128699,  0.612372571957),  // NOLINT
+      MakeJ3( 0.612372571957,  0.000000000000,  0.353553102817, -0.612372616786),  // NOLINT
+      MakeJ3( 0.499999611325,  0.000000000000, -0.866025628186,  0.000000000000)   // NOLINT
+    };
+    // clang-format on
+    EXPECT_THAT(rotation_matrix,
+                testing::Pointwise(JetClose(kLooseTolerance), expected));
+  }
+
+  ArrayToArrayOfJets(sample_euler[1], euler_angles);
+  EulerAnglesToRotation<IntrinsicZXZ>(euler_angles, rotation_matrix);
+  {
+    // clang-format off
+    const J3 expected[] = {
+      MakeJ3( 0.625000065470, -0.649518902838,  0.216506425348, -0.649518902838),  // NOLINT
+      MakeJ3(-0.649518902838, -0.124999676795,  0.375000107735, -0.625000065470),  // NOLINT
+      MakeJ3( 0.433012832394,  0.750000183771,  0.249999816229,  0.000000000000),  // NOLINT
+      MakeJ3( 0.649518902838,  0.625000065470, -0.375000107735,  0.124999676795),  // NOLINT
+      MakeJ3( 0.124999676795, -0.649518902838, -0.649519202838, -0.649518902838),  // NOLINT
+      MakeJ3(-0.750000183771,  0.433012832394, -0.433012359189,  0.000000000000),  // NOLINT
+      MakeJ3( 0.433012832394,  0.000000000000,  0.249999816229,  0.750000183771),  // NOLINT
+      MakeJ3( 0.750000183771,  0.000000000000,  0.433012359189, -0.433012832394),  // NOLINT
+      MakeJ3( 0.499999611325,  0.000000000000, -0.866025628186,  0.000000000000)   // NOLINT
+    };
+    // clang-format on
+    EXPECT_THAT(rotation_matrix,
+                testing::Pointwise(JetClose(kLooseTolerance), expected));
+  }
+
+  ArrayToArrayOfJets(sample_euler[2], euler_angles);
+  EulerAnglesToRotation<IntrinsicZXZ>(euler_angles, rotation_matrix);
+  {
+    // clang-format off
+    const J3 expected[] = {
+      MakeJ3(-0.176777132430, -0.883883325124,  0.306186321334, -0.918558558685),  // NOLINT
+      MakeJ3(-0.918558558685,  0.306186652473,  0.176776571821,  0.176777132430),  // NOLINT
+      MakeJ3( 0.353553418477,  0.353553392595,  0.612372449483,  0.000000000000),  // NOLINT
+      MakeJ3( 0.883883325124, -0.176777132430, -0.306186298920, -0.306186652473),  // NOLINT
+      MakeJ3(-0.306186652473, -0.918558558685, -0.176776558880, -0.883883325124),  // NOLINT
+      MakeJ3(-0.353553392595,  0.353553418477, -0.612372404654,  0.000000000000),  // NOLINT
+      MakeJ3( 0.433012832394,  0.000000000000,  0.750000183771,  0.249999816229),  // NOLINT
+      MakeJ3( 0.249999816229,  0.000000000000,  0.433012359189, -0.433012832394),  // NOLINT
+      MakeJ3( 0.866025391584,  0.000000000000, -0.500000021132,  0.000000000000)   // NOLINT
+    };
+    // clang-format on
+    EXPECT_THAT(rotation_matrix,
+                testing::Pointwise(JetClose(kLooseTolerance), expected));
+  }
+}
+
+// Test ZXZ/313 Extrinsic Euler Angles to rotation matrix conversion using Jets
+TEST(EulerAngles, Extrinsic313EulerSequenceToRotationMatrixForJets) {
+  J3 euler_angles[3];
+  J3 rotation_matrix[9];
+
+  ArrayToArrayOfJets(sample_euler[0], euler_angles);
+  EulerAnglesToRotation<ExtrinsicZXZ>(euler_angles, rotation_matrix);
+  {
+    // clang-format off
+    const J3 expected[] = {
+      MakeJ3( 0.435595832833, -0.659739379323,  0.306186321334, -0.789149008363),  // NOLINT
+      MakeJ3(-0.659739379323, -0.435595832833,  0.530330235247,  0.047367454164),  // NOLINT
+      MakeJ3( 0.612372616786,  0.000000000000,  0.353553128699,  0.612372571957),  // NOLINT
+      MakeJ3( 0.789149008363, -0.047367454164, -0.306186298920,  0.435595832833),  // NOLINT
+      MakeJ3(-0.047367454164, -0.789149008363, -0.530330196424, -0.659739379323),  // NOLINT
+      MakeJ3(-0.612372571957,  0.000000000000, -0.353553102817,  0.612372616786),  // NOLINT
+      MakeJ3( 0.433012832394,  0.750000183771,  0.249999816229,  0.000000000000),  // NOLINT
+      MakeJ3( 0.750000183771, -0.433012832394,  0.433012359189,  0.000000000000),  // NOLINT
+      MakeJ3( 0.499999611325,  0.000000000000, -0.866025628186,  0.000000000000)   // NOLINT
+    };
+    // clang-format on
+    EXPECT_THAT(rotation_matrix,
+                testing::Pointwise(JetClose(kLooseTolerance), expected));
+  }
+
+  ArrayToArrayOfJets(sample_euler[1], euler_angles);
+  EulerAnglesToRotation<ExtrinsicZXZ>(euler_angles, rotation_matrix);
+  {
+    // clang-format off
+    const J3 expected[] = {
+      MakeJ3( 0.625000065470, -0.649518902838,  0.216506425348, -0.649518902838),  // NOLINT
+      MakeJ3(-0.649518902838, -0.625000065470,  0.375000107735, -0.124999676795),  // NOLINT
+      MakeJ3( 0.433012832394,  0.000000000000,  0.249999816229,  0.750000183771),  // NOLINT
+      MakeJ3( 0.649518902838,  0.124999676795, -0.375000107735,  0.625000065470),  // NOLINT
+      MakeJ3( 0.124999676795, -0.649518902838, -0.649519202838, -0.649518902838),  // NOLINT
+      MakeJ3(-0.750000183771,  0.000000000000, -0.433012359189,  0.433012832394),  // NOLINT
+      MakeJ3( 0.433012832394,  0.750000183771,  0.249999816229,  0.000000000000),  // NOLINT
+      MakeJ3( 0.750000183771, -0.433012832394,  0.433012359189,  0.000000000000),  // NOLINT
+      MakeJ3( 0.499999611325,  0.000000000000, -0.866025628186,  0.000000000000)   // NOLINT
+    };
+    // clang-format on
+    EXPECT_THAT(rotation_matrix,
+                testing::Pointwise(JetClose(kLooseTolerance), expected));
+  }
+
+  ArrayToArrayOfJets(sample_euler[2], euler_angles);
+  EulerAnglesToRotation<ExtrinsicZXZ>(euler_angles, rotation_matrix);
+  {
+    // clang-format off
+    const J3 expected[] = {
+      MakeJ3(-0.176777132430, -0.883883325124,  0.306186321334, -0.918558558685),  // NOLINT
+      MakeJ3(-0.883883325124,  0.176777132430,  0.306186298920,  0.306186652473),  // NOLINT
+      MakeJ3( 0.433012832394,  0.000000000000,  0.750000183771,  0.249999816229),  // NOLINT
+      MakeJ3( 0.918558558685, -0.306186652473, -0.176776571821, -0.176777132430),  // NOLINT
+      MakeJ3(-0.306186652473, -0.918558558685, -0.176776558880, -0.883883325124),  // NOLINT
+      MakeJ3(-0.249999816229,  0.000000000000, -0.433012359189,  0.433012832394),  // NOLINT
+      MakeJ3( 0.353553418477,  0.353553392595,  0.612372449483,  0.000000000000),  // NOLINT
+      MakeJ3( 0.353553392595, -0.353553418477,  0.612372404654,  0.000000000000),  // NOLINT
+      MakeJ3( 0.866025391584,  0.000000000000, -0.500000021132,  0.000000000000)   // NOLINT
+    };
+    // clang-format on
+    EXPECT_THAT(rotation_matrix,
+                testing::Pointwise(JetClose(kLooseTolerance), expected));
+  }
+}
+
+using J9 = Jet<double, 9>;
+
+// The following 4 tests Tests the conversion of rotation matrices to Euler
+// Angles for Jets.
+//
+// The dual parts (with dimension 9) of the resultant array of Jets contain the
+// derivative of each Euler angle w.r.t. each of the 9 elements of the rotation
+// matrix, or a 9-by-1 array formed from flattening the rotation matrix. In
+// other words, for each element in angles = RotationMatrixToEulerAngles(R), we
+// have angles.v = jacobian(angles, [R11 R12 R13 R21 ... R32 R33]);
+//
+// Note: the order of elements in v depend on row/column-wise flattening of
+// the rotation matrix
+//
+// The test data (dual parts of the Jets) is generated by analytically
+// differentiating the formulas for Rotation Matrix to Euler Angle conversion
+
+// clang-format off
+static double sample_matrices[][9] = {
+  { 0.433012359189,  0.176776842652,  0.883883614902,  0.249999816229,  0.918558725988, -0.306186150563, -0.866025628186,  0.353553128699,  0.353553102817},  // NOLINT
+  { 0.433012359189, -0.058012606358,  0.899519223971,  0.249999816229,  0.966506404215, -0.058012606358, -0.866025628186,  0.249999816229,  0.433012359189},  // NOLINT
+  { 0.612372404654, -0.047366829780,  0.789149175666,  0.612372449483,  0.659739424151, -0.435596000136, -0.500000021132,  0.750000183771,  0.433012359189}   // NOLINT
+};
+// clang-format on
+
+// Test rotation matrix to ZXY/312 Intrinsic Euler Angles conversion using Jets
+// The two ZXY test cases specifically cover handling of Tait-Bryan angles
+// i.e. last axis of rotation is different from the first
+TEST(EulerAngles, RotationMatrixToIntrinsic312EulerSequenceForJets) {
+  J9 euler_angles[3];
+  J9 rotation_matrix[9];
+
+  ArrayToArrayOfJets(sample_matrices[0], rotation_matrix);
+  RotationMatrixToEulerAngles<IntrinsicZXY>(rotation_matrix, euler_angles);
+  {
+    // clang-format off
+    const J9 expected[] = {
+      MakeJet<9>(-0.190125743401,  0.000000000000, -1.049781178951,  0.000000000000,  0.000000000000,  0.202030634558,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000),  // NOLINT
+      MakeJet<9>( 0.361366843930,  0.000000000000, -0.066815309609,  0.000000000000,  0.000000000000, -0.347182270882,  0.000000000000,  0.000000000000,  0.935414445680,  0.000000000000),  // NOLINT
+      MakeJet<9>( 1.183200015636,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000, -0.404060603418,  0.000000000000, -0.989743365598)   // NOLINT
+    };
+    // clang-format on
+    EXPECT_THAT(euler_angles,
+                testing::Pointwise(JetClose(kLooseTolerance), expected));
+  }
+
+  ArrayToArrayOfJets(sample_matrices[1], rotation_matrix);
+  RotationMatrixToEulerAngles<IntrinsicZXY>(rotation_matrix, euler_angles);
+  {
+    // clang-format off
+    const J9 expected[] = {
+      MakeJet<9>( 0.059951064811,  0.000000000000, -1.030940063452,  0.000000000000,  0.000000000000, -0.061880107384,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000),  // NOLINT
+      MakeJet<9>( 0.252680065344,  0.000000000000,  0.014978778808,  0.000000000000,  0.000000000000, -0.249550684831,  0.000000000000,  0.000000000000,  0.968245884001,  0.000000000000),  // NOLINT
+      MakeJet<9>( 1.107149138016,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000, -0.461879804532,  0.000000000000, -0.923760579526)   // NOLINT
+    };
+    // clang-format on
+    EXPECT_THAT(euler_angles,
+                testing::Pointwise(JetClose(kLooseTolerance), expected));
+  }
+
+  ArrayToArrayOfJets(sample_matrices[2], rotation_matrix);
+  RotationMatrixToEulerAngles<IntrinsicZXY>(rotation_matrix, euler_angles);
+  {
+    // clang-format off
+    const J9 expected[] = {
+      MakeJet<9>( 0.071673287221,  0.000000000000, -1.507976776767,  0.000000000000,  0.000000000000, -0.108267107713,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000),  // NOLINT
+      MakeJet<9>( 0.848062356818,  0.000000000000,  0.053708966648,  0.000000000000,  0.000000000000, -0.748074610289,  0.000000000000,  0.000000000000,  0.661437619389,  0.000000000000),  // NOLINT
+      MakeJet<9>( 0.857072360427,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000, -0.989743158900,  0.000000000000, -1.142857911244)   // NOLINT
+    };
+    // clang-format on
+    EXPECT_THAT(euler_angles,
+                testing::Pointwise(JetClose(kLooseTolerance), expected));
+  }
+}
+
+// Test rotation matrix to ZXY/312 Extrinsic Euler Angles conversion using Jets
+TEST(EulerAngles, RotationMatrixToExtrinsic312EulerSequenceForJets) {
+  J9 euler_angles[3];
+  J9 rotation_matrix[9];
+
+  ArrayToArrayOfJets(sample_matrices[0], rotation_matrix);
+  RotationMatrixToEulerAngles<ExtrinsicZXY>(rotation_matrix, euler_angles);
+  {
+    // clang-format off
+    const J9 expected[] = {
+      MakeJet<9>( 0.265728912717,  0.000000000000,  0.000000000000,  0.000000000000,  1.013581996386, -0.275861853641,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000),  // NOLINT
+      MakeJet<9>( 0.311184173598,  0.000000000000,  0.000000000000, -0.284286741927,  0.000000000000,  0.000000000000, -0.951971659874,  0.000000000000,  0.000000000000, -0.113714586405),  // NOLINT
+      MakeJet<9>( 1.190290284357,  0.000000000000,  0.000000000000,  0.390127543992,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000, -0.975319806582)   // NOLINT
+    };
+    // clang-format on
+    EXPECT_THAT(euler_angles,
+                testing::Pointwise(JetClose(kLooseTolerance), expected));
+  }
+
+  ArrayToArrayOfJets(sample_matrices[1], rotation_matrix);
+  RotationMatrixToEulerAngles<ExtrinsicZXY>(rotation_matrix, euler_angles);
+  {
+    // clang-format off
+    const J9 expected[] = {
+      MakeJet<9>( 0.253115668605,  0.000000000000,  0.000000000000,  0.000000000000,  0.969770129215, -0.250844022378,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000),  // NOLINT
+      MakeJet<9>( 0.058045195612,  0.000000000000,  0.000000000000, -0.052271487648,  0.000000000000,  0.000000000000, -0.998315850572,  0.000000000000,  0.000000000000, -0.025162553041),  // NOLINT
+      MakeJet<9>( 1.122153748896,  0.000000000000,  0.000000000000,  0.434474567050,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000, -0.902556744846)   // NOLINT
+    };
+    // clang-format on
+    EXPECT_THAT(euler_angles,
+                testing::Pointwise(JetClose(kLooseTolerance), expected));
+  }
+
+  ArrayToArrayOfJets(sample_matrices[2], rotation_matrix);
+  RotationMatrixToEulerAngles<ExtrinsicZXY>(rotation_matrix, euler_angles);
+  {
+    // clang-format off
+    const J9 expected[] = {
+      MakeJet<9>( 0.748180444286,  0.000000000000,  0.000000000000,  0.000000000000,  0.814235652244, -0.755776390750,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000),  // NOLINT
+      MakeJet<9>( 0.450700288478,  0.000000000000,  0.000000000000, -0.381884322045,  0.000000000000,  0.000000000000, -0.900142280234,  0.000000000000,  0.000000000000, -0.209542930950),  // NOLINT
+      MakeJet<9>( 1.068945699497,  0.000000000000,  0.000000000000,  0.534414175972,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000, -0.973950275281)   // NOLINT
+    };
+    // clang-format on
+    EXPECT_THAT(euler_angles,
+                testing::Pointwise(JetClose(kLooseTolerance), expected));
+  }
+}
+
+// Test rotation matrix to ZXZ/313 Intrinsic Euler Angles conversion using Jets
+//// The two ZXZ test cases specifically cover handling of proper Euler
+/// Sequences
+// i.e. last axis of rotation is same as the first
+TEST(EulerAngles, RotationMatrixToIntrinsic313EulerSequenceForJets) {
+  J9 euler_angles[3];
+  J9 rotation_matrix[9];
+
+  ArrayToArrayOfJets(sample_matrices[0], rotation_matrix);
+  RotationMatrixToEulerAngles<IntrinsicZXZ>(rotation_matrix, euler_angles);
+  {
+    // clang-format off
+    const J9 expected[] = {
+      MakeJet<9>( 1.237323270947,  0.000000000000,  0.000000000000,  0.349926947837,  0.000000000000,  0.000000000000,  1.010152467826,  0.000000000000,  0.000000000000,  0.000000000000),  // NOLINT
+      MakeJet<9>( 1.209429510533,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000, -0.327326615680,  0.133630397662, -0.935414455462),  // NOLINT
+      MakeJet<9>(-1.183199990019,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000,  0.404060624546,  0.989743344897,  0.000000000000)   // NOLINT
+    };
+    // clang-format on
+    EXPECT_THAT(euler_angles,
+                testing::Pointwise(JetClose(kLooseTolerance), expected));
+  }
+
+  ArrayToArrayOfJets(sample_matrices[1], rotation_matrix);
+  RotationMatrixToEulerAngles<IntrinsicZXZ>(rotation_matrix, euler_angles);
+  {
+    // clang-format off
+    const J9 expected[] = {
+      MakeJet<9>( 1.506392616830,  0.000000000000,  0.000000000000,  0.071400104821,  0.000000000000,  0.000000000000,  1.107100178948,  0.000000000000,  0.000000000000,  0.000000000000),  // NOLINT
+      MakeJet<9>( 1.122964310061,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000, -0.416024849727,  0.120095910090, -0.901387983495),  // NOLINT
+      MakeJet<9>(-1.289761690216,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000,  0.307691969119,  1.065877306886,  0.000000000000)   // NOLINT
+    };
+    // clang-format on
+    EXPECT_THAT(euler_angles,
+                testing::Pointwise(JetClose(kLooseTolerance), expected));
+  }
+
+  ArrayToArrayOfJets(sample_matrices[2], rotation_matrix);
+  RotationMatrixToEulerAngles<IntrinsicZXZ>(rotation_matrix, euler_angles);
+  {
+    // clang-format off
+    const J9 expected[] = {
+      MakeJet<9>( 1.066432836578,  0.000000000000,  0.000000000000,  0.536117958181,  0.000000000000,  0.000000000000,  0.971260169116,  0.000000000000,  0.000000000000,  0.000000000000),  // NOLINT
+      MakeJet<9>( 1.122964310061,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000, -0.240192006893,  0.360288083393, -0.901387983495),  // NOLINT
+      MakeJet<9>(-0.588002509965,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000,  0.923076812076,  0.615384416607,  0.000000000000)   // NOLINT
+    };
+    // clang-format on
+    EXPECT_THAT(euler_angles,
+                testing::Pointwise(JetClose(kLooseTolerance), expected));
+  }
+}
+
+// Test rotation matrix to ZXZ/313 Extrinsic Euler Angles conversion using Jets
+TEST(EulerAngles, RotationMatrixToExtrinsic313EulerSequenceForJets) {
+  J9 euler_angles[3];
+  J9 rotation_matrix[9];
+
+  ArrayToArrayOfJets(sample_matrices[0], rotation_matrix);
+  RotationMatrixToEulerAngles<ExtrinsicZXZ>(rotation_matrix, euler_angles);
+  {
+    // clang-format off
+    const J9 expected[] = {
+      MakeJet<9>(-1.183199990019,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000,  0.404060624546,  0.989743344897,  0.000000000000),  // NOLINT
+      MakeJet<9>( 1.209429510533,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000, -0.327326615680,  0.133630397662, -0.935414455462),  // NOLINT
+      MakeJet<9>( 1.237323270947,  0.000000000000,  0.000000000000,  0.349926947837,  0.000000000000,  0.000000000000,  1.010152467826,  0.000000000000,  0.000000000000,  0.000000000000)   // NOLINT
+    };
+    // clang-format on
+    EXPECT_THAT(euler_angles,
+                testing::Pointwise(JetClose(kLooseTolerance), expected));
+  }
+
+  ArrayToArrayOfJets(sample_matrices[1], rotation_matrix);
+  RotationMatrixToEulerAngles<ExtrinsicZXZ>(rotation_matrix, euler_angles);
+  {
+    // clang-format off
+    const J9 expected[] = {
+      MakeJet<9>(-1.289761690216,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000,  0.307691969119,  1.065877306886,  0.000000000000),  // NOLINT
+      MakeJet<9>( 1.122964310061,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000, -0.416024849727,  0.120095910090, -0.901387983495),  // NOLINT
+      MakeJet<9>( 1.506392616830,  0.000000000000,  0.000000000000,  0.071400104821,  0.000000000000,  0.000000000000,  1.107100178948,  0.000000000000,  0.000000000000,  0.000000000000)   // NOLINT
+    };
+    // clang-format on
+    EXPECT_THAT(euler_angles,
+                testing::Pointwise(JetClose(kLooseTolerance), expected));
+  }
+
+  ArrayToArrayOfJets(sample_matrices[2], rotation_matrix);
+  RotationMatrixToEulerAngles<ExtrinsicZXZ>(rotation_matrix, euler_angles);
+  {
+    // clang-format off
+    const J9 expected[] = {
+      MakeJet<9>(-0.588002509965,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000,  0.923076812076,  0.615384416607,  0.000000000000),  // NOLINT
+      MakeJet<9>( 1.122964310061,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000,  0.000000000000, -0.240192006893,  0.360288083393, -0.901387983495),  // NOLINT
+      MakeJet<9>( 1.066432836578,  0.000000000000,  0.000000000000,  0.536117958181,  0.000000000000,  0.000000000000,  0.971260169116,  0.000000000000,  0.000000000000,  0.000000000000)   // NOLINT
+    };
+    // clang-format on
+    EXPECT_THAT(euler_angles,
+                testing::Pointwise(JetClose(kLooseTolerance), expected));
+  }
 }
 
 TEST(Quaternion, RotatePointGivesSameAnswerAsRotationByMatrixCanned) {
@@ -904,13 +1677,15 @@
 
 // Verify that (a * b) * c == a * (b * c).
 TEST(Quaternion, MultiplicationIsAssociative) {
+  std::mt19937 prng;
+  std::uniform_real_distribution<double> uniform_distribution{-1.0, 1.0};
   double a[4];
   double b[4];
   double c[4];
   for (int i = 0; i < 4; ++i) {
-    a[i] = 2 * RandDouble() - 1;
-    b[i] = 2 * RandDouble() - 1;
-    c[i] = 2 * RandDouble() - 1;
+    a[i] = uniform_distribution(prng);
+    b[i] = uniform_distribution(prng);
+    c[i] = uniform_distribution(prng);
   }
 
   double ab[4];
@@ -930,6 +1705,8 @@
 }
 
 TEST(AngleAxis, RotatePointGivesSameAnswerAsRotationMatrix) {
+  std::mt19937 prng;
+  std::uniform_real_distribution<double> uniform_distribution{-1.0, 1.0};
   double angle_axis[3];
   double R[9];
   double p[3];
@@ -939,16 +1716,15 @@
   for (int i = 0; i < 10000; ++i) {
     double theta = (2.0 * i * 0.0011 - 1.0) * kPi;
     for (int j = 0; j < 50; ++j) {
-      double norm2 = 0.0;
       for (int k = 0; k < 3; ++k) {
-        angle_axis[k] = 2.0 * RandDouble() - 1.0;
-        p[k] = 2.0 * RandDouble() - 1.0;
-        norm2 = angle_axis[k] * angle_axis[k];
+        angle_axis[k] = uniform_distribution(prng);
+        p[k] = uniform_distribution(prng);
       }
 
-      const double inv_norm = theta / sqrt(norm2);
-      for (int k = 0; k < 3; ++k) {
-        angle_axis[k] *= inv_norm;
+      const double inv_norm =
+          theta / std::hypot(angle_axis[0], angle_axis[1], angle_axis[2]);
+      for (double& angle_axi : angle_axis) {
+        angle_axi *= inv_norm;
       }
 
       AngleAxisToRotationMatrix(angle_axis, R);
@@ -973,7 +1749,22 @@
   }
 }
 
+TEST(Quaternion, UnitQuaternion) {
+  using Jet = ceres::Jet<double, 4>;
+  std::array<Jet, 4> quaternion = {
+      Jet(1.0, 0), Jet(0.0, 1), Jet(0.0, 2), Jet(0.0, 3)};
+  std::array<Jet, 3> point = {Jet(0.0), Jet(0.0), Jet(0.0)};
+  std::array<Jet, 3> rotated_point;
+  QuaternionRotatePoint(quaternion.data(), point.data(), rotated_point.data());
+  for (int i = 0; i < 3; ++i) {
+    EXPECT_EQ(rotated_point[i], point[i]);
+    EXPECT_FALSE(rotated_point[i].v.array().isNaN().any());
+  }
+}
+
 TEST(AngleAxis, NearZeroRotatePointGivesSameAnswerAsRotationMatrix) {
+  std::mt19937 prng;
+  std::uniform_real_distribution<double> uniform_distribution{-1.0, 1.0};
   double angle_axis[3];
   double R[9];
   double p[3];
@@ -983,15 +1774,15 @@
   for (int i = 0; i < 10000; ++i) {
     double norm2 = 0.0;
     for (int k = 0; k < 3; ++k) {
-      angle_axis[k] = 2.0 * RandDouble() - 1.0;
-      p[k] = 2.0 * RandDouble() - 1.0;
+      angle_axis[k] = uniform_distribution(prng);
+      p[k] = uniform_distribution(prng);
       norm2 = angle_axis[k] * angle_axis[k];
     }
 
     double theta = (2.0 * i * 0.0001 - 1.0) * 1e-16;
     const double inv_norm = theta / sqrt(norm2);
-    for (int k = 0; k < 3; ++k) {
-      angle_axis[k] *= inv_norm;
+    for (double& angle_axi : angle_axis) {
+      angle_axi *= inv_norm;
     }
 
     AngleAxisToRotationMatrix(angle_axis, R);
@@ -1109,7 +1900,12 @@
 }
 
 TEST(RotationMatrixToAngleAxis, ExhaustiveRoundTrip) {
-  const double kMaxSmallAngle = 1e-8;
+  constexpr double kMaxSmallAngle = 1e-8;
+  std::mt19937 prng;
+  std::uniform_real_distribution<double> uniform_distribution1{
+      kPi - kMaxSmallAngle, kPi};
+  std::uniform_real_distribution<double> uniform_distribution2{
+      -1.0, 2.0 * kMaxSmallAngle - 1.0};
   const int kNumSteps = 1000;
   for (int i = 0; i < kNumSteps; ++i) {
     const double theta = static_cast<double>(i) / kNumSteps * 2.0 * kPi;
@@ -1119,10 +1915,10 @@
       CheckRotationMatrixToAngleAxisRoundTrip(theta, phi, kPi);
       // Rotation of angle approximately Pi.
       CheckRotationMatrixToAngleAxisRoundTrip(
-          theta, phi, kPi - kMaxSmallAngle * RandDouble());
+          theta, phi, uniform_distribution1(prng));
       // Rotations of angle approximately zero.
       CheckRotationMatrixToAngleAxisRoundTrip(
-          theta, phi, kMaxSmallAngle * 2.0 * RandDouble() - 1.0);
+          theta, phi, uniform_distribution2(prng));
     }
   }
 }
diff --git a/third_party/ceres/internal/ceres/schur_complement_solver.cc b/third_party/ceres/internal/ceres/schur_complement_solver.cc
index 65e7854..e113040 100644
--- a/third_party/ceres/internal/ceres/schur_complement_solver.cc
+++ b/third_party/ceres/internal/ceres/schur_complement_solver.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -34,6 +34,7 @@
 #include <ctime>
 #include <memory>
 #include <set>
+#include <utility>
 #include <vector>
 
 #include "Eigen/Dense"
@@ -46,75 +47,56 @@
 #include "ceres/conjugate_gradients_solver.h"
 #include "ceres/detect_structure.h"
 #include "ceres/internal/eigen.h"
-#include "ceres/lapack.h"
 #include "ceres/linear_solver.h"
 #include "ceres/sparse_cholesky.h"
 #include "ceres/triplet_sparse_matrix.h"
 #include "ceres/types.h"
 #include "ceres/wall_time.h"
 
-namespace ceres {
-namespace internal {
-
-using std::make_pair;
-using std::pair;
-using std::set;
-using std::vector;
-
+namespace ceres::internal {
 namespace {
 
-class BlockRandomAccessSparseMatrixAdapter : public LinearOperator {
+class BlockRandomAccessSparseMatrixAdapter final
+    : public ConjugateGradientsLinearOperator<Vector> {
  public:
   explicit BlockRandomAccessSparseMatrixAdapter(
       const BlockRandomAccessSparseMatrix& m)
       : m_(m) {}
 
-  virtual ~BlockRandomAccessSparseMatrixAdapter() {}
-
-  // y = y + Ax;
-  void RightMultiply(const double* x, double* y) const final {
-    m_.SymmetricRightMultiply(x, y);
+  void RightMultiplyAndAccumulate(const Vector& x, Vector& y) final {
+    m_.SymmetricRightMultiplyAndAccumulate(x.data(), y.data());
   }
 
-  // y = y + A'x;
-  void LeftMultiply(const double* x, double* y) const final {
-    m_.SymmetricRightMultiply(x, y);
-  }
-
-  int num_rows() const final { return m_.num_rows(); }
-  int num_cols() const final { return m_.num_rows(); }
-
  private:
   const BlockRandomAccessSparseMatrix& m_;
 };
 
-class BlockRandomAccessDiagonalMatrixAdapter : public LinearOperator {
+class BlockRandomAccessDiagonalMatrixAdapter final
+    : public ConjugateGradientsLinearOperator<Vector> {
  public:
   explicit BlockRandomAccessDiagonalMatrixAdapter(
       const BlockRandomAccessDiagonalMatrix& m)
       : m_(m) {}
 
-  virtual ~BlockRandomAccessDiagonalMatrixAdapter() {}
-
   // y = y + Ax;
-  void RightMultiply(const double* x, double* y) const final {
-    m_.RightMultiply(x, y);
+  void RightMultiplyAndAccumulate(const Vector& x, Vector& y) final {
+    m_.RightMultiplyAndAccumulate(x.data(), y.data());
   }
 
-  // y = y + A'x;
-  void LeftMultiply(const double* x, double* y) const final {
-    m_.RightMultiply(x, y);
-  }
-
-  int num_rows() const final { return m_.num_rows(); }
-  int num_cols() const final { return m_.num_rows(); }
-
  private:
   const BlockRandomAccessDiagonalMatrix& m_;
 };
 
 }  // namespace
 
+SchurComplementSolver::SchurComplementSolver(
+    const LinearSolver::Options& options)
+    : options_(options) {
+  CHECK_GT(options.elimination_groups.size(), 1);
+  CHECK_GT(options.elimination_groups[0], 0);
+  CHECK(options.context != nullptr);
+}
+
 LinearSolver::Summary SchurComplementSolver::SolveImpl(
     BlockSparseMatrix* A,
     const double* b,
@@ -123,7 +105,7 @@
   EventLogger event_logger("SchurComplementSolver::Solve");
 
   const CompressedRowBlockStructure* bs = A->block_structure();
-  if (eliminator_.get() == NULL) {
+  if (eliminator_ == nullptr) {
     const int num_eliminate_blocks = options_.elimination_groups[0];
     const int num_f_blocks = bs->cols.size() - num_eliminate_blocks;
 
@@ -141,9 +123,9 @@
     // mechanism that does not cause binary bloat.
     if (options_.row_block_size == 2 && options_.e_block_size == 3 &&
         options_.f_block_size == 6 && num_f_blocks == 1) {
-      eliminator_.reset(new SchurEliminatorForOneFBlock<2, 3, 6>);
+      eliminator_ = std::make_unique<SchurEliminatorForOneFBlock<2, 3, 6>>();
     } else {
-      eliminator_.reset(SchurEliminatorBase::Create(options_));
+      eliminator_ = SchurEliminatorBase::Create(options_);
     }
 
     CHECK(eliminator_);
@@ -158,7 +140,7 @@
                          b,
                          per_solve_options.D,
                          lhs_.get(),
-                         rhs_.get());
+                         rhs_.data());
   event_logger.AddEvent("Eliminate");
 
   double* reduced_solution = x + A->num_cols() - lhs_->num_cols();
@@ -166,7 +148,7 @@
       SolveReducedLinearSystem(per_solve_options, reduced_solution);
   event_logger.AddEvent("ReducedSolve");
 
-  if (summary.termination_type == LINEAR_SOLVER_SUCCESS) {
+  if (summary.termination_type == LinearSolverTerminationType::SUCCESS) {
     eliminator_->BackSubstitute(
         BlockSparseMatrixData(*A), b, per_solve_options.D, reduced_solution, x);
     event_logger.AddEvent("BackSubstitute");
@@ -174,6 +156,12 @@
 
   return summary;
 }
+DenseSchurComplementSolver::DenseSchurComplementSolver(
+    const LinearSolver::Options& options)
+    : SchurComplementSolver(options),
+      cholesky_(DenseCholesky::Create(options)) {}
+
+DenseSchurComplementSolver::~DenseSchurComplementSolver() = default;
 
 // Initialize a BlockRandomAccessDenseMatrix to store the Schur
 // complement.
@@ -181,28 +169,24 @@
     const CompressedRowBlockStructure* bs) {
   const int num_eliminate_blocks = options().elimination_groups[0];
   const int num_col_blocks = bs->cols.size();
-
-  vector<int> blocks(num_col_blocks - num_eliminate_blocks, 0);
-  for (int i = num_eliminate_blocks, j = 0; i < num_col_blocks; ++i, ++j) {
-    blocks[j] = bs->cols[i].size;
-  }
-
-  set_lhs(new BlockRandomAccessDenseMatrix(blocks));
-  set_rhs(new double[lhs()->num_rows()]);
+  auto blocks = Tail(bs->cols, num_col_blocks - num_eliminate_blocks);
+  set_lhs(std::make_unique<BlockRandomAccessDenseMatrix>(
+      blocks, options().context, options().num_threads));
+  ResizeRhs(lhs()->num_rows());
 }
 
 // Solve the system Sx = r, assuming that the matrix S is stored in a
 // BlockRandomAccessDenseMatrix. The linear system is solved using
 // Eigen's Cholesky factorization.
 LinearSolver::Summary DenseSchurComplementSolver::SolveReducedLinearSystem(
-    const LinearSolver::PerSolveOptions& per_solve_options, double* solution) {
+    const LinearSolver::PerSolveOptions& /*per_solve_options*/,
+    double* solution) {
   LinearSolver::Summary summary;
   summary.num_iterations = 0;
-  summary.termination_type = LINEAR_SOLVER_SUCCESS;
+  summary.termination_type = LinearSolverTerminationType::SUCCESS;
   summary.message = "Success.";
 
-  const BlockRandomAccessDenseMatrix* m =
-      down_cast<const BlockRandomAccessDenseMatrix*>(lhs());
+  auto* m = down_cast<BlockRandomAccessDenseMatrix*>(mutable_lhs());
   const int num_rows = m->num_rows();
 
   // The case where there are no f blocks, and the system is block
@@ -212,26 +196,8 @@
   }
 
   summary.num_iterations = 1;
-
-  if (options().dense_linear_algebra_library_type == EIGEN) {
-    Eigen::LLT<Matrix, Eigen::Upper> llt =
-        ConstMatrixRef(m->values(), num_rows, num_rows)
-            .selfadjointView<Eigen::Upper>()
-            .llt();
-    if (llt.info() != Eigen::Success) {
-      summary.termination_type = LINEAR_SOLVER_FAILURE;
-      summary.message =
-          "Eigen failure. Unable to perform dense Cholesky factorization.";
-      return summary;
-    }
-
-    VectorRef(solution, num_rows) = llt.solve(ConstVectorRef(rhs(), num_rows));
-  } else {
-    VectorRef(solution, num_rows) = ConstVectorRef(rhs(), num_rows);
-    summary.termination_type = LAPACK::SolveInPlaceUsingCholesky(
-        num_rows, m->values(), solution, &summary.message);
-  }
-
+  summary.termination_type = cholesky_->FactorAndSolve(
+      num_rows, m->mutable_values(), rhs().data(), solution, &summary.message);
   return summary;
 }
 
@@ -243,7 +209,14 @@
   }
 }
 
-SparseSchurComplementSolver::~SparseSchurComplementSolver() {}
+SparseSchurComplementSolver::~SparseSchurComplementSolver() {
+  for (int i = 0; i < 4; ++i) {
+    if (scratch_[i]) {
+      delete scratch_[i];
+      scratch_[i] = nullptr;
+    }
+  }
+}
 
 // Determine the non-zero blocks in the Schur Complement matrix, and
 // initialize a BlockRandomAccessSparseMatrix object.
@@ -253,14 +226,11 @@
   const int num_col_blocks = bs->cols.size();
   const int num_row_blocks = bs->rows.size();
 
-  blocks_.resize(num_col_blocks - num_eliminate_blocks, 0);
-  for (int i = num_eliminate_blocks; i < num_col_blocks; ++i) {
-    blocks_[i - num_eliminate_blocks] = bs->cols[i].size;
-  }
+  blocks_ = Tail(bs->cols, num_col_blocks - num_eliminate_blocks);
 
-  set<pair<int, int>> block_pairs;
+  std::set<std::pair<int, int>> block_pairs;
   for (int i = 0; i < blocks_.size(); ++i) {
-    block_pairs.insert(make_pair(i, i));
+    block_pairs.emplace(i, i);
   }
 
   int r = 0;
@@ -269,7 +239,7 @@
     if (e_block_id >= num_eliminate_blocks) {
       break;
     }
-    vector<int> f_blocks;
+    std::vector<int> f_blocks;
 
     // Add to the chunk until the first block in the row is
     // different than the one in the first row for the chunk.
@@ -287,11 +257,12 @@
       }
     }
 
-    sort(f_blocks.begin(), f_blocks.end());
-    f_blocks.erase(unique(f_blocks.begin(), f_blocks.end()), f_blocks.end());
+    std::sort(f_blocks.begin(), f_blocks.end());
+    f_blocks.erase(std::unique(f_blocks.begin(), f_blocks.end()),
+                   f_blocks.end());
     for (int i = 0; i < f_blocks.size(); ++i) {
       for (int j = i + 1; j < f_blocks.size(); ++j) {
-        block_pairs.insert(make_pair(f_blocks[i], f_blocks[j]));
+        block_pairs.emplace(f_blocks[i], f_blocks[j]);
       }
     }
   }
@@ -303,17 +274,18 @@
     CHECK_GE(row.cells.front().block_id, num_eliminate_blocks);
     for (int i = 0; i < row.cells.size(); ++i) {
       int r_block1_id = row.cells[i].block_id - num_eliminate_blocks;
-      for (int j = 0; j < row.cells.size(); ++j) {
-        int r_block2_id = row.cells[j].block_id - num_eliminate_blocks;
+      for (const auto& cell : row.cells) {
+        int r_block2_id = cell.block_id - num_eliminate_blocks;
         if (r_block1_id <= r_block2_id) {
-          block_pairs.insert(make_pair(r_block1_id, r_block2_id));
+          block_pairs.emplace(r_block1_id, r_block2_id);
         }
       }
     }
   }
 
-  set_lhs(new BlockRandomAccessSparseMatrix(blocks_, block_pairs));
-  set_rhs(new double[lhs()->num_rows()]);
+  set_lhs(std::make_unique<BlockRandomAccessSparseMatrix>(
+      blocks_, block_pairs, options().context, options().num_threads));
+  ResizeRhs(lhs()->num_rows());
 }
 
 LinearSolver::Summary SparseSchurComplementSolver::SolveReducedLinearSystem(
@@ -325,33 +297,39 @@
 
   LinearSolver::Summary summary;
   summary.num_iterations = 0;
-  summary.termination_type = LINEAR_SOLVER_SUCCESS;
+  summary.termination_type = LinearSolverTerminationType::SUCCESS;
   summary.message = "Success.";
 
-  const TripletSparseMatrix* tsm =
+  const BlockSparseMatrix* bsm =
       down_cast<const BlockRandomAccessSparseMatrix*>(lhs())->matrix();
-  if (tsm->num_rows() == 0) {
+  if (bsm->num_rows() == 0) {
     return summary;
   }
 
-  std::unique_ptr<CompressedRowSparseMatrix> lhs;
   const CompressedRowSparseMatrix::StorageType storage_type =
       sparse_cholesky_->StorageType();
-  if (storage_type == CompressedRowSparseMatrix::UPPER_TRIANGULAR) {
-    lhs.reset(CompressedRowSparseMatrix::FromTripletSparseMatrix(*tsm));
-    lhs->set_storage_type(CompressedRowSparseMatrix::UPPER_TRIANGULAR);
+  if (storage_type ==
+      CompressedRowSparseMatrix::StorageType::UPPER_TRIANGULAR) {
+    if (!crs_lhs_) {
+      crs_lhs_ = bsm->ToCompressedRowSparseMatrix();
+      crs_lhs_->set_storage_type(
+          CompressedRowSparseMatrix::StorageType::UPPER_TRIANGULAR);
+    } else {
+      bsm->UpdateCompressedRowSparseMatrix(crs_lhs_.get());
+    }
   } else {
-    lhs.reset(
-        CompressedRowSparseMatrix::FromTripletSparseMatrixTransposed(*tsm));
-    lhs->set_storage_type(CompressedRowSparseMatrix::LOWER_TRIANGULAR);
+    if (!crs_lhs_) {
+      crs_lhs_ = bsm->ToCompressedRowSparseMatrixTranspose();
+      crs_lhs_->set_storage_type(
+          CompressedRowSparseMatrix::StorageType::LOWER_TRIANGULAR);
+    } else {
+      bsm->UpdateCompressedRowSparseMatrixTranspose(crs_lhs_.get());
+    }
   }
 
-  *lhs->mutable_col_blocks() = blocks_;
-  *lhs->mutable_row_blocks() = blocks_;
-
   summary.num_iterations = 1;
   summary.termination_type = sparse_cholesky_->FactorAndSolve(
-      lhs.get(), rhs(), solution, &summary.message);
+      crs_lhs_.get(), rhs().data(), solution, &summary.message);
   return summary;
 }
 
@@ -365,7 +343,7 @@
   if (num_rows == 0) {
     LinearSolver::Summary summary;
     summary.num_iterations = 0;
-    summary.termination_type = LINEAR_SOLVER_SUCCESS;
+    summary.termination_type = LinearSolverTerminationType::SUCCESS;
     summary.message = "Success.";
     return summary;
   }
@@ -373,17 +351,17 @@
   // Only SCHUR_JACOBI is supported over here right now.
   CHECK_EQ(options().preconditioner_type, SCHUR_JACOBI);
 
-  if (preconditioner_.get() == NULL) {
-    preconditioner_.reset(new BlockRandomAccessDiagonalMatrix(blocks_));
+  if (preconditioner_ == nullptr) {
+    preconditioner_ = std::make_unique<BlockRandomAccessDiagonalMatrix>(
+        blocks_, options().context, options().num_threads);
   }
 
-  BlockRandomAccessSparseMatrix* sc = down_cast<BlockRandomAccessSparseMatrix*>(
-      const_cast<BlockRandomAccessMatrix*>(lhs()));
+  auto* sc = down_cast<BlockRandomAccessSparseMatrix*>(mutable_lhs());
 
   // Extract block diagonal from the Schur complement to construct the
   // schur_jacobi preconditioner.
   for (int i = 0; i < blocks_.size(); ++i) {
-    const int block_size = blocks_[i];
+    const int block_size = blocks_[i].size;
 
     int sc_r, sc_c, sc_row_stride, sc_col_stride;
     CellInfo* sc_cell_info =
@@ -404,24 +382,28 @@
 
   VectorRef(solution, num_rows).setZero();
 
-  std::unique_ptr<LinearOperator> lhs_adapter(
-      new BlockRandomAccessSparseMatrixAdapter(*sc));
-  std::unique_ptr<LinearOperator> preconditioner_adapter(
-      new BlockRandomAccessDiagonalMatrixAdapter(*preconditioner_));
+  auto lhs = std::make_unique<BlockRandomAccessSparseMatrixAdapter>(*sc);
+  auto preconditioner =
+      std::make_unique<BlockRandomAccessDiagonalMatrixAdapter>(
+          *preconditioner_);
 
-  LinearSolver::Options cg_options;
+  ConjugateGradientsSolverOptions cg_options;
   cg_options.min_num_iterations = options().min_num_iterations;
   cg_options.max_num_iterations = options().max_num_iterations;
-  ConjugateGradientsSolver cg_solver(cg_options);
+  cg_options.residual_reset_period = options().residual_reset_period;
+  cg_options.q_tolerance = per_solve_options.q_tolerance;
+  cg_options.r_tolerance = per_solve_options.r_tolerance;
 
-  LinearSolver::PerSolveOptions cg_per_solve_options;
-  cg_per_solve_options.r_tolerance = per_solve_options.r_tolerance;
-  cg_per_solve_options.q_tolerance = per_solve_options.q_tolerance;
-  cg_per_solve_options.preconditioner = preconditioner_adapter.get();
-
-  return cg_solver.Solve(
-      lhs_adapter.get(), rhs(), cg_per_solve_options, solution);
+  cg_solution_ = Vector::Zero(sc->num_rows());
+  for (int i = 0; i < 4; ++i) {
+    if (scratch_[i] == nullptr) {
+      scratch_[i] = new Vector(sc->num_rows());
+    }
+  }
+  auto summary = ConjugateGradientsSolver<Vector>(
+      cg_options, *lhs, rhs(), *preconditioner, scratch_, cg_solution_);
+  VectorRef(solution, sc->num_rows()) = cg_solution_;
+  return summary;
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/schur_complement_solver.h b/third_party/ceres/internal/ceres/schur_complement_solver.h
index 3bfa22f..5e11b94 100644
--- a/third_party/ceres/internal/ceres/schur_complement_solver.h
+++ b/third_party/ceres/internal/ceres/schur_complement_solver.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,7 +40,9 @@
 #include "ceres/block_random_access_matrix.h"
 #include "ceres/block_sparse_matrix.h"
 #include "ceres/block_structure.h"
-#include "ceres/internal/port.h"
+#include "ceres/dense_cholesky.h"
+#include "ceres/internal/config.h"
+#include "ceres/internal/export.h"
 #include "ceres/linear_solver.h"
 #include "ceres/schur_eliminator.h"
 #include "ceres/types.h"
@@ -50,8 +52,9 @@
 #include "Eigen/SparseCholesky"
 #endif
 
-namespace ceres {
-namespace internal {
+#include "ceres/internal/disable_warnings.h"
+
+namespace ceres::internal {
 
 class BlockSparseMatrix;
 class SparseCholesky;
@@ -62,7 +65,7 @@
 //
 //  E y + F z = b
 //
-// Where x = [y;z] is a partition of the variables.  The paritioning
+// Where x = [y;z] is a partition of the variables.  The partitioning
 // of the variables is such that, E'E is a block diagonal
 // matrix. Further, the rows of A are ordered so that for every
 // variable block in y, all the rows containing that variable block
@@ -107,20 +110,12 @@
 // set to DENSE_SCHUR and SPARSE_SCHUR
 // respectively. LinearSolver::Options::elimination_groups[0] should
 // be at least 1.
-class CERES_EXPORT_INTERNAL SchurComplementSolver
-    : public BlockSparseMatrixSolver {
+class CERES_NO_EXPORT SchurComplementSolver : public BlockSparseMatrixSolver {
  public:
-  explicit SchurComplementSolver(const LinearSolver::Options& options)
-      : options_(options) {
-    CHECK_GT(options.elimination_groups.size(), 1);
-    CHECK_GT(options.elimination_groups[0], 0);
-    CHECK(options.context != NULL);
-  }
+  explicit SchurComplementSolver(const LinearSolver::Options& options);
   SchurComplementSolver(const SchurComplementSolver&) = delete;
   void operator=(const SchurComplementSolver&) = delete;
 
-  // LinearSolver methods
-  virtual ~SchurComplementSolver() {}
   LinearSolver::Summary SolveImpl(
       BlockSparseMatrix* A,
       const double* b,
@@ -130,10 +125,13 @@
  protected:
   const LinearSolver::Options& options() const { return options_; }
 
+  void set_lhs(std::unique_ptr<BlockRandomAccessMatrix> lhs) {
+    lhs_ = std::move(lhs);
+  }
   const BlockRandomAccessMatrix* lhs() const { return lhs_.get(); }
-  void set_lhs(BlockRandomAccessMatrix* lhs) { lhs_.reset(lhs); }
-  const double* rhs() const { return rhs_.get(); }
-  void set_rhs(double* rhs) { rhs_.reset(rhs); }
+  BlockRandomAccessMatrix* mutable_lhs() { return lhs_.get(); }
+  void ResizeRhs(int n) { rhs_.resize(n); }
+  const Vector& rhs() const { return rhs_; }
 
  private:
   virtual void InitStorage(const CompressedRowBlockStructure* bs) = 0;
@@ -145,34 +143,37 @@
 
   std::unique_ptr<SchurEliminatorBase> eliminator_;
   std::unique_ptr<BlockRandomAccessMatrix> lhs_;
-  std::unique_ptr<double[]> rhs_;
+  Vector rhs_;
 };
 
 // Dense Cholesky factorization based solver.
-class DenseSchurComplementSolver : public SchurComplementSolver {
+class CERES_NO_EXPORT DenseSchurComplementSolver final
+    : public SchurComplementSolver {
  public:
-  explicit DenseSchurComplementSolver(const LinearSolver::Options& options)
-      : SchurComplementSolver(options) {}
+  explicit DenseSchurComplementSolver(const LinearSolver::Options& options);
   DenseSchurComplementSolver(const DenseSchurComplementSolver&) = delete;
   void operator=(const DenseSchurComplementSolver&) = delete;
 
-  virtual ~DenseSchurComplementSolver() {}
+  ~DenseSchurComplementSolver() override;
 
  private:
   void InitStorage(const CompressedRowBlockStructure* bs) final;
   LinearSolver::Summary SolveReducedLinearSystem(
       const LinearSolver::PerSolveOptions& per_solve_options,
       double* solution) final;
+
+  std::unique_ptr<DenseCholesky> cholesky_;
 };
 
 // Sparse Cholesky factorization based solver.
-class SparseSchurComplementSolver : public SchurComplementSolver {
+class CERES_NO_EXPORT SparseSchurComplementSolver final
+    : public SchurComplementSolver {
  public:
   explicit SparseSchurComplementSolver(const LinearSolver::Options& options);
   SparseSchurComplementSolver(const SparseSchurComplementSolver&) = delete;
   void operator=(const SparseSchurComplementSolver&) = delete;
 
-  virtual ~SparseSchurComplementSolver();
+  ~SparseSchurComplementSolver() override;
 
  private:
   void InitStorage(const CompressedRowBlockStructure* bs) final;
@@ -182,13 +183,16 @@
   LinearSolver::Summary SolveReducedLinearSystemUsingConjugateGradients(
       const LinearSolver::PerSolveOptions& per_solve_options, double* solution);
 
-  // Size of the blocks in the Schur complement.
-  std::vector<int> blocks_;
+  std::vector<Block> blocks_;
   std::unique_ptr<SparseCholesky> sparse_cholesky_;
   std::unique_ptr<BlockRandomAccessDiagonalMatrix> preconditioner_;
+  std::unique_ptr<CompressedRowSparseMatrix> crs_lhs_;
+  Vector cg_solution_;
+  Vector* scratch_[4] = {nullptr, nullptr, nullptr, nullptr};
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_SCHUR_COMPLEMENT_SOLVER_H_
diff --git a/third_party/ceres/internal/ceres/schur_complement_solver_test.cc b/third_party/ceres/internal/ceres/schur_complement_solver_test.cc
index 550733e..7c5ce28 100644
--- a/third_party/ceres/internal/ceres/schur_complement_solver_test.cc
+++ b/third_party/ceres/internal/ceres/schur_complement_solver_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -45,19 +45,18 @@
 #include "glog/logging.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 class SchurComplementSolverTest : public ::testing::Test {
  protected:
   void SetUpFromProblemId(int problem_id) {
-    std::unique_ptr<LinearLeastSquaresProblem> problem(
-        CreateLinearLeastSquaresProblemFromId(problem_id));
+    std::unique_ptr<LinearLeastSquaresProblem> problem =
+        CreateLinearLeastSquaresProblemFromId(problem_id);
 
     CHECK(problem != nullptr);
     A.reset(down_cast<BlockSparseMatrix*>(problem->A.release()));
-    b.reset(problem->b.release());
-    D.reset(problem->D.release());
+    b = std::move(problem->b);
+    D = std::move(problem->D);
 
     num_cols = A->num_cols();
     num_rows = A->num_rows();
@@ -94,7 +93,7 @@
       ceres::LinearSolverType linear_solver_type,
       ceres::DenseLinearAlgebraLibraryType dense_linear_algebra_library_type,
       ceres::SparseLinearAlgebraLibraryType sparse_linear_algebra_library_type,
-      bool use_postordering) {
+      ceres::internal::OrderingType ordering_type) {
     SetUpFromProblemId(problem_id);
     LinearSolver::Options options;
     options.elimination_groups.push_back(num_eliminate_blocks);
@@ -105,7 +104,7 @@
         dense_linear_algebra_library_type;
     options.sparse_linear_algebra_library_type =
         sparse_linear_algebra_library_type;
-    options.use_postordering = use_postordering;
+    options.ordering_type = ordering_type;
     ContextImpl context;
     options.context = &context;
     DetectStructure(*A->block_structure(),
@@ -123,7 +122,7 @@
     }
 
     summary = solver->Solve(A.get(), b.get(), per_solve_options, x.data());
-    EXPECT_EQ(summary.termination_type, LINEAR_SOLVER_SUCCESS);
+    EXPECT_EQ(summary.termination_type, LinearSolverTerminationType::SUCCESS);
 
     if (regularization) {
       ASSERT_NEAR((sol_d - x).norm() / num_cols, 0, 1e-10)
@@ -151,98 +150,173 @@
 // TODO(sameeragarwal): Refactor these using value parameterized tests.
 // TODO(sameeragarwal): More extensive tests using random matrices.
 TEST_F(SchurComplementSolverTest, DenseSchurWithEigenSmallProblem) {
-  ComputeAndCompareSolutions(2, false, DENSE_SCHUR, EIGEN, SUITE_SPARSE, true);
-  ComputeAndCompareSolutions(2, true, DENSE_SCHUR, EIGEN, SUITE_SPARSE, true);
+  ComputeAndCompareSolutions(
+      2, false, DENSE_SCHUR, EIGEN, SUITE_SPARSE, OrderingType::NATURAL);
+  ComputeAndCompareSolutions(
+      2, true, DENSE_SCHUR, EIGEN, SUITE_SPARSE, OrderingType::NATURAL);
 }
 
 TEST_F(SchurComplementSolverTest, DenseSchurWithEigenLargeProblem) {
-  ComputeAndCompareSolutions(3, false, DENSE_SCHUR, EIGEN, SUITE_SPARSE, true);
-  ComputeAndCompareSolutions(3, true, DENSE_SCHUR, EIGEN, SUITE_SPARSE, true);
+  ComputeAndCompareSolutions(
+      3, false, DENSE_SCHUR, EIGEN, SUITE_SPARSE, OrderingType::NATURAL);
+  ComputeAndCompareSolutions(
+      3, true, DENSE_SCHUR, EIGEN, SUITE_SPARSE, OrderingType::NATURAL);
 }
 
 TEST_F(SchurComplementSolverTest, DenseSchurWithEigenVaryingFBlockSize) {
-  ComputeAndCompareSolutions(4, true, DENSE_SCHUR, EIGEN, SUITE_SPARSE, true);
+  ComputeAndCompareSolutions(
+      4, true, DENSE_SCHUR, EIGEN, SUITE_SPARSE, OrderingType::NATURAL);
 }
 
 #ifndef CERES_NO_LAPACK
 TEST_F(SchurComplementSolverTest, DenseSchurWithLAPACKSmallProblem) {
-  ComputeAndCompareSolutions(2, false, DENSE_SCHUR, LAPACK, SUITE_SPARSE, true);
-  ComputeAndCompareSolutions(2, true, DENSE_SCHUR, LAPACK, SUITE_SPARSE, true);
+  ComputeAndCompareSolutions(
+      2, false, DENSE_SCHUR, LAPACK, SUITE_SPARSE, OrderingType::NATURAL);
+  ComputeAndCompareSolutions(
+      2, true, DENSE_SCHUR, LAPACK, SUITE_SPARSE, OrderingType::NATURAL);
 }
 
 TEST_F(SchurComplementSolverTest, DenseSchurWithLAPACKLargeProblem) {
-  ComputeAndCompareSolutions(3, false, DENSE_SCHUR, LAPACK, SUITE_SPARSE, true);
-  ComputeAndCompareSolutions(3, true, DENSE_SCHUR, LAPACK, SUITE_SPARSE, true);
+  ComputeAndCompareSolutions(
+      3, false, DENSE_SCHUR, LAPACK, SUITE_SPARSE, OrderingType::NATURAL);
+  ComputeAndCompareSolutions(
+      3, true, DENSE_SCHUR, LAPACK, SUITE_SPARSE, OrderingType::NATURAL);
 }
 #endif
 
 #ifndef CERES_NO_SUITESPARSE
 TEST_F(SchurComplementSolverTest,
-       SparseSchurWithSuiteSparseSmallProblemNoPostOrdering) {
+       SparseSchurWithSuiteSparseSmallProblemNATURAL) {
   ComputeAndCompareSolutions(
-      2, false, SPARSE_SCHUR, EIGEN, SUITE_SPARSE, false);
-  ComputeAndCompareSolutions(2, true, SPARSE_SCHUR, EIGEN, SUITE_SPARSE, false);
-}
-
-TEST_F(SchurComplementSolverTest,
-       SparseSchurWithSuiteSparseSmallProblemPostOrdering) {
-  ComputeAndCompareSolutions(2, false, SPARSE_SCHUR, EIGEN, SUITE_SPARSE, true);
-  ComputeAndCompareSolutions(2, true, SPARSE_SCHUR, EIGEN, SUITE_SPARSE, true);
-}
-
-TEST_F(SchurComplementSolverTest,
-       SparseSchurWithSuiteSparseLargeProblemNoPostOrdering) {
+      2, false, SPARSE_SCHUR, EIGEN, SUITE_SPARSE, OrderingType::NATURAL);
   ComputeAndCompareSolutions(
-      3, false, SPARSE_SCHUR, EIGEN, SUITE_SPARSE, false);
-  ComputeAndCompareSolutions(3, true, SPARSE_SCHUR, EIGEN, SUITE_SPARSE, false);
+      2, true, SPARSE_SCHUR, EIGEN, SUITE_SPARSE, OrderingType::NATURAL);
 }
 
 TEST_F(SchurComplementSolverTest,
-       SparseSchurWithSuiteSparseLargeProblemPostOrdering) {
-  ComputeAndCompareSolutions(3, false, SPARSE_SCHUR, EIGEN, SUITE_SPARSE, true);
-  ComputeAndCompareSolutions(3, true, SPARSE_SCHUR, EIGEN, SUITE_SPARSE, true);
+       SparseSchurWithSuiteSparseLargeProblemNATURAL) {
+  ComputeAndCompareSolutions(
+      3, false, SPARSE_SCHUR, EIGEN, SUITE_SPARSE, OrderingType::NATURAL);
+  ComputeAndCompareSolutions(
+      3, true, SPARSE_SCHUR, EIGEN, SUITE_SPARSE, OrderingType::NATURAL);
 }
+
+TEST_F(SchurComplementSolverTest, SparseSchurWithSuiteSparseSmallProblemAMD) {
+  ComputeAndCompareSolutions(
+      2, false, SPARSE_SCHUR, EIGEN, SUITE_SPARSE, OrderingType::AMD);
+  ComputeAndCompareSolutions(
+      2, true, SPARSE_SCHUR, EIGEN, SUITE_SPARSE, OrderingType::AMD);
+}
+
+TEST_F(SchurComplementSolverTest, SparseSchurWithSuiteSparseLargeProblemAMD) {
+  ComputeAndCompareSolutions(
+      3, false, SPARSE_SCHUR, EIGEN, SUITE_SPARSE, OrderingType::AMD);
+  ComputeAndCompareSolutions(
+      3, true, SPARSE_SCHUR, EIGEN, SUITE_SPARSE, OrderingType::AMD);
+}
+
+#ifndef CERES_NO_EIGEN_METIS
+TEST_F(SchurComplementSolverTest,
+       SparseSchurWithSuiteSparseSmallProblemNESDIS) {
+  ComputeAndCompareSolutions(
+      2, false, SPARSE_SCHUR, EIGEN, SUITE_SPARSE, OrderingType::NESDIS);
+  ComputeAndCompareSolutions(
+      2, true, SPARSE_SCHUR, EIGEN, SUITE_SPARSE, OrderingType::NESDIS);
+}
+TEST_F(SchurComplementSolverTest,
+       SparseSchurWithSuiteSparseLargeProblemNESDIS) {
+  ComputeAndCompareSolutions(
+      3, false, SPARSE_SCHUR, EIGEN, SUITE_SPARSE, OrderingType::NESDIS);
+  ComputeAndCompareSolutions(
+      3, true, SPARSE_SCHUR, EIGEN, SUITE_SPARSE, OrderingType::NESDIS);
+}
+#endif  // CERES_NO_EIGEN_METIS
 #endif  // CERES_NO_SUITESPARSE
 
-#ifndef CERES_NO_CXSPARSE
-TEST_F(SchurComplementSolverTest, SparseSchurWithCXSparseSmallProblem) {
-  ComputeAndCompareSolutions(2, false, SPARSE_SCHUR, EIGEN, CX_SPARSE, true);
-  ComputeAndCompareSolutions(2, true, SPARSE_SCHUR, EIGEN, CX_SPARSE, true);
-}
-
-TEST_F(SchurComplementSolverTest, SparseSchurWithCXSparseLargeProblem) {
-  ComputeAndCompareSolutions(3, false, SPARSE_SCHUR, EIGEN, CX_SPARSE, true);
-  ComputeAndCompareSolutions(3, true, SPARSE_SCHUR, EIGEN, CX_SPARSE, true);
-}
-#endif  // CERES_NO_CXSPARSE
-
 #ifndef CERES_NO_ACCELERATE_SPARSE
-TEST_F(SchurComplementSolverTest, SparseSchurWithAccelerateSparseSmallProblem) {
+TEST_F(SchurComplementSolverTest,
+       SparseSchurWithAccelerateSparseSmallProblemAMD) {
   ComputeAndCompareSolutions(
-      2, false, SPARSE_SCHUR, EIGEN, ACCELERATE_SPARSE, true);
+      2, false, SPARSE_SCHUR, EIGEN, ACCELERATE_SPARSE, OrderingType::AMD);
   ComputeAndCompareSolutions(
-      2, true, SPARSE_SCHUR, EIGEN, ACCELERATE_SPARSE, true);
+      2, true, SPARSE_SCHUR, EIGEN, ACCELERATE_SPARSE, OrderingType::AMD);
 }
 
-TEST_F(SchurComplementSolverTest, SparseSchurWithAccelerateSparseLargeProblem) {
+TEST_F(SchurComplementSolverTest,
+       SparseSchurWithAccelerateSparseSmallProblemNESDIS) {
   ComputeAndCompareSolutions(
-      3, false, SPARSE_SCHUR, EIGEN, ACCELERATE_SPARSE, true);
+      2, false, SPARSE_SCHUR, EIGEN, ACCELERATE_SPARSE, OrderingType::NESDIS);
   ComputeAndCompareSolutions(
-      3, true, SPARSE_SCHUR, EIGEN, ACCELERATE_SPARSE, true);
+      2, true, SPARSE_SCHUR, EIGEN, ACCELERATE_SPARSE, OrderingType::NESDIS);
+}
+
+TEST_F(SchurComplementSolverTest,
+       SparseSchurWithAccelerateSparseLargeProblemAMD) {
+  ComputeAndCompareSolutions(
+      3, false, SPARSE_SCHUR, EIGEN, ACCELERATE_SPARSE, OrderingType::AMD);
+  ComputeAndCompareSolutions(
+      3, true, SPARSE_SCHUR, EIGEN, ACCELERATE_SPARSE, OrderingType::AMD);
+}
+
+TEST_F(SchurComplementSolverTest,
+       SparseSchurWithAccelerateSparseLargeProblemNESDIS) {
+  ComputeAndCompareSolutions(
+      3, false, SPARSE_SCHUR, EIGEN, ACCELERATE_SPARSE, OrderingType::NESDIS);
+  ComputeAndCompareSolutions(
+      3, true, SPARSE_SCHUR, EIGEN, ACCELERATE_SPARSE, OrderingType::NESDIS);
 }
 #endif  // CERES_NO_ACCELERATE_SPARSE
 
 #ifdef CERES_USE_EIGEN_SPARSE
-TEST_F(SchurComplementSolverTest, SparseSchurWithEigenSparseSmallProblem) {
-  ComputeAndCompareSolutions(2, false, SPARSE_SCHUR, EIGEN, EIGEN_SPARSE, true);
-  ComputeAndCompareSolutions(2, true, SPARSE_SCHUR, EIGEN, EIGEN_SPARSE, true);
+TEST_F(SchurComplementSolverTest, SparseSchurWithEigenSparseSmallProblemAMD) {
+  ComputeAndCompareSolutions(
+      2, false, SPARSE_SCHUR, EIGEN, EIGEN_SPARSE, OrderingType::AMD);
+  ComputeAndCompareSolutions(
+      2, true, SPARSE_SCHUR, EIGEN, EIGEN_SPARSE, OrderingType::AMD);
 }
 
-TEST_F(SchurComplementSolverTest, SparseSchurWithEigenSparseLargeProblem) {
-  ComputeAndCompareSolutions(3, false, SPARSE_SCHUR, EIGEN, EIGEN_SPARSE, true);
-  ComputeAndCompareSolutions(3, true, SPARSE_SCHUR, EIGEN, EIGEN_SPARSE, true);
+#ifndef CERES_NO_EIGEN_METIS
+TEST_F(SchurComplementSolverTest,
+       SparseSchurWithEigenSparseSmallProblemNESDIS) {
+  ComputeAndCompareSolutions(
+      2, false, SPARSE_SCHUR, EIGEN, EIGEN_SPARSE, OrderingType::NESDIS);
+  ComputeAndCompareSolutions(
+      2, true, SPARSE_SCHUR, EIGEN, EIGEN_SPARSE, OrderingType::NESDIS);
+}
+#endif
+
+TEST_F(SchurComplementSolverTest,
+       SparseSchurWithEigenSparseSmallProblemNATURAL) {
+  ComputeAndCompareSolutions(
+      2, false, SPARSE_SCHUR, EIGEN, EIGEN_SPARSE, OrderingType::NATURAL);
+  ComputeAndCompareSolutions(
+      2, true, SPARSE_SCHUR, EIGEN, EIGEN_SPARSE, OrderingType::NATURAL);
+}
+
+TEST_F(SchurComplementSolverTest, SparseSchurWithEigenSparseLargeProblemAMD) {
+  ComputeAndCompareSolutions(
+      3, false, SPARSE_SCHUR, EIGEN, EIGEN_SPARSE, OrderingType::AMD);
+  ComputeAndCompareSolutions(
+      3, true, SPARSE_SCHUR, EIGEN, EIGEN_SPARSE, OrderingType::AMD);
+}
+
+#ifndef CERES_NO_EIGEN_METIS
+TEST_F(SchurComplementSolverTest,
+       SparseSchurWithEigenSparseLargeProblemNESDIS) {
+  ComputeAndCompareSolutions(
+      3, false, SPARSE_SCHUR, EIGEN, EIGEN_SPARSE, OrderingType::NESDIS);
+  ComputeAndCompareSolutions(
+      3, true, SPARSE_SCHUR, EIGEN, EIGEN_SPARSE, OrderingType::NESDIS);
+}
+#endif
+
+TEST_F(SchurComplementSolverTest,
+       SparseSchurWithEigenSparseLargeProblemNATURAL) {
+  ComputeAndCompareSolutions(
+      3, false, SPARSE_SCHUR, EIGEN, EIGEN_SPARSE, OrderingType::NATURAL);
+  ComputeAndCompareSolutions(
+      3, true, SPARSE_SCHUR, EIGEN, EIGEN_SPARSE, OrderingType::NATURAL);
 }
 #endif  // CERES_USE_EIGEN_SPARSE
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/schur_eliminator.cc b/third_party/ceres/internal/ceres/schur_eliminator.cc
index 613ae95..cb079b5 100644
--- a/third_party/ceres/internal/ceres/schur_eliminator.cc
+++ b/third_party/ceres/internal/ceres/schur_eliminator.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -39,122 +39,125 @@
 //
 // This file is generated using generate_template_specializations.py.
 
+#include <memory>
+
 #include "ceres/linear_solver.h"
 #include "ceres/schur_eliminator.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
-SchurEliminatorBase* SchurEliminatorBase::Create(
+SchurEliminatorBase::~SchurEliminatorBase() = default;
+
+std::unique_ptr<SchurEliminatorBase> SchurEliminatorBase::Create(
     const LinearSolver::Options& options) {
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
   if ((options.row_block_size == 2) &&
      (options.e_block_size == 2) &&
      (options.f_block_size == 2)) {
-    return new SchurEliminator<2, 2, 2>(options);
+    return std::make_unique<SchurEliminator<2, 2, 2>>(options);
   }
   if ((options.row_block_size == 2) &&
      (options.e_block_size == 2) &&
      (options.f_block_size == 3)) {
-    return new SchurEliminator<2, 2, 3>(options);
+    return std::make_unique<SchurEliminator<2, 2, 3>>(options);
   }
   if ((options.row_block_size == 2) &&
      (options.e_block_size == 2) &&
      (options.f_block_size == 4)) {
-    return new SchurEliminator<2, 2, 4>(options);
+    return std::make_unique<SchurEliminator<2, 2, 4>>(options);
   }
   if ((options.row_block_size == 2) &&
      (options.e_block_size == 2)) {
-    return new SchurEliminator<2, 2, Eigen::Dynamic>(options);
+    return std::make_unique<SchurEliminator<2, 2, Eigen::Dynamic>>(options);
   }
   if ((options.row_block_size == 2) &&
      (options.e_block_size == 3) &&
      (options.f_block_size == 3)) {
-    return new SchurEliminator<2, 3, 3>(options);
+    return std::make_unique<SchurEliminator<2, 3, 3>>(options);
   }
   if ((options.row_block_size == 2) &&
      (options.e_block_size == 3) &&
      (options.f_block_size == 4)) {
-    return new SchurEliminator<2, 3, 4>(options);
+    return std::make_unique<SchurEliminator<2, 3, 4>>(options);
   }
   if ((options.row_block_size == 2) &&
      (options.e_block_size == 3) &&
      (options.f_block_size == 6)) {
-    return new SchurEliminator<2, 3, 6>(options);
+    return std::make_unique<SchurEliminator<2, 3, 6>>(options);
   }
   if ((options.row_block_size == 2) &&
      (options.e_block_size == 3) &&
      (options.f_block_size == 9)) {
-    return new SchurEliminator<2, 3, 9>(options);
+    return std::make_unique<SchurEliminator<2, 3, 9>>(options);
   }
   if ((options.row_block_size == 2) &&
      (options.e_block_size == 3)) {
-    return new SchurEliminator<2, 3, Eigen::Dynamic>(options);
+    return std::make_unique<SchurEliminator<2, 3, Eigen::Dynamic>>(options);
   }
   if ((options.row_block_size == 2) &&
      (options.e_block_size == 4) &&
      (options.f_block_size == 3)) {
-    return new SchurEliminator<2, 4, 3>(options);
+    return std::make_unique<SchurEliminator<2, 4, 3>>(options);
   }
   if ((options.row_block_size == 2) &&
      (options.e_block_size == 4) &&
      (options.f_block_size == 4)) {
-    return new SchurEliminator<2, 4, 4>(options);
+    return std::make_unique<SchurEliminator<2, 4, 4>>(options);
   }
   if ((options.row_block_size == 2) &&
      (options.e_block_size == 4) &&
      (options.f_block_size == 6)) {
-    return new SchurEliminator<2, 4, 6>(options);
+    return std::make_unique<SchurEliminator<2, 4, 6>>(options);
   }
   if ((options.row_block_size == 2) &&
      (options.e_block_size == 4) &&
      (options.f_block_size == 8)) {
-    return new SchurEliminator<2, 4, 8>(options);
+    return std::make_unique<SchurEliminator<2, 4, 8>>(options);
   }
   if ((options.row_block_size == 2) &&
      (options.e_block_size == 4) &&
      (options.f_block_size == 9)) {
-    return new SchurEliminator<2, 4, 9>(options);
+    return std::make_unique<SchurEliminator<2, 4, 9>>(options);
   }
   if ((options.row_block_size == 2) &&
      (options.e_block_size == 4)) {
-    return new SchurEliminator<2, 4, Eigen::Dynamic>(options);
+    return std::make_unique<SchurEliminator<2, 4, Eigen::Dynamic>>(options);
   }
   if (options.row_block_size == 2) {
-    return new SchurEliminator<2, Eigen::Dynamic, Eigen::Dynamic>(options);
+    return std::make_unique<SchurEliminator<2, Eigen::Dynamic, Eigen::Dynamic>>(options);
   }
   if ((options.row_block_size == 3) &&
      (options.e_block_size == 3) &&
      (options.f_block_size == 3)) {
-    return new SchurEliminator<3, 3, 3>(options);
+    return std::make_unique<SchurEliminator<3, 3, 3>>(options);
   }
   if ((options.row_block_size == 4) &&
      (options.e_block_size == 4) &&
      (options.f_block_size == 2)) {
-    return new SchurEliminator<4, 4, 2>(options);
+    return std::make_unique<SchurEliminator<4, 4, 2>>(options);
   }
   if ((options.row_block_size == 4) &&
      (options.e_block_size == 4) &&
      (options.f_block_size == 3)) {
-    return new SchurEliminator<4, 4, 3>(options);
+    return std::make_unique<SchurEliminator<4, 4, 3>>(options);
   }
   if ((options.row_block_size == 4) &&
      (options.e_block_size == 4) &&
      (options.f_block_size == 4)) {
-    return new SchurEliminator<4, 4, 4>(options);
+    return std::make_unique<SchurEliminator<4, 4, 4>>(options);
   }
   if ((options.row_block_size == 4) &&
      (options.e_block_size == 4)) {
-    return new SchurEliminator<4, 4, Eigen::Dynamic>(options);
+    return std::make_unique<SchurEliminator<4, 4, Eigen::Dynamic>>(options);
   }
 
 #endif
   VLOG(1) << "Template specializations not found for <"
           << options.row_block_size << "," << options.e_block_size << ","
           << options.f_block_size << ">";
-  return new SchurEliminator<Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic>(
-      options);
+  return std::make_unique<SchurEliminator<Eigen::Dynamic,
+                                          Eigen::Dynamic,
+                                          Eigen::Dynamic>>(options);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/schur_eliminator.h b/third_party/ceres/internal/ceres/schur_eliminator.h
index 2ce0bdc..3832fe6 100644
--- a/third_party/ceres/internal/ceres/schur_eliminator.h
+++ b/third_party/ceres/internal/ceres/schur_eliminator.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,12 +40,13 @@
 #include "ceres/block_random_access_matrix.h"
 #include "ceres/block_sparse_matrix.h"
 #include "ceres/block_structure.h"
+#include "ceres/internal/config.h"
+#include "ceres/internal/disable_warnings.h"
 #include "ceres/internal/eigen.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 #include "ceres/linear_solver.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // Classes implementing the SchurEliminatorBase interface implement
 // variable elimination for linear least squares problems. Assuming
@@ -56,9 +57,8 @@
 // Where x = [y;z] is a partition of the variables.  The partitioning
 // of the variables is such that, E'E is a block diagonal matrix. Or
 // in other words, the parameter blocks in E form an independent set
-// of the of the graph implied by the block matrix A'A. Then, this
-// class provides the functionality to compute the Schur complement
-// system
+// of the graph implied by the block matrix A'A. Then, this class
+// provides the functionality to compute the Schur complement system
 //
 //   S z = r
 //
@@ -164,13 +164,13 @@
 // 2008 for an example of such use].
 //
 // Example usage: Please see schur_complement_solver.cc
-class CERES_EXPORT_INTERNAL SchurEliminatorBase {
+class CERES_NO_EXPORT SchurEliminatorBase {
  public:
-  virtual ~SchurEliminatorBase() {}
+  virtual ~SchurEliminatorBase();
 
-  // Initialize the eliminator. It is the user's responsibilty to call
+  // Initialize the eliminator. It is the user's responsibility to call
   // this function before calling Eliminate or BackSubstitute. It is
-  // also the caller's responsibilty to ensure that the
+  // also the caller's responsibility to ensure that the
   // CompressedRowBlockStructure object passed to this method is the
   // same one (or is equivalent to) the one associated with the
   // BlockSparseMatrix objects below.
@@ -210,7 +210,8 @@
                               const double* z,
                               double* y) = 0;
   // Factory
-  static SchurEliminatorBase* Create(const LinearSolver::Options& options);
+  static std::unique_ptr<SchurEliminatorBase> Create(
+      const LinearSolver::Options& options);
 };
 
 // Templated implementation of the SchurEliminatorBase interface. The
@@ -223,7 +224,7 @@
 template <int kRowBlockSize = Eigen::Dynamic,
           int kEBlockSize = Eigen::Dynamic,
           int kFBlockSize = Eigen::Dynamic>
-class SchurEliminator : public SchurEliminatorBase {
+class CERES_NO_EXPORT SchurEliminator final : public SchurEliminatorBase {
  public:
   explicit SchurEliminator(const LinearSolver::Options& options)
       : num_threads_(options.num_threads), context_(options.context) {
@@ -231,7 +232,7 @@
   }
 
   // SchurEliminatorBase Interface
-  virtual ~SchurEliminator();
+  ~SchurEliminator() override;
   void Init(int num_eliminate_blocks,
             bool assume_full_rank_ete,
             const CompressedRowBlockStructure* bs) final;
@@ -272,9 +273,9 @@
   // buffer_layout[z1] = 0
   // buffer_layout[z5] = y1 * z1
   // buffer_layout[z2] = y1 * z1 + y1 * z5
-  typedef std::map<int, int> BufferLayoutType;
+  using BufferLayoutType = std::map<int, int>;
   struct Chunk {
-    Chunk(int new_start) : size(0), start(new_start) {}
+    explicit Chunk(int start) : size(0), start(start) {}
     int size;
     int start;
     BufferLayoutType buffer_layout;
@@ -378,11 +379,12 @@
 template <int kRowBlockSize = Eigen::Dynamic,
           int kEBlockSize = Eigen::Dynamic,
           int kFBlockSize = Eigen::Dynamic>
-class SchurEliminatorForOneFBlock : public SchurEliminatorBase {
+class CERES_NO_EXPORT SchurEliminatorForOneFBlock final
+    : public SchurEliminatorBase {
  public:
-  virtual ~SchurEliminatorForOneFBlock() {}
+  // TODO(sameeragarwal) Find out why "assume_full_rank_ete" is not used here
   void Init(int num_eliminate_blocks,
-            bool assume_full_rank_ete,
+            bool /*assume_full_rank_ete*/,
             const CompressedRowBlockStructure* bs) override {
     CHECK_GT(num_eliminate_blocks, 0)
         << "SchurComplementSolver cannot be initialized with "
@@ -445,7 +447,7 @@
     const CompressedRowBlockStructure* bs = A.block_structure();
     const double* values = A.values();
 
-    // Add the diagonal to the schur complement.
+    // Add the diagonal to the Schur complement.
     if (D != nullptr) {
       typename EigenTypes<kFBlockSize>::ConstVectorRef diag(
           D + bs->cols[num_eliminate_blocks_].position, kFBlockSize);
@@ -477,14 +479,14 @@
       const Chunk& chunk = chunks_[i];
       const int e_block_id = bs->rows[chunk.start].cells.front().block_id;
 
-      // Naming covention, e_t_e = e_block.transpose() * e_block;
+      // Naming convention, e_t_e = e_block.transpose() * e_block;
       Eigen::Matrix<double, kEBlockSize, kEBlockSize> e_t_e;
       Eigen::Matrix<double, kEBlockSize, kFBlockSize> e_t_f;
       Eigen::Matrix<double, kEBlockSize, 1> e_t_b;
       Eigen::Matrix<double, kFBlockSize, 1> f_t_b;
 
       // Add the square of the diagonal to e_t_e.
-      if (D != NULL) {
+      if (D != nullptr) {
         const typename EigenTypes<kEBlockSize>::ConstVectorRef diag(
             D + bs->cols[e_block_id].position, kEBlockSize);
         e_t_e = diag.array().square().matrix().asDiagonal();
@@ -568,7 +570,7 @@
   // y_i = e_t_e_inverse * sum_i e_i^T * (b_i - f_i * z);
   void BackSubstitute(const BlockSparseMatrixData& A,
                       const double* b,
-                      const double* D,
+                      const double* /*D*/,
                       const double* z_ptr,
                       double* y) override {
     typename EigenTypes<kFBlockSize>::ConstVectorRef z(z_ptr, kFBlockSize);
@@ -621,7 +623,8 @@
   std::vector<double> e_t_e_inverse_matrices_;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_SCHUR_ELIMINATOR_H_
diff --git a/third_party/ceres/internal/ceres/schur_eliminator_benchmark.cc b/third_party/ceres/internal/ceres/schur_eliminator_benchmark.cc
index 6307025..78aa580 100644
--- a/third_party/ceres/internal/ceres/schur_eliminator_benchmark.cc
+++ b/third_party/ceres/internal/ceres/schur_eliminator_benchmark.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -28,16 +28,19 @@
 //
 // Authors: sameeragarwal@google.com (Sameer Agarwal)
 
+#include <algorithm>
+#include <memory>
+#include <random>
+#include <vector>
+
 #include "Eigen/Dense"
 #include "benchmark/benchmark.h"
 #include "ceres/block_random_access_dense_matrix.h"
 #include "ceres/block_sparse_matrix.h"
 #include "ceres/block_structure.h"
-#include "ceres/random.h"
 #include "ceres/schur_eliminator.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 constexpr int kRowBlockSize = 2;
 constexpr int kEBlockSize = 3;
@@ -46,7 +49,7 @@
 class BenchmarkData {
  public:
   explicit BenchmarkData(const int num_e_blocks) {
-    CompressedRowBlockStructure* bs = new CompressedRowBlockStructure;
+    auto* bs = new CompressedRowBlockStructure;
     bs->cols.resize(num_e_blocks + 1);
     int col_pos = 0;
     for (int i = 0; i < num_e_blocks; ++i) {
@@ -88,17 +91,18 @@
       }
     }
 
-    matrix_.reset(new BlockSparseMatrix(bs));
+    matrix_ = std::make_unique<BlockSparseMatrix>(bs);
     double* values = matrix_->mutable_values();
-    for (int i = 0; i < matrix_->num_nonzeros(); ++i) {
-      values[i] = RandNormal();
-    }
+    std::generate_n(values, matrix_->num_nonzeros(), [this] {
+      return standard_normal_(prng_);
+    });
 
     b_.resize(matrix_->num_rows());
     b_.setRandom();
 
-    std::vector<int> blocks(1, kFBlockSize);
-    lhs_.reset(new BlockRandomAccessDenseMatrix(blocks));
+    std::vector<Block> blocks;
+    blocks.emplace_back(kFBlockSize, 0);
+    lhs_ = std::make_unique<BlockRandomAccessDenseMatrix>(blocks, &context_, 1);
     diagonal_.resize(matrix_->num_cols());
     diagonal_.setOnes();
     rhs_.resize(kFBlockSize);
@@ -117,7 +121,11 @@
   Vector* mutable_y() { return &y_; }
   Vector* mutable_z() { return &z_; }
 
+  ContextImpl* context() { return &context_; }
+
  private:
+  ContextImpl context_;
+
   std::unique_ptr<BlockSparseMatrix> matrix_;
   Vector b_;
   std::unique_ptr<BlockRandomAccessDenseMatrix> lhs_;
@@ -125,18 +133,19 @@
   Vector diagonal_;
   Vector z_;
   Vector y_;
+  std::mt19937 prng_;
+  std::normal_distribution<> standard_normal_;
 };
 
-void BM_SchurEliminatorEliminate(benchmark::State& state) {
+static void BM_SchurEliminatorEliminate(benchmark::State& state) {
   const int num_e_blocks = state.range(0);
   BenchmarkData data(num_e_blocks);
 
-  ContextImpl context;
   LinearSolver::Options linear_solver_options;
   linear_solver_options.e_block_size = kEBlockSize;
   linear_solver_options.row_block_size = kRowBlockSize;
   linear_solver_options.f_block_size = kFBlockSize;
-  linear_solver_options.context = &context;
+  linear_solver_options.context = data.context();
   std::unique_ptr<SchurEliminatorBase> eliminator(
       SchurEliminatorBase::Create(linear_solver_options));
 
@@ -150,16 +159,15 @@
   }
 }
 
-void BM_SchurEliminatorBackSubstitute(benchmark::State& state) {
+static void BM_SchurEliminatorBackSubstitute(benchmark::State& state) {
   const int num_e_blocks = state.range(0);
   BenchmarkData data(num_e_blocks);
 
-  ContextImpl context;
   LinearSolver::Options linear_solver_options;
   linear_solver_options.e_block_size = kEBlockSize;
   linear_solver_options.row_block_size = kRowBlockSize;
   linear_solver_options.f_block_size = kFBlockSize;
-  linear_solver_options.context = &context;
+  linear_solver_options.context = data.context();
   std::unique_ptr<SchurEliminatorBase> eliminator(
       SchurEliminatorBase::Create(linear_solver_options));
 
@@ -178,7 +186,7 @@
   }
 }
 
-void BM_SchurEliminatorForOneFBlockEliminate(benchmark::State& state) {
+static void BM_SchurEliminatorForOneFBlockEliminate(benchmark::State& state) {
   const int num_e_blocks = state.range(0);
   BenchmarkData data(num_e_blocks);
   SchurEliminatorForOneFBlock<2, 3, 6> eliminator;
@@ -192,7 +200,8 @@
   }
 }
 
-void BM_SchurEliminatorForOneFBlockBackSubstitute(benchmark::State& state) {
+static void BM_SchurEliminatorForOneFBlockBackSubstitute(
+    benchmark::State& state) {
   const int num_e_blocks = state.range(0);
   BenchmarkData data(num_e_blocks);
   SchurEliminatorForOneFBlock<2, 3, 6> eliminator;
@@ -216,7 +225,6 @@
 BENCHMARK(BM_SchurEliminatorBackSubstitute)->Range(10, 10000);
 BENCHMARK(BM_SchurEliminatorForOneFBlockBackSubstitute)->Range(10, 10000);
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 BENCHMARK_MAIN();
diff --git a/third_party/ceres/internal/ceres/schur_eliminator_impl.h b/third_party/ceres/internal/ceres/schur_eliminator_impl.h
index 9b2ff0e..ef5ce66 100644
--- a/third_party/ceres/internal/ceres/schur_eliminator_impl.h
+++ b/third_party/ceres/internal/ceres/schur_eliminator_impl.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -47,7 +47,7 @@
 
 // This include must come before any #ifndef check on Ceres compile options.
 // clang-format off
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 // clang-format on
 
 #include <algorithm>
@@ -69,8 +69,7 @@
 #include "ceres/thread_token_provider.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
 SchurEliminator<kRowBlockSize, kEBlockSize, kFBlockSize>::~SchurEliminator() {
@@ -107,7 +106,7 @@
   }
 
   // TODO(sameeragarwal): Now that we may have subset block structure,
-  // we need to make sure that we account for the fact that somep
+  // we need to make sure that we account for the fact that some
   // point blocks only have a "diagonal" row and nothing more.
   //
   // This likely requires a slightly different algorithm, which works
@@ -159,12 +158,13 @@
 
   uneliminated_row_begins_ = chunk.start + chunk.size;
 
-  buffer_.reset(new double[buffer_size_ * num_threads_]);
+  buffer_ = std::make_unique<double[]>(buffer_size_ * num_threads_);
 
   // chunk_outer_product_buffer_ only needs to store e_block_size *
   // f_block_size, which is always less than buffer_size_, so we just
   // allocate buffer_size_ per thread.
-  chunk_outer_product_buffer_.reset(new double[buffer_size_ * num_threads_]);
+  chunk_outer_product_buffer_ =
+      std::make_unique<double[]>(buffer_size_ * num_threads_);
 
   STLDeleteElements(&rhs_locks_);
   rhs_locks_.resize(num_col_blocks - num_eliminate_blocks_);
@@ -191,7 +191,7 @@
   const int num_col_blocks = bs->cols.size();
 
   // Add the diagonal to the schur complement.
-  if (D != NULL) {
+  if (D != nullptr) {
     ParallelFor(context_,
                 num_eliminate_blocks_,
                 num_col_blocks,
@@ -201,12 +201,10 @@
                   int r, c, row_stride, col_stride;
                   CellInfo* cell_info = lhs->GetCell(
                       block_id, block_id, &r, &c, &row_stride, &col_stride);
-                  if (cell_info != NULL) {
+                  if (cell_info != nullptr) {
                     const int block_size = bs->cols[i].size;
                     typename EigenTypes<Eigen::Dynamic>::ConstVectorRef diag(
                         D + bs->cols[i].position, block_size);
-
-                    std::lock_guard<std::mutex> l(cell_info->m);
                     MatrixRef m(cell_info->values, row_stride, col_stride);
                     m.block(r, c, block_size, block_size).diagonal() +=
                         diag.array().square().matrix();
@@ -243,7 +241,7 @@
         typename EigenTypes<kEBlockSize, kEBlockSize>::Matrix ete(e_block_size,
                                                                   e_block_size);
 
-        if (D != NULL) {
+        if (D != nullptr) {
           const typename EigenTypes<kEBlockSize>::ConstVectorRef diag(
               D + bs->cols[e_block_id].position, e_block_size);
           ete = diag.array().square().matrix().asDiagonal();
@@ -300,7 +298,7 @@
             thread_id, bs, inverse_ete, buffer, chunk.buffer_layout, lhs);
       });
 
-  // For rows with no e_blocks, the schur complement update reduces to
+  // For rows with no e_blocks, the Schur complement update reduces to
   // S += F'F.
   NoEBlockRowsUpdate(A, b, uneliminated_row_begins_, lhs, rhs);
 }
@@ -325,7 +323,7 @@
 
     typename EigenTypes<kEBlockSize, kEBlockSize>::Matrix ete(e_block_size,
                                                               e_block_size);
-    if (D != NULL) {
+    if (D != nullptr) {
       const typename EigenTypes<kEBlockSize>::ConstVectorRef diag(
           D + bs->cols[e_block_id].position, e_block_size);
       ete = diag.array().square().matrix().asDiagonal();
@@ -409,7 +407,7 @@
       const int block_id = row.cells[c].block_id;
       const int block_size = bs->cols[block_id].size;
       const int block = block_id - num_eliminate_blocks_;
-      std::lock_guard<std::mutex> l(*rhs_locks_[block]);
+      auto lock = MakeConditionalLock(num_threads_, *rhs_locks_[block]);
       // clang-format off
       MatrixTransposeVectorMultiply<kRowBlockSize, kFBlockSize, 1>(
           values + row.cells[c].position,
@@ -432,7 +430,7 @@
 //
 //   ete = y11 * y11' + y12 * y12'
 //
-// and the off diagonal blocks in the Guass Newton Hessian.
+// and the off diagonal blocks in the Gauss Newton Hessian.
 //
 //   buffer = [y11'(z11 + z12), y12' * z22, y11' * z51]
 //
@@ -523,7 +521,7 @@
   // computation of the right-hand matrix product, but memory
   // references to the left hand side.
   const int e_block_size = inverse_ete.rows();
-  BufferLayoutType::const_iterator it1 = buffer_layout.begin();
+  auto it1 = buffer_layout.begin();
 
   double* b1_transpose_inverse_ete =
       chunk_outer_product_buffer_.get() + thread_id * buffer_size_;
@@ -540,16 +538,16 @@
         b1_transpose_inverse_ete, 0, 0, block1_size, e_block_size);
     // clang-format on
 
-    BufferLayoutType::const_iterator it2 = it1;
+    auto it2 = it1;
     for (; it2 != buffer_layout.end(); ++it2) {
       const int block2 = it2->first - num_eliminate_blocks_;
 
       int r, c, row_stride, col_stride;
       CellInfo* cell_info =
           lhs->GetCell(block1, block2, &r, &c, &row_stride, &col_stride);
-      if (cell_info != NULL) {
+      if (cell_info != nullptr) {
         const int block2_size = bs->cols[it2->first].size;
-        std::lock_guard<std::mutex> l(cell_info->m);
+        auto lock = MakeConditionalLock(num_threads_, cell_info->m);
         // clang-format off
         MatrixMatrixMultiply
             <kFBlockSize, kEBlockSize, kEBlockSize, kFBlockSize, -1>(
@@ -562,7 +560,7 @@
   }
 }
 
-// For rows with no e_blocks, the schur complement update reduces to S
+// For rows with no e_blocks, the Schur complement update reduces to S
 // += F'F. This function iterates over the rows of A with no e_block,
 // and calls NoEBlockRowOuterProduct on each row.
 template <int kRowBlockSize, int kEBlockSize, int kFBlockSize>
@@ -595,7 +593,7 @@
 }
 
 // A row r of A, which has no e_blocks gets added to the Schur
-// Complement as S += r r'. This function is responsible for computing
+// complement as S += r r'. This function is responsible for computing
 // the contribution of a single row r to the Schur complement. It is
 // very similar in structure to EBlockRowOuterProduct except for
 // one difference. It does not use any of the template
@@ -625,8 +623,8 @@
     int r, c, row_stride, col_stride;
     CellInfo* cell_info =
         lhs->GetCell(block1, block1, &r, &c, &row_stride, &col_stride);
-    if (cell_info != NULL) {
-      std::lock_guard<std::mutex> l(cell_info->m);
+    if (cell_info != nullptr) {
+      auto lock = MakeConditionalLock(num_threads_, cell_info->m);
       // This multiply currently ignores the fact that this is a
       // symmetric outer product.
       // clang-format off
@@ -645,9 +643,9 @@
       int r, c, row_stride, col_stride;
       CellInfo* cell_info =
           lhs->GetCell(block1, block2, &r, &c, &row_stride, &col_stride);
-      if (cell_info != NULL) {
+      if (cell_info != nullptr) {
         const int block2_size = bs->cols[row.cells[j].block_id].size;
-        std::lock_guard<std::mutex> l(cell_info->m);
+        auto lock = MakeConditionalLock(num_threads_, cell_info->m);
         // clang-format off
         MatrixTransposeMatrixMultiply
             <Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic, 1>(
@@ -680,8 +678,8 @@
     int r, c, row_stride, col_stride;
     CellInfo* cell_info =
         lhs->GetCell(block1, block1, &r, &c, &row_stride, &col_stride);
-    if (cell_info != NULL) {
-      std::lock_guard<std::mutex> l(cell_info->m);
+    if (cell_info != nullptr) {
+      auto lock = MakeConditionalLock(num_threads_, cell_info->m);
       // block += b1.transpose() * b1;
       // clang-format off
       MatrixTransposeMatrixMultiply
@@ -700,9 +698,9 @@
       int r, c, row_stride, col_stride;
       CellInfo* cell_info =
           lhs->GetCell(block1, block2, &r, &c, &row_stride, &col_stride);
-      if (cell_info != NULL) {
+      if (cell_info != nullptr) {
         // block += b1.transpose() * b2;
-        std::lock_guard<std::mutex> l(cell_info->m);
+        auto lock = MakeConditionalLock(num_threads_, cell_info->m);
         // clang-format off
         MatrixTransposeMatrixMultiply
             <kRowBlockSize, kFBlockSize, kRowBlockSize, kFBlockSize, 1>(
@@ -715,7 +713,6 @@
   }
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_INTERNAL_SCHUR_ELIMINATOR_IMPL_H_
diff --git a/third_party/ceres/internal/ceres/schur_eliminator_template.py b/third_party/ceres/internal/ceres/schur_eliminator_template.py
index 5051595..99e6f3e 100644
--- a/third_party/ceres/internal/ceres/schur_eliminator_template.py
+++ b/third_party/ceres/internal/ceres/schur_eliminator_template.py
@@ -1,5 +1,5 @@
 # Ceres Solver - A fast non-linear least squares minimizer
-# Copyright 2017 Google Inc. All rights reserved.
+# Copyright 2023 Google Inc. All rights reserved.
 # http://ceres-solver.org/
 #
 # Redistribution and use in source and binary forms, with or without
@@ -51,7 +51,7 @@
 # Set of template specializations to generate
 
 HEADER = """// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -95,57 +95,56 @@
 DYNAMIC_FILE = """
 #include "ceres/schur_eliminator_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class SchurEliminator<%s, %s, %s>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 """
 
 SPECIALIZATION_FILE = """
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
 
 #include "ceres/schur_eliminator_impl.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template class SchurEliminator<%s, %s, %s>;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_RESTRICT_SCHUR_SPECIALIZATION
 """
 
 FACTORY_FILE_HEADER = """
+#include <memory>
+
 #include "ceres/linear_solver.h"
 #include "ceres/schur_eliminator.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
-SchurEliminatorBase* SchurEliminatorBase::Create(
+SchurEliminatorBase::~SchurEliminatorBase() = default;
+
+std::unique_ptr<SchurEliminatorBase> SchurEliminatorBase::Create(
     const LinearSolver::Options& options) {
 #ifndef CERES_RESTRICT_SCHUR_SPECIALIZATION
 """
 
-FACTORY = """  return new SchurEliminator<%s, %s, %s>(options);"""
+FACTORY = """  return std::make_unique<SchurEliminator<%s, %s, %s>>(options);"""
 
 FACTORY_FOOTER = """
 #endif
   VLOG(1) << "Template specializations not found for <"
           << options.row_block_size << "," << options.e_block_size << ","
           << options.f_block_size << ">";
-  return new SchurEliminator<Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic>(
-      options);
+  return std::make_unique<SchurEliminator<Eigen::Dynamic,
+                                          Eigen::Dynamic,
+                                          Eigen::Dynamic>>(options);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 """
diff --git a/third_party/ceres/internal/ceres/schur_eliminator_test.cc b/third_party/ceres/internal/ceres/schur_eliminator_test.cc
index 6383ced..bdf8b8c 100644
--- a/third_party/ceres/internal/ceres/schur_eliminator_test.cc
+++ b/third_party/ceres/internal/ceres/schur_eliminator_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -30,7 +30,10 @@
 
 #include "ceres/schur_eliminator.h"
 
+#include <algorithm>
 #include <memory>
+#include <random>
+#include <vector>
 
 #include "Eigen/Dense"
 #include "ceres/block_random_access_dense_matrix.h"
@@ -41,7 +44,6 @@
 #include "ceres/detect_structure.h"
 #include "ceres/internal/eigen.h"
 #include "ceres/linear_least_squares_problems.h"
-#include "ceres/random.h"
 #include "ceres/test_util.h"
 #include "ceres/triplet_sparse_matrix.h"
 #include "ceres/types.h"
@@ -51,22 +53,20 @@
 // TODO(sameeragarwal): Reduce the size of these tests and redo the
 // parameterization to be more efficient.
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 class SchurEliminatorTest : public ::testing::Test {
  protected:
   void SetUpFromId(int id) {
-    std::unique_ptr<LinearLeastSquaresProblem> problem(
-        CreateLinearLeastSquaresProblemFromId(id));
+    auto problem = CreateLinearLeastSquaresProblemFromId(id);
     CHECK(problem != nullptr);
     SetupHelper(problem.get());
   }
 
   void SetupHelper(LinearLeastSquaresProblem* problem) {
     A.reset(down_cast<BlockSparseMatrix*>(problem->A.release()));
-    b.reset(problem->b.release());
-    D.reset(problem->D.release());
+    b = std::move(problem->b);
+    D = std::move(problem->D);
 
     num_eliminate_blocks = problem->num_eliminate_blocks;
     num_eliminate_cols = 0;
@@ -126,12 +126,8 @@
                                 const double relative_tolerance) {
     const CompressedRowBlockStructure* bs = A->block_structure();
     const int num_col_blocks = bs->cols.size();
-    std::vector<int> blocks(num_col_blocks - num_eliminate_blocks, 0);
-    for (int i = num_eliminate_blocks; i < num_col_blocks; ++i) {
-      blocks[i - num_eliminate_blocks] = bs->cols[i].size;
-    }
-
-    BlockRandomAccessDenseMatrix lhs(blocks);
+    auto blocks = Tail(bs->cols, num_col_blocks - num_eliminate_blocks);
+    BlockRandomAccessDenseMatrix lhs(blocks, &context_, 1);
 
     const int num_cols = A->num_cols();
     const int schur_size = lhs.num_rows();
@@ -139,8 +135,7 @@
     Vector rhs(schur_size);
 
     LinearSolver::Options options;
-    ContextImpl context;
-    options.context = &context;
+    options.context = &context_;
     options.elimination_groups.push_back(num_eliminate_blocks);
     if (use_static_structure) {
       DetectStructure(*bs,
@@ -150,8 +145,8 @@
                       &options.f_block_size);
     }
 
-    std::unique_ptr<SchurEliminatorBase> eliminator;
-    eliminator.reset(SchurEliminatorBase::Create(options));
+    std::unique_ptr<SchurEliminatorBase> eliminator =
+        SchurEliminatorBase::Create(options);
     const bool kFullRankETE = true;
     eliminator->Init(num_eliminate_blocks, kFullRankETE, A->block_structure());
     eliminator->Eliminate(
@@ -182,6 +177,8 @@
                 relative_tolerance);
   }
 
+  ContextImpl context_;
+
   std::unique_ptr<BlockSparseMatrix> A;
   std::unique_ptr<double[]> b;
   std::unique_ptr<double[]> D;
@@ -228,7 +225,9 @@
   constexpr int kFBlockSize = 6;
   constexpr int num_e_blocks = 5;
 
-  CompressedRowBlockStructure* bs = new CompressedRowBlockStructure;
+  ContextImpl context;
+
+  auto* bs = new CompressedRowBlockStructure;
   bs->cols.resize(num_e_blocks + 1);
   int col_pos = 0;
   for (int i = 0; i < num_e_blocks; ++i) {
@@ -284,9 +283,11 @@
 
   BlockSparseMatrix matrix(bs);
   double* values = matrix.mutable_values();
-  for (int i = 0; i < matrix.num_nonzeros(); ++i) {
-    values[i] = RandNormal();
-  }
+  std::mt19937 prng;
+  std::normal_distribution<> standard_normal;
+  std::generate_n(values, matrix.num_nonzeros(), [&prng, &standard_normal] {
+    return standard_normal(prng);
+  });
 
   Vector b(matrix.num_rows());
   b.setRandom();
@@ -294,9 +295,10 @@
   Vector diagonal(matrix.num_cols());
   diagonal.setOnes();
 
-  std::vector<int> blocks(1, kFBlockSize);
-  BlockRandomAccessDenseMatrix actual_lhs(blocks);
-  BlockRandomAccessDenseMatrix expected_lhs(blocks);
+  std::vector<Block> blocks;
+  blocks.emplace_back(kFBlockSize, 0);
+  BlockRandomAccessDenseMatrix actual_lhs(blocks, &context, 1);
+  BlockRandomAccessDenseMatrix expected_lhs(blocks, &context, 1);
   Vector actual_rhs(kFBlockSize);
   Vector expected_rhs(kFBlockSize);
 
@@ -308,7 +310,6 @@
   expected_e_sol.setZero();
 
   {
-    ContextImpl context;
     LinearSolver::Options linear_solver_options;
     linear_solver_options.e_block_size = kEBlockSize;
     linear_solver_options.row_block_size = kRowBlockSize;
@@ -369,5 +370,4 @@
       << actual_e_sol;
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/schur_jacobi_preconditioner.cc b/third_party/ceres/internal/ceres/schur_jacobi_preconditioner.cc
index 89d770b..fbe258d 100644
--- a/third_party/ceres/internal/ceres/schur_jacobi_preconditioner.cc
+++ b/third_party/ceres/internal/ceres/schur_jacobi_preconditioner.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -30,6 +30,7 @@
 
 #include "ceres/schur_jacobi_preconditioner.h"
 
+#include <memory>
 #include <utility>
 #include <vector>
 
@@ -39,30 +40,32 @@
 #include "ceres/schur_eliminator.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 SchurJacobiPreconditioner::SchurJacobiPreconditioner(
-    const CompressedRowBlockStructure& bs,
-    const Preconditioner::Options& options)
-    : options_(options) {
+    const CompressedRowBlockStructure& bs, Preconditioner::Options options)
+    : options_(std::move(options)) {
   CHECK_GT(options_.elimination_groups.size(), 1);
   CHECK_GT(options_.elimination_groups[0], 0);
   const int num_blocks = bs.cols.size() - options_.elimination_groups[0];
   CHECK_GT(num_blocks, 0) << "Jacobian should have at least 1 f_block for "
                           << "SCHUR_JACOBI preconditioner.";
-  CHECK(options_.context != NULL);
+  CHECK(options_.context != nullptr);
 
-  std::vector<int> blocks(num_blocks);
+  std::vector<Block> blocks(num_blocks);
+  int position = 0;
   for (int i = 0; i < num_blocks; ++i) {
-    blocks[i] = bs.cols[i + options_.elimination_groups[0]].size;
+    blocks[i] =
+        Block(bs.cols[i + options_.elimination_groups[0]].size, position);
+    position += blocks[i].size;
   }
 
-  m_.reset(new BlockRandomAccessDiagonalMatrix(blocks));
+  m_ = std::make_unique<BlockRandomAccessDiagonalMatrix>(
+      blocks, options_.context, options_.num_threads);
   InitEliminator(bs);
 }
 
-SchurJacobiPreconditioner::~SchurJacobiPreconditioner() {}
+SchurJacobiPreconditioner::~SchurJacobiPreconditioner() = default;
 
 // Initialize the SchurEliminator.
 void SchurJacobiPreconditioner::InitEliminator(
@@ -74,7 +77,7 @@
   eliminator_options.f_block_size = options_.f_block_size;
   eliminator_options.row_block_size = options_.row_block_size;
   eliminator_options.context = options_.context;
-  eliminator_.reset(SchurEliminatorBase::Create(eliminator_options));
+  eliminator_ = SchurEliminatorBase::Create(eliminator_options);
   const bool kFullRankETE = true;
   eliminator_->Init(
       eliminator_options.elimination_groups[0], kFullRankETE, &bs);
@@ -93,12 +96,11 @@
   return true;
 }
 
-void SchurJacobiPreconditioner::RightMultiply(const double* x,
-                                              double* y) const {
-  m_->RightMultiply(x, y);
+void SchurJacobiPreconditioner::RightMultiplyAndAccumulate(const double* x,
+                                                           double* y) const {
+  m_->RightMultiplyAndAccumulate(x, y);
 }
 
 int SchurJacobiPreconditioner::num_rows() const { return m_->num_rows(); }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/schur_jacobi_preconditioner.h b/third_party/ceres/internal/ceres/schur_jacobi_preconditioner.h
index 372b790..b540bc0 100644
--- a/third_party/ceres/internal/ceres/schur_jacobi_preconditioner.h
+++ b/third_party/ceres/internal/ceres/schur_jacobi_preconditioner.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -43,10 +43,11 @@
 #include <utility>
 #include <vector>
 
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 #include "ceres/preconditioner.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 class BlockRandomAccessDiagonalMatrix;
 class BlockSparseMatrix;
@@ -69,10 +70,13 @@
 //   options.elimination_groups.push_back(num_cameras);
 //   SchurJacobiPreconditioner preconditioner(
 //      *A.block_structure(), options);
-//   preconditioner.Update(A, NULL);
-//   preconditioner.RightMultiply(x, y);
+//   preconditioner.Update(A, nullptr);
+//   preconditioner.RightMultiplyAndAccumulate(x, y);
 //
-class SchurJacobiPreconditioner : public BlockSparseMatrixPreconditioner {
+// TODO(https://github.com/ceres-solver/ceres-solver/issues/935):
+// SchurJacobiPreconditioner::RightMultiply will benefit from multithreading
+class CERES_NO_EXPORT SchurJacobiPreconditioner
+    : public BlockSparseMatrixPreconditioner {
  public:
   // Initialize the symbolic structure of the preconditioner. bs is
   // the block structure of the linear system to be solved. It is used
@@ -81,14 +85,14 @@
   // It has the same structural requirement as other Schur complement
   // based solvers. Please see schur_eliminator.h for more details.
   SchurJacobiPreconditioner(const CompressedRowBlockStructure& bs,
-                            const Preconditioner::Options& options);
+                            Preconditioner::Options options);
   SchurJacobiPreconditioner(const SchurJacobiPreconditioner&) = delete;
   void operator=(const SchurJacobiPreconditioner&) = delete;
 
-  virtual ~SchurJacobiPreconditioner();
+  ~SchurJacobiPreconditioner() override;
 
   // Preconditioner interface.
-  void RightMultiply(const double* x, double* y) const final;
+  void RightMultiplyAndAccumulate(const double* x, double* y) const final;
   int num_rows() const final;
 
  private:
@@ -101,7 +105,8 @@
   std::unique_ptr<BlockRandomAccessDiagonalMatrix> m_;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_SCHUR_JACOBI_PRECONDITIONER_H_
diff --git a/third_party/ceres/internal/ceres/schur_templates.cc b/third_party/ceres/internal/ceres/schur_templates.cc
index bcf0d14..95df671 100644
--- a/third_party/ceres/internal/ceres/schur_templates.cc
+++ b/third_party/ceres/internal/ceres/schur_templates.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
diff --git a/third_party/ceres/internal/ceres/schur_templates.h b/third_party/ceres/internal/ceres/schur_templates.h
index 90aee0a..218fb51 100644
--- a/third_party/ceres/internal/ceres/schur_templates.h
+++ b/third_party/ceres/internal/ceres/schur_templates.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -32,15 +32,16 @@
 #ifndef CERES_INTERNAL_SCHUR_TEMPLATES_H_
 #define CERES_INTERNAL_SCHUR_TEMPLATES_H_
 
+#include "ceres/internal/config.h"
+#include "ceres/internal/export.h"
 #include "ceres/linear_solver.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
+CERES_NO_EXPORT
 void GetBestSchurTemplateSpecialization(int* row_block_size,
                                         int* e_block_size,
                                         int* f_block_size);
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_INTERNAL_SCHUR_TEMPLATES_H_
diff --git a/third_party/ceres/internal/ceres/scoped_thread_token.h b/third_party/ceres/internal/ceres/scoped_thread_token.h
index c167397..76da95b 100644
--- a/third_party/ceres/internal/ceres/scoped_thread_token.h
+++ b/third_party/ceres/internal/ceres/scoped_thread_token.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -31,31 +31,29 @@
 #ifndef CERES_INTERNAL_SCOPED_THREAD_TOKEN_H_
 #define CERES_INTERNAL_SCOPED_THREAD_TOKEN_H_
 
+#include "ceres/internal/export.h"
 #include "ceres/thread_token_provider.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // Helper class for ThreadTokenProvider. This object acquires a token in its
 // constructor and puts that token back with destruction.
-class ScopedThreadToken {
+class CERES_NO_EXPORT ScopedThreadToken {
  public:
-  ScopedThreadToken(ThreadTokenProvider* provider)
+  explicit ScopedThreadToken(ThreadTokenProvider* provider)
       : provider_(provider), token_(provider->Acquire()) {}
 
   ~ScopedThreadToken() { provider_->Release(token_); }
+  ScopedThreadToken(ScopedThreadToken&) = delete;
+  ScopedThreadToken& operator=(ScopedThreadToken&) = delete;
 
   int token() const { return token_; }
 
  private:
   ThreadTokenProvider* provider_;
   int token_;
-
-  ScopedThreadToken(ScopedThreadToken&);
-  ScopedThreadToken& operator=(ScopedThreadToken&);
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_INTERNAL_SCOPED_THREAD_TOKEN_H_
diff --git a/third_party/ceres/internal/ceres/scratch_evaluate_preparer.cc b/third_party/ceres/internal/ceres/scratch_evaluate_preparer.cc
index 9905b22..86cad93 100644
--- a/third_party/ceres/internal/ceres/scratch_evaluate_preparer.cc
+++ b/third_party/ceres/internal/ceres/scratch_evaluate_preparer.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -30,26 +30,28 @@
 
 #include "ceres/scratch_evaluate_preparer.h"
 
+#include <memory>
+
 #include "ceres/parameter_block.h"
 #include "ceres/program.h"
 #include "ceres/residual_block.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
-ScratchEvaluatePreparer* ScratchEvaluatePreparer::Create(const Program& program,
-                                                         int num_threads) {
-  ScratchEvaluatePreparer* preparers = new ScratchEvaluatePreparer[num_threads];
+std::unique_ptr<ScratchEvaluatePreparer[]> ScratchEvaluatePreparer::Create(
+    const Program& program, unsigned num_threads) {
+  auto preparers = std::make_unique<ScratchEvaluatePreparer[]>(num_threads);
   int max_derivatives_per_residual_block =
       program.MaxDerivativesPerResidualBlock();
-  for (int i = 0; i < num_threads; i++) {
+  for (unsigned i = 0; i < num_threads; i++) {
     preparers[i].Init(max_derivatives_per_residual_block);
   }
   return preparers;
 }
 
 void ScratchEvaluatePreparer::Init(int max_derivatives_per_residual_block) {
-  jacobian_scratch_.reset(new double[max_derivatives_per_residual_block]);
+  jacobian_scratch_ = std::make_unique<double[]>(
+      static_cast<std::size_t>(max_derivatives_per_residual_block));
 }
 
 // Point the jacobian blocks into the scratch area of this evaluate preparer.
@@ -64,13 +66,12 @@
     const ParameterBlock* parameter_block =
         residual_block->parameter_blocks()[j];
     if (parameter_block->IsConstant()) {
-      jacobians[j] = NULL;
+      jacobians[j] = nullptr;
     } else {
       jacobians[j] = jacobian_block_cursor;
-      jacobian_block_cursor += num_residuals * parameter_block->LocalSize();
+      jacobian_block_cursor += num_residuals * parameter_block->TangentSize();
     }
   }
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/scratch_evaluate_preparer.h b/third_party/ceres/internal/ceres/scratch_evaluate_preparer.h
index 2d2745d..a7fd8a8 100644
--- a/third_party/ceres/internal/ceres/scratch_evaluate_preparer.h
+++ b/third_party/ceres/internal/ceres/scratch_evaluate_preparer.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -37,18 +37,20 @@
 
 #include <memory>
 
-namespace ceres {
-namespace internal {
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
+
+namespace ceres::internal {
 
 class Program;
 class ResidualBlock;
 class SparseMatrix;
 
-class ScratchEvaluatePreparer {
+class CERES_NO_EXPORT ScratchEvaluatePreparer {
  public:
   // Create num_threads ScratchEvaluatePreparers.
-  static ScratchEvaluatePreparer* Create(const Program& program,
-                                         int num_threads);
+  static std::unique_ptr<ScratchEvaluatePreparer[]> Create(
+      const Program& program, unsigned num_threads);
 
   // EvaluatePreparer interface
   void Init(int max_derivatives_per_residual_block);
@@ -63,7 +65,8 @@
   std::unique_ptr<double[]> jacobian_scratch_;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_SCRATCH_EVALUATE_PREPARER_H_
diff --git a/third_party/ceres/internal/ceres/single_linkage_clustering.cc b/third_party/ceres/internal/ceres/single_linkage_clustering.cc
index 0e78131..06e76df 100644
--- a/third_party/ceres/internal/ceres/single_linkage_clustering.cc
+++ b/third_party/ceres/internal/ceres/single_linkage_clustering.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -36,8 +36,7 @@
 #include "ceres/graph.h"
 #include "ceres/graph_algorithms.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 int ComputeSingleLinkageClustering(
     const SingleLinkageClusteringOptions& options,
@@ -91,5 +90,4 @@
   return num_clusters;
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/single_linkage_clustering.h b/third_party/ceres/internal/ceres/single_linkage_clustering.h
index e891a9e..3f49540 100644
--- a/third_party/ceres/internal/ceres/single_linkage_clustering.h
+++ b/third_party/ceres/internal/ceres/single_linkage_clustering.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -34,10 +34,10 @@
 #include <unordered_map>
 
 #include "ceres/graph.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 struct SingleLinkageClusteringOptions {
   // Graph edges with edge weight less than min_similarity are ignored
@@ -55,12 +55,13 @@
 //
 // The return value of this function is the number of clusters
 // identified by the algorithm.
-int CERES_EXPORT_INTERNAL
-ComputeSingleLinkageClustering(const SingleLinkageClusteringOptions& options,
-                               const WeightedGraph<int>& graph,
-                               std::unordered_map<int, int>* membership);
+CERES_NO_EXPORT int ComputeSingleLinkageClustering(
+    const SingleLinkageClusteringOptions& options,
+    const WeightedGraph<int>& graph,
+    std::unordered_map<int, int>* membership);
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_SINGLE_LINKAGE_CLUSTERING_H_
diff --git a/third_party/ceres/internal/ceres/single_linkage_clustering_test.cc b/third_party/ceres/internal/ceres/single_linkage_clustering_test.cc
index 28c7c41..cc16cb4 100644
--- a/third_party/ceres/internal/ceres/single_linkage_clustering_test.cc
+++ b/third_party/ceres/internal/ceres/single_linkage_clustering_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,8 +35,7 @@
 #include "ceres/graph.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST(SingleLinkageClustering, GraphHasTwoComponents) {
   WeightedGraph<int> graph;
@@ -122,5 +121,4 @@
   EXPECT_EQ(membership[4], membership[5]);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/small_blas.h b/third_party/ceres/internal/ceres/small_blas.h
index 4ee9229..fb8d7fa 100644
--- a/third_party/ceres/internal/ceres/small_blas.h
+++ b/third_party/ceres/internal/ceres/small_blas.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -36,12 +36,11 @@
 #define CERES_INTERNAL_SMALL_BLAS_H_
 
 #include "ceres/internal/eigen.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 #include "glog/logging.h"
 #include "small_blas_generic.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // The following three macros are used to share code and reduce
 // template junk across the various GEMM variants.
@@ -210,7 +209,7 @@
 
   // Process the couple columns in remainder if present.
   if (NUM_COL_C & 2) {
-    int col = NUM_COL_C & (int)(~(span - 1));
+    int col = NUM_COL_C & (~(span - 1));
     const double* pa = &A[0];
     for (int row = 0; row < NUM_ROW_C; ++row, pa += NUM_COL_A) {
       const double* pb = &B[col];
@@ -232,7 +231,7 @@
   }
 
   // Calculate the main part with multiples of 4.
-  int col_m = NUM_COL_C & (int)(~(span - 1));
+  int col_m = NUM_COL_C & (~(span - 1));
   for (int col = 0; col < col_m; col += span) {
     for (int row = 0; row < NUM_ROW_C; ++row) {
       const int index = (row + start_row_c) * col_stride_c + start_col_c + col;
@@ -315,7 +314,7 @@
 
   // Process the couple columns in remainder if present.
   if (NUM_COL_C & 2) {
-    int col = NUM_COL_C & (int)(~(span - 1));
+    int col = NUM_COL_C & (~(span - 1));
     for (int row = 0; row < NUM_ROW_C; ++row) {
       const double* pa = &A[row];
       const double* pb = &B[col];
@@ -339,7 +338,7 @@
   }
 
   // Process the main part with multiples of 4.
-  int col_m = NUM_COL_C & (int)(~(span - 1));
+  int col_m = NUM_COL_C & (~(span - 1));
   for (int col = 0; col < col_m; col += span) {
     for (int row = 0; row < NUM_ROW_C; ++row) {
       const int index = (row + start_row_c) * col_stride_c + start_col_c + col;
@@ -435,7 +434,7 @@
 
   // Process the couple rows in remainder if present.
   if (NUM_ROW_A & 2) {
-    int row = NUM_ROW_A & (int)(~(span - 1));
+    int row = NUM_ROW_A & (~(span - 1));
     const double* pa1 = &A[row * NUM_COL_A];
     const double* pa2 = pa1 + NUM_COL_A;
     const double* pb = &b[0];
@@ -454,7 +453,7 @@
   }
 
   // Calculate the main part with multiples of 4.
-  int row_m = NUM_ROW_A & (int)(~(span - 1));
+  int row_m = NUM_ROW_A & (~(span - 1));
   for (int row = 0; row < row_m; row += span) {
     // clang-format off
     MVM_mat4x1(NUM_COL_A, &A[row * NUM_COL_A], NUM_COL_A,
@@ -522,7 +521,7 @@
 
   // Process the couple columns in remainder if present.
   if (NUM_COL_A & 2) {
-    int row = NUM_COL_A & (int)(~(span - 1));
+    int row = NUM_COL_A & (~(span - 1));
     const double* pa = &A[row];
     const double* pb = &b[0];
     double tmp1 = 0.0, tmp2 = 0.0;
@@ -543,7 +542,7 @@
   }
 
   // Calculate the main part with multiples of 4.
-  int row_m = NUM_COL_A & (int)(~(span - 1));
+  int row_m = NUM_COL_A & (~(span - 1));
   for (int row = 0; row < row_m; row += span) {
     // clang-format off
     MTV_mat4x1(NUM_ROW_A, &A[row], NUM_COL_A,
@@ -561,7 +560,6 @@
 #undef CERES_GEMM_STORE_SINGLE
 #undef CERES_GEMM_STORE_PAIR
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_INTERNAL_SMALL_BLAS_H_
diff --git a/third_party/ceres/internal/ceres/small_blas_gemm_benchmark.cc b/third_party/ceres/internal/ceres/small_blas_gemm_benchmark.cc
index aa6c41d..ea0ecdf 100644
--- a/third_party/ceres/internal/ceres/small_blas_gemm_benchmark.cc
+++ b/third_party/ceres/internal/ceres/small_blas_gemm_benchmark.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -34,8 +34,7 @@
 #include "benchmark/benchmark.h"
 #include "ceres/small_blas.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // Benchmarking matrix-matrix multiply routines and optimizing memory
 // access requires that we make sure that they are not just sitting in
@@ -50,7 +49,7 @@
   MatrixMatrixMultiplyData(
       int a_rows, int a_cols, int b_rows, int b_cols, int c_rows, int c_cols)
       : num_elements_(1000),
-        a_size_(a_rows * a_cols),
+        a_size_(num_elements_ * a_rows * a_cols),
         b_size_(b_rows * b_cols),
         c_size_(c_rows * c_cols),
         a_(num_elements_ * a_size_, 1.00001),
@@ -72,99 +71,147 @@
   std::vector<double> c_;
 };
 
-static void MatrixMatrixMultiplySizeArguments(
-    benchmark::internal::Benchmark* benchmark) {
-  const std::vector<int> b_rows = {1, 2, 3, 4, 6, 8};
-  const std::vector<int> b_cols = {1, 2, 3, 4, 8, 12, 15};
-  const std::vector<int> c_cols = b_cols;
-  for (int i : b_rows) {
-    for (int j : b_cols) {
-      for (int k : c_cols) {
-        benchmark->Args({i, j, k});
-      }
-    }
-  }
-}
+#define GEMM_KIND_EQ 0
+#define GEMM_KIND_ADD 1
+#define GEMM_KIND_SUB -1
 
-void BM_MatrixMatrixMultiplyDynamic(benchmark::State& state) {
-  const int i = state.range(0);
-  const int j = state.range(1);
-  const int k = state.range(2);
+#define BENCHMARK_MM_FN(FN, M, N, K, NAME, MT, NT, KT)                      \
+  void static BM_##FN##_##NAME##_##M##x##N##x##K(benchmark::State& state) { \
+    const int b_rows = M;                                                   \
+    const int b_cols = N;                                                   \
+    const int c_rows = b_cols;                                              \
+    const int c_cols = K;                                                   \
+    const int a_rows = b_rows;                                              \
+    const int a_cols = c_cols;                                              \
+    MatrixMatrixMultiplyData data(                                          \
+        a_rows, a_cols, b_rows, b_cols, c_rows, c_cols);                    \
+    const int num_elements = data.num_elements();                           \
+    int iter = 0;                                                           \
+    for (auto _ : state) {                                                  \
+      FN<MT, KT, KT, NT, GEMM_KIND_ADD>(data.GetB(iter),                    \
+                                        b_rows,                             \
+                                        b_cols,                             \
+                                        data.GetC(iter),                    \
+                                        c_rows,                             \
+                                        c_cols,                             \
+                                        data.GetA(iter),                    \
+                                        512,                                \
+                                        512,                                \
+                                        a_rows,                             \
+                                        a_cols);                            \
+      iter = (iter + 1) % num_elements;                                     \
+    }                                                                       \
+  }                                                                         \
+  BENCHMARK(BM_##FN##_##NAME##_##M##x##N##x##K);
 
-  const int b_rows = i;
-  const int b_cols = j;
-  const int c_rows = b_cols;
-  const int c_cols = k;
-  const int a_rows = b_rows;
-  const int a_cols = c_cols;
+#define BENCHMARK_STATIC_MM_FN(FN, M, N, K) \
+  BENCHMARK_MM_FN(FN, M, N, K, Static, M, N, K)
+#define BENCHMARK_DYNAMIC_MM_FN(FN, M, N, K) \
+  BENCHMARK_MM_FN(                           \
+      FN, M, N, K, Dynamic, Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic)
 
-  MatrixMatrixMultiplyData data(a_rows, a_cols, b_rows, b_cols, c_rows, c_cols);
-  const int num_elements = data.num_elements();
+#define BENCHMARK_MTM_FN(FN, M, N, K, NAME, MT, NT, KT)                     \
+  void static BM_##FN##_##NAME##_##M##x##N##x##K(benchmark::State& state) { \
+    const int b_rows = M;                                                   \
+    const int b_cols = N;                                                   \
+    const int c_rows = b_rows;                                              \
+    const int c_cols = K;                                                   \
+    const int a_rows = b_cols;                                              \
+    const int a_cols = c_cols;                                              \
+    MatrixMatrixMultiplyData data(                                          \
+        a_rows, a_cols, b_rows, b_cols, c_rows, c_cols);                    \
+    const int num_elements = data.num_elements();                           \
+    int iter = 0;                                                           \
+    for (auto _ : state) {                                                  \
+      FN<KT, MT, KT, NT, GEMM_KIND_ADD>(data.GetB(iter),                    \
+                                        b_rows,                             \
+                                        b_cols,                             \
+                                        data.GetC(iter),                    \
+                                        c_rows,                             \
+                                        c_cols,                             \
+                                        data.GetA(iter),                    \
+                                        0,                                  \
+                                        0,                                  \
+                                        a_rows,                             \
+                                        a_cols);                            \
+      iter = (iter + 1) % num_elements;                                     \
+    }                                                                       \
+  }                                                                         \
+  BENCHMARK(BM_##FN##_##NAME##_##M##x##N##x##K);
 
-  int iter = 0;
-  for (auto _ : state) {
-    // a += b * c
-    // clang-format off
-    MatrixMatrixMultiply
-        <Eigen::Dynamic, Eigen::Dynamic,Eigen::Dynamic,Eigen::Dynamic, 1>
-        (data.GetB(iter), b_rows, b_cols,
-         data.GetC(iter), c_rows, c_cols,
-         data.GetA(iter), 0, 0, a_rows, a_cols);
-    // clang-format on
-    iter = (iter + 1) % num_elements;
-  }
-}
+#define BENCHMARK_STATIC_MMT_FN(FN, M, N, K) \
+  BENCHMARK_MTM_FN(FN, M, N, K, Static, M, N, K)
+#define BENCHMARK_DYNAMIC_MMT_FN(FN, M, N, K) \
+  BENCHMARK_MTM_FN(                           \
+      FN, M, N, K, Dynamic, Eigen::Dynamic, Eigen::Dynamic, Eigen::Dynamic)
 
-BENCHMARK(BM_MatrixMatrixMultiplyDynamic)
-    ->Apply(MatrixMatrixMultiplySizeArguments);
+BENCHMARK_STATIC_MM_FN(MatrixMatrixMultiplyEigen, 2, 3, 4)
+BENCHMARK_STATIC_MM_FN(MatrixMatrixMultiplyEigen, 3, 3, 3)
+BENCHMARK_STATIC_MM_FN(MatrixMatrixMultiplyEigen, 4, 4, 4)
+BENCHMARK_STATIC_MM_FN(MatrixMatrixMultiplyEigen, 8, 8, 8)
+BENCHMARK_STATIC_MM_FN(MatrixMatrixMultiplyEigen, 9, 9, 3)
+BENCHMARK_STATIC_MM_FN(MatrixMatrixMultiplyEigen, 9, 3, 3)
+BENCHMARK_STATIC_MM_FN(MatrixMatrixMultiplyEigen, 3, 9, 9)
+BENCHMARK_DYNAMIC_MM_FN(MatrixMatrixMultiplyEigen, 2, 3, 4)
+BENCHMARK_DYNAMIC_MM_FN(MatrixMatrixMultiplyEigen, 3, 3, 3)
+BENCHMARK_DYNAMIC_MM_FN(MatrixMatrixMultiplyEigen, 4, 4, 4)
+BENCHMARK_DYNAMIC_MM_FN(MatrixMatrixMultiplyEigen, 8, 8, 8)
+BENCHMARK_DYNAMIC_MM_FN(MatrixMatrixMultiplyEigen, 9, 9, 3)
+BENCHMARK_DYNAMIC_MM_FN(MatrixMatrixMultiplyEigen, 9, 3, 3)
+BENCHMARK_DYNAMIC_MM_FN(MatrixMatrixMultiplyEigen, 3, 9, 9)
+BENCHMARK_STATIC_MM_FN(MatrixMatrixMultiplyNaive, 2, 3, 4)
+BENCHMARK_STATIC_MM_FN(MatrixMatrixMultiplyNaive, 3, 3, 3)
+BENCHMARK_STATIC_MM_FN(MatrixMatrixMultiplyNaive, 4, 4, 4)
+BENCHMARK_STATIC_MM_FN(MatrixMatrixMultiplyNaive, 8, 8, 8)
+BENCHMARK_STATIC_MM_FN(MatrixMatrixMultiplyNaive, 9, 9, 3)
+BENCHMARK_STATIC_MM_FN(MatrixMatrixMultiplyNaive, 9, 3, 3)
+BENCHMARK_STATIC_MM_FN(MatrixMatrixMultiplyNaive, 3, 9, 9)
+BENCHMARK_DYNAMIC_MM_FN(MatrixMatrixMultiplyNaive, 2, 3, 4)
+BENCHMARK_DYNAMIC_MM_FN(MatrixMatrixMultiplyNaive, 3, 3, 3)
+BENCHMARK_DYNAMIC_MM_FN(MatrixMatrixMultiplyNaive, 4, 4, 4)
+BENCHMARK_DYNAMIC_MM_FN(MatrixMatrixMultiplyNaive, 8, 8, 8)
+BENCHMARK_DYNAMIC_MM_FN(MatrixMatrixMultiplyNaive, 9, 9, 3)
+BENCHMARK_DYNAMIC_MM_FN(MatrixMatrixMultiplyNaive, 9, 3, 3)
+BENCHMARK_DYNAMIC_MM_FN(MatrixMatrixMultiplyNaive, 3, 9, 9)
+BENCHMARK_STATIC_MMT_FN(MatrixTransposeMatrixMultiplyEigen, 2, 3, 4)
+BENCHMARK_STATIC_MMT_FN(MatrixTransposeMatrixMultiplyEigen, 3, 3, 3)
+BENCHMARK_STATIC_MMT_FN(MatrixTransposeMatrixMultiplyEigen, 4, 4, 4)
+BENCHMARK_STATIC_MMT_FN(MatrixTransposeMatrixMultiplyEigen, 8, 8, 8)
+BENCHMARK_STATIC_MMT_FN(MatrixTransposeMatrixMultiplyEigen, 9, 9, 3)
+BENCHMARK_STATIC_MMT_FN(MatrixTransposeMatrixMultiplyEigen, 9, 3, 3)
+BENCHMARK_STATIC_MMT_FN(MatrixTransposeMatrixMultiplyEigen, 3, 9, 9)
+BENCHMARK_DYNAMIC_MMT_FN(MatrixTransposeMatrixMultiplyEigen, 2, 3, 4)
+BENCHMARK_DYNAMIC_MMT_FN(MatrixTransposeMatrixMultiplyEigen, 3, 3, 3)
+BENCHMARK_DYNAMIC_MMT_FN(MatrixTransposeMatrixMultiplyEigen, 4, 4, 4)
+BENCHMARK_DYNAMIC_MMT_FN(MatrixTransposeMatrixMultiplyEigen, 8, 8, 8)
+BENCHMARK_DYNAMIC_MMT_FN(MatrixTransposeMatrixMultiplyEigen, 9, 9, 3)
+BENCHMARK_DYNAMIC_MMT_FN(MatrixTransposeMatrixMultiplyEigen, 9, 3, 3)
+BENCHMARK_DYNAMIC_MMT_FN(MatrixTransposeMatrixMultiplyEigen, 3, 9, 9)
+BENCHMARK_STATIC_MMT_FN(MatrixTransposeMatrixMultiplyNaive, 2, 3, 4)
+BENCHMARK_STATIC_MMT_FN(MatrixTransposeMatrixMultiplyNaive, 3, 3, 3)
+BENCHMARK_STATIC_MMT_FN(MatrixTransposeMatrixMultiplyNaive, 4, 4, 4)
+BENCHMARK_STATIC_MMT_FN(MatrixTransposeMatrixMultiplyNaive, 8, 8, 8)
+BENCHMARK_STATIC_MMT_FN(MatrixTransposeMatrixMultiplyNaive, 9, 9, 3)
+BENCHMARK_STATIC_MMT_FN(MatrixTransposeMatrixMultiplyNaive, 9, 3, 3)
+BENCHMARK_STATIC_MMT_FN(MatrixTransposeMatrixMultiplyNaive, 3, 9, 9)
+BENCHMARK_DYNAMIC_MMT_FN(MatrixTransposeMatrixMultiplyNaive, 2, 3, 4)
+BENCHMARK_DYNAMIC_MMT_FN(MatrixTransposeMatrixMultiplyNaive, 3, 3, 3)
+BENCHMARK_DYNAMIC_MMT_FN(MatrixTransposeMatrixMultiplyNaive, 4, 4, 4)
+BENCHMARK_DYNAMIC_MMT_FN(MatrixTransposeMatrixMultiplyNaive, 8, 8, 8)
+BENCHMARK_DYNAMIC_MMT_FN(MatrixTransposeMatrixMultiplyNaive, 9, 9, 3)
+BENCHMARK_DYNAMIC_MMT_FN(MatrixTransposeMatrixMultiplyNaive, 9, 3, 3)
+BENCHMARK_DYNAMIC_MMT_FN(MatrixTransposeMatrixMultiplyNaive, 3, 9, 9)
 
-static void MatrixTransposeMatrixMultiplySizeArguments(
-    benchmark::internal::Benchmark* benchmark) {
-  std::vector<int> b_rows = {1, 2, 3, 4, 6, 8};
-  std::vector<int> b_cols = {1, 2, 3, 4, 8, 12, 15};
-  std::vector<int> c_cols = b_rows;
-  for (int i : b_rows) {
-    for (int j : b_cols) {
-      for (int k : c_cols) {
-        benchmark->Args({i, j, k});
-      }
-    }
-  }
-}
+#undef GEMM_KIND_EQ
+#undef GEMM_KIND_ADD
+#undef GEMM_KIND_SUB
+#undef BENCHMARK_MM_FN
+#undef BENCHMARK_STATIC_MM_FN
+#undef BENCHMARK_DYNAMIC_MM_FN
+#undef BENCHMARK_MTM_FN
+#undef BENCHMARK_DYNAMIC_MMT_FN
+#undef BENCHMARK_STATIC_MMT_FN
 
-void BM_MatrixTransposeMatrixMultiplyDynamic(benchmark::State& state) {
-  const int i = state.range(0);
-  const int j = state.range(1);
-  const int k = state.range(2);
-
-  const int b_rows = i;
-  const int b_cols = j;
-  const int c_rows = b_rows;
-  const int c_cols = k;
-  const int a_rows = b_cols;
-  const int a_cols = c_cols;
-
-  MatrixMatrixMultiplyData data(a_rows, a_cols, b_rows, b_cols, c_rows, c_cols);
-  const int num_elements = data.num_elements();
-
-  int iter = 0;
-  for (auto _ : state) {
-    // a += b' * c
-    // clang-format off
-    MatrixTransposeMatrixMultiply
-        <Eigen::Dynamic,Eigen::Dynamic,Eigen::Dynamic,Eigen::Dynamic, 1>
-        (data.GetB(iter), b_rows, b_cols,
-         data.GetC(iter), c_rows, c_cols,
-         data.GetA(iter), 0, 0, a_rows, a_cols);
-    // clang-format on
-    iter = (iter + 1) % num_elements;
-  }
-}
-
-BENCHMARK(BM_MatrixTransposeMatrixMultiplyDynamic)
-    ->Apply(MatrixTransposeMatrixMultiplySizeArguments);
-
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 BENCHMARK_MAIN();
diff --git a/third_party/ceres/internal/ceres/small_blas_gemv_benchmark.cc b/third_party/ceres/internal/ceres/small_blas_gemv_benchmark.cc
index 4b587bf..6bf584d 100644
--- a/third_party/ceres/internal/ceres/small_blas_gemv_benchmark.cc
+++ b/third_party/ceres/internal/ceres/small_blas_gemv_benchmark.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -78,7 +78,7 @@
   }
 }
 
-void BM_MatrixVectorMultiply(benchmark::State& state) {
+static void BM_MatrixVectorMultiply(benchmark::State& state) {
   const int rows = state.range(0);
   const int cols = state.range(1);
   MatrixVectorMultiplyData data(rows, cols);
@@ -94,7 +94,7 @@
 
 BENCHMARK(BM_MatrixVectorMultiply)->Apply(MatrixSizeArguments);
 
-void BM_MatrixTransposeVectorMultiply(benchmark::State& state) {
+static void BM_MatrixTransposeVectorMultiply(benchmark::State& state) {
   const int rows = state.range(0);
   const int cols = state.range(1);
   MatrixVectorMultiplyData data(cols, rows);
diff --git a/third_party/ceres/internal/ceres/small_blas_generic.h b/third_party/ceres/internal/ceres/small_blas_generic.h
index 3f3ea42..93ee338 100644
--- a/third_party/ceres/internal/ceres/small_blas_generic.h
+++ b/third_party/ceres/internal/ceres/small_blas_generic.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,38 +35,35 @@
 #ifndef CERES_INTERNAL_SMALL_BLAS_GENERIC_H_
 #define CERES_INTERNAL_SMALL_BLAS_GENERIC_H_
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // The following macros are used to share code
-#define CERES_GEMM_OPT_NAIVE_HEADER \
-  double c0 = 0.0;                  \
-  double c1 = 0.0;                  \
-  double c2 = 0.0;                  \
-  double c3 = 0.0;                  \
-  const double* pa = a;             \
-  const double* pb = b;             \
-  const int span = 4;               \
-  int col_r = col_a & (span - 1);   \
+#define CERES_GEMM_OPT_NAIVE_HEADER       \
+  double cvec4[4] = {0.0, 0.0, 0.0, 0.0}; \
+  const double* pa = a;                   \
+  const double* pb = b;                   \
+  const int span = 4;                     \
+  int col_r = col_a & (span - 1);         \
   int col_m = col_a - col_r;
 
 #define CERES_GEMM_OPT_STORE_MAT1X4 \
   if (kOperation > 0) {             \
-    *c++ += c0;                     \
-    *c++ += c1;                     \
-    *c++ += c2;                     \
-    *c++ += c3;                     \
+    c[0] += cvec4[0];               \
+    c[1] += cvec4[1];               \
+    c[2] += cvec4[2];               \
+    c[3] += cvec4[3];               \
   } else if (kOperation < 0) {      \
-    *c++ -= c0;                     \
-    *c++ -= c1;                     \
-    *c++ -= c2;                     \
-    *c++ -= c3;                     \
+    c[0] -= cvec4[0];               \
+    c[1] -= cvec4[1];               \
+    c[2] -= cvec4[2];               \
+    c[3] -= cvec4[3];               \
   } else {                          \
-    *c++ = c0;                      \
-    *c++ = c1;                      \
-    *c++ = c2;                      \
-    *c++ = c3;                      \
-  }
+    c[0] = cvec4[0];                \
+    c[1] = cvec4[1];                \
+    c[2] = cvec4[2];                \
+    c[3] = cvec4[3];                \
+  }                                 \
+  c += 4;
 
 // Matrix-Matrix Multiplication
 // Figure out 1x4 of Matrix C in one batch
@@ -100,10 +97,11 @@
 #define CERES_GEMM_OPT_MMM_MAT1X4_MUL \
   av = pa[k];                         \
   pb = b + bi;                        \
-  c0 += av * *pb++;                   \
-  c1 += av * *pb++;                   \
-  c2 += av * *pb++;                   \
-  c3 += av * *pb++;                   \
+  cvec4[0] += av * pb[0];             \
+  cvec4[1] += av * pb[1];             \
+  cvec4[2] += av * pb[2];             \
+  cvec4[3] += av * pb[3];             \
+  pb += 4;                            \
   bi += col_stride_b;                 \
   k++;
 
@@ -167,10 +165,11 @@
 #define CERES_GEMM_OPT_MTM_MAT1X4_MUL \
   av = pa[ai];                        \
   pb = b + bi;                        \
-  c0 += av * *pb++;                   \
-  c1 += av * *pb++;                   \
-  c2 += av * *pb++;                   \
-  c3 += av * *pb++;                   \
+  cvec4[0] += av * pb[0];             \
+  cvec4[1] += av * pb[1];             \
+  cvec4[2] += av * pb[2];             \
+  cvec4[3] += av * pb[3];             \
+  pb += 4;                            \
   ai += col_stride_a;                 \
   bi += col_stride_b;
 
@@ -219,13 +218,13 @@
   double bv = 0.0;
 
   // clang-format off
-#define CERES_GEMM_OPT_MVM_MAT4X1_MUL  \
-  bv = *pb;                            \
-  c0 += *(pa                   ) * bv; \
-  c1 += *(pa + col_stride_a    ) * bv; \
-  c2 += *(pa + col_stride_a * 2) * bv; \
-  c3 += *(pa + col_stride_a * 3) * bv; \
-  pa++;                                \
+#define CERES_GEMM_OPT_MVM_MAT4X1_MUL       \
+  bv = *pb;                                 \
+  cvec4[0] += *(pa                   ) * bv; \
+  cvec4[1] += *(pa + col_stride_a    ) * bv; \
+  cvec4[2] += *(pa + col_stride_a * 2) * bv; \
+  cvec4[3] += *(pa + col_stride_a * 3) * bv; \
+  pa++;                                     \
   pb++;
   // clang-format on
 
@@ -283,16 +282,14 @@
   CERES_GEMM_OPT_NAIVE_HEADER
   double bv = 0.0;
 
-  // clang-format off
 #define CERES_GEMM_OPT_MTV_MAT4X1_MUL \
   bv = *pb;                           \
-  c0 += *(pa    ) * bv;               \
-  c1 += *(pa + 1) * bv;               \
-  c2 += *(pa + 2) * bv;               \
-  c3 += *(pa + 3) * bv;               \
+  cvec4[0] += pa[0] * bv;             \
+  cvec4[1] += pa[1] * bv;             \
+  cvec4[2] += pa[2] * bv;             \
+  cvec4[3] += pa[3] * bv;             \
   pa += col_stride_a;                 \
   pb++;
-  // clang-format on
 
   for (int k = 0; k < col_m; k += span) {
     CERES_GEMM_OPT_MTV_MAT4X1_MUL
@@ -313,7 +310,6 @@
 #undef CERES_GEMM_OPT_NAIVE_HEADER
 #undef CERES_GEMM_OPT_STORE_MAT1X4
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_INTERNAL_SMALL_BLAS_GENERIC_H_
diff --git a/third_party/ceres/internal/ceres/small_blas_test.cc b/third_party/ceres/internal/ceres/small_blas_test.cc
index 6f819c4..97922aa 100644
--- a/third_party/ceres/internal/ceres/small_blas_test.cc
+++ b/third_party/ceres/internal/ceres/small_blas_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -31,6 +31,7 @@
 #include "ceres/small_blas.h"
 
 #include <limits>
+#include <string>
 
 #include "ceres/internal/eigen.h"
 #include "gtest/gtest.h"
@@ -38,341 +39,473 @@
 namespace ceres {
 namespace internal {
 
-const double kTolerance = 3.0 * std::numeric_limits<double>::epsilon();
+const double kTolerance = 5.0 * std::numeric_limits<double>::epsilon();
 
-TEST(BLAS, MatrixMatrixMultiply) {
-  const int kRowA = 3;
-  const int kColA = 5;
-  Matrix A(kRowA, kColA);
-  A.setOnes();
+// Static or dynamic problem types.
+enum class DimType { Static, Dynamic };
 
-  const int kRowB = 5;
-  const int kColB = 7;
-  Matrix B(kRowB, kColB);
-  B.setOnes();
+// Constructs matrix functor type.
+#define MATRIX_FUN_TY(FN)                                         \
+  template <int kRowA,                                            \
+            int kColA,                                            \
+            int kRowB,                                            \
+            int kColB,                                            \
+            int kOperation,                                       \
+            DimType kDimType>                                     \
+  struct FN##Ty {                                                 \
+    void operator()(const double* A,                              \
+                    const int num_row_a,                          \
+                    const int num_col_a,                          \
+                    const double* B,                              \
+                    const int num_row_b,                          \
+                    const int num_col_b,                          \
+                    double* C,                                    \
+                    const int start_row_c,                        \
+                    const int start_col_c,                        \
+                    const int row_stride_c,                       \
+                    const int col_stride_c) {                     \
+      if (kDimType == DimType::Static) {                          \
+        FN<kRowA, kColA, kRowB, kColB, kOperation>(A,             \
+                                                   num_row_a,     \
+                                                   num_col_a,     \
+                                                   B,             \
+                                                   num_row_b,     \
+                                                   num_col_b,     \
+                                                   C,             \
+                                                   start_row_c,   \
+                                                   start_col_c,   \
+                                                   row_stride_c,  \
+                                                   col_stride_c); \
+      } else {                                                    \
+        FN<Eigen::Dynamic,                                        \
+           Eigen::Dynamic,                                        \
+           Eigen::Dynamic,                                        \
+           Eigen::Dynamic,                                        \
+           kOperation>(A,                                         \
+                       num_row_a,                                 \
+                       num_col_a,                                 \
+                       B,                                         \
+                       num_row_b,                                 \
+                       num_col_b,                                 \
+                       C,                                         \
+                       start_row_c,                               \
+                       start_col_c,                               \
+                       row_stride_c,                              \
+                       col_stride_c);                             \
+      }                                                           \
+    }                                                             \
+  };
 
-  for (int row_stride_c = kRowA; row_stride_c < 3 * kRowA; ++row_stride_c) {
-    for (int col_stride_c = kColB; col_stride_c < 3 * kColB; ++col_stride_c) {
-      Matrix C(row_stride_c, col_stride_c);
-      C.setOnes();
+MATRIX_FUN_TY(MatrixMatrixMultiply)
+MATRIX_FUN_TY(MatrixMatrixMultiplyNaive)
+MATRIX_FUN_TY(MatrixTransposeMatrixMultiply)
+MATRIX_FUN_TY(MatrixTransposeMatrixMultiplyNaive)
 
-      Matrix C_plus = C;
-      Matrix C_minus = C;
-      Matrix C_assign = C;
+#undef MATRIX_FUN_TY
 
-      Matrix C_plus_ref = C;
-      Matrix C_minus_ref = C;
-      Matrix C_assign_ref = C;
-      // clang-format off
-      for (int start_row_c = 0; start_row_c + kRowA < row_stride_c; ++start_row_c) {
-        for (int start_col_c = 0; start_col_c + kColB < col_stride_c; ++start_col_c) {
-          C_plus_ref.block(start_row_c, start_col_c, kRowA, kColB) +=
-              A * B;
-
-          MatrixMatrixMultiply<kRowA, kColA, kRowB, kColB, 1>(
-              A.data(), kRowA, kColA,
-              B.data(), kRowB, kColB,
-              C_plus.data(), start_row_c, start_col_c, row_stride_c, col_stride_c);
-
-          EXPECT_NEAR((C_plus_ref - C_plus).norm(), 0.0, kTolerance)
-              << "C += A * B \n"
-              << "row_stride_c : " << row_stride_c << "\n"
-              << "col_stride_c : " << col_stride_c << "\n"
-              << "start_row_c  : " << start_row_c << "\n"
-              << "start_col_c  : " << start_col_c << "\n"
-              << "Cref : \n" << C_plus_ref << "\n"
-              << "C: \n" << C_plus;
-
-          C_minus_ref.block(start_row_c, start_col_c, kRowA, kColB) -=
-              A * B;
-
-          MatrixMatrixMultiply<kRowA, kColA, kRowB, kColB, -1>(
-              A.data(), kRowA, kColA,
-              B.data(), kRowB, kColB,
-              C_minus.data(), start_row_c, start_col_c, row_stride_c, col_stride_c);
-
-           EXPECT_NEAR((C_minus_ref - C_minus).norm(), 0.0, kTolerance)
-              << "C -= A * B \n"
-              << "row_stride_c : " << row_stride_c << "\n"
-              << "col_stride_c : " << col_stride_c << "\n"
-              << "start_row_c  : " << start_row_c << "\n"
-              << "start_col_c  : " << start_col_c << "\n"
-              << "Cref : \n" << C_minus_ref << "\n"
-              << "C: \n" << C_minus;
-
-          C_assign_ref.block(start_row_c, start_col_c, kRowA, kColB) =
-              A * B;
-
-          MatrixMatrixMultiply<kRowA, kColA, kRowB, kColB, 0>(
-              A.data(), kRowA, kColA,
-              B.data(), kRowB, kColB,
-              C_assign.data(), start_row_c, start_col_c, row_stride_c, col_stride_c);
-
-          EXPECT_NEAR((C_assign_ref - C_assign).norm(), 0.0, kTolerance)
-              << "C = A * B \n"
-              << "row_stride_c : " << row_stride_c << "\n"
-              << "col_stride_c : " << col_stride_c << "\n"
-              << "start_row_c  : " << start_row_c << "\n"
-              << "start_col_c  : " << start_col_c << "\n"
-              << "Cref : \n" << C_assign_ref << "\n"
-              << "C: \n" << C_assign;
-        }
-      }
-      // clang-format on
+// Initializes matrix entries.
+static void initMatrix(Matrix& mat) {
+  for (int i = 0; i < mat.rows(); ++i) {
+    for (int j = 0; j < mat.cols(); ++j) {
+      mat(i, j) = i + j + 1;
     }
   }
 }
 
-TEST(BLAS, MatrixTransposeMatrixMultiply) {
-  const int kRowA = 5;
-  const int kColA = 3;
-  Matrix A(kRowA, kColA);
-  A.setOnes();
+template <int kRowA,
+          int kColA,
+          int kColB,
+          DimType kDimType,
+          template <int, int, int, int, int, DimType>
+          class FunctorTy>
+struct TestMatrixFunctions {
+  void operator()() {
+    Matrix A(kRowA, kColA);
+    initMatrix(A);
+    const int kRowB = kColA;
+    Matrix B(kRowB, kColB);
+    initMatrix(B);
 
-  const int kRowB = 5;
-  const int kColB = 7;
-  Matrix B(kRowB, kColB);
-  B.setOnes();
+    for (int row_stride_c = kRowA; row_stride_c < 3 * kRowA; ++row_stride_c) {
+      for (int col_stride_c = kColB; col_stride_c < 3 * kColB; ++col_stride_c) {
+        Matrix C(row_stride_c, col_stride_c);
+        C.setOnes();
 
-  for (int row_stride_c = kColA; row_stride_c < 3 * kColA; ++row_stride_c) {
-    for (int col_stride_c = kColB; col_stride_c < 3 * kColB; ++col_stride_c) {
-      Matrix C(row_stride_c, col_stride_c);
-      C.setOnes();
+        Matrix C_plus = C;
+        Matrix C_minus = C;
+        Matrix C_assign = C;
 
-      Matrix C_plus = C;
-      Matrix C_minus = C;
-      Matrix C_assign = C;
+        Matrix C_plus_ref = C;
+        Matrix C_minus_ref = C;
+        Matrix C_assign_ref = C;
 
-      Matrix C_plus_ref = C;
-      Matrix C_minus_ref = C;
-      Matrix C_assign_ref = C;
-      // clang-format off
-      for (int start_row_c = 0; start_row_c + kColA < row_stride_c; ++start_row_c) {
-        for (int start_col_c = 0; start_col_c + kColB < col_stride_c; ++start_col_c) {
-          C_plus_ref.block(start_row_c, start_col_c, kColA, kColB) +=
-              A.transpose() * B;
+        for (int start_row_c = 0; start_row_c + kRowA < row_stride_c;
+             ++start_row_c) {
+          for (int start_col_c = 0; start_col_c + kColB < col_stride_c;
+               ++start_col_c) {
+            C_plus_ref.block(start_row_c, start_col_c, kRowA, kColB) += A * B;
+            FunctorTy<kRowA, kColA, kRowB, kColB, 1, kDimType>()(A.data(),
+                                                                 kRowA,
+                                                                 kColA,
+                                                                 B.data(),
+                                                                 kRowB,
+                                                                 kColB,
+                                                                 C_plus.data(),
+                                                                 start_row_c,
+                                                                 start_col_c,
+                                                                 row_stride_c,
+                                                                 col_stride_c);
 
-          MatrixTransposeMatrixMultiply<kRowA, kColA, kRowB, kColB, 1>(
-              A.data(), kRowA, kColA,
-              B.data(), kRowB, kColB,
-              C_plus.data(), start_row_c, start_col_c, row_stride_c, col_stride_c);
+            EXPECT_NEAR((C_plus_ref - C_plus).norm(), 0.0, kTolerance)
+                << "C += A * B \n"
+                << "row_stride_c : " << row_stride_c << "\n"
+                << "col_stride_c : " << col_stride_c << "\n"
+                << "start_row_c  : " << start_row_c << "\n"
+                << "start_col_c  : " << start_col_c << "\n"
+                << "Cref : \n"
+                << C_plus_ref << "\n"
+                << "C: \n"
+                << C_plus;
 
-          EXPECT_NEAR((C_plus_ref - C_plus).norm(), 0.0, kTolerance)
-              << "C += A' * B \n"
-              << "row_stride_c : " << row_stride_c << "\n"
-              << "col_stride_c : " << col_stride_c << "\n"
-              << "start_row_c  : " << start_row_c << "\n"
-              << "start_col_c  : " << start_col_c << "\n"
-              << "Cref : \n" << C_plus_ref << "\n"
-              << "C: \n" << C_plus;
+            C_minus_ref.block(start_row_c, start_col_c, kRowA, kColB) -= A * B;
+            FunctorTy<kRowA, kColA, kRowB, kColB, -1, kDimType>()(
+                A.data(),
+                kRowA,
+                kColA,
+                B.data(),
+                kRowB,
+                kColB,
+                C_minus.data(),
+                start_row_c,
+                start_col_c,
+                row_stride_c,
+                col_stride_c);
 
-          C_minus_ref.block(start_row_c, start_col_c, kColA, kColB) -=
-              A.transpose() * B;
+            EXPECT_NEAR((C_minus_ref - C_minus).norm(), 0.0, kTolerance)
+                << "C -= A * B \n"
+                << "row_stride_c : " << row_stride_c << "\n"
+                << "col_stride_c : " << col_stride_c << "\n"
+                << "start_row_c  : " << start_row_c << "\n"
+                << "start_col_c  : " << start_col_c << "\n"
+                << "Cref : \n"
+                << C_minus_ref << "\n"
+                << "C: \n"
+                << C_minus;
 
-          MatrixTransposeMatrixMultiply<kRowA, kColA, kRowB, kColB, -1>(
-              A.data(), kRowA, kColA,
-              B.data(), kRowB, kColB,
-              C_minus.data(), start_row_c, start_col_c, row_stride_c, col_stride_c);
+            C_assign_ref.block(start_row_c, start_col_c, kRowA, kColB) = A * B;
 
-          EXPECT_NEAR((C_minus_ref - C_minus).norm(), 0.0, kTolerance)
-              << "C -= A' * B \n"
-              << "row_stride_c : " << row_stride_c << "\n"
-              << "col_stride_c : " << col_stride_c << "\n"
-              << "start_row_c  : " << start_row_c << "\n"
-              << "start_col_c  : " << start_col_c << "\n"
-              << "Cref : \n" << C_minus_ref << "\n"
-              << "C: \n" << C_minus;
+            FunctorTy<kRowA, kColA, kRowB, kColB, 0, kDimType>()(
+                A.data(),
+                kRowA,
+                kColA,
+                B.data(),
+                kRowB,
+                kColB,
+                C_assign.data(),
+                start_row_c,
+                start_col_c,
+                row_stride_c,
+                col_stride_c);
 
-          C_assign_ref.block(start_row_c, start_col_c, kColA, kColB) =
-              A.transpose() * B;
-
-          MatrixTransposeMatrixMultiply<kRowA, kColA, kRowB, kColB, 0>(
-              A.data(), kRowA, kColA,
-              B.data(), kRowB, kColB,
-              C_assign.data(), start_row_c, start_col_c, row_stride_c, col_stride_c);
-
-          EXPECT_NEAR((C_assign_ref - C_assign).norm(), 0.0, kTolerance)
-              << "C = A' * B \n"
-              << "row_stride_c : " << row_stride_c << "\n"
-              << "col_stride_c : " << col_stride_c << "\n"
-              << "start_row_c  : " << start_row_c << "\n"
-              << "start_col_c  : " << start_col_c << "\n"
-              << "Cref : \n" << C_assign_ref << "\n"
-              << "C: \n" << C_assign;
+            EXPECT_NEAR((C_assign_ref - C_assign).norm(), 0.0, kTolerance)
+                << "C = A * B \n"
+                << "row_stride_c : " << row_stride_c << "\n"
+                << "col_stride_c : " << col_stride_c << "\n"
+                << "start_row_c  : " << start_row_c << "\n"
+                << "start_col_c  : " << start_col_c << "\n"
+                << "Cref : \n"
+                << C_assign_ref << "\n"
+                << "C: \n"
+                << C_assign;
+          }
         }
       }
-      // clang-format on
     }
   }
+};
+
+template <int kRowA,
+          int kColA,
+          int kColB,
+          DimType kDimType,
+          template <int, int, int, int, int, DimType>
+          class FunctorTy>
+struct TestMatrixTransposeFunctions {
+  void operator()() {
+    Matrix A(kRowA, kColA);
+    initMatrix(A);
+    const int kRowB = kRowA;
+    Matrix B(kRowB, kColB);
+    initMatrix(B);
+
+    for (int row_stride_c = kColA; row_stride_c < 3 * kColA; ++row_stride_c) {
+      for (int col_stride_c = kColB; col_stride_c < 3 * kColB; ++col_stride_c) {
+        Matrix C(row_stride_c, col_stride_c);
+        C.setOnes();
+
+        Matrix C_plus = C;
+        Matrix C_minus = C;
+        Matrix C_assign = C;
+
+        Matrix C_plus_ref = C;
+        Matrix C_minus_ref = C;
+        Matrix C_assign_ref = C;
+        for (int start_row_c = 0; start_row_c + kColA < row_stride_c;
+             ++start_row_c) {
+          for (int start_col_c = 0; start_col_c + kColB < col_stride_c;
+               ++start_col_c) {
+            C_plus_ref.block(start_row_c, start_col_c, kColA, kColB) +=
+                A.transpose() * B;
+
+            FunctorTy<kRowA, kColA, kRowB, kColB, 1, kDimType>()(A.data(),
+                                                                 kRowA,
+                                                                 kColA,
+                                                                 B.data(),
+                                                                 kRowB,
+                                                                 kColB,
+                                                                 C_plus.data(),
+                                                                 start_row_c,
+                                                                 start_col_c,
+                                                                 row_stride_c,
+                                                                 col_stride_c);
+
+            EXPECT_NEAR((C_plus_ref - C_plus).norm(), 0.0, kTolerance)
+                << "C += A' * B \n"
+                << "row_stride_c : " << row_stride_c << "\n"
+                << "col_stride_c : " << col_stride_c << "\n"
+                << "start_row_c  : " << start_row_c << "\n"
+                << "start_col_c  : " << start_col_c << "\n"
+                << "Cref : \n"
+                << C_plus_ref << "\n"
+                << "C: \n"
+                << C_plus;
+
+            C_minus_ref.block(start_row_c, start_col_c, kColA, kColB) -=
+                A.transpose() * B;
+
+            FunctorTy<kRowA, kColA, kRowB, kColB, -1, kDimType>()(
+                A.data(),
+                kRowA,
+                kColA,
+                B.data(),
+                kRowB,
+                kColB,
+                C_minus.data(),
+                start_row_c,
+                start_col_c,
+                row_stride_c,
+                col_stride_c);
+
+            EXPECT_NEAR((C_minus_ref - C_minus).norm(), 0.0, kTolerance)
+                << "C -= A' * B \n"
+                << "row_stride_c : " << row_stride_c << "\n"
+                << "col_stride_c : " << col_stride_c << "\n"
+                << "start_row_c  : " << start_row_c << "\n"
+                << "start_col_c  : " << start_col_c << "\n"
+                << "Cref : \n"
+                << C_minus_ref << "\n"
+                << "C: \n"
+                << C_minus;
+
+            C_assign_ref.block(start_row_c, start_col_c, kColA, kColB) =
+                A.transpose() * B;
+
+            FunctorTy<kRowA, kColA, kRowB, kColB, 0, kDimType>()(
+                A.data(),
+                kRowA,
+                kColA,
+                B.data(),
+                kRowB,
+                kColB,
+                C_assign.data(),
+                start_row_c,
+                start_col_c,
+                row_stride_c,
+                col_stride_c);
+
+            EXPECT_NEAR((C_assign_ref - C_assign).norm(), 0.0, kTolerance)
+                << "C = A' * B \n"
+                << "row_stride_c : " << row_stride_c << "\n"
+                << "col_stride_c : " << col_stride_c << "\n"
+                << "start_row_c  : " << start_row_c << "\n"
+                << "start_col_c  : " << start_col_c << "\n"
+                << "Cref : \n"
+                << C_assign_ref << "\n"
+                << "C: \n"
+                << C_assign;
+          }
+        }
+      }
+    }
+  }
+};
+
+TEST(BLAS, MatrixMatrixMultiply_5_3_7) {
+  TestMatrixFunctions<5, 3, 7, DimType::Static, MatrixMatrixMultiplyTy>()();
 }
 
-// TODO(sameeragarwal): Dedup and reduce the amount of duplication of
-// test code in this file.
-
-TEST(BLAS, MatrixMatrixMultiplyNaive) {
-  const int kRowA = 3;
-  const int kColA = 5;
-  Matrix A(kRowA, kColA);
-  A.setOnes();
-
-  const int kRowB = 5;
-  const int kColB = 7;
-  Matrix B(kRowB, kColB);
-  B.setOnes();
-
-  for (int row_stride_c = kRowA; row_stride_c < 3 * kRowA; ++row_stride_c) {
-    for (int col_stride_c = kColB; col_stride_c < 3 * kColB; ++col_stride_c) {
-      Matrix C(row_stride_c, col_stride_c);
-      C.setOnes();
-
-      Matrix C_plus = C;
-      Matrix C_minus = C;
-      Matrix C_assign = C;
-
-      Matrix C_plus_ref = C;
-      Matrix C_minus_ref = C;
-      Matrix C_assign_ref = C;
-      // clang-format off
-      for (int start_row_c = 0; start_row_c + kRowA < row_stride_c; ++start_row_c) {
-        for (int start_col_c = 0; start_col_c + kColB < col_stride_c; ++start_col_c) {
-          C_plus_ref.block(start_row_c, start_col_c, kRowA, kColB) +=
-              A * B;
-
-          MatrixMatrixMultiplyNaive<kRowA, kColA, kRowB, kColB, 1>(
-              A.data(), kRowA, kColA,
-              B.data(), kRowB, kColB,
-              C_plus.data(), start_row_c, start_col_c, row_stride_c, col_stride_c);
-
-          EXPECT_NEAR((C_plus_ref - C_plus).norm(), 0.0, kTolerance)
-              << "C += A * B \n"
-              << "row_stride_c : " << row_stride_c << "\n"
-              << "col_stride_c : " << col_stride_c << "\n"
-              << "start_row_c  : " << start_row_c << "\n"
-              << "start_col_c  : " << start_col_c << "\n"
-              << "Cref : \n" << C_plus_ref << "\n"
-              << "C: \n" << C_plus;
-
-          C_minus_ref.block(start_row_c, start_col_c, kRowA, kColB) -=
-              A * B;
-
-          MatrixMatrixMultiplyNaive<kRowA, kColA, kRowB, kColB, -1>(
-              A.data(), kRowA, kColA,
-              B.data(), kRowB, kColB,
-              C_minus.data(), start_row_c, start_col_c, row_stride_c, col_stride_c);
-
-           EXPECT_NEAR((C_minus_ref - C_minus).norm(), 0.0, kTolerance)
-              << "C -= A * B \n"
-              << "row_stride_c : " << row_stride_c << "\n"
-              << "col_stride_c : " << col_stride_c << "\n"
-              << "start_row_c  : " << start_row_c << "\n"
-              << "start_col_c  : " << start_col_c << "\n"
-              << "Cref : \n" << C_minus_ref << "\n"
-              << "C: \n" << C_minus;
-
-          C_assign_ref.block(start_row_c, start_col_c, kRowA, kColB) =
-              A * B;
-
-          MatrixMatrixMultiplyNaive<kRowA, kColA, kRowB, kColB, 0>(
-              A.data(), kRowA, kColA,
-              B.data(), kRowB, kColB,
-              C_assign.data(), start_row_c, start_col_c, row_stride_c, col_stride_c);
-
-          EXPECT_NEAR((C_assign_ref - C_assign).norm(), 0.0, kTolerance)
-              << "C = A * B \n"
-              << "row_stride_c : " << row_stride_c << "\n"
-              << "col_stride_c : " << col_stride_c << "\n"
-              << "start_row_c  : " << start_row_c << "\n"
-              << "start_col_c  : " << start_col_c << "\n"
-              << "Cref : \n" << C_assign_ref << "\n"
-              << "C: \n" << C_assign;
-        }
-      }
-      // clang-format on
-    }
-  }
+TEST(BLAS, MatrixMatrixMultiply_5_3_7_Dynamic) {
+  TestMatrixFunctions<5, 3, 7, DimType::Dynamic, MatrixMatrixMultiplyTy>()();
 }
 
-TEST(BLAS, MatrixTransposeMatrixMultiplyNaive) {
-  const int kRowA = 5;
-  const int kColA = 3;
-  Matrix A(kRowA, kColA);
-  A.setOnes();
+TEST(BLAS, MatrixMatrixMultiply_1_1_1) {
+  TestMatrixFunctions<1, 1, 1, DimType::Static, MatrixMatrixMultiplyTy>()();
+}
 
-  const int kRowB = 5;
-  const int kColB = 7;
-  Matrix B(kRowB, kColB);
-  B.setOnes();
+TEST(BLAS, MatrixMatrixMultiply_1_1_1_Dynamic) {
+  TestMatrixFunctions<1, 1, 1, DimType::Dynamic, MatrixMatrixMultiplyTy>()();
+}
 
-  for (int row_stride_c = kColA; row_stride_c < 3 * kColA; ++row_stride_c) {
-    for (int col_stride_c = kColB; col_stride_c < 3 * kColB; ++col_stride_c) {
-      Matrix C(row_stride_c, col_stride_c);
-      C.setOnes();
+TEST(BLAS, MatrixMatrixMultiply_9_9_9) {
+  TestMatrixFunctions<9, 9, 9, DimType::Static, MatrixMatrixMultiplyTy>()();
+}
 
-      Matrix C_plus = C;
-      Matrix C_minus = C;
-      Matrix C_assign = C;
+TEST(BLAS, MatrixMatrixMultiply_9_9_9_Dynamic) {
+  TestMatrixFunctions<9, 9, 9, DimType::Dynamic, MatrixMatrixMultiplyTy>()();
+}
 
-      Matrix C_plus_ref = C;
-      Matrix C_minus_ref = C;
-      Matrix C_assign_ref = C;
-      // clang-format off
-      for (int start_row_c = 0; start_row_c + kColA < row_stride_c; ++start_row_c) {
-        for (int start_col_c = 0; start_col_c + kColB < col_stride_c; ++start_col_c) {
-          C_plus_ref.block(start_row_c, start_col_c, kColA, kColB) +=
-              A.transpose() * B;
+TEST(BLAS, MatrixMatrixMultiplyNaive_5_3_7) {
+  TestMatrixFunctions<5,
+                      3,
+                      7,
+                      DimType::Static,
+                      MatrixMatrixMultiplyNaiveTy>()();
+}
 
-          MatrixTransposeMatrixMultiplyNaive<kRowA, kColA, kRowB, kColB, 1>(
-              A.data(), kRowA, kColA,
-              B.data(), kRowB, kColB,
-              C_plus.data(), start_row_c, start_col_c, row_stride_c, col_stride_c);
+TEST(BLAS, MatrixMatrixMultiplyNaive_5_3_7_Dynamic) {
+  TestMatrixFunctions<5,
+                      3,
+                      7,
+                      DimType::Dynamic,
+                      MatrixMatrixMultiplyNaiveTy>()();
+}
 
-          EXPECT_NEAR((C_plus_ref - C_plus).norm(), 0.0, kTolerance)
-              << "C += A' * B \n"
-              << "row_stride_c : " << row_stride_c << "\n"
-              << "col_stride_c : " << col_stride_c << "\n"
-              << "start_row_c  : " << start_row_c << "\n"
-              << "start_col_c  : " << start_col_c << "\n"
-              << "Cref : \n" << C_plus_ref << "\n"
-              << "C: \n" << C_plus;
+TEST(BLAS, MatrixMatrixMultiplyNaive_1_1_1) {
+  TestMatrixFunctions<1,
+                      1,
+                      1,
+                      DimType::Static,
+                      MatrixMatrixMultiplyNaiveTy>()();
+}
 
-          C_minus_ref.block(start_row_c, start_col_c, kColA, kColB) -=
-              A.transpose() * B;
+TEST(BLAS, MatrixMatrixMultiplyNaive_1_1_1_Dynamic) {
+  TestMatrixFunctions<1,
+                      1,
+                      1,
+                      DimType::Dynamic,
+                      MatrixMatrixMultiplyNaiveTy>()();
+}
 
-          MatrixTransposeMatrixMultiplyNaive<kRowA, kColA, kRowB, kColB, -1>(
-              A.data(), kRowA, kColA,
-              B.data(), kRowB, kColB,
-              C_minus.data(), start_row_c, start_col_c, row_stride_c, col_stride_c);
+TEST(BLAS, MatrixMatrixMultiplyNaive_9_9_9) {
+  TestMatrixFunctions<9,
+                      9,
+                      9,
+                      DimType::Static,
+                      MatrixMatrixMultiplyNaiveTy>()();
+}
 
-          EXPECT_NEAR((C_minus_ref - C_minus).norm(), 0.0, kTolerance)
-              << "C -= A' * B \n"
-              << "row_stride_c : " << row_stride_c << "\n"
-              << "col_stride_c : " << col_stride_c << "\n"
-              << "start_row_c  : " << start_row_c << "\n"
-              << "start_col_c  : " << start_col_c << "\n"
-              << "Cref : \n" << C_minus_ref << "\n"
-              << "C: \n" << C_minus;
+TEST(BLAS, MatrixMatrixMultiplyNaive_9_9_9_Dynamic) {
+  TestMatrixFunctions<9,
+                      9,
+                      9,
+                      DimType::Dynamic,
+                      MatrixMatrixMultiplyNaiveTy>()();
+}
 
-          C_assign_ref.block(start_row_c, start_col_c, kColA, kColB) =
-              A.transpose() * B;
+TEST(BLAS, MatrixTransposeMatrixMultiply_5_3_7) {
+  TestMatrixTransposeFunctions<5,
+                               3,
+                               7,
+                               DimType::Static,
+                               MatrixTransposeMatrixMultiplyTy>()();
+}
 
-          MatrixTransposeMatrixMultiplyNaive<kRowA, kColA, kRowB, kColB, 0>(
-              A.data(), kRowA, kColA,
-              B.data(), kRowB, kColB,
-              C_assign.data(), start_row_c, start_col_c, row_stride_c, col_stride_c);
+TEST(BLAS, MatrixTransposeMatrixMultiply_5_3_7_Dynamic) {
+  TestMatrixTransposeFunctions<5,
+                               3,
+                               7,
+                               DimType::Dynamic,
+                               MatrixTransposeMatrixMultiplyTy>()();
+}
 
-          EXPECT_NEAR((C_assign_ref - C_assign).norm(), 0.0, kTolerance)
-              << "C = A' * B \n"
-              << "row_stride_c : " << row_stride_c << "\n"
-              << "col_stride_c : " << col_stride_c << "\n"
-              << "start_row_c  : " << start_row_c << "\n"
-              << "start_col_c  : " << start_col_c << "\n"
-              << "Cref : \n" << C_assign_ref << "\n"
-              << "C: \n" << C_assign;
-        }
-      }
-      // clang-format on
-    }
-  }
+TEST(BLAS, MatrixTransposeMatrixMultiply_1_1_1) {
+  TestMatrixTransposeFunctions<1,
+                               1,
+                               1,
+                               DimType::Static,
+                               MatrixTransposeMatrixMultiplyTy>()();
+}
+
+TEST(BLAS, MatrixTransposeMatrixMultiply_1_1_1_Dynamic) {
+  TestMatrixTransposeFunctions<1,
+                               1,
+                               1,
+                               DimType::Dynamic,
+                               MatrixTransposeMatrixMultiplyTy>()();
+}
+
+TEST(BLAS, MatrixTransposeMatrixMultiply_9_9_9) {
+  TestMatrixTransposeFunctions<9,
+                               9,
+                               9,
+                               DimType::Static,
+                               MatrixTransposeMatrixMultiplyTy>()();
+}
+
+TEST(BLAS, MatrixTransposeMatrixMultiply_9_9_9_Dynamic) {
+  TestMatrixTransposeFunctions<9,
+                               9,
+                               9,
+                               DimType::Dynamic,
+                               MatrixTransposeMatrixMultiplyTy>()();
+}
+
+TEST(BLAS, MatrixTransposeMatrixMultiplyNaive_5_3_7) {
+  TestMatrixTransposeFunctions<5,
+                               3,
+                               7,
+                               DimType::Static,
+                               MatrixTransposeMatrixMultiplyNaiveTy>()();
+}
+
+TEST(BLAS, MatrixTransposeMatrixMultiplyNaive_5_3_7_Dynamic) {
+  TestMatrixTransposeFunctions<5,
+                               3,
+                               7,
+                               DimType::Dynamic,
+                               MatrixTransposeMatrixMultiplyNaiveTy>()();
+}
+
+TEST(BLAS, MatrixTransposeMatrixMultiplyNaive_1_1_1) {
+  TestMatrixTransposeFunctions<1,
+                               1,
+                               1,
+                               DimType::Static,
+                               MatrixTransposeMatrixMultiplyNaiveTy>()();
+}
+
+TEST(BLAS, MatrixTransposeMatrixMultiplyNaive_1_1_1_Dynamic) {
+  TestMatrixTransposeFunctions<1,
+                               1,
+                               1,
+                               DimType::Dynamic,
+                               MatrixTransposeMatrixMultiplyNaiveTy>()();
+}
+
+TEST(BLAS, MatrixTransposeMatrixMultiplyNaive_9_9_9) {
+  TestMatrixTransposeFunctions<9,
+                               9,
+                               9,
+                               DimType::Static,
+                               MatrixTransposeMatrixMultiplyNaiveTy>()();
+}
+
+TEST(BLAS, MatrixTransposeMatrixMultiplyNaive_9_9_9_Dynamic) {
+  TestMatrixTransposeFunctions<9,
+                               9,
+                               9,
+                               DimType::Dynamic,
+                               MatrixTransposeMatrixMultiplyNaiveTy>()();
 }
 
 TEST(BLAS, MatrixVectorMultiply) {
@@ -412,7 +545,7 @@
           b.data(),
           c_minus.data());
       EXPECT_NEAR((c_minus_ref - c_minus).norm(), 0.0, kTolerance)
-          << "c += A * b \n"
+          << "c -= A * b \n"
           << "c_ref : \n" << c_minus_ref << "\n"
           << "c: \n" << c_minus;
 
@@ -422,7 +555,7 @@
           b.data(),
           c_assign.data());
       EXPECT_NEAR((c_assign_ref - c_assign).norm(), 0.0, kTolerance)
-          << "c += A * b \n"
+          << "c = A * b \n"
           << "c_ref : \n" << c_assign_ref << "\n"
           << "c: \n" << c_assign;
       // clang-format on
@@ -467,7 +600,7 @@
           b.data(),
           c_minus.data());
       EXPECT_NEAR((c_minus_ref - c_minus).norm(), 0.0, kTolerance)
-          << "c += A' * b \n"
+          << "c -= A' * b \n"
           << "c_ref : \n" << c_minus_ref << "\n"
           << "c: \n" << c_minus;
 
@@ -477,7 +610,7 @@
           b.data(),
           c_assign.data());
       EXPECT_NEAR((c_assign_ref - c_assign).norm(), 0.0, kTolerance)
-          << "c += A' * b \n"
+          << "c = A' * b \n"
           << "c_ref : \n" << c_assign_ref << "\n"
           << "c: \n" << c_assign;
       // clang-format on
diff --git a/third_party/ceres/internal/ceres/solver.cc b/third_party/ceres/internal/ceres/solver.cc
index dfde122..611e465 100644
--- a/third_party/ceres/internal/ceres/solver.cc
+++ b/third_party/ceres/internal/ceres/solver.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -32,16 +32,19 @@
 #include "ceres/solver.h"
 
 #include <algorithm>
+#include <map>
 #include <memory>
 #include <sstream>  // NOLINT
+#include <string>
 #include <vector>
 
 #include "ceres/casts.h"
 #include "ceres/context.h"
 #include "ceres/context_impl.h"
 #include "ceres/detect_structure.h"
+#include "ceres/eigensparse.h"
 #include "ceres/gradient_checking_cost_function.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 #include "ceres/parameter_block_ordering.h"
 #include "ceres/preprocessor.h"
 #include "ceres/problem.h"
@@ -50,6 +53,7 @@
 #include "ceres/schur_templates.h"
 #include "ceres/solver_utils.h"
 #include "ceres/stringprintf.h"
+#include "ceres/suitesparse.h"
 #include "ceres/types.h"
 #include "ceres/wall_time.h"
 
@@ -58,32 +62,29 @@
 
 using internal::StringAppendF;
 using internal::StringPrintf;
-using std::map;
-using std::string;
-using std::vector;
 
-#define OPTION_OP(x, y, OP)                                          \
-  if (!(options.x OP y)) {                                           \
-    std::stringstream ss;                                            \
-    ss << "Invalid configuration. ";                                 \
-    ss << string("Solver::Options::" #x " = ") << options.x << ". "; \
-    ss << "Violated constraint: ";                                   \
-    ss << string("Solver::Options::" #x " " #OP " " #y);             \
-    *error = ss.str();                                               \
-    return false;                                                    \
+#define OPTION_OP(x, y, OP)                                               \
+  if (!(options.x OP y)) {                                                \
+    std::stringstream ss;                                                 \
+    ss << "Invalid configuration. ";                                      \
+    ss << std::string("Solver::Options::" #x " = ") << options.x << ". "; \
+    ss << "Violated constraint: ";                                        \
+    ss << std::string("Solver::Options::" #x " " #OP " " #y);             \
+    *error = ss.str();                                                    \
+    return false;                                                         \
   }
 
-#define OPTION_OP_OPTION(x, y, OP)                                   \
-  if (!(options.x OP options.y)) {                                   \
-    std::stringstream ss;                                            \
-    ss << "Invalid configuration. ";                                 \
-    ss << string("Solver::Options::" #x " = ") << options.x << ". "; \
-    ss << string("Solver::Options::" #y " = ") << options.y << ". "; \
-    ss << "Violated constraint: ";                                   \
-    ss << string("Solver::Options::" #x);                            \
-    ss << string(#OP " Solver::Options::" #y ".");                   \
-    *error = ss.str();                                               \
-    return false;                                                    \
+#define OPTION_OP_OPTION(x, y, OP)                                        \
+  if (!(options.x OP options.y)) {                                        \
+    std::stringstream ss;                                                 \
+    ss << "Invalid configuration. ";                                      \
+    ss << std::string("Solver::Options::" #x " = ") << options.x << ". "; \
+    ss << std::string("Solver::Options::" #y " = ") << options.y << ". "; \
+    ss << "Violated constraint: ";                                        \
+    ss << std::string("Solver::Options::" #x);                            \
+    ss << std::string(#OP " Solver::Options::" #y ".");                   \
+    *error = ss.str();                                                    \
+    return false;                                                         \
   }
 
 #define OPTION_GE(x, y) OPTION_OP(x, y, >=);
@@ -93,7 +94,7 @@
 #define OPTION_LE_OPTION(x, y) OPTION_OP_OPTION(x, y, <=)
 #define OPTION_LT_OPTION(x, y) OPTION_OP_OPTION(x, y, <)
 
-bool CommonOptionsAreValid(const Solver::Options& options, string* error) {
+bool CommonOptionsAreValid(const Solver::Options& options, std::string* error) {
   OPTION_GE(max_num_iterations, 0);
   OPTION_GE(max_solver_time_in_seconds, 0.0);
   OPTION_GE(function_tolerance, 0.0);
@@ -107,7 +108,286 @@
   return true;
 }
 
-bool TrustRegionOptionsAreValid(const Solver::Options& options, string* error) {
+bool IsNestedDissectionAvailable(SparseLinearAlgebraLibraryType type) {
+  return (((type == SUITE_SPARSE) &&
+           internal::SuiteSparse::IsNestedDissectionAvailable()) ||
+          (type == ACCELERATE_SPARSE) ||
+          ((type == EIGEN_SPARSE) &&
+           internal::EigenSparse::IsNestedDissectionAvailable()));
+}
+
+bool IsIterativeSolver(LinearSolverType type) {
+  return (type == CGNR || type == ITERATIVE_SCHUR);
+}
+
+bool OptionsAreValidForDenseSolver(const Solver::Options& options,
+                                   std::string* error) {
+  const char* library_name = DenseLinearAlgebraLibraryTypeToString(
+      options.dense_linear_algebra_library_type);
+  const char* solver_name =
+      LinearSolverTypeToString(options.linear_solver_type);
+  constexpr char kFormat[] =
+      "Can't use %s with dense_linear_algebra_library_type = %s "
+      "because support not enabled when Ceres was built.";
+
+  if (!IsDenseLinearAlgebraLibraryTypeAvailable(
+          options.dense_linear_algebra_library_type)) {
+    *error = StringPrintf(kFormat, solver_name, library_name);
+    return false;
+  }
+  return true;
+}
+
+bool OptionsAreValidForSparseCholeskyBasedSolver(const Solver::Options& options,
+                                                 std::string* error) {
+  const char* library_name = SparseLinearAlgebraLibraryTypeToString(
+      options.sparse_linear_algebra_library_type);
+  // Sparse factorization based solvers and some preconditioners require a
+  // sparse Cholesky factorization.
+  const char* solver_name =
+      IsIterativeSolver(options.linear_solver_type)
+          ? PreconditionerTypeToString(options.preconditioner_type)
+          : LinearSolverTypeToString(options.linear_solver_type);
+
+  constexpr char kNoSparseFormat[] =
+      "Can't use %s with sparse_linear_algebra_library_type = %s.";
+  constexpr char kNoLibraryFormat[] =
+      "Can't use %s sparse_linear_algebra_library_type = %s, because support "
+      "was not enabled when Ceres Solver was built.";
+  constexpr char kNoNesdisFormat[] =
+      "NESDIS is not available with sparse_linear_algebra_library_type = %s.";
+  constexpr char kMixedFormat[] =
+      "use_mixed_precision_solves with %s is not supported with "
+      "sparse_linear_algebra_library_type = %s";
+  constexpr char kDynamicSparsityFormat[] =
+      "dynamic sparsity is not supported with "
+      "sparse_linear_algebra_library_type = %s";
+
+  if (options.sparse_linear_algebra_library_type == NO_SPARSE) {
+    *error = StringPrintf(kNoSparseFormat, solver_name, library_name);
+    return false;
+  }
+
+  if (!IsSparseLinearAlgebraLibraryTypeAvailable(
+          options.sparse_linear_algebra_library_type)) {
+    *error = StringPrintf(kNoLibraryFormat, solver_name, library_name);
+    return false;
+  }
+
+  if (options.linear_solver_ordering_type == ceres::NESDIS &&
+      !IsNestedDissectionAvailable(
+          options.sparse_linear_algebra_library_type)) {
+    *error = StringPrintf(kNoNesdisFormat, library_name);
+    return false;
+  }
+
+  if (options.use_mixed_precision_solves &&
+      options.sparse_linear_algebra_library_type == SUITE_SPARSE) {
+    *error = StringPrintf(kMixedFormat, solver_name, library_name);
+    return false;
+  }
+
+  if (options.dynamic_sparsity &&
+      options.sparse_linear_algebra_library_type == ACCELERATE_SPARSE) {
+    *error = StringPrintf(kDynamicSparsityFormat, library_name);
+    return false;
+  }
+
+  return true;
+}
+
+bool OptionsAreValidForDenseNormalCholesky(const Solver::Options& options,
+                                           std::string* error) {
+  CHECK_EQ(options.linear_solver_type, DENSE_NORMAL_CHOLESKY);
+  return OptionsAreValidForDenseSolver(options, error);
+}
+
+bool OptionsAreValidForDenseQr(const Solver::Options& options,
+                               std::string* error) {
+  CHECK_EQ(options.linear_solver_type, DENSE_QR);
+
+  if (!OptionsAreValidForDenseSolver(options, error)) {
+    return false;
+  }
+
+  if (options.use_mixed_precision_solves) {
+    *error = "Can't use use_mixed_precision_solves with DENSE_QR.";
+    return false;
+  }
+
+  return true;
+}
+
+bool OptionsAreValidForSparseNormalCholesky(const Solver::Options& options,
+                                            std::string* error) {
+  CHECK_EQ(options.linear_solver_type, SPARSE_NORMAL_CHOLESKY);
+  return OptionsAreValidForSparseCholeskyBasedSolver(options, error);
+}
+
+bool OptionsAreValidForDenseSchur(const Solver::Options& options,
+                                  std::string* error) {
+  CHECK_EQ(options.linear_solver_type, DENSE_SCHUR);
+
+  if (options.dynamic_sparsity) {
+    *error = "dynamic sparsity is only supported with SPARSE_NORMAL_CHOLESKY";
+    return false;
+  }
+
+  if (!OptionsAreValidForDenseSolver(options, error)) {
+    return false;
+  }
+
+  return true;
+}
+
+bool OptionsAreValidForSparseSchur(const Solver::Options& options,
+                                   std::string* error) {
+  CHECK_EQ(options.linear_solver_type, SPARSE_SCHUR);
+  if (options.dynamic_sparsity) {
+    *error = "Dynamic sparsity is only supported with SPARSE_NORMAL_CHOLESKY.";
+    return false;
+  }
+  return OptionsAreValidForSparseCholeskyBasedSolver(options, error);
+}
+
+bool OptionsAreValidForIterativeSchur(const Solver::Options& options,
+                                      std::string* error) {
+  CHECK_EQ(options.linear_solver_type, ITERATIVE_SCHUR);
+  if (options.dynamic_sparsity) {
+    *error = "Dynamic sparsity is only supported with SPARSE_NORMAL_CHOLESKY.";
+    return false;
+  }
+
+  if (options.use_explicit_schur_complement) {
+    if (options.preconditioner_type != SCHUR_JACOBI) {
+      *error =
+          "use_explicit_schur_complement only supports "
+          "SCHUR_JACOBI as the preconditioner.";
+      return false;
+    }
+    if (options.use_spse_initialization) {
+      *error =
+          "use_explicit_schur_complement does not support "
+          "use_spse_initialization.";
+      return false;
+    }
+  }
+
+  if (options.use_spse_initialization ||
+      options.preconditioner_type == SCHUR_POWER_SERIES_EXPANSION) {
+    OPTION_GE(max_num_spse_iterations, 1)
+    OPTION_GE(spse_tolerance, 0.0)
+  }
+
+  if (options.use_mixed_precision_solves) {
+    *error = "Can't use use_mixed_precision_solves with ITERATIVE_SCHUR";
+    return false;
+  }
+
+  if (options.dynamic_sparsity) {
+    *error = "Dynamic sparsity is only supported with SPARSE_NORMAL_CHOLESKY.";
+    return false;
+  }
+
+  if (options.preconditioner_type == SUBSET) {
+    *error = "Can't use SUBSET preconditioner with ITERATIVE_SCHUR";
+    return false;
+  }
+
+  // CLUSTER_JACOBI and CLUSTER_TRIDIAGONAL require sparse Cholesky
+  // factorization.
+  if (options.preconditioner_type == CLUSTER_JACOBI ||
+      options.preconditioner_type == CLUSTER_TRIDIAGONAL) {
+    return OptionsAreValidForSparseCholeskyBasedSolver(options, error);
+  }
+
+  return true;
+}
+
+bool OptionsAreValidForCgnr(const Solver::Options& options,
+                            std::string* error) {
+  CHECK_EQ(options.linear_solver_type, CGNR);
+
+  if (options.preconditioner_type != IDENTITY &&
+      options.preconditioner_type != JACOBI &&
+      options.preconditioner_type != SUBSET) {
+    *error =
+        StringPrintf("Can't use CGNR with preconditioner_type = %s.",
+                     PreconditionerTypeToString(options.preconditioner_type));
+    return false;
+  }
+
+  if (options.use_mixed_precision_solves) {
+    *error = "use_mixed_precision_solves cannot be used with CGNR";
+    return false;
+  }
+
+  if (options.dynamic_sparsity) {
+    *error = "Dynamic sparsity is only supported with SPARSE_NORMAL_CHOLESKY.";
+    return false;
+  }
+
+  if (options.preconditioner_type == SUBSET) {
+    if (options.sparse_linear_algebra_library_type == CUDA_SPARSE) {
+      *error =
+          "Can't use CGNR with preconditioner_type = SUBSET when "
+          "sparse_linear_algebra_library_type = CUDA_SPARSE.";
+      return false;
+    }
+
+    if (options.residual_blocks_for_subset_preconditioner.empty()) {
+      *error =
+          "When using SUBSET preconditioner, "
+          "residual_blocks_for_subset_preconditioner cannot be empty";
+      return false;
+    }
+
+    // SUBSET preconditioner requires sparse Cholesky factorization.
+    if (!OptionsAreValidForSparseCholeskyBasedSolver(options, error)) {
+      return false;
+    }
+  }
+
+  // Check options for CGNR with CUDA_SPARSE.
+  if (options.sparse_linear_algebra_library_type == CUDA_SPARSE) {
+    if (!IsSparseLinearAlgebraLibraryTypeAvailable(CUDA_SPARSE)) {
+      *error =
+          "Can't use CGNR with sparse_linear_algebra_library_type = "
+          "CUDA_SPARSE because support was not enabled when Ceres was built.";
+      return false;
+    }
+  }
+  return true;
+}
+
+bool OptionsAreValidForLinearSolver(const Solver::Options& options,
+                                    std::string* error) {
+  switch (options.linear_solver_type) {
+    case DENSE_NORMAL_CHOLESKY:
+      return OptionsAreValidForDenseNormalCholesky(options, error);
+    case DENSE_QR:
+      return OptionsAreValidForDenseQr(options, error);
+    case SPARSE_NORMAL_CHOLESKY:
+      return OptionsAreValidForSparseNormalCholesky(options, error);
+    case DENSE_SCHUR:
+      return OptionsAreValidForDenseSchur(options, error);
+    case SPARSE_SCHUR:
+      return OptionsAreValidForSparseSchur(options, error);
+    case ITERATIVE_SCHUR:
+      return OptionsAreValidForIterativeSchur(options, error);
+    case CGNR:
+      return OptionsAreValidForCgnr(options, error);
+    default:
+      LOG(FATAL) << "Congratulations you have found a bug. Please report "
+                    "this to the "
+                    "Ceres Solver developers. Unknown linear solver type: "
+                 << LinearSolverTypeToString(options.linear_solver_type);
+  }
+  return false;
+}
+
+bool TrustRegionOptionsAreValid(const Solver::Options& options,
+                                std::string* error) {
   OPTION_GT(initial_trust_region_radius, 0.0);
   OPTION_GT(min_trust_region_radius, 0.0);
   OPTION_GT(max_trust_region_radius, 0.0);
@@ -121,7 +401,7 @@
   OPTION_GE(max_num_consecutive_invalid_steps, 0);
   OPTION_GT(eta, 0.0);
   OPTION_GE(min_linear_solver_iterations, 0);
-  OPTION_GE(max_linear_solver_iterations, 1);
+  OPTION_GE(max_linear_solver_iterations, 0);
   OPTION_LE_OPTION(min_linear_solver_iterations, max_linear_solver_iterations);
 
   if (options.use_inner_iterations) {
@@ -132,76 +412,19 @@
     OPTION_GT(max_consecutive_nonmonotonic_steps, 0);
   }
 
-  if (options.linear_solver_type == ITERATIVE_SCHUR &&
-      options.use_explicit_schur_complement &&
-      options.preconditioner_type != SCHUR_JACOBI) {
+  if ((options.trust_region_strategy_type == DOGLEG) &&
+      IsIterativeSolver(options.linear_solver_type)) {
     *error =
-        "use_explicit_schur_complement only supports "
-        "SCHUR_JACOBI as the preconditioner.";
+        "DOGLEG only supports exact factorization based linear "
+        "solvers. If you want to use an iterative solver please "
+        "use LEVENBERG_MARQUARDT as the trust_region_strategy_type";
     return false;
   }
 
-  if (options.dense_linear_algebra_library_type == LAPACK &&
-      !IsDenseLinearAlgebraLibraryTypeAvailable(LAPACK) &&
-      (options.linear_solver_type == DENSE_NORMAL_CHOLESKY ||
-       options.linear_solver_type == DENSE_QR ||
-       options.linear_solver_type == DENSE_SCHUR)) {
-    *error = StringPrintf(
-        "Can't use %s with "
-        "Solver::Options::dense_linear_algebra_library_type = LAPACK "
-        "because LAPACK was not enabled when Ceres was built.",
-        LinearSolverTypeToString(options.linear_solver_type));
+  if (!OptionsAreValidForLinearSolver(options, error)) {
     return false;
   }
 
-  {
-    const char* sparse_linear_algebra_library_name =
-        SparseLinearAlgebraLibraryTypeToString(
-            options.sparse_linear_algebra_library_type);
-    const char* name = nullptr;
-    if (options.linear_solver_type == SPARSE_NORMAL_CHOLESKY ||
-        options.linear_solver_type == SPARSE_SCHUR) {
-      name = LinearSolverTypeToString(options.linear_solver_type);
-    } else if ((options.linear_solver_type == ITERATIVE_SCHUR &&
-                (options.preconditioner_type == CLUSTER_JACOBI ||
-                 options.preconditioner_type == CLUSTER_TRIDIAGONAL)) ||
-               (options.linear_solver_type == CGNR &&
-                options.preconditioner_type == SUBSET)) {
-      name = PreconditionerTypeToString(options.preconditioner_type);
-    }
-
-    if (name) {
-      if (options.sparse_linear_algebra_library_type == NO_SPARSE) {
-        *error = StringPrintf(
-            "Can't use %s with "
-            "Solver::Options::sparse_linear_algebra_library_type = %s.",
-            name,
-            sparse_linear_algebra_library_name);
-        return false;
-      } else if (!IsSparseLinearAlgebraLibraryTypeAvailable(
-                     options.sparse_linear_algebra_library_type)) {
-        *error = StringPrintf(
-            "Can't use %s with "
-            "Solver::Options::sparse_linear_algebra_library_type = %s, "
-            "because support was not enabled when Ceres Solver was built.",
-            name,
-            sparse_linear_algebra_library_name);
-        return false;
-      }
-    }
-  }
-
-  if (options.trust_region_strategy_type == DOGLEG) {
-    if (options.linear_solver_type == ITERATIVE_SCHUR ||
-        options.linear_solver_type == CGNR) {
-      *error =
-          "DOGLEG only supports exact factorization based linear "
-          "solvers. If you want to use an iterative solver please "
-          "use LEVENBERG_MARQUARDT as the trust_region_strategy_type";
-      return false;
-    }
-  }
-
   if (!options.trust_region_minimizer_iterations_to_dump.empty() &&
       options.trust_region_problem_dump_format_type != CONSOLE &&
       options.trust_region_problem_dump_directory.empty()) {
@@ -209,33 +432,11 @@
     return false;
   }
 
-  if (options.dynamic_sparsity) {
-    if (options.linear_solver_type != SPARSE_NORMAL_CHOLESKY) {
-      *error =
-          "Dynamic sparsity is only supported with SPARSE_NORMAL_CHOLESKY.";
-      return false;
-    }
-    if (options.sparse_linear_algebra_library_type == ACCELERATE_SPARSE) {
-      *error =
-          "ACCELERATE_SPARSE is not currently supported with dynamic sparsity.";
-      return false;
-    }
-  }
-
-  if (options.linear_solver_type == CGNR &&
-      options.preconditioner_type == SUBSET &&
-      options.residual_blocks_for_subset_preconditioner.empty()) {
-    *error =
-        "When using SUBSET preconditioner, "
-        "Solver::Options::residual_blocks_for_subset_preconditioner cannot be "
-        "empty";
-    return false;
-  }
-
   return true;
 }
 
-bool LineSearchOptionsAreValid(const Solver::Options& options, string* error) {
+bool LineSearchOptionsAreValid(const Solver::Options& options,
+                               std::string* error) {
   OPTION_GT(max_lbfgs_rank, 0);
   OPTION_GT(min_line_search_step_size, 0.0);
   OPTION_GT(max_line_search_step_contraction, 0.0);
@@ -255,9 +456,10 @@
        options.line_search_direction_type == ceres::LBFGS) &&
       options.line_search_type != ceres::WOLFE) {
     *error =
-        string("Invalid configuration: Solver::Options::line_search_type = ") +
-        string(LineSearchTypeToString(options.line_search_type)) +
-        string(
+        std::string(
+            "Invalid configuration: Solver::Options::line_search_type = ") +
+        std::string(LineSearchTypeToString(options.line_search_type)) +
+        std::string(
             ". When using (L)BFGS, "
             "Solver::Options::line_search_type must be set to WOLFE.");
     return false;
@@ -265,8 +467,8 @@
 
   // Warn user if they have requested BISECTION interpolation, but constraints
   // on max/min step size change during line search prevent bisection scaling
-  // from occurring. Warn only, as this is likely a user mistake, but one which
-  // does not prevent us from continuing.
+  // from occurring. Warn only, as this is likely a user mistake, but one
+  // which does not prevent us from continuing.
   if (options.line_search_interpolation_type == ceres::BISECTION &&
       (options.max_line_search_step_contraction > 0.5 ||
        options.min_line_search_step_contraction < 0.5)) {
@@ -291,7 +493,7 @@
 #undef OPTION_LE_OPTION
 #undef OPTION_LT_OPTION
 
-void StringifyOrdering(const vector<int>& ordering, string* report) {
+void StringifyOrdering(const std::vector<int>& ordering, std::string* report) {
   if (ordering.empty()) {
     internal::StringAppendF(report, "AUTOMATIC");
     return;
@@ -335,7 +537,7 @@
                                  &(summary->inner_iteration_ordering_given));
 
   // clang-format off
-  summary->dense_linear_algebra_library_type  = options.dense_linear_algebra_library_type;  //  NOLINT
+  summary->dense_linear_algebra_library_type  = options.dense_linear_algebra_library_type;
   summary->dogleg_type                        = options.dogleg_type;
   summary->inner_iteration_time_in_seconds    = 0.0;
   summary->num_line_search_steps              = 0;
@@ -344,18 +546,19 @@
   summary->line_search_polynomial_minimization_time_in_seconds = 0.0;
   summary->line_search_total_time_in_seconds  = 0.0;
   summary->inner_iterations_given             = options.use_inner_iterations;
-  summary->line_search_direction_type         = options.line_search_direction_type;         //  NOLINT
-  summary->line_search_interpolation_type     = options.line_search_interpolation_type;     //  NOLINT
+  summary->line_search_direction_type         = options.line_search_direction_type;
+  summary->line_search_interpolation_type     = options.line_search_interpolation_type;
   summary->line_search_type                   = options.line_search_type;
   summary->linear_solver_type_given           = options.linear_solver_type;
   summary->max_lbfgs_rank                     = options.max_lbfgs_rank;
   summary->minimizer_type                     = options.minimizer_type;
-  summary->nonlinear_conjugate_gradient_type  = options.nonlinear_conjugate_gradient_type;  //  NOLINT
+  summary->nonlinear_conjugate_gradient_type  = options.nonlinear_conjugate_gradient_type;
   summary->num_threads_given                  = options.num_threads;
   summary->preconditioner_type_given          = options.preconditioner_type;
-  summary->sparse_linear_algebra_library_type = options.sparse_linear_algebra_library_type; //  NOLINT
-  summary->trust_region_strategy_type         = options.trust_region_strategy_type;         //  NOLINT
-  summary->visibility_clustering_type         = options.visibility_clustering_type;         //  NOLINT
+  summary->sparse_linear_algebra_library_type = options.sparse_linear_algebra_library_type;
+  summary->linear_solver_ordering_type        = options.linear_solver_ordering_type;
+  summary->trust_region_strategy_type         = options.trust_region_strategy_type;
+  summary->visibility_clustering_type         = options.visibility_clustering_type;
   // clang-format on
 }
 
@@ -363,19 +566,23 @@
                         Solver::Summary* summary) {
   internal::OrderingToGroupSizes(pp.options.linear_solver_ordering.get(),
                                  &(summary->linear_solver_ordering_used));
+  // TODO(sameeragarwal): Update the preprocessor to collapse the
+  // second and higher groups into one group when nested dissection is
+  // used.
   internal::OrderingToGroupSizes(pp.options.inner_iteration_ordering.get(),
                                  &(summary->inner_iteration_ordering_used));
 
   // clang-format off
-  summary->inner_iterations_used          = pp.inner_iteration_minimizer.get() != NULL;     // NOLINT
+  summary->inner_iterations_used          = pp.inner_iteration_minimizer != nullptr;
   summary->linear_solver_type_used        = pp.linear_solver_options.type;
+  summary->mixed_precision_solves_used    = pp.options.use_mixed_precision_solves;
   summary->num_threads_used               = pp.options.num_threads;
   summary->preconditioner_type_used       = pp.options.preconditioner_type;
   // clang-format on
 
   internal::SetSummaryFinalCost(summary);
 
-  if (pp.reduced_program.get() != NULL) {
+  if (pp.reduced_program != nullptr) {
     SummarizeReducedProgram(*pp.reduced_program, summary);
   }
 
@@ -385,8 +592,8 @@
   // case if the preprocessor failed, or if the reduced problem did
   // not contain any parameter blocks. Thus, only extract the
   // evaluator statistics if one exists.
-  if (pp.evaluator.get() != NULL) {
-    const map<string, CallStatistics>& evaluator_statistics =
+  if (pp.evaluator != nullptr) {
+    const std::map<std::string, CallStatistics>& evaluator_statistics =
         pp.evaluator->Statistics();
     {
       const CallStatistics& call_stats = FindWithDefault(
@@ -407,8 +614,8 @@
   // Again, like the evaluator, there may or may not be a linear
   // solver from which we can extract run time statistics. In
   // particular the line search solver does not use a linear solver.
-  if (pp.linear_solver.get() != NULL) {
-    const map<string, CallStatistics>& linear_solver_statistics =
+  if (pp.linear_solver != nullptr) {
+    const std::map<std::string, CallStatistics>& linear_solver_statistics =
         pp.linear_solver->Statistics();
     const CallStatistics& call_stats = FindWithDefault(
         linear_solver_statistics, "LinearSolver::Solve", CallStatistics());
@@ -436,8 +643,7 @@
   }
 
   const Vector original_reduced_parameters = pp->reduced_parameters;
-  std::unique_ptr<Minimizer> minimizer(
-      Minimizer::Create(pp->options.minimizer_type));
+  auto minimizer = Minimizer::Create(pp->options.minimizer_type);
   minimizer->Minimize(
       pp->minimizer_options, pp->reduced_parameters.data(), summary);
 
@@ -465,9 +671,23 @@
   return internal::StringPrintf("%s,%s,%s", row.c_str(), e.c_str(), f.c_str());
 }
 
+#ifndef CERES_NO_CUDA
+bool IsCudaRequired(const Solver::Options& options) {
+  if (options.linear_solver_type == DENSE_NORMAL_CHOLESKY ||
+      options.linear_solver_type == DENSE_SCHUR ||
+      options.linear_solver_type == DENSE_QR) {
+    return (options.dense_linear_algebra_library_type == CUDA);
+  }
+  if (options.linear_solver_type == CGNR) {
+    return (options.sparse_linear_algebra_library_type == CUDA_SPARSE);
+  }
+  return false;
+}
+#endif
+
 }  // namespace
 
-bool Solver::Options::IsValid(string* error) const {
+bool Solver::Options::IsValid(std::string* error) const {
   if (!CommonOptionsAreValid(*this, error)) {
     return false;
   }
@@ -485,7 +705,7 @@
   return LineSearchOptionsAreValid(*this, error);
 }
 
-Solver::~Solver() {}
+Solver::~Solver() = default;
 
 void Solver::Solve(const Solver::Options& options,
                    Problem* problem,
@@ -506,10 +726,19 @@
     return;
   }
 
-  ProblemImpl* problem_impl = problem->impl_.get();
+  ProblemImpl* problem_impl = problem->mutable_impl();
   Program* program = problem_impl->mutable_program();
   PreSolveSummarize(options, problem_impl, summary);
 
+#ifndef CERES_NO_CUDA
+  if (IsCudaRequired(options)) {
+    if (!problem_impl->context()->InitCuda(&summary->message)) {
+      LOG(ERROR) << "Terminating: " << summary->message;
+      return;
+    }
+  }
+#endif  // CERES_NO_CUDA
+
   // If gradient_checking is enabled, wrap all cost functions in a
   // gradient checker and install a callback that terminates if any gradient
   // error is detected.
@@ -518,11 +747,11 @@
   Solver::Options modified_options = options;
   if (options.check_gradients) {
     modified_options.callbacks.push_back(&gradient_checking_callback);
-    gradient_checking_problem.reset(CreateGradientCheckingProblemImpl(
+    gradient_checking_problem = CreateGradientCheckingProblemImpl(
         problem_impl,
         options.gradient_check_numeric_derivative_relative_step_size,
         options.gradient_check_relative_precision,
-        &gradient_checking_callback));
+        &gradient_checking_callback);
     problem_impl = gradient_checking_problem.get();
     program = problem_impl->mutable_program();
   }
@@ -534,8 +763,7 @@
   // The main thread also does work so we only need to launch num_threads - 1.
   problem_impl->context()->EnsureMinimumThreads(options.num_threads - 1);
 
-  std::unique_ptr<Preprocessor> preprocessor(
-      Preprocessor::Create(modified_options.minimizer_type));
+  auto preprocessor = Preprocessor::Create(modified_options.minimizer_type);
   PreprocessedProblem pp;
 
   const bool status =
@@ -545,7 +773,7 @@
   // modified_options.linear_solver_type because, depending on the
   // lack of a Schur structure, the preprocessor may change the linear
   // solver type.
-  if (IsSchurType(pp.linear_solver_options.type)) {
+  if (status && IsSchurType(pp.linear_solver_options.type)) {
     // TODO(sameeragarwal): We can likely eliminate the duplicate call
     // to DetectStructure here and inside the linear solver, by
     // calling this in the preprocessor.
@@ -580,7 +808,7 @@
   }
 
   const double postprocessor_start_time = WallTimeInSeconds();
-  problem_impl = problem->impl_.get();
+  problem_impl = problem->mutable_impl();
   program = problem_impl->mutable_program();
   // On exit, ensure that the parameter blocks again point at the user
   // provided values and the parameter blocks are numbered according
@@ -608,7 +836,7 @@
   solver.Solve(options, problem, summary);
 }
 
-string Solver::Summary::BriefReport() const {
+std::string Solver::Summary::BriefReport() const {
   return StringPrintf(
       "Ceres Solver Report: "
       "Iterations: %d, "
@@ -621,10 +849,12 @@
       TerminationTypeToString(termination_type));
 }
 
-string Solver::Summary::FullReport() const {
+std::string Solver::Summary::FullReport() const {
   using internal::VersionString;
 
-  string report = string("\nSolver Summary (v " + VersionString() + ")\n\n");
+  // NOTE operator+ is not usable for concatenating a string and a string_view.
+  std::string report =
+      std::string{"\nSolver Summary (v "}.append(VersionString()) + ")\n\n";
 
   StringAppendF(&report, "%45s    %21s\n", "Original", "Reduced");
   StringAppendF(&report,
@@ -658,21 +888,13 @@
     if (linear_solver_type_used == DENSE_NORMAL_CHOLESKY ||
         linear_solver_type_used == DENSE_SCHUR ||
         linear_solver_type_used == DENSE_QR) {
+      const char* mixed_precision_suffix =
+          (mixed_precision_solves_used ? "(Mixed Precision)" : "");
       StringAppendF(&report,
-                    "\nDense linear algebra library  %15s\n",
+                    "\nDense linear algebra library  %15s %s\n",
                     DenseLinearAlgebraLibraryTypeToString(
-                        dense_linear_algebra_library_type));
-    }
-
-    if (linear_solver_type_used == SPARSE_NORMAL_CHOLESKY ||
-        linear_solver_type_used == SPARSE_SCHUR ||
-        (linear_solver_type_used == ITERATIVE_SCHUR &&
-         (preconditioner_type_used == CLUSTER_JACOBI ||
-          preconditioner_type_used == CLUSTER_TRIDIAGONAL))) {
-      StringAppendF(&report,
-                    "\nSparse linear algebra library %15s\n",
-                    SparseLinearAlgebraLibraryTypeToString(
-                        sparse_linear_algebra_library_type));
+                        dense_linear_algebra_library_type),
+                    mixed_precision_suffix);
     }
 
     StringAppendF(&report,
@@ -685,17 +907,50 @@
         StringAppendF(&report, " (SUBSPACE)");
       }
     }
-    StringAppendF(&report, "\n");
-    StringAppendF(&report, "\n");
 
+    const bool used_sparse_linear_algebra_library =
+        linear_solver_type_used == SPARSE_NORMAL_CHOLESKY ||
+        linear_solver_type_used == SPARSE_SCHUR ||
+        linear_solver_type_used == CGNR ||
+        (linear_solver_type_used == ITERATIVE_SCHUR &&
+         (preconditioner_type_used == CLUSTER_JACOBI ||
+          preconditioner_type_used == CLUSTER_TRIDIAGONAL));
+
+    const bool linear_solver_ordering_required =
+        linear_solver_type_used == SPARSE_SCHUR ||
+        (linear_solver_type_used == ITERATIVE_SCHUR &&
+         (preconditioner_type_used == CLUSTER_JACOBI ||
+          preconditioner_type_used == CLUSTER_TRIDIAGONAL)) ||
+        (linear_solver_type_used == CGNR && preconditioner_type_used == SUBSET);
+
+    if (used_sparse_linear_algebra_library) {
+      const char* mixed_precision_suffix =
+          (mixed_precision_solves_used ? "(Mixed Precision)" : "");
+      if (linear_solver_ordering_required) {
+        StringAppendF(
+            &report,
+            "\nSparse linear algebra library %15s + %s %s\n",
+            SparseLinearAlgebraLibraryTypeToString(
+                sparse_linear_algebra_library_type),
+            LinearSolverOrderingTypeToString(linear_solver_ordering_type),
+            mixed_precision_suffix);
+      } else {
+        StringAppendF(&report,
+                      "\nSparse linear algebra library %15s %s\n",
+                      SparseLinearAlgebraLibraryTypeToString(
+                          sparse_linear_algebra_library_type),
+                      mixed_precision_suffix);
+      }
+    }
+
+    StringAppendF(&report, "\n");
     StringAppendF(&report, "%45s    %21s\n", "Given", "Used");
     StringAppendF(&report,
                   "Linear solver       %25s%25s\n",
                   LinearSolverTypeToString(linear_solver_type_given),
                   LinearSolverTypeToString(linear_solver_type_used));
 
-    if (linear_solver_type_given == CGNR ||
-        linear_solver_type_given == ITERATIVE_SCHUR) {
+    if (IsIterativeSolver(linear_solver_type_given)) {
       StringAppendF(&report,
                     "Preconditioner      %25s%25s\n",
                     PreconditionerTypeToString(preconditioner_type_given),
@@ -715,9 +970,9 @@
                   num_threads_given,
                   num_threads_used);
 
-    string given;
+    std::string given;
     StringifyOrdering(linear_solver_ordering_given, &given);
-    string used;
+    std::string used;
     StringifyOrdering(linear_solver_ordering_used, &used);
     StringAppendF(&report,
                   "Linear solver ordering %22s %24s\n",
@@ -738,9 +993,9 @@
     }
 
     if (inner_iterations_used) {
-      string given;
+      std::string given;
       StringifyOrdering(inner_iteration_ordering_given, &given);
-      string used;
+      std::string used;
       StringifyOrdering(inner_iteration_ordering_used, &used);
       StringAppendF(&report,
                     "Inner iteration ordering %20s %24s\n",
@@ -751,7 +1006,7 @@
     // LINE_SEARCH HEADER
     StringAppendF(&report, "\nMinimizer                 %19s\n", "LINE_SEARCH");
 
-    string line_search_direction_string;
+    std::string line_search_direction_string;
     if (line_search_direction_type == LBFGS) {
       line_search_direction_string = StringPrintf("LBFGS (%d)", max_lbfgs_rank);
     } else if (line_search_direction_type == NONLINEAR_CONJUGATE_GRADIENT) {
@@ -766,7 +1021,7 @@
                   "Line search direction     %19s\n",
                   line_search_direction_string.c_str());
 
-    const string line_search_type_string = StringPrintf(
+    const std::string line_search_type_string = StringPrintf(
         "%s %s",
         LineSearchInterpolationTypeToString(line_search_interpolation_type),
         LineSearchTypeToString(line_search_type));
diff --git a/third_party/ceres/internal/ceres/solver_test.cc b/third_party/ceres/internal/ceres/solver_test.cc
index c4823be..52bd594 100644
--- a/third_party/ceres/internal/ceres/solver_test.cc
+++ b/third_party/ceres/internal/ceres/solver_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2019 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -33,32 +33,30 @@
 #include <cmath>
 #include <limits>
 #include <memory>
+#include <string>
 #include <vector>
 
 #include "ceres/autodiff_cost_function.h"
 #include "ceres/evaluation_callback.h"
-#include "ceres/local_parameterization.h"
+#include "ceres/manifold.h"
 #include "ceres/problem.h"
 #include "ceres/problem_impl.h"
 #include "ceres/sized_cost_function.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
-
-using std::string;
+namespace ceres::internal {
 
 TEST(SolverOptions, DefaultTrustRegionOptionsAreValid) {
   Solver::Options options;
   options.minimizer_type = TRUST_REGION;
-  string error;
+  std::string error;
   EXPECT_TRUE(options.IsValid(&error)) << error;
 }
 
 TEST(SolverOptions, DefaultLineSearchOptionsAreValid) {
   Solver::Options options;
   options.minimizer_type = LINE_SEARCH;
-  string error;
+  std::string error;
   EXPECT_TRUE(options.IsValid(&error)) << error;
 }
 
@@ -77,7 +75,6 @@
 
 struct RememberingCallback : public IterationCallback {
   explicit RememberingCallback(double* x) : calls(0), x(x) {}
-  virtual ~RememberingCallback() {}
   CallbackReturnType operator()(const IterationSummary& summary) final {
     x_values.push_back(*x);
     return SOLVER_CONTINUE;
@@ -88,7 +85,6 @@
 };
 
 struct NoOpEvaluationCallback : EvaluationCallback {
-  virtual ~NoOpEvaluationCallback() {}
   void PrepareForEvaluation(bool evaluate_jacobians,
                             bool new_evaluation_point) final {
     (void)evaluate_jacobians;
@@ -119,8 +115,8 @@
   num_iterations =
       summary.num_successful_steps + summary.num_unsuccessful_steps;
   EXPECT_GT(num_iterations, 1);
-  for (int i = 0; i < callback.x_values.size(); ++i) {
-    EXPECT_EQ(50.0, callback.x_values[i]);
+  for (double value : callback.x_values) {
+    EXPECT_EQ(50.0, value);
   }
 
   // Second: update_state_every_iteration=true, evaluation_callback=nullptr.
@@ -315,166 +311,12 @@
   EXPECT_EQ(summary.final_cost, 1.0 / 2.0);
 }
 
-#if defined(CERES_NO_SUITESPARSE)
-TEST(Solver, SparseNormalCholeskyNoSuiteSparse) {
-  Solver::Options options;
-  options.sparse_linear_algebra_library_type = SUITE_SPARSE;
-  options.linear_solver_type = SPARSE_NORMAL_CHOLESKY;
-  string message;
-  EXPECT_FALSE(options.IsValid(&message));
-}
-
-TEST(Solver, SparseSchurNoSuiteSparse) {
-  Solver::Options options;
-  options.sparse_linear_algebra_library_type = SUITE_SPARSE;
-  options.linear_solver_type = SPARSE_SCHUR;
-  string message;
-  EXPECT_FALSE(options.IsValid(&message));
-}
-#endif
-
-#if defined(CERES_NO_CXSPARSE)
-TEST(Solver, SparseNormalCholeskyNoCXSparse) {
-  Solver::Options options;
-  options.sparse_linear_algebra_library_type = CX_SPARSE;
-  options.linear_solver_type = SPARSE_NORMAL_CHOLESKY;
-  string message;
-  EXPECT_FALSE(options.IsValid(&message));
-}
-
-TEST(Solver, SparseSchurNoCXSparse) {
-  Solver::Options options;
-  options.sparse_linear_algebra_library_type = CX_SPARSE;
-  options.linear_solver_type = SPARSE_SCHUR;
-  string message;
-  EXPECT_FALSE(options.IsValid(&message));
-}
-#endif
-
-#if defined(CERES_NO_ACCELERATE_SPARSE)
-TEST(Solver, SparseNormalCholeskyNoAccelerateSparse) {
-  Solver::Options options;
-  options.sparse_linear_algebra_library_type = ACCELERATE_SPARSE;
-  options.linear_solver_type = SPARSE_NORMAL_CHOLESKY;
-  string message;
-  EXPECT_FALSE(options.IsValid(&message));
-}
-
-TEST(Solver, SparseSchurNoAccelerateSparse) {
-  Solver::Options options;
-  options.sparse_linear_algebra_library_type = ACCELERATE_SPARSE;
-  options.linear_solver_type = SPARSE_SCHUR;
-  string message;
-  EXPECT_FALSE(options.IsValid(&message));
-}
-#else
-TEST(Solver, DynamicSparseNormalCholeskyUnsupportedWithAccelerateSparse) {
-  Solver::Options options;
-  options.sparse_linear_algebra_library_type = ACCELERATE_SPARSE;
-  options.linear_solver_type = SPARSE_NORMAL_CHOLESKY;
-  options.dynamic_sparsity = true;
-  string message;
-  EXPECT_FALSE(options.IsValid(&message));
-}
-#endif
-
-#if !defined(CERES_USE_EIGEN_SPARSE)
-TEST(Solver, SparseNormalCholeskyNoEigenSparse) {
-  Solver::Options options;
-  options.sparse_linear_algebra_library_type = EIGEN_SPARSE;
-  options.linear_solver_type = SPARSE_NORMAL_CHOLESKY;
-  string message;
-  EXPECT_FALSE(options.IsValid(&message));
-}
-
-TEST(Solver, SparseSchurNoEigenSparse) {
-  Solver::Options options;
-  options.sparse_linear_algebra_library_type = EIGEN_SPARSE;
-  options.linear_solver_type = SPARSE_SCHUR;
-  string message;
-  EXPECT_FALSE(options.IsValid(&message));
-}
-#endif
-
-TEST(Solver, SparseNormalCholeskyNoSparseLibrary) {
-  Solver::Options options;
-  options.sparse_linear_algebra_library_type = NO_SPARSE;
-  options.linear_solver_type = SPARSE_NORMAL_CHOLESKY;
-  string message;
-  EXPECT_FALSE(options.IsValid(&message));
-}
-
-TEST(Solver, SparseSchurNoSparseLibrary) {
-  Solver::Options options;
-  options.sparse_linear_algebra_library_type = NO_SPARSE;
-  options.linear_solver_type = SPARSE_SCHUR;
-  string message;
-  EXPECT_FALSE(options.IsValid(&message));
-}
-
-TEST(Solver, IterativeSchurWithClusterJacobiPerconditionerNoSparseLibrary) {
-  Solver::Options options;
-  options.sparse_linear_algebra_library_type = NO_SPARSE;
-  options.linear_solver_type = ITERATIVE_SCHUR;
-  // Requires SuiteSparse.
-  options.preconditioner_type = CLUSTER_JACOBI;
-  string message;
-  EXPECT_FALSE(options.IsValid(&message));
-}
-
-TEST(Solver,
-     IterativeSchurWithClusterTridiagonalPerconditionerNoSparseLibrary) {
-  Solver::Options options;
-  options.sparse_linear_algebra_library_type = NO_SPARSE;
-  options.linear_solver_type = ITERATIVE_SCHUR;
-  // Requires SuiteSparse.
-  options.preconditioner_type = CLUSTER_TRIDIAGONAL;
-  string message;
-  EXPECT_FALSE(options.IsValid(&message));
-}
-
-TEST(Solver, IterativeLinearSolverForDogleg) {
-  Solver::Options options;
-  options.trust_region_strategy_type = DOGLEG;
-  string message;
-  options.linear_solver_type = ITERATIVE_SCHUR;
-  EXPECT_FALSE(options.IsValid(&message));
-
-  options.linear_solver_type = CGNR;
-  EXPECT_FALSE(options.IsValid(&message));
-}
-
-TEST(Solver, LinearSolverTypeNormalOperation) {
-  Solver::Options options;
-  options.linear_solver_type = DENSE_QR;
-
-  string message;
-  EXPECT_TRUE(options.IsValid(&message));
-
-  options.linear_solver_type = DENSE_NORMAL_CHOLESKY;
-  EXPECT_TRUE(options.IsValid(&message));
-
-  options.linear_solver_type = DENSE_SCHUR;
-  EXPECT_TRUE(options.IsValid(&message));
-
-  options.linear_solver_type = SPARSE_SCHUR;
-#if defined(CERES_NO_SUITESPARSE) && defined(CERES_NO_CXSPARSE) && \
-    !defined(CERES_USE_EIGEN_SPARSE)
-  EXPECT_FALSE(options.IsValid(&message));
-#else
-  EXPECT_TRUE(options.IsValid(&message));
-#endif
-
-  options.linear_solver_type = ITERATIVE_SCHUR;
-  EXPECT_TRUE(options.IsValid(&message));
-}
-
 template <int kNumResiduals, int... Ns>
 class DummyCostFunction : public SizedCostFunction<kNumResiduals, Ns...> {
  public:
   bool Evaluate(double const* const* parameters,
                 double* residuals,
-                double** jacobians) const {
+                double** jacobians) const override {
     for (int i = 0; i < kNumResiduals; ++i) {
       residuals[i] = kNumResiduals * kNumResiduals + i;
     }
@@ -512,12 +354,12 @@
   }
 };
 
-TEST(Solver, ZeroSizedLocalParameterizationHoldsParameterBlockConstant) {
+TEST(Solver, ZeroSizedManifoldHoldsParameterBlockConstant) {
   double x = 0.0;
   double y = 1.0;
   Problem problem;
   problem.AddResidualBlock(LinearCostFunction::Create(), nullptr, &x, &y);
-  problem.SetParameterization(&y, new SubsetParameterization(1, {0}));
+  problem.SetManifold(&y, new SubsetManifold(1, {0}));
   EXPECT_TRUE(problem.IsParameterBlockConstant(&y));
 
   Solver::Options options;
@@ -532,5 +374,856 @@
   EXPECT_EQ(y, 1.0);
 }
 
-}  // namespace internal
-}  // namespace ceres
+TEST(Solver, DenseNormalCholeskyOptions) {
+  std::string message;
+  Solver::Options options;
+  options.linear_solver_type = DENSE_NORMAL_CHOLESKY;
+  EXPECT_TRUE(options.IsValid(&message));
+
+  options.dense_linear_algebra_library_type = EIGEN;
+  options.use_mixed_precision_solves = false;
+  EXPECT_TRUE(options.IsValid(&message));
+
+  options.use_mixed_precision_solves = true;
+  EXPECT_TRUE(options.IsValid(&message));
+
+  if (IsDenseLinearAlgebraLibraryTypeAvailable(LAPACK)) {
+    options.use_mixed_precision_solves = false;
+    options.dense_linear_algebra_library_type = LAPACK;
+
+    EXPECT_TRUE(options.IsValid(&message));
+    options.use_mixed_precision_solves = true;
+    EXPECT_TRUE(options.IsValid(&message));
+  } else {
+    options.use_mixed_precision_solves = false;
+    options.dense_linear_algebra_library_type = LAPACK;
+    EXPECT_FALSE(options.IsValid(&message));
+  }
+}
+
+TEST(Solver, DenseQrOptions) {
+  std::string message;
+  Solver::Options options;
+  options.linear_solver_type = DENSE_QR;
+
+  options.use_mixed_precision_solves = false;
+  options.dense_linear_algebra_library_type = EIGEN;
+  EXPECT_TRUE(options.IsValid(&message));
+
+  options.use_mixed_precision_solves = true;
+  EXPECT_FALSE(options.IsValid(&message));
+
+  if (IsDenseLinearAlgebraLibraryTypeAvailable(LAPACK)) {
+    options.use_mixed_precision_solves = false;
+    options.dense_linear_algebra_library_type = LAPACK;
+    EXPECT_TRUE(options.IsValid(&message));
+    options.use_mixed_precision_solves = true;
+    EXPECT_FALSE(options.IsValid(&message));
+  } else {
+    options.use_mixed_precision_solves = false;
+    options.dense_linear_algebra_library_type = LAPACK;
+    EXPECT_FALSE(options.IsValid(&message));
+  }
+}
+
+TEST(Solver, SparseNormalCholeskyOptionsNoSparse) {
+  std::string message;
+  Solver::Options options;
+  options.linear_solver_type = SPARSE_NORMAL_CHOLESKY;
+  options.sparse_linear_algebra_library_type = NO_SPARSE;
+  EXPECT_FALSE(options.IsValid(&message));
+}
+
+TEST(Solver, SparseNormalCholeskyOptionsEigenSparse) {
+  std::string message;
+  Solver::Options options;
+  options.linear_solver_type = SPARSE_NORMAL_CHOLESKY;
+  options.sparse_linear_algebra_library_type = EIGEN_SPARSE;
+  options.linear_solver_ordering_type = AMD;
+
+  options.use_mixed_precision_solves = false;
+  options.dynamic_sparsity = false;
+  if (IsSparseLinearAlgebraLibraryTypeAvailable(EIGEN_SPARSE)) {
+    EXPECT_TRUE(options.IsValid(&message));
+  } else {
+    EXPECT_FALSE(options.IsValid(&message));
+  }
+
+  if (IsSparseLinearAlgebraLibraryTypeAvailable(EIGEN_SPARSE)) {
+    options.use_mixed_precision_solves = true;
+    options.dynamic_sparsity = false;
+    EXPECT_TRUE(options.IsValid(&message));
+
+    options.use_mixed_precision_solves = false;
+    options.dynamic_sparsity = true;
+    EXPECT_TRUE(options.IsValid(&message));
+
+    options.use_mixed_precision_solves = true;
+    options.dynamic_sparsity = true;
+    EXPECT_TRUE(options.IsValid(&message));
+  }
+
+#ifndef CERES_NO_EIGEN_METIS
+  options.linear_solver_ordering_type = NESDIS;
+  if (IsSparseLinearAlgebraLibraryTypeAvailable(EIGEN_SPARSE)) {
+    options.use_mixed_precision_solves = false;
+    options.dynamic_sparsity = false;
+    EXPECT_TRUE(options.IsValid(&message));
+
+    options.use_mixed_precision_solves = true;
+    options.dynamic_sparsity = false;
+    EXPECT_TRUE(options.IsValid(&message));
+
+    options.use_mixed_precision_solves = false;
+    options.dynamic_sparsity = true;
+    EXPECT_TRUE(options.IsValid(&message));
+
+    options.use_mixed_precision_solves = true;
+    options.dynamic_sparsity = true;
+    EXPECT_TRUE(options.IsValid(&message));
+  }
+#else
+  options.linear_solver_ordering_type = NESDIS;
+  options.use_mixed_precision_solves = false;
+  options.dynamic_sparsity = false;
+  EXPECT_FALSE(options.IsValid(&message));
+#endif
+}
+
+TEST(Solver, SparseNormalCholeskyOptionsSuiteSparse) {
+  std::string message;
+  Solver::Options options;
+  options.linear_solver_type = SPARSE_NORMAL_CHOLESKY;
+  options.sparse_linear_algebra_library_type = SUITE_SPARSE;
+  options.linear_solver_ordering_type = AMD;
+
+  options.use_mixed_precision_solves = false;
+  options.dynamic_sparsity = false;
+  if (IsSparseLinearAlgebraLibraryTypeAvailable(
+          options.sparse_linear_algebra_library_type)) {
+    EXPECT_TRUE(options.IsValid(&message));
+  } else {
+    EXPECT_FALSE(options.IsValid(&message));
+  }
+
+  if (IsSparseLinearAlgebraLibraryTypeAvailable(
+          options.sparse_linear_algebra_library_type)) {
+    options.use_mixed_precision_solves = true;
+    options.dynamic_sparsity = false;
+    EXPECT_FALSE(options.IsValid(&message));
+
+    options.use_mixed_precision_solves = false;
+    options.dynamic_sparsity = true;
+    EXPECT_TRUE(options.IsValid(&message));
+
+    options.use_mixed_precision_solves = true;
+    options.dynamic_sparsity = true;
+    EXPECT_FALSE(options.IsValid(&message));
+  }
+
+#ifndef CERES_NO_CHOLMOD_PARTITION
+  options.linear_solver_ordering_type = NESDIS;
+  if (IsSparseLinearAlgebraLibraryTypeAvailable(
+          options.sparse_linear_algebra_library_type)) {
+    options.use_mixed_precision_solves = false;
+    options.dynamic_sparsity = false;
+    EXPECT_TRUE(options.IsValid(&message));
+
+    options.use_mixed_precision_solves = true;
+    options.dynamic_sparsity = false;
+    EXPECT_FALSE(options.IsValid(&message));
+
+    options.use_mixed_precision_solves = false;
+    options.dynamic_sparsity = true;
+    EXPECT_TRUE(options.IsValid(&message));
+
+    options.use_mixed_precision_solves = true;
+    options.dynamic_sparsity = true;
+    EXPECT_FALSE(options.IsValid(&message));
+  }
+#else
+  options.linear_solver_ordering_type = NESDIS;
+  options.use_mixed_precision_solves = false;
+  options.dynamic_sparsity = false;
+  EXPECT_FALSE(options.IsValid(&message));
+#endif
+}
+
+TEST(Solver, SparseNormalCholeskyOptionsAccelerateSparse) {
+  std::string message;
+  Solver::Options options;
+  options.linear_solver_type = SPARSE_NORMAL_CHOLESKY;
+  options.sparse_linear_algebra_library_type = ACCELERATE_SPARSE;
+  options.linear_solver_ordering_type = AMD;
+
+  options.use_mixed_precision_solves = false;
+  options.dynamic_sparsity = false;
+  if (IsSparseLinearAlgebraLibraryTypeAvailable(
+          options.sparse_linear_algebra_library_type)) {
+    EXPECT_TRUE(options.IsValid(&message));
+  } else {
+    EXPECT_FALSE(options.IsValid(&message));
+  }
+
+  if (IsSparseLinearAlgebraLibraryTypeAvailable(
+          options.sparse_linear_algebra_library_type)) {
+    options.use_mixed_precision_solves = true;
+    options.dynamic_sparsity = false;
+    EXPECT_TRUE(options.IsValid(&message));
+
+    options.use_mixed_precision_solves = false;
+    options.dynamic_sparsity = true;
+    EXPECT_FALSE(options.IsValid(&message));
+
+    options.use_mixed_precision_solves = true;
+    options.dynamic_sparsity = true;
+    EXPECT_FALSE(options.IsValid(&message));
+  }
+
+  options.linear_solver_ordering_type = NESDIS;
+  if (IsSparseLinearAlgebraLibraryTypeAvailable(
+          options.sparse_linear_algebra_library_type)) {
+    options.use_mixed_precision_solves = false;
+    options.dynamic_sparsity = false;
+    EXPECT_TRUE(options.IsValid(&message));
+
+    options.use_mixed_precision_solves = true;
+    options.dynamic_sparsity = false;
+    EXPECT_TRUE(options.IsValid(&message));
+
+    options.use_mixed_precision_solves = false;
+    options.dynamic_sparsity = true;
+    EXPECT_FALSE(options.IsValid(&message));
+
+    options.use_mixed_precision_solves = true;
+    options.dynamic_sparsity = true;
+    EXPECT_FALSE(options.IsValid(&message));
+  }
+}
+
+TEST(Solver, DenseSchurOptions) {
+  std::string message;
+  Solver::Options options;
+  options.linear_solver_type = DENSE_SCHUR;
+  options.dense_linear_algebra_library_type = EIGEN;
+
+  options.use_mixed_precision_solves = false;
+  options.dynamic_sparsity = false;
+  EXPECT_TRUE(options.IsValid(&message));
+
+  options.use_mixed_precision_solves = true;
+  options.dynamic_sparsity = false;
+  EXPECT_TRUE(options.IsValid(&message));
+
+  options.use_mixed_precision_solves = true;
+  options.dynamic_sparsity = true;
+  EXPECT_FALSE(options.IsValid(&message));
+
+  options.use_mixed_precision_solves = false;
+  options.dynamic_sparsity = true;
+  EXPECT_FALSE(options.IsValid(&message));
+
+  options.dense_linear_algebra_library_type = LAPACK;
+  if (IsDenseLinearAlgebraLibraryTypeAvailable(
+          options.dense_linear_algebra_library_type)) {
+    options.use_mixed_precision_solves = false;
+    options.dynamic_sparsity = false;
+    EXPECT_TRUE(options.IsValid(&message));
+
+    options.use_mixed_precision_solves = true;
+    options.dynamic_sparsity = false;
+    EXPECT_TRUE(options.IsValid(&message));
+
+    options.use_mixed_precision_solves = true;
+    options.dynamic_sparsity = true;
+    EXPECT_FALSE(options.IsValid(&message));
+
+    options.use_mixed_precision_solves = false;
+    options.dynamic_sparsity = true;
+    EXPECT_FALSE(options.IsValid(&message));
+  }
+}
+
+TEST(Solver, SparseSchurOptionsNoSparse) {
+  std::string message;
+  Solver::Options options;
+  options.linear_solver_type = SPARSE_SCHUR;
+  options.sparse_linear_algebra_library_type = NO_SPARSE;
+  EXPECT_FALSE(options.IsValid(&message));
+}
+
+TEST(Solver, SparseSchurOptionsEigenSparse) {
+  std::string message;
+  Solver::Options options;
+  options.linear_solver_type = SPARSE_SCHUR;
+  options.sparse_linear_algebra_library_type = EIGEN_SPARSE;
+  options.linear_solver_ordering_type = AMD;
+
+  options.use_mixed_precision_solves = false;
+  options.dynamic_sparsity = false;
+  if (IsSparseLinearAlgebraLibraryTypeAvailable(EIGEN_SPARSE)) {
+    EXPECT_TRUE(options.IsValid(&message));
+  } else {
+    EXPECT_FALSE(options.IsValid(&message));
+  }
+
+  if (IsSparseLinearAlgebraLibraryTypeAvailable(EIGEN_SPARSE)) {
+    options.use_mixed_precision_solves = true;
+    options.dynamic_sparsity = false;
+    EXPECT_TRUE(options.IsValid(&message));
+
+    options.use_mixed_precision_solves = false;
+    options.dynamic_sparsity = true;
+    EXPECT_FALSE(options.IsValid(&message));
+
+    options.use_mixed_precision_solves = true;
+    options.dynamic_sparsity = true;
+    EXPECT_FALSE(options.IsValid(&message));
+  }
+
+#ifndef CERES_NO_EIGEN_METIS
+  options.linear_solver_ordering_type = NESDIS;
+  if (IsSparseLinearAlgebraLibraryTypeAvailable(EIGEN_SPARSE)) {
+    options.use_mixed_precision_solves = false;
+    options.dynamic_sparsity = false;
+    EXPECT_TRUE(options.IsValid(&message));
+
+    options.use_mixed_precision_solves = true;
+    options.dynamic_sparsity = false;
+    EXPECT_TRUE(options.IsValid(&message));
+
+    options.use_mixed_precision_solves = false;
+    options.dynamic_sparsity = true;
+    EXPECT_FALSE(options.IsValid(&message));
+
+    options.use_mixed_precision_solves = true;
+    options.dynamic_sparsity = true;
+    EXPECT_FALSE(options.IsValid(&message));
+  }
+#else
+  options.linear_solver_ordering_type = NESDIS;
+  options.use_mixed_precision_solves = false;
+  options.dynamic_sparsity = false;
+  EXPECT_FALSE(options.IsValid(&message));
+#endif
+}
+
+TEST(Solver, SparseSchurOptionsSuiteSparse) {
+  std::string message;
+  Solver::Options options;
+  options.linear_solver_type = SPARSE_SCHUR;
+  options.sparse_linear_algebra_library_type = SUITE_SPARSE;
+  options.linear_solver_ordering_type = AMD;
+
+  options.use_mixed_precision_solves = false;
+  options.dynamic_sparsity = false;
+  if (IsSparseLinearAlgebraLibraryTypeAvailable(
+          options.sparse_linear_algebra_library_type)) {
+    EXPECT_TRUE(options.IsValid(&message));
+  } else {
+    EXPECT_FALSE(options.IsValid(&message));
+  }
+
+  if (IsSparseLinearAlgebraLibraryTypeAvailable(
+          options.sparse_linear_algebra_library_type)) {
+    options.use_mixed_precision_solves = true;
+    options.dynamic_sparsity = false;
+    EXPECT_FALSE(options.IsValid(&message));
+
+    options.use_mixed_precision_solves = false;
+    options.dynamic_sparsity = true;
+    EXPECT_FALSE(options.IsValid(&message));
+
+    options.use_mixed_precision_solves = true;
+    options.dynamic_sparsity = true;
+    EXPECT_FALSE(options.IsValid(&message));
+  }
+
+#ifndef CERES_NO_CHOLMOD_PARTITION
+  options.linear_solver_ordering_type = NESDIS;
+  if (IsSparseLinearAlgebraLibraryTypeAvailable(
+          options.sparse_linear_algebra_library_type)) {
+    options.use_mixed_precision_solves = false;
+    options.dynamic_sparsity = false;
+    EXPECT_TRUE(options.IsValid(&message));
+
+    options.use_mixed_precision_solves = true;
+    options.dynamic_sparsity = false;
+    EXPECT_FALSE(options.IsValid(&message));
+
+    options.use_mixed_precision_solves = false;
+    options.dynamic_sparsity = true;
+    EXPECT_FALSE(options.IsValid(&message));
+
+    options.use_mixed_precision_solves = true;
+    options.dynamic_sparsity = true;
+    EXPECT_FALSE(options.IsValid(&message));
+  }
+#else
+  options.linear_solver_ordering_type = NESDIS;
+  options.use_mixed_precision_solves = false;
+  options.dynamic_sparsity = false;
+  EXPECT_FALSE(options.IsValid(&message));
+#endif
+}
+
+TEST(Solver, SparseSchurOptionsAccelerateSparse) {
+  std::string message;
+  Solver::Options options;
+  options.linear_solver_type = SPARSE_SCHUR;
+  options.sparse_linear_algebra_library_type = ACCELERATE_SPARSE;
+  options.linear_solver_ordering_type = AMD;
+
+  options.use_mixed_precision_solves = false;
+  options.dynamic_sparsity = false;
+  if (IsSparseLinearAlgebraLibraryTypeAvailable(
+          options.sparse_linear_algebra_library_type)) {
+    EXPECT_TRUE(options.IsValid(&message));
+  } else {
+    EXPECT_FALSE(options.IsValid(&message));
+  }
+
+  if (IsSparseLinearAlgebraLibraryTypeAvailable(
+          options.sparse_linear_algebra_library_type)) {
+    options.use_mixed_precision_solves = true;
+    options.dynamic_sparsity = false;
+    EXPECT_TRUE(options.IsValid(&message));
+
+    options.use_mixed_precision_solves = false;
+    options.dynamic_sparsity = true;
+    EXPECT_FALSE(options.IsValid(&message));
+
+    options.use_mixed_precision_solves = true;
+    options.dynamic_sparsity = true;
+    EXPECT_FALSE(options.IsValid(&message));
+  }
+
+  options.linear_solver_ordering_type = NESDIS;
+  if (IsSparseLinearAlgebraLibraryTypeAvailable(
+          options.sparse_linear_algebra_library_type)) {
+    options.use_mixed_precision_solves = false;
+    options.dynamic_sparsity = false;
+    EXPECT_TRUE(options.IsValid(&message));
+
+    options.use_mixed_precision_solves = true;
+    options.dynamic_sparsity = false;
+    EXPECT_TRUE(options.IsValid(&message));
+
+    options.use_mixed_precision_solves = false;
+    options.dynamic_sparsity = true;
+    EXPECT_FALSE(options.IsValid(&message));
+
+    options.use_mixed_precision_solves = true;
+    options.dynamic_sparsity = true;
+    EXPECT_FALSE(options.IsValid(&message));
+  }
+}
+
+TEST(Solver, CgnrOptionsIdentityPreconditioner) {
+  std::string message;
+  Solver::Options options;
+  options.linear_solver_type = CGNR;
+  options.preconditioner_type = IDENTITY;
+  options.sparse_linear_algebra_library_type = NO_SPARSE;
+
+  options.dynamic_sparsity = false;
+  options.use_mixed_precision_solves = false;
+  EXPECT_TRUE(options.IsValid(&message));
+
+  options.dynamic_sparsity = true;
+  options.use_mixed_precision_solves = false;
+  EXPECT_FALSE(options.IsValid(&message));
+
+  options.dynamic_sparsity = false;
+  options.use_mixed_precision_solves = true;
+  EXPECT_FALSE(options.IsValid(&message));
+
+  options.sparse_linear_algebra_library_type = EIGEN_SPARSE;
+  options.dynamic_sparsity = false;
+  options.use_mixed_precision_solves = false;
+  EXPECT_TRUE(options.IsValid(&message));
+
+  options.dynamic_sparsity = true;
+  options.use_mixed_precision_solves = false;
+  EXPECT_FALSE(options.IsValid(&message));
+
+  options.dynamic_sparsity = false;
+  options.use_mixed_precision_solves = true;
+  EXPECT_FALSE(options.IsValid(&message));
+
+  options.sparse_linear_algebra_library_type = SUITE_SPARSE;
+  options.dynamic_sparsity = false;
+  options.use_mixed_precision_solves = false;
+  EXPECT_TRUE(options.IsValid(&message));
+
+  options.dynamic_sparsity = true;
+  options.use_mixed_precision_solves = false;
+  EXPECT_FALSE(options.IsValid(&message));
+
+  options.dynamic_sparsity = false;
+  options.use_mixed_precision_solves = true;
+  EXPECT_FALSE(options.IsValid(&message));
+
+  options.sparse_linear_algebra_library_type = ACCELERATE_SPARSE;
+  options.dynamic_sparsity = false;
+  options.use_mixed_precision_solves = false;
+  EXPECT_TRUE(options.IsValid(&message));
+
+  options.dynamic_sparsity = true;
+  options.use_mixed_precision_solves = false;
+  EXPECT_FALSE(options.IsValid(&message));
+
+  options.dynamic_sparsity = false;
+  options.use_mixed_precision_solves = true;
+  EXPECT_FALSE(options.IsValid(&message));
+
+  options.sparse_linear_algebra_library_type = CUDA_SPARSE;
+  options.dynamic_sparsity = false;
+  options.use_mixed_precision_solves = false;
+  EXPECT_EQ(options.IsValid(&message),
+            IsSparseLinearAlgebraLibraryTypeAvailable(CUDA_SPARSE));
+
+  options.dynamic_sparsity = true;
+  options.use_mixed_precision_solves = false;
+  EXPECT_FALSE(options.IsValid(&message));
+
+  options.dynamic_sparsity = false;
+  options.use_mixed_precision_solves = true;
+  EXPECT_FALSE(options.IsValid(&message));
+}
+
+TEST(Solver, CgnrOptionsJacobiPreconditioner) {
+  std::string message;
+  Solver::Options options;
+  options.linear_solver_type = CGNR;
+  options.preconditioner_type = JACOBI;
+  options.sparse_linear_algebra_library_type = NO_SPARSE;
+
+  options.dynamic_sparsity = false;
+  options.use_mixed_precision_solves = false;
+  EXPECT_TRUE(options.IsValid(&message));
+
+  options.dynamic_sparsity = true;
+  options.use_mixed_precision_solves = false;
+  EXPECT_FALSE(options.IsValid(&message));
+
+  options.dynamic_sparsity = false;
+  options.use_mixed_precision_solves = true;
+  EXPECT_FALSE(options.IsValid(&message));
+
+  options.sparse_linear_algebra_library_type = EIGEN_SPARSE;
+
+  options.dynamic_sparsity = false;
+  options.use_mixed_precision_solves = false;
+  EXPECT_TRUE(options.IsValid(&message));
+
+  options.dynamic_sparsity = true;
+  options.use_mixed_precision_solves = false;
+  EXPECT_FALSE(options.IsValid(&message));
+
+  options.dynamic_sparsity = false;
+  options.use_mixed_precision_solves = true;
+  EXPECT_FALSE(options.IsValid(&message));
+
+  options.sparse_linear_algebra_library_type = SUITE_SPARSE;
+
+  options.dynamic_sparsity = false;
+  options.use_mixed_precision_solves = false;
+  EXPECT_TRUE(options.IsValid(&message));
+
+  options.dynamic_sparsity = true;
+  options.use_mixed_precision_solves = false;
+  EXPECT_FALSE(options.IsValid(&message));
+
+  options.dynamic_sparsity = false;
+  options.use_mixed_precision_solves = true;
+  EXPECT_FALSE(options.IsValid(&message));
+
+  options.sparse_linear_algebra_library_type = ACCELERATE_SPARSE;
+
+  options.dynamic_sparsity = false;
+  options.use_mixed_precision_solves = false;
+  EXPECT_TRUE(options.IsValid(&message));
+
+  options.dynamic_sparsity = true;
+  options.use_mixed_precision_solves = false;
+  EXPECT_FALSE(options.IsValid(&message));
+
+  options.dynamic_sparsity = false;
+  options.use_mixed_precision_solves = true;
+  EXPECT_FALSE(options.IsValid(&message));
+
+  options.sparse_linear_algebra_library_type = CUDA_SPARSE;
+
+  options.dynamic_sparsity = false;
+  options.use_mixed_precision_solves = false;
+  EXPECT_EQ(options.IsValid(&message),
+            IsSparseLinearAlgebraLibraryTypeAvailable(CUDA_SPARSE));
+
+  options.dynamic_sparsity = true;
+  options.use_mixed_precision_solves = false;
+  EXPECT_FALSE(options.IsValid(&message));
+
+  options.dynamic_sparsity = false;
+  options.use_mixed_precision_solves = true;
+  EXPECT_FALSE(options.IsValid(&message));
+}
+
+TEST(Solver, CgnrOptionsSubsetPreconditioner) {
+  std::string message;
+  Solver::Options options;
+  options.linear_solver_type = CGNR;
+  options.preconditioner_type = SUBSET;
+
+  options.sparse_linear_algebra_library_type = NO_SPARSE;
+  EXPECT_FALSE(options.IsValid(&message));
+  options.residual_blocks_for_subset_preconditioner.insert(nullptr);
+  EXPECT_FALSE(options.IsValid(&message));
+
+  options.dynamic_sparsity = false;
+  options.use_mixed_precision_solves = false;
+  EXPECT_FALSE(options.IsValid(&message));
+
+  options.dynamic_sparsity = true;
+  options.use_mixed_precision_solves = false;
+  EXPECT_FALSE(options.IsValid(&message));
+
+  options.dynamic_sparsity = false;
+  options.use_mixed_precision_solves = true;
+  EXPECT_FALSE(options.IsValid(&message));
+
+  options.sparse_linear_algebra_library_type = EIGEN_SPARSE;
+  if (IsSparseLinearAlgebraLibraryTypeAvailable(
+          options.sparse_linear_algebra_library_type)) {
+    options.dynamic_sparsity = false;
+    options.use_mixed_precision_solves = false;
+    EXPECT_TRUE(options.IsValid(&message));
+
+    options.dynamic_sparsity = true;
+    options.use_mixed_precision_solves = false;
+    EXPECT_FALSE(options.IsValid(&message));
+
+    options.dynamic_sparsity = false;
+    options.use_mixed_precision_solves = true;
+    EXPECT_FALSE(options.IsValid(&message));
+  }
+
+  options.sparse_linear_algebra_library_type = SUITE_SPARSE;
+  if (IsSparseLinearAlgebraLibraryTypeAvailable(
+          options.sparse_linear_algebra_library_type)) {
+    options.dynamic_sparsity = false;
+    options.use_mixed_precision_solves = false;
+    EXPECT_TRUE(options.IsValid(&message));
+
+    options.dynamic_sparsity = true;
+    options.use_mixed_precision_solves = false;
+    EXPECT_FALSE(options.IsValid(&message));
+
+    options.dynamic_sparsity = false;
+    options.use_mixed_precision_solves = true;
+    EXPECT_FALSE(options.IsValid(&message));
+  }
+
+  options.sparse_linear_algebra_library_type = ACCELERATE_SPARSE;
+  if (IsSparseLinearAlgebraLibraryTypeAvailable(
+          options.sparse_linear_algebra_library_type)) {
+    options.dynamic_sparsity = false;
+    options.use_mixed_precision_solves = false;
+    EXPECT_TRUE(options.IsValid(&message));
+
+    options.dynamic_sparsity = true;
+    options.use_mixed_precision_solves = false;
+    EXPECT_FALSE(options.IsValid(&message));
+
+    options.dynamic_sparsity = false;
+    options.use_mixed_precision_solves = true;
+    EXPECT_FALSE(options.IsValid(&message));
+  }
+
+  options.sparse_linear_algebra_library_type = CUDA_SPARSE;
+  options.dynamic_sparsity = false;
+  options.use_mixed_precision_solves = false;
+  EXPECT_FALSE(options.IsValid(&message));
+
+  options.dynamic_sparsity = true;
+  options.use_mixed_precision_solves = false;
+  EXPECT_FALSE(options.IsValid(&message));
+
+  options.dynamic_sparsity = false;
+  options.use_mixed_precision_solves = true;
+  EXPECT_FALSE(options.IsValid(&message));
+}
+
+TEST(Solver, CgnrOptionsSchurPreconditioners) {
+  std::string message;
+  Solver::Options options;
+  options.linear_solver_type = CGNR;
+  options.preconditioner_type = SCHUR_JACOBI;
+  EXPECT_FALSE(options.IsValid(&message));
+  options.preconditioner_type = CLUSTER_JACOBI;
+  EXPECT_FALSE(options.IsValid(&message));
+  options.preconditioner_type = CLUSTER_TRIDIAGONAL;
+  EXPECT_FALSE(options.IsValid(&message));
+}
+
+TEST(Solver, IterativeSchurOptionsNoSparse) {
+  std::string message;
+  Solver::Options options;
+  options.linear_solver_type = ITERATIVE_SCHUR;
+  options.sparse_linear_algebra_library_type = NO_SPARSE;
+  options.preconditioner_type = IDENTITY;
+  EXPECT_TRUE(options.IsValid(&message));
+  options.preconditioner_type = JACOBI;
+  EXPECT_TRUE(options.IsValid(&message));
+  options.preconditioner_type = SCHUR_JACOBI;
+  EXPECT_TRUE(options.IsValid(&message));
+  options.preconditioner_type = CLUSTER_JACOBI;
+  EXPECT_FALSE(options.IsValid(&message));
+  options.preconditioner_type = CLUSTER_TRIDIAGONAL;
+  EXPECT_FALSE(options.IsValid(&message));
+  options.preconditioner_type = SUBSET;
+  EXPECT_FALSE(options.IsValid(&message));
+
+  options.use_explicit_schur_complement = true;
+  options.preconditioner_type = IDENTITY;
+  EXPECT_FALSE(options.IsValid(&message));
+  options.preconditioner_type = JACOBI;
+  EXPECT_FALSE(options.IsValid(&message));
+  options.preconditioner_type = SCHUR_JACOBI;
+  EXPECT_TRUE(options.IsValid(&message));
+  options.preconditioner_type = CLUSTER_JACOBI;
+  EXPECT_FALSE(options.IsValid(&message));
+  options.preconditioner_type = CLUSTER_TRIDIAGONAL;
+  EXPECT_FALSE(options.IsValid(&message));
+}
+
+TEST(Solver, IterativeSchurOptionsEigenSparse) {
+  std::string message;
+  Solver::Options options;
+  options.linear_solver_type = ITERATIVE_SCHUR;
+  options.sparse_linear_algebra_library_type = EIGEN_SPARSE;
+  options.preconditioner_type = IDENTITY;
+  EXPECT_TRUE(options.IsValid(&message));
+  options.preconditioner_type = JACOBI;
+  EXPECT_TRUE(options.IsValid(&message));
+  options.preconditioner_type = SCHUR_JACOBI;
+  EXPECT_TRUE(options.IsValid(&message));
+  options.preconditioner_type = CLUSTER_JACOBI;
+  EXPECT_EQ(options.IsValid(&message),
+            IsSparseLinearAlgebraLibraryTypeAvailable(
+                options.sparse_linear_algebra_library_type));
+  options.preconditioner_type = CLUSTER_TRIDIAGONAL;
+  EXPECT_EQ(options.IsValid(&message),
+            IsSparseLinearAlgebraLibraryTypeAvailable(
+                options.sparse_linear_algebra_library_type));
+  options.preconditioner_type = SUBSET;
+  EXPECT_FALSE(options.IsValid(&message));
+
+  options.use_explicit_schur_complement = true;
+  options.preconditioner_type = IDENTITY;
+  EXPECT_FALSE(options.IsValid(&message));
+  options.preconditioner_type = JACOBI;
+  EXPECT_FALSE(options.IsValid(&message));
+  options.preconditioner_type = SCHUR_JACOBI;
+  EXPECT_TRUE(options.IsValid(&message));
+  options.preconditioner_type = CLUSTER_JACOBI;
+  EXPECT_FALSE(options.IsValid(&message));
+  options.preconditioner_type = CLUSTER_TRIDIAGONAL;
+  EXPECT_FALSE(options.IsValid(&message));
+}
+
+TEST(Solver, IterativeSchurOptionsSuiteSparse) {
+  std::string message;
+  Solver::Options options;
+  options.linear_solver_type = ITERATIVE_SCHUR;
+  options.sparse_linear_algebra_library_type = SUITE_SPARSE;
+  options.preconditioner_type = IDENTITY;
+  EXPECT_TRUE(options.IsValid(&message));
+  options.preconditioner_type = JACOBI;
+  EXPECT_TRUE(options.IsValid(&message));
+  options.preconditioner_type = SCHUR_JACOBI;
+  EXPECT_TRUE(options.IsValid(&message));
+  options.preconditioner_type = CLUSTER_JACOBI;
+  EXPECT_EQ(options.IsValid(&message),
+            IsSparseLinearAlgebraLibraryTypeAvailable(
+                options.sparse_linear_algebra_library_type));
+  options.preconditioner_type = CLUSTER_TRIDIAGONAL;
+  EXPECT_EQ(options.IsValid(&message),
+            IsSparseLinearAlgebraLibraryTypeAvailable(
+                options.sparse_linear_algebra_library_type));
+  options.preconditioner_type = SUBSET;
+  EXPECT_FALSE(options.IsValid(&message));
+
+  options.use_explicit_schur_complement = true;
+  options.preconditioner_type = IDENTITY;
+  EXPECT_FALSE(options.IsValid(&message));
+  options.preconditioner_type = JACOBI;
+  EXPECT_FALSE(options.IsValid(&message));
+  options.preconditioner_type = SCHUR_JACOBI;
+  EXPECT_TRUE(options.IsValid(&message));
+  options.preconditioner_type = CLUSTER_JACOBI;
+  EXPECT_FALSE(options.IsValid(&message));
+  options.preconditioner_type = CLUSTER_TRIDIAGONAL;
+  EXPECT_FALSE(options.IsValid(&message));
+}
+
+TEST(Solver, IterativeSchurOptionsAccelerateSparse) {
+  std::string message;
+  Solver::Options options;
+  options.linear_solver_type = ITERATIVE_SCHUR;
+  options.sparse_linear_algebra_library_type = ACCELERATE_SPARSE;
+  options.preconditioner_type = IDENTITY;
+  EXPECT_TRUE(options.IsValid(&message));
+  options.preconditioner_type = JACOBI;
+  EXPECT_TRUE(options.IsValid(&message));
+  options.preconditioner_type = SCHUR_JACOBI;
+  EXPECT_TRUE(options.IsValid(&message));
+  options.preconditioner_type = CLUSTER_JACOBI;
+  EXPECT_EQ(options.IsValid(&message),
+            IsSparseLinearAlgebraLibraryTypeAvailable(
+                options.sparse_linear_algebra_library_type));
+  options.preconditioner_type = CLUSTER_TRIDIAGONAL;
+  EXPECT_EQ(options.IsValid(&message),
+            IsSparseLinearAlgebraLibraryTypeAvailable(
+                options.sparse_linear_algebra_library_type));
+  options.preconditioner_type = SUBSET;
+  EXPECT_FALSE(options.IsValid(&message));
+
+  options.use_explicit_schur_complement = true;
+  options.preconditioner_type = IDENTITY;
+  EXPECT_FALSE(options.IsValid(&message));
+  options.preconditioner_type = JACOBI;
+  EXPECT_FALSE(options.IsValid(&message));
+  options.preconditioner_type = SCHUR_JACOBI;
+  EXPECT_TRUE(options.IsValid(&message));
+  options.preconditioner_type = CLUSTER_JACOBI;
+  EXPECT_FALSE(options.IsValid(&message));
+  options.preconditioner_type = CLUSTER_TRIDIAGONAL;
+  EXPECT_FALSE(options.IsValid(&message));
+}
+
+class LargeCostCostFunction : public SizedCostFunction<1, 1> {
+ public:
+  bool Evaluate(double const* const* parameters,
+                double* residuals,
+                double** jacobians) const override {
+    residuals[0] = 1e300;
+    if (jacobians && jacobians[0]) {
+      jacobians[0][0] = 1.0;
+    }
+    return true;
+  }
+};
+
+TEST(Solver, LargeCostProblem) {
+  double x = 1;
+  Problem problem;
+  problem.AddResidualBlock(new LargeCostCostFunction, nullptr, &x);
+  Solver::Options options;
+  Solver::Summary summary;
+  Solve(options, &problem, &summary);
+  LOG(INFO) << summary.FullReport();
+  EXPECT_EQ(summary.termination_type, FAILURE);
+}
+
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/solver_utils.cc b/third_party/ceres/internal/ceres/solver_utils.cc
index eb5aafa..f5fbf05 100644
--- a/third_party/ceres/internal/ceres/solver_utils.cc
+++ b/third_party/ceres/internal/ceres/solver_utils.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -30,65 +30,59 @@
 
 #include "ceres/solver_utils.h"
 
-#include <string>
-
 #include "Eigen/Core"
 #include "ceres/internal/config.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 #include "ceres/version.h"
+#ifndef CERES_NO_CUDA
+#include "cuda_runtime.h"
+#endif  // CERES_NO_CUDA
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
-// clang-format off
-#define CERES_EIGEN_VERSION                 \
-  CERES_TO_STRING(EIGEN_WORLD_VERSION) "."  \
-  CERES_TO_STRING(EIGEN_MAJOR_VERSION) "."  \
-  CERES_TO_STRING(EIGEN_MINOR_VERSION)
-// clang-format on
-
-std::string VersionString() {
-  std::string value = std::string(CERES_VERSION_STRING);
-  value += "-eigen-(" + std::string(CERES_EIGEN_VERSION) + ")";
+constexpr char kVersion[] =
+    // clang-format off
+  CERES_VERSION_STRING "-eigen-("
+  CERES_SEMVER_VERSION(EIGEN_WORLD_VERSION,
+                       EIGEN_MAJOR_VERSION,
+                       EIGEN_MINOR_VERSION) ")"
 
 #ifdef CERES_NO_LAPACK
-  value += "-no_lapack";
+  "-no_lapack"
 #else
-  value += "-lapack";
+  "-lapack"
 #endif
 
 #ifndef CERES_NO_SUITESPARSE
-  value += "-suitesparse-(" + std::string(CERES_SUITESPARSE_VERSION) + ")";
+  "-suitesparse-(" CERES_SUITESPARSE_VERSION ")"
 #endif
 
-#ifndef CERES_NO_CXSPARSE
-  value += "-cxsparse-(" + std::string(CERES_CXSPARSE_VERSION) + ")";
+#if !defined(CERES_NO_EIGEN_METIS) || !defined(CERES_NO_CHOLMOD_PARTITION)
+  "-metis-(" CERES_METIS_VERSION ")"
 #endif
 
 #ifndef CERES_NO_ACCELERATE_SPARSE
-  value += "-acceleratesparse";
+  "-acceleratesparse"
 #endif
 
 #ifdef CERES_USE_EIGEN_SPARSE
-  value += "-eigensparse";
+  "-eigensparse"
 #endif
 
 #ifdef CERES_RESTRUCT_SCHUR_SPECIALIZATIONS
-  value += "-no_schur_specializations";
-#endif
-
-#ifdef CERES_USE_OPENMP
-  value += "-openmp";
-#else
-  value += "-no_openmp";
+  "-no_schur_specializations"
 #endif
 
 #ifdef CERES_NO_CUSTOM_BLAS
-  value += "-no_custom_blas";
+  "-no_custom_blas"
 #endif
 
-  return value;
-}
+#ifndef CERES_NO_CUDA
+  "-cuda-(" CERES_TO_STRING(CUDART_VERSION) ")"
+#endif
+  ;
+// clang-format on
 
-}  // namespace internal
-}  // namespace ceres
+std::string_view VersionString() noexcept { return kVersion; }
+
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/solver_utils.h b/third_party/ceres/internal/ceres/solver_utils.h
index 85fbf37..ff5e280 100644
--- a/third_party/ceres/internal/ceres/solver_utils.h
+++ b/third_party/ceres/internal/ceres/solver_utils.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -28,14 +28,18 @@
 //
 // Author: sameeragarwal@google.com (Sameer Agarwal)
 
-#include <algorithm>
-#include <string>
+#ifndef CERES_INTERNAL_SOLVER_UTILS_H_
+#define CERES_INTERNAL_SOLVER_UTILS_H_
 
+#include <algorithm>
+#include <string_view>
+
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 #include "ceres/iteration_callback.h"
 #include "ceres/types.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 template <typename SummaryType>
 bool IsSolutionUsable(const SummaryType& summary) {
@@ -55,7 +59,11 @@
   }
 }
 
-std::string VersionString();
+CERES_NO_EXPORT
+std::string_view VersionString() noexcept;
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
+
+#endif  // CERES_INTERNAL_SOLVER_UTILS_H_
diff --git a/third_party/ceres/internal/ceres/sparse_cholesky.cc b/third_party/ceres/internal/ceres/sparse_cholesky.cc
index 91cdf67..4f1bf87 100644
--- a/third_party/ceres/internal/ceres/sparse_cholesky.cc
+++ b/third_party/ceres/internal/ceres/sparse_cholesky.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -30,29 +30,29 @@
 
 #include "ceres/sparse_cholesky.h"
 
+#include <memory>
+#include <utility>
+
 #include "ceres/accelerate_sparse.h"
-#include "ceres/cxsparse.h"
 #include "ceres/eigensparse.h"
-#include "ceres/float_cxsparse.h"
 #include "ceres/float_suitesparse.h"
 #include "ceres/iterative_refiner.h"
 #include "ceres/suitesparse.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 std::unique_ptr<SparseCholesky> SparseCholesky::Create(
     const LinearSolver::Options& options) {
-  const OrderingType ordering_type = options.use_postordering ? AMD : NATURAL;
   std::unique_ptr<SparseCholesky> sparse_cholesky;
 
   switch (options.sparse_linear_algebra_library_type) {
     case SUITE_SPARSE:
 #ifndef CERES_NO_SUITESPARSE
       if (options.use_mixed_precision_solves) {
-        sparse_cholesky = FloatSuiteSparseCholesky::Create(ordering_type);
+        sparse_cholesky =
+            FloatSuiteSparseCholesky::Create(options.ordering_type);
       } else {
-        sparse_cholesky = SuiteSparseCholesky::Create(ordering_type);
+        sparse_cholesky = SuiteSparseCholesky::Create(options.ordering_type);
       }
       break;
 #else
@@ -62,9 +62,10 @@
     case EIGEN_SPARSE:
 #ifdef CERES_USE_EIGEN_SPARSE
       if (options.use_mixed_precision_solves) {
-        sparse_cholesky = FloatEigenSparseCholesky::Create(ordering_type);
+        sparse_cholesky =
+            FloatEigenSparseCholesky::Create(options.ordering_type);
       } else {
-        sparse_cholesky = EigenSparseCholesky::Create(ordering_type);
+        sparse_cholesky = EigenSparseCholesky::Create(options.ordering_type);
       }
       break;
 #else
@@ -72,25 +73,14 @@
                  << "Eigen's sparse Cholesky factorization routines.";
 #endif
 
-    case CX_SPARSE:
-#ifndef CERES_NO_CXSPARSE
-      if (options.use_mixed_precision_solves) {
-        sparse_cholesky = FloatCXSparseCholesky::Create(ordering_type);
-      } else {
-        sparse_cholesky = CXSparseCholesky::Create(ordering_type);
-      }
-      break;
-#else
-      LOG(FATAL) << "Ceres was compiled without support for CXSparse.";
-#endif
-
     case ACCELERATE_SPARSE:
 #ifndef CERES_NO_ACCELERATE_SPARSE
       if (options.use_mixed_precision_solves) {
-        sparse_cholesky = AppleAccelerateCholesky<float>::Create(ordering_type);
+        sparse_cholesky =
+            AppleAccelerateCholesky<float>::Create(options.ordering_type);
       } else {
         sparse_cholesky =
-            AppleAccelerateCholesky<double>::Create(ordering_type);
+            AppleAccelerateCholesky<double>::Create(options.ordering_type);
       }
       break;
 #else
@@ -105,15 +95,15 @@
   }
 
   if (options.max_num_refinement_iterations > 0) {
-    std::unique_ptr<IterativeRefiner> refiner(
-        new IterativeRefiner(options.max_num_refinement_iterations));
-    sparse_cholesky = std::unique_ptr<SparseCholesky>(new RefinedSparseCholesky(
-        std::move(sparse_cholesky), std::move(refiner)));
+    auto refiner = std::make_unique<SparseIterativeRefiner>(
+        options.max_num_refinement_iterations);
+    sparse_cholesky = std::make_unique<RefinedSparseCholesky>(
+        std::move(sparse_cholesky), std::move(refiner));
   }
   return sparse_cholesky;
 }
 
-SparseCholesky::~SparseCholesky() {}
+SparseCholesky::~SparseCholesky() = default;
 
 LinearSolverTerminationType SparseCholesky::FactorAndSolve(
     CompressedRowSparseMatrix* lhs,
@@ -121,7 +111,7 @@
     double* solution,
     std::string* message) {
   LinearSolverTerminationType termination_type = Factorize(lhs, message);
-  if (termination_type == LINEAR_SOLVER_SUCCESS) {
+  if (termination_type == LinearSolverTerminationType::SUCCESS) {
     termination_type = Solve(rhs, solution, message);
   }
   return termination_type;
@@ -129,11 +119,11 @@
 
 RefinedSparseCholesky::RefinedSparseCholesky(
     std::unique_ptr<SparseCholesky> sparse_cholesky,
-    std::unique_ptr<IterativeRefiner> iterative_refiner)
+    std::unique_ptr<SparseIterativeRefiner> iterative_refiner)
     : sparse_cholesky_(std::move(sparse_cholesky)),
       iterative_refiner_(std::move(iterative_refiner)) {}
 
-RefinedSparseCholesky::~RefinedSparseCholesky() {}
+RefinedSparseCholesky::~RefinedSparseCholesky() = default;
 
 CompressedRowSparseMatrix::StorageType RefinedSparseCholesky::StorageType()
     const {
@@ -151,13 +141,12 @@
                                                          std::string* message) {
   CHECK(lhs_ != nullptr);
   auto termination_type = sparse_cholesky_->Solve(rhs, solution, message);
-  if (termination_type != LINEAR_SOLVER_SUCCESS) {
+  if (termination_type != LinearSolverTerminationType::SUCCESS) {
     return termination_type;
   }
 
   iterative_refiner_->Refine(*lhs_, rhs, sparse_cholesky_.get(), solution);
-  return LINEAR_SOLVER_SUCCESS;
+  return LinearSolverTerminationType::SUCCESS;
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/sparse_cholesky.h b/third_party/ceres/internal/ceres/sparse_cholesky.h
index a6af6b2..53f475a 100644
--- a/third_party/ceres/internal/ceres/sparse_cholesky.h
+++ b/third_party/ceres/internal/ceres/sparse_cholesky.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -33,16 +33,17 @@
 
 // This include must come before any #ifndef check on Ceres compile options.
 // clang-format off
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 // clang-format on
 
 #include <memory>
 
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 #include "ceres/linear_solver.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // An interface that abstracts away the internal details of various
 // sparse linear algebra libraries and offers a simple API for solving
@@ -61,13 +62,14 @@
 //
 //  CompressedRowSparseMatrix lhs = ...;
 //  std::string message;
-//  CHECK_EQ(sparse_cholesky->Factorize(&lhs, &message), LINEAR_SOLVER_SUCCESS);
+//  CHECK_EQ(sparse_cholesky->Factorize(&lhs, &message),
+//           LinearSolverTerminationType::SUCCESS);
 //  Vector rhs = ...;
 //  Vector solution = ...;
 //  CHECK_EQ(sparse_cholesky->Solve(rhs.data(), solution.data(), &message),
-//           LINEAR_SOLVER_SUCCESS);
+//           LinearSolverTerminationType::SUCCESS);
 
-class CERES_EXPORT_INTERNAL SparseCholesky {
+class CERES_NO_EXPORT SparseCholesky {
  public:
   static std::unique_ptr<SparseCholesky> Create(
       const LinearSolver::Options& options);
@@ -103,38 +105,39 @@
 
   // Convenience method which combines a call to Factorize and
   // Solve. Solve is only called if Factorize returns
-  // LINEAR_SOLVER_SUCCESS.
-  virtual LinearSolverTerminationType FactorAndSolve(
-      CompressedRowSparseMatrix* lhs,
-      const double* rhs,
-      double* solution,
-      std::string* message);
+  // LinearSolverTerminationType::SUCCESS.
+  LinearSolverTerminationType FactorAndSolve(CompressedRowSparseMatrix* lhs,
+                                             const double* rhs,
+                                             double* solution,
+                                             std::string* message);
 };
 
-class IterativeRefiner;
+class SparseIterativeRefiner;
 
 // Computes an initial solution using the given instance of
-// SparseCholesky, and then refines it using the IterativeRefiner.
-class CERES_EXPORT_INTERNAL RefinedSparseCholesky : public SparseCholesky {
+// SparseCholesky, and then refines it using the SparseIterativeRefiner.
+class CERES_NO_EXPORT RefinedSparseCholesky final : public SparseCholesky {
  public:
-  RefinedSparseCholesky(std::unique_ptr<SparseCholesky> sparse_cholesky,
-                        std::unique_ptr<IterativeRefiner> iterative_refiner);
-  virtual ~RefinedSparseCholesky();
+  RefinedSparseCholesky(
+      std::unique_ptr<SparseCholesky> sparse_cholesky,
+      std::unique_ptr<SparseIterativeRefiner> iterative_refiner);
+  ~RefinedSparseCholesky() override;
 
-  virtual CompressedRowSparseMatrix::StorageType StorageType() const;
-  virtual LinearSolverTerminationType Factorize(CompressedRowSparseMatrix* lhs,
-                                                std::string* message);
-  virtual LinearSolverTerminationType Solve(const double* rhs,
-                                            double* solution,
-                                            std::string* message);
+  CompressedRowSparseMatrix::StorageType StorageType() const override;
+  LinearSolverTerminationType Factorize(CompressedRowSparseMatrix* lhs,
+                                        std::string* message) override;
+  LinearSolverTerminationType Solve(const double* rhs,
+                                    double* solution,
+                                    std::string* message) override;
 
  private:
   std::unique_ptr<SparseCholesky> sparse_cholesky_;
-  std::unique_ptr<IterativeRefiner> iterative_refiner_;
+  std::unique_ptr<SparseIterativeRefiner> iterative_refiner_;
   CompressedRowSparseMatrix* lhs_ = nullptr;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_SPARSE_CHOLESKY_H_
diff --git a/third_party/ceres/internal/ceres/sparse_cholesky_test.cc b/third_party/ceres/internal/ceres/sparse_cholesky_test.cc
index 2ef24e3..d0d962e 100644
--- a/third_party/ceres/internal/ceres/sparse_cholesky_test.cc
+++ b/third_party/ceres/internal/ceres/sparse_cholesky_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -32,6 +32,7 @@
 
 #include <memory>
 #include <numeric>
+#include <random>
 #include <vector>
 
 #include "Eigen/Dense"
@@ -39,22 +40,23 @@
 #include "ceres/block_sparse_matrix.h"
 #include "ceres/compressed_row_sparse_matrix.h"
 #include "ceres/inner_product_computer.h"
+#include "ceres/internal/config.h"
 #include "ceres/internal/eigen.h"
 #include "ceres/iterative_refiner.h"
-#include "ceres/random.h"
 #include "glog/logging.h"
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 namespace {
 
-BlockSparseMatrix* CreateRandomFullRankMatrix(const int num_col_blocks,
-                                              const int min_col_block_size,
-                                              const int max_col_block_size,
-                                              const double block_density) {
+std::unique_ptr<BlockSparseMatrix> CreateRandomFullRankMatrix(
+    const int num_col_blocks,
+    const int min_col_block_size,
+    const int max_col_block_size,
+    const double block_density,
+    std::mt19937& prng) {
   // Create a random matrix
   BlockSparseMatrix::RandomMatrixOptions options;
   options.num_col_blocks = num_col_blocks;
@@ -65,24 +67,23 @@
   options.min_row_block_size = 1;
   options.max_row_block_size = max_col_block_size;
   options.block_density = block_density;
-  std::unique_ptr<BlockSparseMatrix> random_matrix(
-      BlockSparseMatrix::CreateRandomMatrix(options));
+  auto random_matrix = BlockSparseMatrix::CreateRandomMatrix(options, prng);
 
   // Add a diagonal block sparse matrix to make it full rank.
   Vector diagonal = Vector::Ones(random_matrix->num_cols());
-  std::unique_ptr<BlockSparseMatrix> block_diagonal(
-      BlockSparseMatrix::CreateDiagonalMatrix(
-          diagonal.data(), random_matrix->block_structure()->cols));
+  auto block_diagonal = BlockSparseMatrix::CreateDiagonalMatrix(
+      diagonal.data(), random_matrix->block_structure()->cols);
   random_matrix->AppendRows(*block_diagonal);
-  return random_matrix.release();
+  return random_matrix;
 }
 
-static bool ComputeExpectedSolution(const CompressedRowSparseMatrix& lhs,
-                                    const Vector& rhs,
-                                    Vector* solution) {
+bool ComputeExpectedSolution(const CompressedRowSparseMatrix& lhs,
+                             const Vector& rhs,
+                             Vector* solution) {
   Matrix eigen_lhs;
   lhs.ToDenseMatrix(&eigen_lhs);
-  if (lhs.storage_type() == CompressedRowSparseMatrix::UPPER_TRIANGULAR) {
+  if (lhs.storage_type() ==
+      CompressedRowSparseMatrix::StorageType::UPPER_TRIANGULAR) {
     Matrix full_lhs = eigen_lhs.selfadjointView<Eigen::Upper>();
     Eigen::LLT<Matrix, Eigen::Upper> llt =
         eigen_lhs.selfadjointView<Eigen::Upper>().llt();
@@ -110,20 +111,19 @@
     const int num_blocks,
     const int min_block_size,
     const int max_block_size,
-    const double block_density) {
+    const double block_density,
+    std::mt19937& prng) {
   LinearSolver::Options sparse_cholesky_options;
   sparse_cholesky_options.sparse_linear_algebra_library_type =
       sparse_linear_algebra_library_type;
-  sparse_cholesky_options.use_postordering = (ordering_type == AMD);
-  std::unique_ptr<SparseCholesky> sparse_cholesky =
-      SparseCholesky::Create(sparse_cholesky_options);
+  sparse_cholesky_options.ordering_type = ordering_type;
+  auto sparse_cholesky = SparseCholesky::Create(sparse_cholesky_options);
   const CompressedRowSparseMatrix::StorageType storage_type =
       sparse_cholesky->StorageType();
 
-  std::unique_ptr<BlockSparseMatrix> m(CreateRandomFullRankMatrix(
-      num_blocks, min_block_size, max_block_size, block_density));
-  std::unique_ptr<InnerProductComputer> inner_product_computer(
-      InnerProductComputer::Create(*m, storage_type));
+  auto m = CreateRandomFullRankMatrix(
+      num_blocks, min_block_size, max_block_size, block_density, prng);
+  auto inner_product_computer = InnerProductComputer::Create(*m, storage_type);
   inner_product_computer->Compute();
   CompressedRowSparseMatrix* lhs = inner_product_computer->mutable_result();
 
@@ -140,7 +140,7 @@
   std::string message;
   EXPECT_EQ(
       sparse_cholesky->FactorAndSolve(lhs, rhs.data(), actual.data(), &message),
-      LINEAR_SOLVER_SUCCESS);
+      LinearSolverTerminationType::SUCCESS);
   Matrix eigen_lhs;
   lhs->ToDenseMatrix(&eigen_lhs);
   EXPECT_NEAR((actual - expected).norm() / actual.norm(),
@@ -150,14 +150,14 @@
       << eigen_lhs;
 }
 
-typedef ::testing::tuple<SparseLinearAlgebraLibraryType, OrderingType, bool>
-    Param;
+using Param =
+    ::testing::tuple<SparseLinearAlgebraLibraryType, OrderingType, bool>;
 
 std::string ParamInfoToString(testing::TestParamInfo<Param> info) {
   Param param = info.param;
   std::stringstream ss;
   ss << SparseLinearAlgebraLibraryTypeToString(::testing::get<0>(param)) << "_"
-     << (::testing::get<1>(param) == AMD ? "AMD" : "NATURAL") << "_"
+     << ::testing::get<1>(param) << "_"
      << (::testing::get<2>(param) ? "UseBlockStructure" : "NoBlockStructure");
   return ss.str();
 }
@@ -167,25 +167,29 @@
 class SparseCholeskyTest : public ::testing::TestWithParam<Param> {};
 
 TEST_P(SparseCholeskyTest, FactorAndSolve) {
-  SetRandomState(2982);
-  const int kMinNumBlocks = 1;
-  const int kMaxNumBlocks = 10;
-  const int kNumTrials = 10;
-  const int kMinBlockSize = 1;
-  const int kMaxBlockSize = 5;
+  constexpr int kMinNumBlocks = 1;
+  constexpr int kMaxNumBlocks = 10;
+  constexpr int kNumTrials = 10;
+  constexpr int kMinBlockSize = 1;
+  constexpr int kMaxBlockSize = 5;
+
+  Param param = GetParam();
+
+  std::mt19937 prng;
+  std::uniform_real_distribution<double> distribution(0.1, 1.0);
 
   for (int num_blocks = kMinNumBlocks; num_blocks < kMaxNumBlocks;
        ++num_blocks) {
     for (int trial = 0; trial < kNumTrials; ++trial) {
-      const double block_density = std::max(0.1, RandDouble());
-      Param param = GetParam();
+      const double block_density = distribution(prng);
       SparseCholeskySolverUnitTest(::testing::get<0>(param),
                                    ::testing::get<1>(param),
                                    ::testing::get<2>(param),
                                    num_blocks,
                                    kMinBlockSize,
                                    kMaxBlockSize,
-                                   block_density);
+                                   block_density,
+                                   prng);
     }
   }
 }
@@ -193,29 +197,35 @@
 namespace {
 
 #ifndef CERES_NO_SUITESPARSE
-INSTANTIATE_TEST_SUITE_P(SuiteSparseCholesky,
-                         SparseCholeskyTest,
-                         ::testing::Combine(::testing::Values(SUITE_SPARSE),
-                                            ::testing::Values(AMD, NATURAL),
-                                            ::testing::Values(true, false)),
-                         ParamInfoToString);
+INSTANTIATE_TEST_SUITE_P(
+    SuiteSparseCholesky,
+    SparseCholeskyTest,
+    ::testing::Combine(::testing::Values(SUITE_SPARSE),
+                       ::testing::Values(OrderingType::AMD,
+                                         OrderingType::NATURAL),
+                       ::testing::Values(true, false)),
+    ParamInfoToString);
 #endif
 
-#ifndef CERES_NO_CXSPARSE
-INSTANTIATE_TEST_SUITE_P(CXSparseCholesky,
-                         SparseCholeskyTest,
-                         ::testing::Combine(::testing::Values(CX_SPARSE),
-                                            ::testing::Values(AMD, NATURAL),
-                                            ::testing::Values(true, false)),
-                         ParamInfoToString);
-#endif
+#if !defined(CERES_NO_SUITESPARSE) && !defined(CERES_NO_CHOLMOD_PARTITION)
+INSTANTIATE_TEST_SUITE_P(
+    SuiteSparseCholeskyMETIS,
+    SparseCholeskyTest,
+    ::testing::Combine(::testing::Values(SUITE_SPARSE),
+                       ::testing::Values(OrderingType::NESDIS),
+                       ::testing::Values(true, false)),
+    ParamInfoToString);
+#endif  // !defined(CERES_NO_SUITESPARSE) &&
+        // !defined(CERES_NO_CHOLMOD_PARTITION)
 
 #ifndef CERES_NO_ACCELERATE_SPARSE
 INSTANTIATE_TEST_SUITE_P(
     AccelerateSparseCholesky,
     SparseCholeskyTest,
     ::testing::Combine(::testing::Values(ACCELERATE_SPARSE),
-                       ::testing::Values(AMD, NATURAL),
+                       ::testing::Values(OrderingType::AMD,
+                                         OrderingType::NESDIS,
+                                         OrderingType::NATURAL),
                        ::testing::Values(true, false)),
     ParamInfoToString);
 
@@ -223,26 +233,50 @@
     AccelerateSparseCholeskySingle,
     SparseCholeskyTest,
     ::testing::Combine(::testing::Values(ACCELERATE_SPARSE),
-                       ::testing::Values(AMD, NATURAL),
+                       ::testing::Values(OrderingType::AMD,
+                                         OrderingType::NESDIS,
+                                         OrderingType::NATURAL),
                        ::testing::Values(true, false)),
     ParamInfoToString);
 #endif
 
 #ifdef CERES_USE_EIGEN_SPARSE
-INSTANTIATE_TEST_SUITE_P(EigenSparseCholesky,
-                         SparseCholeskyTest,
-                         ::testing::Combine(::testing::Values(EIGEN_SPARSE),
-                                            ::testing::Values(AMD, NATURAL),
-                                            ::testing::Values(true, false)),
-                         ParamInfoToString);
+INSTANTIATE_TEST_SUITE_P(
+    EigenSparseCholesky,
+    SparseCholeskyTest,
+    ::testing::Combine(::testing::Values(EIGEN_SPARSE),
+                       ::testing::Values(OrderingType::AMD,
+                                         OrderingType::NATURAL),
+                       ::testing::Values(true, false)),
+    ParamInfoToString);
 
-INSTANTIATE_TEST_SUITE_P(EigenSparseCholeskySingle,
-                         SparseCholeskyTest,
-                         ::testing::Combine(::testing::Values(EIGEN_SPARSE),
-                                            ::testing::Values(AMD, NATURAL),
-                                            ::testing::Values(true, false)),
-                         ParamInfoToString);
-#endif
+INSTANTIATE_TEST_SUITE_P(
+    EigenSparseCholeskySingle,
+    SparseCholeskyTest,
+    ::testing::Combine(::testing::Values(EIGEN_SPARSE),
+                       ::testing::Values(OrderingType::AMD,
+                                         OrderingType::NATURAL),
+                       ::testing::Values(true, false)),
+    ParamInfoToString);
+#endif  // CERES_USE_EIGEN_SPARSE
+
+#if defined(CERES_USE_EIGEN_SPARSE) && !defined(CERES_NO_EIGEN_METIS)
+INSTANTIATE_TEST_SUITE_P(
+    EigenSparseCholeskyMETIS,
+    SparseCholeskyTest,
+    ::testing::Combine(::testing::Values(EIGEN_SPARSE),
+                       ::testing::Values(OrderingType::NESDIS),
+                       ::testing::Values(true, false)),
+    ParamInfoToString);
+
+INSTANTIATE_TEST_SUITE_P(
+    EigenSparseCholeskySingleMETIS,
+    SparseCholeskyTest,
+    ::testing::Combine(::testing::Values(EIGEN_SPARSE),
+                       ::testing::Values(OrderingType::NESDIS),
+                       ::testing::Values(true, false)),
+    ParamInfoToString);
+#endif  // defined(CERES_USE_EIGEN_SPARSE) && !defined(CERES_NO_EIGEN_METIS)
 
 class MockSparseCholesky : public SparseCholesky {
  public:
@@ -256,9 +290,9 @@
                                            std::string* message));
 };
 
-class MockIterativeRefiner : public IterativeRefiner {
+class MockSparseIterativeRefiner : public SparseIterativeRefiner {
  public:
-  MockIterativeRefiner() : IterativeRefiner(1) {}
+  MockSparseIterativeRefiner() : SparseIterativeRefiner(1) {}
   MOCK_METHOD4(Refine,
                void(const SparseMatrix& lhs,
                     const double* rhs,
@@ -270,47 +304,48 @@
 using testing::Return;
 
 TEST(RefinedSparseCholesky, StorageType) {
-  MockSparseCholesky* mock_sparse_cholesky = new MockSparseCholesky;
-  MockIterativeRefiner* mock_iterative_refiner = new MockIterativeRefiner;
-  EXPECT_CALL(*mock_sparse_cholesky, StorageType())
+  auto sparse_cholesky = std::make_unique<MockSparseCholesky>();
+  auto iterative_refiner = std::make_unique<MockSparseIterativeRefiner>();
+  EXPECT_CALL(*sparse_cholesky, StorageType())
       .Times(1)
-      .WillRepeatedly(Return(CompressedRowSparseMatrix::UPPER_TRIANGULAR));
-  EXPECT_CALL(*mock_iterative_refiner, Refine(_, _, _, _)).Times(0);
-  std::unique_ptr<SparseCholesky> sparse_cholesky(mock_sparse_cholesky);
-  std::unique_ptr<IterativeRefiner> iterative_refiner(mock_iterative_refiner);
+      .WillRepeatedly(
+          Return(CompressedRowSparseMatrix::StorageType::UPPER_TRIANGULAR));
+  EXPECT_CALL(*iterative_refiner, Refine(_, _, _, _)).Times(0);
   RefinedSparseCholesky refined_sparse_cholesky(std::move(sparse_cholesky),
                                                 std::move(iterative_refiner));
   EXPECT_EQ(refined_sparse_cholesky.StorageType(),
-            CompressedRowSparseMatrix::UPPER_TRIANGULAR);
+            CompressedRowSparseMatrix::StorageType::UPPER_TRIANGULAR);
 };
 
 TEST(RefinedSparseCholesky, Factorize) {
-  MockSparseCholesky* mock_sparse_cholesky = new MockSparseCholesky;
-  MockIterativeRefiner* mock_iterative_refiner = new MockIterativeRefiner;
+  auto* mock_sparse_cholesky = new MockSparseCholesky;
+  auto* mock_iterative_refiner = new MockSparseIterativeRefiner;
   EXPECT_CALL(*mock_sparse_cholesky, Factorize(_, _))
       .Times(1)
-      .WillRepeatedly(Return(LINEAR_SOLVER_SUCCESS));
+      .WillRepeatedly(Return(LinearSolverTerminationType::SUCCESS));
   EXPECT_CALL(*mock_iterative_refiner, Refine(_, _, _, _)).Times(0);
   std::unique_ptr<SparseCholesky> sparse_cholesky(mock_sparse_cholesky);
-  std::unique_ptr<IterativeRefiner> iterative_refiner(mock_iterative_refiner);
+  std::unique_ptr<SparseIterativeRefiner> iterative_refiner(
+      mock_iterative_refiner);
   RefinedSparseCholesky refined_sparse_cholesky(std::move(sparse_cholesky),
                                                 std::move(iterative_refiner));
   CompressedRowSparseMatrix m(1, 1, 1);
   std::string message;
   EXPECT_EQ(refined_sparse_cholesky.Factorize(&m, &message),
-            LINEAR_SOLVER_SUCCESS);
+            LinearSolverTerminationType::SUCCESS);
 };
 
 TEST(RefinedSparseCholesky, FactorAndSolveWithUnsuccessfulFactorization) {
-  MockSparseCholesky* mock_sparse_cholesky = new MockSparseCholesky;
-  MockIterativeRefiner* mock_iterative_refiner = new MockIterativeRefiner;
+  auto* mock_sparse_cholesky = new MockSparseCholesky;
+  auto* mock_iterative_refiner = new MockSparseIterativeRefiner;
   EXPECT_CALL(*mock_sparse_cholesky, Factorize(_, _))
       .Times(1)
-      .WillRepeatedly(Return(LINEAR_SOLVER_FAILURE));
+      .WillRepeatedly(Return(LinearSolverTerminationType::FAILURE));
   EXPECT_CALL(*mock_sparse_cholesky, Solve(_, _, _)).Times(0);
   EXPECT_CALL(*mock_iterative_refiner, Refine(_, _, _, _)).Times(0);
   std::unique_ptr<SparseCholesky> sparse_cholesky(mock_sparse_cholesky);
-  std::unique_ptr<IterativeRefiner> iterative_refiner(mock_iterative_refiner);
+  std::unique_ptr<SparseIterativeRefiner> iterative_refiner(
+      mock_iterative_refiner);
   RefinedSparseCholesky refined_sparse_cholesky(std::move(sparse_cholesky),
                                                 std::move(iterative_refiner));
   CompressedRowSparseMatrix m(1, 1, 1);
@@ -319,23 +354,23 @@
   double solution;
   EXPECT_EQ(
       refined_sparse_cholesky.FactorAndSolve(&m, &rhs, &solution, &message),
-      LINEAR_SOLVER_FAILURE);
+      LinearSolverTerminationType::FAILURE);
 };
 
 TEST(RefinedSparseCholesky, FactorAndSolveWithSuccess) {
-  MockSparseCholesky* mock_sparse_cholesky = new MockSparseCholesky;
-  std::unique_ptr<MockIterativeRefiner> mock_iterative_refiner(
-      new MockIterativeRefiner);
+  auto* mock_sparse_cholesky = new MockSparseCholesky;
+  std::unique_ptr<MockSparseIterativeRefiner> mock_iterative_refiner(
+      new MockSparseIterativeRefiner);
   EXPECT_CALL(*mock_sparse_cholesky, Factorize(_, _))
       .Times(1)
-      .WillRepeatedly(Return(LINEAR_SOLVER_SUCCESS));
+      .WillRepeatedly(Return(LinearSolverTerminationType::SUCCESS));
   EXPECT_CALL(*mock_sparse_cholesky, Solve(_, _, _))
       .Times(1)
-      .WillRepeatedly(Return(LINEAR_SOLVER_SUCCESS));
+      .WillRepeatedly(Return(LinearSolverTerminationType::SUCCESS));
   EXPECT_CALL(*mock_iterative_refiner, Refine(_, _, _, _)).Times(1);
 
   std::unique_ptr<SparseCholesky> sparse_cholesky(mock_sparse_cholesky);
-  std::unique_ptr<IterativeRefiner> iterative_refiner(
+  std::unique_ptr<SparseIterativeRefiner> iterative_refiner(
       std::move(mock_iterative_refiner));
   RefinedSparseCholesky refined_sparse_cholesky(std::move(sparse_cholesky),
                                                 std::move(iterative_refiner));
@@ -345,10 +380,9 @@
   double solution;
   EXPECT_EQ(
       refined_sparse_cholesky.FactorAndSolve(&m, &rhs, &solution, &message),
-      LINEAR_SOLVER_SUCCESS);
+      LinearSolverTerminationType::SUCCESS);
 };
 
 }  // namespace
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/sparse_matrix.cc b/third_party/ceres/internal/ceres/sparse_matrix.cc
index 32388f5..cdc77fc 100644
--- a/third_party/ceres/internal/ceres/sparse_matrix.cc
+++ b/third_party/ceres/internal/ceres/sparse_matrix.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -30,10 +30,24 @@
 
 #include "ceres/sparse_matrix.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
-SparseMatrix::~SparseMatrix() {}
+SparseMatrix::~SparseMatrix() = default;
 
-}  // namespace internal
-}  // namespace ceres
+void SparseMatrix::SquaredColumnNorm(double* x,
+                                     ContextImpl* context,
+                                     int num_threads) const {
+  (void)context;
+  (void)num_threads;
+  SquaredColumnNorm(x);
+}
+
+void SparseMatrix::ScaleColumns(const double* scale,
+                                ContextImpl* context,
+                                int num_threads) {
+  (void)context;
+  (void)num_threads;
+  ScaleColumns(scale);
+}
+
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/sparse_matrix.h b/third_party/ceres/internal/ceres/sparse_matrix.h
index b57f108..9c79417 100644
--- a/third_party/ceres/internal/ceres/sparse_matrix.h
+++ b/third_party/ceres/internal/ceres/sparse_matrix.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -36,12 +36,12 @@
 #include <cstdio>
 
 #include "ceres/internal/eigen.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 #include "ceres/linear_operator.h"
 #include "ceres/types.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
+class ContextImpl;
 
 // This class defines the interface for storing and manipulating
 // sparse matrices. The key property that differentiates different
@@ -64,23 +64,35 @@
 // matrix type dependent and we are at this stage unable to come up
 // with an efficient high level interface that spans multiple sparse
 // matrix types.
-class CERES_EXPORT_INTERNAL SparseMatrix : public LinearOperator {
+class CERES_NO_EXPORT SparseMatrix : public LinearOperator {
  public:
-  virtual ~SparseMatrix();
+  ~SparseMatrix() override;
 
   // y += Ax;
-  virtual void RightMultiply(const double* x, double* y) const = 0;
+  using LinearOperator::RightMultiplyAndAccumulate;
+  void RightMultiplyAndAccumulate(const double* x,
+                                  double* y) const override = 0;
+
   // y += A'x;
-  virtual void LeftMultiply(const double* x, double* y) const = 0;
+  void LeftMultiplyAndAccumulate(const double* x, double* y) const override = 0;
 
   // In MATLAB notation sum(A.*A, 1)
   virtual void SquaredColumnNorm(double* x) const = 0;
+  virtual void SquaredColumnNorm(double* x,
+                                 ContextImpl* context,
+                                 int num_threads) const;
   // A = A * diag(scale)
   virtual void ScaleColumns(const double* scale) = 0;
+  virtual void ScaleColumns(const double* scale,
+                            ContextImpl* context,
+                            int num_threads);
 
   // A = 0. A->num_nonzeros() == 0 is true after this call. The
   // sparsity pattern is preserved.
   virtual void SetZero() = 0;
+  virtual void SetZero(ContextImpl* /*context*/, int /*num_threads*/) {
+    SetZero();
+  }
 
   // Resize and populate dense_matrix with a dense version of the
   // sparse matrix.
@@ -98,12 +110,11 @@
   virtual double* mutable_values() = 0;
   virtual const double* values() const = 0;
 
-  virtual int num_rows() const = 0;
-  virtual int num_cols() const = 0;
+  int num_rows() const override = 0;
+  int num_cols() const override = 0;
   virtual int num_nonzeros() const = 0;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_INTERNAL_SPARSE_MATRIX_H_
diff --git a/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver.cc b/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver.cc
index 0f2e589..5746509 100644
--- a/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver.cc
+++ b/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -45,8 +45,7 @@
 #include "ceres/types.h"
 #include "ceres/wall_time.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 SparseNormalCholeskySolver::SparseNormalCholeskySolver(
     const LinearSolver::Options& options)
@@ -54,7 +53,7 @@
   sparse_cholesky_ = SparseCholesky::Create(options);
 }
 
-SparseNormalCholeskySolver::~SparseNormalCholeskySolver() {}
+SparseNormalCholeskySolver::~SparseNormalCholeskySolver() = default;
 
 LinearSolver::Summary SparseNormalCholeskySolver::SolveImpl(
     BlockSparseMatrix* A,
@@ -64,7 +63,7 @@
   EventLogger event_logger("SparseNormalCholeskySolver::Solve");
   LinearSolver::Summary summary;
   summary.num_iterations = 1;
-  summary.termination_type = LINEAR_SOLVER_SUCCESS;
+  summary.termination_type = LinearSolverTerminationType::SUCCESS;
   summary.message = "Success.";
 
   const int num_cols = A->num_cols();
@@ -72,24 +71,24 @@
   xref.setZero();
   rhs_.resize(num_cols);
   rhs_.setZero();
-  A->LeftMultiply(b, rhs_.data());
+  A->LeftMultiplyAndAccumulate(b, rhs_.data());
   event_logger.AddEvent("Compute RHS");
 
-  if (per_solve_options.D != NULL) {
+  if (per_solve_options.D != nullptr) {
     // Temporarily append a diagonal block to the A matrix, but undo
     // it before returning the matrix to the user.
-    std::unique_ptr<BlockSparseMatrix> regularizer;
-    regularizer.reset(BlockSparseMatrix::CreateDiagonalMatrix(
-        per_solve_options.D, A->block_structure()->cols));
+    std::unique_ptr<BlockSparseMatrix> regularizer =
+        BlockSparseMatrix::CreateDiagonalMatrix(per_solve_options.D,
+                                                A->block_structure()->cols);
     event_logger.AddEvent("Diagonal");
     A->AppendRows(*regularizer);
     event_logger.AddEvent("Append");
   }
   event_logger.AddEvent("Append Rows");
 
-  if (inner_product_computer_.get() == NULL) {
-    inner_product_computer_.reset(
-        InnerProductComputer::Create(*A, sparse_cholesky_->StorageType()));
+  if (inner_product_computer_.get() == nullptr) {
+    inner_product_computer_ =
+        InnerProductComputer::Create(*A, sparse_cholesky_->StorageType());
 
     event_logger.AddEvent("InnerProductComputer::Create");
   }
@@ -97,7 +96,7 @@
   inner_product_computer_->Compute();
   event_logger.AddEvent("InnerProductComputer::Compute");
 
-  if (per_solve_options.D != NULL) {
+  if (per_solve_options.D != nullptr) {
     A->DeleteRowBlocks(A->block_structure()->cols.size());
   }
 
@@ -110,5 +109,4 @@
   return summary;
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver.h b/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver.h
index ef32743..585d1c1 100644
--- a/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver.h
+++ b/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -36,15 +36,16 @@
 
 // This include must come before any #ifndef check on Ceres compile options.
 // clang-format off
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 // clang-format on
 
+#include <memory>
 #include <vector>
 
+#include "ceres/internal/export.h"
 #include "ceres/linear_solver.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 class CompressedRowSparseMatrix;
 class InnerProductComputer;
@@ -52,13 +53,14 @@
 
 // Solves the normal equations (A'A + D'D) x = A'b, using the sparse
 // linear algebra library of the user's choice.
-class SparseNormalCholeskySolver : public BlockSparseMatrixSolver {
+class CERES_NO_EXPORT SparseNormalCholeskySolver
+    : public BlockSparseMatrixSolver {
  public:
   explicit SparseNormalCholeskySolver(const LinearSolver::Options& options);
   SparseNormalCholeskySolver(const SparseNormalCholeskySolver&) = delete;
   void operator=(const SparseNormalCholeskySolver&) = delete;
 
-  virtual ~SparseNormalCholeskySolver();
+  ~SparseNormalCholeskySolver() override;
 
  private:
   LinearSolver::Summary SolveImpl(BlockSparseMatrix* A,
@@ -72,7 +74,6 @@
   std::unique_ptr<InnerProductComputer> inner_product_computer_;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_INTERNAL_SPARSE_NORMAL_CHOLESKY_SOLVER_H_
diff --git a/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver_test.cc b/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver_test.cc
index 8acb98e..3396e34 100644
--- a/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver_test.cc
+++ b/third_party/ceres/internal/ceres/sparse_normal_cholesky_solver_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -41,8 +41,7 @@
 #include "glog/logging.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // TODO(sameeragarwal): These tests needs to be re-written, since
 // SparseNormalCholeskySolver is a composition of two classes now,
@@ -54,20 +53,20 @@
 class SparseNormalCholeskySolverTest : public ::testing::Test {
  protected:
   void SetUp() final {
-    std::unique_ptr<LinearLeastSquaresProblem> problem(
-        CreateLinearLeastSquaresProblemFromId(2));
+    std::unique_ptr<LinearLeastSquaresProblem> problem =
+        CreateLinearLeastSquaresProblemFromId(2);
 
     CHECK(problem != nullptr);
     A_.reset(down_cast<BlockSparseMatrix*>(problem->A.release()));
-    b_.reset(problem->b.release());
-    D_.reset(problem->D.release());
+    b_ = std::move(problem->b);
+    D_ = std::move(problem->D);
   }
 
   void TestSolver(const LinearSolver::Options& options, double* D) {
     Matrix dense_A;
     A_->ToDenseMatrix(&dense_A);
     Matrix lhs = dense_A.transpose() * dense_A;
-    if (D != NULL) {
+    if (D != nullptr) {
       lhs += (ConstVectorRef(D, A_->num_cols()).array() *
               ConstVectorRef(D, A_->num_cols()).array())
                  .matrix()
@@ -76,7 +75,7 @@
 
     Vector rhs(A_->num_cols());
     rhs.setZero();
-    A_->LeftMultiply(b_.get(), rhs.data());
+    A_->LeftMultiplyAndAccumulate(b_.get(), rhs.data());
     Vector expected_solution = lhs.llt().solve(rhs);
 
     std::unique_ptr<LinearSolver> solver(LinearSolver::Create(options));
@@ -87,7 +86,7 @@
     summary = solver->Solve(
         A_.get(), b_.get(), per_solve_options, actual_solution.data());
 
-    EXPECT_EQ(summary.termination_type, LINEAR_SOLVER_SUCCESS);
+    EXPECT_EQ(summary.termination_type, LinearSolverTerminationType::SUCCESS);
 
     for (int i = 0; i < A_->num_cols(); ++i) {
       EXPECT_NEAR(expected_solution(i), actual_solution(i), 1e-8)
@@ -97,7 +96,7 @@
   }
 
   void TestSolver(const LinearSolver::Options& options) {
-    TestSolver(options, NULL);
+    TestSolver(options, nullptr);
     TestSolver(options, D_.get());
   }
 
@@ -112,7 +111,7 @@
   LinearSolver::Options options;
   options.sparse_linear_algebra_library_type = SUITE_SPARSE;
   options.type = SPARSE_NORMAL_CHOLESKY;
-  options.use_postordering = false;
+  options.ordering_type = OrderingType::NATURAL;
   ContextImpl context;
   options.context = &context;
   TestSolver(options);
@@ -123,31 +122,7 @@
   LinearSolver::Options options;
   options.sparse_linear_algebra_library_type = SUITE_SPARSE;
   options.type = SPARSE_NORMAL_CHOLESKY;
-  options.use_postordering = true;
-  ContextImpl context;
-  options.context = &context;
-  TestSolver(options);
-}
-#endif
-
-#ifndef CERES_NO_CXSPARSE
-TEST_F(SparseNormalCholeskySolverTest,
-       SparseNormalCholeskyUsingCXSparsePreOrdering) {
-  LinearSolver::Options options;
-  options.sparse_linear_algebra_library_type = CX_SPARSE;
-  options.type = SPARSE_NORMAL_CHOLESKY;
-  options.use_postordering = false;
-  ContextImpl context;
-  options.context = &context;
-  TestSolver(options);
-}
-
-TEST_F(SparseNormalCholeskySolverTest,
-       SparseNormalCholeskyUsingCXSparsePostOrdering) {
-  LinearSolver::Options options;
-  options.sparse_linear_algebra_library_type = CX_SPARSE;
-  options.type = SPARSE_NORMAL_CHOLESKY;
-  options.use_postordering = true;
+  options.ordering_type = OrderingType::AMD;
   ContextImpl context;
   options.context = &context;
   TestSolver(options);
@@ -160,7 +135,7 @@
   LinearSolver::Options options;
   options.sparse_linear_algebra_library_type = ACCELERATE_SPARSE;
   options.type = SPARSE_NORMAL_CHOLESKY;
-  options.use_postordering = false;
+  options.ordering_type = OrderingType::NATURAL;
   ContextImpl context;
   options.context = &context;
   TestSolver(options);
@@ -171,7 +146,7 @@
   LinearSolver::Options options;
   options.sparse_linear_algebra_library_type = ACCELERATE_SPARSE;
   options.type = SPARSE_NORMAL_CHOLESKY;
-  options.use_postordering = true;
+  options.ordering_type = OrderingType::AMD;
   ContextImpl context;
   options.context = &context;
   TestSolver(options);
@@ -184,7 +159,7 @@
   LinearSolver::Options options;
   options.sparse_linear_algebra_library_type = EIGEN_SPARSE;
   options.type = SPARSE_NORMAL_CHOLESKY;
-  options.use_postordering = false;
+  options.ordering_type = OrderingType::NATURAL;
   ContextImpl context;
   options.context = &context;
   TestSolver(options);
@@ -195,12 +170,11 @@
   LinearSolver::Options options;
   options.sparse_linear_algebra_library_type = EIGEN_SPARSE;
   options.type = SPARSE_NORMAL_CHOLESKY;
-  options.use_postordering = true;
+  options.ordering_type = OrderingType::AMD;
   ContextImpl context;
   options.context = &context;
   TestSolver(options);
 }
 #endif  // CERES_USE_EIGEN_SPARSE
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/split.cc b/third_party/ceres/internal/ceres/split.cc
deleted file mode 100644
index 804f441..0000000
--- a/third_party/ceres/internal/ceres/split.cc
+++ /dev/null
@@ -1,122 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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 Google Inc. 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.
-//
-// Author: keir@google.com (Keir Mierle)
-
-#include "ceres/split.h"
-
-#include <iterator>
-#include <string>
-#include <vector>
-
-#include "ceres/internal/port.h"
-
-namespace ceres {
-namespace internal {
-
-using std::string;
-using std::vector;
-
-// If we know how much to allocate for a vector of strings, we can allocate the
-// vector<string> only once and directly to the right size. This saves in
-// between 33-66 % of memory space needed for the result, and runs faster in the
-// microbenchmarks.
-//
-// The reserve is only implemented for the single character delim.
-//
-// The implementation for counting is cut-and-pasted from
-// SplitStringToIteratorUsing. I could have written my own counting iterator,
-// and use the existing template function, but probably this is more clear and
-// more sure to get optimized to reasonable code.
-static int CalculateReserveForVector(const string& full, const char* delim) {
-  int count = 0;
-  if (delim[0] != '\0' && delim[1] == '\0') {
-    // Optimize the common case where delim is a single character.
-    char c = delim[0];
-    const char* p = full.data();
-    const char* end = p + full.size();
-    while (p != end) {
-      if (*p == c) {  // This could be optimized with hasless(v,1) trick.
-        ++p;
-      } else {
-        while (++p != end && *p != c) {
-          // Skip to the next occurence of the delimiter.
-        }
-        ++count;
-      }
-    }
-  }
-  return count;
-}
-
-template <typename StringType, typename ITR>
-static inline void SplitStringToIteratorUsing(const StringType& full,
-                                              const char* delim,
-                                              ITR& result) {
-  // Optimize the common case where delim is a single character.
-  if (delim[0] != '\0' && delim[1] == '\0') {
-    char c = delim[0];
-    const char* p = full.data();
-    const char* end = p + full.size();
-    while (p != end) {
-      if (*p == c) {
-        ++p;
-      } else {
-        const char* start = p;
-        while (++p != end && *p != c) {
-          // Skip to the next occurence of the delimiter.
-        }
-        *result++ = StringType(start, p - start);
-      }
-    }
-    return;
-  }
-
-  string::size_type begin_index, end_index;
-  begin_index = full.find_first_not_of(delim);
-  while (begin_index != string::npos) {
-    end_index = full.find_first_of(delim, begin_index);
-    if (end_index == string::npos) {
-      *result++ = full.substr(begin_index);
-      return;
-    }
-    *result++ = full.substr(begin_index, (end_index - begin_index));
-    begin_index = full.find_first_not_of(delim, end_index);
-  }
-}
-
-void SplitStringUsing(const string& full,
-                      const char* delim,
-                      vector<string>* result) {
-  result->reserve(result->size() + CalculateReserveForVector(full, delim));
-  std::back_insert_iterator<vector<string>> it(*result);
-  SplitStringToIteratorUsing(full, delim, it);
-}
-
-}  // namespace internal
-}  // namespace ceres
diff --git a/third_party/ceres/internal/ceres/split.h b/third_party/ceres/internal/ceres/split.h
deleted file mode 100644
index f513023..0000000
--- a/third_party/ceres/internal/ceres/split.h
+++ /dev/null
@@ -1,52 +0,0 @@
-// Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
-// http://ceres-solver.org/
-//
-// 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 Google Inc. 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.
-//
-// Author: keir@google.com (Keir Mierle)
-
-#ifndef CERES_INTERNAL_SPLIT_H_
-#define CERES_INTERNAL_SPLIT_H_
-
-#include <string>
-#include <vector>
-
-#include "ceres/internal/port.h"
-
-namespace ceres {
-namespace internal {
-
-// Split a string using one or more character delimiters, presented as a
-// nul-terminated c string. Append the components to 'result'. If there are
-// consecutive delimiters, this function skips over all of them.
-void SplitStringUsing(const std::string& full,
-                      const char* delim,
-                      std::vector<std::string>* res);
-
-}  // namespace internal
-}  // namespace ceres
-
-#endif  // CERES_INTERNAL_SPLIT_H_
diff --git a/third_party/ceres/internal/ceres/spmv_benchmark.cc b/third_party/ceres/internal/ceres/spmv_benchmark.cc
new file mode 100644
index 0000000..6a4efa7
--- /dev/null
+++ b/third_party/ceres/internal/ceres/spmv_benchmark.cc
@@ -0,0 +1,445 @@
+// Ceres Solver - A fast non-linear least squares minimizer
+// Copyright 2023 Google Inc. All rights reserved.
+// http://ceres-solver.org/
+//
+// 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 Google Inc. 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.
+//
+// Authors: joydeepb@cs.utexas.edu (Joydeep Biswas)
+
+#include <memory>
+#include <random>
+#include <string>
+
+#include "Eigen/Dense"
+#include "benchmark/benchmark.h"
+#include "ceres/block_jacobi_preconditioner.h"
+#include "ceres/block_sparse_matrix.h"
+#include "ceres/context_impl.h"
+#include "ceres/cuda_sparse_matrix.h"
+#include "ceres/cuda_vector.h"
+#include "ceres/fake_bundle_adjustment_jacobian.h"
+#include "ceres/internal/config.h"
+#include "ceres/internal/eigen.h"
+#include "ceres/linear_solver.h"
+
+#ifndef CERES_NO_CUDA
+#include "cuda_runtime.h"
+#endif
+
+namespace ceres::internal {
+
+constexpr int kNumCameras = 1000;
+constexpr int kNumPoints = 10000;
+constexpr int kCameraSize = 6;
+constexpr int kPointSize = 3;
+constexpr double kVisibility = 0.1;
+
+constexpr int kNumRowBlocks = 100000;
+constexpr int kNumColBlocks = 10000;
+constexpr int kMinRowBlockSize = 1;
+constexpr int kMaxRowBlockSize = 5;
+constexpr int kMinColBlockSize = 1;
+constexpr int kMaxColBlockSize = 15;
+constexpr double kBlockDensity = 5.0 / kNumColBlocks;
+
+static void BM_BlockSparseRightMultiplyAndAccumulateBA(
+    benchmark::State& state) {
+  const int num_threads = static_cast<int>(state.range(0));
+  std::mt19937 prng;
+  auto jacobian = CreateFakeBundleAdjustmentJacobian(
+      kNumCameras, kNumPoints, kCameraSize, kPointSize, kVisibility, prng);
+
+  ContextImpl context;
+  context.EnsureMinimumThreads(num_threads);
+
+  Vector x(jacobian->num_cols());
+  Vector y(jacobian->num_rows());
+  x.setRandom();
+  y.setRandom();
+  double sum = 0;
+  for (auto _ : state) {
+    jacobian->RightMultiplyAndAccumulate(
+        x.data(), y.data(), &context, num_threads);
+    sum += y.norm();
+  }
+  CHECK_NE(sum, 0.0);
+}
+
+BENCHMARK(BM_BlockSparseRightMultiplyAndAccumulateBA)
+    ->Arg(1)
+    ->Arg(2)
+    ->Arg(4)
+    ->Arg(8)
+    ->Arg(16);
+
+static void BM_BlockSparseRightMultiplyAndAccumulateUnstructured(
+    benchmark::State& state) {
+  const int num_threads = static_cast<int>(state.range(0));
+  BlockSparseMatrix::RandomMatrixOptions options;
+  options.num_row_blocks = kNumRowBlocks;
+  options.num_col_blocks = kNumColBlocks;
+  options.min_row_block_size = kMinRowBlockSize;
+  options.min_col_block_size = kMinColBlockSize;
+  options.max_row_block_size = kMaxRowBlockSize;
+  options.max_col_block_size = kMaxColBlockSize;
+  options.block_density = kBlockDensity;
+  std::mt19937 prng;
+
+  auto jacobian = BlockSparseMatrix::CreateRandomMatrix(options, prng);
+
+  ContextImpl context;
+  context.EnsureMinimumThreads(num_threads);
+
+  Vector x(jacobian->num_cols());
+  Vector y(jacobian->num_rows());
+  x.setRandom();
+  y.setRandom();
+  double sum = 0;
+  for (auto _ : state) {
+    jacobian->RightMultiplyAndAccumulate(
+        x.data(), y.data(), &context, num_threads);
+    sum += y.norm();
+  }
+  CHECK_NE(sum, 0.0);
+}
+
+BENCHMARK(BM_BlockSparseRightMultiplyAndAccumulateUnstructured)
+    ->Arg(1)
+    ->Arg(2)
+    ->Arg(4)
+    ->Arg(8)
+    ->Arg(16);
+
+static void BM_BlockSparseLeftMultiplyAndAccumulateBA(benchmark::State& state) {
+  std::mt19937 prng;
+  auto jacobian = CreateFakeBundleAdjustmentJacobian(
+      kNumCameras, kNumPoints, kCameraSize, kPointSize, kVisibility, prng);
+  Vector x(jacobian->num_rows());
+  Vector y(jacobian->num_cols());
+  x.setRandom();
+  y.setRandom();
+  double sum = 0;
+  for (auto _ : state) {
+    jacobian->LeftMultiplyAndAccumulate(x.data(), y.data());
+    sum += y.norm();
+  }
+  CHECK_NE(sum, 0.0);
+}
+
+BENCHMARK(BM_BlockSparseLeftMultiplyAndAccumulateBA);
+
+static void BM_BlockSparseLeftMultiplyAndAccumulateUnstructured(
+    benchmark::State& state) {
+  BlockSparseMatrix::RandomMatrixOptions options;
+  options.num_row_blocks = 100000;
+  options.num_col_blocks = 10000;
+  options.min_row_block_size = 1;
+  options.min_col_block_size = 1;
+  options.max_row_block_size = 10;
+  options.max_col_block_size = 15;
+  options.block_density = 5.0 / options.num_col_blocks;
+  std::mt19937 prng;
+
+  auto jacobian = BlockSparseMatrix::CreateRandomMatrix(options, prng);
+  Vector x(jacobian->num_rows());
+  Vector y(jacobian->num_cols());
+  x.setRandom();
+  y.setRandom();
+  double sum = 0;
+  for (auto _ : state) {
+    jacobian->LeftMultiplyAndAccumulate(x.data(), y.data());
+    sum += y.norm();
+  }
+  CHECK_NE(sum, 0.0);
+}
+
+BENCHMARK(BM_BlockSparseLeftMultiplyAndAccumulateUnstructured);
+
+static void BM_CRSRightMultiplyAndAccumulateBA(benchmark::State& state) {
+  const int num_threads = static_cast<int>(state.range(0));
+  std::mt19937 prng;
+  auto bsm_jacobian = CreateFakeBundleAdjustmentJacobian(
+      kNumCameras, kNumPoints, kCameraSize, kPointSize, kVisibility, prng);
+
+  auto jacobian = bsm_jacobian->ToCompressedRowSparseMatrix();
+
+  ContextImpl context;
+  context.EnsureMinimumThreads(num_threads);
+
+  Vector x(jacobian->num_cols());
+  Vector y(jacobian->num_rows());
+  x.setRandom();
+  y.setRandom();
+  double sum = 0;
+  for (auto _ : state) {
+    jacobian->RightMultiplyAndAccumulate(
+        x.data(), y.data(), &context, num_threads);
+    sum += y.norm();
+  }
+  CHECK_NE(sum, 0.0);
+}
+
+BENCHMARK(BM_CRSRightMultiplyAndAccumulateBA)
+    ->Arg(1)
+    ->Arg(2)
+    ->Arg(4)
+    ->Arg(8)
+    ->Arg(16);
+
+static void BM_CRSRightMultiplyAndAccumulateUnstructured(
+    benchmark::State& state) {
+  const int num_threads = static_cast<int>(state.range(0));
+  BlockSparseMatrix::RandomMatrixOptions options;
+  options.num_row_blocks = kNumRowBlocks;
+  options.num_col_blocks = kNumColBlocks;
+  options.min_row_block_size = kMinRowBlockSize;
+  options.min_col_block_size = kMinColBlockSize;
+  options.max_row_block_size = kMaxRowBlockSize;
+  options.max_col_block_size = kMaxColBlockSize;
+  options.block_density = kBlockDensity;
+  std::mt19937 prng;
+
+  auto bsm_jacobian = BlockSparseMatrix::CreateRandomMatrix(options, prng);
+  auto jacobian = bsm_jacobian->ToCompressedRowSparseMatrix();
+
+  ContextImpl context;
+  context.EnsureMinimumThreads(num_threads);
+
+  Vector x(jacobian->num_cols());
+  Vector y(jacobian->num_rows());
+  x.setRandom();
+  y.setRandom();
+  double sum = 0;
+  for (auto _ : state) {
+    jacobian->RightMultiplyAndAccumulate(
+        x.data(), y.data(), &context, num_threads);
+    sum += y.norm();
+  }
+  CHECK_NE(sum, 0.0);
+}
+
+BENCHMARK(BM_CRSRightMultiplyAndAccumulateUnstructured)
+    ->Arg(1)
+    ->Arg(2)
+    ->Arg(4)
+    ->Arg(8)
+    ->Arg(16);
+
+static void BM_CRSLeftMultiplyAndAccumulateBA(benchmark::State& state) {
+  std::mt19937 prng;
+  // Perform setup here
+  auto bsm_jacobian = CreateFakeBundleAdjustmentJacobian(
+      kNumCameras, kNumPoints, kCameraSize, kPointSize, kVisibility, prng);
+  auto jacobian = bsm_jacobian->ToCompressedRowSparseMatrix();
+
+  Vector x(jacobian->num_rows());
+  Vector y(jacobian->num_cols());
+  x.setRandom();
+  y.setRandom();
+  double sum = 0;
+  for (auto _ : state) {
+    // This code gets timed
+    jacobian->LeftMultiplyAndAccumulate(x.data(), y.data());
+    sum += y.norm();
+  }
+  CHECK_NE(sum, 0.0);
+}
+
+BENCHMARK(BM_CRSLeftMultiplyAndAccumulateBA);
+
+static void BM_CRSLeftMultiplyAndAccumulateUnstructured(
+    benchmark::State& state) {
+  BlockSparseMatrix::RandomMatrixOptions options;
+  options.num_row_blocks = kNumRowBlocks;
+  options.num_col_blocks = kNumColBlocks;
+  options.min_row_block_size = kMinRowBlockSize;
+  options.min_col_block_size = kMinColBlockSize;
+  options.max_row_block_size = kMaxRowBlockSize;
+  options.max_col_block_size = kMaxColBlockSize;
+  options.block_density = kBlockDensity;
+  std::mt19937 prng;
+
+  auto bsm_jacobian = BlockSparseMatrix::CreateRandomMatrix(options, prng);
+  auto jacobian = bsm_jacobian->ToCompressedRowSparseMatrix();
+
+  Vector x(jacobian->num_rows());
+  Vector y(jacobian->num_cols());
+  x.setRandom();
+  y.setRandom();
+  double sum = 0;
+  for (auto _ : state) {
+    // This code gets timed
+    jacobian->LeftMultiplyAndAccumulate(x.data(), y.data());
+    sum += y.norm();
+  }
+  CHECK_NE(sum, 0.0);
+}
+
+BENCHMARK(BM_CRSLeftMultiplyAndAccumulateUnstructured);
+
+#ifndef CERES_NO_CUDA
+static void BM_CudaRightMultiplyAndAccumulateBA(benchmark::State& state) {
+  std::mt19937 prng;
+  auto jacobian = CreateFakeBundleAdjustmentJacobian(
+      kNumCameras, kNumPoints, kCameraSize, kPointSize, kVisibility, prng);
+  ContextImpl context;
+  std::string message;
+  context.InitCuda(&message);
+  auto jacobian_crs = jacobian->ToCompressedRowSparseMatrix();
+  CudaSparseMatrix cuda_jacobian(&context, *jacobian_crs);
+  CudaVector cuda_x(&context, 0);
+  CudaVector cuda_y(&context, 0);
+
+  Vector x(jacobian->num_cols());
+  Vector y(jacobian->num_rows());
+  x.setRandom();
+  y.setRandom();
+
+  cuda_x.CopyFromCpu(x);
+  cuda_y.CopyFromCpu(y);
+  double sum = 0;
+  for (auto _ : state) {
+    cuda_jacobian.RightMultiplyAndAccumulate(cuda_x, &cuda_y);
+    sum += cuda_y.Norm();
+    CHECK_EQ(cudaDeviceSynchronize(), cudaSuccess);
+  }
+  CHECK_NE(sum, 0.0);
+}
+
+BENCHMARK(BM_CudaRightMultiplyAndAccumulateBA);
+
+static void BM_CudaRightMultiplyAndAccumulateUnstructured(
+    benchmark::State& state) {
+  BlockSparseMatrix::RandomMatrixOptions options;
+  options.num_row_blocks = kNumRowBlocks;
+  options.num_col_blocks = kNumColBlocks;
+  options.min_row_block_size = kMinRowBlockSize;
+  options.min_col_block_size = kMinColBlockSize;
+  options.max_row_block_size = kMaxRowBlockSize;
+  options.max_col_block_size = kMaxColBlockSize;
+  options.block_density = kBlockDensity;
+  std::mt19937 prng;
+
+  auto jacobian = BlockSparseMatrix::CreateRandomMatrix(options, prng);
+  ContextImpl context;
+  std::string message;
+  context.InitCuda(&message);
+  auto jacobian_crs = jacobian->ToCompressedRowSparseMatrix();
+  CudaSparseMatrix cuda_jacobian(&context, *jacobian_crs);
+  CudaVector cuda_x(&context, 0);
+  CudaVector cuda_y(&context, 0);
+
+  Vector x(jacobian->num_cols());
+  Vector y(jacobian->num_rows());
+  x.setRandom();
+  y.setRandom();
+
+  cuda_x.CopyFromCpu(x);
+  cuda_y.CopyFromCpu(y);
+  double sum = 0;
+  for (auto _ : state) {
+    cuda_jacobian.RightMultiplyAndAccumulate(cuda_x, &cuda_y);
+    sum += cuda_y.Norm();
+    CHECK_EQ(cudaDeviceSynchronize(), cudaSuccess);
+  }
+  CHECK_NE(sum, 0.0);
+}
+
+BENCHMARK(BM_CudaRightMultiplyAndAccumulateUnstructured);
+
+static void BM_CudaLeftMultiplyAndAccumulateBA(benchmark::State& state) {
+  std::mt19937 prng;
+  auto jacobian = CreateFakeBundleAdjustmentJacobian(
+      kNumCameras, kNumPoints, kCameraSize, kPointSize, kVisibility, prng);
+  ContextImpl context;
+  std::string message;
+  context.InitCuda(&message);
+  auto jacobian_crs = jacobian->ToCompressedRowSparseMatrix();
+  CudaSparseMatrix cuda_jacobian(&context, *jacobian_crs);
+  CudaVector cuda_x(&context, 0);
+  CudaVector cuda_y(&context, 0);
+
+  Vector x(jacobian->num_rows());
+  Vector y(jacobian->num_cols());
+  x.setRandom();
+  y.setRandom();
+
+  cuda_x.CopyFromCpu(x);
+  cuda_y.CopyFromCpu(y);
+  double sum = 0;
+  for (auto _ : state) {
+    cuda_jacobian.LeftMultiplyAndAccumulate(cuda_x, &cuda_y);
+    sum += cuda_y.Norm();
+    CHECK_EQ(cudaDeviceSynchronize(), cudaSuccess);
+  }
+  CHECK_NE(sum, 0.0);
+}
+
+BENCHMARK(BM_CudaLeftMultiplyAndAccumulateBA);
+
+static void BM_CudaLeftMultiplyAndAccumulateUnstructured(
+    benchmark::State& state) {
+  BlockSparseMatrix::RandomMatrixOptions options;
+  options.num_row_blocks = kNumRowBlocks;
+  options.num_col_blocks = kNumColBlocks;
+  options.min_row_block_size = kMinRowBlockSize;
+  options.min_col_block_size = kMinColBlockSize;
+  options.max_row_block_size = kMaxRowBlockSize;
+  options.max_col_block_size = kMaxColBlockSize;
+  options.block_density = kBlockDensity;
+  std::mt19937 prng;
+
+  auto jacobian = BlockSparseMatrix::CreateRandomMatrix(options, prng);
+  ContextImpl context;
+  std::string message;
+  context.InitCuda(&message);
+  auto jacobian_crs = jacobian->ToCompressedRowSparseMatrix();
+  CudaSparseMatrix cuda_jacobian(&context, *jacobian_crs);
+  CudaVector cuda_x(&context, 0);
+  CudaVector cuda_y(&context, 0);
+
+  Vector x(jacobian->num_rows());
+  Vector y(jacobian->num_cols());
+  x.setRandom();
+  y.setRandom();
+
+  cuda_x.CopyFromCpu(x);
+  cuda_y.CopyFromCpu(y);
+  double sum = 0;
+  for (auto _ : state) {
+    cuda_jacobian.LeftMultiplyAndAccumulate(cuda_x, &cuda_y);
+    sum += cuda_y.Norm();
+    CHECK_EQ(cudaDeviceSynchronize(), cudaSuccess);
+  }
+  CHECK_NE(sum, 0.0);
+}
+
+BENCHMARK(BM_CudaLeftMultiplyAndAccumulateUnstructured);
+
+#endif
+
+}  // namespace ceres::internal
+
+BENCHMARK_MAIN();
diff --git a/third_party/ceres/internal/ceres/stl_util.h b/third_party/ceres/internal/ceres/stl_util.h
index d3411b7..d206279 100644
--- a/third_party/ceres/internal/ceres/stl_util.h
+++ b/third_party/ceres/internal/ceres/stl_util.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -59,8 +59,8 @@
 template <class ForwardIterator>
 void STLDeleteUniqueContainerPointers(ForwardIterator begin,
                                       ForwardIterator end) {
-  sort(begin, end);
-  ForwardIterator new_end = unique(begin, end);
+  std::sort(begin, end);
+  ForwardIterator new_end = std::unique(begin, end);
   while (begin != new_end) {
     ForwardIterator temp = begin;
     ++begin;
@@ -73,7 +73,7 @@
 // hash_set, or any other STL container which defines sensible begin(), end(),
 // and clear() methods.
 //
-// If container is NULL, this function is a no-op.
+// If container is nullptr, this function is a no-op.
 //
 // As an alternative to calling STLDeleteElements() directly, consider
 // ElementDeleter (defined below), which ensures that your container's elements
diff --git a/third_party/ceres/internal/ceres/stringprintf.cc b/third_party/ceres/internal/ceres/stringprintf.cc
index b0e2acc..100bbff 100644
--- a/third_party/ceres/internal/ceres/stringprintf.cc
+++ b/third_party/ceres/internal/ceres/stringprintf.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -36,14 +36,11 @@
 #include <string>
 #include <vector>
 
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
-using std::string;
-
-void StringAppendV(string* dst, const char* format, va_list ap) {
+void StringAppendV(std::string* dst, const char* format, va_list ap) {
   // First try with a small fixed size buffer
   char space[1024];
 
@@ -66,7 +63,7 @@
     // Error or MSVC running out of space.  MSVC 8.0 and higher
     // can be asked about space needed with the special idiom below:
     va_copy(backup_ap, ap);
-    result = vsnprintf(NULL, 0, format, backup_ap);
+    result = vsnprintf(nullptr, 0, format, backup_ap);
     va_end(backup_ap);
 #endif
 
@@ -93,16 +90,16 @@
   delete[] buf;
 }
 
-string StringPrintf(const char* format, ...) {
+std::string StringPrintf(const char* format, ...) {
   va_list ap;
   va_start(ap, format);
-  string result;
+  std::string result;
   StringAppendV(&result, format, ap);
   va_end(ap);
   return result;
 }
 
-const string& SStringPrintf(string* dst, const char* format, ...) {
+const std::string& SStringPrintf(std::string* dst, const char* format, ...) {
   va_list ap;
   va_start(ap, format);
   dst->clear();
@@ -111,12 +108,11 @@
   return *dst;
 }
 
-void StringAppendF(string* dst, const char* format, ...) {
+void StringAppendF(std::string* dst, const char* format, ...) {
   va_list ap;
   va_start(ap, format);
   StringAppendV(dst, format, ap);
   va_end(ap);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/stringprintf.h b/third_party/ceres/internal/ceres/stringprintf.h
index 4d51278..f761770 100644
--- a/third_party/ceres/internal/ceres/stringprintf.h
+++ b/third_party/ceres/internal/ceres/stringprintf.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -41,10 +41,10 @@
 #include <cstdarg>
 #include <string>
 
-#include "ceres/internal/port.h"
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 #if (defined(__GNUC__) || defined(__clang__))
 // Tell the compiler to do printf format string checking if the compiler
@@ -63,32 +63,34 @@
 #endif
 
 // Return a C++ string.
-CERES_EXPORT_INTERNAL extern std::string StringPrintf(const char* format, ...)
+CERES_NO_EXPORT extern std::string StringPrintf(const char* format, ...)
     // Tell the compiler to do printf format string checking.
     CERES_PRINTF_ATTRIBUTE(1, 2);
 
 // Store result into a supplied string and return it.
-CERES_EXPORT_INTERNAL extern const std::string& SStringPrintf(
-    std::string* dst, const char* format, ...)
+CERES_NO_EXPORT extern const std::string& SStringPrintf(std::string* dst,
+                                                        const char* format,
+                                                        ...)
     // Tell the compiler to do printf format string checking.
     CERES_PRINTF_ATTRIBUTE(2, 3);
 
 // Append result to a supplied string.
-CERES_EXPORT_INTERNAL extern void StringAppendF(std::string* dst,
-                                                const char* format,
-                                                ...)
+CERES_NO_EXPORT extern void StringAppendF(std::string* dst,
+                                          const char* format,
+                                          ...)
     // Tell the compiler to do printf format string checking.
     CERES_PRINTF_ATTRIBUTE(2, 3);
 
 // Lower-level routine that takes a va_list and appends to a specified string.
 // All other routines are just convenience wrappers around it.
-CERES_EXPORT_INTERNAL extern void StringAppendV(std::string* dst,
-                                                const char* format,
-                                                va_list ap);
+CERES_NO_EXPORT extern void StringAppendV(std::string* dst,
+                                          const char* format,
+                                          va_list ap);
 
 #undef CERES_PRINTF_ATTRIBUTE
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_STRINGPRINTF_H_
diff --git a/third_party/ceres/internal/ceres/subset_preconditioner.cc b/third_party/ceres/internal/ceres/subset_preconditioner.cc
index 779a34a..068f6ce 100644
--- a/third_party/ceres/internal/ceres/subset_preconditioner.cc
+++ b/third_party/ceres/internal/ceres/subset_preconditioner.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -32,6 +32,7 @@
 
 #include <memory>
 #include <string>
+#include <utility>
 
 #include "ceres/compressed_row_sparse_matrix.h"
 #include "ceres/inner_product_computer.h"
@@ -39,25 +40,25 @@
 #include "ceres/sparse_cholesky.h"
 #include "ceres/types.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
-SubsetPreconditioner::SubsetPreconditioner(
-    const Preconditioner::Options& options, const BlockSparseMatrix& A)
-    : options_(options), num_cols_(A.num_cols()) {
+SubsetPreconditioner::SubsetPreconditioner(Preconditioner::Options options,
+                                           const BlockSparseMatrix& A)
+    : options_(std::move(options)), num_cols_(A.num_cols()) {
   CHECK_GE(options_.subset_preconditioner_start_row_block, 0)
       << "Congratulations, you found a bug in Ceres. Please report it.";
 
   LinearSolver::Options sparse_cholesky_options;
   sparse_cholesky_options.sparse_linear_algebra_library_type =
       options_.sparse_linear_algebra_library_type;
-  sparse_cholesky_options.use_postordering = options_.use_postordering;
+  sparse_cholesky_options.ordering_type = options_.ordering_type;
   sparse_cholesky_ = SparseCholesky::Create(sparse_cholesky_options);
 }
 
-SubsetPreconditioner::~SubsetPreconditioner() {}
+SubsetPreconditioner::~SubsetPreconditioner() = default;
 
-void SubsetPreconditioner::RightMultiply(const double* x, double* y) const {
+void SubsetPreconditioner::RightMultiplyAndAccumulate(const double* x,
+                                                      double* y) const {
   CHECK(x != nullptr);
   CHECK(y != nullptr);
   std::string message;
@@ -66,14 +67,14 @@
 
 bool SubsetPreconditioner::UpdateImpl(const BlockSparseMatrix& A,
                                       const double* D) {
-  BlockSparseMatrix* m = const_cast<BlockSparseMatrix*>(&A);
+  auto* m = const_cast<BlockSparseMatrix*>(&A);
   const CompressedRowBlockStructure* bs = m->block_structure();
 
   // A = [P]
   //     [Q]
 
   // Now add D to A if needed.
-  if (D != NULL) {
+  if (D != nullptr) {
     // A = [P]
     //     [Q]
     //     [D]
@@ -82,19 +83,19 @@
     m->AppendRows(*regularizer);
   }
 
-  if (inner_product_computer_.get() == NULL) {
-    inner_product_computer_.reset(InnerProductComputer::Create(
+  if (inner_product_computer_ == nullptr) {
+    inner_product_computer_ = InnerProductComputer::Create(
         *m,
         options_.subset_preconditioner_start_row_block,
         bs->rows.size(),
-        sparse_cholesky_->StorageType()));
+        sparse_cholesky_->StorageType());
   }
 
   // Compute inner_product = [Q'*Q + D'*D]
   inner_product_computer_->Compute();
 
   // Unappend D if needed.
-  if (D != NULL) {
+  if (D != nullptr) {
     // A = [P]
     //     [Q]
     m->DeleteRowBlocks(bs->cols.size());
@@ -105,7 +106,7 @@
   const LinearSolverTerminationType termination_type =
       sparse_cholesky_->Factorize(inner_product_computer_->mutable_result(),
                                   &message);
-  if (termination_type != LINEAR_SOLVER_SUCCESS) {
+  if (termination_type != LinearSolverTerminationType::SUCCESS) {
     LOG(ERROR) << "Preconditioner factorization failed: " << message;
     return false;
   }
@@ -113,5 +114,4 @@
   return true;
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/subset_preconditioner.h b/third_party/ceres/internal/ceres/subset_preconditioner.h
index 9844a66..e179e99 100644
--- a/third_party/ceres/internal/ceres/subset_preconditioner.h
+++ b/third_party/ceres/internal/ceres/subset_preconditioner.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -33,11 +33,11 @@
 
 #include <memory>
 
-#include "ceres/internal/port.h"
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 #include "ceres/preconditioner.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 class BlockSparseMatrix;
 class SparseCholesky;
@@ -67,15 +67,15 @@
 // computationally expensive this preconditioner will be.
 //
 // See the tests for example usage.
-class CERES_EXPORT_INTERNAL SubsetPreconditioner
+class CERES_NO_EXPORT SubsetPreconditioner
     : public BlockSparseMatrixPreconditioner {
  public:
-  SubsetPreconditioner(const Preconditioner::Options& options,
+  SubsetPreconditioner(Preconditioner::Options options,
                        const BlockSparseMatrix& A);
-  virtual ~SubsetPreconditioner();
+  ~SubsetPreconditioner() override;
 
   // Preconditioner interface
-  void RightMultiply(const double* x, double* y) const final;
+  void RightMultiplyAndAccumulate(const double* x, double* y) const final;
   int num_rows() const final { return num_cols_; }
   int num_cols() const final { return num_cols_; }
 
@@ -88,7 +88,8 @@
   std::unique_ptr<InnerProductComputer> inner_product_computer_;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_SUBSET_PRECONDITIONER_H_
diff --git a/third_party/ceres/internal/ceres/subset_preconditioner_test.cc b/third_party/ceres/internal/ceres/subset_preconditioner_test.cc
index 202110b..b73274c 100644
--- a/third_party/ceres/internal/ceres/subset_preconditioner_test.cc
+++ b/third_party/ceres/internal/ceres/subset_preconditioner_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -31,18 +31,19 @@
 #include "ceres/subset_preconditioner.h"
 
 #include <memory>
+#include <random>
 
 #include "Eigen/Dense"
 #include "Eigen/SparseCore"
 #include "ceres/block_sparse_matrix.h"
 #include "ceres/compressed_row_sparse_matrix.h"
 #include "ceres/inner_product_computer.h"
+#include "ceres/internal/config.h"
 #include "ceres/internal/eigen.h"
 #include "glog/logging.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 namespace {
 
@@ -67,7 +68,8 @@
                              Vector* solution) {
   Matrix dense_triangular_lhs;
   lhs.ToDenseMatrix(&dense_triangular_lhs);
-  if (lhs.storage_type() == CompressedRowSparseMatrix::UPPER_TRIANGULAR) {
+  if (lhs.storage_type() ==
+      CompressedRowSparseMatrix::StorageType::UPPER_TRIANGULAR) {
     Matrix full_lhs = dense_triangular_lhs.selfadjointView<Eigen::Upper>();
     return SolveLinearSystemUsingEigen<Eigen::Upper>(full_lhs, rhs, solution);
   }
@@ -75,7 +77,7 @@
       dense_triangular_lhs, rhs, solution);
 }
 
-typedef ::testing::tuple<SparseLinearAlgebraLibraryType, bool> Param;
+using Param = ::testing::tuple<SparseLinearAlgebraLibraryType, bool>;
 
 std::string ParamInfoToString(testing::TestParamInfo<Param> info) {
   Param param = info.param;
@@ -99,28 +101,28 @@
     options.max_row_block_size = 4;
     options.block_density = 0.9;
 
-    m_.reset(BlockSparseMatrix::CreateRandomMatrix(options));
+    m_ = BlockSparseMatrix::CreateRandomMatrix(options, prng_);
     start_row_block_ = m_->block_structure()->rows.size();
 
     // Ensure that the bottom part of the matrix has the same column
     // block structure.
     options.col_blocks = m_->block_structure()->cols;
-    b_.reset(BlockSparseMatrix::CreateRandomMatrix(options));
+    b_ = BlockSparseMatrix::CreateRandomMatrix(options, prng_);
     m_->AppendRows(*b_);
 
     // Create a Identity block diagonal matrix with the same column
     // block structure.
     diagonal_ = Vector::Ones(m_->num_cols());
-    block_diagonal_.reset(BlockSparseMatrix::CreateDiagonalMatrix(
-        diagonal_.data(), b_->block_structure()->cols));
+    block_diagonal_ = BlockSparseMatrix::CreateDiagonalMatrix(
+        diagonal_.data(), b_->block_structure()->cols);
 
     // Unconditionally add the block diagonal to the matrix b_,
     // because either it is either part of b_ to make it full rank, or
     // we pass the same diagonal matrix later as the parameter D. In
     // either case the preconditioner matrix is b_' b + D'D.
     b_->AppendRows(*block_diagonal_);
-    inner_product_computer_.reset(InnerProductComputer::Create(
-        *b_, CompressedRowSparseMatrix::UPPER_TRIANGULAR));
+    inner_product_computer_ = InnerProductComputer::Create(
+        *b_, CompressedRowSparseMatrix::StorageType::UPPER_TRIANGULAR);
     inner_product_computer_->Compute();
   }
 
@@ -131,6 +133,7 @@
   std::unique_ptr<Preconditioner> preconditioner_;
   Vector diagonal_;
   int start_row_block_;
+  std::mt19937 prng_;
 };
 
 TEST_P(SubsetPreconditionerTest, foo) {
@@ -138,7 +141,7 @@
   Preconditioner::Options options;
   options.subset_preconditioner_start_row_block = start_row_block_;
   options.sparse_linear_algebra_library_type = ::testing::get<0>(param);
-  preconditioner_.reset(new SubsetPreconditioner(options, *m_));
+  preconditioner_ = std::make_unique<SubsetPreconditioner>(options, *m_);
 
   const bool with_diagonal = ::testing::get<1>(param);
   if (!with_diagonal) {
@@ -146,7 +149,7 @@
   }
 
   EXPECT_TRUE(
-      preconditioner_->Update(*m_, with_diagonal ? diagonal_.data() : NULL));
+      preconditioner_->Update(*m_, with_diagonal ? diagonal_.data() : nullptr));
 
   // Repeatedly apply the preconditioner to random vectors and check
   // that the preconditioned value is the same as one obtained by
@@ -158,7 +161,7 @@
     EXPECT_TRUE(ComputeExpectedSolution(*lhs, rhs, &expected));
 
     Vector actual(lhs->num_rows());
-    preconditioner_->RightMultiply(rhs.data(), actual.data());
+    preconditioner_->RightMultiplyAndAccumulate(rhs.data(), actual.data());
 
     Matrix eigen_lhs;
     lhs->ToDenseMatrix(&eigen_lhs);
@@ -180,14 +183,6 @@
                          ParamInfoToString);
 #endif
 
-#ifndef CERES_NO_CXSPARSE
-INSTANTIATE_TEST_SUITE_P(SubsetPreconditionerWithCXSparse,
-                         SubsetPreconditionerTest,
-                         ::testing::Combine(::testing::Values(CX_SPARSE),
-                                            ::testing::Values(true, false)),
-                         ParamInfoToString);
-#endif
-
 #ifndef CERES_NO_ACCELERATE_SPARSE
 INSTANTIATE_TEST_SUITE_P(
     SubsetPreconditionerWithAccelerateSparse,
@@ -205,5 +200,4 @@
                          ParamInfoToString);
 #endif
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/suitesparse.cc b/third_party/ceres/internal/ceres/suitesparse.cc
index 0d6f6bd..d93dd8d 100644
--- a/third_party/ceres/internal/ceres/suitesparse.cc
+++ b/third_party/ceres/internal/ceres/suitesparse.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -29,9 +29,12 @@
 // Author: sameeragarwal@google.com (Sameer Agarwal)
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_NO_SUITESPARSE
+
+#include <memory>
+#include <string>
 #include <vector>
 
 #include "ceres/compressed_col_sparse_matrix_utils.h"
@@ -41,11 +44,24 @@
 #include "ceres/triplet_sparse_matrix.h"
 #include "cholmod.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
+namespace {
+int OrderingTypeToCHOLMODEnum(OrderingType ordering_type) {
+  if (ordering_type == OrderingType::AMD) {
+    return CHOLMOD_AMD;
+  }
+  if (ordering_type == OrderingType::NESDIS) {
+    return CHOLMOD_NESDIS;
+  }
 
-using std::string;
-using std::vector;
+  if (ordering_type == OrderingType::NATURAL) {
+    return CHOLMOD_NATURAL;
+  }
+  LOG(FATAL) << "Congratulations you have discovered a bug in Ceres Solver."
+             << "Please report it to the developers. " << ordering_type;
+  return -1;
+}
+}  // namespace
 
 SuiteSparse::SuiteSparse() { cholmod_start(&cc_); }
 
@@ -102,9 +118,11 @@
   m.x = reinterpret_cast<void*>(A->mutable_values());
   m.z = nullptr;
 
-  if (A->storage_type() == CompressedRowSparseMatrix::LOWER_TRIANGULAR) {
+  if (A->storage_type() ==
+      CompressedRowSparseMatrix::StorageType::LOWER_TRIANGULAR) {
     m.stype = 1;
-  } else if (A->storage_type() == CompressedRowSparseMatrix::UPPER_TRIANGULAR) {
+  } else if (A->storage_type() ==
+             CompressedRowSparseMatrix::StorageType::UPPER_TRIANGULAR) {
     m.stype = -1;
   } else {
     m.stype = 0;
@@ -143,19 +161,18 @@
 }
 
 cholmod_factor* SuiteSparse::AnalyzeCholesky(cholmod_sparse* A,
-                                             string* message) {
-  // Cholmod can try multiple re-ordering strategies to find a fill
-  // reducing ordering. Here we just tell it use AMD with automatic
-  // matrix dependence choice of supernodal versus simplicial
-  // factorization.
+                                             OrderingType ordering_type,
+                                             std::string* message) {
   cc_.nmethods = 1;
-  cc_.method[0].ordering = CHOLMOD_AMD;
-  cc_.supernodal = CHOLMOD_AUTO;
+  cc_.method[0].ordering = OrderingTypeToCHOLMODEnum(ordering_type);
+
+  // postordering with a NATURAL ordering leads to a significant regression in
+  // performance. See https://github.com/ceres-solver/ceres-solver/issues/905
+  if (ordering_type == OrderingType::NATURAL) {
+    cc_.postorder = 0;
+  }
 
   cholmod_factor* factor = cholmod_analyze(A, &cc_);
-  if (VLOG_IS_ON(2)) {
-    cholmod_print_common(const_cast<char*>("Symbolic Analysis"), &cc_);
-  }
 
   if (cc_.status != CHOLMOD_OK) {
     *message =
@@ -164,32 +181,22 @@
   }
 
   CHECK(factor != nullptr);
+  if (VLOG_IS_ON(2)) {
+    cholmod_print_common(const_cast<char*>("Symbolic Analysis"), &cc_);
+  }
+
   return factor;
 }
 
-cholmod_factor* SuiteSparse::BlockAnalyzeCholesky(cholmod_sparse* A,
-                                                  const vector<int>& row_blocks,
-                                                  const vector<int>& col_blocks,
-                                                  string* message) {
-  vector<int> ordering;
-  if (!BlockAMDOrdering(A, row_blocks, col_blocks, &ordering)) {
-    return nullptr;
-  }
-  return AnalyzeCholeskyWithUserOrdering(A, ordering, message);
-}
-
-cholmod_factor* SuiteSparse::AnalyzeCholeskyWithUserOrdering(
-    cholmod_sparse* A, const vector<int>& ordering, string* message) {
+cholmod_factor* SuiteSparse::AnalyzeCholeskyWithGivenOrdering(
+    cholmod_sparse* A, const std::vector<int>& ordering, std::string* message) {
   CHECK_EQ(ordering.size(), A->nrow);
 
   cc_.nmethods = 1;
   cc_.method[0].ordering = CHOLMOD_GIVEN;
-
   cholmod_factor* factor =
-      cholmod_analyze_p(A, const_cast<int*>(&ordering[0]), nullptr, 0, &cc_);
-  if (VLOG_IS_ON(2)) {
-    cholmod_print_common(const_cast<char*>("Symbolic Analysis"), &cc_);
-  }
+      cholmod_analyze_p(A, const_cast<int*>(ordering.data()), nullptr, 0, &cc_);
+
   if (cc_.status != CHOLMOD_OK) {
     *message =
         StringPrintf("cholmod_analyze failed. error code: %d", cc_.status);
@@ -197,40 +204,33 @@
   }
 
   CHECK(factor != nullptr);
-  return factor;
-}
-
-cholmod_factor* SuiteSparse::AnalyzeCholeskyWithNaturalOrdering(
-    cholmod_sparse* A, string* message) {
-  cc_.nmethods = 1;
-  cc_.method[0].ordering = CHOLMOD_NATURAL;
-  cc_.postorder = 0;
-
-  cholmod_factor* factor = cholmod_analyze(A, &cc_);
   if (VLOG_IS_ON(2)) {
     cholmod_print_common(const_cast<char*>("Symbolic Analysis"), &cc_);
   }
-  if (cc_.status != CHOLMOD_OK) {
-    *message =
-        StringPrintf("cholmod_analyze failed. error code: %d", cc_.status);
-    return nullptr;
-  }
 
-  CHECK(factor != nullptr);
   return factor;
 }
 
-bool SuiteSparse::BlockAMDOrdering(const cholmod_sparse* A,
-                                   const vector<int>& row_blocks,
-                                   const vector<int>& col_blocks,
-                                   vector<int>* ordering) {
+bool SuiteSparse::BlockOrdering(const cholmod_sparse* A,
+                                OrderingType ordering_type,
+                                const std::vector<Block>& row_blocks,
+                                const std::vector<Block>& col_blocks,
+                                std::vector<int>* ordering) {
+  if (ordering_type == OrderingType::NATURAL) {
+    ordering->resize(A->nrow);
+    for (int i = 0; i < A->nrow; ++i) {
+      (*ordering)[i] = i;
+    }
+    return true;
+  }
+
   const int num_row_blocks = row_blocks.size();
   const int num_col_blocks = col_blocks.size();
 
   // Arrays storing the compressed column structure of the matrix
-  // incoding the block sparsity of A.
-  vector<int> block_cols;
-  vector<int> block_rows;
+  // encoding the block sparsity of A.
+  std::vector<int> block_cols;
+  std::vector<int> block_rows;
 
   CompressedColumnScalarMatrixToBlockMatrix(reinterpret_cast<const int*>(A->i),
                                             reinterpret_cast<const int*>(A->p),
@@ -242,8 +242,8 @@
   block_matrix.nrow = num_row_blocks;
   block_matrix.ncol = num_col_blocks;
   block_matrix.nzmax = block_rows.size();
-  block_matrix.p = reinterpret_cast<void*>(&block_cols[0]);
-  block_matrix.i = reinterpret_cast<void*>(&block_rows[0]);
+  block_matrix.p = reinterpret_cast<void*>(block_cols.data());
+  block_matrix.i = reinterpret_cast<void*>(block_rows.data());
   block_matrix.x = nullptr;
   block_matrix.stype = A->stype;
   block_matrix.itype = CHOLMOD_INT;
@@ -252,8 +252,8 @@
   block_matrix.sorted = 1;
   block_matrix.packed = 1;
 
-  vector<int> block_ordering(num_row_blocks);
-  if (!cholmod_amd(&block_matrix, nullptr, 0, &block_ordering[0], &cc_)) {
+  std::vector<int> block_ordering(num_row_blocks);
+  if (!Ordering(&block_matrix, ordering_type, block_ordering.data())) {
     return false;
   }
 
@@ -261,9 +261,22 @@
   return true;
 }
 
+cholmod_factor* SuiteSparse::BlockAnalyzeCholesky(
+    cholmod_sparse* A,
+    OrderingType ordering_type,
+    const std::vector<Block>& row_blocks,
+    const std::vector<Block>& col_blocks,
+    std::string* message) {
+  std::vector<int> ordering;
+  if (!BlockOrdering(A, ordering_type, row_blocks, col_blocks, &ordering)) {
+    return nullptr;
+  }
+  return AnalyzeCholeskyWithGivenOrdering(A, ordering, message);
+}
+
 LinearSolverTerminationType SuiteSparse::Cholesky(cholmod_sparse* A,
                                                   cholmod_factor* L,
-                                                  string* message) {
+                                                  std::string* message) {
   CHECK(A != nullptr);
   CHECK(L != nullptr);
 
@@ -281,48 +294,48 @@
   switch (cc_.status) {
     case CHOLMOD_NOT_INSTALLED:
       *message = "CHOLMOD failure: Method not installed.";
-      return LINEAR_SOLVER_FATAL_ERROR;
+      return LinearSolverTerminationType::FATAL_ERROR;
     case CHOLMOD_OUT_OF_MEMORY:
       *message = "CHOLMOD failure: Out of memory.";
-      return LINEAR_SOLVER_FATAL_ERROR;
+      return LinearSolverTerminationType::FATAL_ERROR;
     case CHOLMOD_TOO_LARGE:
       *message = "CHOLMOD failure: Integer overflow occurred.";
-      return LINEAR_SOLVER_FATAL_ERROR;
+      return LinearSolverTerminationType::FATAL_ERROR;
     case CHOLMOD_INVALID:
       *message = "CHOLMOD failure: Invalid input.";
-      return LINEAR_SOLVER_FATAL_ERROR;
+      return LinearSolverTerminationType::FATAL_ERROR;
     case CHOLMOD_NOT_POSDEF:
       *message = "CHOLMOD warning: Matrix not positive definite.";
-      return LINEAR_SOLVER_FAILURE;
+      return LinearSolverTerminationType::FAILURE;
     case CHOLMOD_DSMALL:
       *message =
           "CHOLMOD warning: D for LDL' or diag(L) or "
           "LL' has tiny absolute value.";
-      return LINEAR_SOLVER_FAILURE;
+      return LinearSolverTerminationType::FAILURE;
     case CHOLMOD_OK:
       if (cholmod_status != 0) {
-        return LINEAR_SOLVER_SUCCESS;
+        return LinearSolverTerminationType::SUCCESS;
       }
 
       *message =
           "CHOLMOD failure: cholmod_factorize returned false "
           "but cholmod_common::status is CHOLMOD_OK."
           "Please report this to ceres-solver@googlegroups.com.";
-      return LINEAR_SOLVER_FATAL_ERROR;
+      return LinearSolverTerminationType::FATAL_ERROR;
     default:
       *message = StringPrintf(
           "Unknown cholmod return code: %d. "
           "Please report this to ceres-solver@googlegroups.com.",
           cc_.status);
-      return LINEAR_SOLVER_FATAL_ERROR;
+      return LinearSolverTerminationType::FATAL_ERROR;
   }
 
-  return LINEAR_SOLVER_FATAL_ERROR;
+  return LinearSolverTerminationType::FATAL_ERROR;
 }
 
 cholmod_dense* SuiteSparse::Solve(cholmod_factor* L,
                                   cholmod_dense* b,
-                                  string* message) {
+                                  std::string* message) {
   if (cc_.status != CHOLMOD_OK) {
     *message = "cholmod_solve failed. CHOLMOD status is not CHOLMOD_OK";
     return nullptr;
@@ -331,22 +344,34 @@
   return cholmod_solve(CHOLMOD_A, L, b, &cc_);
 }
 
-bool SuiteSparse::ApproximateMinimumDegreeOrdering(cholmod_sparse* matrix,
-                                                   int* ordering) {
-  return cholmod_amd(matrix, nullptr, 0, ordering, &cc_);
+bool SuiteSparse::Ordering(cholmod_sparse* matrix,
+                           OrderingType ordering_type,
+                           int* ordering) {
+  CHECK_NE(ordering_type, OrderingType::NATURAL);
+  if (ordering_type == OrderingType::AMD) {
+    return cholmod_amd(matrix, nullptr, 0, ordering, &cc_);
+  }
+
+#ifdef CERES_NO_CHOLMOD_PARTITION
+  return false;
+#else
+  std::vector<int> CParent(matrix->nrow, 0);
+  std::vector<int> CMember(matrix->nrow, 0);
+  return cholmod_nested_dissection(
+      matrix, nullptr, 0, ordering, CParent.data(), CMember.data(), &cc_);
+#endif
 }
 
 bool SuiteSparse::ConstrainedApproximateMinimumDegreeOrdering(
     cholmod_sparse* matrix, int* constraints, int* ordering) {
-#ifndef CERES_NO_CAMD
   return cholmod_camd(matrix, nullptr, 0, constraints, ordering, &cc_);
-#else
-  LOG(FATAL) << "Congratulations you have found a bug in Ceres."
-             << "Ceres Solver was compiled with SuiteSparse "
-             << "version 4.1.0 or less. Calling this function "
-             << "in that case is a bug. Please contact the"
-             << "the Ceres Solver developers.";
+}
+
+bool SuiteSparse::IsNestedDissectionAvailable() {
+#ifdef CERES_NO_CHOLMOD_PARTITION
   return false;
+#else
+  return true;
 #endif
 }
 
@@ -366,48 +391,61 @@
 }
 
 LinearSolverTerminationType SuiteSparseCholesky::Factorize(
-    CompressedRowSparseMatrix* lhs, string* message) {
+    CompressedRowSparseMatrix* lhs, std::string* message) {
   if (lhs == nullptr) {
-    *message = "Failure: Input lhs is NULL.";
-    return LINEAR_SOLVER_FATAL_ERROR;
+    *message = "Failure: Input lhs is nullptr.";
+    return LinearSolverTerminationType::FATAL_ERROR;
   }
 
   cholmod_sparse cholmod_lhs = ss_.CreateSparseMatrixTransposeView(lhs);
 
+  // If a factorization does not exist, compute the symbolic
+  // factorization first.
+  //
+  // If the ordering type is NATURAL, then there is no fill reducing
+  // ordering to be computed, regardless of block structure, so we can
+  // just call the scalar version of symbolic factorization. For
+  // SuiteSparse this is the common case since we have already
+  // pre-ordered the columns of the Jacobian.
+  //
+  // Similarly regardless of ordering type, if there is no block
+  // structure in the matrix we call the scalar version of symbolic
+  // factorization.
   if (factor_ == nullptr) {
-    if (ordering_type_ == NATURAL) {
-      factor_ = ss_.AnalyzeCholeskyWithNaturalOrdering(&cholmod_lhs, message);
+    if (ordering_type_ == OrderingType::NATURAL ||
+        (lhs->col_blocks().empty() || lhs->row_blocks().empty())) {
+      factor_ = ss_.AnalyzeCholesky(&cholmod_lhs, ordering_type_, message);
     } else {
-      if (!lhs->col_blocks().empty() && !(lhs->row_blocks().empty())) {
-        factor_ = ss_.BlockAnalyzeCholesky(
-            &cholmod_lhs, lhs->col_blocks(), lhs->row_blocks(), message);
-      } else {
-        factor_ = ss_.AnalyzeCholesky(&cholmod_lhs, message);
-      }
-    }
-
-    if (factor_ == nullptr) {
-      return LINEAR_SOLVER_FATAL_ERROR;
+      factor_ = ss_.BlockAnalyzeCholesky(&cholmod_lhs,
+                                         ordering_type_,
+                                         lhs->col_blocks(),
+                                         lhs->row_blocks(),
+                                         message);
     }
   }
 
+  if (factor_ == nullptr) {
+    return LinearSolverTerminationType::FATAL_ERROR;
+  }
+
+  // Compute and return the numeric factorization.
   return ss_.Cholesky(&cholmod_lhs, factor_, message);
 }
 
 CompressedRowSparseMatrix::StorageType SuiteSparseCholesky::StorageType()
     const {
-  return ((ordering_type_ == NATURAL)
-              ? CompressedRowSparseMatrix::UPPER_TRIANGULAR
-              : CompressedRowSparseMatrix::LOWER_TRIANGULAR);
+  return ((ordering_type_ == OrderingType::NATURAL)
+              ? CompressedRowSparseMatrix::StorageType::UPPER_TRIANGULAR
+              : CompressedRowSparseMatrix::StorageType::LOWER_TRIANGULAR);
 }
 
 LinearSolverTerminationType SuiteSparseCholesky::Solve(const double* rhs,
                                                        double* solution,
-                                                       string* message) {
+                                                       std::string* message) {
   // Error checking
   if (factor_ == nullptr) {
     *message = "Solve called without a call to Factorize first.";
-    return LINEAR_SOLVER_FATAL_ERROR;
+    return LinearSolverTerminationType::FATAL_ERROR;
   }
 
   const int num_cols = factor_->n;
@@ -416,15 +454,14 @@
       ss_.Solve(factor_, &cholmod_rhs, message);
 
   if (cholmod_dense_solution == nullptr) {
-    return LINEAR_SOLVER_FAILURE;
+    return LinearSolverTerminationType::FAILURE;
   }
 
   memcpy(solution, cholmod_dense_solution->x, num_cols * sizeof(*solution));
   ss_.Free(cholmod_dense_solution);
-  return LINEAR_SOLVER_SUCCESS;
+  return LinearSolverTerminationType::SUCCESS;
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_NO_SUITESPARSE
diff --git a/third_party/ceres/internal/ceres/suitesparse.h b/third_party/ceres/internal/ceres/suitesparse.h
index 23f539d..703ee87 100644
--- a/third_party/ceres/internal/ceres/suitesparse.h
+++ b/third_party/ceres/internal/ceres/suitesparse.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -34,44 +34,24 @@
 #define CERES_INTERNAL_SUITESPARSE_H_
 
 // This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
+#include "ceres/internal/config.h"
 
 #ifndef CERES_NO_SUITESPARSE
 
 #include <cstring>
+#include <memory>
 #include <string>
 #include <vector>
 
 #include "SuiteSparseQR.hpp"
+#include "ceres/block_structure.h"
+#include "ceres/internal/disable_warnings.h"
 #include "ceres/linear_solver.h"
 #include "ceres/sparse_cholesky.h"
 #include "cholmod.h"
 #include "glog/logging.h"
 
-// Before SuiteSparse version 4.2.0, cholmod_camd was only enabled
-// if SuiteSparse was compiled with Metis support. This makes
-// calling and linking into cholmod_camd problematic even though it
-// has nothing to do with Metis. This has been fixed reliably in
-// 4.2.0.
-//
-// The fix was actually committed in 4.1.0, but there is
-// some confusion about a silent update to the tar ball, so we are
-// being conservative and choosing the next minor version where
-// things are stable.
-#if (SUITESPARSE_VERSION < 4002)
-#define CERES_NO_CAMD
-#endif
-
-// UF_long is deprecated but SuiteSparse_long is only available in
-// newer versions of SuiteSparse. So for older versions of
-// SuiteSparse, we define SuiteSparse_long to be the same as UF_long,
-// which is what recent versions of SuiteSparse do anyways.
-#ifndef SuiteSparse_long
-#define SuiteSparse_long UF_long
-#endif
-
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 class CompressedRowSparseMatrix;
 class TripletSparseMatrix;
@@ -81,14 +61,14 @@
 // provides the user with a simpler interface. The methods here cannot
 // be static as a cholmod_common object serves as a global variable
 // for all cholmod function calls.
-class SuiteSparse {
+class CERES_NO_EXPORT SuiteSparse {
  public:
   SuiteSparse();
   ~SuiteSparse();
 
   // Functions for building cholmod_sparse objects from sparse
   // matrices stored in triplet form. The matrix A is not
-  // modifed. Called owns the result.
+  // modified. Called owns the result.
   cholmod_sparse* CreateSparseMatrix(TripletSparseMatrix* A);
 
   // This function works like CreateSparseMatrix, except that the
@@ -106,7 +86,7 @@
   cholmod_dense CreateDenseVectorView(const double* x, int size);
 
   // Given a vector x, build a cholmod_dense vector of size out_size
-  // with the first in_size entries copied from x. If x is NULL, then
+  // with the first in_size entries copied from x. If x is nullptr, then
   // an all zeros vector is returned. Caller owns the result.
   cholmod_dense* CreateDenseVector(const double* x, int in_size, int out_size);
 
@@ -123,7 +103,7 @@
   // Create and return a matrix m = A * A'. Caller owns the
   // result. The matrix A is not modified.
   cholmod_sparse* AATranspose(cholmod_sparse* A) {
-    cholmod_sparse* m = cholmod_aat(A, NULL, A->nrow, 1, &cc_);
+    cholmod_sparse* m = cholmod_aat(A, nullptr, A->nrow, 1, &cc_);
     m->stype = 1;  // Pay attention to the upper triangular part.
     return m;
   }
@@ -139,12 +119,11 @@
     cholmod_sdmult(A, 0, alpha_, beta_, x, y, &cc_);
   }
 
-  // Find an ordering of A or AA' (if A is unsymmetric) that minimizes
-  // the fill-in in the Cholesky factorization of the corresponding
-  // matrix. This is done by using the AMD algorithm.
-  //
-  // Using this ordering, the symbolic Cholesky factorization of A (or
-  // AA') is computed and returned.
+  // Compute a symbolic factorization for A or AA' (if A is
+  // unsymmetric). If ordering_type is NATURAL, then no fill reducing
+  // ordering is computed, otherwise depending on the value of
+  // ordering_type AMD or Nested Dissection is used to compute a fill
+  // reducing ordering before the symbolic factorization is computed.
   //
   // A is not modified, only the pattern of non-zeros of A is used,
   // the actual numerical values in A are of no consequence.
@@ -152,11 +131,15 @@
   // message contains an explanation of the failures if any.
   //
   // Caller owns the result.
-  cholmod_factor* AnalyzeCholesky(cholmod_sparse* A, std::string* message);
+  cholmod_factor* AnalyzeCholesky(cholmod_sparse* A,
+                                  OrderingType ordering_type,
+                                  std::string* message);
 
+  // Block oriented version of AnalyzeCholesky.
   cholmod_factor* BlockAnalyzeCholesky(cholmod_sparse* A,
-                                       const std::vector<int>& row_blocks,
-                                       const std::vector<int>& col_blocks,
+                                       OrderingType ordering_type,
+                                       const std::vector<Block>& row_blocks,
+                                       const std::vector<Block>& col_blocks,
                                        std::string* message);
 
   // If A is symmetric, then compute the symbolic Cholesky
@@ -170,20 +153,11 @@
   // message contains an explanation of the failures if any.
   //
   // Caller owns the result.
-  cholmod_factor* AnalyzeCholeskyWithUserOrdering(
+  cholmod_factor* AnalyzeCholeskyWithGivenOrdering(
       cholmod_sparse* A,
       const std::vector<int>& ordering,
       std::string* message);
 
-  // Perform a symbolic factorization of A without re-ordering A. No
-  // postordering of the elimination tree is performed. This ensures
-  // that the symbolic factor does not introduce an extra permutation
-  // on the matrix. See the documentation for CHOLMOD for more details.
-  //
-  // message contains an explanation of the failures if any.
-  cholmod_factor* AnalyzeCholeskyWithNaturalOrdering(cholmod_sparse* A,
-                                                     std::string* message);
-
   // Use the symbolic factorization in L, to find the numerical
   // factorization for the matrix A or AA^T. Return true if
   // successful, false otherwise. L contains the numeric factorization
@@ -196,58 +170,46 @@
 
   // Given a Cholesky factorization of a matrix A = LL^T, solve the
   // linear system Ax = b, and return the result. If the Solve fails
-  // NULL is returned. Caller owns the result.
+  // nullptr is returned. Caller owns the result.
   //
   // message contains an explanation of the failures if any.
   cholmod_dense* Solve(cholmod_factor* L,
                        cholmod_dense* b,
                        std::string* message);
 
+  // Find a fill reducing ordering. ordering is expected to be large
+  // enough to hold the ordering. ordering_type must be AMD or NESDIS.
+  bool Ordering(cholmod_sparse* matrix,
+                OrderingType ordering_type,
+                int* ordering);
+
+  // Find the block oriented fill reducing ordering of a matrix A,
+  // whose row and column blocks are given by row_blocks, and
+  // col_blocks respectively. The matrix may or may not be
+  // symmetric. The entries of col_blocks do not need to sum to the
+  // number of columns in A. If this is the case, only the first
+  // sum(col_blocks) are used to compute the ordering.
+  //
   // By virtue of the modeling layer in Ceres being block oriented,
   // all the matrices used by Ceres are also block oriented. When
   // doing sparse direct factorization of these matrices the
-  // fill-reducing ordering algorithms (in particular AMD) can either
-  // be run on the block or the scalar form of these matrices. The two
-  // SuiteSparse::AnalyzeCholesky methods allows the client to
-  // compute the symbolic factorization of a matrix by either using
-  // AMD on the matrix or a user provided ordering of the rows.
-  //
-  // But since the underlying matrices are block oriented, it is worth
-  // running AMD on just the block structure of these matrices and then
-  // lifting these block orderings to a full scalar ordering. This
-  // preserves the block structure of the permuted matrix, and exposes
-  // more of the super-nodal structure of the matrix to the numerical
-  // factorization routines.
-  //
-  // Find the block oriented AMD ordering of a matrix A, whose row and
-  // column blocks are given by row_blocks, and col_blocks
-  // respectively. The matrix may or may not be symmetric. The entries
-  // of col_blocks do not need to sum to the number of columns in
-  // A. If this is the case, only the first sum(col_blocks) are used
-  // to compute the ordering.
-  bool BlockAMDOrdering(const cholmod_sparse* A,
-                        const std::vector<int>& row_blocks,
-                        const std::vector<int>& col_blocks,
-                        std::vector<int>* ordering);
+  // fill-reducing ordering algorithms can either be run on the block
+  // or the scalar form of these matrices. But since the underlying
+  // matrices are block oriented, it is worth running the fill
+  // reducing ordering on just the block structure of these matrices
+  // and then lifting these block orderings to a full scalar
+  // ordering. This preserves the block structure of the permuted
+  // matrix, and exposes more of the super-nodal structure of the
+  // matrix to the numerical factorization routines.
+  bool BlockOrdering(const cholmod_sparse* A,
+                     OrderingType ordering_type,
+                     const std::vector<Block>& row_blocks,
+                     const std::vector<Block>& col_blocks,
+                     std::vector<int>* ordering);
 
-  // Find a fill reducing approximate minimum degree
-  // ordering. ordering is expected to be large enough to hold the
-  // ordering.
-  bool ApproximateMinimumDegreeOrdering(cholmod_sparse* matrix, int* ordering);
-
-  // Before SuiteSparse version 4.2.0, cholmod_camd was only enabled
-  // if SuiteSparse was compiled with Metis support. This makes
-  // calling and linking into cholmod_camd problematic even though it
-  // has nothing to do with Metis. This has been fixed reliably in
-  // 4.2.0.
-  //
-  // The fix was actually committed in 4.1.0, but there is
-  // some confusion about a silent update to the tar ball, so we are
-  // being conservative and choosing the next minor version where
-  // things are stable.
-  static bool IsConstrainedApproximateMinimumDegreeOrderingAvailable() {
-    return (SUITESPARSE_VERSION > 4001);
-  }
+  // Nested dissection is only available if SuiteSparse is compiled
+  // with Metis support.
+  static bool IsNestedDissectionAvailable();
 
   // Find a fill reducing approximate minimum degree
   // ordering. constraints is an array which associates with each
@@ -259,9 +221,6 @@
   // Calling ApproximateMinimumDegreeOrdering is equivalent to calling
   // ConstrainedApproximateMinimumDegreeOrdering with a constraint
   // array that puts all columns in the same elimination group.
-  //
-  // If CERES_NO_CAMD is defined then calling this function will
-  // result in a crash.
   bool ConstrainedApproximateMinimumDegreeOrdering(cholmod_sparse* matrix,
                                                    int* constraints,
                                                    int* ordering);
@@ -288,12 +247,12 @@
   cholmod_common cc_;
 };
 
-class SuiteSparseCholesky : public SparseCholesky {
+class CERES_NO_EXPORT SuiteSparseCholesky final : public SparseCholesky {
  public:
   static std::unique_ptr<SparseCholesky> Create(OrderingType ordering_type);
 
   // SparseCholesky interface.
-  virtual ~SuiteSparseCholesky();
+  ~SuiteSparseCholesky() override;
   CompressedRowSparseMatrix::StorageType StorageType() const final;
   LinearSolverTerminationType Factorize(CompressedRowSparseMatrix* lhs,
                                         std::string* message) final;
@@ -302,42 +261,39 @@
                                     std::string* message) final;
 
  private:
-  SuiteSparseCholesky(const OrderingType ordering_type);
+  explicit SuiteSparseCholesky(const OrderingType ordering_type);
 
   const OrderingType ordering_type_;
   SuiteSparse ss_;
   cholmod_factor* factor_;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #else  // CERES_NO_SUITESPARSE
 
-typedef void cholmod_factor;
+using cholmod_factor = void;
+
+#include "ceres/internal/disable_warnings.h"
 
 namespace ceres {
 namespace internal {
 
-class SuiteSparse {
+class CERES_NO_EXPORT SuiteSparse {
  public:
-  // Defining this static function even when SuiteSparse is not
-  // available, allows client code to check for the presence of CAMD
-  // without checking for the absence of the CERES_NO_CAMD symbol.
-  //
-  // This is safer because the symbol maybe missing due to a user
-  // accidentally not including suitesparse.h in their code when
-  // checking for the symbol.
-  static bool IsConstrainedApproximateMinimumDegreeOrderingAvailable() {
-    return false;
-  }
-
+  // Nested dissection is only available if SuiteSparse is compiled
+  // with Metis support.
+  static bool IsNestedDissectionAvailable() { return false; }
   void Free(void* /*arg*/) {}
 };
 
 }  // namespace internal
 }  // namespace ceres
 
+#include "ceres/internal/reenable_warnings.h"
+
 #endif  // CERES_NO_SUITESPARSE
 
 #endif  // CERES_INTERNAL_SUITESPARSE_H_
diff --git a/third_party/ceres/internal/ceres/system_test.cc b/third_party/ceres/internal/ceres/system_test.cc
index 429973f..6134995 100644
--- a/third_party/ceres/internal/ceres/system_test.cc
+++ b/third_party/ceres/internal/ceres/system_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,6 +35,7 @@
 #include <cstdlib>
 
 #include "ceres/autodiff_cost_function.h"
+#include "ceres/internal/config.h"
 #include "ceres/problem.h"
 #include "ceres/solver.h"
 #include "ceres/test_util.h"
@@ -42,8 +43,7 @@
 #include "glog/logging.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // This class implements the SystemTestProblem interface and provides
 // access to an implementation of Powell's singular function.
@@ -70,13 +70,13 @@
     x_[3] = 1.0;
 
     problem_.AddResidualBlock(
-        new AutoDiffCostFunction<F1, 1, 1, 1>(new F1), NULL, &x_[0], &x_[1]);
+        new AutoDiffCostFunction<F1, 1, 1, 1>(new F1), nullptr, &x_[0], &x_[1]);
     problem_.AddResidualBlock(
-        new AutoDiffCostFunction<F2, 1, 1, 1>(new F2), NULL, &x_[2], &x_[3]);
+        new AutoDiffCostFunction<F2, 1, 1, 1>(new F2), nullptr, &x_[2], &x_[3]);
     problem_.AddResidualBlock(
-        new AutoDiffCostFunction<F3, 1, 1, 1>(new F3), NULL, &x_[1], &x_[2]);
+        new AutoDiffCostFunction<F3, 1, 1, 1>(new F3), nullptr, &x_[1], &x_[2]);
     problem_.AddResidualBlock(
-        new AutoDiffCostFunction<F4, 1, 1, 1>(new F4), NULL, &x_[0], &x_[3]);
+        new AutoDiffCostFunction<F4, 1, 1, 1>(new F4), nullptr, &x_[0], &x_[3]);
 
     // Settings for the reference solution.
     options_.linear_solver_type = ceres::DENSE_QR;
@@ -97,7 +97,7 @@
     template <typename T>
     bool operator()(const T* const x1, const T* const x2, T* residual) const {
       // f1 = x1 + 10 * x2;
-      *residual = *x1 + 10.0 * *x2;
+      *residual = x1[0] + 10.0 * x2[0];
       return true;
     }
   };
@@ -107,7 +107,7 @@
     template <typename T>
     bool operator()(const T* const x3, const T* const x4, T* residual) const {
       // f2 = sqrt(5) (x3 - x4)
-      *residual = sqrt(5.0) * (*x3 - *x4);
+      *residual = sqrt(5.0) * (x3[0] - x4[0]);
       return true;
     }
   };
@@ -115,9 +115,9 @@
   class F3 {
    public:
     template <typename T>
-    bool operator()(const T* const x2, const T* const x4, T* residual) const {
+    bool operator()(const T* const x2, const T* const x3, T* residual) const {
       // f3 = (x2 - 2 x3)^2
-      residual[0] = (x2[0] - 2.0 * x4[0]) * (x2[0] - 2.0 * x4[0]);
+      residual[0] = (x2[0] - 2.0 * x3[0]) * (x2[0] - 2.0 * x3[0]);
       return true;
     }
   };
@@ -139,7 +139,7 @@
 
 double PowellsFunction::kResidualTolerance = 1e-8;
 
-typedef SystemTest<PowellsFunction> PowellTest;
+using PowellTest = SystemTest<PowellsFunction>;
 
 TEST_F(PowellTest, DenseQR) {
   PowellsFunction powells_function;
@@ -186,17 +186,6 @@
 }
 #endif  // CERES_NO_SUITESPARSE
 
-#ifndef CERES_NO_CXSPARSE
-TEST_F(PowellTest, SparseNormalCholeskyUsingCXSparse) {
-  PowellsFunction powells_function;
-  Solver::Options* options = powells_function.mutable_solver_options();
-  options->linear_solver_type = SPARSE_NORMAL_CHOLESKY;
-  options->sparse_linear_algebra_library_type = CX_SPARSE;
-  RunSolverForConfigAndExpectResidualsMatch(*options,
-                                            powells_function.mutable_problem());
-}
-#endif  // CERES_NO_CXSPARSE
-
 #ifndef CERES_NO_ACCELERATE_SPARSE
 TEST_F(PowellTest, SparseNormalCholeskyUsingAccelerateSparse) {
   PowellsFunction powells_function;
@@ -219,5 +208,4 @@
 }
 #endif  // CERES_USE_EIGEN_SPARSE
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/test_util.cc b/third_party/ceres/internal/ceres/test_util.cc
index a131b79..25888a9 100644
--- a/third_party/ceres/internal/ceres/test_util.cc
+++ b/third_party/ceres/internal/ceres/test_util.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -36,6 +36,7 @@
 #include <cmath>
 
 #include "ceres/file.h"
+#include "ceres/internal/port.h"
 #include "ceres/stringprintf.h"
 #include "ceres/types.h"
 #include "gflags/gflags.h"
@@ -134,7 +135,8 @@
 }
 
 std::string TestFileAbsolutePath(const std::string& filename) {
-  return JoinPath(FLAGS_test_srcdir + CERES_TEST_SRCDIR_SUFFIX, filename);
+  return JoinPath(CERES_GET_FLAG(FLAGS_test_srcdir) + CERES_TEST_SRCDIR_SUFFIX,
+                  filename);
 }
 
 std::string ToString(const Solver::Options& options) {
diff --git a/third_party/ceres/internal/ceres/test_util.h b/third_party/ceres/internal/ceres/test_util.h
index c33c69c..95aaa55 100644
--- a/third_party/ceres/internal/ceres/test_util.h
+++ b/third_party/ceres/internal/ceres/test_util.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -33,7 +33,8 @@
 
 #include <string>
 
-#include "ceres/internal/port.h"
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 #include "ceres/problem.h"
 #include "ceres/solver.h"
 #include "ceres/stringprintf.h"
@@ -45,20 +46,19 @@
 // Expects that x and y have a relative difference of no more than
 // max_abs_relative_difference. If either x or y is zero, then the relative
 // difference is interpreted as an absolute difference.
-//
 // If x and y have the same non-finite value (inf or nan) we treat them as being
 // close. In such a case no error is thrown and true is returned.
-CERES_EXPORT_INTERNAL bool ExpectClose(double x,
-                                       double y,
-                                       double max_abs_relative_difference);
+CERES_NO_EXPORT bool ExpectClose(double x,
+                                 double y,
+                                 double max_abs_relative_difference);
 
 // Expects that for all i = 1,.., n - 1
 //
 //   |p[i] - q[i]| / max(|p[i]|, |q[i]|) < tolerance
-CERES_EXPORT_INTERNAL void ExpectArraysClose(int n,
-                                             const double* p,
-                                             const double* q,
-                                             double tolerance);
+CERES_NO_EXPORT void ExpectArraysClose(int n,
+                                       const double* p,
+                                       const double* q,
+                                       double tolerance);
 
 // Expects that for all i = 1,.., n - 1
 //
@@ -66,17 +66,16 @@
 //
 // where max_norm_p and max_norm_q are the max norms of the arrays p
 // and q respectively.
-CERES_EXPORT_INTERNAL void ExpectArraysCloseUptoScale(int n,
-                                                      const double* p,
-                                                      const double* q,
-                                                      double tolerance);
+CERES_NO_EXPORT void ExpectArraysCloseUptoScale(int n,
+                                                const double* p,
+                                                const double* q,
+                                                double tolerance);
 
 // Construct a fully qualified path for the test file depending on the
 // local build/testing environment.
-CERES_EXPORT_INTERNAL std::string TestFileAbsolutePath(
-    const std::string& filename);
+CERES_NO_EXPORT std::string TestFileAbsolutePath(const std::string& filename);
 
-CERES_EXPORT_INTERNAL std::string ToString(const Solver::Options& options);
+CERES_NO_EXPORT std::string ToString(const Solver::Options& options);
 
 // A templated test fixture, that is used for testing Ceres end to end
 // by computing a solution to the problem for a given solver
@@ -85,7 +84,7 @@
 // It is assumed that the SystemTestProblem has an Solver::Options
 // struct that contains the reference Solver configuration.
 template <typename SystemTestProblem>
-class SystemTest : public ::testing::Test {
+class CERES_NO_EXPORT SystemTest : public ::testing::Test {
  protected:
   void SetUp() final {
     SystemTestProblem system_test_problem;
@@ -130,4 +129,6 @@
 }  // namespace internal
 }  // namespace ceres
 
+#include "ceres/internal/reenable_warnings.h"
+
 #endif  // CERES_INTERNAL_TEST_UTIL_H_
diff --git a/third_party/ceres/internal/ceres/thread_pool.cc b/third_party/ceres/internal/ceres/thread_pool.cc
index 821431c..1ce9ac8 100644
--- a/third_party/ceres/internal/ceres/thread_pool.cc
+++ b/third_party/ceres/internal/ceres/thread_pool.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -28,18 +28,14 @@
 //
 // Author: vitus@google.com (Michael Vitus)
 
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifdef CERES_USE_CXX_THREADS
+#include "ceres/thread_pool.h"
 
 #include <cmath>
 #include <limits>
 
-#include "ceres/thread_pool.h"
+#include "ceres/internal/config.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 namespace {
 
 // Constrain the total number of threads to the amount the hardware can support.
@@ -57,7 +53,7 @@
                                    : num_hardware_threads;
 }
 
-ThreadPool::ThreadPool() {}
+ThreadPool::ThreadPool() = default;
 
 ThreadPool::ThreadPool(int num_threads) { Resize(num_threads); }
 
@@ -83,7 +79,7 @@
       GetNumAllowedThreads(num_threads) - num_current_threads;
 
   for (int i = 0; i < create_num_threads; ++i) {
-    thread_pool_.push_back(std::thread(&ThreadPool::ThreadMainLoop, this));
+    thread_pool_.emplace_back(&ThreadPool::ThreadMainLoop, this);
   }
 }
 
@@ -105,7 +101,4 @@
 
 void ThreadPool::Stop() { task_queue_.StopWaiters(); }
 
-}  // namespace internal
-}  // namespace ceres
-
-#endif  // CERES_USE_CXX_THREADS
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/thread_pool.h b/third_party/ceres/internal/ceres/thread_pool.h
index cdf6625..8c8f06f 100644
--- a/third_party/ceres/internal/ceres/thread_pool.h
+++ b/third_party/ceres/internal/ceres/thread_pool.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -37,10 +37,9 @@
 #include <vector>
 
 #include "ceres/concurrent_queue.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // A thread-safe thread pool with an unbounded task queue and a resizable number
 // of workers.  The size of the thread pool can be increased but never decreased
@@ -58,7 +57,7 @@
 //  workers to stop.  The workers will finish all of the tasks that have already
 //  been added to the thread pool.
 //
-class CERES_EXPORT_INTERNAL ThreadPool {
+class CERES_NO_EXPORT ThreadPool {
  public:
   // Returns the maximum number of hardware threads.
   static int MaxNumThreadsAvailable();
@@ -115,7 +114,6 @@
   std::mutex thread_pool_mutex_;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_INTERNAL_THREAD_POOL_H_
diff --git a/third_party/ceres/internal/ceres/thread_pool_test.cc b/third_party/ceres/internal/ceres/thread_pool_test.cc
index e39f673..fa321b0 100644
--- a/third_party/ceres/internal/ceres/thread_pool_test.cc
+++ b/third_party/ceres/internal/ceres/thread_pool_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2018 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -28,23 +28,19 @@
 //
 // Author: vitus@google.com (Michael Vitus)
 
-// This include must come before any #ifndef check on Ceres compile options.
-#include "ceres/internal/port.h"
-
-#ifdef CERES_USE_CXX_THREADS
+#include "ceres/thread_pool.h"
 
 #include <chrono>
 #include <condition_variable>
 #include <mutex>
 #include <thread>
 
-#include "ceres/thread_pool.h"
+#include "ceres/internal/config.h"
 #include "glog/logging.h"
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // Adds a number of tasks to the thread pool and ensures they all run.
 TEST(ThreadPool, AddTask) {
@@ -193,7 +189,4 @@
   EXPECT_EQ(2, thread_pool.Size());
 }
 
-}  // namespace internal
-}  // namespace ceres
-
-#endif  // CERES_USE_CXX_THREADS
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/thread_token_provider.cc b/third_party/ceres/internal/ceres/thread_token_provider.cc
index c7ec67f..6217e2b 100644
--- a/third_party/ceres/internal/ceres/thread_token_provider.cc
+++ b/third_party/ceres/internal/ceres/thread_token_provider.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -30,44 +30,20 @@
 
 #include "ceres/thread_token_provider.h"
 
-#ifdef CERES_USE_OPENMP
-#include <omp.h>
-#endif
-
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 ThreadTokenProvider::ThreadTokenProvider(int num_threads) {
-  (void)num_threads;
-#ifdef CERES_USE_CXX_THREADS
   for (int i = 0; i < num_threads; i++) {
     pool_.Push(i);
   }
-#endif
 }
 
 int ThreadTokenProvider::Acquire() {
-#ifdef CERES_USE_OPENMP
-  return omp_get_thread_num();
-#endif
-
-#ifdef CERES_NO_THREADS
-  return 0;
-#endif
-
-#ifdef CERES_USE_CXX_THREADS
   int thread_id;
   CHECK(pool_.Wait(&thread_id));
   return thread_id;
-#endif
 }
 
-void ThreadTokenProvider::Release(int thread_id) {
-  (void)thread_id;
-#ifdef CERES_USE_CXX_THREADS
-  pool_.Push(thread_id);
-#endif
-}
+void ThreadTokenProvider::Release(int thread_id) { pool_.Push(thread_id); }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/thread_token_provider.h b/third_party/ceres/internal/ceres/thread_token_provider.h
index 06dc043..5d375d1 100644
--- a/third_party/ceres/internal/ceres/thread_token_provider.h
+++ b/third_party/ceres/internal/ceres/thread_token_provider.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -31,15 +31,11 @@
 #ifndef CERES_INTERNAL_THREAD_TOKEN_PROVIDER_H_
 #define CERES_INTERNAL_THREAD_TOKEN_PROVIDER_H_
 
-#include "ceres/internal/config.h"
-#include "ceres/internal/port.h"
-
-#ifdef CERES_USE_CXX_THREADS
 #include "ceres/concurrent_queue.h"
-#endif
+#include "ceres/internal/config.h"
+#include "ceres/internal/export.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // Helper for C++ thread number identification that is similar to
 // omp_get_thread_num() behaviour. This is necessary to support C++
@@ -48,12 +44,6 @@
 // 0 to num_threads - 1 that can be acquired to identify the thread in a thread
 // pool.
 //
-// If CERES_NO_THREADS is defined, Acquire() always returns 0 and Release()
-// takes no action.
-//
-// If CERES_USE_OPENMP, omp_get_thread_num() is used to Acquire() with no action
-// in Release()
-//
 //
 // Example usage pseudocode:
 //
@@ -66,9 +56,9 @@
 //    ttp.Release(token); // return token to the pool
 //  }
 //
-class ThreadTokenProvider {
+class CERES_NO_EXPORT ThreadTokenProvider {
  public:
-  ThreadTokenProvider(int num_threads);
+  explicit ThreadTokenProvider(int num_threads);
 
   // Returns the first token from the queue. The acquired value must be
   // given back by Release().
@@ -78,20 +68,16 @@
   void Release(int thread_id);
 
  private:
-#ifdef CERES_USE_CXX_THREADS
   // This queue initially holds a sequence from 0..num_threads-1. Every
   // Acquire() call the first number is removed from here. When the token is not
   // needed anymore it shall be given back with corresponding Release()
   // call. This concurrent queue is more expensive than TBB's version, so you
   // should not acquire the thread ID on every for loop iteration.
   ConcurrentQueue<int> pool_;
-#endif
-
-  ThreadTokenProvider(ThreadTokenProvider&);
-  ThreadTokenProvider& operator=(ThreadTokenProvider&);
+  ThreadTokenProvider(ThreadTokenProvider&) = delete;
+  ThreadTokenProvider& operator=(ThreadTokenProvider&) = delete;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_INTERNAL_THREAD_TOKEN_PROVIDER_H_
diff --git a/third_party/ceres/internal/ceres/tiny_solver_autodiff_function_test.cc b/third_party/ceres/internal/ceres/tiny_solver_autodiff_function_test.cc
index 2598188..c192cf3 100644
--- a/third_party/ceres/internal/ceres/tiny_solver_autodiff_function_test.cc
+++ b/third_party/ceres/internal/ceres/tiny_solver_autodiff_function_test.cc
@@ -1,6 +1,6 @@
 
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -60,8 +60,8 @@
 static double const kTolerance = std::numeric_limits<double>::epsilon() * 10;
 
 TEST(TinySolverAutoDiffFunction, SimpleFunction) {
-  typedef TinySolverAutoDiffFunction<AutoDiffTestFunctor, 2, 3>
-      AutoDiffTestFunction;
+  using AutoDiffTestFunction =
+      TinySolverAutoDiffFunction<AutoDiffTestFunctor, 2, 3>;
   AutoDiffTestFunctor autodiff_test_functor;
   AutoDiffTestFunction f(autodiff_test_functor);
 
@@ -97,7 +97,7 @@
 
 class DynamicResidualsFunctor {
  public:
-  typedef double Scalar;
+  using Scalar = double;
   enum {
     NUM_RESIDUALS = Eigen::Dynamic,
     NUM_PARAMETERS = 3,
@@ -140,7 +140,7 @@
   EXPECT_GT(residuals.squaredNorm() / 2.0, 1e-10);
 
   TinySolver<AutoDiffCostFunctor> solver;
-  solver.Solve(f, &x0);
+  solver.Solve(f_autodiff, &x0);
   EXPECT_NEAR(0.0, solver.summary.final_cost, 1e-10);
 }
 
diff --git a/third_party/ceres/internal/ceres/tiny_solver_cost_function_adapter_test.cc b/third_party/ceres/internal/ceres/tiny_solver_cost_function_adapter_test.cc
index 6f57193..638d873 100644
--- a/third_party/ceres/internal/ceres/tiny_solver_cost_function_adapter_test.cc
+++ b/third_party/ceres/internal/ceres/tiny_solver_cost_function_adapter_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -68,8 +68,8 @@
 template <int kNumResiduals, int kNumParameters>
 void TestHelper() {
   std::unique_ptr<CostFunction> cost_function(new CostFunction2x3);
-  typedef TinySolverCostFunctionAdapter<kNumResiduals, kNumParameters>
-      CostFunctionAdapter;
+  using CostFunctionAdapter =
+      TinySolverCostFunctionAdapter<kNumResiduals, kNumParameters>;
   CostFunctionAdapter cfa(*cost_function);
   EXPECT_EQ(CostFunctionAdapter::NUM_RESIDUALS, kNumResiduals);
   EXPECT_EQ(CostFunctionAdapter::NUM_PARAMETERS, kNumParameters);
@@ -85,8 +85,8 @@
   double* parameters[1] = {xyz};
 
   // Check that residual only evaluation works.
-  cost_function->Evaluate(parameters, expected_residuals.data(), NULL);
-  cfa(xyz, actual_residuals.data(), NULL);
+  cost_function->Evaluate(parameters, expected_residuals.data(), nullptr);
+  cfa(xyz, actual_residuals.data(), nullptr);
   EXPECT_NEAR(
       (expected_residuals - actual_residuals).norm() / actual_residuals.norm(),
       0.0,
diff --git a/third_party/ceres/internal/ceres/tiny_solver_test.cc b/third_party/ceres/internal/ceres/tiny_solver_test.cc
index 2e70694..645ddc5 100644
--- a/third_party/ceres/internal/ceres/tiny_solver_test.cc
+++ b/third_party/ceres/internal/ceres/tiny_solver_test.cc
@@ -1,6 +1,6 @@
 
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -39,13 +39,13 @@
 
 namespace ceres {
 
-typedef Eigen::Matrix<double, 2, 1> Vec2;
-typedef Eigen::Matrix<double, 3, 1> Vec3;
-typedef Eigen::VectorXd VecX;
+using Vec2 = Eigen::Matrix<double, 2, 1>;
+using Vec3 = Eigen::Matrix<double, 3, 1>;
+using VecX = Eigen::VectorXd;
 
 class ExampleStatic {
  public:
-  typedef double Scalar;
+  using Scalar = double;
   enum {
     // Can also be Eigen::Dynamic.
     NUM_RESIDUALS = 2,
@@ -60,7 +60,7 @@
 
 class ExampleParametersDynamic {
  public:
-  typedef double Scalar;
+  using Scalar = double;
   enum {
     NUM_RESIDUALS = 2,
     NUM_PARAMETERS = Eigen::Dynamic,
@@ -77,7 +77,7 @@
 
 class ExampleResidualsDynamic {
  public:
-  typedef double Scalar;
+  using Scalar = double;
   enum {
     NUM_RESIDUALS = Eigen::Dynamic,
     NUM_PARAMETERS = 3,
@@ -94,7 +94,7 @@
 
 class ExampleAllDynamic {
  public:
-  typedef double Scalar;
+  using Scalar = double;
   enum {
     NUM_RESIDUALS = Eigen::Dynamic,
     NUM_PARAMETERS = Eigen::Dynamic,
@@ -115,7 +115,7 @@
 void TestHelper(const Function& f, const Vector& x0) {
   Vector x = x0;
   Vec2 residuals;
-  f(x.data(), residuals.data(), NULL);
+  f(x.data(), residuals.data(), nullptr);
   EXPECT_GT(residuals.squaredNorm() / 2.0, 1e-10);
 
   TinySolver<Function> solver;
diff --git a/third_party/ceres/internal/ceres/tiny_solver_test_util.h b/third_party/ceres/internal/ceres/tiny_solver_test_util.h
index 310bb35..003df2f 100644
--- a/third_party/ceres/internal/ceres/tiny_solver_test_util.h
+++ b/third_party/ceres/internal/ceres/tiny_solver_test_util.h
@@ -1,6 +1,6 @@
 
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
diff --git a/third_party/ceres/internal/ceres/triplet_sparse_matrix.cc b/third_party/ceres/internal/ceres/triplet_sparse_matrix.cc
index 5dbf0e7..4bb6685 100644
--- a/third_party/ceres/internal/ceres/triplet_sparse_matrix.cc
+++ b/third_party/ceres/internal/ceres/triplet_sparse_matrix.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -31,21 +31,22 @@
 #include "ceres/triplet_sparse_matrix.h"
 
 #include <algorithm>
-#include <cstddef>
+#include <memory>
+#include <random>
 
+#include "ceres/compressed_row_sparse_matrix.h"
+#include "ceres/crs_matrix.h"
 #include "ceres/internal/eigen.h"
-#include "ceres/internal/port.h"
-#include "ceres/random.h"
+#include "ceres/internal/export.h"
 #include "ceres/types.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TripletSparseMatrix::TripletSparseMatrix()
     : num_rows_(0), num_cols_(0), max_num_nonzeros_(0), num_nonzeros_(0) {}
 
-TripletSparseMatrix::~TripletSparseMatrix() {}
+TripletSparseMatrix::~TripletSparseMatrix() = default;
 
 TripletSparseMatrix::TripletSparseMatrix(int num_rows,
                                          int num_cols,
@@ -109,8 +110,9 @@
   for (int i = 0; i < num_nonzeros_; ++i) {
     // clang-format off
     if ((rows_[i] < 0) || (rows_[i] >= num_rows_) ||
-        (cols_[i] < 0) || (cols_[i] >= num_cols_))
+        (cols_[i] < 0) || (cols_[i] >= num_cols_)) {
       return false;
+    }
     // clang-format on
   }
   return true;
@@ -123,9 +125,12 @@
   // Nothing to do if we have enough space already.
   if (new_max_num_nonzeros <= max_num_nonzeros_) return;
 
-  int* new_rows = new int[new_max_num_nonzeros];
-  int* new_cols = new int[new_max_num_nonzeros];
-  double* new_values = new double[new_max_num_nonzeros];
+  std::unique_ptr<int[]> new_rows =
+      std::make_unique<int[]>(new_max_num_nonzeros);
+  std::unique_ptr<int[]> new_cols =
+      std::make_unique<int[]>(new_max_num_nonzeros);
+  std::unique_ptr<double[]> new_values =
+      std::make_unique<double[]>(new_max_num_nonzeros);
 
   for (int i = 0; i < num_nonzeros_; ++i) {
     new_rows[i] = rows_[i];
@@ -133,10 +138,9 @@
     new_values[i] = values_[i];
   }
 
-  rows_.reset(new_rows);
-  cols_.reset(new_cols);
-  values_.reset(new_values);
-
+  rows_ = std::move(new_rows);
+  cols_ = std::move(new_cols);
+  values_ = std::move(new_values);
   max_num_nonzeros_ = new_max_num_nonzeros;
 }
 
@@ -152,9 +156,9 @@
 }
 
 void TripletSparseMatrix::AllocateMemory() {
-  rows_.reset(new int[max_num_nonzeros_]);
-  cols_.reset(new int[max_num_nonzeros_]);
-  values_.reset(new double[max_num_nonzeros_]);
+  rows_ = std::make_unique<int[]>(max_num_nonzeros_);
+  cols_ = std::make_unique<int[]>(max_num_nonzeros_);
+  values_ = std::make_unique<double[]>(max_num_nonzeros_);
 }
 
 void TripletSparseMatrix::CopyData(const TripletSparseMatrix& orig) {
@@ -165,13 +169,15 @@
   }
 }
 
-void TripletSparseMatrix::RightMultiply(const double* x, double* y) const {
+void TripletSparseMatrix::RightMultiplyAndAccumulate(const double* x,
+                                                     double* y) const {
   for (int i = 0; i < num_nonzeros_; ++i) {
     y[rows_[i]] += values_[i] * x[cols_[i]];
   }
 }
 
-void TripletSparseMatrix::LeftMultiply(const double* x, double* y) const {
+void TripletSparseMatrix::LeftMultiplyAndAccumulate(const double* x,
+                                                    double* y) const {
   for (int i = 0; i < num_nonzeros_; ++i) {
     y[cols_[i]] += values_[i] * x[rows_[i]];
   }
@@ -192,6 +198,11 @@
   }
 }
 
+void TripletSparseMatrix::ToCRSMatrix(CRSMatrix* crs_matrix) const {
+  CompressedRowSparseMatrix::FromTripletSparseMatrix(*this)->ToCRSMatrix(
+      crs_matrix);
+}
+
 void TripletSparseMatrix::ToDenseMatrix(Matrix* dense_matrix) const {
   dense_matrix->resize(num_rows_, num_cols_);
   dense_matrix->setZero();
@@ -252,10 +263,11 @@
   num_nonzeros_ -= dropped_terms;
 }
 
-TripletSparseMatrix* TripletSparseMatrix::CreateSparseDiagonalMatrix(
-    const double* values, int num_rows) {
-  TripletSparseMatrix* m =
-      new TripletSparseMatrix(num_rows, num_rows, num_rows);
+std::unique_ptr<TripletSparseMatrix>
+TripletSparseMatrix::CreateSparseDiagonalMatrix(const double* values,
+                                                int num_rows) {
+  std::unique_ptr<TripletSparseMatrix> m =
+      std::make_unique<TripletSparseMatrix>(num_rows, num_rows, num_rows);
   for (int i = 0; i < num_rows; ++i) {
     m->mutable_rows()[i] = i;
     m->mutable_cols()[i] = i;
@@ -272,8 +284,34 @@
   }
 }
 
-TripletSparseMatrix* TripletSparseMatrix::CreateRandomMatrix(
-    const TripletSparseMatrix::RandomMatrixOptions& options) {
+std::unique_ptr<TripletSparseMatrix> TripletSparseMatrix::CreateFromTextFile(
+    FILE* file) {
+  CHECK(file != nullptr);
+  int num_rows = 0;
+  int num_cols = 0;
+  std::vector<int> rows;
+  std::vector<int> cols;
+  std::vector<double> values;
+  while (true) {
+    int row, col;
+    double value;
+    if (fscanf(file, "%d %d %lf", &row, &col, &value) != 3) {
+      break;
+    }
+    rows.push_back(row);
+    cols.push_back(col);
+    values.push_back(value);
+    num_rows = std::max(num_rows, row + 1);
+    num_cols = std::max(num_cols, col + 1);
+  }
+  VLOG(1) << "Read " << rows.size() << " nonzeros from file.";
+  return std::make_unique<TripletSparseMatrix>(
+      num_rows, num_cols, rows, cols, values);
+}
+
+std::unique_ptr<TripletSparseMatrix> TripletSparseMatrix::CreateRandomMatrix(
+    const TripletSparseMatrix::RandomMatrixOptions& options,
+    std::mt19937& prng) {
   CHECK_GT(options.num_rows, 0);
   CHECK_GT(options.num_cols, 0);
   CHECK_GT(options.density, 0.0);
@@ -282,24 +320,25 @@
   std::vector<int> rows;
   std::vector<int> cols;
   std::vector<double> values;
+  std::uniform_real_distribution<double> uniform01(0.0, 1.0);
+  std::normal_distribution<double> standard_normal;
   while (rows.empty()) {
     rows.clear();
     cols.clear();
     values.clear();
     for (int r = 0; r < options.num_rows; ++r) {
       for (int c = 0; c < options.num_cols; ++c) {
-        if (RandDouble() <= options.density) {
+        if (uniform01(prng) <= options.density) {
           rows.push_back(r);
           cols.push_back(c);
-          values.push_back(RandNormal());
+          values.push_back(standard_normal(prng));
         }
       }
     }
   }
 
-  return new TripletSparseMatrix(
+  return std::make_unique<TripletSparseMatrix>(
       options.num_rows, options.num_cols, rows, cols, values);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/triplet_sparse_matrix.h b/third_party/ceres/internal/ceres/triplet_sparse_matrix.h
index cc9fee5..bcb3d2b 100644
--- a/third_party/ceres/internal/ceres/triplet_sparse_matrix.h
+++ b/third_party/ceres/internal/ceres/triplet_sparse_matrix.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -32,21 +32,23 @@
 #define CERES_INTERNAL_TRIPLET_SPARSE_MATRIX_H_
 
 #include <memory>
+#include <random>
 #include <vector>
 
+#include "ceres/crs_matrix.h"
+#include "ceres/internal/disable_warnings.h"
 #include "ceres/internal/eigen.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 #include "ceres/sparse_matrix.h"
 #include "ceres/types.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // An implementation of the SparseMatrix interface to store and
 // manipulate sparse matrices in triplet (i,j,s) form.  This object is
 // inspired by the design of the cholmod_triplet struct used in the
 // SuiteSparse package and is memory layout compatible with it.
-class CERES_EXPORT_INTERNAL TripletSparseMatrix : public SparseMatrix {
+class CERES_NO_EXPORT TripletSparseMatrix final : public SparseMatrix {
  public:
   TripletSparseMatrix();
   TripletSparseMatrix(int num_rows, int num_cols, int max_num_nonzeros);
@@ -56,18 +58,19 @@
                       const std::vector<int>& cols,
                       const std::vector<double>& values);
 
-  explicit TripletSparseMatrix(const TripletSparseMatrix& orig);
+  TripletSparseMatrix(const TripletSparseMatrix& orig);
 
   TripletSparseMatrix& operator=(const TripletSparseMatrix& rhs);
 
-  virtual ~TripletSparseMatrix();
+  ~TripletSparseMatrix() override;
 
   // Implementation of the SparseMatrix interface.
   void SetZero() final;
-  void RightMultiply(const double* x, double* y) const final;
-  void LeftMultiply(const double* x, double* y) const final;
+  void RightMultiplyAndAccumulate(const double* x, double* y) const final;
+  void LeftMultiplyAndAccumulate(const double* x, double* y) const final;
   void SquaredColumnNorm(double* x) const final;
   void ScaleColumns(const double* scale) final;
+  void ToCRSMatrix(CRSMatrix* matrix) const;
   void ToDenseMatrix(Matrix* dense_matrix) const final;
   void ToTextFile(FILE* file) const final;
   // clang-format off
@@ -115,8 +118,8 @@
   // Build a sparse diagonal matrix of size num_rows x num_rows from
   // the array values. Entries of the values array are copied into the
   // sparse matrix.
-  static TripletSparseMatrix* CreateSparseDiagonalMatrix(const double* values,
-                                                         int num_rows);
+  static std::unique_ptr<TripletSparseMatrix> CreateSparseDiagonalMatrix(
+      const double* values, int num_rows);
 
   // Options struct to control the generation of random
   // TripletSparseMatrix objects.
@@ -132,10 +135,12 @@
   // Create a random CompressedRowSparseMatrix whose entries are
   // normally distributed and whose structure is determined by
   // RandomMatrixOptions.
-  //
-  // Caller owns the result.
-  static TripletSparseMatrix* CreateRandomMatrix(
-      const TripletSparseMatrix::RandomMatrixOptions& options);
+  static std::unique_ptr<TripletSparseMatrix> CreateRandomMatrix(
+      const TripletSparseMatrix::RandomMatrixOptions& options,
+      std::mt19937& prng);
+
+  // Load a triplet sparse matrix from a text file.
+  static std::unique_ptr<TripletSparseMatrix> CreateFromTextFile(FILE* file);
 
  private:
   void AllocateMemory();
@@ -155,7 +160,8 @@
   std::unique_ptr<double[]> values_;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_TRIPLET_SPARSE_MATRIX_H__
diff --git a/third_party/ceres/internal/ceres/triplet_sparse_matrix_test.cc b/third_party/ceres/internal/ceres/triplet_sparse_matrix_test.cc
index beee36b..bde9a6e 100644
--- a/third_party/ceres/internal/ceres/triplet_sparse_matrix_test.cc
+++ b/third_party/ceres/internal/ceres/triplet_sparse_matrix_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -32,10 +32,10 @@
 
 #include <memory>
 
+#include "ceres/crs_matrix.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TEST(TripletSparseMatrix, DefaultConstructorReturnsEmptyObject) {
   TripletSparseMatrix m;
@@ -351,5 +351,42 @@
   }
 }
 
-}  // namespace internal
-}  // namespace ceres
+TEST(TripletSparseMatrix, ToCRSMatrix) {
+  // Test matrix:
+  // [1, 2, 0, 5, 6, 0,
+  //  3, 4, 0, 7, 8, 0,
+  //  0, 0, 9, 0, 0, 0]
+  TripletSparseMatrix m(3,
+                        6,
+                        {0, 0, 0, 0, 1, 1, 1, 1, 2},
+                        {0, 1, 3, 4, 0, 1, 3, 4, 2},
+                        {1, 2, 3, 4, 5, 6, 7, 8, 9});
+  CRSMatrix m_crs;
+  m.ToCRSMatrix(&m_crs);
+  EXPECT_EQ(m_crs.num_rows, 3);
+  EXPECT_EQ(m_crs.num_cols, 6);
+
+  EXPECT_EQ(m_crs.rows.size(), 4);
+  EXPECT_EQ(m_crs.rows[0], 0);
+  EXPECT_EQ(m_crs.rows[1], 4);
+  EXPECT_EQ(m_crs.rows[2], 8);
+  EXPECT_EQ(m_crs.rows[3], 9);
+
+  EXPECT_EQ(m_crs.cols.size(), 9);
+  EXPECT_EQ(m_crs.cols[0], 0);
+  EXPECT_EQ(m_crs.cols[1], 1);
+  EXPECT_EQ(m_crs.cols[2], 3);
+  EXPECT_EQ(m_crs.cols[3], 4);
+  EXPECT_EQ(m_crs.cols[4], 0);
+  EXPECT_EQ(m_crs.cols[5], 1);
+  EXPECT_EQ(m_crs.cols[6], 3);
+  EXPECT_EQ(m_crs.cols[7], 4);
+  EXPECT_EQ(m_crs.cols[8], 2);
+
+  EXPECT_EQ(m_crs.values.size(), 9);
+  for (int i = 0; i < 9; ++i) {
+    EXPECT_EQ(m_crs.values[i], i + 1);
+  }
+}
+
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/trust_region_minimizer.cc b/third_party/ceres/internal/ceres/trust_region_minimizer.cc
index bcf05b3..d76f677 100644
--- a/third_party/ceres/internal/ceres/trust_region_minimizer.cc
+++ b/third_party/ceres/internal/ceres/trust_region_minimizer.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2016 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -42,9 +42,11 @@
 #include "Eigen/Core"
 #include "ceres/array_utils.h"
 #include "ceres/coordinate_descent_minimizer.h"
+#include "ceres/eigen_vector_ops.h"
 #include "ceres/evaluator.h"
 #include "ceres/file.h"
 #include "ceres/line_search.h"
+#include "ceres/parallel_for.h"
 #include "ceres/stringprintf.h"
 #include "ceres/types.h"
 #include "ceres/wall_time.h"
@@ -59,10 +61,7 @@
     }                                                            \
   } while (0)
 
-namespace ceres {
-namespace internal {
-
-TrustRegionMinimizer::~TrustRegionMinimizer() {}
+namespace ceres::internal {
 
 void TrustRegionMinimizer::Minimize(const Minimizer::Options& options,
                                     double* parameters,
@@ -75,12 +74,13 @@
   // Create the TrustRegionStepEvaluator. The construction needs to be
   // delayed to this point because we need the cost for the starting
   // point to initialize the step evaluator.
-  step_evaluator_.reset(new TrustRegionStepEvaluator(
+  step_evaluator_ = std::make_unique<TrustRegionStepEvaluator>(
       x_cost_,
       options_.use_nonmonotonic_steps
           ? options_.max_consecutive_nonmonotonic_steps
-          : 0));
+          : 0);
 
+  bool atleast_one_successful_step = false;
   while (FinalizeIterationAndCheckIfMinimizerCanContinue()) {
     iteration_start_time_in_secs_ = WallTimeInSeconds();
 
@@ -108,7 +108,7 @@
     ComputeCandidatePointAndEvaluateCost();
     DoInnerIterationsIfNeeded();
 
-    if (ParameterToleranceReached()) {
+    if (atleast_one_successful_step && ParameterToleranceReached()) {
       return;
     }
 
@@ -117,6 +117,7 @@
     }
 
     if (IsStepSuccessful()) {
+      atleast_one_successful_step = true;
       RETURN_IF_ERROR_AND_LOG(HandleSuccessfulStep());
     } else {
       // Declare the step unsuccessful and inform the trust region strategy.
@@ -139,8 +140,8 @@
                                 double* parameters,
                                 Solver::Summary* solver_summary) {
   options_ = options;
-  sort(options_.trust_region_minimizer_iterations_to_dump.begin(),
-       options_.trust_region_minimizer_iterations_to_dump.end());
+  std::sort(options_.trust_region_minimizer_iterations_to_dump.begin(),
+            options_.trust_region_minimizer_iterations_to_dump.end());
 
   parameters_ = parameters;
 
@@ -168,7 +169,6 @@
   num_consecutive_invalid_steps_ = 0;
 
   x_ = ConstVectorRef(parameters_, num_parameters_);
-  x_norm_ = x_.norm();
   residuals_.resize(num_residuals_);
   trust_region_step_.resize(num_effective_parameters_);
   delta_.resize(num_effective_parameters_);
@@ -182,7 +182,6 @@
   // the Jacobian, we will compute and overwrite this vector.
   jacobian_scaling_ = Vector::Ones(num_effective_parameters_);
 
-  x_norm_ = -1;  // Invalid value
   x_cost_ = std::numeric_limits<double>::max();
   minimum_cost_ = x_cost_;
   model_cost_change_ = 0.0;
@@ -216,10 +215,11 @@
     }
 
     x_ = candidate_x_;
-    x_norm_ = x_.norm();
   }
 
   if (!EvaluateGradientAndJacobian(/*new_evaluation_point=*/true)) {
+    solver_summary_->message =
+        "Initial residual and Jacobian evaluation failed.";
     return false;
   }
 
@@ -272,7 +272,8 @@
     }
 
     // jacobian = jacobian * diag(J'J) ^{-1}
-    jacobian_->ScaleColumns(jacobian_scaling_.data());
+    jacobian_->ScaleColumns(
+        jacobian_scaling_.data(), options_.context, options_.num_threads);
   }
 
   // The gradient exists in the local tangent space. To account for
@@ -359,13 +360,13 @@
 // Compute the trust region step using the TrustRegionStrategy chosen
 // by the user.
 //
-// If the strategy returns with LINEAR_SOLVER_FATAL_ERROR, which
+// If the strategy returns with LinearSolverTerminationType::FATAL_ERROR, which
 // indicates an unrecoverable error, return false. This is the only
 // condition that returns false.
 //
-// If the strategy returns with LINEAR_SOLVER_FAILURE, which indicates
-// a numerical failure that could be recovered from by retrying
-// (e.g. by increasing the strength of the regularization), we set
+// If the strategy returns with LinearSolverTerminationType::FAILURE, which
+// indicates a numerical failure that could be recovered from by retrying (e.g.
+// by increasing the strength of the regularization), we set
 // iteration_summary_.step_is_valid to false and return true.
 //
 // In all other cases, we compute the decrease in the trust region
@@ -379,9 +380,9 @@
   iteration_summary_.step_is_valid = false;
   TrustRegionStrategy::PerSolveOptions per_solve_options;
   per_solve_options.eta = options_.eta;
-  if (find(options_.trust_region_minimizer_iterations_to_dump.begin(),
-           options_.trust_region_minimizer_iterations_to_dump.end(),
-           iteration_summary_.iteration) !=
+  if (std::find(options_.trust_region_minimizer_iterations_to_dump.begin(),
+                options_.trust_region_minimizer_iterations_to_dump.end(),
+                iteration_summary_.iteration) !=
       options_.trust_region_minimizer_iterations_to_dump.end()) {
     per_solve_options.dump_format_type =
         options_.trust_region_problem_dump_format_type;
@@ -397,7 +398,8 @@
                              residuals_.data(),
                              trust_region_step_.data());
 
-  if (strategy_summary.termination_type == LINEAR_SOLVER_FATAL_ERROR) {
+  if (strategy_summary.termination_type ==
+      LinearSolverTerminationType::FATAL_ERROR) {
     solver_summary_->message =
         "Linear solver failed due to unrecoverable "
         "non-numeric causes. Please see the error log for clues. ";
@@ -409,7 +411,8 @@
       WallTimeInSeconds() - strategy_start_time;
   iteration_summary_.linear_solver_iterations = strategy_summary.num_iterations;
 
-  if (strategy_summary.termination_type == LINEAR_SOLVER_FAILURE) {
+  if (strategy_summary.termination_type ==
+      LinearSolverTerminationType::FAILURE) {
     return true;
   }
 
@@ -421,10 +424,15 @@
   //  = f'f/2  - 1/2 [ f'f + 2f'J * step + step' * J' * J * step]
   //  = -f'J * step - step' * J' * J * step / 2
   //  = -(J * step)'(f + J * step / 2)
-  model_residuals_.setZero();
-  jacobian_->RightMultiply(trust_region_step_.data(), model_residuals_.data());
-  model_cost_change_ =
-      -model_residuals_.dot(residuals_ + model_residuals_ / 2.0);
+  ParallelSetZero(options_.context, options_.num_threads, model_residuals_);
+  jacobian_->RightMultiplyAndAccumulate(trust_region_step_.data(),
+                                        model_residuals_.data(),
+                                        options_.context,
+                                        options_.num_threads);
+  model_cost_change_ = -Dot(model_residuals_,
+                            residuals_ + model_residuals_ / 2.0,
+                            options_.context,
+                            options_.num_threads);
 
   // TODO(sameeragarwal)
   //
@@ -434,7 +442,10 @@
   iteration_summary_.step_is_valid = (model_cost_change_ > 0.0);
   if (iteration_summary_.step_is_valid) {
     // Undo the Jacobian column scaling.
-    delta_ = (trust_region_step_.array() * jacobian_scaling_.array()).matrix();
+    ParallelAssign(options_.context,
+                   options_.num_threads,
+                   delta_,
+                   (trust_region_step_.array() * jacobian_scaling_.array()));
     num_consecutive_invalid_steps_ = 0;
   }
 
@@ -704,10 +715,12 @@
 
 // Solver::Options::parameter_tolerance based convergence check.
 bool TrustRegionMinimizer::ParameterToleranceReached() {
+  const double x_norm = x_.norm();
+
   // Compute the norm of the step in the ambient space.
   iteration_summary_.step_norm = (x_ - candidate_x_).norm();
   const double step_size_tolerance =
-      options_.parameter_tolerance * (x_norm_ + options_.parameter_tolerance);
+      options_.parameter_tolerance * (x_norm + options_.parameter_tolerance);
 
   if (iteration_summary_.step_norm > step_size_tolerance) {
     return false;
@@ -716,7 +729,7 @@
   solver_summary_->message = StringPrintf(
       "Parameter tolerance reached. "
       "Relative step_norm: %e <= %e.",
-      (iteration_summary_.step_norm / (x_norm_ + options_.parameter_tolerance)),
+      (iteration_summary_.step_norm / (x_norm + options_.parameter_tolerance)),
       options_.parameter_tolerance);
   solver_summary_->termination_type = CONVERGENCE;
   if (is_not_silent_) {
@@ -750,14 +763,12 @@
 // Compute candidate_x_ = Plus(x_, delta_)
 // Evaluate the cost of candidate_x_ as candidate_cost_.
 //
-// Failure to compute the step or the cost mean that candidate_cost_
-// is set to std::numeric_limits<double>::max(). Unlike
-// EvaluateGradientAndJacobian, failure in this function is not fatal
-// as we are only computing and evaluating a candidate point, and if
-// for some reason we are unable to evaluate it, we consider it to be
-// a point with very high cost. This allows the user to deal with edge
-// cases/constraints as part of the LocalParameterization and
-// CostFunction objects.
+// Failure to compute the step or the cost mean that candidate_cost_ is set to
+// std::numeric_limits<double>::max(). Unlike EvaluateGradientAndJacobian,
+// failure in this function is not fatal as we are only computing and evaluating
+// a candidate point, and if for some reason we are unable to evaluate it, we
+// consider it to be a point with very high cost. This allows the user to deal
+// with edge cases/constraints as part of the Manifold and CostFunction objects.
 void TrustRegionMinimizer::ComputeCandidatePointAndEvaluateCost() {
   if (!evaluator_->Plus(x_.data(), delta_.data(), candidate_x_.data())) {
     if (is_not_silent_) {
@@ -811,7 +822,6 @@
 // evaluator know that the step has been accepted.
 bool TrustRegionMinimizer::HandleSuccessfulStep() {
   x_ = candidate_x_;
-  x_norm_ = x_.norm();
 
   // Since the step was successful, this point has already had the residual
   // evaluated (but not the jacobian). So indicate that to the evaluator.
@@ -825,5 +835,4 @@
   return true;
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/trust_region_minimizer.h b/third_party/ceres/internal/ceres/trust_region_minimizer.h
index be4d406..c9cdac7 100644
--- a/third_party/ceres/internal/ceres/trust_region_minimizer.h
+++ b/third_party/ceres/internal/ceres/trust_region_minimizer.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2016 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -33,8 +33,9 @@
 
 #include <memory>
 
+#include "ceres/internal/disable_warnings.h"
 #include "ceres/internal/eigen.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 #include "ceres/minimizer.h"
 #include "ceres/solver.h"
 #include "ceres/sparse_matrix.h"
@@ -42,16 +43,13 @@
 #include "ceres/trust_region_strategy.h"
 #include "ceres/types.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // Generic trust region minimization algorithm.
 //
 // For example usage, see SolverImpl::Minimize.
-class CERES_EXPORT_INTERNAL TrustRegionMinimizer : public Minimizer {
+class CERES_NO_EXPORT TrustRegionMinimizer final : public Minimizer {
  public:
-  ~TrustRegionMinimizer();
-
   // This method is not thread safe.
   void Minimize(const Minimizer::Options& options,
                 double* parameters,
@@ -140,8 +138,6 @@
   // Scaling vector to scale the columns of the Jacobian.
   Vector jacobian_scaling_;
 
-  // Euclidean norm of x_.
-  double x_norm_;
   // Cost at x_.
   double x_cost_;
   // Minimum cost encountered up till now.
@@ -161,7 +157,8 @@
   int num_consecutive_invalid_steps_;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_TRUST_REGION_MINIMIZER_H_
diff --git a/third_party/ceres/internal/ceres/trust_region_minimizer_test.cc b/third_party/ceres/internal/ceres/trust_region_minimizer_test.cc
index 8993273..94c7162 100644
--- a/third_party/ceres/internal/ceres/trust_region_minimizer_test.cc
+++ b/third_party/ceres/internal/ceres/trust_region_minimizer_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -36,26 +36,26 @@
 #include "ceres/trust_region_minimizer.h"
 
 #include <cmath>
+#include <memory>
 
 #include "ceres/autodiff_cost_function.h"
 #include "ceres/cost_function.h"
 #include "ceres/dense_qr_solver.h"
 #include "ceres/dense_sparse_matrix.h"
 #include "ceres/evaluator.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/export.h"
 #include "ceres/linear_solver.h"
 #include "ceres/minimizer.h"
 #include "ceres/problem.h"
 #include "ceres/trust_region_strategy.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // Templated Evaluator for Powell's function. The template parameters
 // indicate which of the four variables/columns of the jacobian are
 // active. This is equivalent to constructing a problem and using the
-// SubsetLocalParameterization. This allows us to test the support for
+// SubsetManifold. This allows us to test the support for
 // the Evaluator::Plus operation besides checking for the basic
 // performance of the trust region algorithm.
 template <bool col1, bool col2, bool col3, bool col4>
@@ -76,13 +76,11 @@
   }
   // clang-format on
 
-  virtual ~PowellEvaluator2() {}
-
   // Implementation of Evaluator interface.
-  SparseMatrix* CreateJacobian() const final {
+  std::unique_ptr<SparseMatrix> CreateJacobian() const final {
     CHECK(col1 || col2 || col3 || col4);
-    DenseSparseMatrix* dense_jacobian =
-        new DenseSparseMatrix(NumResiduals(), NumEffectiveParameters());
+    auto dense_jacobian = std::make_unique<DenseSparseMatrix>(
+        NumResiduals(), NumEffectiveParameters());
     dense_jacobian->SetZero();
     return dense_jacobian;
   }
@@ -119,19 +117,19 @@
 
     VLOG(1) << "Cost: " << *cost;
 
-    if (residuals != NULL) {
+    if (residuals != nullptr) {
       residuals[0] = f1;
       residuals[1] = f2;
       residuals[2] = f3;
       residuals[3] = f4;
     }
 
-    if (jacobian != NULL) {
+    if (jacobian != nullptr) {
       DenseSparseMatrix* dense_jacobian;
       dense_jacobian = down_cast<DenseSparseMatrix*>(jacobian);
       dense_jacobian->SetZero();
 
-      ColMajorMatrixRef jacobian_matrix = dense_jacobian->mutable_matrix();
+      Matrix& jacobian_matrix = *(dense_jacobian->mutable_matrix());
       CHECK_EQ(jacobian_matrix.cols(), num_active_cols_);
 
       int column_index = 0;
@@ -141,7 +139,7 @@
             1.0,
             0.0,
             0.0,
-            sqrt(10.0) * 2.0 * (x1 - x4) * (1.0 - x4);
+            sqrt(10.0) * 2.0 * (x1 - x4);
         // clang-format on
       }
       if (col2) {
@@ -149,7 +147,7 @@
         jacobian_matrix.col(column_index++) <<
             10.0,
             0.0,
-            2.0*(x2 - 2.0*x3)*(1.0 - 2.0*x3),
+            2.0*(x2 - 2.0*x3),
             0.0;
         // clang-format on
       }
@@ -159,7 +157,7 @@
         jacobian_matrix.col(column_index++) <<
             0.0,
             sqrt(5.0),
-            2.0*(x2 - 2.0*x3)*(x2 - 2.0),
+            4.0*(2.0*x3 - x2),
             0.0;
         // clang-format on
       }
@@ -170,13 +168,13 @@
             0.0,
             -sqrt(5.0),
             0.0,
-            sqrt(10.0) * 2.0 * (x1 - x4) * (x1 - 1.0);
+            sqrt(10.0) * 2.0 * (x4 - x1);
         // clang-format on
       }
       VLOG(1) << "\n" << jacobian_matrix;
     }
 
-    if (gradient != NULL) {
+    if (gradient != nullptr) {
       int column_index = 0;
       if (col1) {
         gradient[column_index++] = f1 + f4 * sqrt(10.0) * 2.0 * (x1 - x4);
@@ -188,7 +186,7 @@
 
       if (col3) {
         gradient[column_index++] =
-            f2 * sqrt(5.0) + f3 * (2.0 * 2.0 * (2.0 * x3 - x2));
+            f2 * sqrt(5.0) + f3 * (4.0 * (2.0 * x3 - x2));
       }
 
       if (col4) {
@@ -240,10 +238,9 @@
   minimizer_options.gradient_tolerance = 1e-26;
   minimizer_options.function_tolerance = 1e-26;
   minimizer_options.parameter_tolerance = 1e-26;
-  minimizer_options.evaluator.reset(
-      new PowellEvaluator2<col1, col2, col3, col4>);
-  minimizer_options.jacobian.reset(
-      minimizer_options.evaluator->CreateJacobian());
+  minimizer_options.evaluator =
+      std::make_unique<PowellEvaluator2<col1, col2, col3, col4>>();
+  minimizer_options.jacobian = minimizer_options.evaluator->CreateJacobian();
 
   TrustRegionStrategy::Options trust_region_strategy_options;
   trust_region_strategy_options.trust_region_strategy_type = strategy_type;
@@ -252,8 +249,8 @@
   trust_region_strategy_options.max_radius = 1e20;
   trust_region_strategy_options.min_lm_diagonal = 1e-6;
   trust_region_strategy_options.max_lm_diagonal = 1e32;
-  minimizer_options.trust_region_strategy.reset(
-      TrustRegionStrategy::Create(trust_region_strategy_options));
+  minimizer_options.trust_region_strategy =
+      TrustRegionStrategy::Create(trust_region_strategy_options);
 
   TrustRegionMinimizer minimizer;
   Solver::Summary summary;
@@ -330,7 +327,7 @@
 
   bool Evaluate(double const* const* parameters,
                 double* residuals,
-                double** jacobians) const {
+                double** jacobians) const override {
     residuals[0] = target_length_;
 
     for (int i = 0; i < num_vertices_; ++i) {
@@ -343,12 +340,12 @@
       residuals[0] -= sqrt(length);
     }
 
-    if (jacobians == NULL) {
+    if (jacobians == nullptr) {
       return true;
     }
 
     for (int i = 0; i < num_vertices_; ++i) {
-      if (jacobians[i] != NULL) {
+      if (jacobians[i] != nullptr) {
         int prev = (num_vertices_ + i - 1) % num_vertices_;
         int next = (i + 1) % num_vertices_;
 
@@ -398,7 +395,7 @@
   }
 
   Problem problem;
-  problem.AddResidualBlock(new CurveCostFunction(N, 10.), NULL, y);
+  problem.AddResidualBlock(new CurveCostFunction(N, 10.), nullptr, y);
   Solver::Options options;
   options.linear_solver_type = ceres::DENSE_QR;
   Solver::Summary summary;
@@ -425,7 +422,7 @@
 TEST(TrustRegionMinimizer, GradientToleranceConvergenceUpdatesStep) {
   double x = 5;
   Problem problem;
-  problem.AddResidualBlock(ExpCostFunctor::Create(), NULL, &x);
+  problem.AddResidualBlock(ExpCostFunctor::Create(), nullptr, &x);
   problem.SetParameterLowerBound(&x, 0, 3.0);
   Solver::Options options;
   Solver::Summary summary;
@@ -435,5 +432,4 @@
   EXPECT_NEAR(expected_final_cost, summary.final_cost, 1e-12);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/trust_region_preprocessor.cc b/third_party/ceres/internal/ceres/trust_region_preprocessor.cc
index 0943edb..e07e369 100644
--- a/third_party/ceres/internal/ceres/trust_region_preprocessor.cc
+++ b/third_party/ceres/internal/ceres/trust_region_preprocessor.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -32,6 +32,7 @@
 
 #include <numeric>
 #include <string>
+#include <vector>
 
 #include "ceres/callbacks.h"
 #include "ceres/context_impl.h"
@@ -48,20 +49,19 @@
 #include "ceres/trust_region_strategy.h"
 #include "ceres/wall_time.h"
 
-namespace ceres {
-namespace internal {
-
-using std::vector;
+namespace ceres::internal {
 
 namespace {
 
-ParameterBlockOrdering* CreateDefaultLinearSolverOrdering(
+std::shared_ptr<ParameterBlockOrdering> CreateDefaultLinearSolverOrdering(
     const Program& program) {
-  ParameterBlockOrdering* ordering = new ParameterBlockOrdering;
-  const vector<ParameterBlock*>& parameter_blocks = program.parameter_blocks();
-  for (int i = 0; i < parameter_blocks.size(); ++i) {
+  std::shared_ptr<ParameterBlockOrdering> ordering =
+      std::make_shared<ParameterBlockOrdering>();
+  const std::vector<ParameterBlock*>& parameter_blocks =
+      program.parameter_blocks();
+  for (auto* parameter_block : parameter_blocks) {
     ordering->AddElementToGroup(
-        const_cast<double*>(parameter_blocks[i]->user_state()), 0);
+        const_cast<double*>(parameter_block->user_state()), 0);
   }
   return ordering;
 }
@@ -113,6 +113,7 @@
     return ReorderProgramForSchurTypeLinearSolver(
         options.linear_solver_type,
         options.sparse_linear_algebra_library_type,
+        options.linear_solver_ordering_type,
         pp->problem->parameter_map(),
         options.linear_solver_ordering.get(),
         pp->reduced_program.get(),
@@ -123,6 +124,7 @@
       !options.dynamic_sparsity) {
     return ReorderProgramForSparseCholesky(
         options.sparse_linear_algebra_library_type,
+        options.linear_solver_ordering_type,
         *options.linear_solver_ordering,
         0, /* use all the rows of the jacobian */
         pp->reduced_program.get(),
@@ -138,6 +140,7 @@
 
     return ReorderProgramForSparseCholesky(
         options.sparse_linear_algebra_library_type,
+        options.linear_solver_ordering_type,
         *options.linear_solver_ordering,
         pp->linear_solver_options.subset_preconditioner_start_row_block,
         pp->reduced_program.get(),
@@ -160,8 +163,8 @@
     // assume that they are giving all the freedom to us in choosing
     // the best possible ordering. This intent can be indicated by
     // putting all the parameter blocks in the same elimination group.
-    options.linear_solver_ordering.reset(
-        CreateDefaultLinearSolverOrdering(*pp->reduced_program));
+    options.linear_solver_ordering =
+        CreateDefaultLinearSolverOrdering(*pp->reduced_program);
   } else {
     // If the user supplied an ordering, then check if the first
     // elimination group is still non-empty after the reduced problem
@@ -196,10 +199,16 @@
       options.max_linear_solver_iterations;
   pp->linear_solver_options.type = options.linear_solver_type;
   pp->linear_solver_options.preconditioner_type = options.preconditioner_type;
+  pp->linear_solver_options.use_spse_initialization =
+      options.use_spse_initialization;
+  pp->linear_solver_options.spse_tolerance = options.spse_tolerance;
+  pp->linear_solver_options.max_num_spse_iterations =
+      options.max_num_spse_iterations;
   pp->linear_solver_options.visibility_clustering_type =
       options.visibility_clustering_type;
   pp->linear_solver_options.sparse_linear_algebra_library_type =
       options.sparse_linear_algebra_library_type;
+
   pp->linear_solver_options.dense_linear_algebra_library_type =
       options.dense_linear_algebra_library_type;
   pp->linear_solver_options.use_explicit_schur_complement =
@@ -210,7 +219,6 @@
   pp->linear_solver_options.max_num_refinement_iterations =
       options.max_num_refinement_iterations;
   pp->linear_solver_options.num_threads = options.num_threads;
-  pp->linear_solver_options.use_postordering = options.use_postordering;
   pp->linear_solver_options.context = pp->problem->context();
 
   if (IsSchurType(pp->linear_solver_options.type)) {
@@ -224,30 +232,27 @@
     if (pp->linear_solver_options.elimination_groups.size() == 1) {
       pp->linear_solver_options.elimination_groups.push_back(0);
     }
+  }
 
-    if (options.linear_solver_type == SPARSE_SCHUR) {
-      // When using SPARSE_SCHUR, we ignore the user's postordering
-      // preferences in certain cases.
-      //
-      // 1. SUITE_SPARSE is the sparse linear algebra library requested
-      //    but cholmod_camd is not available.
-      // 2. CX_SPARSE is the sparse linear algebra library requested.
-      //
-      // This ensures that the linear solver does not assume that a
-      // fill-reducing pre-ordering has been done.
-      //
-      // TODO(sameeragarwal): Implement the reordering of parameter
-      // blocks for CX_SPARSE.
-      if ((options.sparse_linear_algebra_library_type == SUITE_SPARSE &&
-           !SuiteSparse::
-               IsConstrainedApproximateMinimumDegreeOrderingAvailable()) ||
-          (options.sparse_linear_algebra_library_type == CX_SPARSE)) {
-        pp->linear_solver_options.use_postordering = true;
-      }
+  if (!options.dynamic_sparsity &&
+      AreJacobianColumnsOrdered(options.linear_solver_type,
+                                options.preconditioner_type,
+                                options.sparse_linear_algebra_library_type,
+                                options.linear_solver_ordering_type)) {
+    pp->linear_solver_options.ordering_type = OrderingType::NATURAL;
+  } else {
+    if (options.linear_solver_ordering_type == ceres::AMD) {
+      pp->linear_solver_options.ordering_type = OrderingType::AMD;
+    } else if (options.linear_solver_ordering_type == ceres::NESDIS) {
+      pp->linear_solver_options.ordering_type = OrderingType::NESDIS;
+    } else {
+      LOG(FATAL) << "Congratulations you have found a bug in Ceres Solver."
+                 << " Please report this to the maintainers. : "
+                 << options.linear_solver_ordering_type;
     }
   }
 
-  pp->linear_solver.reset(LinearSolver::Create(pp->linear_solver_options));
+  pp->linear_solver = LinearSolver::Create(pp->linear_solver_options);
   return (pp->linear_solver != nullptr);
 }
 
@@ -256,6 +261,8 @@
   const Solver::Options& options = pp->options;
   pp->evaluator_options = Evaluator::Options();
   pp->evaluator_options.linear_solver_type = options.linear_solver_type;
+  pp->evaluator_options.sparse_linear_algebra_library_type =
+      options.sparse_linear_algebra_library_type;
   pp->evaluator_options.num_eliminate_blocks = 0;
   if (IsSchurType(options.linear_solver_type)) {
     pp->evaluator_options.num_eliminate_blocks =
@@ -269,8 +276,8 @@
   pp->evaluator_options.context = pp->problem->context();
   pp->evaluator_options.evaluation_callback =
       pp->reduced_program->mutable_evaluation_callback();
-  pp->evaluator.reset(Evaluator::Create(
-      pp->evaluator_options, pp->reduced_program.get(), &pp->error));
+  pp->evaluator = Evaluator::Create(
+      pp->evaluator_options, pp->reduced_program.get(), &pp->error);
 
   return (pp->evaluator != nullptr);
 }
@@ -316,12 +323,12 @@
     }
   } else {
     // The user did not supply an ordering, so create one.
-    options.inner_iteration_ordering.reset(
-        CoordinateDescentMinimizer::CreateOrdering(*pp->reduced_program));
+    options.inner_iteration_ordering =
+        CoordinateDescentMinimizer::CreateOrdering(*pp->reduced_program);
   }
 
-  pp->inner_iteration_minimizer.reset(
-      new CoordinateDescentMinimizer(pp->problem->context()));
+  pp->inner_iteration_minimizer =
+      std::make_unique<CoordinateDescentMinimizer>(pp->problem->context());
   return pp->inner_iteration_minimizer->Init(*pp->reduced_program,
                                              pp->problem->parameter_map(),
                                              *options.inner_iteration_ordering,
@@ -329,13 +336,19 @@
 }
 
 // Configure and create a TrustRegionMinimizer object.
-void SetupMinimizerOptions(PreprocessedProblem* pp) {
+bool SetupMinimizerOptions(PreprocessedProblem* pp) {
   const Solver::Options& options = pp->options;
 
   SetupCommonMinimizerOptions(pp);
   pp->minimizer_options.is_constrained =
       pp->reduced_program->IsBoundsConstrained();
-  pp->minimizer_options.jacobian.reset(pp->evaluator->CreateJacobian());
+  pp->minimizer_options.jacobian = pp->evaluator->CreateJacobian();
+  if (pp->minimizer_options.jacobian == nullptr) {
+    pp->error =
+        "Unable to create Jacobian matrix. Likely because it is too large.";
+    return false;
+  }
+
   pp->minimizer_options.inner_iteration_minimizer =
       pp->inner_iteration_minimizer;
 
@@ -348,15 +361,16 @@
   strategy_options.trust_region_strategy_type =
       options.trust_region_strategy_type;
   strategy_options.dogleg_type = options.dogleg_type;
-  pp->minimizer_options.trust_region_strategy.reset(
-      TrustRegionStrategy::Create(strategy_options));
+  strategy_options.context = pp->problem->context();
+  strategy_options.num_threads = options.num_threads;
+  pp->minimizer_options.trust_region_strategy =
+      TrustRegionStrategy::Create(strategy_options);
   CHECK(pp->minimizer_options.trust_region_strategy != nullptr);
+  return true;
 }
 
 }  // namespace
 
-TrustRegionPreprocessor::~TrustRegionPreprocessor() {}
-
 bool TrustRegionPreprocessor::Preprocess(const Solver::Options& options,
                                          ProblemImpl* problem,
                                          PreprocessedProblem* pp) {
@@ -370,10 +384,10 @@
     return false;
   }
 
-  pp->reduced_program.reset(program->CreateReducedProgram(
-      &pp->removed_parameter_blocks, &pp->fixed_cost, &pp->error));
+  pp->reduced_program = program->CreateReducedProgram(
+      &pp->removed_parameter_blocks, &pp->fixed_cost, &pp->error);
 
-  if (pp->reduced_program.get() == NULL) {
+  if (pp->reduced_program.get() == nullptr) {
     return false;
   }
 
@@ -388,9 +402,7 @@
     return false;
   }
 
-  SetupMinimizerOptions(pp);
-  return true;
+  return SetupMinimizerOptions(pp);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/trust_region_preprocessor.h b/third_party/ceres/internal/ceres/trust_region_preprocessor.h
index 2655abe..14febda 100644
--- a/third_party/ceres/internal/ceres/trust_region_preprocessor.h
+++ b/third_party/ceres/internal/ceres/trust_region_preprocessor.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -31,21 +31,21 @@
 #ifndef CERES_INTERNAL_TRUST_REGION_PREPROCESSOR_H_
 #define CERES_INTERNAL_TRUST_REGION_PREPROCESSOR_H_
 
-#include "ceres/internal/port.h"
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 #include "ceres/preprocessor.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
-class CERES_EXPORT_INTERNAL TrustRegionPreprocessor : public Preprocessor {
+class CERES_NO_EXPORT TrustRegionPreprocessor final : public Preprocessor {
  public:
-  virtual ~TrustRegionPreprocessor();
   bool Preprocess(const Solver::Options& options,
                   ProblemImpl* problem,
                   PreprocessedProblem* preprocessed_problem) override;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_TRUST_REGION_PREPROCESSOR_H_
diff --git a/third_party/ceres/internal/ceres/trust_region_preprocessor_test.cc b/third_party/ceres/internal/ceres/trust_region_preprocessor_test.cc
index a2a9523..2579361 100644
--- a/third_party/ceres/internal/ceres/trust_region_preprocessor_test.cc
+++ b/third_party/ceres/internal/ceres/trust_region_preprocessor_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -33,6 +33,7 @@
 #include <array>
 #include <map>
 
+#include "ceres/internal/config.h"
 #include "ceres/ordered_groups.h"
 #include "ceres/problem_impl.h"
 #include "ceres/sized_cost_function.h"
@@ -72,7 +73,7 @@
   EXPECT_FALSE(preprocessor.Preprocess(options, &problem, &pp));
 }
 
-TEST(TrustRegionPreprocessor, ParamterBlockIsInfeasible) {
+TEST(TrustRegionPreprocessor, ParameterBlockIsInfeasible) {
   ProblemImpl problem;
   double x = 3.0;
   problem.AddParameterBlock(&x, 1);
@@ -89,7 +90,7 @@
  public:
   bool Evaluate(double const* const* parameters,
                 double* residuals,
-                double** jacobians) const {
+                double** jacobians) const override {
     return false;
   }
 };
@@ -120,7 +121,7 @@
  public:
   bool Evaluate(double const* const* parameters,
                 double* residuals,
-                double** jacobians) const {
+                double** jacobians) const override {
     for (int i = 0; i < kNumResiduals; ++i) {
       residuals[i] = kNumResiduals * kNumResiduals + i;
     }
@@ -225,7 +226,7 @@
 TEST_F(LinearSolverAndEvaluatorCreationTest, SchurTypeSolverWithBadOrdering) {
   Solver::Options options;
   options.linear_solver_type = DENSE_SCHUR;
-  options.linear_solver_ordering.reset(new ParameterBlockOrdering);
+  options.linear_solver_ordering = std::make_shared<ParameterBlockOrdering>();
   options.linear_solver_ordering->AddElementToGroup(&x_, 0);
   options.linear_solver_ordering->AddElementToGroup(&y_, 0);
   options.linear_solver_ordering->AddElementToGroup(&z_, 1);
@@ -238,7 +239,7 @@
 TEST_F(LinearSolverAndEvaluatorCreationTest, SchurTypeSolverWithGoodOrdering) {
   Solver::Options options;
   options.linear_solver_type = DENSE_SCHUR;
-  options.linear_solver_ordering.reset(new ParameterBlockOrdering);
+  options.linear_solver_ordering = std::make_shared<ParameterBlockOrdering>();
   options.linear_solver_ordering->AddElementToGroup(&x_, 0);
   options.linear_solver_ordering->AddElementToGroup(&z_, 0);
   options.linear_solver_ordering->AddElementToGroup(&y_, 1);
@@ -260,7 +261,7 @@
 
   Solver::Options options;
   options.linear_solver_type = DENSE_SCHUR;
-  options.linear_solver_ordering.reset(new ParameterBlockOrdering);
+  options.linear_solver_ordering = std::make_shared<ParameterBlockOrdering>();
   options.linear_solver_ordering->AddElementToGroup(&x_, 0);
   options.linear_solver_ordering->AddElementToGroup(&z_, 0);
   options.linear_solver_ordering->AddElementToGroup(&y_, 1);
@@ -281,7 +282,7 @@
 
   Solver::Options options;
   options.linear_solver_type = DENSE_SCHUR;
-  options.linear_solver_ordering.reset(new ParameterBlockOrdering);
+  options.linear_solver_ordering = std::make_shared<ParameterBlockOrdering>();
   options.linear_solver_ordering->AddElementToGroup(&x_, 0);
   options.linear_solver_ordering->AddElementToGroup(&z_, 0);
   options.linear_solver_ordering->AddElementToGroup(&y_, 1);
@@ -328,7 +329,7 @@
 TEST_F(LinearSolverAndEvaluatorCreationTest, InvalidInnerIterationsOrdering) {
   Solver::Options options;
   options.use_inner_iterations = true;
-  options.inner_iteration_ordering.reset(new ParameterBlockOrdering);
+  options.inner_iteration_ordering = std::make_shared<ParameterBlockOrdering>();
   options.inner_iteration_ordering->AddElementToGroup(&x_, 0);
   options.inner_iteration_ordering->AddElementToGroup(&z_, 0);
   options.inner_iteration_ordering->AddElementToGroup(&y_, 0);
@@ -341,7 +342,7 @@
 TEST_F(LinearSolverAndEvaluatorCreationTest, ValidInnerIterationsOrdering) {
   Solver::Options options;
   options.use_inner_iterations = true;
-  options.inner_iteration_ordering.reset(new ParameterBlockOrdering);
+  options.inner_iteration_ordering = std::make_shared<ParameterBlockOrdering>();
   options.inner_iteration_ordering->AddElementToGroup(&x_, 0);
   options.inner_iteration_ordering->AddElementToGroup(&z_, 0);
   options.inner_iteration_ordering->AddElementToGroup(&y_, 1);
diff --git a/third_party/ceres/internal/ceres/trust_region_step_evaluator.cc b/third_party/ceres/internal/ceres/trust_region_step_evaluator.cc
index 19045ae..a2333a0 100644
--- a/third_party/ceres/internal/ceres/trust_region_step_evaluator.cc
+++ b/third_party/ceres/internal/ceres/trust_region_step_evaluator.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2016 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,8 +35,7 @@
 
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 TrustRegionStepEvaluator::TrustRegionStepEvaluator(
     const double initial_cost, const int max_consecutive_nonmonotonic_steps)
@@ -111,5 +110,4 @@
   }
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/trust_region_step_evaluator.h b/third_party/ceres/internal/ceres/trust_region_step_evaluator.h
index 03c0036..6df0427 100644
--- a/third_party/ceres/internal/ceres/trust_region_step_evaluator.h
+++ b/third_party/ceres/internal/ceres/trust_region_step_evaluator.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2016 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -31,8 +31,9 @@
 #ifndef CERES_INTERNAL_TRUST_REGION_STEP_EVALUATOR_H_
 #define CERES_INTERNAL_TRUST_REGION_STEP_EVALUATOR_H_
 
-namespace ceres {
-namespace internal {
+#include "ceres/internal/export.h"
+
+namespace ceres::internal {
 
 // The job of the TrustRegionStepEvaluator is to evaluate the quality
 // of a step, i.e., how the cost of a step compares with the reduction
@@ -74,7 +75,7 @@
 //   x = x + delta;
 //   step_evaluator->StepAccepted(cost, model_cost_change);
 // }
-class TrustRegionStepEvaluator {
+class CERES_NO_EXPORT TrustRegionStepEvaluator {
  public:
   // initial_cost is as the name implies the cost of the starting
   // state of the trust region minimizer.
@@ -116,7 +117,6 @@
   int num_consecutive_nonmonotonic_steps_;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_INTERNAL_TRUST_REGION_STEP_EVALUATOR_H_
diff --git a/third_party/ceres/internal/ceres/trust_region_strategy.cc b/third_party/ceres/internal/ceres/trust_region_strategy.cc
index 7e429d5..da5a337 100644
--- a/third_party/ceres/internal/ceres/trust_region_strategy.cc
+++ b/third_party/ceres/internal/ceres/trust_region_strategy.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -32,20 +32,22 @@
 
 #include "ceres/trust_region_strategy.h"
 
+#include <memory>
+
 #include "ceres/dogleg_strategy.h"
 #include "ceres/levenberg_marquardt_strategy.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
-TrustRegionStrategy::~TrustRegionStrategy() {}
+TrustRegionStrategy::~TrustRegionStrategy() = default;
 
-TrustRegionStrategy* TrustRegionStrategy::Create(const Options& options) {
+std::unique_ptr<TrustRegionStrategy> TrustRegionStrategy::Create(
+    const Options& options) {
   switch (options.trust_region_strategy_type) {
     case LEVENBERG_MARQUARDT:
-      return new LevenbergMarquardtStrategy(options);
+      return std::make_unique<LevenbergMarquardtStrategy>(options);
     case DOGLEG:
-      return new DoglegStrategy(options);
+      return std::make_unique<DoglegStrategy>(options);
     default:
       LOG(FATAL) << "Unknown trust region strategy: "
                  << options.trust_region_strategy_type;
@@ -53,8 +55,7 @@
 
   LOG(FATAL) << "Unknown trust region strategy: "
              << options.trust_region_strategy_type;
-  return NULL;
+  return nullptr;
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/trust_region_strategy.h b/third_party/ceres/internal/ceres/trust_region_strategy.h
index 176f73a..0e0a301 100644
--- a/third_party/ceres/internal/ceres/trust_region_strategy.h
+++ b/third_party/ceres/internal/ceres/trust_region_strategy.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -31,13 +31,14 @@
 #ifndef CERES_INTERNAL_TRUST_REGION_STRATEGY_H_
 #define CERES_INTERNAL_TRUST_REGION_STRATEGY_H_
 
+#include <memory>
 #include <string>
 
-#include "ceres/internal/port.h"
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 #include "ceres/linear_solver.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 class LinearSolver;
 class SparseMatrix;
@@ -54,7 +55,7 @@
 // the LevenbergMarquardtStrategy uses the inverse of the trust region
 // radius to scale the damping term, which controls the step size, but
 // does not set a hard limit on its size.
-class CERES_EXPORT_INTERNAL TrustRegionStrategy {
+class CERES_NO_EXPORT TrustRegionStrategy {
  public:
   struct Options {
     TrustRegionStrategyType trust_region_strategy_type = LEVENBERG_MARQUARDT;
@@ -72,10 +73,13 @@
 
     // Further specify which dogleg method to use
     DoglegType dogleg_type = TRADITIONAL_DOGLEG;
+
+    ContextImpl* context = nullptr;
+    int num_threads = 1;
   };
 
   // Factory.
-  static TrustRegionStrategy* Create(const Options& options);
+  static std::unique_ptr<TrustRegionStrategy> Create(const Options& options);
 
   virtual ~TrustRegionStrategy();
 
@@ -110,7 +114,8 @@
     int num_iterations = -1;
 
     // Status of the linear solver used to solve the Newton system.
-    LinearSolverTerminationType termination_type = LINEAR_SOLVER_FAILURE;
+    LinearSolverTerminationType termination_type =
+        LinearSolverTerminationType::FAILURE;
   };
 
   // Use the current radius to solve for the trust region step.
@@ -139,7 +144,8 @@
   virtual double Radius() const = 0;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_TRUST_REGION_STRATEGY_H_
diff --git a/third_party/ceres/internal/ceres/types.cc b/third_party/ceres/internal/ceres/types.cc
index 39bb2d8..e000560 100644
--- a/third_party/ceres/internal/ceres/types.cc
+++ b/third_party/ceres/internal/ceres/types.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -34,18 +34,17 @@
 #include <cctype>
 #include <string>
 
+#include "ceres/internal/config.h"
 #include "glog/logging.h"
 
 namespace ceres {
 
-using std::string;
-
 // clang-format off
 #define CASESTR(x) case x: return #x
 #define STRENUM(x) if (value == #x) { *type = x; return true; }
 // clang-format on
 
-static void UpperCase(string* input) {
+static void UpperCase(std::string* input) {
   std::transform(input->begin(), input->end(), input->begin(), ::toupper);
 }
 
@@ -63,7 +62,7 @@
   }
 }
 
-bool StringToLinearSolverType(string value, LinearSolverType* type) {
+bool StringToLinearSolverType(std::string value, LinearSolverType* type) {
   UpperCase(&value);
   STRENUM(DENSE_NORMAL_CHOLESKY);
   STRENUM(DENSE_QR);
@@ -80,6 +79,7 @@
     CASESTR(IDENTITY);
     CASESTR(JACOBI);
     CASESTR(SCHUR_JACOBI);
+    CASESTR(SCHUR_POWER_SERIES_EXPANSION);
     CASESTR(CLUSTER_JACOBI);
     CASESTR(CLUSTER_TRIDIAGONAL);
     CASESTR(SUBSET);
@@ -88,11 +88,12 @@
   }
 }
 
-bool StringToPreconditionerType(string value, PreconditionerType* type) {
+bool StringToPreconditionerType(std::string value, PreconditionerType* type) {
   UpperCase(&value);
   STRENUM(IDENTITY);
   STRENUM(JACOBI);
   STRENUM(SCHUR_JACOBI);
+  STRENUM(SCHUR_POWER_SERIES_EXPANSION);
   STRENUM(CLUSTER_JACOBI);
   STRENUM(CLUSTER_TRIDIAGONAL);
   STRENUM(SUBSET);
@@ -103,9 +104,9 @@
     SparseLinearAlgebraLibraryType type) {
   switch (type) {
     CASESTR(SUITE_SPARSE);
-    CASESTR(CX_SPARSE);
     CASESTR(EIGEN_SPARSE);
     CASESTR(ACCELERATE_SPARSE);
+    CASESTR(CUDA_SPARSE);
     CASESTR(NO_SPARSE);
     default:
       return "UNKNOWN";
@@ -113,31 +114,50 @@
 }
 
 bool StringToSparseLinearAlgebraLibraryType(
-    string value, SparseLinearAlgebraLibraryType* type) {
+    std::string value, SparseLinearAlgebraLibraryType* type) {
   UpperCase(&value);
   STRENUM(SUITE_SPARSE);
-  STRENUM(CX_SPARSE);
   STRENUM(EIGEN_SPARSE);
   STRENUM(ACCELERATE_SPARSE);
+  STRENUM(CUDA_SPARSE);
   STRENUM(NO_SPARSE);
   return false;
 }
 
+const char* LinearSolverOrderingTypeToString(LinearSolverOrderingType type) {
+  switch (type) {
+    CASESTR(AMD);
+    CASESTR(NESDIS);
+    default:
+      return "UNKNOWN";
+  }
+}
+
+bool StringToLinearSolverOrderingType(std::string value,
+                                      LinearSolverOrderingType* type) {
+  UpperCase(&value);
+  STRENUM(AMD);
+  STRENUM(NESDIS);
+  return false;
+}
+
 const char* DenseLinearAlgebraLibraryTypeToString(
     DenseLinearAlgebraLibraryType type) {
   switch (type) {
     CASESTR(EIGEN);
     CASESTR(LAPACK);
+    CASESTR(CUDA);
     default:
       return "UNKNOWN";
   }
 }
 
 bool StringToDenseLinearAlgebraLibraryType(
-    string value, DenseLinearAlgebraLibraryType* type) {
+    std::string value, DenseLinearAlgebraLibraryType* type) {
   UpperCase(&value);
   STRENUM(EIGEN);
   STRENUM(LAPACK);
+  STRENUM(CUDA);
   return false;
 }
 
@@ -150,7 +170,7 @@
   }
 }
 
-bool StringToTrustRegionStrategyType(string value,
+bool StringToTrustRegionStrategyType(std::string value,
                                      TrustRegionStrategyType* type) {
   UpperCase(&value);
   STRENUM(LEVENBERG_MARQUARDT);
@@ -167,7 +187,7 @@
   }
 }
 
-bool StringToDoglegType(string value, DoglegType* type) {
+bool StringToDoglegType(std::string value, DoglegType* type) {
   UpperCase(&value);
   STRENUM(TRADITIONAL_DOGLEG);
   STRENUM(SUBSPACE_DOGLEG);
@@ -183,7 +203,7 @@
   }
 }
 
-bool StringToMinimizerType(string value, MinimizerType* type) {
+bool StringToMinimizerType(std::string value, MinimizerType* type) {
   UpperCase(&value);
   STRENUM(TRUST_REGION);
   STRENUM(LINE_SEARCH);
@@ -201,7 +221,7 @@
   }
 }
 
-bool StringToLineSearchDirectionType(string value,
+bool StringToLineSearchDirectionType(std::string value,
                                      LineSearchDirectionType* type) {
   UpperCase(&value);
   STRENUM(STEEPEST_DESCENT);
@@ -220,7 +240,7 @@
   }
 }
 
-bool StringToLineSearchType(string value, LineSearchType* type) {
+bool StringToLineSearchType(std::string value, LineSearchType* type) {
   UpperCase(&value);
   STRENUM(ARMIJO);
   STRENUM(WOLFE);
@@ -238,7 +258,7 @@
   }
 }
 
-bool StringToLineSearchInterpolationType(string value,
+bool StringToLineSearchInterpolationType(std::string value,
                                          LineSearchInterpolationType* type) {
   UpperCase(&value);
   STRENUM(BISECTION);
@@ -259,7 +279,7 @@
 }
 
 bool StringToNonlinearConjugateGradientType(
-    string value, NonlinearConjugateGradientType* type) {
+    std::string value, NonlinearConjugateGradientType* type) {
   UpperCase(&value);
   STRENUM(FLETCHER_REEVES);
   STRENUM(POLAK_RIBIERE);
@@ -276,7 +296,7 @@
   }
 }
 
-bool StringToCovarianceAlgorithmType(string value,
+bool StringToCovarianceAlgorithmType(std::string value,
                                      CovarianceAlgorithmType* type) {
   UpperCase(&value);
   STRENUM(DENSE_SVD);
@@ -294,7 +314,8 @@
   }
 }
 
-bool StringToNumericDiffMethodType(string value, NumericDiffMethodType* type) {
+bool StringToNumericDiffMethodType(std::string value,
+                                   NumericDiffMethodType* type) {
   UpperCase(&value);
   STRENUM(CENTRAL);
   STRENUM(FORWARD);
@@ -311,7 +332,7 @@
   }
 }
 
-bool StringToVisibilityClusteringType(string value,
+bool StringToVisibilityClusteringType(std::string value,
                                       VisibilityClusteringType* type) {
   UpperCase(&value);
   STRENUM(CANONICAL_VIEWS);
@@ -384,14 +405,6 @@
 #endif
   }
 
-  if (type == CX_SPARSE) {
-#ifdef CERES_NO_CXSPARSE
-    return false;
-#else
-    return true;
-#endif
-  }
-
   if (type == ACCELERATE_SPARSE) {
 #ifdef CERES_NO_ACCELERATE_SPARSE
     return false;
@@ -408,6 +421,18 @@
 #endif
   }
 
+  if (type == CUDA_SPARSE) {
+#ifdef CERES_NO_CUDA
+    return false;
+#else
+    return true;
+#endif
+  }
+
+  if (type == NO_SPARSE) {
+    return true;
+  }
+
   LOG(WARNING) << "Unknown sparse linear algebra library " << type;
   return false;
 }
@@ -417,6 +442,7 @@
   if (type == EIGEN) {
     return true;
   }
+
   if (type == LAPACK) {
 #ifdef CERES_NO_LAPACK
     return false;
@@ -425,6 +451,14 @@
 #endif
   }
 
+  if (type == CUDA) {
+#ifdef CERES_NO_CUDA
+    return false;
+#else
+    return true;
+#endif
+  }
+
   LOG(WARNING) << "Unknown dense linear algebra library " << type;
   return false;
 }
diff --git a/third_party/ceres/internal/ceres/visibility.cc b/third_party/ceres/internal/ceres/visibility.cc
index 82bf6f1..6c10fb2 100644
--- a/third_party/ceres/internal/ceres/visibility.cc
+++ b/third_party/ceres/internal/ceres/visibility.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -33,6 +33,7 @@
 #include <algorithm>
 #include <cmath>
 #include <ctime>
+#include <memory>
 #include <set>
 #include <unordered_map>
 #include <utility>
@@ -43,18 +44,11 @@
 #include "ceres/pair_hash.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
-
-using std::make_pair;
-using std::max;
-using std::pair;
-using std::set;
-using std::vector;
+namespace ceres::internal {
 
 void ComputeVisibility(const CompressedRowBlockStructure& block_structure,
                        const int num_eliminate_blocks,
-                       vector<set<int>>* visibility) {
+                       std::vector<std::set<int>>* visibility) {
   CHECK(visibility != nullptr);
 
   // Clear the visibility vector and resize it to hold a
@@ -62,8 +56,8 @@
   visibility->resize(0);
   visibility->resize(block_structure.cols.size() - num_eliminate_blocks);
 
-  for (int i = 0; i < block_structure.rows.size(); ++i) {
-    const vector<Cell>& cells = block_structure.rows[i].cells;
+  for (const auto& row : block_structure.rows) {
+    const std::vector<Cell>& cells = row.cells;
     int block_id = cells[0].block_id;
     // If the first block is not an e_block, then skip this row block.
     if (block_id >= num_eliminate_blocks) {
@@ -79,16 +73,16 @@
   }
 }
 
-WeightedGraph<int>* CreateSchurComplementGraph(
-    const vector<set<int>>& visibility) {
-  const time_t start_time = time(NULL);
+std::unique_ptr<WeightedGraph<int>> CreateSchurComplementGraph(
+    const std::vector<std::set<int>>& visibility) {
+  const time_t start_time = time(nullptr);
   // Compute the number of e_blocks/point blocks. Since the visibility
   // set for each e_block/camera contains the set of e_blocks/points
   // visible to it, we find the maximum across all visibility sets.
   int num_points = 0;
-  for (int i = 0; i < visibility.size(); i++) {
-    if (visibility[i].size() > 0) {
-      num_points = max(num_points, (*visibility[i].rbegin()) + 1);
+  for (const auto& visible : visibility) {
+    if (!visible.empty()) {
+      num_points = std::max(num_points, (*visible.rbegin()) + 1);
     }
   }
 
@@ -97,31 +91,31 @@
   // cameras. However, to compute the sparsity structure of the Schur
   // Complement efficiently, its better to have the point->camera
   // mapping.
-  vector<set<int>> inverse_visibility(num_points);
+  std::vector<std::set<int>> inverse_visibility(num_points);
   for (int i = 0; i < visibility.size(); i++) {
-    const set<int>& visibility_set = visibility[i];
-    for (const int v : visibility_set) {
+    const std::set<int>& visibility_set = visibility[i];
+    for (int v : visibility_set) {
       inverse_visibility[v].insert(i);
     }
   }
 
   // Map from camera pairs to number of points visible to both cameras
   // in the pair.
-  std::unordered_map<pair<int, int>, int, pair_hash> camera_pairs;
+  std::unordered_map<std::pair<int, int>, int, pair_hash> camera_pairs;
 
   // Count the number of points visible to each camera/f_block pair.
   for (const auto& inverse_visibility_set : inverse_visibility) {
-    for (set<int>::const_iterator camera1 = inverse_visibility_set.begin();
+    for (auto camera1 = inverse_visibility_set.begin();
          camera1 != inverse_visibility_set.end();
          ++camera1) {
-      set<int>::const_iterator camera2 = camera1;
+      auto camera2 = camera1;
       for (++camera2; camera2 != inverse_visibility_set.end(); ++camera2) {
-        ++(camera_pairs[make_pair(*camera1, *camera2)]);
+        ++(camera_pairs[std::make_pair(*camera1, *camera2)]);
       }
     }
   }
 
-  WeightedGraph<int>* graph = new WeightedGraph<int>;
+  auto graph = std::make_unique<WeightedGraph<int>>();
 
   // Add vertices and initialize the pairs for self edges so that self
   // edges are guaranteed. This is needed for the Canonical views
@@ -146,9 +140,8 @@
     graph->AddEdge(camera1, camera2, weight);
   }
 
-  VLOG(2) << "Schur complement graph time: " << (time(NULL) - start_time);
+  VLOG(2) << "Schur complement graph time: " << (time(nullptr) - start_time);
   return graph;
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/visibility.h b/third_party/ceres/internal/ceres/visibility.h
index 68c6723..2e5f4fc 100644
--- a/third_party/ceres/internal/ceres/visibility.h
+++ b/third_party/ceres/internal/ceres/visibility.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,14 +35,15 @@
 #ifndef CERES_INTERNAL_VISIBILITY_H_
 #define CERES_INTERNAL_VISIBILITY_H_
 
+#include <memory>
 #include <set>
 #include <vector>
 
 #include "ceres/graph.h"
-#include "ceres/internal/port.h"
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 struct CompressedRowBlockStructure;
 
@@ -54,7 +55,7 @@
 //
 // In a structure from motion problem, e_blocks correspond to 3D
 // points and f_blocks correspond to cameras.
-CERES_EXPORT_INTERNAL void ComputeVisibility(
+CERES_NO_EXPORT void ComputeVisibility(
     const CompressedRowBlockStructure& block_structure,
     int num_eliminate_blocks,
     std::vector<std::set<int>>* visibility);
@@ -72,10 +73,11 @@
 //
 // Caller acquires ownership of the returned WeightedGraph pointer
 // (heap-allocated).
-CERES_EXPORT_INTERNAL WeightedGraph<int>* CreateSchurComplementGraph(
+CERES_NO_EXPORT std::unique_ptr<WeightedGraph<int>> CreateSchurComplementGraph(
     const std::vector<std::set<int>>& visibility);
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_VISIBILITY_H_
diff --git a/third_party/ceres/internal/ceres/visibility_based_preconditioner.cc b/third_party/ceres/internal/ceres/visibility_based_preconditioner.cc
index 0cf4afa..42e8a6e 100644
--- a/third_party/ceres/internal/ceres/visibility_based_preconditioner.cc
+++ b/third_party/ceres/internal/ceres/visibility_based_preconditioner.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -35,6 +35,8 @@
 #include <iterator>
 #include <memory>
 #include <set>
+#include <string>
+#include <unordered_set>
 #include <utility>
 #include <vector>
 
@@ -50,14 +52,7 @@
 #include "ceres/visibility.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
-
-using std::make_pair;
-using std::pair;
-using std::set;
-using std::swap;
-using std::vector;
+namespace ceres::internal {
 
 // TODO(sameeragarwal): Currently these are magic weights for the
 // preconditioner construction. Move these higher up into the Options
@@ -70,9 +65,8 @@
 static constexpr double kSingleLinkageMinSimilarity = 0.9;
 
 VisibilityBasedPreconditioner::VisibilityBasedPreconditioner(
-    const CompressedRowBlockStructure& bs,
-    const Preconditioner::Options& options)
-    : options_(options), num_blocks_(0), num_clusters_(0) {
+    const CompressedRowBlockStructure& bs, Preconditioner::Options options)
+    : options_(std::move(options)), num_blocks_(0), num_clusters_(0) {
   CHECK_GT(options_.elimination_groups.size(), 1);
   CHECK_GT(options_.elimination_groups[0], 0);
   CHECK(options_.type == CLUSTER_JACOBI || options_.type == CLUSTER_TRIDIAGONAL)
@@ -80,15 +74,12 @@
   num_blocks_ = bs.cols.size() - options_.elimination_groups[0];
   CHECK_GT(num_blocks_, 0) << "Jacobian should have at least 1 f_block for "
                            << "visibility based preconditioning.";
-  CHECK(options_.context != NULL);
+  CHECK(options_.context != nullptr);
 
   // Vector of camera block sizes
-  block_size_.resize(num_blocks_);
-  for (int i = 0; i < num_blocks_; ++i) {
-    block_size_[i] = bs.cols[i + options_.elimination_groups[0]].size;
-  }
+  blocks_ = Tail(bs.cols, bs.cols.size() - options_.elimination_groups[0]);
 
-  const time_t start_time = time(NULL);
+  const time_t start_time = time(nullptr);
   switch (options_.type) {
     case CLUSTER_JACOBI:
       ComputeClusterJacobiSparsity(bs);
@@ -99,33 +90,26 @@
     default:
       LOG(FATAL) << "Unknown preconditioner type";
   }
-  const time_t structure_time = time(NULL);
+  const time_t structure_time = time(nullptr);
   InitStorage(bs);
-  const time_t storage_time = time(NULL);
+  const time_t storage_time = time(nullptr);
   InitEliminator(bs);
-  const time_t eliminator_time = time(NULL);
+  const time_t eliminator_time = time(nullptr);
 
   LinearSolver::Options sparse_cholesky_options;
   sparse_cholesky_options.sparse_linear_algebra_library_type =
       options_.sparse_linear_algebra_library_type;
-
-  // The preconditioner's sparsity is not available in the
-  // preprocessor, so the columns of the Jacobian have not been
-  // reordered to minimize fill in when computing its sparse Cholesky
-  // factorization. So we must tell the SparseCholesky object to
-  // perform approximate minimum-degree reordering, which is done by
-  // setting use_postordering to true.
-  sparse_cholesky_options.use_postordering = true;
+  sparse_cholesky_options.ordering_type = options_.ordering_type;
   sparse_cholesky_ = SparseCholesky::Create(sparse_cholesky_options);
 
-  const time_t init_time = time(NULL);
+  const time_t init_time = time(nullptr);
   VLOG(2) << "init time: " << init_time - start_time
           << " structure time: " << structure_time - start_time
           << " storage time:" << storage_time - structure_time
           << " eliminator time: " << eliminator_time - storage_time;
 }
 
-VisibilityBasedPreconditioner::~VisibilityBasedPreconditioner() {}
+VisibilityBasedPreconditioner::~VisibilityBasedPreconditioner() = default;
 
 // Determine the sparsity structure of the CLUSTER_JACOBI
 // preconditioner. It clusters cameras using their scene
@@ -133,13 +117,13 @@
 // preconditioner matrix.
 void VisibilityBasedPreconditioner::ComputeClusterJacobiSparsity(
     const CompressedRowBlockStructure& bs) {
-  vector<set<int>> visibility;
+  std::vector<std::set<int>> visibility;
   ComputeVisibility(bs, options_.elimination_groups[0], &visibility);
   CHECK_EQ(num_blocks_, visibility.size());
   ClusterCameras(visibility);
   cluster_pairs_.clear();
   for (int i = 0; i < num_clusters_; ++i) {
-    cluster_pairs_.insert(make_pair(i, i));
+    cluster_pairs_.insert(std::make_pair(i, i));
   }
 }
 
@@ -151,7 +135,7 @@
 // of edges in this forest are the cluster pairs.
 void VisibilityBasedPreconditioner::ComputeClusterTridiagonalSparsity(
     const CompressedRowBlockStructure& bs) {
-  vector<set<int>> visibility;
+  std::vector<std::set<int>> visibility;
   ComputeVisibility(bs, options_.elimination_groups[0], &visibility);
   CHECK_EQ(num_blocks_, visibility.size());
   ClusterCameras(visibility);
@@ -160,13 +144,11 @@
   // edges are the number of 3D points/e_blocks visible in both the
   // clusters at the ends of the edge. Return an approximate degree-2
   // maximum spanning forest of this graph.
-  vector<set<int>> cluster_visibility;
+  std::vector<std::set<int>> cluster_visibility;
   ComputeClusterVisibility(visibility, &cluster_visibility);
-  std::unique_ptr<WeightedGraph<int>> cluster_graph(
-      CreateClusterGraph(cluster_visibility));
+  auto cluster_graph = CreateClusterGraph(cluster_visibility);
   CHECK(cluster_graph != nullptr);
-  std::unique_ptr<WeightedGraph<int>> forest(
-      Degree2MaximumSpanningForest(*cluster_graph));
+  auto forest = Degree2MaximumSpanningForest(*cluster_graph);
   CHECK(forest != nullptr);
   ForestToClusterPairs(*forest, &cluster_pairs_);
 }
@@ -175,7 +157,8 @@
 void VisibilityBasedPreconditioner::InitStorage(
     const CompressedRowBlockStructure& bs) {
   ComputeBlockPairsInPreconditioner(bs);
-  m_.reset(new BlockRandomAccessSparseMatrix(block_size_, block_pairs_));
+  m_ = std::make_unique<BlockRandomAccessSparseMatrix>(
+      blocks_, block_pairs_, options_.context, options_.num_threads);
 }
 
 // Call the canonical views algorithm and cluster the cameras based on
@@ -185,15 +168,14 @@
 // The cluster_membership_ vector is updated to indicate cluster
 // memberships for each camera block.
 void VisibilityBasedPreconditioner::ClusterCameras(
-    const vector<set<int>>& visibility) {
-  std::unique_ptr<WeightedGraph<int>> schur_complement_graph(
-      CreateSchurComplementGraph(visibility));
+    const std::vector<std::set<int>>& visibility) {
+  auto schur_complement_graph = CreateSchurComplementGraph(visibility);
   CHECK(schur_complement_graph != nullptr);
 
   std::unordered_map<int, int> membership;
 
   if (options_.visibility_clustering_type == CANONICAL_VIEWS) {
-    vector<int> centers;
+    std::vector<int> centers;
     CanonicalViewsClusteringOptions clustering_options;
     clustering_options.size_penalty_weight = kCanonicalViewsSizePenaltyWeight;
     clustering_options.similarity_penalty_weight =
@@ -239,7 +221,7 @@
     const CompressedRowBlockStructure& bs) {
   block_pairs_.clear();
   for (int i = 0; i < num_blocks_; ++i) {
-    block_pairs_.insert(make_pair(i, i));
+    block_pairs_.insert(std::make_pair(i, i));
   }
 
   int r = 0;
@@ -267,7 +249,7 @@
       break;
     }
 
-    set<int> f_blocks;
+    std::set<int> f_blocks;
     for (; r < num_row_blocks; ++r) {
       const CompressedRow& row = bs.rows[r];
       if (row.cells.front().block_id != e_block_id) {
@@ -285,14 +267,12 @@
       }
     }
 
-    for (set<int>::const_iterator block1 = f_blocks.begin();
-         block1 != f_blocks.end();
-         ++block1) {
-      set<int>::const_iterator block2 = block1;
+    for (auto block1 = f_blocks.begin(); block1 != f_blocks.end(); ++block1) {
+      auto block2 = block1;
       ++block2;
       for (; block2 != f_blocks.end(); ++block2) {
         if (IsBlockPairInPreconditioner(*block1, *block2)) {
-          block_pairs_.insert(make_pair(*block1, *block2));
+          block_pairs_.emplace(*block1, *block2);
         }
       }
     }
@@ -304,11 +284,11 @@
     CHECK_GE(row.cells.front().block_id, num_eliminate_blocks);
     for (int i = 0; i < row.cells.size(); ++i) {
       const int block1 = row.cells[i].block_id - num_eliminate_blocks;
-      for (int j = 0; j < row.cells.size(); ++j) {
-        const int block2 = row.cells[j].block_id - num_eliminate_blocks;
+      for (const auto& cell : row.cells) {
+        const int block2 = cell.block_id - num_eliminate_blocks;
         if (block1 <= block2) {
           if (IsBlockPairInPreconditioner(block1, block2)) {
-            block_pairs_.insert(make_pair(block1, block2));
+            block_pairs_.insert(std::make_pair(block1, block2));
           }
         }
       }
@@ -328,7 +308,7 @@
   eliminator_options.f_block_size = options_.f_block_size;
   eliminator_options.row_block_size = options_.row_block_size;
   eliminator_options.context = options_.context;
-  eliminator_.reset(SchurEliminatorBase::Create(eliminator_options));
+  eliminator_ = SchurEliminatorBase::Create(eliminator_options);
   const bool kFullRankETE = true;
   eliminator_->Init(
       eliminator_options.elimination_groups[0], kFullRankETE, &bs);
@@ -337,7 +317,7 @@
 // Update the values of the preconditioner matrix and factorize it.
 bool VisibilityBasedPreconditioner::UpdateImpl(const BlockSparseMatrix& A,
                                                const double* D) {
-  const time_t start_time = time(NULL);
+  const time_t start_time = time(nullptr);
   const int num_rows = m_->num_rows();
   CHECK_GT(num_rows, 0);
 
@@ -359,7 +339,7 @@
   // scaling is not needed, which is quite often in our experience.
   LinearSolverTerminationType status = Factorize();
 
-  if (status == LINEAR_SOLVER_FATAL_ERROR) {
+  if (status == LinearSolverTerminationType::FATAL_ERROR) {
     return false;
   }
 
@@ -368,15 +348,16 @@
   // belong to the edges of the degree-2 forest. In the CLUSTER_JACOBI
   // case, the preconditioner is guaranteed to be positive
   // semidefinite.
-  if (status == LINEAR_SOLVER_FAILURE && options_.type == CLUSTER_TRIDIAGONAL) {
+  if (status == LinearSolverTerminationType::FAILURE &&
+      options_.type == CLUSTER_TRIDIAGONAL) {
     VLOG(1) << "Unscaled factorization failed. Retrying with off-diagonal "
             << "scaling";
     ScaleOffDiagonalCells();
     status = Factorize();
   }
 
-  VLOG(2) << "Compute time: " << time(NULL) - start_time;
-  return (status == LINEAR_SOLVER_SUCCESS);
+  VLOG(2) << "Compute time: " << time(nullptr) - start_time;
+  return (status == LinearSolverTerminationType::SUCCESS);
 }
 
 // Consider the preconditioner matrix as meta-block matrix, whose
@@ -395,7 +376,7 @@
     int r, c, row_stride, col_stride;
     CellInfo* cell_info =
         m_->GetCell(block1, block2, &r, &c, &row_stride, &col_stride);
-    CHECK(cell_info != NULL)
+    CHECK(cell_info != nullptr)
         << "Cell missing for block pair (" << block1 << "," << block2 << ")"
         << " cluster pair (" << cluster_membership_[block1] << " "
         << cluster_membership_[block2] << ")";
@@ -404,36 +385,44 @@
     // dominance. See Lemma 1 in "Visibility Based Preconditioning
     // For Bundle Adjustment".
     MatrixRef m(cell_info->values, row_stride, col_stride);
-    m.block(r, c, block_size_[block1], block_size_[block2]) *= 0.5;
+    m.block(r, c, blocks_[block1].size, blocks_[block2].size) *= 0.5;
   }
 }
 
 // Compute the sparse Cholesky factorization of the preconditioner
 // matrix.
 LinearSolverTerminationType VisibilityBasedPreconditioner::Factorize() {
-  // Extract the TripletSparseMatrix that is used for actually storing
+  // Extract the BlockSparseMatrix that is used for actually storing
   // S and convert it into a CompressedRowSparseMatrix.
-  const TripletSparseMatrix* tsm =
-      down_cast<BlockRandomAccessSparseMatrix*>(m_.get())->mutable_matrix();
-
-  std::unique_ptr<CompressedRowSparseMatrix> lhs;
+  const BlockSparseMatrix* bsm =
+      down_cast<BlockRandomAccessSparseMatrix*>(m_.get())->matrix();
   const CompressedRowSparseMatrix::StorageType storage_type =
       sparse_cholesky_->StorageType();
-  if (storage_type == CompressedRowSparseMatrix::UPPER_TRIANGULAR) {
-    lhs.reset(CompressedRowSparseMatrix::FromTripletSparseMatrix(*tsm));
-    lhs->set_storage_type(CompressedRowSparseMatrix::UPPER_TRIANGULAR);
+  if (storage_type ==
+      CompressedRowSparseMatrix::StorageType::UPPER_TRIANGULAR) {
+    if (!m_crs_) {
+      m_crs_ = bsm->ToCompressedRowSparseMatrix();
+      m_crs_->set_storage_type(
+          CompressedRowSparseMatrix::StorageType::UPPER_TRIANGULAR);
+    } else {
+      bsm->UpdateCompressedRowSparseMatrix(m_crs_.get());
+    }
   } else {
-    lhs.reset(
-        CompressedRowSparseMatrix::FromTripletSparseMatrixTransposed(*tsm));
-    lhs->set_storage_type(CompressedRowSparseMatrix::LOWER_TRIANGULAR);
+    if (!m_crs_) {
+      m_crs_ = bsm->ToCompressedRowSparseMatrixTranspose();
+      m_crs_->set_storage_type(
+          CompressedRowSparseMatrix::StorageType::LOWER_TRIANGULAR);
+    } else {
+      bsm->UpdateCompressedRowSparseMatrixTranspose(m_crs_.get());
+    }
   }
 
   std::string message;
-  return sparse_cholesky_->Factorize(lhs.get(), &message);
+  return sparse_cholesky_->Factorize(m_crs_.get(), &message);
 }
 
-void VisibilityBasedPreconditioner::RightMultiply(const double* x,
-                                                  double* y) const {
+void VisibilityBasedPreconditioner::RightMultiplyAndAccumulate(
+    const double* x, double* y) const {
   CHECK(x != nullptr);
   CHECK(y != nullptr);
   CHECK(sparse_cholesky_ != nullptr);
@@ -451,9 +440,9 @@
   int cluster1 = cluster_membership_[block1];
   int cluster2 = cluster_membership_[block2];
   if (cluster1 > cluster2) {
-    swap(cluster1, cluster2);
+    std::swap(cluster1, cluster2);
   }
-  return (cluster_pairs_.count(make_pair(cluster1, cluster2)) > 0);
+  return (cluster_pairs_.count(std::make_pair(cluster1, cluster2)) > 0);
 }
 
 bool VisibilityBasedPreconditioner::IsBlockPairOffDiagonal(
@@ -465,7 +454,7 @@
 // each vertex.
 void VisibilityBasedPreconditioner::ForestToClusterPairs(
     const WeightedGraph<int>& forest,
-    std::unordered_set<pair<int, int>, pair_hash>* cluster_pairs) const {
+    std::unordered_set<std::pair<int, int>, pair_hash>* cluster_pairs) const {
   CHECK(cluster_pairs != nullptr);
   cluster_pairs->clear();
   const std::unordered_set<int>& vertices = forest.vertices();
@@ -474,11 +463,11 @@
   // Add all the cluster pairs corresponding to the edges in the
   // forest.
   for (const int cluster1 : vertices) {
-    cluster_pairs->insert(make_pair(cluster1, cluster1));
+    cluster_pairs->insert(std::make_pair(cluster1, cluster1));
     const std::unordered_set<int>& neighbors = forest.Neighbors(cluster1);
     for (const int cluster2 : neighbors) {
       if (cluster1 < cluster2) {
-        cluster_pairs->insert(make_pair(cluster1, cluster2));
+        cluster_pairs->insert(std::make_pair(cluster1, cluster2));
       }
     }
   }
@@ -488,8 +477,8 @@
 // of all its cameras. In other words, the set of points visible to
 // any camera in the cluster.
 void VisibilityBasedPreconditioner::ComputeClusterVisibility(
-    const vector<set<int>>& visibility,
-    vector<set<int>>* cluster_visibility) const {
+    const std::vector<std::set<int>>& visibility,
+    std::vector<std::set<int>>* cluster_visibility) const {
   CHECK(cluster_visibility != nullptr);
   cluster_visibility->resize(0);
   cluster_visibility->resize(num_clusters_);
@@ -503,24 +492,25 @@
 // Construct a graph whose vertices are the clusters, and the edge
 // weights are the number of 3D points visible to cameras in both the
 // vertices.
-WeightedGraph<int>* VisibilityBasedPreconditioner::CreateClusterGraph(
-    const vector<set<int>>& cluster_visibility) const {
-  WeightedGraph<int>* cluster_graph = new WeightedGraph<int>;
+std::unique_ptr<WeightedGraph<int>>
+VisibilityBasedPreconditioner::CreateClusterGraph(
+    const std::vector<std::set<int>>& cluster_visibility) const {
+  auto cluster_graph = std::make_unique<WeightedGraph<int>>();
 
   for (int i = 0; i < num_clusters_; ++i) {
     cluster_graph->AddVertex(i);
   }
 
   for (int i = 0; i < num_clusters_; ++i) {
-    const set<int>& cluster_i = cluster_visibility[i];
+    const std::set<int>& cluster_i = cluster_visibility[i];
     for (int j = i + 1; j < num_clusters_; ++j) {
-      vector<int> intersection;
-      const set<int>& cluster_j = cluster_visibility[j];
-      set_intersection(cluster_i.begin(),
-                       cluster_i.end(),
-                       cluster_j.begin(),
-                       cluster_j.end(),
-                       back_inserter(intersection));
+      std::vector<int> intersection;
+      const std::set<int>& cluster_j = cluster_visibility[j];
+      std::set_intersection(cluster_i.begin(),
+                            cluster_i.end(),
+                            cluster_j.begin(),
+                            cluster_j.end(),
+                            std::back_inserter(intersection));
 
       if (intersection.size() > 0) {
         // Clusters interact strongly when they share a large number
@@ -545,7 +535,7 @@
 // of integers so that the cluster ids are in [0, num_clusters_).
 void VisibilityBasedPreconditioner::FlattenMembershipMap(
     const std::unordered_map<int, int>& membership_map,
-    vector<int>* membership_vector) const {
+    std::vector<int>* membership_vector) const {
   CHECK(membership_vector != nullptr);
   membership_vector->resize(0);
   membership_vector->resize(num_blocks_, -1);
@@ -581,5 +571,4 @@
   }
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/visibility_based_preconditioner.h b/third_party/ceres/internal/ceres/visibility_based_preconditioner.h
index 0457b9a..d2d4aad 100644
--- a/third_party/ceres/internal/ceres/visibility_based_preconditioner.h
+++ b/third_party/ceres/internal/ceres/visibility_based_preconditioner.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2017 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -55,14 +55,14 @@
 #include <utility>
 #include <vector>
 
+#include "ceres/block_structure.h"
 #include "ceres/graph.h"
 #include "ceres/linear_solver.h"
 #include "ceres/pair_hash.h"
 #include "ceres/preconditioner.h"
 #include "ceres/sparse_cholesky.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 class BlockRandomAccessSparseMatrix;
 class BlockSparseMatrix;
@@ -122,9 +122,10 @@
 //   options.elimination_groups.push_back(num_cameras);
 //   VisibilityBasedPreconditioner preconditioner(
 //      *A.block_structure(), options);
-//   preconditioner.Update(A, NULL);
-//   preconditioner.RightMultiply(x, y);
-class VisibilityBasedPreconditioner : public BlockSparseMatrixPreconditioner {
+//   preconditioner.Update(A, nullptr);
+//   preconditioner.RightMultiplyAndAccumulate(x, y);
+class CERES_NO_EXPORT VisibilityBasedPreconditioner
+    : public BlockSparseMatrixPreconditioner {
  public:
   // Initialize the symbolic structure of the preconditioner. bs is
   // the block structure of the linear system to be solved. It is used
@@ -133,14 +134,14 @@
   // It has the same structural requirement as other Schur complement
   // based solvers. Please see schur_eliminator.h for more details.
   VisibilityBasedPreconditioner(const CompressedRowBlockStructure& bs,
-                                const Preconditioner::Options& options);
+                                Preconditioner::Options options);
   VisibilityBasedPreconditioner(const VisibilityBasedPreconditioner&) = delete;
   void operator=(const VisibilityBasedPreconditioner&) = delete;
 
-  virtual ~VisibilityBasedPreconditioner();
+  ~VisibilityBasedPreconditioner() override;
 
   // Preconditioner interface
-  void RightMultiply(const double* x, double* y) const final;
+  void RightMultiplyAndAccumulate(const double* x, double* y) const final;
   int num_rows() const final;
 
   friend class VisibilityBasedPreconditionerTest;
@@ -160,7 +161,7 @@
   void ComputeClusterVisibility(
       const std::vector<std::set<int>>& visibility,
       std::vector<std::set<int>>* cluster_visibility) const;
-  WeightedGraph<int>* CreateClusterGraph(
+  std::unique_ptr<WeightedGraph<int>> CreateClusterGraph(
       const std::vector<std::set<int>>& visibility) const;
   void ForestToClusterPairs(
       const WeightedGraph<int>& forest,
@@ -176,7 +177,7 @@
   int num_clusters_;
 
   // Sizes of the blocks in the schur complement.
-  std::vector<int> block_size_;
+  std::vector<Block> blocks_;
 
   // Mapping from cameras to clusters.
   std::vector<int> cluster_membership_;
@@ -193,10 +194,10 @@
 
   // Preconditioner matrix.
   std::unique_ptr<BlockRandomAccessSparseMatrix> m_;
+  std::unique_ptr<CompressedRowSparseMatrix> m_crs_;
   std::unique_ptr<SparseCholesky> sparse_cholesky_;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
 
 #endif  // CERES_INTERNAL_VISIBILITY_BASED_PRECONDITIONER_H_
diff --git a/third_party/ceres/internal/ceres/visibility_based_preconditioner_test.cc b/third_party/ceres/internal/ceres/visibility_based_preconditioner_test.cc
index 10aa619..4d52753 100644
--- a/third_party/ceres/internal/ceres/visibility_based_preconditioner_test.cc
+++ b/third_party/ceres/internal/ceres/visibility_based_preconditioner_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -47,8 +47,7 @@
 #include "glog/logging.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 // TODO(sameeragarwal): Re-enable this test once serialization is
 // working again.
@@ -67,8 +66,8 @@
 //   void SetUp() {
 //     string input_file = TestFileAbsolutePath("problem-6-1384-000.lsqp");
 
-//     std::unique_ptr<LinearLeastSquaresProblem> problem(
-//         CHECK_NOTNULL(CreateLinearLeastSquaresProblemFromFile(input_file)));
+//     std::unique_ptr<LinearLeastSquaresProblem> problem =
+//     CreateLinearLeastSquaresProblemFromFile(input_file));
 //     A_.reset(down_cast<BlockSparseMatrix*>(problem->A.release()));
 //     b_.reset(problem->b.release());
 //     D_.reset(problem->D.release());
@@ -96,7 +95,8 @@
 //     // conditioned.
 //     VectorRef(D_.get(), num_cols_).setConstant(10.0);
 
-//     schur_complement_.reset(new BlockRandomAccessDenseMatrix(blocks));
+//     schur_complement_ =
+//     std::make_unique<BlockRandomAccessDenseMatrix>(blocks);
 //     Vector rhs(schur_complement_->num_rows());
 
 //     std::unique_ptr<SchurEliminatorBase> eliminator;
@@ -104,7 +104,7 @@
 //     eliminator_options.elimination_groups = options_.elimination_groups;
 //     eliminator_options.num_threads = options_.num_threads;
 
-//     eliminator.reset(SchurEliminatorBase::Create(eliminator_options));
+//     eliminator = SchurEliminatorBase::Create(eliminator_options);
 //     eliminator->Init(num_eliminate_blocks_, bs);
 //     eliminator->Eliminate(A_.get(), b_.get(), D_.get(),
 //                           schur_complement_.get(), rhs.data());
@@ -242,8 +242,9 @@
 
 // TEST_F(VisibilityBasedPreconditionerTest, OneClusterClusterJacobi) {
 //   options_.type = CLUSTER_JACOBI;
-//   preconditioner_.reset(
-//       new VisibilityBasedPreconditioner(*A_->block_structure(), options_));
+//   preconditioner_ =
+//       std::make_unique<VisibilityBasedPreconditioner>(
+//          *A_->block_structure(), options_);
 
 //   // Override the clustering to be a single clustering containing all
 //   // the cameras.
@@ -275,7 +276,7 @@
 //     y.setZero();
 //     z.setZero();
 //     x[i] = 1.0;
-//     preconditioner_->RightMultiply(x.data(), y.data());
+//     preconditioner_->RightMultiplyAndAccumulate(x.data(), y.data());
 //     z = full_schur_complement
 //         .selfadjointView<Eigen::Upper>()
 //         .llt().solve(x);
@@ -287,8 +288,9 @@
 
 // TEST_F(VisibilityBasedPreconditionerTest, ClusterJacobi) {
 //   options_.type = CLUSTER_JACOBI;
-//   preconditioner_.reset(
-//       new VisibilityBasedPreconditioner(*A_->block_structure(), options_));
+//   preconditioner_ =
+//   std::make_unique<VisibilityBasedPreconditioner>(*A_->block_structure(),
+//   options_);
 
 //   // Override the clustering to be equal number of cameras.
 //   vector<int>& cluster_membership = *get_mutable_cluster_membership();
@@ -312,8 +314,9 @@
 
 // TEST_F(VisibilityBasedPreconditionerTest, ClusterTridiagonal) {
 //   options_.type = CLUSTER_TRIDIAGONAL;
-//   preconditioner_.reset(
-//       new VisibilityBasedPreconditioner(*A_->block_structure(), options_));
+//   preconditioner_ =
+//     std::make_unique<VisibilityBasedPreconditioner>(*A_->block_structure(),
+//     options_);
 //   static const int kNumClusters = 3;
 
 //   // Override the clustering to be 3 clusters.
@@ -336,5 +339,4 @@
 //   EXPECT_TRUE(PreconditionerValuesMatch());
 // }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/visibility_test.cc b/third_party/ceres/internal/ceres/visibility_test.cc
index a199963..3efc77c 100644
--- a/third_party/ceres/internal/ceres/visibility_test.cc
+++ b/third_party/ceres/internal/ceres/visibility_test.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -40,11 +40,7 @@
 #include "glog/logging.h"
 #include "gtest/gtest.h"
 
-namespace ceres {
-namespace internal {
-
-using std::set;
-using std::vector;
+namespace ceres::internal {
 
 class VisibilityTest : public ::testing::Test {};
 
@@ -60,50 +56,50 @@
 
   // Row 1
   {
-    bs.rows.push_back(CompressedRow());
+    bs.rows.emplace_back();
     CompressedRow& row = bs.rows.back();
     row.block.size = 2;
     row.block.position = 0;
-    row.cells.push_back(Cell(0, 0));
-    row.cells.push_back(Cell(5, 0));
+    row.cells.emplace_back(0, 0);
+    row.cells.emplace_back(5, 0);
   }
 
   // Row 2
   {
-    bs.rows.push_back(CompressedRow());
+    bs.rows.emplace_back();
     CompressedRow& row = bs.rows.back();
     row.block.size = 2;
     row.block.position = 2;
-    row.cells.push_back(Cell(0, 1));
-    row.cells.push_back(Cell(3, 1));
+    row.cells.emplace_back(0, 1);
+    row.cells.emplace_back(3, 1);
   }
 
   // Row 3
   {
-    bs.rows.push_back(CompressedRow());
+    bs.rows.emplace_back();
     CompressedRow& row = bs.rows.back();
     row.block.size = 2;
     row.block.position = 4;
-    row.cells.push_back(Cell(1, 2));
-    row.cells.push_back(Cell(2, 2));
+    row.cells.emplace_back(1, 2);
+    row.cells.emplace_back(2, 2);
   }
 
   // Row 4
   {
-    bs.rows.push_back(CompressedRow());
+    bs.rows.emplace_back();
     CompressedRow& row = bs.rows.back();
     row.block.size = 2;
     row.block.position = 6;
-    row.cells.push_back(Cell(1, 3));
-    row.cells.push_back(Cell(4, 3));
+    row.cells.emplace_back(1, 3);
+    row.cells.emplace_back(4, 3);
   }
   bs.cols.resize(num_cols);
 
-  vector<set<int>> visibility;
+  std::vector<std::set<int>> visibility;
   ComputeVisibility(bs, num_eliminate_blocks, &visibility);
   ASSERT_EQ(visibility.size(), num_cols - num_eliminate_blocks);
-  for (int i = 0; i < visibility.size(); ++i) {
-    ASSERT_EQ(visibility[i].size(), 1);
+  for (const auto& visible : visibility) {
+    ASSERT_EQ(visible.size(), 1);
   }
 
   std::unique_ptr<WeightedGraph<int>> graph(
@@ -139,46 +135,46 @@
 
   // Row 1
   {
-    bs.rows.push_back(CompressedRow());
+    bs.rows.emplace_back();
     CompressedRow& row = bs.rows.back();
     row.block.size = 2;
     row.block.position = 0;
-    row.cells.push_back(Cell(0, 0));
+    row.cells.emplace_back(0, 0);
   }
 
   // Row 2
   {
-    bs.rows.push_back(CompressedRow());
+    bs.rows.emplace_back();
     CompressedRow& row = bs.rows.back();
     row.block.size = 2;
     row.block.position = 2;
-    row.cells.push_back(Cell(0, 1));
+    row.cells.emplace_back(0, 1);
   }
 
   // Row 3
   {
-    bs.rows.push_back(CompressedRow());
+    bs.rows.emplace_back();
     CompressedRow& row = bs.rows.back();
     row.block.size = 2;
     row.block.position = 4;
-    row.cells.push_back(Cell(1, 2));
+    row.cells.emplace_back(1, 2);
   }
 
   // Row 4
   {
-    bs.rows.push_back(CompressedRow());
+    bs.rows.emplace_back();
     CompressedRow& row = bs.rows.back();
     row.block.size = 2;
     row.block.position = 6;
-    row.cells.push_back(Cell(1, 3));
+    row.cells.emplace_back(1, 3);
   }
   bs.cols.resize(num_cols);
 
-  vector<set<int>> visibility;
+  std::vector<std::set<int>> visibility;
   ComputeVisibility(bs, num_eliminate_blocks, &visibility);
   ASSERT_EQ(visibility.size(), num_cols - num_eliminate_blocks);
-  for (int i = 0; i < visibility.size(); ++i) {
-    ASSERT_EQ(visibility[i].size(), 0);
+  for (const auto& visible : visibility) {
+    ASSERT_EQ(visible.size(), 0);
   }
 
   std::unique_ptr<WeightedGraph<int>> graph(
@@ -201,5 +197,4 @@
   }
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/wall_time.cc b/third_party/ceres/internal/ceres/wall_time.cc
index 7163927..2f4cf28 100644
--- a/third_party/ceres/internal/ceres/wall_time.cc
+++ b/third_party/ceres/internal/ceres/wall_time.cc
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -30,11 +30,9 @@
 
 #include "ceres/wall_time.h"
 
-#ifdef CERES_USE_OPENMP
-#include <omp.h>
-#else
 #include <ctime>
-#endif
+
+#include "ceres/internal/config.h"
 
 #ifdef _WIN32
 #include <windows.h>
@@ -42,13 +40,9 @@
 #include <sys/time.h>
 #endif
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
 double WallTimeInSeconds() {
-#ifdef CERES_USE_OPENMP
-  return omp_get_wtime();
-#else
 #ifdef _WIN32
   LARGE_INTEGER count;
   LARGE_INTEGER frequency;
@@ -58,10 +52,9 @@
          static_cast<double>(frequency.QuadPart);
 #else
   timeval time_val;
-  gettimeofday(&time_val, NULL);
+  gettimeofday(&time_val, nullptr);
   return (time_val.tv_sec + time_val.tv_usec * 1e-6);
 #endif
-#endif
 }
 
 EventLogger::EventLogger(const std::string& logger_name) {
@@ -72,7 +65,7 @@
   start_time_ = WallTimeInSeconds();
   last_event_time_ = start_time_;
   events_ = StringPrintf(
-      "\n%s\n                                   Delta   Cumulative\n",
+      "\n%s\n                                        Delta   Cumulative\n",
       logger_name.c_str());
 }
 
@@ -101,5 +94,4 @@
                 absolute_time_delta);
 }
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
diff --git a/third_party/ceres/internal/ceres/wall_time.h b/third_party/ceres/internal/ceres/wall_time.h
index 9c92e9e..f99052b 100644
--- a/third_party/ceres/internal/ceres/wall_time.h
+++ b/third_party/ceres/internal/ceres/wall_time.h
@@ -1,5 +1,5 @@
 // Ceres Solver - A fast non-linear least squares minimizer
-// Copyright 2015 Google Inc. All rights reserved.
+// Copyright 2023 Google Inc. All rights reserved.
 // http://ceres-solver.org/
 //
 // Redistribution and use in source and binary forms, with or without
@@ -34,18 +34,16 @@
 #include <map>
 #include <string>
 
-#include "ceres/internal/port.h"
+#include "ceres/internal/disable_warnings.h"
+#include "ceres/internal/export.h"
 #include "ceres/stringprintf.h"
 #include "glog/logging.h"
 
-namespace ceres {
-namespace internal {
+namespace ceres::internal {
 
-// Returns time, in seconds, from some arbitrary starting point. If
-// OpenMP is available then the high precision openmp_get_wtime()
-// function is used. Otherwise on unixes, gettimeofday is used. The
-// granularity is in seconds on windows systems.
-CERES_EXPORT_INTERNAL double WallTimeInSeconds();
+// Returns time, in seconds, from some arbitrary starting point. On unixes,
+// gettimeofday is used. The granularity is microseconds.
+CERES_NO_EXPORT double WallTimeInSeconds();
 
 // Log a series of events, recording for each event the time elapsed
 // since the last event and since the creation of the object.
@@ -71,7 +69,7 @@
 //      Bar1:  time1  time1
 //      Bar2:  time2  time1 + time2;
 //     Total:  time3  time1 + time2 + time3;
-class EventLogger {
+class CERES_NO_EXPORT EventLogger {
  public:
   explicit EventLogger(const std::string& logger_name);
   ~EventLogger();
@@ -83,7 +81,8 @@
   std::string events_;
 };
 
-}  // namespace internal
-}  // namespace ceres
+}  // namespace ceres::internal
+
+#include "ceres/internal/reenable_warnings.h"
 
 #endif  // CERES_INTERNAL_WALL_TIME_H_
diff --git a/third_party/ceres/package.xml b/third_party/ceres/package.xml
index e7e3e02..9d43e43 100644
--- a/third_party/ceres/package.xml
+++ b/third_party/ceres/package.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0"?>
 <!--
-  Copyright 2017 Google Inc. All rights reserved.
+  Copyright 2023 Google Inc. All rights reserved.
   http://ceres-solver.org/
 
   Redistribution and use in source and binary forms, with or without
@@ -30,7 +30,7 @@
 
 <package format="2">
   <name>ceres-solver</name>
-  <version>2.0.0</version>
+  <version>2.2.0</version>
   <description>A large scale non-linear optimization library.</description>
   <maintainer email="ceres-solver@googlegroups.com">
     The Ceres Solver Authors
diff --git a/third_party/ceres/scripts/make_docs.py b/third_party/ceres/scripts/make_docs.py
index 7d5c4cd..9eab97e 100644
--- a/third_party/ceres/scripts/make_docs.py
+++ b/third_party/ceres/scripts/make_docs.py
@@ -1,8 +1,8 @@
-#!/usr/bin/python
+#!/usr/bin/python3
 # encoding: utf-8
 #
 # Ceres Solver - A fast non-linear least squares minimizer
-# Copyright 2015 Google Inc. All rights reserved.
+# Copyright 2023 Google Inc. All rights reserved.
 # http://ceres-solver.org/
 #
 # Redistribution and use in source and binary forms, with or without
@@ -60,7 +60,7 @@
   sphinx_exe = sys.argv[3]
 
 # Run Sphinx to build the documentation.
-os.system('%s -b html -d %s %s %s' %(sphinx_exe, cache_dir, src_dir, html_dir))
+os.system('%s -n -a -d %s %s %s' %(sphinx_exe, cache_dir, src_dir, html_dir))
 
 replacements = [
   # The title for the homepage is not ideal, so change it.
diff --git a/third_party/ceres/scripts/make_release b/third_party/ceres/scripts/make_release
index ce5d5cd..8ec84bf 100755
--- a/third_party/ceres/scripts/make_release
+++ b/third_party/ceres/scripts/make_release
@@ -1,7 +1,7 @@
 #!/bin/bash
 #
 # Ceres Solver - A fast non-linear least squares minimizer
-# Copyright 2015 Google Inc. All rights reserved.
+# Copyright 2023 Google Inc. All rights reserved.
 # http://ceres-solver.org/
 #
 # Redistribution and use in source and binary forms, with or without
@@ -63,7 +63,7 @@
 echo "$GIT_COMMIT" >> $VERSIONFILE
 
 # Build the documentation.
-python $TMP/scripts/make_docs.py $TMP $DOCS_TMP
+python3 $TMP/scripts/make_docs.py $TMP $DOCS_TMP
 cp -pr $DOCS_TMP/html $TMP/docs
 
 # Build the tarball.
diff --git a/third_party/ceres/travis/install_travis_linux_deps.sh b/third_party/ceres/travis/install_travis_linux_deps.sh
deleted file mode 100755
index fd7cc78..0000000
--- a/third_party/ceres/travis/install_travis_linux_deps.sh
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/bash
-
-# Stop processing on any error.
-set -e
-
-# Install default versions of standard dependencies that are new enough in 18.04
-sudo apt-get install -y cmake
-sudo apt-get install -y libatlas-base-dev libsuitesparse-dev
-sudo apt-get install -y libgoogle-glog-dev libgflags-dev
-sudo apt-get install -y libeigen3-dev
diff --git a/third_party/ceres/travis/install_travis_osx_deps.sh b/third_party/ceres/travis/install_travis_osx_deps.sh
deleted file mode 100755
index adb949e..0000000
--- a/third_party/ceres/travis/install_travis_osx_deps.sh
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/bin/bash
-
-# Stop processing on any error.
-set -e
-
-function install_if_not_installed() {
-  declare -r formula="$1"
-  if [[ $(brew list ${formula} &>/dev/null; echo $?) -ne 0 ]]; then
-    brew install ${formula}
-  else
-    echo "$0 - ${formula} is already installed."
-  fi
-}
-
-# Manually trigger an update prior to installing packages to avoid Ruby
-# version related errors as per [1].
-#
-# [1]: https://github.com/travis-ci/travis-ci/issues/8552
-brew update
-
-install_if_not_installed cmake
-install_if_not_installed glog
-install_if_not_installed gflags
-install_if_not_installed eigen
-install_if_not_installed suite-sparse
diff --git a/third_party/cuco/BUILD b/third_party/cuco/BUILD
deleted file mode 100644
index 5b878ee..0000000
--- a/third_party/cuco/BUILD
+++ /dev/null
@@ -1 +0,0 @@
-exports_files(["cuco.BUILD", "template.patch"])
diff --git a/third_party/cuco/cuco.BUILD b/third_party/cuco/cuco.BUILD
deleted file mode 100644
index f88e569..0000000
--- a/third_party/cuco/cuco.BUILD
+++ /dev/null
@@ -1,15 +0,0 @@
-cc_library(
-    name = "cuco",
-    hdrs = glob(include = ["include/**"]),
-    defines = [
-        "__CUDACC_RELAXED_CONSTEXPR__",
-        "__CUDACC_EXTENDED_LAMBDA__",
-    ],
-    features = ["cuda"],
-    includes = ["include"],
-    target_compatible_with = [
-        "@//tools/platforms/gpu:nvidia",
-        "@platforms//os:linux",
-    ],
-    visibility = ["//visibility:public"],
-)
diff --git a/third_party/cuco/template.patch b/third_party/cuco/template.patch
deleted file mode 100644
index 488eb9e..0000000
--- a/third_party/cuco/template.patch
+++ /dev/null
@@ -1,138 +0,0 @@
-diff --git a/include/cuco/detail/pair/pair.inl b/include/cuco/detail/pair/pair.inl
-index 3279a91..44be993 100644
---- a/include/cuco/detail/pair/pair.inl
-+++ b/include/cuco/detail/pair/pair.inl
-@@ -51,7 +51,53 @@ __host__ __device__ constexpr bool operator==(cuco::pair<T1, T2> const& lhs,
- }  // namespace cuco
- 
- namespace thrust {
--#include <cuco/detail/pair/tuple_helpers.inl>
-+template <std::size_t I, typename T1, typename T2>
-+__host__ __device__ constexpr auto get(cuco::pair<T1, T2>& p) ->
-+  typename tuple_element<I, cuco::pair<T1, T2>>::type&
-+{
-+  static_assert(I < 2);
-+  if constexpr (I == 0) {
-+    return p.first;
-+  } else {
-+    return p.second;
-+  }
-+}
-+
-+template <std::size_t I, typename T1, typename T2>
-+__host__ __device__ constexpr auto get(cuco::pair<T1, T2>&& p) ->
-+  typename tuple_element<I, cuco::pair<T1, T2>>::type&&
-+{
-+  static_assert(I < 2);
-+  if constexpr (I == 0) {
-+    return std::move(p.first);
-+  } else {
-+    return std::move(p.second);
-+  }
-+}
-+
-+template <std::size_t I, typename T1, typename T2>
-+__host__ __device__ constexpr auto get(cuco::pair<T1, T2> const& p) ->
-+  typename tuple_element<I, cuco::pair<T1, T2>>::type const&
-+{
-+  static_assert(I < 2);
-+  if constexpr (I == 0) {
-+    return p.first;
-+  } else {
-+    return p.second;
-+  }
-+}
-+
-+template <std::size_t I, typename T1, typename T2>
-+__host__ __device__ constexpr auto get(cuco::pair<T1, T2> const&& p) ->
-+  typename tuple_element<I, cuco::pair<T1, T2>>::type const&&
-+{
-+  static_assert(I < 2);
-+  if constexpr (I == 0) {
-+    return std::move(p.first);
-+  } else {
-+    return std::move(p.second);
-+  }
-+}
- }  // namespace thrust
- 
- namespace cuda::std {
-diff --git a/include/cuco/detail/static_map.inl b/include/cuco/detail/static_map.inl
-index 48799a7..336f6de 100644
---- a/include/cuco/detail/static_map.inl
-+++ b/include/cuco/detail/static_map.inl
-@@ -443,7 +443,7 @@ __device__
-                 "insert_and_find is not supported for unpackable data on pre-Volta GPUs.");
- #endif
- 
--  auto current_slot{initial_slot(insert_pair.first, hash)};
-+  auto current_slot{this->initial_slot(insert_pair.first, hash)};
- 
-   while (true) {
-     key_type const existing_key = current_slot->first.load(cuda::std::memory_order_relaxed);
-@@ -514,7 +514,7 @@ __device__
- 
-     // if we couldn't insert the key, but it wasn't a duplicate, then there must
-     // have been some other key there, so we keep looking for a slot
--    current_slot = next_slot(current_slot);
-+    current_slot = this->next_slot(current_slot);
-   }
- }
- 
-diff --git a/include/cuco/detail/static_map/static_map_ref.inl b/include/cuco/detail/static_map/static_map_ref.inl
-index f27f21e..e90948f 100644
---- a/include/cuco/detail/static_map/static_map_ref.inl
-+++ b/include/cuco/detail/static_map/static_map_ref.inl
-@@ -141,21 +141,6 @@ static_map_ref<Key, T, Scope, KeyEqual, ProbingScheme, StorageRef, Operators...>
-   return impl_.empty_value_sentinel();
- }
- 
--template <typename Key,
--          typename T,
--          cuda::thread_scope Scope,
--          typename KeyEqual,
--          typename ProbingScheme,
--          typename StorageRef,
--          typename... Operators>
--template <typename... NewOperators>
--auto static_map_ref<Key, T, Scope, KeyEqual, ProbingScheme, StorageRef, Operators...>::with(
--  NewOperators...) && noexcept
--{
--  return static_map_ref<Key, T, Scope, KeyEqual, ProbingScheme, StorageRef, NewOperators...>(
--    std::move(*this));
--}
--
- namespace detail {
- 
- template <typename Key,
-diff --git a/include/cuco/pair.cuh b/include/cuco/pair.cuh
-index d28cae5..1caaa24 100644
---- a/include/cuco/pair.cuh
-+++ b/include/cuco/pair.cuh
-@@ -87,8 +87,7 @@ struct alignas(detail::pair_alignment<First, Second>()) pair {
-    */
-   template <typename T, std::enable_if_t<detail::is_std_pair_like<T>::value>* = nullptr>
-   __host__ __device__ constexpr pair(T const& p)
--    : pair{cuda::std::get<0>(thrust::raw_reference_cast(p)),
--           cuda::std::get<1>(thrust::raw_reference_cast(p))}
-+    : pair{std::get<0>(thrust::raw_reference_cast(p)), std::get<1>(thrust::raw_reference_cast(p))}
-   {
-   }
- 
-diff --git a/include/cuco/static_map_ref.cuh b/include/cuco/static_map_ref.cuh
-index 88e40f8..7cf1d74 100644
---- a/include/cuco/static_map_ref.cuh
-+++ b/include/cuco/static_map_ref.cuh
-@@ -174,7 +174,11 @@ class static_map_ref
-    * @return `*this` with `NewOperators...`
-    */
-   template <typename... NewOperators>
--  [[nodiscard]] __host__ __device__ auto with(NewOperators... ops) && noexcept;
-+  [[nodiscard]] __host__ __device__ auto with(NewOperators... ops) && noexcept
-+  {
-+    return static_map_ref<Key, T, Scope, KeyEqual, ProbingScheme, StorageRef, NewOperators...>(
-+      std::move(*this));
-+  }
- 
-  private:
-   impl_type impl_;  ///< Static map ref implementation
diff --git a/third_party/flatbuffers/tests/ts/test_dir/BUILD.bazel b/third_party/flatbuffers/tests/ts/test_dir/BUILD.bazel
index 768fe83..8b0acca 100644
--- a/third_party/flatbuffers/tests/ts/test_dir/BUILD.bazel
+++ b/third_party/flatbuffers/tests/ts/test_dir/BUILD.bazel
@@ -10,5 +10,5 @@
     name = "include_ts_fbs",
     srcs = ["typescript_include.fbs"],
     visibility = ["//visibility:public"],
-    deps = [":typescript_transitive_ts_ts_fbs"],
+    deps = [":typescript_transitive_ts_fbs"],
 )
diff --git a/third_party/gmp/.gdbinit b/third_party/gmp/.gdbinit
new file mode 100644
index 0000000..2a17063
--- /dev/null
+++ b/third_party/gmp/.gdbinit
@@ -0,0 +1,42 @@
+# Copyright 1999 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+
+define pz
+set __gmpz_dump ($)
+end
+
+define pq
+set __gmpz_dump ($->_mp_num)
+echo /
+set __gmpz_dump ($->_mp_den)
+end
+
+define pf
+set __gmpf_dump ($)
+end
diff --git a/third_party/gmp/AUTHORS b/third_party/gmp/AUTHORS
new file mode 100644
index 0000000..3c38ef3
--- /dev/null
+++ b/third_party/gmp/AUTHORS
@@ -0,0 +1,106 @@
+Authors of GNU MP (in chronological order of initial contribution)
+
+Torbjörn Granlund	Main author
+
+John Amanatides		Original version of mpz/pprime_p.c
+
+Paul Zimmermann		mpn/generic/mul_fft.c, now defunct dc_divrem_n.c,
+			rootrem.c, old mpz/powm.c, old toom3 code.
+
+Ken Weber		Now defunct mpn/generic/bdivmod.c, old mpn/generic/gcd.c
+
+Bennet Yee		Previous versions of mpz/jacobi.c mpz/legendre.c
+
+Andreas Schwab		mpn/m68k/lshift.asm, mpn/m68k/rshift.asm
+
+Robert Harley		Old mpn/generic/mul_n.c, previous versions of files in
+			mpn/arm
+
+Linus Nordberg		Random number framework, original autoconfery
+
+Kent Boortz		MacOS 9 port, now defunct.
+
+Kevin Ryde		Most x86 assembly, new autoconfery, and countless other
+			things (please see the GMP manual for complete list)
+
+Gerardo Ballabio	gmpxx.h and C++ istream input
+
+Pedro Gimeno		Mersenne Twister random generator, other random number
+			revisions
+
+Jason Moxham		Previous versions of mpz/fac_ui.c and gen-fac_ui.c
+
+Niels Möller		gen-jacobitab.c,
+			mpn/generic/hgcd2.c, hgcd.c, hgcd_step.c,
+			hgcd_appr.c, hgcd_matrix.c, hgcd_reduce.c,
+			gcd.c, gcd_11.c, gcd_22.c, gcdext.c, matrix22_mul.c,
+			gcdext_1.c, gcd_subdiv_step.c, gcd_lehmer.c,
+			gcdext_subdiv_step.c, gcdext_lehmer.c,
+			jacobi_2.c, jacbase.c, hgcd_jacobi.c, hgcd2_jacobi.c,
+			matrix22_mul1_inverse_vector.c,
+			toom_interpolate_7pts, mulmod_bnm1.c, dcpi1_bdiv_qr.c,
+			dcpi1_bdiv_q.c, sbpi1_bdiv_qr.c, sbpi1_bdiv_q.c,
+			sec_invert.c,
+			toom_eval_dgr3_pm1.c, toom_eval_dgr3_pm2.c,
+			toom_eval_pm1.c, toom_eval_pm2.c, toom_eval_pm2exp.c,
+			divexact.c, mod_1_1.c, div_qr_2.c,
+			div_qr_2n_pi1.c, div_qr_2u_pi1.c, broot.c,
+			brootinv.c,
+			mpn/x86/k7/invert_limb.asm, mod_1_1.asm,
+			mpn/x86_64/invert_limb.asm,
+			invert_limb_table.asm, mod_1_1.asm,
+			div_qr_2n_pi1.asm, div_qr_2u_pi1.asm,
+			mpn/x86_64/core2/aorsmul_1.asm,
+			mpz/nextprime.c, divexact.c, gcd.c, gcdext.c,
+			jacobi.c, combit.c, mini-gmp/mini-gmp.c.
+
+Marco Bodrato		mpn/generic/toom44_mul.c, toom4_sqr.c, toom53_mul.c,
+			toom62_mul.c, toom43_mul.c, toom52_mul.c, toom54_mul.c,
+			toom_interpolate_6pts.c, toom_couple_handling.c,
+			toom63_mul.c, toom_interpolate_8pts.c,
+			toom6h_mul.c, toom6_sqr.c, toom_interpolate_12pts.c,
+			toom8h_mul.c, toom8_sqr.c, toom_interpolate_16pts.c,
+			mulmod_bnm1.c, sqrmod_bnm1.c, nussbaumer_mul.c,
+			toom_eval_pm2.c, toom_eval_pm2rexp.c,
+			fib2m.c, strongfibo.c,
+			mullo_n.c, sqrlo.c, invert.c, invertappr.c;
+			mpn/x86/atom/aors_n.asm, aorslshC_n.asm,
+			aorrlsh{1,2,C}_n.asm, aorsmul_1.asm, logops_n.asm,
+			sublsh2_n.asm, rshift.asm; primesieve.c;
+			mpz/fac_ui.c, 2fac_ui.c, mfac_uiui.c, oddfac_1.c,
+			primorial_ui.c, prodlimbs.c, bin_ui.c,
+			lucmod.c, stronglucas.c,
+			goetgheluck_bin_uiui.c; mini-gmp/mini-mpq.c.
+
+David Harvey		mpn/generic/add_err1_n.c, add_err2_n.c,
+			add_err3_n.c, sub_err1_n.c, sub_err2_n.c,
+			sub_err3_n.c, mulmid_basecase.c, mulmid_n.c,
+			toom42_mulmid.c,
+			mpn/x86_64/mul_basecase.asm, aors_err1_n.asm,
+			aors_err2_n.asm, aors_err3_n.asm,
+			mulmid_basecase.asm,
+			mpn/x86_64/core2/aors_err1_n.asm.
+
+Martin Boij		mpn/generic/perfpow.c
+
+Marc Glisse		gmpxx.h improvements
+
+David Miller		mpn/sparc32/ultrasparct1/{addmul_1,mul_1,submul_1}.asm
+			mpn/sparc64/ultrasparct3/{mul_1,addmul_1,submul_1}.asm
+			mpn/sparc64/ultrasparct3/{add_n,sub_n}.asm
+			mpn/sparc64/ultrasparct3/{popcount,hamdist}.asm
+			mpn/sparc64/ultrasparct3/cnd_aors_n.asm
+			mpn/sparc64/{rshift,lshift,lshiftc}.asm
+			mpn/sparc64/tabselect.asm
+
+Mark Sofroniou		mpn/generic/mul_fft.c type cleanup.
+
+Ulrich Weigand		Changes to support powerpc64le:
+			configure.ac, mpn/powerpc64/{elf,aix,darwin}.m4,
+			mpn/powerpc32/{darwin,elf}.m4,
+			mpn/powerpc64/mode64/{dive_1,divrem_1,divrem_2}.asm,
+			mpn/powerpc64/mode64/{gcd_1,invert_limb,mode1o}.asm,
+			mpn/powerpc64/mode64/{mod_1_1,mod_1_4}.asm,
+			mpn/powerpc64/mode64/p7/gcd_1.asm,
+			mpn/powerpc64/p6/{lshift,lshiftc,rshift}.asm,
+			mpn/powerpc64/vmx/popcount.asm.
diff --git a/third_party/gmp/BUILD b/third_party/gmp/BUILD
new file mode 100644
index 0000000..3630e9f
--- /dev/null
+++ b/third_party/gmp/BUILD
@@ -0,0 +1,1286 @@
+load("@//tools/build_rules:select.bzl", "address_size_select", "cpu_select")
+load(
+    ":mpn.bzl",
+    "architecture_includes",
+    "config_include_from_architecture",
+    "current_directory",
+    "file_from_architecture",
+    "mparam_path",
+    "mpn_cc_library",
+    "mpn_m4_cc_library",
+)
+
+licenses(["reciprocal"])
+
+architecture_paths = {
+    "@//tools:cpu_k8": [
+        "x86_64",
+        "generic",
+    ],
+    "@//tools:cpu_roborio": [
+        "arm/v7a/cora9",
+        "arm/v6t2",
+        "arm/v6",
+        "arm/v5",
+        "arm",
+        "generic",
+    ],
+    "@//tools:cpu_cortex_m4f": [
+        "arm",
+        "generic",
+    ],
+    "@//tools:cpu_arm64": [
+        "arm64",
+        "generic",
+    ],
+    # TODO(phil): Support this properly.
+    #"@//tools:cpu_cortex_m4f_k22": [
+    #    "arm",
+    #    "generic",
+    #],
+}
+
+# gmp's tools leak memory on purpose. Just skip asan for them.
+tool_features = ["-asan"]
+
+genrule(
+    name = "gmp_h_copy",
+    srcs = file_from_architecture(architecture_paths, "gmp.h"),
+    outs = ["gmp.h"],
+    cmd = "cp $< $@",
+    target_compatible_with = ["@platforms//os:linux"],
+)
+
+genrule(
+    name = "config_m4_copy",
+    srcs = file_from_architecture(architecture_paths, "config.m4"),
+    outs = ["config.m4"],
+    cmd = "cp $< $@",
+    target_compatible_with = ["@platforms//os:linux"],
+)
+
+copts_common = [
+    "-Wno-error",
+    "-Wno-unused-but-set-variable",
+    "-Wno-format-nonliteral",
+    "-Wno-unused-parameter",
+    "-Wno-missing-field-initializers",
+    "-DHAVE_CONFIG_H",
+    "-I" + current_directory(),
+    "-I$(GENDIR)/" + current_directory(),
+    "-I" + current_directory() + "/mpn",
+    "-I$(GENDIR)/" + current_directory() + "/mpn",
+    "-Wno-cast-align",
+    "-Wno-dangling-else",
+    "-Wno-cast-qual",
+    "-Wno-sign-compare",
+    "-Wno-unused-function",
+    "-Wno-unused-value",
+    "-Wno-unknown-warning-option",
+    "-Wno-unused-variable",
+] + architecture_includes(architecture_paths) + cpu_select({
+    "arm": [
+        "-Wno-old-style-declaration",
+        "-Wno-maybe-uninitialized",
+        "-Wno-empty-body",
+        "-Wno-implicit-fallthrough",
+    ],
+    "amd64": [],
+}) + config_include_from_architecture(architecture_paths)
+
+ccopts = copts_common + [
+    "-D__GMP_WITHIN_GMPXX",
+    "-Wno-unused-label",
+]
+
+copts = copts_common + [
+    "-D__GMP_WITHIN_GMP",
+    "-Wno-bitwise-conditional-parentheses",
+]
+
+cc_library(
+    name = "bootstrap",
+    target_compatible_with = ["@platforms//os:linux"],
+    textual_hdrs = [
+        "bootstrap.c",
+        "mini-gmp/mini-gmp.c",
+        "mini-gmp/mini-gmp.h",
+    ],
+)
+
+cc_binary(
+    name = "gen-fac",
+    srcs = ["gen-fac.c"],
+    copts = copts,
+    features = tool_features,
+    target_compatible_with = ["@platforms//os:linux"],
+    deps = [":bootstrap"],
+)
+
+nail_bits = "0"
+
+limb_bits = address_size_select({
+    "64": "64",
+    "32": "32",
+})
+
+genrule(
+    name = "fac_table_h",
+    outs = ["fac_table.h"],
+    cmd = "$(location :gen-fac) " + limb_bits + " " + nail_bits + " > $@",
+    target_compatible_with = ["@platforms//os:linux"],
+    tools = [":gen-fac"],
+)
+
+cc_binary(
+    name = "gen-fib",
+    srcs = ["gen-fib.c"],
+    copts = copts,
+    features = tool_features,
+    target_compatible_with = ["@platforms//os:linux"],
+    deps = [":bootstrap"],
+)
+
+genrule(
+    name = "fib_table_h",
+    outs = ["fib_table.h"],
+    cmd = "$(location :gen-fib) header " + limb_bits + " " + nail_bits + " > $@",
+    target_compatible_with = ["@platforms//os:linux"],
+    tools = [":gen-fib"],
+)
+
+genrule(
+    name = "fib_table_c",
+    outs = ["mpn/fib_table.c"],
+    cmd = "$(location :gen-fib) table " + limb_bits + " " + nail_bits + " > $@",
+    target_compatible_with = ["@platforms//os:linux"],
+    tools = [":gen-fib"],
+)
+
+cc_binary(
+    name = "gen-bases",
+    srcs = ["gen-bases.c"],
+    copts = copts,
+    features = tool_features,
+    target_compatible_with = ["@platforms//os:linux"],
+    deps = [":bootstrap"],
+)
+
+genrule(
+    name = "mp_bases_h",
+    outs = ["mp_bases.h"],
+    cmd = "$(location :gen-bases) header " + limb_bits + " " + nail_bits + " > $@",
+    target_compatible_with = ["@platforms//os:linux"],
+    tools = [":gen-bases"],
+)
+
+genrule(
+    name = "mp_bases_c",
+    outs = ["mpn/mp_bases.c"],
+    cmd = "$(location :gen-bases) table " + limb_bits + " " + nail_bits + " > $@",
+    target_compatible_with = ["@platforms//os:linux"],
+    tools = [":gen-bases"],
+)
+
+cc_binary(
+    name = "gen-trialdivtab",
+    srcs = ["gen-trialdivtab.c"],
+    copts = copts,
+    features = tool_features,
+    target_compatible_with = ["@platforms//os:linux"],
+    deps = [":bootstrap"],
+)
+
+genrule(
+    name = "trialdivtab_h",
+    outs = ["trialdivtab.h"],
+    cmd = "$(location :gen-trialdivtab) " + limb_bits + " 8000 > $@",
+    target_compatible_with = ["@platforms//os:linux"],
+    tools = [":gen-trialdivtab"],
+)
+
+cc_binary(
+    name = "gen-jacobitab",
+    srcs = ["gen-jacobitab.c"],
+    copts = copts,
+    target_compatible_with = ["@platforms//os:linux"],
+    deps = [":bootstrap"],
+)
+
+genrule(
+    name = "jacobitab_h",
+    outs = ["mpn/jacobitab.h"],
+    cmd = "$(location :gen-jacobitab) > $@",
+    target_compatible_with = ["@platforms//os:linux"],
+    tools = [":gen-jacobitab"],
+)
+
+cc_binary(
+    name = "gen-psqr",
+    srcs = ["gen-psqr.c"],
+    copts = copts,
+    target_compatible_with = ["@platforms//os:linux"],
+    deps = [":bootstrap"],
+)
+
+genrule(
+    name = "perfsqr_h",
+    outs = ["mpn/perfsqr.h"],
+    cmd = "$(location :gen-psqr) " + limb_bits + " " + nail_bits + " > $@",
+    target_compatible_with = ["@platforms//os:linux"],
+    tools = [":gen-psqr"],
+)
+
+extra_functions = ["invert_limb_table"]
+
+gmp_mpn_functions_optional = extra_functions + [
+    "umul",
+    "udiv",
+    "invert_limb",
+    "sqr_diagonal",
+    "sqr_diag_addlsh1",
+    "mul_2",
+    "mul_3",
+    "mul_4",
+    "mul_5",
+    "mul_6",
+    "addmul_2",
+    "addmul_3",
+    "addmul_4",
+    "addmul_5",
+    "addmul_6",
+    "addmul_7",
+    "addmul_8",
+    "addlsh1_n",
+    "sublsh1_n",
+    "rsblsh1_n",
+    "rsh1add_n",
+    "rsh1sub_n",
+    "addlsh2_n",
+    "sublsh2_n",
+    "rsblsh2_n",
+    "addlsh_n",
+    "sublsh_n",
+    "rsblsh_n",
+    "add_n_sub_n",
+    "addaddmul_1msb0",
+]
+
+gmp_mpn_functions = [
+    "add",
+    "add_1",
+    "add_n",
+    "sub",
+    "sub_1",
+    "sub_n",
+    "cnd_add_n",
+    "cnd_sub_n",
+    "cnd_swap",
+    "neg",
+    "com",
+    "mul_1",
+    "addmul_1",
+    "submul_1",
+    "add_err1_n",
+    "add_err2_n",
+    "add_err3_n",
+    "sub_err1_n",
+    "sub_err2_n",
+    "sub_err3_n",
+    "lshift",
+    "rshift",
+    "dive_1",
+    "diveby3",
+    "divis",
+    "divrem",
+    "divrem_1",
+    "divrem_2",
+    "fib2_ui",
+    "fib2m",
+    "mod_1",
+    "mod_34lsub1",
+    "mode1o",
+    "pre_mod_1",
+    "dump",
+    "mod_1_1",
+    "mod_1_2",
+    "mod_1_3",
+    "mod_1_4",
+    "lshiftc",
+    "mul",
+    "mul_fft",
+    "mul_n",
+    "sqr",
+    "mul_basecase",
+    "sqr_basecase",
+    "nussbaumer_mul",
+    "mulmid_basecase",
+    "toom42_mulmid",
+    "mulmid_n",
+    "mulmid",
+    "random",
+    "random2",
+    "pow_1",
+    "rootrem",
+    "sqrtrem",
+    "sizeinbase",
+    "get_str",
+    "set_str",
+    "compute_powtab",
+    "scan0",
+    "scan1",
+    "popcount",
+    "hamdist",
+    "cmp",
+    "zero_p",
+    "perfsqr",
+    "perfpow",
+    "strongfibo",
+    "gcd_11",
+    "gcd_22",
+    "gcd_1",
+    "gcd",
+    "gcdext_1",
+    "gcdext",
+    "gcd_subdiv_step",
+    "gcdext_lehmer",
+    "div_q",
+    "tdiv_qr",
+    "jacbase",
+    "jacobi_2",
+    "jacobi",
+    "get_d",
+    "matrix22_mul",
+    "matrix22_mul1_inverse_vector",
+    "hgcd_matrix",
+    "hgcd2",
+    "hgcd_step",
+    "hgcd_reduce",
+    "hgcd",
+    "hgcd_appr",
+    "hgcd2_jacobi",
+    "hgcd_jacobi",
+    "mullo_n",
+    "mullo_basecase",
+    "sqrlo",
+    "sqrlo_basecase",
+    "toom22_mul",
+    "toom32_mul",
+    "toom42_mul",
+    "toom52_mul",
+    "toom62_mul",
+    "toom33_mul",
+    "toom43_mul",
+    "toom53_mul",
+    "toom54_mul",
+    "toom63_mul",
+    "toom44_mul",
+    "toom6h_mul",
+    "toom6_sqr",
+    "toom8h_mul",
+    "toom8_sqr",
+    "toom_couple_handling",
+    "toom2_sqr",
+    "toom3_sqr",
+    "toom4_sqr",
+    "toom_eval_dgr3_pm1",
+    "toom_eval_dgr3_pm2",
+    "toom_eval_pm1",
+    "toom_eval_pm2",
+    "toom_eval_pm2exp",
+    "toom_eval_pm2rexp",
+    "toom_interpolate_5pts",
+    "toom_interpolate_6pts",
+    "toom_interpolate_7pts",
+    "toom_interpolate_8pts",
+    "toom_interpolate_12pts",
+    "toom_interpolate_16pts",
+    "invertappr",
+    "invert",
+    "binvert",
+    "mulmod_bnm1",
+    "sqrmod_bnm1",
+    "div_qr_1",
+    "div_qr_1n_pi1",
+    "div_qr_2",
+    "div_qr_2n_pi1",
+    "div_qr_2u_pi1",
+    "sbpi1_div_q",
+    "sbpi1_div_qr",
+    "sbpi1_divappr_q",
+    "dcpi1_div_q",
+    "dcpi1_div_qr",
+    "dcpi1_divappr_q",
+    "mu_div_qr",
+    "mu_divappr_q",
+    "mu_div_q",
+    "bdiv_q_1",
+    "sbpi1_bdiv_q",
+    "sbpi1_bdiv_qr",
+    "sbpi1_bdiv_r",
+    "dcpi1_bdiv_q",
+    "dcpi1_bdiv_qr",
+    "mu_bdiv_q",
+    "mu_bdiv_qr",
+    "bdiv_q",
+    "bdiv_qr",
+    "broot",
+    "brootinv",
+    "bsqrt",
+    "bsqrtinv",
+    "divexact",
+    "bdiv_dbm1c",
+    "redc_1",
+    "redc_2",
+    "redc_n",
+    "powm",
+    "powlo",
+    "sec_powm",
+    "sec_mul",
+    "sec_sqr",
+    "sec_div_qr",
+    "sec_div_r",
+    "sec_pi1_div_qr",
+    "sec_pi1_div_r",
+    "sec_add_1",
+    "sec_sub_1",
+    "sec_invert",
+    "trialdiv",
+    "remove",
+    "and_n",
+    "andn_n",
+    "nand_n",
+    "ior_n",
+    "iorn_n",
+    "nior_n",
+    "xor_n",
+    "xnor_n",
+    "copyi",
+    "copyd",
+    "zero",
+    "sec_tabselect",
+    "comb_tables",
+] + gmp_mpn_functions_optional
+
+gmp_mpn_functions_cpu_aarch64 = ["pre_divrem_1"]
+
+gmp_mpn_functions_cpu_select = cpu_select({
+    "arm64": ["pre_divrem_1"],
+    "arm32": [],
+    "amd64": [],
+})
+
+[
+    mpn_m4_cc_library(
+        name = x,
+        architecture_paths = architecture_paths,
+        target_compatible_with = ["@platforms//os:linux"],
+    )
+    for x in gmp_mpn_functions + gmp_mpn_functions_cpu_aarch64
+]
+
+cc_library(
+    name = "mpn_core",
+    srcs = gmp_mpn_functions + gmp_mpn_functions_cpu_select + [
+        "assert.c",
+        "compat.c",
+        "errno.c",
+        "extract-dbl.c",
+        "invalid.c",
+        "memory.c",
+        "mp_bpl.c",
+        "mp_clz_tab.c",
+        "mp_dv_tab.c",
+        "mp_get_fns.c",
+        "mp_minv_tab.c",
+        "mp_set_fns.c",
+        "nextprime.c",
+        "primesieve.c",
+        "tal-reent.c",
+        "version.c",
+    ],
+    hdrs = [
+        "fac_table.h",
+        "fib_table.h",
+        "gmp.h",
+        "gmp-impl.h",
+        "gmpxx.h",
+        "longlong.h",
+        "mp_bases.h",
+        "mpn/jacobitab.h",
+        "mpn/perfsqr.h",
+        "trialdivtab.h",
+    ] + mparam_path(architecture_paths) + file_from_architecture(architecture_paths, "config.h"),
+    copts = copts + [
+        "-Wno-unused-command-line-argument",
+        "-Wa,--noexecstack",
+    ],
+    target_compatible_with = ["@platforms//os:linux"],
+)
+
+# TODO(austin): Can we run these through the mpn_m4_cc_library and get operation baked in without work?
+mpn_cc_library(
+    name = "fib_table",
+    srcs = [
+        "mpn/fib_table.c",
+    ],
+    copts = copts,
+    target_compatible_with = ["@platforms//os:linux"],
+    deps = [":mpn_core"],
+)
+
+mpn_cc_library(
+    name = "mp_bases",
+    srcs = [
+        "mpn/mp_bases.c",
+    ],
+    copts = copts,
+    target_compatible_with = ["@platforms//os:linux"],
+    deps = [":mpn_core"],
+)
+
+cc_library(
+    name = "mpn",
+    target_compatible_with = ["@platforms//os:linux"],
+    deps = [
+        ":fib_table",
+        ":mp_bases",
+        ":mpn_core",
+    ],
+)
+
+cc_library(
+    name = "mpz",
+    srcs = [
+        "mpz/2fac_ui.c",
+        "mpz/abs.c",
+        "mpz/add.c",
+        "mpz/add_ui.c",
+        "mpz/and.c",
+        "mpz/aors.h",
+        "mpz/aors_ui.h",
+        "mpz/aorsmul.c",
+        "mpz/aorsmul_i.c",
+        "mpz/array_init.c",
+        "mpz/bin_ui.c",
+        "mpz/bin_uiui.c",
+        "mpz/cdiv_q.c",
+        "mpz/cdiv_q_ui.c",
+        "mpz/cdiv_qr.c",
+        "mpz/cdiv_qr_ui.c",
+        "mpz/cdiv_r.c",
+        "mpz/cdiv_r_ui.c",
+        "mpz/cdiv_ui.c",
+        "mpz/cfdiv_q_2exp.c",
+        "mpz/cfdiv_r_2exp.c",
+        "mpz/clear.c",
+        "mpz/clears.c",
+        "mpz/clrbit.c",
+        "mpz/cmp.c",
+        "mpz/cmp_d.c",
+        "mpz/cmp_si.c",
+        "mpz/cmp_ui.c",
+        "mpz/cmpabs.c",
+        "mpz/cmpabs_d.c",
+        "mpz/cmpabs_ui.c",
+        "mpz/com.c",
+        "mpz/combit.c",
+        "mpz/cong.c",
+        "mpz/cong_2exp.c",
+        "mpz/cong_ui.c",
+        "mpz/dive_ui.c",
+        "mpz/divegcd.c",
+        "mpz/divexact.c",
+        "mpz/divis.c",
+        "mpz/divis_2exp.c",
+        "mpz/divis_ui.c",
+        "mpz/dump.c",
+        "mpz/export.c",
+        "mpz/fac_ui.c",
+        "mpz/fdiv_q.c",
+        "mpz/fdiv_q_ui.c",
+        "mpz/fdiv_qr.c",
+        "mpz/fdiv_qr_ui.c",
+        "mpz/fdiv_r.c",
+        "mpz/fdiv_r_ui.c",
+        "mpz/fdiv_ui.c",
+        "mpz/fib2_ui.c",
+        "mpz/fib_ui.c",
+        "mpz/fits_s.h",
+        "mpz/fits_sint.c",
+        "mpz/fits_slong.c",
+        "mpz/fits_sshort.c",
+        "mpz/fits_uint.c",
+        "mpz/fits_ulong.c",
+        "mpz/fits_ushort.c",
+        "mpz/gcd.c",
+        "mpz/gcd_ui.c",
+        "mpz/gcdext.c",
+        "mpz/get_d.c",
+        "mpz/get_d_2exp.c",
+        "mpz/get_si.c",
+        "mpz/get_str.c",
+        "mpz/get_ui.c",
+        "mpz/getlimbn.c",
+        "mpz/hamdist.c",
+        "mpz/import.c",
+        "mpz/init.c",
+        "mpz/init2.c",
+        "mpz/inits.c",
+        "mpz/inp_raw.c",
+        "mpz/inp_str.c",
+        "mpz/invert.c",
+        "mpz/ior.c",
+        "mpz/iset.c",
+        "mpz/iset_d.c",
+        "mpz/iset_si.c",
+        "mpz/iset_str.c",
+        "mpz/iset_ui.c",
+        "mpz/jacobi.c",
+        "mpz/kronsz.c",
+        "mpz/kronuz.c",
+        "mpz/kronzs.c",
+        "mpz/kronzu.c",
+        "mpz/lcm.c",
+        "mpz/lcm_ui.c",
+        "mpz/limbs_finish.c",
+        "mpz/limbs_modify.c",
+        "mpz/limbs_read.c",
+        "mpz/limbs_write.c",
+        "mpz/lucmod.c",
+        "mpz/lucnum2_ui.c",
+        "mpz/lucnum_ui.c",
+        "mpz/mfac_uiui.c",
+        "mpz/millerrabin.c",
+        "mpz/mod.c",
+        "mpz/mul.c",
+        "mpz/mul_2exp.c",
+        "mpz/mul_i.h",
+        "mpz/mul_si.c",
+        "mpz/mul_ui.c",
+        "mpz/n_pow_ui.c",
+        "mpz/neg.c",
+        "mpz/nextprime.c",
+        "mpz/oddfac_1.c",
+        "mpz/out_raw.c",
+        "mpz/out_str.c",
+        "mpz/perfpow.c",
+        "mpz/perfsqr.c",
+        "mpz/popcount.c",
+        "mpz/pow_ui.c",
+        "mpz/powm.c",
+        "mpz/powm_sec.c",
+        "mpz/powm_ui.c",
+        "mpz/pprime_p.c",
+        "mpz/primorial_ui.c",
+        "mpz/prodlimbs.c",
+        "mpz/random.c",
+        "mpz/random2.c",
+        "mpz/realloc.c",
+        "mpz/realloc2.c",
+        "mpz/remove.c",
+        "mpz/roinit_n.c",
+        "mpz/root.c",
+        "mpz/rootrem.c",
+        "mpz/rrandomb.c",
+        "mpz/scan0.c",
+        "mpz/scan1.c",
+        "mpz/set.c",
+        "mpz/set_d.c",
+        "mpz/set_f.c",
+        "mpz/set_q.c",
+        "mpz/set_si.c",
+        "mpz/set_str.c",
+        "mpz/set_ui.c",
+        "mpz/setbit.c",
+        "mpz/size.c",
+        "mpz/sizeinbase.c",
+        "mpz/sqrt.c",
+        "mpz/sqrtrem.c",
+        "mpz/stronglucas.c",
+        "mpz/sub.c",
+        "mpz/sub_ui.c",
+        "mpz/swap.c",
+        "mpz/tdiv_q.c",
+        "mpz/tdiv_q_2exp.c",
+        "mpz/tdiv_q_ui.c",
+        "mpz/tdiv_qr.c",
+        "mpz/tdiv_qr_ui.c",
+        "mpz/tdiv_r.c",
+        "mpz/tdiv_r_2exp.c",
+        "mpz/tdiv_r_ui.c",
+        "mpz/tdiv_ui.c",
+        "mpz/tstbit.c",
+        "mpz/ui_pow_ui.c",
+        "mpz/ui_sub.c",
+        "mpz/urandomb.c",
+        "mpz/urandomm.c",
+        "mpz/xor.c",
+    ],
+    copts = copts,
+    target_compatible_with = ["@platforms//os:linux"],
+    deps = [
+        ":mpn",
+    ],
+)
+
+cc_library(
+    name = "mpq",
+    srcs = [
+        "mpq/abs.c",
+        "mpq/aors.c",
+        "mpq/canonicalize.c",
+        "mpq/clear.c",
+        "mpq/clears.c",
+        "mpq/cmp.c",
+        "mpq/cmp_si.c",
+        "mpq/cmp_ui.c",
+        "mpq/div.c",
+        "mpq/equal.c",
+        "mpq/get_d.c",
+        "mpq/get_den.c",
+        "mpq/get_num.c",
+        "mpq/get_str.c",
+        "mpq/init.c",
+        "mpq/inits.c",
+        "mpq/inp_str.c",
+        "mpq/inv.c",
+        "mpq/md_2exp.c",
+        "mpq/mul.c",
+        "mpq/neg.c",
+        "mpq/out_str.c",
+        "mpq/set.c",
+        "mpq/set_d.c",
+        "mpq/set_den.c",
+        "mpq/set_f.c",
+        "mpq/set_num.c",
+        "mpq/set_si.c",
+        "mpq/set_str.c",
+        "mpq/set_ui.c",
+        "mpq/set_z.c",
+        "mpq/swap.c",
+    ],
+    copts = copts,
+    target_compatible_with = ["@platforms//os:linux"],
+    deps = [
+        ":mpn",
+    ],
+)
+
+cc_library(
+    name = "mpf",
+    srcs = [
+        "mpf/abs.c",
+        "mpf/add.c",
+        "mpf/add_ui.c",
+        "mpf/ceilfloor.c",
+        "mpf/clear.c",
+        "mpf/clears.c",
+        "mpf/cmp.c",
+        "mpf/cmp_d.c",
+        "mpf/cmp_si.c",
+        "mpf/cmp_ui.c",
+        "mpf/cmp_z.c",
+        "mpf/div.c",
+        "mpf/div_2exp.c",
+        "mpf/div_ui.c",
+        "mpf/dump.c",
+        "mpf/eq.c",
+        "mpf/fits_s.h",
+        "mpf/fits_sint.c",
+        "mpf/fits_slong.c",
+        "mpf/fits_sshort.c",
+        "mpf/fits_u.h",
+        "mpf/fits_uint.c",
+        "mpf/fits_ulong.c",
+        "mpf/fits_ushort.c",
+        "mpf/get_d.c",
+        "mpf/get_d_2exp.c",
+        "mpf/get_dfl_prec.c",
+        "mpf/get_prc.c",
+        "mpf/get_si.c",
+        "mpf/get_str.c",
+        "mpf/get_ui.c",
+        "mpf/init.c",
+        "mpf/init2.c",
+        "mpf/inits.c",
+        "mpf/inp_str.c",
+        "mpf/int_p.c",
+        "mpf/iset.c",
+        "mpf/iset_d.c",
+        "mpf/iset_si.c",
+        "mpf/iset_str.c",
+        "mpf/iset_ui.c",
+        "mpf/mul.c",
+        "mpf/mul_2exp.c",
+        "mpf/mul_ui.c",
+        "mpf/neg.c",
+        "mpf/out_str.c",
+        "mpf/pow_ui.c",
+        "mpf/random2.c",
+        "mpf/reldiff.c",
+        "mpf/set.c",
+        "mpf/set_d.c",
+        "mpf/set_dfl_prec.c",
+        "mpf/set_prc.c",
+        "mpf/set_prc_raw.c",
+        "mpf/set_q.c",
+        "mpf/set_si.c",
+        "mpf/set_str.c",
+        "mpf/set_ui.c",
+        "mpf/set_z.c",
+        "mpf/size.c",
+        "mpf/sqrt.c",
+        "mpf/sqrt_ui.c",
+        "mpf/sub.c",
+        "mpf/sub_ui.c",
+        "mpf/swap.c",
+        "mpf/trunc.c",
+        "mpf/ui_div.c",
+        "mpf/ui_sub.c",
+        "mpf/urandomb.c",
+    ],
+    copts = copts,
+    target_compatible_with = ["@platforms//os:linux"],
+    deps = [
+        ":mpn",
+    ],
+)
+
+cc_library(
+    name = "printf",
+    srcs = [
+        "printf/asprintf.c",
+        "printf/asprntffuns.c",
+        "printf/doprnt.c",
+        "printf/doprntf.c",
+        "printf/doprnti.c",
+        "printf/fprintf.c",
+        "printf/obprintf.c",
+        "printf/obprntffuns.c",
+        "printf/obvprintf.c",
+        "printf/printf.c",
+        "printf/printffuns.c",
+        "printf/repl-vsnprintf.c",
+        "printf/snprintf.c",
+        "printf/snprntffuns.c",
+        "printf/sprintf.c",
+        "printf/sprintffuns.c",
+        "printf/vasprintf.c",
+        "printf/vfprintf.c",
+        "printf/vprintf.c",
+        "printf/vsnprintf.c",
+        "printf/vsprintf.c",
+    ],
+    copts = copts,
+    target_compatible_with = ["@platforms//os:linux"],
+    deps = [
+        ":mpn",
+    ],
+)
+
+cc_library(
+    name = "scanf",
+    srcs = [
+        "scanf/doscan.c",
+        "scanf/fscanf.c",
+        "scanf/fscanffuns.c",
+        "scanf/scanf.c",
+        "scanf/sscanf.c",
+        "scanf/sscanffuns.c",
+        "scanf/vfscanf.c",
+        "scanf/vscanf.c",
+        "scanf/vsscanf.c",
+    ],
+    copts = copts,
+    target_compatible_with = ["@platforms//os:linux"],
+    deps = [
+        ":mpn",
+    ],
+)
+
+cc_library(
+    name = "rand",
+    srcs = [
+        "rand/rand.c",
+        "rand/randbui.c",
+        "rand/randclr.c",
+        "rand/randdef.c",
+        "rand/randiset.c",
+        "rand/randlc2s.c",
+        "rand/randlc2x.c",
+        "rand/randmt.c",
+        "rand/randmt.h",
+        "rand/randmts.c",
+        "rand/randmui.c",
+        "rand/rands.c",
+        "rand/randsd.c",
+        "rand/randsdui.c",
+    ],
+    copts = copts,
+    target_compatible_with = ["@platforms//os:linux"],
+    deps = [
+        ":mpn",
+    ],
+)
+
+cc_library(
+    name = "cxx",
+    srcs = [
+        "cxx/isfuns.cc",
+        "cxx/ismpf.cc",
+        "cxx/ismpq.cc",
+        "cxx/ismpz.cc",
+        "cxx/ismpznw.cc",
+        "cxx/limits.cc",
+        "cxx/osdoprnti.cc",
+        "cxx/osfuns.cc",
+        "cxx/osmpf.cc",
+        "cxx/osmpq.cc",
+        "cxx/osmpz.cc",
+    ],
+    copts = ccopts,
+    target_compatible_with = ["@platforms//os:linux"],
+    deps = [
+        ":mpn",
+    ],
+)
+
+cc_library(
+    name = "gmp",
+    includes = ["."],
+    target_compatible_with = ["@platforms//os:linux"],
+    visibility = ["//visibility:public"],
+    deps = [
+        ":cxx",
+        ":mpf",
+        ":mpn",
+        ":mpq",
+        ":mpz",
+        ":printf",
+        ":rand",
+        ":scanf",
+    ],
+)
+
+genrule(
+    name = "call_m4",
+    srcs = glob([
+        "**/*.m4",
+        "**/*.asm",
+    ]) + ["config.m4"],
+    outs = ["tests/call.s"],
+    cmd = "ROOT=$$(pwd); cd ./" + current_directory() + "/tests; LD_LIBRARY_PATH=$${ROOT}/external/m4_v1.4.18/usr/lib/x86_64-linux-gnu/ $${ROOT}/$(location @m4_v1.4.18//:bin) -I $${ROOT}/$(GENDIR)/" + current_directory() + "/tests -DHAVE_CONFIG_H -DPIC " + cpu_select({
+              "arm": "arm32call.asm",
+              "amd64": "amd64call.asm",
+          }) +
+          " > $${ROOT}/$@",
+    target_compatible_with = ["@platforms//os:linux"],
+    tools = [
+        "@m4_v1.4.18//:bin",
+        "@m4_v1.4.18//:lib",
+    ],
+)
+
+cc_library(
+    name = "testlib",
+    srcs =
+        cpu_select({
+            "arm": [],
+            "amd64": [
+                "tests/amd64check.c",
+                ":call_m4",
+            ],
+        }) + [
+            "tests/memory.c",
+            "tests/misc.c",
+            "tests/refmpf.c",
+            "tests/refmpn.c",
+            "tests/refmpq.c",
+            "tests/refmpz.c",
+            "tests/spinner.c",
+            "tests/trace.c",
+        ],
+    hdrs = [
+        "tests/cxx/t-ops2.h",
+        "tests/mpn/toom-shared.h",
+        "tests/mpn/toom-sqr-shared.h",
+        "tests/tests.h",
+    ],
+    copts = copts + ["-Wno-unused-command-line-argument"],
+    includes = [
+        ".",
+        "tests",
+    ] + ["mpn/" + p for p in architecture_paths],
+    target_compatible_with = ["@platforms//os:linux"],
+    deps = [":gmp"],
+)
+
+[cc_test(
+    name = "tests/" + x,
+    srcs = ["tests/" + x + ".c"],
+    copts = copts,
+    target_compatible_with = ["@platforms//os:linux"],
+    deps = [":testlib"],
+) for x in [
+    "t-bswap",
+    "t-constants",
+    "t-count_zeros",
+    "t-hightomask",
+    "t-modlinv",
+    "t-popc",
+    "t-parity",
+    "t-sub",
+]]
+
+[cc_test(
+    name = "tests/mpn/" + x,
+    srcs = ["tests/mpn/" + x + ".c"],
+    copts = copts,
+    target_compatible_with = ["@platforms//os:linux"],
+    deps = [":testlib"],
+) for x in [
+    "t-asmtype",
+    "t-aors_1",
+    "t-divrem_1",
+    "t-mod_1",
+    "t-fat",
+    "t-get_d",
+    "t-instrument",
+    "t-iord_u",
+    "t-mp_bases",
+    "t-perfsqr",
+    "t-scan",
+    "logic",
+    "t-toom22",
+    "t-toom32",
+    "t-toom33",
+    "t-toom42",
+    "t-toom43",
+    "t-toom44",
+    "t-toom52",
+    "t-toom53",
+    "t-toom54",
+    "t-toom62",
+    "t-toom63",
+    "t-toom6h",
+    "t-toom8h",
+    "t-toom2-sqr",
+    "t-toom3-sqr",
+    "t-toom4-sqr",
+    "t-toom6-sqr",
+    "t-toom8-sqr",
+    "t-div",
+    "t-mul",
+    "t-mullo",
+    "t-sqrlo",
+    "t-mulmod_bnm1",
+    "t-sqrmod_bnm1",
+    "t-mulmid",
+    "t-hgcd",
+    "t-hgcd_appr",
+    "t-matrix22",
+    "t-invert",
+    "t-bdiv",
+    "t-fib2m",
+    "t-broot",
+    "t-brootinv",
+    "t-minvert",
+    "t-sizeinbase",
+    "t-gcd_11",
+    "t-gcd_22",
+    "t-gcdext_1",
+]]
+
+[cc_test(
+    name = "tests/mpz/" + x,
+    srcs = ["tests/mpz/" + x + ".c"],
+    copts = copts,
+    target_compatible_with = ["@platforms//os:linux"],
+    deps = [":testlib"],
+) for x in [
+    "reuse",
+    "t-addsub",
+    "t-cmp",
+    "t-mul",
+    "t-mul_i",
+    "t-tdiv",
+    "t-tdiv_ui",
+    "t-fdiv",
+    "t-fdiv_ui",
+    "t-cdiv_ui",
+    "t-gcd",
+    "t-gcd_ui",
+    "t-lcm",
+    "t-invert",
+    "dive",
+    "dive_ui",
+    "t-sqrtrem",
+    "convert",
+    "io",
+    "t-inp_str",
+    "logic",
+    "bit",
+    "t-powm",
+    "t-powm_ui",
+    "t-pow",
+    "t-div_2exp",
+    "t-root",
+    "t-perfsqr",
+    "t-perfpow",
+    "t-jac",
+    "t-bin",
+    "t-get_d",
+    "t-get_d_2exp",
+    "t-get_si",
+    "t-set_d",
+    "t-set_si",
+    "t-lucm",
+    "t-fac_ui",
+    "t-mfac_uiui",
+    "t-primorial_ui",
+    "t-fib_ui",
+    "t-lucnum_ui",
+    "t-scan",
+    "t-fits",
+    "t-divis",
+    "t-divis_2exp",
+    "t-cong",
+    "t-cong_2exp",
+    "t-sizeinbase",
+    "t-set_str",
+    "t-aorsmul",
+    "t-cmp_d",
+    "t-cmp_si",
+    "t-hamdist",
+    "t-oddeven",
+    "t-popcount",
+    "t-set_f",
+    "t-io_raw",
+    "t-import",
+    "t-export",
+    "t-pprime_p",
+    "t-nextprime",
+    "t-remove",
+    "t-limbs",
+]]
+
+[cc_test(
+    name = "tests/mpq/" + x,
+    srcs = ["tests/mpq/" + x + ".c"],
+    copts = copts,
+    target_compatible_with = ["@platforms//os:linux"],
+    deps = [":testlib"],
+) for x in [
+    "t-aors",
+    "t-cmp",
+    "t-cmp_ui",
+    "t-cmp_si",
+    "t-equal",
+    "t-get_d",
+    "t-get_str",
+    "t-inp_str",
+    "t-inv",
+    "t-md_2exp",
+    "t-set_f",
+    "t-set_str",
+    "io",
+    "reuse",
+    "t-cmp_z",
+]]
+
+[cc_test(
+    name = "tests/mpf/" + x,
+    srcs = ["tests/mpf/" + x + ".c"],
+    copts = copts,
+    target_compatible_with = ["@platforms//os:linux"],
+    deps = [":testlib"],
+) for x in [
+    "t-dm2exp",
+    "t-conv",
+    "t-add",
+    "t-sub",
+    "t-sqrt",
+    "t-sqrt_ui",
+    "t-muldiv",
+    "reuse",
+    "t-cmp_d",
+    "t-cmp_si",
+    "t-div",
+    "t-fits",
+    "t-get_d",
+    "t-get_d_2exp",
+    "t-get_si",
+    "t-get_ui",
+    "t-gsprec",
+    "t-inp_str",
+    "t-int_p",
+    "t-mul_ui",
+    "t-set",
+    "t-set_q",
+    "t-set_si",
+    "t-set_ui",
+    "t-trunc",
+    "t-ui_div",
+    "t-eq",
+    "t-pow_ui",
+]]
+
+[cc_test(
+    name = "tests/rand/" + x,
+    srcs = ["tests/rand/" + x + ".c"],
+    copts = copts,
+    target_compatible_with = ["@platforms//os:linux"],
+    deps = [":testlib"],
+) for x in [
+    "t-iset",
+    "t-lc2exp",
+    "t-mt",
+    "t-rand",
+    "t-urbui",
+    "t-urmui",
+    "t-urndmm",
+]]
+
+[cc_test(
+    name = "tests/misc/" + x,
+    srcs = ["tests/misc/" + x + ".c"],
+    copts = copts,
+    target_compatible_with = ["@platforms//os:linux"],
+    deps = [":testlib"],
+) for x in [
+    "t-printf",
+    "t-scanf",
+    "t-locale",
+]]
+
+[cc_test(
+    name = "tests/cxx/" + x,
+    srcs = ["tests/cxx/" + x + ".cc"],
+    copts = copts,
+    target_compatible_with = ["@platforms//os:linux"],
+    deps = [":testlib"],
+) for x in [
+    "t-binary",
+    "t-cast",
+    "t-cxx11",
+    "t-headers",
+    "t-iostream",
+    "t-istream",
+    "t-locale",
+    "t-misc",
+    "t-mix",
+    "t-ops",
+    "t-ops2qf",
+    "t-ops2f",
+    "t-ops3",
+    "t-ostream",
+    "t-prec",
+    "t-ternary",
+    "t-unary",
+    "t-do-exceptions-work-at-all-with-this-compiler",
+    "t-ops2z",
+    "t-assign",
+    "t-constr",
+    "t-rand",
+]]
diff --git a/third_party/gmp/COPYING b/third_party/gmp/COPYING
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/third_party/gmp/COPYING
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/third_party/gmp/COPYING.LESSERv3 b/third_party/gmp/COPYING.LESSERv3
new file mode 100644
index 0000000..fc8a5de
--- /dev/null
+++ b/third_party/gmp/COPYING.LESSERv3
@@ -0,0 +1,165 @@
+		   GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+  This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+  0. Additional Definitions. 
+
+  As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+  "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+  An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+  A "Combined Work" is a work produced by combining or linking an
+Application with the Library.  The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+  The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+  The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+  1. Exception to Section 3 of the GNU GPL.
+
+  You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+  2. Conveying Modified Versions.
+
+  If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+   a) under this License, provided that you make a good faith effort to
+   ensure that, in the event an Application does not supply the
+   function or data, the facility still operates, and performs
+   whatever part of its purpose remains meaningful, or
+
+   b) under the GNU GPL, with none of the additional permissions of
+   this License applicable to that copy.
+
+  3. Object Code Incorporating Material from Library Header Files.
+
+  The object code form of an Application may incorporate material from
+a header file that is part of the Library.  You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+   a) Give prominent notice with each copy of the object code that the
+   Library is used in it and that the Library and its use are
+   covered by this License.
+
+   b) Accompany the object code with a copy of the GNU GPL and this license
+   document.
+
+  4. Combined Works.
+
+  You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+   a) Give prominent notice with each copy of the Combined Work that
+   the Library is used in it and that the Library and its use are
+   covered by this License.
+
+   b) Accompany the Combined Work with a copy of the GNU GPL and this license
+   document.
+
+   c) For a Combined Work that displays copyright notices during
+   execution, include the copyright notice for the Library among
+   these notices, as well as a reference directing the user to the
+   copies of the GNU GPL and this license document.
+
+   d) Do one of the following:
+
+       0) Convey the Minimal Corresponding Source under the terms of this
+       License, and the Corresponding Application Code in a form
+       suitable for, and under terms that permit, the user to
+       recombine or relink the Application with a modified version of
+       the Linked Version to produce a modified Combined Work, in the
+       manner specified by section 6 of the GNU GPL for conveying
+       Corresponding Source.
+
+       1) Use a suitable shared library mechanism for linking with the
+       Library.  A suitable mechanism is one that (a) uses at run time
+       a copy of the Library already present on the user's computer
+       system, and (b) will operate properly with a modified version
+       of the Library that is interface-compatible with the Linked
+       Version. 
+
+   e) Provide Installation Information, but only if you would otherwise
+   be required to provide such information under section 6 of the
+   GNU GPL, and only to the extent that such information is
+   necessary to install and execute a modified version of the
+   Combined Work produced by recombining or relinking the
+   Application with a modified version of the Linked Version. (If
+   you use option 4d0, the Installation Information must accompany
+   the Minimal Corresponding Source and Corresponding Application
+   Code. If you use option 4d1, you must provide the Installation
+   Information in the manner specified by section 6 of the GNU GPL
+   for conveying Corresponding Source.)
+
+  5. Combined Libraries.
+
+  You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+   a) Accompany the combined library with a copy of the same work based
+   on the Library, uncombined with any other library facilities,
+   conveyed under the terms of this License.
+
+   b) Give prominent notice with the combined library that part of it
+   is a work based on the Library, and explaining where to find the
+   accompanying uncombined form of the same work.
+
+  6. Revised Versions of the GNU Lesser General Public License.
+
+  The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+  Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+  If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
diff --git a/third_party/gmp/COPYINGv2 b/third_party/gmp/COPYINGv2
new file mode 100644
index 0000000..d159169
--- /dev/null
+++ b/third_party/gmp/COPYINGv2
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/third_party/gmp/COPYINGv3 b/third_party/gmp/COPYINGv3
new file mode 100644
index 0000000..2a00065
--- /dev/null
+++ b/third_party/gmp/COPYINGv3
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<https://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<https://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/third_party/gmp/ChangeLog b/third_party/gmp/ChangeLog
new file mode 100644
index 0000000..0689b88
--- /dev/null
+++ b/third_party/gmp/ChangeLog
@@ -0,0 +1,35503 @@
+2020-01-17  Torbjörn Granlund  <tg@gmplib.org>
+
+	* Version 6.2.0 released.
+
+	* gmp-h.in (__GNU_MP__): Bump.
+	(__GNU_MP_VERSION,__GNU_MP_VERSION_MINOR,__GNU_MP_VERSION_PATCHLEVEL):
+	Bump version info.
+	* Makefile.am (LIBGMP_LT_*, LIBGMPXX_LT_*, LIBMP_LT_*):
+	Bump version info.
+
+2020-01-15  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86_64/bt1/gcd_11.asm: Add missing FUNC_EXIT.
+
+2020-01-10  Torbjörn Granlund  <tg@gmplib.org>
+
+	* longlong.h (powerpc): Add clobbers, make formatting cleanups.
+
+	* configure.ac (HAVE_NATIVE): Add mpn_sbpi1_bdiv_r.
+
+	* tune/tune-gcd-p.c (main): Use %zu for size_t printing.
+
+	* configfsf.guess: Update from upstream.
+
+	* mpn/x86/pentium4/sse2/popcount.asm: For simplicity and correctness
+	use LEAL directly.
+
+2020-01-03  Niels Möller  <nisse@lysator.liu.se>
+
+	* configure.ac: Delete suggestion to use TESTS_ENVIRONMENT to run
+	wine. It worked only with older versions of automake.
+
+2019-12-23  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpf/mul.c: Rewrite to invoke mpn_sqr when appropriate.
+
+2019-12-08 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpz/powm.c: Full normalisation when e=1 & b<0.
+	* tests/mpz/t-powm.c: More tests for the e=1 case.
+
+2019-12-02  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/generic/gcd_11.c: Remove check for NATIVE_ implementation.
+
+2019-11-24  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/gcdext_1.c [USE_ZEROTAB]: Delete code variant for
+	USE_ZEROTAB != 0. Was used in the currently disabled binary
+	gcdext.
+
+2019-11-20  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/generic/powm.c (MPN_REDC_1): Prefer mpn_sbpi1_bdiv_r when it is
+	provided.
+	* mpn/generic/sec_powm.c (MPN_REDC_1_SEC): Likewise.
+
+2019-11-17  Torbjörn Granlund  <tg@gmplib.org>
+
+	* config.guess: Recognise zen2.
+	* configure.ac: Likewise.
+
+	* mpn/x86_64/bt1/aorsmul_1.asm: Rewrite.
+	* mpn/x86_64/bt1/mul_1.asm: Rewrite.
+
+	* mpn/arm/v6t2/gcd_11.asm: Increase alignment; update x/l table.
+
+2019-11-16 Seth Troisi <sethtroisi@google.com>
+
+	* tune/common.c (speed_mpn_perfect_power_p): New function.
+	(speed_mpn_perfect_power_p): New function.
+	* tune/speed.h: Declare both.
+	* tune/speed.c (routine): Add mpn_perfect_{power,square}_p.
+
+	* tune/common.c (speed_mpz_nextprime): New function.
+	* tune/speed.h: Declare it.
+	* tune/speed.c (routine): Add mpz_nextprime.
+
+2019-11-09 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* tune/speed.c (routine_t): Add R flag to mpz_powm
+	* tune/speed.h (SPEED_ROUTINE_MPZ_POWM): Use R flag as the base.
+
+2019-10-02  Torbjörn Granlund  <tg@gmplib.org>
+
+	* configure.ac: Make more path distinctions for the benefit of
+	gmp-mparam.h.
+
+2019-10-01  Torbjörn Granlund  <tg@gmplib.org>
+
+	* configure.ac (arm64): Let cortex-a7x look in a57 folder.
+
+2019-10-01  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/gcdext_1.c (mpn_gcdext_1) [GCDEXT_1_USE_BINARY]: Fix
+	canonicalization condition.
+
+2019-09-30  Niels Möller  <nisse@lysator.liu.se>
+
+	* tests/mpn/t-gcdext_1.c: New test.
+
+2019-09-23  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/generic/hgcd2.c: Mark added div1 variants as static.
+
+	* tune/tuneup.c, tune/speed.c, tune/speed.h, tune/common.c,
+	tune/Makefile.am: Add measuring of mpn_hgcd2 method 4 and 5.
+	* tune/hgcd2-4.c, tune/hgcd2-5.c: New files.
+
+2019-09-23  Niels Möller  <nisse@lysator.liu.se>
+
+	* gmp-impl.h (hgcd2_func_t) [TUNE_PROGRAM_BUILD]: New typedef.
+	(hgcd2_func) [TUNE_PROGRAM_BUILD]: New function pointer.
+
+	* tune/hgcd2.c (mpn_hgcd2): New file, with a redefined function to
+	invoke an implementation via the hgcd2_func function pointer.
+	Initially points to the default implementation in
+	mpn/generic/hgcd2.c.
+	* tune/Makefile.am (tuneup_SOURCES): Add hgcd2.c.
+
+	* tune/tuneup.c (one_method): Return index of selected function.
+	(tune_hgcd2): Set hgcd2_func to point to selected function. So
+	that the later tuning of mpn_hgcd and mpn_gcd uses the right
+	implementation of hgcd2.
+
+2019-09-23  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/generic/hgcd2.c: Improve method 4 and 5 by using the division
+	free methods optimistically, detecting errors.  Tweak table values.
+
+2019-09-22  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/generic/hgcd2.c: Add a 4th and 5th div1 method.
+
+2019-09-18  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/generic/hgcd2.c (div1, div2): Rearrange things to allow for asm.
+	(div2): Avoid out-of-specs shift.
+	(div2): Use same variable naming in all variants.
+
+2019-09-16  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/hgcd2.c (HGCD2_DIV2_METHOD): New define.
+	(div2): Replaced, since the old implementation had lots of poorly
+	predicted and expensive branches. Two new implementaions, selected
+	by HGCD2_DIV2_METHOD.
+	(div2) [HGCD2_DIV2_METHOD == 1]: Calls div1 on the high limbs,
+	with unlikely case handling large quotients.
+	(div2) [HGCD2_DIV2_METHOD == 2]: The previously #if:ed out
+	version. A bitwise division, relying on fast count_leading_zeros,
+	and with fewer branches than the previous code.
+
+2019-09-15  Torbjörn Granlund  <tg@gmplib.org>
+
+	* acinclude.m4 (GMP_ASM_X86_ADX): Remove unused.
+
+	* configure.ac (x86): Amend last change.
+
+2019-09-14  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/hgcd2.c (HGCD2_DIV1_METHOD): Rename, and change
+	default to 3. Updated all usage.
+	(HGCD2_METHOD): ... the old name, deleted.
+
+2019-09-14  Torbjörn Granlund  <tg@gmplib.org>
+
+	* configure.ac: Remove obsolete path-triggered invocation of
+	GMP_ASM_X86_ADX and GMP_ASM_X86_MULX.
+
+	* acinclude.m4 (GMP_ASM_X86_MULX): Set X86_ASM_MULX to config.h.
+	* configure.ac (x86): Set x86_have_mulx for relevant CPUs.
+	Use if to conditionally invoke GMP_ASM_X86_MULX.
+	* longlong.h (x86 umul_ppmm): Test also X86_ASM_MULX for when to use
+	mulx variant.
+
+2019-09-13  Niels Möller  <nisse@lysator.liu.se>
+
+	* tune/tuneup.c (one_method): New helper function, to measure
+	several functions for a fix size.
+	(tune_hgcd2, tune_div_qr_1, tune_mod_1, tune_jacobi_base): Use it.
+
+2019-09-13  Torbjörn Granlund  <tg@gmplib.org>
+
+	* configure.ac (HAVE_HOST_CPU_1): Add many x86_64 CPU types.
+	* longlong.h (x86 umul_ppmm): Fix criterion for when to use mulx.
+	(count_leading_zeros): Use lzcnt for appropriate CPUs.
+	(count_trailing_zeros): Use tzcnt for appropriate CPUs.
+
+	* mpn/generic/hgcd2.c (HGCD2_METHOD=2 div1): Rewrite.
+
+2019-09-09  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/generic/mul.c: Call mpn_mul_basecase early when in range.  Never
+	call mpn_sqr.
+
+	* mpn/generic/gcd.c: Rewrite tail of function, for n <= 2.
+
+2019-09-08  Torbjörn Granlund  <tg@gmplib.org>
+
+	* configure.ac (arm): Select arch armv7ve for a7, a12, a15, and a17,
+	this enables the use of the udiv instruction.
+
+	* mpn/generic/hgcd2.c (disabled div2): Micro-optimise.
+
+2019-09-07  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/generic/hgcd2.c (HGCD2_METHOD=3 div1): Micro-optimise.
+
+2019-09-07  Vincent Lefevre <vincent@vinc17.net>
+
+	* acinclude.m4 (GMP_C_DOUBLE_FORMAT): Append EXEEXT for executable.
+
+2019-09-05  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/arm64/gcd_22.asm: Rewrite to make better use of Arm conditional
+	execution.
+	* mpn/arm32/gcd_22.asm: Likewise.
+
+2019-09-05  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/hgcd2.c (div1): Return both r and q as a
+	mp_double_limb_t, replacing the DIV1 macro.
+	(div1) [HGCD2_METHOD == 3]: New implementation handling q <= 7
+	specially and without branches. Based on Torbjörn's mail to the
+	gmp-devel list.
+	* tune/speed.c, tune/speed.h, tune/common.c, tune/Makefile.am: Add
+	corresponding speed support.
+	* tune/hgcd2-3.c: New file.
+	* tune/tuneup.c (print_define_with_speedup): New function, to
+	output a comment with speedup compared to next-best method.
+	(tune_hgcd2): Update tuning.
+
+2019-09-04  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/hgcd2.c (HGCD2_METHOD): New parameter.
+	(DIV1): New macro, using either the div1 function or plain
+	division, depending on the value of HGCD2_METHOD.
+	(mpn_hgcd2): Use DIV1.
+	* tune/speed.c, tune/speed.h, tune/common.c, tune/Makefile.am: Add
+	measuring of mpn_hgcd2 methods.
+	* tune/hgcd2-1.c, tune/hgcd2-2.c: New files.
+	* tune/tuneup.c: Tune HGCD2_METHOD.
+
+	* tune/speed.h (SPEED_ROUTINE_MPN_HGCD2): New macro.
+	* tune/common.c (speed_mpn_hgcd2): New function.
+	* tune/speed.c (routine): Add mpn_hgcd2.
+
+2019-09-04  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/arm/v6t2/gcd_22.asm: New file.
+	* mpn/arm64/gcd_22.asm: New file.
+	* mpn/ia64/gcd_11.asm: New file.
+
+2019-09-01  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86_64/bt1/gcd_11.asm: Replace grabber with bt1 optimised code.
+
+2019-08-30  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86_64/bd4/gcd_22.asm: New grabber file.
+
+	* mpn/x86_64/zen/gcd_22.asm: Use coreihwl instead of bd2 gcd_22.
+
+	* mpn/x86_64/bd2/gcd_22.asm: Fix typo in FUNC_ENTRY (currently unused).
+	Avoid a register copy before return.
+	* mpn/x86_64/core2/gcd_22.asm: Likewise.
+	* mpn/x86_64/k10/gcd_22.asm: Likewise.
+	* mpn/x86_64/gcd_22.asm: Likewise.
+
+	* mpn/x86_64/coreihwl/gcd_22.asm: Optimise, now runs well on more CPUs.
+
+	* mpn/x86_64/gcd_11.asm: Remove PROTECT from symbols as they are
+	actually local.
+	* mpn/x86_64/gcd_22.asm: Likewise.
+
+2019-08-25  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86_64/bd2/gcd_22.asm: Repeat tzcnt for exceptional lowz case.
+	Remove dead code.
+
+	* mpn/powerpc64/mode64/p7/gcd_22.asm: Make logic for determining ABI
+	wrt struct return more robust.
+	* mpn/powerpc64/mode64/p9/gcd_22.asm: Likewise.
+
+2019-08-24  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86_64/bt1/gcd_11.asm: New grabber.
+	* mpn/x86_64/bt1/gcd_22.asm: New grabber.
+	* mpn/x86_64/bt2/gcd_22.asm: New grabber.
+
+	* mpn/x86_64/atom/gcd_22.asm: Remove stale grabber file.
+	* mpn/x86_64/zen/gcd_22.asm: Grab bd2 instead of hwl code.
+	* mpn/x86_64/bd2/gcd_22.asm: New file.
+	* mpn/x86_64/k8/gcd_22.asm: Remove, rely on top-level code instead.
+	* mpn/x86_64/bt1/gcd_22.asm: Remove.
+	* x86_64/gcd_22.asm: New file, improved version of removed bt1 code.
+
+2019-08-22  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86_64/coreihwl/gcd_11.asm: Remove as it was never beneficial.
+
+	* mpn/x86_64/bd2/gcd_11.asm: Make sure rdx is zero on return to benefit
+	gcd_22's private calls. Make gcd_11 files more similar in register use.
+	* mpn/x86_64/bd4/gcd_11.asm: Likewise.
+	* mpn/x86_64/core2/gcd_11.asm: Likewise.
+	* mpn/x86_64/gcd_11.asm:: Likewise.
+
+2019-08-22  Niels Möller  <nisse@lysator.liu.se>
+
+	From Hugh McMaster:
+	* gmp.pc.in, gmpxx.pc.in: New files.
+	* configure.ac: New output files gmp.pc and gmpxx.pc.
+	* Makefile.am (pkgconfigdir, pkgconfig_DATA): New automake
+	settings, to install gmp.pc and optionally gmpxx.pc for use with
+	pkg-config.
+
+2019-08-21  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86_64/core2/gcd_22.asm: New file.
+	* mpn/x86_64/k8/gcd_22.asm: New file.
+	* mpn/x86_64/k10/gcd_22.asm: New file.
+	* mpn/x86_64/coreihwl/gcd_22.asm: New file.
+	* mpn/x86_64/bt1/gcd_22.asm: New file.
+	* mpn/x86_64/bd4/gcd_22.asm: New grabber.
+	* mpn/x86_64/zen/gcd_22.asm: New grabber.
+	* mpn/x86_64/atom/gcd_22.asm: New grabber.
+
+2019-08-19  Torbjörn Granlund  <tg@gmplib.org>
+
+	* configure.ac: Check for ELFv1 ABI on PowerPC.
+
+2019-08-18  Torbjörn Granlund  <tg@gmplib.org>
+
+	* longlong.h (arm32 sub_ddmmss): Define separately for thumb and
+	non-thumb as rsc instruction is missing for thumb.
+
+	* mpn/powerpc64/mode64/p7/gcd_22.asm: New file.
+	* mpn/powerpc64/mode64/p9/gcd_22.asm: New file.
+
+2019-08-17  Torbjörn Granlund  <tg@gmplib.org>
+
+	* demos/expr/t-expr.c: #include gmp-impl.h as it includes tests.h.
+
+	* mpn/asm-defs.m4: Add gcd_22.
+
+	* tests/refmpn.c (refmpn_gcd_22): New function.
+	* tests/tests.h: Declare it.
+
+	* tests/t-constants.c: #include gmp-impl.h.
+	* tests/mpf/t-get_d.c: Likewise.
+
+2019-08-17  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/gcd_22.c (mpn_gcd_22): New implementation with less
+	branches.
+
+2019-08-16 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/brootinv.c: Shorten computations, using even exponent.
+	* mpn/generic/powlo.c: Avoid copies with a flipflop.
+
+2019-08-16  Niels Möller  <nisse@lysator.liu.se>
+
+	Speed support for gcd_22. Calls mpn_gcd_22(al, al, bl, bl), so
+	that B+1 is a common factor.
+	* tune/speed.h (SPEED_ROUTINE_MPN_GCD_22): New macro.
+	* tune/speed.c (routine): Add mpn_gcd_22.
+	* tune/common.c (speed_mpn_gcd_22): New function.
+
+	* mpn/generic/gcd.c (gcd_2): Moved to gcd_22.c below.
+	(mpn_gcd): Adapt for calling gcd_22.
+	* mpn/generic/gcd_22.c (mpn_gcd_22): New file and function.
+	* gmp-impl.h (mp_double_limb_t): New (typedef) struct.
+	* configure.ac (gmp_mpn_functions): Added gcd_22.
+
+	* tests/mpn/t-gcd_22.c: New test.
+	* tests/mpn/Makefile.am (check_PROGRAMS): Add t-gcd_22.
+	* tests/refmpz.c (refmpz_gcd): New function (plain binary gcd).
+
+2019-08-15  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86_64/zen/gcd_11.asm: Use bd2 instead of bd4 code.
+
+2019-08-13  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86_64: Add more gcd_11 variants of of x86_64 gcd_11.asm and
+	tweak existing ones.
+
+2019-08-13 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	From Seth Troisi:
+	* doc/gmp.texi: Update mpz_millerrabin documentation.
+
+	* mpn/x86_64/bd2/gcd_11.asm: Micro-optimisation.
+	* doc/gmp.texi: Further update in mpz_millerrabin.
+	* tests/misc.c: Silence a warning.
+	* tests/mpz/t-pprime_p.c (const primes): One more prime in the list.
+	* mpz/millerrabin.c: Return 2 for surely prime numbers (BPSW checked).
+
+2019-08-08  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86/gcd_11.asm: New file.
+
+	* config.sub: Make arm cpu types match what config.guess returns.
+
+2019-08-08  Niels Möller  <nisse@lysator.liu.se>
+
+	* tests/refmpn.c (refmpn_gcd_11): New function, based on refmpn_gcd_1.
+	(refmpn_gcd_1): Use it.
+	* tests/mpn/t-gcd_11.c: New file, test mpn_gcd_11.
+	* tests/mpn/Makefile.am (check_PROGRAMS): Add t-gcd_11.
+
+2019-08-07  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/alpha/ev67/gcd_11.asm: New file, mostly extracted from gcd_1.asm.
+	* mpn/arm/v5/gcd_11.asm: Likewise.
+	* mpn/arm/v6t2/gcd_11.asm: Likewise.
+	* mpn/arm64/gcd_11.asm: Likewise.
+	* mpn/powerpc64/mode64/gcd_11.asm: Likewise.
+	* mpn/powerpc64/mode64/p7/gcd_11.asm: Likewise.
+	* mpn/powerpc64/mode64/p9/gcd_11.asm: Likewise.
+	* mpn/sparc64/gcd_11.asm: Likewise.
+	* mpn/x86/k7/gcd_11.asm: Likewise.
+	* mpn/x86/p6/gcd_11.asm: Likewise.
+	* mpn/x86_64/bd2/gcd_11.asm: Likewise.
+	* mpn/x86_64/core2/gcd_11.asm: Likewise.
+	* mpn/x86_64/gcd_11.asm: Likewise.
+	* mpn/asm-defs.m4: Add gcd_11.
+
+2019-08-06  Niels Möller  <nisse@lysator.liu.se>
+
+	* tune/common.c (speed_mpn_gcd_11): New function.
+	* tune/speed.h (speed_mpn_gcd_11): Declare it.
+	(SPEED_ROUTINE_MPN_GCD_11): New macro.
+	* tune/speed.c (routine): Add mpn_gcd_11.
+
+	* configure.ac (gmp_mpn_functions): Added gcd_11. Also add
+	HAVE_NATIVE_mpn_gcd_11.
+	* mpn/generic/gcd_11.c (mpn_gcd_11): New file and function,
+	extracted from mpn_gcd_1.
+	* gmp-h.in (mpn_gcd_11): Declare it.
+	* mpn/generic/gcd_1.c (mpn_gcd_1): Adapted to call mpn_gcd_11.
+
+2019-08-04  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86_64/bt2/gcd_1.asm: New grabber file.
+	* mpn/x86_64/zen/gcd_1.asm: Grab from "bd2" directory, was "core2".
+
+2019-08-02  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86_64/bd2/gcd_1.asm: New file.
+
+2019-08-01  Torbjörn Granlund  <tg@gmplib.org>
+
+	* tests/mpf/t-conv.c: Add several more fixed test cases.
+
+	* mpf/set_str.c: Ignore leading zeros including ones after radix point
+	to avoid invalid output formats.
+
+2019-07-30  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/powerpc64/mode64/p9/gcd_1.asm: New file.
+
+2019-07-30  Niels Möller  <nisse@lysator.liu.se>
+
+	From Seth Troisi:
+	* doc/gmp.texi (Jacobi Symbol): Update algorithm documentation.
+	* tests/mpz/t-jac.c: Comment update.
+
+2019-07-13  Torbjörn Granlund  <tg@gmplib.org>
+
+	* configure.ac (arm): Generalise arm a72 pattern to match a73...a79.
+
+2019-07-08  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/arm/arm-defs.m4 (ASM_START): Rewrite (fix broken error handling).
+
+2019-07-02  Torbjörn Granlund  <tg@gmplib.org>
+
+	* acinclude.m4 (GMP_C_DOUBLE_FORMAT): Compile conftest.c to executable
+	in order to trigger final compile in case of LTO.
+
+2019-06-17  Torbjörn Granlund  <tg@gmplib.org>
+
+	* config.guess: Work around upstream configfsf.guess's regression wrt
+	mips vs mips64.
+
+2019-06-14  Torbjörn Granlund  <tg@gmplib.org>
+
+	* longlong.h (mips64): Provide r6 asm code as default expression yields
+	libcall.
+
+	* configure.ac (mips64): Use separate paths for r6 and non-r6 as these
+	architectures are mutually incompatible.
+
+	* mpn/mips64/{addmul_1,mul_1,sqr_diagonal,submul_1,umul}.asm:
+	Move into hilo subdir.
+
+2019-05-28  Torbjörn Granlund  <tg@gmplib.org>
+
+	* config.sub: Fixes to which cpu types end with a "*".
+
+2019-04-20  Niels Möller  <nisse@lysator.liu.se>
+
+	* doc/gmp.texi (References): Link to paper on subquadratic GCD.
+
+2019-04-19  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86_64/bd1/hamdist.asm: Really make 2017-06-01 change: Use
+	3-operand DEF_OBJECT.
+
+	* mpn/x86_64/invert_limb.asm: Simplify mpn_invert_limb_table ref.
+
+	* mpn/x86_64/x86_64-defs.m4 (LEA): Use rip addressing for non-PIC.
+
+2019-04-17  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/jacobi.c (mpn_jacobi_n): Use JACOBI_DC_THRESHOLD,
+	not GCD_DC_THRESHOLD. Inconsistency spotted by Seth Troisi.
+
+2019-04-02  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86_64/fat/fat.c (__gmpn_cpuvec_init):
+	Split out silvermont handling, add handling of goldmont.
+
+	* configure.ac: Setup distinct paths for silvermont and goldmont.
+	(fat_path): Add missing x86_64/goldmont.
+
+	* config.guess: Recognise "Goldmont Plus".
+
+2018-12-09  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/generic/mul_fft.c (mpn_fft_add_sub_modF): New function.
+	(mpn_fft_fft, mpn_fft_fftinv): Use it.
+
+2018-11-30  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/powerpc64/mode64/p9/gmp-mparam.h: New file.
+
+	* mpn/powerpc64/mode64/p9/add_n_sub_n.asm: New file.
+
+2018-11-28  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/powerpc64/mode64/p9/sqr_basecase.asm: New file.
+	* mpn/powerpc64/mode64/p9/mul_1.asm: New file.
+
+2018-11-18  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/powerpc64/mode64/p9/mul_basecase.asm: New file.
+
+	* mpn/powerpc64/mode64/p9/addmul_1.asm: Optimise.
+
+2018-11-12  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/powerpc64/mode64/p9/aorsmul_1.asm: New file, providing fast
+	submul_1 (and redundant addmul_1).
+
+2018-11-11  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/powerpc64/mode64/p9/addmul_1.asm: Tweak for slightly better
+	speed.
+
+	* mpn/powerpc32/powerpc-defs.m4: Define addex.
+	* mpn/powerpc64/mode64/p9/mul_2.asm: Use it.
+	* mpn/powerpc64/mode64/p9/addmul_2.asm: Likewise.
+
+2018-11-08  Torbjörn Granlund  <tg@gmplib.org>
+
+	* tests/devel/cnd_aors_n.c: New file.
+
+	* mpn/arm/neon/lorrshift.asm: Declare use of neon insns.
+	* mpn/arm/neon/lshiftc.asm: Likewise + cleanup.
+
+	* tests/devel/Makefile.am (EXTRA_PROGRAMS): Add missing files.
+
+	* mpn/powerpc64/mode64/p9/mul_2.asm: New file.
+	* mpn/powerpc64/mode64/p9/addmul_2.asm: New file.
+
+2018-11-07 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpz/lucnum2_ui.c: Use mpn_rsblsh1_n if available.
+	* tests/mpz/t-nextprime.c: Add one more interval.
+	* tests/mpz/t-pprime_p.c (check_fermat_mersenne): New tests.
+	* mpn/generic/mod_1_3.c: typo in a comment.
+	* mpz/nextprime.c: Use tdiv instead of fdiv.
+
+	* mpn/generic/fib2m.c: New file, Fibonacci numbers modulo.
+	* configure.ac (gmp_mpn_functions): Add it.
+	* gmp-impl.h: Declare mpn_fib2m.
+	* tests/mpn/t-fib2m.c: New file, tests for mpn_fib2m.
+	* tests/mpn/Makefile.am (check_PROGRAMS): Add t-fib2m.
+
+	* mpn/generic/mod_34lsub1.c: Initialise c[012] once.
+	* tests/mpz/t-pprime_p.c (check_primes): Two more primes.
+	* tests/mp?: Use TESTS_REPS in many files.
+
+	* mpn/generic/strongfibo.c: New file, Fibonacci primality test.
+	* configure.ac (gmp_mpn_functions): Add it.
+	* gmp-impl.h: Declare mpn_strongfibo.
+
+	* mpz/stronglucas.c: New file, strong Lucas primality test.
+	* Makefile.am (MPZ_OBJECTS): Add it.
+	* mpz/Makefile.am (libmpz_la_SOURCES): Add it.
+	* gmp-impl.h: Declare mpz_stronglucas.
+
+	* mpz/millerrabin.c: Implement BPSW test for primality.
+
+2018-11-07  Torbjörn Granlund  <tg@gmplib.org>
+
+	* configure.ac (arm): Support a12 and a17.
+	* config.sub: Generalise arm matching.
+	* config.guess: Recognise additional arm CPUs.
+
+	* mpn/arm/arm-defs.m4 (ASM_START): Provide local definition.
+
+2018-10-30  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/arm/v7a/cora17/mod_34lsub1.asm: New file.
+	* mpn/arm/v7a/cora17/gmp-mparam.h: New file.
+	* mpn/arm/v7a/cora17/mul_1.asm: New grabber file.
+	* mpn/arm/v7a/cora17/addmul_1.asm: Likewise.
+	* mpn/arm/v7a/cora17/submul_1.asm: Likewise.
+
+2018-10-18 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/fib2_ui.c: Simplify the possible -2 case.
+
+2018-07-19 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpz/millerrabin.c (mod_eq_m1): New function, equality with -1.
+	* mpz/powm_ui.c: Small optimisations.
+
+2018-07-03  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86_64/lshift.asm: Remove cnt = 1 special code.
+
+	* mpn/x86_64/silvermont/popcount.asm: Add missing ABI_SUPPORT decls.
+	* mpn/x86_64/silvermont/hamdist.asm: Likewise.
+	* mpn/x86_64/zen/mul_1.asm: Likewise.
+
+	* mpn/x86_64/fastsse/lshift.asm: Support DOS64.
+	* mpn/x86_64/fastsse/lshiftc.asm: Likewise.
+
+	* mpn/x86_64/pentium4/gmp-mparam.h: Retune.
+
+2018-07-01  Torbjörn Granlund  <tg@gmplib.org>
+
+	* lshift.asm: Replace with grabber file.
+	* lshiftc.asm: Replace with grabber file.
+	* x86_64/pentium4/addmul_2.asm: New grabber file.
+	* x86_64/pentium4/aorsmul_1.asm: New grabber file.
+	* x86_64/pentium4/mul_1.asm: New grabber file.
+	* x86_64/pentium4/mul_2.asm: New grabber file.
+	* x86_64/pentium4/mul_basecase.asm: New grabber file.
+	* x86_64/pentium4/mullo_basecase.asm: New grabber file.
+	* x86_64/pentium4/redc_1.asm: New grabber file.
+	* x86_64/pentium4/sqr_basecase.asm: New grabber file.
+
+2018-06-13  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/gcd_1.c (mpn_gcd_1): Delete unused code variant for
+	GCD_1_METHOD == 1, and delete GCD_1_METHOD macro. Simplify the
+	structure of the remaining code variant, without gotos to the
+	mid-loop strip_u_maybe label.
+
+2018-05-30  Torbjörn Granlund  <tg@gmplib.org>
+
+	* configure.ac (x86): Provide goldmont specific path.
+
+	* mpn/x86_64/goldmont/gmp-mparam.h: New file.
+
+2018-05-29  Torbjörn Granlund  <tg@gmplib.org>
+
+	* configure.ac (x86): Pass more exact arch/tune options for nehalem.
+
+2018-05-28  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/gcd_1.c (mpn_gcd_1) [USE_ZEROTAB]: Delete unused code
+	variant for USE_ZEROTAB != 0.
+
+2018-05-20 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* bootstrap.c: Define DONT_USE_FLOAT_H before including mini-gmp.
+
+2018-05-14 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/dcpi1_bdiv_q.c (mpn_dcpi1_bdiv_q_n): Decl. static.
+	(mpn_dcpi1_bdiv_q_n_itch): Declare static.
+	* mpn/generic/dcpi1_divappr_q.c (mpn_dcpi1_divappr_q_n): static.
+	* mpn/generic/matrix22_mul.c (mpn_matrix22_mul_strassen): static.
+	* mpn/generic/mu_div_qr.c (mpn_mu_div_qr_choose_in): static.
+	* mpn/generic/mu_divappr_q.c (mpn_preinv_mu_divappr_q): static.
+	(mpn_mu_divappr_q_choose_in): static.
+	* gmp-impl.h: Remove declaration of previous functions.
+
+	* mpn/generic/get_d.c: Enhance generic code using DBL_MANT_DIG.
+
+	* printf/repl-vsnprintf.c: Better handling floating-point
+	specifiers "EeGgFf" (Thanks Vincent Lefevre).
+
+2018-05-04 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* doc/gmp.texi (mpq_*_str): Document the full base allowed range.
+	* mpq/get_str.c: Make all bases either work or return an error.
+
+	* doc/gmp.texi (Integer Internals): Lazy allocation and read-only.
+
+2018-04-27  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/div_q.c (mpn_div_q): Replace dead code with ASSERT.
+	Spotted by Paul Zimmermann and Raphaël Rieu-Hleft.
+
+	* tests/mpn/t-div.c (main): Fill quotient area with junk before
+	calling mpn_div_q.
+
+2018-04-26 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* Makefile.am (EXTRA_DIST): Add mini-gmp/mini-mpq.[ch].
+
+2018-04-23 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/toom2_sqr.c: Handle the cy=-1 branch slightly faster.
+	* mpn/generic/toom22_mul.c: Likewise. (Thanks Paul and Raphaël!)
+
+2018-04-22  Niels Möller  <nisse@lysator.liu.se>
+
+	From Martin Storsjö:
+	* configure.ac (aarch64): Just as on windows/x86_64, "long" still
+	is 32 bit on aarch64. To distinguish between 32-bit and 64-bit
+	ABI, test sizeof(void*) instead of sizeof(long). Use long long for
+	mp_limb_t for mingw targets.
+	* acinclude.m4 (GMP_C_TEST_SIZEOF): Allow '*' in the type name,
+	e.g., void*.
+
+2018-04-18  Marc Glisse  <marc.glisse@inria.fr>
+
+	* mpq/clear.c: Handle lazy numerator.
+	* mpq/clears.c: Likewise.
+	* mpq/init.c: Likewise.
+	* mpq/set_si.c: Likewise.
+	* mpq/set_ui.c: Likewise.
+
+	* tests/cxx/t-ops2z.cc: Add parentheses to quiet a warning.
+
+2018-03-28  Torbjörn Granlund  <tg@gmplib.org>
+
+	* configure.ac (mips): Recognise "mipsisa64*".
+
+2018-03-23  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/generic/sec_powm.c: Remove unused macros.
+	Simplify code for choosing between redc_1 and redc_2.
+	Compute power table with squaring for even powers.
+
+2018-02-28 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* gmpxx.h (__gmp_binary_plus): Special case for mpq + 1.
+	(__gmp_binary_minus): Special case for mpq - 1.
+	(__gmp_binary_equal): Optimised comparison mpq == integer.
+	* tests/cxx/t-ops2qf.cc (checkqf): Some check for +/- 1, +/- 0.
+
+2018-02-18 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* tune/Makefile.am: Disallow parallel make (thanks Vincent Lefevre).
+	* mpq/swap.c: Use *_SWAP_* macros.
+	* mpq/cmp_ui.c: One more little shortcut, comparing fractions to 1.
+	* mpq/get_d.c: Compare (zeros > 0) once, replace tdiv_qr with div_q.
+	* mpq/equal.c: Check size early.
+
+	* printf/obprintf.c: Adda dummy typedef to avoid empty unit.
+	* printf/obvprintf.c: Likewise.
+	* printf/obprntffuns.c: Likewise.
+	* printf/repl-vsnprintf.c: Move #ifdef after #include gmp-impl.h .
+
+2018-02-09  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/arm: Really revert 2018-01-04 changes.
+
+2018-02-08 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* printf/snprntffuns.c: Report -1 as an error.
+	* acinclude.m4 (GMP_FUNC_VSNPRINTF): Refuse -1 as return value.
+
+	* mpz/bin_uiui.c (mpz_smallk_bin_uiui): One more shortcut for small k.
+	* gmp-impl.h (popc_limb): Use fewer constants (GMP_LIMB_BITS == 16).
+	* mpz/divegcd.c (mpz_divexact_limb): Use MPN_DIVREM_OR_DIVEXACT_1.
+	* primesieve.c (fill_bitpattern): Use MPN_FILL.
+
+2018-02-01  Marc Glisse  <marc.glisse@inria.fr>
+
+	* longlong.h (i586): Remove assert.
+
+2018-01-30 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpz/and.c: Rearrange the 3 cases, both <0, both >=0, one and one.
+	* mpz/ior.c: Likewise.
+	* mpz/xor.c: Likewise.
+
+	* mpz/bin_uiui.c (mul[4-8]): Reduce the number of multiplications.
+
+	* printf/doprnt.c: Use __GMP_FREE_FUNC_TYPE.
+	* printf/doprntf.c: Likewise.
+	* printf/snprntffuns.c: Likewise, and use size_t instead of int.
+
+2018-01-15 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* tests/mpz/t-bin.c: Extended tests for bin_ui and uint border cases.
+
+2018-01-10  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86/fat/fat.c (__gmpn_cpuvec_init): Fix old pentium recog.
+	* config.guess: Likewise.
+
+	* mpn/x86/fat/fat.c (__gmpn_cpuvec_init): Add many 64-bit CPUs.
+
+2018-01-07  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/arm: Revert last change, it hides a symbol needed for testing.
+
+2018-01-04  Torbjörn Granlund  <tg@gmplib.org>
+
+	* bdiv_q_1.asm (binvert_limb_table): Declare as ".hidden".
+	* v7a/cora8/bdiv_q_1.asm: Likewise.
+	* dive_1.asm: Likewise.
+	* v6/dive_1.asm: Likewise.
+
+	* mode1o.asm (binvert_limb_table): Remove ".protected", add ".hidden".
+	* v6/mode1o.asm: Likewise.
+
+2018-01-02  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/powerpc64/mode64/divrem_2.asm: Use different rlwinm variant (to
+	appease clang).
+
+2018-01-01  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/powerpc32/powerpc-defs.m4: Define maddld, maddhdu, popcntd, and
+	divdeu.
+	* mpn/powerpc64/mode64/p8/invert_limb.asm: Use new insn defs.
+	* mpn/powerpc64/mode64/p9/addmul_1.asm: Use new insn defs.
+	* mpn/powerpc64/p7/hamdist.asm: Use new insn defs.
+	* mpn/powerpc64/p7/popcount.asm: Use new insn defs.
+
+2017-12-31  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/powerpc64/mode64/p9/addmul_1.asm: Moved from
+	mpn/powerpc64/p9/addmul_1.asm.
+
+2017-12-30 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpz/bin_ui.c: Rewrite, using Fredrik Johansson's suggestions.
+
+2017-12-27  Niels Möller  <nisse@lysator.liu.se>
+
+	* longlong.h (arm32/arm64): Leave COUNT_LEADING_ZEROS_0 undefined,
+	since we use gcc's __builtin_clzl, which doesn't allow zero inputs.
+
+2017-12-27  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/powerpc64/mode64/bdiv_q_1.asm: Use 64-bit cmp for sizes.
+
+	* mpn/powerpc64/p9/addmul_1.asm: New file.
+
+	* configure.ac: Separate handling of POWER8 and POWER9.
+
+	* config.guess: Recognise POWER9 and more variants of POWER8.
+	Reorder recog code to favour PVR over proc/cpuinfo.
+
+2017-12-14  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86_64/fastsse/com.asm: Adhere to DOS64 xmm callee-saves rules.
+	* mpn/x86_64/fastsse/com-palignr.asm: Likewise.
+	* mpn/x86_64/fastsse/copyd.asm: Likewise.
+	* mpn/x86_64/fastsse/copyi.asm: Likewise.
+	* mpn/x86_64/fastsse/lshiftc.asm: Likewise.
+	* mpn/x86_64/fastsse/sec_tabselect.asm: Likewise.
+
+2017-12-11  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86_64/bd1/aorrlsh_n.asm: New grabber file.
+
+2017-12-10  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86_64/bd1/aors_n.asm: New grabber file.
+
+	* mpn/x86_64/bd4/aorrlsh_n.asm: New grabber file.
+
+2017-08-31  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/sparc32/sparc-defs.m4 (LEA64): Rewrite for both PIC and non-PIC.
+
+	* mpn/sparc64/ultrasparct3/cnd_aors_n.asm: Allow arbitrary cnd arg.
+
+2017-08-29  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86_64/silvermont/gmp-mparam.h: Disable mul_2 and addmul_2.
+
+2017-08-28  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/sparc64: Revert 2017-07-23 PIC changes.
+
+	* mpn/powerpc32/divrem_2.asm: Avoid bc+ insn form to accommodate clang.
+
+	* mpn/generic/sbpi1_bdiv_qr.c: Correct ASSERT.
+	* mpn/generic/sbpi1_bdiv_q.c: Likewise.
+	* mpn/generic/sbpi1_bdiv_r.c: Likewise.
+
+2017-08-18  Torbjörn Granlund  <tg@gmplib.org>
+
+	* acinclude.m4 (X86_64_PATTERN): Match zen*.
+
+	* configure.ac (x86): Support AVX challenged systems for Zen.
+
+2017-07-24  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/generic/sbpi1_bdiv_q.c: Add ASSERT for inverse correctness.
+	* mpn/generic/sbpi1_bdiv_qr.c: Likewise.
+
+	* tests/mpn/t-bdiv.c (main): Amend last change.
+
+	* tests/devel/try.c (choice_array): Amend 2013-05-03 change to include
+	more functions.
+
+2017-07-23  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/sparc64/gcd_1.asm: Enforce PIC as GNU/Linux toolchain workaround.
+	* mpn/sparc64/ultrasparct3/bdiv_q_1.asm: Likewise.
+	* mpn/sparc64/ultrasparct3/dive_1.asm: Likewise.
+	* mpn/sparc64/ultrasparct3/invert_limb.asm: Likewise.
+	* mpn/sparc64/ultrasparct3/mode1o.asm: Likewise.
+
+	* gmp-impl.h: Reorganise foolshC_ip1 -> foolshC -> foolsh chain to make
+	it transitive.
+
+2017-07-23  Niels Möller  <nisse@lysator.liu.se>
+
+	* longlong.h: Purge definitions of obsolete UMUL_TIME and
+	UDIV_TIME constants. Also mentioned (but unused) in
+	mpn/cray/gmp-mparam.h and tune/common.c.
+
+2017-07-21  Torbjörn Granlund  <tg@gmplib.org>
+
+	* tests/mpn/t-bdiv.c (main): Test mpn_sbpi1_bdiv_r.
+
+	* tune/common.c (speed_mpn_sbpi1_bdiv_r): New function.
+	* tune/speed.h: Declare it.
+	(SPEED_ROUTINE_MPN_PI1_BDIV_R): New macro.
+	* tune/speed.c (routine): Add mpn_sbpi1_bdiv_r.
+
+2017-07-20  Torbjörn Granlund  <tg@gmplib.org>
+
+	* configure.ac (gmp_mpn_functions): Add sbpi1_bdiv_r.
+
+	* gmp-impl.h (mpn_sbpi1_bdiv_r): Declare.
+
+	* mpn/asm-defs.m4 (define_mpn): Add sbpi1_bdiv_q, sbpi1_bdiv_qr,
+	sbpi1_bdiv_r.
+
+	* mpn/generic/sbpi1_bdiv_r.c: New file.
+	* mpn/x86_64/zen/sbpi1_bdiv_r.asm: New file.
+
+2017-07-19  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86/p6/sse2/submul_1.asm: Get pentium4 code instead of k6 code
+	for better speed on modern Intel P6 cores.
+
+2017-07-02  Torbjörn Granlund  <tg@gmplib.org>
+
+	* tune/tuneup.c (tune_mullo): For MULLO_BASECASE_THRESHOLD start at 2.
+	(tune_sqrlo): Likewise.
+
+2017-06-28  Torbjörn Granlund  <tg@gmplib.org>
+
+	* tests/Makefile.am tests/*/Makefile.am tune/Makefile.am (AM_LDFLAGS):
+	Define.  (Thanks to Emmanuel Thomé and Vincent Lefevre.)
+
+2017-06-27  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86_64/zen/sqr_basecase.asm: Expand to use 4 addmul_1 loops.
+
+	* mpn/x86_64/x86_64-defs.m4 (sarx): New macro.
+
+2017-06-26  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86_64/coreibwl/sqr_basecase.asm: Rewrite to do 2x and limb
+	squaring in main loop.
+
+2017-06-20  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86_64/atom/cnd_add_n.asm: New grabber file.
+	* mpn/x86_64/atom/cnd_sub_n.asm: Likewise.
+
+	* mpn/x86_64/coreihwl/aorrlsh_n.asm: New grabber file.
+
+2017-06-16  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86_64/zen/mul_basecase.asm: Do overlapped software pipelining.
+
+	* mpn/x86_64/silvermont/mul_basecase.asm: New grabber file.
+	* mpn/x86_64/silvermont/sqr_basecase.asm: Likewise.
+	* mpn/x86_64/silvermont/mullo_basecase.asm: Likewise.
+
+2017-06-14  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86_64/zen/mullo_basecase.asm: New file.
+	* mpn/x86_64/coreibwl/mullo_basecase.asm: New file.
+
+2017-06-11  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86_64/popham.asm: Crossjump for code size and mix lead-in insns
+	for lower overhead.
+
+2017-06-09  Torbjörn Granlund  <tg@gmplib.org>
+
+	* configure.ac: Set GMP_NONSTD_ABI protecting against dots in the abi.
+	(hppa): Remove old GNU/Linux restriction to 32-bit ABI.
+
+2017-06-07  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86_64/bd1/addmul_2.asm: New file.
+
+2017-06-06  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86_64/coreihwl/aors_n.asm: New file.
+
+	* mpn/x86_64/x86_64-defs.m4 (c4_helper): New macro.
+	(mulx, shlx, shrx): Use c4_helper.
+
+	* mpn/x86_64/zen/mul_basecase.asm: Use 8-bit imm operands for "test".
+
+	* mpn/x86_64/zen/aorrlsh1_n.asm: New grabber file.
+	* mpn/x86_64/zen/sublsh1_n.asm: Likewise.
+	* mpn/x86_64/zen/aorrlsh_n.asm: New file
+
+2017-06-04  Torbjörn Granlund  <tg@gmplib.org>
+
+	* configure.ac: Use bt1/bt2 for bobcat and jaguar dirs.
+	(fat_path): Add x86_64/bt2.
+
+	* mpn/x86_64/fat/fat.c (__gmpn_cpuvec_init): Adapt to bt1/bt2 changes.
+	Make zen path correspond to non-fat path.
+	* mpn/x86/fat/fat.c (__gmpn_cpuvec_init): Adapt to bt1/bt2 changes.
+
+	* mpn/x86_64/bt2/copyi.asm: New grabber file.
+	* mpn/x86_64/bt2/copyd.asm: New grabber file.
+	* mpn/x86_64/bt2/com.asm: New grabber file.
+
+2017-06-03  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86_64/bd1/popcount.asm: Expand some instructions as .byte
+	sequences.
+	* mpn/x86_64/bd1/hamdist.asm: Likewise.
+
+2017-06-02  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86_64/x86_64-defs.m4 (DEF_OBJECT): Fix quoting (amends recent
+	change).
+	(JUMPTABSECT): Get rid of spurious "w".
+
+2017-06-02  Marc Glisse  <marc.glisse@inria.fr>
+
+	* gmpxx.h (mpf_class::operator bool): Use mpf_sgn to access _mp_size.
+
+2017-06-02  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86_64/bd1/popcount.asm: Use both SSE and XOP trickery, and
+	plain popcnt insn.
+	* mpn/x86_64/bd1/hamdist.asm: Likewise.
+
+2017-06-01  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86_64/x86_64-defs.m4 (DEF_OBJECT): Allow 3rd argument defining
+	section, while making alignment argument non-optional.
+
+	* mpn/x86_64/core2/popcount.asm: Use 3-operand DEF_OBJECT.
+	* mpn/x86_64/core2/hamdist.asm: Likewise.
+	* mpn/x86_64/bd1/popcount.asm: Likewise.
+	* mpn/x86_64/bd1/hamdist.asm: Likewise.
+
+	* configure.ac (GMP_AVX_NOT_REALLY_AVAILABLE): New m4 define.
+	* mpn/x86_64/bd1/popcount.asm: Use GMP_AVX_NOT_REALLY_AVAILABLE.
+	* mpn/x86_64/bd1/hamdist.asm: Likewise.
+
+	* mpn/x86_64/silvermont/popcount.asm: Reinstate, grabbing nehalem code.
+	* mpn/x86_64/silvermont/hamdist.asm: Replace with grabber.
+
+2017-05-31  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86_64/silvermont/popcount.asm: Remove.
+
+	* mpn/x86_64/core2/logops_n.asm: New file.
+
+2017-05-30  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86_64/coreisbr/popcount.asm: Remove.
+
+2017-05-29  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86_64/coreinhm/popcount.asm: Replace grabber code with
+	implementation proper.
+	* mpn/x86_64/coreinhm/hamdist.asm: Likewise.
+	* mpn/x86_64/bd1/popcount.asm: Likewise.
+	* mpn/x86_64/bd1/hamdist.asm: Likewise.
+	* mpn/x86_64/core2/popcount.asm: Likewise.
+	* mpn/x86_64/core2/hamdist.asm: New file.
+
+2017-05-22  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86_64/core2/com.asm: New grabber file.
+
+	* mpn/x86_64/core2/lshift.asm: Rewrite.
+	* mpn/x86_64/core2/rshift.asm: Rewrite.
+	* mpn/x86_64/core2/lshiftc.asm: Rewrite.
+
+2017-05-16  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86_64/zen/mul_1.asm: Port to DOS64.
+	* mpn/x86_64/zen/aorsmul_1.asm: Likewise.
+	* mpn/x86_64/coreibwl/addmul_1.asm: Likewise.
+
+2017-05-16  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/divis.c (mpn_divisible_p): Updated the divisibility
+	test; bdiv now returns R = D rather than R = 0 when D divides a
+	non-zero U.
+
+	* mpn/generic/binvert.c (mpn_binvert): Negate bdiv quotient.
+	* mpn/generic/divexact.c (mpn_divexact): Likewise.
+	* mpn/generic/remove.c (mpn_remove): Likewise.
+	* mpz/bin_uiui.c (mpz_bdiv_bin_uiui): Likewise.
+
+	* tests/mpn/t-bdiv.c (check_one): Updated to new convention,
+	B^{qn} R = U + QD.
+
+	* mpn/generic/sbpi1_bdiv_qr.c (mpn_sbpi1_bdiv_qr): Reimplemented,
+	for new bdiv convention.
+	* mpn/generic/sbpi1_bdiv_q.c (mpn_sbpi1_bdiv_q): Likewise.
+	* mpn/generic/dcpi1_bdiv_q.c (mpn_dcpi1_bdiv_q_n)
+	(mpn_dcpi1_bdiv_q): Adapted to new bdiv convention.
+	* mpn/generic/dcpi1_bdiv_qr.c (mpn_dcpi1_bdiv_qr_n)
+	(mpn_dcpi1_bdiv_qr): Likewise.
+	* mpn/generic/mu_bdiv_qr.c (mpn_mu_bdiv_qr): Adapted to new bdiv
+	convention, using a wrapper calling the old function.
+	* mpn/generic/mu_bdiv_q.c (mpn_mu_bdiv_q): Likewise.
+
+2017-05-03  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86_64/coreisbr/cnd_aors_n.asm: New file.
+	* mpn/x86_64/coreisbr/cnd_add_n.asm: New file.
+
+	* mpn/x86_64/core2/aorsmul_1.asm: Tune.
+
+	* mpn/x86_64/silvermont/mul_1.asm: New file, grabbing another asm file.
+	* mpn/x86_64/silvermont/aorsmul_1.asm: Likewise.
+	* mpn/x86_64/silvermont/aorrlsh1_n.asm: Likewise.
+	* mpn/x86_64/silvermont/aorrlsh2_n.asm: Likewise.
+	* mpn/x86_64/silvermont/lshift.asm: Likewise.
+	* mpn/x86_64/silvermont/rshift.asm: Likewise.
+	* mpn/x86_64/silvermont/lshiftc.asm: Likewise.
+
+	* mpn/x86_64/zen/mul_basecase.asm: Split outer loop into 4 loops.
+
+2017-05-02  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86_64/zen/sqr_basecase.asm: Use .byte for encoding all mulx.
+	Misc tuning.
+
+2017-04-27  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86_64/zen/sqr_basecase.asm: Rewrite to do 2x and limb squaring
+	in main loop.
+
+2017-04-25  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86_64/fat/fat_entry.asm: Allocate correct DOS64 frame.
+	* mpn/x86_64/divrem_2.asm: Likewise.
+	* mpn/x86_64/mod_1_2.asm: Likewise.
+	* mpn/x86_64/mod_1_4.asm: Likewise.
+	* mpn/x86_64/mod_1_1.asm: Likewise.
+
+2017-04-23  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86_64/coreisbr/mul_1.asm: Rewrite feed-in code and add mul_1c
+	entry point.
+
+2017-04-17  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86_64/fat/fat.c (__gmpn_cpuvec_init): Amend last change.
+
+	* mpn/x86_64/zen/mul_basecase.asm: New file.
+	* mpn/x86_64/zen/sqr_basecase.asm: New file.
+
+2017-04-16  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/generic/sqr_basecase.c (addmul_1 variant): Rewrite to compute
+	in-place and to avoid a re-computation.
+
+	* configure.ac: Remove k8, k10 from zen path.
+
+2017-04-15  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86_64/zen/gmp-mparam.h: New file.
+
+	* mpn/x86_64/zen/com.asm: New file, grabbing another asm file.
+	* mpn/x86_64/zen/copyd.asm: Likewise.
+	* mpn/x86_64/zen/copyi.asm: Likewise.
+	* mpn/x86_64/zen/gcd_1.asm: Likewise.
+	* mpn/x86_64/zen/hamdist.asm: Likewise.
+	* mpn/x86_64/zen/lshift.asm: Likewise.
+	* mpn/x86_64/zen/lshiftc.asm: Likewise.
+	* mpn/x86_64/zen/popcount.asm: Likewise.
+	* mpn/x86_64/zen/rshift.asm: Likewise.
+
+	* config.guess: Recognise AMD zen.
+	* acinclude.m4 (X86_64_PATTERN): Add zen.
+	* config.sub: Corresponding changes.
+	* configure.ac: Corresponding changes.
+	* mpn/x86_64/fat/fat.c: Corresponding changes.
+
+2017-03-27 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpz/oddfac_1.c (limb_apprsqrt): Better approximation.
+	* mpz/bin_uiui.c (limb_apprsqrt): Likewise.
+
+2017-03-12  Torbjörn Granlund  <tg@gmplib.org>
+
+	* tests/mpf/t-get_d_2exp.c (check_data): Rewrite of check_onebit.
+
+2017-03-08 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/sqrtrem.c: Direct use of sqrtrem2 when n==2.
+	* mpn/generic/div_qr_2.c (udiv_qr_4by2): Replace add_csaac with add_sssaaaa.
+
+2017-03-07  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpf/get_d_2exp.c: Return negative value for negative input.
+
+2017-03-06  Torbjörn Granlund  <tg@gmplib.org>
+
+	* longlong.h (aarch64): Provide asm-free umul_ppmm.
+	* longlong.h (powerpc64): Enable asm-free umul_ppmm.
+
+2017-03-04  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/arm64/sqr_diag_addlsh1.asm: Complete rewrite.
+
+2017-02-27  Torbjörn Granlund  <tg@gmplib.org>
+
+	* longlong.h (arm32/arm64): Remove useless comparison to 0 introduced
+	in last change (spotted by Marco).
+
+2017-02-26 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/pow_1.c: Use umul_ppmm for a single limb.
+
+2017-02-25  Torbjörn Granlund  <tg@gmplib.org>
+
+	* configure.ac: Allow MP_SIZE_T_MAX for thresholds exported to
+	config.m4.
+
+	* mpn/x86_64/gcd_1.asm: Handle BMOD_1_TO_MOD_1_THRESHOLD=MP_SIZE_T_MAX.
+	Streamline non-reduction path.
+	* mpn/x86_64/core2/gcd_1.asm: Streamline small operands cases similarly
+	to top-level code.
+
+2017-02-24  Torbjörn Granlund  <tg@gmplib.org>
+
+	* longlong.h (arm32/arm64 add_ssaaaa): Use "subs" for some immediates.
+	* longlong.h (arm32/arm64 sub_ddmmss): Use "adds" for some immediates.
+
+	* mpn/arm64/copyi.asm: Avoid branching on flags.
+	* mpn/arm64/copyd.asm: Likewise.
+
+	* mpn/generic/div_qr_2.c (aarch64 add_sssaaaa): New.
+	* mpn/generic/div_qr_1n_pi2.c: Same.
+	* mpn/generic/div_qr_1u_pi2.c: Same.
+
+	* mpn/generic/div_qr_2.c (powerpc add_sssaaaa): Fix typo.
+	* mpn/generic/div_qr_1n_pi2.c: Same.
+	* mpn/generic/div_qr_1u_pi2.c: Same.
+
+2017-02-23 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* tests/devel/sqrtrem_1_2.c: New exhaustive test for sqrtrem_[12].
+	* tests/devel/Makefile.am (EXTRA_PROGRAMS): add it.
+
+2017-02-23  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86_64/silvermont/gmp-mparam.h: New file.
+
+2017-02-22  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/arm64/aorsmul_1.asm: Rewrite.
+
+	* mpn/arm64/lshiftc.asm: New file.
+
+2017-02-21  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/arm64/lshift.asm: Rewrite.
+	* mpn/arm64/rshift.asm: Rewrite.
+
+	* mpn/arm64/rsh1aors_n.asm: New file.
+
+2017-02-19  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/arm64/mul_1.asm: Rewrite.
+	* mpn/arm64/xgene1/mul_1.asm: Remove.
+
+2017-02-17  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/arm64/cora53/cnd_aors_n.asm: Moved from "..".
+
+	* mpn/arm64/xgene1/cnd_aors_n.asm: Remove file since default code
+	performs better.
+
+	* mpn/arm64/cnd_aors_n.asm: Rewrite.
+
+	* mpn/arm64/logops_n.asm: Rewrite based on new aors_n.asm.
+
+2017-02-16  Pedro Gimeno  <pggimeno@wanadoo.es>
+
+	* rand/randmt.c (__gmp_randiset_mt): Set generator functions from
+	source.
+
+2017-02-16  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/arm64/aorsorrlshC_n.asm: New file.
+	* mpn/arm64/aorsorrlsh2_n.asm: New file.
+	* mpn/arm64/aorsorrlsh1_n.asm: New file.
+
+	* mpn/arm64/xgene1/aors_n.asm: Remove file since default code now
+	performs similarly.
+
+	* mpn/arm64/aors_n.asm: Rewrite to use 4x unrolling.
+
+2017-02-15  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86_64/silvermont/hamdist.asm: New file, based on k10 code.
+
+	* mpn/x86_64/silvermont/popcount.asm: Grab coreisbr/popcount.asm.
+
+2017-02-14  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/x86_64/silvermont/aors_n.asm: New file, grabbing coreisbr code.
+
+	* mpn/x86_64/atom/aors_n.asm: Replace coreisbr grabbing code with
+	code based on Marco's x64/atom/aors_n.asm.
+
+2017-02-12  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/powerpc64/aix.m4 (AIX): New define.
+
+	* mpn/powerpc64/mode64/bdiv_q_1.asm: For AIX, don't jump from
+	mpn_bdiv_q_1 to middle of mpn_pi1_bdiv_q_1.  Streamline.
+
+	* mpn/powerpc64/darwin.m4 (LEA): Put code in lea_list instead of in
+	EPILOGUE_cpu.
+	(EPILOGUE_cpu): Output lea_list, the zap it.
+
+	* mpn/sparc64/ultrasparct3/bdiv_q_1.asm: New file, based on dive_1.asm.
+
+2017-02-11  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/arm/v7a/cora8/bdiv_q_1.asm: New file, based on v6/dive_1.asm.
+	* mpn/arm/v7a/cora9/bdiv_q_1.asm: New file, grabbing cora8 code.
+	* mpn/arm/v7a/cora15/bdiv_q_1.asm: Likewise.
+
+	* mpn/arm64/aors_n.asm: (SETCY, RETVAL): Shorten insn sequences.
+	* mpn/arm64/cnd_aors_n.asm: Likewise.
+	* mpn/arm64/xgene1/aors_n.asm: Likewise.
+	* mpn/arm64/xgene1/cnd_aors_n.asm: Likewise.
+
+	* mpn/arm/bdiv_q_1.asm: New file, based on dive_1.asm.
+
+	* mpn/generic/bdiv_q_1.c (mpn_bdiv_q_1): Remove odd d special case.
+
+	* mpn/powerpc64/mode64/bdiv_q_1.asm: New file.
+
+	* mpn/arm64/bdiv_q_1.asm: New file.
+
+2017-02-10  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/arm/arm-defs.m4 (EPILOGUE_cpu): Zap lea_list to avoid repetition.
+
+	* mpn/x86_64/bdiv_q_1.asm: Rewrite, base on atom/dive_1.asm.
+
+2017-02-08  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/generic/compute_powtab.c: Choose mpn_pi1_bdiv_q_1 vs
+	mpn_divexact_1 more wisely (spotted by Marco).
+
+2017-02-07  Torbjörn Granlund  <tg@gmplib.org>
+
+	* tune/tuneup.c (relspeed_div_1_vs_mul_1): Prefer mpn_pi1_bdiv_q_1.
+
+	* mpn/generic/compute_powtab.c: Use mpn_pi1_bdiv_q_1/mpn_bdiv_q_1
+	instead of mpn_divexact_1.
+
+	* gen-bases.c (binvert): New function, computing modular inverse and
+	low zero count.
+	(header): Print MP_BASES_BIG_BASE_CTZ_10 and
+	MP_BASES_BIG_BASE_BINVERTED_10.
+
+2017-02-06  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/generic/bdiv_q_1.c: Make return value consistent.
+
+	* mpn/x86/p6/mmx/gmp-mparam.h (SQR_TOOM2_THRESHOLD): Revert to bogus
+	value to accommodate p6/sqr_basecase.asm fragility.
+
+2017-01-29 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpz/and.c: Simplify branches.
+	* mpz/ior.c: Likewise.
+	* mpz/xor.c: Likewise.
+
+	* gen-bases.c: In generated file, include just gmp-impl.h, not gmp.h
+
+2017-01-29  Torbjörn Granlund  <tg@gmplib.org>
+
+	* configure.ac: Don't check if we got a C99 compiler for now (partially
+	revert 2017-01-24 change as C++ compilers become rejected).
+
+2017-01-24  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/generic/compute_powtab.c: New file, providing mpn_compute_powtab
+	for both get_str and set_str.
+
+	* gmp-impl.h (mpn_str_powtab_alloc): New macro.
+	(mpn_dc_set_str_powtab_alloc, mpn_dc_get_str_powtab_alloc): Remove.
+	(mpn_compute_powtab): Declare.
+
+	* mpn/generic/set_str.c: Use mpn_compute_powtab.
+	(mpn_set_str_compute_powtab): Remove.
+
+	* mpn/generic/get_str.c: Use mpn_compute_powtab.
+	(mpn_get_str_compute_powtab): Remove.
+	(mpn_bc_get_str): New name for mpn_sb_get_str.
+
+	* configure.ac (gmp_mpn_functions): Add compute_powtab.
+
+	* tune/tuneup.c (speed_mpn_pre_set_str): Call mpn_compute_powtab.
+	* tune/set_strb.c: Remove mpn_set_str_compute_powtab name mangling.
+	* tune/set_strs.c: Likewise.
+
+	* configure.ac: Invoke AC_PROG_CC_C99 instead of AC_PROG_CC_STDC.
+
+2017-01-03  Torbjörn Granlund  <tg@gmplib.org>
+
+	* configure.ac (arm*-*-*): Properly point to cortex-a5 subdir.
+
+2016-12-31  Torbjörn Granlund  <tg@gmplib.org>
+
+	* tune/tuneup.c (relspeed_div_1_vs_mul_1): New function.
+
+2016-12-28 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* tune/common.c (speed_mpz_mfac_uiui, speed_mpz_invert): New
+	functions.
+	* tune/speed.h: Declare them.
+	* tune/speed.c (routine): Add mpz_mfac_uiui, mpz_invert.
+
+	* tests/mpz/t-primorial_ui.c: Add randomization to the test.
+	* mpz/tdiv_r.c: Reduce allocation in some corner-case conditions.
+	* mpz/tdiv_r_2exp.c: Rearrange counting non-zero limbs.
+	* mpz/tdiv_q.c: Move common code out of some branches.
+	* mpz/and.c: Alloc only when needed.
+	* mpz/xor.c: Reorder branches.
+	* mpz/gcd.c: Reorder branches.
+	* mpz/pprime_p.c: Save the initial branch of a loop.
+	* mpn/generic/divrem.c: Save an allocation.
+
+2016-12-26  Torbjörn Granlund  <tg@gmplib.org>
+
+	* longlong.h (x86_64 umul_ppmm): Add mulx variant (not automatically
+	used).
+
+2016-12-17 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpz/gcdext.c: Save an allocation if both cofactors are needed.
+	* mpz/oddfac_1.c: Revision of all ASSERTs.
+	* tests/mpz/t-invert.c: All elements are invertible in the zero ring.
+
+2016-12-13  Torbjörn Granlund  <tg@gmplib.org>
+
+	* longlong.h: Test LONGLONG_STANDALONE in two more places.
+
+2016-12-07  Torbjörn Granlund  <tg@gmplib.org>
+
+	* gmp-h.in: Check yet another symbol for FILE.
+
+2016-12-04  Torbjörn Granlund  <tg@gmplib.org>
+
+	* tests/mpz/reuse.c: Use mpz_clobber.  Split mpz_gcdext macros to avoid
+	spurious res3 dependency.
+
+	* tests/misc.c (mpz_clobber): New function.
+
+2016-12-03  Niels Möller  <nisse@lysator.liu.se>
+
+	* doc/gmp.texi (Number Theoretic Functions): Tweak mpz_gcdext
+	documentation. The first and third argument may be NULL, but not
+	the second.
+
+2016-12-02  Niels Möller  <nisse@lysator.liu.se>
+
+	* tests/mpz/reuse.c (main): Test additional cases of reuse for
+	mpz_gcd and mpz_gcdext.
+
+2016-12-01  Torbjörn Granlund  <tg@gmplib.org>
+
+	* tests/misc.c (seed_from_tod): Make shift well-defined.
+
+2016-11-29  Torbjörn Granlund  <tg@gmplib.org>
+
+	* gmp-h.in (__GNU_MP__): Bump.
+
+	* mpz/inp_raw.c: Rewrite size computation to avoid overflow.
+
+	* mpz/kronsz.c: Use ABS_CAST to avoid undefined code.
+
+2016-11-27 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpz/gcd.c, mpz/gcdext.c: Use NEWALLOC.
+	* mpz/oddfac_1.c: Disable an ASSERT that needs a revision.
+
+2016-11-27  Torbjörn Granlund  <tg@gmplib.org>
+
+	* tests/mpz/reuse.c: Rewrite operand randomisation to use fixed ranges.
+
+	* tune/time.c (cgt_works_p): Add a missing verbosity check.
+
+	* configure.ac: Make udiv_w_sdiv use conditional on enable_assembly.
+
+2016-11-25  Marc Glisse  <marc.glisse@inria.fr>
+
+	* mpz/gcdext.c (mpz_gcdext): Allow a first argument of NULL.
+	* doc/gmp.texi (Number Theoretic Functions): Document it.
+	* tests/mpz/t-gcd.c (main): Test it.
+
+2016-11-25  Marc Glisse  <marc.glisse@inria.fr>
+
+	* tests/cxx/t-ops2z.cc (checkz): Avoid left shift of negative number.
+
+2016-11-22  Torbjörn Granlund  <tg@gmplib.org>
+
+	* configure.ac (x86): Define LINUX for GNU/Linux systems.
+	* mpn/x86_64/fat/fat_entry.asm: Set PRETEND_PIC for GNU/Linux.
+
+2016-11-21  Torbjörn Granlund  <tg@gmplib.org>
+
+	* configure.ac (powerpc): Never use -O3.
+
+	* acinclude.m4 (mpn_lshift_com optimization 2): Make it well-defined
+	also for 32-bit systems.
+	(mpn_lshift_com optimization 2): Free allocated memory.
+
+2016-11-19  Niels Möller  <nisse@lysator.liu.se>
+
+	* Makefile.am (check-mini-gmp): Override CFLAGS and CPPFLAGS
+	instead of the deleted EXTRA_CFLAGS. Set TEST_LIBRARY_PATH,
+	instead of LD_LIBRARY_PATH and DYLD_LIBRARY_PATH, to avoid getting
+	gcc linked with an unexpected version of gmp.
+
+2016-11-18  Niels Möller  <nisse@lysator.liu.se>
+
+	* Makefile.am (check-mini-gmp): Get CC and EXTRA_CFLAGS right.
+
+2016-11-17  Torbjörn Granlund  <tg@gmplib.org>
+
+	* asl.h: Initial support for artificially small limbs.
+
+2016-11-09 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* pz/iset_str.c: Lazy allocation.
+
+2016-11-01  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/generic/dive_1.c: Remove a forgotten dummy while-loop.  (Spotted
+	by Peter Barfuss.)
+
+2016-10-31   Oleg Oshmyan  <chortos@inbox.lv>
+
+	* gmp-impl.h (x86_64 MPN_IORD_U): Use proper asm constraint.
+
+2016-10-30  Torbjörn Granlund  <tg@gmplib.org>
+
+	* mpn/Makefile.am (TARG_DIST): Add riscv.
+
+2016-10-28  Marc Glisse  <marc.glisse@inria.fr>
+
+	* gmpxx.h (__gmp_binary_divides): Let 1/q call mpq_inv.
+	* tests/cxx/t-ops.cc (check_mpq): Test it.
+
+2016-10-24  Torbjörn Granlund  <tg@gmplib.org>
+
+	* config.guess: Recognise Itanium Poulson.
+
+2016-10-15  Torbjörn Granlund  <tg@gmplib.org>
+
+	* configure.ac (arm*-*-*): Amend last change.
+
+2016-10-14  Torbjörn Granlund  <tg@gmplib.org>
+
+	* longlong.h (riscv umul_ppmm): New.
+
+	* mpn/riscv/64/aors_n.asm: New file.
+	* mpn/riscv/64/mul_1.asm: New file.
+	* mpn/riscv/64/aorsmul_1.asm: New file.
+
+	* mpn/generic/addmul_1.c: Rewrite for shallower recurrency.
+	* mpn/generic/submul_1.c: Likewise.
+
+	* configure.ac (riscv-*-*): New.
+	(arm*-*-*): Rewrite arm support to handle armv8 CPUs in 32-bit mode.
+
+2016-08-29  Torbjörn Granlund  <tg@gmplib.org>
+
+	* All C files: Include just gmp-impl.h, make gmp-impl.h grab gmp.h.
+
+	* mpf/get_str.c: Use __GMP_ALLOCATE_FUNC_TYPE and friends.
+	* mpf/inp_str.c: Likewise.
+	* mpq/get_str.c: Likewise.
+	* mpz/get_str.c: Likewise.
+	* mpz/inp_str.c: Likewise.
+	* scanf/vsscanf.c: Likewise.
+	* tal-reent.c: Likewise.
+
+2016-08-24  Vlad Zakharov <vzakhar@synopsys.com>
+
+	* longlong.h (arc add_ssaaaa, sub_ddmmss): Replace obsolete 'J'
+	constraint with 'Cal'.
+
+2016-08-22  Marc Glisse  <marc.glisse@inria.fr>
+
+	* longlong.h (umul_ppmm from __umulsidi3): Protect with do ...
+	while (0).
+
+2016-06-02  Torbjörn Granlund  <tg@gmplib.org>
+	    Vincent Lefevre <vincent@vinc17.net>
+
+	* doc/gmp.texi: Various clarifications about variable conventions.
+
+2016-04-07  Marc Glisse  <marc.glisse@inria.fr>
+
+	* gmp-h.in (__GMP_NOTHROW): Prefer noexcept to throw().
+	(mpz_init, mpz_inits): Mark as __GMP_NOTHROW.
+	* mpz/init.c, mpz/inits.c: Likewise.
+	* gmpxx.h (mpz_class): Mark default and move constructors noexcept.
+	* tests/cxx/t-cxx11.cc: Check noexcept.
+
+2016-04-02  Torbjörn Granlund  <torbjorng@google.com>
+
+	* mpf/set_q.c: Rewrite, mainly to use mpn_div_q.
+
+2016-03-29  Torbjörn Granlund  <torbjorng@google.com>
+
+	* mpn/x86_64/fat/addmul_2.c: New file.
+
+2016-03-28  Torbjörn Granlund  <torbjorng@google.com>
+
+	* mpn/x86_64/addmul_2.asm: Move from here...
+	* mpn/x86_64/k8/addmul_2.asm: ...to here.
+
+2016-03-26  Torbjörn Granlund  <torbjorng@google.com>
+
+	* mpn/arm64/sqr_diag_addlsh1.asm: New file.
+
+2016-03-25  Torbjörn Granlund  <torbjorng@google.com>
+
+	* mpn/arm64/xgene1/aors_n.asm: New file.
+	* mpn/arm64/xgene1/aorsmul_1.asm: New file.
+	* mpn/arm64/xgene1/cnd_aors_n.asm: New file.
+	* mpn/arm64/xgene1/gmp-mparam.h: New file.
+	* mpn/arm64/xgene1/mul_1.asm: New file.
+
+	* config.guess: Prefix all arm CPUs with "arm" to accommodate our
+	matchers.
+	* configure.ac (arm): Match arm CPUs consistently.
+
+2016-03-21  Torbjörn Granlund  <torbjorng@google.com>
+
+	* configure.ac: Support many arm64 processors.
+
+2016-03-20  Marc Glisse  <marc.glisse@inria.fr>
+
+	* configure.ac (WANT_ASSEMBLY): Remove.
+	(NO_ASM): Remove from CFLAGS, add to AC_DEFINE.
+	* tests/misc.c: Test NO_ASM instead of WANT_ASSEMBLY.
+
+2016-03-20  Torbjörn Granlund  <torbjorng@google.com>
+
+	* config.guess (arm*): Handle big.LITTLE CPUs by extracting the
+	lexically largest id.
+	* config.guess (arm*): Add many aarch64 CPUs.
+	* config.guess (main): Corresponding changes.
+
+	* mpn/arm/v7a/cora5/gmp-mparam.h: New file.
+
+	* configure.ac (arm*): Support cortex-a5 better.
+
+2016-02-25  Pavel Kopyl  <p.kopyl@samsung.com>
+
+	* acinclude.m4 (GMP_ASM_UNDERSCORE): Tighten gurkmacka detection.
+
+2016-01-27  Niels Möller  <nisse@lysator.liu.se>
+
+	* errno.c (__gmp_exception): Use raise(SIGFPE) when available.
+
+2016-01-15  Torbjörn Granlund  <torbjorng@google.com>
+
+	* config.guess (s390): Don't assume /proc/cpuinfo exists.
+
+2016-01-13  Torbjörn Granlund  <torbjorng@google.com>
+
+	* config.guess: Reorder and generalise ppc code.
+
+2016-01-01 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* tests/cxx/clocale.c: Do not re-define localeconv for mingw.
+	* tests/misc/t-locale.c: Likewise (Thanks Alexander).
+
+	* primesieve.c: Heal a speed regression on small values.
+	* mpz/bin_uiui.c (mpz_bdiv_bin_uiui): 2 factors all at once.
+	  (mpz_goetgheluck_bin_uiui): Use STOP/CONT for loops on primesieve.
+	* mpz/oddfac_1.c: Likewise.
+	* mpz/primorial_ui.c (LOOP_ON_SIEVE_CONTINUE): Define prime locally.
+
+	* gen-fac.c: Use unsigned types for sizes.
+
+	* mpn/generic/invert.c: Use MPN_FILL macro.
+	* mpn/generic/invertappr.c: Likewise.
+	* mpn/generic/toom53_mul.c: Use _ip1 when available.
+
+2015-12-28 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpq/set_str.c: Use __GMP_FREE_FUNC_TYPE.
+	* tests/mpz/t-nextprime.c: Speedup using swap, and correct type.
+
+2015-12-26  Torbjörn Granlund  <torbjorng@google.com>
+
+	* tests/misc.c (tests_start): Assert library version.
+
+2015-12-19  Marc Glisse  <marc.glisse@inria.fr>
+
+	* gmp-impl.h (fft_table_nk): Use gmp_uint_least32_t.
+	* mpn/generic/trialdiv.c (gmp_primes_ptab): Likewise.
+
+2015-12-14  Torbjörn Granlund  <torbjorng@google.com>
+
+	* mpn/x86_64/fat/fat.c (gmp_workaround_skylake_cpuid_bug):
+	New function.
+	(__gmpn_cpuvec_init): Handle more BMI2 crippled CPUs.
+
+2015-12-13 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpf/clears.c, mpf/inits.c, mpq/clears.c, mpq/inits.c,
+	* mpz/clears.c, mpz/inits.c: Stop supporting empty list.
+	* tests/arm32call.asm: bx->ret to support thumb-less chips
+	  (thanks Martin Husemann).
+
+2015-12-13  Torbjörn Granlund  <torbjorng@google.com>
+
+	* config.sub: Fix spelling of kabylake.
+	* acinclude.m4: Likewise.
+	* mpn/x86_64/fat/fat.c: Likewise.
+
+2015-12-10 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* tests/misc/t-printf.c: Test a sequence of '%'.
+	* printf/doprnt.c: Avoid buffer overread with long long limbs.
+
+	* mpn/generic/toom_interpolate_7.c: Use the rsh1 functions,
+	  when available, also for negatives (clearing the carry).
+	* mpn/generic/toom_interpolate_12.c: Likewise.
+	* mpn/generic/toom_interpolate_16.c: Likewise.
+
+2015-12-06  Torbjörn Granlund  <torbjorng@google.com>
+
+	* configure.ac (arm*): Conditionally define NOTHUMB.
+	Simplify and generalise.
+	* mpn/arm/arm-defs.m4 (ret): New macro, conditional on NOTHUMB.
+	* mpn/arm/*.asm: Use ret.
+
+2015-12-03  Torbjörn Granlund  <torbjorng@google.com>
+
+	* config.guess: Work around skylake cpuid bug.
+	Fix spelling of kabylake.
+
+2015-12-01  Torbjörn Granlund  <torbjorng@google.com>
+
+	* mpn/x86_64/coreibwl/mul_basecase.asm: Add FUNC_EXITs.
+
+2015-11-21 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* gmp-impl.h (MPN_TOOM22_MUL_MINSIZE): Consider ToomX2 limits
+	  (thanks Paul).
+	* tests/mpn/t-toom22.c: Keep on testing small sizes.
+	* tests/mpz/t-primorial_ui.c: Test a single "large" number.
+
+	* tune/common.c (speed_mpz_primorial_ui): New function.
+	* tune/speed.h: Declare it.
+	* tune/speed.c (routine): Add mpz_primorial_ui.
+
+	* primesieve.c: Use two presieved patterns on 64-bits CPUs.
+
+2015-11-13 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpq/init.c: Remove conditional code for __CHECKER__.
+	* mpq/set.c: Shorten scope of local variables.
+	* mpq/set_den.c: Likewise.
+	* mpq/set_num.c: Likewise.
+	* mpq/set_z.c: Likewise.
+
+	* primesieve.c: Fill sieve with a presieved 70bits pattern.
+
+2015-11-12  Marc Glisse  <marc.glisse@inria.fr>
+
+	* gmpxx.h (__gmp_fibonacci_function): New class.
+	(fibonacci, mpz_class::fibonacci): New functions.
+	(__gmp_fac_function, __gmp_primorial_function): Add braces.
+	* tests/cxx/t-ops2z.cc: Test fibonacci.
+	* doc/gmp.texi (C++ Interface Integers): Document fibonacci.
+	Warn about factorial and primorial of negative numbers.
+
+2015-11-10  Marc Glisse  <marc.glisse@inria.fr>
+
+	* gmpxx.h (__gmp_primorial_function): Throw on negative operands.
+	* tests/cxx/t-ops2z.cc: Test it.
+
+2015-11-09 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpz: Experimental, lazy allocation.
+
+2015-11-09  Marc Glisse  <marc.glisse@inria.fr>
+
+	* tests/cxx/Makefile.am: Move EXTRA_DIST out of WANT_CXX.
+
+2015-11-08 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpz/urandomm.c: Use mpn_zero_p to shorten code.
+
+2015-11-08  Marc Glisse  <marc.glisse@inria.fr>
+
+	* gmpxx.h (__gmp_fac_function, __gmp_primorial_function): New classes.
+	(__GMPP_DECLARE_UNARY_STATIC_MEMFUN,
+	__GMPNN_DECLARE_UNARY_STATIC_MEMFUN,
+	__GMPNS_DECLARE_UNARY_STATIC_MEMFUN,
+	__GMPNU_DECLARE_UNARY_STATIC_MEMFUN,
+	__GMPND_DECLARE_UNARY_STATIC_MEMFUN,
+	__GMPN_DECLARE_UNARY_STATIC_MEMFUN,
+	__GMP_DECLARE_UNARY_STATIC_MEMFUN, __GMPP_DEFINE_UNARY_STATIC_MEMFUN,
+	__GMPNN_DEFINE_UNARY_STATIC_MEMFUN,
+	__GMPNS_DEFINE_UNARY_STATIC_MEMFUN,
+	__GMPNU_DEFINE_UNARY_STATIC_MEMFUN,
+	__GMPND_DEFINE_UNARY_STATIC_MEMFUN, __GMPN_DEFINE_UNARY_STATIC_MEMFUN,
+	__GMP_DEFINE_UNARY_STATIC_MEMFUN): New macros.
+	(factorial, mpz_class::factorial, primorial, mpz_class::primorial):
+	New functions.
+	* tests/cxx/t-ops2.cc: Test factorial and primorial.
+	* tests/cxx/Makefile.am: Move t-ops2 after
+	t-do-exceptions-work-at-all-with-this-compiler.
+	* doc/gmp.texi: Document factorial and primorial.
+	* NEWS: Likewise.
+
+	* tests/cxx/t-ops2.cc: Remove and split into ...
+	* tests/cxx/t-ops2z.cc, tests/cxx/t-ops2qf.cc, tests/cxx/t-ops2f.cc,
+	tests/cxx/t-ops2.h: New files.
+	* tests/cxx/Makefile.am: Update for the split.
+
+2015-11-07  Marc Glisse  <marc.glisse@inria.fr>
+
+	* gmpxx.h (__GMP_DEFINE_UNARY_FUNCTION_1,
+	__GMPP_DEFINE_BINARY_FUNCTION_1, __GMPNN_DEFINE_BINARY_FUNCTION_1,
+	__GMPNS_DEFINE_BINARY_FUNCTION_1, __GMPNU_DEFINE_BINARY_FUNCTION_1,
+	__GMPND_DEFINE_BINARY_FUNCTION_1, __GMPNLD_DEFINE_BINARY_FUNCTION_1,
+	__GMPN_DEFINE_BINARY_FUNCTION_1, __GMP_DEFINE_BINARY_FUNCTION_1):
+	New macros.
+	(operator~, trunc, floor, ceil, sqrt, operator%, operator&, operator|,
+	operator^, hypot, gcd, lcm): Use them.
+
+2015-11-06 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpz/and.c: Use MPZ_NEWALLOC.
+	* mpz/ior.c: Remove duplicated branches, add branch hints.
+	* mpz/xor.c: Likewise, and use NORMALIZE_NOT_ZERO.
+
+	* mpz/init.c: Remove conditional code for __CHECKER__.
+	* mpz/init2.c: Likewise.
+	* mpz/inits.c: Likewise.
+	* mpz/iset.c: Likewise.
+	* mpz/iset_str.c: Likewise.
+
+2015-11-04  Torbjörn Granlund  <torbjorng@google.com>
+
+	* mpz/xor.c: Use MPZ_REALLOC.
+	* mpz/ior.c: Likewise
+
+2015-11-03 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpz/xor.c: Use the return value of _mpz_realloc.
+	* mpz/ior.c: Likewise.
+	* mpn/generic/sec_div.c: Remove unused var.
+
+2015-11-01  Torbjörn Granlund  <torbjorng@google.com>
+
+	* tests/misc.c (seed_from_tod, seed_from_urandom): New functions.
+	(tests_rand_start): Use them.
+
+2015-11-01 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* Version 6.1.0 released.
+
+	* mpz/inits.c [__CHECKER__]: Init limb, not pointer.
+	* mpz/init.c [__CHECKER__]: Likewise (spotted by Vicente Benjumea).
+	* tests/mpf/t-pow_ui.c: Use another mpf for the size limit.
+
+2015-10-30  Torbjörn Granlund  <torbjorng@google.com>
+
+	* mpf/pow_ui.c: Add log(e) precision bits.
+
+	* doc/gmp.texi (Floating-point): Rewrite mpf introduction.
+
+2015-10-29 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* demos/factorize.c: mpz_div_2exp => mpz_tdiv_q_2exp.
+	* demos/perl/GMP.xs: Likewise.
+	* tests/mpf/t-pow_ui.c: Use reference value to check the size.
+
+	* doc/gmp.texi (Floating-point): Remove "infinite precision" claim.
+
+	* gmp-h.in: Update version.
+
+2015-10-28  Torbjörn Granlund  <torbjorng@google.com>
+
+	* tests/mpf/t-pow_ui.c: New file.
+	* tests/mpf/Makefile.am (check_PROGRAMS): Compile it.
+
+	* mpf/pow_ui.c: Rewrite for accuracy and performance.
+
+2015-10-26 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* configfsf.guess: Updated to version 2015-10-21, for a typo.
+
+	* tests/cxx/t-ops.cc (check_mpq): Compare also with mpz.
+	(check_mpf): Compare also with mpz and mpq.
+
+2015-10-25  Torbjörn Granlund  <torbjorng@google.com>
+
+	* configure.ac: Avoid passing ambiguous -march=skylake.
+
+2015-10-21 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* Version 6.1.0-rc1 published.
+
+	* gmp-h.in: Revert version for RC.
+
+2015-10-20  Torbjörn Granlund  <torbjorng@google.com>
+
+	* mpn/x86/pentium4/sse2/popcount.asm: Use LEAL.
+	* mpn/x86/k7/invert_limb.asm: Likewise.
+
+2015-10-18  Torbjörn Granlund  <torbjorng@google.com>
+
+	* mpn/arm64/gmp-mparam.h: New file.
+
+2015-10-18 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* Makefile.am (LIBGMP_LT_*, LIBGMPXX_LT_*): Bump version info.
+	* gmp-h.in: Bump version.
+
+2015-10-17 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* tests/mpf/t-cmp_si.c: Initialise a variable (only when error arise)
+	* mpn/generic/toom43_mul.c: Insert parentheses around & expressions.
+	* mpn/generic/toom52_mul.c: Likewise.
+	* tests/mpn/t-minvert.c: Remove an unused var.
+	* tests/mpz/t-cong_2exp.c: Likewise.
+
+2015-10-16  Hans Wennborg <hwennborg at google.com>
+
+	* mpn/generic/div_qr_2.c: Insert parentheses around & expressions.
+	* mpn/generic/toom44_mul.c: Likewise.
+	* mpn/generic/toom53_mul.c: Likewise.
+	* mpn/generic/toom62_mul.c: Likewise.
+	* tests/mpn/t-bdiv.c: Simplify conditional printing of whitespace.
+	* tests/mpn/t-div.c: Likewise.
+
+2015-10-15 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* configfsf.sub: Updated to version 2015-08-20, from gnulib.
+	* configfsf.guess: Updated to version 2015-09-14, from gnulib.
+
+2015-10-14  Torbjörn Granlund  <torbjorng@google.com>
+
+	* demos/pexpr.c (main): Clear out a variable.
+
+	* mpn/generic/sqrlo_basecase.c: Move things before addmul_1 to reduce
+	register pressure.
+
+	* .hgignore: Add 'compile' and 'test-driver'.
+
+	* mpn/generic/mu_bdiv_qr.c (mpn_mu_bdiv_qr_itch): Simplify, add ASSERT.
+	* mpn/generic/mu_bdiv_q.c (mpn_mu_bdiv_q_itch): Likewise.
+
+	* tune/tuneup.c (tune_mu_bdiv): Start at measured BDIV_DC_ thresholds.
+
+2015-10-13 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpf/clears.c, mpf/inits.c, mpq/clears.c, mpq/inits.c,
+	* mpz/clears.c, mpz/inits.c: Keep on supporting empty list.
+
+2015-10-13  Marc Glisse  <marc.glisse@inria.fr>
+
+	* gmpxx.h (__GMPP_DEFINE_BINARY_TYPE_FUNCTION): Allow mixed operations.
+	(__gmp_cmp_function, __gmp_binary_equal, __gmp_binary_less):
+	Handle mixed operations.
+	(__gmp_cmp_function): Move before __gmp_binary_equal.
+
+2015-10-13 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpf/pow_ui.c: Increased precision of partial results.
+
+2015-10-12  Torbjörn Granlund  <torbjorng@google.com>
+
+	* configure.ac: Reject AVX for NetBSD.
+
+2015-10-11  Torbjörn Granlund  <torbjorng@google.com>
+
+	* configure.ac (fat_path): Add skylake.
+
+2015-10-10 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* gen-fib.c: Correct the name of the program in error message.
+	* gen-fac.c: Likewise.
+
+	* mpf/get_str.c: Increase precision of base^e computation.
+
+2015-10-09  Torbjörn Granlund  <torbjorng@google.com>
+
+	* config.guess: Recognise cabylake and goldmont and more versions of
+	skylake and silvermont.
+	* acinclude.m4 (X86_64_PATTERN): Add cabylake and goldmont.
+	* config.sub: Corresponding changes.
+	* configure.ac: Corresponding changes.
+	* mpn/x86_64/fat/fat.c: Corresponding changes.
+
+2015-09-12  Torbjörn Granlund  <torbjorng@google.com>
+
+	* mpf/clear.c, mpf/clears.c, mpf/inits.c, mpq/clear.c, mpq/clears.c
+	* mpq/inits.c, mpz/clear.c, mpz/clears.c, mpz/inits.c:
+	Streamline, use macros.
+
+2015-09-27 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpz/cfdiv_r_2exp.c: Use mpn_neg and MPZ_NEWALLOC.
+	* mpz/cfdiv_q_2exp.c: Use MPZ_REALLOC return value.
+
+2015-09-12  Torbjörn Granlund  <torbjorng@google.com>
+
+	* tests/mpf/t-cmp_si.c (check_data): Set precision reflecting data.
+
+2015-09-11 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpf/cmp_z.c: New file implementing mpf_cmp_z.
+	* mpf/Makefile.am (libmpf_la_SOURCES): Add it.
+	* Makefile.am (MPF_OBJECTS): Add generate object to libs.
+	* gmp-h.in: Declare new function.
+	* tests/mpf/t-cmp_si.c: Test also the new function.
+	* doc/gmp.texi: Document it.
+
+2015-09-06  Torbjörn Granlund  <torbjorng@google.com>
+
+	* Wrap remaining limb allocations in __GMP_ALLOCATE_FUNC_LIMBS.
+
+	* mpn/x86/fat/fat.c (fake_cpuid_table): Add missing commas.
+	* mpn/x86_64/fat/fat.c: Likewise.
+
+	* mpn/x86/fat/fat.c (fake_cpuid_table): Improve struct type.
+	* mpn/x86/fat/fat.c: Likewise.
+
+2015-09-03 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* tests/mpq/t-cmp_z.c (sizes_test): New function, tests sizes.
+
+2015-09-03  Torbjörn Granlund  <torbjorng@google.com>
+
+	* acinclude.m4 (GMP_C_HIDDEN_ALIAS): New.
+	* configure.ac (GMP_C_HIDDEN_ALIAS): Invoke.
+
+2015-09-01 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpq/cmp.c (mpq_cmp_numden): Cast to avoid over/underflow.
+	* tests/mpn/t-toom22.c (MIN_AN): Use defined value.
+	* tests/mpz/t-fac_ui.c: Check big factorial modulo a larger prime.
+	* mpn/generic/bsqrtinv.c: Use sqrlo+mullo_n instead of powlo(,,3,,).
+	* mpq/div.c: Move a branch out of the normal flow.
+
+2015-08-31  Torbjörn Granlund  <torbjorng@google.com>
+
+	* mpn/x86/fat/fat.c (fake_cpuid_table): Update similarly to
+	corresponding x86_64 code.
+
+2015-08-31 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpq/cmp.c (mpq_cmp_z): New function to compare mpq with mpz,
+	asked by Vincent Delecroix for the SageMath project.
+	* gmp-h.in: Declare it.
+	* doc/gmp.texi: Document it.
+	* tests/mpq/t-cmp_z.c: New file to test mpq_cmp_z (from t-cmp.c).
+	* tests/mpq/Makefile.am (check_PROGRAMS): Add t-cmp_z.
+
+	* mpn/generic/powlo.c: Use mpn_sqrlo.
+
+2015-08-29  Torbjörn Granlund  <torbjorng@google.com>
+
+	* mpn/x86_64/fat/fat.c (fake_cpuid_table): Add CPU aliases.
+
+2015-08-25 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* configure.ac (AH_VERBATIM): Add HAVE_NATIVE_mpn_mullo_basecase.
+	* mpn/generic/sqrlo.c (mpn_sqrlo): Use mullo_basecase when faster.
+	* mpn/generic/sqrlo_basecase.c: More readable #defines.
+
+	* tune/tuneup.c (tune_sqrlo): New function to tune sqrlo thresholds.
+	(all): Call it, after multiplication and FFT.
+	* tune/Makefile.am (TUNE_MPN_SRCS_BASIC): Add sqrlo{,_basecase}.c .
+	* gmp-impl.h: Add all SQRLO_*_THRESHOLD* defs, for tuning and default.
+	* mpn/generic/sqrlo.c: Remove default threshold definitions.
+	* mpn/generic/sqrlo_basecase.c: Use SQRLO_DC_THRESHOLD_LIMIT.
+	* mpn/minithres/gmp-mparam.h: New SQRLO_*_THRESHOLDs.
+
+	* tune/tuneup.c (tune_mullo): Set MULLO_MUL_N_THRESHOLD to never
+	whenever the FFT threshold does not exist.
+
+	* mpf/cmp.c: Remove some branches.
+
+2015-08-25  Torbjörn Granlund  <torbjorng@google.com>
+
+	* mpn/x86_64/x86_64-defs.m4: Output computed numbers in base-10 instead
+	of base-16 to avoid bugs on Solaris, FreeBSD, and old NetBSD.
+
+2015-08-23  Torbjörn Granlund  <torbjorng@google.com>
+
+	* mpn/x86_64/fat/fat.c (fake_cpuid_table): Add more entries, handle
+	Broadwell separately.
+
+	* configure.ac (fat_path): Add coreibwl.
+
+2015-08-18 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/rootrem.c (logbased_root): New function.
+	(mpn_rootrem_internal): Use it to estimate highest 9 bits of the root.
+
+	* gmp-impl.h (MPQ_PTR_SWAP, MPQ_SRCPTR_SWAP): New macros.
+
+2015-08-17  Torbjörn Granlund  <torbjorng@google.com>
+
+	* acinclude.m4 (X86_64_PATTERN): Add skylake.
+	* config.guess: Corresponding changes.
+	* config.sub: Corresponding changes.
+	* configure.ac: Corresponding changes.
+	* mpn/x86_64/skylake/gmp-mparam.h: New file.
+
+2015-08-15  Torbjörn Granlund  <torbjorng@google.com>
+
+	* mpn/generic/mullo_basecase.c: Provide alternative code, make default.
+
+2015-08-04 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* tests/refmpn.c (refmpn_sqrlo): New function.
+	* tests/tests.h: Define it.
+
+	* mpn/generic/sqrlo.c: New file, new function.
+	* mpn/generic/sqrlo_basecase.c: New file, new function.
+	* gmp-impl.h (mpn_sqrlo, mpn_sqrlo_basecase): Declare them.
+	* configure.ac (gmp_mpn_functions): Add new files.
+
+	* tests/mpn/t-sqrlo.c: New file, new test.
+	* tests/mpn/Makefile.am (check_PROGRAMS): Add new test.
+	* tests/devel/try.c: Support mpn_sqrlo and mpn_sqrlo_basecase.
+
+	* tune/common.c (speed_mpn_sqrlo{,_basecase}): New functions.
+	* tune/speed.c: Support new functions.
+	* tune/speed.h (SPEED_ROUTINE_MPN_MULLO_BASECASE): Update.
+	(SPEED_ROUTINE_MPN_SQRLO): New macro.
+
+	* mpn/generic/rootrem.c: Avoid divisions if not needed.
+
+	* tests/mpn/t-broot.c: Test also k=1.
+	* mpz/aorsmul_i.c: Move branches out of main line.
+
+2015-07-28 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/sqrtrem.c (mpn_dc_sqrt): Support odd sizes.
+
+2015-07-16  Torbjörn Granlund  <torbjorng@google.com>
+
+	* tune/speed.c: Remove now redundant MPN_FILL.
+
+	* configure.ac (hppa-hpux): Never use O3 optimisation.
+
+2015-07-09  Torbjörn Granlund  <torbjorng@google.com>
+
+	* mpn/ia64/add_n_sub_n.asm: Make it work for HP-UX.
+	* mpn/ia64/addmul_2.asm: Likewise.
+	* mpn/ia64/aors_n.asm: Likewise.
+	* mpn/ia64/aorsorrlshC_n.asm: Likewise.
+	* mpn/ia64/cnd_aors_n.asm: Likewise.
+	* mpn/ia64/gcd_1.asm: Likewise.
+	* mpn/ia64/lshiftc.asm: Likewise.
+	* mpn/ia64/mod_34lsub1.asm: Likewise.
+	* mpn/ia64/mul_2.asm: Likewise.
+	* mpn/ia64/sec_tabselect.asm: Likewise.
+	* mpn/ia64/sqr_diag_addlsh1.asm: Likewise.
+
+2015-07-01 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* gmp-impl.h (MPN_FILL): New macro, generalise MPN_ZERO.
+
+	* mpn/generic/sqrtrem.c (mpn_dc_sqrt): New function not computing remainder.
+	(mpn_dc_sqrtrem): Use tdiv_q instead of divrem, use given scratch space.
+	(mpn_sqrtrem): Use mpn_dc_sqrt for both even and odd sizes.
+
+2015-06-24  Torbjörn Granlund  <torbjorng@google.com>
+
+	* mpn/x86_64/fastsse/com.asm: Disallow zero size operands.
+
+	* mpn/x86_64/fastsse/copyi.asm: Suppress looping in basecase code.
+
+2015-06-23 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/sqrtrem.c (mpn_sqrtrem2): Simplify branches.
+	(mpn_dc_sqrtrem): Don't compute remainder if not needed.
+
+2015-06-23  Torbjörn Granlund  <torbjorng@google.com>
+
+	* gmp-impl.h: Remove K&R stringize support.
+	* tests/devel/try.c: Likewise.
+	* tests/t-constants.c: Likewise.
+	* tests/mpf/t-fits.c: Likewise.
+	* tests/mpz/t-fits.c: Likewise.
+
+	* configure.ac (AC_C_STRINGIZE): Remove.
+
+2015-06-15 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* tests/devel/try.c: Support mpn_sqrt (sqrtrem with remainder = NULL).
+	* mpn/generic/sqrtrem.c: Reorder branches for single limb operands.
+
+2015-06-15  Torbjörn Granlund  <torbjorng@google.com>
+
+	* config.guess: Rewrite code for AVX handling to deal with broken cpuid
+	states.
+
+2015-06-11  Torbjörn Granlund  <torbjorng@google.com>
+
+	* mpn/x86/k7/gcd_1.asm: Align stack for calls.
+	* mpn/x86/p6/gcd_1.asm: Amend last change: align for PIC and non-PIC.
+
+2015-06-10 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/sqrtrem.c: Use sqrtrem1 for single limb operands.
+
+	* tests/mpz/t-root.c: Check also mpz_root return value.
+	* mpn/generic/rootrem.c: Shorten first and last loop.
+
+	* mpn/generic/toom2_sqr.c: Add some ASSERTs.
+	* mpn/generic/toom22_mul.c: Likewise.
+	* tests/mpn/t-toom22.c: stop testing some unsafe (unused) corner cases.
+
+2015-06-08  Torbjörn Granlund  <torbjorng@google.com>
+
+	* mpn/x86/p6/gcd_1.asm: Align stack for calls.
+
+2015-06-06  Torbjörn Granlund  <torbjorng@google.com>
+
+	* config.sub: Recognise any arm*neon CPU.
+	* configure.ac (powerpc): Add p8 directory for power8 and later.
+	* mpn/powerpc64/mode64/p8/invert_limb.asm: New file.
+
+2015-06-01  Torbjörn Granlund  <torbjorng@google.com>
+
+	* tune/speed.c (routine): Measure "mpn_sqrt" and "mpn_root", which are
+	really the corresponding "rem" functions with NULL remainder argument.
+
+	* tune/speed.h (SPEED_ROUTINE_MPN_SQRTROOT_CALL): New.
+	(SPEED_ROUTINE_MPN_SQRTREM, SPEED_ROUTINE_MPN_ROOTREM):	Remove.
+
+	* tune/common.c (speed_mpn_sqrt, speed_mpn_root): New functions.
+	(speed_mpn_sqrtrem): Use SPEED_ROUTINE_MPN_SQRTROOT_CALL
+	(speed_mpn_rootrem): Likewise.
+
+2015-05-30 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpf/cmp_ui.c: Use macros, remove branches, correct nails.
+	* mpf/cmp_si.c: Likewise.
+	* mpf/int_p.c: Use a simpler loop to ignore zero limbs.
+
+	* mpf/sqrt_ui.c: Special case for sqrt(1).
+	* tests/mpf/t-sqrt_ui.c: Test special cases.
+
+	* gmp-h.in: Declare (and inline) mpn_zero_p.
+	* gmp-impl.h: Remove mpn_zero_p.
+	* mpn/generic/zero_p: New file to include the function in the library.
+	* configure.ac (gmp_mpn_functions): Add it.
+	* doc/gmp.texi: Document it.
+
+	* mpz/combit.c: Call mpn_zero_p only if size is not zero.
+	* mpz/scan1.c: Likewise.
+	* tests/mpn/t-brootinv.c: Likewise.
+	* tests/mpn/t-div.c: Likewise.
+	* tests/mpn/t-minvert.c: Likewise.
+
+2015-05-28  Niels Möller  <nisse@lysator.liu.se>
+
+	* doc/gmp.texi (Low-level Functions): Document mpn_divexact_1 and
+	mpn_cnd_swap (the latter was forgotten for the 2015-02-08 change).
+
+2015-05-28  Linus Nordberg  <linus@nordberg.se>
+
+	* configure.ac: Remove double quotes in help strings, make some
+	clarifications.
+
+2015-05-24 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpq/div.c: Reduce memory use.
+	* tests/mpq/reuse.c: Test also mpq_FUNCTION (x,x,x).
+	* mpz/swap.c: Use _SWAP macros.
+
+2015-05-18  Torbjörn Granlund  <torbjorng@google.com>
+
+	* configure.ac (arm): Let compiler decide about arm vs thumb encoding.
+
+2015-05-18 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* gmp-h.in (mpn_neg): Niels' code using mpn_neg.
+	* gmp-h.in (mpn_com): Unconditionally declare prototype.
+
+2015-05-17  Torbjörn Granlund  <torbjorng@google.com>
+
+	* mpn/arm/v6/sqr_basecase.asm: Rewrite for speed.
+
+2015-05-16  Torbjörn Granlund  <torbjorng@google.com>
+
+	* mpn/arm/v6/addmul_2.asm: Rewrite for speed and size.
+
+2015-05-15  Torbjörn Granlund  <torbjorng@google.com>
+
+	* mpn/arm/v7a/cora7/gmp-mparam.h: New file.
+	* mpn/arm/v7a/cora8/gmp-mparam.h: New file.
+	* configure.ac (arm): Point to new directories.
+
+2015-05-15 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/invertappr.c: Reduce memory usage.
+	* gmp-impl.h (mpn_invertappr_itch): Update accordingly.
+	* tune/tuneup.c (tune_invertappr, tune_invert): Update min_size.
+
+	* mpn/generic/mu_div_qr.c: Pass scratch memory to mpn_invertappr.
+	* mpn/generic/mu_divappr_q.c: Likewise.
+
+2015-05-12  Felix Janda  <felix.janda@posteo.de>
+
+	* mpn/powerpc32/elf.m4 (LEA): Adopt to new ABI.
+
+2015-05-09 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/invertappr.c: Reduce memory usage.
+	* gmp-impl.h (mpn_invertappr_itch): Update accordingly.
+
+2015-05-01  Torbjörn Granlund  <torbjorng@google.com>
+
+	* tune/tuneup.c (all): Make GCD tuning last since it is not robust.
+
+2015-04-27  Torbjörn Granlund  <torbjorng@google.com>
+
+	* mpn/x86_64/coreibwl/gmp-mparam.h: New file.
+
+2015-04-26  Torbjörn Granlund  <torbjorng@google.com>
+
+	* mpn/x86_64/coreibwl/mul_basecase.asm: New file.
+	* mpn/x86_64/coreibwl/sqr_basecase.asm: New file.
+
+2015-04-26 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* tune/common.c (speed_mpn_neg, speed_mpz_2fac_ui): New functions.
+	(speed_mpn_add_1, speed_mpn_add_1_inplace): New functions.
+	(speed_mpn_sub_1, speed_mpn_sub_1_inplace): New functions.
+	* tune/speed.h: Declare them all.
+	* tune/speed.c (routine): Added mpn_neg, mpn_add_1, mpn_sub_1,
+	mpn_add_1_inplace, mpn_sub_1_inplace, and mpz_2fac_ui.
+
+2015-04-25 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/invert.c: Split add in the correction test.
+	* mpn/generic/invertappr.c: Cleanup of loops and branches.
+
+	* mpn/generic/hgcd_reduce.c: Use TMP_ALLOC_LIMBS_3.
+	* mpn/generic/powm.c: Use TMP_ALLOC_LIMBS_2.
+	* mpn/generic/rootrem.c: Likewise.
+	* mpn/generic/remove.c: Remove redundant #ifdef.
+	* mpn/generic/perfpow.c: Likewise.
+
+2015-04-21  Torbjörn Granlund  <torbjorng@google.com>
+
+	* printf/sprintffuns.c (gmp_sprintf_final): Remove extra parameters.
+
+	* mpn/arm/v6/popham.asm: Add MULFUNC_PROLOGUE.
+	* mpn/powerpc64/mode64/rsh1aors_n.asm: Likewise.
+	* mpn/powerpc64/mode64/p6/aorsmul_1.asm: Likewise.
+
+2015-04-19  Torbjörn Granlund  <torbjorng@google.com>
+
+	* mpn/x86_64/x86_64-defs.m4 (oplist): Fix typo.
+	(mulx): Simplify.
+	(adcx, adox): New defines, using helper function adx.
+	* mpn/x86_64/coreibwl/mul_1.asm: New file.
+	* mpn/x86_64/coreibwl/addmul_1.asm: New file.
+	* configure.ac (x86_64): Put coreibwl in appropriate code path.
+
+	* configure.ac (x86_64): Pass more exact Intel CPU options.
+
+2015-04-13  Torbjörn Granlund  <torbjorng@google.com>
+
+	* longlong.h (arm): Rewrite.  Support thumb2; use gcc builtins for
+	count_leading_zeros, use accurate code selection critera.
+
+2015-04-13  Marc Glisse  <marc.glisse@inria.fr>
+
+	* configure.ac (x86_64): Extend noavx to ABI=64.
+
+2015-04-10  Torbjörn Granlund  <torbjorng@google.com>
+
+	* mpn/alpha/ev6/mod_1_4.asm: Use LDGP.
+
+2015-04-01  Torbjörn Granlund  <torbjorng@google.com>
+
+	* configure.ac (sparc): Don't use use -xO4, it miscompiles by design.
+
+2015-03-24  Torbjörn Granlund  <torbjorng@google.com>
+
+	* mpn/generic/mul_fft.c (mpn_fft_best_k): Don't make pointers `static'
+	just because they point to static (i.e., file-local) data.
+
+2015-03-15  Torbjörn Granlund  <torbjorng@google.com>
+
+	* acinclude.m4 (X86_64_PATTERN): Add CPU code names.
+
+	* config.guess: Add more CPUs, use CPU code names.
+	* config.sub: Corresponding changes.
+	* configure.ac: Corresponding changes.
+
+2015-02-21  Niels Möller  <nisse@lysator.liu.se>
+
+	* gmp-h.in (mpn_divexact_1): New public declaration.
+	* gmp-impl.h: Moved from here.
+
+2015-02-08  Niels Möller  <nisse@lysator.liu.se>
+
+	* doc/gmp.texi (Low-level Functions): Document mpn_cnd_swap.
+
+	* mpn/generic/cnd_swap.c (mpn_cnd_swap): New file, moved function
+	here. Also changed cnd argument type from int to mp_limb_t.
+	* mpn/generic/sec_invert.c (mpn_cnd_swap): Old location.
+	* configure.ac: Added cnd_swap.
+	* gmp-h.in (mpn_cnd_swap): Added prototype.
+
+2015-01-19  Torbjörn Granlund  <torbjorng@google.com>
+
+	* configure.ac (arm): Provide architecture specific configs in addition
+	to implementation specific configs.
+
+	* config.guess (arm): Use configfsf.guess's guess as default before
+	conditionally appending "neon".
+
+2015-01-08  Torbjörn Granlund  <torbjorng@google.com>
+
+	* config.guess: Match POWER8 for AIX.
+
+	* longlong.h: Add many casts inside assembly input operands, this
+	insures proper zero extension.
+
+2014-12-27  Marc Glisse  <marc.glisse@inria.fr>
+
+	* gmpxx.h (__gmp_unary_expr): Use __gmp_resolve_ref.
+	(__gmp_expr): New specialization for unary expressions with
+	a builtin argument.
+
+2014-12-26  Marc Glisse  <marc.glisse@inria.fr>
+
+	* gmp-impl.h (tmp_debug_entry_t): Change block to type void*.
+
+2014-12-22  Torbjörn Granlund  <torbjorng@google.com>
+
+	* longlong.h (mips64, mips32): Work around one clang bug.
+
+2014-12-18  Torbjörn Granlund  <torbjorng@google.com>
+
+	* longlong.h (umul_ppmm): Use input temps in more places.
+
+2014-12-10  Marc Glisse  <marc.glisse@inria.fr>
+
+	* tests/cxx/clocale.c (localeconv, nl_langinfo): Match glibc's
+	prototype in C++.
+
+2014-12-09  Torbjörn Granlund  <torbjorng@google.com>
+
+	* configure.ac (powerpc): Remove hardwired -mpowerpc, causes clang
+	problems.  Optionally pass -m32.
+
+2014-12-08  Marc Glisse  <marc.glisse@inria.fr>
+
+	* config.guess (ultrasparc*-*-*): Update for T4 and T5.
+	* config.sub (ultrasparc*-*-*): Update for T5.
+	* configure.ac (ultrasparc*-*-*): Update for T5.
+
+	* longlong.h (sparc64): Define COUNT_LEADING_ZEROS_NEED_CLZ_TAB
+	with VIS3.
+
+	* tests/misc/t-locale.c (localeconv, nl_langinfo): Match glibc's
+	prototype in C++.
+	* tests/mpf/t-get_si.c (check_limbdata): Avoid narrowing conversion
+	from -1 to unsigned inside {}.
+
+2014-12-02  Torbjörn Granlund  <torbjorng@google.com>
+
+	* config.guess (arm*-*-*): Redirect stderr.
+
+2014-11-26  Torbjörn Granlund  <torbjorng@google.com>
+
+	* configure.ac (arm*-*-*): Optionally pass redundant fpu mode options
+	in order to placate clang.
+
+	* mpn/arm/neon/lshiftc.asm: Avoid insn form missing from clang.
+
+2014-11-24  Torbjörn Granlund  <torbjorng@google.com>
+
+	* configure.ac (mips*-*-*): Provide ABI synonyms (for clang pretending
+	to be gcc).
+
+2014-11-18  Torbjörn Granlund  <torbjorng@google.com>
+
+	From Hannes Mehnert:
+	* config.guess (arm*-*-*): Base guesses on first matching /proc/cpuinfo
+	line.
+
+2014-11-17  Torbjörn Granlund  <torbjorng@google.com>
+
+	* longlong.h (__longlong_h_C): New macro.
+	(mpn_umul_ppmm, etc): Use it for C++ support.
+
+2014-11-15  Torbjörn Granlund  <torbjorng@google.com>
+
+	* tests/mpz/reuse.c: Make function vectors 'static'.
+
+	* tests/mpn/logic.c (check_one): Make string variable 'const'.
+
+	* tests/mpz/t-perfpow.c (tests): Make 'static'.
+
+	* tune/tuneup.c (fftmes): Remove an unused variable.
+
+2014-11-15  Marc Glisse  <marc.glisse@inria.fr>
+
+	* tests/amd64check.c (calling_conventions_fenv): Mark as extern "C".
+	* tests/x86check.c (calling_conventions_fenv): Likewise.
+
+2014-11-13  Hans Wennborg  <hwennborg@google.com>
+
+	* mpn/generic/toom_interpolate_8pts.c: Fix operator precedence in
+	ASSERT.
+
+2014-11-13  Torbjörn Granlund  <torbjorng@google.com>
+
+	* tune/speed.h: Add casts for C++ compatibility.
+	(speed_cyclecounter): Mark as extern "C".
+	(mpn_mod_1_1p_1, mpn_mod_1_1p_2): Correct prototype.
+
+	* tune/tune-gcd-p.c: Add casts for C++ compatibility.
+
+	* tune/tuneup.c: Add casts for C++ compatibility.
+	(mpn_divrem_1_tune, mpn_mod_1_tune): Mark as extern "C".
+	(INSERT_FFTTAB): Produce sentinels differently to silence compiler.
+
+2014-11-12  Torbjörn Granlund  <torbjorng@google.com>
+
+	* gen-psqr.c: Add casts for C++ compatibility.
+
+	* tests/misc/t-scanf.c: Include config.h early for HAVE_xxx.
+
+2014-11-08  Torbjörn Granlund  <torbjorng@google.com>
+
+	* mpn/x86/x86-defs.m4 (LEA, LEAL): Make sure to put eip stub code in
+	text segment.
+	* mpn/x86/darwin.m4: Likewise.
+
+	* tune/speed.h (i386 speed_cyclecounter): Remove inline asm code, rely
+	on external version.
+
+2014-11-06  Torbjörn Granlund  <torbjorng@google.com>
+
+	* config.guess: Ignore appended letters such E in POWER8E.
+	* configure.ac: Supply cflags for power8, power9.
+
+2014-11-03  Torbjörn Granlund  <torbjorng@google.com>
+
+	* mpn/powerpc32/addmul_1.asm: Avoid negative stack pointer references.
+	* mpn/powerpc32/lshift.asm: Likewise.
+	* mpn/powerpc32/lshiftc.asm: Likewise.
+	* mpn/powerpc32/p3-p7/aors_n.asm: Likewise.
+	* mpn/powerpc32/rshift.asm: Likewise.
+	* mpn/powerpc32/sec_tabselect.asm: Likewise.
+	* mpn/powerpc32/submul_1.asm: Likewise.
+	* mpn/powerpc32/vmx/mod_34lsub1.asm: Likewise.
+
+2014-10-13  Torbjörn Granlund  <torbjorng@google.com>
+
+	* acinclude.m4 (freebsd hacked gcc): Test for crash-prone FreeBSD gcc.
+
+2014-10-03  Peter Breitenlohner <peb@mppmu.mpg.de>
+
+	* mpn/generic/sec_tabselect.c: Adjust type to silence compiler.
+
+2014-10-01  Torbjörn Granlund  <torbjorng@google.com>
+
+	* All Makefile.am: INCLUDES => AM_CPPFLAGS.
+
+	* configure.ac (arm64): Set gcc_cflags_maybe to enable Neon (for clang
+	pretending to be gcc).
+
+2014-09-24  Marc Glisse  <marc.glisse@inria.fr>
+
+	* longlong.h (arm64 count_trailing_zeros, count_leading_zeros): Use
+	gcc's builtins.
+	(arm64 umul_ppmm): Use macro arguments only once.
+
+2014-09-22  Marc Glisse  <marc.glisse@inria.fr>
+
+	* mpn/arm64/lshift.asm: Avoid negative immediates.
+	* mpn/arm64/rshift.asm: Likewise.
+
+2014-09-13  Marc Glisse  <marc.glisse@inria.fr>
+
+	* mpn/generic/div_qr_1n_pi1.c: Honor NO_ASM.
+	* mpn/generic/div_qr_1n_pi2.c: Likewise.
+	* mpn/generic/div_qr_1u_pi2.c: Likewise.
+	* mpn/generic/div_qr_2.c: Likewise.
+	* mpn/generic/mod_1_1.c: Likewise.
+	* mpn/generic/redc_2.c: Likewise.
+
+2014-08-31  Torbjörn Granlund  <tege@gmplib.org>
+
+	* mpn/arm64/lshift.asm: New file.
+	* mpn/arm64/rshift.asm: New file.
+
+2014-09-01 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* gmp-impl.h (TMP_ALLOC_LIMBS_3): New macro to allocate 3 blocks.
+	(mpn_remove): Update declaration with mp_srcptr arguments.
+	* mpn/generic/remove.c: Use TMP_ALLOC_LIMBS_3. mp_srcptr for args.
+
+	* mpn/generic/perfpow.c (pow_equals): TMP_DECL only where needed.
+	(perfpow): Use TMP_ALLOC_LIMBS_3.
+	(mpn_perfect_power_p): Skip useless allocations. Use mpn_remove.
+	* tests/mpz/t-perfpow.c (check_random): Check more perfect powers.
+
+	* mpn/generic/divis.c: Use TMP_ALLOC_LIMBS_2. Share a count.
+
+2014-08-30  Torbjörn Granlund  <tege@gmplib.org>
+
+	* mpn/arm64/mod_34lsub1.asm: New file.
+
+2014-08-23  Torbjörn Granlund  <tege@gmplib.org>
+
+	* mpn/arm64/bdiv_dbm1c.asm: New file.
+
+	* mpn/arm64/com.asm: New file.
+
+	* mpn/arm64/sec_tabselect.asm: New file.
+
+	* mpn/arm64/popcount.asm: New file.
+	* mpn/arm64/hamdist.asm: New file.
+
+	* configure.ac: Put generic arm/neon earlier in path.
+
+2014-08-14 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpq/canonicalize.c: Earlier check for negative denominator.
+	* mpq/set_d.c: Stricter allocation.
+
+2014-08-03  Torbjörn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/bobcat/mul_1.asm: Fix typo in offset affecting DOS64.
+
+2014-07-28 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/fib2_ui.c: remove #if HAVE_NATIVE_mpn_rsblsh_n.
+	* mpz/fib2_ui.c: Use tabulated values, when available.
+	* mpz/fib_ui.c: #if HAVE_NATIVE_mpn_addlsh1_n, use it.
+
+	* mpq/cmp_ui.c: Remove a branch.
+	* mpq/cmp_si.c: Likewise.
+
+	* mpn/generic/toom_interpolate_7pts.c: Replace an in-place add
+	with add_n + INCR_U.
+
+	* tests/mpf/t-fits.c: use ui_sub instead of sub_ui+neg.
+
+2014-07-27  Torbjörn Granlund  <tege@gmplib.org>
+
+	* mpn/x86/k7/gcd_1.asm: Use LEAL.
+
+	* mpn/x86/x86-defs.m4 (LEAL): New.
+	(LEA): Append to `load_eip' instead of ASM_END, like darwin.m4.
+	* mpn/x86/darwin.m4 (LEAL): New.
+
+2014-07-26  Torbjörn Granlund  <tege@gmplib.org>
+
+	* mpn/x86/pentium/mode1o.asm: Add Darwin PIC code.
+	* mpn/x86/pentium/bdiv_q_1.asm: Likewise.
+	* mpn/x86/pentium/dive_1.asm: Likewise.
+	* mpn/x86/pentium/popcount.asm: Likewise.
+	* mpn/x86/pentium/hamdist.asm: Likewise.
+	* mpn/x86/k6/gcd_1.asm: Likewise.
+
+	* mpn/x86: Append ASM_END to many files.
+	* tests/x86call.asm: Append ASM_END.
+
+	* mpn/x86/fat/fat_entry.asm (FAT_ENTRY, FAT_INIT):
+	Support Darwin.
+
+	* mpn/x86/darwin.m4 (ASM_END): New, body from EPILOGUE_cpu.
+	(EPILOGUE_cpu): Remove.
+
+	* mpn/x86/x86-defs.m4 (LEA): Put `mov_eip_' thunks in ASM_END instead
+	of EPILOGUE_cpu.
+
+2014-07-05  Niels Möller  <nisse@lysator.liu.se>
+
+	* doc/gmp.texi (Low-level Functions): Document that scratch need
+	for mpn_sec_add_1 and mpn_sec_sub_1 are at most n limbs.
+	(Low-level Functions): Document allowed overlap for mpn_addmul_1
+	and mpn_submul_1.
+
+2014-07-02  Torbjörn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/x86_64-defs.m4: Fix quoting.
+
+	* mpn/x86_64/atom/redc_1.asm: Enforce proper stack allocation.
+	* mpn/x86_64/bobcat/redc_1.asm: Likewise.
+	* mpn/x86_64/core2/divrem_1.asm: Likewise.
+	* mpn/x86_64/core2/gcd_1.asm: Likewise.
+	* mpn/x86_64/core2/redc_1.asm: Likewise.
+	* mpn/x86_64/coreihwl/redc_1.asm: Likewise.
+	* mpn/x86_64/coreinhm/redc_1.asm: Likewise.
+	* mpn/x86_64/coreisbr/redc_1.asm: Likewise.
+	* mpn/x86_64/divrem_1.asm: Likewise.
+	* mpn/x86_64/divrem_2.asm: Likewise.
+	* mpn/x86_64/gcd_1.asm: Likewise.
+	* mpn/x86_64/mod_1_1.asm: Likewise.
+	* mpn/x86_64/mod_1_2.asm: Likewise.
+	* mpn/x86_64/mod_1_4.asm: Likewise.
+
+2014-06-30  Torbjörn Granlund  <tege@gmplib.org>
+
+	* config.sub: Generalise x86 patterns.
+
+2014-06-17  Marc Glisse  <marc.glisse@inria.fr>
+
+	* gmpxx.h (__gmp_gcd_function, __gmp_lcm_function): New classes.
+	(gcd, lcm): New functions.
+	* doc/gmp.texi (C++ Interface Integers): Document them.
+	* tests/cxx/t-ops2.cc (checkz): Test them.
+
+2014-06-16  Torbjörn Granlund  <tege@gmplib.org>
+
+	* mpf/mul.c: Postpone TMP_MARK.
+
+	* mpn/generic/perfpow.c (perfpow): Combine TMP_ALLOCs.
+
+2014-06-15  Torbjörn Granlund  <tege@gmplib.org>
+
+	* tests/refmpn.c (refmpn_mul): Rewrite to avoid O(n) recursion depth.
+
+2014-06-09  Torbjörn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/mullo_n.c: Remove default THRESHOLDs.
+	* gmp-impl.h: Put MULLO THRESHOLDs here.  Improve various THRESHOLD
+	defaults.
+
+2014-06-08  Torbjörn Granlund  <tege@gmplib.org>
+
+	* gmp-impl.h (TMP_ALLOC): Decrease limit to about half.
+
+	* mpn/generic/toom53_mul.c: Replace many TMP_SALLOC invocations
+	by a single TMP_ALLOC.
+	* mpn/generic/toom42_mul.c: Likewise.
+
+	* mpn/generic/sec_sqr.c: Don't unconditionally call mpn_sqr_basecase
+	since it fails for non-cryptographic sizes for some obsolete CPUs.
+
+	* mpn/generic/sec_powm.c: Remove own squaring code, instead use
+	mpn_mul_basecase.
+
+	* tests/mpn/logic.c (main): Don't use TMP_SALLOC_LIMBS.
+
+	* mpn/generic/dcpi1_div_q.c: Avoid TMP_SALLOC_LIMBS.
+	* mpn/generic/dcpi1_div_qr.c: Likewise.
+
+2014-06-08 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/mul.c: Tighter allocation in Toom{2,3}X branches.
+
+2014-06-06  Torbjörn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/mul.c: Swap some TMP_SALLOC_LIMBS for TMP_ALLOC_LIMBS
+	and some TMP_ALLOC_LIMBS for TMP_SALLOC_LIMBS.
+
+2014-05-31 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpf/ui_sub.c: Remove buggy code, use a wrapper to mpf_sub.
+	* tests/mpf/t-sub.c: More corner cases and strict checking.
+	* mpf/sub.c: Use more mpn_ primitives and macros.
+
+	* tests/mpf/t-int_p.c: Test numbers with both integer and
+	fractionary parts.
+
+	* mpf/int_p.c: Delay zero branch and use mpn_zero_p.
+	* mpf/fits_s.h: No special case for SIZ == 0.
+	* mpf/fits_u.h: Likewise.
+
+2014-05-29  Marc Glisse  <marc.glisse@inria.fr>
+
+	* gmp-h.in: Include <limits.h>.
+	(__GMP_UINT_MAX, __GMP_ULONG_MAX, __GMP_USHRT_MAX): Remove.
+	* gmp-impl.h (ULONG_MAX, UINT_MAX, USHRT_MAX, LONG_MAX, INT_MAX,
+	SHRT_MAX): Remove unnecessary redefinition.
+	* tests/t-gmpmax.c: Remove file.
+	* tests/Makefile.am: Remove t-gmpmax.
+
+2014-05-22 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* tests/mpf/t-sub.c (check_data): Test also ui_sub and sub_ui.
+
+2014-05-20 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* gen-fac.c: +1 in the init2 argument before setbit.
+	* gen-fib.c: Likewise. (Thanks Niels)
+	* rand/randmts.c: Likewise.
+
+	* mpn/generic/invert.c: Remove unused TMP_MARK.
+	* mpn/generic/invertappr.c: Avoid a branch.
+	* mpz/millerrabin.c (millerrabin): Consider the rare case n is a power.
+
+2014-05-15 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* gen-fib.c: Use mpz_setbit.
+	* gen-psqr.c: Skip even numbers when looking for primes.
+
+	* mpn/generic/invert.c: Avoid a branch.
+	* mpn/generic/toom2_sqr.c: Avoid a few branches in the odd case.
+	* mpn/generic/toom22_mul.c: Likewise.
+
+2014-05-08  Marc Glisse  <marc.glisse@inria.fr>
+
+	* gmpxx.h (std::common_type): Remove partial specialization for two
+	identical expressions. New partial specialization for a single type.
+	* tests/cxx/t-cxx11.cc: Test it.
+
+2014-04-14  Niels Möller  <nisse@lysator.liu.se>
+
+	* doc/gmp.texi (mpz_invert): Clarify behavior in the zero ring.
+
+2014-04-04  Marc Glisse  <marc.glisse@inria.fr>
+
+	* longlong.h (i386): Add comment about "cc" clobber.
+
+2014-04-04  Torbjorn Granlund  <tege@gmplib.org>
+
+	* acinclude.m4 (X86_64_PATTERN): Generalise patterns to allow "noavx"
+	suffix.
+
+	* mpn/generic/div_qr_1n_pi1.c: Conditionalise ARM asm on !__thumb__.
+
+2014-04-03  Marc Glisse  <marc.glisse@inria.fr>
+
+	* mpn/arm64/mul_1.asm, mpn/arm64/gcd_1.asm: Use official b.cond syntax.
+	* mpn/arm64/invert_limb.asm, mpn/arm64/aorsmul_1.asm: Prefix
+	immediates with #.
+
+2014-04-03  Torbjorn Granlund  <tege@gmplib.org>
+
+	* config.guess: Append "noavx" for CPUs which have AVX but where the
+	kernel does not support it.
+	* configure.ac: Accept "noavx" cpu name suffixes.  Conditionally pass
+	-mno-avx.
+
+2014-04-02  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/k8/redc_1.asm: Workaround for Darwin assembler quirk.
+
+2014-03-28  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/mod_1_1.c: Conditionalise ARM asm on !__thumb__.
+
+2014-03-31  Marc Glisse  <marc.glisse@inria.fr>
+
+	* mpn/arm/dive_1.asm, mpn/arm/invert_limb.asm: Use RODATA.
+	* acinclude.m4 ([long long reliability tests]): Declare functions.
+	(GMP_PROG_CC_FOR_BUILD_WORKS, GMP_PROG_EXEEXT_FOR_BUILD,
+	GMP_C_FOR_BUILD_ANSI, GMP_CHECK_LIBM_FOR_BUILD): Replace exit(0) with
+	return 0, no declaration needed.
+	(GMP_CHECK_LIBM_FOR_BUILD): Include <math.h> to declare log.
+
+2014-03-30  Marc Glisse  <marc.glisse@inria.fr>
+
+	* README: Remove mention to Berkeley MP compatibility.
+
+2014-03-26  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/powerpc64/mode64/gcd_1.asm: Provide default for
+	BMOD_1_TO_MOD_1_THRESHOLD.
+
+2014-03-24  Torbjorn Granlund  <tege@gmplib.org>
+
+	* Version 6.0.0 released.
+
+	* mpn: Update countless gmp-mparam.h files.
+
+2014-03-22  Torbjorn Granlund  <tege@gmplib.org>
+
+	* Makefile.am (LIBGMP_LT_*, LIBGMPXX_LT_*): Bump version info.
+	* gmp-h.in: Bump version.
+
+2014-03-17  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.ac: Remove clipper, i960, ns32k, pyr, a29k, z8000.
+	* mpn/clipper: Remove directory and all its files.
+	* mpn/i960: Likewise.
+	* mpn/ns32k: Likewise.
+	* mpn/pyr: Likewise.
+	* mpn/a29k: Likewise.
+	* mpn/z8000: Likewise.
+	* mpn/Makefile.am (TARG_DIST): Purge removed directories.
+	* doc/gmp.texi: Remove special mentions of removed architectures.
+
+2014-03-12  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86/bd2/gmp-mparam.h: New file.
+	* mpn/x86_64/bd2/gmp-mparam.h: New file.
+
+2014-03-06  Niels Möller  <nisse@lysator.liu.se>
+
+	* tests/mpz/t-pprime_p.c (check_composites): New function.
+	(check_primes): New function.
+	(main): Call them. Also use TESTS_REPS.
+
+2014-03-01  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/sec_powm.c (mpn_sec_powm): Clarify comment and
+	asserts.
+
+2014-02-28  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/fat/fat.c (fake_cpuid): Handle id 7, make bold claims.
+
+2014-02-27  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/fat/fat_entry.asm: Zero ecx for the benefit of new BMI2
+	feature test.
+
+	* mpn/x86_64/fat/fat.c (__gmpn_cpuvec_init): Run CPUVEC_SETUP_coreihwl
+	conditionally on BMI2 availability.
+
+	* config.guess: Revert "coreihwl" to "coreisbr" if cpuid indicates that
+	BMI2 is missing.
+	(x86 cpuid, 2 variants): Zero ecx for the benefit of new BMI2 feature
+	test.
+
+2014-02-17  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/div_qr_1.c (mpn_div_qr_1): Revert yesterday's fix.
+	Hopefully no longer needed.
+
+	* mpn/s390_64/gmp-mparam.h (DIV_QR_1_NORM_THRESHOLD): Up to 1.
+	* mpn/s390_64/z10/gmp-mparam.h (DIV_QR_1_NORM_THRESHOLD): Up to 1.
+
+	* tune/tuneup.c (tune_div_qr_1): Ensure DIV_QR_1_NORM_THRESHOLD,
+	DIV_QR_1_UNNORM_THRESHOLD >= 1.
+
+2014-02-16 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/div_qr_1.c: Disallow DIV_QR_1_NORM_THRESHOLD==0.
+
+2014-02-15  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/mpn/t-div.c: Fix typo.
+
+2014-02-15 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* doc/gmp.texi (mpz_roinit_n, MPZ_ROINIT_N): Document that
+	at least a readable limb is required.
+
+2014-02-14  Niels Möller  <nisse@lysator.liu.se>
+
+	* doc/gmp.texi (Low-level Functions): Update docs for
+	mpn_sec_powm, to specify that left-over exponent bits must be
+	zero.
+
+2014-02-11  Niels Möller  <nisse@lysator.liu.se>
+
+	* Makefile.am (EXTRA_DIST): Distribute COPYING.LESSERv3,
+	COPYINGv2, and COPYINGv3.
+
+	* doc/gmp.texi (Low-level Functions): Updated mpn_sec_powm docs.
+
+	* mpn/generic/sec_powm.c (mpn_sec_powm): Replaced exponent limb
+	count argument by bit count. Don't leak high exponent bits, and
+	drop the requirement that the most significant exponent limb is
+	non-zero.
+	(mpn_sec_powm_itch): Analogous interface change.
+	* gmp-h.in: Updated prototypes.
+	* mpz/powm_sec.c (mpz_powm_sec): Update mpn_sec_powm* calls.
+	* tune/tuneup.c (tune_powm_sec): Likewise. Also deleted code
+	fiddling with the high exponent bits.
+
+2014-02-09  Niels Möller  <nisse@lysator.liu.se>
+
+	* tune/tuneup.c (tune_powm_sec): Avoid timing of the nonsensical
+	parameters nbits = 1, winsize = 2. Decrement tabulated values, to
+	better match the > comparison when the table is used.
+
+	* mpn/generic/sec_powm.c (win_size): Comment why we always get
+	win_size(eb) <= eb. Make the table const.
+	(mpn_sec_powm): Deleted handling of winsize > initial ebi. For
+	now, replaced with an ASSERT_ALWAYS.
+
+2014-02-08  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/sec_invert.c (mpn_cnd_neg_itch): #if:ed out unused
+	function.
+
+	* mpn/generic/sec_div.c: Simplified code for the normalized case.
+
+	* tests/mpn/t-div.c (main): Test mpn_sec_div_qr and mpn_sec_div_r
+	with normalized d.
+
+2014-02-04  Niels Möller  <nisse@lysator.liu.se>
+
+	* doc/gmp.texi (Low-level Functions): Document mpn_sec_add_1 and
+	mpn_sec_sub_1.
+
+2014-01-29  Torbjorn Granlund  <tege@gmplib.org>
+
+	* doc/gmp.texi (Floating-point Functions): Revise.
+
+2014-01-29  Niels Möller  <nisse@lysator.liu.se>
+
+	* README: Don't refer to specific COPYING* files, instead refer to
+	manual for details.
+
+	* COPYING.LIB: Renamed, to...
+	* COPYING.LESSERv3: ... new name.
+	* COPYING: Renamed, to...
+	* COPYINGv3: ... new name.
+	* COPYINGv2: New file, GPLv2.
+
+	* doc/gmp.texi (Copying): Document dual licensing.
+
+2014-01-27  Torbjorn Granlund  <tege@gmplib.org>
+
+	* Update library files license to use LGPL3+ and GPL2+.
+
+2014-01-27 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* tests/mpn/t-aors_1.c: Check sec_aors_1 red zones (not smart).
+
+	* mpn/generic/sec_aors_1.c: Mark the 2nd argument as const.
+	* gmp-h.in (mpn_sec_add_1, mpn_sec_sub_1): Likewise.
+
+2014-01-24  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/fat/fat.c (fake_cpuid_table): Use proper steamroller and
+	excavator values.
+
+	* config.guess: Amend last AMD change.
+
+	* mpn/s390_64/lshift.asm: Align loop.
+	* mpn/s390_64/rshift.asm: Likewise.
+	* mpn/s390_64/lshiftc.asm: Likewise.
+	* mpn/s390_64: Add z10 cycle numbers.
+
+2014-01-23 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* printf/repl-vsnprintf.c: Feed case 'z' in switch (type) with case 'z'
+	in switch (fchar).
+
+2014-01-21 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* acinclude.m4 (GMP_FUNC_VSNPRINTF): Get rid of varargs.
+
+2014-01-20  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/fat/fat.c (__gmpn_cpuvec_init): Fix duplicate entries for
+	AMD "jaguar".
+
+	* demos/expr: Get rid of varargs code and references.
+
+2014-01-19  Torbjorn Granlund  <tege@gmplib.org>
+
+	* config.guess: Add new AMD CPUs (piledriver, steamroller, excavator,
+	jaguar).
+	* config.sub: Corresponding updates.
+	* configure.ac: Likewise.
+	* acinclude.m4 (X86_64_PATTERN): Likewise.
+	* mpn/x86_64/fat/fat.c: Likewise.
+
+	* Rename mpn_sec_minvert => mpn_sec_invert, many files affected.
+	* mpn/generic/sec_invert.c: New name for sec_minvert.c.
+
+	* doc/gmp.texi: Undocument mpz_array_init.
+
+	* acinclude.m4 (GMP_C_STDARG): Comment out.
+	* configure.ac: Suppress GMP_C_STDARG invocation.
+
+	* Get rid of varargs code and references, many file affected.
+
+	* Use mpq_t in favour of MP_RAT, many mpq files affected.
+
+	* Get rid of BYTES_PER_MP_LIMB, most files affected.
+
+	* mpz/iset.c: Avoid overflow in allocation computation.
+	* mpz/mul.c: Likewise.
+	* mpf/init.c: Likewise.
+	* mpf/init2.c: Likewise.
+	* mpf/iset.c: Likewise.
+	* mpf/iset_d.c: Likewise.
+	* mpf/iset_si.c: Likewise.
+	* mpf/iset_str.c: Likewise.
+	* mpf/iset_ui.c: Likewise.
+
+	* mpz/array_init.c: Avoid two overflow scenarios in allocation
+	computation.
+
+	* mpn/s390_64/z10/gmp-mparam.h: New file.
+
+	* mpz/clears.c: Call __gmp_free_func ourselves instead of via
+	mpz_clears.
+	* mpf/clears.c: Analogous change.
+	* mpq/clears.c: Analogous change.
+
+	* mpz/clear.c: Add cast to avoid overflow of (later ignored) argument.
+	* mpf/clear.c: Likewise.
+
+2014-01-18  Niels Möller  <nisse@lysator.liu.se>
+
+	* tests/mpn/t-aors_1.c: Test also mpn_sec_add_1 and mpn_sec_sub_1.
+
+	* tests/mpn/t-minvert.c (main): Pass smallest allowed bit_size
+	argument to mpn_sec_minvert.
+
+2014-01-18  Marc Glisse  <marc.glisse@inria.fr>
+
+	* doc/gmp.texi (C++ Interface Limitations): Warn against C++11 auto.
+
+2014-01-18 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* tests/t-parity.c: Use 1UL to generate unsigned constants.
+	* tests/t-constants.c: Disable a non portable (unneeded) check.
+
+2014-01-18  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/sec_aors_1.c (mpn_sec_add_1, mpn_sec_sub_1): New
+	file.
+
+	* mpn/generic/sec_minvert.c (mpn_sec_add_1_itch, mpn_sec_add_1):
+	Deleted static definitions.
+	(mpn_cnd_swap): Use volatile.
+
+	* configure.ac (gmp_mpn_functions): sec_add_1 and sec_sub_1.
+	(GMP_MULFUNC_CHOICES): Set up for sec_aors_1.
+
+2014-01-16  Niels Möller  <nisse@lysator.liu.se>
+
+	* tune/common.c (speed_mpn_sec_minvert): New function.
+	* tune/speed.h: Declare it.
+	(SPEED_ROUTINE_MPN_SEC_MINVERT): New macro.
+	* tune/speed.c (routine): Added mpn_sec_minvert.
+
+2014-01-12  Marc Glisse  <marc.glisse@inria.fr>
+
+	* demos/expr/expr.h: Add extern "C" for C++.
+
+2014-01-11  Torbjorn Granlund  <tege@gmplib.org>
+
+	* doc/gmp.texi (Notes for Particular Systems): Add items about old
+	NetBSD and current FreeBSD m4 problems.  Add item about FreeBSD's
+	broken limits.h.
+
+2014-01-05 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* gmp-impl.h: Declare all _itch functions using ATTRIBUTE_CONST.
+
+2014-01-05  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.ac (alpha): Set extra_functions conditionally.
+
+	* gmp-h.in (mpn_sec_minvert): Remove formal parameters.
+
+	* doc/gmp.texi: Improve doc for several functions.
+
+	* mpn/generic/sec_tabselect.c: Declare input arg using 'const'.
+	* gmp-h.in: Analogous change.
+
+	* gmp-h.in: Declare all itch functions using __GMP_ATTRIBUTE_PURE.
+	* gmp-impl.h: Likewise.
+
+2014-01-05 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* tests/mpn/t-minvert.c: Always compare with mpz_invert results,
+	add red zone to scratch.
+	* tests/mpn/t-sizeinbase.c: New test.
+	* tests/mpn/Makefile.am (check_PROGRAMS): Added t-sizeinbase.c .
+	* tests/mpn/t-div.c: Use mpn_sec_div_*_itch().
+
+	* mpn/generic/pow_1.c: Micro-optimisation.
+
+2014-01-04  Torbjorn Granlund  <tege@gmplib.org>
+
+	* acinclude.m4 (GMP_PROG_M4): Avoid hex output, since case varies.
+
+2014-01-03  Torbjorn Granlund  <tege@gmplib.org>
+
+	* config.guess: Support newer haswell, broadwell, silvermont.
+	* mpn/x86_64/fat/fat.c (__gmpn_cpuvec_init): Likewise.
+
+	* acinclude.m4 (GMP_PROG_M4): Check that eval's radix argument work.
+
+	* mpz/invert.c: Rely on gcdext for all operands, removing faulty
+	special case.
+	* tests/mpz/t-invert.c: Enforce correct behaviour for |mod| = 1.
+
+2014-01-02  Niels Möller  <nisse@lysator.liu.se>
+
+	* doc/gmp.texi (Low-level Functions): Document mpn_sizeinbase.
+
+	Enable previously unused mpn_sizeinbase function.
+	* configure.ac (gmp_mpn_functions): Added sizeinbase.
+	* gmp-h.in (mpn_sizeinbase): New prototype.
+
+2014-01-02  Marc Glisse  <marc.glisse@inria.fr>
+
+	* gmp-impl.h: Always include <limits.h>.
+	* tests/mpn/t-get_d.c: Remove comment about <limits.h>
+
+	* gmp-h.in (__GMP_USHRT_MAX): Use the promoted type.
+	* gmp-impl.h (USHRT_HIGHBIT, SHRT_MIN, SHRT_MAX): Likewise.
+	* tests/t-constants.c: Adapt printf strings.
+	* tests/t-gmpmax.c: Likewise.
+
+	* tests/mpn/t-hgcd_appr.c (hgcd_appr_valid_p): Add parentheses.
+
+2014-01-01  Torbjorn Granlund  <tege@gmplib.org>
+
+	* doc/gmp.texi (Low-level Functions for cryptography): Update interface
+	for mpn_sec_div_qr and fix typos in mpn_sec_minvert text.
+
+	* mpn/generic/sec_div.c: Rewrite to make mpn_sec_div_qr return high
+	quotient limb.
+	* gmp-h.in (mpn_sec_div_qr): Update declaration.
+	* tests/mpn/t-div.c: Adapt.
+
+2013-12-31  Niels Möller  <nisse@lysator.liu.se>
+
+	* doc/gmp.texi (Low-level Functions for cryptography): Document
+	mpn_sec_minvert.
+
+2013-12-30  Marc Glisse  <marc.glisse@inria.fr>
+
+	* doc/gmp.texi (C++ interface internals): Break long line.
+
+2013-12-30  Torbjorn Granlund  <tege@gmplib.org>
+
+	* doc/gmp.texi (Low-level Functions for cryptography): New section.
+
+2013-12-29  Niels Möller  <nisse@lysator.liu.se>
+
+	* tests/mpn/Makefile.am (check_PROGRAMS): Added t-minvert.
+	* tests/mpn/t-minvert.c: New file.
+
+	* configure.ac (gmp_mpn_functions): Added sec_minvert.
+	* gmp-h.in (mpn_sec_minvert, mpn_sec_minvert_itch): New
+	declarations.
+	* mpn/generic/sec_minvert.c (mpn_sec_minvert)
+	(mpn_sec_minvert_itch): New functions.
+	(mpn_sec_add_1, mpn_cnd_neg, mpn_cnd_swap, mpn_sec_eq_ui): New
+	helper functions.
+
+2013-12-28  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/sec_powm.c: Fix an ASSERT.
+
+	* gmp-h.in (mpn_sec_mul, mpn_sec_mul_itch): New declarations.
+	* gmp-h.in (mpn_sec_sqr, mpn_sec_sqr_itch): Likewise.
+	* mpn/generic/sec_mul.c: New file.
+	* mpn/generic/sec_sqr.c: New file.
+
+	* gmp-h.in (mpn_sec_powm, mpn_sec_powm_itch): New declarations.
+	* gmp-h.in (mpn_sec_div_qr, mpn_sec_div_qr_itch): Likewise.
+	* gmp-h.in (mpn_sec_div_r, mpn_sec_div_r_itch): Likewise.
+	* gmp-impl: Remove declarations of above functions.
+
+	* configure.ac (gmp_mpn_functions): Add sec_mul and sec_sqr.
+
+2013-12-26 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* Update many file's encoding to UTF-8.
+	* doc/tasks.html: Update <meta content> accordingly.
+	* doc/projects.html: Likewise.
+
+2013-12-26  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.ac: Rename mpn_blah_sec to mpn_sec_blah.
+	* gmp-impl.h: Corresponding changes.
+	* mpn/asm-defs.m4: Corresponding changes.
+	* tune/Makefile.am: Corresponding changes.
+	* tune/common.c: Corresponding changes.
+	* tune/speed.c: Corresponding changes.
+	* tune/speed.h: Corresponding changes.
+	* tune/tuneup.c: Corresponding changes.
+	* mpz/powm_sec.c: Update calls.
+	* tests/mpn/t-div.c: Likewise.
+
+	* mpn/generic/sec_powm.c: New name for mpn/generic/powm_sec.c.
+	* mpn/generic/sec_div.c: New name for mpn/generic/sb_div_sec.c.
+	* mpn/generic/sec_pi1_div.c: New name for mpn/generic/sbpi1_div_sec.c.
+	* mpn/generic/sec_tabselect.c: New name for mpn/generic/tabselect.c.
+
+	* mpn/alpha/sec_tabselect.asm: New name for tabselect.asm.
+	* mpn/arm/neon/sec_tabselect.asm: New name for tabselect.asm.
+	* mpn/arm/sec_tabselect.asm: New name for tabselect.asm.
+	* mpn/ia64/sec_tabselect.asm: New name for tabselect.asm
+	* mpn/powerpc32/sec_tabselect.asm: New name for tabselect.asm
+	* mpn/powerpc64/sec_tabselect.asm: New name for tabselect.asm
+	* mpn/sparc64/sec_tabselect.asm: New name for tabselect.asm
+	* mpn/x86/mmx/sec_tabselect.asm: New name for tabselect.asm
+	* mpn/x86/sec_tabselect.asm: New name for tabselect.asm
+	* mpn/x86_64/bd1/sec_tabselect.asm: New name for tabselect.asm
+	* mpn/x86_64/core2/sec_tabselect.asm: New name for tabselect.asm
+	* mpn/x86_64/coreinhm/sec_tabselect.asm: New name for tabselect.asm
+	* mpn/x86_64/coreisbr/sec_tabselect.asm: New name for tabselect.asm
+	* mpn/x86_64/fastsse/sec_tabselect.asm: New name for tabselect.asm
+	* mpn/x86_64/k10/sec_tabselect.asm: New name for tabselect.asm
+	* mpn/x86_64/pentium4/sec_tabselect.asm: New name for tabselect.asm
+	* mpn/x86_64/sec_tabselect.asm: New name for tabselect.asm
+
+2013-12-25  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpz/powm_sec.c: Handle 0^e mod m specially.
+	* mpn/generic/powm_sec.c: ASSERT that the base is non-zero.
+
+2013-12-23  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/powm_sec.c (redcify): Use passed scratch instead of
+	locally allocated.
+	(mpn_powm_sec_itch): Accommodate mpn_sb_div_r_sec's scratch needs.
+
+2013-12-20  Mark Sofroniou  <marks@wolfram.com>
+
+	* mpn/generic/mul_fft.c: Major overhaul of types.
+
+2013-12-18  Torbjorn Granlund  <tege@gmplib.org>
+
+	* doc/gmp.texi (Low-level Functions): Rewrite mpn_set_str docs.
+
+2013-12-14  Ulrich Weigand  <Ulrich.Weigand@de.ibm.com>
+
+	* mpn/powerpc32/darwin.m4: Allow (and ignore) optional
+	'toc' parameter to PROLOGUE_cpu.
+	* mpn/powerpc32/elf.m4: Likewise.
+
+2013-12-09  Ulrich Weigand  <Ulrich.Weigand@de.ibm.com>
+
+	* configure.ac: Check for ELFv2 ABI on PowerPC.
+	* mpn/powerpc64/elf.m4: Set assembler ABI version for ELFv2
+	and use appropriate PROLOGUE_cpu/EPILOGUE_cpu sequences.
+	Support optional 'toc' parameter to PROLOGUE_cpu.
+	* mpn/powerpc64/aix.m4: Allow (and ignore) optional
+	'toc' parameter to PROLOGUE_cpu.
+	* mpn/powerpc64/darwin.m4: Likewise.
+
+	* mpn/powerpc64/mode64/dive_1.asm (mpn_divexact_1): Add 'toc'
+	parameter to PROLOGUE.
+	* mpn/powerpc64/mode64/divrem_1.asm (mpn_divrem_1): Likewise.
+	* mpn/powerpc64/mode64/divrem_2.asm (mpn_divrem_2): Likewise.
+	* mpn/powerpc64/mode64/gcd_1.asm (mpn_gcd_1): Likewise.
+	* mpn/powerpc64/mode64/invert_limb.asm (mpn_invert_limb): Likewise.
+	* mpn/powerpc64/mode64/mod_1_1.asm (mpn_mod_1_1p_cps): Likewise.
+	* mpn/powerpc64/mode64/mod_1_4.asm (mpn_mod_1s_4p_cps): Likewise.
+	* mpn/powerpc64/mode64/mode1o.asm (mpn_modexact_1c_odd): Likewise.
+	* mpn/powerpc64/mode64/p7/gcd_1.asm (mpn_gcd_1): Likewise.
+	* mpn/powerpc64/p6/lshift.asm (mpn_lshift): Likewise.
+	* mpn/powerpc64/p6/lshiftc.asm (mpn_lshiftc): Likewise.
+	* mpn/powerpc64/p6/rshift.asm (mpn_rshift): Likewise.
+	* mpn/powerpc64/vmx/popcount.asm (mpn_popcount): Likewise.
+
+2013-12-07  Niels Möller  <nisse@lysator.liu.se>
+
+	* configfsf.sub: Updated to version 2013-10-01, from gnulib.
+	* configfsf.guess: Updated to version 2013-11-29, from gnulib.
+
+2013-12-03  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/div_qr_1.c: Make constant args asm inlines become limbs.
+	* mpn/generic/div_qr_1n_pi1.c: Likewise.
+	* mpn/generic/div_qr_2.c: Likewise.
+	* mpn/generic/div_qr_2.c: Likewise.
+	* mpn/generic/mod_1_1.c: Likewise.
+	* mpn/generic/mod_1_2.c: Likewise.
+	* mpn/generic/mod_1_3.c: Likewise.
+	* mpn/generic/mod_1_4.c: Likewise.
+	* mpn/generic/mulmid_basecase.c: Likewise.
+	* mpn/generic/mulmod_bnm1.c: Likewise.
+	* mpn/generic/sqrmod_bnm1.c: Likewise.
+	* mpn/sparc64/divrem_1.c: Likewise.
+	* mpn/sparc64/mod_1_4.c: Likewise.
+
+	* mpn/generic/toom_interpolate_7pts.c (BINVERT_15): Fix typo.
+
+2013-11-11  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/dos64.m4 (CALL): Provide to override default.
+
+2013-11-08  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/x86_64-defs.m4 (CALL): Swap PIC test and macro defn.
+
+	* mpn/generic/div_qr_2.c: Test HAVE_HOST_CPU_FAMILY_x86, not i386.
+
+	* doc/gmp.texi: Update many URLs.
+
+2013-11-04  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.ac: Set symbol OPENBSD for x86-openbsd hosts.
+	* mpn/x86_64/fat/fat_entry.asm (PRETEND_PIC): New name for
+	PIC_OR_DARWIN.
+	(PRETEND_PIC): Set also for OPENBSD.
+
+2013-10-29  Torbjorn Granlund  <tege@gmplib.org>
+
+	* printf/doprnt.c (__gmp_doprnt): Use memcpy instead of strcpy.
+
+2013-10-24  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/div_qr_1u_pi2.c: New file.
+	* mpn/generic/div_qr_1n_pi2.c: New file.
+
+2013-10-24  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/x86_64/div_qr_1n_pi1.asm: Bugfixes, for case n == 1 and
+	in-place operation.
+	* mpn/x86_64/k8/div_qr_1n_pi1.asm: Likewise.
+
+	* mpn/generic/div_qr_1n_pi1.c (mpn_div_qr_1n_pi1): Bug fixes,
+	off-by-one MPN_INCR_U, and support for in-place operation.
+
+2013-10-24  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86/fat/fat.c (fake_cpuid_table): Add Haswell.
+
+2013-10-23  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/x86_64-defs.m4 (oplist): New define, data from `regnum'.
+	(regnum): Use x86_lookup, feed oplist.
+
+2013-10-22  Niels Möller  <nisse@lysator.liu.se>
+
+	* tests/devel/try.c: Support mpn_div_qr_1n_pi1.
+
+	* mpn/x86_64/k8/div_qr_1n_pi1.asm: Moved the below k10 file here.
+	Applied tweak from Torbjörn to get it to run well on k8.
+
+	* mpn/x86_64/k10/div_qr_1n_pi1.asm: New file (renamed above).
+	Differs from generic x86_64 version by using cmov.
+
+	* mpn/x86_64/div_qr_1n_pi1.asm: Reordered arguments to second mul.
+	Deleted misleading cycle annotations.
+
+2013-10-21  Niels Möller  <nisse@lysator.liu.se>
+
+	* configure.ac: Add HAVE_NATIVE_mpn_div_qr_1n_pi1 to config.in.
+
+	* mpn/generic/div_qr_1n_pi1.c (mpn_div_qr_1n_pi1): Fix typos
+	affecting ASSERT.
+
+2013-10-20  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/x86_64/div_qr_1n_pi1.asm: New file.
+
+	* tune/div_qr_1_tune.c (__gmpn_div_qr_1n_pi1): Check
+	div_qr_1n_pi1_method only when !HAVE_NATIVE_mpn_div_qr_1n_pi1.
+
+	* mpn/asm-defs.m4 (define_mpn): Add div_qr_1n_pi1.
+
+	* tune/common.c (speed_mpn_div_qr_1): New function, replacing...
+	(speed_mpn_div_qr_1n, speed_mpn_div_qr_1u): ... deleted functions
+	(speed_mpn_div_qr_1n_pi1, speed_mpn_div_qr_1n_pi1_1)
+	(speed_mpn_div_qr_1n_pi1_2): New functions.
+	* gmp-impl.h [TUNE_PROGRAM_BUILD]: Declare div_qr_1-related tuning
+	variables.
+	* tune/tuneup.c (speed_mpn_div_qr_1_tune, tune_div_qr_1): New
+	functions.
+	(div_qr_1n_pi1_method, div_qr_1_norm_threshold)
+	(div_qr_1_unnorm_threshold): New globals.
+	* tune/speed.c (routine): Replaced mpn_div_qr_1n and mpn_div_qr_1u
+	by mpn_div_qr_1, requiring ".r" parameter. Added mpn_div_qr_1n_pi1
+	and variants.
+	* tune/speed.h (SPEED_ROUTINE_MPN_DIV_QR_1): Use the "r" parameter
+	as divisor.
+	* tune/div_qr_1n_pi1_2.c: New file.
+	* tune/div_qr_1n_pi1_1.c: New file.
+	* tune/div_qr_1_tune.c: New file.
+	* tune/Makefile.am (libspeed_la_SOURCES): Added div_qr_1n_pi1_1.c,
+	div_qr_1n_pi1_2.c, and div_qr_1_tune.c.
+
+	* tune/speed.c (routine): Added mpn_div_qr_1n and mpn_div_qr_1u.
+	* tune/speed.h (SPEED_ROUTINE_MPN_DIV_QR_1): New macro.
+	(speed_mpn_div_qr_1n, speed_mpn_div_qr_1u): Declare.
+	* tune/common.c (speed_mpn_div_qr_1n, speed_mpn_div_qr_1u): New
+	functions.
+
+	* gmp-impl.h (mpn_div_qr_1n_pi1): Declare function.
+	* gmp-h.in (mpn_div_qr_1): Declare function.
+	* configure.ac (gmp_mpn_functions): Added div_qr_1 and
+	div_qr_1n_pi1.
+	* mpn/generic/div_qr_1.c (mpn_div_qr_1): New file and function.
+	* mpn/generic/div_qr_1n_pi1.c (mpn_div_qr_1n_pi1): New file and
+	function.
+	* tests/mpn/t-div.c (main): Test mpn_div_qr_1.
+
+2013-10-17  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.ac (alpha): Pass -mieee via gcc_cflags_maybe.
+
+2013-10-16  Torbjorn Granlund  <tege@gmplib.org>
+
+	* config.guess: Let AMD64 cpuid bit override pessimistic cpu guesses.
+
+	* mpn/alpha/unicos.m4 (DATASTART): Accept optional align parameter.
+	* mpn/alpha/divrem_2.asm: Use provided gp mechanisms.
+	* mpn/alpha/default.m4 (PROLOGUE): Provide "..ng" post-gp label.
+	* mpn/alpha/invert_limb.asm: Align table to 8-byte boundary.  Make code
+	work if table is not fully aligned.  Properly test for BWX.
+
+2013-10-15  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/alpha/default.m4 (DATASTART): Use RODATA instead of DATA;
+	accept optional align parameter.
+	* mpn/alpha/invert_limb.asm: Align table.
+	* mpn/alpha/ev5/diveby3.asm: Likewise.
+
+2013-10-11  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86/k7/mod_1_1.asm: Use 'subl' form to avoid ambiguity.
+	* mpn/x86/k7/mod_1_4.asm: Likewise.
+
+	* configure.ac (X86_64_PATTERN): Append "cc" to cclist_64 and
+	cclist_x32.
+
+2013-10-08  Torbjorn Granlund  <tege@gmplib.org>
+	    Marc Glisse  <marc.glisse@inria.fr>
+
+	* tests/mpf/reuse.c (main): Compare addresses instead of names.
+	Use larger numbers for exponents.
+
+2013-10-08  Marc Glisse  <marc.glisse@inria.fr>
+
+	* doc/mdate-sh, doc/texinfo.tex, install-sh, missing, ylwrap: Remove.
+	* .bootstrap: Use autoreconf (and in particular automake -a).
+
+	* gmp-h.in: Remove __need_size_t. Include <stddef.h>, not <cstddef>.
+
+	* tests/mpf/reuse.c (main): Use small numbers as exponents.
+
+2013-10-05  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/atom/aorsmul_1.asm: Slight tweak.
+
+	* doc/gmp.texi (ABI and ISA): Document x32.
+
+	* mpn/sparc64/ultrasparct3/dive_1.asm: Use our register names.
+
+2013-09-24  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/atom/redc_1.asm: New file.
+
+2013-09-23  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/bobcat/redc_1.asm: Make the code for 1 <= n <= 3 work.
+
+2013-09-22  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/coreisbr/redc_1.asm: Slightly tweak basecase code.
+
+	* mpn/x86_64/core2/redc_1.asm: New file.
+
+	* mpn/x86_64/bobcat/redc_1.asm: New file.
+
+2013-09-21  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/coreinhm/redc_1.asm: New file.
+
+2013-09-21  Marc Glisse  <marc.glisse@inria.fr>
+
+	* tests/mpn/t-mulmid.c: Cast arguments of printf to int to match %d.
+	* tests/rand/t-urbui.c: Use 1UL for unsigned constant.
+	* mpn/generic/get_str.c: Avoid temporarily pointing outside an array.
+
+2013-09-20  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/coreisbr/redc_1.asm: New file.
+
+	* mpn/x86_64/k8/redc_1.asm: Complete rewrite.
+
+	* mpn/x86_64/coreisbr/mullo_basecase.asm: Postpone pushes, short-
+	circuit a branch.
+	* mpn/x86_64/coreihwl/mullo_basecase.asm: Short-circuit a branch.
+
+	* mpn/x86_64/core2/mullo_basecase.asm: New file.
+
+2013-09-19  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/fastsse/copyi-palignr.asm: Allocate more stack under DOS.
+
+2013-09-18  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/core2/mul_basecase.asm: New file.
+	* mpn/x86_64/core2/sqr_basecase.asm: New file.
+
+	* mpn/x86_64/coreihwl/mullo_basecase.asm: New file.
+	* mpn/x86_64/coreisbr/mullo_basecase.asm: New file.
+
+2013-09-16  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/fastsse/copyi-palignr.asm: Preserve xmm6-xmm8 under DOS.
+
+2013-09-15  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/tabselect.asm: Use R8 for bit testing.
+
+	* mpn/x86_64/coreihwl/mul_basecase.asm: Replace mul_1 code.
+
+	* mpn/x86_64/coreisbr/aorsmul_1.asm: Rewrite.
+
+2013-09-12  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/ia64/gcd_1.asm: Use dep for combining table base and low bits.
+
+	* mpn/x86_64/fastsse/com-palignr.asm: Implement temp fix to properly
+	handle overlap.
+
+2013-09-10  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/fastsse/copyi-palignr.asm: Rewrite rp != up (mod 16) code
+	to make it handle any allowed overlap.
+
+2013-09-09  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/atom/com.asm: New file, grabbing fastsse code.
+
+	* mpn/x86_64/bd1/copyi.asm: New file, grabbing fastsse code.
+	* mpn/x86_64/bd1/copyd.asm: Likewise.
+	* mpn/x86_64/bd1/com.asm: Likewise.
+
+	* mpn/x86_64/fastavx/copyi.asm: New file.
+	* mpn/x86_64/fastavx/copyd.asm: New file.
+
+2013-09-05  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/coreihwl/aorsmul_1.asm: Streamline.
+
+2013-09-04  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/coreihwl/sqr_basecase.asm: Implement larger "corner".
+	Misc tuning.
+
+2013-09-03  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/coreihwl/redc_1.asm: New file.
+
+	* mpn/x86_64/x86_64-defs.m4 (mulx): Handle negative offsets.
+
+2013-08-31  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/coreisbr/sqr_basecase.asm: New file.
+
+	* mpn/x86_64/sqr_diag_addlsh1.asm: New file.
+
+2013-08-30  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/fat/mul_basecase.c: New file.
+	* mpn/x86_64/fat/sqr_basecase.c: New file.
+	* mpn/x86_64/fat/mullo_basecase.c: New file.
+	* mpn/x86_64/fat/redc_1.c: New file.
+
+2013-08-29  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/k8/mul_basecase.asm: Move top-level basecase file to k8
+	subdir.
+	* mpn/x86_64/k8/sqr_basecase.asm: Likewise.
+	* mpn/x86_64/k8/redc_1.asm: Likewise.
+	* mpn/x86_64/k8/mullo_basecase.asm: Likewise.
+	* mpn/x86_64/k8/mulmid_basecase.asm: Likewise.
+
+	* mpn/ia64/aors_n.asm: Clean up some bundlings.
+
+	* mpn/x86_64/fat/fat.c (__gmpn_cpuvec_init): Support Haswell.
+	(fake_cpuid_table): Likewise.
+
+	* configure.ac (x86): Remove any mulx paths.  Let bwl path = hwl path.
+	(fat_path): Add coreihwl.
+
+	* mpn/x86_64/coreihwl/aorsmul_1.asm: Move from `mulx' directory, use
+	mulx() macro.
+	* mpn/x86_64/coreihwl/mul_1.asm: Likewise.
+	* mpn/x86_64/coreihwl/mul_2.asm: Likewise.
+	* mpn/x86_64/coreihwl/mul_basecase.asm: Likewise.
+	* mpn/x86_64/coreihwl/sqr_basecase.asm: Likewise.
+
+	* mpn/x86_64/x86_64-defs.m4 (mulx): New macro.
+	(regnum, regnumh, ix): Supporting macros.
+
+2013-08-28  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/coreisbr/divrem_1.asm: New file.
+
+2013-08-23  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/fastsse/com-palignr.asm: New file, closely based on
+	copyi-palignr.asm.
+
+	* mpn/x86_64/fastsse/copyi.asm Use "test R8(reg)" instead of "bt".
+	* mpn/x86_64/fastsse/copyd-palignr.asm: Likewise.
+	* mpn/x86_64/fastsse/copyi-palignr.asm: Likewise.
+	* mpn/x86_64/fastsse/lshift-movdqu2.asm: Likewise.
+	* mpn/x86_64/fastsse/lshiftc-movdqu2.asm: Likewise.
+	* mpn/x86_64/fastsse/rshift-movdqu2.asm: Likewise.
+	* mpn/x86_64/fastsse/tabselect.asm: Likewise.
+
+	* mpn/sparc64/ultrasparct3/sqr_diag_addlsh1.asm: New file.
+
+	* mpn/alpha/aorslsh2_n.asm: New file.
+	* mpn/alpha/aorslsh1_n.asm: Rewrite.
+	* mpn/alpha/ev6/aorslsh1_n.asm: New file.
+
+2013-08-21  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/alpha/sqr_diag_addlsh1.asm: New file.
+	* mpn/alpha/sqr_diagonal.asm: Remove.
+	* mpn/alpha/ev6/sqr_diagonal.asm: Remove.
+
+2013-08-20  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/powerpc32/sqr_diag_addlsh1.asm: New file.
+	* mpn/powerpc32/sqr_diagonal.asm: Remove.
+
+2013-08-15  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/coreihwl/mulx/sqr_basecase.asm: New file.
+
+2013-08-05  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/coreisbr/aors_n.asm: Complete rewrite.
+
+2013-08-04  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/coreihwl/mulx/mul_basecase.asm: New file.
+
+	* mpn/x86_64/bd1/mul_2.asm: New file.
+
+	* mpn/x86_64/coreihwl/gmp-mparam.h: New file.
+
+2013-08-03  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/coreihwl/mulx/mul_2.asm: New file.
+	* mpn/x86_64/coreihwl/mulx/addmul_2.asm: New file.
+
+	* mpn/x86_64/coreinhm/aorsmul_1.asm: New file.
+
+	* mpn/x86_64/coreisbr/mul_basecase.asm: Save some O(n) and O(1) cycles.
+
+	* mpn/x86_64/coreisbr/mul_2.asm: New file.
+
+2013-08-02  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/coreisbr/addmul_2.asm: Complete rewrite.
+
+2013-08-01  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/bd1/mul_basecase.asm: New file.
+
+	* mpn/x86_64/coreisbr/mul_basecase.asm: New file.
+
+	* mpn/x86_64/coreihwl/aorsmul_1.asm: New file.
+
+2013-07-31  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/atom/mul_2.asm: New file.
+	* mpn/x86_64/atom/addmul_2.asm: New file.
+	* mpn/x86_64/atom/mul_1.asm: New file.
+	* mpn/x86_64/atom/aorsmul_1.asm: New file.
+
+	* mpn/x86_64/coreihwl/mul_1.asm: New file.
+
+	* configure.ac (x86): Add Haswell-specific path.
+
+	* configure.in (fat_functions): Add cnd_add_n, cnd_sub_n..
+	* gmp-impl.h (struct cpuvec_t): Add fields for new fat functions.
+	* gmp-impl.h: Adjust corresponding declarations.
+
+	* mpn/x86_64/x86_64-defs.m4 (CPUVEC_FUNCS_LIST): Add new fat functions.
+	* mpn/x86/x86-defs.m4 (CPUVEC_FUNCS_LIST): Likewise.
+	* mpn/x86_64/fat/fat.c (__gmpn_cpuvec): Likewise.
+	* mpn/x86/fat/fat.c (__gmpn_cpuvec): Likewise.
+
+2013-07-30  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/coreisbr/popcount.asm: New file.
+
+2013-07-23  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/bobcat/aors_n.asm: New file.
+
+	* mpn/x86_64/pentium4/aorslshC_n.asm: Remove a spurious emms insn.
+
+	* mpn/x86_64/bd1/aorrlsh1_n.asm: New file.
+	* mpn/x86_64/bd1/sublsh1_n.asm: New file.
+
+2013-07-22  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/powerpc64/mode64/mod_1_1.asm: Handle little-endian mode.
+	* mpn/powerpc64/mode64/mod_1_4.asm: Likewise.
+
+2013-07-16  Torbjorn Granlund  <tege@gmplib.org>
+
+	* doc/gmp.texi: Declare countless of function arguments as 'const'.
+
+2013-07-15  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/core2/aors_n.asm: Rewrite.
+
+	* mpn/generic/sb_div_sec.c: Compute inverse as floor(B^2/(dh+1)), per
+	Niels' suggestion.
+	* mpn/generic/sbpi1_div_sec.c: Remove inverse rounding-up code.
+
+2013-07-14  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/powerpc64/mode64/divrem_1.asm: Remove explicit nop after CALL.
+	* mpn/powerpc64/mode64/divrem_2.asm: Likewise.
+	* mpn/powerpc64/mode64/mod_1_1.asm: Likewise.
+	* mpn/powerpc64/mode64/mod_1_4.asm: Likewise.
+
+2013-07-13  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86/atom/cnd_add_n.asm: New file.
+	* mpn/x86/atom/cnd_sub_n.asm: New file.o
+
+2013-07-12  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/sbpi1_div_sec.c: Partial rewrite.
+
+2013-07-11  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/cnd_aors_n.asm: Tweak for better speed on K8, bobcat, bd1,
+	NHM, Atom.
+
+2013-07-05  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/powerpc64/p7/copyi.asm: Handle n = 0.
+	* mpn/powerpc64/p7/copyd.asm: Likewise.
+
+2013-07-04  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/powerpc64/mode64/p7/aormul_2.asm: New file.
+
+	* mpn/powerpc64/darwin.m4 (EXTRA_REGISTER): New define.
+	* mpn/powerpc64/aix.m4: New define (actually undefine).
+	* mpn/powerpc64/elf.m4: Likewise.
+
+2013-07-03  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/powerpc64/com.asm: Rewrite.
+
+	* mpn/powerpc64/p7/copyi.asm: New file.
+	* mpn/powerpc64/p7/copyd.asm: New file.
+
+2013-07-02  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/powerpc64/mode64/gcd_1.asm: New file.
+	* mpn/powerpc64/mode64/p7/gcd_1.asm: New file.
+
+2013-07-01  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.ac: Comment out AC_PROG_F77.
+
+	* mpn/powerpc64/mode64/rsh1add_n.asm: Remove.
+	* mpn/powerpc64/mode64/rsh1sub_n.asm: Remove.
+	* mpn/powerpc64/mode64/rsh1aors_n.asm: New file, code not based on
+	removed files.
+
+2013-06-28  Marc Glisse  <marc.glisse@inria.fr>
+
+	* cxx/ismpf.cc: Use GMP_DECIMAL_POINT.
+	* cxx/osmpf.cc: Likewise.
+	* tests/cxx/t-locale.cc: Likewise.
+
+2013-06-28  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/powerpc64/mode64/p7/aorsorrlshC_n.asm: New file.
+	* mpn/powerpc64/mode64/p7/aorsorrlsh1_n.asm: New file.
+	* mpn/powerpc64/mode64/p7/aorsorrlsh2_n.asm: New file.
+
+	* mpn/powerpc64/mode64/aorsorrlshC_n.asm: Use alias regname.
+
+2013-06-27  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/powerpc64/mode64/p7/aors_n.asm: New file.
+
+2013-06-22  Torbjorn Granlund  <tege@gmplib.org>
+
+	* aorslshC_n.asm, aorslsh2_n.asm, aorslsh1_n.asm: Remove.
+	* aorsorrlshC_n.asm, aorsorrlsh1_n.asm, aorsorrlsh2_n.asm: New files.
+
+2013-06-19  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/powerpc64/p6/lshift.asm: Rewrite switching-into-loop code.
+	* mpn/powerpc64/p6/rshift.asm: Likewise.
+	* mpn/powerpc64/p6/lshiftc.asm: Likewise.
+
+2013-06-17  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/powerpc64/p6/lshift.asm: Fix typo in label reference.
+	For 32-bit mode, zero extend `n' argument and split retval.
+	* mpn/powerpc64/p6/rshift.asm: Likewise.
+	* mpn/powerpc64/p6/lshiftc.asm: Likewise.
+
+2013-06-10  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/mu_div_q.c: Remove obsolete comment.
+
+2013-06-09  Marc Glisse  <marc.glisse@inria.fr>
+
+	* mpn/generic/get_d.c (mpn_get_d): Avoid signed overflow.
+	* mpz/kronzs.c (mpz_kronecker_si): Use ABS_CAST.
+
+2013-05-31  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/mu_div_q.c: Call mpn_mu_divappr_q for entire division,
+	never just for tail.  (This fixes performance issues at the expense of
+	memory needs.)
+
+2013-05-26  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.ac (*sparc*-*-*): Major overhaul.
+
+2013-05-22  Torbjorn Granlund  <tege@gmplib.org>
+
+	* doc/gmp.texi (Reporting Bugs): Ask for configure's output.
+
+	* mpn/ia64/divrem_2.asm: Don't clobber f16-f18.
+
+2013-05-20  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/arm/udiv.asm: Change spacing to work around binutils bug.
+
+2013-05-16  Torbjorn Granlund  <tege@gmplib.org>
+
+	* Makefile.am (LIBGMP_LT_*, LIBGMPXX_LT_*): Bump version info.
+
+	* tests/misc.c (tests_hardware_getround, tests_hardware_setround):
+	Avoid assembly dependency unless WANT_ASSEMBLY.
+
+	* configure.ac (WANT_ASSEMBLY): Conditionally define.
+
+2013-05-14  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.ac (arm1156): Don't fall back to plain v6 compiler option.
+
+2013-05-11  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/coreisbr/mul_1.asm: Handle n = 1 for DOS64.  Streamline.
+	* mpn/x86_64/coreisbr/aorsmul_1.asm: Streamline.
+
+2013-05-10  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/coreisbr/aorsmul_1.asm: Fix, then enable DOS64 support.
+	* mpn/x86_64/coreisbr/mul_1.asm: Enable DOS64 support.
+
+	* mpn/x86/p6/mmx/gmp-mparam.h: Set down SQR_TOOM2_THRESHOLD to parent
+	directory value.
+
+2013-05-09  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.ac (--enable-fake-cpuid): New option.
+	* mpn/x86_64/fat/fat.c (WANT_FAKE_CPUID): Remove defaulting.
+	* mpn/x86/fat/fat.c (WANT_FAKE_CPUID): Likewise.
+
+	* mpn/x86_64/bd1/mul_1.asm: Fix typo.
+
+2013-05-07  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/fat/fat.c (fake_cpuid): Handle 0x80000001 request.
+	(fake_cpuid_available): Remove unused function.
+
+	* mpn/generic/mod_1_1.c: Cast constant udiv_rnnd_preinv arguments.
+	* mpn/generic/mod_1_2.c: Likewise.
+	* mpn/generic/mod_1_3.c: Likewise.
+	* mpn/generic/mod_1_4.c: Likewise.
+	* mpn/generic/divrem_2.c: Likewise.
+
+2013-05-06  Torbjorn Granlund  <tege@gmplib.org>
+
+	* config.guess (power*): Handle all ppc970 variants.
+
+2013-05-03  David S. Miller  <davem@davemloft.net>
+
+	* tune/common.c (speed_mpn_addlsh1_n, speed_mpn_sublsh1_n,
+	speed_mpn_rsblsh1_n, speed_mpn_addlsh2_n, speed_mpn_sublsh2_n,
+	speed_mpn_rsblsh2_n): Don't define if these routines are macros.
+	* tune/speed.c (routine): Likewise don't table if they are macros.
+
+	* mpn/sparc64/ultrasparct3/addmul_1.asm: Add T4 and T3 timings.
+	* mpn/sparc64/ultrasparct3/aormul_4.asm: Likewise.
+	* mpn/sparc64/ultrasparct3/aorslsh_n.asm: Likewise.
+	* mpn/sparc64/ultrasparct3/cnd_aors_n.asm: Likewise.
+	* mpn/sparc64/ultrasparct3/submul_1.asm: Likewise.
+
+2013-05-03  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/sparc64/ultrasparct3/aorslsh_n.asm: Invoke INITCY where it has
+	effect.
+
+	* gmp-impl.h: Amend last change.
+	* tests/devel/try.c (choice_array): Don't try to table addlsh1_n etc if
+	a macro.
+
+2013-05-02  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/arm/copyd.asm: Suppress dead pointer update.
+	* mpn/arm/copyi.asm: Likewise.
+	* mpn/arm/neon/logops_n.asm: Likewise.
+	* mpn/arm/neon/tabselect.asm: Likewise.
+	* mpn/arm/rshift.asm: Likewise.
+	* mpn/arm/tabselect.asm: Likewise.
+	* mpn/arm/v6/dive_1.asm: Likewise
+	* mpn/arm/v7a/cora15/neon/copyi.asm: Likewise.
+
+	* mpn/arm/v7a/cora15/neon/com.asm: New file.
+
+2013-05-01  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/sparc64/ultrasparct3/aormul_4.asm: New file.
+
+	* configure.ac (GMP_MULFUNC_CHOICES): Support mul_3 + addmul_3 and
+	mul_4 + addmul_4.
+
+	* mpn/sparc64/ultrasparct3/aormul_2.asm: Optimise lead-in code.
+
+	* mpn/sparc64/ultrasparct3/missing.m4 (addxccc): Allow g2 as input.
+	(umulxhi): Save and restore o7 to allow it as in/out parameter.
+
+2013-04-29  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/arm/v7a/cora15/cnd_aors_n.asm: New file, was mis-named.
+
+	* mpn/sparc64/ultrasparct3/addmul_1.asm: Rewrite.
+
+	* mpn/sparc64/ultrasparct3/submul_1.asm: Rewrite.
+
+	* mpn/sparc64/ultrasparct3/cnd_aors_n.asm: New file.
+
+	* gmp-impl.h: Override mpn_addlsh1_n, mpn_addlsh2_n, mpn_sublsh1_n, etc
+	with mpn_addlsh_n, etc when !HAVE_NATIVE the former but HAVE_NATIVE the
+	latter.
+
+	* mpn/sparc64/ultrasparct3/aorslsh_n.asm: New file.
+
+	* configure.ac (sparc-*-*): Recognise t5 along with t3 and t4.
+	Remove sparc64/ultrasparct1 from path_64 for T3, T3, and T5.
+
+2013-04-27  Mike Frysinger  <vapier@gentoo.org>
+
+	* configure.ac (arm*-*-*): Set up path also for plainest CPU variants.
+
+2013-04-27  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/arm/v6/popham.asm: New file.
+
+	* mpn/arm/v7a/cora15/cnd-aors_n.asm: New file.
+
+2013-04-25  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/arm/mod_34lsub1.asm: Clear carry smarter.
+
+	* mpn/arm/v7a/cora15/logops_n.asm: Conditionally suppress conditionally
+	used code.
+
+	* mpn/arm/v7a/cora15/submul_1.asm: New file.
+
+2013-04-24  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/arm/v7a/cora15/com.asm: New file.
+
+	* mpn/arm/v7a/cora15/logops_n.asm: New file.
+
+2013-04-19  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/arm/v7a/cora15/aors_n.asm: New file.
+
+	* mpn/arm/v7a/cora15/addmul_1.asm: Rewrite.
+
+2013-04-18  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/alpha/tabselect.asm: New file.
+
+2013-04-17  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/powerpc32/tabselect.asm: New file.
+
+	* longlong.h (arm64 count_trailing_zeros): New.
+
+	* mpn/arm64/invert_limb.asm: New file.
+
+	* mpn/generic/dive_1.c: Rewrite to use Hensel division also for
+	size = 1.
+
+	* mpn/generic/mod_1_1.c (add_mssaaaa): Provide VIS3 variant.
+
+	* configure.ac: Remove "missing" from extra_functions_64 for coreibwl.
+
+	* mpn/sparc64/ultrasparct3/mul_1.asm: Decrease loop alignment.
+	* mpn/sparc64/ultrasparct3/aormul_2.asm: Likewise.
+
+2013-04-16  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/alpha/invert_limb.asm: Generate table.
+	* mpn/powerpc64/mode64/invert_limb.asm: Likewise.
+	* mpn/s390_64/invert_limb.asm: Likewise.
+	* mpn/sparc64/ultrasparct3/invert_limb.asm: Likewise.
+	* mpn/x86_64/invert_limb_table.asm: Likewise.
+
+2013-04-15  David S. Miller  <davem@davemloft.net>
+
+	* mpn/sparc32/sparc-defs.m4 (LEA64): New macro.
+	* mpn/sparc64/gcd_1.asm: Use it.
+	* mpn/sparc64/ultrasparct3/dive_1.asm: Likewise.
+	* mpn/sparc64/ultrasparct3/invert_limb.asm: Likewise.
+	* mpn/sparc64/ultrasparct3/mode1o.asm: Likewise.
+
+	* mpn/sparc64/gcd_1.asm: Use RODATA, TYPE, and SIZE.
+
+2013-04-15  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/sparc64/ultrasparct3/invert_limb.asm: Avoid addend for GOT entry,
+	it is not portable.
+
+	* mpn/sparc64/tabselect.asm: New file.
+
+	* mpn/x86/mmx/tabselect.asm: New file.
+	* configure.ac (x86): Add x86/mmx to path for relevant CPUs.
+
+	* mpn/sparc64/gcd_1.asm: Use rdpc for PIC.
+	* mpn/sparc64/ultrasparct3/mode1o.asm: Use rdpc for PIC.
+	* mpn/sparc64/ultrasparct3/dive_1.asm: Use rdpc for PIC.
+	* mpn/sparc64/ultrasparct3/invert_limb.asm: Handle PIC, use rdpc.
+
+	* Revert remaining parts of recent sparc LEA changes.
+
+2013-04-14  David S. Miller  <davem@davemloft.net>
+
+	* mpn/sparc32/v9/sqr_diagonal.asm: Revert LEA and INT32 changes.
+	* mpn/sparc64/gcd_1.asm: Likewise.
+
+2013-04-13  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/bd1/tabselect.asm: New file.
+	* mpn/x86_64/coreisbr/tabselect.asm: New file.
+	* mpn/x86_64/k10/tabselect.asm: New file.
+	* mpn/x86_64/coreinhm/tabselect.asm: New file.
+	* mpn/x86_64/core2/tabselect.asm: New file.
+	* mpn/x86_64/pentium4/tabselect.asm: New file.
+
+	* mpn/x86_64/fastsse/tabselect.asm: New file.
+	* mpn/arm/neon/tabselect.asm: Rewrite.
+	* mpn/arm/tabselect.asm: Rewrite.
+	* mpn/powerpc64/tabselect.asm: Rewrite.
+	* mpn/x86_64/tabselect.asm: Rewrite.
+
+	* tune/speed.h (SPEED_ROUTINE_MPN_TABSELECT): Implement special code,
+	making .r argument be table width.
+
+2013-04-11  David S. Miller  <davem@davemloft.net>
+
+	* mpn/sparc32/sparc-defs.m4 (LEA): Remove unused local label.
+	(LEA_LEAF): Likewise.
+
+2013-04-11  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/arm/v6/submul_1.asm: New file, using the corresponding
+	addmul_1 loop + complement trick.
+
+2013-04-10  David S. Miller  <davem@davemloft.net>
+
+	* acinclude.m4 (GMP_ASM_SPARC_GOTDATA,
+	GMP_ASM_SPARC_SHARED_THUNKS): New feature tests.
+	* configure.ac: Call GMP_ASM_SPARC_GOTDATA and
+	GMP_ASM_SPARC_SHARED_THUNKS on sparc.
+	* mpn/sparc32/sparc-defs.m4 (LEA, LEA_LEAF, LEA_THUNK): New macros.
+	* mpn/sparc32/udiv.asm: Convert over to LEA, LEA_LEAF, and LEA_THUNK.
+	* mpn/sparc32/v8/addmul_1.asm: Likewise.
+	* mpn/sparc32/v8/mul_1.asm: Likewise.
+	* mpn/sparc32/v8/supersparc/udiv.asm: Likewise.
+	* mpn/sparc32/v8/udiv.asm: Likewise.
+	* mpn/sparc64/gcd_1.asm: Likewise.
+	* mpn/sparc64/ultrasparct3/dive_1.asm: Likewise.
+	* mpn/sparc64/ultrasparct3/invert_limb.asm: Likewise.
+	* mpn/sparc64/ultrasparct3/mode1o.asm: Likewise.
+	* mpn/sparc32/v9/sqr_diagonal.asm: Likewise and use INT32.
+
+2013-04-09  Torbjorn Granlund  <tege@gmplib.org>
+
+	* longlong.h (sparc64): Test __VIS__ instead of __sparc_vis3.
+
+	* config.guess (sparc*): Invoke set_cc_for_build to get $dummy.
+
+2013-04-08  Torbjorn Granlund  <tege@gmplib.org>
+
+	* config.guess: Rework tmp file names, make sure to remove tmp files.
+
+	* mpn/arm/dive_1.asm: Rewrite count-trailing-zeros code, using private
+	table.
+
+	* mpn/arm: Canonicalise arm assembly to use old style "mov ... lsl" for
+	shift ops.
+
+2013-04-07  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/sparc64/ultrasparct3/mod_34lsub1.asm: New file.
+
+	* longlong.h (sparc64): Define umul_ppmm, add_ssaaaa, and
+	count_leading_zeros conditionally under the symbol __sparc_vis3.
+
+	* mpn/arm/dive_1.asm: New file.
+	* mpn/arm/v6/dive_1.asm: New file.
+
+	* mpn/arm/v6t2/mode1o.asm: Make trivial change to avoid v6t2...
+	* mpn/arm/v6/mode1o.asm: ...instruction, move file accordingly.
+
+	* mpn/powerpc64/mode64/invert_limb.asm: Put all multiplies low-limb first.
+
+2013-04-04  David S. Miller  <davem@davemloft.net>
+
+	* mpn/sparc64/ultrasparct3/add_n.asm: Rewrite.
+	* mpn/sparc64/ultrasparct3/sub_n.asm: Rewrite.
+
+	* mpn/sparc64/ultrasparct3/invert_limb.asm: Align table.
+
+2013-04-04  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/sparc32/sparc-defs.m4: Provide dummy lzcnt.
+
+	* tests/mpn/logic.c: Seed using RANDS, then use mpz_rrandomb.
+
+	* tests/mpn/t-div.c (random_word): Remove.  Let callers invoke urandom.
+
+	* mpn/sparc64/ultrasparct3/mul_1.asm: Rewrite.
+
+	* mpn/sparc64/ultrasparct3/bdiv_dbm1c.asm: New file.
+	* mpn/sparc64/ultrasparct3/dive_1.asm: New file.
+	* mpn/sparc64/ultrasparct3/invert_limb.asm: New file.
+	* mpn/sparc64/ultrasparct3/mod_1_4.asm: New file.
+	* mpn/sparc64/ultrasparct3/mode1o.asm: New file.
+
+2013-04-03  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/sparc64/ultrasparct3/aormul_2.asm: Reschedule for better speed.
+
+2013-04-02  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/sparc64/ultrasparct3/missing.m4: Misc tweaks.
+	 (lzcnt): New.
+	* mpn/sparc64/ultrasparct3/missing.asm (__gmpn_lzcnt): New function.
+
+	* mpn/sparc32/sparc-defs.m4: Put FAKE_T3 stuff here...
+	* mpn/sparc64/ultrasparct3/aormul_2.asm: ...moved from here.
+
+	* mpn/sparc64/ultrasparc1234/lshift.asm: Remove.
+	* mpn/sparc64/ultrasparc1234/rshift.asm: Remove.
+
+2013-04-01  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/sparc64/ultrasparct3/missing.m4 (umulxhi): Don't clobber retaddr,
+	allowing use in functions that does not do save/restore.
+
+	* mpn/sparc64/gcd_1.asm: Tweak for tighter loop.
+
+2013-03-31  David S. Miller  <davem@davemloft.net>
+
+	* mpn/sparc64/lshift.asm: New file.
+	* mpn/sparc64/rshift.asm: New file.
+	* mpn/sparc64/lshiftc.asm: New file.
+
+2013-03-31  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/sparc64/ultrasparct1/lshift.asm: Remove.
+	* mpn/sparc64/ultrasparct1/rshift.asm: Remove.
+	* mpn/sparc64/ultrasparct1/lshiftc.asm: Remove.
+
+2013-03-29  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/sparc64/ultrasparct3/aormul_2.asm: Always do mulx before umulxhi.
+
+2013-03-28  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/sparc64/mod_1_4.c (mpn_mod_1s_4p): Make precomputed arg 'const'.
+	(mpn_mod_1s_4p_cps): Update from generic code.
+
+2013-03-27  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/trialdiv.c: Make variables 'const' to match tables.
+
+	* mpn/generic/mod_1_1.c (mpn_mod_1_1p): Make precomputed arg 'const'.
+	* mpn/generic/mod_1_2.c (mpn_mod_1s_2p): Likewise.
+	* mpn/generic/mod_1_3.c (mpn_mod_1s_3p): Likewise.
+	* mpn/generic/mod_1_4.c (mpn_mod_1s_4p): Likewise.
+	* gmp-impl.h: Update prototypes.
+
+	* mpn/x86_64/mulx/aorsmul_1.asm: New file.
+	* mpn/x86_64/mulx/addmul_1.asm: Remove.
+
+2013-03-26  Niels Möller  <nisse@lysator.liu.se>
+
+	Make mpn_cnd_add_n and mpn_cnd_sub_n public.
+	* doc/gmp.texi (Low-level Functions): Document mpn_cnd_add_n and
+	mpn_cnd_sub_n.
+	* gmp-h.in (mpn_cnd_add_n, mpn_cnd_sub_n): Moved prototypes
+	here...
+	* gmp-impl.h: ... from here.
+
+2013-03-26  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86/pentium4/sse2/cnd_add_n.asm: New file.
+	* mpn/x86/pentium4/sse2/cnd_sub_n.asm: New file.
+	* mpn/x86/cnd_aors_n.asm: New file.
+
+2013-03-25  David S. Miller  <davem@davemloft.net>
+
+	* mpn/sparc64/ultrasparct3/hamdist.asm: New file.
+	* mpn/sparc64/ultrasparct3/popcount.asm: New file.
+
+2013-03-25  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/ia64/aorsorrlshC_n.asm: Generalised from aorslshC_n.asm.
+	* mpn/ia64/aorsorrlsh1_n.asm: Generalised from aorslsh1_n.asm.
+	* mpn/ia64/aorsorrlsh2_n.asm: Generalised from aorslsh2_n.asm.
+
+2013-03-24  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/arm/v7a/cora15/neon/aorsorrlshC_n.asm: New file.
+	* mpn/arm/v7a/cora15/neon/aorsorrlsh2_n.asm: New file.
+	* mpn/arm/v7a/cora15/neon/aorsorrlsh1_n.asm: New file.
+	* mpn/arm/v7a/cora15/neon/rsh1aors_n.asm: New file.
+
+	* configure.ac (GMP_MULFUNC_CHOICES): Support add+sub+rsb lsh files.
+
+	* tests/refmpn.c (refmpn_addlsh_nc, refmpn_sublsh_nc): Remove silly
+	assert of mp_limb being non-negative.
+
+2013-03-21  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/arm/neon/lshiftc.asm: New file.
+
+	* mpn/arm/v6/sqr_basecase.asm: Trim 'sqr_diag_addlsh1' loop.
+
+	* gen-trialdivtab.c: Output just raw data, remove actual variables.
+	* mpn/generic/trialdiv.c: Put variables from gen-trialdivtab.c here,
+	and make them 'const'.
+
+2013-03-20  Torbjorn Granlund  <tege@gmplib.org>
+
+	* config.guess: Rework arm CPU recognition.
+	* config.sub: Corresponding updates.
+	* configure.ac: Likewise.
+
+	* mpn/x86_64/mulx/adx/addmul_1.asm: Let FAKE_MULXADX be off by default.
+
+	* mpn/arm/v7a/cora15/neon/copyi.asm: Move from "..".
+	* mpn/arm/v7a/cora15/neon/copyd.asm: Likewise.
+
+	* config.guess: Tack on "neon" for appropriate arm CPUs.
+	* configure.ac (arm*-*-*): Recognise neon suffix for a8, a9, and a15.
+
+2013-03-19 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpf/fits_u.h: Accept numbers truncating to zero before checking the
+	sign.
+	* tests/mpf/t-fits.c: Check new edges.
+
+2013-03-19  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/arm32check.c: Get printing of clobbered register right.
+
+	* mpn/arm/neon/popcount.asm: New file.
+	* mpn/arm/neon/hamdist.asm: New file.
+
+	* tests/Makefile.am (EXTRA_libtests_la_SOURCES): Add arm32call.asm and
+	arm32check.c.
+
+2013-03-18  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.ac (arm*-*-*): Define CALLING_CONVENTIONS_OBJS.
+
+	* tests/arm32call.asm: New file.
+	* tests/arm32check.c: New file.
+
+	* mpn/arm/arm-defs.m4 (LEA): Rewrite to properly handle repeated use.
+	(EPILOGUE_cpu): Define.
+
+	* mpn/arm/v6/addmul_3.asm: Make code work for PIC.
+
+	* tests/x86call.asm: Modernise asm syntax.
+	* tests/amd64call.asm: Likewise.
+
+	* mpn/x86/darwin.m4 (m4append): Move definition from here...
+	* mpn/asm-defs.m4: ...to here.
+
+2013-03-18 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* doc/gmp.texi (--enable-fat): No quote in concept index.
+
+	* mpf/swap.c: Reduce the number of variables.
+
+2012-03-17  Marc Glisse  <marc.glisse@inria.fr>
+
+	* tests/cxx/t-do-exceptions-work-at-all-with-this-compiler.cc: New file.
+	* tests/cxx/Makefile.am: Add new file. Reorder the tests.
+
+2013-03-17  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/mul_fft.c: Use TMP_BALLOC*, but combine several areas.
+
+	* mpz/powm_ui.c (mod): Use TMP_BALLOC in mu code.
+
+	* mpn/arm/v6/addmul_3.asm: New file.
+
+	* mpn/arm/v7a/cora15/copyd.asm: Tweak.
+
+	* mpn/arm64/copyi.asm: New file.
+	* mpn/arm64/copyd.asm: New file.
+
+2013-03-16  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/arm/v6/addmul_2.asm: Tweak for better A9 performance.
+
+2013-03-14  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/ia64/cnd_aors_n.asm: New file.
+
+	* mpn/arm64/cnd_aors_n.asm: New file.
+
+	* mpn/arm64/aors_n.asm (ADDSUB): Remove unused definition.
+
+	* mpn/ia64/aors_n.asm: Remove a redundant ASM_START.
+
+	* mpn/arm/cnd_aors_n.asm: Avoid ARM conditional insn execution.
+
+	* mpn/x86_64/missing.asm: Move from mulx/adx since we cannot currently
+	prune missing.asm from path.
+	* mpn/x86_64/mulx/adx/missing-call.m4: Likewise.
+	* mpn/x86_64/mulx/adx/missing-inline.m4: Likewise.
+	* mpn/x86_64/mulx/adx/addmul_1.asm: Update hardwired path.
+
+2013-03-13 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpz/cong_2exp.c: Write loops in a cleaner way.
+	* gmp-impl.h (mpz_zero_p): Likewise.
+
+2013-03-12  Niels Möller  <nisse@lysator.liu.se>
+
+	New names mpn_cnd_add_n and mpn_cnd_sub_n.
+	* mpn/generic/cnd_add_n.c (mpn_cnd_add_n): Renamed file and
+	function, from addcnd.c:mpn_addcnd_n.
+	* mpn/generic/cnd_sub_n.c (mpn_cnd_sub_n): Renamed, from
+	subcnd.c:mpn_subcnd_n.
+	* mpn/arm/cnd_aors_n.asm: Renamed file, from aorscnd.asm, and
+	renamed functions.
+	* mpn/x86_64/cnd_aors_n.asm: Analogous renaming.
+	* mpn/powerpc64/mode64/cnd_aors_n.asm: Analogous renaming.
+	* gmp-impl.h (mpn_cnd_add_n, mpn_cnd_add_n): Updated prototypes
+	with new names.
+	* configure.ac: Updated for new names.
+	* tests/refmpn.c (refmpn_cnd_add_n): Renamed, from refmpn_addcnd_n.
+	(refmpn_cnd_sub_n): Renamed, from refmpn_subcnd_n.
+	* tests/tests.h (refmpn_cnd_add_n, refmpn_cnd_sub_n): Updated
+	prototypes with new names.
+	* tune/common.c (speed_mpn_cnd_add_n): Renamed, from
+	speed_mpn_addcnd_n, call mpn_cnd_add_n.
+	(speed_mpn_cnd_sub_n): Renamed, from speed_mpn_subcnd_n, call
+	mpn_cnd_sub_n.
+	* tune/speed.h (speed_mpn_cnd_add_n, speed_mpn_cnd_sub_n): Updated
+	prototypes with new names.
+	* tune/speed.c (routine): Updated list with new names.
+	* tests/devel/try.c: Updated for new mpn_cnd_* names.
+	* mpn/generic/sbpi1_div_sec.c: Likewise.
+	* mpn/generic/powm_sec.c: Likewise.
+
+2013-03-12  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.ac: Add "missing" to extra_functions_64 for coreibwl.
+
+	* mpn/x86_64/mulx/adx/addmul_1.asm: Simplify.  Make FAKE_MULXADX the
+	default awaiting proper qemu behaviour.
+
+2013-03-11  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/aorscnd_n.asm: Read 32 bits for 'n' arguments on DOS64.
+
+	* tests/mpz/t-powm_ui.c: Test larger arguments.  General cleanup.
+
+	* mpz/powm_ui.c (mod): Adhere to mpn_mu_div_qr's overlap requirements.
+
+2013-03-10  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/sbpi1_div_sec.c: Update calls of mpn_addcnd_n and
+	mpn_subcnd_n.
+	* mpn/generic/powm_sec.c (MPN_REDC_1_SEC, MPN_REDC_2_SEC)
+	(mpn_powm_sec): Update calls of mpn_subcnd_n.
+
+	* tests/tests.h (refmpn_addcnd_n, refmpn_subcnd_n): Update
+	declarations.
+	* tests/refmpn.c (refmpn_addcnd_n, refmpn_subcnd_n): Similar
+	reorder of arguments.
+	* tests/devel/try.c (call): Pass condition first, for
+	TYPE_ADDCND_N and TYPE_SUBCND_N.
+
+	* tune/common.c (speed_mpn_addcnd_n, speed_mpn_subcnd_n): Update
+	to pass condition as first argument.
+
+	* gmp-impl.h (mpn_addcnd_n, mpn_subcnd_n): Updated declarations.
+
+	* mpn/generic/addcnd_n.c (mpn_addcnd_n): Reordered arguments, make
+	condition the first argument.
+	* mpn/generic/subcnd_n.c (mpn_subcnd_n): Likewise.
+	* mpn/arm/aorscnd_n.asm: Likewise.
+	* mpn/x86_64/aorscnd_n.asm: Likewise.
+	* mpn/powerpc64/mode64/aorscnd_n.asm: Likewise.
+
+2013-03-10  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/mulx/adx/missing.asm: Simulate some mulx/adx insns.
+	* mpn/x86_64/mulx/adx/missing-call.m4: Call variant.
+	* mpn/x86_64/mulx/adx/missing-inline.m4: Inline variant.
+
+	* mpn/sparc64/ultrasparct3/missing.asm: Simulate some v9-2011 insns.
+	* mpn/sparc64/ultrasparct3/missing.m4: Inline or invoke missing.asm for
+	v9-2011 insn.
+
+	* configure.ac: Strip `haswell' from paths for now.
+
+	* mpn/x86_64/mulx/addmul_1.asm: New.
+	* mpn/x86_64/mulx/mul_1.asm: Rewrite file from `haswell' subdir.
+	* mpn/x86_64/mulx/adx/addmul_1.asm: Likewise.
+	* mpn/x86_64/haswell: Remove.
+
+	* mpn/arm/v7a/cora15/mul_1.asm: New file.
+	* mpn/arm/v7a/cora15/addmul_1.asm: New file.
+
+2013-03-09 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* tests/mpz/t-cong_2exp.c: Improve coverage.
+
+2013-03-09  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/sparc64/ultrasparc1234/add_n.asm: Use g5 instead of g4.
+	* mpn/sparc64/ultrasparc1234/sub_n.asm: Likewise.
+
+	* mpn/sparc64/ultrasparct3/aormul_2.asm: Fix a typo.
+
+2013-03-07  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/arm/v7a/cora9/gmp-mparam.h: New file.
+
+	* configure.ac (GMP_MULFUNC_CHOICES): Support mul_2 + addmul_2.
+
+	* mpn/sparc64/ultrasparct3/aormul_2.asm: New file.
+
+	* mpn/sparc64/ultrasparct3/submul_1.asm: Optimise out two carry
+	propagating adds.
+
+2013-03-06  David Miller  <davem@davemloft.net>
+
+	* config.guess: Recognize UltraSparc T4 under Linux.
+	* configure.ac: Add sparc64/ultrasparct3 to path_64 when T3 or T4.
+	Append -xarch=v8plusd or -xarch=v9d to command line, as needed.
+	* mpn/sparc64/ultrasparct3/mul_1.asm: New file.
+	* mpn/sparc64/ultrasparct3/addmul_1.asm: New file.
+	* mpn/sparc64/ultrasparct3/submul_1.asm: New file.
+	* mpn/sparc64/ultrasparct3/add_n.asm: New file.
+	* mpn/sparc64/ultrasparct3/sub_n.asm: New file.
+
+	* mpn/sparc32/ultrasparct1/mul_1.asm: Unroll main loop one time, add
+	T2/T3/T4 timings.
+	* mpn/sparc32/ultrasparct1/addmul_1.asm: Likewise.
+	* mpn/sparc32/ultrasparct1/submul_1.asm: Likewise.
+
+2013-03-04  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/arm/neon/lorrshift.asm: New file.
+
+2013-03-03  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/arm/v7a/cora15/copyd.asm: New file.
+	* mpn/arm/v7a/cora15/copyi.asm: New file.
+
+	* mpn/arm64/logops_n.asm: New file.
+	* mpn/arm64/gcd_1.asm: New file.
+	* mpn/arm64/aorsmul_1.asm: New file.
+	* mpn/arm64/addmul_1.asm: Remove.
+	* mpn/arm64/aors_n.asm: Complete rewrite.
+
+	* mpn/arm/tabselect.asm: New file.
+	* mpn/arm/neon/tabselect.asm: New file.
+
+	* mpn/arm/copyi.asm: Software pipeline.
+	* mpn/arm/copyd.asm: Likewise.
+
+	* config.guess: Rework tmp file handling to resemble configfsf.guess's.
+
+2013-03-03  Niels Möller  <nisse@lysator.liu.se>
+
+	* doc/gmp.texi (Integer Special Functions): Document
+	mpz_limbs_read, mpz_limbs_write, mpz_limbs_modify,
+	mpz_limbs_finish, mpz_roinit_n and MPZ_ROINIT_N.
+
+	* mpz/roinit_n.c (mpz_roinit_n): Normalize the input.
+
+2013-02-27  Niels Möller  <nisse@lysator.liu.se>
+
+	* tune/common.c (speed_measure): Increase repetition count if we
+	get a zero measurement.
+
+2013-02-26  Niels Möller  <nisse@lysator.liu.se>
+
+	* tests/mpz/t-limbs.c (check_roinit): Test MPZ_ROINIT_N only if
+	compiler supports c99.
+
+2013-02-25  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpz/limbs_finish.c (mpz_limbs_finish): New file and function.
+	* mpz/limbs_modify.c (mpz_limbs_modify): New file and function.
+	* mpz/limbs_read.c (mpz_limbs_read): New file and function.
+	* mpz/limbs_write.c (mpz_limbs_write): New file and function.
+	* mpz/roinit_n.c (mpz_roinit_n): New file and function.
+	* gmp-h.in: Declare new functions.
+	(MPZ_ROINIT_N): New macro.
+	* mpz/Makefile.am (libmpz_la_SOURCES): Added new files.
+	* Makefile.am (MPZ_OBJECTS): Added new object files.
+
+	* tests/mpz/t-limbs.c: New testcase.
+	* tests/mpz/Makefile.am (check_PROGRAMS): Added t-limbs.
+
+2013-02-22  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.ac: Fix typo in adx/mulx path stripping code.
+	* config.sub: Match coreibwl.
+
+2013-02-20  Niels Möller  <nisse@lysator.liu.se>
+
+	* tests/mpq/t-get_d.c (check_random): Rewrote to make test less
+	dependent on float operations. Fixes problem with m68k-linux and
+	extended float precision.
+
+2013-02-20  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/haswell/mulx/adx/addmul_1.asm: New file.
+
+	* configure.ac: Support coreibwl.  Use proper name for ADX extension.
+	* acinclude.m4 (GMP_ASM_X86_ADX): Rename from GMP_ASM_X86_ADOX.
+
+	* tests/tests.h (TESTS_REPS): Keep count >= 1.
+
+2013-02-17 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* gmpxx.h (mpq_class, mpf_class) [init_ui, init_si, assign_si]:
+	Optimise _si using _ui for positive arguments.
+	(__gmp_hypot_function): Use _mul_ui to square an ui, abs for si.
+
+	* mpz/remove.c: Delay allocation in the generic case; use swap
+	instead of set.
+	* mpn/generic/remove.c: Delay (possibly smaller) allocation.
+
+2013-02-17  Marc Glisse  <marc.glisse@inria.fr>
+
+	* cxx/osdoprnti.cc: Use <stdarg.h> and <string.h> rather than <cstdarg>
+	and <cstring> (revert 2002-12-21).
+
+	* tests/cxx/Makefile.am: Link with libm.
+	* tests/cxx/t-ops2.cc: Comment about more tests. Use <math.h> rather
+	than <cmath> and using namespace. Don't include <iostream>.
+
+	* gmpxx.h (__GMPXX_BITS_TO_LIMBS, __GMPQ_NUM_DBL_LIMBS,
+	__GMPQ_DEN_DBL_LIMBS, __GMPXX_TMPQ_D): New macros.
+	(__gmp_binary_plus, __gmp_binary_minus, __gmp_binary_multiplies,
+	__gmp_binary_divides, __gmp_binary_equal, __gmp_binary_less,
+	__gmp_cmp_function): Use __GMPXX_TMPQ_D.
+	* tests/cxx/t-ops2.cc: Test __GMPXX_TMPQ_D on DBL_MIN, DBL_MAX.
+
+	* gmpxx.h (__gmp_binary_multiplies, __gmp_binary_divides): Use
+	__GMPXX_CONSTANT_TRUE.
+
+2013-02-16  Marc Glisse  <marc.glisse@inria.fr>
+
+	* gmpxx.h: Include <algorithm>.
+
+2013-02-16  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/Makefile.am (TARG_DIST): Add arm64.
+
+	* mpn/x86_64/x86_64-defs.m4 (PROTECT): Emit '.hidden' instead of
+	'.protected" to please Sun's assembler, but also for semantic reasons.
+
+2013-02-15  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.ac (arm64*-*-*): Match this.
+
+	* mpn/arm64/aors_n.asm: New file.
+	* mpn/arm64/addmul_1.asm: New file.
+	* mpn/arm64/mul_1.asm: New file.
+
+2013-02-15  Marc Glisse  <marc.glisse@inria.fr>
+
+	* gmpxx.h (__GMPXX_DEFINE_ARITHMETIC_CONSTRUCTORS,
+	__GMPXX_DEFINE_ARITHMETIC_ASSIGNMENTS): New macros.
+	(mpz_class, mpq_class, mpf_class) [init_ui, init_si, init_d,
+	assign_ui, assign_si, assign_d]: New functions.
+	(__gmp_expr::__gmp_expr, __gmp_expr::operator=): Replace with macros.
+	(__GMPXX_CONSTANT_TRUE): New macro.
+
+2013-02-15 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* gmp-impl.h (NEG_CAST, ABS_CAST): Use __GMP_CAST.
+	* mpz/fits_s.h: Use NEG_CAST.
+
+2013-02-14  Marc Glisse  <marc.glisse@inria.fr>
+
+	* gmpxx.h (__gmp_binary_greater): Forward to __gmp_binary_less.
+	(__gmp_binary_equal): Forward to itself after swapping operands.
+
+2013-02-14 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mp_dv_tab.c (__gmp_digit_value_tab): Remove a line of unused values.
+	* mpf/set_str.c: Update offset accordingly.
+	* mpz/inp_str.c: Likewise.
+	* mpz/set_str.c: Likewise.
+
+	* gmp-h.in (mpq_cmp_ui): Optimise comparison with 1/1.
+	* tests/mpq/t-cmp_ui.c: Test special comparisons: 0/1, 1/1.
+
+	* mpz/clrbit.c: Reorganise branches.
+	* mpz/setbit.c: Likewise.
+	* mpz/combit.c: Same micro-optimisations as in set/clr.
+
+	* mpz/aors_ui.h: No realloc if size was zero.
+	* mpz/ior.c: Use macros: MPZ_REALLOC and MPN_INCR_U.
+
+	* gmp-impl.h (NEG_CAST): New macro, used by ABS_CAST.
+	* mpq/cmp_si.c: Use NEG_CAST.
+	* mpz/cmp_si.c: Reorganise branches.
+
+2013-02-13  Torbjorn Granlund  <tege@gmplib.org>
+
+	* acinclude.m4 (GMP_ASM_X86_MULX, GMP_ASM_X86_ADOX): New feature tests.
+	* configure.ac: Use new feature tests.
+
+	* mpn/x86_64/haswell/mulx/mul_1.asm: File moved to cope with older
+	assemblers.
+	* configure.ac: Update haswell path to include "mulx".
+
+2013-02-12  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.ac: Recognise haswell.
+	* config.guess: Recognise haswell.
+	* config.sub: Match haswell.
+
+	* mpn/x86_64/haswell/mul_1.asm: New file, mainly for testing HNI.
+
+2013-02-12 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* gmp-impl.h (MPZ_PROVOKE_REALLOC): Remove unused macro.
+	* gen-fac.c (gen_consts): Remove obsolete code, use swap instead of set.
+
+	* mpn/generic/mulmod_bnm1.c: Reorganise branches.
+
+	* mpz/bin_ui.c: Avoid a copy when n < 0.
+	* mpz/mfac_uiui.c: Reduce memory usage.
+	* mpz/primorial_ui.c: Use MPZ_NEWALLOC.
+
+	* mpz/import.c: Use BITS_TO_LIMBS and MPZ_NEWALLOC.
+	* mpz/inp_raw.c: Likewise.
+	* mpz/rrandomb.c: Likewise.
+	* mpz/urandomb.c: Likewise.
+	* mpn/generic/random2.c: Likewise.
+
+	* mpn/generic/brootinv.c: Micro-optimisation.
+
+	* mpf/set_str.c: Don't chech base==0 when base is strictly positive.
+
+2013-02-10  Torbjorn Granlund  <tege@gmplib.org>
+
+	* Version 5.1.1 released.
+
+2013-02-07 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* tune/speed.h (SPEED_ROUTINE_MPN_MUL): Use operands from struct s.
+	* tune/README: Document new parameter syntax mpn_mul.<#> .
+
+2013-02-06  Niels Möller  <nisse@lysator.liu.se>
+
+	* tests/mpz/t-jac.c (check_large_quotients): Rewrote. Now uses a
+	more efficient method for generating the test inputs.
+
+2013-02-05  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/mpn/t-div.c: Limit random dbits to avoid an infinite loop.
+
+2013-02-03  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/mpz/reuse.c: Fix typo causing the same negation condition to be
+	applied to all operands.  Fix condition for when to invoke mpz_remove.
+	Make different-size random operands.
+
+2013-02-02 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpz/remove.c: Correct the sign in case of reuse.
+
+2013-02-01  Torbjorn Granlund  <tege@gmplib.org>
+
+	* gmp-impl.h (DIGITS_IN_BASE_PER_LIMB): Add a cast.
+	(LIMBS_PER_DIGIT_IN_BASE): Likewise.
+
+	* tests/refmpn.c (refmpn_mul): Use toom6h instead of toom44 for the
+	largest operands.
+
+2013-01-31  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/toom44_mul.c: Revert last change in favour of a simple
+	change (thanks Marco!).
+	* mpn/generic/toom4_sqr.c: Likewise.
+
+2013-01-30  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/toom44_mul.c (MAYBE_mul_toom44): Take toom6h and toom8h
+	into account, using new macro MUL_NEXTALG_THRESHOLD.
+	* mpn/generic/toom4_sqr.c (MAYBE_sqr_toom4): Likewise.
+
+2013-01-26 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpz/remove.c: init+set=init_set, cast before shifting.
+
+	* mpz/cmp_si.c: Use ABS_CAST.
+
+2013-01-26  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/mpn/logic.c: Set things up to always test library logops, not
+	gmp-impl.h's inlined variants.  Test also mpn_com.
+
+	* tests/mpn/t-mod_1.c: Test also mpn_mod_1s_3p.
+
+	* mpn/generic/mod_1_3.c: Swap some lines to make it similar to mod_4.c.
+
+	* tests/mpz/reuse.c: Fix typo in last change.
+
+2013-01-22  Torbjorn Granlund  <tege@gmplib.org>
+
+	* Makefile.am (LIBGMP_LT_*, LIBGMPXX_LT_*): Bump version info.
+	* gmp-h.in: Bump version.
+
+	* tests/mpz/reuse.c: Delete always zero 'failures' and code depending
+	on it.  Replace rotating progress with real measure.
+
+	* Makefile.am (check-mini-gmp): Fix typo in last change.
+
+2013-01-20  Torbjorn Granlund  <tege@gmplib.org>
+
+	* Makefile.am (check-mini-gmp): Set also DYLD_LIBRARY_PATH for the
+	benefit of Darwin.
+
+	* tests/mpn/t-div.c: Test mpn_sb_div_qr_sec and mpn_sb_div_r_sec.
+	(main): Separate divisor into normalised (dnp) and unnormalised (dup),
+	pass appropriate variant to each function.
+	(main): Make negative `test' index value mean divisor bits, for better
+	small operands coverage.
+	(main): Put random junk at qp[] instead of zeroing.
+
+	* tests/mpz/t-remove.c: Back out last change which left `divisor_size'
+	uninitialised; achieve change's aim with a parameter tweak.
+
+2013-01-20  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/memory.c (PTRLIMB): New macro, used for conformant casting.
+
+2013-01-19 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* tests/mpz/t-set_str.c: Check also failing conditions.
+
+	* tests/mpz/t-remove.c: Test removal of 1.
+
+2013-01-18  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/set_str.c (normalization_steps): Eliminate set-but-unused
+	variable.
+
+	* tests/tests.h (TESTS_REPS): Fix printf argument type clashes.
+
+2013-01-15  Torbjorn Granlund  <tege@gmplib.org>
+
+	From Mike Frysinger:
+	* configure.ac: Add x32 ABI for x86_64.
+
+2013-01-14 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* doc/gmp.texi (gmp_version): Remove "was used" repetition.
+	(Upward compatibility): Mention mpn_bdivmod, GMP 4 -> GMP 5.
+
+2013-01-13  Marc Glisse  <marc.glisse@inria.fr>
+
+	* doc/gmp.texi: Let mpn_sqrtrem reference mpn_perfect_square_p instead
+	of mpz_perfect_square_p.
+
+2013-01-10 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpz/export.c: Less restrictive ASSERTs.
+
+2013-01-10  Torbjorn Granlund  <tege@gmplib.org>
+
+	* Makefile.am (check-mini-gmp): Set LD_LIBRARY_PATH to allow testing
+	with dynamic main GMP build.
+
+2013-01-05  Torbjorn Granlund  <tege@gmplib.org>
+
+	* longlong.h (aarch64): Make add_ssaaaa and sub_ddmmss actually work.
+
+2013-01-04  Torbjorn Granlund  <tege@gmplib.org>
+
+	From Marko Lindqvist:
+	* configure.ac: Use AC_CONFIG_HEADERS instead of the obsolete
+	AM_CONFIG_HEADER.
+
+2013-01-02 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* tests/mpz/bit.c: Wider testing for mpz_combit.
+	* tests/mpz/logic.c: Check the -2^n case.
+
+	* mpz/ior.c: Fixed an allocation bug in the -2^n case.
+
+2012-12-31  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/get_d.c: Minor reorg, add vax D code.
+
+	* gmp-impl.h (double_extract): New union type for vax D floats.
+
+	* tests/mpq/t-get_d.c (check_random): Limit exponents on vax.
+
+2012-12-30 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* tests/mpz/bit.c (check_clr_extend): Check _set shrink.
+
+2012-12-29  Torbjorn Granlund  <tege@gmplib.org>
+
+	* demos/calc/calc.c: Remove generated file from repo.
+	* demos/calc/calc.h: Likewise.
+	* demos/calc/calclex.c: Likewise.
+
+2012-12-27  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/get_d.c: Complete rewrite of non-IEEE code.
+
+	* tests/mpq/t-get_d.c (main): Suppress check_random for vax.
+
+2012-12-25  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/bdiv_q_1.asm: Use LEA for binvert_limb_table.
+
+2012-12-23  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/mpz/t-get_d.c (check_onebit): Decrease vax limit to avoid
+	overflow in last, unused 'want' value.
+
+	* config.guess: Recognise AMD family 22 as a future bobcat.
+
+2012-12-21  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.ac: Rename configure.in.
+
+2012-12-17  Torbjorn Granlund  <tege@gmplib.org>
+
+	* Version 5.1.0 released.
+
+	* configure.in (none-*-*): Allow this again, but print a warning.
+
+2012-12-17 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpz/n_pow_ui.c: Fix typos in an ASSERT.
+
+2012-12-16  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/mu_div_qr.c (mpn_preinv_mu_div_qr): Explicitly use
+	MPN_COPY_INCR for slightly overlapping copy.
+
+2012-12-15 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* tests/mpn/toom-sqr-shared.h: Skip ALLOCs if the test is skipped.
+
+2012-12-13  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/dos64.m4 (PIC): Move definition early.
+	(JMPENT): Remove PIC variant.
+
+	* mpn/x86_64/darwin.m4 (JUMPTABSECT): Define to .text, instead of
+	something sensible.
+
+2012-12-12  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/x86_64-defs.m4 (JMPENT): New macro.
+	* mpn/x86_64/dos64.m4: Likewise.
+	* mpn/x86_64/darwin.m4: Likewise.
+	* mpn/x86_64/mod_34lsub1.asm: Use JMPENT to properly support PIC.
+	* mpn/x86_64/mullo_basecase.asm: Likewise.
+	* mpn/x86_64/sqr_basecase.asm: Likewise.
+
+2012-12-11  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/mod_34lsub1.asm: Try different jump table for the benefit
+	of broken Apple linkers.
+
+2012-12-09  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.in: Make GMP_NONSTD_ABI ABI specific.
+
+2012-12-08  Torbjorn Granlund  <tege@gmplib.org>
+
+	* Makefile.am (LIBGMP_LT_*, LIBGMPXX_LT_*): Bump version info.
+	* gmp-h.in: Bump version.
+
+2012-12-06 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* tests/mpq/reuse.c: New test (adapted from mpf/reuse.c).
+	* tests/mpq/Makefile.am (check_PROGRAMS): Add reuse.
+
+	* mpz/abs.c: Use NEWALLOC.
+	* mpz/neg.c: Likewise.
+	* mpz/com.c: Reduce branches.
+
+2012-12-05  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/brootinv.c (mpn_brootinv): Make valgrind happier, at
+	the cost of a redundant MPN_ZERO.
+
+	* mpz/jacobi.c (mpz_jacobi): Check for asize == 0 or bsize == 0
+	before using the low limbs.
+
+2012-12-05  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/set_str.c (mpn_dc_set_str): Work around a valgrind issue.
+
+	* mpz/powm_ui.c: Don't assume >= 2 limbs in mod argument.
+
+	* tests/tests.h (TESTS_REPS): Handle float GMP_CHECK_REPFACTOR.
+
+	* longlong.h: Refine cpp test for vax.
+	* tests/mpn/t-get_d.c: Likewise.
+	* tests/mpz/t-get_d.c: Likewise.
+	* tests/mpz/t-cmp_d.c: Likewise.
+	* tests/mpz/t-get_d.c: Likewise.
+	* tests/mpq/t-get_d.c: Likewise.
+	* tests/mpf/t-get_d.c: Likewise.
+
+2012-11-30  Torbjorn Granlund  <tege@gmplib.org>
+
+	* gen-fac.c (gen_consts): Correct printf types.
+
+	* mpn/arm/v7a/cora15/gmp-mparam.h: New file.
+
+	* configure.in (arm*-*-*): New compiler optional "tune".  Pass value for
+	selected processors.  Add more specific path components.
+
+2012-11-29  Torbjorn Granlund  <tege@gmplib.org>
+
+	From Andoni Morales Alastruey:
+	* longlong.h: Conditionalise ARM asm on !__thumb__.
+
+2012-11-28  Torbjorn Granlund  <tege@gmplib.org>
+
+	* config.guess (arm*-*-*): Support specific ARM processors.
+	* config.sub: Match arm CPUs.
+	* configure.in (arm*-*-*): Likewise.
+
+	* mpz/powm.c: Move new_b out since it lives on through b.
+
+	* configure.in (arm*-*-*): Pass -marm to deal with compilers defaulting
+	to thumb code.
+
+2012-11-26  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/cxx/t-ops2.cc (checkz): Reduce huge numbers to avoid vax
+	overflow.
+
+2012-11-25  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/get_d.c: Reinsert non-IEEE code.
+
+	* mpn/vax/add_n.asm: New file.
+	* mpn/vax/add_n.s: Remove.
+	* mpn/vax/addmul_1.asm: New file.
+	* mpn/vax/addmul_1.s: Remove.
+	* mpn/vax/lshift.asm: New file.
+	* mpn/vax/lshift.s: Remove.
+	* mpn/vax/mul_1.asm: New file.
+	* mpn/vax/mul_1.s: Remove.
+	* mpn/vax/rshift.asm: New file.
+	* mpn/vax/rshift.s: Remove.
+	* mpn/vax/sub_n.asm: New file.
+	* mpn/vax/sub_n.s: Remove.
+	* mpn/vax/submul_1.asm: New file.
+	* mpn/vax/submul_1.s: Remove.
+
+	* mpn/vax/elf.m4: New file.
+	* configure.in (vax*-*-*elf*): New case, grabbing vax/elf.m4.
+
+	* tests/mpn/t-get_d.c (check_onebit): Get vax bounds right.
+	(main): Switch off check_rand for vax.
+
+2012-11-16  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/powm_sec.c (redcify): Use mpn_sb_div_r_sec.
+
+	* mpn/generic/sb_div_sec.c: New file.
+	* mpn/generic/sbpi1_div_sec.c: New file.
+	* configure.in (gmp_mpn_functions): Add new files.
+	* gmp-impl.h: Declare new functions.
+
+2012-11-12  Torbjorn Granlund  <tege@gmplib.org>
+
+	* longlong.h: Add ARM64 support.
+	* longlong.h: Add AVR support.
+
+	* mpn/powerpc64/mode64/divrem_1.asm: Tune, simplify.
+
+	* mpq/md_2exp.c: Use MPN_COPY_INCR, not MPN_COPY_DECR.
+	* tests/mpq/t-md_2exp.c (check_random): New function.
+
+2012-11-10  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/remove.c (mpn_bdiv_qr_wrap): Make static.
+
+2012-11-04  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpz/powm_ui.c: Rewrite.
+
+2012-11-01  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/brootinv.c (mpn_brootinv): Input size in limbs
+	rather than bits. Use single-precision iterations for the first
+	limb.
+	* mpn/generic/perfpow.c (is_kth_power): Update mpn_brootinv call.
+	* tests/mpn/t-brootinv.c (main): Likewise.
+	* tune/speed.h (SPEED_ROUTINE_MPN_BROOTINV): Likewise.
+	* gmp-impl.h (mpn_brootinv): Updated prototype.
+
+	* mpn/generic/hgcd2.c (mpn_hgcd2): Removed redundant loop exit
+	tests in the single-precision loop.
+
+	* mpz/combit.c (mpz_combit): Rewrite, optimizing for the common
+	case.
+
+2012-10-31  Niels Möller  <nisse@lysator.liu.se>
+
+	* tests/mpn/Makefile.am (check_PROGRAMS): Added t-brootinv.
+	* tests/mpn/t-brootinv.c: New file
+
+	* mpn/generic/broot.c (mpn_broot_invm1): Avoid a mullo_n in the
+	loop, and do powering as a plain mpn_sqr followed by mpn_powlo.
+
+	* tune/speed.c (routine): Added mpn_broot, mpn_broot_invm1,
+	mpn_brootinv.
+
+	* tune/common.c (speed_mpn_broot, speed_mpn_broot_invm1)
+	(speed_mpn_brootinv): New functions.
+	* tune/speed.h (SPEED_ROUTINE_MPN_BROOT)
+	(SPEED_ROUTINE_MPN_BROOTINV): New macros.
+
+	* mpn/generic/broot.c (mpn_broot_invm1): Made non-static (mainly
+	for benchmarking).
+	* gmp-impl.h (mpn_broot_invm1): Declare it.
+
+2012-10-28  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.in (gmp_mpn_functions): Add new files.
+	* gmp-impl.h: Declare new functions.
+	* mpn/generic/perfpow.c: Overhaul.
+	(binv_root, binv_sqroot): Remove.
+	* mpn/generic/brootinv.c: New file, code from overhauled binv_root.
+	* mpn/generic/bsqrtinv.c: New file, code from overhauled binv_sqroot.
+	* mpn/generic/bsqrt.c: New file.
+
+	* tests/mpn/t-broot.c: Add a forgotten TMP_MARK.
+
+2012-10-28  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/broot.c (mpn_broot): New file and function.
+	* configure.in (gmp_mpn_functions): Add broot.
+	* gmp-impl.h (mpn_broot): Declare.
+	* tests/mpn/t-broot.c: New testcase.
+	* tests/mpn/Makefile.am (check_PROGRAMS): Added t-broot.
+
+2012-10-27  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/remove.c: Get remainder allocation right.
+
+2012-10-25  Torbjorn Granlund  <tege@gmplib.org>
+
+	* longlong.h: De-support old POWER asm syntax.
+
+	* tests/mpz/t-remove.c: Run more tests, but use a tad smaller operands.
+
+	* mpn/generic/remove.c (mpn_bdiv_qr_wrap): New function.
+	(mpn_remove): Call mpn_bdiv_qr_wrap.
+	* mpz/remove.c: Enable suppressed mpn_remove call.
+
+2012-10-17  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpz/powm_ui.c (mpz_powm_ui): Deflect to mpz_powm for large exponent.
+
+2012-09-10  Torbjorn Granlund  <tege@gmplib.org>
+
+	* demos/factorize.c: Rewrite no more current form.  Implement Lucas
+	prime proving, and make its use the default.
+	* demos/primes.h: New file.
+
+2012-08-24  Torbjorn Granlund  <tege@gmplib.org>
+
+	* demos/factorize.c: Overhaul.
+
+2012-08-06 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* doc/gmp.texi (mpn_neg): Correctly document returned type.
+
+	* gmp-impl.h (_mpz_newalloc, log_n_max): mark with inline (spotted by Niels).
+
+2012-07-28  Marc Glisse  <marc.glisse@inria.fr>
+
+	* gmpxx.h (std::common_type): New partial specializations with builtin
+	types.
+	* tests/cxx/t-cxx11.cc: Test it.
+
+2012-07-21  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/powerpc32/vmx/mod_34lsub1.asm: Fix r0 clobbering issue with
+	"large" code affecting elf+darwin PIC.
+
+2012-07-21  Marc Glisse  <marc.glisse@inria.fr>
+
+	* gmpxx.h (__GMPXX_CONSTANT): Disable for g++-3.4.
+
+2012-06-26  Torbjorn Granlund  <tege@gmplib.org>
+
+	* Makefile.am (LIBMP_LT_*): Remove these.
+
+2012-06-26  Marc Glisse  <marc.glisse@inria.fr>
+
+	* Makefile.am (LIBGMP_LT_*, LIBGMPXX_LT_*): Update comment for 5.1.0.
+
+2012-06-24 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* configure.in (CALLING_CONVENTIONS_OBJS): Disable any use of
+	assembly code with the --disable-assembly option.
+	* mpz/oddfac_1.c: Use the ASSERT_CODE macro.
+	* gen-trialdivtab.c (mpz_log2): Use mpz_sizeinbase (., 2).
+
+	* gmp-impl.h (MPN_SIZEINBASE_16): Replace with MPN_SIZEINBASE_2EXP
+	from mpz/export.c .
+	* mpz/export.c (MPN_SIZEINBASE_2EXP): Removed.
+	* mpn/generic/sizeinbase.c: Use MPN_SIZEINBASE.
+
+	* mpz/nextprime.c: Use MPN_SIZEINBASE_2EXP to count bits.
+	* mpn/generic/perfpow.c: Likewise.
+	* mpn/generic/rootrem.c: Likewise.
+	* mpz/get_d_2exp.c: Likewise.
+	* mpn/generic/powm_sec.c: Likewise, nailify.
+	* mpn/generic/powlo.c: Likewise.
+	* mpn/generic/powm.c: Likewise.
+
+2012-06-23  Marc Glisse  <marc.glisse@inria.fr>
+
+	* gmpxx.h (numeric_limits): Make content public.
+	* cxx/limits.cc: New file, proper declarations.
+	* Makefile.am: List new file.
+	* cxx/Makefile.am: Likewise.
+	* cxx/t-misc.cc: Add minimal test for numeric_limits.
+
+2012-06-09  Marc Glisse  <marc.glisse@inria.fr>
+
+	* gmpxx.h (__gmp_resolve_expr::srcptr_type): New typedef.
+	(__gmp_temp): Wrapper for mp*_class, the constructor copies the
+	precision of its second argument for mpf_t.
+	(__gmp_expr::eval(p, prec)): Remove.
+	(__gmp_expr::eval(p)): Use __gmp_temp.
+	(__gmp_set_expr): Never pass prec to eval().
+
+2012-06-08 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* gmp-impl.h (__GMP_WITHIN_CONFIGURE): Use the same #if as in gmp-h.in.
+	(MPN_NORMALIZE_NOT_ZERO): Tighter ASSERT.
+	(MPZ_NEWALLOC): New macro.
+	* mpq: Use the new macro when possible.
+	* mpz/bin_uiui.c: Likewise.
+	* mpz/oddfac_1.c: Likewise.
+	* mpz/prodlimbs.c: Likewise.
+
+2012-06-04  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/powerpc64/aix.m4 (ASM_START): Claim machine type "any".
+
+2012-06-03  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/gcdext.c (mpn_gcdext): Deleted code for handling
+	impossible case u1 == 0, Simplified test for unlikely case u0 == 0.
+
+2012-06-02  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/arm/lshiftc.asm: New file.
+
+2012-06-01  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/arm/aorslsh1_n.asm: Use cmp/cmn instead of subs/adds in more
+	places.
+
+	* mpz/get_str.c: Don't strip leading zeros since current mpn_get_str
+	won't generate any.  Misc streamlining.
+	* mpz/out_str.c: Analogous changes.
+
+	* tests/mpz/io.c: Use a wider range of bases.
+
+	* tests/mpz/t-cong.c (check_random): Rewrite random generation for
+	exponentially distributed operand sizes.
+
+2012-06-01 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpq: Use more macros and MPZ_REALLOC return value when possible.
+
+	* gmp-impl.h (LIMBS): Removed, was an alias for PTR.
+	* mpz/combit.c: Use PTR and CNST_LIMB.
+
+	* tests/mpn/t-bdiv.c: Test also mpn_bdiv_qr.
+	* mpn/generic/bdiv_qr.c: Add an ASSERT.
+
+	* mpn/generic/remove.c: Add a zero limb to use bdiv_qr...
+
+2012-05-31  Marc Glisse  <marc.glisse@inria.fr>
+
+	* gmpxx.h (mpq_class::mpq_class): Handle mpq_class(0,1).
+	* tests/cxx/t-constr.cc: Test it.
+
+2012-05-30  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64 (FUNC_ENTRY): New name for DOS64_ENTRY.
+	* mpn/x86_64 (FUNC_EXIT): New name for DOS64_EXIT.
+
+2012-05-29 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpz/remove.c: Optimise branches.
+
+	* mpn/generic/toom6h_mul.c: less branches in the LIKELY balanced path.
+	* mpn/generic/toom8h_mul.c: Likewise.
+
+2012-05-29  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/arm/v5/mod_1_1.asm: New file.
+
+2012-05-28  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/gcdext.c (compute_v): Simplified carry handling a
+	bit, reduced stated scratch need from 2n+1 to 2n. Also comment and
+	ASSERT improvements.
+
+2012-05-27  Torbjorn Granlund  <tege@gmplib.org>
+
+	* config.guess: Add new x86 CPUs.
+	* mpn/x86/fat/fat.c: Likewise.
+	* mpn/x86_64/fat/fat.c: Likewise.
+
+2012-05-27 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/x86_64/fat/fat.c: abort iff longmode-capable-bit is turned off.
+
+	* mpn/generic/toom8h_mul.c: mark UNLIKELY branches.
+
+2012-05-26  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpz: Use MPZ_REALLOC return value when possible.
+
+2012-05-25 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpz/scan1.c: Simplify, and add a shortcut for scan1(z, 0).
+
+2012-05-24  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpz/n_pow_ui.c: Cast non-limb count_leading_zeros argument.
+
+2012-05-24 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpz/remove.c: Support negative divisor.
+	* tests/mpz/t-remove.c: Test negative divisor.
+
+2012-05-23  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/mpz/reuse.c: Major rewrite.
+
+2012-05-23 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpz/sqrt.c: Further simplify.
+	* mpz/sqrtrem.c: Likewise.
+
+	* Mark failing branches with UNLIKELY. Many files affected.
+
+2012-05-22  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpz/sqrt.c: Allocate less for overlapping operands, simplify.
+	* mpz/sqrtrem.c: Likewise.
+
+2012-05-21 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/toom8_sqr.c: Reduce branches for recursion.
+	* mpn/generic/toom8h_mul.c: Likewise.
+
+	* tests/mpn/t-toom8h.c: Don't use GMP_NUMB_BITS when not yet defined.
+
+2012-05-20  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/mpz/t-gcd.c: Rewrite.
+
+2012-05-19  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/mpz/t-gcd.c: Generate larger operands for better gcd code
+	coverage; distribute size exponentially.
+
+2012-05-17 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpf/pow_ui.c: Simplify.
+	* tests/mpf/reuse.c (dsi_func): Exercise pow_ui.
+
+	* tests/mpf/t-set_ui.c (check_data): LONG_HIGHBIT -> ULONG_HIGHBIT.
+	* tests/mpf/t-set.c (check_random): New check, both set and init_set.
+
+	* tests/cxx/t-ops.cc (check_mpq): Check squaring.
+	* tests/mpq/t-equal.c (check_various): Check different den-size.
+
+	* mpn/generic/mullo_n.c: Disable MAYBE_ if WANT_FAT_BINARY.
+	* mpz/cmpabs_d.c: Remove an unused branch.
+
+	* tests/mpz/t-get_d_2exp.c (check_zero): New check.
+	* tests/mpz/t-inp_str.c: A few more cases.
+	* tests/mpz/t-cmp_d.c: More bases and symbols, a few cases.
+
+	* mpz/rootrem.c: Correctly handle odd roots of negatives.
+	* tests/mpz/t-root.c: Test it.
+
+2012-05-16  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/mpf/t-eq.c (check_random): New function, meat from old main().
+	(check_data): New function.
+
+2012-05-13  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/arm/rsh1aors_n.asm: New file.
+	* mpn/arm/v5/mod_1_2.asm: New file.
+
+2012-05-11  Marc Glisse  <marc.glisse@inria.fr>
+
+	* gmpxx.h (explicit operator bool): New functions.
+	* tests/cxx/t-cxx11.cc: Test the above.
+
+2012-05-10 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* gmp-impl.h (__gmpn_cpuvec_initialized): Was __gmpn_cpuvec.initialized
+	* mpn/x86/fat/fat.c: Use separated _initialized variable.
+	* mpn/x86_64/fat/fat.c: Likewise.
+	* tests/mpn/t-fat.c: Likewise.
+
+	* mpn/generic/toom2_sqr.c: Override global __gmpn_cpuvec_initialized.
+	* mpn/generic/toom22_mul.c: Likewise.
+	* mpn/generic/toom3_sqr.c: Likewise.
+	* mpn/generic/toom33_mul.c: Likewise.
+
+2012-05-09 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/sqrtrem.c (invsqrttab): Reduce size removing common byte.
+
+	* mpz/bin_uiui.c (mul3, mul4, mul8): Remove unneeded shifts.
+	(MAXFACS): Redefine, using the shared (safer) log_n_max.
+
+2012-05-08  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/minithres/gmp-mparam.h (REDC_1_TO_REDC_N_THRESHOLD): Up to 9, for
+	coherency with ASSERT in mpn/generic/redc_n.c.
+
+2012-05-07 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/minithres/gmp-mparam.h: Updated TOOM6 and FAC_DSC.
+	* tests/mpn/toom-sqr-shared.h: Don't test if no range.
+
+	* mpz/oddfac_1.c: Add ASSERTs to warn about small threshold.
+	* tune/tuneup.c: Update minimal threshold for FAC_DSC.
+
+2012-05-06  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/arm/v6/sqr_basecase.asm: Simplify n=4 code.
+
+2012-05-05 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/invert.c: Mark a branch UNLIKELY.
+	* tune/tuneup.c (tune_fac_u): Update DSC_THRESHOLD minimum.
+	* gmp-impl.h (FAC_???_THRESHOLD): Update default values.
+	(ABOVE_THRESHOLD): New definition with __builtin_constant_p.
+
+	* mpn/generic/toom22_mul.c: Disable MAYBE_ if WANT_FAT_BINARY.
+	* mpn/generic/toom33_mul.c: Likewise.
+	* mpn/generic/toom2_sqr.c: Likewise.
+	* mpn/generic/toom3_sqr.c: Likewise.
+
+2012-05-04  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tune/tuneup.c: Measure POWM_SEC_TABLE after the REDC thresholds.
+
+2012-05-03  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/powm_sec.c: Use redc_2.
+	(INNERLOOP): Use this mechanism, like plain powm.c.
+	(WANT_CACHE_SECURITY): Remove, feature now unconditional.
+
+2012-05-02  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpz/bin_uiui.c: Make use of CNST_LIMB.
+
+2012-05-02 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpz/mfac_uiui.c: Support limb != ui.
+
+2012-05-02  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/arm/logops_n.asm: Work around register clobbering issue.
+
+	* mpn/arm/aorscnd_n.asm: New file.
+
+2012-05-01  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.in: Put arm dirs in path in proper prio order.
+
+	* mpn/arm/logops_n.asm: New file.
+
+	* mpz/2fac_ui.c: Fix assumed typo.
+
+	* mpn/arm/v6/gmp-mparam.h: New file.
+
+	* mpn/arm/v5/gcd_1.asm: Hack for undefined BMOD_1_TO_MOD_1_THRESHOLD.
+	* mpn/arm/v6t2/gcd_1.asm: Likewise.
+
+2012-04-30  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/arm/v6/sqr_basecase.asm: New file.
+
+2012-04-30 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/comb_tables.c: New file.
+	* configure.in: Add it.
+	* gen-fac.c: Define table limits.
+	* gmp-impl.h: Declare tables.
+	(log_n_max): New static function.
+	* mpz/2fac_ui.c: Use shared tables.
+	* mpz/bin_uiui.c: Likewise.
+	* mpz/oddfac_1.c: Likewise.
+	* mpz/primorial_ui.c: Likewise.
+
+	* mpz/mfac_uiui.c: New file.
+	* Makefile.am: Compile it.
+	* mpz/Makefile.am (libmpz_la_SOURCES): Add mpz_mfac_uiui.c
+	* gmp-h.in (mpz_mfac_uiui): Declare.
+
+	* tests/mpz/t-mfac_uiui.c: New file.
+	* tests/mpz/Makefile.am: Run it.
+
+	* doc/gmp.texi: Document mpz_mfac_uiui, collapsing with other factorial functions.
+
+	* tests/mpz/t-lcm.c: Test zero too.
+
+	* mpz/prodlimbs.c: Simplify threshold (should be tuned, not guessed).
+
+2012-04-29  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/arm/aors_n.asm: Tune for more stable performance.
+
+	* mpn/arm/aorslsh1_n.asm: New file.
+
+	* mpn/arm/mod_34lsub1.asm: New file.
+
+	* mpn/arm/v6t2/divrem_1.asm: New file.
+
+2012-04-28  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/thumb/add_n.asm: New file.
+	* mpn/thumb/sub_n.asm: New file.
+	* mpn/thumb/add_n.s: Remove broken code.
+	* mpn/thumb/sub_n.s: Likewise.
+
+	* mpn/arm/v6/addmul_1.asm: Rewrite for stable speed, smaller size.
+	* mpn/arm/v6/mul_1.asm: Likewise.
+
+2012-04-27  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.in: Search arm/v6t2 for arm7.
+
+	* mpn/arm/v5/gcd_1.asm: New file.
+	* mpn/arm/v6t2/gcd_1.asm: New file.
+
+	* mpn/arm/mode1o.asm: New file.
+	* mpn/arm/v6t2/mode1o.asm: New file.
+
+	* mpn/arm/arm-defs.m4 (LEA): New define.
+	* mpn/arm/invert_limb.asm: Use LEA.
+
+2012-04-26 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpz/bin_uiui.c (bc_bin_uiui): Nail support.
+	* tests/cxx/t-ops2.cc: Test 0/3.
+	* oddfac_1.c: assume n > 26.
+	* tests/mpz/t-jac.c (mpn_jacobi_n): Enlarge tested sizes.
+
+2012-04-24  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/arm/v6/addmul_2.asm: New file.
+	* mpn/arm/v6/mul_2.asm: New file.
+
+2012-04-23  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/arm/aorsmul_1.asm: Tweak loop control for a 6% speed increase.
+
+2012-04-22  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.in: Recognise ARM sub-architectures.
+
+	* configfsf.guess: Update to current FSF version.
+	* configfsf.sub: Likewise.
+
+	* mpn/arm/bdiv_dbm1c.asm: New file.
+
+	* mpn/arm/v6/mul_1.asm: New file.
+	* mpn/arm/v6/addmul_1.asm: New file.
+
+2012-04-22 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* gen-fac.c: Renamed, was gen-fac_ui.c .
+	* Makefile.am: Renamed gen-fac.c and fac_table.h .
+	* gmp-impl.h: #include "fac_table.h".
+	* mpz/oddfac_1.c: Use generated constant.
+	* mpz/bin_ui.c: Small optimisations.
+
+	* tune/common.c (speed_mpz_bin_ui): New function.
+	* tune/speed.h: Declare it.
+	* tune/speed.c: Use it.
+
+2012-04-21  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/arm/mul_1.asm: Cleanup.
+	* mpn/arm/copyi.asm: Cleanup, assume allocate-on-write cache.
+	* mpn/arm/copyd.asm: Likewise.
+
+	* mpn/arm/add_n.asm: Delete.
+	* mpn/arm/sub_n.asm: Delete.
+	* mpn/arm/aors_n.asm: New file, made from old files.
+
+	* mpn/arm/addmul_1.asm: Delete.
+	* mpn/arm/submul_1.asm: Delete.
+	* mpn/arm/aorsmul_1.asm: New file, made from old files.
+
+	* mpn/arm/com.asm: New file.
+	* mpn/arm/lshift.asm: New file.
+	* mpn/arm/rshift.asm: New file.
+
+2012-04-20  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/mpq/io.c: New file.
+	* tests/mpq/Makefile.am: Run it.
+
+	* mpz/clrbit.c: Simplify along the lines of setbit.c.
+
+2012-04-20 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpz/setbit.c: Simplify.
+
+	* gmp-impl.h (LOG2C): Define.
+	* mpz/fac_ui.c (LOG2C): Remove.
+	* mpz/2fac_ui.c (LOG2C): Remove.
+	* mpz/oddfac_1.c (LOG2C): Remove.
+	* mpn/generic/binvert.c (LOG2C): Remove.
+	* mpn/generic/invertappr.c (LOG2C): Remove.
+
+	* mpz/bin_uiui.c (mpz_goetgheluck_bin_uiui): Move declarations,
+	and assume that n and k are not small.
+
+2012-04-19  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/mpz/Makefile.am (check_PROGRAMS): Add t-remove.
+
+	* tests/mpz/t-remove.c: Clear out mpz variables.
+
+	* tests/mpz/t-cong.c (check_random): Use much larger numbers.
+	(check_data): Check congruences mod 0.
+
+	* tests/mpz/t-divis.c: Test divisibility by zero.
+
+	* tests/mpz/reuse.c: Test mpz_mod.
+
+	* mpz/setbit.c: Remove dead code.  Use CNST_LIMB.
+	* mpz/clrbit.c: Use CNST_LIMB.
+
+2012-04-19 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* primesieve.c: New file, with functions from mpz/oddfac_1.c .
+	* mpz/oddfac_1.c (bitwise_primesieve): Re-moved.
+	* Makefile.am (libgmp_la_SOURCES): Add primesieve.c .
+	* gmp-impl.h (gmp_primesieve): Declare.
+
+	* mpz/bin_uiui.c (mpz_goetgheluck_bin_uiui): New, factor-based
+	implementation.
+	* tests/mpz/t-bin.c: Extend tests, to cover _goetgheluck.
+
+	* mpz/primorial_ui.c: New file.
+	* mpz/Makefile.am (libmpz_la_SOURCES): Add mpz/primorial_ui.c
+	* Makefile.am (MPZ_OBJECTS): Add mpz/primorial_ui$U.lo
+	* gmp-h.in (mpz_primorial_ui): Declare.
+	* tests/mpz/t-primorial_ui.c: New test for the new function.
+	* tests/mpz/Makefile.am (check_PROGRAMS): Add t-primorial_ui.
+	* doc/gmp.texi: Short documentation for the new function.
+
+2012-04-17  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/coreisbr/aorsmul_1.asm: Fix some DOS64 issues.
+	* mpn/x86_64/coreisbr/mul_1.asm: Likewise.
+
+	* mpn/x86_64/fastsse/lshiftc-movdqu2.asm: Adhere to DOS64 register
+	partitioning rules.
+
+	* mpn/x86_64/fastsse/copyi-palignr.asm: Implement temporary workaround
+	to overlap issue.
+
+2012-04-17 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpz/bin_uiui.c: Support small limbs (fallback on bin_ui).
+
+	* tests/mpn/toom-sqr-shared.h: Use a restricted range.
+	* tests/mpn/t-toom2-sqr.c: Specify correct range.
+	* tests/mpn/t-toom3-sqr.c: Likewise.
+	* tests/mpn/t-toom4-sqr.c: Likewise.
+	* tests/mpn/t-toom6-sqr.c: Likewise.
+	* tests/mpn/t-toom8-sqr.c: Likewise, but extended.
+	* tests/mpn/Makefile.am (check_PROGRAMS): Add t-toom?-sqr tests.
+
+	* mpn/generic/sbpi1_bdiv_q.c: Move ASSERTs, to support qp = np.
+
+2012-04-17  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/copyd.asm: Rewrite.
+	* mpn/x86_64/copyi.asm: Rewrite.
+
+2012-04-16  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/fastsse/lshift-movdqu2.asm: Add DOS entry/exit sequences.
+	* mpn/x86_64/fastsse/rshift-movdqu2.asm: Likewise.
+	* mpn/x86_64/fastsse/lshiftc-movdqu2.asm: Likewise.
+
+	* mpn/x86_64/x86_64-defs.m4 (palignr): New macro.
+	(x86_opcode_regxmm, x86_opcode_regxmm_list): New, made from x86 mmx
+	counterparts.
+	(x86_lookup): Copy from x86/x86-defs.m4.
+	* mpn/x86_64/fastsse/copyd-palignr.asm: Use palignr macro.
+	* mpn/x86_64/fastsse/copyi-palignr.asm: Likewise.
+
+2012-04-15 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* tests/mpz/t-bin.c: Add more tests on small values.
+	* mpz/bin_uiui.c (mpz_bdiv_bin_uiui): Smaller temporary areas.
+
+2012-04-15  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/fastsse/copyd-palignr.asm: New file.
+	* mpn/x86_64/fastsse/copyi-palignr.asm: New file.
+	* mpn/x86_64/core2/copyd.asm: New file.
+	* mpn/x86_64/core2/copyi.asm: New file.
+	* mpn/x86_64/nano/copyd.asm: New file.
+	* mpn/x86_64/nano/copyi.asm: New file.
+	* mpn/x86_64/atom/copyd.asm: New file.
+	* mpn/x86_64/atom/copyi.asm: New file.
+
+2012-04-13 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpz/bin_uiui.c: Rewrite (some parts are Torbjorn's).
+	* gen-fac_ui.c: Generate new constants for bin_uiui.
+
+	* tests/mpz/t-fac_ui.c: Check Wilson's theorem on a big value.
+
+	* mpn/generic/invert.c: Remove support for scratch == NULL.
+	* tune/speed.h (SPEED_ROUTINE_MPN_MUPI_DIV_QR): Allocate scratch
+	space for mpn_invert.
+
+	* mpz/mul_i.h: Small clean-up.
+
+	* tests/mpn/toom-sqr-shared.h: New file.
+	* tests/mpn/t-toom2-sqr.c: New file.
+	* tests/mpn/t-toom3-sqr.c: New file.
+	* tests/mpn/t-toom4-sqr.c: New file.
+	* tests/mpn/t-toom6-sqr.c: New file.
+	* tests/mpn/t-toom8-sqr.c: New file.
+	* tests/mpn/Makefile.am (EXTRA_DIST): Add toom-sqr-shared.h .
+
+	* mpn/generic/toom62_mul.c: Use add_n, sub_n, when possible.
+
+2012-04-12  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/fastsse/lshift-movdqu2.asm: New file.
+	* mpn/x86_64/fastsse/rshift-movdqu2.asm: New file.
+	* mpn/x86_64/fastsse/lshiftc-movdqu2.asm: New file.
+	* mpn/x86_64/coreisbr/lshift.asm: New file.
+	* mpn/x86_64/coreisbr/rshift.asm: New file.
+	* mpn/x86_64/coreisbr/lshiftc.asm: New file.
+	* mpn/x86_64/k10/lshift.asm: New file.
+	* mpn/x86_64/k10/rshift.asm: New file.
+	* mpn/x86_64/k10/lshiftc.asm: New file.
+
+	* mpn/x86_64/fastsse/lshift.asm: Simplify to very basic form.
+
+2012-04-11  Niels Möller  <nisse@lysator.liu.se>
+
+	* Makefile.am (check-mini-gmp): Pass -I../.. in EXTRA_CFLAGS, to
+	locate gmp.h.
+
+2012-04-10 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* Makefile.am (check-mini-gmp): Use $(MAKE).
+	(clean-mini-gmp): New target.
+	(clean-local, distclean-local): New automake targets. Depend on
+	clean-mini-gmp.
+
+	* gen-fac_ui.c (mpz_root): Remove.
+
+2012-04-07  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/ia64/gcd_1.asm: Rewrite inner loop to use ctz table.
+
+2012-04-05  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/powerpc64/p7/popcount.asm: Properly extend arg n for mode32.
+	* mpn/powerpc64/p7/hamdist.asm: Likewise.
+
+2012-04-04  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/powerpc64/p7/popcount.asm: New file.
+	* mpn/powerpc64/p7/hamdist.asm: New file.
+
+	* longlong.h (ARM count_leading_zeros): Enable for more arch versions.
+
+	* mpn/x86_64/gcd_1.asm: Make room for DOS64 regparm shadow area.
+	* mpn/x86_64/core2/gcd_1.asm: Likewise.
+
+2012-04-03  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/coreisbr/aorrlsh_n.asm: Make it actually work for DOS64.
+
+2012-04-02 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpz/oddfac_1.c: Initialize size for ASSERT.
+
+2012-04-02  Torbjorn Granlund  <tege@gmplib.org>
+
+	* gmp-h.in (_GMP_H_HAVE_FILE): Test also __STDIO_LOADED (for VMS).
+
+	* gmp-impl.h (doprnt_format_t, etc): Remove bogus __GMP_DECLSPECs.
+
+2012-03-30 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/x86_64/sqr_basecase.asm: Speed-up for small cases.
+
+2012-03-29  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/sparc64/gcd_1.asm: New file.
+
+2012-03-27  Torbjorn Granlund  <tege@gmplib.org>
+
+	* config.guess: Fix typo in coreisbr recognition.
+
+2012-03-26 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/x86_64/gcd_1.asm: Reduce latency.
+	* mpn/x86_64/mul_basecase.asm: Save one jump.
+
+	* mpz/iset_ui.c: Don't realloc.
+
+2012-03-20 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mp_clz_tab.c: Add __clz_tab[128].
+	* longlong.h (count_trailing_zeros): Use it in pure C variant.
+
+2012-03-20  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.in (x86 fat_path): Add many missing directories.
+	* mpn/x86/fat/fat.c (__gmpn_cpuvec_init): Rewrite.
+	(fake_cpuid_table): Add many more CPUs.
+
+	* mpn/x86_64/fat/fat.c (__gmpn_cpuvec_init): Minor spacing cleanup.
+
+2012-03-19  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86/x86-defs.m4 (CALL, PIC_WITH_EBX): New macros.
+	* mpn/x86/darwin.m4: Likewise.
+	* mpn/x86/k7/gcd_1.asm: Use new macros to support PIC.
+	* mpn/x86/p6/gcd_1.asm: Likewise.
+
+2012-03-19 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* gen-fac_ui.c: Generate more constants (possible mini-mpz_root).
+	* mpz/oddfac_1.c: Improve ASSERTs.
+	(log_n_max): Use precomputed table.
+
+	* longlong.h (_PROTO): Remove.
+
+2012-03-18  Torbjorn Granlund  <tege@gmplib.org>
+
+	* longlong.h (count_trailing_zeros): Write better pure C default
+	variant.
+
+	* mpn/x86/p6/gcd_1.asm: Remove forgotten x86_64 reference.
+
+	* mpn/x86/p6/gmp-mparam.h: Update, to get BMOD_1_TO_MOD_1_THRESHOLD
+	defined for fat binaries.
+
+2012-03-17  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86/k7/gcd_1.asm: Rewrite.
+	* mpn/x86/p6/gcd_1.asm: New file.
+
+	* mpn/x86_64/core2/gcd_1.asm: Conditionally suppress reduction calls.
+	* mpn/x86_64/gcd_1.asm: Rewrite.
+
+2012-03-15  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/gcd_1.c: Parameterise zerotab code.
+
+	* mpn/x86_64/nano/gcd_1.asm: New file, grabbing core2 asm file.
+
+	* mpn/x86_64/core2/gcd_1.asm: Speed up loop code, simplify non-loop
+	code.
+
+2012-03-13  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/core2/gcd_1.asm: Add hack to support fat builds.
+
+	* mpn/x86_64/core2/gcd_1.asm: Shorten critical path.
+
+2012-03-12  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/core2/gcd_1.asm: New file.
+	* mpn/x86_64/k10/gcd_1.asm: New file, grabbing core2 asm file.
+	* mpn/x86_64/bd1/gcd_1.asm: Likewise.
+
+	* mpn/x86_64/bobcat/sqr_basecase.asm: New file.
+	* mpn/x86_64/bobcat/mul_basecase.asm: Minor tuning.
+
+2012-03-10  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.in (fat_functions): Add addlsh1_n, addlsh2_n, addmul_2,
+	mullo_basecase, redc_1, redc_2, sublsh1_n.
+
+	* gmp-impl.h (struct cpuvec_t): Add fields for new fat functions.
+	* gmp-impl.h: Adjust corresponding declarations.
+
+	* mpn/generic/redc_2.c (mpn_addmul_2): Make static.
+
+	* mpn/x86_64/fat/fat_entry.asm (FAT_INIT): Expand before fat_init to
+	reduce branch offsets.  Pass plain 0,1,3... in %al since we'd else run
+	out of 8-bit range.
+
+	* mpn/x86_64/fat/fat_entry.asm (fat_init): Scale passed index value.
+	* mpn/x86/fat/fat_entry.asm (fat_init): Use movzbl for expanding index
+	value.
+
+	* mpn/x86_64/x86_64-defs.m4 (CPUVEC_FUNCS_LIST): Add new fat functions.
+	* mpn/x86/x86-defs.m4 (CPUVEC_FUNCS_LIST): Likewise.
+	* mpn/x86_64/fat/fat.c (__gmpn_cpuvec): Likewise.
+	* mpn/x86/fat/fat.c (__gmpn_cpuvec): Likewise.
+
+	* mpn/x86_64/fat/redc_2.c: New file.
+	* mpn/x86/fat/mullo_basecase.c: New file.
+	* mpn/x86/fat/redc_1.c: New file.
+	* mpn/x86/fat/redc_2.c: New file.
+
+	* tests/mpn/t-fat.c: Test mullo_basecase.
+
+2012-03-08  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/coreisbr/addmul_2.asm: Port to DOS64.
+
+2012-02-29  Marc Glisse  <marc.glisse@inria.fr>
+
+	* gmpxx.h: Ignore partial C++11 support in g++-4.6.
+	* tests/cxx/t-cxx11.cc: Likewise.
+
+	* gmpxx.h (operator""): New functions.
+	* tests/cxx/t-cxx11.cc: Test the above.
+	* doc/gmp.texi: Document the above.
+
+2012-03-08 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* acinclude.m4 (GMP_H_ANSI): Remove.
+	* configure.in: Don't use GMP_H_ANSI.
+	* gmp-h.in (__GMP_HAVE_PROTOTYPES): Remove.
+
+2012-03-08  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/fat/fat.c (fake_cpuid_table): Recognise "bulldozer".
+	(__gmpn_cpuvec_init): Overhaul to match configure.in.
+
+	* configure.in: Adjust bulldozer path_64.
+
+2012-03-07  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.in (x86_64 fat_path): List recently added AMD directories.
+
+	* mpn/x86_64/bobcat/copyi.asm: New file.
+	* mpn/x86_64/bobcat/copyd.asm: New file.
+
+	* config.guess: Handle AMD 11h correctly.
+
+	* tune/tuneup.c (tune_redc): Better handle situation where redc_2 is
+	never faster.
+
+2012-03-06  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/bobcat/mul_basecase.asm: New file.
+
+2012-03-04  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/bobcat/mul_1.asm: New file.
+	* mpn/x86_64/bobcat/aorsmul_1.asm: New file.
+
+2012-03-04 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpz/invert.c: Remove mod 0 branch.
+	* tests/mpz/t-invert.c: Avoid testing mod 0.
+	* doc/gmp.texi (mpz_invert): Specify mod 0 is not handled.
+
+	* gmp-h.in (__gmp_signed, __gmp_const): Remove.
+	(__GMP_HAVE_TOKEN_PASTE, __GMP_HAVE_CONST): Remove.
+	* gmp-impl.h: Strip __GMP_HAVE_TOKEN_PASTE and __GMP_HAVE_CONST.
+	* demos/expr/: Strip __gmp_const usage from all files.
+
+	* tests/mpz/t-powm.c (allsizes_seen): Require unsigned*.
+
+2012-03-03  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/k8/gmp-mparam.h: New file.
+	* mpn/x86_64/k10/gmp-mparam.h: New file.
+
+	* mpn/generic/hgcd_step.c (mpn_hgcd_step): Remove unused variables.
+	* mpn/generic/hgcd_jacobi.c (hgcd_jacobi_step): Likewise.
+	* mpn/generic/hgcd_reduce.c (hgcd_matrix_apply): Likewise.
+	* mpn/generic/mu_bdiv_qr.c: Likewise.
+	* mpz/jacobi.c: Likewise.
+	* mpz/mod.c: Likewise.
+
+	* mpn/generic/toom42_mul.c: Remove unread variable.
+	* mpn/generic/set_str.c (mpn_set_str_compute_powtab): Likewise.
+	* mpn/generic/rootrem.c (mpn_rootrem_internal): Likewise.
+	* tests/refmpn.c (refmpn_mul): Likewise.
+	* mpn/generic/hgcd_appr.c (mpn_hgcd_appr): Propagate mask computation
+	into ASSERT, remove variable.
+
+	* gmp-h.in (__GMP_PROTO): Remove.
+	* Strip __GMP_PROTO usage from all files.
+	* Strip prototype parameter names from all files.
+
+2012-03-01 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* doc/gmp.texi (mpz_invert): Correctly document result range.
+	* tests/mpz/t-invert.c: Small range correction.
+
+2012-03-01  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/mullo_basecase.asm: New file.
+
+2012-02-29  Marc Glisse  <marc.glisse@inria.fr>
+
+	* gmpxx.h (std::numeric_limits): New partial specialization.
+
+2012-02-29  Niels Möller  <nisse@lysator.liu.se>
+
+	* Makefile.am (check-mini-gmp): Use $(MAKE).
+	(clean-mini-gmp): New target.
+	(clean-local, distclean-local): New automake targets. Depend on
+	clean-mini-gmp.
+
+2012-02-28  Niels Möller  <nisse@lysator.liu.se>
+
+	* Makefile.am (check-mini-gmp): New target, for running the
+	mini-gmp testsuite.
+
+2012-02-27  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/fastsse/lshiftc.asm: New file.
+	* mpn/x86_64/fastsse/com.asm: New file.
+
+	* mpn/x86_64/bd1/popcount.asm: New file.
+	* mpn/x86_64/bd1/hamdist.asm: New file.
+
+	* mpn/x86_64/fastsse/copyi.asm: New file.
+	* mpn/x86_64/fastsse/copyd.asm: New file.
+	* mpn/x86_64/fastsse/lshift.asm: New file.
+
+2012-02-26  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/coreisbr/addmul_2.asm: New file.
+
+	* tests/devel/try.c (param_init): Don't require addmul_N to handle
+	overlap.
+
+	* mpn/x86_64/bd1/mul_1.asm: New file.
+	* mpn/x86_64/bd1/aorsmul_1.asm: New file.
+
+2012-02-26 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpz/2fac_ui.c: New file: implements n!!.
+	* Makefile.am (MPZ_OBJECTS): Add mpz/2fac_ui.
+	* gmp-h.in: Declare mpz_2fac_ui.
+	* tests/mpz/t-fac.c: Test mpz_2fac_ui.
+	* doc/gmp.texi: Document mpz_2fac_ui.
+	* mpz/Makefile.am (libmpz_la_SOURCES): Add 2fac_ui.c.
+
+	* mpz/oddfac_1.c (mpz_oddfac_1): Use umul_ppmm when size = 2.
+
+2012-02-26  Niels Möller  <nisse@lysator.liu.se>
+
+	* bootstrap.c: New file, replacing dumbmp.c. Uses mini-gmp for the
+	standard GMP functions, and then defines the few functions
+	particular for the bootstrap.
+	* dumbmp.c: Deleted file. A few functions moved to bootstrap.c.
+
+	* gen-bases.c: Include bootstrap.c, not dumbmp.c.
+	* gen-fac_ui.c: Likewise.
+	* gen-trialdivtab.c: Likewise.
+	* gen-fib.c: Include bootstrap.c, not dumbmp.c. Use assert rather
+	than ASSERT. Deleted casts of xmalloc return value.
+	* gen-psqr.c: Likewise.
+	(COLLAPSE_ELEMENT): Use memmove rather than mem_copyi.
+
+	* Makefile.am: Replaced all uses of dumbmp.c by bootstrap.c.
+	(EXTRA_DIST, dist-hook): Arrange for distribution of the mini-gmp
+	files.
+
+2012-02-24 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpz/invert.c: Use ABSIZ, MPZ_EQUAL_1_P.
+	* mpz/abs.c: Collapse MPZ_REALLOC(x,.) and PTR(x).
+	* mpz/aors_ui.h: Likewise.
+	* mpz/com.c: Likewise.
+	* mpz/neg.c: Likewise.
+
+	* mpz/invert.c: Reply "no-inverse" when modulus is zero.
+	* tests/mpz/t-invert.c: Add more checks.
+	* doc/gmp.texi (mpz_invert): Inverse can not be zero.
+
+2012-02-24  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/mpn/logic.c: New file.
+	* tests/mpn/Makefile.am (check_PROGRAMS): Add logic.
+
+	* tests/mpz/t-invert.c: New file.
+	* tests/mpz/Makefile.am (check_PROGRAMS): Add t-invert.
+
+2012-02-24  Marc Glisse  <marc.glisse@inria.fr>
+
+	* tests/mpq/t-cmp.c: Move NUM and DEN macros...
+	* tests/mpq/t-cmp_ui.c: Likewise...
+	* gmp-impl.h: ... to here.
+
+	* mpq/abs.c: Use NUM, DEN, SIZ, ALLOC, PTR, MPZ_REALLOC.
+	* mpq/aors.c: Likewise.
+	* mpq/canonicalize.c: Likewise.
+	* mpq/clear.c: Likewise.
+	* mpq/cmp.c: Likewise.
+	* mpq/cmp_si.c: Likewise.
+	* mpq/cmp_ui.c: Likewise.
+	* mpq/div.c: Likewise.
+	* mpq/equal.c: Likewise.
+	* mpq/get_d.c: Likewise.
+	* mpq/get_den.c: Likewise.
+	* mpq/get_num.c: Likewise.
+	* mpq/get_str.c: Likewise.
+	* mpq/init.c: Likewise.
+	* mpq/inp_str.c: Likewise.
+	* mpq/inv.c: Likewise.
+	* mpq/md_2exp.c: Likewise.
+	* mpq/mul.c: Likewise.
+	* mpq/neg.c: Likewise.
+	* mpq/set.c: Likewise.
+	* mpq/set_d.c: Likewise.
+	* mpq/set_den.c: Likewise.
+	* mpq/set_f.c: Likewise.
+	* mpq/set_num.c: Likewise.
+	* mpq/set_si.c: Likewise.
+	* mpq/set_str.c: Likewise.
+	* mpq/set_ui.c: Likewise.
+	* mpq/set_z.c: Likewise.
+	* mpq/swap.c: Likewise.
+
+	* tests/mpq/t-inv.c: New test file.
+	* tests/mpq/Makefile.am: Add the above.
+
+	* gmpxx.h (__gmp_set_expr): Use mpq_set_z.
+
+	* mpq/md_2exp.c: Collapse MPZ_REALLOC(x,.) and PTR(x).
+	* mpq/set_d.c: Likewise.
+	* mpq/set_f.c: Likewise.
+
+2012-02-24  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/x86_64/core2/aorsmul_1.asm: Added mpn_addmul_1c and
+	mpn_submul_1c entry points.
+
+2012-02-23  Marc Glisse  <marc.glisse@inria.fr>
+
+	* mpz/abs.c: Use ALLOC, SIZ, ABSIZ, PTR, MPZ_REALLOC.
+	* mpz/aors_ui.h: Likewise.
+	* mpz/array_init.c: Likewise.
+	* mpz/cdiv_q.c: Likewise.
+	* mpz/cdiv_qr.c: Likewise.
+	* mpz/cdiv_r.c: Likewise.
+	* mpz/clear.c: Likewise.
+	* mpz/clrbit.c: Likewise.
+	* mpz/cmp_si.c: Likewise.
+	* mpz/com.c: Likewise.
+	* mpz/fdiv_q.c: Likewise.
+	* mpz/fdiv_qr.c: Likewise.
+	* mpz/fdiv_r.c: Likewise.
+	* mpz/get_si.c: Likewise.
+	* mpz/get_str.c: Likewise.
+	* mpz/init.c: Likewise.
+	* mpz/inp_str.c: Likewise.
+	* mpz/iset.c: Likewise.
+	* mpz/iset_d.c: Likewise.
+	* mpz/iset_si.c: Likewise.
+	* mpz/iset_str.c: Likewise.
+	* mpz/iset_ui.c: Likewise.
+	* mpz/mod.c: Likewise.
+	* mpz/neg.c: Likewise.
+	* mpz/out_str.c: Likewise.
+	* mpz/random2.c: Likewise.
+	* mpz/set_si.c: Likewise.
+	* mpz/set_str.c: Likewise.
+	* mpz/set_ui.c: Likewise.
+	* mpz/setbit.c: Likewise.
+	* mpz/sqrt.c: Likewise.
+	* mpz/swap.c: Likewise.
+	* mpz/tdiv_r_2exp.c: Likewise.
+
+	* tests/cxx/t-ops.cc: Test mpz_abs reallocation.
+
+2012-02-23  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/core2/rsh1aors_n.asm: Complete rewrite.
+	* mpn/x86_64/coreisbr/rsh1aors_n.asm: Move old core2 code here.
+
+	* mpn/x86_64/redc_1.asm: Make it work for DOS64 (broken in last edit).
+
+2012-02-20 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/toom_interpolate_8pts.c: Compute carry iif non-trivial.
+
+	* mpz/gcdext.c: Adapt to relaxed mpn_gcdext's input requirements.
+
+	* mpz/and.c: Use mpn_ logic everywhere. Reduce branches.
+	* mpz/ior.c: Likewise.
+	* mpz/xor.c: Likewise.
+
+2012-02-20  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/coreisbr/mul_1.asm: New file.
+
+	* mpn/x86_64/coreisbr/aorsmul_1.asm: New file.
+
+	* mpn/x86_64/mod_34lsub1.asm: Avoid ",pt" branch hint since many
+	assemblers don't support it.
+
+2012-02-19  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/redc_1.c: Put back mpn_add_n call, return its carry.
+	Reintroduce previously removed RP argument.
+	* mpn/x86_64/redc_1.asm: Likewise.
+
+	* mpn/generic/redc_2.c: Remove mpn_sub_n call, return carry from
+	mpn_add_n call.
+
+	* gmp-impl.h (mpn_redc_1, mpn_redc_2): Now return an mp_limb_t.
+
+	* tune/speed.h (SPEED_ROUTINE_REDC_1): Adopt to pass RP argument.
+
+	* tests/refmpn.c (refmpn_redc_1): Adopt to new redc_1 interface.
+
+	* mpn/generic/powm.c (MPN_REDC_1): Pass rp parameter to mpn_redc_1.
+	* mpn/generic/powm_sec.c (MPN_REDC_1_SEC): Likewise.
+	* mpn/generic/powm.c (MPN_REDC_2): New macro, use for mpn_redc_2.
+
+2012-02-18  Marc Glisse  <marc.glisse@inria.fr>
+
+	* gmpxx.h (std::common_type): New partial specialization in C++11.
+	* tests/cxx/t-cxx11.cc: Test it.
+
+	* gmpxx.h: Don't declare long double functions that are never defined.
+
+	* gmpxx.h (__gmp_binary_expr): Let things happen in place: q=q*q+z*z
+	becomes tmp=z*z, q=q*q, q+=tmp.
+	* tests/cxx/t-binary.cc: More variable reuse tests.
+
+2012-02-17  Marc Glisse  <marc.glisse@inria.fr>
+
+	* gmp-h.in (__GMP_WITHIN_GMP): Test with #ifdef instead of #if, for
+	the benefit of applications using gcc -Wundef.
+	(__GMP_WITHIN_GMPXX): Likewise.
+
+2012-02-16  Marc Glisse  <marc.glisse@inria.fr>
+
+	* gmpxx.h (__gmp_binary_expr): Let things happen in place: e=a*b-c*d
+	becomes tmp=c*d, e=a*b, e-=tmp.
+	* tests/cxx/t-binary.cc: More variable reuse tests.
+
+2012-02-15  Niels Möller  <nisse@lysator.liu.se>
+
+	* tune/tuneup.c (mul_toom43_to_toom54_threshold): New global.
+	(tune_mul): Added tuning of MUL_TOOM43_TO_TOOM54_THRESHOLD.
+	* tune/speed.h (SPEED_ROUTINE_MPN_TOOM43_FOR_TOOM54_MUL): New macro.
+	(SPEED_ROUTINE_MPN_TOOM54_FOR_TOOM43_MUL): New macro.
+	Prototypes for corresponding functions.
+	* tune/common.c (speed_mpn_toom43_for_toom54_mul): New function.
+	(speed_mpn_toom54_for_toom43_mul): New function.
+
+	* gmp-impl.h (MPN_TOOM43_MUL_MINSIZE): Corrected constant.
+	(MPN_TOOM53_MUL_MINSIZE): Likewise.
+	(MPN_TOOM54_MUL_MINSIZE): New constant.
+	(mpn_toom54_mul): Added prototype.
+	(MUL_TOOM43_TO_TOOM54_THRESHOLD): New threshold. Default value and
+	tuning setup.
+
+2012-02-14  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/toom54_mul.c: New file, originally contributed by
+	Marco.
+	* gmp-impl.h (mpn_toom54_mul_itch): New function.
+	* configure.in (gmp_mpn_functions): Added toom54_mul.
+	* tests/mpn/t-toom54.c: New file.
+	* tests/mpn/Makefile.am (check_PROGRAMS): Added t-toom54.
+
+2012-02-13  Niels Möller  <nisse@lysator.liu.se>
+
+	* configure.in: Display summary of options.
+
+2012-02-11  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/tests.h (TESTS_REPS): Print any non-standard repetitions.
+
+2012-02-11 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* doc/gmp.texi (Factorial): Shortly describe current algorithm.
+	(Multiplication Algorithms): Add Toom[68]'n'half, (too) shortly.
+	* gmp-impl.h (ASSERT_ALWAYS): Consider failures UNLIKELY.
+
+2012-02-10  Niels Möller  <nisse@lysator.liu.se>
+
+	* tests/mpz/t-gcd.c (gcdext_valid_p): Enforce slightly stricter
+	bound for cofactors.
+
+	* mpn/generic/gcdext_lehmer.c (mpn_gcdext_hook): Corrected
+	handling of unlikely (maybe impossible?) case u1n < un. Related to
+	the 2012-02-05 bugfix of gcdext_subdiv_step.c in the gmp-5.0 repo.
+
+2012-02-09 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* gmp-impl.h (mpn_toom3*_itch): Support any recursion depth.
+	* tests/refmpn.c (refmpn_mul): Restore tight allocations.
+
+	* mpz/oddfac_1.c (mpz_oddfac_1): Get ready for n!!
+	* gmp-impl.h (mpz_oddfac_1): Update signature.
+	* mpz/fac_ui.c (mpz_fac_ui): Update call to mpz_oddfac_1.
+
+2012-02-09  Marc Glisse  <marc.glisse@inria.fr>
+
+	* gmp-impl.h (ABS_CAST): New macro.
+	* mpf/cmp_si.c: Use ABS_CAST.
+	* mpf/get_si.c: Use ABS_CAST.
+	* mpf/iset_si.c: Use ABS_CAST.
+	* mpf/set_si.c: Use ABS_CAST.
+	* mpq/set_si.c: Use ABS_CAST.
+	* mpz/cmp_si.c: Use ABS_CAST.
+	* mpz/get_si.c: Use ABS_CAST.
+	* mpz/iset_si.c: Use ABS_CAST.
+	* mpz/mul_i.h: Use ABS_CAST.
+	* mpz/set_si.c: Use ABS_CAST.
+
+2012-02-08  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/powerpc32/divrem_2.asm: Fix off-by-one condition in invert_limb
+	code.
+
+2012-02-08  Niels Möller  <nisse@lysator.liu.se>
+
+	* doc/gmp.texi (mpz_gcdext): Clarified corner cases in cofactor
+	canonicalization.
+
+2012-02-07  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/gcdext.c (mpn_gcdext): Fixed assert, related to the
+	special case A = (2k+1) G, B = 2 G. Fix copied from gmp-5.0 repo.
+
+2012-02-06  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/hgcd_matrix.c (hgcd_matrix_update_q): Fixed carry
+	handling bug. Fix copied from gmp-5.0 repo, where the function is
+	found in hgcd.c.
+
+	* tests/mpz/t-gcd.c (main): Use mpz_rrandomb for test operands,
+	not mpz_urandomb. Change copied from gmp-5.0 repo.
+	* tests/mpn/t-hgcd.c (main): Likewise.
+
+2012-02-04 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* tests/refmpn.c (refmpn_mul): More conservative allocations.
+
+2012-02-03  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/bd1/gmp-mparam.h: New file.
+
+	* longlong.h (udiv_qrnnd from sdiv_qrnnd): Declare udiv_w_sdiv.
+
+	* mpn/generic/udiv_w_sdiv.c: Use c89 function header.
+
+2012-02-03 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpz/fac_ui.c: mpz_oddfac_1 removed, with many related functions.
+	* mpz/oddfac_1.c: New file, mpz_oddfac_1 implementation.
+	* gmp-impl.h: mpz_oddfac_1 declaration.
+	* Makefile.am (MPZ_OBJECTS): add mpz/oddfac_1$U.lo .
+	* mpz/Makefile.am (libmpz_la_SOURCES): add oddfac_1.c .
+	* tune/Makefile.am (fac_ui.c): include mpz/oddfac_1.c .
+
+2012-02-02 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/toom_interpolate_16pts.c: Correct an unlikely 32-bit bug.
+
+2012-02-02  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/toom63_mul.c: Allow s+t==n by adjusting an ASSERT.
+	* mpn/generic/toom_interpolate_8pts.c: Perform final incr iff s+t!=n.
+
+	* tests/mpn/t-toom6h.c (MIN_BN): Make more consistent with ASSERT in
+	tested function.
+
+2012-02-01  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/mpn/t-mul.c: New file.
+	* tests/mpn/Makefile.am: Compile it.
+
+2012-02-01  Marc Glisse  <marc.glisse@inria.fr>
+
+	* gmpxx.h: Remove check for g++ older than 2.91.
+
+2012-02-01  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/mul.c: Added diagram on where toom functions can be
+	called.
+
+2012-02-01  Marc Glisse  <marc.glisse@inria.fr>
+
+	* gmpxx.h (__gmp_unary_expr): Make the constructor explicit.
+	(__gmp_expr(__gmp_expr&&)): New move constructors.
+	(__gmp_expr::operator=(__gmp_expr&&)): New move assignments.
+	(swap): Mark as noexcept.
+	(__GMPXX_USE_CXX11): New macro.
+	(__GMPXX_NOEXCEPT): New macro.
+	* tests/cxx/t-cxx11.cc: New file.
+	* tests/cxx/Makefile.am: Added t-cxx11.
+
+2012-01-31  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/powm_sec.c (SQR_BASECASE_LIM): New name for
+	SQR_BASECASE_MAX.
+	(SQR_BASECASE_LIM, fat variant): Define to read __gmpn_cpuvec.
+	(SQR_BASECASE_LIM, native variant): Define to SQR_TOOM2_THRESHOLD
+	straight, without arithmetic.
+	(mpn_local_sqr): Use BELOW_THRESHOLD as per Marco's suggestion.
+
+2012-01-30  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/mpz/t-powm.c: Ensure all sizes are seen.
+
+2012-01-30  Marc Glisse  <marc.glisse@inria.fr>
+
+	* gmpxx.h (__gmp_binary_expr): Let things happen in place: d=a+b+c
+	when d != c.
+	* tests/cxx/t-binary.cc: Test variable reuse: c=a+b+c.
+
+2012-01-28  Marc Glisse  <marc.glisse@inria.fr>
+
+	* gmpxx.h: Don't compute -LONG_MIN.
+
+	* doc/gmp.texi (gmp_randclass::get_z_bits): Use mp_bitcnt_t.
+	* gmpxx.h: Replace unsigned long with mp_bitcnt_t.
+
+2012-01-27  Torbjorn Granlund  <tege@gmplib.org>
+
+	* Upgrade to libtool 2.4.2.
+
+2012-01-26 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* tests/mpz/t-fac_ui.c: Increase default test cases.
+
+	* mpz/prodlimbs.c: New file, mpz_prodlimbs implementation.
+	* gmp-impl.h: mpz_prodlimbs declaration.
+	* Makefile.am (MPZ_OBJECTS): add mpz/prodlimbs$U.lo .
+	* mpz/Makefile.am (libmpz_la_SOURCES): add prodlimbs.c .
+	(fac_ui.h): remove target (moved up one directory).
+	* mpz/fac_ui.c: mpz_prodlimbs removed, micro-optimisations.
+
+2012-01-25  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tune/tuneup.c: Remove unused tuneup variables.
+
+2012-01-20 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpz/fac_ui.c: Reduce branches in basecases.
+
+2012-01-18  Marc Glisse  <marc.glisse@inria.fr>
+
+	* doc/gmp.texi (mpf_class::mpf_class): Use mp_bitcnt_t.
+
+2012-01-17  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.in: Add ultrasparc T4 support.
+
+	* demos/isprime.c (main): Run 25 millerrabin tests.
+
+2012-01-16 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpz/fac_ui.c (SIEVE_SEED): Define value for small limb size.
+	(mpz_oddswing_1): Reduce the number of divisions.
+	(mpz_oddfac_1): Reduce memory usage.
+	* mpn/minithres/gmp-mparam.h: Correct minimum for FAC_DSC_.
+	* tune/tuneup.c (tune_fac_ui): Likewise.
+
+2012-01-15  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpz/scan0.c (mpz_scan0): Use ~(mp_bitcnt_t) 0, rather than
+	ULONG_MAX, when returning "infinity".
+	* mpz/scan1.c (mpz_scan1): Likewise.
+
+2012-01-12  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/t-popc.c: Test longer bit strings.
+
+2012-01-12 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpz/divexact.c: Tight realloc, delayed if variables are reused.
+	* mpz/lcm.c: Smaller temp space, avoid goto.
+	* gmp-impl.h (popc_limb): avoid double & (for 8-bits limb).
+
+2012-01-10 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/minithres/gmp-mparam.h: New FAC_ODD_ and FAC_DSC_ thresholds.
+	* tune/tuneup.c (tune_fac_ui): Correct minimum for FAC_DSC_.
+
+2012-01-07  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpz/mul_2exp.c: Rewrite.
+	* mpz/tdiv_q_2exp.c: Rewrite.
+
+2012-01-05 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* gen-fac_ui.c: Remove currently unused constants; add new odd
+	double factorial table.
+	* mpz/fac_ui.c (RECURSIVE_PROD_THRESHOLD): Increase default.
+	(mpz_oddfac_1): New function: a merge of _bc_odd and _dsc_odd.
+	(mpz_prodlimbs): More in-place computations.
+
+	* tune/tuneup.c (tune_fac_ui): min_is_always for FAC_ODD_.
+
+2012-01-02 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* tune/tuneup.c (tune_fac_ui): Compute FAC_DSC before FAC_ODD.
+
+2011-12-31  Torbjorn Granlund  <tege@gmplib.org>
+
+	* Makefile.am (fac_ui.h): Put file in top-level dir, not in mpz.
+
+2011-12-31 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* tune/Makefile.am (fac_ui.c): New target.
+	(nodist_tuneup_SOURCES,CLEANFILES): Add fac_ui.c.
+	* tune/tuneup.c (mpz_fac_ui_tune): Declare prototype.
+	(fac_odd_threshold,fac_dsc_threshold): New global variables.
+	(speed_mpz_fac_ui_tune,tune_fac_ui): New functions.
+	(all): Call tune_fac_ui.
+	* gmp-impl.h (FAC_ODD_THRESHOLD,FAC_DSC_THRESHOLD):
+	New thresholds: default values, and setup for tuning.
+	(FAC_DSC_THRESHOLD_LIMIT): Define (when tuning).
+	* mpz/fac_ui.c (FAC_ODD_THRESHOLD,FAC_DSC_THRESHOLD):
+	Default values removed.
+
+2011-12-30  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpz/hamdist.c: Fix typo in a return statement.
+
+	* mpn/generic/powm_sec.c (SQR_BASECASE_MAX): Set safely from
+	SQR_TOOM2_THRESHOLD.
+
+2011-12-17  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/mpz/t-perfpow.c: Decrease default # of tests.
+
+2011-12-16  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/refmpn.c (AORS_1): Fix typo in variable type.
+
+2011-12-10  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/sbpi1_bdiv_q.c: Delay quotient limb stores in order to
+	allow quotient and dividend to completely overlap.
+	* mpn/generic/sbpi1_bdiv_qr.c: Likewise.
+
+2011-12-10 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpz/fac_ui.c: fac_bc_ui inlined in fac_ui.
+
+2011-12-08  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/powm_sec.c: Handle fat binaries better.
+
+	* mpz/fac_ui.c (mpz_bc_fac_1): Fix typo in allocation size.
+
+	* mpn/x86/fat/com.c: New file.
+
+	* mpn/x86_64/pentium4/aors_n.asm: Make it actually work for DOS64.
+	* mpn/x86_64/pentium4/rsh1aors_n.asm: Conditionalise jump on DOS64
+	to avoid overhead for standard ABIs.
+
+	* mpn/x86_64/gcd_1.asm: Support DOS64.
+
+2011-12-07  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.in: Fix typo making HAVE_NATIVE_mpn_X fail for fat
+	functions.
+
+	* mpn/x86_64/fat/fat.c (__gmpn_cpuvec_init): Add a missing break.
+
+2011-12-07 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* gen-fac_ui.c: Generate two more tables: odd factorial, swing.
+
+	* mpz/fac_ui.c: Rewrite.
+
+2011-12-06  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/hgcd.c (mpn_hgcd): Use hgcd_reduce for first
+	recursive call.
+
+2011-12-06  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tune/mod_1_1-1.c: Redefine the mpn_ functions, not __gmpn_ (for the
+	benefit of fat builds).
+	* tune/mod_1_1-2.c: Likewise.
+
+2011-12-05  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86/fat/lshiftc.c: New file.
+	* mpn/x86/fat/mod_1_1.c: New file.
+	* mpn/x86/fat/mod_1_2.c: New file.
+	* mpn/x86/fat/mod_1_4.c: New file.
+
+	* mpn/x86/fat/diveby3.c: Remove no longer fat function.
+	* mpn/x86_64/fat/diveby3.c: Likewise.
+
+	* mpn/x86_64/fat/gcd_1.c: Remove since always provided as asm.
+	* mpn/x86_64/fat/mode1o.c: Likewise.
+
+	* configure.in (fat_functions): Update to more relevant function set.
+	Add special handling for mod_1_N_cps functions.
+	* gmp-impl.h (struct cpuvec_t) : Corresponding changes.  Also add
+	vrious declarations for new functions.
+	* mpn/x86/x86-defs.m4 (CPUVEC_FUNCS_LIST): Corresponding changes.
+	* mpn/x86_64/x86_64-defs.m4 (CPUVEC_FUNCS_LIST): Corresponding changes.
+	* mpn/x86/fat/fat.c (__gmpn_cpuvec): Corresponding changes.
+	* mpn/x86_64/fat/fat.c (__gmpn_cpuvec): Corresponding changes.
+
+	* mpn/x86_64: Port most remaining x86_64 files to DOS64.
+
+	* mpn/x86_64/coreisbr/aors_n.asm: Add forgotten DOS64_EXIT.
+
+	* mpn/x86_64/x86_64-defs.m4 (LEA): Handle non-PIC code.
+	* mpn/x86_64/darwin.m4 (LEA): Likewise.
+
+2011-12-04  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/fat/fat.c (MAKE_FMS): Rewrite to handle modern CPUs.
+	* mpn/x86/fat/fat.c (MAKE_FMS): Likewise.
+
+	* mpn/x86_64/darwin.m4 (PROTECT): Define to potentially useful value.
+
+2011-12-02  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/invert_limb_table.asm: Use PROTECT.
+	* mpn/x86_64/invert_limb.asm: Likewise.
+
+	* mpn/x86_64/darwin.m4 (PROTECT, IFELF): New defines.
+	* mpn/x86_64/dos64.m4 (PROTECT, IFELF): New defines.
+	* mpn/x86_64/x86_64-defs.m4 (PROTECT, IFELF): New defines.
+
+2011-12-01  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/fat/fat.c: Copy fake cpuid code from x86/fat/fat.c.
+
+	* mpn/x86_64 (STD64, IFSTD): New names for ELF64, IFELF (since these
+	denote all standard calling conventions).
+
+	* mpn/x86_64: Add DOS64 ABI support to more files.
+
+	* mpn/x86_64/mod_1_1.asm: Finish DOS64 support.
+	* mpn/x86_64/mod_1_2.asm: Likewise.
+	* mpn/x86_64/mod_1_4.asm: Likewise.
+
+	* configure.in: Add GMP_NONSTD_ABI also for fat builds.
+
+	* mpn/x86_64/fat/fat_entry.asm: Rewrite to support DOS64.
+
+	* mpn/x86_64/dos64.m4 (IFDOS, IFSTD): New defines.
+	* mpn/x86_64/x86_64-defs (IFDOS, IFSTD): New defines.
+
+	* mpn/x86_64/dive_1.asm: Add DOS64 ABI support.
+	* mpn/x86_64/mode1o.asm: Likewise.
+
+	* mpn/x86_64/mod_34lsub1.asm: Enable for DOS64.
+
+	* mpn/x86_64/invert_limb.asm: Wrap .protected decl.
+
+	* gmp-impl.h (DECL_divexact_1): Fix typo in return type.
+
+	* mpn/x86_64/dos64.m4 (LEA): New define.
+	(PIC): Define.
+
+2011-11-29  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64: Add DOS64 ABI support to most files.
+
+2011-11-28  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/mul_basecase.asm: Support ABI DOS64.
+	* mpn/x86_64/sqr_basecase.asm: Support ABI DOS64.
+	* mpn/x86_64/aorsmul_1.asm: Support ABI DOS64.
+	* mpn/x86_64/mul_1.asm: Support ABI DOS64.
+
+	* mpn/x86_64/x86_64-defs.m4 (DOS64_ENTRY, DOS64_EXIT): New, empty defs.
+
+	* mpn/x86_64/dos64.m4: New file.
+
+	* mpn/asm-defs.m4 (ABI_SUPPORT): New dummy macro.
+
+	* configure.in (64-bit mingw/cygwin): Define HOST_DOS64,GMP_NONSTD_ABI.
+	No longer clear out path_64.
+	(mpn code selection loop): Handle GMP_NONSTD_ABI.
+
+	* mpn/generic/udiv_w_sdiv.c: Use CNST_LIMB for some constants.
+
+2011-11-25  Torbjorn Granlund  <tege@gmplib.org>
+
+	* x86/*: Many new gmp-mparam.h file for 64-bit CPUs in 32-bit mode.
+
+	* configure.in: Overhaul x86/x86_64 support, merging three case
+	statements into one.
+
+2011-11-24  Torbjorn Granlund  <tege@gmplib.org>
+
+	* doc/gmp.texi (Formatted Output Strings): Clarify rules for mpf_t
+	precision.
+
+	* mpn/powerpc32/p7/gmp-mparam.h: New file.
+
+	* tune/tuneup.c (tune_mu_div, tune_mu_bdiv): Up min_size to karatsuba's
+	threshold.
+
+2011-11-22  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/powerpc64/mode64/p6/aorsmul_1.asm: New file.
+
+	* configure.in: Don't fail fat builds under 64-bit DOS.
+
+	* mpn/powerpc64/mode64/aors_n.asm: Align loop for slightly better
+	power5 performance.
+
+2011-11-21  Torbjorn Granlund  <tege@gmplib.org>
+
+	* gmp-h.in (__GNU_MP_RELEASE): Renamed from typo name.
+
+2011-11-20  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.in: Split x86 CPUs into more subtypes for more accurate
+	passing of gcc flags.
+
+	* mpn/powerpc32/p3-p7/aors_n.asm: New file.
+
+	* configure.in: Pass -m32 for powerpc64 with abi=32, using via _maybe
+	mechanism.
+
+	* configure.in: Support powerpc32/p3-p7 directory for affected CPUs.
+
+2011-11-17  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tune/speed.c (routine): Add mpn_tabselect.
+	* tune/common.c (speed_mpn_tabselect): New function.
+	* tune/speed.h (SPEED_ROUTINE_MPN_COPY_CALL): New macro, made from
+	old SPEED_ROUTINE_MPN_COPY.
+	(SPEED_ROUTINE_MPN_COPY): Just invoke SPEED_ROUTINE_MPN_COPY_CALL.
+	(SPEED_ROUTINE_MPN_TABSELECT): New macro.
+
+2011-11-17  Niels Möller  <nisse@lysator.liu.se>
+
+	* tune/tuneup.c (tune_hgcd_appr): Increase stop_since_change.
+
+2011-11-16  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/powerpc32/tabselect.asm: New file.
+
+	* mpn/powerpc64/mode64/aorscnd_n.asm: New file.
+
+2011-11-15  Niels Möller  <nisse@lysator.liu.se>
+
+	* tune/speed.h (speed_mpn_hgcd_appr_lehmer): New prototype.
+	(mpn_hgcd_lehmer_itch): Likewise.
+	(mpn_hgcd_appr_lehmer): Likewise.
+	(mpn_hgcd_appr_lehmer_itch): Likewise.
+	(MPN_HGCD_LEHMER_ITCH): Deleted macro.
+
+	* tune/speed.c (routine): Added mpn_hgcd_appr_lehmer.
+
+	* tune/common.c (speed_mpn_hgcd_lehmer): Use mpn_hgcd_lehmer_itch
+	rather than similarly named macro.
+	(speed_mpn_hgcd_appr_lehmer): New function.
+
+	* tune/Makefile.am (libspeed_la_SOURCES): Added
+	hgcd_appr_lehmer.c.
+
+	* tune/hgcd_appr_lehmer.c: New file.
+
+	* tune/tuneup.c (tune_hgcd_appr): Increased min_size to 50; some
+	machines got small thresholds which appear to be bogus.
+
+2011-11-15  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/powm_sec.c (mpn_local_sqr): Remove forgotten TMP_* calls.
+	(redcify): Likewise.
+	(mpn_powm_sec): Likewise.
+
+	* mpn/generic/powm_sec.c (mpn_powm_sec): Rework scratch usage
+	(mpn_powm_sec_itch): Rewrite.
+
+	* mpn/generic/powm_sec.c (mpn_powm_sec): Use mpn_tabselect also in
+	initialisation.
+
+	* configure.in: Amend 2011-11-03 gcc_cflags change.
+
+	* mpn/powerpc64/tabselect.asm: New file.
+	* mpn/x86_64/tabselect.asm: New file.
+	* mpn/x86/tabselect.asm: New file.
+	* mpn/ia64/tabselect.asm: New file.
+
+	* mpn/asm-defs.m4 (define_mpn): Add tabselect.
+
+	* configure.in (gmp_mpn_functions): Add tabselect.
+	(HAVE_NATIVE): Add entries for addncd_n, subcnd_n, tabselect.
+
+	* mpn/generic/powm_sec.c: Remove mpn_tabselect implementation.
+	* mpn/generic/tabselect.c: New file with removed code.
+
+2011-11-13  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tune/Makefile.am (TUNE_MPN_SRCS_BASIC): Add powm_sec.c.
+
+	* mpn/generic/powm_sec.c (win_size): Use POWM_SEC_TABLE
+	(POWM_SEC_TABLE): Define default.
+
+	* tune/tuneup.c (tune_powm_sec): New function computing POWM_SEC_TABLE.
+	(all): Call new function.
+
+	* mpn/generic/powm_sec.c (win_size): Define only when
+	TUNE_PROGRAM_BUILD is not set.
+
+2011-11-13  Niels Möller  <nisse@lysator.liu.se>
+
+	* tune/tuneup.c (tune_hgcd_appr): Use default min_size.
+	(tune_hgcd_reduce): Increase max_size and step_factor, to 7000
+	and 0.04, respectively.
+
+2011-11-11  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/powerpc64/mode64/sqr_diag_addlsh1.asm: Remove.
+
+2011-11-11  Niels Möller  <nisse@lysator.liu.se>
+
+	* tune/hgcd_reduce_2.c: New file.
+	* tune/hgcd_reduce_1.c: New file.
+
+	* tune/tuneup.c (hgcd_appr_threshold): New threshold variable.
+	(hgcd_reduce_threshold): Likewise.
+	(tune_hgcd_appr): New function.
+	(tune_hgcd_reduce): New function.
+	(all): Call tune_hgcd_appr and tune_hgcd_reduce.
+
+	* tune/speed.h (speed_mpn_hgcd_reduce): Declaration.
+	(speed_mpn_hgcd_reduce_[12]): Likewise.
+	(mpn_hgcd_reduce_[12]): Likewise.
+	(SPEED_ROUTINE_MPN_HGCD_REDUCE_CALL): New macro.
+
+	* tune/speed.c (routine): Added mpn_hgcd_reduce,
+	mpn_hgcd_reduce_1, and mpn_hgcd_reduce_2.
+
+	* tune/common.c (speed_mpn_hgcd_reduce): New function.
+	(speed_mpn_hgcd_reduce_[12]): Likewise.
+
+	* tune/Makefile.am (libspeed_la_SOURCES): Added hgcd_reduce_1.c
+	hgcd_reduce_2.c.
+	(TUNE_MPN_SRCS_BASIC): Added hgcd_appr.c and hgcd_reduce.c.
+
+	* mpn/generic/hgcd_appr.c (submul, hgcd_matrix_apply): Deleted
+	functions, earlier copied to hgcd_reduce.c.
+	(mpn_hgcd_appr): Use hgcd_reduce.
+
+2011-11-09  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/powerpc64/mode64/sqr_basecase.asm: New file.
+
+	* mpn/x86_64/aorscnd_n.asm: New file.
+
+	* tune/speed.c (routine): Add measuring of mpn_addcnd_n, mpn_subcnd_n.
+	* tune/common.c (speed_mpn_addcnd_n,speed_mpn_subcnd_n): New functions.
+	* tune/speed.h: Declare them.
+
+	* tests/devel/try.c: Add tests for mpn_addcnd_n and mpn_subcnd_n.
+	* tests/refmpn.c (refmpn_addcnd_n, refmpn_subcnd_n): New functions.
+	* tests/tests.h: Declare them.
+
+	* configure.in (gmp_mpn_functions): Add addcnd_n and subcnd_n.
+
+2011-11-07  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/redc_1.c: Just reduce U operand using Hensel norm, but
+	not fully canonically; leave add_n and conditional sub_n to caller.
+	Therefore omit R argument.
+
+	* mpn/generic/redc_1_sec.c: Remove.
+
+	* gmp-impl.h (mpn_redc_1): Update declaration.
+	(mpn_redc_1_sec): Remove declaration.
+
+	* configure.in (gmp_mpn_functions): Remove redc_1.
+
+	* mpn/x86_64/redc_1.asm: Adopt to new defined functionality/interface.
+	* tune/speed.h (SPEED_ROUTINE_REDC_1): Likewise.
+
+	* tests/refmpn.c (refmpn_redc_1): Likewise; also call refmpn_addmul_1
+	instead of mpn_addmul_1.
+
+	* mpn/generic/powm.c (MPN_REDC_1): New macro, use for mpn_redc_1.
+	* mpn/generic/powm_sec.c (MPN_REDC_1_SEC): New macro, use for
+	mpn_redc_1_sec.
+
+2011-11-03  Torbjorn Granlund  <tege@gmplib.org>
+
+	* dumbmp.c (mpz_sub): Abort for non-handled case.
+
+	* mpn/powerpc64/mode64/lshiftc.asm: Move file from here...
+	* mpn/powerpc64/lshiftc.asm: ...to here, with trivial modifications.
+
+	* configure.in: Pass -m32 in more cases, using _maybe mechanism.
+	Inherit default gcc_cflags in more places.
+
+	* mpn/powerpc64/mode64/p7/gmp-mparam.h: New file.
+
+2011-11-02  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/s390_64/invert_limb.asm: Slight optimisation.
+
+	* configure.in (s390): Set gcc_32_cflags_maybe.
+
+	* mpn/s390_32/gmp-mparam.h: Put in proper data.
+	* mpn/s390_32/esame/gmp-mparam.h: New file.
+
+	* mpn/x86_64/bobcat/gmp-mparam.h: New file.
+
+	* mpn/s390_32/lshift.asm: New file.
+	* mpn/s390_32/rshift.asm: New file.
+	* mpn/s390_32/lshiftc.asm: New file.
+
+2011-10-31  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/powerpc64/sqr_diagonal.asm: Move from here...
+	* mpn/powerpc64/mode32/sqr_diagonal.asm: ...to here.
+
+	* mpn/powerpc64/mode64/sqr_diag_addlsh1.asm: New file.
+
+	* mpn/s390_64/sqr_basecase.asm: Rewrite sqr_diag_addlsh1 code.
+	* mpn/s390_32/esame/sqr_basecase.asm: Likewise.
+
+2011-10-29  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/s390_64/lshift.asm: Complete rewrite.
+	* mpn/s390_64/rshift.asm: Likewise.
+
+	* mpn/s390_64/lshiftc.asm: New file.
+
+2011-10-28  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/s390_32/esame/aors_n.asm: New file, with rewritten add/sub code.
+
+2011-10-27  Torbjorn Granlund  <tege@gmplib.org>
+
+	From Per Olofsson:
+	* gmp-impl.h (BSWAP_LIMB): Rename variable to avoid BSWAP_LIMB_FETCH
+	clash.
+
+	* mpn/s390_32/esame/mul_basecase.asm: New file.
+
+	* mpn/s390_32/esame/sqr_basecase.asm: New file.
+
+	* mpn/s390_32/logops_n.asm: New file.
+
+	* mpn/s390_64/logops_n.asm: Fix rp=up code.  Remove a leftover insn.
+
+2011-10-26  Niels Möller  <nisse@lysator.liu.se>
+
+	* gmp-impl.h (mpn_hgcd_reduce, mpn_hgcd_reduce_itch): Added
+	prototypes.
+	(HGCD_APPR_THRESHOLD): Set up threshold for tuning.
+	(HGCD_REDUCE_THRESHOLD): Likewise.
+
+	* configure.in (gmp_mpn_functions): Added hgcd_reduce.
+
+	* mpn/generic/hgcd_reduce.c: New file.
+
+2011-10-24  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/sqr_basecase.asm: Put intermediate result into R, don't
+	allocate any stack space.
+
+2011-10-23  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/s390_64/logops_n.asm: Use nc, oc, xc when possible.
+
+	* tune/common.c (speed_mpn_and_n, speed_mpn_andn_n, etc):
+	Pass correct input args.
+
+	* mpn/s390_64/mod_34lsub1.asm: Use llgfr for zero extensions.
+
+	* mpn/s390_64/mul_basecase.asm: New file.
+
+	* mpn/s390_64/sqr_basecase.asm: New file.
+	* mpn/s390_64/sqr_diag_addlsh1.asm: Removed, lives on in sqr_basecase.
+
+	* mpn/s390_64/bdiv_dbm1c.asm: Shave off 1 c/l.
+
+	* mpn/s390_64/aorrlsh1_n.asm: New file, developed from aorslsh1_n.asm.
+	* mpn/s390_64/sublsh1_n.asm: New file.
+	* mpn/s390_64/aorslsh1_n.asm: Remove file.
+
+2011-10-22  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/s390_64/logops_n.asm: New file.
+
+	* mpn/s390_64/aors_n.asm: New file, with rewritten add/sub code.
+
+2011-10-20  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tune/speed.h (SPEED_ROUTINE_MPN_SQR_DIAL_ADDLSH1_CALL): New macro.
+	* tune/common.c (speed_mpn_sqr_diag_addlsh1): New function.
+	* tune/speed.c (routine): Measure mpn_sqr_diag_addlsh1.
+
+	* mpn/s390_64/sqr_diag_addlsh1.asm: Rewrite like s390_32/esame code.
+
+	* mpn/s390_32/esame/sqr_diag_addlsh1.asm: Save just needed registers.
+
+2011-10-19  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/s390_32/esame/add_n.asm: Rewrite, similar to s390_64 code.
+	* mpn/s390_32/esame/add_n.asm: Likewise.
+
+2011-10-17  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/s390_32/esame/aorslsh1_n.asm: New file.
+
+2011-10-16  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/s390_32/esame/sqr_diag_addlsh1.asm: New file.
+
+	* mpn/s390_32/copyi.asm: New file.
+	* mpn/s390_32/copyd.asm: New file.
+
+	* mpn/s390_64/copyd.asm: Optimise.
+
+	* mpn/s390_64/copyi.asm: Rewrite along the lines of glibc memcpy.
+
+	* mpn/s390_64/aorslsh1_n.asm: New file.
+
+	* mpn/s390_64/mod_34lsub1.asm: New file.
+
+	* mpn/s390_64/sqr_diag_addlsh1.asm: New file.
+
+2011-10-15  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.in (s390): Rewrite support to handle known CPUs.
+	* config.guess: Recognise s390 CPUs.
+	* config.sub: Match s390 CPUs.
+	* acinclude.m4 (S390_PATTERN, S390X_PATTERN): New defines.
+
+2011-10-14  Torbjorn Granlund  <tege@gmplib.org>
+
+	From Per Olofsson:
+	* mpn/generic/popham.c: Add __GMP_NOTHROW to make it match gmp.h.
+	* mpn/generic/gcd_1.c: Separate declarations and initialisers for the
+	benefit of C++.
+
+	* configure.in: AC_DEFINE HAVE_HOST_CPU_s390_zarch.
+	* longlong.h (s390): Use it.
+	(s390 umul_ppmm): Fix typo in pure C variant.
+
+2011-10-13  Torbjorn Granlund  <tege@gmplib.org>
+
+	* longlong.h (s390): Put back an accidentally deleted #else.
+
+	* configure.in (s390): Unset extra_functions for s390x.
+
+2011-10-12  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/s390_64/lshift.asm: Reduce register usage.
+	* mpn/s390_64/rshift.asm: Likewise.
+
+	* longlong.h (s390 umul_ppmm): With new-enough gcc, avoid asm.
+
+	From Andreas Krebbel:
+	* longlong.h (s390 umul_ppmm): Support 32-bit limbs with gcc using
+	64-bit registers.
+	(s390 udiv_qrnnd): Likewise.
+
+2011-10-11  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.in (s390x): Pass -mzarch to gcc in 32-bit mode.
+
+	* longlong.h (s390x): Add __CLOBBER_CC for relevant asm patterns.
+	* mpn/generic/mod_1_1.c (s390x add_mssaaaa): Likewise.
+
+	* mpn/s390_64/copyd.asm: New file.
+
+2011-10-10  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/hgcd_appr.c: Deleted debugging code.
+
+	* tests/mpn/t-hgcd_appr.c (main): Added -v flag.
+	(hgcd_appr_valid_p): Increased margin of non-minimality for
+	divide-and-conquer algorithm. Display bit counts only if
+	-v is used.
+
+	* mpn/generic/hgcd_appr.c (submul): New (static) function.
+	(hgcd_matrix_apply): New function.
+	(mpn_hgcd_appr_itch): Account for divide-and-conquer algorithm.
+	(mpn_hgcd_appr): Implemented divide-and-conquer.
+
+2011-10-10  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/mod_1_1.c (add_mssaaaa): Add s390x variant.  Put arm code
+	inside __GNUC__.
+
+	* tune/time.c (STCK): Use proper memory constraint.
+
+	From Marco Trudel:
+	* tests/mpz/t-scan.c (check_ref): Fix loop end bound.
+
+2011-10-10  Niels Möller  <nisse@lysator.liu.se>
+
+	* gmp-impl.h: (HGCD_APPR_THRESHOLD): New threshold.
+
+	* mpn/generic/hgcd_appr.c (mpn_hgcd_appr): Interface change.
+	Destroy inputs, let caller make working copies if needed.
+	(mpn_hgcd_appr_itch): Reduced scratch need.
+	* gmp-impl.h: Updated mpn_hgcd_appr prototype.
+	* tests/mpn/t-hgcd_appr.c (one_test): Make working copies for
+	hgcd_appr.
+	* tune/common.c (speed_mpn_hgcd_appr): Use SPEED_ROUTINE_MPN_HGCD_CALL.
+	* tune/speed.h (SPEED_ROUTINE_MPN_HGCD_APPR_CALL): Deleted.
+
+2011-10-09  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/s390_64/copyi.asm: New file.
+	* mpn/s390_64/lshift.asm: New file.
+	* mpn/s390_64/rshift.asm: New file.
+
+	* mpn/s390_64/add_n.asm: Rewrite using lmg/stmg.
+	* mpn/s390_64/sub_n.asm: Likewise.
+
+	* mpn/s390_64/invert_limb.asm: Save a callee-saves register less.
+
+	* tune/time.c (getrusage_backwards_p): Properly cast printed values.
+
+	* longlong.h (s390x): Put back UDItype casts to make gcc reloading use
+	right more for constants.
+	(s390x count_leading_zeros): Disable until we support z10 specifically.
+	(s390x add_ssaaaa): Remove algsi/slgsi until we support z10.
+
+2011-10-09  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/hgcd_matrix.c (mpn_hgcd_matrix_adjust): Declare
+	matrix argument const.
+
+2011-10-08  Niels Möller  <nisse@lysator.liu.se>
+
+	* tests/mpn/t-hgcd_appr.c (hgcd_appr_valid_p): Adjusted the
+	allowed margin of non-minimality for hgcd_appr.
+
+	* mpn/generic/hgcd_appr.c (mpn_hgcd_appr): Fixed handling of
+	extra_bits, starting at zero, to ensure that we don't produce too
+	small remainders. Added a final reduction loop when we we
+	otherwise terminate with extra_bits > 0, to make the returned
+	remainders closer to minimal.
+
+2011-10-07  Torbjorn Granlund  <tege@gmplib.org>
+
+	* longlong.h (s390): Add 32-bit zarch umul_ppmm and udiv_qrnnd.
+	(s390): Overhaul 32-bit and 64-bit code.
+
+2011-10-07  Niels Möller  <nisse@lysator.liu.se>
+
+	* tune/speed.h (speed_mpn_hgcd_appr): New prototype.
+	(SPEED_ROUTINE_MPN_HGCD_APPR_CALL): New macro.
+	* tune/common.c (speed_mpn_hgcd_appr): New function.
+	* tune/speed.c (routine): Added mpn_hgcd_appr.
+
+	* tests/mpn/t-hgcd_appr.c: New file.
+	* tests/mpn/Makefile.am (check_PROGRAMS): Added t-hgcd_appr.
+
+	* configure.in (gmp_mpn_functions): Added hgcd_step and hgcd_appr.
+
+	* gmp-impl.h: Added prototypes for mpn_hgcd_step,
+	mpn_hgcd_appr_itch and mpn_hgcd_appr.
+
+	* mpn/generic/hgcd_appr.c: New file.
+
+	* mpn/generic/hgcd_step.c: New file, extracted from hgcd.c.
+	(mpn_hgcd_step): Renamed, from...
+	* mpn/generic/hgcd.c (hgcd_step): ...old name. Renamed and moved
+	to hgcd_step.c.
+	(hgcd_hook): Also moved to hgcd_step.c.
+	(mpn_hgcd): Updated for hgcd_step renaming.
+
+2011-10-06  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/s390_64/invert_limb.asm: New file.
+
+2011-10-04  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/s390_64/submul_1.asm: New file.
+	* mpn/s390_32/esame/submul_1.asm: New file.
+
+	* mpn/generic/mulmid.c (mpn_mulmid): Move a TMP_DECL to block start.
+
+	* mpn/Makefile.am (TARG_DIST): Add s390_32 and s390_64, remove s390 and
+	z8000x.
+
+	* doc/gmp.texi (Custom Allocation): Rephrase a paragraph.
+
+	* demos/factorize.c: Run 25 Miller-Rabin tests.
+
+	* mpz/nextprime.c: Run 25 mpz_millerrabin tests (was 10).
+
+2011-10-03  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.in: Support s390x.
+
+	* longlong.h: Add support for 64-bit s390x.
+
+	* mpn/s390_64: New directory.
+	* mpn/s390_64/add_n.asm: New file.
+	* mpn/s390_64/sub_n.asm: New file.
+	* mpn/s390_64/mul_1.asm: New file.
+	* mpn/s390_64/addmul_1.asm: New file.
+	* mpn/s390_64/bdiv_dbm1c.asm: New file.
+	* mpn/s390_64/gmp-mparam.h: New file, taken from x86_64.
+
+	* mpn/s390_32: Directory renamed from mpn/s390.
+	* mpn/s390_32/gmp-mparam.h: New file, taken from x86_64.
+	* mpn/s390_32/esame/add_n.asm: New file.
+	* mpn/s390_32/esame/sub_n.asm: New file.
+	* mpn/s390_32/esame/mul_1.asm: New file.
+	* mpn/s390_32/esame/addmul_1.asm: New file.
+	* mpn/s390_32/esame/bdiv_dbm1c.asm: New file.
+
+2011-10-03  Niels Möller  <nisse@lysator.liu.se>
+
+	* tests/mpn/Makefile.am (check_PROGRAMS): Added t-mulmid.
+	* tests/mpn/t-mulmid.c: New file.
+
+	mulmid-related assembly for x86_64, from David Harvey:
+	* mpn/asm-defs.m4 (define_mpn): Added [add,sub]_err[1,2,3]_n and
+	mulmid_basecase. Also use m4_not_for_expansion on the
+	corresponding OPERATION_* symbols.
+	* mpn/x86_64/aors_err1_n.asm: New file.
+	* mpn/x86_64/aors_err2_n.asm: Likewise.
+	* mpn/x86_64/aors_err3_n.asm: Likewise.
+	* mpn/x86_64/mulmid_basecase.asm: Likewise.
+	* mpn/x86_64/core2/aors_err1_n.asm: Likewise.
+	* mpn/x86_64/gmp-mparam.h (MULMID_TOOM42_THRESHOLD): New value.
+	* mpn/x86_64/core2/gmp-mparam.h (MULMID_TOOM42_THRESHOLD): Likewise.
+
+	Tuning of mulmid, from David Harvey:
+	* tune/Makefile.am (TUNE_MPN_SRCS_BASIC): Added mulmid.c
+	mulmid_n.c toom42_mulmid.c.
+	* tune/speed.h: Prototypes for mulmid-related functions.
+	(struct speed_params): Increased max number of sources to 5.
+	(SPEED_ROUTINE_MPN_BINARY_ERR_N_CALL): New macro.
+	(SPEED_ROUTINE_MPN_BINARY_ERR1_N): Likewise.
+	(SPEED_ROUTINE_MPN_BINARY_ERR2_N): Likewise.
+	(SPEED_ROUTINE_MPN_BINARY_ERR3_N): Likewise.
+	(SPEED_ROUTINE_MPN_MULMID): Likewise.
+	(SPEED_ROUTINE_MPN_MULMID_N): Likewise.
+	(SPEED_ROUTINE_MPN_TOOM42_MULMID): Likewise.
+	* tune/common.c (mpn_[add,sub]_err[1,2,3]_n): New functions.
+	(speed_mpn_mulmid_basecase): New function.
+	(speed_mpn_mulmid): New function.
+	(speed_mpn_mulmid_n): New function.
+	(speed_mpn_toom42_mulmid): New function.
+	* tune/speed.c (routine): Added mpn_[add,sub]_err[1,2,3]_n,
+	mpn_mulmid_basecase, mpn_toom42_mulmid, mpn_mulmid_n, and
+	mpn_mulmid.
+	* tune/tuneup.c (mulmid_toom42_threshold): New threshold variable.
+	(tune_mulmid): New function.
+	(all): Call tune_mulmid.
+
+	Testing of mulmid, from David Harvey:
+	* tests/refmpn.c (AORS_ERR1_N): New macro.
+	(refmpn_add_err1_n, refmpn_sub_err1_n): New functions.
+	(AORS_ERR2_N): New macro.
+	(refmpn_add_err2_n, refmpn_sub_err2_n): New functions.
+	(AORS_ERR3_N): New macro.
+	(refmpn_add_err3_n, refmpn_sub_err3_n): New functions.
+	(refmpn_mulmid_basecase): New function.
+	(refmpn_toom42_mulmid): New function, wrapper for
+	refmpn_mulmid_basecase.
+	(refmpn_mulmid_n): Likewise.
+	(refmpn_mulmid): Likewise.
+	* tests/tests.h: Prototypes for new functions.
+	* tests/devel/try.c (NUM_SOURCES): Increased to 5.
+	(struct try_t): Use NUM_SOURCES and NUM_DESTS constants.
+	(SIZE_4, SIZE_6, SIZE_DIFF_PLUS_3, SIZE_ODD): New constants.
+	(OVERLAP_NOT_DST2): New flag.
+	(param_init): New mulmid-related operation types.
+	(mpn_toom42_mulmid_fun): New function.
+	(choice_array): Added mulmid-related entries.
+	(overlap_array): Extended for larger NUM_SOURCES.
+	(OVERLAP_COUNT): Handle OVERLAP_NOT_DST2.
+	(call): Support mulmid-related functions.
+	(pointer_setup): Handle SIZE_4, SIZE_6, and SIZE_DIFF_PLUS_3.
+	(SIZE_ITERATION): Handle SIZE_ODD.
+	(SIZE2_FIRST): Handle SIZE_CEIL_HALF.
+	(SIZE2_LAST): Likewise.
+
+	Implementation of mulmid, from David Harvey:
+	* mpn/generic/add_err1_n.c (mpn_add_err1_n): New file and function.
+	* mpn/generic/add_err2_n.c (mpn_add_err2_n): Likewise.
+	* mpn/generic/add_err3_n.c (mpn_add_err3_n): Likewise.
+	* mpn/generic/sub_err1_n.c (mpn_sub_err1_n): Likewise.
+	* mpn/generic/sub_err2_n.c (mpn_sub_err2_n): Likewise.
+	* mpn/generic/sub_err3_n.c (mpn_sub_err3_n): Likewise.
+	* mpn/generic/mulmid_basecase.c (mpn_mulmid_basecase): Likewise.
+	* mpn/generic/mulmid_n.c (mpn_mulmid_n): Likewise.
+	* mpn/generic/toom42_mulmid.c (mpn_toom42_mulmid): Likewise.
+	* configure.in (gmp_mpn_functions): Added mulmid-related
+	functions.
+	(GMP_MULFUNC_CHOICES): Handle aors_err1_n, aors_err2_n, and
+	aors_err3_n.
+	* gmp-impl.h: Added prototypes for mulmid functions.
+	(MPN_TOOM42_MULMID_MINSIZE): New constant.
+	(MULMID_TOOM42_THRESHOLD): New threshold.
+	(mpn_toom42_mulmid_itch): New macro.
+
+2011-10-03  Niels Möller  <nisse@lysator.liu.se>
+
+	* tune/tune-gcd-p.c (main): Fixed broken loop conditions.
+
+2011-09-26  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/sh/sh2/submul_1.asm: Make this old submul_1 implementation
+	actually compute intended function.
+
+	* longlong.h (SH): Recognise predefs for all SH processors as defined
+	by current gcc versions.
+
+2011-09-25  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/sh: Migrate files to '.asm'.
+	* configure.in: Recognise sh3 and sh4.
+
+2011-09-21  Marc Glisse  <marc.glisse@inria.fr>
+
+	* gmpxx.h (mpz_class::swap): New function.
+	(mpq_class::swap): Likewise.
+	(mpf_class::swap): Likewise.
+	(swap): New function.
+	* tests/cxx/t-assign.cc: Test the above.
+	* doc/gmp.texi (swap): Document the above.
+
+2011-08-21  Marc Glisse  <marc.glisse@inria.fr>
+
+	* tests/cxx/t-ops2.cc: check mul-div by 2.
+
+	* gmpxx.h (__GMPXX_CONSTANT): New macro (__builtin_constant_p).
+	(__gmp_binary_lshift): Move before multiplication. Optimize x << 0.
+	(__gmp_binary_rshift): Move before division. Optimize x >> 0.
+	(__gmp_binary_plus): Optimize x + 0. Rewrite rational + integer.
+	(__gmp_binary_minus): Optimize x - 0 and 0 - x.
+	Rewrite rational - integer.
+	(__gmp_binary_multiplies): Optimize x * 2^n.
+	(__gmp_binary_divides): Optimize x / 2^n.
+	(__gmp_binary_*): Deduplicate code for symmetric operations.
+
+2011-08-18  Torbjorn Granlund  <tege@gmplib.org>
+
+	* printf/doprntf.c (__gmp_doprnt_mpf): For DOPRNT_CONV_FIXED, ask for
+	one more digit.
+
+2011-08-17  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpf/sub.c: Fix typo in copy condition.  Delay an allocation.
+
+2011-08-12  Torbjorn Granlund  <tege@gmplib.org>
+
+	* gmp-impl.h (LIMBS_PER_DIGIT_IN_BASE): Fix typo.
+
+2011-08-10  Torbjorn Granlund  <tege@gmplib.org>
+
+	* gmp-impl.h (DIGITS_IN_BASEGT2_FROM_BITS): New.
+	(DIGITS_IN_BASE_FROM_BITS): Compute more accurate result.
+	(MPN_SIZEINBASE): Use DIGITS_IN_BASEGT2_FROM_BITS.
+
+	* tests/rand/t-lc2exp.c (check_bigc): Call abort after reporting error.
+
+2011-08-09  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpz/out_str.c (mpz_out_str): Reinsert accidentally deleted str_size
+	adjustment.
+
+	* gmp-impl.h (DIGITS_IN_BASE_FROM_BITS): Simplify, also avoiding
+	overflow for base 2.
+
+2011-08-07  Torbjorn Granlund  <tege@gmplib.org>
+
+	* gmp-impl.h (struct bases): Add log2b and logb2 field, remove
+	chars_per_limb_exactly field.
+	(DIGITS_IN_BASE_FROM_BITS): New.
+	(DIGITS_IN_BASE_PER_LIMB): New.
+	(LIMBS_PER_DIGIT_IN_BASE): New.
+	* gen-bases.c: Generate log2b and logb2 fields; do not generate
+	chars_per_limb_exactly field.
+	* mpf/get_str.c mpf/out_str.c mpf/set_str.c mpn/generic/get_str.c
+	  mpn/generic/sizeinbase.c mpq/get_str.c mpz/inp_str.c mpz/out_str.c
+	  mpz/set_str.c printf/doprntf.c tune/speed.h tune/tuneup.c:
+	Use new macros.
+
+2011-08-04  Torbjorn Granlund  <tege@gmplib.org>
+
+	* dumbmp.c (mpz_root): Reinsert accidentally removed line.
+
+2011-08-03  Torbjorn Granlund  <tege@gmplib.org>
+
+	* dumbmp.c (mpz_tdiv_qr): Correctly handle dividend value being equal
+	to divisor value.
+	(mpz_root): Create reasonable starting approximation.
+	(mpz_sqrt): New function.
+	(mpz_mul_2exp): Add faster block shifting code, disabled for now.
+
+2011-07-15  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/arm/invert_limb.asm: Swap around some registers to silence 'as'
+	warnings.
+
+2011-07-14  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/dcpi1_bdiv_q.c (mpn_dcpi1_bdiv_q): Get mpn_sub_1 size
+	argument right.
+
+2011-07-04  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/misc/t-locale.c: Disable test for mingw.
+
+	* configure.in (x86_64 *-*-mingw*): Handle also cygwin here; clear out
+	extra_functions_64.
+
+2011-07-02  Torbjorn Granlund  <tege@gmplib.org>
+
+	* config.guess: Don't print newline in x86 cpuid function.
+	Rewrite x86-64 cpu recognition asm code to work under Windoze.
+
+2011-06-16  Torbjorn Granlund  <tege@gmplib.org>
+
+	* acinclude.m4 (GMP_ASM_RODATA): Fix typo in 2011-04-20 change.
+
+	* configure.in: Surround tr ranges with [] for portability.
+
+2011-05-25  Niels Möller  <nisse@lysator.liu.se>
+
+	* tune/tune-gcd-p.c (search): New function to search for minimum.
+	(main): Replaced slow linear search.
+
+2011-05-24  Niels Möller  <nisse@lysator.liu.se>
+
+	* tune/Makefile.am (EXTRA_PROGRAMS): Added tune-gcd-p. Also added
+	related automake variables.
+
+	* mpn/Makefile.am (tune-gcd-p): Deleted target.
+
+	* tune/tune-gcd-p.c: New file, extracted from mpn/generic/gcd.c
+	and updated.
+	* mpn/generic/gcd.c: Deleted the corresponding code, including
+	main function.
+
+2011-05-23  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpz/jacobi.c (mpz_jacobi): Simplified by swapping operands when
+	needed, to get asize >= bsize. Use the reciprocity law generalized
+	to work when one operand is even.
+
+2011-05-22  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpz/jacobi.c (mpz_jacobi): Another bugfix for the asize == 1
+	case. Sometimes, powers of two in b were taken into account twice.
+
+2011-05-21  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpz/jacobi.c (mpz_jacobi): The handling of asize == 1 was
+	broken. Rewrote it.
+
+	* tests/mpz/t-jac.c (mpz_nextprime_step): Sanity check that prime
+	candidate and step has no common factor.
+	(check_data): Added some test cases related to the asize == 1 case
+	in mpz_jacobi.
+
+2011-05-20  Niels Möller  <nisse@lysator.liu.se>
+
+	* gmp-impl.h: Jacobi-related prototypes.
+
+	* configure.in (gmp_mpn_functions): Added jacobi_2, jacobi,
+	hgcd2_jacobi, hgcd_jacobi, and removed jacobi_lehmer.
+
+	* mpz/jacobi.c (STRIP_TWOS): Deleted macro.
+	(mpz_jacobi): Partially rewritten, to no longer makes the A
+	operand odd. Use new mpn_jacobi_n.
+
+	* mpn/generic/jacobi_lehmer.c: Deleted file.
+
+	* mpn/generic/jacobi.c (mpn_jacobi_n): New subquadratic jacobi
+	implementation. Supersedes jacobi_lehmer.c.
+
+	* mpn/generic/hgcd_jacobi.c (mpn_hgcd_jacobi): New file and
+	function. A copy of mpn_hgcd, using mpn_hgcd2_jacobi, and with calls to
+	mpn_jacobi_update when appropriate.
+
+	* mpn/generic/jacobi_2.c (mpn_jacobi_2): New file. Extracted from
+	jacobi_lehmer.c.
+	* mpn/generic/hgcd2_jacobi.c (mpn_hgcd2_jacobi): Likewise.
+
+	* mpn/generic/hgcd.c (hgcd_hook): Avoid using NULL.
+
+2011-05-19  Niels Möller  <nisse@lysator.liu.se>
+
+	* tune/hgcd_lehmer.c (__gmpn_hgcd_itch): Don't rename symbols for
+	the functions moved to hgcd_matrix.c.
+
+	* configure.in (gmp_mpn_functions): Added hgcd_matrix.
+
+	* mpn/generic/hgcd.c (hgcd_matrix_update_1): Deleted. Several other
+	helper functions moved to hgcd_matrix.c, see below.
+	(hgcd_hook): New function.
+	(hgcd_step): Simplified, using mpn_gcd_subdiv_step and hgcd_hook.
+
+	* mpn/generic/hgcd_matrix.c: New file.
+	(mpn_hgcd_matrix_init): Moved here, from hgcd.c.
+	(mpn_hgcd_matrix_update_q): Likewise.
+	(mpn_hgcd_matrix_mul_1): Likewise.
+	(mpn_hgcd_matrix_mul): Likewise.
+	(mpn_hgcd_matrix_adjust): Likewise.
+
+	* mpn/generic/gcd_subdiv_step.c (mpn_gcd_subdiv_step): New
+	argument s, for use by hgcd.
+	* gmp-impl.h (mpn_gcd_subdiv_step): Update declaration.
+
+	* mpn/generic/gcd.c (mpn_gcd): Pass s = 0 to mpn_gcd_subdiv_step.
+	* mpn/generic/gcdext.c (mpn_gcdext): Likewise. Also added an ASSERT.
+	* mpn/generic/gcdext_lehmer.c (mpn_gcdext_lehmer_n): Likewise.
+	(mpn_gcdext_hook): Added some ASSERTs.
+	* mpn/generic/jacobi_lehmer.c (mpn_jacobi_lehmer): Likewise.
+
+2011-05-17  Niels Möller  <nisse@lysator.liu.se>
+
+	* doc/gmp.texi (mpn_gcd, mpn_gcdext): Document input requirements:
+	Must have un >= vn > 0, and V normalized.
+	* mpn/generic/gcdext.c (mpn_gcdext): Added ASSERT for input
+	normalization.
+	* mpn/generic/gcd.c (mpn_gcd): Added ASSERTs for input
+	requirements.
+
+2011-05-15  Marc Glisse  <marc.glisse@inria.fr>
+
+	* gmpxx.h (operator<<): Dedup.
+	* tests/cxx/t-iostream.cc: Test on compound types.
+
+	* gmpxx.h (__gmp_binary_expr): Let things happen in place: c=(a+b)/2.
+
+2011-05-10  Marc Glisse  <marc.glisse@inria.fr>
+
+	* gmpxx.h (__gmp_unary_expr): Let things happen in place: c=-(a+b).
+	(operator>>): Clean the commenting out.
+	* tests/cxx/t-iostream.cc: New file.
+	* tests/cxx/Makefile.am: Added t-iostream.
+
+2011-05-10  Niels Möller  <nisse@lysator.liu.se>
+
+	* doc/gmp.texi (mpz_gcd): Document that gcd(0,0) = 0.
+	(mpz_gcdext): Document range for cofactors.
+
+2011-05-09  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpz/gcdext.c (mpz_gcdext): Increased sp allocation to bsize+1 limbs.
+	* doc/gmp.texi (mpn_gcdext): Fixed documentation of allocation
+	requirements; one extra limb is still needed for S.
+
+2011-05-09  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86/fat/gmp-mparam.h (BMOD_1_TO_MOD_1_THRESHOLD): Define.
+	* mpn/x86_64/fat/gmp-mparam.h (BMOD_1_TO_MOD_1_THRESHOLD): Define.
+
+2011-05-08  Marc Glisse  <marc.glisse@inria.fr>
+
+	* gmpxx.h: Replace unsigned long with mp_bitcnt_t in many places.
+	* doc/gmp.texi: Likewise.
+
+2011-05-06  Marc Glisse  <marc.glisse@inria.fr>
+
+	* gmpxx.h (mpz_class): Make constructor from mp[qf]_class explicit.
+	(mpq_class): Make constructor from mpf_class explicit.
+	* doc/gmp.texi: Document the above.
+	* NEWS: Likewise, and mention the EOF istream fix.
+	* tests/cxx/t-mix.cc: New file.
+	* tests/cxx/Makefile.am: Added t-mix.
+
+	* tests/cxx/t-assign.cc: Minor tweak.
+	* tests/cxx/t-misc.cc: Likewise.
+
+	* gmpxx.h (__gmp_resolve_temp): Remove.
+	(__gmp_set_expr): Remove some overloads.
+	(mpq_class): mpz_init_set the numerator and denominator instead of
+	mpq_init + mpq_set.
+	(mpz_class): Dedup the string constructors.
+	(mpq_class): Likewise.
+
+	* tests/cxx/t-ops3.cc: New file.
+	* tests/cxx/Makefile.am: Added t-ops3.
+
+2011-05-05  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpz/gcdext.c: Correct sgn computation.
+	Use MPZ_REALLOC.
+
+2011-05-05  Marc Glisse  <marc.glisse@inria.fr>
+
+	* mpn/x86_64/fat/fat.c: Update for Sandy Bridge.
+	* config.guess: warning to keep it in sync with fat.c.
+
+2011-05-05  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/fat/fat_entry.asm (PIC_OR_DARWIN): New symbol.  Use it to
+	work around Darwin problems.
+
+2011-05-04  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpz/gcdext.c (mpz_gcdext): Reduced temporary allocations. Use
+	mpz_divexact when computing the second cofactor.
+
+2011-05-03  David Harvey  <dmharvey@cims.nyu.edu>
+
+	* configure.in: make invert_limb_table work correctly with
+	--disable-assembly (from Niels Möller)
+
+2011-05-02  Marc Glisse  <marc.glisse@inria.fr>
+
+	* .bootstrap: libtoolize doesn't need -c.
+
+	* configfsf.guess: Update to version of 2011-02-02.
+	* configfsf.sub: Update to version of 2011-03-23.
+
+2011-05-02  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpz/gcdext.c (mpz_gcdext): Don't allocate extra limbs at the end
+	of mpn_gcdext parameters.
+
+	* doc/gmp.texi (mpn_gcdext): Updated doc.
+
+2011-05-01  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/div_qr_2u_pi1.c (mpn_div_qr_2u_pi1): Fixed ASSERT.
+
+2011-04-30  Marc Glisse  <marc.glisse@inria.fr>
+
+	* gmp-h.in (mpz_cdiv_q_2exp): Use mp_bitcnt_t to match the definition
+	and the documentation.
+	(mpz_remove): Likewise.
+	(mpf_eq): Likewise.
+
+	* ltmain.sh: Remove.
+	* .bootstrap: Let libtoolize generate ltmain.sh.
+
+	* tests/cxx/t-ops2.cc: Add a couple tests.
+	* tests/cxx/t-rand.cc: Likewise.
+
+	* doc/gmp.texi (mpf_urandomb): Explicit the fact that it does not
+	change the precision.
+
+	* gmp-h.in (__GMP_EXTERN_INLINE): Recent g++ uses gnu_inline.
+
+2011-04-28  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.in (x86_64): Support bobcat specifically.
+	(x86): Match bobcat and bulldozer, handle like k10.
+
+2011-04-28  David Harvey  <dmharvey@cims.nyu.edu>
+
+	* README.HG: update autotools version numbers.
+
+2011-04-27  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tune/speed.h (speed_cyclecounter): Always use PIC variant when
+	compiled with Apple's GCC.
+
+	* mpn/x86/darwin.m4 (LEA): Complete rewrite.
+	(m4append): New macro.
+
+2011-04-26  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/sparc32/sparc-defs.m4 (changecom): Don't redefine '!' as it
+	interferes with expressions.
+
+2011-04-20  Torbjorn Granlund  <tege@gmplib.org>
+
+	* acinclude.m4 (GMP_ASM_RODATA): Make 'foo' larger to avoid clang
+	problems.
+
+2011-04-12  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/x86_64/invert_limb.asm [PIC]: Declare mpn_invert_limb_table
+	as .protected.
+
+2011-04-11  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86/k7/invert_limb.asm: Use deflit for Darwin bug workaround.
+	Undo 2011-03-28 change.
+
+	* mpn/asm-defs.m4 (define_mpn): Use deflit.
+
+2011-04-10  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/asm-defs.m4 (define_mpn): Added invert_limb_table.
+
+	* configure.in: Add invert_limb_table to extra_functions_64 on
+	x86_64.
+
+	* mpn/x86_64/invert_limb.asm: Changed references from approx_tab
+	mpn_invert_limb_table.
+
+	* mpn/x86_64/invert_limb_table.asm (mpn_invert_limb_table): New
+	file. Extracted approximation table from invert_limb.asm, renamed
+	and made global.
+
+2011-03-30  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/x86_64/div_qr_2u_pi1.asm: New file.
+
+	* configure.in (gmp_mpn_functions): Add div_qr_2u_pi1.
+
+	* gmp-impl.h (mpn_div_qr_2u_pi1): Declare.
+
+	* mpn/generic/div_qr_2u_pi1.c (mpn_div_qr_2u_pi1): Moved to
+	separate file, from...
+	* mpn/generic/div_qr_2.c: ... old location.
+
+	* mpn/generic/div_qr_2n_pi1.c: Renamed file, from...
+	* mpn/generic/div_qr_2_pi1_norm.c: ...old name.
+	* mpn/x86_64/div_qr_2n_pi1.asm: Renamed file, from...
+	* mpn/x86_64/div_qr_2_pi1_norm.asm: ...old name.
+
+	* gmp-impl.h (mpn_div_qr_2n_pi1): Use new name in declaration.
+	* tune/speed.h (speed_mpn_div_qr_2n): Likewise.
+	(speed_mpn_div_qr_2u): Likewise.
+
+	* tune/tuneup.c (tune_div_qr_2): Use new name speed_mpn_div_qr_2n.
+
+	* tune/speed.c (routine): Use new names mpn_div_qr_2n and
+	mpn_div_qr_2u, also on the command line.
+
+	* tune/common.c (speed_mpn_div_qr_2n): Renamed, from...
+	(speed_mpn_div_qr_2_norm): ... old name.
+	(speed_mpn_div_qr_2u): Renamed, from...
+	(speed_mpn_div_qr_2_unnorm): ... old name.
+
+	* mpn/generic/div_qr_2_pi1_norm.c (mpn_div_qr_2n_pi1): Renamed,
+	from...
+	(mpn_div_qr_2_pi1_norm): ...old name.
+	* mpn/x86_64/div_qr_2_pi1_norm.asm: Likewise.
+
+	* mpn/generic/div_qr_2.c (mpn_div_qr_2n_pi2): Renamed, from...
+	(mpn_div_qr_2_pi2_norm): ... old name.
+	(mpn_div_qr_2u_pi1): Renamed, from...
+	(mpn_div_qr_2_pi1_unnorm): ... old name.
+	(mpn_div_qr_2): Call functions using new names.
+
+	* mpn/asm-defs.m4: Renamed div_qr_2-functions to new names.
+
+2011-03-29  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/x86_64/div_qr_2_pi1_norm.asm: Updated to use a separate rp
+	argument.
+
+	* gmp-impl.h (mpn_div_qr_2_pi1_norm): Updated declaration.
+	* gmp-h.in (mpn_div_qr_2): Likewise.
+
+	* tests/mpn/t-div.c (main): Adapted to new mpn_div_qr2 interface.
+	* tune/speed.h (SPEED_ROUTINE_MPN_DIV_QR_2): Likewise.
+
+	* mpn/generic/div_qr_2.c (mpn_div_qr_2_pi2_norm): Added rp
+	argument. Don't clobber the input dividend.
+	(mpn_div_qr_2_pi1_unnorm): Likewise.
+	(mpn_div_qr_2): Likewise.
+	* mpn/generic/div_qr_2_pi1_norm.c (mpn_div_qr_2_pi1_norm): Likewise.
+
+2011-03-29  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/x86/k7/invert_limb.asm: Use mov rather than push and pop.
+	Earlier load of divisor from stack.
+
+2011-03-28  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86/k7/invert_limb.asm: Protect movzwl register parameters from
+	being interpreted as m4 macro parameters.
+
+2011-03-22  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/x86_64/div_qr_2_pi1_norm.asm: Copied optimized inner loop
+	from divrem_2.asm.
+
+	* mpn/x86_64/div_qr_2_pi1_norm.asm: First working, but poorly
+	optimized, implementation.
+
+	* mpn/asm-defs.m4 (define_mpn): Added div_qr_2_pi[12]_*norm.
+
+	* mpn/generic/div_qr_2_pi1_norm.c (mpn_div_qr_2_pi1_norm): Moved
+	to separate file, from...
+	* mpn/generic/div_qr_2.c: ... old location.
+
+	* gmp-impl.h (mpn_div_qr_2_pi1_norm): Declare.
+
+	* configure.in (gmp_mpn_functions): Added div_qr_2_pi1_norm.
+
+2011-03-22  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.in (powerpc): Reinsert lost AIX cpu_path 32-bit handling.
+	Reinsert lost linux/bsd cpu_path handling.
+
+	* mpn/generic/mod_1_1.c: Disable powerpc asm for _LONG_LONG_LIMB.
+	* mpn/generic/div_qr_2.c: Likewise.
+
+	* mpn/generic/div_qr_2.c: Use asm just for gcc.
+	Make powerpc add_sssaaaa work for 32-bit case, and use less strict
+	constraints.
+
+2011-03-21  Niels Möller  <nisse@lysator.liu.se>
+
+	* tune/tuneup.c (div_qr_2_pi2_threshold): New global variable.
+	(tune_div_qr_2): New function.
+	(all): Call tune_div_qr_2.
+
+	* tune/Makefile.am (TUNE_MPN_SRCS_BASIC): Added div_qr_2.c.
+
+	* gmp-impl.h (DIV_QR_2_PI2_THRESHOLD): Setup for tuning.
+
+	New 4/2 division loop, based on Torbjörn's work:
+	* mpn/generic/div_qr_2.c (add_sssaaaa, add_csaac): New macros.
+	(udiv_qr_4by2): New macro.
+	(invert_4by2): New function.
+	(mpn_div_qr_2_pi2_norm): New function.
+	(DIV_QR_2_PI2_THRESHOLD): New threshold.
+	(mpn_div_qr_2_pi1_norm): Renamed, from...
+	(mpn_div_qr_2_norm): ... old name.
+	(mpn_div_qr_2_pi1_unnorm): Renamed, from...
+	(mpn_div_qr_2_unnorm): ... old name.
+	(mpn_div_qr_2): Use mpn_div_qr_2_pi2_norm for large enough
+	normalized divisors.
+
+	* gmp-impl.h (udiv_qr_3by2): Avoid a copy.
+
+2011-03-21  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.in (hppa): Under linux, treat 64-bit processors as if they
+	were 32-bit processors.
+
+	* mpn/generic/addcnd_n.c: New file.
+	* mpn/asm-defs.m4 (define_mpn): Add addcnd_n and subcnd_n.
+	* configure.in (gmp_mpn_functions): Add addcnd_n.
+	* gmp-impl.h (mpn_addcnd_n): Declare.
+
+	* mpn/generic/subcnd_n.c: Combine nails and non-nails functions.
+
+	* gmp-impl.h (invert_pi1): Prepend _ to local variables, protect
+	parameters within () where necessary.
+
+	* mpn/asm-defs.m4 (define_mpn): Add div_qr_2.
+	* configure.in (gmp_mpn_functions): Reinsert mercurial-bug-removed
+	line.
+
+2011-03-20  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.in (powerpc): Add cpu_path for all three ABIs.
+	Rename "aix64" to "mode64" for consistency.
+
+2011-03-16  Marc Glisse  <marc.glisse@inria.fr>
+
+	* gmpxx.h (__gmp_binary_not_equal): Remove, use !__gmp_binary_equal.
+	(__gmp_binary_less_equal): Remove, use !__gmp_binary_greater.
+	(__gmp_binary_greater_equal): Remove, use !__gmp_binary_less.
+	* tests/cxx/t-ops2.cc: Typo.
+
+2011-03-20  Niels Möller  <nisse@lysator.liu.se>
+
+	* tune/common.c (speed_mpn_div_qr_2_norm): New function.
+	(speed_mpn_div_qr_2_unnorm): New function.
+	* tune/speed.c (routine): Recognize above functions.
+	* tune/speed.h: Declarations for above functions.
+	(SPEED_ROUTINE_MPN_DIV_QR_2): New macro.
+
+	* tests/mpn/t-div.c (main): Added tests for mpn_divrem_2 and
+	mpn_div_qr_2.
+
+	* mpn/generic/div_qr_2.c (mpn_div_qr_2): New file and function.
+	Intended to eventually replace divrem_2.
+	* configure.in (gmp_mpn_functions): Add div_qr_2.
+
+2011-03-16  Marc Glisse  <marc.glisse@inria.fr>
+
+	* gmpxx.h (__gmp_set_expr): Remove broken declarations.
+
+2011-03-19  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpz/fac_ui.c (mpz_fac_ui): Use MPZ_REALLOC for standard, conditional
+	reallocation.
+
+2011-03-19  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/divrem_2.c (mpn_divrem_2): Fixed comment and assert
+	regarding q and n overlap.
+
+2011-03-16  Marc Glisse  <marc.glisse@inria.fr>
+
+	* gmpxx.h (__mpz_set_ui_safe): New inline function.
+	(__mpz_set_si_safe): Likewise.
+	(__GMPXX_TMPZ_UI): Use the new function.
+	(__GMPXX_TMPZ_SI): Likewise.
+	(__GMPXX_TMPQ_UI): Likewise.
+	(__GMPXX_TMPQ_SI): Likewise.
+	* tests/cxx/t-ops2.cc: test converting 0 to stack mpq_t.
+
+2011-03-15  Marc Glisse  <marc.glisse@inria.fr>
+
+	* gmpxx.h (__GMPXX_TMPQ_UI): New macro.
+	(__GMPXX_TMPQ_SI): New macro.
+	(struct __gmp_binary_multiplies): Rewrite, using the new macros.
+	(struct __gmp_binary_divides): Likewise.
+
+	* gmpxx.h (__GMPZ_ULI_LIMBS): Rewrite.
+	* tests/cxx/t-ops2.cc: test converting ULONG_MIN to stack mpq_t.
+
+2011-03-15 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/toom_interpolate_16pts.c: Remove ambiguity.
+
+2011-03-14  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tune/tuneup.c (tune_mul): Set tuning min size considering print skew.
+
+	* doc/gmp.texi: Make reference to "Formatted I/O" chapters from type
+	specific I/O sections.
+
+	* mpn/alpha/add_n.asm: Add _nc entry point.
+	* mpn/alpha/sub_n.asm: Likewise.
+	* mpn/mips64/add_n.asm: Likewise.
+	* mpn/mips64/sub_n.asm: Likewise.
+	* mpn/sparc64/ultrasparc1234/add_n.asm: Likewise.
+	* mpn/sparc64/ultrasparc1234/sub_n: Likewise.
+
+2011-03-13  Marc Glisse  <marc.glisse@inria.fr>
+
+	* tests/cxx/t-ops2.cc: New file.
+	* tests/cxx/Makefile.am: Added t-ops2.
+
+2011-03-13  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/toom32_mul.c (mpn_toom32_mul): Make 'hi' be limb-sized
+	for better code.
+
+	* gmp-impl.h (MPN_IORD_U): Handle x86_64 as well as x86_32.  Generate
+	no code for incrementing by constant 0.
+
+2011-03-12  Marc Glisse  <marc.glisse@inria.fr>
+
+	* gmpxx.h: Rename __GMPXX_TMP_* to __GMPXX_TMPZ_*. Use in more places.
+
+2011-03-12  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/powerpc64/rshift.asm: Accept/return values correctly also for
+	32-bit ABI.
+	* mpn/powerpc64/lshift.asm: Likewise.
+
+	* tune/powerpc.asm: Use powerpc syntax, not power syntax.
+
+	* tune/common.c (speed_udiv_qrnnd_preinv1, etc): Remove.
+	* tune/speed.c (routine): Remove udiv_qrnnd_preinv1, etc.
+
+2011-03-12  Marc Glisse  <marc.glisse@inria.fr>
+
+	* tests/cxx/t-istream.cc: Restrict mpq test in t-istream -s.
+
+	* gmpxx.h: Remove leftover #undefs.
+
+2011-03-11  Torbjorn Granlund  <tege@gmplib.org>
+
+	* gmp-impl.h (udiv_qrnnd_preinv1, udiv_qrnnd_preinv2,
+	udiv_qrnnd_preinv2gen): Remove obsolete macros.
+	(udiv_qrnnd_preinv): New name for udiv_qrnnd_preinv3.
+
+2011-03-11 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* gmp-impl.h: Declare many mpn_{sub,add}lsh*_n_ip[12] functions/macros.
+	* mpn/generic/toom_interpolate_5pts.c: Use mpn_sublsh1_n_ip1.
+
+	* tests/devel/try.c: Tests for {add,sub}lsh*_n_ip[12].
+	* tests/refmpn.c: New reference for mpn_{add,sub}lsh*_n_ip[12].
+	* tests/tests.h: Declarations for reference functions above.
+
+	* tune/common.c: New speed_mpn_{add,sub}lsh*_n_ip[12] functions.
+	* tune/speed.h: Prototypes for functions above.
+	* tune/speed.c: Support for mpn_{add,sub}lsh*_n_ip[12].
+
+	* mpn/x86/k7/sublsh1_n.asm: Replaced generic sublsh1 code with faster _ip1.
+	* mpn/x86/atom/sublsh1_n.asm: Changed PROLOGUE accordingly.
+
+	* configure.in: Define HAVE_NATIVE_mpn_addlsh*_n*_ip[12].
+	* mpn/asm-defs.m4: Declare mpn_addlsh*_n*_ip[12].
+
+2011-03-10  Marc Glisse  <marc.glisse@inria.fr>
+
+	* tests/cxx/t-istream.cc: Explicit conversion to streampos.
+
+2011-03-10  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86/atom/sse2/mul_basecase.asm: Suppress wind-down rp updates.
+
+	* Move new aorrlsh_n.asm to new k8 dir.  Revert
+	mpn/x86_64/aorrlsh_n.asm.
+	* configure.in: Setup path for new k8 directory.
+
+2011-03-10 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/x86/pentium4/sse2/bdiv_dbm1c.asm: New file, was in atom.
+	* mpn/x86/atom/sse2/bdiv_dbm1c.asm: Grab file above.
+
+2011-03-09  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/aorrlsh_n.asm: Complete rewrite.
+
+	* mpn/x86_64/core2/aorrlsh_n.asm: New file, grabbing another asm file.
+
+2011-03-09  Marc Glisse  <marc.glisse@inria.fr>
+
+	* tests/cxx/t-ostream.cc: Use bool instead of int.
+	* tests/cxx/t-istream.cc: Likewise.
+	* tests/cxx/t-misc.cc: Likewise.
+
+	* cxx/ismpznw.cc: Don't clear eofbit.
+	* cxx/ismpq.cc: Likewise.
+	* cxx/ismpf.cc: Likewise.
+	* tests/cxx/t-istream.cc: Test accordingly.
+
+2011-03-09 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/x86/atom/sse2/bdiv_dbm1c.asm: New file.
+
+2011-03-09  Marc Glisse  <marc.glisse@inria.fr>
+
+	* doc/gmp.texi: Remove void return type from constructors. Document
+	explicit constructors. Document mpf_class::mpf_class(mpf_t).
+
+2011-03-07 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/x86/atom/sse2/sqr_basecase.asm: Postponed pushes. Cleaned
+	outer loop exit.
+
+2011-03-07  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/gcd_1.asm: Workaround Oracle assembler bug.
+
+	* mpn/x86/atom/sse2/mul_basecase.asm: Replace addmul_1 loops.
+	Tweak outer loop rp updates.
+
+2011-03-06  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86/atom/sse2/sqr_basecase.asm: New file.
+
+2011-03-05  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/bdiv_dbm1c.asm: Write proper feed-in code.
+
+2011-03-04  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/addmul_2.asm: Rewrite for linear performance.
+
+2011-03-03  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/mod_1_1.c (add_mssaaaa): Canonicalise layout.  Add arm
+	variant.  Enable sparc64 code and powerpc code (the latter for 32-bit
+	and 64-bit).
+
+	* mpn/generic/sqrtrem.c (mpn_dc_sqrtrem): Use mpn_addlsh1_n.
+
+	* gmp-impl.h (mpn_addlsh_nc, mpn_rsblsh_nc): Declare.
+	* mpn/asm-defs.m4: Likewise.
+
+	* mpn/x86_64/coreisbr/aorrlsh_n.asm: Disable mpn_rsblsh_n due to
+	carry-in issues.
+	* mpn/x86_64/coreinhm/aorrlsh_n.asm: Likewise.
+	* mpn/x86_64/coreisbr/aorrlsh2_n.asm: Likewise.
+
+2011-03-03  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/mod_1_1.c (add_mssaaaa): For x86 and x86_64, treat m
+	as in output operand only. Added sparc32 implementation. Also
+	added #if:ed out attempts at sparc64 and powerpc64.
+
+	* tune/tuneup.c (tune_mod_1): Record result of MOD_1_1P_METHOD
+	measurement for use by mpn_mod_1_tune. And omit measurement if
+	mpn_mod_1_1p is native assembly code.
+
+	* mpn/generic/mod_1.c (mpn_mod_1_1p) [TUNE_PROGRAM_BUILD]: Macro
+	to check mod_1_1p_method and call the right function.
+	(mpn_mod_1_1p_cps) [TUNE_PROGRAM_BUILD]: Likewise.
+
+	* gmp-impl.h (MOD_1_1P_METHOD) [TUNE_PROGRAM_BUILD]: Define macro.
+	(mod_1_1p_method) [TUNE_PROGRAM_BUILD]: Declare variable.
+
+2011-03-02  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/coreinhm/aorrlsh_n.asm: New file.
+	* mpn/x86_64/coreisbr/aorrlsh_n.asm: New file.
+
+2011-03-01  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/x86_64/mod_1_1.asm (mpn_mod_1_1p_cps): Eliminated a neg and
+	two mov instructions.
+
+	* mpn/x86/k7/mod_1_1.asm (mpn_mod_1_1p_cps): Simplified
+	computation, analogous to recent x86_64/mod_1_1.asm changes.
+	(mpn_mod_1_1p): Corresponding changes. Don't shift b.
+
+	* mpn/sparc64/mod_1_4.c (mpn_mod_1s_4p_cps): Use udiv_rnnd_preinv
+	rather than udiv_rnd_preinv.
+	(mpn_mod_1s_4p): Likewise.
+
+2011-03-01  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86/pentium4/sse2/mul_1.asm: Swap entry insns to share more code
+	between entry points.
+	* mpn/x86/pentium4/sse2/addmul_1.asm: Likewise.
+
+	* mpz/divegcd.c: Rewrite, as per Marc Glisse's suggestion.  Also fix
+	problem with passing a longlong limb to a _ui function.
+
+	* gmp-impl.h (udiv_qrnnd_preinv3): Cast truth value to mask's type.
+	(udiv_rnnd_preinv): Likewise.
+	* mpn/generic/mod_1_1.c (mpn_mod_1_1p): Likewise.
+
+2011-02-28  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/mod_1_1.c (add_mssaaaa): Typo fix, define
+	add_mssaaaa, not add_sssaaaa.
+
+	* tune/tuneup.c (tune_mod_1): Measure mpn_mod_1_1_1 and
+	mpn_mod_1_1_2, to set MOD_1_1P_METHOD.
+
+	* tune/speed.c (routine): Added mpn_mod_1_1_1 and mpn_mod_1_1_2.
+
+	* tune/speed.h: Declare speed_mpn_mod_1_1_1, speed_mpn_mod_1_1_2,
+	mpn_mod_1_1p_1, mpn_mod_1_1p_2, mpn_mod_1_1p_cps_1, and
+	mpn_mod_1_1p_cps_2.
+
+	* tune/common.c (speed_mpn_mod_1_1_1): New function.
+	(speed_mpn_mod_1_1_2): New function.
+
+	* tune/Makefile.am (libspeed_la_SOURCES): Added mod_1_1-1.c
+	mod_1_1-2.c.
+
+	* tune/mod_1_1-1.c: New file.
+	* tune/mod_1_1-2.c: New file.
+
+	* mpn/generic/mod_1_1.c: Implemented an algorithm with fewer
+	multiplications, configured via MOD_1_1P_METHOD.
+
+	* mpn/x86_64/mod_1_1.asm (mpn_mod_1_1p_cps): Simplified
+	computation of B2modb, use B^2 mod (normalized b).
+	(mpn_mod_1_1p): Corresponding changes. Don't shift b.
+
+	* mpn/generic/mod_1_1.c (mpn_mod_1_1p_cps): Use udiv_rnnd_preinv rather
+	than udiv_rnd_preinv.
+	(mpn_mod_1_1p): Likewise.
+	* mpn/generic/mod_1_4.c: Analogous changes.
+	* mpn/generic/mod_1_3.c: Analogous changes.
+	* mpn/generic/mod_1_2.c: Analogous changes.
+	* mpn/generic/mod_1.c: Analogous changes.
+	* mpn/generic/pre_mod_1.c: Analogous changes.
+
+	* gmp-impl.h (udiv_qrnnd_preinv3): Eliminated unpredictable branch
+	using masking logic. Further optimization of the nl == constant 0
+	case, similar to udiv_rnd_preinv.
+	(udiv_rnnd_preinv): Likewise.
+	(udiv_rnd_preinv): Deleted, use udiv_rnnd_preinv with nl == 0
+	instead.
+
+	* tests/mpn/t-divrem_1.c (check_data): Added testcase to exercise
+	the nl == constant 0 special case in udiv_qrnnd_preinv3.
+
+2011-02-28  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/rootrem.c (mpn_rootrem): Combine two similar scalar
+	divisions.  Misc minor cleanup.
+
+	* mpn/x86/atom/sse2/aorsmul_1.asm: Shorten software pipeline.
+
+	* mpn/x86/atom/mul_basecase.asm: Remove file no longer used.
+
+	* mpn/generic/rootrem.c (mpn_rootrem_internal): Delay O(log(U))
+	allocations until they are known to be needed.
+
+2011-02-27 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/x86/atom/sse2/mul_1.asm: New code.
+
+2011-02-27  Niels Möller  <nisse@lysator.liu.se>
+
+	* gmp-impl.h (udiv_rnnd_preinv): New macro.
+
+2011-02-27  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86/atom/sse2/mul_basecase.asm: New file.
+
+2011-02-26 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/x86/atom/sse2/aorsmul_1.asm: Optimise non-loop code.
+
+2011-02-26  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/powerpc64/mode64/aorsmul_1.asm: Add MULFUNC_PROLOGUE.
+	* mpn/m68k/mc68020/aorsmul_1.asm: Likewise.
+
+2011-02-25  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86/atom/sse2/aorsmul_1.asm: New file.
+	* mpn/x86/atom/aorsmul_1.asm: File removed.
+
+2011-02-25 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/x86/atom/sse2/divrem_1.asm: New file (was in x86/atom).
+	* mpn/x86/atom/sse2/mul_1.asm: Likewise.
+	* mpn/x86/atom/sse2/popcount.asm: Likewise.
+	* mpn/x86/atom/divrem_1.asm: ReMoved (in sse2/ now).
+	* mpn/x86/atom/mul_1.asm: Likewise.
+	* mpn/x86/atom/popcount.asm: Likewise.
+
+	* configure.in: Set up mmx path for atom.
+	* mpn/x86/atom/mmx/copyd.asm: New file (was in x86/atom).
+	* mpn/x86/atom/mmx/copyi.asm: Likewise.
+	* mpn/x86/atom/mmx/hamdist.asm: Likewise.
+	* mpn/x86/atom/copyd.asm: ReMoved (in mmx/ now).
+	* mpn/x86/atom/copyi.asm: Likewise.
+	* mpn/x86/atom/hamdist.asm: Likewise.
+
+2011-02-24  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86/atom/sse2/mod_1_1.asm: New file.
+	* mpn/x86/atom/sse2/mod_1_4.asm: New file.
+	* configure.in: Set up sse2 path for atom.
+
+	* mpn/x86/p6/sse2/mod_1_1.asm: New file.
+	* mpn/x86/p6/sse2/mod_1_4.asm: Fix typo in MULFUNC_PROLOGUE.
+
+2011-02-24  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/x86/k7/mod_1_1.asm (mpn_mod_1_1p): Rewrite using the same
+	algorithm as the x86_64 version.
+
+2011-02-23 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/x86/atom/logops_n.asm: New file (same loop as aors_n).
+
+2011-02-23  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/x86_64/mod_1_1.asm (mpn_mod_1_1p): Shaved off one
+	instruction and one register in the inner loop. Rearranged
+	registers slightly, and no longer needs the callee-save register
+	%r12.
+
+2011-02-22  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.in: Export SHLD_SLOW and SHRD_SLOW to config.m4, also
+	fixing typo in exporting code.
+
+	* mpn/x86_64/nano/gmp-mparam.h (SHLD_SLOW, SHRD_SLOW): Define.
+	* mpn/x86_64/atom/gmp-mparam.h (SHLD_SLOW, SHRD_SLOW): Define.
+
+2011-02-22  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/x86_64/mod_1_1.asm (mpn_mod_1_1p): Rewrite.
+
+2011-02-22 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/x86/atom/lshiftc.asm: New file (a copy of lshift.asm with a handful of neg added).
+
+2011-02-21  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86/aors_n.asm: Move _nc entry to after main code.  Align loop
+	and _n entry for claimed performance.  Normalise mnemonic usage.
+
+	* mpn/x86/atom/aorrlsh1_n.asm: New file (code from rsblsh_1, slightly
+	slower for addlsh_1 for large operands, but much faster for small).
+	* mpn/x86/atom/addlsh1_n.asm: Remove.
+	* mpn/x86/atom/rsblsh1_n.asm: Remove.
+
+2011-02-20  Marc Glisse  <marc.glisse@inria.fr>
+
+	* mpq/aors.c: Rewrite to remove redundant division.
+
+2011-02-20  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86/atom/lshift.asm: New file.
+	* mpn/x86/atom/rshift.asm: Normalise mnemonic usage.
+
+	* gmp-impl.h (mpn_divexact_by7): Relax inclusion condition.
+
+	* mpz/divegcd.c (mpz_divexact_by5): New conditionally enabled function.
+	(mpz_divexact_by3): Wrap inside appropriate conditions.
+	(mpz_divexact_gcd): Rewrite.
+
+	* mpn/x86/bdiv_dbm1c.asm: Save a jump.
+
+2011-02-20 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/x86/atom/aorslshC_n.asm: New file.
+	* mpn/x86/atom/sublsh2_n.asm: New file.
+
+	* mpn/x86/atom/aors_n.asm: New code.
+	* mpn/x86/atom/rshift.asm: Atom64 code adapted to 32-bit.
+	* mpn/x86/atom/lshift.asm: Likewise.
+
+2011-02-19  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/atom/rsh1aors_n.asm: New file.
+
+	* mpn/x86_64/atom/lshift.asm: New file.
+	* mpn/x86_64/atom/rshift.asm: New file.
+	* mpn/x86_64/atom/lshiftc.asm: New file.
+
+2011-02-17 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/x86/atom/aorsmul_1.asm: Small improvements for small sizes.
+	* mpn/x86/atom/aorrlshC_n.asm: Tiny size improvements.
+
+2011-02-16  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.in: Fix k8/k10 32-bit path setup problem.
+
+2011-02-16 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/x86/atom/aorsmul_1.asm: Revive an old k7/aorsmul.
+
+2011-02-14 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* gmp-impl.h (mpn_sublsh_n): Declare.
+	* mpn/asm-defs.m4: Likewise.
+
+	* mpn/x86/atom/aorrlshC_n.asm: New file (was k7).
+	* mpn/x86/k7/aorrlshC_n.asm: ReMoved.
+	* mpn/x86/atom/aorrlsh2_n.asm: Grab atom/aorrlshC_n.asm.
+	* mpn/x86/atom/rsblsh1_n.asm: Grab atom/aorrlshC_n.asm.
+
+2011-02-13  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/atom/aorrlsh2_n.asm: New file.
+
+2011-02-12  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/aorrlsh_n.asm: Minor tweaks, update c/l numbers.
+
+	* mpn/x86_64/atom/sublsh1_n.asm: New file.
+
+	* mpn/x86_64/atom/aorrlsh1_n.asm: New file.
+
+2011-02-11  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/powerpc64/mode64/mod_1_1.asm: Fix Darwin syntax issues.
+
+2011-02-10  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/powerpc64/mode64/mod_1_4.asm: Tune away a cycle for 970.
+
+2011-02-11 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/x86/k7/addlsh1_n.asm: Faster core loop (Torbjorn's).
+
+	* configure.in: Add HAVE_NATIVE_{add,sub,rsb}lsh{,1,2}_nc.
+	* tests/tests.h: refmpn_{add,sub,rsb}lsh{,1,2}_nc prototypes.
+	* tests/refmpn.c: New refmpn_{add,sub,rsb}lsh{,1,2}_nc.
+	* tests/devel/try.c: Tests for mpn_{add,sub,rsb}lsh{,1,2}_nc.
+
+	* mpn/x86/k7/aorrlshC_n.asm: New file.
+	* mpn/x86/atom/aorrlsh2_n.asm: Grab k7/aorrlshC_n.asm.
+	* mpn/x86/atom/rsblsh1_n.asm: Grab k7/aorrlshC_n.asm.
+
+2011-02-06 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/x86/k7/addlsh1_n.asm: New file.
+	* mpn/x86/k7/sublsh1_n.asm: New file.
+	* mpn/x86/atom/addlsh1_n.asm: Grab k7/addlsh1_n.asm.
+	* mpn/x86/atom/sublsh1_n.asm: Grab k7/sublsh1_n.asm.
+
+2011-02-05  Torbjorn Granlund  <tege@gmplib.org>
+
+	* gmp-impl.h (mpn_addlsh1_nc, mpn_addlsh2_nc, mpn_sublsh1_nc,
+	mpn_sublsh2_nc, mpn_rsblsh1_nc, mpn_rsblsh2_nc): Declare.
+	* mpn/asm-defs.m4: Likewise.
+
+	* mpn/x86_64/coreisbr/aorrlshC_n.asm: New file.
+	* mpn/x86_64/coreisbr/aorrlsh1_n.asm: New file.
+	* mpn/x86_64/coreisbr/aorrlsh2_n.asm: New file.
+
+	* mpn/x86_64/coreisbr/aors_n.asm: New file, based on old
+	atom/aors_n.asm.
+	* mpn/x86_64/atom/aors_n.asm: Grab coreisbr/aors_n.asm.
+
+2011-02-05 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* gmp-impl.h (mpn_toom6_mul_n_itch): Handle threshold == zero.
+	(mpn_toom8_mul_n_itch): Likewise.
+	(MPN_TOOM6H_MIN, MPN_TOOM8H_MIN): Define.
+	* tests/mpn/t-toom6h.c: No tests below MPN_TOOM6H_MIN.
+	* tests/mpn/t-toom8h.c: No tests below MPN_TOOM8H_MIN.
+
+	* mpz/lucnum_ui.c: Use mpn_addlsh2_n.
+
+2011-02-04  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/atom/rsh1aors_n.asm: Add a MULFUNC_PROLOGUE.
+	* mpn/x86_64/atom/dive_1.asm: Likewise.
+	* mpn/x86_64/atom/popcount.asm: Likewise.
+	* mpn/x86_64/core2/popcount.asm: Likewise.
+	* mpn/x86_64/coreinhm/hamdist.asm: Likewise.
+	* mpn/x86_64/coreinhm/popcount.asm: Likewise.
+	* mpn/x86_64/nano/popcount.asm: Likewise.
+	* mpn/x86_64/pentium4/popcount.asm: Likewise.
+
+2011-02-04 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/x86/atom/mode1o.asm: New file, grabbing another asm file.
+	* mpn/x86/atom/mul_1.asm: Claim mul_1c.
+
+2011-02-02  Niels Möller  <nisse@lysator.liu.se>
+
+	* tune/speed.h (SPEED_ROUTINE_MPN_HGCD_CALL): Fixed one
+	speed_operand_dst call.
+
+2011-02-01  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tune/speed.h (struct speed_params): Allow for 4 dst operands.
+	* tune/common.c (TOLERANCE): Increase from 0.5% to 1%.
+
+	* tune/speed.h (SPEED_ROUTINE_MPN_HGCD_CALL): New macro, mainly based
+	on old speed_mpn_hgcd, but with speed_operand_src calls (as suggested
+	by Niels).
+	* tune/common.c (speed_mpn_hgcd): Invoke SPEED_ROUTINE_MPN_HGCD_CALL.
+	(speed_mpn_hgcd_lehmer): Likewise.
+
+	* configure.in: Set up 32-bit x86 paths for new corei* CPU strings.
+
+2011-01-31  Torbjorn Granlund  <tege@gmplib.org>
+
+	* config.guess: Recognise new Intel processors.
+
+	* config.guess: Support 'coreinhm' and 'coreisbr'.
+	* config.sub: Likewise.
+	* configure.in: Likewise.
+
+2011-01-30  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.in: Support x86/geode.
+	* mpn/x86/geode/gmp-mparam.h: New file.
+
+2011-01-29 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/x86/atom/addlsh1_n.asm: Removed.
+	* mpn/x86/atom/rsh1add_n.asm: Likewise.
+
+2011-01-28  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/alpha/ev6/slot.pl: Add some missing insns.
+
+2011-01-28 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/x86/atom/copyd.asm: New file, grabbing another asm file.
+	* mpn/x86/atom/copyi.asm: Likewise.
+	* mpn/x86/atom/aors_n.asm: Likewise.
+	* mpn/x86/atom/addlsh1_n.asm: Likewise.
+	* mpn/x86/atom/aorsmul_1.asm: Likewise.
+	* mpn/x86/atom/bdiv_q_1.asm: Likewise.
+	* mpn/x86/atom/dive_1.asm: Likewise.
+	* mpn/x86/atom/divrem_1.asm: Likewise.
+	* mpn/x86/atom/hamdist.asm: Likewise.
+	* mpn/x86/atom/logops_n.asm: Likewise.
+	* mpn/x86/atom/lshift.asm: Likewise.
+	* mpn/x86/atom/mod_34lsub1.asm: Likewise.
+	* mpn/x86/atom/mul_1.asm: Likewise.
+	* mpn/x86/atom/mul_basecase.asm: Likewise.
+	* mpn/x86/atom/popcount.asm: Likewise.
+	* mpn/x86/atom/rsh1add_n.asm: Likewise.
+	* mpn/x86/atom/rshift.asm: Likewise.
+	* mpn/x86/atom/sqr_basecase.asm: Likewise.
+
+2011-01-27  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/atom/rsh1aors_n.asm: New file, grabbing another asm file.
+	* mpn/x86_64/atom/popcount.asm: Likewise.
+	* mpn/x86_64/atom/dive_1.asm: Likewise.
+	* mpn/x86_64/nano/popcount.asm: Likewise.
+
+2011-01-26  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/alpha/invert_limb.asm: Complete rewrite.
+
+2011-01-25  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/powerpc32/invert_limb.asm: New file.
+
+2011-01-25 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/x86/pentium4/sse2/bdiv_q_1.asm: New file.
+	* mpn/x86/k7/bdiv_q_1.asm: New file.
+
+2011-01-24  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tune/tuneup.c (tune_mul_n, tune_sqr): Loop, re-measuring thresholds
+	until no tiny ranges remain.
+
+2011-01-23  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/ia64/mul_2.asm: Tweak to 1.5 c/l, less overhead.
+
+	* mpn/ia64/addmul_2.asm: Rewrite, adding mpn_addmul_2s entry point.
+
+2011-01-22  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/ia64/aors_n.asm: Fix some incorrect bundle types.
+
+	* mpn/ia64/sqr_diagonal.asm: Remove.
+
+	* mpn/ia64/sqr_diag_addlsh1.asm: New file.
+
+	* mpn/ia64/ia64-defs.m4: Define some shorter convenience mnemonics.
+
+	* mpn/generic/sqr_basecase.c (MPN_SQR_DIAG_ADDLSH1): New macro, using
+	new function mpn_sqr_diag_addlsh1 or defining its equivalent.
+
+	* gmp-impl.h (mpn_addmul_2s): Declare.
+	(mpn_sqr_diag_addlsh1): Declare.
+	* mpn/asm-defs.m4 (define_mpn): Add addmul_2s and sqr_diag_addlsh1.
+
+	* configure.in: Add HAVE_NATIVEs for mpn_sqr_diag_addlsh1 and
+	mpn_addmul_2s.
+	(gmp_mpn_functions_optional): Add sqr_diag_addlsh1.
+
+2011-01-21 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* tests/devel/try.c: Initial support for mpn_bdiv_q_1.
+	* mpn/x86/pentium/bdiv_q_1.asm: New file.
+	* mpn/x86/p6/bdiv_q_1.asm: New file.
+
+2011-01-20  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tune/speed.c (run_gnuplot): Update to current gnuplot syntax.
+
+	* mpn/powerpc64/mode64/aorsmul_1.asm: Trim away 0.5 c/l for submul_1
+	for POWER5.
+
+2011-01-19  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/core2/rsh1aors_n.asm: New file.
+
+2011-01-18 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/x86/bdiv_q_1.asm: New file (same core alg. as dive_1).
+
+2011-01-15 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/divexact.c: Avoid COPY if not needed.
+
+2011-01-14  Torbjorn Granlund  <tege@gmplib.org>
+
+	* gmp-impl.h (struct cpuvec_t): Add field bmod_1_to_mod_1_threshold.
+	* configure.in (fat_thresholds): Add BMOD_1_TO_MOD_1_THRESHOLD.
+
+2011-01-13 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpz/mul.c: Remove redundant size computation.
+
+2011-01-08  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/devel/try.c (types enum): Add TYPE_MUL_5 and TYPE_MUL_6.
+	(param_init): Support new types.
+	(choice_array): Support testing of mpn_mul_5 and mpn_mul_6.
+	(call): Support new routines.
+
+	* tests/refmpn.c (refmpn_mul_5, refmpn_mul_6): New functions.
+	* tests/tests.h (refmpn_mul_5, refmpn_mul_6): Declare.
+	Remove parameter names from some other functions.
+
+	* gmp-impl.h (mpn_mul_5, mpn_mul_6): Declare.
+	* mpn/asm-defs.m4: Likewise, also declare mpn_addmul_5, mpn_addmul_6,
+	mpn_addmul_7, and mpn_addmul_8.
+
+	* configure.in (gmp_mpn_functions_optional): Add mul_5 and mul_6.
+
+	* tune/speed.c (routine): Add measuring of mpn_mul_5 and mpn_mul_6.
+	* tune/common.c (speed_mpn_mul_5, speed_mpn_mul_6): New functions.
+	* tune/speed.h: Declare new functions.
+
+2011-01-03 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpz/aors.h: Remove #ifdef BERKELEY_MP, and cleanup.
+	* mpz/cmp.c: Likewise.
+	* mpz/gcd.c: Likewise.
+	* mpz/mul.c: Likewise.
+	* mpz/powm.c: Likewise.
+	* mpz/set.c: Likewise.
+	* mpz/sqrtrem.c: Likewise.
+	* mpz/tdiv_qr.c: Likewise.
+
+2010-12-28  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/minithres/gmp-mparam.h: Update with several recent thresholds.
+
+2010-12-19  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86/k7/mod_1_1.asm: Canonicalise cmov forms.
+	* mpn/x86/k7/mod_1_4.asm: Likewise.
+	* mpn/x86/pentium4/sse2/mod_1_1.asm: Likewise.
+	* mpn/x86/pentium4/sse2/mod_1_4.asm: Likewise.
+	* mpn/x86_64/core2/divrem_1.asm: Likewise.
+	* mpn/x86_64/divrem_1.asm: Likewise.
+	* mpn/x86_64/mod_1_1.asm: Likewise.
+	* mpn/x86_64/mod_1_2.asm: Likewise.
+	* mpn/x86_64/mod_1_4.asm: Likewise.
+
+	* mpn/x86/k7/gcd_1.asm: Rewrite.  Remove slow 'div' loop.  Call
+	mpn_mod_1 for operands with mode than BMOD_1_TO_MOD_1_THRESHOLD limbs.
+	Misc cleanups.
+
+2010-12-18  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/gcd_1.asm: Call mpn_mod_1 for operands with mode than
+	BMOD_1_TO_MOD_1_THRESHOLD limbs.
+
+	* configure.in: Generalise code for putting THRESHOLDs in config.m4.
+	Add BMOD_1_TO_MOD_1_THRESHOLD to list.
+
+	* mpn/x86_64/core2/divrem_1.asm: Tweak slightly, correct cycle counts.
+
+	* mpn/x86_64/addmul_2.asm: Remove constant index.
+	* mpn/x86_64/lshiftc.asm: Likewise.
+	* mpn/x86_64/pentium4/lshift.asm: Likewise.
+	* mpn/x86_64/pentium4/lshiftc.asm: Likewise.
+	* mpn/x86_64/pentium4/rshift.asm: Likewise.
+
+2010-12-16  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/mod_34lsub1.asm: Complete rewrite.
+	* mpn/x86_64/pentium4/mod_34lsub1.asm: New file, old
+	mpn/x86_64/mod_34lsub1.asm.
+
+2010-12-15  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/powerpc64/vmx/popcount.asm: Rewrite to use vperm count table.
+
+2010-12-14  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mp-h.in: Remove.
+	* configure.in: Remove mp-h.in from AC_OUTPUT invocation.
+
+2010-12-13  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpz/mod.c: Rewrite.
+
+	* mpn/x86_64/corei/popcount.asm: New file.
+	* mpn/x86_64/corei/hamdist.asm: New file.
+
+	* mpn/x86_64/k10/hamdist.asm: New file.
+
+	* configure.in: Amend last change for lame /bin/sh.
+
+2010-12-12  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.in: Comment out M4=m4-not-needed.
+
+	* mpn/x86_64/k10/popcount.asm: New file.
+	* configure.in: Setup special path for k10 and later AMD CPUs.
+	Remove special x86_64'k8' path, since directory is non-existent.
+
+2010-12-11  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/sparc32/ultrasparct1: New directory.
+	* mpn/sparc32/ultrasparct1/add_n.asm: New file.
+	* mpn/sparc32/ultrasparct1/sub_n.asm: New file.
+	* mpn/sparc32/ultrasparct1/mul_1.asm: New file.
+	* mpn/sparc32/ultrasparct1/addmul_1.asm: New file.
+	* mpn/sparc32/ultrasparct1/submul_1.asm: New file.
+	* mpn/sparc32/ultrasparct1/sqr_diagonal.asm: New file.
+
+	* config.guess: Support Ultrasparc T2 and T3.
+	* config.sub: Likewise.
+	* configure.in: Likewise.
+
+	* config.guess: Generalise BSD Sparc recognition by allowing any
+	caps (needed for OpenBSD which spells things innovatively).
+
+2010-12-01  Torbjorn Granlund  <tege@gmplib.org>
+
+	* config.guess: Match new AMD processors, allow finer distinctions
+	among old ones.
+	* acinclude.m4 (X86_64_PATTERN): Likewise.
+	* config.sub: Likewise.
+	* configure.in: Rudimentarily support new AMD processors.
+
+	* configure.in (--enable_assembly): New option.
+	(target none-*-*): Disable, give error.
+
+2010-11-29  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86/x86-defs.m4 (LEA): Support non-PIC code.
+	* mpn/x86/darwin.m4 (LEA): Likewise.
+
+	* tests/amd64call.asm: Rewrite for code size, and to match calls and
+	returns.
+
+	* tests/x86call.asm: Rewrite for code size, to support PIC, and to
+	match calls and returns.
+	* tests/x86check.c: Rewrite.
+
+2010-11-22  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpz/get_str.c: Make all bases either work or return an error.
+	* mpz/out_str.c: Likewise.
+	* mpq/get_str.c: Likewise.
+	* mpf/get_str.c: Likewise.
+
+2010-11-14  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/misc/t-printf.c: Add explicit casts for type conversions.
+	* mpn/generic/toom62_mul.c: Likewise.
+
+2010-11-13  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/get_d.c: Misc cleanup.  Fail with a syntax error for
+	non-IEEE fp formats.
+
+	* tests/devel/try.c (malloc_region): Add explicit casts for type
+	conversions.
+
+	* acinclude.m4 (GMP_ASM_RODATA): Make test code snippet C++ compatible.
+	(GMP_C_DOUBLE_FORMAT): Likewise.
+	(GMP_FUNC_VSNPRINTF): Likewise.
+
+	* config.guess (x86): Make test C snippet C++ compatible.
+
+2010-11-12  Torbjorn Granlund  <tege@gmplib.org>
+
+	* Makefile.am: Remove mpbsd.
+	* configure.in: Remove mpbsd.
+	* doc/configuration: Remove mpbsd mentions.
+	* doc/gmp.texi: Remove mpbsd docs.
+	* tests/Makefile.am: Remove mpbsd.
+	* libmp.sym: Remove.
+	* mpbsd: Remove directory and files.
+	* tests/mpbsd: Remove directory and files.
+
+2010-11-11  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/atom/aors_n.asm: Don't rely on ZF after 'bt' insn.
+	Use 64-bit 'test' to support operands of 2^32 limbs and more.
+
+	* rand: New directory, move rand*.c and randmt.h here.
+	* rand/Makefile.am: New file.
+	* Makefile.am (SUBDIRS): Add rand.
+	(RANDOM_OBJECTS): New variable.
+	(libgmp_la_SOURCES): Remove random objects.
+	(libgmp_la_DEPENDENCIES): Add RANDOM_OBJECTS.
+	* configure.in (AC_OUTPUT): Add rand/Makefile.
+
+	* ansi2knr.1: File removed.
+	* ansi2knr.c: File removed.
+
+2010-11-10  Torbjorn Granlund  <tege@gmplib.org>
+
+	Make it possible to compile GMP with g++:
+
+	* gmp-impl.h: Declare __gmp_digit_value_tab here.
+	* mpbsd/min.c: ...not here.
+	* mpbsd/xtom.c: ...nor here.
+	* mpf/set_str.c: ...nor here.
+	* mpz/inp_str.c: ...nor here.
+	* mpz/set_str.c: ...nor here.
+
+	* mpn/generic/toom43_mul.c: Add casts for logical operations on enums.
+	* mpn/generic/toom44_mul.c: Likewise.
+	* mpn/generic/toom4_sqr.c: Likewise.
+	* mpn/generic/toom52_mul.c: Likewise.
+	* mpn/generic/toom53_mul.c: Likewise.
+	* mpn/generic/toom62_mul.c: Likewise.
+
+	* mpz/clrbit.c: Clean up typing using MPZ_REALLOC.
+	* mpz/setbit.c: Likewise.
+
+	* mpz/powm.c: Avoid variable name 'new'.
+
+	* randlc2x.c: Add explicit casts for type conversions.
+	* tests/misc/t-printf.c: Likewise.
+	* tests/misc/t-scanf.c: Likewise.
+	* tests/misc.c: Likewise.
+	* tests/mpz/convert.c: Likewise.
+	* tests/refmpn.c: Likewise.
+
+	* tests/tests.h: Unconditionally use <sstream> for now.
+
+	* tests/memory.c: Include "tests.h.
+
+	* mp_get_fns.c: Add a __GMP_NOTHROW for coherency with prototype.
+	* mp_set_fns.c: Likewise.
+	* mpf/cmp.c: Likewise.
+	* mpf/cmp_si.c: Likewise.
+	* mpf/cmp_ui.c: Likewise.
+	* mpf/fits_s.h: Likewise.
+	* mpf/fits_u.h: Likewise.
+	* mpf/get_dfl_prec.c: Likewise.
+	* mpf/get_prc.c: Likewise.
+	* mpf/get_si.c: Likewise.
+	* mpf/get_ui.c: Likewise.
+	* mpf/int_p.c: Likewise.
+	* mpf/set_dfl_prec.c: Likewise.
+	* mpf/set_prc_raw.c: Likewise.
+	* mpf/size.c: Likewise.
+	* mpf/swap.c: Likewise.
+	* mpq/equal.c: Likewise.
+	* mpq/swap.c: Likewise.
+	* mpz/cmp.c: Likewise.
+	* mpz/cmp_si.c: Likewise.
+	* mpz/cmp_ui.c: Likewise.
+	* mpz/cmpabs.c: Likewise.
+	* mpz/cmpabs_ui.c: Likewise.
+	* mpz/cong_2exp.c: Likewise.
+	* mpz/divis_2exp.c: Likewise.
+	* mpz/fits_s.h: Likewise.
+	* mpz/get_si.c: Likewise.
+	* mpz/hamdist.c: Likewise.
+	* mpz/scan0.c: Likewise.
+	* mpz/scan1.c: Likewise.
+	* mpz/sizeinbase.c: Likewise.
+	* mpz/swap.c: Likewise.
+	* mpz/tstbit.c: Likewise.
+	* tal-reent.c: Likewise.
+
+2010-11-09  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.in: Get rid of K&R support.
+	* Makefile.am: Likewise.
+	* mpn/Makefile.am: Likewise.
+	* doc/configuration: Update docs wrt K&R support.
+	* doc/gmp.texi: Likewise.
+
+	* configure.in (AC_INIT): Amend bug reporting address with manual
+	reference.
+
+2010-11-06  Torbjorn Granlund  <tege@gmplib.org>
+
+	* config.guess: If cpuid says we have 32bit-only x86 but
+	configfsf.guess return x86_64, return the latter.
+
+	* mpn/x86_64/aors_n.asm: Rewrite not to rely on ZF after 'bt' insn.
+
+2010-10-09  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/trialdiv.c: Update documentation.
+
+2010-10-04  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/gcd_1.asm: Use m4_lshift to avoid << operator.
+	* mpn/x86_64/aorrlshC_n.asm: Likewise.
+	* mpn/x86_64/pentium4/aorslshC_n.asm: Likewise.
+	* mpn/x86/k7/gcd_1.asm: Likewise.
+
+2010-08-20  Niels Möller  <nisse@lysator.liu.se>
+
+	Suggested by Ozkan Sezer:
+	* configure.in: If $M4 is already set in the environment, don't
+	touch it. Fixed the case that no assembler files are used, and
+	GMP_PROG_M4 is omitted.
+
+2010-08-08  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/fat/fat.c: Recognise many more processors.
+
+2010-06-30  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/divrem_2.asm: Tune.
+
+2010-06-19  Niels Möller  <nisse@lysator.liu.se>
+
+	* tune/speed.h (SPEED_ROUTINE_MPN_MOD_1_1): Pass normalized
+	divisor to the benchmarked function.
+
+2010-06-15  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/mod_1_1.asm (mpn_mod_1_1p_cps): Rewrite.
+	* mpn/x86_64/mod_1_2.asm (mpn_mod_1s_2p_cps): Rewrite.
+	* mpn/x86_64/mod_1_4.asm (mpn_mod_1s_4p_cps): Rewrite.
+
+	* gmp-impl.h (udiv_rnd_preinv): Simplify.
+
+	* mpn/x86/k7/mod_1_1.asm: New file.
+	* mpn/x86/pentium4/sse2/mod_1_1.asm (mpn_mod_1_1p_cps): Rewrite.
+	* mpn/x86/k7/mod_1_4.asm (mpn_mod_1s_4p_cps): Rewrite.
+	* mpn/x86/pentium4/sse2/mod_1_4.asm (mpn_mod_1s_4p_cps): Rewrite.
+
+	* mpn/generic/mod_1_1.c (mpn_mod_1_1p_cps): Store results as they are
+	computed.
+	* mpn/generic/mod_1_2.c (mpn_mod_1s_2p_cps): Likewise.
+	* mpn/generic/mod_1_4.c (mpn_mod_1s_4p_cps): Likewise.
+
+	* mpn/x86/k7/invert_limb.asm: Moved from mpn/x86/invert_limb.asm.
+
+2010-06-15  Niels Möller  <nisse@lysator.liu.se>
+
+	* tests/mpn/Makefile.am (check_PROGRAMS): Added t-mod_1.
+	* tests/mpn/t-mod_1.c: New file.
+
+2010-05-25  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/mu_div_qr.c (mpn_preinv_mu_div_qr_itch): Trim out space
+	for inverse, since that is passed in already.
+
+2010-05-24  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/mu_div_qr.c (mpn_preinv_mu_div_qr_itch): New function.
+	* gmp-impl.h: Declare it.
+	* tune/common.c (speed_mpn_mupi_div_qr): Use new itch function.
+	* tune/speed.h (SPEED_ROUTINE_MPN_MUPI_DIV_QR): Pass parameters right
+	for new itch function.
+
+	* mpn/powerpc32/lshiftc.asm: New file.
+
+2010-05-22  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tune/tuneup.c (tune_mod_1): Revert to version of 2010-05-06.
+
+2010-05-17  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.in (ia64): Get 32-bit sizeof test right.
+
+	* tune/tuneup.c (tune_mod_1): Undo unintensional change to tuning of
+	PREINV_MOD_1_TO_MOD_1_THRESHOLD.
+
+2010-05-16  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/sparc64/mod_1.c: Rewrite.
+	* mpn/sparc64/sparc64.h (umul_ppmm_s): New macro.
+	* mpn/sparc64/mod_1_4.c: New file.
+
+	* mpn/generic/divrem_1.c: Minor cleanup.
+	* mpn/generic/mod_1.c: Likewise.
+	* mpn/generic/mod_1_1.c: Likewise.
+	* mpn/generic/mod_1_2.c: Likewise.
+	* mpn/generic/mod_1_3.c: Likewise.
+	* mpn/generic/mod_1_4.c: Likewise.
+
+	* configure.in (ia64-hpux): Do sizeof tests for 32-bit and 64-bit ABI.
+
+	* tune/tuneup.c (tune_mod_1): Completely finish MOD_1_N tuning before
+	tuning MOD_1U_TO_MOD_1_1_THRESHOLD.
+
+2010-05-14  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/redc_2.c: Use asm code just for GNU C.
+
+2010-05-13  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/sparc64/ultrasparc1234: New directory.  Move all code that uses
+	floating-point into this directory.
+	* configure.in: Point to ultrasparc1234 for appropriate CPUs.
+
+	* mpn/sparc64/ultrasparct1/add_n.asm: New file.
+	* mpn/sparc64/ultrasparct1/addlsh2_n.asm: New file.
+	* mpn/sparc64/ultrasparct1/addmul_1.asm: New file.
+	* mpn/sparc64/ultrasparct1/lshift.asm: New file.
+	* mpn/sparc64/ultrasparct1/mul_1.asm: New file.
+	* mpn/sparc64/ultrasparct1/rsblsh2_n.asm: New file.
+	* mpn/sparc64/ultrasparct1/rshift.asm: New file.
+	* mpn/sparc64/ultrasparct1/sublsh1_n.asm: New file.
+	* mpn/sparc64/ultrasparct1/sublshC_n.asm: New file.
+	* mpn/sparc64/ultrasparct1/addlsh1_n.asm: New file.
+	* mpn/sparc64/ultrasparct1/addlshC_n.asm: New file.
+	* mpn/sparc64/ultrasparct1/lshiftc.asm: New file.
+	* mpn/sparc64/ultrasparct1/rsblsh1_n.asm: New file.
+	* mpn/sparc64/ultrasparct1/rsblshC_n.asm: New file.
+	* mpn/sparc64/ultrasparct1/sub_n.asm: New file.
+	* mpn/sparc64/ultrasparct1/sublsh2_n.asm: New file.
+	* mpn/sparc64/ultrasparct1/submul_1.asm: New file.
+	* mpn/sparc64/ultrasparct1/gmp-mparam.h: New file.
+
+	* configure.in: Give ultrasparct1 and ultrasparct2 special code path.
+
+	* mpn/x86_64/pentium4/gmp-mparam.h: Disable mpn_addlsh_n, mpn_rsblsh_n.
+
+2010-05-12  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpz/jacobi.c (mpz_jacobi): Fixed off-by-one error in use of
+	scratch space.
+
+	* tune/common.c (speed_mpz_powm_sec): New function.
+	* tune/speed.h: Declare speed_mpz_powm_sec.
+	* tune/speed.c (routine): Added speed_mpz_powm_sec.
+
+	* tune/common.c (speed_mpn_addlsh_n, speed_mpn_sublsh_n)
+	(speed_mpn_rsblsh_n): New functions.
+	* tune/speed.h: Declare new functions.
+	* tune/speed.c (routine): Add new functions.
+
+2010-05-12  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/mod_1_4.asm: Tune for more processors.
+
+	* mpn/x86_64/pentium4/lshiftc.asm: New file.
+
+2010-05-11  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpz/jacobi.c (mpz_jacobi): Deleted old implementation.
+	Reorganized new implementation, to handle small inputs efficiently.
+
+	* tests/mpz/t-jac.c (check_large_quotients): Reduced test sizes.
+	(check_data): One more input pair related to a fixed bug.
+	(main): Enable check_large_quotients.
+
+2010-05-10  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/aorrlsh2_n.asm: Fix typo.
+
+2010-05-09  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/aorrlshC_n.asm: New file based on aorrlsh2_n.asm.
+	* mpn/x86_64/aorrlsh2_n.asm: Now just include aorrlshC_n.asm.
+	* mpn/x86_64/core2/aorrlsh1_n.asm: New file, include ../aorrlshC_n.asm.
+	* mpn/x86_64/core2/aorrlsh2_n.asm: Likewise.
+
+	* mpn/x86_64/core2/sublshC_n.asm: New file based on aorslsh1_n.asm.
+	* mpn/x86_64/core2/aorslsh1_n.asm: Remove.
+	* mpn/x86_64/core2/sublsh1_n.asm: Just include sublshC_n.asm.
+	* mpn/x86_64/core2/sublsh2_n.asm: Likewise.
+
+2010-05-08  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/atom/gmp-mparam.h: Disable mpn_rsh1add_n, mpn_rsh1sub_n.
+
+	* mpn/x86_64/pentium4/aorslshC_n.asm: New file based on aorslsh1_n.asm.
+	* mpn/x86_64/pentium4/aorslsh1_n.asm: Now just include aorslshC_n.asm.
+	* mpn/x86_64/pentium4/aorslsh2_n.asm: New file.
+
+2010-05-07  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/sparc64: Support operands of >= 2^32 limbs.
+
+	* mpn/sparc64/lshiftc.asm: New file.
+
+	* mpn/ia64/divrem_2.asm: Complete rewrite.
+
+2010-05-06  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tune/tuneup.c (all): Don't call tune_divrem_2.
+
+	* mpn/generic/divrem_2.c: Complete rewrite.
+
+	* tune/tuneup.c (tune_mod_1): Fix typo.
+
+2010-05-05  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/mod_1_1.asm (mpn_mod_1_1p): Use macro register names.
+	(mpn_mod_1_1p_cps): Rewrite.
+
+	* mpn/generic/mod_1_1.c (mpn_mod_1_1p_cps): Micro-optimise.
+
+	* longlong.h: Undo 2009-03-01 change for powerpc64, it gives poor code.
+
+	* mpn/x86/pentium4/sse2/mod_1_1.asm: New file.
+
+	* mpn/powerpc64/mode64/mod_1_1.asm: New file.
+
+	* tune/tuneup.c (tune_mod_1): Use more typical divisor, for the benefit
+	of machines with early-out multipliers.
+
+2010-05-04  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tune/tuneup.c (tune_mod_1): Fix typo.
+
+	* mpn/generic/mod_1_1.c: Undo last change.
+	* mpn/x86_64/mod_1_1.asm: Likewise.
+
+2010-05-03  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/jacobi_lehmer.c (jacobi_hook): New function.
+	(mpn_jacobi_subdiv_step): Deleted function.
+	(mpn_jacobi_lehmer): Use general mpn_gcd_subdiv_step.
+
+	* mpn/generic/gcd_subdiv_step.c (mpn_gcd_subdiv_step): Reorganized
+	to use a single hook function.
+	* mpn/generic/gcdext.c (mpn_gcdext): Adapted to new hook
+	interface.
+	* mpn/generic/gcdext_lehmer.c (mpn_gcdext_hook): New unified hook
+	function.
+	* mpn/generic/gcd.c (gcd_hook): Renamed from gcd_done, and adapted
+	to new hook interface.
+	* gmp-impl.h (gcd_subdiv_step_hook): New typedef, now a function
+	type, not a struct.
+	(mpn_gcdext_hook): Declare.
+
+2010-05-03  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/mod_1_1.c: Avoid multiply for 2 limb feed-in.
+	* mpn/generic/mod_1_2.c: Likewise.
+	* mpn/generic/mod_1_3.c: Likewise.
+	* mpn/generic/mod_1_4.c: Likewise.
+	* mpn/x86_64/mod_1_1.asm: Likewise.
+	* mpn/x86_64/mod_1_2.asm: Likewise.
+	* mpn/x86_64/mod_1_4.asm: Likewise.
+	* mpn/x86/k7/mod_1_4.asm: Likewise.
+	* mpn/x86/pentium4/sse2/mod_1_4.asm: Likewise.
+	* mpn/alpha/ev6/mod_1_4.asm: Likewise.
+
+	* tune/tuneup.c (tune_mod_1): Measure MOD_1_1_TO_MOD_1_2_THRESHOLD and
+	MOD_1_2_TO_MOD_1_4_THRESHOLD before MOD_1U_TO_MOD_1_1_THRESHOLD for
+	correctness.
+
+	* mpn/powerpc64/sqr_diagonal.asm: Complete rewrite.
+
+	* mpn/powerpc64/mode64/mod_1_4.asm: New file.
+
+2010-05-02  Torbjorn Granlund  <tege@gmplib.org>
+
+	* config.guess: Recognise power7.
+
+	* configure.in: Major overhaul of powerpc support.
+
+	* mpn/powerpc64/p6/lshift.asm: New file.
+	* mpn/powerpc64/p6/lshiftc.asm: Likewise.
+	* mpn/powerpc64/p6/rshift.asm: Likewise.
+
+2010-04-30  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.in (powerpc64): Support CPU specific mode-less subdirs.
+
+	* mpn/powerpc64/aix.m4 (PROLOGUE_cpu): Use "named csect" making
+	requested alignment actually honoured.
+
+2010-04-30  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/jacobi_lehmer.c (mpn_jacobi_2): Fixed handling of
+	the case bl == 1. Fixed missing application of reciprocity.
+
+2010-04-29  Niels Möller  <nisse@lysator.liu.se>
+
+	* configure.in (gmp_mpn_functions): Deleted gcdext_subdiv_step.
+
+	* mpn/generic/gcdext.c (mpn_gcdext): Use new generalized
+	mpn_gcd_subdiv_step.
+
+	* mpn/generic/gcdext_lehmer.c (gcdext_update): New function.
+	(gcdext_done): New function.
+	(gcdext_hook): New const hook struct.
+	(mpn_gcdext_lehmer_n): Use new generalized mpn_gcd_subdiv_step.
+
+	* mpn/generic/gcd.c (gcd_done): New function.
+	(gcd_hook): New const hook struct.
+	(mpn_gcd): Adapted to new mpn_gcd_subdiv_step interface.
+
+	* mpn/generic/gcd_subdiv_step.c (mpn_gcd_subdiv_step): Reorganized
+	function. Added hook function pointers to the argument list, so
+	the same function can be used for gcd, gcdext, and jacobi.
+
+	* gmp-impl.h (struct gcd_subdiv_step_hook): New struct.
+	(mpn_gcdext_subdiv_step): Deleted prototype.
+	(struct gcdext_ctx): New struct.
+	(gcdext_hook): Declare const struct.
+	(mpn_gcd_subdiv_step): Updated prototype.
+
+	* mpn/generic/gcdext_subdiv_step.c: Deleted file.
+
+2010-04-28  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/powerpc64/lshift.asm: Rewrite.
+	* mpn/powerpc64/rshift.asm: Likewise.
+	* mpn/powerpc64/mode64/lshiftc.asm: New file.
+
+	* mpn/powerpc64/aix.m4: Align functions to 32-byte boundary.
+	* mpn/powerpc64/darwin.m4: Likewise.
+	* mpn/powerpc64/elf.m4: Likewise.
+
+2010-04-28  Niels Möller  <nisse@lysator.liu.se>
+
+	* tests/mpz/t-jac.c (check_data): Added some more test cases.
+
+	* mpn/generic/jacobi_lehmer.c (mpn_jacobi_2): Bugfix, count
+	trailing zeros, not leading.
+
+2010-04-27  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/powerpc64/mode64/p6/mul_basecase.asm: New file.
+
+2010-04-23  Niels Möller  <nisse@lysator.liu.se>
+
+	* gmp-impl.h (MPN_GCD_LEHMER_N_ITCH): Deleted.
+	(mpn_gcd_lehmer_n): Deleted declaration.
+
+	* mpn/generic/gcd.c (gcd_2): Moved from gcd_lehmer.c.
+	(mpn_gcd): Inlined the code from mpn_gcd_lehmer_n. Also use
+	MPN_GCD_SUBDIV_STEP_ITCH rather than MPN_GCD_LEHMER_N_ITCH.
+
+2010-04-22  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/powerpc64/mode64/bdiv_dbm1c.asm: Swap multiply insns to make them
+	consecutive, for the benefit of POWER6.
+
+	* mpn/powerpc64/mode64/p6/gmp-mparam.h: New file.
+
+2010-04-21  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/gcd_lehmer.c: Deleted file.
+
+	* mpn/powerpc64/mode64/divrem_1.asm: Swap multiply insns to make them
+	consecutive, for the benefit of POWER6.
+	* mpn/powerpc64/mode64/dive_1.asm: Likewise.
+	* mpn/powerpc64/mode64/divrem_2.asm: Likewise.
+	* mpn/powerpc64/mode64/mul_1.asm: Likewise.
+	* mpn/powerpc64/mode64/aorsmul_1.asm: Likewise.
+
+	* mpn/powerpc64/mode64/aorslshC_n.asm: Swap ldx operands as a temporary
+	workaround for POWER6 pipeline glitch.
+
+2010-04-19  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpz/jacobi.c (mpz_jacobi): New implementation using
+	mpn_jacobi_lehmer. Currently #if:ed out.
+
+	* mpn/generic/jacbase.c (mpn_jacobi_base)
+	[JACOBI_BASE_METHOD < 4]: Support inputs with a >= b.
+
+	* gmp-impl.h (mpn_jacobi_lehmer): Added prototype.
+	(jacobi_table): Declare.
+	(mpn_jacobi_init): New inline function.
+	(mpn_jacobi_finish): Likewise.
+	(mpn_jacobi_update): Likewise.
+
+	* mpn/generic/jacobi_lehmer.c (mpn_jacobi_lehmer): New file, new
+	function.
+
+	* configure.in (gmp_mpn_functions): Added jacobi_lehmer.
+
+2010-04-14  Niels Möller  <nisse@lysator.liu.se>
+
+	* configure.in (gmp_mpn_functions): Added
+	matrix22_mul1_inverse_vector.
+	* mpn/Makefile.am (nodist_EXTRA_libmpn_la_SOURCES): Added
+	matrix22_mul1_inverse_vector.c.
+
+	* gmp-impl.h (mpn_matrix22_mul1_inverse_vector): Updated for
+	rename of mpn_matrix22_mul1_inverse_vector.
+	* mpn/generic/gcd_lehmer.c (mpn_gcd_lehmer_n): Likewise.
+	* mpn/generic/gcdext_lehmer.c (mpn_gcdext_lehmer_n): Likewise.
+	* mpn/generic/hgcd.c (hgcd_step): Likewise.
+
+	* mpn/generic/matrix22_mul1_inverse_vector.c
+	(mpn_matrix22_mul1_inverse_vector): New file, function moved and
+	renamed...
+	* mpn/generic/hgcd2.c (mpn_hgcd_mul_matrix1_inverse_vector):
+	...from here.
+
+2010-04-12  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/mpn/t-toom6h.c (SIZE_LOG): Define.
+	* tests/mpn/t-toom8h.c (SIZE_LOG): Likewise.
+
+2010-04-10  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/ia64/lorrshift.asm: Rewrite feed-in and wind-down code.
+
+	* mpn/ia64/aorslsh1_n.asm: Adapt to new aorslsh1_n.
+	* mpn/ia64/aorslsh1_n.asm: Likewise.
+
+	* mpn/ia64/aors_n.asm: Complete rewrite.
+	* mpn/ia64/aorslsh1_n.asm: Likewise.
+
+	* mpn/ia64/add_n_sub_n.asm: Misc cleanups.  Add slotting comments.
+
+	* mpn/ia64/lshiftc.asm: New file.
+
+	* mpn/x86_64/pentium4/gmp-mparam.h: No longer disable rsh1add_n and
+	rsh1sub_n; instead disable rsblsh1_n, addlsh2_n, rsblsh2_n.
+
+	* mpn/x86/divrem_2.asm: Use "orb" instead of "or" to work around
+	Solaris assembler bug.
+	* mpn/x86_64/mpn/x86_64/divrem_2.asm: Likewise.
+
+	* mpn/x86/aors_n.asm: Use operand-less shift-by-1 insn form.
+	* mpn/x86/pentium/aors_n.asm: Likewise.
+	* mpn/x86_64/invert_limb.asm: Likewise.
+
+	* mpn/x86_64/pentium4/aors_n.asm: Let non-nc code fall into nc code.
+
+	* mpn/x86_64/pentium4/rsh1aors_n.asm: New file.
+
+2010-03-25  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/ia64/add_n_sub_n.asm: New file.
+
+	* mpn/generic/toom33_mul.c: Fix mpn_add_n_sub_n usage.
+	* mpn/generic/toom3_sqr.c: Likewise.
+	* mpn/generic/toom63_mul.c: Likewise.
+
+	* mpn/generic/add_n_sub_n.c: Renamed from addsub_n.c.
+
+2010-03-23  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/divrem_2.asm: Use mpn_invert_limb instead of div insn.
+
+	* mpn/ia64/aorslshC_n.asm: New file, generalised from last iteration of
+	aorslsh1_n.asm.
+	* mpn/ia64/aorslsh1_n.asm: Use aorslshC_n.asm.
+	* mpn/ia64/aorslsh1_n.asm: New file, use aorslshC_n.asm.
+
+2010-03-20  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/powerpc64/mode64/invert_limb.asm: Rewrite to exploit cancellation
+	in the Newton iteration.
+
+2010-03-20 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/toom_interpolate_8pts.c: Use mpn_sublsh2_n.
+
+2010-03-20  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/powerpc64/mode64/aorslshC_n.asm: New file, generalised from
+	last iteration of aorslsh1_n.asm.
+	* mpn/powerpc64/mode64/aorslsh1_n.asm: Use aorslshC_n.asm.
+	* mpn/powerpc64/mode64/aorslsh1_n.asm: New file, use aorslshC_n.asm.
+
+2010-03-19  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/nano/dive_1.asm: New file.
+
+	* mpn/x86_64/divrem_1.asm: Avoid shld since it is slow on several CPU
+	types.  Unconditionally provide code for normalised and unnormalised
+	divisors.  Cleanup labels.
+
+	* mpn/x86_64/core2/divrem_1.asm: Remove special code for normalised
+	divisors.  Cleanup labels.
+
+	* mpn/generic/toom_interpolate_6pts.c: Call mpn_sublsh2_n and
+	mpn_sublsh_n with correct args.
+
+	* tests/devel/try.c: Use enum for TYPE_*.
+
+	* tests/devel/try.c: Test mpn_sublsh2_n.
+	* tests/refmpn.c (refmpn_sublsh2_n): New function.
+	* tests/tests.h (refmpn_sublsh2_n): Declare.
+
+	* mpn/powerpc64/mode64/aorslsh1_n.asm: New file, with faster
+	mpn_addlsh1_n and mpn_sublsh1_n.
+	* mpn/powerpc64/mode64/addlsh1_n.asm: Delete.
+	* mpn/powerpc64/mode64/sublsh1_n.asm: Delete.
+
+2010-03-18  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.in (*-*-aix): Define gcc_32_cflags_maybe, ar_32_flags and
+	nm_32_flags.
+
+	* mpn/x86/pentium4/sse2/addlsh1_n.asm: Tune for slightly better speed.
+	Misc cleanups.  Add cycle table.
+
+	* mpn/x86_64/copyi.asm: Update cycle table.
+	* mpn/x86_64/copyd.asm: Likewise.
+	* mpn/x86_64/rsh1aors_n.asm: Likewise.
+	* mpn/x86_64/dive_1.asm: Likewise.
+
+	* mpn/x86/pentium4/sse2/add_n.asm: Misc cleanups.  Add cycle table.
+	* mpn/x86/pentium4/sse2/sub_n.asm: Likewise.
+
+2010-03-16  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/divrem_1.asm: Use mpn_invert_limb instead of div insn.
+	* mpn/x86_64/core2/divrem_1.asm: Likewise.
+
+	* tune/speed.c (routine): Add FLAG_R_OPTIONAL for many binops.
+
+2010-03-15  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/alpha/ev6/mod_1_4.asm (mpn_mod_1s_4p_cps): Rewrite.
+
+	* mpn/ia64/aors_n.asm: Insert explicitly typed nops to trigger intended
+	bundling.
+	* mpn/ia64/aorslsh1_n.asm: Likewise.
+	* mpn/ia64/dive_1.asm: Likewise.
+
+2010-03-13  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86/pentium4/sse2/submul_1.asm: Rewrite.
+
+	* mpn/powerpc64/mode64/aorsmul_1.asm: New file, faster than old code
+	for both mpn_addmul_1 and mpn_submul_1.
+	* mpn/powerpc64/mode64/addmul_1.asm: Remove.
+	* mpn/powerpc64/mode64/submul_1.asm: Remove.
+
+2010-03-11  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/gcd_lehmer.c (gcd_2): Use sub_ddmmss.
+
+	* mpn/generic/jacbase.c (mpn_jacobi_base): Reorganized the
+	JACOBI_BASE_METHOD 4 slightly. Now requires that b > 1.
+
+2010-03-10  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/divrem_1.asm: Make fraction code take documented # of
+	cycles.  Annotate code for more CPUs.  Misc cleanups.
+	* mpn/x86_64/core2/divrem_1.asm: Annotate code for more CPUs.
+
+	* mpn/alpha/ev6/mod_1_4.asm: New file.
+
+	* mpn/ia64/mod_34lsub1.asm: New file.
+
+	* doc/gmp.texi (Language Bindings): Update Python site, add Ruby.
+
+2010-03-10  Niels Möller  <nisse@lysator.liu.se>
+
+	* tune/tuneup.c (tune_jacobi_base): Consider mpn_jacobi_base_4.
+	* tune/speed.c (routine): Added mpn_jacobi_base_4.
+	* tune/common.c (speed_mpn_jacobi_base_4): New function.
+	* tune/speed.h (speed_mpn_jacobi_base_4): Declare it.
+	* tune/Makefile.am (libspeed_la_SOURCES): Added jacbase4.c.
+	* tune/jacbase4.c: New file.
+
+	* mpn/generic/jacbase.c (mpn_jacobi_base): New function, for
+	JACOBI_BASE_METHOD 4.
+
+2010-03-09  Niels Möller  <nisse@lysator.liu.se>
+
+	* tests/mpz/t-jac.c (check_large_quotients): Also generate inputs
+	with large quotients and a large gcd.
+
+2010-03-09 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* tests/mpz/t-bin.c (randomwalk): New test-generator function.
+
+2010-03-07  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tune/speed.c (routine): Force r argument for several mod_1 calls.
+
+2010-03-06  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/divrem_1.asm: Disable SPECIAL_CODE_FOR_NORMALIZED_DIVISOR.
+	Misc clean up.
+
+	* mpn/x86_64/mod_1_1.asm: New file.
+	* mpn/x86_64/mod_1_2.asm: New file.
+	* mpn/x86_64/mod_1_4.asm: Update cycle counts.
+
+	* tests/tests.h (TESTS_REPS): Fix typo.
+
+2010-03-03  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/core2/divrem_1.asm: New file.
+
+2010-02-26  Niels Möller  <nisse@lysator.liu.se>
+
+	* tune/speed.c (routine): Added udiv_qrnnd_preinv3.
+
+	* tune/common.c (speed_udiv_qrnnd_preinv3): New function.
+	* tune/speed.h: Added prototype for it.
+
+2010-02-26  Niels Möller  <nisse@lysator.liu.se>
+
+	* tests/mpz/t-jac.c (check_large_quotients): New test. Currently
+	disabled, since it's quite slow.
+	(mpz_nextprime_step): New function.
+
+2010-02-26  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/pa64/aors_n.asm: Fix typo in last change.
+
+2010-02-25  Niels Möller  <nisse@lysator.liu.se>
+
+	* tests/mpz/t-jac.c (ref_jacobi): New reference implementation,
+	using factorization and legendre symbols computed by powm.
+
+	* tests/devel/try.c (param_init, call): Don't pass negative values
+	for the second argument to mpz_jacobi and refmpz_jacobi.
+
+	* tests/refmpz.c (refmpz_jacobi): Require that b is odd and positive.
+
+	* tests/devel/try.c (param_init): Support mpz_legendre.
+	(choice_array): Added mpz_kronecker (apparently forgotten) and
+	mpz_legendre.
+	(call): Added TYPE_MPZ_LEGENDRE.
+	(try_one): Added support for DATA_SRC1_ODD_PRIME.
+
+	* tests/refmpz.c (refmpz_legendre): Rewrote using powm.
+
+2010-02-25  Torbjorn Granlund  <tege@gmplib.org>
+
+	* config.guess: Make "corei" default for unrecognised Intel P6 CPUs.
+
+	* tests/mpz/t-perfpow.c (check_random): Use mp_limb_t type for limb
+	variables.
+
+	* tests/mpn/t-toom6h.c (COUNT): Define.
+	* tests/mpn/t-toom8h.c (COUNT): Define.
+
+	* tests/mpn/t-div.c: Cast a switch index to placate HP's cc.
+	* tests/mpn/t-bdiv.c: Likewise.
+
+	* mpn/pa64/aors_n.asm: Fix support of the 2.0n ABI.
+
+2010-02-24 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* tests/mpz/t-bin.c (data): Replace (2k,k), tested by twos ().
+	* tests/mpf/t-inp_str.c (data): Test also "+" in the exponent.
+
+2010-02-23  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/mod_1_3.c: Cast a switch index to placate HP's cc.
+
+	* mpn/generic/sqrtrem.c: Use CNST_LIMB.
+
+2010-02-20  Niels Möller  <nisse@lysator.liu.se>
+
+	* tune/speed.h (mpn_gcd_accel): Deleted prototype.
+	(mpn_hgcd_lehmer): New prototype.
+	(MPN_HGCD_LEHMER_ITCH): New macro (previously in gmp-impl.h).
+
+	* tune/Makefile.am (libspeed_la_SOURCES): Added hgcd_lehmer.c.
+	* tune/hgcd_lehmer.c: New file.
+	* tune/gcd_accel.c: Deleted obsolete file.
+
+	* gmp-impl.h (MPN_HGCD_LEHMER_ITCH): Deleted macro.
+
+	* mpn/generic/hgcd.c (mpn_hgcd_lehmer): Deleted function,
+	(mpn_hgcd): Don't call mpn_hgcd_lehmer, instead use inlined loop
+	around hgcd_step.
+	(mpn_hgcd_itch): Substitute n for MPN_HGCD_LEHMER_ITCH (n).
+
+2010-02-19  Niels Möller  <nisse@lysator.liu.se>
+
+	* Makefile.am (mpn/jacobitab.h): Added the rules needed to
+	generate this file.
+
+	* gen-jacobitab.c: New file.
+
+2010-02-19  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/powm.c: Honour SQR_BASECASE_THRESHOLD in innerloop
+	expansions.
+
+2010-02-16  Niels Möller  <nisse@lysator.liu.se>
+
+	* tune/time.c (cgt_works_p): Added rudimentary sanity check for
+	clock_gettime working.
+
+2010-02-15  Niels Möller  <nisse@lysator.liu.se>
+
+	* tune/time.c (speed_time_init): Make use of cycle counter
+	configurable, via the speed_option_cycles_broken flag.
+	* tune/common.c (speed_option_cycles_broken): New global variable.
+	(speed_option_set): Recognize option "cycles-broken".
+
+	* tune/time.c (cycles_works_p): Deleted hack to disable cycle
+	counter on linux. Needs to be replaced by something more
+	selective.
+
+2010-02-11  Niels Möller  <nisse@lysator.liu.se>
+
+	* tune/time.c (speed_time_init): Fix speed_time_string when using
+	clock_gettime.
+	(cycles_works_p): On linux, don't use the cycle counter.
+
+	* tune/Makefile.am: Add $(TUNE_LIBS) when linking programs.
+
+	* configure.in: Check if -lrt is needed for clock_gettime, and if
+	so, add that flag to TUNE_LIBS.
+
+2010-02-07  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tune/tuneup.c (tune_redc): Set min_size and min_is_always when
+	measuring REDC_1_TO_REDC_2_THRESHOLD.
+	(tune_mod_1): Set min_size for PREINV_MOD_1_TO_MOD_1_THRESHOLD.
+
+	* mpn/x86_64/aorrlsh_n.asm (cnt): Fix a typo.
+	* mpn/x86_64/lshsub_n.asm: Likewise.
+
+2010-02-05  Torbjorn Granlund  <tege@gmplib.org>
+
+	* Version 5.0.1 released.
+
+	* mpn/generic/powm.c: Use rp target area for power table computation in
+	order to use less scratch.
+
+	* mpn/generic/binvert.c (mpn_binvert_itch): Enable more economical
+	mpn_mulmod_bnm1_itch call.
+
+	* mpn/generic/mu_div_qr.c: Remove always true #if.
+	* mpn/generic/mu_divappr_q.c: Likewise.
+	* mpn/generic/mu_bdiv_q.c: Likewise.
+	* mpn/generic/mu_bdiv_qr.c: Likewise.
+
+2010-02-01  Torbjorn Granlund  <tege@gmplib.org>
+
+	* Makefile.am (LIBGMP_LT_*, LIBGMPXX_LT_*, LIBMP_LT_*):
+	Bump version info.
+
+	* mpn/powerpc64/mode64/gmp-mparam.h: Remove {MUL,SQR}_FFT_TABLE2.
+	* mpn/x86/p6/gmp-mparam.h: Likewise.
+	* mpn/x86/p6/mmx/gmp-mparam.h: Likewise.
+	* mpn/generic/mul_fft.c: Don't depend on FFT_TABLE2, it was broken.
+
+2010-01-29  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/mul_fft.c (mpn_mul_fft_internal): Remove arguments n, m,
+	k and rec; add argument sqr.  Don't call mpn_mul_fft_decompose here,
+	instead do that in all callers.
+	(mpn_mul_fft): Trim allocation when squaring, and use TMP_ALLOC*, not
+	explicit alloc/free.
+	(mpn_fft_div_2exp_modF): Avoid a scalar division.
+	(mpn_fft_mul_modF_K): Replace some multiplies by K with shifting by k.
+	(mpn_fft_mul_2exp_modF): Make function more symmetrical.
+
+2010-01-27  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/mu_div_q.c (mpn_mu_div_q_itch): Rewrite.
+	* mpn/generic/mu_div_qr.c (mpn_mu_div_qr_itch): Re-enable
+	better mulmod itch estimate.
+	* mpn/generic/mu_divappr_q.c (mpn_mu_divappr_q_itch): Likewise.
+	* mpn/generic/mu_bdiv_qr.c (mpn_mu_bdiv_qr_itch): Likewise.
+	* mpn/generic/mu_bdiv_q.c (mpn_mu_bdiv_q_itch): Likewise.
+
+2010-01-27 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/mu_div_qr.c (mpn_mu_div_qr_itch): Disabled guessed
+	estimate, enabled a conservative one.
+	* mpn/generic/mu_divappr_q.c (mpn_mu_divappr_q_itch): Likewise.
+	* mpn/generic/mu_bdiv_qr.c (mpn_mu_bdiv_qr_itch): Likewise.
+	* mpn/generic/mu_bdiv_q.c (mpn_mu_bdiv_q_itch): Likewise.
+
+2010-01-26 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/mulmod_bnm1.c (mpn_mulmod_bnm1): Partial rewrite to
+	reduce memory usage.
+	* mpn/generic/sqrmod_bnm1.c (mpn_sqrmod_bnm1): Likewise.
+	(mpn_sqrmod_bnm1_next_size): New function.
+
+	* gmp-impl.h (mpn_mulmod_bnm1_itch): Accepts 3 parameters now.
+	(mpn_sqrmod_bnm1_itch): New inline function.
+	(mpn_sqrmod_bnm1_next_size): Declaration and mangling.
+	* mpn/generic/nussbaumer_mul.c: Use the new functions.
+
+	* mpn/generic/invertappr.c (mpn_ni_invertappr): Use new syntax for
+	mpn_mulmod_bnm1_itch.
+	* mpn/generic/mu_divappr_q.c (mpn_mu_divappr_q_itch): Likewise.
+	* mpn/generic/mu_bdiv_qr.c (mpn_mu_bdiv_qr_itch): Likewise.
+	* mpn/generic/mu_bdiv_q.c (mpn_mu_bdiv_q_itch): Likewise.
+	* mpn/generic/mu_div_qr.c (mpn_mu_div_qr_itch): Likewise.
+	* mpn/generic/binvert.c (mpn_binvert_itch): Likewise.
+	* tune/speed.h (SPEED_ROUTINE_MPN_MULMOD_BNM1_CALL): Likewise.
+	(SPEED_ROUTINE_MPN_MULMOD_BNM1_ROUNDED): Likewise.
+
+	* tests/mpn/t-sqrmod_bnm1.c, tests/mpn/t-mulmod_bnm1.c: Test
+	reduced memory usage.
+
+2010-01-25  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tune/tuneup.c (INSERT_FFTTAB): New macro, like old insertion code but
+	also inserting a sentinel.
+	(fftmes): Use INSERT_FFTTAB for inserting new measurements.
+	Limit k range to best_k - 4 ... best_k + 4.
+
+2010-01-23  Torbjorn Granlund  <tege@gmplib.org>
+
+	* gmp-h.in (__GNU_MP_VERSION_PATCHLEVEL): Bump.
+	(__GMP_MP_RELEASE): New macro.
+
+	* mpf/div.c: Rewrite to use mpn_div_q.
+
+2010-01-21  Torbjorn Granlund  <tege@gmplib.org>
+
+	* Add FFT_TABLE3 tables for a basic set of machines.
+
+	* configure.in: Use -mtune=nocona for 64-bit pentium4.
+
+	* config.guess: Recognise many more Intel processors.
+
+	* tune/common.c: Whitespace cleanup.
+	(speed_mpn_matrix22_mul): Rewrite.
+
+2010-01-21  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/nussbaumer_mul.c (mpn_nussbaumer_mul): Take
+	advantage of new mpn_mulmod_bnm1 interface, to reduce allocation.
+
+	* tests/mpn/t-mulmod_bnm1.c (ref_mulmod_bnm1, main): Adapted to
+	mpn_mulmod_bnm1 interface change.
+
+	* mpn/generic/mulmod_bnm1.c (mpn_mulmod_bnm1): Interface change,
+	in case an + bn < rn, only write an + bn output limbs. New input
+	requirement, an + bn > rn/2.
+	* mpn/generic/sqrmod_bnm1.c (mpn_sqrmod_bnm1): Corresponding
+	changes.
+
+2010-01-19  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tune/tuneup.c (fftmes): Round up initial n according to initial k.
+	Limit k to 24 in loop.  Remove an obsolete always-true condition.
+	Remove a redundant trace printout.
+
+2010-01-18  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tune/tuneup.c (fftmes): New function
+	(fft): Rewrite.
+	(mpn_mul_fft_lcm): New function, copied from mpn/generic/mul_fft.c.
+	(fftfill): New function, code taken from mul_fft.c (mpn_mul_fft).
+	(cached_measure): New function.
+
+	* gmp-impl.h (struct fft_table_nk): Moved from mul_fft.c.
+	(MUL_FFT_TABLE3, SQR_FFT_TABLE3): Provide dummy versions for tuneup
+	builds.
+	(FFT_TABLE3_SIZE): Increase value for tuneup builds.
+
+	* mpn/generic/mul_fft.c: Handle a new FFT threshold table type ("3").
+	Misc cleanups to old table type code.
+
+2010-01-16  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/darwin.m4: Fix typo in last change.
+
+2010-01-15  Torbjorn Granlund  <tege@gmplib.org>
+
+	* gmp-h.in (__GMP_EXTERN_INLINE): Remove "extern" for newer Sun C.
+
+	* gmp-impl.h (GMP_LIMB_BYTES): New define.
+
+	* mpn/x86_64/darwin.m4 (LEA): New define.
+
+	* mpn/x86/invert_limb.asm (approx_tab): Use DEF_OBJECT.
+	Rename and globalise it to work around Mac OS bug.
+
+	With Philip McLaughlin:
+	* mpn/x86_64/gcd_1.asm (ctz_table): Don't use local prefix, but
+	use DEF_OBJECT...END_OBJECT.
+	Keep stack pointer at ABI mandated alignment over call.
+
+2010-01-12  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tune/speed.c (routine): Remove obsolete mpn_dc_tdiv_qr and
+	mpn_dc_div_qr_n.
+	* tune/common.c (speed_mpn_dc_tdiv_qr, speed_mpn_dcpi1_div_qr_n):
+	Remove now unused functions.
+	* tune/speed.h (SPEED_ROUTINE_MPN_DC_DIVREM_N,
+	SPEED_ROUTINE_MPN_DC_DIVREM_SB, SPEED_ROUTINE_MPN_DC_TDIV_QR): Remove
+	now unused macros.
+
+	* mpn/x86_64/fat/fat_entry.asm (mpn_cpuid_available): Remove function.
+
+	* ltmain.sh: Upgrade from 1.5.24 to 2.2.6b.
+	* ylwrap: New file.
+	* .bootstrap: Remove explicit versions.
+
+	* doc/gmp.texi (Block-wise Barrett Division): New node.
+
+	* mpn/generic/powm.c: Change some #if to plain 'if' to avoid fat build
+	problems.
+
+2010-01-11  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tune/speed.h (SPEED_ROUTINE_MPN_PI1_DIV): Accept arguments for size
+	restrictions.
+	* tune/common.c (speed_mpn_sbpi1_div_qr, speed_mpn_dcpi1_div_qr,
+	(speed_mpn_sbpi1_divappr_q, speed_mpn_dcpi1_divappr_q): Pass size
+	limits for SPEED_ROUTINE_MPN_PI1_DIV.
+
+	* tune/speed.c (routine): Allow .r argument for mpn_sbpi1_divappr_q and
+	mpn_dcpi1_divappr_q.
+
+2010-01-08  Torbjorn Granlund  <tege@gmplib.org>
+
+	* Version 5.0.0 released.
+
+	* mpn/generic/div_q.c: Handle mpn_*_divappr_q returning high limb
+	everywhere.
+
+2010-01-07  Torbjorn Granlund  <tege@gmplib.org>
+
+	* Update MUL_FFT_TABLE2 and SQR_FFT_TABLE2 for many machines.
+
+	* mpn/generic/mu_div_q.c: Account for divisor truncation error as well
+	as mpn_mu_divappr_q's error.
+
+	* mpn/generic/mu_div_q.c: Handle mpn_preinv_mu_divappr_q returning a
+	high limb.
+
+	* tests/mpn/t-bdiv.c: Move a random call for debugability.
+	* tests/mpn/t-div.c: Likewise.
+
+	* mpn/generic/mu_divappr_q.c: Rewrite quotient round-up code.
+
+	* mpn/generic/mu_div_qr.c: Handle carry-out from a carry propagation
+	subtract.
+	* mpn/generic/mu_divappr_q.c: Likewise.
+
+	* mpn/generic/mu_divappr_q.c
+	(mpn_preinv_mu_divappr_q, mpn_mu_divappr_q): Declare dividend constant.
+	* gmp-impl.h: Likewise.
+
+	* perfpow.c (mpn_perfect_power_p): Call mpn_divexact instead of
+	mpn_bdiv_q (with too little scratch space!).
+
+	From Niels Möller:
+	* tests/mpn/t-div.c (check_one): Get rid of the poorly managed variable
+	tn.
+
+	* mpn/minithres/gmp-mparam.h: Add all lately defined thresholds.
+
+	* mpn/generic/div_q.c: Use SB division for small quotients as well as
+	small divisors.  Fix typo in itch call.
+
+2010-01-06  Niels Möller  <nisse@lysator.liu.se>
+
+	* tests/mpn/t-div.c (check_one): Checking based on multiplication,
+	refmpn_mul, rather than refmpn_tdiv_qr.
+
+2010-01-06 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/toom8h_mul.c: Avoid overflows of mp_size_t.
+
+2010-01-06  Torbjorn Granlund  <tege@gmplib.org>
+
+	* gmp-h.in (__GNU_MP__): Bump.
+	(__GNU_MP_VERSION,__GNU_MP_VERSION_MINOR,__GNU_MP_VERSION_PATCHLEVEL):
+	Bump version info.
+	* mp-h.in (__GNU_MP__): Bump.
+	* Makefile.am (LIBGMP_LT_*, LIBGMPXX_LT_*, LIBMP_LT_*):
+	Bump version info.
+
+	* doc/gmp.texi: Rewrite mpn_gcdext text.  Remove some out-of-date
+	text in Algorithms chapter.
+
+	* mpn/generic/div_q.c: Properly handle np=scratch.  Fix critical typo
+	in final adjustment code.  Misc cleanups.
+
+	* mpn/generic/rootrem.c: Use mpn_div_q.
+	* mpz/tdiv_q.c: Likewise.
+
+	* tests/mpn/t-div.c: Test mpn_div_q.
+	(SIZE_LOG): Up to 17.
+
+	* mpn/generic/div_q.c: New file.
+	* configure.in (gmp_mpn_functions): Add div_q.
+
+	* mpn/generic/mu_div_q.c: Actually declare dividend constant.
+
+2010-01-04  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tune/tuneup.c (fft): Separate tuning of modf and full products.
+	(struct fft_param_t): New field, mul_modf_function.
+	(tune_fft_sqr): Fix typo.
+	(tune_fft_mul, tune_fft_sqr): Initialise mul_modf_function field.
+	* tune/common.c (speed_mpn_fft_mul, speed_mpn_fft_sqr): New functions.
+
+	* tune/speed.h (SPEED_ROUTINE_MPN_MULMOD_BNM1_ROUNDED): Clean up.
+
+	* mpn/generic/mul.c: Simplify rational expression.
+
+	* gmp-impl.h: Cleanup threshold variables; remove obsolete ones and
+	make all possibly needed definitions for existing ones.
+	* tune/tuneup.c (tune_mul): Write fractions-compensated values to
+	threshold variables.
+
+2010-01-03 Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* tune/common.c, tune/speed.c, tune/speed.h: Support measuring
+	mpn_toom43_mul.
+
+	* mpn/generic/toom_interpolate_6pts.c: Small reorganisation.
+
+2010-01-03  Torbjorn Granlund  <tege@gmplib.org>
+
+	* gmp-impl.h (MUL_TO_MULMOD_BNM1_FOR_2NXN_THRESHOLD): Default to
+	INV_MULMOD_BNM1_THRESHOLD/2 instead.
+
+	* gmp-impl.h (INV_APPR_THRESHOLD, INV_MULMOD_BNM1_THRESHOLD): Default
+	here...
+	* mpn/generic/invert.c, mpn/generic/invertappr.c: ...not here.
+
+	* tests/mpn/t-div.c: Rewrite operand generation code.
+
+2010-01-02  Torbjorn Granlund  <tege@gmplib.org>
+
+	* gmp-impl.h (MUL_TO_MULMOD_BNM1_FOR_2NXN_THRESHOLD): Default to
+	INV_MULMOD_BNM1_THRESHOLD.
+
+2010-01-02  Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/dcpi1_div_q.c: Handle divappr approximation problem more
+	efficiently.
+	* mpn/generic/mu_div_q.c: Likewise.
+
+	* mpn/generic/invert.c: Remove duplicated code.
+
+2010-01-01  Torbjorn Granlund  <tege@gmplib.org>
+
+	* gmp-impl.h (MUL_TO_MULMOD_BNM1_FOR_2NXN_THRESHOLD): Default to 0.
+
+	* mpn/generic/mu_div_qr.c: Rewrite to use mpn_mulmod_bnm1.  Clean up
+	scratch usage.  Improve itch functions.
+	* mpn/generic/mu_divappr_q.c: Likewise.
+	* mpn/generic/mu_bdiv_qr.c: Likewise.
+	* mpn/generic/mu_div_q.c: Likewise.
+
+	* mpn/generic/dcpi1_bdiv_qr.c: Add parameter ASSERTs.
+	* mpn/generic/dcpi1_bdiv_q.c: Likewise.
+
+	* tests/mpn/t-bdiv.c: Replace with unit testing code, based on t-div.c.
+	Increase COUNT to 500.
+
+	* tests/mpn/t-div.c: Avoid generating too small test operands.
+	Move SB suppression limit downwards.  Increase COUNT to 200.
+
+2009-12-31  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/tdiv_qr.c: Handle numerator/remainder overlap in MU case.
+
+	* tests/tests.h (TESTS_REPS): New macro.
+	* tests/mpz/dive.c: Use larger operands, decrease default reps, use
+	TESTS_REPS.
+	* tests/mpz/convert.c: Likewise.
+	* tests/mpz/t-sqrtrem.c: Likewise.
+	* tests/mpz/reuse: Likewise.
+	* tests/mpz/t-root.c: Likewise.
+	* tests/mpz/t-tdiv.c: Likewise.
+	* tests/mpz/t-gcd.c: Likewise.
+	* tests/mpz/t-powm.c: Likewise.
+
+2009-12-31  Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/toom8_sqr.c (SQR_TOOM8_MAX): Avoid overflow.
+	* mpn/generic/toom6_sqr.c (SQR_TOOM6_MAX): Likewise.
+
+	* mpn/generic/mulmod_bnm1.c: Don't mention MISUSE any more,
+	simply consider UNLIKELY any unexpected size.
+
+2009-12-31  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tune/tuneup.c (speed_mpn_sbordcpi1_div_qr): New function.
+	(tune_mu_div): Use it.
+
+2009-12-30  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tune/tuneup.c (tune_mu_bdiv, tune_dc_bdiv, tune_mu_div)
+	(tune_dc_div): Clear global s.r to make speed functions do 2n/n.
+
+	* tune/speed.c (routine): New entries for mpn_mu_div_qr and
+	mpn_mupi_div_qr.  Allow .r parameter for mpn_sbpi1_div_qr,
+	mpn_dcpi1_div_qr.
+	* tune/speed.h (SPEED_ROUTINE_MPN_PI1_DIV, SPEED_ROUTINE_MPN_MU_DIV_QR)
+	(SPEED_ROUTINE_MPN_MUPI_DIV_QR): Handle .r parameter.
+
+	* tests/mpz/t-tdiv.c: Increase operands size again.
+
+	* mpn/generic/tdiv_qr.c: Attempt to choose between DC and MU cleverer.
+
+	* mpn/generic/tdiv_qr.c: Don't overwrite rp with unnecessary temporary
+	alloc.
+
+2009-12-29  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tune/tuneup.c (tune_mu_div): Tune MUPI_DIV_QR_THRESHOLD.
+	* tune/speed.h (struct speed_params): Allow 3 source operands.
+	(SPEED_ROUTINE_MPN_MUPI_DIV_QR): New macro.
+	* tune/common.c (speed_mpn_mupi_div_qr): New function.
+
+	* mpn/generic/tdiv_qr.c: Call mpn_mu_div_qr.
+
+	* tests/mpz/t-tdiv.c: Use larger test operands.
+
+	* mpn/generic/mu_div_qr.c (mpn_mu_div_qr2): Remove code for dn==1.
+
+	* mpz/mul.c: Call mpn_sqr directly.  Use PTR,SIZ,ALLOC.
+
+	* tune/tuneup.c (tune_mu_div): Set min_size to 6, DC functions require
+	this.
+
+	* tests/mpn/t-div.c: Call mu_div functions with operands that generate
+	a high quotient limb.
+
+	* mpn/generic/mu_div_qr.c: Rewrite to return a high quotient limb,
+	to let dividend argument be constant, and as a general cleanup.
+	* mpn/generic/mu_divappr_q.c: Likewise.
+	* mpn/generic/mu_div_q.c: Likewise.
+	* gmp-impl.h: Update declarations of changed functions.
+
+	* mpn/generic/invertappr.c (mpn_invertappr): Allocate scratch space
+	when caller passed NULL.
+
+2009-12-28  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/toom_couple_handling.c: Prefix name with mpn_.
+	* gmp-impl.h: Likewise.
+	* mpn/generic/toom63_mul.c: Likewise.
+	* mpn/generic/toom6_sqr.c: Likewise.
+	* mpn/generic/toom6h_mul.c: Likewise.
+	* mpn/generic/toom8_sqr.c: Likewise.
+	* mpn/generic/toom8h_mul.c: Likewise.
+
+	* configure.in (gmp_mpn_functions_optional) Move "com" from here...
+	(gmp_mpn_functions): ...to here.
+	* mpn/generic/com.c: New file.
+	* (mpn_com): New name for mpn_com_n.  Make public.
+	* (mpn_neg): Analogous changes.
+
+	* tune/tuneup.c (tune_mu_div, tune_mu_bdiv): Set step_factor.
+
+	* tune/common.c, tune/speed.c, tune/speed.h: Support measuring
+	mpn_lshiftc.
+
+	* tests/devel/try.c: Test mpn_lshiftc.
+	* tests/refmpn.c (refmpn_com): New function.
+	(refmpn_lshiftc): Likewise.
+
+	* configure.in (gmp_mpn_functions_optional) Move lshiftc from here...
+	(gmp_mpn_functions): ...to here.
+	* mpn/generic/lshiftc.c: New file.
+	* mpn/x86_64/lshiftc.asm: New file.
+	* mpn/x86_64/core2/lshiftc.asm: New file.
+	* mpn/generic/mul_fft.c (mpn_lshiftc): Remove.
+
+	* mpn/x86_64/core2/lshift.asm: Tweak for better Core iN performance.
+	* mpn/x86_64/core2/rshift.asm: Likewise.
+
+2009-12-27  Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/mul.c: Use toom6h and toom8h for almost balanced.
+
+	* mpn/generic/mullo_n.c (mpn_dc_mullo_n): New ratio, to be used in
+	Toom-8 range.
+
+2009-12-27  Torbjorn Granlund  <tege@gmplib.org>
+
+	* (mpn_sqr): New name for mpn_sqr_n.  Many files affected.
+
+	* tune/tuneup.c (tune_mullo): Up step_factor for MULLO_MUL_N_THRESHOLD.
+	(tune_invertappr, tune_invert, tune_binvert): Let max_size default.
+
+	* tune/tuneup.c (tune_mu_div, tune_mu_bdiv) New functions.
+	* tune/speed.h (SPEED_ROUTINE_MPN_MU_DIV_Q): New macro.
+	(SPEED_ROUTINE_MPN_MU_DIV_QR): Likewise.
+	(SPEED_ROUTINE_MPN_MU_BDIV_Q): Likewise.
+	(SPEED_ROUTINE_MPN_MU_BDIV_QR): Likewise.
+	* tune/Makefile.am (TUNE_MPN_SRCS_BASIC): Add bdiv_q.c and bdiv_qr.c.
+	* tune/common.c (speed_mpn_mu_div_qr): New function.
+	(speed_mpn_mu_divappr_q): Likewise.
+	(speed_mpn_mu_div_q): Likewise.
+	(speed_mpn_mu_bdiv_q): Likewise.
+	(speed_mpn_mu_bdiv_qr): Likewise.
+
+	* mpn/*/gmp-mparam.h: Fix incorrect MOD_1U_TO_MOD_1_1_THRESHOLD 0
+	values.
+
+	* gmp-impl.h (MODEXACT_1_ODD_THRESHOLD): Remove.
+	(BMOD_1_TO_MOD_1_THRESHOLD): New parameter, with the reverse meaning of
+	MODEXACT_1_ODD_THRESHOLD.
+	(MPN_MOD_OR_MODEXACT_1_ODD): Use BMOD_1_TO_MOD_1_THRESHOLD.
+	* mpn/generic/divis.c, mpz/{cong.c,cong_ui.c,divis_ui.c}: Likewise.
+	* tune/tuneup.c (tune_modexact_1_odd): Tune BMOD_1_TO_MOD_1_THRESHOLD;
+	Do not assume native mpn_modexact_1_odd is faster than mpn_mod_1.
+	(tuned_speed_mpn_mod_1): Remove variable.
+	(tune_mod_1): Fix thinkos.  Suppress printing of "always" etc.
+	(all): Measure for divrem_1, mod_1, divexact_1, etc first, since Toom
+	depends on some of them.
+
+	* mpn/generic/toom22_mul.c (TOOM22_MUL_REC): New name for
+	TOOM22_MUL_MN_REC.
+
+2009-12-26  Niels Möller  <nisse@lysator.liu.se>
+
+	* tests/mpn/t-toom32.c (MIN_AN, MIN_BN, MAX_BN): Relax
+	requirements a bit.
+
+	* mpn/generic/toom32_mul.c (mpn_toom32_mul): Relax requirement on
+	input sizes, to support s+t>=n (used to be s+t>=n+2). Keep high
+	limbs of the evaluated values in scalar variables.
+
+	* mpn/generic/sbpi1_divappr_q.c (mpn_sbpi1_divappr_q): Remove
+	unused variables.
+
+	* mpn/generic/toom32_mul.c (mpn_toom32_mul): Fixed left-over use
+	of mpn_addsub_n which should be mpn_add_n_sub_n.
+
+2009-12-26  Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* tune/Makefile.am (TUNE_MPN_SRCS_BASIC): Add new toom files (spotted by Torbjorn).
+
+	* gmp-impl.h (mpn_toom6_sqr_itch): Rename to mpn_toom6_mul_n_itch and redefine.
+	(mpn_toom8_sqr_itch): Rename to mpn_toom8_mul_n_itch and redefine.
+	* mpn/generic/mul_n.c: Use renamed _itch macros.
+
+2009-12-25  Niels Möller  <nisse@lysator.liu.se>
+
+	* tests/mpn/t-toom32.c (MIN_AN, MIN_BN, MAX_BN): Tightened requirements.
+	* gmp-impl.h (mpn_toom32_mul_itch): Updated. Less scratch needed
+	by toom32 itself, and also the pointwise multiplications are
+	currently mpn_mul_n with no supplied scratch.
+	* mpn/generic/toom32_mul.c (mpn_toom32_mul): Reorganized
+	interpolation to use less scratch space. No longer supports the
+	most extreme size ratios.
+
+2009-12-25  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tune/tuneup.c (tune_preinv_mod_1): Purge.
+	(tune_mod_1): Use speed_mpn_mod_1_tune for
+	PREINV_MOD_1_TO_MOD_1_THRESHOLD
+
+	* mpn/generic/dcpi1_divappr_q.c: Handle 2n/n properly.  Don't use full
+	precision in mpn_sbpi1_divappr_q call.  Misc cleanup.
+
+	* tune/tuneup.c (tune_mod_1): Add a check_size for
+	PREINV_MOD_1_TO_MOD_1_THRESHOLD.
+
+2009-12-24  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tune/mod_1_div.c (MOD_1N_TO_MOD_1_1_THRESHOLD,
+	(MOD_1U_TO_MOD_1_1_THRESHOLD): Set.
+	* tune/mod_1_inv.c (MOD_1N_TO_MOD_1_1_THRESHOLD,
+	(MOD_1U_TO_MOD_1_1_THRESHOLD): Set.
+
+	* gmp-impl.h (USE_PREINV_MOD_1): Remove.
+	(MPN_MOD_OR_PREINV_MOD_1): Define to choose functions dynamically in
+	terms of PREINV_MOD_1_TO_MOD_1_THRESHOLD (used to choose statically
+	using USE_PREINV_MOD_1).
+	* mpn/generic/perfsqr.c (PERFSQR_MOD_PP): Corresponding updates.
+
+	* tune/tuneup.c (tune_mod_1): Rewrite.
+	* gmp-impl.h (MOD_1N_TO_MOD_1_1_THRESHOLD): New.
+	(MOD_1U_TO_MOD_1_1_THRESHOLD): New name for MOD_1_1_THRESHOLD.
+	(MOD_1_1_TO_MOD_1_2_THRESHOLD): Mew name for MOD_1_2_THRESHOLD.
+	(MOD_1_2_TO_MOD_1_4_THRESHOLD): New name for MOD_1_4_THRESHOLD.
+	* mpn/generic/mod_1.c: Corresponding updates.
+
+2009-12-24  Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/mul_n.c: Use also toom6h and toom8h.
+	* mpn/generic/sqr_n.c: Use also toom6 and toom8.
+	* gmp-impl.h: Initial support for tuning of Toom-6half and Toom-8half.
+	* tune/tuneup.c: Tune Toom-6half and Toom-8half thresholds.
+
+2009-12-24  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/mod_1_4.c: Get ASSERT right.
+	* mpn/generic/mod_1_3.c: Likewise.
+	* mpn/generic/mod_1_2.c: Likewise.
+
+	* mpn/generic/powm_sec.c: Use SQR_TOOM2_THRESHOLD as limit for a native
+	mpn_sqr_basecase, not TUNE_SQR_TOOM2_MAX.
+
+2009-12-23  Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* tune/common.c, tune/speed.c, tune/speed.h: Support for measuring
+	mpn_toom8h_mul and mpn_toom8_sqr speed.
+
+	* mpn/generic/toom_eval_pm2exp.c: Fix ASSERTs.
+
+	* mpn/generic/toom8h_mul.c: New file.
+	* mpn/generic/toom8_sqr.c: New file.
+	* mpn/generic/toom_interpolate_16pts.c: New file.
+	* gmp-impl.h: Provide corresponding declarations.
+	* configure.in (gmp_mpn_functions): List toom_interpolate_16pts,
+	toom8h_mul, and toom8h_sqr.
+	* tests/mpn/t-toom8h.c: New test program.
+
+	* mpn/generic/toom6_sqr.c: New file, was part of toom6h_mul.
+	* mpn/generic/toom6h_mul.c: Removed _sqr.
+
+	* mpn/generic/mulmod_bnm1.c: Nailify CRT.
+	* mpn/generic/sqrmod_bnm1.c: Likewise.
+
+	* mpn/generic/mullo_n.c: Split dc_mullo_n function;
+	ALLOC memory at once.
+
+	* mpn/Makefile.am (nodist_EXTRA_libmpn_la_SOURCES): Update.
+
+	* mpn/generic/toom6h_mul.c: Add prefix to toom_interpolate_12pts.
+	* mpn/generic/toom_interpolate_12pts.c: Likewise.
+
+	* mpn/generic/invertappr.c (mpn_bc_invertappr): Use mpn_divrem_2.
+	* mpn/generic/invert.c: Faster basecase, use mpn_sbpi1_div_q.
+
+	* mpn/generic/toom_eval_pm2exp.c: Assert support for degree 3.
+	* mpn/generic/toom6h_mul.c: Avoid obsolete _itch function.
+
+2009-12-23  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tune/common.c, tune/speed.c, tune/speed.h: Support for measuring
+	mpn_mod_1_1p, mpn_mod_1s_2p, mpn_mod_1s_3p, mpn_mod_1s_4p.
+
+	* tests/mpz/t-powm.c: Test mpz_powm_sec.
+
+	* mpz/powm_sec.c: New file.
+	* gmp-h.in: Declare it.
+	* Makefile.am, mpz/Makefile.am: Compile it.
+	* doc/gmp.texi: Document it.
+
+	* mpn/generic/powm_sec.c (mpn_powm_sec_itch): New function.
+	(mpn_powm_sec): Use passed scratch, no local allocation.
+	Allow exp argument = 1.
+	(win_size): Start loop from 1.
+
+	* mpn/generic/powm.c (win_size): Start loop from 1.
+
+2009-12-22  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/mpn/t-div.c: New file.
+	* tests/mpn/Makefile.am: Compile it.
+
+	* mpn/generic/mu_divappr_q.c: Handle quotient overflow.
+
+	* mpn/generic/mu_div_q.c (mpn_mu_div_q_itch): New function.
+
+2009-12-22  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/sbpi1_div_q.c: Use udiv_qr_3by2.  Intended to change
+	nothing after preprocessing.
+
+	* mpn/generic/sbpi1_divappr_q.c: For the last call to udiv_qr_3by2,
+	avoid using memory locations as output parameters, and revert to
+	explicitly copying n1 and n0 to memory.
+
+	* gmp-impl.h (udiv_qr_3by2): Tweaked to expand to precisely the
+	same code as was used before the introduction of this macro.
+	Eliminated some local variables, instead do multiple updates to
+	the output parameters.
+
+2009-12-22  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/mpn/t-toom6h.c (MIN_AN): Set to MUL_TOOM6H_THRESHOLD to avoid
+	invalid recursive sizes.
+
+	* tests/mpn/t-bdiv.c: Get itch function calls right.
+
+	* mpn/generic/mu_bdiv_q.c (mpn_mu_bdiv_q_itch): Rewrite.
+	* mpn/generic/mu_bdiv_qr.c (mpn_mu_bdiv_qr_itch): Simplify.
+
+	* mpn/generic/bdiv_qr.c (mpn_bdiv_qr): Simplify, don't allocate.
+	(mpn_bdiv_qr_itch): Conditionalise on MU_BDIV_QR_THRESHOLD.
+
+2009-12-18  Niels Möller  <nisse@lysator.liu.se>
+
+	* tests/mpn/t-bdiv.c: Add red-zones.
+
+2009-12-21  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/sbpi1_div_q.c: Fix fixup code to work for qn = 0.
+
+	* mpn/generic/dcpi1_divappr_q.c: Handle qn = 1 and qn = 2 for initial
+	quotient block (code block copied from dcpi1_div_qr.c).
+
+	* mpn/generic/dcpi1_div_qr.c: Rewrite singular case giving q limb of
+	GMP_NUMB_MAX.  Remove an impossible qn = 0 case.
+
+	* mpn/generic/dcpi1_bdiv_q.c: Remove a spurious mpn_sub_1.
+
+	* mpn/generic/mul.c: Put back call to mpn_mul_n.
+
+	* tune/tuneup.c (all): Call tune_mulmod_bnm1 before tuning fft due to
+	dependency on mulmod_bnm1 from both mul_fft_mul and from mullo_n.
+
+	* mpn/generic/dcpi1_divappr_q.c: ASSERT that dn >= 6 and nn > dn.
+	* mpn/generic/dcpi1_div_q.c: ASSERT that dn >= 6 and nn-dn >= 3.
+	* mpn/generic/dcpi1_div_qr.c: ASSERT that dn >= 6 and nn-dn >= 3.
+
+	* mpn/generic/bdiv_q_1.c (mpn_pi1_bdiv_q_1): Renamed from
+	mpn_bdiv_q_1_pi1.
+	* All references changed.
+
+	* configure.in: Add --enable-old-fft-full.
+	* tune/speed.c (routine): Conditionalise mpn_mul_fft_full references on
+	WANT_OLD_FFT_FULL.
+	* tune/common.c (speed_mpn_mul_fft_full)
+	(speed_mpn_mul_fft_full_sqr): Likewise.
+	* mpn/generic/mul_fft.c (mpn_mul_fft_full): Include iff
+	WANT_OLD_FFT_FULL.
+
+2009-12-21  Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* gmp-impl.h (mpn_toom6h_mul_itch): New inline function.
+	(MUL_TOOM6H_THRESHOLD): Default value.
+	(SQR_TOOM6_THRESHOLD): Default value.
+	* mpn/generic/toom6h_mul.c: Remove definitions moved to gmp-impl.h.
+	* tune/common.c, tune/speed.c, tune/speed.h: Support for measuring
+	mpn_toom6h_mul and mpn_toom6_sqr speed.
+
+	* mpn/generic/toom63_mul.c: Remove unused TMP_*.
+
+	* mpn/generic/toom_eval_pm2rexp.c: New file.
+	* gmp-impl.h: Provide corresponding declaration.
+	* configure.in (gmp_mpn_functions): List toom_eval_pm2rexp.
+	* mpn/generic/toom6h_mul.c: Use shared toom_eval_pm2rexp.
+
+	* mpn/generic/toom_couple_handling.c: New file, helper function
+	for high degree Toom.
+	* gmp-impl.h: Provide corresponding declaration.
+	* configure.in (gmp_mpn_functions): List toom_couple_handling.
+	* mpn/generic/toom6h_mul.c: Use shared toom_couple_handling.
+	* mpn/generic/toom63_mul.c: Likewise.
+
+	* mpn/generic/toom6h_mul.c: New file.
+	* mpn/generic/toom_interpolate_12pts.c: New file.
+	* gmp-impl.h: Provide corresponding declarations.
+	* configure.in (gmp_mpn_functions): List toom_interpolate_12pts,
+	toom6h_mul.
+	* tests/mpn/t-toom6h.c: New test program.
+
+	* tests/mpn/t-mulmod_bnm1.c (ref_mulmod_bnm1): Use ref_mul.
+	* tests/mpn/t-sqrmod_bnm1.c (ref_sqrmod_bnm1): Likewise.
+
+2009-12-20  Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/mulmod_bnm1.c (mpn_mulmod_bnm1): New CRT.
+	* mpn/generic/sqrmod_bnm1.c (mpn_sqrmod_bnm1): Likewise.
+
+2009-12-20  Torbjorn Granlund  <tege@gmplib.org>
+
+	* Change all bit counts for bignums to use mp_bitcnt_t.
+
+	* mpn/generic/bdivmod.c: File removed.  All references purged.
+
+	* mpn/generic/mul_fft.c (mpn_mul_fft_full): Disable.
+
+	* gmp-impl.h: Define mpn_fft_mul as an alias for mpn_nussbaumer_mul.
+	* mpn/generic/mul.c: Refer mpn_fft_mul.
+	* mpn/generic/mul_n.c: Likewise.
+	* mpn/generic/sqr_n.c: Likewise.
+	* mpn/generic/mullo_n.c: Likewise.
+
+	* mpn/generic/mul.c: Loop also over mpn_nussbaumer_mul, as suggested by
+	Marco.  Use TMP_SALLOC_LIMBS in more places.  Clean up ws allocation.
+
+2009-12-19  Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/toom_interpolate_8pts.c: Nailify.
+
+2009-12-19  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/mul.c: Major rewrite.  Use toom43, toom53, toom63.
+	Call mpn_nussbaumer_mul for largest operands.
+
+	* tune/speed.h (SPEED_ROUTINE_MPN_TOOM32_FOR_TOOM43_MUL): New macro.
+	(SPEED_ROUTINE_MPN_TOOM43_FOR_TOOM32_MUL): New macro.
+	(SPEED_ROUTINE_MPN_TOOM32_FOR_TOOM53_MUL): New macro.
+	(SPEED_ROUTINE_MPN_TOOM53_FOR_TOOM32_MUL): New macro.
+	(SPEED_ROUTINE_MPN_TOOM42_FOR_TOOM53_MUL): New macro.
+	(SPEED_ROUTINE_MPN_TOOM53_FOR_TOOM42_MUL): New macro.
+	* tune/common.c (speed_mpn_toom63_mul): New function.
+	(speed_mpn_toom32_for_toom43_mul): New function.
+	(speed_mpn_toom43_for_toom32_mul): New function.
+	(speed_mpn_toom32_for_toom53_mul): New function.
+	(speed_mpn_toom53_for_toom32_mul): New function.
+	(speed_mpn_toom42_for_toom53_mul): New function.
+	(speed_mpn_toom53_for_toom42_mul): New function.
+	* tune/tuneup.c (tune_mul_n): New name for old tune_mul.
+	(tune_sqr_n): New name for old tune_sqr.
+	(tune_mul): New function, for unbalanced multiplication.
+	* gmp-impl.h: Provide declarations for corresponding threshold vars.
+
+	* gmp-impl.h (mpn_rsh1add_nc, mpn_rsh1sub_nc): Declare.
+	* mpn/asm-defs.m4: Likewise.
+	* configure.in: Add corresponding HAVE_NATIVEs.
+	* mpn/x86_64/rsh1aors_n.asm: Add _nc entry point.
+
+2009-12-18  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpz/divexact.c: Rewrite to use mpn_divexact.
+
+	* mpn/generic/bdiv_q_1.c (mpn_bdiv_q_1): Deleted some unused
+	variables.
+
+	* mpn/generic/toom52_mul.c (mpn_toom52_mul)
+	[HAVE_NATIVE_mpn_add_n_sub_n]: Moved declaration of cy to avoid a
+	compiler warning.
+
+	* gmp-impl.h (gmp_pi1_t): Eliminated inv21 member.
+	(invert_pi1): ...and don't store it here.
+
+	* mpn/generic/toom63_mul.c (mpn_toom63_mul): Simplified
+	calculation of block size n.
+	* gmp-impl.h (mpn_toom63_mul_itch): Likewise.
+
+	* mpn/generic/toom_eval_pm2exp.c (mpn_toom_eval_pm2exp): Fixed
+	output asserts.
+
+2009-12-18  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/mpn/t-toom63.c: New test program.
+
+2009-12-18  Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/invert.c: Nailify.
+	* mpn/generic/invertappr.c: Nailify.
+	* mpn/generic/mulmod_bnm1.c: Nailify.
+	* mpn/generic/sqrmod_bnm1.c: Nailify.
+
+	* tests/mpn/t-invert.c: New test program.
+
+	* mpn/generic/toom63_mul.c: New file.
+	* mpn/generic/toom_interpolate_8pts.c: New file.
+	* gmp-impl.h: Provide corresponding declarations.
+	* configure.in (gmp_mpn_functions): List toom_interpolate_8pts and
+	toom63_mul.
+
+2009-12-17  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/mul.c: Move allocation of ws to where it is used.
+	Identify toom22, 32, 42, in that order (in two places).  Use midline
+	between toom22, 32, 42.
+	* mpn/generic/toom22_mul.c (TOOM22_MUL_MN_REC): Call also
+	mpn_toom32_mul.
+
+	* doc/gmp.texi: Update References section.  Update Contributors
+	section.  Misc updates.
+
+	* gmp-impl.h: Renew default values for all THRESHOLDs.
+
+2009-12-17  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/divexact.c (mpn_divexact): Don't require that the
+	dividend is normalized. Use MPN_DIVREM_OR_PREINV_DIVREM_1. When
+	shifting, allocate and process only the low qn+1 limbs. Eliminated
+	code for the impossible case nn < qn.
+
+	* mpn/generic/dcpi1_div_qr.c (mpn_dcpi1_div_qr): Added some input
+	asserts.
+
+	* mpn/generic/dcpi1_div_qr.c (mpn_dcpi1_div_qr): In the case that
+	the initial quotient block is a single limb, use 3/2 division,
+	thereby eliminating the only use of gmp_pi1_t->inv21.
+
+2009-12-17  Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/invert.c: Added some comment.
+	* mpn/generic/invertappr.c: Slightly better threshold handling.
+	* gmp-impl.h (INV_NEWTON_THRESHOLD): Default to 200.
+
+	* mpn/generic/nussbaumer_mul.c: New file.
+	* configure.in (gmp_mpn_functions): Add nussbaumer_mul.
+	* tune/Makefile.am (TUNE_MPN_SRCS_BASIC): Add nussbaumer_mul.
+	* gmp-impl.h (mpn_nussbaumer_mul): Added prototype and name-mangling.
+	* tune/speed.h (speed_mpn_nussbaumer_mul): Declare function.
+	* tune/common.c (speed_mpn_nussbaumer_mul): New function.
+	* tune/speed.c (routine): Add speed_mpn_nussbaumer_mul.
+
+	* mpn/generic/sqrmod_bnm1.c: New file.
+	* configure.in (gmp_mpn_functions): Add sqrmod_bnm1.
+	* tune/Makefile.am (TUNE_MPN_SRCS_BASIC): Add sqrmod_bnm1.
+	* gmp-impl.h (mpn_sqrmod_bnm1): Added prototype and name-mangling.
+	(SQRMOD_BNM1_THRESHOLD): support for the new threshold.
+	* tune/speed.h (speed_mpn_sqrmod_bnm1): Declare function.
+	* tune/common.c (speed_mpn_sqrmod_bnm1): New function.
+	* tune/speed.c (routine): Add speed_mpn_sqrmod_bnm1.
+	* tests/mpn/t-mulmod_bnm1.c: Attribution.
+	* tests/mpn/t-sqrmod_bnm1.c: New test file.
+	* tests/mpn/Makefile.am (check_PROGRAMS): Add t-sqrmod_bnm1.
+
+	* tune/tuneup.c: Tune SQRMOD_BNM1_THRESHOLD.
+
+	* mpn/generic/nussbaumer_mul.c (mpn_nussbaumer_mul): Mimic fft_mul,
+	use squaring if operands coincide.
+	* tune/speed.h (speed_mpn_nussbaumer_mul_sqr): Declare function.
+	* tune/common.c (speed_mpn_nussbaumer_mul_sqr): New function.
+	* tune/speed.c (routine): Add speed_mpn_nussbaumer_mul_sqr.
+
+2009-12-17  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/bdiv_q.c (mpn_bdiv_q_itch): Rewrite.
+
+2009-12-16  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/mpn/t-bdiv.c (bdiv_q_valid_p, bdiv_qr_valid_p): Call refmpn_mul
+	instead of refmpn_mul_basecase.
+	* tests/mpn/toom-shared.h: Likewise.
+	* tests/refmpn.c (refmpn_mullo_n,refmpn_sqr,refmpn_mul_any): Likewise.
+
+	* minithres/gmp-mparam.h: Add new thresholds, trim old values.
+
+	* mpn/generic/powm.c: Use mp_bitcnt_t for bit counts.
+	Handle REDC_1_TO_REDC_N_THRESHOLD < MUL_TOOM22_THRESHOLD in
+	non-WANT_REDC_2 INNERLOOP expansion code.
+	* mpn/generic/powm_sec.c: Use mp_bitcnt_t for bit counts.
+
+2009-12-16  Niels Möller  <nisse@lysator.liu.se>
+
+	* tests/mpz/t-gcd.c (main): Added test case to exercise the
+	unlikely u0 == u1 case in mpn_gcdext_lehmer_n.
+
+	* mpn/generic/gcdext_lehmer.c (mpn_gcdext_lehmer_n): Get ASSERT
+	right.
+
+2009-12-16  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/mpz/t-mul.c: Misc cleanups.
+	(mul_basecase): Remove.
+	(ref_mpn_mul): Remove.
+	* tests/refmpn.c (refmpn_mul): New function, mainly from t-mul.c's
+	ref_mpn_mul.
+	(refmpn_mullo_n): Add a missing free.
+
+	* tune/speed.c (routine): Measure speed_mpn_{sb,dc}pi1_div_qr,
+	mpn_{sb,dc}pi1_divappr_q, mpn_{sb,dc}pi1_bdiv_qr, and
+	mpn_{sb,dc}pi1_bdiv_q.
+
+	* mpn/generic/invertappr.c: New file, meat from invert.c.
+	* mpn/generic/invert.c: Leave just mpn_invert.c.
+	* configure.in (gmp_mpn_functions): Add invertappr.
+	* tune/Makefile.am (TUNE_MPN_SRCS_BASIC): Add invertappr.c.
+	* gmp-impl.h (mpn_invert_itch, mpn_invertappr_itch): New macros.
+
+2009-12-15  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/gcdext_subdiv_step.c: Get an ASSERT right.
+
+2009-12-15  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/sbpi1_div_qr.c (mpn_sbpi1_div_qr): A very small step
+	towards nail support.
+
+2009-12-15  Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* gmp-impl.h (mpn_ni_invertappr): Added prototype and name-mangling.
+	* mpn/generic/mulmod_bnm1.c: Comment representation of class [0].
+
+2009-12-14  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/sbpi1_divappr_q.c (mpn_sbpi1_divappr_q): Use
+	udiv_qr_3by2.
+
+2009-12-14  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tune/tuneup.c (tune_binvert): Remove BINV_MULMOD_BNM1_THRESHOLD
+	tuning, it was always zero and caused BINV_NEWTON_THRESHOLD to be
+	wrong (as pointed out by Marco).
+	* (BINV_MULMOD_BNM1_THRESHOLD): Clean from other files too.
+
+2009-12-14  Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/invert.c: Improved comments.
+	(mpn_bc_invertappr): Conditionally re-enable mpn_dcpi1_divappr_q.
+
+2009-12-14  Niels Möller  <nisse@lysator.liu.se>
+
+	* gmp-impl.h (udiv_qr_3by2): Fix typo in argument list.
+
+2009-12-13  Niels Möller  <nisse@lysator.liu.se>
+
+	* gmp-impl.h (udiv_qr_3by2): New macro.
+	* mpn/generic/sbpi1_div_qr.c (mpn_sbpi1_div_qr): Use udiv_qr_3by2.
+
+2009-12-13  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/dcpi1_divappr_q.c (mpn_dcpi1_divappr_q): Avoid a buffer
+	overrun.
+
+	* mpn/generic/mul_fft.c (mpn_mul_fft_full): Handle carry-out from 2nd
+	mpn_mul_fft, add an ASSERT for the 1st mpn_mul_fft.  Replace some
+	comments on cc's range with ASSERTs.
+
+	* mpn/generic/gcdext.c (compute_v): Normalise tp[] after mpn_mul.
+
+	* mpz/powm.c: Rework buffer handling.
+
+2009-12-13  Niels Möller  <nisse@lysator.liu.se>
+
+	* tests/mpn/toom-shared.h (main): Use refmpn_mul_basecase to check
+	results (slow!). Iteration counts of all toom tests reduced
+	considerably.
+
+2009-12-13  Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/invert.c (mpn_invertapp): Split in _bc and _ni.
+	(mpn_bc_invertappr): New function, the basecase.
+	(mpn_ni_invertapp): New function, Newton iteration.
+	(mpn_invert): Use mpn_ni_invertapp.
+	* tune/tuneup.c (tune_invert): Min for INV_APPR_THRESHOLD.
+	(tune_invertappr): Min for INV_NEWTON_THRESHOLD.
+
+	* tune/speed.h (SPEED_ROUTINE_MPN_NI_INVERTAPPR): New macro.
+	(speed_mpn_ni_invertappr): Declare function.
+	* tune/common.c (speed_mpn_ni_invertappr): New function.
+	* tune/speed.c (routine): Add speed_mpn_ni_invertappr.
+
+	* tune/tuneup.c (tune_invertappr): Use speed_mpn_ni_invertappr to
+	tune INV_MULMOD_BNM1_THRESHOLD.
+
+2009-12-12  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/mu_bdiv_qr.c (mpn_mu_bdiv_qr_itch): Rewrite.
+
+2009-12-12  Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* tests/mpn/t-mulmod_bnm1.c (main): Disable B^n+1 stressing test
+	for odd sizes.
+
+	* mpn/generic/invert.c: Complete rewrite. Uses Newton iterations.
+	* gmp-impl.h (mpn_invertappr): Added prototype and name-mangling.
+	(mpn_invertappr_itch): Added prototype and name-mangling.
+	(INV_APPR_THRESHOLD): Support for a new tunable const.
+	* tune/speed.h (SPEED_ROUTINE_MPN_INVERTAPPR): New macro.
+	(speed_mpn_invertappr): Declare function.
+	* tune/common.c (speed_mpn_invertappr): New function.
+	* tune/speed.c (routine): Add speed_mpn_invertappr.
+	* tune/tuneup.c (tune_invertappr): New function: was tune_invert.
+	(tune_invert): Now tune only INV_APPR_THRESHOLD.
+	(all): Enable call to tune_invert and tune_invertappr.
+
+2009-12-11  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/binvert.c: Use mpn_mulmod_bnm1 instead of FFT wrapping.
+	Old, evidently broken wrapping code removed.
+	* tune/tuneup.c (tune_binvert): Tune BINV_MULMOD_BNM1_THRESHOLD.
+	* gmp-impl.h: Provide declarations for corresponding threshold var.
+
+	* tests/mpn/t-bdiv.c (COUNT): Decrease to keep run time reasonable.
+
+	* tune/tuneup.c (tune_invert): Tune INV_MULMOD_BNM1_THRESHOLD.
+	* gmp-impl.h: Provide declarations for corresponding threshold var.
+
+	* tests/mpn/t-mulmod_bnm1.c: Avoid a division by zero.
+
+	* configure.in: Set up different paths for different 64-bit sparc
+	processors.
+	* mpn/sparc64/ultrasparc34/gmp-mparam.h: New file.
+
+2009-12-10  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/*/gmp-mparam.h: Regenerate many of these files.
+
+2009-12-10  Niels Möller  <nisse@lysator.liu.se>
+
+	* gmp-impl.h (mpn_divexact): Removed scratch pointer from
+	prototype.
+	* mpn/generic/gcdext.c (divexact): Deleted, moved to...
+	* mpn/generic/divexact.c (mpn_divexact): New implementation (moved
+	from gcdext.c). The bidirectional divexact is kept but #if:ed out.
+	Interface change, since the new code doesn't take a scratch
+	argument.
+
+	* tests/mpn/t-mulmod_bnm1.c (main): Ensure that an >= bn. Lowered
+	MIN_N to 1. Various fixes to handle n == 1 properly.
+
+	* mpn/generic/mulmod_bnm1.c (mpn_mulmod_bnm1): Small interface
+	change, require an >= bn.
+
+	* mpn/generic/mulmod_bnm1.c (mpn_mulmod_bnm1): Fixed non-recursive
+	case to not write beyond end of result area.
+
+2009-12-09  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tune/speed.h (SPEED_ROUTINE_MPN_MULMOD_BNM1_CALL): New macro, made
+	from now deleted SPEED_ROUTINE_MPN_MULMOD_BNM1.
+	* tune/common.c (speed_mpn_bc_mulmod_bnm1): New function.
+	(speed_mpn_mulmod_bnm1): Use SPEED_ROUTINE_MPN_MULMOD_BNM1_CALL.
+	* tune/speed.c (routine): Add mpn_bc_mulmod_bnm1.
+
+	* mpn/generic/mulmod_bnm1.c (mpn_mulmod_bnm1_next_size): Rewrite.
+
+	* tune/tuneup.c (tune_mulmod_bnm1): Rewrite.
+
+2009-12-08  Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/mulmod_bnm1.c (mpn_bc_mulmod_bnm1,
+	mpn_bc_mulmod_bnp1): Added a parameter for scratch area, possibly
+	same as result area (as suggested by Niels Möller).
+	(mpn_mulmod_bnm1): Calls changed accordingly.
+
+2009-12-08  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/gcdext_1.c (mpn_gcdext_1) [GCDEXT_1_USE_BINARY]: Use
+	table lookup for count_trailing_zeros. Binary algorithm still
+	disabled by default.
+
+	* mpn/generic/gcdext.c (divexact): Local definition of divexact,
+	using mpn_bdiv_q.
+	(compute_v): Use it.
+
+	* tests/mpn/Makefile.am (check_PROGRAMS): Added t-bdiv.
+
+	* tests/mpn/t-bdiv.c: New file.
+
+	* mpn/generic/bdiv_q.c (mpn_bdiv_q): Fixed bad quotient length,
+	should have qn == nn.
+
+	* mpn/generic/bdiv_qr.c (mpn_bdiv_qr): Pass correct nn length to
+	the lower-level functions.
+
+2009-12-08  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tune/speed.h (SPEED_ROUTINE_MPN_MULMOD_BNM1_ROUNDED): New define.
+	* tune/common.c (speed_mpn_mulmod_bnm1_rounded): New function.
+	* tune/speed.c (routine): Add mpn_mulmod_bnm1_rounded for measuring
+	mpn_mulmod_bnm1 at recommended sizes.
+
+	* mpn/generic/mulmod_bnm1.c (mpn_mulmod_bnm1_next_size): Rewrite.
+	(mpn_bc_mulmod_bnm1): Use mpn_add_n instead of mpn_add.
+
+	* tune/speed.c (routine): Add mpn_invert.
+
+	* tune/tuneup.c (tune_invert): New function.
+	* tune/speed.h (SPEED_ROUTINE_MPN_INVERT): New macro.
+	* tune/common.c (speed_mpn_invert): New function.
+	* gmp-impl.h: Provide declarations for corresponding threshold var.
+	* tune/Makefile.am (TUNE_MPN_SRCS_BASIC): Add invert.c.
+
+2009-12-08  Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* tests/devel/try.c: Test mpn_addlsh2_n and mpn_{add,sub}lsh_n;
+	mpn_rsblsh_n now tests all shift values.
+	* tests/refmpn.c (refmpn_addlsh_n, refmpn_sublsh_n): New functions.
+	(refmpn_addlsh1_n): Use generic refmpn_addlsh_n.
+	(refmpn_sublsh1_n): Use generic refmpn_sublsh_n.
+	(refmpn_addlsh2_n): New function.
+	* tests/tests.h: Declare new functions.
+
+2009-12-06  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tune/tuneup.c (tune_mulmod_bnm1): Up min_size to 12.
+
+	* Globally: Rename *mullow* to *mullo*, *MULLOW* to *MULLO*.
+
+	* configure.in: Don't include ev5 directory for ev6* and ev7.  Misc
+	alpha path cleanups.
+	* mpn/alpha/add_n.asm: Replaced by mpn/alpha/ev5/add_n.asm.
+	* mpn/alpha/sub_n.asm: Replaced by mpn/alpha/ev5/sub_n.asm.
+	* mpn/alpha/lshift.asm: Replaced by mpn/alpha/ev5/lshift.asm.
+	* mpn/alpha/rshift.asm: Replaced by mpn/alpha/ev5/rshift.asm.
+	* mpn/alpha/com_n.asm: New, moved from mpn/alpha/ev5/rshift.asm.
+	* mpn/alpha/ev5/diveby3.asm: New, moved from mpn/alpha/diveby3.asm.
+
+	* mpn/powerpc64/mode64/diveby3.asm: Remove, it is slower than
+	mpn_bdiv_dbm1c on all hardware.
+
+	* mpn/generic/powm_sec.c: Rework logic for mpn_sqr_basecase size limit.
+
+	* gmp-impl.h (mpn_redc_1_sec): Declare.
+	* configure.in (gmp_mpn_functions): Add redc_1_sec.
+
+2009-12-06  Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* tests/devel/try.c (try_one): DATA_SRC0_HIGHBIT sets the high bit.
+
+2009-12-05  Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/toom_eval_dgr3_pm1.c: Change return value: 0 or ~0.
+	* mpn/generic/toom_eval_dgr3_pm2.c: Likewise.
+	* mpn/generic/toom_eval_pm1.c: Likewise.
+	* mpn/generic/toom_eval_pm2exp.c: Likewise.
+	* mpn/generic/toom_eval_pm2.c: Rewrite to use mpn_addlsh2_n.
+
+	* mpn/generic/toom_interpolate_5pts.c: Param sa is a flag, not a sign.
+
+	* mpn/generic/toom33_mul.c: Adapt to changes above.
+	* mpn/generic/toom3_sqr.c: Likewise.
+	* mpn/generic/toom42_mul.c: Likewise.
+	* mpn/generic/toom43_mul.c: Reduce branches.
+	* mpn/generic/toom44_mul.c: Likewise.
+	* mpn/generic/toom53_mul.c: Likewise.
+	* mpn/generic/toom62_mul.c: Likewise.
+
+	* mpn/generic/toom52_mul.c: Use toom_eval_ functions.
+
+	* mpn/generic/toom4_sqr.c: Avoid C99 construct.
+	* mpn/generic/toom_interpolate_7pts.c: Likewise.
+
+2009-12-05  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/redc_1_sec.c: New file.
+	* mpn/generic/powm_sec.c: Use redc_1_sec.  Use dummy full subtract
+	instead of mpn_cmp since the latter leaks to the side channel.
+	(mpn_local_sqr_n): New function, with associated macros.
+	(mpn_powm_sec): Use mpn_local_sqr_n.
+
+	* configure.in (HAVE_NATIVE): Add missing functions, then sort.
+
+2009-12-04  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tune/tuneup.c (tune_dc_div): Up min_size to 6.
+	(tune_mod_1): Set MOD_1_1_THRESHOLD min_size to 2.
+
+	* tune/speed.h: Negate "binvert"-type inverses, as required.
+
+	* mpn/generic/redc_1.c: Add ASSERTs.
+	* mpn/generic/redc_2.c: Likewise.
+
+	* mpn/generic/sbpi1_bdiv_q.c: Simplify loops, indexing.
+
+2009-12-03  Yann Droneaud  <yann@droneaud.fr>
+
+	* acinclude.m4 ([long long reliability test 1]): Add a "static" for C99
+	inline semantics compatibility.
+
+2009-12-03  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.in: Move intptr_t test into common AC_CHECK_TYPES.
+
+	* mpn/generic/gcdext.c: Add a TMP_FREE.
+
+2009-12-03  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/gcdext_1.c (mpn_gcdext_1) [GCDEXT_1_USE_BINARY]:
+	Added various masking tricks.
+
+	* mpn/generic/gcdext_1.c (mpn_gcdext_1) [GCDEXT_1_USE_BINARY]:
+	Reimplemented binary gcdext, with proper canonicalization.
+
+	* mpn/generic/gcdext_lehmer.c (mpn_gcdext_lehmer_n): Handle v == 0
+	from mpn_gcdext_1.
+	* mpn/generic/gcdext_1.c (mpn_gcdext_1): Allow inputs with a < b,
+	assertions fixed accordingly.
+
+2009-12-03  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tune/tuneup.c: Tune DC_DIVAPPR_Q_THRESHOLD.  Rewrite
+	DC_DIV_QR_THRESHOLD tuning code.
+	(tune_dc_div): Rewrite.
+	* tune/speed.h (SPEED_ROUTINE_MPN_PI1_DIV): New macro.
+	* tune/common.c (speed_mpn_sbpi1_div_qr, speed_mpn_dcpi1_div_qr,
+	speed_mpn_sbpi1_divappr_q, speed_mpn_sbpi1_bdiv_qr): New functions.
+	* gmp-impl.h: Provide declarations for corresponding threshold vars.
+	* tune/Makefile.am (TUNE_MPN_SRCS_BASIC): Add dcpi1_divappr_q.c.
+
+	* tune/tuneup.c (tune_binvert): Up max_size.
+
+2009-12-02  Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* tests/devel/try.c: Test mpn_rsblsh2_n and mpn_rsblsh_n.
+	* tests/refmpn.c (refmpn_rsblsh_n, refmpn_rsblsh2_n): New functions.
+	(refmpn_rsblsh1_n): Use generic refmpn_rsblsh_n.
+	* tests/tests.h: Declare new functions.
+
+2009-12-03  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/gcdext_subdiv_step.c (mpn_gcdext_subdiv_step):
+	Select the right cofactor in the cases A == B or A == 2B.
+
+	* mpn/generic/gcdext_lehmer.c (mpn_gcdext_lehmer_n): Deleted
+	handling of ap[0] == 0 and bp[0] == 0; these cases don't happen.
+	Select the right cofactor in the case ap[0] == bp[0].
+	* mpn/generic/gcdext.c (mpn_gcdext): Analogous changes.
+
+2009-12-02  Niels Möller  <nisse@lysator.liu.se>
+
+	* gmp-h.in (mpn_gcdext_1): Updated prototype.
+	* mpn/generic/gcdext_lehmer.c (mpn_gcdext_lehmer_n): Updated for
+	signed cofactors from gcdext_1.
+	* mpn/generic/gcdext_1.c (mpn_gcdext_1): Use Euclid's algorithm,
+	and return signed cofactors.
+
+2009-12-02  Torbjorn Granlund  <tege@gmplib.org>
+
+	* doc/gmp.texi (Low-level Functions): Document mpn_sqr_n.
+
+	* tune/speed.c (routine): Add mpn_binvert.
+
+	* tune/tuneup.c: Tune BINV_NEWTON_THRESHOLD.
+	(tune_binvert): New function.
+	* tune/speed.h (SPEED_ROUTINE_MPN_BINVERT): New macro.
+	* tune/common.c (speed_mpn_binvert): New function.
+	* gmp-impl.h: Provide declarations for corresponding threshold var.
+	* tune/Makefile.am (TUNE_MPN_SRCS_BASIC): Add binvert.c.
+
+	* tune/tuneup.c: Tune DC_BDIV_QR_THRESHOLD and DC_BDIV_Q_THRESHOLD.
+	(tune_dc_bdiv): New function.
+	(tune_dc_div): New name for tune_dc.
+	* tune/speed.h (SPEED_ROUTINE_MPN_PI1_BDIV_QR,
+	SPEED_ROUTINE_MPN_PI1_BDIV_Q): New macros.
+	* tune/common.c (speed_mpn_sbpi1_bdiv_qr, speed_mpn_dcpi1_bdiv_qr,
+	speed_mpn_sbpi1_bdiv_q, speed_mpn_dcpi1_bdiv_q): New functions.
+	* gmp-impl.h: Provide declarations for corresponding threshold vars.
+	* tune/Makefile.am (TUNE_MPN_SRCS_BASIC): Add dcpi1_bdiv_qr.c and
+	dcpi1_bdiv_q.c.
+
+2009-12-01  Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/toom53_mul.c: Removed double computation of vinf.
+
+	* mpn/x86_64/aorrlsh_n.asm: Correct return value for rsblsh_n.
+	* mpn/asm-defs.m4 (define_mpn): Add rsblsh_n.
+	* gmp-impl.h (mpn_rsblsh_n): Added prototype and name-mangling.
+
+	* mpn/generic/fib2_ui.c: Reduce the amount of temporary storage.
+	Use mpn_rsblsh_n.
+
+2009-12-01  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/redc_n.c: Rework temp allocation.
+
+	* mpn/generic/dcpi1_bdiv_qr.c (mpn_dcpi1_bdiv_qr_n_itch): Add pi1 also
+	to this function.
+
+	* mpn/generic/dcpi1_bdiv_q.c: Get the mpn_sbpi1_bdiv_q call right.
+	Misc cleanups.
+
+	* tune/speed.c (routine): Fix typo in last change.
+	Add mpn_redc_2.
+
+	* tune/speed.h (SPEED_ROUTINE_REDC_N): Set min size properly.
+
+2009-12-01  Niels Möller  <nisse@lysator.liu.se>
+
+	* tune/speed.c (routine): Added mpn_toom42_mul and mpn_redc_n.
+	* tune/speed.h (SPEED_ROUTINE_MPN_TOOM42_MUL): New macro.
+	(speed_mpn_toom42_mul): Declare function.
+	* tune/common.c (speed_mpn_toom42_mul): New function.
+	* gmp-impl.h (MPN_TOOM42_MUL_MINSIZE): New constant.
+
+2009-11-30  Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/fib2_ui.c: Use mpn_rsblsh2_n.
+
+2009-11-29  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/pentium4/gmp-mparam.h
+	(HAVE_NATIVE_mpn_addlsh1_n, HAVE_NATIVE_mpn_sublsh1_n): Don't undef.
+
+	* Makefile.am (EXTRA_DIST): Remove macos.
+
+2009-11-28  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tune/tuneup.c (tune_redc): Set min_size to 16 for redc_n tuning.
+
+	* mpn/x86_64/sqr_basecase.asm (SQR_TOOM2_THRESHOLD_MAX): Avoid quoting
+	to allow configure.in parse it more easily.  Trim from 120 to 80.
+
+2009-11-28  Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/mulmod_bnm1.c: Basecases made simpler, this also corrects
+	a bug affecting previous version.
+
+2009-11-28  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.in: Handle atom also in 32-bit mode.
+	* mpn/x86/atom/gmp-mparam.h: New file.
+
+	* gmp-impl.h (MULMOD_BNM1_THRESHOLD): Default.
+
+	* mpn/generic/redc_n.c: Use mpn_mulmod_bnm1 instead of mpn_mul_n.
+
+	* Use TMP_ALLOC_LIMBS consistently.
+	* Finish renaming BITS_PER_MP_LIMB to GMP_LIMB_BITS.
+
+	* macos: Remove entire directory.
+
+2009-11-27  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/corei/gmp-mparam.h: New file.
+	* mpn/x86_64/core2/gmp-mparam.h: Now for just core2.
+	* mpn/powerpc64/mode64/p3/gmp-mparam.h: New file.
+	* mpn/powerpc64/mode64/p4/gmp-mparam.h: New file.
+	* mpn/powerpc64/mode64/p5/gmp-mparam.h: New file.
+
+	* config.guess: Return "corei" for core i7 and core i5.
+	* config.sub: Recognise "corei".
+	* acinclude.m4 (X86_64_PATTERN): Add corei.
+	* configure.in (powerpc): Set up more CPU-specific paths.
+	(x86): Handle corei.
+
+	* mpz/powm.c: Allow input operand overlap also when exponent = 1.
+	Misc cleanups.
+
+2009-11-26  Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* tests/mpn/t-mulmod_bnm1.c: New test file.
+	* tests/mpn/Makefile.am (check_PROGRAMS): Add t-mulmod_bnm1.
+
+	* mpn/generic/mullow_n.c: Comments on Mulders' trick implementation.
+
+2009-11-26  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/powm.c: Make comments reflect current code state.
+
+	* tests/devel/try.c: Make mpn_mullow_n testing actually work.
+
+2009-11-25  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpz/powm.c: Clean up unused defs.
+
+2009-11-24  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tune/tuneup.c (tune_redc): Rewrite.
+	* mpn/generic/powm.c: Use REDC_1_TO_REDC_2_THRESHOLD,
+	REDC_1_TO_REDC_N_THRESHOLD, and REDC_2_TO_REDC_N_THRESHOLD.
+	Get rid of previous REDC params, including LOCAL_REDC_N_THRESHOLD.
+	(WANT_REDC_2): Define.
+	* gmp-impl.h: Corresponding changes.
+
+2009-11-23  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/powm.c: Fix typo.
+	Define LOCAL_REDC_N_THRESHOLD, use in REDC_2_THRESHOLD...
+	REDC_N_THRESHOLD chain.
+
+2009-11-22  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tune/tuneup.c (tune_mullow): Set min_size to 1.
+
+	* mpn/generic/powm_sec.c: Use just mpn_mul_basecase and
+	mpn_sqr_basecase for multiplication and squaring.
+
+	* tune/tuneup.c: Tune REDC_2_THRESHOLD and REDC_N_THRESHOLD.
+	(tune_redc): New function.
+	(tune_powm): Remove function.
+	* tune/speed.h (SPEED_ROUTINE_REDC_2, SPEED_ROUTINE_REDC_N): New.
+	* tune/common.c (speed_mpn_redc_2, speed_mpn_redc_n): New.
+
+	* mpz/powm.c: Complete rewrite.  Use mpn_powm and mpn_powlo.
+	* mpn/generic/powm.c: Rewrite.
+	* mpn/generic/redc_n.c: New file.
+	* configure.in (gmp_mpn_functions): Add redc_n.
+	* gmp-impl.h (REDC_2_THRESHOLD, REDC_N_THRESHOLD): Default, and define
+	for tuneup.
+
+2009-11-21  Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/mullow_n.c: Disable Mulders' trick for small operands,
+	use fft for bigger ones.
+	* tests/mpn/t-mullo.c: New test file.
+
+2009-11-22  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tune/tuneup.c (tune_mullow): Rewrite.
+
+2009-11-21  Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* gmp-impl.h: Removed unused macros (CACHED_ABOVE_THRESHOLD and
+	CACHED_BELOW_THRESHOLD).
+
+	* mpn/generic/mullow_n.c: Use Mulders' trick.
+	* tune/tuneup.c (tune_mullow): MULLOW_MUL_N_THRESHOLD range of
+	search depends on FFT tuning;
+	(all): Anticipate tune_fft_{mul,sqr}.
+
+	* tune/speed.c (routine): Add entry related to mpn_mulmod_bnm1.
+
+2009-11-19  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/toom_eval_dgr3_pm2.c (mpn_toom_eval_dgr3_pm2)
+	[HAVE_NATIVE_mpn_add_n_sub_n]: Fixed typo in mpn_add_n_sub_n call
+	(spotted by Marco Bodrato).
+	* mpn/generic/toom_eval_pm2.c (mpn_toom_eval_pm2): Likewise.
+	* mpn/generic/toom_eval_pm2exp.c (mpn_toom_eval_pm2exp): Likewise.
+
+	* mpn/generic/toom_eval_pm2.c (mpn_toom_eval_pm2) [HAVE_NATIVE_mpn_addlsh_n]:
+	Fixed missing declaration.
+
+	* mpn/asm-defs.m4 (define_mpn): Add addlsh_n.
+	* gmp-impl.h (mpn_addlsh_n): Added prototype and name-mangling.
+
+2009-11-19  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/toom_eval_pm2.c (mpn_toom_eval_pm2): New file.
+	* mpn/generic/toom53_mul.c (mpn_toom53_mul): Use mpn_toom_eval_pm2.
+	* mpn/generic/toom62_mul.c (mpn_toom62_mul): Likewise.
+	* configure.in (gmp_mpn_functions): Added toom_eval_dgr3_pm2.
+
+2009-11-18  Torbjorn Granlund  <tege@gmplib.org>
+
+	* gmp-impl.h (mpn_and_n, etc): Adapt to now-public logic functions.
+
+	* config.guess: Recognise VIA nano.
+	* config.sub: Likewise.
+	* configure.in: Generalise x86_64 support; recognise VIA nano.
+
+2009-11-16  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tune/speed.c (routine): Add measurement of mpn_addlsh2_n,
+	mpn_sublsh2_n, mpn_rsblsh2_n.
+	* tune/common.c: Add speed routines for lsh2 functions.
+
+	* mpn/generic/divis.c: Use MU_BDIV_QR_THRESHOLD.
+
+	* configure.in (gmp_mpn_functions_optional): Add *lsh_n functions.
+
+	* mpn/generic/toom_eval_pm2exp.c: Make HAVE_NATIVE_mpn_addlsh_n code
+	work.
+
+	* mpn/x86_64/aorrlsh2_n.asm: Optimise inner loop.
+
+	* configure.in (gmp_mpn_functions_optional): Remove copyi,copyd, they
+	are now in gmp_mpn_functions.  Analogously move logical functions.
+
+2009-11-16  Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/toom53_mul.c: Use addlsh2 for evaluation (and fix typo).
+	* mpn/generic/toom_eval_dgr3_pm2.c: Likewise (affects toom44 and 43).
+
+	* mpn/asm-defs.m4: Fix comments for op_lsh2 new functions.
+	* gmp-impl.h: Likewise.
+	* tests/mpz/t-fac_ui.c: Fix a comment.
+
+2009-11-15  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/aorrlsh2_n.asm: New file.
+	* configure.in: Add support for addlsh2_n, sublsh2_n, and rsblsh2_n,
+	including mulfuncs.
+	* gmp-impl.h (mpn_addlsh2_n, mpn_sublsh2_n, mpn_rsblsh2_n): Declare.
+	* mpn/asm-defs.m4: Likewise.
+
+	* mpn/generic/copyi.c: New file.
+	* mpn/generic/copyd.c: Likewise.
+	* mpn/generic/zero.c: Likewise.
+	* gmp-h.in: Declare new functions.
+	* configure.in (gmp_mpn_functions): Add new functions.
+
+2009-11-15  Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/mulmod_bnm1.c (mpn_mulmod_bnm1_next_size): fix typo
+
+	* mpn/generic/toom33_mul.c: Use rsblsh1 for evaluation.
+	* mpn/generic/toom3_sqr.c: Likewise.
+
+2009-11-14  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/toom52_mul.c: Use mpn_addlsh1_n.
+
+	* mpn/generic/toom52_mul.c: Toggle the right flag bit in an
+	HAVE_NATIVE_mpn_add_n_sub_n arm.
+
+	* tests/mpz/t-remove.c: New file.
+
+	* mpn/generic/remove.c: Major overhaul.  Add parameter 'cap'.
+
+	* mpn/generic/binvert.c: Fix typo in last change.
+
+	* mpn/generic/bdiv_qr.c: Make it actually work.  Also use passed-in
+	scratch space.
+
+	* mpn/generic/mu_bdiv_qr.c: Reset FFT parameters for each call.
+
+2009-11-12  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86/k7/gcd_1.asm (MASK): Compute from MAXSHIFT.
+
+2009-11-11  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/binvert.c: Simplify, fix comments.
+
+	* tests/devel/try.c: Test mpn_invert and mpn_binvert.
+
+	* tests/refmpn.c (refmpn_invert, refmpn_binvert): New functions.
+	* tests/tests.h: Declare new functions.
+
+2009-11-10  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.in: Supply compiler options for atom in 32-bit mode.
+
+	* acinclude.m4 (X86_64_PATTERN): New.
+	* configure.in: Setup and use X86_64_PATTERN.
+
+	* mpn/x86_64/fat/fat.c: New file.
+	* mpn/x86_64/fat/fat_entry.asm: New file.
+	* mpn/x86_64/fat: Copy C placeholder files from mpn/x86/fat.
+	* mpn/x86_64/x86_64-defs.m4 (CPUVEC_FUNCS_LIST): New, copied from
+	mpn/x86/x86-defs.m4.
+	* configure.in: Move down x86 fat setup code until after ABI has been
+	determined; generalise to handle x86_64.
+
+2009-11-09  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86/fat/mod_1.c: New file.
+
+	* acinclude.m4 (GMP_C_FOR_BUILD_ANSI): Avoid poor quoting.
+
+2009-11-08  Torbjorn Granlund  <tege@gmplib.org>
+
+	* gmp-impl.h (MPN_LOGOPS_N_INLINE): Rewrite, update interface.  Callers
+	updated.
+	* mpn/generic/logops_n.c: New file.
+	* doc/gmp.texi (Low-level Functions): Document logical mpn functions.
+
+2009-11-07  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tune/speed.h (SPEED_ROUTINE_MPN_MULMOD_BNM1): Adapt to new
+	mpn_mulmod_bnm1 interface.
+
+2009-11-07  Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/mulmod_bnm1.c: New interface, with size
+	specified for all operands in mpn_mulmod_bnm1.
+	* gmp-impl.h: Changed mpn_mulmod_bnm1 prototype.
+
+2009-11-05  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86/k7/gcd_1.asm: Actually use div-reduced value.
+	Mnemonic cleanup.
+
+	* mpn/x86_64/gcd_1.asm: New file.
+
+2009-11-03  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tune/Makefile.am (TUNE_MPN_SRCS_BASIC): Add sqr_n.c.
+
+2009-11-03  Marco Bodrato <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/toom_interpolate_6pts.c: removed an addmul_1 and cleanup.
+
+2009-11-02  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.in (gmp_mpn_functions): Remove obsolete functions
+	dc_divrem_n and sb_divrem_mn.
+	* gmp-impl.h: Misc cleanup.
+	(mpn_sb_divrem_mn, mpn_dc_divrem_n): Remove.
+	(DIV_DC_THRESHOLD): Remove.
+	* mpn/generic/dc_divrem_n.c: Remove.
+	* mpn/generic/sb_divrem_mn.c: Remove.
+	* mpn/generic/tdiv_qr.c: Use DC_DIV_QR_THRESHOLD, not DIV_DC_THRESHOLD.
+
+	* tests/devel/try.c: Replace mpn_sb_divrem_mn by mpn_sbpi1_div_qr.
+	* tests/refmpn.c (refmpn_sb_div_qr): New name for refmpn_sb_divrem_mn.
+
+	* tune/Makefile.am (libspeed_la_SOURCES): Remove sb_div.c and sb_inv.c.
+	(TUNE_MPN_SRCS_BASIC): Remove sb_divrem_mn.c.
+	* tune/common.c (speed_mpn_dcpi1_div_qr_n): New function.
+	Remove mpn_sb_divrem_mn related functions.
+	* tune/speed.c (routine): Remove entries related to mpn_dc_divrem and
+	mpn_sb_divrem.
+	(routine): New entry for mpn_dc_div_qr_n.
+	* tune/speed.h (SPEED_ROUTINE_MPN_DC_DIVREM_CALL): Compute inverse
+	needed by pi1 calls.
+	(SPEED_ROUTINE_MPN_SB_DIVREM_M3): Remove.
+	* tune/tuneup.c (tune_sb_preinv): Remove.
+	(tune_dc): Update to measure DC_DIV_QR_THRESHOLD.
+
+	* mpn/generic/sb_divappr_q.c: Remove.
+
+2009-11-01  Torbjorn Granlund  <tege@gmplib.org>
+
+	* gmp-impl.h: Misc minor cleanups.
+
+2009-10-31  Torbjorn Granlund  <tege@gmplib.org>
+
+	* gmp-impl.h (toom itch functions): Simplify, make some into macros.
+	(MPN_KARA_MUL_N_TSIZE, MPN_KARA_SQR_N_TSIZE): Remove.
+	* mpn/generic/mul_n.c (mpn_toom3_mul_n, mpn_toom3_sqr_n): Remove.
+	* mpn/generic/mul_n.c (mpn_sqr_n): Move from here...
+	* mpn/generic/sqr_n.c: ...to this new file.
+	* configure.in (gmp_mpn_functions): Add sqr_n.
+
+	* Globally change
+	  MUL_TOOM3_THRESHOLD => MUL_TOOM33_THRESHOLD,
+	  MUL_KARATSUBA_THRESHOLD => MUL_TOOM22_THRESHOLD,
+	  SQR_KARATSUBA_THRESHOLD => SQR_TOOM2_THRESHOLD,
+	and associated names analogously.
+
+2009-10-31  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/toom_interpolate_7pts.c: Changed evaluation points,
+	replacing -1/2 by -2.
+	* mpn/generic/toom44_mul.c: Updated to use new evaluation points,
+	and use mpn_toom_eval_dgr3_pm2.
+	* mpn/generic/toom4_sqr.c (mpn_toom4_sqr): Likewise.
+	* mpn/generic/toom53_mul.c (mpn_toom53_mul): Updated to use new
+	evaluation points, and use mpn_toom_eval_pm1 and
+	mpn_toom_eval_pm2exp.
+	* mpn/generic/toom62_mul.c (mpn_toom62_mul): Likewise.
+
+	* mpn/generic/toom_eval_pm2exp.c: New file.
+	* mpn/generic/toom_eval_pm1.c: New file.
+
+	* mpn/generic/toom43_mul.c (mpn_toom43_mul): Use
+	mpn_toom_eval_dgr3_pm2.
+
+2009-10-30  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tune/Makefile.am (TUNE_MPN_SRCS_BASIC): Add toom2* and toom3* files.
+
+2009-10-30  Niels Möller  <nisse@lysator.liu.se>
+
+	* configure.in (gmp_mpn_functions): Added toom_eval_dgr3_pm2.
+	* gmp-impl.h: Added prototype for mpn_toom_eval_dgr3_pm2.
+	* mpn/generic/toom_eval_dgr3_pm2.c: New file.
+
+2009-10-29  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/toom43_mul.c (mpn_toom43_mul): Use
+	mpn_toom_eval_dgr3_pm1.
+	* mpn/generic/toom42_mul.c (mpn_toom42_mul): Likewise.
+
+2009-10-29  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/mulmod_bnm1.c: Replace some add_1 by INCR.
+
+	* gmp-impl.h (mpn_mulmod_bnm1_itch): New macro.
+
+	* mpn/generic/mulmod_bnm1.c (mpn_mulmod_bnm1): Call mpn_mul_fft.
+	(mpn_mulmod_bnm1_next_size): Adopt to SS FFT.
+
+	* mpn/generic/mul_fft.c (mpn_mul_fft): Make it return high limb.
+	(mpn_mul_fft_internal): Likewise.
+
+	* mpn/generic/mulmod_bnm1.c: New file, by Niels Möller.
+	* configure.in (gmp_mpn_functions): Add mulmod_bnm1.
+	* gmp-impl.h: Add related declarations.
+	* tune/tuneup.c: Tune MULMOD_BNM1_THRESHOLD.
+	* tune/speed.h (SPEED_ROUTINE_MPN_MULMOD_BNM1): New macro.
+	* tune/common.c (speed_mpn_mulmod_bnm1): New function.
+	* Makefile.am (TUNE_MPN_SRCS_BASIC): Add mulmod_bnm1.c.
+
+	* gmp-impl.h (mpn_kara_mul_n, mpn_kara_sqr_n): Remove declarations.
+	* tune/common.c: Remove/rename kara functions.
+	* tune/speed.h: Likewise.
+
+	* tests/devel/try.c: Clean up usage of %p printf arguments.
+
+	* gmp-impl.h: Update MUL/SQR MINSIZE macros to reflect new function
+	names and limitations
+	* tune/tuneup.c: Use updated macro names.
+	* tune/speed.h: Likewise.
+	* tests/devel/try.c: Test new mul/sqr functions, remove old tests.
+
+2009-10-29  Niels Möller  <nisse@lysator.liu.se>
+
+	* tune/speed.c: Added support for mpn_toom4_sqr.
+
+	* tune/speed.h (SPEED_ROUTINE_MPN_TOOM4_SQR): New macro.
+	(SPEED_ROUTINE_MPN_KARA_MUL_N): Deleted.
+	(SPEED_ROUTINE_MPN_TOOM3_MUL_N): Deleted.
+	(SPEED_ROUTINE_MPN_TOOM2_SQR): Use mpn_toom2_sqr_itch.
+
+	* gmp-impl.h (mpn_toom3_mul_n, mpn_toom3_sqr_n): Remove
+	declarations.
+	(mpn_toom2_sqr_itch): Add margin for recursive calls.
+
+2009-10-28  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/mul_n.c (mpn_kara_mul_n): Deleted old Karatsuba
+	implementation.
+	(mpn_kara_sqr_n): Likewise deleted.
+
+	* mpn/generic/mul_n.c (mpn_sqr_n): Use mpn_toom2_sqr and
+	mpn_toom3_sqr, not the old implementations.
+
+	* gmp-impl.h (MPN_TOOM3_MUL_N_TSIZE): Deleted, replaced by
+	mpn_toom33_mul_itch.
+	(MPN_TOOM3_SQR_N_TSIZE): Deleted, replaced by
+	mpn_toom3_sqr_itch.
+	(mpn_toom33_mul_itch): Needs more scratch.
+	(mpn_toom3_sqr_itch): Likewise.
+	* tune/speed.h (SPEED_ROUTINE_MPN_TOOM3_MUL_N): Use
+	mpn_toom33_mul_itch.
+	(SPEED_ROUTINE_MPN_TOOM3_SQR_N): Use mpn_toom3_sqr_itch.
+	* mpn/generic/mul_n.c (mpn_mul_n): Use mpn_toom33_mul_itch.
+	(mpn_sqr_n): Use mpn_toom3_sqr_itch.
+
+	* mpn/generic/toom33_mul.c (mpn_toom33_mul): Avoid TMP_ALLOC. Needs
+	some more supplied scratch instead.
+	* mpn/generic/toom3_sqr.c (mpn_toom3_sqr): Likewise.
+
+2009-10-26  Torbjorn Granlund  <tege@gmplib.org>
+
+	* gmp-impl.h (invert_pi1): Streamline, as suggested by Niels.
+
+2009-10-24  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/bdiv_q.c: Update to call new functions.
+	* mpn/generic/bdiv_qr.c: Likewise.
+	* mpn/generic/binvert.c: Likewise.
+	* mpn/generic/divexact.c: Likewise.
+	* mpn/generic/divis.c: Likewise.
+	* mpn/generic/perfpow.c: Likewise.
+	* mpn/generic/tdiv_qr.c: Likewise.
+	* mpn/generic/dcpi1_bdiv_q.c: New file.
+	* mpn/generic/dcpi1_bdiv_qr.c: New file.
+	* mpn/generic/dcpi1_div_q.c: New file.
+	* mpn/generic/dcpi1_div_qr.c: New file.
+	* mpn/generic/dcpi1_divappr_q.c: New file.
+	* mpn/generic/sbpi1_bdiv_q.c: New file.
+	* mpn/generic/sbpi1_bdiv_qr.c: New file.
+	* mpn/generic/sbpi1_div_q.c: New file.
+	* mpn/generic/sbpi1_div_qr.c: New file.
+	* mpn/generic/sbpi1_divappr_q.c: New file.
+	* mpn/generic/dc_bdiv_q.c: Removed.
+	* mpn/generic/dc_bdiv_qr.c: Removed.
+	* mpn/generic/dc_div_q.c: Removed.
+	* mpn/generic/dc_div_qr.c: Removed.
+	* mpn/generic/dc_divappr_q.c: Removed.
+	* mpn/generic/sb_bdiv_q.c: Removed.
+	* mpn/generic/sb_bdiv_qr.c: Removed.
+	* mpn/generic/sb_div_q.c: Removed.
+	* mpn/generic/sb_div_qr.c: Removed.
+
+	* configure.in (gmp_mpn_functions): Add new division functions, remove
+	obsolete division functions.
+
+	* gmp-impl.h: Add declarations of new division functions, remove
+	corresponding obsolete declarations.
+	(gmp_pi1_t, gmp_pi2_t): New types.
+	(invert_pi1): New macro for computing 2/1 and 3/2 inverses.
+
+2009-10-23  Niels Möller  <nisse@lysator.liu.se>
+
+	* gmp-impl.h (mpn_toom62_mul_itch): New function.
+
+	* tests/mpn/t-toom53.c: New test program.
+	* tests/mpn/t-toom62.c: New test program.
+
+2009-10-23  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/get_d.c: Fix code handling denorms for 64-bit machines.
+	* tests/mpf/t-get_d.c (test_denorms): New function.
+
+2009-10-23  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/toom52_mul.c (mpn_toom52_mul): Use supplied scratch
+	space, not TMP_ALLOC. Interface change, now requires input sizes
+	such that s + t >= 5.
+
+	* gmp-impl.h (mpn_toom52_mul_itch): New function.
+
+	* tests/mpn/t-toom52.c: New test program.
+
+2009-10-22  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/sqr_basecase.asm: Tune for speed and a 7% size decrease.
+
+2009-10-22  Niels Möller  <nisse@lysator.liu.se>
+
+	* tests/mpn/t-toom44.c: New test program.
+	* tests/mpn/t-toom33.c: New test program.
+
+	* tests/mpn/toom-shared.h (main): Reorganized input generation.
+	Users are now supposed to define macros MAX_AN, MIN_BN and MAX_BN.
+	Updated existing toom test programs.
+
+2009-10-22  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/devel/try.c: Fix typos in last change.
+
+2009-10-21  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/asm-defs.m4 (define_mpn): Add mullow_basecase.
+
+	* tests/devel/try.c: Test mpn_mullow_n.
+
+	* tests/refmpn.c (refmpn_mullow_n): New function.
+	* tests/tests.h: Declare it.
+
+2009-10-21  Niels Möller  <nisse@lysator.liu.se>
+
+	* tests/mpn/toom-shared.h (main): Check for writes outside of the
+	product or scratch area.
+
+	* gmp-impl.h (mpn_toom43_mul_itch): New function.
+
+	* mpn/generic/toom43_mul.c (mpn_toom43_mul): Use supplied scratch
+	space, not TMP_ALLOC. Interface change, now requires input sizes
+	such that s + t >= 5.
+
+2009-10-20  Niels Möller  <nisse@lysator.liu.se>
+
+	* tests/mpn/toom-shared.h (MIN_BLOCK): New constant, which can be
+	overridden by users. Needed by t-toom42 and t-toom43.
+
+	* tests/mpn/Makefile.am (check_PROGRAMS): Added t-toom32,
+	t-toom42 and t-toom43.
+	* tests/mpn/t-toom43.c: New test program.
+	* tests/mpn/t-toom42.c: New test program.
+	* tests/mpn/t-toom32.c: New test program.
+
+	* tests/mpn/Makefile.am (check_PROGRAMS): Added t-toom22.
+	* tests/mpn/t-toom22.c: New test file.
+	* tests/mpn/toom-shared.h: New file. Test framework for Toom
+	functions.
+
+2009-10-14  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/hgcd.c (mpn_hgcd_itch): Thanks to the new
+	mpn_matrix22_mul_strassen, the scratch need is reduced by 16%.
+
+2009-10-14  Marco Bodrato  <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/matrix22_mul.c (mpn_matrix22_mul_strassen): New
+	Strassen-like algorithm, to reduce the amount of temporary
+	storage.
+	(mpn_matrix22_mul_itch): Updated to reflect the reduced storage
+	need.
+
+2009-10-03  Torbjorn Granlund  <tege@gmplib.org>
+
+	* Rename mpn_addsub_n to mpn_add_n_sub_n.
+
+2009-10-01  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/tdiv_qr.c: Call mpn_divrem_1 and mpn_dc_div_qr instead of
+	old functions.
+
+	* mpn/generic/mul_n.c: Call toom22 and toom33 instead of old functions.
+
+	* mpn/generic/toom42_mul.c (TOOM42_MUL_N_REC): Renamed from
+	TOOM22_MUL_N_REC.  Unconditionally call the generic mpn_mul_n.
+	* mpn/generic/toom32_mul.c: Analogous changes.
+
+2009-09-28  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/x86_64/invert_limb.asm: Rewrite. Exploit cancellation in the
+	Newton iteration.
+
+2009-09-27  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/x86/invert_limb.asm: Reduce register usage. Eliminated $1
+	arguments to add, sub and shift.
+
+2009-09-25  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/x86/invert_limb.asm: New file.
+
+2009-09-24  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/toom33_mul.c: Use new toom functions for all recursive
+	products.
+	* mpn/generic/toom3_sqr.c: Likewise.
+	* mpn/generic/toom44_mul.c: Likewise.
+	* mpn/generic/toom4_sqr.c: Likewise.
+
+	* mpn/generic/add_n.c: Relax operand overlap ASSERTs.
+	* mpn/generic/sub_n.c: Likewise.
+
+2009-09-15  Torbjorn Granlund  <tege@gmplib.org>
+
+	Suggested by Uwe Mueller:
+	* printf/doprnt.c: Use "%ld" for exponent printing.
+	* printf/doprntf.c (__gmp_doprnt_mpf): Make expval "long".
+
+2009-09-14  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.in: Handle mingw64.
+	* gmp-impl.h (gmp_intptr_t): Declare.
+	* tests/amd64check.c (calling_conventions_values): Use CNST_LIMB.
+	* tests/memory.c: Use gmp_intptr_t; print pointers using C90 "%p".
+	* tests/misc.c: Use gmp_intptr_t.
+	* tests/mpq/t-get_str.c: Print pointers using C90 "%p".
+
+2009-08-12  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/mod_1_1.c (mpn_mod_1_1p_cps): Remove silly ASSERT code.
+
+	* mpn/asm-defs.m4 (define_mpn): Remove mod_1s_1p, add mod_1_1p.
+
+	* mpn/arm/invert_limb.asm: Complete rewrite.
+
+	* longlong.h: Document LONGLONG_STANDALONE and NO_ASM.
+
+2009-08-05  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/mpz/dive_ui.c (check_random): Avoid zero divisors.
+
+2009-07-31  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/mod_1_1.c: Tweak to handle any modulus (possibility
+	pointed out by Per Austrin).
+	(mpn_mod_1_1p): Renamed from mpn_mod_1s_1p.
+	(mpn_mod_1_1p_cps): Renamed from mpn_mod_1s_1p_cps.
+	*mpn/generic/mod_1.c (mpn_mod_1): Reorganise to call mpn_mod_1_1p for
+	any modulus.
+
+2009-07-28  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.in: Pass arch for x86 also in 64-bit mode.
+
+2009-07-26  Torbjorn Granlund  <tege@swox.com>
+
+	* config.guess (_cpuid): Recognise more Intel "Core" processors.
+
+2009-07-13  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpf/eq.c: Rewrite.
+
+	* tests/mpf/t-eq.c: New test.
+
+2009-07-06  Torbjorn Granlund  <tege@gmplib.org>
+
+	* gmp-impl.h (__mp_bases): Remove this alias.
+
+	* mpf/get_str.c: Use less overflow prone expression for computing limb
+	allocation.
+	* mpz/inp_str.c: Likewise.
+	* mpf/set_str.c: Likewise.
+	* mpz/set_str.c: Likewise.
+
+2009-07-03  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/gcd_1.c (mpn_gcd_1): Use masking tricks to reduce
+	the number of branches in the loop.
+
+2009-06-28  Torbjorn Granlund  <tege@gmplib.org>
+
+	* demos/factorize.c (factor_using_pollard_rho): Rewrite.
+
+	* mpz/clears.c: New file.
+	* mpq/clears.c: New file.
+	* mpf/clears.c: New file.
+	* gmp-h.in (mpz_clears, mpq_clears, mpf_clears): Declare.
+	* mpz/Makefile.am: Add clears.c.
+	* mpq/Makefile.am: Add clears.c.
+	* mpf/Makefile.am: Add clears.c.
+	* Makefile.am: Add these also to respective OBJECTS variables.
+	* doc/gmp.texi: Document inits function and clears functions.
+
+2009-06-20  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mp-h.in (mp_bitcnt_t): Declare here too.
+
+2009-06-19  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpq/inits.c: New file.
+	* mpf/inits.c: New file.
+	* gmp-h.in (mpz_inits, mpq_inits, mpf_inits): Declare .
+
+	* mpn/generic/remove.c: New file.
+	* configure.in (gmp_mpn_functions): Add remove.
+	* gmp-impl.h (mpn_remove): Declare.
+
+	* gmp-h.in (mp_bitcnt_t): New basic type.
+	* mpn/generic/perfpow.c (mp_bitcnt_t): Remove private definition.
+
+	* mpn/generic/bdiv_qr.c: Make it actually work.
+
+	* mpn/x86_64/core2/aorsmul_1.asm: Rewrite to use shorter pipeline and
+	to need fewer registers.
+
+2009-06-17  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/rsh1aors_n.asm: New file.
+	* mpn/x86_64/rsh1add_n.asm: Remove.
+	* mpn/x86_64/rsh1sub_n.asm: Remove.
+
+	* mpz/inits.c: New file.
+
+	* gen-trialdivtab.c: Wrap limb constants into CNST_LIMB.
+
+	With Martin Boij:
+	* mpn/generic/perfpow.c (binv_root, binv_sqroot): Change from being
+	recursive to being iterative.
+	(mpn_perfect_power_p): Reorganise temp memory usage to avoid a buffer
+	overrun.  Trim allocation of next and prev.  Never create oversize
+	products in the multiplicity binary search.
+
+	* mpn/generic/dc_div_q.c: Add missing TMP_FREE.
+
+2009-06-16  Torbjorn Granlund  <tege@gmplib.org>
+
+	Revert:
+	* mpn/generic/perfpow.c (perfpow): Test exponents up to ub, inclusive.
+
+2009-06-16  Martin Boij  <mboij@kth.se>
+
+	* mpn/generic/perfpow.c (logs): Use more conservative table.
+
+2009-06-15  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/pa64/aors_n.asm: New file.
+	* mpn/pa64/add_n.asm: Remove.
+	* mpn/pa64/sub_n.asm: Remove.
+
+	* mpn/generic/perfpow.c (perfpow): Test exponents up to ub, inclusive.
+
+2009-06-14  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/bdiv_q_1.asm: Optimise away a mov insn.
+	* mpn/x86_64/dive_1.asm: Likewise.
+
+	* mpn/generic/perfpow.c (binv_root): Use mpn_bdiv_q_1, not
+	mpn_divexact_itch for 2-adic division.
+	(all functions): Micro optimise.
+
+	* Makefile.am (libmp_la_SOURCES): Add nextprime.c.
+
+2009-06-13  Torbjorn Granlund  <tege@gmplib.org>
+
+	* gmp-h.in (mpn_perfect_power_p): Declare.
+	* configure.in (gmp_mpn_functions): Add perfpow.
+	* mpz/perfpow.c: Now trivial, simply calls mpn_perfect_power_p.
+
+2009-06-13  Martin Boij  <mboij@kth.se>
+
+	* mpn/generic/perfpow.c: New file.
+	* tests/mpz/t-perfpow.c: Rewrite.
+
+2009-06-12  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/bdiv_qr.c: New file.
+	* mpn/generic/bdiv_q.c: New file.
+	* configure.in (gmp_mpn_functions): Add bdiv_qr and bdiv_q.
+	* gmp-impl.h: Declare new functions.
+
+	* nextprime.c: New file.
+	* gmp-impl.h (gmp_primesieve_t, gmp_init_primesieve, gmp_nextprime):
+	Declare.
+	* Makefile.am (libgmp_la_SOURCES): Add nextprime.c.
+
+2009-06-11  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/trialdiv.c: New file.
+	* gen-trialdivtab.c: New file.
+	* configure.in (gmp_mpn_functions): Add trialdiv.
+	* gmp-impl.h (mpn_trialdiv): Declare
+	* Makefile.am: Add rules for gen-trialdivtab and trialdiv.
+
+	* longlong.h (arm count_leading_zeros): Define for armv5.
+
+	* gmp-impl.h: Move down toom itch functions to after we've #defined
+	all THRESHOLDs.
+
+	* dumbmp.c (isprime): Replace with slightly less inefficient code.
+	(mpz_tdiv_r): New function.
+
+2009-06-11  Niels Möller  <nisse@lysator.liu.se>
+
+	Support for mpn_toom32_mul in speed:
+	* tune/speed.c (routine): Added mpn_toom32_mul.
+	* tune/speed.h (SPEED_ROUTINE_MPN_TOOM32_MUL): New macro.
+	* tune/common.c (speed_mpn_toom32_mul): New function.
+
+	* gmp-impl.h (mpn_toom32_mul_itch): Count scratch space needed
+	for the calls to mpn_toom22_mul.
+	(ABOVE_THRESHOLD): Moved this and related macros so it can be used
+	by mpn_toom32_mul_itch.
+	(mpn_toom22_mul_itch): Count scratch space for recursive calls.
+
+2009-06-11  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86/k7/mod_1_4.asm: New file, mainly for k7, but perhaps useful
+	also for k6 and non-sse p6.
+
+2009-06-10  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/mod_1_4.asm: Minor size reducing tweaks.
+
+	* mpn/x86/mod_1.asm: Remove obsolete file.
+	* mpn/x86/k7/mmx/mod_1.asm: Likewise.
+	* mpn/x86/pentium4/sse2/mod_1.asm: Likewise.
+	* mpn/x86/p6/mod_1.asm: Likewise.
+	* mpn/x86/pentium/mod_1.asm: Likewise.
+
+2009-06-08  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/toom4_sqr.c (mpn_toom4_sqr): Reorganized, to reduce
+	the need for scratch space, and get rid of TMP_ALLOC. Also use
+	mpn_toom_eval_dgr3_pm1.
+
+	* mpn/generic/toom_interpolate_6pts.c (mpn_toom_interpolate_6pts):
+	Stricter ASSERTs based on maximum size of polynomial coefficients.
+	Improved comments on the signedness of intermediate values.
+
+2009-06-07  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/toom2_sqr.c: Make it actually work.
+
+	* mpn/generic/toom3_sqr.c: Reduce local scratch space.
+
+2009-06-05  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/mul_fft.c (FFT_TABLE2_SIZE): Default to 200.
+	(MUL_FFT_TABLE2_SIZE, SQR_FFT_TABLE2_SIZE): Let these decide
+	FFT_TABLE2_SIZE if they are defined.
+	(struct nk): Use bit field.
+
+2009-06-05  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/toom44_mul.c (mpn_toom44_mult): Use
+	mpn_toom_eval_dgr3_pm1.
+
+	* mpn/generic/toom_eval_dgr3_pm1.c: New file.
+
+	* mpn/generic/toom_interpolate_7pts.c (mpn_toom_interpolate_7pts):
+	Minor cleanup, use mpn_add rather than mpn_add_n + MPN_INCR_U.
+
+	* mpn/generic/toom44_mul.c (mpn_toom44_mul): Reorganized, to
+	reduce the need for scratch space, and get rid of TMP_ALLOC.
+
+2009-06-05  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/toom_interpolate_7pts.c: Fall back mpn_divexact_byN to
+	mpn_bdiv_q_1_pi1, if the latter is NATIVE.
+
+2009-06-04  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/bdiv_q_1.asm: New file.
+
+	* configure.in (HAVE_NATIVE): Add recently added functions.
+	(GMP_MULFUNC_CHOICES): Handle addlsh_n, sublsh_n, rsblsh_n.
+
+	* tune/common.c (speed_mpn_bdiv_q_1, speed_mpn_bdiv_q_1_pi1):
+	New functions.
+	* tune/speed.c (routine): Add mpn_bdiv_q_1 and mpn_bdiv_q_1_pi1.
+	* tune/speed.h (SPEED_ROUTINE_MPN_BDIV_Q_1_PI1): New #define.
+	(SPEED_ROUTINE_MPN_BDIV_Q_1): Mew #define.
+
+	* configure.in (gmp_mpn_functions): Add bdiv_q_1.
+	* mpn/generic/bdiv_q_1.c: New file.
+	* mpn/asm-defs.m4 (define_mpn): Add mpn_bdiv_q_1 and mpn_bdiv_q_1_pi1.
+	* gmp-impl.h (mpn_bdiv_q_1, mpn_bdiv_q_1_pi1): Declare.
+
+	* mpn/x86_64/lshift.asm: Cleanup.
+	* mpn/x86_64/rshift.asm: Cleanup.
+
+	* mpn/x86_64/addlsh1_n.asm: Removed.
+	* mpn/x86_64/aorrlsh1_n.asm: Generalised addlsh1_n.asm to handle
+	addlsh1_n and rsblsh1_n functionality.
+
+	* tests/refmpn.c (refmpn_rsblsh1_n): New function.
+	* tests/devel/try.c: Test mpn_rsblsh1_n.
+	* tests/tests.h: Declare refmpn_rsblsh1_n.
+	* tune/common.c (speed_mpn_rsblsh1_n): New function.
+	* tune/speed.c (routine): Add mpn_rsblsh1_n.
+	* tune/speed.h (mpn_rsblsh1_n): Declare.
+
+	* configure.in (gmp_mpn_functions_optional): Add rsblsh1_n.
+	(GMP_MULFUNC_CHOICES): Handle rsblsh1_n defined with a mulfunc.
+	* mpn/asm-defs.m4 (define_mpn): Add rsblsh1_n.
+	* gmp-impl.h (mpn_rsblsh1_n): Declare.
+
+	* mpn/generic/toom32_mul.c: Consistently use TOOM22_MUL_N_REC.
+
+2009-06-03  Marco Bodrato  <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/toom43_mul.c: New file.
+	* mpn/generic/toom52_mul.c: New file.
+	* mpn/generic/toom_interpolate_6pts.c: New file.
+
+2009-06-03  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.in (gmp_mpn_functions): Add toom43_mul, toom52_mul, and
+	toom_interpolate_6pts, but also some previously forgotten functions.
+	* mpn/Makefile.am (nodist_EXTRA_libmpn_la_SOURCES): Likewise.
+	* gmp-impl.h: Declare new functions. Sort toom function declarations.
+
+	* gmp-impl.h: Rename  toom4_* flags enum to toom7_*.  Relevant C files
+	updated.
+
+	* mpn/generic/toom_interpolate_7pts (divexact_2exp): Remove.
+
+2009-06-02  Torbjorn Granlund  <tege@gmplib.org>
+
+	* demos/factorize.c: Add -q command line option.
+
+2009-06-02  Marco Bodrato  <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/toom_interpolate_7pts.c: Streamline, resulting in speed
+	improvements.
+
+	* mpn/generic/toom_interpolate_5pts.c: Likewise, but also completely
+	do away with explicit scratch space.
+	* gmp-impl.h (mpn_toom_interpolate_5pts): Update prototype.
+
+	* mpn/generic/mul_n.c (mpn_toom3_sqr_n, mpn_toom3_mul_n):
+	Update toom_interpolate_5pts call without scratch space parameter.
+	* mpn/generic/toom3_sqr.c: Likewise.
+	* mpn/generic/toom42_mul.c: Likewise.
+	* mpn/generic/toom33_mul.c: Likewise.
+
+	* mpn/generic/toom33_mul.c: Reduce local scratch space.
+	* mpn/generic/toom32_mul.c: Rewrite to not use local scratch space.
+
+2009-06-02  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/toom22_mul.c (TOOM22_MUL_MN_REC): New macro, use it for
+	oo point.
+
+2009-06-01  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/mul.c: Loop to avoid excessive recursion in toom33 and
+	toom44 slicing code.
+
+	* mpz/remove.c: Correctly handle multiplicity that does not fit an int.
+
+	* Makefile.am (dist-hook): Check library version consistency.
+
+	* mpn/generic/mul.c: Rewrite.
+
+2009-05-29  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/mpz/t-divis.c (check_random): Create huge test operands.
+
+	* mpn/generic/toom44_mul.c: Allocate temp space using one TMP_ALLOC
+	call, not multiple TMP_SALLOC.
+	* mpn/generic/toom4_sqr.c: Likewise.
+
+	* gmp-impl.h (mpn_toom22_mul_itch): Replace totally wrong code.
+
+	* mpn/generic/mullow_n.c: Relax overlap requirement implied by ASSERT.
+
+	* mpn/generic/divis.c: Rewrite.
+
+	* gmp-impl.h (mpn_mu_bdiv_qr): Now returns mp_limb_t.
+	(mpn_toom2_sqr_itch): Simplify.
+
+	* mpn/generic/mu_bdiv_qr.c: Implement properly.
+
+2009-05-27  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/mod_1_1.c: Add proper ASSERT functionality cps function.
+	* mpn/generic/mod_1_2.c: Likewise.
+	* mpn/generic/mod_1_3.c: Likewise.
+	* mpn/generic/mod_1_4.c: Likewise.
+
+	* tune: Add speed measuring of toom22, toom33, and toom44.
+
+	* mpn/generic/toom22_mul.c: Handle potentially unbalanced coefficient
+	product better.
+
+2009-05-26  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/mpz/t-mul.c (ref_mpn_mul): Use mpn_toom44_mul in FFT range for
+	better huge-operands performance.
+
+2009-05-24  Torbjorn Granlund  <tege@gmplib.org>
+
+	* acinclude.m4 (GMP_ASM_LSYM_PREFIX): Try "$L" too, before "$".
+
+2009-05-23  Torbjorn Granlund  <tege@gmplib.org>
+
+	* gmp-impl.h (mpn_mod_1s_1p,mpn_mod_1s_2p,mpn_mod_1s_3p,mpn_mod_1s_4p):
+	Declare using __GMP_ATTRIBUTE_PURE.
+
+	* tune/tuneup.c (tune_mod_1): Specify check_size for measuring mod_1_N
+	functions.
+	(one): Remove redundant size loop exit condition.
+
+2009-05-20  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86/pentium4/sse2/mod_1_4.asm: New file.
+	* mpn/x86/p6/sse2/mod_1_4.asm: New file (grabbing pentium4 code).
+
+2009-05-18  Torbjorn Granlund  <tege@gmplib.org>
+
+	* gmp-h.in (__GNU_MP_VERSION_MINOR): Bump to 4.
+	(__GNU_MP_VERSION_PATCHLEVEL): Set to -1.
+
+	* mpn/x86_64/mod_1_4.asm: New file.
+
+	* mpn/asm-defs.m4: Correct names for mod_1_N functions.
+	Add defines for corresponding cps functions.
+
+	* mpn/generic/mod_1_2.c: Support any sizes > 1.
+	* mpn/generic/mod_1_3.c: Likewise.
+	* mpn/generic/mod_1_4.c: Likewise.
+
+2009-05-12  Torbjorn Granlund  <tege@gmplib.org>
+
+	* Version 4.3.1 released.
+
+2009-05-11  Torbjorn Granlund  <tege@gmplib.org>
+
+	* gmp-h.in (__GNU_MP_VERSION_MINOR): Bump.
+
+	* Makefile.am (LIBGMP_LT_*, LIBGMPXX_LT_*, LIBMP_LT_*):
+	Bump version info.
+
+2009-05-09  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/mpz: Add MPZ_CHECK_FORMAT to many tests.
+
+2009-05-07  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86/pentium4/sse2/mul_basecase.asm: Avoid L(ret), "ret" is
+	defined in x86-defs.m4.
+
+2009-05-06  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86/p6/aors_n.asm: Use L() for labels.
+	* mpn/x86/pentium4/sse2/addmul_1.asm: Likewise.
+	* mpn/x86/pentium4/sse2/mul_1.asm: Likewise.
+	* mpn/x86/pentium4/sse2/mul_basecase.asm: Likewise.
+	* mpn/x86/pentium4/sse2/sqr_basecase.asm: Likewise.
+	* mpn/x86_64/lshift.asm: Likewise.
+	* mpn/x86_64/rshift.asm: Likewise.
+
+	* tests/cxx/t-locale.cc (point_string): Declare as extern "C" to
+	placate compilers that mangle variable names.
+
+2009-05-04  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/mpz/t-gcd.c: Generate operands that are multiple of each other.
+
+2009-05-01  Torbjorn Granlund  <tege@gmplib.org>
+
+	* gmp-h.in (__GMP_EXTERN_INLINE): Support for more systems.
+	(gmp_randinit_set): Add missing __GMP_DECLSPEC.
+
+2009-04-28  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/neg_n.c: New file.
+	* configure.in (gmp_mpn_functions): Add neg_n.
+	* mpn/asm-defs.m4 (define_mpn): Add neg_n.
+	* mpn/Makefile.am (nodist_EXTRA_libmpn_la_SOURCES): Add neg_n.c.
+	* gmp-h.in: Handle mpn_neg_n properly.
+
+	* mpn/generic/toom_interpolate_7pts.c (divexact_2exp): Nailify.
+
+	* mpn/generic/gcdext.c: Change some MPN_NORMALIZE to
+	MPN_NORMALIZE_NOT_ZERO.
+	* mpn/generic/gcdext_lehmer.c: Likewise.
+	Add a MPN_NORMALIZE_NOT_ZERO.
+
+	* mpn/generic/binvert.c: Remove own mpn_neg_n.
+
+	* tests/mpz/t-gcd.c: Add some MPZ_CHECK_FORMAT calls.
+
+2009-04-27  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/Makefile.am (TARG_DIST): Add minithres.
+
+	* mpn/generic/bdiv_dbm1c.c: Handle nails.
+
+2009-04-26  Torbjorn Granlund  <tege@gmplib.org>
+
+	* config.guess: Recognise more POWER processor types.
+
+2009-04-25  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86/pentium4/sse2/popcount.asm: Work around Apple reloc bug.
+	* mpn/x86/darwin.m4: Define symbol "DARWIN".
+
+2009-04-19  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/powm.c (mpn_redc_n): Use ASSERT_ALWAYS, not abort().
+	* mpn/generic/powm_sec.c: Likewise.
+
+	* mpn/powerpc64/aix.m4 (EXTERN_FUNC): New define.  Add dummy variants
+	for other m4 files.
+	* mpn/powerpc64/mode64/divrem_1.asm: Use EXTERN_FUNC.
+	* mpn/powerpc64/mode64/divrem_1.asm: Likewise.
+
+2009-04-16  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/x86_64-defs.m4 (JUMPTABSECT): New define.
+	* mpn/x86_64/darwin.m4: Likewise.
+	* mpn/x86_64/sqr_basecase.asm: Rework switch code using JUMPTABSECT.
+
+	* tune/common.c (speed_mpn_hgcd, speed_mpn_hgcd_lehmer):
+	Remove an unused variable.
+
+	* mpn/x86/x86-defs.m4 (LEA): Get SIZE arguments right.
+
+2009-04-14  Torbjorn Granlund  <tege@gmplib.org>
+
+	* Version 4.3.0 released.
+
+	* scanf/doscan.c (__gmp_doscan): Pad 3-operand scanf call with dummy
+	argument.
+	* scanf/sscanffuns.c (scan): Disable vsscanf variant for now.
+
+2009-04-13  Torbjorn Granlund  <tege@gmplib.org>
+
+	* scanf/sscanffuns.c (scan): Rewrite to use stdarg.
+
+	* tests/mpz/t-root.c: Rewrite.  Add unconditional gcc 4.3.2 tests.
+
+2009-04-09  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/powm.c: New file.
+	* mpn/generic/powlo.c: New file.
+	* mpn/generic/powm_sec.c: New file.
+	* configure.in (gmp_mpn_functions): List new functions.
+
+2009-04-08  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpz/urandomm.c: Amend last fix.
+
+2009-04-06  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.in: Support Sun cc for x86_64.
+
+	* mpz/urandomm.c: Handle operand overlap.
+
+2009-03-11  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.in (powerpc): Brave removing -Wa,-mppc64, in the hope that
+	GCC now passes the proper options.
+
+2009-03-09  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/divrem_1.asm: Add a nop to save a cycle in unnormalised
+	case.
+
+2009-03-05  Torbjorn Granlund  <tege@gmplib.org>
+
+	* ia64/gmp-mparam.h, arm/gmp-mparam.h, x86/p6/mmx/gmp-mparam.h,
+	pa32/hppa2_0/gmp-mparam.h sparc32/v9/gmp-mparam.h: Update.
+
+2009-03-03  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/ia64/bdiv_dbm1c.asm: Accept/return carry.
+
+2009-03-02  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.in (64-bit sparc/solaris): Pass -xO3, not -O3 to solaris
+	system compiler.
+
+2009-03-01  Torbjorn Granlund  <tege@gmplib.org>
+
+	* longlong.h (mips, powerpc): Provide assembly-free umul_ppmm for newer
+	gcc.
+
+2009-02-04  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/redc_2.c: Remove code for testing and timing.  Update
+	to current FSF header.
+	* mpn/generic/redc_1.c: Update to current FSF header.
+
+2009-01-21  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpz/powm.c (redc): Remove.
+	(mpz_powm): Use mpn_redc_1 instead of redc.
+
+	* tests/mpz/t-powm.c: Rewrite reference code.
+
+2009-01-18  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/mpz: Increase reps for many tests.
+
+	* mpn/generic/rootrem.c (mpn_rootrem_internal): Use MPN_DECR_U instead of
+	mpn_sub_1 (works around gcc 4.3 bugs and is also faster).
+
+2009-01-16  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/tests.h: Declare refmpn_divrem_2.
+
+2009-01-15  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpz/perfpow.c: Add TMP_FREE before every return statement.
+
+	* mpn/generic/rootrem.c (mpn_rootrem_internal): Add a missing TMP_FREE.
+
+	* configure.in (gcc_cflags, gcc_64_cflags): Revert from -O3 to -O2,
+	the change was accidental and cause too much miscompilation.
+
+2009-01-14  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tune/tuneup.c (tune_mod_1): Run MOD_1_x_THRESHOLD tests also when
+	longlong.h specified UDIV_PREINV_ALWAYS.
+
+	* mpn/generic/mod_1.c (mpn_mod_1): Properly check for normalisation
+	divisor.
+
+2009-01-13  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tune/tuneup.c (tune_mod_1): Tune for MOD_1_1_THRESHOLD,
+	MOD_1_2_THRESHOLD, and MOD_1_4_THRESHOLD.
+
+	* mpn/generic/mod_1.c: Rewrite.
+	* mpn/generic/mod_1_1.c: New file.
+	* mpn/generic/mod_1_2.c: New file.
+	* mpn/generic/mod_1_3.c: New file.
+	* mpn/generic/mod_1_4.c: New file.
+	* configure.in (gmp_mpn_functions): Add mod_1_*.
+	* mpn/asm-defs.m4 (define_mpn): Add mod_1_*.
+	* mpn/Makefile.am (nodist_EXTRA_libmpn_la_SOURCES): Add mod_1_*.c.
+	* gmp-impl.h: Declare new mpn_mod_1s_* functions and associated
+	THRESHOLD macros.
+	(udiv_rnd_preinv): New macro.
+
+2009-01-12  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tune/tuneup.c (tune_gcd_dc,tune_gcdext_dc): Lower step_factor to 0.1.
+
+2009-01-08  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/mpz/t-nextprime.c: New test file.
+	* tests/mpz/Makefile.am (check_PROGRAMS): Add t-nextprime.
+
+	From Niels Möller:
+	* mpz/nextprime.c: Handle large prime gaps by limiting incr.
+
+2009-01-04  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpz/and.c, mpz/ior.c, mpz/xor.c: Re-read only necessary source
+	pointers after reallocation.  Misc cleanup.
+
+	* gmp-impl.h (MPN_TOOM44_MAX_N): New define, replaces MPN_TOOM3_MAX_N.
+
+	* mpn/x86/fat/diveby3.c: New file.
+
+2008-12-30  Niels Möller  <nisse@lysator.liu.se>
+
+	* doc/gmp.texi (Greatest Common Divisor Algorithms): Updated
+	section on GCD algorithms.
+
+2008-12-29  Torbjorn Granlund  <tege@gmplib.org>
+
+	* doc/gmp.texi (Multiplication Algorithms): Add descriptions of Toom-4
+	and unbalanced multiplication.
+	(Radix to Binary): Add warning that text is outdated,
+	(Contributors): Fix typos.
+
+	* mpn/generic/toom*.c: Use coherent MAYBE_ macros for trimming
+	unreachable recursive functions.
+	* gmp-impl.h: Update toom itch functions.
+
+	* mpn/x86_64/sqr_basecase.asm: Slightly increase stack allocation, to
+	placate tuneup.
+
+2008-12-28  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/pentium4/aors_n.asm: Tune prologue code.
+
+	* mpn/x86_64/pentium4/aorslsh1_n.asm: New file.
+
+	* mpn/x86_64/darwin.m4: Define symbol "DARWIN".
+	* mpn/x86_64/invert_limb.asm: Work around darwin quirks.
+
+	* mpn/x86_64/sqr_basecase.asm: Further optimize, support Darwin.
+
+	* mpn/x86_64/invert_limb.asm: New file.
+
+2008-12-27  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/core2/aorslsh1_n.asm: New file.
+
+2008-12-26  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpz/perfpow.c: Handle negative arguments properly.
+	* tests/mpz/t-perfpow.c: New file.
+	* tests/mpz/Makefile.am (check_PROGRAMS): Add t-perfpow.
+
+2008-12-23  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/mpz/t-mul.c (dump_abort): Improve error message.
+
+	* gcd.c gcd_subdiv_step.c gcdext.c gcdext_subdiv_step.c:
+	Remove private mpn_zero_p.
+
+	* tune/tuneup.c (tune_mul): Tune for MUL_TOOM44_THRESHOLD.
+	(tune_sqr): Tune for SQR_TOOM4_THRESHOLD.
+
+	* tune/Makefile.am (TUNE_MPN_SRCS_BASIC): Add toom44_mul.c and
+	toom4_sqr.c.
+
+	* configure.in (gmp_mpn_functions): Toom function updates.
+
+	* Rename mpn/mul_toomMN.c to mpn/toomMN_mul.c.  Function names changed
+	accordingly.
+
+	* mpn/toomMN_mul.c: Add scratch parameter.  Do recursive multiplies
+	properly.  Misc tuning.  Remove CHECK and TIMING code.
+
+	* mpn/toom2_sqr.c, mpn/toom3_sqr.c, mpn/toom4_sqr.c: New files.
+
+	* gmp-impl.h (mpn_toomMN_mul_itch): Several new functions.
+	(mpn_zero_p): New functions.
+	Add various TOOM4/TOOM44 related parameters.
+	Update mpn_toomMN_mul prototypes.
+
+	* mpn/generic/mul_n.c (mpn_mul_n): Call mpn_toom44_mul.  Use TMP_BALLOC
+	instead of malloc.
+	(mpn_sqr_n): Analogous changes.
+
+	* mpn/generic/mul.c: Update unbalanced toom code to pass scratch space.
+
+2008-12-21  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpz/nextprime.c: Add TMP_SDECL/MARK/FREE.
+
+2008-12-20  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/sqrtrem.c (mpn_sqrtrem1): Rewrite, improve interface.
+	(invsqrttab): New table, remove table approx_tab.
+	(mpn_sqrtrem2): Optimize, update mpn_sqrtrem1 call.
+	(mpn_sqrtrem): Update mpn_sqrtrem1 call.
+
+2008-12-18  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpz/nextprime.c: Run 10 mpz_millerrabin tests (was 5).
+	Give credit to authors.
+
+	* mpn/x86_64/redc_1.asm: Align stack as mandated by ABI.
+
+	* mpn/x86_64/divrem_2.asm: Add some comments.
+
+	* mpn/x86_64/darwin.m4: New file.
+	* configure.in: Use x86_64/darwin.m4.
+
+2008-12-15  Torbjorn Granlund  <tege@gmplib.org>
+
+	* doc/projects.html: Remove GCD and division projects, update text on
+	multiplication.
+
+	* doc/tasks.html: Add a caution about that the file is somewhat
+	outdated.
+
+2008-12-14  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/alpha/ev6/aorsmul_1.asm: New file (same code for mpn_addmul_1,
+	much improved for mpn_submul_1).
+	* mpn/alpha/ev6/addmul_1: File removed.
+	* mpn/alpha/ev6/submul_1: File removed.
+
+2008-12-09  Torbjorn Granlund  <tege@gmplib.org>
+
+	From David Harvey:
+	* mpn/x86_64/mul_basecase.asm: Further tweaks for code size and speed.
+
+	* mpn/powerpc64/mode64/divrem_1.asm: Rewrite.
+
+	* mpn/powerpc64/mode64/mul_basecase.asm: New file.
+
+2008-12-08  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/powerpc64/mode64/gmp-mparam.h: New file.
+
+	* gmp-impl.h: Additional cleanups.
+	(mpn_set_str_compute_powtab): New prototype.
+	(mpn_powm, mpn_powlo): New prototypes.
+
+	* mpz/pow_ui.c: Handle some small exponents locally.
+
+2008-12-07  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/set_str.c: Remove prototypes (they are in gmp-impl.h).
+
+	* tune/set_strs.c, tune/set_strb.c: Make prototypes effective by moving
+	the #define mpn_set_str* before including gmp-impl.h.
+
+	* All files: Change _PROTO => __GMP_PROTO.
+
+	* tune/speed.c (routine): Remove non-working choice mpn_set_str_subquad.
+	* tune/common.c (speed_mpn_dc_set_str): Remove, it is broken.
+
+	* mpn/generic/toom_interpolate_7pts.c (divexact_2exp): Make this static,
+	and inline it.
+
+	* gmp-impl.h: Major cleanup.
+	(Remove formal parameter names.  Use __GMP_PROTO consistently.  Move
+	__GMP_PROTO and __MPN use to adjacent lines for declared function.
+	Fix typos.  Remove code inside #if 0.)
+
+	* configure.in (gmp_mpn_functions): Add mul_toom33.  Reformat.
+
+2008-12-05  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/redc_1.c: New file.
+	* mpn/generic/redc_2.c: New file.
+
+	* configure.in (gmp_mpn_functions): List redc_1 and redc_2.
+	(HAVE_NATIVE): Likewise.
+
+	* tune/common.c (speed_mpn_redc_1): Renamed from speed_redc.
+	* tune/speed.c (routine): Remove "redc", and "mpn_redc_1".
+	* tune/speed.h (SPEED_ROUTINE_REDC_1): Renamed from SPEED_ROUTINE_REDC.
+	Updated call.
+	* tune/tuneup.c (tune_powm): Update redc call.
+
+2008-12-04  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/sqr_basecase.asm: Inline a combined diagonal product code
+	and addlsh1 loop.  Misc cleanup.
+
+2008-12-02  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/sqr_basecase.asm: New file.
+
+2008-11-30  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/sqr_basecase.c: Fix typo in mpn_addmul_2s variant.
+
+2008-11-28  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/redc_1.asm: Rewrite.
+
+2008-11-27  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/refmpn.c (refmpn_redc_1): New function.
+
+2008-11-25  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86/k7/aorsmul_1.asm: Actually handle mpn_submul_1.
+
+2008-11-23  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/divrem_1.asm: Rewrite.
+
+	* alpha/divrem_2.asm: New file.
+	* powerpc32/divrem_2.asm: New file.
+	* powerpc64/mode64/divrem_2.asm: New file.
+	* x86/divrem_2.asm: New file.
+	* x86_64/divrem_2.asm: New file.
+	* tests/refmpn.c (refmpn_divrem_2): New function.
+
+2008-11-22  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86/k7/mul_1.asm: Rewrite for smaller size and better speed.
+	* mpn/x86/k7/aorsmul_1.asm: Likewise.
+
+	* acinclude.m4 (GMP_VERSION): Include last component even when zero.
+
+2008-11-21  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/README: Rewrite.
+
+	* tests/devel/try.c (malloc_region, mprotect_maybe): Add casts for
+	printf type correctness.
+
+	* gmp-h.in (__GNU_MP_VERSION_MINOR): Bump.
+
+	* Makefile.am (LIBGMP_LT_*, LIBGMPXX_LT_*, LIBMP_LT_*):
+	Bump version info.
+
+2008-11-20  Torbjorn Granlund  <tege@gmplib.org>
+
+	* gmp-impl.h: Rename modlimb_invert to binvert_limb.
+	* tune/speed.h: Likewise.
+	* tune/modlinv.c: Likewise.
+	* tune/common.c: Likewise.
+	* tests/t-modlinv.c: Likewise.
+	* tests/t-constants.c: Likewise.
+	* mpn/sparc64/mode1o.c: Likewise.
+	* mpn/alpha/dive_1.c: Likewise.
+	* mpn/sparc64/dive_1.c: Likewise.
+	* mpn/generic/mode1o.c: Likewise.
+	* mpn/generic/dive_1.c: Likewise.
+	* mpn/generic/bdivmod.c: Likewise.
+	* mpn/alpha/mode1o.asm: Likewise.
+	* mpn/asm-defs.m4: Likewise.
+	* mpn/ia64/mode1o.asm: Likewise.
+	* mpn/powerpc32/README: Likewise.
+	* mpn/powerpc32/mode1o.asm: Likewise.
+	* mpn/powerpc64/mode64/dive_1.asm: Likewise.
+	* mpn/powerpc64/mode64/mode1o.asm: Likewise.
+	* mpn/x86/dive_1.asm: Likewise.
+	* mpn/x86/k6/mmx/dive_1.asm: Likewise.
+	* mpn/x86/k6/mode1o.asm: Likewise.
+	* mpn/x86/k7/dive_1.asm: Likewise.
+	* mpn/x86/k7/mode1o.asm: Likewise.
+	* mpn/x86/p6/dive_1.asm: Likewise.
+	* mpn/x86/p6/mode1o.asm: Likewise.
+	* mpn/x86/pentium/dive_1.asm: Likewise.
+	* mpn/x86/pentium/mode1o.asm: Likewise.
+	* mpn/x86/pentium4/sse2/dive_1.asm: Likewise.
+	* mpn/x86/pentium4/sse2/mode1o.asm: Likewise.
+	* mpn/x86_64/dive_1.asm: Likewise.
+	* mpn/x86_64/mode1o.asm: Likewise.
+
+	* mpn/x86_64/aors_n.asm: Replace with slightly faster, more alignment
+	neutral loop.
+
+2008-11-18  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.in: Remove gcd_finda related declarations.
+	* gmp-impl.h (mpn_gcd_finda): Remove declaration.
+	* mpn/Makefile.am (nodist_EXTRA_libmpn_la_SOURCES): Remove gcd_finda.
+	* mpn/asm-defs.m4: Remove define_mpn(gcd_finda).
+	* mpn/x86/k6/gcd_finda.asm: Remove file.
+	* tests/devel/try.c (param_init): Remove mpn_gcd_finda.
+	(choice_array): Remove mpn_gcd_finda.
+	* tests/mpn/t-instrument.c (check): Remove testing of mpn_gcd_finda.
+	* tests/refmpn.c (refmpn_gcd_finda): Remove.
+	* tests/tests.h (refmpn_gcd_finda): Remove declaration.
+	* tune/common.c (speed_mpn_gcd_finda): Remove.
+	* tune/gcd_finda_gen.c: Remove file.
+	* tune/speed.h (speed_mpn_gcd_finda): Remove declaration.
+	* tune/speed.c (routine): Remove mpn_gcd_finda entry.
+
+	* tests/mpz/t-powm.c: Print test number when failing a test.
+
+	* mpn/x86_64/redc_1.asm (CALL): Move from here...
+	* mpn/x86_64/x86_64-defs.m4: ...to here.
+
+	* gmp-impl.h (mpn_jacobi_base): Remove parameter names.
+
+2008-11-11  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/mpf/t-conv.c: Add some specific tests, supplementing the random
+	tests.
+
+2008-11-09  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpf/set_str.c: Default 'base' before letting exp_base inherit it.
+
+	* tests/cxx/t-prec.cc: Use the right precision for all float constants.
+
+2008-11-08  Torbjorn Granlund  <tege@gmplib.org>
+
+	* doc/gmp.texi (Float Comparison): Update mpf_eq documentation.
+
+	* mpf/eq.c: Compare the right number of bits.
+
+2008-11-02  Torbjorn Granlund  <tege@gmplib.org>
+
+	Undo, it made testing too slow:
+	* tests/mpz/t-mul.c: Use slower geometric progression for operand
+	sizes.
+
+	* mpn/x86/k7/mod_34lsub1.asm: Use movzb for masking low 8 bits.
+
+2008-10-31  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/hgcd2.c (div1): New function (taken from old gcdext
+	implementation)
+	(mpn_hgcd2): Use single precision for the second half of the work.
+
+2008-10-30  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86/p6/sse2/gmp-mparam.h: New file.
+
+2008-10-29  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.in (x86 fat_path): Add "x86/p6/sse2".
+
+	* mpn/x86/fat/fat.c (__gmpn_cpuvec_init): Recognize sse2 capable p6
+	(pentiumm, core2).
+
+	* mpn/x86/p6/sse2/mul_1.asm: New file.
+	* mpn/x86/p6/sse2/addmul_1.asm: New file.
+	* mpn/x86/p6/sse2/submul_1.asm: New file.
+	* mpn/x86/p6/sse2/mul_basecase.asm: New file.
+	* mpn/x86/p6/sse2/sqr_basecase.asm: New file.
+	* mpn/x86/p6/sse2/popcount.asm: New file.
+
+	* mpn/x86/fat/fat.c (__gmpn_cpuvec_init): Handle "extended" fields for
+	model and family.
+
+2008-10-28  Torbjorn Granlund  <tege@gmplib.org>
+
+	From Mickael Gastineau:
+	* gmp-h.in (gmp_urandomm_ui, gmp_urandomb_ui): Add __GMP_DECLSPEC.
+
+2008-10-27  Torbjorn Granlund  <tege@gmplib.org>
+
+	* gmp-h.in (mpn_gcdext_1): Remove bogus __GMP_ATTRIBUTE_PURE.
+
+2008-10-27  Niels Möller  <nisse@lysator.liu.se>
+
+	* tune/common.c (speed_mpn_hgcd): Call mpn_hgcd_matrix_init once
+	for each call to mpn_hgcd.
+	(speed_mpn_hgcd_lehmer): Likewise.
+
+2008-10-26  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.in: Point to p6/sse2 for pentiumm and core2.
+
+	* gmp-impl.h (mpn_add_nc, mpn_sub_nc): Move these macros to after fat
+	definitions.
+
+	* tune/common.c, tune/speed.c, tune/speed.h:
+	Add speed measurement of mpn_bdiv_dbm1c.
+
+2008-10-24  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/gmp-mparam.h (MUL_FFT_TABLE2, SQR_FFT_TABLE2): Extend.
+
+	* mpz/nextprime.c: Move declarations to function beginning.
+
+2008-10-23  Niels Möller  <nisse@lysator.liu.se>
+
+	* gmp-impl.h (DECL_gcdext_1): Deleted.
+
+2008-10-22  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/atom/aors_n.asm: New file.
+	* mpn/x86_64/atom/gmp-mparam.h: New file.
+
+2008-10-21  Torbjorn Granlund  <tege@gmplib.org>
+
+	With Neils Möller:
+	* mpz/nextprime.c: Rewrite.
+
+	* tests/devel/try.c (main): Use strtol for 's' and 'S' optargs.
+
+	* mpn/x86_64/pentium4/rshift.asm: Misc cleanups.
+	* mpn/x86_64/pentium4/lshift.asm: Likewise.
+
+	* mpn/x86_64/pentium4/aors_n.asm: Use fewer registers.
+
+	* configure.in: Set up specific path for x86_64/atom.
+
+2008-10-21  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/Makefile.am (nodist_EXTRA_libmpn_la_SOURCES): Removed
+	qstack.c.
+	* mpn/generic/qstack.c: Deleted obsolete file.
+
+2008-10-20  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/core2/aorsmul_1.asm: New file.
+
+2008-10-19  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/aors_n.asm: Remove redundant MULFUNC_PROLOGUE.
+
+	* gmp-impl.h (popc_limb): Remove redundant checks of GMP_LIMB_BITS
+	inside several of these macros.
+
+2008-10-17  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/mpz/t-mul.c: Use slower geometric progression for operand
+	sizes.  Do every other tests for same size operands.
+
+2008-10-15  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/mul_basecase.asm: Simplify addressing in epilogue.
+
+	* mpn/mips64/divrem_1.asm: Remove file, it is n32-only, and uses an old
+	algorithm.
+
+	* config.guess, config.sub, configure.in: Support Intel Atom processor.
+
+2008-10-10  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpq/mul.c: Fix typo in last change.
+
+2008-10-09  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/refmpn.c (refmpn_sb_divrem_mn): Work around a gcc bug.
+
+2008-10-08  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpq/mul.c: Use TMP_ALLOC.  Cleanup.
+	* mpq/div.c: Likewise.
+
+	* mpn/x86_64/mul_basecase.asm: Use lea directly for loading entry point
+	addresses.
+
+2008-10-09  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/x86/k7/gmp-mparam.h: Updated GCD-related values.
+
+2008-10-05  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/mul_fft.c (mpn_mul_fft_internal): Do store
+	mpn_fft_norm_modF return value, if (rec).
+
+2008-10-04  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/aorsmul_1.asm: Replace with faster code.
+	* mpn/x86_64/mul_1.asm: Likewise.
+	* mpn/x86_64/addmul_2.asm: Likewise.
+	* mpn/x86_64/mul_2.asm: Likewise.
+	* mpn/x86_64/mul_basecase.asm: Likewise.
+
+2008-10-02  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/minithres/gmp-mparam.h: Update FFT values.
+
+2008-10-02  Niels Möller  <nisse@lysator.liu.se>
+
+	* hgcd.c (mpn_hgcd_matrix_mul): Fixed normalization bug.
+
+2008-09-24  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.in: Handle --enable-minithres.
+	* mpn/minithres/gmp-mparam.h: Update all values.
+
+2008-09-22  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tune/speed.c (routine): New entry for mpn_mul.
+	* tune/speed.h (SPEED_ROUTINE_MPN_MUL): Renamed from
+	SPEED_ROUTINE_MPN_MUL_BASECASE.
+	(speed_mpn_mul): Renamed from speed_mpn_mul_basecase.
+	(SPEED_ROUTINE_MPN_MUL): Allocate our own memory of xp operand.
+
+	* tune/common.c: Corresponding changes.
+
+2008-09-22  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/gcdext.c (hgcd_mul_matrix_vector): New function,
+	replaces addmul2_n. Needs less copying.
+	(mpn_gcdext): Use hgcd_mul_matrix_vector. Updated for interface
+	change in mpn_gcdext_subdiv_step
+
+	* mpn/generic/hgcd.c (hgcd_matrix_mul_1): Rewritten to use
+	mpn_hgcd_mul_matrix1_vector.
+	(hgcd_step): Updated for interface change in
+	mpn_hgcd_mul_matrix1_inverse_vector.
+
+	* mpn/generic/gcdext_lehmer.c (mpn_gcdext_lehmer_n): Updated for
+	interface changes in mpn_hgcd_mul_matrix1_vector,
+	mpn_hgcd_mul_matrix1_inverse_vector and mpn_gcdext_subdiv_step.
+
+	* mpn/generic/gcd_lehmer.c (mpn_gcd_lehmer_n): Updated for
+	interface change in mpn_hgcd_mul_matrix1_inverse_vector.
+
+	* mpn/generic/gcdext_subdiv_step.c (mpn_gcdext_subdiv_step): Use
+	separate scratch arguments for the quotient and for the cofactor
+	update.
+
+	* mpn/generic/hgcd2.c (mpn_hgcd_mul_matrix1_vector): Interface
+	change. Store first element in rp and leave ap unmodified. No
+	additional scratch space or copying needed. Callers that require
+	modification in place still need to copy one of the inputs.
+	(mpn_hgcd_mul_matrix1_inverse_vector): Likewise.
+
+2008-09-22  Niels Möller <nisse@lysator.liu.se>  <nisse@king.swox.se>
+
+	* mpn/generic/hgcd.c (hgcd_matrix_mul_1): Use mpn_addaddmul_1msb0.
+	* mpn/generic/hgcd2.c (mpn_hgcd_mul_matrix1_vector): Likewise.
+
+	* mpn/generic/gcd.c: Use libspeed for timing measurements.
+
+	* gmp-impl.h: Declare mpn_addaddmul_1msb0.
+	* mpn/asm-defs.m4: Added addaddmul_1msb0.
+	* mpn/x86_64/addaddmul_1msb0.asm: New file.
+	* configure.in (gmp_mpn_functions_optional): Added
+	addaddmul_1msb0.
+	(HAVE_NATIVE): List addaddmul_1msb0.
+
+2008-09-21  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/get_str.c (GET_STR_DC_THRESHOLD): Remove default.
+	(GET_STR_PRECOMPUTE_THRESHOLD): Likewise.
+	Misc code cleanups.
+
+	* gmp-impl.h (mpn_dc_set_str_itch): Allocate GMP_LIMB_BITS more limbs.
+
+	Revert:
+	* mpn/generic/set_str.c:
+	(mpn_dc_set_str): Remove impossible case, replace by an ASSERT.
+
+2008-09-18  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/alpha/ev6/gmp-mparam.h (DIVEXACT_BY3_METHOD): Define.
+
+	* mpn/ia64/diveby3.asm: Remove.
+	* mpn/x86/diveby3.asm: Remove.
+	* mpn/x86/k6/diveby3.asm: Remove.
+	* mpn/x86/k7/diveby3.asm: Remove.
+	* mpn/x86/p6/diveby3.asm: Remove.
+	* mpn/x86/pentium/diveby3.asm: Remove.
+	* mpn/x86_64/diveby3.asm: Remove.
+	* mpn/x86/pentium4/sse2/diveby3.asm: Remove.
+
+	* configure.in (HAVE_NATIVE): List divexact_by3c.
+
+	* gmp-impl.h (mpn_divexact_by3c): Override gmp-h.in's definition.
+	(DIVEXACT_BY3_METHOD): Don't default to 0 if
+	HAVE_NATIVE_mpn_divexact_by3c.
+
+2008-09-18  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/gcd.c (main): Added code for tuning of CHOOSE_P.
+
+	* mpn/generic/hgcd.c (mpn_hgcd_matrix_mul): Assert that inputs are
+	normalized.
+
+2008-09-17  Niels Möller <nisse@lysator.liu.se>  <nisse@king.swox.se>
+
+	* mpn/generic/gcdext.c (mpn_gcdext): p = n/5 caused a
+	slowdown for large inputs. As a compromise, use p = n/2 for the
+	first iteration, and p = n/3 for the rest. Handle the first
+	iteration specially, since the initial u0 and u1 are trivial.
+
+	* mpn/x86_64/gmp-mparam.h (GCDEXT_DC_THRESHOLD): Reduced threshold
+	from 409 to 390.
+
+	* mpn/generic/gcdext.c (CHOOSE_P): New macro. Use p = n/5.
+	(mpn_gcdext): Use CHOOSE_P, and generalized the calculation of
+	scratch space.
+
+	* tune/tuneup.c (tune_hgcd): Use default step factor.
+
+	* mpn/x86_64/gmp-mparam.h: (GCD_DC_THRESHOLD): Reduced from 493 to
+	412.
+
+	* mpn/generic/gcd.c (CHOOSE_P): New macro, to determine the
+	split when calling hgcd. Use p = 2n/3, as that seems better than
+	the more obvious split p = n/2.
+	(mpn_gcd): Use CHOOSE_P, and generalized the calculation of
+	scratch space.
+
+2008-09-16  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/toom_interpolate_7pts.c: Use new mpn_divexact_byN
+	functions.
+
+	* gmp-impl.h (mpn_divexact_by3, mpn_divexact_by5, mpn_divexact_by7,
+	mpn_divexact_by9, mpn_divexact_by11, mpn_divexact_by13,
+	mpn_divexact_by15): New macros, defined in terms of mpn_bdiv_dbm1.
+
+	* configure.in (gmp_mpn_functions): List bdiv_dbm1c.
+	(HAVE_NATIVE): Likewise.
+	* mpn/asm-defs.m4: Define bdiv_dbm1c.
+	* gmp-impl.h (mpn_bdiv_dbm1c): Declare.
+	(mpn_bdiv_dbm1): New macro.
+	* mpn/generic/bdiv_dbm1c.c: New file.
+	* mpn/alpha/bdiv_dbm1c.asm: New file.
+	* mpn/ia64/bdiv_dbm1c.asm: New file.
+	* mpn/powerpc32/bdiv_dbm1c.asm: New file.
+	* mpn/powerpc64/mode64/bdiv_dbm1c.asm: New file.
+	* mpn/x86/bdiv_dbm1c.asm: New file.
+	* mpn/x86_64/bdiv_dbm1c.asm: New file.
+
+	* mpn/generic/diveby3.c: Add mpn_bdiv_dbm1c based function.
+	Choose function depending on DIVEXACT_BY3_METHOD.
+	* gmp-impl.h (DIVEXACT_BY3_METHOD): Provide default.
+
+2008-09-16  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/hgcd.c (mpn_hgcd_addmul2_n): Moved function to
+	gcdext.c, where it is used.
+	* mpn/generic/gcdext.c (addmul2_n): Moved and renamed, was
+	mpn_hgcd_addmul2_n. Made static. Deleted input normalization.
+	Deleted rn argument.
+	(mpn_gcdext): Updated calls to addmul2_n, and added assertions.
+
+	* gmp-impl.h (MPN_HGCD_MATRIX_INIT_ITCH): Increased storage by 4 limbs.
+	(MPN_HGCD_LEHMER_ITCH): Reduced storage by one limb.
+	(MPN_GCD_SUBDIV_STEP_ITCH): Likewise.
+	(MPN_GCD_LEHMER_N_ITCH): Likewise.
+
+	* mpn/generic/hgcd.c (mpn_hgcd_matrix_init): Use two extra limbs.
+	(hgcd_step): Use overlapping arguments to mpn_tdiv_qr.
+	(mpn_hgcd_matrix_mul): Deleted normalization code. Tighter bounds
+	for the element size of the product. Needs two extra limbs of
+	storage for the elements.
+	(mpn_hgcd_itch): Updated storage calculation.
+
+	* mpn/generic/gcd_subdiv_step.c (mpn_gcd_subdiv_step): Use
+	overlapping arguments to mpn_tdiv_qr. Use mpn_zero_p.
+
+	* mpn/generic/gcd.c (mpn_gcd): Use mpn_zero_p.
+
+2008-09-15  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/hgcd.c (mpn_hgcd_matrix_init): Updated for deleted
+	tp pointer.
+	(hgcd_matrix_update_q): Likewise.
+	(mpn_hgcd_matrix_mul): Likewise.
+	(mpn_hgcd_itch): Updated calculation of scratch space.
+
+	* gmp-impl.h (struct hgcd_matrix): Deleted tp pointer.
+	(MPN_HGCD_MATRIX_INIT_ITCH): Reduced storage.
+	(mpn_hgcd_step, MPN_HGCD_STEP_ITCH): Deleted declarations.
+
+2008-09-15  Niels Möller <nisse@lysator.liu.se>  <nisse@king.swox.se>
+
+	* mpn/x86_64/gmp-mparam.h (MATRIX22_STRASSEN_THRESHOLD): New
+	threshold.
+
+	* mpn/generic/hgcd.c (mpn_hgcd_matrix_mul): Use mpn_matrix22_mul.
+	(mpn_hgcd_itch): Updated calculation of scratch space. Use
+	count_leading_zeros to get the recursion depth.
+
+	* mpn/generic/gcd.c (mpn_gcd): Fixed calculation of scratch space,
+	and use mpn_hgcd_itch.
+
+2008-09-15  Niels Möller  <nisse@lysator.liu.se>
+
+	* tune/tuneup.c (tune_matrix22_mul): New function.
+	(all): Use it.
+
+	* tune/common.c (speed_mpn_matrix22_mul): New function.
+
+	* tune/Makefile.am (TUNE_MPN_SRCS_BASIC): Added matrix22_mul.c.
+
+	* tests/mpn/t-matrix22.c: Use MATRIX22_STRASSEN_THRESHOLD to
+	select sizes for tests.
+
+	* gmp-impl.h (MATRIX22_STRASSEN_THRESHOLD): New threshold
+
+	* configure.in (gmp_mpn_functions): Added matrix22_mul.
+	* gmp-impl.h: Added declarations for mpn_matrix22_mul and related
+	functions.
+
+	* mpn/Makefile.am (nodist_EXTRA_libmpn_la_SOURCES): Added
+	matrix22_mul.c.
+	* tests/mpn/Makefile.am (check_PROGRAMS): Added t-matrix22.
+
+	* tests/mpn/t-matrix22.c: New file.
+	* mpn/generic/matrix22_mul.c: New file.
+
+2008-09-11  Niels Möller  <nisse@king.swox.se>
+
+	* tune/tuneup.c: Updated tuning of gcdext.
+
+	* mpn/x86_64/gmp-mparam.h (GCDEXT_DC_THRESHOLD): Reduced threshold
+	from 713 to 409.
+
+2008-09-11  Niels Möller  <nisse@lysator.liu.se>
+
+	* gmp-impl.h: Updated for gcdext changes.
+	(GCDEXT_DC_THRESHOLD): New constant, renamed from
+	GCDEXT_SCHOENHAGE_THRESHOLD.
+
+	* mpn/generic/gcdext.c (compute_v): Accept non-normalized a and b
+	as inputs.
+	(mpn_gcdext): Rewrote and simplified. Now uses the new mpn_hgcd
+	interface.
+
+	* mpn/generic/hgcd.c (mpn_hgcd_addmul2_n): Renamed from addmul2_n
+	and made non-static. Changed interface to take non-normalized
+	inputs, and only two size arguments.
+	(mpn_hgcd_matrix_mul): Simplified using new mpn_hgcd_addmul2_n.
+
+	* mpn/generic/gcdext_lehmer.c (mpn_gcdext_lehmer_itch): Deleted
+	function.
+	(mpn_gcdext_lehmer_n): Renamed from mpn_gcd_lehmer. Now takes
+	inputs of equal size. Moved the code for the division step to a
+	separate function...
+	* mpn/generic/gcdext_subdiv_step.c (mpn_gcdext_subdiv_step): New
+	file, new function.
+
+	* configure.in (gmp_mpn_functions): Added gcdext_subdiv_step.
+
+2008-09-10  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/devel/anymul_1.c: Include <string.h>.
+
+	* gmp-h.in: Unconditionally include <cstdio>.
+
+2008-09-10  Niels Möller  <nisse@lysator.liu.se>
+
+	* tune/common.c: #if:ed out speed_mpn_gcd_binary and
+	speed_mpn_gcd_accel.
+	* tune/speed.c (routine): #if:ed out mpn_gcd_binary, mpn_gcd_accel
+	and find_a.
+	* tune/Makefile.am (libspeed_la_SOURCES): Removed gcd_bin.c
+	gcd_accel.c gcd_finda_gen.c.
+	* tune/tuneup.c: Enable tuning of GCD_DC_THRESHOLD.
+
+	* mpn/generic/gcd.c (mpn_gcd): Rewrote and simplified. Now uses
+	the new mpn_hgcd interface.
+
+	* */gmp-mparam.h: Renamed GCD_SCHOENHAGE_THRESHOLD to
+	GCD_DC_THRESHOLD.
+
+	* mpn/generic/gcd_lehmer.c (mpn_gcd_lehmer_n): Renamed (was
+	mpn_gcd_lehmer). Now takes inputs of equal size.
+
+	* mpn/generic/gcd_lehmer.c (mpn_gcd_lehmer): Reintroduced gcd_2,
+	to get better performance for small inputs.
+
+	* mpn/generic/hgcd.c: Don't hardcode small HGCD_THRESHOLD.
+	* mpn/x86_64/gmp-mparam.h (HGCD_THRESHOLD): Reduced from 145 to
+	120.
+	* */gmp-mparam.h: Renamed HGCD_SCHOENHAGE_THRESHOLD to
+	HGCD_THRESHOLD.
+
+2008-09-09  Torbjorn Granlund  <tege@gmplib.org>
+
+	* doc/gmp.texi: Fix a typo and clarify mpn_gcdext docs.
+
+2008-09-09  Niels Möller  <nisse@lysator.liu.se>
+
+	* tune/common.c (speed_mpn_hgcd, speed_mpn_hgcd_lehmer): Adapted
+	to new hgcd interface.
+
+	* gmp-impl.h (MPN_HGCD_LEHMER_ITCH): New macro.
+
+	* hgcd.c (mpn_hgcd_lehmer): Renamed function, from hgcd_base. Made
+	non-static.
+
+	* gcd_lehmer.c (mpn_gcd_lehmer): Use hgcd2 also for n == 2.
+
+	* gcdext_lehmer.c (mpn_gcdext_lehmer): Simplified code for
+	division step. Added proper book-keeping of swaps, which affect
+	the sign of the returned cofactor.
+
+	* tests/mpz/t-gcd.c (one_test): Display co-factor when mpn_gcdext
+	fails.
+
+	* gcd_lehmer.c (mpn_gcd_lehmer): At end of loop, need to handle
+	the special case n == 1 correctly.
+
+	* gcd_subdiv_step.c (mpn_gcd_subdiv_step): Simplified function.
+	The special cancellation logic is not needed here.
+
+2008-09-08  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/invert.c: Add working but slow code.
+
+	* mpn/x86_64/x86_64-defs.m4 (R32, R8): New macros.
+
+	* mpn/ia64/submul_1.asm: Move some labels for broader assembler
+	compatibility.
+
+	* gmp-impl.h (mpn_mul_3, mpn_mul_4): Declare.
+	* tests/tests.h (refmpn_mul_3, refmpn_mul_4): Declare.
+	* tests/try.c (param_init): Set things up for mpn_mul_3 and mpn_mul_4.
+	(choice_array): Likewise.
+	(call): Likewise.
+	* mpn/Makefile.am (nodist_EXTRA_libmpn_la_SOURCES):
+	Add mul_3.c and mul_4.
+	* mpn/asm-defs.m4: Define mul_3 and mul_4.
+	* tests/refmpn.c (refmpn_mul_N): New function.
+	(refmpn_mul_2): Remove old definition, call refmpn_mul_N.
+	(refmpn_mul_3, refmpn_mul_4): New functions.
+	* tune/common.c (speed_mpn_mul_3, speed_mpn_mul_4): New functions.
+	* tune/speed.h (speed_mpn_mul_3, speed_mpn_mul_4): Declare.
+	* tune/speed.c (routine): New entries for mpn_mul_2 and mpn_mul_3.
+
+	* ltmain.sh: Update to libtool 1.5.24.
+
+	* mpn/generic/mul_toom22.c: Compute s and t more cleverly.
+
+2008-09-08  Niels Möller  <nisse@lysator.liu.se>
+
+	* tests/mpn/t-hgcd.c: Updated tests. Rewrite of hgcd_ref.
+
+	* mpn/generic/gcdext_lehmer.c (mpn_gcdext_lehmer_itch): New function.
+	(mpn_gcdext_lehmer): Various bugfixes.
+
+	* gcdext.c (mpn_gcdext): Allocate scratch space for gcdext_lehmer.
+
+	* mpn/generic/gcd_lehmer.c (gcd_2): ASSERT that inputs are odd.
+	(mpn_gcd_lehmer): Added tp argument, for scratch space. Make both
+	arguments odd before calling gcd_2.
+
+	* mpn/generic/hgcd.c (mpn_hgcd): Allow the trivial case n <= 2,
+	and return 0 immediately.
+
+	* gmp-impl.h (MPN_EXTRACT_NUMB): New macro.
+
+	* configure.in (gmp_mpn_functions): Added gcdext_lehmer.
+
+2008-09-05  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/toom_interpolate_7pts.c: Use mpn_divexact_by3c instead of
+	divexact_odd.
+
+	* doc/texinfo.tex: Update to 2007-06-29.13.
+
+	* doc/gmp.texi: Update GMP site URL.  Fix some typos.
+
+	* demos/pexpr.c (main): Allow bases up to 62.
+
+	* gmp-impl.h: Remove formal parameter names from function prototypes.
+
+	* config.guess: Recognize recent AMD and Itanium CPUs.
+	Default X86 CPU recognition to configfsf.guess' value.
+
+	* configure.in: Handle core2 separately from athlon64.
+
+2008-09-05  Niels Möller  <nisse@lysator.liu.se>
+
+	* */Makefile.in, configure, aclocal.m4, config.in: Removed files
+	from repository. They're instead generated by automake and
+	autoconf before distribution.
+
+2008-08-25  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpf/set_str.c: Allocate mantissa space based on mantissa size,
+	not on destination variable space.
+	* mpf/set_str.c: Accept unary plus before exponent.
+
+2008-08-06  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/mul_toom22.c: Add statistics gathering functionality,
+	triggered by cpp predef STAT.
+
+	From David Harvey:
+	* mpn/generic/mul_toom22.c: Decrease scratch space usage.
+
+2008-08-02  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/misc/t-scanf.c: Avoid negative arguments to _ui functions.
+	* tests/misc/t-printf.c: Likewise.
+
+	* acinclude.m4 (X86_PATTERN): Add geode.
+
+	* acinclude.m4 (CL_AS_NOEXECSTACK): Avoid -q flag to grep.
+
+2008-08-01  Torbjorn Granlund  <tege@gmplib.org>
+
+	* acinclude.m4 (CL_AS_NOEXECSTACK): New.
+	* configure.in: Use CL_AS_NOEXECSTACK.
+	* mpn/Makeasm.am: Use ASM_FLAGS (defined by CL_AS_NOEXECSTACK).
+
+	* gmpxx.h (__GMP_DBL_LIMBS): Use DBL_MAX_EXP instead of
+	std::numeric_limits<double>::max_exponent for better portability.
+
+2008-07-29  Torbjorn Granlund  <tege@gmplib.org>
+
+	* gmpxx.h (__GMP_DBL_LIMBS): New #define.
+	(__GMP_ULI_LIMBS): New #define.
+	(__GMPXX_TMP_UI): New macro.
+	(__GMPXX_TMP_SI): New macro.
+	(__GMPXX_TMP_D): New macro.
+	(struct __gmp_binary_and): Rewrite, using the new macros.
+	(struct __gmp_binary_ior): Likewise.
+	(struct __gmp_binary_xor): Likewise.
+
+2008-07-28  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/cxx/t-binary.cc: Add some tests for logical operations.
+
+2008-07-24  Torbjorn Granlund  <tege@gmplib.org>
+
+	* gmpxx.h: Use __GMPZ_* instead of __GMPZZ_* for bitwise ops, remove
+	__GMPZZ_*.
+	Remove repeated #undefs.
+	(__gmp_alloc_cstring): Declare freefunc as extern "C".
+
+2008-07-23  Torbjorn Granlund  <tege@gmplib.org>
+
+	* gmp-h.in (__GMP_CC): New define, undocumented for now.
+	(__GMP_CFLAGS): Likewise.
+
+2008-07-21  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/amd64check.c: Fix a printf type clash.
+
+	* mpz/realloc.c: Amend last fix.
+
+	* gmp-h.in: Include <cstdlib> for C++.
+	* gmp-h.in: Handle new gcc 4.3 inline semantics defaults.
+
+	* configfsf.guess: Update to version of 2008-04-14.
+	* configfsf.sub: Update to version of 2008-06-16.
+
+	* configure.in: Separate core2 and athlon64 flags handling.
+
+2008-06-19  Torbjorn Granlund  <tege@gmplib.org>
+
+	* config.guess: Recognize pentiumm and AMD geode.
+	* config.sub: Likewise.
+	* configure.in: Likewise.
+
+2008-06-02  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.in: Disallow odd nails sizes.
+	* configure.in: Inherit default gcc_cflags/gcc_64_cflags everywhere.
+
+2008-05-23  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpz/init2.c: Rewrite to avoid internal overflow and to detect mpz_t
+	overflow.
+	* mpz/realloc2.c: Likewise.
+	* mpz/realloc.c: Detect mpz_t overflow.
+
+2008-05-22  Torbjorn Granlund  <tege@gmplib.org>
+
+	* configure.in (sparc): Remove -fast, it causes documented
+	miscompilation.
+
+	* config.guess: Properly handle the "extended" variants of x86 cpuid.
+
+2008-05-09  Torbjorn Granlund  <tege@gmplib.org>
+
+	* gmp-impl.h (mpn_mul_fft): Now void.
+	(udiv_qrnnd_preinv3): Special case for constant (nl).
+
+2008-05-08  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/generic/mul_fft.c: Clean up types in TRACE (printf (...)).
+	(TRACE): Redefine to allow command line control.
+	(mpn_mul_fft_internal): Now void, remove return value.
+	(mpn_mul_fft): Likewise.
+	(MPN_FFT_TABLE2_SIZE): Up size fro 256 to 512.
+	(mpn_fft_fft): Call mpn_fft_mul_2exp_modF just once instead of twice,
+	then add/subtract result.  Get rid of temp allocation as a result.
+	Remove some redundant CNST_LIMB.
+	(mpn_fft_fftinv): Analogous changes.
+	(mpn_fft_sub_modF): Re-enable, now needed by mpn_fft_fft and
+	mpn_fft_fftinv.
+
+2008-03-10  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/mpz/t-mul.c (main): Let GMP_CHECK_FFT mean largest allowed
+	power-of-2 of test operands.
+
+2008-02-28  Torbjorn Granlund  <tege@gmplib.org>
+
+	* tests/cxx/t-binary.cc (check_mpz): Expect floor rounding for right
+	shift.
+
+2008-02-27  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpz/mul_i.h: Check sml's size (not the signed small_mult).
+
+	* longlong.h (umul_ppmm) [alpha]: Define using __builtin_alpha_umulh
+	when possible.
+
+	* longlong.h (count_trailing_zeros): Force destination register mode.
+
+	* gmpxx.h (struct __gmp_binary_rshift): Use floor rounding, not
+	truncation.
+
+	* gmpxx.h (__gmp_binary_and, __gmp_binary_ior, __gmp_binary_xor):
+	Add variants with unsigned long int argument.
+
+	* config.sub: Recog geode.
+	* config.guess: Likewise.
+	* acinclude.m4 (X86_PATTERN): Likewise.
+
+2008-02-10  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86/p6/aors_n.asm: Use Zdisp to work around GNU as bug.
+	* mpn/x86/x86-defs.m4 (Zdisp): Add more instructions.
+
+2008-02-08  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86_64/aors_n.asm: New file.
+	* mpn/x86_64/add_n.asm: Delete.
+	* mpn/x86_64/sub_n.asm: Delete.
+
+2008-02-07  Torbjorn Granlund  <tege@gmplib.org>
+
+	* mpn/x86/k6/mmx/dive_1.asm: Fix typo in last change.
+
+2007-12-10  Torbjorn Granlund  <tege@swox.com>
+
+	* mpf/set_str.c (mpf_set_str): Write own code for converting the
+	exponent, avoids strtol base < 36 limitation.
+
+2007-10-28  Torbjorn Granlund  <tege@swox.com>
+
+	* gmp-impl.h (mpn_dc_get_str_itch): New macro.
+	(mpn_dc_get_str_powtab_alloc): New macro.
+	(struct powers): Add field "shift".
+
+	* mpn/generic/get_str.c: Compute powers without low zero limbs; all
+	functions modified.  Correct temporary allocation.  Misc cleanups.
+
+	* mpn/generic/set_str.c: Compute powers without low zero limbs; all
+	functions modified.
+	(mpn_dc_set_str): Remove impossible case, replace by an ASSERT.
+
+2007-10-26  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/set_str.c: Remove default thresholds, not in gmp-impl.h.
+	(mpn_dc_set_str): Insert ASSERT_ALWAYS in a presumably dead code arm.
+
+2007-10-22  Torbjorn Granlund  <tege@swox.com>
+
+	* gmp-impl.h (mpn_add_nc): Define as inline function, unless NATIVE.
+	(mpn_sub_nc): Likewise.
+
+2007-10-17  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/misc/t-printf.c: Fix a printf type clash.
+	* tests/mpq/t-get_str.c: Likewise.
+	* tests/mpz/t-import.c: Likewise.
+
+	* acinclude.m4: Conditionally disable some tests when compiled by a C++
+	compiler.
+
+	* gmp-impl.h (udiv_qrnnd_preinv3): Remove an unused variable.
+
+	* mpn/generic/hgcd.c: Add some WANT_ASSERTs to shut up warnings.
+
+2007-10-08  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc64/elf.m4 (LEAL): Define as an alias for LEA.
+	* mpn/powerpc32/darwin.m4 (LEAL): Likewise.
+	* mpn/powerpc64/aix.m4: Likewise.
+
+	* mpn/powerpc64/vmx/popcount.asm: Use LEAL.
+
+	* mpn/powerpc64/darwin.m4 (LEAL): New name for LEA, since it is only
+	usable for local symbols.
+	(LEA): Replace with code for external references.
+
+	* mpn/powerpc32/vmx/mod_34lsub1.asm: Use LEAL.
+
+2007-10-07  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/x86/dive_1.asm: Use LEA, remove explicit movl_eip_*.
+	* mpn/x86/k6/mode1o.asm: Likewise.
+	* mpn/x86/k6/mmx/dive_1.asm: Likewise.
+	* mpn/x86/k7/dive_1.asm: Likewise.
+	* mpn/x86/k7/mode1o.asm: Likewise.
+	* mpn/x86/p6/dive_1.asm: Likewise.
+	* mpn/x86/p6/mode1o.asm: Likewise.
+	* mpn/x86/pentium4/sse2/dive_1.asm: Likewise.
+	* mpn/x86/pentium4/sse2/mode1o.asm: Likewise.
+	* mpn/x86/pentium4/sse2/popcount.asm: Likewise.
+
+	* mpn/x86/p6/aors_n.asm: Table cycle counts.
+
+	* mpn/x86/k7/mod_34lsub1.asm: Fix over-optimistic cycle count claims.
+
+	* mpn/x86/x86-defs.m4 (DEF_OBJECT, END_OBJECT): New define's.
+
+	* mpn/x86/darwin.m4 (LEA): Put also movl_eip_XX into EPILOGUE_cpu.
+	Expect target register to have prepended %.
+
+	* mpn/x86_64/add_n.asm: Use L() for labels.
+	* mpn/x86_64/addlsh1_n.asm: Likewise.
+	* mpn/x86_64/addmul_2.asm: Likewise.
+	* mpn/x86_64/aorrlsh_n.asm: Likewise.
+	* mpn/x86_64/aorsmul_1.asm: Likewise.
+	* mpn/x86_64/com_n.asm: Likewise.
+	* mpn/x86_64/copyd.asm: Likewise.
+	* mpn/x86_64/copyi.asm: Likewise.
+	* mpn/x86_64/diveby3.asm: Likewise.
+	* mpn/x86_64/logops_n.asm: Likewise.
+	* mpn/x86_64/lshsub_n.asm: Likewise.
+	* mpn/x86_64/mul_1.asm: Likewise.
+	* mpn/x86_64/mul_2.asm: Likewise.
+	* mpn/x86_64/mul_basecase.asm: Likewise.
+	* mpn/x86_64/popham.asm: Likewise.
+	* mpn/x86_64/redc_1.asm: Likewise.
+	* mpn/x86_64/rsh1add_n.asm: Likewise.
+	* mpn/x86_64/rsh1sub_n.asm: Likewise.
+	* mpn/x86_64/rshift.asm: Likewise.
+	* mpn/x86_64/sub_n.asm: Likewise.
+	* mpn/x86_64/sublsh1_n.asm Likewise.
+	* mpn/x86_64/pentium4/aors_n.asm: Likewise.
+	* mpn/x86_64/pentium4/lshift.asm: Likewise.
+	* mpn/x86_64/pentium4/rshift.asm: Likewise.
+
+	* mpn/x86_64/x86_64-defs.m4: New file, defining LEA, DEF_OBJECT, and
+	END_OBJECT.
+
+	* mpn/generic/mul.c: Put TMP_DECL as last decl.
+
+2007-10-06  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/x86/pentium4/sse2/popcount.asm: New file.
+
+2007-09-26  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/get_str.c: Cast a char index to int to shut up compilers.
+
+	* mpn/generic/dc_div_qr.c: Pass dummy scratch argument to mpn_invert.
+	* mpn/generic/dc_divappr_q.c: Likewise.
+	* mpn/generic/mu_div_qr.c: Likewise.
+	* mpn/generic/mu_divappr_q.c: Likewise.
+	* mpn/generic/mu_div_q.c: Likewise.
+	* mpn/generic/divexact.c: Likewise.
+
+	* mpn/generic/invert.c: New file, placeholder for now.
+
+2007-09-24  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/toom_interpolate_5pts.c: New file, contents from
+	mpn/generic/mul_n.c
+	* mpn/generic/mul_n.c (mpn_toom3_interpolate): Function removed.
+
+	* mpn/generic/toom_interpolate_7pts.c: New file.
+
+	* mpn/x86/k7/mmx/popham.asm: Table cycle counts.
+
+	* mpn/x86/k6/README: Update URLs.
+
+	* mpn/powerpc32/README: Update URL's, company names.
+
+	* mpn/generic/get_d.c: Complete rewrite.
+
+	* mpn/generic/mul_toom33.c: New file.
+
+	* mpn/generic/mul_toom22.c: Make orthogonal with other toomXY files.
+	* mpn/generic/mul_toom32.c: Likewise.
+	* mpn/generic/mul_toom42.c: Likewise.
+
+	* mpn/alpha/invert_limb.asm: Update cycle counts.  Fix a comment typo.
+
+	* mpf/get_str.c: Include stdlib.h, not stdio.h for NULL.
+
+	* doc/gmp.texi: Fix a typo.
+
+	* memory.c (__gmp_default_allocate, __gmp_default_reallocate):
+	Cast size operands in error fprintf's.
+
+	* longlong.h (sub_ddmmss) [powerpc 64]: Add more variants for constant
+	args.
+
+	* gmp-impl.h (udiv_qrnnd_preinv3): New define.
+	* gmp-impl.h (ULONG_PARITY): Exclude masquerading __INTEL_COMPILER from
+	ia64 asm.
+
+	* gmp-h.in (mpn_neg_n): New function.
+
+2007-09-18  Torbjorn Granlund  <tege@swox.com>
+
+	* demos/pexpr.c (main): Add -v option.
+	(enum op_t): New tag TIMING.
+	(mpz_eval_expr): Execute TIMING.
+	(fns): Add TIMING entry.
+
+	* gmp-impl.h: Add decls and THRESHOLDs for new toom multiplication
+	functions and division functions.
+
+2007-09-10  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc32/addlsh1_n.asm: Use L() for labels.
+	* mpn/powerpc32/sublsh1_n.asm: Likewise.
+
+2007-09-09  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/x86/x86-defs.m4 (LEA): New define.
+	* mpn/x86/darwin.m4: New file, for now just defining LEA.
+	* configure.in: Pick up x86/darwin.m4.
+	* mpn/x86/*: Use LEA for PIC references.
+
+	* configure.in: For X86/32, treat core2 like pentium3.
+
+2007-09-06  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/amd64check.c (calling_conventions_values): Put constants,
+	dynamic values in this array (was in scalars).
+	(calling_conventions_check): Corresponding changes.
+	* tests/amd64call.asm: Rewrite to be PIC, smaller, using amd64check.c's
+	array.
+
+2007-09-04  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/x86/pentium4/sse2/mul_basecase.asm: Misc cleanups.
+	* mpn/x86/pentium4/sse2/sqr_basecase.asm: Likewise.
+
+	* mpn/x86_64/mod_34lsub1.asm: Optimize loop, reduce code size.
+
+	* tests/amd64call.asm: Remove bogus no-op moves.
+
+2007-09-03  Torbjorn Granlund  <tege@swox.com>
+
+	From Richard Guenther:
+	* gmp-h.in (__GMP_EXTERN_INLINE): Declare conditionally on
+	__GNUC_STDC_INLINE__.
+
+	* tests/cxx/t-locale.cc: #include <cstdlib>, for abort.
+
+	* mpn/x86_64/core2/popcount.asm: New file.
+	* mpn/x86_64/pentium4/popcount.asm: New file.
+
+	* mpn/x86_64/addmul_2.asm: New file.
+	* mpn/x86_64/mul_2.asm: New file.
+
+	* mpn/x86_64/aorsmul_1.asm: Use 32-bit mov for zeroing registers
+	(saves space).
+
+2007-09-01  Torbjorn Granlund  <tege@swox.com>
+
+	* configure.in: Handle athlon64, core2, and pentium4 separately for
+	64-bit ABI.
+
+	* config.sub: Recog athlon64, core2, and opteron.
+
+	* config.guess: Do two x86 variants, for 32-bit ABI and 64-bit ABI.
+	Return "athlon64" and "core2", not x86_64.
+
+2007-08-31  Torbjorn Granlund  <tege@swox.com>
+
+	From Patrick Pelissier:
+	* gmp-h.in: Don't refer to FILE from C++ unless we've seen FILE.
+
+2007-08-30  Torbjorn Granlund  <tege@swox.com>
+
+	* demos/isprime.c: Include string.h for strcmp.
+
+	* demos/factorize.c (main): Declare to int.
+
+2007-06-22  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/x86_64/pentium4/lshift.asm: Minor tuning.
+	* mpn/x86_64/pentium4/rshift.asm: Likewise.
+
+2007-05-30  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc64/mode64/aors_n.asm: Add _nc entry points.
+
+2007-05-22  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/memory.c: Cast calls to new mem* calls to avoid unaligned ops.
+
+2007-05-16  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/mpz/convert.c: Tweak operand sizes for best coverage.
+
+	* tests/memory.c: Add red zones around allocations.
+
+2007-05-15  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/ia64/mul_1.asm: Make mul_1c entry point actually work.
+
+	* mpn/generic/set_str.c (mpn_dc_set_str): Avoid calling mpn_add_n when
+	ln == 0.
+
+	* tests/mpz/convert.c (string_urandomb): New function.
+	(main): Use it by enabling ifdef'ed out code.
+
+2007-04-30  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/x86_64/mul_basecase.asm: Complete rewrite.
+
+	* mpn/x86_64/copyi.asm: Use short shift-by-one form.  Misc cleanups.
+	* mpn/x86_64/copyi.asm: Likewise.
+	* mpn/x86_64/popham.asm: Likewise.
+
+	* mpn/x86_64/aorsmul_1.asm: Cleanup formatting.
+
+2007-04-25  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/divexact.c: Handle undefined case of |N| < |D| to avoid segfaults.
+
+2007-02-24  Torbjorn Granlund  <tege@swox.com>
+
+	* doc/gmp.texi (Toom 3-Way Multiplication): Fix typo.
+	(mpz_scan0, mpz_scan1): Fix typos.
+	(Float Internals): Rewrite paragraph about struct types.
+
+2007-02-12  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/x86/pentium4/sse2/sqr_basecase.asm: Complete rewrite (except
+	diagonal code).
+
+2007-02-05  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/mul_fft.c (mpn_fft_fft): New name for mpn_fft_fft_sqr,
+	old mpn_fft_fft removed.
+	(mpn_mul_fft_internal): Call mpn_fft_fft separately for each operand.
+	(mpn_fft_add_modF): Rewrite to avoid random branches.
+	(mpn_fft_sub_modF): Likewise.
+
+	* mpn/x86/pentium4/sse2/addmul_1.asm: Complete rewrite.
+	* mpn/x86/pentium4/sse2/mul_1.asm: Complete rewrite.
+	* mpn/x86/pentium4/sse2/mul_basecase.asm: Complete rewrite, based on
+	new addmul and mul code.
+
+2007-01-31  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/get_str.c (mpn_sb_get_str): Get loop count for frac
+	development right.
+
+	* mpn/powerpc32/vmx/mod_34lsub1.asm: New file.
+
+	* mpn/powerpc32/aors_n.asm: New file, complete rewrite.
+	* mpn/powerpc32/add_n.asm: Remove.
+	* mpn/powerpc32/sub_n.asm: Remove.
+
+2007-01-25  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/x86_64/core2/aors_n.asm: Add _nc entry points, minor cleanups.
+
+	* mpn/x86_64/core2/lshift.asm: Rewrite.
+	* mpn/x86_64/core2/rshift.asm: Rewrite.
+
+	* mpn/x86_64/pentium4/lshift.asm: Swap some loop insns for a small
+	speedup.
+	* mpn/x86_64/pentium4/rshift.asm: New file, based on lshift.asm.
+
+	* mpn/x86_64/pentium4/gmp-mparam.h: New file.
+
+	* mpn/x86_64/pentium4/aors_n.asm: Complete rewrite of add/subtract
+	code.
+	* mpn/x86_64/pentium4/add_n.asm: Remove.
+	* mpn/x86_64/pentium4/sub_n.asm: Remove.
+
+2007-01-20  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/x86_64/lshift.asm: Add special case for cnt=1.
+
+2007-01-19  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/x86_64/aorsmul_1.asm: New file, written from scratch, finally at
+	3.0 c/l on K8 (addmul_1 was 3.3; submul_1 was 3.5).
+	* mpn/x86_64/addmul_1.asm: Remove.
+	* mpn/x86_64/submul_1.asm: Remove.
+
+2006-12-29  Torbjorn Granlund  <tege@swox.com>
+
+	* randmt.c (__gmp_randclear_mt): Initialize ALLOC field, like in
+	__gmp_randinit_mt_noseed.
+	(__gmp_randclear_mt, __gmp_randinit_mt_noseed): Make similar functions
+	look similar.
+	(__gmp_randclear_mt): Pass actually allocated size.
+
+	* mpn/Makefile.am (nodist_EXTRA_libmpn_la_SOURCES): Add mul_toom22.c,
+	mul_toom32.c, mul_toom42.c.
+
+	* configure.in: Recognize athlon64 and core2 as alternatives to x86_64.
+	Provide special settings for core2.
+
+	* configure.in (gmp_mpn_functions): Add mul_toom22, mul_toom32,
+	mul_toom42.
+
+	* mpn/generic/mul_toom22.c: New file.
+	* mpn/generic/mul.c: Use mpn_mul_toom22.  Trim cutoff points between
+	the mpn_mul_toomN2 functions.  Handle balanced operands at function
+	entry.
+
+2006-12-29  Marco Bodrato  <bodrato@mail.dm.unipi.it>
+
+	* mpn/generic/mul_n.c: Rewrite interpolation code.
+
+2006-12-28  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/mul_toom32.c: New file.
+	* mpn/generic/mul_toom42.c: New file.
+	* mpn/generic/mul.c: Use mpn_mul_toom32 and mpn_mul_toom42 for
+	unbalanced operands.
+
+2006-12-17  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/x86_64/aorrlsh_n.asm: New file.
+	* mpn/x86_64/lshsub_n.asm: New file.
+
+	* mpn/x86_64/core2/aors_n.asm: New file.
+	* mpn/x86_64/core2/lshift.asm: New file.
+	* mpn/x86_64/core2/rshift.asm: New file.
+
+	* mpn/x86/p6/aors_n.asm: Replace K7 grabbing code with P6 specific
+	code.
+
+	* mpn/x86/p6/lshsub_n.asm: New file.
+
+2006-11-23  Torbjorn Granlund  <tege@swox.com>
+
+	* tune/speed.h (SPEED_ROUTINE_MPN_MUL_BASECASE): Allocate space for xp
+	locally, s->xp might be insufficient.
+
+2006-11-22  Torbjorn Granlund  <tege@swox.com>
+
+	* randmt.c (__gmp_randinit_mt_noseed): Initialize ALLOC field of result
+	param.
+
+2006-11-06  Torbjorn Granlund  <tege@swox.com>
+
+	* tune/set_strp.c: New file.
+
+2006-11-04  Torbjorn Granlund  <tege@swox.com>
+
+	* extract-dbl.c: Rewrite to handle nails better, and for general
+	optimization.
+
+	* mpz/bin_uiui.c: Simplify.
+
+	* longlong.h (umul_ppmm) [mmix]: New.
+
+	* tune/tuneup.c, tune/common.c, tune/speed.c, tune/speed.h,
+	tune/set_strb.c, tune/set_strs.c: Add tuning and speed measurements
+	of separate SET_STR_DC_THRESHOLD and SET_STR_PRECOMPUTE_THRESHOLD.
+	Add tuning and speed measurement of mpn_addsub_n.
+
+2006-10-31  Torbjorn Granlund  <tege@swox.com>
+
+	* gmpxx.h: Remove ternary stuff, it is hardly an optimization and it
+	writes to destination before reading all source operands.
+
+2006-10-25  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/set_str.c: Complete rewrite.
+	* mpn/generic/get_str.c: Likewise.
+
+	* gmp-impl.h (struct powers, powers_t): New types.
+	Restructure GET_STR_* and SET_STR_* thresholds.
+
+2006-09-21  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/rootrem.c: Remove some redundant casts.
+
+2006-07-12  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/alpha/ev6/nails/addmul_2.asm: Make it run at claimed speed.
+	* mpn/alpha/ev6/nails/addmul_4.asm: Likewise.
+
+	* mpf/get_str.c: Avoid copying result when not needed.  Misc cleanups.
+
+	* tests/amd64call.asm: Use jmp instead of jmpq to placate Solaris.
+
+2006-06-30  Torbjorn Granlund  <tege@swox.com>
+
+	* configure.in (powerpc-*): Remove repeated path component.
+
+2006-06-15  Torbjorn Granlund  <tege@swox.com>
+
+	* configure.in: (ia64-*-linux*): Don't use -O3.
+
+2006-06-14  Torbjorn Granlund  <tege@swox.com>
+
+	* mpq/get_str.c: Fix upper base limit boundary in an ASSERT.
+
+	* tests/refmpn.c (refmpn_sb_divrem_mn): Use ASSERT_CARRY for add-back.
+
+2006-05-31  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/mpz/t-set_d.c (check_data): Add more data points.
+
+	* mpz/set_d.c: Handle negative return values from __gmp_extract_double.
+
+2006-05-17  Torbjorn Granlund  <tege@swox.com>
+
+	* configure.in: Clear out gcc_cflags_cpu and gcc_cflags_arch for a fat
+	build.
+
+2006-05-16  Torbjorn Granlund  <tege@swox.com>
+
+	* demos/primes.c (find_primes): Increase mpz_probab_prime_p cnt to 10.
+
+	* mpn/generic/addsub_n.c: Fix criteria for when to call _nc functions.
+
+2006-05-12  Torbjorn Granlund  <tege@swox.com>
+
+	* config.guess: Recognize more ppc processor types.
+
+2006-05-11  Torbjorn Granlund  <tege@swox.com>
+
+	* tune/speed.c (usage): Update URL for gnuplot and quickplot.
+
+2006-05-10  Torbjorn Granlund  <tege@swox.com>
+
+	* configure.in (powerpc-*-*): Pass -maltivec to assembler for
+	appropriate CPUs.
+
+2006-05-08  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc32/aix.m4 (LEA): Remove [RW] attribute.
+
+2006-05-03  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc64/vmx/popcount.asm: Conditionally zero extend n.
+
+2006-04-27  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/divexact.c: Call mpz_tdiv_q for large operands.
+
+	* configure.in (powerpc-*-darwin): Remove -fast, it affects PIC.
+
+2006-04-26  Torbjorn Granlund  <tege@swox.com>
+
+	* config.guess: Try to recognize Ultrasparc T1 (as ultrasparct1).
+	* config.sub: Handle ultrasparct1.
+
+2006-04-25  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/sparc64/gmp-mparam.h: Retune, without separation of GNUC and
+	non-GNUC data.
+
+2006-04-20  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/mpz/convert.c: Increase operands range.
+
+2006-04-19  Torbjorn Granlund  <tege@swox.com>
+
+	* configure.in: Support powerpc eABI.
+	* mpn/powerpc32/eabi.m4: New file.
+
+	* configure.in: Support powerpc *bsd.
+	* mpn/powerpc64/elf.m4: New name for mpn/powerpc64/linux64.m4.
+	* mpn/powerpc32/elf.m4: New name for mpn/powerpc32/linux.m4.
+
+	* mpn/powerpc64/linux64.m4 (ASM_END): Quote TOC_ENTRY.
+
+2006-04-18  Torbjorn Granlund  <tege@swox.com>
+
+	* configure.in (gmp_mpn_functions_optional): Add lshiftc.
+	(HAVE_NATIVE): Add lshiftc.
+
+	* mpn/powerpc64/mode64/invert_limb.asm: Use LEA, not LDSYM.
+	* mpn/powerpc64/mode64/mode1o.asm: Likewise.
+	* mpn/powerpc64/mode64/dive_1.asm: Likewise.
+
+	* mpn/powerpc64/linux64.m4 (TOC_ENTRY): Define to empty.
+	* mpn/powerpc64/aix.m4 (TOC_ENTRY): Likewise.
+	* mpn/powerpc32/aix.m4 (TOC_ENTRY): Likewise.
+
+	* mpn/powerpc32/aix.m4 (EXTERN): New, copied form powerpc64/aix.m4.
+	* mpn/powerpc32/mode1o.asm: Use EXTERN.
+	* mpn/powerpc32/linux.m4 (EXTERN): Provide dummy definition.
+	* mpn/powerpc32/darwin.m4 (EXTERN): Likewise.
+
+2006-04-13  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/mul_fft.c: Use new thresholds mechanism if MUL_FFT_TABLE2
+	is defined.
+	(mpn_lshiftc): New name for mpn_lshift_com (for consistency with some
+	stuff already in 4.1.4.
+	(mpn_fft_mul_2exp_modF): Reorganize initial operand reductions to avoid
+	divisions.
+
+	* tests/devel/try.c (choice_array): Add mpn_addsub_n[c].
+
+2006-04-11  Torbjorn Granlund  <tege@swox.com>
+
+	* aclocal.m4: Regenerate with patched libtool.
+
+	* mpn/asm-defs.m4 (ASM_END): Provide (empty) default.
+
+2006-04-08  Torbjorn Granlund  <tege@swox.com>
+
+	* configure.in (gmp_mpn_functions_optional): Add addsub.
+
+	* gmpxx.h: Remove missed MPFR references.
+
+	* gmp-impl.h (LIMBS_PER_DOUBLE): Adjust formula to not be pessimistic.
+
+	* gmp-impl.h (TMP_*, WANT_TMP_DEBUG): Don't expect marker argument;
+	define TMP_SALLOC and TMP_BALLOC.
+
+	* mpn/minithres/gmp-mparam.h: New file.
+
+	* tests/mpz/t-io_raw.c: Fix printf type/arg mismatches.
+	* tests/mpz/t-export.c: Likewise.
+	* tests/mpz/io.c: Likewise.
+	* tests/t-constants.c: Likewise.
+
+	* mpn/ia64/popcount.asm: Append "cond.dptk" to conditional branches to
+	placate icc.
+	* mpn/ia64/hamdist.asm: Likewise.
+	* mpn/ia64/lorrshift.asm: Likewise.
+	* mpn/ia64/dive_1.asm: Likewise.
+
+2006-04-05  Torbjorn Granlund  <tege@swox.com>
+
+	* tal-notreent.c (__gmp_tmp_mark): Add "struct" tag for tmp_marker.
+	(__gmp_tmp_free): Likewise.
+
+	* mpn/generic/mul_fft.c: Optimize many scalar divisions and mod
+	operations into masks and shifts.
+	(mpn_fft_mul_modF_K): Fix a spurious ASSERT_NOCARRY.
+
+2006-03-26  Torbjorn Granlund  <tege@swox.com>
+
+	* Version 4.2 released.
+
+	* mpn/powerpc64/aix.m4 (LEA): Renamed from LDSYM.
+	* mpn/powerpc64/darwin.m4: Likewise.
+	* mpn/powerpc64/linux64.m4: Likewise.
+	* mpn/powerpc64/vmx/popcount.asm: Use LEA, not LDSYM.
+
+2006-03-23  Torbjorn Granlund  <tege@swox.com>
+
+	* gmp-impl.h: (class gmp_allocated_string): Prefix strlen with std::.
+
+	* gmpxx.h (__GMP_DEFINE_TERNARY_EXPR2): Remove for now.
+	(struct __gmp_ternary_addmul2): Likewise.
+	(struct __gmp_ternary_submul2): Likewise.
+
+	* gmpxx.h: #include <cstring>.
+	(struct __gmp_alloc_cstring): Prefix strlen with std::.
+
+	* mpn/x86/pentium/com_n.asm: Add TEXT and ALIGN.
+	* mpn/x86/pentium/copyi.asm: Likewise.
+	* mpn/x86/pentium/copyd.asm: Likewise.
+
+2006-03-22  Torbjorn Granlund  <tege@swox.com>
+
+	* gmp-h.in: Add a "using std::FILE" for C++.
+	(_GMP_H_HAVE_FILE): Check also _ISO_STDIO_ISO_H.
+
+	* gmpxx.h: Remove mpfr code.
+	* tests/cxx: Likewise.
+
+	* gmp-impl.h (FORCE_DOUBLE): Rename a tempvar to avoid a clash with
+	GNU/Linux public include file.
+
+	* configure.in (powerpc64, darwin): New optional, gcc_cflags_subtype.
+	Grab powerpc32/darwin.m4 for ABI=mode32.
+
+	* configure.in: Use host_cpu whenever just the cpu type is needed.
+
+2006-03-08  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/get_si.c: Fix a typo.
+
+	* tests/mpq/t-get_d.c (check_random): Improve random generation for
+	nails.
+
+2006-02-28  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/mpq/t-get_d.c (check_random): New function.
+	(main): Call check_random.
+
+	* mpq/set_d.c: Make choices based on LIMBS_PER_DOUBLE, not
+	BITS_PER_MP_LIMB.  Make it work for LIMBS_PER_DOUBLE == 4.
+	Use MPZ_REALLOC.
+
+	* mpz/set_d.c: Make it work for LIMBS_PER_DOUBLE == 4.
+
+	* extract-dbl.c: Make it work for LIMBS_PER_DOUBLE > 3.
+
+2006-02-27  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/cmp_d.c: Declare `i'.
+	* mpz/cmpabs_d.c: Likewise.
+
+2006-02-23  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc32/vmx/copyd.asm: Set right VRSAVE bits.
+	* mpn/powerpc32/vmx/copyi.asm: Likewise.
+
+2006-02-22  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc32/vmx/logops_n.asm: New file.
+
+	* mpn/powerpc32/diveby3.asm: Rewrite.
+
+2006-02-21  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc32/vmx/copyi.asm: New file.
+	* mpn/powerpc32/vmx/copyd.asm: New file.
+
+2006-02-17  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/alpha/ev6/nails/aors_n.asm (CYSH): Import proper setting from
+	deleted mpn_sub_n.
+
+2006-02-16  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/alpha/ev6/addmul_1.asm: Correct slotting comments.
+
+2006-02-15  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/devel/anymul_1.c: Copy error reporting code from addmul_N.c.
+
+	* tests/devel/addmul_N.c: New file.
+	* tests/devel/mul_N.c: New file.
+
+	* mpn/alpha/default.m4 (PROLOGUE_cpu): Align functions at 16-byte
+	boundary.
+
+	* mpn/alpha/ev6/nails/aors_n.asm: New file.
+	* mpn/alpha/ev6/nails/add_n.asm: Remove.
+	* mpn/alpha/ev6/nails/sub_n.asm: Remove.
+
+	* mpn/alpha/ev6/nails/addmul_1.asm: Rewrite.
+	* mpn/alpha/ev6/nails/submul_1.asm: Likewise.
+	* mpn/alpha/ev6/nails/mul_1.asm: Likewise.
+
+	* mpn/alpha/ev6/nails/addmul_2.asm: Use L() for labels.
+	* mpn/alpha/ev6/nails/addmul_3.asm: Use L() for labels.
+	* mpn/alpha/ev6/nails/addmul_4.asm: Use L() for labels.
+
+2006-02-13  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc32/diveby3.asm: Trivially reorder loop insns to save
+	1 c/l.
+
+	* mpn/x86_64/dive_1.asm: Use movabsq to support large model non-PIC.
+
+	* mpn/x86_64/rsh1add_n.asm: Replace high register with rbx.
+	* mpn/x86_64/rsh1sub_n.asm: Likewise.
+
+2006-02-10  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc64/sqr_diagonal.asm: Software pipeline.
+
+	* mpn/powerpc64/vmx/popcount.asm: Add prefetching.
+
+2006-02-07  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc64/mode64/diveby3.asm: Rewrite.
+
+2006-02-04  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc64/vmx/popcount.asm: Remove mpn_hamdist partial code.
+	Move compare for huge n so that it is always executed.
+
+2006-02-03  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc32/linux.m4 (LEA): Add support for PIC.
+
+	* configure.in (powerpc): New optional, gcc_cflags_subtype.
+
+	* mpn/x86_64/pentium4/add_n.asm: New file.
+	* mpn/x86_64/pentium4/sub_n.asm: New file.
+	* mpn/x86_64/pentium4/lshift.asm: New file.
+
+	* mpn/powerpc64/linux64.m4 (PROLOGUE_cpu): Align function start to
+	16-multiple.
+	* mpn/powerpc64/aix.m4: Likewise.
+	* mpn/powerpc64/darwin.m4: Likewise.
+
+	* mpn/powerpc64/copyi.asm: Align loop to 16-multiple.
+	* mpn/powerpc64/copyd.asm: Likewise
+
+	* configure.in (powerpc): Add vmx to relevant paths.
+
+	* mpn/powerpc64/linux64.m4 (DEF_OBJECT): Accept 2nd argument, for
+	alignment.
+	* mpn/powerpc64/aix.m4: Likewise.
+	* mpn/powerpc64/darwin.m4: Likewise.
+
+	* mpn/powerpc32/linux.m4 (DEF_OBJECT, END_OBJECT): New macros,
+	inherited from powerpc64 versions.
+	* mpn/powerpc32/aix.m4: Likewise.
+	* mpn/powerpc32/darwin.m4: Likewise.
+
+	* mpn/powerpc64/vmx/popcount.asm: New file, for ppc32 and ppc64.
+	* mpn/powerpc32/vmx/popcount.asm: New file, grabbing above file.
+
+2006-01-22  Torbjorn Granlund  <tege@swox.com>
+
+	* configure.in: Generalize OS-dependent patterns for powerpcs.
+
+2006-01-20  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/x86_64/popham.asm: Optimize.
+
+	* config.guess: Recognize power4 and up under linux-gnu.
+	* config.sub: Generalize power recognition code.
+	* acinclude.m4 (POWERPC64_PATTERN): Add 64-bit powerpc processors.
+	* configure.in: Recognize powerpc processors masquerading as power
+	processors.
+
+2006-01-19  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/x86_64/logops_n.asm: Rewrite for more stable speed and smaller
+	code.
+	* mpn/x86_64/com_n.asm: Likewise.
+
+2006-01-18  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/x86_64/addlsh1_n.asm: Rewrite to use indexed addressing.
+	* mpn/x86_64/sublsh1_n.asm: Likewise.
+
+2006-01-17  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/diveby3.c: Use GMP standard parameter names.  Nailify
+	alternative code.  Use restrict for params.
+
+	* configure.in: Recognize andn_n as not needing nailification.
+
+	* tests/mpq/t-equal.c (check_various): Disable a test that gives common
+	factors for GMP_NUMB_BITS == 62.
+
+2006-01-16  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/get_str.c (mpn_sb_get_str): Fix digit count computation,
+	was inaccurate for nails.
+
+2006-01-15  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/x86_64/mode1o.asm: Remove unneeded carry register zeroing.
+
+2006-01-08  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/alpha/ev6/sqr_diagonal.asm: New file.
+
+2006-01-06  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc64/mode64/mod_34lsub1.asm: Tune to 1.5 c/l.
+
+	* mpn/generic/mullow_n.c (MUL_BASECASE_ALLOC): New #define.
+	(mpn_mullow_n): Use it.
+
+	* mpn/powerpc64/mode64/dive_1.asm: Use EXTERN.
+	* mpn/powerpc64/mode64/mode1o.asm: Likewise.
+
+	* mpn/powerpc64/aix.m4 (EXTERN): Define to import symbol.
+	(LDSYM): Remove [RW] attribute.
+	* mpn/powerpc64/linux64.m4 (EXTERN): Dummy definition.
+	* mpn/powerpc64/darwin.m4 (EXTERN): Likewise.
+
+2006-01-05  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc64/mode64/mode1o.asm: New file.
+
+	* mpn/powerpc64/mode64/dive_1.asm: Use L() for labels.  Invoke ASM_END.
+
+	* mpn/powerpc64/mode64/invert_limb.asm: Invoke ASM_END.
+
+	* mpn/powerpc64/linux64.m4: Move toc entry generation from direct at
+	DEF_OBJECT to delayed via LDSYM, define ASM_END to output it.
+	* mpn/powerpc64/aix.m4: Likewise.
+	* mpn/powerpc64/darwin.m4: Define a dummy ASM_END.
+
+	* mpn/powerpc64/mode64/addmul_1.asm: Add POWER5 timings.
+	* mpn/powerpc64/mode64/mul_1.asm: Likewise.
+
+	* mpn/powerpc64/mode64/submul_1.asm: Tweak to save 1.5 c/l for POWER5.
+
+2006-01-04  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc64/mode64/dive_1.asm: New file.
+
+	* mpn/powerpc64/mode64/invert_limb.asm: Add missing ASM_START.
+
+	* mpn/powerpc64/mode64/addmul_1.asm: Fix a comment typo.
+
+	* mpn/x86_64/diveby3.asm: Rewrite.
+
+2006-01-03  Torbjorn Granlund  <tege@swox.com>
+
+	* configure.in: Update bugs reporting address.
+
+	* mpn/powerpc64/mode64/diveby3.asm: Trim a cycle off of POWER4 timing.
+	Misc cleanup.
+
+2006-01-02  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc64/linux64.m4 (CALL): New macro.
+	* mpn/powerpc64/aix.m4: Likewise.
+	* mpn/powerpc64/darwin.m4: Likewise, also define macro "DARWIN".
+
+2005-12-28  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc64/mode64/mod_34lsub1.asm: New file.
+
+2005-12-26  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/x86_64/mod_34lsub1.asm: New file.
+
+2005-12-20  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/x86_64/submul_1.asm: Save a push/pop by not using register r12.
+	Use addq instead of leaq for pointer updates; schedule them.  (These
+	changes shaves one cycle of overhead and 0.25 c/l.)
+
+2005-12-18  Torbjorn Granlund  <tege@swox.com>
+
+	* mpf/ui_div.c: Implement workaround for GCC bug triggered on alpha.
+	* mpf/set_q.c: Likewise.
+
+2005-12-16  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/tdiv_qr.c: Remove statement with no effect.
+	Rename dead variable to `dummy'.
+
+2005-12-15  Torbjorn Granlund  <tege@swox.com>
+
+	* demos/pexpr.c (setup_error_handler): Add a missing ";".
+
+2005-11-27  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/mul.c: Crudely call mpn_mul_fft_full before checking
+	for unbalanced operands.
+
+	* mpn/generic/mul_fft.c: Remove many scalar divisions.
+	(mpn_mul_fft_lcm): Simplify.
+	(mpn_mul_fft_decompose): Rewrite to handle arbitrarily unbalanced
+	operands.
+
+2005-11-22  Torbjorn Granlund  <tege@swox.com>
+
+	* configure.in: Properly recognize all 32-bit Solaris releases.
+
+2005-11-10  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/mul_fft.c: Inline mpn_fft_mul_2exp_modF,
+	mpn_fft_add_modF and mpn_fft_normalize.
+
+2005-11-02  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/mpz/reuse.c: Increase operand size, decrease # of reps.
+
+	* mpz/rootrem.c: Adapt to new mpn_rootrem.
+	* mpz/root.c: Likewise.
+
+	* tests/mpz/reuse.c: Test mpz_rootrem.
+
+	With Paul Zimmermann:
+	* mpn/generic/rootrem.c: Complete rewrite.
+
+2005-10-31  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/pprime_p.c (mpz_probab_prime_p): Considerably limit trial
+	dividing.
+
+	* mpz/perfpow.c (mpz_perfect_power_p): Use mpz_divisible_ui_p instead
+	of mpz_tdiv_ui.
+
+	* mpz/divegcd.c: Correct probability number for GCD == 1.
+
+	* mpn/x86_64/mul_basecase.asm: Remove an obsolete comment.
+
+	* mpn/x86: Add cycle counts for array of x86 processors.
+
+	* mpn/x86/k7/mod_34lsub1.asm: Remove spurious mentions of ebp.
+
+	* mpn/powerpc32: Add POWER5 timings.
+
+	* mpn/powerpc32/README: Describe global reference variations.
+
+	* mpn/ia64/divrem_2.asm: Add some comments.
+
+	* mpn/ia64/divrem_1.asm: Reformat.
+
+	* mpn/ia64/addmul_2.asm: Correct a comment on slotting.
+	* mpn/ia64/logops_n.asm: Likewise.
+
+	* mpn/ia64/addmul_1.asm: Remove a redundant preg mutex decl.
+
+	* mpn/generic/dive_1.c: Whitespace cleanup.
+
+	* mpn/alpha/ev6/nails/addmul_1.asm: Correct comments on slotting.
+	* mpn/alpha/ev6/nails/addmul_2.asm: Likewise.
+	* mpn/alpha/ev6/nails/addmul_4.asm: Likewise.
+
+	* mpf/out_str.c: List some allocation improvement ideas.
+
+	* doc/gmp.texi: Update many URLs and email addresses.
+
+	* gmp-h.in (_GMP_H_HAVE_FILE): Check also _STDIO_H_INCLUDED.
+
+2005-10-26  Torbjorn Granlund  <tege@swox.com>
+
+	* tune/tuneup.c (tune_mullow): Update param.max_size for each threshold
+	measurement.
+
+	* configure.in (POWERPC64_PATTERN/*-*-darwin*): Set
+	SPEED_CYCLECOUNTER_OBJ_mode64 and cyclecounter_size_mode64.
+	(POWERPC64_PATTERN/*-*-linux*): Likewise.
+
+2005-10-03  Torbjorn Granlund  <tege@swox.com>
+
+	* demos/factorize.c (factor_using_division_2kp): Honor verbose flag.
+	(factor_using_pollard_rho): Divide out new factor before it's
+	clobbered.  Don't stop factoring after a composite factor was found.
+
+2005-09-17  Torbjorn Granlund  <tege@swox.com>
+
+	* demos/pexpr.c (fns): Add factorial keywords.
+
+2005-08-16  Torbjorn Granlund  <tege@swox.com>
+
+	* tune/Makefile.am (EXTRA_DIST): Change "amd64" => "x86_64".
+	* mpn/Makefile.am (TARG_DIST): Change "amd64" => "x86_64".
+
+2005-08-15  Torbjorn Granlund  <tege@swox.com>
+
+	* configure.in: Change "amd64" => "x86_64".
+
+2005-06-13  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/pre_mod_1.c: Canonicalize variable names.
+
+	* mpn/generic/divrem.c: Rate qxn test as UNLIKELY.
+
+	* mpn/generic/gcdext.c (sanity_check_row): Invoke TMP_MARK.
+
+	* tune/tuneup.c (tune_mullow): Fix all max_size fields.
+
+	* gmp-impl.h (SQR_TOOM3_THRESHOLD_LIMIT): New #define.
+	* tune/tuneup.c (tune_sqr): Use SQR_TOOM3_THRESHOLD_LIMIT.
+	(sqr_toom3_threshold): Initialize from SQR_TOOM3_THRESHOLD_LIMIT.
+
+	* mpn/generic/mul_n.c (mpn_sqr_n): Use SQR_TOOM3_THRESHOLD_LIMIT.
+
+	* gmp-impl.h (mpn_nand_n, mpn_iorn_n, mpn_nior_n, mpn_xnor_n):
+	Handle nails.
+
+2005-06-13  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/gcdext.c (gcdext_schoenhage): Check for the
+	(unlikely) case that one of the hgcd/euclid steps results in two
+	remainders of one limb each. Then use gcdext_1.
+
+2005-06-12  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/alpha/ev6/sub_n.asm: Analogous changes as to add_n.asm last.
+
+2005-06-11  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/alpha/ev6/add_n.asm: Rewrite inner loop to load later.
+	Add mpn_add_nc entry.
+
+	* mpn/alpha/ev6/addmul_1.asm: Remove redundant initial loads.
+
+2005-06-09  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/ia64/dive_1.asm: Fix issues with HP-UX.
+
+2005-06-08  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/ia64/diveby3.asm: Update TODO list.
+
+	* mpn/ia64/mode1o.asm: Fix comment typos.
+
+	* mpn/ia64/dive_1.asm: New file.
+
+2005-06-07  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/ia64/mode1o.asm: Add prefetching.
+
+	* mpn/generic/dive_1.c: Use variable h for upper umul_ppmm result.
+
+2005-06-06  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/ia64/hamdist.asm: Complete rewrite.
+	* mpn/ia64/popcount.asm: Rewrite to use multi-pronged feed-in.
+
+	* mpn/ia64/aors_n.asm: Rewrite feed-in code.
+	* mpn/ia64/rsh1aors_n.asm: Likewise.
+	* mpn/ia64/aorslsh1_n.asm: Likewise.
+	* mpn/ia64/lorrshift.asm: Likewise.
+
+2005-06-04  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/devel/try.c (choice_array): Exclude mpn_preinv_mod_1 unless
+	USE_PREINV_MOD_1.
+	(choice_array): Exclude mpn_sqr_basecase if SQR_KARATSUBA_THRESHOLD
+	is zero.
+
+2005-06-03  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/alpha/ev6/addmul_1.asm: Prefix all labels with "$".
+	* mpn/alpha/ev6/mul_1.asm: Likewise.
+
+2005-06-02  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/refmpn.c (refmpn_divmod_1c_workaround): Implement workaround
+	to gcc 3.4.x bug triggered on powerpc64 with 32-bit ABI.
+
+2005-06-01  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/devel/try.c (main): Fix a typo.
+
+2005-05-31  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/alpha/ev6/addmul_1.asm: Rewrite for L1 cache, add prefetch.
+
+2005-05-30  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/misc.c (tests_rand_start): Mask random seed to 32 bits.
+
+2005-05-29  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc64/mode32/mul_1.asm: Handle BROKEN_LONGLONG_PARAM.
+	* mpn/powerpc64/mode32/addmul_1.asm: Likewise.
+	* mpn/powerpc64/mode32/submul_1.asm: Likewise.
+
+	* mpn/powerpc32/mode1o.asm: Rewrite to actually work.
+
+	* mpn/powerpc32/aix.m4 (LEA): New macro.
+	(ASM_END): New macro.
+
+	* mpn/powerpc32/linux.m4: New file.
+	* mpn/powerpc32/darwin.m4: New file.
+	* configure.in: Use linux.m4 and darwin.m4.
+	(powerpc64-linux-gnu): Add support for mode32.
+
+2005-05-25  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/mullow_n.c: Remove FIXME mentioning fixed flaw.
+
+	* tests/mpz/t-cmp_d.c (check_one): Fix printf fmt string typo.
+
+	* demos/isprime.c: #include stdlib.h.
+	* tests/rand/t-urbui.c: Likewise.
+	* tests/rand/t-urmui.c: Likewise.
+
+	* tests/mpz/t-popcount.c (check_random): Remove spurious printf arg.
+
+	* mpn/ia64/lorrshift.asm: Cleanup code layout.
+	* mpn/ia64/popcount.asm: Likewise.
+
+2005-05-24  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/devel/try.c (param_init) [TYPE_GET_STR]: Set retval field.
+	(compare): Handle SIZE_GET_STR as SIZE_RETVAL.
+
+	* tests/refmpn.c (refmpn_get_str): Rewrite to make it work.
+
+2005-05-23  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/amd64/add_n.asm: Add mpn_add_nc entry point.
+	* mpn/amd64/sub_n.asm: Add mpn_sub_nc entry point.
+
+	* longlong.h (many places): Remove lvalue casts.
+
+	* gmp-impl.h (MPF_SIGNIFICANT_DIGITS): Cast prec to avoid overflow
+	for > 4G digits.
+
+	* mpn/alpha/ev6/add_n.asm: Prefetch using ldl.
+	* mpn/alpha/ev6/sub_n.asm: Likewise.
+
+	* mpn/alpha/ev6/slot.pl (optable): Recognize negq and ldl.
+
+	* mpn/ia64/aors_n.asm: Prefetch using lfetch.
+	* mpn/ia64/lorrshift.asm: Likewise.
+	* mpn/ia64/popcount.asm: Likewise.
+	* mpn/ia64/diveby3.asm: Likewise.
+
+2005-05-22  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/alpha/ev67/popcount.asm: Prefetch.
+	* mpn/alpha/ev67/hamdist.asm: Prefetch.
+
+	* longlong.h (add_ssaaaa) [x86]: Remove lvalue casts.
+	(sub_ddmmss) [x86]: Likewise.
+
+	* tests/devel/try.c (param_init) [TYPE_MPZ_JACOBI]: Add DATA_SRC1_ODD.
+	(param_init) [TYPE_MPZ_KRONECKER]: Clear inherited DATA_SRC1_ODD.
+	(param_init) [TYPE_DIVEXACT_1]: Use symbolic name DIVISOR_LIMB.
+
+2005-05-21  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/devel/try.c (param_init) [TYPE_MPZ_JACOBI]: Initialize divisor
+	field according to UDIV_NEEDS_NORMALIZATION.
+
+	* mpz/mul_i.h: Remove left-over TMP_XXXX marker arguments.
+
+2005-05-20  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/x86/pentium4/sse2/addmul_1.asm (mpn_addmul_1c): Put carry in
+	proper register.
+
+	* mpn/generic/sqr_basecase.c (mpn_sqr_basecase, addmul_2 version):
+	Avoid accesses out-of-bound in MPN_SQR_DIAGONAL applicate code.
+
+2005-05-19  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/alpha/diveby3.asm: Make it actually work.
+
+	* gmp-impl.h (MULLOW_BASECASE_THRESHOLD_LIMIT): New #define.
+	* mpn/generic/mullow_n.c: Use fixed stack allocation for the smallest
+	operands; use TMP_S* allocation for medium operands.
+
+	* gmp-impl.h: Remove nested TUNE_PROGRAM_BUILD test.
+
+2005-05-18  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/mul_n.c: Make squaring and multiplication code more
+	similar.  Use TMP_S* functions.
+
+	* gmp-impl.h (TMP_DECL, TMP_MARK, TMP_FREE): Get rid of argument.
+	(TMP_SALLOC): New macro for "small" allocations.
+	(TMP_BALLOC): New macro for "big" allocations.
+	(TMP_SDECL, TMP_SMARK, TMP_SFREE): New macros for functions that use
+	just TMP_SALLOC.
+	(WANT_TMP_ALLOCA): Make default functions choose alloca or reentrant
+	functions, depending on size.
+
+	* *.c: Remove TMP_XXXX marker arguments.
+
+	* acinclude.m4 (WANT_TMP): Want tal-reent.lo also for alloca case.
+
+2005-05-16  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/ia64/gmp-mparam.h: Further extend FFT tables.
+
+2005-05-15  Torbjorn Granlund  <tege@swox.com>
+
+	* gmp-impl.h (udiv_qrnnd_preinv2): Pull an add into add_ssaaaa.
+	(udiv_qrnnd_preinv2gen): Likewise.
+
+2005-05-14  Torbjorn Granlund  <tege@swox.com>
+
+	* longlong.h (add_ssaaaa) [x86_64]: Restrict allowed immediate
+	operands.
+	* (sub_ddmmss) [x86_64]: Likewise.
+
+2005-05-02  Torbjorn Granlund  <tege@swox.com>
+
+	* acinclude.m4 (GMP_HPC_HPPA_2_0): Make gmp_tmp_v1 sed pattern handle
+	version numbers like B.11.X.32509-32512.GP.
+
+	* mpn/m68k/aors_n.asm: Correct MULFUNC_PROLOGUE.
+
+	* mpn/powerpc64/mode64/aors_n.asm: Add a MULFUNC_PROLOGUE.
+
+	* mpf/inp_str.c: Use plain int for mpf_set_str return value (works
+	around gcc 4 bug).
+
+	* acinclude.m4 (GMP_ASM_POWERPC_PIC_ALWAYS): Handle darwin's assembly
+	syntax.
+	(long long reliability test 1): New GMP_PROG_CC_WORKS_PART test.
+	(long long reliability test 2): New GMP_PROG_CC_WORKS_PART test.
+
+	* configure.in: Add mode64 support for darwin.  Use darwin.m4.
+	Add cflags_opt flags for mode32 darwin.
+
+	* mpn/powerpc64: Use L() for all asm files.
+
+	* mpn/asm-defs.m4 (PIC_ALWAYS): Define PIC just iff PIC_ALWAYS = "yes".
+
+	* mpn/powerpc64/darwin.m4: New file.
+
+	* mpn/powerpc64/linux64.m4: Remove TOCREF, add LDSYM.
+	Rework DEF_OBJECT to need just one argument.
+	* mpn/powerpc64/aix.m4: Likewise.
+
+	* mpn/powerpc64/mode64/invert_limb.asm: Load approx_tab address with
+	LDSYM.  Optimize somewhat.  Remove 2nd DEF_OBJECT operand.
+
+2005-05-01  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/popham.c: Compute final summation differently for 64-bit.
+
+	* tests/mpz/t-popcount.c (check_random): New function.
+	(main): Call it.
+
+2005-04-28  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/amd64/add_n.asm: Use r9 instead of rbx to save push/pop.
+	* mpn/amd64/sub_n.asm: Likewise.
+
+2005-04-09  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc64/copyi.asm: If HAVE_ABI_mode32, ignore upper 32 bits of
+	mp_size_t argument.
+	* mpn/powerpc64/copyd.asm: Likewise.
+	* mpn/powerpc64/sqr_diagonal.asm: Likewise.
+	* mpn/powerpc64/lshift.asm: Likewise.
+	* mpn/powerpc64/rshift.asm: Likewise.
+	* mpn/powerpc64/logops_n.asm: Likewise.
+	* mpn/powerpc64/com_n.asm: Likewise.
+
+2005-04-08  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/rootrem.c: Allocate PP_ALLOC limbs also for qp.
+
+2005-04-07  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc32/add_n.asm: Add nc entry point.
+	* mpn/powerpc32/sub_n.asm: Likewise.
+
+	* mpn/amd64/*.asm: Add Prescott/Nocona cycle/limb numbers.
+
+	* mpn/alpha/add_n.asm: Add correct cycle/limb numbers.
+	* mpn/alpha/sub_n.asm: Likewise.
+	* mpn/alpha/ev5/add_n.asm: Likewise.
+	* mpn/alpha/ev5/sub_n.asm: Likewise.
+
+2005-03-31  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/x86/k7/gmp-mparam.h: Fix typo in last change.
+
+2005-03-19  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/amd64/gmp-mparam.h: Update.
+
+	* mpn/alpha/gmp-mparam.h: Update.
+	* mpn/alpha/ev5/gmp-mparam.h: Update.
+	* mpn/alpha/ev6/gmp-mparam.h: Update.
+
+	* mpn/ia64/gmp-mparam.h: Update.
+
+	* mpn/x86/p6/mmx/gmp-mparam.h: Update.
+	* mpn/x86/pentium4/sse2/gmp-mparam.h: Update.
+	* mpn/x86/k7/gmp-mparam.h: Update.
+
+	* tests/mpz/t-gcd.c (main): Honor command line reps argument.
+
+	* tune/speed.h (SPEED_ROUTINE_MPN_GCD_CALL): Simplify and correct code
+	for generating test operands.
+
+2005-03-17  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/hgcd.c (qstack_adjust): New argument d, saying how much
+	to adjust the top quotient.
+	(hgcd_adjust): The quotient can be off by either 1 or 2.
+
+2005-03-16  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/mpz/t-gcd.c (MAX_SCHOENHAGE_THRESHOLD): Set to largest of
+	gcd,gcdext thresholds.
+
+2005-03-15  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/gcdext.c (gcdext_schoenhage): When calling gcdext_lehmer,
+	reuse all temporary limb storage, including the storage used for the
+	qstack.
+
+2005-03-09  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/amd64/logops_n.asm: Add MULFUNC_PROLOGUE.
+
+2005-03-05  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/amd64/gmp-mparam.h: Extend MUL_FFT_TABLE and SQR_FFT_TABLE.
+	* mpn/ia64/gmp-mparam.h: Likewise.
+
+2005-02-17  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/ia64/divrem_1.asm: Add preinv entry point.
+
+2005-01-13  Torbjorn Granlund  <tege@swox.com>
+
+	* gmp-impl.h (MPN_SIZEINBASE): Count bits in type size_t.
+	(MPN_SIZEINBASE_16): Likewise.
+
+2004-12-17  Torbjorn Granlund  <tege@swox.com>
+
+	* tune/speed.c (run_gnuplot): Use lines, not linespoints.
+	Output a reset gnuplot command initially.
+
+2004-12-04  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/random2.c (gmp_rrandomb): Rework again.
+	* mpz/rrandomb.c (gmp_rrandomb): Likewise.
+
+	* mpn/amd64/redc_1.asm: Call via PLT when PIC.
+
+2004-11-29  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/amd64/divrem_1.asm: Add preinv entry point.
+	* mpn/amd64/gmp-mparam.h: Set USE_PREINV_DIVREM_1 to 1.
+
+2004-11-24  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/alpha/diveby3.asm: Use correct prefetch instruction.
+
+2004-11-19  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/alpha/diveby3.asm: Add ",gp" glue in PROLOGUE.
+	Add r31 dummy operand to `br' instruction.
+
+2004-11-17  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc64/mode64/addmul_1.asm: Rewrite.
+	* mpn/powerpc64/mode64/mul_1.asm: Rewrite.
+
+	* configure.in: Invoke AC_C_RESTRICT.
+
+2004-11-16  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/alpha/diveby3.asm: New file.
+
+2004-11-13  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/amd64/popham.asm: New file.
+
+2004-11-12  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/amd64/add_n.asm: Correct cycle count.
+	* mpn/amd64/sub_n.asm: Likewise.
+
+	* mpn/amd64/dive_1.asm: Speed divisors with many factors of 2.
+
+2004-11-11  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/amd64/dive_1.asm: New file.
+
+2004-11-10  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/popham.c: Add comment.
+
+2004-11-09  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/amd64/com_n.asm: New file.
+
+	* mpn/amd64/logops_n.asm: New file.
+
+2004-11-08  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc64/com_n.asm: New file.
+
+2004-11-05  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/amd64/diveby3.asm: New file.
+
+	* config.guess: Strip any PPC string in /proc/cpuinfo.
+	Recognize 970 in that code.
+
+2004-11-01  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/amd64/mul_basecase.asm: New file.
+
+	* mpn/amd64/redc_1.asm: New file.
+
+2004-10-25  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc64/mode64/addlsh1_n.asm: Correct cycle counts.
+
+	* mpn/powerpc64/README: Update POWER5/PPC970 pipeline information.
+
+	* mpn/generic/mul_basecase.c (MAX_LEFT): Add comment.
+
+	* doc/gmp.texi: Consistently use "x86" denotation.
+	(Assembler SIMD Instructions): Mention SSE2 usage.
+
+	* demos/pexpr.c (main): Handle "negative" base in mpz_sizeinbase call.
+
+2004-10-18  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc64/mode64/submul_1.asm: Shave 2 cycles/limb with new carry
+	inversion trick.
+
+2004-10-16  Torbjorn Granlund  <tege@swox.com>
+
+	* configure.in: Support icc under x86.
+	(ia64-*-linux*): Pass -no-gcc to icc.
+
+2004-10-15  Torbjorn Granlund  <tege@swox.com>
+
+	* longlong.h (ia64 umul_ppmm): Add version for icc.
+
+	* configure.in: Support icc under ia64-*-linux*.
+
+	* acinclude.m4: New "compiler works" test for icc 8.1 bug.
+	(GMP_PROG_CC_IS_GNU): Don't let Intel's icc fool us it is GCC.
+
+2004-10-14  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/gcdext.c: Add a few missing TMP_MARK.
+
+2004-10-14  Torbjorn Granlund  <tege@swox.com>
+
+	* acinclude.m4 (GMP_ASM_W32): Try also "data4".
+
+	* mpn/ia64/logops_n.asm: Don't use naked "br", rejected by Intel
+	assembler.
+	* mpn/ia64/aors_n.asm: Likewise.
+
+	* mpn/ia64/divrem_2.asm: Add ".prologue".
+
+	* mpn/ia64/hamdist.asm: Put alloc first in bundle, enforced by the
+	Intel assembler.
+
+	* longlong.h: Exclude masquerading __INTEL_COMPILER from ia64 asm.
+	* gmp-impl.h: Likewise.
+
+2004-10-12  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/ia64/mul_2.asm: Rewrite function entry code, write new code for
+	n=2.
+	* mpn/ia64/addmul_2.asm: Likewise.
+
+	* tests/devel/try.c: Handle mpn_mul_2 like mpn_addmul_2.
+
+	* tune/speed.c (routine): Make R parameter optional for mpn_mul_2.
+
+2004-10-11  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/sparc64/addmul_1.asm: Update a comment.
+
+	* tests/devel/aors_n.c: #include tests.h.
+	* tests/devel/anymul_1.c: Likewise.
+	* tests/devel/shift.c: Likewise.
+	* tests/devel/copy.c: Likewise.
+
+	* tests/devel/aors_n.c: Handle also mpn_addlsh1_n, mpn_sublsh1_n,
+	mpn_rsh1add_n, and mpn_rsh1sub_n.
+
+	* mpn/ia64/submul_1.asm: Add TODO item.
+
+	* mpn/ia64/aors_n.asm: Rewrite function entry code (again).
+	* mpn/ia64/aorslsh1_n.asm: Likewise.
+	* mpn/ia64/logops_n.asm: Likewise.
+
+	* mpn/ia64/rsh1aors_n.asm: Tune function entry and feed-in code.
+	* mpn/ia64/lorrshift.asm: Likewise.  Remove several spurious loads.
+
+	* tests/devel/Makefile.am (EXTRA_PROGRAMS): Updates for yesterday's
+	file removals and additions.
+
+2004-10-10  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/ia64/copyi.asm: Tune function entry code.
+	* mpn/ia64/copyd.asm: Likewise.
+
+	* mpn/ia64/logops_n.asm: Tune function entry and feed-in code for speed
+	and size.
+	* mpn/ia64/aors_n.asm: Likewise.
+
+	* mpn/powerpc64/logops_n.asm: Correct cycles counts.
+	* mpn/powerpc64/mode64/aors_n.asm: Likewise.
+
+	* tests/devel/copy.c: Handle both MPN_COPY_INCR and MPN_COPY_DECR.
+
+	* tests/devel/logops_n.c: New file, handle all logical operations.
+
+	* tests/devel/anymul_1.c: New file, handle mpn_mul_1, mpn_addmul_1, and
+	mpn_submul_1
+	* tests/devel/mul_1.c: Remove.
+	* tests/devel/addmul_1.c: Remove.
+	* tests/devel/submul_1.c: Remove.
+
+	* tests/devel/shift.c: New file, handle mpn_lshift and mpn_rshift.
+	* tests/devel/lshift.c: Remove.
+	* tests/devel/rshift.c: Remove.
+
+	* tests/devel/aors_n.c: New file, handle mpn_add_n and mpn_sub_n.
+	* tests/devel/add_n.c: Remove.
+	* tests/devel/sub_n.c: Remove.
+
+2004-10-09  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc64/linux64.m4: Define DEF_OBJECT, END_OBJECT, and TOCREF.
+	* mpn/powerpc64/aix.m4: Likewise.
+	* mpn/powerpc64/mode64/invert_limb.asm: Use DEF_OBJECT, END_OBJECT, and
+	TOCREF for approx_tab.
+
+	* mpn/amd64/mul_1.asm: Add mpn_mul_1c entry point.
+
+2004-10-08  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc64/copyi.asm: New file.
+	* mpn/powerpc64/copyd.asm: New file.
+	* gmp-h.in: Remove PPC MPN_COPY variants.
+	* gmp-impl.h: Likewise.
+
+	* mpn/powerpc64/logops_n.asm: New file.
+
+	* mpn/powerpc64/mode64/invert_limb.asm: New file.
+
+2004-10-07  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc64/mode64/aors_n.asm: New file, optimized for POWER4 and
+	its derivatives.
+	* mpn/powerpc64/mode64/add_n.asm: Delete.
+	* mpn/powerpc64/mode64/sub_n.asm: Delete.
+
+	* configfsf.guess: Patch HP-UX code to accommodate HP compiler's new
+	inability to read from stdin.
+
+	* mpn/powerpc64/mode64/addsub_n.asm: Remove accidentally added file.
+
+2004-10-02  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/amd64/README: Update for new developments, fix typos.
+
+	* mpn/amd64/mul_1.asm: Tweak addressing (3.25 => 3.0 cycles/limb).
+
+	* mpn/amd64/addmul_1.asm: Remove unreachable code block.
+
+2004-09-30  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/amd64/addmul_1.asm: Rewrite, now 3.25 cycles/limb.
+
+	* mpn/ia64/addmul_1.asm: Slightly enhance cross-jumping for code
+	density.
+	* mpn/ia64/mul_1.asm: Analogous changes.
+
+2004-09-29  Torbjorn Granlund  <tege@swox.com>
+
+	* gmp-impl.h (x86 ULONG_PARITY): Work around GCC change of "q" register
+	flag.
+
+2004-09-28  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/ia64/divrem_1.asm: Add cycle counts to loop.
+
+	* mpn/ia64/divrem_2.asm: New file.
+
+2004-09-28  Paul Zimmermann  <Paul.Zimmermann@loria.fr>
+
+	* mpn/generic/mul_fft.c (mpn_mul_fft): Fix a bug in the choice of the
+	recursive fft parameters.
+
+2004-09-20  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/misc.c (tests_rand_start): Default to strtoul for re-seeding.
+
+	* tests/mpz/t-mul.c (ref_mpn_mul): Fudge tmp allocation for toom3.
+
+2004-09-19  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/misc.c (tests_rand_start): Shift tv_usec for better seeding.
+
+2004-09-18  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/misc.c (tests_rand_start): Invoke fflush after printing seed.
+
+	* tests/mpz/t-mul.c (main): Check environment for GMP_CHECK_FFT, run
+	extra FFT tests if set.
+	(ref_mpn_mul): Use library code for kara and toom, but skewded so that
+	we never use the same algorithm that we're testing.
+	(mul_kara): Delete.
+	(debug_mp): Print just one line of large numbers.
+	(ref_mpn_mul): Rework usage of tp temporary space.
+
+2004-09-15  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/ia64/mul_2.asm: For HAVE_ABI_32, convert vp.
+	* mpn/ia64/addmul_2.asm: Likewise.
+
+2004-09-13  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/ia64/invert_limb.asm: Rewrite.
+
+	* mpn/ia64/logops_n.asm: Insert some more stops.
+
+2004-09-12  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/ia64/gmp-mparam.h: Update.
+	* mpn/amd64/gmp-mparam.h: Update.
+
+	* mpn/ia64/sqr_diagonal.asm: Shave off a few cycles.
+
+2004-09-11  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/ia64/mul_2.asm: New file.
+	* mpn/ia64/addmul_2.asm: New file.
+
+	* mpn/ia64/addmul_1.asm: Tune a cycle from prologue.
+
+	* mpn/ia64/lorrshift.asm: Insert stops after several branches.
+	* mpn/ia64/aorslsh1_n.asm: Likewise.
+	* mpn/ia64/rsh1aors_n.asm: Likewise.
+
+	* mpn/generic/sqr_basecase.c: In variant for HAVE_NATIVE_mpn_addmul_2,
+	accumulate carry also for when HAVE_NATIVE_mpn_addlsh1_n.
+
+2004-09-07  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/ia64/submul_1.asm: Rewrite.
+
+	* mpn/ia64/addmul_1.asm: Format to placate HP-UX assembler.
+	* mpn/ia64/mul_1.asm: Likewise.
+
+2004-09-02  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/ia64/mul_1.asm: Optimize feed-in code.
+	* mpn/ia64/addmul_1.asm: Rewrite feed-in code.
+
+2004-08-29  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/mpz/t-sizeinbase.c: Disable mpz_fake_bits and check_sample.
+
+2004-07-16  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/ia64/addmul_1.asm: Format to placate HP-UX assembler.
+
+2004-06-17  Kevin Ryde  <kevin@swox.se>
+
+	* doc/gmp.texi: Use @. when sentence ends with a capital, for good
+	spacing in tex.
+	(Language Bindings): Add gmp-d, reported by Ben Hinkle.  Update SWI
+	Prolog URL, reported by Jan Wielemaker.
+
+2004-06-09  Torbjorn Granlund  <tege@swox.com>
+
+	* configure.in: Handle --enable-fat.  Use that to enable x86 fat
+	builds, remove magic meaning of i386-*-*.
+
+2004-06-03  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-impl.h (memset): Use a local char* pointer, in case parameter is
+	something else (eg. tune/common.c).  Reported by Emmanuel Thomé.
+
+2004-06-01  Kevin Ryde  <kevin@swox.se>
+
+	* config.guess (i?86-*-*): Avoid "Illegal instruction" message which
+	goes to stdout on 80386 freebsd4.9.
+
+2004-05-23  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/gcdext.c (gcdext_1_u): New function.
+	(mpn_gcdext): Use it.
+
+2004-05-23  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/gcdext.c (gcdext_1_odd): Use masking to avoid jumps.
+
+2004-05-22  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/x86/pentium4/sse2/addmul_1.asm: Add Prescott cycle numbers.
+
+	* mpn/amd64/divrem_1.asm: Shave a cycle from fraction development code.
+
+	* mpn/powerpc32/lshift.asm: Add more cycle numbers.
+	* mpn/powerpc32/rshift.asm: Likewise.
+
+	* mpn/ia64/addmul_1.asm: Reformat.
+
+2004-05-21  Torbjorn Granlund  <tege@swox.com>
+
+	* gmp-impl.h (mpn_mullow_n, mpn_mullow_basecase): Declare.
+
+	* tune/Makefile.am: Compile gcdext.c.
+
+	* gmp-impl.h (GET_STR_THRESHOLD_LIMIT): Lower outrageous value to 150.
+	(GCDEXT_SCHOENHAGE_THRESHOLD): Set reasonable default.  Override when
+	TUNE_PROGRAM_BUILD.
+	(GCDEXT_THRESHOLD): Remove.
+
+	* tune/tuneup.c (gcdext_schoenhage_threshold): New variable.
+	(gcdext_threshold): Remove variable.
+	(tune_gcd_schoenhage): Lower step_factor to 0.1.
+	(tune_gcdext_schoenhage): New function, based on tune_gcd_schoenhage.
+	(tune_gcdext): Remove function.
+	(all): Corresponding changes.
+
+2004-05-21  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/gcdext.c: Complete rewrite.  Uses fast Lehmer code for
+	small operands, and Schoenhage code for large operands.
+
+	* tune/speed.h (SPEED_ROUTINE_MPN_GCD_CALL): Ensure first operand is
+	not smaller than 2nd operand.
+
+2004-05-17  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-h.in (mpz_get_ui): Use #if instead of plain if, and for nails
+	use ?: same as normal case, to avoid warnings from Borland C++ 6.0.
+	Reported by delta trinity.
+
+2004-05-15  Kevin Ryde  <kevin@swox.se>
+
+	* tune/time.c (getrusage_backwards_p): New function
+	(speed_time_init): Use it to exclude broken netbsd1.4.1 getrusage.
+	* configure.in (m68*-*-netbsd1.4*): Remove code pretending getrusage
+	doesn't exist.
+	* tune/README (NetBSD 1.4.1 m68k): Update notes.
+
+	* configure.in (mips*-*-* ABI=n32): Remove gcc_n32_ldflags and
+	cc_n32_ldflags, libtool knows to put the linker in n32 mode.
+
+2004-05-15  Torbjorn Granlund  <tege@swox.com>
+
+	* config.guess (powerpc*-*-*): Add more processor types to mfpvr code.
+	* configure.in: Generalize powerpc subtype matching code.
+
+	* mpz/fac_ui.c: Misc cleanups, spelling corrections.
+
+2004-05-14  Kevin Ryde  <kevin@swox.se>
+
+	* mpf/sub.c: When one operand cancels high limbs of the other, strip
+	high zeros on the balance before truncating to destination precision.
+	Truncating first loses accuracy and can lead to a result 0 despite
+	operands being not equal.  Reported by John Abbott.
+	Also, ensure exponent is zero when result is zero, for instance if
+	operands are exactly equal.
+	* tests/mpf/t-sub.c (check_data): New function, exercising these.
+
+2004-05-12  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (AC_PROG_RANLIB): New macro, supposedly required by
+	automake, though it doesn't complain.
+
+	* demos/expr/Makefile.am (ARFLAGS): Add a default setting, to
+	workaround an automake bug.
+
+2004-05-10  Kevin Ryde  <kevin@swox.se>
+
+	* */Makefile.in, install-sh, aclocal.m4: Update to automake 1.8.4.
+
+	* doc/gmp.texi (Demonstration Programs): Add a remark about expression
+	evaluation in the main gmp library.
+
+	* demos/expr/exprfa.c (mpf_expr_a): Correction to mpX_init, use
+	mpf_init2 to follow requested precision.
+	* demos/expr/exprza.c, demos/expr/exprqa.c: Use wrappers for mpX_init,
+	to make parameters match.
+
+	* demos/expr/run-expr.c: Don't use getopt, to avoid needing configury
+	for optarg declaration.  Remove TRY macro, rename foo and bar to var_a
+	and var_b, for clarity.
+	* demos/expr/expr-impl.h: Don't use expr-config.h.
+	* configure.in (demos/expr/expr-config.h): Remove.
+	* demos/expr/expr-config.in: Remove file.
+
+2004-05-08  Kevin Ryde  <kevin@swox.se>
+
+	* doc/configuration (Configure): Update for current automake not
+	copying acinclude.m4 into aclocal.m4.
+
+	* configure.in, Makefile.am, doc/gmp.texi, doc/configuration,
+	tests/cxx/Makefile.am, demos/expr/Makefile.am, demos/expr/README,
+	demos/expr/expr.c, demos/expr/expr.h, demos/expr/expr-config-h.in,
+	demos/expr/expr-impl.h, demos/expr/run-expr.c, demos/expr/t-expr.c:
+	MPFR now published separately, remove various bits.
+	* mpfr/*, tests/cxx/t-headfr.cc, demos/expr/exprfr.c,
+	demos/expr/exprfra.c: Remove.
+
+2004-05-07  Kevin Ryde  <kevin@swox.se>
+
+	* tests/cxx/Makefile.am (TESTS_ENVIRONMENT): Amend c++ shared library
+	path hack, on k62-unknown-dragonfly1.0 /usr/bin/make runs its commands
+	"set -e", so we need an "|| true" in case there's nothing to copy (for
+	instance in a static build).
+
+2004-05-06  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/alpha/mode1o.c: Remove, in favour of ...
+	* mpn/alpha/mode1o.asm: New file.
+	* mpn/alpha/alpha-defs.m4 (bwx_available_p): New macro.
+
+	* tune/amd64.asm: Save rbx in r10 rather than on the stack.
+
+	* configure.in (x86_64-*-*): Try also "-march=k8 -mno-sse2", in case
+	we're in ABI=32 on an old OS not supporting xmm regs.
+	(GMP_GCC_PENTIUM4_SSE2, GMP_OS_X86_XMM): Run these tests under
+	-march=k8 too, and not under ABI=64.
+
+	* doc/gmp.texi (Converting Integers): For mpz_get_d, note truncation
+	and overflows.  For mpz_get_d_2exp note truncation, note result if
+	OP==0, and cross reference libc frexp.
+	(Rational Conversions): For mpq_get_d, note truncation and overflows.
+	(Converting Floats): For mpf_get_d, note truncation and overflows.
+	For mpf_get_d_2exp, note truncation, note result if OP==0.
+	(Assembler Code Organisation): Note nails subdirectories.
+	Clarification of get_d_2exp OP==0 reported by Sylvain Pion.
+
+2004-05-05  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/mullow_n.c, mpn/generic/mullow_basecase.c: New files
+	(mainly by Niels Möller).
+	* configure.in, mpn/Makefile.am: Add them.
+
+	* gmp-impl.h (MULLOW_BASECASE_THRESHOLD, MULLOW_DC_THRESHOLD,
+	MULLOW_MUL_N_THRESHOLD): Override for TUNE_PROGRAM_BUILD.
+
+	* tune/Makefile.am: Compile mullow_n.c.
+	* tune/common.c (speed_mpn_mullow_n, speed_mpn_mullow_basecase):
+	New functions.
+	* tune/speed.c (routine): Add entries for mpn_mullow_n and
+	mpn_mullow_basecase.
+	* tune/speed.h (SPEED_ROUTINE_MPN_MULLOW_N_CALL,
+	SPEED_ROUTINE_MPN_MULLOW_BASECASE): New #defines.
+	* tune/tuneup.c (tune_mullow): New function.
+
+	* gmp-impl.h (invert_limb): Compute branch-freely.
+
+2004-05-02  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/amd64/mode1o.asm: Use movabsq to support large model non-PIC.
+	Use 32-bit insns to save code bytes, and to save a couple of cycles on
+	the initial setup multiplies.
+
+2004-05-01  Kevin Ryde  <kevin@swox.se>
+
+	* doc/gmp.texi (References): Update gcc online docs url to
+	gcc.gnu.org.
+
+	* configure.in (mips*-*-irix[6789]*): Correction to m4 quoting of this
+	pattern.  (Believe the mips64*-*-* part also used picks up all current
+	irix6 tuples anyway.)  Reported by Rainer Orth.
+
+2004-04-30  Kevin Ryde  <kevin@swox.se>
+
+	* acinclude.m4 (GMP_PROG_CC_X86_GOT_EAX_EMITTED,
+	GMP_ASM_X86_GOT_EAX_OK): New macros.
+	(GMP_PROG_CC_WORKS): Use them to detect an old gas bug tickled by
+	recent gcc.  Reported by David Newman.
+
+	* doc/gmp.texi (Reentrancy): Note also gmp_randinit_default as an
+	alternative to gmp_randinit.
+
+2004-04-29  Torbjorn Granlund  <tege@swox.com>
+
+	* configfsf.guess: Update to 2004-03-12.
+	* configfsf.sub: Likewise.
+
+2004-04-27  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/rrandomb.c (gmp_rrandomb): Rework to avoid extra limb allocation
+	and to generate even numbers.
+	* mpn/generic/random2.c (gmp_rrandomb): Likewise.
+
+2004-04-25  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-impl.h (FORCE_DOUBLE): Don't use an asm with a match constraint
+	on a memory output, apparently not supported and provokes a warning
+	from gcc 3.4.
+
+2004-04-24  Kevin Ryde  <kevin@swox.se>
+
+	* longlong.h (count_leading_zeros_gcc_clz,
+	count_trailing_zeros_gcc_ctz): New macros.
+	(count_leading_zeros, count_trailing_zeros) [x86]: Use them on gcc
+	3.4.
+
+	* configure.in (x86-*-* gcc_cflags_cpu): Give a -mtune at the start of
+	each option list, for use by gcc 3.4 to avoid deprecation warnings
+	about -mcpu.
+
+	* mpz/aorsmul.c, mpz/aorsmul_i.c, mpz/cfdiv_q_2exp.c,
+	mpz/cfdiv_r_2exp.c, mpq/aors.c, mpf/ceilfloor.c: Give REGPARM_ATTR()
+	on function definition too, as demanded by gcc 3.4.
+
+2004-04-22  Kevin Ryde  <kevin@swox.se>
+
+	* tests/rand/t-lc2exp.c (check_bigc1): New test.
+
+	* doc/fdl.texi: Tweak @appendixsubsec -> @appendixsec to match our
+	preference for this in an @appendix, and because texi2pdf doesn't
+	support @appendixsubsec directly within an @appendix.
+
+2004-04-20  Kevin Ryde  <kevin@swox.se>
+
+	* doc/texinfo.tex: Update to 2004-04-07.08 from texinfo 4.7.
+	* doc/gmp.texi, mpfr/mpfr.texi (@copying): Don't put a line break in
+	@ref within @copying, recent texinfo.tex doesn't like that.
+
+	* demos/perl/GMP.xs (static_functable): Treat cygwin the same as mingw
+	DLLs.
+
+	* */Makefile.in, install-sh: Update to automake 1.8.3.
+	* ltmain.sh, aclocal.m4, configure: Update to libtool 1.5.6.
+
+	* gmp-impl.h (LIMB_HIGHBIT_TO_MASK): Use a compile-time constant
+	expression, rather than a configure test.
+	* acinclude.m4, configure.in (GMP_C_RIGHT_SHIFT): Remove, no longer
+	needed.
+	* tests/t-hightomask.c: New file.
+	* tests/Makefile.am (check_PROGRAMS): Add it.
+
+	* macos/configure (parse_top_configure): Look for PACKAGE_NAME and
+	PACKAGE_VERSION now used by autoconf.
+	(what_objects): Only demand 9 object files, as for instance occurs in
+	the scanf directory.
+	(asm files): Transform labels L(foo) -> Lfoo.  Take func name from
+	PROLOGUE to support empty "EPILOGUE()".  Recognise and substitute
+	register name "define()"s.
+	* macos/Makefile.in (CmnObjs): Add tal-notreent.o.
+
+2004-04-19  Torbjorn Granlund  <tege@swox.com>
+
+	* tune/speed.h (SPEED_ROUTINE_MPN_ROOTREM): New #define.
+	(speed_mpn_rootrem): Declare.
+	* tune/common.c (speed_mpn_rootrem): New function.
+	* tune/speed.c (routine): Add entry for mpn_rootrem.
+
+2004-04-16  Kevin Ryde  <kevin@swox.se>
+
+	* doc/fdl.texi: Update from FSF, just fixing a couple of typos.
+
+	* macos/configure, macos/Makefile.in: Add printf and scanf directories.
+
+	* tests/mpz/t-gcd.c (check_data): New function, exercising K6
+	gcd_finda bug.
+
+2004-04-14  Kevin Ryde  <kevin@swox.se>
+
+	* doc/gmp.texi (Reentrancy, Random State Initialization): Note
+	gmp_randinit use of gmp_errno is not thread safe.  Reported by Vincent
+	Lefèvre.
+
+	* doc/gmp.texi (Random State Initialization): Add index entries for
+	gmp_errno and constants.
+
+	* mpn/m68k/README: Update _SHORT_LIMB -> __GMP_SHORT_LIMB.
+
+	* configure.in (--enable-mpbsd): Typo Berkley -> Berkeley in help msg.
+
+2004-04-12  Kevin Ryde  <kevin@swox.se>
+
+	* demos/perl/GMP.xs (static_functable): New macro, use it for all
+	function tables, to support mingw DLL builds.
+	* demos/perl/INSTALL (NOTES FOR PARTICULAR SYSTEMS): Remove note on
+	DLLs, should be ok now.
+
+	* demos/perl/sample.pl: Print the module and library versions in use.
+
+	* demos/perl/GMP.pm, Makefile.PL (VERSION): Set to '2.00'.
+	* demos/perl/GMP.pm (COPYRIGHT): New in the doc section.
+
+	* Makefile.am: Note 4.1.3 libtool versioning info, and REVISION policy.
+
+	* tal-debug.c: Add <stdlib.h> for abort.
+
+2004-04-07  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/refmpf.c (refmpf_add_ulp): Adjust exponent when needed.
+
+	* mpn/generic/random2.c: Rewrite (clone mpz/rrandomb.c).
+
+2004-04-07  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/x86/k6/gcd_finda.asm: Correction jbe -> jb in initial setups.
+	Zero flag is wrong here, it relects only the high limb of the compare,
+	leading to n1>=n2 not satisfied and wrong results.  cp[1]==0x7FFFFFFF
+	with cp[0]>=0x80000001 provokes this.
+
+	* doc/gmp.texi (BSD Compatible Functions): Note "pow" name clash under
+	the pow function description too.
+	(Language Bindings): Add XEmacs (betas at this stage).  Reported by
+	Jerry James.
+
+	* tests/refmpn.c (refmpn_mod2): Correction to ASSERTs, r==a is allowed.
+
+	* gen-psqr.c (generate_mod): Cast mpz_invert_ui_2exp args, for K&R.
+	* gen-bases.c, gen-fib.c, gen-psqr.c: For mpz_out_str, use stdout
+	instead of 0, in case a K&R treats int and FILE* params differently.
+
+2004-04-04  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-impl.h (BSWAP_LIMB) [amd64]: New macro.
+	(FORCE_DOUBLE): Use this for amd64 too.
+
+	* tests/amd64check.c, tests/amd64call.asm: New files, derived in part
+	from x86check.c and x86call.asm.
+	* tests/Makefile.am (EXTRA_libtests_la_SOURCES): Add them.
+	* configure.in (x86_64-*-* ABI=64): Use them.
+
+2004-04-03  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/amd64/mode1o.asm: New file.
+	* mpn/amd64/amd64-defs.m4 (ASSERT): New macro.
+
+	* mpn/x86/k7/mmx/divrem_1.asm, mpn/x86/pentium4/sse2/divrem_1.asm: Add
+	note on how "dr" part of algorithm is handled.
+
+	* mpn/x86/k7/dive_1.asm, mpn/x86/k7/mod_34lsub1.asm,
+	mpn/x86/k7/mode1o.asm: Note Hammer (32-bit mode) speeds.
+
+2004-03-31  Kevin Ryde  <kevin@swox.se>
+
+	* doc/gmp.texi (Language Bindings): Add GOO, MLGMP and Numerix.
+
+	* mpf/mul_2exp.c, mpf/div_2exp.c: Rate u==0 as UNLIKELY.
+
+2004-03-28  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/amd64/divrem_1.asm: Trim a few cycles.
+
+2004-03-27  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/amd64/sublsh1_n.asm: Fix typo.
+
+	* mpn/generic/divrem_1.c: Fix typo.
+
+	* mpn/generic/sqr_basecase.c: Fix typo.
+
+	* mpn/amd64/divrem_1.asm: New file.
+
+2004-03-20  Kevin Ryde  <kevin@swox.se>
+
+	* longlong.h (power, powerpc): Add comments on how we select this code.
+
+	* gmp-h.in (mpz_get_ui): Use ?: instead of mask style, gcc treats the
+	two identically but ?: is a bit clearer.
+
+	* insert-dbl.c: Remove file, no longer used, scaling is now integrated
+	in mpn_get_d.
+	* Makefile.am (libgmp_la_SOURCES): Remove insert-dbl.c.
+	* gmp-impl.h (__gmp_scale2): Remove prototype.
+
+2004-03-17  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/x86/fat/fat.c (__gmpn_cpuvec_init, fake_cpuid_table): Add x86_64.
+
+	* mpq/get_d.c: Use mpn_tdiv_qr, demand den>0 per canonical form.
+
+2004-03-16  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/sqr_basecase.c: Add versions using mpn_addmul_2 and
+	mpn_addmul_2s.
+
+2004-03-14  Kevin Ryde  <kevin@swox.se>
+
+	* mpf/mul_ui.c: Incorporate carry from low limbs, for exactness.
+	* tests/mpf/t-mul_ui.c: New file.
+	* tests/mpf/Makefile.am (check_PROGRAMS): Add it.
+
+	* mpf/div.c: Use mpn_tdiv_qr.  Use just one TMP_ALLOC.  Use full
+	divisor, since truncating can lose accuracy.
+	* tests/mpf/t-div.c: New file.
+	* tests/mpf/Makefile.am (check_PROGRAMS): Add it.
+
+	* tests/mpf/t-set_q.c, tests/mpf/t-ui_div.c (check_various): Amend
+	bogus 99/4 test.
+	* tests/mpf/t-ui_div.c (check_rand): Exercise r==v overlap.
+
+	* tests/refmpf.c, tests/tests.h (refmpf_set_overlap): New function.
+
+	* mpf/cmp_si.c [nails]: Correction, cast vval in exp comparisons, for
+	when vval=-0x800..00 and limb==longlong.
+
+	* mpf/cmp_si.c [nails]: Correction, return usign instead of 1 when
+	uexp==2 but value bigger than an mp_limb_t.
+	* tests/mpf/t-cmp_si.c (check_data): Add test cases.
+
+	* tests/trace.c (mpf_trace): Use ABS(mp_trace_base) to allow for
+	negative bases used for upper case hex in integer traces.
+
+2004-03-12  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/sb_divrem_mn.c: Correct header comment.
+
+2004-03-11  Kevin Ryde  <kevin@swox.se>
+
+	* aclocal.m4, configure, ltmain.sh: Downgrade to libtool 1.5, version
+	1.5.2 doesn't remove .libs/*.a files when rebuilding, which is bad for
+	development when changing contents or with duplicate named files like
+	we have.
+
+	Revert this, ie restore AR_FLAGS=cq:
+	* acinclude.m4 (GMP_PROG_AR): Remove AR_FLAGS=cq, libtool 1.5.2 now
+	does this itself on detecting duplicate object filenames in piecewise
+	linking mode.
+
+	* randbui.c, randmui.c [longlong+nails]: Correction to conditionals
+	for second limb.
+
+	* mpz/aors_ui.h, mpz/cdiv_q_ui.c, mpz/cdiv_qr_ui.c, mpz/cdiv_r_ui.c,
+	mpz/cdiv_ui.c, mpz/fdiv_q_ui.c, mpz/fdiv_qr_ui.c, mpz/fdiv_r_ui.c,
+	mpz/fdiv_ui.c, mpz/gcd_ui.c, mpz/iset_ui.c, mpz/lcm_ui.c,
+	mpz/set_ui.c, mpz/tdiv_q_ui.c, mpz/tdiv_qr_ui.c, mpz/tdiv_r_ui.c,
+	mpz/tdiv_ui.c, mpz/ui_sub.c, mpf/div_ui.c, mpf/mul_ui.c
+	[longlong+nails]: Amend #if to avoid warnings about shift amount.
+
+2004-03-07  Kevin Ryde  <kevin@swox.se>
+
+	* mpf/reldiff.c: Use rprec+ysize limbs for d, to ensure accurate
+	result.  Inline mpf_abs(d,d) and mpf_cmp_ui(x,0), and rate the latter
+	UNLIKELY.
+
+	* mpf/ui_div.c: Use mpn_tdiv_qr.  Use just one TMP_ALLOC.  Use full
+	divisor, since truncating can lose accuracy.
+	* tests/mpf/t-ui_div.c: New file.
+	* tests/mpf/Makefile.am (check_PROGRAMS): Add it.
+
+	* mpf/set_q.c: Expand TMP_ALLOC_LIMBS_2, to make conditional clearer
+	and avoid 1 limb alloc when not wanted.
+
+	* gmp-impl.h (WANT_TMP_DEBUG): Define to 0 if not defined.
+	(TMP_ALLOC_LIMBS_2): Use "if" within macro rather than "#if", for less
+	preprocessor conditionals.
+
+	* mpf/mul_2exp.c, mpf/div_2exp.c: Add some comments.
+
+	* tests/refmpn.c (refmpn_sb_divrem_mn, refmpn_tdiv_qr): Nailify.
+
+2004-03-04  Kevin Ryde  <kevin@swox.se>
+
+	* gen-psqr.c (print): Add CNST_LIMB in PERFSQR_MOD_TEST, for benefit
+	of K&R.
+	* tests/mpn/t-perfsqr.c (PERFSQR_MOD_1): Use CNST_LIMB for K&R.
+
+	* doc/configuration (Configure): Remove mkinstalldirs, no longer used.
+
+	* acinclude.m4 (GMP_PROG_AR): Remove AR_FLAGS=cq, libtool 1.5.2 now
+	does this itself on detecting duplicate object filenames in piecewise
+	linking mode.
+
+	* configure.in (hppa2.0*-*-*): Test sizeof(long) == 4 or 8 to verify
+	ABI=2.0n versus ABI=2.0w.  In particular this lets CC=cc_bundled
+	correctly fall back to ABI=2.0n (we don't automatically add CC=+DD64
+	to that compiler, currently).
+
+	* doc/gmp.texi (Reentrancy): Note C++ mpf_class constructors using
+	global default precision.
+	(Random State Miscellaneous): Describe gmp_urandomb_ui as giving N
+	bits.
+	(C++ Interface Floats): Describe operator= copying the value, not the
+	precision, and what this can mean about copy constructor versus
+	default constructor plus assignment.
+
+	* mpf/set_q.c: Use mpn_tdiv_qr rather than mpn_divrem, so no shifting.
+	Don't truncate the divisor, it can make the result inaccurate.
+	* tests/mpf/t-set_q.c: New file.
+	* tests/mpf/Makefile.am (check_PROGRAMS): Add it.
+
+	* mpf/set.c: Use MPN_COPY_INCR, in case r==u and ABSIZ(u) > PREC(r)+1.
+	No actual bug here, because MPN_COPY has thusfar been an alias for
+	MPN_COPY_INCR, only an ASSERT failure.
+	* tests/mpf/t-set.c: New file.
+	* tests/mpf/Makefile.am (check_PROGRAMS): Add it.
+
+	* mpf/set.c, mpf/iset.c: Do MPN_COPY last, for possible tail call.
+
+	* mpf/set_d.c: Rate d==0 as UNLIKELY.  Store size before extract call,
+	to shorten lifespan of "negative".
+
+	* mpf/init.c, mpf/init2.c, mpf/iset_d.c, mpf/iset_si.c,
+	mpf/iset_str.c, mpf/iset_ui.c: Store prec before alloc call, for one
+	less live quantity across that call.
+	* mpf/init.c, mpf/init2.c, mpf/iset_str.c: Store size and exp before
+	alloc call, to overlap with other operations.
+
+	* tests/refmpf.c, tests/tests.h (refmpf_fill, refmpf_normalize,
+	refmpf_validate, refmpf_validate_division): New functions.
+
+	* tests/refmpn.c, tests/tests.h (refmpn_copy_extend,
+	refmpn_lshift_or_copy_any, refmpn_rshift_or_copy_any): New functions.
+
+	* tal-debug.c: Add <string.h> for strcmp.
+
+	* tests/cxx/t-istream.cc (check_mpz, check_mpq, check_mpf): Use size_t
+	for loop index, to quieten g++ warning.
+
+2004-03-02  Kevin Ryde  <kevin@swox.se>
+
+	* tests/mpn/t-hgcd.c: Use __GMP_PROTO on prototypes.
+
+2004-03-01  Torbjorn Granlund  <tege@swox.com>
+
+	With Karl Hasselström:
+	* mpn/generic/dc_divrem_n.c (mpn_dc_div_2_by_1): New function, with
+	meat from old mpn_dc_divrem_n.  Accept scratch parameter.  Rewrite to
+	avoid a recursive call.
+	(mpn_dc_div_3_by_2): New function, with meat from old
+	mpn_dc_div_3_halves_by_2.  Accept scratch parameter.
+	(mpn_dc_divrem_n): Now just allocate scratch space and call new
+	mpn_dc_div_2_by_1.
+
+2004-02-29  Kevin Ryde  <kevin@swox.se>
+
+	* longlong.h (count_leading_zeros) [alpha gcc]: New version, inlining
+	mpn/alpha/cntlz.asm cmpbge technique.
+
+	* aclocal.m4, configure, install-sh, missing, ltmain.sh,
+	*/Makefile.in: Update to automake 1.8.2 and libtool 1.5.2.
+
+	* doc/gmp.texi (C++ Interface Integers): Note / and % rounding follows
+	C99 / and %.
+	(Exact Remainder): Index entries for divisibility testing algorithm.
+
+	* tune/time.c (speed_endtime): Return 0.0 for negative time measured.
+	Revise usage comments for clarity.
+	* tune/common.c (speed_measure): Recognise speed_endtime 0.0 for
+	failed measurement.
+
+	* tests/mpn/t-get_d.c (check_rand): Correction to nhigh_mask setup.
+
+2004-02-27  Torbjorn Granlund  <tege@swox.com>
+
+	* tune/tuneup.c (tune_dc, tune_set_str): Up param.step_factor.
+
+	* tests/mpz/t-gcd.c: Decrease # of tests to 50.
+
+2004-02-27  Kevin Ryde  <kevin@swox.se>
+
+	* tests/devel/try.c: Add a comment that this is not for Cray systems.
+
+	* mpf/set_q.c: Don't support den(q)<0, demand canonical form in the
+	usual way.
+
+2004-02-24  Torbjorn Granlund  <tege@swox.com>
+
+	From Kevin:
+	* mpn/generic/mul_fft.c (mpn_fft_add_modF): Loop until normalization
+	criterion met.
+
+2004-02-22  Kevin Ryde  <kevin@swox.se>
+
+	* acinclude.m4 (GMP_PROG_CC_WORKS, GMP_OS_X86_XMM, GMP_PROG_CXX_WORKS):
+	Remove files that might look like compiler output, so our "||"
+	alternatives are not fooled.
+
+	* acinclude.m4 (GMP_PROG_CC_WORKS): Add test for lshift_com code
+	mis-compiled by certain IA-64 HP cc at +O3.
+
+	* gmp-impl.h (USE_LEADING_REGPARM): Disable under prof or gprof, for
+	the benefit of freebsd where .mcount clobbers registers.  Spotted by
+	Torbjorn.
+	* configure.in (WANT_PROFILING_PROF, WANT_PROFILING_GPROF): New
+	AC_DEFINEs.
+
+2004-02-21  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (sparc64-*-*bsd*): Amend -m32 setup for ABI=32, so it's
+	not used in ABI=64 on the BSD systems.
+
+2004-02-18  Niels Möller  <nisse@lysator.liu.se>
+
+	* tests/mpz/t-gcd.c (gcdext_valid_p): New function.
+	(ref_mpz_gcd): Deleted function.
+	(one_test): Rearranged to call mpz_gcdext first, so that the
+	returned value can be validated.
+	(main): Don't use ref_mpz_gcd.
+
+2004-02-18  Torbjorn Granlund  <tege@swox.com>
+
+	* gmp-impl.h (MPN_TOOM3_MAX_N): Move to !WANT_FFT section.
+
+	* tests/mpz/t-mul.c: Exclude special huge operands unless WANT_FFT.
+
+	* mpz/rrandomb.c (gmp_rrandomb): Rewrite.
+
+	* mpn/generic/mul_n.c (mpn_toom3_sqr_n): Remove write-only variable c5.
+
+2004-02-18  Kevin Ryde  <kevin@swox.se>
+
+	* mpf/iset_si.c, mpf/iset_ui.c, mpf/set_si.c, mpf/set_ui.c [nails]:
+	Always store second limb, to avoid a conditional.
+
+	* tests/mpf/t-get_ui.c: New file.
+	* tests/mpf/Makefile.am (check_PROGRAMS): Add it.
+	* tests/mpf/t-get_si.c (check_limbdata): Further tests.
+	* gmp-impl.h (MP_EXP_T_MAX, MP_EXP_T_MIN): New defines.
+
+	* mpf/get_ui.c, mpf/get_si.c: Remove size==0 test, it's covered by
+	other conditions.  Attempt greater clarity by expressing conditions as
+	based on available data range.
+	* mpf/get_si.c [nails]: Correction, don't bail on exp > abs_size,
+	since may still have second limb above radix point available.
+	* mpf/get_ui.c: Nailify.
+
+2004-02-16  Kevin Ryde  <kevin@swox.se>
+
+	* mpz/scan0.c, mpz/scan1.c: Use count_trailing_zeros, instead of
+	count_leading_zeros on limb&-limb.
+
+	* mpf/sqrt.c: Use "/ 2" for exp, avoiding C undefined behaviour on
+	">>" of negatives.  Correction to comment, exp is rounded upwards.
+	SIZ(r) always prec now, no need for tsize expression.  Store EXP(r)
+	and SIZ(r) where calculated to reduce variable lifespans.  Make tsize
+	mp_size_t not mp_exp_t, though of course those are currently the same.
+
+	* gmp-h.in (GMP_ERROR_ALLOCATE, GMP_ERROR_BAD_STRING,
+	GMP_ERROR_UNUSED_ERROR): Remove, never used or documented, and we
+	don't want to use globals for communicating error information.
+
+	* mpz/gcd_ui.c [nails]: Correction, actually return a value.
+
+	* mpn/generic/addmul_1.c, mpn/generic/submul_1.c [nails==1]: Add code.
+
+2004-02-15  Kevin Ryde  <kevin@swox.se>
+
+	* tests/mpz/t-jac.c (check_data): Remove unnecessary variable
+	"answer".
+
+2004-02-14  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/ia64/aors_n.asm: Break a group with a RAW conflict.
+
+2004-02-14  Kevin Ryde  <kevin@swox.se>
+
+	* acinclude.m4 (GMP_C_RIGHT_SHIFT): Note that it's "long"s which we're
+	concerned about.
+
+	* mpn/generic/mul_n.c: Add some remarks about toom3 high zero
+	stripping.
+
+	* mpn/generic/scan0.c, mpn/generic/scan1.c: Remove design issue
+	remarks.  What to do about going outside `up' space is a problem, but
+	anything to address it would be an incompatible change.
+
+2004-02-12  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/mpn/t-hgcd.c: Remove unused variables.
+
+	* mpn/ia64/hamdist.asm: Remove bundling incompatible with HP-UX
+	assembler.  Misc HP-UX changes.
+	* mpn/ia64/gcd_1.asm: Add some syntax to placid the HP-UX assembler.
+
+2004-02-11  Kevin Ryde  <kevin@swox.se>
+
+	* longlong.h (power, powerpc): Use HAVE_HOST_CPU_FAMILY_power and
+	HAVE_HOST_CPU_FAMILY_powerpc rather than various cpp defines.
+
+	* gmp-impl.h: Add remarks about limits.h and Cray etc.
+
+	* mpn/ia64/mul_1.asm: Don't put .pred directives on labelled lines,
+	hpux 11.23 assembler doesn't like that.
+	* mpn/ia64/README: Add a note on this.
+
+	* dumbmp.c (mpz_mul): Set ALLOC(r) for new data block used.  Reported
+	by Jason Moxham.
+
+	* mpn/pa32/README, mpn/pa64/README (REFERENCES): New sections.
+
+2004-02-10  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/mpz/t-gcd.c: Decrease # of tests run.
+
+	* mpn/*/gmp-mparam.h: Add HGCD values, update TOOM values.
+
+2004-02-01  Torbjorn Granlund  <tege@swox.com>
+
+	From Kevin:
+	* config.guess: Recognize AMD's hammer processors, return x86_64.
+
+2004-01-31  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/hgcd.c (mpn_cmp_sum3): Declare static.
+
+2004-01-25  Niels Möller  <nisse@lysator.liu.se>
+
+	* tests/mpn/Makefile.am (check_PROGRAMS): Add t-hgcd.
+
+	* mpn/generic/hgcd.c (hgcd_jebelean): Simplify, use mpn_cmp_sum3.
+	(mpn_cmp_sum3): New function.
+	(mpn_diff_smaller_p): Remove.
+	(hgcd_final, hgcd_jebelean, hgcd_small_1, hgcd_small_2, euclid_step):
+	Remove tp,talloc arguments.  Callers changed.
+
+2004-01-25  Torbjorn Granlund  <tege@swox.com>
+
+	* tune/tuneup.c (all): Reenable calls of tune_gcd_schoenhage and
+	tune_hgcd.
+
+	* mpn/generic/gcd.c: Reenable Schoenhage code.
+
+	With Niels Möller:
+	* mpn/generic/hgcd.c: Add const and inline to several functions.
+	(qstack_push_start qstack_push_end qstack_push_quotient): Remove.
+	(euclid_step): Insert removed functions here.
+	(hgcd_adjust): Simplify, don't handle d != 1.
+	(qstack_adjust): Corresponding changes.
+	(mpn_hgcd2_lehmer_step): Remove redundant tests for bh against zero.
+	(hgcd_start_row_p): Tweak.
+	(hgcd_final): Shorten life of ralloc.
+
+2004-01-24  Kevin Ryde  <kevin@swox.se>
+
+	* tests/mpf/t-sqrt.c (check_rand1): Further diagnostic printouts.
+
+	* mpn/generic/sqrtrem.c (mpn_sqrtrem): Add ASSERT_MPN.
+	(mpn_dc_sqrtrem): Add casts for K&R.
+
+	* mpf/sqrt_ui.c: Nailify.
+
+	* mpf/set_z.c: Do MPN_COPY last, for possible tail call.
+
+	* doc/gmp.texi (Miscellaneous Float Functions): For mpf_random2, note
+	exponent is in limbs.
+
+	* mpn/ia64/README: Add remark about concentrating on itanium-2.
+
+2004-01-22  Kevin Ryde  <kevin@swox.se>
+
+	* mpf/sqrt.c: Change tsize calculation to get prec limbs result
+	always, previously got prec+1 when exp was odd.
+	* tests/mpf/t-sqrt.c (check_rand1): New function, code from main.
+	(check_rand2): New function.
+
+	* mpf/sqrt_ui.c: Change rsize calculation to get prec limbs result,
+	previously got prec+1.
+	* tests/mpf/t-sqrt_ui.c: New file.
+	* tests/mpf/Makefile.am (check_PROGRAMS): Add it.
+
+	* tests/refmpf.c, tests/tests.h (refmpf_add_ulp,
+	refmpf_set_prec_limbs): New functions.
+
+	* mpz/get_d_2exp.c, mpf/get_d_2exp.c: Remove x86+m68k force to double,
+	mpn_get_d now does this.  Remove res==1.0 check for round upwards,
+	mpn_get_d now rounds towards zero.  Move exp store to make mpn_get_d a
+	tail call.
+
+	* configure.in (x86-*-*): Use ABI=32 rather than ABI=standard.
+	Use gcc -m32 when available, to force mode on bi-arch amd64 gcc.
+	* configure.in, acinclude.m4 (x86_64-*-*): Merge into plain x86 setups
+	as ABI=64.  Support ABI=32, using athlon code.  Use gcc -mcpu=k8,
+	-march=k8.
+	(amd64-*-*): Remove pattern, config.sub only gives x86_64.
+	* doc/gmp.texi (ABI and ISA): Add x86_64 dual ABIs.
+
+	* mpn/amd64/README: Add reference to ABI spec.
+
+2004-01-17  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/hgcd.c (hgcd_adjust): Backed out mpn_addlsh1_n
+	change for now.
+
+	* mpn/generic/hgcd.c (hgcd_adjust): Fixed calls of mpn_addlsh1_n.
+
+2004-01-17  Kevin Ryde  <kevin@swox.se>
+
+	* tune/README: Remove open/mpn versions of toom3, no longer exist.
+	* tune/powerpc64.asm: Remove unused L(again).
+	* tune/time.c (mftb): Note single mftb possible for powerpc64.
+
+	* mpn/generic/mode1o.c: Use "c<s" to do underflow detection in last
+	step, for better parallelism.
+
+	* mpn/generic/get_d.c: Preserve comments about hppa fcnv,udw,dbl from
+	previous mpz_get_d code.
+
+	* tune/freq.c: Add some comments about systems not covered.
+
+	* gmp-h.in (_GMP_H_HAVE_FILE): Add _MSL_STDIO_H for Metrowerks.
+	Reported by Tomas Zahradnicky.
+
+2004-01-16  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/hgcd.c (mpn_diff_smaller_p): Use MPN_DECR_U.
+	(hgcd_adjust): Use mpn_addlsh1_n when available.
+
+2004-01-16  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (powerpc64-*-linux*): Try gcc64.  Try -m64 with
+	"cflags_maybe" to get it used in all probing.  Add sizeof-long-8 test
+	to check the mode is right if -m64 is not applicable.
+
+2004-01-15  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (--with-readline=detect): Check for readline/readline.h
+	and readline/history.h.  Report result of detection.
+
+2004-01-14  Niels Möller  <nisse@lysator.liu.se>
+
+	* tune/speed.c (routine): Disabled speed_mpn_hgcd_lehmer.
+	* tune/common.c (speed_mpn_hgcd_lehmer): Disabled function.
+
+	* mpn/generic/hgcd.c (mpn_hgcd_lehmer_itch, mpn_hgcd_lehmer)
+	(mpn_hgcd_equal): Deleted functions.
+
+	* mpn/generic/gcd.c (hgcd_start_row_p): Deleted function.
+	(gcd_schoenhage): Deleted assertion code using mpn_hgcd_lehmer.
+
+	* mpn/generic/hgcd.c (hgcd_final): Fixed ASSERT typos.
+	(mpn_hgcd): To use Lehmer's algorithm, call hgcd_final directly,
+	not mpn_hgcd_lehmer.
+
+	* mpn/generic/gcd.c (gcd_schoenhage): Updated for changes to
+	mpn_hgcd and mpn_hgcd_fix. (Schoenhage code is still disabled).
+
+	* gmp-impl.h (mpn_hgcd_fix): Updated prototype.
+
+	* mpn/generic/hgcd.c (mpn_hgcd_fix): Replaced a bunch of arguments
+	by a pointer const struct hgcd_row *s. Updated callers.
+
+	* mpn/generic/hgcd.c (hgcd_start_row_p): Use const for the input.
+	Moved function definition before hgcd_jebelean.
+	(hgcd_jebelean): Interface change, analogous to hgcd2.
+	(mpn_hgcd_fix): Normalize v. Require that v > 0.
+	(hgcd_adjust): Fix bug in carry update.
+	(mpn_hgcd): Reorganized again, to adapt to mpn_hgcd/hgcd_jebelean
+	now sometimes returning 1. Reintroduced hgcd_adjust.
+
+	* mpn/generic/hgcd.c (hgcd_final): Streamlined logic for the first
+	hgcd2 call.
+
+	* mpn/generic/hgcd2.c (mpn_hgcd2): Interface change. Return 1
+	instead of 2, in the no progress case r0=A, r1=B.
+
+	* mpn/generic/hgcd.c (hgcd_adjust): Changed arguments and return
+	value. Now takes a struct hgcd_row * and the uv size, and returns
+	updated uvsize.
+	(hgcd_final): Special handling of the case hgcd2 returning 1. Now
+	uses hgcd_adjust, instead of a full Euclid division.
+
+2004-01-13  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/hgcd.c (euclid_step, hgcd_case0): Merged into a
+	single function euclid_step.
+	(mpn_hgcd): Reorganized the logic for the second recursive call.
+	Avoid unnecessary Euclid steps.
+
+	* tests/mpn/t-hgcd.c (hgcd_values): One more test value.
+
+	* tests/mpn/t-hgcd.c (hgcd_values): Added values that trigged the
+	hgcd_jebelean bug.
+
+	* mpn/generic/hgcd.c (hgcd_jebelean): Fixed off by one error.
+	(mpn_hgcd): Simplified the logic for the first recursive call. Now
+	it uses only the correct values from the recursive call, and
+	doesn't do tricks with hgcd_adjust (hgcd_adjust will probably be
+	reintroduced later, though).
+
+	* tests/mpn/t-hgcd.c (mpz_mpn_equal, hgcd_ref_equal)
+	(hgcd_ref_init, hgcd_ref_clear): New functions.
+	(hgcd_ref): Reference implementation of hgcd, using mpz.
+	(one_test): Use hgcd_ref. Don't use mpn_hgcd_lehmer.
+	(main): Skip one_step if both input values are zero.
+
+2004-01-12  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/hgcd.c (hgcd_final): Rewritten, now uses Lehmer
+	steps instead of a division loop.
+	(mpn_hgcd_lehmer): Deleted old Lehmer code, instead just
+	initialize and then call hgcd_final.
+
+	* tests/tests.h: Added refmpn_free_limbs prototype.
+	* tests/refmpn.c (refmpn_free_limbs): New function.
+
+	* tests/mpn/t-hgcd.c: Try the same kind of random inputs as for
+	mpz/t-gcd.
+
+2004-01-11  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/hgcd.c (mpn_hgcd_lehmer): Rewritten, after some more
+	analysis of the size reduction for one Lehmer step.
+
+	* tests/mpn/t-hgcd.c: New file.
+
+2004-01-11  Torbjorn Granlund  <tege@swox.com>
+
+	With Niels Möller:
+	* mpn/generic/hgcd.c (hgcd_normalize): Fix ASSERTs.
+	(hgcd_mul): Normalize R[1].uvp[1].  Add some more ASSERTs.
+	(hgcd_update_uv): Streamline.  ASSERT that input and output is
+	normalized.
+
+2004-01-11  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/alpha/ev6/slot.pl: New file, derived in part from
+	mpn/x86/k6/cross.pl.
+
+	* mpn/alpha/alpha-defs.m4 (ASSERT): New macro.
+
+	* mpn/asm-defs.m4 (m4_ifdef): New macro, avoiding OSF 4.0 m4 bug.
+	(m4_assert_defined): Use it.
+
+	* mpn/alpha/default.m4, mpn/alpha/unicos.m4 (LDGP): New macro.
+	* mpn/alpha/ev67/gcd_1.asm: Use it to re-establish gp after jsr.
+
+	* configure.in, demos/calc/Makefile.am: Use -lcurses or -lncurses with
+	readline, when available.
+
+	* longlong.h (sub_ddmmss) [generic]: Use al<bl for the borrow rather
+	than __x>al, since the former can be done without waiting for __x,
+	helping superscalar chips, in particular alpha ev5 and ev6.
+
+	* longlong.h (sub_ddmmss) [ia64]: New macro.
+
+	* tests/t-sub.c: New file.
+	* tests/Makefile.am (check_PROGRAMS): Add it.
+	* tests/refmpn.c, tests/tests.h (refmpn_sub_ddmmss): New function.
+
+2004-01-09  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/x86/p6/mod_34lsub1.asm: New file, derived in part from
+	mpn/x86/mod_34lsub1.asm.
+
+	* configure.in (IA64_PATTERN): Use -mtune on gcc 3.4.
+
+2004-01-07  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-h.in, mp-h.in (__GMP_SHORT_LIMB): Renamed from _SHORT_LIMB, to
+	keep in our namespace.  (Not actually used anywhere currently.)
+	Reported by Patrick Pelissier.
+
+	* mp-h.in: Use "! defined (__GMP_WITHIN_CONFIGURE)" in the same style
+	as gmp-h.in (though mp-h.in is not actually used during configure).
+
+	* mp-h.in (__GMP_DECLSPEC_EXPORT, __GMP_DECLSPEC_IMPORT) [__GNUC__]:
+	Use __dllexport__ and __dllimport__ to keep out of application
+	namespace.  Same previously done in gmp-h.in.
+
+2004-01-06  Kevin Ryde  <kevin@swox.se>
+
+	* configfsf.sub, configfsf.guess: Update to 2004-01-05.
+	* configure.in (amd64-*-* | x86_64-*-*): Update comments on what
+	configfsf.sub does.
+
+2004-01-04  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/alpha/README (REFERENCES): Add tru64 assembly manuals.
+	(ASSEMBLY RULES): Note what gcc says about !literal! etc.
+
+2004-01-03  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/alpha/ev67/gcd_1.asm: New file.
+
+	* mpn/x86/pentium4/sse2/rsh1add_n.asm: New file, derived in part from
+	mpn/x86/pentium4/sse2/addlsh1_n.asm.
+
+	* mpn/x86/p6/p3mmx/popham.asm: Note measured speeds.
+
+	* mpn/ia64/hamdist.asm: Correction to inputs vs locals in alloc (makes
+	no difference to the generated code).  Corrections to a couple of
+	comments.
+
+	* mpn/x86/pentium4/sse2/addlsh1_n.asm (PARAM_CARRY): Remove macro, not
+	used, no such parameter.
+
+	* mpn/generic/gcd.c: Use <stdio.h> for NULL.
+
+	* doc/gmp.texi (Single Limb Division): Correction to tex expression
+	for (1/2)x1.  And minor wording tweaks elsewhere.
+
+	* gmp-impl.h (mpn_rsh1add_n, mpn_rsh1sub_n): Correction to comments
+	about how carries returned.
+
+	* longlong.h (umul_ppmm) [generic]: Add comments about squaring
+	(dropped from tasks list)
+
+2003-12-31  Kevin Ryde  <kevin@swox.se>
+
+	* demos/perl/GMP.xs (scan0, scan1): Return ~0 for not-found.
+	* demos/perl/GMP.pm: Describe this, remove the note about ULONG_MAX
+	being the same as ~0 (which is not true in old perl).
+	* demos/perl/test.pl: Update tests.
+	* demos/perl/typemap (gmp_UV): New type.
+
+	* demos/perl/test.pl (fits_slong_p): Comment out uv_max test, it won't
+	necessarily exceed a long.
+
+	* demos/perl/GMP.pm: Add a remark about get_str to the bugs section.
+
+	* mpn/generic/sqrtrem.c, mpz/fac_ui.c, tests/mpf/reuse.c: Add casts
+	for K&R.
+	* tests/mpf/t-muldiv.c: Make ulimb, vlimb into ulongs, which is how
+	they're used, for the benefit of K&R calling.
+
+	* doc/gmp.texi (Square Root Algorithm): Add a summary of the algorithm.
+	And add further index entries in various places.
+
+	* mpz/lucnum_ui.c, mpz/lucnum2_ui.c: Use mpn_addlsh1_n when available.
+
+	* gmp-impl.h, mpn/generic/mul_n.c (mpn_addlsh1_n, mpn_sublsh1_n,
+	mpn_rsh1add_n, mpn_rsh1sub_n): Move descriptions to gmp-impl.h with
+	the prototypes, for ease of locating.
+
+2003-12-30  Torbjorn Granlund  <tege@swox.com>
+
+	* tune/tuneup.c (all): Disable calls of tune_gcd_schoenhage and
+	tune_hgcd for now.
+
+2003-12-29  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/mpz/t-gcd.c: Rewrite, based on suggestions by Kevin.
+
+	* mpn/ia64/mul_1.asm: Amend TODO list.
+
+	* mpn/sparc64/README: Remove mpn_Xmul_2, done.
+	Add blurb about L1 cache conflicts.
+
+	* mpn/generic/gcd.c: Disable Schoenhage code for now.
+
+2003-12-29  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/generic/mul_fft.c, mpz/root.c, mpq/cmp_ui.c: Add casts for K&R.
+
+2003-12-27  Kevin Ryde  <kevin@swox.se>
+
+	* tests/mpz/t-mul.c (mul_kara, mul_basecase): Use __GMP_PROTO.
+
+	* mpn/generic/gcd.c (NHGCD_SWAP4_2, NHGCD_SWAP3_LEFT),
+	mpn/generic/hgcd.c (HGCD_SWAP4_LEFT, HGCD_SWAP4_RIGHT, HGCD_SWAP4_2,
+	HGCD_SWAP3_LEFT): Aggregate initializers for automatics is an
+	ANSI-ism, avoid.
+
+	* Makefile.am (AUTOMAKE_OPTIONS): Restore this, giving no directory on
+	ansi2knr to avoid a circular build rule.
+	* configure.in (AM_INIT_AUTOMAKE): Note options also in Makefile.am.
+
+	* configure.in (cflags_maybe): Don't loop adding cflags_maybe if the
+	user has set CFLAGS.
+
+2003-12-24  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/gcd.c (gcd_schoenhage_itch): Avoid unary "+".
+	(mpn_gcd): Allocate scratch space on heap for gcd_schoenhage.
+	(mpn_gcd): Don't invoke MPN_NORMALIZE on input operands.
+
+2003-12-23  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (*sparc*-*-*): Test sizeof(long)==4 or 8 for ABIs, to
+	get the right mode when the user sets the CFLAGS.
+	(testlist): Introduce "any_<abi>_testlist" to apply to all compilers.
+
+	* demos/perl/typemap (MPZ_ASSUME, MPQ_ASSUME, MPF_ASSUME): Remove
+	output rules, these are only meant for inputs.
+	(MPZ_MUTATE): Remove, not used since changes for magic.
+
+	* demos/perl/GMP.xs (mpz_class_hv, mpq_class_hv, mpf_class_hv): New
+	variables, initialized in BOOT.
+	* demos/perl/GMP.xs, demos/perl/typemap: Use them and explicit
+	sv_bless, to save a gv_stashpv for every new object.
+
+2003-12-22  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/alpha/mode1o.c, mpn/alpha/dive_1.c: Moved from ev5/mode1o.c and
+	ev5/dive_1.c, these are good for ev4, and would like them in a generic
+	alpha build.
+
+2003-12-21  Kevin Ryde  <kevin@swox.se>
+
+	* doc/gmp.texi (Integer Logic and Bit Fiddling): Say "bitwise" in
+	mpz_and, mpz_ior and mpz_xor, to avoid any confusion with what C means
+	by "logical".  Reported by Rüdiger Schütz.
+
+	* gmp-h.in (_GMP_H_HAVE_FILE): Note why defined(EOF) is not good.
+
+2003-12-20  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/hgcd.c (mpn_diff_smaller_p): Use mpn_cmp instead of
+	mpn_sub_n where possible.  Use mp_size_t for relevant variables.
+
+2003-12-20  Kevin Ryde  <kevin@swox.se>
+
+	* tune/speed.h (SPEED_TMP_ALLOC_LIMBS): Correction to last change,
+	don't want "- 1" on the TMP_ALLOC_LIMBS.
+
+	* demos/expr/expr.h: Test #ifdef MPFR_VERSION_MAJOR for when mpfr.h is
+	included, not GMP_RNDZ which is now an enum.
+
+	* demos/expr/exprfra.c (e_mpfr_ulong_p): Use mpfr_integer_p and
+	mpfr_fits_ulong_p.
+	(e_mpfr_get_ui_fits): Use mpfr_get_ui.
+
+	* mpfr/*: Update to mpfr cvs head 2003-12-20.
+
+	* configure, config.in: Update to autoconf 2.59.
+	* */Makefile.in, configure, aclocal.m4, ansi2knr.c, install-sh,
+	doc/mdate-sh: Update to automake 1.8.
+
+	* mkinstalldirs: Remove, not required by automake 1.8.
+	* doc/gmp.texi (Build Options): HTML is a usual target in automake 1.8.
+
+	* configure.in (AC_PREREQ): Require autoconf 2.59.
+	(AM_INIT_AUTOMAKE): Require automake 1.8.
+	(AC_C_INLINE): Use rather than GMP_C_INLINE, now has #ifndef
+	__cplusplus we want.
+	(gettimeofday): Use AC_CHECK_FUNCS rather than our workaround code,
+	autoconf now ok.
+
+	* acinclude.m4 (GMP_C_INLINE): Remove.
+	(GMP_H_EXTERN_INLINE): Use AC_C_INLINE.
+	(GMP_PROG_AR): Comment on automake $ARFLAGS.
+
+2003-12-19  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/hgcd.c (mpn_diff_smaller_p): Rewrote function. Tried
+	to explain how it works.
+	(slow_diff_smaller_p, wrap_mpn_diff_smaller_p) [WANT_ASSERT]: Use
+	CPP to wrap assertion checks around all calls to
+	mpn_diff_smaller_p.
+
+	* mpn/generic/hgcd.c (mpn_addmul2_n_1) [nails]: Fixed carry handling.
+
+	* mpn/generic/hgcd.c (mpn_diff_smaller_p) [nails]: Use
+	GMP_NUMB_MAX, not MP_LIMB_T_MAX.
+	(mpn_hgcd_itch): Improved size calculation.
+	(mpn_hgcd_max_recursion): Moved function from qstack.c. Should to
+	be recompiled when HGCD_SCHOENHAGE_THRESHOLD is tuned.
+
+	* mpn/generic/qstack.c (mpn_hgcd_max_recursion): ... moved from
+	here.
+
+2003-12-19  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/mpf/t-get_d.c: Print message before aborting.
+
+	* mpn/generic/hgcd2.c (mpn_hgcd2): Substitute always-zero variable
+	with 0.  Remove bogus comment.
+
+	* mpn/generic/get_d.c: Make ONE_LIMB case actually work for nails.
+
+2003-12-18  Niels Möller  <niels@lysator.liu.se>
+
+	* mpn/generic/hgcd.c (hgcd_update_r): Assert that the output r2 is
+	smaller than the input r1.
+
+2003-12-18  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/get_d.c: Don't include longlong.h.
+
+	* tests/mpz/t-mul.c (ref_mpn_mul): Handle un == vn specially, to avoid
+	a dummy r/w outside of allocated area.
+
+2003-12-18  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/alpha/unicos.m4 (ALIGN): Add comments on what GCC does.
+
+	* configure.in (fat setups), acinclude.m4 (GMP_INIT): Obscure
+	include() from automake 1.8 aclocal.
+	* acinclude.m4: Quote names in AC_DEFUN, for automake 1.8 aclocal.
+
+2003-12-17  Niels Möller  <nisse@lysator.liu.se>
+
+	* tune/common.c (speed_mpn_hgcd, speed_mpn_hgcd_lehmer) [nails]:
+	Enabled code also for GMP_NAIL_BITS > 0.
+	* tune/speed.c [nails]: Enable speed_mpn_hgcd and
+	speed_mpn_hgcd_lehmer.
+	* tune/tuneup.c (tune_hgcd) [nails]: Likewise.
+
+	* mpn/generic/gcd.c [nails]: Use Schönhage's algorithm also for
+	GMP_NAIL_BITS > 0.
+
+	* mpn/generic/hgcd.c [nails]: Enable the code for GMP_NAIL_BITS > 0.
+	(MPN_EXTRACT_LIMB) [nails]: Handle nails.
+	(__gmpn_hgcd_sanity): Allocate temporaries on the heap, not on the
+	stack. Also check that r[i] >= r[i+1].
+	(mpn_hgcd2_lehmer_step) [nails]: Handle nails.
+	(mpn_hgcd_lehmer): When we temporarily have r3 > r2, avoid
+	trigging that assert in __gmpn_hgcd_sanity.
+	(mpn_hgcd): Likewise.
+
+	* mpn/generic/hgcd2.c (div2) [nails]: Alternative nail-aware
+	version.
+	(SUB_2): New macro of Kevin's, which reduces do sub_ddmmss in the
+	non-nail case.
+	(HGCD2_STEP): Use SUB_2, not sub_ddmmss. Added alternative version
+	for K&R compilers.
+	(mpn_hgcd2) [nails]: Use SUB_2, not sub_ddmmss. New nail-aware
+	code for checking Jebelean's condition.
+
+2003-12-13  Kevin Ryde  <kevin@swox.se>
+
+	* mpq/get_d.c: Amend comments per mpn_get_d change.
+	(limb2dbl): Remove, no longer used.
+
+	* gmp-impl.h (DIVREM_1_NORM_THRESHOLD etc) [nails]: Correction to
+	comments, MP_SIZE_T_MAX means preinv never.
+
+	* gmp-impl.h (DIVEXACT_1_THRESHOLD, MODEXACT_1_ODD_THRESHOLD) [nails]:
+	Remove overrides, divexact_1 and modexact_1 have been nailified.
+
+	* mpz/inp_str.c (mpz_inp_str_nowhite): Use ASSERT_ALWAYS for EOF value
+	requirement.
+
+	* tests/refmpn.c (refmpn_rsh1add_n, refmpn_rsh1sub_n): Parens around
+	GMP_NUMB_BITS - 1 with ">>", to quieten gcc -Wall.
+	* tests/t-constants.c (main), tests/t-count_zeros.c (check_clz),
+	tests/t-modlinv.c (one), tests/mpz/t-jac.c (try_si_zi),
+	tests/mpq/t-get_d.c (check_onebit): : Correction to printfs.
+	* tests/mpn/t-fat.c: Add <string.h> for memcpy.
+	* tests/mpz/t-scan.c (check_ref): Remove unused variable "isigned".
+	* tests/mpq/t-get_d.c (check_onebit): Remove unused variable "limit".
+	* tests/mpf/t-set_si.c, tests/mpf/t-set_ui.c (check_data): Braces for
+	initializers.
+	* tests/devel/try.c (mpn_divexact_by3_fun, mpn_modexact_1_odd_fun):
+	Correction to return values.
+
+	* doc/gmp.texi (Miscellaneous Integer Functions): Note mpz_sizeinbase
+	can be used to locate the most significant bit.  Reword a bit for
+	clarity.
+
+2003-12-12  Niels Möller  <niels@lysator.liu.se>
+
+	* mpn/generic/hgcd.c (__gmpn_hgcd_sanity): Fixed stack buffer
+	overrun.
+	* mpn/generic/hgcd.c: Improved comments.
+
+2003-12-11  Torbjorn Granlund  <tege@swox.com>
+
+	* gmp-impl.h: Change asm => __asm__, tabify.
+	* mpz/get_d_2exp.c: Likewise.
+	* mpf/get_d_2exp.c: Likewise.
+
+	* tests/cxx/t-ops.cc: #if .. #endif out tests that cause ambiguities.
+
+2003-12-10  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/mpz/t-gcd.c: Generate operands with sizes as a geometric
+	progression, to allow for larger operands and less varying timing.
+
+	* tune/tuneup.c (tune_gcd_schoenhage): Set param.step_factor.
+	(tune_hgcd): Likewise.
+
+2003-12-10  Kevin Ryde  <kevin@swox.se>
+
+	* demos/perl/test.pl: Should be $] for perl version in old perl.
+
+	* configure.in (sparc64-*-*): Single block of gcc configs for all
+	systems, on unknown systems try both ABI 32 and 64.
+
+	* configure.in (LIBGMP_LDFLAGS, LIBGMPXX_LDFLAGS): New AC_SUBSTs with
+	options to generate .def files with windows DLLs.
+	* Makefile.am (libgmp_la_LDFLAGS, libgmpxx_la_LDFLAGS): Use them.
+
+	* mpn/generic/gcd.c: Use ABOVE_THRESHOLD / BELOW_THRESHOLD, to follow
+	convention and cooperate with tune/tuneup.c.
+
+	* tune/tuneup.c (tune_gcd_schoenhage): Increase max_size to 3000, side
+	default 1000 is approx the crossover point on athlon.
+
+	* tune/common.c, tune/speed.c, tune/speed.h, tune/speed-ext.c,
+	tune/tuneup.c (SPEED_TMP_ALLOC_LIMBS): Take variable as parameter
+	rather than returning a value, avoids alloca in a function call.
+	* tune/common.c, tune/speed.h (speed_tmp_alloc_adjust): Remove, now
+	inline in SPEED_TMP_ALLOC_LIMBS, and using ptr-NULL for alignment
+	extraction.
+
+	* gmpxx.h (__gmp_binary_equal, __gmp_binary_not_equal,
+	__gmp_binary_less, __gmp_binary_less_equal, __gmp_binary_greater,
+	__gmp_binary_greater_equal, __gmp_cmp_function): Use mpfr_cmp_si and
+	mpfr_cmp_d.
+	* tests/cxx/t-ops.cc: Exercise this.
+
+	* demos/perl/Makefile.PL: Don't install sample.pl and test2.pl.
+
+	* demos/perl/GMP.xs (use_sv): Prefer PV over IV or NV to avoid any
+	rounding.
+	* demos/perl/test.pl: Exercise this.
+
+	* demos/perl/GMP/Mpf.pm (overload_string): Corrections to $# usage.
+	* demos/perl/test.pl: Exercise this.
+
+2003-12-08  Kevin Ryde  <kevin@swox.se>
+
+	* demos/perl/GMP.pm: Correction to canonicalize example.
+
+	* demos/perl/GMP.xs: New type check scheme, support magic scalars,
+	support UV when available.  Remove some unused local variables.
+	(coerce_long): Check range of double.
+	(get_d_2exp): Remove stray printf.
+
+	* demos/perl/test.pl: Exercise magic, rearrange to make it clearer
+	what's being tested.
+
+2003-12-07  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/generic/hgcd.c (mpn_hgcd): Use BELOW_THRESHOLD, to follow the
+	convention of N<THRESH for the lower algorithm, not <=.  Fixes
+	algorithm selection in tuneup.c.
+
+	* tune/common.c (speed_mpn_hgcd, speed_mpn_hgcd_lehmer): Use intended
+	align_xp, align_yp.
+
+	* tune/tuneup.c (mul_toom3_threshold): Use MUL_TOOM3_THRESHOLD_LIMIT,
+	for the benefit of ASSERT in mpn_mul_n.
+
+	* tune/tuneup.c (tune_mul): Correction to toom3 param.min_size, should
+	use MPN_TOOM3_MUL_N_MINSIZE.
+
+	* tune/speed.c (check_align_option): Correction to printf format.
+	* tune/freq.c (freq_sysctl_hw_model): Remove unused "i" variable.
+
+	* scanf/doscan.c: Correction to a couple of trace printfs.
+	Add <stdlib.h> for strtol.
+
+	* tests/misc/t-scanf.c (test_sscanf_eof_ok): New function.
+	(check_misc): Use it to suppress tests broken by libc.
+	And should be EOF rather than -1 in various places.
+
+2003-12-06  Torbjorn Granlund  <tege@swox.com>
+
+	* tune/common.c (speed_mpn_hgcd, speed_mpn_hgcd_lehmer):
+	Move SPEED_TMP_ALLOC_LIMBS invocations out from calls.
+
+	* mpn/generic/get_str.c (mpn_get_str, POW2_P case):
+	Don't append extra '\0' byte.
+
+2003-12-05  Niels Möller  <niels@lysator.liu.se>
+
+	* tune/common.c (speed_mpn_hgcd_lehmer, speed_mpn_hgcd):
+	Updated for the renaming hgcd_sanity -> ASSERT_HGCD.
+
+	* mpn/generic/gcd.c (gcd_schoenhage): TMP_DECL must be the final
+	declaration in the declaration section of a block.
+
+	* tune/speed.h (mpn_gcd_accel): Added prototype.
+
+2003-12-05  Torbjorn Granlund  <tege@swox.com>
+
+	* randmt.c (__gmp_mt_recalc_buffer): Put parens around "&" expressions
+	inside "!=".
+
+	* mpf/get_str.c: Remove unused variable "fracn".
+
+2003-12-03  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in, Makefile.am (LIBGMP_LDFLAGS, LIBGMPXX_LDFLAGS): New
+	AC_SUBSTs, use them to create .def files with Windows DLLs.
+	* doc/gmp.texi (Notes for Particular Systems): Update notes on mingw
+	DLL with MS C.
+
+	* mpz/export.c: Allow NULL for countp.
+	* doc/gmp.texi (Integer Import and Export): Describe this.
+	Suggested by Jack Lloyd.
+
+	* mpn/x86/p6/aors_n.asm: New file, grabbing the K7 code.
+	Superiority of this reported by Patrick Pelissier.
+
+2003-11-30  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/alpha/ev67/popcount.asm, mpn/alpha/ev67/hamdist.asm: New files.
+
+	* mpn/alpha/ev67: New directory.
+	* configure.in (alphaev67, alphaev68, alphaev7*): Use it.
+
+	* doc/gmp.texi (GMPrefu, GMPpxrefu): Change back to plain ref and
+	pxref, remove macros.
+	(GMPreftopu, GMPpxreftopu): Remove URL parameter, rename to GMPreftop
+	and GMPpxreftop.
+	(Debugging): Remove debauch, seems to have disappeared.
+	(Language Bindings): Corrections to URLs for CLN, Omni F77, Pike.
+
+2003-11-29  Kevin Ryde  <kevin@swox.se>
+
+	* demos/perl/GMP/Mpf.pm (overload_string): Use $OFMT to avoid warnings
+	about $#.
+
+	* demos/perl/GMP.xs (fits_slong_p): Use LONG_MAX+1 to avoid possible
+	rounding of 0x7F..FF in a double on 64-bit systems.
+
+	* configure.in (ppc601-*-*): Remove this case, it never matched
+	anything, the name adopted is powerpc601.
+	(powerpc601-*-*): Use gcc -mcpu=601, xlc -qarch=601.
+
+	* configure.in: Introduce ${cc}_cflags_maybe, used if they work.
+	(*sparc*-*-*) [ABI=32]: Add gcc_cflags_maybe=-m32 to force that mode.
+
+	* doc/gmp.texi (Introduction to GMP): Add AMD64 to optimizations list.
+	(Build Options): Add cpu types alphaev7 and amd64.  Update texinfo
+	html cross reference.
+
+2003-11-28  Niels Möller  <nisse@lysator.liu.se>
+
+	* tune/tuneup.c (tune_hgcd): Disable if GMP_NAIL_BITS > 0.
+	* tune/speed.c (routine): Likewise.
+	* tune/common.c (speed_mpn_hgcd, speed_mpn_hgcd_lehmer): Likewise.
+
+	* mpn/generic/gcd.c, mpn/generic/hgcd.c, mpn/generic/hgcd2.c
+	[GMP_NAIL_BITS]: Disabled new code if we have nails.
+
+	* mpn/generic/gcd.c (MPN_LEQ_P): Copied macro definition (needed
+	for compilation with --enable-assert).
+
+	* tune/tuneup.c (hgcd_schoenhage_threshold,
+	gcd_schoenhage_threshold): New variables.
+	(tune_hgcd, tune_gcd_schoenhage): New functions.
+	(all): Call tune_hgcd and tune_gcd_schoenhage.
+
+	* tune/common.c (speed_mpn_hgcd, speed_mpn_hgcd_lehmer)
+	(speed_mpn_gcd_accel): New functions.
+	* tune/speed.c (routine): Added mpn_hgcd, mpn_hgcd_lehmer and
+	mpn_gcd _accel.
+	* tune/speed.h: Added corresponding prototypes.
+
+	* tune/gcd_accel.c: New file.
+
+	* tune/gcd_bin.c (GCD_SCHOENHAGE_THRESHOLD): Set to MP_SIZE_T_MAX.
+
+	* tune/Makefile.am (libspeed_la_SOURCES): Added gcd_accel.c.
+	(TUNE_MPN_SRCS_BASIC): Added hgcd.c.
+
+	* mpn/x86/k7/gmp-mparam.h (HGCD_SCHOENHAGE_THRESHOLD)
+	(GCD_SCHOENHAGE_THRESHOLD): Tuned values.
+
+	* mpn/generic/gcd.c (mpn_gcd, gcd_binary_odd): Renamed the
+	old mpn_gcd function (which implements accelerated binary gcd) to
+	gcd_binary_odd.
+	(gcd_binary): New function, with the additional book keeping
+	needed when using gcd_binary_odd to compute the gcd of non-odd
+	numbers.
+	(hgcd_tdiv): New function.
+	(gcd_lehmer): New function, currently #if:ed out.
+	(hgcd_start_row_p): New function, duplicated from hgcd.c.
+	(gcd_schoenhage_itch): New function.
+	(gcd_schoenhage): New function.
+	(mpn_gcd): New advertised gcd function, which calls
+	mpn_gcd_binary_odd or mpn_gcd_schoenhage, depending on the size of
+	the input.
+
+	* mpn/generic/hgcd.c (mpn_hgcd2_lehmer_step): Renamed function
+	(was lehmer_step), and made non-static. Updated callers.
+
+	* gmp-impl.h (GCD_LEHMER_THRESHOLD): #if:ed out this macro.
+	(mpn_hgcd2_lehmer_step): Added prototype.
+
+2003-11-27  Niels Möller  <nisse@lysator.liu.se>
+
+	* tests/mpz/t-gcd.c (gcd_values): Moved definition, so that we
+	don't need to forward declare the array.
+
+2003-11-26  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpn/generic/hgcd.c (mpn_hgcd2_fix): Deleted duplicate definition
+	(the function belongs to hgcd2.c).
+
+2003-11-26  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/mpz/t-gcd.c: Generate random operands up to 32767 bits;
+	decrease # of test to 1000.
+	(gcd_values): Remove oversize test case.
+
+2003-11-26  Niels Möller  <niels@lysator.liu.se>
+
+	* gmp-impl.h: Added name mangling for hgcd-related functions. Also
+	use __GMP_PROTO.
+	(MPN_LEQ_P, MPN_EXTRACT_LIMB): Moved macros to hgcd.c.
+	* mpn/generic/hgcd.c, mpn/generic/hgcd2.c, mpn/generic/qstack.c:
+	Adapted to name changes.
+
+	* tests/mpz/t-gcd.c (main): Added some tests with non-random
+	input.
+
+2003-11-25  Niels Möller  <nisse@lysator.liu.se>
+
+	* gmp-impl.h (MPN_LEQ_P, MPN_EXTRACT_LIMB): New macros.
+	(struct qstack, struct hgcd2_row, struct hgcd2, struct hgcd_row)
+	(struct hgcd): New structs. Also added prototypes for new hgcd,
+	hgcd2, qstack and gcd functions.
+
+	* configure.in (gmp_mpn_functions): Added hgcd2, hgcd and qstack.
+
+	* mpn/Makefile.am (nodist_EXTRA_libmpn_la_SOURCES): Added hgcd2.c,
+	hgcd.c and qstack.c.
+
+	* mpn/generic/hgcd.c, mpn/generic/hgcd2.c, mpn/generic/qstack.c:
+	New files, needed for the sub-quadratic gcd.
+
+2003-11-25  Kevin Ryde  <kevin@swox.se>
+
+	* doc/gmp.texi (Language Bindings): Add Axiom.
+
+2003-11-22  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/alpha/README: More notes on assembler syntax variations.
+
+	* mpn/alpha/alpha-defs.m4, mpn/alpha/unicos.m4 (unop): Should be ldq_u
+	not bis, and move to alpha-defs.m4 since it can be happily used
+	everywhere.
+
+	* mpn/alpha/alpha-defs.m4, mpn/alpha/default.m4, mpn/alpha/unicos.m4
+	(bigend): Move to alpha-defs.m4 and base it on HAVE_LIMB_BIG_ENDIAN or
+	HAVE_LIMB_LITTLE_ENDIAN, so as not to hard code system endianness.
+
+	* mpn/alpha/alpha-defs.m4: New file.
+	* configure.in (alpha*-*-*): Use it.
+
+2003-11-21  Kevin Ryde  <kevin@swox.se>
+
+	* mpfr/*: Update to mpfr-2-0-2-branch 2003-11-21.
+
+	* mpn/alpha/ev5/com_n.asm: Change "not" to "ornot r31", since "not"
+	isn't recognised by on Cray Unicos.  Add missing "gp" to PROLOGUE.
+	* mpn/alpha/README: Add a note on "not".
+
+2003-11-19  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/alpha/aorslsh1_n.asm: Slightly rework feed-in code, avoiding
+	spurious reads beyond operand limits.
+
+	* mpn/alpha/ev5/com_n.asm: Add ASM_START/ASM_END.
+
+	* mpn/generic/mul_fft.c (mpn_fft_zero_p): Remove unused function.
+	(mpn_lshift_com): Make static, nailify properly.
+
+2003-11-19  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/generic/diveby3.c: Use a "q" variable to make it clearer what
+	the code is doing.
+
+	* mpn/powerpc32/750/lshift.asm, mpn/powerpc32/750/rshift.asm: New
+	files.
+
+	* mpn/alpha/ev5/com_n.asm: New file.
+
+	* doc/gmp.texi (Assembler Functional Units, Assembler Writing Guide):
+	New sections by Torbjorn, tweaked by me.
+
+2003-11-17  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc32: Add power4/powerpc970 cycle counts.
+	Use cmpwi instead of cmpi to placate darwin.
+
+2003-11-15  Kevin Ryde  <kevin@swox.se>
+
+	* config.guess: Add comments on MacOS "machine" command.
+
+	* tests/devel/try.c (main): Use gmp_randinit_default explicitly on
+	__gmp_rands, since RANDS doesn't allow seeding.
+
+	* doc/gmp.texi (Assigning Integers): Remove notes on possible change
+	to disallow whitespace, this would be an incompatible change and
+	really can't be made.
+	(Toom 3-Way Multiplication): Updates for Paul's new code.
+
+	* mpn/generic/mul_n.c (toom3_interpolate, mpn_toom3_mul_n): Put
+	if/else braces around whole of #if code, for readability.
+
+	* tests/refmpn.c (refmpn_addlsh1_n, refmpn_sublsh1_n,
+	refmpn_rsh1add_n, refmpn_rsh1sub_n): Add ASSERTs for operand overlaps
+	etc.
+
+	* mpfr/*: Update to mpfr-2-0-2-branch 2003-11-15.
+
+2003-11-14  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/alpha/aorslsh1_n.asm: Use Cray-friendly syntax for "br".
+
+2003-11-13  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/alpha/aorslsh1_n.asm: New file.
+
+2003-11-12  Kevin Ryde  <kevin@swox.se>
+
+	* acinclude.m4 (GMP_PROG_CC_WORKS): Add case provoking AIX power2
+	assembler, test code by Torbjorn.
+	* configure.in (power*-*-*): Add a comment about -mcpu=rios2 fallback.
+
+	* tune/speed.c (main): Use gmp_randinit_default explicitly on
+	__gmp_rands, since RANDS doesn't allow seeding.
+
+	* mpfr/*: Update to mpfr-2-0-2-branch 2003-11-12.
+
+	* gmp-impl.h, randmt.h (__gmp_randinit_mt_noseed): Move prototype to
+	gmp-impl.h, for use by RANDS.
+
+	* mpn/Makeasm.am (.s, .S, .asm): Quote $< in test -f, per automake.
+	(.obj): Use test -f and $(CYGPATH_W) as per automake.
+
+2003-11-11  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in: Make umul and udiv standard-optional objects, rather
+	than under various extra_functions.
+
+	* mpn/pa32/hppa1_1/pa7100/add_n.asm,
+	mpn/pa32/hppa1_1/pa7100/addmul_1.asm,
+	mpn/pa32/hppa1_1/pa7100/lshift.asm,
+	mpn/pa32/hppa1_1/pa7100/rshift.asm,
+	mpn/pa32/hppa1_1/pa7100/sub_n.asm,
+	mpn/pa32/hppa1_1/pa7100/submul_1.asm: Use LDEF for labels.
+
+	* mpf/set_str.c: Don't use memcmp for decimal point testing, just a
+	loop is enough and avoids any chance of memcmp reading past the end of
+	the given string.
+
+	* randmts.c, randmt.h: New files.
+	* Makefile.am (libgmp_la_SOURCES): Add them.
+	* randmt.c: Move seeding to randmts.c, common defines in randmt.h.
+	* gmp-impl.h (RANDS): Use __gmp_randinit_mt_noseed.
+	* tests/misc.c (tests_rand_start): Use gmp_randinit_default
+	explicitly, not RANDS.
+
+	* mpn/ia64/ia64-defs.m4 (PROLOGUE_cpu): Use 32-byte alignment, for the
+	benefit of itanium 2.
+	* mpn/ia64/gcd_1.asm: Remove own .align 32.
+
+	* mpn/ia64/ia64-defs.m4 (ALIGN): New define, using IA64_ALIGN_OK.
+	* mpn/ia64/hamdist.asm: Use ALIGN instead of .align.
+
+	* acinclude.m4 (GMP_ASM_IA64_ALIGN_OK): New macro.
+	* configure.in (IA64_PATTERN): Use it.
+	* mpn/ia64/README: Add notes on gas big endian align problem.
+
+2003-11-10  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/ia64/mul_1.asm: Rewrite.
+
+2003-11-08  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/x86/aors_n.asm: Align loop to a multiple of 16.  Also align
+	M4_function_n to a multiple of 16, to minimize alignment padding.
+	Update P6 cycle counts reflecting improvements with new alignment.
+
+2003-11-07  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-impl.h (HAVE_HOST_CPU_alpha_CIX): New define.
+	(ULONG_PARITY, popc_limb): Use it, to pick up ev7 as well as 67 and 68.
+	* longlong.h (count_leading_zeros, count_trailing_zeros): Ditto.
+
+	* doc/gmp.texi (Notes for Package Builds): Add notes on multi-ABI
+	system packaging.
+	(ABI and ISA): Add GNU/Linux ABI=64.
+	(Binary GCD): Add notes on 1x1 GCD algorithms.
+
+	* mpn/alpha/README: Add some literature references.
+
+	* mpn/ia64/mode1o.asm: Various corrections to initial checkin.
+	* mpn/ia64/ia64-defs.m4 (ASSERT): Correction to arg quoting.
+
+2003-11-05  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc64/linux64.m4: New file.
+	* configure.in (POWERPC64_PATTERN): Handle *-*-linux*.
+	Use linux64.m4.
+
+	* mpn/ia64/logops_n.asm: New file.
+
+2003-11-05  Kevin Ryde  <kevin@swox.se>
+
+	* tune/freq.c (freq_sysctl_hw_model): Relax to just look for "%u MHz",
+	for the benefit of sparc cypress under netbsd 1.6.1.
+
+	* mpfr/*: Update to mpfr-2-0-2-branch 2003-11-05.
+
+	* mpn/alpha/ev5/dive_1.c: New file.
+
+	* configure.in (x86_64-*-*): Accept together with amd64-*-*.
+
+	* tune/speed.c: Check range of -x,-y,-w,-W alignment specifiers.
+	* tune/speed.h (CACHE_LINE_SIZE): Amend comments.
+
+2003-11-04  Torbjorn Granlund  <tege@swox.com>
+
+	* tune/speed.c: Fix typo in testing HAVE_NATIVE_mpn_modexact_1_odd.
+
+2003-11-03  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/ia64/hamdist.asm: New file.
+	* mpn/ia64/mode1o.asm: New file.
+	* mpn/ia64/ia64-defs.m4 (ASSERT): New macro.
+
+	* tests/mpz/t-set_d.c (check_2n_plus_1): New test.
+
+2003-11-01  Kevin Ryde  <kevin@swox.se>
+
+	* mpz/fac_ui.c (BSWAP_ULONG) [limb==2*long]: Remove this case, it
+	provokes code gen problems on HP cc.
+	(BSWAP_ULONG) [generic]: Rename __dst variable to avoid conflicts with
+	BITREV_ULONG.
+	Fix by Jason Moxham.
+
+	* mpn/powerpc32/mode1o.asm: Use 16-bit i*i for early out, no need to
+	truncate divisor.  Amend stated 750/7400 speeds, and note operands
+	that give the extremes.
+
+	* mpz/set_d.c: Don't use a special case for d < MP_BASE_AS_DOUBLE, gcc
+	3.3 -mpowerpc64 on darwin gets ulonglong->double casts wrong.
+
+	* mpn/generic/diveby3.c: Show a better style carry handling in the
+	alternative pipelined sample code.
+
+	Revert this, the longlong.h macros need -mpowerpc64:
+	* acinclude.m4 (GMP_GCC_POWERPC64): New macro.
+	* configure.in (powerpc64-*-darwin*): Use it to exclude -mpowerpc64
+	when bad.
+
+2003-10-31  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc64/mode64/submul_1.asm: Move an instruction to save a
+	cycle on POWER4.
+
+	* mpn/powerpc64/mode64/divrem_1.asm: Fix several syntax problems
+	revealed on Mac OS X.
+
+	* mpn/powerpc64/mode64/*.asm: Add cycle counts for POWER4.
+
+	* mpn/powerpc64/sqr_diagonal.asm: Rewrite to save a cycle on POWER4.
+
+2003-10-31  Kevin Ryde  <kevin@swox.se>
+
+	* mpfr/*: Update to mpfr-2-0-2-branch 2003-10-31.
+
+	* mpn/powerpc64/README: Add subdirectory organisation notes.
+
+	* tests/mpn/t-get_d.c: Don't use limits.h, LONG_MIN is wrong on gcc
+	2.95 with -mcpu=ultrasparc.
+
+	* acinclude.m4 (GMP_GCC_POWERPC64): New macro.
+	* configure.in (powerpc64-*-darwin*): Use it to exclude -mpowerpc64
+	when bad.
+
+	* configure.in (powerpc64-*-darwin*) [ABI=mode32]: Use gcc -mcpu flags.
+
+	* mpn/ia64/divrem_1.asm, mpn/ia64/gcd_1.asm: Use "C" for comments.
+	* mpn/ia64/README, mpn/ia64/ia64-defs.m4: Note this.
+
+	* mpn/ia64/ia64-defs.m4: Renamed from default.m4, per other defs files.
+	* configure.in (IA64_PATTERN): Update GMP_INCLUDE_MPN.
+
+	* doc/gmp.texi (Notes for Particular Systems): Remove m68k ABI notes
+	for -mshort and PalmOS, now works.
+	(References): Correction, GMP Square Root proof already there, just
+	wanting URL from RRRR 4475.
+
+2003-10-29  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (sparc*-*-*): Use gcc -m32 when that option works, to
+	force 32-bit mode on dual 32/64 configurations like GNU/Linux.
+	(sparc64-*-linux*): Add support for ABI=64.
+
+	* mpn/generic/pre_divrem_1.c: In fraction part, use CNST_LIMB(0) with
+	udiv_qrnnd_preinv to avoid warning about shift > type.
+
+	* mpfr/*: Update to mpfr-2-0-2-branch 2003-10-29.
+
+	* tests/cxx/t-istream.cc: Avoid tellg() checks if putback() doesn't
+	update that, avoids certain g++ 2.96 problems.
+
+	* tests/mpn/t-fat.c: New file.
+	* tests/mpn/Makefile.am (check_PROGRAMS): Add it.
+
+	* configure.in (CPUVEC_INSTALL, ITERATE_FAT_THRESHOLDS): New macros
+	for fat.h.
+	* mpn/x86/fat/fat.c (__gmpn_cpuvec_init): Use CPUVEC_INSTALL instead
+	of memcpy.  Correction to location of "initialized" set.  Improve
+	various comments.
+
+2003-10-27  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/sparc64/mul_1.asm: Change addcc => add in a few places.
+	* mpn/sparc64/addmul_1.asm: Likewise.
+
+	* mpn/sparc32/v9/mul_1.asm: Apply cross-jumping.
+	* mpn/sparc32/v9/addmul_1.asm: Likewise.
+	* mpn/sparc32/v9/submul_1.asm: Likewise.
+	* mpn/sparc32/v9/sqr_diagonal.asm: Likewise.
+
+2003-10-27  Kevin Ryde  <kevin@swox.se>
+
+	* tests/cxx/t-misc.cc: Don't use <climits>, on g++ 2.95.4 (debian 3.0)
+	-mcpu=ultrasparc LONG_MIN is wrong and kills the compile.
+
+	* tests/cxx/t-istream.cc: Correction to tellg tests, don't assume
+	streampos is zero based.
+
+	* configure.in (HAVE_HOST_CPU_FAMILY_alpha): New define for config.h.
+	* mpn/generic/get_d.c: Use it instead of __alpha for alpha workaround,
+	since Cray cc doesn't define __alpha.
+
+	* mpn/x86/README: Revise PIC coding notes a bit, add gcc visibility
+	attribute.
+
+2003-10-25  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/ia64/gcd_1.asm: New file.
+
+	* tune/many.pl: Allow for PROLOGUE(fun,...), as used on alpha.
+
+	* doc/gmp.texi (C++ Formatted Input): Describe base indicator handling.
+
+	* tests/cxx/t-istream.cc: New file.
+	* tests/cxx/Makefile.am: Add it.
+
+	* cxx/ismpznw.cc: New file, integer input without whitespace ...
+	* cxx/ismpz.cc: ... from here.
+	* gmp-impl.h (__gmpz_operator_in_nowhite): Add prototype.
+	* cxx/ismpq.cc: Rewrite using mpz input routines.  Change to accept a
+	separate base indicator on numerator and denominator.  Fix base
+	indicator case where "123/0456" would stop at "123/0".
+	* Makefile.am, cxx/Makefile.am: Add cxx/ismpznw.cc.
+
+	* tests/mpz/t-set_d.c: New file, derived from tests/mpz/t-set_si.c
+	* tests/mpz/Makefile.am (check_PROGRAMS): Add it.
+
+	* mpn/m68k/lshift.asm, mpn/m68k/rshift.asm: Support 16-bit int and
+	stack alignment.
+	* mpn/m68k/README: Add notes on this.
+	* configure.in (SIZEOF_UNSIGNED): New define in config.m4.
+	* mpn/m68k/m68k-defs.m4 (m68k_definsn): Add cmpw, movew.
+	Reported by Patrick Pelissier.
+
+	* mpn/m68k/t-m68k-defs.pl: Don't use -> with hashes, to avoid
+	deprecation warnings from perl 5.8.
+
+	* configure.in (viac3-*-*): Use just x86/pentium in $path not x86/p6.
+	If gcc is to be believed the old C3s don't have cmov.
+
+	* Makefile.am: Amend comments about not building from libtool
+	convenience libraries.
+
+	* mpn/asm-defs.m4 (PROLOGUE): Use m4_file_seen, for correct filename
+	in missing EPILOGUE error messages.
+	(m4_file_seen): Amend comments about where used.
+
+	* Makefile.am (CXX_OBJECTS): Remove $U, C++ files are not subject to
+	ansi2knr rules.
+
+	* gmp-h.in (mpn_divmod_1): Use __GMP_CAST, to avoid warnings in
+	applications using g++ -Wold-style-cast.
+
+	* mpn/z8000/README: New file.
+
+2003-10-22  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/generic/get_d.c (CONST_1024, CONST_NEG_1023,
+	CONST_NEG_1022_SUB_53): Replace ALPHA_WORKAROUND with a non-gcc-ism,
+	and use on Cray Unicos alpha too, which has the same problem.
+
+	* configure.in (powerpc64-*-darwin*): Make ABI=32 available as the
+	final fallback, remove mode64 until we know how it will work.
+
+	* doc/gmp.texi (Build Options): Add powerpc970 to available CPUs.
+	(ABI and ISA): Add mode32 for Darwin.
+
+	* configure.in (gettimeofday): Use an explicit AC_TRY_LINK, to avoid
+	known autoconf 2.57 problems with gettimeofday in AC_CHECK_FUNCS on
+	HP-UX.
+
+	* configure.in (powerpc*-*-*): Use ABI=32 instead of ABI=standard for
+	the default 32-bit ABI.  Fixes powerpc64-*-aix* which is documented as
+	choices "aix64 32" but had "aix64 standard".
+
+	* mpfr/*: Update to mpfr-2-0-2-branch 2003-10-22.
+
+	* doc/gmp.texi (Notes for Particular Systems): Note m68k gcc -mshort
+	and PalmOS calling conventions not supported.  Reported by Patrick
+	Pelissier.
+	(References): Add Paul Zimmermann's Inria 4475 paper.
+
+2003-10-21  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/ia64/submul_1.asm: Slightly reschedule loop to accommodate
+	Itanium 2 getf.sig latency.
+
+2003-10-21  Kevin Ryde  <kevin@swox.se>
+
+	* tests/mpn/t-instrument.c: Add mpn_addlsh1_n, mpn_rsh1add_n,
+	mpn_rsh1sub_n, mpn_sub_nc, mpn_sublsh1_n.  Typo in mpn_preinv_divrem_1
+	conditional.
+
+2003-10-20  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc64/mode32/add_n.asm: New file.
+	* mpn/powerpc64/mode32/sub_n.asm: New file.
+	* mpn/powerpc64/mode32/mul_1.asm: New file.
+	* mpn/powerpc64/mode32/addmul_1.asm: New file.
+	* mpn/powerpc64/mode32/submul_1.asm: New file.
+
+2003-10-19  Torbjorn Granlund  <tege@swox.com>
+
+	* longlong.h (AMD64): __x86_64__ => __amd64__.
+	(64-bit powerpc): Only define carry-dependent macros if
+	!_LONG_LONG_LIMB.
+
+	* acinclude.m4 (POWERPC64_PATTERN): Add powerpc970-*-*.
+
+	* configure.in (POWERPC64_PATTERN): Handle *-*-darwin*.
+	(POWERPC64_PATTERN, *-*-aix*): Prepend powerpc64/mode64 to path_aix64.
+
+	* mpn/powerpc64/mode64/mul_1.asm: Change cal => addi.
+	* mpn/powerpc64/mode64/addmul_1.asm: Likewise.
+	* mpn/powerpc64/mode64/submul_1.asm: Likewise.
+	* mpn/powerpc64/sqr_diagonal.asm: Likewise.
+
+	* mpn/powerpc64/mode64/mul_1.asm: Move from "..".
+	* mpn/powerpc64/mode64/addmul_1.asm: Likewise.
+	* mpn/powerpc64/mode64/submul_1.asm: Likewise.
+	* mpn/powerpc64/mode64/divrem_1.asm: Likewise.
+	* mpn/powerpc64/mode64/rsh1sub_n.asm: Likewise.
+	* mpn/powerpc64/mode64/add_n.asm: Likewise.
+	* mpn/powerpc64/mode64/addsub_n.asm: Likewise.
+	* mpn/powerpc64/mode64/sub_n.asm: Likewise.
+	* mpn/powerpc64/mode64/addlsh1_n.asm: Likewise.
+	* mpn/powerpc64/mode64/diveby3.asm: Likewise.
+	* mpn/powerpc64/mode64/rsh1add_n.asm: Likewise.
+	* mpn/powerpc64/mode64/sublsh1_n.asm: Likewise.
+
+	* mpn/powerpc64/lshift.asm: Handle mode32 ABI.
+	* mpn/powerpc64/rshift.asm: Likewise.
+	* mpn/powerpc64/umul.asm: Likewise.
+
+	* tune/powerpc64.asm: Make it actually work.
+
+2003-10-19  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/generic/get_d.c: Add a workaround for alpha gcc signed constant
+	comparison bug.
+
+	* gmpxx.h (gmp_randclass gmp_randinit_lc_2exp_size constructor): Throw
+	std::length_error if size is too big.
+	* tests/cxx/t-rand.cc (check_randinit): Exercise this.
+
+	* mpn/x86/pentium4/sse2/addlsh1_n.asm: New file, derived in part from
+	mpn/x86/pentium4/sse2/add_n.asm.
+
+	* doc/gmp.texi (C++ Interface Integers, C++ Interface Rationals, C++
+	Interface Floats): Note std::invalid_argument exception for invalid
+	strings to constructors and operator=.
+	(C++ Interface Random Numbers): Note std::length_error exception for
+	size too big in gmp_randinit_lc_2exp_size.
+
+2003-10-18  Kevin Ryde  <kevin@swox.se>
+
+	* mpfr/*: Update to mpfr-2-0-2-branch 2003-10-18.
+
+	* gmpxx.h (mpz_class, mpq_class, mpf_class, mpfr_class constructors
+	and operator= taking string or char*): Throw std::invalid_argument if
+	string cannot be converted.
+	* tests/cxx/t-constr.cc, tests/cxx/t-assign.cc: Exercise this.
+
+	* cxx/ismpz.cc, cxx/ismpq.cc, cxx/ismpf.cc: Use istream std::locale
+	ctype facet for isspace when available.  Only accept space at the
+	start of the input, same as g++ libstdc++.  Use ASSERT_NOCARRY to
+	check result of mpz_set_str etc.
+	* cxx/ismpf.cc: Don't accept "@" for exponent indicator.
+
+	* tune/speed.c, tune/speed.h, tune/common.c, tune/Makefile.am: Remove
+	_open and _mpn variants of mpn_toom3_mul_n, only one style now.
+	* tune/mul_n_open.c, tune/mul_n_mpn.c: Remove files.
+
+	* gmp-impl.h (LIMB_HIGHBIT_TO_MASK): New macro.
+	(udiv_qrnnd_preinv2, udiv_qrnnd_preinv2gen): Use it.
+
+	* tests/mpz/t-import.c, tests/mpz/t-export.c: Use octal for character
+	constants, hex is an ANSI-ism.
+
+	* mpn/alpha/ev5/mode1o.c: Corrections to ASSERTs, as per
+	mpn/generic/mode1o.c.
+
+	* mpn/generic/diveby3.c: Add commented out alternative code and notes
+	for taking the multiply off the dependent chain.  Amend/clarify some
+	of the other comments.
+
+	* configure.in (powerpc970-*-*): Use gcc -mcpu=970 when available.
+	(powerpc7400-*-*): Fallback on gcc -mcpu=750 if -mcpu=7400 not
+	available.
+
+	* doc/gmp.texi (C++ Formatted Input): Note locale digit grouping not
+	supported.
+	(C++ Formatted Input, C++ Formatted Output): Cross reference class
+	interface on overloading.
+
+	* mpn/m68k/README: Add various ideas from doc/tasks.html.
+
+	* mpn/m88k/README: New file.
+
+2003-10-16  Torbjorn Granlund  <tege@swox.com>
+
+	* config.sub: Recognize powerpc970.
+
+2003-10-15  Torbjorn Granlund  <tege@swox.com>
+
+	* config.guess: Recognize powerpc970 under MacOS.
+
+2003-10-15  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in, acinclude.m4 (GMP_C_RIGHT_SHIFT): New test.
+	* gmp-impl.h (LIMB_HIGHBIT_TO_MASK): New macro.
+	(udiv_qrnnd_preinv2, udiv_qrnnd_preinv2gen): Use it.
+
+	* mpn/amd64/amd64-defs.m4: New file, with a non-aligning PROLOGUE.
+	* configure.in (amd64-*-*): Use it.
+	* mpn/amd64/addlsh1_n.asm: Add ALIGN(16).
+
+	* mpfr/*: Update to mpfr cvs 2003-10-15.
+
+	* mpn/generic/get_d.c: Rewrite, simplifying and truncating towards
+	zero unconditionally.
+	* tests/mpn/t-get_d.c: Add various further tests.
+	* gmp-impl.h (FORCE_DOUBLE): New macro.
+
+	* gmp-h.in (__mpz_struct): Add comment on __mpz_struct getting into
+	C++ mangled function names.
+
+	* doc/gmp.texi (Build Options): Update notes for new doc subdir.
+	(Low-level Functions): Note mpn functions don't check for zero limbs
+	etc, it's up to an application to strip.
+
+	* doc/configuration (Configure): mdate-sh now in doc subdir, add
+	generated fat.h.
+
+2003-10-14  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/ia64/lorrshift.asm: Rewrite.
+
+	* mpn/ia64/diveby3.asm: Remove explicit bundling; add branch hints.
+
+2003-10-13  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/ia64/diveby3.asm: New file.
+
+2003-10-13  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/powerpc32/mod_34lsub1.asm: New file.
+
+	* mpn/powerpc32/diveby3.asm, mpn/powerpc64/diveby3.asm: src[] in
+	second operand of mullw, to allow possible early-out, which the
+	0xAA..AB inverse cannot give.  This improvement noticed by Torbjorn.
+
+	* acinclude.m4 (GMP_ASM_LSYM_PREFIX): Print to config.log whether
+	local label is purely temporary or appears in object files, for
+	development purposes.
+
+	* doc/gmp.texi, doc/fdl.texi, doc/texinfo.tex, doc/mdate-sh: Moved
+	from top-level.
+	* doc/Makefile.am: New file.
+	* configure.in (AC_OUTPUT): Add doc/Makefile.
+	* Makefile.am (SUBDIRS): Move doc subdirectory from EXTRA_DIST.
+	(info_TEXINFOS, gmp_TEXINFOS): Moved to doc/Makefile.am.
+	* mpfr/Makefile.am (mpfr_TEXINFOS): fdl.texi now in doc subdir.
+	(TEXINFO_TEX): texinfo.tex now in doc subdir.
+	(AM_MAKEINFOFLAGS): Set -I to doc subdir.
+
+	* mpz/and.c: For positive/positive, use mpn_and_n, rate a realloc as
+	UNLIKELY.
+
+	* mpn/generic/mul_n.c (mpn_toom3_mul_n, mpn_toom3_sqr_n): Don't test
+	for high zero limbs.
+
+2003-10-12  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc64/diveby3.asm: New file (trivial edits of
+	powerpc32/diveby3.asm).
+
+	* mpn/powerpc32/diveby3.asm: Update cycle counts with more processors.
+	* mpn/powerpc32/sqr_diagonal.asm: Likewise.
+
+	* mpn/pa64/add_n.asm: Correct PA8500 cycle counts.
+	* mpn/pa64/sub_n.asm: Likewise.
+
+	* mpn/m68k/aors_n.asm (INPUT PARAMETERS): Fix typo.
+	* mpn/m68k/lshift.asm: Likewise.
+	* mpn/m68k/rshift.asm: Likewise.
+
+	* mpn/m68k/README: Correct an URL; add some STATUS comments.
+
+	* mpn/ia64/aorslsh1_n.asm: Avoid shrp when shl/shr works just as well.
+
+	* mpn/powerpc32/addlsh1_n.asm: New file.
+	* mpn/powerpc32/sublsh1_n.asm: New file.
+
+2003-10-12  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/sparc64/divrem_1.c, mpn/sparc64/mod_1.c: New files.
+	* mpn/sparc64/sparc64.h (HALF_ENDIAN_ADJ, count_leading_zeros_32,
+	invert_half_limb, udiv_qrnnd_half_preinv): New macros.
+
+	* gmp-impl.h (udiv_qrnnd_preinv2): Use a ? : for getting the n1 bit,
+	so as not to depend on signed right shifts being arithmetic.
+
+	* mpn/powerpc32/diveby3.asm: New file.
+
+	* mpn/generic/divrem_1.c: Use CNST_LIMB(0) to avoid warnings from
+	udiv_qrnnd_preinv about shift count when int<long.  Do the same with
+	udiv_qrnnd, for consistency.
+
+	* Makefile.am (install-data-hook): Print a warning recommending "make
+	check" to watch out for compiler bugs.  Proposed by Torbjorn.
+
+	* mpn/ia64/README (mpn_lshift, mpn_rshift): Amend prospective itanium2
+	speed, 0.75 c/l with shrp plus shl/shr.
+
+	* mpn/ia64/popcount.asm: Add comment on optimality.
+
+2003-10-11  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/ia64/rsh1aors_n.asm: New file.
+
+	* mpn/asm-defs.m4: Handle rsh1aors_n.
+
+	* configure.in (tmp_mulfunc): Handle rsh1aors_n.
+
+2003-10-11  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/x86/pentium4/sse2/diveby3.asm: Remove non-PIC RODATA memory
+	access for 0xAAAAAAAB constant.
+
+	* gmp-impl.h (popc_limb, ULONG_PARITY) [ev67, ev68]: Add gcc asm
+	versions using ctpop.
+
+	* mpn/x86/k6/aorsmul_1.asm: Tweak some comments, remove M4_description
+	and M4_desc_retval used only in comments.
+
+	* mpn/x86/k6/mul_basecase.asm: Add comment on using mpn_mul_1.
+
+2003-10-09  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc64/addlsh1_n.asm: Tweak for 0.25 c/l better loop speed.
+	* mpn/powerpc64/sublsh1_n.asm: Likewise.
+
+2003-10-09  Kevin Ryde  <kevin@swox.se>
+
+	* mpfr/*: Update to mpfr cvs 2003-10-09.
+
+	* tests/devel/try.c (_SC_PAGESIZE): Define from _SC_PAGE_SIZE on
+	systems which use that, eg. hpux 9.
+
+2003-10-07  Kevin Ryde  <kevin@swox.se>
+
+	* tune/freq.c (freq_sysctl_hw_model): Correction to last sscanf change.
+
+	* configure.in: Check for psp_iticksperclktick in struct pst_processor.
+	* tune/freq.c (freq_pstat_getprocessor): Use this.
+
+	* tests/devel/try.c (divisor_array): Add a couple of half-limb values.
+
+	* acinclude.m4 (GMP_PROG_CC_WORKS): Correction to last change, need to
+	set result "yes" when cross compiling.
+
+2003-10-06  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/mul_n.c: Use __GMPN_ADD_1/_GMPN_SUB_1 instead of
+	mpn_add_1 and mpn_sub_1.
+
+	* mpn/pa64/aorslsh1_n.asm: Schedule register save and restore code.
+
+2003-10-05  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/pa64/mul_1.asm: Misc comment cleanups.
+	* mpn/pa64/addmul_1.asm: Likewise.
+	* mpn/pa64/submul_1.asm: Likewise.
+
+	* mpn/pa64/README: Correct cycle counts.
+
+	* mpn/pa64/aorslsh1_n.asm: New file.
+
+2003-10-04  Kevin Ryde  <kevin@swox.se>
+
+	* tune/freq.c (freq_sysctl_hw_model, freq_sunos_sysinfo,
+	freq_sco_etchw, freq_bsd_dmesg, freq_irix_hinv): Demand matching of
+	MHz etc at end of sscanf format string.  In particular need this for
+	freq_bsd_dmesg on i486-pc-freebsd4.7 to avoid the 486 cpu being used
+	for the frequency.
+
+	* tests/misc.c, tests/tests.h (tests_setjmp_sigfpe,
+	tests_sigfpe_handler, tests_sigfpe_done, tests_sigfpe_target,
+	tests_dbl_mant_bits): New.
+
+	* configure.in (viac3*-*-*): Add gcc VIA c3 options.
+
+	* mpfr/*: Update to mpfr cvs 2003-10-04.
+
+	* tests/refmpn.c (refmpn_addlsh1_n, refmpn_sublsh1_n,
+	refmpn_rsh1add_n, refmpn_rsh1sub_n): Add ASSERTs for operand overlaps.
+	* tests/tests.h (refmpn_addlsh1_n, refmpn_sublsh1_n, refmpn_rsh1add_n,
+	refmpn_rsh1sub_n): Add prototypes.
+
+	* tests/devel/try.c, tune/many.pl: Add mpn_addlsh1_n, mpn_sublsh1_n,
+	mpn_rsh1add_n, mpn_rsh1sub_n.
+
+2003-10-03  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/refmpn.c (refmpn_addlsh1_n, refmpn_sublsh1_n, refmpn_rsh1add_n,
+	refmpn_rsh1sub_n): New functions.
+
+2003-10-03  Paul Zimmermann  <Paul.Zimmermann@loria.fr>
+
+	* mpn/generic/mul_n.c (toom3_interpolate): Use mpn_add_1/mpn_sub_1
+	instead of MPN_INCR_/MPN_DECR_U.
+
+2003-10-02  Torbjorn Granlund  <tege@swox.com>
+
+	* configure.in (ia64*-*-hpux*): Fall back to +O1, not +O.
+
+2003-10-02  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (ia64*-*-hpux*): For cc, let +O optimization level
+	fallback if +O3 doesn't work.
+
+	* acinclude.m4 (GMP_PROG_CC_WORKS): Add a test of __builtin_alloca
+	when available, to pick up Itanium HP-UX cc internal errors in +O2.
+	Provoking code by Torbjorn.
+
+2003-10-01  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/ia64/gmp-mparam.h: Retune.
+
+	* mpn/asm-defs.m4: Handle aorslsh1_n.
+
+	* configure.in (tmp_mulfunc): Handle aorslsh1_n.
+
+	* mpn/ia64/aorslsh1_n.asm: New file.
+
+	* mpn/ia64/aors_n.asm: New file, complete rewrite of mpn_add_n and
+	mpn_sub_n.
+	* mpn/ia64/add_n.asm: Replace by aors_n.asm.
+	* mpn/ia64/sub_n.asm: Replace by aors_n.asm.
+
+2003-10-01  Kevin Ryde  <kevin@swox.se>
+
+	* acinclude.m4 (GMP_C_DOUBLE_FORMAT): Make bad ARM last byte into a
+	separate case and consider it non-IEEE, since it looks like this is
+	due to some sort of restricted or incorrect software floats.
+
+	* demos/calc/Makefile.am: Use automake yacc/lex support, seems fine in
+	separate objdir now.
+
+	* cxx/dummy.cc: Moved from top-level dummy.cc.
+	* Makefile.am (libgmpxx_la_SOURCES): Update to cxx/dummy.cc,
+	correction to comment about this.
+
+2003-09-30  Torbjorn Granlund  <tege@swox.com>
+
+	* demos/pexpr.c: Correct documentation of -split.
+	(TIME): Remove cast of result to double.
+	(main): Change timing variables to int.
+	(main): #ifdef LIMIT_RESOURCE_USAGE, don't convert numbers of more than
+	100000 digits.
+
+2003-09-28  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/*/*.asm: Clean up spacing, tabify.
+
+	* mpn/alpha/rshift.asm: Table cycle counts.
+	* mpn/alpha/lshift.asm: Likewise.
+	* mpn/alpha/ev5/rshift.asm: Likewise.
+	* mpn/alpha/ev5/lshift.asm: Likewise.
+	* mpn/alpha/ev6/add_n.asm: Likewise.
+	* mpn/alpha/ev6/sub_n.asm: Likewise.
+
+	* mpn/ia64/lorrshift.asm: Amend comments about performance.
+
+	* mpn/pa64/mul_1.asm: Fix comment typo.
+	* mpn/pa64/addmul_1.asm: Likewise.
+	* mpn/pa64/submul_1.asm: Likewise.
+
+	* mpn/amd64/addlsh1_n.asm: Save/restore carry using two insn to break
+	recurrency.  Add remarks about possible further speedup.
+	* mpn/amd64/sublsh1_n.asm: Likewise.
+
+	* mpn/amd64/rsh1add_n.asm: Add remarks about possible further speedup.
+	* mpn/amd64/rsh1sub_n.asm: Likewise.
+
+2003-09-27  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc64/README: Update with POWER4/PPC970 pipeline info.
+
+	* mpn/powerpc64/rsh1add_n.asm: New file.
+	* mpn/powerpc64/rsh1sub_n.asm: New file.
+	* mpn/powerpc64/rshift.asm: Rewrite.
+	* mpn/powerpc64/lshift.asm: Rewrite.
+
+2003-09-26  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc64/addlsh1_n.asm: New file.
+	* mpn/powerpc64/sublsh1_n.asm: New file.
+
+2003-09-25  Torbjorn Granlund  <tege@swox.com>
+
+	* tune/common.c (speed_mpn_addlsh1_n, speed_mpn_sublsh1_n,
+	speed_mpn_rsh1add_n, speed_mpn_rsh1sub_n): Conditionalize on
+	corresponding HAVE_NATIVE_*.
+
+2003-09-25  Kevin Ryde  <kevin@swox.se>
+
+	* mpz/combit.c: Use GMP_NUMB_BITS not BITS_PER_MP_LIMB.
+
+	* demos/expr/exprfr.c: Allow for mpfr_inf_p, mpfr_nan_p and
+	mpfr_number_p merely returning non-zero, rather than 1 or 0.
+
+	* demos/expr/exprfr.c, demos/expr/t-expr.c: Add erf, integer_p, zeta.
+
+	* demos/expr/Makefile.am (LDADD): Update comments on $(LIBM).
+
+2003-09-24  Torbjorn Granlund  <tege@swox.com>
+
+	* tune/speed.c (routine): Add entries for mpn_addlsh1_n, mpn_sublsh1_n,
+	mpn_rsh1add_n, and mpn_rsh1sub_n.
+
+	* tune/speed.h: Declare speed_mpn_addlsh1_n, speed_mpn_sublsh1_n,
+	speed_mpn_rsh1add_n, and speed_mpn_rsh1sub_n.
+
+	* tune/common.c (speed_mpn_addlsh1_n, speed_mpn_sublsh1_n,
+	speed_mpn_rsh1add_n, speed_mpn_rsh1sub_n): New functions.
+
+	* gmp-impl.h: Declare mpn_addlsh1_n, mpn_sublsh1_n, mpn_rsh1add_n, and
+	mpn_rsh1sub_n.
+
+	* mpn/asm-defs.m4: Add define_mpn's for addlsh1_n, sublsh1_n,
+	rsh1add_n, and rsh1sub_n.
+
+	* mpn/powerpc64/*.asm: Add cycle counts in consistent style.  Misc
+	styling edits.
+
+	* mpn/amd64/gmp-mparam.h: Retune.
+
+	* configure.in: Add #undefs for HAVE_NATIVE_mpn_addlsh1_n,
+	HAVE_NATIVE_mpn_sublsh1_n, HAVE_NATIVE_mpn_rsh1add_n,
+	HAVE_NATIVE_mpn_rsh1sub_n.
+	(gmp_mpn_functions_optional): List addlsh1_n, sublsh1_n, rsh1add_n,
+	and rsh1sub_n.
+
+	* mpn/amd64/addlsh1_n.asm: New file.
+	* mpn/amd64/sublsh1_n.asm: New file.
+	* mpn/amd64/rsh1add_n.asm: New file.
+	* mpn/amd64/rsh1sub_n.asm: New file.
+
+2003-09-24  Kevin Ryde  <kevin@swox.se>
+
+	* mpfr/*: Update to mpfr cvs 2003-09-24.
+
+	* acinclude.m4 (GMP_C_DOUBLE_FORMAT): Remove conftest* temporary files.
+
+2003-09-23  Torbjorn Granlund  <tege@swox.com>
+
+	* gmp-impl.h (MUL_TOOM3_THRESHOLD, SQR_TOOM3_THRESHOLD): Now 128.
+
+2003-09-23  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-h.in (gmp_randinit_set): Use __gmp_const rather than const.
+
+2003-09-22  Torbjorn Granlund  <tege@swox.com>
+
+	* tune/mul_n_mpn.c: (__gmpn_sqr_n): New #define.
+	* tune/mul_n_open.c (__gmpn_sqr_n): New #define.
+
+	* mpn/generic/mul.c (mpn_sqr_n): Move from here...
+	* mpn/generic/mul_n.c (mpn_sqr_n): ...to here.
+	(mpn_sqr_n): Allocate workspace for toom3 using TMP_* mechanism except
+	for very large operands when !WANT_FFT.
+
+	* mpn/generic/mul_n.c: Add a missing ";". Misc comment fixes.
+
+	* mpn/generic/mul.c: Remove spurious #include <stdio.h>.
+
+	* mpn/x86/k7/gmp-mparam.h: Retune.
+
+	* mpn/generic/mul_n.c (mpn_mul_n): Allocate workspace for toom3 using
+	TMP_* mechanism except for very large operands when !WANT_FFT.
+
+	* gmp-impl.h (MPN_TOOM3_MUL_N_TSIZE, MPN_TOOM3_SQR_N_TSIZE):
+	Define conditionally on WANT_FFT and HAVE_NATIVE_mpn_sublsh1_n.
+	(MPN_TOOM3_MAX_N): New #define.
+
+	* mpn/amd64/gmp-mparam.h: Retune.
+
+	* mpn/Makefile.am (TARG_DIST): Add amd64.
+
+	* mpn/generic/sqr_basecase.c: Use mpn_addlsh1_n when available.
+
+	* mpn/generic/mul_n.c: Use proper form for HAVE_NATIVE macros.
+
+2003-09-22  Kevin Ryde  <kevin@swox.se>
+
+	* mpfr/*: Update to mpfr cvs 2003-09-22.
+
+2003-09-21  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/x86/pentium4/sse2/gmp-mparam.h (USE_PREINV_DIVREM_1,
+	USE_PREINV_MOD_1): Set to 1 for new asm versions.
+
+	* mpfr/*: Update to mpfr cvs 2003-09-21.
+
+2003-09-21  Paul Zimmermann  <Paul.Zimmermann@loria.fr>
+
+	* mpn/generic/mul_n.c (mpn_toom3_mul_n): Conditionally use
+	mpn_sublsh1_n, mpn_rsh1add_n and mpn_rsh1sub_n, in addition to
+	mpn_addlsh1_n.  Avoid all copying, at the expense of some additional
+	workspace.
+
+	* gmp-impl.h (MPN_TOOM3_MUL_N_TSIZE, MPN_TOOM3_SQR_N_TSIZE): Accommodate
+	latest toom3 code.
+
+2003-09-19  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/x86/pentium4/sse2/divrem_1.asm, mpn/x86/pentium4/sse2/mod_1.asm:
+	New files.
+
+2003-09-16  Kevin Ryde  <kevin@swox.se>
+
+	* tune/speed.c (run_one): Don't scale the -1.0 not-available return.
+	Print "n/a" for times not-available.
+
+2003-09-13  Paul Zimmermann  <Paul.Zimmermann@loria.fr>
+
+	* mpn/generic/mul_n.c (toom3_interpolate): New function.
+	(mpn_toom3_mul_n, mpn_toom3_sqr_n): Call toom3_interpolate.
+
+2003-09-12  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/mul_n.c (mpn_toom3_mul_n, mpn_toom3_sqr_n): Remove unused
+	variables.
+	(mpn_toom3_mul_n, mpn_toom3_sqr_n): Use offset `+ 1', not `+ 2' in last
+	MPN_DECR_U calls.
+
+2003-09-12  Paul Zimmermann  <Paul.Zimmermann@loria.fr>
+
+	* mpn/generic/mul_n.c (mpn_toom3_mul_n, mpn_toom3_sqr_n): Rewrite.
+
+2003-09-12  Torbjorn Granlund  <tege@swox.com>
+
+	* gmp-impl.h (MPN_KARA_MUL_N_TSIZE, MPN_KARA_SQR_N_TSIZE): Reformulate
+	to use the same form as MPN_TOOM3_MUL_N_TSIZE.
+	(MPN_TOOM3_MUL_N_TSIZE, MPN_TOOM3_SQR_N_TSIZE): Update for new Toom3
+	code requirements.
+	* mpn/generic/mul_n.c (evaluate3, interpolate3, add2Times): Remove.
+	(USE_MORE_MPN): Remove.
+
+2003-08-31  Kevin Ryde  <kevin@swox.se>
+
+	* mpfr/*: Update to mpfr cvs 2003-08-31.
+
+2003-08-30  Kevin Ryde  <kevin@swox.se>
+
+	* mpfr/*: Update to mpfr cvs 2003-08-30.
+
+2003-08-29  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/amd64/copyi.asm: New file.
+	* mpn/amd64/copyd.asm: New file.
+	* mpn/amd64/README: New file.
+
+2003-08-28  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/amd64/lshift.asm: New file.
+	* mpn/amd64/rshift.asm: New file.
+	* mpn/amd64/gmp-mparam.h: Retune.
+
+2003-08-23  Kevin Ryde  <kevin@swox.se>
+
+	* tune/freq.c (freq_getsysinfo): Correction to speed_cycletime value
+	established.
+
+	* mpz/rootrem.c, gmp-h.in, gmp.texi (mpz_rootrem): Don't return
+	exactness indication, can get that from testing the remainder.
+
+	* mpn/x86/k7/aors_n.asm, mpn/x86/k7/mmx/copyi.asm: Amend to comments
+	about loads and stores and what speed should be possible.
+
+2003-08-22  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/amd64/add_n.asm: New file.
+	* mpn/amd64/sub_n.asm: New file.
+	* mpn/amd64/mul_1.asm: New file.
+	* mpn/amd64/addmul_1.asm: New file.
+	* mpn/amd64/submul_1.asm: New file.
+
+2003-08-19  Kevin Ryde  <kevin@swox.se>
+
+	* longlong.h (add_ssaaaa, sub_ddmmss) [hppa 64]: Move down into main
+	__GNUC__ block.  Exclude for _LONG_LONG_LIMB (ie. ABI=2.0n) since
+	these forms are only for ABI=2.0w.
+
+	* longlong.h (count_leading_zeros) [__mcpu32__]: Check __mcpu32__ to
+	avoid bfffo on GCC 3.4 in CPU32 mode.  Reported by Bernardo Innocenti.
+
+	* longlong.h (count_trailing_zeros) [x86_64]: Use "%q0" to force
+	64-bit register destination.  Pointed out by Torbjorn.
+
+	* mpz/combit.c: Correction to carry handling when extending a
+	negative, and use __GMPN_ADD_1.  Correction to complement limb for a
+	negative when there's a non-zero low limb.
+	* tests/mpz/bit.c (check_clr_extend, check_com_negs): Exercise these.
+
+	* demos/perl/GMP.xs, demos/perl/GMP.pm, demos/perl/test.pl: Add
+	get_d_2exp.
+	* demos/perl/GMP.xs, demos/perl/GMP.pm, demos/perl/GMP/Rand.pm,
+	demos/perl/test.pl: Add gmp_urandomb_ui, gmp_urandomm_ui.
+	(GMP::Rand::randstate): Accept a randstate object to copy.
+	* demos/perl/GMP.xs, demos/perl/GMP.pm, demos/perl/GMP/Mpz.pm,
+	demos/perl/test.pl: Add combit, rootrem.
+
+2003-08-19  Torbjorn Granlund  <tege@swox.com>
+
+	* tune/Makefile.am (EXTRA_DIST): Add amd64.asm.
+
+2003-08-17  Kevin Ryde  <kevin@swox.se>
+
+	* gmpxx.h [__MPFR_H]: Include full <iostream> for inlines.
+	* tests/cxx/t-headfr.cc: New file, exercising this.
+	* tests/cxx/Makefile.am: Add it.
+
+	* tests/cxx/t-constr.cc: Include config.h for WANT_MPFR.
+
+	* gmpxx.h: Correction to temp variable type in mpf -> mpfr assignment.
+	Reported by Derrick Bass.
+	* tests/cxx/t-assign.cc (check_mpfr): Exercise this.
+
+	* configure.in (WANT_MPFR): AC_DEFINE this, for the benefit of
+	tests/cxx/t-*.cc.  (Was always meant to have been defined.)
+	* tests/cxx/Makefile.am (INCLUDES): Add -I$(top_srcdir)/mpfr.
+
+	* gmpxx.h: __gmp_default_rounding_mode -> __gmpfr_default_rounding_mode
+	(struct __gmp_hypot_function): Correction to mpfr_hypot addition.
+	* tests/cxx/t-misc.cc (check_mpfr_hypot): Corrections to mpfr/long
+	tests.
+
+2003-08-16  Torbjorn Granlund  <tege@swox.com>
+
+	* configure.in (amd64): New.
+
+	* mpn/amd64/gmp-mparam.h: New file.
+
+	* tune/amd64.asm: New file, derived in part from tune/pentium.asm.
+
+2003-08-15  Kevin Ryde  <kevin@swox.se>
+
+	* tune/freq.c (freq_irix_hinv): Reinstate, for the benefit of IRIX 6.2.
+	(freq_attr_get_invent): Conditionalize on INFO_LBL_DETAIL_INVENT too.
+
+2003-08-14  Kevin Ryde  <kevin@swox.se>
+
+	* mpq/get_d.c: Use mpn_get_d.
+	* tests/mpq/t-get_d.c (check_onebit): New test.
+
+	* gmp.texi (Notes for Particular Systems): Under x86 cpu types, note
+	i386 is a fat binary, remove pentium4 recommendation since i386 is now
+	quite reasonable for p4.
+	(Notes for Particular Systems): Under Windows DLLs, remove caveat
+	about --enable-cxx now ok, update .lib creation for new libtool,
+	remove .exp not needed for MS C.
+	(Notes for Package Builds): i386 is a fat binary.
+	(Reentrancy): Remove SCO ctype.h note, don't want to list every system
+	misfeature, and was quite possibly for non-threading mode anyway.
+	(Autoconf): Remove notes on gmp 2 detection, too old to want to
+	encourage anyone to use.
+	(Karatsuba Multiplication): Correction to threshold increase/decrease
+	for a and b terms.  Reported by Richard Brent and Paul Zimmermann.
+	Also add various further index entries.
+
+	* tune/freq.c (freq_attr_get_invent): New function.
+	(freq_irix_hinv): Remove, in favour or freq_attr_get_invent.
+	* configure.in (AC_CHECK_FUNCS): Add attr_get.
+	(AC_CHECK_HEADERS): Add invent.h, sys/attributes.h, sys/iograph.h.
+
+2003-08-03  Kevin Ryde  <kevin@swox.se>
+
+	* tune/tuneup.c (tune_mul): Use MUL_KARATSUBA_THRESHOLD_LIMIT.
+
+2003-08-02  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/asm-defs.m4: Tweak some comments, add hpux11 to m4wrap 0xFF
+	problem systems.
+
+	* configure.in (*-*-sco3.2v5*): Remove lt_cv_archive_cmds_need_lc=no,
+	since libtool no longer uses it.  This was a workaround fixing ctype.h
+	in SCO 5 shared libraries; not sure if libtool now gets it right on
+	its own, let's hope so.
+
+	* configure.in, acinclude.m4 (GMP_PROG_HOST_CC): Remove, libtool no
+	longer demands HOST_CC.
+
+	* configure.in: When C or C++ compiler not found, refer user to
+	config.log.
+
+	* configure.in (i386-*-*): Turn i386 into a fat binary build.
+	* mpn/x86/fat/fat.c, mpn/x86/fat/fat_entry.asm,
+	mpn/x86/fat/gmp-mparam.h, mpn/x86/fat/gcd_1.c, mpn/x86/fat/mode1o.c:
+	New files.
+	* gmp-impl.h (struct cpuvec_t) [x86 fat]: New structure.
+	* longlong.h (COUNT_LEADING_ZEROS_NEED_CLZ_TAB) [x86 fat]: Define.
+	* mpn/asm-defs.m4 (foreach): New macro.
+	* mpn/x86/x86-defs.m4 (CPUVEC_FUNCS_LIST): New define.
+	* mpn/x86/sqr_basecase.asm: New file, primarily as a fallback for fat
+	binaries.
+	* mpn/x86/p6/gmp-mparam.h, mpn/x86/p6/mmx/gmp-mparam.h: Add comments
+	about fat binary SQR_KARATSUBA_THRESHOLD for p6 and p6/mmx.
+
+	* configure.in: Add various supports for fat binaries, via fat_path,
+	fat_functions and fat_thresholds variables.
+	* acinclude.m4 (GMP_STRIP_PATH): Mung $fat_path too.
+	(GMP_FAT_SUFFIX, GMP_REMOVE_FROM_LIST): New macros.
+	* gmp-impl.h: Add various supports for fat binaries.
+	(DECL_add_n etc): New macros.
+	(mpn_mul_basecase etc): Define only if not already defined.
+	* mpn/asm-defs.m4 (m4_config_gmp_mparam): Mention fat binary.
+	(MPN): Use m4_unquote, for the benefit of fat binary name expansion.
+	* doc/configuration: Notes on fat binaries.
+	* gmp-impl.h (MUL_TOOM3_THRESHOLD_LIMIT): Define always.
+	(MUL_KARATSUBA_THRESHOLD_LIMIT): New define.
+	* mpn/generic/mul.c, mpn/generic/mul_n.c: Use these.
+	* tune/divrem1div.c, tune/divrem1inv.c, tune/mod_1_div.c,
+	tune/mod_1_inv.c: Define OPERATION_divrem_1 and OPERATION_mod_1, to
+	tell fat.h what's being done.
+
+	* config.guess (alpha-*-*): Update comments on what configfsf.guess
+	does and doesn't do for us.
+
+2003-07-31  Kevin Ryde  <kevin@swox.se>
+
+	* config.guess: Remove $dummy.o files everywhere, in case vendor
+	compilers produce that even when not asked.
+
+	* demos/perl/GMP.xs (class_or_croak): Rename "class" parameter to
+	avoid C++ keyword.
+	(coerce_ulong, coerce_long): Move croaks to stop g++ 3.3 complaining
+	about uninitialized variables.
+
+	* demos/perl/INSTALL: Add notes on building with a DLL.
+
+	* longlong.h (count_trailing_zeros) [x86_64]: Ensure bsfq destination
+	is a 64-bit register.  Diagnosed by Francois G. Dorais.
+
+2003-07-31  Torbjorn Granlund  <tege@swox.com>
+
+	* longlong.h [ppc]: Remove nested test for vxworks.
+
+2003-07-24  Kevin Ryde  <kevin@swox.se>
+
+	* gmpxx.h (struct __gmp_binary_multiplies): Use mpz_mul_si for
+	mpz*long and long*mpz.
+	* tests/cxx/t-ops.cc (check_mpz): Exercise mpz*long and mpz*ulong.
+
+	* cxx/ismpf.cc: Use std::locale decimal point when available.  Expect
+	localeconv available always.
+	* tests/cxx/t-locale.cc: Enable check_input tests.
+
+	* gmpxx.h (struct __gmp_hypot_function): Use mpfr_hypot.
+	* tests/cxx/t-misc.cc (check_mpfr_hypot): New tests.
+
+	* tests/cxx/t-assign.cc, tests/cxx/t-binary.cc, tests/cxx/t-ops.cc,
+	tests/cxx/t-prec.cc, tests/cxx/t-ternary.cc, tests/cxx/t-unary.cc:
+	Include config.h for WANT_MPFR.
+
+	* tests/mpz/bit.c (check_single): Correction to a diagnostic print.
+
+2003-07-24  Niels Möller  <nisse@lysator.liu.se>
+
+	* mpz/combit.c: New file.
+	* Makefile.am, mpz/Makefile.am: Add it.
+	* gmp-h.in (mpz_combit): Add prototype.
+	* tests/mpz/bit.c (check_single): Exercise mpz_combit.
+
+2003-07-16  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/generic/get_d.c: Correction to infinity handling for large exp.
+
+2003-07-14  Kevin Ryde  <kevin@swox.se>
+
+	* mpz/get_d.c, mpz/get_d_2exp.c, mpf/get_d.c, mpf/get_d_2exp.c: Use
+	mpn_get_d.
+
+	* mpn/generic/get_d.c: New file, based on mpz/get_d.c and insert-dbl.c.
+	* configure.in, mpn/Makefile.am: Add it.
+	* gmp-impl.h (mpn_get_d): Add prototype.
+
+	* tests/mpn/t-get_d.c: New file.
+	* tests/mpn/Makefile.am: Add it.
+
+	* tests/mpz/t-get_d_2exp.c (check_onebit, check_round): Test negatives.
+	(check_onebit): Add a few more bit sizes.
+
+	* tests/misc.c, tests/tests.h (tests_isinf): New function.
+
+2003-07-12  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (GMP_PROG_CXX_WORKS): Include $CPPFLAGS, same as
+	automake does in the actual build.
+
+	* acinclude.m4 (GMP_PROG_CXX_WORKS): In the namespace test, declare
+	namespace before trying to use.  In std iostream test, provoke a
+	failure from Compaq C++ in pre-standard mode.
+
+2003-07-08  Kevin Ryde  <kevin@swox.se>
+
+	* acinclude.m4 (GMP_PROG_CC_WORKS): Use separate compiles for various
+	known problems, and indicate to the user the reason for rejecting.
+	(GMP_PROG_CXX_WORKS): Ditto, and insist on being able to execute each
+	compiled program.
+
+2003-07-05  Kevin Ryde  <kevin@swox.se>
+
+	* config.sub: Add comments to our alias transformations.
+
+	* configfsf.sub, configfsf.guess: Update to 2003-07-04.
+
+	* acinclude.m4 (GMP_PROG_CC_WORKS, GMP_PROG_CC_WORKS_LONGLONG): Show
+	failing program in config.log, per other autoconf tests.
+
+	* configure.in (i786-*-*): Recognise as pentium4, per configfsf.sub.
+
+2003-06-28  Kevin Ryde  <kevin@swox.se>
+
+	* mpz/get_d_2exp.c, mpf/get_d_2exp.c: Avoid res==1.0 when floats round
+	upwards.
+
+	* tests/mpz/t-get_d_2exp.c: New file.
+	* tests/mpz/Makefile.am (check_PROGRAMS): Add it.
+	* tests/mpf/t-get_d_2exp.c: New file.
+	* tests/mpf/Makefile.am (check_PROGRAMS): Add it.
+	* tests/x86call.asm, test/tests.h (x86_fldcw, x86_fstcw): New
+	functions.
+	* tests/misc.c, tests/tests.h (tests_hardware_getround,
+	tests_hardware_setround): New functions.
+
+2003-06-25  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/sparc64/dive_1.c: New file.
+
+	* mpn/sparc64/sparc64.h: New file.
+	* mpn/sparc64/mode1o.c: Remove things now in sparc64.h.
+
+	* mpfr/*: Update to mpfr cvs 2003-06-25.
+
+	* acinclude.m4 (GMP_PROG_CC_WORKS): In last change provoking gnupro
+	gcc, don't use ANSI style function definition.
+
+2003-06-22  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/pa32/hppa1_1/udiv.asm: Remove .proc, .entry, .exit and .procend,
+	handled by PROLOGUE and EPILOGUE.  Comment out .callinfo, per other
+	asm files.
+
+	* gmpxx.h (mpz_class __gmp_binary_divides, __gmp_binary_modulus): Fix
+	long/mpz and long%mpz for dividend==LONG_MIN divisor==-LONG_MIN.
+	(mpz_class __gmp_binary_modulus): Fix mpz%long for negative dividend.
+	* tests/cxx/t-ops.cc (check_mpz): Add test cases for these, merging
+	operator/ and operator% sections for clarity.
+
+2003-06-21  Kevin Ryde  <kevin@swox.se>
+
+	* mpfr/*: Update to mpfr cvs 2003-06-21.
+
+	* acinclude.m4 (GMP_PROG_CC_WORKS): Add code by Torbjorn provoking an
+	ICE from gcc 2.9-gnupro-99r1 under -O2 -mcpu=ev6.
+	* configure.in (alpha*-*-* gcc_cflags_cpu): Fallback on -mcpu=ev56 for
+	this compiler.
+
+	* gmpxx.h (get_d): Remove comments about long double, double is
+	correct for get_d, a future long double form would be get_ld.
+
+2003-06-19  Kevin Ryde  <kevin@swox.se>
+
+	* mpfr/*: Update to mpfr cvs 2003-06-19.
+
+	* mpn/generic/dive_1.c: Share src[0] fetch among all cases.  No need
+	for separate final umul_ppmm in even case, make it part of the loop.
+
+	* mpz/get_d_2exp.c, mpq/set_si.c, mpq/set_ui.c: Nailify.
+
+	* mpf/iset_si.c: Rewrite using mpf/set_si.c code, in particular this
+	nailifies it.
+	* tests/mpf/t-set_si.c: Nailify tests.
+
+	* mpf/iset_ui.c: Nailify, as per mpf/set_ui.c
+	* tests/mpf/t-set_ui.c: New file.
+	* tests/mpf/Makefile.am (check_PROGRAMS): Add it.
+
+2003-06-15  Kevin Ryde  <kevin@swox.se>
+
+	* mpfr/*: Update to mpfr cvs 2003-06-15.
+
+	* mpn/x86/k6/mode1o.asm: Remove a bogus ASSERT.
+
+2003-06-12  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (--enable-assert): Emit WANT_ASSERT to config.m4.
+	* mpn/powerpc32/powerpc-defs.m4, mpn/x86/x86-defs.m4 (ASSERT): Check
+	WANT_ASSERT is defined.
+
+	* mpn/sparc32/v9/udiv.asm: Amend heading, this file is for sparc v9.
+
+	* tests/cxx/Makefile.am (TESTS_ENVIRONMENT): In libtool openbsd hack,
+	discard error messages from cp, for the benefit of --disable-shared or
+	systems not using names libgmp.so.*.
+
+	* tests/devel/try.c (try_one): When overlapping, copy source data
+	after filling dst.  Previously probably used only DEADVAL in
+	overlapping cases.
+
+2003-06-11  Torbjorn Granlund  <tege@swox.com>
+
+	* mpf/random2.c: Rewrite.  Ignore sign of exp parameter.
+
+2003-06-10  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/sparc64/mode1o.c: New file.
+
+2003-06-09  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc32/lshift.asm: Add more cycle counts.
+	* mpn/powerpc32/rshift.asm: Add more cycle counts.
+
+	* mpn/ia64/addmul_1.asm: Reformat comments for 80 columns.
+
+	* gmp-impl.h (udiv_qrnnd_preinv1): New name for udiv_qrnnd_preinv.
+	(udiv_qrnnd_preinv2): New name for udiv_qrnnd_preinv2norm.
+	(udiv_qrnnd_preinv): New #define, making udiv_qrnnd_preinv2
+	the default.
+	* tune/speed.c: Corresponding changes.
+	* tune/speed.h: Likewise.
+	* tune/common.c: Likewise.
+
+	* mpf/get_str.c: Simplify `off' computation.
+
+	* longlong.h: Tabify.
+
+2003-06-09  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi (ABI and ISA): FreeBSD has sparc64 too, just say "BSD" to
+	cover all flavours.
+	* configure.in: Ditto in some comments.
+
+	* mpfr/*: Update to mpfr cvs 2003-06-09.
+
+	* tests/cxx/Makefile.am (LDADD): Add -L$(top_builddir)/$(LIBS), for
+	the benefit of gcc 3.2 on itanium2-hp-hpux11.22.
+
+	* tune/many.pl (mul_2): Add speed routine settings.
+	(MAKEFILE): Close when done, for the benefit of development hackery.
+
+2003-06-08  Kevin Ryde  <kevin@swox.se>
+
+	* mpfr/*: Update to mpfr cvs 2003-06-08.
+
+	* mpn/x86/x86-defs.m4 (femms): Remove fallback to emms.
+	(cmovCC, psadbw): Remove simulated versions.
+	(cmov_available_p, psadbw_available_p): Remove.
+	This trickery was only ever for development purposes on machines
+	without those instructions.  Removing it simplifies gmp and in
+	particular avoids complications for fat binary builds.  Development
+	can be done with a wrapper around "as" if really needed.
+
+	* mpn/x86/divrem_1.asm: Don't use loop_or_decljnz, now K6 has its own
+	mpn/x86/k6/divrem_1.asm.  Amend K6 comments now moved to there.
+	* mpn/x86/x86-defs.m4 (loop_or_decljnz): Remove, no longer used.
+
+	* mpn/x86/k6/divrem_1.asm: New file, derived from mpn/x86/divrem_1.asm.
+
+	* mpn/x86/k6/pre_mod_1.asm: Remove comments now in mpn/x86/mod_1.asm.
+
+	* mpn/x86/mod_1.asm: Put mpn_mod_1c after mpn_mod_1 for better branch
+	prediction.  Put done_zero at end for less wastage in alignment.  Use
+	decl+jnz unconditionally since in fact it's ok on k6.  Amend comments.
+
+2003-06-07  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/generic/mode1o.c: Fix ASSERTs on return value.
+
+	* gmp.texi (Build Options): Add viac3 and viac32 cpu types.
+	(ABI and ISA): Note on sparcv9 ABI=32 vs ABI=64 speed.  More indexing.
+
+	* configfsf.guess, configfsf.sub: Update to 2003-06-06.
+	* config.guess: Remove $RANDOM hack supporting netbsd 1.4, not needed
+	by new configfsf.guess.
+
+2003-06-06  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/ia64/submul_1.asm: Add branch over .align block.
+
+2003-06-05  Torbjorn Granlund  <tege@swox.com>
+
+	* longlong.h (add_ssaaaa) [pa64]: Output zero operand as register 0.
+	Allow more immediate operands.
+	(sub_ddmmss) [pa64]: Likewise.
+	(add_ssaaaa) [pa32]: Likewise.
+	(sub_ddmmss) [pa32]: Likewise.
+
+	* mpn/pa64: Change ".level 2.0W" to ".level 2.0w" to please
+	picky GNU assembler.
+
+2003-06-05  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi (Integer Special Functions): In mpz_array_init, fix type
+	shown for integer_array and give an example use.
+
+2003-06-04  Torbjorn Granlund  <tege@swox.com>
+
+	* mpf/set_str.c (mpf_set_str): Work around gcc 2 bug triggered on
+	alpha.
+
+2003-06-03  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/x86/pentium/README: Add 7 c/l mmx mul_1, tweak wordings.
+
+	* acinclude.m4 (GMP_C_DOUBLE_FORMAT): Use octal char constants in test
+	program, hex is not supported by K&R.
+
+2003-06-02  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/mips64/divrem_1.asm: New file.
+
+2003-06-01  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc32/lshift.asm: Reformat code.
+	* mpn/powerpc32/rshift.asm: Reformat code.
+
+2003-05-30  Kevin Ryde  <kevin@swox.se>
+
+	* tests/misc.c (tests_start): Set stdout and stderr to unbuffered, to
+	avoid any chance of losing output on segv etc.
+
+2003-05-28  Torbjorn Granlund  <tege@swox.com>
+
+	* mpf/get_str.c: Move label `done' to match TMP_MARK and TMP_FREE.
+	Remove redundant variable prec.
+
+2003-05-26  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/mpz/convert.c: Test bases up to 62.
+
+	* tests/mpf/t-conv.c: Test bases up to 62.
+
+	* demos/pexpr.c: Don't iterate to get accurate timing.
+
+	* mpf/set_str.c (mpn_pow_1_highpart): Cleanup.
+
+	* mp_dv_tab.c: Fix typo.
+
+	* mpf/get_str.c: Rewrite (now sub-quadratic).
+
+2003-05-22  Kevin Ryde  <kevin@swox.se>
+
+	* tests/mpn/t-divrem_1.c: New file.
+	* tests/mpn/Makefile.am: Add it.
+
+2003-05-22  Torbjorn Granlund  <tege@swox.com>
+
+	* config.sub: Recognize viac3* processors.
+
+2003-05-20  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/sparc64/addmul_2.asm: New file.
+
+2003-05-19  Torbjorn Granlund  <tege@swox.com>
+
+	* configure.in: Recognize alphaev7* as alphaev67.
+
+	* config.guess: Recognize viac3* processors.
+	* configure.in: Set up path for viac3* processors.
+	* acinclude.m4 (X86_PATTERN): Include viac3* processors.
+
+2003-05-19  Kevin Ryde  <kevin@swox.se>
+
+	* tune/freq.c (freq_pstat_getprocessor): New function.
+	(freq_all): Use it.
+	* configure.in (AC_CHECK_HEADERS): Add sys/pstat.h.
+	(AC_CHECK_FUNCS): Add pstat_getprocessor.
+
+2003-05-15  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/generic/mul_fft.c (mpn_mul_fft_decompose): Remove "inline",
+	since the code is a bit too big.  gcc doesn't actually inline when
+	alloca (TMP_ALLOC) is used anyway.
+
+2003-05-13  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi (Notes for Particular Systems): Libtool directory is .libs
+	not _libs for mingw dll.  Reported by Andreas Fabri.
+
+2003-05-07  Kevin Ryde  <kevin@swox.se>
+
+	* acinclude.m4 (GMP_PROG_CC_WORKS): Add code to generate sse2/xmm code
+	from gcc -march=pentium4, to check the assembler supports that.
+	(GMP_GCC_PENTIUM4_SSE2, GMP_OS_X86_XMM): New macros.
+	* configure.in (pentium4-*-*): Use them to see if gcc -march=pentium4
+	(with sse2) is ok.
+
+2003-05-06  Kevin Ryde  <kevin@swox.se>
+
+	* mpz/com.c: Rate size==0 as UNLIKELY, fix comment to mpn_add_1.
+
+	* tune/freq.c (<sys/sysinfo.h>): Include only when needed for
+	getsysinfo(), to avoid a problem with this file on AIX 5.1.
+
+2003-05-03  Torbjorn Granlund  <tege@swox.com>
+
+	* mpf/set_str.c: Do not ignore supposedly superfluous digits (in part
+	reverting last change).
+
+2003-05-03  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi: Use @code for files in @cindex entries, it looks nicer
+	than @file.
+
+	* Makefile.am: Note gmp 4.1.1 and 4.1.2 version info.
+
+	* configure.in, acinclude.m4 (GMP_CRAY_OPTIONS): New macro for Cray
+	system setups, letting AC_REQUIRE do its job instead of a hard coded
+	AC_PROG_EGREP.
+
+	* config.guess: Amend fake RANDOM to avoid ". configfsf.guess" which
+	segfaults on Debian "ash" 0.4.16.
+
+2003-05-01  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (AC_CHECK_FUNCS): Add getsysinfo.
+	(AC_CHECK_HEADERS): Add sys/sysinfo.h and machine/hal_sysinfo.h.
+	* tune/freq.c (freq_getsysinfo): New function.
+	(freq_all): Use it.
+	(freq_sysctlbyname_i586_freq, freq_sysctlbyname_tsc_freq,
+	freq_sysctl_hw_cpufrequency, freq_sysctl_hw_model): Set
+	speed_cycletime before trying to print it, when verbose.
+
+2003-04-28  Torbjorn Granlund  <tege@swox.com>
+
+	* mpf/set_str.c: Major overhaul.
+	(mpn_pow_1_highpart): New helper function, meat extracted from
+	mpf_set_str.
+
+2003-04-24  Kevin Ryde  <kevin@swox.se>
+
+	* acinclude.m4 (GMP_GCC_ARM_UMODSI): Quote result string against m4.
+
+	* configure, ltmain.sh, aclocal.m4: Update to libtool 1.5.
+
+	* longlong.h (add_ssaaaa) [all]: Remove first "%" commutative in each,
+	since gcc only supports one per asm.
+
+	* printf/doprnt.c: Add M for mp_limb_t.
+	* tests/misc/t-printf.c: Exercise this.
+
+	* tests/mpz/t-cmp_d.c: Test infinities.
+	* tests/mpf/t-cmp_d.c: New file.
+	* tests/mpf/Makefile.am: Add it.
+
+	* mpz/cmp_d.c, mpz/cmpabs_d.c, mpf/cmp_d.c: NaN invalid, Inf bigger
+	than any value.
+	* mpz/set_d.c, mpq/set_d.c, mpf/set_d.c: Nan or Inf invalid.
+
+	* configure.in (AC_CHECK_FUNCS): Add raise.
+	* invalid.c: New file.
+	* Makefile.am: Add it.
+	* gmp-impl.h (__gmp_invalid_operation): Add prototype.
+	(DOUBLE_NAN_INF_ACTION): New macro.
+
+	* tests/trace.c, tests/tests.h (d_trace): New function.
+	* tests/misc.c, tests/tests.h (tests_infinity_d): New function.
+	* tests/misc.c (mpz_erandomb, mpz_errandomb): Use gmp_urandomm_ui.
+
+	* tune/tuneup.c, tune/common.c, tests/devel/try.c: Cast various
+	mp_size_t values for printf %ld in case mp_size_t==int.  Use
+	gmp_printf for mp_limb_t values.
+
+	* gmp.texi (Nomenclature and Types): Add mp_exp_t, mp_size_t,
+	gmp_randstate_t.  Note ulong for bit counts and size_t for byte
+	counts.  Don't bother with @noindent.
+	(Debugging): New valgrind is getting MMX/SSE.
+	(Integer Comparisons): mpz_cmp_d and mpz_cmpabs_d on NaNs and Infs.
+	(Float Comparison): mpf_cmp_d behaviour on NaNs and Infs.
+	(Low-level Functions): Note with mpn_hamdist what hamming distance is.
+	(Formatted Output Strings): Add type M.
+	(Internals): Remove remarks on ulong bits and size_t bytes.  Move int
+	field remarks to ...
+	(Integer Internals, Float Internals): ... here.
+
+2003-04-19  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (*sparc*-*-* ABI=32): Add umul to extra_functions.
+
+	* mpn/x86/p6/mul_basecase.asm: New file.
+
+2003-04-18  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (m68060-*-*): Fallback to gcc -m68000 when -m68060 not
+	available, and don't use mpn/m68k/mc68020 asm routines.  (Avoids 32x32
+	mul and 64/32 div which trap to the kernel on 68060.  Advice by
+	Richard Zidlicky.)
+	* mpn/m68k/README: Update notes on directory usage.
+
+	* tests/cxx/Makefile.am (TESTS_ENVIRONMENT): Add a hack to let the
+	test programs run with a shared libgmpxx on openbsd 3.2.
+
+	* gmp.texi (Language Bindings): Add Guile.
+
+2003-04-12  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (cygwin*, mingw*, pw32*, os2*): Add
+	-Wl,--export-all-symbols to GMP_LDFLAGS, no longer the default in
+	latest mingw and libtool.
+
+	* acinclude.m4 (GMP_ASM_COFF_TYPE): New macro.
+	* configure.in (x86s): Use it.
+	* mpn/x86/x86-defs.m4 (COFF_TYPE): New macro.
+	(PROLOGUE_cpu): Use it, for the benefit of mingw DLLs.
+
+	* gmp-impl.h (mpn_copyi, mpn_copyd): Add __GMP_DECLSPEC.
+
+	* gmp.texi (Known Build Problems): Remove windows test program .exe
+	repeated built, fixed by new libtool.  Remove MacOS C++ shared library
+	creation, fixed by new libtool.
+	(Notes for Package Builds, Known Build Problems): Remove DESTDIR notes
+	on libgmpxx, fixed in new libtool.
+
+2003-04-10  Torbjorn Granlund  <tege@swox.com>
+
+	* configure.in: Match turbosparc.
+	* config.guess: Recognize turbosparc (just for *bsd for now).
+
+2003-04-09  Kevin Ryde  <kevin@swox.se>
+
+	* mpf/mul_ui.c [nails]: Call mpf_mul to handle v > GMP_NUMB_MAX.
+
+	* tests/mpz/t-mul.c (main): Don't try FFT sizes when FFT disabled via
+	MP_SIZE_T_MAX, eg. for nails.
+
+	* tests/cxx/t-ternary.cc: Split up tests to help compile speed and
+	memory usage.
+
+	* tests/devel/try.c: Print seed under -R, add -E to reseed, use ulong
+	for seed not uint.
+
+	* gmp.texi: Add @: after various abbreviations, more index entries.
+	(leftarrow): New macro, for non-tex.
+	(Random State Initialization): Remove commented gmp_randinit_lc, not
+	going to be implemented.
+	(Random Number Algorithms): New section.
+	(References): Add Matsumoto and Nishimura on Mersenne Twister, add
+	Bertot, Magaud and Zimmermann on GMP Square Root.
+
+2003-04-06  Kevin Ryde  <kevin@swox.se>
+
+	* tests/mpz/t-gcd_ui.c: New file.
+	* tests/mpz/Makefile.am: Add it.
+
+	* mpz/gcd_ui.c: Correction to return value on longlong limb systems,
+	limb might not fit a ulong.
+
+2003-04-04  Kevin Ryde  <kevin@swox.se>
+
+	* configure, aclocal.m4, ltmain.sh: Update to libtool cvs snapshot
+	2003-04-02.
+
+2003-04-02  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (*-*-cygwin*): No longer force lt_cv_sys_max_cmd_len,
+	libtool has addressed this now.
+	(AC_PROVIDE_AC_LIBTOOL_WIN32_DLL): Remove this, libtool _LT_AC_LOCK
+	no longer needs it.
+
+	* acinclude.m4 (GMP_PROG_AR): Also set ac_cv_prog_AR and
+	ac_cv_prog_ac_ct_AR when adding flags to AR, so they're not lost by
+	libtool's call to AC_CHECK_TOOL.
+
+2003-04-01  Kevin Ryde  <kevin@swox.se>
+
+	* configure, aclocal.m4, ltmain.sh: Update to libtool cvs snapshot
+	2003-03-31.
+
+	* configure.in (AC_PROG_F77): Add a dummy AC_PROVIDE to stop libtool
+	running F77 probes.
+
+	* randlc2x.c (gmp_rand_lc_struct): Add comments about what exactly is
+	in each field.
+	(randseed_lc): Rename seedp to seedz to avoid confusion with seedp in
+	the lc function.  Suggested by Pedro Gimeno.
+	(gmp_randinit_lc_2exp): Use __GMP_ALLOCATE_FUNC_TYPE.  No need for
+	"+1" in mpz_init2 of _mp_seed.  Don't bother with mpz_init2 for _mp_a.
+
+2003-03-29  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (m68k-*-*): Use -O2, no longer need to fallback to -O.
+	* acinclude.m4 (GMP_GCC_M68K_OPTIMIZE): Remove macro.
+
+	* configure.in (AC_CHECK_TYPES): Add notes on why tested.
+
+	* gmp.texi (GMPrefu, GMPpxrefu, GMPreftopu, GMPpxreftopu): New macros,
+	use them for all external references to get URLs into HTML output.
+	(Random State Initialization): Add gmp_randinit_set.
+	(Random State Miscellaneous): New section.
+
+2003-03-29  Kevin Ryde  <kevin@swox.se>
+
+	* randbui.c, randmui.c: New files.
+	* Makefile.am: Add them.
+	* gmp-h.in (gmp_urandomb_ui, gmp_urandomm_ui): Add prototypes.
+	* tests/rand/t-urbui.c, tests/rand/t-urmui.c: New files.
+	* tests/rand/Makefile.am: Add them.
+
+	* gmp-impl.h (gmp_randstate_srcptr): New typedef.
+	(gmp_randfnptr_t): Add randiset_fn.
+	* randiset.c: New file.
+	* Makefile.am: Add it.
+	* gmp-h.in (gmp_randinit_set): Add prototype.
+	* randlc2x.c, randmt.c: Add gmp_randinit_set support.
+	* tests/rand/t-iset.c: New file.
+	* tests/rand/Makefile.am: Add it.
+
+	* tests/misc.c, tests/tests.h (call_rand_algs): New function.
+
+2003-03-27  Kevin Ryde  <kevin@swox.se>
+
+	* mpz/bin_uiui.c: Use plain "*" for kacc products rather than
+	umul_ppmm since high not needed, except for an ASSERT now amended.
+
+2003-03-26  Kevin Ryde  <kevin@swox.se>
+
+	* demos/expr/exprfr.c (cbrt, cmpabs, exp2, gamma, nextabove,
+	nextbelow, nexttoward): New functions.
+	* demos/expr/t-expr.c: Exercise these.
+
+	* mpfr/*: Update to mpfr cvs 2003-03-26.
+
+	* gmp-impl.h (MPZ_REALLOC): Use UNLIKELY, to expect no realloc.
+
+	* tune/time.c (cycles_works_p): Scope variables down to relevant part
+	to avoid warnings about unused.
+
+	* configfsf.guess, configfsf.sub: Update to 2003-02-22.
+	* config.guess: Fake a $RANDOM variable when running configfsf.guess,
+	to workaround a problem on m68k NetBSD 1.4.1.
+
+	* mpz/fac_ui.c: Remove unused variable "z1".
+
+	* tune/freq.c (freq_irix_hinv): Allow "Processor 0" line from IRIX 6.5.
+
+2003-03-24  Torbjorn Granlund  <tege@swox.com>
+
+	* randlc2x.c (randget_lc): Remove write-only variable rn.
+	* mpf/eq.c: Remove write-only variable usign.
+	* gen-psqr.c (main): Remove write-only variable numb_bits.
+
+2003-03-17  Torbjorn Granlund  <tege@swox.com>
+
+	* Makefile.am (libgmp_la_SOURCES): Add mp_dv_tab.c.
+	(libmp_la_SOURCES): Add mp_dv_tab.c.
+
+	* mpn/alpha/invert_limb.asm: Add a few comments.
+
+	* mp_dv_tab.c: New file, defining __gmp_digit_value_tab.
+
+	* mpz/set_str.c: Get rid of function digit_value_in_base and use table
+	__gmp_digit_value_tab instead.
+	* mpz/inp_str.c: Likewise.
+	* mpf/set_str.c: Likewise.
+	* mpbsd/min.c: Likewise.
+	* mpbsd/xtom.c: Likewise.
+
+	* mpz/set_str.c: Allow bases <= 62.  Return error for invalid bases.
+	* mpz/inp_str.c: Likewise.
+	* mpf/set_str.c: Likewise.
+	* mpz/out_str.c: Likewise.
+	* mpz/get_str.c: Likewise.
+	* mpf/get_str.c: Likewise.
+
+	* mpz/inp_str.c: Restructure to allocate more string space just
+	before needed.
+	* mpbsd/min.c: Likewise.
+
+	* longlong.h (__udiv_qrnnd_c): Remove redundant casts.
+	(32-bit sparc): Test HAVE_HOST_CPU_supersparc in addition to various
+	sparc_v8 spellings.
+
+2003-03-17  Kevin Ryde  <kevin@swox.se>
+
+	* mpfr/*: Update to mpfr cvs 2003-03-17.
+
+2003-03-15  Kevin Ryde  <kevin@swox.se>
+
+	* Makefile.am (EXTRA_libgmp_la_SOURCES): Use this for TMP_ALLOC
+	sources, instead of a libdummy.la.
+
+2003-03-16  Torbjorn Granlund  <tege@swox.com>
+
+	* config.guess: Recognize supersparc and microsparc for *BSD systems.
+	Generalize some superscalar recognition patterns.
+
+2003-03-14  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/sparc64/udiv.asm: New file.
+
+2003-03-13  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/sparc64: Table cycle counts.  Update some comments.
+
+	* mpn/powerpc64/divrem_1.asm: New file.
+
+2003-03-10  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/mul.c (mpn_mul): Don't blindly expect
+	MUL_KARATSUBA_THRESHOLD to be a constant.
+
+2003-03-07  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/mul.c (mpn_mul): New operand splitting code for
+	avoiding cache misses when un >> MUL_KARATSUBA_THRESHOLD > vn.
+	(MUL_BASECASE_MAX_UN): New #define, default to 500 for now.
+
+2003-03-07  Kevin Ryde  <kevin@swox.se>
+
+	* Makefile.am: Put gmp.h and mp.h under $(exec_prefix)/include.
+	* gmp.texi (Build Options): Add notes on this.
+	Reported by Vincent Lefèvre.
+
+2003-03-06  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (alpha*-*-* gcc): Add asm option before testing -mcpu,
+	for the benefit of gcc 2.9-gnupro-99r1 on alphaev68-dec-osf5.1 which
+	doesn't otherwise put the assembler in the right mode for -mcpu=ev6.
+
+2003-03-05  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc32/powerpc-defs.m4: Set up renaming for v registers.
+
+	* mpz/powm.c (redc): Instead of repeated mpn_incr_u invocations,
+	accumulate carries and add at the end.
+	(mpz_powm): Trim tp allocation, now as redc doesn't need carry guard.
+
+2003-02-25  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/x86/pentium4/copyd.asm: Correct header comment.
+
+	* mpn/arm/addmul_1.asm: Correct cycle counts.
+	* mpn/arm/submul_1.asm: Likewise.
+
+2003-02-20  Kevin Ryde  <kevin@swox.se>
+
+	* demos/factorize.c (factor_using_pollard_rho): Test k>0 to avoid
+	infinite loop if k=0 and gcd!=1 reveals a factor.  Reported by John
+	Pongsajapan.
+
+	* gmp.texi, fdl.texi: Update to FDL version 1.2.
+
+2003-02-18  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/arm/mul_1.asm: Fix typo introduced in last change.
+
+2003-02-17  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/ia64/gmp-mparam.h: Retune.
+
+	* mpn/sparc64/copyi.asm: Add some header comments.
+	* mpn/sparc64/copyd.asm: Likewise.
+
+	* mpn/arm/mul_1.asm: Put vl operand last for umull/umlal.
+	Add some header comments.
+	* mpn/arm/addmul_1.asm: Rewrite.
+	* mpn/arm/submul_1.asm: Rewrite.
+	* mpn/arm/gmp-mparam.h: Retune.
+
+2003-02-16  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/arm/copyi.asm: New file.
+	* mpn/arm/copyd.asm: New file.
+
+2003-02-16  Kevin Ryde  <kevin@swox.se>
+
+	* acinclude.m4 (GMP_C_DOUBLE_FORMAT): Tolerate incorrect last data
+	byte seen on an arm system.
+
+2003-02-15  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/arm/gmp-mparam.h: Retune.
+
+2003-02-13  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc32/750/com_n.asm: Add more cycle counts.
+
+2003-02-13  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (AC_PREREQ): Bump to 2.57.
+
+	* configure.in, acinclude.m4 (GMP_GCC_WA_OLDAS): New macro, applying
+	-Wa,-oldas only when necessary.
+
+	* configure.in (powerpc*-*-*): Don't use -Wa,-mppc with gcc, it
+	overrides options recent gcc adds for -mcpu, making generated code
+	fail to assemble.
+
+	* tune/tuneup.c (mpn_fft_table): Remove definition, it's in mul_fft.c.
+
+2003-02-12  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/x86/pentium4/sse2/gmp-mparam.h: Retune.
+	* mpn/x86/k7/gmp-mparam.h: Retune.
+	* mpn/x86/k6/gmp-mparam.h: Retune.
+	* mpn/x86/p6/gmp-mparam.h: Retune.
+	* mpn/x86/p6/mmx/gmp-mparam.h: Retune.
+
+	* tests/mpz/t-mul.c (main): Rewrite FFT testing code.
+
+2003-02-10  Torbjorn Granlund  <tege@swox.com>
+
+	* config.guess: Recognize "power2" systems.
+
+	* mpn/powerpc64/gmp-mparam.h: Fix indentation.
+	* mpn/power/gmp-mparam.h: Retune.
+	* mpn/alpha/ev6/nails/gmp-mparam.h: Retune.
+	* mpn/sparc64/gmp-mparam.h: Retune.
+	* mpn/pa64/gmp-mparam.h: Retune.
+	* mpn/sparc32/v8/supersparc/gmp-mparam.h: Retune.
+	* mpn/sparc32/v8/gmp-mparam.h: Retune.
+	* mpn/mips64/gmp-mparam.h: Retune.
+	* mpn/alpha/ev6/gmp-mparam.h: Retune.
+	* mpn/powerpc32/gmp-mparam.h: Retune.
+	* mpn/powerpc32/750/gmp-mparam.h: Retune.
+	* mpn/alpha/ev5/gmp-mparam.h: Retune.
+	* mpn/m68k/gmp-mparam.h: Retune.
+	* mpn/cray/gmp-mparam.h: Set GET_STR_PRECOMPUTE_THRESHOLD.
+
+	* configure.in: Undo this, problem doesn't happen any more:
+	(mips64*-*-*): Pass just -O1 to cc, to work around compiler bug.
+
+2003-02-03  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-impl.h (MPN_NORMALIZE, MPN_NORMALIZE_NOT_ZERO): Add parens
+	around macro parameters.  Reported by Jason Moxham.
+
+2003-02-01  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi (Low-level Functions): No overlap permitted by mpn_mul_n.
+	Reported by Jason Moxham.
+	(Formatted Input Strings): Correction to strtoul cross reference
+	formatting.
+	(BSD Compatible Functions): Add index entry for MINT.
+
+2003-01-29  Torbjorn Granlund  <tege@swox.com>
+
+	* gmp-impl.h (mpn_mul_fft): Now returns int.
+
+2003-01-29  Paul Zimmermann  <Paul.Zimmermann@loria.fr>
+
+	* mpn/generic/mul_fft.c: Major rewrite.
+
+2003-01-25  Kevin Ryde  <kevin@swox.se>
+
+	* config.guess (powerpc*-*-*): Remove $dummy.core file when mfpvr
+	fails on NetBSD.
+	(trap): Remove $dummy.core on abnormal termination too.
+
+	* mpfr/*: Update to mpfr cvs 2003-01-25.
+
+2003-01-24  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/ia64/README: Update cycle counts to match current code.
+
+2003-01-18  Kevin Ryde  <kevin@swox.se>
+
+	* mpfr/*: Update to mpfr cvs 2003-01-18.
+
+2003-01-17  Torbjorn Granlund  <tege@swox.com>
+
+	* gmp.texi: Canonicalize URLs.
+
+2003-01-15  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi (Notes for Particular Systems): Add hardware floating point
+	precision mode.
+
+	* mpfr/*, configure, aclocal.m4, config.in: Update to mpfr cvs
+	2003-01-15.
+
+2003-01-11  Kevin Ryde  <kevin@swox.se>
+
+	* mpfr/*: Update to mpfr cvs 2003-01-11.
+
+2003-01-09  Kevin Ryde  <kevin@swox.se>
+
+	* mpfr/get_str.c: Update to mpfr cvs 2003-01-09.
+
+	* doc/configuration: Various updates.
+
+2003-01-06  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/alpha/copyi.asm: Avoid `nop' mnemonic, unsupported on Cray.
+	* mpn/alpha/copyd.asm: Likewise.
+
+2003-01-05  Kevin Ryde  <kevin@swox.se>
+
+	* demos/expr/t-expr.c (check_r): Tolerate mpfr_set_str new return
+	value.
+
+	* configure, aclocal.m4 (*-*-osf4*, *-*-osf5*): Regenerate with
+	libtool patch to avoid bash printf option problem when building shared
+	libraries with cxx.
+
+	* configure.in (pentium4-*-*): Use "-march=pentium4 -mno-sse2" since
+	sse2 causes buggy code from gcc 3.2.1 and is only supported on new
+	enough kernels.
+
+	* acinclude.m4 (GMP_PROG_NM): Add some notes about failures, per
+	report by Krzysztof Kozminski.
+
+	* gmp-h.in (mpz_mdivmod_ui, mpz_mmod_ui): Add parens around "r".
+
+	* gmp-h.in (__GMP_CAST): New macro, clean to g++ -Wold-style-cast.
+	(GMP_NUMB_MASK, mpz_cmp_si, mpq_cmp_si, mpz_odd_p, mpn_divexact_by3,
+	mpn_divmod): Use it.  Reported by Krzysztof Kozminski.
+	(mpz_odd_p): No need for the outermost cast to "int".
+	* tests/cxx/t-cast.cc: New file.
+	* tests/cxx/Makefile.am: Add it.
+
+2003-01-04  Kevin Ryde  <kevin@swox.se>
+
+	* mpfr/set_str.c: Update to mpfr cvs 2003-01-04.
+
+	* demos/expr/exprfra.c (e_mpfr_number): Tolerate recent mpfr_set_str
+	returning count of characters accepted.
+
+2003-01-03  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/alpha/copyi.asm: New file.
+	* mpn/alpha/copyd.asm: New file.
+
+2003-01-03  Kevin Ryde  <kevin@swox.se>
+
+	* demos/expr/t-expr.c: Use __gmpfr on some mpfr internals that have
+	changed.
+
+	* mpfr/*, aclocal.m4, config.in, configure: Update to mpfr cvs
+	2003-01-03.
+
+	* gmp.texi (Introduction to GMP): Mention release announcements
+	mailing list, and put home page and ftp before mailing lists.
+
+2002-12-28  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/mul_fft.c (mpn_fft_next_size): Simplify.
+
+2002-12-28  Kevin Ryde  <kevin@swox.se>
+
+	* acinclude.m4 (M68K_PATTERN): New macro.
+	(GMP_GCC_M68K_OPTIMIZE): Use it to avoid m6811 and friends.
+	* configure.in: Ditto.
+
+	* tests/mpz/t-import.c, tests/mpz/t-export.c: Use '\xHH' to avoid
+	warnings about char overflows.
+	* acinclude.m4 (GMP_C_DOUBLE_FORMAT): Ditto.
+
+2002-12-28  Pedro Gimeno  <pggimeno@wanadoo.es>
+
+	* randmt.c (randseed_mt, default_state): Fix off-by-one bug on padding.
+	(randseed_mt): Add ASSERT checking result of mpz_export.
+
+2002-12-24  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi (Integer Import and Export): Clarify treatment of signs,
+	reported by Kent Boortz.
+
+	* randmt.c: Use gmp_uint_least32_t.
+	(randseed_mt): Add nails to mpz_export in case mt[i] more than 32 bits.
+
+	* gmp-impl.h (gmp_uint_least32_t): New typedef, replacing GMP_UINT32.
+	* configure.in (AC_CHECK_TYPES): Add uint_least32_t.
+	(AC_CHECK_SIZEOF): Add unsigned short.
+
+2002-12-22  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-impl.h (ULONG_PARITY) [generic C]: Mask result to a single bit.
+	(ULONG_PARITY) [_CRAY, __ia64]: New macros.
+	* tests/t-parity.c: New test.
+	* tests/Makefile.am (check_PROGRAMS): Add it.
+
+	* longlong.h (count_trailing_zeros) [ia64]: New macro.
+
+	* tests/t-count_zeros.c (check_various): Remove unused variable "n".
+
+	* mpn/x86/README: Revise notes on PIC, PLT and GOT.
+
+	* demos/perl/GMP.xs, demos/perl/GMP.pm, demos/perl/test.pl: Add "mt"
+	to GMP::Rand::randstate.
+
+2002-12-22  Pedro Gimeno  <pggimeno@wanadoo.es>
+
+	* randmt.c (randseed_mt): Fix bug that might cause the generator to
+	return all zeros with certain seeds.  Fix WARM_UP==0 case.
+	(gmp_randinit_mt): Initialize to a known state by default.
+	(randget_mt): Remove check for uninitialized buffer: no longer needed.
+	(recalc_buffer): Use ?: instead of two-element array.
+
+	* tests/rand/t-mt.c: New test.
+	* tests/rand/Makefile.am (check_PROGRAMS): Add it.
+
+2002-12-21  Kevin Ryde  <kevin@swox.se>
+
+	* cxx/osdoprnti.cc: Use <cstdarg> and <cstring> rather than <stdarg.h>
+	and <string.h>.  No need for <stdio.h>.
+
+	* demos/expr/expr.c, demos/expr/exprfa.c, demos/expr/exprfra.c,
+	demos/expr/exprza.c: Use mp_get_memory_functions, not
+	__gmp_allocate_func etc.
+	* demos/expr/t-expr.c: Don't use gmp-impl.h.
+	(numberof): New macro.
+
+	* gmp-h.in, gmp-impl.h (__gmp_allocate_func, __gmp_reallocate_func,
+	__gmp_free_func): Move declarations to gmp-impl.h
+
+	* mp_get_fns.c: New file.
+	* Makefile.am (libgmp_la_SOURCES, libmp_la_SOURCES): Add it.
+	* gmp-h.in (mp_get_memory_functions): Add prototype.
+	* gmp.texi (Custom Allocation): Add mp_get_memory_functions, refer to
+	"free" not "deallocate" function.
+	* gmpxx.h (struct __gmp_alloc_cstring): Use mp_get_memory_functions,
+	not __gmp_free_func.
+
+	* gmp-impl.h [__cplusplus]: Add <cstring> for strlen.
+	(gmp_allocated_string): Hold length in a field.
+	* cxx/osdoprnti.cc, cxx/osmpf.cc: Use this.
+
+2002-12-20  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/mpz/t-perfsqr.c (check_sqrt): Print more variables upon
+	failure.
+
+	* mpn/generic/rootrem.c: In Newton loop, pad qp with leading zero.
+
+2002-12-19  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/rootrem.c: Allocate 1.585 (log2(3)) times more space
+	for pp temporary to allow for worst case overestimate of root.
+	Add some asserts.
+
+	* tests/mpz/t-root.c: Generalize and speed up.
+
+2002-12-19  Kevin Ryde  <kevin@swox.se>
+
+	* tests/cxx/t-rand.cc (check_randinit): Add gmp_randinit_mt test.
+
+	* gmp-h.in: Don't bother trying to support Compaq C++ in pre-standard
+	I/O mode.
+	* gmp.texi (Notes for Particular Systems): Compaq C++ must be used in
+	"standard" iostream mode.
+
+2002-12-18  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/alpha/mod_34lsub1.asm: Add code for big-endian, using existing
+	little-endian code only if HAVE_LIMB_LITTLE_ENDIAN is defined.
+
+2002-12-18  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (HAVE_LIMB_BIG_ENDIAN, HAVE_LIMB_LITTLE_ENDIAN): New
+	defines in config.m4.
+
+2002-12-17  Torbjorn Granlund  <tege@swox.com>
+
+	* printf/printffuns.c (gmp_fprintf_reps): Make it actually work
+	for padding > 256.
+
+2002-12-17  Kevin Ryde  <kevin@swox.se>
+
+	* tune/freq.c: Add <string.h> for memcmp.
+
+	* mpz/pprime_p.c: Use MPN_MOD_OR_MODEXACT_1_ODD.
+
+	* gmp.texi (Formatted Output Strings): %a and %A are C99 not glibc.
+	(Formatted Input Strings): Type "l" is for double too.  Hex floats are
+	accepted for mpf_t.
+	(Formatted Input Functions): Describe tightened parse rule, clarify
+	return value a bit.
+
+	* scanf/doscan.c: Add hex floats, tighten matching to follow C99, for
+	instance "0x" is no longer acceptable to "%Zi".
+	Rename "invalid" label to avoid "invalid" variable, SunOS cc doesn't
+	like them the same.
+	* tests/misc/t-scanf.c: Update tests.
+	* tests/misc/t-locale.c (check_input): Don't let "0x" appear from fake
+	decimal point.
+
+	* config.guess (sparc*-*-*): Look at BSD sysctl hw.model to recognise
+	ultrasparcs.
+
+	* mpfr/tests/dummy.c: New file.
+	* mpfr/tests/Makefile.am (libfrtests_a_SOURCES): Add it.
+
+2002-12-14  Kevin Ryde  <kevin@swox.se>
+
+	* mpbsd/Makefile.am (nodist_libmpbsd_la_SOURCES): Move these mpz
+	sources to libmpbsd_la_SOURCES directly, automake 1.7.2 now gets the
+	ansi2knr setups right for sources in other directories.
+
+	* mpfr/tests/Makefile.am: Add libfrtests.a in preparation for new mpfr.
+
+2002-12-13  Kevin Ryde  <kevin@swox.se>
+
+	* mpfr/Makefile.am (mpfr_TEXINFOS, AM_MAKEINFOFLAGS): Allow for
+	fdl.texi in recent mpfr.
+
+	* configure.in (AC_PROG_EGREP): Ensure this is run outside the Cray
+	conditional AC_EGREP_CPP.
+
+	* configure.in (alpha*-*-*): Use gcc -Wa,-oldas if it works, to avoid
+	problems with new compaq "as" on OSF 5.1.
+
+	* mpn/Makefile.am (EXTRA_DIST): Remove Makeasm.am, automake 1.7.2 does
+	it automatically.
+
+	* acinclude.m4 (AC_LANG_FUNC_LINK_TRY(C)): Remove this hack, fixed by
+	autoconf 2.57.
+
+	* configure.in (AC_CONFIG_LIBOBJ_DIR): Set to mpfr, for the benefit of
+	new mpfr using LIBOBJ.
+
+	* configure.in: (AM_INIT_AUTOMAKE): Use "gnu no-dependencies
+	$(top_builddir)/ansi2knr".
+	* */Makefile.am (AUTOMAKE_OPTIONS): Remove, now in configure.in.
+
+	* configure, config.in, INSTALL.autoconf: Update to autoconf 2.57.
+	* */Makefile.in, configure, aclocal.m4, install-sh, mkinstalldirs:
+	Update to automake 1.7.2.
+
+	* gmp.texi (Build Options): Add hppa64 to cpu types.
+	(ABI and ISA): Add gcc to hppa 2.0.
+	(Debugging): Add maximum debuggability config options.
+	(Language Bindings): Add Arithmos, reported by Johan Vervloet.
+	(Formatted Output Strings): 128 bits is about 40 digits, ll is only
+	for long long not long double.
+	(Formatted Input Strings): ll is only for long long not long double.
+
+	* mpz/divis.c, mpz/divis_ui.c, mpz/cong.c, mpz/cong_ui.c: Allow d=0,
+	under the rule n==c mod d iff exists q satisfying n=c+q*d.
+	* gmp.texi (Integer Division): Describe this.
+	Suggested by Jason Moxham.
+
+2002-12-13  Pedro Gimeno  <pggimeno@wanadoo.es>
+
+	* randlc2x.c (lc): Remove check for seedn < an, which is now
+	superfluous.  Add ASSERT to ensure it's correct.  Add ASSERT to check
+	precondition of __GMPN_ADD.
+	(gmp_randinit_lc_2exp): Avoid reallocation by allocating one extra bit
+	for both seed and a.  Simplify seedn < p->_cn case.
+
+	* tests/rand/t-lc2exp.c (check_bigs): Test negative seeds.
+
+2002-12-12  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/pa32/pa-defs.m4 (PROLOGUE_cpu): Zap spurious argument to `.proc'.
+	Add empty `.callinfo'.
+
+2002-12-11  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/x86/pentium4/sse2/addmul_1.asm: Don't reuse `ret' symbol for a
+	label.
+
+2002-12-11  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (hppa*-*-*): Don't use gcc -mpa-risc-2-0 in ABI=1.0.
+
+	* mpn/pa32/pa-defs.m4: New file, arranging for .proc/.procend.
+	* configure.in (hppa*-*-*): Use it.
+
+	* printf/doprnt.c: Comments on "ll" versus "L".
+
+	* tests/mpz/t-div_2exp.c: Reduce tests, especially the random ones.
+
+2002-12-11  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/get_d.c (limb2dbl): New macro for conversion to `double'.
+	Define it to something non-trivial for 64-bit hppa.
+	* mpq/get_d.c: Likewise.
+	* mpf/get_d.c: Likewise.
+
+	* mpn/x86/pentium4/sse2/addmul_1.asm: Unroll to save one c/l.
+
+2002-12-09  Kevin Ryde  <kevin@swox.se>
+
+	* tune/Makefile.am: Don't use -static under --disable-static, it tends
+	not to work.
+	* configure.in (ENABLE_STATIC): New AM_CONDITIONAL.
+
+	* gmp-h.in: Use <iostream> instead of <iosfwd> with Compaq C++ in
+	pre-standard I/O mode.
+
+	* tests/mpz/t-jac.c, tests/mpz/t-scan.c: Reduce tests.
+
+2002-12-08  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (*-*-ultrix*): Remove forcible --disable-shared,
+	believe this was a generic problem with libtool, now gone.
+
+2002-12-08  Torbjorn Granlund  <tege@swox.com>
+
+	* gmp-impl.h (USE_LEADING_REGPARM): Disable for PIC code generation.
+
+2002-12-07  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/cxx/t-misc.cc (check_mpq): Use 0/1 for canonical 0 in
+	mpq_cmp_ui calls.
+
+	* configure.in (hppa2.0*-*-*): Pass +O2 instead of +O3 to work around
+	compiler bug with mpfr/tests/tdiv.
+
+2002-12-07  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (hppa2.0*-*-* ABI=2.0n): Make -mpa-risc-2-0 optional.
+	New hppa-level-2.0 test using GMP_HPPA_LEVEL_20 to detect assembler
+	support for 2.0n.
+	* acinclude.m4 (GMP_PROG_CC_WORKS): Add code that provokes an error
+	from gcc -mpa-risc-2-0 if the assembler doesn't know 2.0 instructions.
+	(GMP_HPPA_LEVEL_20): New macro.
+
+2002-12-07  Pedro Gimeno  <pggimeno@wanadoo.es>
+
+	* gmp-impl.h (gmp_randfnptr_t.randseed_fn) Return void.
+	(LIMBS_PER_ULONG, MPN_SET_UI): New macros.
+	(MPZ_FAKE_UI): Rename couple of parameters.
+
+	* randlc2x.c (gmp_rand_lc_struct): _mp_c and _mp_c_limbs replaced
+	with mpn style _cp and _cn.  All callers changed.
+	(randseed_lc): Fix limbs(seed) > bits_to_limbs(m2exp) case.
+	Remove return value.
+	(gmp_randinit_lc_2exp): Attempt to avoid redundant reallocation.
+
+	* randmt.c (mangle_seed): New function by Kevin.
+	(randseed_mt): Use it instead of mpz_powm, for performance.  Remove
+	return value.  Remove commented out code (an inferior alternative to
+	mpz_export).
+
+	* randsdui.c (gmp_randseed_ui): Use MPZ_FAKE_UI.
+
+	* tests/rand/t-lc2exp.c (check_bigm, check_bigs): New tests.
+	* tests/rand/t-urndmm.c: Add L to constants in calls, for K&R.
+
+2002-12-06  Torbjorn Granlund  <tege@swox.com>
+
+	* configure.in: Remove -g.
+	(hppa*-*-*): Pass -Wl,+vnocompatwarnings with +DA2.0.
+
+2002-12-05  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/pa64/sqr_diagonal.asm: Remove .entry, .proc, .procend.
+	* mpn/pa64/udiv.asm: Likewise.
+
+2002-12-05  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/pa64/sub_n.asm: Remove space in "sub, db" which gas objects to.
+	* mpn/pa64/*.asm, tune/hppa2.asm: Use ".level 2.0" for 2.0n, since gas
+	doesn't like ".level 2.0N".
+
+	* configure.in (hppa*-*-*): Group path and flags choices, for clarity.
+	(hppa1.0*-*-*): Use gcc -mpa-risc-1-0 when available.
+	(hppa2.0*-*-*): Ditto -mpa-risc-2-0.
+	(*-*-hpux*): Exclude ABI=2.0w for hpux[1-9] and hpux10, rather than
+	the converse of allowing it for hpux1[1-9]; ie. list the bad systems
+	rather than try to guess the good systems.
+	(hppa2.0*-*-*) [ABI=2.0n ABI=2.0w]: Add gcc to likely compilers.
+	(hppa*-*-*) [gcc]: Test sizeof(long) to differentiate a 32-bit or
+	64-bit build of the compiler.
+	(hppa64-*-*): Add this as equivalent to hppa2.0-*-*.
+	* acinclude.m4 (GMP_C_TEST_SIZEOF): New macro.
+
+	* tests/tests.h (ostringstream::str): Must null-terminate
+	ostrstream::str() for the string constructor.
+
+2002-12-04  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/pa32/hppa1_1/udiv.asm: Don't wrap symbol to INT64 in L() stuff.
+
+	* longlong.h (mpn_udiv_qrnnd_r based udiv_qrnnd): Fix typo.
+
+	* mpn/powerpc32/powerpc-defs.m4: Define float registers with `f'
+	prefix.
+
+2002-12-04  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi (Floating-point Functions): Note the mantissa is binary and
+	decimal fractions cannot be represented exactly.  Suggested by Serge
+	Winitzki.
+	(Known Build Problems): Note libtool stripping options when linking.
+	Reported by Vincent Lefevre.
+
+	* acinclude.m4 (GMP_ASM_LABEL_SUFFIX): Don't make an empty result a
+	failure, that's a valid result.
+	(GMP_ASM_GLOBL): Establish this from the host cpu type.
+	(IA64_PATTERN): New macro.
+	(GMP_PROG_EXEEXT_FOR_BUILD, GMP_C_FOR_BUILD_ANSI,
+	GMP_CHECK_LIBM_FOR_BUILD): Remove temporary files created.
+	* configure.in: Use IA64_PATTERN.
+
+2002-12-03  Torbjorn Granlund  <tege@swox.com>
+
+	* tune/hppa.asm: Use config.m4.
+	* tune/hppa2.asm: Likewise.
+	* tune/hppa2w.asm: Likewise.
+
+	* mpn/pa64: Use LDEF.
+
+2002-12-03  Kevin Ryde  <kevin@swox.se>
+
+	* INSTALL: Use return rather than exit in the example programs.
+	Suggested by Richard Dawe.
+
+	* gmp.texi (Build Options): Move non-unix notes to ...
+	(Notes for Particular Systems): ... here.  Mention MS Interix,
+	reported by Paul Leyland.
+	(C++ Interface Random Numbers): Add gmp_randinit_mt to examples.
+
+	* acinclude.m4 (GMP_ASM_LABEL_SUFFIX): Must test empty suffix first,
+	for the benefit of hppa hp-ux.
+	(GMP_ASM_UNDERSCORE): Grep the output of "nm" instead of trying to
+	construct an asm file, and in case of failure fallback on no
+	underscore and a warning.
+
+	* longlong.h (count_leading_zeros, count_trailing_zeros) [ev67, ev68]:
+	Restrict __asm__ ctlz and cttz to __GNUC__.
+
+	* gen-psqr.c (HAVE_CONST, const): New macros.
+
+	* tests/cxx/t-rand.cc (check_randinit): Add gmp_randinit_mt.
+
+2002-12-02  Torbjorn Granlund  <tege@swox.com>
+
+	* gmp-impl.h: Split popc_limb again, combined version gives too many
+	compiler warnings.
+
+2002-12-01  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/gcdext.c (div1): Disable unused function.
+
+	* mpz/root.c: Don't include stdlib.h or longlong.h.
+	* mpz/rootrem.c: Likewise.
+
+	* extract-dbl.c: abort => ASSERT_ALWAYS.
+	* mpz/set_d.c: Likewise.
+	* mpn/generic/tdiv_qr.c: Likewise.
+
+	* gen-psqr.c (f_cmp_fraction, f_cmp_divisor): Change parameter to
+	`const void *', to match qsort spec.
+
+2002-12-01  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi (Integer Division): Fix a couple of @math's for tex.
+	Use @dots in more places.
+
+	* tests/cxx/t-locale.cc: Test non std::locale systems too.
+	* tests/cxx/clocale.c: New file, reinstating what was localeconv.c,
+	and subverting nl_langinfo too.
+	* tests/cxx/Makefile.am (t_locale_SOURCES): Add it.
+
+	* tests/tests.h (ostringstream, istringstream): Provide fakes of these
+	if <sstream> not available.
+	* tests/cxx/t-locale.cc, tests/cxx/t-ostream.cc: Remove <sstream>.
+	* configure.in (AC_CHECK_HEADERS) [C++]: Add <sstream>.
+
+2002-11-30  Torbjorn Granlund  <tege@swox.com>
+
+	* printf/doprnt.c (__gmp_doprnt): Comment out a `break' to shut up
+	compiler warnings.
+
+	* mpn/ia64/invert_limb.asm: Add `many' hints to return insns.
+
+	* mpn/ia64/divrem_1.asm: Allocate more local registers; put b0 in
+	one of them.
+
+	* mpn/ia64/popcount.asm: Properly restore register ar.lc.
+
+	* longlong.h (umul_ppmm) [ia64]: Form both product parts in asm.
+
+	* mpz/bin_uiui.c: Cast umul_ppmm operands.
+
+	* scanf/doscan.c (gmpscan): Remove unused label store_get_digits.
+
+	* gmp-impl.h: #undef MIN and MAX before #defining.
+
+	* mpn/ia64/copyi.asm: Add `;' after bundle declarators.
+	* mpn/ia64/copyd.asm: Likewise.
+
+	* mpn/ia64/divrem_1.asm: Add some syntax to placid the HP-UX assembler.
+
+2002-11-30  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (AC_CHECK_HEADERS): Add nl_types.h.
+	* tests/misc/t-locale.c: Use this, for nl_item on netbsd 1.4.1.
+
+2002-11-29  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/devel/addmul_1.c: Provide prototype for mpn_print.
+	(OPS): Account for function overhead.
+	* tests/devel/{submul_1.c,mul_1.c,add_n.c,sub_n.c}: Likewise.
+
+	* mpn/ia64/addmul_1.asm: Rewrite.
+
+2002-11-28  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/ia64/sqr_diagonal.asm: Don't allocate any registers.
+
+	* mpn/ia64/submul_1.asm: Adapt to Itanium 2.
+
+	* mpn/ia64/mul_1.asm: Fix typo in HAVE_ABI_32 code.
+
+	* mpn/ia64/add_n.asm: Rewrite.
+	* mpn/ia64/sub_n.asm: Rewrite.
+
+2002-11-28  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/Makefile.am (nodist_EXTRA_libmpn_la_SOURCES): Use this rather
+	than libdummy.
+	* tests/Makefile.am (EXTRA_libtests_la_SOURCES): Use this for
+	x86call.asm and x86check.c rather than libdummy.
+
+2002-11-27  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/mpz/t-mul.c: Implement reference Karatsuba multiplication.
+	Rewrite testing scheme to run fewer really huge tests.
+
+2002-11-26  Torbjorn Granlund  <tege@swox.com>
+
+	* tests: Decrease repetition count for some of the slowest tests.
+
+	* mpn/ia64/divrem_1.asm: New file.
+
+2002-11-25  Torbjorn Granlund  <tege@swox.com>
+
+	* mpfr/tests/tdiv.c: Decrease number of performed tests.
+
+2002-11-23  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/ia64/mul_1.asm: Rewrite.
+
+2002-11-23  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/ia64/README: Add some references.
+
+	* gmp.texi (Build Options): Add itanium and itanium2, mention DocBook
+	and XML from makeinfo, add texinfo top level cross reference.
+	(Integer Division): Try to clarify 2exp functions a bit.
+	(C++ Interface Floats): Giving bad string to constructor is undefined.
+	(C++ Interface Integers, C++ Interface Rationals): Ditto, and show
+	default base in prototype, not the description.
+
+	* config.sub, config.guess, configure.in (itanium, itanium2): New cpu
+	types.
+
+	* tests/misc/t-printf.c, tests/misc/t-scanf.c (check_misc): Suppress
+	%zd test on glibc prior to 2.1, it's not supported.
+
+2002-11-22  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/ia64/copyi.asm: Optimize for Itanium 2.
+	* mpn/ia64/copyd.asm: Likewise.
+
+2002-11-20  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/ia64/sqr_diagonal.asm: New file.
+
+	* mpn/ia64/submul_1.asm: Handle vl == 0 specially.
+
+2002-11-20  Kevin Ryde  <kevin@swox.se>
+
+	* tests/cxx/t-locale.cc: Test with locales imbued into stream, use
+	<sstream>, eliminated some C-isms.  istream tests disabled, not yet
+	locale-ized.
+	* tests/cxx/Makefile.am (t_locale_SOURCES): Remove localeconv.c.
+	* tests/cxx/localeconv.c: Remove file.
+
+	* configure.in (AC_CHECK_TYPES) [C++]: Add std::locale.
+	* printf/doprntf.c: Add decimal point parameter, remove localeconv use.
+	* gmp-impl.h (__gmp_doprnt_mpf): Update prototype, bump symbol to
+	__gmp_doprnt_mpf2 to protect old libgmpxx.
+	* cxx/osmpf.cc: Use this with ostream locale decimal_point facet.
+	* printf/doprnt.c: Ditto, with GMP_DECIMAL_POINT.
+
+	* gmp-h.in: More comments on __declspec for windows DLLs.
+
+	* mpf/set_str.c, scanf/doscan.c: Cast through "unsigned char" for
+	decimal point string, same as input chars.
+
+	* configure.in (AC_CHECK_HEADERS): Add langinfo.h.
+	(AC_CHECK_FUNCS): Add nl_langinfo.
+	* gmp-impl.h (GMP_DECIMAL_POINT): New macro.
+	* mpf/out_str.c, mpf/set_str.c, scanf/doscan.c: Use it, and don't
+	bother with special code for non-locale systems.
+	* tests/misc/t-locale.c: Subvert nl_langinfo too.
+
+	* configure.in, acinclude.m4 (GMP_ASM_X86_GOT_UNDERSCORE): New macro.
+	* mpn/x86/x86-defs.m4 (_GLOBAL_OFFSET_TABLE_): New macro, inserting
+	extra underscore for OpenBSD.
+	* mpn/x86/README (_GLOBAL_OFFSET_TABLE_): Update notes.
+	Reported by Christian Weisgerber.
+
+	* tests/cxx/t-rand.cc (check_randinit): New function, collecting up
+	constructor tests.
+
+	* tests/cxx/t-ostream.cc: Use <sstream> instead of <strstream>, use
+	compare instead of strcmp.
+
+	* gmpxx.h (__gmp_randinit_lc_2exp_size_t): Return type is int.
+
+2002-11-18  Kevin Ryde  <kevin@swox.se>
+
+	* tune/speed.c (r_string): Use CNST_LIMB with <N>bits, spotted by
+	Torbjorn.
+
+2002-11-19  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/ia64/mul_1.asm: Remove redundant cmp from prologue code.
+	Streamline prologue.
+	* mpn/ia64/addmul_1.asm: Likewise.
+	* mpn/ia64/submul_1.asm: New file.
+	* mpn/ia64/submul_1.c: Remove.
+
+2002-11-17  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/popham.c: New file, using new faster algorithm.
+	* mpn/generic/popcount.c: Remove.
+	* mpn/generic/hamdist.c: Remove.
+
+	* mpn/ia64/addmul_1.asm: Don't clobber callee-saves register f16.
+	* mpn/ia64/mul_1.asm: Likewise.
+
+	* mpn/ia64/addmul_1.asm: Add pred.rel declarations.  Resolve RAW
+	hazards for condition code registers, duplicating code as needed.  Add
+	prediction to all branches.
+	* mpn/ia64/mul_1.asm: Likewise.
+	* mpn/ia64/add_n.asm: Likewise.
+	* mpn/ia64/sub_n.asm: Likewise.
+	* mpn/ia64/copyi.asm: Likewise.
+	* mpn/ia64/copyd.asm: Likewise.
+
+	* mpn/generic/random2.c: Add a cast to silence some compilers.
+
+2002-11-16  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/powm.c: Cap allocation by limiting k to 10 (512 precomputed
+	values).
+
+2002-11-16  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in, gmp.texi: Remove powerpc64 ABI=32L, doesn't work and
+	is unlikely to ever do so.
+	* configure.in: Allow ABI=32 for powerpc64.
+	Reported by David Edelsohn.
+
+2002-11-14  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/Makefile.am (nodist_libdummy_la_SOURCES): Add addmul_2.c
+	addmul_3.c addmul_4.c addmul_5.c addmul_6.c addmul_7.c addmul_8.c.
+
+	* gmp-h.in (__GMP_DECLSPEC_EXPORT, __GMP_DECLSPEC_IMPORT) [__GNUC__]:
+	Use __dllexport__ and __dllimport__ to keep out of application
+	namespace.
+
+2002-11-14  Gerardo Ballabio <gerardo.ballabio@unimib.it>
+
+	* gmpxx.h (__gmp_randinit_default_t, __gmp_randinit_lc_2exp_t,
+	__gmp_randinit_lc_2exp_size_t): Use extern "C" { typedef ... }, for
+	the benefit of g++ prior to 3.2.
+
+2002-11-12  Kevin Ryde  <kevin@swox.se>
+
+	* gmpxx.h (gmp_randclass constructors): Patch from Roberto Bagnara to
+	use extern "C" on C function pointer arguments.
+
+2002-11-09  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in, Makefile.am, printf/Makefile.am,
+	printf/repl-vsnprintf.c: Handle vsnprintf replacement with C
+	conditionals.
+
+	* acinclude.m4 (AC_LANG_FUNC_LINK_TRY(C)): Workaround troubles recent
+	HP cc +O3 causes for AC_CHECK_FUNCS.
+
+	* gmp.texi (Notes for Particular Systems): Add Sparc app regs.
+	(Debugging): Note gcc -fstack options to detect overflow.
+	(Formatted Output Strings, Formatted Input Strings): Format strings
+	are not multibyte.
+
+2002-11-06  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/tdiv_qr.c: Remove a bogus assert.
+
+2002-11-05  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/tdiv_qr.c: Remove two dead mpn_divrem_2 calls.
+
+2002-11-04  Kevin Ryde  <kevin@swox.se>
+
+	* acinclude.m4 (GMP_C_INLINE): Don't define "inline" for C++.
+
+	* demos/expr/expr-impl.h (stdarg.h): Test __DECC same as gmp.h.
+
+	* mpbsd/mtox.c, printf/obprintf.c, printf/obvprintf.c,
+	scanf/vsscanf.c, demos/expr/expr.c, demos/expr/exprf.c,
+	demos/expr/exprfa.c, demos/expr/exprfr.c, demos/expr/exprq.c,
+	demos/expr/exprz.c, demos/expr/exprza.c: Add <string.h> for strlen and
+	memcpy.
+
+2002-11-02  Kevin Ryde  <kevin@swox.se>
+
+	* longlong.h: Test __x86_64__ not __x86_64.  Reported by Andreas
+	Jaeger.
+
+	* mpz/import.c, mpz/export.c: Use char* subtract from NULL to get
+	pointer alignment, for the benefit of Cray vector systems.
+
+	* cxx/ismpf.cc: Use <clocale>.
+	* tests/cxx/t-locale.cc: No need to conditionalize <clocale>.
+
+	* scanf/doscan.c: Don't use isascii, rely on C99 ctype.h.
+
+	* gmp.texi (Build Options): Describe CC_FOR_BUILD, cross reference
+	texinfo manual.
+	(ABI and ISA): Add powerpc620 and powerpc630 to powerpc64, add NetBSD
+	and OpenBSD sparc64.
+	(Notes for Package Builds): Cross reference libtool manual.
+	(Notes for Particular Systems): Add OpenBSD to non-MMX versions of gas.
+	(Known Build Problems): Add MacOS X C++ shared libraries.
+
+2002-10-31  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-impl.h, tune/speed.c, tune/speed.h, tune/common.c, tune/many.pl,
+	tests/devel/try.c, tests/tests.h, tests/refmpn.c (mpn_addmul_5,
+	mpn_addmul_6, mpn_addmul_7, mpn_addmul_8): Add testing and measuring.
+	* configure.in (config.in): Add #undefs of HAVE_NATIVE_mpn_addmul_5,
+	HAVE_NATIVE_mpn_addmul_6, HAVE_NATIVE_mpn_addmul_7,
+	HAVE_NATIVE_mpn_addmul_8.
+	(gmp_mpn_functions_optional): Add addmul_5 addmul_6 addmul_7 addmul_8.
+
+	* tests/devel/try.c (ASSERT_CARRY): Remove, now in gmp-impl.h
+	(try_one): Do dest setups after sources, for benefit of
+	dst0_from_src1.
+
+2002-11-01  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/tdiv_qr.c: Avoid quadratic behaviour for
+	sub-division when numerator is more than twice the size of the
+	denominator.  Simplify loop logic for the same case.  Clean up a
+	few comments.
+
+2002-10-29  Torbjorn Granlund  <tege@swox.com>
+
+	* configure.in (*-cray-unicos*): Pass -hnofastmd again.
+
+2002-10-25  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/tadd.c: Disable test of denorms.
+
+2002-10-23  Linus Nordberg  <linus@swox.se>
+
+	* gmp.texi (Introduction to GMP): Update section about mailing
+	lists.
+
+2002-10-23  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-h.in (__GMP_ATTRIBUTE_PURE): Suppress this when
+	__GMP_NO_ATTRIBUTE_CONST_PURE is defined.
+	* gmp-impl.h (ATTRIBUTE_CONST): Ditto.
+	* tune/common.c: Use __GMP_NO_ATTRIBUTE_CONST_PURE.
+
+	* tune/speed.h, tune/many.pl: Remove ATTRIBUTEs from prototypes.
+	* tune/speed.h: Remove various "dummy" variables attempting to keep
+	"pure" calls live, no longer necessary.  They weren't sufficient for
+	recent MacOS cc anyway.
+
+2002-10-21  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/cray/ieee/addmul_1.c: Handle overlap as in mul_1.c.
+	* mpn/cray/ieee/submul_1.c: Likewise.
+
+2002-10-19  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (sparcv9 etc -*-*bsd*): Add support for NetBSD and
+	OpenBSD sparc64.  Reported by Christian Weisgerber.
+	(AC_CHECK_HEADERS): Add sys/param.h for sys/sysctl.h on *BSD.
+
+	* demos/calc/calc.y: Change ={ to {, needed for bison 1.50.
+
+	* longlong.h (count_leading_zeros, count_trailing_zeros) [x86_64]:
+	Should be UDItype.
+
+	* mpz/set_str.c, mpf/set_str.c, mpbsd/xtom.c, scanf/sscanffuns.c: Cast
+	chars through "unsigned char" to zero extend, required by C99 ctype.h.
+
+2002-10-18  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/mpz/t-root.c: Test also mpz_rootrem.
+
+	* mpn/generic/rootrem.c: Avoid overflow problem when n is huge.
+
+	* mpz/root.c: Avoid overflow problems in allocation computation; also
+	simplify it.  Misc cleanups.
+
+	* mpz/rootrem.c: New file.
+	* Makefile.am, mpz/Makefile.am, gmp-h.in: Add them.
+
+2002-10-17  Torbjorn Granlund  <tege@swox.com>
+
+	* gmp-impl.h (popc_limb): Combine variants.
+
+2002-10-14  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (AC_CHECK_HEADERS): Add sys/time.h for sys/resource.h
+	test, needed by SunOS, and next autoconf will insist headers actually
+	compile.
+
+2002-10-08  Kevin Ryde  <kevin@swox.se>
+
+	* tune/time.c (speed_time_init): Allow for Cray times() apparently
+	being a cycle counter.
+
+	* dumbmp.c (mpz_get_str): Fix buf size allocation.
+
+	* tests/trace.c, tests/tests.h (mp_limb_trace): New function.
+
+	* tune/speed-ext.c (SPEED_EXTRA_PROTOS): Use __GMP_PROTO.
+	* tests/devel/try.c (malloc_region): Add a cast for SunOS cc.
+
+	* configure.in (AC_CHECK_FUNCS): Add strerror.
+	(AC_CHECK_DECLS): Add sys_errlist, sys_nerr.
+	* tune/time.c, tests/devel/try.c: Use them.
+
+2002-10-05  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (AC_CHECK_HEADERS): Test float.h, not in SunOS cc.
+	* printf/repl-vsnprintf.c: Use this.
+
+	* configure.in (*sparc*-*-*): Collect up various options for clarity,
+	use gcc -mcpu=supersparc and ultrasparc3, use cc -xchip, don't use
+	-xtarget=native, use cc configs with acc, merge SunOS bundled cc and
+	SunPRO cc configs.
+
+	* gmp-impl.h (gmp_randfnptr_t): Use __GMP_PROTO.
+	(MPZ_REALLOC): Cast _mpz_realloc return value to mp_ptr, for the
+	benefit of SunOS cc which requires pointers of the same type on the
+	two legs of a ?:.
+
+	* dumbmp.c (mpz_realloc): Add a cast to avoid a warning from SunOS cc.
+
+	* acinclude.m4: Allow for i960 b.out default cc output.
+
+	* gmp.texi (Random State Initialization): Add gmp_randinit_mt.
+	(Perfect Square Algorithm): Describe new mpn_mod_34lsub1 use.
+	(Factorial Algorithm): Describe Jason's new code.
+	(Binomial Coefficients Algorithm): Ideas about improvements
+	moved to doc/projects.html.
+	(Contributors): Add Jason Moxham and Pedro Gimeno.
+
+2002-10-03  Kevin Ryde  <kevin@swox.se>
+
+	* gen-psqr.c: New file.
+	* Makefile.am, mpn/Makefile.am: Use it to generate mpn/perfsqr.h.
+	* mpn/generic/perfsqr.c: Use generated data, put mod 256 data into
+	limbs to save space, use mpn_mod_34lsub1 when good.
+	* tests/mpn/t-perfsqr.c: New file.
+	* tests/mpn/Makefile.am (check_PROGRAMS): Add it.
+	* tests/mpz/t-perfsqr.c (check_modulo): New test.
+	(check_sqrt): New function holding current tests.
+
+	* configure.in (AC_INIT): Modernize to package name and version here
+	rather than AM_INIT_AUTOMAKE, add bug report email.
+	(AC_CONFIG_SRCDIR): New macro.
+
+	* gmp-impl.h (ROUND_UP_MULTIPLE): Fix for non-power-of-2 moduli (not
+	normal in current uses), clarify the comments a bit.
+
+2002-09-30  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/Makeasm.am (.s.lo): Add --tag=CC for the benefit of CCAS!=CC,
+	same as .S.lo and .asm.lo.
+
+	* Makefile.am (gen-fac_ui, gen-fib, gen-bases): Quote source files in
+	test -f stuff to avoid Sun make rewriting them.
+
+2002-09-28  Kevin Ryde  <kevin@swox.se>
+
+	* tests/devel/try.c, tune/speed.c: Avoid strings longer than C99
+	guarantees.
+
+	* tests/refmpn.c, tests/tests.h (refmpn_zero_extend, refmpn_normalize,
+	refmpn_sqrtrem): New functions.
+	* tests/devel/try.c (TYPE_SQRTREM): Use refmpn_sqrtrem.
+	(compare): Correction to tr->dst_size subscripting.
+
+	* dumbmp.c: Add several new functions, allow for initial n<d in
+	mpz_tdiv_q (now in mpz_tdiv_qr actually).
+
+	* gen-bases.c (chars_per_limb): Get GMP_NUMB_BITS for base==2,
+	similarly other powers of 2, which this was in the past.
+	* tests/refmpn.c (refmpn_chars_per_limb): Ditto.
+	* tests/mpn/t-mp_bases.c: Test chars_per_limb for power-of-2 bases too.
+
+	* Makefile.am, mpz/Makefile.am: Setups for gen-fac_ui.c generating
+	mpz/fac_ui.h.
+
+2002-09-28  Jason Moxham <J.L.Moxham@maths.soton.ac.uk>
+
+	* dumbmp.c (mpz_pow_ui, mpz_addmul_ui, mpz_root): New functions.
+	* gen-fac_ui.c: New file.
+	* mpz/fac_ui.c: Rewrite.
+
+2002-09-26  Kevin Ryde  <kevin@swox.se>
+
+	* tests/cxx/localeconv.c: New file, split from t-locale.cc.
+	* tests/cxx/t-locale.cc: Use it.
+	* tests/cxx/Makefile.am (t_locale_SOURCES): Add it.
+
+	* tests/cxx/Makefile.am: Updates for Gerardo's new test programs.
+
+2002-09-26  Gerardo Ballabio <gerardo.ballabio@unimib.it>
+
+	* gmpxx.h (__gmp_cmp_function): Bug fixes in double/mpq and
+	double/mpfr comparisons.
+
+	* tests/cxx/t-assign.cc, tests/cxx/t-binary.cc, tests/cxx/t-constr.cc,
+	tests/cxx/t-ternary.cc, tests/cxx/t-unary.cc: Revise and add various
+	tests, including some for mpfr, some split from t-expr.cc.
+	* tests/cxx/t-locale.cc: Modernize include files.
+	* tests/cxx/t-ostream.cc: Modernize include files, use cout rather
+	than printf for diagnostics.
+	* tests/cxx/t-misc.cc, tests/cxx/t-rand.cc: New file, split from
+	t-allfuns.cc.
+	* tests/cxx/t-ops.cc: New file, some split from t-allfuns.cc.
+	* tests/cxx/t-prec.cc: New file.
+	* tests/cxx/t-allfuns.cc, tests/cxx/t-expr.cc: Remove files.
+
+2002-09-25  Torbjorn Granlund  <tege@swox.com>
+
+	* configure.in (*-cray-unicos*): Remove -hscalar0, it causes too much
+	performance loss.  Let's trust Cray to fix their compilers.
+
+2002-09-24  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc32/add_n.asm: Rewrite.
+	* mpn/powerpc32/sub_n.asm: Rewrite.
+
+2002-09-24  Pedro Gimeno  <pggimeno@wanadoo.es>
+
+	* randlc2x.c: Prepare for nails by changing type of _mp_c to mpz_t,
+	make _mp_seed fixed-size, disallow SIZ(a)==0 to optimize comparisons
+	for mpn_mul.
+	* gmp-impl.h (MPZ_FAKE_UI): New macro.
+
+	* randmt.c: Some constants made long for K&R compliance; remove UL at
+	the end of other constants; use mp_size_t where appropriate; use
+	mpz_export to split the seed.
+
+	* gmp-impl.h: Remove type cast in RNG_FNPTR and RNG_STATE, to allow
+	them to be used as lvalues.
+	* randclr.c, randlc2x.c, randmt.c, randsd.c: All callers changed.
+
+	* mpz/urandomm.c: Replace mpn_cmp with MPN_CMP.
+
+	* tests/rand/gen.c: Get rid of gmp_errno.
+
+2002-09-24  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi (Custom Allocation): Keep allocate_function etc out of the
+	function index by using @deftypevr.
+	More index entries.
+
+2002-09-24  Gerardo Ballabio <gerardo.ballabio@unimib.it>
+
+	* gmpxx.h (mpfr_class constructors from strings): Precision was set
+	incorrectly, fixed.
+
+2002-09-23  Torbjorn Granlund  <tege@swox.com>
+
+	* mpf/urandomb.c: Don't crash for overlarge nbits argument.
+	Let nbits==0 mean to fill number with random bits.
+
+2002-09-21  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/alpha/mod_34lsub1.asm: Add r31 dummy operand to `br' instruction.
+
+2002-09-20  Gerardo Ballabio <gerardo.ballabio@unimib.it>
+
+	* gmpxx.h (__gmp_binary_equal, __gmp_binary_not_equal): Fix broken
+	mpq/double functions.
+
+2002-09-18  Torbjorn Granlund  <tege@swox.com>
+
+	* randmt.c (randget_mt): Fix typo.
+
+2002-09-18  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-impl.h (_gmp_rand): Avoid evaluating "state" more than once, for
+	the benefit places calling it with RANDS.
+
+	* randmt.c (randseed_mt): Use mpz_init for mod and seed1, for safety.
+
+	* tune/tuneup.c (sqr_karatsuba_threshold): Initialize to
+	TUNE_SQR_KARATSUBA_MAX so mpn_sqr_n works for randmt initialization.
+
+	* gmp.texi (Integer Comparisons): Remove mention of non-existent
+	mpz_cmpabs_si, reported by Conrad Curry.
+
+	* tune/speed.c, tune/speed.h, tune/common.c: Add gmp_randseed,
+	gmp_randseed_ui and mpz_urandomb.
+
+2002-09-18  Pedro Gimeno  <pggimeno@wanadoo.es>
+
+	* tests/rand/gen.c: Add mt, remove lc and bbs.
+
+	* Makefile.am (libgmp_la_SOURCES): Add randmt.c, remove randlc.c and
+	randraw.c.
+
+	* randmt.c: New file.
+	* gmp-h.in (gmp_randinit_mt): Add prototype.
+	* randdef.c: Use gmp_randinit_mt.
+
+	* gmp-impl.h (RNG_FNPTR, RNG_STATE): New macros.
+	(gmp_randfnptr_t): New structure.
+	(_gmp_rand): Now a macro not a function.
+	* gmp-h.in (__gmp_randata_lc): Remove, now internal to randlc2x.c.
+	(__gmp_randstate_struct): Revise comments on field usage.
+	* randsd.c, randclr.c: Use function pointer scheme.
+	* randsdui.c: Use gmp_randseed.
+	* randraw.c: Remove file.
+	* randlc2x.c: Collect up lc_2exp related code from randsd.c, randclr.c
+	and randraw.c, use function pointer scheme, integrate seed==0/a==0
+	into main case and fix case where bits(a) < m2exp.
+
+	* randlc.c: Remove file, never documented and never worked.
+	* gmp-h.in (gmp_randinit_lc): Remove prototype.
+
+2002-09-16  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/alpha/mod_34lsub1.asm: New file.
+
+2002-09-16  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in, acinclude.m4 (GMP_C_RESTRICT): Remove this, not
+	currently used, and #define restrict upsets Microsoft C headers on
+	win64.  Reported by David Librik.
+
+	* configure.in (x86): Add gcc 3.2 -march and -mcpu flags, remove some
+	unnecessary -march=i486 fallbacks.
+
+	* gmp.texi (Notes for Particular Systems): Note cl /MD is required for
+	Microsoft C and MINGW to cooperate on I/O.  Explained by David Librik.
+	(Language Bindings): Add linbox.
+	* gmp.texi (Language Bindings):
+
+2002-09-12  Kevin Ryde  <kevin@swox.se>
+
+	* mpz/aorsmul_i.c: Allow for w==x overlap with nails.  Test
+	BITS_PER_ULONG > GMP_NUMB_BITS rather than GMP_NAIL_BITS != 0.
+	* tests/mpz/t-aorsmul.c: Test this.
+
+	* tune/common.c: mpn_mod_34lsub1 only exists for GMP_NUMB_BITS%4==0
+	* tune/speed.c: Add mpn_mod_34lsub1.
+
+2002-09-10  Pedro Gimeno  <pggimeno@wanadoo.es>
+
+	* rand.c: Remove old disabled BBS code.
+	* mpf/urandomb.c: Use BITS_TO_LIMBS.
+
+2002-09-10  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi (Multiplication Algorithms): FFT is now enabled by default.
+
+2002-09-10  Pedro Gimeno  <pggimeno@wanadoo.es>
+
+	* mpz/urandomm.c: Use mpn level functions, avoid an infinite loop if
+	_gmp_rand forever returns all "1" bits.
+	* tests/rand/t-urndmm.c: New file
+	* tests/rand/Makefile.am (check_PROGRAMS): Add it.
+
+	* gmp-impl.h (BITS_TO_LIMBS): New macro.
+	* mpz/urandomb.c: Use it, and use MPZ_REALLOC.
+
+2002-09-08  Kevin Ryde  <kevin@swox.se>
+
+	* acinclude.m4 (GMP_GCC_WA_MCPU): New macro.
+	* configure.in (alpha*-*-*): Use it to avoid -Wa,-mev67 if gas isn't
+	new enough to know ev67.  Reported by David Bremner.
+
+2002-07-30  Gerardo Ballabio <gerardo.ballabio@unimib.it>
+
+	* gmpxx.h (__gmpz_value etc): Remove, use mpz_t etc instead.
+	(__gmp_expr): Reorganise specializations, use __gmp_expr<T,T> not
+	mpz_class etc.
+	(mpfr evals): Remove mode parameter, was always
+	__gmp_default_rounding_mode anyway.
+
+2002-09-07  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-h.in, mp-h.in: Use #ifdef for tests, for the benefit of
+	applications using gcc -Wundef.
+
+	* longlong.h: Define COUNT_LEADING_ZEROS_NEED_CLZ_TAB for all alphas,
+	since mpn/alpha/cntlz.asm always goes into libgmp.so, even for ev67
+	and ev68 which don't need it.  Reported by David Bremner.
+
+	* gmp.texi (Demonstration Programs): New section, expanding on what
+	was under "Build Options".
+	(Converting Floats): Don't need \ for _ in @var within @math.
+	Add and amend various index entries.
+
+	* demos/qcn.c: Add -p prime limit option.
+
+2002-08-30  Kevin Ryde  <kevin@swox.se>
+
+	* mpz/pprime_p.c: Handle small negatives with isprime, in particular
+	must do so for n==-2.
+	* tests/mpz/t-pprime_p.c: New file.
+	* tests/mpz/Makefile.am: Add it.
+
+2002-08-26  Torbjorn Granlund  <tege@swox.com>
+
+	* gmp.texi (Converting Floats): Fix typo in mpf_get_d_2exp docs,
+	reported by Paul Zimmermann.
+
+2002-08-26  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in: Echo the ABI being tried for the compilers.
+	(powerpc*-*-*): Use powerpc64/aix.m4 for ABI=aix64 too.
+	(AC_CHECK_FUNCS): Add strtol, for tests/rand/gen.c.
+
+2002-08-24  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (HAVE_HOST_CPU_, HAVE_HOST_CPU_FAMILY_, HAVE_NATIVE_):
+	Setup templates for these using AH_VERBATIM rather than acconfig.h,
+	preferred by latest autoconf.  Prune lists to just things used.
+	* acconfig.h: Remove file.
+
+	* mpn/powerpc32/mode1o.asm: Forgot ASM_START.
+
+	* tune/time.c (have_cgt_id): Renamed from HAVE_CGT_ID so avoid
+	confusion with autoconf outputs, and turn it into a "const" variable.
+
+2002-08-23  Torbjorn Granlund  <tege@swox.com>
+
+	* configure.in: Choose powerpc32/aix.m4 or powerpc64/aix.m4 based on
+	ABI, not configuration triple.
+
+	* mpz/pprime_p.c: Partially undo last change--handle small and
+	negative numbers in the same test.
+
+2002-08-22  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-impl.h (MUL_FFT_THRESHOLD, SQR_FFT_THRESHOLD): Note
+	mpn/generic/mul_fft.c is not nails-capable, and don't bother setting
+	other FFT data for nails.
+
+	* configfsf.guess: Update to 2002-08-19.
+	* configfsf.sub: Update to 2002-08-20.
+
+	* config.guess (powerpc*-*-*): Use a { } construct to suppress SIGILL
+	message on AIX.
+
+2002-08-20  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi (Build Options): Add ia64 under cpu types.
+	(ABI and ISA): Describe IRIX 6 ABI=o32.
+	(Notes for Particular Systems): Remove -march=pentiumpro, now ok.
+	(Known Build Problems): Binutils 2.12 is ok for libgmp.a.
+	(Emacs): New section.
+	(Language Bindings): Update MLton URL, reported by Stephen Weeks.
+	(Prime Testing Algorithm): New section.
+	Don't put a blank line after @item in @table since it can make a page
+	break between the heading and the entry.
+	Misc tweaks elsewhere, in particular more index entries.
+
+	* mpz/millerrabin.c: Need x to be size+1 for change to urandomm.
+
+	* gmp-impl.h: Comments on the use of __GMP_DECLSPEC.
+
+	* tune/time.c (freq_measure_mftb_one): Use struct_timeval, for the
+	benefit of mingw.
+
+	* tests/refmpn.c, tests/tests.h (ref_addc_limb, ref_subc_limb):
+	Renamed from add and sub, following gmp-impl.h ADDC_LIMB and SUBC_LIMB.
+
+2002-08-17  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/powerpc32/mode1o.asm: New file.
+	* configure.in, acinclude.m4 (GMP_ASM_POWERPC_PIC_ALWAYS): New macro.
+	* mpn/asm-defs.m4: Use it to help setting up PIC.
+
+	* configure.in (AC_PREREQ): Bump to 2.53.
+
+	* mpn/powerpc32/powerpc-defs.m4 (ASSERT): New macro.
+	(PROLOGUE_cpu): New macro, giving ALIGN(4) not 8.
+
+2002-08-16  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/m68k/lshift.asm: Fix typo in !scale_available_p code.
+	* mpn/m68k/rshift.asm: Likewise.
+
+2002-08-16  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (--enable-profiling=instrument): New option.
+	* gmp.texi (Profiling): Describe it.
+	* mpn/x86/x86-defs.m4 (PROLOGUE_cpu, call_instrument, ret_internal):
+	Add support.
+	(call_mcount): Share PIC setups with call_instrument.
+	* mpn/x86/*.asm: Use ret_internal.
+	* mpn/asm-defs.m4 (m4_unquote): New macro.
+	* tests/mpn/t-instrument.c: New file.
+	* tests/mpn/Makefile.am: Add it.
+
+	* mpn/alpha/umul.asm: Add ASM_END.
+
+2002-08-12  Kevin Ryde  <kevin@swox.se>
+
+	* mpz/pprime_p.c: Fake up a local mpz_t to take abs(n), rather than
+	using mpz_init etc.
+
+	* mpz/millerrabin.c: Use mpz_urandomm for uniform selection of x,
+	reported by Jason Moxham.  Exclude x==n-1, ie. -1 mod n.  Use
+	gmp_randinit_default.
+
+	* mpn/alpha/umul.asm: Use "r" registers, for the benefit of Unicos.
+
+	* tests/devel/try.c: Add mpn_copyi and mpn_copyd.
+
+2002-08-09  Kevin Ryde  <kevin@swox.se>
+
+	* Makefile.am: Remove configure.lineno from DISTCLEANFILES and gmp.tmp
+	from MOSTLYCLEANFILES, automake does these itself now.
+
+	* */Makefile.in, aclocal.m4, configure, install-sh, missing,
+	mkinstalldirs: Update to automake 1.6.3.
+
+	* mpn/ia64/README: Some notes on assembler syntax.
+
+	* mpn/ia64/add_n.asm, mpn/ia64/sub_n.asm: Add .body.
+	* mpn/ia64/add_n.asm, mpn/ia64/addmul_1.asm, mpn/ia64/mul_1.asm,
+	mpn/ia64/sub_n.asm: Position .save ar.lc just before relevant
+	instruction.
+	* mpn/ia64/addmul_1.asm, mpn/ia64/mul_1.asm: Add .save ar.pfs and pr.
+	* mpn/ia64/copyd.asm, mpn/ia64/copyi.asm: Correction to .body position.
+	* mpn/ia64/lorrshift.asm: Add .prologue stuff.
+
+	* configure.in (*-*-unicos*): Remove forcible --disable-shared,
+	libtool gets this right itself now.
+
+2002-08-07  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/x86/pentium/mmx/hamdist.asm: New file, adapted from
+	mpn/x86/pentium/mmx/popham.asm.
+	* mpn/x86/pentium/mmx/popham.asm: Remove file, not faster than plain
+	mpn/x86/pentium/popcount.asm for the popcount.
+
+	* mpn/alpha/umul.asm: Use PROLOGUE/EPILOGUE, rename it mpn_umul_ppmm.
+	* configure.in (alpha*-*-*): Add umul to extra_functions.
+
+	* mpz/remove.c: Make src==0 return 0, not do DIVIDE_BY_ZERO.
+
+2002-08-05  Torbjorn Granlund  <tege@swox.com>
+
+	* acconfig.h: Remove spurious undefs for mpn_divrem_newton and
+	mpn_divrem_classic.
+
+2002-08-05  Kevin Ryde  <kevin@swox.se>
+
+	* tests/refmpn.c, tests/tests.h, tests/misc/t-printf.c,
+	tests/mpf/t-trunc.c, tests/mpn/t-mp_bases.c, tests/mpn/t-scan.c,
+	tests/mpq/t-cmp_ui.c, tests/mpz/bit.c, tests/mpz/t-aorsmul.c,
+	tests/mpz/t-powm_ui.c tests/mpz/t-root.c, tests/mpz/t-scan.c: More
+	care with long and mp_size_t parameters, for the benefit of K&R.
+
+	* demos/perl/GMP.pm, demos/perl/GMP.xs, demos/perl/GMP/Mpz.pm,
+	demos/perl/test.pl: Add mpz_import and mpz_export.
+	* demos/perl/GMP.pm: Remove "preliminary" warning.
+
+	* mpn/lisp/gmpasm-mode.el: Set add-log-current-defun-header-regexp to
+	pick up m4 defines etc.
+
+	* Makefile.am (libgmpxx_la_DEPENDENCIES): libgmp.la should be here,
+	not libgmpxx_la_LIBADD, for the benefit of "make -j2".
+
+	* mpn/ia64/*.asm [hpux ABI=32]: Extend 32-bit operands to 64-bits, not
+	optimal and might not be sufficient, but seems to work.
+
+2002-08-03  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi (Profiling): Use a table and expand for clarity.
+	(Integer Special Functions): New section for mpz_array_init,
+	_mpz_realloc, mpz_getlimbn and mpz_size, to discourage their use.
+
+	* configure.in (*-*-msdosdjgpp*): Remove forcible --disable-shared,
+	libtool gets this right itself now.
+
+2002-07-30  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/powerpc32/lshift.asm, mpn/powerpc32/rshift.asm: Lose final mr,
+	and make final stwu into an stw.
+
+	* gmp.texi (Known Build Problems): An easier workaround for DESTDIR,
+	using LD_LIBRARY_PATH.
+	(C++ Interface MPFR): Remove mpfrxx.h.
+
+	* mpfrxx.h: Remove file.
+	* Makefile.am: Remove mpfrxx.h.
+	* tests/cxx/Makefile.am: Add Gerardo's new test programs.
+
+2002-07-30  Gerardo Ballabio <gerardo.ballabio@unimib.it>
+
+	* gmpxx.h: Use mpz_addmul etc for ternary a+b*c etc.  Reorganise some
+	macros for maintainability.  Merge mpfrxx.h.
+	* tests/cxx/t-constr.cc, tests/cxx/t-expr.cc: Various updates.
+	* tests/cxx/t-assign.cc, tests/cxx/t-binary.cc,
+	tests/cxx/t-ternary.cc, tests/cxx/t-unary.cc: New files.
+
+2002-07-27  Kevin Ryde  <kevin@swox.se>
+
+	* longlong.h (count_trailing_zeros) [ia64 __GNUC__]: Don't use
+	__builtin_ffs for now, doesn't seem to work.
+
+	* configure.in: Establish CONFIG_SHELL to avoid a problem with
+	AC_LIBTOOL_SYS_MAX_CMD_LEN on ia64-*-hpux*.
+
+	* tune/speed.h (SPEED_ROUTINE_MPN_GCD_FINDA): Don't let calls to
+	mpn_gcd_finda go dead.
+
+	* mpn/generic/tdiv_qr.c: Inline mpn_rshift and MPN_COPY of 2 limbs.
+
+2002-07-24  Kevin Ryde  <kevin@swox.se>
+
+	* demos/primes.c: Use __GMP_PROTO and don't use signed, for the
+	benefit of K&R.
+
+	* demos/calc/calclex.l: Add <string.h> for strcmp.
+
+	* mpn/ia64/invert_limb.asm: Use .rodata which works on ia64-*-hpux*
+	and should be standard, rather than worrying about RODATA.
+
+	* gmp.texi (Function Classes): Add cross references.
+	(Integer Import and Export): Fix return value grouping.
+
+	* mpn/lisp/gmpasm-mode.el (gmpasm-comment-start-regexp): Add // for
+	ia64.  Add notes on what the various styles are for.
+
+	* mpn/ia64/default.m4 (ASM_START): Define to empty, not dnl, so as not
+	to kill text on the same line.
+	(EPILOGUE_cpu): Force a newline after "#", so as not to suppress macro
+	expansion in the rest of the EPILOGUE line.
+
+2002-07-21  Kevin Ryde  <kevin@swox.se>
+
+	* tune/speed.h: Fix some missing _PROTOs.
+
+	* Makefile.am (DISTCLEANFILES): Add configure.lineno.
+
+	* acinclude.m4 (GMP_C_DOUBLE_FORMAT): Define
+	HAVE_DOUBLE_IEEE_BIG_ENDIAN and HAVE_DOUBLE_IEEE_LITTLE_ENDIAN in
+	config.m4 too.
+	* mpn/ia64/invert_limb.asm: Add big-endian data.
+
+	* tests/mpz/t-jac.c (try_si_zi): Correction to "a" parameter type.
+
+2002-07-20  Kevin Ryde  <kevin@swox.se>
+
+	* mpz/bin_ui.c, mpz/jacobi.c, mpz/pprime_p.c, mpn/generic/divis.c:
+	More care with long and mp_size_t parameters, for the benefit of K&R.
+
+	* gmp-impl.h (invert_limb): Use parens around macro arguments.
+	(mpn_invert_limb): Give prototype and define unconditionally.
+
+	* gmp-impl.h (CACHED_ABOVE_THRESHOLD, CACHED_BELOW_THRESHOLD): New
+	macros.
+	* mpn/generic/sb_divrem_mn.c: Use them to help gcc let preinv code go
+	dead when not wanted.
+
+2002-07-17  Kevin Ryde  <kevin@swox.se>
+
+	* tests/refmpz.c (refmpz_hamdist): Ensure mp_size_t parameters are
+	that type, for the benefit of hpux ia64 bundled cc ABI=64.
+
+	* configure.in (ia64*-*-hpux*): Need +DD64 in cc_64_cppflags to get
+	the right headers for ansi2knr.
+
+	* acinclude.m4 (GMP_TRY_ASSEMBLE, GMP_ASM_UNDERSCORE): Use $CPPFLAGS
+	with $CCAS and when linking, as done by the makefiles.
+	(GMP_ASM_X86_MMX, GMP_ASM_X86_SSE2): Show $CPPFLAGS in diagnostics.
+
+	* gmp-impl.h (ieee_double_extract): Setup using HAVE_DOUBLE_IEEE_*.
+	(GMP_UINT32): New define, 32 bit type for ieee_double_extract.
+	* configure.in: Add AC_CHECK_SIZEOF unsigned.
+	* configure.in, acinclude.m4 (GMP_IMPL_H_IEEE_FLOATS): Remove.
+	(GMP_C_DOUBLE_FORMAT): Instead warn about unknown float here.
+
+	* configure.in, acinclude.m4 (GMP_C_SIZES): Remove.
+	* acinclude.m4 (GMP_INCLUDE_GMP_H_BITS_PER_MP_LIMB): Remove this
+	scheme, not required.
+	* configure.in (unsigned long, mp_limb_t): Run AC_CHECK_SIZEOF for
+	these unconditionally, check mp_limb_t against gmp-mparam.h values.
+	* gmp-impl.h (BYTES_PER_MP_LIMB, BITS_PER_MP_LIMB): Define based on
+	SIZEOF_MP_LIMB_T if not provided by gmp-mparam.h.
+	(BITS_PER_ULONG): Define here now.
+
+	* gmp.texi (ABI and ISA): Add HP-UX IA-64 choices.
+	(Random State Initialization): Typo in m2exp described for
+	gmp_randinit_lc_2exp_size.
+	(Formatted Output Functions): Clarify gmp_obstack_printf a bit.
+	(Formatted Input Strings): Typo in %n summary.
+
+	* mpz/inp_raw.c (NTOH_LIMB_FETCH): Use simple generic default, since
+	endianness detection is now cross-compile friendly.
+	* mpz/out_raw.c (HTON_LIMB_STORE): Ditto.
+
+	* mpz/fib_ui.c: Nailify.
+	* mpz/random.c: Nailify.
+
+	* mpfr/acinclude.m4 (MPFR_CONFIGS): Patch by Vincent for an apparent
+	float rounding gremlin on powerpc.
+
+2002-07-15  Kevin Ryde  <kevin@swox.se>
+
+	* Makefile.am (PRINTF_OBJECTS): Avoid ending in a backslash, hpux ia64
+	make doesn't like that.
+
+	* mpn/ia64/*.asm: Add .sptk to unconditional branches, add ";" after
+	.mib etc, for the benefit of hpux.
+
+	* configure.in (ia64*-*-*): Use ABI=64 on non-HPUX systems, for
+	consistency.
+
+	* gmp-impl.h (ieee_double_extract): Test __sparc__, used by gcc 3.1.
+	Reported by nix@esperi.demon.co.uk.
+	* mpfr/mpfr-math.h (_MPFR_NAN_BYTES etc): Ditto.
+
+2002-07-13  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/powerpc32/rshift.asm: Rewrite, transformed from lshift.asm.
+
+	* tune/tuneup.c (DIVEXACT_1_THRESHOLD, MODEXACT_1_ODD_THRESHOLD):
+	Always zero for native mpn_divexact_1, mpn_modexact_1_odd.
+
+	* gmp-h.in (__GMP_EXTERN_INLINE): Don't use this during configure,
+	ie. __GMP_WITHIN_CONFIGURE, to avoid needing dependent routines.
+	* acinclude.m4 (GMP_H_EXTERN_INLINE): Consequent changes.
+
+	* gmp-impl.h, mpn/asm-defs.m4 (mpn_addmul_2, mpn_addmul_3,
+	mpn_addmul_4): Add prototypes and defines.
+
+	* gmp.texi (Number Theoretic Functions): Clarify return value.
+	Reported by Peter Keller.
+
+2002-07-10  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in, acinclude.m4 (GMP_PROG_LEX): Remove this in favour of
+	AM_PROG_LEX, now ok when lex is missing.
+
+	* longlong.h (count_leading_zeros) [pentiummmx]: Don't use __clz_tab
+	variant under LONGLONG_STANDALONE.
+	(count_trailing_zeros) [ia64 __GNUC__]: Use __builtin_ffs.
+
+	* gmp-impl.h (popc_limb): Add an ia64 asm version.
+	(DItype): Use HAVE_LONG_LONG to choose long long, avoiding _LONGLONG
+	which is in gcc but means something unrelated in MS Visual C 7.0.
+	Reported by David Librik.
+
+	* mpz/divexact.c: Add an ASSERT that den divides num.
+
+	* mpn/asm-defs.m4 (LDEF): New macro.
+	(INT32, INT64): Use it.
+	* mpn/pa32/*.asm: Use it.
+	* mpn/pa32/README: Update notes on labels.
+
+	* tests/refmpn.c, tests/tests.h, tests/t-bswap.c (ref_bswap_limb):
+	Renamed from refmpn_bswap_limb.
+	* tests/t-bswap.c: Add tests_start/tests_end for randomization.
+
+	* tests/refmpn.c, tests/tests.h (ref_popc_limb): New function.
+	* tests/t-popc.c: New file.
+	* tests/Makefile.am: Add it.
+
+	* mpn/ia64/invert_limb.asm: Use RODATA since ".section .rodata" is not
+	accepted by ia64-*-hpux*.
+
+	* acinclude.m4 (GMP_ASM_BYTE): New macro.
+	(GMP_ASM_ALIGN_LOG, GMP_ASM_W32): Use it.
+	(GMP_ASM_LABEL_SUFFIX): Use test compiles, not $host.
+	(GMP_ASM_GLOBL): Ditto, and add .global for ia64-*-hpux*.
+	(GMP_ASM_GLOBL_ATTR): Use GMP_ASM_GLOBL result, not $host.
+	(GMP_ASM_LSYM_PREFIX): Allow any "a-z" nm symbol code, add ".text" to
+	test program, required by ia64-*-hpux*.
+	(GMP_ASM_LABEL_SUFFIX): Make LABEL_SUFFIX just the value, not a "$1:",
+	the former being how it's currently being used in fact.
+
+	* configure.in, acinclude.m4 (GMP_PROG_CC_WORKS_LONGLONG): New macro.
+	* configure.in (ia64-*-hpux*): Add 32 and 64 bit ABI modes.
+
+2002-07-06  Kevin Ryde  <kevin@swox.se>
+
+	* tests/cxx/t-allfuns.cc: New file.
+	* tests/cxx/Makefile.am: Add it.
+
+	* mpz/clrbit.c, mpz/setbit.c: Only MPN_NORMALIZE if high limb changes
+	to zero.  Use _mpz_realloc return value.
+
+	* gmp.texi (Build Options, C++ Formatted Output, C++ Formatted Input):
+	Cross reference to Headers and Libraries for libgmpxx stuff.
+	(Low-level Functions): mpn_divexact_by3 result based on GMP_NUMB_BITS.
+	mpn_set_str takes "unsigned char *", reported by Mark Sofroniou.
+	(C++ Interface General): Describe linking with libgmpxx and libgmp.
+
+2002-07-01  Kevin Ryde  <kevin@swox.se>
+
+	* tune/tuneup.c, gmp-impl.h: Eliminate the array of thresholds in
+	one(), tune just one at a time and let the callers hand dependencies.
+	Eliminate the second_start_min hack, handle SQR_KARATSUBA_THRESHOLD
+	oddities in tune_sqr() instead.
+
+	* mpn/pa64/umul.asm, mpn/pa64/udiv.asm, mpn/asm-defs.m4, acconfig.h,
+	longlong.h, tune/speed.c, tune/speed.h, tune/common.c, tune/many.pl,
+	tests/devel/try.c: Introduce mpn_umul_ppmm_r and mpn_udiv_qrnnd_r
+	rather than having variant parameter order for mpn_umul_ppmm and
+	mpn_udiv_qrnnd on pa64.
+
+	* gmp-h.in (mpz_export): Remove a spurious parameter name.
+	* gmp-impl.h (mpn_rootrem): Use __MPN.
+
+2002-06-29  Kevin Ryde  <kevin@swox.se>
+
+	* longlong.h (udiv_qrnnd) [hppa32]: Remove mpn_udiv_qrnnd version, the
+	general mechanism for that suffices.
+
+	* mpf/inp_str.c: Fix returned count of chars read, reported by Paul
+	Zimmermann.  Also fix a memory leak for invalid input.
+	* tests/mpf/t-inp_str.c: New file.
+	* tests/mpf/Makefile.am (check_PROGRAMS): Add it.
+
+	* tests/devel/try.c (mpn_mod_34lsub1): Only exists for
+	GMP_NUMB_BITS%4==0.
+	(SIZE2_FIRST): Respect option_firstsize2 for "fraction" case.
+
+	* mpn/generic/diveby3.c: Further nailifications.
+	* gmp-impl.h (MODLIMB_INVERSE_3): Allow for GMP_NUMB_BITS odd.
+	(GMP_NUMB_CEIL_MAX_DIV3, GMP_NUMB_CEIL_2MAX_DIV3): New constants.
+	* tests/t-constants.c: Check them.
+
+	* gmp-h.in (__GMP_CRAY_Pragma): New macro.
+	(__GMPN_COPY_REST): Use it.
+	* gmp-impl.h (CRAY_Pragma): Use it.
+
+2002-06-25  Kevin Ryde  <kevin@swox.se>
+
+	* mpz/import.c, mpz/export.c: Cast data pointer through "char *" in
+	alignment tests, for the benefit of Cray vector systems.
+
+	* configure.in (x86-*-*): Remove -march=pentiumpro check, seems ok
+	with current code.
+	* acinclude.m4 (GMP_GCC_MARCH_PENTIUMPRO, GMP_GCC_VERSION_GE): Remove
+	macros, no longer needed
+
+	* acinclude.m4 (GMP_ASM_RODATA): Remove temporary files.
+
+	* configure.in (GMP_ASM_GLOBL_ATTR): Reposition to avoid duplication
+	through AC_REQUIRE.
+
+2002-06-23  Kevin Ryde  <kevin@swox.se>
+
+	* tests/mpz/t-fib_ui.c (check_fib_table): Check table values, not just
+	that they're non-zero.
+
+	* acinclude.m4 (GMP_GCC_ARM_UMODSI): Match bad "gcc --version" output
+	exactly, rather than parsing it with GMP_GCC_VERSION_GE.
+	(GMP_ASM_UNDERSCORE): Use GLOBL_ATTR.
+
+	* mpn/pa32/udiv.asm, mpn/pa32/hppa1_1/udiv.asm, mpn/pa64/udiv.asm:
+	Renamed from udiv_qrnnd.asm, for consistency with other udiv's.
+	* mpn/pa64/umul.asm: Renamed from umul_ppmm.asm likewise.
+	* configure.in (hppa*-*-*): Update extra_functions.
+	(NAILS_SUPPORT): Remove umul_ppmm, udiv_qrnnd, udiv_fp, udiv_nfp from
+	nails-neutral list, no longer needed.
+
+	* gmp-h.in (__DECC): Add notes on testing this for ANSI-ness.
+	(__GMP_EXTERN_INLINE): Add static __inline for DEC C.
+	(mpz_mod_ui): Move up to main section, it's still documented.
+
+2002-06-22  Kevin Ryde  <kevin@swox.se>
+
+	* mpz/jacobi.c, mpz/kronsz.c, mpz/kronuz.c, mpz/kronzs.c,
+	mpz/kronzu.c: Allow for odd GMP_NUMB_BITS, tweak a few variable setups.
+	* gmp-impl.h (JACOBI_STRIP_LOW_ZEROS): New macro.
+
+	* mpn/generic/mod_34lsub1.c: Nailify.
+	* tests/devel/try.c (CNST_34LSUB1): Nailify.
+	* gmp-impl.h (ADDC_LIMB): New macro.
+
+	* gmpxx.h (mpf_class::get_str): Make exponent mp_exp_t&, default
+	base=10 and ndigits=0.
+	(mpz_class::set_str, mpq_class::set_str, mpf_class::set_str): Add
+	versions accepting "const char *".
+	* mpfrxx.h (mpfr_class::get_str, mpfr_class::set_str): Ditto, and
+	uncommenting set_str and operator=.
+	* gmp.texi (C++ Interface Integers, C++ Interface Rationals)
+	(C++ Interface Floats): Update.
+
+	* gmp-impl.h (modlimb_invert): Merge the <=64bits and general versions.
+	(const, signed): Move to near top of file, fixes --enable-alloca=debug
+	on K&R.
+
+	* gen-fib.c: New file, derived from mainline in mpn/generic/fib2_ui.c.
+	* dumbmp.c (mpz_init_set_ui): New function.
+	* Makefile.am, mpn/Makefile.am: Generate fib_table.h, mpn/fib_table.c.
+	* gmp-impl.h: Use fib_table.h, add __GMP_DECLSPEC to __gmp_fib_table
+	(for the benefit of tests/mpz/t-fib_ui.c).
+	* mpn/generic/fib2_ui.c: Remove __gmp_fib_table and generating code.
+
+	* Makefile.am: Add mp.h to BUILT_SOURCES, distclean all BUILT_SOURCES,
+	use += more.
+
+	* acinclude.m4 (GMP_ASM_M68K_INSTRUCTION, GMP_ASM_M68K_BRANCHES):
+	Don't let "unknown" get into the cache variables.
+	(GMP_ASM_TEXT): See what assembles, don't hard-code hpux and aix.
+	(GMP_PROG_EXEEXT_FOR_BUILD): Add ,ff8 for RISC OS, per autoconf cvs.
+	(GMP_PROG_CPP_FOR_BUILD): Restructure per AC_PROG_CPP, print correct
+	result if CPP_FOR_BUILD overrides the cache variable.
+	(GMP_PROG_CC_FOR_BUILD_WORKS): New macro split from
+	GMP_PROG_CC_FOR_BUILD.  Allow for "conftest" default compiler output.
+	* configure.in, acinclude.m4 (GMP_PROG_HOST_CC): Reinstate this,
+	separating HOST_CC establishment from GMP_PROG_CC_FOR_BUILD.
+
+	* configure.in (mpn_objs_in_libgmp): Move mpn/mp_bases.lo ...
+	* Makefile.am (MPN_OBJECTS): ... to here, add $U, and arrange
+	MPN_OBJECTS to be common between libgmp and libmp.
+
+2002-06-20  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/mul_n.c (TOOM3_MUL_REC, TOOM3_SQR_REC): Don't check if
+	basecase is to be invoked when *_TOOM3_THRESHOLD is more than 3 times
+	the corresponding *_THRESHOLD.
+
+2002-06-20  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/ia64/submul_1.c: Add missing TMP_DECL, TMP_MARK, TMP_FREE.
+	Reported by Paul Zimmermann.
+
+	* configure.in, acinclude.m4 (AC_DEFINE): Make templates read "Define
+	to 1", for clarity as per autoconf.
+	* acinclude.m4 (GMP_OPTION_ALLOCA): Group WANT_TMP templates.
+
+2002-06-20  Gerardo Ballabio <gerardo.ballabio@unimib.it>
+
+	* gmpxx.h, mpfrxx.h: Remove mpz_classref, let mpq_class::get_num and
+	mpq_class::get_den return mpz_class& as per the documentation.
+	Reported by Roberto Bagnara.
+
+2002-06-18  Kevin Ryde  <kevin@swox.se>
+
+	* tests/rand/t-lc2exp.c: New file.
+	* tests/rand/Makefile.am: Add it, and use tests/libtests.la.
+
+	* randraw.c (lc): Pad seed==0 case with zero limbs, return same
+	(m2exp+1)/2 bits as normal, right shift "c" result as normal.
+
+	* configure.in: Don't bother with line numbers in some diagnostics.
+	(*-*-mingw*): Use -mno-cygwin if it works, suggested by delta trinity.
+
+	* tests/mpz/Makefile.am, tests/mpq/Makefile.am,
+	tests/misc/Makefile.am, (CLEANFILES): Set to *.tmp for test program
+	temporaries, to get t-scanf.tmp and reduce future maintenance.
+
+2002-06-16  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/get_str.c (mpn_dc_get_str): Pass scratch memory area in
+	new `tmp' parameter.  Trim allocation needs by reusing input parameter.
+
+2002-06-15  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/sparc32/v9/udiv.asm: New file.
+
+2002-06-15  Kevin Ryde  <kevin@swox.se>
+
+	* acinclude.m4 (GMP_GCC_VERSION_GE): Correction to recognising mingw
+	gcc 3.1 version number.  Reported by Jim Fougeron.
+
+	* configure.in (AC_PROVIDE_AC_LIBTOOL_WIN32_DLL): New define, to make
+	AC_LIBTOOL_WIN32_DLL work with autoconf 2.53.
+
+	* acinclude.m4 (GMP_C_SIZES): Establish BITS_PER_MP_LIMB as a value,
+	not an expression, for the benefit of the gen-bases invocation.
+
+	* config.guess (CC_FOR_BUILD): Try c99, same as configfsf.guess.
+
+2002-06-15  Paul Zimmermann  <Paul.Zimmermann@loria.fr>
+
+	* mpfr/set_q.c: Allow for 1 bit numerator or denominator.
+
+2002-06-14  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (AC_C_BIGENDIAN): Use new style action parameters.
+
+	* randlc2x.c: Allow for a<0, allow for c>=2^m2exp.
+	* randraw.c (lc): Allow for a==0.
+
+	* mpn/sparc32/udiv.asm: Renamed from udiv_fp.asm.  Don't know if float
+	is the best way for v7, but it's what configure has chosen since gmp 3.
+	* configure.in (*sparc*-*-* ABI=32): extra_functions="udiv" for all,
+	in particular sparc32/v8/udiv.asm is faster (on ultrasparc2) than
+	udiv_fp previously used for v9 chips.
+
+	* gen-bases.c: New file, derived from mpn/mp_bases.c.
+	* dumbmp.c: New file, mostly by Torbjorn, some by me.
+	* configure.in, acinclude.m4 (GMP_PROG_CC_FOR_BUILD,
+	GMP_PROG_CPP_FOR_BUILD, GMP_PROG_EXEEXT_FOR_BUILD,
+	GMP_C_FOR_BUILD_ANSI, GMP_CHECK_LIBM_FOR_BUILD): New macros.
+	(GMP_PROG_HOST_CC): Remove, superceded by GMP_PROG_CC_FOR_BUILD.
+	* Makefile.am: Run gen-bases to create mp_bases.h and mpn/mp_bases.c.
+	* gmp-impl.h: Use mp_bases.h.
+	* mpn/mp_bases.c: Remove file.
+	* mpn/Makefile.am: mp_bases.c now in nodist_libmpn_la_SOURCES.
+
+	* tests/mpz/t-cmp_d.c (check_one_2exp): Use volatile to force to
+	double, fixes gcc 3.1 with -O4.  Reported by Michael Lee.
+	* configure.in (AC_C_VOLATILE): New macro.
+
+	* tests/misc/t-scanf.c: (fromstring_gmp_fscanf): Add missing va_end.
+	Don't mix varargs and fixed args functions, not good on x86_64.
+	Reported by Marcus Meissner.
+
+	* Makefile.am (EXTRA_DIST): Remove mpfr/README, now in mpfr/Makefile.in
+
+	* configure, config.in, INSTALL.autoconf: Update to autoconf 2.53.
+	* */Makefile.in, install-sh, mdate-sh, missing, aclocal.m4, configure:
+	Update to automake 1.6.1.
+	* configfsf.guess, configfsf.sub: Update to 2002-05-29.
+
+2002-06-12  Kevin Ryde  <kevin@swox.se>
+
+	* acinclude.m4 (GMP_GCC_VERSION_GE): Recognise mingw gcc 3.1 version.
+	(GMP_PROG_CC_WORKS): Allow for a_out.exe, as per autoconf.
+	(GMP_GCC_NO_CPP_PRECOMP, GMP_ASM_UNDERSCORE): Ditto, plus a.exe.
+
+2002-06-09  Torbjorn Granlund  <tege@swox.com>
+
+	* randraw.c (lc): Remove broken ASSERT_ALWAYS.
+
+	* mpn/x86: Update gmp-mparam.h files with current measures *_THRESHOLD
+	values.
+	* mpn/x86/p6/mmx/gmp-mparam.h: New file.
+
+2002-06-09  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/x86/*/gmp-mparam.h (USE_PREINV_DIVREM_1): Add tuned settings.
+
+	* acconfig.h (HAVE_NATIVE_mpn_preinv_divrem_1): New template.
+
+	* tests/refmpn.c, tests/tests.h (refmpn_chars_per_limb,
+	refmpn_big_base): New functions.
+	* tests/mpn/t-mp_bases.c: Use them, and don't test big_base_inverted
+	unless it's being used.
+
+	* gmp.texi (Notes for Particular Systems): Using Microsoft C with DLLs.
+	(Known Build Problems): Notes on MacOS and GCC.
+	(Integer Logic and Bit Fiddling): Use ULONG_MAX for maximum ulong.
+	(Low-level Functions): mpn_get_str accepts base==256.
+	(Formatted Output Functions): Note output is not atomic.
+	(Internals): Note mp_size_t for limb counts.
+
+	* mp-h.in, gmp-h.in (mp_ptr, mp_srcptr, mp_size_t, mp_exp_t): Remove
+	these types from mp.h, not needed.
+
+	* mpfr/tests/tadd.c, mpfr/tests/tmul.c (check): Apply a hack to the
+	parameter order to make sparc gcc 2.95.2 happy.
+
+	* doc/configuration: Notes on bootstrapping.
+
+2002-06-08  Kevin Ryde  <kevin@swox.se>
+
+	* mpfr/tests/tsqrt.c, mpfr/tests/tsqrt_ui.c: Suppress tests if sqrt is
+	not affected by mpfr_set_machine_rnd_mode.
+
+	* mpfr/mul_2si.c: Workaround a mips gcc 2.95.3 bug under -O2 -mabi=n32.
+
+	* configure.in (alphev56): Fix to use ev5 path.
+
+2002-06-06  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-h.in: Use __gmp_const not const, in a number of places.
+
+	* configure.in (sparc): Use ABI=32 instead of ABI=standard on v7 and
+	v8, for consistency with v9 choices.
+	(sparc64): Restrict GMP_ASM_SPARC_REGISTER to ABI=64.
+	(x86): Move MMX $path munging to before printout.
+	(CCAS): Move upward to support this.
+
+	* gmp-impl.h (modlimb_invert): Merge macros for specific limb sizes,
+	add a version for arbitrary limb size, use GMP_NUMB_BITS.
+	(modlimb_invert, MODLIMB_INVERSE_3): Fix comments to say GMP_NUMB_BITS.
+
+	* gmp-h.in (__GMP_LIKELY, __GMP_UNLIKELY): New macros.
+	(mpz_getlimbn, mpz_perfect_square_p, mpz_popcount): Use them, make the
+	fetch or mpn call likely, unconditionally calculate the alternative so
+	as to avoid an "else" clause.
+	* gmp-impl.h (LIKELY, UNLIKELY): Aliases.
+
+	* configure.in, mpfr/tests/Makefile.am: Add $LIBM to $LIBS for
+	MPFR_CONFIGS so it detects fesetround, and let it go through to
+	$MPFR_LIBS.
+	* mpfr/rnd_mode.c: Use gmp-impl.h to get MPFR_HAVE_FESETROUND.
+
+	* tests/mpz/t-sizeinbase.c: Disable fake bits test, such pointer
+	setups are bogus and have been seen failing on hppa.
+
+	* tests/misc.c, tests/refmpz.c, tests.tests.h, tests/mpz/t-cong.c:
+	Rename mpz_flipbit to refmpz_combit and move from misc.c to refmpz.c.
+
+2002-06-05  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/mpz/t-powm_ui.c Print proper routine name in error message.
+
+2002-06-03  Kevin Ryde  <kevin@swox.se>
+
+	* tune/time.c, tune/freq.c, tune/speed.h: Add powerpc mftb support.
+	(FREQ_MEASURE_ONE): Move to speed.h, fix tv_sec factor.
+	(freq_measure): Use for mftb measuring too.
+	* tune/powerpc.asm, tune/powerpc64.asm: New files.
+	* configure.in, tune/Makefile.am: Add them.
+
+	* gmp-impl.h (popc_limb): Add versions for Cray and fallback for
+	arbitrary limb size.
+
+	* mpn/sparc32/sparc-defs.m4: New file.
+	* configure.in (sparc*-*-*): Use it.
+	* acinclude.m4 (GMP_ASM_SPARC_REGISTER): New macro.
+	* configure.in (sparc64): Use it.  Also, use -Wc,-m64 for linking.
+	* mpn/sparc64/add_n.asm, mpn/sparc64/addmul_1.asm,
+	mpn/sparc64/copyd.asm, mpn/sparc64/copyi.asm, mpn/sparc64/lshift.asm,
+	mpn/sparc64/mul_1.asm, mpn/sparc64/rshift.asm,
+	mpn/sparc64/sqr_diagonal.asm, mpn/sparc64/sub_n.asm,
+	mpn/sparc64/submul_1.asm: Use REGISTER for .register.
+
+2002-06-01  Kevin Ryde  <kevin@swox.se>
+
+	* mpz/powm_ui.c: Fix for result range in certain circumstances.
+
+	* mpn/x86/k6/diveby3.asm: Speedup to 10 c/l, same as divexact_1.
+	Anomaly pointed out by Alexander Kruppa.
+
+2002-05-31  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/export.c: Cast pointer via `unsigned long' when checking
+	alignment to avoid compiler warnings.
+
+2002-05-29  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-impl.h (BSWAP_LIMB): Versions for m68k, powerpc, and arbitrary
+	limb size.
+	* configure.in, acconfig.h (HAVE_HOST_CPU_FAMILY_m68k): New define.
+
+2002-05-27  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/mul_basecase.c: Improve MAX_LEFT handling, returning
+	when possible.  Add code for mpn_addmul_5 and mpn_addmul_6.
+
+2002-05-25  Kevin Ryde  <kevin@swox.se>
+
+	* tune/tuneup.c: Misc nailifications, and disable preinv thresholds
+	with nails.
+	* tune/speed.h: Use GMP_NUMB_HIGHBIT with mpn_sb_divrem_mn and
+	mpn_divrem_2.
+	* mpz/powm.c (redc): Nailify q.
+
+	* tests/mpn/t-scan.c: Reduce the amount of testing, to go faster.
+
+2002-05-23  Torbjorn Granlund  <tege@swox.com>
+
+	* Version 4.1 released.
+
+	* mpn/alpha/ev6/nails/gmp-mparam.h: New file.
+
+	* tests/devel/add_n.c (refmpn_add_n): Nailify.
+	* tests/devel/sub_n.c (refmpn_sub_n): Nailify.
+	* tests/devel/addmul_1.c (refmpn_addmul_1): Nailify.
+	* tests/devel/submul_1.c (refmpn_submul_1): Nailify.
+
+	* mpn/alpha/ev6/nails/add_n.asm: New file.
+	* mpn/alpha/ev6/nails/sub_n.asm: New file.
+	* mpn/alpha/ev6/nails/mul_1.asm: New file.
+	* mpn/alpha/ev6/nails/submul_1.asm: New file.
+
+2002-05-22  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/alpha/ev6/nails/addmul_1.asm: New file.
+
+	* mpz/inp_str.c (mpz_inp_str_nowhite): Nailify.
+
+	* mpn/generic/mul_basecase.c: Update pointers before conditional
+	MAX_LEFT break statements.
+
+2002-05-21  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/mpz/t-gcd.c: Test mpz_gcd_ui.
+
+	* mpz/lcm_ui.c: Nailify.
+
+	* mpz/gcd_ui.c: Nailify.  Make it work as documented, allowing
+	NULL to be passed for result parameter.  Fix gcd(0,0) case.
+
+	* mpz/set_str.c: Nailify.
+
+	* randlc2x.c (gmp_randinit_lc_2exp): Nailify.
+
+	From Jakub Jelinek:
+	* longlong.h (add_ssaaaa,sub_ddmmss) [64-bit sparc]:
+	Make it actually work.
+
+2002-05-18  Torbjorn Granlund  <tege@swox.com>
+
+	* mpf/ui_div.c: Shut up compiler warning.
+
+	* mpn/generic/mul_basecase.c: Use mpn_addmul_2, mpn_addmul_3, and
+	mpn_addmul_4, as available.
+
+	* mpn/alpha/ev6/nails/addmul_2.asm: Adjust NAILS_SUPPORT decls.
+	* mpn/alpha/ev6/nails/addmul_3.asm: Likewise
+	* mpn/alpha/ev6/nails/addmul_4.asm: Likewise.
+
+	* configure.in (*-cray-unicos*): Back again to -hscalar0.
+	(gmp_mpn_functions_optional): Add mul_3, mul_4, addmul_2, addmul_3,
+	and addmul_4.
+	* acconfig.h: Add #undefs for new optional mpn functions.
+
+2002-05-18  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi (Integer Import and Export): Mention Cray unfilled words.
+
+	* mpz/set_d.c, mpq/set_d.c: Use LIMBS_PER_DOUBLE for the output of
+	__gmp_extract_double.  Reported by Henrik Johansson.
+
+2002-05-17  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/alpha/ev6/nails/addmul_2.asm: New file.
+	* mpn/alpha/ev6/nails/addmul_3.asm: New file.
+	* mpn/alpha/ev6/nails/addmul_4.asm: New file.
+
+	* mpn/generic/dump.c: Rewrite and nailify.
+
+2002-05-16  Kevin Ryde  <kevin@swox.se>
+
+	* mpfr/Makefile.am (EXTRA_DIST): Add BUGS file.
+
+2002-05-15  Torbjorn Granlund  <tege@swox.com>
+
+	* configure.in (*-cray-unicos*): Remove -hscalar0, add -hnofastmd
+	as workaround for compiler bug.
+	(mips64*-*-*): Pass just -O1 to cc, to work around compiler bug.
+
+2002-05-14  Torbjorn Granlund  <tege@swox.com>
+
+	* configure.in (*-cray-unicos*): Pass -hscalar0 to work around
+	compiler bug for mpz/import.c.
+
+2002-05-11  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/import.c: Cast pointer via `unsigned long' when checking
+	alignment to avoid compiler warnings.
+
+	* mpn/generic/rootrem.c: Adjust allocation of qp temporary area.
+
+2002-05-09  Kevin Ryde  <kevin@swox.se>
+
+	* mpz/import.c: Corrections to size store, special case tests, and
+	general case ACCUMULATE.
+	* tests/mpz/t-import.c, tests/mpz/t-export.c: More test data.
+
+2002-05-09  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/rootrem.c: Use temp space for root, copy value in place
+	before returning.
+	* mpz/root.c: Don't allocate extra limb for root value.
+	* mpz/perfpow.c: Undo last change.
+
+2002-05-08  Torbjorn Granlund  <tege@swox.com>
+
+	* gmp-impl.h (powerpc BSWAP_LIMB_FETCH): Rename local variable to make
+	it not clash with caller.
+
+	* mpn/generic/rootrem.c: New file.
+	* configure.in (gmp_mpn_functions): Add rootrem and pow_1.
+	* mpn/Makefile.am (nodist_libdummy_la_SOURCES): Add rootrem.c and
+	pow_1.c
+	* gmp-impl.h (mpn_rootrem): Add declaration.
+	* mpz/perfpow.c: Amend allocations for mpn_rootrem requirements.
+	* mpz/root.c: Rewrite to use mpn_rootrem.
+
+2002-05-08  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-impl.h (MUL_KARATSUBA_THRESHOLD etc): Remove forced nail values.
+
+	* mpf/fits_u.h, mpf/fits_s.h, tests/mpf/t-fits.c: Ignore fraction
+	part, making the code match the documentation.
+
+	* gmpxx.h (struct __gmp_binary_minus): Use mpz_ui_sub.
+
+2002-05-07  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/powerpc32/README: New file.
+
+	* mpz/root.c: Use unsigned long with mpz_sub_ui not mp_limb_t.
+
+	* tune/README: Misc updates including sparc32/v9 smoothness, low res
+	timebase, and mpn_add_n operand overlaps.
+	* tune/many.pl: Add udiv.asm support.
+
+	* gmp.texi (Build Options): A couple of --build better as --host.
+	(Known Build Problems, Notes for Package Builds): Add DESTDIR problem.
+	(Compatibility with older versions): Compatible with 4.x versions.
+	(Converting Integers): Remove mpz_get_ui + mpz_tdiv_q_2exp decompose.
+	(Integer Import and Export): New section.
+	(Miscellaneous Integer Functions): Clarify mpz_sizeinbase returns 1
+	for operand of 0.
+	(Language Bindings): Add GNU Pascal.
+	(Low-level Functions): Add GMP_NUMB_MAX.
+
+	* tests/mpz/t-import.c, tests/mpz/t-export.c, tests/mpz/t-get_d.c:
+	New tests.
+	* tests/mpz/Makefile.am: Add them.
+
+	* mpz/import.c, mpz/export.c: New files.
+	* Makefile.am, mpz/Makefile.am, gmp-h.in: Add them.
+
+	* gmp-h.in, gmp-impl.h (GMP_NUMB_MAX): Move to gmp.h.
+	* gmp-impl.h (CNST_LIMB): Add cast to mp_limb_t to ensure unsigned.
+	(CRAY_Pragma, MPN_REVERSE, MPN_BSWAP, MPN_BSWAP_REVERSE,
+	ASSERT_ALWAYS_LIMB, ASSERT_ALWAYS_MPN): New macros.
+	(MPZ_CHECK_FORMAT): Use ASSERT_ALWAYS_MPN.
+
+2002-05-07  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/aors_ui.h: Nailify.
+
+	* tests/mpz/t-addsub.c: New file.
+	* tests/mpz/Makefile.am (check_PROGRAMS): Add t-addsub.
+
+	* mpz/ui_sub.c: New file.
+	* mpz/Makefile.am (libmpz_la_SOURCES): Add ui_sub.c.
+	* Makefile.am (MPZ_OBJECTS): Ditto.
+	* gmp-h.in (mpz_ui_sub): Add declaration.
+
+	* gmp-impl.h (MPZ_REALLOC): Rewrite to allow the use of _mpz_realloc
+	return value.
+
+	* gmp-h.in (mpn_pow_1): Add declaration.
+
+	* mpn/generic/pow_1.c: Handle exp <= 1.  Reverse rp/tp parity scheme
+	for bn == 1 arm.
+
+	* Rename MP_LIMB_T_HIGHBIT => GMP_LIMB_HIGHBIT.
+
+2002-05-06  Torbjorn Granlund  <tege@swox.com>
+
+	* demos/pexpr.c (main): Don't call mpz_sizeinbase with negative base.
+
+	* randraw.c (lc): Remove an unused variable.
+
+	* mpn/generic/get_str.c: Clarify an algorithm description.
+
+	* tests/mpf/t-trunc.c: Nailify.
+	* tests/mpf/t-set_si.c: Disable for nails.
+
+	* mpf/cmp_si.c: Nailify.
+	* mpf/cmp_ui.c: Nailify.
+	* mpf/div.c: Nailify.
+	* mpf/div_2exp.c: Nailify.
+	* mpf/div_ui.c: Nailify.
+	* mpf/eq.c: Nailify.
+	* mpf/get_d.c: Nailify.
+	* mpf/get_d_2exp.c: Nailify.
+	* mpf/get_si.c: Nailify.
+	* mpf/get_str.c: Nailify.
+	* mpf/get_ui.c: Nailify.
+	* mpf/mul_2exp.c: Nailify.
+	* mpf/random2.c: Nailify.
+	* mpf/set_q.c: Nailify.
+	* mpf/set_si.c: Nailify.
+	* mpf/set_str.c: Nailify.
+	* mpf/set_ui.c: Nailify.
+	* mpf/sub.c: Nailify.
+	* mpf/ui_div.c: Nailify.
+	* mpf/ui_sub.c: Nailify.
+	* mpf/urandomb.c: Nailify.
+
+	* gmp-impl.h (__GMPF_BITS_TO_PREC, __GMPF_PREC_TO_BITS): Nailify.
+
+	* mpz/get_si.c: Misc variable name changes.
+
+	* mpf/fits_u.h: Rewrite - nailify.
+	* mpf/fits_s.h: Likewise.
+
+	* mpz/mod.c: Disambiguate if-statement with extra {}.
+
+	* mpf/int_p.c: Fix type of size variables.
+	* mpf/get_ui: Likewise.
+	* mpf/get_si: Likewise.
+	* mpq/equal.c: Likewise.
+	* mpq/get_d.c: Likewise.
+	* mpz/cmp_d.c: Likewise.
+	* mpz/cmpabs_d.c: Likewise.
+	* mpz/divis_2exp.c: Likewise.
+	* mpz/kronuz.c: Likewise.
+	* mpz/kronzu.c: Likewise.
+	* mpz/kronzs.c: Likewise.
+	* mpz/kronsz.c: Likewise.
+	* mpz/scan0.c: Likewise.
+	* mpz/scan1.c: Likewise.
+	* mpz/tstbit.c: Likewise.
+	* mpz/cong_2exp.c: Likewise.
+	* mpz/divis.c: Likewise.
+
+2002-05-04  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/gcd.c: Additional nailify changes.
+
+2002-05-04  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-h.in (__GNU_MP_VERSION): Set to 4.1.
+	* Makefile.am (-version-info): Bump for new release.
+
+2002-04-30  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/divrem_1.c: Additional nailify changes.
+	* mpn/generic/mod_1.c: Likewise.
+
+	* tests/mpq/t-get_d.c: Print floats with all 16 digits.
+
+	* mpq/get_d.c: Nailify.
+
+	* tests/mpq/t-set_f.c: Disable for nails.
+
+	* mpz/get_d.c: Nailify.
+
+	* gmp-impl.h (LIMBS_PER_DOUBLE, MP_BASE_AS_DOUBLE): Nailify.
+
+	* gmp-h.in (__GMPZ_FITS_UTYPE_P): Cast maxval to before shifting it.
+
+	* extract-dbl.c: Nailify.
+
+2002-04-29  Torbjorn Granlund  <tege@swox.com>
+
+	* mpq/md_2exp.c (mord_2exp): Nailify.
+
+	* mpq/cmp_ui.c: Nailify.
+
+	* mpq/cmp.c (mpq_cmp): Nailify.
+
+	* mpn/generic/gcd.c: Nailify.  GNUify code layout.
+
+	* mpn/generic/gcdext.c: Nailify.  Misc changes.
+
+	* tests/mpz/t-sqrtrem.c: Let argv[1] mean # of repetitions.
+	* tests/mpz/t-gcd.c: Likewise.
+
+	* mpz/gcd.c: Nailify.
+
+	* mpn/generic/random.c: Nailify.
+
+	* gmp-impl.h (modlimb_invert): Nailify.
+
+2002-04-27  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/gcdext.c (div2): Remove qh parameter.
+	(mpn_gcdext): Streamline double-limb code.
+	Move GCDEXT_THRESHOLD check to after initial division.
+
+2002-04-27  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-impl.h (JACOBI_MOD_OR_MODEXACT_1_ODD): Allow for odd
+	GMP_NUMB_BITS.
+
+	* tune/time.c (sgi_works_p): Allow for 64-bit counter, and fix
+	SGI_CYCLECNTR_SIZE handling.
+
+	* demos/expr/exprfr.c: Add nan and inf constants.
+	* demos/expr/t-expr.c: Exercise them.
+
+2002-04-26  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/cmp_ui.c: Fix overflow conditions for nails.
+
+	* gmp-h.in (mpz_get_ui): Fix typo from last change.
+
+	* mpz/n_pow_ui.c: Adjust allocation for nails.
+	(GMP_NUMB_HALFMAX): Renamed from MP_LIMB_T_HALFMAX.
+	Fix umul_ppmm invocation for for nails.
+
+2002-04-24  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/gcdext.c: Simplify by using mpn_tdiv_qr instead of
+	mpn_divmod.
+
+2002-04-24  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (*-*-cygwin*): Give a sensible default command line
+	limit, to avoid blowups reported by Jim Fougeron on windows 9x.
+	(--enable-nails): Make the default 2, since mp_bases has data for that.
+
+	* mpfr/mpfr-math.h (__mpfr_nan): Use a "double" for the bytes, to
+	avoid a mis-conversion on alpha gcc 3.0.2.
+	(_MPFR_INFP_BYTES, _MPFR_INFM_BYTES): Should be a zero mantissa.
+
+2002-04-23  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/dive_ui.c: Fix typo.
+
+	* mpz/fits_s.h: Rewrite.
+
+	* mpz/jacobi.c: Nailify.
+	* mpz/kronuz.c: Additional nailify changes.
+	* mpz/kronsz.c: Likewise.
+
+2002-04-23  Kevin Ryde  <kevin@swox.se>
+
+	* demos/expr/Makefile.am (LDADD): Add $(LIBM) for the benefit of mpfr.
+
+	* mpz/divis_ui.c, mpz/cong_ui.c: Nailify.
+	* mpn/generic/bdivmod.c, mpz/divexact.c, mpz/dive_ui.c: Nailify.
+	* mpn/generic/sb_divrem_mn.c, mpn/generic/divrem.c,
+	mpn/generic/divrem_2.c: Nailify ASSERTs.
+	* mpn/x86/k6/mmx/logops_n.asm, mpn/x86/k6/mmx/com_n.asm: Nailify.
+	* mpz/inp_raw.c, mpz/out_raw.c: Nailify.
+	* mpz/kronzu.c, mpz/kronuz.c, mpz/kronzs.c, mpz/kronsz.c: Nailify.
+	* mpn/generic/divis.c, mpz/cong.c, mpz/cong_2exp.c: Nailify.
+	* gmp-impl.h (NEG_MOD): Nailify.
+
+	* gmp-impl.h, mpn/mp_bases.c: Add back GMP_NUMB_BITS==30 bases data.
+
+	* mpfr/get_d.c: Patch from Paul to avoid problem with constant folding
+	in gcc on OSF.
+
+	* mpn/lisp/gmpasm-mode.el: Remove mention of defunct LF macro.
+
+2002-04-22  Torbjorn Granlund  <tege@swox.com>
+
+	* demos/pexpr.c: Handle "binomial" operator.
+
+	* mpz/cmp_ui.c: Move assignments of `up' out of conditionals.
+
+	* mpn/generic/gcdext.c: Fix fencepost error in STAT code.
+
+	* gmp-impl.h (mpn_com_n): Nailify.
+
+	* tests/mpz/t-cdiv_ui.c: New file.
+	* tests/mpz/Makefile.am (check_PROGRAMS): Add t-cdiv_ui.
+	* mpz/cdiv_qr_ui.c: Nailify.
+	* mpz/cdiv_q_ui.c: Nailify.
+	* mpz/cdiv_r_ui.c: Nailify.
+	* mpz/cdiv_ui.c: Nailify.
+
+	* tests/misc/t-printf.c (CHECK_N): Add cast to allow `char' to be an
+	unsigned type.
+	* tests/misc/t-scanf.c: Likewise.
+
+	* mpz/mul_i.h: Rework nails code to handle parameter overlap.
+
+	* tests/mpz/t-set_f.c: Disable for nails.
+
+2002-04-21  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/set_si.c: Add cast to support LONG_LONG_LIMB.
+	* mpz/iset_si.c: Likewise.
+
+	* mpz/bin_ui.c: Nailify.
+	* mpz/bin_uiui.c: Nailify.
+
+	* mpz/cmpabs_ui.c: Nailify.
+
+	* tests/mpz/t-aorsmul.c: Nailify.
+	* mpz/aorsmul_i.c (mpz_addmul_ui, mpz_submul_ui): Nailify better.
+
+2002-04-20  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/mpz/t-fdiv_ui.c: Check mpz_fdiv_ui.
+	* tests/mpz/t-tdiv_ui.c: Check mpz_tdiv_ui.
+
+	* mpz/tdiv_ui.c: Rewrite nails code.
+	* mpz/fdiv_ui.c: Nailify.
+
+	* tests/mpz/t-tdiv_ui.c: Check returned remainders.
+	* tests/mpz/t-fdiv_ui.c: Merge in recent t-tdiv_ui changes.
+
+	* mpz/tdiv_q_ui.c: Remove spurious TMP_* calls.
+
+	* mpz/fdiv_qr_ui.c: Nailify.
+	* mpz/fdiv_q_ui.c: Nailify.
+	* mpz/fdiv_r_ui.c: Nailify.
+
+	* mpz/get_si.c: Misc nailify changes to shut up compiler warnings.
+
+	* mpz/ui_pow_ui.c: Fix typo in last change.
+
+2002-04-20  Kevin Ryde  <kevin@swox.se>
+
+	* tests/misc/t-printf.c, tests/misc/t-scanf.c: Check all %n types.
+
+	* mpn/x86/k7/mmx/divrem_1.asm, mpn/x86/p6/mmx/divrem_1.asm
+	(mpn_preinv_divrem_1): New entrypoint.
+	(mpn_divrem_1): Avoid a branch when testing high<divisor.
+	* mpn/asm-defs.m4: Add define_mpn(preinv_divrem_1).
+	* configure.in: Allow divrem_1.asm to provide mpn_preinv_divrem_1.
+
+	* gmp-impl.h [nails]: Add #undefs of MUL_KARATSUBA_THRESHOLD etc, to
+	override CPU gmp-mparam.h.  Remove JACOBI_BASE_METHOD override since
+	it's nails-neutral.
+
+	* tests/mpn/t-mp_bases.c: New file.
+	* tests/mpn/Makefile.am (check_PROGRAMS): Add it.
+	* tests/t-constants.c: Move MP_BASES constants checks to it.
+
+	* mpn/mp_bases.c: Fix big_base_inverted values for nails.
+	* gmp-impl.h (MP_BASES_BIG_BASE_INVERTED_10,
+	MP_BASES_NORMALIZATION_STEPS_10): Fix nails values.
+	(MP_BASES_*): Remove GMP_NUMB_BITS == 30 data.
+
+	* mpn/x86/pentium/com_n.asm, mpn/x86/pentium/logops_n.asm: Add
+	NAILS_SUPPORT indicators.
+
+	* configure.in: Grep for NAILS_SUPPORT in cpu-specific code, and look
+	in "nails" subdirectories, print path used.
+	* mpn/asm-defs.m4 (NAILS_SUPPORT): New macro.
+
+	* mpfr/mpfr-test.h: Include config.h, for the benefit of test programs
+	not using gmp-impl.h.
+
+2002-04-19  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/mpz/t-scan.c: Nailify.
+
+	* mpz/tdiv_qr_ui.c: Nailify.
+	* mpz/tdiv_q_ui.c: Nailify.
+	* mpz/tdiv_r_ui.c: Nailify.
+	* mpz/tdiv_ui.c: Nailify.
+
+	* mpz/cmp_ui.c: Nailify.
+
+	* mpz/ui_pow_ui.c: Misc nailify changes to shut up compiler warnings.
+
+	* mpz/scan0.c: Nailify.
+	* mpz/scan1.c: Nailify.
+
+	* tests/mpz/t-sizeinbase.c (mpz_fake_bits): Nailify.
+
+2002-04-18  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/aorsmul_i.c: Nailify.
+
+	* mpz/cmp_si.c: Nailify (botched).
+
+	* mpz/ui_pow_ui.c: Nailify.
+
+	* gmp-h.in (__GMPZ_FITS_UTYPE_P): Nailify.
+
+	* mpz/fits_s.h: Nailify.
+
+	* tests/mpz/bit.c (check_tstbit): Nailify.
+
+	From Paul Zimmermann:
+	* mpn/generic/sqrtrem.c: Nailify.
+
+	* mpz/n_pow_ui.c: Nailify.
+
+	* mpz/cfdiv_r_2exp.c: Nailify.
+
+	* randraw.c (lc): Undo: Let mpn_rshift put result in place to avoid
+	extra MPN_COPY.
+
+2002-04-17  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/clrbit.c: Add two GMP_NUMB_MASK masks after addition.
+
+	* mpn/generic/random2.c (LOGBITS_PER_BLOCK): Decrease to 4.
+
+	* gmp-impl.h (nail DIV_DC_THRESHOLD): Decrease to 50 to allow fast
+	division.
+
+	* mpn/generic/random2.c: Nailify.
+
+	* mpz/fac_ui.c: Nailify.
+
+	* mpz/mul_i.h: #if ... #endif code block to shut up gcc warnings.
+
+	* mpn/generic/sqrtrem.c: Adopt to GNU coding standards.
+	(mpn_dc_sqrtrem): New name for mpn_dq_sqrtrem.
+	Partial nailification.
+
+	* configure.in: As a temporary hack, clear extra_functions for nails
+	builds.
+
+	* gmp-h.in (mpz_get_ui): #if ... #endif else code block to shut up gcc
+	warnings.
+
+2002-04-17  Kevin Ryde  <kevin@swox.se>
+
+	* texinfo.tex: Update to 2002-03-26.08 per texinfo 4.2.
+	* gmp.texi: Must have @top in @ifnottex (or @contents doesn't come out
+	in one run).
+
+	* mpn/generic/scan0.c, mpn/generic/scan1.c: Nailify.
+
+	* tests/mpn/t-scan.c: New file.
+	* tests/mpn/Makefile.am (check_PROGRAMS): Add it.
+
+	* tests/refmpn.c, tests/tests.h (refmpn_tstbit): Use unsigned long for
+	bit index.
+	(refmpn_setbit, refmpn_clrbit, refmpn_scan0, refmpn_scan1): New
+	functions.
+
+	* mpfr/cmp_ui.c (mpfr_cmp_si_2exp): Fix b==0 i!=0 case.
+
+2002-04-17  Gerardo Ballabio <gerardo.ballabio@unimib.it>
+
+	* gmpxx.h, mpfrxx.h: Remove mpfr_class bool combinations, remove
+	mpfr_class::get_str2, use mp_rnd_t for rounding modes, use
+	8*sizeof(double) for mpfr_t's holding doubles.
+
+2002-04-17  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/powm.c: Nailify.
+	* mpz/powm_ui.c: Nailify.
+
+2002-04-16  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/hamdist.c: Nailify.
+	* tests/misc.c (urandom): Nailify.
+
+	* mpz/get_si.c: Nailify.
+	* gmp-h.in (mpz_get_ui): Nailify.  Streamline (and probably upset
+	memory checkers).
+
+	* gmp-impl.h (mp_bases[10] values): Add versions for GMP_NUMB_BITS
+	being 28, 60, and 63.
+	* mpn/mp_bases.c: Add tables for GMP_NUMB_BITS being 28, 60, and 63.
+
+	* mpz/iset_si.c: Nailify.
+	* mpz/iset_ui.c: Nailify
+
+	* tests/mpz/convert.c (main): Print test number in error message.
+
+	* mpn/generic/get_str.c (mpn_sb_get_str): Shift up `frac' into nails
+	field after bignum division.
+
+2002-04-16  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-h.in, gmp-impl.h (GMP_NAIL_MASK): Move to gmp.h.
+
+	* gmp.texi: Use @documentdescription and @copying, per texinfo 4.2.
+	(Low-level Functions): Clarify mpn_gcd overlap requirements, rewrite
+	mpn_set_str description, add nails section.
+	(C++ Interface General): Remove bool from types that mix with classes.
+	(Language Bindings): Add STklos, GNU Smalltalk, Regina.
+	(Binary to Radix, Radix to Binary): Describe new code.
+	(Assembler Cache Handling): More notes, mostly by Torbjorn.
+
+	* macos/configure (%vars): Remove __GMP from substitutions, per change
+	to main configure.
+
+	* mpn/generic/dive_1.c: Nailify.
+	* mpn/generic/mode1o.c: Nailify, remove bogus ASSERT in commented-out
+	alternate implementation.
+	* gmp-impl.h (SUBC_LIMB): New macro.
+
+	* tests/devel/try.c (validate_divexact_1): Correction to compare.
+	(udiv_qrnnd): New testing.
+	(SHIFT_LIMIT): Nailify.
+	(-b): New option, remove spurious "H" from getopt string.
+
+	* mpz/clrbit.c: Nailify.
+	* tests/mpz/t-hamdist.c: Nailify.
+	* gmp-impl.h (MPN_FIB2_SIZE): Nailify.
+	(PP): Nailify conditionals.
+	* tests/mpz/t-fib_ui.c (MPZ_FIB_SIZE_FLOAT): Nailify.
+
+	* configure.in, acinclude.m4: Establish GMP_NAIL_BITS and
+	GMP_LIMB_BITS for gmp-h.in configure tests.
+
+	* mpfr/*, configure.in: Update to final mpfr 2.0.1.
+	* mpfr/acinclude.m4 (MPFR_CONFIGS): Use $host, not uname stuff.
+	* mpfr/tests/tout_str.c: Patch from Paul for denorm fprintf tests.
+
+2002-04-15  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/divrem_1.c (EXTRACT): Remove.
+
+	* tests/mpz/t-tdiv_ui.c (dump_abort): Accept argument for error string.
+
+	* mpz/rrandomb.c: Nailify.  Needs further work.
+
+	* mpn/generic/mod_1.c: Nailify.
+
+	* gmp-impl.h: Set various *_THRESHOLD values to be used for nails to
+	avoid not yet qualified algorithms.
+	(MPZ_CHECK_FORMAT): Check that nail part is zero.
+
+	* tests/mpz/t-mul.c (main): Test squaring even for huge operands.
+	(base_mul): Nailify.
+	(dump_abort): Accept argument for error string.  Print product
+	difference.
+
+	* mpn/generic/set_str.c: Nailify.
+
+	* gmp-h.in (__GMPN_ADD, __GMPN_SUB): Nailify.
+
+2002-04-14  Torbjorn Granlund  <tege@swox.com>
+
+	* randraw.c (lc): Return non-nonsense return value for seed=0 case.
+	Check for m2exp being non-zero early; remove all other tests of m2exp.
+	Remove redundant MPN_ZERO call.
+	Let mpn_rshift put result in place to avoid extra MPN_COPY.
+	Remove confusing comment before function `lc' describing BBS algorithm.
+	Misc simplification and cleanups.
+	Nailify.  Needs further work.
+
+	* mpz/set_si.c: Nailify.
+	* mpz/set_ui.c: Nailify.
+	* mpz/mul_i.h: Nailify.
+
+	* tests/mpz/t-mul_i.c: Actually test _ui routines.  Add some more test
+	values.
+
+	* mpn/generic/mul_n.c: Finish nailifying toom3 code.
+
+2002-04-13  Kevin Ryde  <kevin@swox.se>
+
+	* mpfr/*: Update to another new mpfr 2.0.1.
+	* configure.in, Makefile.am, mpfr/Makefile.am, mpfr/tests/Makefile.am:
+	Use MPFR_CONFIGS macro, establish separate MPFR_CFLAGS for mpfr build.
+
+	* mpfr/tests/Makefile.am: Correction to convenience rule for libmpfr.a.
+
+2002-04-11  Kevin Ryde  <kevin@swox.se>
+
+	* mpfr/set_q.c: gmp-impl.h before mpfr.h to avoid _PROTO redefine.
+
+	* mpfr/*, configure.in: Update to new mpfr 2.0.1.
+
+	* tests/refmpn.c (refmpn_udiv_qrnnd, refmpn_divmod_1c_workaround):
+	Fixes for nails.
+
+	* tests/t-constants.c (MODLIMB_INVERSE_3): Nailify tests.
+	(MP_BASES_BIG_BASE_INVERTED_10, MP_BASES_NORMALIZATION_STEPS_10): Only
+	check these under USE_PREINV_DIVREM_1.
+	* tests/t-modlinv.c: Nailify tests.
+
+2002-04-11  Gerardo Ballabio <gerardo.ballabio@unimib.it>
+
+	* gmpxx.h: Remove bool combinations, remove mpf_class::get_str2, only
+	need <iosfwd> now.
+
+2002-04-11  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/diveby3.c: Nailify.
+	* gmp-impl.h (MODLIMB_INVERSE_3): Nailify.
+
+	* mpn/generic/mul_n.c: Nailify Toom3 code.
+
+2002-04-10  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-impl.h (MPN_KARA_MUL_N_MINSIZE, MPN_KARA_SQR_N_MINSIZE): Set to
+	3, as needed by nails case.
+
+	* mpn/generic/addmul_1.c, mpn/generic/submul_1.c [nails]: Fix vl
+	assert, add rp,n and up,n asserts.
+
+	* mpfr/Makefile.am: Add new mpfr-math.h, install mpf2mpfr.h.
+
+2002-04-10  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/divrem_1.c: Nailify.  Update mp_size_t variables to use
+	`n' suffix instead of `size' suffix.
+	* mpn/generic/divrem_2.c: Likewise.
+	* mpn/generic/sb_divrem_mn.c: Nailify.
+	* mpn/generic/tdiv_qr.c: Nailify.
+	(SHL): Remove silly macro.
+
+	* mpn/generic/mul_n.c (mpn_kara_mul_n): Replace open-coded increment by
+	mpn_incr_u call.  Handle nails in ws[n] increment.
+	* mpn/generic/mul_n.c (mpn_kara_sqr_n): Likewise.
+
+	* gmp-h.in (GMP_NUMB_MASK): New #define.
+	(__GMPN_AORS_1): Add version for nails.
+
+	* gmp-impl.h (GMP_NUMB_MASK): Comment out, now in gmp.h.
+	(mpn_incr_u): Don't assume `incr' is non-zero.
+	(mpn_decr_u): Similarly.
+
+2002-04-09  Kevin Ryde  <kevin@swox.se>
+
+	* mpfr/*, configure.in: Update to mpfr 2.0.1.
+
+	* tests/refmpn.c (refmpn_mul_1c, lshift_make): Corrections for nails.
+	* tssts/refmpn.c, tests/tests.h (refmpn_cmp_allowzero): New function.
+
+	* mpn/generic/mul_1.c [nails]: Fix vl assert, add {up,n} assert.
+
+	* mpn/pa32/hppa1_1/pa7100/addmul_1.asm,
+	mpn/pa32/hppa1_1/pa7100/submul_1.asm: Rename "size" define, to avoid
+	ELF .size directive.  Reported by LaMont Jones.
+
+	* tests/mpz/t-set_si.c: Add nails support.
+
+2002-04-05  Torbjorn Granlund  <tege@swox.com>
+
+	* gmp-impl.h: Replace nail mpn_incr_u, mpn_decr_u with faster versions.
+	(mp_bases[10] values): Check GMP_NUMB_BITS instead of BITS_PER_MP_LIMB.
+	Add GMP_NUMB_BITS == 30 version.
+	(__gmp_doprnt, etc): Remove parameter names.
+
+	* mpn/generic/mul_n.c: Nailify Karatsuba code.
+	* mpn/generic/get_str.c: Nailify.
+	* mpn/generic/sqr_basecase.c: Nailify.
+	* mpn/generic/lshift.c: Nailify.
+	* mpn/generic/rshift.c: Likewise.
+	* mpn/generic/add_n.c: Nailify.  Revamp non-nail code.
+	* mpn/generic/sub_n.c: Likewise.
+	* mpn/generic/mul_1.c: Likewise.
+	* mpn/generic/addmul_1.c: Likewise.
+	* mpn/generic/submul_1.c: Likewise.
+
+2002-04-02  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-impl.h (BSWAP_LIMB_FETCH, BSWAP_LIMB_STORE) [powerpc]:
+	Corrections to constraints, and restrict to bigendian.
+
+2002-03-31  Kevin Ryde  <kevin@swox.se>
+
+	* tests/mpz/dive.c: Better diagnostics.
+
+	* tests/devel/try.c (mpn_get_str, mpn_umul_ppmm_r): New tests.
+
+	* tests/misc.c, tests/tests.h (byte_diff_lowest, byte_diff_highest):
+	New functions.
+
+	* tests/t-bswap.c: New file.
+	* tests/Makefile.am (check_PROGRAMS): Add it.
+
+	* tests/mpn/t-aors_1.c, tests/mpn/t-iord_u.c: Add nails support.
+
+	* gmp-impl.h (MPN_IORD_U) [x86]: Eliminate unnecessary jiord and iord,
+	rename "n" to incr per generic versions, restrict to nails==0.
+	(mpn_incr_u, mpn_decr_u): Add nails support.
+	(GMP_NAIL_LOWBIT, GMP_NUMB_MAX): New macros.
+
+	* tests/trace.c, tests/tests.h (byte_trace, byte_tracen): New
+	functions.
+	* tests/trace.c: Handle NULL operands.
+
+	* tests/refmpn.c, tests/devel/try.c, tune/speed.c: Add preliminary
+	nail support.
+
+	* tests/refmpn.c, test/tests.h (byte_overlap_p, refmpn_equal_anynail,
+	refmpn_umul_ppmm_r, refmpn_udiv_qrnnd_r, refmpn_get_str,
+	refmpn_bswap_limb, refmpn_random, refmpn_random2, refmpn_bswap_limb):
+	New functions.
+
+	* gmp-impl.h, tests/refmpn.c (ASSERT_LIMB): Renamed from
+	ASSERT_MP_LIMB_T.
+
+	* mpn/x86/*/*.asm, mpn/powerpc32/*/*.asm, mpn/powerpc64/*/*.asm: Put
+	speeds after the copyright notice, so as to keep that clear.
+
+2002-03-29  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (powerpc*-*-aix*): Correction to xlc -qarch selection,
+	for 32-bit mode.
+
+2002-03-28  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn: Fix spacing in many files.
+
+	* mpn/generic/aorsmul_1.c: Split into addmul_1.c and submul_1.c.
+	* mpn/generic/aors_n.c: Split into add_n.c and sub_n.c.
+
+	* mpn/pa64/add_n.asm: Trim another 0.125 cycle/limb.  Fix a comment.
+	* mpn/pa64/sub_n.asm: Likewise.
+
+	* mpn/pa64/mul_1.asm: Change comclr, comb to proper forms cmpclr, cmpb.
+	* mpn/pa64/addmul_1.asm: Likewise.
+	* mpn/pa64/submul_1.asm: Likewise.
+
+2002-03-28  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi (Converting Integers): Fix type of exp in mpz_get_d_2exp,
+	reported by epl@unimelb.edu.au.
+	(References): Update Burnikel and Ziegler URL, reported by Keith
+	Briggs.
+
+	* gmp-h.in, mp-h.in, configure.in, acinclude.m4: Remove __GMP from
+	AC_SUBSTs, since autoconf says leading "_" in makefile variables is
+	not portable.
+
+	* demos/expr/run-expr.c: Declare optarg, optind, opterr if necessary.
+	* configure.in, demos/expr/expr-config-h.in: Configs for this.
+
+2002-03-27  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/Makefile.am (TARG_DIST): Remove pa64w and hppa, add pa32.
+
+	* configure.in (path_20w): Remove pa64w.
+
+	* mpn/pa64/udiv_qrnnd.asm: Tweak for PA8000 performance comparative to
+	that on PA8500.
+
+2002-03-26  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/pa32: New name for mpn/hppa.
+	* configure.in: Corresponding changes.
+
+	* mpn/pa64/umul_ppmm.asm: New file, generalized for both 2.0N and 2.0W.
+	* mpn/pa64/umul_ppmm.S: Remove.
+
+	* mpn/pa64/udiv_qrnnd.asm: Generalize for both 2.0N and 2.0W.
+	* mpn/pa64w/udiv_qrnnd.asm: Remove.
+
+2002-03-26  Kevin Ryde  <kevin@swox.se>
+
+	* mpfr/tests/tdiv.c, mpfr/tests/tui_div.c: Don't depend on nan and inf
+	handling in "double", for the benefit of alpha.
+
+	* configure (hppa2.0w): Set path to "pa64w pa64".
+
+	* acinclude.m4, configure.in (GMP_C_INLINE): New macro.
+	* acinclude.m4 (GMP_H_EXTERN_INLINE): Use it, and fix "yes" handling.
+
+2002-03-25  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/pa64w/add_n.s: Remove.
+	* mpn/pa64w/sub_n.s: Remove.
+	* mpn/pa64w/lshift.s: Remove.
+	* mpn/pa64w/rshift.s: Remove.
+	* mpn/pa64w/mul_1.S: Remove.
+	* mpn/pa64w/addmul_1.S: Remove.
+	* mpn/pa64w/submul_1.S: Remove.
+	* mpn/pa64w/sqr_diagonal.asm: Remove.
+
+	* mpn/pa64/mul_1.asm: New file with twice faster code; generalized
+	for both 2.0N and 2.0W.
+	* mpn/pa64/submul_1.asm: Likewise.
+	* mpn/pa64/mul_1.S: Remove.
+	* mpn/pa64/submul_1.S: Remove.
+
+	* mpn/pa64/sqr_diagonal.asm: Generalize for both 2.0N and 2.0W.
+
+	* mpn/pa64/add_n.asm: New file, generalized for both 2.0N and 2.0W.
+	* mpn/pa64/sub_n.asm: Likewise.
+	* mpn/pa64/lshift.asm: Likewise.
+	* mpn/pa64/rshift.asm: Likewise.
+	* mpn/pa64/add_n.s: Remove.
+	* mpn/pa64/sub_n.s: Remove.
+	* mpn/pa64/lshift.s: Remove.
+	* mpn/pa64/rshift.s: Remove.
+
+2002-03-24  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-impl.h (BSWAP_LIMB_FETCH, BSWAP_LIMB_STORE): New macros.
+	* mpz/inp_raw.c, mpz/out_raw.c: Use them.
+	* acconfig.h (HAVE_HOST_CPU): Add some powerpc types.
+
+	* mpn/powerpc32/750/com_n.asm: New file.
+
+	* mpfr/tests/tout_str.c: Disable random tests, since they fail on
+	alphaev56-unknown-freebsd4.1 and do nothing by default.
+
+	* mpfr/tests/tsqrt.c: Don't depend on nan, inf or -0 in "double", for
+	the benefit of alpha.
+	* mpfr/sqrt.c: Clear nan flag on -0.
+
+	* demos/factorize.c: Use mpn_random() instead of random(), to avoid
+	portability problems.
+
+	* demos/isprime.c (print_usage_and_exit): Declare as "void" to avoid
+	warnings.
+
+	* demos/pexpr.c (setup_error_handler): Corrections to sigstack code.
+
+	* demos/calc/calc.y: Add some `;'s to make bison 1.34 happy.
+
+2002-03-23  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/pa64/addmul_1.asm: New file with twice faster code; generalized
+	for both 2.0N and 2.0W.
+
+2002-03-22  Kevin Ryde  <kevin@swox.se>
+
+	* tune/time.c: Add SGI hardware counter measuring method, change some
+	abort()s into ASSERT_FAIL()s.
+
+	* configure.in (AC_CHECK_HEADERS): Add fcntl.h and sys/syssgi.h.
+	(AC_CHECK_FUNCS): Add syssgi.
+
+	* configure.in, mpfr/Makefile.am, mpfr/tests/Makefile.am: Use
+	-mieee-with-inexact or -ieee_with_inexact for mpfr on alpha, so
+	denorms work.
+
+	* mpfr/isinteger.c: Fix a memory leak.
+
+2002-03-21  Torbjorn Granlund  <tege@swox.com>
+
+	* tune/speed.c (struct choice_t): Make `r' an mp_limb_t.
+
+2002-03-21  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (HAVE_LIMB_BIG_ENDIAN, HAVE_LIMB_LITTLE_ENDIAN): Use an
+	AH_VERBATIM and better explanation.
+	* acinclude.m4 (GMP_C_DOUBLE_FORMAT): Similarly for the HAVE_DOUBLE
+	constants.
+
+	* gmp.texi (Number Theoretic Functions): Clarify sign of GCD returned
+	by mpz_gcdext.
+
+	* demos/pexpr.c, demos/pexpr-config-h.in, configure.in: Use an
+	autoconf test for stack_t.
+
+	* configure.in, gmp-h.in, mp-h.in, macos/configure, tests/mpz/reuse.c,
+	tests/mpf/reuse.c: Use __GMP_LIBGMP_DLL to enable windows declspec,
+	don't require _WIN32 (etc), remove __GMP_LIBGMP_SHARED and
+	__GMP_LIBGMP_STATIC.
+
+	* gmp-impl.h (mp_bases): Add __GMP_DECLSPEC, for the benefit of
+	tests/t-constants.c.
+
+	* tune/many.pl, tune/speed.h: Remove suffix hack for back.asm.
+
+2002-03-21  Paul Zimmermann  <Paul.Zimmermann@loria.fr>
+
+	* mpfr/sin_cos.c (mpfr_sin_cos): New file.
+	* mpfr/mpfr.h, mpfr/mpfr.texi, mpfr/Makefile.am: Add it.
+	* mpfr/tan.c: Fix sign in 2nd and 4th quadrants.
+
+	* mpfr/log10.c: Fix hangs on certain inputs.
+
+2002-03-20  Torbjorn Granlund  <tege@swox.com>
+
+	* demos/pexpr.c (setup_error_handler): Declare `s', the first
+	sigaltstack parameter, using `stack_t' just on AIX.
+
+2002-03-19  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc32/mul_1.asm: Use free caller-saves registers instead
+	of the callee-saves r30 and r31.
+
+2002-03-19  Kevin Ryde  <kevin@swox.se>
+
+	* tune/freq.c (freq_proc_cpuinfo): Recognise powerpc "clock", where
+	previously got the wrong result from "bogomips".
+
+	* mpn/powerpc32/add_n.asm, mpn/powerpc32/sub_n.asm: Rewrite, faster on
+	750, and smaller too.
+	* mpn/powerpc32/*.asm: Use L(), add some measured speeds.
+
+	* longlong.h (count_trailing_zeros) [vax]: Add a version using ffs,
+	but commented out.
+
+2002-03-17  Kevin Ryde  <kevin@swox.se>
+
+	* tune/speed.c, tune/speed.h, tune/common.c, many.pl: Use optional
+	".r" to specify operand overlaps for mpn_add_n, mpn_sub_n and logops.
+	Remove mpn_add_n_inplace and mpn_add_n_self.
+	* tune/many.pl: Fix MULFUNC_PROLOGUE parsing.
+
+	* gmp.texi (Known Build Problems): Note `make' problem with long
+	libgmp.la dependencies list.
+
+	* printf/doprnt.c, scanf/doscan.c (%zn): Remove test of non-existent
+	HAVE_SIZE_T, just use size_t unconditionally.
+	* printf/doprnt.c (%zd etc): Fix 'z' type parsing.
+	* tests/misc/t-printf.c, tests/misc/t-scanf.c: More tests.
+
+	* configure.in: Use AC_COPYRIGHT.
+	Add m4_pattern_allow(GMP_MPARAM_H_SUGGEST).
+
+	* tune/Makefile.am (libdummy.la): Remove this, sqr_basecase.c already
+	gets an ansi2knr rule from nodist_tuneup_SOURCES.
+
+	* longlong.h (count_leading_zeros) [pentiumpro gcc<3]: Test
+	HAVE_HOST_CPU_i686 too.
+
+	* mpz/out_raw.c (HTON_LIMB_STORE): Fix a typo in big endian #if.
+
+2002-03-14  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/x86/pentium/com_n.asm, mpn/x86/pentium/logops_n.asm,
+	mpn/x86/k6/mmx/com_n.asm: Add nails support.
+
+	* texinfo.tex: Update to 2002-03-01.06 (per texinfo 4.1).
+	* gmp.texi (@ma): Remove, @math does this now.
+
+	* mpfr/tests/reuse.c: Clear op1 and op2 flags only in their respective
+	outer loops.
+
+	* configure.in (--enable-cxx): Correction to the default stated in the
+	help string.
+	(power*-*-aix*, not powerpc): Use aix.m4, don't run
+	GMP_ASM_POWERPC_R_REGISTERS or use powerpc-defs.m4.
+
+2002-03-13  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/sparc32/gmp-mparam.h: New file.
+
+2002-03-13  Kevin Ryde  <kevin@swox.se>
+
+	* demos/expr/exprfr.c: More mpfr functions, corrections to agm, cos,
+	sin, rename log2 constant to loge2 to make room for log2 function.
+	* demos/expr/t-expr.c: More tests.
+
+	* mpz/inp_raw.c (NTOH_LIMB_FETCH) [generic 16bit]: Remove spurious "+".
+
+	* mpfr/acos.c: Avoid a memory leak for certain operands.
+
+	* acinclude.m4, configure.in (GMP_C_DOUBLE_FORMAT): New macro.
+
+	* acinclude.m4 (GMP_HPC_HPPA_2_0, GMP_ASM_UNDERSCORE,
+	GMP_ASM_ALIGN_LOG, GMP_ASM_LSYM_PREFIX, GMP_ASM_W32, GMP_ASM_X86_MMX):
+	Change ac_objext to OBJEXT, which is the documented variable.
+
+	* config.guess (powerpc*-*-*): Use #ifdef on constants POWER_630 etc
+	in the AIX test, since old versions don't have them all.
+
+2002-03-11  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (LIBC211): New AC_DEFINE, for mpfr.
+
+	* configure.in (mips*-*-*): Support ABI=o32 on irix 6, allow gcc 2.7.2
+	to fall back on it, but detect it doesn't work with gcc 2.95.  Use
+	single mips-defs.m4 for both mips32 and mips64.
+	* acinclude.m4 (GMP_GCC_MIPS_O32): New macro.
+	* mpn/mips32/mips-defs.m4: Renamed from mips.m4.
+	* mpn/mips64/mips.m4: Remove (was a copy of mips32/mips.m4).
+
+	* mpn/powerpc32/750: New directory.
+	* configure.in (powerpc740, powerpc750, powerpc7400): Use it.
+	* mpn/powerpc32/750/gmp-mparam.h: New file.
+
+	* config.sub, gmp.texi (ultrasparc1): Remove this, just use plain
+	"ultrasparc".
+
+2002-03-10  Kevin Ryde  <kevin@swox.se>
+
+	* mpfr: Update to 20020301, except internal_ceil_exp2.c,
+	internal_ceil_log2.c, internal_floor_log2.c renamed to i_ceil_exp2.c,
+	i_ceil_log2.c, i_floor_log2.c to be unique in DOS 8.3.  And sqrtrem.c
+	removed since no longer required.
+	* mpfr/mpfr.texi: Fix some formatting.
+	* mpfr/tests/reuse.c: Patch by Paul to fix test4 variable handling.
+	* mpfr/sinh.c: Patch by Paul to fix err calculation when t==0.
+	* mpfr/tests/tget_d.c: Disable until portability of rnd_mode.c can be
+	sorted out.
+
+	* configure.in (powerpc*-*-*): Separate gcc and xlc cpu flags setups
+	for clarity.
+
+	* longlong.h (count_leading_zeros, count_trailing_zeros) [x86_64]: New
+	macros.
+
+2002-03-07  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi (Build Options): Note all the ultrasparcs accepted.
+	(Language Bindings): Add Math::BigInt::GMP.
+
+	* config.sub (ultrasparc2i): New cpu type.
+	* config.guess (sparc-*-*, sparc64-*-*): Add some exact CPU detection.
+
+2002-03-05  Kevin Ryde  <kevin@swox.se>
+
+	* longlong.h (count_leading_zeros, count_trailing_zeros) [alphaev67,
+	alphaev68]: Use ctlz and cttz insns (as per gcc longlong.h).
+	(count_leading_zeros) [sparclite]: Fix parameter order (as per gcc
+	longlong.h).
+	* acconfig.h (HAVE_HOST_CPU_alphaev68): New define.
+
+	* config.guess [i?86-*-*]: Suppress error messages if compiler not
+	found or test program won't run.
+	[rs6000-*-*, powerpc-*-*]: Force code alignment for mfpvr test.
+
+2002-03-04  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/pow_1.c: New file.
+
+2002-03-03  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi (Build Options): Note compiler must be able to fully link,
+	add alphapca57 and alphaev68, give a clearer example of MPN_PATH
+	(Debugging): Add notes on valgrind.
+	(C++ Formatted Output): Clarify mpf showbase handling, in particular
+	note "00.4" in octal.
+
+	* printf/doprntf.c: Do a showbase on octal float fractions, for
+	instance "00.4" where previously it gave "0.4".
+	* tests/cxx/t-ostream.cc: Update.
+
+	* gmp-h.in, mp-h.in (__GMP_DECLSPEC, __GMP_DECLSPEC_XX): Test
+	__WIN32__ for Borland C, reported by "delta trinity".
+
+	* gmp-h.in, mp-h.in: Use <cstddef> for size_t under C++, suggested by
+	Hans Aberg some time ago.
+	* gmp-h.in (<iosfwd>): Move to top of file for clarity.
+
+	* Makefile.am (libgmpxx_la_SOURCES): Use dummy.cc to force C++.
+	(CXX_OBJECTS): Add osfuns$U.lo.
+	* dummy.cc: New file.
+	* cxx/Makefile.am (INCLUDES): Use __GMP_WITHIN_GMPXX.
+	(libcxx_la_SOURCES): Add osfuns.cc.
+	* gmp-h.in (__GMP_DECLSPEC_XX): New define, use it on libgmpxx funs.
+	* gmp-impl.h: Add __GMP_DECLSPEC to libgmp functions used by libgmpxx.
+
+	* longlong.h (COUNT_TRAILING_ZEROS_TIME): Remove, no longer used.
+
+	* gmp-impl.h (MPN_SIZEINBASE, MPN_SIZEINBASE_16): Correction to
+	__totbits for nails.
+
+	* gmp-impl.h (JACOBI_LS0): Test size before limb, to pacify valgrind.
+	(JACOBI_0LS): Ditto, and fix parens around arguments.
+
+	* mpn/x86/x86-defs.m4 (call_mcount): Add a counter to make data labels
+	unique, since simplified L() scheme no longer gives that effect.
+	(notl_or_xorl_GMP_NUMB_MASK): New macro.
+	Add m4_assert_numargs in a few places.
+
+	* configure.in (*sparc*): Fix cycle counter setups for ABI=64.
+
+2002-02-28  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/vax/gmp-mparam.h: New file.
+
+2002-02-28  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-h.in (gmp_errno, gmp_version): Move into extern "C" block,
+	reported by librik@panix.com.
+
+	* gmp-h.in, mp-h.in (__GMP_DECLSPEC_EXPORT, __GMP_DECLSPEC_IMPORT):
+	Use __declspec(dllexport) and __declspec(dllimport) on Borland.
+	* gmp-h.in (_GMP_H_HAVE_FILE): Test __STDIO_H for Borland.
+	Reported by "delta trinity".
+
+	* gmp-impl.h (va_copy): Fall back on memcpy, not "=".
+
+	* mpn/generic/pre_mod_1.c: Add a comment about obsolescence.
+
+	* tune/time.c (MICROSECONDS_P): Don't trust time differences of 1
+	microsecond.
+
+	* tests/cxx/t-ostream.cc: Use "const char *" not just "char *" for
+	test data strings, avoids warnings on Sun CC.
+
+2002-02-27  Torbjorn Granlund  <tege@swox.com>
+
+	* configure.in: For sparc under solaris2.[7-9], pass -fsimple=1 to
+	disable some crazy -fast optimizations.
+
+2002-02-25  Torbjorn Granlund  <tege@swox.com>
+
+	* configure.in: For sparc under solaris2.[7-9], pass -fns=no to enable
+	denorm handling under -fast.
+
+2002-02-25  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (alpha*-*-*): Rearrange -mcpu selection for gcc,
+	provide an ev67 -> ev6 fallback.  Fix -arch,-tune selection for DEC C.
+	Allow ~ for space in optional options lists.
+
+	* tune/tuneup.c (tune_preinv_divrem_1): Compare against an assembler
+	mpn_divrem_1 if it exists, not the generic C mpn_divrem_1_div.
+	(tune_preinv_mod_1): Ditto with mpn_mod_1.
+
+	* tune/time.c (DIFF_SECS_ROUTINE): Eliminate the unused "type"
+	parameter, try to make the code a bit clearer.
+
+	* tune/freq.c: Reduce the period measured for cycles versus
+	gettimeofday, add cycles versus microsecond getrusage.
+
+	* mpz/array_init.c: "i" should be mp_size_t, noticed by E. Khong.
+
+2002-02-24  Torbjorn Granlund  <tege@swox.com>
+
+	* configure.in: For sparc under solaris2.[7-9], pass -fast instead of
+	other optimization options.
+
+2002-02-23  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/asm-defs.m4 (GMP_NUMB_MASK): New macro.
+	(PROLOGUE, EPILOGUE): Relax quoting for the benefit of tune/many.pl
+	when GSYM_PREFIX non-empty.
+
+	* tune/time.c, tune/speed.h (speed_time_init): Include clock tick
+	period in speed_time_string.
+	* tune/time.c, configure.in (clock_gettime): New measuring method.
+
+	* tune/many.pl: Add -DHAVE_NATIVE_mpn_foo to C objects, to avoid
+	conflicts with a macro version in gmp-impl.h, eg. mpn_com_n.
+
+2002-02-22  Torbjorn Granlund  <tege@swox.com>
+
+	* demos/pexpr.c: Increase RLIMIT_STACK to 4Mibyte.
+
+2002-02-22  Kevin Ryde  <kevin@swox.se>
+
+	* tune/tuneup.c: Don't confuse gcc with mipspro cc in diagnostic.
+
+2002-02-20  Torbjorn Granlund  <tege@swox.com>
+
+	* configure.in (mips*-*-irix[6789]*]): Set `extra_functions_n32', not
+	`extra_functions'.
+
+	* printf/doprnt.c: Conditionally include inttypes.h.
+	* printf/repl-vsnprintf.c: Likewise.
+	* scanf/doscan.c: Likewise.
+
+2002-02-20  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/x86/k7/mmx/com_n.asm: New file.
+
+	* mpz/n_pow_ui.c (SWAP_RP_TP): Use ASSERT_CODE on ralloc and talloc,
+	to ensure they needn't live past the initial allocs in a normal build.
+
+	* mpn/generic/mod_34lsub1.c: Note this is for internal use.
+
+2002-02-19  Torbjorn Granlund  <tege@swox.com>
+
+	* Clean up *_THRESHOLD names.  Many files affected.
+
+	* mpn/mips32: Asm-ify 32-bit mips code.
+	Move files from `mips2' to `mips32' directory.
+	* mpn/mips64: Move files from `mips3' to `mips64' directory.
+	* configure.in: Change `mips2' => `mips32' and `mips3' => `mips64'.
+
+2002-02-19  Kevin Ryde  <kevin@swox.se>
+
+	* acinclude.m4, configure.in (GMP_PROG_LEX): New macro.
+
+	* tune/tuneup.c (one): Start next threshold at a max of previous ones,
+	in order to get a good starting point for TOOM3_SQR_THRESHOLD if
+	KARATSUBA_SQR_THRESHOLD is 0 (ie. using mpn_mul_basecase only).
+
+	* configure.in, tune/tuneup.c (GMP_MPARAM_H_SUGGEST): New AC_DEFINE
+	replacing GMP_MPARAM_H_FILENAME.  Suggest a new file in a cpu specific
+	subdirectory rather than mpn/generic.
+
+	* acinclude.m4 (POWERPC64_PATTERN): New macro.
+	* configure.in (powerpc*-*-*): Use it.
+	(powerpc*-*-*): Use umul in 32L and aix64.
+	(mips*-*-*): Use umul, 32 and 64 bit versions.
+
+2002-02-18  Torbjorn Granlund  <tege@swox.com>
+
+	* longlong.h: Add basic x86-64 support.
+
+2002-02-17  Torbjorn Granlund  <tege@swox.com>
+
+	* demos/pexpr.c: Support `-X' for upper case hex, make `-x' output
+	lower case hex.
+
+	* mpn/mips2/umul.s: Make it actually work.
+	* mpn/mips3/umul.asm: New file.
+
+	* mpn/mips2/gmp-mparam.h: New file.
+
+2002-02-16  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/get_str.c (mpn_sb_get_str): Round frac upwards after
+	umul_ppmm calls.
+
+2002-02-16  Kevin Ryde  <kevin@swox.se>
+
+	* config.guess (alpha-*-*): Do alpha exact cpu probes on any system,
+	and only if configfsf.guess gives a plain "alpha".
+
+	* acinclude.m4 (GMP_PROG_CC_WORKS): Detect a gcc 3.0.3 powerpc64
+	linker invocation problem.
+
+2002-02-15  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/get_str.c (mpn_sb_get_str): For base 10, develop initial
+	digits using umul_ppmm, then switch to plain multiplication.
+
+	* config.guess: Rewrite Alpha subtype detection code for *bsd systems.
+
+2002-02-15  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi (Build Options): Note powerpc exact cpu types.
+	(Debugging): Advertise DEBUG in memory.c.
+
+	* config.sub, config.guess: Add some powerpc exact cpus.
+	* configure.in: Add configs for them.
+
+	* memory.c [__NeXT__]: Remove unused #define of "static".
+	(__gmp_default_allocate, __gmp_default_reallocate): Print size if
+	allocation fails, don't use perror.
+
+	* gmp-h.in: g++ 3 demands __GMP_NOTHROW is before other attributes.
+
+2002-02-14  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/alpha/mul_1.asm: Fix typo preventing build on T3E systems.
+
+2002-02-14  Kevin Ryde  <kevin@swox.se>
+
+	* tune/tuneup.c (tune_set_str): Increase max_size, for the benefit of
+	alpha.
+
+	* macos/README: Bug reports to bug-gmp@gnu.org, clarify MacOS X a bit.
+
+	* mpn/generic/gcdext.c [WANT_GCDEXT_ONE_STEP]: Add missing TMP_FREE.
+
+	* tune/speed.c, tune/tuneup.c: Allow for speed_cycletime of 0.0 in
+	some diagnostic printouts.
+	* tune/time.c (speed_cycletime): Note can be 0.0.
+
+2002-02-12  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/alpha/mul_1.asm: Add mpn_mul_1c entry.
+
+	* mpn/pa64w/sqr_diagonal.asm: Use L() for labels.
+
+2002-02-11  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/get_str.c (mpn_sb_get_str): Change declaration of rp to
+	accommodate tuneup compiles.
+
+2002-02-11  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/alpha/default.m4, mpn/alpha/unicos.m4 (PROLOGUE_cpu): Add
+	noalign option.
+	* mpn/alpha/default.m4 (PROLOGUE_cpu): use ALIGN instead of ".align".
+
+	* gmp.texi (Debugging): Notes on Checker.
+	(Other Multiplication): Move note on float FFTs to here.
+	(Assembler Floating Point): New text and revisions by Torbjorn,
+	picture formatting by me.
+	Simplify tex pictures elsewhere a bit, share heights, eliminate some
+	gaps at line joins.
+
+2002-02-11  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/get_str.c (mpn_sb_get_str): Rewrite to generate fraction
+	limbs and use multiplication for digit development.  Trim allocation of
+	buf.  Get rid of code for !USE_MULTILIMB.
+
+2002-02-10  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/set_str.c (mpn_set_str): Undo this:
+	Change invocations of mpn_add_1 to instead use mpn_incr_u.
+
+	* tests/mpz/convert.c: Free str only after it is used in error message.
+
+	* mpn/generic/get_str.c (mpn_sb_get_str): Combine tail code for base 10
+	and generic bases.
+
+	* mpn/mp_bases.c: Add entries for base 256.  Remove __ prefix from
+	table name.
+	* gmp-impl.h (__mp_bases): Remove superfluous mp_ part of name, making
+	it __gmpn_bases instead of __gmpn_mp_bases.
+	(mp_bases): New #define.
+	* tune/speed.h (SPEED_ROUTINE_MPN_SET_STR): Allow bases up to 256.
+	(SPEED_ROUTINE_MPN_GET_STR): Likewise.
+
+2002-02-09  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/set_str.c (mpn_set_str): Use mpn_mul_1c if available.
+	Change invocations of mpn_add_1 to instead use mpn_incr_u.
+
+2002-02-09  Kevin Ryde  <kevin@swox.se>
+
+	* mpz/array_init.c, mpz/cfdiv_q_2exp.c, mpz/cfdiv_r_2exp.c,
+	mpz/cong_2exp.c, mpz/divis_2exp.c, mpz/hamdist.c, mpz/init2.c,
+	mpz/mul_2exp.c, mpz/realloc2.c, mpz/scan0.c, mpz/scan1.c,
+	mpz/setbit.c, mpz/tdiv_q_2exp.c, mpz/tdiv_r_2exp.c, mpz/tstbit.c,
+	mpz/urandomb.c: Use GMP_NUMB_BITS.
+
+	* mpz/iset_str.c [__CHECKER__]: Store a dummy value to the low limb to
+	stop it appearing uninitialized.
+
+	* gmp-h.in (__GMP_NOTHROW): New macro.
+	(mp_set_memory_functions, mpz_cmp, mpz_cmp_si, mpz_cmp_ui, mpz_cmpabs,
+	mpz_cmpabs_ui, mpz_congruent_2exp_p, mpz_divisible_2exp_p,
+	mpz_fits_sint_p, mpz_fits_slong_p, mpz_fits_sshort_p, mpz_fits_uint_p,
+	mpz_fits_ulong_p, mpz_fits_ushort_p, mpz_get_si, mpz_get_ui,
+	mpz_getlimbn, mpz_hamdist, mpz_popcount, mpz_scan0, mpz_scan1,
+	mpz_size, mpz_sizeinbase, mpz_swap, mpz_tstbit, mpq_equal, mpq_swap,
+	mpf_cmp, mpf_cmp_si, mpf_cmp_ui, mpf_fits_sint_p, mpf_fits_slong_p,
+	mpf_fits_sshort_p, mpf_fits_uint_p, mpf_fits_ulong_p,
+	mpf_fits_ushort_p, mpf_get_default_prec, mpf_get_prec, mpf_get_si,
+	mpf_get_ui, mpf_integer_p, mpf_set_default_prec, mpf_set_prec_raw,
+	mpf_size, mpf_swap, mpn_add_1, mpn_cmp, mpn_hamdist, mpn_popcount,
+	mpn_sub_1): Use it.
+
+	* gmp-impl.h (MPN_SIZEINBASE, MPN_SIZEINBASE_16): New macros from
+	mpn_sizeinbase, and use GMP_NUMB_BITS.
+	* mpz/get_str.c, mpz/sizeinbase.c, mpbsd/mout.c, tune/speed.h: Use
+	MPN_SIZEINBASE.
+	* mpbsd/mtox.c: Use MPN_SIZEINBASE_16.
+
+	* configure.in, mpn/Makefile.am, gmp-impl.h (mpn_sizeinbase): Remove.
+	* mpn/generic/sizeinbase.c: Remove file.
+
+	* gmp-impl.h (MPN_GET_STR_SIZE): Remove.
+	* tests/mpn/t-g_str_size.c: Remove file.
+	* tests/mpn/Makefile.am: Update.
+
+	* Makefile.am (dist-hook): Don't distribute cvs merge ".#" files.
+
+2002-02-08  Torbjorn Granlund  <tege@swox.com>
+
+	* configure.in: Override extra_functions for all sparcv8 systems, not
+	just supersparc.
+
+2002-02-06  Kevin Ryde  <kevin@swox.se>
+
+	* tune/tuneup.c (tune_mul, tune_sqr): Disable FFTs until tuned.
+	* tune/speed.h (SPEED_ROUTINE_MPN_SET_STR): Fix memory clobber in
+	destination cache priming.
+
+	* printf/doprnt.c: Fix parsing of %s and %p conversions.
+	* tests/misc/t-printf.c (check_misc): Add some tests.
+
+2002-02-03  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/sparc32/v8/udiv.asm: New file, from v8/supersparc.
+
+	* mpn/generic/set_str.c: Rename indigits_per_limb => chars_per_limb.
+	Remove redundant chars_per_limb.  Reverse 4 loops in basecase code for
+	speed.  Use MP_BASES_CHARS_PER_LIMB_10.
+
+2002-02-03  Kevin Ryde  <kevin@swox.se>
+
+	* acinclude.m4 (GMP_PROG_NM): Ensure -B or -p get used when doing a
+	cross compile with the native nm, helps OSF for instance.
+	(GMP_ASM_LSYM_PREFIX): Remove ".byte 0" for the benefit of irix 6,
+	allow "N" from nm for OSF, allow for "t" for other systems, but prefer
+	no mention of the symbol at all.
+
+	* tune/tuneup.c (print_define_remark): New function.
+	Turn some "#if"s into plain "if"s.
+
+	* tune/tuneup.c, gmp-impl.h, tune/Makefile.am
+	(GET_STR_BASECASE_THRESHOLD, GET_STR_PRECOMPUTE_THRESHOLD): Tune these.
+	* mpn/generic/get_str.c [TUNE_PROGRAM_BUILD]: Cope with non-constant
+	GET_STR_PRECOMPUTE_THRESHOLD.
+
+2002-02-02  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/get_str.c (mpn_get_str): Fix typo in a declaration.
+
+2002-02-02  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/generic/set_str.c: Use MP_PTR_SWAP and POW2_P, add __GMP_PROTO
+	to convert_blocks prototype, disable SET_STR_BLOCK_SIZE sanity check.
+
+	* tune/set_strb.c, tune/set_strs.c: New files.
+	* tune/speed.h, tune/speed.c, tune/common.c,tune/Makefile.am: Add them.
+	* tune/tuneup.c: Tune SET_STR_THRESHOLD.
+	(DEFAULT_MAX_SIZE): Renamed from MAX_SIZE, allow any param.max_size[].
+
+2002-02-01  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/mpz/convert.c: Increase operand size.  Add (yet disabled) code
+	for testing with random strings.
+
+	* mpn/generic/get_str.c (mpn_get_str): Rewrite to become sub-quadratic.
+	(mpn_dc_get_str, mpn_sb_get_str): New functions.
+
+2002-01-31  Kevin Ryde  <kevin@swox.se>
+
+	* gmpxx.h (cmp): Renamed from "compare".
+
+	* configure.in (AC_C_BIGENDIAN): Don't abort when cross compiling.
+	(PROLOGUE): Allow new style optional second parameter when grepping.
+
+	* acinclude.m4 (GMP_HPC_HPPA_2_0, GMP_ASM_UNDERSCORE,
+	GMP_ASM_ALIGN_LOG, GMP_ASM_LSYM_PREFIX, GMP_ASM_W32, GMP_ASM_X86_MMX):
+	Use $ac_objext for object filenames.
+	(GMP_ASM_UNDERSCORE): Use CCAS to assemble.
+
+	* demos/pexpr-config-h.in: New file.
+	* configure.in: Generate demos/pexpr-config.h.
+	(AC_CHECK_FUNCS): Add clock, cputime, setrlimit, sigaction,
+	sigaltstack, sigstack.
+	* acinclude.m4 (GMP_SUBST_CHECK_FUNCS, GMP_SUBST_CHECK_HEADERS): New
+	macros.
+	* demos/pexpr.c: Use pexpr-config.h, not various #ifdefs.
+	(setup_error_handler): Use signal if sigaction not available, allow
+	for SIGBUS missing on mingw.
+	(main): Use time() for random seed if gettimeofday not available.
+	(cleanup_and_exit): Move SIGFPE out of LIMIT_RESOURCE_USAGE.
+
+2002-01-30  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/set_str.c: Rewrite to become sub-quadratic.
+	(convert_blocks): New function.
+
+2002-01-30  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-impl.h (GMP_NUMB_MASK, GMP_NAIL_MASK, GMP_NUMB_HIGHBIT,
+	ASSERT_MPN, ASSERT_MP_LIMB_T): New macros.
+
+	* mpn/generic/fib2_ui.c: Use GMP_NUMB_BITS, simplify the data
+	generator program, share __gmp_fib_table initializers between bit
+	sizes, cope with bit sizes other than those specifically setup.
+	* gmp-impl.h (FIB_TABLE_LIMIT, FIB_TABLE_LUCNUM_LIMIT): Corresponding
+	rearrangement of conditionals.
+	* tests/mpz/t-fib_ui.c (check_fib_table): New test.
+
+2002-01-28  Kevin Ryde  <kevin@swox.se>
+
+	* mpz/set_si.c, mpz/iset_si.c: Store to _mp_d[0] unconditionally, use
+	an expression for _mp_size.
+
+	* mpz/init.c, mpz/init2.c, mpz/iset.c, mpq/init.c [__CHECKER__]: Store
+	dummy values to low limbs to stop them appearing uninitialized.
+
+2002-01-26  Kevin Ryde  <kevin@swox.se>
+
+	* mpfr/mpfr-test.h (MAX, MIN, ABS): Use instead a patch from Paul and
+	Vincent.
+
+2002-01-24  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in: Extra quoting to get argument help messages right.
+
+	* gmp.texi (Efficiency): Suggest hex or octal for input and output.
+	(Formatted Output Strings): Mention "*" for width and precision.
+
+	* mpn/generic/sizeinbase.c: New file, adapted from mpz/sizeinbase.c.
+	Use POW2_P, use __mp_bases[base].big_base for log2(base).
+	* configure.in, mpn/Makefile.am: Add it.
+	* gmp-impl.h: Add prototype.
+	* mpz/sizeinbase.c, tune/speed.h, mpn/generic/get_str.c,
+	mpz/get_str.c, mpbsd/mout.c, mpbsd/mtox.c: Use it.
+	* mpz/get_str.c: Write directly to user buffer, skip at most one
+	leading zero, eliminate special case for x==0.
+	* mpbsd/mtox.c: Allocate exact result space at the start, eliminate
+	special case for x==0.
+	* mpbsd/mout.c: Only need to skip one high zero with mpn_sizeinbase.
+
+	* configure.in (--enable-nails): New option.
+	(GMP_NAIL_BITS, GMP_LIMB_BITS, GMP_NUMB_BITS): New defines for gmp.h
+	and config.m4.
+	* gmp-h.in: Add templates.
+
+	* mpfr/mpfr-test.h (MAX, MIN, ABS): Use #ifndef to avoid a redefine
+	error on AIX xlc.
+
+2002-01-23  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/get_str.c: Correct type of `out_len'.
+
+2002-01-22  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/generic/pre_divrem_1.c: Corrections to some ASSERTs.
+
+	* mpfr/mul_ui.c: Don't call mpn_lshift with 0 shift.
+
+	* mpfr/mpz_set_fr.c: Produce correct mpz_t for f==0.
+
+2002-01-21  Torbjorn Granlund  <tege@swox.com>
+
+	* longlong.h (32-bit powerpc add_ssaaaa): Remove spurious commutative
+	declaration.
+	(64-bit powerpc add_ssaaaa): Likewise.
+
+2002-01-20  Kevin Ryde  <kevin@swox.se>
+
+	* acinclude.m4 (GMP_FUNC_VSNPRINTF): Use %n to better detect sparc
+	solaris 2.7 problems.
+
+2002-01-19  Torbjorn Granlund  <tege@swox.com>
+
+	* demos/pexpr.c (mpz_eval_expr): Optimize s^rhs for -1 <= s <= 1.
+	(cleanup_and_exit): Improve error message wording.
+
+2002-01-19  Kevin Ryde  <kevin@swox.se>
+
+	* mpfr/mpfr.h (_PROTO): Use __GMP_PROTO, for compatibility with
+	gmp-impl.h.
+
+2002-01-17  Torbjorn Granlund  <tege@swox.com>
+
+	* mpfr/mpfr-test.h: Test "__hpux", not "hpux".  Mask off mrand48
+	return value to 31 bits to work around sloppy mpfr #include practices.
+
+	* mpfr/tests/*.c: Use #include "", not <>, for gmp.h and mpfr.h.
+	Make sure to #include mpfr-test.h from all files that use random().
+
+2002-01-17  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-impl.h (__GMP_REALLOCATE_FUNC_MAYBE_TYPE): New macro.
+	* gmp-impl.h, mpz/get_str.c, mpz/out_raw.c, mpq/get_str.c,
+	mpq/set_str.c, mpf/get_str.c, printf/asprntffuns.c, printf/doprnt.c,
+	printf/repl-vsnprintf.c, printf/snprntffuns.c, scanf/doscan.c,
+	mpbsd/mtox.c: Some fixes to compile as C++.
+
+	* mpn/generic/jacbase.c (JACOBI_BASE_METHOD): New tuned parameter,
+	replacing COUNT_TRAILING_ZEROS_TIME test.  Add a third method too.
+	* tune/speed.c, tune/speed.h, tune/common.c, tune/Makefile.am: Add
+	measuring of mpn_jacobi_base methods.
+	* tune/jacbase1.c, tune/jacbase2.c, tune/jacbase3.c: New files.
+	* tune/tuneup.c (JACOBI_BASE_METHOD): Tune this.
+	* mpn/x86/*/gmp-mparam.h (COUNT_TRAILING_ZEROS_TIME): Remove macro.
+
+	* gmp-h.in: Use __gmp prefix on variables in inlines.
+
+	* gmp-impl.h (MPN_COPY_INCR, MPN_COPY_DECR): Remove __i, unused.
+
+	* mpn/generic/mul_fft.c: Use HAVE_NATIVE_mpn_addsub_n, not ADDSUB.
+	Use CNST_LIMB for some constants.
+
+2002-01-15  Kevin Ryde  <kevin@swox.se>
+
+	* tests/mpbsd/Makefile.am: Add a convenience rule for ../libtests.la.
+
+	* printf/Makefile.am: libdummy.la should be in EXTRA_LTLIBRARIES.
+
+	* mpf/out_str.c: Use MPF_SIGNIFICANT_DIGITS, so mpf_out_str and
+	mpf_get_str give the same for ndigits==0.
+
+	* mpfr/exceptions.c (mpfr_set_emin, mpfr_set_emax): Work around a
+	powerpc64 gcc 3.0 -O2 bug.
+
+	* tests/memory.c, tests/tests.h (tests_memory_validate): New function.
+
+2002-01-14  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/generic/sb_divrem_mn.c, mpn/generic/divrem_1.c,
+	mpn/generic/divrem_2.c, mpn/generic/mod_1.c: Don't use UMUL_TIME and
+	UDIV_TIME, just default to preinv.
+	* gmp-impl.h (USE_PREINV_DIVREM_1, USE_PREINV_MOD_1): Ditto.
+	(DIVEXACT_1_THRESHOLD, MODEXACT_1_ODD_THRESHOLD): Don't use UMUL_TIME
+	and UDIV_TIME, make default thresholds 0.
+	(UDIV_NORM_PREINV_TIME, UDIV_UNNORM_PREINV_TIME): Remove macros.
+	* mpn/x86/*/gmp-mparam.h (UMUL_TIME, UDIV_TIME,
+	UDIV_NORM_PREINV_TIME): Remove macros.
+
+	* gmp.texi (Headers and Libraries): New section, being the header
+	notes from "GMP Basics" and some new stuff.
+	(Parameter Conventions): Notes on "const" parameters.
+	(Formatted Output Strings): Add type N, tweak some wording.
+
+	* tests/refmpn.c (refmpn_divmod_1c): Avoid a bug in i386 gcc 3.0.
+
+2002-01-12  Kevin Ryde  <kevin@swox.se>
+
+	* mpz/root.c: Add <stdlib.h>, for abort().
+
+	* mpfr/tests/Makefile.am (AUTOMAKE_OPTIONS): Add ansi2knr.
+	* mpfr/mpfr.h, mpfr/mpfr-tests.h, reuse.c, tadd.c, tadd_ui.c, tagm.c,
+	tatan.c, tcmp2.c, tcos.c, tdiv.c, tdiv_ui.c, teq.c, texp.c,
+	tget_str.c, thyperbolic.c, tlog.c, tmul.c, tout_str.c, tpow.c,
+	trandom.c, tset_z.c, tsin.c, tsqrt.c, tsqrt_ui.c, tsub_ui.c, ttan.c,
+	tui_div.c: Fixes for K&R.
+
+	* tests/misc/t-scanf.c (check_misc, check_misc):
+
+	* tests/mpz/t-inp_str.c, tests/mpq/t-inp_str.c, tests/misc/t-scanf.c:
+	Avoid strings in ASSERT, not enjoyed by K&R.
+	* gmp-impl.h (ASSERT): Note this.
+
+	* tests/tests.h (refmpn_mod_34lsub1): Add __GMP_PROTO.
+
+	* mpbsd/Makefile.am: Avoid an automake problem with ansi2knr and
+	sources in a different directory.
+
+	* printf/repl-vsnprintf.c: Test HAVE_LONG_DOUBLE for long double.
+
+	* mpn/Makefile.am (nodist_libdummy_la_SOURCES): Add mod_34lsub1.c,
+	mul_2.c, pre_divrem_1.c.
+
+	* gmp-h.in, gmp-impl.h (mpn_add_nc, mpn_addmul_1c, mpn_addsub_n,
+	mpn_addsub_nc, mpn_divrem_1c, mpn_dump, mpn_mod_1c, mpn_mul_1c,
+	mpn_mul_basecase, mpn_sqr_n, mpn_sqr_basecase, mpn_sub_nc,
+	mpn_submul_1c): Move to gmp-impl.h, since they're undocumented.
+
+	* gmp-impl.h (mpn_reciprocal): Remove, unused.
+
+	* tune/many.pl (cntlz, cnttz): Use new SPEED_ROUTINE_COUNT_ZEROS.
+
+2002-01-11  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/hppa/*.asm, mpn/pa64/*.asm, mpn/pa64w/*.asm: Use L().
+
+2002-01-08  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/asm-defs.m4 (PROLOGUE, EPILOGUE): New scheme, optional function
+	name to EPILOGUE, check for missing or wrong function name EPILOGUE.
+	* mpn/alpha/unicos.m4, mpn/alpha/default.m4, mpn/m68k/m68k-defs.m4,
+	mpn/mips3/mips.m4, mpn/ia64/default.m4, mpn/powerpc32/aix.m4,
+	mpn/powerpc64/aix.m4, mpn/x86/x86-defs.m4: Consequent updates, add a
+	few more asserts.
+	* mpn/alpha/unicos.m4, mpn/alpha/default.m4, mpn/alpha/cntlz.asm,
+	mpn/alpha/invert_limb.asm (PROLOGUE_GP): Change to an optional "gp"
+	parameter on plain PROLOGUE.
+
+	* gmp.texi (Low-level Functions): mpn_get_str doesn't clobber an extra
+	limb, and doesn't clobber at all for power of 2 bases.
+	(Language Bindings): Add python gmpy.
+
+	* mpz/get_str.c: Determine realloc size arithmetically.
+
+	* mpbsd/mtox.c: Size memory block returned to actual space needed.
+	* gmp.texi (BSD Compatible Functions): Describe this.
+
+	* mpz/get_str.c: Don't copy mpn_get_str input for power of 2 bases.
+	* mpbsd/mtox.c: Ditto, and as a side effect avoid a memory leak from a
+	missing TMP_FREE.
+
+	* mpz/get_str.c, mpbsd/mout.c: No longer need for +1 limb for
+	mpn_get_str clobber.
+
+	* gmp-impl.h (MPN_GET_STR_SIZE): New macro.
+	* mpn/generic/get_str.c, mpz/get_str.c, mpbsd/mout.c, mpbsd/mtox.c,
+	tune/speed.h: Use it.
+	* tests/mpn/t-g_str_size.c: New test.
+	* tests/mpn/Makefile.am: Add it.
+
+	* gmp-impl.h (POW2_P): New macro.
+	* mpn/generic/get_str.c, tests/misc.c: Use it.
+
+	* printf/doprnt.c: Add "N" for mpn, share some code between N, Q and Z.
+	* tests/misc/t-printf.c: Add tests.
+	* gmp-impl.h (ASSERT_CODE): New macro.
+
+	* tests/mpbsd/t-mtox.c: New test.
+	* tests/mpbsd/Makefile.am: Add it.
+	(allfuns_LDADD): Don't link against libgmp when testing everything in
+	libmp can link.
+
+2002-01-07  Torbjorn Granlund  <tege@swox.com>
+
+	* gmp-impl.h (MPN_COPY_INCR, MPN_COPY_DECR): Rewrite generic versions.
+
+2002-01-06  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/generic/pre_divrem_1.c: Don't support size==0.
+	* tests/devel/try.c: Update.
+
+	* mpn/generic/get_str.c: Add special case for base==10.
+	* gmp-impl.h (MP_BASES_CHARS_PER_LIMB_10, MP_BASES_BIG_BASE_10,
+	MP_BASES_BIG_BASE_INVERTED_10, MP_BASES_NORMALIZATION_STEPS_10): New
+	constants.
+	* tests/t-constants.c: Add checks.
+	* mpn/mp_bases.c [GENERATE_TABLE]: Print defines for gmp-impl.h, print
+	all standard bits-per-limb by default.
+
+	* demos/pexpr.c, demos/expr/expr.h, demos/expr/expr-impl.h: Use
+	__GMP_PROTO.
+
+	* gmp-h.in (mpn_divexact_by3c): Remove variables from prototype, to
+	keep out of application namespace.
+
+2002-01-04  Torbjorn Granlund  <tege@swox.com>
+
+	* gmp-impl.h: Move _PROTO declaration to before its first usages.
+
+2002-01-04  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-h.in, mp-h.in, tests/tests.h: Rename _PROTO to __GMP_PROTO, and
+	don't use #ifndef just define it ourselves.
+	* gmp-impl.h: Provide _PROTO as an alias for __GMP_PROTO, to avoid big
+	edits internally, for the moment.
+
+2002-01-03  Torbjorn Granlund  <tege@swox.com>
+
+	* tune/speed.c (usage): Insert "\n\" into a string.
+
+2001-12-30  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/pa64/udiv_qrnnd.c: Remove file.
+	* mpn/pa64w/udiv_qrnnd.c: Remove file.
+
+	* gmp-impl.h (MPN_IORD_U): Change formatting (labels in pos 0, insns
+	indented by tab).
+	(MPN_INCR_U): Use "addl $1,foo; jc", not "incl foo; jz".
+
+	* gmp-impl.h (udiv_qrnnd_preinv): Use plain subtract, not sub_ddmmss,
+	in one more case.
+
+2001-12-30  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/generic/get_str.c (udiv_qrnd_unnorm): New macro.
+	Use "do while" for dig_per_u loop since it's non-zero.
+	* acconfig.h (HAVE_HOST_CPU_m68k etc): Add templates.
+
+	* mpn/generic/mul_basecase.c, mpz/mul.c, mpz/n_pow_ui.c,
+	mpn/x86/pentium/mul_2.asm, tests/devel/try.c, tests/tests.h,
+	tests/refmpn.c, tune/speed.c, tune/speed.h, tune/common.c,
+	tune/many.pl (mpn_mul_2): New parameter style.
+	* gmp-impl.h (mpn_mul_2): Add prototype.
+	* configure.in (gmp_mpn_functions_optional): Add mul_2.
+
+	* longlong.h (__vxworks__): Remove from powerpc tests, not correct,
+	not on its own at least.
+
+	* tune/speed.c: Add "aas" to specify 0xAA..AA data.
+
+	* tune/tuneup.c (print_define_end): Indicate "never" and "always".
+
+2001-12-29  Torbjorn Granlund  <tege@swox.com>
+
+	* mpq/set_d.c: ANSI-fy.
+	* mpz/invert.c: Use PTR and SIZ (cosmetic change).
+
+	* mpz/cong.c: Rename `xor' to `sign' to avoid C++ reserved word.
+
+2001-12-28  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/sparc64/sqr_diagonal.asm: New file.
+
+2001-12-28  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/generic/get_str.c: Avoid one mpn_divrem_1 by running main loop
+	only until msize==1.
+
+	* tune/tuneup.c: Break up all() for clarity.
+	(USE_PREINV_DIVREM_1, USE_PREINV_MOD_1): Compare against plain
+	division udiv_qrnnd, not the tuned and possibly preinv version.
+
+	* tune/freq.c: Split sysctl and sysctlbyname probes into separate
+	functions, shorten some identifiers, put descriptions inside
+	functions, define functions unconditionally and do nothing if
+	requisites not available.
+
+	* mpz/inp_raw.c: Avoid a gcc 3.0 powerpc64 bug on AIX.
+
+	* acinclude.m4, configure.in (GMP_C_RESTRICT): New macro.
+
+	* mpfr/sin.c: Patch from Paul to fix sign of sin(3pi/2).
+
+	* demos/calc/calc.y: Improve some error messages.
+
+2001-12-28  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/sparc64/mul_1.asm: Rename r72 -> r80.
+	* mpn/sparc64/addmul_1.asm: Likewise.
+
+2001-12-27  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/tdiv_qr.c: Misc formatting cleanups.
+	For switch case 2, replace `dn' with its value (2).
+
+2001-12-25  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/devel/mul_1.c: Add FIXED_XLIMB.
+	* tests/devel/addmul_1.c: Likewise.
+	* tests/devel/submul_1.c: Likewise.
+
+	* tests/devel/add_n.c: Improve error message.
+	Accept command line argument for # of tests.
+	* tests/devel/sub_n.c: Likewise.
+
+	* tests/devel/: Remove CLOCK settings.
+
+	* mpn/sparc32/v9/mul_1.asm: Rewrite.
+	* mpn/sparc32/v9/addmul_1.asm: Rewrite.
+	* mpn/sparc32/v9/submul_1.asm: Rewrite.
+
+2001-12-24  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/sparc64/mul_1.asm: Get rid of global constant 0.0 (L(noll)).
+	* mpn/sparc64/addmul_1.asm: Likewise.
+
+2001-12-23  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/get_str.c: Move final ASSERT to just before zero fill
+	loop.
+
+2001-12-22  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/get_str.c: Move ASSERTs out of loops.  Split digit
+	generation code into two loops, saving a test of msize in the loop.
+
+2001-12-22  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/x86/x86-defs.m4, mpn/x86/*/*.asm: Remove L / LF scheme putting
+	function name in local labels.
+
+	* mpn/generic/get_str.c: Use mpn_preinv_divrem_1, add a couple of
+	ASSERTs.
+
+	* mpn/generic/pre_divrem_1.c: New file.
+	* configure.in (gmp_mpn_functions): Add it.
+	* gmp-impl.h (mpn_preinv_divrem_1): Add prototype.
+	(USE_PREINV_DIVREM_1, MPN_DIVREM_OR_PREINV_DIVREM_1): New macros.
+	* tests/devel/try.c, tune/speed.c, tune/speed.h, tune/common.c,
+	tune/many.pl, tune/Makefile.am (mpn_preinv_divrem_1): Add testing and
+	measuring.
+	* tune/tuneup.c: Determine USE_PREINV_DIVREM_1.
+	* tune/pre_divrem_1.c: New file.
+	* tests/refmpn.c, tests/tests.h (refmpn_preinv_divrem_1): New function.
+
+	* tests/mpz/t-io_raw.c: New file.
+	* tests/mpz/Makefile.am (check_PROGRAMS): Add it.
+
+	* mpz/inp_raw.c, mpz/out_raw.c: Rewrite.
+	* acinclude.m4, configure.in (AC_C_BIGENDIAN): New test.
+	* gmp-impl.h (BSWAP_LIMB): New macro.
+
+	* acinclude.m4 (GMP_PROG_CC_WORKS): For a native compile, demand
+	executables will run, per AC_PROG_CC.  This detects ABI=64 is unusable
+	in a native sparc solaris 7 build with the kernel in 32-bit mode.
+	* gmp.texi (ABI and ISA): Add notes on this, add an example configure
+	setting an ABI.
+
+	* tune/tuneup.c, configure.in: Print the gmp-mparam.h filename.
+	* tune/tuneup.c: Print the CPU frequency.
+
+	* tune/time.c, tune/speed.h: Add s390 "stck" method, flatten
+	conditionals in speed_time_init a bit, use have_* variables to let
+	some code go dead in speed_starttime and speed_endtime.
+
+	* tune/freq.c (speed_cpu_frequency_irix_hinv): New function.
+
+	* Makefile.am, configure.in: Restore mpfr.
+
+	* configure.in: Add --with-readline, AC_PROG_YACC and AM_PROG_LEX.
+	* demos/calc/calc.y, demos/calc/calclex.l: Add readline support, add
+	lucnum function.
+	* demos/calc/Makefile.am: Add calcread.c, calc-common.h, use $(YACC),
+	$(LEX) and $(LEXLIB).
+	* demos/calc/calcread.c, demos/calc/calc-common.h,
+	demos/calc/calc-config-h.in, demos/calc/README: New files.
+
+	* configure.in: Put demos/expr configs in expr-config.h.
+	* demos/expr/expr-config-h.in: New file.
+	* demos/expr/expr-impl.h: Renamed from expr-impl-h.in, get configs
+	from expr-config.h.
+	* demos/expr/Makefile.am: Update.
+
+	* demos/expr/exprfr.c: Use mpfr_sin and mpfr_cos, remove some spurious
+	returns.
+
+2001-12-20  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/sparc64/mul_1.asm: Trim an instruction.
+	* mpn/sparc64/addmul_1.asm: Likewise.
+
+	* mpn/ia64/add_n.asm: Rewrite.
+	* mpn/ia64/sub_n.asm: Rewrite.
+
+2001-12-19  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/ia64/mul_1.asm: Rewrite.
+	* mpn/ia64/addmul_1.asm: Rewrite.
+	* mpn/ia64/submul_1.c: Use TMP_ALLOC_LIMBS.
+
+	* tests/devel/mul_1.c: Improve error message.
+	Accept command line argument for # of tests.
+	* tests/devel/addmul_1.c: Likewise.
+	* tests/devel/submul_1.c: Likewise.
+
+2001-12-18  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/mips3/mul_1.asm: Add NOPs to save a cycle on R1x000.
+
+2001-12-18  Kevin Ryde  <kevin@swox.se>
+
+	* gmpxx.h (gmp_randclass): Don't allow copy constructors or "=",
+	implementation by Gerardo.
+
+	* gmp-h.in (operator<<, operator>>): Remove parameter names from
+	prototypes, to keep out of user namespace.
+
+	* acinclude.m4 (GMP_FUNC_VSNPRINTF): Let the test program work as C++.
+
+2001-12-16  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/sparc64/mul_1.asm: Rewrite.
+	* mpn/sparc64/addmul_1.asm: Rewrite.
+	* mpn/sparc64/submul_1.asm: Rewrite.
+
+	* mpn/sparc64/addmul1h.asm: Remove.
+	* mpn/sparc64/submul1h.asm: Remove.
+	* mpn/sparc64/mul1h.asm: Remove.
+
+2001-12-15  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-h.in (mpn_add, mpn_add_1, mpn_cmp, mpn_sub, mpn_sub_1): Follow
+	__GMP_INLINE_PROTOTYPES for whether to give prototype with inline.
+
+	* configure.in (i686*-*-*, pentiumpro-*-*, pentium[23]-*-*,
+	athlon-*-*, pentium4-*-*): Fall back on -march=pentium if
+	-march=pentiumpro or higher is not good (eg. solaris cmov).
+
+2001-12-12  Torbjorn Granlund  <tege@swox.com>
+
+	* gmp-impl.h (MPN_ZERO): Rewrite generic version to be similar to
+	powerpc version.
+
+2001-12-12  Kevin Ryde  <kevin@swox.se>
+
+	* acinclude.m4 (GMP_PROG_CC_WORKS): Detect cmov problems with gcc
+	-march=pentiumpro on solaris 2.8.
+
+	* tune/common.c, tune/speed.h: Allow for commas in count_leading_zeros
+	and count_trailing_zeros macros.
+
+	* demos/expr/Makefile.am: Distribute exprfr.c and exprfra.c.
+
+	* tune/Makefile.am (speed_ext_SOURCES): Should be speed-ext.c.
+
+2001-12-10  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/s390/addmul_1.asm: New file.
+	* mpn/s390/submul_1.asm: New file.
+	* mpn/s390/mul_1.asm: New file.
+	* mpn/s390/gmp-mparam.h: Update.
+
+2001-12-07  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-h.in, mp-h.in, gmp-impl.h: __GMP_DECLSPEC at start of
+	prototypes, for the benefit of Microsoft C.
+
+	* gmp.texi (Introduction to GMP): Mention ABI and ISA section.
+	(Known Build Problems): Recommend GNU sed on solaris 2.6.
+	(Assigning Integers): Direct feedback to bug-gmp.
+	(References): Typo Knuth vol 2 is from 1998.
+
+	* gmpxx.h (gmp_randclass): Add initializers for gmp_randinit_default
+	and gmp_randinit_lc_2exp_size.
+	gmp.texi (C++ Interface Random Numbers): Describe them.
+
+	* tests/misc/t-locale.c, tests/cxx/t-locale.cc: Ensure mpf_clear is
+	done when the localconv override doesn't work.  Reported by Mike
+	Jetzer.
+
+	* printf/doprnti.c: Don't showbase on a zero mpq denominator.
+	* tests/misc/t-printf.c, tests/cxx/t-ostream.c: Add test cases.
+
+2001-12-04  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi (Known Build Problems): Update to gmp_randinit_lc_2exp_size
+	for the sparc solaris 2.7 problem.
+	(Reentrancy): SCO ctype.h affects all text-based input functions.
+	(Formatted Output Strings): Correction to the mpf example.
+	(Single Limb Division): Correction, should be q-1 not q+1.
+	(Extended GCD): Clarify why single-limb is inferior.
+	(Raw Output Internals): Clarify size is twos complement, note limb
+	order means _mp_d doesn't get directly read or written.
+	(Contributors): Clarify mpz_jacobi.
+	And a couple of formatting tweaks elsewhere.
+
+	* tests/cxx/t-headers.cc: New file.
+	* tests/cxx/Makefile.am: Add it.
+
+	* gmpxx.h: Add <strstream>, needed by mpf_class::get_str2.
+
+	* gmp-h.in (mpq_inp_str, mpn_hamdist): Add __GMP_DECLSPEC.
+
+2001-12-01  Torbjorn Granlund  <tege@swox.com>
+
+	* Version 4.0 released.
+
+	* mpfr/README: Replace contents with explanation of why mpfr is gone.
+
+2001-12-01  Kevin Ryde  <kevin@swox.se>
+
+	* Makefile.am, configure.in: Temporarily remove mpfr, just leave a
+	README.
+
+	* mpn/Makefile.am (EXTRA_DIST): Add Makeasm.am.
+
+2001-11-30  Gerardo Ballabio  <ballabio@sissa.it>
+
+	* tests/cxx/t-constr.cc, tests/cxx/t-expr.cc: New files.
+	* tests/cxx/Makefile.am (check_PROGRAMS): Add them.
+
+2001-11-30  Kevin Ryde  <kevin@swox.se>
+
+	* mpfr: Update to 2001-11-16.  Patch TMP handling of agm.c and sqrt.c,
+	use plain mpn_sqrtrem in sqrt.c, separate .c files for floor and ceil,
+	disable an expression style assert in add1.c.
+
+	* mpn/s370: Rename to s390.
+	* configure.in (s3[6-9]0*-*-*): Update.
+	* mpn/Makefile.am (TARG_DIST): Add s390.
+
+	* mpz/fits_s.c, mpf/fits_s.c, mpf/fits_u.c: Remove files, unused since
+	change to .h style.
+
+2001-11-29  Torbjorn Granlund  <tege@swox.com>
+
+	* gmp-h.in: Declare mpz_get_d_2exp and mpf_get_d_2exp.
+	* Makefile.am: Add mpz/get_d_2exp$U.lo and mpf/get_d_2exp$U.lo.
+	* mpf/Makefile.am: Add get_d_2exp.c.
+	* mpz/Makefile.am: Add get_d_2exp.c.
+
+2001-11-29  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/*/gmp-mparam.h: Update measured thresholds.
+	* mpn/s370/gmp-mparam.h: New file.
+
+	* mpz/millerrabin.c: Mark for internal use only, for now.
+	* gmp.texi (Number Theoretic Functions): Remove documentation.
+
+2001-11-28  Torbjorn Granlund  <tege@swox.com>
+
+	* mpf/get_d_2exp.c: New file.
+	* mpz/get_d_2exp.c: New file.
+
+	* mpz/realloc2.c: Fix typo.  Make more similar to mpz_realloc.
+	* mpz/realloc.c: Use __GMP_REALLOCATE_FUNC_LIMBS.
+
+2001-11-27  Gerardo Ballabio  <ballabio@sissa.it>
+
+	* gmpxx.h, mpfrxx.h: Various updates and improvements.
+
+2001-11-27  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi (Useful Macros and Constants): Add gmp_version, add @findex
+	for mp_bits_per_limb.
+
+	* demos/perl/GMP.pm, demos/perl/GMP.xs: Use new style gmp_randinit's.
+	* demos/perl/test.pl: Update for this, and for mpz_perfect_power_p
+	handling of 0 and 1.
+
+2001-11-26  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/realloc.c: Clear variable when decreasing allocation to less than
+	needed.  Misc updates.
+
+2001-11-25  Kevin Ryde  <kevin@swox.se>
+
+	* tests/misc/t-locale.c: Avoid printf in the normal case, since the
+	replacement localeconv breaks it on SunOS 4.
+
+	* gmp.texi (Build Options, Notes for Package Builds): Note libgmpxx
+	depends on libgmp from same GMP version.
+
+	* acinclude.m4, configure.in (GMP_FUNC_SSCANF_WRITABLE_INPUT): New
+	test.
+	* scanf/sscanf.c, scanf/vsscanf.c: Use it to ensure sscanf input is
+	writable, if necessary.
+
+	* tests/misc/t-scanf.c: Ensure sscanf arguments are writable, always.
+	* configure.in (AC_CHECK_DECLS): Remove sscanf, no longer required.
+
+	* configure.in (none-*-*): Fix default CFLAGS setups.
+
+	* doc/configuration: Misc updates.
+
+2001-11-23  Kevin Ryde  <kevin@swox.se>
+
+	* mpz/init2.c, mpz/realloc2.c: New files.
+	* Makefile.am, mpz/Makefile.am: Add them.
+	* gmp-h.in: Add prototypes.
+	* gmp.texi (Efficiency): Mention these instead of _mpz_realloc.
+	(Initializing Integers): Add documentation, reword other parts.
+
+2001-11-22  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/cray/ieee/addmul_1.c: Fix logic for more_carries scalar loop.
+	* mpn/cray/ieee/submul_1.c: Likewise.
+
+2001-11-20  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi (Known Build Problems): Note an out of memory on DJGPP.
+	(Function Classes): Update function counts.
+	Misc tweaks elsewhere.
+
+	* configure.in (AC_CHECK_DECLS): Add sscanf.
+	* tests/misc/t-scanf.c: Use it, for the benefit of SunOS 4.
+
+	* tal-debug.c, gmp-impl.h: More checks of TMP_DECL/TMP_MARK/TMP_FREE
+	consistency.
+
+	* mpfr/Makefile.am (AR): Explicit AR=@AR@ to override automake
+	default, necessary for powerpc64 ABI=aix64.
+
+2001-11-18  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/powm.c: Move TMP_MARK to before any TMP_ALLOCs.
+
+2001-11-18  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (--enable-fft): Make this the default.
+	* gmp.texi (Build Options): Update.
+
+	* Makefile.am (libmp_la_DEPENDENCIES): Revise mpz objects needed by
+	new mpz/powm.c.
+
+	* gmp.texi (Random State Initialization): Add gmp_randinit_default and
+	gmp_randinit_lc_2exp_size, mark gmp_randinit as obsolete.
+	(Random State Seeding): New section, taken from "Random State
+	Initialization" and "Random Number Functions".
+
+	* configure.in (AC_CHECK_DECLS): Add fgetc, fscanf, ungetc.
+	* scanf/fscanffuns.c: Use these, for the benefit of SunOS 4.
+
+	* gmp-impl.h, gmp-h.in (__gmp_default_fp_limb_precision): Move back to
+	gmp-impl.h now not required for inlined mpf.
+
+	* randlc2s.c (gmp_randinit_lc_2exp_size): New file, the size-based LC
+	selection from rand.c.
+	* rand.c (gmp_randinit): Use it.
+	* randdef.c (gmp_randinit_default): New file.
+	* gmp-impl.h (RANDS): Use it.
+	(ASSERT_CARRY): New macro.
+	* gmp-h.in (gmp_randinit_default, gmp_randinit_lc_2exp_size: Add
+	prototypes.
+	* Makefile.am (libgmp_la_SOURCES): Add randdef.c and randlc2s.c.
+
+	* printf/asprntffuns.c: Include config.h before using its defines.
+
+	* gmp-impl.h: Move C++ <string> to top of file to avoid the memset
+	redefine upsetting configure tests.  Remove <iostream> since <iosfwd>
+	in gmp.h suffices.
+
+2001-11-16  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi (Integer Exponentiation): mpz_powm supports negative
+	exponents.
+	(Assigning Floats, I/O of Floats, C++ Formatted Output, C++ Formatted
+	Input): Decimal point follows locale.
+	(Formatted Output Strings): %n accepts any type.
+	(Formatted Input Strings): New section.
+	(Formatted Input Functions): New section.
+	(C++ Class Interface): Corrections and clarifications suggested by
+	Gerardo.
+
+	* scanf/doscan.c, scanf/fscanf.c, scanf/fscanffuns.c, scanf/scanf.c,
+	scanf/sscanf.c, scanf/sscanffuns.c, scanf/vfscanf.c, scanf/vscanf.c,
+	scanf/vsscanf.c, scanf/Makefile.am, tests/misc/t-scanf.c: New files.
+	* gmp-h.in, gmp-impl.h, Makefile.am, configure.in: Consequent
+	additions.
+
+	* tests/misc: New directory.
+	* tests/misc/Makefile.am: New file.
+	* tests/misc/t-locale.c: New file.
+	* tests/misc/t-printf.c: Moved from tests/printf.
+	* tests/printf: Remove directory.
+	* configure.in, tests/Makefile.am: Update.
+
+	* tests/cxx/t-locale.cc: New file.
+	* tests/cxx/Makefile.am: Add it.
+
+	* mpf/set_str.c, cxx/ismpf.cc: Use localeconv for the decimal point.
+
+	* acinclude.m4 (GMP_ASM_X86_MCOUNT): Update to $lt_prog_compiler_pic
+	for current libtool, recognise non-PIC style mcount in windows DLLs.
+
+	* gmp-impl.h (__gmp_replacement_vsnprintf): Add prototype.
+
+	* gmp-impl.h (__gmp_rands, __gmp_rands_initialized,
+	modlimb_invert_table): Add __GMP_DECLSPEC for the benefit of test
+	programs using them from a windows DLL.
+	* longlong.h (__clz_tab): Ditto.
+
+	* mpn/x86/t-zdisp2.pl: New file.
+
+	* mpn/x86/pentium4/README: New file.
+
+2001-11-15  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/powm.c (HANDLE_NEGATIVE_EXPONENT): #define to 1.
+	* tests/mpz/reuse.c (main): Use mpz_invert to avoid undefined mpz_powm
+	cases.
+
+2001-11-14  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/powm_ui.c: Rewrite along the lines of mpz/powm.c (except still no
+	redc).
+	* mpz/powm.c: Adjust for negative b, after exponentiation done.  Add
+	(still disabled) code for handling negative exponents.  Misc cleanups.
+
+2001-11-14  Kevin Ryde  <kevin@swox.se>
+
+	* mpf/out_str.c: Use localeconv for the decimal point.
+
+	* tests/misc.c (tests_rand_end): Use time() if gettimeofday() not
+	available (eg. on mingw).
+
+2001-11-11  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-h.in: Remove parameter names from prototypes, to keep out of
+	application namespace.
+
+2001-11-08  Kevin Ryde  <kevin@swox.se>
+
+	* acinclude.m4 (GMP_GCC_VERSION_GE): Fix sed regexps to work on
+	Solaris 8.
+
+	* printf/doprnt.c: Support %n of all types, per glibc.
+
+	* gmp-h.in, gmp-impl.h, mpf/abs.c, mpf/neg.c, mpf/get_prc.c,
+	mpf/get_dfl_prec.c, mpf/set_dfl_prec.c, mpf/set_prc_raw.c,
+	mpf/set_si.c, mpf/set_ui.c, mpf/size.c: Revert mpf inlining, in order
+	to leave open the possibility of keeping binary compatibility if mpf
+	becomes mpfr.
+
+	* mpn/x86/k7/mmx/lshift.asm, mpn/x86/k7/mmx/rshift.asm: Use Zdisp to
+	force code size for computed jumps.
+	* mpn/x86/k6/mod_34lsub1.asm, mpn/x86/k6/k62mmx/copyd.asm: Use Zdisp
+	to force good code alignment.
+	* mpn/x86/x86-defs.m4 (Zdisp): More instructions.
+
+	* mpn/x86/pentium/sqr_basecase.asm, mpn/x86/k7/mmx/mod_1.asm,
+	mpn/x86/k7/mmx/popham.asm: Remove some unnecessary "0" address offsets.
+
+	* mpq/set_si.c, mpq/set_ui.c: Set _mp_den._mp_size correctly if den==0.
+
+2001-11-07  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/hppa/hppa1_1/udiv_qrnnd.asm: Work around gas bug.
+
+	* mpn/asm-defs.m4 (PROLOGUE): Change alignment to 8 (probably a good
+	idea in general; required for hppa/hppa1_1/udiv_qrnnd.asm).
+
+2001-11-06  Torbjorn Granlund  <tege@swox.com>
+
+	* gmp-impl.h (MPN_COPY_INCR): Prepend local variable by `__'.
+	(MPN_COPY_DECR): Likewise.
+
+2001-11-05  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/powm.c: Call mpn functions, not mpz functions, for computation
+	mod m.  Streamline allocations to use a mixture of stack allocation and
+	heap allocation.  Add currently disabled phi(m) exponent reduction
+	code.  Misc optimizations and cleanups.
+
+2001-11-05  Kevin Ryde  <kevin@swox.se>
+
+	* mpq/inp_str.c: Remove unused variable "ret".
+
+	* mpn/x86/k7/sqr_basecase.asm: Fix a 0(%edi) to use Zdisp, so the
+	computed jumps hit the right spot on old gas.
+
+	* mpq/canonicalize.c: DIVIDE_BY_ZERO if denominator is zero.
+
+	* mpn/lisp/gmpasm-mode.el (comment-start-skip): Correction to the way
+	the first \( \) pair is setup.
+	(gmpasm-font-lock-keywords): Don't fontify the space before a "#" etc.
+	Misc tweaks to some comments.
+
+2001-11-03  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/refmpn.c (refmpn_overlap_p): Reverse return values.
+
+2001-11-02  Kevin Ryde  <kevin@swox.se>
+
+	* tune/many.pl: Setup CFLAGS_PIC and ASMFLAGS_PIC, since that's no
+	longer done by configure.
+
+	* mpn/x86/pentium4/mmx/popham.asm: New file.
+
+	* mpn/x86/x86-defs.m4 (psadbw): New macro.
+	* mpn/x86/k7/mmx/popham.asm: Use it.
+
+	* tests/refmpn.c (refmpn_overlap_p): New function, independent of
+	MPN_OVERLAP_P.
+
+2001-10-31  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/mpz/t-powm.c: Print proper error message when finding
+	discrepancy.
+
+2001-10-31  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/x86/pentium/mod_34lsub1.asm: New file.
+	* mpn/x86/k7/mod_34lsub1.asm: New file.
+	* mpn/x86/mod_34lsub1.asm: New file.
+
+2001-10-30  Kevin Ryde  <kevin@swox.se>
+
+	* tests/printf/t-printf.c (check_misc): Add checks from the glibc docs.
+	(check_vasprintf, check_vsnprintf): Run these unconditionally.
+
+	* gmp-impl.h (ASSERT_MPQ_CANONICAL): New macro.
+	* mpq/cmp.c, mpq/cmp_si.c, mpq/cmp_ui.c, mpq/equal.c: Add ASSERTs for
+	canonical inputs, where correctness depends on it.
+
+	* mpn/lisp/gmpasm-mode.el (comment-start-skip): Add "dnl".
+
+2001-10-27  Torbjorn Granlund  <tege@swox.com>
+
+	* demos/pexpr.c: Remove some unused variables.
+	(main): Allocate more buffer space to accommodate minus sign.
+
+2001-10-27  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-impl.h, mpn/asm-defs.m4, configure.in, tune/speed.h,
+	tune/speed.c, tune/common.c, tune/many.pl, tests/devel/try.c: Add
+	mpn_mod_34lsub1.
+	* tests/refmpn.c, tests/tests.h (refmpn_mod_34lsub1): New function.
+
+	* mpn/generic/mod_34lsub1.c: New file.
+	* mpn/x86/k6/mod_34lsub1.asm: New file.
+	* mpn/x86/pentium4/sse2/mod_34lsub1.asm: New file.
+	* mpn/x86/x86-defs.m4 (Zdisp): Add another instruction.
+
+	* gmp-h.in, gmpxx.h: Use <iosfwd> not whole <iostream>.
+
+	* gmp.texi (Known Build Problems): Add note on test programs with
+	Windows DLLs.
+
+2001-10-26  Kevin Ryde  <kevin@swox.se>
+
+	* tests/mpq/t-get_d.c: Limit the size of "eps" for vax.
+
+	* gmp.texi (maybepagebreak): New macro, use it in a few places.
+	(Notes for Particular Systems): C++ Windows DLLs are not supported.
+	(Known Build Problems): Note sparc solaris 2.7 gcc 2.95.2 shared
+	library problems.
+	(Autoconf): Tweak version numbers shown.
+	(Integer Roots): mpz_perfect_square_p and mpz_perfect_power_p consider
+	0 and 1 perfect powers, mpz_perfect_power_p accepts negatives.
+	(Number Theoretic Functions): Add mpz_millerrabin, combined with a
+	reworded mpz_probab_prime_p.
+	(Formatted Output Strings): Misc clarifications.
+	(Formatted Output Functions): gmp_asprintf, gmp_vasprintf,
+	gmp_snprintf, gmp_vsnprintf always available.
+	(C++ Formatted Output): Misc rewordings.
+	(Formatted Input): New chapter.
+	(C++ Class Interface): New chapter, by Gerardo and me.
+	(Language Bindings): Update GMP++ now in GMP.
+	(C++ Interface Internals): New section, by Gerardo and me.
+
+	* printf/repl-vsnprintf.c: New file.
+	* configure.in, acinclude.m4, Makefile.am, printf/Makefile.am: Use it
+	if libc vsnprintf missing or bad.
+	* configure.in (AC_CHECK_FUNCS): Add strnlen.
+
+	* printf/snprntffuns.c, printf/vasprintf.c: Use
+	__gmp_replacement_vsnprintf if libc vsnprintf not available.
+	* printf/asprintf.c, printf/snprintf.c, printf/vasprintf.c,
+	printf/vsnprintf.c: Provide these functions unconditionally.
+	* acinclude.m4 (GMP_FUNC_VSNPRINTF): Remove warning about omissions
+	when vsnprintf not available.
+
+2001-10-24  Kevin Ryde  <kevin@swox.se>
+
+	* configure, aclocal.m4: Regenerate with a libtool patch for a stray
+	quote in AC_LIBTOOL_PROG_LD_SHLIBS under mingw and cygwin.
+
+	* gmp-impl.h (modlimb_invert): More comments.
+
+	* printf/doprnt.c, printf/doprnti.c: Use the precision field to print
+	leading zeros.
+	* tests/printf/t-printf.c: Test this.
+	* cxx/osdoprnti.cc, gmp-impl.h: Ignore precision in operator<<.
+
+	* tune/speed.c, tune/speed.h, tune/common.c: Add mpn_mul_1_inplace.
+
+2001-10-23  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/pprime_p.c (mpz_millerrabin): Remove function and its descendant.
+
+	* mpz/millerrabin.c: New file with code from pprime.c.
+	* mpz/Makefile.am: Compile millerrabin.c.
+	* Makefile.am (MPZ_OBJECTS): Ditto.
+	* gmp-h.in: Declare mpz_millerrabin.
+
+2001-10-22  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/mpz/t-perfsqr.c: New file.
+	* tests/mpz/Makefile.am (check_PROGRAMS): Add it.
+
+	* demos/factorize.c (factor): Check for number to factor == 0.
+	(main): When invoked without arguments, read from stdin.
+
+	* mpz/perfpow.c: Add code to handle negative perfect powers ((-b)^odd).
+	Treat 0 and 1 as perfect powers.
+
+	* mpn/sparc32/v9/sqr_diagonal.asm: Jump past .align.
+
+2001-10-21  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/perfsqr.c (sq_res_0x100): Remove bogus final `,'.
+	(mpn_perfect_square_p): Suppress superfluous `&1' in sq_res_0x100 test.
+	(mpn_perfect_square_p, O(n) test): Improve comments.  Combine remainder
+	tests for some small primes.  Don't share code for different limb
+	sizes.  Use single `if' with many `||' for better code density.
+
+2001-10-22  Kevin Ryde  <kevin@swox.se>
+
+	* demos/perl/GMP.xs (mutate_mpz, tmp_mpf_grow): Make these "static".
+
+	* mpn/x86/pentium/popcount.asm, mpn/x86/pentium/hamdist.asm
+	(mpn_popcount_table): Use GSYM_PREFIX.
+
+2001-10-19  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/x86/*.asm: Add some measured speeds on various x86s.
+
+	* tests/mpz/reuse.c, tests/mpf/reuse.c: Disable tests when using a
+	windows DLL, because certain global variable usages won't compile.
+
+	* configure.in (AC_CHECK_FUNCS): Add alarm.
+	* tests/spinner.c: Conditionalize alarm and SIGALRM availability, for
+	the benefit of mingw32.
+
+	* acinclude.m4 (GMP_ASM_TYPE, GMP_ASM_SIZE): Suppress .type and .size
+	on COFF.
+
+	* acinclude.m4 (GMP_PROG_HOST_CC): New macro.
+	* configure.in: Use it for windows DLL cross-compiles.
+	* aclocal.m4, configure: Regenerate with libtool patch to hold HOST_CC
+	in the generated libtool script.
+
+	* aclocal.m4, configure: Regenerate with libtool patch to suppress
+	warnings when probing command line limit on FreeBSD.
+
+	* demos/qcn.c (M_PI): Define if not already provided, helps mingw32.
+
+2001-10-17  Kevin Ryde  <kevin@swox.se>
+
+	* printf/doprnt.c: Use <stdint.h> for intmax_t.
+
+	* longlong.h: Recognise __sparcv8 for gcc on Solaris.  Reported by
+	Mark Mentovai <mark@mentovai.com>.
+
+	* gmp-impl.h (gmp_allocated_string): No need for inline on member funs.
+
+2001-10-16  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi (Debugging): Add mpatrol.
+	(Integer Comparisons, Comparing Rationals, Float Comparison): Index
+	entries for sign tests.
+	(I/O of Floats): Clarify mpf_out_str exponent is in decimal.
+	(C++ Formatted Output): mpf_t operator<< exponent now in decimal.
+	(FFT Multiplication): Use an ascii art sigma.
+	(Contributors): Add Gerardo Ballabio.
+
+	* cxx/osfuns.cc (__gmp_doprnt_params_from_ios): Always give mpf_t
+	exponent in decimal, irrespective of ios::hex or ios::oct.
+	* tests/cxx/t-ostream.cc (check_mpf): Update.
+
+	* printf/doprnt.c: Support %lln and %hhn.
+
+	* mpn/x86/pentium4/sse2/submul_1.asm: Use a psubq to negate the
+	initial carry (helps the submul_1c case), and improve the comments.
+
+2001-10-11  Kevin Ryde  <kevin@swox.se>
+
+	* acinclude.m4, configure.in (GMP_IMPL_H_IEEE_FLOATS): New macro.
+
+	* ltmain.sh: Send some rm errors to /dev/null, helps during compiles
+	on Solaris 2.7 and HP-UX 10.
+
+	* tal-notreent.c: Renamed from stack-alloc.c.
+	* Makefile.am, acinclude.m4, gmp-impl.h: Update.
+
+	* gmp-h.in: Don't give both prototypes and inlines, except on gcc.
+
+	* gmp-h.in, gmp-impl.h: Use #includes to get necessary standard
+	classes, add std:: to prototypes.
+	* cxx/*.cc, tests/cxx/t-ostream.cc: Add "use namespace std".
+	* acinclude.m4 (GMP_PROG_CXX_WORKS): Ditto.
+
+	* tests/*/Makefile.in, mpfr/tests/Makefile.in: Regenerate with
+	automake patch to avoid Ultrix problem with empty $(TESTS).
+
+	* */Makefile.in: Regenerate with automake patch to only rm *_.c in
+	"make clean" when ansi2knr actually in use, helps DOS 8.3.
+
+	* Makefile.in: Regenerate with automake patch to fix stamp-h
+	numbering, avoiding an unnecessary config.status run.
+
+2001-10-09  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/hppa/hppa1_1/udiv_qrnnd.asm: Use L macros for labels.
+	Quote L reloc operator.
+
+	* gmp-impl.h: Declare class string.
+
+	* mpn/asm-defs.m4 (INT32, INT64): Quote $1 to prevent further
+	expansion.
+
+	* mpn/alpha/ev6/mul_1.asm: New file.
+
+2001-10-09  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi (Introduction to GMP): Add pentium 4 to optimized CPUs.
+	(Build Options): Note macos directory.
+	(Notes for Package Builds): GMP 4 series binary compatible with 3.
+	(Known Build Problems): Remove $* and ansi2knr note, now fixed, except
+	possibly under --host=none.
+	(Formatted Output Strings): Remove -1 prec for all digits.
+
+	* mpz/add.c, mpz/sub.c: Don't use mpz path on #include (helps macos).
+	* mpbsd/Makefile.am (INCLUDES): Add -I$(top_srcdir)/mpz.
+
+	* printf/doprnt.c, tests/printf/t-printf.c: Remove support for %.*Fe
+	prec -1 meaning all digits.
+
+	* acinclude.m4 (GMP_PROG_AR): Override libtool, use AR_FLAGS="cq".
+	(GMP_HPC_HPPA_2_0): Print version string to config.log.
+
+	* Makefile.am (AUTOMAKE_OPTIONS): Remove check-news (permission notice
+	in NEWS file is too big).
+	(dist-hook): Don't distribute numbered or unnumbered emacs backups.
+
+	* Makefile.am, cxx/Makefile.am: Updates for Gerardo's stuff.
+
+2001-10-09  Gerardo Ballabio  <ballabio@sissa.it>
+
+	* cxx/isfuns.cc: New file.
+	* gmp-impl.h: Add prototypes.
+	* cxx/ismpf.cc, cxx/ismpq.cc, cxx/ismpz.cc: New files.
+	* gmp-h.in: Add prototypes.
+	* gmpxx.h, mpfrxx.h: New files.
+
+2001-10-08  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (with_tags): Establish a default based on --enable-cxx.
+
+	* aclocal.m4: Regenerate with libtool patches for sed char range to
+	help Cray, LTCC quotes and +Z warnings grep to help HP-UX.
+
+	* gmp-impl.h (doprnt_format_t, doprnt_memory_t, doprnt_reps_t,
+	doprnt_final_t): Use _PROTO.
+
+2001-10-05  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/asm-defs.m4 (INT32, INT64): Use LABEL_SUFFIX.
+
+	* mpn/hppa: Convert files to `.asm'.
+
+2001-10-05  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/Makeasm.am (.S files): Revert to separate CPP and CCAS, use
+	cpp-ccas, and only pass CPPFLAGS to CPP, not whole CFLAGS.
+	* mpn/cpp-ccas: New file.
+	* mpn/Makefile.am (EXTRA_DIST): Add it.
+
+	* tune/common.c, tune/speed.h: Change SPEED_ROUTINE_MPN_COPY_CALL uses
+	to SPEED_ROUTINE_MPN_COPY or new SPEED_ROUTINE_MPN_COPY_BYTES.  Avoids
+	macro expansion problems on Cray.
+
+	* configure.in (AC_PROG_CXXCPP): Add this, to make libtool happier.
+
+2001-10-04  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/rrandomb.c (gmp_rrandomb): Change bit_pos to be 0-based (was
+	1-based); shift 2 (was 1) when making bit mask.  These two changes
+	avoid undefined shift counts.
+	(gmp_rrandomb): Avoid most calls to _gmp_rand by caching random values.
+
+	* mpn/generic/random2.c: Changes for mirroring mpz/rrandomb.c.
+
+2001-10-04  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi (Build Options): Add --enable-cxx.
+	(Notes for Particular Systems): Mention pentium4 performance and SSE2.
+	(Known Build Problems): Remove vax jsobgtr note, no longer needed.
+	(Converting Floats): Tweak mpf_get_str description.
+	(Low-level Functions): Correction to mpn_gcdext destination space
+	requirements.
+	(C++ Formatted Output): New section.
+	(Language Bindings): Add ALP
+	(Contributors): Add Paul Zimmermann's square root, update my things.
+
+	* acinclude.m4 (GMP_PROG_CC_IS_GNU, GMP_PROG_CXX_WORKS): Send compiler
+	errors to config.log.
+
+	* mpq/Makefile.am (INCLUDES): Remove -DOPERATION_$*, not needed.
+
+	* mpn/x86/*.asm: Change references to old README.family to just README.
+
+	* mpz/README: Remove file, now adequately covered in the manual.
+
+2001-10-03  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/x86/pentium4/copyi.asm: New file.
+	* mpn/x86/pentium4/copyd.asm: New file.
+
+	* gmp-impl.h: Implement separate MPN_COPY_INCR and MPN_COPY_DECR
+	macros for CRAY systems.
+	(CRAY _MPN_COPY): Delete.
+
+2001-10-02  Kevin Ryde  <kevin@swox.se>
+
+	* tests/mpz/t-popcount.c (check_data): Use "~ (unsigned long) 0" to
+	avoid compiler warnings on sco.
+
+	* mpbsd/Makefile.am: Compile mpz files directly, no copying.
+	Use mpz/add.c and mpz/sub.c rather than mpz/aors.c.
+	(INCLUDES): Remove -DOPERATION_$*, no longer needed (by mpz).
+
+	* mpz/aors.h: Renamed from mpz/aors.c.
+	* mpz/add.c, mpz/sub.c: New files, using mpz/aors.h.
+	* mpz/aors_ui.h: Renamed from mpz/aors_ui.c.
+	* mpz/add_ui.c, mpz/sub_ui.c: New files, using mpz/aors_ui.h.
+	* mpz/fits_s.h: Renamed and adapted from mpz/fits_s.c.
+	* mpz/fits_sshort.c, mpz/fits_sint.c, mpz/fits_slong.c: New files.
+	* mpz/mul_i.h: Renamed from mpz/mul_siui.c.
+	* mpz/mul_ui.c, mpz/mul_ui.c: New files, using mpz/mul_i.h.
+	* mpz/Makefile.am: Consequent updates.
+	(INCLUDES): Remove -DOPERATION_$*.
+
+	* mpf/fits_s.h: Renamed and adapted from mpf/fits_s.c.
+	* mpf/fits_sshort.c, mpf/fits_sint.c, mpf/fits_slong.c: New files.
+	* mpf/fits_u.h: Renamed and adapted from mpf/fits_u.c.
+	* mpf/fits_ushort.c, mpf/fits_uint.c, mpf/fits_ulong.c: New files.
+	* mpf/Makefile.am: Consequent updates.
+	(INCLUDES): Remove -DOPERATION_$*.
+
+	* cxx/osfuns.cc (__gmp_doprnt_params_from_ios): Don't use ios::hex etc
+	as cases in a switch, they're not constant in g++ 3.0.
+
+	* mpn/Makeasm.am (.s.o, .s.obj, .S.o, .S.obj, .asm.o, .asm.obj):
+	Locate source file with test -f the same as automake.
+	(.S): Let CCAS do the preprocessing, and run libtool for .S.lo.
+	(.asm.lo): Run libtool via m4-ccas to get new style foo.lo right.
+	(COMPILE_FLAGS): Add $(DEFAULT_INCLUDES), per new automake.
+	* mpn/m4-ccas: New file.
+	* mpn/Makefile.am (EXTRA_DIST): Add it.
+	* mpn/asm-defs.m4: Add m4_not_for_expansion(`DLL_EXPORT').
+	* mpn/x86/x86-defs.m4: Undefine PIC if DLL_EXPORT is set.
+	* configure.in (CFLAGS_PIC, ASMFLAGS_PIC): Remove, no longer needed.
+
+	* acinclude.m4 (GMP_FUNC_VSNPRINTF): Warn what's omitted when
+	vsnprintf not available.
+
+	* mpn/underscore.h: Remove file, not used since m68k converted to asm.
+	* mpn/Makefile.am (EXTRA_DIST): Remove it.
+
+	* tests/refmpz.c: Add <stdlib.h>, for free().
+
+2001-10-01  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/x86/pentium4/sse2/submul_1.asm: Apply some algebraic
+	simplifications.
+	* mpn/x86/pentium4/sse2/addmul_1.asm: Comment.
+
+2001-10-01  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (--enable-cxx): New option for C++ support.
+	Add cxx and tests/cxx subdirectories.
+	* ltmain.sh, aclocal.m4: Update to libtool 2001-09-30.
+
+	* cxx/Makefile.am, cxx/Makefile.in, cxx/osdoprnti.cc, cxx/osfuns.cc,
+	cxx/osmpf.cc, cxx/osmpq.cc, cxx/osmpz.cc: New files.
+	* Makefile.am: Add them, in new libgmpxx.
+	* gmp-h.in, gmp-impl.h: Prototypes and support.
+	* tests/cxx/Makefile.am, tests/cxx/Makefile.in,
+	tests/cxx/t-ostream.cc: New files.
+
+	* tune/speed.h (SPEED_ROUTINE_MPN_GCD_CALL,
+	SPEED_ROUTINE_MPN_GCDEXT_ONE): mpn_gcdext needs size+1 for
+	destinations.  Found by Torbjorn.
+
+	* gmp-h.in (__GNU_MP__, __GNU_MP_VERSION): Bump to 4.0.
+	* mp-h.in (__GNU_MP__): Ditto.
+	* gmp.texi, Makefile.am, compat.c: Amend version 3.2 to 4.0.
+
+	* acinclude.m4 (GMP_PROG_CXX_WORKS): New macro.
+	(GMP_PROG_CC_WORKS): Write "conftest" test program, not a.out.
+
+	* gmp-impl.h (struct gmp_asprintf_t): Moved from printf/vasprintf.c.
+	(GMP_ASPRINTF_T_INIT): New macro.
+	(GMP_ASPRINTF_T_NEED): New macro, adapted from vasprintf.c NEED().
+	* printf/vasprintf.c: Use these.
+
+	* printf/asprntffuns.c: New file.
+	* printf/Makefile.am, Makefile.am: Add it.
+	* printf/asprntffuns.c, printf/vasprintf.c, gmp-impl.h
+	(__gmp_asprintf_memory, __gmp_asprintf_reps, __gmp_asprintf_final):
+	Move to asprntffuns.c, rename to __gmp and make global, remove
+	spurious formal parameters from __gmp_asprintf_final.
+
+	* configure.in (j90-*-*, sv1-*-*): Don't duplicate $path in $add_path.
+	(*-*-mingw*): Don't assemble with -DPIC (as per cygwin).
+
+	* printf/snprntffuns.c (gmp_snprintf_final): Remove spurious formal
+	parameters.
+
+	* tune/tuneup.c (POWM_THRESHOLD): Reduce stop_factor to 1.1 to help
+	Cray vector systems.
+
+	* tests/misc.c (tests_rand_start): Print GMP_CHECK_RANDOMIZE=NN to
+	facilitate cut and paste when re-running.
+	* tests/mpz/t-inp_str.c (check_data): Add more diagnostic prints.
+
+2001-09-30  Kent Boortz  <kent@swox.com>
+
+	* macos/configure, macos/Makefile.in, macos/README: Updates for gmp 4.
+	* gmp-h.in (_GMP_H_HAVE_FILE): Recognise Apple MPW.
+
+2001-09-30  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/cray/ieee/submul_1.c: Rewrite.  Streamline multiplications;
+	use `majority' logic.
+
+2001-09-27  Torbjorn Granlund  <tege@swox.com>
+
+	* gmp-h.in (__GMPN_AORS_1): Rewrite to work around Cray compiler bug.
+
+2001-09-26  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/x86/pentium4/sse2/gmp-mparam.h: New file.
+
+2001-09-26  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/x86/pentium4/sse2/dive_1.asm: New file.
+	* mpn/x86/pentium4/sse2/submul_1.asm: New file.
+	* mpn/x86/pentium4/sse2/sqr_basecase.asm: New file.
+
+	* mpn/x86/pentium/copyi.asm: New file, based on past work by Torbjorn.
+	* mpn/x86/pentium/copyi.asm: New file, ditto.
+	* mpn/x86/pentium/com_n.asm: Rewrite, ditto.
+
+	* printf/snprntffuns.c (gmp_snprintf_format): Copy va_list in case
+	vsnprintf trashes it.
+	* printf/vasprintf.c (gmp_asprintf_format): Ditto.
+	* gmp-impl.h, doprnt.c (va_copy): Move to gmp-impl.h.
+
+	* tests/mpz/t-cmp_d.c (check_low_z_one): Patch by Torbjorn for vax
+	limited float range.
+
+2001-09-23  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/vax/lshift.s: Change `jsob*' to `sob*'.
+	* mpn/vax/rshift.s: Likewise.
+
+2001-09-23  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/x86/pentium4/sse2/mul_basecase.asm: Some simple but real code.
+
+	* printf/doprnt.c: Use va_copy for va_list variables, copy function
+	parameter in case it's call-by-reference.
+
+	* tune/freq.c (speed_cpu_frequency_bsd_dmesg): New function.
+	(speed_cpu_frequency_table): Use it.
+
+	* tune/many.pl (popcount, hamdist): Fix declared return value.
+	(sb_divrem_mn): Remove a spurious duplicate entry.
+	(CLEAN): Add tmp-$objbase.c when using that for .h files.
+	(macro_speed): Give a default for .h files.
+	Add ATTRIBUTE_CONST or __GMP_ATTRIBUTE_PURE as appropriate.
+
+	* tune/speed.h (SPEED_ROUTINE_MPN_MOD_CALL,
+	SPEED_ROUTINE_MPN_PREINV_MOD_1, SPEED_ROUTINE_MPN_POPCOUNT,
+	SPEED_ROUTINE_MPN_HAMDIST, SPEED_ROUTINE_MPN_GCD_1N,
+	SPEED_ROUTINE_MPN_GCD_1_CALL, SPEED_ROUTINE_MPZ_JACOBI): Use return
+	values so gcc 3 won't discard calls to pure or const functions.
+	(mpn_mod_1_div, mpn_mod_1_inv): Add __GMP_ATTRIBUTE_PURE.
+
+2001-09-22  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/x86/pentium4/sse2/mul_basecase.asm: New file, placeholder
+	for real code, hiding the default x86 mul_basecase.asm.
+
+2001-09-22  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (AC_PREREQ): Bump to 2.52.
+	(m4_pattern_forbid, m4_pattern_allow): New calls, forbid GMP_.
+	(AC_CHECK_HEADERS): Remove sys/types.h, already done by autoconf.
+	* acinclude.m4, configure.in (GMP_GCC_NO_CPP_PRECOMP): New macro.
+
+	* tests/devel/try.c (TYPE_PREINV_MOD_1): Don't run size==0.
+	(malloc_region): Need fd=-1 for mmap MAP_ANON on BSD.
+
+2001-09-20  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/cong.c (mpz_congruent_p): Fix one-limb c<d test.
+
+	* longlong.h: Rewrite __i370__ smul_ppmm; enable also for __s390__.
+
+	* configure.in: Add support for IBM 360, 370, 390 families.
+
+2001-09-20  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/x86/pentium4/sse2/diveby3.asm: New file.
+	* mpn/x86/pentium4/sse2/mode1o.asm: New file.
+
+2001-09-16  Kevin Ryde  <kevin@swox.se>
+
+	* printf/doprnt.c: '#' means showpoint and showtrailing for %e, %f, %g.
+	* tests/printf/t-printf.c (check_f): More test cases.
+
+2001-09-15  Torbjorn Granlund  <tege@swox.com>
+
+	* gmp-h.in (__GMPN_AORS_1): Remove param TEST, add OP and CB.
+	Postpone zeroing of (cout).
+	(__GMPN_ADD_1, __GMPN_SUB_1): Corresponding changes.
+
+2001-09-14  Kevin Ryde  <kevin@swox.se>
+
+	* ChangeLog: Merge in tests/rand/ChangeLog.
+	* tests/rand/ChangeLog: Remove file.
+
+	* printf/doprnt.c: Fix handling of a plain format after a GMP one; no
+	need to protect against negative precision internally.
+	* tests/printf/t-printf.c (check_misc): More checks.
+
+2001-09-12  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/cray/ieee/invert_limb.c: Add a PROLOGUE in a comment to have
+	HAVE_NATIVE_... defined.
+
+2001-09-11  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in, gmp-h.in (__GMP_HAVE_HOST_CPU_FAMILY_power,
+	__GMP_HAVE_HOST_CPU_FAMILY_powerpc): New AC_SUBSTs.
+	* gmp-h.in (__GMPN_COPY_INCR): Use them to select the power/powerpc
+	code, rather than preprocessor defines.
+
+	* acinclude.m4, configure.in (GMP_H_ANSI): New macro.
+
+	* gmp-h.in (__GMP_EXTERN_INLINE): Add a definition for SCO 8 cc.
+
+	* gmp-h.in, version.c (gmp_version): Make the pointer "const" as well
+	as the string.
+
+	* acinclude.m4, configure.in (GMP_PROG_CC_IS_XLC): Recognise xlc when
+	invoked under another name (cc, xlc128, etc).
+	* acinclude.m4 (GMP_PROG_CC_IS_GCC): Print a message when recognised.
+
+2001-09-11  Torbjorn Granlund  <tege@swox.com>
+
+	* gmp-h.in: Let __DECC mean __GMP_HAVE_CONST, etc.
+	* mp-h.in: Likewise.
+
+2001-09-10  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/x86/pentium4/mmx/lshift.asm: New file.
+	* mpn/x86/pentium4/mmx/rshift.asm: New file.
+
+	* tests/mpn/t-iord_u.c (check_incr_data): Work around HP compiler bug.
+	(check_decr_data): Likewise.
+
+2001-09-08  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi (Integer Logic and Bit Fiddling): Update mpz_hamdist
+	behaviour, clarify mpz_popcount a touch.
+	(Language Bindings): Add mlton, fix alphabetical order.
+	(Single Limb Division): Describe 2 or 1/2 limbs at a time style.
+
+	* configure.in (AC_CHECK_FUNCS): Add mmap.
+	* tests/devel/try.c (malloc_region): Use mmap if available.
+
+	* tests/refmpz.c, tests/tests.h (refmpz_hamdist): New function.
+	* tests/mpz/t-hamdist.c: New file.
+	* tests/mpz/Makefile.am: Add it.
+
+	* mpz/hamdist.c: Support neg/neg operands.
+
+	* macos/Makefile.in: Remove dual compile of mpq/aors.c and
+	mpn/generic/popham.c.
+
+	* gmp-impl.h (popc_limb): New macro, adapted from mpn/generic/popham.c.
+	For 64-bits reuse 0x33...33 constant.
+	* mpn/generic/popcount.c, mpn/generic/hamdist.c: Split from popham.c,
+	use popc_limb macro, remove unused "i", don't bother with "register"
+	qualifiers.
+	* mpn/generic/popham.c: Remove file.
+
+	* ltmain.sh, configure, aclocal.m4: Update to libtool 1.4.1, with one
+	ltdll.c generation patch.
+	* doc/configuration: Misc updates, note libtool patch used.
+
+	* mpn/x86/pentium4/sse2/mul_1.asm: Use pointer increments not indexed
+	addressing, to get 4.0 c/l flat.
+
+	* tests/mpq/t-cmp_si.c (check_data): Use ULONG_MAX for denominators.
+
+	* tests/misc.c (mpz_negrandom): Use given rstate, not RANDS.
+
+2001-09-07  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/x86/pentium4/sse2/addmul_1.asm: New file.
+
+2001-09-04  Kevin Ryde  <kevin@swox.se>
+
+	* tune/freq.c: Define a HAVE for each speed_cpu_frequency routine to
+	avoid duplicating conditionals.
+	(speed_cpu_frequency_sco_etchw): New function.
+	(speed_cpu_frequency_table): Use it.
+	* tune/README: Mention SCO openunix 8 /etc/hw.
+
+	* mpz/fib_ui.c: Use ?: to avoid a gcc 3 bug on powerpc64.
+	Store back a carry for limb<long.
+
+	* mpn/x86/k7/mmx/divrem_1.asm, mpn/x86/k7/mmx/mod_1.asm,
+	mpn/x86/p6/mmx/divrem_1.asm: Fix a couple of comments.
+
+	* config.guess: Give m68020 for 68020 or better, not m68k.
+	* configfsf.guess: Update to 2001-09-04.
+
+2001-09-02  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (m68k-*-*): Let m68k mean 68000, not 68020.
+	* gmp.texi (Notes for Particular Systems): Update.
+
+	* gmp-impl.h (union ieee_double_extract) [m68k]: Use longs, since int
+	might be only 16 bits.
+
+	* tests/mpq/t-aors.c: New file.
+	* tests/mpq/Makefile.am: Add it.
+
+	* tests/refmpq.c: New file.
+	* tests/Makefile.am: Add it.
+	* tests/tests.h: Add prototypes.
+
+	* mpq/aors.c: Share object code for mpq_add and mpq_sub.
+	* Makefile.am, mpq/Makefile.am: Single mpq/aors.lo now.
+
+	* tests/devel/try.c (TYPE_SUBMUL_1): Use correct reference routine.
+
+2001-08-30  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/x86/x86-defs.m4 (cmov_available_p): Add pentium4.
+
+	* gmp-h.in: Put #define renamings with prototypes.
+	Remove commented out #defines of gmp-impl.h things.
+	(mpn_invert_limb): Remove #define, already in gmp-impl.h.
+	(mpn_lshiftc, mpn_rshiftc): Remove #defines, unused.
+	(mpn_addsub_nc): Add prototype to #define.
+
+2001-08-28  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi: Switch to GFDL.
+	(Top): Arrange copyright and conditions to appear here too.  For
+	clarity have all this before the miscellaneous macro definitions.
+	(Copying): Refer to COPYING.LIB file, mention plain GPL2 in demo
+	programs.
+	(Contributors, References): Use @appendix rather than @unnumbered.
+	(GNU Free Documentation License): New appendix.
+	(@contents): Move to start of document, use only for tex (not html).
+	(Debugging): Add leakbug.
+	(Build Options): Add pentium4.
+	(I/O of Rationals): Add mpq_inp_str.
+
+	* fdl.texi: New file, with two @appendix directive tweaks.
+	* Makefile.am (gmp_TEXINFOS): Add it.
+
+	* tests/mpz/io.c: Check mpz_inp_str return against ftell, send error
+	messages just to stdout.
+
+	* mpz/inp_str.c, gmp-impl.h (__gmpz_inp_str_nowhite): New function,
+	and share a __gmp_free_func call.
+	* mpq/inp_str.c: New file.
+	* Makefile.am, mpq/Makefile.am: Add it.
+	* tests/mpq/t-inp_str.c: New file.
+	* tests/mpq/Makefile.am (check_PROGRAMS): Add it.
+
+	* configure.in, acconfig.h (HAVE_HOST_CPU_FAMILY_power,
+	HAVE_HOST_CPU_FAMILY_powerpc, HAVE_HOST_CPU_FAMILY_x86): AC_DEFINEs
+	for processor families.
+	* gmp-impl.h: Use them, rather than cpp defines.
+
+	* demos/Makefile.am (primes_LDADD): Use $(LIBM), for log().
+
+	* tune/many.pl, tune/Makefile.am: Fix some from clean and distclean.
+
+2001-08-26  Kevin Ryde  <kevin@swox.se>
+
+	* tests/devel/try.c (ARRAY_ITERATION): Make types match on "?:" legs.
+	(TYPE_MPZ_JACOBI, TYPE_MPZ_KRONECKER): Remove some superseded code.
+
+	* tests/printf/t-printf.c (check_plain): Don't compare "all digits"
+	precision against plain printf.
+
+	* tune/Makefile.am: Eliminate empty TUNE_MPZ_SRCS.
+
+	* configure, config.in, INSTALL.autoconf: Update to autoconf 2.52.
+	* */Makefile.in, mdate-sh, missing, aclocal.m4, configure: Update to
+	automake 1.5.
+	* configfsf.guess, configfsf.sub: Update to 2001-08-23.
+
+2001-08-24  Torbjorn Granlund  <tege@swox.com>
+
+	* demos/primes.c: Complete rewrite.
+
+2001-08-24  Kevin Ryde  <kevin@swox.se>
+
+	* longlong.h: Test __ppc__ for apple darwin cc, reported by Jon
+	Becker.  Also test __POWERPC__, PPC and __vxworks__.
+
+	* tune/speed.h (speed_cyclecounter) [x86]: Don't clobber ebx in PIC.
+
+2001-08-22  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (x86 mmx): Correction to mmx path stripping.
+
+2001-08-17  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in, acinclude.m4, Makefile.am, printf/Makefile.am,
+	tests/printf/Makefile.am, gmp-h.in, gmp-impl.h, gmp.texi: Remove C++
+	support, for the time being.
+	* printf/doprntfx.cc, doprntix.cc, osfuns.cc, osmpf.cc, osmpq.cc,
+	osmpz.cc, tests/printf/t-ostream.cc: Remove files.
+
+	* printf/doprnt.c, printf/doprntf.c, gmp-impl.h: Use a single
+	__gmp_doprnt_mpf, rather than a separate ndigits calculation.
+	* printf/doprnt.c, printf/doprntf.c, gmp-impl.h, gmp.texi,
+	tests/printf/t-printf.c: Let empty or -1 prec mean all digits for mpf.
+	* printf/doprnt.c, tests/printf/t-printf.c: Accept h or l in %n; let
+	negative "*" style width mean left justify.
+
+	* gmp-impl.h, mpf/get_str.c (MPF_SIGNIFICANT_DIGITS): New macro,
+	extracted from mpf/get_str.c.
+
+	* libmp.sym: New file.
+	* Makefile.am (libmp_la_LDFLAGS): Use it.
+	(DISTCLEANFILES): Remove asm-syntax.h, no longer generated.
+	Remove some comments about "make check".
+
+	* demos/perl/GMP.pm, GMP.xs, GMP/Mpf.pm: Add printf and sprintf,
+	change get_str to string/exponent for floats, remove separate
+	mpf_get_str.
+	* demos/perl/GMP/Mpf.pm (overload_string): Use $# (default "%.g").
+	* demos/perl/typemap: Fix some duplicate string entries.
+	* demos/perl/test.pl: Update tests, split overloaded constants into ...
+	* demos/perl/test2.pl: ... this new file.
+	* demos/perl/Makefile.PL (clean): Add test.tmp.
+
+2001-08-16  Kevin Ryde  <kevin@swox.se>
+
+	* printf/snprntffuns.c (gmp_snprintf_format): Correction to bufsize-1
+	return value handling.
+
+	* demos/calc/calc.y: Reposition "%{" so copyright notice gets into
+	generated files.
+
+	* INSTALL: Use gmp_printf.
+
+2001-08-14  Kevin Ryde  <kevin@swox.se>
+
+	* mpz/inp_str.c: Fix return value (was 1 too big).
+	* tests/mpz/t-inp_str.c: New file.
+	* tests/mpz/Makefile.am: Add it.
+
+	* mpn/x86/pentium4/sse2/add_n.asm: New file.
+	* mpn/x86/pentium4/sse2/sub_n.asm: New file.
+	* mpn/x86/pentium4/sse2/mul_1.asm: New file.
+
+2001-08-12  Kevin Ryde  <kevin@swox.se>
+
+	* printf/sprintffuns.c, printf/doprntf.c: Don't use sprintf return
+	value (it's a pointer on SunOS 4).
+
+	* acinclude.m4 (GMP_ASM_X86_SSE2, GMP_STRIP_PATH): New macros.
+	* configure.in: Add pentium4 support.
+	* mpn/x86/pentium4, mpn/x86/pentium4/mmx, mpn/x86/pentium4/sse2: New
+	directories.
+	* mpn/x86/README: Update.
+
+2001-08-10  Torbjorn Granlund  <tege@swox.com>
+
+	* demos/pexpr.c (setup_error_handler): Catch also SIGABRT.
+
+2001-07-31  Kevin Ryde  <kevin@swox.se>
+
+	* tests/refmpn.c (refmpn_mul_1c): Allow low to high overlaps.
+
+	* gmp-h.in, gmp-impl.h (_gmp_rand): Move prototype to gmp-impl.h.
+
+	* tune/Makefile.am (EXTRA_DIST): Add many.pl.
+
+2001-07-28  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi (Random Number Functions): Old rand functions no longer use
+	the C library.
+
+	* configure.in, acinclude.m4 (GMP_FUNC_VSNPRINTF): New macro.
+
+	* mpn/generic/get_str.c: Add an ASSERT for high limb non-zero.
+
+2001-07-24  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi (Build Options): Add --enable-cxx.
+	(Converting Floats): Note mpf_get_str only generates accurately
+	representable digits.
+	(Low-level Functions): Note mpn_get_str requires non-zero high limb.
+	(Formatted Output): New chapter.
+	(Multiplication Algorithms): Use @quotation with @multitable.
+	(Toom-Cook 3-Way Multiplication): Ditto.
+
+	* tests/memory.c (tests_free_nosize): New function.
+	* tests/tests.h (tests_allocate etc): Add prototypes.
+
+	* tests/printf: New directory.
+	* tests/printf/Makefile.am, t-printf.c, t-ostream.cc: New files.
+	* configure.in, tests/Makefile.am: Add them.
+
+	* configure.in, acinclude.m4 (GMP_PROG_CXX): New macro.
+	* configure.in (--enable-cxx): New option.
+	(AC_CHECK_HEADERS): Add locale.h and sys/types.h, remove unistd.h.
+	(AC_CHECK_TYPES): Add intmax_t, long double, long long, ptrdiff_t,
+	quad_t.
+	(AC_CHECK_FUNCS): Add localeconv, memset, obstack_vprintf, snprintf,
+	strchr, vsnprintf.
+	(AC_CHECK_DECLS): Add vfprintf.
+
+	* gmp-h.in, gmp-impl.h: Additions for gmp_printf etc.
+
+	* printf: New directory.
+	* printf/Makefile.am, asprintf.c, doprnt.c, doprntf.c, doprntfx.cc,
+	doprnti.c, doprntix.cc, fprintf.c, obprintf.c, obprntffuns.c,
+	obvprintf.c, osfuns.cc, osmpf.cc, osmpq.cc, osmpz.cc, printf.c,
+	printffuns.c, snprintf.c, snprntffuns.c, sprintf.c, sprintffuns.c,
+	vasprintf.c, vfprintf.c, vprintf.c, vsnprintf.c, vsprintf.c: New
+	files.
+	* configure.in, Makefile.am: Add them.
+
+	* configure.in (HAVE_INLINE): Remove AC_DEFINE, unused.
+	(AC_CHECK_TYPES): Don't test for void, assume it always exists.
+
+	* gmp-impl.h (__GMP_REALLOCATE_FUNC_MAYBE): New macro.
+	* mpz/get_str.c, mpq/get_str.c, mpf/get_str.c: Use it.
+
+	* gmp-impl.h (mpn_fib2_ui): Use __MPN.
+	(MPN_COPY_DECR): Fix an ASSERT.
+	(CAST_TO_VOID): Remove macro.
+
+	* gmp-h.in (mpq_out_str): Give #define even without prototype.
+	(mpz_cmp_d, mpz_cmpabs_d): Corrections to #defines.
+
+	* tests/devel/try.c: Add mpn_add and mpn_sub, don't use CAST_TO_VOID.
+
+2001-07-23  Torbjorn Granlund  <tege@swox.com>
+
+	* config.guess: Recognize pentium4.
+	* config.sub: Recognize pentium4.
+
+2001-07-17  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-h.in (__GMPN_AORS_1): Remove x86 and gcc versions, leave just
+	one version.
+	(__GMPN_ADD, __GMPN_SUB): New macros, rewrite of mpn_add and mpn_sub.
+	(mpn_add, mpn_sub): Use them.
+	(__GMPN_COPY_REST): New macro.
+
+	* gmp-h.in, gmp-impl.h, acinclude.m4: Remove __GMP_ASM_L and
+	__GMP_LSYM_PREFIX, revert to ASM_L in gmp-impl.h and AC_DEFINE of
+	LSYM_PREFIX.
+
+2001-07-11  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-h.in (__GMPN_ADD_1 etc) [x86]: Don't use this on egcs 2.91.
+
+	* mpz/fits_uint.c, fits_ulong.c, mpz/fits_ushort.c: Split up fits_u.c.
+	* mpz/fits_u.c: Remove file.
+	* mpz/Makefile.am, macos/Makefile.in: Update.
+
+	* tests/refmpn.c,tests.h (refmpn_copy): New function.
+	* tests/devel/try.c (TYPE_ZERO): No return value from call.
+	(TYPE_MODEXACT_1_ODD, TYPE_MODEXACT_1C_ODD): Share call with
+	TYPE_MOD_1 and TYPE_MOD_1C.
+	(MPN_COPY, __GMPN_COPY, __GMPN_COPY_INCR): Add testing.
+
+2001-07-10  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-h.in (__GMPN_COPY): Add form to help gcc on power and powerpc.
+	* gmp-impl.h (MPN_COPY_INCR, MPN_COPY_DECR, MPN_ZERO): Ditto.
+	* mpn/powerpc64/copyi.asm, mpn/powerpc64/copyd.asm: Remove files.
+
+	* mpz/tdiv_ui.c: Eliminate some local variables (seems to save code on
+	i386 gcc 2.95.x), remove a bogus comment about quotient.
+
+	* errno.c, gmp-impl.h (__gmp_exception, __gmp_divide_by_zero,
+	__gmp_sqrt_of_negative): New functions.
+	* gmp-impl.h (GMP_ERROR, DIVIDE_BY_ZERO, SQRT_OF_NEGATIVE): Use them.
+
+	* randclr.c, randraw.c: Use ASSERT(0) for unrecognised algorithms.
+
+2001-07-07  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (powerpc*-*-*): Use -no-cpp-precomp for Darwin.
+
+	* tests/mpbsd/t-itom.c: Renamed from t-misc.c.
+	* tests/mpbsd/t-misc.c: Remove file.
+	* tests/mpbsd/Makefile.am: Update.
+
+	* tests/mpf/t-set_si.c,t-cmp_si.c,t-gsprec.c: Split from t-misc.c.
+	* tests/mpf/t-misc.c: Remove file.
+	* tests/mpf/Makefile.am: Update.
+
+	* tests/mpz/t-oddeven.c,t-set_si.c,t-cmp_si.c: Split from t-misc.c.
+	* tests/mpz/t-misc.c: Remove file.
+	* tests/mpz/Makefile.am: Update.
+
+	* stack-alloc.c: Add some alignment ASSERTs.
+
+	* gmp-impl.h (MPN_NORMALIZE): Add notes on x86 repe/scasl slow.
+
+	* tests/devel/try.c (MPN_ZERO): Add testing.
+	* tune/speed.c,speed.h,common.c,many.pl (MPN_ZERO): Add measuring.
+
+	* mpn/x86/divrem_1.asm: Update a remark about gcc and "loop".
+
+	* tests/mpq/t-cmp_si.c: New file.
+	* tests/mpq/Makefile.am: Add it.
+
+	* tests/misc.c,tests.h (mpq_set_str_or_abort): New function.
+
+	* mpq/cmp_si.c: New file.
+	* Makefile.am, mpq/Makefile.am: Add it.
+	* gmp-h.in (mpq_cmp_si): Add prototype.
+	* gmp.texi (Comparing Rationals): Add doco.
+
+	* gmp-h.in (_GMP_H_HAVE_FILE): Add _FILE_DEFINED for microsoft, add
+	notes on what symbols are for what systems.
+
+2001-07-06  Torbjorn Granlund  <tege@swox.com>
+
+	* longlong.h (ibm032 umul_ppmm): Fix typo.
+	* longlong.h (sparclite sdiv_qrnnd): Fix typo.
+
+2001-07-03  Kevin Ryde  <kevin@swox.se>
+
+	* mpz/bin_ui.c (DIVIDE): Use MPN_DIVREM_OR_DIVEXACT_1.
+	* mpz/bin_uiui.c (MULDIV): Ditto, and use local variables for size and
+	pointer.
+
+	* acinclude.m4 (GMP_INCLUDE_GMP_H): New macro, use it everywhere gmp.h
+	is wanted at configure time.
+	* acinclude.m4, configure.in (GMP_H_EXTERN_INLINE, GMP_H_HAVE_FILE):
+	New macros.
+
+	* gmp-h.in (__GMP_EXTERN_INLINE): Set to "inline" for C++.
+	(mpn_add, mpn_sub): Use new style __GMP_EXTERN_INLINE.
+	* gmp-h.in, mp-h.in, gmp-impl.h (_EXTERN_INLINE): Remove, unused.
+	* mpn/generic/add.c, mpn/generic/sub.c: New files.
+	* mpn/generic/inlines.c: Remove file.
+	* configure.in, mpn/Makefile.am: Update.
+
+	* gmp.texi (GMP Basics): Note the need for stdio.h to get FILE
+	prototypes.
+
+2001-07-01  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi (Build Options, Reentrancy): Updates for new
+	--enable-alloca behaviour.
+	(Debugging): Describe --enable-alloca=debug.
+	(Miscellaneous Integer Functions): Note mpz_sizeinbase ignores signs.
+	(Low-level Functions): Give a formula for mpn_gcdext cofactor.
+	(Factorial Algorithm): New section.
+	(Binomial Coefficients Algorithm): New section.
+	Misc tweaks elsewhere.
+
+	* mpf/set_prc.c: Merge the two truncation conditionals, misc cleanups,
+	no functional changes.
+
+	* mpn/*/gmp-mparam.h (DIVEXACT_1_THRESHOLD): Add tuned values.
+	* gmp-impl.h (DIVEXACT_1_THRESHOLD): Make the default 0 when
+	2*UMUL_TIME < UDIV_TIME.
+
+	* mpn/x86/p6/dive_1.asm: New file.
+
+	* mpn/x86/dive_1.asm: New file.
+	* mpn/x86/gmp-mparam.h (DIVEXACT_1_THRESHOLD): Use it always.
+
+	* tests/refmpn.c, tests.h (refmpn_zero): New function.
+	* tests/devel/try.c: Use it.
+
+	* tests/refmpn.c (refmpn_sb_divrem_mn): Use refmpn_cmp, not mpn_cmp.
+
+	* tests/mpf/t-get_d.c (main): Use || not |.
+
+	* tests/misc.c, tests/t-modlinv.c, tests/mpq/t-get_str.c,
+	tests/mpf/reuse.c: Add string.h.
+
+2001-06-29  Kevin Ryde  <kevin@swox.se>
+
+	* tune/speed.h (SPEED_ROUTINE_MPN_FIB2_UI,
+	SPEED_ROUTINE_COUNT_ZEROS_C): Corrections to TMP block handling.
+
+	* gmp-impl.h (MPN_TOOM3_MUL_N_MINSIZE, MPN_TOOM3_SQR_N_MINSIZE):
+	Corrections to these to account for adding tD into E.
+	(MPN_INCR_U, MPN_DECR_U) [WANT_ASSERT]: Add size
+	assertions, since mpn_add_1 and mpn_sub_1 from gmp.h don't get them.
+	(MPN_DIVREM_OR_DIVEXACT_1): Add an assert of no remainder.
+
+	* assert.c: Add stdlib.h for abort prototype.
+	* tests/spinner.c, trace.c, t-constants.c, t-count_zeros.c,
+	t-gmpmax.c, t-modlinv.c: Ditto.
+	* tests/mpz/t-bin.c, t-cmp.c, t-get_si.c, t-misc.c, t-popcount.c,
+	t-set_str.c, t-sizeinbase.c: Ditto.
+	* tests/mpq/t-equal.c, t-get_str.c, t-set_f.c, t-set_str.c: Ditto.
+	* tests/mpf/t-fits.c, t-get_d.c, t-get_si.c, t-int_p.c, t-misc.c,
+	t-trunc.c: Ditto.
+	* tests/mpbsd/allfuns.c, t-misc.c: Ditto.
+
+	* mpn/generic/mul_n.c, mpz/cfdiv_r_2exp.c: Use MPN_INCR_U rather than
+	mpn_incr_u.
+
+	* tests/devel/try.c (TYPE_SB_DIVREM_MN): More fixes for calling method.
+
+	* mpn/x86/k6/cross.pl: More insn exceptions.
+
+2001-06-23  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-h.in (__GMPN_ADD_1, __GMPN_SUB_1) [i386]: Fix some asm output
+	constraints.
+
+	* gmp-impl.h (modlimb_invert): Mask after shifting, so mask constant
+	fits a signed byte.
+
+	* tests/devel/try.c (TYPE_SB_DIVREM_MN): Fix initial fill of quotient
+	with garbage.
+
+2001-06-20  Kevin Ryde  <kevin@swox.se>
+
+	* config.guess (rs6000-*-aix4* | powerpc-*-aix4*): Suppress error
+	messages if $CC_FOR_BUILD or program don't work.
+
+	* mpz/sqrt.c,sqrtrem.c: Special case for op==0, to avoid TMP_ALLOC(0).
+	* tests/refmpf.c (refmpf_add, refmpf_sub): Avoid TMP_ALLOC(0).
+
+	* tests/mpn/t-aors_1.c: New file.
+	* tests/mpn/Makefile.am: Add it.
+
+	* gmp-h.in (__GMPN_ADD_1, __GMPN_SUB_1): New macros, rewrite of
+	mpn_add_1 and mpn_sub_1, better code for src==dst and/or n==1,
+	separate versions for gcc x86, gcc generic, and non-gcc.
+	(mpn_add_1, mpn_sub_1): Use them.
+	(mpn_add, mpn_sub): Ditto, to get inlines on all compilers.
+	(extern "C") [__cplusplus]: Let this encompass the extern inlines too.
+	* mpn/generic/add_1.c,sub_1.c: New files, force code from gmp.h.
+	* configure.in, mpn/Makefile.am: Add them.
+
+	* acinclude.m4 (GMP_ASM_LSYM_PREFIX): AC_SUBST __GMP_LSYM_PREFIX
+	rather than AC_DEFINE LSYM_PREFIX.
+	* gmp-h.in (__GMP_LSYM_PREFIX): New substitution.
+	(__GMP_ASM_L): New macro.
+	* gmp-impl.h (ASM_L): Use it.
+
+	* acinclude.m4, configure.in (GMP_C_ATTRIBUTE_MALLOC): New macro.
+	* gmp-impl.h: Use it for all the malloc based TMP_ALLOCs.
+
+	* stack-alloc.h: Remove file.
+	* tal-reent.c: New file.
+	* Makefile.am: Update.
+
+	* acinclude.m4, configure.in (GMP_OPTION_ALLOCA): New macro, add
+	malloc-reentrant method, use stack-alloc.c as malloc-notreentrant,
+	make "reentrant" the default.
+	* gmp-impl.h (__TMP_ALIGN): Moved from stack-alloc.c, use a union to
+	determine the value, and demand only 4 bytes align on 32-bit systems.
+	* gmp-impl.h (WANT_TMP_NOTREENTRANT): Move global parts of
+	stack-alloc.h to here, allow non power-of-2 __TMP_ALIGN in TMP_ALLOC.
+	* gmp-impl.h: Extend extern "C" to TMP_ALLOC declarations.
+	* stack-alloc.c (tmp_stack): Move private parts of stack-alloc.h to
+	here, use gmp-impl.h.
+
+	* gmp-impl.h (TMP_ALLOC_LIMBS_2): New macro.
+	* mpz/fib_ui.c, mpz/jacobi.c, mpq/cmp.c, mpn/generic/fib2_ui.c: Use it.
+
+	* mpfr/exp2.c: Patch by Paul to match TMP_MARK and TMP_FREE in loop.
+	* mpfr/sqrt.c: Scope nested TMP_DECL into nested { } block, patch by
+	Paul, tweaked by me.
+	* mpfr/agm.c: Ditto, and add a final TMP_FREE(marker2).
+
+	* gmp-h.in (mpn_cmp): Add __GMP_ATTRIBUTE_PURE.
+
+	* INSTALL: Clarify "make install", tweak formatting a bit.
+
+2001-06-17  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in, Makefile.am, gmp-impl.h: Add a debugging TMP_ALLOC,
+	selected with --enable-alloca=debug.
+	* tal-debug.c: New file.
+	* configure.in, Makefile.am: Compile stack-alloc.c only for
+	--disable-alloca.
+	* assert.c (__gmp_assert_header): New function, split from
+	__gmp_assert_fail.
+
+	* mpz/lcm.c: Don't TMP_MARK and then just return. Remove unnecessary
+	_mpz_realloc prototype.
+
+	* mpn/generic/mul.c (mpn_sqr_n): Use __gmp_allocate_func for toom3
+	temporary workspace.
+
+2001-06-15  Kevin Ryde  <kevin@swox.se>
+
+	* tests/mpz/t-set_f.c: New file.
+	* tests/mpz/Makefile.am (check_PROGRAMS): Add it.
+
+	* mpz/set_f.c: Share MPN_COPY between pad and trunc cases, do exp<=0
+	test earlier, store SIZ(w) earlier.
+
+	* tests/t-count_zeros.c: New file.
+	* tests/t-gmpmax.c: New file.
+	* tests/Makefile.am (check_PROGRAMS): Add them.
+
+	* mp_clz_tab.c: Compile the table only if longlong.h says it's needed;
+	add an internal-use-only comment.
+	* tune/common.c: Force a __clz_tab for convenience when testing.
+
+	* mpn/x86/pentium/gmp-mparam.h, mpn/x86/pentium/mmx/gmp-mparam.h: Add
+	COUNT_LEADING_ZEROS_NEED_CLZ_TAB, for mod_1.asm.
+
+	* longlong.h (count_leading_zeros) [pentium]: Decide to go with float
+	method for p54.
+	(count_leading_zeros) [alpha]: Add COUNT_LEADING_ZEROS_NEED_CLZ_TAB.
+	(__clz_tab): Provide a prototype only if it's needed.
+
+	* tests/trace.c (mpz_trace): Don't use = on structures.
+	(mpn_trace): Set _mp_alloc when creating mpz.
+
+2001-06-12  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/x86/divrem_1.asm: Amend some comments about P5 speed.
+
+	* tune/README: Clarify reconfigure on gmp-mparam.h update.
+
+	* mpn/x86/p6/copyd.asm: New file.
+	* mpn/x86/p6/README: Update copyd and mod_1.
+	* mpn/x86/copyd.asm: Amend some comments.
+
+	* gmp-impl.h (__builtin_constant_p): Add dummy for non-gcc.
+	(mpn_incr_u, mpn_decr_u): Recognise incr==1 at compile time in the
+	generic code on gcc.
+
+	* gmp-impl.h (ASSERT_ZERO_P, ASSERT_MPN_NONZERO_P): New macros.
+	* mpn/generic/gcd_1.c, mpn/generic/mul_fft.c: Use them.
+	* mpz/get_d.c: Add a private mpn_zero_p.
+	* mpfr/trunc.c: Use own mpn_zero_p.
+	* tune/speed.h (SPEED_ROUTINE_MPN_GCD_1N): Use refmpn_zero_p.
+	* gmp-impl.h (mpn_zero_p): Remove, no longer needed.
+
+	* gmp-h.in, gmp-impl.h: Move MPN_CMP to gmp.h as __GMPN_CMP, leave an
+	MPN_CMP alias in gmp-impl.h.
+	* gmp-h.in (mpn_cmp): Add an inline version.
+	* mpn/generic/cmp.c: Use __GMP_FORCE_mpn_cmp to get code from gmp.h.
+
+	* acinclude.m4 (GMP_C_ATTRIBUTE_MODE): New macro.
+	* configure.in: Call it.
+	* gmp-impl.h (SItype etc): Use it.
+
+	* randraw.c (lc): Change mpn_mul_basecase->mpn_mul,
+	mpn_incr_u->MPN_INCR_U, abort->ASSERT_ALWAYS(0).
+
+	* longlong.h (count_leading_zeros) [pentiumpro]: Work around a partial
+	register stall on gcc < 3.
+
+	* gmp.texi (Introduction to GMP): Add IA-64.
+	(Notes for Particular Systems): i386 means generic x86.
+
+	* tests/t-modlinv.c: Use tests_start and tests_end.
+
+2001-06-10  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi (Number Theoretic Functions): mpz_jacobi only defined for b
+	odd.  Separate the jacobi/legendre/kronecker descriptions.
+	(Low-level Functions): Document mpn_mul_1 "incr" overlaps.
+	(Language Bindings): New chapter.
+
+	* mpz/jacobi.c: Don't retaining old behaviour of mpz_jacobi on even b
+	(it wasn't documented in 3.1.1).
+	* mpz/jacobi.c, gmp-h.in (mpz_kronecker, mpz_legendre): Remove
+	separate entrypoints, just #define to mpz_jacobi.
+	* compat.c (__gmpz_legendre): Add compatibility entrypoint.
+
+	* mpn/generic/mul_1.c: Allow "incr" style overlaps.
+	* tests/devel/try.c (param_init): Test this.
+
+	* mpf/mul_ui.c: Do size==0 test earlier.
+
+2001-06-08  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-impl.h (ULONG_HIGHBIT, UINT_HIGHBIT, USHRT_HIGHBIT): Cast
+	ULONG_MAX etc to unsigned long etc before attempting to right shift.
+
+	* acinclude.m4 (GMP_ASM_LSYM_PREFIX): Add an AC_DEFINE of LSYM_PREFIX.
+	* gmp-impl.h (ASM_L): New macro.
+	(mpn_incr_u, mpn_decr_u, MPN_INCR_U, MPN_DECR_U): Add i386 optimized
+	versions.
+
+	* mpn/hppa/*.s,S,asm: Use .label so the code works with gas on hppa
+	GNU/Linux too, reported by LaMont Jones <lamont@smallone.fc.hp.com>.
+	* mpn/hppa/README: Add some notes on this.
+	* acinclude.m4 (GMP_ASM_LABEL_SUFFIX): Ditto.
+
+	* mpn/Makefile.am (nodist_libdummy_la_SOURCES): Add dive_1.c,
+	fib2_ui.c.
+
+	* tests/mpn/t-iord_u.c: New file.
+	* tests/mpn/Makefile.am (check_PROGRAMS): Add it.
+
+	* configure.in (mips*-*-irix[6789]*): Make ABI=n32 the default, same
+	as in gmp 3.1.
+	* gmp.texi (ABI and ISA): Update.
+
+	* gmp.texi (Build Options): Misc tweaks.
+	(Notes for Particular Systems): Describe windows DLL handling.
+	(Known Build Problems): DJGPP needs bash 2.04.
+	(Number Theoretic Functions): mpz_invert returns 0<=r<modulus; add
+	mpz_fib2_ui, mpz_lucnum_ui, mpz_lucnum2_ui.
+	(Fibonacci Numbers Algorithm): Update for new formulas used.
+	(Lucas Numbers Algorithm): New section.
+
+	* tune/speed.c,speed.h,common.c,many.pl: Add mpn_fib2_ui, mpz_fib2_ui,
+	mpz_lucnum_ui, mpz_lucnum2_ui.
+	* demos/expr/exprz.c,README: Add lucnum.
+	* demos/perl/GMP.pm,GMP.xs,GMP/Mpz.pm,test.pl: Add fib2, lucnum,
+	lucnum2.
+
+	* tests/mpz/t-lucnum_ui.c: New file.
+	* tests/mpz/Makefile.am (check_PROGRAMS): Add it.
+	* tests/mpz/t-fib_ui.c: Check mpz_fib2_ui too, updates for new style
+	MPN_FIB2_SIZE.
+
+	* tune/tuneup.c, tune/Makefile.am, gmp-impl.h, mpn/*/gmp-mparam.h:
+	Remove FIB_THRESHOLD, no longer required.
+
+	* mpz/fib2_ui.c, mpz/lucnum_ui.c mpz/lucnum2_ui.c: New files.
+	* Makefile.am, mpz/Makefile.am: Add them.
+	* gmp-h.in (mpz_fib2_ui, mpz_lucnum_ui, mpz_lucnum2_ui): Add
+	prototypes.
+
+	* mpn/generic/fib2_ui.c: New file.
+	* configure.in (gmp_mpn_functions): Add it.
+	* gmp-impl.h (mpn_fib2_ui, FIB_TABLE, etc): Add these.
+	* mpz/fib_ui.c: Rewrite.
+
+	* acinclude.m4 (GMP_C_SIZES): Fix _LONG_LONG_LIMB define for mp_limb_t
+	size test.
+	(GMP_FUNC_ALLOCA): Add dummy __GMP_BITS_PER_MP_LIMB for gmp-h.in work.
+
+	* configure.in (CPPFLAGS): Remove -D__GMP_WITHIN_GMP, don't want it
+	everywhere.
+	* Makefile.am, mpn/Makefile.am, mpz/Makefile.am, mpq/Makefile.am,
+	mpf/Makefile.am, mpbsd/Makefile.am (INCLUDES): Set -D__GMP_WITHIN_GMP.
+
+	* configure.in (*-*-msdosdjgpp*): Forcibly disable shared libraries,
+	to make libtests.la work.
+
+	* acconfig.h (_LONG_LONG_LIMB, HAVE_MPFR): Remove dummy defines, no
+	longer needed.
+
+	* mpz/set_ui.c: Store to _mp_d[0] unconditionally.
+
+2001-05-27  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in, gmp-h.in, mp-h.in: Add support for windows DLLs.
+
+2001-05-26  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi (ABI and ISA, Reentrancy): Minor tweaks
+	(Notes for Package Builds): Note gmp.h is a generated file.
+	(Notes for Particular Systems): -march=pentiumpro is used for gcc
+	2.95.4 and up.
+	(Assembler Loop Unrolling): Mention non power-of-2 unrolling.
+	(Internals): New chapter.
+	* mpf/README: Remove file.
+
+	* demos/expr/README: Miscellaneous rewordings.
+
+	* demos/perl: New directory.
+	* demos/Makefile.am: Add it.
+	* demos/perl/INSTALL, Makefile.PL, GMP.pm, GMP.xs, typemap,
+	GMP/Mpz.pm, GMP/Mpq.pm, GMP/mpf.pm, GMP/Rand.pm, sample.pl, test.pl:
+	New files.
+
+	* configure, aclocal.m4: Update to autoconf 2.50.
+
+	* configure, aclocal.m4, ltmain.sh: Update to libtool 1.4.
+
+	* configure, aclocal.m4, missing, ansi2knr.c, */Makefile.in: Update to
+	automake 1.4f.
+	* Makefile.am: Conditionalize mpfr in $(SUBDIRS) to handle mpfr.info.
+	* mpfr/Makefile.am (INFO_DEPS): Remove previous mpfr.info handling.
+	* mpn/Makefile.am (GENERIC_SOURCES): Remove this, just put mp_bases.c
+	in libmpn_la_SOURCES.
+	* tests/Makefile.am (tests.h): Move from EXTRA_HEADERS to
+	libtests_la_SOURCES.
+	* ltconfig: Remove file, no longer needed.
+
+	* Makefile.am (gmp-impl.h, longlong.h, stack-alloc.h): Move from
+	EXTRA_DIST to libgmp_la_SOURCES, so they get included in TAGS.
+	* tests/rand/Makefile.am (gmpstat.h): Move to libstat_la_SOURCES
+	similarly.
+
+	* config.guess (68k-*-*): Use $SHELL not "sh", tweak some comments.
+
+	* mpfr/mpfr.texi (Introduction to MPFR): Tweak table formatting, note
+	non-free programs must be able to be re-linked.
+
+2001-05-20  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/powerpc64/addmul_1.asm, mpn/powerpc64/mul_1.asm,
+	mpn/powerpc64/submul_1.asm: Add carry-in entrypoints.
+
+2001-05-17  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi (ge): Fix definition for info.
+	(Notes for Particular Systems): Mention 68k dragonball and cpu32.
+	(Efficiency): Add static linking, more about in-place operations,
+	describe mpq+/-integer using addmul.
+	(Reporting Bugs): A couple of words about self-contained reports.
+	(Floating-point Functions): Note exponent limitations of mpf_get_str
+	and mpf_set_str.
+	(Initializing Floats): Clarify mpf_get_prec, mpf_set_prec and
+	mpf_set_prec_raw a bit.
+	(Float Comparison): Note current mpf_eq deficiencies.
+
+	* gmp-h.in (__GMP_HAVE_CONST, __GMP_HAVE_PROTOTYPES,
+	__GMP_HAVE_TOKEN_PASTE): Merge GNU ansidecl.h tests for ANSI compilers.
+	* demos/expr/expr-impl-h.in: Ditto.
+
+	* gmp-impl.h (BITS_PER_MP_LIMB): Define from __GMP_BITS_PER_MP_LIMB if
+	not already in gmp-mparam.h.
+	* tests/t-constants.c (BITS_PER_MP_LIMB, __GMP_BITS_PER_MP_LIMB):
+	Check these are the same.
+
+	* gmp-h.in (mpf_get_default_prec, mpf_get_prec, mpf_set_default_prec,
+	mpf_set_prec_raw): Provide "extern inline" versions, use __GMPF on the
+	macros.
+	* mpf/get_dfl_prc.c, mpf/get_prc.c, mpf/set_dfl_prc.c,
+	mpf/set_prc_raw.c: Get code from gmp.h using __GMP_FORCE.
+
+	* gmp-h.in, gmp-impl.h (__gmp_default_fp_limb_precision): Move from
+	gmp-impl.h to gmp-h.in.
+	(__GMPF_BITS_TO_PREC, __GMPF_PREC_TO_BITS): Ditto, and use __GMPF
+	prefix and add a couple of casts.
+	* gmp-h.in (__GMP_MAX): New macro.
+	* mpf/init2.c mpf/set_prc.c: Update for __GMPF prefix.
+
+	* gmp-h.in (__GMP_BITS_PER_MP_LIMB): New templated define.
+	* acinclude.m4 (GMP_C_SIZES): Add AC_SUBST __GMP_BITS_PER_MP_LIMB,
+	remove AC_DEFINE BITS_PER_MP_LIMB.
+
+2001-05-13  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-h.in, gmp.texi, Makefile.am, mpz/Makefile.am, tests/mpz/t-pow.c:
+	Remove mpz_si_pow_ui, pending full si support.
+	* mpz/si_pow_ui.c: Remove file.
+
+2001-05-11  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/x86/pentium/dive_1.asm: New file.
+
+	* mpn/powerpc32/umul.asm: Use r on registers.
+	* mpn/powerpc64/umul.asm: New file.
+	* configure.in (powerpc*-*-*): Enable umul in extra_functions.
+
+	* tests/refmpn.c, tests/tests.h (refmpn_umul_ppmm): Use same arguments
+	as normal mpn_umul_ppmm.
+	(refmpn_mul_1c): Update.
+	* tests/devel/try.c, tune/many.pl: Add some umul_ppmm testing support.
+
+	* mpn/x86/k6/mmx/popham.asm, mpn/x86/k7/mmx/popham.asm: Don't support
+	size==0.
+	* mpn/x86/pentium/popcount.asm, mpn/x86/pentium/hamdist.asm: Ditto,
+	and shave a couple of cycles from the PIC entry code.
+
+	* mpz/mul.c: Use mpn_mul_1 for size==1 and mpn_mul_2 (if available)
+	for size==2, to avoid copying; do vsize==0 test earlier.
+
+	* mpf/sub.c: Test r!=u before calling mpf_set.
+	* mpf/add.c: Ditto, and share mpf_set between usize==0 and vsize==0.
+
+	* mpn/generic/tdiv_qr.c, mpq/get_d.c, mpf/div.c, mpf/set_q.c,
+	mpf/set_str.c, mpf/ui_div.c: Test for high bit set, not for
+	count_leading_zeros zero.
+
+	* acinclude.m4 (GMP_PROG_AR, GMP_PROG_NM): Print a message if extra
+	flags are added.
+
+	* tests/mpz/t-mul_i.c: New file.
+	* tests/mpz/Makefile.am: Add it.
+
+	* mpz/mul_siui.c (mpz_mul_si): Fix for -0x80..00 on long long limb.
+
+	* gmp-h.in (mpf_set_si, mpf_set_ui): Revert last change, set exp to 0
+	when n==0.
+	* mpf/ceilfloor.c, mpf/trunc.c: Fix exp to 0 when setting r to 0.
+	* gmp-impl.h (MPF_CHECK_FORMAT): Check exp==0 when size==0.
+
+2001-05-07  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-h.in (mpf_set_si, mpf_set_ui): Don't bother setting _mp_exp to 0
+	when n==0 (use 1 unconditionally).
+	* tests/mpf/t-misc.c (check_mpf_set_si): Don't demand anything of
+	_mp_exp when _mp_size is zero.
+
+	* mpn/x86/README: Note gas _GLOBAL_OFFSET_TABLE_ with leal problem.
+
+	* gmp-h.in (mpz_fits_uint_p, mpz_fits_ulong_p, mpz_fits_ushort_p):
+	Provide these as "extern inline"s.
+	(__GMP_UINT_MAX, __GMP_ULONG_MAX, __GMP_USHRT_MAX): New macros.
+	(mpz_popcount): Use __GMP_ULONG_MAX.
+	* gmp-impl.h (UINT_MAX, ULONG_MAX, USHRT_MAX): Use __GMP_U*_MAX, if
+	not already defined.
+	* mpz/fits_u.c: Use the code from gmp.h.
+
+2001-05-06  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/x86/k7/dive_1.asm: New file.
+	* mpn/x86/k7/gcd_1.asm: New file.
+	* mpn/asm-defs.m4 (m4_count_trailing_zeros): New macro.
+
+	* gmp-h.in (mpz_get_ui, mpz_getlimbn, mpz_set_q, mpz_perfect_square_p,
+	mpz_popcount, mpz_size, mpf_set_ui, mpf_set_si, mpf_size): Provide
+	these as "extern inlines".
+	Use just one big extern "C" block.
+	* mpz/getlimbn.c, mpz/get_ui.c, mpz/perfsqr.c, mpz/popcount.c
+	mpz/set_q.c, mpz/size.c, mpf/set_si.c, mpf/set_ui.c, mpf/size.c: Use
+	__GMP_FORCE to get code from gmp.h.
+
+2001-05-03  Kevin Ryde  <kevin@swox.se>
+
+	* extract-dbl.c: Add ASSERT d>=0.
+
+	* gmp.texi (Efficiency): Add mpz_addmul etc for mpz+=integer, add
+	mpz_neg etc in-place.
+	(Integer Arithmetic): Add mpz_addmul, mpz_submul, mpz_submul_ui.
+	(Initializing Rationals): Add mpq_set_str.
+	(Low-level Functions): mpn_set_str requires strsize >= 1.
+
+	* gmp-h.in (__GMP_EXTERN_INLINE, __GMP_ABS): New macros.
+	(mpz_abs, mpq_abs, mpf_abs, mpz_neg, mpq_neg, mpf_neg): Provide inline
+	versions.
+	* mpz/abs.c, mpq/abs.c, mpf/abs.c, mpz/neg.c, mpq/neg.c, mpf/neg.c:
+	Add suitable __GMP_FORCE to turn off inline versions.
+
+	* tests/mpz/t-aorsmul.c,t-cmp_d.c,t-popcount,t-set_str.c: New files.
+	* tests/mpz/Makefile.am: Add them.
+
+	* mpz/aorsmul_i.c: New file, rewrite of addmul_ui.c.  Add
+	mpz_submul_ui entrypoint, share more code between some of the
+	conditionals, use mpn_mul_1c if available.
+	* mpz/addmul_ui.c: Remove file.
+	* mpz/aorsmul.c: New file.
+	* Makefile.am, mpz/Makefile.am: Update.
+	* gmp-h.in (mpz_addmul, mpz_submul, mpz_submul_ui): Add prototypes.
+	* gmp-impl.h (mpz_aorsmul_1): Add prototype.
+
+	* tests/mpq/t-set_str.c: New file.
+	* tests/mpq/Makefile.am: Add it.
+
+	* mpq/set_str.c: New file.
+	* Makefile.am, mpq/Makefile.am: Add it.
+	* gmp-h.in (mpq_set_str): Add prototype.
+
+	* mpz/set_str.c: Fix for trailing white space on zero, eg. "0 ".
+	* mpn/generic/set_str.c: Add ASSERT str_len >= 1.
+
+	* gmp-h.in, gmp-impl.h (mpn_incr_u, mpn_decr_u): Move to gmp-impl.h.
+	* gmp-impl.h (MPN_INCR_U, MPN_DECR_U): New macros.
+
+2001-04-30  Kevin Ryde  <kevin@swox.se>
+
+	* tests/mpz/t-lcm.c: New file.
+	* tests/mpz/Makefile.am (check_PROGRAMS): Add it.
+
+	* mpz/lcm.c: Add one limb special case.
+
+	* mpz/lcm_ui.c: New file.
+	* Makefile.am, mpz/Makefile.am: Add it.
+	* gmp-h.in (mpz_lcm_ui): Add prototype.
+	* gmp.texi (Number Theoretic Functions): Add mpz_lcm_ui, document lcm
+	now always positive.
+
+	* mp-h.in (mp_size_t, mp_exp_t): Fix typedefs to match gmp-h.in.
+
+	* gmp-h.in (mpn_add_1, mpn_add, mpn_sub_1, mpn_sub): Remove K&R
+	function defines (ansi2knr will handle mpn/inline.c, and just ansi is
+	enough for gcc extern inline).
+
+	* gmp-h.in (__GMP_HAVE_TOKEN_PASTE): New macro.
+	(__MPN): Use it.
+	* gmp-impl.h (CNST_LIMB): Ditto.
+
+	* gmp-h.in, mp-h.in (__gmp_const, __gmp_signed, _PROTO, __MPN): Use
+	ANSI forms on Microsoft C.
+	(__GMP_HAVE_CONST): New define.
+	* gmp-impl.h (const, signed): Use it.
+
+	* demos/expr/expr-impl-h.in (<stdarg.h>): Use this with Microsoft C.
+	(HAVE_STDARG): New define.
+	* demos/expr/expr.c,exprz.c,exprq.c,exprf.c,exprfr.c: Use it.
+
+	* acinclude.m4 (GMP_C_STDARG): New macro.
+	* configure.in: Call it.
+	* rand.c: Use it.
+
+	* configure.in (AC_PROG_CC_STDC): New test.
+
+2001-04-25  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/x86/k6/mmx/dive_1.asm: New file.
+	* mpn/x86/x86-defs.m4 (Zdisp): Two more insns.
+
+	* mpn/x86/pentium/mul_2.asm: New file.
+	* mpn/asm-defs.m4: Add define_mpn(mul_2).
+	* acconfig.h (HAVE_NATIVE_mpn_divexact_1, mul_2): Add templates.
+
+	* configure.in (ABI): Use AC_ARG_VAR.
+
+	* tests/devel/try.c: Run reference function when validate fails.
+
+	* mpq/get_str.c: Fixes for negative bases.
+	* tests/mpq/t-get_str.c: Check negative bases.
+	* tests/misc.c,tests.h (__gmp_allocate_strdup, strtoupper): New
+	functions.
+
+2001-04-24  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/lcm.c (mpz_lcm): Make result always positive.
+
+	* gmp-h.in (mpz_inp_binary, mpz_out_binary): Remove declarations.
+
+2001-04-22  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/powerpc64/addsub_n.asm: Use config.m4 not asm-syntax.m4.
+
+	* mpz/cmp_d.c, mpz/cmpabs_d.c: New files.
+	* Makefile.am, mpz/Makefile.am: Add them.
+	* mpf/cmp_d.c, mpf/get_dfl_prec.c: New files.
+	* Makefile.am, mpf/Makefile.am: Add them.
+	* gmp-h.in (mpz_cmp_d, mpz_cmpabs_d, mpf_cmp_d, mpf_get_default_prec):
+	Add prototypes.
+	* gmp.texi: Add documentation.
+
+	* mpf/set_prc.c: Avoid a realloc call if already the right precision.
+
+	* gmp-impl.h (MPF_BITS_TO_PREC, MPF_PREC_TO_BITS): New macros.
+	* mpf/get_prc.c, init2.c, set_dfl_prec.c, set_prc.c, set_prc_raw.c:
+	Use them.
+
+2001-04-20  Kevin Ryde  <kevin@swox.se>
+
+	* tests/devel/try.c: Don't test size==0 on mpn_popcount and
+	mpn_hamdist; add testing for mpn_divexact_1; print some limb values
+	with mpn_trace not printf.
+
+	* mpz/popcount.c, mpz/hamdist.c: Don't pass size==0 to mpn_popcount
+	and mpn_hamdist.
+	* mpn/generic/popham.c: Don't support size==0.
+
+	* config.guess (m68k-*-*): Detect m68010, return m68360 for cpu32,
+	cleanup the nesting a bit.
+
+	* gmp.texi (Integer Division): Fix mpz_congruent_2exp_p "c" type.
+	(Integer Division): Add mpz_divexact_ui.
+	(Number Theoretic Functions): Fix mpz_nextprime return type.
+	(Exact Remainder): Divisibility tests now implemented.
+	And more index entries in a few places.
+
+	* tests/mpz/dive_ui.c: New file.
+	* tests/mpz/Makefile.am (check_PROGRAMS): Add it.
+
+	* mpz/dive_ui.c: New file.
+	* Makefile.am, mpz/Makefile.am: Add it.
+	* gmp-h.in (mpz_divexact_ui): Add prototype.
+
+	* tune/many.pl, tune/speed.h: Add special mpn_back_to_back for
+	development.
+
+	* gmp-impl.h (MPN_DIVREM_OR_DIVEXACT_1): New macro.
+	* mpz/divexact.c: Use it.
+
+	* gmp-impl.h (DIVEXACT_1_THRESHOLD): New threshold.
+	* tune/tuneup.c: Tune it.
+
+	* tune/speed.c,speed.h,common.c,many.pl: Add measuring of
+	mpn_divexact_1, mpn_copyi, mpn_copyd.
+
+	* mpn/generic/dive_1.c: New file.
+	* configure.in (gmp_mpn_functions): Add it.
+	* gmp-impl.h (mpn_divexact_1): Add prototype.
+	* mpn/asm-defs.m4: Add define_mpn(divexact_1).
+
+	* tests/mpn: New directory.
+	* tests/Makefile.am: Add it.
+	* tests/mpn/Makefile.am: New file.
+	* configure.in (AC_OUTPUT): Add it.
+	* tests/mpn/t-asmtype.c: New file.
+
+	* configure, config.in: Update to autoconf 2.49d.
+
+	* configure.in, gmp-h.in, mp-h.in, demos/expr/expr-impl-h.in: Revert
+	to generating gmp.h, mp.h and expr-impl.h with AC_OUTPUT and AC_SUBST.
+
+	* configure.in (m68*-*-*): Oops, m683?2 is 68000, m68360 is cpu32.
+	* mpn/m68k/m68k-defs.m4 (scale_available_p): Ditto.
+
+	* configure.in (underscore, asm_align): Remove these variables, unused.
+	(GMP_ASM_*): Sort by AC_REQUIREs, to avoid duplication.
+	* acinclude.m4 (GMP_ASM_UNDERSCORE, GMP_ASM_ALIGN_LOG): Remove support
+	for actions, no longer needed.
+
+2001-04-17  Kevin Ryde  <kevin@swox.se>
+
+	* config.guess (m68k-*-*): Look for cpu in linux kernel /proc/cpuinfo.
+
+	* acinclude.m4 (GMP_GCC_MARCH_PENTIUMPRO): The -mpentiumpro problem is
+	fixed in 2.95.4, so test for that.
+	(GMP_ASM_TYPE): Amend some comments.
+
+	* tune/freq.c (speed_cpu_frequency_sysctl): Avoid having unused
+	variables on GNU/Linux.
+
+	* mpn/asm-defs.m4 (m4_instruction_wrapper): Fix a quoting problem if
+	the name of the file is a macro.
+
+2001-04-15  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/powerpc64/*.asm: Add speeds on ppc630.
+
+	* acconfig.h: Add dummy templates for _LONG_LONG_LIMB and HAVE_MPFR.
+	* configure.in: Ensure config.in is the last AM_CONFIG_HEADER,
+	which autoheader requires.
+
+	* mpn/x86/pentium/popcount.asm: New file.
+	* mpn/x86/pentium/hamdist.asm: New file.
+
+	* mpn/asm-defs.m4: (m4_popcount): New macro.
+	Amend a few comments elsewhere.
+
+	* acinclude.m4 (GMP_ASM_RODATA): If possible, grep compiler output for
+	the right directive.
+
+	* tune/speed.c: Print clock speed in MHz, not cycle time.
+
+	* configure.in (AC_CHECK_HEADERS): Check for sys/processor.h.
+	* tune/freq.c (speed_cpu_frequency_processor_info): Require
+	<sys/processor.h> to exist, to differentiate the different
+	processor_info on Darwin.
+	(speed_cpu_frequency_sysctlbyname): Remove hw.model test which is in
+	speed_cpu_frequency_sysctl.
+	(speed_cpu_frequency_sysctl): Add hw.cpufrequency for Darwin.
+
+	* gmp-impl.h (MPN_LOGOPS_N_INLINE, mpn_and_n ... mpn_xnor_n): Use a
+	single expression argument for the different operations, necessary for
+	the Darwin "smart" preprocessor.
+
+	* mpn/m68k/t-m68k-defs.pl: Allow white space in m4_definsn and
+	m4_defbranch.
+
+	* tune/many.pl: Change RM_TMP_S to RM_TMP to match mpn/Makeasm.am,
+	avoid a possibly undefined array in a diagnostic, add more renaming to
+	hamdist.
+
+2001-04-13  Kevin Ryde  <kevin@swox.se>
+
+	* ltmain.sh, aclocal.m4, configure, config.in: Update to libtool 1.3d.
+	* configure.in: Change ac_ to lt_ in lt_cv_archive_cmds_need_lc and
+	lt_cv_proc_cc_pic.
+
+	* config.guess (m68*-*-*): Detect exact cpu with BSD sysctl hw.model,
+	detect 68000/68010 with trapf, detect 68302 with bfffo.
+
+2001-04-11  Kevin Ryde  <kevin@swox.se>
+
+	* acinclude.m4 (GMP_ASM_M68K_INSTRUCTION, GMP_ASM_M68K_ADDRESSING,
+	GMP_ASM_M68K_BRANCHES): New macros.
+	* configure.in: Use them, remove old 68k configs, use mc68020 udiv and
+	umul.
+
+	* mpn/m68k/m68k-defs.m4: New file.
+	* mpn/m68k/t-m68k-defs.pl: New file.
+	* mpn/m68k/*.asm: New files, converted from .S.  Merge add_n and sub_n
+	to aors_n, ditto mc68020 addmul_1 and submul_1 to aorsmul_1.  No
+	object code changes (except .type and .size now used on NetBSD 1.4).
+	* mpn/m68k/README: New file.
+	* mpn/m68k/*.S, */*.S, syntax.h: Remove files.
+
+	* configure.in (m68*-*-netbsd1.4*): Pretend getrusage doesn't exist.
+	* tune/README: Update.
+
+	* configure.in (powerpc*-*-*): For the benefit of Darwin 1.3, add cc
+	to cclist, make gcc_cflags -Wa,-mppc optional.
+
+2001-04-06  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/lisp/gmpasm-mode.el (gmpasm-comment-start-regexp): Add | for 68k.
+	(gmpasm-mode-syntax-table): Add to comments.
+
+	* tests/mpz/reuse.c (dsi_div_func_names): Add names for cdiv_[qr]_2exp.
+
+2001-04-04  Kevin Ryde  <kevin@swox.se>
+
+	* acinclude.m4 (GMP_M4_M4WRAP_SPURIOUS): Fix test so as to actually
+	detect the problem, add notes on m68k netbsd 1.4.1.
+
+	* gmp.texi (Compatibility with older versions): Note libmp
+	compatibility.
+
+2001-04-03  Kevin Ryde  <kevin@swox.se>
+
+	* tests/mpz/reuse.c: Add mpz_cdiv_q_2exp and mpz_cdiv_r_2exp.
+
+	* tests/mpz/t-pow.c: Drag in refmpn.o when testing mpz_pow_ui etc with
+	refmpn_mul_2.
+
+	* tune/speed.c,speed.h,common.c,many.pl: Add measuring of mpn_com_n
+	and mpn_mul_2.
+	* tests/devel/try.c: Add testing of mpn_mul_2, and a
+	DATA_MULTIPLE_DIVISOR attribute.
+
+	* gmp.texi (Build Options): List more m68k's.
+	(Build Options): Add cross reference to tex2html.
+	(Notes for Particular Systems): Add m68k means 68020 or up.
+	(Rational Conversions): New section, with mpq_get_d, mpq_set_d and
+	mpq_set_f from Miscellaneous, and new mpq_set_str.
+	(Applying Integer Functions): Move mpq_get_num, mpq_get_den,
+	mpq_set_num and mpq_set_den from Misc.
+	(Miscellaneous Rational Functions): Remove section.
+	(Custom Allocation): Partial rewrite for various clarifications.
+	(References): Improve line breaks near URLs.
+
+	* acinclude.m4 (GMP_GCC_M68K_OPTIMIZE): New macro.
+	* configure.in (m68*-*-*): Use it to run gcc 2.95.x at -O not -O2.
+	(m680?0-*-*, m683?2-*-*, m68360-*-*): Add optional gcc -m options.
+
+	* tests/mpz/t-cmp.c: New file.
+	* tests/mpz/t-sizeinbase.c: New file.
+	* tests/mpz/Makefile.am: Add them.
+
+	* gmp-impl.h (MPN_CMP): New macro.
+	* mpz/cmp.c,cmpabs.c: Use it, and minor cleanups too.
+
+	* tests/mpq/t-equal.c: New file.
+	* tests/mpq/t-get_str.c: New file.
+	* tests/mpq/Makefile.am: Add them.
+
+	* mpq/get_str.c: New file.
+	* Makefile.am, mpq/Makefile.am: Add it.
+	* gmp-h.in (mpq_get_str): Add prototype.
+
+	* mpq/equal.c: Rewrite using inline compare loops.
+
+	* tests/refmpn.c,tests.h (refmpn_mul_2): Fix parameter order.
+	* mpz/n_pow_ui.c: Fix mpn_mul_2 calls parameter order.
+
+2001-03-29  Kevin Ryde  <kevin@swox.se>
+
+	* tests/mpf/t-trunc.c: New file.
+	* tests/mpf/Makefile.am (check_PROGRAMS): Add it.
+	* gmp-impl.h (MPF_CHECK_FORMAT): New macro.
+
+	* mpf/trunc.c: New file, rewrite of integer.c, preserve prec+1 in
+	copy, don't copy if unnecessary.
+	* mpf/ceilfloor.c: New file likewise, and use common subroutine for
+	ceil and floor.
+	* mpf/integer.c: Remove file.
+	* Makefile.am, mpf/Makefile.am, macos/Makefile.in: Update.
+
+	* acinclude.m4 (GMP_GCC_VERSION_GE): New macro.
+	(GMP_GCC_MARCH_PENTIUMPRO): Use it, remove CCBASE parameter (don't
+	bother checking it's gcc).
+	(GMP_GCC_ARM_UMODSI): New macro.
+	* configure.in (GMP_GCC_MARCH_PENTIUMPRO): Update parameters.
+	(arm*-*-*): Use GMP_GCC_ARM_UMODSI.
+	* gmp.texi (Notes for Particular Systems): Add arm gcc requirements.
+
+2001-03-28  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi (Converting Integers): Document mpz_getlimbn using absolute
+	value and giving zero for N out of range, move to end of section.
+
+	* tests/refmpn.c (refmpn_tdiv_qr): Use refmpn_divmod_1 rather than
+	refmpn_divrem_1.
+	* tests/tests.h: Add some prototypes that were missing.
+
+	* mpz/tdiv_q_ui.c: Remove a comment that belonged to mpz_tdiv_r_ui.
+
+2001-03-26  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/gcdext.c: Handle carry overflow after m*n multiply code
+	in both arms.  Partially combine multiply arms.
+
+2001-03-24  Kevin Ryde  <kevin@swox.se>
+
+	* longlong.h: Add comments to P5 count_leading_zeros.
+
+	* demos/expr/exprz.c,t-expr.c,README: Add congruent_p and divisible_p.
+
+2001-03-23  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi (GMPceil, GMPfloor, ge, le): New macros.
+	(Integer Division, mpn_cmp, mpn_sqrtrem, Algorithms): Use them.
+	(mpn_bdivmod): Refer to mp_bits_per_limb, not BITS_PER_MP_LIMB, and
+	improve formatting a bit.
+	(mpn_lshift, mpn_rshift): Clarify the return values, and use {rp,n}
+	for the destination.
+	Miscellaneous minor rewordings in a few places.
+
+	* mpn/arm/arm-defs.m4: New file.
+	* configure.in (arm*-*-*): Use it.
+	* mpn/arm/*.asm: Use changecom and registers from arm-defs.m4, use L()
+	for local labels.
+
+	* mpn/x86/k6/mmx/com_n.asm: Relax code alignment (same speed).
+
+	* gmp-h.in (__GMP_ATTRIBUTE_PURE): Use __pure__ to avoid application
+	namespace.
+
+	* gmp-impl.h (ABS): Add parens around argument.
+
+2001-03-20  Kevin Ryde  <kevin@swox.se>
+
+	* acinclude.m4 (GMP_PROG_M4): Use AC_ARG_VAR on $M4.
+
+	* acinclude.m4 (GMP_M4_M4WRAP_SPURIOUS): New macro.
+	* configure.in: Use it.
+	* mpn/asm-defs.m4: Ditto.
+
+2001-03-18  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/x86/pentium/logops_n.asm: New file.
+
+	* mpn/x86/k6/k62mmx/copyd.asm: Rewrite, smaller and simpler, faster on
+	small sizes, slower on big sizes (about half the time).
+	* mpn/x86/k6/k62mmx/copyi.asm: Remove file, in favour of generic x86.
+	* mpn/x86/copyi.asm: Add some comments.
+	* mpn/x86/k6/README: Update.
+
+	* mpn/x86/k6/gcd_1.asm: New file.
+
+	* gmp-impl.h (NEG_MOD): Fix type of __dnorm.
+
+	* acinclude.m4 (GMP_C_SIZES): Fix use of __GMP_WITHIN_CONFIGURE.
+
+2001-03-15  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi (GMPabs): New macro.
+	(Float Comparison - mpf_reldiff): Use it.
+	(Integer Comparisons - mpz_cmpabs): Ditto, puts "abs" in info.
+	(Reentrancy): Update notes on old random functions.
+	(Karatsuba Multiplication): Better characterize the effect of basecase
+	speedups on the thresholds, pointed out by Torbjorn.
+
+	* tune/README: Notes on the 1x1 div threshold for mpn_gcd_1.
+
+	* tests/misc.c (mpz_pow2abs_p, mpz_flipbit, mpz_errandomb,
+	mpz_errandomb_nonzero, mpz_negrandom): New functions.
+	(mpz_erandomb, mpz_erandomb_nonzero): Use urandom().
+	* tests/spinner.c (spinner_wanted, spinner_tick): Make global.
+	* tests/tests.h: Update prototypes.
+
+	* tests/mpz/t-cong.c, tests/mpz/t-cong_2exp.c: New files.
+	* tests/mpz/Makefile.am (check_PROGRAMS): Add them.
+
+	* mpz/cong.c, mpz/cong_2exp.c, mpz/cong_ui.c: New files.
+	* Makefile.am, mpz/Makefile.am: Add them.
+	* gmp-impl.h (NEG_MOD): New macro.
+	* gmp-h.in (mpz_congruent_p, mpz_congruent_2exp_p,
+	mpz_congruent_ui_p): Add prototypes.
+	* gmp.texi (Integer Division, Efficiency): Add documentation.
+
+	* mpq/aors.c: No need for ABS on denominator sizes.
+
+	* gmp-impl.h (mpn_divisible_p): Use __MPN.
+
+	* gmp-impl.h (LOW_ZEROS_MASK): New macro.
+	* mpz/divis_ui.c, mpn/generic/divis.c: Use it.
+
+	* mpz/setbit.c: Fix normalization for case of a negative ending up
+	with a zero high limb.
+	* tests/mpz/bit.c (check_single): New test for this problem.
+
+	* configure.in (none-*-*): Fix cclist for default ABI=long.
+
+2001-03-10  Kevin Ryde  <kevin@swox.se>
+
+	* mpz/cfdiv_q_2exp.c: Don't scan for non-zero limbs if they don't
+	matter to the rounding.
+
+	* mpz/get_ui.c: Fetch _mp_d[0] unconditionally, so the code can come
+	out branch-free.
+
+2001-03-08  Kevin Ryde  <kevin@swox.se>
+
+	* tests/devel/try.c (param_init): Fix reference functions for and_n
+	and nand_n.
+
+	* tune/speed.c, tests/devel/try.c: Seed RANDS, not srandom etc.
+	* configure.in (AC_CHECK_FUNCS): Remove srand48 and srandom.
+	* macos/configure (coptions): Remove random/srandom, now unnecessary.
+
+	* configure.in (gmp.h, mp.h, demos/expr/expr-impl.h): Generate using
+	AM_CONFIG_HEADER.
+	(_LONG_LONG_LIMB, HAVE_MPFR): Change to AC_DEFINEs.
+	* gmp-h.in, mp-h.in, demos/expr/expr-impl-h.in: Change to #undef's.
+	* acinclude.m4 (GMP_FUNC_ALLOCA, GMP_C_SIZES): Use gmp-h.in, not gmp.h.
+	* Makefile.am (EXTRA_DIST): Remove gmp-h.in and mp-h.in, now done
+	automatically.
+	* acinclude.m4 (GMP_FUNC_ALLOCA), gmp-impl.h: Set and use
+	__GMP_WITHIN_CONFIGURE rather than GMP_FUNC_ALLOCA_TEST.
+
+	* mpf/random2.c: Use _gmp_rand and RANDS instead of random() for the
+	exponent, ensures full range of values too.
+
+	* tests/mpz/t-div_2exp.c (check_various): Start with d based on i, but
+	don't let it go negative.
+
+	* tune/tuneup.c (KARATSUBA_MUL_THRESHOLD): Limit probing to
+	TOOM3_MUL_THRESHOLD_LIMIT, the size of the workspace in mul_n.c.
+	Use a -1 with this too, so size<LIMIT not <=.
+
+2001-03-07  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/cray/cfp/mul_1.c: Don't call mpn_add_n with size 0.
+	* mpn/cray/cfp/addmul_1.c: Likewise.
+	* mpn/cray/cfp/submul_1.c: Don't call mpn_sub_n with size 0.
+
+	* tests/mpz/t-div_2exp.c (check_various): Start 2nd d loop from 0
+	(avoid problems with Cray compilers).
+
+2001-03-06  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/cray/ieee/submul_1.c: Don't call mpn_sub_n with size 0.
+
+	* mpn/cray/ieee/mul_basecase.c: New file.
+	* mpn/cray/ieee/sqr_basecase.c: New file, derived from mul_basecase.c.
+
+2001-03-06  Kevin Ryde  <kevin@swox.se>
+
+	* tests/devel/try.c (pointer_setup): Allow dst_size == SIZE_SIZE2 for
+	the benefit of mpn_tdiv_qr.
+
+	* tune/tuneup.c (all): Start karatsuba probing at size==4, for the
+	benefit of cray t90 ieee which has speed oddities at size==2.
+
+	* gmp-impl.h (USE_LEADING_REGPARM): Use __GMP_GNUC_PREREQ.
+	Use __GMP_ATTRIBUTE_PURE and ATTRIBUTE_CONST in a few places.
+
+	* gmp-h.in (__GMP_GNUC_PREREQ) New macro.
+	(__GMP_ATTRIBUTE_PURE): New macro, use it in many places.
+
+	* gmp-impl.h, gmp-h.in (mpn_jacobi_base): Move prototype to
+	gmp-impl.h, use ATTRIBUTE_CONST.
+
+	* tune/speed.h (speed_cyclecounter): Inline asm version for i386.
+
+	* mpz/cfdiv_r_2exp.c (cfdiv_r_2exp): Only reread "up" after second
+	realloc, first is under w!=u.
+
+2001-03-05  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/cray/sub_n.c: Rewrite using `majority' logic.
+
+	* mpz/cfdiv_r_2exp.c (cfdiv_r_2exp): Reread `up' after realloc of w.
+
+	* mpn/cray/ieee/mul_1.c: Rewrite.  Streamline multiplications;
+	use `majority' logic.
+	* mpn/cray/ieee/addmul_1.c: Likewise.
+
+	* mpn/cray/add_n.c: Rewrite using `majority' logic.
+
+2001-03-04  Torbjorn Granlund  <tege@swox.com>
+
+	* longlong.h (CRAY udiv_qrnnd): No longer conditional on CRAYMPP.
+	(64-bit hppa add_ssaaaa): New.
+	(64-bit hppa sub_ddmmss): New.
+
+	* mpn/cray/ieee/invert_limb.c: New file.
+
+	* gmp-impl.h (RANDS): Add a `,0' to make it compile on more compilers.
+
+2001-03-03  Kevin Ryde  <kevin@swox.se>
+
+	* mpz/n_pow_ui.c (ULONG_PARITY): Move to gmp-impl.h.
+	* gmp-impl.h (ULONG_PARITY): i386 part from n_pow_ui.c, new generic
+	form by Torbjorn.
+
+	* tests/mpz/t-div_2exp.c: New file, rewrite of t-2exp.c.
+	* tests/mpz/t-2exp.c: Remove file.
+	* tests/mpz/Makefile.am (check_PROGRAMS): Update.
+
+	* gmp-h.in (mpz_cdiv_q_2exp, mpz_cdiv_q_2exp): Add prototypes.
+	* gmp.texi (Integer Division): Add mpz_cdiv_q_2exp and mpz_cdiv_q_2exp.
+
+	* mpz/cfdiv_q_2exp.c: New file, partial rewrite of fdiv_q_2exp.c, add
+	mpz_cdiv_q_2exp entrypoint.
+	* mpz/cfdiv_r_2exp.c: New file, rewrite of fdiv_r_2exp.c, use all mpn,
+	add mpz_cdiv_r_2exp entrypoint.
+	* mpz/fdiv_q_2exp.c, mpz/fdiv_r_2exp.c: Remove files.
+	* mpz/Makefile.am (libmpz_la_SOURCES): Update.
+	* Makefile.am (MPZ_OBJECTS): Ditto.
+
+	* gmp-impl.h (USE_LEADING_REGPARM): Use __i386__ same as longlong.h
+	(REGPARM_2_1, REGPARM_3_1, REGPARM_ATTR): New macros.
+	* mpz/jacobi.c (jac_or_kron): Use them.
+
+	* configure.in (HAVE_ABI_$ABI): Re-enable this for config.m4, with
+	dots changed to underscores (necessary for hppa).
+
+	* tests/mpz/t-divis.c, tests/mpz/t-divis_2exp.c: New files.
+	* tests/mpz/Makefile.am (check_PROGRAMS): Add them.
+
+	* gmp-h.in (mpz_divisible_p, mpz_divisible_ui_p,
+	mpz_divisible_2exp_p): Add prototypes.
+	* gmp.texi (Integer Division): Add mpz_divisible_p.
+	(Efficiency): Add remarks about divisibility testing.
+
+	* mpz/divis.c, mpz/divis_ui.c, mpz/divis_2exp.c: New files.
+	* mpz/Makefile.am (libmpz_la_SOURCES): Add them.
+	* Makefile.am (MPZ_OBJECTS): Ditto.
+
+	* mpn/generic/divis.c: New file.
+	* configure.in (gmp_mpn_functions): Add it.
+	* mpn/Makefile.am (nodist_libdummy_la_SOURCES): Ditto.
+	* gmp-impl.h (mpn_divisible_p): Add prototype.
+
+	* urandom.h: Remove file.
+	* Makefile.am (EXTRA_DIST): Remove it.
+
+	* tests/mpz/convert.c, dive.c, io.c, logic.c, reuse.c, t-2exp.c,
+	t-fdiv.c, t-fdiv_ui.c, t-gcd.c, t-jac.c, t-mul.c, t-pow.c,
+	t-powm.c, t-powm_ui.c, t-root.c, t-sqrtrem.c, t-tdiv.c,
+	t-tdiv_ui.c: Use RANDS, initialized by tests_rand_start.
+
+	* tests/mpz/t-pow.c: New file, being t-pow_ui renamed and with some
+	further tests added.
+	* tests/mpz/t-pow_ui.c: Remove file.
+	* tests/mpz/Makefile.am (check_PROGRAMS): Update.
+
+	* tests/t-modlinv.c: Don't use urandom.h.
+	* tests/mpz/bit.c, tests/mpz/t-scan.c: Ditto.
+	* tests/mpq/t-cmp.c, tests/mpq/t-cmp_ui.c, tests/mpq/t-get_d.c: Ditto.
+	* tests/mpf/reuse.c, t-add.c, t-conv.c, t-dm2exp.c, t-muldiv.c,
+	t-sqrt.c, t-sub.c: Ditto.
+
+	* tests/misc.c (tests_rand_start, tests_rand_end): New functions.
+	(tests_start, tests_end): Use them.
+	(urandom): New function.
+	* tests/tests.h: Add prototypes.
+
+	* mpz/random.c: Rewrite using mpz_urandomb and RANDS.
+	* mpn/generic/random.c: Rewrite using _gmp_rand and RANDS.
+	* mpn/generic/random2.c: Use RANDS not random() etc.
+
+	* gmp-impl.h (__gmp_rands, __gmp_rands_initialized): Add externs.
+	(gmp_randstate_ptr): New typedef.
+	(RANDS, RANDS_CLEAR): New macros.
+
+	* rands.c: New file.
+	* Makefile.am (libgmp_la_SOURCES): Add it.
+
+	* configure.in (mpn_objs_in_libmp): New AC_SUBST.
+	* Makefile.am (libmp_la_DEPENDENCIES): Use it.
+
+2001-03-02  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/pa64/udiv_qrnnd.asm: New file.
+
+2001-03-01  Kevin Ryde  <kevin@swox.se>
+
+	* mpbsd/rpow.c: New file.
+	* mpbsd/Makefile.am (libmpbsd_la_SOURCES): Add it
+	(nodist_libmpbsd_la_SOURCES): Remove pow_ui.c.
+	* Makefile.am (MPBSD_OBJECTS): Add rpow.lo, remove pow_ui.lo.
+	(libmp_la_DEPENDENCIES): Add mpz/n_pow_ui.lo.
+
+	* mpz/ui_pow_ui.c: Rewrite using mpz_n_pow_ui.
+	* mpz/pow_ui.c: Ditto, and no longer provide rpow for mpbsd.
+
+	* mpz/n_pow_ui.c: New file, rewrite of pow_ui.c and ui_pow_ui.c.  Use
+	less temporary memory, strip factors of 2 from the base, use mpn_mul_2
+	if available.
+	* mpz/si_pow_ui.c: New file.
+	* mpz/Makefile.am (libmpz_la_SOURCES): Add them.
+	* Makefile.am (MPZ_OBJECTS): Ditto.
+	* gmp-impl.h (mpz_n_pow_ui): Add prototype.
+	* gmp-h.in (mpz_si_pow_ui): Add prototype.
+	* gmp.texi (Integer Exponentiation): Add mpz_si_pow_ui.
+
+	* acinclude.m4 (GMP_C_SIZES): Add BITS_PER_ULONG.
+	Correction to mp_limb_t working check.
+	* configure.in (limb_chosen): New variable.
+	* tests/t-constants.c (BITS_PER_ULONG): Check this value.
+	Add some reminders about tests that fail on Cray.
+
+	* tests/refmpn.c (refmpn_mul_2): New function.
+	* tests/refmpz.c (refmpz_pow_ui): Copied from tests/mpz/t-pow_ui.c
+	* tests/tests.h: Add prototypes.
+
+	* configure.in (none-*-*): Add ABI=longlong.
+	* doc/configuration (Long long limb testing): Describe it.
+
+	* gmp.texi (Low-level Functions): Move some commented out remarks ...
+	* mpn/generic/mul_basecase.c: ... to here.
+
+	* mpn/x86/README: Note "%=" as an alternative to "1:" in __asm__.
+
+	* tests/trace.c (mp_trace_start): Print "bin" for binary.
+
+	* mpn/generic/dump.c: Add a couple of casts to keep gcc quiet.
+
+	* gmp-h.in (mpn_incr_u, mpn_decr_u): Add parens around arguments.
+
+	* mpbsd/mout.c, mpbsd/mtox.c (num_to_text): Remove unused variable.
+
+	* mpfr/set_d.c (mpfr_get_d2): Declare "q" for 64-bit limbs.
+
+2001-02-28  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/pa64w/udiv_qrnnd.asm: Tune.
+
+2001-02-27  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/pa64w/udiv_qrnnd.asm: New file.
+
+2001-02-26  Torbjorn Granlund  <tege@swox.com>
+
+	* longlong.h (arm): Optimize sub_ddmmss by testing for constant
+	operands.
+	* mpn/arm/invert_limb.asm: New file.
+
+2001-02-24  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/lshift.c: Rewrite.
+	* mpn/generic/rshift.c: Rewrite.
+
+	* longlong.h: Use UWtype for external interfaces that expect mp_limb_t.
+
+	* longlong.h (arm): #define invert_limb.
+
+	* mpn/arm: Make labels have local scope.
+
+	* configure.in (arm*-*-*): Set extra_functions.
+	* longlong.h (arm): #define udiv_qrnnd.
+	* mpn/arm/udiv.asm: New file.
+
+2001-02-24  Kevin Ryde  <kevin@swox.se>
+
+	* tune/many.pl: Add mpn_count_leading_zeros, mpn_count_trailing_zeros
+	and mpn_invert_limb.  Add count_leading_zeros, count_trailing_zeros
+	from a .h file.  Correction to modexact_1_odd prototype.  Support
+	ansi2knr.
+	* tune/speed.h, tune/common.c: Consequent changes.
+
+	* demos/expr/*: Make a few more functions available in expressions,
+	create only libexpr.a, misc minor updates.
+
+	* mpn/Makeasm.am: Add some comments about suffix ordering.
+
+	* tests/refmpn.c (rshift_make, lshift_make): No need to compare
+	unsigned to zero.
+
+	* mpq/mul.c: Detect and optimize squaring.
+
+2001-02-23  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/mips3: Convert files to `.asm'.
+
+	* mpn/arm: Convert files to `.asm'.  Misc cleanups.
+	* mpn/arm/submul_1.asm: New file.
+
+2001-02-21  Kevin Ryde  <kevin@swox.se>
+
+	* tune/tuneup.c (all): Only one compiler print should match, no need
+	for #undef PRINTED_COMPILER.
+
+	* mpfr/mpfr.h (mpfr_sgn): Use mpfr_cmp_ui (patch from Paul).
+
+	* mpz/fib_ui.c: Update some remarks about alternative algorithms.
+	* gmp.texi (Fibonacci Numbers Algorithm): Ditto.
+	(Assigning Floats): Clarify mpf_swap swaps the precisions too.
+	(Low-level Functions): Try to be clearer about negative cofactors.
+
+2001-02-21  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/sparc64/copyi.asm: Streamline for small operands.
+	* mpn/sparc64/add_n.asm: Likewise.
+	* mpn/sparc64/sub_n.asm: Likewise.
+
+	* mpn/sparc64/copyd.asm: New file.
+
+2001-02-20  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/sparc64/lshift.asm: Rewrite.
+	* mpn/sparc64/rshift.asm: Rewrite.
+
+2001-02-19  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/sparc64/add_n.asm: Rewrite using `majority' logic.
+	* mpn/sparc64/sub_n.asm: Likewise.
+
+	* tune/tuneup.c (all): Recognise DECC and MIPSpro compilers.
+
+	* mpn/pa64/sqr_diagonal.asm: Use PROLOGUE/EPILOGUE.
+	* mpn/pa642/sqr_diagonal.asm: Likewise.
+
+	* configure.in (HAVE_ABI_$abi): Disable for now.
+
+	* mpn/asm-defs.m4 (PROLOGUE): Use LABEL_SUFFIX.
+
+	* acinclude.m4 (GMP_ASM_ATTR): New check, for hppa oddities.
+
+2001-02-18  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/hppa/hppa1_1/gmp-mparam.h: New file.
+	* mpn/hppa/hppa2_0/gmp-mparam.h: New file.
+
+	* mpn/pa64/sqr_diagonal.asm: New file.
+	* mpn/pa64w/sqr_diagonal.asm: New file.
+	* mpn/hppa/hppa1_1/sqr_diagonal.asm: New file.
+	* mpn/hppa/hppa2_0/sqr_diagonal.asm: New file.
+
+	* mpn/sparc32/v9/add_n.asm: Use `fitod' instead of `fxtod' for dummy
+	FA-pipeline insns.
+	* mpn/sparc32/v9/sub_n.asm: Likewise.
+
+2001-02-18  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi (Known Build Problems): Notes on make, $* and K&R, misc
+	tweaks elsewhere.
+	(Low-level Functions): Use {} notation in mpn_sqrtrem.
+	(Basecase Multiplication): Mention BASECASE_SQR_THRESHOLD.
+
+	* mpfr/isnan.c (mpfr_number_p): Infinity is not a number.
+	* mpfr/out_str.c: Pass strlen+1 for the block size to free.
+	* mpfr/get_str.c: Correction for realloc to strlen+1.
+
+	* acinclude.m4 (GMP_C_SIZES): Generate an error if mp_limb_t doesn't
+	seem to work for some reason.
+
+2001-02-16  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/sparc32/v9/gmp-mparam.h: Retune.
+
+	* mpn/sparc32/v9/add_n.asm: New file.
+	* mpn/sparc32/v9/sub_n.asm: New file.
+
+	* mpn/sparc32/v9/mul_1.asm: Tune function entry.
+	* mpn/sparc32/v9/addmul_1.asm: Likewise.
+	* mpn/sparc32/v9/submul_1.asm: Likewise.
+
+	* mpn/sparc32/v9/sqr_diagonal.asm: New file.
+
+2001-02-16  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in: Fix flags selection when $CC is a compiler known to us.
+
+	* demos/expr/exprfr.c (e_mpfr_cos, e_mpfr_sin): mpfr_sin_cos now
+	allows NULL for one parameter.
+
+	* mpfr/*: Update to 20010215.
+	* mpfr/trunc.c: Use -DOPERATION scheme, and gmp mpn_zero_p.
+	* mpfr/sqrt.c: Use plain mpn_sqrtrem, not mpn_sqrtrem_new.
+	* mpfr/sqrtrem.c: Remove file.
+	* mpfr/Makefile.am (libmpfr_a_SOURCES): Add isnan.c and set_ui.c,
+	remove sqrtrem.c and srandom.h.
+
+	* configfsf.guess: Update to 2001-02-13.
+	* configfsf.sub: Update to 2001-02-16.
+	* config.sub (j90, t90): Remove special handing, configfsf.sub now ok.
+
+	* Makefile.am (MPF_OBJECTS): Add a couple of missing $U's.
+
+	* tune/tuneup.c: Identify compiler used (GCC and Sun C so far).
+
+2001-02-15  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/sparc32/v9/mul_1.asm: Change `ld' to `lduw' and `st' to `stw'.
+	* mpn/sparc32/v9/addmul_1.asm: Likewise.
+	* mpn/sparc32/v9/submul_1.asm: Likewise.
+
+2001-02-14  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/mips3/mips.m4: New file.
+	* configure.in (mips*-*-irix[6789]*): Use mips3/mips.m4.
+
+	* mpn/powerpc64/sqr_diagonal.asm: New file.
+
+	* mpn/mips3/sqr_diagonal.asm: New file.
+
+2001-02-12  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc32/sqr_diagonal.asm: New file.
+
+	* mpn/generic/sqr_basecase.c: Remove declaration of mpn_sqr_diagonal.
+	Fix typo in header comment.
+
+2001-02-12  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/generic/mul.c, mpn/generic/mul_n.c, gmp-impl.h: Use
+	mpn_mul_basecase for squaring below new BASECASE_SQR_THRESHOLD.
+	* tune/tuneup.c gmp-impl.h: Tune BASECASE_SQR_THRESHOLD.
+
+	* Makefile.am (libgmp.la, libmp.la): Revert change to build from
+	mpn/libmpn.la etc, go back to explicitly listed objects.
+
+	* configure.in: Recognise sparc64-*-*, not just sparc64-*-linux*.
+
+2001-02-11  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/asm-defs.m4 (sqr_diagonal): New define_mpn.
+
+	* mpn/alpha/sqr_diagonal.asm: New file.
+
+2001-02-11  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi (Low-level Functions): Note mpn_get_str clobbers its input
+	plus 1 extra limb.
+
+	* mpfr/add.c,agm.c,exp2.c,exp3.c,generic.c,log2.c,pi.c,print_raw.c,
+	set_d.c,sin_cos.c,sqrtrem.c,sub.c: Apply some tweaks for K&R.
+	* tests/mpz/reuse.c, tests/mpq/t-md_2exp.c, demos/pexpr.c,
+	demos/expr/t-expr.c: Ditto.
+
+	* configure.in (HAVE_ABI_$abi): New define in config.m4.
+
+	* gmp-impl.h (mpn_sqr_diagonal): Add prototype and define.
+	* tune/speed.c,speed.h,common.c,many.pl: Add measuring of
+	mpn_sqr_diagonal.
+
+	* gmp.texi, acinclude.m4: Mention x86 solaris 2.7 has the reg->reg
+	movq bug the same as 2.6.
+
+	* mpfr/Makefile.am (EXTRA_DIST): Add mpfr-test.h and mpf2mpfr.h.
+
+	* mpn/x86/README: Merge contents of README.family.
+	* mpn/x86/README.family: Remove file.
+
+	* mpn/Makefile.am (nodist_libdummy_la_SOURCES): Add mode1o, gcd_finda,
+	invert_limb, sqr_diagonal; remove mod_1_rs; sort alphabetically.
+
+2001-02-10  Torbjorn Granlund  <tege@swox.com>
+
+	* configure.in (gmp_mpn_functions_optional): List sqr_diagonal.
+
+	* mpn/powerpc32/aix.m4: Use unnamed csects.
+	* mpn/powerpc64/aix.m4: Likewise.
+
+	* acconfig.h: Add #undef of mpn_sqr_diagonal.
+	Remove lots of spacing.
+
+	* configure.in (syntax testing section): Match power* instead of
+	powerpc*.
+	* mpn/power: Convert files to `.asm'.
+	Prefix umul_ppmm and sdiv_qrnnd.
+	Update some comments.
+
+2001-02-09  Kevin Ryde  <kevin@swox.se>
+
+	* acconfig.h: Add HAVE_NATIVE_mpn_modexact_1_odd and
+	HAVE_NATIVE_mpn_modexact_1c_odd.
+
+	* configure.in (CCAS): Don't override a user selection.
+
+	* mpq/cmp_ui.c: DIVIDE_BY_ZERO if den2==0.
+
+2001-02-08  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/sqr_basecase.c: Use mpn_sqr_diagonal when appropriate.
+
+2001-02-07  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi (Low-level Functions): mpn_preinv_mod_1 now undocumented.
+
+	* mpn/generic/random2.c (myrandom): Use rand() on mingw.
+
+	* mpn/alpha/gmp-mparam.h: Update tuned parameters.
+
+2001-02-05  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/alpha/ev6/gmp-mparam.h: Retune.
+
+2001-02-05  Kevin Ryde  <kevin@swox.se>
+
+	* Makefile.am (libgmp, libmp): Construct from mpn/libmpn.la etc rather
+	than explicitly listed objects.
+
+	* urandom.h: Use rand() on mingw.
+
+	* mpn/powerpc64/lshift.asm,addsub_n.asm: Use r1 not 1.
+
+2001-02-04  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/ia64/copyi.asm: New file.
+	* mpn/ia64/copyd.asm: New file.
+
+2001-02-04  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/alpha/ev5/gmp-mparam.h, mpn/mips3/gmp-mparam.h,
+	mpn/powerpc32/gmp-mparam.h, mpn/powerpc64/gmp-mparam.h,
+	mpn/sparc64/gmp-mparam.h, mpn/x86/*/gmp-mparam.h:
+	Update tuned parameters.
+
+	* mpn/x86/i486: New directory.
+	* configure.in (i486-*-*): Use it.
+	* mpn/x86/i486/gmp-mparam.h: New file.
+
+	* mpn/x86/pentium/mode1o.asm: New file.
+	* mpn/x86/p6/mode1o.asm: New file.
+
+	* tune/many.pl: Use $(ASMFLAGS_PIC) and $(CFLAGS_PIC).
+
+	* gmp.texi (Integer Division): Another rewording of 2exp divisions.
+
+2001-02-03  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/arm/gmp-mparam.h: Tune.
+
+	* mpn/ia64/popcount.asm: Put a `;;' break at end of main loop.
+
+	* configure.in (arm*-*-*): Set gcc_cflags in order to pass
+	$fomit_frame_pointer.
+
+	* tests/mpz/t-mul.c (base_mul): Remove an unused variable.
+
+2001-02-02  Torbjorn Granlund  <tege@swox.com>
+
+	* demos/pexpr.c (TIME): New macro.
+	(main): Use TIME--print timing more accurately.
+	(setup_error_handler): Increase RLIMIT_DATA to 16 Mibyte.
+
+	* longlong.h (arm): Add __CLOBBER_CC to add_ssaaaa and sub_ddmmss.
+
+2001-02-02  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in: Don't remove gmp-mparam.h and mpn source links under
+	--no-create since in that case they're not re-created.
+
+	* demos/expr: New directory.
+	* Makefile.am (SUBDIRS, allprogs): Add it.
+	* demos/expr/README, Makefile.am, expr.c, exprv.c, exprz.c, exprza.c,
+	exprq.c, exprqa.c, exprfa.c, exprf.c, exprfr.c, exprfra.c, expr.h,
+	expr-impl-h.in, run-expr.c, t-expr.c: New files.
+	* configure.in: Generate demos/expr/Makefile & demos/expr/expr-impl.h.
+
+	* Makefile.am: Remove mpfr from main libgmp.
+	* mpfr/Makefile.am: Build and install separate libmpfr.a.
+	* mpfr/*: Update to mpfr 2001.
+
+	* gmp-h.in (__GNU_MP_VERSION_MINOR): Bump to 2.
+	* Makefile.am (libtool -version-info): Bump appropriately.
+	* NEWS: Updates.
+
+	* tune/divrem1div.c, tune/divrem1inv.c, tune/divrem2div.c,
+	tune/divrem2inv.c: Renamed from divrem_1_div.c, divrem_1_inv.c,
+	divrem_2_div.c, divrem_2_inv.c, to be unique in DOS 8.3 filenames.
+	* tune/Makefile.am (libspeed_la_SOURCES): Update.
+
+	* mpn/x86/*/README, mpn/x86/README.family: Misc updates.
+	* tune/README: Misc updates.
+	* doc/configuration: Misc updates.
+
+	* mpn/x86/pentium/mmx/gmp-mparam.h: Change UDIV_PREINV_TIME to
+	UDIV_NORM_PREINV_TIME.
+
+	* mpz/pprime_p.c: Use ASSERT_ALWAYS instead of abort.
+
+	* rand.c (__gmp_rand_lc_scheme): Add "const".
+	(struct __gmp_rand_lc_scheme_struct): Make astr "const char *".
+
+	* demos/calc/calc.y, demos/calc/calclex.l: Add kron function.
+
+	* tests/devel/try.c: Partial rewrite, new scheme of function types,
+	allow result validation functions, add sqrtrem and jacobi testing.
+	* tune/many.pl: Corresponding updates.
+	* tests/devel/Makefile.am: Add a convenience rule for libtests.la.
+
+	* tests/refmpz.c: New file.
+	* tests/Makefile.am: Add it.
+	* tests/misc.c (mpz_erandomb, mpz_erandomb_nonzero): New functions.
+	* tests/tests.h: Add prototypes.
+
+	* mpn/x86/k6/cross.pl: Add a couple more exceptions.
+
+	* gmp.texi: Don't use @nicode{'\0'}, it doesn't come out right in tex.
+	(Introduction to GMP): Mention Cray vector systems.
+	(Build Options): Describe --enable-mpfr, refer to its manual.  Add
+	Crays under supported CPUs.
+	(Debugging): Add notes on source file paths.
+	(Autoconf): New section.
+	(Assigning Integers): Note truncation by mpz_set_d, mpz_set_q and
+	mpz_set_f.
+	(Converting Integers): Note the size mpz_get_str allocates.
+	(Floating-point Functions): Rewrite introduction, clarifying some
+	points about precision handling.
+	(Converting Floats): Note the size mpf_get_str allocates, and that it
+	gives an empty string for zero.  Add mpf_get_si and mpf_get_ui.
+	(Float Comparison): Give the formula mpf_reldiff calculates.
+	(Miscellaneous Float Functions): Add mpf_integer_p and mpf_fits_*_p.
+	(Random Number Functions): Misc rewordings for clarity.
+	(Random State Initialization): Ditto.
+	(Custom Allocation): Remove note on deallocate_function called with 0,
+	misc rewording and clarifications.
+	(Exact Remainder): New section.
+	(Binary GCD): A few words on initial reduction using division.
+	(Accelerated GCD): Refer to exact remainder section.
+	(Extended GCD): Extra remarks on single versus double selection.
+	(Jacobi Symbol): Update for mpz/jacobi.c rewrite and modexact_1_odd.
+	(Modular Powering Algorithm): Refer to exact remainder section.
+	(Assembler SIMD Instructions): Update remarks on MMX.
+	(Contributors): Amend to "Divide and Conquer" division.
+	(References): Tweak some formatting.  Add "Proof of GMP Fast Division
+	and Square Root Implementations" by Paul Zimmermann.
+
+2001-01-31  Torbjorn Granlund  <tege@swox.com>
+
+	* configure.in: Don't ever pass -mips3; let ABI flags imply ISA.
+
+2001-01-31  Kevin Ryde  <kevin@swox.se>
+
+	* tune/time.c: Remove unnecessary longlong.h.
+	(speed_endtime): Add some extra diagnostics.
+
+	* tests/mpz/t-fdiv_ui.c, tests/mpz/t-tdiv_ui.c: Use unsigned long for
+	the divisor, not mp_limb_t.
+	* tests/mpz/t-jac.c (try_base): Use %llu for long long limb.
+	* tests/trace.c: Add <string.h> for strlen.
+
+	* tune/freq.c (speed_cpu_frequency_proc_cpuinfo): Ignore "cycle
+	frequency" of 0, allow "BogoMIPS" as well as "bogomips".
+
+	* macos/Makefile.in: Add mpf/fits_s.c and mpf/fits_u.c objects.
+
+2001-01-30  Torbjorn Granlund  <tege@swox.com>
+
+	* longlong.h: Add add_ssaaaa and sub_ddmmss for 64-bit sparc.
+
+2001-01-29  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc64/addmul_1.asm: Prefix registers with an `r'.
+	* mpn/powerpc64/submul_1.asm: Likewise.
+	* mpn/powerpc64/mul_1.asm: Likewise.
+
+	* configure.in (alpha*-*-*): Amend last change to handle pca*.
+
+2001-01-29  Kevin Ryde  <kevin@swox.se>
+
+	* tune/speed.h (SPEED_ROUTINE_INVERT_LIMB_CALL): Don't let the
+	compiler optimize everything away.
+
+	* tune/speed.c, tune/speed.h, tune/common.c, tune/Makefile.am: Measure
+	operator_div, operator_mod, mpn_divrem_2_div, mpn_divrem_2_inv,
+	mpn_sb_divrem_m3, mpn_sb_divrem_m3_div, mpn_sb_divrem_m3_inv,
+	mpn_dc_divrem_sb_div, mpn_dc_divrem_sb_inv.
+	* tune/divrem_2_div.c, tune/divrem_2_inv.c, tune/sb_div.c,
+	tune/sb_inv.c: New files.
+
+	* tune/tuneup.c, gmp-impl.h, tune/speed.h, tune/common.c,
+	tune/Makefile.am: Tune SB_PREINV_THRESHOLD and DIVREM_2_THRESHOLD.
+
+	* mpn/generic/divrem_2.c: Use new DIVREM_2_THRESHOLD.
+	* mpn/generic/sb_divrem_mn.c: Use new SB_PREINV_THRESHOLD.
+
+	* mpn/x86/p6/mmx/lshift.asm, mpn/x86/p6/mmx/rshift.asm: New files,
+	just m4 include()ing the P55 code.
+	* configure.in (pentium[23]-*-*): Remove x86/pentium/mmx from path.
+
+2001-01-27  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (AC_CHECK_FUNCS): Add srand48.
+	* tune/speed.c: Use this test.
+
+	* acinclude.m4 (GMP_GCC_MARCH_PENTIUMPRO): Allow "egcs-" prefix on gcc
+	--version, warn if the format is unrecognised.
+	(GMP_COMPARE_GE): Guard against empty $1 not only on last arg.
+	(GMP_INIT, GMP_FINISH, GMP_PROG_M4): Obscure or eliminate literal
+	"dnl"s since autoconf thinks they indicate faulty macros.
+
+	* mpz/get_str.c, mpf/get_str.c: Make allocated string block exactly
+	strlen(str)+1 bytes.
+	* mpz/dump.c, mpf/dump.c, tests/mpz/convert.c: Use this size when
+	freeing.
+	* tests/mpf/t-conv.c: Ditto, and ensure x==0 is exercised.
+
+	* tests/mpz/t-fits.c: New file.
+	* tests/mpz/Makefile.am: Add it.
+
+	* tests/mpf/t-fits.c: New file.
+	* tests/mpf/t-get_si.c: New file.
+	* tests/mpf/t-int.c: New file.
+	* tests/mpf/Makefile.am: Add them.
+
+	* mpf/fits_s.c: New file.
+	* mpf/fits_u.c: New file.
+	* mpf/get_si.c: New file.
+	* mpf/get_ui.c: New file.
+	* mpf/int_p.c: New file.
+	* Makefile.am, mpf/Makefile.am: Add them.
+	* gmp-h.in (mpf_fits_*_p, mpf_get_si, mpf_get_ui, mpf_integer_p): Add
+	prototypes.
+
+	* tests/memory.c (tests_allocate, tests_reallocate): Guard against
+	size==0.
+
+	* tests/mpz/*.c, tests/mpq/*.c, tests/mpf/*.c: Uses tests_start and
+	tests_end.
+
+	* gmp-impl.h (USE_LEADING_REGPARM): Fix conditionals.
+
+2001-01-23  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in, mpn/Makeasm.am (ASMFLAGS_PIC): New substitution,
+	allowing -DPIC to be suppressed on cygwin.
+	(CFLAGS_PIC): New substitution, use it and $(CCAS) directly, rather
+	than $(LIBTOOL), avoiding a problem with FreeBSD 2.2.8.
+
+	* mpn/x86/k6/mode1o.asm, mpn/x86/k7/mode1o.asm: Remove an unnecessary
+	+[.-L(here)] from _GLOBAL_OFFSET_TABLE_, avoids a segv from gas 1.92.3.
+	* mpn/x86/README.family: Add notes on the problem.
+
+2001-01-20  Torbjorn Granlund  <tege@swox.com>
+
+	* configure.in (alpha*-*-*): Default `flavour' to ev4.
+
+2001-01-19  Kevin Ryde  <kevin@swox.se>
+
+	* assert.c, gmp-impl.h (__gmp_assert_fail): Change return type to
+	void, since it's no longer used in expressions.
+
+	* mpn/x86/addsub_n.S: Remove file, since it doesn't work and it upsets
+	tune/many.pl.
+
+	* mpz/jacobi.c: Rewrite, but still binary algorithm; accept zero and
+	negative denominators; merge mpz_jacobi and mpz_legendre, add
+	mpz_kronecker; use mpn directly, add special cases for size==1.
+	* gmp.texi (Number Theoretic Functions): Update.
+	* gmp-h.in (mpz_kronecker): Add prototype.
+	* gmp-impl.h (USE_LEADING_REGPARM): New macro.
+	* tests/mpz/t-jac.c: Test mpz_kronecker.
+	* mpz/legendre.c: Remove file.
+	* Makefile.am, mpz/Makefile.am: Update.
+
+	* longlong.h (alpha count_leading_zeros): Use __attribute__ ((const))
+	when possible, add parameter to prototype.
+	(ia64 udiv_qrnnd): Use for all compilers, not just gcc.
+	(pentium count_trailing_zeros): Use count_leading_zeros.
+
+	* acinclude.m4 (GMP_C_ATTRIBUTE_CONST, GMP_C_ATTRIBUTE_NORETURN): New
+	macros.
+	* configure.in: Use them.
+	* gmp-impl.h (ATTRIBUTE_CONST, ATTRIBUTE_NORETURN): New macros.
+	(mpn_invert_limb): Add ATTRIBUTE_CONST.
+	(__gmp_assert_fail): Add ATTRIBUTE_NORETURN.
+
+2001-01-18  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-h.in, gmp-impl.h (__gmp_allocate_func, __gmp_reallocate_func,
+	__gmp_free_func): Move prototypes from gmp-impl.h to gmp-h.in, for the
+	benefit of gmp++.h.
+
+	* gmp-impl.h, tests/misc.c, tests/tests.h: Move MPZ_SET_STR_OR_ABORT
+	and MPF_SET_STR_OR_ABORT to mpz_set_str_or_abort and
+	mpf_set_str_or_abort in libtests.
+	* tests/mpz/convert.c, tests/mpz/t-bin.c, tests/mpz/t-get_si.c,
+	tests/mpz/t-jac.c, tests/mpz/t-misc.c, tests/mpq/t-md_2exp.c,
+	tests/mpq/t-set_f.c, tests/mpf/t-conv.c, tests/mpf/t-misc.c: Update.
+
+	* mpn/generic/sqrtrem.c: Use MPN_COPY_INCR (for when rp==NULL).
+
+	* tests/mpz/reuse.c: Only run mpz_divexact_gcd on positive divisors.
+
+2001-01-18  Torbjorn Granlund  <tege@swox.com>
+
+	* demos/pexpr.c (main): Accept -vml option.
+	(fns): List `hamdist', `pow', `nextprime'.
+	(mpz_eval_expr): Return -1 for `popc' of negative.
+	(mpz_eval_expr): Handle `hamdist', `pow', `nextprime'.
+
+2001-01-15  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/alpha/ev5/mode1o.c: New file.
+
+	* tune/freq.c (speed_cpu_frequency_measure): Check cycles_works_p
+	before running speed_cyclecounter.
+	* tune/speed.h (cycles_works_p): Add prototype.
+
+2001-01-13  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/rand/t-rand.c (farr): Fix typo.
+	(zarr): Fix typo.
+
+2001-01-12  Kevin Ryde  <kevin@swox.se>
+
+	* mpz/kronsz.c: Don't depend on right shifting a negative.
+
+	* mpn/x86/gmp-mparam.h: New file.
+
+	* mpn/x86/pentium/mmx/mul_1.asm: New file.
+
+2001-01-11  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/kronsz.c: Temporary workaround for Cray right shift oddities.
+	Explicitly compare against zero in tests.
+
+2001-01-10  Kevin Ryde  <kevin@swox.se>
+
+	* mpz/kronzs.c: Don't depend on right shifting a negative.
+
+2001-01-09  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/t-constants.c: Disable some undefined tests.
+	(CHECK_MAX_S): Remove workaround for gcc 2.95.2 bug recently added.
+
+2001-01-09  Kevin Ryde  <kevin@swox.se>
+
+	* tests/t-constants.c: Add more diagnostics.
+	(CHECK_MAX_S): Fix for gcc 2.95.2 -mpowerpc64 -maix64.
+
+	* mpn/x86/k6/mode1o.asm: New file.
+	* mpn/x86/k7/mode1o.asm: New file.
+
+	* mpn/asm-defs.m4 (modexact_1_odd, modexact_1c_odd): New define_mpn's.
+	(__clz_tab, modlimb_invert_table, PROLOGUE, EPILOGUE): Add asserts for
+	GSYM_PREFIX.
+	* mpn/x86/x86-defs.m4 (Zdisp): Add a movzbl.
+
+	* tests/mpz/t-jac.c (check_a_zero): New test.
+	(check_squares_zi): Fix to use (a^2/b), not (a*b/b); revert last
+	change avoiding a,b=0, both are fine.
+	(try_2den): Don't use mpz_kronecker_ui for the expected answer.
+	(try_*): Call abort rather than exit.
+
+	* mpz/kronzu.c, mpz/kronzs.c: Fix for a=0.
+
+	* tune/tuneup.c (USE_PREINV_MOD_1): Fix to use new DATA_HIGH_LT_R.
+
+2001-01-08  Torbjorn Granlund  <tege@swox.com>
+
+	* urandom.h: Amend 2000-11-21 change to also handle cygwin.
+
+2001-01-08  Kevin Ryde  <kevin@swox.se>
+
+	* tune/many.pl: Updates for move to tests/devel, add modexact_1_odd,
+	don't assume C files can't have carry-in entrypoints, remove
+	$(TRY_TESTS_OBJS) now in libtests.
+
+	* tests/devel/try.c, tests/refmpn.c, tests/tests.h: Remove
+	mpn_mod_1_rshift testing.
+
+	* tune/tuneup.c (fft_step_size): Test for overflow using the actual
+	mp_size_t, don't use BITS_PER_INT.
+
+	* tune/speed.c (r_string): "r" is a limb, use BITS_PER_MP_LIMB and
+	change LONG_ONES to LIMB_ONES.
+	* tune/time.c (M_2POWU): Use INT_MAX rather than BITS_PER_INT.
+
+	* extract-dbl.c (BITS_PER_PART): Use BITS_PER_MP_LIMB not
+	BITS_PER_LONGINT.
+
+	* mpz/inp_raw.c, mpz/out_raw.c: Add private defines of BITS_PER_CHAR.
+	* mpz/fac_ui.c, tests/mpz/t-fac_ui.c: Don't use BITS_PER_LONGINT.
+	* tests/mpz/t-get_si.c: Don't use BITS_PER_LONGINT, do the LONG_MAX
+	tests with some explicit code.
+
+	* mpn/*/gmp-mparam.h, acinclude.m4, tests/t-constants.c
+	(BITS_PER_LONGINT, BITS_PER_INT, BITS_PER_SHORTINT, BITS_PER_CHAR):
+	Remove defines, remove probings, remove tests.
+
+	* tune/tuneup.c (MODEXACT_1_ODD_THRESHOLD): Add tuning.
+
+	* tune/speed.c,speed.h,common.c: Add measuring of mpn_modexact_1_odd,
+	mpn_gcd_finda, and an "N" form for mpn_gcd_1.
+
+	* tests/mpz/t-jac.c (check_squares_zi): Ensure random a,b != 0.
+
+2001-01-07  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (gmp_mpn_functions): Add mode1o, remove mod_1_rs.
+
+	* mpn/generic/mod_1_rs.c: Remove file, no longer needed.
+	* gmp-h.in (mpn_mod_1_rshift): Remove prototype and define.
+
+	* mpq/set_f.c: Use MPN_STRIP_LOW_ZEROS_NOT_ZERO.
+
+	* mpz/kronzu.c, mpz/kronzs.c, mpz/kronuz.c, mpz/kronsz.c: Use
+	mpn_modexact_1_odd, new style MPN_STRIP_LOW_ZEROS_NOT_ZERO, and new
+	JACOBI macros.  Various rearrangements supporting all this.
+
+	* mpn/generic/gcd_1.c: Use mpn_modexact_1_odd, reduce u%v if u much
+	bigger than v when size==1, some rearrangements supporting this.
+
+	* gmp-impl.h (JACOBI_*): More macros, add some casts to "int".
+	(MPN_STRIP_LOW_ZEROS_NOT_ZERO): Add a "low" parameter.
+	(mpn_modexact_1_odd, mpn_modexact_1c_odd): Add prototype and defines.
+	(MODEXACT_1_ODD_THRESHOLD): New threshold.
+	(MPN_MOD_OR_MODEXACT_1_ODD, JACOBI_MOD_OR_MODEXACT_1_ODD): New macros.
+
+	* mpn/generic/mode1o.c: New file.
+
+	* tests/mpz/reuse.c: Add testing of mpz_divexact_gcd.
+	* tests/mpz/t-fac_ui.c: Use libtests for memory leak checking.
+	* tests/mpz/t-fib_ui.c: Add a usage comment.
+
+	* tests/mpz/bit.c: Use libtests.
+	* tests/mpz/t-scan.c: Remove unused subroutines.
+	* tests/devel/try.c: Use libtests, define PROT_NONE if the system
+	doesn't.
+
+	* tests/spinner.c, tests/x86check.c: Use tests.h.
+	* tests/trace.c: Use tests.h, add mpf_trace.
+	* tests/refmpn.c: Use tests.h, add refmpn_malloc_limbs_aligned,
+	refmpn_tstbit, refmpn_neg.
+
+	* tune/common.c, tune/speed.h: Update for functions moved to
+	tests/misc.c.
+
+	* tune/Makefile.am, tests/mpz/Makefile.am, tests/mpq/Makefile.am,
+	tests/mpf/Makefile.am: Use tests/libtests.la.
+
+	* configure.in (AC_OUTPUT): Update for new directories.
+	(x86 CALLING_CONVENTIONS_OBJS): Use .lo for libtests.la, allow
+	ansi2knr on x86check.c.
+
+	* tests/Makefile.am: Establish new libtests.la convenience library,
+	add mpz, mpq, mpf, mpbsd subdirectories.
+	* tests/tests.h: New file.
+	* mpn/tests/ref.h,try.h: Remove files, now in tests.h.
+
+	* tests/mpf/ref.c: Move to tests/refmpf.c, rename functions to refmpf.
+	* tests/mpf/t-add.c, tests/mpf/t-sub.c: Use libtests.
+	* tests/mpf/Makefile.am: Update.
+
+	* tests/memory.c: New file.
+	* tests/misc.c: New file, a few subroutines from the test programs.
+
+	* mpz/tests, mpq/tests, mpf/tests, mpbsd/tests: Move directories to
+	tests/mpz etc.
+	* mpz/Makefile.am, mpq/Makefile.am, mpf/Makefile.am, mpbsd/Makefile.am
+	(SUBDIRS): Remove.
+
+	* tests/devel: New directory.
+	* mpn/tests/*.c: Move programs to tests/devel.
+	* mpn/tests/Makefile.am, mpn/tests/README: Move to tests/devel, update.
+
+	* mpn/tests/ref.c: Move to tests/refmpn.c.
+	* mpn/tests/spinner.c,trace.c,x86call.asm,x86check.c: Move to tests
+	directory.
+
+	* tests/t-constants.c: Add checks of HIGHBIT, MAX and MIN constants,
+	simplify ANSI vs K&R stringizing, use correct printf format types, do
+	all tests before aborting.
+
+2001-01-05  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/cray/ieee/gmp-mparam.h: Retune.
+
+2001-01-05  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (mp.h): Only create this under --enable-mpbsd.
+
+	* demos/calc: New subdirectory, move demos/calc* to it.
+	* demos/calc/Makefile.am: New file, split from demos/Makefile.am.
+	* demos/Makefile.am: Update.
+	* configure.in (AC_OUTPUT): Add demos/calc/Makefile.
+
+	* tests/t-constants.c (CALC_BITS_PER_TYPE etc): Use a run-time test
+	for how many bits work in a give type, don't assume bits==8*sizeof.
+
+2001-01-04  Kevin Ryde  <kevin@swox.se>
+
+	* mpz/fits_s.c, mpz/fits_u.c: New files, split from fits.c, use plain
+	UINT_MAX etc, not MPZ_FITS_UTYPE_SDT etc.
+	* mpz/fits.c: Remove file.
+	* mpz/Makefile.am, macos/Makefile.in: Update.
+
+	* gmp-impl.h (UNSIGNED_TYPE_MAX etc): Remove these generic forms.
+	(MPZ_FITS_[SU]TYPE_SDT): Remove these.
+	(UINT_MAX etc): Provide a full set of defaults.
+	* gmp-h.in (__GMP_MP_SIZE_T_INT): New define.
+
+	* mpz/tests/t-scan.c: New file.
+	* mpz/tests/Makefile.am (check_PROGRAMS): Add it.
+
+	* mpz/scan0.c, mpz/scan1.c: Rewrite, don't read beyond allocated
+	memory, support negatives, return ULONG_MAX for no bit found.
+	* gmp.texi (Integer Logic and Bit Fiddling): Update.
+
+2001-01-03  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/tests/dive.c: Generate test operands using new random functions.
+	* mpz/tests/io.c: Likewise.
+	* mpz/tests/logic.c: Likewise.
+	* mpz/tests/t-2exp.c: Likewise.
+
+	* stack-alloc.c (__gmp_tmp_alloc): Round `now' to required alignment.
+
+	* stack-alloc.h (__TMP_ALIGN): Append `L'.
+
+	* gmp-impl.h: For Cray, #include limits.h.
+	(LONG_MIN): New #define.
+	(ULONG_HIGHBIT): #define in terms of ULONG_MAX.
+	(LONG_HIGHBIT): #define as LONG_MIN.
+	(USHRT_MAX): New name for USHORT_MAX.
+	(SHRT_MAX): New name for SHORT_MAX.
+	(SHRT_MIN): New #define.
+	(USHORT_HIGHBIT,SHORT_HIGHBIT): Removed.
+
+	* mpbsd/tests/t-misc.c (check_itom [data]): *SHORT* => *SHRT*;
+	remove code disabling a test for Cray.
+
+	* tests/t-constants.c (CHECK_CONSTANT): Cast parameters to long.
+
+	* mpn/generic/mul_n.c (mpn_kara_sqr_n): Remove unused variable `t'.
+	(mpn_kara_mul_n): Likewise.
+
+	* mpz/fac_ui.c (MPZ_SET_1_NZ): Actually use `__z'.
+
+	* mpz/tests/t-jac.c
+	(main, check_squares_zi): Generate test operands using new random
+	functions.
+
+	All changes below on this date for enabling `make; make check'
+	with C++ compilers:
+
+	* mpz/tests/t-pow_ui.c (debug_mp, ref_mpz_pow_ui): Provide prototypes.
+
+	* mpz/tests/t-mul.c (debug_mp, base_mul, ref_mpz_mul):
+	Provide prototypes.
+	(dump_abort): Provide prototype and declare properly for C++.
+
+	* mpz/tests/t-jac.c: #include stdlib.h and sys/time.h.
+
+	* mpz/tests/t-fdiv.c
+	(dump_abort): Provide prototype and declare properly for C++.
+	(debug_mp): Provide prototype.
+	* mpz/tests/t-fdiv_ui.c: Likewise.
+	* mpz/tests/t-gcd.c: Likewise.
+	* mpz/tests/t-powm.c: Likewise.
+	* mpz/tests/t-powm_ui.c: Likewise.
+	* mpz/tests/t-sqrtrem.c: Likewise.
+	* mpz/tests/t-tdiv_ui.c: Likewise.
+	* mpz/tests/t-tdiv.c: Likewise.
+
+	* mpz/tests/t-2exp.c: #include stdlib.h and sys/time.h.
+	Remove #include of longlong.h.
+
+	* mpz/tests/io.c: #include config.h, stdlib.h, sys/time.h, and
+	conditionally unistd.h.
+
+	* mpz/tests/dive.c: #include stdlib.h and sys/time.h.
+	(dump_abort): Provide prototype and declare properly for C++.
+	(debug_mp): Provide prototype.
+	* mpz/tests/logic.c: Likewise.
+
+	* mpz/tests/convert.c (debug_mp): Provide prototype.
+	* mpz/tests/t-root.c (debug_mp): Likewise.
+
+	* mpz/tests/bit.c: #include stdlib.h and sys/time.h.
+
+	* mpq/tests/t-get_d.c: #include stdlib.h and sys/time.h.
+	(dump): Provide prototype and declare properly for C++.
+
+	* mpq/tests/t-cmp_ui.c: #include stdio.h, stdlib.h and sys/time.h.
+	(ref_mpq_cmp_ui): Declare properly for C++.
+
+	* mpq/tests/t-cmp.c: #include stdlib.h and sys/time.h.
+	(ref_mpq_cmp): Declare properly for C++.
+	(dump): Delete unused function.
+
+	* mpf/random2.c (myrandom): New function.
+	(mpf_random2): Use it.
+
+	* mpn/generic/random2.c: #include stdlib.h (for random/mrand48).
+	(myrandom): New function.
+	(mpn_random2): Use it.
+
+	* mpf/tests/t-add.c: #include stdlib.h and sys/time.h.
+	(oo): Remove unused function.
+	* mpf/tests/t-conv.c: Likewise.
+	* mpf/tests/t-sub.c: Likewise.
+	* mpf/tests/t-dm2exp.c: Likewise.
+	* mpf/tests/t-muldiv.c: Likewise.
+	* mpf/tests/t-sqrt.c: Likewise.
+
+	* mpf/tests/reuse.c: #include stdlib.h and sys/time.h.
+	Use PROTO on some typedefs.
+	(oo): Remove function.
+	(dump_abort): Call mpf_dump instead of oo.
+
+	* mpf/set_str.c: #include stdlib.h (for strtol).
+
+	* mpf/random2.c: #include stdlib.h (for random/mrand48).
+	* mpn/alpha/udiv_arnnd: File deleted.
+
+	* Remove K&R function headers.
+
+2001-01-02  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/mul.c: Clean up spacing and indentation.
+
+	* mpn/generic/mul_fft.c (mpn_fft_add_modF): Use mpn_decr_u.
+	Clean up spacing and indentation.
+
+	* extract-dbl.c: Generalize to handle smaller limb sizes.
+
+2001-01-01  Torbjorn Granlund  <tege@swox.com>
+
+	* mpbsd/mout.c: Output newline after "0".
+
+2000-12-31  Torbjorn Granlund  <tege@swox.com>
+
+	* ltmain.sh: Remove space between `#!' and `$SHELL' when generating
+	`libtool'.
+
+	* mpbsd/tests/t-misc.c (check_itom): Exclude test for all Cray
+	vector systems.  Correct comment.
+
+2000-12-31  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi (ABI and ISA): New enough gcc needed for mips n32 etc, gcc
+	2.95 needed for sparc 64-bit ABI, gcc 2.8 needed for -mv8plus.
+
+	* configure.in ([cjt]90,sv1-cray-unicos*): Preserve user specified
+	MPN_PATH, amend test program indenting.
+	(none-*-*): Add -DNO_ASM to gcc to disable longlong.h asm macros in
+	generic C.
+
+	* config.sub (j90, t90): Preserve these, don't let configfsf.sub turn
+	them into c90.
+
+	* config.guess (m68k-*-nextstep*,m68k-*-openstep*): Don't transform
+	m68k to m68020, since m68k is already interpreted as 68020.
+
+2000-12-30  Kevin Ryde  <kevin@swox.se>
+
+	* mpq/neg.c: Rewrite, use mpn, avoid denominator copy if unnecessary.
+
+	* mpz/tstbit.c: Rewrite, slightly simplified.
+	* mpz/tests/bit.c (check_tstbit): New test, and add a couple more
+	diagnostics elsewhere.
+
+	* configure.in (x86 gcc_cflags_cpu): Add -m486 for gcc 2.7.2.
+	(ccbase): Only use a known compiler in eval statements (avoids
+	problems with non-symbol characters).
+	(ccbase): Use GMP_PROG_CC_IS_GNU to identify gcc installed under a
+	different name.
+	(cclist): Use same style $abi as other variables.
+
+	* acinclude.m4 (GMP_PROG_CC_IS_GNU): New macro.
+	(GMP_GCC_MARCH_PENTIUMPRO): Use $ccbase to identify gcc.
+	(GMP_ASM_TYPE): Define TYPE to empty, not "dnl", when no .type needed.
+	(GMP_ASM_SIZE): Ditto for SIZE, which ensures EPILOGUE on the last
+	line of a file doesn't leave a tab and no newline.
+	(GMP_ASM_UNDERSCORE): Add a prototype for C++.
+
+	* configure.in (sys/mman.h, mprotect): New tests.
+	* mpn/tests/try.c: Use them, and HAVE_UNISTD_H too.
+
+	* configure.in (getopt.h): Remove test.
+	* tune/speed.c, mpn/tests/try.c (getopt.h): Remove include, since
+	plain getopt() is in <unistd.h>.
+
+	* configure.in, gmp-h.in (mips*-*-irix6*): Set limb_n32=longlong
+	rather than using _ABIN32.
+
+2000-12-29  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/tests/reuse.c: Rename dump_abort => dump.
+	* mpz/tests/reuse.c: Generate operands using gmp_rand*.
+	* mpz/tests/convert.c: Likewise.
+
+	* configure.in: Detect T90-ieee systems; move Cray path
+	selection to after AC_PROG_CC.  Invoke AC_PROG_CPP.
+	* mpn/cray/cfp: New directory.  Move cfp specific files here.
+	* mpn/cray/cfp/mulwwc90.s: New file.
+	* mpn/cray/cfp/mulwwj90.s: New file.
+	* mpn/cray/mulww.s: Delete.
+
+2000-12-27  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/cray/ieee/mul_1.c: New file.
+	* mpn/cray/ieee/addmul_1.c: New file.
+	* mpn/cray/ieee/submul_1.c: New file.
+	* mpn/cray/ieee/gmp-mparam.h: New file.
+
+	* mpn/cray/gmp-mparam.h: Disable UMUL_TIME and UDIV_TIME.
+
+	* mpn/cray/hamdist.c: New file.
+	* mpn/cray/popcount.c: New file.
+	* mpn/cray/rshift.c: New file.
+	* mpn/cray/lshift.c: New file.
+
+	* longlong.h: Add count_leading_zeros for _CRAY.
+	Reorganize _CRAY stuff.
+
+2000-12-24  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (alpha*-cray-unicos*): Disable SPEED_CYCLECOUNTER_OBJ,
+	as tune/alpha.asm doesn't suit.
+
+	* mpn/generic/sqrtrem.c, mpz/pow_ui.c, mpz/powm_ui.c, mpf/get_str.c,
+	mpf/set_str.c: Use mpn_sqr_n when applicable, not mpn_mul_n.
+
+2000-12-23  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/mul_fft.c: Reformat.
+	(mpn_fft_neg_modF): Remove.
+	(mpn_fft_mul_2exp_modF): Inline mpn_fft_neg_modF.
+
+	* mpn/cray/gmp-mparam.h: Retune.
+
+	* configure.in (*-cray-unicos*): Pass `-O3 -htask0'.
+	(vax*-*-*): Fix typo.
+
+	* mpn/cray/mul_1.c: Use dynamic arrays, get rid of TMP_*.
+	* mpn/cray/addmul_1.c: Likewise.
+	* mpn/cray/submul_1.c: Likewise.
+	* mpn/cray/add_n.c: Likewise.
+	* mpn/cray/sub_n.c: Likewise.
+
+	* configure.in (default cc_cflags,cc_64_cflags): Remove -g/add -O.
+	(mips*-*-irix[6789]*]): Remove -g from cc_*_cflags.
+
+2000-12-22  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/mul_n.c: Delete K&R function headers.
+
+	* mpn/generic/mul_n.c (mpn_kara_mul_n): Clean up type confusion
+	between mp_limb_t and mp_size_t.
+	(mpn_kara_sqr_n): Likewise.
+
+	* mpn/generic/mul_n.c (mpn_kara_mul_n): Use mpn_incr_u.
+	(mpn_kara_sqr_n): Likewise.
+
+	* mpn/generic/mul_n.c (mpn_kara_mul_n): Change handling of `sign'
+	to work around GCC 2.8.1 MIPS bug.
+
+	* configure.in (implied alpha*-cray-unicos*): Remove -g from cc_cflags.
+
+2000-12-21  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/alpha/invert_limb.asm: Simplify a bit.
+	Add handling of bigend systems.
+	* mpn/alpha/unicos.m4: Define `bigend'.
+	* mpn/alpha/default.m4: Define `bigend' (to expand to nothing).
+
+	* tests/t-constants.c (CHECK_CONSTANT): Print using %lx.
+
+	* mpn/alpha/gmp-mparam.h: Remove sizes for plain C types.
+	* mpn/alpha/ev5/gmp-mparam.h: Likewise.
+	* mpn/alpha/ev6/gmp-mparam.h: Likewise.
+
+	* mpn/alpha/unicos.m4: Define LEA.
+	* mpn/alpha/default.m4: Likewise.
+	* mpn/alpha/invert_limb.asm: Use LEA for loading symbolic addresses.
+	* mpn/alpha/cntlz.asm: Likewise.
+
+	* mpn/alpha/cntlz.asm: Don't use `ldbu', use slightly slower
+	`ldq_u' + `extbl' instead.
+
+	* mpn/alpha/unicos.m4: Define EXTERN.
+	* mpn/alpha/default.m4: Define EXTERN (to expand to nothing).
+	* mpn/alpha/cntlz.asm: Declare __clz_tab usign `EXTERN' (for the
+	benefit of Unicos).
+
+2000-12-21  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/alpha/unicos.m4 (GSYM_PREFIX): Define for the benefit of
+	__clz_tab.
+
+2000-12-20  Torbjorn Granlund  <tege@swox.com>
+
+	* longlong.h: Add udiv_qrnnd and count_leading_zeros for _CRAYMPP
+	systems.
+
+2000-12-19  Torbjorn Granlund  <tege@swox.com>
+
+	* configure.in (*sparc*-*-*): Remove -g from cc_cflags and acc_cflags.
+
+	* mpn/generic/sqrtrem.c (mpn_sqrtrem): Separate `limb' values from
+	`size' values.
+
+	* configure.in (*-cray-unicos*): Add `-Wa,-B' to cc_cflags.
+
+	* demos/pexpr.c (rstate): New variable.
+	(main): Initialize rstate.
+	(enum op_t): Add RANDOM.
+	(fns): Add field for RANDOM.
+	(mpz_eval_expr): Handle RANDOM.
+
+2000-12-19  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/generic/sqrtrem.c: Rewrite by Paul Zimmermann, based on his
+	Karatsuba Square Root algorithm.
+	* gmp.texi (Square Root Algorithm): Update.
+
+	* tune/many.pl: New file.
+
+	* mpn/tests/try.c,ref.[ch] (mpn_preinv_mod_1, mpn_sb_divrem_mn,
+	mpn_tdiv_qr, mpn_gcd_finda, mpn_kara_mul_n, mpn_kara_sqr_n,
+	mpn_toom3_mul_n, mpn_toom3_sqr_n): Add testing.
+	* mpn/tests/ref.c: Cast some "0"s in function calls.
+
+	* mpn/x86/k7/mmx/mod_1.asm: Add preinv_mod_1 entrypoint, remove extra
+	variable for loop termination.
+
+	* mpn/x86/p6/mmx/mod_1.asm: Remove file, in favour of the following.
+	* mpn/x86/p6/mod_1.asm: New file.
+
+	* mpn/x86/pentium/mod_1.asm: New file.
+
+2000-12-18  Torbjorn Granlund  <tege@swox.com>
+
+	* configure.in (mips*-*-irix[6789]*): Pass options to compiler using
+	`-Wc'.
+
+2000-12-18  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/x86/k6/pre_mod_1.asm: New file.
+
+	* tune/tuneup.c (USE_PREINV_MOD_1): Tune this, rearrange mpn_divrem_1
+	and mpn_mod_1 handling in support of it.
+	* tune/Makefile.am: Consequent changes to divrem_1.c and mod_1.c.
+
+	* gmp-impl.h (USE_PREINV_MOD_1, MPN_MOD_OR_PREINV_MOD_1): New macros.
+	* mpn/generic/perfsqr.c, mpz/pprime_p.c: Use MPN_MOD_OR_PREINV_MOD_1.
+
+	* configure.in: Let an asm mod_1 provide a preinv_mod_1 entrypoint.
+
+	* mpn/alpha/default.m4: Remove some newlines, add some asserts.
+	(r0 etc, f0 etc): Use defreg and deflit.
+	(PROLOGUE, PROLOGUE_GP, EPILOGUE): Use GSYM_PREFIX.
+	* mpn/alpha/unicos.m4: Remove some newlines, add some asserts.
+	* mpn/alpha/invert_limb.asm: Remove unused second DATASTART parameter.
+	* mpn/alpha/cntlz.asm: Use mpn_count_leading_zeros and __clz_tab.
+
+	* mpn/asm-defs.m4 (changecom): Comments on portability.
+	(__clz_tab, modlimb_invert_table): New macros, matching gmp-impl.h.
+	(count_leading_zeros, count_trailing_zeros): New define_mpn's.
+	(PROLOGUE etc): Comments on usage, add some asserts.
+	(OPERATION_[lr]shift): Use m4_not_for_expansion, for the benefit of
+	lorrshift multifunc.
+
+	* mpn/Makeasm.am (RM_TMP): New variable controlling tmp-*.s
+	removal, for development purposes.
+
+	* mpz/fac_ui.c: Fix for long long limb by using mpn_mul_1 not
+	mpz_mul_ui, and note some possible enhancements.
+
+	* mpz/tests/t-fac_ui.c: New test.
+	* mpz/tests/Makefile.am (check_PROGRAMS): Add it.
+	* macos/Makefile.in: Ditto, and add t-fib_ui too.
+
+	* mpn/generic/[lr]shift.c: Remove some DEBUG code adequately covered
+	by new parameter ASSERTs.
+
+	* longlong.h (count_trailing_zeros): Assert x!=0.
+
+	* doc/configuration: Updates for new configure things, add some notes
+	on test setups.
+
+2000-12-16  Torbjorn Granlund  <tege@swox.com>
+
+	* configure.in (*-*-aix): Pass -qmaxmem=20000 to xlc also for 64-bit
+	compiles.
+	* configure.in: Disable shared libs for *-*-ultrix*.
+
+2000-12-15  Torbjorn Granlund  <tege@swox.com>
+
+	* configure.in (powerpc*-*-*): Pass -Wa,-mppc when using gcc.
+
+	* gmp-impl.h (_EXTERN_INLINE): #define different for GCC and other
+	compilers.
+
+	* gmp-h.in (__gmp_inline): Remove.
+	* mp-h.in: Likewise.
+	* mpn/generic/gcd.c: Use `inline' instead of `__gmp_inline'.
+
+	* configure.in (mips*-*-irix[6789]*): Define *_ldflags.
+
+2000-12-14  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/pre_mod_1.c: Use proper type for udiv_qrnnd
+	parameter `dummy'.
+
+	* mpn/generic/divrem_1.c: Use explicit `!= 0' in if statement.
+	* mpn/generic/mod_1.c: Likewise.
+
+2000-12-14  Kevin Ryde  <kevin@swox.se>
+
+	* config.guess (mips-*-irix[6789]*): Transform to mips64.
+	(m68k-*-nextstep* | m68k-*-openstep*): Transform to m68020.
+
+2000-12-13  Torbjorn Granlund  <tege@swox.com>
+
+	* tests/t-constants.c (main): Conditionalize use of PP_INVERTED.
+
+	* mpn/mp_bases.c: Handle 4-bit limbs.
+	(main): Add code for generating tables.
+
+	* mpn/generic/popham.c: Handle limb bitsizes of 4, 8, 16.
+	Suffix all 32-bit constant with `L'.
+	Use CNST_LIMB for 64-bit constants.
+
+2000-12-13  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-impl.h (FIB_THRESHOLD): Defaults for 4,8,16 bits per limb, and
+	an arbitrary fallback default.
+	(modlimb_invert): Add efficient code for 8,16 (or 4) bits per limb.
+
+	* configure.in (mips3, mips64): Don't bother with o32 (mips2 32-bit
+	limb) on IRIX 6.
+
+	* Makefile.am (SUBDIRS): Put "tests" first so tests/t-constants.c is
+	run first, to pick up any limb size mismatch.
+
+	* tune/tuneup.c (DIVREM_1, MOD_1): Fix result values, were off by 1.
+
+	* mpz/fib_ui.c (table1, table2): Add data for 4,8,16 bits per limb.
+
+2000-12-12  Torbjorn Granlund  <tege@swox.com>
+
+	* gmp-impl.h (LIMBS_PER_DOUBLE): Define for any limb bitsize.
+
+2000-12-11  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/mp_bases.c: Add tables for 8-bit and 16-bit limbs.
+	Round existing `double' values properly.
+
+	* gmp-h.in (__gmp_randstate_struct): Prefix field names with _mp_
+	to keep out of user name space.
+	(__gmp_randata_lc): Likewise.
+	* randclr.c, randlc.c, randlc2x.c, randraw.c, randsd.c, randsdui.c:
+	Corresponding changes.
+
+	* gmp-impl.h (PP): #define for machines with BITS_PER_MP_LIMB
+	of 2, 4, 8, and 16.
+	(PP_FIRST_OMITTED): New, define for various BITS_PER_MP_LIMB.
+	(PP_MASK): Remove.
+	(PP_MAXPRIME): Remove.
+
+	* mpn/generic/perfsqr.c: Generalize PP handling for machines with
+	limbs of < 32 bits.  Allow PP_INVERTED to be undefined.
+	* mpz/pprime_p.c: Likewise.
+
+2000-12-10  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/mul_1.c: Declare parameters in C89 style.
+
+2000-12-10  Kevin Ryde  <kevin@swox.se>
+
+	* tune/Makefile.am (speed_LDFLAGS, speed_ext_LDFLAGS, tune_LDFLAGS):
+	Don't use -all-static, as gcc 2.95.2 on i386 solaris 8 doesn't like
+	it.
+
+	* configure.in (mips3,mips64): Add ABI=64, name the others ABI=n32 and
+	ABI=o32.
+	* mpn/mips3/gmp-mparam.h (BITS_PER_LONGINT): Remove #define and let
+	configure determine it, since it varies with ABI=64 or ABI=n32.
+	* gmp.texi (ABI and ISA): Update.
+	(mpz_mod_ui): Remark that it's identical to mpz_fdiv_r_ui.
+	(mpn_divexact_by3): Qualify a statement needing mp_bits_per_limb even.
+
+	* mul_fft.c (mpn_fft_mul_modF_K etc): Patch by Paul Zimmermann to fix
+	results in certain cases of recursing into a further FFT.
+
+2000-12-09  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/cmpabs.c: Remove unused variable.
+	* mpz/rrandomb.c: Likewise.
+	* mpz/xor.c: Likewise.
+
+2000-12-07  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/gcdext.c: Handle double carry when computing s1.
+	Merge two code blocks for computing s0 and s1.
+
+2000-12-07  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (hppa*-*-*): Remove -Aa -D_HPUX_SOURCE from
+	cc_cflags/cppflags, and instead let AM_C_PROTOTYPES add it, or -Ae,
+	whichever works.
+
+	* configure.in (*-*-aix[34]*): Disable shared by default, but let
+	the user override that, if desired.
+	* gmp.texi (Notes for Particular Systems): Update.
+
+2000-12-06  Torbjorn Granlund  <tege@swox.com>
+
+	* mpq/cmp_ui.c: Streamline.
+
+2000-12-06  Kevin Ryde  <kevin@swox.se>
+
+	* tune/divrem_1_div.c,divrem_1_inv.c,mod_1_div.c,mod_1_inv.c,
+	gcdext_double.c: New files for measuring.
+	* tune/Makefile.am (libspeed_la_SOURCES): Add them.
+	* tune/speed.c,speed.h,common.c: Add measuring of them.
+	(mpn_preinv_mod_1, mpz_jacobi, mpz_powm_ui): Add measuring.
+
+	* speed.c (getopt_long): Don't use this, just plain getopt.
+	* configure.in (getopt_long): Remove test.
+
+	* gmp-impl.h (MPN_KARA_MUL_N_TSIZE, MPN_KARA_MUL_N_MINSIZE,
+	MPN_TOOM3_MUL_N_TSIZE, MPN_TOOM3_MUL_N_MINSIZE): New macros, and
+	assume toom3 square tsize was meant to be the same as the mul (both
+	are overestimates).
+	* tune/tuneup.c, mpn/generic/mul.c, mpn/generic/mul_n.c: Use them.
+	* mpn/generic/mul_n.c (mpn_toom3_sqr_n): Fix an ASSERT to use
+	TOOM3_SQR_THRESHOLD not TOOM3_MUL_THRESHOLD, add a few that might
+	be more realistic size checks.
+	* tune/speed.h (SPEED_ROUTINE_MPN_MUL_N_TSPACE etc): Use minsize.
+
+	* mpn/generic/divrem_1.c: Partial rewrite, merge fractional part
+	calculation, skip a divide step in more cases, introduce
+	DIVREM_1_NORM_THRESHOLD and DIVREM_1_UNNORM_THRESHOLD.
+	* mpn/generic/mod_1.c: Partial rewrite, skip a divide step in more
+	cases, introduce MOD_1_NORM_THRESHOLD, MOD_1_UNNORM_THRESHOLD.
+	* longlong.h (UDIV_PREINV_ALWAYS): New define, set for alpha and ia64.
+	* tune/tuneup.c (DIVREM_1_NORM_THRESHOLD, DIVREM_1_UNNORM_THRESHOLD,
+	MOD_1_NORM_THRESHOLD, MOD_1_UNNORM_THRESHOLD): Tune these.
+	* gmp-impl.h [TUNE_PROGRAM_BUILD]: Support for this.
+	* tune/Makefile.am (TUNE_MPN_SRCS): Add divrem_1.c and mod_1.c.
+
+	* gmp-impl.h (UDIV_NORM_PREINV_TIME): Renamed from UDIV_PREINV_TIME.
+	* mpn/generic/perfsqr.c, mpn/generic/sb_divrem_mn.c,
+	mpn/x86/*/gmp-mparam.h: Ditto.
+	* gmp-impl.h (UDIV_UNNORM_PREINV_TIME): New define.
+
+	* configure.in (AC_C_INLINE, HAVE_INLINE): New test and define.
+	* gmp-impl.h (inline): Remove, use config.h.
+	(_EXTERN_INLINE): Redefine based on HAVE_INLINE.
+	(mpn_zero_p): Use HAVE_INLINE.
+
+	* acinclude.m4 (GMP_PROG_AR, GMP_PROG_NM): Don't add flags to a user
+	selected $AR or $NM.
+
+	* tune/tuneup.c (all): Print how long the tuning took.
+
+	* configure.in (AM_C_PROTOTYPES): Use this, not GMP_ANSI2KNR.
+	* acinclude.m4 (GMP_ANSI2KNR): Remove.
+
+	* Makefile.am (gmp.h, mp.h): In DISTCLEANFILES not CLEANFILES.
+
+	* gmp-h.in (mpn_divmod, mpn_divmod_1, mpn_divexact_by3): Cast some
+	zeros, for the benefit of K&R if long!=int.
+
+	* mpn/lisp/gmpasm-mode.el (gmpasm-comment-start-regexp): Add "*" for
+	the benefit of cray.
+
+	* compat.c (mpn_divexact_by3, mpn_divmod_1): Return types should be
+	mp_limb_t, not int, and need an actual "return".
+
+2000-12-05  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/sparc32/v8/supersparc/gmp-mparam.h: Retune.
+	* mpn/alpha/gmp-mparam.h: Tune for 21064.
+
+	* longlong.h: Reformat to avoid newlines within strings.
+
+	* gmp-impl.h (inline): Disable if GCC has defined __STRICT_ANSI__.
+
+	* configure.in: Do a `mkdir tune' before creating tune/sqr_basecase.c.
+
+	* Makefile.am: Treat mp.h analogously to gmp.h.
+
+	configure.in (*-*-aix): Pass -qmaxmem=20000 to xlc.
+
+	* mp-h.in: Renamed from mp.h.
+	Add #define for _LONG_LONG_LIMB.
+	Move some other fixes from gmp-h.in.
+	* mp.h: Removed.
+	* configure.in: Generate mp.h from mp-h.in like we handle
+	gmp-h.in/gmp.h.
+
+2000-12-04  Torbjorn Granlund  <tege@swox.com>
+
+	* acinclude.m4: Fix typo testing for bad HP compiler.
+
+2000-12-03  Torbjorn Granlund  <tege@swox.com>
+
+	* mpbsd/tests/t-misc.c (check_itom): Exclude some tests for Cray
+	CFP systems.
+
+	* longlong.h (CRAYIEEE umul_ppmm): New.
+
+	* mpn/cray/gmp-mparam.h (BITS_PER_SHORTINT): 32 => 64.
+	(*_THRESHOLD): Tune.
+
+	* configure.in: Disable shared libs for *-*-unicos*.
+
+2000-12-03  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in, tune/Makefile.am: Create tune/sqr_basecase.c during
+	configure, and use it unconditionally in $(nodist_tuneup_SOURCES).
+	Fixes a problem with sqr_basecase.lo under --disable-static.
+
+2000-12-01  Torbjorn Granlund  <tege@swox.com>
+
+	* mpf/tests/t-get_d.c (LOW_BOUND,HIGH_BOUND): #define for non-IEEE
+	Cray systems.
+
+	* gmp-impl.h (union ieee_double_extract): Test for _CRAYIEEE.
+
+2000-11-30  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/tests/t-mul.c (base_mul): Fix re-evaluation problems in macro
+	invocations.
+	(ref_mpz_mul): New name from mpz_refmul.  Make static.
+	(base_mul): New name for _mpn_mul_classic.
+
+2000-11-30  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in: Rewrite of CC/CFLAGS selection scheme, introduce a
+	notion of ABI, merge compiler and mpn path selection, add flags
+	selection for AR and NM, let CC without CFLAGS work.
+	(AC_PROG_CC): Use this, not GMP_SELECT_CC.
+	* acinclude.m4 (GMP_PROG_CC_WORKS): Don't use AC_TRY_COMPILE, combine
+	cc/cflags parameter.
+	(GMP_PROG_CC_FIND, GMP_CHECK_CC_64BIT, GMP_PROG_CC_SELECT): Remove.
+	* gmp.texi (Installing GMP): Updates for new scheme.
+
+	* configure.in (AC_CANONICAL_HOST): Use this and $host, not $target.
+	* acinclude.m4, acconfig.h, longlong.h, mpn/x86/x86-defs.m4,
+	mpn/x86/k7/mmx/popham.asm: Ditto, renaming HAVE_TARGET_CPU to
+	HAVE_HOST_CPU.
+	* gmp.texi (Build Options, and elsewhere): Update.
+
+	* acinclude.m4 (GMP_COMPARE_GE): New macro.
+	(GMP_GCC_MARCH_PENTIUMPRO): Use it, add CC parameter, check for GCC.
+	(GMP_HPC_HPPA_2_0): New macro, adapted from GMP_CHECK_CC_64BIT.
+
+	* acinclude.m4 (GMP_PROG_AR): New macro, using AC_CHECK_TOOL, adding
+	GMP flags.
+	* configure.in: Use it
+
+	* gmp-h.in: Renamed from gmp.h.
+	(@define_LONG_LONG_LIMB@): Placeholder for instantiation.
+	(__GNU_MP__): Bump to 3.
+	* acinclude.m4 (GMP_VERSION): Get version from gmp-h.in.
+	* configure.in: Create gmp.h from gmp-h.in to set _LONG_LONG_LIMB.
+	* gmp.texi.h (ABI and ISA): Mention this.
+	* acconfig.h (_LONG_LONG_LIMB): Remove undef.
+	* Makefile.am: Distribute gmp-h.in, not gmp.h.
+
+	* configure.in (AC_PROG_CPP, AC_PROG_INSTALL, AC_PROG_LN_S): Remove,
+	dragged in by other macros.
+	(gmp_asm_syntax_testing): Renamed from gmp_no_asm_syntax_testing.
+	(AC_EXEEXT, AC_OBJEXT): Remove, done automatically by libtool.
+	* configure.in, acinclude.m4: Remove "" from "`foo`", being
+	unnecessary and not portable.
+
+	* configure.in (GMP_LDFLAGS): New AC_SUBST flags for libtool link.
+	(powerpc64*-*-aix*): Use for -Wc,-maix to fix shared library creation,
+	but can't build shared and static at the same time.
+	* Makefile.am (libgmp_la_LDFLAGS, libmp_la_LDFLAGS): Use
+	$(GMP_LDFLAGS).
+	* gmp.texi (Notes for Particular Systems): Update AIX problem
+
+	* configure.in (AC_CONFIG_LINKS): Use where needed, not via gmp_links.
+	(gmp_srclinks): Build up as needed, not via gmp_links.
+
+	* acinclude.m4 (GMP_INIT): Do CONFIG_TOP_SRCDIR and asm-defs.m4 here.
+	* configure.in (asm-defs.m4): Consequent changes.
+
+	* acinclude.m4 (GMP_INCLUDE_MPN): Using include_mpn(), replacing
+	GMP_INCLUDE and GMP_SINCLUDE.
+	* configure.in (gmp_m4postinc): Remove this scheme, use
+	GMP_INCLUDE_MPN instead.
+
+	* configure.in (*-*-sco3.2v5*): Force ac_cv_archive_cmds_need_lc=no,
+	until libtool does this itself.
+	* gmp.texi (Known Build Problems): Remove SCO -lc problem.
+
+	* configure, INSTALL.autoconf, etc: Update to autoconf 2000-11-29.
+	* acinclude.m4 (GMP_C_SIZES): Use AC_CHECK_SIZEOF.
+	* gmp.texi (Known Build Problems): Remove version.c sed/config.h
+	problem, fixed.
+
+	* ltmain.sh, aclocal.m4: Update to libtool 2000-11-25.
+	* ltconfig: No longer required, but leave an empty dummy for automake.
+	* gmp.texi (Known Build Problems): Remove SunOS native ar ranlib
+	problem, fixed.
+
+	* */Makefile.in, aclocal.m4: Update to automake 2000-11-25.
+	* mpbsd/tests/Makefile.am, mpfr/tests/Makefile.am (check_PROGRAMS):
+	Remove dummy, no longer required.
+	* mpbsd/tests/dummy.c, mpfr/tests/dummy.c: Remove files.
+	* depcomp: Remove file, no longer required (with no-dependencies).
+
+	* texinfo.tex: Update to 2000-11-09.
+	* gmp.texi (Build Options): Mention PDF from gmp.texi.
+	* Makefile.am (MOSTLYCLEANFILES): Add gmp.tmp, from new texinfo.tex.
+
+	* gmp.texi (Build Options): List alphaev56, alphapca56, alphaev67,
+	hppa2.0n and power among supported CPUs.
+
+2000-11-30  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/tests/t-mul.c: Increase max operand size from 2^17 bits
+	to 2^19 bits.  Misc cleanups.
+
+2000-11-26  Kevin Ryde  <kevin@swox.se>
+
+	* tune/tuneup.c (FIB_THRESHOLD): Cope better with different speeds of
+	odd and even sizes.
+
+	* longlong.h (alpha): Use udiv_qrnnd and count_leading_zeros on all
+	compilers, not just gcc.
+
+	* pre_mod_1.c: Use conditional subtract to always skip a division.
+	(UMUL_TIME, UDIV_TIME): Remove defaults, now in longlong.h.
+
+2000-11-22  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/pa64w/gmp-mparam.h: Retune.
+	* mpn/pa64/gmp-mparam.h: Retune.
+	* mpn/sparc64/gmp-mparam.h: Retune.
+
+2000-11-22  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-impl.h (ABOVE_THRESHOLD, BELOW_THRESHOLD): New macros.
+	* mpn/generic/gcdext.c: Use them.
+
+	* mpn/generic/gcdext.c [WANT_GCDEXT_ONE_STEP]: Force only one step.
+	* tune/gcdextos.c, tune/gcdextod.c: New files, one step gcdext, single
+	and double.
+	* tune/Makefile.am (libspeed_la_SOURCES): Add them.
+	(TUNE_MPN_SRCS): Remove gcdext.c.
+	* tune/speed.h, tune/common.c, tune/speed.c: Add measuring.
+	* tune/tuneup.c: Use for GCDEXT_THRESHOLD, plus check if double limb
+	is ever better.  Should be more accurate, and hopefully faster.
+
+	* tune/gcdext_single.c: New file, gcdext forced to single limbs.
+	* tune/Makefile.am: Add it.
+	* tune/speed.h, tune/common.c, tune/speed.c: Add measuring, and of
+	invert_limb.
+
+	* tune/speed.h (speed_params r): Use mp_limb_t, not long.
+	* tune/speed.h, tune/common.c: Don't "switch" on "r".
+	* tune/speed.c (r_string): Accept limb sized constants.
+	(choice scale): Add a scale factor (eg. "2.33*mpn_add_n").
+	* tune/common.c (SPEED_ROUTINE_UDIV_QRNND_A): Default r to
+	__mp_bases[10].big_base, being a full limb value.
+
+	* configure.in (alphapca56*-*-*): Use ev5 mpn path.
+	(am29000*-*-*): Remove this, leave the canonical a29k.
+	(z8k*-*-*, z8kx*-*-*): Changed from z8000, since z8k is canonical.
+	(gmp_mpn_functions_optional): Add invert_limb, use for alpha and ia64.
+
+	* configure.in (alloca): Accept yes/no/detect, generate an error if
+	"yes" but not available.
+	* gmp.texi (Build Options): Update.
+
+	* acinclude.m4 (GMP_TRY_ASSEMBLE): Make conftest.out available.
+	(GMP_ASM_ALIGN_FILL_0x90): Use it.
+
+	* acinclude.m4 (GMP_ASM_X86_MMX) [*-*-solaris*]: Check for solaris
+	2.6 "as" movq bug.
+	* gmp.texi (Notes for Particular Systems): Update x86 MMX note.
+
+2000-11-21  Torbjorn Granlund  <tege@swox.com>
+
+	* tune/Makefile.am (EXTRA_DIST): List hppa2w.asm.
+
+	* tune/hppa2.asm: Change level directive to "2.0n".
+	* tune/hppa2w.asm: New file.
+	* configure.in [SPEED_CYCLECOUNTER_OBJS switch]: Separate out hppa2.0w.
+
+	* mpn/pa64/gmp-mparam.h (BITS_PER_LONGINT): 64 => 32.
+
+2000-11-21  Kevin Ryde  <kevin@swox.se>
+
+	* urandom.h (random): No prototype if glibc stdlib.h has already
+	provided it (avoids an int32_t/long conflict).
+
+	* tune/Makefile.am (LDFLAGS): Use -all-static.
+	(speed-dynamic): Dynamic linked version of speed.c.
+	* tune/README: Update.
+
+	* mpn/generic/gcd.c (find_a): Use native version if available.
+	* acconfig.h (HAVE_NATIVE_mpn_gcd_finda): Add #undef.
+	* gmp-impl.h (mpn_gcd_finda): Add prototype and define.
+	* mpn/asm-defs.m4 (mpn_gcd_finda): New define_mpn.
+	* tune/gcd_finda_gen.c: #undef any HAVE_NATIVE_mpn_gcd_finda.
+	* configure.in (gmp_mpn_functions_optional): Add gcd_finda.
+	* mpn/x86/k6/gcd_finda.asm: New file.
+
+	* tune/tuneup.c (POWM_THRESHOLD): Slightly bigger size steps.
+
+	* gmp-impl.h (__GMP_IMPL_H__): Protect against multiple inclusion.
+	* tune/gcd_bin.c, tune/powm_mod.c, tune/powm_redc.c: Use #undef after
+	gmp-impl.h to force thresholds.
+	* tune/tuneup.c (print_define, fft): No need for #ifndefs on
+	thresholds any more.
+
+2000-11-20  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/tests/t-powm.c: Analogous changes as made 2000-11-12 to t-mul.c.
+	* mpz/tests/t-powm_ui.c: Likewise.
+	* mpz/tests/t-pow_ui.c: Likewise.
+	* mpz/tests/t-root.c: Likewise.
+
+	* configure.in [compiler switch]: Pass "-Aa -D_HPUX_SOURCE" to cc for
+	all hppa versions.
+
+	* mpn/hppa/hppa1_1/udiv_qrnnd.S: Reference data using PC relative
+	addressing (was r19 relative addressing).
+
+2000-11-18  Torbjorn Granlund  <tege@swox.com>
+
+	* rand.c: (__gmp_rand_lc_scheme): Convert strings to hexadecimal.
+	(gmp_randinit): Expect strings in hexadecimal.
+
+2000-11-18  Kevin Ryde  <kevin@swox.se>
+
+	* configfsf.guess, configfsf.sub: Update to 2000-11-16.
+	* config.guess (alpha*-*-openbsd*): Do exact cpu detection.
+
+2000-11-14  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/tests/t-fdiv.c: Analogous changes as made 2000-11-12 to t-mul.c.
+	* mpz/tests/t-tdiv_ui.c: Likewise.
+	* mpz/tests/t-fdiv_ui.c: Likewise.
+	* mpz/tests/t-sqrtrem.c: Likewise.
+	* mpz/tests/t-gcd.c: Likewise.
+
+2000-11-13  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/Makeasm.am: New file, splitting out assembler rules.
+	* mpn/Makefile.am, tune/Makefile.am: Use it.
+
+	* mpn/Makefile.am (@CPP@): Remove this, automake already gives it.
+
+	* configure.in (AC_CHECK_LIBM): New test, and AC_SUBST it.
+	* Makefile.am (MPFR_LIBADD_OPTION): Use it.
+	* demos/Makefile.am (qcn_LDADD): Ditto.
+	* tune/Makefile.am (libspeed_la_LIBADD): Ditto.
+	* tests/rand/Makefile.am (libstat_la_LIBADD): Ditto.
+
+	* tune/time.c (timeval_diff_secs): Better calculation.
+	(read_real_time): New measuring method for AIX power/powerpc.
+	(speed_endtime): Protect against negative times.
+	* tune/common.c (speed_measure): Protect against big reps.
+	* tune/freq.c (speed_cpu_frequency_measure_one): Better timeval diff.
+	* tune/speed.h (TIMEVAL_DIFF_SEC,USEC): Remove macros.
+	* configure.in: (sys/systemcfg.h, read_real_time): New tests.
+
+2000-11-13  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/tests/t-mul.c: Remove #include urandom.h.
+	* mpz/tests/t-tdiv.c: Likewise.
+
+	* configure.in [SPEED_CYCLECOUNTER_OBJS switch]:
+	Declare hppa.asm as just 32 bits (cyclecounter_size=1).
+
+2000-11-12  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/tests/t-mul.c
+	(main): Generate random numbers using gmp_rand* functions.
+	(main): Distribute random numbers non-uniformly.
+	(main): Seed by current time if GMP_CHECK_RANDOMIZE is set.
+	(_mpn_mul_classic): Streamline.
+	* mpz/tests/t-tdiv.c: Analogous changes.
+
+	* demos/pexpr.c (HAVE_sigaltstack): Fix typo in testing for _UNICOS.
+	Also test for __hpux.
+
+2000-11-11  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/alpha/ev5/gmp-mparam.h: Retune.
+
+	* mpn/alpha/ev6/gmp-mparam.h: Retune.
+
+	* mpn/alpha/ev6/add_n.asm: Misc cleanups.
+
+	* mpn/alpha/ev6/sub_n.asm: New file.
+
+2000-11-10  Torbjorn Granlund  <tege@swox.com>
+
+	* configure.in [path switch] (alphaev6*-*-*): Add alpha/ev5 to path.
+
+	* mpn/alpha/ev6/add_n.asm: New file.
+
+2000-11-10  Kevin Ryde  <kevin@swox.se>
+
+	* mpz/powm.c (redc): Make global under WANT_REDC_GLOBAL.
+	* tune/powm_mod.c, tune/powm_redc.c: New files.
+	* tune/Makefile.am (libspeed_la_SOURCES): Add them.
+	* tune/*: Add measuring of redc, mpz_mod, mpz_powm_mod, mpz_powm_redc.
+
+	* tune/tuneup.c (POWM_THRESHOLD): Determine from redc and mpz_mod.
+	* tune/Makefile.am (TUNE_MPZ_SRCS): Remove powm.
+
+2000-11-10  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/mips3/gmp-mparam.h: Retune.
+
+	* configure.in (os_64bit): Rename to check_64bit_compiler.
+
+2000-11-09  Torbjorn Granlund  <tege@swox.com>
+
+	* configure.in [SPEED_CYCLECOUNTER_OBJS switch]: Choose hppa/hppa2 code
+	depending on $CC64.
+
+2000-11-09  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/x86/pentium/mul_1.asm: Unroll 2x, saving 1 c/l when in L1.
+	Add 1c entrypoint.
+	* mpn/x86/pentium/aorsmul_1.asm: Add 1c entrypoints, shave a couple
+	of cycles at entry and exit.
+
+	* configure.in (power1,2,2sc): Support these as synonyms for plain
+	power.
+
+	* acinclude.m4 (GMP_ASM_X86_SHLDL_CL): GMP_DEFINE WANT_SHLDL_CL here.
+	(GMP_ASM_X86_MMX, GMP_ASM_X86_SHLDL_CL): Add X86 into the names.
+	* configure.in: Consequent changes.
+
+	* gmp.texi (Notes for Particular Systems): Remarks about power/powerpc.
+	(Reentrancy): Remarks about simultaneous writing.
+	(Reporting Bugs): Ask for configfsf.guess.
+
+2000-11-08  Kevin Ryde  <kevin@swox.se>
+
+	* acinclude.m4 (GMP_FUNC_ALLOCA): New macro.
+	* configure.in: Use it.
+	* gmp-impl.h (alloca): Conditionals and setups as per autoconf
+	(should make alloca available on more non-gcc compilers).
+
+	* acinclude.m4: Misc reformatting, simplify some quoting.
+	(GMP_ASM_UNDERSCORE, GMP_ASM_X86_MCOUNT): Use $CC $CFLAGS $CPPFLAGS.
+	(GMP_ASM_UNDERSCORE, GMP_ASM_ALIGN_FILL_0x90, GMP_ASM_RODATA): Put
+	AC_REQUIREs outside AC_CACHE_CHECK.
+	(GMP_C_SIZES): Use $srcdir/gmp.h, not -I; use $CPPFLAGS.
+	(GMP_ASM_UNDERSCORE): Use "gmp_compile" variable, and only rm
+	conftes1* conftes2*.
+	(GMP_PROG_NM): New macro, require it in appropriate GMP_ASM_*.
+	(GMP_TRY_ASSEMBLE): New macro, use it in various GMP_ASM_*.
+	* configure.in: Use GMP_PROG_NM.
+
+	* mpn/tests/spinner.c (spinner_signal): Use RETSIGTYPE.
+	(spinner_init): Force output to unbuffered.
+
+	* mpn/x86/README.family: Notes about GOT table and imul, misc updates.
+	* mpn/x86/k7/diveby3.asm: Change to 3 operands for immediate imul.
+	* mpn/x86/k6/diveby3.asm: Ditto.
+
+2000-11-06  Torbjorn Granlund  <tege@swox.com>
+
+	* urandom.h: Simplify and make it work properly for 64-bit
+	machines also in environments without `random'.
+
+2000-11-04  Torbjorn Granlund  <tege@swox.com>
+
+	* configure.in [path switch]: Don't match rs6000-*-*, in
+	particular don't assume POWER.
+
+	* tune/tuneup.c (fft): Remove usleep calls.
+
+	* config.guess: Don't pass "$@" when it is known to be empty.
+
+	* Makefile.am (EXTRA_DIST): List configfsf.guess and configfsf.sub.
+
+2000-11-04  Kevin Ryde  <kevin@swox.se>
+
+	* configfsf.guess, configfsf.sub: Moved from config.guess and
+	config.sub.
+	* config.guess, config.sub: New files, wrappers around around
+	configfsf versions.
+	* configfsf.guess: Update to FSF 2000-10-23.
+	* configfsf.sub: Update to FSF 2000-10-25.
+
+	* acinclude.m4 (GMP_ASM_POWERPC_R_REGISTERS): New macro.
+	* mpn/powerpc32/powerpc-defs.m4: New file, regmap.m4 r0 etc macros
+	conditionalized by GMP_ASM_POWERPC_R_REGISTERS.
+	* mpn/powerpc32/regmap.m4: Remove file.
+	* configure.in (powerpc*-*-*): Use all this.
+
+	* mpz/divegcd.c: New file, providing mpz_divexact_gcd.
+	* Makefile.am, mpz/Makefile.am: Add it.
+	* gmp-impl.h (mpz_divexact_gcd): Add prototype.
+	* mpq/aors.c,canonicalize.c,div.c,mul.c: Use it.
+
+	* longlong.h [pentium] (count_leading_zeros): New macro.
+	(__clz_tab): Always provide prototype.
+	* acconfig.h (HAVE_TARGET_CPU_): Add x86s.
+
+	* tune/speed.[ch],common.c (count_leading_zeros,
+	count_trailing_zeros, __udiv_qrnnd_c): Add measuring.
+
+	* configure.in (X86_PATTERN): Move from here ...
+	* acinclude.m4 (X86_PATTERN): ... to here.
+	(GMP_ASM_RODATA): Use it.
+
+	* configure.in (srandom): New test.
+	* mpn/tests/try.c: Use it.
+	* tune/speed.c: Ditto, and conditionalize getrusage and headers.
+
+2000-11-02  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/Makefile.am (nodist_libdummy_la_SOURCES): Add udiv_qrnnd.c
+	and udiv_w_sdiv.c.
+
+	* mpn/generic/mul_n.c (mpn_kara_sqr_n): Remove a duplicate
+	subtract at the evaluate stage.
+
+2000-11-01  Torbjorn Granlund  <tege@swox.com>
+
+	* configure.in [compiler switch] (sparc64-*-linux*): Spell
+	gmp_xoptcflags_gcc properly, and pass same options as for other
+	sparcv9 configs.
+
+	* tune/speed.h (SPEED_ROUTINE_MPN_GET_STR): Fix type of wsize.
+
+2000-10-31  Torbjorn Granlund  <tege@swox.com>
+
+	* configure.in [compiler switch] (sparc64-*-linux*): Remove -mvis
+	from gmp_xoptflags_gcc, this might not be an ultrasparc.
+	Remove -m32 from gmp_cflags_gcc; add -Wa,-xarch=v8plus.
+
+2000-10-29  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/ia64/lorrshift.asm: New file.
+
+	* configure.in: New mulfunc `lorrshift' for lshift and rshift.
+
+2000-10-29  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/generic/mul_n.c (mpn_kara_sqr_n): Delete code performing
+	superfluous mpn_sub_n calls.
+
+	* configure.in (found_asm, M4): Account for SPEED_CYCLECOUNTER_OBJ,
+	for the benefit of targets whose only .asm is a cycle counter.
+
+	* tune/tuneup.c (fft): Remove bogus usleep calls.
+
+2000-10-28  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/ia64/invert_limb.asm: Get return value for 0x800...00 right.
+
+	* tune/Makefile.am (EXTRA_DIST): Add ia64.asm.
+
+	* tune/ia64.asm: Fix typo.
+
+	* add_n.asm addmul_1.asm mul_1.asm popcount.asm sub_n.asm:
+	Preserve ar.lc as required by ABI.
+	* longlong.h (ia64 udiv_qrnnd): New.
+
+	* configure.in [path switch] (ia64*-*-*): Set extra_functions.
+	* mpn/ia64/invert_limb.asm: New file.
+
+2000-10-27  Torbjorn Granlund  <tege@swox.com>
+
+	* configure.in [compiler switch]:
+	Get rid of c89 for all hppa flavours--it is an evil compiler!
+
+	* tune/speed.h (SPEED_ROUTINE_MPN_SET_STR): Fix type of xp.
+	(SPEED_ROUTINE_MPN_GET_STR): Fix type of wp.
+
+2000-10-27  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi (Fibonacci Number Algorithm): New section.
+
+	* mpz/tests/t-fib_ui.c: New file.
+	* mpz/tests/Makefile.am (check_PROGRAMS): Add it.
+
+	* mpz/fib_ui.c: Rewrite, same formulas but using mpn functions and
+	some lookup tables, much faster at small to moderate sizes.
+	* gmp-impl.h (MPZ_FIB_SIZE): New macro.
+	(FIB_THRESHOLD): Establish default here.
+	* tune/tuneup.c (FIB_THRESHOLD): Start search after the new table
+	data.
+
+	* mpn/x86/x86-defs.m4 (mcount_movl_GOT_ebx): Rename from movl_GOT_ebx,
+	and don't use GSYM_PREFIX with _GLOBAL_OFFSET_TABLE_.
+
+	* tune/freq.c (speed_cpu_frequency_measure): New test comparing
+	gettimeofday and speed_cyclecounter, should cover many systems.
+
+2000-10-27  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/ia64/gmp-mparam.h: Retune.
+
+2000-10-26  Torbjorn Granlund  <tege@swox.com>
+
+	* longlong.h (ia64): Set UMUL_TIME and UDIV_TIME.
+
+	* mpn/ia64/submul_1.c: Fix typo.
+
+2000-10-25  Kevin Ryde  <kevin@swox.se>
+
+	* tune/freq.c (speed_cpu_frequency_sysctl): New test, supporting
+	hw.model for BSD flavours.
+	* configure.in (sysctl, sys/param.h): New tests.
+
+2000-10-24  Torbjorn Granlund  <tege@swox.com>
+
+	* tune/freq.c: Explicitly #include config.h before other include files.
+
+	* mpz/tests/reuse.c (FAIL2): New #define.
+	(main): Use FAIL2.  Now this test properly returns non-zero exit
+	status when it fails.
+
+	* mpn/powerpc32/gmp-mparam.h: Retune.
+	* mpn/powerpc64/gmp-mparam.h: Retune.
+
+2000-10-24  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/x86/k6/cross.pl: Support 8 and 16 byte code alignment.
+
+	* mpq/aors.c, mpq/canonicalize.c: Skip two mpz_divexact calls if
+	gcd gives 1, which should be 60% of the time.
+	* gmp-impl.h (MPZ_EQUAL_1_P): New macro.
+	* mpq/mul.c, mpq/div.c: Use it, and a new DIV_OR_SET.
+
+	* tune/tuneup.c (xp_block, yp_block): Initialize these with random
+	data.  Fixes GCD_ACCEL and GCDEXT thresholds, and latest POWM.
+
+2000-10-23  Torbjorn Granlund  <tege@swox.com>
+
+	* configure.in [SPEED_CYCLECOUNTER_OBJS switch]: Add ia64 case.
+
+	* mpn/ia64/gmp-mparam.h: Fill in some parameters.
+
+	* mpn/ia64/submul_1.c: New file.
+
+	* tune/ia64.asm: New file.
+
+	* gmp-impl.h (union ieee_double_extract): Handle ia64.
+
+	* mpn/mp_bases.c: Decrease chars_per_bit_exactly for entry 1 to
+	work around buggy ia64-linux.
+
+	* longlong.h (ia64 umul_ppmm): Update register flags to match new GCC.
+
+2000-10-22  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/alpha/ev6/gmp-mparam.h (DC_THRESHOLD): Update.
+	* mpn/alpha/ev6/submul_1.asm: New file.
+
+2000-10-22  Kevin Ryde  <kevin@swox.se>
+
+	* tune/gcd_bin.c: New file.
+	* tune/gcd_finda_gen.c: New file.
+	* tune/Makefile.am (libspeed_la_SOURCES): Add them.
+	* tune/speed.[ch],common.c (mpn_gcd_binary, find_a): Add measuring.
+
+	* * (__gmp_allocate_func etc): Rename from _mp_allocate_func etc.
+	(__gmp_default_allocate etc): Rename from _mp_default_allocate etc.
+	* gmp-impl.h (__GMP_REALLOCATE_FUNC_TYPE,
+	__GMP_REALLOCATE_FUNC_LIMBS): New macros.
+
+	* gmp-impl.h (DC_THRESHOLD): Establish default here, set to 3*KARA
+	since that's the measured average.
+	* mpn/generic/dc_divrem_n.c, mpn/generic/tdiv_qr.c (DC_THRESHOLD):
+	Remove default.
+
+2000-10-21  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/Makefile.am (TARG_DIST): Add ia64.
+
+2000-10-21  Kevin Ryde  <kevin@swox.se>
+
+	* *: Change BZ -> DC.
+	* mpn/generic/dc_divrem_n.c: Renamed from bz_divrem_n.c.
+
+	* doc/multiplication: Remove file, now in the manual.
+	* doc/assembly_code: Ditto.
+	* tune/README: Remove some parts now in the manual.
+
+	* gmp.texi (@m etc): Add and use some new macros.
+	(Integer Division - mpz_[cft]div_*): Merge descriptions, for brevity
+	and to emphasise similarities.
+	(Low-Level Functions - mpn_[lr]shift): Specify count as 1 to
+	mp_bits_per_limb-1.
+	(Algorithms): New chapter.
+	(References): Add some papers.
+
+	* mpn/generic/mul_n.c (mpn_toom3_mul_n, mpn_toom3_sqr_n): Remove some
+	unused variables.
+	* mpn/generic/mul_fft.c (mpn_fft_best_k): Ditto.
+
+	* tune/freq.c: New file, split from time.c.
+	* tune/time.c: Rewrite, now more automated.
+	* configure.in, tune/*: Consequent changes.
+
+2000-10-20  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/ia64/default.m4: New file.
+	* configure.in [config.m4 switch] (ia64*-*-*): Use ia64/default.m4.
+
+	* mpn/ia64/mul_1.asm: New file.
+	* mpn/ia64/addmul_1.asm: New file.
+	* mpn/ia64/add_n.asm: New file.
+	* mpn/ia64/sub_n.asm: New file.
+	* mpn/ia64/popcount.asm: New file.
+	* mpn/ia64/README: New file.
+
+	* mpn/alpha/cntlz.asm: Override `.set noat' from ASM_START.
+
+	* configure.in (HAVE_TARGET_CPU_*): Support hppa1.0, hppa1.1, hppa2.0
+	by sed'ing the period into `_'.
+
+	* acconfig.h: Add #undefs for hppa targets.
+
+	* longlong.h (udiv_qrnnd): Fix typo in last change.
+
+	* mpz/tstbit.c: Rewrite (partly to work around GCC 2.95.2 HPPA bug).
+
+	* configure.in [path switch]:
+	(hppa2.0*-*-*): For non-CC64 case, update path.
+
+	* configure.in [compiler switch]:
+	(hppa2.0w-*-*): Match with same regexp in both places.
+	(hppa*-*-*): New case.
+	(all hppa alternatives): Don't inherit default gmp_cflags_cc,
+	gmp_cflags_c89.
+
+2000-10-18  Torbjorn Granlund  <tege@swox.com>
+
+	* configure.in (alpha*-*-*): Define gmp_xoptcflags_gcc like for
+	alpha*-*-osf*.
+
+	* longlong.h (x86 udiv_qrnnd): Change `d' => `dx' to avoid K&R C
+	stringification.
+
+2000-10-15  Kevin Ryde  <kevin@swox.se>
+
+	* doc/configuration: Updates.
+
+	* demos/calc.y: Remove some comments.
+
+2000-10-14  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi (Parameter Conventions, Memory Management): New sections
+	split from "Variable Conventions".
+	(Efficiency, Debugging, Profiling): New sections in "GMP Basics".
+	(Reentrancy): Some rewording, add note on standard I/O.
+	(Build options): Add --enable-assert and --enable-profiling.
+
+	* configure.in (--enable-profiling): New option.
+	* acinclude.m4 (GMP_ASM_X86_MCOUNT): New macro, finding how to profile.
+	* mpn/x86/x86-defs.m4 (PROLOGUE_cpu, call_mcount): Profiling support.
+
+	* acinclude.m4, configure.in (GMP_ASM_*): Rename from GMP_CHECK_ASM_*,
+	to follow autoconf conventions.
+
+	* configure.in: Run GMP_CHECK_ASM tests only if needed.
+	* acinclude.m4 (GMP_CHECK_ASM_MMX): Don't use GMP_CHECK_ASM_TEXT.
+
+	* mpn/x86/x86-defs.m4 (ASSERT): Allow no condition, to just emit code.
+
+2000-10-13  Kevin Ryde  <kevin@swox.se>
+
+	* mpq/md_2exp.c: New file.
+	* mpq/Makefile.am (libmpq_la_SOURCES): Add it.
+	* Makefile.am (MPQ_OBJECTS): Ditto.
+	* gmp.h (mpq_mul_2exp, mpq_div_2exp): Add prototypes.
+	* gmp.texi (Rational Arithmetic): Add documentation.
+
+	* mpq/tests/t-md_2exp.c: New file.
+	* mpq/tests/Makefile.am (check_PROGRAMS): Add it.
+
+	* mpn/generic/perfsqr.c: Add/amend some comments.
+
+	* gmp.texi (Known Build Problems): Note VERSION problem with old
+	sed, do some minor rewording.
+	(Build Options): Add cygwin and djgpp URLs, mention INSTALL.autoconf,
+	mention HTML.
+	(Getting the Latest Version of GMP): Move this ...
+	(Introduction to GMP): ... to here.
+	(Compatibility with older versions): Just refer to 2.x and 3.x, not
+	every minor version.
+	(Initializing Integers): Note restrictions on mpz_array_init'ed
+	variables.
+	(Integer Logic and Bit Fiddling): Note bits are numbered from 0.
+
+	* INSTALL.autoconf: New file.
+	* Makefile.am (EXTRA_DIST): Add it.
+
+	* tune/Makefile.am, tune/tuneup.c, configure.in, gmp-impl.h: New
+	scheme for recompiled objects used by tune program.  Don't use
+	libgmptune.a, make better use of libtool, work with ansi2knr.
+
+	* tune/speed.h,common.c (SPEED_ROUTINE_MPZ_POWM): Use s->yp and
+	s->xp_block, make exponent a fixed size.
+
+2000-10-07  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/mips3/gmp-mparam.h: Retune.
+
+	* mpn/generic/mul_n.c (USE_MORE_MPN): Revert last change.
+
+2000-10-06  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/mips3/add_n.s: Decrease carry recurrence from 4 to 3 cycles.
+	* mpn/mips3/sub_n.s: Likewise.
+
+2000-10-04  Torbjorn Granlund  <tege@swox.com>
+
+	* configure.in (sparc64-*-linux*): Set path according to CC64.
+
+2000-10-04  Kevin Ryde  <kevin@swox.se>
+
+	* acinclude.m4 (GMP_CHECK_ASM_UNDERSCORE): Use LABEL_SUFFIX, not a
+	hard-coded ":".
+
+	* config.sub: Don't demand "86" in CPU name for SCO.
+
+	* configure.in (supersparc-*-*): Remove -DSUPERSPARC.
+	* longlong.h: Use HAVE_TARGET_CPU_supersparc.
+
+	* configure.in (HAVE_TARGET_CPU_*): AC_DEFINE from $target_cpu.
+	* acconfig.h: Add #undefs, but only for targets of interest.
+
+2000-10-03  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/alpha/cntlz.asm: Rewrite.
+
+	* mp_clz_tab.c (__clz_tab): Half table size to 128 entires.
+	* longlong.h (count_leading_zeros): Demand just 128 entries from
+	__clz_tab.
+
+	* configure.in (mips-sgi-irix6.*): Pass -mips3 in addition to options
+	for n32 ABI.
+
+	* longlong.h: Move NO_ASM test around all assembly code.
+	From gcc:
+	* longlong.h (count_leading_zeros): Sparclite scan instruction was
+	being invoked incorrectly.
+	Replace __mc68332__ with __mcpu32__.
+	Add ARC support.
+
+2000-10-02  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/mips3/gmp-mparam.h: Retune for both gcc and cc.
+
+	* mpn/generic/mul_n.c (USE_MORE_MPN): Remove exception for __mips.
+	(interpolate3): Cast mp_limb_t variables to mp_limb_signed_t
+	when testing sign bit.
+
+	* mpn/alpha/ev6/gmp-mparam.h: Retune.
+	* mpn/powerpc32/gmp-mparam.h: Retune.
+	* mpn/powerpc64/gmp-mparam.h: Retune.
+	* mpn/x86/pentium/gmp-mparam.h: Retune.
+	* mpn/x86/pentium/mmx/gmp-mparam.h: Retune.
+	* mpn/sparc32/v9/gmp-mparam.h: Retune.
+	* mpn/x86/k6/gmp-mparam.h: Retune.
+	* mpn/x86/p6/gmp-mparam.h: Retune.
+	* mpn/x86/k7/gmp-mparam.h: Retune.
+	* mpn/sparc64/gmp-mparam.h: Retune.
+
+	* mpn/m68k/gmp-mparam.h: New file.
+	* mpn/alpha/ev5/gmp-mparam.h: New file.
+
+	* gmp-impl.h (default MPN_COPY): Remove final `;'.
+
+	* tune/time.c (speed_endtime): Rewrite.
+
+	* tune/speed.h (SPEED_ROUTINE_MPZ_POWM): Set base to a large value,
+	not 2.
+
+	* demos/pexpr.c (setup_error_handler): Fix typo.
+
+	* mpz/powm.c (redc): New function, based on old mpz_redc.  Don't
+	multiply here.
+	(mpz_redc): Remove.
+	(mpz_powm): Major changes, partially reverting to mpn calls.
+	Multiply before calling redc.
+	(mpz_powm): Use TMP_ allocation.
+	(mpz_powm): Refine calculation of k (width of exponent window).
+	(mpz_powm): Cast constants to mp_limb_t before left shifting.
+
+	* longlong.h: Use ia64 count_leading_zeros just when __GNUC__.
+
+2000-09-29  Kevin Ryde  <kevin@swox.se>
+
+	* acinclude.m4 (GMP_C_SIZES): New macro.
+	* configure.in: Use it.
+	* acconfig.in (BYTES_PER_MP_LIMB etc): Add #undefs.
+	* mpn/generic/gmp-mparam.h (BYTES_PER_MP_LIMB etc): Remove #defines.
+	* gmp.texi (Known Build Problems): Remove 64-bit generic C
+	gmp-mparam.h problem, now fixed.
+
+	* configure.in: Only run GMP_PROG_M4 if it's actually needed.
+
+2000-09-27  Torbjorn Granlund  <tege@swox.com>
+
+	* demos/pexpr.c: Clean up code for systems not supporting
+	sigaltstack.  Handle old Linux without sigaltstack.  Properly
+	disable all stuff related to sigaltstack under Unicos.
+
+	* mpn/alpha/ev6/addmul_1.asm: Use explicit offset for all load and
+	store insns.  Helps old gas.
+
+	* longlong.h (count_leading_zeros): Define for ia64.
+
+2000-09-27  Paul Zimmermann  <Paul.Zimmermann@loria.fr>
+
+	* mpn/generic/bz_divrem_n.c: Fix qhl handling, simplify.
+
+2000-09-27  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/Makefile.in (.SUFFIXES): Regenerate with patched automake to
+	get .s before .c, which is needed to override ansi2knr .c rules.
+
+	* gmp.texi (mpn_sqrtrem): Fix r2p==NULL return value description
+	to match the code (change by Torbjorn).
+	(mpn_gcd, mpn_gcdext, mpn_sqrtrem, mpn_tdiv_qr): Note most
+	significant limbs must be non-zero.
+	(mpn_gcd, mpn_gcdext, mpn_sqrtrem): Clarify destination size
+	requirements.
+	(mpn_gcd_1): Clarify value must be non-zero, not just size.
+
+	* gmp-impl.h (mpn_zero_p): New inline function.
+	* mpn/generic/inlines.c: Add gmp-impl.h.
+	* mpf/integer.c, mpz/get_d.c, mpn/generic/mul_fft.c: Use it.
+
+	* mpn/generic/gcd.c: Use MPN_COPY_INCR not MPN_COPY.
+	* mpf/add_ui.c: Ditto.
+	* mpf/add.c: Ditto, and fix test to skip copy.
+
+2000-09-26  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-impl.h, longlong.h, mpn/generic/*.c: Add ASSERTs for various
+	parameter restrictions.
+
+	* gmp-impl.h (UDIV_PREINV_TIME): New macro.
+	* mpn/generic/sb_divrem_mn.c: Use it.
+	* mpn/generic/perfsqr.c: Ditto.
+	* mpn/x86/*/gmp-mparam.h (UDIV_PREINV_TIME): Add values.
+
+	* macos/Makefile.in: Add mpz/tests/t-get_si.c, mpf/tests/t-set_f.c,
+	and new multi-function mpz and mpq files.
+
+2000-09-25  Kevin Ryde  <kevin@swox.se>
+
+	* randlc.c, randlc2x.c, randsd.c, mpz/urandomb.c, mpz/urandomm.c:
+	Use mpz_ptr and mpz_srcptr for parameters.
+	* gmp.h (gmp_randinit_lc, gmp_randinit_lc_2exp, gmp_randseed,
+	mpz_urandomb, mpz_urandomm): Corresponding change to prototypes.
+	* randsdui.c: Remove wrong K&R parameters part.
+
+2000-09-12  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-impl.h (mpn_tdiv_qr): Move prototype from here ...
+	* gmp.h (mpn_tdiv_qr): ... to here.
+
+	* gmp.texi (Miscellaneous Rational Functions): Comment-out and
+	move version 1 compatibility note to "Compatibility" section.
+	(Rational Number Functions): Ditto for canonicalization note.
+
+2000-09-10  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/x86/pentium/com_n.asm: New file.
+
+	* gmp.texi (Rational Arithmetic): Add mpq_abs.
+	(Miscellaneous Rational Functions): Merge and simplify descriptions of
+	mpq_get_num, mpq_get_den, mpq_set_num, mpq_set_den.
+
+	* mpq/abs.c: New file.
+	* mpq/Makefile.am (libmpq_la_SOURCES): Add it.
+	* Makefile.am (MPQ_OBJECTS): Add it.
+	* gmp.h (mpq_abs): Add prototype.
+
+	* mpq/set_den.c: Don't discard sign when copying, this makes the
+	code match the manual.
+
+2000-09-07  Torbjorn Granlund  <tege@swox.com>
+
+	* tune/alpha.asm: Rewrite to actually work right.
+
+2000-09-07  Kevin Ryde  <kevin@swox.se>
+
+	* tune/common.c,speed.[ch]: Add measuring of mpn_sqrtrem,
+	mpn_get_str, mpn_set_str.
+	* tune/README: Various updates.
+
+2000-09-06  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/fits.c: Correct type of `data'.
+
+2000-09-06  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi (Build Options): Clarify where to find CFLAGS.
+	(Known Build Problems): Note SCO -lc problem.
+
+	* tune/speed.h (SPEED_ROUTINE_MPN_GCD_CALL): Fix for sizes > 512 limbs.
+
+	* doc/multiplication: Corrections and additions suggested by Paul.
+
+	* tune/modlinv.c: New file with alternate modlimb_inverts.
+	* tune/Makefile.am, tune/speed.[ch]: Add measuring of them.
+	* tune/speed.c (FLAG_NODATA): New attribute, use for mpz_bin_uiui,
+	mpz_fib_ui, mpz_fac_ui.
+
+	* mpn/x86/t-zdisp.sh: New file.
+
+	* tests/t-modlinv.c: New file.
+	* tests/Makefile.am (check_PROGRAMS): Add it.
+
+	* mpq/tests/t-set_f.c: New file.
+	* mpq/tests/Makefile.am (check_PROGRAMS): Add it.
+
+	* gmp-impl.h (MPQ_CHECK_FORMAT): New macro.
+	* mpq/tests/t-get_d.c: Use it.
+
+	* mpq/set_f.c: New file.
+	* mpq/Makefile.am (libmpq_la_SOURCES): Add it.
+	* Makefile.am (MPQ_OBJECTS): Ditto.
+	* gmp.h: Add prototype.
+	* gmp.texi (Miscellaneous Rational Functions): Document mpq_set_f,
+	correct return type of mpq_set_d.
+
+2000-09-03  Kevin Ryde  <kevin@swox.se>
+
+	* mpz/aors_ui.c: New file merging add_ui.c and sub_ui.c, no object
+	code changes.
+	* mpz/add_ui.c, mpz/sub_ui.c: Remove files.
+	* mpz/Makefile.am: Update.
+
+	* gmp-impl.h (MPZ_FITS_STYPE_SDT, MPZ_FITS_UTYPE_SDT): New macros.
+	* mpz/fits.c: New file merging six separate fits*.c.
+	* mpz/fits_sshort_p.c, fits_sint_p.c, fits_slong_p.c, fits_ushort_p.c,
+	fits_uint_p.c, fits_ulong_p.c: Remove files
+	* mpz/Makefile.am: Use new fits.c, change object names from
+	fits_*_p.lo to fits_*.lo to avoid SunOS 4 native "ar" warnings.
+	* Makefile.am (MPZ_OBJECTS): Change from fits_*_p.lo to fits_*.lo.
+
+	* acinclude.m4 (GMP_CHECK_ASM_RODATA): New macro, defining RODATA.
+	* configure.in: Use it.
+	* mpn/x86/k[67]/mmx/popham.asm: Use it.
+
+	* mpn/x86/*/*.asm: Use "TEXT" not ".text".
+
+2000-09-02  Kevin Ryde  <kevin@swox.se>
+
+	* mpq/aors.c: New file merging add.c and sub.c, no object code changes.
+	* mpq/add.c, mpq/sub.c: Remove files.
+	* mpq/Makefile.am: Update.
+
+	* mpz/aors.c: New file merging add.c and sub.c, no object code changes.
+	* mpz/add.c, mpz/sub.c: Remove files.
+	* mpz/Makefile.am, mpbsd/Makefile.am: Update.
+
+	* configure.in: Re-apply "PROLOGUE.*" regexp change for the
+	benefit of alpha PROLOGUE_GP, lost in path search reorganisation.
+
+	* mpn/x86/x86-defs.m4 (jadcl0, cmov_simulate, ASSERT,
+	movl_text_address): Don't use "1:" style labels.
+	(Zdisp): Rearrange a bit, switch to all hex.
+	* mpn/x86/README.family: Note SCO "as" doesn't support "1:" style
+	local labels, misc rewordings.
+
+2000-08-29  Torbjorn Granlund  <tege@swox.com>
+
+	* demos/primes.c: Include string.h.
+
+	* config.guess (x86 variant recog code): Remove dummy*.o files
+	generated by some compilers.
+
+2000-08-28  Kevin Ryde  <kevin@swox.se>
+
+	* acinclude.m4 (GMP_CHECK_ASM_ALIGN_FILL_0x90): Fix Solaris 2.8
+	warning message suppression, add notes about SCO.
+
+	* Makefile.am (MPZ_OBJECTS etc): Move some comments.
+
+2000-08-25  Kevin Ryde  <kevin@swox.se>
+
+	* mpz/pprime_p.c (mpz_millerrabin): Fix a TMP_FREE.
+
+	* gmp.texi (Copying): Refer to Lesser not Library GPL.
+	(GMP and Reentrancy): Note stack-alloc.c is not reentrant, and
+	that SCO <ctype.h> is potentially not reentrant.
+
+	* acinclude.m4 (GMP_CHECK_ASM_UNDERSCORE): Test by attempting to
+	link with or without an underscore.
+	* gmp.texi (Known Build Problems): Remove SunOS 4 native grep
+	GSYM_PREFIX problem, now fixed.
+
+	* gmp-impl.h (MODLIMB_INVERSE_3): New constant.
+	* mpn/generic/diveby3.c: Use it instead of own INVERSE_3.
+	* mpn/generic/mul_n.c: Ditto.
+	* tests/t-constants.c: Check it, and PP_INVERTED too.
+
+	* acinclude.m4 (GMP_GCC_MARCH_PENTIUMPRO): New macro.
+	* configure.in [p6 and athlon] (gmp_optcflags_gcc): Use it to
+	possibly add -march=pentiumpro.
+
+	* gmp-impl.h (MPZ_SET_STR_OR_ABORT, MPF_SET_STR_OR_ABORT): New macros.
+	* mpz/tests/t-bin.c, mpz/tests/t-get_si.c, mpz/tests/t-jac.c,
+	mpz/tests/t-misc.c: Use them.
+	* mpf/tests/t-conv.c, mpf/tests/t-misc.c: Ditto.
+	* mpz/tests/convert.c: Ditto and amend diagnostics slightly.
+	* mpz/tests/t-misc.c (check_mpz_set_si): Remove a superfluous init.
+	* mpz/tests/io.c: Differentiate between I/O and data conversion errors.
+
+	* mpn/generic/aors_n.c: New file merging add_n and sub_n, no
+	object code changes.
+	* mpn/generic/add_n.c: Remove file.
+	* mpn/generic/sub_n.c: Remove file.
+
+	* mpn/generic/aorsmul_1.c: New file merging addmul_1 and submul_1,
+	no object code changes.
+	* mpn/generic/addmul_1.c: Remove file.
+	* mpn/generic/submul_1.c: Remove file.
+
+	* mpn/generic/popham.c: New file merging popcount and hamdist, no
+	object code changes.
+	* mpn/generic/popcount.c: Remove file.
+	* mpn/generic/hamdist.c: Remove file.
+
+2000-08-24  Torbjorn Granlund  <tege@swox.com>
+
+	* gmp-impl.h (mpn_com_n): Fix typo.
+
+2000-08-23  Torbjorn Granlund  <tege@swox.com>
+
+	* demos/primes.c (main): Don't call mpz_probab_prime_p for numbers
+	that are known to be prime after sieving.
+	(main): Declare and initialize max_s_prime_squared.
+	(MAX_S_PRIME): Increase.
+	(ST_SIZE): Increase.
+
+2000-08-23  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-impl.h (ASSERT_ALWAYS): Change to statement style.
+	(JACOBI_TWO_U_BIT1): Remove ASSERT.
+	(MPZ_CHECK_FORMAT): Use ASSERT_ALWAYS as a statement.
+
+2000-08-21  Torbjorn Granlund  <tege@swox.com>
+
+	* gmp-impl.h (ASSERT): Use do..while for dummy version.
+
+	* mpf/get_str.c: Don't set n_digits from digits_computed_so_far
+	when the converted operand becomes zero.  Misc cleanups.
+
+2000-08-21  Kevin Ryde  <kevin@swox.se>
+
+	* mpz/fdiv_r_2exp.c, mpz/lcm.c, mpz/urandomm.c: Add missing
+	TMP_MARK/FREE, avoiding memory leak when using stack-alloc.c.
+
+2000-08-20  Kevin Ryde  <kevin@swox.se>
+
+	* mpz/set.c [BERKELEY_MP] (move): Add conditionals to build as
+	"move" for libmp.
+	* mpbsd/Makefile.am: Use mpz/set.c, not move.c.
+	* Makefile.am (MPBSD_OBJECTS): Corresponding change.
+	* mpbsd/move.c: Remove file.
+
+	* mpn/Makefile.am, mpz/Makefile.am, mpq/Makefile.am, mpf/Makefile.am,
+	mpbsd/Makefile.am (-DOPERATION_foo): Use "foo" even for ansi2knr
+	"foo_" objects.  Do this with the makefiles to keep the sources
+	cleaner.
+	* mpz/mul_siui.c, mpf/integer.c: Revert to plain OPERATION_* forms.
+
+	* mpn/lisp/gmpasm-mode.el (gmpasm-remove-from-list): Renamed from
+	gmpasm-delete-from-list, because it's non-destructive.
+	(gmpasm-font-lock-keywords): Add some more keywords.
+
+2000-08-16  Kevin Ryde  <kevin@swox.se>
+
+	* tune/mul_n_mpn.c, tune/mul_n_open.c: New files, being forced
+	open-coded and mpn #includes of mpn/generic/mul_n.c.
+	* tune/*: Add measuring of them.
+	* tune/speed.c: Print command line into *.gnuplot file.
+
+	* mpn/generic/mul_n.c (USE_MORE_MPN): Change to #if not #ifdef for
+	using the value, add #ifndef for providing the default.
+	* mpn/sparc64/gmp-mparam.h (USE_MORE_MPN): Add #ifndef.
+
+	* tests/t-constants.c: New file.
+	* tests/Makefile.am (check_PROGRAMS): Add it.
+
+	* mpz/get_si.c: Use LONG_MAX, not BITS_PER_MP_LIMB, so the result
+	doesn't depend on limb size when outside the range of a long
+	(though such results are not actually documented).
+	* mpz/tests/t-get_si.c: New file.
+	* mpz/tests/Makefile.am (check_PROGRAMS): Add it.
+
+	* mpn/tests/try.c (call): Cast popcount and hamdist calls,
+	for the benefit of long long limb.
+
+2000-08-15  Kevin Ryde  <kevin@swox.se>
+
+	* mp.h (mp_set_memory_functions): Add missing #define.
+	* mpbsd/tests/allfuns.c (mp_set_memory_functions): Verify its
+	existence.
+
+	* mpf/tests/t-misc.c (check_mpf_getset_prec): New test, verifying
+	reverted behaviour of mpf_get_prec.
+
+	* mpn/tests/ref.c (refmpn_strip_twos): Use refmpn_copyi, not
+	MPN_COPY_INCR.
+
+	* mpz/mul_siui.c, mpf/integer.c: Recognise OPERATION_*_ forms
+	produced under ansi2knr.
+
+	* configure.in (mpn_objects, mpn_objs_in_libgmp): Add $U to .c
+	objects when ansi2knr in use.
+
+	* mpn/Makefile.am (AUTOMAKE_OPTIONS): Enable ansi2knr.
+	(libdummy.la): Add this, not built, to create ansi2knr style rules
+	for all potential .c files.
+	* mpz/Makefile.am, mpq/Makefile.am, mpf/Makefile.am, mpfr/Makefile.am,
+	mpbsd/Makefile.am, mpq/tests/Makefile.am, tests/Makefile.am
+	(AUTOMAKE_OPTIONS): Enable ansi2knr (now everywhere).
+	* Makefile.am (MPZ_OBJECTS, MPQ_OBJECTS, MPF_OBJECTS, MPFR_OBJECTS,
+	MPBSD_OBJECTS, libmp_la_DEPENDENCIES): Add $U to all .lo filenames.
+
+2000-08-03  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/alpha/ev6/addmul_1.asm: Correct number of cycles to 3.5/28.
+
+2000-08-02  Torbjorn Granlund  <tege@swox.com>
+
+	* Version 3.1 released.
+
+	* gmp.texi: Rephrase mpf_urandomb documentation.
+
+	* mpn/alpha/ev6: New directory with ev6/21264 optimized code.
+	* mpn/alpha/ev6/addmul_1.asm: New file.
+	* mpn/alpha/ev6/gmp-mparam.h: New file.
+
+2000-08-02  Kevin Ryde  <kevin@swox.se>
+
+	* demos/factorize.c (random): Don't use "inline".
+
+	* mpfr/log.c, mpfr/mul_ui.c, mpfr/round.c, mpfr/set.c, mpfr/set_d.c:
+	Corrections to K&R parts.
+
+	* Makefile.am (EXTRA_HEADERS): Omit $(MPFR_HEADERS_OPTION).
+	* mpfr/Makefile.am (EXTRA_DIST): Add mpfr.h.
+
+	* gmp.texi (Known Build Problems): Note problem stripping libgmp.a.
+
+2000-08-02  Kent Boortz  <kent@swox.com>
+
+	* mpfr: Integrated experimental version of mpfr-0.4.
+	* configure.in: Changes for option --enable-mpfr.
+	* Makefile.am: Changes for option --enable-mpfr.
+
+2000-08-01  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/popcount.c: Disable SPARC v9 popc_limb pattern.
+	* mpn/generic/hamdist.c: Likewise.
+
+2000-08-01  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/tests/try.c (try_init): Account for ALIGNMENTS when sizing
+	source and dest regions.
+
+2000-07-31  Torbjorn Granlund  <tege@swox.com>
+
+	* mpf/get_str.c: Develop three extra digits, not just one.
+
+2000-07-31  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi (References): Add URL for invariant division.
+
+2000-07-30  Kevin Ryde  <kevin@swox.se>
+
+	* tune/time.c (speed_cpu_frequency_proc_cpuinfo): Add support for
+	alpha linux "cycle frequency".
+
+	* mpn/sparc64/gmp-mparam.h: Re-run tune program for FFT thresholds.
+
+2000-07-29  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi (ABI and ISA): Add sparc64-*-linux*.
+	* configure.in [sparc64-*-linux*] (gmp_cflags64_gcc): Same flags
+	as under solaris.
+
+	* configure.in (--enable-fft): New option, default "no".
+	* gmp.texi (Build Options): Describe it.
+	* mpn/generic/mul.c, mpn/generic/mul_n.c [WANT_FFT]: Use it.
+	* tune/tuneup.c [WANT_FFT]: By default don't probe FFTs if not enabled.
+	* NEWS: Multiplication optionally using FFT.
+
+	* tune/README: Notes on FFT and GCD thresholds, other minor updates.
+
+	* Makefile.am: Expunge the macos generated files update stuff.
+
+2000-07-28  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/x86/*/gmp-mparam.h: Add some FFT thresholds.
+
+2000-07-28  Kent Boortz  <kent@swox.se>
+
+	* macos/Asm*, macos/CmnObj, macos/Mp*: Delete directories.
+	* macos/Makefile: Delete file.
+	* macos/Makefile.cw: Delete file.
+	* macos/config.h: Delete file.
+	* macos/Asm/*.s: Delete files.
+	* macos/configure: Create target directories. Don't transform
+	'(C)' to '(;)' in a 'dnl' line comment in .asm file.
+	* Makefile.am: Delete macos targets.
+	* macos/README: Reflect that we reverted back to a build
+	process that require ""macos/configure" to run on MacOS.
+	This imply that MacPerl is needed for a build in MacOS.
+
+2000-07-27  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/generic/mul_fft.c: New file, by Paul Zimmermann, minor mods
+	applied.
+	* configure.in (gmp_mpn_functions): Add it.
+	* mpn/generic/mul.c, mpn/generic/mul_n.c: Use it.
+	* doc/multiplication: Describe it (briefly).
+
+	* gmp-impl.h (FFT_MUL_THRESHOLD etc): New thresholds.
+	(mpn_fft_best_k, mpn_fft_next_size, mpn_mul_fft, mpn_mul_fft_full):
+	New functions.
+	(numberof, TMP_ALLOC_TYPE etc, _MP_ALLOCATE_FUNC_TYPE etc,
+	UNSIGNED_TYPE_MAX etc): New macros.
+
+	* tune/*: Add FFT threshold tuning and speed measuring.
+	* tune/common.c: Avoid huge macro expansions for umul and udiv.
+
+	* mpz/tests/t-bin.c, mpz/tests/t-jac.c, mpz/tests/t-misc.c,
+	mpbsd/tests/t-misc.c, mpf/tests/t-misc.c, mpn/tests/try.c,
+	mpn/tests/spinner.c: Use new gmp-impl.h macros.
+
+	* demos/Makefile.am (BUILT_SOURCES): Don't need calc.c etc under this.
+
+2000-07-27  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/ia64/gmp-mparam.h: New file.
+
+2000-07-26  Torbjorn Granlund  <tege@swox.com>
+
+	* demos/isprime.c: Handle any number of arguments and print
+	classification for each.  Add `-q' option for old behaviour.
+
+2000-07-26  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi (Build Options): Mention djgpp stack size.
+	(Notes for Package Builds): New section.
+	(Compatibility with older versions): Update for 3.1, add mpf_get_prec.
+
+	* demos/factorize.c [__GLIBC__]: Don't declare random() under glibc.
+
+	* gmp.h (gmp_version): Add prototype and define.
+
+	* Makefile.am: Keep macos directory generated files up-to-date
+	during development and on a "make dist".
+
+2000-07-25  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/hppa/gmp-mparam.h: Update threshold values from new `tune' run.
+
+	* mpn/pa64/gmp-mparam.h: Fill in values from `make tune' run.
+	* mpn/pa64w/gmp-mparam.h: Likewise.
+	* mpn/mips3/gmp-mparam.h: Likewise.
+
+	* tune/hppa2.asm: Fix typo in .level directive.
+
+	* configure.in: Add sparc64-*-linux* support (from Jakub Jelinek).
+	* configure: Regenerate.
+
+	* mpn/sparc64/rshift.asm: Use %g5 instead of volatile stack frame area
+	for return value (from Jakub Jelinek).
+	* mpn/sparc64/lshift.asm: Likewise.
+
+	* mpf/get_prc.c: Revert Aug 8, 1996 change.
+
+	* version.c: No longer static.
+
+	* mpn/pa64/gmp-mparam.h: Only #define *_THRESHOLD if not already
+	defined.
+	* mpn/pa64w/gmp-mparam.h: Likewise.
+	* mpn/arm/gmp-mparam.h: Likewise.
+	* mpn/mips3/gmp-mparam.h: Likewise.
+
+2000-07-25  Kevin Ryde  <kevin@swox.se>
+
+	* INSTALL: It's "info -f ./gmp.info" to be sure of hitting the
+	gmp.info in the current directory.
+
+	* Makefile.am (libmp_la_DEPENDENCIES): Add mpz/cmp.lo, for last
+	mpz/powm.c fix.
+
+	* mpn/sparc64/addmul1h.asm, mpn/sparc64/submul1h.asm: Renamed from
+	addmul_1h.asm, submul_1h.asm to avoid name conflicts on an 8.3
+	filesystem.
+	* mpn/sparc64/addmul_1.asm, mpn/sparc64/submul_1.asm,
+	mpn/sparc64/mul_1.asm: Update include_mpn()s.
+
+2000-07-24  Torbjorn Granlund  <tege@swox.com>
+
+	* Update header of all files previously under the Library GPL
+	to instead be under the Lesser GPL.
+
+	* COPYING.LIB: Now Lesser GPL.
+	* demos/primes.c: Change license to GPL (was Library GPL).
+	* demos/isprime.c: Change license to GPL (was Library GPL).
+
+	* gmp.h (error code enum): Add GMP_ERROR_BAD_STRING (currently unused).
+
+	* mpz/tests/t-mul.c: Default SIZE to a function of TOOM3_MUL_THRESHOLD.
+	Improve error messages.  Decrease reps.
+
+2000-07-22  Kevin Ryde  <kevin@swox.se>
+
+	* tune/speed.h: Decrease the amount of data used for gcd and powm
+	measuring, to make the tune go a bit faster.
+
+2000-07-21  Kent Boortz  <kent@swox.se>
+
+	* macos/Asm*, macos/CmnObj, macos/Mp*: Directories no longer created
+	from configure script, now part of dist.
+	* macos/Makefile
+	* macos/Makefile.cw
+	* macos/config.h
+	* macos/Asm/*.s
+	New files and directories that is the output from configure. This way
+	no Perl installation is required to build on MacOS, just MPW.
+	* macos/configure: Added prefix '__g' to exported assembler labels.
+	Changed to handle new m4 syntax instead of the old cpp syntax in asm.
+	* macos/Makefile.in: Corrected 'clean' target, added 'distclean'
+	and 'maintainer_clean'. Added "mpn/mp_bases.c" to build.
+	* macos/README: Reflect the new build process without configure.
+	Corrected the file structure for Apple MPW installation.
+
+2000-07-21  Torbjorn Granlund  <tege@swox.com>
+
+	* mpf/tests/t-muldiv.c: Relax error limit.  Make precision depend
+	on SIZE.  Misc changes.
+
+	* configure: Regenerate.
+
+2000-07-20  Kent Boortz  <kent@swox.com>
+
+	* macos/Makefile.in: Removed hard coded targets, added special
+	targets found in Makefile.am files.
+	* macos/configure: Generate targets from top configure script and
+	Makefile.am files. Made script runnable from Unix for testing.
+	* macos/README: Notes about search paths for includes, contributed
+	by Marco Bambini.
+	* configure.in: Added comment about lines that the "macos/configure"
+	script depend on.
+
+2000-07-20  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/powm.c (mpz_powm): After final mpz_redc call, subtract `mod'
+	from result if it is greater than `mod'.
+
+2000-07-19  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/hppa/gmp-mparam.h: Fill in values from `make tune' run.
+	* mpn/alpha/gmp-mparam.h: Likewise.
+	* mpn/powerpc32/gmp-mparam.h: Likewise.
+
+	* tune/hppa.asm: New file.
+	* tune/hppa2.asm: New file.
+	* configure.in (SPEED_CYCLECOUNTER_OBJS): Set for hppa2*-*-* and
+	hppa*-*-*.
+	* tune/Makefile.am (EXTRA_DIST): Add hppa.asm and hppa2.asm.
+
+	* tune/speed.h (SPEED_ROUTINE_MPN_BZ_DIVREM_CALL): Declare `marker';
+	invoke TMP_FREE.
+
+	* mpn/hppa/hppa1_1/udiv_qrnnd.S: Use "%" instead of "'" for
+	reloc/symbol delimiter.
+
+2000-07-16  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc64/gmp-mparam.h: Update with output from tune utility.
+	* mpn/powerpc64/copyi.asm: New file.
+	* mpn/powerpc64/copyd.asm: New file.
+
+2000-07-16  Kevin Ryde  <kevin@swox.se>
+
+	* tune/*: Add measuring for umul_ppmm and udiv_qrnnd.
+
+2000-07-14  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/x86/k6/k62mmx: New directory.
+	* configure.in (k6[23]*-*-*): Use it.
+	* mpn/x86/k6/k62mmx/copyi.asm, mpn/x86/k6/k62mmx/copyd.asm: Move from
+	mmx directory, improve code alignment a bit.
+	* mpn/x86/k6/k62mmx/lshift.asm, mpn/x86/k6/k62mmx/rshift.asm: Ditto,
+	and improve addressing modes for pre-CXT cores.
+	* mpn/x86/x86-defs.m4 (Zdisp): Add an instruction.
+	* mpn/x86/k6/mmx/lshift.asm, mpn/x86/k6/mmx/rshift.asm: New files,
+	suiting plain K6.
+	* mpn/x86/README, mpn/x86/k6/README: Updates.
+	* mpn/x86/k6/mmx/*.asm: Update some comments.
+
+	* mpn/tests/Makefile.am: Use $(MAKE) in .asm rules, not "m".
+	* tune/Makefile.am: Use $(EXEEXT) and libtool --config objdir, for
+	the benefit of djgpp.
+
+	* */Makefile.in: Regenerate with patched automake that adds
+	$(EXEEXT) to EXTRA_PROGRAMS.
+
+	* mpn/tests/try.c: Add #ifdef to SIGBUS, for the benefit of djgpp.
+	* config.guess: Recognise pc:*:*:* as an x86, for djgpp.
+
+	* configure: Regenerate with patched autoconf to fix temp file
+	".hdr" which is invalid on a DOS 8.3 filesystem, and to fix two
+	sed substitutes that clobbered a ":" in $srcdir (eg. a DOS drive
+	spec).
+
+	* mpz/tests/io.c: Use one fp opened "w+", since separately opened
+	input and output doesn't work on MS-DOS 6.21.
+
+	* tests/rand/Makefile.am (allprogs): Pseudo-target to build everything.
+	(CLEANFILES): Add EXTRA_PROGRAMS and EXTRA_LTLIBRARIES.
+	(manual-test, manual-bigtest): Add $(EXEEXT) to dependencies.
+
+	* tests/rand/*/Makefile.in: Regenerate with patched automake that adds
+	$(EXEEXT) to EXTRA_PROGRAMS.
+
+2000-07-13  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/tests/t-root.c: Also test mpz_perfect_power_p.
+	Generate `nth' so that there will be fewer trivial values.
+
+	* mpz/root.c: Reverse return value in tests for detecting root of +1
+	and -1.
+
+	* mpz/perfpow.c: Use TMP_ALLOC interface.
+
+2000-07-12  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/perfpow.c (primes): Make it const.
+
+2000-07-06  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/x86/k6/cross.pl: New file.
+
+	* mpn/x86/*/gmp-mparam.h: Updates to thresholds, conditionalize
+	all _TIME defines.
+	* mpn/x86/pentium/mmx/gmp-mparam.h: New file.
+	* mpn/sparc64/gmp-mparam.h: Update thresholds.
+	* mpn/sparc32/v9/gmp-mparam.h: Ditto.
+
+2000-07-04  Kevin Ryde  <kevin@swox.se>
+
+	* NEWS: Updates.
+	* mpn/x86/*/README: Miscellaneous updates.
+
+	* tune/speed-ext.c: New file.
+	* tune/Makefile.am: Add it.
+	* tune/README: Updates.
+	* tune/speed.h (SPEED_ROUTINE_MPN_DIVREM_2): Bug fixes.
+
+	* demos/calc.y,calclex.l: New files.
+	* demos/calc.c,calc.h,calclex.c: New files, generated from .y and .l.
+	* demos/Makefile.am: Add them.
+
+	* gmp.h (mpq_swap, mpf_swap): Add prototypes and defines.
+
+2000-07-01  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi (ABI and ISA): New section, bringing together ABI notes.
+	(Build Options): Add MPN_PATH, various updates.
+	(Build Options): Add note on setting CFLAGS when setting CC.
+	(Notes for Particular Systems): Add -march=pentiumpro problem.
+	(Known Build Problems): Note on gmp-mparam.h for 64-bit generic C.
+	(GMP Variable Conventions): Add some info on user defined functions.
+	(Reporting Bugs): Minor rewording.
+
+	* configure.in (MPN_PATH): Renamed from mpn_path.
+
+	* gmp-impl.h (ULONG_MAX,ULONG_HIGHBIT,...,SHORT_MAX): New defines.
+	* mp[zf]/tests/t-misc.c: Use them.
+
+	* mpbsd/tests/t-misc.c: New file.
+	* mpbsd/tests/Makefile.am: Add it.
+
+	* Makefile.am (LIBGMP_LT_*, LIBMP_LT_*): Bump version info.
+	* gmp.h (__GNU_MP_VERSION_*): Bump to 3.1.
+
+	* mpf/tests/Makefile.am (AUTOMAKE_OPTIONS): Add ansi2knr.
+
+	* Makefile.am (libmp_la_SOURCES): Add mp_set_fns.c, accidentally
+	omitted in gmp 3.0.x.
+	* gmp.texi (Custom Allocation): Note this is available in mpbsd,
+	and some minor rewording.
+
+2000-06-30  Torbjorn Granlund  <tege@swox.com>
+
+	* demos/factorize.c (random): New function, defined conditionally.
+	(factor_using_pollard_rho): Use it, not mrand48.
+
+	* mpn/cray/README: New file.
+
+2000-06-30  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/x86/pentium/aorsmul_1.asm: Add MULFUNC_PROLOGUE.
+
+	* mpz/tests/t-jac.c: Test limbs on mpn_jacobi_base, not just ulongs.
+
+	* gmp-impl.h, mpn/tests/try.c, mpn/tests/spinner.c, tune/speed.c:
+	Use config.h unconditionally, not under HAVE_CONFIG_H.
+
+	* demos/pexpr.c [__DJGPP__]: Patch by Richard Dawe to not use
+	setup_error_handler on djgpp.
+
+	* tune/*: Locate data to help direct-mapped caches, add measuring
+	of mpz_init/clear, mpz_add and mpz_bin_uiui, various cleanups.
+	* configure.in (AC_CHECK_FUNCS): Add popen.
+
+2000-06-29  Torbjorn Granlund  <tege@swox.com>
+
+	* mpf/mul_2exp.c: Streamline criterion for whether to use mpn_lshift or
+	mpn_rshift.  Increase precision when exp is a multiple of
+	BITS_PER_MP_LIMB primarily to make exp==0 be a noop.
+	* mpf/div_2exp.c: Analogous changes.
+
+	* mpf/tests/t-dm2exp.c: Set u randomly in loop.  Perform more
+	mpf_mul_2exp testing.
+
+	* configure.in: Recognize cray vector processors with a broad `*';
+	move after alpha* not to match that.
+
+2000-06-28  Kevin Ryde  <kevin@swox.se>
+
+	* mpz/tests/io.c: Use a disk file, not a pipe, switch to ansi2knr
+	style, switch from MP_INT to mpz_t, add a couple of error checks.
+	* mpz/tests/Makefile.am (CLEANFILES): Add io.tmp, in case io.c fails.
+
+2000-06-27  Torbjorn Granlund  <tege@swox.com>
+
+	* mpf/tests/t-get_d.c: Be more lax about relative error, to handle Cray
+	floating point format.
+
+	* mpq/tests/t-get_d.c: Decrease default reps to 1000.
+
+	* mpf/tests/t-conv.c: Correct type of `bexp'.
+
+	* configure.in (cray vector machines): Don't inherit gmp_cflags_cc.
+
+	* tune/Makefile.am (EXTRA_DIST): Delete sparc64.asm.
+
+	* configure.in (cray vector machines): Set extra_functions.
+
+	* mpn/cray/mulww.f: New file with vectorizing cray code.
+	* mpn/cray/mulww.s: Generated from mulww.f.
+	* mpn/cray/mul_1.c: New file.
+	* mpn/cray/addmul_1.c: New file.
+	* mpn/cray/submul_1.c: New file.
+	* mpn/cray/add_n.c: New file.
+	* mpn/cray/sub_n.c: New file.
+
+2000-06-26  Kevin Ryde  <kevin@swox.se>
+
+	* acinclude.m4 (GMP_CHECK_ASM_ALIGN_FILL_0x90): Fix so it actually
+	detects solaris 2.6, and also suppress warning on solaris 2.8.
+	* configure.in (SPEED_CYCLECOUNTER): Remove spurious "athlon" from
+	sparc case.
+
+	* mpn/lisp/gmpasm-mode.el: Move keymap to the top of the docstring.
+
+2000-06-21  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/generic/mul_n.c (mpn_kara_mul_n, mpn_kara_sqr_n): Use
+	mp_size_t for n2.
+	(mpn_toom3_mul_n, mpn_toom3_sqr_n): Use mp_size_t for size
+	parameters and "l" variables.
+	* gmp-impl.h (mpn_toom3_mul_n, mpn_toom3_sqr_n): Update prototypes.
+
+	* mpbsd/itom.c, mpbsd/sdiv.c: Add casts for correct handling of
+	-0x80...00 on systems with sizeof(short)==sizeof(int).
+
+	* mpz/tests/t-misc.c: Move "bin" test from here ...
+	* mpz/tests/t-bin.c: ... to here, and add a new (2k,k) test too.
+	* mpz/tests/Makefile.am (check_PROGRAMS): Add t-bin.
+
+	* mpz/bin_ui.c [_LONG_LONG_LIMB]: Use mpn_divrem_1, since kacc is
+	a limb not a ulong.
+	* mpz/bin_uiui.c [_LONG_LONG_LIMB]: Ditto, and use mpn_mul_1 too,
+	since nacc is a limb.
+
+	* mpf/tests/t-misc.c (check_mpf_set_si, check_mpf_cmp_si):
+	New file, testing mpf_set_si, mpf_init_set_si, and mpf_cmp_si.
+	* mpf/tests/Makefile.am (check_PROGRAMS): Add it.
+
+	* mpz/tests/t-misc.c (check_mpz_set_si, check_mpz_cmp_si):
+	New tests, for mpz_set_si, mpz_init_set_si, and mpz_cmp_si.
+
+	* mpz/set_si.c, mpz/iset_si.c, mpz/cmp_si.c [_LONG_LONG_LIMB]: Fix
+	handling of -0x80..00.
+	* mpf/set_si.c, mpf/iset_si.c, mpf/cmp_si.c [_LONG_LONG_LIMB]: Ditto.
+
+2000-06-19  Torbjorn Granlund  <tege@swox.com>
+
+	* demos/primes.c: Properly handle arguments `m +n'.
+
+2000-06-17  Torbjorn Granlund  <tege@swox.com>
+
+	* config.sub: Recognize k5 and k6 with common pattern.
+
+	* mpq/tests/t-get_d.c: Also test mpq_set_d.  Misc improvements.
+
+	* mpq/set_d.c: Special case 0.0.  Don't call mpn_rshift with 0 count.
+	Allocate correct amount of memory for numerator.  Delete spurious
+	ASSERT_ALWAYS(1).
+
+2000-06-17  Kevin Ryde  <kevin@swox.se>
+
+	* mpz/perfsqr.c: Fix so that zero is considered a perfect square.
+	(Was wrongly calling mpn_perfect_square_p with size==0.)
+
+2000-06-16  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in: Set k5*-*-* to use basic i386 code until there's
+	something specific.  Add path=x86 as a default for x86s.
+
+	* acinclude.m4 (GMP_CHECK_ASM_ALIGN_LOG): Generate
+	ALIGN_LOGARITHMIC setting, not a full ALIGN definition.
+	(GMP_CHECK_ASM_ALIGN_FILL_0x90): New test.
+	* configure.in [x86-*-*]: Use GMP_CHECK_ASM_ALIGN_FILL_0x90.
+	* mpn/asm-defs.m4 (ALIGN): New macro.
+	* mpn/x86/x86-defs.m4 (ALIGN): Remove supplementary definition.
+
+	* tune/*: Plain "unsigned" for speed_cyclecounter.
+	* configure.in: Use tune/sparcv9.asm for 32 and 64 bit modes.
+	* tune/sparc64.asm: Remove file.
+
+2000-06-15  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/x86/k7/mmx/copyi.asm: Use `testb' instead of `test'.
+	* mpn/x86/k7/mmx/copyd.asm: Likewise.
+
+	* mpn/x86/k7/mmx/lshift.asm: Avoid using `~' (Solaris as problems).
+	* mpn/x86/k7/mmx/rshift.asm: Likewise.
+	* mpn/x86/k6/aors_n.asm: Likewise.
+	* mpn/x86/k7/aors_n.asm: Likewise.
+	* mpn/x86/k7/mul_basecase.asm: Likewise.
+
+2000-06-13  Torbjorn Granlund  <tege@swox.com>
+
+	* tune/sparcv9.asm: Tune, deleting two instructions.
+
+	* tune/alpha.asm: Update to unified speed_cyclecounter.
+
+2000-06-11  Kevin Ryde  <kevin@swox.se>
+
+	* mpz/tests/reuse.c (FAIL): Add a K&R version.
+	Use _PROTO on some typedefs.
+	* mpz/tests/t-misc.c: Add gmp-impl.h for "const".
+
+	* configure.in: Rework mpn multi-function and optional files.
+	Names standardized, no need for explicit declarations, all picked
+	up in one $path traversal.
+	* doc/configuration: Updates.
+
+	* tests/rand/t-rand.c (main): Change "usage" to work with K&R.
+
+2000-06-10  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/x86/pentium/mmx/popham.asm, mpn/x86/p6/mmx/popham.asm,
+	mpn/x86/p6/p3mmx/popham.asm, mpn/x86/p6/diveby3.asm: Add
+	MULFUNC_PROLOGUE for correct HAVE_NATIVE_* matching.
+
+	* mpn/x86/x86-defs.m4 (cmov_bytes_tttn): Use eval() on expressions.
+	(cmov_available_p): Switch to list CPUs which do have cmov.
+	* mpn/x86/p6/sqr_basecase.asm, mpn/x86/k6/sqr_basecase.asm,
+	mpn/x86/k7/sqr_basecase.asm: Use eval() for multiplication.
+	* mpn/x86/README.family: Various updates.
+
+2000-06-09  Kevin Ryde  <kevin@swox.se>
+
+	* mpbsd/tests/allfuns.c (main): Call exit() instead of doing return.
+
+	* doc/tasks.html, doc/projects.html: Moved from projects directory.
+	* doc/multiplication: New file.
+	* Makefile.am (EXTRA_DIST): Remove projects, add doc.
+
+	* Makefile.am (libgmp_la_LIBADD, libmp_la_LIBADD): Remove
+	unnecessary -lm.
+	* INSTALL: Remove -lm from instructions.
+	* demos/Makefile.am (qcn_LDADD): Add -lm.
+
+	* tune/*: Add measuring for mpn_divrem_2 and modlimb_invert,
+	improve addsub_n.  Switch to unified speed_cyclecounter.
+	* configure.in: Update configs for speed_cyclecounter.
+
+	* gmp-impl.h (MP_LIMB_T_MAX, MP_LIMB_T_HIGHBIT): New macros.
+	* mpn/generic/diveby3.c, mpn/generic/mul_n.c, mpn/generic/gcd.c,
+	tune/speed.c, mpn/tests/ref.c: Use them.
+
+	* mpn/tests/spinner.c: Remove setitimer, just alarm is enough.
+	* configure.in (AC_CHECK_FUNCS): Remove setitimer.
+	* mpn/tests/x86call.asm: Start with junk in %eax, %ecx, %edx.
+	* mpn/tests/ref.[ch] (refmpn_addsub_nc): New function.
+	* mpn/tests/try.c: Add some support for mpn_addsub_nc.
+	* mpn/tests/Makefile.am (EXTRA_PROGRAMS): Remove addsub_n and
+	addsub_n_2 which don't currently build.
+	* mpn/tests/copy.c: Test MPN_COPY_INCR, not __gmpn_copy.
+
+	* tests/rand/Makefile.am (libstat_la_LIBADD): Add -lm, no longer on
+	libgmp.la.
+	(findlc_LDADD): Use libstat.la.
+	(AUTOMAKE_OPTIONS): Use ansi2knr.
+
+2000-06-08  Torbjorn Granlund  <tege@swox.com>
+
+	* configure.in (alpha*-*-osf*): Default `flavour' to ev6 for ev6 and
+	higher.
+	(alpha*-*-*): Likewise.
+	(alpha*-*-osf*: gmp_optcflags_cc): Move -arch/-tune flags from
+	gmp_xoptcflags_gcc.
+
+	* mpn/Makefile.am (TARG_DIST): Add pa64w.
+
+	* longlong.h: Wrap 64-bit hppa code in #ifndef LONGLONG_STANDALONE.
+
+2000-06-07  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/remove.c: Fail for `src' being zero.
+
+	* mpz/tests/reuse.c: Test more functions.
+	(FAIL): New define.
+
+	* mpz/tests/t-powm.c: Loop during operand generation while they
+	are mathematically ill-defined (used to just skip such tests).
+
+	* mpz/powm.c (mpz_redc): Clean up argument declarations.
+
+	* configure.in (gmp_cflags64_gcc): Don't add bogus -mWHAT option.
+	(sparcv9-*-solaris2.[7-9]], gmp_cflags64_gcc):
+	Inherit from previous gmp_cflags64_gcc; pass `-m64 -mptr64'.
+	(ia64*-*-*): New.
+
+	* mpn/generic/dump.c: Make it work when an mp_limb_t is not `long'.
+
+	* mpf/set_prc.c: MPN_COPY => MPN_COPY_INCR.
+
+2000-06-06  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/mul_n.c (mpn_toom3_mul_n, mpn_toom3_sqr_n):
+	Use mpn_incr_u for final carry propagation.
+
+	* mpz/tests/t-gcd.c: Add calls to mpz_gcdext with argument t == NULL.
+
+	* mpz/tests/reuse.c: Major rewrite; test many more functions.
+
+	* mpz/powm_ui.c: When exp is 0, change res assign order in order
+	to handle argument overlap.
+	* mpz/powm.c: When exp is 0, change res assign order in order
+	to handle argument overlap.  Handle negative exp and mod arguments.
+
+	* mpz/gcdext.c: Rework code after mpn_gcdext call to handle
+	argument overlap.
+
+	* mpz/fdiv_qr.c: Read dividend->_mp_size before calling mpz_tdiv_qr
+	in order to handle argument overlap.
+	* mpz/cdiv_qr.c: Likewise.
+
+	* mpf/tests/reuse.c: Fix typo that effectively disabled `dis_funcs'
+	tests.  Clean up test for mpf_ui_div.
+
+2000-06-06  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/x86/p6/sqr_basecase.asm: New file.
+	* mpn/x86/mod_1.asm: Avoid one conditional jump.
+	* mpn/x86/p6/gmp-mparam.h: Update thresholds, #ifndef UMUL_TIME
+	and UDIV_TIME, add COUNT_TRAILING_ZEROS_TIME.
+
+	* mp_minv_tab.c: New file.
+	* Makefile.am (libgmp_la_SOURCES, libmp_la_SOURCES): Add it.
+	* gmp-impl.h (modlimb_invert): New macro.
+	* mpz/powm.c: Remove mpz_dmprepare, use modlimb_invert instead.
+	* mpn/generic/bdivmod.c: Use modlimb_invert instead of a loop.
+	* mpn/generic/gcd.c: Inline two small mpn_bdivmod calls, use
+	MPN_COPY_INCR not MPN_COPY in one place.
+
+2000-06-05  Torbjorn Granlund  <tege@swox.com>
+
+	* mpf/tests/reuse.c (dsi_funcs): Add mpf_mul_2exp and mpf_div_2exp.
+	(main): Clean up test for mpf_div_ui.
+
+	* mpf/mul_2exp.c: Correct criterion for whether to use mpn_lshift or
+	mpn_rshift.  MPN_COPY => MPN_COPY_INCR.  Coerce the two assignments to
+	r->_mp_size.
+
+	* mpf/div_2exp.c: Use mpn_rshift instead of mpn_lshift when overlap
+	so requires.  MPN_COPY => MPN_COPY_INCR.
+
+	* mpf/tests/t-dm2exp.c: Correct type of res_prec.
+
+2000-06-04  Kevin Ryde  <kevin@swox.se>
+
+	* mpz/bin_uiui.c: Fix result for n==0 and n==k.
+	* mpz/bin_ui.c: Fix result for k>n, add support for n<0.
+	* gmp.texi (Number Theoretic Functions): Update mpz_bin_ui to
+	note n<0 is supported.
+
+	* mpz/tests/t-misc.c: New file.
+	* mpz/tests/Makefile.am (check_PROGRAMS): Add it.
+
+2000-05-31  Kevin Ryde  <kevin@swox.se>
+
+	* tune/speed.* (FLAG_R_OPTIONAL): New option for routines, use on
+	mpn_gcd_1 and mpn_mul_basecase.
+	* tune/README: Update.
+
+	* tune/alpha.asm: New file, by Torbjorn.
+	* tune/Makefile.am (EXTRA_DIST): Add it.
+	* configure.in (alpha*-*-*): Use it.
+
+2000-05-31  Linus Nordberg  <linus@swox.se>
+
+	* doc/configuration: New file.
+
+2000-05-30  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/mul_basecase.c: Call mpn_mul_2 and mpn_addmul_2
+	if available.  Don't include longlong.h.
+
+	* doc/isa_abi_headache: New file.
+
+2000-05-30  Linus Nordberg  <linus@swox.se>
+
+	* configure.in (NM): Use AC_PROG_NM rather than AC_CHECK_TOOL to
+	find `nm'.  (AC_PROG_NM comes with Libtool and is needed to get
+	the `-B' option (BSD compatible output) included in $NM.)
+	(AR): Use AC_CHECK_PROG rather than AC_CHECK_TOOL to find `ar'.
+	(Now that NM isn't a cross compilation tool, don't give the
+	impression that we know how to cross compile.)
+	(CCAS): Remove spurious comment.
+
+	* gmp.texi (Notes for Particular Systems): Remove comment about
+	using GNU `nm' on AIX since system nm now works.
+
+2000-05-29  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/power/mul_1.s: Remove [PR] from first word in function
+	descriptor.
+	* mpn/power/addmul_1.s: Likewise.
+	* mpn/power/submul_1.s: Likewise.
+
+2000-05-28  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in, tune/*: Change pentium rdtsc cycle scheme to
+	HAVE_SPEED_CYCLECOUNTER and SPEED_CYCLECOUNTER_OBJS.
+	* tune/pentium.asm: Renamed and converted from rdtsc.asm.
+	* tune/sparcv9.asm: New file, by Torbjorn.
+	* tune/sparc64.asm: New file.
+	* tune/tuneup.c: Put a limit on gcdext search.
+
+	* gmp.h (mp_set_memory_functions): Add extern "C".
+	* mp.h (__GNU_MP__): Bump to "3".
+	* mpz/add.c,mul.c,powm.c,sub.c,sqrtrem.c,tdiv_qr.c [BERKELEY_MP]:
+	Include mp.h for mpbsd compile.
+	* mpz/gcd.c: Ditto, and remove _mpz_realloc declaration.
+
+	* gmp.texi (Integer Functions): Flatten @subsections into @sections.
+	(Floating-point Functions): Ditto.
+	(Integer Random Numbers): Split from miscellaneous as a sep section.
+	(Installing GMP): Make nodes for the sections.
+	Add more "@cindex"s.
+	(Known Build Problems): Remove SunOS get_d problem, believed fixed.
+	(Notes for Particular Systems): Remove HPPA note since now PIC.
+	(References): URL for Jebelean.
+
+2000-05-27  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/pa64w: New directory, contents based on corresponding mpn/pa64
+	files.
+	* configure.in (hppa2.0w-*-*): New.
+	* mpz/tests/io.c (_INCLUDE_POSIX_SOURCE): Define when __hpux before
+	including stdio.h.
+	* gmp-impl.h: Always define DItype and UDItype.
+
+2000-05-27  Kevin Ryde  <kevin@swox.se>
+
+	* tune/common.c (speed_measure): Correction to array sorting,
+	better diagnostic when measuring fails.
+	* tune/time.c: Add microsecond accurate getrusage method.
+
+	* tune/time.c (speed_cpu_frequency_processor_info): New function.
+	* configure.in (AC_CHECK_FUNCS): Add processor_info.
+
+2000-05-26  Linus Nordberg  <linus@swox.se>
+
+	* gmp.texi (Installing GMP): Shared libraries work for AIX < 4.3
+	if using GNU nm.
+
+2000-05-26  Torbjorn Granlund  <tege@swox.com>
+
+	* tune/tuneup.c (SIGNED_TYPE_MAX): Shift `-1' instead of `1' to
+	avoid signed overflow.
+
+	* demos/pexpr.c (setup_error_handler): Don't call sigaltstack on
+	Unicos.
+
+2000-05-25  Torbjorn Granlund  <tege@swox.com>
+
+	* insert-dbl.c: Work around GCC 2.8 bug.
+	* extract-dbl.c: Likewise.
+
+	* config.sub: Allow i586, i686, i786 again.
+
+	* config.guess: Use X86CPU for lots more systems.
+
+2000-05-25  Linus Nordberg  <linus@swox.se>
+
+	* mpbsd/tests/dummy.c (main): Call exit() instead of doing return
+	(some old SysV machines don't get this correct, I've heard.)
+
+2000-05-25  Kevin Ryde  <kevin@swox.se>
+
+	* mpf/iset_str.c: Initialize _mp_size and _mp_exp to 0, in case no
+	digits in string, so it's the same as a separate init and set_str.
+
+2000-05-24  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/tests/reuse.c: Use mpz_random2 instead of mpz_random.
+
+	* mpz/divexact.c: Read pointers after reallocation.
+	Compare `quot' and `den' instead of `qp' and `dp' in overlap check.
+	Use MPN_COPY_INCR for copying from `np'.
+
+	(*-*-aix4.[3-9]*): Disable shared libs just for problematic AIX
+	versions.
+	* configure.in (*-cray-unicos*): Disable asm syntax checking; set
+	compiler explicitly.
+	* configure.in (hppa*-*-*): Remove code disabling shared libs.
+
+2000-05-24  Linus Nordberg  <linus@swox.se>
+
+	* acinclude.m4 (GMP_PROG_CC_WORKS): Don't report progress to user
+	when doing the AIX specific test to avoid "nested output".
+
+2000-05-22  Kevin Ryde  <kevin@swox.se>
+
+	* mp.h (_PROTO): Copy from gmp.h, use on prototypes.
+	Add extern "C" too.
+	* mpbsd/tests/Makefile.am (AUTOMAKE_OPTIONS): Enable ansi2knr.
+	* mpbsd/tests/allfuns.c: Don't execute mout, just link to it.
+	(main): ANSI style definition.
+
+	* gmp-impl.h (MP_BASE_AS_DOUBLE): Change the expression to
+	something that works on SunOS native cc.  Seems to fix the
+	mp*_get_d problems.
+
+	* mpn/tests/ref.c (refmpn_strip_twos): Use MPN_COPY_INCR.
+	* mpn/tests/Makefile.am: Let .asm.o rules work with absolute $srcdir.
+
+2000-05-21  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/x86/k7/sqr_basecase.asm: Replace file with K7 specific code.
+	* mpn/x86/k7/README: Update.
+	* mpn/x86/k7/gmp-mparam.h: Tune thresholds.
+	(COUNT_TRAILING_ZEROS_TIME): New define.
+	* mpn/x86/k6/gmp-mparam.h: Ditto.
+
+	* mpn/x86/pentium/mmx/popham.asm: New file (include_mpn of K6 version).
+	* mpn/x86/p6/diveby3.asm: New file (include_mpn of P5 version).
+	* mpn/x86/p6/mmx/popham.asm: New file (include_mpn of K6 version).
+	* mpn/x86/p6/p3mmx/popham.asm: New file (include_mpn of K7 version).
+	* configure.in (pentium3-*-*): Add p3mmx to $path.
+
+	* gmp.texi (Integer Arithmetic): Clarify mpz_jacobi op2; add
+	mpz_*_kronecker_*.
+	(Miscellaneous Integer Functions): Add mpz_odd_p and mpz_even_p.
+	(Low-level Functions): Put mpn_divmod_1 with mpn_divrem_1 and note
+	it's now a macro.
+	(References): Add Henri Cohen.
+
+	* gmp.h (mpn_addmul_1c, mpn_divrem_1c, mpn_mod_1c, mpn_mul_1c,
+	mpn_submul_1c): Add prototypes.
+	(mpz_odd_p, mpz_even_p): New macros.
+
+	* mpn/asm-defs.m4 (m4wrap_prepend): New macro.
+	(m4_error): Use it.
+	(m4_not_for_expansion): Corrections to OPERATION symbols.
+	More comments about variations between m4 versions.
+	* mpn/x86/x86-defs.m4 (PROLOGUE): Use m4wrap_prepend (fixes error
+	exit under BSD m4, previously m4_error printed the message but the
+	exit code was 0).
+
+	* gmp.h (mpn_divmod_1): Change to a macro calling mpn_divrem_1.
+	* mpn/generic/divrem_1.c: Move divmod_1.c code to here, make it
+	static and call it __gmpn_divmod_1_internal.
+	* mpn/generic/divmod_1.c: Remove file.
+	* configure.in (gmp_mpn_functions): Remove divmod_1.
+	* mpn/asm-defs.m4 (define_mpn): Remove divmod_1 and divmod_1c.
+	* compat.c (mpn_divmod_1): Add compatibility function.
+	* tune/*: Remove mpn_divmod_1 measuring (leave just divrem_1).
+
+	* acconfig.h (HAVE_NATIVE_mpn_*): Add some missing carry-in
+	variants, remove divmod_1.
+
+	* mpn/x86/diveby3.asm: Use imul, update comments.
+
+	* demos/qcn.c: New file.
+	* demos/Makefile.am (EXTRA_PROGRAMS): Add it.
+
+	* mpz/tests/t-jac.c: New file.
+	* mpz/tests/Makefile.am (check_PROGRAMS): Add it. Enable ansi2knr.
+
+	* mpz/kronsz.c: New file.
+	* mpz/kronuz.c: New file.
+	* mpz/kronzs.c: New file.
+	* mpz/kronzu.c: New file.
+	* mpz/Makefile.am (libmpz_la_SOURCES): Add them.
+	* Makefile.am (MPZ_OBJECTS): Add them.
+	* gmp-impl.h (JACOBI_*, MPN_STRIP_LOW_ZEROS_NOT_ZERO): New macros.
+	* gmp.h (mpz_*_kronecker_*): New defines and prototypes.
+
+	* mpn/generic/jacbase.c: New file.
+	* mpn/generic/mod_1_rs.c: New file.
+	* configure.in (gmp_mpn_functions): Add them.
+	* gmp.h (mpn_jacobi_base, mpn_mod_1_rshift): New defines and
+	prototypes.
+	* longlong.h (COUNT_TRAILING_ZEROS_TIME): New define.
+	* mpn/tests/ref.c (refmpn_mod_1_rshift): New function.
+	* mpn/tests/try.c: Add mpn_mod_1_rshift.
+	* tune/*: Add measuring for mpn_jacobi_base.
+
+	* acinclude.m4 (GMP_FINISH): Add ifdefs to allow multiple
+	inclusion of config.m4.
+	(GMP_PROG_M4): Put "good" message through to config.log.
+
+	* mpz/powm.c: Use a POWM_THRESHOLD for where redc stops.
+	* tune/*: Add mpz_powm measuring, and tune POWM_THRESHOLD.
+	* gmp-impl.h [TUNE_PROGRAM_BUILD] (POWM_THRESHOLD): Conditional
+	redefinition for use when tuning.
+
+	* mpz/powm_ui.c: Use DIVIDE_BY_ZERO.
+
+	* mpz/iset_str.c: Initialize _mp_size to 0, in case no digits in
+	string; this makes it the same as a separate init and set_str.
+
+2000-05-20  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/asm-defs.m4: Note &,|,^ aren't bitwise in BSD m4 eval().
+	* mpn/x86/k6/sqr_basecase.asm: Use "%" not "&" in m4 eval()s.
+
+	* mpn/x86/x86-defs.m4 (Zdisp): Yet more instruction forms.
+
+2000-05-19  Linus Nordberg  <linus@swox.se>
+
+	* acinclude.m4 (GMP_CHECK_CC_64BIT): Don't use shell variable
+	`ac_compile' for our own compile command string since other
+	Autoconf macros may depend on it.
+
+2000-05-19  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/generic/mul_n.c (mpn_toom3_mul_n, mpn_toom3_sqr_n): Fix
+	carry propagation in final coefficient additions.
+
+2000-05-18  Linus Nordberg  <linus@swox.se>
+
+	* configure.in: Set NM before looking for compiler since
+	GMP_CHECK_CC_64BIT needs it.
+
+	* acinclude.m4 (GMP_CHECK_CC_64BIT): Don't execute on target.
+	(GMP_PROG_CC_FIND): Before checking if the compiler knows how to
+	produce 64-bit code, verify that it works at all.  The background
+	is that /usr/ucb/cc on Solaris 7 successfully compiles in 64-bit
+	mode but fails when doing final link.
+	(GMP_PROG_CC_WORKS): Report to user what's happening.
+
+2000-05-17  Linus Nordberg  <linus@swox.se>
+
+	* config.guess: Use X86CPU for x86 Cygwin.
+
+2000-05-16  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/x86/p6/mmx/divrem_1.asm: New file.
+	* mpn/x86/p6/mmx/mod_1.asm: New file.
+	* mpn/x86/p6/README: Update.
+	* mpn/x86/divrem_1.asm: Update comments.
+	* mpn/x86/mod_1.asm: Ditto.
+
+2000-05-14  Kevin Ryde  <kevin@swox.se>
+
+	* tune/speed.h: Run gcd functions on a set of data.
+
+	* mpn/tests/try.c: New file.
+	* mpn/tests/try.h: New file.
+	* mpn/tests/spinner.c: New file.
+	* mpn/tests/trace.c: New file.
+	* mpn/tests/x86call.asm: New file.
+	* mpn/tests/x86check.c: New file.
+	* mpn/tests/ref.c (refmpn_hamdist): Allow size==0.
+	(refmpn_gcd): New function, and other additions supporting it.
+	* mpn/tests/ref.h: More prototypes.
+	* mpn/tests/Makefile.am: Add try program, use ansi2knr.
+
+	* mpn/x86/k7/mmx/popham.asm: New file.
+	* mpn/x86/k6/mmx/popham.asm: New file.
+	* mpn/x86/k6/sqr_basecase.asm: Unroll the addmul, for approx 1.3x
+	speedup above 15 limbs.
+	* mpn/x86/k7/README: Update.
+	* mpn/x86/k6/README: Update, and add notes on plain K6 and pre-CXT
+	K6-2 problems.
+	* configure.in (k6*-*-*, athlon-*-*): Add popham.
+
+	* mpn/x86/pentium/diveby3.asm: New file.
+	* mpn/x86/pentium/README: Update.
+
+	* gmp.texi (Installing GMP): Add note on bad OpenBSD 2.6 m4.
+	(Reporting Bugs): Ask for config.m4 if asm file related.
+	(I/O of Rationals): New section, add mpq_out_str.
+	(References): Add url for on-line gcc manuals.
+	A few node and menu updates.
+
+	* INSTALL: Better command line argument checking for test progs.
+	Change MP -> GMP.
+
+	* configure.in (WANT_ASSERT, USE_STACK_ALLOC, HAVE_PENTIUM_RDTSC):
+	Put descriptions here, not in acconfig.h.
+	(CALLING_CONVENTIONS_OBJS): New AC_SUBST (for mpn/tests/try).
+	(HAVE_CALLING_CONVENTIONS): New AC_DEFINE.
+	(AC_CHECK_HEADERS): Add sys/time.h.
+	(AC_CHECK_FUNCS): Add getpagesize, setitimer.
+	(KARATSUBA_SQR_THRESHOLD): Strip trailing comments from the
+	#define when passing through to config.m4.
+	* acconfig.h (PACKAGE, VERSION, WANT_ASSERT, USE_STACK_ALLOC,
+	HAVE_PENTIUM_RDTSC): No need for #undefs, autoheader gets them
+	from configure.in.
+
+	* acinclude.m4 (GMP_PROG_M4): Check for broken OpenBSD 2.6 m4
+	eval(), put messages into config.log.
+	* mpn/asm-defs.m4: Add notes and test for OpenBSD 2.6 m4.
+
+	* mpq/out_str.c: New file.
+	* mpq/Makefile.am (libmpq_la_SOURCES): Add it.
+	* Makefile.am (MPQ_OBJECTS): Ditto.
+	* gmp.h (mpq_out_str): New define and prototype.
+
+2000-05-12  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (CONFIG_TOP_SRCDIR): Fix to use $srcdir not
+	$top_srcdir (which doesn't exist).
+	* acinclude.m4 (GMP_C_ANSI2KNR): Fix setting U=_.
+	* gmp-impl.h (mpn_com_n, MPN_LOGOPS_N_INLINE): Fix missing "do"
+	(not currently used, probably no ill effect anyway).
+
+2000-05-11  Torbjorn Granlund  <tege@swox.com>
+
+	* randraw.c (lc): Major overhaul (pending rewrite).
+	(_gmp_rand): Rewrite.
+
+2000-05-08  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/tests/convert.c: Call free via _mp_free_func.
+	* mpf/tests/t-conv.c: Likewise.
+
+	* memory.c: Add code enabled for DEBUG that adds special patterns
+	around allocated blocks.
+
+2000-05-05  Linus Nordberg  <linus@swox.se>
+
+	* gmp.texi (Miscellaneous Float Functions): Correct parameter list
+	for mpf_urandomb().
+
+	* configure.in: Invoke AC_REVISION.
+
+2000-05-05  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi: Use @dircategory and @direntry.
+	(Installing GMP): Clarification for --target, updates on SunOS
+	problems.
+	(Integer Arithmetic): Add mpz_mul_si.
+	(Initializing Rationals): Add mpq_swap.
+	(Assigning Floats): Add mpf_swap.
+	(Low-level Functions): Add mpn_divexact_by3c, and details of what
+	the calculation actually gives.
+	(Low-level Functions): Note extra space needed by mpn_gcdext,
+	clarify the details a bit.
+
+	* compat.c: New file, entry points for upward binary compatibility.
+	(mpn_divexact_by3): Compatibility function.
+	* Makefile.am (libgmp_la_SOURCES): Add compat.c.
+
+	* mpn/tests/ref.c: Rearrange macros for ansi2knr.
+	(div1): Renamed from div to avoid library function.
+	(refmpn_divexact_by3c, refmpn_gcd_1, refmpn_popcount,
+	refmpn_hamdist): New functions.
+	* mpn/tests/ref.h: Add extern "C", add new prototypes.
+
+	* gmp.h (gmp_randinit, etc): Add extern "C".
+	(_mpq_cmp_ui): Fix prototype name from mpq_cmp_ui.
+	(mpn_divexact_by3): Now a macro calling mpn_divexact_by3c.
+	(mpn_divexact_by3c): New prototype and define.
+
+	* mpn/x86/diveby3.asm: Change to mpn_divexact_by3c.
+	* mpn/x86/k6/diveby3.asm: Ditto.
+	* mpn/generic/diveby3.c: Ditto.
+	* mpn/asm-defs.m4: Ditto on the define_mpn.
+	* acconfig.h (HAVE_NATIVE_mpn_divexact_by3c): New define.
+
+	* mpq/swap.c: New file, derived from mpz/swap.c.
+	* mpf/swap.c: Ditto.
+	* mpq/Makefile.am: Add swap.c.
+	* mpf/Makefile.am: Ditto.
+	* Makefile.am: Add two new "swap.lo"s.
+
+	* mpn/x86/k6/mmx/com_n.asm: Fix an addressing bug (fortunately
+	this code hasn't been used anywhere yet).
+
+	* mpn/x86/k7/mmx/divrem_1.asm: New file.
+	* mpn/x86/k7/mmx/mod_1.asm: New file.
+	* mpn/x86/k7/diveby3.asm: New file.
+	* mpn/x86/k7/README: Update.
+
+	* mpn/x86/k7/aorsmul_1.asm: Use new cmovCC, no object code change.
+	* mpn/x86/k7/mul_basecase.asm: Ditto.
+	* mpn/x86/p6/aorsmul_1.asm: Ditto.
+
+	* mpn/x86/x86-defs.m4 (defframe_empty_if_zero): Eval the argument.
+	(cmovCC): New macros, replacing individual cmovCC_reg_reg forms.
+	(Zdisp): Recognise more instructions.
+	(shldl,etc): Use m4_instruction_wrapper().
+	(ASSERT, movl_text_address): New macros.
+
+	* mpn/asm-defs.m4: Add remarks on SunOS /usr/bin/m4 and new
+	OpenBSD m4.
+	(m4_assert_numargs_internal_check): Remove a spurious parameter.
+	(m4_empty_if_zero): Eval the argument.
+	(m4_assert, m4_assert_numargs_range, m4_config_gmp_mparam,
+	m4_instruction_wrapper): New macros.
+
+2000-05-04  Linus Nordberg  <linus@swox.se>
+
+	* gmp.texi (Reporting Bugs): Be explicit about output from running
+	a command.
+
+2000-05-02  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/bz_divrem_n.c (mpn_bz_divrem_n): Handle non-zero return
+	from first mpn_bz_div_3_halves_by_2 call.
+	(mpn_bz_divrem_aux): Likewise.
+
+2000-04-30  Kevin Ryde  <kevin@swox.se>
+
+	* tune/* (GCD_ACCEL_THRESHOLD, GCDEXT_THRESHOLD): Tune these.
+
+	* mpn/generic/gcdext.c (GCDEXT_THRESHOLD): Rename from THRESHOLD,
+	use with >=, adjust default to 17 accordingly.
+	Use new *_SWAP macros.
+
+	* mpn/generic/gcd.c (GCD_ACCEL_THRESHOLD): Rename from
+	ACCEL_THRESHOLD, use with >=, adjust default to 5 accordingly.
+	Use new *_SWAP macros.
+
+	* mpf/get_str.c, mpf/set_str.c, mpf/sub.c, mpz/add.c, mpz/ior.c,
+	mpz/and.c, mpz/sub.c, mpz/xor.c, mpz/ui_pow_ui.c,
+	mpn/generic/mul.c: Use new *_SWAP macros.
+
+	* stack-alloc.h: Add extern "C" around prototypes.
+
+	* gmp-impl.h: (MP_PTR_SWAP, etc): New macros.
+	(_mp_allocate_func, etc): Use _PROTO.
+	[TUNE_PROGRAM_BUILD]: More changes in tune program build part.
+
+2000-04-28  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/pa64/add_n.s: Add `,entry' to export directive.
+	* mpn/pa64/addmul_1.S, mpn/pa64/lshift.s, mpn/pa64/mul_1.S,
+	mpn/pa64/rshift.s, mpn/pa64/sub_n.s, mpn/pa64/submul_1.S,
+	mpn/pa64/umul_ppmm.S: Likewise.
+	* mpn/hppa/hppa1_1/udiv_qrnnd.S: New name for udiv_qrnnd.s.
+	Add PIC support.
+
+2000-04-29  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-impl.h [TUNE_PROGRAM_BUILD] (TOOM3_MUL_THRESHOLD_LIMIT): New
+	define.
+	* mpn/generic/mul_n.c [TUNE_PROGRAM_BUILD] (mpn_mul_n): Use
+	TOOM3_MUL_THRESHOLD_LIMIT, not a hard coded 500.
+
+	* memory.c: Use <stdlib.h> for malloc etc, and use _PROTO.
+	* stack-alloc.c: Don't use C++ reserved word "this".
+	* urandom.h: Put extern "C" around prototypes.
+	* mpz/powm.c: Switch a couple of parameters to "const", which they
+	are, to satisfy g++.
+
+	* randraw.c, stack-alloc.c, mpbsd/mout.c, mpbsd/mtox.c: Add casts to
+	help g++.
+
+	* stack-alloc.c: Provide dual ANSI/K&R function definitions.
+	* mpz/addmul_ui.c,get_d.c,inp_str.c,perfpow.c,powm.c,pprime_p.c,
+	rrandomb.c,set_str.c,ui_pow_ui.c: Ditto.
+	* mpf/integer.c,set_str.c: Ditto.
+	* mpbsd/min.c,xtom.c: Ditto.
+	* mpn/generic/bz_divrem_n.c,dump.c,gcd_1.c,get_str.c,hamdist.c,
+	popcount.c,random.c,random2.c,set_str.c: Ditto.
+
+	* rand.c: Use <stdio.h> for NULL.
+	* mpz/gcd_ui.c,gcdext.c,mul.c,perfpow.c,powm_ui.c,root.c,sqrt.c,
+	sqrtrem.c: Ditto
+	* mpf/sqrt.c,sqrt_ui.c: Ditto.
+	* mpn/generic/perfsqr.c,sqrtrem.c: Ditto.
+
+	* gmp-impl.h (NULL, malloc, realloc, free): Don't define/declare.
+	(extern "C"): Add around function prototypes.
+	(mpn_kara_mul_n, mpn_kara_sqr_n, mpn_toom3_mul_n, mpn_toom3_sqr_n):
+	Add prototypes.
+	[TUNE_PROGRAM_BUILD] (FIB_THRESHOLD): Add necessary redefinitions for
+	use by tune program.
+	* mpn/generic/mul_n.c: Remove mpn_toom3_mul_n prototype.
+
+	* acinclude.m4 (GMP_C_ANSI2KNR): New macro.
+	(GMP_CHECK_ASM_MMX, GMP_CHECK_ASM_SHLDL_CL): Fix to use
+	$gmp_cv_check_asm_text which is what GMP_CHECK_ASM_TEXT sets.
+	* configure.in (GMP_C_ANSI2KNR): Use this instead of AM_C_PROTOTYPES,
+	for reasons described with its definition.
+
+	* demos/Makefile.am (ansi2knr): Use $(top_builddir) nor $(top_srcdir).
+
+	* mpz/fib_ui.c (FIB_THRESHOLD): Rename from FIB_THRES, for consistency.
+	(FIB_THRESHOLD): Conditionalize so gmp-mparam.h can define a value.
+	(mpz_fib_bigcase): Use >= FIB_THRESHOLD, same as main mpz_fib_ui.
+	* tune/tuneup.c,Makefile.am (FIB_THRESHOLD): Tune this.
+
+	* configure.in (*-*-aix* gmp_m4postinc): Fix setting (don't overwrite
+	a value just stored).
+
+2000-04-26  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/sparc32/udiv_fp.asm: Use mpn_udiv_qrnnd macro.
+	* mpn/sparc32/udiv_nfp.asm: Ditto.
+	* mpn/sparc32/v8/supersparc/udiv.asm: Ditto.
+	* mpn/sparc32/umul.asm: Name the function mpn_umul_ppmm.
+	* mpn/sparc32/v8/umul.asm: Ditto.
+	* mpn/powerpc32/umul.asm: Ditto.
+
+	* mpn/x86/syntax.h: Remove file, since now unused.
+
+	* configure.in (x86): Remove -DBROKEN_ALIGN and -DOLD_GAS
+	previously used by .S files.
+	(x86 extra_functions): Add udiv and umul.
+	(GMP_PROG_M4): Use this instead of AC_CHECK_PROG(M4,m4,...)
+	(HAVE_NATIVE_*): Loosen up the regexp to "PROLOGUE.*" so as to
+	accept PROLOGUE_GP on alpha.
+
+	* acconfig.h (HAVE_NATIVE_mpn_umul_ppmm, udiv_qrnnd, invert_limb):
+	New template defines.
+	* mpn/asm-defs.m4 (mpn_umul_ppmm, mpn_udiv_qrnnd): New define_mpn()s.
+	* longlong.h (umul_ppmm, udiv_qrnnd): Use a library version if
+	it's available and an asm macro isn't.
+	* gmp-impl.h (invert_limb): Ditto.
+
+	* gmp-impl.h (ASSERT_NOREALLOC): Not a good idea, remove it.
+
+	* acinclude.m4 (GMP_PROG_M4): New macro.
+
+2000-04-25  Linus Nordberg  <linus@swox.se>
+
+	* gmp.texi (Random State Initialization): Correct arguments to
+	`gmp_randinit'.
+
+	* acinclude.m4 (GMP_VERSION): Change `eval' --> `m4_eval'.  Fix
+	from Kevin.
+	* aclocal.m4: Regenerate.
+
+2000-04-25  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/x86/aors_n.asm: Remove parentheses around an immediate that
+	Solaris "as" doesn't like, change by Torbjorn.
+
+2000-04-24  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (AC_CHECK_FUNCS): Add strtoul.
+
+	* mpn/generic/mul_n.c [TUNE_PROGRAM_BUILD] (mpn_mul_n): Bigger
+	array for karatsuba temporary space for tune program build.
+	(mpn_toom3_sqr_n) Remove an unused variable.
+
+	* demos/Makefile.am (AUTOMAKE_OPTIONS): Add ansi2knr.
+	Add "allprogs:" pseudo-target.
+	* demos/factorize.c, demos/isprime.c: Switch to ANSI functions,
+	rely on ansi2knr.
+
+	* gmp.texi (Getting the Latest Version of GMP): Add reference to
+	ftp.gnu.org mirrors list.
+	* INSTALL: Add arg count check to example programs.
+
+	* mpn/x86/*/*.asm: Convert to FORTRAN ... or rather to
+	FORTRAN-style "C" commenting to support Solaris "as".
+	* mpn/x86/x86-defs.m4: Ditto, and add another Zdisp insn.
+	* mpn/asm-defs.m4 (C): Update comments.
+	* mpn/x86/README.family: Add a note on commenting, remove
+	description of .S files.
+
+	* mpn/sparc64/addmul_1.asm, mul_1.asm, submul_1.asm: Use
+	include_mpn().
+
+2000-04-23  Torbjorn Granlund  <tege@swox.com>
+
+	* config.sub: Merge with FSF version of April 23.
+
+	* mpn/powerpc32: Use dnl/C instead of `#' for comments.
+
+	* config.guess: Get "model" limit between pentium 2 and pentium3 right.
+	Get rid of code determining `_' prefix; use double labels instead.
+	* config.guess: Partially merge with FSF version of April 22.
+	(Don't bring over NetBSD changes for now.)
+
+2000-04-23  Kevin Ryde  <kevin@swox.se>
+
+	* tune/Makefile.am, tune/README, tune/common.c, tune/rdtsc.asm,
+	tune/speed.c, tune/speed.h, tune/time.c, tune/tuneup.c: New files.
+	* tune/Makefile.in: New file, generated from Makefile.am.
+
+	* gmp-impl.h (ASSERT_NOREALLOC,TMP_ALLOC_LIMBS): New macros.
+	[TUNE_PROGRAM_BUILD] Further mods for tune program builds.
+
+	* mpz/Makefile.am: Add -DOPERATION_$* for new mul_siui.c.
+	Add rules to build mul_si and mul_ui from a common mul_siui.c.
+	* mpz/mul_siui.c: New file, derived from and replacing mul_ui.c.
+	* gmp.h (mpz_mul_si): New prototype and define.
+
+	* mpn/tests/*.c [__i386__] (CLOCK): Don't use floating point in
+	CLOCK because cpp can't handle floats in #if's (TIMES is derived
+	from CLOCK by default).
+
+	* mpn/asm-defs.m4 (include_mpn): New macro.
+	(m4_assert_numargs) Changes to implementation.
+
+	* mpf/Makefile.am: Add -DOPERATION_$* for new integer.c.
+	Remove explicit rules for floor.o etc.
+	* mpf/integer.c: Use OPERATION_$* for floor/ceil/trunc.
+
+	* mpn/Makefile.am: Put "tests" in SUBDIRS.
+	* mpn/tests/Makefile.am: New file providing rules to build test
+	programs, nothing done in a "make all" or "make check" though.
+	* mpn/tests/README: New file.
+
+	* acconfig.h (HAVE_PENTIUM_RDTSC): New define.
+
+	* configure.in (x86): Rearrange target cases.
+	Add mulfunc aors_n and aorsmul_1 for x86 and pentium (now all x86s).
+	Remove asm-syntax.h generation not needed.
+	Remove now unused family=x86.
+	(sparc) Remove unused family=sparc.
+	(HAVE_PENTIUM_RDTSC) New AC_DEFINE and AM_CONDITIONAL.
+	(AM_C_PROTOTYPES) New test, supporting ansi2knr.
+	(AC_CHECK_HEADERS) Add getopt.h, unistd.h and sys/sysctl.h for
+	tune progs.
+	(AC_CHECK_FUNCS) Add getopt_long, sysconf and sysctlbyname for
+	tune progs.
+	(config.m4 CONFIG_TOP_SRCDIR) Renamed from CONFIG_SRCDIR.
+	(config.m4 asm-defs.m4) Use CONFIG_TOP_SRCDIR and include().
+	(gmp_m4postinc) Use include_mpn().
+	(gmp_links) Omit asm-defs.m4/asm.m4 and gmp_m4postinc's.
+	(MULFUNC_PROLOGUE) Fix regexps so all functions get AC_DEFINE'd.
+	(PROLOGUE) Ditto (native copyi and copyd were unused in gmp 3).
+	(KARATSUBA_SQR_THRESHOLD) Copy from gmp-mparam.h into config.m4.
+	(AC_OUTPUT) Add tune/Makefile, mpn/tests/Makefile.
+
+	* Makefile.am (AUTOMAKE_OPTIONS): Add ansi2knr.
+	(SUBDIRS): Add tune, reorder directories.
+	(MPZ_OBJECTS): Add mpz/mul_si.lo.
+	(libmp_la_SOURCES): Use this for top-level objects, not .lo's.
+	* ansi2knr.c, ansi2knr.1: New files, provided by automake.
+
+	* mpn/x86/aors_n.asm: Convert add_n.S and sub_n.S to a
+	multi-function aors_n.asm, no object code change.
+	* mpn/x86/pentium/aors_n.asm: Ditto.
+	* mpn/x86/aorsmul_1.asm: Ditto for addmul/submul.
+	* mpn/x86/pentium/aorsmul_1.asm: Ditto.
+
+	* mpn/x86/lshift.asm, mpn/x86/mul_1.asm, mpn/x86/mul_basecase.asm,
+	mpn/x86/rshift.asm: Convert from .S, no object code change.
+	* mpn/x86/pentium/lshift.asm, mpn/x86/pentium/mul_1.asm,
+	mpn/x86/pentium/mul_basecase.asm, mpn/x86/pentium/rshift.asm: Ditto.
+
+	* gmp.texi (Reporting Bugs): Itemize the list of things to include.
+	(Miscellaneous Float Functions): Correct typo in mpf_ceil etc
+	argument types.
+	Change @ifinfo -> @ifnottex for benefit of makeinfo --html.
+	Remove unnecessary @iftex's around @tex.
+
+2000-04-22  Torbjorn Granlund  <tege@swox.com>
+
+	* config.guess: Generalize x86 cpu determination code.
+	Now works on Solaris.
+
+	* mpz/nextprime.c: Rewrite still disabled code.
+
+	* configure.in: Specifically match freebsd[3-9].
+
+2000-04-21  Torbjorn Granlund  <tege@swox.com>
+
+	* rand.c: Call mpz_clear for otherwise leaking mpz_t.
+
+	* mpz/pprime_p.c (mpz_probab_prime_p): Merge handling of negative
+	n into code for handling small positive n.  Merge variables m and n.
+	After dividing, simply call mpz_millerrabin.
+	(isprime): Local variables now use attribute `long'.
+	(mpz_millerrabin): New static function, based on code from
+	mpz_probab_prime_p.
+	(millerrabin): Now simple workhorse for mpz_millerrabin.
+
+2000-04-19  Torbjorn Granlund  <tege@swox.com>
+
+	* gmp-impl.h: Fix parenthesis error in test for __APPLE_CC__.
+
+2000-04-18  Linus Nordberg  <linus@swox.se>
+
+	* NEWS: Add info about shared libraries.  Remove reference to
+	gmp_randinit_lc.
+
+2000-04-17  Torbjorn Granlund  <tege@swox.com>
+
+	* Version 3.0 released.
+
+	* mpn/arm/add_n.S: New version from Robert Harley.
+	* mpn/arm/addmul_1.S: Likewise.
+	* mpn/arm/mul_1.S: Likewise.
+	* mpn/arm/sub_n.S: Likewise.
+
+	* gmp.h (__GNU_MP_VERSION_PATCHLEVEL): Now 0.
+
+2000-04-17  Linus Nordberg  <linus@swox.se>
+
+	* configure.in (hppa2.0*-*-*): Pass `+O3' to cc/c89 in 64-bit mode
+	to avoid compiler bug.
+	(ns32k*-*-*): Fix typo in path.  Change by Kevin.
+	(alpha*-*-osf*): New case.  Pass assembly flags for architecture
+	to gcc.
+	(alpha*-*-*): Don't bother searching for cc.
+	* configure: Regenerate.
+
+	* Makefile.am (EXTRA_DIST): Add `macos', `.gdbinit'.
+	* Makefile.in: Regenerate.
+	* mpn/Makefile.am (EXTRA_DIST): Add `m88k', `lisp'.
+	* mpn/Makefile.in: Regenerate.
+
+2000-04-16  Kevin Ryde  <kevin@swox.se>
+
+	* README: Updates, and don't duplicate the example in INSTALL.
+	* INSTALL: Minor updates.
+	* gmp.texi (Installing MP): Minor edits, restore CC/CFLAGS description.
+
+2000-04-16  Linus Nordberg  <linus@swox.se>
+
+	* configure.in (*-*-cygwin*): Select BSD_SYNTAX to avoid
+	.type/.size in PROLOGUE for ELF_SYNTAX.  Override ALIGN definition
+	from x86/syntax.h.
+	(gmp_xoptcflags_${CC}): New set of variables, indicating
+	``exclusive optional cflags''.
+	(most sparcs): Use gmp_xoptcflags instead of gmp_optcflags to
+	ensure that we pass CPU type to older gcc.
+	(CFLAGS): CFLAGS on the command line was spoiled.
+	* configure: Regenerate.
+
+2000-04-16  Linus Nordberg  <linus@swox.se>
+
+	* configure.in: Invoke AC_PROG_LIBTOOL directly.
+
+	* acinclude.m4 (GMP_PROG_CC_FIND): Quote source variable when
+	setting CC64 and CFLAGS64.
+	(GMP_PROG_CC_SELECT): Cache result.
+	(GMP_PROG_LIBTOOL): Remove.
+
+	* aclocal.m4: Regenerate.
+	* configure: Regenerate.
+
+2000-04-16  Linus Nordberg  <linus@swox.se>
+
+	* tests/rand/t-rand.c (main): Add non-ANSI function declaration.
+	Don't use `const'.
+
+2000-04-16  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/dump.c: Suppress output of leading zeros.
+
+	* mpz/inp_str.c: Fix memory leakage.
+
+	* mpz/tests/reuse.c (dss_func_division): Add a final 1.
+
+	* longlong.h (alpha count_leading_zeros): Wrap in __MPN.
+	* mpn/alpha/cntlz.asm: Use __gmpn prefix (by means of __MPN).
+
+	* longlong.h (__umul_ppmm, __udiv_qrnnd): Wrap in __MPN.
+	* mpn/alpha/udiv_qrnnd.S: Use __gmpn prefix.
+	* mpn/hppa/udiv_qrnnd.s: Likewise.
+	* mpn/hppa/hppa1_1/udiv_qrnnd.s: Likewise.
+	* mpn/pa64/udiv_qrnnd.c: Likewise (by means of __MPN).
+	* mpn/pa64/umul_ppmm.S: Likewise.
+	* mpn/sparc32/udiv_fp.asm: Likewise (by means of MPN).
+	* mpn/sparc32/udiv_nfp.asm: Likewise (by means of MPN).
+	* mpn/sparc32/v8/supersparc/udiv.asm: Likewise (by means of MPN).
+
+	* mpn/generic/tdiv_qr.c: Work around gcc 2.7.2.3 i386 register handling
+	bug.
+
+	* mpn/generic/tdiv_qr.c: Use udiv_qrnnd instead of mpn_divrem_1
+	when computing appropriate quotient; mpn_divrem_1 writes too
+	many quotient limbs.
+
+	* mpn/asm-defs.m4: invert_normalized_limb => invert_limb.
+	* mpn/alpha/invert_limb.asm: mpn_invert_normalized_limb =>
+	mpn_invert_limb.
+	* gmp.h: Likewise.
+	* gmp-impl.h (alpha specific): invert_normalized_limb => invert_limb;
+	wrap with __MPN.
+	* longlong.h (alpha udiv_qrnnd): Likewise.
+
+2000-04-16  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.h (mp_set_memory_functions,mp_bits_per_limb,gmp_errno): Add
+	#defines so the library symbols are __gmp_*.
+	* errno.c: Include gmp.h.
+	* gmp-impl.h (_mp_allocate_func,etc): Add #defines to __gmp_*.
+	(__clz_tab): New #define to __MPN(clz_tab).
+	* stack-alloc.c (__gmp_allocate_func,etc): Change from _mp_*.
+
+	* Makefile.am (libmp_la_DEPENDENCIES): Add some mpz files needed
+	for new mpz_powm (pow in libmp).
+	(EXTRA_DIST): Add projects directory.
+
+	* mpn/*: Change __mpn to __gmpn.
+	* gmp.h (__MPN): Ditto.
+	* stack_alloc.c,stack-alloc.h: Change __tmp to __gmp_tmp.
+
+	* mpn/generic/sb_divrem_mn.c (mpn_sb_divrem_mn): Avoid gcc 2.7.2.3
+	i386 register handling bug (same as previously in mpn_divrem_classic).
+
+	* mpn/generic/divrem.c: Now contains mpn_divrem, which is not an
+	internal function, so remove warning comment.
+
+	* gmp.texi (Compatibility with Version 2.0.x): Source level only.
+
+2000-04-16  Linus Nordberg  <linus@swox.se>
+
+	* configure.in (hppa1.0*): Prefer c89 to cc.
+	* configure: Regenerate.
+
+2000-04-15  Linus Nordberg  <linus@swox.se>
+
+	* configure.in: If `mpn_path' is set by user on configure command
+	line, use that as path.
+	* configure: Regenerate.
+
+2000-04-15  Linus Nordberg  <linus@swox.se>
+
+	* configure.in (hppa2.0*): Use path "hppa/hppa1_1 hppa" if no
+	64-bit compiler was found.
+	* configure: Regenerate.
+
+2000-04-15  Linus Nordberg  <linus@swox.se>
+
+	* configure.in: Honor `CC' and `CFLAGS' set by user on configure
+	command line.
+	* acinclude.m4: (GMP_PROG_CC_SELECT): Set CFLAGS if not set already.
+	* aclocal.m4: Regenerate.
+	* configure: Regenerate.
+
+2000-04-15  Linus Nordberg  <linus@swox.se>
+
+	* acinclude.m4 (GMP_PROG_CC_FIND): Remove debug output.  Remove
+	commented out code.
+	* aclocal.m4: Regenerate.
+	* configure: Regenerate.
+
+	* configure.in: Make all `-mcpu' options to gcc optional.
+	* configure: Regenerate.
+
+	* tests/rand/Makefile.am: Don't do anything for target 'all'.
+	* tests/rand/Makefile.in: Regenerate.
+
+2000-04-15  Kevin Ryde  <kevin@swox.se>
+
+	* README: Small updates.
+	* NEWS: Add some things about 3.0.
+
+	* mpz/Makefile.am (EXTRA_DIST): Remove dmincl.c.
+
+	* Makefile.am: Use -version-info on libraries, not -release.
+
+	* mpz/tdiv_qr.c: Add mdiv function header #ifdef BERKELEY_MP.
+	* mpbsd/Makefile.am: Use mpz/tdiv_qr.c, not mdiv.c.
+	* Makefile.am (MPBSD_OBJECTS): Change mdiv.lo to tdiv_qr.lo.
+	(libmp_la_DEPENDENCIES): Add mp_clz_tab.lo.
+	* mpbsd/mdiv.c: Remove file.
+
+	* config/mt-linux,mt-m68k,mt-m88110,mt-ppc,mt-ppc64-aix,mt-pwr,
+	mt-sprc8-gcc,mt-sprc9-gcc,mt-supspc-gcc,mt-vax,mt-x86,
+	mpn/config/mt-pa2hpux,mt-sprc9,t-oldgas,t-ppc-aix,t-pwr-aix:
+	Remove configure fragments not used since change to autoconf.
+
+	* mpn/generic/bz_divrem_n.c,sb_divrem_mn.c: Add comment that
+	internal functions are changeable and shouldn't be used directly.
+
+2000-04-15  Linus Nordberg  <linus@swox.se>
+
+	* configure.in: Remove debug output.
+	* configure: Regenerate.
+
+2000-04-15  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/tdiv_qr.c: Don't use alloca directly.
+
+	* mpz/tdiv_qr.c: Fix typo.
+	* mpz/tdiv_r.c: Fix typo.
+	* mpz/tdiv_q.c: Fix typo.
+
+	* configure.in: Disable -march=pentiumpro due to apparent compiler
+	problems.
+
+	* mpz/powm.c: Replace with new code from Paul Zimmermann.
+
+	* mpz/tdiv_q.c: Remove debug code.
+
+	* mpn/generic/divrem.c: Remove C++ style `//' commented-out code.
+	* mpn/generic/sb_divrem_mn.c: Likewise.
+
+2000-04-14  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/cdiv_q.c: Change temp allocation for new requirements of
+	mpz_tdiv_qr.
+	* mpz/fdiv_q.c: Likewise.
+
+	* mpn/sparc64/gmp-mparam.h: Set up parameters for TOOM3.
+
+	* mpz/dmincl.c: Delete file.
+	* mpz/tdiv_qr.c: Rewrite using mpn_tdiv_qr.
+	* mpz/tdiv_r.c: Likewise.
+	* mpz/tdiv_q.c: Likewise.
+
+	* mpn/generic/tdiv_qr.c: New file.
+	* mpn/generic/bz_divrem_n.c: New file.
+	* mpn/generic/sb_divrem_mn.c: New file.
+
+	* gmp-impl.h (MPZ_REALLOC): New macro.
+	(mpn_sb_divrem_mn): Declare.
+	(mpn_bz_divrem_n): Declare.
+	(mpn_tdiv_qr): Declare.
+
+	* configure.in (gmp_mpn_functions): Delete divrem_newt and divrem_1n;
+	add tdiv_qr, bz_divrem_n, and sb_divrem_mn.
+	* mpn/generic/divrem_newt.c: Delete file.
+	* mpn/generic/divrem_1n.c: Delete file.
+
+	* gmp.h (mpn_divrem_newton): Remove declaration.
+	(mpn_divrem_classic): Remove declaration.
+
+	* gmp.h (mpn_divrem): Remove function definition.
+	* mpn/generic/divrem.c: Replace mpn_divrem_classic with a
+	mpn_divrem wrapper.
+
+2000-04-14  Kevin Ryde  <kevin@swox.se>
+
+	* mpf/dump.c, mpz/dump.c, mpn/generic/dump.c,
+	mpn/generic/divrem.c, mpn/generic/divrem_1n.c,
+	mpn/generic/divrem_2.c, mpn/generic/divrem_newt.c,
+	mpn/generic/mul.c, mpn/generic/mul_basecase.c,
+	mpn/generic/mul_n.c, mpn/generic/sqr_basecase.c,
+	mpn/generic/udiv_w_sdiv.c: Add comment that internal functions are
+	changeable and shouldn't be used directly.
+
+	* mpq/div.c: Use DIVIDE_BY_ZERO (previously didn't get an
+	exception on zero divisor).
+
+	* mpf/tests/t-get_d.c, mpz/tests/reuse.c: Add K&R function
+	definitions.
+	* mpz/tests/t-2exp.c: Don't use ANSI-ism 2ul.
+
+	* gmp.texi (Installing MP): Build problem notes for GSYM_PREFIX
+	and ranlib on native SunOS.
+	Particular systems notes about AIX and HPPA shared libraries
+	disabled.
+	(MP Basics): Add that undocumented things shouldn't be used.
+	(Introduction to MP): Add to CPUs listed.
+
+	* acinclude.m4 (GMP_CHECK_ASM_UNDERSCORE): Don't depend on C
+	having "void".
+
+2000-04-13  Linus Nordberg  <linus@swox.se>
+
+	* mpn/pa64/udiv_qrnnd.c (__udiv_qrnnd64): Add K&R function
+	definition.
+
+	* configure.in: Disable shared libraries for hppa*.
+	(mips-sgi-irix6.*): Fix flags for 64-bit gcc.
+	(hppa2.0*-*-*): Prefer c89 to cc.
+	* configure: Regenerate.
+
+	* gmp.h (gmp_randalg_t): Remove comma after last element.
+
+	* tests/rand/t-rand.c: Add copyright notice.
+
+2000-04-13  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/generic/mul_n.c, mpn/generic/gcdext.c, mpz/nextprime.c,
+	mpz/remove.c, mpz/root.c: Add K&R function definitions.
+	* mpz/rrandomb.c: Fix typo in K&R part.
+	* stack-alloc.c: Add K&R style function pointer declarations.
+
+	* mpz/root.c: Use SQRT_OF_NEGATIVE on even roots of negatives.
+	Use DIVIDE_BY_ZERO on a "zero'th" root.
+
+	* configure: Regenerate with autoconf backpatched to fix --srcdir
+	absolute path wildcards that bash doesn't like, change by Linus.
+
+	* gmp.texi (Integer Arithmetic): Document mpz_nextprime.
+	(Miscellaneous Integer Functions): Fix mpz_fits_* formatting.
+	(Installing MP): Comment-out CC and CFLAGS description.
+
+2000-04-13  Linus Nordberg  <linus@swox.se>
+
+	* rand.c (gmp_randinit): Don't combine va_alist with ordinary
+	arguments for non STDC.
+
+2000-04-13  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/nextprime.c: Use proper names of new random types and functions.
+
+	* mpz/rrandomb.c: New file.
+	* mpz/Makefile.am: List it.
+	* mpz/Makefile.in: Regenerate.
+	* Makefile.am: Here too.
+	* Makefile.in: Regenerate.
+	* gmp.h: Declare mpz_rrandomb.
+
+2000-04-12  Linus Nordberg  <linus@swox.se>
+
+	* Makefile.am, demos/Makefile.am, mpbsd/Makefile.am,
+	mpbsd/tests/Makefile.am, mpf/Makefile.am, mpf/tests/Makefile.am,
+	mpn/Makefile.am, mpq/Makefile.am, mpq/tests/Makefile.am,
+	mpz/Makefile.am, mpz/tests/Makefile.am, tests/Makefile.am,
+	tests/rand/Makefile.am (AUTOMAKE_OPTIONS): Add 'no-dependencies'.
+
+	* Makefile.in, demos/Makefile.in, mpbsd/Makefile.in,
+	mpbsd/tests/Makefile.in, mpf/Makefile.in, mpf/tests/Makefile.in,
+	mpn/Makefile.in, mpq/Makefile.in, mpq/tests/Makefile.in,
+	mpz/Makefile.in, mpz/tests/Makefile.in, tests/Makefile.in,
+	tests/rand/Makefile.in: Regenerate.
+
+2000-04-12  Linus Nordberg  <linus@swox.se>
+
+	* randlc.c (gmp_randinit_lc): Disable function.
+	* gmp.texi (Random State Initialization): Remove gmp_randinit_lc.
+
+	* acinclude.m4 (GMP_CHECK_CC_64BIT): Compiling an empty main
+	successfully with `-n32' will have to suffice on irix6.
+	* aclocal.m4: Regenerate.
+
+	* configure.in (sparc): Don't pass -D_LONG_LONG_LIMB to compiler.
+	(mips-sgi-irix6.*): Use compiler option `-n32' rather than `-64'
+	for 64-bit `cc'.  Add options for gcc.
+	* configure: Regenerate.
+
+	* mpf/urandomb.c (mpf_urandomb): Add third parameter 'nbits'.  If
+	'nbits' doesn't make even limbs, shift up result before
+	normalizing.
+
+	* gmp.h (mpf_urandomb): Add parameter to prototype.
+
+	* mpf/urandom.c: Rename file to ...
+	* mpf/urandomb.c: ... this.
+	* Makefile.am (MPF_OBJECTS): Change urandom.lo --> urandomb.lo.
+	* Makefile.in: Regenerate.
+	* mpf/Makefile.am (libmpf_la_SOURCES): Change urandom.c --> urandomb.c.
+	* mpf/Makefile.in: Regenerate.
+
+	* config.in: Regenerate for HAVE_DECL_OPTARG.
+
+	* randraw.c (_gmp_rand): Fix bug with _LONG_LONG_LIMB.
+	(lc): Change return type.
+	Use one temporary storage instead of two.
+	Handle seed of size 0.
+	Avoid modulus operation in some cases.
+	Abort if M is not a power of 2.
+	Fix bug with 64-bit limbs.
+	Fix bug with small seed, small A and large M.
+
+	* tests/rand/gen.c (main): Include gmp.h.  Remove macros MIN, MAX.  Add
+	option '-q'.  Don't demand argument N.  Change parameters in call
+	to mpf_urandomb.
+
+	* tests/rand/t-rand.c: New file for testing random number generation.
+
+	* tests/rand/Makefile.am: Run t-rand for 'make check'.
+	(test, bigtest): Rename to manual-test, manual-bigtest.
+	* tests/rand/Makefile.in: Regenerate.
+
+2000-04-12  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-impl.h: Include config.h before TMP_ALLOC, so
+	--disable-alloca works.
+
+	* mpbsd/Makefile.am: Don't recompile top-level sources here.
+	* Makefile.am (libmp_la_DEPENDENCIES): Put objects here instead,
+	add errno.lo and stack-alloc.lo.
+
+	* mpn/asm-defs.m4: Add a test and message for the unsuitable SunOS m4.
+	* gmp.texi (Installing MP): Update note on SunOS m4 failure.
+
+	* acconfig.h: Add copyright notice using @TOP@.
+
+	* stack-alloc.c: Use _mp_allocate_func, not malloc.
+	* gmp.texi (Installing MP): Note this under --disable-alloca.
+
+	* gmp.texi (Comparison Functions): mpz_cmp_abs => mpz_cmpabs.
+	(Integer Arithmetic): mpz_prime_p not yet implemented, comment out.
+	(Float Arithmetic): mpf_pow_ui now implemented, uncomment-out.
+	(Miscellaneous Float Functions): Add mpf_ceil, mpf_floor, mpf_trunc.
+	(Low-level Functions): Add mpn_random2, with mpn_random.
+
+	* mpn/m68k/mc68020/udiv.S: Rename from udiv.s.
+	* mpn/m68k/mc68020/umul.S: Ditto.
+
+	* mpn/alpha/umul.asm: Rename from umul.s, remove .file and
+	compiler identifiers.
+
+	* mpn/powerpc32/syntax.h: Removed, no longer used.
+
+	* mpn/a29k/udiv.s: Remove .file and compiler identifiers.
+	* mpn/a29k/umul.s: Ditto.
+
+	* mpn/tests/ref.c: Use WANT_ASSERT.
+	* mpn/tests/ref.h: Use _PROTO.
+
+	* mpbsd/configure.in: Removed, no longer required.
+
+	* mpf/div.c: Use DIVIDE_BY_ZERO.
+	* mpf/div_ui.c: Ditto.
+	* mpf/ui_div.c: Ditto.
+	* mpq/inv.c: Ditto.
+	* mpf/sqrt.c: Use SQRT_OF_NEGATIVE.
+	* mpz/sqrt.c: Ditto.
+	* mpz/sqrtrem.c: Ditto.
+
+	* gmp-impl.h (GMP_ERROR,SQRT_OF_NEGATIVE): New macros.
+	(DIVIDE_BY_ZERO): Use GMP_ERROR.
+	(__mp_bases): #define to __MPN(mp_bases).
+
+2000-04-11  Linus Nordberg  <linus@swox.se>
+
+	* tests/rand/stat.c (main): Initialize `l1runs' at declaration.
+
+2000-04-11  Kevin Ryde  <kevin@swox.se>
+
+	* mpz/fib_ui.c: Add K&R function definitions.
+
+	* mpbsd/tests/Makefile.am (TESTS): Add a dummy test to avoid a
+	shell problem with an empty "for tst in $(TESTS) ; ...".
+	* mpbsd/tests/dummy.c: New file.
+
+2000-04-10  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/bin_uiui.c: Delete several unused variables.
+	Add copyright notice.
+	* mpz/bin_ui.c: Add copyright notice.
+
+	* longlong.h: Declare __count_leading_zeros for alpha.
+
+2000-04-10  Linus Nordberg  <linus@swox.se>
+
+	* rand.c (gmp_randinit): Change parameter list to (rstate, alg, ...).
+	* gmp.h: Change prototype accordingly.
+	* mpz/pprime_p.c (millerrabin): Change call accordingly.
+
+	* configure.in: Check for `optarg'.
+	* configure: Regenerate.
+
+	* mpn/Makefile.am: Remove incorrect comment.
+	* mpn/Makefile.in: Regenerate.
+
+	* gmp.h: Rename most of the random number functions, structs and some
+	of the struct members.
+	* rand.c (gmp_randinit): Likewise.
+	* randclr.c (gmp_randclear): Likewise.
+	* randlc.c (gmp_randinit_lc): Likewise.
+	* randlc2x.c (gmp_randinit_lc_2exp): Likewise.
+	* randraw.c (lc): Likewise.
+	(_gmp_rand_getraw): Likewise.
+	* randsd.c (gmp_randseed): Likewise.
+	* randsdui.c (gmp_randseed_ui): Likewise.
+	* gmp.texi: Likewise.
+
+	* gmp.texi: Use three hyphens for a dash.
+	(Low-level Functions): Remove documentation for gmp_rand_getraw.
+	(Random Number Functions): Add info on where to find documentation
+	on the random number functions.
+
+	* tests/rand/Makefile.am (test, bigtest): Quote argument to grep.
+	* tests/rand/Makefile.in: Regenerate.
+
+	* tests/rand/gen.c: Declare optarg, optind, opterr if not already
+	declared.
+	(main): Use new names for the random stuff.
+	(main): Don't use strtoul() if we don't have it.  Use strtol()
+	instead, if we have it.  Otherwise, use atoi().
+	(main): Use srandom/srandomdev for __FreeBSD__ only.
+	(main): Use new parameter order to gmp_randinit().
+
+	* tests/rand/stat.c: Declare optarg, optind, opterr if not already
+	declared.
+
+2000-04-10  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/pprime_p.c: Pass 0L for mpz_scan1.  mpz_mmod => mpz_mod.
+	(millerrabin): Use new random interface.
+	(millerrabin): ... and don't forget to call gmp_randclear.
+
+	* mpz/nextprime.c: New file.
+	* gmp.h: Declare mpz_nextprime.
+	* mpz/Makefile.am: List nextprime.c.
+	* mpz/Makefile.in: Regenerate.
+	* Makefile.am: List mpz/nextprime.lo.
+	* Makefile.in: Regenerate.
+
+2000-04-10  Kevin Ryde  <kevin@swox.se>
+
+	* move-if-change, mpz/tests/move-if-change, mpq/tests/move-if-change,
+	mpf/tests/move-if-change: Remove, no longer used.
+
+	* Makefile.am (SUBDIRS): Add tests, demos, mpbsd.
+	(libmp.la): New target, conditional on WANT_MPBSD.
+	(libgmp_la_LIBADD): Add -lm.
+	(AUTOMAKE_OPTIONS): Add check-news.
+	(include_HEADERS): Setup to install gmp.h and possibly mp.h.
+	(DISTCLEANFILES): Add generated files.
+	(check): Remove explicit target (now uses check-recursive).
+
+	* configure.in: Use AM_CONFIG_HEADER.
+	Add --enable-mpbsd setting automake conditional WANT_MPBSD.
+	Output demos/Makefile, mpbsd/Makefile and mpbsd/tests/Makefile.
+
+	* mpz/Makefile.am: Add SUBDIRS=tests, shorten INCLUDES since now
+	using AM_CONFIG_HEADER.
+	* mpq/Makefile.am: Ditto.
+	* mpf/Makefile.am: Ditto, and add DISTCLEANFILES.
+	* mpn/Makefile.am: Shorten INCLUDES, amend some comments.
+	* mpz/tests/Makefile.am: Use TESTS and $(top_builddir).
+	* mpf/tests/Makefile.am: Ditto.
+	* mpq/tests/Makefile.am: Ditto.
+	* demos/Makefile.am: New file.
+
+	* mpbsd/Makefile.am: New file, derived from old mpbsd/Makefile.in.
+	* mpbsd/Makefile.in: Now generated from Makefile.am.
+	* mpbsd/realloc.c: Removed, use mpz/realloc.c instead.
+	* mpbsd/tests/Makefile.am: New file.
+	* mpbsd/tests/Makefile.in: New file, generated from Makefile.am.
+	* mpbsd/tests/allfuns.c: New file.
+
+	* gmp.texi (Top): Use @ifnottex, to help makeinfo --html.
+	(Installing MP): Describe --enable-mpbsd and demo programs.
+
+	* tests/rand/statlib.c: mpz_cmp_abs => mpz_cmpabs.
+
+	* tests/rand/Makefile.am (LDADD): Don't need -lm (now in libgmp.la).
+	(EXTRA_PROGRAMS): Not noinst_PROGRAMS.
+	(INCLUDES): Shorten to -I$(top_srcdir) now using AM_CONFIG_HEADER.
+
+2000-04-09  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/urandomm.c: Get type of count right.
+	Simplify computation of nbits.
+
+2000-04-08  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/urandomb.c: Fix reallocation condition.
+	Simplify size computation.
+
+2000-04-08  Linus Nordberg  <linus@swox.se>
+
+	* acinclude.m4 (GMP_CHECK_CC_64BIT): Add special handling for
+	HPUX.
+	(GMP_CHECK_ASM_W32): Ditto.
+	* aclocal.m4: Regenerate.
+
+	* mpn/Makefile.am: Use $(CCAS) for assembling.
+	(.asm.obj): Add rule.
+	* mpn/Makefile.in: Regenerate.
+
+	* gmp.texi (Miscellaneous Integer Functions): Fix typos.
+
+	* configure.in: Never pass `-h' to grep.
+	(mips-sgi-irix6.[2-9]*): Try to find 64-bit compiler.
+	(hppa1.0*-*-*): New flag for cc.
+	(hppa2.0*-*-*): Try to find 64-bit compiler.  Chose path, set
+	CCAS.
+	* configure: Regenerate.
+
+2000-04-08  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/bin_ui.c: Don't depend on ANSI C features.
+	* mpz/bin_uiui.c: Likewise.
+
+	* Makefile.am (MPZ_OBJECTS): mpz/cmp_abs* => mpz/cmpabs*.
+	(MPQ_OBJECTS): Add mpq/set_d.lo.
+	(MPZ_OBJECTS): Add mpz/fits*.lo.
+	* Makefile.in: Regenerate.
+
+	* mpz/cmpabs.c: New name for mpz/cmp_abs.c.
+	* mpz/cmpabs_ui.c: New name for mpz/cmp_abs_ui.c.
+	* mpz/Makefile.am: Corresponding changes.
+	* mpz/Makefile.in: Regenerate.
+	* gmp.h: mpz_cmp_abs* => mpz_cmpabs*.
+
+	* mpz/addmul_ui.c (mpn_neg1): Don't depend on ANSI C features.
+
+	* mpz/invert.c: Use TMP_MARK since we invoke MPZ_TMP_INIT.
+
+	* gmp.h (mpq_set_d): Declare correctly.
+	(mpz_root): Use _PROTO.
+	(mpz_remove): Use _PROTO.
+	(mpf_pow_iu): Use _PROTO.
+
+	* mpn/asm-defs.m4 (MPN_PREFIX): Revert previous change.
+	* gmp.h (__MPN): Revert previous change.
+
+	* mpz/perfpow.c: De-ANSI-fy.  Add copyright notice.
+
+	* mpz/set_d.c: Misc cleanups.
+
+	* mpq/set_d: New file.
+	* gmp.h: Declare mpq_set_d.
+	* mpq/Makefile.am: List set_d.c.
+	* mpq/Makefile.in: Regenerate.
+
+2000-04-07  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/fits_sint_p.c: New file.
+	* mpz/fits_slong_p.c: New file.
+	* mpz/fits_sshort_p.c: New file.
+	* mpz/fits_uint_p.c: New file.
+	* mpz/fits_ulong_p.c: New file.
+	* mpz/fits_ushort_p.c: New file.
+	* gmp.h: Declare mpz_fits_*.
+	* mpz/Makefile.am: List fits_* files.
+	* mpz/Makefile.in: Regenerate.
+
+2000-04-06  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.texi (Installing MP): Add known build problem SunOS 4.1.4 m4
+	failure.
+
+	* mpn/x86/pentium/gmp-mparam.h: Tune thresholds.
+	* mpn/x86/p6/gmp-mparam.h: Ditto.
+	* mpn/x86/k6/gmp-mparam.h: Tune thresholds, add UMUL_TIME, UDIV_TIME.
+	* mpn/x86/k7/gmp-mparam.h: Tune thresholds, amend UMUL_TIME.
+
+	* mpn/generic/mul_n.c (mpn_kara_mul_n): Add an ASSERT.
+	(mpn_kara_sqr_n): Add an ASSERT, use KARATSUBA_SQR_THRESHOLD.
+	(mpn_toom3_sqr_n): Eliminate second evaluate3.
+
+	* gmp-impl.h (mpn_com_n,MPN_LOGOPS_N_INLINE): Don't allow size==0.
+	(tune_mul_threshold,tune_sqr_threshold): Conditionalize
+	declarations on TUNE_PROGRAM_BUILD.
+
+	* mpn/generic/sqr_basecase.c: Add an assert.
+
+2000-04-05  Torbjorn Granlund  <tege@swox.com>
+
+	* gmp.h, mpn/asm-defs.m4: List the same functions for __MPN, but
+	leave some commented out.
+
+	* gmp-impl.h (MPN_LOGOPS_N_INLINE): Optimize.
+	(mpn_com_n): Optimize.
+
+	* gmp.h (__MPN): Make it use __gmpn instead of __mpn for consistency.
+	* mpn/asm-defs.m4 (MPN_PREFIX): Likewise.
+
+	* gmp.h (GMP_ERROR_ALLOCATE): New errcode.
+
+	* gmp-impl.h (MPN_MUL_N_RECURSE): Delete.
+	(MPN_SQR_RECURSE): Delete.
+
+	* gmp-impl.h (TARGET_REGISTER_STARVED): New define.
+
+	* gmp-impl.h (mpn_kara_sqr_n): Remap with __MPN.
+	(mpn_toom3_sqr_n): Likewise.
+	(mpn_kara_mul_n): Likewise.
+	(mpn_toom3_mul_n): Likewise.
+	(mpn_reciprocal): Likewise.
+
+	* gmp-impl.h (__gmpn_mul_n): Remove declaration.
+	(__gmpn_sqr): Likewise.
+	* gmp.h (mpn_sqr_n): Declare/remap.
+	* mpn/generic/mul.c (mpn_sqr_n): New name for mpn_sqr.
+
+	* gmp.h (mpn_udiv_w_sdiv): Move __MPN remap from here...
+	* gmp-impl.h: ...to here.
+
+2000-04-05  Linus Nordberg  <linus@swox.se>
+
+	* gmp.texi (Top): Add `Random Number Functions' to menu.
+	(Introduction to MP): Fix typo.
+	(MP Basics): Create menu for all sections.  Move `Random Number
+	Functions' to its own chapter.  Add nodes for all sections.
+	(Function Classes): Mention random generation functions under
+	miscellaneous.
+	(Miscellaneous Integer Functions): Update mpz_urandomb,
+	mpz_urandomm.
+	(Low-level Functions): Remove mpn_rawrandom.
+	(Random State Initialization): Update.
+
+	* mpf/urandom.c (mpf_urandomb): Remove SIZE parameter.  Normalize
+	result correctly.
+
+	* gmp.h (mpf_urandomb): Remove SIZE parameter.
+
+	* randraw.c (gmp_rand_getraw): Handle the case where (1) the LC
+	scheme doesn't generate even limbs and (2) more than one LC
+	invocation is necessary to produce the requested number of bits.
+
+2000-04-05  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/mul_n.c (INVERSE_3): New name for THIRD, define for
+	any BITS_PER_MP_LIMB.
+	(MP_LIMB_T_MAX): New.
+	(mpn_divexact3_n): Remove.
+	(interpolate3): Use mpn_divexact_by3 instead of mpn_divexact3_n.
+
+2000-04-05  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-impl.h (KARATSUBA_MUL_THRESHOLD<2): Remove cpp test.
+	(tune_mul_threshold,tune_sqr_threshold): Add declarations, used in
+	development only.
+
+	* mpn/x86/k7/sqr_basecase.asm: New file, only a copy of k6 for now.
+
+2000-04-04  Torbjorn Granlund  <tege@swox.com>
+
+	* gmp-impl.h (TOOM3_MUL_THRESHOLD): Provide default.
+	(TOOM3_SQR_THRESHOLD): Provide default.
+
+	* mpn/generic/mul_n.c: Rewrite (mostly by Robert Harley).
+	* mpn/generic/mul.c: Rewrite (mostly by Robert Harley).
+
+	* configure.in (sparcv9 64-bit OS): Set extra_functions.
+
+2000-04-04  Linus Nordberg  <linus@swox.se>
+
+	* mpn/generic/rawrandom.c: Remove file and replace with randraw.c
+	on top level.
+	(mpn_rawrandom): Rename to gmp_rand_getraw.
+
+	* randraw.c: New file; essentially a copy of
+	mpn/generic/rawrandom.c.
+	(gmp_rand_getraw): New function (formerly known as mpn_rawrandom).
+
+	* mpz/urandomb.c (mpz_urandomb): Change mpn_rawrandom -->
+	gmp_rand_getraw.
+	* mpz/urandomm.c (mpz_urandomb): Ditto.
+	* mpf/urandom.c (mpf_urandomb): Ditto.
+
+	* gmp.h (gmp_rand_getraw): Add function prototype.
+	(mpn_rawrandom): Remove function prototype.
+
+	* Makefile.am (libgmp_la_SOURCES): Add randraw.c.
+	* Makefile.in: Regenerate.
+
+	* configure.in (gmp_mpn_functions): Remove rawrandom.
+	* configure: Regenerate.
+
+2000-04-04  Linus Nordberg  <linus@swox.se>
+
+	* gmp.h (GMP_ERROR enum): Remove comma after last enumeration
+	since the AIX compiler (xlc) doesn't like that.
+
+	* randlc.c (gmp_rand_init_lc): Allocate enough space for seed to
+	hold any upcoming seed.
+	* randlc2x.c (gmp_rand_init_lc_2exp): Likewise.
+
+	* mpn/generic/rawrandom.c: Remove debugging code.
+	(mpn_lc): Don't reallocate seed.
+
+	* mpz/urandomm.c (mpz_urandomm): Implement function.
+
+	* mpz/urandomb.c (mpz_urandomb): Fix typo in function definition.
+
+2000-04-04  Kevin Ryde  <kevin@swox.se>
+
+	* make.bat: Removed (no longer works, no longer supported).
+	* mpn/msdos/asm-syntax.h: Removed (was used only by make.bat).
+
+2000-04-03  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/brandom.c: New file, replacing random2.
+
+2000-04-02  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/sparc32/v9/submul_1.asm: Change some carry-form instructions
+	into their plain counterparts.
+
+	* mpn/sparc64/copyi.asm: Avoid executing ALIGN.
+
+	* mpn/sparc64/mul_1.asm: Handle overlap of rp/sp.
+	* mpn/sparc64/addmul_1.asm: Likewise.
+	* mpn/sparc64/submul_1.asm: Likewise.
+
+2000-04-01  Linus Nordberg  <linus@swox.se>
+
+	* gmp.h: Fix function prototypes for randomization functions.
+	(__gmp_rand_lc_scheme_struct): Replace `m' with `m2exp'. Remove
+	unused `bits'.
+	(__gmp_rand_data_lc): Add `m2exp' as another way of representing
+	the modulus.
+	(__gmp_rand_state_struct): Remove unused `size'.
+
+	* rand.c (__gmp_rand_scheme): Use better multipliers.  Remove test
+	schemes.  Replace `m' with `m2exp'.
+	(gmp_rand_init): Change parameters and return type.  Use `m2exp'
+	instead of `m'.  Set `gmp_errno' on error.  Disable BBS algorithm.
+
+	* randlc.c (gmp_rand_init_lc): Don't use malloc().  Change
+	parameters.
+
+	* randclr.c (gmp_rand_clear): Don't use free().  Disable BBS
+	algorithm.  Set `gmp_errno' on error.
+
+	* randlc2x.c (gmp_rand_init_lc_2exp): New function.
+	* randsd.c (gmp_rand_seed): New function.
+	* randsdui.c (gmp_rand_seed_ui): New function.
+	* randlcui.c: Remove unused file.
+
+	* mpn/generic/rawrandom.c (mpn_rawrandom): Rewrite.
+	(mpn_lc): New static function.
+
+	* mpz/urandomb.c (mpz_urandomb): Use ABSIZ() instead of SIZ() for
+	determining size of ROP.
+
+	* mpf/urandom.c (mpf_urandomb): Add third parameter, nbits.  (Not
+	used yet!)
+	Change parameter order to mpn_rawrandom().
+
+	* Makefile.am (libgmp_la_SOURCES): Add errno.c, randlc2x.c,
+	randsd.c, randsdui.c.  Remove randui.c.
+	(MPZ_OBJECTS): Rename urandom.lo --> urandomb.lo.  Add urandomm.lo.
+	* Makefile.in: Regenerate.
+
+	* mpz/Makefile.am (libmpz_la_SOURCES): Change urandom.c -->
+	urandomb.c.  Add urandomm.c.
+	* mpz/Makefile.in: Regenerate.
+
+	* tests/rand/Makefile.am (noinst_PROGRAMS): Change findcl --> findlc.
+	Add gen.static.
+	* tests/rand/Makefile.in: Regenerate.
+
+	* tests/rand/gen.c (main): Add mpz_urandomm.  Add command line options
+	`-C', `-m', extend `-a'.  Use *mp*_*rand*() with new parameters.  Call
+	gmp_rand_seed().
+
+2000-04-01  Kevin Ryde  <kevin@swox.se>
+
+	* acinclude.m4 (GMP_CHECK_ASM_DATA): Plain .data for hpux.
+	* configure.in (CCAS): No CFLAGS, they're added when it's used.
+	(CONFIG_SRCDIR): New define for config.m4.
+	* mpn/sparc64/addmul_1.asm: Use it for an include().
+	* mpn/sparc64/submul_1.asm: Ditto.
+	* mpn/sparc64/mul_1.asm: Ditto.
+
+2000-03-31  Linus Nordberg  <linus@swox.se>
+
+	* mpz/urandom.c: Rename to...
+	* mpz/urandomb.c: ...this.
+
+	* mpz/urandomb.c (mpz_urandomb): Change operand order in call to
+	mpn_rawrandom().  Use ABSIZ() instead of SIZ() when checking size
+	of ROP.
+
+	* mpz/urandomm.c: New file.
+
+2000-03-31  Kevin Ryde  <kevin@swox.se>
+
+	* acinclude.m4 (GMP_CHECK_ASM_MMX): Give a warning when mmx code
+	will be omitted.
+
+2000-03-30  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/sparc64/mul_1h.asm: New file.
+	* mpn/sparc64/addmul_1h.asm: New file.
+	* mpn/sparc64/submul_1h.asm: New file.
+	* mpn/sparc64/mul_1.asm: Rewrite.
+	* mpn/sparc64/addmul_1.asm: Rewrite.
+	* mpn/sparc64/submul_1.asm: Rewrite.
+
+2000-03-28  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/sparc32/v9/mul_1.asm: Fix typo in branch prediction.
+	* mpn/sparc32/v9/addmul_1.asm: Likewise.
+	* mpn/sparc32/v9/submul_1.asm: Likewise.
+
+2000-03-25  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/lisp/gmpasm-mode.el: Fix some comment detection, use custom,
+	fontify more keywords, turn into a standalone mode.
+
+	* stamp-vti: New file, generated together with version.texi.
+
+	* acinclude.m4 (GMP_VERSION,GMP_HEADER_GETVAL): New macros.
+	* configure.in (AM_INIT_AUTOMAKE): Use GMP_VERSION.
+
+2000-03-24  Kevin Ryde  <kevin@swox.se>
+
+	* INSTALL: Updates for new configure system.
+
+	* configure.in: Add gmp_optcflags_gcc for the x86s, setting -mcpu
+	and -march.
+
+2000-03-23  Torbjorn Granlund  <tege@swox.com>
+
+	* demos/pexpr.c (mpz_eval_expr): Properly initialize rhs/lhs
+	for ROOT.
+
+2000-03-23  Kevin Ryde  <kevin@swox.se>
+
+	* config.guess (i?86:*:*:*): Use uname -m if detection program fails.
+
+	* mpn/x86/README: Remove remarks on the now implemented MMX shifts.
+	* mpn/x86/k6/README: Add speed of mpn_divexact_by3, update mpn_mul_1.
+
+	* gmp.texi (Installing MP): Corrections to target CPUs.
+
+	* version.c: Use VERSION from config.h, add copyright comment,
+	restore "const" somehow lost.
+
+	* configure.in (a29k*-*-*): Fix directory name.
+
+2000-03-22  Torbjorn Granlund  <tege@swox.com>
+
+	* demos/pexpr.c (op_t): Add ROOT.
+	(fns): Add ROOT.
+	(mpz_eval_expr): Add ROOT.
+
+	* mpz/root.c: Handle roots of negative numbers.
+	Fix other border cases.
+	Fix rare memory leakage.
+
+	* errno.c: New file.
+
+2000-03-21  Torbjorn Granlund  <tege@swox.com>
+
+	* gmp.h (error number enum): New anonymous enum.
+	(gmp_errno): New.
+
+	* gmp.h (__GNU_MP_VERSION, __GNU_MP_VERSION_MINOR): Bump for GMP 3.0.
+
+2000-03-20  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/alpha/unicos.m4 (FLOAT64): New define.
+	* mpn/alpha/default.m4 (FLOAT64): New define.
+	* mpn/alpha/invert_limb.asm (C36): Use FLOAT64.
+
+2000-03-21  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/x86/k6/diveby3.asm: Tiny speedup.
+
+	* acinclude.m4 (GMP_CHECK_ASM_SHLDL_CL): New macro.
+	* configure.in: Use it, set WANT_SHLDL_CL in config.m4.
+	* mpn/x86/x86-defs.m4 (shldl,shrdl,shldw,shrdw): New macros, using
+	WANT_SHLDL_CL.
+	* mpn/x86/k6/mmx/lshift.asm: Use shldl macro.
+	* mpn/x86/k7/mmx/lshift.asm: Ditto.
+	* mpn/x86/pentium/mmx/lshift.asm: Ditto.
+	* mpn/x86/k6/mmx/rshift.asm: Use shrdl macro.
+	* mpn/x86/k7/mmx/rshift.asm: Ditto.
+	* mpn/x86/pentium/mmx/rshift.asm: Ditto.
+	* mpn/x86/README.family: Add a note about this.
+
+2000-03-20  Linus Nordberg  <linus@swox.se>
+
+	* mpn/generic/rawrandom.c (mpn_rawrandom): Handle seed value of 0
+	correctly.
+
+	* configure.in: Fix detection of alpha flavour.
+	Set compiler options for `sparcv8'.
+	* configure: Regenerate.
+
+	* rand.c (__gmp_rand_scheme): Clean up some.  Use slightly better
+	multipliers.
+
+	* configure.in (AC_OUTPUT): Add tests/Makefile and
+	tests/rand/Makefile.
+
+	* acinclude.m4 (AC_CANONICAL_BUILD): Define to
+	`_AC_CANONICAL_BUILD' to deal with incompatibilities between
+	Autoconf and Libtool.
+	(AC_CHECK_TOOL_PREFIX): Likewise.
+
+	* Makefile.am (EXTRA_DIST): Add directory `tests'.
+
+	* mkinstalldirs: Update (Automake 2000-03-17).
+	* ltconfig: Update (Libtool 2000-03-17).
+	* ltmain.sh: Ditto.
+
+	* configure: Regenerate with new autoconf/-make/libtool suite.
+	* aclocal.m4: Ditto.
+	* config.in: Ditto.
+	* all Makefile.in's: Ditto.
+
+2000-03-20  Torbjorn Granlund  <tege@swox.com>
+
+	* demos/pexpr.c (main): Don't allow `-N' for base, require `-bN'.
+
+	* mpn/alpha/unicos.m4 (cvttqc): New define.
+	* mpn/alpha/invert_limb.asm: Use new define for cvttqc.
+
+2000-03-19  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/x86/k6/sqr_basecase.asm: Tiny amendments for 3x3 case.
+
+	* gmp.texi: Use @include version.texi.
+	Use @email and @uref.
+	(Installing MP): Rewrite for new configure.
+	(Low-level Functions): Add mpn_divexact_by3.
+
+	* configure.in (--enable-alloca): New option.
+	* acconfig.h (USE_STACK_ALLOC): For --disable-alloca.
+
+2000-03-18  Kent Boortz  <kent@swox.com>
+
+	* macos: New directory with macos port files.
+
+2000-03-17  Torbjorn Granlund  <tege@swox.com>
+
+	* gmp-impl.h (union ieee_double_extract): Check _CRAYMPP.
+
+	* mpn/asm-defs.m4 (invert_normalized_limb): Define.
+
+	* mpn/alpha: Translate `.s' files to `.asm'.
+
+	* configure: Regenerate.
+
+	* mpn/alpha/invert_limb.asm: Replace dash in file name with underscore.
+	* configure.in: Corresponding change.
+
+	* configure.in: Assign special "path" for alphaev6.
+
+	* mpn/alpha/unicos.m4: New file.
+	* configure.in (alpha*-cray-unicos*): [This part of the change
+	commited 2000-03-13 by linus]
+	* mpn/alpha/default.m4: New file.
+	* configure.in (alpha*-*-*): Use it.
+
+2000-03-17  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/x86/pentium/rshift.S: Use plain rcrl (not rcrl $1) for
+	shift-by-1 case, significant speedup.
+	* mpn/x86/pentium/README: Add shift-by-1 speed.
+
+2000-03-16  Torbjorn Granlund  <tege@swox.com>
+
+	* config.guess: Handle Cray T3D/E.
+
+2000-03-15  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/generic/diveby3.c: New file.
+	* mpn/x86/diveby3.asm: New file.
+	* mpn/x86/k6/diveby3.asm: New file.
+	* gmp.h (mpn_divexact_by3): Prototype and define.
+	* mpn/asm-defs.m4: define_mpn(divexact_by3).
+	* configure.in (gmp_mpn_functions): Add diveby3.
+
+	* mpn/x86/pentium/sqr_basecase.asm: A few better addressing modes.
+
+	* configure.in: Add AC_C_STRINGIZE and AC_CHECK_TYPES((void)).
+	* gmp-impl.h (ASSERT): Use them.
+
+	* mpn/x86/k7/mmx/lshift.asm: New file.
+	* mpn/x86/k7/mmx/rshift.asm: Rewrite simple loop and return value
+	handling, add some pictures.
+
+2000-03-14  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/sparc32/v8/mul_1.asm: Make PIC actually work.
+	* mpn/sparc32/v8/addmul_1.asm: Likewise.
+
+	* mpn/sparc32/v8/mul_1.asm: Use m4 ifdef, not cpp #if.
+	* mpn/sparc32/v8/addmul_1.asm: Likewise.
+
+	* mpn/asm-defs.m4 (C): New define for comments.
+	* mpn/sparc32: Start comments with `C'.
+
+	* config.guess: Remove `SunOS 6' handling.
+	Recognize sun4m and sun4d architectures under old SunOS.
+
+2000-03-14  Linus Nordberg  <linus@swox.se>
+
+	* configure.in (gmp_srclinks): Set to list of links created by
+	configure.
+	* configure: Regenerate.
+
+	* Makefile.am (libgmp_la_LDFLAGS): Set version info.
+	(DISTCLEANFILES): Include @gmp_srclinks@.
+	* Makefile.in: Regenerate.
+
+2000-03-13  Linus Nordberg  <linus@swox.se>
+
+	* configure.in: Remove some changequote's by quoting the strings
+	containing `[]'.
+	Add support for `alpha*-cray-unicos*'.
+	AC_DEFINE `_LONG_LONG_LIMB' instead of passing it in CFLAGS.
+	Conditionalize the assembler syntax checks.
+	* configure: Regenerate.
+	* config.in: Regenerate.
+
+	* acinclude.m4 (GMP_PROG_CCAS): Remove macro.
+	* aclocal.m4: Regenerate.
+
+2000-03-13  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/x86/p6/README: New file.
+
+	* mpn/x86/k6/mul_1.asm: Rewrite, smaller and slightly faster.
+
+	* mpn/lisp/gmpasm-mode.el: Rewrite assembler comment detection and
+	handling.
+
+	* configure.in: Separate mmx directories for each x86 flavour.
+	* configure: Regenerate.
+
+2000-03-12  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/x86/x86-defs.m4 (ALIGN): Supplement definition from
+	config.m4 so as to pad with nops not zeros on old gas.
+
+	* mpn/x86/k7/mmx/copyd.asm: Use plain emms (femms is just an alias
+	for emms now).
+	* mpn/x86/k7/mmx/copyi.asm: Ditto.
+	* mpn/x86/k7/mmx/rshift.asm: Ditto.
+	* mpn/x86/x86-defs.m4: Amend comments.
+
+	* mpn/x86/mod_1.asm: Add comments on speeds.
+
+	* mpn/x86/pentium/mmx/lshift.asm: New file.
+	* mpn/x86/pentium/mmx/rshift.asm: New file.
+	* mpn/x86/pentium/README: Add speeds of various routines.
+
+2000-03-10  Linus Nordberg  <linus@swox.se>
+
+	* configure.in: Reorganize.
+	Use AC_CHECK_TOOL to find `ar'.
+	Add post-includes `regmap.m4' and `aix.m4' for AIX targets.
+	asm-syntax.h is not needed for PPC or sparc anymore.
+	(powerpc64-*-aix*): Compiler is always 64-bit. Use `-q64
+	-qtune=pwr3' to xlc and `-maix64 -mpowerpc64' to gcc.  Pass `-X
+	64' to `ar' and `nm'.
+	(pentiummmx): Use GMP_CHECK_ASM_MMX and avoid MMX assembly path if
+	assembler is not MMX capable.
+	(pentium[23]): Likewise.
+	(athlon): Likewise.
+	(k6*): Likewise.
+	* configure: Regenerate.
+
+	* acinclude.m4 (GMP_PROG_CC_WORKS): New macro.
+	(GMP_PROG_CC_FIND): Use GMP_PROG_CC_WORKS instead of
+	AC_TRY_COMPILER.  Make sure that the *first* working 32-bit
+	compiler is used if no 64-bit compiler is found.
+	(GMP_CHECK_ASM_MMX): New macro.
+	* aclocal.m4: Regenerate.
+
+	* Makefile.in: Regenerate.  (CC_TEST removed.)
+	* mpf/Makefile.in: Likewise.
+	* mpn/Makefile.in: Likewise.
+	* mpq/Makefile.in: Likewise.
+	* mpz/Makefile.in: Likewise.
+	* mpf/tests/Makefile.in: Likewise.
+	* mpq/tests/Makefile.in: Likewise.
+	* mpz/tests/Makefile.in: Likewise.
+
+	* acconfig.h (_LONG_LONG_LIMB): Add.
+
+	* gmp-impl.h: Include config.h only if HAVE_CONFIG_H is defined.
+
+2000-03-09  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/x86/pentium/mul_basecase.S: Small speedup by avoiding an AGI.
+
+	* mpn/x86/k7/mmx/copyd.asm: Tiny speedup by avoiding popl.
+	* mpn/x86/k7/mmx/copyi.asm: Ditto.
+	* mpn/x86/k7/mul_basecase.asm: Ditto.
+
+2000-03-07  Torbjorn Granlund  <tege@swox.com>
+
+	* config.guess: Better recognize POWER/PowerPC processor type.
+
+2000-03-07  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/generic/addsub_n.c: Use HAVE_NATIVE_* now in config.h.
+
+	* mpn/asm-defs.m4: Add comments about SysV m4.
+	(m4_log2): Don't use <<.
+	(m4_lshift,m4_rshift): New macros.
+
+2000-03-06  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc32/regmap.m4: Map cr0 => `0', etc.
+
+2000-03-06  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/tests/ref.c (refmpn_divexact_by3): New function.
+	* mpn/tests/ref.h: Prototype.
+
+	* acconfig.h (WANT_ASSERT): New define.
+	* configure.in (--enable-assert): Turn on WANT_ASSERT.
+	* assert.c: New file.
+	* Makefile.am: Add to build.
+	* gmp-impl.h (ASSERT): New macro.
+	(ASSERT_NOCARRY) Renamed from assert_nocarry.
+	(MPZ_CHECK_FORMAT): Use ASSERT_ALWAYS.
+	* mpn/tests/ref.c: Use ASSERT.
+	* mpf/get_str.c: Use ASSERT_ALWAYS.
+	* mpf/set_str.c: Remove old assert macro.
+
+	* mpn/x86/x86-defs.m4 (cmovnz_ebx_ecx): New macro.
+	* mpn/x86/p6/aorsmul_1.asm: Use cmov.
+
+	* mpn/x86/lshift.S: Use %dl with testb, not %edx. No object code
+	change, testb was still getting generated.
+	* mpn/x86/rshift.S: Ditto.
+
+2000-03-03  Torbjorn Granlund  <tege@swox.com>
+
+	* longlong.h: Add IA-64 support.
+
+	* mpn/powerpc32: Misc cleanups.
+	* mpn/powerpc32/aix.m4: New file (mainly by Linus).
+	* mpn/powerpc64/aix.m4: New file (mainly by Linus).
+	* mpn/powerpc64: Translate `.S' files to `.asm'.
+
+	* configure.in: Fix tyops.
+	* configure: Regenerate.
+
+2000-03-02  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc32/regmap.m4: New file.
+	* mpn/powerpc32: Translate `.S' files to `.asm'.
+	* configure.in: Use mpn/powerpc32/regmap.m4 for powerpc targets
+	except some weird ones.
+
+2000-03-03  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/lisp/gmpasm-mode.el: Suppress postscript comment prefixes in
+	filladapt.
+
+	* mpn/x86/pentium/sqr_basecase.asm: New file.
+	* mpn/x86/pentium/gmp-mparam.h (KARATSUBA_SQR_THRESHOLD): Update.
+
+	* configure.in: Add --enable-assert, enable k6 logops functions.
+
+	* mpn/x86/k6/mmx/copyi.asm: Use m4 for divide, not as.
+	* mpn/x86/k6/mmx/copyd.asm: Ditto.
+	* mpn/x86/README.family: Add a note on this.
+
+2000-03-02  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/x86/k6/aors_n.asm: Don't use stosl.
+	* mpn/x86/copyi.asm: Use cld to clear direction flag.
+	* mpn/x86/divrem_1.asm: Ditto.
+	* mpn/x86/README.family: Add a note on this.
+
+	* mpn/x86/k6/mmx/copyi.asm: Rewrite.
+	* mpn/x86/k6/mmx/copyd.asm: New file.
+	* mpn/x86/k6/README: Update, and small amendments.
+
+	* mpn/x86/x86-defs.m4 (Zdisp): New macro.
+	* mpn/asm-defs.m4 (m4_stringequal_p): New macro.
+
+	* mpn/x86/p6/aorsmul_1.asm: Use Zdisp to force zero displacements.
+	* mpn/x86/k6/aorsmul_1.asm: Ditto.
+	* mpn/x86/k6/mul_1.asm: Ditto.
+	* mpn/x86/k6/mul_basecase.asm: Ditto.
+	* mpn/x86/k7/aors_n.asm: Ditto.
+	* mpn/x86/k7/aorsmul_1.asm: Ditto.
+	* mpn/x86/k7/mul_1.asm: Ditto.
+	* mpn/x86/k7/mul_basecase.asm: Ditto.
+	* mpn/x86/README.family: Add a note on this.
+
+2000-02-27  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/generic/divrem.c (mpn_divrem_classic): Patch to avoid gcc
+	2.7.2.3 i386 register handling bug.
+
+	* mpn/x86/k6/aors_n.asm: Rewrite.
+	* mpn/x86/k6/mmx/lshift.asm: Rewrite.
+	* mpn/x86/k6/mmx/rshift.asm: Rewrite.
+	* mpn/x86/k6/README: Update.
+
+	* mpn/x86/k7/mmx/copyd.asm: Support size==0.
+	* mpn/x86/k7/mmx/copyi.asm: Ditto.
+	* mpn/x86/k6/mmx/copyi.asm: Ditto.
+	* gmp-impl.h: Comment size==0 allowed in MPN_COPY_INCR and
+	MPN_COPY_DECR.
+	* configure.in: Enable x86 copyi, copyd; add k6 com_n.
+
+2000-02-25  Torbjorn Granlund  <tege@swox.com>
+
+	* demos/pexpr.c (power): Move factorial handing code from `factor'
+	to `power'.
+
+	* demos/factorize.c (factor_using_pollard_rho): Move resetting of `c'
+	to before checking for a non-zero gcd.
+
+2000-02-25  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/asm-defs.m4 (MULFUNC_PROLOGUE): New macro by Linus.
+	* mpn/x86/k6/aors_n.asm: Use MULFUNC_PROLOGUE.
+	* mpn/x86/k6/aorsmul_1.asm: Ditto.
+	* mpn/x86/k7/aors_n.asm: Ditto.
+	* mpn/x86/k7/aorsmul_1.asm: Ditto.
+	* mpn/x86/p6/aorsmul_1.asm: Ditto.
+
+	* mpn/tests/ref.c (refmpn_copyi,refmpn_copyd): Allow size==0.
+
+	* gmp-impl.h: Move mpn_and_n, mpn_andn_n, mpn_com_n, mpn_ior_n,
+	mpn_iorn_n, mpn_nand_n, mpn_nior_n, mpn_xor_n and mpn_xorn_n here
+	from gmp.h.  Use HAVE_NATIVE_mpn_* to make these functions or
+	inlines.
+
+	* gmp-impl.h: Move mpn_copyd, mpn_copyi here from gmp.h.
+	* gmp-impl.h (MPN_COPY_INCR): Use mpn_copyi if available.
+	* gmp-impl.h (MPN_COPY_DECR): Use mpn_copyd if available.
+
+	* mpn/x86/k6/mmx/com_n.asm: Moved into mmx subdirectory.
+	* mpn/x86/k6/mmx/copyi.asm: Ditto.
+	* mpn/x86/k6/mmx/lshift.asm: Ditto.
+	* mpn/x86/k6/mmx/rshift.asm: Ditto.
+	* mpn/x86/k7/mmx/rshift.asm: Ditto.
+	* mpn/x86/k6/mmx/logops_n.asm: New file.
+	* configure.in (k6*-*-*): Add logops_n.asm.
+	* mpn/x86/k6/README: Update.
+
+	* mpn/x86/k7/mmx/copyi.asm: New file.
+	* mpn/x86/k7/mmx/copyd.asm: New file.
+	* mpn/x86/k7/README: Update.
+
+2000-02-24  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/x86/x86-defs.m4 (femms): Generate emms if 3dnow not available.
+	* mpn/x86/x86-defs.m4 (FRAME_popl): New macro.
+
+	* Makefile.am: Add info_TEXINFOS = gmp.texi
+
+	* mpn/x86/divrem_1.asm: Moved from mpn/x86/k6, allow size==0,
+	conditionalize loop versus decl/jnz.
+	* mpn/x86/mod_1.asm: Ditto.
+	* mpn/x86/divmod_1.asm: Removed.
+	* gmp.texi (mpn_divrem_1,mpn_mod_1): Add that size==0 is allowed.
+	* mpn/tests/ref.c (refmpn_divrem_1c,etc): Allow size==0.
+
+	* mpn/x86/k6/aors_n.asm: Avoid gas 1.92.3 leal displacement
+	expression problem.
+	* mpn/x86/k6/aorsmul_1.asm: Ditto.
+	* mpn/x86/k6/mul_1.asm: Ditto.
+	* mpn/x86/k6/mul_basecase.asm: Ditto
+	* mpn/x86/k7/aors_n.asm: Ditto.
+	* mpn/x86/k7/aorsmul_1.asm: Ditto.
+	* mpn/x86/k7/mul_1.asm: Ditto.
+	* mpn/x86/k7/mul_basecase.asm: Ditto.
+	* mpn/x86/k7/rshift.asm: Ditto.
+	* mpn/x86/p6/aorsmul_1.asm: Ditto.
+	* mpn/x86/README.family: Describe problem.
+
+2000-02-24  Linus Nordberg  <linus@swox.se>
+
+	* acinclude.m4 (GMP_CHECK_ASM_LSYM_PREFIX): Add dummy symbol to
+	testcase to avoid nm failure.  Try nm before piping to grep.
+
+	* acconfig.h: Undef HAVE_NATIVE_func for every mpn function found
+	in gmp.h.
+
+	* configure.in: Invoke AC_CONFIG_HEADERS.
+	Don't invoke AM_CONFIG_HEADER; it makes autoconf confused.
+	Dig out entry points declared in assembly code and AC_DEFINE proper
+	HAVE_NATIVE_func.
+
+	* mpn/asm-defs.m4 (MULFUNC_PROLOGUE): New macro.
+
+	* mpn/x86/p6/aorsmul_1.asm: Use MULFUNC_PROLOGUE.
+	* mpn/x86/k6/aors_n.asm: Likewise.
+
+	* Makefile.am (EXTRA_DIST): Add config.in; needed when we don't
+	use AM_CONFIG_HEADER in configure.in.
+
+	* mpn/Makefile.am (INCLUDES): Add `-I..' for config.h and
+	gmp-mparam.h.
+	* mpf/Makefile.am: Likewise.
+	* mpq/Makefile.am: Likewise.
+	* mpz/Makefile.am: Likewise.
+
+	* mpf/tests/Makefile.am (INCLUDES): Add `-I../..' for config.h and
+	gmp-mparam.h.
+	* mpq/tests/Makefile.am: Likewise.
+	* mpz/tests/Makefile.am: Likewise.
+
+	* configure: Regenerate.
+	* aclocal.m4: Regenerate.
+	* config.in: Regenerate.
+	* Makefile.in: Regenerate.
+	* mpf/Makefile.in: Regenerate.
+	* mpn/Makefile.in: Regenerate.
+	* mpq/Makefile.in: Regenerate.
+	* mpz/Makefile.in: Regenerate.
+	* mpf/tests/Makefile.in: Regenerate.
+	* mpq/tests/Makefile.in: Regenerate.
+	* mpz/tests/Makefile.in: Regenerate.
+
+2000-02-23  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/x86/addmul_1.S: Amend comments, this code no longer used by
+	PentiumPro.
+	* mpn/x86/submul_1.S: Ditto.
+
+	* mpn/x86/k6/com_n.asm: Rewrite, smaller but same speed.
+
+	* mpn/x86/addmul_1.S: Add PROLOGUE and EPILOGUE to get .type and
+	.size for ELF.  Rename #define size to n to avoid .size.
+	* mpn/x86/lshift.S: Ditto.
+	* mpn/x86/mul_1.S: Ditto.
+	* mpn/x86/mul_basecase.S: Ditto.
+	* mpn/x86/rshift.S: Ditto.
+	* mpn/x86/submul_1.S: Ditto.
+	* mpn/x86/udiv.S: Ditto.
+	* mpn/x86/umul.S: Ditto.
+	* mpn/x86/pentium/add_n.S: Ditto.
+	* mpn/x86/pentium/addmul_1.S: Ditto.
+	* mpn/x86/pentium/lshift.S: Ditto.
+	* mpn/x86/pentium/mul_1.S: Ditto.
+	* mpn/x86/pentium/mul_basecase.S: Ditto.
+	* mpn/x86/pentium/rshift.S: Ditto.
+	* mpn/x86/pentium/sub_n.S: Ditto.
+	* mpn/x86/pentium/submul_1.S: Ditto.
+
+2000-02-22  Linus Nordberg  <linus@swox.se>
+
+	* acinclude.m4 (GMP_INIT): Use temporary file cnfm4p.tmp for
+	post-defines.
+	(GMP_FINISH): Ditto.
+	(GMP_DEFINE): Add third optional argument specifying location in
+	outfile.
+	(GMP_DEFINE_RAW): New macro.
+	* aclocal.m4: Regenerate.
+
+	* configure.in: Add `HAVE_TARGET_CPU_$target_cpu' using
+	GMP_DEFINE_RAW.
+	* configure: Regenerate.
+
+	* mpz/tests/Makefile.am: New test t-root.
+	* mpz/tests/Makefile.in: Regenerate.
+
+2000-02-22  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/root.c: Complete rewrite; still primitive, but at least correct.
+	* mpz/tests/t-root.c: New test.
+
+2000-02-22  Kevin Ryde  <kevin@swox.se>
+
+	* mpn/x86/k7/mul_basecase.asm: New file.
+	* mpn/x86/k7/README: Add mpn_mul_basecase speed.
+	* mpn/x86/k7/gmp-mparam.h: New file.
+
+	* mpn/x86/x86-defs.m4 (loop_or_decljnz,cmov_bytes): New macros.
+	* mpn/asm-defs.m4 (m4_ifdef_anyof_p): New macro.
+
+	* mpn/x86/k6/aorsmul_1.asm: New file.
+	* mpn/x86/k6/addmul_1.S: Removed (was a copy of pentium version).
+	* mpn/x86/k6/submul_1.S: Removed (was a copy of pentium version).
+
+	* mpn/x86/p6/aorsmul_1.asm: Use OPERATION_addmul_1 and
+	OPERATION_submul_1.
+	* mpn/x86/k6/aors_n.asm: Use OPERATION_add_n and OPERATION_sub_n.
+	* configure.in: Declare multi-function files for k6 and p6.
+
+	* configure.in: Add HAVE_TARGET_CPU_$target_cpu for config.m4.
+	* mpn/asm-defs.m4 (define_not_for_expansion): New macro.
+
+	* mpn/generic/divrem_1n.c (__gmpn_divrem_1n): New file, split from
+	mpn/generic/divrem_1.c.
+	* mpn/generic/divrem_1.c: Ditto.
+	* configure.in (gmp_mpn_functions): Ditto.
+
+2000-02-21  Torbjorn Granlund  <tege@swox.com>
+
+	* gmp.h: Undo 1996-10-06 NeXT change, it was clearly improperly
+	written.
+
+2000-02-21  Linus Nordberg  <linus@swox.se>
+
+	* configure.in: Link <src>/mpn/asm-defs.m4 to <build>mpn/asm.m4.
+	* configure: Regenerate.
+
+2000-02-21  Linus Nordberg  <linus@swox.se>
+
+	* mpn/x86/k7/aorsmul_1.asm: Change OPERATION_ADDMUL -->
+	OPERATION_addmul_1.  Change OPERATION_SUBMUL -->
+	OPERATION_submul_1.
+
+	* mpn/x86/k7/aors_n.asm: Change OPERATION_ADD --> OPERATION_add_n.
+	Change OPERATION_SUB --> OPERATION_sub_n.
+
+	* mpn/Makefile.am: Pass -DOPERATION_$* to preprocessors.
+	* mpn/Makefile.in: Regenerate.
+
+	* configure.in: Symlink mpn/asm-defs.m4 to build-dir/mpn.  Link
+	multi-function files to mpn/<function>.asm and remove function
+	name from `gmp_mpn_functions'.
+	* configure: Regenerate.
+
+	* acinclude.m4 (GMP_FINISH): Tell user what we're doing.
+	* aclocal.m4: Regenerate.
+
+2000-02-21  Kevin Ryde  <kevin@swox.se>
+
+	* gmp-impl.h: Rename __gmpn_mul_basecase to mpn_mul_basecase and
+	__gmpn_sqr_basecase to mpn_sqr_basecase, remove __gmpn prototypes.
+	* mpn/x86/mul_basecase.S: Ditto.
+	* mpn/x86/pentium/mul_basecase.S: Ditto.
+
+	* configure.in (gmp_m4postinc): Use x86-defs.m4 on athlon-*-* too.
+
+2000-02-20  Kevin Ryde  <kevin@swox.se>
+
+	* acinclude.m4 (GSYM_PREFIX): Drop $1, change by Linus.
+	* mpn/asm-defs.m4 (PROLOGUE,EPILOGUE): Use GSYM_PREFIX as a
+	string, change by Linus.
+	* mpn/x86/x86-defs.m4: Use GSYM_PREFIX as a string.
+
+	* mpn/x86/k6/gmp-mparam.h: New file.
+	* mpn/asm-defs.m4 (m4_warning): New macro.
+
+	* mpn/x86/README: Amendments per new code and directories.
+	* mpn/x86/README.family: New file.
+	* mpn/x86/k6/README: New file.
+	* mpn/x86/k7/README: New file.
+
+	* mpn/generic/mul_n.c: Rename __gmpn_mul_basecase to
+	mpn_mul_basecase and __gmpn_sqr_basecase to mpn_sqr_basecase.
+	* mpn/generic/mul_basecase.c: Ditto.
+	* mpn/generic/sqr_basecase.c: Ditto.
+	* mpn/generic/mul.c: Ditto.
+
+2000-02-19  Linus Nordberg  <linus@swox.se>
+
+	* configure.in: Don't try to symlink more than one multi-func
+	file.
+	* configure: Regenerate.
+
+2000-02-18  Linus Nordberg  <linus@swox.se>
+
+	* acinclude.m4 (GMP_CHECK_ASM_UNDERSCORE): GMP_DEFINE
+	`GSYM_PREFIX'.  Run ACTIONs even when value is found in cache.
+	(GMP_CHECK_ASM_ALIGN_LOG): GMP_DEFINE `ALIGN'.  Run ACTIONs even
+	when value is found in cache.
+	* aclocal.m4: Regenerate.
+
+	* configure.in: Don't define GSYM_PREFIX or ALIGN.
+	Add mechanism for multi-function files.
+	* configure: Regenerate.
+
+2000-02-18  Kevin Ryde  <kevin@swox.se>
+
+	* configure.in (gmp_m4postinc): Enable x86-defs.m4.
+	* mpn/x86/k7/mul_1.asm: Fix include.
+	* mpn/x86/k6/mul_basecase.S: Removed (copy of the pentium version).
+	* mpn/x86/k6/mul_basecase.asm: New file.
+	* mpn/x86/k6/sqr_basecase.asm: New file.
+	* mpn/x86/k6/com_n.asm: New file.
+	* mpn/x86/k6/copyi.asm: New file.
+	* gmp.texi (Low-level Functions): Clarify mpn overlaps permitted.
+	* gmp-impl.h (MPN_OVERLAP_P): New macro.
+	* gmp-impl.h (assert_nocarry): New macro.
+	* mpn/tests/ref.c: New file, based in part on other mpn/tests/*.c.
+	* mpn/tests/ref.h: New file.
+
+2000-02-17  Linus Nordberg  <linus@swox.se>
+
+	* Makefile.am (dist-hook): Don't include any emacs backup files
+	(*.~*) in dist.
+	* Makefile.in: Regenerate.
+
+2000-02-17  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/sparc32/v9/mul_1.asm: Use `rd' to get current PC; get rid of
+	getpc function.
+	* mpn/sparc32/v9/addmul_1.asm: Likewise.
+	* mpn/sparc32/v9/submul_1.asm: Likewise.
+
+2000-02-17  Kevin Ryde  <kevin@swox.se>
+
+	* gmp.h: Add prototypes and defines for mpn_and_n, mpn_andn_n,
+	mpn_com_n, mpn_copyd, mpn_copyi, mpn_ior_n, mpn_iorn_n,
+	mpn_mul_basecase, mpn_nand_n, mpn_nior_n, mpn_sqr_basecase,
+	mpn_xor_n, mpn_xorn_n.
+
+	* mpn/asm-defs.m4: Many additions making up initial version.
+	* mpn/asm-defs.m4 (L): Use defn(`LSYM_PREFIX').
+	* mpn/x86/x86-defs.m4: New file.
+	* mpn/x86/k6/aors_n.asm: New file.
+	* mpn/x86/k6/divmod_1.asm: New file.
+	* mpn/x86/k6/divrem_1.asm: New file.
+	* mpn/x86/k6/lshift.S: Removed (was a copy of the pentium version).
+	* mpn/x86/k6/lshift.asm: New file.
+	* mpn/x86/k6/mod_1.asm: New file.
+	* mpn/x86/k6/mul_1.S: Removed (was a copy of the pentium version).
+	* mpn/x86/k6/mul_1.asm: New file.
+	* mpn/x86/k6/rshift.S: Removed (was a copy of the pentium version).
+	* mpn/x86/k6/rshift.asm: New file.
+	* mpn/x86/k7/aors_n.asm: New file.
+	* mpn/x86/k7/aorsmul_1.asm: New file.
+	* mpn/x86/k7/mul_1.asm: New file.
+	* mpn/x86/k7/rshift.asm: New file.
+	* mpn/x86/p6/aorsmul_1.asm: New file.
+	* mpn/x86/copyi.asm: New file.
+	* mpn/x86/copyd.asm: New file.
+	* mpn/lisp/gmpasm-mode.el: New file.
+
+2000-02-16  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/sparc32/v9/mul_1.asm: Conditionalize for PIC.
+	* mpn/sparc32/v9/addmul_1.asm: Likewise.
+	* mpn/sparc32/v9/submul_1.asm: Likewise.
+	* mpn/sparc32/v8/supersparc/udiv.asm: Likewise.
+	* mpn/sparc32/udiv_fp.asm: Likewise.
+
+2000-02-16  Linus Nordberg  <linus@swox.se>
+
+	* configure.in: Add mechanism for including target specific
+	m4-files in config.m4.
+	* configure: Regenerate.
+
+	* acinclude.m4 (GMP_PROG_CCAS): Begin assembly lines (except
+	labels) with a tab character.  HP-UX demands it.
+	(GMP_CHECK_ASM_SIZE): Ditto.
+	(GMP_CHECK_ASM_LSYM_PREFIX): Ditto.
+	(GMP_CHECK_ASM_LABEL_SUFFIX): Set to empty string for HP-UX.
+	(GMP_CHECK_ASM_GLOBL): Change `.xport' --> `.export'.
+	* aclocal.m4: Regenerate.
+
+2000-02-16  Linus Nordberg  <linus@swox.se>
+
+	* acinclude.m4 (GMP_CHECK_ASM_LSYM_PREFIX): Define LSYM_PREFIX as
+	the prefix only, no argument.
+	* aclocal.m4: Regenerate.
+	* configure: Regenerate.
+
+	* mpn/asm-defs.m4 (L): No argument to LSYM_PREFIX.
+
+2000-02-15  Linus Nordberg  <linus@swox.se>
+
+	* acinclude.m4: Prefix all temporary shell variables with
+	`gmp_tmp_'.
+	(GMP_PROG_CC_FIND): Use defaults if no arguments are passed.
+	Quote use of arguments.
+	(GMP_PROG_CCAS): New macro.
+	(GMP_INIT): New macro.
+	(GMP_FINISH): New macro.
+	(GMP_INCLUDE): New macro.
+	(GMP_SINCLUDE): New macro.
+	(GMP_DEFINE): New macro.
+	(GMP_CHECK_ASM_LABEL_SUFFIX): New macro.
+	(GMP_CHECK_ASM_TEXT): New macro.
+	(GMP_CHECK_ASM_DATA): New macro.
+	(GMP_CHECK_ASM_GLOBL): New macro.
+	(GMP_CHECK_ASM_TYPE): New macro.
+	(GMP_CHECK_ASM_SIZE): New macro.
+	(GMP_CHECK_ASM_LSYM_PREFIX): New macro.
+	(GMP_CHECK_ASM_W32): New macro.
+	* aclocal.m4: Regenerate.
+
+	* configure.in: Find m4 and nm for target.
+	Use new macros to create config.m4.
+	Prefix all temporary shell variables with `tmp_'.
+	Pass `-X 64' to nm for 64-bit PPC target with 64-bit compiler.
+	* configure: Regenerate.
+
+	* Makefile.am (dist-hook): *Really* remove all CVS dirs in
+	dist.
+	* Makefile.in: Regenerate.
+
+	* mpn/Makefile.am: Add target for building .lo and .o from
+	.asm.
+	Pass -DPIC to preprocessor (CPP/m4) when building .lo.
+	Build .o a second time for target .lo, without -DPIC to
+	preprocessor.
+	(SUFFIX): Add `.asm'.
+	(EXTRA_DIST): Add asm-defs.m4.
+	* mpn/Makefile.in: Regenerate.
+
+	* mpf/Makefile.in: Regenerate.
+	* mpf/tests/Makefile.in: Regenerate.
+	* mpq/Makefile.in: Regenerate.
+	* mpq/tests/Makefile.in: Regenerate.
+	* mpz/Makefile.in: Regenerate.
+	* mpz/tests/Makefile.in: Regenerate.
+
+2000-02-15  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/sparc32/udiv_fp.asm: Change `RODATA' to `DATA'.
+	* mpn/sparc32/v8/supersparc/udiv.asm: Likewise.
+	* mpn/sparc32/v9/addmul_1.asm: Likewise.
+	* mpn/sparc32/v9/submul_1.asm: Likewise.
+	* mpn/sparc32/v9/mul_1.asm: Likewise.
+
+	* mpn/sparc32/add_n.asm: Rename `size' -> `n'.
+	* mpn/sparc32/sub_n.asm: Likewise.
+
+	* sparc32: Rename `.s' and `.S' files to `.asm'.
+	* sparc64: Rename `.s' and `.S' files to `.asm'.
+
+2000-02-11  Torbjorn Granlund  <tege@swox.com>
+
+	* config.sub: Adopt to new config.guess sparc naming conventions.
+
+	* config.guess (sun4u:SunOS:5.*:*): Change `sparc9' to `sparcv9'.
+	* config.guess (sun4m:SunOS:5.*:*): Change to sun4[md]:SunOS:5.*:* and
+	change `sparc8' to `sparcv8'.
+
+	* mpn/x86/add_n.S: Use PROLOGUE/EPILOGUE.
+	* mpn/x86/sub_n.S: Likewise.
+
+	* mpn/x86/syntax.h (PROLOGUE): New name for PROLOG.
+	* mpn/x86/syntax.h (EPILOGUE): New name for EPILOG.
+
+2000-02-11  Linus Nordberg  <linus@swox.se>
+
+	* configure.in: Better path for 64-bit sparc without 64-bit cc.
+	Change sparc8 --> sparcv8.
+	Change sparc9 --> sparcv9.
+	* configure: Regenerate.
+
+2000-02-10  Linus Nordberg  <linus@swox.se>
+
+	* configure.in: Use Autoconf.
+	* Makefile.am: New file.
+
+	* AUTHORS: New file.
+	* COPYING: New file.
+	* acinclude.m4: New file.
+	* acconfig.h: New file.
+
+	* configure: Generate.
+	* Makefile.in: Generate.
+	* aclocal.m4: Generate.
+	* config.in: Generate.
+
+	* install.sh: Remove.
+	* install-sh: New file from Automake.
+	* missing: New file from Automake.
+	* ltconfig: New file from Libtool.
+	* ltmain.sh: New file from Libtool.
+
+	* mpf/Makefile.am: New file.
+	* mpf/Makefile.in: Generate.
+	* mpf/configure.in: Remove.
+	* mpf/tests/Makefile.am: New file.
+	* mpf/tests/Makefile.in: Generate.
+	* mpf/tests/configure.in: Remove.
+
+	* mpn/Makefile.am: New file.
+	* mpn/Makefile.in: Generate.
+	* mpn/configure.in: Remove.
+
+	* mpq/Makefile.am: New file.
+	* mpq/Makefile.in: Generate.
+	* mpq/configure.in: Remove.
+	* mpq/tests/Makefile.am: New file.
+	* mpq/tests/Makefile.in: Generate.
+	* mpq/tests/configure.in: Remove.
+
+	* mpz/Makefile.am: New file.
+	* mpz/Makefile.in: Generate.
+	* mpz/configure.in: Remove.
+	* mpz/tests/Makefile.am: New file.
+	* mpz/tests/Makefile.in: Generate.
+	* mpz/tests/configure.in: Remove.
+
+2000-02-10  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/x86/add_n.S: Don't use label L0 twice.
+	* mpn/x86/sub_n.S: Likewise.
+
+2000-01-20  Linus Nordberg  <linus@swox.se>
+
+	* demos/pexpr.c: Don't use setup_error_handler() in windoze.
+
+2000-01-19  Torbjorn Granlund  <tege@swox.com>
+
+	* demos/pexpr.c (sigaltstack): #define to sigstack for AIX.
+	(setup_error_handler): Don't write to ss_size and ss_flags
+	on AIX.
+
+2000-01-11  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/configure.in (hppa2.0*-*-*): Move assignment of
+	target_makefile_frag to where it belongs.
+
+1999-12-21  Torbjorn Granlund  <tege@swox.com>
+
+	* longlong.h (v9 umul_ppmm): New #define.
+	(v9 udiv_qrnnd): New #define.
+
+1999-12-14  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/divmod_1.c: Use invert_limb.
+	* mpn/generic/mod_1.c: Use invert_limb.
+
+	* gmp-impl.h (invert_limb): Put definition here.
+	* mpn/generic/divrem.c (invert_limb): Delete definition.
+	* mpn/generic/divrem_2.c (invert_limb): Delete definition.
+
+	* gmp.h (mpn_divrem): Inhibit for non-gcc.
+	But declare (undo 1999-11-22 change).
+
+	* gmp-impl.h (DItype,UDItype): Do these also if _LONG_LONG_LIMB.
+
+	* longlong.h: Move 64-bit hppa code out of __GNUC__ conditional.
+
+	* stack-alloc.c (HSIZ): New #define.
+	(__tmp_alloc): Use HSIZ instead of sizeof(tmp_stack).
+
+1999-12-10  Torbjorn Granlund  <tege@swox.com>
+
+	* config.sub: Clean up handling of x86 CPUs: Properly recognize
+	Amd CPUs as unique entities.  Use manufacturer's names of
+	processors ("pentium", etc); still match ambiguous names like
+	"i586", "i686", "p6" but be conservative in interpreting them.
+
+	* configure.in: Recognize x86 CPU types known by config.guess.
+	* mpn/configure.in: Likewise.  Add x86/mmx path component as
+	appropriate.
+	(athlon-*-*): Fix typo.
+
+	* config.guess: Update x86 recog code to initially match
+	more than just i386.
+	Call K6-2 and K6-III for "k62" and "k63" respectively.
+
+	* config.guess: Recognize x86 CPU types.
+	Update code for FreeBSD, NetBSD, OpenBSD, Linux.
+
+1999-12-08  Torbjorn Granlund  <tege@swox.com>
+
+	* mpf/pow_ui.c: Avoid final squaring in loop.
+
+1999-12-07  Torbjorn Granlund  <tege@swox.com>
+
+	* gmp-impl.h (udiv_qrnnd_preinv2gen): Prefix local variables with `_'.
+	(udiv_qrnnd_preinv2norm): Likewise.
+	From Kevin Ryde:
+	(HAVE_ALLOCA): #define also if defined (alloca).
+
+1999-12-04  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/tests/add_n.c: Set OPS from CLOCK.
+	* mpn/tests/sub_n.c: Likewise.
+	* mpn/tests/mul_1.c: Likewise.
+	* mpn/tests/addmul_1.c: Likewise.
+	* mpn/tests/submul_1.c: Likewise.
+
+	* mpn/tests/lshift.c: Update from add_n.c.
+	* mpn/tests/rshift.c: Likewise.
+
+1999-12-03  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/powerpc64/copy.S: New file.
+
+1999-12-02  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/sparc64/copy.s: New file.
+
+	* mpn/tests/copy.c: New file.
+
+	* mpn/configure.in: Recognize more Amd CPUs; Set special paths for
+	k7 CPU.
+
+	* configure.in: Recognize Amd x86 CPUs.
+
+	* mpz/fdiv_r_2exp.c: In rounding code, read in->_mp_size before
+	writing to res->_mp_size.
+
+	* mpn/powerpc64/*.S: Clean up assembly syntax, add function headers.
+	* mpn/powerpc64/gmp-mparam.h: (KARATSUBA_MUL_THRESHOLD): #define.
+	(KARATSUBA_SQR_THRESHOLD): #define.
+
+	* mpn/tests/add_n.c (main): Only print test number if TIMES==1
+	and not printing.
+	(main): Don't run reference code if NOCHECK.
+	* mpn/tests/sub_n.c: Likewise.
+	* mpn/tests/mul_1.c: Likewise.
+	* mpn/tests/addmul_1.c: Likewise.
+	* mpn/tests/submul_1.c: Likewise.
+
+	* mpn/tests/lshift.c: (main): Only print test number if TIMES==1
+	and not printing.
+	* mpn/tests/rshift.c: Likewise.
+
+1999-11-22  Torbjorn Granlund  <tege@swox.com>
+
+	* gmp.h (mpz_init_set_str): Declare using __gmp_const.
+	(mpz_set_str): Likewise.
+	(mpf_init_set_str): Likewise.
+	(mpf_set_str): Likewise.
+	(mpn_set_str): Likewise.
+	(__gmp_0): Likewise.
+	(mpn_divrem): Remove separate declaration; it's defined later in
+	this file.
+
+	* gmp.h: Replace "defined (__STD__)' by (__STDC__-0) in
+	expressions involving more than one term, to handle Sun's compiler
+	that most helpfully sets __STDC__ to 0.
+	* gmp-impl.h: Likewise.
+	* longlong.h: Likewise.
+
+1999-11-21  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/sparc64/gmp-mparam.h (KARATSUBA_MUL_THRESHOLD): #define.
+	(KARATSUBA_SQR_THRESHOLD): #define.
+
+	* mpn/sparc64/lshift.s: Compensate stack references for odd stack ptr.
+	* mpn/sparc64/rshift.s: Likewise.
+
+	* mpn/sparc64/addmul_1.s: Propagate carry properly.
+	* mpn/sparc64/submul_1.s: Likewise.
+
+	* mpn/sparc64/sub_n.s: Rewrite.
+
+	* mpn/sparc64/sub_n.s: Get operand order for main subcc right
+	(before scrapping this code for new code).
+
+1999-11-20  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/sparc64/add_n.s: Rewrite.
+
+1999-11-17  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/x86/syntax.h (PROLOG): New #define.
+	(EPILOG): New #define.
+
+	* gmp.h (mpn_addsub_n): Declare.
+	* gmp.h (mpn_add_nc): Declare.
+	* gmp.h (mpn_sub_nc): Declare.
+	* mpn/powerpc64/addsub_n.S: New file.
+
+1999-11-17  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/alpha/gmp-mparam.h
+	(KARATSUBA_MUL_THRESHOLD): Only #define #ifndef.
+	(KARATSUBA_SQR_THRESHOLD): Likewise.
+
+1999-11-14  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/x86/mul_1.S: Unroll and optimize for P6 and K7.
+
+1999-11-09  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/x86/p6/gmp-mparam.h
+	(KARATSUBA_MUL_THRESHOLD): Only #define #ifndef.
+	(KARATSUBA_SQR_THRESHOLD): Likewise.
+
+1999-11-05  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/addsub_n.c: New file.
+
+1999-11-02  Torbjorn Granlund  <tege@swox.com>
+
+	* config.guess: Handle alpha:FreeBSD with alpha:NetBSD.
+
+	* configure.in (vax*-*-*): New case.
+	* config/mt-vax: New file.
+	* mpn/vax/add_n.s: Rewrite.
+	* mpn/vax/sub_n.s: Rewrite.
+
+1999-10-31  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/vax/rshift.s: New file.
+	* mpn/vax/lshift.s: New file.
+
+1999-10-29  Torbjorn Granlund  <tege@swox.com>
+
+	* config.sub: Handle k5 and k6.
+	* mpn/configure.in: Recognize k6.
+
+	* mpf/tests/t-get_d.c (LOW_BOUND, HIGH_BOUND): New #defines.
+	(main): Tighten error bounds to 14 digits.
+
+	* longlong.h (default umul_ppmm, when smul_ppmm exists):
+	Rename __m0 => __xm0, __m1 => __xm1.
+	(default smul_ppmm): Likewise.
+
+1999-10-11  Torbjorn Granlund  <tege@swox.com>
+
+	* config.guess: Reverse the test for POWER vs PowerPC.
+	* config.guess (sun4m:SunOS:5.*:*): New case.
+	* config.guess (sun4u:SunOS:5.*:*): New case.
+
+1999-09-29  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/divrem_2.c: Clean up comments.
+
+1999-09-23  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/tests/Makefile.in: Use move-if-change when generating binaries.
+	* mpf/tests/Makefile.in: Likewise.
+	* mpq/tests/Makefile.in: Likewise.
+	* mpz/tests/move-if-change: New file.
+	* mpf/tests/move-if-change: New file.
+	* mpq/tests/move-if-change: New file.
+
+	* gmp.h (mpn_incr_u): New macro (from mpn/generic/mul_n.c).
+	(mpn_decr_u): New macro.
+
+	* mpn/generic/mul_n.c (mpn_incr): Delete.
+	* mpn/generic/mul_n.c: Update usages mpn_incr => mpn_incr_u.
+	* mpn/generic/divrem_newt.c: Use mpn_incr_u and mpn_decr_u instead of
+	mpn_add_1 and mpn_sub_1.
+	* mpn/generic/sqrtrem.c: Likewise.
+	* mpz/cdiv_q_ui.c: Likewise.
+	* mpz/cdiv_qr_ui.c: Likewise.
+	* mpz/fdiv_q_ui.c: Likewise.
+	* mpz/fdiv_qr_ui.c: Likewise.
+
+	* mpn/generic/sqrtrem.c: Start single-limb Newton iteration from 18
+	bits.
+
+1999-07-27  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/divrem_1.c (__gmpn_divrem_1n): New function.
+
+	* mpn/generic/divrem_2.c: New file, code from divrem.c, `case 2:'.
+	* mpn/Makefile.in: Compile divrem_2.c.
+	* make.bat: Compile divrem_2.c.
+	* mpn/configure.in (functions): Add divrem_2.
+	* gmp.h: Declare mpn_divrem_2.
+
+	* mpn/generic/divrem.c: Delete special cases, handle just divisors
+	of more than 2 limbs.
+	* gmp.h (mpn_divrem): Call mpn_divrem_1, mpn_divrem_2, as appropriate.
+
+	* mpn/generic/divrem.c: Rework variable usage for better register
+	allocation.
+
+1999-07-26  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/alpha/ev5/add_n.s: Rewrite for better ev6 speed.
+	* mpn/alpha/ev5/sub_n.s: Likewise.
+
+1999-07-21  Torbjorn Granlund  <tege@swox.com>
+
+	* longlong.h (alpha): Define umul_ppmm for cc.
+
+	* gmp-impl.h (DItype, UDItype): Define for non-gcc if _LONGLONG is
+	defined.
+
+1999-07-15  Torbjorn Granlund  <tege@swox.com>
+
+	* longlong.h (powerpc64 count_leading_zeros): Fix typo.
+	(powerpc64 add_ssaaaa): Fix typos.
+	(powerpc64 sub_ddmmss): Fix typos.
+
+1999-07-14  Torbjorn Granlund  <tege@swox.com>
+
+	* mpz/tests/Makefile.in: Pass XCFLAGS when linking.
+	* mpf/tests/Makefile.in: Likewise.
+	* mpq/tests/Makefile.in: Likewise.
+	* mpn/Makefile.in (.S.o): Pass XCFLAGS.
+
+	* longlong.h: Add support for 64-bit PowerPC.
+	* config.sub: Handle "powerpc64".
+	* configure.in: Likewise.
+	* mpn/configure.in: Suppress use of config/t-ppc-aix for now,
+	it seems compiler passes proper options.
+	* mpn/powerpc64/*.S: New files.
+
+	* Makefile.in (FLAGS_TO_PASS): Pass "AR=$(AR)".
+
+1999-07-07  Torbjorn Granlund  <tege@swox.com>
+
+	* demos/pexpr.c (factor): Change alloca call to a malloc/free pair.
+
+	* mpn/powerpc32/syntax.h: Add #define's for crN.
+
+	* gmp.h (gmp_rand_algorithm): Remove spurious `,'.
+
+1999-07-05  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/generic/divrem_1.c: Normalize divisor when needed.
+
+1999-07-02  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/configure.in (powerpc*-apple-mach): New configuration.
+	* mpn/powerpc32/*: Add support for apple-macho syntax.
+	* mpn/powerpc32/syntax.h: New file.
+	* gmp-impl.h: Don't use `__attribute__' syntax for Apple's perversion
+	of GCC.
+
+1999-05-26  Linus Nordberg  <linus@swox.se>
+
+	* rand.c (gmp_rand_init): Fix typo.
+
+	* mpn/generic/rawrandom.c (mpn_rawrandom): Count bits, not limbs,
+	to keep track of how many rounds to do in loop.  Clean up
+	temporary allocation.  Update `seedsize' inside loop.  Mask off
+	the correct number of bits from final result.  Init `mcopyp' even
+	when not normalizing `m'.
+
+	* randlc.c (gmp_rand_init_lc): Fix typo (don't call
+	mpz_init_set_ui()).
+
+	* mpn/generic/rawrandom.c (mpn_rawrandom): Set SIZ(s->seed) when
+	reallocating.
+
+	* tests/rand/Makefile (test, bigtest): Add 33-bit tests.
+
+	* tests/rand/gen.c (main): Set precision of variable passed to
+	mpf_urandomb().  Add option `-p'.
+
+1999-05-25  Linus Nordberg  <linus@swox.se>
+
+	* randcm.c: Remove.
+	* randcmui.c: Remove.
+	* Makefile.in: Remove randcm and randcmui.
+	* make.bat: Ditto.
+	* gmp-impl.h: Remove prototypes for __gmp_rand_init_common() and
+	__gmp_rand_init_common_ui().
+	* randlc.c (gmp_rand_init_lc): Don't call
+	__gmp_rand_init_common().
+
+	* randlcui.c (gmp_rand_init_lc_ui): Don't call
+	__gmp_rand_init_common_ui().
+
+	* gmp.h (__gmp_rand_state_struct): Remove unused member `maxval'.
+	* randclr.c (gmp_rand_clear): Remove reference to s->maxval.
+	* randcm.c (__gmp_rand_init_common): Ditto
+
+	* mpn/generic/rawrandom.c (mpn_rawrandom): Don't calculate nlimbs
+	twice.
+
+	* gmp.h (__gmp_rand_dist): Remove.
+
+1999-05-24  Linus Nordberg  <linus@swox.se>
+
+	* mpn/generic/rawrandom.c: Clean up comments.
+
+	* gmp.texi: Add documentation for random number generation.
+
+1999-05-21  Linus Nordberg  <linus@swox.se>
+
+	* gmp.h: Typedef `gmp_rand_state' as an array with one element.
+	Change prototypes accordingly.
+	* gmp-impl.h: Change prototypes using `gmp_rand_state'.
+	* rand.c (gmp_rand_init): Take `gmp_rand_state' as argument
+	instead of a pointer to a `gmp_rand_state'.
+	* mpf/urandom.c (mpf_urandomb): Ditto.
+	* mpz/urandom.c (mpz_urandomb): Ditto.
+	* mpn/generic/rawrandom.c (mpn_rawrandom): Ditto.
+	* randcmui.c (__gmp_rand_init_common_ui): Ditto.
+	* randlc.c (gmp_rand_init_lc): Ditto.
+	* randlcui.c (gmp_rand_init_lc_ui): Ditto.
+	* randui.c (gmp_rand_init_ui): Ditto.
+	* randcm.c (__gmp_rand_init_common): Ditto.
+	* randclr.c (gmp_rand_clear): Ditto.
+
+	* tests/rand/gen.c (main): Pass `s' to rand-funcs instead of address
+	of `s'.
+
+1999-05-20  Linus Nordberg  <linus@swox.se>
+
+	* Makefile.in: Rename randi.c --> rand.c, randi_lc.c --> randlc.c,
+	randicom.c --> randcm.c.  Add randui.c, randcmui.c, randlcui.c.
+	* make.bat: Ditto.
+
+	* gmp.h: Add prototypes for gmp_rand_init_ui() and
+	gmp_rand_init_lc_ui().
+	* gmp-impl.h: Add prototypes for __gmp_rand_init_common() and
+	__gmp_rand_init_common_ui().
+
+	* randlc.c, randcm.c, randclr.c, rand.c: Change #include of
+	<gmp.h> to "gmp.h".
+	* randclr.c: Include stdlib.h for free().
+	* rand.c: Include gmp-impl.h.
+
+1999-05-12  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/configure.in: Put generic m68k alternative last.
+
+1999-05-04  Torbjorn Granlund  <tege@swox.com>
+
+	* demos/pexpr.c (setup_error_handler): Use sigemptyset to create
+	empty set (for portability).
+	(fns): Fix typo '#if #if'.
+	(mpz_eval_expr): Implement FERMAT and MERSENNE.
+
+	* demos/pexpr.c: Cast longjmp argument via long to silent warnings on
+	64-bit hosts.
+
+1999-05-03  Torbjorn Granlund  <tege@swox.com>
+
+	* demos/pexpr.c: Add #defines for GMP 1.x and 2.0 compatibility.
+
+	* demos/pexpr.c (setup_error_handler): New function; take signal
+	handler setup code from main(), with major modifications to use modern
+	signal interface.
+	(main): Remove signal handler setup code; call setup_error_handler.
+
+1999-04-29  Linus Nordberg  <linus@swox.se>
+
+	* tests/rand/findcl.c (main): Add option '-i' for interval factor.
+	Separate v and merit lose figures.  Add '-v' for version.
+
+1999-04-28  Linus Nordberg  <linus@swox.se>
+
+	* tests/rand/statlib.c: Change debugging stuff.
+
+	* tests/rand/gmpstat.h: Add debug values definitions.
+
+	* tests/rand/findcl.c (main): Print low and high merit on startup.
+	Print version string on startup.  Catch SEGV and HUP.  Add option -d
+	for debug.  Fix bug making test for v too hard.
+	(sh_status): New function.
+	(sh_status): Flush stdout.  Add RCSID.
+
+1999-04-27  Linus Nordberg  <linus@swox.se>
+
+	* tests/rand/Makefile (clean): Add target.
+
+1999-04-27  Linus Nordberg  <linus.nordberg@canit.se>
+
+	* tests/rand/stat.c: Include gmpstat.h.
+	Add global int g_debug.
+
+	* tests/rand/spect.c: Include <unistd.h>.
+
+	* tests/rand/findcl.c (main): Input is `m', not all factors of `m'.
+	Print only the very first matching multiplier.  Include <unistd.h>.
+	Flush stdout.  Print "done." when done.
+
+	* tests/rand/spect.c: Move everything but main() to statlib.c.
+
+	* tests/rand/findcl.c: New file.
+
+	* tests/rand/gmpstat.h: New file.
+
+	* tests/rand/statlib.c (merit, merit_u, f_floor, vz_dot,
+	spectral_test): New functions.
+
+1999-04-27  Torbjorn Granlund  <tege@swox.com>
+
+	* mpn/configure.in: Fix typo, "sparc-*)" was "sparc)".
+
+1999-04-21  Torbjorn Granlund  <tege@swox.com>
+
+	* config.sub: Recognize ev6.
+
+1999-04-12  Linus Nordberg  <linus.nordberg@canit.se>
+
+	* urandom.c: Split up into randclr.c, randi.c, randi_lc.c,
+	randicom.c.
+	* randclr.c, randi.c, randi_lc.c, randicom.c: New files.
+	* Makefile.in: Remove urandom.  Add randclr, randi, randi_lc,
+	randicom.
+	* make.bat: Ditto
+
+1999-03-31  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* configure.in (sparc9-*-solaris2.[789]*, etc): New alternative.
+	* mpn/configure.in: Use mt-sprc9 also for ultrasparc*-*-solaris2*.
+
+1999-03-30  Linus Nordberg  <linus.nordberg@canit.se>
+
+	* urandom.c (__gmp_rand_scheme): Change NULL->0.
+	Include "gmp.h" instead of <gmp.h>.
+
+1999-03-29  Linus Nordberg  <linus.nordberg@canit.se>
+
+	* gmp.h (__gmp_rand_data_lc): Now holds a, c, m instead of scheme
+	struct.
+	(__gmp_rand_lc_scheme_struct): Remove mpz_t's `a' and `m'.
+
+	* tests/rand/stat.c (f_freq): Don't print 2nd level results if doing
+	1st level.
+
+	* tests/rand/gen.c (main): Set default algorithm to mpz_urandomb.
+	(main): Add option -c.
+
+1999-03-24  Linus Nordberg  <linus.nordberg@canit.se>
+
+	* tests/rand/Makefile (GMPINC): Rename to GMPH.
+	(GMPH): Add gmp-mparam.h.
+	(CFLAGS): Add -I$(GMPLIBDIR)/mpn
+
+1999-03-23  Linus Nordberg  <linus.nordberg@canit.se>
+
+	* Makefile.in: Compile top-dir/urandom.c.
+	* make.bat: Ditto.
+
+	* mpn/Makefile.in: Compile rawrandom.c.
+	* make.bat: Ditto.
+
+	* mpn/configure.in (functions): Add rawrandom.
+
+	* gmp.h (__gmp_rand_scheme_struct): Rename to
+	__gmp_rand_lc_scheme_struct.
+	(__gmp_rand_data_lc): Remove member 'n'.  Allocate a
+	__gmp_rand_lc_scheme_struct instead of a pointer to one.
+	Add prototype for gmp_rand_init_lc(), mpn_rawrandom().
+	New prototype for mpz_urandomb().
+
+	* urandom.c: New file.
+	(__gmp_rand_init_common): New function.
+	(gmp_rand_init_lc): New function.
+	(gmp_rand_init): Don't init data_lc->n.  Call gmp_rand_init_lc()
+	and __gmp_rand_init_common().
+	(gmp_rand_clear): Remove reference to data_lc->n.
+
+	* mpz/urandom.c (gmp_rand_init, gmp_rand_clear): Move to new file
+	urandom.c in top-dir.
+	(mpz_urandomb): Add function parameter nbits.  Call mpn_rawrandom().
+
+	* mpf/urandom.c (mpf_urandomb): Call mpn_rawrandom().
+
+	* mpn/generic/rawrandom.c: New file.
+	(mpn_rawrandom): New function.
+
+1999-03-17  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* extract-dbl.c: When packing result, adjust exp when sc == 0.
+
+	* mpf/tests/t-get_d.c: New file.
+	* mpf/tests/Makefile.in: Compile t-get_d.c.
+
+1999-03-16  Linus Nordberg  <linus.nordberg@canit.se>
+
+	* mpz/urandom.c (__gmp_rand_scheme): Add extra braces around the
+	mpz_t members.
+
+	* make.bat: Compile mpz/urandom.c and mpf/urandom.c
+
+	* tests/rand/statlib.c (ks_table): Use mpf_pow_ui() and exp().
+
+	* tests/rand/gen.c: Include unistd.h for getopt.
+
+1999-03-15  Linus Nordberg  <linus.nordberg@canit.se>
+
+	* mpz/urandom.c (gmp_rand_init): New function.
+	(gmp_rand_clear): New function.
+	(mpz_urandomb): New function.
+
+	* mpz/Makefile.in: Compile urandom.c
+
+	* mpf/urandom.c (mpf_urandomb): New function.
+
+	* mpf/Makefile.in: Compile urandom.c.
+
+	* gmp.h (__gmp_rand_state_struct, __gmp_rand_scheme_struct): New
+	structs for randomization functions.
+	(gmp_rand_dist, gmp_rand_alogrithm): New enums for randomization
+	functions.
+	(mpz_urandomb, mpf_urandomb): Add prototype.
+	(gmp_rand_init, gmp_rand_clear): Add prototype.
+
+	* tests/rand/gen.c, stat.c, statlib.c, statlib.h: New files.
+	* tests/rand/Makefile, tests/rand/ChangeLog: New files.
+
+1999-03-15  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* .gdbinit: New file.
+
+	* mpz/dump.c: New file.
+	* mpz/Makefile.in: Compile dump.c.
+	* make.bat: Likewise.
+	* gmp.h (mpz_dump): Declare.
+
+1999-03-14  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpz/tests/reuse.c: Also test mpz_invert and mpz_divexact.
+
+	* mpz/tests/convert.c: Update to GMP 2 variable syntax.
+
+1999-03-13  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpf/README: New file.
+	* mpz/README: New file.
+
+	* mpf/pow_ui.c: New file.
+	* mpf/Makefile.in: Compile pow_ui.c.
+	* make.bat: Likewise.
+	* gmp.h (mpf_pow_ui): Declare.
+
+1999-03-12  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpn/configure.in: Stage 1 of rewrite.
+	* mpn/underscore.h: New name for bsd.h.
+	* mpn/sysv.h: Deleted.
+
+	* mpn/m68k/*: Don't include sysdep.h.
+
+	* mpn/pa64/README: New file.
+
+1999-03-11  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpn/powerpc32/add_n.S: Add support for both AIX and ELF syntax.
+	Renamed from `.s'.
+	* mpn/powerpc32/sub_n.S: Likewise.
+	* mpn/powerpc32/lshift.S: Likewise.
+	* mpn/powerpc32/rshift.S: Likewise.
+	* mpn/powerpc32/mul_1.S: Likewise.
+	* mpn/powerpc32/addmul_1.S: Likewise.
+	* mpn/powerpc32/submul_1.S: Likewise.
+
+	* mpn/powerpc32/umul.S: New file.
+	* mpn/sparc32/v8/umul.S: New file.
+	* mpn/sparc32/umul.S: New file.
+	* mpn/x86/umul.S: New file.
+	* mpn/x86/udiv.S: New file.
+
+	* mpn/Makefile.in (mul_basecase.o): Delete rule.
+
+1999-02-22  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* configure.in (hppa2.0*-*-*): Force use of GCC.
+
+	* extract-dbl.c: Handle IEEE denormalized numbrs.  Clean up.
+
+1998-12-02  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpn/Makefile.in (CCAS): New macro.
+	(.s.o): Use CCAS.
+	(.S.o): Likewise.
+
+	* mpn/Makefile.in (mul_basecase.o): Add dependency.
+	(sqr_basecase.o): Likewise.
+	(mod_1.o): Likewise.
+
+	* demos/pexpr.c (cputime): Test also __hpux.
+	(cleanup_and_exit): Check SIGXCPU only #ifdef LIMIT_RESOURCE_USAGE.
+
+	* mpz/tests/t-2exp.c: Use urandom, not random.
+
+	* mpn/configure.in (arm*-*-*): New alternative.
+
+1998-11-30  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* gmp-impl.h (union ieee_double_extract): Special case for
+	little-endian arm.
+	(LIMBS): Alias for PTR.
+
+1998-11-26  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* longlong.h (m68000 umul_ppmm): Use `muluw', not `mulu'.
+	(m68k stuff): Clean up; add coldfire support.
+
+1998-11-23  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpn/mips3/gmp-mparam.h (KARATSUBA_MUL_THRESHOLD): #define.
+	(KARATSUBA_SQR_THRESHOLD): #define.
+
+	* mpn/sparc32/v9/README: New file.
+
+1998-11-20  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpn/x86/README: New file.
+
+	* mpn/arm/gmp-mparam.h: New file.
+	* mpn/pa64/gmp-mparam.h: New file.
+	* mpn/hppa/gmp-mparam.h: New file.
+	* mpn/x86/pentium/gmp-mparam.h: New file.
+	* mpn/sparc32/v9/gmp-mparam.h: New file.
+	* mpn/powerpc32/gmp-mparam.h: New file.
+	* mpn/x86/p6/gmp-mparam.h: New file.
+
+	* mpn/alpha/gmp-mparam.h (KARATSUBA_MUL_THRESHOLD): #define.
+	(KARATSUBA_SQR_THRESHOLD): #define.
+
+	* mpn/configure.in: Point to x86/p6 when appropriate.
+
+	* mpn/power/umul.s: New file.
+	* mpn/power/sdiv.s: New file.
+	* mpn/pa64/addmul_1.S: New file.
+	* mpn/pa64/submul_1.S: New file.
+	* mpn/pa64/mul_1.S: New file.
+	* mpn/pa64/udiv_qrnnd.c: New file.
+	* mpn/pa64/umul_ppmm.S: New file.
+	* mpn/mips2/umul.s: New file.
+	* mpn/m68k/mc68020/umul.s: New file.
+	* mpn/m68k/mc68020/udiv.s: New file.
+	* mpn/hppa/hppa1_1/umul.s: New file.
+	* mpn/alpha/umul.s: New file.
+	* mpn/a29k/udiv.s: New file.
+	* mpn/a29k/umul.s: New file.
+
+1998-11-17  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpn/x86/mul_basecase.S: New file for non-pentiums.
+	* mpn/x86/mul_basecase.S: Move to mpn/x86/pentium.
+
+1998-11-16  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* make.bat: Compile mul_basecase.c and sqr_basecase.c.
+
+1998-11-10  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpz/invert.c: Defer writing to parameter `invert' until
+	end.
+
+1998-11-03  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpn/pa64/udiv_qrnnd.c: Handle more border cases.
+
+1998-10-29  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* insert-dbl.c: Special case biased exponents < 1; Get boundary for
+	Inf right.
+
+	* longlong.h (COUNT_LEADING_ZEROS_NEED_CLZ_TAB): New #define.
+
+1998-10-28  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpn/powerpc32/submul_1.s: Rewrite, optimizing for PPC604.
+	* mpn/powerpc32/addmul_1.s: Likewise.
+	* mpn/powerpc32/lshift.s: Likewise.
+
+1998-10-23  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* config/mt-sprc9-gcc (XCFLAGS): Add -Wa,-xarch=v8plus.
+
+	* mpn/sparc32/v9/submul_1.s: New file.
+
+1998-10-21  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpn/config/mt-pa2hpux: New file.
+	* mpn/configure.in (hppa2.0*-*-*): Use new 64-bit code.
+
+	* config.sub: Recognize hppa2.0 as CPU type.
+
+	* longlong.h (64-bit hppa): Add umul_ppmm and udiv_qrnnd.
+	* mpn/pa64/mul_1.S: New file.
+	* mpn/pa64/addmul_1.S: New file.
+	* mpn/pa64/submul_1.S: New file.
+	* mpn/pa64/umul_ppmm.S: New file.
+	* mpn/pa64/udiv_qrnnd.c: New file.
+
+1998-10-20  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpz/pprime_p.c: Pass 1L, not 1, to mpz_cmp_ui.
+
+	* mpz/fdiv_q_2exp.c: Cast `long' argument to `mp_limb_t' for mpn calls.
+	* mpz/gcd_ui.c: Likewise.
+	* mpz/add_ui.c: Likewise.
+	* mpz/sub_ui.c: Likewise.
+
+1998-10-19  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpn/generic/bdivmod.c: Avoid using switch statement with mp_limb_t
+	index.
+
+1998-10-17  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpn/sparc32/v9/mul_1.s: Misc cleanups.
+	* mpn/sparc32/v9/addmul_1.s: Misc cleanups.
+
+1998-10-16  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpn/tests/{add,sub,}mul_1.c: Print xlimb using mpn_print.
+
+	* mpz/tests/t-powm.c (SIZE): Increase to 50.
+	(EXP_SIZE): New parameter; use it for computing exp_size.
+
+1998-10-15  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpn/generic/divrem_newt.c: Use TMP_ALLOC interface.
+
+	* mpn/generic/sqrtrem.c: Check BITS_PER_MP_LIMB before defining
+	assembly variants of SQRT.
+
+1998-10-14  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpn/tests: Clean up timing routines.  Don't include longlong.h
+	where it is not needed.
+	(mpn_print): Handle printing when _LONG_LONG_LIMB.
+	* mpn/tests/{add,sub,}mul_1.c: Generate xlimb with mpn_random2
+	and do it whether TIMES != 1 or not.
+
+	* mpn/generic/mul_n.c: Delay assignment of `sign' for lower
+	register pressure.
+
+	* mpn/sparc32/v9/mul_1.s: New file.
+
+	* config/mt-sprc9-gcc: New file.
+	* configure.in: Use it.
+
+	* mpn/configure.in: Use sparc64 for Solaris 2.7 and later with a
+	sparc v9 CPU.
+	* mpn/configure.in: Use sparc32/v9 for Solaris 2.6 or earlier with
+	a sparc v9 CPU.
+
+	* mpf/sub.c: In initial code for ediff == 0, limit precision
+	before jumping to `normalize'.
+
+1998-10-13  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpn/hppa/hppa2_0/add_n.s: New file.
+	* mpn/hppa/hppa2_0/sub_n.s: New file.
+	* mpn/configure.in: Handle hppa2.0 (32-bit code for now).
+
+	* config.guess: Update from egcs 1.1.
+	(9000/[3478]??:HP-UX:*:*): Properly return 2.0 for all known 2.0
+	machines.
+
+1998-10-07  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpz/root.c (mpz_root): New file.
+	* mpz/Makefile.in: Compile it.
+	* make.bat: Likewise.
+	* gmp.h (mpz_root): Declare.
+
+	* mpz/perfpow.c: New file.
+	* mpz/Makefile.in: Compile it.
+	* make.bat: Likewise.
+	* gmp.h (mpz_perfect_power_p): Declare.
+
+	* mpz/remove.c: New file.
+	* mpz/Makefile.in: Compile it.
+	* make.bat: Likewise.
+	* gmp.h (mpz_remove): Declare.
+
+	* mpz/bin_ui.c: New file.
+	* mpz/Makefile.in: Compile it.
+	* make.bat: Likewise.
+	* gmp.h (mpz_bin_ui): Declare.
+
+	* mpz/bin_uiui.c: New file.
+	* mpz/Makefile.in: Compile it.
+	* make.bat: Likewise.
+	* gmp.h (mpz_bin_uiui): Declare.
+
+1998-09-16  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* longlong.h: Test for __powerpc__ in addition to _ARCH_PPC.
+
+Sat Sep  5 17:22:28 1998  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpf/cmp_si.c: Compare most significant mantissa limb before
+	trying to deduce anything from the limb count.
+	* mpf/cmp_ui.c: Likewise.
+
+Tue Aug 18 10:24:39 1998  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpz/pprime_p.c (mpz_probab_prime_p): Add new code block
+	for doing more dividing.
+
+Sat Aug 15 18:43:17 1998  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpn/generic/divrem_newt.c: New name for divrem_newton.c.
+	* mpn/Makefile.in: Corresponding changes.
+	* mpn/configure.in: Likewise.
+
+Wed Aug 12 23:07:09 1998  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* config.guess: Handle powerpc for NetBSD.
+
+Tue Jul 28 23:10:55 1998  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpz/fib_ui.c: New file.
+	* mpz/Makefile.in: Compile it.
+	* make.bat: Likewise.
+	* gmp.h (mpz_fib_ui): Declare.
+
+Wed Jun 17 22:52:58 1998  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* make.bat: Fix typo, `asm-synt.h' => `asm-syntax.h'.
+
+Wed Jun  3 11:27:32 1998  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* config/mt-pwr: New file.
+	* config/mt-ppc: New file.
+	* configure.in: Use the new files.
+
+Tue Jun  2 13:04:17 1998  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpn/sparc32/v9/addmul_1.s: New file.
+	* mpn/config/mt-sprc9: New file.
+	* mpn/configure.in: Use mt-sprc9.
+
+Tue May 26 11:24:18 1998  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* demos/factorize.c (factor_using_pollard_rho): Pass correct
+	parameters in recursive calls; join the two recursion arms.
+
+	* mpf/set_q.c: Set result sign.
+	When normalizing the numerator, don't allow it to increase in size
+	beyond prec.
+
+Tue May 19 17:28:14 1998  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* demos/factorize.c (factor_using_division): Call fflush
+	also for the factor 2.
+
+Mon May 18 15:51:01 1998  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* make.bat: Pass -fomit-frame-pointer.  Do not pass -g.
+
+Tue May  5 01:42:50 1998  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpz/Makefile.in (LOCAL_CC): Remove definition.
+
+	* gmp.h: Get rid of GMP_SMALL stuff.
+	* mpz/Makefile.in: Likewise.
+	* mpq/Makefile.in: Likewise.
+	* mpf/Makefile.in: Likewise.
+
+	* mpz/invert.c: Fix typo in comment.
+
+Mon May  4 23:05:32 1998  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpn/generic/sqrtrem.c: Check that __arch64__ is not defined
+	before defining sparc SQRT.
+
+Mon Apr 20 19:16:17 1998  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpn/generic/gcdext.c: Allow gp to be NULL.
+
+1998-04-03  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpn/configure.in: Recognize `alphaev5*', not `alphaev5'.
+
+	* config.guess: Handle CPU variants for NetBSD.
+
+Mon Mar 16 13:07:54 1998  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpz/pprime_p.c: Use mpn_mod_1/mpn_preinv_mod_1 for computing mod PP,
+	not mpz_tdiv_r_ui (which expects an `unsigned long').
+	(mpz_probab_prime_p): Change type of `r' to mp_limb_t.
+
+Thu Mar 12 17:19:04 1998  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* gmp.h (mpf_ceil, mpf_floor, mpf_trunc): Add declarations.
+
+	* config.guess: Update from FSF version.
+	* config.sub: Likewise.
+
+	* config.guess: Add special handling of alpha-*-NetBSD.
+
+Wed Mar 11 00:55:34 1998  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpz/inp_str.c: Update from set_str.c.
+	Properly increment `nread' when skipping minus sign.
+
+	* mpz/set_str.c: Check for empty string after having skipped
+	leading zeros.
+
+Mon Mar  9 19:28:00 1998  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpz/set_str.c: Skip leading zeros.
+
+Wed Mar  4 19:29:16 1998  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* gmp.h (mpz_cmp_si): Cast argument before calling mpz_cmp_ui.
+
+	* demos/factorize.c: Rewrite.
+
+1998-02-04  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* configure.in (i[3456]86* etc): Check if using gcc before
+	choosing mt-x86.
+
+	* configure.in (m68*-*-*): New alternative.
+	* config/mt-m68k: New file.
+
+	* mpn/alpha/invert-limb.s: Put tables in text segment,
+	since not all systems support "rdata".
+
+Wed Feb  4 02:20:57 1998  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* gmp.h (__GNU_MP_VERSION_SNAP): New #define.
+	(__GNU_MP_VERSION_MINOR): Now 1.
+
+Wed Jan 28 22:29:36 1998  Torbjorn Granlund  <tege@tunnis.tmg.se>
+
+	* longlong.h (alpha udiv_qrnnd): #define UDIV_NEEDS_NORMALIZATION.
+
+Wed Jan 28 20:28:19 1998  Torbjorn Granlund  <tege@sophie.matematik.su.se>
+
+	* mpz/pprime_p.c (mpz_probab_prime_p): Delete 59 from tried divisors.
+
+Mon Jan 26 01:39:02 1998  Torbjorn Granlund  <tege@tunnis.tmg.se>
+
+	* mpz/pprime_p.c (mpz_probab_prime_p): Major overhaul: Check small
+	numbers specifically; check small factors, then perform a fermat test.
+
+Tue Jan 13 14:58:28 1998  Torbjorn Granlund  <tege@tunnis.tmg.se>
+
+	* longlong.h (alpha udiv_qrnnd): Call __mpn_invert_normalized_limb
+	and udiv_qrnnd_preinv.
+
+Wed Jan  7 01:52:54 1998  Torbjorn Granlund  <tege@tunnis.tmg.se>
+
+	* mpn/configure.in (alpha*, extra_functions): Add invert-limb and
+	remove udiv_qrnnd.
+
+	* mpn/tests/divrem.c: Get allocations right.
+
+	* mpn/generic/divrem.c: Conditionally pre-invert most significant
+	divisor limb.
+
+Tue Jan  6 23:08:54 1998  Torbjorn Granlund  <tege@tunnis.tmg.se>
+
+	* mpn/generic/divrem_1.c: Rename variables to comply to conventions.
+	Make `i' have type `mp_size_t'.
+
+Tue Dec 30 22:21:42 1997  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpz/tdiv_qr_ui.c: Return the remainder.
+	* mpz/tdiv_r_ui.c: Likewise.
+	* mpz/tdiv_q_ui.c: Likewise.
+	* gmp.h: Change return type of mpz_tdiv_qr_ui, mpz_tdiv_r_ui,
+	mpz_tdiv_q_ui.
+
+	* mpz/tdiv_ui.c: New file.
+	* mpz/Makefile.in: Compile it.
+	* make.bat: Likewise.
+	* gmp.h (mpz_tdiv_ui): Declare.
+
+Fri Nov  7 04:21:15 1997  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpf/integer.c (FUNC_NAME): Fix bogus test for mpf_trunc.
+
+	* demos/isprime.c: New file.
+
+	Sat Nov  1 19:32:25 1997  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpz/cmp_abs.c: New file.
+	* mpz/Makefile.in: Compile it.
+	* make.bat: Likewise.
+	* gmp.h (mpz_cmp_abs): Declare.
+
+	* mpz/cmp_abs_ui.c: New file.
+	* mpz/Makefile.in: Compile it.
+	* make.bat: Likewise.
+	* gmp.h (mpz_cmp_abs_ui): Declare.
+
+Sat Sep 27 04:49:52 1997  Torbjorn Granlund  <tege@tunnis.tmg.se>
+
+	* mpz/fdiv_r_2exp.c: Get allocation for `tmp' right.
+
+	* mpz/fdiv_q_2exp.c: In final result adjustment code, handle
+	that intermediate result is zero.
+
+	* mpz/tests/t-2exp.c: New file.
+	* mpz/tests/Makefile.in: Handle t-2exp.c.
+
+Fri Sep 26 16:29:21 1997  Torbjorn Granlund  <tege@tunnis.tmg.se>
+
+	* mpz/divexact.c: Fix typo in test for whether to copy numerator to
+	quotient and move that statement to after handling quotient and
+	denominator overlap.  Misc cleanups.
+
+	* mpn/generic/gcd.c: Change count argument of mpn_lshift/mpn_rshift
+	calls to `unsigned int'.
+	* mpz/divexact.c: Likewise.
+
+Mon Sep 22 02:19:52 1997  Torbjorn Granlund  <tege@pro.tmg.se>
+
+	* mpz/tests/t-powm.c: Decrease `reps' to 2500.
+
+	* mpz/tests/t-pow_ui.c: New file.
+	* mpz/tests/Makefile.in: Handle t-pow_ui.c.
+
+	* mpz/ui_pow_ui.c: Get special cases for exponent and base right.
+
+	* mpz/pow_ui.c: Increase temp space allocation by 1 limb.
+	Split `rsize' into two variables; compute space allocation into
+	`ralloc'.
+
+Sun Sep  7 04:15:12 1997  Torbjorn Granlund  <tege@pro.tmg.se>
+
+	* mpn/pa64/lshift.s: New file.
+	* mpn/pa64/rshift.s: New file.
+	* mpn/pa64/sub_n.s: New file.
+
+Sat Sep  6 19:14:13 1997  Torbjorn Granlund  <tege@gmp.tmg.se>
+
+	* mpn/pa64/add_n.s: New file.
+	* mpn/pa64: New directory.
+
+Tue Aug 19 16:17:09 1997  Torbjorn Granlund  <tege@pro.tmg.se>
+
+	* mpz/swap.c: New file.
+	* mpz/Makefile.in: Compile it.
+	* make.bat: Likewise.
+	* gmp.h (mpz_swap): Declare.
+
+	* mpn/generic/mul_n.c: Push assignment of x and y pointers into the
+	if/else clauses in several places.  (Decreases register pressure.)
+
+Mon Aug 18 03:29:50 1997  Torbjorn Granlund  <tege@pro.tmg.se>
+
+	* mpn/thumb/add_n.s: New file.
+	* mpn/thumb/sub_n.s: New file.
+	* mpn/arm/add_n.s: New file.
+	* mpn/arm/sub_n.s: New file.
+
+	* mpz/powm.c: After mpn_mul_n and mpn_mul calls, adjust product size
+	if most significant limb is zero.
+	* mpz/powm_ui.c: Likewise.
+
+Fri Aug 15 02:13:57 1997  Torbjorn Granlund  <tege@pro.tmg.se>
+
+	* mpn/arm/m/mul_1.s: New file.
+	* mpn/arm/m/addmul_1.s: New file.
+
+	* mpn/powerpc32/mul_1.s: Rewrite.
+
+	* mpn/alpha/mul_1.s: Prefix labels with `.'.
+
+Mon Aug 11 02:37:16 1997  Torbjorn Granlund  <tege@pro.tmg.se>
+
+	* mpn/powerpc32/add_n.s: Rewrite.
+	* mpn/powerpc32/sub_n.s: Rewrite.
+
+Sun Aug 10 17:07:15 1997  Torbjorn Granlund  <tege@pro.tmg.se>
+
+	* mpn/powerpc32/addmul_1.s: Delete obsolete comments.
+	* mpn/powerpc32/submul_1.s: Likewise.
+
+Fri Jul 25 20:07:54 1997  Torbjorn Granlund  <tege@pro.tmg.se>
+
+	* mpz/addmul_ui.c: New file.
+	* mpz/Makefile.in: Compile it.
+	* make.bat: Likewise.
+	* gmp.h (mpz_addmul_ui): Declare.
+
+	* mpz/setbit.c: Add missing code after final `else'.
+
+Tue Jul 22 17:45:01 1997  Torbjorn Granlund  <tege@tunnis.tmg.se>
+
+	* mpn/sh/add_n.s: Fix typo.
+	* mpn/sh/sub_n.s: Likewise.
+
+	* longlong.h (ns32k count_trailing_zeros): Fix typo.
+
+	* insert-dbl.c: Check for exponent overflow and return Inf.
+
+	* mpz/get_d.c: Rewrite to avoid rounding errors.
+
+Thu May 29 11:51:07 1997  Torbjorn Granlund  <tege@pro.tmg.se>
+
+	* mpq/add.c: Swap some usages of tmp1 and tmp2 to make sure
+	their allocation suffices.
+	* mpq/sub.c: Likewise.
+
+Wed Apr 16 02:24:25 1997  Torbjorn Granlund  <tege@pro.tmg.se>
+
+	* demos/pexpr.c: New file.
+
+	* mpn/generic/mul_n.c: Misc optimizations from Robert Harley.
+
+	* gmp-impl.h (MPZ_PROVOKE_REALLOC): New #define.
+
+Sat Apr 12 17:54:04 1997  Torbjorn Granlund  <tege@pro.tmg.se>
+
+	* mpz/tstbit.c: New file.
+	* mpz/Makefile.in: Compile it.
+	* make.bat: Likewise.
+	* gmp.h (mpz_tstbit): Declare.
+
+	* mpz/tests/logic.c: Use MPZ_CHECK_FORMAT.
+	* mpz/tests/bit.c: New test.
+	* mpz/tests/Makefile.in: Handle bit.c.
+
+	* mpz/ior.c: In -OP2,+OP1 case, normalize OP2 after call to mpn_sub_1.
+
+	* gmp-impl.h (MPZ_CHECK_FORMAT): New #define.
+
+Thu Apr 10 00:30:14 1997  Torbjorn Granlund  <tege@tmg.se>
+
+	* longlong.h (POWER/PowerPC): Test _ARCH_PWR instead of _IBMR2.
+
+Wed Apr  9 18:23:31 1997  Torbjorn Granlund  <tege@pro.tmg.se>
+
+	* gmp-impl.h: Move defaulting of UMUL_TIME and UDIV_TIME from here...
+	* longlong.h: ...to here.
+
+Sun Mar 30 12:16:23 1997  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpn/generic/next_prime.c: New file.
+
+	* mpn/generic/perfsqr.c: Remove definitions of PP and PP_INVERTED.
+	* gmp-impl.h: Put them here.
+
+Fri Mar 28 08:18:05 1997  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* gmp-impl.h (MPN_COPY_INCR, MPN_COPY_DECR): Define as inline asm for
+	for x86, but leave disabled for now.
+
+Fri Feb 28 02:39:47 1997  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpn/Makefile.in (.S.o): Pass SFLAGS and CFLAGS also to compiler
+	for assembly phase.
+	(.s.o): Pass SFLAGS.
+
+Wed Feb 26 06:46:08 1997  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpn/configure.in: For Pentium Pro, use default code, not Pentium
+	optimized code.
+
+	* mpn/x86/addmul_1.S: Unroll and optimize for Pentium Pro.
+	* mpn/x86/submul_1.S: Likewise.
+
+Thu Feb 13 08:26:09 1997  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpf/Makefile.in: Compile floor.o, ceil.o and trunc.o (from
+	integer.c).
+	* make.bat: Likewise.
+
+Wed Feb  5 05:58:44 1997  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpn/configure.in (alpha*): Add cntlz to extra_functions.
+
+Wed Feb  4 03:30:45 1997  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpf/integer.c: New file (supporting mpf_floor, mpf_ceil, mpf_trunc).
+
+Mon Feb  3 14:21:36 1997  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* make.bat: Fix typo, set_dfl_prc => set_dfl_prec.
+
+Sun Feb  2 02:34:33 1997  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpf/out_str.c: After outputting `-', decrement n_digits.
+
+Wed Jan  8 02:50:20 1997  Torbjorn Granlund  <tege@quiet.matematik.su.se>
+
+	* mpn/generic/divrem.c: qextra_limbs => qxn.
+
+Wed Dec 18 07:50:46 1996  Torbjorn Granlund  <tege@quiet.matematik.su.se>
+
+	* mpz/tests/t-tdiv.c (SIZE): Increase to 200.
+
+Tue Dec 17 19:32:48 1996  Torbjorn Granlund  <tege@quiet.matematik.su.se>
+
+	* mpn/generic/divrem.c (mpn_divrem_classic): New name for mpn_divrem.
+	* gmp.h (mpn_divrem): New function.
+	* mpn/generic/divrem_newton.c: New file.
+	* mpn/configure.in (functions): Add divrem_newton.
+	* make.bat: Likewise.
+
+Thu Dec 12 17:55:13 1996  Torbjorn Granlund  <tege@quiet.matematik.su.se>
+
+	* gmp.h (_GMP_H_HAVE_FILE): Test also __dj_include_stdio_h_.
+
+Sat Dec  7 09:40:06 1996  Torbjorn Granlund  <tege@quiet.matematik.su.se>
+
+	* mpn/alpha/invert-limb.s: New file.
+
+Thu Dec  5 01:25:31 1996  Torbjorn Granlund  <tege@quiet.matematik.su.se>
+
+	* mpz/ui_pow_ui.c (mpz_pow2): New (static) function.
+	(mpz_ui_pow_ui): Rewrite.
+
+	* make.bat: `pre_mod_1.c' => `pre_mod_.c'.  Fix typo in path to
+	gmp-mpar.h.
+
+Fri Nov 15 00:49:55 1996  Torbjorn Granlund  <tege@quiet.matematik.su.se>
+
+	* mpz/ui_pow_ui.c: Rewrite for better speed.
+
+Fri Nov  1 16:36:56 1996  Torbjorn Granlund  <tege@quiet.matematik.su.se>
+
+	* Makefile.in (recursive make rules): Use `&&' instead of `;' as
+	delimiter.
+
+Fri Oct 25 17:12:36 1996  Torbjorn Granlund  <tege@quiet.matematik.su.se>
+
+	* gmp-impl.h (Cray/uxp MPN_COPY): Really declare as inline.
+
+Thu Oct 24 15:08:19 1996  Torbjorn Granlund  <tege@quiet.matematik.su.se>
+
+	* mpn/fujitsu/rshift.c: Fix typo in loop boundaries.
+
+Fri Oct 18 03:13:54 1996  Torbjorn Granlund  <tege@quiet.matematik.su.se>
+
+	* mpn/configure.in: Recognize `nextstep' for m68k variants; likewise
+	for x86 variants.
+
+	* mpn/x86/syntax.h (INSND): New macro.
+	* mpn/x86/[lr]shift.S: Use INSND.
+	* mpn/x86/pentium/[lr]shift.S: Likewise.
+	* mpn/config/t-oldgas (SFLAGS): Pass -DOLD_GAS.
+
+	* gmp-impl.h: In code for determining endianness, test also
+	__BIG_ENDIAN__ and __hppa__.  Remove test of __NeXT__.
+
+Wed Oct 16 03:50:34 1996  Torbjorn Granlund  <tege@quiet.matematik.su.se>
+
+	* mpf/set_str.c: Let `prec' determine precision used in
+	exponentiation code; decrease allocation accordingly.
+
+	* mpn/vax: Change `jsob*' to `sob*' in all files.
+
+Tue Oct 15 03:54:06 1996  Torbjorn Granlund  <tege@quiet.matematik.su.se>
+
+	* longlong.h (m88110 udiv_qrnnd): Change type of intermediate quotient
+	to DImode (divu.d generates a 64-bit quotient).
+
+	* configure.in (m88110*): Fix typo.
+
+	* mpf/get_str.c: Compute exp_in_base using `double' to avoid overflow.
+
+	* gmp-impl.h (struct bases): Change type of chars_per_bit_exactly from
+	float to double.
+	* mpn/mp_bases.c (__mp_bases): Give 17 digits for chars_per_bit_exactly
+	field.
+
+	* mpf/get_str.c: Let `prec' determine precision used in
+	exponentiation code; decrease allocation accordingly.
+
+Sun Oct 13 03:31:53 1996  Torbjorn Granlund  <tege@quiet.matematik.su.se>
+
+	* longlong.h: Major cleanup.
+	(__udiv_qrnnd_c): Compute remainders using multiply and subtract,
+	not explicit `%' operator.
+	(C umul_ppmm): Get rid of a redundant __ll_lowpart.
+
+	* mpz/invert.c: Properly detect all operands that would yield an
+	undefined inverse; make sure the inverse is always positive.
+
+	* mpz/xor.c: New file.
+	* mpz/Makefile.in: Compile it.
+	* make.bat: Likewise.
+	* gmp.h (mpz_xor): Declare.
+
+	* mpz/tests/logic.c: Also test mpz_xor.
+
+	* mpz/lcm.c: Special case for when either operand equals 0.
+
+Sat Oct 12 01:57:09 1996  Torbjorn Granlund  <tege@quiet.matematik.su.se>
+
+	* mpn/generic/gcd.c (find_a): Don't inline on x86.
+
+	* Makefile.in (CFLAGS): Default to just `-g'.
+
+	* configure.in: Recognize 386 and 486 wherever other x86 cpus are
+	recognized.
+	* configure.in: Use mt-x86 for all x86 cpus.
+	* config/mt-x86: New file.
+
+	* mpn/alpha/cntlz.s: New file.
+
+Tue Oct  8 00:16:18 1996  Torbjorn Granlund  <tege@quiet.matematik.su.se>
+
+	* longlong.h: Define smul_ppmm for Fujitsu vpp/uxp.
+	Rewrite umul_ppmm to actually work on the hardware.
+
+	* mpn/x86/sub_n.S: Avoid parens around displacement of `leal'.
+	* mpn/x86/add_n.S: Likewise.
+
+	* mpn/x86/syntax.h (R): Define differently depending on __STDC__.
+
+Mon Oct  7 16:48:08 1996  Torbjorn Granlund  <tege@quiet.matematik.su.se>
+
+	* longlong.h: Don't test for __NeXT__ in outer 68k conditional;
+	add test for __m68k__.
+
+Sun Oct  6 00:59:09 1996  Torbjorn Granlund  <tege@quiet.matematik.su.se>
+
+	* gmp.h: Declare mpn_random.
+	* make.bat: Compile mpn/generic/random.c.
+
+	* longlong.h: Define umul_ppmm for Fujitsu vpp/uxp.
+
+	* gmp-impl.h: Protect definitions using `__attribute__ ((mode (...)))'
+	with test also for __GNUC_MINOR__.
+
+	* gmp.h: Don't define macros using __builtin_constant_p when using
+	NeXT's compiler.
+
+Fri Oct  4 16:53:50 1996  Torbjorn Granlund  <tege@quiet.matematik.su.se>
+
+	* mpz/lcm.c: New file.
+	* mpz/Makefile.in: Compile it.
+	* make.bat: Likewise.
+	* gmp.h (mpz_lcm): Declare.
+
+Wed Sep 25 00:06:21 1996  Torbjorn Granlund  <tege@quiet.matematik.su.se>
+
+	* mpq/tests/t-cmp_ui.c: Make sure numerator and denominator of `b' is
+	within limits of an `unsigned long int'.
+
+	* mpz/tests/t-powm_ui.c: Change type of exp2 to `unsigned long int'.
+
+Tue Sep 24 18:58:20 1996  Torbjorn Granlund  <tege@quiet.matematik.su.se>
+
+	* mpz/powm_ui.c: Make result always positive.
+
+	* urandom.h (urandom): Make it return mp_limb_t.
+
+	* gmp-impl.h (CNST_LIMB): New macro.
+	* mpn/mp_bases.c: Use CNST_LIMB.
+	* mpn/generic/hamdist.c (popc_limb): Likewise.
+	* mpn/generic/popcount.c (popc_limb): Likewise.
+	* mpn/generic/perfsqr.c: Likewise.
+
+Fri Sep 20 03:08:10 1996  Torbjorn Granlund  <tege@quiet.matematik.su.se>
+
+	* mpz/pprime_p.c: When n <= 3, don't clear out n before using it.
+
+Wed Sep 18 11:22:45 1996  Torbjorn Granlund  <tege@quiet.matematik.su.se>
+
+	* mpn/fujitsu/mul_1.c: New file.
+	* mpn/fujitsu/addmul_1.c: New file.
+	* mpn/fujitsu/sub_n.c: New file.
+	* mpn/fujitsu/add_n.c: Mew file.
+
+Sun Sep 15 03:13:02 1996  Torbjorn Granlund  <tege@quiet.matematik.su.se>
+
+	* mpn/generic/random.c: New file.
+	* mpn/configure.in (functions): Add `random'.
+
+	* gmp-impl.h (MPN_COPY): Define as annotated inline function for
+	Crays and Fujitsu VPPs.
+
+	* gmp.h (mp_size_t): Define as `int' for non-MPP Cray.
+	(mp_exp_t): Likewise.
+
+	* configure.in: Add support for Fujitsu VPP machines.
+	* mpn/configure.in: Likewise.
+	* config.guess: Likewise.
+	* config.sub: Likewise.
+
+	* mpn/fujitsu/rshift.c: New file.
+	* mpn/fujitsu/lshift.c: New file.
+	* mpn/fujitsu: New directory, for Fujitsu VPP machines.
+
+Wed Sep 11 11:34:38 1996  Torbjorn Granlund  <tege@quiet.matematik.su.se>
+
+	* mpn/generic/mul_n.c (__gmpn_mul_n): New name for impn_mul_n.
+	Call __gmpn_mul_basecase, not impn_mul_n_basecase; update parameter
+	list to work with __gmpn_mul_basecase.
+	(__gmpn_sqr): New name for impn_sqr_n.
+	Call __gmpn_sqr_basecase, not impn_sqr_n_basecase; update parameter
+	list to work with __gmpn_sqr_basecase.
+	(mpn_mul_n): Update calls to match new names and parameter conventions.
+	* gmp-impl.h (MPN_MUL_N_RECURSE): Likewise.
+	(MPN_SQR_RECURSE): New name for MPN_SQR_N_RECURSE.
+	Update calls to match new names and parameter conventions.
+	* mpn/generic/mul.c: Never perform multiply explicitly here, call
+	__gmpn_mul_basecase instead.
+	Update calls to match new names and parameter conventions.
+
+	* mpn/x86/mul_basecase.S: New file.
+	* mpn/generic/mul_basecase.c: New file.
+	* mpn/generic/sqr_basecase.c: New file.
+
+Wed Sep  4 02:59:21 1996  Torbjorn Granlund  <tege@quiet.matematik.su.se>
+
+	* mpz/set_str.c: Let `0b' and `0B' mean base 2.
+
+Fri Aug 30 00:44:00 1996  Torbjorn Granlund  <tege@quiet.matematik.su.se>
+
+	* longlong.h (x86 umul_ppmm): Work around GCC bug that was
+	triggered by Aug 28 change.
+
+	* mpbsd/min.c (digit_value_in_base): New function.
+
+	* mpz/set_str.c: Refine allocation size computation, use
+	chars_per_bit_exactly instead of chars_per_limb.
+
+	* mpbsd/Makefile.in (.c.o): Add -D_mpz_realloc=_mp_realloc.
+
+Wed Aug 28 02:52:14 1996  Torbjorn Granlund  <tege@quiet.matematik.su.se>
+
+	* longlong.h (x86 umul_ppmm): Don't cast result operands.
+	(x86 udiv_qrnnd): Likewise.
+	(default smul_ppmm): Fix typo, umul_ppmm => smul_ppmm.
+	(default umul_ppmm): New #define using smul_ppmm.
+	(vax smul_ppmm): New #define.
+	(vax umul_ppmm): Delete.
+	(POWER umul_ppmm): Delete.
+	(IBM 370 smul_ppmm): New #define.
+	(IBM 370 umul_ppmm): Delete.
+	(IBM RT/ROMP smul_ppmm): New #define.
+	(IBM RT/ROMP umul_ppmm): Delete.
+
+Tue Aug 27 01:03:25 1996  Torbjorn Granlund  <tege@quiet.matematik.su.se>
+
+	* gmp-impl.h (__gmp_0): Make it `const'.
+
+	* mpn/Makefile.in (clean mostlyclean): Comment out recursive clean
+	of `tests'.
+
+	* mpn/generic/mul.c: Identify when we do squaring, and call
+	impn_sqr_n_basecase/impn_sqr_n as appropriate.  Use
+	KARATSUBA_MUL_THRESHOLD and KARATSUBA_SQR_THRESHOLD.
+	Don't #define KARATSUBA_THRESHOLD.
+
+	* mpn/generic/mul_n.c: Don't #define KARATSUBA_THRESHOLD.
+	(impn_mul_n, impn_sqr_n): Rewrite, based on code contributed by
+	Robert Harley.
+	(impn_sqr_n_basecase): Rewrite.
+
+	* gmp-impl.h (KARATSUBA_MUL_THRESHOLD): New #define.
+	(KARATSUBA_SQR_THRESHOLD): Likewise.
+	(MPN_SQR_N_RECURSE): Use KARATSUBA_SQR_THRESHOLD.
+	(MPN_MUL_N_RECURSE): Use KARATSUBA_MUL_THRESHOLD.
+
+	* configure.in: Fix typo in last change.
+
+Mon Aug 26 22:25:18 1996  Torbjorn Granlund  <tege@quiet.matematik.su.se>
+
+	* mpn/generic/random2.c: Fix typo, `alpha__' => `__alpha'.
+	* mpf/random2.c: Likewise.
+
+Sun Aug 25 00:07:09 1996  Torbjorn Granlund  <tege@quiet.matematik.su.se>
+
+	* mpz/tests/t-mul.c: Also test squaring.
+
+Fri Aug 16 05:12:08 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mp_clz_tab.c (__clz_tab): Declare as `const'.
+	* version.c (gmp_version): Likewise.
+	* mpn/generic/sqrtrem.c (even_approx_tab, odd_approx_tab): Likewise.
+
+Thu Aug 15 02:34:47 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* gmp.h: Fix typo, `mips__' => `__mips'.
+
+	* mpf/set_str.c: Allow a number to start with a period, if next
+	position contains a digit.
+
+Tue Aug 13 18:41:25 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpz/gcdext.c: Get cofactor sign right for negative input operands.
+	Clean up code for computing tt.
+
+	* mpz/invert.c: Get rid of variable `rv'.
+
+	* mpz/divexact.c: Test for zero divisor in special case for zero
+	dividend.
+
+Mon Aug 12 18:04:07 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpz/?div_*_ui.c: Special case for division by 0.
+	* mpz/tdiv_q.c: Likewise.
+
+Sat Aug 10 14:45:26 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpz/dmincl.c: Special case for division by 0.
+
+	* mpz/tdiv_*_ui.c: Delete special case for dividend being 0; handle
+	it when computing size after mpn_divmod_1 call.
+
+	* mp_bpl.c: (__gmp_junk): New variable.
+	(__gmp_0): New constant.
+
+	* gmp-impl.h (DIVIDE_BY_ZERO): New #define.
+
+Fri Aug  9 20:03:27 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpz/divexact.c: Test for dividend being zero before testing
+	for small divisors.
+
+Thu Aug  8 13:20:23 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* configure.in: Require operating system specification for cpus
+	where assembly syntax differs between system.
+
+	* Makefile.in (many targets): Change `-' action prefix to `@'.
+
+	* mpn/Makefile.in: (distclean): Fix typo.
+
+	* mpq/cmp_ui.c: Rename function to _mpq_cmp_ui.
+	(mpq_cmp_ui): #undef deleted.
+	* mpz/cmp_si.c: Rename function to _mpz_cmp_si.
+	(mpz_cmp_si): #undef deleted.
+	* mpz/cmp_ui.c: Rename function to _mpz_cmp_ui.
+	(mpz_cmp_ui): #undef deleted.
+	* Makefile.in: Corresponding changes.
+
+	* mpf/get_prc.c: Return the *highest* precision achievable.
+
+	* mpf/get_str.c: Complete rewrite.
+
+	* mpf/set_str.c (swapptr): New #define.
+	(assert): New #define.
+	* mpf/set_str.c: Set prec to one more than the saved _mp_prec.
+	Misc cleanups.
+
+	* mpz/set_str.c: #include string.h.
+	* mpf/out_str.c: #include string.h.
+	* mpbsd/xtom.c: #include string.h and ctype.h.
+	* mpbsd/mout.c: #include string.h.
+
+Wed Aug  7 11:46:04 EDT 1996  Ken Weber <kweber@mcs.kent.edu>
+
+	* mpn/generic/gcd.c: Reorder mpn_gcd argument list.
+	* mpz/gcd.c: Change call to mpn_gcd.
+	* gmp.texi: Update manual entry on mpn_gcd.
+	* mpn/generic/bdivmod.c: Delete limb cache to make mpn_bdivmod
+	reentrant.
+
+Wed Aug  7 02:15:38 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpf/get_str.c: Rewrite code for converting integral part of a
+	number with both an integral and fractional part.
+
+	* mpf/set_str.c: Get rid of variable xxx.  New variables madj and radj.
+	In exp_in_base==0 case, add madj to msize for EXP field.
+
+	* mpz/tests/t-gcd.c: Test deleted.  Rename t-gcd2.c to t-gcd.c.
+	Increase reps to 2000.
+	* mpz/tests/t-gcd2.c: Get rid of mpz_refgcd.
+
+	* mpf/set_str.c: Ignore excess limbs in MP,MSIZE.
+
+Thu Jul 25 04:39:10 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpn/configure.in: Fix typo in setting path, "sparc" => "sparc32".
+
+Wed Jul 24 02:27:02 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpn/generic/gcdext.c: Reorganize and clean up.  Get rid of all
+	signed limb arithmetic.
+
+Mon Jul 22 02:39:56 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpn/generic/gcdext.c (mpn_gcdext): For large enough operands,
+	work with most significant *two* limbs.
+	(div2): New function (two variants).
+	(THRESHOLD): New #define.
+
+	* mpz/gcdext.c: Fix typo in MPZ_TMP_INIT call.
+
+	* longlong.h (alpha UMUL_TIME): Now 30.
+	(alpha UDIV_TIME): Now 350.
+	(x86 UMUL_TIME): Now 10 (let Pentium decide).
+	(SuperSPARC UDIV_TIME): Override default.
+
+	* extract-dbl.c (MP_BASE_AS_DOUBLE): Don't redefine here.
+
+	* extract-dbl.c: New name for extract-double.c.
+	* insert-dbl.c: New name for insert-double.c.
+	* Makefile.in: Corresponding changes.
+	* make.bat: Likewise.
+
+	* mpz/Makefile.in (.c.o): Don't pass non-portable `-f' to cp.
+	* mpq/Makefile.in: Likewise.
+	* mpf/Makefile.in: Likewise.
+
+Sat Jul 20 01:35:18 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpz/getlimbn.c: Take ABS of integer->_mp_size.
+
+	* mpz/divexact.c: Use mpn_divmod_1 if divisor is a single limb.
+
+Thu Jul 18 00:31:15 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpn/generic/popcount.c (popc_limb): Use different masking trick
+	for first step (due to David Seal).
+	* mpn/generic/hamdist.c (popc_limb): Likewise.
+
+Wed Jul 17 23:21:48 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpn/generic/divrem.c: In MPN_COPY_DECR call, copy dsize - 1 limbs.
+
+Sun Jul 14 17:47:46 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* configure.in: Handle sparc9, sparc64, and ultrasparc like sparc8.
+
+Thu Jul 11 14:05:54 1996  J.T. Conklin  <jtc@rtl.cygnus.com>
+
+	* longlong.h (mc680x0): Define umul_ppmm, udiv_qrnnd, sdiv_qrnnd
+	for the '020, '030, '040, and '332.  Define count_leading_zeros
+	for the '020, '030, '040, and '060.
+
+Sun Jul 14 15:24:53 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	From Joe Keane:
+	* mpq/equal.c: Take ABS of num1_size before passing it to mpn_cmp.
+
+Fri Jul 12 17:11:17 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpn/generic/sqrtrem.c (SQRT): New asm for x86, but leave it
+	disabled for now.
+
+	* mpn/generic/sqrtrem.c: Use MP_BASE_AS_DOUBLE.
+
+Wed Jul 10 03:17:45 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* cre-mparam.c: Delete obsolete file.
+
+	* gmp.h: #define _LONG_LONG_LIMB if __mips && _ABIN32.
+	* longlong.h: Test __mips instead of __mips__.
+
+Sun Jul  7 23:19:13 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* longlong.h (_PROTO): Define, unless already defined.
+	(alpha __udiv_qrnnd): Declare using _PROTO.
+	(hppa __udiv_qrnnd): Likewise.
+	(sparc __udiv_qrnnd): Likewise.
+
+Mon Jul  1 01:44:30 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* config.guess: Update from master version; add Cray x90 handling.
+
+Wed Jun 26 05:35:02 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpn/power/add_n.s (__mpn_add_n): Work around GAS bug.
+	* mpn/power/sub_n.s (__mpn_sub_n): Likewise.
+
+	* insert-double.c: Rework loop to avoid potential overflow.
+
+	* mpq/get_d.c: For vax, if qsize > N_QLIMBS, ignore excess limbs.
+
+	* mpq/tests/t-get_d.c (SIZE): Special case for vax.
+
+	* gmp.h (mpX_cmp_ui): #define also when ! __GNUC__.
+
+Mon Jun 24 17:13:21 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* longlong.h (vax sdiv_qrnnd): Fix typo.
+
+Sat Jun 15 01:33:33 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* gmp.h: Support `small' and `large' type and function variants,
+	controlled by GMP_SMALL.
+
+	* mpz/Makefile.in (.c.o): Compile each function twice, for small and
+	large variant.
+	(MPZS_OBJS): New variable.
+	(libmpz.a): Include MPZS_OBJS in archive.
+	* mpf/Makefile.in: Analogous changes.
+	* mpq/Makefile.in: Analogous changes.
+
+	* gmp.h: Prefix all functions with __gmp, to allow namespace-clean
+	internal calls.
+
+	* mp.h: Rip out __MP_SMALL__ stuff.
+	(__mpz_struct): mp_size_t => int.
+
+	* mpz/invert.c: #include "gmp-impl.h".
+	Use MPZ_TMP_INIT, not mpz_init.
+
+	* mpz/gcdext.c: Rewrite to call mpn_gcdext.
+
+Fri Jun 14 18:05:29 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpn/generic/gcdext.c (s0size): New parameter.
+	* gmp.h (mpn_gcdext): Update prototype.
+
+	* mpn/generic/gcdext.c: Major rewrite.
+
+Mon Jun 10 00:14:27 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpn/generic/dump.c: Add missing `else'.
+
+Fri Jun  7 03:35:12 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* Makefile.in (gmp_toc.html): Pass -expandinfo to texi2html.
+
+Thu Jun  6 19:00:53 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* Version 2.0.2 released.
+
+	* install.sh: New file.
+	* Makefile.in (INSTALL): Use install.sh.
+	(install-normal): New name for target `install'.
+	(install): New dummy target.
+
+	* mpz/pow_ui.c: Swap tests for (e == 0) and (bsize == 0).
+	* mpz/ui_pow_ui.c: Swap tests for (e == 0) and (blimb == 0).
+
+	* config/mt-linux (AR_FLAGS): New file.
+	* configure.in: Use config/mt-linux for all linux systems.
+
+Tue Jun  4 03:42:18 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* Version 2.0.1 released.
+
+	* mpf/tests/ref.c: Cast result of TMP_ALLOC to the right pointer type.
+
+	* extract-double.c: Test _GMP_IEEE_FLOATS with #if, not plain if.
+
+	* insert-double.c: Don't #include stdlib.h.
+
+	* gmp-impl.h (union ieee_double_extract): Test sparc and __sparc.
+	Do not test __sparc__.
+
+	* mpf/reldiff.c: Change declaration to work around irix5 compiler bug.
+	* mpq/equal.c: Likewise.
+
+	* mpn/generic/gcd.c: Delete spurious comma at end of enumeration.
+
+	* mpn/generic/gcdext.c: Add K&R declaration syntax.
+	* stack-alloc.h: Likewise.
+	* insert-double.c: Likewise.
+	* extract-double.c: Likewise.
+	* mpf/tests/reuse.c: Likewise.
+	* mpz/tests/reuse.c: Likewise.
+	* mpf/tests/t-sub.c: Likewise.
+	* mpf/tests/t-add.c: Likewise.
+	* mpf/tests/t-muldiv.c: Likewise.
+	* mpf/tests/t-conv.c: Likewise.
+	* mpf/tests/ref.c: Likewise.
+
+	* mpn/config/t-oldgas: Renamed from t-freebsd.
+	* mpn/configure.in: Use t-oldgas for freebsd, netbsd, and some linux
+	configurations.
+
+	* mpn/powerpc32/mul_1.s: Really clear cy before entering loop.
+	* mpn/powerpc32/*.s: Fix power/powerpc syntax issues.
+
+	* mpn/config/t-ppc-aix: New file.
+	* mpn/configure.in: Use t-ppc-aix for powerpc like t-pwr-aix for power.
+
+Wed May 29 02:07:31 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* gmp.h (mp_bits_per_limb): Change qualifier from `const' to
+	__gmp_const.
+
+	* gmp.h (mpf_init_set_str): Add `const' qualifier for 2nd parameter.
+	* mpf/iset_str.c: Likewise.
+
+Mon May 27 00:15:58 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* gmp-impl.h: Declare __gmp_extract_double.
+
+	* mpz/set_q.c: Delete unused variables.
+
+	* gmp.h (mpq_equal): Declare.
+
+	* mpf/eq.c: mpf_cmp2 -> mpf_eq.
+
+Fri May 24 03:20:44 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpz/iset_d.c: Don't include <math.h>.
+
+	* insert-double.c (__gmp_scale2): New name for scal2.
+	* mpz/get_d.c: Corresponding change.
+	* mpf/get_d.c: Likewise.
+	* mpq/get_d.c: Likewise.
+	* gmp-impl.h: Declare __gmp_scale2.
+
+	* mpn/generic/scan0.c: Clarify comment.
+
+	* mpz/set_q.c: New file.
+	* Makefile.in: Compile it.
+	* make.bat: Likewise.
+	* gmp.h: Declare mpz_set_q.
+
+	* insert-double.c: New file.
+	* Makefile.in: Compile it.
+	* make.bat: Likewise.
+
+	* mpz/get_d.c: New file.
+	* mpz/Makefile.in: Compile it.
+	* make.bat: Likewise.
+	* gmp.h: Declare mpz_get_d.
+
+	* mpf/get_d.c: New file.
+	* mpf/Makefile.in: Compile it.
+	* make.bat: Likewise.
+	* gmp.h: Declare mpf_get_d.
+
+	* make.bat: Compile things in alphabetical order.
+
+	* gmp-impl.h (MP_BASE_AS_DOUBLE): New #define.
+	(LIMBS_PER_DOUBLE): New #define.
+
+	* extract-double.c: New file.
+	* Makefile.in: Compile it.
+	* make.bat: Likewise.
+	* mpz/set_d.c: Rewrite to use __gmp_extract_double.
+	* mpf/set_d.c: Likewise.
+
+	* mpn/configure.in: Use t-pwr-aix also for aix 3.2.4 and up.
+
+Wed May 22 02:48:35 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* gmp-impl.h: Rework code for defining ieee_double_extract.
+	(IEEE_DOUBLE_BIG_ENDIAN): Macro removed.
+	(_GMP_IEEE_FLOATS): New macro.
+	* mpn/vax/gmp-mparam.h: Delete.
+
+	* mpn/config/t-pwr-aix: New file.
+	* mpn/configure.in: Use t-pwr-aix for aix 4 and later.
+
+Mon May 20 16:30:31 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* gmp.h: In code for setting _GMP_H_HAVE_FILE, test more symbols.
+
+	* mpf/tests/t-add.c (oo): Add some `l' printf modifiers.
+	* mpf/tests/t-sub.c (oo): Likewise.
+	* mpf/tests/t-conv.c (oo): Likewise.
+	* mpf/tests/t-sqrt.c (oo): Likewise.
+
+	* mpz/tests/t-mul.c (_mpn_mul_classic): Remove unused variables.
+
+	* mpn/{pyr,i960,clipper}/*.s: Add missing copyright headers.
+
+Fri May 17 02:24:43 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpz/set_d.c: Call _mpz_realloc.
+
+	* mpq/set_z.c: New file.
+	* mpq/Makefile.in: Compile it.
+	* make.bat: Likewise.
+	* gmp.h: Declare mpq_set_z.
+
+	* mp?/Makefile.in (libmp?.a): Depend on Makefile, not Makefile.in.
+	* mpf/Makefile.in (test): Delete spurious target.
+	* mpq/Makefile.in (test): Likewise.
+
+	* mpf/out_str.c: Use `e' to separate exponent when base <= 10.
+
+	* mpn/configure.in: Treat ultrasparc just like sparc v8,
+	until 64-bit compilers are ready.
+
+	* mpf/set_d.c: Make it work for 64-bit machines.
+
+Thu May 16 20:53:57 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* gmp-impl.h: Set IEEE_DOUBLE_BIG_ENDIAN to 0 for little-endian
+	machines.
+	* mpn/x86/gmp-mparam.h: Delete file.
+
+	* configure.in: Treat microsparc like sparc8.
+
+	* urandom.h: Test __alpha instead of __alpha__, since the former
+	is the standard symbol.
+	* mpn/generic/random2.c: Likewise.
+	* mpf/random2.c: Likewise.
+
+Tue May 14 13:42:39 1996  Torbjorn Granlund  (tege@tiny.matematik.su.se)
+
+	* mpz/set_f.c: New file.
+	* mpz/Makefile.in: Compile it.
+	* gmp.h: Declare mpz_set_f.
+
+	* mpf/set_q.c: Simplify expression in rsize == nsize if-then-else arms.
+
+Tue May 14 13:03:07 1996  Torbjorn Granlund  (tege@tiny.matematik.su.se)
+
+	* make.bat: Add all new files.
+
+Sun May 12 22:24:36 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpf/set_z.c: New file.
+	* mpf/Makefile.in: Compile it.
+	* gmp.h: Declare mpf_set_z.
+
+Sat May 11 19:26:25 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* gmp.h: Declare mpf_set_q.
+
+	* mpf/set_q.c: Compute prec-1 limbs in mpn_divrem call.
+
+Fri May 10 17:37:38 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpf/set_q.c: New file.
+	* mpf/Makefile.in: Compile it.
+
+	* config.sub: Recognize sparc8.
+
+Wed May  8 09:19:11 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpf/tests/t-dm2exp.c: New file.
+
+	* mpf/tests/t-add.c: Correct header comment.
+	* mpf/tests/t-sub.c: Likewise.
+	* mpf/tests/t-sqrt.c: Likewise.
+
+	* mpf/div.c: Misc variable name cleanups.
+	* mpf/div_ui.c: Base more closely on mpf/div.c.
+	* mpf/ui_div.c: Likewise.
+
+	* mpz/tests/Makefile.in (check): Depend on Makefile.
+	* mpq/tests/Makefile.in (check): Likewise.
+	* mpf/tests/Makefile.in (check): Likewise.
+
+	* mpf/tests/t-muldiv.c: New file.
+	* mpf/tests/Makefile.in: Compile and run `t-muldiv'.
+	(t-ref.o): Delete spurious rule.
+
+	* mpf/sqrt.c: Properly detect negative input operand.
+
+	* mpf/sqrt_ui.c: Delete spurious header comment.
+	* mpf/sqrt.c: Likewise.
+	* mpz/sqrt.c: Likewise.
+
+	* mpz/tests/reuse.c (main): Read `reps' from command line.
+
+	* mpf/tests/reuse.c: New file.
+	* mpf/tests/Makefile.in: Compile and run `reuse'.
+
+	* mpf/mul_ui.c: Disable code for removing low zero limbs.
+
+	* mpf/div.c: Fix condition for when vp and qp overlaps.
+
+	* mpf/add_ui.c: When sum equals u, copy up to prec+1 limbs.
+
+	* mpf/out_str.c: Don't output '\n' after exponent.
+
+	* mpf/add_ui.c: New special case for when U is completely cancelled.
+
+Wed Apr 24 05:33:28 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* Version 2.0 released.
+
+	* All files: Update FSF's address.
+
+	* Makefile.in (gmp_toc.html): New name for gmp.html.
+	(TAGS): Depend on force.
+
+	* mpf/tests/t-conv.c: Pass -base to mpf_set_str.
+
+Sat Apr 20 03:54:06 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* Makefile.in (ps): New target, depend on gmp.ps.
+
+Fri Apr 19 14:03:15 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpf/out_str.c: Print `@' before exponent, not `e'.
+
+	* make.bat: Update from Makefiles.
+
+Thu Apr 18 01:22:05 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpf/set_str.c: If parameter `base' is negative, expect exponent
+	to be decimal, otherwise in the same base as the mantissa.
+
+Wed Apr 17 17:28:36 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpf/set_dfl_prec.c: Don't return anything.
+	* gmp.h: Corresponding changes.
+
+	* mpf/set_dfl_prec.c: Use `unsigned long int' for bit counts.
+	* mpf/init2.c: Likewise.
+	* mpf/get_prc.c: Likewise.
+	* mpf/set_prc.c: Likewise.
+	* mpf/set_prc_raw.c: Likewise.
+	* mpz/popcount.c: Likewise.
+	* mpz/hamdist.c: Likewise.
+	* mpz/scan1.c: Likewise.
+	* mpz/scan0.c: Likewise.
+	* mpn/generic/popcount.c: Likewise.
+	* mpn/generic/hamdist.c: Likewise.
+	* mpn/generic/scan1.c: Likewise.
+	* mpn/generic/scan0.c: Likewise.
+	* gmp.h: Likewise.
+
+	* mpf/eq.c: New file, based on mpf/diff.c.
+	* mpf/diff.c: Delete.
+	* mpf/Makefile.in: Corresponding changes.
+	* gmp.h: Likewise.
+
+	* mpf/reldiff.c: New file.
+	* mpf/Makefile.in: Compile it.
+	* gmp.h: Declare mpf_reldiff.
+
+	* mpz/iset_d.c: New file.
+	* mpz/Makefile.in: Compile it.
+	* gmp.h: Declare mpz_init_set_d.
+
+Tue Apr 16 16:28:31 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* Makefile.in (gmp.html): Pass -acc to texi2html.
+
+Mon Apr 15 16:20:24 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpf/set_str.c: Switch off code for defaulting the base from the
+	leading characters.
+
+	* gmp.h (mp?_sign): Delete.
+	(mp?_sgn): New macros.
+
+Fri Apr 12 17:23:33 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* Makefile.in (gmp.dvi): Delete tmp.* at end of rule.
+
+Wed Apr 10 22:52:02 1996  Torbjorn Granlund  (tege@tiny.matematik.su.se)
+
+	* mpf/random2.c: Change of `exp' param, mp_size_t => mp_exp_t.
+	* gmp.h: Corresponding change.
+
+	* gmp.h (mp_bits_per_limb): Make it const.
+
+Sat Mar 30 01:20:23 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* configure.in: Re-enable recognition of with_gcc.
+
+	* mpf/Makefile.in (.c.o): Pass XCFLAGS.
+	* mpn/Makefile.in (.c.o): Likewise.
+	* mpz/Makefile.in (.c.o): Likewise.
+	* mpq/Makefile.in (.c.o): Likewise.
+	* mpbsd/Makefile.in (.c.o): Likewise.
+	* mpf/tests/Makefile.in (.c.o): Likewise.
+	* mpz/tests/Makefile.in (.c.o): Likewise.
+	* mpq/tests/Makefile.in (.c.o): Likewise.
+
+	* Makefile.in (XCFLAGS): Default to empty.
+	(FLAGS_TO_PASS): Pass on XCFLAGS.
+	(.c.o): Pass XCFLAGS.
+
+	* config/mt-m88110 (XCFLAGS): Define instead of CC.
+	* config/mt-sprc8-gcc (XCFLAGS): Likewise.
+	* config/mt-supspc-gcc (XCFLAGS): Likewise.
+
+	* configure: Don't default CC to "gcc -O2" is -with-gcc=no was
+	specified.
+
+Mon Mar 25 01:07:54 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* urandom.h: Test for __SVR4 in addition to __svr4__.
+
+	* mp_bpl.c (mp_bits_per_limb): Declare as `const'.
+
+	* Makefile.in (CFLAGS): `-O2' => `-O'.
+	* mpn/Makefile.in (CFLAGS): Likewise.
+
+	* gmp-impl.h: Get rid of obsolete field access macros.
+
+	* mpn/mp_bases.c (__mp_bases): 1e39 => 1e38 to work around Solaris
+	cc compiler bug.
+
+	* gmp.h (__MPN): Make it work also for non-ANSI compilers.
+
+Thu Mar 21 01:07:54 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpf/sub.c: New special case for ediff <= 1 before generic code.
+	Simplify generic code for ediff == 0.
+	Rename uexp => exp.
+
+Mon Mar 11 18:24:57 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpf/tests/*.c: Use ref_mpf_sub for error calculation.
+	* mpf/tests/Makefile.in: Link ref.o to all executables.
+
+	* mpf/tests/t-sub.c: Make u = v + 1 with 50% probability.
+
+Sun Mar 10 21:03:17 1996  Torbjorn Granlund  (tege@tiny.matematik.su.se)
+
+	* mpf/get_str.c: In digit development loop for fractions, change
+	loop condition from `<' to `<='.
+
+Thu Mar  7 04:58:11 1996  Torbjorn Granlund  <tege@tiny.matematik.su.se>
+
+	* mpn/mp_bases.c (__mp_bases): 1e100 => 1e39 to avoid overflow warning.
+
+Wed Mar  6 01:10:42 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpf/tests/t-sqrt.c: New file.
+	* mpf/tests/Makefile.in: Corresponding changes.
+
+	* mpf/sqrt.c: Special case for square root of zero.
+
+	* mpq/add.c: Clean up variable names.
+	* mpq/sub.c: Update from mpq/add.c.
+
+	* mpz/divexact.c: abs => ABS.
+	* mpz/gcd.c: Likewise.  Rewrite final fixup code, to decrease
+	allocation.  Misc cleanups.
+
+Tue Mar  5 22:24:56 1996  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpn/configure.in: Recognize linuxoldld as a synonym for linuxaout.
+
+	* gmp.h (mpn_add, mpn_add_1, mpn_sub, mpn_sub_1): Add prototypes.
+
+	* mpn/configure.in: Use t-freebsd also for netbsd.
+
+Mon Mar  4 15:13:28 1996  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpq/Makefile.in (cmp.o): Depend on longlong.h.
+
+	* mpq/equal.c: New file.
+	* mpq/Makefile.in: Corresponding changes.
+
+	* mpf/tests/t-add.c: New file.
+	* mpf/tests/t-sub.c: Renamed from t-addsub.c.
+	* mpf/tests/ref.c: New file.
+	* mpf/tests/Makefile.in: Corresponding changes.
+
+	* gmp-impl.h (SIZ, ABSIZ, PTR, EXP, PREC, ALLOC): New #defines.
+
+Sun Mar  3 07:45:46 1996  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpf/set_str.c: In exponentiation code, allocate 3 extra
+	limbs, not just 2.
+
+	* mpf/get_str.c: Allocate sufficient space for tstr.
+	When calculating exp_in_base, round result down.
+
+	* mpf/tests/t-conv.c: New file.
+	* mpf/tests/Makefile.in: Corresponding changes.
+
+	* mp_bpl.c: New file.
+	* gmp.h: Declare it.
+	* Makefile.in: Corresponding changes.
+
+Sat Mar  2 06:27:56 1996  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpf/set_prc_raw.c: New file.
+	* mpf/set_prc.c: Renamed from set_prec.c.
+	* mpf/get_prc.c: New file.
+	* mpf/Makefile.in: Corresponding changes.
+	* gmp.h: Declare new functions.
+
+	* mpn/generic/gcdext.c: Add copyright header.
+
+Fri Mar  1 01:22:24 1996  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpn/configure.in: For ppc601, search "power" before "powerpc32".
+
+	* mp?/Makefile.in (AR_FLAGS): New variable.
+	(libmp?.a): Use it.
+
+	* make.bat: New file.
+	* mpn/msdos: New directory.
+	* mpn/msdos/asm-syntax.h: New file.
+
+	* mpn/Makefile.in (distclean maintainer-clean): Delete asm-syntax.h.
+
+	* config.sub: Recognize [ctj]90-cray.
+
+	* mpn/configure.in: Recognize [ctj]90-cray-unicos*.
+
+	* mpn/generic/gcdext.c: Don't use alloca directly, use TMP_* macros.
+
+	* mpn/generic/gcd.c: Split increment from use of USIZE to avoid
+	undefined behaviour.
+
+Thu Feb 29 04:11:24 1996  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* Makefile.in (install-info-files): Update for new install-info
+	behaviour.
+
+	* mpn/power/add_n.s: Rewrite.
+	* mpn/power/sub_n.s: Rewrite.
+
+Wed Feb 28 01:34:30 1996  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpz/pow_ui.c: Compute allocation more aggressively for small bases.
+	* mpz/ui_pow_ui.c: Likewise.
+
+	* mpn/mp_bases.c (__mp_bases): Put huge value in 2nd field for index 1.
+
+	* mpn/generic/sqrtrem.c: sizeof (mp_limb_t) => BYTES_PER_MP_LIMB.
+	* mpn/generic/gcd.c: Likewise.
+	(SIGN_BIT): Compute differently.
+
+Mon Feb 26 00:07:36 1996  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* All files: mp_limb => mp_limb_t, mp_limb_signed => mp_limb_signed_t.
+
+	* Makefile.in (install, install-bsdmp, install-info-files): Depend
+	on installdirs.  chmod all installed files.
+
+Sun Feb 25 01:47:41 1996  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpbsd/configure.in: Delete debugging code.
+
+	* All Makefile.in: Update clean targets.
+
+	* Makefile.in (AR_FLAGS): New variable.
+	(libgmp.a): Use it.
+	(libmp.a): Likewise.
+
+	* VERSION: Delete file.
+
+	* Makefile.in (installdirs): New target.
+	* mkinstalldirs: New file (from the texinfo package).
+
+	* Makefile.in (INSTALL, INSTALL_DATA, INSTALL_PROGRAM): New variables.
+	(MAKEINFO, MAKEINFOFLAGS, TEXI2DVI): New variables.
+	(install-info): New target.
+	(install, install-bsdmp): Depend on install-info.
+	($(srcdir)/gmp.info): Changed from plain gmp.info; put info files
+	into source directory.
+	(distclean, mostlyclean): New targets.
+	(maintainer-clean): New name for realclean.
+	(uninstall): New target.
+	(TAGS): New target.
+	(info, dvi): New targets.
+	(.PHONY): Assign.
+
+	* Makefile.in (install, install-bsdmp): Use INSTALL_DATA.
+
+	* mp{n,z,f,bsd}/move-if-change: Delete.
+
+	* mpbsd/Makefile.in (stamp-stddefh): Delete target.
+
+	* Makefile.in (.c.o): Pass CFLAGS last.
+	* mpbsd/Makefile.in (.c.o): Likewise.
+	* mpf/Makefile.in (.c.o): Likewise.
+	* mpq/Makefile.in (.c.o): Likewise.
+	* mpz/Makefile.in (.c.o): Likewise.
+	* mpn/Makefile.in (.c.o): Likewise.
+	(.S.o): Likewise.
+
+	* memory.c: Change allocation error message.
+
+	* Makefile.in (install): Prefix gmp.h with $(srcdir).
+	(install-bsdmp): Prefix mp.h with $(srcdir).
+
+	* mp{n,z,f,bsd}/{configure,config.sub}: Delete.
+
+	* Makefile.in (gmp.dvi): Set TEXINPUTS also for 2nd tex invocation
+	(install targets): Install gmp.info-N.
+
+Sat Feb 24 03:36:52 1996  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpf/get_str.c: Fix typo.
+
+	* mpz/legendre.c: Clarify expression with extra parens.
+
+	* version.c (gmp_version): Not static.
+
+	* mpf/iset_str.c: Properly return error code.
+
+	* mpf/add.c: Delete unused variables.
+	* mpf/inp_str.c: Likewise.
+	* mpq/get_d.c: Likewise.
+
+	* mpn/generic/dump.c: #include <stdio.h>.
+	* mpf/dump.c: Likewise.
+	* mpf/set_str.c: #include <ctype.h>.
+	(strtol): Declare.
+
+	* gmp.h: mpn_sqrt => mpn_sqrtrem.
+
+	* Makefile.in (clean, realclean): Clean in mpbsd.
+	(check): Test in mpf.
+
+	* mpf/Makefile.in (clean): Clean in tests.
+	* mpq/Makefile.in (clean): Clean in tests.
+
+	* mpf/tests/Makefile.in: New file.
+	* mpf/tests/configure.in: New file.
+	* mpf/tests/t-addsub.c: New file.
+
+	* mpf/sub_ui.c: Simply call mpf_sub for now.
+
+	* mpf/sub.c: Increase prec by 1.
+	* mpf/ui_sub.c: Likewise.
+
+Fri Feb 23 00:59:54 1996  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpf/ui_sub.c: Fix typos.
+
+	* mpf/get_str.c: When allocating space for tmp, allow for an extra
+	limb.  In code for fraction conversion, add special case for bases
+	that are a power of 2.
+
+	* mpf/out_str.c: Output leading "0.".
+	Default base to 10, before computing string allocation.
+
+	* mpf/get_str.c: Make variables for string size have type size_t.
+	* gmp.h: Corresponding change.
+
+	* mpf/random2.c: Allow creation of prec+1 large mantissas.
+
+	* mpf/add_ui.c: Don't abort if u < 0; special case for u <= 0.
+	Fix typo in MPN_COPY offset.
+	* mpf/sub_ui.c: Analogous changes.
+
+	* mpf/set_prec.c: Rewrite.
+
+	* mpf/init2.c: Compute precision as in set_prec.c.
+
+	* mpf/div_2exp.c: Special case for u == 0.
+	* mpf/mul_2exp.c: Likewise.  Write r->_mp_size always.
+
+	* mpf/sqrt_ui.c: mpn_sqrt => mpn_sqrtrem.
+	* mpf/sqrt.c: Likewise.  When computing new exponent, round quotient
+	towards -infinity.
+
+	* mpf/add.c: Fix typos.
+	* mpf/sub.c: Fix typos.
+
+Thu Feb 22 00:24:48 1996  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpz/Makefile.in (stamp-stddefh): Delete target.
+	(test): Delete target.
+	* Makefile.in (stamp-stddefh): Delete target.
+	(cre-stddefh.o): Delete target.
+	(gmp.dvi): Set TEXINPUTS before invoking tex.
+
+	* cre-stddefh.c: Delete.
+
+	* mpz/sqrt.c: Fix typo.
+
+	* mpz/powm.c: Special case for mod == 0.
+	* mpz/powm_ui.c: Likewise.
+
+	* mpz/get_si.c: Handle -0x80000000 correctly.
+
+	* mpz/inp_str.c: Now returns size_t.
+	Make it return number of bytes read or error indication.
+	* mpf/inp_str.c: Likewise.
+
+	* mpz/out_raw.c: Replace by mpz/out_binary.c, with modifications.
+	* mpz/inp_raw.c: Rewrite, using mpz/inp_binary as a base.
+	* mpz/inp_binary.c: Delete.
+
+	* mpn/Makefile.in (XCFLAGS): Remove variable.
+	(.c.o): Don't pass XCFLAGS.
+	(SFLAGS): Set to nothing.
+	(.S.o): Pass SFLAGS, not XCFLAGS.
+
+	* mpn/config/t-freebsd (SFLAGS): New name for XCFLAGS.
+
+	* mpf/out_str.c: Make return number of bytes written or error
+	indication.
+	* mpz/out_str.c: Likewise.
+	* gmp.h: Corresponding changes.
+
+	* gmp.h (__mpz_struct): mp_size_t => int.
+	(__mpq_struct): Likewise.
+	(__mpf_struct): Likewise.
+	(mp_size_t): int => long int.
+
+	* mpn/cray: New directory.
+	* mpn/cray/gmp-mparam.h: New file.
+	* mpn/configure.in: Recognize cray variants.
+
+	* Makefile.in: Set defaults for prefix, libdir, etc.
+	(install): New target.
+	(install-bsdmp): New target.
+	(gmp.html): New target.
+
+	* stack-alloc.c (__tmp_alloc): Cast void ptrs to char * in comparison.
+
+Wed Feb 21 04:35:02 1996  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* gmp.h: Sort mpn declarations.
+	(mpn_gcdext): Add declaration.
+
+	* mpn/generic/divrem_1.c: New file.
+	* mpn/Makefile.in (divrem_1.o): New rule.
+	* configure.in (functions): Add divrem_1.
+
+	* mpn/generic/divmod.c: Delete file.
+	* mpn/configure.in (functions): Delete divmod.
+	* Makefile.in (divmod.o): Delete rule.
+	* gmp.h (mpn_divmod): New #define.
+
+	* gmp.h (mpn_next_bit_set): Delete spurious declaration.
+
+	* mpn/generic/divrem.c (default case): In code assigning
+	most_significant_q_limb, move reassignment of n0 into if statement.
+
+	* gmp.h (mpf_inp_str): Fix typo.
+	(mpf_out_str): Make prototype match reality.
+	* mpf/inp_str.c: New file.
+	* mpf/out_str.c: New file.
+	* mpf/Makefile.in: Compile new files.
+
+	* mpn/Makefile.in (dump.o): Fix dependency path.
+	(inlines.o): Likewise.
+
+	* mpn/configure.in: Make m68060 be the same as m68000.  Clean up
+	m68k configs.
+
+Tue Feb 20 01:35:11 1996  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpn/generic/sqrtrem.c: Renamed from sqrt.
+	* mpn/configure.in (functions): Corresponding change.
+	* mpn/Makefile.in: Likewise.
+	* mpz/sqrtrem.c: Likewise.
+	* mpz/sqrt.c: Likewise.
+	* mpn/generic/perfsqr.c: Likewise.
+
+	* Makefile.in (clean): Also remove libmp.a.
+	Don't compile cre-conv-tab.c or mp_bases.c.
+	cre-conv-tab.c: Delete file.
+	(gmp.ps): New rule.
+
+	* mpn/mp_bases.c: New file.
+	* mpn/Makefile.in: Compile mp_bases.c.
+
+	* mpz/set_str.c: Skip initial whitespace.
+	* mpf/set_str.c: Likewise.
+	* mpbsd/xtom.c: Likewise.
+
+	* gmp.h: Add missing mpz declarations.
+	Delete all formal parameter names from declarations.
+
+	* mpn/Makefile.in: Add dependencies for .c files.
+
+	* Makefile.in (check): Write recursive make calls separately, not as
+	a loop.
+	(FLAGS_TO_PASS): New variable.  Use it for most recursive makes.
+
+Mon Feb 19 01:02:20 1996  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpn/Makefile.in (.S.o): Pipe cpp output to grep in order to delete
+	lines starting with #.
+	(CPP): Set to $(CC) -E to avoid gcc dependency.
+
+	* mpn/m68k/syntax.h (moveql): Define to moveq for MIT_SYNTAX.
+
+	* mpn/hppa/hppa1_1/pa7100/addmul_1.S: Fix typo in s1_ptr alignment
+	code.
+	* mpn/hppa/hppa1_1/pa7100/submul_1.S: Likewise.
+
+	* gmp.h: Fix typos in #defines of recently added mpn functions.
+
+	* mpz/inp_str.c: Skip all whitespace, not just plain space.
+	* mpbsd/min.c: Likewise.
+
+	* mpn/configure.in (functions): Add gcdext.
+	* mpn/generic/gcdext.c: New file.
+
+	* mpz/legendre.c: mpz_div_2exp => mpz_tdiv_q_2exp.
+
+	* gmp.h: Surround mpn declarations with extern "C" { ... }.
+
+	* Makefile.in (check): New target.
+
+	* mpq/get_d.c: Update comments.  Use rsize instead of dsize + N_QLIMBS
+	when possible.  Add special case for nsize == 0.
+
+	* gmp.h (mpq_get_d): Add declaration.
+	(mpq_canonicalize): Likewise.
+	(mpq_cmp_ui): Likewise.
+	(mpf_diff): Likewise.
+	(mpf_ui_sub): Likewise.
+	(mpf_set_prec): Likewise.
+	(mpf_random2): Likewise.
+
+	* gmp.h (mpz_cmp_ui): New #define.
+	(mpz_cmp_si): New #define.
+	(mpq_cmp_ui): New #define.
+	(mpz_sign): New #define.
+	(mpq_sign): New #define.
+	(mpf_sign): New #define.
+	(mpq_numref): New #define.
+	(mpq_denref): New #define.
+
+	* mpq/set_z.c: File deleted.
+	* mpq/Makefile.in: Corresponding changes.
+
+Sun Feb 18 01:34:47 1996  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpbsd/sdiv.c: Use _mp_realloc, not _mpz_realloc.
+
+	* mpz/inp_binary.c: Default stream to stdin.
+	* mpz/inp_str.c: Likewise.
+	* mpz/inp_raw.c: Likewise.
+	* mpz/out_binary.c: Default stream to stdout.
+	* mpz/out_raw.c: Likewise.
+	* mpz/out_str.c: Likewise.
+
+	* mpbsd/realloc.c: New file.
+	* mpbsd/Makefile.in: Corresponding changes.
+
+	* mpbsd/min.c: Rewrite (base on mpz/inp_str.c).
+	* mpbsd/mtox.c: Rewrite (base on mpz/get_str.c).
+
+	* mpbsd/mout.c: Rewrite (base on mpz/out_str) but make it output
+	spaces in each 10th position.
+	* mpbsd/xtom.c: Rewrite (base on mpz/set_str).
+
+	* mpq/tests/Makefile.in (st-cmp): New file.
+	* mpq/tests/configure.in (srcname): New file.
+
+	* mpz/tests/configure.in (srcname): Fix typo.
+
+	* mpq/cmp.c: Add check using number of significant bits, to avoid
+	general multiplication.
+
+Sat Feb 17 11:58:30 1996  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpq/cmp_ui.c: Store cy_limb after the mpn_mul_1 calls.
+
+	* mpq/tests: New directory.
+	* mpq/tests/t-cmp.c: New file.
+	* mpq/tests/t-cmp_ui.c: New file.
+
+	* mpz/tests/dive.c (main): Generate zero numerator.
+	(get_random_size) : Delete.
+
+	* mpz/divexact.c: Add special case for 0/x.
+
+	* gmp.h (mpz_mod): Add declaration.
+
+Fri Feb 16 18:18:39 1996  Andreas Schwab  <schwab@informatik.uni-dortmund.de>
+
+	* mpn/m68k/*: Rewrite code not to use the INSN macros.
+	(L): New macro to properly prefix local labels for ELF.
+
+Fri Feb 16 00:20:56 1996  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* gmp-impl.h (ieee_double_extract): Use plain `unsigned int' for
+	fields.
+	* mpn/generic/inlines.c (_FORCE_INLINES): New #define.  Delete
+	conditional __GNUC__.
+	* gmp.h (mpn_add, mpn_sub, mpn_add_1, mpn_sub_1):
+	Only define these if __GNUC__ || _FORCE_INLINES.
+	* mpf/random2.c: Add missing parameter in non-ANSI header.
+	* mpn/generic/gcd.c (SIGN_BIT): Do as #define to work around bug
+	in AIX compilers.
+	* mpq/get_d.c: #define N_QLIMBS.
+	* mpz/divexact.c: Obscure division by 0 to silent compiler warnings.
+	* stack-alloc.c: Cast void* pointer to char* before doing arithmetic
+	on it.
+
+	* Makefile.in (mpbsd/libmpbsd.a): New rule.
+	* configure.in (configdirs): Add mpbsd.
+
+	* gmp.h: Add declarations for a few missing mpn functions.
+
+	* Makefile.in (libmp.a): New rule.
+
+	* mpbsd/mdiv.c: #include "dmincl.c", not "mpz_dmincl.c"
+	* gmp.h: Move #define of __GNU_MP__ into the `#if __GNU_MP__' block.
+	* mp.h: Likewise.  Update typedefs from gmp.h.
+	* mpbsd/configure.in: New file.
+	* mpbsd/Makefile.in: New file.
+	* mpbsd/configure: Link to master configure.
+	* mpbsd/config.sub: Link to master config.sub.
+
+	* Makefile.in: Set RANLIB_TEST.
+	* (libgmp.a): Use it.
+	* (libgmp.a): Do ranlib before moving the libgmp.a to the build
+	directory.
+	* mp?/Makefile.in: Don't use or set RANLIB.
+
+Thu Feb 15 16:38:41 1996  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpz/add_ui.c: MP_INT => mpz_t.
+	* mpz/cmp_ui.c: Likewise.
+	* mpz/fac_ui.c: Likewise.
+	* mpz/inp_binary.c: Likewise.
+	* mpz/inp_raw.c: Likewise.
+	* mpz/legendre.c: Likewise.
+	* mpz/jacobi.c: Likewise.
+	* mpz/out_binary.c: Likewise.
+	* mpz/out_raw.c: Likewise.
+	* mpz/random2.c: Likewise.
+	* mpz/random.c: Likewise.
+	* mpz/realloc.c: Likewise.
+
+	* mpz/legendre.c: __mpz_2factor(X) => mpz_scan1(X,0),
+	__mpz_odd_less1_2factor => mpz_scan1(X,1).
+	* mpz/ntsup.c: File deleted.
+	* mpz/Makefile.in: Corresponding changes.
+
+	* mpz/pprime_p: Use mpz_scan1 to avoid looping.
+
+	* mpz/fac_ui.c: Type of `k' and `p' is `unsigned long'.
+	* mpz/pprime_p.c: Pass long to *_ui functions.
+	* mpz/gcdext.c: Likewise.
+	* mpz/fdiv_r_2exp.c: Likewise.
+	* mpz/fac_ui.c: Likewise.
+
+	* mpz/powm.c: Don't use mpn_rshift when mod_shift_cnt is 0.
+
+	* mpz/tests/Makefile.in (st-sqrtrem): Fix typo.
+
+	* mpz/cmp_ui.c: #undef mpz_cmp_ui.
+	* mpz/cmp_si.c: #undef mpz_cmp_si.
+	* gmp.h (mpz_cmp_ui): New #define.
+	(mpz_cmp_si): New #define.
+
+Wed Feb 14 22:11:24 1996  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* gmp.h: Test __cplusplus in addition to __STDC__.
+	* gmp-impl.h: Likewise.
+
+	* gmp.h: Surround declarations with extern "C" { ... }.
+
+Tue Feb 13 15:20:45 1996  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpz/fdiv_r_2exp.c: Use MPN_NORMALIZE.
+	* mpz/tdiv_r_2exp.c: Likewise.
+
+	* mpz/fdiv_r_2exp.c: New file.
+	* mpz/fdiv_q_2exp.c: New file.
+	* mpz/tdiv_r_2exp.c: Renamed from mpz/mod_2exp.c.
+	* mpz/tdiv_q_2exp.c: Renamed from mpz/div_2exp.c
+	* mpz/Makefile.in: Corresponding changes.
+
+	* mpz/scan0.c,scan1.c: New files.
+	* mpz/Makefile.in: Compile them.
+
+	* gmp.h (mpn_normal_size): Delete.
+
+	* config.guess: Update from Cygnus version.
+
+	* mpn/m68k/rshift.S: Use INSN2 macro for lea instructions.
+	* mpn/m68k/lshift.S: Likewise.
+
+	* mpn/configure.in: Fix configuration for plain 68000.
+
+Mon Feb 12 01:06:06 1996  Torbjorn Granlund  <tege@matematik.su.se>
+
+	* mpz/tests/t-powm.c: Generate negative BASE operand.
+
+	* mpz/powm.c: Make result always positive.
+
+Sun Feb 11 01:44:56 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpz/tests/*.c: Add t- prefix.
+	* mpz/tests/Makefile.in: Corresponding changes.
+	* mpz/tests/configure.in: Update srctrigger.
+
+	* mpz/tests/gcd.c: Generate negative operands.
+	* mpz/tests/gcd2.c: Likewise.
+
+	* mpz/gcdext.c: At end, if G is negative, negate all G, S, and T.
+
+Thu Feb  8 17:16:12 UTC 1996 Ken Weber <kweber@mat.ufrgs.br>
+
+	* mp{z,n}/gcd.c: Change mpn_gcd interface.
+	* gmp.h: Ditto.
+	* gmp.texi: update documentation.
+
+Mon Feb  7 23:58:43 1996  Andreas Schwab  <schwab@informatik.uni-dortmund.de>
+
+	* mpn/m68k/{lshift,rshift}.S: New files.
+	* mpn/m68k/syntax.h: New ELF_SYNTAX macros.
+	(MEM_INDX, R, PROLOG, EPILOG): New macros.
+	* mpn/m68k/*.S: Use R macro with register name.  Use PROLOG and EPILOG
+	macros.  Rename `size' to `s_size' or s1_size to avoid clash with ELF
+	.size directive.
+	* mpn/configure.in: New target m68k-*-linux*.
+
+Wed Feb  7 07:41:31 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* Makefile.in (cre-conv-tab): Workaround for SunOS make.
+
+	* mpz/tests/reuse.c: New file.
+	* mpz/tests/Makefile.in: Handle reuse.c.
+
+Tue Feb  6 11:56:24 UTC 1996 Ken Weber <kweber@mat.ufrgs.br>
+
+	* mpz/gcd.c: Fix g->size when one op is 0 and g == other op.
+
+Tue Feb  6 01:36:39 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* gmp.h (mpz_divexact): Delete parameter names.
+	(mpz_lcm): Delete spurious declaration.
+
+	* mpz/dmincl.c: Fix typo.
+
+Mon Feb  5 01:11:56 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpn/generic/gcd.c (gcd_2): Declare consistently.
+
+	* mpz/tdiv_q.c: Optimize division by a single-limb divisor.
+	* mpz/dmincl.c: Likewise.
+
+	* mpz/add.c: Use MPN_NORMALIZE instead of mpn_normal_size.
+	* mpz/sub.c: Likewise.
+	* mpn/generic/sqrt.c: Likewise.
+
+	* mpn/tests/{add_n,sub_n,lshift,rshift}.c: Put garbage in the
+	destination arrays.
+
+Fri Feb  2 02:21:27 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpz/{jacobi.c,legendre.c,ntsup.c,invert.c}: New files.
+	* mpz/Makefile.in: Compile them.
+
+	* mpn/Makefile.in (INCLUDES): Don't search in `generic'.
+
+Thu Feb  1 02:15:11 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	Change from Ken Weber:
+	* mpz/divexact.c: Make it work when quot is identical to either input.
+
+	* mpf/ui_sub.c: New file.
+	* mpf/Makefile.in: Compile it.
+
+	* gmp-impl.h (MPZ_TMP_INIT): alloca -> TMP_ALLOC.
+	* mpz/{c,f}div_{q,qr,r}.c: Use TMP_DECL/TMP_MARK/TMP_FREE since
+	these use MPZ_TMP_INIT.
+	* mpz/mod.c: Likewise.
+	* mpq/{add,sub}.c: Likewise.
+	* mpq/canonicalize: Likewise.
+
+	* mpq/{add,sub,mul,div}.c: Use mpz_divexact. MP_INT -> mpz_t.
+	* mpq/canonicalize.c: Likewise.
+
+Wed Jan 31 01:45:00 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpn/generic/gcd.c: Misc changes from Ken.
+
+	* mpz/tests/gcd2.c: New file.
+	* mpz/tests/Makefile.in: Handle gcd2.c.
+
+	* mpn/generic/gcd.c (mpn_gcd): When GCD == ORIG_V, return vsize,
+	not orig_vsize.  Fix parameter declaration.
+
+	* mpz/mod_ui.c: Delete file.
+	* mpz/Makefile.in: Don't try to compile mod_ui.
+
+	* mpz/cdiv_*_ui.c): Make them work right.
+	* gmp.h: Declare cdiv*.
+
+Tue Jan 30 02:22:56 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpz/{cdiv_q.c,cdiv_q_ui.c,cdiv_qr.c,cdiv_qr_ui.c,cdiv_r.c,
+	cdiv_r_ui.c,cdiv_ui.c}: New files.
+	* mpz/Makefile.in: Compile them.
+
+	* All files: Make file permissions right.
+
+	Changes from Ken Weber:
+	* mpn/generic/accelgcd.c: Delete.
+	* mpn/generic/bingcd.c: Delete.
+	* mpn/generic/numbits.c: Delete.
+	* mpn/generic/gcd.c: New file.
+	* mpn/configure.in (functions): Update accordingly.
+	* mpz/divexact.c: New file.
+	* mpz/Makefile.in: Compile divexact.c.
+	* mpz/gcd.c: Rewrite to accommodate for gcd changes in mpn.
+	* gmp.h: declare new functions, delete obsolete declarations.
+	* mpz/tests/dive.c: New file.
+	* mpz/tests/Makefile.in: Handle dive.c.
+
+Mon Jan 29 03:53:24 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpz/random.c: Handle negative SIZE parameter.
+
+	* mpz/tests/tdiv(_ui).c: New name for tst-dm(_ui).c.
+	* mpz/tests/tst-mdm(_ui).c: Delete.
+	* mpz/tests/fdiv(_ui).c: New test based in tst-mdm(_ui).
+	* mpz/tests/*.c: Get rid of tst- prefix for DOS 8+3 naming.
+	* mpz/tests/Makefile.in: Corresponding changes.
+	* mpz/tests/configure.in: Update srctrigger.
+
+	* mpn/generic/divmod.c: Update from divrem.
+	* mpn/generic/divrem.c: Misc cleanups.
+
+Sun Jan 28 03:25:08 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* All files: Use new TMP_ALLOC interface.
+
+	* mpz/powm_ui.c: Make Jan 25 changes to powm.c also here.
+
+	* mpz/tests/powm_ui.c: New file.
+	* mpz/tests/Makefile.in: Add rules for tst-powm and tst-powm_ui.
+
+	* Makefile.in: Update dependency list.
+	* mpf/Makefile.in: Likewise.
+	* mpz/Makefile.in: Likewise.
+	* mpq/Makefile.in: Likewise.
+	* Makefile.in: Set RANLIB simply to ranlib, and allow configure
+	to override it.
+
+	* mpz/Makefile.in (conf): Delete spurious target.
+	(mp_bases.c): Delete.
+	(cre-conv-tab rules): Delete.
+
+	* Makefile.in (cre-conv-tab): Greatly simplify.
+
+Sat Jan 27 13:38:15 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* stack-alloc.c: New file.
+	* stack-alloc.h: New file.
+
+	* gmp.h (__gmp_inline): Define using __inline__.
+
+Thu Jan 25 00:28:37 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpn/generic/scan0.c: New file.
+	* mpn/generic/scan1.c: Renamed from next_bit.c.
+	* mpn/configure.in (functions): Include scan0 and scan1.
+
+	* mpn/m68k/*: #include sysdep.h.  Use C_GLOBAL_NAME.
+
+	* configure: Update from Cygnus version.
+	* config.guess: Likewise.
+	* config.sub: Likewise.
+	* configure: Pass --nfp to recursive configures.
+
+	* mpz/tests/tst-*.c: Adjust SIZE and reps.
+
+	* mpz/powm.c: Move esize==0 test earlier.
+	In final reduction of rp,rsize, don't call mpn_divmod unless
+	reduction is really needed.
+
+	* mpz/tests/tst-powm.c: Fix thinko in checking code.
+
+	* All files: Get rid of `__' prefix from mpn_* calls and declarations.
+	* gmp.h: #define __MPN.
+	* gmp.h: Use __MPN in #defines for mpn calls.
+
+	* mpn/generic/mul_n.c: Prepend `i' to internal routines.
+	* gmp-impl.h: Add #defines using __MPN for those internal routines.
+
+	* mpn/generic/sqrt.c: Change call to mpn_mul to mpn_mul_n.
+
+Wed Jan 24 13:28:19 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpn/sparc32/udiv_fp.S: New name for udiv_qrnnd.S.
+	* mpn/sparc32/udiv_nfp.S: New name for v8/udiv_qrnnd.S.
+	* mpn/sparc32/v8/supersparc: New directory.
+	* mpn/sparc32/v8/supersparc/udiv.S: New file.
+
+Tue Jan 23 01:10:11 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	This major contribution is from Ken Weber:
+	* mpn/generic/accelgcd.c: New file.
+	* mpn/generic/bdivmod.c: New file.
+	* mpn/generic/bingcd.c: New file.
+	* mpn/generic/gcd_1.c: Rewrite.
+	* mpn/generic/numbits.c: New file (to go away soon).
+	* mpz/gcd.c: Rewrite.
+	* mpz/tests/tst-gcd.c (SIZE): Now 128.
+	* gmp.h: Declare new functions.
+	* mpn/configure.in (functions): List new files.
+	* gmp-impl.h (MPN_SWAP): Delete.
+	(MPN_LESS_BITS_LIMB, MPN_LESS_BITS, MPN_MORE_BITS): Delete.
+	(MPN_COMPL_INCR, MPN_COMPL): Delete.
+
+Mon Jan 22 02:04:59 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* gmp.h (mpn_name): New #define.
+
+	* mpn/m88k/mc88110/addmul_1.s: New file.
+	* mpn/m88k/mc88110/add_n.S: New file.
+	* mpn/m88k/mc88110/sub_n.S: New file.
+
+	* mpn/m88k/sub_n.s: Correctly initialize carry.
+
+	* mpn/sparc32/{add_n.S,sub_n.S,lshift.S,rshift.S): `beq' => `be'.
+
+Sun Jan 21 00:04:35 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpn/sparc64/addmul_1.s: New file.
+	* mpn/sparc64/submul_1.s: New file.
+	* mpn/sparc64/rshift.s: New file.
+
+Sat Jan 20 00:32:54 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpz/iset.c: Fix typo introduced Dec 25.
+
+Wed Jan 17 13:16:44 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* config/mt-sprc8-gcc: New name for mt-sparc8-gcc.
+	* config/mt-sparcv8-gcc: Delete.
+	* configure.in: Corresponding changes.
+
+Tue Jan 16 16:31:01 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* gmp-impl.h: #include alloca.h when necessary.
+
+	* longlong.h: Test __alpha instead of __alpha__, since the former
+	is the standard symbol.
+
+Mon Jan 15 18:06:57 1996  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpn/sparc64/mul_1.s: Swap operands of mulx instructions.
+	* mpn/sparc64/lshift.s: New file.
+
+Fri Dec 29 17:34:03 1995  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpn/x86/pentium/add_n.S: Get rid of #defines for register names.
+	* mpn/x86/pentium/sub_n.S: Likewise.
+
+Thu Dec 28 03:16:57 1995  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpn/x86/pentium/mul_1.S: Rework loop to avoid AGI between update
+	of loop induction variable and load insn at beginning of loop.
+	* mpn/x86/pentium/addmul_1.S: Likewise.
+	* mpn/x86/pentium/submul_1.S: Likewise.
+
+Mon Dec 25 23:22:55 1995  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* All files: Prefix user-visible structure fields with _mp_.
+
+Fri Dec 22 20:42:17 1995  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpn/configure.in (m68k configs): Terminate path variable with
+	plain "m68k".
+
+Fri Dec 22 03:29:33 1995  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpn/sparc32/add_n.S: Update from sub_n.S to fix bugs, and to
+	clean things up.
+
+	* mpn/configure.in (m68k configs): Update #include path for new
+	mpn directory organization.
+
+Tue Dec 12 02:53:02 1995  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* gmp.h: Prefix all structure field with _mp_.
+	* gmp-impl.h: Define access macros for these fields.
+
+Sun Dec 10 00:47:17 1995  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpn/alpha/addmul_1.s: Prefix labels with `.'.
+	* mpn/alpha/submul_1.s: Likewise.
+	* mpn/alpha/[lr]shift.s: Likewise.
+	* mpn/alpha/udiv_qrnnd.S: Likewise.
+	* mpn/alpha/ev5/[lr]shift.s: Likewise.
+
+	* mpn/alpha/ev5/lshift.s: Fix typos.
+
+Fri Dec  1 14:28:20 1995  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpn/Makefile.in (.SUFFIXES): Define.
+
+Wed Nov 29 23:11:57 1995  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpn/sparc64/{add_n.s, sub_n.s}: New files.
+
+Tue Nov 28 06:03:13 1995  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpn/x86/syntax.h: Handle ELF_SYNTAX.
+	Rename GAS_SYNTAX => BSD_SYNTAX.
+
+	* mpn/configure.in: Handle linuxelf and SysV for x86 variants.
+
+Mon Nov 27 01:32:12 1995  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpn/hppa/hppa1_1/pa7100/submul_1.S: New file.
+
+Sun Nov 26 04:30:47 1995  Torbjorn Granlund  <tege@noisy.matematik.su.se>
+
+	* mpn/hppa/hppa1_1/pa7100/addmul_1.S: New file.
+
+	* mpn/sparc32/add_n.S: Rewrite to use 64 bit loads/stores.
+	* mpn/sparc32/sub_n.S: Likewise.
+
+Fri Nov 17 00:18:46 1995  Torbjorn Granlund  <tege@bozo.matematik.su.se>
+
+	* mpn/configure.in: Handle m68k on NextStep.
+
+Thu Nov 16 02:30:26 1995  Torbjorn Granlund  <tege@bozo.matematik.su.se>
+
+	* mpn: Reorganize machine-specific directories.
+	* mpn/configure.in: Corresponding changes.
+	(sh, sh2): Handle these.
+	(m68k targets): Create asm-syntax.h.
+
+Thu Nov  9 02:20:50 1995  Torbjorn Granlund  <tege@bozo.matematik.su.se>
+
+	* mpn/generic/mul_n.c (____mpn_sqr_n): Delete code that calls abort.
+	(____mpn_mul_n): Likewise.
+
+Tue Nov  7 03:25:12 1995  Torbjorn Granlund  <tege@bozo.matematik.su.se>
+
+	* mpf/get_str.c: In exponentiation code (two places), don't swap
+	input and output areas when calling mpn_mul_1.
+	* mpf/set_str.c: Likewise.
+
+Fri Nov  3 02:35:58 1995  Torbjorn Granlund  <tege@bozo.matematik.su.se>
+
+	* mpf/Makefile.in: Make sure all objects are listed in dependency list;
+	delete spurious entries.
+
+	* mpf/mul.c: Handle U or V being 0.  Allow prec+1 for result precision.
+
+	* mpf/set_prec.c: New computation of limb precision.
+	* mpf/set_dfl_prec.c: Likewise.
+
+	* mpf/random2.c: Fix typo computing exp.
+	* mpf/get_str.c: In (uexp > usize) case, set n_limbs as a function of
+	the user-requested number of digits, n_digits.
+
+Thu Nov  2 16:25:07 1995  Torbjorn Granlund  <tege@bozo.matematik.su.se>
+
+	* mpn/generic/divrem.c (case 2): Don't move np vector back, it is
+	never read.
+	(default case): Put most significant limb from np in new variable n2;
+	decrease size argument for MPN_COPY_DECR; use n2 instead of np[dsize].
+
+Wed Nov  1 02:59:53 1995  Torbjorn Granlund  <tege@bozo.matematik.su.se>
+
+	* mpn/sparc/[lr]shift.S: New files.
+
+Tue Oct 31 00:08:12 1995  Torbjorn Granlund  <tege@bozo.matematik.su.se>
+
+	* mpz/gcd_ui.c: Set w->size unconditionally when v is zero.
+
+	* gmp-impl.h (assert): Delete definition.
+
+	* mpf/sub.c: Delete all assert calls.  Delete variable `cy'.
+
+	* mpf/neg.c: Use prec+1 as precision.  Optimize for when arguments
+	are the same.
+	* mpf/abs.c: Likewise.
+	* mpf/{set,neg,abs}.c: Make structure and variable names similar.
+
+Mon Oct 30 12:45:26 1995  Torbjorn Granlund  <tege@bozo.matematik.su.se>
+
+	* mpf/random2.c (random): Test __SVR4 in addition to __svr4__.
+	* mpn/generic/random2.c (random): Likewise.
+
+Sun Oct 29 01:54:28 1995  Torbjorn Granlund  <tege@bozo.matematik.su.se>
+
+	* mpf/div.c: Special handle U or V being 0.
+
+	* mpf/random2.c: New file.
+
+	* longlong.h (i860 rshift_rhlc): Define.
+	(i960 udiv_qrnnd): Define.
+	(i960 count_leading_zeros): Define.
+	(i960 add_ssaaaa): Define.
+	(i960 sub_ddmmss): Define.
+	(i960 rshift_rhlc): Define.
+
+Sat Oct 28 19:09:15 1995  Torbjorn Granlund  <tege@bozo.matematik.su.se>
+
+	* mpn/pentium/rshift.S: Fix and generalize condition for when to use
+	special code for shift by 1.
+	* mpn/pentium/lshift.S: Likewise.
+
+Thu Oct 26 00:02:56 1995  Torbjorn Granlund  <tege@bozo.matematik.su.se>
+
+	* gmp.h: #undef __need_size_t.
+	* mp.h: Update from gmp.h.
+
+Wed Oct 25 00:17:27 1995  Torbjorn Granlund  <tege@bozo.matematik.su.se>
+
+	* mpf/Makefile.in: Compile set_prec.c.
+	* mpf/realloc.c: Delete this file.
+	* mpf/Makefile.in: Delete mentions of realloc.c.
+
+	* gmp.h (__mpf_struct): Get rid of `alloc' field.
+	* mpf/clear.c: Likewise.
+	* mpf/init*.c: Likewise.
+	* mpf/set_prec.c: Likewise.
+	* mpf/iset*.c: Likewise.
+
+	* mpf/iset_str.c: New file.
+
+	* mpn/configure.in: Handle pyramid.
+
+	* mpf/set.c: Use prec+1 as precision.
+
+	* mpf/set_prec.c: New file.
+
+Tue Oct 24 00:56:41 1995  Torbjorn Granlund  <tege@bozo.matematik.su.se>
+
+	* mpn/generic/divrem.c: New file.  Will replace mpn/generic/divmod.c
+	when rest of source is converted.
+	* mpn/configure.in (functions): Add `divrem'
+	* mpn/generic/set_str.c: Never call __mpn_mul_1 with zero size.
+
+	* mpf/get_str.c: Completely rewritten.
+	* mpf/add.c: Fix several problems.
+	* mpf/sub.c: Compare operands from most significant end until
+	first difference, exclude skipped limbs from computation.
+	Accordingly simplify normalization code.
+	* mpf/set_str.c: Fix several problems.
+	* mpf/dump.c: New file.
+	* mpf/Makefile.in: Compile dump.c.
+	* mpf/init2.c: Set prec field correctly.
+
+Sun Oct 22 03:02:09 1995  Torbjorn Granlund  <tege@bozo.matematik.su.se>
+
+	* cre-conv-tab.c: #include math.h; don't declare log and floor.
+
+Sat Oct 21 23:04:10 1995  Torbjorn Granlund  <tege@bozo.matematik.su.se>
+
+	* mpf/mul_ui.c: Handle U being 0.
+
+Wed Oct 18 19:39:27 1995  Torbjorn Granlund  <tege@bozo.matematik.su.se>
+
+	* mpn/generic/set_str.c: Correctly handle input like "000000000000".
+	Misc cleanups.
+
+Tue Oct 17 15:14:13 1995  Torbjorn Granlund  <tege@bozo.matematik.su.se>
+
+	* longlong.h: Define COUNT_LEADING_ZEROS_0 for machines where
+	appropriate.
+
+Mon Oct 16 19:14:43 1995  Torbjorn Granlund  <tege@bozo.matematik.su.se>
+
+	* mpf/add.c: Rewrite.
+	* mpf/set_str.c: New file.  Needs more work.
+
+Sat Oct 14 00:14:04 1995  Torbjorn Granlund  <tege@bozo.matematik.su.se>
+
+	* mpf/div_2exp.c: Vastly simplify.
+	* mpf/mul_2exp.c: Likewise.
+
+	* mpf/sub.c: Rewrite.
+
+	* gmp-impl.h (udiv_qrnnd_preinv2gen): Terminate comment.
+
+	* mpf/dump.c: Free allocated memory.
+
+	* gmp-impl.h (assert): Define.
+
+Wed Oct 11 13:31:00 1995  Torbjorn Granlund  <tege@bozo.matematik.su.se>
+
+	* mpn/pentium/rshift.S: Install new code to optimize shift-by-1.
+
+Tue Oct 10 00:37:21 1995  Torbjorn Granlund  <tege@bozo.matematik.su.se>
+
+	* mpn/pentium/lshift.S: Install new code to optimize shift-by-1.
+
+	* mpn/powerpc32/{lshift.s,rshift.s}: New files.
+
+	* configure.in: Fix typo.
+
+Sat Oct  7 08:17:09 1995  Torbjorn Granlund  <tege@bozo.matematik.su.se>
+
+	* longlong.h (smul_ppmm): Correct type of __m0 and __m1.
+
+Wed Oct  4 16:31:28 1995  Torbjorn Granlund  <tege@bozo.matematik.su.se>
+
+	* mpn/configure.in: Handle alphaev5.
+	* mpn/ev4: New name for alpha subdir.
+	* mpn/ev5: New subdir.
+	* mpn/ev5/lshift.s: New file.
+
+Tue Oct  3 15:06:45 1995  Torbjorn Granlund  <tege@bozo.matematik.su.se>
+
+	* mpn/alpha/mul_1.s: Avoid static increments of pointers; use
+	corresponding offsets in ldq and stq instructions instead.
+	(Loop): Swap cmpult and stq to save one cycle on EV5.
+
+	* mpn/tests/{add_n.s,sub_n.s,lshift.s,rshift.s,mul_1.s,addmul_1.s,
+	submul_1.s}: Don't check results if NOCHECK is defined.
+
+Mon Oct  2 11:40:18 1995  Torbjorn Granlund  <tege@bozo.matematik.su.se>
+
+	* longlong.h (mips umul_ppmm [32 and 64 bit versions]):
+	Make new variants, based on GCC version number, that use `l' and `h'
+	constraints instead of explicit mflo and mfhi instructions
+
+Sun Oct  1 00:17:47 1995  Torbjorn Granlund  <tege@bozo.matematik.su.se>
+
+	* mpn/mc88100/add_n.s: Decrease unrolling factor from 16 to 8.
+	* mpn/mc88100/sub_n.s: Likewise.
+
+	* config/mt-m88110: New file.
+	* configure.in: Use it.
+
+	* mpn/mc88110/mul_1.s: Fix thinko.
+
+Sat Sep 30 21:28:19 1995  Torbjorn Granlund  <tege@bozo.matematik.su.se>
+
+	* mpz/set_d.c: Declare `size' at function start.
+
+	* experimental: New directory for mpx and mpz2.
+
+	* mpz/tdiv_q.c: Clarify comments.
+	* mpz/{mod.c,mod_ui.c}: New file, for math mod function.
+
+	* mpn/sh2/{mul_1.s,addmul_1.s,submul_1.s}: New files.
+
+	* mpn/sh/{add_n.s,sub_n.s}: New files.
+
+	* mpn/pyr/{add_n.s,sub_n.s,mul_1.s,addmul_1.s}: New files.
+
+	* mpn/i960/{add_n.s,sub_n.s}: New files.
+
+	* mpn/alpha/addmul_1.s (Loop): Move decrement of r18 to before umulh,
+	to save cycles on EV5.
+	* mpn/alpha/submul_1.s: Ditto.
+	* mpn/alpha/mul_1.s: Ditto.
+
+Thu Sep 28 02:48:59 1995  Torbjorn Granlund  <tege@bozo.matematik.su.se>
+
+	* gmp.h (mp_limb, mp_limb_signed): Define as `long long' if
+	_LONG_LONG_LIMB is defined.
+
+	* longlong.h (m88110): Test __m88110__, not __mc88110__
+
+	* mpn/mc88110/mul_1.s: Rewrite.
+
+Tue Sep 26 23:29:05 1995  Torbjorn Granlund  <tege@bozo.matematik.su.se>
+
+	* config.sub: Update from current Cygnus version.
+
+	* mpn/configure.in: Recognize canonical m88*, not mc88*.
+
+Fri Sep 22 14:58:05 1995  Torbjorn Granlund  <tege@bozo.matematik.su.se>
+
+	* mpz/set_d.c: New file.
+	* mpz/Makefile.in: Build new files.
+
+	* mpq/get_d.c: Replace usage of scalbn with ldexp.
+
+	* mpn/{vax,i386}/gmp-mparam.h: New files.
+	* gmp-impl.h (ieee_double_extract): Define here.
+	* mpf/set_d.c (ieee_double_extract): Not here.
+
+Thu Sep 21 00:56:36 1995  Torbjorn Granlund  <tege@bozo.matematik.su.se>
+
+	* longlong.h (C umul_ppmm): Use UWtype, not USItype for temps.
+	(udiv_qrnnd): For cases implemented with call to __udiv_qrnnd,
+	protect with new symbol LONGLONG_STANDALONE.
+	(68000 umul_ppmm): Use %# prefix for immediate constants.
+
+Wed Sep 20 15:36:23 1995  Torbjorn Granlund  <tege@bozo.matematik.su.se>
+
+	* mpn/generic/divmod_1.c: Handle
+	divisor_limb == 1 << (BITS_PER_MP_LIMB - 1)
+	specifically also when normalization_steps != 0.
+
+Mon Sep 18 15:42:30 1995  Torbjorn Granlund  <tege@bozo.matematik.su.se>
+
+	* mpq/get_d.c: New file.
+
+Sun Sep 17 02:04:36 1995  Torbjorn Granlund  <tege@bozo.matematik.su.se>
+
+	* longlong.h (pyr): Botch up for now.
+
+Sat Sep 16 00:11:50 1995  Torbjorn Granlund  <tege@bozo.matematik.su.se>
+
+	* mpn/clipper/mul_1.s: New file.
+	* mpn/clipper/add_n.s: New file.
+	* mpn/clipper/sub_n.s: New file.
+	* mpn/configure.in: Handle clipper*-*-*.
+
+	* mpn/configure.in: Recognize rs6000-*-*.
+
+Fri Sep 15 00:41:34 1995  Torbjorn Granlund  <tege@bozo.matematik.su.se>
+
+	* mpn/alpha/add_n.s: New file.
+	* mpn/alpha/sub_n.s: New file.
+
+	* mpn/mips3: New name for mpn/r4000.
+	* mpn/mips2: New name for mpn/r3000.
+	* mpn/configure.in: Corresponding changes.
+
+	* mpn/generic/perfsqr.c (primes): Delete.
+	(residue_map): Delete.
+
+Thu Sep 14 00:07:58 1995  Torbjorn Granlund  <tege@bozo.matematik.su.se>
+
+	* mpn/r3000/sub_n.s: Fix typo.
+
+	* dm_trunc.c: Delete spurious file.
+
+	* mpz/out_binary.c: Fix typo.
+
+	* mpn/configure.in (per-target): Make mips*-*-irix6* imply r4000.
+
+	* gmp-impl.h: For sparc and sgi, include alloca.h.
+
+	* mpn/z8000/mul_1.s: Replace `test r' with `and r,r'.  Replace
+	`ldk r,#0' with `xor r,r'.
+
+Wed Sep  6 00:58:38 1995  Torbjorn Granlund  <tege@bozo.matematik.su.se>
+
+	* mpz/inp_binary.c: New file.
+	* mpz/out_binary.c: New file.
+	* mpz/Makefile.in: Build new files.
+
+Tue Sep  5 22:53:51 1995  Torbjorn Granlund  <tege@bozo.matematik.su.se>
+
+	* gmp.h (__mpz_struct): Change `long int' => `mp_size_t' for alloc
+	and size fields.
+
+Sat Sep  2 17:47:59 1995  Torbjorn Granlund  <tege@bozo.matematik.su.se>
+
+	* mpn/r4000/{add_n.s,sub_n.s}: Optimize away some pointer arithmetic.
+	* mpn/r3000/{add_n.s,sub_n.s,lshift.s,rshift.s}: New files,
+	derived from r4000 code.
+
+Fri Sep  1 05:35:52 1995  Torbjorn Granlund  <tege@bozo.matematik.su.se>
+
+	* mpn/r3000/mul_1.s: Fix typo.
+
+	* mpn/powerpc32: Fix some old vs new mnemonic issues.
+
+	* mpn/powerpc32/{add_n.s,sub_n.s}: New files.
+	* mpn/r4000/{add_n.s,sub_n.s,lshift.s,rshift.s}: New files.
+
+Wed Aug 30 10:43:47 1995  Torbjorn Granlund  <tege@bozo.matematik.su.se>
+
+	* mpn/r3000/mul_1.s ($LC1): Use addiu for immediate add.
+	* mpn/r4000/{mul_1.s,addmul_1.s,submul_1.s}: New files.
+
+	* config.guess: Update to latest FSF revision.
+
+Mon Aug 28 02:18:13 1995  Torbjorn Granlund  <tege@bozo.matematik.su.se>
+
+	* mpz/out_str.c: Cast str to char * in fputs call.
+
+	* gmp-impl.h: Define UQItype, SItype, and USItype also
+	when not __GNUC__.
+
+Fri Aug 25 01:45:04 1995  Torbjorn Granlund  <tege@bozo.matematik.su.se>
+
+	* mpn/i386/syntax.h: Renamed from asm-syntax.h.
+	* mpn/mc68020/syntax.h: Renamed from asm-syntax.h.
+	* mpn/configure.in: Corresponding changes.
+
+Sun Aug 13 19:20:04 1995  Torbjorn Granlund  <tege@bozo.matematik.su.se>
+
+	* mpn/generic/random2.c: Test __hpux, not hpux.
+
+Sat Apr 15 20:50:33 1995  Torbjorn Granlund  (tege@tiny.cygnus.com)
+
+	* mpn/sparc/add_n.S: Make it work for PIC.
+	* mpn/sparc/sub_n.s: Likewise.
+	* mpn/sparc8/addmul_1.S: Likewise.
+	* mpn/sparc8/mul_1.S: Likewise.
+	* mpn/i386/add_n.S: Likewise.
+	* mpn/i386/sub_n.S: Likewise.
+
+Thu Apr 13 23:15:03 1995  Torbjorn Granlund  (tege@tiny.cygnus.com)
+
+	* mpn/configure.in: Don't search power subdir for generic ppc configs.
+	Add some ppc cpu-specific configs.  Misc clean up.
+
+Mon Apr 10 00:16:35 1995  Torbjorn Granlund  (tege@tiny.cygnus.com)
+
+	* mpz/ui_pow_ui.c: Delete spurious code to handle negative results.
+
+Sun Apr  9 12:38:11 1995  Torbjorn Granlund  (tege@tiny.cygnus.com)
+
+	* longlong.h (SPARC v8 udiv_qrnnd): Generate remainder in C,
+	not in asm.
+
+	* mpn/generic/sqrt.c (SQRT): Test for __SOFT_FLOAT.
+
+Tue Mar 28 00:19:52 1995  Torbjorn Granlund  (tege@tiny.cygnus.com)
+
+	* mpn/generic/hamdist.c (popc_limb): Make Mar 16 change here too.
+
+Fri Mar 17 23:29:22 1995  Torbjorn Granlund  (tege@tiny.cygnus.com)
+
+	* longlong.h (SH umul_ppmm): Define.
+
+Thu Mar 16 16:40:44 1995  Torbjorn Granlund  (tege@tiny.cygnus.com)
+
+	* mpn/generic/popcount.c (popc_limb): Rearrange 32 bit case
+	to help CSE.
+
+Fri Mar 10 20:03:49 1995  Torbjorn Granlund  (tege@tiny.cygnus.com)
+
+	* mpn/powerpc32/mul_1.s: Clear cy before entering loop.
+	Rearrange loop to save a cycle.
+	* mpn/powerpc32/addmul_1.s: New file.
+	* mpn/powerpc32/submul_1.s: New file.
+
+Fri Feb 17 22:44:45 1995  Torbjorn Granlund  (tege@tiny.cygnus.com)
+
+	* mpn/configure.in: Set target_makefile_frag for freebsd
+	in new case stmt.
+	* mpn/config/t-freebsd: New file.
+	* mpn/Makefile.in: Add #### for frag insertion.
+	(XCFLAGS): Clear by default.
+	(.c.o, .S.o rules): Pass XCFLAGS.
+
+Tue Feb  7 16:27:50 1995  Torbjorn Granlund  (tege@tiny.cygnus.com)
+
+	* longlong.h (68000 umul_ppmm): Merge improvements from henderson.
+
+Tue Jan 24 04:23:20 1995  Torbjorn Granlund  (tege@tiny.cygnus.com)
+
+	* longlong.h (default umul_ppmm): Store input parameters in temporaries
+	to avoid reading them twice.
+	(default smul_ppmm): New definition.
+
+Thu Dec 29 04:20:07 1994  Jim Meyering  (meyering@comco.com)
+
+	* generic/perfsqr.c (__mpn_perfect_square_p): Remove declaration
+	of unused variable.
+	* generic/pre_mod_1.c (__mpn_preinv_mod_1): Likewise.
+	* mpz/powm.c (pow): Likewise.
+
+	* mpz/and.c (mpz_and): Use {} instead of `;' for empty else clause
+	to placate `gcc -Wall'.
+	* mpz/ior.c (mpz_ior): Likewise.
+
+Wed Dec 28 13:31:40 1994  Torbjorn Granlund  (tege@tiny.cygnus.com)
+
+	* mpn/m*68*/*.S: #include asm-syntax.h, not asm.h.
+
+Mon Dec 26 17:15:36 1994  Torbjorn Granlund  (tege@tiny.cygnus.com)
+
+	* longlong.h: Test for more symbols, in __mc68000__ case.
+
+	* mpn/mpn/config.sub: Recognize m68060.
+	* mpn/configure.in: Change mc* to m* for 68k targets.
+	* mpn/Makefile.in (.S.o): Delete spurious creation of temp .c file.
+
+Mon Dec 19 01:56:30 1994  Torbjorn Granlund  (tege@tiny.cygnus.com)
+
+	* config.sub: Recognize pentium as a valid CPU.
+	* mpn/configure.in: Handle pentium specifically, to use new assembly
+	code.
+
+Mon Dec 19 00:13:01 1994  Jim Meyering  (meyering@comco.com)
+
+	* gmp.h: Define _GMP_H_HAVE_FILE if FILE, __STDIO_H__, or H_STDIO
+	is defined.
+	* gmp.h: test _GMP_H_HAVE_FILE instead of FILE everywhere else.
+
+Mon Dec 19 00:04:54 1994  Kent Boortz  (boortz@sics.se)
+
+	* Makefile.in (recursive makes): Pass CFLAGS.
+
+Sun Dec 18 22:34:49 1994  Torbjorn Granlund  (tege@tiny.cygnus.com)
+
+	* mpn/pentium: New directory.
+
+	* mpz/pprime.c: Make sure to mpz_clear all temporaries.
+
+	* longlong.h: Don't use udiv instruction when SUPERSPARC is defined.
+	* configure.in: Handle supersparc*-.
+	* config/mt-supspc-gcc: New file.
+	* config/mt-sparc8-gcc: New name for mt-sparcv8-gcc.
+
+Mon Dec 12 22:22:10 1994  Torbjorn Granlund  (tege@tiny.cygnus.com)
+
+	* mpn/i386/*.S: #include "asm-syntax.h", not "asm.h".
+	#include sysdep.h before asm-syntax.h.
+
+	* mpn/mc68020/asm-syntax.h: #undef ALIGN before defining it.
+	* mpn/i386/asm-syntax.h: Likewise.
+
+	* mpn/mc68020/asm-syntax.h: New name for asm.h.
+	* mpn/i386/asm-syntax.h: New name for asm.h.
+
+Tue Dec  6 21:55:25 1994  Torbjorn Granlund  (tege@tiny.cygnus.com)
+
+	* mpz/array_init.c: Fix typo in declaration.
+
+Fri Nov 18 19:50:52 1994  Torbjorn Granlund  (tege@tiny.cygnus.com)
+
+	* mpn/Makefile.in (.S.o): Pass CFLAGS and INCLUDES.
+
+Mon Nov 14 00:34:12 1994  Torbjorn Granlund  (tege@tiny.cygnus.com)
+
+	* mpn/generic/random2.c (random): Test for __svr4__.
+
+Wed Oct 12 23:28:16 1994  Torbjorn Granlund  (tege@tiny.cygnus.com)
+
+	* cre-conv-tab.c (main): Avoid upper-case X in printf format string.
+
+Tue Aug 23 17:16:35 1994  Torbjorn Granlund  (tege@tiny.cygnus.com)
+
+	* mpz/perfsqr.c: Use mpn_perfect_square_p.
+	* mpn/generic/perfsqr.c: New file.
+
+Wed Jul  6 13:46:51 1994  Torbjorn Granlund  (tege@tiny.cygnus.com)
+
+	* mpz/array_init.c: New file.
+	* mpz/Makefile.in: Compile array_init.
+	* gmp.h: Declare mpz_array_init.
+
+Mon Jul  4 01:10:03 1994  Torbjorn Granlund  (tege@tiny.cygnus.com)
+
+	* mpz/add.c: Fix bogus comment.
+	* mpz/sub.c: Likewise.
+
+Sat Jul  2 02:14:56 1994  Torbjorn Granlund  (tege@adder.cygnus.com)
+
+	* mpn/generic/pre_mod_1.c: New file.
+	* mpz/perfsqr.c: Use __mpn_preinv_mod_1 when faster.
+
+Fri Jul 01 22:10:19 1994  Richard Earnshaw (rwe11@cl.cam.ac.uk)
+
+	* longlong.h (arm umul_ppmm): Fix typos in last change.  Mark
+	hard-coded registers with "%|"
+
+Thu Jun 30 03:59:33 1994  Torbjorn Granlund  (tege@tiny.cygnus.com)
+
+	* mpz/perfsqr.c: Define PP, etc, for machines with 64 bit limbs.
+	Use __mpn_mod_1.
+	* mpz/perfsqr.c: Don't clobber REM in quadratic residue check loop.
+
+Wed Jun 29 18:45:41 1994  Torbjorn Granlund  (tege@adder.cygnus.com)
+
+	* mpn/generic/sqrt.c (SQRT): New asm for IBM POWER2.
+
+	* mpz/gcd_ui.c: Return 0 if result does not fit an unsigned long.
+
+	* gmp.h: Use "defined (__STDC__)" consistently.
+
+Tue Jun 28 18:44:58 1994  Torbjorn Granlund  (tege@adder.cygnus.com)
+
+	* gmp.h (mpz_get_si): Don't use "signed" keyword for return type.
+
+	* mpz/tests/Makefile.in: Use CFLAGS for linking.
+
+	* Makefile.in (CFLAGS): Use -O2 here.
+	* mpn/Makefile (CFLAGS): Not here.
+
+	* mpq/cmp_ui.c: Fix typo.
+	* mpq/canonicalize.c: Fix typo.
+	* mpz/gcd_ui.c: Handle gcd(0,v) and gcd(u,0) correctly.
+	* mpn/generic/gcd_1.c: Fix braino in last change.
+
+Mon Jun 27 16:10:27 1994  Torbjorn Granlund  (tege@rtl.cygnus.com)
+
+	* mpz/gcd_ui.c: Change return type and return result.
+	Allow destination param to be NULL.
+	* gmp.h: Corresponding change.
+	* mpn/generic/gcd_1.c: Handle zero return from mpn_mod_1.
+
+Tue Jun 14 02:17:43 1994  Torbjorn Granlund  (tege@tiny.cygnus.com)
+
+	* mpn/i386/asm.h (ALIGN): Make it take a parameter.
+	* mpn/i386/*.S: Use ALIGN to align all loops.
+
+	* mpn/i386/*.S: Move colon inside C_GLOBAL_NAME expression.
+	(Makes old versions of GAS happy.)
+
+Sat May 28 01:43:54 1994  Torbjorn Granlund  (tege@adder.cygnus.com)
+
+	* Many files: Delete unused variables and labels.
+	* mpn/generic/dump.c: cast printf width argument to int.
+
+Wed May 25 00:42:37 1994  Torbjorn Granlund  (tege@thepub.cygnus.com)
+
+	* mpz/gcd.c (mpz_gcd): Normalize after __mpn_sub calls.
+	(xmod): Ignore return value of __mpn_divmod.
+	(xmod): Improve normalization code.
+
+Sat May 21 01:30:09 1994  Torbjorn Granlund  (tege@adder.cygnus.com)
+
+	* mpz/gcdext.c: Cosmetic changes.
+
+	* mpz/fdiv_ui.c: New file.
+
+Fri May 20 00:24:53 1994  Torbjorn Granlund  (tege@adder.cygnus.com)
+
+	* mpz/tests/Makefile.in: Use explicit rules for running tests,
+	not a shell loop.
+	(clean): Delete stmp-*.
+
+	* mpz/Makefile.in: Update.
+
+	* mpz/div_ui.c: Don't include longlong.h.
+	* mpz/dm_ui.c: Likewise.
+
+	* mpz/fdiv_q.c, mpz/fdiv_q_ui.c, mpz/fdiv_qr.c, mpz/fdiv_qr_ui.c,
+	mpz/fdiv_r.c, mpz/fdiv_r_ui.c: New files.  Code partly from deleted
+	mdm.c, mdm_ui.c, etc, partly rewritten.
+	* mpz/dm_floor_ui.c, mpz/dm_floor.c: Delete.
+	* mpz/mdm.c, mpz/mdm_ui.c, mpz/mdiv.c, mpz/mdiv_ui.c, mpz/mmod.c,
+	mpz/mmod_ui.c: Delete.
+
+	* mpz/tdiv_q.c, mpz/tdiv_q_ui.c, mpz/tdiv_qr.c, mpz/tdiv_qr_ui.c,
+	mpz/tdiv_r.c, mpz/tdiv_r_ui.c:
+	New names for files implementing truncating division.
+	* mpz/div_ui.c, mpz/dm_ui.c, mpz/mod_ui.c: Simplify.
+
+	* mpn/Makefile.in (.S.o): Don't rely on CPP being defined, use CC
+	instead.
+	(clean): Delete tmp-*.
+
+Thu May 19 01:37:44 1994  Torbjorn Granlund  (tege@adder.cygnus.com)
+
+	* mpz/cmp.c: Call __mpn_cmp.
+
+	* mpz/popcount.c: Fix typo.
+
+	* mpz/powm_ui.c: Simplify main loop.  Keep principal operand size
+	smaller than MSIZE when possible.
+	* mpz/powm.c: Likewise.
+
+	* mpn/generic/sqrt.c: Move alloca calls into where the memory is
+	needed.  Simplify.
+
+	* gmp.h: (_PROTO): New macro.
+	Add many function declarations; use _PROTO macro in all declarations.
+
+	* mpf/*.c: Prepend mpn calls with __.
+
+Wed May 18 20:57:06 1994  Torbjorn Granlund  (tege@adder.cygnus.com)
+
+	* mpf/*ui*.c: Make ui argument `long' for consistency with mpz
+	functions.
+
+	* mpf/div_ui.c: Simplify.
+
+Tue May 17 01:05:14 1994  Torbjorn Granlund  (tege@adder.cygnus.com)
+
+	* mpz/*.c: Prepend mpn calls with __.
+
+	* mpz/mul_ui.c: Use mpn_mul_1.
+
+Mon May 16 17:19:41 1994  Torbjorn Granlund  (tege@adder.cygnus.com)
+
+	* mpn/i386/mul_1.S: Use C_GLOBAL_NAME.
+	* mpn/i386/mul_1.S, mpn/i386/addmul_1.S, mpn/i386/submul_1.S:
+	Nuke use of LAB.
+
+Sat May 14 14:21:02 1994  Torbjorn Granlund  (tege@adder.cygnus.com)
+
+	* gmp-impl.h: Don't define abort here.
+
+	* mpz/pow_ui.c: Increase temporary allocation.
+	* mpz/ui_pow_ui.c: Likewise.
+
+	* gmp.h (mpz_add_1, mpz_sub_1): Don't call memcpy.
+
+	* All Makefile.in: Delete spurious -I arguments.
+	Update dependencies.
+
+	* mpz/popcount.c: New file.
+	* mpz/hamdist.c: New file.
+
+	* All configure: Latest version from Cygnus.
+
+	* mpq/Makefile.in: New file.
+	* mpq/configure.in: New file.
+	* Makefile.in, configure.in: Enable compilation of mpq.
+
+	* mpq/set_z.c: Fix typos.
+	* mpq/canonicalize.c: Fix typos.
+	* mpq/cmp_ui.c: Fix typos.
+
+	* mpf/add_ui.c: Read U->D into UP always.  Delete spurious MPN_COPY.
+	* mpf/sub_ui.c: Likewise.
+
+	* gmp-impl.h: Don't redefine alloca.
+
+	* COPYING.LIB: Renamed from COPYING.
+
+Wed May 11 01:45:44 1994  Torbjorn Granlund  (tege@adder.cygnus.com)
+
+	* mpz/powm_ui.c: When shifting E left by C+1, handle out-of-range
+	shift counts.  Fix typo when testing negative_result.
+	* mpz/powm.c: Likewise.
+
+	* mpz/ui_pow_ui.c: New file.
+	* mpz/Makefile.in: Update.
+
+	* mpz/pow_ui.c: Call __mpn_mul_n instead of __mpn_mul when possible.
+
+	* mpz/div.c, mpz/div_ui.c, mpz/gcd.c: Prefix external mpn calls.
+	* mpz/gcd.c: Declare mpn_xmod.
+
+	* mpz/powm.c: Major changes to accommodate changed mpn semantics.
+	* mpz/powm_ui.c: Update from mpz/powm.c.
+
+	* mpz/tests/tst-io.c: New file.
+	* mpz/tests/tst-logic: New file.
+	* mpz/tests/Makefile.in: Update.
+
+	* mpz/inp_str.c: Get base right when checking for first digit.
+	* mpz/inp_str.c: Allocate more space for DEST when needed.
+
+	* mpz/com.c: Use mpn_add_1 and mpn_sub_1.
+	* mpz/and.c, mpz/ior.c: Likewise.  Simplify somewhat.
+
+	* mpz/add_ui.c: Use mpn_add_1 and mpn_sub_1.
+	Rename parameters to be consistent with mpz/sub_ui.
+	General simplifications.
+	* mpz/sub_ui.x: Likewise.
+
+Tue Aug 10 19:41:16 1993  Torbjorn Granlund  (tege@prudens.matematik.su.se)
+
+	* mpf: New directory.
+	* mpf/*.c: Merge basic set of mpf functions.
+
+	* Many logs missing...
+
+Sun Apr 25 18:40:26 1993  Torbjorn Granlund  (tege@pde.nada.kth.se)
+
+	* memory.c: Use #if instead of #ifdef for __STDC__ for consistency.
+	* bsd/xtom.c: Likewise.
+
+	* mpz/div.c: Remove free_me and free_me_size and their usage.
+	Use mpn_divmod for division; corresponding changes in return value
+	convention.
+	* mpz/powm.c: `carry_digit' => `carry_limb'.
+	* bsd/sdiv.c: Clarify comment.
+
+Sun Apr 25 00:31:28 1993  Torbjorn Granlund  (tege@pde.nada.kth.se)
+
+	* longlong.h (__udiv_qrnnd_c): Make all variables `unsigned long int'.
+
+Sat Apr 24 16:23:33 1993  Torbjorn Granlund  (tege@pde.nada.kth.se)
+
+	* longlong.h (__udiv_qrnnd_c): Make all variables `unsigned long int'.
+
+	* gmp-impl.h: #define ABS.
+	* (Many files): Use ABS instead of abs.
+
+	* mpn/generic/sqrt.c, mpz/clrbit.c, mpz/get_si.c, mpz/mod_2exp.c,
+	mpz/pow_ui.c: Cast 1 to mp_limb before shifting.
+
+	* mpz/perfsqr.c: Use #if, not plain if for exclusion of code for
+	non-32-bit machines.
+
+Tue Apr 20 13:13:58 1993  Torbjorn Granlund  (tege@du.nada.kth.se)
+
+	* mpn/generic/sqrt.c: Handle overflow for intermediate quotients by
+	rounding them down to fit.
+
+	* mpz/perfsqr.c (PP): Define in hexadecimal to avoid GCC warnings.
+
+	* mpz/inp_str.c (char_ok_for_base): New function.
+	(mpz_inp_str): Use it.
+
+Sun Mar 28 21:54:06 1993  Torbjorn Granlund  (tege@cyklop.nada.kth.se)
+
+	* mpz/inp_raw.c: Allocate x_index, not xsize limbs.
+
+Mon Mar 15 11:44:06 1993  Torbjorn Granlund  (tege@pde.nada.kth.se)
+
+	* mpz/pprime.c: Declare param `const'.
+	* gmp.h: Add declarations for mpz_com.
+
+Thu Feb 18 14:10:34 1993  Torbjorn Granlund  (tege@pde.nada.kth.se)
+
+	* mpq/add.c, mpq/sub.c: Call mpz_clear for t.
+
+Fri Feb 12 20:27:34 1993  Torbjorn Granlund  (tege@cyklop.nada.kth.se)
+
+	* mpz/inp_str.c: Recog minus sign as first character.
+
+Wed Feb  3 01:36:02 1993  Torbjorn Granlund  (tege@cyklop.nada.kth.se)
+
+	* mpz/iset.c: Handle 0 size.
+
+Tue Feb  2 13:03:33 1993  Torbjorn Granlund  (tege@cyklop.nada.kth.se)
+
+	* mpz/mod_ui.c: Initialize dividend_size before it's used.
+
+Mon Jan  4 09:11:15 1993  Torbjorn Granlund  (tege@sics.se)
+
+	* bsd/itom.c: Declare param explicitly 'signed'.
+	* bsd/sdiv.c: Likewise.
+
+	* mpq/cmp.c: Remove unused variable tmp_size.
+	* mpz/powm_ui.c: Fix typo in esize==0 if stmt.
+	* mpz/powm.c: Likewise.
+
+Sun Nov 29 01:16:11 1992  Torbjorn Granlund  (tege@sics.se)
+
+	* mpn/generic/divmod_1.c (mpn_divmod_1): Handle
+	divisor_limb == 1 << (BITS_PER_MP_LIMB - 1)
+	specifically.
+
+	* Reorganize sources.  New directories mpn, mpn/MACH, mpn/generic,
+	mpz, mpq, bsd.  Use full file name for change logs hereafter.
+
+Wed Oct 28 17:40:04 1992  Torbjorn Granlund  (tege@jupiter.sics.se)
+
+	* longlong.h (__hppa umul_ppmm): Fix typos.
+	(__hppa sub_ddmmss): Swap input arguments.
+
+	* mpz_perfsqr.c (mpz_perfect_square_p): Avoid , before } in
+	initializator.
+
+Sun Oct 25 20:30:06 1992  Torbjorn Granlund  (tege@jupiter.sics.se)
+
+	* mpz_pprime.c (mpz_probab_prime_p): Handle numbers <= 3
+	specifically (used to consider all negative numbers prime).
+
+	* mpz_powm_ui: `carry_digit' => `carry_limb'.
+
+	* sdiv: Handle zero dividend specifically.  Replace most code in
+	this function with a call to mpn_divmod_1.
+
+Fri Sep 11 22:15:55 1992  Torbjorn Granlund  (tege@tarrega.sics.se)
+
+	* mpq_clear: Don't free the MP_RAT!
+
+	* mpn_lshift, mpn_rshift, mpn_rshiftci: Remove `long' from 4:th arg.
+
+Thu Sep  3 01:47:07 1992  Torbjorn Granlund  (tege@jupiter.sics.se)
+
+	* All files: Remove leading _ from mpn function names.
+
+Wed Sep  2 22:21:16 1992  Torbjorn Granlund  (tege@jupiter.sics.se)
+
+	Fix from Jan-Hein Buhrman:
+	* mpz_mdiv.c, mpz_mmod.c, mpz_mdm.c: Make them work as documented.
+
+	* mpz_mmod.c, mpz_mdm.c: Move decl of TEMP_DIVISOR to reflect its
+	life.
+
+Sun Aug 30 18:37:15 1992  Torbjorn Granlund  (tege@jupiter.sics.se)
+
+	* _mpz_get_str: Use mpz_sizeinbase for computing out_len.
+	* _mpz_get_str: Don't remove leading zeros.  Abort if there are some.
+
+Wed Mar  4 17:56:56 1992  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* gmp.h: Change definition of MP_INT to make the & before params
+	optional.  Use typedef to define it.
+	* mp.h: Use typedef to define MINT.
+
+Tue Feb 18 14:38:39 1992  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	longlong.h (hppa umul_ppmm): Add missing semicolon.  Declare type
+	of __w1 and __w0.
+
+Fri Feb 14 21:33:21 1992  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* longlong.h: Make default count_leading_zeros work for machines >
+	32 bits.  Prepend `__' before local variables to avoid conflicts
+	with users' variables.
+
+	* mpn_dm_1.c: Remove udiv_qrnnd_preinv ...
+	* gmp-impl.h: ... and put it here.
+	* mpn_mod_1: Use udiv_qrnnd_preinv if it is faster than udiv_qrnnd.
+
+Tue Feb 11 17:20:12 1992  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* mpn_mul: Enhance base case by handling small multiplicands.
+	* mpn_dm_1.c: Revert last change.
+
+Mon Feb 10 11:55:15 1992  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* mpn_dm_1.c: Don't define udiv_qrnnd_preinv unless needed.
+
+Fri Feb  7 16:26:16 1992  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* mpn_mul: Replace code for base case.
+
+Thu Feb  6 15:10:42 1992  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* mpn_dm_1.c (_mpn_divmod_1): Add code for avoiding division by
+	pre-inverting divisor.
+
+Sun Feb  2 11:10:25 1992  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* longlong.h: Make __LLDEBUG__ work differently.
+	(_IBMR2): Reinsert old code.
+
+Sat Feb  1 16:43:00 1992  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* longlong.h (#ifdef _IBMR2): Replace udiv_qrnnd with new code
+	using floating point operations.  Don't define
+	UDIV_NEEDS_NORMALIZATION any longer.
+
+Fri Jan 31 15:09:13 1992  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* longlong.h: Define UMUL_TIME and UDIV_TIME for most machines.
+	* longlong.h (#ifdef __hppa): Define umul_ppmm.
+
+Wed Jan 29 16:41:36 1992  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* mpn_cmp: Only one length parameter, assume operand lengths are
+	the same.  Don't require normalization.
+	* mpq_cmp, mpz_add, mpz_sub, mpz_gcd, mpn_mul, mpn_sqrt: Change for
+	new mpn_cmp definition.
+
+Tue Jan 28 11:18:55 1992  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* _mpz_get_str: Fix typo in comment.
+
+Mon Jan 27 09:44:16 1992  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* Makefile.in: Add new files.
+
+	* mpn_dm_1.c: New file with function _mpn_divmod_1.
+	* mpz_dm_ui.c (mpz_divmod_ui): Use _mpn_divmod_1.
+	* mpz_div_ui: Likewise.
+
+	* mpn_mod_1.c: New file with function _mpn_mod_1.
+	* mpz_mod_ui: Use _mpn_mod_1.
+
+Thu Jan 23 18:54:09 1992  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	Bug found by Paul Zimmermann (zimmermann@inria.inria.fr):
+	* mpz_div_ui.c (mpz_div_ui), mpz_dm_ui.c (mpz_divmod_ui):
+	Handle dividend == 0.
+
+Wed Jan 22 12:02:26 1992  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* mpz_pprime.c: Use "" for #include.
+
+Sun Jan 19 13:36:55 1992  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* mpn_rshiftci.c (header): Correct comment.
+
+Wed Jan 15 18:56:04 1992  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* mpz_powm, mpz_powm_ui (if (bsize > msize)): Do alloca (bsize + 1)
+	to make space for ignored quotient at the end.  (The quotient might
+	always be an extra limb.)
+
+Tue Jan 14 21:28:48 1992  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* mpz_powm_ui: Fix comment.
+	* mpz_powm: Likewise.
+
+Mon Jan 13 18:16:25 1992  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* tests/Makefile.in: Prepend $(TEST_PREFIX) to Makefile target.
+
+Sun Jan 12 13:54:28 1992  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	Fixes from Kazumaro Aoki:
+	* mpz_out_raw: Take abs of size to handle negative values.
+	* mpz_inp_raw: Reallocate before reading ptr from X.
+	* mpz_inp_raw: Store, don't read, size to x->size.
+
+Tue Jan  7 17:50:25 1992  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* gmp.h, mp.h: Remove parameter names from prototypes.
+
+Sun Dec 15 00:09:36 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* tests/Makefile.in: Prepend "./" to file names when executing
+	tests.
+
+	* Makefile.in: Fix many problems.
+
+Sat Dec 14 01:00:02 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* mpn_sqrt.c: New file with _mpn_sqrt.
+	* mpz_sqrt, mpz_sqrtrem, mpz_perfect_square_p: Use _mpn_sqrt.
+	* msqrt.c: Delete.  Create from mpz_sqrtrem.c in Makefile.in.
+	* mpz_do_sqrt.c: Delete.
+	* Makefile.in: Update to reflect these changes.
+
+	* Makefile.in, configure, configure.subr: New files
+	(from bothner@cygnus.com).
+	* dist-Makefile: Delete.
+
+	* mpz_fac_ui: Fix comment.
+
+	* mpz_random2: Rewrite a bit to make it possible for the most
+	significant limb to be == 1.
+
+	* mpz_pprime.c (mpz_probab_prime_p): Remove \t\n.
+
+Fri Dec 13 23:10:02 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* mpz_do_sqrt: Simplify special case for U == 0.
+	* m*sqrt*.c, mpz_perfsqr.c (mpz_perfect_square_p):
+	Rename _mpz_impl_sqrt to _mpz_do_sqrt.
+
+Fri Dec 13 12:52:28 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* gmp-impl.h (MPZ_TMP_INIT): Cast to the right type.
+
+Thu Dec 12 22:17:29 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* mpn_add, mpn_sub, mpn_mul, mpn_div: Change type of several
+	variables to mp_size.
+
+Wed Dec 11 22:00:34 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* mpn_rshift.c: Fix header comments.
+
+Mon Dec  9 17:46:10 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	Released 1.2.
+
+	* gmp-impl.h (MPZ_TMP_INIT): Cast alloca return value.
+
+	* dist-Makefile: Add missing dependency for cre-mparam.
+
+	* mpz_mdiv.c, mpz_mmod.c, mpz_mdm.c, mpz_mdiv_ui.c,
+	  mpz_mmod_ui.c, mpz_mdm_ui.c: Remove obsolete comment.
+
+	* dist-Makefile (clean): clean in tests subdir too.
+	* tests/Makefile: Define default values for ROOT and SUB.
+
+	* longlong.h (__a29k__ udiv_qrnnd): Change "q" to "1" for operand
+	2 constraint.
+
+Mon Nov 11 00:06:05 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* mpz_sizeinb.c (mpz_sizeinbase): Special code for size == 0.
+
+Sat Nov  9 23:47:38 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	Released 1.1.94.
+
+	* dist-Makefile, Makefile, tests/Makefile: Merge tests into
+	distribution.
+
+Fri Nov  8 22:57:19 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* gmp.h: Don't use keyword `signed' for non-ANSI compilers.
+
+Thu Nov  7 22:06:46 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* longlong.h: Cosmetic changes to keep it identical to gcc2 version
+	of longlong.h.
+	* longlong.h (__ibm032__): Fix operand order for add_ssaaaa and
+	sub_ddmmss.
+
+Mon Nov  4 00:36:46 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* mpn_mul: Fix indentation.
+
+	* mpz_do_sqrt: Don't assume 32 bit limbs (had constant
+	4294967296.0).
+	* mpz_do_sqrt: Handle overflow in conversion from double returned
+	by SQRT to mp_limb.
+
+	* gmp.h: Add missing function definitions.
+
+Sun Nov  3 18:25:25 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* mpz_pow_ui: Change type of `i' to int.
+
+	* ChangeLog: Add change log entry.
+	* ChangeLog: Add change log entry.
+	* ChangeLog: Add change log entry.
+	* ChangeLog: Add change log entry.
+	* ChangeLog: Add change log entry.
+	* ChangeLog: Add change log entry.
+	* ChangeLog: Add change log entry.
+	* ChangeLog: Add change log entry.
+Stack overflow.
+
+	* mpz_pow_ui.c: Fix typo in comment.
+
+	* dist-Makefile: Create rpow.c from mpz_powm_ui.c.
+	* mpz_powm_ui.c: Add code for rpow.
+	* rpow.c: Delete this file.  The rpow function is now implemented
+	in mpz_powm_ui.c.
+
+	* mpz_fac_ui.c: New file.
+	* gmp.h, dist-Makefile: Add stuff for mpz_fac_ui.
+
+	Bug found by John Amanatides (amana@sasquatch.cs.yorku.ca):
+	* mpz_powm_ui, mpz_powm: Call _mpn_mul in the right way, with
+	the first argument not smaller than the second.
+
+Tue Oct 29 13:56:55 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* cre-conv-tab.c (main), cre-mparam.c (main): Fix typo in output
+	header text.
+
+Mon Oct 28 00:35:29 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* mpz_random2: Handle size == 0.
+
+	* gmp-impl.h (struct __mp_bases): Rename chars_per_limb_exactly to
+	chars_per_bit_exactly, and change its definition.
+	* cre-conv-tab.c (main): Output field according to its new
+	definition.
+	* mpz_out_str, _mpz_get_str, mpz_sizeinb, mout:
+	Use chars_per_bit_exactly.
+
+	* mpz_random2: Change the loop termination condition in order to
+	get a large most significant limb with higher probability.
+
+	* gmp.h: Add declaration of new mpz_random2 and mpz_get_si.
+	* mpz_get_si.c: New file.
+	* dist-Makefile: Add mpz_random2 and mpz_get_si.
+
+	* mpz_sizeinb.c (mpz_sizeinbase): Special code for base being a
+	power of 2, giving exact result.
+
+	* mpn_mul: Fix MPN_MUL_VERIFY in various ways.
+	* mpn_mul: New macro KARATSUBA_THRESHOLD.
+	* mpn_mul (karatsuba's algorithm): Don't write intermediate results
+	to prodp, use temporary pp instead.  (Intermediate results can be
+	larger than the final result, possibly writing into hyperspace.)
+	* mpn_mul: Make smarter choice between Karatsuba's algorithm and the
+	shortcut algorithm.
+	* mpn_mul: Fix typo, cy instead of xcy.  Unify carry handling code.
+
+Sun Oct 27 19:57:32 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* mpn_mul: In non-classical case, choose Karatsuba's algorithm only
+	when usize > 1.5 vsize.
+
+	* mpn_mul: Break between classical and Karatsuba's algorithm at
+	KARATSUBA_THRESHOLD, if defined.  Default to 8.
+
+	* mpn_div: Kludge to fix stray memory read.
+
+Sat Oct 26 20:06:14 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* mpz_gcdext: Handle a = b = 0.  Remove memory leakage by calling
+	mpz_clear for all temporary variables.
+
+	* mpz_gcd: Reduce w_bcnt in _mpn_lshift call to hold that
+	function's argument constraints.  Compute wsize correctly.
+
+	* mpz_gcd: Fix typo in comment.
+
+	* memory.c (_mp_default_allocate, _mp_default_reallocate): Call
+	abort if allocation fails, don't just exit.
+
+Fri Oct 25 22:17:20 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* mpz_random2.c: New file.
+
+Thu Oct 17 18:06:42 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	Bugs found by Pierre-Joseph Gailly (pjg@sunbim.be):
+	* mpq_cmp: Take sign into account, don't just compare the
+	magnitudes.
+	* mpq_cmp: Call _mpn_mul in the right way, with the first argument
+	not smaller than the second.
+
+Wed Oct 16 19:27:32 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* mpz_random: Ensure the result is normalized.
+
+Tue Oct 15 14:55:13 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* mpz_clrbit: Support non-ANSI compilers.
+
+Wed Oct  9 18:03:28 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* longlong.h (68k add_ssaaaa, sub_ddmmss): Generalize constraints.
+
+Tue Oct  8 17:42:59 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* mpz_mdm_ui: Add comments.
+
+	* mpz_mdiv: Use MPZ_TMP_INIT instead of mpz_init.
+	* mpz_init_ui: Change spacing and header comment.
+
+Thu Oct  3 18:36:13 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* dist-Makefile: Prepend `./' before some filenames.
+
+Sun Sep 29 14:02:11 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	Released 1.1 (public).
+
+	* mpz_com: New name of mpz_not.
+	* dist-Makefile: Change mpz_not to mpz_com.
+
+Tue Sep 24 12:44:11 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* longlong.h: Fix header comment.
+
+Mon Sep  9 15:16:24 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	Released 1.0.92.
+
+	* mpn_mul.c (_mpn_mul): Handle leading zero limbs in non-Karatsuba
+	case.
+
+	* longlong.h (m68000 umul_ppmm): Clobber one register less by
+	slightly rearranging the code.
+
+Sun Sep  1 18:53:25 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* dist-Makefile (stamp-stddefh): Fix typo.
+
+Sat Aug 31 20:41:31 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	Released 1.0.91.
+
+	* mpz_mdiv.c, mpz_mmod.c, mpz_mdm.c, mpz_mdiv_ui.c,
+	  mpz_mmod_ui.c, mpz_mdm_ui.c: New files and functions.
+	* gmp.h, gmp.texi: Define the new functions.
+
+Fri Aug 30 08:32:56 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* mpz_gcdext: Compute t argument from the other quantities at the
+	  end, of the function, not in the loop.  New feature: Allow t to be
+	  NULL.
+
+	* mpz_add.c, mpz_sub.c, mpz_mul.c, mpz_powm.c, mpz_gcd.c: Don't
+	  include "mp.h".  Use type name `MP_INT' always.
+
+	* dist-Makefile, mpz_cmp.c: Merge mcmp.c from mpz_cmp.c.
+
+Wed Aug 28 00:45:11 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* dist-Makefile (documentation): Go via tmp.texi to avoid the
+	  creation of gmp.dvi if any errors occur.  Make tex read input
+	  from /dev/null.
+
+Fri Aug 23 15:58:52 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* longlong.h (68020, i386): Don't define machine-dependent
+	  __umulsidi3 (so the default definition is used).
+	* longlong.h (all machines): Cast all operands, sources and
+	  destinations, to `unsigned long int'.
+	* longlong.h: Add gmicro support.
+
+Thu Aug 22 00:28:29 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* longlong.h: Rename BITS_PER_LONG to LONG_TYPE_SIZE.
+	* longlong.h (__ibm032__): Define count_leading_zeros and umul_ppmm.
+	* longlong.h: Define UMUL_TIME and UDIV_TIME for some CPUs.
+	* _mpz_get_str.c: Add code to do division by big_base using only
+	  umul_qrnnd, if that is faster.  Use UMUL_TIME and UDIV_TIME to
+	  decide which variant to use.
+
+Wed Aug 21 15:45:23 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* longlong.h (__sparc__ umul_ppmm): Move two insn from end to the
+	  nops.  (Saves two insn.)
+
+	* longlong.h (__sparc__ umul_ppmm): Rewrite in order to avoid
+	  branch, and to permit input/output register overlap.
+
+	* longlong.h (__29k__): Remove duplicated udiv_qrnnd definition.
+	* longlong.h (__29k__ umul_ppmm): Split asm instructions into two
+	  asm statements (gives better code if either the upper or lower
+	  part of the product is unused.
+
+Tue Aug 20 17:57:59 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* _mpz_get_str.c (outside of functions): Remove
+	  num_to_ascii_lower_case and num_to_ascii_upper_case.  Use string
+	  constants in the function instead.
+
+Mon Aug 19 00:37:42 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* cre-conv-tab.c (main): Output table in hex.  Output 4 fields, not
+	  3, for components 0 and 1.
+
+	* gmp.h: Add declaration of mpq_neg.
+
+	Released 1.0beta.13.
+
+	* _mpz_set_str.c (mpz_set_str): Cast EOF and SPC to char before
+	  comparing to enum literals SPC and EOF.  This makes the code work
+	  for compilers where `char' is unsigned.  (Bug found by Brian
+	  Beuning).
+
+	Released 1.0beta.12.
+
+	* mpz_mod_ui: Remove references to quot.  Remove quot_ptr, quot_size
+	  declarations and assignment code.
+
+Sun Aug 18 14:44:26 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* mpz_mod_ui: Handle dividend < 0.
+
+	Released 1.0beta.11.
+
+	* mpz_dm_ui, mpz_div_ui, mpz_mod_ui, sdiv: Make them share the same
+	  general structure, variable names, etc.
+
+	* sdiv: Un-normalize the remainder in n1 before it is negated.
+
+	* longlong.h: Mention UDIV_NEEDS_NORMALIZATION in description of
+	  udiv_qrnnd.
+
+	* mpz_dm_ui.c (mpz_divmod_ui), mpz_div_ui.c (mpz_div_ui): Increment
+	  the quotient size if the dividend size is incremented.  (Bug found
+	  by Brian Beuning.)
+
+	* mpz_mod_ui: Shift back the remainder, if UDIV_NEEDS_NORMALIZATION.
+	  (Bug found by Brian Beuning.)
+
+	* mpz_mod_ui: Replace "digit" by "limb".
+
+	* mpz_perfsqr.c (mpz_perfect_square_p): Disable second test case
+	  for non-32-bit machines (PP is hardwired for such machines).
+	* mpz_perfsqr.c (outside of functions): Define PP value with an L.
+
+	* mpn_mul.c (_mpn_mul): Add verification code that is activated if
+	  DEBUG is defined.  Replace "digit" by "limb".
+	* mpn_mul.c (_mpn_mul: Karatsuba's algorithm: 4.): Normalize temp
+	  after the addition.
+	* mpn_mul.c (_mpn_mul: Karatsuba's algorithm: 1.): Compare u0_size
+	  and v0_size, and according to the result, swap arguments in
+	  recursive call.  (Don't violate mpn_mul's own argument
+	  constraints.)
+
+Fri Aug 16 13:47:12 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	Released 1.0beta.10.
+
+	* longlong.h (IBMR2): Add udiv_qrnnd.
+
+	* mpz_perfsqr: Remove unused variables.
+
+	* mpz_and (case for different signs): Initialize loop variable i!
+
+	* dist-Makefile: Update automatically generated dependencies.
+	* dist-Makefile (madd.c, msub.c, pow.c, mult.c, gcd.c): Add mp.h,
+	  etc to dependency file lists.
+
+	* longlong.h (add_ssaaaa, sub_ddmmss [C default versions]): Make __x
+	  `unsigned long int'.
+	* longlong.h: Add `int' after `unsigned' and `long' everywhere.
+
+Wed Aug 14 18:06:48 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* longlong.h: Add ARM, i860 support.
+
+	* mpn_lshift, mpn_rshift, mpn_rshiftci: Rename *_word with *_limb.
+
+Tue Aug 13 21:57:43 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* _mpz_get_str.c, _mpz_set_str.c, mpz_sizeinb.c (mpz_sizeinbase),
+	  mpz_out_str.c, mout.c: Remove declaration of __mp_bases.
+	* gmp-impl.h: Put it here, and make it `const'.
+	* cre-conv-tab.c (main): Make struct __mp_bases `const'.
+
+Mon Aug 12 17:11:46 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* cre-conv-tab.c (main): Use %lu in printf for long ints.
+
+	* dist-Makefile: Fix cre-* dependencies.
+
+	* cre-conv-tab.c (main): Output field big_base_inverted.
+
+	* gmp-impl.h (struct bases): New field big_base_inverted.
+	* gmp-impl.h (struct bases): Change type of chars_per_limb_exactly
+	  to float (in order to keep the structure smaller).
+
+	* mp.h, gmp.h: Change names of macros for avoiding multiple
+	  includes.
+
+Fri Aug  9 18:01:36 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* _mpz_get_str: Only shift limb array if normalization_steps != 0
+	  (optimization).
+
+	* longlong.h (sparc umul_ppmm): Use __asm__, not asm.
+	* longlong.h (IBMR2 umul_ppmm): Refer to __m0 and __m1, not to m0
+	  and m1 (overlap between output and input operands did not work).
+	* longlong.h: Add VAX, ROMP and HP-PA support.
+	* longlong.h: Sort the machine dependent code in alphabetical order
+	  on the CPU name.
+	* longlong.h: Hack comments.
+
+Thu Aug  8 14:13:36 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	Released 1.0beta.9.
+
+	* longlong.h: Define BITS_PER_LONG to 32 if it's not already
+	  defined.
+	* Define __BITS4 to BITS_PER_LONG / 4.
+	* Don't assume 32 bit word size in "count_leading_zeros" C macro.
+	  Use __BITS4 and BITS_PER_LONG instead.
+
+	* longlong.h: Don't #undef internal macros (reverse change of Aug 3).
+
+	* longlong.h (68k): Define add_ssaaaa sub_ddmmss, and umul_ppmm
+	  even for plain mc68000.
+
+	* mpq_div: Flip the sign of the numerator *and* denominator of the
+	  result if the intermediate denominator is negative.
+
+	* mpz_and.c, mpz_ior.c: Use MPN_COPY for all copying operations.
+
+	* mpz_and.c: Compute the result size more conservatively.
+	* mpz_ior.c: Likewise.
+
+	* mpz_realloc: Never allocate zero space even if NEW_SIZE == 0.
+
+	* dist-Makefile: Remove madd.c, msub.c, pow.c, mult.c, gcd.c from
+	  BSDMP_SRCS.
+
+	* dist-Makefile: Create mult.c from mpz_mul.c.
+	* mult.c: Delete this file.
+
+	* _mpz_set_str: Normalize the result (for bases 2, 4, 8... it was
+	  not done properly if the input string had many leading zeros).
+
+Sun Aug  4 16:54:14 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* dist-Makefile (gcd.c, pow.c, madd.c, msub.c): Make these targets
+	  work with VPATH and GNU MP.
+
+	* mpz_gcd: Don't call mpz_set; inline its functionality.
+
+	* mpq_mul, mpq_div: Fix several serious typos.
+
+	* mpz_dmincl, mpz_div: Don't normalize the quotient if it's already
+	  zero.
+
+	* mpq_neg.c: New file.
+
+	* dist-Makefile: Remove obsolete dependencies.
+
+	* mpz_sub: Fix typo.
+
+	Bugs found by Pierre-Joseph Gailly (pjg@sunbim.be):
+	* mpq_mul, mpq_div: Initialize tmp[12] variables even when the gcd
+	  is just 1.
+	* mpz_gcd: Handle gcd(0,v) and gcd(u,0) in special cases.
+
+Sat Aug  3 23:45:28 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* longlong.h: Clean up comments.
+	* longlong.h: #undef internal macros.
+
+Fri Aug  2 18:29:11 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* mpq_set_si, mpq_set_ui: Canonicalize 0/x to 0/1.
+	* mpq_set_si, mpq_set_ui: Cosmetic formatting changes.
+
+	* mpz_dmincl.c: Normalize the remainder before shifting it back.
+
+	* mpz_dm_ui.c (mpz_divmod_ui): Handle rem == dividend.
+
+	* mpn_div.c: Fix comment.
+
+	* mpz_add.c, mpz_sub.c: Use __MP_INT (not MP_INT) for intermediate
+	  type, in order to work for both GNU and Berkeley functions.
+
+	* dist-Makefile: Create gcd.c from mpz_gcd.c, pow.c from mpz_powm,
+	  madd.c from mpz_add.c, msub.c from mpz_sub.c.
+	  respectively.
+	* pow.c, gcd.c, mpz_powmincl.c, madd.c, msub.c: Remove these.
+	* mpz_powm.c, mpz_gcd.c, mpz_add.c, mpz_sub.c: #ifdef for GNU and
+	  Berkeley function name variants.
+	* dist-Makefile: Add created files to "clean" target.
+
+Tue Jul 16 15:19:46 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* mpq_get_den: No need for absolute value of the size, the
+	  denominator is always positive.
+
+	* mpz_get_ui: If the operand is zero, return zero.  Don't read the
+	  limb array!
+
+	* mpz_dmincl.c: Don't ignore the return value from _mpn_rshift, it
+	  is the size of the remainder.
+
+Mon Jul 15 11:08:05 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* Several files: Remove unused variables and functions.
+
+	* gmp-impl.h: Declare _mpz_impl_sqrt.
+
+	* mpz_dm_ui (mpz_divmod_ui), sdiv: Shift back the remainder if
+	  UDIV_NEEDS_NORMALIZATION.  (Fix from Brian Beuning.)
+
+	* mpz_dm_ui.c, sdiv: Replace *digit with *limb.
+
+	* mpz_ior: Add missing else statement in -OP1 | -OP2 case.
+	* mpz_ior: Add missing else statement in OP1 | -OP2 case.
+	* mpz_ior: Swap also OP1 and OP2 pointers in -OP1 & OP2 case.
+	* mpz_ior: Duplicate _mpz_realloc code.
+
+	* mpz_and: Add missing else statement in -OP1 & -OP2 case.
+	* mpz_and: Rewrite OP1 & -OP2 case.
+	* mpz_and: Swap also OP1 and OP2 pointers in -OP1 & OP2 case.
+
+	* mpz_gcdext: Loop in d1.size (not b->size).  (Fix from Brian
+	  Beuning.)
+
+	* mpz_perfsqr: Fix argument order in _mpz_impl_sqrt call.  (Fix from
+	  Brian Beuning.)
+
+Fri Jul 12 17:10:33 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* mpq_set.c, mpq_set_ui.c, mpq_set_si.c, mpq_inv.c,
+	  mpq_get_num.c, mpq_get_den.c, mpq_set_num.c, mpq_set_den.c:
+	  New files.
+
+	* mpz_dmincl.c: Remove second re-allocation of rem->d.  It
+	  was never executed.
+
+	* dist-Makefile: Use `-r' instead of `-x' for test for ranlib (as
+	  some unixes' test doesn't have the -r option).
+
+	* *.*: Cast allocated pointers to the appropriate type (makes old C
+	  compilers happier).
+
+	* cre-conv-tab.c (main): Divide max_uli by 2 and multiply again
+	  after conversion to double.  (Kludge for broken C compilers.)
+
+	* dist-Makefile (stamp-stddefh): New target.  Test if "stddef.h"
+	  exists in the system and creates a minimal one if it does not
+	  exist.
+	* cre-stddefh.c: New file.
+	* dist-Makefile: Make libgmp.a and libmp.a depend on stamp-stddefh.
+	* dist-Makefile (clean): Add some more.
+	* gmp.h, mp.h: Unconditionally include "stddef.h".
+
+Thu Jul 11 10:08:21 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* min: Do ungetc of last read character.
+	* min.c: include stdio.h.
+
+	* dist-Makefile: Go via tmp- files for cre* redirection.
+	* dist-Makefile: Add tmp* to "clean" target.
+
+	* dist-Makefile: Use LOCAL_CC for cre*, to simplify cross
+	  compilation.
+
+	* gmp.h, mp.h: Don't define NULL here.
+	* gmp-impl.h: Define it here.
+
+Wed Jul 10 14:13:33 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* mpz_mod_2exp: Don't copy too much, overwriting most significant
+	  limb.
+
+	* mpz_and, mpz_ior: Don't read op[12]_ptr from op[12] when
+	  reallocating res, if op[12]_ptr got their value from alloca.
+
+	* mpz_and, mpz_ior: Clear up comments.
+
+	* cre-mparam.c: Output parameters for `short int' and `int'.
+
+	* mpz_and, mpz_ior: Negate negative op[12]_size in several places.
+
+Tue Jul  9 18:40:30 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* gmp.h, mp.h: Test for _SIZE_T defined before typedef'ing size_t.
+	  (Fix for Sun lossage.)
+
+	* gmp.h: Add declaration of mpq_clear.
+
+	* dist-Makefile: Check if "ranlib" exists, before using it.
+	* dist-Makefile: Add mpz_sqrtrem.c and mpz_size.c.
+	* mpz_powm: Fix typo, "pow" instead of "mpz_powm".
+
+Fri Jul  5 19:08:09 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* move: Remove incorrect comment.
+
+	* mpz_free, mpq_free: Rename to *_clear.
+	* dist-Makefile: Likewise.
+	* mpq_add, mpq_sub, mpq_mul, mpq_div: Likewise.
+
+	* mpz_dmincl.c: Don't call "move", inline its functionality.
+
+Thu Jul  4 00:06:39 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* Makefile: Include dist-Makefile.  Fix dist target to include
+	  dist-Makefile (with the name "Makefile" in the archive).
+
+	* dist-Makefile: New file made from Makefile.  Add new mpz_...
+	  functions.
+
+	* mpz_powincl.c New file for mpz_powm (Berkeley MP pow)
+	  functionality.  Avoids code duplication.
+	* pow.c, mpz_powm.c: Include mpz_powincl.c
+
+	* mpz_dmincl.c: New file containing general division code.  Avoids
+	  code duplication.
+	* mpz_dm.c (mpz_divmod), mpz_mod.c (mpz_mod), mdiv.c (mdiv): Include
+	  mpz_dmincl.c.
+
+	* _mpz_get_str: Don't call memmove, unless HAS_MEMMOVE is defined.
+	  Instead, write the overlapping memory copying inline.
+
+	* mpz_dm_ui.c: New name for mpz_divmod_ui.c (SysV file name limit).
+
+	* longlong.h: Don't use #elif.
+	* mpz_do_sqrt.c: Likewise.
+
+	* longlong.h: Use __asm__ instead of asm.
+	* longlong.h (sparc udiv_qrnnd): Make it to one string over several
+	  lines.
+
+	* longlong.h: Preend __ll_ to B, highpart, and lowpart.
+
+	* longlong.h: Move array t in count_leading_zeros to the new file
+	  mp_clz_tab.c.  Rename the array __clz_tab.
+	* All files: #ifdef for traditional C compatibility.
+
+Wed Jul  3 11:42:14 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* mpz_and: Initialize res_ptr always (used to be initialized only
+	  when reallocating).
+
+	* longlong.h (umul_ppmm [C variant]): Make __ul...__vh
+	  `unsigned int', and cast the multiplications.  This way
+	  compilers more easily can choose cheaper multiplication
+	  instructions.
+
+	* mpz_mod_2exp: Handle input argument < modulo argument.
+	* mpz_many: Make sure mp_size is the type for sizes, not int.
+
+	* mpz_init, mpz_init_set*, mpq_init, mpq_add, mpq_sub, mpq_mul,
+	  mpq_div: Change mpz_init* interface.  Structure pointer as first
+	  arg to initialization function, no longer *return* struct.
+
+Sun Jun 30 19:21:44 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* Rename mpz_impl_sqrt.c to mpz_do_sqrt.c to satisfy SysV 14
+	  character file name length limit.
+
+	* Most files: Rename MINT to MP_INT.  Rename MRAT to MP_RAT.
+	* mpz_sizeinb.c: New file with function mpz_sizeinbase.
+	* mp_bases.c: New file, with array __mp_bases.
+	* _mpz_get_str, _mpz_set_str: Remove struct bases, use extern
+	  __mp_bases instead.
+	* mout, mpz_out_str: Use array __mp_bases instead of function
+	  _mpz_get_cvtlen.
+	* mpz_get_cvtlen.c: Remove.
+	* Makefile: Update.
+
+Sat Jun 29 21:57:28 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* longlong.h (__sparc8__ umul_ppmm): Insert 3 nop:s for wr delay.
+	* longlong.h (___IBMR2__): Define umul_ppmm, add_ssaaaa, sub_ddmmss.
+	* longlong.h (__sparc__): Don't call .umul; expand asm instead.
+	  Don't define __umulsidi3 (i.e. use default definition).
+
+Mon Jun 24 17:37:23 1991  Torbjorn Granlund  (tege@amon.sics.se)
+
+	* _mpz_get_str.c (num_to_ascii_lower_case, num_to_ascii_upper_case):
+	  Swap 't' and 's'.
+
+Sat Jun 22 13:54:01 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* mpz_gcdext.c: New file.
+
+	* mpn_mul: Handle carry and unexpected operand sizes in last
+	  additions/subtractions.  (Bug trigged when v1_size == 1.)
+
+	* mp*_alloc*: Rename functions to mp*_init* (files to mp*_iset*.c).
+	* mpq_*: Call mpz_init*.
+
+	* mpz_pow_ui, rpow: Use _mpn_mul instead of mult.  Restructure.
+
+Wed May 29 20:32:33 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* mpz_get_cvtlen: multiply by size.
+
+Sun May 26 15:01:15 1991  Torbjorn Granlund  (tege@bella.nada.kth.se)
+
+	Alpha-release 0.95.
+
+	Fixes from Doug Lea (dl@g.oswego.edu):
+	* mpz_mul_ui: Loop to MULT_SIZE (not PROD_SIZE).  Adjust PROD_SIZE
+	  correctly.
+	* mpz_div: Prepend _ to mpz_realloc.
+	* mpz_set_xs, mpz_set_ds: Fix typos in function name.
+
+Sat May 25 22:51:16 1991  Torbjorn Granlund  (tege@bella.nada.kth.se)
+
+	* mpz_divmod_ui: New function.
+
+	* sdiv: Make the sign of the remainder correct.
+
+Thu May 23 15:28:24 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* Alpha-release 0.94.
+
+	* mpz_mul_ui: Include longlong.h.
+
+	* mpz_perfsqr.c (mpz_perfect_square_p): Call _mpz_impl_sqrt instead
+	  of msqrt.
+
+	* mpz_impl_sqrt: Don't call "move", inline its functionality.
+
+	* mdiv: Use MPN_COPY instead of memcpy.
+	* rpow, mpz_mul, mpz_mod_2exp: Likewise.
+	* pow.c: Likewise, and fix bug in the size arg.
+
+	* xtom: Don't use mpz_alloc, inline needed code instead.  Call
+	  _mpz_set_str instead of mpz_set_str.
+
+	* Makefile: Make two libraries, libmp.a and libgmp.a.
+
+Thu May 22 20:25:29 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* Add manual to distribution.
+	* Fold in many missing routines described in the manual.
+	* Update Makefile.
+
+Wed May 22 13:48:46 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* mpz_set_str: Make it handle 0x prefix OK.
+
+Sat May 18 18:31:02 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* memory.c (_mp_default_reallocate): Swap OLD_SIZE and NEW_SIZE
+	  arguments.
+	* mpz_realloc (_mpz_realloc): Swap in call to _mp_reallocate_func.
+	* min: Likewise.
+
+Thu May 16 20:43:05 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* memory.c: Make the default allocations functions global.
+	* mp_set_fns (mp_set_memory_functions): Make a NULL pointer mean the
+	  default memory function.
+
+Wed May  8 20:02:42 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* mpz_div: Handle DEN the same as QUOT correctly by copying DEN->D
+	  even if no normalization is needed.
+	* mpz_div: Rework reallocation scheme, to avoid excess copying.
+
+	* mpz_sub_ui.c, mpz_add_ui.c: New files.
+
+	* mpz_cmp.c, mpz_cmp_ui.c: New files.
+
+	* mpz_mul_2exp: Handle zero input MINT correctly.
+
+	* mpn_rshiftci: Don't handle shift counts > BITS_PER_MP_DIGIT.
+
+	* mpz_out_raw.c, mpz_inp_raw.c: New files for raw I/O.
+
+Tue May  7 15:44:58 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* mpn_rshift: Don't handle shift counts > BITS_PER_MP_DIGIT.
+	* mpz_div_2exp: Don't call _mpn_rshift with cnt > BITS_PER_MP_DIGIT.
+	* gcd, mpz_gcd: Likewise.
+
+	* gcd, mpz_gcd: Handle common 2 factors correctly.
+
+Mon May  6 20:22:59 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* gmp-impl.h (MPN_COPY): Inline a loop instead of calling memcpy.
+
+	* gmp-impl.h, mpz_get_str, rpow: Swap DST and SRC in TMPCOPY* macros.
+
+Sun May  5 15:16:23 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* mpz_div: Remove test for QUOT == 0.
+
+Sun Apr 28 20:21:04 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* pow: Don't make MOD normalization in place, as it's a bad idea to
+	  write on an input parameter.
+	* pow: Reduce BASE if it's > MOD.
+	* pow, mult, mpz_mul: Simplify realloc code.
+
+Sat Apr 27 21:03:11 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* Install multiplication using Karatsuba's algorithm as default.
+
+Fri Apr 26 01:03:57 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* msqrt: Store in ROOT even for U==0, to make msqrt(0) defined.
+
+	* mpz_div_2exp.c, mpz_mul_2exp.c: New files for shifting right and
+	  left, respectively.
+	* gmp.h: Add definitions for mpz_div_2exp and mpz_mul_2exp.
+
+	* mlshift.c, mrshift.c: Remove.
+
+Wed Apr 24 21:39:22 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* mpn_mul: Check only for m2_size == 0 in function header.
+
+Mon Apr 22 01:31:57 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* karatsuba.c: New file for Karatsuba's multiplication algorithm.
+
+	* mpz_random, mpz_init, mpz_mod_2exp: New files and functions.
+
+	* mpn_cmp: Fix header comment.
+
+Sun Apr 21 00:10:44 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* pow: Switch off initial base reduction.
+
+Sat Apr 20 22:06:05 1991  Torbjorn Granlund  (tege@echnaton.sics.se)
+
+	* mpz_get_str: Don't generate initial zeros for initial word.
+	  Used to write outside of allocated storage.
+
+Mon Apr 15 15:48:08 1991  Torbjorn Granlund  (tege@zevs.sics.se)
+
+	* _mpz_realloc: Make it accept size in number of mp_digits.
+	* Most functions: Use new _mpz_realloc definition.
+
+	* mpz_set_str: Remove calls _mp_free_func.
+
+	* Most functions: Rename mpn_* to _mpn_*.  Rename mpz_realloc to
+	  _mpz_realloc.
+	* mpn_lshift: Redefine _mpn_lshift to only handle small shifts.
+	* mdiv, mpz_div, ...: Changes for new definition of _mpn_lshift.
+	* msqrt, mp*_*shift*: Define cnt as unsigned (for speed).
+
+Sat Apr  6 14:05:16 1991  Torbjorn Granlund  (tege@musta.nada.kth.se)
+
+	* mpn_mul: Multiply by the first digit in M2 in a special
+	  loop instead of zeroing the product area.
+
+	* mpz_abs.c: New file.
+
+	* sdiv: Implement as mpz_div_si for speed.
+
+	* mpn_add: Make it work for second source operand == 0.
+
+	* msub: Negate the correct operand, i.e. V before swapping, not
+	  the smaller of U and V!
+	* madd, msub: Update abs_* when swapping operands, and not after
+	  (optimization).
+
+Fri Apr  5 00:19:36 1991  Torbjorn Granlund  (tege@black.nada.kth.se)
+
+	* mpn_sub: Make it work for subtrahend == 0.
+
+	* madd, msub: Rewrite to minimize mpn_cmp calls.  Ensure
+	  mpn_cmp is called with positive sizes (used to be called
+	  incorrectly with negative sizes sometimes).
+
+	* msqrt: Make it divide by zero if fed with a negative number.
+	* Remove if statement at end of precision calculation that was
+	  never true.
+
+	* itom, mp.h: The argument is of type short, not int.
+
+	* mpz_realloc, gmp.h: Make mpz_realloc return the new digit pointer.
+
+	* mpz_get_str.c, mpz_set_str.c, mpz_new_str.c: Don't include mp.h.
+
+	* Add COPYING to distribution.
+
+	* mpz_div_ui.c, mpz_div_si.c, mpz_new_ui.c, mpz_new_si.c: New files.
+
+Fri Mar 15 00:26:29 1991  Torbjorn Granlund  (tege@musta.nada.kth.se)
+
+	* Add Copyleft headers to all files.
+
+	* mpn_mul.c, mpn_div.c: Add header comments.
+	* mult.c, mdiv.c: Update header comments.
+
+	* mpq_add.c, mpq_sub.c, mpq_div.c, mpq_new.c, mpq_new_ui.c,
+	  mpq_free.c: New files for rational arithmetics.
+
+	* mpn_lshift.c: Avoid writing the most significant word if it is 0.
+
+	* mdiv.c: Call mpn_lshift for the normalization.
+	* mdiv.c: Remove #ifdefs.
+
+	* Makefile: Add ChangeLog to DISTFILES.
+
+	* mpn_div.c: Make the add_back code work (by removing abort()).
+	* mpn_div.c: Make it return if the quotient is size as compared
+	  with the difference NSIZE - DSIZE.  If the stored quotient is
+	  larger than that, return 1, otherwise 0.
+	* gmp.h: Fix mpn_div declaration.
+	* mdiv.c: Adopt call to mpn_div.
+	* mpz_div.c: New file (developed from mdiv.c).
+
+	* README: Update routine names.
+
+Thu Mar 14 18:45:28 1991  Torbjorn Granlund  (tege@musta.nada.kth.se)
+
+	* mpq_mul.c: New file for rational multiplication.
+
+	* gmp.h: Add definitions for rational arithmetics.
+
+	* mpn_div: Kludge the case where the high numerator digit > the
+	  high denominator digit.  (This code is going to be optimized later.)
+
+	* New files: gmp.h for GNU specific functions, gmp-common.h for
+	  definitions common for mp.h and gmp.h.
+
+	* Ensure mp.h just defines what BSD mp.h defines.
+
+	* pow.c: Fix typo for bp allocation.
+
+	* Rename natural number functions to mpn_*, integer functions to
+	  mpz_*.
+
+Tue Mar  5 18:47:04 1991  Torbjorn Granlund  (tege@musta.nada.kth.se)
+
+	* mdiv.c (_mp_divide, case 2): Change test for estimate of Q from
+	  "n0 >= r" to "n0 > r".
+
+	* msqrt: Tune the increasing precision scheme, to do fewer steps.
+
+Tue Mar  3 18:50:10 1991  Torbjorn Granlund  (tege@musta.nada.kth.se)
+
+	* msqrt: Use the low level routines.  Use low precision in the
+	beginning, and increase the precision as the result converges.
+	(This optimization gave a 6-fold speedup.)
diff --git a/third_party/gmp/INSTALL b/third_party/gmp/INSTALL
new file mode 100644
index 0000000..75199a1
--- /dev/null
+++ b/third_party/gmp/INSTALL
@@ -0,0 +1,80 @@
+Copyright 1996, 1997, 1999-2002, 2006 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.
+
+
+
+
+
+                          INSTALLING GNU MP
+                          =================
+
+
+These instructions are only for the impatient.  Others should read the install
+instructions in gmp.info.  Use
+
+	info -f doc/gmp.info
+
+from the gmp source directory.
+
+Here are some brief instructions on how to install GMP.  First you need to
+compile.  Since you're impatient, try this
+
+	./configure
+	make
+	make check		<= VERY IMPORTANT!!
+
+If that fails, or you care about the performance of GMP, you need to read the
+full instructions in the chapter "Installing GMP" in the manual.
+
+You should not skip the "make check" part; the risk that the GMP sources are
+miscompiled are unfortunately quite high.  And if they indeed are, "make check"
+is very likely to trigger the compiler-introduced bug.
+
+Optionally, you can install the library with the following command.  This will
+be to /usr/local by default, and you'll probably need to be "root" to be able
+to write there.
+
+	make install
+
+To create the printable documentation from the texinfo source, type "make
+gmp.dvi" or "make gmp.ps".  This requires various "tex" commands.
+
+If you are new to GMP, it is a good idea you at least read the chapter "GMP
+Basics" in the manual.
+
+Some known build problems are noted in the "Installing GMP" chapter of
+the manual.  Please report other problems to gmp-bugs@gmplib.org.
+
+The GMP web site is located here: https://gmplib.org/.
+
+
+----------------
+Local variables:
+mode: text
+fill-column: 78
+End:
diff --git a/third_party/gmp/INSTALL.autoconf b/third_party/gmp/INSTALL.autoconf
new file mode 100644
index 0000000..0600b32
--- /dev/null
+++ b/third_party/gmp/INSTALL.autoconf
@@ -0,0 +1,228 @@
+Copyright (C) 1994-1996, 1999-2002 Free Software Foundation, Inc.
+
+   This file is free documentation; the Free Software Foundation gives
+unlimited permission to copy, distribute and modify it.
+
+Basic Installation
+==================
+
+   These are generic installation instructions.
+
+   The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation.  It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions.  Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+   It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring.  (Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.)
+
+   If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release.  If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+   The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'.  You only need
+`configure.ac' if you want to change it or regenerate `configure' using
+a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+  1. `cd' to the directory containing the package's source code and type
+     `./configure' to configure the package for your system.  If you're
+     using `csh' on an old version of System V, you might need to type
+     `sh ./configure' instead to prevent `csh' from trying to execute
+     `configure' itself.
+
+     Running `configure' takes awhile.  While running, it prints some
+     messages telling which features it is checking for.
+
+  2. Type `make' to compile the package.
+
+  3. Optionally, type `make check' to run any self-tests that come with
+     the package.
+
+  4. Type `make install' to install the programs and any data files and
+     documentation.
+
+  5. You can remove the program binaries and object files from the
+     source code directory by typing `make clean'.  To also remove the
+     files that `configure' created (so you can compile the package for
+     a different kind of computer), type `make distclean'.  There is
+     also a `make maintainer-clean' target, but that is intended mainly
+     for the package's developers.  If you use it, you may have to get
+     all sorts of other programs in order to regenerate files that came
+     with the distribution.
+
+Compilers and Options
+=====================
+
+   Some systems require unusual options for compilation or linking that
+the `configure' script does not know about.  Run `./configure --help'
+for details on some of the pertinent environment variables.
+
+   You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment.  Here
+is an example:
+
+     ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
+
+   *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+   You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory.  To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'.  `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script.  `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+   If you have to use a `make' that does not support the `VPATH'
+variable, you have to compile the package for one architecture at a
+time in the source code directory.  After you have installed the
+package for one architecture, use `make distclean' before reconfiguring
+for another architecture.
+
+Installation Names
+==================
+
+   By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc.  You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+   You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files.  If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+   In addition, if you use an unusual directory layout you can give
+options like `--bindir=PATH' to specify different values for particular
+kinds of files.  Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+   If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+   Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System).  The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+   For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+   There may be some features `configure' cannot figure out
+automatically, but needs to determine by the type of machine the package
+will run on.  Usually, assuming the package is built to be run on the
+_same_ architectures, `configure' can figure that out, but if it prints
+a message saying it cannot guess the machine type, give it the
+`--build=TYPE' option.  TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+     CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+     OS KERNEL-OS
+
+   See the file `config.sub' for the possible values of each field.  If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+   If you are _building_ compiler tools for cross-compiling, you should
+use the `--target=TYPE' option to select the type of system they will
+produce code for.
+
+   If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+   If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists.  Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+   Variables not defined in a site shell script can be set in the
+environment passed to `configure'.  However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost.  In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'.  For example:
+
+     ./configure CC=/usr/local2/bin/gcc
+
+will cause the specified gcc to be used as the C compiler (unless it is
+overridden in the site shell script).
+
+`configure' Invocation
+======================
+
+   `configure' recognizes the following options to control how it
+operates.
+
+`--help'
+`-h'
+     Print a summary of the options to `configure', and exit.
+
+`--version'
+`-V'
+     Print the version of Autoconf used to generate the `configure'
+     script, and exit.
+
+`--cache-file=FILE'
+     Enable the cache: use and save the results of the tests in FILE,
+     traditionally `config.cache'.  FILE defaults to `/dev/null' to
+     disable caching.
+
+`--config-cache'
+`-C'
+     Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+     Do not print messages saying which checks are being made.  To
+     suppress all normal output, redirect it to `/dev/null' (any error
+     messages will still be shown).
+
+`--srcdir=DIR'
+     Look for the package's source code in directory DIR.  Usually
+     `configure' can determine that directory automatically.
+
+`configure' also accepts some other, not widely useful, options.  Run
+`configure --help' for more details.
+
diff --git a/third_party/gmp/Makefile.am b/third_party/gmp/Makefile.am
new file mode 100644
index 0000000..0b9eb85
--- /dev/null
+++ b/third_party/gmp/Makefile.am
@@ -0,0 +1,456 @@
+## Process this file with automake to generate Makefile.in
+
+
+# Copyright 1991, 1993, 1994, 1996, 1997, 1999-2004, 2006-2009, 2011-2016,
+# 2018, 2020 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+
+# The following options are the same as AM_INIT_AUTOMAKE in configure.in,
+# except no $(top_builddir) on ansi2knr.  That directory is wanted for the
+# Makefiles in subdirectories, but here we must omit it so automake gives
+# the actual ansi2knr build rule, not "cd $(top_builddir) && make ansi2knr".
+#
+# AUTOMAKE_OPTIONS = 1.8 gnu no-dependencies
+
+
+# Libtool -version-info for libgmp.la and libmp.la.  See "Versioning" in the
+# libtool manual.
+#
+#	CURRENT:REVISION:AGE
+#
+# 1. No interfaces changed, only implementations (good): Increment REVISION.
+#
+# 2. Interfaces added, none removed (good): Increment CURRENT, increment
+#    AGE, set REVISION to 0.
+#
+# 3. Interfaces removed (BAD, breaks upward compatibility): Increment
+#    CURRENT, set AGE and REVISION to 0.
+#
+# Do this separately for libgmp, libgmpxx and libmp, and only for releases.
+#
+#	  GMP	   -version-info
+#       release   libgmp  libgmpxx libmp
+#        2.0.x      -        -       -
+#        3.0      3:0:0      -     3:0:0
+#        3.0.1    3:1:0      -     3:0:0
+#        3.1      4:0:1      -     4:0:1
+#        3.1.1    4:1:1      -     4:1:1
+#        4.0      5:0:2    3:0:0   4:2:1
+#        4.0.1    5:1:2    3:1:0   4:3:1
+#        4.1      6:0:3    3:2:0   4:4:1
+#        4.1.1    6:1:3    3:3:0   4:5:1
+#        4.1.2    6:2:3    3:4:0   4:6:1
+#        4.1.3    6:3:3    3:5:0   4:7:1
+#        4.1.4    6:3:3    3:5:0   4:7:1	WRONG, same as 4.1.3!
+#        4.2      6:0:3    3:2:0   4:4:1	REALLY WRONG, same as 4.1!
+#        4.2.1    7:1:4    4:1:1   4:10:1	WRONG for libgmpxx
+#        4.2.2    7:2:4    4:2:0   4:11:1
+#        4.2.3    7:3:4    4:3:0   4:12:1
+#        4.2.4    7:4:4    4:4:0   4:13:1
+#        4.3.0    8:0:5    5:0:1   4:14:1
+#        4.3.1    8:1:5    5:1:1   4:15:1	WRONG Really used same as 4.3.0
+#        4.3.2    8:2:5    5:2:1   4:16:1
+#        5.0.0    9:0:6    6:0:2   4:20:1	Should have been 10:0:0
+#        5.0.1   10:1:0    6:1:2   4:21:1
+#        5.0.2   10:2:0    6:2:2   4:22:1
+#        5.0.3   10:3:0    6:3:2   4:23:1
+#        5.0.4   10:4:0    6:4:2   4:24:1
+#        5.0.5   10:5:0    6:5:2   4:25:1
+#        5.1.0   11:0:1    7:0:3     -
+#        5.1.1   11:1:1    7:1:3     -
+#        5.1.2   11:2:1    7:2:3     -
+#        6.0.0   12:0:2    8:0:4     -
+#        6.1.0   13:0:3    9:0:5     -
+#        6.1.1   13:1:3    9:1:5     -
+#        6.1.2   13:2:3    9:2:5     -
+#        6.2.0   14:0:4   10:0:6     -
+#
+# Starting at 3:0:0 is a slight abuse of the versioning system, but it
+# ensures we're past soname libgmp.so.2, which was used on Debian GNU/Linux
+# packages of gmp 2.  Pretend gmp 2 was 2:0:0, so the interface changes for
+# gmp 3 mean 3:0:0 is right.
+#
+# We interpret "implementation changed" in item "1." above as meaning any
+# release, ie. the REVISION is incremented every time (if nothing else).
+# Even if we thought the code generated will be identical on all systems,
+# it's still good to get the shared library filename (like
+# libgmpxx.so.3.0.4) incrementing, to make it clear which GMP it's from.
+
+LIBGMP_LT_CURRENT    = 14
+LIBGMP_LT_REVISION   = 0
+LIBGMP_LT_AGE        = 4
+
+LIBGMPXX_LT_CURRENT  = 10
+LIBGMPXX_LT_REVISION = 0
+LIBGMPXX_LT_AGE      = 6
+
+
+SUBDIRS = tests mpn mpz mpq mpf printf scanf rand cxx demos tune doc
+
+EXTRA_DIST = configfsf.guess configfsf.sub .gdbinit INSTALL.autoconf \
+	     COPYING.LESSERv3 COPYINGv2 COPYINGv3
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = gmp.pc
+
+# Put asl.h here for now.
+EXTRA_DIST += asl.h
+
+if WANT_CXX
+GMPXX_HEADERS_OPTION = gmpxx.h
+pkgconfig_DATA += gmpxx.pc
+endif
+EXTRA_DIST += gmpxx.h
+
+# gmp.h is architecture dependent, mainly since it encodes the limb size used
+# in libgmp.  For that reason it belongs under $exec_prefix not $prefix,
+# strictly speaking.
+#
+# $exec_prefix/include is not in the default include path for gcc built to
+# the same $prefix and $exec_prefix, which might mean gmp.h is not found,
+# but anyone knowledgeable enough to be playing with exec_prefix will be able
+# to address that.
+#
+includeexecdir = $(exec_prefix)/include
+include_HEADERS = $(GMPXX_HEADERS_OPTION)
+nodist_includeexec_HEADERS = gmp.h
+lib_LTLIBRARIES = libgmp.la $(GMPXX_LTLIBRARIES_OPTION)
+
+BUILT_SOURCES = gmp.h
+
+DISTCLEANFILES = $(BUILT_SOURCES) config.m4 @gmp_srclinks@
+
+# Tell gmp.h it's building gmp, not an application, used by windows DLL stuff.
+AM_CPPFLAGS=-D__GMP_WITHIN_GMP
+
+
+MPF_OBJECTS = mpf/init$U.lo mpf/init2$U.lo mpf/inits$U.lo mpf/set$U.lo	    \
+  mpf/set_ui$U.lo mpf/set_si$U.lo mpf/set_str$U.lo mpf/set_d$U.lo	    \
+  mpf/set_z$U.lo mpf/iset$U.lo mpf/iset_ui$U.lo mpf/iset_si$U.lo	    \
+  mpf/iset_str$U.lo mpf/iset_d$U.lo mpf/clear$U.lo mpf/clears$U.lo	    \
+  mpf/get_str$U.lo mpf/dump$U.lo mpf/size$U.lo mpf/eq$U.lo mpf/reldiff$U.lo \
+  mpf/sqrt$U.lo mpf/random2$U.lo mpf/inp_str$U.lo mpf/out_str$U.lo	    \
+  mpf/add$U.lo mpf/add_ui$U.lo mpf/sub$U.lo mpf/sub_ui$U.lo mpf/ui_sub$U.lo \
+  mpf/mul$U.lo mpf/mul_ui$U.lo mpf/div$U.lo mpf/div_ui$U.lo mpf/cmp_z$U.lo  \
+  mpf/cmp$U.lo mpf/cmp_d$U.lo mpf/cmp_ui$U.lo mpf/cmp_si$U.lo		    \
+  mpf/mul_2exp$U.lo mpf/div_2exp$U.lo mpf/abs$U.lo mpf/neg$U.lo		    \
+  mpf/set_q$U.lo mpf/get_d$U.lo mpf/get_d_2exp$U.lo mpf/set_dfl_prec$U.lo   \
+  mpf/set_prc$U.lo mpf/set_prc_raw$U.lo mpf/get_dfl_prec$U.lo               \
+  mpf/get_prc$U.lo mpf/ui_div$U.lo mpf/sqrt_ui$U.lo                         \
+  mpf/ceilfloor$U.lo mpf/trunc$U.lo mpf/pow_ui$U.lo			    \
+  mpf/urandomb$U.lo mpf/swap$U.lo					    \
+  mpf/fits_sint$U.lo mpf/fits_slong$U.lo mpf/fits_sshort$U.lo		    \
+  mpf/fits_uint$U.lo mpf/fits_ulong$U.lo mpf/fits_ushort$U.lo		    \
+  mpf/get_si$U.lo mpf/get_ui$U.lo					    \
+  mpf/int_p$U.lo
+
+MPZ_OBJECTS = mpz/abs$U.lo mpz/add$U.lo mpz/add_ui$U.lo			\
+  mpz/aorsmul$U.lo mpz/aorsmul_i$U.lo mpz/and$U.lo mpz/array_init$U.lo	\
+  mpz/bin_ui$U.lo mpz/bin_uiui$U.lo					\
+  mpz/cdiv_q$U.lo mpz/cdiv_q_ui$U.lo					\
+  mpz/cdiv_qr$U.lo mpz/cdiv_qr_ui$U.lo					\
+  mpz/cdiv_r$U.lo mpz/cdiv_r_ui$U.lo mpz/cdiv_ui$U.lo			\
+  mpz/cfdiv_q_2exp$U.lo mpz/cfdiv_r_2exp$U.lo				\
+  mpz/clear$U.lo mpz/clears$U.lo mpz/clrbit$U.lo			\
+  mpz/cmp$U.lo mpz/cmp_d$U.lo mpz/cmp_si$U.lo mpz/cmp_ui$U.lo		\
+  mpz/cmpabs$U.lo mpz/cmpabs_d$U.lo mpz/cmpabs_ui$U.lo			\
+  mpz/com$U.lo mpz/combit$U.lo						\
+  mpz/cong$U.lo mpz/cong_2exp$U.lo mpz/cong_ui$U.lo			\
+  mpz/divexact$U.lo mpz/divegcd$U.lo mpz/dive_ui$U.lo			\
+  mpz/divis$U.lo mpz/divis_ui$U.lo mpz/divis_2exp$U.lo mpz/dump$U.lo	\
+  mpz/export$U.lo mpz/mfac_uiui$U.lo					\
+  mpz/2fac_ui$U.lo mpz/fac_ui$U.lo mpz/oddfac_1$U.lo mpz/prodlimbs$U.lo	\
+  mpz/fdiv_q_ui$U.lo mpz/fdiv_qr$U.lo mpz/fdiv_qr_ui$U.lo		\
+  mpz/fdiv_r$U.lo mpz/fdiv_r_ui$U.lo mpz/fdiv_q$U.lo			\
+  mpz/fdiv_ui$U.lo mpz/fib_ui$U.lo mpz/fib2_ui$U.lo mpz/fits_sint$U.lo	\
+  mpz/fits_slong$U.lo mpz/fits_sshort$U.lo mpz/fits_uint$U.lo		\
+  mpz/fits_ulong$U.lo mpz/fits_ushort$U.lo mpz/gcd$U.lo			\
+  mpz/gcd_ui$U.lo mpz/gcdext$U.lo mpz/get_d$U.lo mpz/get_d_2exp$U.lo	\
+  mpz/get_si$U.lo mpz/get_str$U.lo mpz/get_ui$U.lo mpz/getlimbn$U.lo	\
+  mpz/hamdist$U.lo							\
+  mpz/import$U.lo mpz/init$U.lo mpz/init2$U.lo mpz/inits$U.lo		\
+  mpz/inp_raw$U.lo mpz/inp_str$U.lo mpz/invert$U.lo			\
+  mpz/ior$U.lo mpz/iset$U.lo mpz/iset_d$U.lo mpz/iset_si$U.lo		\
+  mpz/iset_str$U.lo mpz/iset_ui$U.lo mpz/jacobi$U.lo mpz/kronsz$U.lo	\
+  mpz/kronuz$U.lo mpz/kronzs$U.lo mpz/kronzu$U.lo			\
+  mpz/lcm$U.lo mpz/lcm_ui$U.lo mpz/limbs_finish$U.lo			\
+  mpz/limbs_modify$U.lo mpz/limbs_read$U.lo mpz/limbs_write$U.lo	\
+  mpz/lucmod$U.lo mpz/lucnum_ui$U.lo mpz/lucnum2_ui$U.lo		\
+  mpz/millerrabin$U.lo mpz/mod$U.lo mpz/mul$U.lo mpz/mul_2exp$U.lo	\
+  mpz/mul_si$U.lo mpz/mul_ui$U.lo					\
+  mpz/n_pow_ui$U.lo mpz/neg$U.lo mpz/nextprime$U.lo			\
+  mpz/out_raw$U.lo mpz/out_str$U.lo mpz/perfpow$U.lo mpz/perfsqr$U.lo	\
+  mpz/popcount$U.lo mpz/pow_ui$U.lo mpz/powm$U.lo mpz/powm_sec$U.lo	\
+  mpz/powm_ui$U.lo mpz/primorial_ui$U.lo				\
+  mpz/pprime_p$U.lo mpz/random$U.lo mpz/random2$U.lo			\
+  mpz/realloc$U.lo mpz/realloc2$U.lo mpz/remove$U.lo mpz/roinit_n$U.lo  \
+  mpz/root$U.lo mpz/rootrem$U.lo mpz/rrandomb$U.lo mpz/scan0$U.lo	\
+  mpz/scan1$U.lo mpz/set$U.lo mpz/set_d$U.lo mpz/set_f$U.lo		\
+  mpz/set_q$U.lo mpz/set_si$U.lo mpz/set_str$U.lo mpz/set_ui$U.lo	\
+  mpz/setbit$U.lo							\
+  mpz/size$U.lo mpz/sizeinbase$U.lo mpz/sqrt$U.lo			\
+  mpz/sqrtrem$U.lo mpz/stronglucas$U.lo mpz/sub$U.lo			\
+  mpz/sub_ui$U.lo mpz/swap$U.lo						\
+  mpz/tdiv_ui$U.lo mpz/tdiv_q$U.lo mpz/tdiv_q_2exp$U.lo			\
+  mpz/tdiv_q_ui$U.lo mpz/tdiv_qr$U.lo mpz/tdiv_qr_ui$U.lo		\
+  mpz/tdiv_r$U.lo mpz/tdiv_r_2exp$U.lo mpz/tdiv_r_ui$U.lo		\
+  mpz/tstbit$U.lo mpz/ui_pow_ui$U.lo mpz/ui_sub$U.lo mpz/urandomb$U.lo	\
+  mpz/urandomm$U.lo mpz/xor$U.lo
+
+MPQ_OBJECTS = mpq/abs$U.lo mpq/aors$U.lo				\
+  mpq/canonicalize$U.lo mpq/clear$U.lo mpq/clears$U.lo			\
+  mpq/cmp$U.lo mpq/cmp_si$U.lo mpq/cmp_ui$U.lo mpq/div$U.lo		\
+  mpq/get_d$U.lo mpq/get_den$U.lo mpq/get_num$U.lo mpq/get_str$U.lo	\
+  mpq/init$U.lo mpq/inits$U.lo mpq/inp_str$U.lo mpq/inv$U.lo		\
+  mpq/md_2exp$U.lo mpq/mul$U.lo mpq/neg$U.lo mpq/out_str$U.lo		\
+  mpq/set$U.lo mpq/set_den$U.lo mpq/set_num$U.lo			\
+  mpq/set_si$U.lo mpq/set_str$U.lo mpq/set_ui$U.lo			\
+  mpq/equal$U.lo mpq/set_z$U.lo mpq/set_d$U.lo				\
+  mpq/set_f$U.lo mpq/swap$U.lo
+
+MPN_OBJECTS = mpn/fib_table$U.lo mpn/mp_bases$U.lo
+
+PRINTF_OBJECTS =							\
+  printf/asprintf$U.lo printf/asprntffuns$U.lo				\
+  printf/doprnt$U.lo printf/doprntf$U.lo printf/doprnti$U.lo		\
+  printf/fprintf$U.lo							\
+  printf/obprintf$U.lo printf/obvprintf$U.lo printf/obprntffuns$U.lo	\
+  printf/printf$U.lo printf/printffuns$U.lo				\
+  printf/snprintf$U.lo printf/snprntffuns$U.lo				\
+  printf/sprintf$U.lo printf/sprintffuns$U.lo				\
+  printf/vasprintf$U.lo printf/vfprintf$U.lo printf/vprintf$U.lo	\
+  printf/vsnprintf$U.lo printf/vsprintf$U.lo				\
+  printf/repl-vsnprintf$U.lo
+
+SCANF_OBJECTS =							\
+  scanf/doscan$U.lo scanf/fscanf$U.lo scanf/fscanffuns$U.lo	\
+  scanf/scanf$U.lo scanf/sscanf$U.lo scanf/sscanffuns$U.lo	\
+  scanf/vfscanf$U.lo scanf/vscanf$U.lo scanf/vsscanf$U.lo
+
+RANDOM_OBJECTS =							\
+  rand/rand$U.lo rand/randclr$U.lo rand/randdef$U.lo rand/randiset$U.lo	\
+  rand/randlc2s$U.lo rand/randlc2x$U.lo rand/randmt$U.lo		\
+  rand/randmts$U.lo rand/rands$U.lo rand/randsd$U.lo rand/randsdui$U.lo	\
+  rand/randbui$U.lo rand/randmui$U.lo
+
+# no $U for C++ files
+CXX_OBJECTS =								\
+  cxx/isfuns.lo cxx/ismpf.lo cxx/ismpq.lo cxx/ismpz.lo cxx/ismpznw.lo	\
+  cxx/limits.lo cxx/osdoprnti.lo cxx/osfuns.lo				\
+  cxx/osmpf.lo cxx/osmpq.lo cxx/osmpz.lo
+
+# In libtool 1.5 it doesn't work to build libgmp.la from the convenience
+# libraries like mpz/libmpz.la.  Or rather it works, but it ends up putting
+# PIC objects into libgmp.a if shared and static are both built.  (The PIC
+# objects go into mpz/.libs/libmpz.a, and thence into .libs/libgmp.a.)
+#
+# For now the big lists of objects above are used.  Something like mpz/*.lo
+# would probably work, but might risk missing something out or getting
+# something extra.  The source files for each .lo are listed in the
+# Makefile.am's in the subdirectories.
+#
+# Currently, for libgmp, unlike libmp below, we're not using
+# -export-symbols, since the tune and speed programs, and perhaps some of
+# the test programs, want to access undocumented symbols.
+
+libgmp_la_SOURCES = gmp-impl.h longlong.h				\
+  assert.c compat.c errno.c extract-dbl.c invalid.c memory.c		\
+  mp_bpl.c mp_clz_tab.c mp_dv_tab.c mp_minv_tab.c mp_get_fns.c mp_set_fns.c \
+  version.c nextprime.c primesieve.c
+EXTRA_libgmp_la_SOURCES = tal-debug.c tal-notreent.c tal-reent.c
+libgmp_la_DEPENDENCIES = @TAL_OBJECT@		\
+  $(MPF_OBJECTS) $(MPZ_OBJECTS) $(MPQ_OBJECTS)	\
+  $(MPN_OBJECTS) @mpn_objs_in_libgmp@		\
+  $(PRINTF_OBJECTS)  $(SCANF_OBJECTS) $(RANDOM_OBJECTS)
+libgmp_la_LIBADD = $(libgmp_la_DEPENDENCIES)
+libgmp_la_LDFLAGS = $(GMP_LDFLAGS) $(LIBGMP_LDFLAGS) \
+  -version-info $(LIBGMP_LT_CURRENT):$(LIBGMP_LT_REVISION):$(LIBGMP_LT_AGE)
+
+
+# We need at least one .cc file in $(libgmpxx_la_SOURCES) so automake will
+# use $(CXXLINK) rather than the plain C $(LINK).  cxx/dummy.cc is that
+# file.
+
+if WANT_CXX
+GMPXX_LTLIBRARIES_OPTION = libgmpxx.la
+endif
+libgmpxx_la_SOURCES = cxx/dummy.cc
+libgmpxx_la_DEPENDENCIES = $(CXX_OBJECTS) libgmp.la
+libgmpxx_la_LIBADD = $(libgmpxx_la_DEPENDENCIES)
+libgmpxx_la_LDFLAGS = $(GMP_LDFLAGS) $(LIBGMPXX_LDFLAGS) \
+  -version-info $(LIBGMPXX_LT_CURRENT):$(LIBGMPXX_LT_REVISION):$(LIBGMPXX_LT_AGE)
+
+
+
+install-data-hook:
+	@echo ''
+	@echo '+-------------------------------------------------------------+'
+	@echo '| CAUTION:                                                    |'
+	@echo '|                                                             |'
+	@echo '| If you have not already run "make check", then we strongly  |'
+	@echo '| recommend you do so.                                        |'
+	@echo '|                                                             |'
+	@echo '| GMP has been carefully tested by its authors, but compilers |'
+	@echo '| are all too often released with serious bugs.  GMP tends to |'
+	@echo '| explore interesting corners in compilers and has hit bugs   |'
+	@echo '| on quite a few occasions.                                   |'
+	@echo '|                                                             |'
+	@echo '+-------------------------------------------------------------+'
+	@echo ''
+
+
+# The "test -f" support for srcdir!=builddir is similar to the automake .c.o
+# etc rules, but with each foo.c explicitly, since $< is not portable
+# outside an inference rule.
+#
+# A quoted 'foo.c' is used with the "test -f"'s to avoid Sun make rewriting
+# it as part of its VPATH support.  See the autoconf manual "Limitations of
+# Make".
+#
+# Generated .h files which are used by gmp-impl.h are BUILT_SOURCES since
+# they must exist before anything can be compiled.
+#
+# Other generated .h files are also BUILT_SOURCES so as to get all the
+# build-system stuff over and done with at the start.  Also, dependencies on
+# the .h files are not properly expressed for the various objects that use
+# them.
+
+EXTRA_DIST += bootstrap.c
+
+fac_table.h: gen-fac$(EXEEXT_FOR_BUILD)
+	./gen-fac $(GMP_LIMB_BITS) $(GMP_NAIL_BITS) >fac_table.h || (rm -f fac_table.h; exit 1)
+BUILT_SOURCES += fac_table.h
+
+gen-fac$(EXEEXT_FOR_BUILD): gen-fac$(U_FOR_BUILD).c bootstrap.c
+	$(CC_FOR_BUILD) `test -f 'gen-fac$(U_FOR_BUILD).c' || echo '$(srcdir)/'`gen-fac$(U_FOR_BUILD).c -o gen-fac$(EXEEXT_FOR_BUILD)
+DISTCLEANFILES += gen-fac$(EXEEXT_FOR_BUILD)
+EXTRA_DIST += gen-fac.c
+
+
+fib_table.h: gen-fib$(EXEEXT_FOR_BUILD)
+	./gen-fib header $(GMP_LIMB_BITS) $(GMP_NAIL_BITS) >fib_table.h || (rm -f fib_table.h; exit 1)
+BUILT_SOURCES += fib_table.h
+
+mpn/fib_table.c: gen-fib$(EXEEXT_FOR_BUILD)
+	./gen-fib table $(GMP_LIMB_BITS) $(GMP_NAIL_BITS) >mpn/fib_table.c || (rm -f mpn/fib_table.c; exit 1)
+BUILT_SOURCES += mpn/fib_table.c
+
+gen-fib$(EXEEXT_FOR_BUILD): gen-fib$(U_FOR_BUILD).c bootstrap.c
+	$(CC_FOR_BUILD) `test -f 'gen-fib$(U_FOR_BUILD).c' || echo '$(srcdir)/'`gen-fib$(U_FOR_BUILD).c -o gen-fib$(EXEEXT_FOR_BUILD)
+DISTCLEANFILES += gen-fib$(EXEEXT_FOR_BUILD)
+EXTRA_DIST += gen-fib.c
+
+
+mp_bases.h: gen-bases$(EXEEXT_FOR_BUILD)
+	./gen-bases header $(GMP_LIMB_BITS) $(GMP_NAIL_BITS) >mp_bases.h || (rm -f mp_bases.h; exit 1)
+BUILT_SOURCES += mp_bases.h
+
+mpn/mp_bases.c: gen-bases$(EXEEXT_FOR_BUILD)
+	./gen-bases table $(GMP_LIMB_BITS) $(GMP_NAIL_BITS) >mpn/mp_bases.c || (rm -f mpn/mp_bases.c; exit 1)
+BUILT_SOURCES += mpn/mp_bases.c
+
+gen-bases$(EXEEXT_FOR_BUILD): gen-bases$(U_FOR_BUILD).c bootstrap.c
+	$(CC_FOR_BUILD) `test -f 'gen-bases$(U_FOR_BUILD).c' || echo '$(srcdir)/'`gen-bases$(U_FOR_BUILD).c -o gen-bases$(EXEEXT_FOR_BUILD) $(LIBM_FOR_BUILD)
+DISTCLEANFILES += gen-bases$(EXEEXT_FOR_BUILD)
+EXTRA_DIST += gen-bases.c
+
+
+trialdivtab.h: gen-trialdivtab$(EXEEXT_FOR_BUILD)
+	./gen-trialdivtab $(GMP_LIMB_BITS) 8000 >trialdivtab.h || (rm -f trialdivtab.h; exit 1)
+BUILT_SOURCES += trialdivtab.h
+
+gen-trialdivtab$(EXEEXT_FOR_BUILD): gen-trialdivtab$(U_FOR_BUILD).c bootstrap.c
+	$(CC_FOR_BUILD) `test -f 'gen-trialdivtab$(U_FOR_BUILD).c' || echo '$(srcdir)/'`gen-trialdivtab$(U_FOR_BUILD).c -o gen-trialdivtab$(EXEEXT_FOR_BUILD) $(LIBM_FOR_BUILD)
+DISTCLEANFILES += gen-trialdivtab$(EXEEXT_FOR_BUILD)
+EXTRA_DIST += gen-trialdivtab.c
+
+
+mpn/jacobitab.h: gen-jacobitab$(EXEEXT_FOR_BUILD)
+	./gen-jacobitab >mpn/jacobitab.h || (rm -f mpn/jacobitab.h; exit 1)
+BUILT_SOURCES += mpn/jacobitab.h
+
+gen-jacobitab$(EXEEXT_FOR_BUILD): gen-jacobitab$(U_FOR_BUILD).c
+	$(CC_FOR_BUILD) `test -f 'gen-jacobitab$(U_FOR_BUILD).c' || echo '$(srcdir)/'`gen-jacobitab$(U_FOR_BUILD).c -o gen-jacobitab$(EXEEXT_FOR_BUILD)
+DISTCLEANFILES += gen-jacobitab$(EXEEXT_FOR_BUILD)
+EXTRA_DIST += gen-jacobitab.c
+
+
+mpn/perfsqr.h: gen-psqr$(EXEEXT_FOR_BUILD)
+	./gen-psqr $(GMP_LIMB_BITS) $(GMP_NAIL_BITS) >mpn/perfsqr.h || (rm -f mpn/perfsqr.h; exit 1)
+BUILT_SOURCES += mpn/perfsqr.h
+
+gen-psqr$(EXEEXT_FOR_BUILD): gen-psqr$(U_FOR_BUILD).c bootstrap.c
+	$(CC_FOR_BUILD) `test -f 'gen-psqr$(U_FOR_BUILD).c' || echo '$(srcdir)/'`gen-psqr$(U_FOR_BUILD).c -o gen-psqr$(EXEEXT_FOR_BUILD) $(LIBM_FOR_BUILD)
+DISTCLEANFILES += gen-psqr$(EXEEXT_FOR_BUILD)
+EXTRA_DIST += gen-psqr.c
+
+# Distribute mini-gmp. Test sources copied by dist-hook.
+EXTRA_DIST += mini-gmp/README mini-gmp/mini-gmp.c mini-gmp/mini-gmp.h \
+	      mini-gmp/mini-mpq.c mini-gmp/mini-mpq.h \
+	      mini-gmp/tests/Makefile mini-gmp/tests/run-tests
+
+# Avoid: CVS - cvs directories
+#        *~  - emacs backups
+#        .#* - cvs merge originals
+#
+# *~ and .#* only occur when a whole directory without it's own Makefile.am
+# is distributed, like "doc" or the mpn cpu subdirectories.
+#
+dist-hook:
+	-find $(distdir) \( -name CVS -type d \) -o -name "*~" -o -name ".#*" \
+		| xargs rm -rf
+	cp "$(srcdir)"/mini-gmp/tests/*.[ch] "$(distdir)/mini-gmp/tests"
+#	grep -F $(VERSION) $(srcdir)/Makefile.am \
+#		| grep -q "^# *$(VERSION) *$(LIBGMP_LT_CURRENT):$(LIBGMP_LT_REVISION):$(LIBGMP_LT_AGE) *$(LIBGMPXX_LT_CURRENT):$(LIBGMPXX_LT_REVISION):$(LIBGMPXX_LT_AGE)"
+#	test -z "`sed -n 's/^# *[0-9]*\.[0-9]*\.[0-9]* *\([0-9]*:[0-9]*:[0-9]*\) *\([0-9]*:[0-9]*:[0-9]*\) *\([0-9]*:[0-9]*:[0-9]*\).*/A\1\nB\2\nC\3/p' $(srcdir)/Makefile.am | grep -v 'A6:3:3\|B3:5:0\|C4:7:1' | sort | uniq -d`"
+
+.PHONY: check-mini-gmp clean-mini-gmp
+
+check-mini-gmp:
+	abs_srcdir="`cd $(srcdir) && pwd`" ; \
+	$(MKDIR_P) mini-gmp/tests \
+	&& cd mini-gmp/tests \
+	&& TEST_LIBRARY_PATH="../../.libs"  \
+	   $(MAKE) -f "$$abs_srcdir/mini-gmp/tests/Makefile" \
+		VPATH="$$abs_srcdir/mini-gmp/tests" \
+		srcdir="$$abs_srcdir/mini-gmp/tests" \
+		MINI_GMP_DIR="$$abs_srcdir/mini-gmp" \
+		LDFLAGS="-L../../.libs" \
+		LIBS="-lgmp -lm" \
+		CC="$(CC)" CFLAGS="$(CFLAGS)" CPPFLAGS="$(CPPFLAGS) -I../.." check
+
+clean-mini-gmp:
+	if [ -d mini-gmp/tests ] ; then \
+	  abs_srcdir="`cd $(srcdir) && pwd`" ; \
+	  cd mini-gmp/tests \
+	  && $(MAKE) -f "$$abs_srcdir/mini-gmp/tests/Makefile" clean ; \
+	fi
+
+clean-local: clean-mini-gmp
+distclean-local: clean-mini-gmp
diff --git a/third_party/gmp/Makefile.in b/third_party/gmp/Makefile.in
new file mode 100644
index 0000000..ca12871
--- /dev/null
+++ b/third_party/gmp/Makefile.in
@@ -0,0 +1,1532 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Copyright 1991, 1993, 1994, 1996, 1997, 1999-2004, 2006-2009, 2011-2016,
+# 2018, 2020 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+# The following options are the same as AM_INIT_AUTOMAKE in configure.in,
+# except no $(top_builddir) on ansi2knr.  That directory is wanted for the
+# Makefiles in subdirectories, but here we must omit it so automake gives
+# the actual ansi2knr build rule, not "cd $(top_builddir) && make ansi2knr".
+#
+# AUTOMAKE_OPTIONS = 1.8 gnu no-dependencies
+
+# Libtool -version-info for libgmp.la and libmp.la.  See "Versioning" in the
+# libtool manual.
+#
+#	CURRENT:REVISION:AGE
+#
+# 1. No interfaces changed, only implementations (good): Increment REVISION.
+#
+# 2. Interfaces added, none removed (good): Increment CURRENT, increment
+#    AGE, set REVISION to 0.
+#
+# 3. Interfaces removed (BAD, breaks upward compatibility): Increment
+#    CURRENT, set AGE and REVISION to 0.
+#
+# Do this separately for libgmp, libgmpxx and libmp, and only for releases.
+#
+#	  GMP	   -version-info
+#       release   libgmp  libgmpxx libmp
+#        2.0.x      -        -       -
+#        3.0      3:0:0      -     3:0:0
+#        3.0.1    3:1:0      -     3:0:0
+#        3.1      4:0:1      -     4:0:1
+#        3.1.1    4:1:1      -     4:1:1
+#        4.0      5:0:2    3:0:0   4:2:1
+#        4.0.1    5:1:2    3:1:0   4:3:1
+#        4.1      6:0:3    3:2:0   4:4:1
+#        4.1.1    6:1:3    3:3:0   4:5:1
+#        4.1.2    6:2:3    3:4:0   4:6:1
+#        4.1.3    6:3:3    3:5:0   4:7:1
+#        4.1.4    6:3:3    3:5:0   4:7:1	WRONG, same as 4.1.3!
+#        4.2      6:0:3    3:2:0   4:4:1	REALLY WRONG, same as 4.1!
+#        4.2.1    7:1:4    4:1:1   4:10:1	WRONG for libgmpxx
+#        4.2.2    7:2:4    4:2:0   4:11:1
+#        4.2.3    7:3:4    4:3:0   4:12:1
+#        4.2.4    7:4:4    4:4:0   4:13:1
+#        4.3.0    8:0:5    5:0:1   4:14:1
+#        4.3.1    8:1:5    5:1:1   4:15:1	WRONG Really used same as 4.3.0
+#        4.3.2    8:2:5    5:2:1   4:16:1
+#        5.0.0    9:0:6    6:0:2   4:20:1	Should have been 10:0:0
+#        5.0.1   10:1:0    6:1:2   4:21:1
+#        5.0.2   10:2:0    6:2:2   4:22:1
+#        5.0.3   10:3:0    6:3:2   4:23:1
+#        5.0.4   10:4:0    6:4:2   4:24:1
+#        5.0.5   10:5:0    6:5:2   4:25:1
+#        5.1.0   11:0:1    7:0:3     -
+#        5.1.1   11:1:1    7:1:3     -
+#        5.1.2   11:2:1    7:2:3     -
+#        6.0.0   12:0:2    8:0:4     -
+#        6.1.0   13:0:3    9:0:5     -
+#        6.1.1   13:1:3    9:1:5     -
+#        6.1.2   13:2:3    9:2:5     -
+#        6.2.0   14:0:4   10:0:6     -
+#
+# Starting at 3:0:0 is a slight abuse of the versioning system, but it
+# ensures we're past soname libgmp.so.2, which was used on Debian GNU/Linux
+# packages of gmp 2.  Pretend gmp 2 was 2:0:0, so the interface changes for
+# gmp 3 mean 3:0:0 is right.
+#
+# We interpret "implementation changed" in item "1." above as meaning any
+# release, ie. the REVISION is incremented every time (if nothing else).
+# Even if we thought the code generated will be identical on all systems,
+# it's still good to get the shared library filename (like
+# libgmpxx.so.3.0.4) incrementing, to make it clear which GMP it's from.
+
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@WANT_CXX_TRUE@am__append_1 = gmpxx.pc
+subdir = .
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \
+	$(am__configure_deps) $(am__include_HEADERS_DIST) \
+	$(am__DIST_COMMON)
+am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
+ configure.lineno config.status.lineno
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = config.h
+CONFIG_CLEAN_FILES = gmp.h gmp.pc gmpxx.pc gmp-mparam.h
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+  test -z "$$files" \
+    || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+    || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+         $(am__cd) "$$dir" && rm -f $$files; }; \
+  }
+am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkgconfigdir)" \
+	"$(DESTDIR)$(includedir)" "$(DESTDIR)$(includeexecdir)"
+LTLIBRARIES = $(lib_LTLIBRARIES)
+am__DEPENDENCIES_1 = $(MPF_OBJECTS) $(MPZ_OBJECTS) $(MPQ_OBJECTS) \
+	$(MPN_OBJECTS) $(PRINTF_OBJECTS) $(SCANF_OBJECTS) \
+	$(RANDOM_OBJECTS)
+am_libgmp_la_OBJECTS = assert.lo compat.lo errno.lo extract-dbl.lo \
+	invalid.lo memory.lo mp_bpl.lo mp_clz_tab.lo mp_dv_tab.lo \
+	mp_minv_tab.lo mp_get_fns.lo mp_set_fns.lo version.lo \
+	nextprime.lo primesieve.lo
+libgmp_la_OBJECTS = $(am_libgmp_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+libgmp_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(libgmp_la_LDFLAGS) $(LDFLAGS) -o $@
+am__dirstamp = $(am__leading_dot)dirstamp
+am_libgmpxx_la_OBJECTS = cxx/dummy.lo
+libgmpxx_la_OBJECTS = $(am_libgmpxx_la_OBJECTS)
+libgmpxx_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+	$(CXXFLAGS) $(libgmpxx_la_LDFLAGS) $(LDFLAGS) -o $@
+@WANT_CXX_TRUE@am_libgmpxx_la_rpath = -rpath $(libdir)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I.@am__isrc@
+depcomp =
+am__depfiles_maybe =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo "  CXX     " $@;
+am__v_CXX_1 = 
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+	$(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo "  CXXLD   " $@;
+am__v_CXXLD_1 = 
+SOURCES = $(libgmp_la_SOURCES) $(EXTRA_libgmp_la_SOURCES) \
+	$(libgmpxx_la_SOURCES)
+DIST_SOURCES = $(libgmp_la_SOURCES) $(EXTRA_libgmp_la_SOURCES) \
+	$(libgmpxx_la_SOURCES)
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+	ctags-recursive dvi-recursive html-recursive info-recursive \
+	install-data-recursive install-dvi-recursive \
+	install-exec-recursive install-html-recursive \
+	install-info-recursive install-pdf-recursive \
+	install-ps-recursive install-recursive installcheck-recursive \
+	installdirs-recursive pdf-recursive ps-recursive \
+	tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+DATA = $(pkgconfig_DATA)
+am__include_HEADERS_DIST = gmpxx.h
+HEADERS = $(include_HEADERS) $(nodist_includeexec_HEADERS)
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive	\
+  distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+  $(RECURSIVE_TARGETS) \
+  $(RECURSIVE_CLEAN_TARGETS) \
+  $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+	cscope distdir dist dist-all distcheck
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \
+	$(LISP)config.in
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+CSCOPE = cscope
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config.in \
+	$(srcdir)/gmp-h.in $(srcdir)/gmp.pc.in $(srcdir)/gmpxx.pc.in \
+	AUTHORS COPYING ChangeLog INSTALL NEWS README compile \
+	config.guess config.sub install-sh ltmain.sh missing
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+am__remove_distdir = \
+  if test -d "$(distdir)"; then \
+    find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \
+      && rm -rf "$(distdir)" \
+      || { sleep 5 && rm -rf "$(distdir)"; }; \
+  else :; fi
+am__post_remove_distdir = $(am__remove_distdir)
+am__relativize = \
+  dir0=`pwd`; \
+  sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+  sed_rest='s,^[^/]*/*,,'; \
+  sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+  sed_butlast='s,/*[^/]*$$,,'; \
+  while test -n "$$dir1"; do \
+    first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+    if test "$$first" != "."; then \
+      if test "$$first" = ".."; then \
+        dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+        dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+      else \
+        first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+        if test "$$first2" = "$$first"; then \
+          dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+        else \
+          dir2="../$$dir2"; \
+        fi; \
+        dir0="$$dir0"/"$$first"; \
+      fi; \
+    fi; \
+    dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+  done; \
+  reldir="$$dir2"
+DIST_ARCHIVES = $(distdir).tar.gz
+GZIP_ENV = --best
+DIST_TARGETS = dist-gzip
+distuninstallcheck_listfiles = find . -type f -print
+am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \
+  | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$'
+distcleancheck_listfiles = find . -type f -print
+ABI = @ABI@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+ASMFLAGS = @ASMFLAGS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CALLING_CONVENTIONS_OBJS = @CALLING_CONVENTIONS_OBJS@
+CC = @CC@
+CCAS = @CCAS@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPP_FOR_BUILD = @CPP_FOR_BUILD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFN_LONG_LONG_LIMB = @DEFN_LONG_LONG_LIMB@
+DEFS = @DEFS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@
+FGREP = @FGREP@
+GMP_LDFLAGS = @GMP_LDFLAGS@
+GMP_LIMB_BITS = @GMP_LIMB_BITS@
+GMP_NAIL_BITS = @GMP_NAIL_BITS@
+GREP = @GREP@
+HAVE_CLOCK_01 = @HAVE_CLOCK_01@
+HAVE_CPUTIME_01 = @HAVE_CPUTIME_01@
+HAVE_GETRUSAGE_01 = @HAVE_GETRUSAGE_01@
+HAVE_GETTIMEOFDAY_01 = @HAVE_GETTIMEOFDAY_01@
+HAVE_HOST_CPU_FAMILY_power = @HAVE_HOST_CPU_FAMILY_power@
+HAVE_HOST_CPU_FAMILY_powerpc = @HAVE_HOST_CPU_FAMILY_powerpc@
+HAVE_SIGACTION_01 = @HAVE_SIGACTION_01@
+HAVE_SIGALTSTACK_01 = @HAVE_SIGALTSTACK_01@
+HAVE_SIGSTACK_01 = @HAVE_SIGSTACK_01@
+HAVE_STACK_T_01 = @HAVE_STACK_T_01@
+HAVE_SYS_RESOURCE_H_01 = @HAVE_SYS_RESOURCE_H_01@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCURSES = @LIBCURSES@
+LIBGMPXX_LDFLAGS = @LIBGMPXX_LDFLAGS@
+LIBGMP_DLL = @LIBGMP_DLL@
+LIBGMP_LDFLAGS = @LIBGMP_LDFLAGS@
+LIBM = @LIBM@
+LIBM_FOR_BUILD = @LIBM_FOR_BUILD@
+LIBOBJS = @LIBOBJS@
+LIBREADLINE = @LIBREADLINE@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+M4 = @M4@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPEED_CYCLECOUNTER_OBJ = @SPEED_CYCLECOUNTER_OBJ@
+STRIP = @STRIP@
+TAL_OBJECT = @TAL_OBJECT@
+TUNE_LIBS = @TUNE_LIBS@
+TUNE_SQR_OBJ = @TUNE_SQR_OBJ@
+U_FOR_BUILD = @U_FOR_BUILD@
+VERSION = @VERSION@
+WITH_READLINE_01 = @WITH_READLINE_01@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__leading_dot = @am__leading_dot@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gmp_srclinks = @gmp_srclinks@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+mpn_objects = @mpn_objects@
+mpn_objs_in_libgmp = @mpn_objs_in_libgmp@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+LIBGMP_LT_CURRENT = 14
+LIBGMP_LT_REVISION = 0
+LIBGMP_LT_AGE = 4
+LIBGMPXX_LT_CURRENT = 10
+LIBGMPXX_LT_REVISION = 0
+LIBGMPXX_LT_AGE = 6
+SUBDIRS = tests mpn mpz mpq mpf printf scanf rand cxx demos tune doc
+
+# Put asl.h here for now.
+
+# The "test -f" support for srcdir!=builddir is similar to the automake .c.o
+# etc rules, but with each foo.c explicitly, since $< is not portable
+# outside an inference rule.
+#
+# A quoted 'foo.c' is used with the "test -f"'s to avoid Sun make rewriting
+# it as part of its VPATH support.  See the autoconf manual "Limitations of
+# Make".
+#
+# Generated .h files which are used by gmp-impl.h are BUILT_SOURCES since
+# they must exist before anything can be compiled.
+#
+# Other generated .h files are also BUILT_SOURCES so as to get all the
+# build-system stuff over and done with at the start.  Also, dependencies on
+# the .h files are not properly expressed for the various objects that use
+# them.
+
+# Distribute mini-gmp. Test sources copied by dist-hook.
+EXTRA_DIST = configfsf.guess configfsf.sub .gdbinit INSTALL.autoconf \
+	COPYING.LESSERv3 COPYINGv2 COPYINGv3 asl.h gmpxx.h bootstrap.c \
+	gen-fac.c gen-fib.c gen-bases.c gen-trialdivtab.c \
+	gen-jacobitab.c gen-psqr.c mini-gmp/README mini-gmp/mini-gmp.c \
+	mini-gmp/mini-gmp.h mini-gmp/mini-mpq.c mini-gmp/mini-mpq.h \
+	mini-gmp/tests/Makefile mini-gmp/tests/run-tests
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = gmp.pc $(am__append_1)
+@WANT_CXX_TRUE@GMPXX_HEADERS_OPTION = gmpxx.h
+
+# gmp.h is architecture dependent, mainly since it encodes the limb size used
+# in libgmp.  For that reason it belongs under $exec_prefix not $prefix,
+# strictly speaking.
+#
+# $exec_prefix/include is not in the default include path for gcc built to
+# the same $prefix and $exec_prefix, which might mean gmp.h is not found,
+# but anyone knowledgeable enough to be playing with exec_prefix will be able
+# to address that.
+#
+includeexecdir = $(exec_prefix)/include
+include_HEADERS = $(GMPXX_HEADERS_OPTION)
+nodist_includeexec_HEADERS = gmp.h
+lib_LTLIBRARIES = libgmp.la $(GMPXX_LTLIBRARIES_OPTION)
+BUILT_SOURCES = gmp.h fac_table.h fib_table.h mpn/fib_table.c \
+	mp_bases.h mpn/mp_bases.c trialdivtab.h mpn/jacobitab.h \
+	mpn/perfsqr.h
+DISTCLEANFILES = $(BUILT_SOURCES) config.m4 @gmp_srclinks@ \
+	gen-fac$(EXEEXT_FOR_BUILD) gen-fib$(EXEEXT_FOR_BUILD) \
+	gen-bases$(EXEEXT_FOR_BUILD) \
+	gen-trialdivtab$(EXEEXT_FOR_BUILD) \
+	gen-jacobitab$(EXEEXT_FOR_BUILD) gen-psqr$(EXEEXT_FOR_BUILD)
+
+# Tell gmp.h it's building gmp, not an application, used by windows DLL stuff.
+AM_CPPFLAGS = -D__GMP_WITHIN_GMP
+MPF_OBJECTS = mpf/init$U.lo mpf/init2$U.lo mpf/inits$U.lo mpf/set$U.lo	    \
+  mpf/set_ui$U.lo mpf/set_si$U.lo mpf/set_str$U.lo mpf/set_d$U.lo	    \
+  mpf/set_z$U.lo mpf/iset$U.lo mpf/iset_ui$U.lo mpf/iset_si$U.lo	    \
+  mpf/iset_str$U.lo mpf/iset_d$U.lo mpf/clear$U.lo mpf/clears$U.lo	    \
+  mpf/get_str$U.lo mpf/dump$U.lo mpf/size$U.lo mpf/eq$U.lo mpf/reldiff$U.lo \
+  mpf/sqrt$U.lo mpf/random2$U.lo mpf/inp_str$U.lo mpf/out_str$U.lo	    \
+  mpf/add$U.lo mpf/add_ui$U.lo mpf/sub$U.lo mpf/sub_ui$U.lo mpf/ui_sub$U.lo \
+  mpf/mul$U.lo mpf/mul_ui$U.lo mpf/div$U.lo mpf/div_ui$U.lo mpf/cmp_z$U.lo  \
+  mpf/cmp$U.lo mpf/cmp_d$U.lo mpf/cmp_ui$U.lo mpf/cmp_si$U.lo		    \
+  mpf/mul_2exp$U.lo mpf/div_2exp$U.lo mpf/abs$U.lo mpf/neg$U.lo		    \
+  mpf/set_q$U.lo mpf/get_d$U.lo mpf/get_d_2exp$U.lo mpf/set_dfl_prec$U.lo   \
+  mpf/set_prc$U.lo mpf/set_prc_raw$U.lo mpf/get_dfl_prec$U.lo               \
+  mpf/get_prc$U.lo mpf/ui_div$U.lo mpf/sqrt_ui$U.lo                         \
+  mpf/ceilfloor$U.lo mpf/trunc$U.lo mpf/pow_ui$U.lo			    \
+  mpf/urandomb$U.lo mpf/swap$U.lo					    \
+  mpf/fits_sint$U.lo mpf/fits_slong$U.lo mpf/fits_sshort$U.lo		    \
+  mpf/fits_uint$U.lo mpf/fits_ulong$U.lo mpf/fits_ushort$U.lo		    \
+  mpf/get_si$U.lo mpf/get_ui$U.lo					    \
+  mpf/int_p$U.lo
+
+MPZ_OBJECTS = mpz/abs$U.lo mpz/add$U.lo mpz/add_ui$U.lo			\
+  mpz/aorsmul$U.lo mpz/aorsmul_i$U.lo mpz/and$U.lo mpz/array_init$U.lo	\
+  mpz/bin_ui$U.lo mpz/bin_uiui$U.lo					\
+  mpz/cdiv_q$U.lo mpz/cdiv_q_ui$U.lo					\
+  mpz/cdiv_qr$U.lo mpz/cdiv_qr_ui$U.lo					\
+  mpz/cdiv_r$U.lo mpz/cdiv_r_ui$U.lo mpz/cdiv_ui$U.lo			\
+  mpz/cfdiv_q_2exp$U.lo mpz/cfdiv_r_2exp$U.lo				\
+  mpz/clear$U.lo mpz/clears$U.lo mpz/clrbit$U.lo			\
+  mpz/cmp$U.lo mpz/cmp_d$U.lo mpz/cmp_si$U.lo mpz/cmp_ui$U.lo		\
+  mpz/cmpabs$U.lo mpz/cmpabs_d$U.lo mpz/cmpabs_ui$U.lo			\
+  mpz/com$U.lo mpz/combit$U.lo						\
+  mpz/cong$U.lo mpz/cong_2exp$U.lo mpz/cong_ui$U.lo			\
+  mpz/divexact$U.lo mpz/divegcd$U.lo mpz/dive_ui$U.lo			\
+  mpz/divis$U.lo mpz/divis_ui$U.lo mpz/divis_2exp$U.lo mpz/dump$U.lo	\
+  mpz/export$U.lo mpz/mfac_uiui$U.lo					\
+  mpz/2fac_ui$U.lo mpz/fac_ui$U.lo mpz/oddfac_1$U.lo mpz/prodlimbs$U.lo	\
+  mpz/fdiv_q_ui$U.lo mpz/fdiv_qr$U.lo mpz/fdiv_qr_ui$U.lo		\
+  mpz/fdiv_r$U.lo mpz/fdiv_r_ui$U.lo mpz/fdiv_q$U.lo			\
+  mpz/fdiv_ui$U.lo mpz/fib_ui$U.lo mpz/fib2_ui$U.lo mpz/fits_sint$U.lo	\
+  mpz/fits_slong$U.lo mpz/fits_sshort$U.lo mpz/fits_uint$U.lo		\
+  mpz/fits_ulong$U.lo mpz/fits_ushort$U.lo mpz/gcd$U.lo			\
+  mpz/gcd_ui$U.lo mpz/gcdext$U.lo mpz/get_d$U.lo mpz/get_d_2exp$U.lo	\
+  mpz/get_si$U.lo mpz/get_str$U.lo mpz/get_ui$U.lo mpz/getlimbn$U.lo	\
+  mpz/hamdist$U.lo							\
+  mpz/import$U.lo mpz/init$U.lo mpz/init2$U.lo mpz/inits$U.lo		\
+  mpz/inp_raw$U.lo mpz/inp_str$U.lo mpz/invert$U.lo			\
+  mpz/ior$U.lo mpz/iset$U.lo mpz/iset_d$U.lo mpz/iset_si$U.lo		\
+  mpz/iset_str$U.lo mpz/iset_ui$U.lo mpz/jacobi$U.lo mpz/kronsz$U.lo	\
+  mpz/kronuz$U.lo mpz/kronzs$U.lo mpz/kronzu$U.lo			\
+  mpz/lcm$U.lo mpz/lcm_ui$U.lo mpz/limbs_finish$U.lo			\
+  mpz/limbs_modify$U.lo mpz/limbs_read$U.lo mpz/limbs_write$U.lo	\
+  mpz/lucmod$U.lo mpz/lucnum_ui$U.lo mpz/lucnum2_ui$U.lo		\
+  mpz/millerrabin$U.lo mpz/mod$U.lo mpz/mul$U.lo mpz/mul_2exp$U.lo	\
+  mpz/mul_si$U.lo mpz/mul_ui$U.lo					\
+  mpz/n_pow_ui$U.lo mpz/neg$U.lo mpz/nextprime$U.lo			\
+  mpz/out_raw$U.lo mpz/out_str$U.lo mpz/perfpow$U.lo mpz/perfsqr$U.lo	\
+  mpz/popcount$U.lo mpz/pow_ui$U.lo mpz/powm$U.lo mpz/powm_sec$U.lo	\
+  mpz/powm_ui$U.lo mpz/primorial_ui$U.lo				\
+  mpz/pprime_p$U.lo mpz/random$U.lo mpz/random2$U.lo			\
+  mpz/realloc$U.lo mpz/realloc2$U.lo mpz/remove$U.lo mpz/roinit_n$U.lo  \
+  mpz/root$U.lo mpz/rootrem$U.lo mpz/rrandomb$U.lo mpz/scan0$U.lo	\
+  mpz/scan1$U.lo mpz/set$U.lo mpz/set_d$U.lo mpz/set_f$U.lo		\
+  mpz/set_q$U.lo mpz/set_si$U.lo mpz/set_str$U.lo mpz/set_ui$U.lo	\
+  mpz/setbit$U.lo							\
+  mpz/size$U.lo mpz/sizeinbase$U.lo mpz/sqrt$U.lo			\
+  mpz/sqrtrem$U.lo mpz/stronglucas$U.lo mpz/sub$U.lo			\
+  mpz/sub_ui$U.lo mpz/swap$U.lo						\
+  mpz/tdiv_ui$U.lo mpz/tdiv_q$U.lo mpz/tdiv_q_2exp$U.lo			\
+  mpz/tdiv_q_ui$U.lo mpz/tdiv_qr$U.lo mpz/tdiv_qr_ui$U.lo		\
+  mpz/tdiv_r$U.lo mpz/tdiv_r_2exp$U.lo mpz/tdiv_r_ui$U.lo		\
+  mpz/tstbit$U.lo mpz/ui_pow_ui$U.lo mpz/ui_sub$U.lo mpz/urandomb$U.lo	\
+  mpz/urandomm$U.lo mpz/xor$U.lo
+
+MPQ_OBJECTS = mpq/abs$U.lo mpq/aors$U.lo				\
+  mpq/canonicalize$U.lo mpq/clear$U.lo mpq/clears$U.lo			\
+  mpq/cmp$U.lo mpq/cmp_si$U.lo mpq/cmp_ui$U.lo mpq/div$U.lo		\
+  mpq/get_d$U.lo mpq/get_den$U.lo mpq/get_num$U.lo mpq/get_str$U.lo	\
+  mpq/init$U.lo mpq/inits$U.lo mpq/inp_str$U.lo mpq/inv$U.lo		\
+  mpq/md_2exp$U.lo mpq/mul$U.lo mpq/neg$U.lo mpq/out_str$U.lo		\
+  mpq/set$U.lo mpq/set_den$U.lo mpq/set_num$U.lo			\
+  mpq/set_si$U.lo mpq/set_str$U.lo mpq/set_ui$U.lo			\
+  mpq/equal$U.lo mpq/set_z$U.lo mpq/set_d$U.lo				\
+  mpq/set_f$U.lo mpq/swap$U.lo
+
+MPN_OBJECTS = mpn/fib_table$U.lo mpn/mp_bases$U.lo
+PRINTF_OBJECTS = \
+  printf/asprintf$U.lo printf/asprntffuns$U.lo				\
+  printf/doprnt$U.lo printf/doprntf$U.lo printf/doprnti$U.lo		\
+  printf/fprintf$U.lo							\
+  printf/obprintf$U.lo printf/obvprintf$U.lo printf/obprntffuns$U.lo	\
+  printf/printf$U.lo printf/printffuns$U.lo				\
+  printf/snprintf$U.lo printf/snprntffuns$U.lo				\
+  printf/sprintf$U.lo printf/sprintffuns$U.lo				\
+  printf/vasprintf$U.lo printf/vfprintf$U.lo printf/vprintf$U.lo	\
+  printf/vsnprintf$U.lo printf/vsprintf$U.lo				\
+  printf/repl-vsnprintf$U.lo
+
+SCANF_OBJECTS = \
+  scanf/doscan$U.lo scanf/fscanf$U.lo scanf/fscanffuns$U.lo	\
+  scanf/scanf$U.lo scanf/sscanf$U.lo scanf/sscanffuns$U.lo	\
+  scanf/vfscanf$U.lo scanf/vscanf$U.lo scanf/vsscanf$U.lo
+
+RANDOM_OBJECTS = \
+  rand/rand$U.lo rand/randclr$U.lo rand/randdef$U.lo rand/randiset$U.lo	\
+  rand/randlc2s$U.lo rand/randlc2x$U.lo rand/randmt$U.lo		\
+  rand/randmts$U.lo rand/rands$U.lo rand/randsd$U.lo rand/randsdui$U.lo	\
+  rand/randbui$U.lo rand/randmui$U.lo
+
+
+# no $U for C++ files
+CXX_OBJECTS = \
+  cxx/isfuns.lo cxx/ismpf.lo cxx/ismpq.lo cxx/ismpz.lo cxx/ismpznw.lo	\
+  cxx/limits.lo cxx/osdoprnti.lo cxx/osfuns.lo				\
+  cxx/osmpf.lo cxx/osmpq.lo cxx/osmpz.lo
+
+
+# In libtool 1.5 it doesn't work to build libgmp.la from the convenience
+# libraries like mpz/libmpz.la.  Or rather it works, but it ends up putting
+# PIC objects into libgmp.a if shared and static are both built.  (The PIC
+# objects go into mpz/.libs/libmpz.a, and thence into .libs/libgmp.a.)
+#
+# For now the big lists of objects above are used.  Something like mpz/*.lo
+# would probably work, but might risk missing something out or getting
+# something extra.  The source files for each .lo are listed in the
+# Makefile.am's in the subdirectories.
+#
+# Currently, for libgmp, unlike libmp below, we're not using
+# -export-symbols, since the tune and speed programs, and perhaps some of
+# the test programs, want to access undocumented symbols.
+libgmp_la_SOURCES = gmp-impl.h longlong.h				\
+  assert.c compat.c errno.c extract-dbl.c invalid.c memory.c		\
+  mp_bpl.c mp_clz_tab.c mp_dv_tab.c mp_minv_tab.c mp_get_fns.c mp_set_fns.c \
+  version.c nextprime.c primesieve.c
+
+EXTRA_libgmp_la_SOURCES = tal-debug.c tal-notreent.c tal-reent.c
+libgmp_la_DEPENDENCIES = @TAL_OBJECT@		\
+  $(MPF_OBJECTS) $(MPZ_OBJECTS) $(MPQ_OBJECTS)	\
+  $(MPN_OBJECTS) @mpn_objs_in_libgmp@		\
+  $(PRINTF_OBJECTS)  $(SCANF_OBJECTS) $(RANDOM_OBJECTS)
+
+libgmp_la_LIBADD = $(libgmp_la_DEPENDENCIES)
+libgmp_la_LDFLAGS = $(GMP_LDFLAGS) $(LIBGMP_LDFLAGS) \
+  -version-info $(LIBGMP_LT_CURRENT):$(LIBGMP_LT_REVISION):$(LIBGMP_LT_AGE)
+
+
+# We need at least one .cc file in $(libgmpxx_la_SOURCES) so automake will
+# use $(CXXLINK) rather than the plain C $(LINK).  cxx/dummy.cc is that
+# file.
+@WANT_CXX_TRUE@GMPXX_LTLIBRARIES_OPTION = libgmpxx.la
+libgmpxx_la_SOURCES = cxx/dummy.cc
+libgmpxx_la_DEPENDENCIES = $(CXX_OBJECTS) libgmp.la
+libgmpxx_la_LIBADD = $(libgmpxx_la_DEPENDENCIES)
+libgmpxx_la_LDFLAGS = $(GMP_LDFLAGS) $(LIBGMPXX_LDFLAGS) \
+  -version-info $(LIBGMPXX_LT_CURRENT):$(LIBGMPXX_LT_REVISION):$(LIBGMPXX_LT_AGE)
+
+all: $(BUILT_SOURCES) config.h
+	$(MAKE) $(AM_MAKEFLAGS) all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .c .cc .lo .o .obj
+am--refresh: Makefile
+	@:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      echo ' cd $(srcdir) && $(AUTOMAKE) --gnu --ignore-deps'; \
+	      $(am__cd) $(srcdir) && $(AUTOMAKE) --gnu --ignore-deps \
+		&& exit 0; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu --ignore-deps Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu --ignore-deps Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    echo ' $(SHELL) ./config.status'; \
+	    $(SHELL) ./config.status;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	$(SHELL) ./config.status --recheck
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	$(am__cd) $(srcdir) && $(AUTOCONF)
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	$(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
+$(am__aclocal_m4_deps):
+
+config.h: stamp-h1
+	@test -f $@ || rm -f stamp-h1
+	@test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1
+
+stamp-h1: $(srcdir)/config.in $(top_builddir)/config.status
+	@rm -f stamp-h1
+	cd $(top_builddir) && $(SHELL) ./config.status config.h
+$(srcdir)/config.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) 
+	($(am__cd) $(top_srcdir) && $(AUTOHEADER))
+	rm -f stamp-h1
+	touch $@
+
+distclean-hdr:
+	-rm -f config.h stamp-h1
+gmp.h: $(top_builddir)/config.status $(srcdir)/gmp-h.in
+	cd $(top_builddir) && $(SHELL) ./config.status $@
+gmp.pc: $(top_builddir)/config.status $(srcdir)/gmp.pc.in
+	cd $(top_builddir) && $(SHELL) ./config.status $@
+gmpxx.pc: $(top_builddir)/config.status $(srcdir)/gmpxx.pc.in
+	cd $(top_builddir) && $(SHELL) ./config.status $@
+
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+	@$(NORMAL_INSTALL)
+	@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+	list2=; for p in $$list; do \
+	  if test -f $$p; then \
+	    list2="$$list2 $$p"; \
+	  else :; fi; \
+	done; \
+	test -z "$$list2" || { \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+	}
+
+uninstall-libLTLIBRARIES:
+	@$(NORMAL_UNINSTALL)
+	@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+	for p in $$list; do \
+	  $(am__strip_dir) \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+	done
+
+clean-libLTLIBRARIES:
+	-test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+	@list='$(lib_LTLIBRARIES)'; \
+	locs=`for p in $$list; do echo $$p; done | \
+	      sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+	      sort -u`; \
+	test -z "$$locs" || { \
+	  echo rm -f $${locs}; \
+	  rm -f $${locs}; \
+	}
+
+libgmp.la: $(libgmp_la_OBJECTS) $(libgmp_la_DEPENDENCIES) $(EXTRA_libgmp_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(libgmp_la_LINK) -rpath $(libdir) $(libgmp_la_OBJECTS) $(libgmp_la_LIBADD) $(LIBS)
+cxx/$(am__dirstamp):
+	@$(MKDIR_P) cxx
+	@: > cxx/$(am__dirstamp)
+cxx/dummy.lo: cxx/$(am__dirstamp)
+
+libgmpxx.la: $(libgmpxx_la_OBJECTS) $(libgmpxx_la_DEPENDENCIES) $(EXTRA_libgmpxx_la_DEPENDENCIES) 
+	$(AM_V_CXXLD)$(libgmpxx_la_LINK) $(am_libgmpxx_la_rpath) $(libgmpxx_la_OBJECTS) $(libgmpxx_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+	-rm -f cxx/*.$(OBJEXT)
+	-rm -f cxx/*.lo
+
+distclean-compile:
+	-rm -f *.tab.c
+
+.c.o:
+	$(AM_V_CC)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+	$(AM_V_CC)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+	$(AM_V_CC)$(LTCOMPILE) -c -o $@ $<
+
+.cc.o:
+	$(AM_V_CXX)$(CXXCOMPILE) -c -o $@ $<
+
+.cc.obj:
+	$(AM_V_CXX)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cc.lo:
+	$(AM_V_CXX)$(LTCXXCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+	-rm -rf cxx/.libs cxx/_libs
+
+distclean-libtool:
+	-rm -f libtool config.lt
+install-pkgconfigDATA: $(pkgconfig_DATA)
+	@$(NORMAL_INSTALL)
+	@list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \
+	if test -n "$$list"; then \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(pkgconfigdir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" || exit 1; \
+	fi; \
+	for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  echo "$$d$$p"; \
+	done | $(am__base_list) | \
+	while read files; do \
+	  echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \
+	  $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \
+	done
+
+uninstall-pkgconfigDATA:
+	@$(NORMAL_UNINSTALL)
+	@list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \
+	files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+	dir='$(DESTDIR)$(pkgconfigdir)'; $(am__uninstall_files_from_dir)
+install-includeHEADERS: $(include_HEADERS)
+	@$(NORMAL_INSTALL)
+	@list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \
+	if test -n "$$list"; then \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(includedir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(includedir)" || exit 1; \
+	fi; \
+	for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  echo "$$d$$p"; \
+	done | $(am__base_list) | \
+	while read files; do \
+	  echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includedir)'"; \
+	  $(INSTALL_HEADER) $$files "$(DESTDIR)$(includedir)" || exit $$?; \
+	done
+
+uninstall-includeHEADERS:
+	@$(NORMAL_UNINSTALL)
+	@list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \
+	files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+	dir='$(DESTDIR)$(includedir)'; $(am__uninstall_files_from_dir)
+install-nodist_includeexecHEADERS: $(nodist_includeexec_HEADERS)
+	@$(NORMAL_INSTALL)
+	@list='$(nodist_includeexec_HEADERS)'; test -n "$(includeexecdir)" || list=; \
+	if test -n "$$list"; then \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(includeexecdir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(includeexecdir)" || exit 1; \
+	fi; \
+	for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  echo "$$d$$p"; \
+	done | $(am__base_list) | \
+	while read files; do \
+	  echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includeexecdir)'"; \
+	  $(INSTALL_HEADER) $$files "$(DESTDIR)$(includeexecdir)" || exit $$?; \
+	done
+
+uninstall-nodist_includeexecHEADERS:
+	@$(NORMAL_UNINSTALL)
+	@list='$(nodist_includeexec_HEADERS)'; test -n "$(includeexecdir)" || list=; \
+	files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+	dir='$(DESTDIR)$(includeexecdir)'; $(am__uninstall_files_from_dir)
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+#     (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+	@fail=; \
+	if $(am__make_keepgoing); then \
+	  failcom='fail=yes'; \
+	else \
+	  failcom='exit 1'; \
+	fi; \
+	dot_seen=no; \
+	target=`echo $@ | sed s/-recursive//`; \
+	case "$@" in \
+	  distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+	  *) list='$(SUBDIRS)' ;; \
+	esac; \
+	for subdir in $$list; do \
+	  echo "Making $$target in $$subdir"; \
+	  if test "$$subdir" = "."; then \
+	    dot_seen=yes; \
+	    local_target="$$target-am"; \
+	  else \
+	    local_target="$$target"; \
+	  fi; \
+	  ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+	  || eval $$failcom; \
+	done; \
+	if test "$$dot_seen" = "no"; then \
+	  $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+	fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+	  include_option=--etags-include; \
+	  empty_fix=.; \
+	else \
+	  include_option=--include; \
+	  empty_fix=; \
+	fi; \
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    test ! -f $$subdir/TAGS || \
+	      set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+	  fi; \
+	done; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscope: cscope.files
+	test ! -s cscope.files \
+	  || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS)
+clean-cscope:
+	-rm -f cscope.files
+cscope.files: clean-cscope cscopelist
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+	-rm -f cscope.out cscope.in.out cscope.po.out cscope.files
+
+distdir: $(DISTFILES)
+	$(am__remove_distdir)
+	test -d "$(distdir)" || mkdir "$(distdir)"
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+	@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    $(am__make_dryrun) \
+	      || test -d "$(distdir)/$$subdir" \
+	      || $(MKDIR_P) "$(distdir)/$$subdir" \
+	      || exit 1; \
+	    dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+	    $(am__relativize); \
+	    new_distdir=$$reldir; \
+	    dir1=$$subdir; dir2="$(top_distdir)"; \
+	    $(am__relativize); \
+	    new_top_distdir=$$reldir; \
+	    echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+	    echo "     am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+	    ($(am__cd) $$subdir && \
+	      $(MAKE) $(AM_MAKEFLAGS) \
+	        top_distdir="$$new_top_distdir" \
+	        distdir="$$new_distdir" \
+		am__remove_distdir=: \
+		am__skip_length_check=: \
+		am__skip_mode_fix=: \
+	        distdir) \
+	      || exit 1; \
+	  fi; \
+	done
+	$(MAKE) $(AM_MAKEFLAGS) \
+	  top_distdir="$(top_distdir)" distdir="$(distdir)" \
+	  dist-hook
+	-test -n "$(am__skip_mode_fix)" \
+	|| find "$(distdir)" -type d ! -perm -755 \
+		-exec chmod u+rwx,go+rx {} \; -o \
+	  ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
+	  ! -type d ! -perm -400 -exec chmod a+r {} \; -o \
+	  ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
+	|| chmod -R a+r "$(distdir)"
+dist-gzip: distdir
+	tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+	$(am__post_remove_distdir)
+
+dist-bzip2: distdir
+	tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2
+	$(am__post_remove_distdir)
+
+dist-lzip: distdir
+	tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz
+	$(am__post_remove_distdir)
+
+dist-xz: distdir
+	tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz
+	$(am__post_remove_distdir)
+
+dist-tarZ: distdir
+	@echo WARNING: "Support for distribution archives compressed with" \
+		       "legacy program 'compress' is deprecated." >&2
+	@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
+	tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
+	$(am__post_remove_distdir)
+
+dist-shar: distdir
+	@echo WARNING: "Support for shar distribution archives is" \
+	               "deprecated." >&2
+	@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
+	shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
+	$(am__post_remove_distdir)
+
+dist-zip: distdir
+	-rm -f $(distdir).zip
+	zip -rq $(distdir).zip $(distdir)
+	$(am__post_remove_distdir)
+
+dist dist-all:
+	$(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:'
+	$(am__post_remove_distdir)
+
+# This target untars the dist file and tries a VPATH configuration.  Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+	case '$(DIST_ARCHIVES)' in \
+	*.tar.gz*) \
+	  GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\
+	*.tar.bz2*) \
+	  bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
+	*.tar.lz*) \
+	  lzip -dc $(distdir).tar.lz | $(am__untar) ;;\
+	*.tar.xz*) \
+	  xz -dc $(distdir).tar.xz | $(am__untar) ;;\
+	*.tar.Z*) \
+	  uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
+	*.shar.gz*) \
+	  GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\
+	*.zip*) \
+	  unzip $(distdir).zip ;;\
+	esac
+	chmod -R a-w $(distdir)
+	chmod u+w $(distdir)
+	mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst
+	chmod a-w $(distdir)
+	test -d $(distdir)/_build || exit 0; \
+	dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
+	  && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
+	  && am__cwd=`pwd` \
+	  && $(am__cd) $(distdir)/_build/sub \
+	  && ../../configure \
+	    $(AM_DISTCHECK_CONFIGURE_FLAGS) \
+	    $(DISTCHECK_CONFIGURE_FLAGS) \
+	    --srcdir=../.. --prefix="$$dc_install_base" \
+	  && $(MAKE) $(AM_MAKEFLAGS) \
+	  && $(MAKE) $(AM_MAKEFLAGS) dvi \
+	  && $(MAKE) $(AM_MAKEFLAGS) check \
+	  && $(MAKE) $(AM_MAKEFLAGS) install \
+	  && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+	  && $(MAKE) $(AM_MAKEFLAGS) uninstall \
+	  && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
+	        distuninstallcheck \
+	  && chmod -R a-w "$$dc_install_base" \
+	  && ({ \
+	       (cd ../.. && umask 077 && mkdir "$$dc_destdir") \
+	       && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
+	       && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
+	       && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
+	            distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
+	      } || { rm -rf "$$dc_destdir"; exit 1; }) \
+	  && rm -rf "$$dc_destdir" \
+	  && $(MAKE) $(AM_MAKEFLAGS) dist \
+	  && rm -rf $(DIST_ARCHIVES) \
+	  && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \
+	  && cd "$$am__cwd" \
+	  || exit 1
+	$(am__post_remove_distdir)
+	@(echo "$(distdir) archives ready for distribution: "; \
+	  list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
+	  sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'
+distuninstallcheck:
+	@test -n '$(distuninstallcheck_dir)' || { \
+	  echo 'ERROR: trying to run $@ with an empty' \
+	       '$$(distuninstallcheck_dir)' >&2; \
+	  exit 1; \
+	}; \
+	$(am__cd) '$(distuninstallcheck_dir)' || { \
+	  echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \
+	  exit 1; \
+	}; \
+	test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \
+	   || { echo "ERROR: files left after uninstall:" ; \
+	        if test -n "$(DESTDIR)"; then \
+	          echo "  (check DESTDIR support)"; \
+	        fi ; \
+	        $(distuninstallcheck_listfiles) ; \
+	        exit 1; } >&2
+distcleancheck: distclean
+	@if test '$(srcdir)' = . ; then \
+	  echo "ERROR: distcleancheck can only run from a VPATH build" ; \
+	  exit 1 ; \
+	fi
+	@test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
+	  || { echo "ERROR: files left in build directory after distclean:" ; \
+	       $(distcleancheck_listfiles) ; \
+	       exit 1; } >&2
+check-am: all-am
+check: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) check-recursive
+all-am: Makefile $(LTLIBRARIES) $(DATA) $(HEADERS) config.h
+installdirs: installdirs-recursive
+installdirs-am:
+	for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkgconfigdir)" "$(DESTDIR)$(includedir)" "$(DESTDIR)$(includeexecdir)"; do \
+	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+	done
+install: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+	-rm -f cxx/$(am__dirstamp)
+	-test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+	-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-recursive
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool clean-local \
+	mostlyclean-am
+
+distclean: distclean-recursive
+	-rm -f $(am__CONFIG_DISTCLEAN_FILES)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-hdr distclean-libtool distclean-local distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am: install-includeHEADERS install-pkgconfigDATA
+	@$(NORMAL_INSTALL)
+	$(MAKE) $(AM_MAKEFLAGS) install-data-hook
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am: install-libLTLIBRARIES \
+	install-nodist_includeexecHEADERS
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+	-rm -f $(am__CONFIG_DISTCLEAN_FILES)
+	-rm -rf $(top_srcdir)/autom4te.cache
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-includeHEADERS uninstall-libLTLIBRARIES \
+	uninstall-nodist_includeexecHEADERS uninstall-pkgconfigDATA
+
+.MAKE: $(am__recursive_targets) all check install install-am \
+	install-data-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \
+	am--refresh check check-am clean clean-cscope clean-generic \
+	clean-libLTLIBRARIES clean-libtool clean-local cscope \
+	cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \
+	dist-gzip dist-hook dist-lzip dist-shar dist-tarZ dist-xz \
+	dist-zip distcheck distclean distclean-compile \
+	distclean-generic distclean-hdr distclean-libtool \
+	distclean-local distclean-tags distcleancheck distdir \
+	distuninstallcheck dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am \
+	install-data-hook install-dvi install-dvi-am install-exec \
+	install-exec-am install-html install-html-am \
+	install-includeHEADERS install-info install-info-am \
+	install-libLTLIBRARIES install-man \
+	install-nodist_includeexecHEADERS install-pdf install-pdf-am \
+	install-pkgconfigDATA install-ps install-ps-am install-strip \
+	installcheck installcheck-am installdirs installdirs-am \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+	pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \
+	uninstall-includeHEADERS uninstall-libLTLIBRARIES \
+	uninstall-nodist_includeexecHEADERS uninstall-pkgconfigDATA
+
+.PRECIOUS: Makefile
+
+
+install-data-hook:
+	@echo ''
+	@echo '+-------------------------------------------------------------+'
+	@echo '| CAUTION:                                                    |'
+	@echo '|                                                             |'
+	@echo '| If you have not already run "make check", then we strongly  |'
+	@echo '| recommend you do so.                                        |'
+	@echo '|                                                             |'
+	@echo '| GMP has been carefully tested by its authors, but compilers |'
+	@echo '| are all too often released with serious bugs.  GMP tends to |'
+	@echo '| explore interesting corners in compilers and has hit bugs   |'
+	@echo '| on quite a few occasions.                                   |'
+	@echo '|                                                             |'
+	@echo '+-------------------------------------------------------------+'
+	@echo ''
+
+fac_table.h: gen-fac$(EXEEXT_FOR_BUILD)
+	./gen-fac $(GMP_LIMB_BITS) $(GMP_NAIL_BITS) >fac_table.h || (rm -f fac_table.h; exit 1)
+
+gen-fac$(EXEEXT_FOR_BUILD): gen-fac$(U_FOR_BUILD).c bootstrap.c
+	$(CC_FOR_BUILD) `test -f 'gen-fac$(U_FOR_BUILD).c' || echo '$(srcdir)/'`gen-fac$(U_FOR_BUILD).c -o gen-fac$(EXEEXT_FOR_BUILD)
+
+fib_table.h: gen-fib$(EXEEXT_FOR_BUILD)
+	./gen-fib header $(GMP_LIMB_BITS) $(GMP_NAIL_BITS) >fib_table.h || (rm -f fib_table.h; exit 1)
+
+mpn/fib_table.c: gen-fib$(EXEEXT_FOR_BUILD)
+	./gen-fib table $(GMP_LIMB_BITS) $(GMP_NAIL_BITS) >mpn/fib_table.c || (rm -f mpn/fib_table.c; exit 1)
+
+gen-fib$(EXEEXT_FOR_BUILD): gen-fib$(U_FOR_BUILD).c bootstrap.c
+	$(CC_FOR_BUILD) `test -f 'gen-fib$(U_FOR_BUILD).c' || echo '$(srcdir)/'`gen-fib$(U_FOR_BUILD).c -o gen-fib$(EXEEXT_FOR_BUILD)
+
+mp_bases.h: gen-bases$(EXEEXT_FOR_BUILD)
+	./gen-bases header $(GMP_LIMB_BITS) $(GMP_NAIL_BITS) >mp_bases.h || (rm -f mp_bases.h; exit 1)
+
+mpn/mp_bases.c: gen-bases$(EXEEXT_FOR_BUILD)
+	./gen-bases table $(GMP_LIMB_BITS) $(GMP_NAIL_BITS) >mpn/mp_bases.c || (rm -f mpn/mp_bases.c; exit 1)
+
+gen-bases$(EXEEXT_FOR_BUILD): gen-bases$(U_FOR_BUILD).c bootstrap.c
+	$(CC_FOR_BUILD) `test -f 'gen-bases$(U_FOR_BUILD).c' || echo '$(srcdir)/'`gen-bases$(U_FOR_BUILD).c -o gen-bases$(EXEEXT_FOR_BUILD) $(LIBM_FOR_BUILD)
+
+trialdivtab.h: gen-trialdivtab$(EXEEXT_FOR_BUILD)
+	./gen-trialdivtab $(GMP_LIMB_BITS) 8000 >trialdivtab.h || (rm -f trialdivtab.h; exit 1)
+
+gen-trialdivtab$(EXEEXT_FOR_BUILD): gen-trialdivtab$(U_FOR_BUILD).c bootstrap.c
+	$(CC_FOR_BUILD) `test -f 'gen-trialdivtab$(U_FOR_BUILD).c' || echo '$(srcdir)/'`gen-trialdivtab$(U_FOR_BUILD).c -o gen-trialdivtab$(EXEEXT_FOR_BUILD) $(LIBM_FOR_BUILD)
+
+mpn/jacobitab.h: gen-jacobitab$(EXEEXT_FOR_BUILD)
+	./gen-jacobitab >mpn/jacobitab.h || (rm -f mpn/jacobitab.h; exit 1)
+
+gen-jacobitab$(EXEEXT_FOR_BUILD): gen-jacobitab$(U_FOR_BUILD).c
+	$(CC_FOR_BUILD) `test -f 'gen-jacobitab$(U_FOR_BUILD).c' || echo '$(srcdir)/'`gen-jacobitab$(U_FOR_BUILD).c -o gen-jacobitab$(EXEEXT_FOR_BUILD)
+
+mpn/perfsqr.h: gen-psqr$(EXEEXT_FOR_BUILD)
+	./gen-psqr $(GMP_LIMB_BITS) $(GMP_NAIL_BITS) >mpn/perfsqr.h || (rm -f mpn/perfsqr.h; exit 1)
+
+gen-psqr$(EXEEXT_FOR_BUILD): gen-psqr$(U_FOR_BUILD).c bootstrap.c
+	$(CC_FOR_BUILD) `test -f 'gen-psqr$(U_FOR_BUILD).c' || echo '$(srcdir)/'`gen-psqr$(U_FOR_BUILD).c -o gen-psqr$(EXEEXT_FOR_BUILD) $(LIBM_FOR_BUILD)
+
+# Avoid: CVS - cvs directories
+#        *~  - emacs backups
+#        .#* - cvs merge originals
+#
+# *~ and .#* only occur when a whole directory without it's own Makefile.am
+# is distributed, like "doc" or the mpn cpu subdirectories.
+#
+dist-hook:
+	-find $(distdir) \( -name CVS -type d \) -o -name "*~" -o -name ".#*" \
+		| xargs rm -rf
+	cp "$(srcdir)"/mini-gmp/tests/*.[ch] "$(distdir)/mini-gmp/tests"
+#	grep -F $(VERSION) $(srcdir)/Makefile.am \
+#		| grep -q "^# *$(VERSION) *$(LIBGMP_LT_CURRENT):$(LIBGMP_LT_REVISION):$(LIBGMP_LT_AGE) *$(LIBGMPXX_LT_CURRENT):$(LIBGMPXX_LT_REVISION):$(LIBGMPXX_LT_AGE)"
+#	test -z "`sed -n 's/^# *[0-9]*\.[0-9]*\.[0-9]* *\([0-9]*:[0-9]*:[0-9]*\) *\([0-9]*:[0-9]*:[0-9]*\) *\([0-9]*:[0-9]*:[0-9]*\).*/A\1\nB\2\nC\3/p' $(srcdir)/Makefile.am | grep -v 'A6:3:3\|B3:5:0\|C4:7:1' | sort | uniq -d`"
+
+.PHONY: check-mini-gmp clean-mini-gmp
+
+check-mini-gmp:
+	abs_srcdir="`cd $(srcdir) && pwd`" ; \
+	$(MKDIR_P) mini-gmp/tests \
+	&& cd mini-gmp/tests \
+	&& TEST_LIBRARY_PATH="../../.libs"  \
+	   $(MAKE) -f "$$abs_srcdir/mini-gmp/tests/Makefile" \
+		VPATH="$$abs_srcdir/mini-gmp/tests" \
+		srcdir="$$abs_srcdir/mini-gmp/tests" \
+		MINI_GMP_DIR="$$abs_srcdir/mini-gmp" \
+		LDFLAGS="-L../../.libs" \
+		LIBS="-lgmp -lm" \
+		CC="$(CC)" CFLAGS="$(CFLAGS)" CPPFLAGS="$(CPPFLAGS) -I../.." check
+
+clean-mini-gmp:
+	if [ -d mini-gmp/tests ] ; then \
+	  abs_srcdir="`cd $(srcdir) && pwd`" ; \
+	  cd mini-gmp/tests \
+	  && $(MAKE) -f "$$abs_srcdir/mini-gmp/tests/Makefile" clean ; \
+	fi
+
+clean-local: clean-mini-gmp
+distclean-local: clean-mini-gmp
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/third_party/gmp/NEWS b/third_party/gmp/NEWS
new file mode 100644
index 0000000..d83556a
--- /dev/null
+++ b/third_party/gmp/NEWS
@@ -0,0 +1,1054 @@
+Copyright 1996, 1999-2016, 2018-2020 Free Software Foundation, Inc.
+
+Verbatim copying and distribution of this entire article is permitted in any
+medium, provided this notice is preserved.
+
+Changes between GMP version 6.1.* and 6.2.0
+
+  BUGS FIXED
+  * gmp_snprintf now correctly reports an error (returns -1) when snprintf
+    does.
+
+  * Conversion to double is now more robust even if the configuration process
+    does not recognize the float format.
+
+  * mpz_powm could return a not completely normalised value, when the
+    exponent was 1 and the base < 0.
+
+  * mpf_set_str could create invalid mpf_t variables for input strings with
+    many leading zeros.
+
+  FEATURES
+  * New C++ functions factorial, primorial and fibonacci for mpz_class.
+
+  * Functions to detect primality now substitute the first 24 Miller-Rabin
+    iterations with the BPSW test.
+
+  * Mini-GMP: new functions mpz_2fac_ui and mpz_mfac_uiui.
+
+  * Mini-GMP: mpz_sizeinbase, mpz_get_str, and mpz_set_str now support bases up
+    to 62.
+
+  * Mini-GMP: added support for the mpq_t layer.
+
+  * MIPS r6 cores are now supported.
+
+  SPEEDUPS
+  * Major speedup for AMD Ryzen and Epyc thanks to an extensive set of assembly
+    code.
+
+  * Major speedup for IBM POWER9 thanks to assembly code making use of new madd
+    instruction.
+
+  * Speedup for 64-bit ARM CPUs thanks to new/improved assembly code.
+
+  * The n-over-k function mpz_bin_ui has been reimplemented for great speedups
+    for large operands.
+
+  * Speedup for the worst case of mpz_perfect_power_p.
+
+  * Speedup for gcd for small and medium size operands.
+
+  * Speedup for really huge multiplies thanks to much larger FFT tables.
+
+  MISC
+  * Internal representation of the mpz_t variables now supports lazy
+    allocation; memory is allocated only when a value is stored.
+
+  * Small improvements and better coverage for the test suite.
+
+  * The tune/speed program can measure some more functions.
+
+  * The low-level function mpn_mul no longer diverts to mpn_sqr, users should
+    call mpn_sqr directly when applicable.
+
+  * New installed files gmp.pc and gmpxx.pc, for use with pkg-config.
+    Contributed by Hugh McMaster.
+
+Changes between GMP version 6.1.1 and 6.1.2
+
+  BUGS FIXED
+  * Mini-GMP: Fixed a division bug, which on a machine with 64-bit
+    unsigned long affects approximately 1 out of 2^32 divisors.
+
+  * Mini-GMP: Fix mpz_set_str crash on inputs with a large number of
+    leading zeros. Also stricter input validation, rejecting inputs
+    with no digits.
+
+  FEATURES
+  * Handle more systems which require PIC code in static libraries (e.g.,
+    "hardened" Gentoo and Debian 9).
+
+  * Configuration for arm (-32 and -64) has been rewritten, fixing poor
+    code selection for many CPUs.
+
+  * Mini-GMP: Updated to the latest development version, including
+    new functions mpn_com and mpn_neg.
+
+  SPEEDUPS
+  * None, except for arm CPUs affected by the configuration rewrite.
+
+  MISC
+  -
+
+Changes between GMP version 6.1.0 and 6.1.1
+
+  BUGS FIXED
+  * Make Intel Broadwell configurations work on Windows.
+
+  FEATURES
+  * Work around faulty cpuid on some recent Intel chips (this allows GMP to run
+    on Skylake Pentiums).
+
+  * Support thumb-less ARM chips.
+
+Changes between GMP version 6.0.* and 6.1.0
+
+  BUGS FIXED
+  * The public function mpn_com is now correctly declared in gmp.h.
+
+  * Healed possible failures of mpn_sec_sqr for non-cryptographic sizes for
+    some obsolete CPUs.
+
+  * The option --disable-assembly now disables all inlined asm.
+
+  * Fixed bug affecting mini-gmp's bitwise functions mpz_setbit, mpz_clrbit,
+    and mpz_combit.
+
+  * Various problems related to precision for mpf have been fixed.
+
+  * Fixed ABI incompatible stack alignment in calls from assembly code.
+
+  * Fixed PIC bug in popcount affecting Intel processors using the 32-bit ABI.
+
+  SPEEDUPS
+  * Speedup for Intel Broadwell and Skylake through assembly code making use of
+    new ADX instructions.
+
+  * Square root is now faster when the remainder is not needed. Also the speed
+    to compute the k-th root improved, for small sizes.
+
+  * Improved arm64 support.
+
+  FEATURES
+  * New C++ functions gcd and lcm for mpz_class.
+
+  * New public mpn functions mpn_divexact_1, mpn_zero_p, and mpn_cnd_swap.
+
+  * New public mpq_cmp_z function, to efficiently compare rationals with
+    integers.
+
+  * Support for Darwin in all x86 code, thereby enabling fat builds on Darwin.
+
+  * Support for more 32-bit arm processors.
+
+  * Support for compilation with clang/llvm on more platforms.  Caution: GMP
+    triggers mis-compilation bugs in clang for many platforms, such as arm, x86
+    (32-bit and 64-bit), powerpc, mips.
+
+  * Support for AVX-less modern x86 CPUs. (Such support might be missing either
+    because the CPU vendor chose to disable AVX, or because the running kernel
+    lacks AVX context switch support.)
+
+  * Stack usage trimmed; we believe 512 KiB is now sufficient for any GMP
+    call, irrespective of operand size.
+
+  * Support for NetBSD under Xen; we switch off AVX unconditionally under
+    NetBSD since a bug in NetBSD makes AVX fail under Xen.
+
+  MISC
+  * We now use manufacturers' code names for x86 CPUs, e.g., "haswell" instead
+    of names derived from the commercial brands.
+
+  * Small improvements and better coverage for the test suite.
+
+  * The various FreeBSD problems listed for 6.0.0 affect this release too.
+
+  * Tuned values for FFT multiplications are provided for larger number on
+    many platforms.
+
+Changes between GMP version 5.1.* and 6.0.0
+
+  BUGS FIXED
+  * The function mpz_invert now considers any number invertible in Z/1Z.
+
+  * The mpn multiply code now handles operands of more than 2^31 limbs
+    correctly.  (Note however that the mpz code is limited to 2^32 bits on
+    32-bit hosts and 2^37 bits on 64-bit hosts.)
+
+  * Contains all fixes from release 5.1.3.
+
+  SPEEDUPS
+  * Plain division of large operands is faster and more monotonous in operand
+    size.
+
+  * Major speedup for ARM, in particular ARM Cortex-A15, thanks to improved
+    assembly.
+
+  * Major speedup for SPARC T4/T5 and speedup also for T3, thanks to a lot of
+    new assembly.
+
+  * Speedup for Intel Sandy Bridge, Ivy Bridge, Haswell, thanks to rewritten
+    and vastly expanded assembly support.  Speedup also for the older Core 2
+    and Nehalem.
+
+  * Faster mixed arithmetic between mpq_class and double.
+
+  * With g++, optimise more operations when one argument is a simple constant.
+
+  FEATURES
+  * Support for new Intel and AMD CPUs.
+
+  * Support for ARM64 alias Aarch64 alias ARMv8.
+
+  * New public functions mpn_sec_mul and mpn_sec_sqr, implementing side-channel
+    silent multiplication and squaring.
+
+  * New public functions mpn_sec_div_qr and mpn_sec_div_r, implementing
+    side-channel silent division.
+
+  * New public functions mpn_cnd_add_n and mpn_cnd_sub_n.  Side-channel silent
+    conditional addition and subtraction.
+
+  * New public function mpn_sec_powm, implementing side-channel silent modexp.
+
+  * New public function mpn_sec_invert, implementing side-channel silent
+    modular inversion.
+
+  * Better support for applications which use the mpz_t type, but nevertheless
+    need to call some of the lower-level mpn functions.  See the documentation
+    for mpz_limbs_read and related functions.
+
+  MISC
+  * This release will not work on NetBSD 5.x, FreeBSD 7.x, 8.x or 9 series
+    before 9.3.  The reason is that the m4 command is not correctly
+    implemented.  (Workaround: Use an older GMP release, or install GNU m4 from
+    /usr/ports and tell GMP to use it.)
+
+  * This release will not build properly on FreeBSD/amd64 before version 10
+    using the 32-bit ABI (once a working m4 is installed).  The reason is
+    broken limits.h.  (Workaround: Use an older GMP release if using the 32-bit
+    ABI on these FreeBSD releases is important.)
+
+  * This release will not work reliably on FreeBSD 10.0 for i386 or amd64 using
+    the 32-bit ABI.  The reason is bugs in the compiler 'clang'.  Depending on
+    CPU-dependent compiler flags, GMP may or may not be miscompiled in a
+    particular build.  (Workaround: Compiling gcc from /usr/ports should work,
+    except that gcc circularly depends on GMP; we have not been able to test
+    that workaround due to FreeBSD 10.0 bugs affecting its ability to run under
+    KVM and Xen.)
+
+  * This release will not compile on FreeBSD before version 10 for i386,
+    targeting any modern AMD processor.  The reason is bugs in the old gcc
+    bundled with FreeBSD.  (Workaround: install a less obsolete gcc from
+    /usr/ports and tell GMP to use it, or override the -march=amdfam10
+    GMP configure command line argument.)
+
+
+Changes between GMP version 5.1.2 and 5.1.3
+
+  BUGS FIXED
+  * The internal functions mpn_sbpi1_div_qr_sec mpn_sbpi1_div_r_sec could
+    compute garbage with a low probability.  They are now rewritten, and the
+    test code has been improved.
+
+  * A bug in the ia64 implementation of mpn_divrem_2, clobbering some
+    callee-save registers, has been fixed. This is an internal
+    function, with the bug manifesting itself as miscomputation in,
+    e.g., mpn_sqrtrem.
+
+  * The documentation now correctly says 'const' for input arguments.
+
+  SPEEDUPS
+  * None.
+
+  FEATURES
+  * None.
+
+  MISC
+  * None.
+
+
+Changes between GMP version 5.1.1 and 5.1.2
+
+  BUGS FIXED
+  * A bug in mpz_powm_ui triggered by base arguments of at least 15000 decimal
+    digits or mod arguments of at least 7500 decimal digits has been fixed.
+
+  * An AMD Bulldozer specific bug affecting the 64-bit Windows ABI has been
+    fixed.  This bug was in a key function (mpn_mul_1) and made both Bulldozer
+    specific builds and fat builds run on Bulldozer completely non-functional.
+
+  SPEEDUPS
+  * None.
+
+  FEATURES
+  * None.
+
+  MISC
+  * Fixes and generalisations to the test suite.
+
+  * Minor portability enhancements.
+
+
+Changes between GMP version 5.1.0 and 5.1.1
+
+  BUGS FIXED
+  * On Windows 64-bit, an error causing link errors about
+    __gmp_binvert_limb_table has been fixed.
+
+  * Aarch64 alias ARM64 support now works.
+
+  * A possible buffer overrun in mpz_ior has been fixed.
+
+  * A rare sign flip in mpz_remove has been fixed.
+
+  * A bug causing problems with mpf numbers with absolute value >= 2^31 has
+    been fixed.
+
+  * Several bugs in mini-gmp have been fixed.
+
+  * A bug caused by automake, related to the 'distcheck' target, has been fixed
+    by upgrading the automake used for GMP release engineering.
+
+  SPEEDUPS
+  * None.
+
+  FEATURES
+  * Preliminary support for the x32 ABI under x86-64.
+
+  MISC
+  * The mini-gmp testsuite now tests the entire set of functions.
+
+  * Various improvements of the GMP testsuite.
+
+
+Changes between GMP version 5.0.* and 5.1.0
+
+  BUGS FIXED
+  * When reading a C++ number (like mpz_class) in an istream reaches the end
+    of the stream, the eofbit is now set.
+
+  * The result sign of mpz_rootrem's remainder is now always correct.
+
+  * The mpz_remove function now handles negative divisors.
+
+  * Contains all fixes from release 5.0.5.
+
+  SPEEDUPS
+  * The n-factorial and n-over-k functions have been reimplemented for great
+    speedups for small and large operands.
+
+  * New subquadratic algorithm for the Kronecker/Jacobi/Legendre symbol.
+
+  * Major speedup for ARM, in particular ARM Cortex-A9 and A15, thanks to broad
+    assembly support.
+
+  * Significant speedup for POWER6 and POWER7 thanks to improved assembly.
+
+  * The performance under M$ Windows' 64-bit ABI has been greatly improved
+    thanks to complete assembly support.
+
+  * Minor speed improvements of many functions and for many platforms.
+
+  FEATURES
+  * Many new CPUs recognised.
+
+  * New functions for multi-factorials, and primorial: mpz_2fac_ui,
+    mpz_mfac_uiui and mpz_primorial_ui.
+
+  * The mpz_powm_sec function now uses side-channel silent division for
+    converting into Montgomery residues.
+
+  * The fat binary mechanism is now more robust in its CPU recognition.
+
+  MISC
+  * Inclusion of assembly code is now controlled by the configure options
+    --enable-assembly and --disable-assembly.  The "none" CPU target is gone.
+
+  * In C++, the conversions mpq_class->mpz_class, mpf_class->mpz_class and
+    mpf_class->mpq_class are now explicit.
+
+  * Includes "mini-gmp", a small, portable, but less efficient, implementation
+    of a subset of GMP's mpn and mpz interfaces. Used in GMP bootstrap, but it
+    can also be bundled with applications as a fallback when the real GMP
+    library is unavailable.
+
+  * The ABIs under AIX are no longer called aix32 and aix64, but mode64 and 32.
+    This is more consistent with other powerpc systems.
+
+  * The coverage of the testsuite has been improved, using the lcov tool.  See
+    also https://gmplib.org/devel/lcov/.
+
+  * It is now possible to compile GMP using a C++ compiler.
+
+  * K&R C compilers are no longer supported.
+
+  * The BSD MP compatibility functions have been removed.
+
+
+Changes between GMP version 5.0.4 and 5.0.5
+
+  BUGS FIXED
+  * A bug causing AMD 11h processors to be treated like AMD 10h has been fixed.
+    The 11h processors do not correctly handle all 10h (aka K10) instructions,
+    and GMP's use of these instructions results in major miscomputations (not
+    as one would have hoped CPU traps of some 'illegal instruction' sort).
+
+  * A bug affecting recent Intel Sandy Bridge CPUs resulting in configuration
+    failures has been fixed.
+
+  SPEEDUPS
+  * None.
+
+  FEATURES
+  * A couple of tests added to the self-check suite.
+
+  MISC
+  * None.
+
+
+Changes between GMP version 5.0.3 and 5.0.4
+
+  BUGS FIXED
+  * Thresholds in mpn_powm_sec for both fat and non-fat builds are now used
+    safely, plugging a one-word buffer overrun introduced in the 5.0.3 release
+    (for non-fat) and a multi-word buffer overrun that existed since 5.0 (for
+    fat).  (We have not been able to provoke malign stack smashing in any of
+    the ~100 configurations explored by the GMP nightly builds, but the bug
+    should be assumed to be exploitable.)
+
+  * Two bugs in multiplication code causing incorrect computation with
+    extremely low probability have been fixed.
+
+  * A bug in the test suite causing buffer overruns during "make check",
+    sometimes leading to subsequent malloc crashes, has been fixed.
+
+  * Two bugs in the gcd code have been fixed.  They could lead to incorrect
+    results, but for uniformly distributed random operands, the likelihood for
+    that is infinitesimally small.  (There was also a third bug, but that was
+    an incorrect ASSERT, which furthermore was not enabled by default.)
+
+  * A bug affecting 32-bit PowerPC division has been fixed.  The bug caused
+    miscomputation for certain divisors in the range 2^32 ... 2^64-1 (about 1
+    in 2^30 of these).
+
+  SPEEDUPS
+  * None, except indirectly through recognition of new CPUs, and through better
+    tuning parameters.
+
+  FEATURES
+  * Some more tests added to the self-check suite.
+
+  * The AMD "Bulldozer" CPU is now recognised.
+
+  MISC
+  * None.
+
+
+Changes between GMP version 5.0.2 and 5.0.3
+
+  BUGS FIXED
+  * A few minor bugs related to portability fixed.
+
+  * A slight timing leak of the powm_sec functions have been sealed.  (This
+    leak could possibly be used to extract the most significant few bits of the
+    exponent.  "Few" here means at most 10.)
+
+  * The mpz_nextprime function now runs a safer number of pseudo-random prime
+    tests.
+
+  * A bug in division code possibly causing incorrect computation was fixed.
+
+  SPEEDUPS
+  * None, except indirectly through recognition of new CPUs, and through better
+    tuning parameters.
+
+  FEATURES
+  * New CPUs recognised.
+
+  * IBM S/390 are now supported in both 31/32-bit and 64-bit mode.  (We have
+    not been able to fully test this on any multilib machine, since IBM expired
+    our guest account a few days before our release.)
+
+  MISC
+  * None.
+
+
+Changes between GMP version 5.0.1 and 5.0.2
+
+  BUGS FIXED
+  * Many minor bugs related to portability fixed.
+
+  * The support for HPPA 2.0N now works, after an assembly bug fix.
+
+  * A test case type error has been fixed.  The symptom of this bug was
+    spurious 'make check' failures.
+
+  SPEEDUPS
+  * None, except indirectly through recognition of new CPUs.
+
+  FEATURES
+  * Fat builds are now supported for 64-bit x86 processors also under Darwin.
+
+  MISC
+  * None.
+
+
+Changes between GMP version 5.0.0 and 5.0.1
+
+  BUGS FIXED
+  * Fat builds fixed.
+
+  * Fixed crash for huge multiplies when old FFT_TABLE2 type of parameter
+    selection tables' sentinel was smaller than multiplied operands.
+
+  * The solib numbers now reflect the removal of the documented but preliminary
+    mpn_bdivmod function; we correctly flag incompatibility with GMP 4.3.  GMP
+    5.0.0 has this wrong, and should perhaps be uninstalled to avoid confusion.
+
+  SPEEDUPS
+  * Multiplication of large numbers has indirectly been sped up through better
+    FFT tuning and processor recognition.  Since many operations depend on
+    multiplication, there will be a general speedup.
+
+  FEATURES
+  * More Core i3, i5 an Core i7 processor models are recognised.
+
+  * Fixes and workarounds for Mac OS quirks should make this GMP version build
+    using many of the different versions of "Xcode".
+
+  MISC
+  * The amount of scratch memory needed for multiplication of huge numbers has
+    been reduced substantially (but is still larger than in GMP 4.3.)
+
+  * Likewise, the amount of scratch memory needed for division of large numbers
+    has been reduced substantially.
+
+  * The FFT tuning code of tune/tuneup.c has been completely rewritten, and
+    new, large FFT parameter selection tables are provided for many machines.
+
+  * Upgraded to the latest autoconf, automake, libtool.
+
+
+Changes between GMP version 4.3.X and 5.0.0
+
+  BUGS FIXED
+  * None (contains the same fixes as release 4.3.2).
+
+  SPEEDUPS
+  * Multiplication has been overhauled:
+    (1) Multiplication of larger same size operands has been improved with
+        the addition of two new Toom functions and a new internal function
+        mpn_mulmod_bnm1 (computing U * V mod (B^n-1), B being the word base.
+        This latter function is used for the largest products, waiting for a
+        better Schoenhage-Strassen U * V mod (B^n+1) implementation.
+    (2) Likewise for squaring.
+    (3) Multiplication of different size operands has been improved with the
+        addition of many new Toom function, and by selecting underlying
+        functions better from the main multiply functions.
+
+  * Division and mod have been overhauled:
+    (1) Plain "schoolbook" division is reimplemented using faster quotient
+        approximation.
+    (2) Division Q = N/D, R = N mod D where both the quotient and remainder
+        are needed now runs in time O(M(log(N))).  This is an improvement of
+        a factor log(log(N))
+    (3) Division where just the quotient is needed is now O(M(log(Q))) on
+        average.
+    (4) Modulo operations using Montgomery REDC form now take time O(M(n)).
+    (5) Exact division Q = N/D by means of mpz_divexact has been improved
+        for all sizes, and now runs in time O(M(log(N))).
+
+  * The function mpz_powm is now faster for all sizes.  Its complexity has
+    gone from O(M(n)log(n)m) to O(M(n)m) where n is the size of the modulo
+    argument and m is the size of the exponent.  It is also radically
+    faster for even modulus, since it now partially factors such modulus
+    and performs two smaller modexp operations, then uses CRT.
+
+  * The internal support for multiplication yielding just the lower n limbs
+    has been improved by using Mulders' algorithm.
+
+  * Computation of inverses, both plain 1/N and 1/N mod B^n have been
+    improved by using well-tuned Newton iterations, and wrap-around
+    multiplication using mpn_mulmod_bnm1.
+
+  * A new algorithm makes mpz_perfect_power_p asymptotically faster.
+
+  * The function mpz_remove uses a much faster algorithm, is better tuned,
+    and also benefits from the division improvements.
+
+  * Intel Atom and VIA Nano specific optimisations.
+
+  * Plus hundreds of smaller improvements and tweaks!
+
+  FEATURES
+  * New mpz function: mpz_powm_sec for side-channel quiet modexp
+    computations.
+
+  * New mpn functions: mpn_sqr, mpn_and_n, mpn_ior_n, mpn_xor_n, mpn_nand_n,
+    mpn_nior_n, mpn_xnor_n, mpn_andn_n, mpn_iorn_n, mpn_com, mpn_neg,
+    mpn_copyi, mpn_copyd, mpn_zero.
+
+  * The function mpn_tdiv_qr now allows certain argument overlap.
+
+  * Support for fat binaries for 64-bit x86 processors has been added.
+
+  * A new type, mp_bitcnt_t for bignum bit counts, has been introduced.
+
+  * Support for Windows64 through mingw64 has been added.
+
+  * The cofactors of mpz_gcdext and mpn_gcdext are now more strictly
+    normalised, returning to how GMP 4.2 worked.  (Note that also release
+    4.3.2 has this change.)
+
+  MISC
+  * The mpn_mul function should no longer be used for squaring,
+    instead use the new mpn_sqr.
+
+  * The algorithm selection has been improved, the number of thresholds have
+    more than doubled, and the tuning and use of existing thresholds have
+    been improved.
+
+  * The tune/speed program can measure many of new functions.
+
+  * The mpn_bdivmod function has been removed.  We do not consider this an
+    incompatible change, since the function was marked as preliminary.
+
+  * The testsuite has been enhanced in various ways.
+
+
+Changes between GMP version 4.3.1 and 4.3.2
+
+  Bugs:
+  * Fixed bug in mpf_eq.
+  * Fixed overflow issues in mpz_set_str, mpz_inp_str, mpf_set_str, and
+    mpf_get_str.
+  * Avoid unbounded stack allocation for unbalanced multiplication.
+  * Fixed bug in FFT multiplication.
+
+  Speedups:
+  * None, except that proper processor recognition helps affected processors.
+
+  Features:
+  * Recognise more "Core 2" processor variants.
+  * The cofactors of mpz_gcdext and mpn_gcdext are now more strictly
+    normalised, returning to how GMP 4.2 worked.
+
+
+Changes between GMP version 4.3.0 and 4.3.1
+
+  Bugs:
+  * Fixed bug in mpn_gcdext, affecting also mpz_gcdext and mpz_invert.
+    The bug could cause a cofactor to have a leading zero limb, which
+    could lead to crashes or miscomputation later on.
+  * Fixed some minor documentation issues.
+
+  Speedups:
+  * None.
+
+  Features:
+  * Workarounds for various issues with Mac OS X's build tools.
+  * Recognise more IBM "POWER" processor variants.
+
+
+Changes between GMP version 4.2.X and 4.3.0
+
+  Bugs:
+  * Fixed bug in mpz_perfect_power_p with recognition of negative perfect
+    powers that can be written both as an even and odd power.
+  * We might accidentally have added bugs since there is a large amount of
+    new code in this release.
+
+  Speedups:
+  * Vastly improved assembly code for x86-64 processors from AMD and Intel.
+  * Major improvements also for many other processor families, such as
+    Alpha, PowerPC, and Itanium.
+  * New sub-quadratic mpn_gcd and mpn_gcdext, as well as improved basecase
+    gcd code.
+  * The multiply FFT code has been slightly improved.
+  * Balanced multiplication now uses 4-way Toom in addition to schoolbook,
+    Karatsuba, 3-way Toom, and FFT.
+  * Unbalanced multiplication has been vastly improved.
+  * Improved schoolbook division by means of faster quotient approximation.
+  * Several new algorithms for division and mod by single limbs, giving
+    many-fold speedups.
+  * Improved nth root computations.
+  * The mpz_nextprime function uses sieving and is much faster.
+  * Countless minor tweaks.
+
+  Features:
+  * Updated support for fat binaries for x86_32 include current processors
+  * Lots of new mpn internal interfaces.  Some of them will become public
+    in a future GMP release.
+  * Support for the 32-bit ABI under x86-apple-darwin.
+  * x86 CPU recognition code should now default better for future
+    processors.
+  * The experimental nails feature does not work in this release, but
+    it might be re-enabled in the future.
+
+  Misc:
+  * The gmp_version variable now always contains three parts.  For this
+    release, it is "4.3.0".
+
+
+Changes between GMP version 4.2.3 and 4.2.4
+
+  Bugs:
+  * Fix bug with parsing exponent '+' sign in mpf.
+  * Fix an allocation bug in mpf_set_str, also affecting mpf_init_set_str, and
+    mpf_inp_str.
+
+  Speedups:
+  * None, except that proper processor recognition helps affected processors.
+
+  Features:
+  * Recognize new AMD processors.
+
+
+Changes between GMP version 4.2.2 and 4.2.3
+
+  Bugs:
+  * Fix x86 CPU recognition code to properly identify recent AMD and Intel
+    64-bit processors.
+  * The >> operator of the C++ wrapper gmpxx.h now does floor rounding, not
+    truncation.
+  * Inline semantics now follow the C99 standard, and works with recent GCC
+    releases.
+  * C++ bitwise logical operations work for more types.
+  * For C++, gmp.h now includes cstdio, improving compiler compatibility.
+  * Bases > 36 now work properly in mpf_set_str.
+
+  Speedups:
+  * None, except that proper processor recognition helps affected processors.
+
+  Features:
+  * The allocation functions now detect overflow of the mpz_t type.  This means
+    that overflow will now cause an abort, except when the allocation
+    computation itself overflows.  (Such overflow can probably only happen in
+    powering functions; we will detect powering overflow in the future.)
+
+
+Changes between GMP version 4.2.1 and 4.2.2
+
+  * License is now LGPL version 3.
+
+  Bugs:
+  * Shared library numbers corrected for libcxx.
+  * Fixed serious bug in gmpxx.h where a=a+b*c would generate garbage.
+    Note that this only affects C++ programs.
+  * Fix crash in mpz_set_d for arguments with large negative exponent.
+  * Fix 32-bit ABI bug with Itanium assembly for popcount and hamdist.
+  * Fix assembly syntax problem for powerpc-ibm-aix with AIX native assembler.
+  * Fix problems with x86 --enable-fat, where the compiler where told to
+    generate code for the build machine, not plain i386 code as it should.
+  * Improved recognition of powerpc systems wrt Altivec/VMX capability.
+  * Misc minor fixes, mainly workarounds for compiler/assembler bugs.
+
+  Speedups:
+  * "Core 2" and Pentium 4 processors, running in 64-bit mode will get a
+     slight boost as they are now specifically recognized.
+
+  Features:
+  * New support for x86_64-solaris
+  * New, rudimentary support for x86-apple-darwin and x86_64-apple-darwin.
+    (Please see https://gmplib.org/macos.html for more information.)
+
+
+Changes between GMP version 4.2 and 4.2.1
+
+  Bugs:
+  * Shared library numbers corrected.
+  * Broken support for 32-bit AIX fixed.
+  * Misc minor fixes.
+
+  Speedups:
+  * Exact division (mpz_divexact) now falls back to plain division for large
+    operands.
+
+  Features:
+  * Support for some new systems.
+
+
+Changes between GMP version 4.1.4 and 4.2
+
+  Bugs:
+  * Minor bug fixes and code generalizations.
+  * Expanded and improved test suite.
+
+  Speedups:
+  * Many minor optimizations, too many to mention here.
+  * Division now always subquadratic.
+  * Computation of n-factorial much faster.
+  * Added basic x86-64 assembly code.
+  * Floating-point output is now subquadratic for all bases.
+  * FFT multiply code now about 25% faster.
+  * Toom3 multiply code faster.
+
+  Features:
+  * Much improved configure.
+  * Workarounds for many more compiler bugs.
+  * Temporary allocations are now made on the stack only if small.
+  * New systems supported: HPPA-2.0 gcc, IA-64 HP-UX, PowerPC-64 Darwin,
+    Sparc64 GNU/Linux.
+  * New i386 fat binaries, selecting optimised code at runtime (--enable-fat).
+  * New build option: --enable-profiling=instrument.
+  * New memory function: mp_get_memory_functions.
+  * New Mersenne Twister random numbers: gmp_randinit_mt, also now used for
+    gmp_randinit_default.
+  * New random functions: gmp_randinit_set, gmp_urandomb_ui, gmp_urandomm_ui.
+  * New integer functions: mpz_combit, mpz_rootrem.
+  * gmp_printf etc new type "M" for mp_limb_t.
+  * gmp_scanf and friends now accept C99 hex floats.
+  * Numeric input and output can now be in bases up to 62.
+  * Comparisons mpz_cmp_d, mpz_cmpabs_d, mpf_cmp_d recognise infinities.
+  * Conversions mpz_get_d, mpq_get_d, mpf_get_d truncate towards zero,
+    previously their behaviour was unspecified.
+  * Fixes for overflow issues with operands >= 2^31 bits.
+
+  Caveats:
+  * mpfr is gone, and will from now on be released only separately.  Please see
+    www.mpfr.org.
+
+
+Changes between GMP version 4.1.3 and 4.1.4
+
+* Bug fix to FFT multiplication code (crash for huge operands).
+* Bug fix to mpf_sub (miscomputation).
+* Support for powerpc64-gnu-linux.
+* Better support for AMD64 in 32-bit mode.
+* Upwardly binary compatible with 4.1.3, 4.1.2, 4.1.1, 4.1, 4.0.1, 4.0,
+  and 3.x versions.
+
+
+Changes between GMP version 4.1.2 and 4.1.3
+
+* Bug fix for FFT multiplication code (miscomputation).
+* Bug fix to K6 assembly code for gcd.
+* Bug fix to IA-64 assembly code for population count.
+* Portability improvements, most notably functional AMD64 support.
+* mpz_export allows NULL for countp parameter.
+* Many minor bug fixes.
+* mpz_export allows NULL for countp parameter.
+* Upwardly binary compatible with 4.1.2, 4.1.1, 4.1, 4.0.1, 4.0, and 3.x
+  versions.
+
+
+Changes between GMP version 4.1.1 and 4.1.2
+
+* Bug fixes.
+
+
+Changes between GMP version 4.1 and 4.1.1
+
+* Bug fixes.
+* New systems supported: NetBSD and OpenBSD sparc64.
+
+
+Changes between GMP version 4.0.1 and 4.1
+
+* Bug fixes.
+* Speed improvements.
+* Upwardly binary compatible with 4.0, 4.0.1, and 3.x versions.
+* Asymptotically fast conversion to/from strings (mpz, mpq, mpn levels), but
+  also major speed improvements for tiny operands.
+* mpn_get_str parameter restrictions relaxed.
+* Major speed improvements for HPPA 2.0 systems.
+* Major speed improvements for UltraSPARC systems.
+* Major speed improvements for IA-64 systems (but still sub-optimal code).
+* Extended test suite.
+* mpfr is back, with many bug fixes and portability improvements.
+* New function: mpz_ui_sub.
+* New functions: mpz_export, mpz_import.
+* Optimization for nth root functions (mpz_root, mpz_perfect_power_p).
+* Optimization for extended gcd (mpz_gcdext, mpz_invert, mpn_gcdext).
+* Generalized low-level number format, reserving a `nails' part of each
+  limb.  (Please note that this is really experimental; some functions
+  are likely to compute garbage when nails are enabled.)
+* Nails-enabled Alpha 21264 assembly code, allowing up to 75% better
+  performance.  (Use --enable-nails=4 to enable it.)
+
+
+Changes between GMP version 4.0 and 4.0.1
+
+* Bug fixes.
+
+
+Changes between GMP version 3.1.1 and 4.0
+
+* Bug fixes.
+* Speed improvements.
+* Upwardly binary compatible with 3.x versions.
+* New CPU support: IA-64, Pentium 4.
+* Improved CPU support: 21264, Cray vector systems.
+* Support for all MIPS ABIs: o32, n32, 64.
+* New systems supported: Darwin, SCO, Windows DLLs.
+* New divide-and-conquer square root algorithm.
+* New algorithms chapter in the manual.
+* New malloc reentrant temporary memory method.
+* New C++ class interface by Gerardo Ballabio (beta).
+* Revamped configure, featuring ABI selection.
+* Speed improvements for mpz_powm and mpz_powm_ui (mainly affecting small
+  operands).
+* mpz_perfect_power_p now properly recognizes 0, 1, and negative perfect
+  powers.
+* mpz_hamdist now supports negative operands.
+* mpz_jacobi now accepts non-positive denominators.
+* mpz_powm now supports negative exponents.
+* mpn_mul_1 operand overlap requirements relaxed.
+* Float input and output uses locale specific decimal point where available.
+* New gmp_printf, gmp_scanf and related functions.
+* New division functions: mpz_cdiv_q_2exp, mpz_cdiv_r_2exp, mpz_divexact_ui.
+* New divisibility tests: mpz_divisible_p, mpz_divisible_ui_p,
+  mpz_divisible_2exp_p, mpz_congruent_p, mpz_congruent_ui_p,
+  mpz_congruent_2exp_p.
+* New Fibonacci function: mpz_fib2_ui.
+* New Lucas number functions: mpz_lucnum_ui, mpz_lucnum2_ui.
+* Other new integer functions: mpz_cmp_d, mpz_cmpabs_d, mpz_get_d_2exp,
+  mpz_init2, mpz_kronecker, mpz_lcm_ui, mpz_realloc2.
+* New rational I/O: mpq_get_str, mpq_inp_str, mpq_out_str, mpq_set_str.
+* Other new rational functions: mpq_abs, mpq_cmp_si, mpq_div_2exp,
+  mpq_mul_2exp, mpq_set_f.
+* New float tests: mpf_integer_p, mpf_fits_sint_p, mpf_fits_slong_p,
+  mpf_fits_sshort_p, mpf_fits_uint_p, mpf_fits_ulong_p, mpf_fits_ushort_p.
+* Other new float functions: mpf_cmp_d, mpf_get_default_prec, mpf_get_si,
+  mpf_get_ui, mpf_get_d_2exp.
+* New random functions: gmp_randinit_default, gmp_randinit_lc_2exp_size.
+* New demo expression string parser (see demos/expr).
+* New preliminary perl interface (see demos/perl).
+* Tuned algorithm thresholds for many more CPUs.
+
+
+Changes between GMP version 3.1 and 3.1.1
+
+* Bug fixes for division (rare), mpf_get_str, FFT, and miscellaneous minor
+  things.
+
+
+Changes between GMP version 3.0 and 3.1
+
+* Bug fixes.
+* Improved `make check' running more tests.
+* Tuned algorithm cutoff points for many machines.  This will improve speed for
+  a lot of operations, in some cases by a large amount.
+* Major speed improvements: Alpha 21264.
+* Some speed improvements: Cray vector computers, AMD K6 and Athlon, Intel P5
+  and Pentium Pro/II/III.
+* The mpf_get_prec function now works as it did in GMP 2.
+* New utilities for auto-tuning and speed measuring.
+* Multiplication now optionally uses FFT for very large operands.  (To enable
+  it, pass --enable-fft to configure.)
+* Support for new systems: Solaris running on x86, FreeBSD 5, HP-UX 11, Cray
+  vector computers, Rhapsody, Nextstep/Openstep, MacOS.
+* Support for shared libraries on 32-bit HPPA.
+* New integer functions: mpz_mul_si, mpz_odd_p, mpz_even_p.
+* New Kronecker symbol functions: mpz_kronecker_si, mpz_kronecker_ui,
+  mpz_si_kronecker, mpz_ui_kronecker.
+* New rational functions: mpq_out_str, mpq_swap.
+* New float functions: mpf_swap.
+* New mpn functions: mpn_divexact_by3c, mpn_tdiv_qr.
+* New EXPERIMENTAL function layer for accurate floating-point arithmetic, mpfr.
+  To try it, pass --enable-mpfr to configure.  See the mpfr subdirectory for
+  more information; it is not documented in the main GMP manual.
+
+
+Changes between GMP version 3.0 and 3.0.1
+
+* Memory leaks in gmp_randinit and mpz_probab_prime_p fixed.
+* Documentation for gmp_randinit fixed.  Misc documentation errors fixed.
+
+
+Changes between GMP version 2.0 and 3.0
+
+* Source level compatibility with past releases (except mpn_gcd).
+* Bug fixes.
+* Much improved speed thanks to both host independent and host dependent
+  optimizations.
+* Switch to autoconf/automake/libtool.
+* Support for building libgmp as a shared library.
+* Multiplication and squaring using 3-way Toom-Cook.
+* Division using the Burnikel-Ziegler method.
+* New functions computing binomial coefficients: mpz_bin_ui, mpz_bin_uiui.
+* New function computing Fibonacci numbers: mpz_fib_ui.
+* New random number generators: mpf_urandomb, mpz_rrandomb, mpz_urandomb,
+  mpz_urandomm, gmp_randclear, gmp_randinit, gmp_randinit_lc_2exp,
+  gmp_randseed, gmp_randseed_ui.
+* New function for quickly extracting limbs: mpz_getlimbn.
+* New functions performing integer size tests: mpz_fits_sint_p,
+  mpz_fits_slong_p, mpz_fits_sshort_p, mpz_fits_uint_p, mpz_fits_ulong_p,
+  mpz_fits_ushort_p.
+* New mpf functions: mpf_ceil, mpf_floor, mpf_pow_ui, mpf_trunc.
+* New mpq function: mpq_set_d.
+* New mpz functions: mpz_addmul_ui, mpz_cmpabs, mpz_cmpabs_ui, mpz_lcm,
+  mpz_nextprime, mpz_perfect_power_p, mpz_remove, mpz_root, mpz_swap,
+  mpz_tdiv_ui, mpz_tstbit, mpz_xor.
+* New mpn function: mpn_divexact_by3.
+* New CPU support: DEC Alpha 21264, AMD K6 and Athlon, HPPA 2.0 and 64,
+  Intel Pentium Pro and Pentium-II/III, Sparc 64, PowerPC 64.
+* Almost 10 times faster mpz_invert and mpn_gcdext.
+* The interface of mpn_gcd has changed.
+* Better support for MIPS R4x000 and R5000 under Irix 6.
+* Improved support for SPARCv8 and SPARCv9 processors.
+
+
+Changes between GMP version 2.0 and 2.0.2
+
+* Many bug fixes.
+
+
+Changes between GMP version 1.3.2 and 2.0
+
+* Division routines in the mpz class have changed.  There are three classes of
+  functions, that rounds the quotient to -infinity, 0, and +infinity,
+  respectively.  The first class of functions have names that begin with
+  mpz_fdiv (f is short for floor), the second class' names begin with mpz_tdiv
+  (t is short for trunc), and the third class' names begin with mpz_cdiv (c is
+  short for ceil).
+
+  The old division routines beginning with mpz_m are similar to the new
+  mpz_fdiv, with the exception that some of the new functions return useful
+  values.
+
+  The old function names can still be used.  All the old functions names will
+  now do floor division, not trunc division as some of them used to.  This was
+  changed to make the functions more compatible with common mathematical
+  practice.
+
+  The mpz_mod and mpz_mod_ui functions now compute the mathematical mod
+  function.  I.e., the sign of the 2nd argument is ignored.
+
+* The mpq assignment functions do not canonicalize their results.  A new
+  function, mpq_canonicalize must be called by the user if the result is not
+  known to be canonical.
+* The mpn functions are now documented.  These functions are intended for
+  very time critical applications, or applications that need full control over
+  memory allocation.  Note that the mpn interface is irregular and hard to
+  use.
+* New functions for arbitrary precision floating point arithmetic.  Names
+  begin with `mpf_'.  Associated type mpf_t.
+* New and improved mpz functions, including much faster GCD, fast exact
+  division (mpz_divexact), bit scan (mpz_scan0 and mpz_scan1), and number
+  theoretical functions like Jacobi (mpz_jacobi) and multiplicative inverse
+  (mpz_invert).
+* New variable types (mpz_t and mpq_t) are available that makes syntax of
+  mpz and mpq calls nicer (no need for & before variables).  The MP_INT and
+  MP_RAT types are still available for compatibility.
+* Uses GNU configure.  This makes it possible to choose target architecture
+  and CPU variant, and to compile into a separate object directory.
+* Carefully optimized assembly for important inner loops.  Support for DEC
+  Alpha, Amd 29000, HPPA 1.0 and 1.1, Intel Pentium and generic x86, Intel
+  i960, Motorola MC68000, MC68020, MC88100, and MC88110, Motorola/IBM
+  PowerPC, National NS32000, IBM POWER, MIPS R3000, R4000, SPARCv7,
+  SuperSPARC, generic SPARCv8, and DEC VAX.  Some support also for ARM,
+  Clipper, IBM ROMP (RT), and Pyramid AP/XP.
+* Faster.  Thanks to the assembler code, new algorithms, and general tuning.
+  In particular, the speed on machines without GCC is improved.
+* Support for machines without alloca.
+* Now under the LGPL.
+
+INCOMPATIBILITIES BETWEEN GMP 1 AND GMP 2
+
+* mpq assignment functions do not canonicalize their results.
+* mpz division functions round differently.
+* mpz mod functions now really compute mod.
+* mpz_powm and mpz_powm_ui now really use mod for reduction.
diff --git a/third_party/gmp/README b/third_party/gmp/README
new file mode 100644
index 0000000..73ce364
--- /dev/null
+++ b/third_party/gmp/README
@@ -0,0 +1,111 @@
+Copyright 1991, 1996, 1999, 2000, 2007 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.
+
+
+
+
+
+
+			THE GNU MP LIBRARY
+
+
+GNU MP is a library for arbitrary precision arithmetic, operating on signed
+integers, rational numbers, and floating point numbers.  It has a rich set of
+functions, and the functions have a regular interface.
+
+GNU MP is designed to be as fast as possible, both for small operands and huge
+operands.  The speed is achieved by using fullwords as the basic arithmetic
+type, by using fast algorithms, with carefully optimized assembly code for the
+most common inner loops for lots of CPUs, and by a general emphasis on speed
+(instead of simplicity or elegance).
+
+GNU MP is believed to be faster than any other similar library.  Its advantage
+increases with operand sizes for certain operations, since GNU MP in many
+cases has asymptotically faster algorithms.
+
+GNU MP is free software and may be freely copied on the terms contained in the
+files COPYING* (see the manual for information on which license(s) applies to
+which components of GNU MP).
+
+
+
+			OVERVIEW OF GNU MP
+
+There are four classes of functions in GNU MP.
+
+ 1. Signed integer arithmetic functions (mpz).  These functions are intended
+    to be easy to use, with their regular interface.  The associated type is
+    `mpz_t'.
+
+ 2. Rational arithmetic functions (mpq).  For now, just a small set of
+    functions necessary for basic rational arithmetics.  The associated type
+    is `mpq_t'.
+
+ 3. Floating-point arithmetic functions (mpf).  If the C type `double'
+    doesn't give enough precision for your application, declare your
+    variables as `mpf_t' instead, set the precision to any number desired,
+    and call the functions in the mpf class for the arithmetic operations.
+
+ 4. Positive-integer, hard-to-use, very low overhead functions are in the
+    mpn class.  No memory management is performed.  The caller must ensure
+    enough space is available for the results.  The set of functions is not
+    regular, nor is the calling interface.  These functions accept input
+    arguments in the form of pairs consisting of a pointer to the least
+    significant word, and an integral size telling how many limbs (= words)
+    the pointer points to.
+
+    Almost all calculations, in the entire package, are made by calling these
+    low-level functions.
+
+For more information on how to use GNU MP, please refer to the documentation.
+It is composed from the file doc/gmp.texi, and can be displayed on the screen
+or printed.  How to do that, as well how to build the library, is described in
+the INSTALL file in this directory.
+
+
+
+			REPORTING BUGS
+
+If you find a bug in the library, please make sure to tell us about it!
+
+You should first check the GNU MP web pages at https://gmplib.org/, under
+"Status of the current release".  There will be patches for all known serious
+bugs there.
+
+Report bugs to gmp-bugs@gmplib.org.  What information is needed in a useful bug
+report is described in the manual.  The same address can be used for suggesting
+modifications and enhancements.
+
+
+
+
+----------------
+Local variables:
+mode: text
+fill-column: 78
+End:
diff --git a/third_party/gmp/acinclude.m4 b/third_party/gmp/acinclude.m4
new file mode 100644
index 0000000..86175ce
--- /dev/null
+++ b/third_party/gmp/acinclude.m4
@@ -0,0 +1,3994 @@
+dnl  GMP specific autoconf macros
+
+
+dnl  Copyright 2000-2006, 2009, 2011, 2013-2018 Free Software Foundation, Inc.
+dnl
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+dnl  Some tests use, or must delete, the default compiler output.  The
+dnl  possible filenames are based on what autoconf looks for, namely
+dnl
+dnl    a.out - normal unix style
+dnl    b.out - i960 systems, including gcc there
+dnl    a.exe - djgpp
+dnl    a_out.exe - OpenVMS DEC C called via GNV wrapper (gnv.sourceforge.net)
+dnl    conftest.exe - various DOS compilers
+
+
+define(IA64_PATTERN,
+[[ia64*-*-* | itanium-*-* | itanium2-*-*]])
+
+dnl  Need to be careful not to match m6811, m6812, m68hc11 and m68hc12, all
+dnl  of which config.sub accepts.  (Though none of which are likely to work
+dnl  with GMP.)
+dnl
+define(M68K_PATTERN,
+[[m68k-*-* | m68[0-9][0-9][0-9]-*-*]])
+
+define(POWERPC64_PATTERN,
+[[powerpc64-*-* | powerpc64le-*-* | powerpc620-*-* | powerpc630-*-* | powerpc970-*-* | power[3-9]-*-*]])
+
+define(S390_PATTERN,
+[[s390-*-* | z900esa-*-* | z990esa-*-* | z9esa-*-* | z10esa-*-* | z196esa-*-*]])
+
+define(S390X_PATTERN,
+[[s390x-*-* | z900-*-* | z990-*-* | z9-*-* | z10-*-* | z196-*-*]])
+
+define(X86_PATTERN,
+[[i?86*-*-* | k[5-8]*-*-* | pentium*-*-* | athlon-*-* | viac3*-*-* | geode*-*-* | atom-*-*]])
+
+define(X86_64_PATTERN,
+[[athlon64-*-* | k8-*-* | k10-*-* | bobcat-*-* | jaguar*-*-* | bulldozer*-*-* | piledriver*-*-* | steamroller*-*-* | excavator*-*-* | zen*-*-* | pentium4-*-* | atom-*-* | silvermont-*-* | goldmont-*-* | core2-*-* | corei*-*-* | x86_64-*-* | nano-*-* | nehalem*-*-* | westmere*-*-* | sandybridge*-*-* | ivybridge*-*-* | haswell*-*-* | broadwell*-*-* | skylake*-*-* | kabylake*-*-*]])
+
+dnl  GMP_FAT_SUFFIX(DSTVAR, DIRECTORY)
+dnl  ---------------------------------
+dnl  Emit code to set shell variable DSTVAR to the suffix for a fat binary
+dnl  routine from DIRECTORY.  DIRECTORY can be a shell expression like $foo
+dnl  etc.
+dnl
+dnl  The suffix is directory separators / or \ changed to underscores, and
+dnl  if there's more than one directory part, then the first is dropped.
+dnl
+dnl  For instance,
+dnl
+dnl      x86         ->  x86
+dnl      x86/k6      ->  k6
+dnl      x86/k6/mmx  ->  k6_mmx
+
+define(GMP_FAT_SUFFIX,
+[[$1=`echo $2 | sed -e '/\//s:^[^/]*/::' -e 's:[\\/]:_:g'`]])
+
+
+dnl  GMP_REMOVE_FROM_LIST(listvar,item)
+dnl  ----------------------------------
+dnl  Emit code to remove any occurrence of ITEM from $LISTVAR.  ITEM can be a
+dnl  shell expression like $foo if desired.
+
+define(GMP_REMOVE_FROM_LIST,
+[remove_from_list_tmp=
+for remove_from_list_i in $[][$1]; do
+  if test $remove_from_list_i = [$2]; then :;
+  else
+     remove_from_list_tmp="$remove_from_list_tmp $remove_from_list_i"
+  fi
+done
+[$1]=$remove_from_list_tmp
+])
+
+
+dnl  GMP_STRIP_PATH(subdir)
+dnl  ----------------------
+dnl  Strip entries */subdir from $path and $fat_path.
+
+define(GMP_STRIP_PATH,
+[GMP_STRIP_PATH_VAR(path, [$1])
+GMP_STRIP_PATH_VAR(fat_path, [$1])
+])
+
+define(GMP_STRIP_PATH_VAR,
+[tmp_path=
+for i in $[][$1]; do
+  case $i in
+    */[$2]) ;;
+    *) tmp_path="$tmp_path $i" ;;
+  esac
+done
+[$1]="$tmp_path"
+])
+
+
+dnl  GMP_INCLUDE_GMP_H
+dnl  -----------------
+dnl  Expand to the right way to #include gmp-h.in.  This must be used
+dnl  instead of gmp.h, since that file isn't generated until the end of the
+dnl  configure.
+dnl
+dnl  Dummy value for GMP_LIMB_BITS is enough
+dnl  for all current configure-time uses of gmp.h.
+
+define(GMP_INCLUDE_GMP_H,
+[[#define __GMP_WITHIN_CONFIGURE 1   /* ignore template stuff */
+#define GMP_NAIL_BITS $GMP_NAIL_BITS
+#define GMP_LIMB_BITS 123
+$DEFN_LONG_LONG_LIMB
+#include "$srcdir/gmp-h.in"]
+])
+
+
+dnl  GMP_HEADER_GETVAL(NAME,FILE)
+dnl  ----------------------------
+dnl  Expand at autoconf time to the value of a "#define NAME" from the given
+dnl  FILE.  The regexps here aren't very rugged, but are enough for gmp.
+dnl  /dev/null as a parameter prevents a hang if $2 is accidentally omitted.
+
+define(GMP_HEADER_GETVAL,
+[patsubst(patsubst(
+esyscmd([grep "^#define $1 " $2 /dev/null 2>/dev/null]),
+[^.*$1[ 	]+],[]),
+[[
+ 	]*$],[])])
+
+
+dnl  GMP_VERSION
+dnl  -----------
+dnl  The gmp version number, extracted from the #defines in gmp-h.in at
+dnl  autoconf time.  Two digits like 3.0 if patchlevel <= 0, or three digits
+dnl  like 3.0.1 if patchlevel > 0.
+
+define(GMP_VERSION,
+[GMP_HEADER_GETVAL(__GNU_MP_VERSION,gmp-h.in)[]dnl
+.GMP_HEADER_GETVAL(__GNU_MP_VERSION_MINOR,gmp-h.in)[]dnl
+.GMP_HEADER_GETVAL(__GNU_MP_VERSION_PATCHLEVEL,gmp-h.in)])
+
+
+dnl  GMP_SUBST_CHECK_FUNCS(func,...)
+dnl  ------------------------------
+dnl  Setup an AC_SUBST of HAVE_FUNC_01 for each argument.
+
+AC_DEFUN([GMP_SUBST_CHECK_FUNCS],
+[m4_if([$1],,,
+[_GMP_SUBST_CHECK_FUNCS(ac_cv_func_[$1],HAVE_[]m4_translit([$1],[a-z],[A-Z])_01)
+GMP_SUBST_CHECK_FUNCS(m4_shift($@))])])
+
+dnl  Called: _GMP_SUBST_CHECK_FUNCS(cachevar,substvar)
+AC_DEFUN([_GMP_SUBST_CHECK_FUNCS],
+[case $[$1] in
+yes) AC_SUBST([$2],1) ;;
+no)  [$2]=0 ;;
+esac
+])
+
+
+dnl  GMP_SUBST_CHECK_HEADERS(foo.h,...)
+dnl  ----------------------------------
+dnl  Setup an AC_SUBST of HAVE_FOO_H_01 for each argument.
+
+AC_DEFUN([GMP_SUBST_CHECK_HEADERS],
+[m4_if([$1],,,
+[_GMP_SUBST_CHECK_HEADERS(ac_cv_header_[]m4_translit([$1],[./],[__]),
+HAVE_[]m4_translit([$1],[a-z./],[A-Z__])_01)
+GMP_SUBST_CHECK_HEADERS(m4_shift($@))])])
+
+dnl  Called: _GMP_SUBST_CHECK_HEADERS(cachevar,substvar)
+AC_DEFUN([_GMP_SUBST_CHECK_HEADERS],
+[case $[$1] in
+yes) AC_SUBST([$2],1) ;;
+no)  [$2]=0 ;;
+esac
+])
+
+
+dnl  GMP_COMPARE_GE(A1,B1, A2,B2, ...)
+dnl  ---------------------------------
+dnl  Compare two version numbers A1.A2.etc and B1.B2.etc.  Set
+dnl  $gmp_compare_ge to yes or no according to the result.  The A parts
+dnl  should be variables, the B parts fixed numbers.  As many parts as
+dnl  desired can be included.  An empty string in an A part is taken to be
+dnl  zero, the B parts should be non-empty and non-zero.
+dnl
+dnl  For example,
+dnl
+dnl      GMP_COMPARE($major,10, $minor,3, $subminor,1)
+dnl
+dnl  would test whether $major.$minor.$subminor is greater than or equal to
+dnl  10.3.1.
+
+AC_DEFUN([GMP_COMPARE_GE],
+[gmp_compare_ge=no
+GMP_COMPARE_GE_INTERNAL($@)
+])
+
+AC_DEFUN([GMP_COMPARE_GE_INTERNAL],
+[ifelse(len([$3]),0,
+[if test -n "$1" && test "$1" -ge $2; then
+  gmp_compare_ge=yes
+fi],
+[if test -n "$1"; then
+  if test "$1" -gt $2; then
+    gmp_compare_ge=yes
+  else
+    if test "$1" -eq $2; then
+      GMP_COMPARE_GE_INTERNAL(m4_shift(m4_shift($@)))
+    fi
+  fi
+fi])
+])
+
+
+dnl  GMP_PROG_AR
+dnl  -----------
+dnl  GMP additions to $AR.
+dnl
+dnl  A cross-"ar" may be necessary when cross-compiling since the build
+dnl  system "ar" might try to interpret the object files to build a symbol
+dnl  table index, hence the use of AC_CHECK_TOOL.
+dnl
+dnl  A user-selected $AR is always left unchanged.  AC_CHECK_TOOL is still
+dnl  run to get the "checking" message printed though.
+dnl
+dnl  If extra flags are added to AR, then ac_cv_prog_AR and
+dnl  ac_cv_prog_ac_ct_AR are set too, since libtool (cvs 2003-03-31 at
+dnl  least) will do an AC_CHECK_TOOL and that will AR from one of those two
+dnl  cached variables.  (ac_cv_prog_AR is used if there's an ac_tool_prefix,
+dnl  or ac_cv_prog_ac_ct_AR is used otherwise.)  FIXME: This is highly
+dnl  dependent on autoconf internals, perhaps it'd work to put our extra
+dnl  flags into AR_FLAGS instead.
+dnl
+dnl  $AR_FLAGS is set to "cq" rather than leaving it to libtool "cru".  The
+dnl  latter fails when libtool goes into piecewise mode and is unlucky
+dnl  enough to have two same-named objects in separate pieces, as happens
+dnl  for instance to random.o (and others) on vax-dec-ultrix4.5.  Naturally
+dnl  a user-selected $AR_FLAGS is left unchanged.
+dnl
+dnl  For reference, $ARFLAGS is used by automake (1.8) for its ".a" archive
+dnl  file rules.  This doesn't get used by the piecewise linking, so we
+dnl  leave it at the default "cru".
+dnl
+dnl  FIXME: Libtool 1.5.2 has its own arrangements for "cq", but that version
+dnl  is broken in other ways.  When we can upgrade, remove the forcible
+dnl  AR_FLAGS=cq.
+
+AC_DEFUN([GMP_PROG_AR],
+[dnl  Want to establish $AR before libtool initialization.
+AC_BEFORE([$0],[AC_PROG_LIBTOOL])
+gmp_user_AR=$AR
+AC_CHECK_TOOL(AR, ar, ar)
+if test -z "$gmp_user_AR"; then
+                        eval arflags=\"\$ar${abi1}_flags\"
+  test -n "$arflags" || eval arflags=\"\$ar${abi2}_flags\"
+  if test -n "$arflags"; then
+    AC_MSG_CHECKING([for extra ar flags])
+    AR="$AR $arflags"
+    ac_cv_prog_AR="$AR $arflags"
+    ac_cv_prog_ac_ct_AR="$AR $arflags"
+    AC_MSG_RESULT([$arflags])
+  fi
+fi
+if test -z "$AR_FLAGS"; then
+  AR_FLAGS=cq
+fi
+])
+
+
+dnl  GMP_PROG_M4
+dnl  -----------
+dnl  Find a working m4, either in $PATH or likely locations, and setup $M4
+dnl  and an AC_SUBST accordingly.  If $M4 is already set then it's a user
+dnl  choice and is accepted with no checks.  GMP_PROG_M4 is like
+dnl  AC_PATH_PROG or AC_CHECK_PROG, but tests each m4 found to see if it's
+dnl  good enough.
+dnl
+dnl  See mpn/asm-defs.m4 for details on the known bad m4s.
+
+AC_DEFUN([GMP_PROG_M4],
+[AC_ARG_VAR(M4,[m4 macro processor])
+AC_CACHE_CHECK([for suitable m4],
+                gmp_cv_prog_m4,
+[if test -n "$M4"; then
+  gmp_cv_prog_m4="$M4"
+else
+  cat >conftest.m4 <<\EOF
+dnl  Must protect this against being expanded during autoconf m4!
+dnl  Dont put "dnl"s in this as autoconf will flag an error for unexpanded
+dnl  macros.
+[define(dollarhash,``$][#'')ifelse(dollarhash(x),1,`define(t1,Y)',
+``bad: $][# not supported (SunOS /usr/bin/m4)
+'')ifelse(eval(89),89,`define(t2,Y)',
+`bad: eval() doesnt support 8 or 9 in a constant (OpenBSD 2.6 m4)
+')ifelse(eval(9,9),10,`define(t3,Y)',
+`bad: eval() doesnt support radix in eval (FreeBSD 8.x,9.0,9.1,9.2 m4)
+')ifelse(t1`'t2`'t3,YYY,`good
+')]
+EOF
+dnl ' <- balance the quotes for emacs sh-mode
+  echo "trying m4" >&AC_FD_CC
+  gmp_tmp_val=`(m4 conftest.m4) 2>&AC_FD_CC`
+  echo "$gmp_tmp_val" >&AC_FD_CC
+  if test "$gmp_tmp_val" = good; then
+    gmp_cv_prog_m4="m4"
+  else
+    IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+dnl $ac_dummy forces splitting on constant user-supplied paths.
+dnl POSIX.2 word splitting is done only on the output of word expansions,
+dnl not every word.  This closes a longstanding sh security hole.
+    ac_dummy="$PATH:/usr/5bin"
+    for ac_dir in $ac_dummy; do
+      test -z "$ac_dir" && ac_dir=.
+      echo "trying $ac_dir/m4" >&AC_FD_CC
+      gmp_tmp_val=`($ac_dir/m4 conftest.m4) 2>&AC_FD_CC`
+      echo "$gmp_tmp_val" >&AC_FD_CC
+      if test "$gmp_tmp_val" = good; then
+        gmp_cv_prog_m4="$ac_dir/m4"
+        break
+      fi
+    done
+    IFS="$ac_save_ifs"
+    if test -z "$gmp_cv_prog_m4"; then
+      AC_MSG_ERROR([No usable m4 in \$PATH or /usr/5bin (see config.log for reasons).])
+    fi
+  fi
+  rm -f conftest.m4
+fi])
+M4="$gmp_cv_prog_m4"
+AC_SUBST(M4)
+])
+
+
+dnl  GMP_M4_M4WRAP_SPURIOUS
+dnl  ----------------------
+dnl  Check for spurious output from m4wrap(), as described in mpn/asm-defs.m4.
+dnl
+dnl  The following systems have been seen with the problem.
+dnl
+dnl  - Unicos alpha, but its assembler doesn't seem to mind.
+dnl  - MacOS X Darwin, its assembler fails.
+dnl  - NetBSD 1.4.1 m68k, and gas 1.92.3 there gives a warning and ignores
+dnl    the bad last line since it doesn't have a newline.
+dnl  - NetBSD 1.4.2 alpha, but its assembler doesn't seem to mind.
+dnl  - HP-UX ia64.
+dnl
+dnl  Enhancement: Maybe this could be in GMP_PROG_M4, and attempt to prefer
+dnl  an m4 with a working m4wrap, if it can be found.
+
+AC_DEFUN([GMP_M4_M4WRAP_SPURIOUS],
+[AC_REQUIRE([GMP_PROG_M4])
+AC_CACHE_CHECK([if m4wrap produces spurious output],
+               gmp_cv_m4_m4wrap_spurious,
+[# hide the d-n-l from autoconf's error checking
+tmp_d_n_l=d""nl
+cat >conftest.m4 <<EOF
+[changequote({,})define(x,)m4wrap({x})$tmp_d_n_l]
+EOF
+echo test input is >&AC_FD_CC
+cat conftest.m4 >&AC_FD_CC
+tmp_chars=`$M4 conftest.m4 | wc -c`
+echo produces $tmp_chars chars output >&AC_FD_CC
+rm -f conftest.m4
+if test $tmp_chars = 0; then
+  gmp_cv_m4_m4wrap_spurious=no
+else
+  gmp_cv_m4_m4wrap_spurious=yes
+fi
+])
+GMP_DEFINE_RAW(["define(<M4WRAP_SPURIOUS>,<$gmp_cv_m4_m4wrap_spurious>)"])
+])
+
+
+dnl  GMP_PROG_NM
+dnl  -----------
+dnl  GMP additions to libtool AC_PROG_NM.
+dnl
+dnl  Note that if AC_PROG_NM can't find a working nm it still leaves
+dnl  $NM set to "nm", so $NM can't be assumed to actually work.
+dnl
+dnl  A user-selected $NM is always left unchanged.  AC_PROG_NM is still run
+dnl  to get the "checking" message printed though.
+dnl
+dnl  Perhaps it'd be worthwhile checking that nm works, by running it on an
+dnl  actual object file.  For instance on sparcv9 solaris old versions of
+dnl  GNU nm don't recognise 64-bit objects.  Checking would give a better
+dnl  error message than just a failure in later tests like GMP_ASM_W32 etc.
+dnl
+dnl  On the other hand it's not really normal autoconf practice to take too
+dnl  much trouble over detecting a broken set of tools.  And libtool doesn't
+dnl  do anything at all for say ranlib or strip.  So for now we're inclined
+dnl  to just demand that the user provides a coherent environment.
+
+AC_DEFUN([GMP_PROG_NM],
+[dnl  Make sure we're the first to call AC_PROG_NM, so our extra flags are
+dnl   used by everyone.
+AC_BEFORE([$0],[AC_PROG_NM])
+gmp_user_NM=$NM
+AC_PROG_NM
+
+# FIXME: When cross compiling (ie. $ac_tool_prefix not empty), libtool
+# defaults to plain "nm" if a "${ac_tool_prefix}nm" is not found.  In this
+# case run it again to try the native "nm", firstly so that likely locations
+# are searched, secondly so that -B or -p are added if necessary for BSD
+# format.  This is necessary for instance on OSF with "./configure
+# --build=alphaev5-dec-osf --host=alphaev6-dec-osf".
+#
+if test -z "$gmp_user_NM" && test -n "$ac_tool_prefix" && test "$NM" = nm; then
+  $as_unset lt_cv_path_NM
+  gmp_save_ac_tool_prefix=$ac_tool_prefix
+  ac_tool_prefix=
+  NM=
+  AC_PROG_NM
+  ac_tool_prefix=$gmp_save_ac_tool_prefix
+fi
+
+if test -z "$gmp_user_NM"; then
+                        eval nmflags=\"\$nm${abi1}_flags\"
+  test -n "$nmflags" || eval nmflags=\"\$nm${abi2}_flags\"
+  if test -n "$nmflags"; then
+    AC_MSG_CHECKING([for extra nm flags])
+    NM="$NM $nmflags"
+    AC_MSG_RESULT([$nmflags])
+  fi
+fi
+])
+
+
+dnl  GMP_PROG_CC_WORKS(cc+cflags,[ACTION-IF-WORKS][,ACTION-IF-NOT-WORKS])
+dnl  --------------------------------------------------------------------
+dnl  Check if cc+cflags can compile and link.
+dnl
+dnl  This test is designed to be run repeatedly with different cc+cflags
+dnl  selections, so the result is not cached.
+dnl
+dnl  For a native build, meaning $cross_compiling == no, we require that the
+dnl  generated program will run.  This is the same as AC_PROG_CC does in
+dnl  _AC_COMPILER_EXEEXT_WORKS, and checking here will ensure we don't pass
+dnl  a CC/CFLAGS combination that it rejects.
+dnl
+dnl  sparc-*-solaris2.7 can compile ABI=64 but won't run it if the kernel
+dnl  was booted in 32-bit mode.  The effect of requiring the compiler output
+dnl  will run is that a plain native "./configure" falls back on ABI=32, but
+dnl  ABI=64 is still available as a cross-compile.
+dnl
+dnl  The various specific problems we try to detect are done in separate
+dnl  compiles.  Although this is probably a bit slower than one test
+dnl  program, it makes it easy to indicate the problem in AC_MSG_RESULT,
+dnl  hence giving the user a clue about why we rejected the compiler.
+
+AC_DEFUN([GMP_PROG_CC_WORKS],
+[AC_MSG_CHECKING([compiler $1])
+gmp_prog_cc_works=yes
+
+# first see a simple "main()" works, then go on to other checks
+GMP_PROG_CC_WORKS_PART([$1], [])
+
+GMP_PROG_CC_WORKS_PART([$1], [function pointer return],
+[/* The following provokes an internal error from gcc 2.95.2 -mpowerpc64
+   (without -maix64), hence detecting an unusable compiler */
+void *g() { return (void *) 0; }
+void *f() { return g(); }
+])
+
+GMP_PROG_CC_WORKS_PART([$1], [cmov instruction],
+[/* The following provokes an invalid instruction syntax from i386 gcc
+   -march=pentiumpro on Solaris 2.8.  The native sun assembler
+   requires a non-standard syntax for cmov which gcc (as of 2.95.2 at
+   least) doesn't know.  */
+int n;
+int cmov () { return (n >= 0 ? n : 0); }
+])
+
+GMP_PROG_CC_WORKS_PART([$1], [double -> ulong conversion],
+[/* The following provokes a linker invocation problem with gcc 3.0.3
+   on AIX 4.3 under "-maix64 -mpowerpc64 -mcpu=630".  The -mcpu=630
+   option causes gcc to incorrectly select the 32-bit libgcc.a, not
+   the 64-bit one, and consequently it misses out on the __fixunsdfdi
+   helper (double -> uint64 conversion).  */
+double d;
+unsigned long gcc303 () { return (unsigned long) d; }
+])
+
+GMP_PROG_CC_WORKS_PART([$1], [double negation],
+[/* The following provokes an error from hppa gcc 2.95 under -mpa-risc-2-0 if
+   the assembler doesn't know hppa 2.0 instructions.  fneg is a 2.0
+   instruction, and a negation like this comes out using it.  */
+double fneg_data;
+unsigned long fneg () { return -fneg_data; }
+])
+
+GMP_PROG_CC_WORKS_PART([$1], [double -> float conversion],
+[/* The following makes gcc 3.3 -march=pentium4 generate an SSE2 xmm insn
+   (cvtsd2ss) which will provoke an error if the assembler doesn't recognise
+   those instructions.  Not sure how much of the gmp code will come out
+   wanting sse2, but it's easiest to reject an option we know is bad.  */
+double ftod_data;
+float ftod () { return (float) ftod_data; }
+])
+
+GMP_PROG_CC_WORKS_PART([$1], [gnupro alpha ev6 char spilling],
+[/* The following provokes an internal compiler error from gcc version
+   "2.9-gnupro-99r1" under "-O2 -mcpu=ev6", apparently relating to char
+   values being spilled into floating point registers.  The problem doesn't
+   show up all the time, but has occurred enough in GMP for us to reject
+   this compiler+flags.  */
+#include <string.h>  /* for memcpy */
+struct try_t
+{
+ char dst[2];
+ char size;
+ long d0, d1, d2, d3, d4, d5, d6;
+ char overlap;
+};
+struct try_t param[6];
+int
+param_init ()
+{
+ struct try_t *p;
+ memcpy (p, &param[ 2 ], sizeof (*p));
+ memcpy (p, &param[ 2 ], sizeof (*p));
+ p->size = 2;
+ memcpy (p, &param[ 1 ], sizeof (*p));
+ p->dst[0] = 1;
+ p->overlap = 2;
+ memcpy (p, &param[ 3 ], sizeof (*p));
+ p->dst[0] = 1;
+ p->overlap = 8;
+ memcpy (p, &param[ 4 ], sizeof (*p));
+ memcpy (p, &param[ 4 ], sizeof (*p));
+ p->overlap = 8;
+ memcpy (p, &param[ 5 ], sizeof (*p));
+ memcpy (p, &param[ 5 ], sizeof (*p));
+ memcpy (p, &param[ 5 ], sizeof (*p));
+ return 0;
+}
+])
+
+# __builtin_alloca is not available everywhere, check it exists before
+# seeing that it works
+GMP_PROG_CC_WORKS_PART_TEST([$1],[__builtin_alloca availability],
+[int k; int foo () { __builtin_alloca (k); }],
+  [GMP_PROG_CC_WORKS_PART([$1], [alloca array],
+[/* The following provokes an internal compiler error from Itanium HP-UX cc
+    under +O2 or higher.  We use this sort of code in mpn/generic/mul_fft.c. */
+int k;
+int foo ()
+{
+  int i, **a;
+  a = __builtin_alloca (k);
+  for (i = 0; i <= k; i++)
+    a[i] = __builtin_alloca (1 << i);
+}
+])])
+
+GMP_PROG_CC_WORKS_PART([$1], [abs int -> double conversion],
+[/* The following provokes an internal error from the assembler on
+   power2-ibm-aix4.3.1.0.  gcc -mrios2 compiles to nabs+fcirz, and this
+   results in "Internal error related to the source program domain".
+
+   For reference it seems to be the combination of nabs+fcirz which is bad,
+   not either alone.  This sort of thing occurs in mpz/get_str.c with the
+   way double chars_per_bit_exactly is applied in MPN_SIZEINBASE.  Perhaps
+   if that code changes to a scaled-integer style then we won't need this
+   test.  */
+
+double fp[1];
+int x;
+int f ()
+{
+  int a;
+  a = (x >= 0 ? x : -x);
+  return a * fp[0];
+}
+])
+
+GMP_PROG_CC_WORKS_PART([$1], [long long reliability test 1],
+[/* The following provokes a segfault in the compiler on powerpc-apple-darwin.
+   Extracted from tests/mpn/t-iord_u.c.  Causes Apple's gcc 3.3 build 1640 and
+   1666 to segfault with e.g., -O2 -mpowerpc64.  */
+
+#if defined (__GNUC__) && ! defined (__cplusplus)
+typedef unsigned long long t1;typedef t1*t2;
+void g(){}
+void h(){}
+static __inline__ t1 e(t2 rp,t2 up,int n,t1 v0)
+{t1 c,x,r;int i;if(v0){c=1;for(i=1;i<n;i++){x=up[i];r=x+1;rp[i]=r;}}return c;}
+void f(){static const struct{t1 n;t1 src[9];t1 want[9];}d[]={{1,{0},{1}},};t1 got[9];int i;
+for(i=0;i<1;i++){if(e(got,got,9,d[i].n)==0)h();g(i,d[i].src,d[i].n,got,d[i].want,9);if(d[i].n)h();}}
+#else
+int dummy;
+#endif
+])
+
+GMP_PROG_CC_WORKS_PART([$1], [long long reliability test 2],
+[/* The following provokes an internal compiler error on powerpc-apple-darwin.
+   Extracted from mpz/cfdiv_q_2exp.c.  Causes Apple's gcc 3.3 build 1640 and
+   1666 to get an ICE with -O1 -mpowerpc64.  */
+
+#if defined (__GNUC__) && ! defined (__cplusplus)
+int g();
+void f(int u){int i;long long x;x=u?~0:0;if(x)for(i=0;i<9;i++);x&=g();if(x)g();}
+int g(){return 0;}
+#else
+int dummy;
+#endif
+])
+
+GMP_PROG_CC_WORKS_PART([$1], [freebsd hacked gcc],
+[/* Provokes an ICE on i386-freebsd with the FreeBSD-hacked gcc, under
+   -O2 -march=amdfam10.  We call helper functions here "open" and "close" in
+   order for linking to succeed.  */
+
+#if defined (__GNUC__) && ! defined (__cplusplus)
+int open(int*,int*,int);void*close(int);void g(int*rp,int*up,int un){
+__builtin_expect(un<=0x7f00,1)?__builtin_alloca(un):close(un);if(__builtin_clzl
+(up[un])){open(rp,up,un);while(1){if(rp[un-1]!=0)break;un--;}}}
+#else
+int dummy;
+#endif
+])
+
+GMP_PROG_CC_WORKS_PART_MAIN([$1], [mpn_lshift_com optimization],
+[/* The following is mis-compiled by HP ia-64 cc version
+        cc: HP aC++/ANSI C B3910B A.05.55 [Dec 04 2003]
+   under "cc +O3", both in +DD32 and +DD64 modes.  The mpn_lshift_com gets
+   inlined and its return value somehow botched to be 0 instead of 1.  This
+   arises in the real mpn_lshift_com in mul_fft.c.  A lower optimization
+   level, like +O2 seems ok.  This code needs to be run to show the problem,
+   but that's fine, the offending cc is a native-only compiler so we don't
+   have to worry about cross compiling.  */
+
+#if ! defined (__cplusplus)
+unsigned long
+lshift_com (rp, up, n, cnt)
+  unsigned long *rp;
+  unsigned long *up;
+  long n;
+  unsigned cnt;
+{
+  unsigned long retval, high_limb, low_limb;
+  unsigned tnc;
+  long i;
+  tnc = 8 * sizeof (unsigned long) - cnt;
+  low_limb = *up++;
+  retval = low_limb >> tnc;
+  high_limb = low_limb << cnt;
+  for (i = n - 1; i != 0; i--)
+    {
+      low_limb = *up++;
+      *rp++ = ~(high_limb | (low_limb >> tnc));
+      high_limb = low_limb << cnt;
+    }
+  return retval;
+}
+int
+main ()
+{
+  unsigned long cy, rp[2], up[2];
+  up[0] = ~ 0L;
+  up[1] = 0;
+  cy = lshift_com (rp, up, 2L, 1);
+  if (cy != 1L)
+    return 1;
+  return 0;
+}
+#else
+int
+main ()
+{
+  return 0;
+}
+#endif
+])
+
+GMP_PROG_CC_WORKS_PART_MAIN([$1], [mpn_lshift_com optimization 2],
+[/* The following is mis-compiled by Intel ia-64 icc version 1.8 under
+    "icc -O3",  After several calls, the function writes partial garbage to
+    the result vector.  Perhaps relates to the chk.a.nc insn.  This code needs
+    to be run to show the problem, but that's fine, the offending cc is a
+    native-only compiler so we don't have to worry about cross compiling.  */
+
+#if ! defined (__cplusplus)
+#include <stdlib.h>
+void
+lshift_com (rp, up, n, cnt)
+  unsigned long *rp;
+  unsigned long *up;
+  long n;
+  unsigned cnt;
+{
+  unsigned long high_limb, low_limb;
+  unsigned tnc;
+  long i;
+  up += n;
+  rp += n;
+  tnc = 8 * sizeof (unsigned long) - cnt;
+  low_limb = *--up;
+  high_limb = low_limb << cnt;
+  for (i = n - 1; i != 0; i--)
+    {
+      low_limb = *--up;
+      *--rp = ~(high_limb | (low_limb >> tnc));
+      high_limb = low_limb << cnt;
+    }
+  *--rp = ~high_limb;
+}
+int
+main ()
+{
+  unsigned long *r, *r2;
+  unsigned long a[88 + 1];
+  long i;
+  for (i = 0; i < 88 + 1; i++)
+    a[i] = ~0L;
+  r = calloc (10000, sizeof (unsigned long));
+  r2 = r;
+  for (i = 0; i < 528; i += 23)
+    {
+      lshift_com (r2, a,
+		  i / (8 * sizeof (unsigned long)) + 1,
+		  i % (8 * sizeof (unsigned long)));
+      r2 += 88 + 1;
+    }
+  if (r[2048] != 0 || r[2049] != 0 || r[2050] != 0 || r[2051] != 0 ||
+      r[2052] != 0 || r[2053] != 0 || r[2054] != 0)
+    abort ();
+  free (r);
+  return 0;
+}
+#else
+int
+main ()
+{
+  return 0;
+}
+#endif
+])
+
+
+# A certain _GLOBAL_OFFSET_TABLE_ problem in past versions of gas, tickled
+# by recent versions of gcc.
+#
+if test "$gmp_prog_cc_works" = yes; then
+  case $host in
+    X86_PATTERN)
+      # this problem only arises in PIC code, so don't need to test when
+      # --disable-shared.  We don't necessarily have $enable_shared set to
+      # yes at this point, it will still be unset for the default (which is
+      # yes); hence the use of "!= no".
+      if test "$enable_shared" != no; then
+        GMP_PROG_CC_X86_GOT_EAX_EMITTED([$1],
+          [GMP_ASM_X86_GOT_EAX_OK([$1],,
+            [gmp_prog_cc_works="no, bad gas GOT with eax"])])
+      fi
+      ;;
+  esac
+fi
+
+AC_MSG_RESULT($gmp_prog_cc_works)
+case $gmp_prog_cc_works in
+  yes)
+    [$2]
+    ;;
+  *)
+    [$3]
+    ;;
+esac
+])
+
+dnl  Called: GMP_PROG_CC_WORKS_PART(CC+CFLAGS,FAIL-MESSAGE [,CODE])
+dnl  A dummy main() is appended to the CODE given.
+dnl
+AC_DEFUN([GMP_PROG_CC_WORKS_PART],
+[GMP_PROG_CC_WORKS_PART_MAIN([$1],[$2],
+[$3]
+[int main () { return 0; }])
+])
+
+dnl  Called: GMP_PROG_CC_WORKS_PART_MAIN(CC+CFLAGS,FAIL-MESSAGE,CODE)
+dnl  CODE must include a main().
+dnl
+AC_DEFUN([GMP_PROG_CC_WORKS_PART_MAIN],
+[GMP_PROG_CC_WORKS_PART_TEST([$1],[$2],[$3],
+  [],
+  gmp_prog_cc_works="no[]m4_if([$2],,,[[, ]])[$2]",
+  gmp_prog_cc_works="no[]m4_if([$2],,,[[, ]])[$2][[, program does not run]]")
+])
+
+dnl  Called: GMP_PROG_CC_WORKS_PART_TEST(CC+CFLAGS,TITLE,[CODE],
+dnl            [ACTION-GOOD],[ACTION-BAD][ACTION-NORUN])
+dnl
+AC_DEFUN([GMP_PROG_CC_WORKS_PART_TEST],
+[if test "$gmp_prog_cc_works" = yes; then
+  # remove anything that might look like compiler output to our "||" expression
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  cat >conftest.c <<EOF
+[$3]
+EOF
+  echo "Test compile: [$2]" >&AC_FD_CC
+  gmp_compile="$1 conftest.c >&AC_FD_CC"
+  if AC_TRY_EVAL(gmp_compile); then
+    cc_works_part=yes
+    if test "$cross_compiling" = no; then
+      if AC_TRY_COMMAND([./a.out || ./b.out || ./a.exe || ./a_out.exe || ./conftest]); then :;
+      else
+        cc_works_part=norun
+      fi
+    fi
+  else
+    cc_works_part=no
+  fi
+  if test "$cc_works_part" != yes; then
+    echo "failed program was:" >&AC_FD_CC
+    cat conftest.c >&AC_FD_CC
+  fi
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  case $cc_works_part in
+    yes)
+      $4
+      ;;
+    no)
+      $5
+      ;;
+    norun)
+      $6
+      ;;
+  esac
+fi
+])
+
+
+dnl  GMP_PROG_CC_WORKS_LONGLONG(cc+cflags,[ACTION-YES][,ACTION-NO])
+dnl  --------------------------------------------------------------
+dnl  Check that cc+cflags accepts "long long".
+dnl
+dnl  This test is designed to be run repeatedly with different cc+cflags
+dnl  selections, so the result is not cached.
+
+AC_DEFUN([GMP_PROG_CC_WORKS_LONGLONG],
+[AC_MSG_CHECKING([compiler $1 has long long])
+cat >conftest.c <<EOF
+long long  foo;
+long long  bar () { return foo; }
+int main () { return 0; }
+EOF
+gmp_prog_cc_works=no
+gmp_compile="$1 -c conftest.c >&AC_FD_CC"
+if AC_TRY_EVAL(gmp_compile); then
+  gmp_prog_cc_works=yes
+else
+  echo "failed program was:" >&AC_FD_CC
+  cat conftest.c >&AC_FD_CC
+fi
+rm -f conftest* a.out b.out a.exe a_out.exe
+AC_MSG_RESULT($gmp_prog_cc_works)
+if test $gmp_prog_cc_works = yes; then
+  ifelse([$2],,:,[$2])
+else
+  ifelse([$3],,:,[$3])
+fi
+])
+
+
+dnl  GMP_C_TEST_SIZEOF(cc/cflags,test,[ACTION-GOOD][,ACTION-BAD])
+dnl  ------------------------------------------------------------
+dnl  The given cc/cflags compiler is run to check the size of a type
+dnl  specified by the "test" argument.  "test" can either be a string, or a
+dnl  variable like $foo.  The value should be for instance "sizeof-long-4",
+dnl  to test that sizeof(long)==4.
+dnl
+dnl  This test is designed to be run for different compiler and/or flags
+dnl  combinations, so the result is not cached.
+dnl
+dnl  The idea for making an array that has a negative size if the desired
+dnl  condition test is false comes from autoconf AC_CHECK_SIZEOF.  The cast
+dnl  to "long" in the array dimension also follows autoconf, apparently it's
+dnl  a workaround for a HP compiler bug.
+
+AC_DEFUN([GMP_C_TEST_SIZEOF],
+[echo "configure: testlist $2" >&AC_FD_CC
+[gmp_sizeof_type=`echo "$2" | sed 's/sizeof-\([a-z\*]*\).*/\1/'`]
+[gmp_sizeof_want=`echo "$2" | sed 's/sizeof-[a-z\*]*-\([0-9]*\).*/\1/'`]
+AC_MSG_CHECKING([compiler $1 has sizeof($gmp_sizeof_type)==$gmp_sizeof_want])
+cat >conftest.c <<EOF
+[int
+main ()
+{
+  static int test_array [1 - 2 * (long) (sizeof ($gmp_sizeof_type) != $gmp_sizeof_want)];
+  test_array[0] = 0;
+  return 0;
+}]
+EOF
+gmp_c_testlist_sizeof=no
+gmp_compile="$1 -c conftest.c >&AC_FD_CC"
+if AC_TRY_EVAL(gmp_compile); then
+  gmp_c_testlist_sizeof=yes
+fi
+rm -f conftest*
+AC_MSG_RESULT($gmp_c_testlist_sizeof)
+if test $gmp_c_testlist_sizeof = yes; then
+  ifelse([$3],,:,[$3])
+else
+  ifelse([$4],,:,[$4])
+fi
+])
+
+
+dnl  GMP_PROG_CC_IS_GNU(CC,[ACTIONS-IF-YES][,ACTIONS-IF-NO])
+dnl  -------------------------------------------------------
+dnl  Determine whether the given compiler is GNU C.
+dnl
+dnl  This test is the same as autoconf _AC_LANG_COMPILER_GNU, but doesn't
+dnl  cache the result.  The same "ifndef" style test is used, to avoid
+dnl  problems with syntax checking cpp's used on NeXT and Apple systems.
+
+AC_DEFUN([GMP_PROG_CC_IS_GNU],
+[cat >conftest.c <<EOF
+#if ! defined (__GNUC__) || defined (__INTEL_COMPILER)
+  choke me
+#endif
+EOF
+gmp_compile="$1 -c conftest.c >&AC_FD_CC"
+if AC_TRY_EVAL(gmp_compile); then
+  rm -f conftest*
+  AC_MSG_CHECKING([whether $1 is gcc])
+  AC_MSG_RESULT(yes)
+  ifelse([$2],,:,[$2])
+else
+  rm -f conftest*
+  ifelse([$3],,:,[$3])
+fi
+])
+
+
+dnl  GMP_PROG_CC_IS_XLC(CC,[ACTIONS-IF-YES][,ACTIONS-IF-NO])
+dnl  -------------------------------------------------------
+dnl  Determine whether the given compiler is IBM xlc (on AIX).
+dnl
+dnl  There doesn't seem to be a preprocessor symbol to test for this, or if
+dnl  there is one then it's well hidden in xlc 3.1 on AIX 4.3, so just grep
+dnl  the man page printed when xlc is invoked with no arguments.
+
+AC_DEFUN([GMP_PROG_CC_IS_XLC],
+[gmp_command="$1 2>&1 | grep xlc >/dev/null"
+if AC_TRY_EVAL(gmp_command); then
+  AC_MSG_CHECKING([whether $1 is xlc])
+  AC_MSG_RESULT(yes)
+  ifelse([$2],,:,[$2])
+else
+  ifelse([$3],,:,[$3])
+fi
+])
+
+
+dnl  GMP_PROG_CC_X86_GOT_EAX_EMITTED(CC+CFLAGS, [ACTION-YES] [, ACTION-NO])
+dnl  ----------------------------------------------------------------------
+dnl  Determine whether CC+CFLAGS emits instructions using %eax with
+dnl  _GLOBAL_OFFSET_TABLE_.  This test is for use on x86 systems.
+dnl
+dnl  Recent versions of gcc will use %eax for the GOT in leaf functions, for
+dnl  instance gcc 3.3.3 with -O3.  This avoids having to save and restore
+dnl  %ebx which otherwise usually holds the GOT, and is what gcc used in the
+dnl  past.
+dnl
+dnl  %ecx and %edx are also candidates for this sort of optimization, and
+dnl  are used under lesser optimization levels, like -O2 in 3.3.3.  FIXME:
+dnl  It's not quite clear what the conditions for using %eax are, we might
+dnl  need more test code to provoke it.
+dnl
+dnl  The motivation for this test is that past versions of gas have bugs
+dnl  affecting this usage, see GMP_ASM_X86_GOT_EAX_OK.
+dnl
+dnl  This test is not specific to gcc, other compilers might emit %eax GOT
+dnl  insns like this, though we've not investigated that.
+dnl
+dnl  This is for use by compiler probing in GMP_PROG_CC_WORKS, so we doesn't
+dnl  cache the result.
+dnl
+dnl  -fPIC is hard coded here, because this test is for use before libtool
+dnl  has established the pic options.  It's right for gcc, but perhaps not
+dnl  other compilers.
+
+AC_DEFUN([GMP_PROG_CC_X86_GOT_EAX_EMITTED],
+[echo "Testing gcc GOT with eax emitted" >&AC_FD_CC
+cat >conftest.c <<\EOF
+[int foo;
+int bar () { return foo; }
+]EOF
+tmp_got_emitted=no
+gmp_compile="$1 -fPIC -S conftest.c >&AC_FD_CC 2>&1"
+if AC_TRY_EVAL(gmp_compile); then
+  if grep "addl.*_GLOBAL_OFFSET_TABLE_.*eax" conftest.s >/dev/null; then
+    tmp_got_emitted=yes
+  fi
+fi
+rm -f conftest.*
+echo "Result: $tmp_got_emitted" >&AC_FD_CC
+if test "$tmp_got_emitted" = yes; then
+  ifelse([$2],,:,[$2])
+else
+  ifelse([$3],,:,[$3])
+fi
+])
+
+
+dnl  GMP_HPC_HPPA_2_0(cc,[ACTION-IF-GOOD][,ACTION-IF-BAD])
+dnl  ---------------------------------------------------------
+dnl  Find out whether a HP compiler is good enough to generate hppa 2.0.
+dnl
+dnl  This test might be repeated for different compilers, so the result is
+dnl  not cached.
+
+AC_DEFUN([GMP_HPC_HPPA_2_0],
+[AC_MSG_CHECKING([whether HP compiler $1 is good for 64-bits])
+# Bad compiler output:
+#   ccom: HP92453-01 G.10.32.05 HP C Compiler
+# Good compiler output:
+#   ccom: HP92453-01 A.10.32.30 HP C Compiler
+# Let A.10.32.30 or higher be ok.
+echo >conftest.c
+gmp_tmp_vs=`$1 $2 -V -c -o conftest.$OBJEXT conftest.c 2>&1 | grep "^ccom:"`
+echo "Version string: $gmp_tmp_vs" >&AC_FD_CC
+rm conftest*
+gmp_tmp_v1=`echo $gmp_tmp_vs | sed 's/.* .\.\([[0-9]]*\).*/\1/'`
+gmp_tmp_v2=`echo $gmp_tmp_vs | sed 's/.* .\..*\.\(.*\)\..* HP C.*/\1/'`
+gmp_tmp_v3=`echo $gmp_tmp_vs | sed 's/.* .\..*\..*\.\(.*\) HP C.*/\1/'`
+echo "Version number: $gmp_tmp_v1.$gmp_tmp_v2.$gmp_tmp_v3" >&AC_FD_CC
+if test -z "$gmp_tmp_v1"; then
+  gmp_hpc_64bit=not-applicable
+else
+  GMP_COMPARE_GE($gmp_tmp_v1, 10, $gmp_tmp_v2, 32, $gmp_tmp_v3, 30)
+  gmp_hpc_64bit=$gmp_compare_ge
+fi
+AC_MSG_RESULT($gmp_hpc_64bit)
+if test $gmp_hpc_64bit = yes; then
+  ifelse([$2],,:,[$2])
+else
+  ifelse([$3],,:,[$3])
+fi
+])
+
+
+dnl  GMP_GCC_ARM_UMODSI(CC,[ACTIONS-IF-GOOD][,ACTIONS-IF-BAD])
+dnl  ---------------------------------------------------------
+dnl  gcc 2.95.3 and earlier on arm has a bug in the libgcc __umodsi routine
+dnl  making "%" give wrong results for some operands, eg. "0x90000000 % 3".
+dnl  We're hoping it'll be fixed in 2.95.4, and we know it'll be fixed in
+dnl  gcc 3.
+dnl
+dnl  There's only a couple of places gmp cares about this, one is the
+dnl  size==1 case in mpn/generic/mode1o.c, and this shows up in
+dnl  tests/mpz/t-jac.c as a wrong result from mpz_kronecker_ui.
+
+AC_DEFUN([GMP_GCC_ARM_UMODSI],
+[AC_MSG_CHECKING([whether ARM gcc unsigned division works])
+tmp_version=`$1 --version`
+echo "$tmp_version" >&AC_FD_CC
+case $tmp_version in
+  [2.95 | 2.95.[123]])
+    ifelse([$3],,:,[$3])
+    gmp_gcc_arm_umodsi_result=["no, gcc 2.95.[0123]"] ;;
+  *)
+    ifelse([$2],,:,[$2])
+    gmp_gcc_arm_umodsi_result=yes ;;
+esac
+AC_MSG_RESULT([$gmp_gcc_arm_umodsi_result])
+])
+
+
+dnl  GMP_GCC_MIPS_O32(gcc,[actions-yes][,[actions-no]])
+dnl  -------------------------------------------------
+dnl  Test whether gcc supports o32.
+dnl
+dnl  gcc 2.7.2.2 only does o32, and doesn't accept -mabi=32.
+dnl
+dnl  gcc 2.95 accepts -mabi=32 but it only works on irix5, on irix6 it gives
+dnl  "cc1: The -mabi=32 support does not work yet".
+
+AC_DEFUN([GMP_GCC_MIPS_O32],
+[AC_MSG_CHECKING([whether gcc supports o32])
+echo 'int x;' >conftest.c
+echo "$1 -mabi=32 -c conftest.c" >&AC_FD_CC
+if $1 -mabi=32 -c conftest.c >conftest.out 2>&1; then
+  result=yes
+else
+  cat conftest.out >&AC_FD_CC
+  if grep "cc1: Invalid option \`abi=32'" conftest.out >/dev/null; then
+    result=yes
+  else
+    result=no
+  fi
+fi
+rm -f conftest.*
+AC_MSG_RESULT($result)
+if test $result = yes; then
+  ifelse([$2],,:,[$2])
+else
+  ifelse([$3],,:,[$3])
+fi
+])
+
+
+dnl  GMP_GCC_NO_CPP_PRECOMP(CCBASE,CC,CFLAGS,[ACTIONS-YES][,ACTIONS-NO])
+dnl  -------------------------------------------------------------------
+dnl  Check whether -no-cpp-precomp should be used on this compiler, and
+dnl  execute the corresponding ACTIONS-YES or ACTIONS-NO.
+dnl
+dnl  -no-cpp-precomp is only meant for Apple's hacked version of gcc found
+dnl  on powerpc*-*-darwin*, but we can give it a try on any gcc.  Normal gcc
+dnl  (as of 3.0 at least) only gives a warning, not an actual error, and we
+dnl  watch for that and decide against the option in that case, to avoid
+dnl  confusing the user.
+
+AC_DEFUN([GMP_GCC_NO_CPP_PRECOMP],
+[if test "$ccbase" = gcc; then
+  AC_MSG_CHECKING([compiler $2 $3 -no-cpp-precomp])
+  result=no
+  cat >conftest.c <<EOF
+int main () { return 0; }
+EOF
+  gmp_compile="$2 $3 -no-cpp-precomp conftest.c >conftest.out 2>&1"
+  if AC_TRY_EVAL(gmp_compile); then
+    if grep "unrecognized option.*-no-cpp-precomp" conftest.out >/dev/null; then : ;
+    else
+      result=yes
+    fi
+  fi
+  cat conftest.out >&AC_FD_CC
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  AC_MSG_RESULT($result)
+  if test "$result" = yes; then
+      ifelse([$4],,:,[$4])
+  else
+      ifelse([$5],,:,[$5])
+  fi
+fi
+])
+
+
+dnl  GMP_GCC_PENTIUM4_SSE2(CC+CFLAGS,[ACTION-IF-YES][,ACTION-IF-NO])
+dnl  ---------------------------------------------------------------
+dnl  Determine whether gcc CC+CFLAGS is a good enough version for
+dnl  -march=pentium4 with sse2.
+dnl
+dnl  Gcc 3.2.1 was seen generating incorrect code for raw double -> int
+dnl  conversions through a union.  We believe the problem is in all 3.1 and
+dnl  3.2 versions, but that it's fixed in 3.3.
+
+AC_DEFUN([GMP_GCC_PENTIUM4_SSE2],
+[AC_MSG_CHECKING([whether gcc is good for sse2])
+case `$1 -dumpversion` in
+  [3.[012] | 3.[012].*]) result=no ;;
+  *)                     result=yes ;;
+esac
+AC_MSG_RESULT($result)
+if test "$result" = yes; then
+  ifelse([$2],,:,[$2])
+else
+  ifelse([$3],,:,[$3])
+fi
+])
+
+
+dnl  GMP_GCC_WA_MCPU(CC+CFLAGS, NEWFLAG [,ACTION-YES [,ACTION-NO]])
+dnl  --------------------------------------------------------------
+dnl  Check whether gcc (or gas rather) accepts a flag like "-Wa,-mev67".
+dnl
+dnl  Gas doesn't give an error for an unknown cpu, it only prints a warning
+dnl  like "Warning: Unknown CPU identifier `ev78'".
+dnl
+dnl  This is intended for use on alpha, since only recent versions of gas
+dnl  accept -mev67, but there's nothing here that's alpha specific.
+
+AC_DEFUN([GMP_GCC_WA_MCPU],
+[AC_MSG_CHECKING([assembler $1 $2])
+result=no
+cat >conftest.c <<EOF
+int main () {}
+EOF
+gmp_compile="$1 $2 -c conftest.c >conftest.out 2>&1"
+if AC_TRY_EVAL(gmp_compile); then
+  if grep "Unknown CPU identifier" conftest.out >/dev/null; then : ;
+  else
+    result=yes
+  fi
+fi
+cat conftest.out >&AC_FD_CC
+rm -f conftest*
+AC_MSG_RESULT($result)
+if test "$result" = yes; then
+  ifelse([$3],,:,[$3])
+else
+  ifelse([$4],,:,[$4])
+fi
+])
+
+
+dnl  GMP_GCC_WA_OLDAS(CC+CFLAGS [,ACTION-YES [,ACTION-NO]])
+dnl  ------------------------------------------------------
+dnl  Check whether gcc should be run with "-Wa,-oldas".
+dnl
+dnl  On systems alpha*-*-osf* (or maybe just osf5), apparently there's a
+dnl  newish Compaq "as" which doesn't work with the gcc mips-tfile.
+dnl  Compiling an empty file with "gcc -c foo.c" produces for instance
+dnl
+dnl      mips-tfile, /tmp/ccaqUNnF.s:7 Segmentation fault
+dnl
+dnl  The fix is to pass "-oldas" to that assembler, as noted by
+dnl
+dnl      http://gcc.gnu.org/install/specific.html#alpha*-dec-osf*
+dnl
+dnl  The test here tries to compile an empty file, and if that fails but
+dnl  adding -Wa,-oldas makes it succeed, then that flag is considered
+dnl  necessary.
+dnl
+dnl  We look for the failing case specifically, since it may not be a good
+dnl  idea to use -Wa,-oldas in other circumstances.  For instance gas takes
+dnl  "-oldas" to mean the "-o" option and will write a file called "ldas" as
+dnl  its output.  Normally gcc puts its own "-o" after any -Wa options, so
+dnl  -oldas ends up being harmless, but clearly that's only through good
+dnl  luck.
+dnl
+dnl  This macro is designed for use while probing for a good compiler, and
+dnl  so doesn't cache it's result.
+
+AC_DEFUN([GMP_GCC_WA_OLDAS],
+[AC_MSG_CHECKING([for $1 -Wa,-oldas])
+result=no
+cat >conftest.c <<EOF
+EOF
+echo "with empty conftest.c" >&AC_FD_CC
+gmp_compile="$1 -c conftest.c >&AC_FD_CC 2>&1"
+if AC_TRY_EVAL(gmp_compile); then : ;
+else
+  # empty fails
+  gmp_compile="$1 -Wa,-oldas -c conftest.c >&AC_FD_CC 2>&1"
+  if AC_TRY_EVAL(gmp_compile); then
+    # but with -Wa,-oldas it works
+    result=yes
+  fi
+fi
+rm -f conftest*
+AC_MSG_RESULT($result)
+if test "$result" = yes; then
+  ifelse([$2],,:,[$2])
+else
+  ifelse([$3],,:,[$3])
+fi
+])
+
+
+dnl  GMP_OS_X86_XMM(CC+CFLAGS,[ACTION-IF-YES][,ACTION-IF-NO])
+dnl  --------------------------------------------------------
+dnl  Determine whether the operating system supports XMM registers.
+dnl
+dnl  If build==host then a test program is run, executing an SSE2
+dnl  instruction using an XMM register.  This will give a SIGILL if the
+dnl  system hasn't set the OSFXSR bit in CR4 to say it knows it must use
+dnl  fxsave/fxrestor in a context switch (to save xmm registers).
+dnl
+dnl  If build!=host, we can fallback on:
+dnl
+dnl      - FreeBSD version 4 is the first supporting xmm.
+dnl
+dnl      - Linux kernel 2.4 might be the first stable series supporting xmm
+dnl        (not sure).  But there's no version number in the GNU/Linux
+dnl        config tuple to test anyway.
+dnl
+dnl  The default is to allow xmm.  This might seem rash, but it's likely
+dnl  most systems know xmm by now, so this will normally be what's wanted.
+dnl  And cross compiling is a bit hairy anyway, so hopefully anyone doing it
+dnl  will be smart enough to know what to do.
+dnl
+dnl  In the test program, .text and .globl are hard coded because this macro
+dnl  is wanted before GMP_ASM_TEXT and GMP_ASM_GLOBL are run.  A .byte
+dnl  sequence is used (for xorps %xmm0, %xmm0) to make us independent of
+dnl  tests for whether the assembler supports sse2/xmm.  Obviously we need
+dnl  both assembler and OS support, but this means we don't force the order
+dnl  in which we test.
+dnl
+dnl  FIXME: Maybe we should use $CCAS to assemble, if it's set.  (Would
+dnl  still want $CC/$CFLAGS for the link.)  But this test is used before
+dnl  AC_PROG_CC sets $OBJEXT, so we'd need to check for various object file
+dnl  suffixes ourselves.
+
+AC_DEFUN([GMP_OS_X86_XMM],
+[AC_CACHE_CHECK([whether the operating system supports XMM registers],
+		gmp_cv_os_x86_xmm,
+[if test "$build" = "$host"; then
+  # remove anything that might look like compiler output to our "||" expression
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  cat >conftest.s <<EOF
+	.text
+main:
+_main:
+	.globl	main
+	.globl	_main
+	.byte	0x0f, 0x57, 0xc0
+	xorl	%eax, %eax
+	ret
+EOF
+  gmp_compile="$1 conftest.s -o conftest >&AC_FD_CC"
+  if AC_TRY_EVAL(gmp_compile); then
+    if AC_TRY_COMMAND([./a.out || ./b.out || ./a.exe || ./a_out.exe || ./conftest]); then
+      gmp_cv_os_x86_xmm=yes
+    else
+      gmp_cv_os_x86_xmm=no
+    fi
+  else
+    AC_MSG_WARN([Oops, cannot compile test program])
+  fi
+  rm -f conftest*
+fi
+
+if test -z "$gmp_cv_os_x86_xmm"; then
+  case $host_os in
+    [freebsd[123] | freebsd[123].*])
+      gmp_cv_os_x86_xmm=no ;;
+    freebsd*)
+      gmp_cv_os_x86_xmm=yes ;;
+    *)
+      gmp_cv_os_x86_xmm=probably ;;
+  esac
+fi
+])
+
+if test "$gmp_cv_os_x86_xmm" = probably; then
+  AC_MSG_WARN([Not certain of OS support for xmm when cross compiling.])
+  AC_MSG_WARN([Will assume it's ok, expect a SIGILL if this is wrong.])
+fi
+
+case $gmp_cv_os_x86_xmm in
+no)
+  $3
+  ;;
+*)
+  $2
+  ;;
+esac
+])
+
+
+dnl  GMP_CRAY_HOST_TYPES(C90/T90-IEEE, C90/T90-CFP, J90/SV1)
+dnl  -------------------------------------------------------
+dnl  Execute the actions in the arguments on the respective Cray vector
+dnl  systems.  For other hosts, do nothing.
+dnl
+dnl  This macro should be used after the C compiler has been chosen, since
+dnl  on c90 and t90 we ask the compiler whether we're in IEEE or CFP float
+dnl  mode.
+dnl
+dnl  This code is in a macro so that any AC_REQUIRE pre-requisites of
+dnl  AC_EGREP_CPP will be expanded at the top-level, ie. for all hosts not
+dnl  merely c90 and t90.  In autoconf 2.57 for instance this means
+dnl  AC_PROG_EGREP, which is needed by various other macros.
+
+AC_DEFUN([GMP_CRAY_OPTIONS],
+[case $host_cpu in
+  c90 | t90)
+    AC_EGREP_CPP(yes,
+[#ifdef _CRAYIEEE
+yes
+#endif],
+    [$1],
+    [$2])
+    ;;
+  j90 | sv1)
+    [$3]
+    ;;
+esac
+])
+
+
+dnl  GMP_HPPA_LEVEL_20(cc/cflags [, ACTION-GOOD [,ACTION-BAD]])
+dnl  ----------------------------------------------------------
+dnl  Check that the given cc/cflags accepts HPPA 2.0n assembler code.
+dnl
+dnl  Old versions of gas don't know 2.0 instructions.  It rejects ".level
+dnl  2.0" for a start, so just test that.
+dnl
+dnl  This test is designed to be run for various different compiler and
+dnl  flags combinations, and hence doesn't cache its result.
+
+AC_DEFUN([GMP_HPPA_LEVEL_20],
+[AC_MSG_CHECKING([$1 assembler knows hppa 2.0])
+result=no
+cat >conftest.s <<EOF
+	.level 2.0
+EOF
+gmp_compile="$1 -c conftest.s >&AC_FD_CC 2>&1"
+if AC_TRY_EVAL(gmp_compile); then
+  result=yes
+else
+  echo "failed program was" >&AC_FD_CC
+  cat conftest.s >&AC_FD_CC
+fi
+rm -f conftest*
+AC_MSG_RESULT($result)
+if test "$result" = yes; then
+  ifelse([$2],,:,[$2])
+else
+  ifelse([$3],,:,[$3])
+fi
+])
+
+
+dnl  GMP_PROG_CXX_WORKS(cxx/cxxflags [, ACTION-YES [,ACTION-NO]])
+dnl  ------------------------------------------------------------
+dnl  Check whether cxx/cxxflags can compile and link.
+dnl
+dnl  This test is designed to be run repeatedly with different cxx/cxxflags
+dnl  selections, so the result is not cached.
+dnl
+dnl  For a native build, we insist on being able to run the program, so as
+dnl  to detect any problems with the standard C++ library.  During
+dnl  development various systems with broken or incomplete C++ installations
+dnl  were seen.
+dnl
+dnl  The various features and problems we try to detect are done in separate
+dnl  compiles.  Although this is probably a bit slower than one test
+dnl  program, it makes it easy to indicate the problem in AC_MSG_RESULT,
+dnl  hence giving the user a clue about why we rejected the compiler.
+
+AC_DEFUN([GMP_PROG_CXX_WORKS],
+[AC_MSG_CHECKING([C++ compiler $1])
+gmp_prog_cxx_works=yes
+
+# start with a plain "main()", then go on to further checks
+GMP_PROG_CXX_WORKS_PART([$1], [])
+
+GMP_PROG_CXX_WORKS_PART([$1], [namespace],
+[namespace foo { }
+using namespace foo;
+])
+
+# GMP requires the standard C++ iostream classes
+GMP_PROG_CXX_WORKS_PART([$1], [std iostream],
+[/* This test rejects g++ 2.7.2 which doesn't have <iostream>, only a
+    pre-standard iostream.h. */
+#include <iostream>
+
+/* This test rejects OSF 5.1 Compaq C++ in its default pre-standard iostream
+   mode, since that mode puts cout in the global namespace, not "std".  */
+void someoutput (void) { std::cout << 123; }
+])
+
+AC_MSG_RESULT($gmp_prog_cxx_works)
+case $gmp_prog_cxx_works in
+  yes)
+    [$2]
+    ;;
+  *)
+    [$3]
+    ;;
+esac
+])
+
+dnl  Called: GMP_PROG_CXX_WORKS_PART(CXX+CXXFLAGS, FAIL-MESSAGE [,CODE])
+dnl
+AC_DEFUN([GMP_PROG_CXX_WORKS_PART],
+[if test "$gmp_prog_cxx_works" = yes; then
+  # remove anything that might look like compiler output to our "||" expression
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  cat >conftest.cc <<EOF
+[$3]
+int main (void) { return 0; }
+EOF
+  echo "Test compile: [$2]" >&AC_FD_CC
+  gmp_cxxcompile="$1 conftest.cc >&AC_FD_CC"
+  if AC_TRY_EVAL(gmp_cxxcompile); then
+    if test "$cross_compiling" = no; then
+      if AC_TRY_COMMAND([./a.out || ./b.out || ./a.exe || ./a_out.exe || ./conftest]); then :;
+      else
+        gmp_prog_cxx_works="no[]m4_if([$2],,,[, ])[$2], program does not run"
+      fi
+    fi
+  else
+    gmp_prog_cxx_works="no[]m4_if([$2],,,[, ])[$2]"
+  fi
+  case $gmp_prog_cxx_works in
+    no*)
+      echo "failed program was:" >&AC_FD_CC
+      cat conftest.cc >&AC_FD_CC
+      ;;
+  esac
+  rm -f conftest* a.out b.out a.exe a_out.exe
+fi
+])
+
+
+dnl  GMP_INIT([M4-DEF-FILE])
+dnl  -----------------------
+dnl  Initializations for GMP config.m4 generation.
+dnl
+dnl  FIXME: The generated config.m4 doesn't get recreated by config.status.
+dnl  Maybe the relevant "echo"s should go through AC_CONFIG_COMMANDS.
+
+AC_DEFUN([GMP_INIT],
+[ifelse([$1], , gmp_configm4=config.m4, gmp_configm4="[$1]")
+gmp_tmpconfigm4=cnfm4.tmp
+gmp_tmpconfigm4i=cnfm4i.tmp
+gmp_tmpconfigm4p=cnfm4p.tmp
+rm -f $gmp_tmpconfigm4 $gmp_tmpconfigm4i $gmp_tmpconfigm4p
+
+# CONFIG_TOP_SRCDIR is a path from the mpn builddir to the top srcdir.
+# The pattern here tests for an absolute path the same way as
+# _AC_OUTPUT_FILES in autoconf acgeneral.m4.
+case $srcdir in
+[[\\/]]* | ?:[[\\/]]* )  tmp="$srcdir"    ;;
+*)                       tmp="../$srcdir" ;;
+esac
+echo ["define(<CONFIG_TOP_SRCDIR>,<\`$tmp'>)"] >>$gmp_tmpconfigm4
+
+# All CPUs use asm-defs.m4
+echo ["include][(CONFIG_TOP_SRCDIR\`/mpn/asm-defs.m4')"] >>$gmp_tmpconfigm4i
+])
+
+
+dnl  GMP_FINISH
+dnl  ----------
+dnl  Create config.m4 from its accumulated parts.
+dnl
+dnl  __CONFIG_M4_INCLUDED__ is used so that a second or subsequent include
+dnl  of config.m4 is harmless.
+dnl
+dnl  A separate ifdef on the angle bracket quoted part ensures the quoting
+dnl  style there is respected.  The basic defines from gmp_tmpconfigm4 are
+dnl  fully quoted but are still put under an ifdef in case any have been
+dnl  redefined by one of the m4 include files.
+dnl
+dnl  Doing a big ifdef within asm-defs.m4 and/or other macro files wouldn't
+dnl  work, since it'd interpret parentheses and quotes in dnl comments, and
+dnl  having a whole file as a macro argument would overflow the string space
+dnl  on BSD m4.
+
+AC_DEFUN([GMP_FINISH],
+[AC_REQUIRE([GMP_INIT])
+echo "creating $gmp_configm4"
+echo ["d""nl $gmp_configm4.  Generated automatically by configure."] > $gmp_configm4
+if test -f $gmp_tmpconfigm4; then
+  echo ["changequote(<,>)"] >> $gmp_configm4
+  echo ["ifdef(<__CONFIG_M4_INCLUDED__>,,<"] >> $gmp_configm4
+  cat $gmp_tmpconfigm4 >> $gmp_configm4
+  echo [">)"] >> $gmp_configm4
+  echo ["changequote(\`,')"] >> $gmp_configm4
+  rm $gmp_tmpconfigm4
+fi
+echo ["ifdef(\`__CONFIG_M4_INCLUDED__',,\`"] >> $gmp_configm4
+if test -f $gmp_tmpconfigm4i; then
+  cat $gmp_tmpconfigm4i >> $gmp_configm4
+  rm $gmp_tmpconfigm4i
+fi
+if test -f $gmp_tmpconfigm4p; then
+  cat $gmp_tmpconfigm4p >> $gmp_configm4
+  rm $gmp_tmpconfigm4p
+fi
+echo ["')"] >> $gmp_configm4
+echo ["define(\`__CONFIG_M4_INCLUDED__')"] >> $gmp_configm4
+])
+
+
+dnl  GMP_INCLUDE_MPN(FILE)
+dnl  ---------------------
+dnl  Add an include_mpn(`FILE') to config.m4.  FILE should be a path
+dnl  relative to the mpn source directory, for example
+dnl
+dnl      GMP_INCLUDE_MPN(`x86/x86-defs.m4')
+dnl
+
+AC_DEFUN([GMP_INCLUDE_MPN],
+[AC_REQUIRE([GMP_INIT])
+echo ["include_mpn(\`$1')"] >> $gmp_tmpconfigm4i
+])
+
+
+dnl  GMP_DEFINE(MACRO, DEFINITION [, LOCATION])
+dnl  ------------------------------------------
+dnl  Define M4 macro MACRO as DEFINITION in temporary file.
+dnl
+dnl  If LOCATION is `POST', the definition will appear after any include()
+dnl  directives inserted by GMP_INCLUDE.  Mind the quoting!  No shell
+dnl  variables will get expanded.  Don't forget to invoke GMP_FINISH to
+dnl  create file config.m4.  config.m4 uses `<' and '>' as quote characters
+dnl  for all defines.
+
+AC_DEFUN([GMP_DEFINE],
+[AC_REQUIRE([GMP_INIT])
+echo ['define(<$1>, <$2>)'] >>ifelse([$3], [POST],
+                              $gmp_tmpconfigm4p, $gmp_tmpconfigm4)
+])
+
+
+dnl  GMP_DEFINE_RAW(STRING [, LOCATION])
+dnl  ------------------------------------
+dnl  Put STRING into config.m4 file.
+dnl
+dnl  If LOCATION is `POST', the definition will appear after any include()
+dnl  directives inserted by GMP_INCLUDE.  Don't forget to invoke GMP_FINISH
+dnl  to create file config.m4.
+
+AC_DEFUN([GMP_DEFINE_RAW],
+[AC_REQUIRE([GMP_INIT])
+echo [$1] >> ifelse([$2], [POST], $gmp_tmpconfigm4p, $gmp_tmpconfigm4)
+])
+
+
+dnl  GMP_TRY_ASSEMBLE(asm-code,[action-success][,action-fail])
+dnl  ----------------------------------------------------------
+dnl  Attempt to assemble the given code.
+dnl  Do "action-success" if this succeeds, "action-fail" if not.
+dnl
+dnl  conftest.o and conftest.out are available for inspection in
+dnl  "action-success".  If either action does a "break" out of a loop then
+dnl  an explicit "rm -f conftest*" will be necessary.
+dnl
+dnl  This is not unlike AC_TRY_COMPILE, but there's no default includes or
+dnl  anything in "asm-code", everything wanted must be given explicitly.
+
+AC_DEFUN([GMP_TRY_ASSEMBLE],
+[cat >conftest.s <<EOF
+[$1]
+EOF
+gmp_assemble="$CCAS $CFLAGS $CPPFLAGS conftest.s >conftest.out 2>&1"
+if AC_TRY_EVAL(gmp_assemble); then
+  cat conftest.out >&AC_FD_CC
+  ifelse([$2],,:,[$2])
+else
+  cat conftest.out >&AC_FD_CC
+  echo "configure: failed program was:" >&AC_FD_CC
+  cat conftest.s >&AC_FD_CC
+  ifelse([$3],,:,[$3])
+fi
+rm -f conftest*
+])
+
+
+dnl Checks whether the stack can be marked nonexecutable by passing an option
+dnl to the C-compiler when acting on .s files. Appends that option to ASMFLAGS.
+dnl This macro is adapted from one found in GLIBC-2.3.5.
+dnl FIXME: This test looks broken. It tests that a file with .note.GNU-stack...
+dnl can be compiled/assembled with -Wa,--noexecstack.  It does not determine
+dnl if that command-line option has any effect on general asm code.
+AC_DEFUN([CL_AS_NOEXECSTACK],[
+dnl AC_REQUIRE([AC_PROG_CC]) GMP uses something else
+AC_CACHE_CHECK([whether assembler supports --noexecstack option],
+cl_cv_as_noexecstack, [dnl
+  cat > conftest.c <<EOF
+void foo() {}
+EOF
+  if AC_TRY_COMMAND([${CC} $CFLAGS $CPPFLAGS
+                     -S -o conftest.s conftest.c >/dev/null]) \
+     && grep .note.GNU-stack conftest.s >/dev/null \
+     && AC_TRY_COMMAND([${CC} $CFLAGS $CPPFLAGS -Wa,--noexecstack
+                       -c -o conftest.o conftest.s >/dev/null])
+  then
+    cl_cv_as_noexecstack=yes
+  else
+    cl_cv_as_noexecstack=no
+  fi
+  rm -f conftest*])
+  if test "$cl_cv_as_noexecstack" = yes; then
+    ASMFLAGS="$ASMFLAGS -Wa,--noexecstack"
+  fi
+  AC_SUBST(ASMFLAGS)
+])
+
+
+dnl  GMP_ASM_LABEL_SUFFIX
+dnl  --------------------
+dnl  : - is usual.
+dnl  empty - hppa on HP-UX doesn't use a :, just the label name
+dnl
+dnl  Note that it's necessary to test the empty case first, since HP "as"
+dnl  will accept "somelabel:", and take it to mean a label with a name that
+dnl  happens to end in a colon.
+
+AC_DEFUN([GMP_ASM_LABEL_SUFFIX],
+[AC_REQUIRE([GMP_ASM_TEXT])
+AC_CACHE_CHECK([for assembler label suffix],
+                gmp_cv_asm_label_suffix,
+[gmp_cv_asm_label_suffix=unknown
+for i in "" ":"; do
+  echo "trying $i" >&AC_FD_CC
+  GMP_TRY_ASSEMBLE(
+[	$gmp_cv_asm_text
+somelabel$i],
+    [gmp_cv_asm_label_suffix=$i
+     rm -f conftest*
+     break],
+    [cat conftest.out >&AC_FD_CC])
+done
+if test "$gmp_cv_asm_label_suffix" = "unknown"; then
+  AC_MSG_ERROR([Cannot determine label suffix])
+fi
+])
+echo ["define(<LABEL_SUFFIX>, <$gmp_cv_asm_label_suffix>)"] >> $gmp_tmpconfigm4
+])
+
+
+dnl  GMP_ASM_UNDERSCORE
+dnl  ------------------
+dnl  Determine whether global symbols need to be prefixed with an underscore.
+dnl  The output from "nm" is grepped to see what a typical symbol looks like.
+dnl
+dnl  This test used to grep the .o file directly, but that failed with greps
+dnl  that don't like binary files (eg. SunOS 4).
+dnl
+dnl  This test also used to construct an assembler file with and without an
+dnl  underscore and try to link that to a C file, to see which worked.
+dnl  Although that's what will happen in the real build we don't really want
+dnl  to depend on creating asm files within configure for every possible CPU
+dnl  (or at least we don't want to do that more than we have to).
+dnl
+dnl  The fallback on no underscore is based on the assumption that the world
+dnl  is moving towards non-underscore systems.  There should actually be no
+dnl  good reason for nm to fail though.
+
+AC_DEFUN([GMP_ASM_UNDERSCORE],
+[AC_REQUIRE([GMP_PROG_NM])
+AC_CACHE_CHECK([if globals are prefixed by underscore],
+               gmp_cv_asm_underscore,
+[gmp_cv_asm_underscore="unknown"
+cat >conftest.c <<EOF
+int gurkmacka;
+EOF
+gmp_compile="$CC $CFLAGS $CPPFLAGS -c conftest.c >&AC_FD_CC"
+if AC_TRY_EVAL(gmp_compile); then
+  $NM conftest.$OBJEXT >conftest.out
+  if grep "[[ 	]]_gurkmacka" conftest.out >/dev/null; then
+    gmp_cv_asm_underscore=yes
+  elif grep "[[ 	]]gurkmacka" conftest.out >/dev/null; then
+    gmp_cv_asm_underscore=no
+  else
+    echo "configure: $NM doesn't have gurkmacka:" >&AC_FD_CC
+    cat conftest.out >&AC_FD_CC
+  fi
+else
+  echo "configure: failed program was:" >&AC_FD_CC
+  cat conftest.c >&AC_FD_CC
+fi
+rm -f conftest*
+])
+case $gmp_cv_asm_underscore in
+  yes)
+    GMP_DEFINE(GSYM_PREFIX, [_]) ;;
+  no)
+    GMP_DEFINE(GSYM_PREFIX, []) ;;
+  *)
+    AC_MSG_WARN([+----------------------------------------------------------])
+    AC_MSG_WARN([| Cannot determine global symbol prefix.])
+    AC_MSG_WARN([| $NM output doesn't contain a global data symbol.])
+    AC_MSG_WARN([| Will proceed with no underscore.])
+    AC_MSG_WARN([| If this is wrong then you'll get link errors referring])
+    AC_MSG_WARN([| to ___gmpn_add_n (note three underscores).])
+    AC_MSG_WARN([| In this case do a fresh build with an override,])
+    AC_MSG_WARN([|     ./configure gmp_cv_asm_underscore=yes])
+    AC_MSG_WARN([+----------------------------------------------------------])
+    GMP_DEFINE(GSYM_PREFIX, [])
+    ;;
+esac
+])
+
+
+dnl  GMP_ASM_ALIGN_LOG
+dnl  -----------------
+dnl  Is parameter to `.align' logarithmic?
+
+AC_DEFUN([GMP_ASM_ALIGN_LOG],
+[AC_REQUIRE([GMP_ASM_GLOBL])
+AC_REQUIRE([GMP_ASM_BYTE])
+AC_REQUIRE([GMP_ASM_DATA])
+AC_REQUIRE([GMP_ASM_LABEL_SUFFIX])
+AC_REQUIRE([GMP_PROG_NM])
+AC_CACHE_CHECK([if .align assembly directive is logarithmic],
+               gmp_cv_asm_align_log,
+[GMP_TRY_ASSEMBLE(
+[	$gmp_cv_asm_data
+	.align  4
+	$gmp_cv_asm_globl	foo
+	$gmp_cv_asm_byte	1
+	.align	4
+foo$gmp_cv_asm_label_suffix
+	$gmp_cv_asm_byte	2],
+  [gmp_tmp_val=[`$NM conftest.$OBJEXT | grep foo | \
+     sed -e 's;[[][0-9][]]\(.*\);\1;' -e 's;[^1-9]*\([0-9]*\).*;\1;'`]
+  if test "$gmp_tmp_val" = "10" || test "$gmp_tmp_val" = "16"; then
+    gmp_cv_asm_align_log=yes
+  else
+    gmp_cv_asm_align_log=no
+  fi],
+  [AC_MSG_ERROR([cannot assemble alignment test])])])
+
+GMP_DEFINE_RAW(["define(<ALIGN_LOGARITHMIC>,<$gmp_cv_asm_align_log>)"])
+])
+
+
+dnl  GMP_ASM_ALIGN_FILL_0x90
+dnl  -----------------------
+dnl  Determine whether a ",0x90" suffix works on a .align directive.
+dnl  This is only meant for use on x86, 0x90 being a "nop".
+dnl
+dnl  Old gas, eg. 1.92.3
+dnl       Needs ",0x90" or else the fill is 0x00, which can't be executed
+dnl       across.
+dnl
+dnl  New gas, eg. 2.91
+dnl       Generates multi-byte nop fills even when ",0x90" is given.
+dnl
+dnl  Solaris 2.6 as
+dnl       ",0x90" is not allowed, causes a fatal error.
+dnl
+dnl  Solaris 2.8 as
+dnl       ",0x90" does nothing, generates a warning that it's being ignored.
+dnl
+dnl  SCO OpenServer 5 as
+dnl       Second parameter is max bytes to fill, not a fill pattern.
+dnl       ",0x90" is an error due to being bigger than the first parameter.
+dnl       Multi-byte nop fills are generated in text segments.
+dnl
+dnl  Note that both solaris "as"s only care about ",0x90" if they actually
+dnl  have to use it to fill something, hence the .byte in the test.  It's
+dnl  the second .align which provokes the error or warning.
+dnl
+dnl  The warning from solaris 2.8 is suppressed to stop anyone worrying that
+dnl  something might be wrong.
+
+AC_DEFUN([GMP_ASM_ALIGN_FILL_0x90],
+[AC_REQUIRE([GMP_ASM_TEXT])
+AC_CACHE_CHECK([if the .align directive accepts an 0x90 fill in .text],
+               gmp_cv_asm_align_fill_0x90,
+[GMP_TRY_ASSEMBLE(
+[	$gmp_cv_asm_text
+	.align  4, 0x90
+	.byte   0
+	.align  4, 0x90],
+[if grep "Warning: Fill parameter ignored for executable section" conftest.out >/dev/null; then
+  echo "Suppressing this warning by omitting 0x90" 1>&AC_FD_CC
+  gmp_cv_asm_align_fill_0x90=no
+else
+  gmp_cv_asm_align_fill_0x90=yes
+fi],
+[gmp_cv_asm_align_fill_0x90=no])])
+
+GMP_DEFINE_RAW(["define(<ALIGN_FILL_0x90>,<$gmp_cv_asm_align_fill_0x90>)"])
+])
+
+
+dnl  GMP_ASM_BYTE
+dnl  ------------
+dnl  .byte - is usual.
+dnl  data1 - required by ia64 (on hpux at least).
+dnl
+dnl  This macro is just to support other configure tests, not any actual asm
+dnl  code.
+
+AC_DEFUN([GMP_ASM_BYTE],
+[AC_REQUIRE([GMP_ASM_TEXT])
+AC_REQUIRE([GMP_ASM_LABEL_SUFFIX])
+AC_CACHE_CHECK([for assembler byte directive],
+                gmp_cv_asm_byte,
+[for i in .byte data1; do
+  echo "trying $i" >&AC_FD_CC
+  GMP_TRY_ASSEMBLE(
+[	$gmp_cv_asm_data
+	$i	0
+],
+    [gmp_cv_asm_byte=$i
+     rm -f conftest*
+     break],
+    [cat conftest.out >&AC_FD_CC])
+done
+if test -z "$gmp_cv_asm_byte"; then
+  AC_MSG_ERROR([Cannot determine how to emit a data byte])
+fi
+])
+])
+
+
+dnl  GMP_ASM_TEXT
+dnl  ------------
+dnl  .text - is usual.
+dnl  .code - is needed by the hppa on HP-UX (but ia64 HP-UX uses .text)
+dnl  .csect .text[PR] - is for AIX.
+
+AC_DEFUN([GMP_ASM_TEXT],
+[AC_CACHE_CHECK([how to switch to text section],
+                gmp_cv_asm_text,
+[for i in ".text" ".code" [".csect .text[PR]"]; do
+  echo "trying $i" >&AC_FD_CC
+  GMP_TRY_ASSEMBLE([	$i],
+    [gmp_cv_asm_text=$i
+     rm -f conftest*
+     break])
+done
+if test -z "$gmp_cv_asm_text"; then
+  AC_MSG_ERROR([Cannot determine text section directive])
+fi
+])
+echo ["define(<TEXT>, <$gmp_cv_asm_text>)"] >> $gmp_tmpconfigm4
+])
+
+
+dnl  GMP_ASM_DATA
+dnl  ------------
+dnl  Can we say `.data'?
+
+AC_DEFUN([GMP_ASM_DATA],
+[AC_CACHE_CHECK([how to switch to data section],
+                gmp_cv_asm_data,
+[case $host in
+  *-*-aix*) gmp_cv_asm_data=[".csect .data[RW]"] ;;
+  *)        gmp_cv_asm_data=".data" ;;
+esac
+])
+echo ["define(<DATA>, <$gmp_cv_asm_data>)"] >> $gmp_tmpconfigm4
+])
+
+
+dnl  GMP_ASM_RODATA
+dnl  --------------
+dnl  Find out how to switch to the read-only data section.
+dnl
+dnl  The compiler output is grepped for the right directive.  It's not
+dnl  considered wise to just probe for ".section .rodata" or whatever works,
+dnl  since arbitrary section names might be accepted, but not necessarily do
+dnl  the right thing when they get to the linker.
+dnl
+dnl  Only a few asm files use RODATA, so this code is perhaps a bit
+dnl  excessive right now, but should find more uses in the future.
+dnl
+dnl  FIXME: gcc on aix generates something like ".csect _foo.ro_c[RO],3"
+dnl  where foo is the object file.  Might need to check for that if we use
+dnl  RODATA there.
+
+AC_DEFUN([GMP_ASM_RODATA],
+[AC_REQUIRE([GMP_ASM_TEXT])
+AC_REQUIRE([GMP_ASM_DATA])
+AC_REQUIRE([GMP_ASM_LABEL_SUFFIX])
+AC_REQUIRE([GMP_ASM_UNDERSCORE])
+AC_CACHE_CHECK([how to switch to read-only data section],
+               gmp_cv_asm_rodata,
+[
+dnl Default to DATA on CPUs with split code/data caching, and TEXT
+dnl elsewhere.  i386 means generic x86, so use DATA on it.
+case $host in
+X86_PATTERN | x86_64-*-*)
+  gmp_cv_asm_rodata="$gmp_cv_asm_data" ;;
+*)
+  gmp_cv_asm_rodata="$gmp_cv_asm_text" ;;
+esac
+
+cat >conftest.c <<EOF
+extern const int foo[[]];		/* Suppresses C++'s suppression of foo */
+const int foo[[]] = {1,2,3};
+EOF
+echo "Test program:" >&AC_FD_CC
+cat conftest.c >&AC_FD_CC
+gmp_compile="$CC $CFLAGS $CPPFLAGS -S conftest.c >&AC_FD_CC"
+if AC_TRY_EVAL(gmp_compile); then
+  echo "Compiler output:" >&AC_FD_CC
+  cat conftest.s >&AC_FD_CC
+  if test $gmp_cv_asm_underscore = yes; then
+    tmp_gsym_prefix=_
+  else
+    tmp_gsym_prefix=
+  fi
+  # must see our label
+  if grep "^${tmp_gsym_prefix}foo$gmp_cv_asm_label_suffix" conftest.s >/dev/null 2>&AC_FD_CC; then
+    # take the last directive before our label (hence skipping segments
+    # getting debugging info etc)
+    tmp_match=`sed -n ["/^${tmp_gsym_prefix}foo$gmp_cv_asm_label_suffix/q
+                        /^[. 	]*data/p
+                        /^[. 	]*rdata/p
+                        /^[. 	]*text/p
+                        /^[. 	]*section/p
+                        /^[. 	]*csect/p
+                        /^[. 	]*CSECT/p"] conftest.s | sed -n '$p'`
+    echo "Match: $tmp_match" >&AC_FD_CC
+    if test -n "$tmp_match"; then
+      gmp_cv_asm_rodata=$tmp_match
+    fi
+  else
+    echo "Couldn't find label: ^${tmp_gsym_prefix}foo$gmp_cv_asm_label_suffix" >&AC_FD_CC
+  fi
+fi
+rm -f conftest*
+])
+echo ["define(<RODATA>, <$gmp_cv_asm_rodata>)"] >> $gmp_tmpconfigm4
+])
+
+
+dnl  GMP_ASM_GLOBL
+dnl  -------------
+dnl  The assembler directive to mark a label as a global symbol.
+dnl
+dnl  ia64 - .global is standard, according to the Intel documentation.
+dnl
+dnl  hppa - ".export foo,entry" is demanded by HP hppa "as".  ".global" is a
+dnl      kind of import.
+dnl
+dnl  other - .globl is usual.
+dnl
+dnl  "gas" tends to accept .globl everywhere, in addition to .export or
+dnl  .global or whatever the system assembler demands.
+
+AC_DEFUN([GMP_ASM_GLOBL],
+[AC_REQUIRE([GMP_ASM_TEXT])
+AC_CACHE_CHECK([for assembler global directive],
+                gmp_cv_asm_globl,
+[case $host in
+  hppa*-*-*)     gmp_cv_asm_globl=.export ;;
+  IA64_PATTERN)  gmp_cv_asm_globl=.global ;;
+  *)             gmp_cv_asm_globl=.globl  ;;
+esac
+])
+echo ["define(<GLOBL>, <$gmp_cv_asm_globl>)"] >> $gmp_tmpconfigm4
+])
+
+
+dnl  GMP_ASM_GLOBL_ATTR
+dnl  ------------------
+dnl  Do we need something after `GLOBL symbol'?
+
+AC_DEFUN([GMP_ASM_GLOBL_ATTR],
+[AC_REQUIRE([GMP_ASM_GLOBL])
+AC_CACHE_CHECK([for assembler global directive attribute],
+                gmp_cv_asm_globl_attr,
+[case $gmp_cv_asm_globl in
+  .export) gmp_cv_asm_globl_attr=",entry" ;;
+  *)       gmp_cv_asm_globl_attr="" ;;
+esac
+])
+echo ["define(<GLOBL_ATTR>, <$gmp_cv_asm_globl_attr>)"] >> $gmp_tmpconfigm4
+])
+
+
+dnl  GMP_ASM_TYPE
+dnl  ------------
+dnl  Can we say ".type", and how?
+dnl
+dnl  For i386 GNU/Linux ELF systems, and very likely other ELF systems,
+dnl  .type and .size are important on functions in shared libraries.  If
+dnl  .type is omitted and the mainline program references that function then
+dnl  the code will be copied down to the mainline at load time like a piece
+dnl  of data.  If .size is wrong or missing (it defaults to 4 bytes or some
+dnl  such) then incorrect bytes will be copied and a segv is the most likely
+dnl  result.  In any case such copying is not what's wanted, a .type
+dnl  directive will ensure a PLT entry is used.
+dnl
+dnl  In GMP the assembler functions are normally only used from within the
+dnl  library (since most programs are not interested in the low level
+dnl  routines), and in those circumstances a missing .type isn't fatal,
+dnl  letting the problem go unnoticed.  tests/mpn/t-asmtype.c aims to check
+dnl  for it.
+
+AC_DEFUN([GMP_ASM_TYPE],
+[AC_CACHE_CHECK([for assembler .type directive],
+                gmp_cv_asm_type,
+[gmp_cv_asm_type=
+for gmp_tmp_prefix in @ \# %; do
+  GMP_TRY_ASSEMBLE([	.type	sym,${gmp_tmp_prefix}function],
+    [if grep "\.type pseudo-op used outside of \.def/\.endef ignored" conftest.out >/dev/null; then : ;
+    else
+      gmp_cv_asm_type=".type	\$][1,${gmp_tmp_prefix}\$][2"
+      break
+    fi])
+done
+rm -f conftest*
+])
+echo ["define(<TYPE>, <$gmp_cv_asm_type>)"] >> $gmp_tmpconfigm4
+])
+
+
+dnl  GMP_ASM_SIZE
+dnl  ------------
+dnl  Can we say `.size'?
+
+AC_DEFUN([GMP_ASM_SIZE],
+[AC_CACHE_CHECK([for assembler .size directive],
+                gmp_cv_asm_size,
+[gmp_cv_asm_size=
+GMP_TRY_ASSEMBLE([	.size	sym,1],
+  [if grep "\.size pseudo-op used outside of \.def/\.endef ignored" conftest.out >/dev/null; then : ;
+  else
+    gmp_cv_asm_size=".size	\$][1,\$][2"
+  fi])
+])
+echo ["define(<SIZE>, <$gmp_cv_asm_size>)"] >> $gmp_tmpconfigm4
+])
+
+
+dnl  GMP_ASM_COFF_TYPE
+dnl  -----------------
+dnl  Determine whether the assembler supports COFF type information.
+dnl
+dnl  Currently this is only needed for mingw (and cygwin perhaps) and so is
+dnl  run only on the x86s, but it ought to work anywhere.
+dnl
+dnl  On MINGW, recent versions of the linker have an automatic import scheme
+dnl  for data in a DLL which is referenced by a mainline but without
+dnl  __declspec (__dllimport__) on the prototype.  It seems functions
+dnl  without type information are treated as data, or something, and calls
+dnl  to them from the mainline will crash.  gcc puts type information on the
+dnl  C functions it generates, we need to do the same for assembler
+dnl  functions.
+dnl
+dnl  This applies only to functions without __declspec(__dllimport__),
+dnl  ie. without __GMP_DECLSPEC in the case of libgmp, so it also works just
+dnl  to ensure all assembler functions used from outside libgmp have
+dnl  __GMP_DECLSPEC on their prototypes.  But this isn't an ideal situation,
+dnl  since we don't want perfectly valid calls going wrong just because
+dnl  there wasn't a prototype in scope.
+dnl
+dnl  When an auto-import takes place, the following warning is given by the
+dnl  linker.  This shouldn't be seen for any functions.
+dnl
+dnl      Info: resolving _foo by linking to __imp__foo (auto-import)
+dnl
+dnl
+dnl  COFF type directives look like the following
+dnl
+dnl      .def    _foo
+dnl      .scl    2
+dnl      .type   32
+dnl      .endef
+dnl
+dnl  _foo is the symbol with GSYM_PREFIX (_).  .scl is the storage class, 2
+dnl  for external, 3 for static.  .type is the object type, 32 for a
+dnl  function.
+dnl
+dnl  On an ELF system, this is (correctly) rejected due to .def, .endef and
+dnl  .scl being invalid, and .type not having enough arguments.
+
+AC_DEFUN([GMP_ASM_COFF_TYPE],
+[AC_REQUIRE([GMP_ASM_TEXT])
+AC_REQUIRE([GMP_ASM_GLOBL])
+AC_REQUIRE([GMP_ASM_GLOBL_ATTR])
+AC_REQUIRE([GMP_ASM_LABEL_SUFFIX])
+AC_REQUIRE([GMP_ASM_UNDERSCORE])
+AC_CACHE_CHECK([for assembler COFF type directives],
+		gmp_cv_asm_x86_coff_type,
+[GMP_TRY_ASSEMBLE(
+[	$gmp_cv_asm_text
+	$gmp_cv_asm_globl ${tmp_gsym_prefix}foo$gmp_cv_asm_globl_attr
+	.def	${tmp_gsym_prefix}foo
+	.scl	2
+	.type	32
+	.endef
+${tmp_gsym_prefix}foo$gmp_cv_asm_label_suffix
+],
+  [gmp_cv_asm_x86_coff_type=yes],
+  [gmp_cv_asm_x86_coff_type=no])
+])
+echo ["define(<HAVE_COFF_TYPE>, <$gmp_cv_asm_x86_coff_type>)"] >> $gmp_tmpconfigm4
+])
+
+
+dnl  GMP_ASM_LSYM_PREFIX
+dnl  -------------------
+dnl  What is the prefix for a local label?
+dnl
+dnl  The prefixes tested are,
+dnl
+dnl      L  - usual for underscore systems
+dnl      .L - usual for non-underscore systems
+dnl      $  - alpha (gas and OSF system assembler)
+dnl      L$ - hppa (gas and HP-UX system assembler)
+dnl
+dnl  The default is "L" if the tests fail for any reason.  There's a good
+dnl  chance this will be adequate, since on most systems labels are local
+dnl  anyway unless given a ".globl", and an "L" will avoid clashes with
+dnl  other identifers.
+dnl
+dnl  For gas, ".L" is normally purely local to the assembler, it doesn't get
+dnl  put into the object file at all.  This style is preferred, to keep the
+dnl  object files nice and clean.
+dnl
+dnl  BSD format nm produces a line like
+dnl
+dnl      00000000 t Lgurkmacka
+dnl
+dnl  The symbol code is normally "t" for text, but any lower case letter
+dnl  indicates a local definition.
+dnl
+dnl  Code "n" is for a debugging symbol, OSF "nm -B" gives that as an upper
+dnl  case "N" for a local.
+dnl
+dnl  HP-UX nm prints an error message (though seems to give a 0 exit) if
+dnl  there's no symbols at all in an object file, hence the use of "dummy".
+
+AC_DEFUN([GMP_ASM_LSYM_PREFIX],
+[AC_REQUIRE([GMP_ASM_LABEL_SUFFIX])
+AC_REQUIRE([GMP_ASM_TEXT])
+AC_REQUIRE([GMP_PROG_NM])
+AC_CACHE_CHECK([for assembler local label prefix],
+               gmp_cv_asm_lsym_prefix,
+[gmp_tmp_pre_appears=yes
+for gmp_tmp_pre in L .L $L $ L$; do
+  echo "Trying $gmp_tmp_pre" >&AC_FD_CC
+  GMP_TRY_ASSEMBLE(
+[	$gmp_cv_asm_text
+dummy${gmp_cv_asm_label_suffix}
+${gmp_tmp_pre}gurkmacka${gmp_cv_asm_label_suffix}],
+  [if $NM conftest.$OBJEXT >conftest.nm 2>&AC_FD_CC; then : ; else
+    cat conftest.nm >&AC_FD_CC
+    AC_MSG_WARN(["$NM" failure])
+    break
+  fi
+  cat conftest.nm >&AC_FD_CC
+  if grep gurkmacka conftest.nm >/dev/null; then : ; else
+    # no mention of the symbol, this is good
+    echo "$gmp_tmp_pre label doesn't appear in object file at all (good)" >&AC_FD_CC
+    gmp_cv_asm_lsym_prefix="$gmp_tmp_pre"
+    gmp_tmp_pre_appears=no
+    break
+  fi
+  if grep [' [a-zN] .*gurkmacka'] conftest.nm >/dev/null; then
+    # symbol mentioned as a local, use this if nothing better
+    echo "$gmp_tmp_pre label is local but still in object file" >&AC_FD_CC
+    if test -z "$gmp_cv_asm_lsym_prefix"; then
+      gmp_cv_asm_lsym_prefix="$gmp_tmp_pre"
+    fi
+  else
+    echo "$gmp_tmp_pre label is something unknown" >&AC_FD_CC
+  fi
+  ])
+done
+rm -f conftest*
+if test -z "$gmp_cv_asm_lsym_prefix"; then
+  gmp_cv_asm_lsym_prefix=L
+  AC_MSG_WARN([cannot determine local label, using default $gmp_cv_asm_lsym_prefix])
+fi
+# for development purposes, note whether we got a purely temporary local label
+echo "Local label appears in object files: $gmp_tmp_pre_appears" >&AC_FD_CC
+])
+echo ["define(<LSYM_PREFIX>, <${gmp_cv_asm_lsym_prefix}>)"] >> $gmp_tmpconfigm4
+AC_DEFINE_UNQUOTED(LSYM_PREFIX, "$gmp_cv_asm_lsym_prefix",
+                   [Assembler local label prefix])
+])
+
+
+dnl  GMP_ASM_W32
+dnl  -----------
+dnl  How to define a 32-bit word.
+dnl
+dnl  FIXME: This test is not right for ia64-*-hpux*.  The directive should
+dnl  be "data4", but the W32 macro is not currently used by the mpn/ia64 asm
+dnl  files.
+
+AC_DEFUN([GMP_ASM_W32],
+[AC_REQUIRE([GMP_ASM_DATA])
+AC_REQUIRE([GMP_ASM_BYTE])
+AC_REQUIRE([GMP_ASM_GLOBL])
+AC_REQUIRE([GMP_ASM_LABEL_SUFFIX])
+AC_REQUIRE([GMP_PROG_NM])
+AC_CACHE_CHECK([how to define a 32-bit word],
+	       gmp_cv_asm_w32,
+[case $host in
+  *-*-hpux*)
+    # FIXME: HPUX puts first symbol at 0x40000000, breaking our assumption
+    # that it's at 0x0.  We'll have to declare another symbol before the
+    # .long/.word and look at the distance between the two symbols.  The
+    # only problem is that the sed expression(s) barfs (on Solaris, for
+    # example) for the symbol with value 0.  For now, HPUX uses .word.
+    gmp_cv_asm_w32=".word"
+    ;;
+  *-*-*)
+    gmp_tmp_val=
+    for gmp_tmp_op in .long .word data4; do
+      GMP_TRY_ASSEMBLE(
+[	$gmp_cv_asm_data
+	$gmp_cv_asm_globl	foo
+	$gmp_tmp_op	0
+foo$gmp_cv_asm_label_suffix
+	$gmp_cv_asm_byte	0],
+        [gmp_tmp_val=[`$NM conftest.$OBJEXT | grep foo | \
+          sed -e 's;[[][0-9][]]\(.*\);\1;' -e 's;[^1-9]*\([0-9]*\).*;\1;'`]
+        if test "$gmp_tmp_val" = 4; then
+          gmp_cv_asm_w32="$gmp_tmp_op"
+          break
+        fi])
+    done
+    rm -f conftest*
+    ;;
+esac
+if test -z "$gmp_cv_asm_w32"; then
+  AC_MSG_ERROR([cannot determine how to define a 32-bit word])
+fi
+])
+echo ["define(<W32>, <$gmp_cv_asm_w32>)"] >> $gmp_tmpconfigm4
+])
+
+
+dnl  GMP_X86_ASM_GOT_UNDERSCORE
+dnl  --------------------------
+dnl  Determine whether i386 _GLOBAL_OFFSET_TABLE_ needs an additional
+dnl  underscore prefix.
+dnl
+dnl    SVR4      - the standard is _GLOBAL_OFFSET_TABLE_
+dnl    GNU/Linux - follows SVR4
+dnl    OpenBSD   - an a.out underscore system, uses __GLOBAL_OFFSET_TABLE_
+dnl    NetBSD    - also an a.out underscore system, but _GLOBAL_OFFSET_TABLE_
+dnl
+dnl  The test attempts to link a program using _GLOBAL_OFFSET_TABLE_ or
+dnl  __GLOBAL_OFFSET_TABLE_ to see which works.
+dnl
+dnl  $lt_prog_compiler_pic is included in the compile because old versions
+dnl  of gas wouldn't accept PIC idioms without the right option (-K).  This
+dnl  is the same as what libtool and mpn/Makeasm.am will do.
+dnl
+dnl  $lt_prog_compiler_pic is also included in the link because OpenBSD ld
+dnl  won't accept an R_386_GOTPC relocation without the right options.  This
+dnl  is not what's done by the Makefiles when building executables, but
+dnl  let's hope it's ok (it works fine with gcc).
+dnl
+dnl  The fallback is no additional underscore, on the basis that this will
+dnl  suit SVR4/ELF style systems, which should be much more common than
+dnl  a.out systems with shared libraries.
+dnl
+dnl  Note that it's not an error for the tests to fail, since for instance
+dnl  cygwin, mingw and djgpp don't have a _GLOBAL_OFFSET_TABLE_ scheme at
+dnl  all.
+dnl
+dnl  Perhaps $CCAS could be asked to do the linking as well as the
+dnl  assembling, but in the Makefiles it's only used for assembling, so lets
+dnl  keep it that way.
+dnl
+dnl  The test here is run even under --disable-shared, so that PIC objects
+dnl  can be built and tested by the tune/many.pl development scheme.  The
+dnl  tests will be reasonably quick and won't give a fatal error, so this
+dnl  arrangement is ok.  AC_LIBTOOL_PROG_COMPILER_PIC does its
+dnl  $lt_prog_compiler_pic setups even for --disable-shared too.
+
+AC_DEFUN([GMP_ASM_X86_GOT_UNDERSCORE],
+[AC_REQUIRE([GMP_ASM_TEXT])
+AC_REQUIRE([GMP_ASM_GLOBL])
+AC_REQUIRE([GMP_ASM_GLOBL_ATTR])
+AC_REQUIRE([GMP_ASM_LABEL_SUFFIX])
+AC_REQUIRE([GMP_ASM_UNDERSCORE])
+AC_REQUIRE([AC_LIBTOOL_PROG_COMPILER_PIC])
+AC_CACHE_CHECK([if _GLOBAL_OFFSET_TABLE_ is prefixed by underscore],
+               gmp_cv_asm_x86_got_underscore,
+[gmp_cv_asm_x86_got_underscore="not applicable"
+if test $gmp_cv_asm_underscore = yes; then
+  tmp_gsym_prefix=_
+else
+  tmp_gsym_prefix=
+fi
+for tmp_underscore in "" "_"; do
+  cat >conftest.s <<EOF
+	$gmp_cv_asm_text
+	$gmp_cv_asm_globl ${tmp_gsym_prefix}main$gmp_cv_asm_globl_attr
+${tmp_gsym_prefix}main$gmp_cv_asm_label_suffix
+	addl	$ ${tmp_underscore}_GLOBAL_OFFSET_TABLE_, %ebx
+EOF
+  gmp_compile="$CCAS $CFLAGS $CPPFLAGS $lt_prog_compiler_pic conftest.s >&AC_FD_CC && $CC $CFLAGS $CPPFLAGS $lt_prog_compiler_pic conftest.$OBJEXT >&AC_FD_CC"
+  if AC_TRY_EVAL(gmp_compile); then
+    if test "$tmp_underscore" = "_"; then
+      gmp_cv_asm_x86_got_underscore=yes
+    else
+      gmp_cv_asm_x86_got_underscore=no
+    fi
+    break
+  fi
+done
+rm -f conftest* a.out b.out a.exe a_out.exe
+])
+if test "$gmp_cv_asm_x86_got_underscore" = "yes"; then
+  GMP_DEFINE(GOT_GSYM_PREFIX, [_])
+else
+  GMP_DEFINE(GOT_GSYM_PREFIX, [])
+fi
+])
+
+
+dnl  GMP_ASM_X86_GOT_EAX_OK(CC+CFLAGS, [ACTION-YES] [, ACTION-NO])
+dnl  -------------------------------------------------------------
+dnl  Determine whether _GLOBAL_OFFSET_TABLE_ used with %eax is ok.
+dnl
+dnl  An instruction
+dnl
+dnl          addl  $_GLOBAL_OFFSET_TABLE_, %eax
+dnl
+dnl  is incorrectly assembled by gas 2.12 (or thereabouts) and earlier.  It
+dnl  puts an addend 2 into the R_386_GOTPC relocation, but it should be 1
+dnl  for this %eax form being a 1 byte opcode (with other registers it's 2
+dnl  opcode bytes).  See note about this in mpn/x86/README too.
+dnl
+dnl  We assemble this, surrounded by some unlikely byte sequences as
+dnl  delimiters, and check for the bad output.
+dnl
+dnl  This is for use by compiler probing in GMP_PROG_CC_WORKS, so the result
+dnl  is not cached.
+dnl
+dnl  This test is not specific to gas, but old gas is the only assembler we
+dnl  know of with this problem.  The Solaris has been seen coming out ok.
+dnl
+dnl  ".text" is hard coded because this macro is wanted before GMP_ASM_TEXT.
+dnl  This should be fine, ".text" is normal on x86 systems, and certainly
+dnl  will be fine with the offending gas.
+dnl
+dnl  If an error occurs when assembling, we consider the assembler ok, since
+dnl  the bad output does not occur.  This happens for instance on mingw,
+dnl  where _GLOBAL_OFFSET_TABLE_ results in a bfd error, since there's no
+dnl  GOT etc in PE object files.
+dnl
+dnl  This test is used before the object file extension has been determined,
+dnl  so we force output to conftest.o.  Using -o with -c is not portable,
+dnl  but we think all x86 compilers will accept -o with -c, certainly gcc
+dnl  does.
+dnl
+dnl  -fPIC is hard coded here, because this test is for use before libtool
+dnl  has established the pic options.  It's right for gcc, but perhaps not
+dnl  other compilers.
+
+AC_DEFUN([GMP_ASM_X86_GOT_EAX_OK],
+[echo "Testing gas GOT with eax good" >&AC_FD_CC
+cat >conftest.awk <<\EOF
+[BEGIN {
+  want[0]  = "001"
+  want[1]  = "043"
+  want[2]  = "105"
+  want[3]  = "147"
+  want[4]  = "211"
+  want[5]  = "253"
+  want[6]  = "315"
+  want[7]  = "357"
+
+  want[8]  = "005"
+  want[9]  = "002"
+  want[10] = "000"
+  want[11] = "000"
+  want[12] = "000"
+
+  want[13] = "376"
+  want[14] = "334"
+  want[15] = "272"
+  want[16] = "230"
+  want[17] = "166"
+  want[18] = "124"
+  want[19] = "062"
+  want[20] = "020"
+
+  result = "yes"
+}
+{
+  for (f = 2; f <= NF; f++)
+    {
+      for (i = 0; i < 20; i++)
+        got[i] = got[i+1];
+      got[20] = $f;
+
+      found = 1
+      for (i = 0; i < 21; i++)
+        if (got[i] != want[i])
+          {
+            found = 0
+            break
+          }
+      if (found)
+        {
+          result = "no"
+          exit
+        }
+    }
+}
+END {
+  print result
+}
+]EOF
+cat >conftest.s <<\EOF
+[	.text
+	.byte	1, 35, 69, 103, 137, 171, 205, 239
+	addl	$_GLOBAL_OFFSET_TABLE_, %eax
+	.byte	254, 220, 186, 152, 118, 84, 50, 16
+]EOF
+tmp_got_good=yes
+gmp_compile="$1 -fPIC -o conftest.o -c conftest.s >&AC_FD_CC 2>&1"
+if AC_TRY_EVAL(gmp_compile); then
+  tmp_got_good=`od -b conftest.o | $AWK -f conftest.awk`
+fi
+rm -f conftest.*
+echo "Result: $tmp_got_good" >&AC_FD_CC
+if test "$tmp_got_good" = no; then
+  ifelse([$3],,:,[$3])
+else
+  ifelse([$2],,:,[$2])
+fi
+])
+
+
+dnl  GMP_ASM_X86_MMX([ACTION-IF-YES][,ACTION-IF-NO])
+dnl  -----------------------------------------------
+dnl  Determine whether the assembler supports MMX instructions.
+dnl
+dnl  This macro is wanted before GMP_ASM_TEXT, so ".text" is hard coded
+dnl  here.  ".text" is believed to be correct on all x86 systems.  Actually
+dnl  ".text" probably isn't needed at all, at least for just checking
+dnl  instruction syntax.
+dnl
+dnl  "movq %mm0, %mm1" should assemble to "0f 6f c8", but Solaris 2.6 and
+dnl  2.7 wrongly assemble it to "0f 6f c1" (that being the reverse "movq
+dnl  %mm1, %mm0").  It seems more trouble than it's worth to work around
+dnl  this in the code, so just detect and reject.
+
+AC_DEFUN([GMP_ASM_X86_MMX],
+[AC_CACHE_CHECK([if the assembler knows about MMX instructions],
+		gmp_cv_asm_x86_mmx,
+[GMP_TRY_ASSEMBLE(
+[	.text
+	movq	%mm0, %mm1],
+[gmp_cv_asm_x86_mmx=yes
+case $host in
+*-*-solaris*)
+  if (dis conftest.$OBJEXT >conftest.out) 2>/dev/null; then
+    if grep "0f 6f c1" conftest.out >/dev/null; then
+      gmp_cv_asm_x86_mmx=movq-bug
+    fi
+  else
+    AC_MSG_WARN(["dis" not available to check for "as" movq bug])
+  fi
+esac],
+[gmp_cv_asm_x86_mmx=no])])
+
+case $gmp_cv_asm_x86_mmx in
+movq-bug)
+  AC_MSG_WARN([+----------------------------------------------------------])
+  AC_MSG_WARN([| WARNING WARNING WARNING])
+  AC_MSG_WARN([| Host CPU has MMX code, but the assembler])
+  AC_MSG_WARN([|     $CCAS $CFLAGS $CPPFLAGS])
+  AC_MSG_WARN([| has the Solaris 2.6 and 2.7 bug where register to register])
+  AC_MSG_WARN([| movq operands are reversed.])
+  AC_MSG_WARN([| Non-MMX replacements will be used.])
+  AC_MSG_WARN([| This will be an inferior build.])
+  AC_MSG_WARN([+----------------------------------------------------------])
+  ;;
+no)
+  AC_MSG_WARN([+----------------------------------------------------------])
+  AC_MSG_WARN([| WARNING WARNING WARNING])
+  AC_MSG_WARN([| Host CPU has MMX code, but it can't be assembled by])
+  AC_MSG_WARN([|     $CCAS $CFLAGS $CPPFLAGS])
+  AC_MSG_WARN([| Non-MMX replacements will be used.])
+  AC_MSG_WARN([| This will be an inferior build.])
+  AC_MSG_WARN([+----------------------------------------------------------])
+  ;;
+esac
+if test "$gmp_cv_asm_x86_mmx" = yes; then
+  ifelse([$1],,:,[$1])
+else
+  ifelse([$2],,:,[$2])
+fi
+])
+
+
+dnl  GMP_ASM_X86_SHLDL_CL
+dnl  --------------------
+
+AC_DEFUN([GMP_ASM_X86_SHLDL_CL],
+[AC_REQUIRE([GMP_ASM_TEXT])
+AC_CACHE_CHECK([if the assembler takes cl with shldl],
+		gmp_cv_asm_x86_shldl_cl,
+[GMP_TRY_ASSEMBLE(
+[	$gmp_cv_asm_text
+	shldl	%cl, %eax, %ebx],
+  gmp_cv_asm_x86_shldl_cl=yes,
+  gmp_cv_asm_x86_shldl_cl=no)
+])
+if test "$gmp_cv_asm_x86_shldl_cl" = "yes"; then
+  GMP_DEFINE(WANT_SHLDL_CL,1)
+else
+  GMP_DEFINE(WANT_SHLDL_CL,0)
+fi
+])
+
+
+dnl  GMP_ASM_X86_SSE2([ACTION-IF-YES][,ACTION-IF-NO])
+dnl  ------------------------------------------------
+dnl  Determine whether the assembler supports SSE2 instructions.
+dnl
+dnl  This macro is wanted before GMP_ASM_TEXT, so ".text" is hard coded
+dnl  here.  ".text" is believed to be correct on all x86 systems, certainly
+dnl  it's all GMP_ASM_TEXT gives currently.  Actually ".text" probably isn't
+dnl  needed at all, at least for just checking instruction syntax.
+
+AC_DEFUN([GMP_ASM_X86_SSE2],
+[AC_CACHE_CHECK([if the assembler knows about SSE2 instructions],
+		gmp_cv_asm_x86_sse2,
+[GMP_TRY_ASSEMBLE(
+[	.text
+	paddq	%mm0, %mm1],
+  [gmp_cv_asm_x86_sse2=yes],
+  [gmp_cv_asm_x86_sse2=no])
+])
+case $gmp_cv_asm_x86_sse2 in
+yes)
+  ifelse([$1],,:,[$1])
+  ;;
+*)
+  AC_MSG_WARN([+----------------------------------------------------------])
+  AC_MSG_WARN([| WARNING WARNING WARNING])
+  AC_MSG_WARN([| Host CPU has SSE2 code, but it can't be assembled by])
+  AC_MSG_WARN([|     $CCAS $CFLAGS $CPPFLAGS])
+  AC_MSG_WARN([| Non-SSE2 replacements will be used.])
+  AC_MSG_WARN([| This will be an inferior build.])
+  AC_MSG_WARN([+----------------------------------------------------------])
+  ifelse([$2],,:,[$2])
+  ;;
+esac
+])
+
+
+dnl  GMP_ASM_X86_MULX([ACTION-IF-YES][,ACTION-IF-NO])
+dnl  ------------------------------------------------
+dnl  Determine whether the assembler supports the mulx instruction which debut
+dnl  with Haswell.
+dnl
+dnl  This macro is wanted before GMP_ASM_TEXT, so ".text" is hard coded
+dnl  here.  ".text" is believed to be correct on all x86 systems, certainly
+dnl  it's all GMP_ASM_TEXT gives currently.  Actually ".text" probably isn't
+dnl  needed at all, at least for just checking instruction syntax.
+
+AC_DEFUN([GMP_ASM_X86_MULX],
+[AC_CACHE_CHECK([if the assembler knows about the mulx instruction],
+		gmp_cv_asm_x86_mulx,
+[GMP_TRY_ASSEMBLE(
+[	.text
+	mulx	%r8, %r9, %r10],
+  [gmp_cv_asm_x86_mulx=yes],
+  [gmp_cv_asm_x86_mulx=no])
+])
+case $gmp_cv_asm_x86_mulx in
+yes)
+  AC_DEFINE(X86_ASM_MULX, 1,
+  [Define to 1 if the assembler understands the mulx instruction])
+  ifelse([$1],,:,[$1])
+  ;;
+*)
+  AC_MSG_WARN([+----------------------------------------------------------])
+  AC_MSG_WARN([| WARNING WARNING WARNING])
+  AC_MSG_WARN([| Host CPU has the mulx instruction, but it can't be])
+  AC_MSG_WARN([| assembled by])
+  AC_MSG_WARN([|     $CCAS $CFLAGS $CPPFLAGS])
+  AC_MSG_WARN([| Older x86 instructions will be used.])
+  AC_MSG_WARN([| This will be an inferior build.])
+  AC_MSG_WARN([+----------------------------------------------------------])
+  ifelse([$2],,:,[$2])
+  ;;
+esac
+])
+
+
+dnl  GMP_ASM_X86_MCOUNT
+dnl  ------------------
+dnl  Find out how to call mcount for profiling on an x86 system.
+dnl
+dnl  A dummy function is compiled and the ".s" output examined.  The pattern
+dnl  matching might be a bit fragile, but should work at least with gcc on
+dnl  sensible systems.  Certainly it's better than hard coding a table of
+dnl  conventions.
+dnl
+dnl  For non-PIC, any ".data" is taken to mean a counter might be passed.
+dnl  It's assumed a movl will set it up, and the right register is taken
+dnl  from that movl.  Any movl involving %esp is ignored (a frame pointer
+dnl  setup normally).
+dnl
+dnl  For PIC, any ".data" is similarly interpreted, but a GOTOFF identifies
+dnl  the line setting up the right register.
+dnl
+dnl  In both cases a line with "mcount" identifies the call and that line is
+dnl  used literally.
+dnl
+dnl  On some systems (eg. FreeBSD 3.5) gcc emits ".data" but doesn't use it,
+dnl  so it's not an error to have .data but then not find a register.
+dnl
+dnl  Variations in mcount conventions on different x86 systems can be found
+dnl  in gcc config/i386.  mcount can have a "_" prefix or be .mcount or
+dnl  _mcount_ptr, and for PIC it can be called through a GOT entry, or via
+dnl  the PLT.  If a pointer to a counter is required it's passed in %eax or
+dnl  %edx.
+dnl
+dnl  Flags to specify PIC are taken from $lt_prog_compiler_pic set by
+dnl  AC_PROG_LIBTOOL.
+dnl
+dnl  Enhancement: Cache the values determined here. But what's the right way
+dnl  to get two variables (mcount_nonpic_reg and mcount_nonpic_call say) set
+dnl  from one block of commands?
+
+AC_DEFUN([GMP_ASM_X86_MCOUNT],
+[AC_REQUIRE([AC_ENABLE_SHARED])
+AC_REQUIRE([AC_PROG_LIBTOOL])
+AC_MSG_CHECKING([how to call x86 mcount])
+cat >conftest.c <<EOF
+foo(){bar();}
+EOF
+
+if test "$enable_static" = yes; then
+  gmp_asmout_compile="$CC $CFLAGS $CPPFLAGS -S conftest.c 1>&AC_FD_CC"
+  if AC_TRY_EVAL(gmp_asmout_compile); then
+    if grep '\.data' conftest.s >/dev/null; then
+      mcount_nonpic_reg=`sed -n ['/esp/!s/.*movl.*,\(%[a-z]*\).*$/\1/p'] conftest.s`
+    else
+      mcount_nonpic_reg=
+    fi
+    mcount_nonpic_call=`grep 'call.*mcount' conftest.s`
+    if test -z "$mcount_nonpic_call"; then
+      AC_MSG_ERROR([Cannot find mcount call for non-PIC])
+    fi
+  else
+    AC_MSG_ERROR([Cannot compile test program for non-PIC])
+  fi
+fi
+
+if test "$enable_shared" = yes; then
+  gmp_asmout_compile="$CC $CFLAGS $CPPFLAGS $lt_prog_compiler_pic -S conftest.c 1>&AC_FD_CC"
+  if AC_TRY_EVAL(gmp_asmout_compile); then
+    if grep '\.data' conftest.s >/dev/null; then
+      case $lt_prog_compiler_pic in
+        *-DDLL_EXPORT*)
+          # Windows DLLs have non-PIC style mcount
+          mcount_pic_reg=`sed -n ['/esp/!s/.*movl.*,\(%[a-z]*\).*$/\1/p'] conftest.s`
+          ;;
+        *)
+          mcount_pic_reg=`sed -n ['s/.*GOTOFF.*,\(%[a-z]*\).*$/\1/p'] conftest.s`
+          ;;
+      esac
+    else
+      mcount_pic_reg=
+    fi
+    mcount_pic_call=`grep 'call.*mcount' conftest.s`
+    if test -z "$mcount_pic_call"; then
+      AC_MSG_ERROR([Cannot find mcount call for PIC])
+    fi
+  else
+    AC_MSG_ERROR([Cannot compile test program for PIC])
+  fi
+fi
+
+GMP_DEFINE_RAW(["define(<MCOUNT_NONPIC_REG>, <\`$mcount_nonpic_reg'>)"])
+GMP_DEFINE_RAW(["define(<MCOUNT_NONPIC_CALL>,<\`$mcount_nonpic_call'>)"])
+GMP_DEFINE_RAW(["define(<MCOUNT_PIC_REG>,    <\`$mcount_pic_reg'>)"])
+GMP_DEFINE_RAW(["define(<MCOUNT_PIC_CALL>,   <\`$mcount_pic_call'>)"])
+
+rm -f conftest.*
+AC_MSG_RESULT([determined])
+])
+
+
+dnl  GMP_ASM_IA64_ALIGN_OK
+dnl  ---------------------
+dnl  Determine whether .align correctly pads with nop instructions in a text
+dnl  segment.
+dnl
+dnl  gas 2.14 and earlier byte swaps its padding bundle on big endian
+dnl  systems, which is incorrect (endianness only changes data).  What
+dnl  should be "nop.m / nop.f / nop.i" comes out as "break" instructions.
+dnl
+dnl  The test here detects the bad case, and assumes anything else is ok
+dnl  (there are many sensible nop bundles, so it'd be impractical to try to
+dnl  match everything good).
+
+AC_DEFUN([GMP_ASM_IA64_ALIGN_OK],
+[AC_CACHE_CHECK([whether assembler .align padding is good],
+		gmp_cv_asm_ia64_align_ok,
+[cat >conftest.awk <<\EOF
+[BEGIN {
+  want[0]  = "011"
+  want[1]  = "160"
+  want[2]  = "074"
+  want[3]  = "040"
+  want[4]  = "000"
+  want[5]  = "040"
+  want[6]  = "020"
+  want[7]  = "221"
+  want[8]  = "114"
+  want[9]  = "000"
+  want[10] = "100"
+  want[11] = "200"
+  want[12] = "122"
+  want[13] = "261"
+  want[14] = "000"
+  want[15] = "200"
+
+  want[16] = "000"
+  want[17] = "004"
+  want[18] = "000"
+  want[19] = "000"
+  want[20] = "000"
+  want[21] = "000"
+  want[22] = "002"
+  want[23] = "000"
+  want[24] = "000"
+  want[25] = "000"
+  want[26] = "000"
+  want[27] = "001"
+  want[28] = "000"
+  want[29] = "000"
+  want[30] = "000"
+  want[31] = "014"
+
+  want[32] = "011"
+  want[33] = "270"
+  want[34] = "140"
+  want[35] = "062"
+  want[36] = "000"
+  want[37] = "040"
+  want[38] = "240"
+  want[39] = "331"
+  want[40] = "160"
+  want[41] = "000"
+  want[42] = "100"
+  want[43] = "240"
+  want[44] = "343"
+  want[45] = "371"
+  want[46] = "000"
+  want[47] = "200"
+
+  result = "yes"
+}
+{
+  for (f = 2; f <= NF; f++)
+    {
+      for (i = 0; i < 47; i++)
+        got[i] = got[i+1];
+      got[47] = $f;
+
+      found = 1
+      for (i = 0; i < 48; i++)
+        if (got[i] != want[i])
+          {
+            found = 0
+            break
+          }
+      if (found)
+        {
+          result = "no"
+          exit
+        }
+    }
+}
+END {
+  print result
+}
+]EOF
+GMP_TRY_ASSEMBLE(
+[	.text
+	.align	32
+{ .mmi;	add	r14 = r15, r16
+	add	r17 = r18, r19
+	add	r20 = r21, r22 ;; }
+	.align	32
+{ .mmi;	add	r23 = r24, r25
+	add	r26 = r27, r28
+	add	r29 = r30, r31 ;; }
+],
+  [gmp_cv_asm_ia64_align_ok=`od -b conftest.$OBJEXT | $AWK -f conftest.awk`],
+  [AC_MSG_WARN([oops, cannot compile test program])
+   gmp_cv_asm_ia64_align_ok=yes])
+])
+GMP_DEFINE_RAW(["define(<IA64_ALIGN_OK>, <\`$gmp_cv_asm_ia64_align_ok'>)"])
+])
+
+
+
+
+dnl  GMP_ASM_M68K_INSTRUCTION
+dnl  ------------------------
+dnl  Not sure if ".l" and "%" are independent settings, but it doesn't hurt
+dnl  to try all four possibilities.  Note that the % ones must be first, so
+dnl  "d0" won't be interpreted as a label.
+dnl
+dnl  gas 1.92.3 on NetBSD 1.4 needs to be tested with a two operand
+dnl  instruction.  It takes registers without "%", but a single operand
+dnl  "clrl %d0" only gives a warning, not an error.
+
+AC_DEFUN([GMP_ASM_M68K_INSTRUCTION],
+[AC_REQUIRE([GMP_ASM_TEXT])
+AC_CACHE_CHECK([assembler instruction and register style],
+		gmp_cv_asm_m68k_instruction,
+[for i in "addl %d0,%d1" "add.l %d0,%d1" "addl d0,d1" "add.l d0,d1"; do
+  GMP_TRY_ASSEMBLE(
+    [	$gmp_cv_asm_text
+	$i],
+    [gmp_cv_asm_m68k_instruction=$i
+    rm -f conftest*
+    break])
+done
+if test -z "$gmp_cv_asm_m68k_instruction"; then
+  AC_MSG_ERROR([cannot determine assembler instruction and register style])
+fi
+])
+case $gmp_cv_asm_m68k_instruction in
+"addl d0,d1")    want_dot_size=no;  want_register_percent=no  ;;
+"addl %d0,%d1")  want_dot_size=no;  want_register_percent=yes ;;
+"add.l d0,d1")   want_dot_size=yes; want_register_percent=no  ;;
+"add.l %d0,%d1") want_dot_size=yes; want_register_percent=yes ;;
+*) AC_MSG_ERROR([oops, unrecognised instruction and register style]) ;;
+esac
+GMP_DEFINE_RAW(["define(<WANT_REGISTER_PERCENT>, <\`$want_register_percent'>)"])
+GMP_DEFINE_RAW(["define(<WANT_DOT_SIZE>, <\`$want_dot_size'>)"])
+])
+
+
+dnl  GMP_ASM_M68K_ADDRESSING
+dnl  -----------------------
+
+AC_DEFUN([GMP_ASM_M68K_ADDRESSING],
+[AC_REQUIRE([GMP_ASM_TEXT])
+AC_REQUIRE([GMP_ASM_M68K_INSTRUCTION])
+AC_CACHE_CHECK([assembler addressing style],
+		gmp_cv_asm_m68k_addressing,
+[case $gmp_cv_asm_m68k_instruction in
+addl*)  movel=movel ;;
+add.l*) movel=move.l ;;
+*) AC_MSG_ERROR([oops, unrecognised gmp_cv_asm_m68k_instruction]) ;;
+esac
+case $gmp_cv_asm_m68k_instruction in
+*"%d0,%d1") dreg=%d0; areg=%a0 ;;
+*"d0,d1")   dreg=d0;  areg=a0  ;;
+*) AC_MSG_ERROR([oops, unrecognised gmp_cv_asm_m68k_instruction]) ;;
+esac
+GMP_TRY_ASSEMBLE(
+[	$gmp_cv_asm_text
+	$movel	$dreg, $areg@-],
+  [gmp_cv_asm_m68k_addressing=mit],
+[GMP_TRY_ASSEMBLE(
+[	$gmp_cv_asm_text
+	$movel	$dreg, -($areg)],
+  [gmp_cv_asm_m68k_addressing=motorola],
+[AC_MSG_ERROR([cannot determine assembler addressing style])])])
+])
+GMP_DEFINE_RAW(["define(<WANT_ADDRESSING>, <\`$gmp_cv_asm_m68k_addressing'>)"])
+])
+
+
+dnl  GMP_ASM_M68K_BRANCHES
+dnl  ---------------------
+dnl  "bra" is the standard branch instruction.  "jra" or "jbra" are
+dnl  preferred where available, since on gas for instance they give a
+dnl  displacement only as big as it needs to be, whereas "bra" is always
+dnl  16-bits.  This applies to the conditional branches "bcc" etc too.
+dnl  However "dbcc" etc on gas are already only as big as they need to be.
+
+AC_DEFUN([GMP_ASM_M68K_BRANCHES],
+[AC_REQUIRE([GMP_ASM_TEXT])
+AC_CACHE_CHECK([assembler shortest branches],
+		gmp_cv_asm_m68k_branches,
+[for i in jra jbra bra; do
+  GMP_TRY_ASSEMBLE(
+[	$gmp_cv_asm_text
+foo$gmp_cv_asm_label_suffix
+	$i	foo],
+  [gmp_cv_asm_m68k_branches=$i
+  rm -f conftest*
+  break])
+done
+if test -z "$gmp_cv_asm_m68k_branches"; then
+  AC_MSG_ERROR([cannot determine assembler branching style])
+fi
+])
+GMP_DEFINE_RAW(["define(<WANT_BRANCHES>, <\`$gmp_cv_asm_m68k_branches'>)"])
+])
+
+
+dnl  GMP_ASM_POWERPC_PIC_ALWAYS
+dnl  --------------------------
+dnl  Determine whether PIC is the default compiler output.
+dnl
+dnl  SVR4 style "foo@ha" addressing is interpreted as non-PIC, and anything
+dnl  else is assumed to require PIC always (Darwin or AIX).  SVR4 is the
+dnl  only non-PIC addressing syntax the asm files have at the moment anyway.
+dnl
+dnl  Libtool does this by taking "*-*-aix* | *-*-darwin* | *-*-rhapsody*" to
+dnl  mean PIC always, but it seems more reliable to grep the compiler
+dnl  output.
+dnl
+dnl The next paragraph is untrue for Tiger.  Was it ever true?  For tiger,
+dnl "cc -fast" makes non-PIC the default (and the binaries do run).
+dnl  On Darwin "cc -static" is non-PIC with syntax "ha16(_foo)", but that's
+dnl  apparently only for use in the kernel, which we're not attempting to
+dnl  target at the moment, so don't look for that.
+
+AC_DEFUN([GMP_ASM_POWERPC_PIC_ALWAYS],
+[AC_REQUIRE([AC_PROG_CC])
+AC_CACHE_CHECK([whether compiler output is PIC by default],
+               gmp_cv_asm_powerpc_pic,
+[gmp_cv_asm_powerpc_pic=yes
+cat >conftest.c <<EOF
+int foo;
+int *bar() { return &foo; }
+EOF
+echo "Test program:" >&AC_FD_CC
+cat conftest.c >&AC_FD_CC
+gmp_compile="$CC $CFLAGS $CPPFLAGS -S conftest.c >&AC_FD_CC"
+if AC_TRY_EVAL(gmp_compile); then
+  echo "Compiler output:" >&AC_FD_CC
+  cat conftest.s >&AC_FD_CC
+  if grep 'foo@ha' conftest.s >/dev/null 2>&AC_FD_CC; then
+    gmp_cv_asm_powerpc_pic=no
+  fi
+  if grep 'ha16(_foo)' conftest.s >/dev/null 2>&AC_FD_CC; then
+    gmp_cv_asm_powerpc_pic=no
+  fi
+fi
+rm -f conftest*
+])
+GMP_DEFINE_RAW(["define(<PIC_ALWAYS>,<$gmp_cv_asm_powerpc_pic>)"])
+])
+
+
+dnl  GMP_ASM_POWERPC_R_REGISTERS
+dnl  ---------------------------
+dnl  Determine whether the assembler takes powerpc registers with an "r" as
+dnl  in "r6", or as plain "6".  The latter is standard, but NeXT, Rhapsody,
+dnl  and MacOS-X require the "r" forms.
+dnl
+dnl  See also mpn/powerpc32/powerpc-defs.m4 which uses the result of this
+dnl  test.
+
+AC_DEFUN([GMP_ASM_POWERPC_R_REGISTERS],
+[AC_REQUIRE([GMP_ASM_TEXT])
+AC_CACHE_CHECK([if the assembler needs r on registers],
+               gmp_cv_asm_powerpc_r_registers,
+[GMP_TRY_ASSEMBLE(
+[	$gmp_cv_asm_text
+	mtctr	6],
+[gmp_cv_asm_powerpc_r_registers=no],
+[GMP_TRY_ASSEMBLE(
+[	$gmp_cv_asm_text
+	mtctr	r6],
+[gmp_cv_asm_powerpc_r_registers=yes],
+[AC_MSG_ERROR([neither "mtctr 6" nor "mtctr r6" works])])])])
+
+GMP_DEFINE_RAW(["define(<WANT_R_REGISTERS>,<$gmp_cv_asm_powerpc_r_registers>)"])
+])
+
+
+dnl  GMP_ASM_SPARC_REGISTER
+dnl  ----------------------
+dnl  Determine whether the assembler accepts the ".register" directive.
+dnl  Old versions of solaris "as" don't.
+dnl
+dnl  See also mpn/sparc32/sparc-defs.m4 which uses the result of this test.
+
+AC_DEFUN([GMP_ASM_SPARC_REGISTER],
+[AC_REQUIRE([GMP_ASM_TEXT])
+AC_CACHE_CHECK([if the assembler accepts ".register"],
+               gmp_cv_asm_sparc_register,
+[GMP_TRY_ASSEMBLE(
+[	$gmp_cv_asm_text
+	.register	%g2,#scratch
+],
+[gmp_cv_asm_sparc_register=yes],
+[gmp_cv_asm_sparc_register=no])])
+
+GMP_DEFINE_RAW(["define(<HAVE_REGISTER>,<$gmp_cv_asm_sparc_register>)"])
+])
+
+
+dnl  GMP_ASM_SPARC_GOTDATA
+dnl  ----------------------
+dnl  Determine whether the assembler accepts gotdata relocations.
+dnl
+dnl  See also mpn/sparc32/sparc-defs.m4 which uses the result of this test.
+
+AC_DEFUN([GMP_ASM_SPARC_GOTDATA],
+[AC_REQUIRE([GMP_ASM_TEXT])
+AC_CACHE_CHECK([if the assembler accepts gotdata relocations],
+               gmp_cv_asm_sparc_gotdata,
+[GMP_TRY_ASSEMBLE(
+[	$gmp_cv_asm_text
+	.text
+	sethi	%gdop_hix22(symbol), %g1
+	or	%g1, %gdop_lox10(symbol), %g1
+],
+[gmp_cv_asm_sparc_gotdata=yes],
+[gmp_cv_asm_sparc_gotdata=no])])
+
+GMP_DEFINE_RAW(["define(<HAVE_GOTDATA>,<$gmp_cv_asm_sparc_gotdata>)"])
+])
+
+
+dnl  GMP_ASM_SPARC_SHARED_THUNKS
+dnl  ----------------------
+dnl  Determine whether the assembler supports all of the features
+dnl  necessary in order to emit shared PIC thunks on sparc.
+dnl
+dnl  See also mpn/sparc32/sparc-defs.m4 which uses the result of this test.
+
+AC_DEFUN([GMP_ASM_SPARC_SHARED_THUNKS],
+[AC_REQUIRE([GMP_ASM_TEXT])
+AC_CACHE_CHECK([if the assembler can support shared PIC thunks],
+               gmp_cv_asm_sparc_shared_thunks,
+[GMP_TRY_ASSEMBLE(
+[	$gmp_cv_asm_text
+	.section	.text.__sparc_get_pc_thunk.l7,"axG",@progbits,__sparc_get_pc_thunk.l7,comdat
+	.weak	__sparc_get_pc_thunk.l7
+	.hidden	__sparc_get_pc_thunk.l7
+	.type	__sparc_get_pc_thunk.l7, #function
+__sparc_get_pc_thunk.l7:
+	jmp	%o7+8
+	 add	%o7, %l7, %l7
+],
+[gmp_cv_asm_sparc_shared_thunks=yes],
+[gmp_cv_asm_sparc_shared_thunks=no])])
+
+GMP_DEFINE_RAW(["define(<HAVE_SHARED_THUNKS>,<$gmp_cv_asm_sparc_shared_thunks>)"])
+])
+
+
+dnl  GMP_C_ATTRIBUTE_CONST
+dnl  ---------------------
+
+AC_DEFUN([GMP_C_ATTRIBUTE_CONST],
+[AC_CACHE_CHECK([whether gcc __attribute__ ((const)) works],
+                gmp_cv_c_attribute_const,
+[AC_TRY_COMPILE([int foo (int x) __attribute__ ((const));], ,
+  gmp_cv_c_attribute_const=yes, gmp_cv_c_attribute_const=no)
+])
+if test $gmp_cv_c_attribute_const = yes; then
+  AC_DEFINE(HAVE_ATTRIBUTE_CONST, 1,
+  [Define to 1 if the compiler accepts gcc style __attribute__ ((const))])
+fi
+])
+
+
+dnl  GMP_C_ATTRIBUTE_MALLOC
+dnl  ----------------------
+dnl  gcc 2.95.x accepts __attribute__ ((malloc)) but with a warning that
+dnl  it's ignored.  Pretend it doesn't exist in this case, to avoid that
+dnl  warning.
+
+AC_DEFUN([GMP_C_ATTRIBUTE_MALLOC],
+[AC_CACHE_CHECK([whether gcc __attribute__ ((malloc)) works],
+                gmp_cv_c_attribute_malloc,
+[cat >conftest.c <<EOF
+void *foo (int x) __attribute__ ((malloc));
+EOF
+gmp_compile="$CC $CFLAGS $CPPFLAGS -c conftest.c >conftest.out 2>&1"
+if AC_TRY_EVAL(gmp_compile); then
+  if grep "attribute directive ignored" conftest.out >/dev/null; then
+    gmp_cv_c_attribute_malloc=no
+  else
+    gmp_cv_c_attribute_malloc=yes
+  fi
+else
+  gmp_cv_c_attribute_malloc=no
+fi
+cat conftest.out >&AC_FD_CC
+rm -f conftest*
+])
+if test $gmp_cv_c_attribute_malloc = yes; then
+  AC_DEFINE(HAVE_ATTRIBUTE_MALLOC, 1,
+  [Define to 1 if the compiler accepts gcc style __attribute__ ((malloc))])
+fi
+])
+
+
+dnl  GMP_C_ATTRIBUTE_MODE
+dnl  --------------------
+dnl  Introduced in gcc 2.2, but perhaps not in all Apple derived versions.
+
+AC_DEFUN([GMP_C_ATTRIBUTE_MODE],
+[AC_CACHE_CHECK([whether gcc __attribute__ ((mode (XX))) works],
+                gmp_cv_c_attribute_mode,
+[AC_TRY_COMPILE([typedef int SItype __attribute__ ((mode (SI)));], ,
+  gmp_cv_c_attribute_mode=yes, gmp_cv_c_attribute_mode=no)
+])
+if test $gmp_cv_c_attribute_mode = yes; then
+  AC_DEFINE(HAVE_ATTRIBUTE_MODE, 1,
+  [Define to 1 if the compiler accepts gcc style __attribute__ ((mode (XX)))])
+fi
+])
+
+
+dnl  GMP_C_ATTRIBUTE_NORETURN
+dnl  ------------------------
+
+AC_DEFUN([GMP_C_ATTRIBUTE_NORETURN],
+[AC_CACHE_CHECK([whether gcc __attribute__ ((noreturn)) works],
+                gmp_cv_c_attribute_noreturn,
+[AC_TRY_COMPILE([void foo (int x) __attribute__ ((noreturn));], ,
+  gmp_cv_c_attribute_noreturn=yes, gmp_cv_c_attribute_noreturn=no)
+])
+if test $gmp_cv_c_attribute_noreturn = yes; then
+  AC_DEFINE(HAVE_ATTRIBUTE_NORETURN, 1,
+  [Define to 1 if the compiler accepts gcc style __attribute__ ((noreturn))])
+fi
+])
+
+dnl  GMP_C_HIDDEN_ALIAS
+dnl  ------------------------
+
+AC_DEFUN([GMP_C_HIDDEN_ALIAS],
+[AC_CACHE_CHECK([whether gcc hidden aliases work],
+                gmp_cv_c_hidden_alias,
+[AC_TRY_COMPILE(
+[void hid() __attribute__ ((visibility("hidden")));
+void hid() {}
+void pub() __attribute__ ((alias("hid")));],
+, gmp_cv_c_hidden_alias=yes, gmp_cv_c_hidden_alias=no)
+])
+if test $gmp_cv_c_hidden_alias = yes; then
+  AC_DEFINE(HAVE_HIDDEN_ALIAS, 1,
+  [Define to 1 if the compiler accepts gcc style __attribute__ ((visibility))
+and __attribute__ ((alias))])
+fi
+])
+
+dnl  GMP_C_DOUBLE_FORMAT
+dnl  -------------------
+dnl  Determine the floating point format.
+dnl
+dnl  The object file is grepped, in order to work when cross compiling.  A
+dnl  start and end sequence is included to avoid false matches, and allowance
+dnl  is made for the desired data crossing an "od -b" line boundary.  The test
+dnl  number is a small integer so it should appear exactly, no rounding or
+dnl  truncation etc.
+dnl
+dnl  "od -b", incidentally, is supported even by Unix V7, and the awk script
+dnl  used doesn't have functions or anything, so even an "old" awk should
+dnl  suffice.
+dnl
+dnl  The C code here declares the variable foo as extern; without that, some
+dnl  C++ compilers will not put foo in the object file.
+
+AC_DEFUN([GMP_C_DOUBLE_FORMAT],
+[AC_REQUIRE([AC_PROG_CC])
+AC_REQUIRE([AC_PROG_AWK])
+AC_CACHE_CHECK([format of `double' floating point],
+                gmp_cv_c_double_format,
+[gmp_cv_c_double_format=unknown
+cat >conftest.c <<\EOF
+[#include <stdio.h>
+struct foo {
+  char    before[8];
+  double  x;
+  char    after[8];
+};
+extern struct foo foo;
+struct foo foo = {
+  { '\001', '\043', '\105', '\147', '\211', '\253', '\315', '\357' },
+  -123456789.0,
+  { '\376', '\334', '\272', '\230', '\166', '\124', '\062', '\020' },
+};
+int main(){
+  int i;
+  for (i = 0; i < 8; i++) {
+    printf ("%d %f\n", foo.before[i] + foo.after[i], foo.x);
+  }
+  return 0;
+}]
+EOF
+gmp_compile="$CC $CFLAGS $CPPFLAGS conftest.c -o conftest$EXEEXT >&AC_FD_CC 2>&1"
+if AC_TRY_EVAL(gmp_compile); then
+cat >conftest.awk <<\EOF
+[
+BEGIN {
+  found = 0
+}
+
+{
+  for (f = 2; f <= NF; f++)
+    {
+      for (i = 0; i < 23; i++)
+        got[i] = got[i+1];
+      got[23] = $f;
+
+      # match the special begin and end sequences
+      if (got[0] != "001") continue
+      if (got[1] != "043") continue
+      if (got[2] != "105") continue
+      if (got[3] != "147") continue
+      if (got[4] != "211") continue
+      if (got[5] != "253") continue
+      if (got[6] != "315") continue
+      if (got[7] != "357") continue
+      if (got[16] != "376") continue
+      if (got[17] != "334") continue
+      if (got[18] != "272") continue
+      if (got[19] != "230") continue
+      if (got[20] != "166") continue
+      if (got[21] != "124") continue
+      if (got[22] != "062") continue
+      if (got[23] != "020") continue
+
+      saw = " (" got[8] " " got[9] " " got[10] " " got[11] " " got[12] " " got[13] " " got[14] " " got[15] ")"
+
+      if (got[8]  == "000" &&  \
+          got[9]  == "000" &&  \
+          got[10] == "000" &&  \
+          got[11] == "124" &&  \
+          got[12] == "064" &&  \
+          got[13] == "157" &&  \
+          got[14] == "235" &&  \
+          got[15] == "301")
+        {
+          print "IEEE little endian"
+          found = 1
+          exit
+        }
+
+      # Little endian with the two 4-byte halves swapped, as used by ARM
+      # when the chip is in little endian mode.
+      #
+      if (got[8]  == "064" &&  \
+          got[9]  == "157" &&  \
+          got[10] == "235" &&  \
+          got[11] == "301" &&  \
+          got[12] == "000" &&  \
+          got[13] == "000" &&  \
+          got[14] == "000" &&  \
+          got[15] == "124")
+        {
+          print "IEEE little endian, swapped halves"
+          found = 1
+          exit
+        }
+
+      # gcc 2.95.4 on one GNU/Linux ARM system was seen generating 000 in
+      # the last byte, whereas 124 is correct.  Not sure where the bug
+      # actually lies, but a running program didn't seem to get a full
+      # mantissa worth of working bits.
+      #
+      # We match this case explicitly so we can give a nice result message,
+      # but we deliberately exclude it from the normal IEEE double setups
+      # since it's too broken.
+      #
+      if (got[8]  == "064" &&  \
+          got[9]  == "157" &&  \
+          got[10] == "235" &&  \
+          got[11] == "301" &&  \
+          got[12] == "000" &&  \
+          got[13] == "000" &&  \
+          got[14] == "000" &&  \
+          got[15] == "000")
+        {
+          print "bad ARM software floats"
+          found = 1
+          exit
+        }
+
+      if (got[8]  == "301" &&  \
+          got[9]  == "235" &&  \
+          got[10] == "157" &&  \
+          got[11] == "064" &&  \
+          got[12] == "124" &&  \
+          got[13] == "000" &&  \
+          got[14] == "000" &&  \
+          got[15] == "000")
+        {
+          print "IEEE big endian"
+          found = 1
+          exit
+        }
+
+      if (got[8]  == "353" &&  \
+          got[9]  == "315" &&  \
+          got[10] == "242" &&  \
+          got[11] == "171" &&  \
+          got[12] == "000" &&  \
+          got[13] == "240" &&  \
+          got[14] == "000" &&  \
+          got[15] == "000")
+        {
+          print "VAX D"
+          found = 1
+          exit
+        }
+
+      if (got[8]  == "275" &&  \
+          got[9]  == "301" &&  \
+          got[10] == "064" &&  \
+          got[11] == "157" &&  \
+          got[12] == "000" &&  \
+          got[13] == "124" &&  \
+          got[14] == "000" &&  \
+          got[15] == "000")
+        {
+          print "VAX G"
+          found = 1
+          exit
+        }
+
+      if (got[8]  == "300" &&  \
+          got[9]  == "033" &&  \
+          got[10] == "353" &&  \
+          got[11] == "171" &&  \
+          got[12] == "242" &&  \
+          got[13] == "240" &&  \
+          got[14] == "000" &&  \
+          got[15] == "000")
+        {
+          print "Cray CFP"
+          found = 1
+          exit
+        }
+    }
+}
+
+END {
+  if (! found)
+    print "unknown", saw
+}
+]
+EOF
+  gmp_cv_c_double_format=`od -b conftest$EXEEXT | $AWK -f conftest.awk`
+  case $gmp_cv_c_double_format in
+  unknown*)
+    echo "cannot match anything, conftest$EXEEXT contains" >&AC_FD_CC
+    od -b conftest$EXEEXT >&AC_FD_CC
+    ;;
+  esac
+else
+  AC_MSG_WARN([oops, cannot compile test program])
+fi
+rm -f conftest*
+])
+
+AH_VERBATIM([HAVE_DOUBLE],
+[/* Define one of the following to 1 for the format of a `double'.
+   If your format is not among these choices, or you don't know what it is,
+   then leave all undefined.
+   IEEE_LITTLE_SWAPPED means little endian, but with the two 4-byte halves
+   swapped, as used by ARM CPUs in little endian mode.  */
+#undef HAVE_DOUBLE_IEEE_BIG_ENDIAN
+#undef HAVE_DOUBLE_IEEE_LITTLE_ENDIAN
+#undef HAVE_DOUBLE_IEEE_LITTLE_SWAPPED
+#undef HAVE_DOUBLE_VAX_D
+#undef HAVE_DOUBLE_VAX_G
+#undef HAVE_DOUBLE_CRAY_CFP])
+
+case $gmp_cv_c_double_format in
+  "IEEE big endian")
+    AC_DEFINE(HAVE_DOUBLE_IEEE_BIG_ENDIAN, 1)
+    GMP_DEFINE_RAW("define_not_for_expansion(\`HAVE_DOUBLE_IEEE_BIG_ENDIAN')", POST)
+    ;;
+  "IEEE little endian")
+    AC_DEFINE(HAVE_DOUBLE_IEEE_LITTLE_ENDIAN, 1)
+    GMP_DEFINE_RAW("define_not_for_expansion(\`HAVE_DOUBLE_IEEE_LITTLE_ENDIAN')", POST)
+    ;;
+  "IEEE little endian, swapped halves")
+    AC_DEFINE(HAVE_DOUBLE_IEEE_LITTLE_SWAPPED, 1) ;;
+  "VAX D")
+    AC_DEFINE(HAVE_DOUBLE_VAX_D, 1) ;;
+  "VAX G")
+    AC_DEFINE(HAVE_DOUBLE_VAX_G, 1) ;;
+  "Cray CFP")
+    AC_DEFINE(HAVE_DOUBLE_CRAY_CFP, 1) ;;
+  "bad ARM software floats")
+    ;;
+  unknown*)
+    AC_MSG_WARN([Could not determine float format.])
+    AC_MSG_WARN([Conversions to and from "double" may be slow.])
+    ;;
+  *)
+    AC_MSG_WARN([oops, unrecognised float format: $gmp_cv_c_double_format])
+    ;;
+esac
+])
+
+
+dnl  GMP_C_STDARG
+dnl  ------------
+dnl  Test whether to use <stdarg.h>.
+dnl
+dnl  Notice the AC_DEFINE here is HAVE_STDARG to avoid clashing with
+dnl  HAVE_STDARG_H which could arise from AC_CHECK_HEADERS.
+dnl
+dnl  This test might be slight overkill, after all there's really only going
+dnl  to be ANSI or K&R and the two can be differentiated by AC_PROG_CC_STDC
+dnl  or very likely by the setups for _PROTO in gmp.h.  On the other hand
+dnl  this test is nice and direct, being what we're going to actually use.
+
+dnl  AC_DEFUN([GMP_C_STDARG],
+dnl  [AC_CACHE_CHECK([whether <stdarg.h> exists and works],
+dnl                  gmp_cv_c_stdarg,
+dnl  [AC_TRY_COMPILE(
+dnl  [#include <stdarg.h>
+dnl  int foo (int x, ...)
+dnl  {
+dnl    va_list  ap;
+dnl    int      y;
+dnl    va_start (ap, x);
+dnl    y = va_arg (ap, int);
+dnl    va_end (ap);
+dnl    return y;
+dnl  }],,
+dnl  gmp_cv_c_stdarg=yes, gmp_cv_c_stdarg=no)
+dnl  ])
+dnl  if test $gmp_cv_c_stdarg = yes; then
+dnl    AC_DEFINE(HAVE_STDARG, 1, [Define to 1 if <stdarg.h> exists and works])
+dnl  fi
+dnl  ])
+
+
+dnl  GMP_FUNC_ALLOCA
+dnl  ---------------
+dnl  Determine whether "alloca" is available.  This is AC_FUNC_ALLOCA from
+dnl  autoconf, but changed so it doesn't use alloca.c if alloca() isn't
+dnl  available, and also to use gmp-impl.h for the conditionals detecting
+dnl  compiler builtin alloca's.
+
+AC_DEFUN([GMP_FUNC_ALLOCA],
+[AC_REQUIRE([GMP_HEADER_ALLOCA])
+AC_CACHE_CHECK([for alloca (via gmp-impl.h)],
+               gmp_cv_func_alloca,
+[AC_TRY_LINK(
+GMP_INCLUDE_GMP_H
+[#include "$srcdir/gmp-impl.h"
+],
+  [char *p = (char *) alloca (1);],
+  gmp_cv_func_alloca=yes,
+  gmp_cv_func_alloca=no)])
+if test $gmp_cv_func_alloca = yes; then
+  AC_DEFINE(HAVE_ALLOCA, 1, [Define to 1 if alloca() works (via gmp-impl.h).])
+fi
+])
+
+AC_DEFUN([GMP_HEADER_ALLOCA],
+[# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works
+# for constant arguments.  Useless!
+AC_CACHE_CHECK([for working alloca.h],
+               gmp_cv_header_alloca,
+[AC_TRY_LINK([#include <alloca.h>],
+  [char *p = (char *) alloca (2 * sizeof (int));],
+  gmp_cv_header_alloca=yes,
+  gmp_cv_header_alloca=no)])
+if test $gmp_cv_header_alloca = yes; then
+  AC_DEFINE(HAVE_ALLOCA_H, 1,
+  [Define to 1 if you have <alloca.h> and it should be used (not on Ultrix).])
+fi
+])
+
+
+dnl  GMP_OPTION_ALLOCA
+dnl  -----------------
+dnl  Decide what to do about --enable-alloca from the user.
+dnl  This is a macro so it can require GMP_FUNC_ALLOCA.
+
+AC_DEFUN([GMP_OPTION_ALLOCA],
+[AC_REQUIRE([GMP_FUNC_ALLOCA])
+AC_CACHE_CHECK([how to allocate temporary memory],
+               gmp_cv_option_alloca,
+[case $enable_alloca in
+  yes)
+    gmp_cv_option_alloca=alloca
+    ;;
+  no)
+    gmp_cv_option_alloca=malloc-reentrant
+    ;;
+  reentrant | notreentrant)
+    case $gmp_cv_func_alloca in
+    yes)  gmp_cv_option_alloca=alloca ;;
+    *)    gmp_cv_option_alloca=malloc-$enable_alloca ;;
+    esac
+    ;;
+  *)
+    gmp_cv_option_alloca=$enable_alloca
+    ;;
+esac
+])
+
+AH_VERBATIM([WANT_TMP],
+[/* Define one of these to 1 for the desired temporary memory allocation
+   method, per --enable-alloca. */
+#undef WANT_TMP_ALLOCA
+#undef WANT_TMP_REENTRANT
+#undef WANT_TMP_NOTREENTRANT
+#undef WANT_TMP_DEBUG])
+
+case $gmp_cv_option_alloca in
+  alloca)
+    if test $gmp_cv_func_alloca = no; then
+      AC_MSG_ERROR([--enable-alloca=alloca specified, but alloca not available])
+    fi
+    AC_DEFINE(WANT_TMP_ALLOCA)
+    TAL_OBJECT=tal-reent$U.lo
+    ;;
+  malloc-reentrant)
+    AC_DEFINE(WANT_TMP_REENTRANT)
+    TAL_OBJECT=tal-reent$U.lo
+    ;;
+  malloc-notreentrant)
+    AC_DEFINE(WANT_TMP_NOTREENTRANT)
+    TAL_OBJECT=tal-notreent$U.lo
+    ;;
+  debug)
+    AC_DEFINE(WANT_TMP_DEBUG)
+    TAL_OBJECT=tal-debug$U.lo
+    ;;
+  *)
+    # checks at the start of configure.in should protect us
+    AC_MSG_ERROR([unrecognised --enable-alloca=$gmp_cv_option_alloca])
+    ;;
+esac
+AC_SUBST(TAL_OBJECT)
+])
+
+
+dnl  GMP_FUNC_SSCANF_WRITABLE_INPUT
+dnl  ------------------------------
+dnl  Determine whether sscanf requires a writable input string.
+dnl
+dnl  It might be nicer to run a program to determine this when doing a
+dnl  native build, but the systems afflicted are few and far between these
+dnl  days, so it seems good enough just to list them.
+
+AC_DEFUN([GMP_FUNC_SSCANF_WRITABLE_INPUT],
+[AC_CACHE_CHECK([whether sscanf needs writable input],
+                 gmp_cv_func_sscanf_writable_input,
+[case $host in
+  *-*-hpux9 | *-*-hpux9.*)
+     gmp_cv_func_sscanf_writable_input=yes ;;
+  *) gmp_cv_func_sscanf_writable_input=no  ;;
+esac
+])
+case $gmp_cv_func_sscanf_writable_input in
+  yes) AC_DEFINE(SSCANF_WRITABLE_INPUT, 1,
+                 [Define to 1 if sscanf requires writable inputs]) ;;
+  no)  ;;
+  *)   AC_MSG_ERROR([unrecognised \$gmp_cv_func_sscanf_writable_input]) ;;
+esac
+])
+
+
+dnl  GMP_FUNC_VSNPRINTF
+dnl  ------------------
+dnl  Check whether vsnprintf exists, and works properly.
+dnl
+dnl  Systems without vsnprintf include mingw32, OSF 4.
+dnl
+dnl  Sparc Solaris 2.7 in 64-bit mode doesn't always truncate, making
+dnl  vsnprintf like vsprintf, and hence completely useless.  On one system a
+dnl  literal string is enough to provoke the problem, on another a "%n" was
+dnl  needed.  There seems to be something weird going on with the optimizer
+dnl  or something, since on the first system adding a second check with
+dnl  "%n", or even just an initialized local variable, makes it work.  In
+dnl  any case, without bothering to get to the bottom of this, the two
+dnl  program runs in the code below end up successfully detecting the
+dnl  problem.
+dnl
+dnl  glibc 2.0.x returns either -1 or bufsize-1 for an overflow (both seen,
+dnl  not sure which 2.0.x does which), but still puts the correct null
+dnl  terminated result into the buffer.
+
+AC_DEFUN([GMP_FUNC_VSNPRINTF],
+[AC_CHECK_FUNC(vsnprintf,
+              [gmp_vsnprintf_exists=yes],
+              [gmp_vsnprintf_exists=no])
+if test "$gmp_vsnprintf_exists" = no; then
+  gmp_cv_func_vsnprintf=no
+else
+  AC_CACHE_CHECK([whether vsnprintf works],
+                 gmp_cv_func_vsnprintf,
+  [gmp_cv_func_vsnprintf=yes
+   for i in 'return check ("hello world");' 'int n; return check ("%nhello world", &n);'; do
+     AC_TRY_RUN([
+#include <string.h>  /* for strcmp */
+#include <stdio.h>   /* for vsnprintf */
+
+#include <stdarg.h>
+
+int
+check (const char *fmt, ...)
+{
+  static char  buf[128];
+  va_list  ap;
+  int      ret;
+
+  va_start (ap, fmt);
+
+  ret = vsnprintf (buf, 4, fmt, ap);
+
+  if (ret == -1 || strcmp (buf, "hel") != 0)
+    return 1;
+
+  /* allowed return values */
+  if (ret != 3 && ret != 11)
+    return 2;
+
+  return 0;
+}
+
+int
+main ()
+{
+$i
+}
+],
+      [:],
+      [gmp_cv_func_vsnprintf=no; break],
+      [gmp_cv_func_vsnprintf=probably; break])
+  done
+  ])
+  if test "$gmp_cv_func_vsnprintf" = probably; then
+    AC_MSG_WARN([cannot check for properly working vsnprintf when cross compiling, will assume it's ok])
+  fi
+  if test "$gmp_cv_func_vsnprintf" != no; then
+    AC_DEFINE(HAVE_VSNPRINTF,1,
+    [Define to 1 if you have the `vsnprintf' function and it works properly.])
+  fi
+fi
+])
+
+
+dnl  GMP_H_EXTERN_INLINE
+dnl  -------------------
+dnl  If the compiler has an "inline" of some sort, check whether the
+dnl  #ifdef's in gmp.h recognise it.
+
+AC_DEFUN([GMP_H_EXTERN_INLINE],
+[AC_REQUIRE([AC_C_INLINE])
+case $ac_cv_c_inline in
+no) ;;
+*)
+  AC_TRY_COMPILE(
+[#define __GMP_WITHIN_CONFIGURE_INLINE 1
+]GMP_INCLUDE_GMP_H[
+#ifndef __GMP_EXTERN_INLINE
+die die die
+#endif
+],,,
+  [case $ac_cv_c_inline in
+  yes) tmp_inline=inline ;;
+  *)   tmp_inline=$ac_cv_c_inline ;;
+  esac
+  AC_MSG_WARN([gmp.h doesnt recognise compiler "$tmp_inline", inlines will be unavailable])])
+  ;;
+esac
+])
+
+
+dnl  GMP_H_HAVE_FILE
+dnl  ---------------
+dnl  Check whether the #ifdef's in gmp.h recognise when stdio.h has been
+dnl  included to get FILE.
+
+AC_DEFUN([GMP_H_HAVE_FILE],
+[AC_TRY_COMPILE(
+[#include <stdio.h>]
+GMP_INCLUDE_GMP_H
+[#if ! _GMP_H_HAVE_FILE
+die die die
+#endif
+],,,
+  [AC_MSG_WARN([gmp.h doesnt recognise <stdio.h>, FILE prototypes will be unavailable])])
+])
+
+
+dnl  GMP_PROG_CC_FOR_BUILD
+dnl  ---------------------
+dnl  Establish CC_FOR_BUILD, a C compiler for the build system.
+dnl
+dnl  If CC_FOR_BUILD is set then it's expected to work, likewise the old
+dnl  style HOST_CC, otherwise some likely candidates are tried, the same as
+dnl  configfsf.guess.
+
+AC_DEFUN([GMP_PROG_CC_FOR_BUILD],
+[AC_REQUIRE([AC_PROG_CC])
+if test -n "$CC_FOR_BUILD"; then
+  GMP_PROG_CC_FOR_BUILD_WORKS($CC_FOR_BUILD,,
+    [AC_MSG_ERROR([Specified CC_FOR_BUILD doesn't seem to work])])
+elif test -n "$HOST_CC"; then
+  GMP_PROG_CC_FOR_BUILD_WORKS($HOST_CC,
+    [CC_FOR_BUILD=$HOST_CC],
+    [AC_MSG_ERROR([Specified HOST_CC doesn't seem to work])])
+else
+  for i in "$CC" "$CC $CFLAGS $CPPFLAGS" cc gcc c89 c99; do
+    GMP_PROG_CC_FOR_BUILD_WORKS($i,
+      [CC_FOR_BUILD=$i
+       break])
+  done
+  if test -z "$CC_FOR_BUILD"; then
+    AC_MSG_ERROR([Cannot find a build system compiler])
+  fi
+fi
+
+AC_ARG_VAR(CC_FOR_BUILD,[build system C compiler])
+AC_SUBST(CC_FOR_BUILD)
+])
+
+
+dnl  GMP_PROG_CC_FOR_BUILD_WORKS(cc/cflags[,[action-if-good][,action-if-bad]])
+dnl  -------------------------------------------------------------------------
+dnl  See if the given cc/cflags works on the build system.
+dnl
+dnl  It seems easiest to just use the default compiler output, rather than
+dnl  figuring out the .exe or whatever at this stage.
+
+AC_DEFUN([GMP_PROG_CC_FOR_BUILD_WORKS],
+[AC_MSG_CHECKING([build system compiler $1])
+# remove anything that might look like compiler output to our "||" expression
+rm -f conftest* a.out b.out a.exe a_out.exe
+cat >conftest.c <<EOF
+int
+main ()
+{
+  return 0;
+}
+EOF
+gmp_compile="$1 conftest.c"
+cc_for_build_works=no
+if AC_TRY_EVAL(gmp_compile); then
+  if (./a.out || ./b.out || ./a.exe || ./a_out.exe || ./conftest) >&AC_FD_CC 2>&1; then
+    cc_for_build_works=yes
+  fi
+fi
+rm -f conftest* a.out b.out a.exe a_out.exe
+AC_MSG_RESULT($cc_for_build_works)
+if test "$cc_for_build_works" = yes; then
+  ifelse([$2],,:,[$2])
+else
+  ifelse([$3],,:,[$3])
+fi
+])
+
+
+dnl  GMP_PROG_CPP_FOR_BUILD
+dnl  ---------------------
+dnl  Establish CPP_FOR_BUILD, the build system C preprocessor.
+dnl  The choices tried here are the same as AC_PROG_CPP, but with
+dnl  CC_FOR_BUILD.
+
+AC_DEFUN([GMP_PROG_CPP_FOR_BUILD],
+[AC_REQUIRE([GMP_PROG_CC_FOR_BUILD])
+AC_MSG_CHECKING([for build system preprocessor])
+if test -z "$CPP_FOR_BUILD"; then
+  AC_CACHE_VAL(gmp_cv_prog_cpp_for_build,
+  [cat >conftest.c <<EOF
+#define FOO BAR
+EOF
+  for i in "$CC_FOR_BUILD -E" "$CC_FOR_BUILD -E -traditional-cpp" "/lib/cpp"; do
+    gmp_compile="$i conftest.c"
+    if AC_TRY_EVAL(gmp_compile) >&AC_FD_CC 2>&1; then
+      gmp_cv_prog_cpp_for_build=$i
+      break
+    fi
+  done
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  if test -z "$gmp_cv_prog_cpp_for_build"; then
+    AC_MSG_ERROR([Cannot find build system C preprocessor.])
+  fi
+  ])
+  CPP_FOR_BUILD=$gmp_cv_prog_cpp_for_build
+fi
+AC_MSG_RESULT([$CPP_FOR_BUILD])
+
+AC_ARG_VAR(CPP_FOR_BUILD,[build system C preprocessor])
+AC_SUBST(CPP_FOR_BUILD)
+])
+
+
+dnl  GMP_PROG_EXEEXT_FOR_BUILD
+dnl  -------------------------
+dnl  Determine EXEEXT_FOR_BUILD, the build system executable suffix.
+dnl
+dnl  The idea is to find what "-o conftest$foo" will make it possible to run
+dnl  the program with ./conftest.  On Unix-like systems this is of course
+dnl  nothing, for DOS it's ".exe", or for a strange RISC OS foreign file
+dnl  system cross compile it can be ",ff8" apparently.  Not sure if the
+dnl  latter actually applies to a build-system executable, maybe it doesn't,
+dnl  but it won't hurt to try.
+
+AC_DEFUN([GMP_PROG_EXEEXT_FOR_BUILD],
+[AC_REQUIRE([GMP_PROG_CC_FOR_BUILD])
+AC_CACHE_CHECK([for build system executable suffix],
+               gmp_cv_prog_exeext_for_build,
+[cat >conftest.c <<EOF
+int
+main ()
+{
+  return 0;
+}
+EOF
+for i in .exe ,ff8 ""; do
+  gmp_compile="$CC_FOR_BUILD conftest.c -o conftest$i"
+  if AC_TRY_EVAL(gmp_compile); then
+    if (./conftest) 2>&AC_FD_CC; then
+      gmp_cv_prog_exeext_for_build=$i
+      break
+    fi
+  fi
+done
+rm -f conftest*
+if test "${gmp_cv_prog_exeext_for_build+set}" != set; then
+  AC_MSG_ERROR([Cannot determine executable suffix])
+fi
+])
+AC_SUBST(EXEEXT_FOR_BUILD,$gmp_cv_prog_exeext_for_build)
+])
+
+
+dnl  GMP_C_FOR_BUILD_ANSI
+dnl  --------------------
+dnl  Determine whether CC_FOR_BUILD is ANSI, and establish U_FOR_BUILD
+dnl  accordingly.
+dnl
+dnl  FIXME: Use AC_PROG_CC sets ac_cv_prog_cc_c89 which could be used instead
+
+AC_DEFUN([GMP_C_FOR_BUILD_ANSI],
+[AC_REQUIRE([GMP_PROG_CC_FOR_BUILD])
+AC_CACHE_CHECK([whether build system compiler is ANSI],
+               gmp_cv_c_for_build_ansi,
+[cat >conftest.c <<EOF
+int
+main (int argc, char **argv)
+{
+  return 0;
+}
+EOF
+gmp_compile="$CC_FOR_BUILD conftest.c"
+if AC_TRY_EVAL(gmp_compile); then
+  gmp_cv_c_for_build_ansi=yes
+else
+  gmp_cv_c_for_build_ansi=no
+fi
+rm -f conftest* a.out b.out a.exe a_out.exe
+])
+if test "$gmp_cv_c_for_build_ansi" = yes; then
+  U_FOR_BUILD=
+else
+  AC_SUBST(U_FOR_BUILD,_)
+fi
+])
+
+
+dnl  GMP_CHECK_LIBM_FOR_BUILD
+dnl  ------------------------
+dnl  Establish LIBM_FOR_BUILD as -lm, if that seems to work.
+dnl
+dnl  Libtool AC_CHECK_LIBM also uses -lmw on *-ncr-sysv4.3*, if it works.
+dnl  Don't know what that does, lets assume it's not needed just for log().
+
+AC_DEFUN([GMP_CHECK_LIBM_FOR_BUILD],
+[AC_REQUIRE([GMP_PROG_CC_FOR_BUILD])
+AC_CACHE_CHECK([for build system compiler math library],
+               gmp_cv_check_libm_for_build,
+[cat >conftest.c <<EOF
+#include <math.h>
+int
+main ()
+{
+  return 0;
+}
+double d;
+double
+foo ()
+{
+  return log (d);
+}
+EOF
+gmp_compile="$CC_FOR_BUILD conftest.c -lm"
+if AC_TRY_EVAL(gmp_compile); then
+  gmp_cv_check_libm_for_build=-lm
+else
+  gmp_cv_check_libm_for_build=no
+fi
+rm -f conftest* a.out b.out a.exe a_out.exe
+])
+case $gmp_cv_check_libm_for_build in
+  yes) AC_SUBST(LIBM_FOR_BUILD,-lm) ;;
+  no)  LIBM_FOR_BUILD= ;;
+  *)   LIBM_FOR_BUILD=$gmp_cv_check_libm_for_build ;;
+esac
+])
diff --git a/third_party/gmp/aclocal.m4 b/third_party/gmp/aclocal.m4
new file mode 100644
index 0000000..32cc8ee
--- /dev/null
+++ b/third_party/gmp/aclocal.m4
@@ -0,0 +1,9921 @@
+# generated automatically by aclocal 1.15 -*- Autoconf -*-
+
+# Copyright (C) 1996-2014 Free Software Foundation, Inc.
+
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
+m4_ifndef([AC_AUTOCONF_VERSION],
+  [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],,
+[m4_warning([this file was generated for autoconf 2.69.
+You have another version of autoconf.  It may work, but is not guaranteed to.
+If you have problems, you may need to regenerate the build system entirely.
+To do so, use the procedure documented by the package, typically 'autoreconf'.])])
+
+# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
+#
+#   Copyright (C) 1996-2001, 2003-2015 Free Software Foundation, Inc.
+#   Written by Gordon Matzigkeit, 1996
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+m4_define([_LT_COPYING], [dnl
+# Copyright (C) 2014 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions.  There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# GNU Libtool is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of of the License, or
+# (at your option) any later version.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program or library that is built
+# using GNU Libtool, you may include this file under the  same
+# distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+])
+
+# serial 58 LT_INIT
+
+
+# LT_PREREQ(VERSION)
+# ------------------
+# Complain and exit if this libtool version is less that VERSION.
+m4_defun([LT_PREREQ],
+[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1,
+       [m4_default([$3],
+		   [m4_fatal([Libtool version $1 or higher is required],
+		             63)])],
+       [$2])])
+
+
+# _LT_CHECK_BUILDDIR
+# ------------------
+# Complain if the absolute build directory name contains unusual characters
+m4_defun([_LT_CHECK_BUILDDIR],
+[case `pwd` in
+  *\ * | *\	*)
+    AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;;
+esac
+])
+
+
+# LT_INIT([OPTIONS])
+# ------------------
+AC_DEFUN([LT_INIT],
+[AC_PREREQ([2.62])dnl We use AC_PATH_PROGS_FEATURE_CHECK
+AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
+AC_BEFORE([$0], [LT_LANG])dnl
+AC_BEFORE([$0], [LT_OUTPUT])dnl
+AC_BEFORE([$0], [LTDL_INIT])dnl
+m4_require([_LT_CHECK_BUILDDIR])dnl
+
+dnl Autoconf doesn't catch unexpanded LT_ macros by default:
+m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl
+m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl
+dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4
+dnl unless we require an AC_DEFUNed macro:
+AC_REQUIRE([LTOPTIONS_VERSION])dnl
+AC_REQUIRE([LTSUGAR_VERSION])dnl
+AC_REQUIRE([LTVERSION_VERSION])dnl
+AC_REQUIRE([LTOBSOLETE_VERSION])dnl
+m4_require([_LT_PROG_LTMAIN])dnl
+
+_LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}])
+
+dnl Parse OPTIONS
+_LT_SET_OPTIONS([$0], [$1])
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS=$ltmain
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+AC_SUBST(LIBTOOL)dnl
+
+_LT_SETUP
+
+# Only expand once:
+m4_define([LT_INIT])
+])# LT_INIT
+
+# Old names:
+AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT])
+AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_PROG_LIBTOOL], [])
+dnl AC_DEFUN([AM_PROG_LIBTOOL], [])
+
+
+# _LT_PREPARE_CC_BASENAME
+# -----------------------
+m4_defun([_LT_PREPARE_CC_BASENAME], [
+# Calculate cc_basename.  Skip known compiler wrappers and cross-prefix.
+func_cc_basename ()
+{
+    for cc_temp in @S|@*""; do
+      case $cc_temp in
+        compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;;
+        distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;;
+        \-*) ;;
+        *) break;;
+      esac
+    done
+    func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+}
+])# _LT_PREPARE_CC_BASENAME
+
+
+# _LT_CC_BASENAME(CC)
+# -------------------
+# It would be clearer to call AC_REQUIREs from _LT_PREPARE_CC_BASENAME,
+# but that macro is also expanded into generated libtool script, which
+# arranges for $SED and $ECHO to be set by different means.
+m4_defun([_LT_CC_BASENAME],
+[m4_require([_LT_PREPARE_CC_BASENAME])dnl
+AC_REQUIRE([_LT_DECL_SED])dnl
+AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl
+func_cc_basename $1
+cc_basename=$func_cc_basename_result
+])
+
+
+# _LT_FILEUTILS_DEFAULTS
+# ----------------------
+# It is okay to use these file commands and assume they have been set
+# sensibly after 'm4_require([_LT_FILEUTILS_DEFAULTS])'.
+m4_defun([_LT_FILEUTILS_DEFAULTS],
+[: ${CP="cp -f"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+])# _LT_FILEUTILS_DEFAULTS
+
+
+# _LT_SETUP
+# ---------
+m4_defun([_LT_SETUP],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl
+AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl
+
+_LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl
+dnl
+_LT_DECL([], [host_alias], [0], [The host system])dnl
+_LT_DECL([], [host], [0])dnl
+_LT_DECL([], [host_os], [0])dnl
+dnl
+_LT_DECL([], [build_alias], [0], [The build system])dnl
+_LT_DECL([], [build], [0])dnl
+_LT_DECL([], [build_os], [0])dnl
+dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([LT_PATH_LD])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+dnl
+AC_REQUIRE([AC_PROG_LN_S])dnl
+test -z "$LN_S" && LN_S="ln -s"
+_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl
+dnl
+AC_REQUIRE([LT_CMD_MAX_LEN])dnl
+_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl
+_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl
+dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_CHECK_SHELL_FEATURES])dnl
+m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl
+m4_require([_LT_CMD_RELOAD])dnl
+m4_require([_LT_CHECK_MAGIC_METHOD])dnl
+m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl
+m4_require([_LT_CMD_OLD_ARCHIVE])dnl
+m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
+m4_require([_LT_WITH_SYSROOT])dnl
+m4_require([_LT_CMD_TRUNCATE])dnl
+
+_LT_CONFIG_LIBTOOL_INIT([
+# See if we are running on zsh, and set the options that allow our
+# commands through without removal of \ escapes INIT.
+if test -n "\${ZSH_VERSION+set}"; then
+   setopt NO_GLOB_SUBST
+fi
+])
+if test -n "${ZSH_VERSION+set}"; then
+   setopt NO_GLOB_SUBST
+fi
+
+_LT_CHECK_OBJDIR
+
+m4_require([_LT_TAG_COMPILER])dnl
+
+case $host_os in
+aix3*)
+  # AIX sometimes has problems with the GCC collect2 program.  For some
+  # reason, if we set the COLLECT_NAMES environment variable, the problems
+  # vanish in a puff of smoke.
+  if test set != "${COLLECT_NAMES+set}"; then
+    COLLECT_NAMES=
+    export COLLECT_NAMES
+  fi
+  ;;
+esac
+
+# Global variables:
+ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a '.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+
+with_gnu_ld=$lt_cv_prog_gnu_ld
+
+old_CC=$CC
+old_CFLAGS=$CFLAGS
+
+# Set sane defaults for various variables
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
+test -z "$LD" && LD=ld
+test -z "$ac_objext" && ac_objext=o
+
+_LT_CC_BASENAME([$compiler])
+
+# Only perform the check for file, if the check method requires it
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+case $deplibs_check_method in
+file_magic*)
+  if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+    _LT_PATH_MAGIC
+  fi
+  ;;
+esac
+
+# Use C for the default configuration in the libtool script
+LT_SUPPORTED_TAG([CC])
+_LT_LANG_C_CONFIG
+_LT_LANG_DEFAULT_CONFIG
+_LT_CONFIG_COMMANDS
+])# _LT_SETUP
+
+
+# _LT_PREPARE_SED_QUOTE_VARS
+# --------------------------
+# Define a few sed substitution that help us do robust quoting.
+m4_defun([_LT_PREPARE_SED_QUOTE_VARS],
+[# Backslashify metacharacters that are still active within
+# double-quoted strings.
+sed_quote_subst='s/\([["`$\\]]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\([["`\\]]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to delay expansion of an escaped single quote.
+delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+])
+
+# _LT_PROG_LTMAIN
+# ---------------
+# Note that this code is called both from 'configure', and 'config.status'
+# now that we use AC_CONFIG_COMMANDS to generate libtool.  Notably,
+# 'config.status' has no value for ac_aux_dir unless we are using Automake,
+# so we pass a copy along to make sure it has a sensible value anyway.
+m4_defun([_LT_PROG_LTMAIN],
+[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl
+_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir'])
+ltmain=$ac_aux_dir/ltmain.sh
+])# _LT_PROG_LTMAIN
+
+
+
+# So that we can recreate a full libtool script including additional
+# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS
+# in macros and then make a single call at the end using the 'libtool'
+# label.
+
+
+# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS])
+# ----------------------------------------
+# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later.
+m4_define([_LT_CONFIG_LIBTOOL_INIT],
+[m4_ifval([$1],
+          [m4_append([_LT_OUTPUT_LIBTOOL_INIT],
+                     [$1
+])])])
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_INIT])
+
+
+# _LT_CONFIG_LIBTOOL([COMMANDS])
+# ------------------------------
+# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later.
+m4_define([_LT_CONFIG_LIBTOOL],
+[m4_ifval([$1],
+          [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS],
+                     [$1
+])])])
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS])
+
+
+# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS])
+# -----------------------------------------------------
+m4_defun([_LT_CONFIG_SAVE_COMMANDS],
+[_LT_CONFIG_LIBTOOL([$1])
+_LT_CONFIG_LIBTOOL_INIT([$2])
+])
+
+
+# _LT_FORMAT_COMMENT([COMMENT])
+# -----------------------------
+# Add leading comment marks to the start of each line, and a trailing
+# full-stop to the whole comment if one is not present already.
+m4_define([_LT_FORMAT_COMMENT],
+[m4_ifval([$1], [
+m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])],
+              [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.])
+)])
+
+
+
+
+
+# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?])
+# -------------------------------------------------------------------
+# CONFIGNAME is the name given to the value in the libtool script.
+# VARNAME is the (base) name used in the configure script.
+# VALUE may be 0, 1 or 2 for a computed quote escaped value based on
+# VARNAME.  Any other value will be used directly.
+m4_define([_LT_DECL],
+[lt_if_append_uniq([lt_decl_varnames], [$2], [, ],
+    [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name],
+	[m4_ifval([$1], [$1], [$2])])
+    lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3])
+    m4_ifval([$4],
+	[lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])])
+    lt_dict_add_subkey([lt_decl_dict], [$2],
+	[tagged?], [m4_ifval([$5], [yes], [no])])])
+])
+
+
+# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION])
+# --------------------------------------------------------
+m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])])
+
+
+# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...])
+# ------------------------------------------------
+m4_define([lt_decl_tag_varnames],
+[_lt_decl_filter([tagged?], [yes], $@)])
+
+
+# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..])
+# ---------------------------------------------------------
+m4_define([_lt_decl_filter],
+[m4_case([$#],
+  [0], [m4_fatal([$0: too few arguments: $#])],
+  [1], [m4_fatal([$0: too few arguments: $#: $1])],
+  [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)],
+  [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)],
+  [lt_dict_filter([lt_decl_dict], $@)])[]dnl
+])
+
+
+# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...])
+# --------------------------------------------------
+m4_define([lt_decl_quote_varnames],
+[_lt_decl_filter([value], [1], $@)])
+
+
+# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...])
+# ---------------------------------------------------
+m4_define([lt_decl_dquote_varnames],
+[_lt_decl_filter([value], [2], $@)])
+
+
+# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...])
+# ---------------------------------------------------
+m4_define([lt_decl_varnames_tagged],
+[m4_assert([$# <= 2])dnl
+_$0(m4_quote(m4_default([$1], [[, ]])),
+    m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]),
+    m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))])
+m4_define([_lt_decl_varnames_tagged],
+[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])])
+
+
+# lt_decl_all_varnames([SEPARATOR], [VARNAME1...])
+# ------------------------------------------------
+m4_define([lt_decl_all_varnames],
+[_$0(m4_quote(m4_default([$1], [[, ]])),
+     m4_if([$2], [],
+	   m4_quote(lt_decl_varnames),
+	m4_quote(m4_shift($@))))[]dnl
+])
+m4_define([_lt_decl_all_varnames],
+[lt_join($@, lt_decl_varnames_tagged([$1],
+			lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl
+])
+
+
+# _LT_CONFIG_STATUS_DECLARE([VARNAME])
+# ------------------------------------
+# Quote a variable value, and forward it to 'config.status' so that its
+# declaration there will have the same value as in 'configure'.  VARNAME
+# must have a single quote delimited value for this to work.
+m4_define([_LT_CONFIG_STATUS_DECLARE],
+[$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`'])
+
+
+# _LT_CONFIG_STATUS_DECLARATIONS
+# ------------------------------
+# We delimit libtool config variables with single quotes, so when
+# we write them to config.status, we have to be sure to quote all
+# embedded single quotes properly.  In configure, this macro expands
+# each variable declared with _LT_DECL (and _LT_TAGDECL) into:
+#
+#    <var>='`$ECHO "$<var>" | $SED "$delay_single_quote_subst"`'
+m4_defun([_LT_CONFIG_STATUS_DECLARATIONS],
+[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames),
+    [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])])
+
+
+# _LT_LIBTOOL_TAGS
+# ----------------
+# Output comment and list of tags supported by the script
+m4_defun([_LT_LIBTOOL_TAGS],
+[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl
+available_tags='_LT_TAGS'dnl
+])
+
+
+# _LT_LIBTOOL_DECLARE(VARNAME, [TAG])
+# -----------------------------------
+# Extract the dictionary values for VARNAME (optionally with TAG) and
+# expand to a commented shell variable setting:
+#
+#    # Some comment about what VAR is for.
+#    visible_name=$lt_internal_name
+m4_define([_LT_LIBTOOL_DECLARE],
+[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1],
+					   [description])))[]dnl
+m4_pushdef([_libtool_name],
+    m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl
+m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])),
+    [0], [_libtool_name=[$]$1],
+    [1], [_libtool_name=$lt_[]$1],
+    [2], [_libtool_name=$lt_[]$1],
+    [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl
+m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl
+])
+
+
+# _LT_LIBTOOL_CONFIG_VARS
+# -----------------------
+# Produce commented declarations of non-tagged libtool config variables
+# suitable for insertion in the LIBTOOL CONFIG section of the 'libtool'
+# script.  Tagged libtool config variables (even for the LIBTOOL CONFIG
+# section) are produced by _LT_LIBTOOL_TAG_VARS.
+m4_defun([_LT_LIBTOOL_CONFIG_VARS],
+[m4_foreach([_lt_var],
+    m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)),
+    [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])])
+
+
+# _LT_LIBTOOL_TAG_VARS(TAG)
+# -------------------------
+m4_define([_LT_LIBTOOL_TAG_VARS],
+[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames),
+    [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])])
+
+
+# _LT_TAGVAR(VARNAME, [TAGNAME])
+# ------------------------------
+m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])])
+
+
+# _LT_CONFIG_COMMANDS
+# -------------------
+# Send accumulated output to $CONFIG_STATUS.  Thanks to the lists of
+# variables for single and double quote escaping we saved from calls
+# to _LT_DECL, we can put quote escaped variables declarations
+# into 'config.status', and then the shell code to quote escape them in
+# for loops in 'config.status'.  Finally, any additional code accumulated
+# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded.
+m4_defun([_LT_CONFIG_COMMANDS],
+[AC_PROVIDE_IFELSE([LT_OUTPUT],
+	dnl If the libtool generation code has been placed in $CONFIG_LT,
+	dnl instead of duplicating it all over again into config.status,
+	dnl then we will have config.status run $CONFIG_LT later, so it
+	dnl needs to know what name is stored there:
+        [AC_CONFIG_COMMANDS([libtool],
+            [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])],
+    dnl If the libtool generation code is destined for config.status,
+    dnl expand the accumulated commands and init code now:
+    [AC_CONFIG_COMMANDS([libtool],
+        [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])])
+])#_LT_CONFIG_COMMANDS
+
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT],
+[
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+sed_quote_subst='$sed_quote_subst'
+double_quote_subst='$double_quote_subst'
+delay_variable_subst='$delay_variable_subst'
+_LT_CONFIG_STATUS_DECLARATIONS
+LTCC='$LTCC'
+LTCFLAGS='$LTCFLAGS'
+compiler='$compiler_DEFAULT'
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+\$[]1
+_LTECHO_EOF'
+}
+
+# Quote evaled strings.
+for var in lt_decl_all_varnames([[ \
+]], lt_decl_quote_varnames); do
+    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+    *[[\\\\\\\`\\"\\\$]]*)
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes
+      ;;
+    *)
+      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+      ;;
+    esac
+done
+
+# Double-quote double-evaled strings.
+for var in lt_decl_all_varnames([[ \
+]], lt_decl_dquote_varnames); do
+    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+    *[[\\\\\\\`\\"\\\$]]*)
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes
+      ;;
+    *)
+      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+      ;;
+    esac
+done
+
+_LT_OUTPUT_LIBTOOL_INIT
+])
+
+# _LT_GENERATED_FILE_INIT(FILE, [COMMENT])
+# ------------------------------------
+# Generate a child script FILE with all initialization necessary to
+# reuse the environment learned by the parent script, and make the
+# file executable.  If COMMENT is supplied, it is inserted after the
+# '#!' sequence but before initialization text begins.  After this
+# macro, additional text can be appended to FILE to form the body of
+# the child script.  The macro ends with non-zero status if the
+# file could not be fully written (such as if the disk is full).
+m4_ifdef([AS_INIT_GENERATED],
+[m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])],
+[m4_defun([_LT_GENERATED_FILE_INIT],
+[m4_require([AS_PREPARE])]dnl
+[m4_pushdef([AS_MESSAGE_LOG_FD])]dnl
+[lt_write_fail=0
+cat >$1 <<_ASEOF || lt_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+$2
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$1 <<\_ASEOF || lt_write_fail=1
+AS_SHELL_SANITIZE
+_AS_PREPARE
+exec AS_MESSAGE_FD>&1
+_ASEOF
+test 0 = "$lt_write_fail" && chmod +x $1[]dnl
+m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT
+
+# LT_OUTPUT
+# ---------
+# This macro allows early generation of the libtool script (before
+# AC_OUTPUT is called), incase it is used in configure for compilation
+# tests.
+AC_DEFUN([LT_OUTPUT],
+[: ${CONFIG_LT=./config.lt}
+AC_MSG_NOTICE([creating $CONFIG_LT])
+_LT_GENERATED_FILE_INIT(["$CONFIG_LT"],
+[# Run this file to recreate a libtool stub with the current configuration.])
+
+cat >>"$CONFIG_LT" <<\_LTEOF
+lt_cl_silent=false
+exec AS_MESSAGE_LOG_FD>>config.log
+{
+  echo
+  AS_BOX([Running $as_me.])
+} >&AS_MESSAGE_LOG_FD
+
+lt_cl_help="\
+'$as_me' creates a local libtool stub from the current configuration,
+for use in further configure time tests before the real libtool is
+generated.
+
+Usage: $[0] [[OPTIONS]]
+
+  -h, --help      print this help, then exit
+  -V, --version   print version number, then exit
+  -q, --quiet     do not print progress messages
+  -d, --debug     don't remove temporary files
+
+Report bugs to <bug-libtool@gnu.org>."
+
+lt_cl_version="\
+m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl
+m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION])
+configured by $[0], generated by m4_PACKAGE_STRING.
+
+Copyright (C) 2011 Free Software Foundation, Inc.
+This config.lt script is free software; the Free Software Foundation
+gives unlimited permision to copy, distribute and modify it."
+
+while test 0 != $[#]
+do
+  case $[1] in
+    --version | --v* | -V )
+      echo "$lt_cl_version"; exit 0 ;;
+    --help | --h* | -h )
+      echo "$lt_cl_help"; exit 0 ;;
+    --debug | --d* | -d )
+      debug=: ;;
+    --quiet | --q* | --silent | --s* | -q )
+      lt_cl_silent=: ;;
+
+    -*) AC_MSG_ERROR([unrecognized option: $[1]
+Try '$[0] --help' for more information.]) ;;
+
+    *) AC_MSG_ERROR([unrecognized argument: $[1]
+Try '$[0] --help' for more information.]) ;;
+  esac
+  shift
+done
+
+if $lt_cl_silent; then
+  exec AS_MESSAGE_FD>/dev/null
+fi
+_LTEOF
+
+cat >>"$CONFIG_LT" <<_LTEOF
+_LT_OUTPUT_LIBTOOL_COMMANDS_INIT
+_LTEOF
+
+cat >>"$CONFIG_LT" <<\_LTEOF
+AC_MSG_NOTICE([creating $ofile])
+_LT_OUTPUT_LIBTOOL_COMMANDS
+AS_EXIT(0)
+_LTEOF
+chmod +x "$CONFIG_LT"
+
+# configure is writing to config.log, but config.lt does its own redirection,
+# appending to config.log, which fails on DOS, as config.log is still kept
+# open by configure.  Here we exec the FD to /dev/null, effectively closing
+# config.log, so it can be properly (re)opened and appended to by config.lt.
+lt_cl_success=:
+test yes = "$silent" &&
+  lt_config_lt_args="$lt_config_lt_args --quiet"
+exec AS_MESSAGE_LOG_FD>/dev/null
+$SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false
+exec AS_MESSAGE_LOG_FD>>config.log
+$lt_cl_success || AS_EXIT(1)
+])# LT_OUTPUT
+
+
+# _LT_CONFIG(TAG)
+# ---------------
+# If TAG is the built-in tag, create an initial libtool script with a
+# default configuration from the untagged config vars.  Otherwise add code
+# to config.status for appending the configuration named by TAG from the
+# matching tagged config vars.
+m4_defun([_LT_CONFIG],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+_LT_CONFIG_SAVE_COMMANDS([
+  m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl
+  m4_if(_LT_TAG, [C], [
+    # See if we are running on zsh, and set the options that allow our
+    # commands through without removal of \ escapes.
+    if test -n "${ZSH_VERSION+set}"; then
+      setopt NO_GLOB_SUBST
+    fi
+
+    cfgfile=${ofile}T
+    trap "$RM \"$cfgfile\"; exit 1" 1 2 15
+    $RM "$cfgfile"
+
+    cat <<_LT_EOF >> "$cfgfile"
+#! $SHELL
+# Generated automatically by $as_me ($PACKAGE) $VERSION
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+
+# Provide generalized library-building support services.
+# Written by Gordon Matzigkeit, 1996
+
+_LT_COPYING
+_LT_LIBTOOL_TAGS
+
+# Configured defaults for sys_lib_dlsearch_path munging.
+: \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"}
+
+# ### BEGIN LIBTOOL CONFIG
+_LT_LIBTOOL_CONFIG_VARS
+_LT_LIBTOOL_TAG_VARS
+# ### END LIBTOOL CONFIG
+
+_LT_EOF
+
+    cat <<'_LT_EOF' >> "$cfgfile"
+
+# ### BEGIN FUNCTIONS SHARED WITH CONFIGURE
+
+_LT_PREPARE_MUNGE_PATH_LIST
+_LT_PREPARE_CC_BASENAME
+
+# ### END FUNCTIONS SHARED WITH CONFIGURE
+
+_LT_EOF
+
+  case $host_os in
+  aix3*)
+    cat <<\_LT_EOF >> "$cfgfile"
+# AIX sometimes has problems with the GCC collect2 program.  For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test set != "${COLLECT_NAMES+set}"; then
+  COLLECT_NAMES=
+  export COLLECT_NAMES
+fi
+_LT_EOF
+    ;;
+  esac
+
+  _LT_PROG_LTMAIN
+
+  # We use sed instead of cat because bash on DJGPP gets confused if
+  # if finds mixed CR/LF and LF-only lines.  Since sed operates in
+  # text mode, it properly converts lines to CR/LF.  This bash problem
+  # is reportedly fixed, but why not run on old versions too?
+  sed '$q' "$ltmain" >> "$cfgfile" \
+     || (rm -f "$cfgfile"; exit 1)
+
+   mv -f "$cfgfile" "$ofile" ||
+    (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+  chmod +x "$ofile"
+],
+[cat <<_LT_EOF >> "$ofile"
+
+dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded
+dnl in a comment (ie after a #).
+# ### BEGIN LIBTOOL TAG CONFIG: $1
+_LT_LIBTOOL_TAG_VARS(_LT_TAG)
+# ### END LIBTOOL TAG CONFIG: $1
+_LT_EOF
+])dnl /m4_if
+],
+[m4_if([$1], [], [
+    PACKAGE='$PACKAGE'
+    VERSION='$VERSION'
+    RM='$RM'
+    ofile='$ofile'], [])
+])dnl /_LT_CONFIG_SAVE_COMMANDS
+])# _LT_CONFIG
+
+
+# LT_SUPPORTED_TAG(TAG)
+# ---------------------
+# Trace this macro to discover what tags are supported by the libtool
+# --tag option, using:
+#    autoconf --trace 'LT_SUPPORTED_TAG:$1'
+AC_DEFUN([LT_SUPPORTED_TAG], [])
+
+
+# C support is built-in for now
+m4_define([_LT_LANG_C_enabled], [])
+m4_define([_LT_TAGS], [])
+
+
+# LT_LANG(LANG)
+# -------------
+# Enable libtool support for the given language if not already enabled.
+AC_DEFUN([LT_LANG],
+[AC_BEFORE([$0], [LT_OUTPUT])dnl
+m4_case([$1],
+  [C],			[_LT_LANG(C)],
+  [C++],		[_LT_LANG(CXX)],
+  [Go],			[_LT_LANG(GO)],
+  [Java],		[_LT_LANG(GCJ)],
+  [Fortran 77],		[_LT_LANG(F77)],
+  [Fortran],		[_LT_LANG(FC)],
+  [Windows Resource],	[_LT_LANG(RC)],
+  [m4_ifdef([_LT_LANG_]$1[_CONFIG],
+    [_LT_LANG($1)],
+    [m4_fatal([$0: unsupported language: "$1"])])])dnl
+])# LT_LANG
+
+
+# _LT_LANG(LANGNAME)
+# ------------------
+m4_defun([_LT_LANG],
+[m4_ifdef([_LT_LANG_]$1[_enabled], [],
+  [LT_SUPPORTED_TAG([$1])dnl
+  m4_append([_LT_TAGS], [$1 ])dnl
+  m4_define([_LT_LANG_]$1[_enabled], [])dnl
+  _LT_LANG_$1_CONFIG($1)])dnl
+])# _LT_LANG
+
+
+m4_ifndef([AC_PROG_GO], [
+# NOTE: This macro has been submitted for inclusion into   #
+#  GNU Autoconf as AC_PROG_GO.  When it is available in    #
+#  a released version of Autoconf we should remove this    #
+#  macro and use it instead.                               #
+m4_defun([AC_PROG_GO],
+[AC_LANG_PUSH(Go)dnl
+AC_ARG_VAR([GOC],     [Go compiler command])dnl
+AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl
+_AC_ARG_VAR_LDFLAGS()dnl
+AC_CHECK_TOOL(GOC, gccgo)
+if test -z "$GOC"; then
+  if test -n "$ac_tool_prefix"; then
+    AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo])
+  fi
+fi
+if test -z "$GOC"; then
+  AC_CHECK_PROG(GOC, gccgo, gccgo, false)
+fi
+])#m4_defun
+])#m4_ifndef
+
+
+# _LT_LANG_DEFAULT_CONFIG
+# -----------------------
+m4_defun([_LT_LANG_DEFAULT_CONFIG],
+[AC_PROVIDE_IFELSE([AC_PROG_CXX],
+  [LT_LANG(CXX)],
+  [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])])
+
+AC_PROVIDE_IFELSE([AC_PROG_F77],
+  [LT_LANG(F77)],
+  [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])])
+
+AC_PROVIDE_IFELSE([AC_PROG_FC],
+  [LT_LANG(FC)],
+  [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])])
+
+dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal
+dnl pulling things in needlessly.
+AC_PROVIDE_IFELSE([AC_PROG_GCJ],
+  [LT_LANG(GCJ)],
+  [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],
+    [LT_LANG(GCJ)],
+    [AC_PROVIDE_IFELSE([LT_PROG_GCJ],
+      [LT_LANG(GCJ)],
+      [m4_ifdef([AC_PROG_GCJ],
+	[m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])])
+       m4_ifdef([A][M_PROG_GCJ],
+	[m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])])
+       m4_ifdef([LT_PROG_GCJ],
+	[m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])])
+
+AC_PROVIDE_IFELSE([AC_PROG_GO],
+  [LT_LANG(GO)],
+  [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])])
+
+AC_PROVIDE_IFELSE([LT_PROG_RC],
+  [LT_LANG(RC)],
+  [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])])
+])# _LT_LANG_DEFAULT_CONFIG
+
+# Obsolete macros:
+AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)])
+AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)])
+AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)])
+AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)])
+AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_CXX], [])
+dnl AC_DEFUN([AC_LIBTOOL_F77], [])
+dnl AC_DEFUN([AC_LIBTOOL_FC], [])
+dnl AC_DEFUN([AC_LIBTOOL_GCJ], [])
+dnl AC_DEFUN([AC_LIBTOOL_RC], [])
+
+
+# _LT_TAG_COMPILER
+# ----------------
+m4_defun([_LT_TAG_COMPILER],
+[AC_REQUIRE([AC_PROG_CC])dnl
+
+_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl
+_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl
+_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl
+_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+])# _LT_TAG_COMPILER
+
+
+# _LT_COMPILER_BOILERPLATE
+# ------------------------
+# Check for compiler boilerplate output or warnings with
+# the simple compiler test code.
+m4_defun([_LT_COMPILER_BOILERPLATE],
+[m4_require([_LT_DECL_SED])dnl
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+])# _LT_COMPILER_BOILERPLATE
+
+
+# _LT_LINKER_BOILERPLATE
+# ----------------------
+# Check for linker boilerplate output or warnings with
+# the simple link test code.
+m4_defun([_LT_LINKER_BOILERPLATE],
+[m4_require([_LT_DECL_SED])dnl
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+])# _LT_LINKER_BOILERPLATE
+
+# _LT_REQUIRED_DARWIN_CHECKS
+# -------------------------
+m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[
+  case $host_os in
+    rhapsody* | darwin*)
+    AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:])
+    AC_CHECK_TOOL([NMEDIT], [nmedit], [:])
+    AC_CHECK_TOOL([LIPO], [lipo], [:])
+    AC_CHECK_TOOL([OTOOL], [otool], [:])
+    AC_CHECK_TOOL([OTOOL64], [otool64], [:])
+    _LT_DECL([], [DSYMUTIL], [1],
+      [Tool to manipulate archived DWARF debug symbol files on Mac OS X])
+    _LT_DECL([], [NMEDIT], [1],
+      [Tool to change global to local symbols on Mac OS X])
+    _LT_DECL([], [LIPO], [1],
+      [Tool to manipulate fat objects and archives on Mac OS X])
+    _LT_DECL([], [OTOOL], [1],
+      [ldd/readelf like tool for Mach-O binaries on Mac OS X])
+    _LT_DECL([], [OTOOL64], [1],
+      [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4])
+
+    AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod],
+      [lt_cv_apple_cc_single_mod=no
+      if test -z "$LT_MULTI_MODULE"; then
+	# By default we will add the -single_module flag. You can override
+	# by either setting the environment variable LT_MULTI_MODULE
+	# non-empty at configure time, or by adding -multi_module to the
+	# link flags.
+	rm -rf libconftest.dylib*
+	echo "int foo(void){return 1;}" > conftest.c
+	echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+-dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD
+	$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+	  -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
+        _lt_result=$?
+	# If there is a non-empty error log, and "single_module"
+	# appears in it, assume the flag caused a linker warning
+        if test -s conftest.err && $GREP single_module conftest.err; then
+	  cat conftest.err >&AS_MESSAGE_LOG_FD
+	# Otherwise, if the output was created with a 0 exit code from
+	# the compiler, it worked.
+	elif test -f libconftest.dylib && test 0 = "$_lt_result"; then
+	  lt_cv_apple_cc_single_mod=yes
+	else
+	  cat conftest.err >&AS_MESSAGE_LOG_FD
+	fi
+	rm -rf libconftest.dylib*
+	rm -f conftest.*
+      fi])
+
+    AC_CACHE_CHECK([for -exported_symbols_list linker flag],
+      [lt_cv_ld_exported_symbols_list],
+      [lt_cv_ld_exported_symbols_list=no
+      save_LDFLAGS=$LDFLAGS
+      echo "_main" > conftest.sym
+      LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
+      AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
+	[lt_cv_ld_exported_symbols_list=yes],
+	[lt_cv_ld_exported_symbols_list=no])
+	LDFLAGS=$save_LDFLAGS
+    ])
+
+    AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load],
+      [lt_cv_ld_force_load=no
+      cat > conftest.c << _LT_EOF
+int forced_loaded() { return 2;}
+_LT_EOF
+      echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD
+      $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD
+      echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD
+      $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD
+      echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD
+      $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD
+      cat > conftest.c << _LT_EOF
+int main() { return 0;}
+_LT_EOF
+      echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD
+      $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
+      _lt_result=$?
+      if test -s conftest.err && $GREP force_load conftest.err; then
+	cat conftest.err >&AS_MESSAGE_LOG_FD
+      elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then
+	lt_cv_ld_force_load=yes
+      else
+	cat conftest.err >&AS_MESSAGE_LOG_FD
+      fi
+        rm -f conftest.err libconftest.a conftest conftest.c
+        rm -rf conftest.dSYM
+    ])
+    case $host_os in
+    rhapsody* | darwin1.[[012]])
+      _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;;
+    darwin1.*)
+      _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
+    darwin*) # darwin 5.x on
+      # if running on 10.5 or later, the deployment target defaults
+      # to the OS version, if on x86, and 10.4, the deployment
+      # target defaults to 10.4. Don't you love it?
+      case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
+	10.0,*86*-darwin8*|10.0,*-darwin[[91]]*)
+	  _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
+	10.[[012]][[,.]]*)
+	  _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
+	10.*)
+	  _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
+      esac
+    ;;
+  esac
+    if test yes = "$lt_cv_apple_cc_single_mod"; then
+      _lt_dar_single_mod='$single_module'
+    fi
+    if test yes = "$lt_cv_ld_exported_symbols_list"; then
+      _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym'
+    else
+      _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib'
+    fi
+    if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then
+      _lt_dsymutil='~$DSYMUTIL $lib || :'
+    else
+      _lt_dsymutil=
+    fi
+    ;;
+  esac
+])
+
+
+# _LT_DARWIN_LINKER_FEATURES([TAG])
+# ---------------------------------
+# Checks for linker and compiler features on darwin
+m4_defun([_LT_DARWIN_LINKER_FEATURES],
+[
+  m4_require([_LT_REQUIRED_DARWIN_CHECKS])
+  _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+  _LT_TAGVAR(hardcode_direct, $1)=no
+  _LT_TAGVAR(hardcode_automatic, $1)=yes
+  _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+  if test yes = "$lt_cv_ld_force_load"; then
+    _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+    m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes],
+                  [FC],  [_LT_TAGVAR(compiler_needs_object, $1)=yes])
+  else
+    _LT_TAGVAR(whole_archive_flag_spec, $1)=''
+  fi
+  _LT_TAGVAR(link_all_deplibs, $1)=yes
+  _LT_TAGVAR(allow_undefined_flag, $1)=$_lt_dar_allow_undefined
+  case $cc_basename in
+     ifort*|nagfor*) _lt_dar_can_shared=yes ;;
+     *) _lt_dar_can_shared=$GCC ;;
+  esac
+  if test yes = "$_lt_dar_can_shared"; then
+    output_verbose_link_cmd=func_echo_all
+    _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil"
+    _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil"
+    _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil"
+    _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil"
+    m4_if([$1], [CXX],
+[   if test yes != "$lt_cv_apple_cc_single_mod"; then
+      _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dsymutil"
+      _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dar_export_syms$_lt_dsymutil"
+    fi
+],[])
+  else
+  _LT_TAGVAR(ld_shlibs, $1)=no
+  fi
+])
+
+# _LT_SYS_MODULE_PATH_AIX([TAGNAME])
+# ----------------------------------
+# Links a minimal program and checks the executable
+# for the system default hardcoded library path. In most cases,
+# this is /usr/lib:/lib, but when the MPI compilers are used
+# the location of the communication and MPI libs are included too.
+# If we don't find anything, use the default library path according
+# to the aix ld manual.
+# Store the results from the different compilers for each TAGNAME.
+# Allow to override them for all tags through lt_cv_aix_libpath.
+m4_defun([_LT_SYS_MODULE_PATH_AIX],
+[m4_require([_LT_DECL_SED])dnl
+if test set = "${lt_cv_aix_libpath+set}"; then
+  aix_libpath=$lt_cv_aix_libpath
+else
+  AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])],
+  [AC_LINK_IFELSE([AC_LANG_PROGRAM],[
+  lt_aix_libpath_sed='[
+      /Import File Strings/,/^$/ {
+	  /^0/ {
+	      s/^0  *\([^ ]*\) *$/\1/
+	      p
+	  }
+      }]'
+  _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  # Check for a 64-bit object if we didn't find anything.
+  if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then
+    _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  fi],[])
+  if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then
+    _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=/usr/lib:/lib
+  fi
+  ])
+  aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])
+fi
+])# _LT_SYS_MODULE_PATH_AIX
+
+
+# _LT_SHELL_INIT(ARG)
+# -------------------
+m4_define([_LT_SHELL_INIT],
+[m4_divert_text([M4SH-INIT], [$1
+])])# _LT_SHELL_INIT
+
+
+
+# _LT_PROG_ECHO_BACKSLASH
+# -----------------------
+# Find how we can fake an echo command that does not interpret backslash.
+# In particular, with Autoconf 2.60 or later we add some code to the start
+# of the generated configure script that will find a shell with a builtin
+# printf (that we can use as an echo command).
+m4_defun([_LT_PROG_ECHO_BACKSLASH],
+[ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+
+AC_MSG_CHECKING([how to print strings])
+# Test print first, because it will be a builtin if present.
+if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \
+   test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
+  ECHO='print -r --'
+elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
+  ECHO='printf %s\n'
+else
+  # Use this function as a fallback that always works.
+  func_fallback_echo ()
+  {
+    eval 'cat <<_LTECHO_EOF
+$[]1
+_LTECHO_EOF'
+  }
+  ECHO='func_fallback_echo'
+fi
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+    $ECHO "$*"
+}
+
+case $ECHO in
+  printf*) AC_MSG_RESULT([printf]) ;;
+  print*) AC_MSG_RESULT([print -r]) ;;
+  *) AC_MSG_RESULT([cat]) ;;
+esac
+
+m4_ifdef([_AS_DETECT_SUGGESTED],
+[_AS_DETECT_SUGGESTED([
+  test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || (
+    ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+    ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+    ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+    PATH=/empty FPATH=/empty; export PATH FPATH
+    test "X`printf %s $ECHO`" = "X$ECHO" \
+      || test "X`print -r -- $ECHO`" = "X$ECHO" )])])
+
+_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts])
+_LT_DECL([], [ECHO], [1], [An echo program that protects backslashes])
+])# _LT_PROG_ECHO_BACKSLASH
+
+
+# _LT_WITH_SYSROOT
+# ----------------
+AC_DEFUN([_LT_WITH_SYSROOT],
+[AC_MSG_CHECKING([for sysroot])
+AC_ARG_WITH([sysroot],
+[AS_HELP_STRING([--with-sysroot@<:@=DIR@:>@],
+  [Search for dependent libraries within DIR (or the compiler's sysroot
+   if not specified).])],
+[], [with_sysroot=no])
+
+dnl lt_sysroot will always be passed unquoted.  We quote it here
+dnl in case the user passed a directory name.
+lt_sysroot=
+case $with_sysroot in #(
+ yes)
+   if test yes = "$GCC"; then
+     lt_sysroot=`$CC --print-sysroot 2>/dev/null`
+   fi
+   ;; #(
+ /*)
+   lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"`
+   ;; #(
+ no|'')
+   ;; #(
+ *)
+   AC_MSG_RESULT([$with_sysroot])
+   AC_MSG_ERROR([The sysroot must be an absolute path.])
+   ;;
+esac
+
+ AC_MSG_RESULT([${lt_sysroot:-no}])
+_LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl
+[dependent libraries, and where our libraries should be installed.])])
+
+# _LT_ENABLE_LOCK
+# ---------------
+m4_defun([_LT_ENABLE_LOCK],
+[AC_ARG_ENABLE([libtool-lock],
+  [AS_HELP_STRING([--disable-libtool-lock],
+    [avoid locking (might break parallel builds)])])
+test no = "$enable_libtool_lock" || enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+  # Find out what ABI is being produced by ac_compile, and set mode
+  # options accordingly.
+  echo 'int i;' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    case `/usr/bin/file conftest.$ac_objext` in
+      *ELF-32*)
+	HPUX_IA64_MODE=32
+	;;
+      *ELF-64*)
+	HPUX_IA64_MODE=64
+	;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+*-*-irix6*)
+  # Find out what ABI is being produced by ac_compile, and set linker
+  # options accordingly.
+  echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    if test yes = "$lt_cv_prog_gnu_ld"; then
+      case `/usr/bin/file conftest.$ac_objext` in
+	*32-bit*)
+	  LD="${LD-ld} -melf32bsmip"
+	  ;;
+	*N32*)
+	  LD="${LD-ld} -melf32bmipn32"
+	  ;;
+	*64-bit*)
+	  LD="${LD-ld} -melf64bmip"
+	;;
+      esac
+    else
+      case `/usr/bin/file conftest.$ac_objext` in
+	*32-bit*)
+	  LD="${LD-ld} -32"
+	  ;;
+	*N32*)
+	  LD="${LD-ld} -n32"
+	  ;;
+	*64-bit*)
+	  LD="${LD-ld} -64"
+	  ;;
+      esac
+    fi
+  fi
+  rm -rf conftest*
+  ;;
+
+mips64*-*linux*)
+  # Find out what ABI is being produced by ac_compile, and set linker
+  # options accordingly.
+  echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    emul=elf
+    case `/usr/bin/file conftest.$ac_objext` in
+      *32-bit*)
+	emul="${emul}32"
+	;;
+      *64-bit*)
+	emul="${emul}64"
+	;;
+    esac
+    case `/usr/bin/file conftest.$ac_objext` in
+      *MSB*)
+	emul="${emul}btsmip"
+	;;
+      *LSB*)
+	emul="${emul}ltsmip"
+	;;
+    esac
+    case `/usr/bin/file conftest.$ac_objext` in
+      *N32*)
+	emul="${emul}n32"
+	;;
+    esac
+    LD="${LD-ld} -m $emul"
+  fi
+  rm -rf conftest*
+  ;;
+
+x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \
+s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
+  # Find out what ABI is being produced by ac_compile, and set linker
+  # options accordingly.  Note that the listed cases only cover the
+  # situations where additional linker options are needed (such as when
+  # doing 32-bit compilation for a host where ld defaults to 64-bit, or
+  # vice versa); the common cases where no linker options are needed do
+  # not appear in the list.
+  echo 'int i;' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    case `/usr/bin/file conftest.o` in
+      *32-bit*)
+	case $host in
+	  x86_64-*kfreebsd*-gnu)
+	    LD="${LD-ld} -m elf_i386_fbsd"
+	    ;;
+	  x86_64-*linux*)
+	    case `/usr/bin/file conftest.o` in
+	      *x86-64*)
+		LD="${LD-ld} -m elf32_x86_64"
+		;;
+	      *)
+		LD="${LD-ld} -m elf_i386"
+		;;
+	    esac
+	    ;;
+	  powerpc64le-*linux*)
+	    LD="${LD-ld} -m elf32lppclinux"
+	    ;;
+	  powerpc64-*linux*)
+	    LD="${LD-ld} -m elf32ppclinux"
+	    ;;
+	  s390x-*linux*)
+	    LD="${LD-ld} -m elf_s390"
+	    ;;
+	  sparc64-*linux*)
+	    LD="${LD-ld} -m elf32_sparc"
+	    ;;
+	esac
+	;;
+      *64-bit*)
+	case $host in
+	  x86_64-*kfreebsd*-gnu)
+	    LD="${LD-ld} -m elf_x86_64_fbsd"
+	    ;;
+	  x86_64-*linux*)
+	    LD="${LD-ld} -m elf_x86_64"
+	    ;;
+	  powerpcle-*linux*)
+	    LD="${LD-ld} -m elf64lppc"
+	    ;;
+	  powerpc-*linux*)
+	    LD="${LD-ld} -m elf64ppc"
+	    ;;
+	  s390*-*linux*|s390*-*tpf*)
+	    LD="${LD-ld} -m elf64_s390"
+	    ;;
+	  sparc*-*linux*)
+	    LD="${LD-ld} -m elf64_sparc"
+	    ;;
+	esac
+	;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+
+*-*-sco3.2v5*)
+  # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+  SAVE_CFLAGS=$CFLAGS
+  CFLAGS="$CFLAGS -belf"
+  AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
+    [AC_LANG_PUSH(C)
+     AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])
+     AC_LANG_POP])
+  if test yes != "$lt_cv_cc_needs_belf"; then
+    # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+    CFLAGS=$SAVE_CFLAGS
+  fi
+  ;;
+*-*solaris*)
+  # Find out what ABI is being produced by ac_compile, and set linker
+  # options accordingly.
+  echo 'int i;' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    case `/usr/bin/file conftest.o` in
+    *64-bit*)
+      case $lt_cv_prog_gnu_ld in
+      yes*)
+        case $host in
+        i?86-*-solaris*|x86_64-*-solaris*)
+          LD="${LD-ld} -m elf_x86_64"
+          ;;
+        sparc*-*-solaris*)
+          LD="${LD-ld} -m elf64_sparc"
+          ;;
+        esac
+        # GNU ld 2.21 introduced _sol2 emulations.  Use them if available.
+        if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then
+          LD=${LD-ld}_sol2
+        fi
+        ;;
+      *)
+	if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
+	  LD="${LD-ld} -64"
+	fi
+	;;
+      esac
+      ;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+esac
+
+need_locks=$enable_libtool_lock
+])# _LT_ENABLE_LOCK
+
+
+# _LT_PROG_AR
+# -----------
+m4_defun([_LT_PROG_AR],
+[AC_CHECK_TOOLS(AR, [ar], false)
+: ${AR=ar}
+: ${AR_FLAGS=cru}
+_LT_DECL([], [AR], [1], [The archiver])
+_LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive])
+
+AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file],
+  [lt_cv_ar_at_file=no
+   AC_COMPILE_IFELSE([AC_LANG_PROGRAM],
+     [echo conftest.$ac_objext > conftest.lst
+      lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD'
+      AC_TRY_EVAL([lt_ar_try])
+      if test 0 -eq "$ac_status"; then
+	# Ensure the archiver fails upon bogus file names.
+	rm -f conftest.$ac_objext libconftest.a
+	AC_TRY_EVAL([lt_ar_try])
+	if test 0 -ne "$ac_status"; then
+          lt_cv_ar_at_file=@
+        fi
+      fi
+      rm -f conftest.* libconftest.a
+     ])
+  ])
+
+if test no = "$lt_cv_ar_at_file"; then
+  archiver_list_spec=
+else
+  archiver_list_spec=$lt_cv_ar_at_file
+fi
+_LT_DECL([], [archiver_list_spec], [1],
+  [How to feed a file listing to the archiver])
+])# _LT_PROG_AR
+
+
+# _LT_CMD_OLD_ARCHIVE
+# -------------------
+m4_defun([_LT_CMD_OLD_ARCHIVE],
+[_LT_PROG_AR
+
+AC_CHECK_TOOL(STRIP, strip, :)
+test -z "$STRIP" && STRIP=:
+_LT_DECL([], [STRIP], [1], [A symbol stripping program])
+
+AC_CHECK_TOOL(RANLIB, ranlib, :)
+test -z "$RANLIB" && RANLIB=:
+_LT_DECL([], [RANLIB], [1],
+    [Commands used to install an old-style archive])
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+  case $host_os in
+  bitrig* | openbsd*)
+    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib"
+    ;;
+  *)
+    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib"
+    ;;
+  esac
+  old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib"
+fi
+
+case $host_os in
+  darwin*)
+    lock_old_archive_extraction=yes ;;
+  *)
+    lock_old_archive_extraction=no ;;
+esac
+_LT_DECL([], [old_postinstall_cmds], [2])
+_LT_DECL([], [old_postuninstall_cmds], [2])
+_LT_TAGDECL([], [old_archive_cmds], [2],
+    [Commands used to build an old-style archive])
+_LT_DECL([], [lock_old_archive_extraction], [0],
+    [Whether to use a lock for old archive extraction])
+])# _LT_CMD_OLD_ARCHIVE
+
+
+# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+#		[OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------------------
+# Check whether the given compiler option works
+AC_DEFUN([_LT_COMPILER_OPTION],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_SED])dnl
+AC_CACHE_CHECK([$1], [$2],
+  [$2=no
+   m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4])
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+   lt_compiler_flag="$3"  ## exclude from sc_useless_quotes_in_assignment
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   # The option is referenced via a variable to avoid confusing sed.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&AS_MESSAGE_LOG_FD
+   echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+   if (exit $ac_status) && test -s "$ac_outfile"; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings other than the usual output.
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+       $2=yes
+     fi
+   fi
+   $RM conftest*
+])
+
+if test yes = "[$]$2"; then
+    m4_if([$5], , :, [$5])
+else
+    m4_if([$6], , :, [$6])
+fi
+])# _LT_COMPILER_OPTION
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], [])
+
+
+# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+#                  [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------
+# Check whether the given linker option works
+AC_DEFUN([_LT_LINKER_OPTION],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_SED])dnl
+AC_CACHE_CHECK([$1], [$2],
+  [$2=no
+   save_LDFLAGS=$LDFLAGS
+   LDFLAGS="$LDFLAGS $3"
+   echo "$lt_simple_link_test_code" > conftest.$ac_ext
+   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+     # The linker can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test -s conftest.err; then
+       # Append any errors to the config.log.
+       cat conftest.err 1>&AS_MESSAGE_LOG_FD
+       $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+       if diff conftest.exp conftest.er2 >/dev/null; then
+         $2=yes
+       fi
+     else
+       $2=yes
+     fi
+   fi
+   $RM -r conftest*
+   LDFLAGS=$save_LDFLAGS
+])
+
+if test yes = "[$]$2"; then
+    m4_if([$4], , :, [$4])
+else
+    m4_if([$5], , :, [$5])
+fi
+])# _LT_LINKER_OPTION
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], [])
+
+
+# LT_CMD_MAX_LEN
+#---------------
+AC_DEFUN([LT_CMD_MAX_LEN],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+# find the maximum length of command line arguments
+AC_MSG_CHECKING([the maximum length of command line arguments])
+AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
+  i=0
+  teststring=ABCD
+
+  case $build_os in
+  msdosdjgpp*)
+    # On DJGPP, this test can blow up pretty badly due to problems in libc
+    # (any single argument exceeding 2000 bytes causes a buffer overrun
+    # during glob expansion).  Even if it were fixed, the result of this
+    # check would be larger than it should be.
+    lt_cv_sys_max_cmd_len=12288;    # 12K is about right
+    ;;
+
+  gnu*)
+    # Under GNU Hurd, this test is not required because there is
+    # no limit to the length of command line arguments.
+    # Libtool will interpret -1 as no limit whatsoever
+    lt_cv_sys_max_cmd_len=-1;
+    ;;
+
+  cygwin* | mingw* | cegcc*)
+    # On Win9x/ME, this test blows up -- it succeeds, but takes
+    # about 5 minutes as the teststring grows exponentially.
+    # Worse, since 9x/ME are not pre-emptively multitasking,
+    # you end up with a "frozen" computer, even though with patience
+    # the test eventually succeeds (with a max line length of 256k).
+    # Instead, let's just punt: use the minimum linelength reported by
+    # all of the supported platforms: 8192 (on NT/2K/XP).
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  mint*)
+    # On MiNT this can take a long time and run out of memory.
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  amigaos*)
+    # On AmigaOS with pdksh, this test takes hours, literally.
+    # So we just punt and use a minimum line length of 8192.
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  bitrig* | darwin* | dragonfly* | freebsd* | netbsd* | openbsd*)
+    # This has been around since 386BSD, at least.  Likely further.
+    if test -x /sbin/sysctl; then
+      lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+    elif test -x /usr/sbin/sysctl; then
+      lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+    else
+      lt_cv_sys_max_cmd_len=65536	# usable default for all BSDs
+    fi
+    # And add a safety zone
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+    ;;
+
+  interix*)
+    # We know the value 262144 and hardcode it with a safety zone (like BSD)
+    lt_cv_sys_max_cmd_len=196608
+    ;;
+
+  os2*)
+    # The test takes a long time on OS/2.
+    lt_cv_sys_max_cmd_len=8192
+    ;;
+
+  osf*)
+    # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+    # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+    # nice to cause kernel panics so lets avoid the loop below.
+    # First set a reasonable default.
+    lt_cv_sys_max_cmd_len=16384
+    #
+    if test -x /sbin/sysconfig; then
+      case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+        *1*) lt_cv_sys_max_cmd_len=-1 ;;
+      esac
+    fi
+    ;;
+  sco3.2v5*)
+    lt_cv_sys_max_cmd_len=102400
+    ;;
+  sysv5* | sco5v6* | sysv4.2uw2*)
+    kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+    if test -n "$kargmax"; then
+      lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[	 ]]//'`
+    else
+      lt_cv_sys_max_cmd_len=32768
+    fi
+    ;;
+  *)
+    lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
+    if test -n "$lt_cv_sys_max_cmd_len" && \
+       test undefined != "$lt_cv_sys_max_cmd_len"; then
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+    else
+      # Make teststring a little bigger before we do anything with it.
+      # a 1K string should be a reasonable start.
+      for i in 1 2 3 4 5 6 7 8; do
+        teststring=$teststring$teststring
+      done
+      SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+      # If test is not a shell built-in, we'll probably end up computing a
+      # maximum length that is only half of the actual maximum length, but
+      # we can't tell.
+      while { test X`env echo "$teststring$teststring" 2>/dev/null` \
+	         = "X$teststring$teststring"; } >/dev/null 2>&1 &&
+	      test 17 != "$i" # 1/2 MB should be enough
+      do
+        i=`expr $i + 1`
+        teststring=$teststring$teststring
+      done
+      # Only check the string length outside the loop.
+      lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
+      teststring=
+      # Add a significant safety factor because C++ compilers can tack on
+      # massive amounts of additional arguments before passing them to the
+      # linker.  It appears as though 1/2 is a usable value.
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+    fi
+    ;;
+  esac
+])
+if test -n "$lt_cv_sys_max_cmd_len"; then
+  AC_MSG_RESULT($lt_cv_sys_max_cmd_len)
+else
+  AC_MSG_RESULT(none)
+fi
+max_cmd_len=$lt_cv_sys_max_cmd_len
+_LT_DECL([], [max_cmd_len], [0],
+    [What is the maximum length of a command?])
+])# LT_CMD_MAX_LEN
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], [])
+
+
+# _LT_HEADER_DLFCN
+# ----------------
+m4_defun([_LT_HEADER_DLFCN],
+[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl
+])# _LT_HEADER_DLFCN
+
+
+# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE,
+#                      ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING)
+# ----------------------------------------------------------------
+m4_defun([_LT_TRY_DLOPEN_SELF],
+[m4_require([_LT_HEADER_DLFCN])dnl
+if test yes = "$cross_compiling"; then :
+  [$4]
+else
+  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+  lt_status=$lt_dlunknown
+  cat > conftest.$ac_ext <<_LT_EOF
+[#line $LINENO "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+#  define LT_DLGLOBAL		RTLD_GLOBAL
+#else
+#  ifdef DL_GLOBAL
+#    define LT_DLGLOBAL		DL_GLOBAL
+#  else
+#    define LT_DLGLOBAL		0
+#  endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+   find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+#  ifdef RTLD_LAZY
+#    define LT_DLLAZY_OR_NOW		RTLD_LAZY
+#  else
+#    ifdef DL_LAZY
+#      define LT_DLLAZY_OR_NOW		DL_LAZY
+#    else
+#      ifdef RTLD_NOW
+#        define LT_DLLAZY_OR_NOW	RTLD_NOW
+#      else
+#        ifdef DL_NOW
+#          define LT_DLLAZY_OR_NOW	DL_NOW
+#        else
+#          define LT_DLLAZY_OR_NOW	0
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+/* When -fvisibility=hidden is used, assume the code has been annotated
+   correspondingly for the symbols needed.  */
+#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+int fnord () __attribute__((visibility("default")));
+#endif
+
+int fnord () { return 42; }
+int main ()
+{
+  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+  int status = $lt_dlunknown;
+
+  if (self)
+    {
+      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
+      else
+        {
+	  if (dlsym( self,"_fnord"))  status = $lt_dlneed_uscore;
+          else puts (dlerror ());
+	}
+      /* dlclose (self); */
+    }
+  else
+    puts (dlerror ());
+
+  return status;
+}]
+_LT_EOF
+  if AC_TRY_EVAL(ac_link) && test -s "conftest$ac_exeext" 2>/dev/null; then
+    (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null
+    lt_status=$?
+    case x$lt_status in
+      x$lt_dlno_uscore) $1 ;;
+      x$lt_dlneed_uscore) $2 ;;
+      x$lt_dlunknown|x*) $3 ;;
+    esac
+  else :
+    # compilation failed
+    $3
+  fi
+fi
+rm -fr conftest*
+])# _LT_TRY_DLOPEN_SELF
+
+
+# LT_SYS_DLOPEN_SELF
+# ------------------
+AC_DEFUN([LT_SYS_DLOPEN_SELF],
+[m4_require([_LT_HEADER_DLFCN])dnl
+if test yes != "$enable_dlopen"; then
+  enable_dlopen=unknown
+  enable_dlopen_self=unknown
+  enable_dlopen_self_static=unknown
+else
+  lt_cv_dlopen=no
+  lt_cv_dlopen_libs=
+
+  case $host_os in
+  beos*)
+    lt_cv_dlopen=load_add_on
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+    ;;
+
+  mingw* | pw32* | cegcc*)
+    lt_cv_dlopen=LoadLibrary
+    lt_cv_dlopen_libs=
+    ;;
+
+  cygwin*)
+    lt_cv_dlopen=dlopen
+    lt_cv_dlopen_libs=
+    ;;
+
+  darwin*)
+    # if libdl is installed we need to link against it
+    AC_CHECK_LIB([dl], [dlopen],
+		[lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl],[
+    lt_cv_dlopen=dyld
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+    ])
+    ;;
+
+  tpf*)
+    # Don't try to run any link tests for TPF.  We know it's impossible
+    # because TPF is a cross-compiler, and we know how we open DSOs.
+    lt_cv_dlopen=dlopen
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=no
+    ;;
+
+  *)
+    AC_CHECK_FUNC([shl_load],
+	  [lt_cv_dlopen=shl_load],
+      [AC_CHECK_LIB([dld], [shl_load],
+	    [lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld],
+	[AC_CHECK_FUNC([dlopen],
+	      [lt_cv_dlopen=dlopen],
+	  [AC_CHECK_LIB([dl], [dlopen],
+		[lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl],
+	    [AC_CHECK_LIB([svld], [dlopen],
+		  [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld],
+	      [AC_CHECK_LIB([dld], [dld_link],
+		    [lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld])
+	      ])
+	    ])
+	  ])
+	])
+      ])
+    ;;
+  esac
+
+  if test no = "$lt_cv_dlopen"; then
+    enable_dlopen=no
+  else
+    enable_dlopen=yes
+  fi
+
+  case $lt_cv_dlopen in
+  dlopen)
+    save_CPPFLAGS=$CPPFLAGS
+    test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+    save_LDFLAGS=$LDFLAGS
+    wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+    save_LIBS=$LIBS
+    LIBS="$lt_cv_dlopen_libs $LIBS"
+
+    AC_CACHE_CHECK([whether a program can dlopen itself],
+	  lt_cv_dlopen_self, [dnl
+	  _LT_TRY_DLOPEN_SELF(
+	    lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes,
+	    lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross)
+    ])
+
+    if test yes = "$lt_cv_dlopen_self"; then
+      wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
+      AC_CACHE_CHECK([whether a statically linked program can dlopen itself],
+	  lt_cv_dlopen_self_static, [dnl
+	  _LT_TRY_DLOPEN_SELF(
+	    lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes,
+	    lt_cv_dlopen_self_static=no,  lt_cv_dlopen_self_static=cross)
+      ])
+    fi
+
+    CPPFLAGS=$save_CPPFLAGS
+    LDFLAGS=$save_LDFLAGS
+    LIBS=$save_LIBS
+    ;;
+  esac
+
+  case $lt_cv_dlopen_self in
+  yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+  *) enable_dlopen_self=unknown ;;
+  esac
+
+  case $lt_cv_dlopen_self_static in
+  yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+  *) enable_dlopen_self_static=unknown ;;
+  esac
+fi
+_LT_DECL([dlopen_support], [enable_dlopen], [0],
+	 [Whether dlopen is supported])
+_LT_DECL([dlopen_self], [enable_dlopen_self], [0],
+	 [Whether dlopen of programs is supported])
+_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0],
+	 [Whether dlopen of statically linked programs is supported])
+])# LT_SYS_DLOPEN_SELF
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], [])
+
+
+# _LT_COMPILER_C_O([TAGNAME])
+# ---------------------------
+# Check to see if options -c and -o are simultaneously supported by compiler.
+# This macro does not hard code the compiler like AC_PROG_CC_C_O.
+m4_defun([_LT_COMPILER_C_O],
+[m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext],
+  [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)],
+  [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no
+   $RM -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&AS_MESSAGE_LOG_FD
+   echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+       _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+     fi
+   fi
+   chmod u+w . 2>&AS_MESSAGE_LOG_FD
+   $RM conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+   $RM out/* && rmdir out
+   cd ..
+   $RM -r conftest
+   $RM conftest*
+])
+_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1],
+	[Does compiler simultaneously support -c and -o options?])
+])# _LT_COMPILER_C_O
+
+
+# _LT_COMPILER_FILE_LOCKS([TAGNAME])
+# ----------------------------------
+# Check to see if we can do hard links to lock some files if needed
+m4_defun([_LT_COMPILER_FILE_LOCKS],
+[m4_require([_LT_ENABLE_LOCK])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+_LT_COMPILER_C_O([$1])
+
+hard_links=nottested
+if test no = "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" && test no != "$need_locks"; then
+  # do not overwrite the value of need_locks provided by the user
+  AC_MSG_CHECKING([if we can lock with hard links])
+  hard_links=yes
+  $RM conftest*
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  touch conftest.a
+  ln conftest.a conftest.b 2>&5 || hard_links=no
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  AC_MSG_RESULT([$hard_links])
+  if test no = "$hard_links"; then
+    AC_MSG_WARN(['$CC' does not support '-c -o', so 'make -j' may be unsafe])
+    need_locks=warn
+  fi
+else
+  need_locks=no
+fi
+_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?])
+])# _LT_COMPILER_FILE_LOCKS
+
+
+# _LT_CHECK_OBJDIR
+# ----------------
+m4_defun([_LT_CHECK_OBJDIR],
+[AC_CACHE_CHECK([for objdir], [lt_cv_objdir],
+[rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+  lt_cv_objdir=.libs
+else
+  # MS-DOS does not allow filenames that begin with a dot.
+  lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null])
+objdir=$lt_cv_objdir
+_LT_DECL([], [objdir], [0],
+         [The name of the directory that contains temporary libtool files])dnl
+m4_pattern_allow([LT_OBJDIR])dnl
+AC_DEFINE_UNQUOTED([LT_OBJDIR], "$lt_cv_objdir/",
+  [Define to the sub-directory where libtool stores uninstalled libraries.])
+])# _LT_CHECK_OBJDIR
+
+
+# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME])
+# --------------------------------------
+# Check hardcoding attributes.
+m4_defun([_LT_LINKER_HARDCODE_LIBPATH],
+[AC_MSG_CHECKING([how to hardcode library paths into programs])
+_LT_TAGVAR(hardcode_action, $1)=
+if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" ||
+   test -n "$_LT_TAGVAR(runpath_var, $1)" ||
+   test yes = "$_LT_TAGVAR(hardcode_automatic, $1)"; then
+
+  # We can hardcode non-existent directories.
+  if test no != "$_LT_TAGVAR(hardcode_direct, $1)" &&
+     # If the only mechanism to avoid hardcoding is shlibpath_var, we
+     # have to relink, otherwise we might link with an installed library
+     # when we should be linking with a yet-to-be-installed one
+     ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" &&
+     test no != "$_LT_TAGVAR(hardcode_minus_L, $1)"; then
+    # Linking always hardcodes the temporary library directory.
+    _LT_TAGVAR(hardcode_action, $1)=relink
+  else
+    # We can link without hardcoding, and we can hardcode nonexisting dirs.
+    _LT_TAGVAR(hardcode_action, $1)=immediate
+  fi
+else
+  # We cannot hardcode anything, or else we can only hardcode existing
+  # directories.
+  _LT_TAGVAR(hardcode_action, $1)=unsupported
+fi
+AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)])
+
+if test relink = "$_LT_TAGVAR(hardcode_action, $1)" ||
+   test yes = "$_LT_TAGVAR(inherit_rpath, $1)"; then
+  # Fast installation is not supported
+  enable_fast_install=no
+elif test yes = "$shlibpath_overrides_runpath" ||
+     test no = "$enable_shared"; then
+  # Fast installation is not necessary
+  enable_fast_install=needless
+fi
+_LT_TAGDECL([], [hardcode_action], [0],
+    [How to hardcode a shared library path into an executable])
+])# _LT_LINKER_HARDCODE_LIBPATH
+
+
+# _LT_CMD_STRIPLIB
+# ----------------
+m4_defun([_LT_CMD_STRIPLIB],
+[m4_require([_LT_DECL_EGREP])
+striplib=
+old_striplib=
+AC_MSG_CHECKING([whether stripping libraries is possible])
+if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
+  test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+  test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+  AC_MSG_RESULT([yes])
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+  case $host_os in
+  darwin*)
+    if test -n "$STRIP"; then
+      striplib="$STRIP -x"
+      old_striplib="$STRIP -S"
+      AC_MSG_RESULT([yes])
+    else
+      AC_MSG_RESULT([no])
+    fi
+    ;;
+  *)
+    AC_MSG_RESULT([no])
+    ;;
+  esac
+fi
+_LT_DECL([], [old_striplib], [1], [Commands to strip libraries])
+_LT_DECL([], [striplib], [1])
+])# _LT_CMD_STRIPLIB
+
+
+# _LT_PREPARE_MUNGE_PATH_LIST
+# ---------------------------
+# Make sure func_munge_path_list() is defined correctly.
+m4_defun([_LT_PREPARE_MUNGE_PATH_LIST],
+[[# func_munge_path_list VARIABLE PATH
+# -----------------------------------
+# VARIABLE is name of variable containing _space_ separated list of
+# directories to be munged by the contents of PATH, which is string
+# having a format:
+# "DIR[:DIR]:"
+#       string "DIR[ DIR]" will be prepended to VARIABLE
+# ":DIR[:DIR]"
+#       string "DIR[ DIR]" will be appended to VARIABLE
+# "DIRP[:DIRP]::[DIRA:]DIRA"
+#       string "DIRP[ DIRP]" will be prepended to VARIABLE and string
+#       "DIRA[ DIRA]" will be appended to VARIABLE
+# "DIR[:DIR]"
+#       VARIABLE will be replaced by "DIR[ DIR]"
+func_munge_path_list ()
+{
+    case x@S|@2 in
+    x)
+        ;;
+    *:)
+        eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'` \@S|@@S|@1\"
+        ;;
+    x:*)
+        eval @S|@1=\"\@S|@@S|@1 `$ECHO @S|@2 | $SED 's/:/ /g'`\"
+        ;;
+    *::*)
+        eval @S|@1=\"\@S|@@S|@1\ `$ECHO @S|@2 | $SED -e 's/.*:://' -e 's/:/ /g'`\"
+        eval @S|@1=\"`$ECHO @S|@2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \@S|@@S|@1\"
+        ;;
+    *)
+        eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'`\"
+        ;;
+    esac
+}
+]])# _LT_PREPARE_PATH_LIST
+
+
+# _LT_SYS_DYNAMIC_LINKER([TAG])
+# -----------------------------
+# PORTME Fill in your ld.so characteristics
+m4_defun([_LT_SYS_DYNAMIC_LINKER],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_OBJDUMP])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_CHECK_SHELL_FEATURES])dnl
+m4_require([_LT_PREPARE_MUNGE_PATH_LIST])dnl
+AC_MSG_CHECKING([dynamic linker characteristics])
+m4_if([$1],
+	[], [
+if test yes = "$GCC"; then
+  case $host_os in
+    darwin*) lt_awk_arg='/^libraries:/,/LR/' ;;
+    *) lt_awk_arg='/^libraries:/' ;;
+  esac
+  case $host_os in
+    mingw* | cegcc*) lt_sed_strip_eq='s|=\([[A-Za-z]]:\)|\1|g' ;;
+    *) lt_sed_strip_eq='s|=/|/|g' ;;
+  esac
+  lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
+  case $lt_search_path_spec in
+  *\;*)
+    # if the path contains ";" then we assume it to be the separator
+    # otherwise default to the standard path separator (i.e. ":") - it is
+    # assumed that no part of a normal pathname contains ";" but that should
+    # okay in the real world where ";" in dirpaths is itself problematic.
+    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'`
+    ;;
+  *)
+    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
+    ;;
+  esac
+  # Ok, now we have the path, separated by spaces, we can step through it
+  # and add multilib dir if necessary...
+  lt_tmp_lt_search_path_spec=
+  lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+  # ...but if some path component already ends with the multilib dir we assume
+  # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer).
+  case "$lt_multi_os_dir; $lt_search_path_spec " in
+  "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*)
+    lt_multi_os_dir=
+    ;;
+  esac
+  for lt_sys_path in $lt_search_path_spec; do
+    if test -d "$lt_sys_path$lt_multi_os_dir"; then
+      lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir"
+    elif test -n "$lt_multi_os_dir"; then
+      test -d "$lt_sys_path" && \
+	lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
+    fi
+  done
+  lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
+BEGIN {RS = " "; FS = "/|\n";} {
+  lt_foo = "";
+  lt_count = 0;
+  for (lt_i = NF; lt_i > 0; lt_i--) {
+    if ($lt_i != "" && $lt_i != ".") {
+      if ($lt_i == "..") {
+        lt_count++;
+      } else {
+        if (lt_count == 0) {
+          lt_foo = "/" $lt_i lt_foo;
+        } else {
+          lt_count--;
+        }
+      }
+    }
+  }
+  if (lt_foo != "") { lt_freq[[lt_foo]]++; }
+  if (lt_freq[[lt_foo]] == 1) { print lt_foo; }
+}'`
+  # AWK program above erroneously prepends '/' to C:/dos/paths
+  # for these hosts.
+  case $host_os in
+    mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
+      $SED 's|/\([[A-Za-z]]:\)|\1|g'` ;;
+  esac
+  sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
+else
+  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi])
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=.so
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+AC_ARG_VAR([LT_SYS_LIBRARY_PATH],
+[User-defined run-time library search path.])
+
+case $host_os in
+aix3*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='$libname$release$shared_ext$versuffix $libname.a'
+  shlibpath_var=LIBPATH
+
+  # AIX 3 has no versioning support, so we append a major version to the name.
+  soname_spec='$libname$release$shared_ext$major'
+  ;;
+
+aix[[4-9]]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  hardcode_into_libs=yes
+  if test ia64 = "$host_cpu"; then
+    # AIX 5 supports IA64
+    library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext'
+    shlibpath_var=LD_LIBRARY_PATH
+  else
+    # With GCC up to 2.95.x, collect2 would create an import file
+    # for dependence libraries.  The import file would start with
+    # the line '#! .'.  This would cause the generated library to
+    # depend on '.', always an invalid library.  This was fixed in
+    # development snapshots of GCC prior to 3.0.
+    case $host_os in
+      aix4 | aix4.[[01]] | aix4.[[01]].*)
+      if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+	   echo ' yes '
+	   echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then
+	:
+      else
+	can_build_shared=no
+      fi
+      ;;
+    esac
+    # Using Import Files as archive members, it is possible to support
+    # filename-based versioning of shared library archives on AIX. While
+    # this would work for both with and without runtime linking, it will
+    # prevent static linking of such archives. So we do filename-based
+    # shared library versioning with .so extension only, which is used
+    # when both runtime linking and shared linking is enabled.
+    # Unfortunately, runtime linking may impact performance, so we do
+    # not want this to be the default eventually. Also, we use the
+    # versioned .so libs for executables only if there is the -brtl
+    # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only.
+    # To allow for filename-based versioning support, we need to create
+    # libNAME.so.V as an archive file, containing:
+    # *) an Import File, referring to the versioned filename of the
+    #    archive as well as the shared archive member, telling the
+    #    bitwidth (32 or 64) of that shared object, and providing the
+    #    list of exported symbols of that shared object, eventually
+    #    decorated with the 'weak' keyword
+    # *) the shared object with the F_LOADONLY flag set, to really avoid
+    #    it being seen by the linker.
+    # At run time we better use the real file rather than another symlink,
+    # but for link time we create the symlink libNAME.so -> libNAME.so.V
+
+    case $with_aix_soname,$aix_use_runtimelinking in
+    # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct
+    # soname into executable. Probably we can add versioning support to
+    # collect2, so additional links can be useful in future.
+    aix,yes) # traditional libtool
+      dynamic_linker='AIX unversionable lib.so'
+      # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+      # instead of lib<name>.a to let people know that these are not
+      # typical AIX shared libraries.
+      library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+      ;;
+    aix,no) # traditional AIX only
+      dynamic_linker='AIX lib.a[(]lib.so.V[)]'
+      # We preserve .a as extension for shared libraries through AIX4.2
+      # and later when we are not doing run time linking.
+      library_names_spec='$libname$release.a $libname.a'
+      soname_spec='$libname$release$shared_ext$major'
+      ;;
+    svr4,*) # full svr4 only
+      dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)]"
+      library_names_spec='$libname$release$shared_ext$major $libname$shared_ext'
+      # We do not specify a path in Import Files, so LIBPATH fires.
+      shlibpath_overrides_runpath=yes
+      ;;
+    *,yes) # both, prefer svr4
+      dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)], lib.a[(]lib.so.V[)]"
+      library_names_spec='$libname$release$shared_ext$major $libname$shared_ext'
+      # unpreferred sharedlib libNAME.a needs extra handling
+      postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"'
+      postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"'
+      # We do not specify a path in Import Files, so LIBPATH fires.
+      shlibpath_overrides_runpath=yes
+      ;;
+    *,no) # both, prefer aix
+      dynamic_linker="AIX lib.a[(]lib.so.V[)], lib.so.V[(]$shared_archive_member_spec.o[)]"
+      library_names_spec='$libname$release.a $libname.a'
+      soname_spec='$libname$release$shared_ext$major'
+      # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling
+      postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)'
+      postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"'
+      ;;
+    esac
+    shlibpath_var=LIBPATH
+  fi
+  ;;
+
+amigaos*)
+  case $host_cpu in
+  powerpc)
+    # Since July 2007 AmigaOS4 officially supports .so libraries.
+    # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+    ;;
+  m68k)
+    library_names_spec='$libname.ixlibrary $libname.a'
+    # Create ${libname}_ixlibrary.a entries in /sys/libs.
+    finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+    ;;
+  esac
+  ;;
+
+beos*)
+  library_names_spec='$libname$shared_ext'
+  dynamic_linker="$host_os ld.so"
+  shlibpath_var=LIBRARY_PATH
+  ;;
+
+bsdi[[45]]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+  sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+  # the default ld.so.conf also contains /usr/contrib/lib and
+  # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+  # libtool to hard-code these into programs
+  ;;
+
+cygwin* | mingw* | pw32* | cegcc*)
+  version_type=windows
+  shrext_cmds=.dll
+  need_version=no
+  need_lib_prefix=no
+
+  case $GCC,$cc_basename in
+  yes,*)
+    # gcc
+    library_names_spec='$libname.dll.a'
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \$file`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname~
+      chmod a+x \$dldir/$dlname~
+      if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+        eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+      fi'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $RM \$dlpath'
+    shlibpath_overrides_runpath=yes
+
+    case $host_os in
+    cygwin*)
+      # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+      soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
+m4_if([$1], [],[
+      sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"])
+      ;;
+    mingw* | cegcc*)
+      # MinGW DLLs use traditional 'lib' prefix
+      soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
+      ;;
+    pw32*)
+      # pw32 DLLs use 'pw' prefix rather than 'lib'
+      library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
+      ;;
+    esac
+    dynamic_linker='Win32 ld.exe'
+    ;;
+
+  *,cl*)
+    # Native MSVC
+    libname_spec='$name'
+    soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
+    library_names_spec='$libname.dll.lib'
+
+    case $build_os in
+    mingw*)
+      sys_lib_search_path_spec=
+      lt_save_ifs=$IFS
+      IFS=';'
+      for lt_path in $LIB
+      do
+        IFS=$lt_save_ifs
+        # Let DOS variable expansion print the short 8.3 style file name.
+        lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"`
+        sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path"
+      done
+      IFS=$lt_save_ifs
+      # Convert to MSYS style.
+      sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'`
+      ;;
+    cygwin*)
+      # Convert to unix form, then to dos form, then back to unix form
+      # but this time dos style (no spaces!) so that the unix form looks
+      # like /cygdrive/c/PROGRA~1:/cygdr...
+      sys_lib_search_path_spec=`cygpath --path --unix "$LIB"`
+      sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null`
+      sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+      ;;
+    *)
+      sys_lib_search_path_spec=$LIB
+      if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then
+        # It is most probably a Windows format PATH.
+        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+      else
+        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+      fi
+      # FIXME: find the short name or the path components, as spaces are
+      # common. (e.g. "Program Files" -> "PROGRA~1")
+      ;;
+    esac
+
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \$file`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $RM \$dlpath'
+    shlibpath_overrides_runpath=yes
+    dynamic_linker='Win32 link.exe'
+    ;;
+
+  *)
+    # Assume MSVC wrapper
+    library_names_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext $libname.lib'
+    dynamic_linker='Win32 ld.exe'
+    ;;
+  esac
+  # FIXME: first we should search . and the directory the executable is in
+  shlibpath_var=PATH
+  ;;
+
+darwin* | rhapsody*)
+  dynamic_linker="$host_os dyld"
+  version_type=darwin
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$major$shared_ext $libname$shared_ext'
+  soname_spec='$libname$release$major$shared_ext'
+  shlibpath_overrides_runpath=yes
+  shlibpath_var=DYLD_LIBRARY_PATH
+  shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+m4_if([$1], [],[
+  sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"])
+  sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+  ;;
+
+dgux*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+freebsd* | dragonfly*)
+  # DragonFly does not have aout.  When/if they implement a new
+  # versioning mechanism, adjust this.
+  if test -x /usr/bin/objformat; then
+    objformat=`/usr/bin/objformat`
+  else
+    case $host_os in
+    freebsd[[23]].*) objformat=aout ;;
+    *) objformat=elf ;;
+    esac
+  fi
+  version_type=freebsd-$objformat
+  case $version_type in
+    freebsd-elf*)
+      library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+      soname_spec='$libname$release$shared_ext$major'
+      need_version=no
+      need_lib_prefix=no
+      ;;
+    freebsd-*)
+      library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+      need_version=yes
+      ;;
+  esac
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_os in
+  freebsd2.*)
+    shlibpath_overrides_runpath=yes
+    ;;
+  freebsd3.[[01]]* | freebsdelf3.[[01]]*)
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \
+  freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1)
+    shlibpath_overrides_runpath=no
+    hardcode_into_libs=yes
+    ;;
+  *) # from 4.6 on, and DragonFly
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  esac
+  ;;
+
+haiku*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  dynamic_linker="$host_os runtime_loader"
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  shlibpath_var=LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
+  hardcode_into_libs=yes
+  ;;
+
+hpux9* | hpux10* | hpux11*)
+  # Give a soname corresponding to the major version so that dld.sl refuses to
+  # link against other versions.
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  case $host_cpu in
+  ia64*)
+    shrext_cmds='.so'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.so"
+    shlibpath_var=LD_LIBRARY_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+    soname_spec='$libname$release$shared_ext$major'
+    if test 32 = "$HPUX_IA64_MODE"; then
+      sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+      sys_lib_dlsearch_path_spec=/usr/lib/hpux32
+    else
+      sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+      sys_lib_dlsearch_path_spec=/usr/lib/hpux64
+    fi
+    ;;
+  hppa*64*)
+    shrext_cmds='.sl'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+    soname_spec='$libname$release$shared_ext$major'
+    sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+  *)
+    shrext_cmds='.sl'
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=SHLIB_PATH
+    shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+    soname_spec='$libname$release$shared_ext$major'
+    ;;
+  esac
+  # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
+  postinstall_cmds='chmod 555 $lib'
+  # or fails outright, so override atomically:
+  install_override_mode=555
+  ;;
+
+interix[[3-9]]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $host_os in
+    nonstopux*) version_type=nonstopux ;;
+    *)
+	if test yes = "$lt_cv_prog_gnu_ld"; then
+		version_type=linux # correct to gnu/linux during the next big refactor
+	else
+		version_type=irix
+	fi ;;
+  esac
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='$libname$release$shared_ext$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext'
+  case $host_os in
+  irix5* | nonstopux*)
+    libsuff= shlibsuff=
+    ;;
+  *)
+    case $LD in # libtool.m4 will add one of these switches to LD
+    *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+      libsuff= shlibsuff= libmagic=32-bit;;
+    *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+      libsuff=32 shlibsuff=N32 libmagic=N32;;
+    *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+      libsuff=64 shlibsuff=64 libmagic=64-bit;;
+    *) libsuff= shlibsuff= libmagic=never-match;;
+    esac
+    ;;
+  esac
+  shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+  shlibpath_overrides_runpath=no
+  sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff"
+  sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff"
+  hardcode_into_libs=yes
+  ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+  dynamic_linker=no
+  ;;
+
+linux*android*)
+  version_type=none # Android doesn't support versioned libraries.
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext'
+  soname_spec='$libname$release$shared_ext'
+  finish_cmds=
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+
+  # This implies no fast_install, which is unacceptable.
+  # Some rework will be needed to allow for fast_install
+  # before this can be enabled.
+  hardcode_into_libs=yes
+
+  dynamic_linker='Android linker'
+  # Don't embed -rpath directories since the linker doesn't support them.
+  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+  ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+
+  # Some binutils ld are patched to set DT_RUNPATH
+  AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath],
+    [lt_cv_shlibpath_overrides_runpath=no
+    save_LDFLAGS=$LDFLAGS
+    save_libdir=$libdir
+    eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \
+	 LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\""
+    AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
+      [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null],
+	 [lt_cv_shlibpath_overrides_runpath=yes])])
+    LDFLAGS=$save_LDFLAGS
+    libdir=$save_libdir
+    ])
+  shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
+
+  # This implies no fast_install, which is unacceptable.
+  # Some rework will be needed to allow for fast_install
+  # before this can be enabled.
+  hardcode_into_libs=yes
+
+  # Ideally, we could use ldconfig to report *all* directores which are
+  # searched for libraries, however this is still not possible.  Aside from not
+  # being certain /sbin/ldconfig is available, command
+  # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64,
+  # even though it is searched at run-time.  Try to do the best guess by
+  # appending ld.so.conf contents (and includes) to the search path.
+  if test -f /etc/ld.so.conf; then
+    lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[	 ]*hwcap[	 ]/d;s/[:,	]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
+    sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+  fi
+
+  # We used to test for /lib/ld.so.1 and disable shared libraries on
+  # powerpc, because MkLinux only supported shared libraries with the
+  # GNU dynamic linker.  Since this was broken with cross compilers,
+  # most powerpc-linux boxes support dynamic linking these days and
+  # people can always --disable-shared, the test was removed, and we
+  # assume the GNU/Linux dynamic linker is in use.
+  dynamic_linker='GNU/Linux ld.so'
+  ;;
+
+netbsd*)
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+    finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+    dynamic_linker='NetBSD (a.out) ld.so'
+  else
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+    soname_spec='$libname$release$shared_ext$major'
+    dynamic_linker='NetBSD ld.elf_so'
+  fi
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  ;;
+
+newsos6)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+*nto* | *qnx*)
+  version_type=qnx
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='ldqnx.so'
+  ;;
+
+openbsd* | bitrig*)
+  version_type=sunos
+  sys_lib_dlsearch_path_spec=/usr/lib
+  need_lib_prefix=no
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
+    need_version=no
+  else
+    need_version=yes
+  fi
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+os2*)
+  libname_spec='$name'
+  version_type=windows
+  shrext_cmds=.dll
+  need_version=no
+  need_lib_prefix=no
+  # OS/2 can only load a DLL with a base name of 8 characters or less.
+  soname_spec='`test -n "$os2dllname" && libname="$os2dllname";
+    v=$($ECHO $release$versuffix | tr -d .-);
+    n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _);
+    $ECHO $n$v`$shared_ext'
+  library_names_spec='${libname}_dll.$libext'
+  dynamic_linker='OS/2 ld.exe'
+  shlibpath_var=BEGINLIBPATH
+  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+  sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+  postinstall_cmds='base_file=`basename \$file`~
+    dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~
+    dldir=$destdir/`dirname \$dlpath`~
+    test -d \$dldir || mkdir -p \$dldir~
+    $install_prog $dir/$dlname \$dldir/$dlname~
+    chmod a+x \$dldir/$dlname~
+    if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+      eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+    fi'
+  postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~
+    dlpath=$dir/\$dldll~
+    $RM \$dlpath'
+  ;;
+
+osf3* | osf4* | osf5*)
+  version_type=osf
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='$libname$release$shared_ext$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+  sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+  ;;
+
+rdos*)
+  dynamic_linker=no
+  ;;
+
+solaris*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  # ldd complains unless libraries are executable
+  postinstall_cmds='chmod +x $lib'
+  ;;
+
+sunos4*)
+  version_type=sunos
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+  finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  if test yes = "$with_gnu_ld"; then
+    need_lib_prefix=no
+  fi
+  need_version=yes
+  ;;
+
+sysv4 | sysv4.3*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_vendor in
+    sni)
+      shlibpath_overrides_runpath=no
+      need_lib_prefix=no
+      runpath_var=LD_RUN_PATH
+      ;;
+    siemens)
+      need_lib_prefix=no
+      ;;
+    motorola)
+      need_lib_prefix=no
+      need_version=no
+      shlibpath_overrides_runpath=no
+      sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+      ;;
+  esac
+  ;;
+
+sysv4*MP*)
+  if test -d /usr/nec; then
+    version_type=linux # correct to gnu/linux during the next big refactor
+    library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext'
+    soname_spec='$libname$shared_ext.$major'
+    shlibpath_var=LD_LIBRARY_PATH
+  fi
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  version_type=sco
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  if test yes = "$with_gnu_ld"; then
+    sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+  else
+    sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+    case $host_os in
+      sco3.2v5*)
+        sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+	;;
+    esac
+  fi
+  sys_lib_dlsearch_path_spec='/usr/lib'
+  ;;
+
+tpf*)
+  # TPF is a cross-target only.  Preferred cross-host = GNU/Linux.
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+uts4*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+*)
+  dynamic_linker=no
+  ;;
+esac
+AC_MSG_RESULT([$dynamic_linker])
+test no = "$dynamic_linker" && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test yes = "$GCC"; then
+  variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then
+  sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec
+fi
+
+if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then
+  sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec
+fi
+
+# remember unaugmented sys_lib_dlsearch_path content for libtool script decls...
+configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec
+
+# ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code
+func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH"
+
+# to be used as default LT_SYS_LIBRARY_PATH value in generated libtool
+configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH
+
+_LT_DECL([], [variables_saved_for_relink], [1],
+    [Variables whose values should be saved in libtool wrapper scripts and
+    restored at link time])
+_LT_DECL([], [need_lib_prefix], [0],
+    [Do we need the "lib" prefix for modules?])
+_LT_DECL([], [need_version], [0], [Do we need a version for libraries?])
+_LT_DECL([], [version_type], [0], [Library versioning type])
+_LT_DECL([], [runpath_var], [0],  [Shared library runtime path variable])
+_LT_DECL([], [shlibpath_var], [0],[Shared library path variable])
+_LT_DECL([], [shlibpath_overrides_runpath], [0],
+    [Is shlibpath searched before the hard-coded library search path?])
+_LT_DECL([], [libname_spec], [1], [Format of library name prefix])
+_LT_DECL([], [library_names_spec], [1],
+    [[List of archive names.  First name is the real one, the rest are links.
+    The last name is the one that the linker finds with -lNAME]])
+_LT_DECL([], [soname_spec], [1],
+    [[The coded name of the library, if different from the real name]])
+_LT_DECL([], [install_override_mode], [1],
+    [Permission mode override for installation of shared libraries])
+_LT_DECL([], [postinstall_cmds], [2],
+    [Command to use after installation of a shared archive])
+_LT_DECL([], [postuninstall_cmds], [2],
+    [Command to use after uninstallation of a shared archive])
+_LT_DECL([], [finish_cmds], [2],
+    [Commands used to finish a libtool library installation in a directory])
+_LT_DECL([], [finish_eval], [1],
+    [[As "finish_cmds", except a single script fragment to be evaled but
+    not shown]])
+_LT_DECL([], [hardcode_into_libs], [0],
+    [Whether we should hardcode library paths into libraries])
+_LT_DECL([], [sys_lib_search_path_spec], [2],
+    [Compile-time system search path for libraries])
+_LT_DECL([sys_lib_dlsearch_path_spec], [configure_time_dlsearch_path], [2],
+    [Detected run-time system search path for libraries])
+_LT_DECL([], [configure_time_lt_sys_library_path], [2],
+    [Explicit LT_SYS_LIBRARY_PATH set during ./configure time])
+])# _LT_SYS_DYNAMIC_LINKER
+
+
+# _LT_PATH_TOOL_PREFIX(TOOL)
+# --------------------------
+# find a file program that can recognize shared library
+AC_DEFUN([_LT_PATH_TOOL_PREFIX],
+[m4_require([_LT_DECL_EGREP])dnl
+AC_MSG_CHECKING([for $1])
+AC_CACHE_VAL(lt_cv_path_MAGIC_CMD,
+[case $MAGIC_CMD in
+[[\\/*] |  ?:[\\/]*])
+  lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path.
+  ;;
+*)
+  lt_save_MAGIC_CMD=$MAGIC_CMD
+  lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
+dnl $ac_dummy forces splitting on constant user-supplied paths.
+dnl POSIX.2 word splitting is done only on the output of word expansions,
+dnl not every word.  This closes a longstanding sh security hole.
+  ac_dummy="m4_if([$2], , $PATH, [$2])"
+  for ac_dir in $ac_dummy; do
+    IFS=$lt_save_ifs
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/$1"; then
+      lt_cv_path_MAGIC_CMD=$ac_dir/"$1"
+      if test -n "$file_magic_test_file"; then
+	case $deplibs_check_method in
+	"file_magic "*)
+	  file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+	  MAGIC_CMD=$lt_cv_path_MAGIC_CMD
+	  if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+	    $EGREP "$file_magic_regex" > /dev/null; then
+	    :
+	  else
+	    cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such.  This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem.  Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+	  fi ;;
+	esac
+      fi
+      break
+    fi
+  done
+  IFS=$lt_save_ifs
+  MAGIC_CMD=$lt_save_MAGIC_CMD
+  ;;
+esac])
+MAGIC_CMD=$lt_cv_path_MAGIC_CMD
+if test -n "$MAGIC_CMD"; then
+  AC_MSG_RESULT($MAGIC_CMD)
+else
+  AC_MSG_RESULT(no)
+fi
+_LT_DECL([], [MAGIC_CMD], [0],
+	 [Used to examine libraries when file_magic_cmd begins with "file"])dnl
+])# _LT_PATH_TOOL_PREFIX
+
+# Old name:
+AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], [])
+
+
+# _LT_PATH_MAGIC
+# --------------
+# find a file program that can recognize a shared library
+m4_defun([_LT_PATH_MAGIC],
+[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH)
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+  if test -n "$ac_tool_prefix"; then
+    _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH)
+  else
+    MAGIC_CMD=:
+  fi
+fi
+])# _LT_PATH_MAGIC
+
+
+# LT_PATH_LD
+# ----------
+# find the pathname to the GNU or non-GNU linker
+AC_DEFUN([LT_PATH_LD],
+[AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_PROG_ECHO_BACKSLASH])dnl
+
+AC_ARG_WITH([gnu-ld],
+    [AS_HELP_STRING([--with-gnu-ld],
+	[assume the C compiler uses GNU ld @<:@default=no@:>@])],
+    [test no = "$withval" || with_gnu_ld=yes],
+    [with_gnu_ld=no])dnl
+
+ac_prog=ld
+if test yes = "$GCC"; then
+  # Check if gcc -print-prog-name=ld gives a path.
+  AC_MSG_CHECKING([for ld used by $CC])
+  case $host in
+  *-*-mingw*)
+    # gcc leaves a trailing carriage return, which upsets mingw
+    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+  *)
+    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+  esac
+  case $ac_prog in
+    # Accept absolute paths.
+    [[\\/]]* | ?:[[\\/]]*)
+      re_direlt='/[[^/]][[^/]]*/\.\./'
+      # Canonicalize the pathname of ld
+      ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+      while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+	ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+      done
+      test -z "$LD" && LD=$ac_prog
+      ;;
+  "")
+    # If it fails, then pretend we aren't using GCC.
+    ac_prog=ld
+    ;;
+  *)
+    # If it is relative, then search for the first ld in PATH.
+    with_gnu_ld=unknown
+    ;;
+  esac
+elif test yes = "$with_gnu_ld"; then
+  AC_MSG_CHECKING([for GNU ld])
+else
+  AC_MSG_CHECKING([for non-GNU ld])
+fi
+AC_CACHE_VAL(lt_cv_path_LD,
+[if test -z "$LD"; then
+  lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
+  for ac_dir in $PATH; do
+    IFS=$lt_save_ifs
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+      lt_cv_path_LD=$ac_dir/$ac_prog
+      # Check to see if the program is GNU ld.  I'd rather use --version,
+      # but apparently some variants of GNU ld only accept -v.
+      # Break only if it was the GNU/non-GNU ld that we prefer.
+      case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+      *GNU* | *'with BFD'*)
+	test no != "$with_gnu_ld" && break
+	;;
+      *)
+	test yes != "$with_gnu_ld" && break
+	;;
+      esac
+    fi
+  done
+  IFS=$lt_save_ifs
+else
+  lt_cv_path_LD=$LD # Let the user override the test with a path.
+fi])
+LD=$lt_cv_path_LD
+if test -n "$LD"; then
+  AC_MSG_RESULT($LD)
+else
+  AC_MSG_RESULT(no)
+fi
+test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
+_LT_PATH_LD_GNU
+AC_SUBST([LD])
+
+_LT_TAGDECL([], [LD], [1], [The linker used to build libraries])
+])# LT_PATH_LD
+
+# Old names:
+AU_ALIAS([AM_PROG_LD], [LT_PATH_LD])
+AU_ALIAS([AC_PROG_LD], [LT_PATH_LD])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_PROG_LD], [])
+dnl AC_DEFUN([AC_PROG_LD], [])
+
+
+# _LT_PATH_LD_GNU
+#- --------------
+m4_defun([_LT_PATH_LD_GNU],
+[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
+[# I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+  lt_cv_prog_gnu_ld=yes
+  ;;
+*)
+  lt_cv_prog_gnu_ld=no
+  ;;
+esac])
+with_gnu_ld=$lt_cv_prog_gnu_ld
+])# _LT_PATH_LD_GNU
+
+
+# _LT_CMD_RELOAD
+# --------------
+# find reload flag for linker
+#   -- PORTME Some linkers may need a different reload flag.
+m4_defun([_LT_CMD_RELOAD],
+[AC_CACHE_CHECK([for $LD option to reload object files],
+  lt_cv_ld_reload_flag,
+  [lt_cv_ld_reload_flag='-r'])
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+  cygwin* | mingw* | pw32* | cegcc*)
+    if test yes != "$GCC"; then
+      reload_cmds=false
+    fi
+    ;;
+  darwin*)
+    if test yes = "$GCC"; then
+      reload_cmds='$LTCC $LTCFLAGS -nostdlib $wl-r -o $output$reload_objs'
+    else
+      reload_cmds='$LD$reload_flag -o $output$reload_objs'
+    fi
+    ;;
+esac
+_LT_TAGDECL([], [reload_flag], [1], [How to create reloadable object files])dnl
+_LT_TAGDECL([], [reload_cmds], [2])dnl
+])# _LT_CMD_RELOAD
+
+
+# _LT_PATH_DD
+# -----------
+# find a working dd
+m4_defun([_LT_PATH_DD],
+[AC_CACHE_CHECK([for a working dd], [ac_cv_path_lt_DD],
+[printf 0123456789abcdef0123456789abcdef >conftest.i
+cat conftest.i conftest.i >conftest2.i
+: ${lt_DD:=$DD}
+AC_PATH_PROGS_FEATURE_CHECK([lt_DD], [dd],
+[if "$ac_path_lt_DD" bs=32 count=1 <conftest2.i >conftest.out 2>/dev/null; then
+  cmp -s conftest.i conftest.out \
+  && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=:
+fi])
+rm -f conftest.i conftest2.i conftest.out])
+])# _LT_PATH_DD
+
+
+# _LT_CMD_TRUNCATE
+# ----------------
+# find command to truncate a binary pipe
+m4_defun([_LT_CMD_TRUNCATE],
+[m4_require([_LT_PATH_DD])
+AC_CACHE_CHECK([how to truncate binary pipes], [lt_cv_truncate_bin],
+[printf 0123456789abcdef0123456789abcdef >conftest.i
+cat conftest.i conftest.i >conftest2.i
+lt_cv_truncate_bin=
+if "$ac_cv_path_lt_DD" bs=32 count=1 <conftest2.i >conftest.out 2>/dev/null; then
+  cmp -s conftest.i conftest.out \
+  && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1"
+fi
+rm -f conftest.i conftest2.i conftest.out
+test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q"])
+_LT_DECL([lt_truncate_bin], [lt_cv_truncate_bin], [1],
+  [Command to truncate a binary pipe])
+])# _LT_CMD_TRUNCATE
+
+
+# _LT_CHECK_MAGIC_METHOD
+# ----------------------
+# how to check for library dependencies
+#  -- PORTME fill in with the dynamic library characteristics
+m4_defun([_LT_CHECK_MAGIC_METHOD],
+[m4_require([_LT_DECL_EGREP])
+m4_require([_LT_DECL_OBJDUMP])
+AC_CACHE_CHECK([how to recognize dependent libraries],
+lt_cv_deplibs_check_method,
+[lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# 'unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# that responds to the $file_magic_cmd with a given extended regex.
+# If you have 'file' or equivalent on your system and you're not sure
+# whether 'pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix[[4-9]]*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+beos*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+bsdi[[45]]*)
+  lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)'
+  lt_cv_file_magic_cmd='/usr/bin/file -L'
+  lt_cv_file_magic_test_file=/shlib/libc.so
+  ;;
+
+cygwin*)
+  # func_win32_libid is a shell function defined in ltmain.sh
+  lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+  lt_cv_file_magic_cmd='func_win32_libid'
+  ;;
+
+mingw* | pw32*)
+  # Base MSYS/MinGW do not provide the 'file' command needed by
+  # func_win32_libid shell function, so use a weaker test based on 'objdump',
+  # unless we find 'file', for example because we are cross-compiling.
+  if ( file / ) >/dev/null 2>&1; then
+    lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+    lt_cv_file_magic_cmd='func_win32_libid'
+  else
+    # Keep this pattern in sync with the one in func_win32_libid.
+    lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)'
+    lt_cv_file_magic_cmd='$OBJDUMP -f'
+  fi
+  ;;
+
+cegcc*)
+  # use the weaker test based on 'objdump'. See mingw*.
+  lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
+  lt_cv_file_magic_cmd='$OBJDUMP -f'
+  ;;
+
+darwin* | rhapsody*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+freebsd* | dragonfly*)
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+    case $host_cpu in
+    i*86 )
+      # Not sure whether the presence of OpenBSD here was a mistake.
+      # Let's accept both of them until this is cleared up.
+      lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library'
+      lt_cv_file_magic_cmd=/usr/bin/file
+      lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+      ;;
+    esac
+  else
+    lt_cv_deplibs_check_method=pass_all
+  fi
+  ;;
+
+haiku*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+hpux10.20* | hpux11*)
+  lt_cv_file_magic_cmd=/usr/bin/file
+  case $host_cpu in
+  ia64*)
+    lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64'
+    lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+    ;;
+  hppa*64*)
+    [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]']
+    lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+    ;;
+  *)
+    lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library'
+    lt_cv_file_magic_test_file=/usr/lib/libc.sl
+    ;;
+  esac
+  ;;
+
+interix[[3-9]]*)
+  # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+  lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$'
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $LD in
+  *-32|*"-32 ") libmagic=32-bit;;
+  *-n32|*"-n32 ") libmagic=N32;;
+  *-64|*"-64 ") libmagic=64-bit;;
+  *) libmagic=never-match;;
+  esac
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+netbsd*)
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$'
+  fi
+  ;;
+
+newos6*)
+  lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)'
+  lt_cv_file_magic_cmd=/usr/bin/file
+  lt_cv_file_magic_test_file=/usr/lib/libnls.so
+  ;;
+
+*nto* | *qnx*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+openbsd* | bitrig*)
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+  fi
+  ;;
+
+osf3* | osf4* | osf5*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+rdos*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+solaris*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sysv4 | sysv4.3*)
+  case $host_vendor in
+  motorola)
+    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]'
+    lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+    ;;
+  ncr)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  sequent)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )'
+    ;;
+  sni)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib"
+    lt_cv_file_magic_test_file=/lib/libc.so
+    ;;
+  siemens)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  pc)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  esac
+  ;;
+
+tpf*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+os2*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+esac
+])
+
+file_magic_glob=
+want_nocaseglob=no
+if test "$build" = "$host"; then
+  case $host_os in
+  mingw* | pw32*)
+    if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then
+      want_nocaseglob=yes
+    else
+      file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"`
+    fi
+    ;;
+  esac
+fi
+
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+
+_LT_DECL([], [deplibs_check_method], [1],
+    [Method to check whether dependent libraries are shared objects])
+_LT_DECL([], [file_magic_cmd], [1],
+    [Command to use when deplibs_check_method = "file_magic"])
+_LT_DECL([], [file_magic_glob], [1],
+    [How to find potential files when deplibs_check_method = "file_magic"])
+_LT_DECL([], [want_nocaseglob], [1],
+    [Find potential files using nocaseglob when deplibs_check_method = "file_magic"])
+])# _LT_CHECK_MAGIC_METHOD
+
+
+# LT_PATH_NM
+# ----------
+# find the pathname to a BSD- or MS-compatible name lister
+AC_DEFUN([LT_PATH_NM],
+[AC_REQUIRE([AC_PROG_CC])dnl
+AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM,
+[if test -n "$NM"; then
+  # Let the user override the test.
+  lt_cv_path_NM=$NM
+else
+  lt_nm_to_check=${ac_tool_prefix}nm
+  if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
+    lt_nm_to_check="$lt_nm_to_check nm"
+  fi
+  for lt_tmp_nm in $lt_nm_to_check; do
+    lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
+    for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+      IFS=$lt_save_ifs
+      test -z "$ac_dir" && ac_dir=.
+      tmp_nm=$ac_dir/$lt_tmp_nm
+      if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext"; then
+	# Check to see if the nm accepts a BSD-compat flag.
+	# Adding the 'sed 1q' prevents false positives on HP-UX, which says:
+	#   nm: unknown option "B" ignored
+	# Tru64's nm complains that /dev/null is an invalid object file
+	# MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty
+	case $build_os in
+	mingw*) lt_bad_file=conftest.nm/nofile ;;
+	*) lt_bad_file=/dev/null ;;
+	esac
+	case `"$tmp_nm" -B $lt_bad_file 2>&1 | sed '1q'` in
+	*$lt_bad_file* | *'Invalid file or object type'*)
+	  lt_cv_path_NM="$tmp_nm -B"
+	  break 2
+	  ;;
+	*)
+	  case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+	  */dev/null*)
+	    lt_cv_path_NM="$tmp_nm -p"
+	    break 2
+	    ;;
+	  *)
+	    lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+	    continue # so that we can try to find one that supports BSD flags
+	    ;;
+	  esac
+	  ;;
+	esac
+      fi
+    done
+    IFS=$lt_save_ifs
+  done
+  : ${lt_cv_path_NM=no}
+fi])
+if test no != "$lt_cv_path_NM"; then
+  NM=$lt_cv_path_NM
+else
+  # Didn't find any BSD compatible name lister, look for dumpbin.
+  if test -n "$DUMPBIN"; then :
+    # Let the user override the test.
+  else
+    AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :)
+    case `$DUMPBIN -symbols -headers /dev/null 2>&1 | sed '1q'` in
+    *COFF*)
+      DUMPBIN="$DUMPBIN -symbols -headers"
+      ;;
+    *)
+      DUMPBIN=:
+      ;;
+    esac
+  fi
+  AC_SUBST([DUMPBIN])
+  if test : != "$DUMPBIN"; then
+    NM=$DUMPBIN
+  fi
+fi
+test -z "$NM" && NM=nm
+AC_SUBST([NM])
+_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl
+
+AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface],
+  [lt_cv_nm_interface="BSD nm"
+  echo "int some_variable = 0;" > conftest.$ac_ext
+  (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD)
+  (eval "$ac_compile" 2>conftest.err)
+  cat conftest.err >&AS_MESSAGE_LOG_FD
+  (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD)
+  (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
+  cat conftest.err >&AS_MESSAGE_LOG_FD
+  (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD)
+  cat conftest.out >&AS_MESSAGE_LOG_FD
+  if $GREP 'External.*some_variable' conftest.out > /dev/null; then
+    lt_cv_nm_interface="MS dumpbin"
+  fi
+  rm -f conftest*])
+])# LT_PATH_NM
+
+# Old names:
+AU_ALIAS([AM_PROG_NM], [LT_PATH_NM])
+AU_ALIAS([AC_PROG_NM], [LT_PATH_NM])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_PROG_NM], [])
+dnl AC_DEFUN([AC_PROG_NM], [])
+
+# _LT_CHECK_SHAREDLIB_FROM_LINKLIB
+# --------------------------------
+# how to determine the name of the shared library
+# associated with a specific link library.
+#  -- PORTME fill in with the dynamic library characteristics
+m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB],
+[m4_require([_LT_DECL_EGREP])
+m4_require([_LT_DECL_OBJDUMP])
+m4_require([_LT_DECL_DLLTOOL])
+AC_CACHE_CHECK([how to associate runtime and link libraries],
+lt_cv_sharedlib_from_linklib_cmd,
+[lt_cv_sharedlib_from_linklib_cmd='unknown'
+
+case $host_os in
+cygwin* | mingw* | pw32* | cegcc*)
+  # two different shell functions defined in ltmain.sh;
+  # decide which one to use based on capabilities of $DLLTOOL
+  case `$DLLTOOL --help 2>&1` in
+  *--identify-strict*)
+    lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib
+    ;;
+  *)
+    lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback
+    ;;
+  esac
+  ;;
+*)
+  # fallback: assume linklib IS sharedlib
+  lt_cv_sharedlib_from_linklib_cmd=$ECHO
+  ;;
+esac
+])
+sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd
+test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO
+
+_LT_DECL([], [sharedlib_from_linklib_cmd], [1],
+    [Command to associate shared and link libraries])
+])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB
+
+
+# _LT_PATH_MANIFEST_TOOL
+# ----------------------
+# locate the manifest tool
+m4_defun([_LT_PATH_MANIFEST_TOOL],
+[AC_CHECK_TOOL(MANIFEST_TOOL, mt, :)
+test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt
+AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool],
+  [lt_cv_path_mainfest_tool=no
+  echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD
+  $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out
+  cat conftest.err >&AS_MESSAGE_LOG_FD
+  if $GREP 'Manifest Tool' conftest.out > /dev/null; then
+    lt_cv_path_mainfest_tool=yes
+  fi
+  rm -f conftest*])
+if test yes != "$lt_cv_path_mainfest_tool"; then
+  MANIFEST_TOOL=:
+fi
+_LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl
+])# _LT_PATH_MANIFEST_TOOL
+
+
+# _LT_DLL_DEF_P([FILE])
+# ---------------------
+# True iff FILE is a Windows DLL '.def' file.
+# Keep in sync with func_dll_def_p in the libtool script
+AC_DEFUN([_LT_DLL_DEF_P],
+[dnl
+  test DEF = "`$SED -n dnl
+    -e '\''s/^[[	 ]]*//'\'' dnl Strip leading whitespace
+    -e '\''/^\(;.*\)*$/d'\'' dnl      Delete empty lines and comments
+    -e '\''s/^\(EXPORTS\|LIBRARY\)\([[	 ]].*\)*$/DEF/p'\'' dnl
+    -e q dnl                          Only consider the first "real" line
+    $1`" dnl
+])# _LT_DLL_DEF_P
+
+
+# LT_LIB_M
+# --------
+# check for math library
+AC_DEFUN([LT_LIB_M],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+LIBM=
+case $host in
+*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*)
+  # These system don't have libm, or don't need it
+  ;;
+*-ncr-sysv4.3*)
+  AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM=-lmw)
+  AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm")
+  ;;
+*)
+  AC_CHECK_LIB(m, cos, LIBM=-lm)
+  ;;
+esac
+AC_SUBST([LIBM])
+])# LT_LIB_M
+
+# Old name:
+AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_CHECK_LIBM], [])
+
+
+# _LT_COMPILER_NO_RTTI([TAGNAME])
+# -------------------------------
+m4_defun([_LT_COMPILER_NO_RTTI],
+[m4_require([_LT_TAG_COMPILER])dnl
+
+_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+
+if test yes = "$GCC"; then
+  case $cc_basename in
+  nvcc*)
+    _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;;
+  *)
+    _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;;
+  esac
+
+  _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions],
+    lt_cv_prog_compiler_rtti_exceptions,
+    [-fno-rtti -fno-exceptions], [],
+    [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"])
+fi
+_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1],
+	[Compiler flag to turn off builtin functions])
+])# _LT_COMPILER_NO_RTTI
+
+
+# _LT_CMD_GLOBAL_SYMBOLS
+# ----------------------
+m4_defun([_LT_CMD_GLOBAL_SYMBOLS],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+AC_REQUIRE([LT_PATH_LD])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+AC_MSG_CHECKING([command to parse $NM output from $compiler object])
+AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe],
+[
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix.  What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[[BCDEGRST]]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)'
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+  symcode='[[BCDT]]'
+  ;;
+cygwin* | mingw* | pw32* | cegcc*)
+  symcode='[[ABCDGISTW]]'
+  ;;
+hpux*)
+  if test ia64 = "$host_cpu"; then
+    symcode='[[ABCDEGRST]]'
+  fi
+  ;;
+irix* | nonstopux*)
+  symcode='[[BCDEGRST]]'
+  ;;
+osf*)
+  symcode='[[BCDEGQRST]]'
+  ;;
+solaris*)
+  symcode='[[BDRT]]'
+  ;;
+sco3.2v5*)
+  symcode='[[DT]]'
+  ;;
+sysv4.2uw2*)
+  symcode='[[DT]]'
+  ;;
+sysv5* | sco5v6* | unixware* | OpenUNIX*)
+  symcode='[[ABDT]]'
+  ;;
+sysv4)
+  symcode='[[DFNSTU]]'
+  ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+  symcode='[[ABCDGIRSTW]]' ;;
+esac
+
+if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+  # Gets list of data symbols to import.
+  lt_cv_sys_global_symbol_to_import="sed -n -e 's/^I .* \(.*\)$/\1/p'"
+  # Adjust the below global symbol transforms to fixup imported variables.
+  lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'"
+  lt_c_name_hook=" -e 's/^I .* \(.*\)$/  {\"\1\", (void *) 0},/p'"
+  lt_c_name_lib_hook="\
+  -e 's/^I .* \(lib.*\)$/  {\"\1\", (void *) 0},/p'\
+  -e 's/^I .* \(.*\)$/  {\"lib\1\", (void *) 0},/p'"
+else
+  # Disable hooks by default.
+  lt_cv_sys_global_symbol_to_import=
+  lt_cdecl_hook=
+  lt_c_name_hook=
+  lt_c_name_lib_hook=
+fi
+
+# Transform an extracted symbol line into a proper C declaration.
+# Some systems (esp. on ia64) link data and code symbols differently,
+# so use this general approach.
+lt_cv_sys_global_symbol_to_cdecl="sed -n"\
+$lt_cdecl_hook\
+" -e 's/^T .* \(.*\)$/extern int \1();/p'"\
+" -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n"\
+$lt_c_name_hook\
+" -e 's/^: \(.*\) .*$/  {\"\1\", (void *) 0},/p'"\
+" -e 's/^$symcode$symcode* .* \(.*\)$/  {\"\1\", (void *) \&\1},/p'"
+
+# Transform an extracted symbol line into symbol name with lib prefix and
+# symbol address.
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n"\
+$lt_c_name_lib_hook\
+" -e 's/^: \(.*\) .*$/  {\"\1\", (void *) 0},/p'"\
+" -e 's/^$symcode$symcode* .* \(lib.*\)$/  {\"\1\", (void *) \&\1},/p'"\
+" -e 's/^$symcode$symcode* .* \(.*\)$/  {\"lib\1\", (void *) \&\1},/p'"
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+  opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+  ;;
+esac
+
+# Try without a prefix underscore, then with it.
+for ac_symprfx in "" "_"; do
+
+  # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+  symxfrm="\\1 $ac_symprfx\\2 \\2"
+
+  # Write the raw and C identifiers.
+  if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+    # Fake it for dumpbin and say T for any non-static function,
+    # D for any global variable and I for any imported variable.
+    # Also find C++ and __fastcall symbols from MSVC++,
+    # which start with @ or ?.
+    lt_cv_sys_global_symbol_pipe="$AWK ['"\
+"     {last_section=section; section=\$ 3};"\
+"     /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\
+"     /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
+"     /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\
+"     /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\
+"     /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\
+"     \$ 0!~/External *\|/{next};"\
+"     / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
+"     {if(hide[section]) next};"\
+"     {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\
+"     {split(\$ 0,a,/\||\r/); split(a[2],s)};"\
+"     s[1]~/^[@?]/{print f,s[1],s[1]; next};"\
+"     s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\
+"     ' prfx=^$ac_symprfx]"
+  else
+    lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[	 ]]\($symcode$symcode*\)[[	 ]][[	 ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+  fi
+  lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'"
+
+  # Check to see that the pipe works correctly.
+  pipe_works=no
+
+  rm -f conftest*
+  cat > conftest.$ac_ext <<_LT_EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(void);
+void nm_test_func(void){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+_LT_EOF
+
+  if AC_TRY_EVAL(ac_compile); then
+    # Now try to grab the symbols.
+    nlist=conftest.nm
+    if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then
+      # Try sorting and uniquifying the output.
+      if sort "$nlist" | uniq > "$nlist"T; then
+	mv -f "$nlist"T "$nlist"
+      else
+	rm -f "$nlist"T
+      fi
+
+      # Make sure that we snagged all the symbols we need.
+      if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
+	if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
+	  cat <<_LT_EOF > conftest.$ac_ext
+/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests.  */
+#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE
+/* DATA imports from DLLs on WIN32 can't be const, because runtime
+   relocations are performed -- see ld's documentation on pseudo-relocs.  */
+# define LT@&t@_DLSYM_CONST
+#elif defined __osf__
+/* This system does not cope well with relocations in const data.  */
+# define LT@&t@_DLSYM_CONST
+#else
+# define LT@&t@_DLSYM_CONST const
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+_LT_EOF
+	  # Now generate the symbol file.
+	  eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
+
+	  cat <<_LT_EOF >> conftest.$ac_ext
+
+/* The mapping between symbol names and symbols.  */
+LT@&t@_DLSYM_CONST struct {
+  const char *name;
+  void       *address;
+}
+lt__PROGRAM__LTX_preloaded_symbols[[]] =
+{
+  { "@PROGRAM@", (void *) 0 },
+_LT_EOF
+	  $SED "s/^$symcode$symcode* .* \(.*\)$/  {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
+	  cat <<\_LT_EOF >> conftest.$ac_ext
+  {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+  return lt__PROGRAM__LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+_LT_EOF
+	  # Now try linking the two files.
+	  mv conftest.$ac_objext conftstm.$ac_objext
+	  lt_globsym_save_LIBS=$LIBS
+	  lt_globsym_save_CFLAGS=$CFLAGS
+	  LIBS=conftstm.$ac_objext
+	  CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)"
+	  if AC_TRY_EVAL(ac_link) && test -s conftest$ac_exeext; then
+	    pipe_works=yes
+	  fi
+	  LIBS=$lt_globsym_save_LIBS
+	  CFLAGS=$lt_globsym_save_CFLAGS
+	else
+	  echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD
+	fi
+      else
+	echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD
+      fi
+    else
+      echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD
+    fi
+  else
+    echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD
+    cat conftest.$ac_ext >&5
+  fi
+  rm -rf conftest* conftst*
+
+  # Do not use the global_symbol_pipe unless it works.
+  if test yes = "$pipe_works"; then
+    break
+  else
+    lt_cv_sys_global_symbol_pipe=
+  fi
+done
+])
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+  lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+  AC_MSG_RESULT(failed)
+else
+  AC_MSG_RESULT(ok)
+fi
+
+# Response file support.
+if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+  nm_file_list_spec='@'
+elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then
+  nm_file_list_spec='@'
+fi
+
+_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1],
+    [Take the output of nm and produce a listing of raw symbols and C names])
+_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1],
+    [Transform the output of nm in a proper C declaration])
+_LT_DECL([global_symbol_to_import], [lt_cv_sys_global_symbol_to_import], [1],
+    [Transform the output of nm into a list of symbols to manually relocate])
+_LT_DECL([global_symbol_to_c_name_address],
+    [lt_cv_sys_global_symbol_to_c_name_address], [1],
+    [Transform the output of nm in a C name address pair])
+_LT_DECL([global_symbol_to_c_name_address_lib_prefix],
+    [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1],
+    [Transform the output of nm in a C name address pair when lib prefix is needed])
+_LT_DECL([nm_interface], [lt_cv_nm_interface], [1],
+    [The name lister interface])
+_LT_DECL([], [nm_file_list_spec], [1],
+    [Specify filename containing input files for $NM])
+]) # _LT_CMD_GLOBAL_SYMBOLS
+
+
+# _LT_COMPILER_PIC([TAGNAME])
+# ---------------------------
+m4_defun([_LT_COMPILER_PIC],
+[m4_require([_LT_TAG_COMPILER])dnl
+_LT_TAGVAR(lt_prog_compiler_wl, $1)=
+_LT_TAGVAR(lt_prog_compiler_pic, $1)=
+_LT_TAGVAR(lt_prog_compiler_static, $1)=
+
+m4_if([$1], [CXX], [
+  # C++ specific cases for pic, static, wl, etc.
+  if test yes = "$GXX"; then
+    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+    case $host_os in
+    aix*)
+      # All AIX code is PIC.
+      if test ia64 = "$host_cpu"; then
+	# AIX 5 now supports IA64 processor
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      fi
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+        ;;
+      m68k)
+            # FIXME: we need at least 68020 code to build shared libraries, but
+            # adding the '-m68020' flag to GCC prevents building anything better,
+            # like '-m68040'.
+            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+        ;;
+      esac
+      ;;
+
+    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+    mingw* | cygwin* | os2* | pw32* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      # Although the cygwin gcc ignores -fPIC, still need this for old-style
+      # (--disable-auto-import) libraries
+      m4_if([$1], [GCJ], [],
+	[_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+      case $host_os in
+      os2*)
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static'
+	;;
+      esac
+      ;;
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+      ;;
+    *djgpp*)
+      # DJGPP does not support shared libraries at all
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+      ;;
+    haiku*)
+      # PIC is the default for Haiku.
+      # The "-static" flag exists, but is broken.
+      _LT_TAGVAR(lt_prog_compiler_static, $1)=
+      ;;
+    interix[[3-9]]*)
+      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+      # Instead, we relocate shared libraries at runtime.
+      ;;
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+      fi
+      ;;
+    hpux*)
+      # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+      # PA HP-UX.  On IA64 HP-UX, PIC is the default but the pic flag
+      # sets the default TLS model and affects inlining.
+      case $host_cpu in
+      hppa*64*)
+	;;
+      *)
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	;;
+      esac
+      ;;
+    *qnx* | *nto*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+      ;;
+    *)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+      ;;
+    esac
+  else
+    case $host_os in
+      aix[[4-9]]*)
+	# All AIX code is PIC.
+	if test ia64 = "$host_cpu"; then
+	  # AIX 5 now supports IA64 processor
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	else
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+	fi
+	;;
+      chorus*)
+	case $cc_basename in
+	cxch68*)
+	  # Green Hills C++ Compiler
+	  # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
+	  ;;
+	esac
+	;;
+      mingw* | cygwin* | os2* | pw32* | cegcc*)
+	# This hack is so that the source file can tell whether it is being
+	# built for inclusion in a dll (and should export symbols for example).
+	m4_if([$1], [GCJ], [],
+	  [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+	;;
+      dgux*)
+	case $cc_basename in
+	  ec++*)
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    ;;
+	  ghcx*)
+	    # Green Hills C++ Compiler
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      freebsd* | dragonfly*)
+	# FreeBSD uses GNU C++
+	;;
+      hpux9* | hpux10* | hpux11*)
+	case $cc_basename in
+	  CC*)
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive'
+	    if test ia64 != "$host_cpu"; then
+	      _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+	    fi
+	    ;;
+	  aCC*)
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive'
+	    case $host_cpu in
+	    hppa*64*|ia64*)
+	      # +Z the default
+	      ;;
+	    *)
+	      _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+	      ;;
+	    esac
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      interix*)
+	# This is c89, which is MS Visual C++ (no shared libs)
+	# Anyone wants to do a port?
+	;;
+      irix5* | irix6* | nonstopux*)
+	case $cc_basename in
+	  CC*)
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+	    # CC pic flag -KPIC is the default.
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+	case $cc_basename in
+	  KCC*)
+	    # KAI C++ Compiler
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	    ;;
+	  ecpc* )
+	    # old Intel C++ for x86_64, which still supported -KPIC.
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+	    ;;
+	  icpc* )
+	    # Intel C++, used to be incompatible with GCC.
+	    # ICC 10 doesn't accept -KPIC any more.
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+	    ;;
+	  pgCC* | pgcpp*)
+	    # Portland Group C++ compiler
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	    ;;
+	  cxx*)
+	    # Compaq C++
+	    # Make sure the PIC flag is empty.  It appears that all Alpha
+	    # Linux and Compaq Tru64 Unix objects are PIC.
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+	    ;;
+	  xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*)
+	    # IBM XL 8.0, 9.0 on PPC and BlueGene
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
+	    ;;
+	  *)
+	    case `$CC -V 2>&1 | sed 5q` in
+	    *Sun\ C*)
+	      # Sun C++ 5.9
+	      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+	      ;;
+	    esac
+	    ;;
+	esac
+	;;
+      lynxos*)
+	;;
+      m88k*)
+	;;
+      mvs*)
+	case $cc_basename in
+	  cxx*)
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      netbsd*)
+	;;
+      *qnx* | *nto*)
+        # QNX uses GNU C++, but need to define -shared option too, otherwise
+        # it will coredump.
+        _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+        ;;
+      osf3* | osf4* | osf5*)
+	case $cc_basename in
+	  KCC*)
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+	    ;;
+	  RCC*)
+	    # Rational C++ 2.4.1
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+	    ;;
+	  cxx*)
+	    # Digital/Compaq C++
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    # Make sure the PIC flag is empty.  It appears that all Alpha
+	    # Linux and Compaq Tru64 Unix objects are PIC.
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      psos*)
+	;;
+      solaris*)
+	case $cc_basename in
+	  CC* | sunCC*)
+	    # Sun C++ 4.2, 5.x and Centerline C++
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+	    ;;
+	  gcx*)
+	    # Green Hills C++ Compiler
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      sunos4*)
+	case $cc_basename in
+	  CC*)
+	    # Sun C++ 4.x
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	    ;;
+	  lcc*)
+	    # Lucid
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+	case $cc_basename in
+	  CC*)
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	    ;;
+	esac
+	;;
+      tandem*)
+	case $cc_basename in
+	  NCC*)
+	    # NonStop-UX NCC 3.20
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      vxworks*)
+	;;
+      *)
+	_LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+	;;
+    esac
+  fi
+],
+[
+  if test yes = "$GCC"; then
+    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+    case $host_os in
+      aix*)
+      # All AIX code is PIC.
+      if test ia64 = "$host_cpu"; then
+	# AIX 5 now supports IA64 processor
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      fi
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+        ;;
+      m68k)
+            # FIXME: we need at least 68020 code to build shared libraries, but
+            # adding the '-m68020' flag to GCC prevents building anything better,
+            # like '-m68040'.
+            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+        ;;
+      esac
+      ;;
+
+    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+
+    mingw* | cygwin* | pw32* | os2* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      # Although the cygwin gcc ignores -fPIC, still need this for old-style
+      # (--disable-auto-import) libraries
+      m4_if([$1], [GCJ], [],
+	[_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+      case $host_os in
+      os2*)
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static'
+	;;
+      esac
+      ;;
+
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+      ;;
+
+    haiku*)
+      # PIC is the default for Haiku.
+      # The "-static" flag exists, but is broken.
+      _LT_TAGVAR(lt_prog_compiler_static, $1)=
+      ;;
+
+    hpux*)
+      # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+      # PA HP-UX.  On IA64 HP-UX, PIC is the default but the pic flag
+      # sets the default TLS model and affects inlining.
+      case $host_cpu in
+      hppa*64*)
+	# +Z the default
+	;;
+      *)
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	;;
+      esac
+      ;;
+
+    interix[[3-9]]*)
+      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+      # Instead, we relocate shared libraries at runtime.
+      ;;
+
+    msdosdjgpp*)
+      # Just because we use GCC doesn't mean we suddenly get shared libraries
+      # on systems that don't support them.
+      _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+      enable_shared=no
+      ;;
+
+    *nto* | *qnx*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+      fi
+      ;;
+
+    *)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+      ;;
+    esac
+
+    case $cc_basename in
+    nvcc*) # Cuda Compiler Driver 2.2
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker '
+      if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
+        _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)"
+      fi
+      ;;
+    esac
+  else
+    # PORTME Check for flag to pass linker flags through the system compiler.
+    case $host_os in
+    aix*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      if test ia64 = "$host_cpu"; then
+	# AIX 5 now supports IA64 processor
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      else
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+      fi
+      ;;
+
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+      case $cc_basename in
+      nagfor*)
+        # NAG Fortran compiler
+        _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,'
+        _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+        _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+        ;;
+      esac
+      ;;
+
+    mingw* | cygwin* | pw32* | os2* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      m4_if([$1], [GCJ], [],
+	[_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+      case $host_os in
+      os2*)
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static'
+	;;
+      esac
+      ;;
+
+    hpux9* | hpux10* | hpux11*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+      # not for PA HP-UX.
+      case $host_cpu in
+      hppa*64*|ia64*)
+	# +Z the default
+	;;
+      *)
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+	;;
+      esac
+      # Is there a better lt_prog_compiler_static that works with the bundled CC?
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive'
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      # PIC (with -KPIC) is the default.
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+      ;;
+
+    linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+      case $cc_basename in
+      # old Intel for x86_64, which still supported -KPIC.
+      ecc*)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+        ;;
+      # icc used to be incompatible with GCC.
+      # ICC 10 doesn't accept -KPIC any more.
+      icc* | ifort*)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+        ;;
+      # Lahey Fortran 8.1.
+      lf95*)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='--static'
+	;;
+      nagfor*)
+	# NAG Fortran compiler
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	;;
+      tcc*)
+	# Fabrice Bellard et al's Tiny C Compiler
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+	;;
+      pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
+        # Portland Group compilers (*not* the Pentium gcc compiler,
+	# which looks to be a dead project)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+        ;;
+      ccc*)
+        _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+        # All Alpha code is PIC.
+        _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+        ;;
+      xl* | bgxl* | bgf* | mpixl*)
+	# IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
+	;;
+      *)
+	case `$CC -V 2>&1 | sed 5q` in
+	*Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*)
+	  # Sun Fortran 8.3 passes all unrecognized flags to the linker
+	  _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	  _LT_TAGVAR(lt_prog_compiler_wl, $1)=''
+	  ;;
+	*Sun\ F* | *Sun*Fortran*)
+	  _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	  _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+	  ;;
+	*Sun\ C*)
+	  # Sun C 5.9
+	  _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	  _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	  ;;
+        *Intel*\ [[CF]]*Compiler*)
+	  _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	  _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+	  ;;
+	*Portland\ Group*)
+	  _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	  _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	  ;;
+	esac
+	;;
+      esac
+      ;;
+
+    newsos6)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    *nto* | *qnx*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+      ;;
+
+    osf3* | osf4* | osf5*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      # All OSF/1 code is PIC.
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+      ;;
+
+    rdos*)
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+      ;;
+
+    solaris*)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      case $cc_basename in
+      f77* | f90* | f95* | sunf77* | sunf90* | sunf95*)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';;
+      *)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';;
+      esac
+      ;;
+
+    sunos4*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    sysv4 | sysv4.2uw2* | sysv4.3*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      fi
+      ;;
+
+    sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    unicos*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+      ;;
+
+    uts4*)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    *)
+      _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+      ;;
+    esac
+  fi
+])
+case $host_os in
+  # For platforms that do not support PIC, -DPIC is meaningless:
+  *djgpp*)
+    _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+    ;;
+  *)
+    _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])"
+    ;;
+esac
+
+AC_CACHE_CHECK([for $compiler option to produce PIC],
+  [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)],
+  [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)])
+_LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
+  _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works],
+    [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)],
+    [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [],
+    [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in
+     "" | " "*) ;;
+     *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;;
+     esac],
+    [_LT_TAGVAR(lt_prog_compiler_pic, $1)=
+     _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no])
+fi
+_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1],
+	[Additional compiler flags for building library objects])
+
+_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1],
+	[How to pass a linker flag through the compiler])
+#
+# Check to make sure the static flag actually works.
+#
+wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\"
+_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works],
+  _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1),
+  $lt_tmp_static_flag,
+  [],
+  [_LT_TAGVAR(lt_prog_compiler_static, $1)=])
+_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1],
+	[Compiler flag to prevent dynamic linking])
+])# _LT_COMPILER_PIC
+
+
+# _LT_LINKER_SHLIBS([TAGNAME])
+# ----------------------------
+# See if the linker supports building shared libraries.
+m4_defun([_LT_LINKER_SHLIBS],
+[AC_REQUIRE([LT_PATH_LD])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+m4_require([_LT_PATH_MANIFEST_TOOL])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+m4_if([$1], [CXX], [
+  _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
+  case $host_os in
+  aix[[4-9]]*)
+    # If we're using GNU nm, then we don't want the "-C" option.
+    # -C means demangle to GNU nm, but means don't demangle to AIX nm.
+    # Without the "-l" option, or with the "-B" option, AIX nm treats
+    # weak defined symbols like other global defined symbols, whereas
+    # GNU nm marks them as "W".
+    # While the 'weak' keyword is ignored in the Export File, we need
+    # it in the Import File for the 'aix-soname' feature, so we have
+    # to replace the "-B" option with "-P" for AIX nm.
+    if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+      _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols'
+    else
+      _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
+    fi
+    ;;
+  pw32*)
+    _LT_TAGVAR(export_symbols_cmds, $1)=$ltdll_cmds
+    ;;
+  cygwin* | mingw* | cegcc*)
+    case $cc_basename in
+    cl*)
+      _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
+      ;;
+    *)
+      _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
+      _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
+      ;;
+    esac
+    ;;
+  *)
+    _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+    ;;
+  esac
+], [
+  runpath_var=
+  _LT_TAGVAR(allow_undefined_flag, $1)=
+  _LT_TAGVAR(always_export_symbols, $1)=no
+  _LT_TAGVAR(archive_cmds, $1)=
+  _LT_TAGVAR(archive_expsym_cmds, $1)=
+  _LT_TAGVAR(compiler_needs_object, $1)=no
+  _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+  _LT_TAGVAR(export_dynamic_flag_spec, $1)=
+  _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  _LT_TAGVAR(hardcode_automatic, $1)=no
+  _LT_TAGVAR(hardcode_direct, $1)=no
+  _LT_TAGVAR(hardcode_direct_absolute, $1)=no
+  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+  _LT_TAGVAR(hardcode_libdir_separator, $1)=
+  _LT_TAGVAR(hardcode_minus_L, $1)=no
+  _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+  _LT_TAGVAR(inherit_rpath, $1)=no
+  _LT_TAGVAR(link_all_deplibs, $1)=unknown
+  _LT_TAGVAR(module_cmds, $1)=
+  _LT_TAGVAR(module_expsym_cmds, $1)=
+  _LT_TAGVAR(old_archive_from_new_cmds, $1)=
+  _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)=
+  _LT_TAGVAR(thread_safe_flag_spec, $1)=
+  _LT_TAGVAR(whole_archive_flag_spec, $1)=
+  # include_expsyms should be a list of space-separated symbols to be *always*
+  # included in the symbol list
+  _LT_TAGVAR(include_expsyms, $1)=
+  # exclude_expsyms can be an extended regexp of symbols to exclude
+  # it will be wrapped by ' (' and ')$', so one must not match beginning or
+  # end of line.  Example: 'a|bc|.*d.*' will exclude the symbols 'a' and 'bc',
+  # as well as any symbol that contains 'd'.
+  _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
+  # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+  # platforms (ab)use it in PIC code, but their linkers get confused if
+  # the symbol is explicitly referenced.  Since portable code cannot
+  # rely on this symbol name, it's probably fine to never include it in
+  # preloaded symbol tables.
+  # Exclude shared library initialization/finalization symbols.
+dnl Note also adjust exclude_expsyms for C++ above.
+  extract_expsyms_cmds=
+
+  case $host_os in
+  cygwin* | mingw* | pw32* | cegcc*)
+    # FIXME: the MSVC++ port hasn't been tested in a loooong time
+    # When not using gcc, we currently assume that we are using
+    # Microsoft Visual C++.
+    if test yes != "$GCC"; then
+      with_gnu_ld=no
+    fi
+    ;;
+  interix*)
+    # we just hope/assume this is gcc and not c89 (= MSVC++)
+    with_gnu_ld=yes
+    ;;
+  openbsd* | bitrig*)
+    with_gnu_ld=no
+    ;;
+  esac
+
+  _LT_TAGVAR(ld_shlibs, $1)=yes
+
+  # On some targets, GNU ld is compatible enough with the native linker
+  # that we're better off using the native interface for both.
+  lt_use_gnu_ld_interface=no
+  if test yes = "$with_gnu_ld"; then
+    case $host_os in
+      aix*)
+	# The AIX port of GNU ld has always aspired to compatibility
+	# with the native linker.  However, as the warning in the GNU ld
+	# block says, versions before 2.19.5* couldn't really create working
+	# shared libraries, regardless of the interface used.
+	case `$LD -v 2>&1` in
+	  *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
+	  *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;;
+	  *\ \(GNU\ Binutils\)\ [[3-9]]*) ;;
+	  *)
+	    lt_use_gnu_ld_interface=yes
+	    ;;
+	esac
+	;;
+      *)
+	lt_use_gnu_ld_interface=yes
+	;;
+    esac
+  fi
+
+  if test yes = "$lt_use_gnu_ld_interface"; then
+    # If archive_cmds runs LD, not CC, wlarc should be empty
+    wlarc='$wl'
+
+    # Set some defaults for GNU ld with shared library support. These
+    # are reset later if shared libraries are not supported. Putting them
+    # here allows them to be overridden if necessary.
+    runpath_var=LD_RUN_PATH
+    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+    _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
+    # ancient GNU ld didn't support --whole-archive et. al.
+    if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
+      _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
+    else
+      _LT_TAGVAR(whole_archive_flag_spec, $1)=
+    fi
+    supports_anon_versioning=no
+    case `$LD -v | $SED -e 's/([^)]\+)\s\+//' 2>&1` in
+      *GNU\ gold*) supports_anon_versioning=yes ;;
+      *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
+      *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+      *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+      *\ 2.11.*) ;; # other 2.11 versions
+      *) supports_anon_versioning=yes ;;
+    esac
+
+    # See if GNU ld supports shared libraries.
+    case $host_os in
+    aix[[3-9]]*)
+      # On AIX/PPC, the GNU linker is very broken
+      if test ia64 != "$host_cpu"; then
+	_LT_TAGVAR(ld_shlibs, $1)=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.19, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support.  If you
+*** really care for shared libraries, you may want to install binutils
+*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
+*** You will then need to restart the configuration process.
+
+_LT_EOF
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+            _LT_TAGVAR(archive_expsym_cmds, $1)=''
+        ;;
+      m68k)
+            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+            _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+            _LT_TAGVAR(hardcode_minus_L, $1)=yes
+        ;;
+      esac
+      ;;
+
+    beos*)
+      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+	# Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+	# support --undefined.  This deserves some investigation.  FIXME
+	_LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+      else
+	_LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    cygwin* | mingw* | pw32* | cegcc*)
+      # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+      # as there is no search path for DLLs.
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols'
+      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+      _LT_TAGVAR(always_export_symbols, $1)=no
+      _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+      _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
+      _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
+
+      if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+	# If the export-symbols file already is a .def file, use it as
+	# is; otherwise, prepend EXPORTS...
+	_LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then
+          cp $export_symbols $output_objdir/$soname.def;
+        else
+          echo EXPORTS > $output_objdir/$soname.def;
+          cat $export_symbols >> $output_objdir/$soname.def;
+        fi~
+        $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+      else
+	_LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    haiku*)
+      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      ;;
+
+    os2*)
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+      shrext_cmds=.dll
+      _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+	$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+	$ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+	$ECHO EXPORTS >> $output_objdir/$libname.def~
+	emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
+	$CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+	emximp -o $lib $output_objdir/$libname.def'
+      _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+	$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+	$ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+	$ECHO EXPORTS >> $output_objdir/$libname.def~
+	prefix_cmds="$SED"~
+	if test EXPORTS = "`$SED 1q $export_symbols`"; then
+	  prefix_cmds="$prefix_cmds -e 1d";
+	fi~
+	prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
+	cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
+	$CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+	emximp -o $lib $output_objdir/$libname.def'
+      _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
+      _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+      ;;
+
+    interix[[3-9]]*)
+      _LT_TAGVAR(hardcode_direct, $1)=no
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+      # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+      # Instead, shared libraries are loaded at an image base (0x10000000 by
+      # default) and relocated if they conflict, which is a slow very memory
+      # consuming and fragmenting process.  To avoid this, we pick a random,
+      # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+      # time.  Moving up from 0x10000000 also allows more sbrk(2) space.
+      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      ;;
+
+    gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
+      tmp_diet=no
+      if test linux-dietlibc = "$host_os"; then
+	case $cc_basename in
+	  diet\ *) tmp_diet=yes;;	# linux-dietlibc with static linking (!diet-dyn)
+	esac
+      fi
+      if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
+	 && test no = "$tmp_diet"
+      then
+	tmp_addflag=' $pic_flag'
+	tmp_sharedflag='-shared'
+	case $cc_basename,$host_cpu in
+        pgcc*)				# Portland Group C compiler
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+	  tmp_addflag=' $pic_flag'
+	  ;;
+	pgf77* | pgf90* | pgf95* | pgfortran*)
+					# Portland Group f77 and f90 compilers
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+	  tmp_addflag=' $pic_flag -Mnomain' ;;
+	ecc*,ia64* | icc*,ia64*)	# Intel C compiler on ia64
+	  tmp_addflag=' -i_dynamic' ;;
+	efc*,ia64* | ifort*,ia64*)	# Intel Fortran compiler on ia64
+	  tmp_addflag=' -i_dynamic -nofor_main' ;;
+	ifc* | ifort*)			# Intel Fortran compiler
+	  tmp_addflag=' -nofor_main' ;;
+	lf95*)				# Lahey Fortran 8.1
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)=
+	  tmp_sharedflag='--shared' ;;
+        nagfor*)                        # NAGFOR 5.3
+          tmp_sharedflag='-Wl,-shared' ;;
+	xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below)
+	  tmp_sharedflag='-qmkshrobj'
+	  tmp_addflag= ;;
+	nvcc*)	# Cuda Compiler Driver 2.2
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+	  _LT_TAGVAR(compiler_needs_object, $1)=yes
+	  ;;
+	esac
+	case `$CC -V 2>&1 | sed 5q` in
+	*Sun\ C*)			# Sun C 5.9
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+	  _LT_TAGVAR(compiler_needs_object, $1)=yes
+	  tmp_sharedflag='-G' ;;
+	*Sun\ F*)			# Sun Fortran 8.3
+	  tmp_sharedflag='-G' ;;
+	esac
+	_LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+
+        if test yes = "$supports_anon_versioning"; then
+          _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+            cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+            echo "local: *; };" >> $output_objdir/$libname.ver~
+            $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib'
+        fi
+
+	case $cc_basename in
+	tcc*)
+	  _LT_TAGVAR(export_dynamic_flag_spec, $1)='-rdynamic'
+	  ;;
+	xlf* | bgf* | bgxlf* | mpixlf*)
+	  # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive'
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
+	  if test yes = "$supports_anon_versioning"; then
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+              cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+              echo "local: *; };" >> $output_objdir/$libname.ver~
+              $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+	  fi
+	  ;;
+	esac
+      else
+        _LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    netbsd*)
+      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+	_LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+	wlarc=
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+      fi
+      ;;
+
+    solaris*)
+      if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
+	_LT_TAGVAR(ld_shlibs, $1)=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+      elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+	_LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+      case `$LD -v 2>&1` in
+        *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*)
+	_LT_TAGVAR(ld_shlibs, $1)=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot
+*** reliably create shared libraries on SCO systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+	;;
+	*)
+	  # For security reasons, it is highly recommended that you always
+	  # use absolute paths for naming shared libraries, and exclude the
+	  # DT_RUNPATH tag from executables and libraries.  But doing so
+	  # requires that you compile everything twice, which is a pain.
+	  if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+	  else
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	  fi
+	;;
+      esac
+      ;;
+
+    sunos4*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      wlarc=
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    *)
+      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+	_LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+    esac
+
+    if test no = "$_LT_TAGVAR(ld_shlibs, $1)"; then
+      runpath_var=
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)=
+      _LT_TAGVAR(whole_archive_flag_spec, $1)=
+    fi
+  else
+    # PORTME fill in a description of your system's linker (not GNU ld)
+    case $host_os in
+    aix3*)
+      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+      _LT_TAGVAR(always_export_symbols, $1)=yes
+      _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+      # Note: this linker hardcodes the directories in LIBPATH if there
+      # are no directories specified by -L.
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then
+	# Neither direct hardcoding nor static linking is supported with a
+	# broken collect2.
+	_LT_TAGVAR(hardcode_direct, $1)=unsupported
+      fi
+      ;;
+
+    aix[[4-9]]*)
+      if test ia64 = "$host_cpu"; then
+	# On IA64, the linker does run time linking by default, so we don't
+	# have to do anything special.
+	aix_use_runtimelinking=no
+	exp_sym_flag='-Bexport'
+	no_entry_flag=
+      else
+	# If we're using GNU nm, then we don't want the "-C" option.
+	# -C means demangle to GNU nm, but means don't demangle to AIX nm.
+	# Without the "-l" option, or with the "-B" option, AIX nm treats
+	# weak defined symbols like other global defined symbols, whereas
+	# GNU nm marks them as "W".
+	# While the 'weak' keyword is ignored in the Export File, we need
+	# it in the Import File for the 'aix-soname' feature, so we have
+	# to replace the "-B" option with "-P" for AIX nm.
+	if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+	  _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols'
+	else
+	  _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
+	fi
+	aix_use_runtimelinking=no
+
+	# Test if we are trying to use run time linking or normal
+	# AIX style linking. If -brtl is somewhere in LDFLAGS, we
+	# have runtime linking enabled, and use it for executables.
+	# For shared libraries, we enable/disable runtime linking
+	# depending on the kind of the shared library created -
+	# when "with_aix_soname,aix_use_runtimelinking" is:
+	# "aix,no"   lib.a(lib.so.V) shared, rtl:no,  for executables
+	# "aix,yes"  lib.so          shared, rtl:yes, for executables
+	#            lib.a           static archive
+	# "both,no"  lib.so.V(shr.o) shared, rtl:yes
+	#            lib.a(lib.so.V) shared, rtl:no,  for executables
+	# "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables
+	#            lib.a(lib.so.V) shared, rtl:no
+	# "svr4,*"   lib.so.V(shr.o) shared, rtl:yes, for executables
+	#            lib.a           static archive
+	case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
+	  for ld_flag in $LDFLAGS; do
+	  if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then
+	    aix_use_runtimelinking=yes
+	    break
+	  fi
+	  done
+	  if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then
+	    # With aix-soname=svr4, we create the lib.so.V shared archives only,
+	    # so we don't have lib.a shared libs to link our executables.
+	    # We have to force runtime linking in this case.
+	    aix_use_runtimelinking=yes
+	    LDFLAGS="$LDFLAGS -Wl,-brtl"
+	  fi
+	  ;;
+	esac
+
+	exp_sym_flag='-bexport'
+	no_entry_flag='-bnoentry'
+      fi
+
+      # When large executables or shared objects are built, AIX ld can
+      # have problems creating the table of contents.  If linking a library
+      # or program results in "error TOC overflow" add -mminimal-toc to
+      # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+      # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+      _LT_TAGVAR(archive_cmds, $1)=''
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      _LT_TAGVAR(file_list_spec, $1)='$wl-f,'
+      case $with_aix_soname,$aix_use_runtimelinking in
+      aix,*) ;; # traditional, no import file
+      svr4,* | *,yes) # use import file
+	# The Import File defines what to hardcode.
+	_LT_TAGVAR(hardcode_direct, $1)=no
+	_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+	;;
+      esac
+
+      if test yes = "$GCC"; then
+	case $host_os in aix4.[[012]]|aix4.[[012]].*)
+	# We only want to do this on AIX 4.2 and lower, the check
+	# below for broken collect2 doesn't work under 4.3+
+	  collect2name=`$CC -print-prog-name=collect2`
+	  if test -f "$collect2name" &&
+	   strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+	  then
+	  # We have reworked collect2
+	  :
+	  else
+	  # We have old collect2
+	  _LT_TAGVAR(hardcode_direct, $1)=unsupported
+	  # It fails to find uninstalled libraries when the uninstalled
+	  # path is not listed in the libpath.  Setting hardcode_minus_L
+	  # to unsupported forces relinking
+	  _LT_TAGVAR(hardcode_minus_L, $1)=yes
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+	  _LT_TAGVAR(hardcode_libdir_separator, $1)=
+	  fi
+	  ;;
+	esac
+	shared_flag='-shared'
+	if test yes = "$aix_use_runtimelinking"; then
+	  shared_flag="$shared_flag "'$wl-G'
+	fi
+	# Need to ensure runtime linking is disabled for the traditional
+	# shared library, or the linker may eventually find shared libraries
+	# /with/ Import File - we do not want to mix them.
+	shared_flag_aix='-shared'
+	shared_flag_svr4='-shared $wl-G'
+      else
+	# not using gcc
+	if test ia64 = "$host_cpu"; then
+	# VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+	# chokes on -Wl,-G. The following line is correct:
+	  shared_flag='-G'
+	else
+	  if test yes = "$aix_use_runtimelinking"; then
+	    shared_flag='$wl-G'
+	  else
+	    shared_flag='$wl-bM:SRE'
+	  fi
+	  shared_flag_aix='$wl-bM:SRE'
+	  shared_flag_svr4='$wl-G'
+	fi
+      fi
+
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall'
+      # It seems that -bexpall does not export symbols beginning with
+      # underscore (_), so it is better to generate a list of symbols to export.
+      _LT_TAGVAR(always_export_symbols, $1)=yes
+      if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then
+	# Warning - without using the other runtime loading flags (-brtl),
+	# -berok will link without error, but may produce a broken library.
+	_LT_TAGVAR(allow_undefined_flag, $1)='-berok'
+        # Determine the default libpath from the value encoded in an
+        # empty executable.
+        _LT_SYS_MODULE_PATH_AIX([$1])
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath"
+        _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag
+      else
+	if test ia64 = "$host_cpu"; then
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib'
+	  _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+	  _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols"
+	else
+	 # Determine the default libpath from the value encoded in an
+	 # empty executable.
+	 _LT_SYS_MODULE_PATH_AIX([$1])
+	 _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath"
+	  # Warning - without using the other run time loading flags,
+	  # -berok will link without error, but may produce a broken library.
+	  _LT_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok'
+	  _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok'
+	  if test yes = "$with_gnu_ld"; then
+	    # We only use this code for GNU lds that support --whole-archive.
+	    _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive'
+	  else
+	    # Exported symbols can be pulled into shared objects from archives
+	    _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+	  fi
+	  _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d'
+	  # -brtl affects multiple linker settings, -berok does not and is overridden later
+	  compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`'
+	  if test svr4 != "$with_aix_soname"; then
+	    # This is similar to how AIX traditionally builds its shared libraries.
+	    _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname'
+	  fi
+	  if test aix != "$with_aix_soname"; then
+	    _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp'
+	  else
+	    # used by -dlpreopen to get the symbols
+	    _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV  $output_objdir/$realname.d/$soname $output_objdir'
+	  fi
+	  _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d'
+	fi
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+            _LT_TAGVAR(archive_expsym_cmds, $1)=''
+        ;;
+      m68k)
+            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+            _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+            _LT_TAGVAR(hardcode_minus_L, $1)=yes
+        ;;
+      esac
+      ;;
+
+    bsdi[[45]]*)
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic
+      ;;
+
+    cygwin* | mingw* | pw32* | cegcc*)
+      # When not using gcc, we currently assume that we are using
+      # Microsoft Visual C++.
+      # hardcode_libdir_flag_spec is actually meaningless, as there is
+      # no search path for DLLs.
+      case $cc_basename in
+      cl*)
+	# Native MSVC
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+	_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+	_LT_TAGVAR(always_export_symbols, $1)=yes
+	_LT_TAGVAR(file_list_spec, $1)='@'
+	# Tell ltmain to make .lib files, not .a files.
+	libext=lib
+	# Tell ltmain to make .dll files, not .so files.
+	shrext_cmds=.dll
+	# FIXME: Setting linknames here is a bad hack.
+	_LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames='
+	_LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then
+            cp "$export_symbols" "$output_objdir/$soname.def";
+            echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp";
+          else
+            $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp;
+          fi~
+          $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+          linknames='
+	# The linker will not automatically build a static lib if we build a DLL.
+	# _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+	_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+	_LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
+	_LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols'
+	# Don't use ranlib
+	_LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib'
+	_LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~
+          lt_tool_outputfile="@TOOL_OUTPUT@"~
+          case $lt_outputfile in
+            *.exe|*.EXE) ;;
+            *)
+              lt_outputfile=$lt_outputfile.exe
+              lt_tool_outputfile=$lt_tool_outputfile.exe
+              ;;
+          esac~
+          if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then
+            $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+            $RM "$lt_outputfile.manifest";
+          fi'
+	;;
+      *)
+	# Assume MSVC wrapper
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+	_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+	# Tell ltmain to make .lib files, not .a files.
+	libext=lib
+	# Tell ltmain to make .dll files, not .so files.
+	shrext_cmds=.dll
+	# FIXME: Setting linknames here is a bad hack.
+	_LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
+	# The linker will automatically build a .lib file if we build a DLL.
+	_LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+	# FIXME: Should let the user specify the lib program.
+	_LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs'
+	_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+	;;
+      esac
+      ;;
+
+    darwin* | rhapsody*)
+      _LT_DARWIN_LINKER_FEATURES($1)
+      ;;
+
+    dgux*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+    # support.  Future versions do this automatically, but an explicit c++rt0.o
+    # does not break anything, and helps significantly (at the cost of a little
+    # extra space).
+    freebsd2.2*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+    freebsd2.*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+    freebsd* | dragonfly*)
+      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    hpux9*)
+      if test yes = "$GCC"; then
+	_LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
+      fi
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+
+      # hardcode_minus_L: Not really in the search PATH,
+      # but as the default location of the library.
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+      ;;
+
+    hpux10*)
+      if test yes,no = "$GCC,$with_gnu_ld"; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      if test no = "$with_gnu_ld"; then
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
+	_LT_TAGVAR(hardcode_libdir_separator, $1)=:
+	_LT_TAGVAR(hardcode_direct, $1)=yes
+	_LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+	_LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+	# hardcode_minus_L: Not really in the search PATH,
+	# but as the default location of the library.
+	_LT_TAGVAR(hardcode_minus_L, $1)=yes
+      fi
+      ;;
+
+    hpux11*)
+      if test yes,no = "$GCC,$with_gnu_ld"; then
+	case $host_cpu in
+	hppa*64*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	ia64*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	esac
+      else
+	case $host_cpu in
+	hppa*64*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	ia64*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+	m4_if($1, [], [
+	  # Older versions of the 11.00 compiler do not understand -b yet
+	  # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
+	  _LT_LINKER_OPTION([if $CC understands -b],
+	    _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b],
+	    [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'],
+	    [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])],
+	  [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'])
+	  ;;
+	esac
+      fi
+      if test no = "$with_gnu_ld"; then
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
+	_LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	case $host_cpu in
+	hppa*64*|ia64*)
+	  _LT_TAGVAR(hardcode_direct, $1)=no
+	  _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	  ;;
+	*)
+	  _LT_TAGVAR(hardcode_direct, $1)=yes
+	  _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+	  _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+
+	  # hardcode_minus_L: Not really in the search PATH,
+	  # but as the default location of the library.
+	  _LT_TAGVAR(hardcode_minus_L, $1)=yes
+	  ;;
+	esac
+      fi
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      if test yes = "$GCC"; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+	# Try to use the -exported_symbol ld option, if it does not
+	# work, assume that -exports_file does not work either and
+	# implicitly export all symbols.
+	# This should be the same for all languages, so no per-tag cache variable.
+	AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol],
+	  [lt_cv_irix_exported_symbol],
+	  [save_LDFLAGS=$LDFLAGS
+	   LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null"
+	   AC_LINK_IFELSE(
+	     [AC_LANG_SOURCE(
+	        [AC_LANG_CASE([C], [[int foo (void) { return 0; }]],
+			      [C++], [[int foo (void) { return 0; }]],
+			      [Fortran 77], [[
+      subroutine foo
+      end]],
+			      [Fortran], [[
+      subroutine foo
+      end]])])],
+	      [lt_cv_irix_exported_symbol=yes],
+	      [lt_cv_irix_exported_symbol=no])
+           LDFLAGS=$save_LDFLAGS])
+	if test yes = "$lt_cv_irix_exported_symbol"; then
+          _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib'
+	fi
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib'
+      fi
+      _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      _LT_TAGVAR(inherit_rpath, $1)=yes
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      ;;
+
+    linux*)
+      case $cc_basename in
+      tcc*)
+	# Fabrice Bellard et al's Tiny C Compiler
+	_LT_TAGVAR(ld_shlibs, $1)=yes
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	;;
+      esac
+      ;;
+
+    netbsd*)
+      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+	_LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'  # a.out
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags'      # ELF
+      fi
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    newsos6)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    *nto* | *qnx*)
+      ;;
+
+    openbsd* | bitrig*)
+      if test -f /usr/libexec/ld.so; then
+	_LT_TAGVAR(hardcode_direct, $1)=yes
+	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	_LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+	if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols'
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+	  _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+	else
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+	fi
+      else
+	_LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    os2*)
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+      shrext_cmds=.dll
+      _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+	$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+	$ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+	$ECHO EXPORTS >> $output_objdir/$libname.def~
+	emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
+	$CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+	emximp -o $lib $output_objdir/$libname.def'
+      _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+	$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+	$ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+	$ECHO EXPORTS >> $output_objdir/$libname.def~
+	prefix_cmds="$SED"~
+	if test EXPORTS = "`$SED 1q $export_symbols`"; then
+	  prefix_cmds="$prefix_cmds -e 1d";
+	fi~
+	prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
+	cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
+	$CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+	emximp -o $lib $output_objdir/$libname.def'
+      _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
+      _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+      ;;
+
+    osf3*)
+      if test yes = "$GCC"; then
+	_LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+      else
+	_LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+      fi
+      _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      ;;
+
+    osf4* | osf5*)	# as osf3* with the addition of -msym flag
+      if test yes = "$GCC"; then
+	_LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+      else
+	_LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
+          $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp'
+
+	# Both c and cxx compiler support -rpath directly
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+      fi
+      _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      ;;
+
+    solaris*)
+      _LT_TAGVAR(no_undefined_flag, $1)=' -z defs'
+      if test yes = "$GCC"; then
+	wlarc='$wl'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+          $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+      else
+	case `$CC -V 2>&1` in
+	*"Compilers 5.0"*)
+	  wlarc=''
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+            $LD -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+	  ;;
+	*)
+	  wlarc='$wl'
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+            $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+	  ;;
+	esac
+      fi
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      case $host_os in
+      solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+      *)
+	# The compiler driver will combine and reorder linker options,
+	# but understands '-z linker_flag'.  GCC discards it without '$wl',
+	# but is careful enough not to reorder.
+	# Supported since Solaris 2.6 (maybe 2.5.1?)
+	if test yes = "$GCC"; then
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract'
+	else
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
+	fi
+	;;
+      esac
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      ;;
+
+    sunos4*)
+      if test sequent = "$host_vendor"; then
+	# Use $CC to link under sequent, because it throws in some extra .o
+	# files that make .init and .fini sections work.
+	_LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    sysv4)
+      case $host_vendor in
+	sni)
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true???
+	;;
+	siemens)
+	  ## LD is ld it makes a PLAMLIB
+	  ## CC just makes a GrossModule.
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+	  _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs'
+	  _LT_TAGVAR(hardcode_direct, $1)=no
+        ;;
+	motorola)
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie
+	;;
+      esac
+      runpath_var='LD_RUN_PATH'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    sysv4.3*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	_LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	runpath_var=LD_RUN_PATH
+	hardcode_runpath_var=yes
+	_LT_TAGVAR(ld_shlibs, $1)=yes
+      fi
+      ;;
+
+    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+      _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text'
+      _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      runpath_var='LD_RUN_PATH'
+
+      if test yes = "$GCC"; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      ;;
+
+    sysv5* | sco3.2v5* | sco5v6*)
+      # Note: We CANNOT use -z defs as we might desire, because we do not
+      # link with -lc, and that would cause any symbols used from libc to
+      # always be unresolved, which means just about no library would
+      # ever link correctly.  If we're not using GNU ld we use -z text
+      # though, which does catch some bad symbols but isn't as heavy-handed
+      # as -z defs.
+      _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text'
+      _LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs'
+      _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport'
+      runpath_var='LD_RUN_PATH'
+
+      if test yes = "$GCC"; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      ;;
+
+    uts4*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    *)
+      _LT_TAGVAR(ld_shlibs, $1)=no
+      ;;
+    esac
+
+    if test sni = "$host_vendor"; then
+      case $host in
+      sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+	_LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Blargedynsym'
+	;;
+      esac
+    fi
+  fi
+])
+AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
+test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no
+
+_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld
+
+_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl
+_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl
+_LT_DECL([], [extract_expsyms_cmds], [2],
+    [The commands to extract the exported symbol list from a shared archive])
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in
+x|xyes)
+  # Assume -lc should be added
+  _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+
+  if test yes,yes = "$GCC,$enable_shared"; then
+    case $_LT_TAGVAR(archive_cmds, $1) in
+    *'~'*)
+      # FIXME: we may have to deal with multi-command sequences.
+      ;;
+    '$CC '*)
+      # Test whether the compiler implicitly links with -lc since on some
+      # systems, -lgcc has to come before -lc. If gcc already passes -lc
+      # to ld, don't add -lc before -lgcc.
+      AC_CACHE_CHECK([whether -lc should be explicitly linked in],
+	[lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1),
+	[$RM conftest*
+	echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+	if AC_TRY_EVAL(ac_compile) 2>conftest.err; then
+	  soname=conftest
+	  lib=conftest
+	  libobjs=conftest.$ac_objext
+	  deplibs=
+	  wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1)
+	  pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1)
+	  compiler_flags=-v
+	  linker_flags=-v
+	  verstring=
+	  output_objdir=.
+	  libname=conftest
+	  lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1)
+	  _LT_TAGVAR(allow_undefined_flag, $1)=
+	  if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1)
+	  then
+	    lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+	  else
+	    lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+	  fi
+	  _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag
+	else
+	  cat conftest.err 1>&5
+	fi
+	$RM conftest*
+	])
+      _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)
+      ;;
+    esac
+  fi
+  ;;
+esac
+
+_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0],
+    [Whether or not to add -lc for building shared libraries])
+_LT_TAGDECL([allow_libtool_libs_with_static_runtimes],
+    [enable_shared_with_static_runtimes], [0],
+    [Whether or not to disallow shared libs when runtime libs are static])
+_LT_TAGDECL([], [export_dynamic_flag_spec], [1],
+    [Compiler flag to allow reflexive dlopens])
+_LT_TAGDECL([], [whole_archive_flag_spec], [1],
+    [Compiler flag to generate shared objects directly from archives])
+_LT_TAGDECL([], [compiler_needs_object], [1],
+    [Whether the compiler copes with passing no objects directly])
+_LT_TAGDECL([], [old_archive_from_new_cmds], [2],
+    [Create an old-style archive from a shared archive])
+_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2],
+    [Create a temporary old-style archive to link instead of a shared archive])
+_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive])
+_LT_TAGDECL([], [archive_expsym_cmds], [2])
+_LT_TAGDECL([], [module_cmds], [2],
+    [Commands used to build a loadable module if different from building
+    a shared archive.])
+_LT_TAGDECL([], [module_expsym_cmds], [2])
+_LT_TAGDECL([], [with_gnu_ld], [1],
+    [Whether we are building with GNU ld or not])
+_LT_TAGDECL([], [allow_undefined_flag], [1],
+    [Flag that allows shared libraries with undefined symbols to be built])
+_LT_TAGDECL([], [no_undefined_flag], [1],
+    [Flag that enforces no undefined symbols])
+_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1],
+    [Flag to hardcode $libdir into a binary during linking.
+    This must work even if $libdir does not exist])
+_LT_TAGDECL([], [hardcode_libdir_separator], [1],
+    [Whether we need a single "-rpath" flag with a separated argument])
+_LT_TAGDECL([], [hardcode_direct], [0],
+    [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes
+    DIR into the resulting binary])
+_LT_TAGDECL([], [hardcode_direct_absolute], [0],
+    [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes
+    DIR into the resulting binary and the resulting library dependency is
+    "absolute", i.e impossible to change by setting $shlibpath_var if the
+    library is relocated])
+_LT_TAGDECL([], [hardcode_minus_L], [0],
+    [Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+    into the resulting binary])
+_LT_TAGDECL([], [hardcode_shlibpath_var], [0],
+    [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+    into the resulting binary])
+_LT_TAGDECL([], [hardcode_automatic], [0],
+    [Set to "yes" if building a shared library automatically hardcodes DIR
+    into the library and all subsequent libraries and executables linked
+    against it])
+_LT_TAGDECL([], [inherit_rpath], [0],
+    [Set to yes if linker adds runtime paths of dependent libraries
+    to runtime path list])
+_LT_TAGDECL([], [link_all_deplibs], [0],
+    [Whether libtool must link a program against all its dependency libraries])
+_LT_TAGDECL([], [always_export_symbols], [0],
+    [Set to "yes" if exported symbols are required])
+_LT_TAGDECL([], [export_symbols_cmds], [2],
+    [The commands to list exported symbols])
+_LT_TAGDECL([], [exclude_expsyms], [1],
+    [Symbols that should not be listed in the preloaded symbols])
+_LT_TAGDECL([], [include_expsyms], [1],
+    [Symbols that must always be exported])
+_LT_TAGDECL([], [prelink_cmds], [2],
+    [Commands necessary for linking programs (against libraries) with templates])
+_LT_TAGDECL([], [postlink_cmds], [2],
+    [Commands necessary for finishing linking programs])
+_LT_TAGDECL([], [file_list_spec], [1],
+    [Specify filename containing input files])
+dnl FIXME: Not yet implemented
+dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1],
+dnl    [Compiler flag to generate thread safe objects])
+])# _LT_LINKER_SHLIBS
+
+
+# _LT_LANG_C_CONFIG([TAG])
+# ------------------------
+# Ensure that the configuration variables for a C compiler are suitably
+# defined.  These variables are subsequently used by _LT_CONFIG to write
+# the compiler configuration to 'libtool'.
+m4_defun([_LT_LANG_C_CONFIG],
+[m4_require([_LT_DECL_EGREP])dnl
+lt_save_CC=$CC
+AC_LANG_PUSH(C)
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}'
+
+_LT_TAG_COMPILER
+# Save the default compiler, since it gets overwritten when the other
+# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
+compiler_DEFAULT=$CC
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+if test -n "$compiler"; then
+  _LT_COMPILER_NO_RTTI($1)
+  _LT_COMPILER_PIC($1)
+  _LT_COMPILER_C_O($1)
+  _LT_COMPILER_FILE_LOCKS($1)
+  _LT_LINKER_SHLIBS($1)
+  _LT_SYS_DYNAMIC_LINKER($1)
+  _LT_LINKER_HARDCODE_LIBPATH($1)
+  LT_SYS_DLOPEN_SELF
+  _LT_CMD_STRIPLIB
+
+  # Report what library types will actually be built
+  AC_MSG_CHECKING([if libtool supports shared libraries])
+  AC_MSG_RESULT([$can_build_shared])
+
+  AC_MSG_CHECKING([whether to build shared libraries])
+  test no = "$can_build_shared" && enable_shared=no
+
+  # On AIX, shared libraries and static libraries use the same namespace, and
+  # are all built from PIC.
+  case $host_os in
+  aix3*)
+    test yes = "$enable_shared" && enable_static=no
+    if test -n "$RANLIB"; then
+      archive_cmds="$archive_cmds~\$RANLIB \$lib"
+      postinstall_cmds='$RANLIB $lib'
+    fi
+    ;;
+
+  aix[[4-9]]*)
+    if test ia64 != "$host_cpu"; then
+      case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in
+      yes,aix,yes) ;;			# shared object as lib.so file only
+      yes,svr4,*) ;;			# shared object as lib.so archive member only
+      yes,*) enable_static=no ;;	# shared object in lib.a archive as well
+      esac
+    fi
+    ;;
+  esac
+  AC_MSG_RESULT([$enable_shared])
+
+  AC_MSG_CHECKING([whether to build static libraries])
+  # Make sure either enable_shared or enable_static is yes.
+  test yes = "$enable_shared" || enable_static=yes
+  AC_MSG_RESULT([$enable_static])
+
+  _LT_CONFIG($1)
+fi
+AC_LANG_POP
+CC=$lt_save_CC
+])# _LT_LANG_C_CONFIG
+
+
+# _LT_LANG_CXX_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for a C++ compiler are suitably
+# defined.  These variables are subsequently used by _LT_CONFIG to write
+# the compiler configuration to 'libtool'.
+m4_defun([_LT_LANG_CXX_CONFIG],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_PATH_MANIFEST_TOOL])dnl
+if test -n "$CXX" && ( test no != "$CXX" &&
+    ( (test g++ = "$CXX" && `g++ -v >/dev/null 2>&1` ) ||
+    (test g++ != "$CXX"))); then
+  AC_PROG_CXXCPP
+else
+  _lt_caught_CXX_error=yes
+fi
+
+AC_LANG_PUSH(C++)
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(compiler_needs_object, $1)=no
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for C++ test sources.
+ac_ext=cpp
+
+# Object file extension for compiled C++ test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the CXX compiler isn't working.  Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test yes != "$_lt_caught_CXX_error"; then
+  # Code to be used in simple compile tests
+  lt_simple_compile_test_code="int some_variable = 0;"
+
+  # Code to be used in simple link tests
+  lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }'
+
+  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+  _LT_TAG_COMPILER
+
+  # save warnings/boilerplate of simple test code
+  _LT_COMPILER_BOILERPLATE
+  _LT_LINKER_BOILERPLATE
+
+  # Allow CC to be a program name with arguments.
+  lt_save_CC=$CC
+  lt_save_CFLAGS=$CFLAGS
+  lt_save_LD=$LD
+  lt_save_GCC=$GCC
+  GCC=$GXX
+  lt_save_with_gnu_ld=$with_gnu_ld
+  lt_save_path_LD=$lt_cv_path_LD
+  if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
+    lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
+  else
+    $as_unset lt_cv_prog_gnu_ld
+  fi
+  if test -n "${lt_cv_path_LDCXX+set}"; then
+    lt_cv_path_LD=$lt_cv_path_LDCXX
+  else
+    $as_unset lt_cv_path_LD
+  fi
+  test -z "${LDCXX+set}" || LD=$LDCXX
+  CC=${CXX-"c++"}
+  CFLAGS=$CXXFLAGS
+  compiler=$CC
+  _LT_TAGVAR(compiler, $1)=$CC
+  _LT_CC_BASENAME([$compiler])
+
+  if test -n "$compiler"; then
+    # We don't want -fno-exception when compiling C++ code, so set the
+    # no_builtin_flag separately
+    if test yes = "$GXX"; then
+      _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
+    else
+      _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+    fi
+
+    if test yes = "$GXX"; then
+      # Set up default GNU C++ configuration
+
+      LT_PATH_LD
+
+      # Check if GNU C++ uses GNU ld as the underlying linker, since the
+      # archiving commands below assume that GNU ld is being used.
+      if test yes = "$with_gnu_ld"; then
+        _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+        _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+        _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
+
+        # If archive_cmds runs LD, not CC, wlarc should be empty
+        # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
+        #     investigate it a little bit more. (MM)
+        wlarc='$wl'
+
+        # ancient GNU ld didn't support --whole-archive et. al.
+        if eval "`$CC -print-prog-name=ld` --help 2>&1" |
+	  $GREP 'no-whole-archive' > /dev/null; then
+          _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
+        else
+          _LT_TAGVAR(whole_archive_flag_spec, $1)=
+        fi
+      else
+        with_gnu_ld=no
+        wlarc=
+
+        # A generic and very simple default shared library creation
+        # command for GNU C++ for the case where it uses the native
+        # linker, instead of GNU ld.  If possible, this setting should
+        # overridden to take advantage of the native linker features on
+        # the platform it is being used on.
+        _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+      fi
+
+      # Commands to make compiler produce verbose output that lists
+      # what "hidden" libraries, object files and flags are used when
+      # linking a shared library.
+      output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+
+    else
+      GXX=no
+      with_gnu_ld=no
+      wlarc=
+    fi
+
+    # PORTME: fill in a description of your system's C++ link characteristics
+    AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+    _LT_TAGVAR(ld_shlibs, $1)=yes
+    case $host_os in
+      aix3*)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+      aix[[4-9]]*)
+        if test ia64 = "$host_cpu"; then
+          # On IA64, the linker does run time linking by default, so we don't
+          # have to do anything special.
+          aix_use_runtimelinking=no
+          exp_sym_flag='-Bexport'
+          no_entry_flag=
+        else
+          aix_use_runtimelinking=no
+
+          # Test if we are trying to use run time linking or normal
+          # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+          # have runtime linking enabled, and use it for executables.
+          # For shared libraries, we enable/disable runtime linking
+          # depending on the kind of the shared library created -
+          # when "with_aix_soname,aix_use_runtimelinking" is:
+          # "aix,no"   lib.a(lib.so.V) shared, rtl:no,  for executables
+          # "aix,yes"  lib.so          shared, rtl:yes, for executables
+          #            lib.a           static archive
+          # "both,no"  lib.so.V(shr.o) shared, rtl:yes
+          #            lib.a(lib.so.V) shared, rtl:no,  for executables
+          # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables
+          #            lib.a(lib.so.V) shared, rtl:no
+          # "svr4,*"   lib.so.V(shr.o) shared, rtl:yes, for executables
+          #            lib.a           static archive
+          case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
+	    for ld_flag in $LDFLAGS; do
+	      case $ld_flag in
+	      *-brtl*)
+	        aix_use_runtimelinking=yes
+	        break
+	        ;;
+	      esac
+	    done
+	    if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then
+	      # With aix-soname=svr4, we create the lib.so.V shared archives only,
+	      # so we don't have lib.a shared libs to link our executables.
+	      # We have to force runtime linking in this case.
+	      aix_use_runtimelinking=yes
+	      LDFLAGS="$LDFLAGS -Wl,-brtl"
+	    fi
+	    ;;
+          esac
+
+          exp_sym_flag='-bexport'
+          no_entry_flag='-bnoentry'
+        fi
+
+        # When large executables or shared objects are built, AIX ld can
+        # have problems creating the table of contents.  If linking a library
+        # or program results in "error TOC overflow" add -mminimal-toc to
+        # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+        # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+        _LT_TAGVAR(archive_cmds, $1)=''
+        _LT_TAGVAR(hardcode_direct, $1)=yes
+        _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+        _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+        _LT_TAGVAR(link_all_deplibs, $1)=yes
+        _LT_TAGVAR(file_list_spec, $1)='$wl-f,'
+        case $with_aix_soname,$aix_use_runtimelinking in
+        aix,*) ;;	# no import file
+        svr4,* | *,yes) # use import file
+          # The Import File defines what to hardcode.
+          _LT_TAGVAR(hardcode_direct, $1)=no
+          _LT_TAGVAR(hardcode_direct_absolute, $1)=no
+          ;;
+        esac
+
+        if test yes = "$GXX"; then
+          case $host_os in aix4.[[012]]|aix4.[[012]].*)
+          # We only want to do this on AIX 4.2 and lower, the check
+          # below for broken collect2 doesn't work under 4.3+
+	  collect2name=`$CC -print-prog-name=collect2`
+	  if test -f "$collect2name" &&
+	     strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+	  then
+	    # We have reworked collect2
+	    :
+	  else
+	    # We have old collect2
+	    _LT_TAGVAR(hardcode_direct, $1)=unsupported
+	    # It fails to find uninstalled libraries when the uninstalled
+	    # path is not listed in the libpath.  Setting hardcode_minus_L
+	    # to unsupported forces relinking
+	    _LT_TAGVAR(hardcode_minus_L, $1)=yes
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+	    _LT_TAGVAR(hardcode_libdir_separator, $1)=
+	  fi
+          esac
+          shared_flag='-shared'
+	  if test yes = "$aix_use_runtimelinking"; then
+	    shared_flag=$shared_flag' $wl-G'
+	  fi
+	  # Need to ensure runtime linking is disabled for the traditional
+	  # shared library, or the linker may eventually find shared libraries
+	  # /with/ Import File - we do not want to mix them.
+	  shared_flag_aix='-shared'
+	  shared_flag_svr4='-shared $wl-G'
+        else
+          # not using gcc
+          if test ia64 = "$host_cpu"; then
+	  # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+	  # chokes on -Wl,-G. The following line is correct:
+	  shared_flag='-G'
+          else
+	    if test yes = "$aix_use_runtimelinking"; then
+	      shared_flag='$wl-G'
+	    else
+	      shared_flag='$wl-bM:SRE'
+	    fi
+	    shared_flag_aix='$wl-bM:SRE'
+	    shared_flag_svr4='$wl-G'
+          fi
+        fi
+
+        _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall'
+        # It seems that -bexpall does not export symbols beginning with
+        # underscore (_), so it is better to generate a list of symbols to
+	# export.
+        _LT_TAGVAR(always_export_symbols, $1)=yes
+	if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then
+          # Warning - without using the other runtime loading flags (-brtl),
+          # -berok will link without error, but may produce a broken library.
+          # The "-G" linker flag allows undefined symbols.
+          _LT_TAGVAR(no_undefined_flag, $1)='-bernotok'
+          # Determine the default libpath from the value encoded in an empty
+          # executable.
+          _LT_SYS_MODULE_PATH_AIX([$1])
+          _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath"
+
+          _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag
+        else
+          if test ia64 = "$host_cpu"; then
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib'
+	    _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+	    _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols"
+          else
+	    # Determine the default libpath from the value encoded in an
+	    # empty executable.
+	    _LT_SYS_MODULE_PATH_AIX([$1])
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath"
+	    # Warning - without using the other run time loading flags,
+	    # -berok will link without error, but may produce a broken library.
+	    _LT_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok'
+	    _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok'
+	    if test yes = "$with_gnu_ld"; then
+	      # We only use this code for GNU lds that support --whole-archive.
+	      _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive'
+	    else
+	      # Exported symbols can be pulled into shared objects from archives
+	      _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+	    fi
+	    _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d'
+	    # -brtl affects multiple linker settings, -berok does not and is overridden later
+	    compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`'
+	    if test svr4 != "$with_aix_soname"; then
+	      # This is similar to how AIX traditionally builds its shared
+	      # libraries. Need -bnortl late, we may have -brtl in LDFLAGS.
+	      _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname'
+	    fi
+	    if test aix != "$with_aix_soname"; then
+	      _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp'
+	    else
+	      # used by -dlpreopen to get the symbols
+	      _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV  $output_objdir/$realname.d/$soname $output_objdir'
+	    fi
+	    _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d'
+          fi
+        fi
+        ;;
+
+      beos*)
+	if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	  _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+	  # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+	  # support --undefined.  This deserves some investigation.  FIXME
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+	else
+	  _LT_TAGVAR(ld_shlibs, $1)=no
+	fi
+	;;
+
+      chorus*)
+        case $cc_basename in
+          *)
+	  # FIXME: insert proper C++ library support
+	  _LT_TAGVAR(ld_shlibs, $1)=no
+	  ;;
+        esac
+        ;;
+
+      cygwin* | mingw* | pw32* | cegcc*)
+	case $GXX,$cc_basename in
+	,cl* | no,cl*)
+	  # Native MSVC
+	  # hardcode_libdir_flag_spec is actually meaningless, as there is
+	  # no search path for DLLs.
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+	  _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+	  _LT_TAGVAR(always_export_symbols, $1)=yes
+	  _LT_TAGVAR(file_list_spec, $1)='@'
+	  # Tell ltmain to make .lib files, not .a files.
+	  libext=lib
+	  # Tell ltmain to make .dll files, not .so files.
+	  shrext_cmds=.dll
+	  # FIXME: Setting linknames here is a bad hack.
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames='
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then
+              cp "$export_symbols" "$output_objdir/$soname.def";
+              echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp";
+            else
+              $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp;
+            fi~
+            $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+            linknames='
+	  # The linker will not automatically build a static lib if we build a DLL.
+	  # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+	  _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+	  # Don't use ranlib
+	  _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib'
+	  _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~
+            lt_tool_outputfile="@TOOL_OUTPUT@"~
+            case $lt_outputfile in
+              *.exe|*.EXE) ;;
+              *)
+                lt_outputfile=$lt_outputfile.exe
+                lt_tool_outputfile=$lt_tool_outputfile.exe
+                ;;
+            esac~
+            func_to_tool_file "$lt_outputfile"~
+            if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then
+              $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+              $RM "$lt_outputfile.manifest";
+            fi'
+	  ;;
+	*)
+	  # g++
+	  # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+	  # as there is no search path for DLLs.
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+	  _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols'
+	  _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+	  _LT_TAGVAR(always_export_symbols, $1)=no
+	  _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+
+	  if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+	    # If the export-symbols file already is a .def file, use it as
+	    # is; otherwise, prepend EXPORTS...
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then
+              cp $export_symbols $output_objdir/$soname.def;
+            else
+              echo EXPORTS > $output_objdir/$soname.def;
+              cat $export_symbols >> $output_objdir/$soname.def;
+            fi~
+            $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+	  else
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	  fi
+	  ;;
+	esac
+	;;
+      darwin* | rhapsody*)
+        _LT_DARWIN_LINKER_FEATURES($1)
+	;;
+
+      os2*)
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+	_LT_TAGVAR(hardcode_minus_L, $1)=yes
+	_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+	shrext_cmds=.dll
+	_LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+	  $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+	  $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+	  $ECHO EXPORTS >> $output_objdir/$libname.def~
+	  emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
+	  $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+	  emximp -o $lib $output_objdir/$libname.def'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+	  $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+	  $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+	  $ECHO EXPORTS >> $output_objdir/$libname.def~
+	  prefix_cmds="$SED"~
+	  if test EXPORTS = "`$SED 1q $export_symbols`"; then
+	    prefix_cmds="$prefix_cmds -e 1d";
+	  fi~
+	  prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
+	  cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
+	  $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+	  emximp -o $lib $output_objdir/$libname.def'
+	_LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
+	_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+	;;
+
+      dgux*)
+        case $cc_basename in
+          ec++*)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          ghcx*)
+	    # Green Hills C++ Compiler
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          *)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+        esac
+        ;;
+
+      freebsd2.*)
+        # C++ shared libraries reported to be fairly broken before
+	# switch to ELF
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+
+      freebsd-elf*)
+        _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+        ;;
+
+      freebsd* | dragonfly*)
+        # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
+        # conventions
+        _LT_TAGVAR(ld_shlibs, $1)=yes
+        ;;
+
+      haiku*)
+        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+        _LT_TAGVAR(link_all_deplibs, $1)=yes
+        ;;
+
+      hpux9*)
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
+        _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+        _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+        _LT_TAGVAR(hardcode_direct, $1)=yes
+        _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+				             # but as the default
+				             # location of the library.
+
+        case $cc_basename in
+          CC*)
+            # FIXME: insert proper C++ library support
+            _LT_TAGVAR(ld_shlibs, $1)=no
+            ;;
+          aCC*)
+            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
+            # Commands to make compiler produce verbose output that lists
+            # what "hidden" libraries, object files and flags are used when
+            # linking a shared library.
+            #
+            # There doesn't appear to be a way to prevent this compiler from
+            # explicitly linking system object files so we need to strip them
+            # from the output so that they don't get included in the library
+            # dependencies.
+            output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+            ;;
+          *)
+            if test yes = "$GXX"; then
+              _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
+            else
+              # FIXME: insert proper C++ library support
+              _LT_TAGVAR(ld_shlibs, $1)=no
+            fi
+            ;;
+        esac
+        ;;
+
+      hpux10*|hpux11*)
+        if test no = "$with_gnu_ld"; then
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
+	  _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+          case $host_cpu in
+            hppa*64*|ia64*)
+              ;;
+            *)
+	      _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+              ;;
+          esac
+        fi
+        case $host_cpu in
+          hppa*64*|ia64*)
+            _LT_TAGVAR(hardcode_direct, $1)=no
+            _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+            ;;
+          *)
+            _LT_TAGVAR(hardcode_direct, $1)=yes
+            _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+            _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+					         # but as the default
+					         # location of the library.
+            ;;
+        esac
+
+        case $cc_basename in
+          CC*)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          aCC*)
+	    case $host_cpu in
+	      hppa*64*)
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	        ;;
+	      ia64*)
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	        ;;
+	      *)
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	        ;;
+	    esac
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+	    ;;
+          *)
+	    if test yes = "$GXX"; then
+	      if test no = "$with_gnu_ld"; then
+	        case $host_cpu in
+	          hppa*64*)
+	            _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	            ;;
+	          ia64*)
+	            _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	            ;;
+	          *)
+	            _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	            ;;
+	        esac
+	      fi
+	    else
+	      # FIXME: insert proper C++ library support
+	      _LT_TAGVAR(ld_shlibs, $1)=no
+	    fi
+	    ;;
+        esac
+        ;;
+
+      interix[[3-9]]*)
+	_LT_TAGVAR(hardcode_direct, $1)=no
+	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+	_LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+	# Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+	# Instead, shared libraries are loaded at an image base (0x10000000 by
+	# default) and relocated if they conflict, which is a slow very memory
+	# consuming and fragmenting process.  To avoid this, we pick a random,
+	# 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+	# time.  Moving up from 0x10000000 also allows more sbrk(2) space.
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+	;;
+      irix5* | irix6*)
+        case $cc_basename in
+          CC*)
+	    # SGI C++
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+
+	    # Archives containing C++ object files must be created using
+	    # "CC -ar", where "CC" is the IRIX C++ compiler.  This is
+	    # necessary to make sure instantiated templates are included
+	    # in the archive.
+	    _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs'
+	    ;;
+          *)
+	    if test yes = "$GXX"; then
+	      if test no = "$with_gnu_ld"; then
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+	      else
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` -o $lib'
+	      fi
+	    fi
+	    _LT_TAGVAR(link_all_deplibs, $1)=yes
+	    ;;
+        esac
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+        _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+        _LT_TAGVAR(inherit_rpath, $1)=yes
+        ;;
+
+      linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+        case $cc_basename in
+          KCC*)
+	    # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+	    # KCC will only create a shared library if the output file
+	    # ends with ".so" (or ".sl" for HP-UX), so rename the library
+	    # to its proper name (with version) after linking.
+	    _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib $wl-retain-symbols-file,$export_symbols; mv \$templib $lib'
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
+
+	    # Archives containing C++ object files must be created using
+	    # "CC -Bstatic", where "CC" is the KAI C++ compiler.
+	    _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
+	    ;;
+	  icpc* | ecpc* )
+	    # Intel C++
+	    with_gnu_ld=yes
+	    # version 8.0 and above of icpc choke on multiply defined symbols
+	    # if we add $predep_objects and $postdep_objects, however 7.1 and
+	    # earlier do not add the objects themselves.
+	    case `$CC -V 2>&1` in
+	      *"Version 7."*)
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+		_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+		;;
+	      *)  # Version 8.0 or newer
+	        tmp_idyn=
+	        case $host_cpu in
+		  ia64*) tmp_idyn=' -i_dynamic';;
+		esac
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+		_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+		;;
+	    esac
+	    _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
+	    _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive'
+	    ;;
+          pgCC* | pgcpp*)
+            # Portland Group C++ compiler
+	    case `$CC -V` in
+	    *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*)
+	      _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~
+               rm -rf $tpldir~
+               $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
+               compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
+	      _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~
+                rm -rf $tpldir~
+                $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
+                $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
+                $RANLIB $oldlib'
+	      _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~
+                rm -rf $tpldir~
+                $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+                $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+	      _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~
+                rm -rf $tpldir~
+                $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+                $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+	      ;;
+	    *) # Version 6 and above use weak symbols
+	      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+	      _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+	      ;;
+	    esac
+
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl--rpath $wl$libdir'
+	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
+	    _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+            ;;
+	  cxx*)
+	    # Compaq C++
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname  -o $lib $wl-retain-symbols-file $wl$export_symbols'
+
+	    runpath_var=LD_RUN_PATH
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+	    _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed'
+	    ;;
+	  xl* | mpixl* | bgxl*)
+	    # IBM XL 8.0 on PPC, with GNU ld
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+	    if test yes = "$supports_anon_versioning"; then
+	      _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+                cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+                echo "local: *; };" >> $output_objdir/$libname.ver~
+                $CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib'
+	    fi
+	    ;;
+	  *)
+	    case `$CC -V 2>&1 | sed 5q` in
+	    *Sun\ C*)
+	      # Sun C++ 5.9
+	      _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+	      _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	      _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file $wl$export_symbols'
+	      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+	      _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+	      _LT_TAGVAR(compiler_needs_object, $1)=yes
+
+	      # Not sure whether something based on
+	      # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1
+	      # would be better.
+	      output_verbose_link_cmd='func_echo_all'
+
+	      # Archives containing C++ object files must be created using
+	      # "CC -xar", where "CC" is the Sun C++ compiler.  This is
+	      # necessary to make sure instantiated templates are included
+	      # in the archive.
+	      _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+	      ;;
+	    esac
+	    ;;
+	esac
+	;;
+
+      lynxos*)
+        # FIXME: insert proper C++ library support
+	_LT_TAGVAR(ld_shlibs, $1)=no
+	;;
+
+      m88k*)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+	;;
+
+      mvs*)
+        case $cc_basename in
+          cxx*)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+	  *)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+	esac
+	;;
+
+      netbsd*)
+        if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable  -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
+	  wlarc=
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+	  _LT_TAGVAR(hardcode_direct, $1)=yes
+	  _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	fi
+	# Workaround some broken pre-1.5 toolchains
+	output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
+	;;
+
+      *nto* | *qnx*)
+        _LT_TAGVAR(ld_shlibs, $1)=yes
+	;;
+
+      openbsd* | bitrig*)
+	if test -f /usr/libexec/ld.so; then
+	  _LT_TAGVAR(hardcode_direct, $1)=yes
+	  _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	  _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+	  if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`"; then
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file,$export_symbols -o $lib'
+	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+	    _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
+	  fi
+	  output_verbose_link_cmd=func_echo_all
+	else
+	  _LT_TAGVAR(ld_shlibs, $1)=no
+	fi
+	;;
+
+      osf3* | osf4* | osf5*)
+        case $cc_basename in
+          KCC*)
+	    # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+	    # KCC will only create a shared library if the output file
+	    # ends with ".so" (or ".sl" for HP-UX), so rename the library
+	    # to its proper name (with version) after linking.
+	    _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+	    _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	    # Archives containing C++ object files must be created using
+	    # the KAI C++ compiler.
+	    case $host in
+	      osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;;
+	      *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;;
+	    esac
+	    ;;
+          RCC*)
+	    # Rational C++ 2.4.1
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          cxx*)
+	    case $host in
+	      osf3*)
+	        _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*'
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $soname `test -n "$verstring" && func_echo_all "$wl-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+	        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+		;;
+	      *)
+	        _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+	        _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
+                  echo "-hidden">> $lib.exp~
+                  $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname $wl-input $wl$lib.exp  `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~
+                  $RM $lib.exp'
+	        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+		;;
+	    esac
+
+	    _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+	    ;;
+	  *)
+	    if test yes,no = "$GXX,$with_gnu_ld"; then
+	      _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*'
+	      case $host in
+	        osf3*)
+	          _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+		  ;;
+	        *)
+	          _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+		  ;;
+	      esac
+
+	      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+	      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	      # Commands to make compiler produce verbose output that lists
+	      # what "hidden" libraries, object files and flags are used when
+	      # linking a shared library.
+	      output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+
+	    else
+	      # FIXME: insert proper C++ library support
+	      _LT_TAGVAR(ld_shlibs, $1)=no
+	    fi
+	    ;;
+        esac
+        ;;
+
+      psos*)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+
+      sunos4*)
+        case $cc_basename in
+          CC*)
+	    # Sun C++ 4.x
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          lcc*)
+	    # Lucid
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          *)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+        esac
+        ;;
+
+      solaris*)
+        case $cc_basename in
+          CC* | sunCC*)
+	    # Sun C++ 4.2, 5.x and Centerline C++
+            _LT_TAGVAR(archive_cmds_need_lc,$1)=yes
+	    _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+              $CC -G$allow_undefined_flag $wl-M $wl$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+	    _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	    case $host_os in
+	      solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+	      *)
+		# The compiler driver will combine and reorder linker options,
+		# but understands '-z linker_flag'.
+	        # Supported since Solaris 2.6 (maybe 2.5.1?)
+		_LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
+	        ;;
+	    esac
+	    _LT_TAGVAR(link_all_deplibs, $1)=yes
+
+	    output_verbose_link_cmd='func_echo_all'
+
+	    # Archives containing C++ object files must be created using
+	    # "CC -xar", where "CC" is the Sun C++ compiler.  This is
+	    # necessary to make sure instantiated templates are included
+	    # in the archive.
+	    _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+	    ;;
+          gcx*)
+	    # Green Hills C++ Compiler
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib'
+
+	    # The C++ compiler must be used to create the archive.
+	    _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
+	    ;;
+          *)
+	    # GNU C++ compiler with Solaris linker
+	    if test yes,no = "$GXX,$with_gnu_ld"; then
+	      _LT_TAGVAR(no_undefined_flag, $1)=' $wl-z ${wl}defs'
+	      if $CC --version | $GREP -v '^2\.7' > /dev/null; then
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib'
+	        _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+                  $CC -shared $pic_flag -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+	        # Commands to make compiler produce verbose output that lists
+	        # what "hidden" libraries, object files and flags are used when
+	        # linking a shared library.
+	        output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+	      else
+	        # g++ 2.7 appears to require '-G' NOT '-shared' on this
+	        # platform.
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib'
+	        _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+                  $CC -G -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+	        # Commands to make compiler produce verbose output that lists
+	        # what "hidden" libraries, object files and flags are used when
+	        # linking a shared library.
+	        output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+	      fi
+
+	      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $wl$libdir'
+	      case $host_os in
+		solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+		*)
+		  _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract'
+		  ;;
+	      esac
+	    fi
+	    ;;
+        esac
+        ;;
+
+    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+      _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text'
+      _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      runpath_var='LD_RUN_PATH'
+
+      case $cc_basename in
+        CC*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+      esac
+      ;;
+
+      sysv5* | sco3.2v5* | sco5v6*)
+	# Note: We CANNOT use -z defs as we might desire, because we do not
+	# link with -lc, and that would cause any symbols used from libc to
+	# always be unresolved, which means just about no library would
+	# ever link correctly.  If we're not using GNU ld we use -z text
+	# though, which does catch some bad symbols but isn't as heavy-handed
+	# as -z defs.
+	_LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text'
+	_LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs'
+	_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir'
+	_LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+	_LT_TAGVAR(link_all_deplibs, $1)=yes
+	_LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport'
+	runpath_var='LD_RUN_PATH'
+
+	case $cc_basename in
+          CC*)
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~
+              '"$_LT_TAGVAR(old_archive_cmds, $1)"
+	    _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~
+              '"$_LT_TAGVAR(reload_cmds, $1)"
+	    ;;
+	  *)
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    ;;
+	esac
+      ;;
+
+      tandem*)
+        case $cc_basename in
+          NCC*)
+	    # NonStop-UX NCC 3.20
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          *)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+        esac
+        ;;
+
+      vxworks*)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+
+      *)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+    esac
+
+    AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
+    test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no
+
+    _LT_TAGVAR(GCC, $1)=$GXX
+    _LT_TAGVAR(LD, $1)=$LD
+
+    ## CAVEAT EMPTOR:
+    ## There is no encapsulation within the following macros, do not change
+    ## the running order or otherwise move them around unless you know exactly
+    ## what you are doing...
+    _LT_SYS_HIDDEN_LIBDEPS($1)
+    _LT_COMPILER_PIC($1)
+    _LT_COMPILER_C_O($1)
+    _LT_COMPILER_FILE_LOCKS($1)
+    _LT_LINKER_SHLIBS($1)
+    _LT_SYS_DYNAMIC_LINKER($1)
+    _LT_LINKER_HARDCODE_LIBPATH($1)
+
+    _LT_CONFIG($1)
+  fi # test -n "$compiler"
+
+  CC=$lt_save_CC
+  CFLAGS=$lt_save_CFLAGS
+  LDCXX=$LD
+  LD=$lt_save_LD
+  GCC=$lt_save_GCC
+  with_gnu_ld=$lt_save_with_gnu_ld
+  lt_cv_path_LDCXX=$lt_cv_path_LD
+  lt_cv_path_LD=$lt_save_path_LD
+  lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
+  lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
+fi # test yes != "$_lt_caught_CXX_error"
+
+AC_LANG_POP
+])# _LT_LANG_CXX_CONFIG
+
+
+# _LT_FUNC_STRIPNAME_CNF
+# ----------------------
+# func_stripname_cnf prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+#
+# This function is identical to the (non-XSI) version of func_stripname,
+# except this one can be used by m4 code that may be executed by configure,
+# rather than the libtool script.
+m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl
+AC_REQUIRE([_LT_DECL_SED])
+AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])
+func_stripname_cnf ()
+{
+  case @S|@2 in
+  .*) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%\\\\@S|@2\$%%"`;;
+  *)  func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%@S|@2\$%%"`;;
+  esac
+} # func_stripname_cnf
+])# _LT_FUNC_STRIPNAME_CNF
+
+
+# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME])
+# ---------------------------------
+# Figure out "hidden" library dependencies from verbose
+# compiler output when linking a shared library.
+# Parse the compiler output and extract the necessary
+# objects, libraries and library flags.
+m4_defun([_LT_SYS_HIDDEN_LIBDEPS],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl
+# Dependencies to place before and after the object being linked:
+_LT_TAGVAR(predep_objects, $1)=
+_LT_TAGVAR(postdep_objects, $1)=
+_LT_TAGVAR(predeps, $1)=
+_LT_TAGVAR(postdeps, $1)=
+_LT_TAGVAR(compiler_lib_search_path, $1)=
+
+dnl we can't use the lt_simple_compile_test_code here,
+dnl because it contains code intended for an executable,
+dnl not a library.  It's possible we should let each
+dnl tag define a new lt_????_link_test_code variable,
+dnl but it's only used here...
+m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF
+int a;
+void foo (void) { a = 0; }
+_LT_EOF
+], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF
+class Foo
+{
+public:
+  Foo (void) { a = 0; }
+private:
+  int a;
+};
+_LT_EOF
+], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF
+      subroutine foo
+      implicit none
+      integer*4 a
+      a=0
+      return
+      end
+_LT_EOF
+], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF
+      subroutine foo
+      implicit none
+      integer a
+      a=0
+      return
+      end
+_LT_EOF
+], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF
+public class foo {
+  private int a;
+  public void bar (void) {
+    a = 0;
+  }
+};
+_LT_EOF
+], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF
+package foo
+func foo() {
+}
+_LT_EOF
+])
+
+_lt_libdeps_save_CFLAGS=$CFLAGS
+case "$CC $CFLAGS " in #(
+*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;;
+*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;;
+*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;;
+esac
+
+dnl Parse the compiler output and extract the necessary
+dnl objects, libraries and library flags.
+if AC_TRY_EVAL(ac_compile); then
+  # Parse the compiler output and extract the necessary
+  # objects, libraries and library flags.
+
+  # Sentinel used to keep track of whether or not we are before
+  # the conftest object file.
+  pre_test_object_deps_done=no
+
+  for p in `eval "$output_verbose_link_cmd"`; do
+    case $prev$p in
+
+    -L* | -R* | -l*)
+       # Some compilers place space between "-{L,R}" and the path.
+       # Remove the space.
+       if test x-L = "$p" ||
+          test x-R = "$p"; then
+	 prev=$p
+	 continue
+       fi
+
+       # Expand the sysroot to ease extracting the directories later.
+       if test -z "$prev"; then
+         case $p in
+         -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;;
+         -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;;
+         -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;;
+         esac
+       fi
+       case $p in
+       =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;;
+       esac
+       if test no = "$pre_test_object_deps_done"; then
+	 case $prev in
+	 -L | -R)
+	   # Internal compiler library paths should come after those
+	   # provided the user.  The postdeps already come after the
+	   # user supplied libs so there is no need to process them.
+	   if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then
+	     _LT_TAGVAR(compiler_lib_search_path, $1)=$prev$p
+	   else
+	     _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} $prev$p"
+	   fi
+	   ;;
+	 # The "-l" case would never come before the object being
+	 # linked, so don't bother handling this case.
+	 esac
+       else
+	 if test -z "$_LT_TAGVAR(postdeps, $1)"; then
+	   _LT_TAGVAR(postdeps, $1)=$prev$p
+	 else
+	   _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} $prev$p"
+	 fi
+       fi
+       prev=
+       ;;
+
+    *.lto.$objext) ;; # Ignore GCC LTO objects
+    *.$objext)
+       # This assumes that the test object file only shows up
+       # once in the compiler output.
+       if test "$p" = "conftest.$objext"; then
+	 pre_test_object_deps_done=yes
+	 continue
+       fi
+
+       if test no = "$pre_test_object_deps_done"; then
+	 if test -z "$_LT_TAGVAR(predep_objects, $1)"; then
+	   _LT_TAGVAR(predep_objects, $1)=$p
+	 else
+	   _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p"
+	 fi
+       else
+	 if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then
+	   _LT_TAGVAR(postdep_objects, $1)=$p
+	 else
+	   _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p"
+	 fi
+       fi
+       ;;
+
+    *) ;; # Ignore the rest.
+
+    esac
+  done
+
+  # Clean up.
+  rm -f a.out a.exe
+else
+  echo "libtool.m4: error: problem compiling $1 test program"
+fi
+
+$RM -f confest.$objext
+CFLAGS=$_lt_libdeps_save_CFLAGS
+
+# PORTME: override above test on systems where it is broken
+m4_if([$1], [CXX],
+[case $host_os in
+interix[[3-9]]*)
+  # Interix 3.5 installs completely hosed .la files for C++, so rather than
+  # hack all around it, let's just trust "g++" to DTRT.
+  _LT_TAGVAR(predep_objects,$1)=
+  _LT_TAGVAR(postdep_objects,$1)=
+  _LT_TAGVAR(postdeps,$1)=
+  ;;
+esac
+])
+
+case " $_LT_TAGVAR(postdeps, $1) " in
+*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;;
+esac
+ _LT_TAGVAR(compiler_lib_search_dirs, $1)=
+if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then
+ _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | $SED -e 's! -L! !g' -e 's!^ !!'`
+fi
+_LT_TAGDECL([], [compiler_lib_search_dirs], [1],
+    [The directories searched by this compiler when creating a shared library])
+_LT_TAGDECL([], [predep_objects], [1],
+    [Dependencies to place before and after the objects being linked to
+    create a shared library])
+_LT_TAGDECL([], [postdep_objects], [1])
+_LT_TAGDECL([], [predeps], [1])
+_LT_TAGDECL([], [postdeps], [1])
+_LT_TAGDECL([], [compiler_lib_search_path], [1],
+    [The library search path used internally by the compiler when linking
+    a shared library])
+])# _LT_SYS_HIDDEN_LIBDEPS
+
+
+# _LT_LANG_F77_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for a Fortran 77 compiler are
+# suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to 'libtool'.
+m4_defun([_LT_LANG_F77_CONFIG],
+[AC_LANG_PUSH(Fortran 77)
+if test -z "$F77" || test no = "$F77"; then
+  _lt_disable_F77=yes
+fi
+
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for f77 test sources.
+ac_ext=f
+
+# Object file extension for compiled f77 test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the F77 compiler isn't working.  Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test yes != "$_lt_disable_F77"; then
+  # Code to be used in simple compile tests
+  lt_simple_compile_test_code="\
+      subroutine t
+      return
+      end
+"
+
+  # Code to be used in simple link tests
+  lt_simple_link_test_code="\
+      program t
+      end
+"
+
+  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+  _LT_TAG_COMPILER
+
+  # save warnings/boilerplate of simple test code
+  _LT_COMPILER_BOILERPLATE
+  _LT_LINKER_BOILERPLATE
+
+  # Allow CC to be a program name with arguments.
+  lt_save_CC=$CC
+  lt_save_GCC=$GCC
+  lt_save_CFLAGS=$CFLAGS
+  CC=${F77-"f77"}
+  CFLAGS=$FFLAGS
+  compiler=$CC
+  _LT_TAGVAR(compiler, $1)=$CC
+  _LT_CC_BASENAME([$compiler])
+  GCC=$G77
+  if test -n "$compiler"; then
+    AC_MSG_CHECKING([if libtool supports shared libraries])
+    AC_MSG_RESULT([$can_build_shared])
+
+    AC_MSG_CHECKING([whether to build shared libraries])
+    test no = "$can_build_shared" && enable_shared=no
+
+    # On AIX, shared libraries and static libraries use the same namespace, and
+    # are all built from PIC.
+    case $host_os in
+      aix3*)
+        test yes = "$enable_shared" && enable_static=no
+        if test -n "$RANLIB"; then
+          archive_cmds="$archive_cmds~\$RANLIB \$lib"
+          postinstall_cmds='$RANLIB $lib'
+        fi
+        ;;
+      aix[[4-9]]*)
+	if test ia64 != "$host_cpu"; then
+	  case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in
+	  yes,aix,yes) ;;		# shared object as lib.so file only
+	  yes,svr4,*) ;;		# shared object as lib.so archive member only
+	  yes,*) enable_static=no ;;	# shared object in lib.a archive as well
+	  esac
+	fi
+        ;;
+    esac
+    AC_MSG_RESULT([$enable_shared])
+
+    AC_MSG_CHECKING([whether to build static libraries])
+    # Make sure either enable_shared or enable_static is yes.
+    test yes = "$enable_shared" || enable_static=yes
+    AC_MSG_RESULT([$enable_static])
+
+    _LT_TAGVAR(GCC, $1)=$G77
+    _LT_TAGVAR(LD, $1)=$LD
+
+    ## CAVEAT EMPTOR:
+    ## There is no encapsulation within the following macros, do not change
+    ## the running order or otherwise move them around unless you know exactly
+    ## what you are doing...
+    _LT_COMPILER_PIC($1)
+    _LT_COMPILER_C_O($1)
+    _LT_COMPILER_FILE_LOCKS($1)
+    _LT_LINKER_SHLIBS($1)
+    _LT_SYS_DYNAMIC_LINKER($1)
+    _LT_LINKER_HARDCODE_LIBPATH($1)
+
+    _LT_CONFIG($1)
+  fi # test -n "$compiler"
+
+  GCC=$lt_save_GCC
+  CC=$lt_save_CC
+  CFLAGS=$lt_save_CFLAGS
+fi # test yes != "$_lt_disable_F77"
+
+AC_LANG_POP
+])# _LT_LANG_F77_CONFIG
+
+
+# _LT_LANG_FC_CONFIG([TAG])
+# -------------------------
+# Ensure that the configuration variables for a Fortran compiler are
+# suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to 'libtool'.
+m4_defun([_LT_LANG_FC_CONFIG],
+[AC_LANG_PUSH(Fortran)
+
+if test -z "$FC" || test no = "$FC"; then
+  _lt_disable_FC=yes
+fi
+
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for fc test sources.
+ac_ext=${ac_fc_srcext-f}
+
+# Object file extension for compiled fc test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the FC compiler isn't working.  Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test yes != "$_lt_disable_FC"; then
+  # Code to be used in simple compile tests
+  lt_simple_compile_test_code="\
+      subroutine t
+      return
+      end
+"
+
+  # Code to be used in simple link tests
+  lt_simple_link_test_code="\
+      program t
+      end
+"
+
+  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+  _LT_TAG_COMPILER
+
+  # save warnings/boilerplate of simple test code
+  _LT_COMPILER_BOILERPLATE
+  _LT_LINKER_BOILERPLATE
+
+  # Allow CC to be a program name with arguments.
+  lt_save_CC=$CC
+  lt_save_GCC=$GCC
+  lt_save_CFLAGS=$CFLAGS
+  CC=${FC-"f95"}
+  CFLAGS=$FCFLAGS
+  compiler=$CC
+  GCC=$ac_cv_fc_compiler_gnu
+
+  _LT_TAGVAR(compiler, $1)=$CC
+  _LT_CC_BASENAME([$compiler])
+
+  if test -n "$compiler"; then
+    AC_MSG_CHECKING([if libtool supports shared libraries])
+    AC_MSG_RESULT([$can_build_shared])
+
+    AC_MSG_CHECKING([whether to build shared libraries])
+    test no = "$can_build_shared" && enable_shared=no
+
+    # On AIX, shared libraries and static libraries use the same namespace, and
+    # are all built from PIC.
+    case $host_os in
+      aix3*)
+        test yes = "$enable_shared" && enable_static=no
+        if test -n "$RANLIB"; then
+          archive_cmds="$archive_cmds~\$RANLIB \$lib"
+          postinstall_cmds='$RANLIB $lib'
+        fi
+        ;;
+      aix[[4-9]]*)
+	if test ia64 != "$host_cpu"; then
+	  case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in
+	  yes,aix,yes) ;;		# shared object as lib.so file only
+	  yes,svr4,*) ;;		# shared object as lib.so archive member only
+	  yes,*) enable_static=no ;;	# shared object in lib.a archive as well
+	  esac
+	fi
+        ;;
+    esac
+    AC_MSG_RESULT([$enable_shared])
+
+    AC_MSG_CHECKING([whether to build static libraries])
+    # Make sure either enable_shared or enable_static is yes.
+    test yes = "$enable_shared" || enable_static=yes
+    AC_MSG_RESULT([$enable_static])
+
+    _LT_TAGVAR(GCC, $1)=$ac_cv_fc_compiler_gnu
+    _LT_TAGVAR(LD, $1)=$LD
+
+    ## CAVEAT EMPTOR:
+    ## There is no encapsulation within the following macros, do not change
+    ## the running order or otherwise move them around unless you know exactly
+    ## what you are doing...
+    _LT_SYS_HIDDEN_LIBDEPS($1)
+    _LT_COMPILER_PIC($1)
+    _LT_COMPILER_C_O($1)
+    _LT_COMPILER_FILE_LOCKS($1)
+    _LT_LINKER_SHLIBS($1)
+    _LT_SYS_DYNAMIC_LINKER($1)
+    _LT_LINKER_HARDCODE_LIBPATH($1)
+
+    _LT_CONFIG($1)
+  fi # test -n "$compiler"
+
+  GCC=$lt_save_GCC
+  CC=$lt_save_CC
+  CFLAGS=$lt_save_CFLAGS
+fi # test yes != "$_lt_disable_FC"
+
+AC_LANG_POP
+])# _LT_LANG_FC_CONFIG
+
+
+# _LT_LANG_GCJ_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for the GNU Java Compiler compiler
+# are suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to 'libtool'.
+m4_defun([_LT_LANG_GCJ_CONFIG],
+[AC_REQUIRE([LT_PROG_GCJ])dnl
+AC_LANG_SAVE
+
+# Source file extension for Java test sources.
+ac_ext=java
+
+# Object file extension for compiled Java test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="class foo {}"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC=$CC
+lt_save_CFLAGS=$CFLAGS
+lt_save_GCC=$GCC
+GCC=yes
+CC=${GCJ-"gcj"}
+CFLAGS=$GCJFLAGS
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_TAGVAR(LD, $1)=$LD
+_LT_CC_BASENAME([$compiler])
+
+# GCJ did not exist at the time GCC didn't implicitly link libc in.
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+
+if test -n "$compiler"; then
+  _LT_COMPILER_NO_RTTI($1)
+  _LT_COMPILER_PIC($1)
+  _LT_COMPILER_C_O($1)
+  _LT_COMPILER_FILE_LOCKS($1)
+  _LT_LINKER_SHLIBS($1)
+  _LT_LINKER_HARDCODE_LIBPATH($1)
+
+  _LT_CONFIG($1)
+fi
+
+AC_LANG_RESTORE
+
+GCC=$lt_save_GCC
+CC=$lt_save_CC
+CFLAGS=$lt_save_CFLAGS
+])# _LT_LANG_GCJ_CONFIG
+
+
+# _LT_LANG_GO_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for the GNU Go compiler
+# are suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to 'libtool'.
+m4_defun([_LT_LANG_GO_CONFIG],
+[AC_REQUIRE([LT_PROG_GO])dnl
+AC_LANG_SAVE
+
+# Source file extension for Go test sources.
+ac_ext=go
+
+# Object file extension for compiled Go test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="package main; func main() { }"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='package main; func main() { }'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC=$CC
+lt_save_CFLAGS=$CFLAGS
+lt_save_GCC=$GCC
+GCC=yes
+CC=${GOC-"gccgo"}
+CFLAGS=$GOFLAGS
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_TAGVAR(LD, $1)=$LD
+_LT_CC_BASENAME([$compiler])
+
+# Go did not exist at the time GCC didn't implicitly link libc in.
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+
+if test -n "$compiler"; then
+  _LT_COMPILER_NO_RTTI($1)
+  _LT_COMPILER_PIC($1)
+  _LT_COMPILER_C_O($1)
+  _LT_COMPILER_FILE_LOCKS($1)
+  _LT_LINKER_SHLIBS($1)
+  _LT_LINKER_HARDCODE_LIBPATH($1)
+
+  _LT_CONFIG($1)
+fi
+
+AC_LANG_RESTORE
+
+GCC=$lt_save_GCC
+CC=$lt_save_CC
+CFLAGS=$lt_save_CFLAGS
+])# _LT_LANG_GO_CONFIG
+
+
+# _LT_LANG_RC_CONFIG([TAG])
+# -------------------------
+# Ensure that the configuration variables for the Windows resource compiler
+# are suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to 'libtool'.
+m4_defun([_LT_LANG_RC_CONFIG],
+[AC_REQUIRE([LT_PROG_RC])dnl
+AC_LANG_SAVE
+
+# Source file extension for RC test sources.
+ac_ext=rc
+
+# Object file extension for compiled RC test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }'
+
+# Code to be used in simple link tests
+lt_simple_link_test_code=$lt_simple_compile_test_code
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC=$CC
+lt_save_CFLAGS=$CFLAGS
+lt_save_GCC=$GCC
+GCC=
+CC=${RC-"windres"}
+CFLAGS=
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_CC_BASENAME([$compiler])
+_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+
+if test -n "$compiler"; then
+  :
+  _LT_CONFIG($1)
+fi
+
+GCC=$lt_save_GCC
+AC_LANG_RESTORE
+CC=$lt_save_CC
+CFLAGS=$lt_save_CFLAGS
+])# _LT_LANG_RC_CONFIG
+
+
+# LT_PROG_GCJ
+# -----------
+AC_DEFUN([LT_PROG_GCJ],
+[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ],
+  [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ],
+    [AC_CHECK_TOOL(GCJ, gcj,)
+      test set = "${GCJFLAGS+set}" || GCJFLAGS="-g -O2"
+      AC_SUBST(GCJFLAGS)])])[]dnl
+])
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_GCJ], [])
+
+
+# LT_PROG_GO
+# ----------
+AC_DEFUN([LT_PROG_GO],
+[AC_CHECK_TOOL(GOC, gccgo,)
+])
+
+
+# LT_PROG_RC
+# ----------
+AC_DEFUN([LT_PROG_RC],
+[AC_CHECK_TOOL(RC, windres,)
+])
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_RC], [])
+
+
+# _LT_DECL_EGREP
+# --------------
+# If we don't have a new enough Autoconf to choose the best grep
+# available, choose the one first in the user's PATH.
+m4_defun([_LT_DECL_EGREP],
+[AC_REQUIRE([AC_PROG_EGREP])dnl
+AC_REQUIRE([AC_PROG_FGREP])dnl
+test -z "$GREP" && GREP=grep
+_LT_DECL([], [GREP], [1], [A grep program that handles long lines])
+_LT_DECL([], [EGREP], [1], [An ERE matcher])
+_LT_DECL([], [FGREP], [1], [A literal string matcher])
+dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too
+AC_SUBST([GREP])
+])
+
+
+# _LT_DECL_OBJDUMP
+# --------------
+# If we don't have a new enough Autoconf to choose the best objdump
+# available, choose the one first in the user's PATH.
+m4_defun([_LT_DECL_OBJDUMP],
+[AC_CHECK_TOOL(OBJDUMP, objdump, false)
+test -z "$OBJDUMP" && OBJDUMP=objdump
+_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper])
+AC_SUBST([OBJDUMP])
+])
+
+# _LT_DECL_DLLTOOL
+# ----------------
+# Ensure DLLTOOL variable is set.
+m4_defun([_LT_DECL_DLLTOOL],
+[AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+_LT_DECL([], [DLLTOOL], [1], [DLL creation program])
+AC_SUBST([DLLTOOL])
+])
+
+# _LT_DECL_SED
+# ------------
+# Check for a fully-functional sed program, that truncates
+# as few characters as possible.  Prefer GNU sed if found.
+m4_defun([_LT_DECL_SED],
+[AC_PROG_SED
+test -z "$SED" && SED=sed
+Xsed="$SED -e 1s/^X//"
+_LT_DECL([], [SED], [1], [A sed program that does not truncate output])
+_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"],
+    [Sed that helps us avoid accidentally triggering echo(1) options like -n])
+])# _LT_DECL_SED
+
+m4_ifndef([AC_PROG_SED], [
+# NOTE: This macro has been submitted for inclusion into   #
+#  GNU Autoconf as AC_PROG_SED.  When it is available in   #
+#  a released version of Autoconf we should remove this    #
+#  macro and use it instead.                               #
+
+m4_defun([AC_PROG_SED],
+[AC_MSG_CHECKING([for a sed that does not truncate output])
+AC_CACHE_VAL(lt_cv_path_SED,
+[# Loop through the user's path and test for sed and gsed.
+# Then use that list of sed's as ones to test for truncation.
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for lt_ac_prog in sed gsed; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then
+        lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext"
+      fi
+    done
+  done
+done
+IFS=$as_save_IFS
+lt_ac_max=0
+lt_ac_count=0
+# Add /usr/xpg4/bin/sed as it is typically found on Solaris
+# along with /bin/sed that truncates output.
+for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
+  test ! -f "$lt_ac_sed" && continue
+  cat /dev/null > conftest.in
+  lt_ac_count=0
+  echo $ECHO_N "0123456789$ECHO_C" >conftest.in
+  # Check for GNU sed and select it if it is found.
+  if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then
+    lt_cv_path_SED=$lt_ac_sed
+    break
+  fi
+  while true; do
+    cat conftest.in conftest.in >conftest.tmp
+    mv conftest.tmp conftest.in
+    cp conftest.in conftest.nl
+    echo >>conftest.nl
+    $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break
+    cmp -s conftest.out conftest.nl || break
+    # 10000 chars as input seems more than enough
+    test 10 -lt "$lt_ac_count" && break
+    lt_ac_count=`expr $lt_ac_count + 1`
+    if test "$lt_ac_count" -gt "$lt_ac_max"; then
+      lt_ac_max=$lt_ac_count
+      lt_cv_path_SED=$lt_ac_sed
+    fi
+  done
+done
+])
+SED=$lt_cv_path_SED
+AC_SUBST([SED])
+AC_MSG_RESULT([$SED])
+])#AC_PROG_SED
+])#m4_ifndef
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_SED], [])
+
+
+# _LT_CHECK_SHELL_FEATURES
+# ------------------------
+# Find out whether the shell is Bourne or XSI compatible,
+# or has some other useful features.
+m4_defun([_LT_CHECK_SHELL_FEATURES],
+[if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  lt_unset=unset
+else
+  lt_unset=false
+fi
+_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl
+
+# test EBCDIC or ASCII
+case `echo X|tr X '\101'` in
+ A) # ASCII based system
+    # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
+  lt_SP2NL='tr \040 \012'
+  lt_NL2SP='tr \015\012 \040\040'
+  ;;
+ *) # EBCDIC based system
+  lt_SP2NL='tr \100 \n'
+  lt_NL2SP='tr \r\n \100\100'
+  ;;
+esac
+_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl
+_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl
+])# _LT_CHECK_SHELL_FEATURES
+
+
+# _LT_PATH_CONVERSION_FUNCTIONS
+# -----------------------------
+# Determine what file name conversion functions should be used by
+# func_to_host_file (and, implicitly, by func_to_host_path).  These are needed
+# for certain cross-compile configurations and native mingw.
+m4_defun([_LT_PATH_CONVERSION_FUNCTIONS],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+AC_MSG_CHECKING([how to convert $build file names to $host format])
+AC_CACHE_VAL(lt_cv_to_host_file_cmd,
+[case $host in
+  *-*-mingw* )
+    case $build in
+      *-*-mingw* ) # actually msys
+        lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32
+        ;;
+      *-*-cygwin* )
+        lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32
+        ;;
+      * ) # otherwise, assume *nix
+        lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32
+        ;;
+    esac
+    ;;
+  *-*-cygwin* )
+    case $build in
+      *-*-mingw* ) # actually msys
+        lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin
+        ;;
+      *-*-cygwin* )
+        lt_cv_to_host_file_cmd=func_convert_file_noop
+        ;;
+      * ) # otherwise, assume *nix
+        lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin
+        ;;
+    esac
+    ;;
+  * ) # unhandled hosts (and "normal" native builds)
+    lt_cv_to_host_file_cmd=func_convert_file_noop
+    ;;
+esac
+])
+to_host_file_cmd=$lt_cv_to_host_file_cmd
+AC_MSG_RESULT([$lt_cv_to_host_file_cmd])
+_LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd],
+         [0], [convert $build file names to $host format])dnl
+
+AC_MSG_CHECKING([how to convert $build file names to toolchain format])
+AC_CACHE_VAL(lt_cv_to_tool_file_cmd,
+[#assume ordinary cross tools, or native build.
+lt_cv_to_tool_file_cmd=func_convert_file_noop
+case $host in
+  *-*-mingw* )
+    case $build in
+      *-*-mingw* ) # actually msys
+        lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32
+        ;;
+    esac
+    ;;
+esac
+])
+to_tool_file_cmd=$lt_cv_to_tool_file_cmd
+AC_MSG_RESULT([$lt_cv_to_tool_file_cmd])
+_LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd],
+         [0], [convert $build files to toolchain format])dnl
+])# _LT_PATH_CONVERSION_FUNCTIONS
+
+# Helper functions for option handling.                    -*- Autoconf -*-
+#
+#   Copyright (C) 2004-2005, 2007-2009, 2011-2015 Free Software
+#   Foundation, Inc.
+#   Written by Gary V. Vaughan, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 8 ltoptions.m4
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
+
+
+# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME)
+# ------------------------------------------
+m4_define([_LT_MANGLE_OPTION],
+[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])])
+
+
+# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME)
+# ---------------------------------------
+# Set option OPTION-NAME for macro MACRO-NAME, and if there is a
+# matching handler defined, dispatch to it.  Other OPTION-NAMEs are
+# saved as a flag.
+m4_define([_LT_SET_OPTION],
+[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl
+m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]),
+        _LT_MANGLE_DEFUN([$1], [$2]),
+    [m4_warning([Unknown $1 option '$2'])])[]dnl
+])
+
+
+# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET])
+# ------------------------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+m4_define([_LT_IF_OPTION],
+[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])])
+
+
+# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET)
+# -------------------------------------------------------
+# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME
+# are set.
+m4_define([_LT_UNLESS_OPTIONS],
+[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
+	    [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option),
+		      [m4_define([$0_found])])])[]dnl
+m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3
+])[]dnl
+])
+
+
+# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST)
+# ----------------------------------------
+# OPTION-LIST is a space-separated list of Libtool options associated
+# with MACRO-NAME.  If any OPTION has a matching handler declared with
+# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about
+# the unknown option and exit.
+m4_defun([_LT_SET_OPTIONS],
+[# Set options
+m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
+    [_LT_SET_OPTION([$1], _LT_Option)])
+
+m4_if([$1],[LT_INIT],[
+  dnl
+  dnl Simply set some default values (i.e off) if boolean options were not
+  dnl specified:
+  _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no
+  ])
+  _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no
+  ])
+  dnl
+  dnl If no reference was made to various pairs of opposing options, then
+  dnl we run the default mode handler for the pair.  For example, if neither
+  dnl 'shared' nor 'disable-shared' was passed, we enable building of shared
+  dnl archives by default:
+  _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED])
+  _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC])
+  _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
+  _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
+		   [_LT_ENABLE_FAST_INSTALL])
+  _LT_UNLESS_OPTIONS([LT_INIT], [aix-soname=aix aix-soname=both aix-soname=svr4],
+		   [_LT_WITH_AIX_SONAME([aix])])
+  ])
+])# _LT_SET_OPTIONS
+
+
+
+# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME)
+# -----------------------------------------
+m4_define([_LT_MANGLE_DEFUN],
+[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])])
+
+
+# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE)
+# -----------------------------------------------
+m4_define([LT_OPTION_DEFINE],
+[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl
+])# LT_OPTION_DEFINE
+
+
+# dlopen
+# ------
+LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes
+])
+
+AU_DEFUN([AC_LIBTOOL_DLOPEN],
+[_LT_SET_OPTION([LT_INIT], [dlopen])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the 'dlopen' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], [])
+
+
+# win32-dll
+# ---------
+# Declare package support for building win32 dll's.
+LT_OPTION_DEFINE([LT_INIT], [win32-dll],
+[enable_win32_dll=yes
+
+case $host in
+*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
+  AC_CHECK_TOOL(AS, as, false)
+  AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+  AC_CHECK_TOOL(OBJDUMP, objdump, false)
+  ;;
+esac
+
+test -z "$AS" && AS=as
+_LT_DECL([], [AS],      [1], [Assembler program])dnl
+
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl
+
+test -z "$OBJDUMP" && OBJDUMP=objdump
+_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl
+])# win32-dll
+
+AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+_LT_SET_OPTION([LT_INIT], [win32-dll])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the 'win32-dll' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [])
+
+
+# _LT_ENABLE_SHARED([DEFAULT])
+# ----------------------------
+# implement the --enable-shared flag, and supports the 'shared' and
+# 'disable-shared' LT_INIT options.
+# DEFAULT is either 'yes' or 'no'.  If omitted, it defaults to 'yes'.
+m4_define([_LT_ENABLE_SHARED],
+[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([shared],
+    [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
+	[build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])],
+    [p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_shared=yes ;;
+    no) enable_shared=no ;;
+    *)
+      enable_shared=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
+      for pkg in $enableval; do
+	IFS=$lt_save_ifs
+	if test "X$pkg" = "X$p"; then
+	  enable_shared=yes
+	fi
+      done
+      IFS=$lt_save_ifs
+      ;;
+    esac],
+    [enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
+
+    _LT_DECL([build_libtool_libs], [enable_shared], [0],
+	[Whether or not to build shared libraries])
+])# _LT_ENABLE_SHARED
+
+LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])])
+
+# Old names:
+AC_DEFUN([AC_ENABLE_SHARED],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared])
+])
+
+AC_DEFUN([AC_DISABLE_SHARED],
+[_LT_SET_OPTION([LT_INIT], [disable-shared])
+])
+
+AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
+AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_ENABLE_SHARED], [])
+dnl AC_DEFUN([AM_DISABLE_SHARED], [])
+
+
+
+# _LT_ENABLE_STATIC([DEFAULT])
+# ----------------------------
+# implement the --enable-static flag, and support the 'static' and
+# 'disable-static' LT_INIT options.
+# DEFAULT is either 'yes' or 'no'.  If omitted, it defaults to 'yes'.
+m4_define([_LT_ENABLE_STATIC],
+[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([static],
+    [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@],
+	[build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])],
+    [p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_static=yes ;;
+    no) enable_static=no ;;
+    *)
+     enable_static=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
+      for pkg in $enableval; do
+	IFS=$lt_save_ifs
+	if test "X$pkg" = "X$p"; then
+	  enable_static=yes
+	fi
+      done
+      IFS=$lt_save_ifs
+      ;;
+    esac],
+    [enable_static=]_LT_ENABLE_STATIC_DEFAULT)
+
+    _LT_DECL([build_old_libs], [enable_static], [0],
+	[Whether or not to build static libraries])
+])# _LT_ENABLE_STATIC
+
+LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])])
+
+# Old names:
+AC_DEFUN([AC_ENABLE_STATIC],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static])
+])
+
+AC_DEFUN([AC_DISABLE_STATIC],
+[_LT_SET_OPTION([LT_INIT], [disable-static])
+])
+
+AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
+AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_ENABLE_STATIC], [])
+dnl AC_DEFUN([AM_DISABLE_STATIC], [])
+
+
+
+# _LT_ENABLE_FAST_INSTALL([DEFAULT])
+# ----------------------------------
+# implement the --enable-fast-install flag, and support the 'fast-install'
+# and 'disable-fast-install' LT_INIT options.
+# DEFAULT is either 'yes' or 'no'.  If omitted, it defaults to 'yes'.
+m4_define([_LT_ENABLE_FAST_INSTALL],
+[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([fast-install],
+    [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
+    [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
+    [p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_fast_install=yes ;;
+    no) enable_fast_install=no ;;
+    *)
+      enable_fast_install=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
+      for pkg in $enableval; do
+	IFS=$lt_save_ifs
+	if test "X$pkg" = "X$p"; then
+	  enable_fast_install=yes
+	fi
+      done
+      IFS=$lt_save_ifs
+      ;;
+    esac],
+    [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
+
+_LT_DECL([fast_install], [enable_fast_install], [0],
+	 [Whether or not to optimize for fast installation])dnl
+])# _LT_ENABLE_FAST_INSTALL
+
+LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])])
+
+# Old names:
+AU_DEFUN([AC_ENABLE_FAST_INSTALL],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you put
+the 'fast-install' option into LT_INIT's first parameter.])
+])
+
+AU_DEFUN([AC_DISABLE_FAST_INSTALL],
+[_LT_SET_OPTION([LT_INIT], [disable-fast-install])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you put
+the 'disable-fast-install' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
+dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
+
+
+# _LT_WITH_AIX_SONAME([DEFAULT])
+# ----------------------------------
+# implement the --with-aix-soname flag, and support the `aix-soname=aix'
+# and `aix-soname=both' and `aix-soname=svr4' LT_INIT options. DEFAULT
+# is either `aix', `both' or `svr4'.  If omitted, it defaults to `aix'.
+m4_define([_LT_WITH_AIX_SONAME],
+[m4_define([_LT_WITH_AIX_SONAME_DEFAULT], [m4_if($1, svr4, svr4, m4_if($1, both, both, aix))])dnl
+shared_archive_member_spec=
+case $host,$enable_shared in
+power*-*-aix[[5-9]]*,yes)
+  AC_MSG_CHECKING([which variant of shared library versioning to provide])
+  AC_ARG_WITH([aix-soname],
+    [AS_HELP_STRING([--with-aix-soname=aix|svr4|both],
+      [shared library versioning (aka "SONAME") variant to provide on AIX, @<:@default=]_LT_WITH_AIX_SONAME_DEFAULT[@:>@.])],
+    [case $withval in
+    aix|svr4|both)
+      ;;
+    *)
+      AC_MSG_ERROR([Unknown argument to --with-aix-soname])
+      ;;
+    esac
+    lt_cv_with_aix_soname=$with_aix_soname],
+    [AC_CACHE_VAL([lt_cv_with_aix_soname],
+      [lt_cv_with_aix_soname=]_LT_WITH_AIX_SONAME_DEFAULT)
+    with_aix_soname=$lt_cv_with_aix_soname])
+  AC_MSG_RESULT([$with_aix_soname])
+  if test aix != "$with_aix_soname"; then
+    # For the AIX way of multilib, we name the shared archive member
+    # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o',
+    # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File.
+    # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag,
+    # the AIX toolchain works better with OBJECT_MODE set (default 32).
+    if test 64 = "${OBJECT_MODE-32}"; then
+      shared_archive_member_spec=shr_64
+    else
+      shared_archive_member_spec=shr
+    fi
+  fi
+  ;;
+*)
+  with_aix_soname=aix
+  ;;
+esac
+
+_LT_DECL([], [shared_archive_member_spec], [0],
+    [Shared archive member basename, for filename based shared library versioning on AIX])dnl
+])# _LT_WITH_AIX_SONAME
+
+LT_OPTION_DEFINE([LT_INIT], [aix-soname=aix], [_LT_WITH_AIX_SONAME([aix])])
+LT_OPTION_DEFINE([LT_INIT], [aix-soname=both], [_LT_WITH_AIX_SONAME([both])])
+LT_OPTION_DEFINE([LT_INIT], [aix-soname=svr4], [_LT_WITH_AIX_SONAME([svr4])])
+
+
+# _LT_WITH_PIC([MODE])
+# --------------------
+# implement the --with-pic flag, and support the 'pic-only' and 'no-pic'
+# LT_INIT options.
+# MODE is either 'yes' or 'no'.  If omitted, it defaults to 'both'.
+m4_define([_LT_WITH_PIC],
+[AC_ARG_WITH([pic],
+    [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@],
+	[try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
+    [lt_p=${PACKAGE-default}
+    case $withval in
+    yes|no) pic_mode=$withval ;;
+    *)
+      pic_mode=default
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
+      for lt_pkg in $withval; do
+	IFS=$lt_save_ifs
+	if test "X$lt_pkg" = "X$lt_p"; then
+	  pic_mode=yes
+	fi
+      done
+      IFS=$lt_save_ifs
+      ;;
+    esac],
+    [pic_mode=m4_default([$1], [default])])
+
+_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
+])# _LT_WITH_PIC
+
+LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])])
+LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])])
+
+# Old name:
+AU_DEFUN([AC_LIBTOOL_PICMODE],
+[_LT_SET_OPTION([LT_INIT], [pic-only])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the 'pic-only' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_PICMODE], [])
+
+
+m4_define([_LTDL_MODE], [])
+LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive],
+		 [m4_define([_LTDL_MODE], [nonrecursive])])
+LT_OPTION_DEFINE([LTDL_INIT], [recursive],
+		 [m4_define([_LTDL_MODE], [recursive])])
+LT_OPTION_DEFINE([LTDL_INIT], [subproject],
+		 [m4_define([_LTDL_MODE], [subproject])])
+
+m4_define([_LTDL_TYPE], [])
+LT_OPTION_DEFINE([LTDL_INIT], [installable],
+		 [m4_define([_LTDL_TYPE], [installable])])
+LT_OPTION_DEFINE([LTDL_INIT], [convenience],
+		 [m4_define([_LTDL_TYPE], [convenience])])
+
+# ltsugar.m4 -- libtool m4 base layer.                         -*-Autoconf-*-
+#
+# Copyright (C) 2004-2005, 2007-2008, 2011-2015 Free Software
+# Foundation, Inc.
+# Written by Gary V. Vaughan, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 6 ltsugar.m4
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])])
+
+
+# lt_join(SEP, ARG1, [ARG2...])
+# -----------------------------
+# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their
+# associated separator.
+# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier
+# versions in m4sugar had bugs.
+m4_define([lt_join],
+[m4_if([$#], [1], [],
+       [$#], [2], [[$2]],
+       [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])])
+m4_define([_lt_join],
+[m4_if([$#$2], [2], [],
+       [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])])
+
+
+# lt_car(LIST)
+# lt_cdr(LIST)
+# ------------
+# Manipulate m4 lists.
+# These macros are necessary as long as will still need to support
+# Autoconf-2.59, which quotes differently.
+m4_define([lt_car], [[$1]])
+m4_define([lt_cdr],
+[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])],
+       [$#], 1, [],
+       [m4_dquote(m4_shift($@))])])
+m4_define([lt_unquote], $1)
+
+
+# lt_append(MACRO-NAME, STRING, [SEPARATOR])
+# ------------------------------------------
+# Redefine MACRO-NAME to hold its former content plus 'SEPARATOR''STRING'.
+# Note that neither SEPARATOR nor STRING are expanded; they are appended
+# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked).
+# No SEPARATOR is output if MACRO-NAME was previously undefined (different
+# than defined and empty).
+#
+# This macro is needed until we can rely on Autoconf 2.62, since earlier
+# versions of m4sugar mistakenly expanded SEPARATOR but not STRING.
+m4_define([lt_append],
+[m4_define([$1],
+	   m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])])
+
+
+
+# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...])
+# ----------------------------------------------------------
+# Produce a SEP delimited list of all paired combinations of elements of
+# PREFIX-LIST with SUFFIX1 through SUFFIXn.  Each element of the list
+# has the form PREFIXmINFIXSUFFIXn.
+# Needed until we can rely on m4_combine added in Autoconf 2.62.
+m4_define([lt_combine],
+[m4_if(m4_eval([$# > 3]), [1],
+       [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl
+[[m4_foreach([_Lt_prefix], [$2],
+	     [m4_foreach([_Lt_suffix],
+		]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[,
+	[_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])])
+
+
+# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ])
+# -----------------------------------------------------------------------
+# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited
+# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ.
+m4_define([lt_if_append_uniq],
+[m4_ifdef([$1],
+	  [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1],
+		 [lt_append([$1], [$2], [$3])$4],
+		 [$5])],
+	  [lt_append([$1], [$2], [$3])$4])])
+
+
+# lt_dict_add(DICT, KEY, VALUE)
+# -----------------------------
+m4_define([lt_dict_add],
+[m4_define([$1($2)], [$3])])
+
+
+# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE)
+# --------------------------------------------
+m4_define([lt_dict_add_subkey],
+[m4_define([$1($2:$3)], [$4])])
+
+
+# lt_dict_fetch(DICT, KEY, [SUBKEY])
+# ----------------------------------
+m4_define([lt_dict_fetch],
+[m4_ifval([$3],
+	m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]),
+    m4_ifdef([$1($2)], [m4_defn([$1($2)])]))])
+
+
+# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE])
+# -----------------------------------------------------------------
+m4_define([lt_if_dict_fetch],
+[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4],
+	[$5],
+    [$6])])
+
+
+# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...])
+# --------------------------------------------------------------
+m4_define([lt_dict_filter],
+[m4_if([$5], [], [],
+  [lt_join(m4_quote(m4_default([$4], [[, ]])),
+           lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]),
+		      [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl
+])
+
+# ltversion.m4 -- version numbers			-*- Autoconf -*-
+#
+#   Copyright (C) 2004, 2011-2015 Free Software Foundation, Inc.
+#   Written by Scott James Remnant, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# @configure_input@
+
+# serial 4179 ltversion.m4
+# This file is part of GNU Libtool
+
+m4_define([LT_PACKAGE_VERSION], [2.4.6])
+m4_define([LT_PACKAGE_REVISION], [2.4.6])
+
+AC_DEFUN([LTVERSION_VERSION],
+[macro_version='2.4.6'
+macro_revision='2.4.6'
+_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
+_LT_DECL(, macro_revision, 0)
+])
+
+# lt~obsolete.m4 -- aclocal satisfying obsolete definitions.    -*-Autoconf-*-
+#
+#   Copyright (C) 2004-2005, 2007, 2009, 2011-2015 Free Software
+#   Foundation, Inc.
+#   Written by Scott James Remnant, 2004.
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 5 lt~obsolete.m4
+
+# These exist entirely to fool aclocal when bootstrapping libtool.
+#
+# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN),
+# which have later been changed to m4_define as they aren't part of the
+# exported API, or moved to Autoconf or Automake where they belong.
+#
+# The trouble is, aclocal is a bit thick.  It'll see the old AC_DEFUN
+# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
+# using a macro with the same name in our local m4/libtool.m4 it'll
+# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
+# and doesn't know about Autoconf macros at all.)
+#
+# So we provide this file, which has a silly filename so it's always
+# included after everything else.  This provides aclocal with the
+# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
+# because those macros already exist, or will be overwritten later.
+# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6.
+#
+# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
+# Yes, that means every name once taken will need to remain here until
+# we give up compatibility with versions before 1.7, at which point
+# we need to keep only those names which we still refer to.
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
+
+m4_ifndef([AC_LIBTOOL_LINKER_OPTION],	[AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
+m4_ifndef([AC_PROG_EGREP],		[AC_DEFUN([AC_PROG_EGREP])])
+m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH],	[AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
+m4_ifndef([_LT_AC_SHELL_INIT],		[AC_DEFUN([_LT_AC_SHELL_INIT])])
+m4_ifndef([_LT_AC_SYS_LIBPATH_AIX],	[AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
+m4_ifndef([_LT_PROG_LTMAIN],		[AC_DEFUN([_LT_PROG_LTMAIN])])
+m4_ifndef([_LT_AC_TAGVAR],		[AC_DEFUN([_LT_AC_TAGVAR])])
+m4_ifndef([AC_LTDL_ENABLE_INSTALL],	[AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
+m4_ifndef([AC_LTDL_PREOPEN],		[AC_DEFUN([AC_LTDL_PREOPEN])])
+m4_ifndef([_LT_AC_SYS_COMPILER],	[AC_DEFUN([_LT_AC_SYS_COMPILER])])
+m4_ifndef([_LT_AC_LOCK],		[AC_DEFUN([_LT_AC_LOCK])])
+m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE],	[AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
+m4_ifndef([_LT_AC_TRY_DLOPEN_SELF],	[AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
+m4_ifndef([AC_LIBTOOL_PROG_CC_C_O],	[AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
+m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
+m4_ifndef([AC_LIBTOOL_OBJDIR],		[AC_DEFUN([AC_LIBTOOL_OBJDIR])])
+m4_ifndef([AC_LTDL_OBJDIR],		[AC_DEFUN([AC_LTDL_OBJDIR])])
+m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
+m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP],	[AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
+m4_ifndef([AC_PATH_MAGIC],		[AC_DEFUN([AC_PATH_MAGIC])])
+m4_ifndef([AC_PROG_LD_GNU],		[AC_DEFUN([AC_PROG_LD_GNU])])
+m4_ifndef([AC_PROG_LD_RELOAD_FLAG],	[AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
+m4_ifndef([AC_DEPLIBS_CHECK_METHOD],	[AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
+m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
+m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
+m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
+m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS],	[AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
+m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP],	[AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
+m4_ifndef([LT_AC_PROG_EGREP],		[AC_DEFUN([LT_AC_PROG_EGREP])])
+m4_ifndef([LT_AC_PROG_SED],		[AC_DEFUN([LT_AC_PROG_SED])])
+m4_ifndef([_LT_CC_BASENAME],		[AC_DEFUN([_LT_CC_BASENAME])])
+m4_ifndef([_LT_COMPILER_BOILERPLATE],	[AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
+m4_ifndef([_LT_LINKER_BOILERPLATE],	[AC_DEFUN([_LT_LINKER_BOILERPLATE])])
+m4_ifndef([_AC_PROG_LIBTOOL],		[AC_DEFUN([_AC_PROG_LIBTOOL])])
+m4_ifndef([AC_LIBTOOL_SETUP],		[AC_DEFUN([AC_LIBTOOL_SETUP])])
+m4_ifndef([_LT_AC_CHECK_DLFCN],		[AC_DEFUN([_LT_AC_CHECK_DLFCN])])
+m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER],	[AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
+m4_ifndef([_LT_AC_TAGCONFIG],		[AC_DEFUN([_LT_AC_TAGCONFIG])])
+m4_ifndef([AC_DISABLE_FAST_INSTALL],	[AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
+m4_ifndef([_LT_AC_LANG_CXX],		[AC_DEFUN([_LT_AC_LANG_CXX])])
+m4_ifndef([_LT_AC_LANG_F77],		[AC_DEFUN([_LT_AC_LANG_F77])])
+m4_ifndef([_LT_AC_LANG_GCJ],		[AC_DEFUN([_LT_AC_LANG_GCJ])])
+m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG],	[AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
+m4_ifndef([_LT_AC_LANG_C_CONFIG],	[AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG],	[AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
+m4_ifndef([_LT_AC_LANG_CXX_CONFIG],	[AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG],	[AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
+m4_ifndef([_LT_AC_LANG_F77_CONFIG],	[AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG],	[AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
+m4_ifndef([_LT_AC_LANG_GCJ_CONFIG],	[AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG],	[AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
+m4_ifndef([_LT_AC_LANG_RC_CONFIG],	[AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
+m4_ifndef([AC_LIBTOOL_CONFIG],		[AC_DEFUN([AC_LIBTOOL_CONFIG])])
+m4_ifndef([_LT_AC_FILE_LTDLL_C],	[AC_DEFUN([_LT_AC_FILE_LTDLL_C])])
+m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS],	[AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])])
+m4_ifndef([_LT_AC_PROG_CXXCPP],		[AC_DEFUN([_LT_AC_PROG_CXXCPP])])
+m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS],	[AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])])
+m4_ifndef([_LT_PROG_ECHO_BACKSLASH],	[AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])])
+m4_ifndef([_LT_PROG_F77],		[AC_DEFUN([_LT_PROG_F77])])
+m4_ifndef([_LT_PROG_FC],		[AC_DEFUN([_LT_PROG_FC])])
+m4_ifndef([_LT_PROG_CXX],		[AC_DEFUN([_LT_PROG_CXX])])
+
+# Copyright (C) 2002-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_AUTOMAKE_VERSION(VERSION)
+# ----------------------------
+# Automake X.Y traces this macro to ensure aclocal.m4 has been
+# generated from the m4 files accompanying Automake X.Y.
+# (This private macro should not be called outside this file.)
+AC_DEFUN([AM_AUTOMAKE_VERSION],
+[am__api_version='1.15'
+dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
+dnl require some minimum version.  Point them to the right macro.
+m4_if([$1], [1.15], [],
+      [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
+])
+
+# _AM_AUTOCONF_VERSION(VERSION)
+# -----------------------------
+# aclocal traces this macro to find the Autoconf version.
+# This is a private macro too.  Using m4_define simplifies
+# the logic in aclocal, which can simply ignore this definition.
+m4_define([_AM_AUTOCONF_VERSION], [])
+
+# AM_SET_CURRENT_AUTOMAKE_VERSION
+# -------------------------------
+# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
+# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
+AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
+[AM_AUTOMAKE_VERSION([1.15])dnl
+m4_ifndef([AC_AUTOCONF_VERSION],
+  [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
+
+# AM_AUX_DIR_EXPAND                                         -*- Autoconf -*-
+
+# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
+# $ac_aux_dir to '$srcdir/foo'.  In other projects, it is set to
+# '$srcdir', '$srcdir/..', or '$srcdir/../..'.
+#
+# Of course, Automake must honor this variable whenever it calls a
+# tool from the auxiliary directory.  The problem is that $srcdir (and
+# therefore $ac_aux_dir as well) can be either absolute or relative,
+# depending on how configure is run.  This is pretty annoying, since
+# it makes $ac_aux_dir quite unusable in subdirectories: in the top
+# source directory, any form will work fine, but in subdirectories a
+# relative path needs to be adjusted first.
+#
+# $ac_aux_dir/missing
+#    fails when called from a subdirectory if $ac_aux_dir is relative
+# $top_srcdir/$ac_aux_dir/missing
+#    fails if $ac_aux_dir is absolute,
+#    fails when called from a subdirectory in a VPATH build with
+#          a relative $ac_aux_dir
+#
+# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
+# are both prefixed by $srcdir.  In an in-source build this is usually
+# harmless because $srcdir is '.', but things will broke when you
+# start a VPATH build or use an absolute $srcdir.
+#
+# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
+# iff we strip the leading $srcdir from $ac_aux_dir.  That would be:
+#   am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
+# and then we would define $MISSING as
+#   MISSING="\${SHELL} $am_aux_dir/missing"
+# This will work as long as MISSING is not called from configure, because
+# unfortunately $(top_srcdir) has no meaning in configure.
+# However there are other variables, like CC, which are often used in
+# configure, and could therefore not use this "fixed" $ac_aux_dir.
+#
+# Another solution, used here, is to always expand $ac_aux_dir to an
+# absolute PATH.  The drawback is that using absolute paths prevent a
+# configured tree to be moved without reconfiguration.
+
+AC_DEFUN([AM_AUX_DIR_EXPAND],
+[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
+# Expand $ac_aux_dir to an absolute path.
+am_aux_dir=`cd "$ac_aux_dir" && pwd`
+])
+
+# AM_CONDITIONAL                                            -*- Autoconf -*-
+
+# Copyright (C) 1997-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_CONDITIONAL(NAME, SHELL-CONDITION)
+# -------------------------------------
+# Define a conditional.
+AC_DEFUN([AM_CONDITIONAL],
+[AC_PREREQ([2.52])dnl
+ m4_if([$1], [TRUE],  [AC_FATAL([$0: invalid condition: $1])],
+       [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
+AC_SUBST([$1_TRUE])dnl
+AC_SUBST([$1_FALSE])dnl
+_AM_SUBST_NOTMAKE([$1_TRUE])dnl
+_AM_SUBST_NOTMAKE([$1_FALSE])dnl
+m4_define([_AM_COND_VALUE_$1], [$2])dnl
+if $2; then
+  $1_TRUE=
+  $1_FALSE='#'
+else
+  $1_TRUE='#'
+  $1_FALSE=
+fi
+AC_CONFIG_COMMANDS_PRE(
+[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
+  AC_MSG_ERROR([[conditional "$1" was never defined.
+Usually this means the macro was only invoked conditionally.]])
+fi])])
+
+# Do all the work for Automake.                             -*- Autoconf -*-
+
+# Copyright (C) 1996-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This macro actually does too much.  Some checks are only needed if
+# your package does certain things.  But this isn't really a big deal.
+
+dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O.
+m4_define([AC_PROG_CC],
+m4_defn([AC_PROG_CC])
+[_AM_PROG_CC_C_O
+])
+
+# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
+# AM_INIT_AUTOMAKE([OPTIONS])
+# -----------------------------------------------
+# The call with PACKAGE and VERSION arguments is the old style
+# call (pre autoconf-2.50), which is being phased out.  PACKAGE
+# and VERSION should now be passed to AC_INIT and removed from
+# the call to AM_INIT_AUTOMAKE.
+# We support both call styles for the transition.  After
+# the next Automake release, Autoconf can make the AC_INIT
+# arguments mandatory, and then we can depend on a new Autoconf
+# release and drop the old call support.
+AC_DEFUN([AM_INIT_AUTOMAKE],
+[AC_PREREQ([2.65])dnl
+dnl Autoconf wants to disallow AM_ names.  We explicitly allow
+dnl the ones we care about.
+m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
+AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
+AC_REQUIRE([AC_PROG_INSTALL])dnl
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+  # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+  # is not polluted with repeated "-I."
+  AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl
+  # test to see if srcdir already configured
+  if test -f $srcdir/config.status; then
+    AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+  fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+  if (cygpath --version) >/dev/null 2>/dev/null; then
+    CYGPATH_W='cygpath -w'
+  else
+    CYGPATH_W=echo
+  fi
+fi
+AC_SUBST([CYGPATH_W])
+
+# Define the identity of the package.
+dnl Distinguish between old-style and new-style calls.
+m4_ifval([$2],
+[AC_DIAGNOSE([obsolete],
+             [$0: two- and three-arguments forms are deprecated.])
+m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
+ AC_SUBST([PACKAGE], [$1])dnl
+ AC_SUBST([VERSION], [$2])],
+[_AM_SET_OPTIONS([$1])dnl
+dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT.
+m4_if(
+  m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]),
+  [ok:ok],,
+  [m4_fatal([AC_INIT should be called with package and version arguments])])dnl
+ AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
+ AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
+
+_AM_IF_OPTION([no-define],,
+[AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package])
+ AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl
+
+# Some tools Automake needs.
+AC_REQUIRE([AM_SANITY_CHECK])dnl
+AC_REQUIRE([AC_ARG_PROGRAM])dnl
+AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}])
+AM_MISSING_PROG([AUTOCONF], [autoconf])
+AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}])
+AM_MISSING_PROG([AUTOHEADER], [autoheader])
+AM_MISSING_PROG([MAKEINFO], [makeinfo])
+AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl
+AC_REQUIRE([AC_PROG_MKDIR_P])dnl
+# For better backward compatibility.  To be removed once Automake 1.9.x
+# dies out for good.  For more background, see:
+# <http://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
+# <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
+AC_SUBST([mkdir_p], ['$(MKDIR_P)'])
+# We need awk for the "check" target (and possibly the TAP driver).  The
+# system "awk" is bad on some platforms.
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([AC_PROG_MAKE_SET])dnl
+AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
+	      [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
+			     [_AM_PROG_TAR([v7])])])
+_AM_IF_OPTION([no-dependencies],,
+[AC_PROVIDE_IFELSE([AC_PROG_CC],
+		  [_AM_DEPENDENCIES([CC])],
+		  [m4_define([AC_PROG_CC],
+			     m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_CXX],
+		  [_AM_DEPENDENCIES([CXX])],
+		  [m4_define([AC_PROG_CXX],
+			     m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJC],
+		  [_AM_DEPENDENCIES([OBJC])],
+		  [m4_define([AC_PROG_OBJC],
+			     m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJCXX],
+		  [_AM_DEPENDENCIES([OBJCXX])],
+		  [m4_define([AC_PROG_OBJCXX],
+			     m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl
+])
+AC_REQUIRE([AM_SILENT_RULES])dnl
+dnl The testsuite driver may need to know about EXEEXT, so add the
+dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen.  This
+dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below.
+AC_CONFIG_COMMANDS_PRE(dnl
+[m4_provide_if([_AM_COMPILER_EXEEXT],
+  [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl
+
+# POSIX will say in a future version that running "rm -f" with no argument
+# is OK; and we want to be able to make that assumption in our Makefile
+# recipes.  So use an aggressive probe to check that the usage we want is
+# actually supported "in the wild" to an acceptable degree.
+# See automake bug#10828.
+# To make any issue more visible, cause the running configure to be aborted
+# by default if the 'rm' program in use doesn't match our expectations; the
+# user can still override this though.
+if rm -f && rm -fr && rm -rf; then : OK; else
+  cat >&2 <<'END'
+Oops!
+
+Your 'rm' program seems unable to run without file operands specified
+on the command line, even when the '-f' option is present.  This is contrary
+to the behaviour of most rm programs out there, and not conforming with
+the upcoming POSIX standard: <http://austingroupbugs.net/view.php?id=542>
+
+Please tell bug-automake@gnu.org about your system, including the value
+of your $PATH and any error possibly output before this message.  This
+can help us improve future automake versions.
+
+END
+  if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then
+    echo 'Configuration will proceed anyway, since you have set the' >&2
+    echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2
+    echo >&2
+  else
+    cat >&2 <<'END'
+Aborting the configuration process, to ensure you take notice of the issue.
+
+You can download and install GNU coreutils to get an 'rm' implementation
+that behaves properly: <http://www.gnu.org/software/coreutils/>.
+
+If you want to complete the configuration process using your problematic
+'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM
+to "yes", and re-run configure.
+
+END
+    AC_MSG_ERROR([Your 'rm' program is bad, sorry.])
+  fi
+fi
+dnl The trailing newline in this macro's definition is deliberate, for
+dnl backward compatibility and to allow trailing 'dnl'-style comments
+dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841.
+])
+
+dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion.  Do not
+dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further
+dnl mangled by Autoconf and run in a shell conditional statement.
+m4_define([_AC_COMPILER_EXEEXT],
+m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])])
+
+# When config.status generates a header, we must update the stamp-h file.
+# This file resides in the same directory as the config header
+# that is generated.  The stamp files are numbered to have different names.
+
+# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
+# loop where config.status creates the headers, so we can generate
+# our stamp files there.
+AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
+[# Compute $1's index in $config_headers.
+_am_arg=$1
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+  case $_am_header in
+    $_am_arg | $_am_arg:* )
+      break ;;
+    * )
+      _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+  esac
+done
+echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
+
+# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_SH
+# ------------------
+# Define $install_sh.
+AC_DEFUN([AM_PROG_INSTALL_SH],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+if test x"${install_sh+set}" != xset; then
+  case $am_aux_dir in
+  *\ * | *\	*)
+    install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+  *)
+    install_sh="\${SHELL} $am_aux_dir/install-sh"
+  esac
+fi
+AC_SUBST([install_sh])])
+
+# Copyright (C) 2003-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# Check whether the underlying file-system supports filenames
+# with a leading dot.  For instance MS-DOS doesn't.
+AC_DEFUN([AM_SET_LEADING_DOT],
+[rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+  am__leading_dot=.
+else
+  am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+AC_SUBST([am__leading_dot])])
+
+# Copyright (C) 1998-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_LEX
+# -----------
+# Autoconf leaves LEX=: if lex or flex can't be found.  Change that to a
+# "missing" invocation, for better error output.
+AC_DEFUN([AM_PROG_LEX],
+[AC_PREREQ([2.50])dnl
+AC_REQUIRE([AM_MISSING_HAS_RUN])dnl
+AC_REQUIRE([AC_PROG_LEX])dnl
+if test "$LEX" = :; then
+  LEX=${am_missing_run}flex
+fi])
+
+# Add --enable-maintainer-mode option to configure.         -*- Autoconf -*-
+# From Jim Meyering
+
+# Copyright (C) 1996-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_MAINTAINER_MODE([DEFAULT-MODE])
+# ----------------------------------
+# Control maintainer-specific portions of Makefiles.
+# Default is to disable them, unless 'enable' is passed literally.
+# For symmetry, 'disable' may be passed as well.  Anyway, the user
+# can override the default with the --enable/--disable switch.
+AC_DEFUN([AM_MAINTAINER_MODE],
+[m4_case(m4_default([$1], [disable]),
+       [enable], [m4_define([am_maintainer_other], [disable])],
+       [disable], [m4_define([am_maintainer_other], [enable])],
+       [m4_define([am_maintainer_other], [enable])
+        m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])])
+AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
+  dnl maintainer-mode's default is 'disable' unless 'enable' is passed
+  AC_ARG_ENABLE([maintainer-mode],
+    [AS_HELP_STRING([--]am_maintainer_other[-maintainer-mode],
+      am_maintainer_other[ make rules and dependencies not useful
+      (and sometimes confusing) to the casual installer])],
+    [USE_MAINTAINER_MODE=$enableval],
+    [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes]))
+  AC_MSG_RESULT([$USE_MAINTAINER_MODE])
+  AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes])
+  MAINT=$MAINTAINER_MODE_TRUE
+  AC_SUBST([MAINT])dnl
+]
+)
+
+# Fake the existence of programs that GNU maintainers use.  -*- Autoconf -*-
+
+# Copyright (C) 1997-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_MISSING_PROG(NAME, PROGRAM)
+# ------------------------------
+AC_DEFUN([AM_MISSING_PROG],
+[AC_REQUIRE([AM_MISSING_HAS_RUN])
+$1=${$1-"${am_missing_run}$2"}
+AC_SUBST($1)])
+
+# AM_MISSING_HAS_RUN
+# ------------------
+# Define MISSING if not defined so far and test if it is modern enough.
+# If it is, set am_missing_run to use it, otherwise, to nothing.
+AC_DEFUN([AM_MISSING_HAS_RUN],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([missing])dnl
+if test x"${MISSING+set}" != xset; then
+  case $am_aux_dir in
+  *\ * | *\	*)
+    MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
+  *)
+    MISSING="\${SHELL} $am_aux_dir/missing" ;;
+  esac
+fi
+# Use eval to expand $SHELL
+if eval "$MISSING --is-lightweight"; then
+  am_missing_run="$MISSING "
+else
+  am_missing_run=
+  AC_MSG_WARN(['missing' script is too old or missing])
+fi
+])
+
+# Helper functions for option handling.                     -*- Autoconf -*-
+
+# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_MANGLE_OPTION(NAME)
+# -----------------------
+AC_DEFUN([_AM_MANGLE_OPTION],
+[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
+
+# _AM_SET_OPTION(NAME)
+# --------------------
+# Set option NAME.  Presently that only means defining a flag for this option.
+AC_DEFUN([_AM_SET_OPTION],
+[m4_define(_AM_MANGLE_OPTION([$1]), [1])])
+
+# _AM_SET_OPTIONS(OPTIONS)
+# ------------------------
+# OPTIONS is a space-separated list of Automake options.
+AC_DEFUN([_AM_SET_OPTIONS],
+[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
+
+# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
+# -------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+AC_DEFUN([_AM_IF_OPTION],
+[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
+
+# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_PROG_CC_C_O
+# ---------------
+# Like AC_PROG_CC_C_O, but changed for automake.  We rewrite AC_PROG_CC
+# to automatically call this.
+AC_DEFUN([_AM_PROG_CC_C_O],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([compile])dnl
+AC_LANG_PUSH([C])dnl
+AC_CACHE_CHECK(
+  [whether $CC understands -c and -o together],
+  [am_cv_prog_cc_c_o],
+  [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])])
+  # Make sure it works both with $CC and with simple cc.
+  # Following AC_PROG_CC_C_O, we do the test twice because some
+  # compilers refuse to overwrite an existing .o file with -o,
+  # though they will create one.
+  am_cv_prog_cc_c_o=yes
+  for am_i in 1 2; do
+    if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \
+         && test -f conftest2.$ac_objext; then
+      : OK
+    else
+      am_cv_prog_cc_c_o=no
+      break
+    fi
+  done
+  rm -f core conftest*
+  unset am_i])
+if test "$am_cv_prog_cc_c_o" != yes; then
+   # Losing compiler, so override with the script.
+   # FIXME: It is wrong to rewrite CC.
+   # But if we don't then we get into trouble of one sort or another.
+   # A longer-term fix would be to have automake use am__CC in this case,
+   # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
+   CC="$am_aux_dir/compile $CC"
+fi
+AC_LANG_POP([C])])
+
+# For backward compatibility.
+AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])])
+
+# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_RUN_LOG(COMMAND)
+# -------------------
+# Run COMMAND, save the exit status in ac_status, and log it.
+# (This has been adapted from Autoconf's _AC_RUN_LOG macro.)
+AC_DEFUN([AM_RUN_LOG],
+[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD
+   ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD
+   ac_status=$?
+   echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+   (exit $ac_status); }])
+
+# Check to make sure that the build environment is sane.    -*- Autoconf -*-
+
+# Copyright (C) 1996-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_SANITY_CHECK
+# ---------------
+AC_DEFUN([AM_SANITY_CHECK],
+[AC_MSG_CHECKING([whether build environment is sane])
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name.  Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+  *[[\\\"\#\$\&\'\`$am_lf]]*)
+    AC_MSG_ERROR([unsafe absolute working directory name]);;
+esac
+case $srcdir in
+  *[[\\\"\#\$\&\'\`$am_lf\ \	]]*)
+    AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);;
+esac
+
+# Do 'set' in a subshell so we don't clobber the current shell's
+# arguments.  Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+   am_has_slept=no
+   for am_try in 1 2; do
+     echo "timestamp, slept: $am_has_slept" > conftest.file
+     set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+     if test "$[*]" = "X"; then
+	# -L didn't work.
+	set X `ls -t "$srcdir/configure" conftest.file`
+     fi
+     if test "$[*]" != "X $srcdir/configure conftest.file" \
+	&& test "$[*]" != "X conftest.file $srcdir/configure"; then
+
+	# If neither matched, then we have a broken ls.  This can happen
+	# if, for instance, CONFIG_SHELL is bash and it inherits a
+	# broken ls alias from the environment.  This has actually
+	# happened.  Such a system could not be considered "sane".
+	AC_MSG_ERROR([ls -t appears to fail.  Make sure there is not a broken
+  alias in your environment])
+     fi
+     if test "$[2]" = conftest.file || test $am_try -eq 2; then
+       break
+     fi
+     # Just in case.
+     sleep 1
+     am_has_slept=yes
+   done
+   test "$[2]" = conftest.file
+   )
+then
+   # Ok.
+   :
+else
+   AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+AC_MSG_RESULT([yes])
+# If we didn't sleep, we still need to ensure time stamps of config.status and
+# generated files are strictly newer.
+am_sleep_pid=
+if grep 'slept: no' conftest.file >/dev/null 2>&1; then
+  ( sleep 1 ) &
+  am_sleep_pid=$!
+fi
+AC_CONFIG_COMMANDS_PRE(
+  [AC_MSG_CHECKING([that generated files are newer than configure])
+   if test -n "$am_sleep_pid"; then
+     # Hide warnings about reused PIDs.
+     wait $am_sleep_pid 2>/dev/null
+   fi
+   AC_MSG_RESULT([done])])
+rm -f conftest.file
+])
+
+# Copyright (C) 2009-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_SILENT_RULES([DEFAULT])
+# --------------------------
+# Enable less verbose build rules; with the default set to DEFAULT
+# ("yes" being less verbose, "no" or empty being verbose).
+AC_DEFUN([AM_SILENT_RULES],
+[AC_ARG_ENABLE([silent-rules], [dnl
+AS_HELP_STRING(
+  [--enable-silent-rules],
+  [less verbose build output (undo: "make V=1")])
+AS_HELP_STRING(
+  [--disable-silent-rules],
+  [verbose build output (undo: "make V=0")])dnl
+])
+case $enable_silent_rules in @%:@ (((
+  yes) AM_DEFAULT_VERBOSITY=0;;
+   no) AM_DEFAULT_VERBOSITY=1;;
+    *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);;
+esac
+dnl
+dnl A few 'make' implementations (e.g., NonStop OS and NextStep)
+dnl do not support nested variable expansions.
+dnl See automake bug#9928 and bug#10237.
+am_make=${MAKE-make}
+AC_CACHE_CHECK([whether $am_make supports nested variables],
+   [am_cv_make_support_nested_variables],
+   [if AS_ECHO([['TRUE=$(BAR$(V))
+BAR0=false
+BAR1=true
+V=1
+am__doit:
+	@$(TRUE)
+.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then
+  am_cv_make_support_nested_variables=yes
+else
+  am_cv_make_support_nested_variables=no
+fi])
+if test $am_cv_make_support_nested_variables = yes; then
+  dnl Using '$V' instead of '$(V)' breaks IRIX make.
+  AM_V='$(V)'
+  AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
+else
+  AM_V=$AM_DEFAULT_VERBOSITY
+  AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
+fi
+AC_SUBST([AM_V])dnl
+AM_SUBST_NOTMAKE([AM_V])dnl
+AC_SUBST([AM_DEFAULT_V])dnl
+AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl
+AC_SUBST([AM_DEFAULT_VERBOSITY])dnl
+AM_BACKSLASH='\'
+AC_SUBST([AM_BACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl
+])
+
+# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_STRIP
+# ---------------------
+# One issue with vendor 'install' (even GNU) is that you can't
+# specify the program used to strip binaries.  This is especially
+# annoying in cross-compiling environments, where the build's strip
+# is unlikely to handle the host's binaries.
+# Fortunately install-sh will honor a STRIPPROG variable, so we
+# always use install-sh in "make install-strip", and initialize
+# STRIPPROG with the value of the STRIP variable (set by the user).
+AC_DEFUN([AM_PROG_INSTALL_STRIP],
+[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+# Installed binaries are usually stripped using 'strip' when the user
+# run "make install-strip".  However 'strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the 'STRIP' environment variable to overrule this program.
+dnl Don't test for $cross_compiling = yes, because it might be 'maybe'.
+if test "$cross_compiling" != no; then
+  AC_CHECK_TOOL([STRIP], [strip], :)
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+AC_SUBST([INSTALL_STRIP_PROGRAM])])
+
+# Copyright (C) 2006-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_SUBST_NOTMAKE(VARIABLE)
+# ---------------------------
+# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in.
+# This macro is traced by Automake.
+AC_DEFUN([_AM_SUBST_NOTMAKE])
+
+# AM_SUBST_NOTMAKE(VARIABLE)
+# --------------------------
+# Public sister of _AM_SUBST_NOTMAKE.
+AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
+
+# Check how to create a tarball.                            -*- Autoconf -*-
+
+# Copyright (C) 2004-2014 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_PROG_TAR(FORMAT)
+# --------------------
+# Check how to create a tarball in format FORMAT.
+# FORMAT should be one of 'v7', 'ustar', or 'pax'.
+#
+# Substitute a variable $(am__tar) that is a command
+# writing to stdout a FORMAT-tarball containing the directory
+# $tardir.
+#     tardir=directory && $(am__tar) > result.tar
+#
+# Substitute a variable $(am__untar) that extract such
+# a tarball read from stdin.
+#     $(am__untar) < result.tar
+#
+AC_DEFUN([_AM_PROG_TAR],
+[# Always define AMTAR for backward compatibility.  Yes, it's still used
+# in the wild :-(  We should find a proper way to deprecate it ...
+AC_SUBST([AMTAR], ['$${TAR-tar}'])
+
+# We'll loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
+
+m4_if([$1], [v7],
+  [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'],
+
+  [m4_case([$1],
+    [ustar],
+     [# The POSIX 1988 'ustar' format is defined with fixed-size fields.
+      # There is notably a 21 bits limit for the UID and the GID.  In fact,
+      # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343
+      # and bug#13588).
+      am_max_uid=2097151 # 2^21 - 1
+      am_max_gid=$am_max_uid
+      # The $UID and $GID variables are not portable, so we need to resort
+      # to the POSIX-mandated id(1) utility.  Errors in the 'id' calls
+      # below are definitely unexpected, so allow the users to see them
+      # (that is, avoid stderr redirection).
+      am_uid=`id -u || echo unknown`
+      am_gid=`id -g || echo unknown`
+      AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format])
+      if test $am_uid -le $am_max_uid; then
+         AC_MSG_RESULT([yes])
+      else
+         AC_MSG_RESULT([no])
+         _am_tools=none
+      fi
+      AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format])
+      if test $am_gid -le $am_max_gid; then
+         AC_MSG_RESULT([yes])
+      else
+        AC_MSG_RESULT([no])
+        _am_tools=none
+      fi],
+
+  [pax],
+    [],
+
+  [m4_fatal([Unknown tar format])])
+
+  AC_MSG_CHECKING([how to create a $1 tar archive])
+
+  # Go ahead even if we have the value already cached.  We do so because we
+  # need to set the values for the 'am__tar' and 'am__untar' variables.
+  _am_tools=${am_cv_prog_tar_$1-$_am_tools}
+
+  for _am_tool in $_am_tools; do
+    case $_am_tool in
+    gnutar)
+      for _am_tar in tar gnutar gtar; do
+        AM_RUN_LOG([$_am_tar --version]) && break
+      done
+      am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
+      am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
+      am__untar="$_am_tar -xf -"
+      ;;
+    plaintar)
+      # Must skip GNU tar: if it does not support --format= it doesn't create
+      # ustar tarball either.
+      (tar --version) >/dev/null 2>&1 && continue
+      am__tar='tar chf - "$$tardir"'
+      am__tar_='tar chf - "$tardir"'
+      am__untar='tar xf -'
+      ;;
+    pax)
+      am__tar='pax -L -x $1 -w "$$tardir"'
+      am__tar_='pax -L -x $1 -w "$tardir"'
+      am__untar='pax -r'
+      ;;
+    cpio)
+      am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
+      am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
+      am__untar='cpio -i -H $1 -d'
+      ;;
+    none)
+      am__tar=false
+      am__tar_=false
+      am__untar=false
+      ;;
+    esac
+
+    # If the value was cached, stop now.  We just wanted to have am__tar
+    # and am__untar set.
+    test -n "${am_cv_prog_tar_$1}" && break
+
+    # tar/untar a dummy directory, and stop if the command works.
+    rm -rf conftest.dir
+    mkdir conftest.dir
+    echo GrepMe > conftest.dir/file
+    AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
+    rm -rf conftest.dir
+    if test -s conftest.tar; then
+      AM_RUN_LOG([$am__untar <conftest.tar])
+      AM_RUN_LOG([cat conftest.dir/file])
+      grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
+    fi
+  done
+  rm -rf conftest.dir
+
+  AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
+  AC_MSG_RESULT([$am_cv_prog_tar_$1])])
+
+AC_SUBST([am__tar])
+AC_SUBST([am__untar])
+]) # _AM_PROG_TAR
+
+m4_include([acinclude.m4])
diff --git a/third_party/gmp/asl.h b/third_party/gmp/asl.h
new file mode 100644
index 0000000..64deea0
--- /dev/null
+++ b/third_party/gmp/asl.h
@@ -0,0 +1,127 @@
+/* asl.h -- artificially small limbs support by means of C++ operator
+   overloading.
+
+Copyright 2016 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <iostream>
+#include <cstdint>
+#include <cstdlib>
+// #include <stdexcept>
+
+#ifndef GMP_ASSERT_ALWAYS
+#define GMP_ASSERT_ALWAYS(cc) do {if (!(cc)) abort();} while (0)
+#endif
+
+// Missing: post++ post-- ++pre --prec bool(limb) !limb
+
+#ifndef GMP_LIMB_BITS
+#define GMP_LIMB_BITS 4
+#endif
+
+#define GMP_NUMB_MASK (2 * (1ul << (GMP_LIMB_BITS - 1)) - 1)
+
+#define BINOP_MASK(op, type)				\
+  mp_limb_t& operator op##=(const type& rhs) {		\
+    limbo = (limbo op rhs.limbo) & GMP_NUMB_MASK;	\
+    return *this;					\
+  }
+#define BINOP_NOMASK(op, type)				\
+  mp_limb_t& operator op##=(const type& rhs) {		\
+    limbo = limbo op rhs.limbo;				\
+    return *this;					\
+  }
+
+typedef std::conditional<(GMP_NUMB_MASK <= 0xffff), uint16_t, uint32_t >::type type24;
+typedef std::conditional<(GMP_NUMB_MASK <= 0xff), uint8_t, type24>::type mtype;
+
+class mp_limb_t {
+public:
+  mp_limb_t() {}	// put random garbage in limbo?
+  mp_limb_t(const unsigned int rhs) { limbo = rhs & GMP_NUMB_MASK; }
+  // mp_limb_t(const mp_limb_t& rhs) { limbo = rhs.limbo; } // Causes havoc
+  BINOP_MASK(+, mp_limb_t)
+  BINOP_MASK(-, mp_limb_t)
+  BINOP_MASK(*, mp_limb_t)
+  BINOP_NOMASK(/, mp_limb_t)
+  BINOP_NOMASK(%, mp_limb_t)
+  BINOP_NOMASK(&, mp_limb_t)
+  BINOP_NOMASK(|, mp_limb_t)
+  BINOP_NOMASK(^, mp_limb_t)
+  mp_limb_t& operator<<=(const unsigned int rhs) {
+    GMP_ASSERT_ALWAYS (rhs < GMP_LIMB_BITS);
+    limbo = (limbo << rhs) & GMP_NUMB_MASK;
+    return *this;
+  }
+  mp_limb_t& operator>>=(const unsigned int rhs) {
+    GMP_ASSERT_ALWAYS (rhs < GMP_LIMB_BITS);
+    limbo = limbo >> rhs;
+    return *this;
+  }
+  mp_limb_t operator-() {
+    return static_cast<mp_limb_t>((-limbo) & GMP_NUMB_MASK);
+    // mp_limb_t x;  x.limbo = (-limbo) & GMP_NUMB_MASK;  return x;
+  }
+  mp_limb_t operator~() {
+    return static_cast<mp_limb_t>((~limbo) & GMP_NUMB_MASK);
+    // mp_limb_t x;  x.limbo = (~limbo) & GMP_NUMB_MASK;  return x;
+  }
+  operator unsigned int() const { return limbo; }
+  operator          int() const { return limbo; }
+
+#define RELOP(op)							\
+  inline bool operator op(const mp_limb_t rhs) {			\
+    return limbo op rhs.limbo;						\
+  }
+  RELOP(==)
+  RELOP(!=)
+  RELOP(<)
+  RELOP(>)
+  RELOP(<=)
+  RELOP(>=)
+
+private:
+  mtype limbo;
+};
+
+#define BINOP2(op, type)						\
+  inline mp_limb_t operator op(mp_limb_t lhs, const type& rhs) {	\
+    lhs op##= rhs;							\
+    return lhs;								\
+  }
+
+BINOP2(+, mp_limb_t)
+BINOP2(-, mp_limb_t)
+BINOP2(*, mp_limb_t)
+BINOP2(/, mp_limb_t)
+BINOP2(%, mp_limb_t)
+BINOP2(&, mp_limb_t)
+BINOP2(|, mp_limb_t)
+BINOP2(^, mp_limb_t)
+BINOP2(<<, unsigned int)
+BINOP2(>>, unsigned int)
diff --git a/third_party/gmp/assert.c b/third_party/gmp/assert.c
new file mode 100644
index 0000000..aef95b2
--- /dev/null
+++ b/third_party/gmp/assert.c
@@ -0,0 +1,58 @@
+/* GMP assertion failure handler.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+
+
+void
+__gmp_assert_header (const char *filename, int linenum)
+{
+  if (filename != NULL && filename[0] != '\0')
+    {
+      fprintf (stderr, "%s:", filename);
+      if (linenum != -1)
+        fprintf (stderr, "%d: ", linenum);
+    }
+}
+
+void
+__gmp_assert_fail (const char *filename, int linenum,
+                   const char *expr)
+{
+  __gmp_assert_header (filename, linenum);
+  fprintf (stderr, "GNU MP assertion failed: %s\n", expr);
+  abort();
+}
diff --git a/third_party/gmp/bootstrap.c b/third_party/gmp/bootstrap.c
new file mode 100644
index 0000000..5f8ed72
--- /dev/null
+++ b/third_party/gmp/bootstrap.c
@@ -0,0 +1,146 @@
+/* Functions needed for bootstrapping the gmp build, based on mini-gmp.
+
+Copyright 2001, 2002, 2004, 2011, 2012, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#define MINI_GMP_DONT_USE_FLOAT_H 1
+#include "mini-gmp/mini-gmp.c"
+
+#define MIN(l,o) ((l) < (o) ? (l) : (o))
+#define PTR(x)   ((x)->_mp_d)
+#define SIZ(x)   ((x)->_mp_size)
+
+#define xmalloc gmp_default_alloc
+
+int
+isprime (unsigned long int t)
+{
+  unsigned long int q, r, d;
+
+  if (t < 32)
+    return (0xa08a28acUL >> t) & 1;
+  if ((t & 1) == 0)
+    return 0;
+
+  if (t % 3 == 0)
+    return 0;
+  if (t % 5 == 0)
+    return 0;
+  if (t % 7 == 0)
+    return 0;
+
+  for (d = 11;;)
+    {
+      q = t / d;
+      r = t - q * d;
+      if (q < d)
+	return 1;
+      if (r == 0)
+	break;
+      d += 2;
+      q = t / d;
+      r = t - q * d;
+      if (q < d)
+	return 1;
+      if (r == 0)
+	break;
+      d += 4;
+    }
+  return 0;
+}
+
+int
+log2_ceil (int n)
+{
+  int  e;
+  assert (n >= 1);
+  for (e = 0; ; e++)
+    if ((1 << e) >= n)
+      break;
+  return e;
+}
+
+/* Set inv to the inverse of d, in the style of invert_limb, ie. for
+   udiv_qrnnd_preinv.  */
+void
+mpz_preinv_invert (mpz_t inv, const mpz_t d, int numb_bits)
+{
+  mpz_t  t;
+  int    norm;
+  assert (SIZ(d) > 0);
+
+  norm = numb_bits - mpz_sizeinbase (d, 2);
+  assert (norm >= 0);
+  mpz_init (t);
+  mpz_setbit (t, 2*numb_bits - norm);
+  mpz_tdiv_q (inv, t, d);
+  mpz_clrbit (inv, numb_bits);
+
+  mpz_clear (t);
+}
+
+/* Calculate r satisfying r*d == 1 mod 2^n. */
+void
+mpz_invert_2exp (mpz_t r, const mpz_t a, unsigned long n)
+{
+  unsigned long  i;
+  mpz_t  inv, prod;
+
+  assert (mpz_odd_p (a));
+
+  mpz_init_set_ui (inv, 1L);
+  mpz_init (prod);
+
+  for (i = 1; i < n; i++)
+    {
+      mpz_mul (prod, inv, a);
+      if (mpz_tstbit (prod, i) != 0)
+	mpz_setbit (inv, i);
+    }
+
+  mpz_mul (prod, inv, a);
+  mpz_tdiv_r_2exp (prod, prod, n);
+  assert (mpz_cmp_ui (prod, 1L) == 0);
+
+  mpz_set (r, inv);
+
+  mpz_clear (inv);
+  mpz_clear (prod);
+}
+
+/* Calculate inv satisfying r*a == 1 mod 2^n. */
+void
+mpz_invert_ui_2exp (mpz_t r, unsigned long a, unsigned long n)
+{
+  mpz_t  az;
+
+  mpz_init_set_ui (az, a);
+  mpz_invert_2exp (r, az, n);
+  mpz_clear (az);
+}
diff --git a/third_party/gmp/compat.c b/third_party/gmp/compat.c
new file mode 100644
index 0000000..b4b44ce
--- /dev/null
+++ b/third_party/gmp/compat.c
@@ -0,0 +1,59 @@
+/* Old function entrypoints retained for binary compatibility.
+
+Copyright 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp-impl.h"
+
+
+/* mpn_divexact_by3 was a function in gmp 3.0.1, but as of gmp 3.1 it's a
+   macro calling mpn_divexact_by3c.  */
+mp_limb_t
+__MPN (divexact_by3) (mp_ptr dst, mp_srcptr src, mp_size_t size)
+{
+  return mpn_divexact_by3 (dst, src, size);
+}
+
+
+/* mpn_divmod_1 was a function in gmp 3.0.1 and earlier, but marked obsolete
+   in both gmp 2 and 3.  As of gmp 3.1 it's a macro calling mpn_divrem_1. */
+mp_limb_t
+__MPN (divmod_1) (mp_ptr dst, mp_srcptr src, mp_size_t size, mp_limb_t divisor)
+{
+  return mpn_divmod_1 (dst, src, size, divisor);
+}
+
+
+/* mpz_legendre was a separate function in gmp 3.1.1 and earlier, but as of
+   4.0 it's a #define alias for mpz_jacobi.  */
+int
+__gmpz_legendre (mpz_srcptr a, mpz_srcptr b)
+{
+  return mpz_jacobi (a, b);
+}
diff --git a/third_party/gmp/compile b/third_party/gmp/compile
new file mode 100755
index 0000000..a85b723
--- /dev/null
+++ b/third_party/gmp/compile
@@ -0,0 +1,347 @@
+#! /bin/sh
+# Wrapper for compilers which do not understand '-c -o'.
+
+scriptversion=2012-10-14.11; # UTC
+
+# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+# Written by Tom Tromey <tromey@cygnus.com>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+nl='
+'
+
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent tools from complaining about whitespace usage.
+IFS=" ""	$nl"
+
+file_conv=
+
+# func_file_conv build_file lazy
+# Convert a $build file to $host form and store it in $file
+# Currently only supports Windows hosts. If the determined conversion
+# type is listed in (the comma separated) LAZY, no conversion will
+# take place.
+func_file_conv ()
+{
+  file=$1
+  case $file in
+    / | /[!/]*) # absolute file, and not a UNC file
+      if test -z "$file_conv"; then
+	# lazily determine how to convert abs files
+	case `uname -s` in
+	  MINGW*)
+	    file_conv=mingw
+	    ;;
+	  CYGWIN*)
+	    file_conv=cygwin
+	    ;;
+	  *)
+	    file_conv=wine
+	    ;;
+	esac
+      fi
+      case $file_conv/,$2, in
+	*,$file_conv,*)
+	  ;;
+	mingw/*)
+	  file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
+	  ;;
+	cygwin/*)
+	  file=`cygpath -m "$file" || echo "$file"`
+	  ;;
+	wine/*)
+	  file=`winepath -w "$file" || echo "$file"`
+	  ;;
+      esac
+      ;;
+  esac
+}
+
+# func_cl_dashL linkdir
+# Make cl look for libraries in LINKDIR
+func_cl_dashL ()
+{
+  func_file_conv "$1"
+  if test -z "$lib_path"; then
+    lib_path=$file
+  else
+    lib_path="$lib_path;$file"
+  fi
+  linker_opts="$linker_opts -LIBPATH:$file"
+}
+
+# func_cl_dashl library
+# Do a library search-path lookup for cl
+func_cl_dashl ()
+{
+  lib=$1
+  found=no
+  save_IFS=$IFS
+  IFS=';'
+  for dir in $lib_path $LIB
+  do
+    IFS=$save_IFS
+    if $shared && test -f "$dir/$lib.dll.lib"; then
+      found=yes
+      lib=$dir/$lib.dll.lib
+      break
+    fi
+    if test -f "$dir/$lib.lib"; then
+      found=yes
+      lib=$dir/$lib.lib
+      break
+    fi
+    if test -f "$dir/lib$lib.a"; then
+      found=yes
+      lib=$dir/lib$lib.a
+      break
+    fi
+  done
+  IFS=$save_IFS
+
+  if test "$found" != yes; then
+    lib=$lib.lib
+  fi
+}
+
+# func_cl_wrapper cl arg...
+# Adjust compile command to suit cl
+func_cl_wrapper ()
+{
+  # Assume a capable shell
+  lib_path=
+  shared=:
+  linker_opts=
+  for arg
+  do
+    if test -n "$eat"; then
+      eat=
+    else
+      case $1 in
+	-o)
+	  # configure might choose to run compile as 'compile cc -o foo foo.c'.
+	  eat=1
+	  case $2 in
+	    *.o | *.[oO][bB][jJ])
+	      func_file_conv "$2"
+	      set x "$@" -Fo"$file"
+	      shift
+	      ;;
+	    *)
+	      func_file_conv "$2"
+	      set x "$@" -Fe"$file"
+	      shift
+	      ;;
+	  esac
+	  ;;
+	-I)
+	  eat=1
+	  func_file_conv "$2" mingw
+	  set x "$@" -I"$file"
+	  shift
+	  ;;
+	-I*)
+	  func_file_conv "${1#-I}" mingw
+	  set x "$@" -I"$file"
+	  shift
+	  ;;
+	-l)
+	  eat=1
+	  func_cl_dashl "$2"
+	  set x "$@" "$lib"
+	  shift
+	  ;;
+	-l*)
+	  func_cl_dashl "${1#-l}"
+	  set x "$@" "$lib"
+	  shift
+	  ;;
+	-L)
+	  eat=1
+	  func_cl_dashL "$2"
+	  ;;
+	-L*)
+	  func_cl_dashL "${1#-L}"
+	  ;;
+	-static)
+	  shared=false
+	  ;;
+	-Wl,*)
+	  arg=${1#-Wl,}
+	  save_ifs="$IFS"; IFS=','
+	  for flag in $arg; do
+	    IFS="$save_ifs"
+	    linker_opts="$linker_opts $flag"
+	  done
+	  IFS="$save_ifs"
+	  ;;
+	-Xlinker)
+	  eat=1
+	  linker_opts="$linker_opts $2"
+	  ;;
+	-*)
+	  set x "$@" "$1"
+	  shift
+	  ;;
+	*.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
+	  func_file_conv "$1"
+	  set x "$@" -Tp"$file"
+	  shift
+	  ;;
+	*.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
+	  func_file_conv "$1" mingw
+	  set x "$@" "$file"
+	  shift
+	  ;;
+	*)
+	  set x "$@" "$1"
+	  shift
+	  ;;
+      esac
+    fi
+    shift
+  done
+  if test -n "$linker_opts"; then
+    linker_opts="-link$linker_opts"
+  fi
+  exec "$@" $linker_opts
+  exit 1
+}
+
+eat=
+
+case $1 in
+  '')
+     echo "$0: No command.  Try '$0 --help' for more information." 1>&2
+     exit 1;
+     ;;
+  -h | --h*)
+    cat <<\EOF
+Usage: compile [--help] [--version] PROGRAM [ARGS]
+
+Wrapper for compilers which do not understand '-c -o'.
+Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
+arguments, and rename the output as expected.
+
+If you are trying to build a whole package this is not the
+right script to run: please start by reading the file 'INSTALL'.
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+    exit $?
+    ;;
+  -v | --v*)
+    echo "compile $scriptversion"
+    exit $?
+    ;;
+  cl | *[/\\]cl | cl.exe | *[/\\]cl.exe )
+    func_cl_wrapper "$@"      # Doesn't return...
+    ;;
+esac
+
+ofile=
+cfile=
+
+for arg
+do
+  if test -n "$eat"; then
+    eat=
+  else
+    case $1 in
+      -o)
+	# configure might choose to run compile as 'compile cc -o foo foo.c'.
+	# So we strip '-o arg' only if arg is an object.
+	eat=1
+	case $2 in
+	  *.o | *.obj)
+	    ofile=$2
+	    ;;
+	  *)
+	    set x "$@" -o "$2"
+	    shift
+	    ;;
+	esac
+	;;
+      *.c)
+	cfile=$1
+	set x "$@" "$1"
+	shift
+	;;
+      *)
+	set x "$@" "$1"
+	shift
+	;;
+    esac
+  fi
+  shift
+done
+
+if test -z "$ofile" || test -z "$cfile"; then
+  # If no '-o' option was seen then we might have been invoked from a
+  # pattern rule where we don't need one.  That is ok -- this is a
+  # normal compilation that the losing compiler can handle.  If no
+  # '.c' file was seen then we are probably linking.  That is also
+  # ok.
+  exec "$@"
+fi
+
+# Name of file we expect compiler to create.
+cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
+
+# Create the lock directory.
+# Note: use '[/\\:.-]' here to ensure that we don't use the same name
+# that we are using for the .o file.  Also, base the name on the expected
+# object file name, since that is what matters with a parallel build.
+lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
+while true; do
+  if mkdir "$lockdir" >/dev/null 2>&1; then
+    break
+  fi
+  sleep 1
+done
+# FIXME: race condition here if user kills between mkdir and trap.
+trap "rmdir '$lockdir'; exit 1" 1 2 15
+
+# Run the compile.
+"$@"
+ret=$?
+
+if test -f "$cofile"; then
+  test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
+elif test -f "${cofile}bj"; then
+  test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
+fi
+
+rmdir "$lockdir"
+exit $ret
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/third_party/gmp/config.guess b/third_party/gmp/config.guess
new file mode 100755
index 0000000..6631488
--- /dev/null
+++ b/third_party/gmp/config.guess
@@ -0,0 +1,1147 @@
+#! /bin/sh
+#
+# GMP config.guess wrapper.
+
+
+# Copyright 2000-2019 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+
+# Usage: config.guess
+#
+# Print the host system CPU-VENDOR-OS.
+#
+# configfsf.guess is run and its guess then sharpened up to take advantage
+# of the finer grained CPU types that GMP knows.
+
+
+# Expect to find configfsf.guess in the same directory as this config.guess
+configfsf_guess="`echo \"$0\" | sed 's/config.guess$/configfsf.guess/'`"
+if test "$configfsf_guess" = "$0"; then
+  echo "Cannot derive configfsf.guess from $0" 1>&2
+  exit 1
+fi
+if test -f "$configfsf_guess"; then
+  :
+else
+  echo "$configfsf_guess not found" 1>&2
+  exit 1
+fi
+
+# Setup a $SHELL with which to run configfsf.guess, using the same
+# $CONFIG_SHELL or /bin/sh as autoconf does when running config.guess
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+# Identify ourselves on --version, --help or errors
+if test $# != 0; then
+  echo "(GNU MP wrapped config.guess)"
+  $SHELL $configfsf_guess "$@"
+  exit 1
+fi
+
+guess_full=`$SHELL $configfsf_guess`
+if test $? != 0; then
+  exit 1
+fi
+
+guess_cpu=`echo "$guess_full" | sed 's/-.*$//'`
+guess_rest=`echo "$guess_full" | sed 's/^[^-]*//'`
+exact_cpu=
+
+
+# -------------------------------------------------------------------------
+# The following should look at the current guess and probe the system to
+# establish a better guess in exact_cpu.  Leave exact_cpu empty if probes
+# can't be done, or don't work.
+#
+# When a number of probes are done, test -z "$exact_cpu" can be used instead
+# of putting each probe under an "else" of the preceeding.  That can stop
+# the code getting horribly nested and marching off the right side of the
+# screen.
+
+# Note that when a compile-and-link is done in one step we need to remove .o
+# files, since lame C compilers generate these even when not asked.
+#
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy $dummy.core ${dummy}0.s" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,)    echo "int x;" > $dummy.c ;
+	for c in cc gcc c89 c99 ; do
+	  if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+	     CC_FOR_BUILD="$c"; break ;
+	  fi ;
+	done ;
+	if test x"$CC_FOR_BUILD" = x ; then
+	  CC_FOR_BUILD=no_compiler_found ;
+	fi
+	;;
+ ,,*)   CC_FOR_BUILD=$CC ;;
+ ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+
+case "$guess_full" in
+
+alpha-*-*)
+  eval $set_cc_for_build
+  # configfsf.guess detects exact alpha cpu types for OSF and GNU/Linux, but
+  # not for *BSD and other systems.  We try to get an exact type for any
+  # plain "alpha" it leaves.
+  #
+  # configfsf.guess used to have a block of code not unlike this, but these
+  # days does its thing with Linux kernel /proc/cpuinfo or OSF psrinfo.
+  #
+  cat <<EOF >${dummy}0.s
+	.data
+Lformat:
+	.byte 37,100,45,37,120,10,0	# "%d-%x\n"
+	.text
+	.globl main
+	.align 4
+	.ent main
+main:
+	.frame \$30,16,\$26,0
+	ldgp \$29,0(\$27)
+	.prologue 1
+	.long 0x47e03d91 # implver \$17
+	lda \$2,-1
+	.long 0x47e20c21 # amask \$2,\$1
+	lda \$16,Lformat
+	not \$1,\$18
+	jsr \$26,printf
+	ldgp \$29,0(\$26)
+	mov 0,\$16
+	jsr \$26,exit
+	.end main
+EOF
+  $CC_FOR_BUILD ${dummy}0.s -o $dummy 2>/dev/null
+  if test "$?" = 0 ; then
+    case `$dummy` in
+    0-0)	exact_cpu=alpha      ;;
+    1-0)	exact_cpu=alphaev5   ;;
+    1-1)	exact_cpu=alphaev56  ;;
+    1-101)	exact_cpu=alphapca56 ;;
+    2-303)	exact_cpu=alphaev6   ;;
+    2-307)	exact_cpu=alphaev67  ;;
+    2-1307)	exact_cpu=alphaev68  ;;
+    esac
+  fi
+  ;;
+
+arm*-*-* | aarch64-*-*)
+  cpu_code=`sed -n 's/^CPU part.*\(0x.*\)$/\1/p' /proc/cpuinfo 2>/dev/null | sort -r | head -n 1 2>/dev/null`
+  cpu_implementer=`sed -n 's/^CPU implementer.*\(0x.*\)$/\1/p' /proc/cpuinfo 2>/dev/null | head -n 1 2>/dev/null`
+  case "${cpu_implementer}_${cpu_code}" in
+    0x53_0x001) exact_cpu=armexynosm1  ;;
+    0x51_0x800) exact_cpu=armcortexa57 ;;
+    0x43_0x0a1) exact_cpu=armthunderx  ;;
+    0x50_0x000) exact_cpu=armxgene1    ;;
+  esac
+  if test -z "$exact_cpu"; then
+    case "$cpu_code" in
+	0xa10 | 0xa11 | 0xb11)			# v4 strongarm/sa1100
+		exact_cpu="armsa1";;
+	0x915 | 0x925 | \
+	0x920 | 0x922 | 0x940)			# v4
+		exact_cpu="arm9tdmi";;
+	0x210 | 0x290 | 0x2d0 | \
+	0x212 | 0x292 | 0x2d2 | \
+	0x411)	exact_cpu="armxscale";;		# v5 pxa2xx
+	0x926 | 0x946 | 0x966 | 0x968)		# v5te/v5tej
+		exact_cpu="arm9te";;
+	0xa20 | 0xa22 | 0xa26)			# v5te
+		exact_cpu="arm10";;
+	0xb02)	exact_cpu="arm11mpcore";;	# v6
+	0xb36)	exact_cpu="arm1136";;		# v6
+	0xb56)	exact_cpu="arm1156";;		# v6t2
+	0xb76)	exact_cpu="arm1176";;		# v6
+	0xc05)	exact_cpu="armcortexa5";;	# v7a
+	0xc07)	exact_cpu="armcortexa7";;	# v7a
+	0xc08)	exact_cpu="armcortexa8";;	# v7a
+	0xc09)	exact_cpu="armcortexa9";;	# v7a
+	0xc0f)	exact_cpu="armcortexa15";;	# v7a
+	0xc0d)	exact_cpu="armcortexa12";;	# v7a
+	0xc0e)	exact_cpu="armcortexa17";;	# v7a
+	0xc14)	exact_cpu="armcortexr4";;	# v7r
+	0xc15)	exact_cpu="armcortexr5";;	# v7r
+	0xc23)	exact_cpu="armcortexm3";;	# v7m
+
+	0xd04)	exact_cpu="armcortexa35";;	# v8
+	0xd03)	exact_cpu="armcortexa53";;	# v8
+	0xd05)	exact_cpu="armcortexa55";;	# v8.2
+	0xd07)	exact_cpu="armcortexa57";;	# v8
+	0xd08)	exact_cpu="armcortexa72";;	# v8
+	0xd09)	exact_cpu="armcortexa73";;	# v8
+	0xd0a)	exact_cpu="armcortexa75";;	# v8.2
+	0xd0b)	exact_cpu="armcortexa76";;	# v8.3
+	*)	exact_cpu=$guess_cpu;;
+    esac
+  fi
+  exact_cpu="${exact_cpu}`sed -n 's;^Features.*\(neon\).*;\1;p' /proc/cpuinfo 2>/dev/null | head -n 1 2>/dev/null`"
+  ;;
+
+ia64*-*-*)
+  eval $set_cc_for_build
+  # CPUID[3] bits 24 to 31 is the processor family.  itanium2 is documented
+  # as 0x1f, plain itanium has been seen returning 0x07 on two systems, but
+  # haven't found any documentation on it as such.
+  #
+  # Defining both getcpuid and _getcpuid lets us ignore whether the system
+  # expects underscores or not.
+  #
+  # "unsigned long long" is always 64 bits, in fact on hpux in ilp32 mode
+  # (which is the default there), it's the only 64-bit type.
+  #
+  cat >${dummy}0.s <<EOF
+	.text
+	.global	_getcpuid
+	.proc	_getcpuid
+_getcpuid:
+	mov	r8 = CPUID[r32] ;;
+	br.ret.sptk.many rp ;;
+	.endp	_getcpuid
+	.global	getcpuid
+	.proc	getcpuid
+getcpuid:
+	mov	r8 = CPUID[r32] ;;
+	br.ret.sptk.many rp ;;
+	.endp	getcpuid
+EOF
+  cat >$dummy.c <<EOF
+#include <stdio.h>
+unsigned long long getcpuid ();
+int
+main ()
+{
+  if (getcpuid(0LL) == 0x49656E69756E6547LL && getcpuid(1LL) == 0x6C65746ELL)
+    {
+      /* "GenuineIntel" */
+      switch ((getcpuid(3LL) >> 24) & 0xFF) {
+      case 0x07: puts ("itanium");  break;
+      case 0x1F: puts ("itanium2"); break; /* McKinley, Madison */
+      case 0x20: puts ("itanium2"); break; /* Montecito, Montvale, Tukwila */
+      case 0x21: puts ("itanium2"); break; /* Poulson */
+      }
+    }
+  return 0;
+}
+EOF
+  if $CC_FOR_BUILD ${dummy}0.s $dummy.c -o $dummy >/dev/null 2>&1; then
+    exact_cpu=`$dummy`
+  fi
+  ;;
+
+mips-*-irix[6789]*)
+  # IRIX 6 and up always has a 64-bit mips cpu
+  exact_cpu=mips64
+  ;;
+
+mips-*-*)
+  case $(uname -m) in
+    mips64)	exact_cpu=mips64;;
+  esac
+  ;;
+
+mipsel-*-*)
+  case $(uname -m) in
+    mips64)	exact_cpu=mips64el;;
+  esac
+  ;;
+
+m68k-*-*)
+  eval $set_cc_for_build
+  # NetBSD (and presumably other *BSD) "sysctl hw.model" gives for example
+  #   hw.model = Apple Macintosh Quadra 610  (68040)
+  exact_cpu=`(sysctl hw.model) 2>/dev/null | sed -n 's/^.*\(680[012346]0\).*$/m\1/p'`
+  if test -z "$exact_cpu"; then
+    # Linux kernel 2.2 gives for example "CPU: 68020" (tabs in between).
+    exact_cpu=`sed -n 's/^CPU:.*\(680[012346]0\).*$/m\1/p' /proc/cpuinfo 2>/dev/null`
+  fi
+  if test -z "$exact_cpu"; then
+    # Try: movel #0,%d0; rts
+    # This is to check the compiler and our asm code works etc, before
+    # assuming failures below indicate cpu characteristics.
+    # .byte is used to avoid problems with assembler syntax variations.
+    # For testing, provoke failures by adding "illegal" possibly as
+    # ".byte 0x4A, 0xFC"
+    cat >${dummy}0.s <<EOF
+	.text
+	.globl main
+	.globl _main
+main:
+_main:
+	.byte	0x70, 0x00
+	.byte	0x4e, 0x75
+EOF
+
+    if ($CC_FOR_BUILD ${dummy}0.s -o $dummy && $dummy) >/dev/null 2>&1; then
+
+      # $SHELL -c is used to execute $dummy below, since ($dummy)
+      # 2>/dev/null still prints the SIGILL message on some shells.
+      #
+        # Try: movel #0,%d0
+        #      rtd #0
+        cat >${dummy}0.s <<EOF
+	.text
+	.globl main
+	.globl _main
+main:
+_main:
+	.byte	0x70, 0x00
+	.byte	0x4e, 0x74, 0x00, 0x00
+EOF
+        if $CC_FOR_BUILD ${dummy}0.s -o $dummy >/dev/null 2>&1; then
+          $SHELL -c $dummy >/dev/null 2>&1
+	  if test $? != 0; then
+            exact_cpu=m68000    # because rtd didn't work
+          fi
+        fi
+      #
+
+      if test -z "$exact_cpu"; then
+        # Try: trapf
+        #      movel #0,%d0
+        #      rts
+        # Another possibility for identifying 68000 and 68010 is the
+        # different value stored by "movem a0,(a0)+"
+        cat >${dummy}0.s <<EOF
+	.text
+	.globl main
+	.globl _main
+main:
+_main:
+	.byte	0x51, 0xFC
+	.byte	0x70, 0x00
+	.byte	0x4e, 0x75
+EOF
+        if $CC_FOR_BUILD ${dummy}0.s -o $dummy >/dev/null 2>&1; then
+          $SHELL -c $dummy >/dev/null 2>&1
+	  if test $? != 0; then
+            exact_cpu=m68010    # because trapf didn't work
+          fi
+        fi
+      fi
+
+      if test -z "$exact_cpu"; then
+        # Try: bfffo %d1{0:31},%d0
+        #      movel #0,%d0
+        #      rts
+        cat >${dummy}0.s <<EOF
+	.text
+	.globl main
+	.globl _main
+main:
+_main:
+	.byte	0xED, 0xC1, 0x00, 0x1F
+	.byte	0x70, 0x00
+	.byte	0x4e, 0x75
+EOF
+        if $CC_FOR_BUILD ${dummy}0.s -o $dummy >/dev/null 2>&1; then
+          $SHELL -c $dummy >/dev/null 2>&1
+	  if test $? != 0; then
+            exact_cpu=m68360  # cpu32, because bfffo didn't work
+          fi
+        fi
+      fi
+
+      if test -z "$exact_cpu"; then
+        # FIXME: Now we know 68020 or up, but how to detect 030, 040 and 060?
+        exact_cpu=m68020
+      fi
+    fi
+  fi
+  if test -z "$exact_cpu"; then
+    case "$guess_full" in
+      *-*-next* | *-*-openstep*)  # NeXTs are 68020 or better
+        exact_cpu=m68020 ;;
+    esac
+  fi
+  ;;
+
+
+rs6000-*-* | powerpc*-*-*)
+  # Enhancement: On MacOS the "machine" command prints for instance
+  # "ppc750".  Interestingly on powerpc970-apple-darwin6.8.5 it prints
+  # "ppc970" where there's no actual #define for 970 from NXGetLocalArchInfo
+  # (as noted below).  But the man page says the command is still "under
+  # development", so it doesn't seem wise to use it just yet, not while
+  # there's an alternative.
+
+  # Try to read the PVR.  mfpvr is a protected instruction, NetBSD, MacOS and
+  # AIX don't allow it in user mode, but the Linux kernel does.  We prefer this
+  # to /proc/cpuinfo since the latter lags for newer CPUs.
+  #
+  # Note this is no good on AIX, since a C function there is the address of
+  # a function descriptor, not actual code.  But this doesn't matter since
+  # AIX doesn't allow mfpvr anyway.
+  #
+  if test -z "$exact_cpu"; then
+    eval $set_cc_for_build
+    cat >$dummy.c <<\EOF
+#include <stdio.h>
+int
+main ()
+{
+  unsigned  pvr;
+
+  asm ("mfpvr	%0" : "=r" (pvr));
+
+  switch (pvr >> 16) {
+  case 0x0001: puts ("powerpc601");  break;
+  case 0x0003: puts ("powerpc603");  break;
+  case 0x0004: puts ("powerpc604");  break;
+  case 0x0006: puts ("powerpc603e"); break;
+  case 0x0007: puts ("powerpc603e"); break;  /* 603ev */
+  case 0x0008: puts ("powerpc750");  break;
+  case 0x0009: puts ("powerpc604e"); break;
+  case 0x000a: puts ("powerpc604e"); break;  /* 604ev5 */
+  case 0x000c: puts ("powerpc7400"); break;
+  case 0x0041: puts ("powerpc630");  break;
+  case 0x003f: puts ("power7");      break;
+  case 0x004b:
+  case 0x004c:
+  case 0x004d: puts ("power8");      break;
+  case 0x004e: puts ("power9");      break;
+  case 0x0050: puts ("powerpc860");  break;
+  case 0x8000: puts ("powerpc7450"); break;
+  case 0x8001: puts ("powerpc7455"); break;
+  case 0x8002: puts ("powerpc7457"); break;
+  case 0x8003: puts ("powerpc7447"); break; /* really 7447A */
+  case 0x800c: puts ("powerpc7410"); break;
+  }
+  return 0;
+}
+EOF
+    if ($CC_FOR_BUILD $dummy.c -o $dummy) >/dev/null 2>&1; then
+      # This style construct is needed on AIX 4.3 to suppress the SIGILL error
+      # from (*fun)().  Using $SHELL -c $dummy 2>/dev/null doesn't work.
+      { x=`$dummy`; } 2>/dev/null
+      if test -n "$x"; then
+	exact_cpu=$x
+      fi
+    fi
+  fi
+
+
+  # Grep the /proc/cpuinfo pseudo-file.
+  # Anything unrecognised is ignored, since of course we mustn't spit out
+  # a cpu type config.sub doesn't know.
+  if test -z "$exact_cpu" && test -f /proc/cpuinfo; then
+    x=`grep "^cpu[ 	]" /proc/cpuinfo | head -n 1`
+    x=`echo $x | sed -n 's/^cpu[ 	]*:[ 	]*\([A-Za-z0-9]*\).*/\1/p'`
+    x=`echo $x | sed 's/PPC//'`
+    case $x in
+      601)     exact_cpu="power" ;;
+      603ev)   exact_cpu="powerpc603e" ;;
+      604ev5)  exact_cpu="powerpc604e" ;;
+      970??)   exact_cpu="powerpc970" ;;
+      603 | 603e | 604 | 604e | 750 | 821 | 860)
+        exact_cpu="powerpc$x" ;;
+      POWER[4-9]*)
+        exact_cpu=`echo $x | sed -e "s;POWER;power;" -e "s;[a-zA-Z]*$;;"` ;;
+    esac
+  fi
+
+
+  if test -z "$exact_cpu"; then
+    # On AIX, try looking at _system_configuration.  This is present in
+    # version 4 at least.
+    cat >$dummy.c <<EOF
+#include <stdio.h>
+#include <sys/systemcfg.h>
+int
+main ()
+{
+  switch (_system_configuration.implementation) {
+  /* Old versions of AIX don't have all these constants,
+     use ifdef for safety. */
+#ifdef POWER_RS2
+  case POWER_RS2:    puts ("power2");     break;
+#endif
+#ifdef POWER_601
+  case POWER_601:    puts ("power");      break;
+#endif
+#ifdef POWER_603
+  case POWER_603:    puts ("powerpc603"); break;
+#endif
+#ifdef POWER_604
+  case POWER_604:    puts ("powerpc604"); break;
+#endif
+#ifdef POWER_620
+  case POWER_620:    puts ("powerpc620"); break;
+#endif
+#ifdef POWER_630
+  case POWER_630:    puts ("powerpc630"); break;
+#endif
+  /* Dunno what this is, leave it out for now.
+  case POWER_A35:    puts ("powerpca35"); break;
+  */
+  /* This is waiting for a bit more info.
+  case POWER_RS64II: puts ("powerpcrs64ii"); break;
+  */
+#ifdef POWER_4
+  case POWER_4:    puts ("power4"); break;
+#endif
+#ifdef POWER_5
+  case POWER_5:    puts ("power5"); break;
+#endif
+#ifdef POWER_6
+  case POWER_6:    puts ("power6"); break;
+#endif
+#ifdef POWER_7
+  case POWER_7:    puts ("power7"); break;
+#endif
+#ifdef POWER_8
+  case POWER_8:    puts ("power8"); break;
+#endif
+#ifdef POWER_9
+  case POWER_9:    puts ("power9"); break;
+#endif
+  default:
+    if (_system_configuration.architecture == POWER_RS)
+      puts ("power");
+    else if (_system_configuration.width == 64)
+      puts ("powerpc64");
+  }
+  return 0;
+}
+EOF
+    if ($CC_FOR_BUILD $dummy.c -o $dummy) >/dev/null 2>&1; then
+      x=`$dummy`
+      if test -n "$x"; then
+        exact_cpu=$x
+      fi
+    fi
+  fi
+
+  if test -z "$exact_cpu"; then
+    # On MacOS X (or any Mach-O presumably), NXGetLocalArchInfo cpusubtype
+    # can tell us the exact cpu.
+    cat >$dummy.c <<EOF
+#include <stdio.h>
+#include <mach-o/arch.h>
+int
+main (void)
+{
+  const NXArchInfo *a = NXGetLocalArchInfo();
+  if (a->cputype == CPU_TYPE_POWERPC)
+    {
+      switch (a->cpusubtype) {
+      /* The following known to Darwin 1.3. */
+      case CPU_SUBTYPE_POWERPC_601:   puts ("powerpc601");  break;
+      case CPU_SUBTYPE_POWERPC_602:   puts ("powerpc602");  break;
+      case CPU_SUBTYPE_POWERPC_603:   puts ("powerpc603");  break;
+      case CPU_SUBTYPE_POWERPC_603e:  puts ("powerpc603e"); break;
+      case CPU_SUBTYPE_POWERPC_603ev: puts ("powerpc603e"); break;
+      case CPU_SUBTYPE_POWERPC_604:   puts ("powerpc604");  break;
+      case CPU_SUBTYPE_POWERPC_604e:  puts ("powerpc604e"); break;
+      case CPU_SUBTYPE_POWERPC_620:   puts ("powerpc620");  break;
+      case CPU_SUBTYPE_POWERPC_750:   puts ("powerpc750");  break;
+      case CPU_SUBTYPE_POWERPC_7400:  puts ("powerpc7400"); break;
+      case CPU_SUBTYPE_POWERPC_7450:  puts ("powerpc7450"); break;
+      /* Darwin 6.8.5 doesn't define the following */
+      case 0x8001:                    puts ("powerpc7455"); break;
+      case 0x8002:                    puts ("powerpc7457"); break;
+      case 0x8003:                    puts ("powerpc7447"); break;
+      case 100:                       puts ("powerpc970");  break;
+      }
+    }
+  return 0;
+}
+EOF
+    if ($CC_FOR_BUILD $dummy.c -o $dummy) >/dev/null 2>&1; then
+      x=`$dummy`
+      if test -n "$x"; then
+        exact_cpu=$x
+      fi
+    fi
+  fi
+  ;;
+
+sparc-*-* | sparc64-*-*)
+  # If we can recognise an actual v7 then $exact_cpu is set to "sparc" so as
+  # to short-circuit subsequent tests.
+
+  # Grep the linux kernel /proc/cpuinfo pseudo-file.
+  # A typical line is "cpu\t\t: TI UltraSparc II  (BlackBird)"
+  # See arch/sparc/kernel/cpu.c and arch/sparc64/kernel/cpu.c.
+  #
+  if test -f /proc/cpuinfo; then
+    if grep 'cpu.*Cypress' /proc/cpuinfo >/dev/null; then
+      exact_cpu="sparc"   # ie. v7
+    elif grep 'cpu.*Power-UP' /proc/cpuinfo >/dev/null; then
+      exact_cpu="sparc"   # ie. v7
+    elif grep 'cpu.*HyperSparc' /proc/cpuinfo >/dev/null; then
+      exact_cpu="sparcv8"
+    elif grep 'cpu.*SuperSparc' /proc/cpuinfo >/dev/null; then
+      exact_cpu="supersparc"
+    elif grep 'cpu.*MicroSparc' /proc/cpuinfo >/dev/null; then
+      exact_cpu="microsparc"
+    elif grep 'cpu.*MB86904' /proc/cpuinfo >/dev/null; then
+      # actually MicroSPARC-II
+      exact_cpu=microsparc
+    elif grep 'cpu.*UltraSparc T5' /proc/cpuinfo >/dev/null; then
+      exact_cpu="ultrasparct5"
+    elif grep 'cpu.*UltraSparc T4' /proc/cpuinfo >/dev/null; then
+      exact_cpu="ultrasparct4"
+    elif grep 'cpu.*UltraSparc T3' /proc/cpuinfo >/dev/null; then
+      exact_cpu="ultrasparct3"
+    elif grep 'cpu.*UltraSparc T2' /proc/cpuinfo >/dev/null; then
+      exact_cpu="ultrasparct2"
+    elif grep 'cpu.*UltraSparc T1' /proc/cpuinfo >/dev/null; then
+      exact_cpu="ultrasparct1"
+    elif grep 'cpu.*UltraSparc III' /proc/cpuinfo >/dev/null; then
+      exact_cpu="ultrasparc3"
+    elif grep 'cpu.*UltraSparc IIi' /proc/cpuinfo >/dev/null; then
+      exact_cpu="ultrasparc2i"
+    elif grep 'cpu.*UltraSparc II' /proc/cpuinfo >/dev/null; then
+      exact_cpu="ultrasparc2"
+    elif grep 'cpu.*UltraSparc' /proc/cpuinfo >/dev/null; then
+      exact_cpu="ultrasparc"
+    fi
+  fi
+
+  # Need to invoke this for setup of $dummy
+  eval $set_cc_for_build
+
+  # Grep the output from sysinfo on SunOS.
+  # sysinfo has been seen living in /bin or in /usr/kvm
+  #	cpu0 is a "SuperSPARC Model 41 SPARCmodule" CPU
+  #	cpu0 is a "75 MHz TI,TMS390Z55" CPU
+  #
+  if test -z "$exact_cpu"; then
+    for i in sysinfo /usr/kvm/sysinfo; do
+      if $SHELL -c $i 2>/dev/null >$dummy; then
+        if grep 'cpu0 is a "SuperSPARC' $dummy >/dev/null; then
+          exact_cpu=supersparc
+          break
+        elif grep 'cpu0 is a .*TMS390Z5.' $dummy >/dev/null; then
+          # TMS390Z50 and TMS390Z55
+          exact_cpu=supersparc
+          break
+        fi
+      fi
+    done
+  fi
+
+  # Grep the output from prtconf on Solaris.
+  # Use an explicit /usr/sbin, since that directory might not be in a normal
+  # user's path.
+  #
+  #     SUNW,UltraSPARC (driver not attached)
+  #     SUNW,UltraSPARC-II (driver not attached)
+  #     SUNW,UltraSPARC-IIi (driver not attached)
+  #     SUNW,UltraSPARC-III+ (driver not attached)
+  #     Ross,RT625 (driver not attached)
+  #     TI,TMS390Z50 (driver not attached)
+  #
+  # /usr/sbin/sysdef prints similar information, but includes all loadable
+  # cpu modules, not just the real cpu.
+  #
+  # We first try a plain prtconf, since that is known to work on older systems.
+  # But for newer T1 systems, that doesn't produce any useful output, we need
+  # "prtconf -vp" there.
+  #
+  for prtconfopt in "" "-vp"; do
+    if test -z "$exact_cpu"; then
+      if $SHELL -c "/usr/sbin/prtconf $prtconfopt" 2>/dev/null >$dummy; then
+	if grep 'SUNW,UltraSPARC-T5' $dummy >/dev/null; then
+	  exact_cpu=ultrasparct5
+	elif grep 'SUNW,UltraSPARC-T4' $dummy >/dev/null; then
+	  exact_cpu=ultrasparct4
+	elif grep 'SUNW,UltraSPARC-T3' $dummy >/dev/null; then
+	  exact_cpu=ultrasparct3
+	elif grep 'SUNW,UltraSPARC-T2' $dummy >/dev/null; then
+	  exact_cpu=ultrasparct2
+	elif grep 'SUNW,UltraSPARC-T1' $dummy >/dev/null; then
+	  exact_cpu=ultrasparct1
+	elif grep 'SUNW,UltraSPARC-III' $dummy >/dev/null; then
+	  exact_cpu=ultrasparc3
+	elif grep 'SUNW,UltraSPARC-IIi' $dummy >/dev/null; then
+	  exact_cpu=ultrasparc2i
+	elif grep 'SUNW,UltraSPARC-II' $dummy >/dev/null; then
+	  exact_cpu=ultrasparc2
+	elif grep 'SUNW,UltraSPARC' $dummy >/dev/null; then
+	  exact_cpu=ultrasparc
+	elif grep 'Ross,RT62.' $dummy >/dev/null; then
+	  # RT620, RT625, RT626 hypersparcs (v8).
+	  exact_cpu=sparcv8
+	elif grep 'TI,TMS390Z5.' $dummy >/dev/null; then
+	  # TMS390Z50 and TMS390Z55
+	  exact_cpu=supersparc
+	elif grep 'TI,TMS390S10' $dummy >/dev/null; then
+	  exact_cpu=microsparc
+	elif grep 'FMI,MB86904' $dummy >/dev/null; then
+	  # actually MicroSPARC-II
+	  exact_cpu=microsparc
+	fi
+      fi
+    fi
+  done
+
+  # Grep the output from sysctl hw.model on sparc or sparc64 *BSD.
+  # Use an explicit /sbin, since that directory might not be in a normal
+  # user's path.  Example outputs,
+  #
+  #     hw.model: Sun Microsystems UltraSparc-IIi
+  #
+  if test -z "$exact_cpu"; then
+    if $SHELL -c "/sbin/sysctl hw.model" 2>/dev/null >$dummy; then
+      if grep -i 'UltraSparc-T5' $dummy >/dev/null; then
+        exact_cpu=ultrasparct5
+      elif grep -i 'UltraSparc-T4' $dummy >/dev/null; then
+        exact_cpu=ultrasparct4
+      elif grep -i 'UltraSparc-T3' $dummy >/dev/null; then
+        exact_cpu=ultrasparct3
+      elif grep -i 'UltraSparc-T2' $dummy >/dev/null; then
+        exact_cpu=ultrasparct2
+      elif grep -i 'UltraSparc-T1' $dummy >/dev/null; then
+        exact_cpu=ultrasparct1
+      elif grep -i 'UltraSparc-III' $dummy >/dev/null; then
+        exact_cpu=ultrasparc3
+      elif grep -i 'UltraSparc-IIi' $dummy >/dev/null; then
+        exact_cpu=ultrasparc2i
+      elif grep -i 'UltraSparc-II' $dummy >/dev/null; then
+        exact_cpu=ultrasparc2
+      elif grep -i 'UltraSparc' $dummy >/dev/null; then
+        exact_cpu=ultrasparc
+      elif grep 'TMS390Z5.' $dummy >/dev/null; then
+        # TMS390Z50 and TMS390Z55
+        exact_cpu=supersparc
+      elif grep 'TMS390S10' $dummy >/dev/null; then
+        exact_cpu=microsparc
+      elif grep 'MB86904' $dummy >/dev/null; then
+        # actually MicroSPARC-II
+        exact_cpu=microsparc
+      elif grep 'MB86907' $dummy >/dev/null; then
+        exact_cpu=turbosparc
+      fi
+    fi
+  fi
+
+  # sun4m and sun4d are v8s of some sort, sun4u is a v9 of some sort
+  #
+  if test -z "$exact_cpu"; then
+    case `uname -m` in
+      sun4[md]) exact_cpu=sparcv8 ;;
+      sun4u)    exact_cpu=sparcv9 ;;
+    esac
+  fi
+  ;;
+
+
+# Recognise x86 processors using a tricky cpuid with 4 arguments, repeating
+# arguments; for x86-64 we effectively pass the 1st in rdx and the 2nd in rcx.
+# This allows the same asm to work for both standard and Windoze calling
+# conventions.
+
+i?86-*-* | amd64-*-* | x86_64-*-*)
+  eval $set_cc_for_build
+
+  cat <<EOF >$dummy.c
+#include <string.h>
+#include <stdio.h>
+#define CPUID(a,b) cpuid(b,a,a,b)
+#if __cplusplus
+extern "C"
+#endif
+unsigned int cpuid (int, char *, char *, int);
+
+int
+gmp_workaround_skylake_cpuid_bug ()
+{
+  char feature_string[49];
+  char processor_name_string[49];
+  static const char *bad_cpus[] = {" G44", " G45", " G39" /* , "6600" */ };
+  int i;
+
+  /* Example strings:                                   */
+  /* "Intel(R) Pentium(R) CPU G4400 @ 3.30GHz"          */
+  /* "Intel(R) Core(TM) i5-6600K CPU @ 3.50GHz"         */
+  /*                  ^               ^               ^ */
+  /*     0x80000002       0x80000003      0x80000004    */
+  /* We match out just the 0x80000003 part here. */
+
+  /* In their infinitive wisdom, Intel decided to use one register order for
+     the vendor string, and another for the processor name string.  We shuffle
+     things about here, rather than write a new variant of our assembly cpuid.
+  */
+
+  unsigned int eax, ebx, ecx, edx;
+  eax = CPUID (feature_string, 0x80000003);
+  ebx = ((unsigned int *)feature_string)[0];
+  edx = ((unsigned int *)feature_string)[1];
+  ecx = ((unsigned int *)feature_string)[2];
+
+  ((unsigned int *) (processor_name_string))[0] = eax;
+  ((unsigned int *) (processor_name_string))[1] = ebx;
+  ((unsigned int *) (processor_name_string))[2] = ecx;
+  ((unsigned int *) (processor_name_string))[3] = edx;
+
+  processor_name_string[16] = 0;
+
+  for (i = 0; i < sizeof (bad_cpus) / sizeof (char *); i++)
+    {
+      if (strstr (processor_name_string, bad_cpus[i]) != 0)
+	return 1;
+    }
+  return 0;
+}
+
+int
+main ()
+{
+  char vendor_string[13];
+  char feature_string[12];
+  long fms;
+  int family, model;
+  const char *modelstr, *suffix;
+  int cpu_64bit = 0, cpu_avx = 0;
+  int cpuid_64bit, cpuid_avx, cpuid_osxsave;
+
+  CPUID (vendor_string, 0);
+  vendor_string[12] = 0;
+
+  fms = CPUID (feature_string, 1);
+
+  family = ((fms >> 8) & 0xf) + ((fms >> 20) & 0xff);
+  model = ((fms >> 4) & 0xf) + ((fms >> 12) & 0xf0);
+
+  cpuid_avx     = (feature_string[11] >> 4) & 1;
+  cpuid_osxsave = (feature_string[11] >> 3) & 1;
+
+  modelstr = "$guess_cpu";
+
+  /**************************************************/
+  /*** WARNING: keep this list in sync with fat.c ***/
+  /**************************************************/
+  if (strcmp (vendor_string, "GenuineIntel") == 0)
+    {
+      switch (family)
+	{
+	case 5:
+          if (model == 4 || model == 8)               modelstr = "pentiummmx";
+	  else                                        modelstr = "pentium";
+	  break;
+	case 6:
+          if (model <= 1)                                   modelstr = "pentiumpro";
+          else if (model <= 6)                              modelstr = "pentium2";
+          else if (model <= 8)                              modelstr = "pentium3";
+          else if (model <= 9)                              modelstr = "pentiumm";
+          else if (model <= 0x0c)                           modelstr = "pentium3";
+          else if (model <= 0x0e)                           modelstr = "pentiumm";
+          else if (model <= 0x19) cpu_64bit = 1,            modelstr = "core2";
+          else if (model == 0x1a) cpu_64bit = 1,            modelstr = "nehalem";    /* NHM Gainestown */
+          else if (model == 0x1c) cpu_64bit = 1,            modelstr = "atom";       /* Silverthorne */
+          else if (model == 0x1d) cpu_64bit = 1,            modelstr = "core2";      /* PNR Dunnington */
+          else if (model == 0x1e) cpu_64bit = 1,            modelstr = "nehalem";    /* NHM Lynnfield/Jasper */
+          else if (model == 0x25) cpu_64bit = 1,            modelstr = "westmere";   /* WSM Clarkdale/Arrandale */
+          else if (model == 0x26) cpu_64bit = 1,            modelstr = "atom";       /* Lincroft */
+          else if (model == 0x27) cpu_64bit = 1,            modelstr = "atom";       /* Saltwell */
+          else if (model == 0x2a) cpu_64bit = 1, cpu_avx=1, modelstr = "sandybridge";/* SB */
+          else if (model == 0x2c) cpu_64bit = 1,            modelstr = "westmere";   /* WSM Gulftown */
+          else if (model == 0x2d) cpu_64bit = 1, cpu_avx=1, modelstr = "sandybridge";/* SBC-EP */
+          else if (model == 0x2e) cpu_64bit = 1,            modelstr = "nehalem";    /* NHM Beckton */
+          else if (model == 0x2f) cpu_64bit = 1,            modelstr = "westmere";   /* WSM Eagleton */
+          else if (model == 0x36) cpu_64bit = 1,            modelstr = "atom";       /* Cedarview/Saltwell */
+          else if (model == 0x37) cpu_64bit = 1,            modelstr = "silvermont"; /* Silvermont */
+          else if (model == 0x3a) cpu_64bit = 1, cpu_avx=1, modelstr = "ivybridge";  /* IBR */
+          else if (model == 0x3c) cpu_64bit = 1, cpu_avx=1, modelstr = "haswell";    /* Haswell client */
+          else if (model == 0x3d) cpu_64bit = 1, cpu_avx=1, modelstr = "broadwell";  /* Broadwell */
+          else if (model == 0x3e) cpu_64bit = 1, cpu_avx=1, modelstr = "ivybridge";  /* Ivytown */
+          else if (model == 0x3f) cpu_64bit = 1, cpu_avx=1, modelstr = "haswell";    /* Haswell server */
+          else if (model == 0x45) cpu_64bit = 1, cpu_avx=1, modelstr = "haswell";    /* Haswell ULT */
+          else if (model == 0x46) cpu_64bit = 1, cpu_avx=1, modelstr = "haswell";    /* Crystal Well */
+          else if (model == 0x47) cpu_64bit = 1, cpu_avx=1, modelstr = "broadwell";  /* Broadwell */
+          else if (model == 0x4a) cpu_64bit = 1,            modelstr = "silvermont"; /* Silvermont */
+          else if (model == 0x4c) cpu_64bit = 1,            modelstr = "silvermont"; /* Airmont */
+          else if (model == 0x4d) cpu_64bit = 1,            modelstr = "silvermont"; /* Silvermont/Avoton */
+          else if (model == 0x4e) cpu_64bit = 1, cpu_avx=1, modelstr = "skylake";    /* Skylake client */
+          else if (model == 0x4f) cpu_64bit = 1, cpu_avx=1, modelstr = "broadwell";  /* Broadwell server */
+          else if (model == 0x55) cpu_64bit = 1, cpu_avx=1, modelstr = "skylake";    /* Skylake server */
+          else if (model == 0x56) cpu_64bit = 1, cpu_avx=1, modelstr = "broadwell";  /* Broadwell microserver */
+          else if (model == 0x57) cpu_64bit = 1,            modelstr = "knightslanding"; /* aka Xeon Phi */
+          else if (model == 0x5a) cpu_64bit = 1,            modelstr = "silvermont"; /* Silvermont */
+          else if (model == 0x5c) cpu_64bit = 1,            modelstr = "goldmont";   /* Goldmont */
+          else if (model == 0x5e) cpu_64bit = 1, cpu_avx=1, modelstr = "skylake";    /* Skylake */
+          else if (model == 0x5f) cpu_64bit = 1,            modelstr = "goldmont";   /* Goldmont */
+          else if (model == 0x7a) cpu_64bit = 1,            modelstr = "goldmont";   /* Goldmont Plus */
+          else if (model == 0x8e) cpu_64bit = 1, cpu_avx=1, modelstr = "kabylake";   /* Kabylake Y/U */
+          else if (model == 0x9e) cpu_64bit = 1, cpu_avx=1, modelstr = "kabylake";   /* Kabylake desktop */
+          else                    cpu_64bit = 1,            modelstr = "nehalem";    /* default */
+
+	  if (strcmp (modelstr, "haswell") == 0 ||
+	      strcmp (modelstr, "broadwell") == 0 ||
+	      strcmp (modelstr, "skylake") == 0)
+	    {
+	      /* Some haswell, broadwell, skylake lack BMI2.  Let them appear
+		 as sandybridge for now.  */
+	      CPUID (feature_string, 7);
+	      if ((feature_string[0 + 8 / 8] & (1 << (8 % 8))) == 0
+		  || gmp_workaround_skylake_cpuid_bug ())
+		modelstr = "sandybridge";
+	    }
+
+	  break;
+	case 15:
+	  cpu_64bit = 1, modelstr = "pentium4";
+	  break;
+	}
+    }
+  else if (strcmp (vendor_string, "AuthenticAMD") == 0)
+    {
+      switch (family)
+	{
+	case 5:
+	  if (model <= 3)	modelstr = "k5";
+	  else if (model <= 7)	modelstr = "k6";
+	  else if (model == 8)	modelstr = "k62";
+	  else if (model == 9)	modelstr = "k63";
+	  else if (model == 10) modelstr = "geode";
+	  else if (model == 13) modelstr = "k63";
+	  break;
+	case 6:
+	  modelstr = "athlon";
+	  break;
+	case 15:		/* K8, K9 */
+	  cpu_64bit = 1, modelstr = "k8";
+	  break;
+	case 16:		/* K10 */
+	  cpu_64bit = 1, modelstr = "k10";
+	  break;
+	case 17:		/* Hybrid k8/k10, claim k8 */
+	  cpu_64bit = 1, modelstr = "k8";
+	  break;
+	case 18:		/* Llano, uses K10 core */
+	  cpu_64bit = 1, modelstr = "k10";
+	  break;
+	case 19:		/* AMD Internal, assume future K10 */
+	  cpu_64bit = 1, modelstr = "k10";
+	  break;
+	case 20:		/* Bobcat */
+	  cpu_64bit = 1, modelstr = "bobcat";
+	  break;
+	case 21:		/* Bulldozer */
+	  cpu_64bit = 1, cpu_avx = 1;
+	  if (model <= 1)
+	    modelstr = "bulldozer";
+	  else if (model < 0x20)	/* really 2, [0x10-0x20) */
+	    modelstr = "piledriver";
+	  else if (model < 0x40)	/* really [0x30-0x40) */
+	    modelstr = "steamroller";
+	  else				/* really [0x60-0x70) */
+	    modelstr = "excavator";
+	  break;
+	case 22:		/* Jaguar, an improved bobcat */
+	  cpu_64bit = 1, cpu_avx = 1, modelstr = "jaguar";
+	  break;
+	case 23:		/* Zen */
+	  cpu_64bit = 1, cpu_avx = 1;
+	  switch (model)
+	    {
+	    case 1:
+	    case 8:
+	    case 17:
+	    case 24:
+	      modelstr = "zen";
+	      break;
+	    default:
+	      modelstr = "zen2";
+	      break;
+	  }
+	}
+    }
+  else if (strcmp (vendor_string, "CyrixInstead") == 0)
+    {
+      /* Should recognize Cyrix' processors too.  */
+    }
+  else if (strcmp (vendor_string, "CentaurHauls") == 0)
+    {
+      switch (family)
+	{
+	case 6:
+	  if (model < 9)	modelstr = "viac3";
+	  else if (model < 15)	modelstr = "viac32";
+	  else			cpu_64bit = 1, modelstr = "nano";
+	  break;
+	}
+    }
+
+  CPUID (feature_string, 0x80000001);
+  cpuid_64bit = (feature_string[7] >> 5) & 1;
+
+  suffix = "";
+
+  if (cpuid_64bit && ! cpu_64bit)
+    /* If our cpuid-based CPU identification thinks this is a 32-bit CPU but
+       cpuid claims AMD64 capabilities, then revert to the generic "x86_64".
+       This is of course wrong, but it can happen in some virtualisers and
+       emulators, and this workaround allows for successful 64-bit builds.  */
+    modelstr = "x86_64";
+  else if (cpu_avx && ! (cpuid_avx && cpuid_osxsave))
+    /* For CPUs nominally capable of executing AVX, append "noavx" when not
+       both the AVX and OSXSAVE cpuid bits are set.  We tolerate weirdness
+       here, as some virtualisers set a broken cpuid state, while other
+       virtualisers allow guests to set a broken state.  */
+    suffix = "noavx";
+
+  printf ("%s%s", modelstr, suffix);
+  return 0;
+}
+EOF
+
+# The rcx/ecx zeroing here and in the variant below is needed for the BMI2
+# check.
+
+  cat <<EOF >${dummy}0.s
+	.globl cpuid
+	.globl _cpuid
+cpuid:
+_cpuid:
+	push	%rbx
+	mov	%rdx, %r8
+	mov	%ecx, %eax
+	xor	%ecx, %ecx
+	.byte	0x0f
+	.byte	0xa2
+	mov	%ebx, (%r8)
+	mov	%edx, 4(%r8)
+	mov	%ecx, 8(%r8)
+	pop	%rbx
+	ret
+EOF
+
+  if ($CC_FOR_BUILD ${dummy}0.s $dummy.c -o $dummy) >/dev/null 2>&1; then
+    # On 80386 and early 80486 cpuid is not available and will result in a
+    # SIGILL message, hence 2>/dev/null.
+    #
+    # On i386-unknown-freebsd4.9, "/bin/sh -c ./dummy" seems to send an
+    # "Illegal instruction (core dumped)" message to stdout, so we test $?
+    # to check if the program run was successful.
+    #
+    x=`$SHELL -c $dummy 2>/dev/null`
+    if test $? = 0 && test -n "$x"; then
+      exact_cpu=$x
+    fi
+  fi
+
+  cat <<EOF >${dummy}0.s
+	.globl cpuid
+	.globl _cpuid
+cpuid:
+_cpuid:
+	pushl %esi
+	pushl %ebx
+	movl 24(%esp),%eax
+	xor	%ecx, %ecx
+	.byte 0x0f
+	.byte 0xa2
+	movl 20(%esp),%esi
+	movl %ebx,(%esi)
+	movl %edx,4(%esi)
+	movl %ecx,8(%esi)
+	popl %ebx
+	popl %esi
+	ret
+EOF
+
+  if test -z "$exact_cpu"; then
+  if ($CC_FOR_BUILD ${dummy}0.s $dummy.c -o $dummy) >/dev/null 2>&1; then
+    # On 80386 and early 80486 cpuid is not available and will result in a
+    # SIGILL message, hence 2>/dev/null.
+    #
+    # On i386-unknown-freebsd4.9, "/bin/sh -c ./dummy" seems to send an
+    # "Illegal instruction (core dumped)" message to stdout, so we test $?
+    # to check if the program run was successful.
+    #
+    x=`$SHELL -c $dummy 2>/dev/null`
+    if test $? = 0 && test -n "$x"; then
+      exact_cpu=$x
+    fi
+  fi
+  fi
+
+  # We need to remove some .o files here since lame C compilers
+  # generate these even when not asked.
+  ;;
+
+s390*-*-*)
+  if test -f /proc/cpuinfo; then
+    model=`grep "^processor 0: version =" /proc/cpuinfo | sed -e 's/.*machine = //'`
+    case $model in
+      2064 | 2066) zcpu="z900" ;;
+      2084 | 2086) zcpu="z990" ;;
+      2094 | 2096) zcpu="z9"   ;;
+      2097 | 2098) zcpu="z10"  ;;
+      2817 | 2818 | *) zcpu="z196" ;;
+    esac
+    case "$guess_full" in
+      s390x-*-*) exact_cpu=${zcpu}    ;;
+      s390-*-*)  exact_cpu=${zcpu}esa ;;
+    esac
+  fi
+  ;;
+
+esac
+
+
+
+# -------------------------------------------------------------------------
+# Use an exact cpu, if possible
+
+if test -n "$exact_cpu"; then
+  echo "$exact_cpu$guess_rest"
+else
+  echo "$guess_full"
+fi
+exit 0
+
+
+
+# Local variables:
+# fill-column: 76
+# End:
diff --git a/third_party/gmp/config.in b/third_party/gmp/config.in
new file mode 100644
index 0000000..13bf6f8
--- /dev/null
+++ b/third_party/gmp/config.in
@@ -0,0 +1,667 @@
+/* config.in.  Generated from configure.ac by autoheader.  */
+
+/*
+
+Copyright 1996-2020 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.
+*/
+
+/* Define if building universal (internal helper macro) */
+#undef AC_APPLE_UNIVERSAL_BUILD
+
+/* The gmp-mparam.h file (a string) the tune program should suggest updating.
+   */
+#undef GMP_MPARAM_H_SUGGEST
+
+/* Define to 1 if you have the `alarm' function. */
+#undef HAVE_ALARM
+
+/* Define to 1 if alloca() works (via gmp-impl.h). */
+#undef HAVE_ALLOCA
+
+/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix).
+   */
+#undef HAVE_ALLOCA_H
+
+/* Define to 1 if the compiler accepts gcc style __attribute__ ((const)) */
+#undef HAVE_ATTRIBUTE_CONST
+
+/* Define to 1 if the compiler accepts gcc style __attribute__ ((malloc)) */
+#undef HAVE_ATTRIBUTE_MALLOC
+
+/* Define to 1 if the compiler accepts gcc style __attribute__ ((mode (XX)))
+   */
+#undef HAVE_ATTRIBUTE_MODE
+
+/* Define to 1 if the compiler accepts gcc style __attribute__ ((noreturn)) */
+#undef HAVE_ATTRIBUTE_NORETURN
+
+/* Define to 1 if you have the `attr_get' function. */
+#undef HAVE_ATTR_GET
+
+/* Define to 1 if tests/libtests has calling conventions checking for the CPU
+   */
+#undef HAVE_CALLING_CONVENTIONS
+
+/* Define to 1 if you have the `clock' function. */
+#undef HAVE_CLOCK
+
+/* Define to 1 if you have the `clock_gettime' function */
+#undef HAVE_CLOCK_GETTIME
+
+/* Define to 1 if you have the `cputime' function. */
+#undef HAVE_CPUTIME
+
+/* Define to 1 if you have the declaration of `fgetc', and to 0 if you don't.
+   */
+#undef HAVE_DECL_FGETC
+
+/* Define to 1 if you have the declaration of `fscanf', and to 0 if you don't.
+   */
+#undef HAVE_DECL_FSCANF
+
+/* Define to 1 if you have the declaration of `optarg', and to 0 if you don't.
+   */
+#undef HAVE_DECL_OPTARG
+
+/* Define to 1 if you have the declaration of `sys_errlist', and to 0 if you
+   don't. */
+#undef HAVE_DECL_SYS_ERRLIST
+
+/* Define to 1 if you have the declaration of `sys_nerr', and to 0 if you
+   don't. */
+#undef HAVE_DECL_SYS_NERR
+
+/* Define to 1 if you have the declaration of `ungetc', and to 0 if you don't.
+   */
+#undef HAVE_DECL_UNGETC
+
+/* Define to 1 if you have the declaration of `vfprintf', and to 0 if you
+   don't. */
+#undef HAVE_DECL_VFPRINTF
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define one of the following to 1 for the format of a `double'.
+   If your format is not among these choices, or you don't know what it is,
+   then leave all undefined.
+   IEEE_LITTLE_SWAPPED means little endian, but with the two 4-byte halves
+   swapped, as used by ARM CPUs in little endian mode.  */
+#undef HAVE_DOUBLE_IEEE_BIG_ENDIAN
+#undef HAVE_DOUBLE_IEEE_LITTLE_ENDIAN
+#undef HAVE_DOUBLE_IEEE_LITTLE_SWAPPED
+#undef HAVE_DOUBLE_VAX_D
+#undef HAVE_DOUBLE_VAX_G
+#undef HAVE_DOUBLE_CRAY_CFP
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#undef HAVE_FCNTL_H
+
+/* Define to 1 if you have the <float.h> header file. */
+#undef HAVE_FLOAT_H
+
+/* Define to 1 if you have the `getpagesize' function. */
+#undef HAVE_GETPAGESIZE
+
+/* Define to 1 if you have the `getrusage' function. */
+#undef HAVE_GETRUSAGE
+
+/* Define to 1 if you have the `getsysinfo' function. */
+#undef HAVE_GETSYSINFO
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#undef HAVE_GETTIMEOFDAY
+
+/* Define to 1 if the compiler accepts gcc style __attribute__ ((visibility))
+   and __attribute__ ((alias)) */
+#undef HAVE_HIDDEN_ALIAS
+
+/* Define one of these to 1 for the host CPU family.
+   If your CPU is not in any of these families, leave all undefined.
+   For an AMD64 chip, define "x86" in ABI=32, but not in ABI=64. */
+#undef HAVE_HOST_CPU_FAMILY_alpha
+#undef HAVE_HOST_CPU_FAMILY_m68k
+#undef HAVE_HOST_CPU_FAMILY_power
+#undef HAVE_HOST_CPU_FAMILY_powerpc
+#undef HAVE_HOST_CPU_FAMILY_x86
+#undef HAVE_HOST_CPU_FAMILY_x86_64
+
+/* Define one of the following to 1 for the host CPU, as per the output of
+   ./config.guess.  If your CPU is not listed here, leave all undefined.  */
+#undef HAVE_HOST_CPU_alphaev67
+#undef HAVE_HOST_CPU_alphaev68
+#undef HAVE_HOST_CPU_alphaev7
+#undef HAVE_HOST_CPU_m68020
+#undef HAVE_HOST_CPU_m68030
+#undef HAVE_HOST_CPU_m68040
+#undef HAVE_HOST_CPU_m68060
+#undef HAVE_HOST_CPU_m68360
+#undef HAVE_HOST_CPU_powerpc604
+#undef HAVE_HOST_CPU_powerpc604e
+#undef HAVE_HOST_CPU_powerpc750
+#undef HAVE_HOST_CPU_powerpc7400
+#undef HAVE_HOST_CPU_supersparc
+#undef HAVE_HOST_CPU_i386
+#undef HAVE_HOST_CPU_i586
+#undef HAVE_HOST_CPU_i686
+#undef HAVE_HOST_CPU_pentium
+#undef HAVE_HOST_CPU_pentiummmx
+#undef HAVE_HOST_CPU_pentiumpro
+#undef HAVE_HOST_CPU_pentium2
+#undef HAVE_HOST_CPU_pentium3
+#undef HAVE_HOST_CPU_pentium4
+#undef HAVE_HOST_CPU_core2
+#undef HAVE_HOST_CPU_nehalem
+#undef HAVE_HOST_CPU_westmere
+#undef HAVE_HOST_CPU_sandybridge
+#undef HAVE_HOST_CPU_ivybridge
+#undef HAVE_HOST_CPU_haswell
+#undef HAVE_HOST_CPU_broadwell
+#undef HAVE_HOST_CPU_skylake
+#undef HAVE_HOST_CPU_silvermont
+#undef HAVE_HOST_CPU_goldmont
+#undef HAVE_HOST_CPU_k8
+#undef HAVE_HOST_CPU_k10
+#undef HAVE_HOST_CPU_bulldozer
+#undef HAVE_HOST_CPU_piledriver
+#undef HAVE_HOST_CPU_steamroller
+#undef HAVE_HOST_CPU_excavator
+#undef HAVE_HOST_CPU_zen
+#undef HAVE_HOST_CPU_bobcat
+#undef HAVE_HOST_CPU_jaguar
+#undef HAVE_HOST_CPU_s390_z900
+#undef HAVE_HOST_CPU_s390_z990
+#undef HAVE_HOST_CPU_s390_z9
+#undef HAVE_HOST_CPU_s390_z10
+#undef HAVE_HOST_CPU_s390_z196
+
+/* Define to 1 iff we have a s390 with 64-bit registers.  */
+#undef HAVE_HOST_CPU_s390_zarch
+
+/* Define to 1 if the system has the type `intmax_t'. */
+#undef HAVE_INTMAX_T
+
+/* Define to 1 if the system has the type `intptr_t'. */
+#undef HAVE_INTPTR_T
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the <invent.h> header file. */
+#undef HAVE_INVENT_H
+
+/* Define to 1 if you have the <langinfo.h> header file. */
+#undef HAVE_LANGINFO_H
+
+/* Define one of these to 1 for the endianness of `mp_limb_t'.
+   If the endianness is not a simple big or little, or you don't know what
+   it is, then leave both undefined. */
+#undef HAVE_LIMB_BIG_ENDIAN
+#undef HAVE_LIMB_LITTLE_ENDIAN
+
+/* Define to 1 if you have the `localeconv' function. */
+#undef HAVE_LOCALECONV
+
+/* Define to 1 if you have the <locale.h> header file. */
+#undef HAVE_LOCALE_H
+
+/* Define to 1 if the system has the type `long double'. */
+#undef HAVE_LONG_DOUBLE
+
+/* Define to 1 if the system has the type `long long'. */
+#undef HAVE_LONG_LONG
+
+/* Define to 1 if you have the <machine/hal_sysinfo.h> header file. */
+#undef HAVE_MACHINE_HAL_SYSINFO_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the `memset' function. */
+#undef HAVE_MEMSET
+
+/* Define to 1 if you have the `mmap' function. */
+#undef HAVE_MMAP
+
+/* Define to 1 if you have the `mprotect' function. */
+#undef HAVE_MPROTECT
+
+/* Define to 1 each of the following for which a native (ie. CPU specific)
+    implementation of the corresponding routine exists.  */
+#undef HAVE_NATIVE_mpn_add_n
+#undef HAVE_NATIVE_mpn_add_n_sub_n
+#undef HAVE_NATIVE_mpn_add_nc
+#undef HAVE_NATIVE_mpn_addaddmul_1msb0
+#undef HAVE_NATIVE_mpn_addlsh1_n
+#undef HAVE_NATIVE_mpn_addlsh2_n
+#undef HAVE_NATIVE_mpn_addlsh_n
+#undef HAVE_NATIVE_mpn_addlsh1_nc
+#undef HAVE_NATIVE_mpn_addlsh2_nc
+#undef HAVE_NATIVE_mpn_addlsh_nc
+#undef HAVE_NATIVE_mpn_addlsh1_n_ip1
+#undef HAVE_NATIVE_mpn_addlsh2_n_ip1
+#undef HAVE_NATIVE_mpn_addlsh_n_ip1
+#undef HAVE_NATIVE_mpn_addlsh1_nc_ip1
+#undef HAVE_NATIVE_mpn_addlsh2_nc_ip1
+#undef HAVE_NATIVE_mpn_addlsh_nc_ip1
+#undef HAVE_NATIVE_mpn_addlsh1_n_ip2
+#undef HAVE_NATIVE_mpn_addlsh2_n_ip2
+#undef HAVE_NATIVE_mpn_addlsh_n_ip2
+#undef HAVE_NATIVE_mpn_addlsh1_nc_ip2
+#undef HAVE_NATIVE_mpn_addlsh2_nc_ip2
+#undef HAVE_NATIVE_mpn_addlsh_nc_ip2
+#undef HAVE_NATIVE_mpn_addmul_1c
+#undef HAVE_NATIVE_mpn_addmul_2
+#undef HAVE_NATIVE_mpn_addmul_3
+#undef HAVE_NATIVE_mpn_addmul_4
+#undef HAVE_NATIVE_mpn_addmul_5
+#undef HAVE_NATIVE_mpn_addmul_6
+#undef HAVE_NATIVE_mpn_addmul_7
+#undef HAVE_NATIVE_mpn_addmul_8
+#undef HAVE_NATIVE_mpn_addmul_2s
+#undef HAVE_NATIVE_mpn_and_n
+#undef HAVE_NATIVE_mpn_andn_n
+#undef HAVE_NATIVE_mpn_bdiv_dbm1c
+#undef HAVE_NATIVE_mpn_bdiv_q_1
+#undef HAVE_NATIVE_mpn_pi1_bdiv_q_1
+#undef HAVE_NATIVE_mpn_cnd_add_n
+#undef HAVE_NATIVE_mpn_cnd_sub_n
+#undef HAVE_NATIVE_mpn_com
+#undef HAVE_NATIVE_mpn_copyd
+#undef HAVE_NATIVE_mpn_copyi
+#undef HAVE_NATIVE_mpn_div_qr_1n_pi1
+#undef HAVE_NATIVE_mpn_div_qr_2
+#undef HAVE_NATIVE_mpn_divexact_1
+#undef HAVE_NATIVE_mpn_divexact_by3c
+#undef HAVE_NATIVE_mpn_divrem_1
+#undef HAVE_NATIVE_mpn_divrem_1c
+#undef HAVE_NATIVE_mpn_divrem_2
+#undef HAVE_NATIVE_mpn_gcd_1
+#undef HAVE_NATIVE_mpn_gcd_11
+#undef HAVE_NATIVE_mpn_gcd_22
+#undef HAVE_NATIVE_mpn_hamdist
+#undef HAVE_NATIVE_mpn_invert_limb
+#undef HAVE_NATIVE_mpn_ior_n
+#undef HAVE_NATIVE_mpn_iorn_n
+#undef HAVE_NATIVE_mpn_lshift
+#undef HAVE_NATIVE_mpn_lshiftc
+#undef HAVE_NATIVE_mpn_lshsub_n
+#undef HAVE_NATIVE_mpn_mod_1
+#undef HAVE_NATIVE_mpn_mod_1_1p
+#undef HAVE_NATIVE_mpn_mod_1c
+#undef HAVE_NATIVE_mpn_mod_1s_2p
+#undef HAVE_NATIVE_mpn_mod_1s_4p
+#undef HAVE_NATIVE_mpn_mod_34lsub1
+#undef HAVE_NATIVE_mpn_modexact_1_odd
+#undef HAVE_NATIVE_mpn_modexact_1c_odd
+#undef HAVE_NATIVE_mpn_mul_1
+#undef HAVE_NATIVE_mpn_mul_1c
+#undef HAVE_NATIVE_mpn_mul_2
+#undef HAVE_NATIVE_mpn_mul_3
+#undef HAVE_NATIVE_mpn_mul_4
+#undef HAVE_NATIVE_mpn_mul_5
+#undef HAVE_NATIVE_mpn_mul_6
+#undef HAVE_NATIVE_mpn_mul_basecase
+#undef HAVE_NATIVE_mpn_mullo_basecase
+#undef HAVE_NATIVE_mpn_nand_n
+#undef HAVE_NATIVE_mpn_nior_n
+#undef HAVE_NATIVE_mpn_popcount
+#undef HAVE_NATIVE_mpn_preinv_divrem_1
+#undef HAVE_NATIVE_mpn_preinv_mod_1
+#undef HAVE_NATIVE_mpn_redc_1
+#undef HAVE_NATIVE_mpn_redc_2
+#undef HAVE_NATIVE_mpn_rsblsh1_n
+#undef HAVE_NATIVE_mpn_rsblsh2_n
+#undef HAVE_NATIVE_mpn_rsblsh_n
+#undef HAVE_NATIVE_mpn_rsblsh1_nc
+#undef HAVE_NATIVE_mpn_rsblsh2_nc
+#undef HAVE_NATIVE_mpn_rsblsh_nc
+#undef HAVE_NATIVE_mpn_rsh1add_n
+#undef HAVE_NATIVE_mpn_rsh1add_nc
+#undef HAVE_NATIVE_mpn_rsh1sub_n
+#undef HAVE_NATIVE_mpn_rsh1sub_nc
+#undef HAVE_NATIVE_mpn_rshift
+#undef HAVE_NATIVE_mpn_sbpi1_bdiv_r
+#undef HAVE_NATIVE_mpn_sqr_basecase
+#undef HAVE_NATIVE_mpn_sqr_diagonal
+#undef HAVE_NATIVE_mpn_sqr_diag_addlsh1
+#undef HAVE_NATIVE_mpn_sub_n
+#undef HAVE_NATIVE_mpn_sub_nc
+#undef HAVE_NATIVE_mpn_sublsh1_n
+#undef HAVE_NATIVE_mpn_sublsh2_n
+#undef HAVE_NATIVE_mpn_sublsh_n
+#undef HAVE_NATIVE_mpn_sublsh1_nc
+#undef HAVE_NATIVE_mpn_sublsh2_nc
+#undef HAVE_NATIVE_mpn_sublsh_nc
+#undef HAVE_NATIVE_mpn_sublsh1_n_ip1
+#undef HAVE_NATIVE_mpn_sublsh2_n_ip1
+#undef HAVE_NATIVE_mpn_sublsh_n_ip1
+#undef HAVE_NATIVE_mpn_sublsh1_nc_ip1
+#undef HAVE_NATIVE_mpn_sublsh2_nc_ip1
+#undef HAVE_NATIVE_mpn_sublsh_nc_ip1
+#undef HAVE_NATIVE_mpn_submul_1c
+#undef HAVE_NATIVE_mpn_tabselect
+#undef HAVE_NATIVE_mpn_udiv_qrnnd
+#undef HAVE_NATIVE_mpn_udiv_qrnnd_r
+#undef HAVE_NATIVE_mpn_umul_ppmm
+#undef HAVE_NATIVE_mpn_umul_ppmm_r
+#undef HAVE_NATIVE_mpn_xor_n
+#undef HAVE_NATIVE_mpn_xnor_n
+
+/* Define to 1 if you have the `nl_langinfo' function. */
+#undef HAVE_NL_LANGINFO
+
+/* Define to 1 if you have the <nl_types.h> header file. */
+#undef HAVE_NL_TYPES_H
+
+/* Define to 1 if you have the `obstack_vprintf' function. */
+#undef HAVE_OBSTACK_VPRINTF
+
+/* Define to 1 if you have the `popen' function. */
+#undef HAVE_POPEN
+
+/* Define to 1 if you have the `processor_info' function. */
+#undef HAVE_PROCESSOR_INFO
+
+/* Define to 1 if <sys/pstat.h> `struct pst_processor' exists and contains
+   `psp_iticksperclktick'. */
+#undef HAVE_PSP_ITICKSPERCLKTICK
+
+/* Define to 1 if you have the `pstat_getprocessor' function. */
+#undef HAVE_PSTAT_GETPROCESSOR
+
+/* Define to 1 if the system has the type `ptrdiff_t'. */
+#undef HAVE_PTRDIFF_T
+
+/* Define to 1 if the system has the type `quad_t'. */
+#undef HAVE_QUAD_T
+
+/* Define to 1 if you have the `raise' function. */
+#undef HAVE_RAISE
+
+/* Define to 1 if you have the `read_real_time' function. */
+#undef HAVE_READ_REAL_TIME
+
+/* Define to 1 if you have the `sigaction' function. */
+#undef HAVE_SIGACTION
+
+/* Define to 1 if you have the `sigaltstack' function. */
+#undef HAVE_SIGALTSTACK
+
+/* Define to 1 if you have the `sigstack' function. */
+#undef HAVE_SIGSTACK
+
+/* Tune directory speed_cyclecounter, undef=none, 1=32bits, 2=64bits) */
+#undef HAVE_SPEED_CYCLECOUNTER
+
+/* Define to 1 if you have the <sstream> header file. */
+#undef HAVE_SSTREAM
+
+/* Define to 1 if the system has the type `stack_t'. */
+#undef HAVE_STACK_T
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if the system has the type `std::locale'. */
+#undef HAVE_STD__LOCALE
+
+/* Define to 1 if you have the `strchr' function. */
+#undef HAVE_STRCHR
+
+/* Define to 1 if you have the `strerror' function. */
+#undef HAVE_STRERROR
+
+/* 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. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the `strnlen' function. */
+#undef HAVE_STRNLEN
+
+/* Define to 1 if you have the `strtol' function. */
+#undef HAVE_STRTOL
+
+/* Define to 1 if you have the `strtoul' function. */
+#undef HAVE_STRTOUL
+
+/* Define to 1 if you have the `sysconf' function. */
+#undef HAVE_SYSCONF
+
+/* Define to 1 if you have the `sysctl' function. */
+#undef HAVE_SYSCTL
+
+/* Define to 1 if you have the `sysctlbyname' function. */
+#undef HAVE_SYSCTLBYNAME
+
+/* Define to 1 if you have the `syssgi' function. */
+#undef HAVE_SYSSGI
+
+/* Define to 1 if you have the <sys/attributes.h> header file. */
+#undef HAVE_SYS_ATTRIBUTES_H
+
+/* Define to 1 if you have the <sys/iograph.h> header file. */
+#undef HAVE_SYS_IOGRAPH_H
+
+/* Define to 1 if you have the <sys/mman.h> header file. */
+#undef HAVE_SYS_MMAN_H
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#undef HAVE_SYS_PARAM_H
+
+/* Define to 1 if you have the <sys/processor.h> header file. */
+#undef HAVE_SYS_PROCESSOR_H
+
+/* Define to 1 if you have the <sys/pstat.h> header file. */
+#undef HAVE_SYS_PSTAT_H
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#undef HAVE_SYS_RESOURCE_H
+
+/* 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/sysctl.h> header file. */
+#undef HAVE_SYS_SYSCTL_H
+
+/* Define to 1 if you have the <sys/sysinfo.h> header file. */
+#undef HAVE_SYS_SYSINFO_H
+
+/* Define to 1 if you have the <sys/syssgi.h> header file. */
+#undef HAVE_SYS_SYSSGI_H
+
+/* Define to 1 if you have the <sys/systemcfg.h> header file. */
+#undef HAVE_SYS_SYSTEMCFG_H
+
+/* Define to 1 if you have the <sys/times.h> header file. */
+#undef HAVE_SYS_TIMES_H
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_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 `times' function. */
+#undef HAVE_TIMES
+
+/* Define to 1 if the system has the type `uint_least32_t'. */
+#undef HAVE_UINT_LEAST32_T
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the `vsnprintf' function and it works properly. */
+#undef HAVE_VSNPRINTF
+
+/* Define to 1 for Windos/64 */
+#undef HOST_DOS64
+
+/* Assembler local label prefix */
+#undef LSYM_PREFIX
+
+/* Define to the sub-directory where libtool stores uninstalled libraries. */
+#undef LT_OBJDIR
+
+/* Define to 1 to disable the use of inline assembly */
+#undef NO_ASM
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#undef RETSIGTYPE
+
+/* The size of `mp_limb_t', as computed by sizeof. */
+#undef SIZEOF_MP_LIMB_T
+
+/* The size of `unsigned', as computed by sizeof. */
+#undef SIZEOF_UNSIGNED
+
+/* The size of `unsigned long', as computed by sizeof. */
+#undef SIZEOF_UNSIGNED_LONG
+
+/* The size of `unsigned short', as computed by sizeof. */
+#undef SIZEOF_UNSIGNED_SHORT
+
+/* The size of `void *', as computed by sizeof. */
+#undef SIZEOF_VOID_P
+
+/* Define to 1 if sscanf requires writable inputs */
+#undef SSCANF_WRITABLE_INPUT
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Maximum size the tune program can test for SQR_TOOM2_THRESHOLD */
+#undef TUNE_SQR_TOOM2_MAX
+
+/* Version number of package */
+#undef VERSION
+
+/* Define to 1 to enable ASSERT checking, per --enable-assert */
+#undef WANT_ASSERT
+
+/* Define to 1 to enable GMP_CPU_TYPE faking cpuid, per --enable-fake-cpuid */
+#undef WANT_FAKE_CPUID
+
+/* Define to 1 when building a fat binary. */
+#undef WANT_FAT_BINARY
+
+/* Define to 1 to enable FFTs for multiplication, per --enable-fft */
+#undef WANT_FFT
+
+/* Define to 1 to enable old mpn_mul_fft_full for multiplication, per
+   --enable-old-fft-full */
+#undef WANT_OLD_FFT_FULL
+
+/* Define to 1 if --enable-profiling=gprof */
+#undef WANT_PROFILING_GPROF
+
+/* Define to 1 if --enable-profiling=instrument */
+#undef WANT_PROFILING_INSTRUMENT
+
+/* Define to 1 if --enable-profiling=prof */
+#undef WANT_PROFILING_PROF
+
+/* Define one of these to 1 for the desired temporary memory allocation
+   method, per --enable-alloca. */
+#undef WANT_TMP_ALLOCA
+#undef WANT_TMP_REENTRANT
+#undef WANT_TMP_NOTREENTRANT
+#undef WANT_TMP_DEBUG
+
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+   significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+#  define WORDS_BIGENDIAN 1
+# endif
+#else
+# ifndef WORDS_BIGENDIAN
+#  undef WORDS_BIGENDIAN
+# endif
+#endif
+
+/* Define to 1 if the assembler understands the mulx instruction */
+#undef X86_ASM_MULX
+
+/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
+   `char[]'. */
+#undef YYTEXT_POINTER
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+#undef inline
+#endif
+
+/* Define to the equivalent of the C99 'restrict' keyword, or to
+   nothing if this is not supported.  Do not define if restrict is
+   supported directly.  */
+#undef restrict
+/* Work around a bug in Sun C++: it does not support _Restrict or
+   __restrict__, even though the corresponding Sun C compiler ends up with
+   "#define restrict _Restrict" or "#define restrict __restrict__" in the
+   previous line.  Perhaps some future version of Sun C++ will work with
+   restrict; if so, hopefully it defines __RESTRICT like Sun C does.  */
+#if defined __SUNPRO_CC && !defined __RESTRICT
+# define _Restrict
+# define __restrict__
+#endif
+
+/* Define to empty if the keyword `volatile' does not work. Warning: valid
+   code using `volatile' can become incorrect without. Disable with care. */
+#undef volatile
diff --git a/third_party/gmp/config.sub b/third_party/gmp/config.sub
new file mode 100755
index 0000000..8ec227f
--- /dev/null
+++ b/third_party/gmp/config.sub
@@ -0,0 +1,165 @@
+#! /bin/sh
+#
+# GMP config.sub wrapper.
+
+
+# Copyright 2000-2003, 2006, 2009-2016 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+
+# Usage: config.sub CPU-VENDOR-OS
+#        config.sub ALIAS
+#
+# Validate and canonicalize the given configuration name, with special
+# handling for GMP extra CPU names.
+#
+# When the CPU isn't special the whole name is simply passed straight
+# through to configfsf.sub.
+#
+# When the CPU is a GMP extra, configfsf.sub is run on a similar CPU that it
+# will recognise.  For example "athlon-pc-freebsd3.5" is validated using
+# "i386-pc-freebsd3.5".
+#
+# Any canonicalizations made by configfsf.sub are preserved.  For example
+# given "athlon-linux", configfsf.sub is called with "i386-linux" and will
+# give back "i386-pc-linux-gnu".  "athlon" is then reinstated, so we print
+# "athlon-pc-linux-gnu".
+
+
+# Expect to find configfsf.sub in the same directory as this config.sub
+configfsf_sub="`echo \"$0\" | sed 's/config.sub$/configfsf.sub/'`"
+if test "$configfsf_sub" = "$0"; then
+  echo "Cannot derive configfsf.sub from $0" 1>&2
+  exit 1
+fi
+if test -f "$configfsf_sub"; then
+  :
+else
+  echo "$configfsf_sub not found" 1>&2
+  exit 1
+fi
+
+# Always run configfsf.sub with $SHELL, like autoconf does for config.sub
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+# Identify ourselves on --version, --help, etc
+case "$1" in
+"" | -*)
+  echo "(GNU MP wrapped config.sub)" 1>&2
+  $SHELL $configfsf_sub "$@"
+  exit
+  ;;
+esac
+
+given_full="$1"
+given_cpu=`echo "$given_full" | sed 's/-.*$//'`
+given_rest=`echo "$given_full" | sed 's/^[^-]*//'`
+
+
+# Aliases for GMP extras
+case "$given_cpu" in
+  # configfsf.sub turns p5 into i586, instead use our exact cpu type
+  p5 | p54)   given_cpu=pentium ;;
+  p55)        given_cpu=pentiummmx ;;
+
+  # configfsf.sub turns p6, pentiumii and pentiumiii into i686, instead use
+  # our exact cpu types
+  p6)         given_cpu=pentiumpro ;;
+  pentiumii)  given_cpu=pentium2 ;;
+  pentiumiii) given_cpu=pentium3 ;;
+esac
+given_full="$given_cpu$given_rest"
+
+
+# GMP extras and what to use for the config.sub test
+case "$given_cpu" in
+itanium | itanium2)
+  test_cpu=ia64 ;;
+pentium | pentiummmx | pentiumpro | pentium[234m] | k[567] | k6[23] | geode | athlon | viac3*)
+  test_cpu=i386 ;;
+athlon64 | atom | silvermont | goldmont | core2 | corei* | opteron | k[89] | k10 | bobcat | jaguar* | bulldozer* | piledriver* | steamroller* | excavator* | zen* | nano | nehalem | westmere | sandybridge* | ivybridge* | haswell* | broadwell* | skylake* | kabylake* | knightslanding)
+  test_cpu=x86_64 ;;
+power[2-9] | power2sc)
+  test_cpu=power ;;
+powerpc401 | powerpc403 | powerpc405 | \
+powerpc505 | \
+powerpc601 | powerpc602  | \
+powerpc603 | powerpc603e | \
+powerpc604 | powerpc604e | \
+powerpc620 | powerpc630  | powerpc970  | \
+powerpc740 | powerpc7400 | powerpc7450 | powerpc750  | \
+powerpc801 | powerpc821 | powerpc823  | powerpc860 | \
+powerpc64)
+  test_cpu=powerpc ;;
+sparcv8 | supersparc | microsparc | \
+ultrasparc | ultrasparc2 | ultrasparc2i | ultrasparc3 | ultrasparct[12345])
+  test_cpu=sparc ;;
+sh2)
+  test_cpu=sh ;;
+
+z900 | z990 | z9 | z10 | z196)
+  test_cpu=s390x;;
+z900esa | z990esa | z9esa | z10esa | z196esa)
+  test_cpu=s390;;
+
+armsa1 | armxscale | arm9tdmi | arm9te |				\
+arm10* | arm11mpcore | armsa1 | arm1136 | arm1156 | arm1176 |		\
+armcortex[arm][0-9] | armcortex[arm][0-9][0-9] |			\
+arm*neon | armxgene1 | armexynosm1 | armthunderx)
+  test_cpu="arm";;
+
+*)
+  # Don't need or want to change the given name, just run configfsf.sub
+  $SHELL $configfsf_sub "$given_full"
+  if test $? = 0; then
+    exit 0
+  else
+    echo "(GNU MP wrapped config.sub, testing \"$given_full\")"
+    exit 1
+  fi
+esac
+
+
+test_full="$test_cpu$given_rest"
+canonical_full=`$SHELL $configfsf_sub "$test_full"`
+if test $? = 0; then
+  :
+else
+  echo "(GNU MP wrapped config.sub, testing \"$given_full\" as \"$test_full\")"
+  exit 1
+fi
+
+canonical_rest=`echo "$canonical_full" | sed 's/^[^-]*//'`
+echo "$given_cpu$canonical_rest"
+exit 0
+
+
+
+# Local variables:
+# fill-column: 76
+# End:
diff --git a/third_party/gmp/config/arm/v7a/cora9/config.h b/third_party/gmp/config/arm/v7a/cora9/config.h
new file mode 100644
index 0000000..f0c64c8
--- /dev/null
+++ b/third_party/gmp/config/arm/v7a/cora9/config.h
@@ -0,0 +1,668 @@
+/* config.h.  Generated from config.in by configure.  */
+/* config.in.  Generated from configure.ac by autoheader.  */
+
+/*
+
+Copyright 1996-2020 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.
+*/
+
+/* Define if building universal (internal helper macro) */
+/* #undef AC_APPLE_UNIVERSAL_BUILD */
+
+/* The gmp-mparam.h file (a string) the tune program should suggest updating.
+   */
+#define GMP_MPARAM_H_SUGGEST "./mpn/arm/gmp-mparam.h"
+
+/* Define to 1 if you have the `alarm' function. */
+#define HAVE_ALARM 1
+
+/* Define to 1 if alloca() works (via gmp-impl.h). */
+#define HAVE_ALLOCA 1
+
+/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix).
+   */
+#define HAVE_ALLOCA_H 1
+
+/* Define to 1 if the compiler accepts gcc style __attribute__ ((const)) */
+#define HAVE_ATTRIBUTE_CONST 1
+
+/* Define to 1 if the compiler accepts gcc style __attribute__ ((malloc)) */
+#define HAVE_ATTRIBUTE_MALLOC 1
+
+/* Define to 1 if the compiler accepts gcc style __attribute__ ((mode (XX)))
+   */
+#define HAVE_ATTRIBUTE_MODE 1
+
+/* Define to 1 if the compiler accepts gcc style __attribute__ ((noreturn)) */
+#define HAVE_ATTRIBUTE_NORETURN 1
+
+/* Define to 1 if you have the `attr_get' function. */
+/* #undef HAVE_ATTR_GET */
+
+/* Define to 1 if tests/libtests has calling conventions checking for the CPU
+   */
+#define HAVE_CALLING_CONVENTIONS 1
+
+/* Define to 1 if you have the `clock' function. */
+#define HAVE_CLOCK 1
+
+/* Define to 1 if you have the `clock_gettime' function */
+#define HAVE_CLOCK_GETTIME 1
+
+/* Define to 1 if you have the `cputime' function. */
+/* #undef HAVE_CPUTIME */
+
+/* Define to 1 if you have the declaration of `fgetc', and to 0 if you don't.
+   */
+#define HAVE_DECL_FGETC 1
+
+/* Define to 1 if you have the declaration of `fscanf', and to 0 if you don't.
+   */
+#define HAVE_DECL_FSCANF 1
+
+/* Define to 1 if you have the declaration of `optarg', and to 0 if you don't.
+   */
+#define HAVE_DECL_OPTARG 1
+
+/* Define to 1 if you have the declaration of `sys_errlist', and to 0 if you
+   don't. */
+#define HAVE_DECL_SYS_ERRLIST 1
+
+/* Define to 1 if you have the declaration of `sys_nerr', and to 0 if you
+   don't. */
+#define HAVE_DECL_SYS_NERR 1
+
+/* Define to 1 if you have the declaration of `ungetc', and to 0 if you don't.
+   */
+#define HAVE_DECL_UNGETC 1
+
+/* Define to 1 if you have the declaration of `vfprintf', and to 0 if you
+   don't. */
+#define HAVE_DECL_VFPRINTF 1
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define one of the following to 1 for the format of a `double'.
+   If your format is not among these choices, or you don't know what it is,
+   then leave all undefined.
+   IEEE_LITTLE_SWAPPED means little endian, but with the two 4-byte halves
+   swapped, as used by ARM CPUs in little endian mode.  */
+/* #undef HAVE_DOUBLE_IEEE_BIG_ENDIAN */
+#define HAVE_DOUBLE_IEEE_LITTLE_ENDIAN 1
+/* #undef HAVE_DOUBLE_IEEE_LITTLE_SWAPPED */
+/* #undef HAVE_DOUBLE_VAX_D */
+/* #undef HAVE_DOUBLE_VAX_G */
+/* #undef HAVE_DOUBLE_CRAY_CFP */
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the <float.h> header file. */
+#define HAVE_FLOAT_H 1
+
+/* Define to 1 if you have the `getpagesize' function. */
+#define HAVE_GETPAGESIZE 1
+
+/* Define to 1 if you have the `getrusage' function. */
+#define HAVE_GETRUSAGE 1
+
+/* Define to 1 if you have the `getsysinfo' function. */
+/* #undef HAVE_GETSYSINFO */
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if the compiler accepts gcc style __attribute__ ((visibility))
+   and __attribute__ ((alias)) */
+#define HAVE_HIDDEN_ALIAS 1
+
+/* Define one of these to 1 for the host CPU family.
+   If your CPU is not in any of these families, leave all undefined.
+   For an AMD64 chip, define "x86" in ABI=32, but not in ABI=64. */
+/* #undef HAVE_HOST_CPU_FAMILY_alpha */
+/* #undef HAVE_HOST_CPU_FAMILY_m68k */
+/* #undef HAVE_HOST_CPU_FAMILY_power */
+/* #undef HAVE_HOST_CPU_FAMILY_powerpc */
+/* #undef HAVE_HOST_CPU_FAMILY_x86 */
+/* #undef HAVE_HOST_CPU_FAMILY_x86_64 */
+
+/* Define one of the following to 1 for the host CPU, as per the output of
+   ./config.guess.  If your CPU is not listed here, leave all undefined.  */
+/* #undef HAVE_HOST_CPU_alphaev67 */
+/* #undef HAVE_HOST_CPU_alphaev68 */
+/* #undef HAVE_HOST_CPU_alphaev7 */
+/* #undef HAVE_HOST_CPU_m68020 */
+/* #undef HAVE_HOST_CPU_m68030 */
+/* #undef HAVE_HOST_CPU_m68040 */
+/* #undef HAVE_HOST_CPU_m68060 */
+/* #undef HAVE_HOST_CPU_m68360 */
+/* #undef HAVE_HOST_CPU_powerpc604 */
+/* #undef HAVE_HOST_CPU_powerpc604e */
+/* #undef HAVE_HOST_CPU_powerpc750 */
+/* #undef HAVE_HOST_CPU_powerpc7400 */
+/* #undef HAVE_HOST_CPU_supersparc */
+/* #undef HAVE_HOST_CPU_i386 */
+/* #undef HAVE_HOST_CPU_i586 */
+/* #undef HAVE_HOST_CPU_i686 */
+/* #undef HAVE_HOST_CPU_pentium */
+/* #undef HAVE_HOST_CPU_pentiummmx */
+/* #undef HAVE_HOST_CPU_pentiumpro */
+/* #undef HAVE_HOST_CPU_pentium2 */
+/* #undef HAVE_HOST_CPU_pentium3 */
+/* #undef HAVE_HOST_CPU_pentium4 */
+/* #undef HAVE_HOST_CPU_core2 */
+/* #undef HAVE_HOST_CPU_nehalem */
+/* #undef HAVE_HOST_CPU_westmere */
+/* #undef HAVE_HOST_CPU_sandybridge */
+/* #undef HAVE_HOST_CPU_ivybridge */
+/* #undef HAVE_HOST_CPU_haswell */
+/* #undef HAVE_HOST_CPU_broadwell */
+/* #undef HAVE_HOST_CPU_skylake */
+/* #undef HAVE_HOST_CPU_silvermont */
+/* #undef HAVE_HOST_CPU_goldmont */
+/* #undef HAVE_HOST_CPU_k8 */
+/* #undef HAVE_HOST_CPU_k10 */
+/* #undef HAVE_HOST_CPU_bulldozer */
+/* #undef HAVE_HOST_CPU_piledriver */
+/* #undef HAVE_HOST_CPU_steamroller */
+/* #undef HAVE_HOST_CPU_excavator */
+/* #undef HAVE_HOST_CPU_zen */
+/* #undef HAVE_HOST_CPU_bobcat */
+/* #undef HAVE_HOST_CPU_jaguar */
+/* #undef HAVE_HOST_CPU_s390_z900 */
+/* #undef HAVE_HOST_CPU_s390_z990 */
+/* #undef HAVE_HOST_CPU_s390_z9 */
+/* #undef HAVE_HOST_CPU_s390_z10 */
+/* #undef HAVE_HOST_CPU_s390_z196 */
+
+/* Define to 1 iff we have a s390 with 64-bit registers.  */
+/* #undef HAVE_HOST_CPU_s390_zarch */
+
+/* Define to 1 if the system has the type `intmax_t'. */
+#define HAVE_INTMAX_T 1
+
+/* Define to 1 if the system has the type `intptr_t'. */
+#define HAVE_INTPTR_T 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the <invent.h> header file. */
+/* #undef HAVE_INVENT_H */
+
+/* Define to 1 if you have the <langinfo.h> header file. */
+#define HAVE_LANGINFO_H 1
+
+/* Define one of these to 1 for the endianness of `mp_limb_t'.
+   If the endianness is not a simple big or little, or you don't know what
+   it is, then leave both undefined. */
+/* #undef HAVE_LIMB_BIG_ENDIAN */
+#define HAVE_LIMB_LITTLE_ENDIAN 1
+
+/* Define to 1 if you have the `localeconv' function. */
+#define HAVE_LOCALECONV 1
+
+/* Define to 1 if you have the <locale.h> header file. */
+#define HAVE_LOCALE_H 1
+
+/* Define to 1 if the system has the type `long double'. */
+#define HAVE_LONG_DOUBLE 1
+
+/* Define to 1 if the system has the type `long long'. */
+#define HAVE_LONG_LONG 1
+
+/* Define to 1 if you have the <machine/hal_sysinfo.h> header file. */
+/* #undef HAVE_MACHINE_HAL_SYSINFO_H */
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `memset' function. */
+#define HAVE_MEMSET 1
+
+/* Define to 1 if you have the `mmap' function. */
+#define HAVE_MMAP 1
+
+/* Define to 1 if you have the `mprotect' function. */
+#define HAVE_MPROTECT 1
+
+/* Define to 1 each of the following for which a native (ie. CPU specific)
+    implementation of the corresponding routine exists.  */
+#define HAVE_NATIVE_mpn_add_n 1
+/* #undef HAVE_NATIVE_mpn_add_n_sub_n */
+#define HAVE_NATIVE_mpn_add_nc 1
+/* #undef HAVE_NATIVE_mpn_addaddmul_1msb0 */
+#define HAVE_NATIVE_mpn_addlsh1_n 1
+/* #undef HAVE_NATIVE_mpn_addlsh2_n */
+/* #undef HAVE_NATIVE_mpn_addlsh_n */
+/* #undef HAVE_NATIVE_mpn_addlsh1_nc */
+/* #undef HAVE_NATIVE_mpn_addlsh2_nc */
+/* #undef HAVE_NATIVE_mpn_addlsh_nc */
+/* #undef HAVE_NATIVE_mpn_addlsh1_n_ip1 */
+/* #undef HAVE_NATIVE_mpn_addlsh2_n_ip1 */
+/* #undef HAVE_NATIVE_mpn_addlsh_n_ip1 */
+/* #undef HAVE_NATIVE_mpn_addlsh1_nc_ip1 */
+/* #undef HAVE_NATIVE_mpn_addlsh2_nc_ip1 */
+/* #undef HAVE_NATIVE_mpn_addlsh_nc_ip1 */
+/* #undef HAVE_NATIVE_mpn_addlsh1_n_ip2 */
+/* #undef HAVE_NATIVE_mpn_addlsh2_n_ip2 */
+/* #undef HAVE_NATIVE_mpn_addlsh_n_ip2 */
+/* #undef HAVE_NATIVE_mpn_addlsh1_nc_ip2 */
+/* #undef HAVE_NATIVE_mpn_addlsh2_nc_ip2 */
+/* #undef HAVE_NATIVE_mpn_addlsh_nc_ip2 */
+/* #undef HAVE_NATIVE_mpn_addmul_1c */
+/* #undef HAVE_NATIVE_mpn_addmul_2 */
+/* #undef HAVE_NATIVE_mpn_addmul_3 */
+/* #undef HAVE_NATIVE_mpn_addmul_4 */
+/* #undef HAVE_NATIVE_mpn_addmul_5 */
+/* #undef HAVE_NATIVE_mpn_addmul_6 */
+/* #undef HAVE_NATIVE_mpn_addmul_7 */
+/* #undef HAVE_NATIVE_mpn_addmul_8 */
+/* #undef HAVE_NATIVE_mpn_addmul_2s */
+#define HAVE_NATIVE_mpn_and_n 1
+#define HAVE_NATIVE_mpn_andn_n 1
+#define HAVE_NATIVE_mpn_bdiv_dbm1c 1
+#define HAVE_NATIVE_mpn_bdiv_q_1 1
+#define HAVE_NATIVE_mpn_pi1_bdiv_q_1 1
+#define HAVE_NATIVE_mpn_cnd_add_n 1
+#define HAVE_NATIVE_mpn_cnd_sub_n 1
+#define HAVE_NATIVE_mpn_com 1
+#define HAVE_NATIVE_mpn_copyd 1
+#define HAVE_NATIVE_mpn_copyi 1
+/* #undef HAVE_NATIVE_mpn_div_qr_1n_pi1 */
+/* #undef HAVE_NATIVE_mpn_div_qr_2 */
+#define HAVE_NATIVE_mpn_divexact_1 1
+/* #undef HAVE_NATIVE_mpn_divexact_by3c */
+/* #undef HAVE_NATIVE_mpn_divrem_1 */
+/* #undef HAVE_NATIVE_mpn_divrem_1c */
+/* #undef HAVE_NATIVE_mpn_divrem_2 */
+/* #undef HAVE_NATIVE_mpn_gcd_1 */
+/* #undef HAVE_NATIVE_mpn_gcd_11 */
+/* #undef HAVE_NATIVE_mpn_gcd_22 */
+/* #undef HAVE_NATIVE_mpn_hamdist */
+#define HAVE_NATIVE_mpn_invert_limb 1
+#define HAVE_NATIVE_mpn_ior_n 1
+#define HAVE_NATIVE_mpn_iorn_n 1
+#define HAVE_NATIVE_mpn_lshift 1
+#define HAVE_NATIVE_mpn_lshiftc 1
+/* #undef HAVE_NATIVE_mpn_lshsub_n */
+/* #undef HAVE_NATIVE_mpn_mod_1 */
+/* #undef HAVE_NATIVE_mpn_mod_1_1p */
+/* #undef HAVE_NATIVE_mpn_mod_1c */
+/* #undef HAVE_NATIVE_mpn_mod_1s_2p */
+/* #undef HAVE_NATIVE_mpn_mod_1s_4p */
+#define HAVE_NATIVE_mpn_mod_34lsub1 1
+/* #undef HAVE_NATIVE_mpn_modexact_1_odd */
+#define HAVE_NATIVE_mpn_modexact_1c_odd 1
+#define HAVE_NATIVE_mpn_mul_1 1
+/* #undef HAVE_NATIVE_mpn_mul_1c */
+/* #undef HAVE_NATIVE_mpn_mul_2 */
+/* #undef HAVE_NATIVE_mpn_mul_3 */
+/* #undef HAVE_NATIVE_mpn_mul_4 */
+/* #undef HAVE_NATIVE_mpn_mul_5 */
+/* #undef HAVE_NATIVE_mpn_mul_6 */
+/* #undef HAVE_NATIVE_mpn_mul_basecase */
+/* #undef HAVE_NATIVE_mpn_mullo_basecase */
+#define HAVE_NATIVE_mpn_nand_n 1
+#define HAVE_NATIVE_mpn_nior_n 1
+/* #undef HAVE_NATIVE_mpn_popcount */
+/* #undef HAVE_NATIVE_mpn_preinv_divrem_1 */
+/* #undef HAVE_NATIVE_mpn_preinv_mod_1 */
+/* #undef HAVE_NATIVE_mpn_redc_1 */
+/* #undef HAVE_NATIVE_mpn_redc_2 */
+/* #undef HAVE_NATIVE_mpn_rsblsh1_n */
+/* #undef HAVE_NATIVE_mpn_rsblsh2_n */
+/* #undef HAVE_NATIVE_mpn_rsblsh_n */
+/* #undef HAVE_NATIVE_mpn_rsblsh1_nc */
+/* #undef HAVE_NATIVE_mpn_rsblsh2_nc */
+/* #undef HAVE_NATIVE_mpn_rsblsh_nc */
+#define HAVE_NATIVE_mpn_rsh1add_n 1
+/* #undef HAVE_NATIVE_mpn_rsh1add_nc */
+#define HAVE_NATIVE_mpn_rsh1sub_n 1
+/* #undef HAVE_NATIVE_mpn_rsh1sub_nc */
+#define HAVE_NATIVE_mpn_rshift 1
+/* #undef HAVE_NATIVE_mpn_sbpi1_bdiv_r */
+/* #undef HAVE_NATIVE_mpn_sqr_basecase */
+/* #undef HAVE_NATIVE_mpn_sqr_diagonal */
+/* #undef HAVE_NATIVE_mpn_sqr_diag_addlsh1 */
+#define HAVE_NATIVE_mpn_sub_n 1
+#define HAVE_NATIVE_mpn_sub_nc 1
+#define HAVE_NATIVE_mpn_sublsh1_n 1
+/* #undef HAVE_NATIVE_mpn_sublsh2_n */
+/* #undef HAVE_NATIVE_mpn_sublsh_n */
+/* #undef HAVE_NATIVE_mpn_sublsh1_nc */
+/* #undef HAVE_NATIVE_mpn_sublsh2_nc */
+/* #undef HAVE_NATIVE_mpn_sublsh_nc */
+/* #undef HAVE_NATIVE_mpn_sublsh1_n_ip1 */
+/* #undef HAVE_NATIVE_mpn_sublsh2_n_ip1 */
+/* #undef HAVE_NATIVE_mpn_sublsh_n_ip1 */
+/* #undef HAVE_NATIVE_mpn_sublsh1_nc_ip1 */
+/* #undef HAVE_NATIVE_mpn_sublsh2_nc_ip1 */
+/* #undef HAVE_NATIVE_mpn_sublsh_nc_ip1 */
+/* #undef HAVE_NATIVE_mpn_submul_1c */
+/* #undef HAVE_NATIVE_mpn_tabselect */
+#define HAVE_NATIVE_mpn_udiv_qrnnd 1
+/* #undef HAVE_NATIVE_mpn_udiv_qrnnd_r */
+/* #undef HAVE_NATIVE_mpn_umul_ppmm */
+/* #undef HAVE_NATIVE_mpn_umul_ppmm_r */
+#define HAVE_NATIVE_mpn_xor_n 1
+#define HAVE_NATIVE_mpn_xnor_n 1
+
+/* Define to 1 if you have the `nl_langinfo' function. */
+#define HAVE_NL_LANGINFO 1
+
+/* Define to 1 if you have the <nl_types.h> header file. */
+#define HAVE_NL_TYPES_H 1
+
+/* Define to 1 if you have the `obstack_vprintf' function. */
+#define HAVE_OBSTACK_VPRINTF 1
+
+/* Define to 1 if you have the `popen' function. */
+#define HAVE_POPEN 1
+
+/* Define to 1 if you have the `processor_info' function. */
+/* #undef HAVE_PROCESSOR_INFO */
+
+/* Define to 1 if <sys/pstat.h> `struct pst_processor' exists and contains
+   `psp_iticksperclktick'. */
+/* #undef HAVE_PSP_ITICKSPERCLKTICK */
+
+/* Define to 1 if you have the `pstat_getprocessor' function. */
+/* #undef HAVE_PSTAT_GETPROCESSOR */
+
+/* Define to 1 if the system has the type `ptrdiff_t'. */
+#define HAVE_PTRDIFF_T 1
+
+/* Define to 1 if the system has the type `quad_t'. */
+#define HAVE_QUAD_T 1
+
+/* Define to 1 if you have the `raise' function. */
+#define HAVE_RAISE 1
+
+/* Define to 1 if you have the `read_real_time' function. */
+/* #undef HAVE_READ_REAL_TIME */
+
+/* Define to 1 if you have the `sigaction' function. */
+#define HAVE_SIGACTION 1
+
+/* Define to 1 if you have the `sigaltstack' function. */
+#define HAVE_SIGALTSTACK 1
+
+/* Define to 1 if you have the `sigstack' function. */
+#define HAVE_SIGSTACK 1
+
+/* Tune directory speed_cyclecounter, undef=none, 1=32bits, 2=64bits) */
+/* #undef HAVE_SPEED_CYCLECOUNTER */
+
+/* Define to 1 if you have the <sstream> header file. */
+#define HAVE_SSTREAM 1
+
+/* Define to 1 if the system has the type `stack_t'. */
+#define HAVE_STACK_T 1
+
+/* 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 the system has the type `std::locale'. */
+#define HAVE_STD__LOCALE 1
+
+/* Define to 1 if you have the `strchr' function. */
+#define HAVE_STRCHR 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. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strnlen' function. */
+#define HAVE_STRNLEN 1
+
+/* Define to 1 if you have the `strtol' function. */
+#define HAVE_STRTOL 1
+
+/* Define to 1 if you have the `strtoul' function. */
+#define HAVE_STRTOUL 1
+
+/* Define to 1 if you have the `sysconf' function. */
+#define HAVE_SYSCONF 1
+
+/* Define to 1 if you have the `sysctl' function. */
+#define HAVE_SYSCTL 1
+
+/* Define to 1 if you have the `sysctlbyname' function. */
+/* #undef HAVE_SYSCTLBYNAME */
+
+/* Define to 1 if you have the `syssgi' function. */
+/* #undef HAVE_SYSSGI */
+
+/* Define to 1 if you have the <sys/attributes.h> header file. */
+/* #undef HAVE_SYS_ATTRIBUTES_H */
+
+/* Define to 1 if you have the <sys/iograph.h> header file. */
+/* #undef HAVE_SYS_IOGRAPH_H */
+
+/* Define to 1 if you have the <sys/mman.h> header file. */
+#define HAVE_SYS_MMAN_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/processor.h> header file. */
+/* #undef HAVE_SYS_PROCESSOR_H */
+
+/* Define to 1 if you have the <sys/pstat.h> header file. */
+/* #undef HAVE_SYS_PSTAT_H */
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#define HAVE_SYS_RESOURCE_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/sysctl.h> header file. */
+#define HAVE_SYS_SYSCTL_H 1
+
+/* Define to 1 if you have the <sys/sysinfo.h> header file. */
+#define HAVE_SYS_SYSINFO_H 1
+
+/* Define to 1 if you have the <sys/syssgi.h> header file. */
+/* #undef HAVE_SYS_SYSSGI_H */
+
+/* Define to 1 if you have the <sys/systemcfg.h> header file. */
+/* #undef HAVE_SYS_SYSTEMCFG_H */
+
+/* Define to 1 if you have the <sys/times.h> header file. */
+#define HAVE_SYS_TIMES_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the `times' function. */
+#define HAVE_TIMES 1
+
+/* Define to 1 if the system has the type `uint_least32_t'. */
+#define HAVE_UINT_LEAST32_T 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `vsnprintf' function and it works properly. */
+#define HAVE_VSNPRINTF 1
+
+/* Define to 1 for Windos/64 */
+/* #undef HOST_DOS64 */
+
+/* Assembler local label prefix */
+#define LSYM_PREFIX ".L"
+
+/* Define to the sub-directory where libtool stores uninstalled libraries. */
+#define LT_OBJDIR ".libs/"
+
+/* Define to 1 to disable the use of inline assembly */
+/* #undef NO_ASM */
+
+/* Name of package */
+#define PACKAGE "gmp"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "gmp-bugs@gmplib.org, see https://gmplib.org/manual/Reporting-Bugs.html"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "GNU MP"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "GNU MP 6.2.0"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "gmp"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL "http://www.gnu.org/software/gmp/"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "6.2.0"
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#define RETSIGTYPE void
+
+/* The size of `mp_limb_t', as computed by sizeof. */
+#define SIZEOF_MP_LIMB_T 4
+
+/* The size of `unsigned', as computed by sizeof. */
+#define SIZEOF_UNSIGNED 4
+
+/* The size of `unsigned long', as computed by sizeof. */
+#define SIZEOF_UNSIGNED_LONG 4
+
+/* The size of `unsigned short', as computed by sizeof. */
+#define SIZEOF_UNSIGNED_SHORT 2
+
+/* The size of `void *', as computed by sizeof. */
+#define SIZEOF_VOID_P 4
+
+/* Define to 1 if sscanf requires writable inputs */
+/* #undef SSCANF_WRITABLE_INPUT */
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Maximum size the tune program can test for SQR_TOOM2_THRESHOLD */
+#define TUNE_SQR_TOOM2_MAX SQR_TOOM2_MAX_GENERIC
+
+/* Version number of package */
+#define VERSION "6.2.0"
+
+/* Define to 1 to enable ASSERT checking, per --enable-assert */
+/* #undef WANT_ASSERT */
+
+/* Define to 1 to enable GMP_CPU_TYPE faking cpuid, per --enable-fake-cpuid */
+/* #undef WANT_FAKE_CPUID */
+
+/* Define to 1 when building a fat binary. */
+/* #undef WANT_FAT_BINARY */
+
+/* Define to 1 to enable FFTs for multiplication, per --enable-fft */
+#define WANT_FFT 1
+
+/* Define to 1 to enable old mpn_mul_fft_full for multiplication, per
+   --enable-old-fft-full */
+/* #undef WANT_OLD_FFT_FULL */
+
+/* Define to 1 if --enable-profiling=gprof */
+/* #undef WANT_PROFILING_GPROF */
+
+/* Define to 1 if --enable-profiling=instrument */
+/* #undef WANT_PROFILING_INSTRUMENT */
+
+/* Define to 1 if --enable-profiling=prof */
+/* #undef WANT_PROFILING_PROF */
+
+/* Define one of these to 1 for the desired temporary memory allocation
+   method, per --enable-alloca. */
+#define WANT_TMP_ALLOCA 1
+/* #undef WANT_TMP_REENTRANT */
+/* #undef WANT_TMP_NOTREENTRANT */
+/* #undef WANT_TMP_DEBUG */
+
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+   significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+#  define WORDS_BIGENDIAN 1
+# endif
+#else
+# ifndef WORDS_BIGENDIAN
+/* #  undef WORDS_BIGENDIAN */
+# endif
+#endif
+
+/* Define to 1 if the assembler understands the mulx instruction */
+/* #undef X86_ASM_MULX */
+
+/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
+   `char[]'. */
+/* #undef YYTEXT_POINTER */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to the equivalent of the C99 'restrict' keyword, or to
+   nothing if this is not supported.  Do not define if restrict is
+   supported directly.  */
+#define restrict __restrict
+/* Work around a bug in Sun C++: it does not support _Restrict or
+   __restrict__, even though the corresponding Sun C compiler ends up with
+   "#define restrict _Restrict" or "#define restrict __restrict__" in the
+   previous line.  Perhaps some future version of Sun C++ will work with
+   restrict; if so, hopefully it defines __RESTRICT like Sun C does.  */
+#if defined __SUNPRO_CC && !defined __RESTRICT
+# define _Restrict
+# define __restrict__
+#endif
+
+/* Define to empty if the keyword `volatile' does not work. Warning: valid
+   code using `volatile' can become incorrect without. Disable with care. */
+/* #undef volatile */
diff --git a/third_party/gmp/config/arm/v7a/cora9/config.m4 b/third_party/gmp/config/arm/v7a/cora9/config.m4
new file mode 100644
index 0000000..54a046a
--- /dev/null
+++ b/third_party/gmp/config/arm/v7a/cora9/config.m4
@@ -0,0 +1,37 @@
+dnl config.m4.  Generated automatically by configure.
+changequote(<,>)
+ifdef(<__CONFIG_M4_INCLUDED__>,,<
+define(<CONFIG_TOP_SRCDIR>,<`../.'>)
+define(<WANT_ASSERT>,0)
+define(<WANT_PROFILING>,<`no'>)
+define(<NOTHUMB>,0)
+define(<M4WRAP_SPURIOUS>,<no>)
+define(<TEXT>, <.text>)
+define(<DATA>, <.data>)
+define(<LABEL_SUFFIX>, <:>)
+define(<GLOBL>, <.globl>)
+define(<GLOBL_ATTR>, <>)
+define(<GSYM_PREFIX>, <>)
+define(<RODATA>, <	.section	.rodata>)
+define(<TYPE>, <.type	$1,#$2>)
+define(<SIZE>, <.size	$1,$2>)
+define(<LSYM_PREFIX>, <.L>)
+define(<W32>, <.long>)
+define(<ALIGN_LOGARITHMIC>,<yes>)
+define(<SQR_TOOM2_THRESHOLD>,<78>)
+define(<BMOD_1_TO_MOD_1_THRESHOLD>,<41>)
+define(<SIZEOF_UNSIGNED>,<4>)
+define(<GMP_LIMB_BITS>,32)
+define(<GMP_NAIL_BITS>,0)
+define(<GMP_NUMB_BITS>,eval(GMP_LIMB_BITS-GMP_NAIL_BITS))
+>)
+changequote(`,')
+ifdef(`__CONFIG_M4_INCLUDED__',,`
+include(CONFIG_TOP_SRCDIR`/mpn/asm-defs.m4')
+include_mpn(`arm/arm-defs.m4')
+define_not_for_expansion(`HAVE_HOST_CPU_arm')
+define_not_for_expansion(`HAVE_ABI_32')
+define_not_for_expansion(`HAVE_LIMB_LITTLE_ENDIAN')
+define_not_for_expansion(`HAVE_DOUBLE_IEEE_LITTLE_ENDIAN')
+')
+define(`__CONFIG_M4_INCLUDED__')
diff --git a/third_party/gmp/config/arm/v7a/cora9/gmp.h b/third_party/gmp/config/arm/v7a/cora9/gmp.h
new file mode 100644
index 0000000..acec864
--- /dev/null
+++ b/third_party/gmp/config/arm/v7a/cora9/gmp.h
@@ -0,0 +1,2336 @@
+/* Definitions for GNU multiple precision functions.   -*- mode: c -*-
+
+Copyright 1991, 1993-1997, 1999-2016, 2020 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#ifndef __GMP_H__
+
+#if defined (__cplusplus)
+#include <iosfwd>   /* for std::istream, std::ostream, std::string */
+#include <cstdio>
+#endif
+
+
+/* Instantiated by configure. */
+#if ! defined (__GMP_WITHIN_CONFIGURE)
+#define __GMP_HAVE_HOST_CPU_FAMILY_power   0
+#define __GMP_HAVE_HOST_CPU_FAMILY_powerpc 0
+#define GMP_LIMB_BITS                      32
+#define GMP_NAIL_BITS                      0
+#endif
+#define GMP_NUMB_BITS     (GMP_LIMB_BITS - GMP_NAIL_BITS)
+#define GMP_NUMB_MASK     ((~ __GMP_CAST (mp_limb_t, 0)) >> GMP_NAIL_BITS)
+#define GMP_NUMB_MAX      GMP_NUMB_MASK
+#define GMP_NAIL_MASK     (~ GMP_NUMB_MASK)
+
+
+#ifndef __GNU_MP__
+#define __GNU_MP__ 6
+
+#include <stddef.h>    /* for size_t */
+#include <limits.h>
+
+/* Instantiated by configure. */
+#if ! defined (__GMP_WITHIN_CONFIGURE)
+/* #undef _LONG_LONG_LIMB */
+#define __GMP_LIBGMP_DLL  0
+#endif
+
+
+/* __GMP_DECLSPEC supports Windows DLL versions of libgmp, and is empty in
+   all other circumstances.
+
+   When compiling objects for libgmp, __GMP_DECLSPEC is an export directive,
+   or when compiling for an application it's an import directive.  The two
+   cases are differentiated by __GMP_WITHIN_GMP defined by the GMP Makefiles
+   (and not defined from an application).
+
+   __GMP_DECLSPEC_XX is similarly used for libgmpxx.  __GMP_WITHIN_GMPXX
+   indicates when building libgmpxx, and in that case libgmpxx functions are
+   exports, but libgmp functions which might get called are imports.
+
+   Libtool DLL_EXPORT define is not used.
+
+   There's no attempt to support GMP built both static and DLL.  Doing so
+   would mean applications would have to tell us which of the two is going
+   to be used when linking, and that seems very tedious and error prone if
+   using GMP by hand, and equally tedious from a package since autoconf and
+   automake don't give much help.
+
+   __GMP_DECLSPEC is required on all documented global functions and
+   variables, the various internals in gmp-impl.h etc can be left unadorned.
+   But internals used by the test programs or speed measuring programs
+   should have __GMP_DECLSPEC, and certainly constants or variables must
+   have it or the wrong address will be resolved.
+
+   In gcc __declspec can go at either the start or end of a prototype.
+
+   In Microsoft C __declspec must go at the start, or after the type like
+   void __declspec(...) *foo()".  There's no __dllexport or anything to
+   guard against someone foolish #defining dllexport.  _export used to be
+   available, but no longer.
+
+   In Borland C _export still exists, but needs to go after the type, like
+   "void _export foo();".  Would have to change the __GMP_DECLSPEC syntax to
+   make use of that.  Probably more trouble than it's worth.  */
+
+#if defined (__GNUC__)
+#define __GMP_DECLSPEC_EXPORT  __declspec(__dllexport__)
+#define __GMP_DECLSPEC_IMPORT  __declspec(__dllimport__)
+#endif
+#if defined (_MSC_VER) || defined (__BORLANDC__)
+#define __GMP_DECLSPEC_EXPORT  __declspec(dllexport)
+#define __GMP_DECLSPEC_IMPORT  __declspec(dllimport)
+#endif
+#ifdef __WATCOMC__
+#define __GMP_DECLSPEC_EXPORT  __export
+#define __GMP_DECLSPEC_IMPORT  __import
+#endif
+#ifdef __IBMC__
+#define __GMP_DECLSPEC_EXPORT  _Export
+#define __GMP_DECLSPEC_IMPORT  _Import
+#endif
+
+#if __GMP_LIBGMP_DLL
+#ifdef __GMP_WITHIN_GMP
+/* compiling to go into a DLL libgmp */
+#define __GMP_DECLSPEC  __GMP_DECLSPEC_EXPORT
+#else
+/* compiling to go into an application which will link to a DLL libgmp */
+#define __GMP_DECLSPEC  __GMP_DECLSPEC_IMPORT
+#endif
+#else
+/* all other cases */
+#define __GMP_DECLSPEC
+#endif
+
+
+#ifdef __GMP_SHORT_LIMB
+typedef unsigned int		mp_limb_t;
+typedef int			mp_limb_signed_t;
+#else
+#ifdef _LONG_LONG_LIMB
+typedef unsigned long long int	mp_limb_t;
+typedef long long int		mp_limb_signed_t;
+#else
+typedef unsigned long int	mp_limb_t;
+typedef long int		mp_limb_signed_t;
+#endif
+#endif
+typedef unsigned long int	mp_bitcnt_t;
+
+/* For reference, note that the name __mpz_struct gets into C++ mangled
+   function names, which means although the "__" suggests an internal, we
+   must leave this name for binary compatibility.  */
+typedef struct
+{
+  int _mp_alloc;		/* Number of *limbs* allocated and pointed
+				   to by the _mp_d field.  */
+  int _mp_size;			/* abs(_mp_size) is the number of limbs the
+				   last field points to.  If _mp_size is
+				   negative this is a negative number.  */
+  mp_limb_t *_mp_d;		/* Pointer to the limbs.  */
+} __mpz_struct;
+
+#endif /* __GNU_MP__ */
+
+
+typedef __mpz_struct MP_INT;    /* gmp 1 source compatibility */
+typedef __mpz_struct mpz_t[1];
+
+typedef mp_limb_t *		mp_ptr;
+typedef const mp_limb_t *	mp_srcptr;
+#if defined (_CRAY) && ! defined (_CRAYMPP)
+/* plain `int' is much faster (48 bits) */
+#define __GMP_MP_SIZE_T_INT     1
+typedef int			mp_size_t;
+typedef int			mp_exp_t;
+#else
+#define __GMP_MP_SIZE_T_INT     0
+typedef long int		mp_size_t;
+typedef long int		mp_exp_t;
+#endif
+
+typedef struct
+{
+  __mpz_struct _mp_num;
+  __mpz_struct _mp_den;
+} __mpq_struct;
+
+typedef __mpq_struct MP_RAT;    /* gmp 1 source compatibility */
+typedef __mpq_struct mpq_t[1];
+
+typedef struct
+{
+  int _mp_prec;			/* Max precision, in number of `mp_limb_t's.
+				   Set by mpf_init and modified by
+				   mpf_set_prec.  The area pointed to by the
+				   _mp_d field contains `prec' + 1 limbs.  */
+  int _mp_size;			/* abs(_mp_size) is the number of limbs the
+				   last field points to.  If _mp_size is
+				   negative this is a negative number.  */
+  mp_exp_t _mp_exp;		/* Exponent, in the base of `mp_limb_t'.  */
+  mp_limb_t *_mp_d;		/* Pointer to the limbs.  */
+} __mpf_struct;
+
+/* typedef __mpf_struct MP_FLOAT; */
+typedef __mpf_struct mpf_t[1];
+
+/* Available random number generation algorithms.  */
+typedef enum
+{
+  GMP_RAND_ALG_DEFAULT = 0,
+  GMP_RAND_ALG_LC = GMP_RAND_ALG_DEFAULT /* Linear congruential.  */
+} gmp_randalg_t;
+
+/* Random state struct.  */
+typedef struct
+{
+  mpz_t _mp_seed;	  /* _mp_d member points to state of the generator. */
+  gmp_randalg_t _mp_alg;  /* Currently unused. */
+  union {
+    void *_mp_lc;         /* Pointer to function pointers structure.  */
+  } _mp_algdata;
+} __gmp_randstate_struct;
+typedef __gmp_randstate_struct gmp_randstate_t[1];
+
+/* Types for function declarations in gmp files.  */
+/* ??? Should not pollute user name space with these ??? */
+typedef const __mpz_struct *mpz_srcptr;
+typedef __mpz_struct *mpz_ptr;
+typedef const __mpf_struct *mpf_srcptr;
+typedef __mpf_struct *mpf_ptr;
+typedef const __mpq_struct *mpq_srcptr;
+typedef __mpq_struct *mpq_ptr;
+
+
+#if __GMP_LIBGMP_DLL
+#ifdef __GMP_WITHIN_GMPXX
+/* compiling to go into a DLL libgmpxx */
+#define __GMP_DECLSPEC_XX  __GMP_DECLSPEC_EXPORT
+#else
+/* compiling to go into a application which will link to a DLL libgmpxx */
+#define __GMP_DECLSPEC_XX  __GMP_DECLSPEC_IMPORT
+#endif
+#else
+/* all other cases */
+#define __GMP_DECLSPEC_XX
+#endif
+
+
+#ifndef __MPN
+#define __MPN(x) __gmpn_##x
+#endif
+
+/* For reference, "defined(EOF)" cannot be used here.  In g++ 2.95.4,
+   <iostream> defines EOF but not FILE.  */
+#if defined (FILE)                                              \
+  || defined (H_STDIO)                                          \
+  || defined (_H_STDIO)               /* AIX */                 \
+  || defined (_STDIO_H)               /* glibc, Sun, SCO */     \
+  || defined (_STDIO_H_)              /* BSD, OSF */            \
+  || defined (__STDIO_H)              /* Borland */             \
+  || defined (__STDIO_H__)            /* IRIX */                \
+  || defined (_STDIO_INCLUDED)        /* HPUX */                \
+  || defined (__dj_include_stdio_h_)  /* DJGPP */               \
+  || defined (_FILE_DEFINED)          /* Microsoft */           \
+  || defined (__STDIO__)              /* Apple MPW MrC */       \
+  || defined (_MSL_STDIO_H)           /* Metrowerks */          \
+  || defined (_STDIO_H_INCLUDED)      /* QNX4 */		\
+  || defined (_ISO_STDIO_ISO_H)       /* Sun C++ */		\
+  || defined (__STDIO_LOADED)         /* VMS */			\
+  || defined (__DEFINED_FILE)         /* musl */
+#define _GMP_H_HAVE_FILE 1
+#endif
+
+/* In ISO C, if a prototype involving "struct obstack *" is given without
+   that structure defined, then the struct is scoped down to just the
+   prototype, causing a conflict if it's subsequently defined for real.  So
+   only give prototypes if we've got obstack.h.  */
+#if defined (_OBSTACK_H)   /* glibc <obstack.h> */
+#define _GMP_H_HAVE_OBSTACK 1
+#endif
+
+/* The prototypes for gmp_vprintf etc are provided only if va_list is defined,
+   via an application having included <stdarg.h>.  Usually va_list is a typedef
+   so can't be tested directly, but C99 specifies that va_start is a macro.
+
+   <stdio.h> will define some sort of va_list for vprintf and vfprintf, but
+   let's not bother trying to use that since it's not standard and since
+   application uses for gmp_vprintf etc will almost certainly require the
+   whole <stdarg.h> anyway.  */
+
+#ifdef va_start
+#define _GMP_H_HAVE_VA_LIST 1
+#endif
+
+/* Test for gcc >= maj.min, as per __GNUC_PREREQ in glibc */
+#if defined (__GNUC__) && defined (__GNUC_MINOR__)
+#define __GMP_GNUC_PREREQ(maj, min) \
+  ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
+#else
+#define __GMP_GNUC_PREREQ(maj, min)  0
+#endif
+
+/* "pure" is in gcc 2.96 and up, see "(gcc)Function Attributes".  Basically
+   it means a function does nothing but examine its arguments and memory
+   (global or via arguments) to generate a return value, but changes nothing
+   and has no side-effects.  __GMP_NO_ATTRIBUTE_CONST_PURE lets
+   tune/common.c etc turn this off when trying to write timing loops.  */
+#if __GMP_GNUC_PREREQ (2,96) && ! defined (__GMP_NO_ATTRIBUTE_CONST_PURE)
+#define __GMP_ATTRIBUTE_PURE   __attribute__ ((__pure__))
+#else
+#define __GMP_ATTRIBUTE_PURE
+#endif
+
+
+/* __GMP_CAST allows us to use static_cast in C++, so our macros are clean
+   to "g++ -Wold-style-cast".
+
+   Casts in "extern inline" code within an extern "C" block don't induce
+   these warnings, so __GMP_CAST only needs to be used on documented
+   macros.  */
+
+#ifdef __cplusplus
+#define __GMP_CAST(type, expr)  (static_cast<type> (expr))
+#else
+#define __GMP_CAST(type, expr)  ((type) (expr))
+#endif
+
+
+/* An empty "throw ()" means the function doesn't throw any C++ exceptions,
+   this can save some stack frame info in applications.
+
+   Currently it's given only on functions which never divide-by-zero etc,
+   don't allocate memory, and are expected to never need to allocate memory.
+   This leaves open the possibility of a C++ throw from a future GMP
+   exceptions scheme.
+
+   mpz_set_ui etc are omitted to leave open the lazy allocation scheme
+   described in doc/tasks.html.  mpz_get_d etc are omitted to leave open
+   exceptions for float overflows.
+
+   Note that __GMP_NOTHROW must be given on any inlines the same as on their
+   prototypes (for g++ at least, where they're used together).  Note also
+   that g++ 3.0 demands that __GMP_NOTHROW is before other attributes like
+   __GMP_ATTRIBUTE_PURE.  */
+
+#if defined (__cplusplus)
+#if __cplusplus >= 201103L
+#define __GMP_NOTHROW  noexcept
+#else
+#define __GMP_NOTHROW  throw ()
+#endif
+#else
+#define __GMP_NOTHROW
+#endif
+
+
+/* PORTME: What other compilers have a useful "extern inline"?  "static
+   inline" would be an acceptable substitute if the compiler (or linker)
+   discards unused statics.  */
+
+ /* gcc has __inline__ in all modes, including strict ansi.  Give a prototype
+    for an inline too, so as to correctly specify "dllimport" on windows, in
+    case the function is called rather than inlined.
+    GCC 4.3 and above with -std=c99 or -std=gnu99 implements ISO C99
+    inline semantics, unless -fgnu89-inline is used.  */
+#ifdef __GNUC__
+#if (defined __GNUC_STDC_INLINE__) || (__GNUC__ == 4 && __GNUC_MINOR__ == 2) \
+  || (defined __GNUC_GNU_INLINE__ && defined __cplusplus)
+#define __GMP_EXTERN_INLINE extern __inline__ __attribute__ ((__gnu_inline__))
+#else
+#define __GMP_EXTERN_INLINE      extern __inline__
+#endif
+#define __GMP_INLINE_PROTOTYPES  1
+#endif
+
+/* DEC C (eg. version 5.9) supports "static __inline foo()", even in -std1
+   strict ANSI mode.  Inlining is done even when not optimizing (ie. -O0
+   mode, which is the default), but an unnecessary local copy of foo is
+   emitted unless -O is used.  "extern __inline" is accepted, but the
+   "extern" appears to be ignored, ie. it becomes a plain global function
+   but which is inlined within its file.  Don't know if all old versions of
+   DEC C supported __inline, but as a start let's do the right thing for
+   current versions.  */
+#ifdef __DECC
+#define __GMP_EXTERN_INLINE  static __inline
+#endif
+
+/* SCO OpenUNIX 8 cc supports "static inline foo()" but not in -Xc strict
+   ANSI mode (__STDC__ is 1 in that mode).  Inlining only actually takes
+   place under -O.  Without -O "foo" seems to be emitted whether it's used
+   or not, which is wasteful.  "extern inline foo()" isn't useful, the
+   "extern" is apparently ignored, so foo is inlined if possible but also
+   emitted as a global, which causes multiple definition errors when
+   building a shared libgmp.  */
+#ifdef __SCO_VERSION__
+#if __SCO_VERSION__ > 400000000 && __STDC__ != 1 \
+  && ! defined (__GMP_EXTERN_INLINE)
+#define __GMP_EXTERN_INLINE  static inline
+#endif
+#endif
+
+/* Microsoft's C compiler accepts __inline */
+#ifdef _MSC_VER
+#define __GMP_EXTERN_INLINE  __inline
+#endif
+
+/* Recent enough Sun C compilers want "inline" */
+#if defined (__SUNPRO_C) && __SUNPRO_C >= 0x560 \
+  && ! defined (__GMP_EXTERN_INLINE)
+#define __GMP_EXTERN_INLINE  inline
+#endif
+
+/* Somewhat older Sun C compilers want "static inline" */
+#if defined (__SUNPRO_C) && __SUNPRO_C >= 0x540 \
+  && ! defined (__GMP_EXTERN_INLINE)
+#define __GMP_EXTERN_INLINE  static inline
+#endif
+
+
+/* C++ always has "inline" and since it's a normal feature the linker should
+   discard duplicate non-inlined copies, or if it doesn't then that's a
+   problem for everyone, not just GMP.  */
+#if defined (__cplusplus) && ! defined (__GMP_EXTERN_INLINE)
+#define __GMP_EXTERN_INLINE  inline
+#endif
+
+/* Don't do any inlining within a configure run, since if the compiler ends
+   up emitting copies of the code into the object file it can end up
+   demanding the various support routines (like mpn_popcount) for linking,
+   making the "alloca" test and perhaps others fail.  And on hppa ia64 a
+   pre-release gcc 3.2 was seen not respecting the "extern" in "extern
+   __inline__", triggering this problem too.  */
+#if defined (__GMP_WITHIN_CONFIGURE) && ! __GMP_WITHIN_CONFIGURE_INLINE
+#undef __GMP_EXTERN_INLINE
+#endif
+
+/* By default, don't give a prototype when there's going to be an inline
+   version.  Note in particular that Cray C++ objects to the combination of
+   prototype and inline.  */
+#ifdef __GMP_EXTERN_INLINE
+#ifndef __GMP_INLINE_PROTOTYPES
+#define __GMP_INLINE_PROTOTYPES  0
+#endif
+#else
+#define __GMP_INLINE_PROTOTYPES  1
+#endif
+
+
+#define __GMP_ABS(x)   ((x) >= 0 ? (x) : -(x))
+#define __GMP_MAX(h,i) ((h) > (i) ? (h) : (i))
+
+
+/* __builtin_expect is in gcc 3.0, and not in 2.95. */
+#if __GMP_GNUC_PREREQ (3,0)
+#define __GMP_LIKELY(cond)    __builtin_expect ((cond) != 0, 1)
+#define __GMP_UNLIKELY(cond)  __builtin_expect ((cond) != 0, 0)
+#else
+#define __GMP_LIKELY(cond)    (cond)
+#define __GMP_UNLIKELY(cond)  (cond)
+#endif
+
+#ifdef _CRAY
+#define __GMP_CRAY_Pragma(str)  _Pragma (str)
+#else
+#define __GMP_CRAY_Pragma(str)
+#endif
+
+
+/* Allow direct user access to numerator and denominator of an mpq_t object.  */
+#define mpq_numref(Q) (&((Q)->_mp_num))
+#define mpq_denref(Q) (&((Q)->_mp_den))
+
+
+#if defined (__cplusplus)
+extern "C" {
+using std::FILE;
+#endif
+
+#define mp_set_memory_functions __gmp_set_memory_functions
+__GMP_DECLSPEC void mp_set_memory_functions (void *(*) (size_t),
+				      void *(*) (void *, size_t, size_t),
+				      void (*) (void *, size_t)) __GMP_NOTHROW;
+
+#define mp_get_memory_functions __gmp_get_memory_functions
+__GMP_DECLSPEC void mp_get_memory_functions (void *(**) (size_t),
+				      void *(**) (void *, size_t, size_t),
+				      void (**) (void *, size_t)) __GMP_NOTHROW;
+
+#define mp_bits_per_limb __gmp_bits_per_limb
+__GMP_DECLSPEC extern const int mp_bits_per_limb;
+
+#define gmp_errno __gmp_errno
+__GMP_DECLSPEC extern int gmp_errno;
+
+#define gmp_version __gmp_version
+__GMP_DECLSPEC extern const char * const gmp_version;
+
+
+/**************** Random number routines.  ****************/
+
+/* obsolete */
+#define gmp_randinit __gmp_randinit
+__GMP_DECLSPEC void gmp_randinit (gmp_randstate_t, gmp_randalg_t, ...);
+
+#define gmp_randinit_default __gmp_randinit_default
+__GMP_DECLSPEC void gmp_randinit_default (gmp_randstate_t);
+
+#define gmp_randinit_lc_2exp __gmp_randinit_lc_2exp
+__GMP_DECLSPEC void gmp_randinit_lc_2exp (gmp_randstate_t, mpz_srcptr, unsigned long int, mp_bitcnt_t);
+
+#define gmp_randinit_lc_2exp_size __gmp_randinit_lc_2exp_size
+__GMP_DECLSPEC int gmp_randinit_lc_2exp_size (gmp_randstate_t, mp_bitcnt_t);
+
+#define gmp_randinit_mt __gmp_randinit_mt
+__GMP_DECLSPEC void gmp_randinit_mt (gmp_randstate_t);
+
+#define gmp_randinit_set __gmp_randinit_set
+__GMP_DECLSPEC void gmp_randinit_set (gmp_randstate_t, const __gmp_randstate_struct *);
+
+#define gmp_randseed __gmp_randseed
+__GMP_DECLSPEC void gmp_randseed (gmp_randstate_t, mpz_srcptr);
+
+#define gmp_randseed_ui __gmp_randseed_ui
+__GMP_DECLSPEC void gmp_randseed_ui (gmp_randstate_t, unsigned long int);
+
+#define gmp_randclear __gmp_randclear
+__GMP_DECLSPEC void gmp_randclear (gmp_randstate_t);
+
+#define gmp_urandomb_ui __gmp_urandomb_ui
+__GMP_DECLSPEC unsigned long gmp_urandomb_ui (gmp_randstate_t, unsigned long);
+
+#define gmp_urandomm_ui __gmp_urandomm_ui
+__GMP_DECLSPEC unsigned long gmp_urandomm_ui (gmp_randstate_t, unsigned long);
+
+
+/**************** Formatted output routines.  ****************/
+
+#define gmp_asprintf __gmp_asprintf
+__GMP_DECLSPEC int gmp_asprintf (char **, const char *, ...);
+
+#define gmp_fprintf __gmp_fprintf
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC int gmp_fprintf (FILE *, const char *, ...);
+#endif
+
+#define gmp_obstack_printf __gmp_obstack_printf
+#if defined (_GMP_H_HAVE_OBSTACK)
+__GMP_DECLSPEC int gmp_obstack_printf (struct obstack *, const char *, ...);
+#endif
+
+#define gmp_obstack_vprintf __gmp_obstack_vprintf
+#if defined (_GMP_H_HAVE_OBSTACK) && defined (_GMP_H_HAVE_VA_LIST)
+__GMP_DECLSPEC int gmp_obstack_vprintf (struct obstack *, const char *, va_list);
+#endif
+
+#define gmp_printf __gmp_printf
+__GMP_DECLSPEC int gmp_printf (const char *, ...);
+
+#define gmp_snprintf __gmp_snprintf
+__GMP_DECLSPEC int gmp_snprintf (char *, size_t, const char *, ...);
+
+#define gmp_sprintf __gmp_sprintf
+__GMP_DECLSPEC int gmp_sprintf (char *, const char *, ...);
+
+#define gmp_vasprintf __gmp_vasprintf
+#if defined (_GMP_H_HAVE_VA_LIST)
+__GMP_DECLSPEC int gmp_vasprintf (char **, const char *, va_list);
+#endif
+
+#define gmp_vfprintf __gmp_vfprintf
+#if defined (_GMP_H_HAVE_FILE) && defined (_GMP_H_HAVE_VA_LIST)
+__GMP_DECLSPEC int gmp_vfprintf (FILE *, const char *, va_list);
+#endif
+
+#define gmp_vprintf __gmp_vprintf
+#if defined (_GMP_H_HAVE_VA_LIST)
+__GMP_DECLSPEC int gmp_vprintf (const char *, va_list);
+#endif
+
+#define gmp_vsnprintf __gmp_vsnprintf
+#if defined (_GMP_H_HAVE_VA_LIST)
+__GMP_DECLSPEC int gmp_vsnprintf (char *, size_t, const char *, va_list);
+#endif
+
+#define gmp_vsprintf __gmp_vsprintf
+#if defined (_GMP_H_HAVE_VA_LIST)
+__GMP_DECLSPEC int gmp_vsprintf (char *, const char *, va_list);
+#endif
+
+
+/**************** Formatted input routines.  ****************/
+
+#define gmp_fscanf __gmp_fscanf
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC int gmp_fscanf (FILE *, const char *, ...);
+#endif
+
+#define gmp_scanf __gmp_scanf
+__GMP_DECLSPEC int gmp_scanf (const char *, ...);
+
+#define gmp_sscanf __gmp_sscanf
+__GMP_DECLSPEC int gmp_sscanf (const char *, const char *, ...);
+
+#define gmp_vfscanf __gmp_vfscanf
+#if defined (_GMP_H_HAVE_FILE) && defined (_GMP_H_HAVE_VA_LIST)
+__GMP_DECLSPEC int gmp_vfscanf (FILE *, const char *, va_list);
+#endif
+
+#define gmp_vscanf __gmp_vscanf
+#if defined (_GMP_H_HAVE_VA_LIST)
+__GMP_DECLSPEC int gmp_vscanf (const char *, va_list);
+#endif
+
+#define gmp_vsscanf __gmp_vsscanf
+#if defined (_GMP_H_HAVE_VA_LIST)
+__GMP_DECLSPEC int gmp_vsscanf (const char *, const char *, va_list);
+#endif
+
+
+/**************** Integer (i.e. Z) routines.  ****************/
+
+#define _mpz_realloc __gmpz_realloc
+#define mpz_realloc __gmpz_realloc
+__GMP_DECLSPEC void *_mpz_realloc (mpz_ptr, mp_size_t);
+
+#define mpz_abs __gmpz_abs
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_abs)
+__GMP_DECLSPEC void mpz_abs (mpz_ptr, mpz_srcptr);
+#endif
+
+#define mpz_add __gmpz_add
+__GMP_DECLSPEC void mpz_add (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_add_ui __gmpz_add_ui
+__GMP_DECLSPEC void mpz_add_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_addmul __gmpz_addmul
+__GMP_DECLSPEC void mpz_addmul (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_addmul_ui __gmpz_addmul_ui
+__GMP_DECLSPEC void mpz_addmul_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_and __gmpz_and
+__GMP_DECLSPEC void mpz_and (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_array_init __gmpz_array_init
+__GMP_DECLSPEC void mpz_array_init (mpz_ptr, mp_size_t, mp_size_t);
+
+#define mpz_bin_ui __gmpz_bin_ui
+__GMP_DECLSPEC void mpz_bin_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_bin_uiui __gmpz_bin_uiui
+__GMP_DECLSPEC void mpz_bin_uiui (mpz_ptr, unsigned long int, unsigned long int);
+
+#define mpz_cdiv_q __gmpz_cdiv_q
+__GMP_DECLSPEC void mpz_cdiv_q (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_cdiv_q_2exp __gmpz_cdiv_q_2exp
+__GMP_DECLSPEC void mpz_cdiv_q_2exp (mpz_ptr, mpz_srcptr, mp_bitcnt_t);
+
+#define mpz_cdiv_q_ui __gmpz_cdiv_q_ui
+__GMP_DECLSPEC unsigned long int mpz_cdiv_q_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_cdiv_qr __gmpz_cdiv_qr
+__GMP_DECLSPEC void mpz_cdiv_qr (mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_cdiv_qr_ui __gmpz_cdiv_qr_ui
+__GMP_DECLSPEC unsigned long int mpz_cdiv_qr_ui (mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_cdiv_r __gmpz_cdiv_r
+__GMP_DECLSPEC void mpz_cdiv_r (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_cdiv_r_2exp __gmpz_cdiv_r_2exp
+__GMP_DECLSPEC void mpz_cdiv_r_2exp (mpz_ptr, mpz_srcptr, mp_bitcnt_t);
+
+#define mpz_cdiv_r_ui __gmpz_cdiv_r_ui
+__GMP_DECLSPEC unsigned long int mpz_cdiv_r_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_cdiv_ui __gmpz_cdiv_ui
+__GMP_DECLSPEC unsigned long int mpz_cdiv_ui (mpz_srcptr, unsigned long int) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_clear __gmpz_clear
+__GMP_DECLSPEC void mpz_clear (mpz_ptr);
+
+#define mpz_clears __gmpz_clears
+__GMP_DECLSPEC void mpz_clears (mpz_ptr, ...);
+
+#define mpz_clrbit __gmpz_clrbit
+__GMP_DECLSPEC void mpz_clrbit (mpz_ptr, mp_bitcnt_t);
+
+#define mpz_cmp __gmpz_cmp
+__GMP_DECLSPEC int mpz_cmp (mpz_srcptr, mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_cmp_d __gmpz_cmp_d
+__GMP_DECLSPEC int mpz_cmp_d (mpz_srcptr, double) __GMP_ATTRIBUTE_PURE;
+
+#define _mpz_cmp_si __gmpz_cmp_si
+__GMP_DECLSPEC int _mpz_cmp_si (mpz_srcptr, signed long int) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define _mpz_cmp_ui __gmpz_cmp_ui
+__GMP_DECLSPEC int _mpz_cmp_ui (mpz_srcptr, unsigned long int) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_cmpabs __gmpz_cmpabs
+__GMP_DECLSPEC int mpz_cmpabs (mpz_srcptr, mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_cmpabs_d __gmpz_cmpabs_d
+__GMP_DECLSPEC int mpz_cmpabs_d (mpz_srcptr, double) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_cmpabs_ui __gmpz_cmpabs_ui
+__GMP_DECLSPEC int mpz_cmpabs_ui (mpz_srcptr, unsigned long int) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_com __gmpz_com
+__GMP_DECLSPEC void mpz_com (mpz_ptr, mpz_srcptr);
+
+#define mpz_combit __gmpz_combit
+__GMP_DECLSPEC void mpz_combit (mpz_ptr, mp_bitcnt_t);
+
+#define mpz_congruent_p __gmpz_congruent_p
+__GMP_DECLSPEC int mpz_congruent_p (mpz_srcptr, mpz_srcptr, mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_congruent_2exp_p __gmpz_congruent_2exp_p
+__GMP_DECLSPEC int mpz_congruent_2exp_p (mpz_srcptr, mpz_srcptr, mp_bitcnt_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_congruent_ui_p __gmpz_congruent_ui_p
+__GMP_DECLSPEC int mpz_congruent_ui_p (mpz_srcptr, unsigned long, unsigned long) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_divexact __gmpz_divexact
+__GMP_DECLSPEC void mpz_divexact (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_divexact_ui __gmpz_divexact_ui
+__GMP_DECLSPEC void mpz_divexact_ui (mpz_ptr, mpz_srcptr, unsigned long);
+
+#define mpz_divisible_p __gmpz_divisible_p
+__GMP_DECLSPEC int mpz_divisible_p (mpz_srcptr, mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_divisible_ui_p __gmpz_divisible_ui_p
+__GMP_DECLSPEC int mpz_divisible_ui_p (mpz_srcptr, unsigned long) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_divisible_2exp_p __gmpz_divisible_2exp_p
+__GMP_DECLSPEC int mpz_divisible_2exp_p (mpz_srcptr, mp_bitcnt_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_dump __gmpz_dump
+__GMP_DECLSPEC void mpz_dump (mpz_srcptr);
+
+#define mpz_export __gmpz_export
+__GMP_DECLSPEC void *mpz_export (void *, size_t *, int, size_t, int, size_t, mpz_srcptr);
+
+#define mpz_fac_ui __gmpz_fac_ui
+__GMP_DECLSPEC void mpz_fac_ui (mpz_ptr, unsigned long int);
+
+#define mpz_2fac_ui __gmpz_2fac_ui
+__GMP_DECLSPEC void mpz_2fac_ui (mpz_ptr, unsigned long int);
+
+#define mpz_mfac_uiui __gmpz_mfac_uiui
+__GMP_DECLSPEC void mpz_mfac_uiui (mpz_ptr, unsigned long int, unsigned long int);
+
+#define mpz_primorial_ui __gmpz_primorial_ui
+__GMP_DECLSPEC void mpz_primorial_ui (mpz_ptr, unsigned long int);
+
+#define mpz_fdiv_q __gmpz_fdiv_q
+__GMP_DECLSPEC void mpz_fdiv_q (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_fdiv_q_2exp __gmpz_fdiv_q_2exp
+__GMP_DECLSPEC void mpz_fdiv_q_2exp (mpz_ptr, mpz_srcptr, mp_bitcnt_t);
+
+#define mpz_fdiv_q_ui __gmpz_fdiv_q_ui
+__GMP_DECLSPEC unsigned long int mpz_fdiv_q_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_fdiv_qr __gmpz_fdiv_qr
+__GMP_DECLSPEC void mpz_fdiv_qr (mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_fdiv_qr_ui __gmpz_fdiv_qr_ui
+__GMP_DECLSPEC unsigned long int mpz_fdiv_qr_ui (mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_fdiv_r __gmpz_fdiv_r
+__GMP_DECLSPEC void mpz_fdiv_r (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_fdiv_r_2exp __gmpz_fdiv_r_2exp
+__GMP_DECLSPEC void mpz_fdiv_r_2exp (mpz_ptr, mpz_srcptr, mp_bitcnt_t);
+
+#define mpz_fdiv_r_ui __gmpz_fdiv_r_ui
+__GMP_DECLSPEC unsigned long int mpz_fdiv_r_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_fdiv_ui __gmpz_fdiv_ui
+__GMP_DECLSPEC unsigned long int mpz_fdiv_ui (mpz_srcptr, unsigned long int) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_fib_ui __gmpz_fib_ui
+__GMP_DECLSPEC void mpz_fib_ui (mpz_ptr, unsigned long int);
+
+#define mpz_fib2_ui __gmpz_fib2_ui
+__GMP_DECLSPEC void mpz_fib2_ui (mpz_ptr, mpz_ptr, unsigned long int);
+
+#define mpz_fits_sint_p __gmpz_fits_sint_p
+__GMP_DECLSPEC int mpz_fits_sint_p (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_fits_slong_p __gmpz_fits_slong_p
+__GMP_DECLSPEC int mpz_fits_slong_p (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_fits_sshort_p __gmpz_fits_sshort_p
+__GMP_DECLSPEC int mpz_fits_sshort_p (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_fits_uint_p __gmpz_fits_uint_p
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_fits_uint_p)
+__GMP_DECLSPEC int mpz_fits_uint_p (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpz_fits_ulong_p __gmpz_fits_ulong_p
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_fits_ulong_p)
+__GMP_DECLSPEC int mpz_fits_ulong_p (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpz_fits_ushort_p __gmpz_fits_ushort_p
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_fits_ushort_p)
+__GMP_DECLSPEC int mpz_fits_ushort_p (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpz_gcd __gmpz_gcd
+__GMP_DECLSPEC void mpz_gcd (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_gcd_ui __gmpz_gcd_ui
+__GMP_DECLSPEC unsigned long int mpz_gcd_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_gcdext __gmpz_gcdext
+__GMP_DECLSPEC void mpz_gcdext (mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_get_d __gmpz_get_d
+__GMP_DECLSPEC double mpz_get_d (mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_get_d_2exp __gmpz_get_d_2exp
+__GMP_DECLSPEC double mpz_get_d_2exp (signed long int *, mpz_srcptr);
+
+#define mpz_get_si __gmpz_get_si
+__GMP_DECLSPEC /* signed */ long int mpz_get_si (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_get_str __gmpz_get_str
+__GMP_DECLSPEC char *mpz_get_str (char *, int, mpz_srcptr);
+
+#define mpz_get_ui __gmpz_get_ui
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_get_ui)
+__GMP_DECLSPEC unsigned long int mpz_get_ui (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpz_getlimbn __gmpz_getlimbn
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_getlimbn)
+__GMP_DECLSPEC mp_limb_t mpz_getlimbn (mpz_srcptr, mp_size_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpz_hamdist __gmpz_hamdist
+__GMP_DECLSPEC mp_bitcnt_t mpz_hamdist (mpz_srcptr, mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_import __gmpz_import
+__GMP_DECLSPEC void mpz_import (mpz_ptr, size_t, int, size_t, int, size_t, const void *);
+
+#define mpz_init __gmpz_init
+__GMP_DECLSPEC void mpz_init (mpz_ptr) __GMP_NOTHROW;
+
+#define mpz_init2 __gmpz_init2
+__GMP_DECLSPEC void mpz_init2 (mpz_ptr, mp_bitcnt_t);
+
+#define mpz_inits __gmpz_inits
+__GMP_DECLSPEC void mpz_inits (mpz_ptr, ...) __GMP_NOTHROW;
+
+#define mpz_init_set __gmpz_init_set
+__GMP_DECLSPEC void mpz_init_set (mpz_ptr, mpz_srcptr);
+
+#define mpz_init_set_d __gmpz_init_set_d
+__GMP_DECLSPEC void mpz_init_set_d (mpz_ptr, double);
+
+#define mpz_init_set_si __gmpz_init_set_si
+__GMP_DECLSPEC void mpz_init_set_si (mpz_ptr, signed long int);
+
+#define mpz_init_set_str __gmpz_init_set_str
+__GMP_DECLSPEC int mpz_init_set_str (mpz_ptr, const char *, int);
+
+#define mpz_init_set_ui __gmpz_init_set_ui
+__GMP_DECLSPEC void mpz_init_set_ui (mpz_ptr, unsigned long int);
+
+#define mpz_inp_raw __gmpz_inp_raw
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC size_t mpz_inp_raw (mpz_ptr, FILE *);
+#endif
+
+#define mpz_inp_str __gmpz_inp_str
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC size_t mpz_inp_str (mpz_ptr, FILE *, int);
+#endif
+
+#define mpz_invert __gmpz_invert
+__GMP_DECLSPEC int mpz_invert (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_ior __gmpz_ior
+__GMP_DECLSPEC void mpz_ior (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_jacobi __gmpz_jacobi
+__GMP_DECLSPEC int mpz_jacobi (mpz_srcptr, mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_kronecker mpz_jacobi  /* alias */
+
+#define mpz_kronecker_si __gmpz_kronecker_si
+__GMP_DECLSPEC int mpz_kronecker_si (mpz_srcptr, long) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_kronecker_ui __gmpz_kronecker_ui
+__GMP_DECLSPEC int mpz_kronecker_ui (mpz_srcptr, unsigned long) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_si_kronecker __gmpz_si_kronecker
+__GMP_DECLSPEC int mpz_si_kronecker (long, mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_ui_kronecker __gmpz_ui_kronecker
+__GMP_DECLSPEC int mpz_ui_kronecker (unsigned long, mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_lcm __gmpz_lcm
+__GMP_DECLSPEC void mpz_lcm (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_lcm_ui __gmpz_lcm_ui
+__GMP_DECLSPEC void mpz_lcm_ui (mpz_ptr, mpz_srcptr, unsigned long);
+
+#define mpz_legendre mpz_jacobi  /* alias */
+
+#define mpz_lucnum_ui __gmpz_lucnum_ui
+__GMP_DECLSPEC void mpz_lucnum_ui (mpz_ptr, unsigned long int);
+
+#define mpz_lucnum2_ui __gmpz_lucnum2_ui
+__GMP_DECLSPEC void mpz_lucnum2_ui (mpz_ptr, mpz_ptr, unsigned long int);
+
+#define mpz_millerrabin __gmpz_millerrabin
+__GMP_DECLSPEC int mpz_millerrabin (mpz_srcptr, int) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_mod __gmpz_mod
+__GMP_DECLSPEC void mpz_mod (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_mod_ui mpz_fdiv_r_ui /* same as fdiv_r because divisor unsigned */
+
+#define mpz_mul __gmpz_mul
+__GMP_DECLSPEC void mpz_mul (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_mul_2exp __gmpz_mul_2exp
+__GMP_DECLSPEC void mpz_mul_2exp (mpz_ptr, mpz_srcptr, mp_bitcnt_t);
+
+#define mpz_mul_si __gmpz_mul_si
+__GMP_DECLSPEC void mpz_mul_si (mpz_ptr, mpz_srcptr, long int);
+
+#define mpz_mul_ui __gmpz_mul_ui
+__GMP_DECLSPEC void mpz_mul_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_neg __gmpz_neg
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_neg)
+__GMP_DECLSPEC void mpz_neg (mpz_ptr, mpz_srcptr);
+#endif
+
+#define mpz_nextprime __gmpz_nextprime
+__GMP_DECLSPEC void mpz_nextprime (mpz_ptr, mpz_srcptr);
+
+#define mpz_out_raw __gmpz_out_raw
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC size_t mpz_out_raw (FILE *, mpz_srcptr);
+#endif
+
+#define mpz_out_str __gmpz_out_str
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC size_t mpz_out_str (FILE *, int, mpz_srcptr);
+#endif
+
+#define mpz_perfect_power_p __gmpz_perfect_power_p
+__GMP_DECLSPEC int mpz_perfect_power_p (mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_perfect_square_p __gmpz_perfect_square_p
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_perfect_square_p)
+__GMP_DECLSPEC int mpz_perfect_square_p (mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpz_popcount __gmpz_popcount
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_popcount)
+__GMP_DECLSPEC mp_bitcnt_t mpz_popcount (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpz_pow_ui __gmpz_pow_ui
+__GMP_DECLSPEC void mpz_pow_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_powm __gmpz_powm
+__GMP_DECLSPEC void mpz_powm (mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_powm_sec __gmpz_powm_sec
+__GMP_DECLSPEC void mpz_powm_sec (mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_powm_ui __gmpz_powm_ui
+__GMP_DECLSPEC void mpz_powm_ui (mpz_ptr, mpz_srcptr, unsigned long int, mpz_srcptr);
+
+#define mpz_probab_prime_p __gmpz_probab_prime_p
+__GMP_DECLSPEC int mpz_probab_prime_p (mpz_srcptr, int) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_random __gmpz_random
+__GMP_DECLSPEC void mpz_random (mpz_ptr, mp_size_t);
+
+#define mpz_random2 __gmpz_random2
+__GMP_DECLSPEC void mpz_random2 (mpz_ptr, mp_size_t);
+
+#define mpz_realloc2 __gmpz_realloc2
+__GMP_DECLSPEC void mpz_realloc2 (mpz_ptr, mp_bitcnt_t);
+
+#define mpz_remove __gmpz_remove
+__GMP_DECLSPEC mp_bitcnt_t mpz_remove (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_root __gmpz_root
+__GMP_DECLSPEC int mpz_root (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_rootrem __gmpz_rootrem
+__GMP_DECLSPEC void mpz_rootrem (mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_rrandomb __gmpz_rrandomb
+__GMP_DECLSPEC void mpz_rrandomb (mpz_ptr, gmp_randstate_t, mp_bitcnt_t);
+
+#define mpz_scan0 __gmpz_scan0
+__GMP_DECLSPEC mp_bitcnt_t mpz_scan0 (mpz_srcptr, mp_bitcnt_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_scan1 __gmpz_scan1
+__GMP_DECLSPEC mp_bitcnt_t mpz_scan1 (mpz_srcptr, mp_bitcnt_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_set __gmpz_set
+__GMP_DECLSPEC void mpz_set (mpz_ptr, mpz_srcptr);
+
+#define mpz_set_d __gmpz_set_d
+__GMP_DECLSPEC void mpz_set_d (mpz_ptr, double);
+
+#define mpz_set_f __gmpz_set_f
+__GMP_DECLSPEC void mpz_set_f (mpz_ptr, mpf_srcptr);
+
+#define mpz_set_q __gmpz_set_q
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_set_q)
+__GMP_DECLSPEC void mpz_set_q (mpz_ptr, mpq_srcptr);
+#endif
+
+#define mpz_set_si __gmpz_set_si
+__GMP_DECLSPEC void mpz_set_si (mpz_ptr, signed long int);
+
+#define mpz_set_str __gmpz_set_str
+__GMP_DECLSPEC int mpz_set_str (mpz_ptr, const char *, int);
+
+#define mpz_set_ui __gmpz_set_ui
+__GMP_DECLSPEC void mpz_set_ui (mpz_ptr, unsigned long int);
+
+#define mpz_setbit __gmpz_setbit
+__GMP_DECLSPEC void mpz_setbit (mpz_ptr, mp_bitcnt_t);
+
+#define mpz_size __gmpz_size
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_size)
+__GMP_DECLSPEC size_t mpz_size (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpz_sizeinbase __gmpz_sizeinbase
+__GMP_DECLSPEC size_t mpz_sizeinbase (mpz_srcptr, int) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_sqrt __gmpz_sqrt
+__GMP_DECLSPEC void mpz_sqrt (mpz_ptr, mpz_srcptr);
+
+#define mpz_sqrtrem __gmpz_sqrtrem
+__GMP_DECLSPEC void mpz_sqrtrem (mpz_ptr, mpz_ptr, mpz_srcptr);
+
+#define mpz_sub __gmpz_sub
+__GMP_DECLSPEC void mpz_sub (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_sub_ui __gmpz_sub_ui
+__GMP_DECLSPEC void mpz_sub_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_ui_sub __gmpz_ui_sub
+__GMP_DECLSPEC void mpz_ui_sub (mpz_ptr, unsigned long int, mpz_srcptr);
+
+#define mpz_submul __gmpz_submul
+__GMP_DECLSPEC void mpz_submul (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_submul_ui __gmpz_submul_ui
+__GMP_DECLSPEC void mpz_submul_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_swap __gmpz_swap
+__GMP_DECLSPEC void mpz_swap (mpz_ptr, mpz_ptr) __GMP_NOTHROW;
+
+#define mpz_tdiv_ui __gmpz_tdiv_ui
+__GMP_DECLSPEC unsigned long int mpz_tdiv_ui (mpz_srcptr, unsigned long int) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_tdiv_q __gmpz_tdiv_q
+__GMP_DECLSPEC void mpz_tdiv_q (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_tdiv_q_2exp __gmpz_tdiv_q_2exp
+__GMP_DECLSPEC void mpz_tdiv_q_2exp (mpz_ptr, mpz_srcptr, mp_bitcnt_t);
+
+#define mpz_tdiv_q_ui __gmpz_tdiv_q_ui
+__GMP_DECLSPEC unsigned long int mpz_tdiv_q_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_tdiv_qr __gmpz_tdiv_qr
+__GMP_DECLSPEC void mpz_tdiv_qr (mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_tdiv_qr_ui __gmpz_tdiv_qr_ui
+__GMP_DECLSPEC unsigned long int mpz_tdiv_qr_ui (mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_tdiv_r __gmpz_tdiv_r
+__GMP_DECLSPEC void mpz_tdiv_r (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_tdiv_r_2exp __gmpz_tdiv_r_2exp
+__GMP_DECLSPEC void mpz_tdiv_r_2exp (mpz_ptr, mpz_srcptr, mp_bitcnt_t);
+
+#define mpz_tdiv_r_ui __gmpz_tdiv_r_ui
+__GMP_DECLSPEC unsigned long int mpz_tdiv_r_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_tstbit __gmpz_tstbit
+__GMP_DECLSPEC int mpz_tstbit (mpz_srcptr, mp_bitcnt_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_ui_pow_ui __gmpz_ui_pow_ui
+__GMP_DECLSPEC void mpz_ui_pow_ui (mpz_ptr, unsigned long int, unsigned long int);
+
+#define mpz_urandomb __gmpz_urandomb
+__GMP_DECLSPEC void mpz_urandomb (mpz_ptr, gmp_randstate_t, mp_bitcnt_t);
+
+#define mpz_urandomm __gmpz_urandomm
+__GMP_DECLSPEC void mpz_urandomm (mpz_ptr, gmp_randstate_t, mpz_srcptr);
+
+#define mpz_xor __gmpz_xor
+#define mpz_eor __gmpz_xor
+__GMP_DECLSPEC void mpz_xor (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_limbs_read __gmpz_limbs_read
+__GMP_DECLSPEC mp_srcptr mpz_limbs_read (mpz_srcptr);
+
+#define mpz_limbs_write __gmpz_limbs_write
+__GMP_DECLSPEC mp_ptr mpz_limbs_write (mpz_ptr, mp_size_t);
+
+#define mpz_limbs_modify __gmpz_limbs_modify
+__GMP_DECLSPEC mp_ptr mpz_limbs_modify (mpz_ptr, mp_size_t);
+
+#define mpz_limbs_finish __gmpz_limbs_finish
+__GMP_DECLSPEC void mpz_limbs_finish (mpz_ptr, mp_size_t);
+
+#define mpz_roinit_n __gmpz_roinit_n
+__GMP_DECLSPEC mpz_srcptr mpz_roinit_n (mpz_ptr, mp_srcptr, mp_size_t);
+
+#define MPZ_ROINIT_N(xp, xs) {{0, (xs),(xp) }}
+
+/**************** Rational (i.e. Q) routines.  ****************/
+
+#define mpq_abs __gmpq_abs
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpq_abs)
+__GMP_DECLSPEC void mpq_abs (mpq_ptr, mpq_srcptr);
+#endif
+
+#define mpq_add __gmpq_add
+__GMP_DECLSPEC void mpq_add (mpq_ptr, mpq_srcptr, mpq_srcptr);
+
+#define mpq_canonicalize __gmpq_canonicalize
+__GMP_DECLSPEC void mpq_canonicalize (mpq_ptr);
+
+#define mpq_clear __gmpq_clear
+__GMP_DECLSPEC void mpq_clear (mpq_ptr);
+
+#define mpq_clears __gmpq_clears
+__GMP_DECLSPEC void mpq_clears (mpq_ptr, ...);
+
+#define mpq_cmp __gmpq_cmp
+__GMP_DECLSPEC int mpq_cmp (mpq_srcptr, mpq_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define _mpq_cmp_si __gmpq_cmp_si
+__GMP_DECLSPEC int _mpq_cmp_si (mpq_srcptr, long, unsigned long) __GMP_ATTRIBUTE_PURE;
+
+#define _mpq_cmp_ui __gmpq_cmp_ui
+__GMP_DECLSPEC int _mpq_cmp_ui (mpq_srcptr, unsigned long int, unsigned long int) __GMP_ATTRIBUTE_PURE;
+
+#define mpq_cmp_z __gmpq_cmp_z
+__GMP_DECLSPEC int mpq_cmp_z (mpq_srcptr, mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpq_div __gmpq_div
+__GMP_DECLSPEC void mpq_div (mpq_ptr, mpq_srcptr, mpq_srcptr);
+
+#define mpq_div_2exp __gmpq_div_2exp
+__GMP_DECLSPEC void mpq_div_2exp (mpq_ptr, mpq_srcptr, mp_bitcnt_t);
+
+#define mpq_equal __gmpq_equal
+__GMP_DECLSPEC int mpq_equal (mpq_srcptr, mpq_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpq_get_num __gmpq_get_num
+__GMP_DECLSPEC void mpq_get_num (mpz_ptr, mpq_srcptr);
+
+#define mpq_get_den __gmpq_get_den
+__GMP_DECLSPEC void mpq_get_den (mpz_ptr, mpq_srcptr);
+
+#define mpq_get_d __gmpq_get_d
+__GMP_DECLSPEC double mpq_get_d (mpq_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpq_get_str __gmpq_get_str
+__GMP_DECLSPEC char *mpq_get_str (char *, int, mpq_srcptr);
+
+#define mpq_init __gmpq_init
+__GMP_DECLSPEC void mpq_init (mpq_ptr);
+
+#define mpq_inits __gmpq_inits
+__GMP_DECLSPEC void mpq_inits (mpq_ptr, ...);
+
+#define mpq_inp_str __gmpq_inp_str
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC size_t mpq_inp_str (mpq_ptr, FILE *, int);
+#endif
+
+#define mpq_inv __gmpq_inv
+__GMP_DECLSPEC void mpq_inv (mpq_ptr, mpq_srcptr);
+
+#define mpq_mul __gmpq_mul
+__GMP_DECLSPEC void mpq_mul (mpq_ptr, mpq_srcptr, mpq_srcptr);
+
+#define mpq_mul_2exp __gmpq_mul_2exp
+__GMP_DECLSPEC void mpq_mul_2exp (mpq_ptr, mpq_srcptr, mp_bitcnt_t);
+
+#define mpq_neg __gmpq_neg
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpq_neg)
+__GMP_DECLSPEC void mpq_neg (mpq_ptr, mpq_srcptr);
+#endif
+
+#define mpq_out_str __gmpq_out_str
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC size_t mpq_out_str (FILE *, int, mpq_srcptr);
+#endif
+
+#define mpq_set __gmpq_set
+__GMP_DECLSPEC void mpq_set (mpq_ptr, mpq_srcptr);
+
+#define mpq_set_d __gmpq_set_d
+__GMP_DECLSPEC void mpq_set_d (mpq_ptr, double);
+
+#define mpq_set_den __gmpq_set_den
+__GMP_DECLSPEC void mpq_set_den (mpq_ptr, mpz_srcptr);
+
+#define mpq_set_f __gmpq_set_f
+__GMP_DECLSPEC void mpq_set_f (mpq_ptr, mpf_srcptr);
+
+#define mpq_set_num __gmpq_set_num
+__GMP_DECLSPEC void mpq_set_num (mpq_ptr, mpz_srcptr);
+
+#define mpq_set_si __gmpq_set_si
+__GMP_DECLSPEC void mpq_set_si (mpq_ptr, signed long int, unsigned long int);
+
+#define mpq_set_str __gmpq_set_str
+__GMP_DECLSPEC int mpq_set_str (mpq_ptr, const char *, int);
+
+#define mpq_set_ui __gmpq_set_ui
+__GMP_DECLSPEC void mpq_set_ui (mpq_ptr, unsigned long int, unsigned long int);
+
+#define mpq_set_z __gmpq_set_z
+__GMP_DECLSPEC void mpq_set_z (mpq_ptr, mpz_srcptr);
+
+#define mpq_sub __gmpq_sub
+__GMP_DECLSPEC void mpq_sub (mpq_ptr, mpq_srcptr, mpq_srcptr);
+
+#define mpq_swap __gmpq_swap
+__GMP_DECLSPEC void mpq_swap (mpq_ptr, mpq_ptr) __GMP_NOTHROW;
+
+
+/**************** Float (i.e. F) routines.  ****************/
+
+#define mpf_abs __gmpf_abs
+__GMP_DECLSPEC void mpf_abs (mpf_ptr, mpf_srcptr);
+
+#define mpf_add __gmpf_add
+__GMP_DECLSPEC void mpf_add (mpf_ptr, mpf_srcptr, mpf_srcptr);
+
+#define mpf_add_ui __gmpf_add_ui
+__GMP_DECLSPEC void mpf_add_ui (mpf_ptr, mpf_srcptr, unsigned long int);
+#define mpf_ceil __gmpf_ceil
+__GMP_DECLSPEC void mpf_ceil (mpf_ptr, mpf_srcptr);
+
+#define mpf_clear __gmpf_clear
+__GMP_DECLSPEC void mpf_clear (mpf_ptr);
+
+#define mpf_clears __gmpf_clears
+__GMP_DECLSPEC void mpf_clears (mpf_ptr, ...);
+
+#define mpf_cmp __gmpf_cmp
+__GMP_DECLSPEC int mpf_cmp (mpf_srcptr, mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_cmp_z __gmpf_cmp_z
+__GMP_DECLSPEC int mpf_cmp_z (mpf_srcptr, mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_cmp_d __gmpf_cmp_d
+__GMP_DECLSPEC int mpf_cmp_d (mpf_srcptr, double) __GMP_ATTRIBUTE_PURE;
+
+#define mpf_cmp_si __gmpf_cmp_si
+__GMP_DECLSPEC int mpf_cmp_si (mpf_srcptr, signed long int) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_cmp_ui __gmpf_cmp_ui
+__GMP_DECLSPEC int mpf_cmp_ui (mpf_srcptr, unsigned long int) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_div __gmpf_div
+__GMP_DECLSPEC void mpf_div (mpf_ptr, mpf_srcptr, mpf_srcptr);
+
+#define mpf_div_2exp __gmpf_div_2exp
+__GMP_DECLSPEC void mpf_div_2exp (mpf_ptr, mpf_srcptr, mp_bitcnt_t);
+
+#define mpf_div_ui __gmpf_div_ui
+__GMP_DECLSPEC void mpf_div_ui (mpf_ptr, mpf_srcptr, unsigned long int);
+
+#define mpf_dump __gmpf_dump
+__GMP_DECLSPEC void mpf_dump (mpf_srcptr);
+
+#define mpf_eq __gmpf_eq
+__GMP_DECLSPEC int mpf_eq (mpf_srcptr, mpf_srcptr, mp_bitcnt_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpf_fits_sint_p __gmpf_fits_sint_p
+__GMP_DECLSPEC int mpf_fits_sint_p (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_fits_slong_p __gmpf_fits_slong_p
+__GMP_DECLSPEC int mpf_fits_slong_p (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_fits_sshort_p __gmpf_fits_sshort_p
+__GMP_DECLSPEC int mpf_fits_sshort_p (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_fits_uint_p __gmpf_fits_uint_p
+__GMP_DECLSPEC int mpf_fits_uint_p (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_fits_ulong_p __gmpf_fits_ulong_p
+__GMP_DECLSPEC int mpf_fits_ulong_p (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_fits_ushort_p __gmpf_fits_ushort_p
+__GMP_DECLSPEC int mpf_fits_ushort_p (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_floor __gmpf_floor
+__GMP_DECLSPEC void mpf_floor (mpf_ptr, mpf_srcptr);
+
+#define mpf_get_d __gmpf_get_d
+__GMP_DECLSPEC double mpf_get_d (mpf_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpf_get_d_2exp __gmpf_get_d_2exp
+__GMP_DECLSPEC double mpf_get_d_2exp (signed long int *, mpf_srcptr);
+
+#define mpf_get_default_prec __gmpf_get_default_prec
+__GMP_DECLSPEC mp_bitcnt_t mpf_get_default_prec (void) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_get_prec __gmpf_get_prec
+__GMP_DECLSPEC mp_bitcnt_t mpf_get_prec (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_get_si __gmpf_get_si
+__GMP_DECLSPEC long mpf_get_si (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_get_str __gmpf_get_str
+__GMP_DECLSPEC char *mpf_get_str (char *, mp_exp_t *, int, size_t, mpf_srcptr);
+
+#define mpf_get_ui __gmpf_get_ui
+__GMP_DECLSPEC unsigned long mpf_get_ui (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_init __gmpf_init
+__GMP_DECLSPEC void mpf_init (mpf_ptr);
+
+#define mpf_init2 __gmpf_init2
+__GMP_DECLSPEC void mpf_init2 (mpf_ptr, mp_bitcnt_t);
+
+#define mpf_inits __gmpf_inits
+__GMP_DECLSPEC void mpf_inits (mpf_ptr, ...);
+
+#define mpf_init_set __gmpf_init_set
+__GMP_DECLSPEC void mpf_init_set (mpf_ptr, mpf_srcptr);
+
+#define mpf_init_set_d __gmpf_init_set_d
+__GMP_DECLSPEC void mpf_init_set_d (mpf_ptr, double);
+
+#define mpf_init_set_si __gmpf_init_set_si
+__GMP_DECLSPEC void mpf_init_set_si (mpf_ptr, signed long int);
+
+#define mpf_init_set_str __gmpf_init_set_str
+__GMP_DECLSPEC int mpf_init_set_str (mpf_ptr, const char *, int);
+
+#define mpf_init_set_ui __gmpf_init_set_ui
+__GMP_DECLSPEC void mpf_init_set_ui (mpf_ptr, unsigned long int);
+
+#define mpf_inp_str __gmpf_inp_str
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC size_t mpf_inp_str (mpf_ptr, FILE *, int);
+#endif
+
+#define mpf_integer_p __gmpf_integer_p
+__GMP_DECLSPEC int mpf_integer_p (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_mul __gmpf_mul
+__GMP_DECLSPEC void mpf_mul (mpf_ptr, mpf_srcptr, mpf_srcptr);
+
+#define mpf_mul_2exp __gmpf_mul_2exp
+__GMP_DECLSPEC void mpf_mul_2exp (mpf_ptr, mpf_srcptr, mp_bitcnt_t);
+
+#define mpf_mul_ui __gmpf_mul_ui
+__GMP_DECLSPEC void mpf_mul_ui (mpf_ptr, mpf_srcptr, unsigned long int);
+
+#define mpf_neg __gmpf_neg
+__GMP_DECLSPEC void mpf_neg (mpf_ptr, mpf_srcptr);
+
+#define mpf_out_str __gmpf_out_str
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC size_t mpf_out_str (FILE *, int, size_t, mpf_srcptr);
+#endif
+
+#define mpf_pow_ui __gmpf_pow_ui
+__GMP_DECLSPEC void mpf_pow_ui (mpf_ptr, mpf_srcptr, unsigned long int);
+
+#define mpf_random2 __gmpf_random2
+__GMP_DECLSPEC void mpf_random2 (mpf_ptr, mp_size_t, mp_exp_t);
+
+#define mpf_reldiff __gmpf_reldiff
+__GMP_DECLSPEC void mpf_reldiff (mpf_ptr, mpf_srcptr, mpf_srcptr);
+
+#define mpf_set __gmpf_set
+__GMP_DECLSPEC void mpf_set (mpf_ptr, mpf_srcptr);
+
+#define mpf_set_d __gmpf_set_d
+__GMP_DECLSPEC void mpf_set_d (mpf_ptr, double);
+
+#define mpf_set_default_prec __gmpf_set_default_prec
+__GMP_DECLSPEC void mpf_set_default_prec (mp_bitcnt_t) __GMP_NOTHROW;
+
+#define mpf_set_prec __gmpf_set_prec
+__GMP_DECLSPEC void mpf_set_prec (mpf_ptr, mp_bitcnt_t);
+
+#define mpf_set_prec_raw __gmpf_set_prec_raw
+__GMP_DECLSPEC void mpf_set_prec_raw (mpf_ptr, mp_bitcnt_t) __GMP_NOTHROW;
+
+#define mpf_set_q __gmpf_set_q
+__GMP_DECLSPEC void mpf_set_q (mpf_ptr, mpq_srcptr);
+
+#define mpf_set_si __gmpf_set_si
+__GMP_DECLSPEC void mpf_set_si (mpf_ptr, signed long int);
+
+#define mpf_set_str __gmpf_set_str
+__GMP_DECLSPEC int mpf_set_str (mpf_ptr, const char *, int);
+
+#define mpf_set_ui __gmpf_set_ui
+__GMP_DECLSPEC void mpf_set_ui (mpf_ptr, unsigned long int);
+
+#define mpf_set_z __gmpf_set_z
+__GMP_DECLSPEC void mpf_set_z (mpf_ptr, mpz_srcptr);
+
+#define mpf_size __gmpf_size
+__GMP_DECLSPEC size_t mpf_size (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_sqrt __gmpf_sqrt
+__GMP_DECLSPEC void mpf_sqrt (mpf_ptr, mpf_srcptr);
+
+#define mpf_sqrt_ui __gmpf_sqrt_ui
+__GMP_DECLSPEC void mpf_sqrt_ui (mpf_ptr, unsigned long int);
+
+#define mpf_sub __gmpf_sub
+__GMP_DECLSPEC void mpf_sub (mpf_ptr, mpf_srcptr, mpf_srcptr);
+
+#define mpf_sub_ui __gmpf_sub_ui
+__GMP_DECLSPEC void mpf_sub_ui (mpf_ptr, mpf_srcptr, unsigned long int);
+
+#define mpf_swap __gmpf_swap
+__GMP_DECLSPEC void mpf_swap (mpf_ptr, mpf_ptr) __GMP_NOTHROW;
+
+#define mpf_trunc __gmpf_trunc
+__GMP_DECLSPEC void mpf_trunc (mpf_ptr, mpf_srcptr);
+
+#define mpf_ui_div __gmpf_ui_div
+__GMP_DECLSPEC void mpf_ui_div (mpf_ptr, unsigned long int, mpf_srcptr);
+
+#define mpf_ui_sub __gmpf_ui_sub
+__GMP_DECLSPEC void mpf_ui_sub (mpf_ptr, unsigned long int, mpf_srcptr);
+
+#define mpf_urandomb __gmpf_urandomb
+__GMP_DECLSPEC void mpf_urandomb (mpf_t, gmp_randstate_t, mp_bitcnt_t);
+
+
+/************ Low level positive-integer (i.e. N) routines.  ************/
+
+/* This is ugly, but we need to make user calls reach the prefixed function. */
+
+#define mpn_add __MPN(add)
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_add)
+__GMP_DECLSPEC mp_limb_t mpn_add (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+#endif
+
+#define mpn_add_1 __MPN(add_1)
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_add_1)
+__GMP_DECLSPEC mp_limb_t mpn_add_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t) __GMP_NOTHROW;
+#endif
+
+#define mpn_add_n __MPN(add_n)
+__GMP_DECLSPEC mp_limb_t mpn_add_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+
+#define mpn_addmul_1 __MPN(addmul_1)
+__GMP_DECLSPEC mp_limb_t mpn_addmul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_cmp __MPN(cmp)
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_cmp)
+__GMP_DECLSPEC int mpn_cmp (mp_srcptr, mp_srcptr, mp_size_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpn_zero_p __MPN(zero_p)
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_zero_p)
+__GMP_DECLSPEC int mpn_zero_p (mp_srcptr, mp_size_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpn_divexact_1 __MPN(divexact_1)
+__GMP_DECLSPEC void mpn_divexact_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_divexact_by3(dst,src,size) \
+  mpn_divexact_by3c (dst, src, size, __GMP_CAST (mp_limb_t, 0))
+
+#define mpn_divexact_by3c __MPN(divexact_by3c)
+__GMP_DECLSPEC mp_limb_t mpn_divexact_by3c (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_divmod_1(qp,np,nsize,dlimb) \
+  mpn_divrem_1 (qp, __GMP_CAST (mp_size_t, 0), np, nsize, dlimb)
+
+#define mpn_divrem __MPN(divrem)
+__GMP_DECLSPEC mp_limb_t mpn_divrem (mp_ptr, mp_size_t, mp_ptr, mp_size_t, mp_srcptr, mp_size_t);
+
+#define mpn_divrem_1 __MPN(divrem_1)
+__GMP_DECLSPEC mp_limb_t mpn_divrem_1 (mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_divrem_2 __MPN(divrem_2)
+__GMP_DECLSPEC mp_limb_t mpn_divrem_2 (mp_ptr, mp_size_t, mp_ptr, mp_size_t, mp_srcptr);
+
+#define mpn_div_qr_1 __MPN(div_qr_1)
+__GMP_DECLSPEC mp_limb_t mpn_div_qr_1 (mp_ptr, mp_limb_t *, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_div_qr_2 __MPN(div_qr_2)
+__GMP_DECLSPEC mp_limb_t mpn_div_qr_2 (mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+
+#define mpn_gcd __MPN(gcd)
+__GMP_DECLSPEC mp_size_t mpn_gcd (mp_ptr, mp_ptr, mp_size_t, mp_ptr, mp_size_t);
+
+#define mpn_gcd_11 __MPN(gcd_11)
+__GMP_DECLSPEC mp_limb_t mpn_gcd_11 (mp_limb_t, mp_limb_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_gcd_1 __MPN(gcd_1)
+__GMP_DECLSPEC mp_limb_t mpn_gcd_1 (mp_srcptr, mp_size_t, mp_limb_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_gcdext_1 __MPN(gcdext_1)
+__GMP_DECLSPEC mp_limb_t mpn_gcdext_1 (mp_limb_signed_t *, mp_limb_signed_t *, mp_limb_t, mp_limb_t);
+
+#define mpn_gcdext __MPN(gcdext)
+__GMP_DECLSPEC mp_size_t mpn_gcdext (mp_ptr, mp_ptr, mp_size_t *, mp_ptr, mp_size_t, mp_ptr, mp_size_t);
+
+#define mpn_get_str __MPN(get_str)
+__GMP_DECLSPEC size_t mpn_get_str (unsigned char *, int, mp_ptr, mp_size_t);
+
+#define mpn_hamdist __MPN(hamdist)
+__GMP_DECLSPEC mp_bitcnt_t mpn_hamdist (mp_srcptr, mp_srcptr, mp_size_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpn_lshift __MPN(lshift)
+__GMP_DECLSPEC mp_limb_t mpn_lshift (mp_ptr, mp_srcptr, mp_size_t, unsigned int);
+
+#define mpn_mod_1 __MPN(mod_1)
+__GMP_DECLSPEC mp_limb_t mpn_mod_1 (mp_srcptr, mp_size_t, mp_limb_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_mul __MPN(mul)
+__GMP_DECLSPEC mp_limb_t mpn_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+
+#define mpn_mul_1 __MPN(mul_1)
+__GMP_DECLSPEC mp_limb_t mpn_mul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_mul_n __MPN(mul_n)
+__GMP_DECLSPEC void mpn_mul_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+
+#define mpn_sqr __MPN(sqr)
+__GMP_DECLSPEC void mpn_sqr (mp_ptr, mp_srcptr, mp_size_t);
+
+#define mpn_neg __MPN(neg)
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_neg)
+__GMP_DECLSPEC mp_limb_t mpn_neg (mp_ptr, mp_srcptr, mp_size_t);
+#endif
+
+#define mpn_com __MPN(com)
+__GMP_DECLSPEC void mpn_com (mp_ptr, mp_srcptr, mp_size_t);
+
+#define mpn_perfect_square_p __MPN(perfect_square_p)
+__GMP_DECLSPEC int mpn_perfect_square_p (mp_srcptr, mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_perfect_power_p __MPN(perfect_power_p)
+__GMP_DECLSPEC int mpn_perfect_power_p (mp_srcptr, mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_popcount __MPN(popcount)
+__GMP_DECLSPEC mp_bitcnt_t mpn_popcount (mp_srcptr, mp_size_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpn_pow_1 __MPN(pow_1)
+__GMP_DECLSPEC mp_size_t mpn_pow_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_ptr);
+
+/* undocumented now, but retained here for upward compatibility */
+#define mpn_preinv_mod_1 __MPN(preinv_mod_1)
+__GMP_DECLSPEC mp_limb_t mpn_preinv_mod_1 (mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_random __MPN(random)
+__GMP_DECLSPEC void mpn_random (mp_ptr, mp_size_t);
+
+#define mpn_random2 __MPN(random2)
+__GMP_DECLSPEC void mpn_random2 (mp_ptr, mp_size_t);
+
+#define mpn_rshift __MPN(rshift)
+__GMP_DECLSPEC mp_limb_t mpn_rshift (mp_ptr, mp_srcptr, mp_size_t, unsigned int);
+
+#define mpn_scan0 __MPN(scan0)
+__GMP_DECLSPEC mp_bitcnt_t mpn_scan0 (mp_srcptr, mp_bitcnt_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_scan1 __MPN(scan1)
+__GMP_DECLSPEC mp_bitcnt_t mpn_scan1 (mp_srcptr, mp_bitcnt_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_set_str __MPN(set_str)
+__GMP_DECLSPEC mp_size_t mpn_set_str (mp_ptr, const unsigned char *, size_t, int);
+
+#define mpn_sizeinbase __MPN(sizeinbase)
+__GMP_DECLSPEC size_t mpn_sizeinbase (mp_srcptr, mp_size_t, int);
+
+#define mpn_sqrtrem __MPN(sqrtrem)
+__GMP_DECLSPEC mp_size_t mpn_sqrtrem (mp_ptr, mp_ptr, mp_srcptr, mp_size_t);
+
+#define mpn_sub __MPN(sub)
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_sub)
+__GMP_DECLSPEC mp_limb_t mpn_sub (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+#endif
+
+#define mpn_sub_1 __MPN(sub_1)
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_sub_1)
+__GMP_DECLSPEC mp_limb_t mpn_sub_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t) __GMP_NOTHROW;
+#endif
+
+#define mpn_sub_n __MPN(sub_n)
+__GMP_DECLSPEC mp_limb_t mpn_sub_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+
+#define mpn_submul_1 __MPN(submul_1)
+__GMP_DECLSPEC mp_limb_t mpn_submul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_tdiv_qr __MPN(tdiv_qr)
+__GMP_DECLSPEC void mpn_tdiv_qr (mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+
+#define mpn_and_n __MPN(and_n)
+__GMP_DECLSPEC void mpn_and_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_andn_n __MPN(andn_n)
+__GMP_DECLSPEC void mpn_andn_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_nand_n __MPN(nand_n)
+__GMP_DECLSPEC void mpn_nand_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_ior_n __MPN(ior_n)
+__GMP_DECLSPEC void mpn_ior_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_iorn_n __MPN(iorn_n)
+__GMP_DECLSPEC void mpn_iorn_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_nior_n __MPN(nior_n)
+__GMP_DECLSPEC void mpn_nior_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_xor_n __MPN(xor_n)
+__GMP_DECLSPEC void mpn_xor_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_xnor_n __MPN(xnor_n)
+__GMP_DECLSPEC void mpn_xnor_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+
+#define mpn_copyi __MPN(copyi)
+__GMP_DECLSPEC void mpn_copyi (mp_ptr, mp_srcptr, mp_size_t);
+#define mpn_copyd __MPN(copyd)
+__GMP_DECLSPEC void mpn_copyd (mp_ptr, mp_srcptr, mp_size_t);
+#define mpn_zero __MPN(zero)
+__GMP_DECLSPEC void mpn_zero (mp_ptr, mp_size_t);
+
+#define mpn_cnd_add_n __MPN(cnd_add_n)
+__GMP_DECLSPEC mp_limb_t mpn_cnd_add_n (mp_limb_t, mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_cnd_sub_n __MPN(cnd_sub_n)
+__GMP_DECLSPEC mp_limb_t mpn_cnd_sub_n (mp_limb_t, mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+
+#define mpn_sec_add_1 __MPN(sec_add_1)
+__GMP_DECLSPEC mp_limb_t mpn_sec_add_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_ptr);
+#define mpn_sec_add_1_itch __MPN(sec_add_1_itch)
+__GMP_DECLSPEC mp_size_t mpn_sec_add_1_itch (mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_sec_sub_1 __MPN(sec_sub_1)
+__GMP_DECLSPEC mp_limb_t mpn_sec_sub_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_ptr);
+#define mpn_sec_sub_1_itch __MPN(sec_sub_1_itch)
+__GMP_DECLSPEC mp_size_t mpn_sec_sub_1_itch (mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_cnd_swap  __MPN(cnd_swap)
+__GMP_DECLSPEC void mpn_cnd_swap (mp_limb_t, volatile mp_limb_t *, volatile mp_limb_t *, mp_size_t);
+
+#define mpn_sec_mul __MPN(sec_mul)
+__GMP_DECLSPEC void mpn_sec_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+#define mpn_sec_mul_itch __MPN(sec_mul_itch)
+__GMP_DECLSPEC mp_size_t mpn_sec_mul_itch (mp_size_t, mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_sec_sqr __MPN(sec_sqr)
+__GMP_DECLSPEC void mpn_sec_sqr (mp_ptr, mp_srcptr, mp_size_t, mp_ptr);
+#define mpn_sec_sqr_itch __MPN(sec_sqr_itch)
+__GMP_DECLSPEC mp_size_t mpn_sec_sqr_itch (mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_sec_powm __MPN(sec_powm)
+__GMP_DECLSPEC void mpn_sec_powm (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_bitcnt_t, mp_srcptr, mp_size_t, mp_ptr);
+#define mpn_sec_powm_itch __MPN(sec_powm_itch)
+__GMP_DECLSPEC mp_size_t mpn_sec_powm_itch (mp_size_t, mp_bitcnt_t, mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_sec_tabselect __MPN(sec_tabselect)
+__GMP_DECLSPEC void mpn_sec_tabselect (volatile mp_limb_t *, volatile const mp_limb_t *, mp_size_t, mp_size_t, mp_size_t);
+
+#define mpn_sec_div_qr __MPN(sec_div_qr)
+__GMP_DECLSPEC mp_limb_t mpn_sec_div_qr (mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+#define mpn_sec_div_qr_itch __MPN(sec_div_qr_itch)
+__GMP_DECLSPEC mp_size_t mpn_sec_div_qr_itch (mp_size_t, mp_size_t) __GMP_ATTRIBUTE_PURE;
+#define mpn_sec_div_r __MPN(sec_div_r)
+__GMP_DECLSPEC void mpn_sec_div_r (mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+#define mpn_sec_div_r_itch __MPN(sec_div_r_itch)
+__GMP_DECLSPEC mp_size_t mpn_sec_div_r_itch (mp_size_t, mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_sec_invert __MPN(sec_invert)
+__GMP_DECLSPEC int mpn_sec_invert (mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_bitcnt_t, mp_ptr);
+#define mpn_sec_invert_itch __MPN(sec_invert_itch)
+__GMP_DECLSPEC mp_size_t mpn_sec_invert_itch (mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+
+/**************** mpz inlines ****************/
+
+/* The following are provided as inlines where possible, but always exist as
+   library functions too, for binary compatibility.
+
+   Within gmp itself this inlining generally isn't relied on, since it
+   doesn't get done for all compilers, whereas if something is worth
+   inlining then it's worth arranging always.
+
+   There are two styles of inlining here.  When the same bit of code is
+   wanted for the inline as for the library version, then __GMP_FORCE_foo
+   arranges for that code to be emitted and the __GMP_EXTERN_INLINE
+   directive suppressed, eg. mpz_fits_uint_p.  When a different bit of code
+   is wanted for the inline than for the library version, then
+   __GMP_FORCE_foo arranges the inline to be suppressed, eg. mpz_abs.  */
+
+#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpz_abs)
+__GMP_EXTERN_INLINE void
+mpz_abs (mpz_ptr __gmp_w, mpz_srcptr __gmp_u)
+{
+  if (__gmp_w != __gmp_u)
+    mpz_set (__gmp_w, __gmp_u);
+  __gmp_w->_mp_size = __GMP_ABS (__gmp_w->_mp_size);
+}
+#endif
+
+#if GMP_NAIL_BITS == 0
+#define __GMPZ_FITS_UTYPE_P(z,maxval)					\
+  mp_size_t  __gmp_n = z->_mp_size;					\
+  mp_ptr  __gmp_p = z->_mp_d;						\
+  return (__gmp_n == 0 || (__gmp_n == 1 && __gmp_p[0] <= maxval));
+#else
+#define __GMPZ_FITS_UTYPE_P(z,maxval)					\
+  mp_size_t  __gmp_n = z->_mp_size;					\
+  mp_ptr  __gmp_p = z->_mp_d;						\
+  return (__gmp_n == 0 || (__gmp_n == 1 && __gmp_p[0] <= maxval)	\
+	  || (__gmp_n == 2 && __gmp_p[1] <= ((mp_limb_t) maxval >> GMP_NUMB_BITS)));
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_fits_uint_p)
+#if ! defined (__GMP_FORCE_mpz_fits_uint_p)
+__GMP_EXTERN_INLINE
+#endif
+int
+mpz_fits_uint_p (mpz_srcptr __gmp_z) __GMP_NOTHROW
+{
+  __GMPZ_FITS_UTYPE_P (__gmp_z, UINT_MAX);
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_fits_ulong_p)
+#if ! defined (__GMP_FORCE_mpz_fits_ulong_p)
+__GMP_EXTERN_INLINE
+#endif
+int
+mpz_fits_ulong_p (mpz_srcptr __gmp_z) __GMP_NOTHROW
+{
+  __GMPZ_FITS_UTYPE_P (__gmp_z, ULONG_MAX);
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_fits_ushort_p)
+#if ! defined (__GMP_FORCE_mpz_fits_ushort_p)
+__GMP_EXTERN_INLINE
+#endif
+int
+mpz_fits_ushort_p (mpz_srcptr __gmp_z) __GMP_NOTHROW
+{
+  __GMPZ_FITS_UTYPE_P (__gmp_z, USHRT_MAX);
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_get_ui)
+#if ! defined (__GMP_FORCE_mpz_get_ui)
+__GMP_EXTERN_INLINE
+#endif
+unsigned long
+mpz_get_ui (mpz_srcptr __gmp_z) __GMP_NOTHROW
+{
+  mp_ptr __gmp_p = __gmp_z->_mp_d;
+  mp_size_t __gmp_n = __gmp_z->_mp_size;
+  mp_limb_t __gmp_l = __gmp_p[0];
+  /* This is a "#if" rather than a plain "if" so as to avoid gcc warnings
+     about "<< GMP_NUMB_BITS" exceeding the type size, and to avoid Borland
+     C++ 6.0 warnings about condition always true for something like
+     "ULONG_MAX < GMP_NUMB_MASK".  */
+#if GMP_NAIL_BITS == 0 || defined (_LONG_LONG_LIMB)
+  /* limb==long and no nails, or limb==longlong, one limb is enough */
+  return (__gmp_n != 0 ? __gmp_l : 0);
+#else
+  /* limb==long and nails, need two limbs when available */
+  __gmp_n = __GMP_ABS (__gmp_n);
+  if (__gmp_n <= 1)
+    return (__gmp_n != 0 ? __gmp_l : 0);
+  else
+    return __gmp_l + (__gmp_p[1] << GMP_NUMB_BITS);
+#endif
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_getlimbn)
+#if ! defined (__GMP_FORCE_mpz_getlimbn)
+__GMP_EXTERN_INLINE
+#endif
+mp_limb_t
+mpz_getlimbn (mpz_srcptr __gmp_z, mp_size_t __gmp_n) __GMP_NOTHROW
+{
+  mp_limb_t  __gmp_result = 0;
+  if (__GMP_LIKELY (__gmp_n >= 0 && __gmp_n < __GMP_ABS (__gmp_z->_mp_size)))
+    __gmp_result = __gmp_z->_mp_d[__gmp_n];
+  return __gmp_result;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpz_neg)
+__GMP_EXTERN_INLINE void
+mpz_neg (mpz_ptr __gmp_w, mpz_srcptr __gmp_u)
+{
+  if (__gmp_w != __gmp_u)
+    mpz_set (__gmp_w, __gmp_u);
+  __gmp_w->_mp_size = - __gmp_w->_mp_size;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_perfect_square_p)
+#if ! defined (__GMP_FORCE_mpz_perfect_square_p)
+__GMP_EXTERN_INLINE
+#endif
+int
+mpz_perfect_square_p (mpz_srcptr __gmp_a)
+{
+  mp_size_t __gmp_asize;
+  int       __gmp_result;
+
+  __gmp_asize = __gmp_a->_mp_size;
+  __gmp_result = (__gmp_asize >= 0);  /* zero is a square, negatives are not */
+  if (__GMP_LIKELY (__gmp_asize > 0))
+    __gmp_result = mpn_perfect_square_p (__gmp_a->_mp_d, __gmp_asize);
+  return __gmp_result;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_popcount)
+#if ! defined (__GMP_FORCE_mpz_popcount)
+__GMP_EXTERN_INLINE
+#endif
+mp_bitcnt_t
+mpz_popcount (mpz_srcptr __gmp_u) __GMP_NOTHROW
+{
+  mp_size_t      __gmp_usize;
+  mp_bitcnt_t    __gmp_result;
+
+  __gmp_usize = __gmp_u->_mp_size;
+  __gmp_result = (__gmp_usize < 0 ? ~ __GMP_CAST (mp_bitcnt_t, 0) : __GMP_CAST (mp_bitcnt_t, 0));
+  if (__GMP_LIKELY (__gmp_usize > 0))
+    __gmp_result =  mpn_popcount (__gmp_u->_mp_d, __gmp_usize);
+  return __gmp_result;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_set_q)
+#if ! defined (__GMP_FORCE_mpz_set_q)
+__GMP_EXTERN_INLINE
+#endif
+void
+mpz_set_q (mpz_ptr __gmp_w, mpq_srcptr __gmp_u)
+{
+  mpz_tdiv_q (__gmp_w, mpq_numref (__gmp_u), mpq_denref (__gmp_u));
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_size)
+#if ! defined (__GMP_FORCE_mpz_size)
+__GMP_EXTERN_INLINE
+#endif
+size_t
+mpz_size (mpz_srcptr __gmp_z) __GMP_NOTHROW
+{
+  return __GMP_ABS (__gmp_z->_mp_size);
+}
+#endif
+
+
+/**************** mpq inlines ****************/
+
+#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpq_abs)
+__GMP_EXTERN_INLINE void
+mpq_abs (mpq_ptr __gmp_w, mpq_srcptr __gmp_u)
+{
+  if (__gmp_w != __gmp_u)
+    mpq_set (__gmp_w, __gmp_u);
+  __gmp_w->_mp_num._mp_size = __GMP_ABS (__gmp_w->_mp_num._mp_size);
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpq_neg)
+__GMP_EXTERN_INLINE void
+mpq_neg (mpq_ptr __gmp_w, mpq_srcptr __gmp_u)
+{
+  if (__gmp_w != __gmp_u)
+    mpq_set (__gmp_w, __gmp_u);
+  __gmp_w->_mp_num._mp_size = - __gmp_w->_mp_num._mp_size;
+}
+#endif
+
+
+/**************** mpn inlines ****************/
+
+/* The comments with __GMPN_ADD_1 below apply here too.
+
+   The test for FUNCTION returning 0 should predict well.  If it's assumed
+   {yp,ysize} will usually have a random number of bits then the high limb
+   won't be full and a carry out will occur a good deal less than 50% of the
+   time.
+
+   ysize==0 isn't a documented feature, but is used internally in a few
+   places.
+
+   Producing cout last stops it using up a register during the main part of
+   the calculation, though gcc (as of 3.0) on an "if (mpn_add (...))"
+   doesn't seem able to move the true and false legs of the conditional up
+   to the two places cout is generated.  */
+
+#define __GMPN_AORS(cout, wp, xp, xsize, yp, ysize, FUNCTION, TEST)     \
+  do {                                                                  \
+    mp_size_t  __gmp_i;                                                 \
+    mp_limb_t  __gmp_x;                                                 \
+                                                                        \
+    /* ASSERT ((ysize) >= 0); */                                        \
+    /* ASSERT ((xsize) >= (ysize)); */                                  \
+    /* ASSERT (MPN_SAME_OR_SEPARATE2_P (wp, xsize, xp, xsize)); */      \
+    /* ASSERT (MPN_SAME_OR_SEPARATE2_P (wp, xsize, yp, ysize)); */      \
+                                                                        \
+    __gmp_i = (ysize);                                                  \
+    if (__gmp_i != 0)                                                   \
+      {                                                                 \
+        if (FUNCTION (wp, xp, yp, __gmp_i))                             \
+          {                                                             \
+            do                                                          \
+              {                                                         \
+                if (__gmp_i >= (xsize))                                 \
+                  {                                                     \
+                    (cout) = 1;                                         \
+                    goto __gmp_done;                                    \
+                  }                                                     \
+                __gmp_x = (xp)[__gmp_i];                                \
+              }                                                         \
+            while (TEST);                                               \
+          }                                                             \
+      }                                                                 \
+    if ((wp) != (xp))                                                   \
+      __GMPN_COPY_REST (wp, xp, xsize, __gmp_i);                        \
+    (cout) = 0;                                                         \
+  __gmp_done:                                                           \
+    ;                                                                   \
+  } while (0)
+
+#define __GMPN_ADD(cout, wp, xp, xsize, yp, ysize)              \
+  __GMPN_AORS (cout, wp, xp, xsize, yp, ysize, mpn_add_n,       \
+               (((wp)[__gmp_i++] = (__gmp_x + 1) & GMP_NUMB_MASK) == 0))
+#define __GMPN_SUB(cout, wp, xp, xsize, yp, ysize)              \
+  __GMPN_AORS (cout, wp, xp, xsize, yp, ysize, mpn_sub_n,       \
+               (((wp)[__gmp_i++] = (__gmp_x - 1) & GMP_NUMB_MASK), __gmp_x == 0))
+
+
+/* The use of __gmp_i indexing is designed to ensure a compile time src==dst
+   remains nice and clear to the compiler, so that __GMPN_COPY_REST can
+   disappear, and the load/add/store gets a chance to become a
+   read-modify-write on CISC CPUs.
+
+   Alternatives:
+
+   Using a pair of pointers instead of indexing would be possible, but gcc
+   isn't able to recognise compile-time src==dst in that case, even when the
+   pointers are incremented more or less together.  Other compilers would
+   very likely have similar difficulty.
+
+   gcc could use "if (__builtin_constant_p(src==dst) && src==dst)" or
+   similar to detect a compile-time src==dst.  This works nicely on gcc
+   2.95.x, it's not good on gcc 3.0 where __builtin_constant_p(p==p) seems
+   to be always false, for a pointer p.  But the current code form seems
+   good enough for src==dst anyway.
+
+   gcc on x86 as usual doesn't give particularly good flags handling for the
+   carry/borrow detection.  It's tempting to want some multi instruction asm
+   blocks to help it, and this was tried, but in truth there's only a few
+   instructions to save and any gain is all too easily lost by register
+   juggling setting up for the asm.  */
+
+#if GMP_NAIL_BITS == 0
+#define __GMPN_AORS_1(cout, dst, src, n, v, OP, CB)		\
+  do {								\
+    mp_size_t  __gmp_i;						\
+    mp_limb_t  __gmp_x, __gmp_r;                                \
+								\
+    /* ASSERT ((n) >= 1); */					\
+    /* ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, n)); */	\
+								\
+    __gmp_x = (src)[0];						\
+    __gmp_r = __gmp_x OP (v);                                   \
+    (dst)[0] = __gmp_r;						\
+    if (CB (__gmp_r, __gmp_x, (v)))                             \
+      {								\
+	(cout) = 1;						\
+	for (__gmp_i = 1; __gmp_i < (n);)                       \
+	  {							\
+	    __gmp_x = (src)[__gmp_i];                           \
+	    __gmp_r = __gmp_x OP 1;                             \
+	    (dst)[__gmp_i] = __gmp_r;                           \
+	    ++__gmp_i;						\
+	    if (!CB (__gmp_r, __gmp_x, 1))                      \
+	      {							\
+		if ((src) != (dst))				\
+		  __GMPN_COPY_REST (dst, src, n, __gmp_i);      \
+		(cout) = 0;					\
+		break;						\
+	      }							\
+	  }							\
+      }								\
+    else							\
+      {								\
+	if ((src) != (dst))					\
+	  __GMPN_COPY_REST (dst, src, n, 1);			\
+	(cout) = 0;						\
+      }								\
+  } while (0)
+#endif
+
+#if GMP_NAIL_BITS >= 1
+#define __GMPN_AORS_1(cout, dst, src, n, v, OP, CB)		\
+  do {								\
+    mp_size_t  __gmp_i;						\
+    mp_limb_t  __gmp_x, __gmp_r;				\
+								\
+    /* ASSERT ((n) >= 1); */					\
+    /* ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, n)); */	\
+								\
+    __gmp_x = (src)[0];						\
+    __gmp_r = __gmp_x OP (v);					\
+    (dst)[0] = __gmp_r & GMP_NUMB_MASK;				\
+    if (__gmp_r >> GMP_NUMB_BITS != 0)				\
+      {								\
+	(cout) = 1;						\
+	for (__gmp_i = 1; __gmp_i < (n);)			\
+	  {							\
+	    __gmp_x = (src)[__gmp_i];				\
+	    __gmp_r = __gmp_x OP 1;				\
+	    (dst)[__gmp_i] = __gmp_r & GMP_NUMB_MASK;		\
+	    ++__gmp_i;						\
+	    if (__gmp_r >> GMP_NUMB_BITS == 0)			\
+	      {							\
+		if ((src) != (dst))				\
+		  __GMPN_COPY_REST (dst, src, n, __gmp_i);	\
+		(cout) = 0;					\
+		break;						\
+	      }							\
+	  }							\
+      }								\
+    else							\
+      {								\
+	if ((src) != (dst))					\
+	  __GMPN_COPY_REST (dst, src, n, 1);			\
+	(cout) = 0;						\
+      }								\
+  } while (0)
+#endif
+
+#define __GMPN_ADDCB(r,x,y) ((r) < (y))
+#define __GMPN_SUBCB(r,x,y) ((x) < (y))
+
+#define __GMPN_ADD_1(cout, dst, src, n, v)	     \
+  __GMPN_AORS_1(cout, dst, src, n, v, +, __GMPN_ADDCB)
+#define __GMPN_SUB_1(cout, dst, src, n, v)	     \
+  __GMPN_AORS_1(cout, dst, src, n, v, -, __GMPN_SUBCB)
+
+
+/* Compare {xp,size} and {yp,size}, setting "result" to positive, zero or
+   negative.  size==0 is allowed.  On random data usually only one limb will
+   need to be examined to get a result, so it's worth having it inline.  */
+#define __GMPN_CMP(result, xp, yp, size)                                \
+  do {                                                                  \
+    mp_size_t  __gmp_i;                                                 \
+    mp_limb_t  __gmp_x, __gmp_y;                                        \
+                                                                        \
+    /* ASSERT ((size) >= 0); */                                         \
+                                                                        \
+    (result) = 0;                                                       \
+    __gmp_i = (size);                                                   \
+    while (--__gmp_i >= 0)                                              \
+      {                                                                 \
+        __gmp_x = (xp)[__gmp_i];                                        \
+        __gmp_y = (yp)[__gmp_i];                                        \
+        if (__gmp_x != __gmp_y)                                         \
+          {                                                             \
+            /* Cannot use __gmp_x - __gmp_y, may overflow an "int" */   \
+            (result) = (__gmp_x > __gmp_y ? 1 : -1);                    \
+            break;                                                      \
+          }                                                             \
+      }                                                                 \
+  } while (0)
+
+
+#if defined (__GMPN_COPY) && ! defined (__GMPN_COPY_REST)
+#define __GMPN_COPY_REST(dst, src, size, start)                 \
+  do {                                                          \
+    /* ASSERT ((start) >= 0); */                                \
+    /* ASSERT ((start) <= (size)); */                           \
+    __GMPN_COPY ((dst)+(start), (src)+(start), (size)-(start)); \
+  } while (0)
+#endif
+
+/* Copy {src,size} to {dst,size}, starting at "start".  This is designed to
+   keep the indexing dst[j] and src[j] nice and simple for __GMPN_ADD_1,
+   __GMPN_ADD, etc.  */
+#if ! defined (__GMPN_COPY_REST)
+#define __GMPN_COPY_REST(dst, src, size, start)                 \
+  do {                                                          \
+    mp_size_t __gmp_j;                                          \
+    /* ASSERT ((size) >= 0); */                                 \
+    /* ASSERT ((start) >= 0); */                                \
+    /* ASSERT ((start) <= (size)); */                           \
+    /* ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, size)); */     \
+    __GMP_CRAY_Pragma ("_CRI ivdep");                           \
+    for (__gmp_j = (start); __gmp_j < (size); __gmp_j++)        \
+      (dst)[__gmp_j] = (src)[__gmp_j];                          \
+  } while (0)
+#endif
+
+/* Enhancement: Use some of the smarter code from gmp-impl.h.  Maybe use
+   mpn_copyi if there's a native version, and if we don't mind demanding
+   binary compatibility for it (on targets which use it).  */
+
+#if ! defined (__GMPN_COPY)
+#define __GMPN_COPY(dst, src, size)   __GMPN_COPY_REST (dst, src, size, 0)
+#endif
+
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_add)
+#if ! defined (__GMP_FORCE_mpn_add)
+__GMP_EXTERN_INLINE
+#endif
+mp_limb_t
+mpn_add (mp_ptr __gmp_wp, mp_srcptr __gmp_xp, mp_size_t __gmp_xsize, mp_srcptr __gmp_yp, mp_size_t __gmp_ysize)
+{
+  mp_limb_t  __gmp_c;
+  __GMPN_ADD (__gmp_c, __gmp_wp, __gmp_xp, __gmp_xsize, __gmp_yp, __gmp_ysize);
+  return __gmp_c;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_add_1)
+#if ! defined (__GMP_FORCE_mpn_add_1)
+__GMP_EXTERN_INLINE
+#endif
+mp_limb_t
+mpn_add_1 (mp_ptr __gmp_dst, mp_srcptr __gmp_src, mp_size_t __gmp_size, mp_limb_t __gmp_n) __GMP_NOTHROW
+{
+  mp_limb_t  __gmp_c;
+  __GMPN_ADD_1 (__gmp_c, __gmp_dst, __gmp_src, __gmp_size, __gmp_n);
+  return __gmp_c;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_cmp)
+#if ! defined (__GMP_FORCE_mpn_cmp)
+__GMP_EXTERN_INLINE
+#endif
+int
+mpn_cmp (mp_srcptr __gmp_xp, mp_srcptr __gmp_yp, mp_size_t __gmp_size) __GMP_NOTHROW
+{
+  int __gmp_result;
+  __GMPN_CMP (__gmp_result, __gmp_xp, __gmp_yp, __gmp_size);
+  return __gmp_result;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_zero_p)
+#if ! defined (__GMP_FORCE_mpn_zero_p)
+__GMP_EXTERN_INLINE
+#endif
+int
+mpn_zero_p (mp_srcptr __gmp_p, mp_size_t __gmp_n) __GMP_NOTHROW
+{
+  /* if (__GMP_LIKELY (__gmp_n > 0)) */
+    do {
+      if (__gmp_p[--__gmp_n] != 0)
+	return 0;
+    } while (__gmp_n != 0);
+  return 1;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_sub)
+#if ! defined (__GMP_FORCE_mpn_sub)
+__GMP_EXTERN_INLINE
+#endif
+mp_limb_t
+mpn_sub (mp_ptr __gmp_wp, mp_srcptr __gmp_xp, mp_size_t __gmp_xsize, mp_srcptr __gmp_yp, mp_size_t __gmp_ysize)
+{
+  mp_limb_t  __gmp_c;
+  __GMPN_SUB (__gmp_c, __gmp_wp, __gmp_xp, __gmp_xsize, __gmp_yp, __gmp_ysize);
+  return __gmp_c;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_sub_1)
+#if ! defined (__GMP_FORCE_mpn_sub_1)
+__GMP_EXTERN_INLINE
+#endif
+mp_limb_t
+mpn_sub_1 (mp_ptr __gmp_dst, mp_srcptr __gmp_src, mp_size_t __gmp_size, mp_limb_t __gmp_n) __GMP_NOTHROW
+{
+  mp_limb_t  __gmp_c;
+  __GMPN_SUB_1 (__gmp_c, __gmp_dst, __gmp_src, __gmp_size, __gmp_n);
+  return __gmp_c;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_neg)
+#if ! defined (__GMP_FORCE_mpn_neg)
+__GMP_EXTERN_INLINE
+#endif
+mp_limb_t
+mpn_neg (mp_ptr __gmp_rp, mp_srcptr __gmp_up, mp_size_t __gmp_n)
+{
+  while (*__gmp_up == 0) /* Low zero limbs are unchanged by negation. */
+    {
+      *__gmp_rp = 0;
+      if (!--__gmp_n) /* All zero */
+	return 0;
+      ++__gmp_up; ++__gmp_rp;
+    }
+
+  *__gmp_rp = (- *__gmp_up) & GMP_NUMB_MASK;
+
+  if (--__gmp_n) /* Higher limbs get complemented. */
+    mpn_com (++__gmp_rp, ++__gmp_up, __gmp_n);
+
+  return 1;
+}
+#endif
+
+#if defined (__cplusplus)
+}
+#endif
+
+
+/* Allow faster testing for negative, zero, and positive.  */
+#define mpz_sgn(Z) ((Z)->_mp_size < 0 ? -1 : (Z)->_mp_size > 0)
+#define mpf_sgn(F) ((F)->_mp_size < 0 ? -1 : (F)->_mp_size > 0)
+#define mpq_sgn(Q) ((Q)->_mp_num._mp_size < 0 ? -1 : (Q)->_mp_num._mp_size > 0)
+
+/* When using GCC, optimize certain common comparisons.  */
+#if defined (__GNUC__) && __GNUC__ >= 2
+#define mpz_cmp_ui(Z,UI) \
+  (__builtin_constant_p (UI) && (UI) == 0				\
+   ? mpz_sgn (Z) : _mpz_cmp_ui (Z,UI))
+#define mpz_cmp_si(Z,SI)						\
+  (__builtin_constant_p ((SI) >= 0) && (SI) >= 0			\
+   ? mpz_cmp_ui (Z, __GMP_CAST (unsigned long, SI))			\
+   : _mpz_cmp_si (Z,SI))
+#define mpq_cmp_ui(Q,NUI,DUI)					\
+  (__builtin_constant_p (NUI) && (NUI) == 0 ? mpq_sgn (Q)	\
+   : __builtin_constant_p ((NUI) == (DUI)) && (NUI) == (DUI)	\
+   ? mpz_cmp (mpq_numref (Q), mpq_denref (Q))			\
+   : _mpq_cmp_ui (Q,NUI,DUI))
+#define mpq_cmp_si(q,n,d)				\
+  (__builtin_constant_p ((n) >= 0) && (n) >= 0		\
+   ? mpq_cmp_ui (q, __GMP_CAST (unsigned long, n), d)	\
+   : _mpq_cmp_si (q, n, d))
+#else
+#define mpz_cmp_ui(Z,UI) _mpz_cmp_ui (Z,UI)
+#define mpz_cmp_si(Z,UI) _mpz_cmp_si (Z,UI)
+#define mpq_cmp_ui(Q,NUI,DUI) _mpq_cmp_ui (Q,NUI,DUI)
+#define mpq_cmp_si(q,n,d)  _mpq_cmp_si(q,n,d)
+#endif
+
+
+/* Using "&" rather than "&&" means these can come out branch-free.  Every
+   mpz_t has at least one limb allocated, so fetching the low limb is always
+   allowed.  */
+#define mpz_odd_p(z)   (((z)->_mp_size != 0) & __GMP_CAST (int, (z)->_mp_d[0]))
+#define mpz_even_p(z)  (! mpz_odd_p (z))
+
+
+/**************** C++ routines ****************/
+
+#ifdef __cplusplus
+__GMP_DECLSPEC_XX std::ostream& operator<< (std::ostream &, mpz_srcptr);
+__GMP_DECLSPEC_XX std::ostream& operator<< (std::ostream &, mpq_srcptr);
+__GMP_DECLSPEC_XX std::ostream& operator<< (std::ostream &, mpf_srcptr);
+__GMP_DECLSPEC_XX std::istream& operator>> (std::istream &, mpz_ptr);
+__GMP_DECLSPEC_XX std::istream& operator>> (std::istream &, mpq_ptr);
+__GMP_DECLSPEC_XX std::istream& operator>> (std::istream &, mpf_ptr);
+#endif
+
+
+/* Source-level compatibility with GMP 2 and earlier. */
+#define mpn_divmod(qp,np,nsize,dp,dsize) \
+  mpn_divrem (qp, __GMP_CAST (mp_size_t, 0), np, nsize, dp, dsize)
+
+/* Source-level compatibility with GMP 1.  */
+#define mpz_mdiv	mpz_fdiv_q
+#define mpz_mdivmod	mpz_fdiv_qr
+#define mpz_mmod	mpz_fdiv_r
+#define mpz_mdiv_ui	mpz_fdiv_q_ui
+#define mpz_mdivmod_ui(q,r,n,d) \
+  (((r) == 0) ? mpz_fdiv_q_ui (q,n,d) : mpz_fdiv_qr_ui (q,r,n,d))
+#define mpz_mmod_ui(r,n,d) \
+  (((r) == 0) ? mpz_fdiv_ui (n,d) : mpz_fdiv_r_ui (r,n,d))
+
+/* Useful synonyms, but not quite compatible with GMP 1.  */
+#define mpz_div		mpz_fdiv_q
+#define mpz_divmod	mpz_fdiv_qr
+#define mpz_div_ui	mpz_fdiv_q_ui
+#define mpz_divmod_ui	mpz_fdiv_qr_ui
+#define mpz_div_2exp	mpz_fdiv_q_2exp
+#define mpz_mod_2exp	mpz_fdiv_r_2exp
+
+enum
+{
+  GMP_ERROR_NONE = 0,
+  GMP_ERROR_UNSUPPORTED_ARGUMENT = 1,
+  GMP_ERROR_DIVISION_BY_ZERO = 2,
+  GMP_ERROR_SQRT_OF_NEGATIVE = 4,
+  GMP_ERROR_INVALID_ARGUMENT = 8
+};
+
+/* Define CC and CFLAGS which were used to build this version of GMP */
+#define __GMP_CC "arm-frc2020-linux-gnueabi-gcc"
+#define __GMP_CFLAGS "-O2 -pedantic -fomit-frame-pointer -march=armv4 -mfloat-abi=softfp"
+
+/* Major version number is the value of __GNU_MP__ too, above. */
+#define __GNU_MP_VERSION            6
+#define __GNU_MP_VERSION_MINOR      2
+#define __GNU_MP_VERSION_PATCHLEVEL 0
+#define __GNU_MP_RELEASE (__GNU_MP_VERSION * 10000 + __GNU_MP_VERSION_MINOR * 100 + __GNU_MP_VERSION_PATCHLEVEL)
+
+#define __GMP_H__
+#endif /* __GMP_H__ */
diff --git a/third_party/gmp/config/arm64/config.h b/third_party/gmp/config/arm64/config.h
new file mode 100644
index 0000000..fcac711
--- /dev/null
+++ b/third_party/gmp/config/arm64/config.h
@@ -0,0 +1,668 @@
+/* config.h.  Generated from config.in by configure.  */
+/* config.in.  Generated from configure.ac by autoheader.  */
+
+/*
+
+Copyright 1996-2020 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.
+*/
+
+/* Define if building universal (internal helper macro) */
+/* #undef AC_APPLE_UNIVERSAL_BUILD */
+
+/* The gmp-mparam.h file (a string) the tune program should suggest updating.
+   */
+#define GMP_MPARAM_H_SUGGEST "./mpn/arm64/gmp-mparam.h"
+
+/* Define to 1 if you have the `alarm' function. */
+#define HAVE_ALARM 1
+
+/* Define to 1 if alloca() works (via gmp-impl.h). */
+#define HAVE_ALLOCA 1
+
+/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix).
+   */
+#define HAVE_ALLOCA_H 1
+
+/* Define to 1 if the compiler accepts gcc style __attribute__ ((const)) */
+#define HAVE_ATTRIBUTE_CONST 1
+
+/* Define to 1 if the compiler accepts gcc style __attribute__ ((malloc)) */
+#define HAVE_ATTRIBUTE_MALLOC 1
+
+/* Define to 1 if the compiler accepts gcc style __attribute__ ((mode (XX)))
+   */
+#define HAVE_ATTRIBUTE_MODE 1
+
+/* Define to 1 if the compiler accepts gcc style __attribute__ ((noreturn)) */
+#define HAVE_ATTRIBUTE_NORETURN 1
+
+/* Define to 1 if you have the `attr_get' function. */
+/* #undef HAVE_ATTR_GET */
+
+/* Define to 1 if tests/libtests has calling conventions checking for the CPU
+   */
+/* #undef HAVE_CALLING_CONVENTIONS */
+
+/* Define to 1 if you have the `clock' function. */
+#define HAVE_CLOCK 1
+
+/* Define to 1 if you have the `clock_gettime' function */
+#define HAVE_CLOCK_GETTIME 1
+
+/* Define to 1 if you have the `cputime' function. */
+/* #undef HAVE_CPUTIME */
+
+/* Define to 1 if you have the declaration of `fgetc', and to 0 if you don't.
+   */
+#define HAVE_DECL_FGETC 1
+
+/* Define to 1 if you have the declaration of `fscanf', and to 0 if you don't.
+   */
+#define HAVE_DECL_FSCANF 1
+
+/* Define to 1 if you have the declaration of `optarg', and to 0 if you don't.
+   */
+#define HAVE_DECL_OPTARG 1
+
+/* Define to 1 if you have the declaration of `sys_errlist', and to 0 if you
+   don't. */
+#define HAVE_DECL_SYS_ERRLIST 1
+
+/* Define to 1 if you have the declaration of `sys_nerr', and to 0 if you
+   don't. */
+#define HAVE_DECL_SYS_NERR 1
+
+/* Define to 1 if you have the declaration of `ungetc', and to 0 if you don't.
+   */
+#define HAVE_DECL_UNGETC 1
+
+/* Define to 1 if you have the declaration of `vfprintf', and to 0 if you
+   don't. */
+#define HAVE_DECL_VFPRINTF 1
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define one of the following to 1 for the format of a `double'.
+   If your format is not among these choices, or you don't know what it is,
+   then leave all undefined.
+   IEEE_LITTLE_SWAPPED means little endian, but with the two 4-byte halves
+   swapped, as used by ARM CPUs in little endian mode.  */
+/* #undef HAVE_DOUBLE_IEEE_BIG_ENDIAN */
+#define HAVE_DOUBLE_IEEE_LITTLE_ENDIAN 1
+/* #undef HAVE_DOUBLE_IEEE_LITTLE_SWAPPED */
+/* #undef HAVE_DOUBLE_VAX_D */
+/* #undef HAVE_DOUBLE_VAX_G */
+/* #undef HAVE_DOUBLE_CRAY_CFP */
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the <float.h> header file. */
+#define HAVE_FLOAT_H 1
+
+/* Define to 1 if you have the `getpagesize' function. */
+#define HAVE_GETPAGESIZE 1
+
+/* Define to 1 if you have the `getrusage' function. */
+#define HAVE_GETRUSAGE 1
+
+/* Define to 1 if you have the `getsysinfo' function. */
+/* #undef HAVE_GETSYSINFO */
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if the compiler accepts gcc style __attribute__ ((visibility))
+   and __attribute__ ((alias)) */
+#define HAVE_HIDDEN_ALIAS 1
+
+/* Define one of these to 1 for the host CPU family.
+   If your CPU is not in any of these families, leave all undefined.
+   For an AMD64 chip, define "x86" in ABI=32, but not in ABI=64. */
+/* #undef HAVE_HOST_CPU_FAMILY_alpha */
+/* #undef HAVE_HOST_CPU_FAMILY_m68k */
+/* #undef HAVE_HOST_CPU_FAMILY_power */
+/* #undef HAVE_HOST_CPU_FAMILY_powerpc */
+/* #undef HAVE_HOST_CPU_FAMILY_x86 */
+/* #undef HAVE_HOST_CPU_FAMILY_x86_64 */
+
+/* Define one of the following to 1 for the host CPU, as per the output of
+   ./config.guess.  If your CPU is not listed here, leave all undefined.  */
+/* #undef HAVE_HOST_CPU_alphaev67 */
+/* #undef HAVE_HOST_CPU_alphaev68 */
+/* #undef HAVE_HOST_CPU_alphaev7 */
+/* #undef HAVE_HOST_CPU_m68020 */
+/* #undef HAVE_HOST_CPU_m68030 */
+/* #undef HAVE_HOST_CPU_m68040 */
+/* #undef HAVE_HOST_CPU_m68060 */
+/* #undef HAVE_HOST_CPU_m68360 */
+/* #undef HAVE_HOST_CPU_powerpc604 */
+/* #undef HAVE_HOST_CPU_powerpc604e */
+/* #undef HAVE_HOST_CPU_powerpc750 */
+/* #undef HAVE_HOST_CPU_powerpc7400 */
+/* #undef HAVE_HOST_CPU_supersparc */
+/* #undef HAVE_HOST_CPU_i386 */
+/* #undef HAVE_HOST_CPU_i586 */
+/* #undef HAVE_HOST_CPU_i686 */
+/* #undef HAVE_HOST_CPU_pentium */
+/* #undef HAVE_HOST_CPU_pentiummmx */
+/* #undef HAVE_HOST_CPU_pentiumpro */
+/* #undef HAVE_HOST_CPU_pentium2 */
+/* #undef HAVE_HOST_CPU_pentium3 */
+/* #undef HAVE_HOST_CPU_pentium4 */
+/* #undef HAVE_HOST_CPU_core2 */
+/* #undef HAVE_HOST_CPU_nehalem */
+/* #undef HAVE_HOST_CPU_westmere */
+/* #undef HAVE_HOST_CPU_sandybridge */
+/* #undef HAVE_HOST_CPU_ivybridge */
+/* #undef HAVE_HOST_CPU_haswell */
+/* #undef HAVE_HOST_CPU_broadwell */
+/* #undef HAVE_HOST_CPU_skylake */
+/* #undef HAVE_HOST_CPU_silvermont */
+/* #undef HAVE_HOST_CPU_goldmont */
+/* #undef HAVE_HOST_CPU_k8 */
+/* #undef HAVE_HOST_CPU_k10 */
+/* #undef HAVE_HOST_CPU_bulldozer */
+/* #undef HAVE_HOST_CPU_piledriver */
+/* #undef HAVE_HOST_CPU_steamroller */
+/* #undef HAVE_HOST_CPU_excavator */
+/* #undef HAVE_HOST_CPU_zen */
+/* #undef HAVE_HOST_CPU_bobcat */
+/* #undef HAVE_HOST_CPU_jaguar */
+/* #undef HAVE_HOST_CPU_s390_z900 */
+/* #undef HAVE_HOST_CPU_s390_z990 */
+/* #undef HAVE_HOST_CPU_s390_z9 */
+/* #undef HAVE_HOST_CPU_s390_z10 */
+/* #undef HAVE_HOST_CPU_s390_z196 */
+
+/* Define to 1 iff we have a s390 with 64-bit registers.  */
+/* #undef HAVE_HOST_CPU_s390_zarch */
+
+/* Define to 1 if the system has the type `intmax_t'. */
+#define HAVE_INTMAX_T 1
+
+/* Define to 1 if the system has the type `intptr_t'. */
+#define HAVE_INTPTR_T 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the <invent.h> header file. */
+/* #undef HAVE_INVENT_H */
+
+/* Define to 1 if you have the <langinfo.h> header file. */
+#define HAVE_LANGINFO_H 1
+
+/* Define one of these to 1 for the endianness of `mp_limb_t'.
+   If the endianness is not a simple big or little, or you don't know what
+   it is, then leave both undefined. */
+/* #undef HAVE_LIMB_BIG_ENDIAN */
+#define HAVE_LIMB_LITTLE_ENDIAN 1
+
+/* Define to 1 if you have the `localeconv' function. */
+#define HAVE_LOCALECONV 1
+
+/* Define to 1 if you have the <locale.h> header file. */
+#define HAVE_LOCALE_H 1
+
+/* Define to 1 if the system has the type `long double'. */
+#define HAVE_LONG_DOUBLE 1
+
+/* Define to 1 if the system has the type `long long'. */
+#define HAVE_LONG_LONG 1
+
+/* Define to 1 if you have the <machine/hal_sysinfo.h> header file. */
+/* #undef HAVE_MACHINE_HAL_SYSINFO_H */
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `memset' function. */
+#define HAVE_MEMSET 1
+
+/* Define to 1 if you have the `mmap' function. */
+#define HAVE_MMAP 1
+
+/* Define to 1 if you have the `mprotect' function. */
+#define HAVE_MPROTECT 1
+
+/* Define to 1 each of the following for which a native (ie. CPU specific)
+    implementation of the corresponding routine exists.  */
+#define HAVE_NATIVE_mpn_add_n 1
+/* #undef HAVE_NATIVE_mpn_add_n_sub_n */
+#define HAVE_NATIVE_mpn_add_nc 1
+/* #undef HAVE_NATIVE_mpn_addaddmul_1msb0 */
+#define HAVE_NATIVE_mpn_addlsh1_n 1
+#define HAVE_NATIVE_mpn_addlsh2_n 1
+/* #undef HAVE_NATIVE_mpn_addlsh_n */
+/* #undef HAVE_NATIVE_mpn_addlsh1_nc */
+/* #undef HAVE_NATIVE_mpn_addlsh2_nc */
+/* #undef HAVE_NATIVE_mpn_addlsh_nc */
+/* #undef HAVE_NATIVE_mpn_addlsh1_n_ip1 */
+/* #undef HAVE_NATIVE_mpn_addlsh2_n_ip1 */
+/* #undef HAVE_NATIVE_mpn_addlsh_n_ip1 */
+/* #undef HAVE_NATIVE_mpn_addlsh1_nc_ip1 */
+/* #undef HAVE_NATIVE_mpn_addlsh2_nc_ip1 */
+/* #undef HAVE_NATIVE_mpn_addlsh_nc_ip1 */
+/* #undef HAVE_NATIVE_mpn_addlsh1_n_ip2 */
+/* #undef HAVE_NATIVE_mpn_addlsh2_n_ip2 */
+/* #undef HAVE_NATIVE_mpn_addlsh_n_ip2 */
+/* #undef HAVE_NATIVE_mpn_addlsh1_nc_ip2 */
+/* #undef HAVE_NATIVE_mpn_addlsh2_nc_ip2 */
+/* #undef HAVE_NATIVE_mpn_addlsh_nc_ip2 */
+/* #undef HAVE_NATIVE_mpn_addmul_1c */
+/* #undef HAVE_NATIVE_mpn_addmul_2 */
+/* #undef HAVE_NATIVE_mpn_addmul_3 */
+/* #undef HAVE_NATIVE_mpn_addmul_4 */
+/* #undef HAVE_NATIVE_mpn_addmul_5 */
+/* #undef HAVE_NATIVE_mpn_addmul_6 */
+/* #undef HAVE_NATIVE_mpn_addmul_7 */
+/* #undef HAVE_NATIVE_mpn_addmul_8 */
+/* #undef HAVE_NATIVE_mpn_addmul_2s */
+#define HAVE_NATIVE_mpn_and_n 1
+#define HAVE_NATIVE_mpn_andn_n 1
+#define HAVE_NATIVE_mpn_bdiv_dbm1c 1
+#define HAVE_NATIVE_mpn_bdiv_q_1 1
+#define HAVE_NATIVE_mpn_pi1_bdiv_q_1 1
+#define HAVE_NATIVE_mpn_cnd_add_n 1
+#define HAVE_NATIVE_mpn_cnd_sub_n 1
+#define HAVE_NATIVE_mpn_com 1
+#define HAVE_NATIVE_mpn_copyd 1
+#define HAVE_NATIVE_mpn_copyi 1
+/* #undef HAVE_NATIVE_mpn_div_qr_1n_pi1 */
+/* #undef HAVE_NATIVE_mpn_div_qr_2 */
+/* #undef HAVE_NATIVE_mpn_divexact_1 */
+/* #undef HAVE_NATIVE_mpn_divexact_by3c */
+/* #undef HAVE_NATIVE_mpn_divrem_1 */
+/* #undef HAVE_NATIVE_mpn_divrem_1c */
+/* #undef HAVE_NATIVE_mpn_divrem_2 */
+/* #undef HAVE_NATIVE_mpn_gcd_1 */
+#define HAVE_NATIVE_mpn_gcd_11 1
+#define HAVE_NATIVE_mpn_gcd_22 1
+#define HAVE_NATIVE_mpn_hamdist 1
+#define HAVE_NATIVE_mpn_invert_limb 1
+#define HAVE_NATIVE_mpn_ior_n 1
+#define HAVE_NATIVE_mpn_iorn_n 1
+#define HAVE_NATIVE_mpn_lshift 1
+#define HAVE_NATIVE_mpn_lshiftc 1
+/* #undef HAVE_NATIVE_mpn_lshsub_n */
+/* #undef HAVE_NATIVE_mpn_mod_1 */
+/* #undef HAVE_NATIVE_mpn_mod_1_1p */
+/* #undef HAVE_NATIVE_mpn_mod_1c */
+/* #undef HAVE_NATIVE_mpn_mod_1s_2p */
+/* #undef HAVE_NATIVE_mpn_mod_1s_4p */
+#define HAVE_NATIVE_mpn_mod_34lsub1 1
+/* #undef HAVE_NATIVE_mpn_modexact_1_odd */
+/* #undef HAVE_NATIVE_mpn_modexact_1c_odd */
+#define HAVE_NATIVE_mpn_mul_1 1
+#define HAVE_NATIVE_mpn_mul_1c 1
+/* #undef HAVE_NATIVE_mpn_mul_2 */
+/* #undef HAVE_NATIVE_mpn_mul_3 */
+/* #undef HAVE_NATIVE_mpn_mul_4 */
+/* #undef HAVE_NATIVE_mpn_mul_5 */
+/* #undef HAVE_NATIVE_mpn_mul_6 */
+/* #undef HAVE_NATIVE_mpn_mul_basecase */
+/* #undef HAVE_NATIVE_mpn_mullo_basecase */
+#define HAVE_NATIVE_mpn_nand_n 1
+#define HAVE_NATIVE_mpn_nior_n 1
+#define HAVE_NATIVE_mpn_popcount 1
+/* #undef HAVE_NATIVE_mpn_preinv_divrem_1 */
+/* #undef HAVE_NATIVE_mpn_preinv_mod_1 */
+/* #undef HAVE_NATIVE_mpn_redc_1 */
+/* #undef HAVE_NATIVE_mpn_redc_2 */
+#define HAVE_NATIVE_mpn_rsblsh1_n 1
+#define HAVE_NATIVE_mpn_rsblsh2_n 1
+/* #undef HAVE_NATIVE_mpn_rsblsh_n */
+/* #undef HAVE_NATIVE_mpn_rsblsh1_nc */
+/* #undef HAVE_NATIVE_mpn_rsblsh2_nc */
+/* #undef HAVE_NATIVE_mpn_rsblsh_nc */
+#define HAVE_NATIVE_mpn_rsh1add_n 1
+/* #undef HAVE_NATIVE_mpn_rsh1add_nc */
+#define HAVE_NATIVE_mpn_rsh1sub_n 1
+/* #undef HAVE_NATIVE_mpn_rsh1sub_nc */
+#define HAVE_NATIVE_mpn_rshift 1
+/* #undef HAVE_NATIVE_mpn_sbpi1_bdiv_r */
+/* #undef HAVE_NATIVE_mpn_sqr_basecase */
+/* #undef HAVE_NATIVE_mpn_sqr_diagonal */
+#define HAVE_NATIVE_mpn_sqr_diag_addlsh1 1
+#define HAVE_NATIVE_mpn_sub_n 1
+#define HAVE_NATIVE_mpn_sub_nc 1
+#define HAVE_NATIVE_mpn_sublsh1_n 1
+#define HAVE_NATIVE_mpn_sublsh2_n 1
+/* #undef HAVE_NATIVE_mpn_sublsh_n */
+/* #undef HAVE_NATIVE_mpn_sublsh1_nc */
+/* #undef HAVE_NATIVE_mpn_sublsh2_nc */
+/* #undef HAVE_NATIVE_mpn_sublsh_nc */
+/* #undef HAVE_NATIVE_mpn_sublsh1_n_ip1 */
+/* #undef HAVE_NATIVE_mpn_sublsh2_n_ip1 */
+/* #undef HAVE_NATIVE_mpn_sublsh_n_ip1 */
+/* #undef HAVE_NATIVE_mpn_sublsh1_nc_ip1 */
+/* #undef HAVE_NATIVE_mpn_sublsh2_nc_ip1 */
+/* #undef HAVE_NATIVE_mpn_sublsh_nc_ip1 */
+/* #undef HAVE_NATIVE_mpn_submul_1c */
+/* #undef HAVE_NATIVE_mpn_tabselect */
+/* #undef HAVE_NATIVE_mpn_udiv_qrnnd */
+/* #undef HAVE_NATIVE_mpn_udiv_qrnnd_r */
+/* #undef HAVE_NATIVE_mpn_umul_ppmm */
+/* #undef HAVE_NATIVE_mpn_umul_ppmm_r */
+#define HAVE_NATIVE_mpn_xor_n 1
+#define HAVE_NATIVE_mpn_xnor_n 1
+
+/* Define to 1 if you have the `nl_langinfo' function. */
+#define HAVE_NL_LANGINFO 1
+
+/* Define to 1 if you have the <nl_types.h> header file. */
+#define HAVE_NL_TYPES_H 1
+
+/* Define to 1 if you have the `obstack_vprintf' function. */
+#define HAVE_OBSTACK_VPRINTF 1
+
+/* Define to 1 if you have the `popen' function. */
+#define HAVE_POPEN 1
+
+/* Define to 1 if you have the `processor_info' function. */
+/* #undef HAVE_PROCESSOR_INFO */
+
+/* Define to 1 if <sys/pstat.h> `struct pst_processor' exists and contains
+   `psp_iticksperclktick'. */
+/* #undef HAVE_PSP_ITICKSPERCLKTICK */
+
+/* Define to 1 if you have the `pstat_getprocessor' function. */
+/* #undef HAVE_PSTAT_GETPROCESSOR */
+
+/* Define to 1 if the system has the type `ptrdiff_t'. */
+#define HAVE_PTRDIFF_T 1
+
+/* Define to 1 if the system has the type `quad_t'. */
+#define HAVE_QUAD_T 1
+
+/* Define to 1 if you have the `raise' function. */
+#define HAVE_RAISE 1
+
+/* Define to 1 if you have the `read_real_time' function. */
+/* #undef HAVE_READ_REAL_TIME */
+
+/* Define to 1 if you have the `sigaction' function. */
+#define HAVE_SIGACTION 1
+
+/* Define to 1 if you have the `sigaltstack' function. */
+#define HAVE_SIGALTSTACK 1
+
+/* Define to 1 if you have the `sigstack' function. */
+#define HAVE_SIGSTACK 1
+
+/* Tune directory speed_cyclecounter, undef=none, 1=32bits, 2=64bits) */
+/* #undef HAVE_SPEED_CYCLECOUNTER */
+
+/* Define to 1 if you have the <sstream> header file. */
+#define HAVE_SSTREAM 1
+
+/* Define to 1 if the system has the type `stack_t'. */
+#define HAVE_STACK_T 1
+
+/* 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 the system has the type `std::locale'. */
+#define HAVE_STD__LOCALE 1
+
+/* Define to 1 if you have the `strchr' function. */
+#define HAVE_STRCHR 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. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strnlen' function. */
+#define HAVE_STRNLEN 1
+
+/* Define to 1 if you have the `strtol' function. */
+#define HAVE_STRTOL 1
+
+/* Define to 1 if you have the `strtoul' function. */
+#define HAVE_STRTOUL 1
+
+/* Define to 1 if you have the `sysconf' function. */
+#define HAVE_SYSCONF 1
+
+/* Define to 1 if you have the `sysctl' function. */
+/* #undef HAVE_SYSCTL */
+
+/* Define to 1 if you have the `sysctlbyname' function. */
+/* #undef HAVE_SYSCTLBYNAME */
+
+/* Define to 1 if you have the `syssgi' function. */
+/* #undef HAVE_SYSSGI */
+
+/* Define to 1 if you have the <sys/attributes.h> header file. */
+/* #undef HAVE_SYS_ATTRIBUTES_H */
+
+/* Define to 1 if you have the <sys/iograph.h> header file. */
+/* #undef HAVE_SYS_IOGRAPH_H */
+
+/* Define to 1 if you have the <sys/mman.h> header file. */
+#define HAVE_SYS_MMAN_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/processor.h> header file. */
+/* #undef HAVE_SYS_PROCESSOR_H */
+
+/* Define to 1 if you have the <sys/pstat.h> header file. */
+/* #undef HAVE_SYS_PSTAT_H */
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#define HAVE_SYS_RESOURCE_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/sysctl.h> header file. */
+#define HAVE_SYS_SYSCTL_H 1
+
+/* Define to 1 if you have the <sys/sysinfo.h> header file. */
+#define HAVE_SYS_SYSINFO_H 1
+
+/* Define to 1 if you have the <sys/syssgi.h> header file. */
+/* #undef HAVE_SYS_SYSSGI_H */
+
+/* Define to 1 if you have the <sys/systemcfg.h> header file. */
+/* #undef HAVE_SYS_SYSTEMCFG_H */
+
+/* Define to 1 if you have the <sys/times.h> header file. */
+#define HAVE_SYS_TIMES_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the `times' function. */
+#define HAVE_TIMES 1
+
+/* Define to 1 if the system has the type `uint_least32_t'. */
+#define HAVE_UINT_LEAST32_T 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `vsnprintf' function and it works properly. */
+#define HAVE_VSNPRINTF 1
+
+/* Define to 1 for Windos/64 */
+/* #undef HOST_DOS64 */
+
+/* Assembler local label prefix */
+#define LSYM_PREFIX ".L"
+
+/* Define to the sub-directory where libtool stores uninstalled libraries. */
+#define LT_OBJDIR ".libs/"
+
+/* Define to 1 to disable the use of inline assembly */
+/* #undef NO_ASM */
+
+/* Name of package */
+#define PACKAGE "gmp"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "gmp-bugs@gmplib.org, see https://gmplib.org/manual/Reporting-Bugs.html"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "GNU MP"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "GNU MP 6.2.0"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "gmp"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL "http://www.gnu.org/software/gmp/"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "6.2.0"
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#define RETSIGTYPE void
+
+/* The size of `mp_limb_t', as computed by sizeof. */
+#define SIZEOF_MP_LIMB_T 8
+
+/* The size of `unsigned', as computed by sizeof. */
+#define SIZEOF_UNSIGNED 4
+
+/* The size of `unsigned long', as computed by sizeof. */
+#define SIZEOF_UNSIGNED_LONG 8
+
+/* The size of `unsigned short', as computed by sizeof. */
+#define SIZEOF_UNSIGNED_SHORT 2
+
+/* The size of `void *', as computed by sizeof. */
+#define SIZEOF_VOID_P 8
+
+/* Define to 1 if sscanf requires writable inputs */
+/* #undef SSCANF_WRITABLE_INPUT */
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Maximum size the tune program can test for SQR_TOOM2_THRESHOLD */
+#define TUNE_SQR_TOOM2_MAX SQR_TOOM2_MAX_GENERIC
+
+/* Version number of package */
+#define VERSION "6.2.0"
+
+/* Define to 1 to enable ASSERT checking, per --enable-assert */
+/* #undef WANT_ASSERT */
+
+/* Define to 1 to enable GMP_CPU_TYPE faking cpuid, per --enable-fake-cpuid */
+/* #undef WANT_FAKE_CPUID */
+
+/* Define to 1 when building a fat binary. */
+/* #undef WANT_FAT_BINARY */
+
+/* Define to 1 to enable FFTs for multiplication, per --enable-fft */
+#define WANT_FFT 1
+
+/* Define to 1 to enable old mpn_mul_fft_full for multiplication, per
+   --enable-old-fft-full */
+/* #undef WANT_OLD_FFT_FULL */
+
+/* Define to 1 if --enable-profiling=gprof */
+/* #undef WANT_PROFILING_GPROF */
+
+/* Define to 1 if --enable-profiling=instrument */
+/* #undef WANT_PROFILING_INSTRUMENT */
+
+/* Define to 1 if --enable-profiling=prof */
+/* #undef WANT_PROFILING_PROF */
+
+/* Define one of these to 1 for the desired temporary memory allocation
+   method, per --enable-alloca. */
+#define WANT_TMP_ALLOCA 1
+/* #undef WANT_TMP_REENTRANT */
+/* #undef WANT_TMP_NOTREENTRANT */
+/* #undef WANT_TMP_DEBUG */
+
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+   significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+#  define WORDS_BIGENDIAN 1
+# endif
+#else
+# ifndef WORDS_BIGENDIAN
+/* #  undef WORDS_BIGENDIAN */
+# endif
+#endif
+
+/* Define to 1 if the assembler understands the mulx instruction */
+/* #undef X86_ASM_MULX */
+
+/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
+   `char[]'. */
+#define YYTEXT_POINTER 1
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to the equivalent of the C99 'restrict' keyword, or to
+   nothing if this is not supported.  Do not define if restrict is
+   supported directly.  */
+#define restrict __restrict
+/* Work around a bug in Sun C++: it does not support _Restrict or
+   __restrict__, even though the corresponding Sun C compiler ends up with
+   "#define restrict _Restrict" or "#define restrict __restrict__" in the
+   previous line.  Perhaps some future version of Sun C++ will work with
+   restrict; if so, hopefully it defines __RESTRICT like Sun C does.  */
+#if defined __SUNPRO_CC && !defined __RESTRICT
+# define _Restrict
+# define __restrict__
+#endif
+
+/* Define to empty if the keyword `volatile' does not work. Warning: valid
+   code using `volatile' can become incorrect without. Disable with care. */
+/* #undef volatile */
diff --git a/third_party/gmp/config/arm64/config.m4 b/third_party/gmp/config/arm64/config.m4
new file mode 100644
index 0000000..15a10dd
--- /dev/null
+++ b/third_party/gmp/config/arm64/config.m4
@@ -0,0 +1,35 @@
+dnl config.m4.  Generated automatically by configure.
+changequote(<,>)
+ifdef(<__CONFIG_M4_INCLUDED__>,,<
+define(<CONFIG_TOP_SRCDIR>,<`../.'>)
+define(<WANT_ASSERT>,0)
+define(<WANT_PROFILING>,<`no'>)
+define(<M4WRAP_SPURIOUS>,<no>)
+define(<TEXT>, <.text>)
+define(<DATA>, <.data>)
+define(<LABEL_SUFFIX>, <:>)
+define(<GLOBL>, <.globl>)
+define(<GLOBL_ATTR>, <>)
+define(<GSYM_PREFIX>, <>)
+define(<RODATA>, <	.section	.rodata>)
+define(<TYPE>, <.type	$1,@$2>)
+define(<SIZE>, <.size	$1,$2>)
+define(<LSYM_PREFIX>, <.L>)
+define(<W32>, <.long>)
+define(<ALIGN_LOGARITHMIC>,<yes>)
+define(<SQR_TOOM2_THRESHOLD>,<18>)
+define(<BMOD_1_TO_MOD_1_THRESHOLD>,<40>)
+define(<SIZEOF_UNSIGNED>,<4>)
+define(<GMP_LIMB_BITS>,64)
+define(<GMP_NAIL_BITS>,0)
+define(<GMP_NUMB_BITS>,eval(GMP_LIMB_BITS-GMP_NAIL_BITS))
+>)
+changequote(`,')
+ifdef(`__CONFIG_M4_INCLUDED__',,`
+include(CONFIG_TOP_SRCDIR`/mpn/asm-defs.m4')
+define_not_for_expansion(`HAVE_HOST_CPU_aarch64')
+define_not_for_expansion(`HAVE_ABI_64')
+define_not_for_expansion(`HAVE_LIMB_LITTLE_ENDIAN')
+define_not_for_expansion(`HAVE_DOUBLE_IEEE_LITTLE_ENDIAN')
+')
+define(`__CONFIG_M4_INCLUDED__')
diff --git a/third_party/gmp/config/arm64/gmp.h b/third_party/gmp/config/arm64/gmp.h
new file mode 100644
index 0000000..133edc3
--- /dev/null
+++ b/third_party/gmp/config/arm64/gmp.h
@@ -0,0 +1,2336 @@
+/* Definitions for GNU multiple precision functions.   -*- mode: c -*-
+
+Copyright 1991, 1993-1997, 1999-2016, 2020 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#ifndef __GMP_H__
+
+#if defined (__cplusplus)
+#include <iosfwd>   /* for std::istream, std::ostream, std::string */
+#include <cstdio>
+#endif
+
+
+/* Instantiated by configure. */
+#if ! defined (__GMP_WITHIN_CONFIGURE)
+#define __GMP_HAVE_HOST_CPU_FAMILY_power   0
+#define __GMP_HAVE_HOST_CPU_FAMILY_powerpc 0
+#define GMP_LIMB_BITS                      64
+#define GMP_NAIL_BITS                      0
+#endif
+#define GMP_NUMB_BITS     (GMP_LIMB_BITS - GMP_NAIL_BITS)
+#define GMP_NUMB_MASK     ((~ __GMP_CAST (mp_limb_t, 0)) >> GMP_NAIL_BITS)
+#define GMP_NUMB_MAX      GMP_NUMB_MASK
+#define GMP_NAIL_MASK     (~ GMP_NUMB_MASK)
+
+
+#ifndef __GNU_MP__
+#define __GNU_MP__ 6
+
+#include <stddef.h>    /* for size_t */
+#include <limits.h>
+
+/* Instantiated by configure. */
+#if ! defined (__GMP_WITHIN_CONFIGURE)
+/* #undef _LONG_LONG_LIMB */
+#define __GMP_LIBGMP_DLL  0
+#endif
+
+
+/* __GMP_DECLSPEC supports Windows DLL versions of libgmp, and is empty in
+   all other circumstances.
+
+   When compiling objects for libgmp, __GMP_DECLSPEC is an export directive,
+   or when compiling for an application it's an import directive.  The two
+   cases are differentiated by __GMP_WITHIN_GMP defined by the GMP Makefiles
+   (and not defined from an application).
+
+   __GMP_DECLSPEC_XX is similarly used for libgmpxx.  __GMP_WITHIN_GMPXX
+   indicates when building libgmpxx, and in that case libgmpxx functions are
+   exports, but libgmp functions which might get called are imports.
+
+   Libtool DLL_EXPORT define is not used.
+
+   There's no attempt to support GMP built both static and DLL.  Doing so
+   would mean applications would have to tell us which of the two is going
+   to be used when linking, and that seems very tedious and error prone if
+   using GMP by hand, and equally tedious from a package since autoconf and
+   automake don't give much help.
+
+   __GMP_DECLSPEC is required on all documented global functions and
+   variables, the various internals in gmp-impl.h etc can be left unadorned.
+   But internals used by the test programs or speed measuring programs
+   should have __GMP_DECLSPEC, and certainly constants or variables must
+   have it or the wrong address will be resolved.
+
+   In gcc __declspec can go at either the start or end of a prototype.
+
+   In Microsoft C __declspec must go at the start, or after the type like
+   void __declspec(...) *foo()".  There's no __dllexport or anything to
+   guard against someone foolish #defining dllexport.  _export used to be
+   available, but no longer.
+
+   In Borland C _export still exists, but needs to go after the type, like
+   "void _export foo();".  Would have to change the __GMP_DECLSPEC syntax to
+   make use of that.  Probably more trouble than it's worth.  */
+
+#if defined (__GNUC__)
+#define __GMP_DECLSPEC_EXPORT  __declspec(__dllexport__)
+#define __GMP_DECLSPEC_IMPORT  __declspec(__dllimport__)
+#endif
+#if defined (_MSC_VER) || defined (__BORLANDC__)
+#define __GMP_DECLSPEC_EXPORT  __declspec(dllexport)
+#define __GMP_DECLSPEC_IMPORT  __declspec(dllimport)
+#endif
+#ifdef __WATCOMC__
+#define __GMP_DECLSPEC_EXPORT  __export
+#define __GMP_DECLSPEC_IMPORT  __import
+#endif
+#ifdef __IBMC__
+#define __GMP_DECLSPEC_EXPORT  _Export
+#define __GMP_DECLSPEC_IMPORT  _Import
+#endif
+
+#if __GMP_LIBGMP_DLL
+#ifdef __GMP_WITHIN_GMP
+/* compiling to go into a DLL libgmp */
+#define __GMP_DECLSPEC  __GMP_DECLSPEC_EXPORT
+#else
+/* compiling to go into an application which will link to a DLL libgmp */
+#define __GMP_DECLSPEC  __GMP_DECLSPEC_IMPORT
+#endif
+#else
+/* all other cases */
+#define __GMP_DECLSPEC
+#endif
+
+
+#ifdef __GMP_SHORT_LIMB
+typedef unsigned int		mp_limb_t;
+typedef int			mp_limb_signed_t;
+#else
+#ifdef _LONG_LONG_LIMB
+typedef unsigned long long int	mp_limb_t;
+typedef long long int		mp_limb_signed_t;
+#else
+typedef unsigned long int	mp_limb_t;
+typedef long int		mp_limb_signed_t;
+#endif
+#endif
+typedef unsigned long int	mp_bitcnt_t;
+
+/* For reference, note that the name __mpz_struct gets into C++ mangled
+   function names, which means although the "__" suggests an internal, we
+   must leave this name for binary compatibility.  */
+typedef struct
+{
+  int _mp_alloc;		/* Number of *limbs* allocated and pointed
+				   to by the _mp_d field.  */
+  int _mp_size;			/* abs(_mp_size) is the number of limbs the
+				   last field points to.  If _mp_size is
+				   negative this is a negative number.  */
+  mp_limb_t *_mp_d;		/* Pointer to the limbs.  */
+} __mpz_struct;
+
+#endif /* __GNU_MP__ */
+
+
+typedef __mpz_struct MP_INT;    /* gmp 1 source compatibility */
+typedef __mpz_struct mpz_t[1];
+
+typedef mp_limb_t *		mp_ptr;
+typedef const mp_limb_t *	mp_srcptr;
+#if defined (_CRAY) && ! defined (_CRAYMPP)
+/* plain `int' is much faster (48 bits) */
+#define __GMP_MP_SIZE_T_INT     1
+typedef int			mp_size_t;
+typedef int			mp_exp_t;
+#else
+#define __GMP_MP_SIZE_T_INT     0
+typedef long int		mp_size_t;
+typedef long int		mp_exp_t;
+#endif
+
+typedef struct
+{
+  __mpz_struct _mp_num;
+  __mpz_struct _mp_den;
+} __mpq_struct;
+
+typedef __mpq_struct MP_RAT;    /* gmp 1 source compatibility */
+typedef __mpq_struct mpq_t[1];
+
+typedef struct
+{
+  int _mp_prec;			/* Max precision, in number of `mp_limb_t's.
+				   Set by mpf_init and modified by
+				   mpf_set_prec.  The area pointed to by the
+				   _mp_d field contains `prec' + 1 limbs.  */
+  int _mp_size;			/* abs(_mp_size) is the number of limbs the
+				   last field points to.  If _mp_size is
+				   negative this is a negative number.  */
+  mp_exp_t _mp_exp;		/* Exponent, in the base of `mp_limb_t'.  */
+  mp_limb_t *_mp_d;		/* Pointer to the limbs.  */
+} __mpf_struct;
+
+/* typedef __mpf_struct MP_FLOAT; */
+typedef __mpf_struct mpf_t[1];
+
+/* Available random number generation algorithms.  */
+typedef enum
+{
+  GMP_RAND_ALG_DEFAULT = 0,
+  GMP_RAND_ALG_LC = GMP_RAND_ALG_DEFAULT /* Linear congruential.  */
+} gmp_randalg_t;
+
+/* Random state struct.  */
+typedef struct
+{
+  mpz_t _mp_seed;	  /* _mp_d member points to state of the generator. */
+  gmp_randalg_t _mp_alg;  /* Currently unused. */
+  union {
+    void *_mp_lc;         /* Pointer to function pointers structure.  */
+  } _mp_algdata;
+} __gmp_randstate_struct;
+typedef __gmp_randstate_struct gmp_randstate_t[1];
+
+/* Types for function declarations in gmp files.  */
+/* ??? Should not pollute user name space with these ??? */
+typedef const __mpz_struct *mpz_srcptr;
+typedef __mpz_struct *mpz_ptr;
+typedef const __mpf_struct *mpf_srcptr;
+typedef __mpf_struct *mpf_ptr;
+typedef const __mpq_struct *mpq_srcptr;
+typedef __mpq_struct *mpq_ptr;
+
+
+#if __GMP_LIBGMP_DLL
+#ifdef __GMP_WITHIN_GMPXX
+/* compiling to go into a DLL libgmpxx */
+#define __GMP_DECLSPEC_XX  __GMP_DECLSPEC_EXPORT
+#else
+/* compiling to go into a application which will link to a DLL libgmpxx */
+#define __GMP_DECLSPEC_XX  __GMP_DECLSPEC_IMPORT
+#endif
+#else
+/* all other cases */
+#define __GMP_DECLSPEC_XX
+#endif
+
+
+#ifndef __MPN
+#define __MPN(x) __gmpn_##x
+#endif
+
+/* For reference, "defined(EOF)" cannot be used here.  In g++ 2.95.4,
+   <iostream> defines EOF but not FILE.  */
+#if defined (FILE)                                              \
+  || defined (H_STDIO)                                          \
+  || defined (_H_STDIO)               /* AIX */                 \
+  || defined (_STDIO_H)               /* glibc, Sun, SCO */     \
+  || defined (_STDIO_H_)              /* BSD, OSF */            \
+  || defined (__STDIO_H)              /* Borland */             \
+  || defined (__STDIO_H__)            /* IRIX */                \
+  || defined (_STDIO_INCLUDED)        /* HPUX */                \
+  || defined (__dj_include_stdio_h_)  /* DJGPP */               \
+  || defined (_FILE_DEFINED)          /* Microsoft */           \
+  || defined (__STDIO__)              /* Apple MPW MrC */       \
+  || defined (_MSL_STDIO_H)           /* Metrowerks */          \
+  || defined (_STDIO_H_INCLUDED)      /* QNX4 */		\
+  || defined (_ISO_STDIO_ISO_H)       /* Sun C++ */		\
+  || defined (__STDIO_LOADED)         /* VMS */			\
+  || defined (__DEFINED_FILE)         /* musl */
+#define _GMP_H_HAVE_FILE 1
+#endif
+
+/* In ISO C, if a prototype involving "struct obstack *" is given without
+   that structure defined, then the struct is scoped down to just the
+   prototype, causing a conflict if it's subsequently defined for real.  So
+   only give prototypes if we've got obstack.h.  */
+#if defined (_OBSTACK_H)   /* glibc <obstack.h> */
+#define _GMP_H_HAVE_OBSTACK 1
+#endif
+
+/* The prototypes for gmp_vprintf etc are provided only if va_list is defined,
+   via an application having included <stdarg.h>.  Usually va_list is a typedef
+   so can't be tested directly, but C99 specifies that va_start is a macro.
+
+   <stdio.h> will define some sort of va_list for vprintf and vfprintf, but
+   let's not bother trying to use that since it's not standard and since
+   application uses for gmp_vprintf etc will almost certainly require the
+   whole <stdarg.h> anyway.  */
+
+#ifdef va_start
+#define _GMP_H_HAVE_VA_LIST 1
+#endif
+
+/* Test for gcc >= maj.min, as per __GNUC_PREREQ in glibc */
+#if defined (__GNUC__) && defined (__GNUC_MINOR__)
+#define __GMP_GNUC_PREREQ(maj, min) \
+  ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
+#else
+#define __GMP_GNUC_PREREQ(maj, min)  0
+#endif
+
+/* "pure" is in gcc 2.96 and up, see "(gcc)Function Attributes".  Basically
+   it means a function does nothing but examine its arguments and memory
+   (global or via arguments) to generate a return value, but changes nothing
+   and has no side-effects.  __GMP_NO_ATTRIBUTE_CONST_PURE lets
+   tune/common.c etc turn this off when trying to write timing loops.  */
+#if __GMP_GNUC_PREREQ (2,96) && ! defined (__GMP_NO_ATTRIBUTE_CONST_PURE)
+#define __GMP_ATTRIBUTE_PURE   __attribute__ ((__pure__))
+#else
+#define __GMP_ATTRIBUTE_PURE
+#endif
+
+
+/* __GMP_CAST allows us to use static_cast in C++, so our macros are clean
+   to "g++ -Wold-style-cast".
+
+   Casts in "extern inline" code within an extern "C" block don't induce
+   these warnings, so __GMP_CAST only needs to be used on documented
+   macros.  */
+
+#ifdef __cplusplus
+#define __GMP_CAST(type, expr)  (static_cast<type> (expr))
+#else
+#define __GMP_CAST(type, expr)  ((type) (expr))
+#endif
+
+
+/* An empty "throw ()" means the function doesn't throw any C++ exceptions,
+   this can save some stack frame info in applications.
+
+   Currently it's given only on functions which never divide-by-zero etc,
+   don't allocate memory, and are expected to never need to allocate memory.
+   This leaves open the possibility of a C++ throw from a future GMP
+   exceptions scheme.
+
+   mpz_set_ui etc are omitted to leave open the lazy allocation scheme
+   described in doc/tasks.html.  mpz_get_d etc are omitted to leave open
+   exceptions for float overflows.
+
+   Note that __GMP_NOTHROW must be given on any inlines the same as on their
+   prototypes (for g++ at least, where they're used together).  Note also
+   that g++ 3.0 demands that __GMP_NOTHROW is before other attributes like
+   __GMP_ATTRIBUTE_PURE.  */
+
+#if defined (__cplusplus)
+#if __cplusplus >= 201103L
+#define __GMP_NOTHROW  noexcept
+#else
+#define __GMP_NOTHROW  throw ()
+#endif
+#else
+#define __GMP_NOTHROW
+#endif
+
+
+/* PORTME: What other compilers have a useful "extern inline"?  "static
+   inline" would be an acceptable substitute if the compiler (or linker)
+   discards unused statics.  */
+
+ /* gcc has __inline__ in all modes, including strict ansi.  Give a prototype
+    for an inline too, so as to correctly specify "dllimport" on windows, in
+    case the function is called rather than inlined.
+    GCC 4.3 and above with -std=c99 or -std=gnu99 implements ISO C99
+    inline semantics, unless -fgnu89-inline is used.  */
+#ifdef __GNUC__
+#if (defined __GNUC_STDC_INLINE__) || (__GNUC__ == 4 && __GNUC_MINOR__ == 2) \
+  || (defined __GNUC_GNU_INLINE__ && defined __cplusplus)
+#define __GMP_EXTERN_INLINE extern __inline__ __attribute__ ((__gnu_inline__))
+#else
+#define __GMP_EXTERN_INLINE      extern __inline__
+#endif
+#define __GMP_INLINE_PROTOTYPES  1
+#endif
+
+/* DEC C (eg. version 5.9) supports "static __inline foo()", even in -std1
+   strict ANSI mode.  Inlining is done even when not optimizing (ie. -O0
+   mode, which is the default), but an unnecessary local copy of foo is
+   emitted unless -O is used.  "extern __inline" is accepted, but the
+   "extern" appears to be ignored, ie. it becomes a plain global function
+   but which is inlined within its file.  Don't know if all old versions of
+   DEC C supported __inline, but as a start let's do the right thing for
+   current versions.  */
+#ifdef __DECC
+#define __GMP_EXTERN_INLINE  static __inline
+#endif
+
+/* SCO OpenUNIX 8 cc supports "static inline foo()" but not in -Xc strict
+   ANSI mode (__STDC__ is 1 in that mode).  Inlining only actually takes
+   place under -O.  Without -O "foo" seems to be emitted whether it's used
+   or not, which is wasteful.  "extern inline foo()" isn't useful, the
+   "extern" is apparently ignored, so foo is inlined if possible but also
+   emitted as a global, which causes multiple definition errors when
+   building a shared libgmp.  */
+#ifdef __SCO_VERSION__
+#if __SCO_VERSION__ > 400000000 && __STDC__ != 1 \
+  && ! defined (__GMP_EXTERN_INLINE)
+#define __GMP_EXTERN_INLINE  static inline
+#endif
+#endif
+
+/* Microsoft's C compiler accepts __inline */
+#ifdef _MSC_VER
+#define __GMP_EXTERN_INLINE  __inline
+#endif
+
+/* Recent enough Sun C compilers want "inline" */
+#if defined (__SUNPRO_C) && __SUNPRO_C >= 0x560 \
+  && ! defined (__GMP_EXTERN_INLINE)
+#define __GMP_EXTERN_INLINE  inline
+#endif
+
+/* Somewhat older Sun C compilers want "static inline" */
+#if defined (__SUNPRO_C) && __SUNPRO_C >= 0x540 \
+  && ! defined (__GMP_EXTERN_INLINE)
+#define __GMP_EXTERN_INLINE  static inline
+#endif
+
+
+/* C++ always has "inline" and since it's a normal feature the linker should
+   discard duplicate non-inlined copies, or if it doesn't then that's a
+   problem for everyone, not just GMP.  */
+#if defined (__cplusplus) && ! defined (__GMP_EXTERN_INLINE)
+#define __GMP_EXTERN_INLINE  inline
+#endif
+
+/* Don't do any inlining within a configure run, since if the compiler ends
+   up emitting copies of the code into the object file it can end up
+   demanding the various support routines (like mpn_popcount) for linking,
+   making the "alloca" test and perhaps others fail.  And on hppa ia64 a
+   pre-release gcc 3.2 was seen not respecting the "extern" in "extern
+   __inline__", triggering this problem too.  */
+#if defined (__GMP_WITHIN_CONFIGURE) && ! __GMP_WITHIN_CONFIGURE_INLINE
+#undef __GMP_EXTERN_INLINE
+#endif
+
+/* By default, don't give a prototype when there's going to be an inline
+   version.  Note in particular that Cray C++ objects to the combination of
+   prototype and inline.  */
+#ifdef __GMP_EXTERN_INLINE
+#ifndef __GMP_INLINE_PROTOTYPES
+#define __GMP_INLINE_PROTOTYPES  0
+#endif
+#else
+#define __GMP_INLINE_PROTOTYPES  1
+#endif
+
+
+#define __GMP_ABS(x)   ((x) >= 0 ? (x) : -(x))
+#define __GMP_MAX(h,i) ((h) > (i) ? (h) : (i))
+
+
+/* __builtin_expect is in gcc 3.0, and not in 2.95. */
+#if __GMP_GNUC_PREREQ (3,0)
+#define __GMP_LIKELY(cond)    __builtin_expect ((cond) != 0, 1)
+#define __GMP_UNLIKELY(cond)  __builtin_expect ((cond) != 0, 0)
+#else
+#define __GMP_LIKELY(cond)    (cond)
+#define __GMP_UNLIKELY(cond)  (cond)
+#endif
+
+#ifdef _CRAY
+#define __GMP_CRAY_Pragma(str)  _Pragma (str)
+#else
+#define __GMP_CRAY_Pragma(str)
+#endif
+
+
+/* Allow direct user access to numerator and denominator of an mpq_t object.  */
+#define mpq_numref(Q) (&((Q)->_mp_num))
+#define mpq_denref(Q) (&((Q)->_mp_den))
+
+
+#if defined (__cplusplus)
+extern "C" {
+using std::FILE;
+#endif
+
+#define mp_set_memory_functions __gmp_set_memory_functions
+__GMP_DECLSPEC void mp_set_memory_functions (void *(*) (size_t),
+				      void *(*) (void *, size_t, size_t),
+				      void (*) (void *, size_t)) __GMP_NOTHROW;
+
+#define mp_get_memory_functions __gmp_get_memory_functions
+__GMP_DECLSPEC void mp_get_memory_functions (void *(**) (size_t),
+				      void *(**) (void *, size_t, size_t),
+				      void (**) (void *, size_t)) __GMP_NOTHROW;
+
+#define mp_bits_per_limb __gmp_bits_per_limb
+__GMP_DECLSPEC extern const int mp_bits_per_limb;
+
+#define gmp_errno __gmp_errno
+__GMP_DECLSPEC extern int gmp_errno;
+
+#define gmp_version __gmp_version
+__GMP_DECLSPEC extern const char * const gmp_version;
+
+
+/**************** Random number routines.  ****************/
+
+/* obsolete */
+#define gmp_randinit __gmp_randinit
+__GMP_DECLSPEC void gmp_randinit (gmp_randstate_t, gmp_randalg_t, ...);
+
+#define gmp_randinit_default __gmp_randinit_default
+__GMP_DECLSPEC void gmp_randinit_default (gmp_randstate_t);
+
+#define gmp_randinit_lc_2exp __gmp_randinit_lc_2exp
+__GMP_DECLSPEC void gmp_randinit_lc_2exp (gmp_randstate_t, mpz_srcptr, unsigned long int, mp_bitcnt_t);
+
+#define gmp_randinit_lc_2exp_size __gmp_randinit_lc_2exp_size
+__GMP_DECLSPEC int gmp_randinit_lc_2exp_size (gmp_randstate_t, mp_bitcnt_t);
+
+#define gmp_randinit_mt __gmp_randinit_mt
+__GMP_DECLSPEC void gmp_randinit_mt (gmp_randstate_t);
+
+#define gmp_randinit_set __gmp_randinit_set
+__GMP_DECLSPEC void gmp_randinit_set (gmp_randstate_t, const __gmp_randstate_struct *);
+
+#define gmp_randseed __gmp_randseed
+__GMP_DECLSPEC void gmp_randseed (gmp_randstate_t, mpz_srcptr);
+
+#define gmp_randseed_ui __gmp_randseed_ui
+__GMP_DECLSPEC void gmp_randseed_ui (gmp_randstate_t, unsigned long int);
+
+#define gmp_randclear __gmp_randclear
+__GMP_DECLSPEC void gmp_randclear (gmp_randstate_t);
+
+#define gmp_urandomb_ui __gmp_urandomb_ui
+__GMP_DECLSPEC unsigned long gmp_urandomb_ui (gmp_randstate_t, unsigned long);
+
+#define gmp_urandomm_ui __gmp_urandomm_ui
+__GMP_DECLSPEC unsigned long gmp_urandomm_ui (gmp_randstate_t, unsigned long);
+
+
+/**************** Formatted output routines.  ****************/
+
+#define gmp_asprintf __gmp_asprintf
+__GMP_DECLSPEC int gmp_asprintf (char **, const char *, ...);
+
+#define gmp_fprintf __gmp_fprintf
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC int gmp_fprintf (FILE *, const char *, ...);
+#endif
+
+#define gmp_obstack_printf __gmp_obstack_printf
+#if defined (_GMP_H_HAVE_OBSTACK)
+__GMP_DECLSPEC int gmp_obstack_printf (struct obstack *, const char *, ...);
+#endif
+
+#define gmp_obstack_vprintf __gmp_obstack_vprintf
+#if defined (_GMP_H_HAVE_OBSTACK) && defined (_GMP_H_HAVE_VA_LIST)
+__GMP_DECLSPEC int gmp_obstack_vprintf (struct obstack *, const char *, va_list);
+#endif
+
+#define gmp_printf __gmp_printf
+__GMP_DECLSPEC int gmp_printf (const char *, ...);
+
+#define gmp_snprintf __gmp_snprintf
+__GMP_DECLSPEC int gmp_snprintf (char *, size_t, const char *, ...);
+
+#define gmp_sprintf __gmp_sprintf
+__GMP_DECLSPEC int gmp_sprintf (char *, const char *, ...);
+
+#define gmp_vasprintf __gmp_vasprintf
+#if defined (_GMP_H_HAVE_VA_LIST)
+__GMP_DECLSPEC int gmp_vasprintf (char **, const char *, va_list);
+#endif
+
+#define gmp_vfprintf __gmp_vfprintf
+#if defined (_GMP_H_HAVE_FILE) && defined (_GMP_H_HAVE_VA_LIST)
+__GMP_DECLSPEC int gmp_vfprintf (FILE *, const char *, va_list);
+#endif
+
+#define gmp_vprintf __gmp_vprintf
+#if defined (_GMP_H_HAVE_VA_LIST)
+__GMP_DECLSPEC int gmp_vprintf (const char *, va_list);
+#endif
+
+#define gmp_vsnprintf __gmp_vsnprintf
+#if defined (_GMP_H_HAVE_VA_LIST)
+__GMP_DECLSPEC int gmp_vsnprintf (char *, size_t, const char *, va_list);
+#endif
+
+#define gmp_vsprintf __gmp_vsprintf
+#if defined (_GMP_H_HAVE_VA_LIST)
+__GMP_DECLSPEC int gmp_vsprintf (char *, const char *, va_list);
+#endif
+
+
+/**************** Formatted input routines.  ****************/
+
+#define gmp_fscanf __gmp_fscanf
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC int gmp_fscanf (FILE *, const char *, ...);
+#endif
+
+#define gmp_scanf __gmp_scanf
+__GMP_DECLSPEC int gmp_scanf (const char *, ...);
+
+#define gmp_sscanf __gmp_sscanf
+__GMP_DECLSPEC int gmp_sscanf (const char *, const char *, ...);
+
+#define gmp_vfscanf __gmp_vfscanf
+#if defined (_GMP_H_HAVE_FILE) && defined (_GMP_H_HAVE_VA_LIST)
+__GMP_DECLSPEC int gmp_vfscanf (FILE *, const char *, va_list);
+#endif
+
+#define gmp_vscanf __gmp_vscanf
+#if defined (_GMP_H_HAVE_VA_LIST)
+__GMP_DECLSPEC int gmp_vscanf (const char *, va_list);
+#endif
+
+#define gmp_vsscanf __gmp_vsscanf
+#if defined (_GMP_H_HAVE_VA_LIST)
+__GMP_DECLSPEC int gmp_vsscanf (const char *, const char *, va_list);
+#endif
+
+
+/**************** Integer (i.e. Z) routines.  ****************/
+
+#define _mpz_realloc __gmpz_realloc
+#define mpz_realloc __gmpz_realloc
+__GMP_DECLSPEC void *_mpz_realloc (mpz_ptr, mp_size_t);
+
+#define mpz_abs __gmpz_abs
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_abs)
+__GMP_DECLSPEC void mpz_abs (mpz_ptr, mpz_srcptr);
+#endif
+
+#define mpz_add __gmpz_add
+__GMP_DECLSPEC void mpz_add (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_add_ui __gmpz_add_ui
+__GMP_DECLSPEC void mpz_add_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_addmul __gmpz_addmul
+__GMP_DECLSPEC void mpz_addmul (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_addmul_ui __gmpz_addmul_ui
+__GMP_DECLSPEC void mpz_addmul_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_and __gmpz_and
+__GMP_DECLSPEC void mpz_and (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_array_init __gmpz_array_init
+__GMP_DECLSPEC void mpz_array_init (mpz_ptr, mp_size_t, mp_size_t);
+
+#define mpz_bin_ui __gmpz_bin_ui
+__GMP_DECLSPEC void mpz_bin_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_bin_uiui __gmpz_bin_uiui
+__GMP_DECLSPEC void mpz_bin_uiui (mpz_ptr, unsigned long int, unsigned long int);
+
+#define mpz_cdiv_q __gmpz_cdiv_q
+__GMP_DECLSPEC void mpz_cdiv_q (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_cdiv_q_2exp __gmpz_cdiv_q_2exp
+__GMP_DECLSPEC void mpz_cdiv_q_2exp (mpz_ptr, mpz_srcptr, mp_bitcnt_t);
+
+#define mpz_cdiv_q_ui __gmpz_cdiv_q_ui
+__GMP_DECLSPEC unsigned long int mpz_cdiv_q_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_cdiv_qr __gmpz_cdiv_qr
+__GMP_DECLSPEC void mpz_cdiv_qr (mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_cdiv_qr_ui __gmpz_cdiv_qr_ui
+__GMP_DECLSPEC unsigned long int mpz_cdiv_qr_ui (mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_cdiv_r __gmpz_cdiv_r
+__GMP_DECLSPEC void mpz_cdiv_r (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_cdiv_r_2exp __gmpz_cdiv_r_2exp
+__GMP_DECLSPEC void mpz_cdiv_r_2exp (mpz_ptr, mpz_srcptr, mp_bitcnt_t);
+
+#define mpz_cdiv_r_ui __gmpz_cdiv_r_ui
+__GMP_DECLSPEC unsigned long int mpz_cdiv_r_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_cdiv_ui __gmpz_cdiv_ui
+__GMP_DECLSPEC unsigned long int mpz_cdiv_ui (mpz_srcptr, unsigned long int) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_clear __gmpz_clear
+__GMP_DECLSPEC void mpz_clear (mpz_ptr);
+
+#define mpz_clears __gmpz_clears
+__GMP_DECLSPEC void mpz_clears (mpz_ptr, ...);
+
+#define mpz_clrbit __gmpz_clrbit
+__GMP_DECLSPEC void mpz_clrbit (mpz_ptr, mp_bitcnt_t);
+
+#define mpz_cmp __gmpz_cmp
+__GMP_DECLSPEC int mpz_cmp (mpz_srcptr, mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_cmp_d __gmpz_cmp_d
+__GMP_DECLSPEC int mpz_cmp_d (mpz_srcptr, double) __GMP_ATTRIBUTE_PURE;
+
+#define _mpz_cmp_si __gmpz_cmp_si
+__GMP_DECLSPEC int _mpz_cmp_si (mpz_srcptr, signed long int) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define _mpz_cmp_ui __gmpz_cmp_ui
+__GMP_DECLSPEC int _mpz_cmp_ui (mpz_srcptr, unsigned long int) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_cmpabs __gmpz_cmpabs
+__GMP_DECLSPEC int mpz_cmpabs (mpz_srcptr, mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_cmpabs_d __gmpz_cmpabs_d
+__GMP_DECLSPEC int mpz_cmpabs_d (mpz_srcptr, double) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_cmpabs_ui __gmpz_cmpabs_ui
+__GMP_DECLSPEC int mpz_cmpabs_ui (mpz_srcptr, unsigned long int) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_com __gmpz_com
+__GMP_DECLSPEC void mpz_com (mpz_ptr, mpz_srcptr);
+
+#define mpz_combit __gmpz_combit
+__GMP_DECLSPEC void mpz_combit (mpz_ptr, mp_bitcnt_t);
+
+#define mpz_congruent_p __gmpz_congruent_p
+__GMP_DECLSPEC int mpz_congruent_p (mpz_srcptr, mpz_srcptr, mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_congruent_2exp_p __gmpz_congruent_2exp_p
+__GMP_DECLSPEC int mpz_congruent_2exp_p (mpz_srcptr, mpz_srcptr, mp_bitcnt_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_congruent_ui_p __gmpz_congruent_ui_p
+__GMP_DECLSPEC int mpz_congruent_ui_p (mpz_srcptr, unsigned long, unsigned long) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_divexact __gmpz_divexact
+__GMP_DECLSPEC void mpz_divexact (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_divexact_ui __gmpz_divexact_ui
+__GMP_DECLSPEC void mpz_divexact_ui (mpz_ptr, mpz_srcptr, unsigned long);
+
+#define mpz_divisible_p __gmpz_divisible_p
+__GMP_DECLSPEC int mpz_divisible_p (mpz_srcptr, mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_divisible_ui_p __gmpz_divisible_ui_p
+__GMP_DECLSPEC int mpz_divisible_ui_p (mpz_srcptr, unsigned long) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_divisible_2exp_p __gmpz_divisible_2exp_p
+__GMP_DECLSPEC int mpz_divisible_2exp_p (mpz_srcptr, mp_bitcnt_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_dump __gmpz_dump
+__GMP_DECLSPEC void mpz_dump (mpz_srcptr);
+
+#define mpz_export __gmpz_export
+__GMP_DECLSPEC void *mpz_export (void *, size_t *, int, size_t, int, size_t, mpz_srcptr);
+
+#define mpz_fac_ui __gmpz_fac_ui
+__GMP_DECLSPEC void mpz_fac_ui (mpz_ptr, unsigned long int);
+
+#define mpz_2fac_ui __gmpz_2fac_ui
+__GMP_DECLSPEC void mpz_2fac_ui (mpz_ptr, unsigned long int);
+
+#define mpz_mfac_uiui __gmpz_mfac_uiui
+__GMP_DECLSPEC void mpz_mfac_uiui (mpz_ptr, unsigned long int, unsigned long int);
+
+#define mpz_primorial_ui __gmpz_primorial_ui
+__GMP_DECLSPEC void mpz_primorial_ui (mpz_ptr, unsigned long int);
+
+#define mpz_fdiv_q __gmpz_fdiv_q
+__GMP_DECLSPEC void mpz_fdiv_q (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_fdiv_q_2exp __gmpz_fdiv_q_2exp
+__GMP_DECLSPEC void mpz_fdiv_q_2exp (mpz_ptr, mpz_srcptr, mp_bitcnt_t);
+
+#define mpz_fdiv_q_ui __gmpz_fdiv_q_ui
+__GMP_DECLSPEC unsigned long int mpz_fdiv_q_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_fdiv_qr __gmpz_fdiv_qr
+__GMP_DECLSPEC void mpz_fdiv_qr (mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_fdiv_qr_ui __gmpz_fdiv_qr_ui
+__GMP_DECLSPEC unsigned long int mpz_fdiv_qr_ui (mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_fdiv_r __gmpz_fdiv_r
+__GMP_DECLSPEC void mpz_fdiv_r (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_fdiv_r_2exp __gmpz_fdiv_r_2exp
+__GMP_DECLSPEC void mpz_fdiv_r_2exp (mpz_ptr, mpz_srcptr, mp_bitcnt_t);
+
+#define mpz_fdiv_r_ui __gmpz_fdiv_r_ui
+__GMP_DECLSPEC unsigned long int mpz_fdiv_r_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_fdiv_ui __gmpz_fdiv_ui
+__GMP_DECLSPEC unsigned long int mpz_fdiv_ui (mpz_srcptr, unsigned long int) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_fib_ui __gmpz_fib_ui
+__GMP_DECLSPEC void mpz_fib_ui (mpz_ptr, unsigned long int);
+
+#define mpz_fib2_ui __gmpz_fib2_ui
+__GMP_DECLSPEC void mpz_fib2_ui (mpz_ptr, mpz_ptr, unsigned long int);
+
+#define mpz_fits_sint_p __gmpz_fits_sint_p
+__GMP_DECLSPEC int mpz_fits_sint_p (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_fits_slong_p __gmpz_fits_slong_p
+__GMP_DECLSPEC int mpz_fits_slong_p (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_fits_sshort_p __gmpz_fits_sshort_p
+__GMP_DECLSPEC int mpz_fits_sshort_p (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_fits_uint_p __gmpz_fits_uint_p
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_fits_uint_p)
+__GMP_DECLSPEC int mpz_fits_uint_p (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpz_fits_ulong_p __gmpz_fits_ulong_p
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_fits_ulong_p)
+__GMP_DECLSPEC int mpz_fits_ulong_p (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpz_fits_ushort_p __gmpz_fits_ushort_p
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_fits_ushort_p)
+__GMP_DECLSPEC int mpz_fits_ushort_p (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpz_gcd __gmpz_gcd
+__GMP_DECLSPEC void mpz_gcd (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_gcd_ui __gmpz_gcd_ui
+__GMP_DECLSPEC unsigned long int mpz_gcd_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_gcdext __gmpz_gcdext
+__GMP_DECLSPEC void mpz_gcdext (mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_get_d __gmpz_get_d
+__GMP_DECLSPEC double mpz_get_d (mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_get_d_2exp __gmpz_get_d_2exp
+__GMP_DECLSPEC double mpz_get_d_2exp (signed long int *, mpz_srcptr);
+
+#define mpz_get_si __gmpz_get_si
+__GMP_DECLSPEC /* signed */ long int mpz_get_si (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_get_str __gmpz_get_str
+__GMP_DECLSPEC char *mpz_get_str (char *, int, mpz_srcptr);
+
+#define mpz_get_ui __gmpz_get_ui
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_get_ui)
+__GMP_DECLSPEC unsigned long int mpz_get_ui (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpz_getlimbn __gmpz_getlimbn
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_getlimbn)
+__GMP_DECLSPEC mp_limb_t mpz_getlimbn (mpz_srcptr, mp_size_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpz_hamdist __gmpz_hamdist
+__GMP_DECLSPEC mp_bitcnt_t mpz_hamdist (mpz_srcptr, mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_import __gmpz_import
+__GMP_DECLSPEC void mpz_import (mpz_ptr, size_t, int, size_t, int, size_t, const void *);
+
+#define mpz_init __gmpz_init
+__GMP_DECLSPEC void mpz_init (mpz_ptr) __GMP_NOTHROW;
+
+#define mpz_init2 __gmpz_init2
+__GMP_DECLSPEC void mpz_init2 (mpz_ptr, mp_bitcnt_t);
+
+#define mpz_inits __gmpz_inits
+__GMP_DECLSPEC void mpz_inits (mpz_ptr, ...) __GMP_NOTHROW;
+
+#define mpz_init_set __gmpz_init_set
+__GMP_DECLSPEC void mpz_init_set (mpz_ptr, mpz_srcptr);
+
+#define mpz_init_set_d __gmpz_init_set_d
+__GMP_DECLSPEC void mpz_init_set_d (mpz_ptr, double);
+
+#define mpz_init_set_si __gmpz_init_set_si
+__GMP_DECLSPEC void mpz_init_set_si (mpz_ptr, signed long int);
+
+#define mpz_init_set_str __gmpz_init_set_str
+__GMP_DECLSPEC int mpz_init_set_str (mpz_ptr, const char *, int);
+
+#define mpz_init_set_ui __gmpz_init_set_ui
+__GMP_DECLSPEC void mpz_init_set_ui (mpz_ptr, unsigned long int);
+
+#define mpz_inp_raw __gmpz_inp_raw
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC size_t mpz_inp_raw (mpz_ptr, FILE *);
+#endif
+
+#define mpz_inp_str __gmpz_inp_str
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC size_t mpz_inp_str (mpz_ptr, FILE *, int);
+#endif
+
+#define mpz_invert __gmpz_invert
+__GMP_DECLSPEC int mpz_invert (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_ior __gmpz_ior
+__GMP_DECLSPEC void mpz_ior (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_jacobi __gmpz_jacobi
+__GMP_DECLSPEC int mpz_jacobi (mpz_srcptr, mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_kronecker mpz_jacobi  /* alias */
+
+#define mpz_kronecker_si __gmpz_kronecker_si
+__GMP_DECLSPEC int mpz_kronecker_si (mpz_srcptr, long) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_kronecker_ui __gmpz_kronecker_ui
+__GMP_DECLSPEC int mpz_kronecker_ui (mpz_srcptr, unsigned long) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_si_kronecker __gmpz_si_kronecker
+__GMP_DECLSPEC int mpz_si_kronecker (long, mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_ui_kronecker __gmpz_ui_kronecker
+__GMP_DECLSPEC int mpz_ui_kronecker (unsigned long, mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_lcm __gmpz_lcm
+__GMP_DECLSPEC void mpz_lcm (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_lcm_ui __gmpz_lcm_ui
+__GMP_DECLSPEC void mpz_lcm_ui (mpz_ptr, mpz_srcptr, unsigned long);
+
+#define mpz_legendre mpz_jacobi  /* alias */
+
+#define mpz_lucnum_ui __gmpz_lucnum_ui
+__GMP_DECLSPEC void mpz_lucnum_ui (mpz_ptr, unsigned long int);
+
+#define mpz_lucnum2_ui __gmpz_lucnum2_ui
+__GMP_DECLSPEC void mpz_lucnum2_ui (mpz_ptr, mpz_ptr, unsigned long int);
+
+#define mpz_millerrabin __gmpz_millerrabin
+__GMP_DECLSPEC int mpz_millerrabin (mpz_srcptr, int) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_mod __gmpz_mod
+__GMP_DECLSPEC void mpz_mod (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_mod_ui mpz_fdiv_r_ui /* same as fdiv_r because divisor unsigned */
+
+#define mpz_mul __gmpz_mul
+__GMP_DECLSPEC void mpz_mul (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_mul_2exp __gmpz_mul_2exp
+__GMP_DECLSPEC void mpz_mul_2exp (mpz_ptr, mpz_srcptr, mp_bitcnt_t);
+
+#define mpz_mul_si __gmpz_mul_si
+__GMP_DECLSPEC void mpz_mul_si (mpz_ptr, mpz_srcptr, long int);
+
+#define mpz_mul_ui __gmpz_mul_ui
+__GMP_DECLSPEC void mpz_mul_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_neg __gmpz_neg
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_neg)
+__GMP_DECLSPEC void mpz_neg (mpz_ptr, mpz_srcptr);
+#endif
+
+#define mpz_nextprime __gmpz_nextprime
+__GMP_DECLSPEC void mpz_nextprime (mpz_ptr, mpz_srcptr);
+
+#define mpz_out_raw __gmpz_out_raw
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC size_t mpz_out_raw (FILE *, mpz_srcptr);
+#endif
+
+#define mpz_out_str __gmpz_out_str
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC size_t mpz_out_str (FILE *, int, mpz_srcptr);
+#endif
+
+#define mpz_perfect_power_p __gmpz_perfect_power_p
+__GMP_DECLSPEC int mpz_perfect_power_p (mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_perfect_square_p __gmpz_perfect_square_p
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_perfect_square_p)
+__GMP_DECLSPEC int mpz_perfect_square_p (mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpz_popcount __gmpz_popcount
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_popcount)
+__GMP_DECLSPEC mp_bitcnt_t mpz_popcount (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpz_pow_ui __gmpz_pow_ui
+__GMP_DECLSPEC void mpz_pow_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_powm __gmpz_powm
+__GMP_DECLSPEC void mpz_powm (mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_powm_sec __gmpz_powm_sec
+__GMP_DECLSPEC void mpz_powm_sec (mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_powm_ui __gmpz_powm_ui
+__GMP_DECLSPEC void mpz_powm_ui (mpz_ptr, mpz_srcptr, unsigned long int, mpz_srcptr);
+
+#define mpz_probab_prime_p __gmpz_probab_prime_p
+__GMP_DECLSPEC int mpz_probab_prime_p (mpz_srcptr, int) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_random __gmpz_random
+__GMP_DECLSPEC void mpz_random (mpz_ptr, mp_size_t);
+
+#define mpz_random2 __gmpz_random2
+__GMP_DECLSPEC void mpz_random2 (mpz_ptr, mp_size_t);
+
+#define mpz_realloc2 __gmpz_realloc2
+__GMP_DECLSPEC void mpz_realloc2 (mpz_ptr, mp_bitcnt_t);
+
+#define mpz_remove __gmpz_remove
+__GMP_DECLSPEC mp_bitcnt_t mpz_remove (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_root __gmpz_root
+__GMP_DECLSPEC int mpz_root (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_rootrem __gmpz_rootrem
+__GMP_DECLSPEC void mpz_rootrem (mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_rrandomb __gmpz_rrandomb
+__GMP_DECLSPEC void mpz_rrandomb (mpz_ptr, gmp_randstate_t, mp_bitcnt_t);
+
+#define mpz_scan0 __gmpz_scan0
+__GMP_DECLSPEC mp_bitcnt_t mpz_scan0 (mpz_srcptr, mp_bitcnt_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_scan1 __gmpz_scan1
+__GMP_DECLSPEC mp_bitcnt_t mpz_scan1 (mpz_srcptr, mp_bitcnt_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_set __gmpz_set
+__GMP_DECLSPEC void mpz_set (mpz_ptr, mpz_srcptr);
+
+#define mpz_set_d __gmpz_set_d
+__GMP_DECLSPEC void mpz_set_d (mpz_ptr, double);
+
+#define mpz_set_f __gmpz_set_f
+__GMP_DECLSPEC void mpz_set_f (mpz_ptr, mpf_srcptr);
+
+#define mpz_set_q __gmpz_set_q
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_set_q)
+__GMP_DECLSPEC void mpz_set_q (mpz_ptr, mpq_srcptr);
+#endif
+
+#define mpz_set_si __gmpz_set_si
+__GMP_DECLSPEC void mpz_set_si (mpz_ptr, signed long int);
+
+#define mpz_set_str __gmpz_set_str
+__GMP_DECLSPEC int mpz_set_str (mpz_ptr, const char *, int);
+
+#define mpz_set_ui __gmpz_set_ui
+__GMP_DECLSPEC void mpz_set_ui (mpz_ptr, unsigned long int);
+
+#define mpz_setbit __gmpz_setbit
+__GMP_DECLSPEC void mpz_setbit (mpz_ptr, mp_bitcnt_t);
+
+#define mpz_size __gmpz_size
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_size)
+__GMP_DECLSPEC size_t mpz_size (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpz_sizeinbase __gmpz_sizeinbase
+__GMP_DECLSPEC size_t mpz_sizeinbase (mpz_srcptr, int) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_sqrt __gmpz_sqrt
+__GMP_DECLSPEC void mpz_sqrt (mpz_ptr, mpz_srcptr);
+
+#define mpz_sqrtrem __gmpz_sqrtrem
+__GMP_DECLSPEC void mpz_sqrtrem (mpz_ptr, mpz_ptr, mpz_srcptr);
+
+#define mpz_sub __gmpz_sub
+__GMP_DECLSPEC void mpz_sub (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_sub_ui __gmpz_sub_ui
+__GMP_DECLSPEC void mpz_sub_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_ui_sub __gmpz_ui_sub
+__GMP_DECLSPEC void mpz_ui_sub (mpz_ptr, unsigned long int, mpz_srcptr);
+
+#define mpz_submul __gmpz_submul
+__GMP_DECLSPEC void mpz_submul (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_submul_ui __gmpz_submul_ui
+__GMP_DECLSPEC void mpz_submul_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_swap __gmpz_swap
+__GMP_DECLSPEC void mpz_swap (mpz_ptr, mpz_ptr) __GMP_NOTHROW;
+
+#define mpz_tdiv_ui __gmpz_tdiv_ui
+__GMP_DECLSPEC unsigned long int mpz_tdiv_ui (mpz_srcptr, unsigned long int) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_tdiv_q __gmpz_tdiv_q
+__GMP_DECLSPEC void mpz_tdiv_q (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_tdiv_q_2exp __gmpz_tdiv_q_2exp
+__GMP_DECLSPEC void mpz_tdiv_q_2exp (mpz_ptr, mpz_srcptr, mp_bitcnt_t);
+
+#define mpz_tdiv_q_ui __gmpz_tdiv_q_ui
+__GMP_DECLSPEC unsigned long int mpz_tdiv_q_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_tdiv_qr __gmpz_tdiv_qr
+__GMP_DECLSPEC void mpz_tdiv_qr (mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_tdiv_qr_ui __gmpz_tdiv_qr_ui
+__GMP_DECLSPEC unsigned long int mpz_tdiv_qr_ui (mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_tdiv_r __gmpz_tdiv_r
+__GMP_DECLSPEC void mpz_tdiv_r (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_tdiv_r_2exp __gmpz_tdiv_r_2exp
+__GMP_DECLSPEC void mpz_tdiv_r_2exp (mpz_ptr, mpz_srcptr, mp_bitcnt_t);
+
+#define mpz_tdiv_r_ui __gmpz_tdiv_r_ui
+__GMP_DECLSPEC unsigned long int mpz_tdiv_r_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_tstbit __gmpz_tstbit
+__GMP_DECLSPEC int mpz_tstbit (mpz_srcptr, mp_bitcnt_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_ui_pow_ui __gmpz_ui_pow_ui
+__GMP_DECLSPEC void mpz_ui_pow_ui (mpz_ptr, unsigned long int, unsigned long int);
+
+#define mpz_urandomb __gmpz_urandomb
+__GMP_DECLSPEC void mpz_urandomb (mpz_ptr, gmp_randstate_t, mp_bitcnt_t);
+
+#define mpz_urandomm __gmpz_urandomm
+__GMP_DECLSPEC void mpz_urandomm (mpz_ptr, gmp_randstate_t, mpz_srcptr);
+
+#define mpz_xor __gmpz_xor
+#define mpz_eor __gmpz_xor
+__GMP_DECLSPEC void mpz_xor (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_limbs_read __gmpz_limbs_read
+__GMP_DECLSPEC mp_srcptr mpz_limbs_read (mpz_srcptr);
+
+#define mpz_limbs_write __gmpz_limbs_write
+__GMP_DECLSPEC mp_ptr mpz_limbs_write (mpz_ptr, mp_size_t);
+
+#define mpz_limbs_modify __gmpz_limbs_modify
+__GMP_DECLSPEC mp_ptr mpz_limbs_modify (mpz_ptr, mp_size_t);
+
+#define mpz_limbs_finish __gmpz_limbs_finish
+__GMP_DECLSPEC void mpz_limbs_finish (mpz_ptr, mp_size_t);
+
+#define mpz_roinit_n __gmpz_roinit_n
+__GMP_DECLSPEC mpz_srcptr mpz_roinit_n (mpz_ptr, mp_srcptr, mp_size_t);
+
+#define MPZ_ROINIT_N(xp, xs) {{0, (xs),(xp) }}
+
+/**************** Rational (i.e. Q) routines.  ****************/
+
+#define mpq_abs __gmpq_abs
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpq_abs)
+__GMP_DECLSPEC void mpq_abs (mpq_ptr, mpq_srcptr);
+#endif
+
+#define mpq_add __gmpq_add
+__GMP_DECLSPEC void mpq_add (mpq_ptr, mpq_srcptr, mpq_srcptr);
+
+#define mpq_canonicalize __gmpq_canonicalize
+__GMP_DECLSPEC void mpq_canonicalize (mpq_ptr);
+
+#define mpq_clear __gmpq_clear
+__GMP_DECLSPEC void mpq_clear (mpq_ptr);
+
+#define mpq_clears __gmpq_clears
+__GMP_DECLSPEC void mpq_clears (mpq_ptr, ...);
+
+#define mpq_cmp __gmpq_cmp
+__GMP_DECLSPEC int mpq_cmp (mpq_srcptr, mpq_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define _mpq_cmp_si __gmpq_cmp_si
+__GMP_DECLSPEC int _mpq_cmp_si (mpq_srcptr, long, unsigned long) __GMP_ATTRIBUTE_PURE;
+
+#define _mpq_cmp_ui __gmpq_cmp_ui
+__GMP_DECLSPEC int _mpq_cmp_ui (mpq_srcptr, unsigned long int, unsigned long int) __GMP_ATTRIBUTE_PURE;
+
+#define mpq_cmp_z __gmpq_cmp_z
+__GMP_DECLSPEC int mpq_cmp_z (mpq_srcptr, mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpq_div __gmpq_div
+__GMP_DECLSPEC void mpq_div (mpq_ptr, mpq_srcptr, mpq_srcptr);
+
+#define mpq_div_2exp __gmpq_div_2exp
+__GMP_DECLSPEC void mpq_div_2exp (mpq_ptr, mpq_srcptr, mp_bitcnt_t);
+
+#define mpq_equal __gmpq_equal
+__GMP_DECLSPEC int mpq_equal (mpq_srcptr, mpq_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpq_get_num __gmpq_get_num
+__GMP_DECLSPEC void mpq_get_num (mpz_ptr, mpq_srcptr);
+
+#define mpq_get_den __gmpq_get_den
+__GMP_DECLSPEC void mpq_get_den (mpz_ptr, mpq_srcptr);
+
+#define mpq_get_d __gmpq_get_d
+__GMP_DECLSPEC double mpq_get_d (mpq_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpq_get_str __gmpq_get_str
+__GMP_DECLSPEC char *mpq_get_str (char *, int, mpq_srcptr);
+
+#define mpq_init __gmpq_init
+__GMP_DECLSPEC void mpq_init (mpq_ptr);
+
+#define mpq_inits __gmpq_inits
+__GMP_DECLSPEC void mpq_inits (mpq_ptr, ...);
+
+#define mpq_inp_str __gmpq_inp_str
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC size_t mpq_inp_str (mpq_ptr, FILE *, int);
+#endif
+
+#define mpq_inv __gmpq_inv
+__GMP_DECLSPEC void mpq_inv (mpq_ptr, mpq_srcptr);
+
+#define mpq_mul __gmpq_mul
+__GMP_DECLSPEC void mpq_mul (mpq_ptr, mpq_srcptr, mpq_srcptr);
+
+#define mpq_mul_2exp __gmpq_mul_2exp
+__GMP_DECLSPEC void mpq_mul_2exp (mpq_ptr, mpq_srcptr, mp_bitcnt_t);
+
+#define mpq_neg __gmpq_neg
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpq_neg)
+__GMP_DECLSPEC void mpq_neg (mpq_ptr, mpq_srcptr);
+#endif
+
+#define mpq_out_str __gmpq_out_str
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC size_t mpq_out_str (FILE *, int, mpq_srcptr);
+#endif
+
+#define mpq_set __gmpq_set
+__GMP_DECLSPEC void mpq_set (mpq_ptr, mpq_srcptr);
+
+#define mpq_set_d __gmpq_set_d
+__GMP_DECLSPEC void mpq_set_d (mpq_ptr, double);
+
+#define mpq_set_den __gmpq_set_den
+__GMP_DECLSPEC void mpq_set_den (mpq_ptr, mpz_srcptr);
+
+#define mpq_set_f __gmpq_set_f
+__GMP_DECLSPEC void mpq_set_f (mpq_ptr, mpf_srcptr);
+
+#define mpq_set_num __gmpq_set_num
+__GMP_DECLSPEC void mpq_set_num (mpq_ptr, mpz_srcptr);
+
+#define mpq_set_si __gmpq_set_si
+__GMP_DECLSPEC void mpq_set_si (mpq_ptr, signed long int, unsigned long int);
+
+#define mpq_set_str __gmpq_set_str
+__GMP_DECLSPEC int mpq_set_str (mpq_ptr, const char *, int);
+
+#define mpq_set_ui __gmpq_set_ui
+__GMP_DECLSPEC void mpq_set_ui (mpq_ptr, unsigned long int, unsigned long int);
+
+#define mpq_set_z __gmpq_set_z
+__GMP_DECLSPEC void mpq_set_z (mpq_ptr, mpz_srcptr);
+
+#define mpq_sub __gmpq_sub
+__GMP_DECLSPEC void mpq_sub (mpq_ptr, mpq_srcptr, mpq_srcptr);
+
+#define mpq_swap __gmpq_swap
+__GMP_DECLSPEC void mpq_swap (mpq_ptr, mpq_ptr) __GMP_NOTHROW;
+
+
+/**************** Float (i.e. F) routines.  ****************/
+
+#define mpf_abs __gmpf_abs
+__GMP_DECLSPEC void mpf_abs (mpf_ptr, mpf_srcptr);
+
+#define mpf_add __gmpf_add
+__GMP_DECLSPEC void mpf_add (mpf_ptr, mpf_srcptr, mpf_srcptr);
+
+#define mpf_add_ui __gmpf_add_ui
+__GMP_DECLSPEC void mpf_add_ui (mpf_ptr, mpf_srcptr, unsigned long int);
+#define mpf_ceil __gmpf_ceil
+__GMP_DECLSPEC void mpf_ceil (mpf_ptr, mpf_srcptr);
+
+#define mpf_clear __gmpf_clear
+__GMP_DECLSPEC void mpf_clear (mpf_ptr);
+
+#define mpf_clears __gmpf_clears
+__GMP_DECLSPEC void mpf_clears (mpf_ptr, ...);
+
+#define mpf_cmp __gmpf_cmp
+__GMP_DECLSPEC int mpf_cmp (mpf_srcptr, mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_cmp_z __gmpf_cmp_z
+__GMP_DECLSPEC int mpf_cmp_z (mpf_srcptr, mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_cmp_d __gmpf_cmp_d
+__GMP_DECLSPEC int mpf_cmp_d (mpf_srcptr, double) __GMP_ATTRIBUTE_PURE;
+
+#define mpf_cmp_si __gmpf_cmp_si
+__GMP_DECLSPEC int mpf_cmp_si (mpf_srcptr, signed long int) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_cmp_ui __gmpf_cmp_ui
+__GMP_DECLSPEC int mpf_cmp_ui (mpf_srcptr, unsigned long int) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_div __gmpf_div
+__GMP_DECLSPEC void mpf_div (mpf_ptr, mpf_srcptr, mpf_srcptr);
+
+#define mpf_div_2exp __gmpf_div_2exp
+__GMP_DECLSPEC void mpf_div_2exp (mpf_ptr, mpf_srcptr, mp_bitcnt_t);
+
+#define mpf_div_ui __gmpf_div_ui
+__GMP_DECLSPEC void mpf_div_ui (mpf_ptr, mpf_srcptr, unsigned long int);
+
+#define mpf_dump __gmpf_dump
+__GMP_DECLSPEC void mpf_dump (mpf_srcptr);
+
+#define mpf_eq __gmpf_eq
+__GMP_DECLSPEC int mpf_eq (mpf_srcptr, mpf_srcptr, mp_bitcnt_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpf_fits_sint_p __gmpf_fits_sint_p
+__GMP_DECLSPEC int mpf_fits_sint_p (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_fits_slong_p __gmpf_fits_slong_p
+__GMP_DECLSPEC int mpf_fits_slong_p (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_fits_sshort_p __gmpf_fits_sshort_p
+__GMP_DECLSPEC int mpf_fits_sshort_p (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_fits_uint_p __gmpf_fits_uint_p
+__GMP_DECLSPEC int mpf_fits_uint_p (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_fits_ulong_p __gmpf_fits_ulong_p
+__GMP_DECLSPEC int mpf_fits_ulong_p (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_fits_ushort_p __gmpf_fits_ushort_p
+__GMP_DECLSPEC int mpf_fits_ushort_p (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_floor __gmpf_floor
+__GMP_DECLSPEC void mpf_floor (mpf_ptr, mpf_srcptr);
+
+#define mpf_get_d __gmpf_get_d
+__GMP_DECLSPEC double mpf_get_d (mpf_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpf_get_d_2exp __gmpf_get_d_2exp
+__GMP_DECLSPEC double mpf_get_d_2exp (signed long int *, mpf_srcptr);
+
+#define mpf_get_default_prec __gmpf_get_default_prec
+__GMP_DECLSPEC mp_bitcnt_t mpf_get_default_prec (void) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_get_prec __gmpf_get_prec
+__GMP_DECLSPEC mp_bitcnt_t mpf_get_prec (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_get_si __gmpf_get_si
+__GMP_DECLSPEC long mpf_get_si (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_get_str __gmpf_get_str
+__GMP_DECLSPEC char *mpf_get_str (char *, mp_exp_t *, int, size_t, mpf_srcptr);
+
+#define mpf_get_ui __gmpf_get_ui
+__GMP_DECLSPEC unsigned long mpf_get_ui (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_init __gmpf_init
+__GMP_DECLSPEC void mpf_init (mpf_ptr);
+
+#define mpf_init2 __gmpf_init2
+__GMP_DECLSPEC void mpf_init2 (mpf_ptr, mp_bitcnt_t);
+
+#define mpf_inits __gmpf_inits
+__GMP_DECLSPEC void mpf_inits (mpf_ptr, ...);
+
+#define mpf_init_set __gmpf_init_set
+__GMP_DECLSPEC void mpf_init_set (mpf_ptr, mpf_srcptr);
+
+#define mpf_init_set_d __gmpf_init_set_d
+__GMP_DECLSPEC void mpf_init_set_d (mpf_ptr, double);
+
+#define mpf_init_set_si __gmpf_init_set_si
+__GMP_DECLSPEC void mpf_init_set_si (mpf_ptr, signed long int);
+
+#define mpf_init_set_str __gmpf_init_set_str
+__GMP_DECLSPEC int mpf_init_set_str (mpf_ptr, const char *, int);
+
+#define mpf_init_set_ui __gmpf_init_set_ui
+__GMP_DECLSPEC void mpf_init_set_ui (mpf_ptr, unsigned long int);
+
+#define mpf_inp_str __gmpf_inp_str
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC size_t mpf_inp_str (mpf_ptr, FILE *, int);
+#endif
+
+#define mpf_integer_p __gmpf_integer_p
+__GMP_DECLSPEC int mpf_integer_p (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_mul __gmpf_mul
+__GMP_DECLSPEC void mpf_mul (mpf_ptr, mpf_srcptr, mpf_srcptr);
+
+#define mpf_mul_2exp __gmpf_mul_2exp
+__GMP_DECLSPEC void mpf_mul_2exp (mpf_ptr, mpf_srcptr, mp_bitcnt_t);
+
+#define mpf_mul_ui __gmpf_mul_ui
+__GMP_DECLSPEC void mpf_mul_ui (mpf_ptr, mpf_srcptr, unsigned long int);
+
+#define mpf_neg __gmpf_neg
+__GMP_DECLSPEC void mpf_neg (mpf_ptr, mpf_srcptr);
+
+#define mpf_out_str __gmpf_out_str
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC size_t mpf_out_str (FILE *, int, size_t, mpf_srcptr);
+#endif
+
+#define mpf_pow_ui __gmpf_pow_ui
+__GMP_DECLSPEC void mpf_pow_ui (mpf_ptr, mpf_srcptr, unsigned long int);
+
+#define mpf_random2 __gmpf_random2
+__GMP_DECLSPEC void mpf_random2 (mpf_ptr, mp_size_t, mp_exp_t);
+
+#define mpf_reldiff __gmpf_reldiff
+__GMP_DECLSPEC void mpf_reldiff (mpf_ptr, mpf_srcptr, mpf_srcptr);
+
+#define mpf_set __gmpf_set
+__GMP_DECLSPEC void mpf_set (mpf_ptr, mpf_srcptr);
+
+#define mpf_set_d __gmpf_set_d
+__GMP_DECLSPEC void mpf_set_d (mpf_ptr, double);
+
+#define mpf_set_default_prec __gmpf_set_default_prec
+__GMP_DECLSPEC void mpf_set_default_prec (mp_bitcnt_t) __GMP_NOTHROW;
+
+#define mpf_set_prec __gmpf_set_prec
+__GMP_DECLSPEC void mpf_set_prec (mpf_ptr, mp_bitcnt_t);
+
+#define mpf_set_prec_raw __gmpf_set_prec_raw
+__GMP_DECLSPEC void mpf_set_prec_raw (mpf_ptr, mp_bitcnt_t) __GMP_NOTHROW;
+
+#define mpf_set_q __gmpf_set_q
+__GMP_DECLSPEC void mpf_set_q (mpf_ptr, mpq_srcptr);
+
+#define mpf_set_si __gmpf_set_si
+__GMP_DECLSPEC void mpf_set_si (mpf_ptr, signed long int);
+
+#define mpf_set_str __gmpf_set_str
+__GMP_DECLSPEC int mpf_set_str (mpf_ptr, const char *, int);
+
+#define mpf_set_ui __gmpf_set_ui
+__GMP_DECLSPEC void mpf_set_ui (mpf_ptr, unsigned long int);
+
+#define mpf_set_z __gmpf_set_z
+__GMP_DECLSPEC void mpf_set_z (mpf_ptr, mpz_srcptr);
+
+#define mpf_size __gmpf_size
+__GMP_DECLSPEC size_t mpf_size (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_sqrt __gmpf_sqrt
+__GMP_DECLSPEC void mpf_sqrt (mpf_ptr, mpf_srcptr);
+
+#define mpf_sqrt_ui __gmpf_sqrt_ui
+__GMP_DECLSPEC void mpf_sqrt_ui (mpf_ptr, unsigned long int);
+
+#define mpf_sub __gmpf_sub
+__GMP_DECLSPEC void mpf_sub (mpf_ptr, mpf_srcptr, mpf_srcptr);
+
+#define mpf_sub_ui __gmpf_sub_ui
+__GMP_DECLSPEC void mpf_sub_ui (mpf_ptr, mpf_srcptr, unsigned long int);
+
+#define mpf_swap __gmpf_swap
+__GMP_DECLSPEC void mpf_swap (mpf_ptr, mpf_ptr) __GMP_NOTHROW;
+
+#define mpf_trunc __gmpf_trunc
+__GMP_DECLSPEC void mpf_trunc (mpf_ptr, mpf_srcptr);
+
+#define mpf_ui_div __gmpf_ui_div
+__GMP_DECLSPEC void mpf_ui_div (mpf_ptr, unsigned long int, mpf_srcptr);
+
+#define mpf_ui_sub __gmpf_ui_sub
+__GMP_DECLSPEC void mpf_ui_sub (mpf_ptr, unsigned long int, mpf_srcptr);
+
+#define mpf_urandomb __gmpf_urandomb
+__GMP_DECLSPEC void mpf_urandomb (mpf_t, gmp_randstate_t, mp_bitcnt_t);
+
+
+/************ Low level positive-integer (i.e. N) routines.  ************/
+
+/* This is ugly, but we need to make user calls reach the prefixed function. */
+
+#define mpn_add __MPN(add)
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_add)
+__GMP_DECLSPEC mp_limb_t mpn_add (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+#endif
+
+#define mpn_add_1 __MPN(add_1)
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_add_1)
+__GMP_DECLSPEC mp_limb_t mpn_add_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t) __GMP_NOTHROW;
+#endif
+
+#define mpn_add_n __MPN(add_n)
+__GMP_DECLSPEC mp_limb_t mpn_add_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+
+#define mpn_addmul_1 __MPN(addmul_1)
+__GMP_DECLSPEC mp_limb_t mpn_addmul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_cmp __MPN(cmp)
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_cmp)
+__GMP_DECLSPEC int mpn_cmp (mp_srcptr, mp_srcptr, mp_size_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpn_zero_p __MPN(zero_p)
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_zero_p)
+__GMP_DECLSPEC int mpn_zero_p (mp_srcptr, mp_size_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpn_divexact_1 __MPN(divexact_1)
+__GMP_DECLSPEC void mpn_divexact_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_divexact_by3(dst,src,size) \
+  mpn_divexact_by3c (dst, src, size, __GMP_CAST (mp_limb_t, 0))
+
+#define mpn_divexact_by3c __MPN(divexact_by3c)
+__GMP_DECLSPEC mp_limb_t mpn_divexact_by3c (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_divmod_1(qp,np,nsize,dlimb) \
+  mpn_divrem_1 (qp, __GMP_CAST (mp_size_t, 0), np, nsize, dlimb)
+
+#define mpn_divrem __MPN(divrem)
+__GMP_DECLSPEC mp_limb_t mpn_divrem (mp_ptr, mp_size_t, mp_ptr, mp_size_t, mp_srcptr, mp_size_t);
+
+#define mpn_divrem_1 __MPN(divrem_1)
+__GMP_DECLSPEC mp_limb_t mpn_divrem_1 (mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_divrem_2 __MPN(divrem_2)
+__GMP_DECLSPEC mp_limb_t mpn_divrem_2 (mp_ptr, mp_size_t, mp_ptr, mp_size_t, mp_srcptr);
+
+#define mpn_div_qr_1 __MPN(div_qr_1)
+__GMP_DECLSPEC mp_limb_t mpn_div_qr_1 (mp_ptr, mp_limb_t *, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_div_qr_2 __MPN(div_qr_2)
+__GMP_DECLSPEC mp_limb_t mpn_div_qr_2 (mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+
+#define mpn_gcd __MPN(gcd)
+__GMP_DECLSPEC mp_size_t mpn_gcd (mp_ptr, mp_ptr, mp_size_t, mp_ptr, mp_size_t);
+
+#define mpn_gcd_11 __MPN(gcd_11)
+__GMP_DECLSPEC mp_limb_t mpn_gcd_11 (mp_limb_t, mp_limb_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_gcd_1 __MPN(gcd_1)
+__GMP_DECLSPEC mp_limb_t mpn_gcd_1 (mp_srcptr, mp_size_t, mp_limb_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_gcdext_1 __MPN(gcdext_1)
+__GMP_DECLSPEC mp_limb_t mpn_gcdext_1 (mp_limb_signed_t *, mp_limb_signed_t *, mp_limb_t, mp_limb_t);
+
+#define mpn_gcdext __MPN(gcdext)
+__GMP_DECLSPEC mp_size_t mpn_gcdext (mp_ptr, mp_ptr, mp_size_t *, mp_ptr, mp_size_t, mp_ptr, mp_size_t);
+
+#define mpn_get_str __MPN(get_str)
+__GMP_DECLSPEC size_t mpn_get_str (unsigned char *, int, mp_ptr, mp_size_t);
+
+#define mpn_hamdist __MPN(hamdist)
+__GMP_DECLSPEC mp_bitcnt_t mpn_hamdist (mp_srcptr, mp_srcptr, mp_size_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpn_lshift __MPN(lshift)
+__GMP_DECLSPEC mp_limb_t mpn_lshift (mp_ptr, mp_srcptr, mp_size_t, unsigned int);
+
+#define mpn_mod_1 __MPN(mod_1)
+__GMP_DECLSPEC mp_limb_t mpn_mod_1 (mp_srcptr, mp_size_t, mp_limb_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_mul __MPN(mul)
+__GMP_DECLSPEC mp_limb_t mpn_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+
+#define mpn_mul_1 __MPN(mul_1)
+__GMP_DECLSPEC mp_limb_t mpn_mul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_mul_n __MPN(mul_n)
+__GMP_DECLSPEC void mpn_mul_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+
+#define mpn_sqr __MPN(sqr)
+__GMP_DECLSPEC void mpn_sqr (mp_ptr, mp_srcptr, mp_size_t);
+
+#define mpn_neg __MPN(neg)
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_neg)
+__GMP_DECLSPEC mp_limb_t mpn_neg (mp_ptr, mp_srcptr, mp_size_t);
+#endif
+
+#define mpn_com __MPN(com)
+__GMP_DECLSPEC void mpn_com (mp_ptr, mp_srcptr, mp_size_t);
+
+#define mpn_perfect_square_p __MPN(perfect_square_p)
+__GMP_DECLSPEC int mpn_perfect_square_p (mp_srcptr, mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_perfect_power_p __MPN(perfect_power_p)
+__GMP_DECLSPEC int mpn_perfect_power_p (mp_srcptr, mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_popcount __MPN(popcount)
+__GMP_DECLSPEC mp_bitcnt_t mpn_popcount (mp_srcptr, mp_size_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpn_pow_1 __MPN(pow_1)
+__GMP_DECLSPEC mp_size_t mpn_pow_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_ptr);
+
+/* undocumented now, but retained here for upward compatibility */
+#define mpn_preinv_mod_1 __MPN(preinv_mod_1)
+__GMP_DECLSPEC mp_limb_t mpn_preinv_mod_1 (mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_random __MPN(random)
+__GMP_DECLSPEC void mpn_random (mp_ptr, mp_size_t);
+
+#define mpn_random2 __MPN(random2)
+__GMP_DECLSPEC void mpn_random2 (mp_ptr, mp_size_t);
+
+#define mpn_rshift __MPN(rshift)
+__GMP_DECLSPEC mp_limb_t mpn_rshift (mp_ptr, mp_srcptr, mp_size_t, unsigned int);
+
+#define mpn_scan0 __MPN(scan0)
+__GMP_DECLSPEC mp_bitcnt_t mpn_scan0 (mp_srcptr, mp_bitcnt_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_scan1 __MPN(scan1)
+__GMP_DECLSPEC mp_bitcnt_t mpn_scan1 (mp_srcptr, mp_bitcnt_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_set_str __MPN(set_str)
+__GMP_DECLSPEC mp_size_t mpn_set_str (mp_ptr, const unsigned char *, size_t, int);
+
+#define mpn_sizeinbase __MPN(sizeinbase)
+__GMP_DECLSPEC size_t mpn_sizeinbase (mp_srcptr, mp_size_t, int);
+
+#define mpn_sqrtrem __MPN(sqrtrem)
+__GMP_DECLSPEC mp_size_t mpn_sqrtrem (mp_ptr, mp_ptr, mp_srcptr, mp_size_t);
+
+#define mpn_sub __MPN(sub)
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_sub)
+__GMP_DECLSPEC mp_limb_t mpn_sub (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+#endif
+
+#define mpn_sub_1 __MPN(sub_1)
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_sub_1)
+__GMP_DECLSPEC mp_limb_t mpn_sub_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t) __GMP_NOTHROW;
+#endif
+
+#define mpn_sub_n __MPN(sub_n)
+__GMP_DECLSPEC mp_limb_t mpn_sub_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+
+#define mpn_submul_1 __MPN(submul_1)
+__GMP_DECLSPEC mp_limb_t mpn_submul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_tdiv_qr __MPN(tdiv_qr)
+__GMP_DECLSPEC void mpn_tdiv_qr (mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+
+#define mpn_and_n __MPN(and_n)
+__GMP_DECLSPEC void mpn_and_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_andn_n __MPN(andn_n)
+__GMP_DECLSPEC void mpn_andn_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_nand_n __MPN(nand_n)
+__GMP_DECLSPEC void mpn_nand_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_ior_n __MPN(ior_n)
+__GMP_DECLSPEC void mpn_ior_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_iorn_n __MPN(iorn_n)
+__GMP_DECLSPEC void mpn_iorn_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_nior_n __MPN(nior_n)
+__GMP_DECLSPEC void mpn_nior_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_xor_n __MPN(xor_n)
+__GMP_DECLSPEC void mpn_xor_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_xnor_n __MPN(xnor_n)
+__GMP_DECLSPEC void mpn_xnor_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+
+#define mpn_copyi __MPN(copyi)
+__GMP_DECLSPEC void mpn_copyi (mp_ptr, mp_srcptr, mp_size_t);
+#define mpn_copyd __MPN(copyd)
+__GMP_DECLSPEC void mpn_copyd (mp_ptr, mp_srcptr, mp_size_t);
+#define mpn_zero __MPN(zero)
+__GMP_DECLSPEC void mpn_zero (mp_ptr, mp_size_t);
+
+#define mpn_cnd_add_n __MPN(cnd_add_n)
+__GMP_DECLSPEC mp_limb_t mpn_cnd_add_n (mp_limb_t, mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_cnd_sub_n __MPN(cnd_sub_n)
+__GMP_DECLSPEC mp_limb_t mpn_cnd_sub_n (mp_limb_t, mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+
+#define mpn_sec_add_1 __MPN(sec_add_1)
+__GMP_DECLSPEC mp_limb_t mpn_sec_add_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_ptr);
+#define mpn_sec_add_1_itch __MPN(sec_add_1_itch)
+__GMP_DECLSPEC mp_size_t mpn_sec_add_1_itch (mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_sec_sub_1 __MPN(sec_sub_1)
+__GMP_DECLSPEC mp_limb_t mpn_sec_sub_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_ptr);
+#define mpn_sec_sub_1_itch __MPN(sec_sub_1_itch)
+__GMP_DECLSPEC mp_size_t mpn_sec_sub_1_itch (mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_cnd_swap  __MPN(cnd_swap)
+__GMP_DECLSPEC void mpn_cnd_swap (mp_limb_t, volatile mp_limb_t *, volatile mp_limb_t *, mp_size_t);
+
+#define mpn_sec_mul __MPN(sec_mul)
+__GMP_DECLSPEC void mpn_sec_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+#define mpn_sec_mul_itch __MPN(sec_mul_itch)
+__GMP_DECLSPEC mp_size_t mpn_sec_mul_itch (mp_size_t, mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_sec_sqr __MPN(sec_sqr)
+__GMP_DECLSPEC void mpn_sec_sqr (mp_ptr, mp_srcptr, mp_size_t, mp_ptr);
+#define mpn_sec_sqr_itch __MPN(sec_sqr_itch)
+__GMP_DECLSPEC mp_size_t mpn_sec_sqr_itch (mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_sec_powm __MPN(sec_powm)
+__GMP_DECLSPEC void mpn_sec_powm (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_bitcnt_t, mp_srcptr, mp_size_t, mp_ptr);
+#define mpn_sec_powm_itch __MPN(sec_powm_itch)
+__GMP_DECLSPEC mp_size_t mpn_sec_powm_itch (mp_size_t, mp_bitcnt_t, mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_sec_tabselect __MPN(sec_tabselect)
+__GMP_DECLSPEC void mpn_sec_tabselect (volatile mp_limb_t *, volatile const mp_limb_t *, mp_size_t, mp_size_t, mp_size_t);
+
+#define mpn_sec_div_qr __MPN(sec_div_qr)
+__GMP_DECLSPEC mp_limb_t mpn_sec_div_qr (mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+#define mpn_sec_div_qr_itch __MPN(sec_div_qr_itch)
+__GMP_DECLSPEC mp_size_t mpn_sec_div_qr_itch (mp_size_t, mp_size_t) __GMP_ATTRIBUTE_PURE;
+#define mpn_sec_div_r __MPN(sec_div_r)
+__GMP_DECLSPEC void mpn_sec_div_r (mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+#define mpn_sec_div_r_itch __MPN(sec_div_r_itch)
+__GMP_DECLSPEC mp_size_t mpn_sec_div_r_itch (mp_size_t, mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_sec_invert __MPN(sec_invert)
+__GMP_DECLSPEC int mpn_sec_invert (mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_bitcnt_t, mp_ptr);
+#define mpn_sec_invert_itch __MPN(sec_invert_itch)
+__GMP_DECLSPEC mp_size_t mpn_sec_invert_itch (mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+
+/**************** mpz inlines ****************/
+
+/* The following are provided as inlines where possible, but always exist as
+   library functions too, for binary compatibility.
+
+   Within gmp itself this inlining generally isn't relied on, since it
+   doesn't get done for all compilers, whereas if something is worth
+   inlining then it's worth arranging always.
+
+   There are two styles of inlining here.  When the same bit of code is
+   wanted for the inline as for the library version, then __GMP_FORCE_foo
+   arranges for that code to be emitted and the __GMP_EXTERN_INLINE
+   directive suppressed, eg. mpz_fits_uint_p.  When a different bit of code
+   is wanted for the inline than for the library version, then
+   __GMP_FORCE_foo arranges the inline to be suppressed, eg. mpz_abs.  */
+
+#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpz_abs)
+__GMP_EXTERN_INLINE void
+mpz_abs (mpz_ptr __gmp_w, mpz_srcptr __gmp_u)
+{
+  if (__gmp_w != __gmp_u)
+    mpz_set (__gmp_w, __gmp_u);
+  __gmp_w->_mp_size = __GMP_ABS (__gmp_w->_mp_size);
+}
+#endif
+
+#if GMP_NAIL_BITS == 0
+#define __GMPZ_FITS_UTYPE_P(z,maxval)					\
+  mp_size_t  __gmp_n = z->_mp_size;					\
+  mp_ptr  __gmp_p = z->_mp_d;						\
+  return (__gmp_n == 0 || (__gmp_n == 1 && __gmp_p[0] <= maxval));
+#else
+#define __GMPZ_FITS_UTYPE_P(z,maxval)					\
+  mp_size_t  __gmp_n = z->_mp_size;					\
+  mp_ptr  __gmp_p = z->_mp_d;						\
+  return (__gmp_n == 0 || (__gmp_n == 1 && __gmp_p[0] <= maxval)	\
+	  || (__gmp_n == 2 && __gmp_p[1] <= ((mp_limb_t) maxval >> GMP_NUMB_BITS)));
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_fits_uint_p)
+#if ! defined (__GMP_FORCE_mpz_fits_uint_p)
+__GMP_EXTERN_INLINE
+#endif
+int
+mpz_fits_uint_p (mpz_srcptr __gmp_z) __GMP_NOTHROW
+{
+  __GMPZ_FITS_UTYPE_P (__gmp_z, UINT_MAX);
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_fits_ulong_p)
+#if ! defined (__GMP_FORCE_mpz_fits_ulong_p)
+__GMP_EXTERN_INLINE
+#endif
+int
+mpz_fits_ulong_p (mpz_srcptr __gmp_z) __GMP_NOTHROW
+{
+  __GMPZ_FITS_UTYPE_P (__gmp_z, ULONG_MAX);
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_fits_ushort_p)
+#if ! defined (__GMP_FORCE_mpz_fits_ushort_p)
+__GMP_EXTERN_INLINE
+#endif
+int
+mpz_fits_ushort_p (mpz_srcptr __gmp_z) __GMP_NOTHROW
+{
+  __GMPZ_FITS_UTYPE_P (__gmp_z, USHRT_MAX);
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_get_ui)
+#if ! defined (__GMP_FORCE_mpz_get_ui)
+__GMP_EXTERN_INLINE
+#endif
+unsigned long
+mpz_get_ui (mpz_srcptr __gmp_z) __GMP_NOTHROW
+{
+  mp_ptr __gmp_p = __gmp_z->_mp_d;
+  mp_size_t __gmp_n = __gmp_z->_mp_size;
+  mp_limb_t __gmp_l = __gmp_p[0];
+  /* This is a "#if" rather than a plain "if" so as to avoid gcc warnings
+     about "<< GMP_NUMB_BITS" exceeding the type size, and to avoid Borland
+     C++ 6.0 warnings about condition always true for something like
+     "ULONG_MAX < GMP_NUMB_MASK".  */
+#if GMP_NAIL_BITS == 0 || defined (_LONG_LONG_LIMB)
+  /* limb==long and no nails, or limb==longlong, one limb is enough */
+  return (__gmp_n != 0 ? __gmp_l : 0);
+#else
+  /* limb==long and nails, need two limbs when available */
+  __gmp_n = __GMP_ABS (__gmp_n);
+  if (__gmp_n <= 1)
+    return (__gmp_n != 0 ? __gmp_l : 0);
+  else
+    return __gmp_l + (__gmp_p[1] << GMP_NUMB_BITS);
+#endif
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_getlimbn)
+#if ! defined (__GMP_FORCE_mpz_getlimbn)
+__GMP_EXTERN_INLINE
+#endif
+mp_limb_t
+mpz_getlimbn (mpz_srcptr __gmp_z, mp_size_t __gmp_n) __GMP_NOTHROW
+{
+  mp_limb_t  __gmp_result = 0;
+  if (__GMP_LIKELY (__gmp_n >= 0 && __gmp_n < __GMP_ABS (__gmp_z->_mp_size)))
+    __gmp_result = __gmp_z->_mp_d[__gmp_n];
+  return __gmp_result;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpz_neg)
+__GMP_EXTERN_INLINE void
+mpz_neg (mpz_ptr __gmp_w, mpz_srcptr __gmp_u)
+{
+  if (__gmp_w != __gmp_u)
+    mpz_set (__gmp_w, __gmp_u);
+  __gmp_w->_mp_size = - __gmp_w->_mp_size;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_perfect_square_p)
+#if ! defined (__GMP_FORCE_mpz_perfect_square_p)
+__GMP_EXTERN_INLINE
+#endif
+int
+mpz_perfect_square_p (mpz_srcptr __gmp_a)
+{
+  mp_size_t __gmp_asize;
+  int       __gmp_result;
+
+  __gmp_asize = __gmp_a->_mp_size;
+  __gmp_result = (__gmp_asize >= 0);  /* zero is a square, negatives are not */
+  if (__GMP_LIKELY (__gmp_asize > 0))
+    __gmp_result = mpn_perfect_square_p (__gmp_a->_mp_d, __gmp_asize);
+  return __gmp_result;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_popcount)
+#if ! defined (__GMP_FORCE_mpz_popcount)
+__GMP_EXTERN_INLINE
+#endif
+mp_bitcnt_t
+mpz_popcount (mpz_srcptr __gmp_u) __GMP_NOTHROW
+{
+  mp_size_t      __gmp_usize;
+  mp_bitcnt_t    __gmp_result;
+
+  __gmp_usize = __gmp_u->_mp_size;
+  __gmp_result = (__gmp_usize < 0 ? ~ __GMP_CAST (mp_bitcnt_t, 0) : __GMP_CAST (mp_bitcnt_t, 0));
+  if (__GMP_LIKELY (__gmp_usize > 0))
+    __gmp_result =  mpn_popcount (__gmp_u->_mp_d, __gmp_usize);
+  return __gmp_result;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_set_q)
+#if ! defined (__GMP_FORCE_mpz_set_q)
+__GMP_EXTERN_INLINE
+#endif
+void
+mpz_set_q (mpz_ptr __gmp_w, mpq_srcptr __gmp_u)
+{
+  mpz_tdiv_q (__gmp_w, mpq_numref (__gmp_u), mpq_denref (__gmp_u));
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_size)
+#if ! defined (__GMP_FORCE_mpz_size)
+__GMP_EXTERN_INLINE
+#endif
+size_t
+mpz_size (mpz_srcptr __gmp_z) __GMP_NOTHROW
+{
+  return __GMP_ABS (__gmp_z->_mp_size);
+}
+#endif
+
+
+/**************** mpq inlines ****************/
+
+#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpq_abs)
+__GMP_EXTERN_INLINE void
+mpq_abs (mpq_ptr __gmp_w, mpq_srcptr __gmp_u)
+{
+  if (__gmp_w != __gmp_u)
+    mpq_set (__gmp_w, __gmp_u);
+  __gmp_w->_mp_num._mp_size = __GMP_ABS (__gmp_w->_mp_num._mp_size);
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpq_neg)
+__GMP_EXTERN_INLINE void
+mpq_neg (mpq_ptr __gmp_w, mpq_srcptr __gmp_u)
+{
+  if (__gmp_w != __gmp_u)
+    mpq_set (__gmp_w, __gmp_u);
+  __gmp_w->_mp_num._mp_size = - __gmp_w->_mp_num._mp_size;
+}
+#endif
+
+
+/**************** mpn inlines ****************/
+
+/* The comments with __GMPN_ADD_1 below apply here too.
+
+   The test for FUNCTION returning 0 should predict well.  If it's assumed
+   {yp,ysize} will usually have a random number of bits then the high limb
+   won't be full and a carry out will occur a good deal less than 50% of the
+   time.
+
+   ysize==0 isn't a documented feature, but is used internally in a few
+   places.
+
+   Producing cout last stops it using up a register during the main part of
+   the calculation, though gcc (as of 3.0) on an "if (mpn_add (...))"
+   doesn't seem able to move the true and false legs of the conditional up
+   to the two places cout is generated.  */
+
+#define __GMPN_AORS(cout, wp, xp, xsize, yp, ysize, FUNCTION, TEST)     \
+  do {                                                                  \
+    mp_size_t  __gmp_i;                                                 \
+    mp_limb_t  __gmp_x;                                                 \
+                                                                        \
+    /* ASSERT ((ysize) >= 0); */                                        \
+    /* ASSERT ((xsize) >= (ysize)); */                                  \
+    /* ASSERT (MPN_SAME_OR_SEPARATE2_P (wp, xsize, xp, xsize)); */      \
+    /* ASSERT (MPN_SAME_OR_SEPARATE2_P (wp, xsize, yp, ysize)); */      \
+                                                                        \
+    __gmp_i = (ysize);                                                  \
+    if (__gmp_i != 0)                                                   \
+      {                                                                 \
+        if (FUNCTION (wp, xp, yp, __gmp_i))                             \
+          {                                                             \
+            do                                                          \
+              {                                                         \
+                if (__gmp_i >= (xsize))                                 \
+                  {                                                     \
+                    (cout) = 1;                                         \
+                    goto __gmp_done;                                    \
+                  }                                                     \
+                __gmp_x = (xp)[__gmp_i];                                \
+              }                                                         \
+            while (TEST);                                               \
+          }                                                             \
+      }                                                                 \
+    if ((wp) != (xp))                                                   \
+      __GMPN_COPY_REST (wp, xp, xsize, __gmp_i);                        \
+    (cout) = 0;                                                         \
+  __gmp_done:                                                           \
+    ;                                                                   \
+  } while (0)
+
+#define __GMPN_ADD(cout, wp, xp, xsize, yp, ysize)              \
+  __GMPN_AORS (cout, wp, xp, xsize, yp, ysize, mpn_add_n,       \
+               (((wp)[__gmp_i++] = (__gmp_x + 1) & GMP_NUMB_MASK) == 0))
+#define __GMPN_SUB(cout, wp, xp, xsize, yp, ysize)              \
+  __GMPN_AORS (cout, wp, xp, xsize, yp, ysize, mpn_sub_n,       \
+               (((wp)[__gmp_i++] = (__gmp_x - 1) & GMP_NUMB_MASK), __gmp_x == 0))
+
+
+/* The use of __gmp_i indexing is designed to ensure a compile time src==dst
+   remains nice and clear to the compiler, so that __GMPN_COPY_REST can
+   disappear, and the load/add/store gets a chance to become a
+   read-modify-write on CISC CPUs.
+
+   Alternatives:
+
+   Using a pair of pointers instead of indexing would be possible, but gcc
+   isn't able to recognise compile-time src==dst in that case, even when the
+   pointers are incremented more or less together.  Other compilers would
+   very likely have similar difficulty.
+
+   gcc could use "if (__builtin_constant_p(src==dst) && src==dst)" or
+   similar to detect a compile-time src==dst.  This works nicely on gcc
+   2.95.x, it's not good on gcc 3.0 where __builtin_constant_p(p==p) seems
+   to be always false, for a pointer p.  But the current code form seems
+   good enough for src==dst anyway.
+
+   gcc on x86 as usual doesn't give particularly good flags handling for the
+   carry/borrow detection.  It's tempting to want some multi instruction asm
+   blocks to help it, and this was tried, but in truth there's only a few
+   instructions to save and any gain is all too easily lost by register
+   juggling setting up for the asm.  */
+
+#if GMP_NAIL_BITS == 0
+#define __GMPN_AORS_1(cout, dst, src, n, v, OP, CB)		\
+  do {								\
+    mp_size_t  __gmp_i;						\
+    mp_limb_t  __gmp_x, __gmp_r;                                \
+								\
+    /* ASSERT ((n) >= 1); */					\
+    /* ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, n)); */	\
+								\
+    __gmp_x = (src)[0];						\
+    __gmp_r = __gmp_x OP (v);                                   \
+    (dst)[0] = __gmp_r;						\
+    if (CB (__gmp_r, __gmp_x, (v)))                             \
+      {								\
+	(cout) = 1;						\
+	for (__gmp_i = 1; __gmp_i < (n);)                       \
+	  {							\
+	    __gmp_x = (src)[__gmp_i];                           \
+	    __gmp_r = __gmp_x OP 1;                             \
+	    (dst)[__gmp_i] = __gmp_r;                           \
+	    ++__gmp_i;						\
+	    if (!CB (__gmp_r, __gmp_x, 1))                      \
+	      {							\
+		if ((src) != (dst))				\
+		  __GMPN_COPY_REST (dst, src, n, __gmp_i);      \
+		(cout) = 0;					\
+		break;						\
+	      }							\
+	  }							\
+      }								\
+    else							\
+      {								\
+	if ((src) != (dst))					\
+	  __GMPN_COPY_REST (dst, src, n, 1);			\
+	(cout) = 0;						\
+      }								\
+  } while (0)
+#endif
+
+#if GMP_NAIL_BITS >= 1
+#define __GMPN_AORS_1(cout, dst, src, n, v, OP, CB)		\
+  do {								\
+    mp_size_t  __gmp_i;						\
+    mp_limb_t  __gmp_x, __gmp_r;				\
+								\
+    /* ASSERT ((n) >= 1); */					\
+    /* ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, n)); */	\
+								\
+    __gmp_x = (src)[0];						\
+    __gmp_r = __gmp_x OP (v);					\
+    (dst)[0] = __gmp_r & GMP_NUMB_MASK;				\
+    if (__gmp_r >> GMP_NUMB_BITS != 0)				\
+      {								\
+	(cout) = 1;						\
+	for (__gmp_i = 1; __gmp_i < (n);)			\
+	  {							\
+	    __gmp_x = (src)[__gmp_i];				\
+	    __gmp_r = __gmp_x OP 1;				\
+	    (dst)[__gmp_i] = __gmp_r & GMP_NUMB_MASK;		\
+	    ++__gmp_i;						\
+	    if (__gmp_r >> GMP_NUMB_BITS == 0)			\
+	      {							\
+		if ((src) != (dst))				\
+		  __GMPN_COPY_REST (dst, src, n, __gmp_i);	\
+		(cout) = 0;					\
+		break;						\
+	      }							\
+	  }							\
+      }								\
+    else							\
+      {								\
+	if ((src) != (dst))					\
+	  __GMPN_COPY_REST (dst, src, n, 1);			\
+	(cout) = 0;						\
+      }								\
+  } while (0)
+#endif
+
+#define __GMPN_ADDCB(r,x,y) ((r) < (y))
+#define __GMPN_SUBCB(r,x,y) ((x) < (y))
+
+#define __GMPN_ADD_1(cout, dst, src, n, v)	     \
+  __GMPN_AORS_1(cout, dst, src, n, v, +, __GMPN_ADDCB)
+#define __GMPN_SUB_1(cout, dst, src, n, v)	     \
+  __GMPN_AORS_1(cout, dst, src, n, v, -, __GMPN_SUBCB)
+
+
+/* Compare {xp,size} and {yp,size}, setting "result" to positive, zero or
+   negative.  size==0 is allowed.  On random data usually only one limb will
+   need to be examined to get a result, so it's worth having it inline.  */
+#define __GMPN_CMP(result, xp, yp, size)                                \
+  do {                                                                  \
+    mp_size_t  __gmp_i;                                                 \
+    mp_limb_t  __gmp_x, __gmp_y;                                        \
+                                                                        \
+    /* ASSERT ((size) >= 0); */                                         \
+                                                                        \
+    (result) = 0;                                                       \
+    __gmp_i = (size);                                                   \
+    while (--__gmp_i >= 0)                                              \
+      {                                                                 \
+        __gmp_x = (xp)[__gmp_i];                                        \
+        __gmp_y = (yp)[__gmp_i];                                        \
+        if (__gmp_x != __gmp_y)                                         \
+          {                                                             \
+            /* Cannot use __gmp_x - __gmp_y, may overflow an "int" */   \
+            (result) = (__gmp_x > __gmp_y ? 1 : -1);                    \
+            break;                                                      \
+          }                                                             \
+      }                                                                 \
+  } while (0)
+
+
+#if defined (__GMPN_COPY) && ! defined (__GMPN_COPY_REST)
+#define __GMPN_COPY_REST(dst, src, size, start)                 \
+  do {                                                          \
+    /* ASSERT ((start) >= 0); */                                \
+    /* ASSERT ((start) <= (size)); */                           \
+    __GMPN_COPY ((dst)+(start), (src)+(start), (size)-(start)); \
+  } while (0)
+#endif
+
+/* Copy {src,size} to {dst,size}, starting at "start".  This is designed to
+   keep the indexing dst[j] and src[j] nice and simple for __GMPN_ADD_1,
+   __GMPN_ADD, etc.  */
+#if ! defined (__GMPN_COPY_REST)
+#define __GMPN_COPY_REST(dst, src, size, start)                 \
+  do {                                                          \
+    mp_size_t __gmp_j;                                          \
+    /* ASSERT ((size) >= 0); */                                 \
+    /* ASSERT ((start) >= 0); */                                \
+    /* ASSERT ((start) <= (size)); */                           \
+    /* ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, size)); */     \
+    __GMP_CRAY_Pragma ("_CRI ivdep");                           \
+    for (__gmp_j = (start); __gmp_j < (size); __gmp_j++)        \
+      (dst)[__gmp_j] = (src)[__gmp_j];                          \
+  } while (0)
+#endif
+
+/* Enhancement: Use some of the smarter code from gmp-impl.h.  Maybe use
+   mpn_copyi if there's a native version, and if we don't mind demanding
+   binary compatibility for it (on targets which use it).  */
+
+#if ! defined (__GMPN_COPY)
+#define __GMPN_COPY(dst, src, size)   __GMPN_COPY_REST (dst, src, size, 0)
+#endif
+
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_add)
+#if ! defined (__GMP_FORCE_mpn_add)
+__GMP_EXTERN_INLINE
+#endif
+mp_limb_t
+mpn_add (mp_ptr __gmp_wp, mp_srcptr __gmp_xp, mp_size_t __gmp_xsize, mp_srcptr __gmp_yp, mp_size_t __gmp_ysize)
+{
+  mp_limb_t  __gmp_c;
+  __GMPN_ADD (__gmp_c, __gmp_wp, __gmp_xp, __gmp_xsize, __gmp_yp, __gmp_ysize);
+  return __gmp_c;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_add_1)
+#if ! defined (__GMP_FORCE_mpn_add_1)
+__GMP_EXTERN_INLINE
+#endif
+mp_limb_t
+mpn_add_1 (mp_ptr __gmp_dst, mp_srcptr __gmp_src, mp_size_t __gmp_size, mp_limb_t __gmp_n) __GMP_NOTHROW
+{
+  mp_limb_t  __gmp_c;
+  __GMPN_ADD_1 (__gmp_c, __gmp_dst, __gmp_src, __gmp_size, __gmp_n);
+  return __gmp_c;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_cmp)
+#if ! defined (__GMP_FORCE_mpn_cmp)
+__GMP_EXTERN_INLINE
+#endif
+int
+mpn_cmp (mp_srcptr __gmp_xp, mp_srcptr __gmp_yp, mp_size_t __gmp_size) __GMP_NOTHROW
+{
+  int __gmp_result;
+  __GMPN_CMP (__gmp_result, __gmp_xp, __gmp_yp, __gmp_size);
+  return __gmp_result;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_zero_p)
+#if ! defined (__GMP_FORCE_mpn_zero_p)
+__GMP_EXTERN_INLINE
+#endif
+int
+mpn_zero_p (mp_srcptr __gmp_p, mp_size_t __gmp_n) __GMP_NOTHROW
+{
+  /* if (__GMP_LIKELY (__gmp_n > 0)) */
+    do {
+      if (__gmp_p[--__gmp_n] != 0)
+	return 0;
+    } while (__gmp_n != 0);
+  return 1;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_sub)
+#if ! defined (__GMP_FORCE_mpn_sub)
+__GMP_EXTERN_INLINE
+#endif
+mp_limb_t
+mpn_sub (mp_ptr __gmp_wp, mp_srcptr __gmp_xp, mp_size_t __gmp_xsize, mp_srcptr __gmp_yp, mp_size_t __gmp_ysize)
+{
+  mp_limb_t  __gmp_c;
+  __GMPN_SUB (__gmp_c, __gmp_wp, __gmp_xp, __gmp_xsize, __gmp_yp, __gmp_ysize);
+  return __gmp_c;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_sub_1)
+#if ! defined (__GMP_FORCE_mpn_sub_1)
+__GMP_EXTERN_INLINE
+#endif
+mp_limb_t
+mpn_sub_1 (mp_ptr __gmp_dst, mp_srcptr __gmp_src, mp_size_t __gmp_size, mp_limb_t __gmp_n) __GMP_NOTHROW
+{
+  mp_limb_t  __gmp_c;
+  __GMPN_SUB_1 (__gmp_c, __gmp_dst, __gmp_src, __gmp_size, __gmp_n);
+  return __gmp_c;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_neg)
+#if ! defined (__GMP_FORCE_mpn_neg)
+__GMP_EXTERN_INLINE
+#endif
+mp_limb_t
+mpn_neg (mp_ptr __gmp_rp, mp_srcptr __gmp_up, mp_size_t __gmp_n)
+{
+  while (*__gmp_up == 0) /* Low zero limbs are unchanged by negation. */
+    {
+      *__gmp_rp = 0;
+      if (!--__gmp_n) /* All zero */
+	return 0;
+      ++__gmp_up; ++__gmp_rp;
+    }
+
+  *__gmp_rp = (- *__gmp_up) & GMP_NUMB_MASK;
+
+  if (--__gmp_n) /* Higher limbs get complemented. */
+    mpn_com (++__gmp_rp, ++__gmp_up, __gmp_n);
+
+  return 1;
+}
+#endif
+
+#if defined (__cplusplus)
+}
+#endif
+
+
+/* Allow faster testing for negative, zero, and positive.  */
+#define mpz_sgn(Z) ((Z)->_mp_size < 0 ? -1 : (Z)->_mp_size > 0)
+#define mpf_sgn(F) ((F)->_mp_size < 0 ? -1 : (F)->_mp_size > 0)
+#define mpq_sgn(Q) ((Q)->_mp_num._mp_size < 0 ? -1 : (Q)->_mp_num._mp_size > 0)
+
+/* When using GCC, optimize certain common comparisons.  */
+#if defined (__GNUC__) && __GNUC__ >= 2
+#define mpz_cmp_ui(Z,UI) \
+  (__builtin_constant_p (UI) && (UI) == 0				\
+   ? mpz_sgn (Z) : _mpz_cmp_ui (Z,UI))
+#define mpz_cmp_si(Z,SI)						\
+  (__builtin_constant_p ((SI) >= 0) && (SI) >= 0			\
+   ? mpz_cmp_ui (Z, __GMP_CAST (unsigned long, SI))			\
+   : _mpz_cmp_si (Z,SI))
+#define mpq_cmp_ui(Q,NUI,DUI)					\
+  (__builtin_constant_p (NUI) && (NUI) == 0 ? mpq_sgn (Q)	\
+   : __builtin_constant_p ((NUI) == (DUI)) && (NUI) == (DUI)	\
+   ? mpz_cmp (mpq_numref (Q), mpq_denref (Q))			\
+   : _mpq_cmp_ui (Q,NUI,DUI))
+#define mpq_cmp_si(q,n,d)				\
+  (__builtin_constant_p ((n) >= 0) && (n) >= 0		\
+   ? mpq_cmp_ui (q, __GMP_CAST (unsigned long, n), d)	\
+   : _mpq_cmp_si (q, n, d))
+#else
+#define mpz_cmp_ui(Z,UI) _mpz_cmp_ui (Z,UI)
+#define mpz_cmp_si(Z,UI) _mpz_cmp_si (Z,UI)
+#define mpq_cmp_ui(Q,NUI,DUI) _mpq_cmp_ui (Q,NUI,DUI)
+#define mpq_cmp_si(q,n,d)  _mpq_cmp_si(q,n,d)
+#endif
+
+
+/* Using "&" rather than "&&" means these can come out branch-free.  Every
+   mpz_t has at least one limb allocated, so fetching the low limb is always
+   allowed.  */
+#define mpz_odd_p(z)   (((z)->_mp_size != 0) & __GMP_CAST (int, (z)->_mp_d[0]))
+#define mpz_even_p(z)  (! mpz_odd_p (z))
+
+
+/**************** C++ routines ****************/
+
+#ifdef __cplusplus
+__GMP_DECLSPEC_XX std::ostream& operator<< (std::ostream &, mpz_srcptr);
+__GMP_DECLSPEC_XX std::ostream& operator<< (std::ostream &, mpq_srcptr);
+__GMP_DECLSPEC_XX std::ostream& operator<< (std::ostream &, mpf_srcptr);
+__GMP_DECLSPEC_XX std::istream& operator>> (std::istream &, mpz_ptr);
+__GMP_DECLSPEC_XX std::istream& operator>> (std::istream &, mpq_ptr);
+__GMP_DECLSPEC_XX std::istream& operator>> (std::istream &, mpf_ptr);
+#endif
+
+
+/* Source-level compatibility with GMP 2 and earlier. */
+#define mpn_divmod(qp,np,nsize,dp,dsize) \
+  mpn_divrem (qp, __GMP_CAST (mp_size_t, 0), np, nsize, dp, dsize)
+
+/* Source-level compatibility with GMP 1.  */
+#define mpz_mdiv	mpz_fdiv_q
+#define mpz_mdivmod	mpz_fdiv_qr
+#define mpz_mmod	mpz_fdiv_r
+#define mpz_mdiv_ui	mpz_fdiv_q_ui
+#define mpz_mdivmod_ui(q,r,n,d) \
+  (((r) == 0) ? mpz_fdiv_q_ui (q,n,d) : mpz_fdiv_qr_ui (q,r,n,d))
+#define mpz_mmod_ui(r,n,d) \
+  (((r) == 0) ? mpz_fdiv_ui (n,d) : mpz_fdiv_r_ui (r,n,d))
+
+/* Useful synonyms, but not quite compatible with GMP 1.  */
+#define mpz_div		mpz_fdiv_q
+#define mpz_divmod	mpz_fdiv_qr
+#define mpz_div_ui	mpz_fdiv_q_ui
+#define mpz_divmod_ui	mpz_fdiv_qr_ui
+#define mpz_div_2exp	mpz_fdiv_q_2exp
+#define mpz_mod_2exp	mpz_fdiv_r_2exp
+
+enum
+{
+  GMP_ERROR_NONE = 0,
+  GMP_ERROR_UNSUPPORTED_ARGUMENT = 1,
+  GMP_ERROR_DIVISION_BY_ZERO = 2,
+  GMP_ERROR_SQRT_OF_NEGATIVE = 4,
+  GMP_ERROR_INVALID_ARGUMENT = 8
+};
+
+/* Define CC and CFLAGS which were used to build this version of GMP */
+#define __GMP_CC "gcc"
+#define __GMP_CFLAGS "-O2 -pedantic -march=armv8-a"
+
+/* Major version number is the value of __GNU_MP__ too, above. */
+#define __GNU_MP_VERSION            6
+#define __GNU_MP_VERSION_MINOR      2
+#define __GNU_MP_VERSION_PATCHLEVEL 0
+#define __GNU_MP_RELEASE (__GNU_MP_VERSION * 10000 + __GNU_MP_VERSION_MINOR * 100 + __GNU_MP_VERSION_PATCHLEVEL)
+
+#define __GMP_H__
+#endif /* __GMP_H__ */
diff --git a/third_party/gmp/config/x86_64/config.h b/third_party/gmp/config/x86_64/config.h
new file mode 100644
index 0000000..d7960e4
--- /dev/null
+++ b/third_party/gmp/config/x86_64/config.h
@@ -0,0 +1,670 @@
+/* config.h.  Generated from config.in by configure.  */
+/* config.in.  Generated from configure.ac by autoheader.  */
+
+/*
+
+Copyright 1996-2020 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.
+*/
+
+/* Define if building universal (internal helper macro) */
+/* #undef AC_APPLE_UNIVERSAL_BUILD */
+
+/* The gmp-mparam.h file (a string) the tune program should suggest updating.
+   */
+#define GMP_MPARAM_H_SUGGEST "./mpn/x86_64/zen2/gmp-mparam.h"
+
+/* Define to 1 if you have the `alarm' function. */
+#define HAVE_ALARM 1
+
+/* Define to 1 if alloca() works (via gmp-impl.h). */
+#define HAVE_ALLOCA 1
+
+/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix).
+   */
+#define HAVE_ALLOCA_H 1
+
+/* Define to 1 if the compiler accepts gcc style __attribute__ ((const)) */
+#define HAVE_ATTRIBUTE_CONST 1
+
+/* Define to 1 if the compiler accepts gcc style __attribute__ ((malloc)) */
+#define HAVE_ATTRIBUTE_MALLOC 1
+
+/* Define to 1 if the compiler accepts gcc style __attribute__ ((mode (XX)))
+   */
+#define HAVE_ATTRIBUTE_MODE 1
+
+/* Define to 1 if the compiler accepts gcc style __attribute__ ((noreturn)) */
+#define HAVE_ATTRIBUTE_NORETURN 1
+
+/* Define to 1 if you have the `attr_get' function. */
+/* #undef HAVE_ATTR_GET */
+
+/* Define to 1 if tests/libtests has calling conventions checking for the CPU
+   */
+#define HAVE_CALLING_CONVENTIONS 1
+
+/* Define to 1 if you have the `clock' function. */
+#define HAVE_CLOCK 1
+
+/* Define to 1 if you have the `clock_gettime' function */
+#define HAVE_CLOCK_GETTIME 1
+
+/* Define to 1 if you have the `cputime' function. */
+/* #undef HAVE_CPUTIME */
+
+/* Define to 1 if you have the declaration of `fgetc', and to 0 if you don't.
+   */
+#define HAVE_DECL_FGETC 1
+
+/* Define to 1 if you have the declaration of `fscanf', and to 0 if you don't.
+   */
+#define HAVE_DECL_FSCANF 1
+
+/* Define to 1 if you have the declaration of `optarg', and to 0 if you don't.
+   */
+#define HAVE_DECL_OPTARG 1
+
+/* Define to 1 if you have the declaration of `sys_errlist', and to 0 if you
+   don't. */
+#define HAVE_DECL_SYS_ERRLIST 1
+
+/* Define to 1 if you have the declaration of `sys_nerr', and to 0 if you
+   don't. */
+#define HAVE_DECL_SYS_NERR 1
+
+/* Define to 1 if you have the declaration of `ungetc', and to 0 if you don't.
+   */
+#define HAVE_DECL_UNGETC 1
+
+/* Define to 1 if you have the declaration of `vfprintf', and to 0 if you
+   don't. */
+#define HAVE_DECL_VFPRINTF 1
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define one of the following to 1 for the format of a `double'.
+   If your format is not among these choices, or you don't know what it is,
+   then leave all undefined.
+   IEEE_LITTLE_SWAPPED means little endian, but with the two 4-byte halves
+   swapped, as used by ARM CPUs in little endian mode.  */
+/* #undef HAVE_DOUBLE_IEEE_BIG_ENDIAN */
+#define HAVE_DOUBLE_IEEE_LITTLE_ENDIAN 1
+/* #undef HAVE_DOUBLE_IEEE_LITTLE_SWAPPED */
+/* #undef HAVE_DOUBLE_VAX_D */
+/* #undef HAVE_DOUBLE_VAX_G */
+/* #undef HAVE_DOUBLE_CRAY_CFP */
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the <float.h> header file. */
+#define HAVE_FLOAT_H 1
+
+/* Define to 1 if you have the `getpagesize' function. */
+#define HAVE_GETPAGESIZE 1
+
+/* Define to 1 if you have the `getrusage' function. */
+#define HAVE_GETRUSAGE 1
+
+/* Define to 1 if you have the `getsysinfo' function. */
+/* #undef HAVE_GETSYSINFO */
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if the compiler accepts gcc style __attribute__ ((visibility))
+   and __attribute__ ((alias)) */
+#define HAVE_HIDDEN_ALIAS 1
+
+/* Define one of these to 1 for the host CPU family.
+   If your CPU is not in any of these families, leave all undefined.
+   For an AMD64 chip, define "x86" in ABI=32, but not in ABI=64. */
+/* #undef HAVE_HOST_CPU_FAMILY_alpha */
+/* #undef HAVE_HOST_CPU_FAMILY_m68k */
+/* #undef HAVE_HOST_CPU_FAMILY_power */
+/* #undef HAVE_HOST_CPU_FAMILY_powerpc */
+/* #undef HAVE_HOST_CPU_FAMILY_x86 */
+#define HAVE_HOST_CPU_FAMILY_x86_64 1
+
+/* Define one of the following to 1 for the host CPU, as per the output of
+   ./config.guess.  If your CPU is not listed here, leave all undefined.  */
+/* #undef HAVE_HOST_CPU_alphaev67 */
+/* #undef HAVE_HOST_CPU_alphaev68 */
+/* #undef HAVE_HOST_CPU_alphaev7 */
+/* #undef HAVE_HOST_CPU_m68020 */
+/* #undef HAVE_HOST_CPU_m68030 */
+/* #undef HAVE_HOST_CPU_m68040 */
+/* #undef HAVE_HOST_CPU_m68060 */
+/* #undef HAVE_HOST_CPU_m68360 */
+/* #undef HAVE_HOST_CPU_powerpc604 */
+/* #undef HAVE_HOST_CPU_powerpc604e */
+/* #undef HAVE_HOST_CPU_powerpc750 */
+/* #undef HAVE_HOST_CPU_powerpc7400 */
+/* #undef HAVE_HOST_CPU_supersparc */
+/* #undef HAVE_HOST_CPU_i386 */
+/* #undef HAVE_HOST_CPU_i586 */
+/* #undef HAVE_HOST_CPU_i686 */
+/* #undef HAVE_HOST_CPU_pentium */
+/* #undef HAVE_HOST_CPU_pentiummmx */
+/* #undef HAVE_HOST_CPU_pentiumpro */
+/* #undef HAVE_HOST_CPU_pentium2 */
+/* #undef HAVE_HOST_CPU_pentium3 */
+/* #undef HAVE_HOST_CPU_pentium4 */
+/* #undef HAVE_HOST_CPU_core2 */
+/* #undef HAVE_HOST_CPU_nehalem */
+/* #undef HAVE_HOST_CPU_westmere */
+/* #undef HAVE_HOST_CPU_sandybridge */
+/* #undef HAVE_HOST_CPU_ivybridge */
+/* #undef HAVE_HOST_CPU_haswell */
+/* #undef HAVE_HOST_CPU_broadwell */
+/* #undef HAVE_HOST_CPU_skylake */
+/* #undef HAVE_HOST_CPU_silvermont */
+/* #undef HAVE_HOST_CPU_goldmont */
+/* #undef HAVE_HOST_CPU_k8 */
+/* #undef HAVE_HOST_CPU_k10 */
+/* #undef HAVE_HOST_CPU_bulldozer */
+/* #undef HAVE_HOST_CPU_piledriver */
+/* #undef HAVE_HOST_CPU_steamroller */
+/* #undef HAVE_HOST_CPU_excavator */
+/* #undef HAVE_HOST_CPU_zen */
+/* #undef HAVE_HOST_CPU_bobcat */
+/* #undef HAVE_HOST_CPU_jaguar */
+/* #undef HAVE_HOST_CPU_s390_z900 */
+/* #undef HAVE_HOST_CPU_s390_z990 */
+/* #undef HAVE_HOST_CPU_s390_z9 */
+/* #undef HAVE_HOST_CPU_s390_z10 */
+/* #undef HAVE_HOST_CPU_s390_z196 */
+
+/* Define to 1 iff we have a s390 with 64-bit registers.  */
+/* #undef HAVE_HOST_CPU_s390_zarch */
+
+/* Define to 1 if the system has the type `intmax_t'. */
+#define HAVE_INTMAX_T 1
+
+/* Define to 1 if the system has the type `intptr_t'. */
+#define HAVE_INTPTR_T 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the <invent.h> header file. */
+/* #undef HAVE_INVENT_H */
+
+/* Define to 1 if you have the <langinfo.h> header file. */
+#define HAVE_LANGINFO_H 1
+
+/* Define one of these to 1 for the endianness of `mp_limb_t'.
+   If the endianness is not a simple big or little, or you don't know what
+   it is, then leave both undefined. */
+/* #undef HAVE_LIMB_BIG_ENDIAN */
+#define HAVE_LIMB_LITTLE_ENDIAN 1
+
+/* Define to 1 if you have the `localeconv' function. */
+#define HAVE_LOCALECONV 1
+
+/* Define to 1 if you have the <locale.h> header file. */
+#define HAVE_LOCALE_H 1
+
+/* Define to 1 if the system has the type `long double'. */
+#define HAVE_LONG_DOUBLE 1
+
+/* Define to 1 if the system has the type `long long'. */
+#define HAVE_LONG_LONG 1
+
+/* Define to 1 if you have the <machine/hal_sysinfo.h> header file. */
+/* #undef HAVE_MACHINE_HAL_SYSINFO_H */
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `memset' function. */
+#define HAVE_MEMSET 1
+
+/* Define to 1 if you have the `mmap' function. */
+#define HAVE_MMAP 1
+
+/* Define to 1 if you have the `mprotect' function. */
+#define HAVE_MPROTECT 1
+
+#if !NO_ASM
+/* Define to 1 each of the following for which a native (ie. CPU specific)
+    implementation of the corresponding routine exists.  */
+#define HAVE_NATIVE_mpn_add_n 1
+/* #undef HAVE_NATIVE_mpn_add_n_sub_n */
+#define HAVE_NATIVE_mpn_add_nc 1
+#define HAVE_NATIVE_mpn_addaddmul_1msb0 1
+#define HAVE_NATIVE_mpn_addlsh1_n 1
+#define HAVE_NATIVE_mpn_addlsh2_n 1
+#define HAVE_NATIVE_mpn_addlsh_n 1
+#define HAVE_NATIVE_mpn_addlsh1_nc 1
+/* #undef HAVE_NATIVE_mpn_addlsh2_nc */
+/* #undef HAVE_NATIVE_mpn_addlsh_nc */
+/* #undef HAVE_NATIVE_mpn_addlsh1_n_ip1 */
+/* #undef HAVE_NATIVE_mpn_addlsh2_n_ip1 */
+/* #undef HAVE_NATIVE_mpn_addlsh_n_ip1 */
+/* #undef HAVE_NATIVE_mpn_addlsh1_nc_ip1 */
+/* #undef HAVE_NATIVE_mpn_addlsh2_nc_ip1 */
+/* #undef HAVE_NATIVE_mpn_addlsh_nc_ip1 */
+/* #undef HAVE_NATIVE_mpn_addlsh1_n_ip2 */
+/* #undef HAVE_NATIVE_mpn_addlsh2_n_ip2 */
+/* #undef HAVE_NATIVE_mpn_addlsh_n_ip2 */
+/* #undef HAVE_NATIVE_mpn_addlsh1_nc_ip2 */
+/* #undef HAVE_NATIVE_mpn_addlsh2_nc_ip2 */
+/* #undef HAVE_NATIVE_mpn_addlsh_nc_ip2 */
+/* #undef HAVE_NATIVE_mpn_addmul_1c */
+/* #undef HAVE_NATIVE_mpn_addmul_2 */
+/* #undef HAVE_NATIVE_mpn_addmul_3 */
+/* #undef HAVE_NATIVE_mpn_addmul_4 */
+/* #undef HAVE_NATIVE_mpn_addmul_5 */
+/* #undef HAVE_NATIVE_mpn_addmul_6 */
+/* #undef HAVE_NATIVE_mpn_addmul_7 */
+/* #undef HAVE_NATIVE_mpn_addmul_8 */
+/* #undef HAVE_NATIVE_mpn_addmul_2s */
+#define HAVE_NATIVE_mpn_and_n 1
+#define HAVE_NATIVE_mpn_andn_n 1
+#define HAVE_NATIVE_mpn_bdiv_dbm1c 1
+#define HAVE_NATIVE_mpn_bdiv_q_1 1
+#define HAVE_NATIVE_mpn_pi1_bdiv_q_1 1
+#define HAVE_NATIVE_mpn_cnd_add_n 1
+#define HAVE_NATIVE_mpn_cnd_sub_n 1
+#define HAVE_NATIVE_mpn_com 1
+#define HAVE_NATIVE_mpn_copyd 1
+#define HAVE_NATIVE_mpn_copyi 1
+#define HAVE_NATIVE_mpn_div_qr_1n_pi1 1
+/* #undef HAVE_NATIVE_mpn_div_qr_2 */
+#define HAVE_NATIVE_mpn_divexact_1 1
+/* #undef HAVE_NATIVE_mpn_divexact_by3c */
+#define HAVE_NATIVE_mpn_divrem_1 1
+/* #undef HAVE_NATIVE_mpn_divrem_1c */
+#define HAVE_NATIVE_mpn_divrem_2 1
+/* #undef HAVE_NATIVE_mpn_gcd_1 */
+#define HAVE_NATIVE_mpn_gcd_11 1
+#define HAVE_NATIVE_mpn_gcd_22 1
+#define HAVE_NATIVE_mpn_hamdist 1
+#define HAVE_NATIVE_mpn_invert_limb 1
+#define HAVE_NATIVE_mpn_ior_n 1
+#define HAVE_NATIVE_mpn_iorn_n 1
+#define HAVE_NATIVE_mpn_lshift 1
+#define HAVE_NATIVE_mpn_lshiftc 1
+/* #undef HAVE_NATIVE_mpn_lshsub_n */
+/* #undef HAVE_NATIVE_mpn_mod_1 */
+#define HAVE_NATIVE_mpn_mod_1_1p 1
+/* #undef HAVE_NATIVE_mpn_mod_1c */
+#define HAVE_NATIVE_mpn_mod_1s_2p 1
+#define HAVE_NATIVE_mpn_mod_1s_4p 1
+#define HAVE_NATIVE_mpn_mod_34lsub1 1
+#define HAVE_NATIVE_mpn_modexact_1_odd 1
+#define HAVE_NATIVE_mpn_modexact_1c_odd 1
+#define HAVE_NATIVE_mpn_mul_1 1
+#define HAVE_NATIVE_mpn_mul_1c 1
+#define HAVE_NATIVE_mpn_mul_2 1
+/* #undef HAVE_NATIVE_mpn_mul_3 */
+/* #undef HAVE_NATIVE_mpn_mul_4 */
+/* #undef HAVE_NATIVE_mpn_mul_5 */
+/* #undef HAVE_NATIVE_mpn_mul_6 */
+#define HAVE_NATIVE_mpn_mul_basecase 1
+#define HAVE_NATIVE_mpn_mullo_basecase 1
+#define HAVE_NATIVE_mpn_nand_n 1
+#define HAVE_NATIVE_mpn_nior_n 1
+#define HAVE_NATIVE_mpn_popcount 1
+#define HAVE_NATIVE_mpn_preinv_divrem_1 1
+/* #undef HAVE_NATIVE_mpn_preinv_mod_1 */
+/* #undef HAVE_NATIVE_mpn_redc_1 */
+/* #undef HAVE_NATIVE_mpn_redc_2 */
+#define HAVE_NATIVE_mpn_rsblsh1_n 1
+#define HAVE_NATIVE_mpn_rsblsh2_n 1
+#define HAVE_NATIVE_mpn_rsblsh_n 1
+#define HAVE_NATIVE_mpn_rsblsh1_nc 1
+/* #undef HAVE_NATIVE_mpn_rsblsh2_nc */
+/* #undef HAVE_NATIVE_mpn_rsblsh_nc */
+#define HAVE_NATIVE_mpn_rsh1add_n 1
+#define HAVE_NATIVE_mpn_rsh1add_nc 1
+#define HAVE_NATIVE_mpn_rsh1sub_n 1
+#define HAVE_NATIVE_mpn_rsh1sub_nc 1
+#define HAVE_NATIVE_mpn_rshift 1
+#define HAVE_NATIVE_mpn_sbpi1_bdiv_r 1
+#define HAVE_NATIVE_mpn_sqr_basecase 1
+/* #undef HAVE_NATIVE_mpn_sqr_diagonal */
+#define HAVE_NATIVE_mpn_sqr_diag_addlsh1 1
+#define HAVE_NATIVE_mpn_sub_n 1
+#define HAVE_NATIVE_mpn_sub_nc 1
+#define HAVE_NATIVE_mpn_sublsh1_n 1
+/* #undef HAVE_NATIVE_mpn_sublsh2_n */
+/* #undef HAVE_NATIVE_mpn_sublsh_n */
+#define HAVE_NATIVE_mpn_sublsh1_nc 1
+/* #undef HAVE_NATIVE_mpn_sublsh2_nc */
+/* #undef HAVE_NATIVE_mpn_sublsh_nc */
+/* #undef HAVE_NATIVE_mpn_sublsh1_n_ip1 */
+/* #undef HAVE_NATIVE_mpn_sublsh2_n_ip1 */
+/* #undef HAVE_NATIVE_mpn_sublsh_n_ip1 */
+/* #undef HAVE_NATIVE_mpn_sublsh1_nc_ip1 */
+/* #undef HAVE_NATIVE_mpn_sublsh2_nc_ip1 */
+/* #undef HAVE_NATIVE_mpn_sublsh_nc_ip1 */
+/* #undef HAVE_NATIVE_mpn_submul_1c */
+/* #undef HAVE_NATIVE_mpn_tabselect */
+/* #undef HAVE_NATIVE_mpn_udiv_qrnnd */
+/* #undef HAVE_NATIVE_mpn_udiv_qrnnd_r */
+/* #undef HAVE_NATIVE_mpn_umul_ppmm */
+/* #undef HAVE_NATIVE_mpn_umul_ppmm_r */
+#define HAVE_NATIVE_mpn_xor_n 1
+#define HAVE_NATIVE_mpn_xnor_n 1
+#endif  // !NO_ASM
+
+/* Define to 1 if you have the `nl_langinfo' function. */
+#define HAVE_NL_LANGINFO 1
+
+/* Define to 1 if you have the <nl_types.h> header file. */
+#define HAVE_NL_TYPES_H 1
+
+/* Define to 1 if you have the `obstack_vprintf' function. */
+#define HAVE_OBSTACK_VPRINTF 1
+
+/* Define to 1 if you have the `popen' function. */
+#define HAVE_POPEN 1
+
+/* Define to 1 if you have the `processor_info' function. */
+/* #undef HAVE_PROCESSOR_INFO */
+
+/* Define to 1 if <sys/pstat.h> `struct pst_processor' exists and contains
+   `psp_iticksperclktick'. */
+/* #undef HAVE_PSP_ITICKSPERCLKTICK */
+
+/* Define to 1 if you have the `pstat_getprocessor' function. */
+/* #undef HAVE_PSTAT_GETPROCESSOR */
+
+/* Define to 1 if the system has the type `ptrdiff_t'. */
+#define HAVE_PTRDIFF_T 1
+
+/* Define to 1 if the system has the type `quad_t'. */
+#define HAVE_QUAD_T 1
+
+/* Define to 1 if you have the `raise' function. */
+#define HAVE_RAISE 1
+
+/* Define to 1 if you have the `read_real_time' function. */
+/* #undef HAVE_READ_REAL_TIME */
+
+/* Define to 1 if you have the `sigaction' function. */
+#define HAVE_SIGACTION 1
+
+/* Define to 1 if you have the `sigaltstack' function. */
+#define HAVE_SIGALTSTACK 1
+
+/* Define to 1 if you have the `sigstack' function. */
+#define HAVE_SIGSTACK 1
+
+/* Tune directory speed_cyclecounter, undef=none, 1=32bits, 2=64bits) */
+#define HAVE_SPEED_CYCLECOUNTER 2
+
+/* Define to 1 if you have the <sstream> header file. */
+#define HAVE_SSTREAM 1
+
+/* Define to 1 if the system has the type `stack_t'. */
+#define HAVE_STACK_T 1
+
+/* 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 the system has the type `std::locale'. */
+#define HAVE_STD__LOCALE 1
+
+/* Define to 1 if you have the `strchr' function. */
+#define HAVE_STRCHR 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. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strnlen' function. */
+#define HAVE_STRNLEN 1
+
+/* Define to 1 if you have the `strtol' function. */
+#define HAVE_STRTOL 1
+
+/* Define to 1 if you have the `strtoul' function. */
+#define HAVE_STRTOUL 1
+
+/* Define to 1 if you have the `sysconf' function. */
+#define HAVE_SYSCONF 1
+
+/* Define to 1 if you have the `sysctl' function. */
+#define HAVE_SYSCTL 1
+
+/* Define to 1 if you have the `sysctlbyname' function. */
+/* #undef HAVE_SYSCTLBYNAME */
+
+/* Define to 1 if you have the `syssgi' function. */
+/* #undef HAVE_SYSSGI */
+
+/* Define to 1 if you have the <sys/attributes.h> header file. */
+/* #undef HAVE_SYS_ATTRIBUTES_H */
+
+/* Define to 1 if you have the <sys/iograph.h> header file. */
+/* #undef HAVE_SYS_IOGRAPH_H */
+
+/* Define to 1 if you have the <sys/mman.h> header file. */
+#define HAVE_SYS_MMAN_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/processor.h> header file. */
+/* #undef HAVE_SYS_PROCESSOR_H */
+
+/* Define to 1 if you have the <sys/pstat.h> header file. */
+/* #undef HAVE_SYS_PSTAT_H */
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#define HAVE_SYS_RESOURCE_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/sysctl.h> header file. */
+#define HAVE_SYS_SYSCTL_H 1
+
+/* Define to 1 if you have the <sys/sysinfo.h> header file. */
+#define HAVE_SYS_SYSINFO_H 1
+
+/* Define to 1 if you have the <sys/syssgi.h> header file. */
+/* #undef HAVE_SYS_SYSSGI_H */
+
+/* Define to 1 if you have the <sys/systemcfg.h> header file. */
+/* #undef HAVE_SYS_SYSTEMCFG_H */
+
+/* Define to 1 if you have the <sys/times.h> header file. */
+#define HAVE_SYS_TIMES_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the `times' function. */
+#define HAVE_TIMES 1
+
+/* Define to 1 if the system has the type `uint_least32_t'. */
+#define HAVE_UINT_LEAST32_T 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `vsnprintf' function and it works properly. */
+#define HAVE_VSNPRINTF 1
+
+/* Define to 1 for Windos/64 */
+/* #undef HOST_DOS64 */
+
+/* Assembler local label prefix */
+#define LSYM_PREFIX ".L"
+
+/* Define to the sub-directory where libtool stores uninstalled libraries. */
+#define LT_OBJDIR ".libs/"
+
+/* Define to 1 to disable the use of inline assembly */
+/* #undef NO_ASM */
+
+/* Name of package */
+#define PACKAGE "gmp"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "gmp-bugs@gmplib.org, see https://gmplib.org/manual/Reporting-Bugs.html"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "GNU MP"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "GNU MP 6.2.0"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "gmp"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL "http://www.gnu.org/software/gmp/"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "6.2.0"
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#define RETSIGTYPE void
+
+/* The size of `mp_limb_t', as computed by sizeof. */
+#define SIZEOF_MP_LIMB_T 8
+
+/* The size of `unsigned', as computed by sizeof. */
+#define SIZEOF_UNSIGNED 4
+
+/* The size of `unsigned long', as computed by sizeof. */
+#define SIZEOF_UNSIGNED_LONG 8
+
+/* The size of `unsigned short', as computed by sizeof. */
+#define SIZEOF_UNSIGNED_SHORT 2
+
+/* The size of `void *', as computed by sizeof. */
+#define SIZEOF_VOID_P 8
+
+/* Define to 1 if sscanf requires writable inputs */
+/* #undef SSCANF_WRITABLE_INPUT */
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Maximum size the tune program can test for SQR_TOOM2_THRESHOLD */
+/* #undef TUNE_SQR_TOOM2_MAX */
+
+/* Version number of package */
+#define VERSION "6.2.0"
+
+/* Define to 1 to enable ASSERT checking, per --enable-assert */
+/* #undef WANT_ASSERT */
+
+/* Define to 1 to enable GMP_CPU_TYPE faking cpuid, per --enable-fake-cpuid */
+/* #undef WANT_FAKE_CPUID */
+
+/* Define to 1 when building a fat binary. */
+/* #undef WANT_FAT_BINARY */
+
+/* Define to 1 to enable FFTs for multiplication, per --enable-fft */
+#define WANT_FFT 1
+
+/* Define to 1 to enable old mpn_mul_fft_full for multiplication, per
+   --enable-old-fft-full */
+/* #undef WANT_OLD_FFT_FULL */
+
+/* Define to 1 if --enable-profiling=gprof */
+/* #undef WANT_PROFILING_GPROF */
+
+/* Define to 1 if --enable-profiling=instrument */
+/* #undef WANT_PROFILING_INSTRUMENT */
+
+/* Define to 1 if --enable-profiling=prof */
+/* #undef WANT_PROFILING_PROF */
+
+/* Define one of these to 1 for the desired temporary memory allocation
+   method, per --enable-alloca. */
+#define WANT_TMP_ALLOCA 1
+/* #undef WANT_TMP_REENTRANT */
+/* #undef WANT_TMP_NOTREENTRANT */
+/* #undef WANT_TMP_DEBUG */
+
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+   significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+#  define WORDS_BIGENDIAN 1
+# endif
+#else
+# ifndef WORDS_BIGENDIAN
+/* #  undef WORDS_BIGENDIAN */
+# endif
+#endif
+
+/* Define to 1 if the assembler understands the mulx instruction */
+#define X86_ASM_MULX 1
+
+/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
+   `char[]'. */
+#define YYTEXT_POINTER 1
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to the equivalent of the C99 'restrict' keyword, or to
+   nothing if this is not supported.  Do not define if restrict is
+   supported directly.  */
+#define restrict __restrict
+/* Work around a bug in Sun C++: it does not support _Restrict or
+   __restrict__, even though the corresponding Sun C compiler ends up with
+   "#define restrict _Restrict" or "#define restrict __restrict__" in the
+   previous line.  Perhaps some future version of Sun C++ will work with
+   restrict; if so, hopefully it defines __RESTRICT like Sun C does.  */
+#if defined __SUNPRO_CC && !defined __RESTRICT
+# define _Restrict
+# define __restrict__
+#endif
+
+/* Define to empty if the keyword `volatile' does not work. Warning: valid
+   code using `volatile' can become incorrect without. Disable with care. */
+/* #undef volatile */
diff --git a/third_party/gmp/config/x86_64/config.m4 b/third_party/gmp/config/x86_64/config.m4
new file mode 100644
index 0000000..4b58a62
--- /dev/null
+++ b/third_party/gmp/config/x86_64/config.m4
@@ -0,0 +1,38 @@
+dnl config.m4.  Generated automatically by configure.
+changequote(<,>)
+ifdef(<__CONFIG_M4_INCLUDED__>,,<
+define(<CONFIG_TOP_SRCDIR>,<`../.'>)
+define(<WANT_ASSERT>,0)
+define(<WANT_PROFILING>,<`no'>)
+define(<M4WRAP_SPURIOUS>,<no>)
+define(<TEXT>, <.text>)
+define(<DATA>, <.data>)
+define(<LABEL_SUFFIX>, <:>)
+define(<GLOBL>, <.globl>)
+define(<GLOBL_ATTR>, <>)
+define(<GSYM_PREFIX>, <>)
+define(<RODATA>, <	.section	.rodata,"a",@progbits>)
+define(<TYPE>, <.type	$1,@$2>)
+define(<SIZE>, <.size	$1,$2>)
+define(<LSYM_PREFIX>, <.L>)
+define(<W32>, <.long>)
+define(<ALIGN_LOGARITHMIC>,<no>)
+define(<ALIGN_FILL_0x90>,<yes>)
+define(<LINUX>,1)
+define(<SQR_TOOM2_THRESHOLD>,<30>)
+define(<BMOD_1_TO_MOD_1_THRESHOLD>,<22>)
+define(<SIZEOF_UNSIGNED>,<4>)
+define(<GMP_LIMB_BITS>,64)
+define(<GMP_NAIL_BITS>,0)
+define(<GMP_NUMB_BITS>,eval(GMP_LIMB_BITS-GMP_NAIL_BITS))
+>)
+changequote(`,')
+ifdef(`__CONFIG_M4_INCLUDED__',,`
+include(CONFIG_TOP_SRCDIR`/mpn/asm-defs.m4')
+include_mpn(`x86_64/x86_64-defs.m4')
+define_not_for_expansion(`HAVE_HOST_CPU_zen2')
+define_not_for_expansion(`HAVE_ABI_64')
+define_not_for_expansion(`HAVE_LIMB_LITTLE_ENDIAN')
+define_not_for_expansion(`HAVE_DOUBLE_IEEE_LITTLE_ENDIAN')
+')
+define(`__CONFIG_M4_INCLUDED__')
diff --git a/third_party/gmp/config/x86_64/gmp.h b/third_party/gmp/config/x86_64/gmp.h
new file mode 100644
index 0000000..98c0bdd
--- /dev/null
+++ b/third_party/gmp/config/x86_64/gmp.h
@@ -0,0 +1,2336 @@
+/* Definitions for GNU multiple precision functions.   -*- mode: c -*-
+
+Copyright 1991, 1993-1997, 1999-2016, 2020 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#ifndef __GMP_H__
+
+#if defined (__cplusplus)
+#include <iosfwd>   /* for std::istream, std::ostream, std::string */
+#include <cstdio>
+#endif
+
+
+/* Instantiated by configure. */
+#if ! defined (__GMP_WITHIN_CONFIGURE)
+#define __GMP_HAVE_HOST_CPU_FAMILY_power   0
+#define __GMP_HAVE_HOST_CPU_FAMILY_powerpc 0
+#define GMP_LIMB_BITS                      64
+#define GMP_NAIL_BITS                      0
+#endif
+#define GMP_NUMB_BITS     (GMP_LIMB_BITS - GMP_NAIL_BITS)
+#define GMP_NUMB_MASK     ((~ __GMP_CAST (mp_limb_t, 0)) >> GMP_NAIL_BITS)
+#define GMP_NUMB_MAX      GMP_NUMB_MASK
+#define GMP_NAIL_MASK     (~ GMP_NUMB_MASK)
+
+
+#ifndef __GNU_MP__
+#define __GNU_MP__ 6
+
+#include <stddef.h>    /* for size_t */
+#include <limits.h>
+
+/* Instantiated by configure. */
+#if ! defined (__GMP_WITHIN_CONFIGURE)
+/* #undef _LONG_LONG_LIMB */
+#define __GMP_LIBGMP_DLL  0
+#endif
+
+
+/* __GMP_DECLSPEC supports Windows DLL versions of libgmp, and is empty in
+   all other circumstances.
+
+   When compiling objects for libgmp, __GMP_DECLSPEC is an export directive,
+   or when compiling for an application it's an import directive.  The two
+   cases are differentiated by __GMP_WITHIN_GMP defined by the GMP Makefiles
+   (and not defined from an application).
+
+   __GMP_DECLSPEC_XX is similarly used for libgmpxx.  __GMP_WITHIN_GMPXX
+   indicates when building libgmpxx, and in that case libgmpxx functions are
+   exports, but libgmp functions which might get called are imports.
+
+   Libtool DLL_EXPORT define is not used.
+
+   There's no attempt to support GMP built both static and DLL.  Doing so
+   would mean applications would have to tell us which of the two is going
+   to be used when linking, and that seems very tedious and error prone if
+   using GMP by hand, and equally tedious from a package since autoconf and
+   automake don't give much help.
+
+   __GMP_DECLSPEC is required on all documented global functions and
+   variables, the various internals in gmp-impl.h etc can be left unadorned.
+   But internals used by the test programs or speed measuring programs
+   should have __GMP_DECLSPEC, and certainly constants or variables must
+   have it or the wrong address will be resolved.
+
+   In gcc __declspec can go at either the start or end of a prototype.
+
+   In Microsoft C __declspec must go at the start, or after the type like
+   void __declspec(...) *foo()".  There's no __dllexport or anything to
+   guard against someone foolish #defining dllexport.  _export used to be
+   available, but no longer.
+
+   In Borland C _export still exists, but needs to go after the type, like
+   "void _export foo();".  Would have to change the __GMP_DECLSPEC syntax to
+   make use of that.  Probably more trouble than it's worth.  */
+
+#if defined (__GNUC__)
+#define __GMP_DECLSPEC_EXPORT  __declspec(__dllexport__)
+#define __GMP_DECLSPEC_IMPORT  __declspec(__dllimport__)
+#endif
+#if defined (_MSC_VER) || defined (__BORLANDC__)
+#define __GMP_DECLSPEC_EXPORT  __declspec(dllexport)
+#define __GMP_DECLSPEC_IMPORT  __declspec(dllimport)
+#endif
+#ifdef __WATCOMC__
+#define __GMP_DECLSPEC_EXPORT  __export
+#define __GMP_DECLSPEC_IMPORT  __import
+#endif
+#ifdef __IBMC__
+#define __GMP_DECLSPEC_EXPORT  _Export
+#define __GMP_DECLSPEC_IMPORT  _Import
+#endif
+
+#if __GMP_LIBGMP_DLL
+#ifdef __GMP_WITHIN_GMP
+/* compiling to go into a DLL libgmp */
+#define __GMP_DECLSPEC  __GMP_DECLSPEC_EXPORT
+#else
+/* compiling to go into an application which will link to a DLL libgmp */
+#define __GMP_DECLSPEC  __GMP_DECLSPEC_IMPORT
+#endif
+#else
+/* all other cases */
+#define __GMP_DECLSPEC
+#endif
+
+
+#ifdef __GMP_SHORT_LIMB
+typedef unsigned int		mp_limb_t;
+typedef int			mp_limb_signed_t;
+#else
+#ifdef _LONG_LONG_LIMB
+typedef unsigned long long int	mp_limb_t;
+typedef long long int		mp_limb_signed_t;
+#else
+typedef unsigned long int	mp_limb_t;
+typedef long int		mp_limb_signed_t;
+#endif
+#endif
+typedef unsigned long int	mp_bitcnt_t;
+
+/* For reference, note that the name __mpz_struct gets into C++ mangled
+   function names, which means although the "__" suggests an internal, we
+   must leave this name for binary compatibility.  */
+typedef struct
+{
+  int _mp_alloc;		/* Number of *limbs* allocated and pointed
+				   to by the _mp_d field.  */
+  int _mp_size;			/* abs(_mp_size) is the number of limbs the
+				   last field points to.  If _mp_size is
+				   negative this is a negative number.  */
+  mp_limb_t *_mp_d;		/* Pointer to the limbs.  */
+} __mpz_struct;
+
+#endif /* __GNU_MP__ */
+
+
+typedef __mpz_struct MP_INT;    /* gmp 1 source compatibility */
+typedef __mpz_struct mpz_t[1];
+
+typedef mp_limb_t *		mp_ptr;
+typedef const mp_limb_t *	mp_srcptr;
+#if defined (_CRAY) && ! defined (_CRAYMPP)
+/* plain `int' is much faster (48 bits) */
+#define __GMP_MP_SIZE_T_INT     1
+typedef int			mp_size_t;
+typedef int			mp_exp_t;
+#else
+#define __GMP_MP_SIZE_T_INT     0
+typedef long int		mp_size_t;
+typedef long int		mp_exp_t;
+#endif
+
+typedef struct
+{
+  __mpz_struct _mp_num;
+  __mpz_struct _mp_den;
+} __mpq_struct;
+
+typedef __mpq_struct MP_RAT;    /* gmp 1 source compatibility */
+typedef __mpq_struct mpq_t[1];
+
+typedef struct
+{
+  int _mp_prec;			/* Max precision, in number of `mp_limb_t's.
+				   Set by mpf_init and modified by
+				   mpf_set_prec.  The area pointed to by the
+				   _mp_d field contains `prec' + 1 limbs.  */
+  int _mp_size;			/* abs(_mp_size) is the number of limbs the
+				   last field points to.  If _mp_size is
+				   negative this is a negative number.  */
+  mp_exp_t _mp_exp;		/* Exponent, in the base of `mp_limb_t'.  */
+  mp_limb_t *_mp_d;		/* Pointer to the limbs.  */
+} __mpf_struct;
+
+/* typedef __mpf_struct MP_FLOAT; */
+typedef __mpf_struct mpf_t[1];
+
+/* Available random number generation algorithms.  */
+typedef enum
+{
+  GMP_RAND_ALG_DEFAULT = 0,
+  GMP_RAND_ALG_LC = GMP_RAND_ALG_DEFAULT /* Linear congruential.  */
+} gmp_randalg_t;
+
+/* Random state struct.  */
+typedef struct
+{
+  mpz_t _mp_seed;	  /* _mp_d member points to state of the generator. */
+  gmp_randalg_t _mp_alg;  /* Currently unused. */
+  union {
+    void *_mp_lc;         /* Pointer to function pointers structure.  */
+  } _mp_algdata;
+} __gmp_randstate_struct;
+typedef __gmp_randstate_struct gmp_randstate_t[1];
+
+/* Types for function declarations in gmp files.  */
+/* ??? Should not pollute user name space with these ??? */
+typedef const __mpz_struct *mpz_srcptr;
+typedef __mpz_struct *mpz_ptr;
+typedef const __mpf_struct *mpf_srcptr;
+typedef __mpf_struct *mpf_ptr;
+typedef const __mpq_struct *mpq_srcptr;
+typedef __mpq_struct *mpq_ptr;
+
+
+#if __GMP_LIBGMP_DLL
+#ifdef __GMP_WITHIN_GMPXX
+/* compiling to go into a DLL libgmpxx */
+#define __GMP_DECLSPEC_XX  __GMP_DECLSPEC_EXPORT
+#else
+/* compiling to go into a application which will link to a DLL libgmpxx */
+#define __GMP_DECLSPEC_XX  __GMP_DECLSPEC_IMPORT
+#endif
+#else
+/* all other cases */
+#define __GMP_DECLSPEC_XX
+#endif
+
+
+#ifndef __MPN
+#define __MPN(x) __gmpn_##x
+#endif
+
+/* For reference, "defined(EOF)" cannot be used here.  In g++ 2.95.4,
+   <iostream> defines EOF but not FILE.  */
+#if defined (FILE)                                              \
+  || defined (H_STDIO)                                          \
+  || defined (_H_STDIO)               /* AIX */                 \
+  || defined (_STDIO_H)               /* glibc, Sun, SCO */     \
+  || defined (_STDIO_H_)              /* BSD, OSF */            \
+  || defined (__STDIO_H)              /* Borland */             \
+  || defined (__STDIO_H__)            /* IRIX */                \
+  || defined (_STDIO_INCLUDED)        /* HPUX */                \
+  || defined (__dj_include_stdio_h_)  /* DJGPP */               \
+  || defined (_FILE_DEFINED)          /* Microsoft */           \
+  || defined (__STDIO__)              /* Apple MPW MrC */       \
+  || defined (_MSL_STDIO_H)           /* Metrowerks */          \
+  || defined (_STDIO_H_INCLUDED)      /* QNX4 */		\
+  || defined (_ISO_STDIO_ISO_H)       /* Sun C++ */		\
+  || defined (__STDIO_LOADED)         /* VMS */			\
+  || defined (__DEFINED_FILE)         /* musl */
+#define _GMP_H_HAVE_FILE 1
+#endif
+
+/* In ISO C, if a prototype involving "struct obstack *" is given without
+   that structure defined, then the struct is scoped down to just the
+   prototype, causing a conflict if it's subsequently defined for real.  So
+   only give prototypes if we've got obstack.h.  */
+#if defined (_OBSTACK_H)   /* glibc <obstack.h> */
+#define _GMP_H_HAVE_OBSTACK 1
+#endif
+
+/* The prototypes for gmp_vprintf etc are provided only if va_list is defined,
+   via an application having included <stdarg.h>.  Usually va_list is a typedef
+   so can't be tested directly, but C99 specifies that va_start is a macro.
+
+   <stdio.h> will define some sort of va_list for vprintf and vfprintf, but
+   let's not bother trying to use that since it's not standard and since
+   application uses for gmp_vprintf etc will almost certainly require the
+   whole <stdarg.h> anyway.  */
+
+#ifdef va_start
+#define _GMP_H_HAVE_VA_LIST 1
+#endif
+
+/* Test for gcc >= maj.min, as per __GNUC_PREREQ in glibc */
+#if defined (__GNUC__) && defined (__GNUC_MINOR__)
+#define __GMP_GNUC_PREREQ(maj, min) \
+  ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
+#else
+#define __GMP_GNUC_PREREQ(maj, min)  0
+#endif
+
+/* "pure" is in gcc 2.96 and up, see "(gcc)Function Attributes".  Basically
+   it means a function does nothing but examine its arguments and memory
+   (global or via arguments) to generate a return value, but changes nothing
+   and has no side-effects.  __GMP_NO_ATTRIBUTE_CONST_PURE lets
+   tune/common.c etc turn this off when trying to write timing loops.  */
+#if __GMP_GNUC_PREREQ (2,96) && ! defined (__GMP_NO_ATTRIBUTE_CONST_PURE)
+#define __GMP_ATTRIBUTE_PURE   __attribute__ ((__pure__))
+#else
+#define __GMP_ATTRIBUTE_PURE
+#endif
+
+
+/* __GMP_CAST allows us to use static_cast in C++, so our macros are clean
+   to "g++ -Wold-style-cast".
+
+   Casts in "extern inline" code within an extern "C" block don't induce
+   these warnings, so __GMP_CAST only needs to be used on documented
+   macros.  */
+
+#ifdef __cplusplus
+#define __GMP_CAST(type, expr)  (static_cast<type> (expr))
+#else
+#define __GMP_CAST(type, expr)  ((type) (expr))
+#endif
+
+
+/* An empty "throw ()" means the function doesn't throw any C++ exceptions,
+   this can save some stack frame info in applications.
+
+   Currently it's given only on functions which never divide-by-zero etc,
+   don't allocate memory, and are expected to never need to allocate memory.
+   This leaves open the possibility of a C++ throw from a future GMP
+   exceptions scheme.
+
+   mpz_set_ui etc are omitted to leave open the lazy allocation scheme
+   described in doc/tasks.html.  mpz_get_d etc are omitted to leave open
+   exceptions for float overflows.
+
+   Note that __GMP_NOTHROW must be given on any inlines the same as on their
+   prototypes (for g++ at least, where they're used together).  Note also
+   that g++ 3.0 demands that __GMP_NOTHROW is before other attributes like
+   __GMP_ATTRIBUTE_PURE.  */
+
+#if defined (__cplusplus)
+#if __cplusplus >= 201103L
+#define __GMP_NOTHROW  noexcept
+#else
+#define __GMP_NOTHROW  throw ()
+#endif
+#else
+#define __GMP_NOTHROW
+#endif
+
+
+/* PORTME: What other compilers have a useful "extern inline"?  "static
+   inline" would be an acceptable substitute if the compiler (or linker)
+   discards unused statics.  */
+
+ /* gcc has __inline__ in all modes, including strict ansi.  Give a prototype
+    for an inline too, so as to correctly specify "dllimport" on windows, in
+    case the function is called rather than inlined.
+    GCC 4.3 and above with -std=c99 or -std=gnu99 implements ISO C99
+    inline semantics, unless -fgnu89-inline is used.  */
+#ifdef __GNUC__
+#if (defined __GNUC_STDC_INLINE__) || (__GNUC__ == 4 && __GNUC_MINOR__ == 2) \
+  || (defined __GNUC_GNU_INLINE__ && defined __cplusplus)
+#define __GMP_EXTERN_INLINE extern __inline__ __attribute__ ((__gnu_inline__))
+#else
+#define __GMP_EXTERN_INLINE      extern __inline__
+#endif
+#define __GMP_INLINE_PROTOTYPES  1
+#endif
+
+/* DEC C (eg. version 5.9) supports "static __inline foo()", even in -std1
+   strict ANSI mode.  Inlining is done even when not optimizing (ie. -O0
+   mode, which is the default), but an unnecessary local copy of foo is
+   emitted unless -O is used.  "extern __inline" is accepted, but the
+   "extern" appears to be ignored, ie. it becomes a plain global function
+   but which is inlined within its file.  Don't know if all old versions of
+   DEC C supported __inline, but as a start let's do the right thing for
+   current versions.  */
+#ifdef __DECC
+#define __GMP_EXTERN_INLINE  static __inline
+#endif
+
+/* SCO OpenUNIX 8 cc supports "static inline foo()" but not in -Xc strict
+   ANSI mode (__STDC__ is 1 in that mode).  Inlining only actually takes
+   place under -O.  Without -O "foo" seems to be emitted whether it's used
+   or not, which is wasteful.  "extern inline foo()" isn't useful, the
+   "extern" is apparently ignored, so foo is inlined if possible but also
+   emitted as a global, which causes multiple definition errors when
+   building a shared libgmp.  */
+#ifdef __SCO_VERSION__
+#if __SCO_VERSION__ > 400000000 && __STDC__ != 1 \
+  && ! defined (__GMP_EXTERN_INLINE)
+#define __GMP_EXTERN_INLINE  static inline
+#endif
+#endif
+
+/* Microsoft's C compiler accepts __inline */
+#ifdef _MSC_VER
+#define __GMP_EXTERN_INLINE  __inline
+#endif
+
+/* Recent enough Sun C compilers want "inline" */
+#if defined (__SUNPRO_C) && __SUNPRO_C >= 0x560 \
+  && ! defined (__GMP_EXTERN_INLINE)
+#define __GMP_EXTERN_INLINE  inline
+#endif
+
+/* Somewhat older Sun C compilers want "static inline" */
+#if defined (__SUNPRO_C) && __SUNPRO_C >= 0x540 \
+  && ! defined (__GMP_EXTERN_INLINE)
+#define __GMP_EXTERN_INLINE  static inline
+#endif
+
+
+/* C++ always has "inline" and since it's a normal feature the linker should
+   discard duplicate non-inlined copies, or if it doesn't then that's a
+   problem for everyone, not just GMP.  */
+#if defined (__cplusplus) && ! defined (__GMP_EXTERN_INLINE)
+#define __GMP_EXTERN_INLINE  inline
+#endif
+
+/* Don't do any inlining within a configure run, since if the compiler ends
+   up emitting copies of the code into the object file it can end up
+   demanding the various support routines (like mpn_popcount) for linking,
+   making the "alloca" test and perhaps others fail.  And on hppa ia64 a
+   pre-release gcc 3.2 was seen not respecting the "extern" in "extern
+   __inline__", triggering this problem too.  */
+#if defined (__GMP_WITHIN_CONFIGURE) && ! __GMP_WITHIN_CONFIGURE_INLINE
+#undef __GMP_EXTERN_INLINE
+#endif
+
+/* By default, don't give a prototype when there's going to be an inline
+   version.  Note in particular that Cray C++ objects to the combination of
+   prototype and inline.  */
+#ifdef __GMP_EXTERN_INLINE
+#ifndef __GMP_INLINE_PROTOTYPES
+#define __GMP_INLINE_PROTOTYPES  0
+#endif
+#else
+#define __GMP_INLINE_PROTOTYPES  1
+#endif
+
+
+#define __GMP_ABS(x)   ((x) >= 0 ? (x) : -(x))
+#define __GMP_MAX(h,i) ((h) > (i) ? (h) : (i))
+
+
+/* __builtin_expect is in gcc 3.0, and not in 2.95. */
+#if __GMP_GNUC_PREREQ (3,0)
+#define __GMP_LIKELY(cond)    __builtin_expect ((cond) != 0, 1)
+#define __GMP_UNLIKELY(cond)  __builtin_expect ((cond) != 0, 0)
+#else
+#define __GMP_LIKELY(cond)    (cond)
+#define __GMP_UNLIKELY(cond)  (cond)
+#endif
+
+#ifdef _CRAY
+#define __GMP_CRAY_Pragma(str)  _Pragma (str)
+#else
+#define __GMP_CRAY_Pragma(str)
+#endif
+
+
+/* Allow direct user access to numerator and denominator of an mpq_t object.  */
+#define mpq_numref(Q) (&((Q)->_mp_num))
+#define mpq_denref(Q) (&((Q)->_mp_den))
+
+
+#if defined (__cplusplus)
+extern "C" {
+using std::FILE;
+#endif
+
+#define mp_set_memory_functions __gmp_set_memory_functions
+__GMP_DECLSPEC void mp_set_memory_functions (void *(*) (size_t),
+				      void *(*) (void *, size_t, size_t),
+				      void (*) (void *, size_t)) __GMP_NOTHROW;
+
+#define mp_get_memory_functions __gmp_get_memory_functions
+__GMP_DECLSPEC void mp_get_memory_functions (void *(**) (size_t),
+				      void *(**) (void *, size_t, size_t),
+				      void (**) (void *, size_t)) __GMP_NOTHROW;
+
+#define mp_bits_per_limb __gmp_bits_per_limb
+__GMP_DECLSPEC extern const int mp_bits_per_limb;
+
+#define gmp_errno __gmp_errno
+__GMP_DECLSPEC extern int gmp_errno;
+
+#define gmp_version __gmp_version
+__GMP_DECLSPEC extern const char * const gmp_version;
+
+
+/**************** Random number routines.  ****************/
+
+/* obsolete */
+#define gmp_randinit __gmp_randinit
+__GMP_DECLSPEC void gmp_randinit (gmp_randstate_t, gmp_randalg_t, ...);
+
+#define gmp_randinit_default __gmp_randinit_default
+__GMP_DECLSPEC void gmp_randinit_default (gmp_randstate_t);
+
+#define gmp_randinit_lc_2exp __gmp_randinit_lc_2exp
+__GMP_DECLSPEC void gmp_randinit_lc_2exp (gmp_randstate_t, mpz_srcptr, unsigned long int, mp_bitcnt_t);
+
+#define gmp_randinit_lc_2exp_size __gmp_randinit_lc_2exp_size
+__GMP_DECLSPEC int gmp_randinit_lc_2exp_size (gmp_randstate_t, mp_bitcnt_t);
+
+#define gmp_randinit_mt __gmp_randinit_mt
+__GMP_DECLSPEC void gmp_randinit_mt (gmp_randstate_t);
+
+#define gmp_randinit_set __gmp_randinit_set
+__GMP_DECLSPEC void gmp_randinit_set (gmp_randstate_t, const __gmp_randstate_struct *);
+
+#define gmp_randseed __gmp_randseed
+__GMP_DECLSPEC void gmp_randseed (gmp_randstate_t, mpz_srcptr);
+
+#define gmp_randseed_ui __gmp_randseed_ui
+__GMP_DECLSPEC void gmp_randseed_ui (gmp_randstate_t, unsigned long int);
+
+#define gmp_randclear __gmp_randclear
+__GMP_DECLSPEC void gmp_randclear (gmp_randstate_t);
+
+#define gmp_urandomb_ui __gmp_urandomb_ui
+__GMP_DECLSPEC unsigned long gmp_urandomb_ui (gmp_randstate_t, unsigned long);
+
+#define gmp_urandomm_ui __gmp_urandomm_ui
+__GMP_DECLSPEC unsigned long gmp_urandomm_ui (gmp_randstate_t, unsigned long);
+
+
+/**************** Formatted output routines.  ****************/
+
+#define gmp_asprintf __gmp_asprintf
+__GMP_DECLSPEC int gmp_asprintf (char **, const char *, ...);
+
+#define gmp_fprintf __gmp_fprintf
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC int gmp_fprintf (FILE *, const char *, ...);
+#endif
+
+#define gmp_obstack_printf __gmp_obstack_printf
+#if defined (_GMP_H_HAVE_OBSTACK)
+__GMP_DECLSPEC int gmp_obstack_printf (struct obstack *, const char *, ...);
+#endif
+
+#define gmp_obstack_vprintf __gmp_obstack_vprintf
+#if defined (_GMP_H_HAVE_OBSTACK) && defined (_GMP_H_HAVE_VA_LIST)
+__GMP_DECLSPEC int gmp_obstack_vprintf (struct obstack *, const char *, va_list);
+#endif
+
+#define gmp_printf __gmp_printf
+__GMP_DECLSPEC int gmp_printf (const char *, ...);
+
+#define gmp_snprintf __gmp_snprintf
+__GMP_DECLSPEC int gmp_snprintf (char *, size_t, const char *, ...);
+
+#define gmp_sprintf __gmp_sprintf
+__GMP_DECLSPEC int gmp_sprintf (char *, const char *, ...);
+
+#define gmp_vasprintf __gmp_vasprintf
+#if defined (_GMP_H_HAVE_VA_LIST)
+__GMP_DECLSPEC int gmp_vasprintf (char **, const char *, va_list);
+#endif
+
+#define gmp_vfprintf __gmp_vfprintf
+#if defined (_GMP_H_HAVE_FILE) && defined (_GMP_H_HAVE_VA_LIST)
+__GMP_DECLSPEC int gmp_vfprintf (FILE *, const char *, va_list);
+#endif
+
+#define gmp_vprintf __gmp_vprintf
+#if defined (_GMP_H_HAVE_VA_LIST)
+__GMP_DECLSPEC int gmp_vprintf (const char *, va_list);
+#endif
+
+#define gmp_vsnprintf __gmp_vsnprintf
+#if defined (_GMP_H_HAVE_VA_LIST)
+__GMP_DECLSPEC int gmp_vsnprintf (char *, size_t, const char *, va_list);
+#endif
+
+#define gmp_vsprintf __gmp_vsprintf
+#if defined (_GMP_H_HAVE_VA_LIST)
+__GMP_DECLSPEC int gmp_vsprintf (char *, const char *, va_list);
+#endif
+
+
+/**************** Formatted input routines.  ****************/
+
+#define gmp_fscanf __gmp_fscanf
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC int gmp_fscanf (FILE *, const char *, ...);
+#endif
+
+#define gmp_scanf __gmp_scanf
+__GMP_DECLSPEC int gmp_scanf (const char *, ...);
+
+#define gmp_sscanf __gmp_sscanf
+__GMP_DECLSPEC int gmp_sscanf (const char *, const char *, ...);
+
+#define gmp_vfscanf __gmp_vfscanf
+#if defined (_GMP_H_HAVE_FILE) && defined (_GMP_H_HAVE_VA_LIST)
+__GMP_DECLSPEC int gmp_vfscanf (FILE *, const char *, va_list);
+#endif
+
+#define gmp_vscanf __gmp_vscanf
+#if defined (_GMP_H_HAVE_VA_LIST)
+__GMP_DECLSPEC int gmp_vscanf (const char *, va_list);
+#endif
+
+#define gmp_vsscanf __gmp_vsscanf
+#if defined (_GMP_H_HAVE_VA_LIST)
+__GMP_DECLSPEC int gmp_vsscanf (const char *, const char *, va_list);
+#endif
+
+
+/**************** Integer (i.e. Z) routines.  ****************/
+
+#define _mpz_realloc __gmpz_realloc
+#define mpz_realloc __gmpz_realloc
+__GMP_DECLSPEC void *_mpz_realloc (mpz_ptr, mp_size_t);
+
+#define mpz_abs __gmpz_abs
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_abs)
+__GMP_DECLSPEC void mpz_abs (mpz_ptr, mpz_srcptr);
+#endif
+
+#define mpz_add __gmpz_add
+__GMP_DECLSPEC void mpz_add (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_add_ui __gmpz_add_ui
+__GMP_DECLSPEC void mpz_add_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_addmul __gmpz_addmul
+__GMP_DECLSPEC void mpz_addmul (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_addmul_ui __gmpz_addmul_ui
+__GMP_DECLSPEC void mpz_addmul_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_and __gmpz_and
+__GMP_DECLSPEC void mpz_and (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_array_init __gmpz_array_init
+__GMP_DECLSPEC void mpz_array_init (mpz_ptr, mp_size_t, mp_size_t);
+
+#define mpz_bin_ui __gmpz_bin_ui
+__GMP_DECLSPEC void mpz_bin_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_bin_uiui __gmpz_bin_uiui
+__GMP_DECLSPEC void mpz_bin_uiui (mpz_ptr, unsigned long int, unsigned long int);
+
+#define mpz_cdiv_q __gmpz_cdiv_q
+__GMP_DECLSPEC void mpz_cdiv_q (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_cdiv_q_2exp __gmpz_cdiv_q_2exp
+__GMP_DECLSPEC void mpz_cdiv_q_2exp (mpz_ptr, mpz_srcptr, mp_bitcnt_t);
+
+#define mpz_cdiv_q_ui __gmpz_cdiv_q_ui
+__GMP_DECLSPEC unsigned long int mpz_cdiv_q_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_cdiv_qr __gmpz_cdiv_qr
+__GMP_DECLSPEC void mpz_cdiv_qr (mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_cdiv_qr_ui __gmpz_cdiv_qr_ui
+__GMP_DECLSPEC unsigned long int mpz_cdiv_qr_ui (mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_cdiv_r __gmpz_cdiv_r
+__GMP_DECLSPEC void mpz_cdiv_r (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_cdiv_r_2exp __gmpz_cdiv_r_2exp
+__GMP_DECLSPEC void mpz_cdiv_r_2exp (mpz_ptr, mpz_srcptr, mp_bitcnt_t);
+
+#define mpz_cdiv_r_ui __gmpz_cdiv_r_ui
+__GMP_DECLSPEC unsigned long int mpz_cdiv_r_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_cdiv_ui __gmpz_cdiv_ui
+__GMP_DECLSPEC unsigned long int mpz_cdiv_ui (mpz_srcptr, unsigned long int) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_clear __gmpz_clear
+__GMP_DECLSPEC void mpz_clear (mpz_ptr);
+
+#define mpz_clears __gmpz_clears
+__GMP_DECLSPEC void mpz_clears (mpz_ptr, ...);
+
+#define mpz_clrbit __gmpz_clrbit
+__GMP_DECLSPEC void mpz_clrbit (mpz_ptr, mp_bitcnt_t);
+
+#define mpz_cmp __gmpz_cmp
+__GMP_DECLSPEC int mpz_cmp (mpz_srcptr, mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_cmp_d __gmpz_cmp_d
+__GMP_DECLSPEC int mpz_cmp_d (mpz_srcptr, double) __GMP_ATTRIBUTE_PURE;
+
+#define _mpz_cmp_si __gmpz_cmp_si
+__GMP_DECLSPEC int _mpz_cmp_si (mpz_srcptr, signed long int) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define _mpz_cmp_ui __gmpz_cmp_ui
+__GMP_DECLSPEC int _mpz_cmp_ui (mpz_srcptr, unsigned long int) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_cmpabs __gmpz_cmpabs
+__GMP_DECLSPEC int mpz_cmpabs (mpz_srcptr, mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_cmpabs_d __gmpz_cmpabs_d
+__GMP_DECLSPEC int mpz_cmpabs_d (mpz_srcptr, double) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_cmpabs_ui __gmpz_cmpabs_ui
+__GMP_DECLSPEC int mpz_cmpabs_ui (mpz_srcptr, unsigned long int) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_com __gmpz_com
+__GMP_DECLSPEC void mpz_com (mpz_ptr, mpz_srcptr);
+
+#define mpz_combit __gmpz_combit
+__GMP_DECLSPEC void mpz_combit (mpz_ptr, mp_bitcnt_t);
+
+#define mpz_congruent_p __gmpz_congruent_p
+__GMP_DECLSPEC int mpz_congruent_p (mpz_srcptr, mpz_srcptr, mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_congruent_2exp_p __gmpz_congruent_2exp_p
+__GMP_DECLSPEC int mpz_congruent_2exp_p (mpz_srcptr, mpz_srcptr, mp_bitcnt_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_congruent_ui_p __gmpz_congruent_ui_p
+__GMP_DECLSPEC int mpz_congruent_ui_p (mpz_srcptr, unsigned long, unsigned long) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_divexact __gmpz_divexact
+__GMP_DECLSPEC void mpz_divexact (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_divexact_ui __gmpz_divexact_ui
+__GMP_DECLSPEC void mpz_divexact_ui (mpz_ptr, mpz_srcptr, unsigned long);
+
+#define mpz_divisible_p __gmpz_divisible_p
+__GMP_DECLSPEC int mpz_divisible_p (mpz_srcptr, mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_divisible_ui_p __gmpz_divisible_ui_p
+__GMP_DECLSPEC int mpz_divisible_ui_p (mpz_srcptr, unsigned long) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_divisible_2exp_p __gmpz_divisible_2exp_p
+__GMP_DECLSPEC int mpz_divisible_2exp_p (mpz_srcptr, mp_bitcnt_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_dump __gmpz_dump
+__GMP_DECLSPEC void mpz_dump (mpz_srcptr);
+
+#define mpz_export __gmpz_export
+__GMP_DECLSPEC void *mpz_export (void *, size_t *, int, size_t, int, size_t, mpz_srcptr);
+
+#define mpz_fac_ui __gmpz_fac_ui
+__GMP_DECLSPEC void mpz_fac_ui (mpz_ptr, unsigned long int);
+
+#define mpz_2fac_ui __gmpz_2fac_ui
+__GMP_DECLSPEC void mpz_2fac_ui (mpz_ptr, unsigned long int);
+
+#define mpz_mfac_uiui __gmpz_mfac_uiui
+__GMP_DECLSPEC void mpz_mfac_uiui (mpz_ptr, unsigned long int, unsigned long int);
+
+#define mpz_primorial_ui __gmpz_primorial_ui
+__GMP_DECLSPEC void mpz_primorial_ui (mpz_ptr, unsigned long int);
+
+#define mpz_fdiv_q __gmpz_fdiv_q
+__GMP_DECLSPEC void mpz_fdiv_q (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_fdiv_q_2exp __gmpz_fdiv_q_2exp
+__GMP_DECLSPEC void mpz_fdiv_q_2exp (mpz_ptr, mpz_srcptr, mp_bitcnt_t);
+
+#define mpz_fdiv_q_ui __gmpz_fdiv_q_ui
+__GMP_DECLSPEC unsigned long int mpz_fdiv_q_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_fdiv_qr __gmpz_fdiv_qr
+__GMP_DECLSPEC void mpz_fdiv_qr (mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_fdiv_qr_ui __gmpz_fdiv_qr_ui
+__GMP_DECLSPEC unsigned long int mpz_fdiv_qr_ui (mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_fdiv_r __gmpz_fdiv_r
+__GMP_DECLSPEC void mpz_fdiv_r (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_fdiv_r_2exp __gmpz_fdiv_r_2exp
+__GMP_DECLSPEC void mpz_fdiv_r_2exp (mpz_ptr, mpz_srcptr, mp_bitcnt_t);
+
+#define mpz_fdiv_r_ui __gmpz_fdiv_r_ui
+__GMP_DECLSPEC unsigned long int mpz_fdiv_r_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_fdiv_ui __gmpz_fdiv_ui
+__GMP_DECLSPEC unsigned long int mpz_fdiv_ui (mpz_srcptr, unsigned long int) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_fib_ui __gmpz_fib_ui
+__GMP_DECLSPEC void mpz_fib_ui (mpz_ptr, unsigned long int);
+
+#define mpz_fib2_ui __gmpz_fib2_ui
+__GMP_DECLSPEC void mpz_fib2_ui (mpz_ptr, mpz_ptr, unsigned long int);
+
+#define mpz_fits_sint_p __gmpz_fits_sint_p
+__GMP_DECLSPEC int mpz_fits_sint_p (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_fits_slong_p __gmpz_fits_slong_p
+__GMP_DECLSPEC int mpz_fits_slong_p (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_fits_sshort_p __gmpz_fits_sshort_p
+__GMP_DECLSPEC int mpz_fits_sshort_p (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_fits_uint_p __gmpz_fits_uint_p
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_fits_uint_p)
+__GMP_DECLSPEC int mpz_fits_uint_p (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpz_fits_ulong_p __gmpz_fits_ulong_p
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_fits_ulong_p)
+__GMP_DECLSPEC int mpz_fits_ulong_p (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpz_fits_ushort_p __gmpz_fits_ushort_p
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_fits_ushort_p)
+__GMP_DECLSPEC int mpz_fits_ushort_p (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpz_gcd __gmpz_gcd
+__GMP_DECLSPEC void mpz_gcd (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_gcd_ui __gmpz_gcd_ui
+__GMP_DECLSPEC unsigned long int mpz_gcd_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_gcdext __gmpz_gcdext
+__GMP_DECLSPEC void mpz_gcdext (mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_get_d __gmpz_get_d
+__GMP_DECLSPEC double mpz_get_d (mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_get_d_2exp __gmpz_get_d_2exp
+__GMP_DECLSPEC double mpz_get_d_2exp (signed long int *, mpz_srcptr);
+
+#define mpz_get_si __gmpz_get_si
+__GMP_DECLSPEC /* signed */ long int mpz_get_si (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_get_str __gmpz_get_str
+__GMP_DECLSPEC char *mpz_get_str (char *, int, mpz_srcptr);
+
+#define mpz_get_ui __gmpz_get_ui
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_get_ui)
+__GMP_DECLSPEC unsigned long int mpz_get_ui (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpz_getlimbn __gmpz_getlimbn
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_getlimbn)
+__GMP_DECLSPEC mp_limb_t mpz_getlimbn (mpz_srcptr, mp_size_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpz_hamdist __gmpz_hamdist
+__GMP_DECLSPEC mp_bitcnt_t mpz_hamdist (mpz_srcptr, mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_import __gmpz_import
+__GMP_DECLSPEC void mpz_import (mpz_ptr, size_t, int, size_t, int, size_t, const void *);
+
+#define mpz_init __gmpz_init
+__GMP_DECLSPEC void mpz_init (mpz_ptr) __GMP_NOTHROW;
+
+#define mpz_init2 __gmpz_init2
+__GMP_DECLSPEC void mpz_init2 (mpz_ptr, mp_bitcnt_t);
+
+#define mpz_inits __gmpz_inits
+__GMP_DECLSPEC void mpz_inits (mpz_ptr, ...) __GMP_NOTHROW;
+
+#define mpz_init_set __gmpz_init_set
+__GMP_DECLSPEC void mpz_init_set (mpz_ptr, mpz_srcptr);
+
+#define mpz_init_set_d __gmpz_init_set_d
+__GMP_DECLSPEC void mpz_init_set_d (mpz_ptr, double);
+
+#define mpz_init_set_si __gmpz_init_set_si
+__GMP_DECLSPEC void mpz_init_set_si (mpz_ptr, signed long int);
+
+#define mpz_init_set_str __gmpz_init_set_str
+__GMP_DECLSPEC int mpz_init_set_str (mpz_ptr, const char *, int);
+
+#define mpz_init_set_ui __gmpz_init_set_ui
+__GMP_DECLSPEC void mpz_init_set_ui (mpz_ptr, unsigned long int);
+
+#define mpz_inp_raw __gmpz_inp_raw
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC size_t mpz_inp_raw (mpz_ptr, FILE *);
+#endif
+
+#define mpz_inp_str __gmpz_inp_str
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC size_t mpz_inp_str (mpz_ptr, FILE *, int);
+#endif
+
+#define mpz_invert __gmpz_invert
+__GMP_DECLSPEC int mpz_invert (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_ior __gmpz_ior
+__GMP_DECLSPEC void mpz_ior (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_jacobi __gmpz_jacobi
+__GMP_DECLSPEC int mpz_jacobi (mpz_srcptr, mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_kronecker mpz_jacobi  /* alias */
+
+#define mpz_kronecker_si __gmpz_kronecker_si
+__GMP_DECLSPEC int mpz_kronecker_si (mpz_srcptr, long) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_kronecker_ui __gmpz_kronecker_ui
+__GMP_DECLSPEC int mpz_kronecker_ui (mpz_srcptr, unsigned long) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_si_kronecker __gmpz_si_kronecker
+__GMP_DECLSPEC int mpz_si_kronecker (long, mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_ui_kronecker __gmpz_ui_kronecker
+__GMP_DECLSPEC int mpz_ui_kronecker (unsigned long, mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_lcm __gmpz_lcm
+__GMP_DECLSPEC void mpz_lcm (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_lcm_ui __gmpz_lcm_ui
+__GMP_DECLSPEC void mpz_lcm_ui (mpz_ptr, mpz_srcptr, unsigned long);
+
+#define mpz_legendre mpz_jacobi  /* alias */
+
+#define mpz_lucnum_ui __gmpz_lucnum_ui
+__GMP_DECLSPEC void mpz_lucnum_ui (mpz_ptr, unsigned long int);
+
+#define mpz_lucnum2_ui __gmpz_lucnum2_ui
+__GMP_DECLSPEC void mpz_lucnum2_ui (mpz_ptr, mpz_ptr, unsigned long int);
+
+#define mpz_millerrabin __gmpz_millerrabin
+__GMP_DECLSPEC int mpz_millerrabin (mpz_srcptr, int) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_mod __gmpz_mod
+__GMP_DECLSPEC void mpz_mod (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_mod_ui mpz_fdiv_r_ui /* same as fdiv_r because divisor unsigned */
+
+#define mpz_mul __gmpz_mul
+__GMP_DECLSPEC void mpz_mul (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_mul_2exp __gmpz_mul_2exp
+__GMP_DECLSPEC void mpz_mul_2exp (mpz_ptr, mpz_srcptr, mp_bitcnt_t);
+
+#define mpz_mul_si __gmpz_mul_si
+__GMP_DECLSPEC void mpz_mul_si (mpz_ptr, mpz_srcptr, long int);
+
+#define mpz_mul_ui __gmpz_mul_ui
+__GMP_DECLSPEC void mpz_mul_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_neg __gmpz_neg
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_neg)
+__GMP_DECLSPEC void mpz_neg (mpz_ptr, mpz_srcptr);
+#endif
+
+#define mpz_nextprime __gmpz_nextprime
+__GMP_DECLSPEC void mpz_nextprime (mpz_ptr, mpz_srcptr);
+
+#define mpz_out_raw __gmpz_out_raw
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC size_t mpz_out_raw (FILE *, mpz_srcptr);
+#endif
+
+#define mpz_out_str __gmpz_out_str
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC size_t mpz_out_str (FILE *, int, mpz_srcptr);
+#endif
+
+#define mpz_perfect_power_p __gmpz_perfect_power_p
+__GMP_DECLSPEC int mpz_perfect_power_p (mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_perfect_square_p __gmpz_perfect_square_p
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_perfect_square_p)
+__GMP_DECLSPEC int mpz_perfect_square_p (mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpz_popcount __gmpz_popcount
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_popcount)
+__GMP_DECLSPEC mp_bitcnt_t mpz_popcount (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpz_pow_ui __gmpz_pow_ui
+__GMP_DECLSPEC void mpz_pow_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_powm __gmpz_powm
+__GMP_DECLSPEC void mpz_powm (mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_powm_sec __gmpz_powm_sec
+__GMP_DECLSPEC void mpz_powm_sec (mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_powm_ui __gmpz_powm_ui
+__GMP_DECLSPEC void mpz_powm_ui (mpz_ptr, mpz_srcptr, unsigned long int, mpz_srcptr);
+
+#define mpz_probab_prime_p __gmpz_probab_prime_p
+__GMP_DECLSPEC int mpz_probab_prime_p (mpz_srcptr, int) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_random __gmpz_random
+__GMP_DECLSPEC void mpz_random (mpz_ptr, mp_size_t);
+
+#define mpz_random2 __gmpz_random2
+__GMP_DECLSPEC void mpz_random2 (mpz_ptr, mp_size_t);
+
+#define mpz_realloc2 __gmpz_realloc2
+__GMP_DECLSPEC void mpz_realloc2 (mpz_ptr, mp_bitcnt_t);
+
+#define mpz_remove __gmpz_remove
+__GMP_DECLSPEC mp_bitcnt_t mpz_remove (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_root __gmpz_root
+__GMP_DECLSPEC int mpz_root (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_rootrem __gmpz_rootrem
+__GMP_DECLSPEC void mpz_rootrem (mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_rrandomb __gmpz_rrandomb
+__GMP_DECLSPEC void mpz_rrandomb (mpz_ptr, gmp_randstate_t, mp_bitcnt_t);
+
+#define mpz_scan0 __gmpz_scan0
+__GMP_DECLSPEC mp_bitcnt_t mpz_scan0 (mpz_srcptr, mp_bitcnt_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_scan1 __gmpz_scan1
+__GMP_DECLSPEC mp_bitcnt_t mpz_scan1 (mpz_srcptr, mp_bitcnt_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_set __gmpz_set
+__GMP_DECLSPEC void mpz_set (mpz_ptr, mpz_srcptr);
+
+#define mpz_set_d __gmpz_set_d
+__GMP_DECLSPEC void mpz_set_d (mpz_ptr, double);
+
+#define mpz_set_f __gmpz_set_f
+__GMP_DECLSPEC void mpz_set_f (mpz_ptr, mpf_srcptr);
+
+#define mpz_set_q __gmpz_set_q
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_set_q)
+__GMP_DECLSPEC void mpz_set_q (mpz_ptr, mpq_srcptr);
+#endif
+
+#define mpz_set_si __gmpz_set_si
+__GMP_DECLSPEC void mpz_set_si (mpz_ptr, signed long int);
+
+#define mpz_set_str __gmpz_set_str
+__GMP_DECLSPEC int mpz_set_str (mpz_ptr, const char *, int);
+
+#define mpz_set_ui __gmpz_set_ui
+__GMP_DECLSPEC void mpz_set_ui (mpz_ptr, unsigned long int);
+
+#define mpz_setbit __gmpz_setbit
+__GMP_DECLSPEC void mpz_setbit (mpz_ptr, mp_bitcnt_t);
+
+#define mpz_size __gmpz_size
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_size)
+__GMP_DECLSPEC size_t mpz_size (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpz_sizeinbase __gmpz_sizeinbase
+__GMP_DECLSPEC size_t mpz_sizeinbase (mpz_srcptr, int) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_sqrt __gmpz_sqrt
+__GMP_DECLSPEC void mpz_sqrt (mpz_ptr, mpz_srcptr);
+
+#define mpz_sqrtrem __gmpz_sqrtrem
+__GMP_DECLSPEC void mpz_sqrtrem (mpz_ptr, mpz_ptr, mpz_srcptr);
+
+#define mpz_sub __gmpz_sub
+__GMP_DECLSPEC void mpz_sub (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_sub_ui __gmpz_sub_ui
+__GMP_DECLSPEC void mpz_sub_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_ui_sub __gmpz_ui_sub
+__GMP_DECLSPEC void mpz_ui_sub (mpz_ptr, unsigned long int, mpz_srcptr);
+
+#define mpz_submul __gmpz_submul
+__GMP_DECLSPEC void mpz_submul (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_submul_ui __gmpz_submul_ui
+__GMP_DECLSPEC void mpz_submul_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_swap __gmpz_swap
+__GMP_DECLSPEC void mpz_swap (mpz_ptr, mpz_ptr) __GMP_NOTHROW;
+
+#define mpz_tdiv_ui __gmpz_tdiv_ui
+__GMP_DECLSPEC unsigned long int mpz_tdiv_ui (mpz_srcptr, unsigned long int) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_tdiv_q __gmpz_tdiv_q
+__GMP_DECLSPEC void mpz_tdiv_q (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_tdiv_q_2exp __gmpz_tdiv_q_2exp
+__GMP_DECLSPEC void mpz_tdiv_q_2exp (mpz_ptr, mpz_srcptr, mp_bitcnt_t);
+
+#define mpz_tdiv_q_ui __gmpz_tdiv_q_ui
+__GMP_DECLSPEC unsigned long int mpz_tdiv_q_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_tdiv_qr __gmpz_tdiv_qr
+__GMP_DECLSPEC void mpz_tdiv_qr (mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_tdiv_qr_ui __gmpz_tdiv_qr_ui
+__GMP_DECLSPEC unsigned long int mpz_tdiv_qr_ui (mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_tdiv_r __gmpz_tdiv_r
+__GMP_DECLSPEC void mpz_tdiv_r (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_tdiv_r_2exp __gmpz_tdiv_r_2exp
+__GMP_DECLSPEC void mpz_tdiv_r_2exp (mpz_ptr, mpz_srcptr, mp_bitcnt_t);
+
+#define mpz_tdiv_r_ui __gmpz_tdiv_r_ui
+__GMP_DECLSPEC unsigned long int mpz_tdiv_r_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_tstbit __gmpz_tstbit
+__GMP_DECLSPEC int mpz_tstbit (mpz_srcptr, mp_bitcnt_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_ui_pow_ui __gmpz_ui_pow_ui
+__GMP_DECLSPEC void mpz_ui_pow_ui (mpz_ptr, unsigned long int, unsigned long int);
+
+#define mpz_urandomb __gmpz_urandomb
+__GMP_DECLSPEC void mpz_urandomb (mpz_ptr, gmp_randstate_t, mp_bitcnt_t);
+
+#define mpz_urandomm __gmpz_urandomm
+__GMP_DECLSPEC void mpz_urandomm (mpz_ptr, gmp_randstate_t, mpz_srcptr);
+
+#define mpz_xor __gmpz_xor
+#define mpz_eor __gmpz_xor
+__GMP_DECLSPEC void mpz_xor (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_limbs_read __gmpz_limbs_read
+__GMP_DECLSPEC mp_srcptr mpz_limbs_read (mpz_srcptr);
+
+#define mpz_limbs_write __gmpz_limbs_write
+__GMP_DECLSPEC mp_ptr mpz_limbs_write (mpz_ptr, mp_size_t);
+
+#define mpz_limbs_modify __gmpz_limbs_modify
+__GMP_DECLSPEC mp_ptr mpz_limbs_modify (mpz_ptr, mp_size_t);
+
+#define mpz_limbs_finish __gmpz_limbs_finish
+__GMP_DECLSPEC void mpz_limbs_finish (mpz_ptr, mp_size_t);
+
+#define mpz_roinit_n __gmpz_roinit_n
+__GMP_DECLSPEC mpz_srcptr mpz_roinit_n (mpz_ptr, mp_srcptr, mp_size_t);
+
+#define MPZ_ROINIT_N(xp, xs) {{0, (xs),(xp) }}
+
+/**************** Rational (i.e. Q) routines.  ****************/
+
+#define mpq_abs __gmpq_abs
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpq_abs)
+__GMP_DECLSPEC void mpq_abs (mpq_ptr, mpq_srcptr);
+#endif
+
+#define mpq_add __gmpq_add
+__GMP_DECLSPEC void mpq_add (mpq_ptr, mpq_srcptr, mpq_srcptr);
+
+#define mpq_canonicalize __gmpq_canonicalize
+__GMP_DECLSPEC void mpq_canonicalize (mpq_ptr);
+
+#define mpq_clear __gmpq_clear
+__GMP_DECLSPEC void mpq_clear (mpq_ptr);
+
+#define mpq_clears __gmpq_clears
+__GMP_DECLSPEC void mpq_clears (mpq_ptr, ...);
+
+#define mpq_cmp __gmpq_cmp
+__GMP_DECLSPEC int mpq_cmp (mpq_srcptr, mpq_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define _mpq_cmp_si __gmpq_cmp_si
+__GMP_DECLSPEC int _mpq_cmp_si (mpq_srcptr, long, unsigned long) __GMP_ATTRIBUTE_PURE;
+
+#define _mpq_cmp_ui __gmpq_cmp_ui
+__GMP_DECLSPEC int _mpq_cmp_ui (mpq_srcptr, unsigned long int, unsigned long int) __GMP_ATTRIBUTE_PURE;
+
+#define mpq_cmp_z __gmpq_cmp_z
+__GMP_DECLSPEC int mpq_cmp_z (mpq_srcptr, mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpq_div __gmpq_div
+__GMP_DECLSPEC void mpq_div (mpq_ptr, mpq_srcptr, mpq_srcptr);
+
+#define mpq_div_2exp __gmpq_div_2exp
+__GMP_DECLSPEC void mpq_div_2exp (mpq_ptr, mpq_srcptr, mp_bitcnt_t);
+
+#define mpq_equal __gmpq_equal
+__GMP_DECLSPEC int mpq_equal (mpq_srcptr, mpq_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpq_get_num __gmpq_get_num
+__GMP_DECLSPEC void mpq_get_num (mpz_ptr, mpq_srcptr);
+
+#define mpq_get_den __gmpq_get_den
+__GMP_DECLSPEC void mpq_get_den (mpz_ptr, mpq_srcptr);
+
+#define mpq_get_d __gmpq_get_d
+__GMP_DECLSPEC double mpq_get_d (mpq_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpq_get_str __gmpq_get_str
+__GMP_DECLSPEC char *mpq_get_str (char *, int, mpq_srcptr);
+
+#define mpq_init __gmpq_init
+__GMP_DECLSPEC void mpq_init (mpq_ptr);
+
+#define mpq_inits __gmpq_inits
+__GMP_DECLSPEC void mpq_inits (mpq_ptr, ...);
+
+#define mpq_inp_str __gmpq_inp_str
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC size_t mpq_inp_str (mpq_ptr, FILE *, int);
+#endif
+
+#define mpq_inv __gmpq_inv
+__GMP_DECLSPEC void mpq_inv (mpq_ptr, mpq_srcptr);
+
+#define mpq_mul __gmpq_mul
+__GMP_DECLSPEC void mpq_mul (mpq_ptr, mpq_srcptr, mpq_srcptr);
+
+#define mpq_mul_2exp __gmpq_mul_2exp
+__GMP_DECLSPEC void mpq_mul_2exp (mpq_ptr, mpq_srcptr, mp_bitcnt_t);
+
+#define mpq_neg __gmpq_neg
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpq_neg)
+__GMP_DECLSPEC void mpq_neg (mpq_ptr, mpq_srcptr);
+#endif
+
+#define mpq_out_str __gmpq_out_str
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC size_t mpq_out_str (FILE *, int, mpq_srcptr);
+#endif
+
+#define mpq_set __gmpq_set
+__GMP_DECLSPEC void mpq_set (mpq_ptr, mpq_srcptr);
+
+#define mpq_set_d __gmpq_set_d
+__GMP_DECLSPEC void mpq_set_d (mpq_ptr, double);
+
+#define mpq_set_den __gmpq_set_den
+__GMP_DECLSPEC void mpq_set_den (mpq_ptr, mpz_srcptr);
+
+#define mpq_set_f __gmpq_set_f
+__GMP_DECLSPEC void mpq_set_f (mpq_ptr, mpf_srcptr);
+
+#define mpq_set_num __gmpq_set_num
+__GMP_DECLSPEC void mpq_set_num (mpq_ptr, mpz_srcptr);
+
+#define mpq_set_si __gmpq_set_si
+__GMP_DECLSPEC void mpq_set_si (mpq_ptr, signed long int, unsigned long int);
+
+#define mpq_set_str __gmpq_set_str
+__GMP_DECLSPEC int mpq_set_str (mpq_ptr, const char *, int);
+
+#define mpq_set_ui __gmpq_set_ui
+__GMP_DECLSPEC void mpq_set_ui (mpq_ptr, unsigned long int, unsigned long int);
+
+#define mpq_set_z __gmpq_set_z
+__GMP_DECLSPEC void mpq_set_z (mpq_ptr, mpz_srcptr);
+
+#define mpq_sub __gmpq_sub
+__GMP_DECLSPEC void mpq_sub (mpq_ptr, mpq_srcptr, mpq_srcptr);
+
+#define mpq_swap __gmpq_swap
+__GMP_DECLSPEC void mpq_swap (mpq_ptr, mpq_ptr) __GMP_NOTHROW;
+
+
+/**************** Float (i.e. F) routines.  ****************/
+
+#define mpf_abs __gmpf_abs
+__GMP_DECLSPEC void mpf_abs (mpf_ptr, mpf_srcptr);
+
+#define mpf_add __gmpf_add
+__GMP_DECLSPEC void mpf_add (mpf_ptr, mpf_srcptr, mpf_srcptr);
+
+#define mpf_add_ui __gmpf_add_ui
+__GMP_DECLSPEC void mpf_add_ui (mpf_ptr, mpf_srcptr, unsigned long int);
+#define mpf_ceil __gmpf_ceil
+__GMP_DECLSPEC void mpf_ceil (mpf_ptr, mpf_srcptr);
+
+#define mpf_clear __gmpf_clear
+__GMP_DECLSPEC void mpf_clear (mpf_ptr);
+
+#define mpf_clears __gmpf_clears
+__GMP_DECLSPEC void mpf_clears (mpf_ptr, ...);
+
+#define mpf_cmp __gmpf_cmp
+__GMP_DECLSPEC int mpf_cmp (mpf_srcptr, mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_cmp_z __gmpf_cmp_z
+__GMP_DECLSPEC int mpf_cmp_z (mpf_srcptr, mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_cmp_d __gmpf_cmp_d
+__GMP_DECLSPEC int mpf_cmp_d (mpf_srcptr, double) __GMP_ATTRIBUTE_PURE;
+
+#define mpf_cmp_si __gmpf_cmp_si
+__GMP_DECLSPEC int mpf_cmp_si (mpf_srcptr, signed long int) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_cmp_ui __gmpf_cmp_ui
+__GMP_DECLSPEC int mpf_cmp_ui (mpf_srcptr, unsigned long int) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_div __gmpf_div
+__GMP_DECLSPEC void mpf_div (mpf_ptr, mpf_srcptr, mpf_srcptr);
+
+#define mpf_div_2exp __gmpf_div_2exp
+__GMP_DECLSPEC void mpf_div_2exp (mpf_ptr, mpf_srcptr, mp_bitcnt_t);
+
+#define mpf_div_ui __gmpf_div_ui
+__GMP_DECLSPEC void mpf_div_ui (mpf_ptr, mpf_srcptr, unsigned long int);
+
+#define mpf_dump __gmpf_dump
+__GMP_DECLSPEC void mpf_dump (mpf_srcptr);
+
+#define mpf_eq __gmpf_eq
+__GMP_DECLSPEC int mpf_eq (mpf_srcptr, mpf_srcptr, mp_bitcnt_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpf_fits_sint_p __gmpf_fits_sint_p
+__GMP_DECLSPEC int mpf_fits_sint_p (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_fits_slong_p __gmpf_fits_slong_p
+__GMP_DECLSPEC int mpf_fits_slong_p (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_fits_sshort_p __gmpf_fits_sshort_p
+__GMP_DECLSPEC int mpf_fits_sshort_p (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_fits_uint_p __gmpf_fits_uint_p
+__GMP_DECLSPEC int mpf_fits_uint_p (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_fits_ulong_p __gmpf_fits_ulong_p
+__GMP_DECLSPEC int mpf_fits_ulong_p (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_fits_ushort_p __gmpf_fits_ushort_p
+__GMP_DECLSPEC int mpf_fits_ushort_p (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_floor __gmpf_floor
+__GMP_DECLSPEC void mpf_floor (mpf_ptr, mpf_srcptr);
+
+#define mpf_get_d __gmpf_get_d
+__GMP_DECLSPEC double mpf_get_d (mpf_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpf_get_d_2exp __gmpf_get_d_2exp
+__GMP_DECLSPEC double mpf_get_d_2exp (signed long int *, mpf_srcptr);
+
+#define mpf_get_default_prec __gmpf_get_default_prec
+__GMP_DECLSPEC mp_bitcnt_t mpf_get_default_prec (void) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_get_prec __gmpf_get_prec
+__GMP_DECLSPEC mp_bitcnt_t mpf_get_prec (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_get_si __gmpf_get_si
+__GMP_DECLSPEC long mpf_get_si (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_get_str __gmpf_get_str
+__GMP_DECLSPEC char *mpf_get_str (char *, mp_exp_t *, int, size_t, mpf_srcptr);
+
+#define mpf_get_ui __gmpf_get_ui
+__GMP_DECLSPEC unsigned long mpf_get_ui (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_init __gmpf_init
+__GMP_DECLSPEC void mpf_init (mpf_ptr);
+
+#define mpf_init2 __gmpf_init2
+__GMP_DECLSPEC void mpf_init2 (mpf_ptr, mp_bitcnt_t);
+
+#define mpf_inits __gmpf_inits
+__GMP_DECLSPEC void mpf_inits (mpf_ptr, ...);
+
+#define mpf_init_set __gmpf_init_set
+__GMP_DECLSPEC void mpf_init_set (mpf_ptr, mpf_srcptr);
+
+#define mpf_init_set_d __gmpf_init_set_d
+__GMP_DECLSPEC void mpf_init_set_d (mpf_ptr, double);
+
+#define mpf_init_set_si __gmpf_init_set_si
+__GMP_DECLSPEC void mpf_init_set_si (mpf_ptr, signed long int);
+
+#define mpf_init_set_str __gmpf_init_set_str
+__GMP_DECLSPEC int mpf_init_set_str (mpf_ptr, const char *, int);
+
+#define mpf_init_set_ui __gmpf_init_set_ui
+__GMP_DECLSPEC void mpf_init_set_ui (mpf_ptr, unsigned long int);
+
+#define mpf_inp_str __gmpf_inp_str
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC size_t mpf_inp_str (mpf_ptr, FILE *, int);
+#endif
+
+#define mpf_integer_p __gmpf_integer_p
+__GMP_DECLSPEC int mpf_integer_p (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_mul __gmpf_mul
+__GMP_DECLSPEC void mpf_mul (mpf_ptr, mpf_srcptr, mpf_srcptr);
+
+#define mpf_mul_2exp __gmpf_mul_2exp
+__GMP_DECLSPEC void mpf_mul_2exp (mpf_ptr, mpf_srcptr, mp_bitcnt_t);
+
+#define mpf_mul_ui __gmpf_mul_ui
+__GMP_DECLSPEC void mpf_mul_ui (mpf_ptr, mpf_srcptr, unsigned long int);
+
+#define mpf_neg __gmpf_neg
+__GMP_DECLSPEC void mpf_neg (mpf_ptr, mpf_srcptr);
+
+#define mpf_out_str __gmpf_out_str
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC size_t mpf_out_str (FILE *, int, size_t, mpf_srcptr);
+#endif
+
+#define mpf_pow_ui __gmpf_pow_ui
+__GMP_DECLSPEC void mpf_pow_ui (mpf_ptr, mpf_srcptr, unsigned long int);
+
+#define mpf_random2 __gmpf_random2
+__GMP_DECLSPEC void mpf_random2 (mpf_ptr, mp_size_t, mp_exp_t);
+
+#define mpf_reldiff __gmpf_reldiff
+__GMP_DECLSPEC void mpf_reldiff (mpf_ptr, mpf_srcptr, mpf_srcptr);
+
+#define mpf_set __gmpf_set
+__GMP_DECLSPEC void mpf_set (mpf_ptr, mpf_srcptr);
+
+#define mpf_set_d __gmpf_set_d
+__GMP_DECLSPEC void mpf_set_d (mpf_ptr, double);
+
+#define mpf_set_default_prec __gmpf_set_default_prec
+__GMP_DECLSPEC void mpf_set_default_prec (mp_bitcnt_t) __GMP_NOTHROW;
+
+#define mpf_set_prec __gmpf_set_prec
+__GMP_DECLSPEC void mpf_set_prec (mpf_ptr, mp_bitcnt_t);
+
+#define mpf_set_prec_raw __gmpf_set_prec_raw
+__GMP_DECLSPEC void mpf_set_prec_raw (mpf_ptr, mp_bitcnt_t) __GMP_NOTHROW;
+
+#define mpf_set_q __gmpf_set_q
+__GMP_DECLSPEC void mpf_set_q (mpf_ptr, mpq_srcptr);
+
+#define mpf_set_si __gmpf_set_si
+__GMP_DECLSPEC void mpf_set_si (mpf_ptr, signed long int);
+
+#define mpf_set_str __gmpf_set_str
+__GMP_DECLSPEC int mpf_set_str (mpf_ptr, const char *, int);
+
+#define mpf_set_ui __gmpf_set_ui
+__GMP_DECLSPEC void mpf_set_ui (mpf_ptr, unsigned long int);
+
+#define mpf_set_z __gmpf_set_z
+__GMP_DECLSPEC void mpf_set_z (mpf_ptr, mpz_srcptr);
+
+#define mpf_size __gmpf_size
+__GMP_DECLSPEC size_t mpf_size (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_sqrt __gmpf_sqrt
+__GMP_DECLSPEC void mpf_sqrt (mpf_ptr, mpf_srcptr);
+
+#define mpf_sqrt_ui __gmpf_sqrt_ui
+__GMP_DECLSPEC void mpf_sqrt_ui (mpf_ptr, unsigned long int);
+
+#define mpf_sub __gmpf_sub
+__GMP_DECLSPEC void mpf_sub (mpf_ptr, mpf_srcptr, mpf_srcptr);
+
+#define mpf_sub_ui __gmpf_sub_ui
+__GMP_DECLSPEC void mpf_sub_ui (mpf_ptr, mpf_srcptr, unsigned long int);
+
+#define mpf_swap __gmpf_swap
+__GMP_DECLSPEC void mpf_swap (mpf_ptr, mpf_ptr) __GMP_NOTHROW;
+
+#define mpf_trunc __gmpf_trunc
+__GMP_DECLSPEC void mpf_trunc (mpf_ptr, mpf_srcptr);
+
+#define mpf_ui_div __gmpf_ui_div
+__GMP_DECLSPEC void mpf_ui_div (mpf_ptr, unsigned long int, mpf_srcptr);
+
+#define mpf_ui_sub __gmpf_ui_sub
+__GMP_DECLSPEC void mpf_ui_sub (mpf_ptr, unsigned long int, mpf_srcptr);
+
+#define mpf_urandomb __gmpf_urandomb
+__GMP_DECLSPEC void mpf_urandomb (mpf_t, gmp_randstate_t, mp_bitcnt_t);
+
+
+/************ Low level positive-integer (i.e. N) routines.  ************/
+
+/* This is ugly, but we need to make user calls reach the prefixed function. */
+
+#define mpn_add __MPN(add)
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_add)
+__GMP_DECLSPEC mp_limb_t mpn_add (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+#endif
+
+#define mpn_add_1 __MPN(add_1)
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_add_1)
+__GMP_DECLSPEC mp_limb_t mpn_add_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t) __GMP_NOTHROW;
+#endif
+
+#define mpn_add_n __MPN(add_n)
+__GMP_DECLSPEC mp_limb_t mpn_add_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+
+#define mpn_addmul_1 __MPN(addmul_1)
+__GMP_DECLSPEC mp_limb_t mpn_addmul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_cmp __MPN(cmp)
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_cmp)
+__GMP_DECLSPEC int mpn_cmp (mp_srcptr, mp_srcptr, mp_size_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpn_zero_p __MPN(zero_p)
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_zero_p)
+__GMP_DECLSPEC int mpn_zero_p (mp_srcptr, mp_size_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpn_divexact_1 __MPN(divexact_1)
+__GMP_DECLSPEC void mpn_divexact_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_divexact_by3(dst,src,size) \
+  mpn_divexact_by3c (dst, src, size, __GMP_CAST (mp_limb_t, 0))
+
+#define mpn_divexact_by3c __MPN(divexact_by3c)
+__GMP_DECLSPEC mp_limb_t mpn_divexact_by3c (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_divmod_1(qp,np,nsize,dlimb) \
+  mpn_divrem_1 (qp, __GMP_CAST (mp_size_t, 0), np, nsize, dlimb)
+
+#define mpn_divrem __MPN(divrem)
+__GMP_DECLSPEC mp_limb_t mpn_divrem (mp_ptr, mp_size_t, mp_ptr, mp_size_t, mp_srcptr, mp_size_t);
+
+#define mpn_divrem_1 __MPN(divrem_1)
+__GMP_DECLSPEC mp_limb_t mpn_divrem_1 (mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_divrem_2 __MPN(divrem_2)
+__GMP_DECLSPEC mp_limb_t mpn_divrem_2 (mp_ptr, mp_size_t, mp_ptr, mp_size_t, mp_srcptr);
+
+#define mpn_div_qr_1 __MPN(div_qr_1)
+__GMP_DECLSPEC mp_limb_t mpn_div_qr_1 (mp_ptr, mp_limb_t *, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_div_qr_2 __MPN(div_qr_2)
+__GMP_DECLSPEC mp_limb_t mpn_div_qr_2 (mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+
+#define mpn_gcd __MPN(gcd)
+__GMP_DECLSPEC mp_size_t mpn_gcd (mp_ptr, mp_ptr, mp_size_t, mp_ptr, mp_size_t);
+
+#define mpn_gcd_11 __MPN(gcd_11)
+__GMP_DECLSPEC mp_limb_t mpn_gcd_11 (mp_limb_t, mp_limb_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_gcd_1 __MPN(gcd_1)
+__GMP_DECLSPEC mp_limb_t mpn_gcd_1 (mp_srcptr, mp_size_t, mp_limb_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_gcdext_1 __MPN(gcdext_1)
+__GMP_DECLSPEC mp_limb_t mpn_gcdext_1 (mp_limb_signed_t *, mp_limb_signed_t *, mp_limb_t, mp_limb_t);
+
+#define mpn_gcdext __MPN(gcdext)
+__GMP_DECLSPEC mp_size_t mpn_gcdext (mp_ptr, mp_ptr, mp_size_t *, mp_ptr, mp_size_t, mp_ptr, mp_size_t);
+
+#define mpn_get_str __MPN(get_str)
+__GMP_DECLSPEC size_t mpn_get_str (unsigned char *, int, mp_ptr, mp_size_t);
+
+#define mpn_hamdist __MPN(hamdist)
+__GMP_DECLSPEC mp_bitcnt_t mpn_hamdist (mp_srcptr, mp_srcptr, mp_size_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpn_lshift __MPN(lshift)
+__GMP_DECLSPEC mp_limb_t mpn_lshift (mp_ptr, mp_srcptr, mp_size_t, unsigned int);
+
+#define mpn_mod_1 __MPN(mod_1)
+__GMP_DECLSPEC mp_limb_t mpn_mod_1 (mp_srcptr, mp_size_t, mp_limb_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_mul __MPN(mul)
+__GMP_DECLSPEC mp_limb_t mpn_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+
+#define mpn_mul_1 __MPN(mul_1)
+__GMP_DECLSPEC mp_limb_t mpn_mul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_mul_n __MPN(mul_n)
+__GMP_DECLSPEC void mpn_mul_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+
+#define mpn_sqr __MPN(sqr)
+__GMP_DECLSPEC void mpn_sqr (mp_ptr, mp_srcptr, mp_size_t);
+
+#define mpn_neg __MPN(neg)
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_neg)
+__GMP_DECLSPEC mp_limb_t mpn_neg (mp_ptr, mp_srcptr, mp_size_t);
+#endif
+
+#define mpn_com __MPN(com)
+__GMP_DECLSPEC void mpn_com (mp_ptr, mp_srcptr, mp_size_t);
+
+#define mpn_perfect_square_p __MPN(perfect_square_p)
+__GMP_DECLSPEC int mpn_perfect_square_p (mp_srcptr, mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_perfect_power_p __MPN(perfect_power_p)
+__GMP_DECLSPEC int mpn_perfect_power_p (mp_srcptr, mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_popcount __MPN(popcount)
+__GMP_DECLSPEC mp_bitcnt_t mpn_popcount (mp_srcptr, mp_size_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpn_pow_1 __MPN(pow_1)
+__GMP_DECLSPEC mp_size_t mpn_pow_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_ptr);
+
+/* undocumented now, but retained here for upward compatibility */
+#define mpn_preinv_mod_1 __MPN(preinv_mod_1)
+__GMP_DECLSPEC mp_limb_t mpn_preinv_mod_1 (mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_random __MPN(random)
+__GMP_DECLSPEC void mpn_random (mp_ptr, mp_size_t);
+
+#define mpn_random2 __MPN(random2)
+__GMP_DECLSPEC void mpn_random2 (mp_ptr, mp_size_t);
+
+#define mpn_rshift __MPN(rshift)
+__GMP_DECLSPEC mp_limb_t mpn_rshift (mp_ptr, mp_srcptr, mp_size_t, unsigned int);
+
+#define mpn_scan0 __MPN(scan0)
+__GMP_DECLSPEC mp_bitcnt_t mpn_scan0 (mp_srcptr, mp_bitcnt_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_scan1 __MPN(scan1)
+__GMP_DECLSPEC mp_bitcnt_t mpn_scan1 (mp_srcptr, mp_bitcnt_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_set_str __MPN(set_str)
+__GMP_DECLSPEC mp_size_t mpn_set_str (mp_ptr, const unsigned char *, size_t, int);
+
+#define mpn_sizeinbase __MPN(sizeinbase)
+__GMP_DECLSPEC size_t mpn_sizeinbase (mp_srcptr, mp_size_t, int);
+
+#define mpn_sqrtrem __MPN(sqrtrem)
+__GMP_DECLSPEC mp_size_t mpn_sqrtrem (mp_ptr, mp_ptr, mp_srcptr, mp_size_t);
+
+#define mpn_sub __MPN(sub)
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_sub)
+__GMP_DECLSPEC mp_limb_t mpn_sub (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+#endif
+
+#define mpn_sub_1 __MPN(sub_1)
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_sub_1)
+__GMP_DECLSPEC mp_limb_t mpn_sub_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t) __GMP_NOTHROW;
+#endif
+
+#define mpn_sub_n __MPN(sub_n)
+__GMP_DECLSPEC mp_limb_t mpn_sub_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+
+#define mpn_submul_1 __MPN(submul_1)
+__GMP_DECLSPEC mp_limb_t mpn_submul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_tdiv_qr __MPN(tdiv_qr)
+__GMP_DECLSPEC void mpn_tdiv_qr (mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+
+#define mpn_and_n __MPN(and_n)
+__GMP_DECLSPEC void mpn_and_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_andn_n __MPN(andn_n)
+__GMP_DECLSPEC void mpn_andn_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_nand_n __MPN(nand_n)
+__GMP_DECLSPEC void mpn_nand_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_ior_n __MPN(ior_n)
+__GMP_DECLSPEC void mpn_ior_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_iorn_n __MPN(iorn_n)
+__GMP_DECLSPEC void mpn_iorn_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_nior_n __MPN(nior_n)
+__GMP_DECLSPEC void mpn_nior_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_xor_n __MPN(xor_n)
+__GMP_DECLSPEC void mpn_xor_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_xnor_n __MPN(xnor_n)
+__GMP_DECLSPEC void mpn_xnor_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+
+#define mpn_copyi __MPN(copyi)
+__GMP_DECLSPEC void mpn_copyi (mp_ptr, mp_srcptr, mp_size_t);
+#define mpn_copyd __MPN(copyd)
+__GMP_DECLSPEC void mpn_copyd (mp_ptr, mp_srcptr, mp_size_t);
+#define mpn_zero __MPN(zero)
+__GMP_DECLSPEC void mpn_zero (mp_ptr, mp_size_t);
+
+#define mpn_cnd_add_n __MPN(cnd_add_n)
+__GMP_DECLSPEC mp_limb_t mpn_cnd_add_n (mp_limb_t, mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_cnd_sub_n __MPN(cnd_sub_n)
+__GMP_DECLSPEC mp_limb_t mpn_cnd_sub_n (mp_limb_t, mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+
+#define mpn_sec_add_1 __MPN(sec_add_1)
+__GMP_DECLSPEC mp_limb_t mpn_sec_add_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_ptr);
+#define mpn_sec_add_1_itch __MPN(sec_add_1_itch)
+__GMP_DECLSPEC mp_size_t mpn_sec_add_1_itch (mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_sec_sub_1 __MPN(sec_sub_1)
+__GMP_DECLSPEC mp_limb_t mpn_sec_sub_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_ptr);
+#define mpn_sec_sub_1_itch __MPN(sec_sub_1_itch)
+__GMP_DECLSPEC mp_size_t mpn_sec_sub_1_itch (mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_cnd_swap  __MPN(cnd_swap)
+__GMP_DECLSPEC void mpn_cnd_swap (mp_limb_t, volatile mp_limb_t *, volatile mp_limb_t *, mp_size_t);
+
+#define mpn_sec_mul __MPN(sec_mul)
+__GMP_DECLSPEC void mpn_sec_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+#define mpn_sec_mul_itch __MPN(sec_mul_itch)
+__GMP_DECLSPEC mp_size_t mpn_sec_mul_itch (mp_size_t, mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_sec_sqr __MPN(sec_sqr)
+__GMP_DECLSPEC void mpn_sec_sqr (mp_ptr, mp_srcptr, mp_size_t, mp_ptr);
+#define mpn_sec_sqr_itch __MPN(sec_sqr_itch)
+__GMP_DECLSPEC mp_size_t mpn_sec_sqr_itch (mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_sec_powm __MPN(sec_powm)
+__GMP_DECLSPEC void mpn_sec_powm (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_bitcnt_t, mp_srcptr, mp_size_t, mp_ptr);
+#define mpn_sec_powm_itch __MPN(sec_powm_itch)
+__GMP_DECLSPEC mp_size_t mpn_sec_powm_itch (mp_size_t, mp_bitcnt_t, mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_sec_tabselect __MPN(sec_tabselect)
+__GMP_DECLSPEC void mpn_sec_tabselect (volatile mp_limb_t *, volatile const mp_limb_t *, mp_size_t, mp_size_t, mp_size_t);
+
+#define mpn_sec_div_qr __MPN(sec_div_qr)
+__GMP_DECLSPEC mp_limb_t mpn_sec_div_qr (mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+#define mpn_sec_div_qr_itch __MPN(sec_div_qr_itch)
+__GMP_DECLSPEC mp_size_t mpn_sec_div_qr_itch (mp_size_t, mp_size_t) __GMP_ATTRIBUTE_PURE;
+#define mpn_sec_div_r __MPN(sec_div_r)
+__GMP_DECLSPEC void mpn_sec_div_r (mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+#define mpn_sec_div_r_itch __MPN(sec_div_r_itch)
+__GMP_DECLSPEC mp_size_t mpn_sec_div_r_itch (mp_size_t, mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_sec_invert __MPN(sec_invert)
+__GMP_DECLSPEC int mpn_sec_invert (mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_bitcnt_t, mp_ptr);
+#define mpn_sec_invert_itch __MPN(sec_invert_itch)
+__GMP_DECLSPEC mp_size_t mpn_sec_invert_itch (mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+
+/**************** mpz inlines ****************/
+
+/* The following are provided as inlines where possible, but always exist as
+   library functions too, for binary compatibility.
+
+   Within gmp itself this inlining generally isn't relied on, since it
+   doesn't get done for all compilers, whereas if something is worth
+   inlining then it's worth arranging always.
+
+   There are two styles of inlining here.  When the same bit of code is
+   wanted for the inline as for the library version, then __GMP_FORCE_foo
+   arranges for that code to be emitted and the __GMP_EXTERN_INLINE
+   directive suppressed, eg. mpz_fits_uint_p.  When a different bit of code
+   is wanted for the inline than for the library version, then
+   __GMP_FORCE_foo arranges the inline to be suppressed, eg. mpz_abs.  */
+
+#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpz_abs)
+__GMP_EXTERN_INLINE void
+mpz_abs (mpz_ptr __gmp_w, mpz_srcptr __gmp_u)
+{
+  if (__gmp_w != __gmp_u)
+    mpz_set (__gmp_w, __gmp_u);
+  __gmp_w->_mp_size = __GMP_ABS (__gmp_w->_mp_size);
+}
+#endif
+
+#if GMP_NAIL_BITS == 0
+#define __GMPZ_FITS_UTYPE_P(z,maxval)					\
+  mp_size_t  __gmp_n = z->_mp_size;					\
+  mp_ptr  __gmp_p = z->_mp_d;						\
+  return (__gmp_n == 0 || (__gmp_n == 1 && __gmp_p[0] <= maxval));
+#else
+#define __GMPZ_FITS_UTYPE_P(z,maxval)					\
+  mp_size_t  __gmp_n = z->_mp_size;					\
+  mp_ptr  __gmp_p = z->_mp_d;						\
+  return (__gmp_n == 0 || (__gmp_n == 1 && __gmp_p[0] <= maxval)	\
+	  || (__gmp_n == 2 && __gmp_p[1] <= ((mp_limb_t) maxval >> GMP_NUMB_BITS)));
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_fits_uint_p)
+#if ! defined (__GMP_FORCE_mpz_fits_uint_p)
+__GMP_EXTERN_INLINE
+#endif
+int
+mpz_fits_uint_p (mpz_srcptr __gmp_z) __GMP_NOTHROW
+{
+  __GMPZ_FITS_UTYPE_P (__gmp_z, UINT_MAX);
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_fits_ulong_p)
+#if ! defined (__GMP_FORCE_mpz_fits_ulong_p)
+__GMP_EXTERN_INLINE
+#endif
+int
+mpz_fits_ulong_p (mpz_srcptr __gmp_z) __GMP_NOTHROW
+{
+  __GMPZ_FITS_UTYPE_P (__gmp_z, ULONG_MAX);
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_fits_ushort_p)
+#if ! defined (__GMP_FORCE_mpz_fits_ushort_p)
+__GMP_EXTERN_INLINE
+#endif
+int
+mpz_fits_ushort_p (mpz_srcptr __gmp_z) __GMP_NOTHROW
+{
+  __GMPZ_FITS_UTYPE_P (__gmp_z, USHRT_MAX);
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_get_ui)
+#if ! defined (__GMP_FORCE_mpz_get_ui)
+__GMP_EXTERN_INLINE
+#endif
+unsigned long
+mpz_get_ui (mpz_srcptr __gmp_z) __GMP_NOTHROW
+{
+  mp_ptr __gmp_p = __gmp_z->_mp_d;
+  mp_size_t __gmp_n = __gmp_z->_mp_size;
+  mp_limb_t __gmp_l = __gmp_p[0];
+  /* This is a "#if" rather than a plain "if" so as to avoid gcc warnings
+     about "<< GMP_NUMB_BITS" exceeding the type size, and to avoid Borland
+     C++ 6.0 warnings about condition always true for something like
+     "ULONG_MAX < GMP_NUMB_MASK".  */
+#if GMP_NAIL_BITS == 0 || defined (_LONG_LONG_LIMB)
+  /* limb==long and no nails, or limb==longlong, one limb is enough */
+  return (__gmp_n != 0 ? __gmp_l : 0);
+#else
+  /* limb==long and nails, need two limbs when available */
+  __gmp_n = __GMP_ABS (__gmp_n);
+  if (__gmp_n <= 1)
+    return (__gmp_n != 0 ? __gmp_l : 0);
+  else
+    return __gmp_l + (__gmp_p[1] << GMP_NUMB_BITS);
+#endif
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_getlimbn)
+#if ! defined (__GMP_FORCE_mpz_getlimbn)
+__GMP_EXTERN_INLINE
+#endif
+mp_limb_t
+mpz_getlimbn (mpz_srcptr __gmp_z, mp_size_t __gmp_n) __GMP_NOTHROW
+{
+  mp_limb_t  __gmp_result = 0;
+  if (__GMP_LIKELY (__gmp_n >= 0 && __gmp_n < __GMP_ABS (__gmp_z->_mp_size)))
+    __gmp_result = __gmp_z->_mp_d[__gmp_n];
+  return __gmp_result;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpz_neg)
+__GMP_EXTERN_INLINE void
+mpz_neg (mpz_ptr __gmp_w, mpz_srcptr __gmp_u)
+{
+  if (__gmp_w != __gmp_u)
+    mpz_set (__gmp_w, __gmp_u);
+  __gmp_w->_mp_size = - __gmp_w->_mp_size;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_perfect_square_p)
+#if ! defined (__GMP_FORCE_mpz_perfect_square_p)
+__GMP_EXTERN_INLINE
+#endif
+int
+mpz_perfect_square_p (mpz_srcptr __gmp_a)
+{
+  mp_size_t __gmp_asize;
+  int       __gmp_result;
+
+  __gmp_asize = __gmp_a->_mp_size;
+  __gmp_result = (__gmp_asize >= 0);  /* zero is a square, negatives are not */
+  if (__GMP_LIKELY (__gmp_asize > 0))
+    __gmp_result = mpn_perfect_square_p (__gmp_a->_mp_d, __gmp_asize);
+  return __gmp_result;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_popcount)
+#if ! defined (__GMP_FORCE_mpz_popcount)
+__GMP_EXTERN_INLINE
+#endif
+mp_bitcnt_t
+mpz_popcount (mpz_srcptr __gmp_u) __GMP_NOTHROW
+{
+  mp_size_t      __gmp_usize;
+  mp_bitcnt_t    __gmp_result;
+
+  __gmp_usize = __gmp_u->_mp_size;
+  __gmp_result = (__gmp_usize < 0 ? ~ __GMP_CAST (mp_bitcnt_t, 0) : __GMP_CAST (mp_bitcnt_t, 0));
+  if (__GMP_LIKELY (__gmp_usize > 0))
+    __gmp_result =  mpn_popcount (__gmp_u->_mp_d, __gmp_usize);
+  return __gmp_result;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_set_q)
+#if ! defined (__GMP_FORCE_mpz_set_q)
+__GMP_EXTERN_INLINE
+#endif
+void
+mpz_set_q (mpz_ptr __gmp_w, mpq_srcptr __gmp_u)
+{
+  mpz_tdiv_q (__gmp_w, mpq_numref (__gmp_u), mpq_denref (__gmp_u));
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_size)
+#if ! defined (__GMP_FORCE_mpz_size)
+__GMP_EXTERN_INLINE
+#endif
+size_t
+mpz_size (mpz_srcptr __gmp_z) __GMP_NOTHROW
+{
+  return __GMP_ABS (__gmp_z->_mp_size);
+}
+#endif
+
+
+/**************** mpq inlines ****************/
+
+#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpq_abs)
+__GMP_EXTERN_INLINE void
+mpq_abs (mpq_ptr __gmp_w, mpq_srcptr __gmp_u)
+{
+  if (__gmp_w != __gmp_u)
+    mpq_set (__gmp_w, __gmp_u);
+  __gmp_w->_mp_num._mp_size = __GMP_ABS (__gmp_w->_mp_num._mp_size);
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpq_neg)
+__GMP_EXTERN_INLINE void
+mpq_neg (mpq_ptr __gmp_w, mpq_srcptr __gmp_u)
+{
+  if (__gmp_w != __gmp_u)
+    mpq_set (__gmp_w, __gmp_u);
+  __gmp_w->_mp_num._mp_size = - __gmp_w->_mp_num._mp_size;
+}
+#endif
+
+
+/**************** mpn inlines ****************/
+
+/* The comments with __GMPN_ADD_1 below apply here too.
+
+   The test for FUNCTION returning 0 should predict well.  If it's assumed
+   {yp,ysize} will usually have a random number of bits then the high limb
+   won't be full and a carry out will occur a good deal less than 50% of the
+   time.
+
+   ysize==0 isn't a documented feature, but is used internally in a few
+   places.
+
+   Producing cout last stops it using up a register during the main part of
+   the calculation, though gcc (as of 3.0) on an "if (mpn_add (...))"
+   doesn't seem able to move the true and false legs of the conditional up
+   to the two places cout is generated.  */
+
+#define __GMPN_AORS(cout, wp, xp, xsize, yp, ysize, FUNCTION, TEST)     \
+  do {                                                                  \
+    mp_size_t  __gmp_i;                                                 \
+    mp_limb_t  __gmp_x;                                                 \
+                                                                        \
+    /* ASSERT ((ysize) >= 0); */                                        \
+    /* ASSERT ((xsize) >= (ysize)); */                                  \
+    /* ASSERT (MPN_SAME_OR_SEPARATE2_P (wp, xsize, xp, xsize)); */      \
+    /* ASSERT (MPN_SAME_OR_SEPARATE2_P (wp, xsize, yp, ysize)); */      \
+                                                                        \
+    __gmp_i = (ysize);                                                  \
+    if (__gmp_i != 0)                                                   \
+      {                                                                 \
+        if (FUNCTION (wp, xp, yp, __gmp_i))                             \
+          {                                                             \
+            do                                                          \
+              {                                                         \
+                if (__gmp_i >= (xsize))                                 \
+                  {                                                     \
+                    (cout) = 1;                                         \
+                    goto __gmp_done;                                    \
+                  }                                                     \
+                __gmp_x = (xp)[__gmp_i];                                \
+              }                                                         \
+            while (TEST);                                               \
+          }                                                             \
+      }                                                                 \
+    if ((wp) != (xp))                                                   \
+      __GMPN_COPY_REST (wp, xp, xsize, __gmp_i);                        \
+    (cout) = 0;                                                         \
+  __gmp_done:                                                           \
+    ;                                                                   \
+  } while (0)
+
+#define __GMPN_ADD(cout, wp, xp, xsize, yp, ysize)              \
+  __GMPN_AORS (cout, wp, xp, xsize, yp, ysize, mpn_add_n,       \
+               (((wp)[__gmp_i++] = (__gmp_x + 1) & GMP_NUMB_MASK) == 0))
+#define __GMPN_SUB(cout, wp, xp, xsize, yp, ysize)              \
+  __GMPN_AORS (cout, wp, xp, xsize, yp, ysize, mpn_sub_n,       \
+               (((wp)[__gmp_i++] = (__gmp_x - 1) & GMP_NUMB_MASK), __gmp_x == 0))
+
+
+/* The use of __gmp_i indexing is designed to ensure a compile time src==dst
+   remains nice and clear to the compiler, so that __GMPN_COPY_REST can
+   disappear, and the load/add/store gets a chance to become a
+   read-modify-write on CISC CPUs.
+
+   Alternatives:
+
+   Using a pair of pointers instead of indexing would be possible, but gcc
+   isn't able to recognise compile-time src==dst in that case, even when the
+   pointers are incremented more or less together.  Other compilers would
+   very likely have similar difficulty.
+
+   gcc could use "if (__builtin_constant_p(src==dst) && src==dst)" or
+   similar to detect a compile-time src==dst.  This works nicely on gcc
+   2.95.x, it's not good on gcc 3.0 where __builtin_constant_p(p==p) seems
+   to be always false, for a pointer p.  But the current code form seems
+   good enough for src==dst anyway.
+
+   gcc on x86 as usual doesn't give particularly good flags handling for the
+   carry/borrow detection.  It's tempting to want some multi instruction asm
+   blocks to help it, and this was tried, but in truth there's only a few
+   instructions to save and any gain is all too easily lost by register
+   juggling setting up for the asm.  */
+
+#if GMP_NAIL_BITS == 0
+#define __GMPN_AORS_1(cout, dst, src, n, v, OP, CB)		\
+  do {								\
+    mp_size_t  __gmp_i;						\
+    mp_limb_t  __gmp_x, __gmp_r;                                \
+								\
+    /* ASSERT ((n) >= 1); */					\
+    /* ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, n)); */	\
+								\
+    __gmp_x = (src)[0];						\
+    __gmp_r = __gmp_x OP (v);                                   \
+    (dst)[0] = __gmp_r;						\
+    if (CB (__gmp_r, __gmp_x, (v)))                             \
+      {								\
+	(cout) = 1;						\
+	for (__gmp_i = 1; __gmp_i < (n);)                       \
+	  {							\
+	    __gmp_x = (src)[__gmp_i];                           \
+	    __gmp_r = __gmp_x OP 1;                             \
+	    (dst)[__gmp_i] = __gmp_r;                           \
+	    ++__gmp_i;						\
+	    if (!CB (__gmp_r, __gmp_x, 1))                      \
+	      {							\
+		if ((src) != (dst))				\
+		  __GMPN_COPY_REST (dst, src, n, __gmp_i);      \
+		(cout) = 0;					\
+		break;						\
+	      }							\
+	  }							\
+      }								\
+    else							\
+      {								\
+	if ((src) != (dst))					\
+	  __GMPN_COPY_REST (dst, src, n, 1);			\
+	(cout) = 0;						\
+      }								\
+  } while (0)
+#endif
+
+#if GMP_NAIL_BITS >= 1
+#define __GMPN_AORS_1(cout, dst, src, n, v, OP, CB)		\
+  do {								\
+    mp_size_t  __gmp_i;						\
+    mp_limb_t  __gmp_x, __gmp_r;				\
+								\
+    /* ASSERT ((n) >= 1); */					\
+    /* ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, n)); */	\
+								\
+    __gmp_x = (src)[0];						\
+    __gmp_r = __gmp_x OP (v);					\
+    (dst)[0] = __gmp_r & GMP_NUMB_MASK;				\
+    if (__gmp_r >> GMP_NUMB_BITS != 0)				\
+      {								\
+	(cout) = 1;						\
+	for (__gmp_i = 1; __gmp_i < (n);)			\
+	  {							\
+	    __gmp_x = (src)[__gmp_i];				\
+	    __gmp_r = __gmp_x OP 1;				\
+	    (dst)[__gmp_i] = __gmp_r & GMP_NUMB_MASK;		\
+	    ++__gmp_i;						\
+	    if (__gmp_r >> GMP_NUMB_BITS == 0)			\
+	      {							\
+		if ((src) != (dst))				\
+		  __GMPN_COPY_REST (dst, src, n, __gmp_i);	\
+		(cout) = 0;					\
+		break;						\
+	      }							\
+	  }							\
+      }								\
+    else							\
+      {								\
+	if ((src) != (dst))					\
+	  __GMPN_COPY_REST (dst, src, n, 1);			\
+	(cout) = 0;						\
+      }								\
+  } while (0)
+#endif
+
+#define __GMPN_ADDCB(r,x,y) ((r) < (y))
+#define __GMPN_SUBCB(r,x,y) ((x) < (y))
+
+#define __GMPN_ADD_1(cout, dst, src, n, v)	     \
+  __GMPN_AORS_1(cout, dst, src, n, v, +, __GMPN_ADDCB)
+#define __GMPN_SUB_1(cout, dst, src, n, v)	     \
+  __GMPN_AORS_1(cout, dst, src, n, v, -, __GMPN_SUBCB)
+
+
+/* Compare {xp,size} and {yp,size}, setting "result" to positive, zero or
+   negative.  size==0 is allowed.  On random data usually only one limb will
+   need to be examined to get a result, so it's worth having it inline.  */
+#define __GMPN_CMP(result, xp, yp, size)                                \
+  do {                                                                  \
+    mp_size_t  __gmp_i;                                                 \
+    mp_limb_t  __gmp_x, __gmp_y;                                        \
+                                                                        \
+    /* ASSERT ((size) >= 0); */                                         \
+                                                                        \
+    (result) = 0;                                                       \
+    __gmp_i = (size);                                                   \
+    while (--__gmp_i >= 0)                                              \
+      {                                                                 \
+        __gmp_x = (xp)[__gmp_i];                                        \
+        __gmp_y = (yp)[__gmp_i];                                        \
+        if (__gmp_x != __gmp_y)                                         \
+          {                                                             \
+            /* Cannot use __gmp_x - __gmp_y, may overflow an "int" */   \
+            (result) = (__gmp_x > __gmp_y ? 1 : -1);                    \
+            break;                                                      \
+          }                                                             \
+      }                                                                 \
+  } while (0)
+
+
+#if defined (__GMPN_COPY) && ! defined (__GMPN_COPY_REST)
+#define __GMPN_COPY_REST(dst, src, size, start)                 \
+  do {                                                          \
+    /* ASSERT ((start) >= 0); */                                \
+    /* ASSERT ((start) <= (size)); */                           \
+    __GMPN_COPY ((dst)+(start), (src)+(start), (size)-(start)); \
+  } while (0)
+#endif
+
+/* Copy {src,size} to {dst,size}, starting at "start".  This is designed to
+   keep the indexing dst[j] and src[j] nice and simple for __GMPN_ADD_1,
+   __GMPN_ADD, etc.  */
+#if ! defined (__GMPN_COPY_REST)
+#define __GMPN_COPY_REST(dst, src, size, start)                 \
+  do {                                                          \
+    mp_size_t __gmp_j;                                          \
+    /* ASSERT ((size) >= 0); */                                 \
+    /* ASSERT ((start) >= 0); */                                \
+    /* ASSERT ((start) <= (size)); */                           \
+    /* ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, size)); */     \
+    __GMP_CRAY_Pragma ("_CRI ivdep");                           \
+    for (__gmp_j = (start); __gmp_j < (size); __gmp_j++)        \
+      (dst)[__gmp_j] = (src)[__gmp_j];                          \
+  } while (0)
+#endif
+
+/* Enhancement: Use some of the smarter code from gmp-impl.h.  Maybe use
+   mpn_copyi if there's a native version, and if we don't mind demanding
+   binary compatibility for it (on targets which use it).  */
+
+#if ! defined (__GMPN_COPY)
+#define __GMPN_COPY(dst, src, size)   __GMPN_COPY_REST (dst, src, size, 0)
+#endif
+
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_add)
+#if ! defined (__GMP_FORCE_mpn_add)
+__GMP_EXTERN_INLINE
+#endif
+mp_limb_t
+mpn_add (mp_ptr __gmp_wp, mp_srcptr __gmp_xp, mp_size_t __gmp_xsize, mp_srcptr __gmp_yp, mp_size_t __gmp_ysize)
+{
+  mp_limb_t  __gmp_c;
+  __GMPN_ADD (__gmp_c, __gmp_wp, __gmp_xp, __gmp_xsize, __gmp_yp, __gmp_ysize);
+  return __gmp_c;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_add_1)
+#if ! defined (__GMP_FORCE_mpn_add_1)
+__GMP_EXTERN_INLINE
+#endif
+mp_limb_t
+mpn_add_1 (mp_ptr __gmp_dst, mp_srcptr __gmp_src, mp_size_t __gmp_size, mp_limb_t __gmp_n) __GMP_NOTHROW
+{
+  mp_limb_t  __gmp_c;
+  __GMPN_ADD_1 (__gmp_c, __gmp_dst, __gmp_src, __gmp_size, __gmp_n);
+  return __gmp_c;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_cmp)
+#if ! defined (__GMP_FORCE_mpn_cmp)
+__GMP_EXTERN_INLINE
+#endif
+int
+mpn_cmp (mp_srcptr __gmp_xp, mp_srcptr __gmp_yp, mp_size_t __gmp_size) __GMP_NOTHROW
+{
+  int __gmp_result;
+  __GMPN_CMP (__gmp_result, __gmp_xp, __gmp_yp, __gmp_size);
+  return __gmp_result;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_zero_p)
+#if ! defined (__GMP_FORCE_mpn_zero_p)
+__GMP_EXTERN_INLINE
+#endif
+int
+mpn_zero_p (mp_srcptr __gmp_p, mp_size_t __gmp_n) __GMP_NOTHROW
+{
+  /* if (__GMP_LIKELY (__gmp_n > 0)) */
+    do {
+      if (__gmp_p[--__gmp_n] != 0)
+	return 0;
+    } while (__gmp_n != 0);
+  return 1;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_sub)
+#if ! defined (__GMP_FORCE_mpn_sub)
+__GMP_EXTERN_INLINE
+#endif
+mp_limb_t
+mpn_sub (mp_ptr __gmp_wp, mp_srcptr __gmp_xp, mp_size_t __gmp_xsize, mp_srcptr __gmp_yp, mp_size_t __gmp_ysize)
+{
+  mp_limb_t  __gmp_c;
+  __GMPN_SUB (__gmp_c, __gmp_wp, __gmp_xp, __gmp_xsize, __gmp_yp, __gmp_ysize);
+  return __gmp_c;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_sub_1)
+#if ! defined (__GMP_FORCE_mpn_sub_1)
+__GMP_EXTERN_INLINE
+#endif
+mp_limb_t
+mpn_sub_1 (mp_ptr __gmp_dst, mp_srcptr __gmp_src, mp_size_t __gmp_size, mp_limb_t __gmp_n) __GMP_NOTHROW
+{
+  mp_limb_t  __gmp_c;
+  __GMPN_SUB_1 (__gmp_c, __gmp_dst, __gmp_src, __gmp_size, __gmp_n);
+  return __gmp_c;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_neg)
+#if ! defined (__GMP_FORCE_mpn_neg)
+__GMP_EXTERN_INLINE
+#endif
+mp_limb_t
+mpn_neg (mp_ptr __gmp_rp, mp_srcptr __gmp_up, mp_size_t __gmp_n)
+{
+  while (*__gmp_up == 0) /* Low zero limbs are unchanged by negation. */
+    {
+      *__gmp_rp = 0;
+      if (!--__gmp_n) /* All zero */
+	return 0;
+      ++__gmp_up; ++__gmp_rp;
+    }
+
+  *__gmp_rp = (- *__gmp_up) & GMP_NUMB_MASK;
+
+  if (--__gmp_n) /* Higher limbs get complemented. */
+    mpn_com (++__gmp_rp, ++__gmp_up, __gmp_n);
+
+  return 1;
+}
+#endif
+
+#if defined (__cplusplus)
+}
+#endif
+
+
+/* Allow faster testing for negative, zero, and positive.  */
+#define mpz_sgn(Z) ((Z)->_mp_size < 0 ? -1 : (Z)->_mp_size > 0)
+#define mpf_sgn(F) ((F)->_mp_size < 0 ? -1 : (F)->_mp_size > 0)
+#define mpq_sgn(Q) ((Q)->_mp_num._mp_size < 0 ? -1 : (Q)->_mp_num._mp_size > 0)
+
+/* When using GCC, optimize certain common comparisons.  */
+#if defined (__GNUC__) && __GNUC__ >= 2
+#define mpz_cmp_ui(Z,UI) \
+  (__builtin_constant_p (UI) && (UI) == 0				\
+   ? mpz_sgn (Z) : _mpz_cmp_ui (Z,UI))
+#define mpz_cmp_si(Z,SI)						\
+  (__builtin_constant_p ((SI) >= 0) && (SI) >= 0			\
+   ? mpz_cmp_ui (Z, __GMP_CAST (unsigned long, SI))			\
+   : _mpz_cmp_si (Z,SI))
+#define mpq_cmp_ui(Q,NUI,DUI)					\
+  (__builtin_constant_p (NUI) && (NUI) == 0 ? mpq_sgn (Q)	\
+   : __builtin_constant_p ((NUI) == (DUI)) && (NUI) == (DUI)	\
+   ? mpz_cmp (mpq_numref (Q), mpq_denref (Q))			\
+   : _mpq_cmp_ui (Q,NUI,DUI))
+#define mpq_cmp_si(q,n,d)				\
+  (__builtin_constant_p ((n) >= 0) && (n) >= 0		\
+   ? mpq_cmp_ui (q, __GMP_CAST (unsigned long, n), d)	\
+   : _mpq_cmp_si (q, n, d))
+#else
+#define mpz_cmp_ui(Z,UI) _mpz_cmp_ui (Z,UI)
+#define mpz_cmp_si(Z,UI) _mpz_cmp_si (Z,UI)
+#define mpq_cmp_ui(Q,NUI,DUI) _mpq_cmp_ui (Q,NUI,DUI)
+#define mpq_cmp_si(q,n,d)  _mpq_cmp_si(q,n,d)
+#endif
+
+
+/* Using "&" rather than "&&" means these can come out branch-free.  Every
+   mpz_t has at least one limb allocated, so fetching the low limb is always
+   allowed.  */
+#define mpz_odd_p(z)   (((z)->_mp_size != 0) & __GMP_CAST (int, (z)->_mp_d[0]))
+#define mpz_even_p(z)  (! mpz_odd_p (z))
+
+
+/**************** C++ routines ****************/
+
+#ifdef __cplusplus
+__GMP_DECLSPEC_XX std::ostream& operator<< (std::ostream &, mpz_srcptr);
+__GMP_DECLSPEC_XX std::ostream& operator<< (std::ostream &, mpq_srcptr);
+__GMP_DECLSPEC_XX std::ostream& operator<< (std::ostream &, mpf_srcptr);
+__GMP_DECLSPEC_XX std::istream& operator>> (std::istream &, mpz_ptr);
+__GMP_DECLSPEC_XX std::istream& operator>> (std::istream &, mpq_ptr);
+__GMP_DECLSPEC_XX std::istream& operator>> (std::istream &, mpf_ptr);
+#endif
+
+
+/* Source-level compatibility with GMP 2 and earlier. */
+#define mpn_divmod(qp,np,nsize,dp,dsize) \
+  mpn_divrem (qp, __GMP_CAST (mp_size_t, 0), np, nsize, dp, dsize)
+
+/* Source-level compatibility with GMP 1.  */
+#define mpz_mdiv	mpz_fdiv_q
+#define mpz_mdivmod	mpz_fdiv_qr
+#define mpz_mmod	mpz_fdiv_r
+#define mpz_mdiv_ui	mpz_fdiv_q_ui
+#define mpz_mdivmod_ui(q,r,n,d) \
+  (((r) == 0) ? mpz_fdiv_q_ui (q,n,d) : mpz_fdiv_qr_ui (q,r,n,d))
+#define mpz_mmod_ui(r,n,d) \
+  (((r) == 0) ? mpz_fdiv_ui (n,d) : mpz_fdiv_r_ui (r,n,d))
+
+/* Useful synonyms, but not quite compatible with GMP 1.  */
+#define mpz_div		mpz_fdiv_q
+#define mpz_divmod	mpz_fdiv_qr
+#define mpz_div_ui	mpz_fdiv_q_ui
+#define mpz_divmod_ui	mpz_fdiv_qr_ui
+#define mpz_div_2exp	mpz_fdiv_q_2exp
+#define mpz_mod_2exp	mpz_fdiv_r_2exp
+
+enum
+{
+  GMP_ERROR_NONE = 0,
+  GMP_ERROR_UNSUPPORTED_ARGUMENT = 1,
+  GMP_ERROR_DIVISION_BY_ZERO = 2,
+  GMP_ERROR_SQRT_OF_NEGATIVE = 4,
+  GMP_ERROR_INVALID_ARGUMENT = 8
+};
+
+/* Define CC and CFLAGS which were used to build this version of GMP */
+#define __GMP_CC "clang"
+#define __GMP_CFLAGS "-O2 -pedantic -fomit-frame-pointer -m64 -mtune=znver2 -march=znver1"
+
+/* Major version number is the value of __GNU_MP__ too, above. */
+#define __GNU_MP_VERSION            6
+#define __GNU_MP_VERSION_MINOR      2
+#define __GNU_MP_VERSION_PATCHLEVEL 0
+#define __GNU_MP_RELEASE (__GNU_MP_VERSION * 10000 + __GNU_MP_VERSION_MINOR * 100 + __GNU_MP_VERSION_PATCHLEVEL)
+
+#define __GMP_H__
+#endif /* __GMP_H__ */
diff --git a/third_party/gmp/configfsf.guess b/third_party/gmp/configfsf.guess
new file mode 100644
index 0000000..45001cf
--- /dev/null
+++ b/third_party/gmp/configfsf.guess
@@ -0,0 +1,1667 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright 1992-2020 Free Software Foundation, Inc.
+
+timestamp='2020-01-01'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that
+# program.  This Exception is an additional permission under section 7
+# of the GNU General Public License, version 3 ("GPLv3").
+#
+# Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
+#
+# You can get the latest version of this script from:
+# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
+#
+# Please send patches to <config-patches@gnu.org>.
+
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Options:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright 1992-2020 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help" >&2
+       exit 1 ;;
+    * )
+       break ;;
+  esac
+done
+
+if test $# != 0; then
+  echo "$me: too many arguments$help" >&2
+  exit 1
+fi
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+tmp=
+# shellcheck disable=SC2172
+trap 'test -z "$tmp" || rm -fr "$tmp"' 0 1 2 13 15
+
+set_cc_for_build() {
+    # prevent multiple calls if $tmp is already set
+    test "$tmp" && return 0
+    : "${TMPDIR=/tmp}"
+    # shellcheck disable=SC2039
+    { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+	{ test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir "$tmp" 2>/dev/null) ; } ||
+	{ tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+	{ echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; }
+    dummy=$tmp/dummy
+    case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in
+	,,)    echo "int x;" > "$dummy.c"
+	       for driver in cc gcc c89 c99 ; do
+		   if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then
+		       CC_FOR_BUILD="$driver"
+		       break
+		   fi
+	       done
+	       if test x"$CC_FOR_BUILD" = x ; then
+		   CC_FOR_BUILD=no_compiler_found
+	       fi
+	       ;;
+	,,*)   CC_FOR_BUILD=$CC ;;
+	,*,*)  CC_FOR_BUILD=$HOST_CC ;;
+    esac
+}
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if test -f /.attbin/uname ; then
+	PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+case "$UNAME_SYSTEM" in
+Linux|GNU|GNU/*)
+	# If the system lacks a compiler, then just pick glibc.
+	# We could probably try harder.
+	LIBC=gnu
+
+	set_cc_for_build
+	cat <<-EOF > "$dummy.c"
+	#include <features.h>
+	#if defined(__UCLIBC__)
+	LIBC=uclibc
+	#elif defined(__dietlibc__)
+	LIBC=dietlibc
+	#else
+	LIBC=gnu
+	#endif
+	EOF
+	eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`"
+
+	# If ldd exists, use it to detect musl libc.
+	if command -v ldd >/dev/null && \
+		ldd --version 2>&1 | grep -q ^musl
+	then
+	    LIBC=musl
+	fi
+	;;
+esac
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
+    *:NetBSD:*:*)
+	# NetBSD (nbsd) targets should (where applicable) match one or
+	# more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
+	# *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
+	# switched to ELF, *-*-netbsd* would select the old
+	# object file format.  This provides both forward
+	# compatibility and a consistent mechanism for selecting the
+	# object file format.
+	#
+	# Note: NetBSD doesn't particularly care about the vendor
+	# portion of the name.  We always set it to "unknown".
+	sysctl="sysctl -n hw.machine_arch"
+	UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \
+	    "/sbin/$sysctl" 2>/dev/null || \
+	    "/usr/sbin/$sysctl" 2>/dev/null || \
+	    echo unknown)`
+	case "$UNAME_MACHINE_ARCH" in
+	    armeb) machine=armeb-unknown ;;
+	    arm*) machine=arm-unknown ;;
+	    sh3el) machine=shl-unknown ;;
+	    sh3eb) machine=sh-unknown ;;
+	    sh5el) machine=sh5le-unknown ;;
+	    earmv*)
+		arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'`
+		endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'`
+		machine="${arch}${endian}"-unknown
+		;;
+	    *) machine="$UNAME_MACHINE_ARCH"-unknown ;;
+	esac
+	# The Operating System including object format, if it has switched
+	# to ELF recently (or will in the future) and ABI.
+	case "$UNAME_MACHINE_ARCH" in
+	    earm*)
+		os=netbsdelf
+		;;
+	    arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+		set_cc_for_build
+		if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+			| grep -q __ELF__
+		then
+		    # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+		    # Return netbsd for either.  FIX?
+		    os=netbsd
+		else
+		    os=netbsdelf
+		fi
+		;;
+	    *)
+		os=netbsd
+		;;
+	esac
+	# Determine ABI tags.
+	case "$UNAME_MACHINE_ARCH" in
+	    earm*)
+		expr='s/^earmv[0-9]/-eabi/;s/eb$//'
+		abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"`
+		;;
+	esac
+	# The OS release
+	# Debian GNU/NetBSD machines have a different userland, and
+	# thus, need a distinct triplet. However, they do not need
+	# kernel version information, so it can be replaced with a
+	# suitable tag, in the style of linux-gnu.
+	case "$UNAME_VERSION" in
+	    Debian*)
+		release='-gnu'
+		;;
+	    *)
+		release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2`
+		;;
+	esac
+	# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+	# contains redundant information, the shorter form:
+	# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+	echo "$machine-${os}${release}${abi-}"
+	exit ;;
+    *:Bitrig:*:*)
+	UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
+	echo "$UNAME_MACHINE_ARCH"-unknown-bitrig"$UNAME_RELEASE"
+	exit ;;
+    *:OpenBSD:*:*)
+	UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+	echo "$UNAME_MACHINE_ARCH"-unknown-openbsd"$UNAME_RELEASE"
+	exit ;;
+    *:LibertyBSD:*:*)
+	UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'`
+	echo "$UNAME_MACHINE_ARCH"-unknown-libertybsd"$UNAME_RELEASE"
+	exit ;;
+    *:MidnightBSD:*:*)
+	echo "$UNAME_MACHINE"-unknown-midnightbsd"$UNAME_RELEASE"
+	exit ;;
+    *:ekkoBSD:*:*)
+	echo "$UNAME_MACHINE"-unknown-ekkobsd"$UNAME_RELEASE"
+	exit ;;
+    *:SolidBSD:*:*)
+	echo "$UNAME_MACHINE"-unknown-solidbsd"$UNAME_RELEASE"
+	exit ;;
+    *:OS108:*:*)
+	echo "$UNAME_MACHINE"-unknown-os108_"$UNAME_RELEASE"
+	exit ;;
+    macppc:MirBSD:*:*)
+	echo powerpc-unknown-mirbsd"$UNAME_RELEASE"
+	exit ;;
+    *:MirBSD:*:*)
+	echo "$UNAME_MACHINE"-unknown-mirbsd"$UNAME_RELEASE"
+	exit ;;
+    *:Sortix:*:*)
+	echo "$UNAME_MACHINE"-unknown-sortix
+	exit ;;
+    *:Twizzler:*:*)
+	echo "$UNAME_MACHINE"-unknown-twizzler
+	exit ;;
+    *:Redox:*:*)
+	echo "$UNAME_MACHINE"-unknown-redox
+	exit ;;
+    mips:OSF1:*.*)
+	echo mips-dec-osf1
+	exit ;;
+    alpha:OSF1:*:*)
+	case $UNAME_RELEASE in
+	*4.0)
+		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+		;;
+	*5.*)
+		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+		;;
+	esac
+	# According to Compaq, /usr/sbin/psrinfo has been available on
+	# OSF/1 and Tru64 systems produced since 1995.  I hope that
+	# covers most systems running today.  This code pipes the CPU
+	# types through head -n 1, so we only detect the type of CPU 0.
+	ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+	case "$ALPHA_CPU_TYPE" in
+	    "EV4 (21064)")
+		UNAME_MACHINE=alpha ;;
+	    "EV4.5 (21064)")
+		UNAME_MACHINE=alpha ;;
+	    "LCA4 (21066/21068)")
+		UNAME_MACHINE=alpha ;;
+	    "EV5 (21164)")
+		UNAME_MACHINE=alphaev5 ;;
+	    "EV5.6 (21164A)")
+		UNAME_MACHINE=alphaev56 ;;
+	    "EV5.6 (21164PC)")
+		UNAME_MACHINE=alphapca56 ;;
+	    "EV5.7 (21164PC)")
+		UNAME_MACHINE=alphapca57 ;;
+	    "EV6 (21264)")
+		UNAME_MACHINE=alphaev6 ;;
+	    "EV6.7 (21264A)")
+		UNAME_MACHINE=alphaev67 ;;
+	    "EV6.8CB (21264C)")
+		UNAME_MACHINE=alphaev68 ;;
+	    "EV6.8AL (21264B)")
+		UNAME_MACHINE=alphaev68 ;;
+	    "EV6.8CX (21264D)")
+		UNAME_MACHINE=alphaev68 ;;
+	    "EV6.9A (21264/EV69A)")
+		UNAME_MACHINE=alphaev69 ;;
+	    "EV7 (21364)")
+		UNAME_MACHINE=alphaev7 ;;
+	    "EV7.9 (21364A)")
+		UNAME_MACHINE=alphaev79 ;;
+	esac
+	# A Pn.n version is a patched version.
+	# A Vn.n version is a released version.
+	# A Tn.n version is a released field test version.
+	# A Xn.n version is an unreleased experimental baselevel.
+	# 1.2 uses "1.2" for uname -r.
+	echo "$UNAME_MACHINE"-dec-osf"`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`"
+	# Reset EXIT trap before exiting to avoid spurious non-zero exit code.
+	exitcode=$?
+	trap '' 0
+	exit $exitcode ;;
+    Amiga*:UNIX_System_V:4.0:*)
+	echo m68k-unknown-sysv4
+	exit ;;
+    *:[Aa]miga[Oo][Ss]:*:*)
+	echo "$UNAME_MACHINE"-unknown-amigaos
+	exit ;;
+    *:[Mm]orph[Oo][Ss]:*:*)
+	echo "$UNAME_MACHINE"-unknown-morphos
+	exit ;;
+    *:OS/390:*:*)
+	echo i370-ibm-openedition
+	exit ;;
+    *:z/VM:*:*)
+	echo s390-ibm-zvmoe
+	exit ;;
+    *:OS400:*:*)
+	echo powerpc-ibm-os400
+	exit ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+	echo arm-acorn-riscix"$UNAME_RELEASE"
+	exit ;;
+    arm*:riscos:*:*|arm*:RISCOS:*:*)
+	echo arm-unknown-riscos
+	exit ;;
+    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+	echo hppa1.1-hitachi-hiuxmpp
+	exit ;;
+    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+	# akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+	if test "`(/bin/universe) 2>/dev/null`" = att ; then
+		echo pyramid-pyramid-sysv3
+	else
+		echo pyramid-pyramid-bsd
+	fi
+	exit ;;
+    NILE*:*:*:dcosx)
+	echo pyramid-pyramid-svr4
+	exit ;;
+    DRS?6000:unix:4.0:6*)
+	echo sparc-icl-nx6
+	exit ;;
+    DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+	case `/usr/bin/uname -p` in
+	    sparc) echo sparc-icl-nx7; exit ;;
+	esac ;;
+    s390x:SunOS:*:*)
+	echo "$UNAME_MACHINE"-ibm-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`"
+	exit ;;
+    sun4H:SunOS:5.*:*)
+	echo sparc-hal-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
+	exit ;;
+    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+	echo sparc-sun-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`"
+	exit ;;
+    i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
+	echo i386-pc-auroraux"$UNAME_RELEASE"
+	exit ;;
+    i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+	set_cc_for_build
+	SUN_ARCH=i386
+	# If there is a compiler, see if it is configured for 64-bit objects.
+	# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+	# This test works for both compilers.
+	if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
+	    if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+		(CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+		grep IS_64BIT_ARCH >/dev/null
+	    then
+		SUN_ARCH=x86_64
+	    fi
+	fi
+	echo "$SUN_ARCH"-pc-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
+	exit ;;
+    sun4*:SunOS:6*:*)
+	# According to config.sub, this is the proper way to canonicalize
+	# SunOS6.  Hard to guess exactly what SunOS6 will be like, but
+	# it's likely to be more like Solaris than SunOS4.
+	echo sparc-sun-solaris3"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
+	exit ;;
+    sun4*:SunOS:*:*)
+	case "`/usr/bin/arch -k`" in
+	    Series*|S4*)
+		UNAME_RELEASE=`uname -v`
+		;;
+	esac
+	# Japanese Language versions have a version number like `4.1.3-JL'.
+	echo sparc-sun-sunos"`echo "$UNAME_RELEASE"|sed -e 's/-/_/'`"
+	exit ;;
+    sun3*:SunOS:*:*)
+	echo m68k-sun-sunos"$UNAME_RELEASE"
+	exit ;;
+    sun*:*:4.2BSD:*)
+	UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+	test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3
+	case "`/bin/arch`" in
+	    sun3)
+		echo m68k-sun-sunos"$UNAME_RELEASE"
+		;;
+	    sun4)
+		echo sparc-sun-sunos"$UNAME_RELEASE"
+		;;
+	esac
+	exit ;;
+    aushp:SunOS:*:*)
+	echo sparc-auspex-sunos"$UNAME_RELEASE"
+	exit ;;
+    # The situation for MiNT is a little confusing.  The machine name
+    # can be virtually everything (everything which is not
+    # "atarist" or "atariste" at least should have a processor
+    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
+    # to the lowercase version "mint" (or "freemint").  Finally
+    # the system name "TOS" denotes a system which is actually not
+    # MiNT.  But MiNT is downward compatible to TOS, so this should
+    # be no problem.
+    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+	echo m68k-atari-mint"$UNAME_RELEASE"
+	exit ;;
+    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+	echo m68k-atari-mint"$UNAME_RELEASE"
+	exit ;;
+    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+	echo m68k-atari-mint"$UNAME_RELEASE"
+	exit ;;
+    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+	echo m68k-milan-mint"$UNAME_RELEASE"
+	exit ;;
+    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+	echo m68k-hades-mint"$UNAME_RELEASE"
+	exit ;;
+    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+	echo m68k-unknown-mint"$UNAME_RELEASE"
+	exit ;;
+    m68k:machten:*:*)
+	echo m68k-apple-machten"$UNAME_RELEASE"
+	exit ;;
+    powerpc:machten:*:*)
+	echo powerpc-apple-machten"$UNAME_RELEASE"
+	exit ;;
+    RISC*:Mach:*:*)
+	echo mips-dec-mach_bsd4.3
+	exit ;;
+    RISC*:ULTRIX:*:*)
+	echo mips-dec-ultrix"$UNAME_RELEASE"
+	exit ;;
+    VAX*:ULTRIX*:*:*)
+	echo vax-dec-ultrix"$UNAME_RELEASE"
+	exit ;;
+    2020:CLIX:*:* | 2430:CLIX:*:*)
+	echo clipper-intergraph-clix"$UNAME_RELEASE"
+	exit ;;
+    mips:*:*:UMIPS | mips:*:*:RISCos)
+	set_cc_for_build
+	sed 's/^	//' << EOF > "$dummy.c"
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+	int main (int argc, char *argv[]) {
+#else
+	int main (argc, argv) int argc; char *argv[]; {
+#endif
+	#if defined (host_mips) && defined (MIPSEB)
+	#if defined (SYSTYPE_SYSV)
+	  printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_SVR4)
+	  printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+	  printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0);
+	#endif
+	#endif
+	  exit (-1);
+	}
+EOF
+	$CC_FOR_BUILD -o "$dummy" "$dummy.c" &&
+	  dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+	  SYSTEM_NAME=`"$dummy" "$dummyarg"` &&
+	    { echo "$SYSTEM_NAME"; exit; }
+	echo mips-mips-riscos"$UNAME_RELEASE"
+	exit ;;
+    Motorola:PowerMAX_OS:*:*)
+	echo powerpc-motorola-powermax
+	exit ;;
+    Motorola:*:4.3:PL8-*)
+	echo powerpc-harris-powermax
+	exit ;;
+    Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+	echo powerpc-harris-powermax
+	exit ;;
+    Night_Hawk:Power_UNIX:*:*)
+	echo powerpc-harris-powerunix
+	exit ;;
+    m88k:CX/UX:7*:*)
+	echo m88k-harris-cxux7
+	exit ;;
+    m88k:*:4*:R4*)
+	echo m88k-motorola-sysv4
+	exit ;;
+    m88k:*:3*:R3*)
+	echo m88k-motorola-sysv3
+	exit ;;
+    AViiON:dgux:*:*)
+	# DG/UX returns AViiON for all architectures
+	UNAME_PROCESSOR=`/usr/bin/uname -p`
+	if [ "$UNAME_PROCESSOR" = mc88100 ] || [ "$UNAME_PROCESSOR" = mc88110 ]
+	then
+	    if [ "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx ] || \
+	       [ "$TARGET_BINARY_INTERFACE"x = x ]
+	    then
+		echo m88k-dg-dgux"$UNAME_RELEASE"
+	    else
+		echo m88k-dg-dguxbcs"$UNAME_RELEASE"
+	    fi
+	else
+	    echo i586-dg-dgux"$UNAME_RELEASE"
+	fi
+	exit ;;
+    M88*:DolphinOS:*:*)	# DolphinOS (SVR3)
+	echo m88k-dolphin-sysv3
+	exit ;;
+    M88*:*:R3*:*)
+	# Delta 88k system running SVR3
+	echo m88k-motorola-sysv3
+	exit ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+	echo m88k-tektronix-sysv3
+	exit ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+	echo m68k-tektronix-bsd
+	exit ;;
+    *:IRIX*:*:*)
+	echo mips-sgi-irix"`echo "$UNAME_RELEASE"|sed -e 's/-/_/g'`"
+	exit ;;
+    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+	echo romp-ibm-aix     # uname -m gives an 8 hex-code CPU id
+	exit ;;               # Note that: echo "'`uname -s`'" gives 'AIX '
+    i*86:AIX:*:*)
+	echo i386-ibm-aix
+	exit ;;
+    ia64:AIX:*:*)
+	if [ -x /usr/bin/oslevel ] ; then
+		IBM_REV=`/usr/bin/oslevel`
+	else
+		IBM_REV="$UNAME_VERSION.$UNAME_RELEASE"
+	fi
+	echo "$UNAME_MACHINE"-ibm-aix"$IBM_REV"
+	exit ;;
+    *:AIX:2:3)
+	if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+		set_cc_for_build
+		sed 's/^		//' << EOF > "$dummy.c"
+		#include <sys/systemcfg.h>
+
+		main()
+			{
+			if (!__power_pc())
+				exit(1);
+			puts("powerpc-ibm-aix3.2.5");
+			exit(0);
+			}
+EOF
+		if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"`
+		then
+			echo "$SYSTEM_NAME"
+		else
+			echo rs6000-ibm-aix3.2.5
+		fi
+	elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+		echo rs6000-ibm-aix3.2.4
+	else
+		echo rs6000-ibm-aix3.2
+	fi
+	exit ;;
+    *:AIX:*:[4567])
+	IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+	if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then
+		IBM_ARCH=rs6000
+	else
+		IBM_ARCH=powerpc
+	fi
+	if [ -x /usr/bin/lslpp ] ; then
+		IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc |
+			   awk -F: '{ print $3 }' | sed s/[0-9]*$/0/`
+	else
+		IBM_REV="$UNAME_VERSION.$UNAME_RELEASE"
+	fi
+	echo "$IBM_ARCH"-ibm-aix"$IBM_REV"
+	exit ;;
+    *:AIX:*:*)
+	echo rs6000-ibm-aix
+	exit ;;
+    ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*)
+	echo romp-ibm-bsd4.4
+	exit ;;
+    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
+	echo romp-ibm-bsd"$UNAME_RELEASE"   # 4.3 with uname added to
+	exit ;;                             # report: romp-ibm BSD 4.3
+    *:BOSX:*:*)
+	echo rs6000-bull-bosx
+	exit ;;
+    DPX/2?00:B.O.S.:*:*)
+	echo m68k-bull-sysv3
+	exit ;;
+    9000/[34]??:4.3bsd:1.*:*)
+	echo m68k-hp-bsd
+	exit ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+	echo m68k-hp-bsd4.4
+	exit ;;
+    9000/[34678]??:HP-UX:*:*)
+	HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'`
+	case "$UNAME_MACHINE" in
+	    9000/31?)            HP_ARCH=m68000 ;;
+	    9000/[34]??)         HP_ARCH=m68k ;;
+	    9000/[678][0-9][0-9])
+		if [ -x /usr/bin/getconf ]; then
+		    sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+		    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+		    case "$sc_cpu_version" in
+		      523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0
+		      528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1
+		      532)                      # CPU_PA_RISC2_0
+			case "$sc_kernel_bits" in
+			  32) HP_ARCH=hppa2.0n ;;
+			  64) HP_ARCH=hppa2.0w ;;
+			  '') HP_ARCH=hppa2.0 ;;   # HP-UX 10.20
+			esac ;;
+		    esac
+		fi
+		if [ "$HP_ARCH" = "" ]; then
+		    set_cc_for_build
+		    sed 's/^		//' << EOF > "$dummy.c"
+
+		#define _HPUX_SOURCE
+		#include <stdlib.h>
+		#include <unistd.h>
+
+		int main ()
+		{
+		#if defined(_SC_KERNEL_BITS)
+		    long bits = sysconf(_SC_KERNEL_BITS);
+		#endif
+		    long cpu  = sysconf (_SC_CPU_VERSION);
+
+		    switch (cpu)
+			{
+			case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+			case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+			case CPU_PA_RISC2_0:
+		#if defined(_SC_KERNEL_BITS)
+			    switch (bits)
+				{
+				case 64: puts ("hppa2.0w"); break;
+				case 32: puts ("hppa2.0n"); break;
+				default: puts ("hppa2.0"); break;
+				} break;
+		#else  /* !defined(_SC_KERNEL_BITS) */
+			    puts ("hppa2.0"); break;
+		#endif
+			default: puts ("hppa1.0"); break;
+			}
+		    exit (0);
+		}
+EOF
+		    (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"`
+		    test -z "$HP_ARCH" && HP_ARCH=hppa
+		fi ;;
+	esac
+	if [ "$HP_ARCH" = hppa2.0w ]
+	then
+	    set_cc_for_build
+
+	    # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+	    # 32-bit code.  hppa64-hp-hpux* has the same kernel and a compiler
+	    # generating 64-bit code.  GNU and HP use different nomenclature:
+	    #
+	    # $ CC_FOR_BUILD=cc ./config.guess
+	    # => hppa2.0w-hp-hpux11.23
+	    # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+	    # => hppa64-hp-hpux11.23
+
+	    if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) |
+		grep -q __LP64__
+	    then
+		HP_ARCH=hppa2.0w
+	    else
+		HP_ARCH=hppa64
+	    fi
+	fi
+	echo "$HP_ARCH"-hp-hpux"$HPUX_REV"
+	exit ;;
+    ia64:HP-UX:*:*)
+	HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'`
+	echo ia64-hp-hpux"$HPUX_REV"
+	exit ;;
+    3050*:HI-UX:*:*)
+	set_cc_for_build
+	sed 's/^	//' << EOF > "$dummy.c"
+	#include <unistd.h>
+	int
+	main ()
+	{
+	  long cpu = sysconf (_SC_CPU_VERSION);
+	  /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+	     true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
+	     results, however.  */
+	  if (CPU_IS_PA_RISC (cpu))
+	    {
+	      switch (cpu)
+		{
+		  case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+		  default: puts ("hppa-hitachi-hiuxwe2"); break;
+		}
+	    }
+	  else if (CPU_IS_HP_MC68K (cpu))
+	    puts ("m68k-hitachi-hiuxwe2");
+	  else puts ("unknown-hitachi-hiuxwe2");
+	  exit (0);
+	}
+EOF
+	$CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` &&
+		{ echo "$SYSTEM_NAME"; exit; }
+	echo unknown-hitachi-hiuxwe2
+	exit ;;
+    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*)
+	echo hppa1.1-hp-bsd
+	exit ;;
+    9000/8??:4.3bsd:*:*)
+	echo hppa1.0-hp-bsd
+	exit ;;
+    *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+	echo hppa1.0-hp-mpeix
+	exit ;;
+    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*)
+	echo hppa1.1-hp-osf
+	exit ;;
+    hp8??:OSF1:*:*)
+	echo hppa1.0-hp-osf
+	exit ;;
+    i*86:OSF1:*:*)
+	if [ -x /usr/sbin/sysversion ] ; then
+	    echo "$UNAME_MACHINE"-unknown-osf1mk
+	else
+	    echo "$UNAME_MACHINE"-unknown-osf1
+	fi
+	exit ;;
+    parisc*:Lites*:*:*)
+	echo hppa1.1-hp-lites
+	exit ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+	echo c1-convex-bsd
+	exit ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+	exit ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+	echo c34-convex-bsd
+	exit ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+	echo c38-convex-bsd
+	exit ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+	echo c4-convex-bsd
+	exit ;;
+    CRAY*Y-MP:*:*:*)
+	echo ymp-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*[A-Z]90:*:*:*)
+	echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \
+	| sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+	      -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+	      -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*TS:*:*:*)
+	echo t90-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*T3E:*:*:*)
+	echo alphaev5-cray-unicosmk"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*SV1:*:*:*)
+	echo sv1-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    *:UNICOS/mp:*:*)
+	echo craynv-cray-unicosmp"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+	FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
+	FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
+	FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'`
+	echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+	exit ;;
+    5000:UNIX_System_V:4.*:*)
+	FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
+	FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'`
+	echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+	exit ;;
+    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+	echo "$UNAME_MACHINE"-pc-bsdi"$UNAME_RELEASE"
+	exit ;;
+    sparc*:BSD/OS:*:*)
+	echo sparc-unknown-bsdi"$UNAME_RELEASE"
+	exit ;;
+    *:BSD/OS:*:*)
+	echo "$UNAME_MACHINE"-unknown-bsdi"$UNAME_RELEASE"
+	exit ;;
+    arm:FreeBSD:*:*)
+	UNAME_PROCESSOR=`uname -p`
+	set_cc_for_build
+	if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
+	    | grep -q __ARM_PCS_VFP
+	then
+	    echo "${UNAME_PROCESSOR}"-unknown-freebsd"`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`"-gnueabi
+	else
+	    echo "${UNAME_PROCESSOR}"-unknown-freebsd"`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`"-gnueabihf
+	fi
+	exit ;;
+    *:FreeBSD:*:*)
+	UNAME_PROCESSOR=`/usr/bin/uname -p`
+	case "$UNAME_PROCESSOR" in
+	    amd64)
+		UNAME_PROCESSOR=x86_64 ;;
+	    i386)
+		UNAME_PROCESSOR=i586 ;;
+	esac
+	echo "$UNAME_PROCESSOR"-unknown-freebsd"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`"
+	exit ;;
+    i*:CYGWIN*:*)
+	echo "$UNAME_MACHINE"-pc-cygwin
+	exit ;;
+    *:MINGW64*:*)
+	echo "$UNAME_MACHINE"-pc-mingw64
+	exit ;;
+    *:MINGW*:*)
+	echo "$UNAME_MACHINE"-pc-mingw32
+	exit ;;
+    *:MSYS*:*)
+	echo "$UNAME_MACHINE"-pc-msys
+	exit ;;
+    i*:PW*:*)
+	echo "$UNAME_MACHINE"-pc-pw32
+	exit ;;
+    *:Interix*:*)
+	case "$UNAME_MACHINE" in
+	    x86)
+		echo i586-pc-interix"$UNAME_RELEASE"
+		exit ;;
+	    authenticamd | genuineintel | EM64T)
+		echo x86_64-unknown-interix"$UNAME_RELEASE"
+		exit ;;
+	    IA64)
+		echo ia64-unknown-interix"$UNAME_RELEASE"
+		exit ;;
+	esac ;;
+    i*:UWIN*:*)
+	echo "$UNAME_MACHINE"-pc-uwin
+	exit ;;
+    amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+	echo x86_64-pc-cygwin
+	exit ;;
+    prep*:SunOS:5.*:*)
+	echo powerpcle-unknown-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
+	exit ;;
+    *:GNU:*:*)
+	# the GNU system
+	echo "`echo "$UNAME_MACHINE"|sed -e 's,[-/].*$,,'`-unknown-$LIBC`echo "$UNAME_RELEASE"|sed -e 's,/.*$,,'`"
+	exit ;;
+    *:GNU/*:*:*)
+	# other systems with GNU libc and userland
+	echo "$UNAME_MACHINE-unknown-`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`-$LIBC"
+	exit ;;
+    *:Minix:*:*)
+	echo "$UNAME_MACHINE"-unknown-minix
+	exit ;;
+    aarch64:Linux:*:*)
+	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+	exit ;;
+    aarch64_be:Linux:*:*)
+	UNAME_MACHINE=aarch64_be
+	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+	exit ;;
+    alpha:Linux:*:*)
+	case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null` in
+	  EV5)   UNAME_MACHINE=alphaev5 ;;
+	  EV56)  UNAME_MACHINE=alphaev56 ;;
+	  PCA56) UNAME_MACHINE=alphapca56 ;;
+	  PCA57) UNAME_MACHINE=alphapca56 ;;
+	  EV6)   UNAME_MACHINE=alphaev6 ;;
+	  EV67)  UNAME_MACHINE=alphaev67 ;;
+	  EV68*) UNAME_MACHINE=alphaev68 ;;
+	esac
+	objdump --private-headers /bin/sh | grep -q ld.so.1
+	if test "$?" = 0 ; then LIBC=gnulibc1 ; fi
+	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+	exit ;;
+    arc:Linux:*:* | arceb:Linux:*:*)
+	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+	exit ;;
+    arm*:Linux:*:*)
+	set_cc_for_build
+	if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+	    | grep -q __ARM_EABI__
+	then
+	    echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+	else
+	    if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
+		| grep -q __ARM_PCS_VFP
+	    then
+		echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabi
+	    else
+		echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabihf
+	    fi
+	fi
+	exit ;;
+    avr32*:Linux:*:*)
+	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+	exit ;;
+    cris:Linux:*:*)
+	echo "$UNAME_MACHINE"-axis-linux-"$LIBC"
+	exit ;;
+    crisv32:Linux:*:*)
+	echo "$UNAME_MACHINE"-axis-linux-"$LIBC"
+	exit ;;
+    e2k:Linux:*:*)
+	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+	exit ;;
+    frv:Linux:*:*)
+	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+	exit ;;
+    hexagon:Linux:*:*)
+	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+	exit ;;
+    i*86:Linux:*:*)
+	echo "$UNAME_MACHINE"-pc-linux-"$LIBC"
+	exit ;;
+    ia64:Linux:*:*)
+	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+	exit ;;
+    k1om:Linux:*:*)
+	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+	exit ;;
+    m32r*:Linux:*:*)
+	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+	exit ;;
+    m68*:Linux:*:*)
+	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+	exit ;;
+    mips:Linux:*:* | mips64:Linux:*:*)
+	set_cc_for_build
+	IS_GLIBC=0
+	test x"${LIBC}" = xgnu && IS_GLIBC=1
+	sed 's/^	//' << EOF > "$dummy.c"
+	#undef CPU
+	#undef mips
+	#undef mipsel
+	#undef mips64
+	#undef mips64el
+	#if ${IS_GLIBC} && defined(_ABI64)
+	LIBCABI=gnuabi64
+	#else
+	#if ${IS_GLIBC} && defined(_ABIN32)
+	LIBCABI=gnuabin32
+	#else
+	LIBCABI=${LIBC}
+	#endif
+	#endif
+
+	#if ${IS_GLIBC} && defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6
+	CPU=mipsisa64r6
+	#else
+	#if ${IS_GLIBC} && !defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6
+	CPU=mipsisa32r6
+	#else
+	#if defined(__mips64)
+	CPU=mips64
+	#else
+	CPU=mips
+	#endif
+	#endif
+	#endif
+
+	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+	MIPS_ENDIAN=el
+	#else
+	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+	MIPS_ENDIAN=
+	#else
+	MIPS_ENDIAN=
+	#endif
+	#endif
+EOF
+	eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI'`"
+	test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; }
+	;;
+    mips64el:Linux:*:*)
+	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+	exit ;;
+    openrisc*:Linux:*:*)
+	echo or1k-unknown-linux-"$LIBC"
+	exit ;;
+    or32:Linux:*:* | or1k*:Linux:*:*)
+	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+	exit ;;
+    padre:Linux:*:*)
+	echo sparc-unknown-linux-"$LIBC"
+	exit ;;
+    parisc64:Linux:*:* | hppa64:Linux:*:*)
+	echo hppa64-unknown-linux-"$LIBC"
+	exit ;;
+    parisc:Linux:*:* | hppa:Linux:*:*)
+	# Look for CPU level
+	case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+	  PA7*) echo hppa1.1-unknown-linux-"$LIBC" ;;
+	  PA8*) echo hppa2.0-unknown-linux-"$LIBC" ;;
+	  *)    echo hppa-unknown-linux-"$LIBC" ;;
+	esac
+	exit ;;
+    ppc64:Linux:*:*)
+	echo powerpc64-unknown-linux-"$LIBC"
+	exit ;;
+    ppc:Linux:*:*)
+	echo powerpc-unknown-linux-"$LIBC"
+	exit ;;
+    ppc64le:Linux:*:*)
+	echo powerpc64le-unknown-linux-"$LIBC"
+	exit ;;
+    ppcle:Linux:*:*)
+	echo powerpcle-unknown-linux-"$LIBC"
+	exit ;;
+    riscv32:Linux:*:* | riscv64:Linux:*:*)
+	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+	exit ;;
+    s390:Linux:*:* | s390x:Linux:*:*)
+	echo "$UNAME_MACHINE"-ibm-linux-"$LIBC"
+	exit ;;
+    sh64*:Linux:*:*)
+	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+	exit ;;
+    sh*:Linux:*:*)
+	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+	exit ;;
+    sparc:Linux:*:* | sparc64:Linux:*:*)
+	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+	exit ;;
+    tile*:Linux:*:*)
+	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+	exit ;;
+    vax:Linux:*:*)
+	echo "$UNAME_MACHINE"-dec-linux-"$LIBC"
+	exit ;;
+    x86_64:Linux:*:*)
+	echo "$UNAME_MACHINE"-pc-linux-"$LIBC"
+	exit ;;
+    xtensa*:Linux:*:*)
+	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+	exit ;;
+    i*86:DYNIX/ptx:4*:*)
+	# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+	# earlier versions are messed up and put the nodename in both
+	# sysname and nodename.
+	echo i386-sequent-sysv4
+	exit ;;
+    i*86:UNIX_SV:4.2MP:2.*)
+	# Unixware is an offshoot of SVR4, but it has its own version
+	# number series starting with 2...
+	# I am not positive that other SVR4 systems won't match this,
+	# I just have to hope.  -- rms.
+	# Use sysv4.2uw... so that sysv4* matches it.
+	echo "$UNAME_MACHINE"-pc-sysv4.2uw"$UNAME_VERSION"
+	exit ;;
+    i*86:OS/2:*:*)
+	# If we were able to find `uname', then EMX Unix compatibility
+	# is probably installed.
+	echo "$UNAME_MACHINE"-pc-os2-emx
+	exit ;;
+    i*86:XTS-300:*:STOP)
+	echo "$UNAME_MACHINE"-unknown-stop
+	exit ;;
+    i*86:atheos:*:*)
+	echo "$UNAME_MACHINE"-unknown-atheos
+	exit ;;
+    i*86:syllable:*:*)
+	echo "$UNAME_MACHINE"-pc-syllable
+	exit ;;
+    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
+	echo i386-unknown-lynxos"$UNAME_RELEASE"
+	exit ;;
+    i*86:*DOS:*:*)
+	echo "$UNAME_MACHINE"-pc-msdosdjgpp
+	exit ;;
+    i*86:*:4.*:*)
+	UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'`
+	if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+		echo "$UNAME_MACHINE"-univel-sysv"$UNAME_REL"
+	else
+		echo "$UNAME_MACHINE"-pc-sysv"$UNAME_REL"
+	fi
+	exit ;;
+    i*86:*:5:[678]*)
+	# UnixWare 7.x, OpenUNIX and OpenServer 6.
+	case `/bin/uname -X | grep "^Machine"` in
+	    *486*)	     UNAME_MACHINE=i486 ;;
+	    *Pentium)	     UNAME_MACHINE=i586 ;;
+	    *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+	esac
+	echo "$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}"
+	exit ;;
+    i*86:*:3.2:*)
+	if test -f /usr/options/cb.name; then
+		UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+		echo "$UNAME_MACHINE"-pc-isc"$UNAME_REL"
+	elif /bin/uname -X 2>/dev/null >/dev/null ; then
+		UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+		(/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+		(/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+			&& UNAME_MACHINE=i586
+		(/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		(/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		echo "$UNAME_MACHINE"-pc-sco"$UNAME_REL"
+	else
+		echo "$UNAME_MACHINE"-pc-sysv32
+	fi
+	exit ;;
+    pc:*:*:*)
+	# Left here for compatibility:
+	# uname -m prints for DJGPP always 'pc', but it prints nothing about
+	# the processor, so we play safe by assuming i586.
+	# Note: whatever this is, it MUST be the same as what config.sub
+	# prints for the "djgpp" host, or else GDB configure will decide that
+	# this is a cross-build.
+	echo i586-pc-msdosdjgpp
+	exit ;;
+    Intel:Mach:3*:*)
+	echo i386-pc-mach3
+	exit ;;
+    paragon:*:*:*)
+	echo i860-intel-osf1
+	exit ;;
+    i860:*:4.*:*) # i860-SVR4
+	if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+	  echo i860-stardent-sysv"$UNAME_RELEASE" # Stardent Vistra i860-SVR4
+	else # Add other i860-SVR4 vendors below as they are discovered.
+	  echo i860-unknown-sysv"$UNAME_RELEASE"  # Unknown i860-SVR4
+	fi
+	exit ;;
+    mini*:CTIX:SYS*5:*)
+	# "miniframe"
+	echo m68010-convergent-sysv
+	exit ;;
+    mc68k:UNIX:SYSTEM5:3.51m)
+	echo m68k-convergent-sysv
+	exit ;;
+    M680?0:D-NIX:5.3:*)
+	echo m68k-diab-dnix
+	exit ;;
+    M68*:*:R3V[5678]*:*)
+	test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+    3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+	OS_REL=''
+	test -r /etc/.relid \
+	&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	  && { echo i486-ncr-sysv4.3"$OS_REL"; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+	  && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	  && { echo i486-ncr-sysv4; exit; } ;;
+    NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+	OS_REL='.3'
+	test -r /etc/.relid \
+	    && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	    && { echo i486-ncr-sysv4.3"$OS_REL"; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+	    && { echo i586-ncr-sysv4.3"$OS_REL"; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+	    && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;;
+    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+	echo m68k-unknown-lynxos"$UNAME_RELEASE"
+	exit ;;
+    mc68030:UNIX_System_V:4.*:*)
+	echo m68k-atari-sysv4
+	exit ;;
+    TSUNAMI:LynxOS:2.*:*)
+	echo sparc-unknown-lynxos"$UNAME_RELEASE"
+	exit ;;
+    rs6000:LynxOS:2.*:*)
+	echo rs6000-unknown-lynxos"$UNAME_RELEASE"
+	exit ;;
+    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
+	echo powerpc-unknown-lynxos"$UNAME_RELEASE"
+	exit ;;
+    SM[BE]S:UNIX_SV:*:*)
+	echo mips-dde-sysv"$UNAME_RELEASE"
+	exit ;;
+    RM*:ReliantUNIX-*:*:*)
+	echo mips-sni-sysv4
+	exit ;;
+    RM*:SINIX-*:*:*)
+	echo mips-sni-sysv4
+	exit ;;
+    *:SINIX-*:*:*)
+	if uname -p 2>/dev/null >/dev/null ; then
+		UNAME_MACHINE=`(uname -p) 2>/dev/null`
+		echo "$UNAME_MACHINE"-sni-sysv4
+	else
+		echo ns32k-sni-sysv
+	fi
+	exit ;;
+    PENTIUM:*:4.0*:*)	# Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+			# says <Richard.M.Bartel@ccMail.Census.GOV>
+	echo i586-unisys-sysv4
+	exit ;;
+    *:UNIX_System_V:4*:FTX*)
+	# From Gerald Hewes <hewes@openmarket.com>.
+	# How about differentiating between stratus architectures? -djm
+	echo hppa1.1-stratus-sysv4
+	exit ;;
+    *:*:*:FTX*)
+	# From seanf@swdc.stratus.com.
+	echo i860-stratus-sysv4
+	exit ;;
+    i*86:VOS:*:*)
+	# From Paul.Green@stratus.com.
+	echo "$UNAME_MACHINE"-stratus-vos
+	exit ;;
+    *:VOS:*:*)
+	# From Paul.Green@stratus.com.
+	echo hppa1.1-stratus-vos
+	exit ;;
+    mc68*:A/UX:*:*)
+	echo m68k-apple-aux"$UNAME_RELEASE"
+	exit ;;
+    news*:NEWS-OS:6*:*)
+	echo mips-sony-newsos6
+	exit ;;
+    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+	if [ -d /usr/nec ]; then
+		echo mips-nec-sysv"$UNAME_RELEASE"
+	else
+		echo mips-unknown-sysv"$UNAME_RELEASE"
+	fi
+	exit ;;
+    BeBox:BeOS:*:*)	# BeOS running on hardware made by Be, PPC only.
+	echo powerpc-be-beos
+	exit ;;
+    BeMac:BeOS:*:*)	# BeOS running on Mac or Mac clone, PPC only.
+	echo powerpc-apple-beos
+	exit ;;
+    BePC:BeOS:*:*)	# BeOS running on Intel PC compatible.
+	echo i586-pc-beos
+	exit ;;
+    BePC:Haiku:*:*)	# Haiku running on Intel PC compatible.
+	echo i586-pc-haiku
+	exit ;;
+    x86_64:Haiku:*:*)
+	echo x86_64-unknown-haiku
+	exit ;;
+    SX-4:SUPER-UX:*:*)
+	echo sx4-nec-superux"$UNAME_RELEASE"
+	exit ;;
+    SX-5:SUPER-UX:*:*)
+	echo sx5-nec-superux"$UNAME_RELEASE"
+	exit ;;
+    SX-6:SUPER-UX:*:*)
+	echo sx6-nec-superux"$UNAME_RELEASE"
+	exit ;;
+    SX-7:SUPER-UX:*:*)
+	echo sx7-nec-superux"$UNAME_RELEASE"
+	exit ;;
+    SX-8:SUPER-UX:*:*)
+	echo sx8-nec-superux"$UNAME_RELEASE"
+	exit ;;
+    SX-8R:SUPER-UX:*:*)
+	echo sx8r-nec-superux"$UNAME_RELEASE"
+	exit ;;
+    SX-ACE:SUPER-UX:*:*)
+	echo sxace-nec-superux"$UNAME_RELEASE"
+	exit ;;
+    Power*:Rhapsody:*:*)
+	echo powerpc-apple-rhapsody"$UNAME_RELEASE"
+	exit ;;
+    *:Rhapsody:*:*)
+	echo "$UNAME_MACHINE"-apple-rhapsody"$UNAME_RELEASE"
+	exit ;;
+    *:Darwin:*:*)
+	UNAME_PROCESSOR=`uname -p`
+	case $UNAME_PROCESSOR in
+	    unknown) UNAME_PROCESSOR=powerpc ;;
+	esac
+	if command -v xcode-select > /dev/null 2> /dev/null && \
+		! xcode-select --print-path > /dev/null 2> /dev/null ; then
+	    # Avoid executing cc if there is no toolchain installed as
+	    # cc will be a stub that puts up a graphical alert
+	    # prompting the user to install developer tools.
+	    CC_FOR_BUILD=no_compiler_found
+	else
+	    set_cc_for_build
+	fi
+	if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
+	    if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+		   (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+		   grep IS_64BIT_ARCH >/dev/null
+	    then
+		case $UNAME_PROCESSOR in
+		    i386) UNAME_PROCESSOR=x86_64 ;;
+		    powerpc) UNAME_PROCESSOR=powerpc64 ;;
+		esac
+	    fi
+	    # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc
+	    if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \
+		   (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+		   grep IS_PPC >/dev/null
+	    then
+		UNAME_PROCESSOR=powerpc
+	    fi
+	elif test "$UNAME_PROCESSOR" = i386 ; then
+	    # uname -m returns i386 or x86_64
+	    UNAME_PROCESSOR=$UNAME_MACHINE
+	fi
+	echo "$UNAME_PROCESSOR"-apple-darwin"$UNAME_RELEASE"
+	exit ;;
+    *:procnto*:*:* | *:QNX:[0123456789]*:*)
+	UNAME_PROCESSOR=`uname -p`
+	if test "$UNAME_PROCESSOR" = x86; then
+		UNAME_PROCESSOR=i386
+		UNAME_MACHINE=pc
+	fi
+	echo "$UNAME_PROCESSOR"-"$UNAME_MACHINE"-nto-qnx"$UNAME_RELEASE"
+	exit ;;
+    *:QNX:*:4*)
+	echo i386-pc-qnx
+	exit ;;
+    NEO-*:NONSTOP_KERNEL:*:*)
+	echo neo-tandem-nsk"$UNAME_RELEASE"
+	exit ;;
+    NSE-*:NONSTOP_KERNEL:*:*)
+	echo nse-tandem-nsk"$UNAME_RELEASE"
+	exit ;;
+    NSR-*:NONSTOP_KERNEL:*:*)
+	echo nsr-tandem-nsk"$UNAME_RELEASE"
+	exit ;;
+    NSV-*:NONSTOP_KERNEL:*:*)
+	echo nsv-tandem-nsk"$UNAME_RELEASE"
+	exit ;;
+    NSX-*:NONSTOP_KERNEL:*:*)
+	echo nsx-tandem-nsk"$UNAME_RELEASE"
+	exit ;;
+    *:NonStop-UX:*:*)
+	echo mips-compaq-nonstopux
+	exit ;;
+    BS2000:POSIX*:*:*)
+	echo bs2000-siemens-sysv
+	exit ;;
+    DS/*:UNIX_System_V:*:*)
+	echo "$UNAME_MACHINE"-"$UNAME_SYSTEM"-"$UNAME_RELEASE"
+	exit ;;
+    *:Plan9:*:*)
+	# "uname -m" is not consistent, so use $cputype instead. 386
+	# is converted to i386 for consistency with other x86
+	# operating systems.
+	# shellcheck disable=SC2154
+	if test "$cputype" = 386; then
+	    UNAME_MACHINE=i386
+	else
+	    UNAME_MACHINE="$cputype"
+	fi
+	echo "$UNAME_MACHINE"-unknown-plan9
+	exit ;;
+    *:TOPS-10:*:*)
+	echo pdp10-unknown-tops10
+	exit ;;
+    *:TENEX:*:*)
+	echo pdp10-unknown-tenex
+	exit ;;
+    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+	echo pdp10-dec-tops20
+	exit ;;
+    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+	echo pdp10-xkl-tops20
+	exit ;;
+    *:TOPS-20:*:*)
+	echo pdp10-unknown-tops20
+	exit ;;
+    *:ITS:*:*)
+	echo pdp10-unknown-its
+	exit ;;
+    SEI:*:*:SEIUX)
+	echo mips-sei-seiux"$UNAME_RELEASE"
+	exit ;;
+    *:DragonFly:*:*)
+	echo "$UNAME_MACHINE"-unknown-dragonfly"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`"
+	exit ;;
+    *:*VMS:*:*)
+	UNAME_MACHINE=`(uname -p) 2>/dev/null`
+	case "$UNAME_MACHINE" in
+	    A*) echo alpha-dec-vms ; exit ;;
+	    I*) echo ia64-dec-vms ; exit ;;
+	    V*) echo vax-dec-vms ; exit ;;
+	esac ;;
+    *:XENIX:*:SysV)
+	echo i386-pc-xenix
+	exit ;;
+    i*86:skyos:*:*)
+	echo "$UNAME_MACHINE"-pc-skyos"`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'`"
+	exit ;;
+    i*86:rdos:*:*)
+	echo "$UNAME_MACHINE"-pc-rdos
+	exit ;;
+    i*86:AROS:*:*)
+	echo "$UNAME_MACHINE"-pc-aros
+	exit ;;
+    x86_64:VMkernel:*:*)
+	echo "$UNAME_MACHINE"-unknown-esx
+	exit ;;
+    amd64:Isilon\ OneFS:*:*)
+	echo x86_64-unknown-onefs
+	exit ;;
+    *:Unleashed:*:*)
+	echo "$UNAME_MACHINE"-unknown-unleashed"$UNAME_RELEASE"
+	exit ;;
+esac
+
+# No uname command or uname output not recognized.
+set_cc_for_build
+cat > "$dummy.c" <<EOF
+#ifdef _SEQUENT_
+#include <sys/types.h>
+#include <sys/utsname.h>
+#endif
+#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__)
+#if defined (vax) || defined (__vax) || defined (__vax__) || defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__)
+#include <signal.h>
+#if defined(_SIZE_T_) || defined(SIGLOST)
+#include <sys/utsname.h>
+#endif
+#endif
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
+     I don't know....  */
+  printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+  printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+  "4"
+#else
+  ""
+#endif
+  ); exit (0);
+#endif
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+  int version;
+  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+  if (version < 4)
+    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+  else
+    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+  exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+  printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+  printf ("ns32k-encore-mach\n"); exit (0);
+#else
+  printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+  printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+  printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+  printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+  struct utsname un;
+
+  uname(&un);
+  if (strncmp(un.version, "V2", 2) == 0) {
+    printf ("i386-sequent-ptx2\n"); exit (0);
+  }
+  if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+    printf ("i386-sequent-ptx1\n"); exit (0);
+  }
+  printf ("i386-sequent-ptx\n"); exit (0);
+#endif
+
+#if defined (vax)
+#if !defined (ultrix)
+#include <sys/param.h>
+#if defined (BSD)
+#if BSD == 43
+  printf ("vax-dec-bsd4.3\n"); exit (0);
+#else
+#if BSD == 199006
+  printf ("vax-dec-bsd4.3reno\n"); exit (0);
+#else
+  printf ("vax-dec-bsd\n"); exit (0);
+#endif
+#endif
+#else
+  printf ("vax-dec-bsd\n"); exit (0);
+#endif
+#else
+#if defined(_SIZE_T_) || defined(SIGLOST)
+  struct utsname un;
+  uname (&un);
+  printf ("vax-dec-ultrix%s\n", un.release); exit (0);
+#else
+  printf ("vax-dec-ultrix\n"); exit (0);
+#endif
+#endif
+#endif
+#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__)
+#if defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__)
+#if defined(_SIZE_T_) || defined(SIGLOST)
+  struct utsname *un;
+  uname (&un);
+  printf ("mips-dec-ultrix%s\n", un.release); exit (0);
+#else
+  printf ("mips-dec-ultrix\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (alliant) && defined (i860)
+  printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+  exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+	{ echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+test -d /usr/apollo && { echo "$ISP-apollo-$SYSTYPE"; exit; }
+
+echo "$0: unable to guess system type" >&2
+
+case "$UNAME_MACHINE:$UNAME_SYSTEM" in
+    mips:Linux | mips64:Linux)
+	# If we got here on MIPS GNU/Linux, output extra information.
+	cat >&2 <<EOF
+
+NOTE: MIPS GNU/Linux systems require a C compiler to fully recognize
+the system type. Please install a C compiler and try again.
+EOF
+	;;
+esac
+
+cat >&2 <<EOF
+
+This script (version $timestamp), has failed to recognize the
+operating system you are using. If your script is old, overwrite *all*
+copies of config.guess and config.sub with the latest versions from:
+
+  https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
+and
+  https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
+
+If $0 has already been updated, send the following data and any
+information you think might be pertinent to config-patches@gnu.org to
+provide the necessary information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo               = `(hostinfo) 2>/dev/null`
+/bin/universe          = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch              = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = "$UNAME_MACHINE"
+UNAME_RELEASE = "$UNAME_RELEASE"
+UNAME_SYSTEM  = "$UNAME_SYSTEM"
+UNAME_VERSION = "$UNAME_VERSION"
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/third_party/gmp/configfsf.sub b/third_party/gmp/configfsf.sub
new file mode 100644
index 0000000..f02d43a
--- /dev/null
+++ b/third_party/gmp/configfsf.sub
@@ -0,0 +1,1793 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+#   Copyright 1992-2020 Free Software Foundation, Inc.
+
+timestamp='2020-01-01'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that
+# program.  This Exception is an additional permission under section 7
+# of the GNU General Public License, version 3 ("GPLv3").
+
+
+# Please send patches to <config-patches@gnu.org>.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# You can get the latest version of this script from:
+# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support.  The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+#	CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+#	CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS
+
+Canonicalize a configuration name.
+
+Options:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright 1992-2020 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help" >&2
+       exit 1 ;;
+
+    *local*)
+       # First pass through any local machine types.
+       echo "$1"
+       exit ;;
+
+    * )
+       break ;;
+  esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+    exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+    exit 1;;
+esac
+
+# Split fields of configuration type
+# shellcheck disable=SC2162
+IFS="-" read field1 field2 field3 field4 <<EOF
+$1
+EOF
+
+# Separate into logical components for further validation
+case $1 in
+	*-*-*-*-*)
+		echo Invalid configuration \`"$1"\': more than four components >&2
+		exit 1
+		;;
+	*-*-*-*)
+		basic_machine=$field1-$field2
+		os=$field3-$field4
+		;;
+	*-*-*)
+		# Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two
+		# parts
+		maybe_os=$field2-$field3
+		case $maybe_os in
+			nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc \
+			| linux-newlib* | linux-musl* | linux-uclibc* | uclinux-uclibc* \
+			| uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \
+			| netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \
+			| storm-chaos* | os2-emx* | rtmk-nova*)
+				basic_machine=$field1
+				os=$maybe_os
+				;;
+			android-linux)
+				basic_machine=$field1-unknown
+				os=linux-android
+				;;
+			*)
+				basic_machine=$field1-$field2
+				os=$field3
+				;;
+		esac
+		;;
+	*-*)
+		# A lone config we happen to match not fitting any pattern
+		case $field1-$field2 in
+			decstation-3100)
+				basic_machine=mips-dec
+				os=
+				;;
+			*-*)
+				# Second component is usually, but not always the OS
+				case $field2 in
+					# Prevent following clause from handling this valid os
+					sun*os*)
+						basic_machine=$field1
+						os=$field2
+						;;
+					# Manufacturers
+					dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \
+					| att* | 7300* | 3300* | delta* | motorola* | sun[234]* \
+					| unicom* | ibm* | next | hp | isi* | apollo | altos* \
+					| convergent* | ncr* | news | 32* | 3600* | 3100* \
+					| hitachi* | c[123]* | convex* | sun | crds | omron* | dg \
+					| ultra | tti* | harris | dolphin | highlevel | gould \
+					| cbm | ns | masscomp | apple | axis | knuth | cray \
+					| microblaze* | sim | cisco \
+					| oki | wec | wrs | winbond)
+						basic_machine=$field1-$field2
+						os=
+						;;
+					*)
+						basic_machine=$field1
+						os=$field2
+						;;
+				esac
+			;;
+		esac
+		;;
+	*)
+		# Convert single-component short-hands not valid as part of
+		# multi-component configurations.
+		case $field1 in
+			386bsd)
+				basic_machine=i386-pc
+				os=bsd
+				;;
+			a29khif)
+				basic_machine=a29k-amd
+				os=udi
+				;;
+			adobe68k)
+				basic_machine=m68010-adobe
+				os=scout
+				;;
+			alliant)
+				basic_machine=fx80-alliant
+				os=
+				;;
+			altos | altos3068)
+				basic_machine=m68k-altos
+				os=
+				;;
+			am29k)
+				basic_machine=a29k-none
+				os=bsd
+				;;
+			amdahl)
+				basic_machine=580-amdahl
+				os=sysv
+				;;
+			amiga)
+				basic_machine=m68k-unknown
+				os=
+				;;
+			amigaos | amigados)
+				basic_machine=m68k-unknown
+				os=amigaos
+				;;
+			amigaunix | amix)
+				basic_machine=m68k-unknown
+				os=sysv4
+				;;
+			apollo68)
+				basic_machine=m68k-apollo
+				os=sysv
+				;;
+			apollo68bsd)
+				basic_machine=m68k-apollo
+				os=bsd
+				;;
+			aros)
+				basic_machine=i386-pc
+				os=aros
+				;;
+			aux)
+				basic_machine=m68k-apple
+				os=aux
+				;;
+			balance)
+				basic_machine=ns32k-sequent
+				os=dynix
+				;;
+			blackfin)
+				basic_machine=bfin-unknown
+				os=linux
+				;;
+			cegcc)
+				basic_machine=arm-unknown
+				os=cegcc
+				;;
+			convex-c1)
+				basic_machine=c1-convex
+				os=bsd
+				;;
+			convex-c2)
+				basic_machine=c2-convex
+				os=bsd
+				;;
+			convex-c32)
+				basic_machine=c32-convex
+				os=bsd
+				;;
+			convex-c34)
+				basic_machine=c34-convex
+				os=bsd
+				;;
+			convex-c38)
+				basic_machine=c38-convex
+				os=bsd
+				;;
+			cray)
+				basic_machine=j90-cray
+				os=unicos
+				;;
+			crds | unos)
+				basic_machine=m68k-crds
+				os=
+				;;
+			da30)
+				basic_machine=m68k-da30
+				os=
+				;;
+			decstation | pmax | pmin | dec3100 | decstatn)
+				basic_machine=mips-dec
+				os=
+				;;
+			delta88)
+				basic_machine=m88k-motorola
+				os=sysv3
+				;;
+			dicos)
+				basic_machine=i686-pc
+				os=dicos
+				;;
+			djgpp)
+				basic_machine=i586-pc
+				os=msdosdjgpp
+				;;
+			ebmon29k)
+				basic_machine=a29k-amd
+				os=ebmon
+				;;
+			es1800 | OSE68k | ose68k | ose | OSE)
+				basic_machine=m68k-ericsson
+				os=ose
+				;;
+			gmicro)
+				basic_machine=tron-gmicro
+				os=sysv
+				;;
+			go32)
+				basic_machine=i386-pc
+				os=go32
+				;;
+			h8300hms)
+				basic_machine=h8300-hitachi
+				os=hms
+				;;
+			h8300xray)
+				basic_machine=h8300-hitachi
+				os=xray
+				;;
+			h8500hms)
+				basic_machine=h8500-hitachi
+				os=hms
+				;;
+			harris)
+				basic_machine=m88k-harris
+				os=sysv3
+				;;
+			hp300 | hp300hpux)
+				basic_machine=m68k-hp
+				os=hpux
+				;;
+			hp300bsd)
+				basic_machine=m68k-hp
+				os=bsd
+				;;
+			hppaosf)
+				basic_machine=hppa1.1-hp
+				os=osf
+				;;
+			hppro)
+				basic_machine=hppa1.1-hp
+				os=proelf
+				;;
+			i386mach)
+				basic_machine=i386-mach
+				os=mach
+				;;
+			isi68 | isi)
+				basic_machine=m68k-isi
+				os=sysv
+				;;
+			m68knommu)
+				basic_machine=m68k-unknown
+				os=linux
+				;;
+			magnum | m3230)
+				basic_machine=mips-mips
+				os=sysv
+				;;
+			merlin)
+				basic_machine=ns32k-utek
+				os=sysv
+				;;
+			mingw64)
+				basic_machine=x86_64-pc
+				os=mingw64
+				;;
+			mingw32)
+				basic_machine=i686-pc
+				os=mingw32
+				;;
+			mingw32ce)
+				basic_machine=arm-unknown
+				os=mingw32ce
+				;;
+			monitor)
+				basic_machine=m68k-rom68k
+				os=coff
+				;;
+			morphos)
+				basic_machine=powerpc-unknown
+				os=morphos
+				;;
+			moxiebox)
+				basic_machine=moxie-unknown
+				os=moxiebox
+				;;
+			msdos)
+				basic_machine=i386-pc
+				os=msdos
+				;;
+			msys)
+				basic_machine=i686-pc
+				os=msys
+				;;
+			mvs)
+				basic_machine=i370-ibm
+				os=mvs
+				;;
+			nacl)
+				basic_machine=le32-unknown
+				os=nacl
+				;;
+			ncr3000)
+				basic_machine=i486-ncr
+				os=sysv4
+				;;
+			netbsd386)
+				basic_machine=i386-pc
+				os=netbsd
+				;;
+			netwinder)
+				basic_machine=armv4l-rebel
+				os=linux
+				;;
+			news | news700 | news800 | news900)
+				basic_machine=m68k-sony
+				os=newsos
+				;;
+			news1000)
+				basic_machine=m68030-sony
+				os=newsos
+				;;
+			necv70)
+				basic_machine=v70-nec
+				os=sysv
+				;;
+			nh3000)
+				basic_machine=m68k-harris
+				os=cxux
+				;;
+			nh[45]000)
+				basic_machine=m88k-harris
+				os=cxux
+				;;
+			nindy960)
+				basic_machine=i960-intel
+				os=nindy
+				;;
+			mon960)
+				basic_machine=i960-intel
+				os=mon960
+				;;
+			nonstopux)
+				basic_machine=mips-compaq
+				os=nonstopux
+				;;
+			os400)
+				basic_machine=powerpc-ibm
+				os=os400
+				;;
+			OSE68000 | ose68000)
+				basic_machine=m68000-ericsson
+				os=ose
+				;;
+			os68k)
+				basic_machine=m68k-none
+				os=os68k
+				;;
+			paragon)
+				basic_machine=i860-intel
+				os=osf
+				;;
+			parisc)
+				basic_machine=hppa-unknown
+				os=linux
+				;;
+			pw32)
+				basic_machine=i586-unknown
+				os=pw32
+				;;
+			rdos | rdos64)
+				basic_machine=x86_64-pc
+				os=rdos
+				;;
+			rdos32)
+				basic_machine=i386-pc
+				os=rdos
+				;;
+			rom68k)
+				basic_machine=m68k-rom68k
+				os=coff
+				;;
+			sa29200)
+				basic_machine=a29k-amd
+				os=udi
+				;;
+			sei)
+				basic_machine=mips-sei
+				os=seiux
+				;;
+			sequent)
+				basic_machine=i386-sequent
+				os=
+				;;
+			sps7)
+				basic_machine=m68k-bull
+				os=sysv2
+				;;
+			st2000)
+				basic_machine=m68k-tandem
+				os=
+				;;
+			stratus)
+				basic_machine=i860-stratus
+				os=sysv4
+				;;
+			sun2)
+				basic_machine=m68000-sun
+				os=
+				;;
+			sun2os3)
+				basic_machine=m68000-sun
+				os=sunos3
+				;;
+			sun2os4)
+				basic_machine=m68000-sun
+				os=sunos4
+				;;
+			sun3)
+				basic_machine=m68k-sun
+				os=
+				;;
+			sun3os3)
+				basic_machine=m68k-sun
+				os=sunos3
+				;;
+			sun3os4)
+				basic_machine=m68k-sun
+				os=sunos4
+				;;
+			sun4)
+				basic_machine=sparc-sun
+				os=
+				;;
+			sun4os3)
+				basic_machine=sparc-sun
+				os=sunos3
+				;;
+			sun4os4)
+				basic_machine=sparc-sun
+				os=sunos4
+				;;
+			sun4sol2)
+				basic_machine=sparc-sun
+				os=solaris2
+				;;
+			sun386 | sun386i | roadrunner)
+				basic_machine=i386-sun
+				os=
+				;;
+			sv1)
+				basic_machine=sv1-cray
+				os=unicos
+				;;
+			symmetry)
+				basic_machine=i386-sequent
+				os=dynix
+				;;
+			t3e)
+				basic_machine=alphaev5-cray
+				os=unicos
+				;;
+			t90)
+				basic_machine=t90-cray
+				os=unicos
+				;;
+			toad1)
+				basic_machine=pdp10-xkl
+				os=tops20
+				;;
+			tpf)
+				basic_machine=s390x-ibm
+				os=tpf
+				;;
+			udi29k)
+				basic_machine=a29k-amd
+				os=udi
+				;;
+			ultra3)
+				basic_machine=a29k-nyu
+				os=sym1
+				;;
+			v810 | necv810)
+				basic_machine=v810-nec
+				os=none
+				;;
+			vaxv)
+				basic_machine=vax-dec
+				os=sysv
+				;;
+			vms)
+				basic_machine=vax-dec
+				os=vms
+				;;
+			vsta)
+				basic_machine=i386-pc
+				os=vsta
+				;;
+			vxworks960)
+				basic_machine=i960-wrs
+				os=vxworks
+				;;
+			vxworks68)
+				basic_machine=m68k-wrs
+				os=vxworks
+				;;
+			vxworks29k)
+				basic_machine=a29k-wrs
+				os=vxworks
+				;;
+			xbox)
+				basic_machine=i686-pc
+				os=mingw32
+				;;
+			ymp)
+				basic_machine=ymp-cray
+				os=unicos
+				;;
+			*)
+				basic_machine=$1
+				os=
+				;;
+		esac
+		;;
+esac
+
+# Decode 1-component or ad-hoc basic machines
+case $basic_machine in
+	# Here we handle the default manufacturer of certain CPU types.  It is in
+	# some cases the only manufacturer, in others, it is the most popular.
+	w89k)
+		cpu=hppa1.1
+		vendor=winbond
+		;;
+	op50n)
+		cpu=hppa1.1
+		vendor=oki
+		;;
+	op60c)
+		cpu=hppa1.1
+		vendor=oki
+		;;
+	ibm*)
+		cpu=i370
+		vendor=ibm
+		;;
+	orion105)
+		cpu=clipper
+		vendor=highlevel
+		;;
+	mac | mpw | mac-mpw)
+		cpu=m68k
+		vendor=apple
+		;;
+	pmac | pmac-mpw)
+		cpu=powerpc
+		vendor=apple
+		;;
+
+	# Recognize the various machine names and aliases which stand
+	# for a CPU type and a company and sometimes even an OS.
+	3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+		cpu=m68000
+		vendor=att
+		;;
+	3b*)
+		cpu=we32k
+		vendor=att
+		;;
+	bluegene*)
+		cpu=powerpc
+		vendor=ibm
+		os=cnk
+		;;
+	decsystem10* | dec10*)
+		cpu=pdp10
+		vendor=dec
+		os=tops10
+		;;
+	decsystem20* | dec20*)
+		cpu=pdp10
+		vendor=dec
+		os=tops20
+		;;
+	delta | 3300 | motorola-3300 | motorola-delta \
+	      | 3300-motorola | delta-motorola)
+		cpu=m68k
+		vendor=motorola
+		;;
+	dpx2*)
+		cpu=m68k
+		vendor=bull
+		os=sysv3
+		;;
+	encore | umax | mmax)
+		cpu=ns32k
+		vendor=encore
+		;;
+	elxsi)
+		cpu=elxsi
+		vendor=elxsi
+		os=${os:-bsd}
+		;;
+	fx2800)
+		cpu=i860
+		vendor=alliant
+		;;
+	genix)
+		cpu=ns32k
+		vendor=ns
+		;;
+	h3050r* | hiux*)
+		cpu=hppa1.1
+		vendor=hitachi
+		os=hiuxwe2
+		;;
+	hp3k9[0-9][0-9] | hp9[0-9][0-9])
+		cpu=hppa1.0
+		vendor=hp
+		;;
+	hp9k2[0-9][0-9] | hp9k31[0-9])
+		cpu=m68000
+		vendor=hp
+		;;
+	hp9k3[2-9][0-9])
+		cpu=m68k
+		vendor=hp
+		;;
+	hp9k6[0-9][0-9] | hp6[0-9][0-9])
+		cpu=hppa1.0
+		vendor=hp
+		;;
+	hp9k7[0-79][0-9] | hp7[0-79][0-9])
+		cpu=hppa1.1
+		vendor=hp
+		;;
+	hp9k78[0-9] | hp78[0-9])
+		# FIXME: really hppa2.0-hp
+		cpu=hppa1.1
+		vendor=hp
+		;;
+	hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+		# FIXME: really hppa2.0-hp
+		cpu=hppa1.1
+		vendor=hp
+		;;
+	hp9k8[0-9][13679] | hp8[0-9][13679])
+		cpu=hppa1.1
+		vendor=hp
+		;;
+	hp9k8[0-9][0-9] | hp8[0-9][0-9])
+		cpu=hppa1.0
+		vendor=hp
+		;;
+	i*86v32)
+		cpu=`echo "$1" | sed -e 's/86.*/86/'`
+		vendor=pc
+		os=sysv32
+		;;
+	i*86v4*)
+		cpu=`echo "$1" | sed -e 's/86.*/86/'`
+		vendor=pc
+		os=sysv4
+		;;
+	i*86v)
+		cpu=`echo "$1" | sed -e 's/86.*/86/'`
+		vendor=pc
+		os=sysv
+		;;
+	i*86sol2)
+		cpu=`echo "$1" | sed -e 's/86.*/86/'`
+		vendor=pc
+		os=solaris2
+		;;
+	j90 | j90-cray)
+		cpu=j90
+		vendor=cray
+		os=${os:-unicos}
+		;;
+	iris | iris4d)
+		cpu=mips
+		vendor=sgi
+		case $os in
+		    irix*)
+			;;
+		    *)
+			os=irix4
+			;;
+		esac
+		;;
+	miniframe)
+		cpu=m68000
+		vendor=convergent
+		;;
+	*mint | mint[0-9]* | *MiNT | *MiNT[0-9]*)
+		cpu=m68k
+		vendor=atari
+		os=mint
+		;;
+	news-3600 | risc-news)
+		cpu=mips
+		vendor=sony
+		os=newsos
+		;;
+	next | m*-next)
+		cpu=m68k
+		vendor=next
+		case $os in
+		    openstep*)
+		        ;;
+		    nextstep*)
+			;;
+		    ns2*)
+		      os=nextstep2
+			;;
+		    *)
+		      os=nextstep3
+			;;
+		esac
+		;;
+	np1)
+		cpu=np1
+		vendor=gould
+		;;
+	op50n-* | op60c-*)
+		cpu=hppa1.1
+		vendor=oki
+		os=proelf
+		;;
+	pa-hitachi)
+		cpu=hppa1.1
+		vendor=hitachi
+		os=hiuxwe2
+		;;
+	pbd)
+		cpu=sparc
+		vendor=tti
+		;;
+	pbb)
+		cpu=m68k
+		vendor=tti
+		;;
+	pc532)
+		cpu=ns32k
+		vendor=pc532
+		;;
+	pn)
+		cpu=pn
+		vendor=gould
+		;;
+	power)
+		cpu=power
+		vendor=ibm
+		;;
+	ps2)
+		cpu=i386
+		vendor=ibm
+		;;
+	rm[46]00)
+		cpu=mips
+		vendor=siemens
+		;;
+	rtpc | rtpc-*)
+		cpu=romp
+		vendor=ibm
+		;;
+	sde)
+		cpu=mipsisa32
+		vendor=sde
+		os=${os:-elf}
+		;;
+	simso-wrs)
+		cpu=sparclite
+		vendor=wrs
+		os=vxworks
+		;;
+	tower | tower-32)
+		cpu=m68k
+		vendor=ncr
+		;;
+	vpp*|vx|vx-*)
+		cpu=f301
+		vendor=fujitsu
+		;;
+	w65)
+		cpu=w65
+		vendor=wdc
+		;;
+	w89k-*)
+		cpu=hppa1.1
+		vendor=winbond
+		os=proelf
+		;;
+	none)
+		cpu=none
+		vendor=none
+		;;
+	leon|leon[3-9])
+		cpu=sparc
+		vendor=$basic_machine
+		;;
+	leon-*|leon[3-9]-*)
+		cpu=sparc
+		vendor=`echo "$basic_machine" | sed 's/-.*//'`
+		;;
+
+	*-*)
+		# shellcheck disable=SC2162
+		IFS="-" read cpu vendor <<EOF
+$basic_machine
+EOF
+		;;
+	# We use `pc' rather than `unknown'
+	# because (1) that's what they normally are, and
+	# (2) the word "unknown" tends to confuse beginning users.
+	i*86 | x86_64)
+		cpu=$basic_machine
+		vendor=pc
+		;;
+	# These rules are duplicated from below for sake of the special case above;
+	# i.e. things that normalized to x86 arches should also default to "pc"
+	pc98)
+		cpu=i386
+		vendor=pc
+		;;
+	x64 | amd64)
+		cpu=x86_64
+		vendor=pc
+		;;
+	# Recognize the basic CPU types without company name.
+	*)
+		cpu=$basic_machine
+		vendor=unknown
+		;;
+esac
+
+unset -v basic_machine
+
+# Decode basic machines in the full and proper CPU-Company form.
+case $cpu-$vendor in
+	# Here we handle the default manufacturer of certain CPU types in canonical form. It is in
+	# some cases the only manufacturer, in others, it is the most popular.
+	craynv-unknown)
+		vendor=cray
+		os=${os:-unicosmp}
+		;;
+	c90-unknown | c90-cray)
+		vendor=cray
+		os=${os:-unicos}
+		;;
+	fx80-unknown)
+		vendor=alliant
+		;;
+	romp-unknown)
+		vendor=ibm
+		;;
+	mmix-unknown)
+		vendor=knuth
+		;;
+	microblaze-unknown | microblazeel-unknown)
+		vendor=xilinx
+		;;
+	rs6000-unknown)
+		vendor=ibm
+		;;
+	vax-unknown)
+		vendor=dec
+		;;
+	pdp11-unknown)
+		vendor=dec
+		;;
+	we32k-unknown)
+		vendor=att
+		;;
+	cydra-unknown)
+		vendor=cydrome
+		;;
+	i370-ibm*)
+		vendor=ibm
+		;;
+	orion-unknown)
+		vendor=highlevel
+		;;
+	xps-unknown | xps100-unknown)
+		cpu=xps100
+		vendor=honeywell
+		;;
+
+	# Here we normalize CPU types with a missing or matching vendor
+	dpx20-unknown | dpx20-bull)
+		cpu=rs6000
+		vendor=bull
+		os=${os:-bosx}
+		;;
+
+	# Here we normalize CPU types irrespective of the vendor
+	amd64-*)
+		cpu=x86_64
+		;;
+	blackfin-*)
+		cpu=bfin
+		os=linux
+		;;
+	c54x-*)
+		cpu=tic54x
+		;;
+	c55x-*)
+		cpu=tic55x
+		;;
+	c6x-*)
+		cpu=tic6x
+		;;
+	e500v[12]-*)
+		cpu=powerpc
+		os=$os"spe"
+		;;
+	mips3*-*)
+		cpu=mips64
+		;;
+	ms1-*)
+		cpu=mt
+		;;
+	m68knommu-*)
+		cpu=m68k
+		os=linux
+		;;
+	m9s12z-* | m68hcs12z-* | hcs12z-* | s12z-*)
+		cpu=s12z
+		;;
+	openrisc-*)
+		cpu=or32
+		;;
+	parisc-*)
+		cpu=hppa
+		os=linux
+		;;
+	pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+		cpu=i586
+		;;
+	pentiumpro-* | p6-* | 6x86-* | athlon-* | athalon_*-*)
+		cpu=i686
+		;;
+	pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+		cpu=i686
+		;;
+	pentium4-*)
+		cpu=i786
+		;;
+	pc98-*)
+		cpu=i386
+		;;
+	ppc-* | ppcbe-*)
+		cpu=powerpc
+		;;
+	ppcle-* | powerpclittle-*)
+		cpu=powerpcle
+		;;
+	ppc64-*)
+		cpu=powerpc64
+		;;
+	ppc64le-* | powerpc64little-*)
+		cpu=powerpc64le
+		;;
+	sb1-*)
+		cpu=mipsisa64sb1
+		;;
+	sb1el-*)
+		cpu=mipsisa64sb1el
+		;;
+	sh5e[lb]-*)
+		cpu=`echo "$cpu" | sed 's/^\(sh.\)e\(.\)$/\1\2e/'`
+		;;
+	spur-*)
+		cpu=spur
+		;;
+	strongarm-* | thumb-*)
+		cpu=arm
+		;;
+	tx39-*)
+		cpu=mipstx39
+		;;
+	tx39el-*)
+		cpu=mipstx39el
+		;;
+	x64-*)
+		cpu=x86_64
+		;;
+	xscale-* | xscalee[bl]-*)
+		cpu=`echo "$cpu" | sed 's/^xscale/arm/'`
+		;;
+
+	# Recognize the canonical CPU Types that limit and/or modify the
+	# company names they are paired with.
+	cr16-*)
+		os=${os:-elf}
+		;;
+	crisv32-* | etraxfs*-*)
+		cpu=crisv32
+		vendor=axis
+		;;
+	cris-* | etrax*-*)
+		cpu=cris
+		vendor=axis
+		;;
+	crx-*)
+		os=${os:-elf}
+		;;
+	neo-tandem)
+		cpu=neo
+		vendor=tandem
+		;;
+	nse-tandem)
+		cpu=nse
+		vendor=tandem
+		;;
+	nsr-tandem)
+		cpu=nsr
+		vendor=tandem
+		;;
+	nsv-tandem)
+		cpu=nsv
+		vendor=tandem
+		;;
+	nsx-tandem)
+		cpu=nsx
+		vendor=tandem
+		;;
+	s390-*)
+		cpu=s390
+		vendor=ibm
+		;;
+	s390x-*)
+		cpu=s390x
+		vendor=ibm
+		;;
+	tile*-*)
+		os=${os:-linux-gnu}
+		;;
+
+	*)
+		# Recognize the canonical CPU types that are allowed with any
+		# company name.
+		case $cpu in
+			1750a | 580 \
+			| a29k \
+			| aarch64 | aarch64_be \
+			| abacus \
+			| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] \
+			| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] \
+			| alphapca5[67] | alpha64pca5[67] \
+			| am33_2.0 \
+			| amdgcn \
+			| arc | arceb \
+			| arm  | arm[lb]e | arme[lb] | armv* \
+			| avr | avr32 \
+			| asmjs \
+			| ba \
+			| be32 | be64 \
+			| bfin | bpf | bs2000 \
+			| c[123]* | c30 | [cjt]90 | c4x \
+			| c8051 | clipper | craynv | csky | cydra \
+			| d10v | d30v | dlx | dsp16xx \
+			| e2k | elxsi | epiphany \
+			| f30[01] | f700 | fido | fr30 | frv | ft32 | fx80 \
+			| h8300 | h8500 \
+			| hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+			| hexagon \
+			| i370 | i*86 | i860 | i960 | ia16 | ia64 \
+			| ip2k | iq2000 \
+			| k1om \
+			| le32 | le64 \
+			| lm32 \
+			| m32c | m32r | m32rle \
+			| m5200 | m68000 | m680[012346]0 | m68360 | m683?2 | m68k \
+			| m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x \
+			| m88110 | m88k | maxq | mb | mcore | mep | metag \
+			| microblaze | microblazeel \
+			| mips | mipsbe | mipseb | mipsel | mipsle \
+			| mips16 \
+			| mips64 | mips64eb | mips64el \
+			| mips64octeon | mips64octeonel \
+			| mips64orion | mips64orionel \
+			| mips64r5900 | mips64r5900el \
+			| mips64vr | mips64vrel \
+			| mips64vr4100 | mips64vr4100el \
+			| mips64vr4300 | mips64vr4300el \
+			| mips64vr5000 | mips64vr5000el \
+			| mips64vr5900 | mips64vr5900el \
+			| mipsisa32 | mipsisa32el \
+			| mipsisa32r2 | mipsisa32r2el \
+			| mipsisa32r6 | mipsisa32r6el \
+			| mipsisa64 | mipsisa64el \
+			| mipsisa64r2 | mipsisa64r2el \
+			| mipsisa64r6 | mipsisa64r6el \
+			| mipsisa64sb1 | mipsisa64sb1el \
+			| mipsisa64sr71k | mipsisa64sr71kel \
+			| mipsr5900 | mipsr5900el \
+			| mipstx39 | mipstx39el \
+			| mmix \
+			| mn10200 | mn10300 \
+			| moxie \
+			| mt \
+			| msp430 \
+			| nds32 | nds32le | nds32be \
+			| nfp \
+			| nios | nios2 | nios2eb | nios2el \
+			| none | np1 | ns16k | ns32k | nvptx \
+			| open8 \
+			| or1k* \
+			| or32 \
+			| orion \
+			| picochip \
+			| pdp10 | pdp11 | pj | pjl | pn | power \
+			| powerpc | powerpc64 | powerpc64le | powerpcle | powerpcspe \
+			| pru \
+			| pyramid \
+			| riscv | riscv32 | riscv64 \
+			| rl78 | romp | rs6000 | rx \
+			| score \
+			| sh | shl \
+			| sh[1234] | sh[24]a | sh[24]ae[lb] | sh[23]e | she[lb] | sh[lb]e \
+			| sh[1234]e[lb] |  sh[12345][lb]e | sh[23]ele | sh64 | sh64le \
+			| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet \
+			| sparclite \
+			| sparcv8 | sparcv9 | sparcv9b | sparcv9v | sv1 | sx* \
+			| spu \
+			| tahoe \
+			| tic30 | tic4x | tic54x | tic55x | tic6x | tic80 \
+			| tron \
+			| ubicom32 \
+			| v70 | v850 | v850e | v850e1 | v850es | v850e2 | v850e2v3 \
+			| vax \
+			| visium \
+			| w65 \
+			| wasm32 | wasm64 \
+			| we32k \
+			| x86 | x86_64 | xc16x | xgate | xps100 \
+			| xstormy16 | xtensa* \
+			| ymp \
+			| z8k | z80)
+				;;
+
+			*)
+				echo Invalid configuration \`"$1"\': machine \`"$cpu-$vendor"\' not recognized 1>&2
+				exit 1
+				;;
+		esac
+		;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $vendor in
+	digital*)
+		vendor=dec
+		;;
+	commodore*)
+		vendor=cbm
+		;;
+	*)
+		;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x$os != x ]
+then
+case $os in
+	# First match some system type aliases that might get confused
+	# with valid system types.
+	# solaris* is a basic system type, with this one exception.
+	auroraux)
+		os=auroraux
+		;;
+	bluegene*)
+		os=cnk
+		;;
+	solaris1 | solaris1.*)
+		os=`echo $os | sed -e 's|solaris1|sunos4|'`
+		;;
+	solaris)
+		os=solaris2
+		;;
+	unixware*)
+		os=sysv4.2uw
+		;;
+	gnu/linux*)
+		os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+		;;
+	# es1800 is here to avoid being matched by es* (a different OS)
+	es1800*)
+		os=ose
+		;;
+	# Some version numbers need modification
+	chorusos*)
+		os=chorusos
+		;;
+	isc)
+		os=isc2.2
+		;;
+	sco6)
+		os=sco5v6
+		;;
+	sco5)
+		os=sco3.2v5
+		;;
+	sco4)
+		os=sco3.2v4
+		;;
+	sco3.2.[4-9]*)
+		os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+		;;
+	sco3.2v[4-9]* | sco5v6*)
+		# Don't forget version if it is 3.2v4 or newer.
+		;;
+	scout)
+		# Don't match below
+		;;
+	sco*)
+		os=sco3.2v2
+		;;
+	psos*)
+		os=psos
+		;;
+	# Now accept the basic system types.
+	# The portable systems comes first.
+	# Each alternative MUST end in a * to match a version number.
+	# sysv* is not here because it comes later, after sysvr4.
+	gnu* | bsd* | mach* | minix* | genix* | ultrix* | irix* \
+	     | *vms* | esix* | aix* | cnk* | sunos | sunos[34]*\
+	     | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \
+	     | sym* | kopensolaris* | plan9* \
+	     | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \
+	     | aos* | aros* | cloudabi* | sortix* | twizzler* \
+	     | nindy* | vxsim* | vxworks* | ebmon* | hms* | mvs* \
+	     | clix* | riscos* | uniplus* | iris* | isc* | rtu* | xenix* \
+	     | knetbsd* | mirbsd* | netbsd* \
+	     | bitrig* | openbsd* | solidbsd* | libertybsd* | os108* \
+	     | ekkobsd* | kfreebsd* | freebsd* | riscix* | lynxos* \
+	     | bosx* | nextstep* | cxux* | aout* | elf* | oabi* \
+	     | ptx* | coff* | ecoff* | winnt* | domain* | vsta* \
+	     | udi* | eabi* | lites* | ieee* | go32* | aux* | hcos* \
+	     | chorusrdb* | cegcc* | glidix* \
+	     | cygwin* | msys* | pe* | moss* | proelf* | rtems* \
+	     | midipix* | mingw32* | mingw64* | linux-gnu* | linux-android* \
+	     | linux-newlib* | linux-musl* | linux-uclibc* \
+	     | uxpv* | beos* | mpeix* | udk* | moxiebox* \
+	     | interix* | uwin* | mks* | rhapsody* | darwin* \
+	     | openstep* | oskit* | conix* | pw32* | nonstopux* \
+	     | storm-chaos* | tops10* | tenex* | tops20* | its* \
+	     | os2* | vos* | palmos* | uclinux* | nucleus* \
+	     | morphos* | superux* | rtmk* | windiss* \
+	     | powermax* | dnix* | nx6 | nx7 | sei* | dragonfly* \
+	     | skyos* | haiku* | rdos* | toppers* | drops* | es* \
+	     | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \
+	     | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \
+	     | nsk* | powerunix)
+	# Remember, each alternative MUST END IN *, to match a version number.
+		;;
+	qnx*)
+		case $cpu in
+		    x86 | i*86)
+			;;
+		    *)
+			os=nto-$os
+			;;
+		esac
+		;;
+	hiux*)
+		os=hiuxwe2
+		;;
+	nto-qnx*)
+		;;
+	nto*)
+		os=`echo $os | sed -e 's|nto|nto-qnx|'`
+		;;
+	sim | xray | os68k* | v88r* \
+	    | windows* | osx | abug | netware* | os9* \
+	    | macos* | mpw* | magic* | mmixware* | mon960* | lnews*)
+		;;
+	linux-dietlibc)
+		os=linux-dietlibc
+		;;
+	linux*)
+		os=`echo $os | sed -e 's|linux|linux-gnu|'`
+		;;
+	lynx*178)
+		os=lynxos178
+		;;
+	lynx*5)
+		os=lynxos5
+		;;
+	lynx*)
+		os=lynxos
+		;;
+	mac*)
+		os=`echo "$os" | sed -e 's|mac|macos|'`
+		;;
+	opened*)
+		os=openedition
+		;;
+	os400*)
+		os=os400
+		;;
+	sunos5*)
+		os=`echo "$os" | sed -e 's|sunos5|solaris2|'`
+		;;
+	sunos6*)
+		os=`echo "$os" | sed -e 's|sunos6|solaris3|'`
+		;;
+	wince*)
+		os=wince
+		;;
+	utek*)
+		os=bsd
+		;;
+	dynix*)
+		os=bsd
+		;;
+	acis*)
+		os=aos
+		;;
+	atheos*)
+		os=atheos
+		;;
+	syllable*)
+		os=syllable
+		;;
+	386bsd)
+		os=bsd
+		;;
+	ctix* | uts*)
+		os=sysv
+		;;
+	nova*)
+		os=rtmk-nova
+		;;
+	ns2)
+		os=nextstep2
+		;;
+	# Preserve the version number of sinix5.
+	sinix5.*)
+		os=`echo $os | sed -e 's|sinix|sysv|'`
+		;;
+	sinix*)
+		os=sysv4
+		;;
+	tpf*)
+		os=tpf
+		;;
+	triton*)
+		os=sysv3
+		;;
+	oss*)
+		os=sysv3
+		;;
+	svr4*)
+		os=sysv4
+		;;
+	svr3)
+		os=sysv3
+		;;
+	sysvr4)
+		os=sysv4
+		;;
+	# This must come after sysvr4.
+	sysv*)
+		;;
+	ose*)
+		os=ose
+		;;
+	*mint | mint[0-9]* | *MiNT | MiNT[0-9]*)
+		os=mint
+		;;
+	zvmoe)
+		os=zvmoe
+		;;
+	dicos*)
+		os=dicos
+		;;
+	pikeos*)
+		# Until real need of OS specific support for
+		# particular features comes up, bare metal
+		# configurations are quite functional.
+		case $cpu in
+		    arm*)
+			os=eabi
+			;;
+		    *)
+			os=elf
+			;;
+		esac
+		;;
+	nacl*)
+		;;
+	ios)
+		;;
+	none)
+		;;
+	*-eabi)
+		;;
+	*)
+		echo Invalid configuration \`"$1"\': system \`"$os"\' not recognized 1>&2
+		exit 1
+		;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system.  Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $cpu-$vendor in
+	score-*)
+		os=elf
+		;;
+	spu-*)
+		os=elf
+		;;
+	*-acorn)
+		os=riscix1.2
+		;;
+	arm*-rebel)
+		os=linux
+		;;
+	arm*-semi)
+		os=aout
+		;;
+	c4x-* | tic4x-*)
+		os=coff
+		;;
+	c8051-*)
+		os=elf
+		;;
+	clipper-intergraph)
+		os=clix
+		;;
+	hexagon-*)
+		os=elf
+		;;
+	tic54x-*)
+		os=coff
+		;;
+	tic55x-*)
+		os=coff
+		;;
+	tic6x-*)
+		os=coff
+		;;
+	# This must come before the *-dec entry.
+	pdp10-*)
+		os=tops20
+		;;
+	pdp11-*)
+		os=none
+		;;
+	*-dec | vax-*)
+		os=ultrix4.2
+		;;
+	m68*-apollo)
+		os=domain
+		;;
+	i386-sun)
+		os=sunos4.0.2
+		;;
+	m68000-sun)
+		os=sunos3
+		;;
+	m68*-cisco)
+		os=aout
+		;;
+	mep-*)
+		os=elf
+		;;
+	mips*-cisco)
+		os=elf
+		;;
+	mips*-*)
+		os=elf
+		;;
+	or32-*)
+		os=coff
+		;;
+	*-tti)	# must be before sparc entry or we get the wrong os.
+		os=sysv3
+		;;
+	sparc-* | *-sun)
+		os=sunos4.1.1
+		;;
+	pru-*)
+		os=elf
+		;;
+	*-be)
+		os=beos
+		;;
+	*-ibm)
+		os=aix
+		;;
+	*-knuth)
+		os=mmixware
+		;;
+	*-wec)
+		os=proelf
+		;;
+	*-winbond)
+		os=proelf
+		;;
+	*-oki)
+		os=proelf
+		;;
+	*-hp)
+		os=hpux
+		;;
+	*-hitachi)
+		os=hiux
+		;;
+	i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+		os=sysv
+		;;
+	*-cbm)
+		os=amigaos
+		;;
+	*-dg)
+		os=dgux
+		;;
+	*-dolphin)
+		os=sysv3
+		;;
+	m68k-ccur)
+		os=rtu
+		;;
+	m88k-omron*)
+		os=luna
+		;;
+	*-next)
+		os=nextstep
+		;;
+	*-sequent)
+		os=ptx
+		;;
+	*-crds)
+		os=unos
+		;;
+	*-ns)
+		os=genix
+		;;
+	i370-*)
+		os=mvs
+		;;
+	*-gould)
+		os=sysv
+		;;
+	*-highlevel)
+		os=bsd
+		;;
+	*-encore)
+		os=bsd
+		;;
+	*-sgi)
+		os=irix
+		;;
+	*-siemens)
+		os=sysv4
+		;;
+	*-masscomp)
+		os=rtu
+		;;
+	f30[01]-fujitsu | f700-fujitsu)
+		os=uxpv
+		;;
+	*-rom68k)
+		os=coff
+		;;
+	*-*bug)
+		os=coff
+		;;
+	*-apple)
+		os=macos
+		;;
+	*-atari*)
+		os=mint
+		;;
+	*-wrs)
+		os=vxworks
+		;;
+	*)
+		os=none
+		;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer.  We pick the logical manufacturer.
+case $vendor in
+	unknown)
+		case $os in
+			riscix*)
+				vendor=acorn
+				;;
+			sunos*)
+				vendor=sun
+				;;
+			cnk*|-aix*)
+				vendor=ibm
+				;;
+			beos*)
+				vendor=be
+				;;
+			hpux*)
+				vendor=hp
+				;;
+			mpeix*)
+				vendor=hp
+				;;
+			hiux*)
+				vendor=hitachi
+				;;
+			unos*)
+				vendor=crds
+				;;
+			dgux*)
+				vendor=dg
+				;;
+			luna*)
+				vendor=omron
+				;;
+			genix*)
+				vendor=ns
+				;;
+			clix*)
+				vendor=intergraph
+				;;
+			mvs* | opened*)
+				vendor=ibm
+				;;
+			os400*)
+				vendor=ibm
+				;;
+			ptx*)
+				vendor=sequent
+				;;
+			tpf*)
+				vendor=ibm
+				;;
+			vxsim* | vxworks* | windiss*)
+				vendor=wrs
+				;;
+			aux*)
+				vendor=apple
+				;;
+			hms*)
+				vendor=hitachi
+				;;
+			mpw* | macos*)
+				vendor=apple
+				;;
+			*mint | mint[0-9]* | *MiNT | MiNT[0-9]*)
+				vendor=atari
+				;;
+			vos*)
+				vendor=stratus
+				;;
+		esac
+		;;
+esac
+
+echo "$cpu-$vendor-$os"
+exit
+
+# Local variables:
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/third_party/gmp/configure b/third_party/gmp/configure
new file mode 100755
index 0000000..23b9077
--- /dev/null
+++ b/third_party/gmp/configure
@@ -0,0 +1,30525 @@
+#! /bin/sh
+# From configure.ac Revision.
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.69 for GNU MP 6.2.0.
+#
+# Report bugs to <gmp-bugs@gmplib.org, see https://gmplib.org/manual/Reporting-Bugs.html>.
+#
+#
+#
+# Copyright 1996-2020 Free Software Foundation, Inc.
+#
+# This file is part of the GNU MP Library.
+#
+# The GNU MP Library is free software; you can redistribute it and/or modify
+# it under the terms of either:
+#
+#   * the GNU Lesser General Public License as published by the Free
+#     Software Foundation; either version 3 of the License, or (at your
+#     option) any later version.
+#
+# or
+#
+#   * the GNU General Public License as published by the Free Software
+#     Foundation; either version 2 of the License, or (at your option) any
+#     later version.
+#
+# or both in parallel, as here.
+#
+# The GNU MP Library is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received copies of the GNU General Public License and the
+# GNU Lesser General Public License along with the GNU MP Library.  If not,
+# see https://www.gnu.org/licenses/.
+#
+#
+#
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in #(
+      *"$as_nl"*)
+	expr "X$arg" : "X\\(.*\\)$as_nl";
+	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""	$as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Use a proper internal environment variable to ensure we don't fall
+  # into an infinite loop, continuously re-executing ourselves.
+  if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+    _as_can_reexec=no; export _as_can_reexec;
+    # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+  *v*x* | *x*v* ) as_opts=-vx ;;
+  *v* ) as_opts=-v ;;
+  *x* ) as_opts=-x ;;
+  * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+  fi
+  # We don't want this to propagate to other subprocesses.
+          { _as_can_reexec=; unset _as_can_reexec;}
+if test "x$CONFIG_SHELL" = x; then
+  as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '\${1+\"\$@\"}'='\"\$@\"'
+  setopt NO_GLOB_SUBST
+else
+  case \`(set -o) 2>/dev/null\` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+"
+  as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+  exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
+  as_suggested="  as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+  as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+  eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+  test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1
+
+  test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || (
+    ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+    ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO
+    ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO
+    PATH=/empty FPATH=/empty; export PATH FPATH
+    test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\
+      || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1"
+  if (eval "$as_required") 2>/dev/null; then :
+  as_have_required=yes
+else
+  as_have_required=no
+fi
+  if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  as_found=:
+  case $as_dir in #(
+	 /*)
+	   for as_base in sh bash ksh sh5; do
+	     # Try only shells that exist, to save several forks.
+	     as_shell=$as_dir/$as_base
+	     if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+		    { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  CONFIG_SHELL=$as_shell as_have_required=yes
+		   if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  break 2
+fi
+fi
+	   done;;
+       esac
+  as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+	      { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+  CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+      if test "x$CONFIG_SHELL" != x; then :
+  export CONFIG_SHELL
+             # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+  *v*x* | *x*v* ) as_opts=-vx ;;
+  *v* ) as_opts=-v ;;
+  *x* ) as_opts=-x ;;
+  * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
+fi
+
+    if test x$as_have_required = xno; then :
+  $as_echo "$0: This script requires a shell more modern than all"
+  $as_echo "$0: the shells that I found on your system."
+  if test x${ZSH_VERSION+set} = xset ; then
+    $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+    $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+  else
+    $as_echo "$0: Please tell bug-autoconf@gnu.org and
+$0: gmp-bugs@gmplib.org, see
+$0: https://gmplib.org/manual/Reporting-Bugs.html about
+$0: your system, including any error possibly output before
+$0: this message. Then install a modern shell, or manually
+$0: run the script under such a shell if you do have one."
+  fi
+  exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_dir" : 'X\(//\)[^/]' \| \
+	 X"$as_dir" : 'X\(//\)$' \| \
+	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+  test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$1; test $as_status -eq 0 && as_status=1
+  if test "$4"; then
+    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+  fi
+  $as_echo "$as_me: error: $2" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+  as_lineno_1=$LINENO as_lineno_1a=$LINENO
+  as_lineno_2=$LINENO as_lineno_2a=$LINENO
+  eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+  test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+  # Blame Lee E. McMahon (1931-1989) for sed's syntax.  :-)
+  sed -n '
+    p
+    /[$]LINENO/=
+  ' <$as_myself |
+    sed '
+      s/[$]LINENO.*/&-/
+      t lineno
+      b
+      :lineno
+      N
+      :loop
+      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+      t loop
+      s/-\n.*//
+    ' >$as_me.lineno &&
+  chmod +x "$as_me.lineno" ||
+    { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+  # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+  # already done that, so ensure we don't try to do so again and fall
+  # in an infinite loop.  This has already happened in practice.
+  _as_can_reexec=no; export _as_can_reexec
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensitive to this).
+  . "./$as_me.lineno"
+  # Exit status is that of the last command.
+  exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='	';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -pR'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -pR'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -pR'
+  fi
+else
+  as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p='mkdir -p "$as_dir"'
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME='GNU MP'
+PACKAGE_TARNAME='gmp'
+PACKAGE_VERSION='6.2.0'
+PACKAGE_STRING='GNU MP 6.2.0'
+PACKAGE_BUGREPORT='gmp-bugs@gmplib.org, see https://gmplib.org/manual/Reporting-Bugs.html'
+PACKAGE_URL='http://www.gnu.org/software/gmp/'
+
+ac_unique_file="gmp-impl.h"
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='am__EXEEXT_FALSE
+am__EXEEXT_TRUE
+LTLIBOBJS
+LIBOBJS
+LEXLIB
+LEX_OUTPUT_ROOT
+LEX
+YFLAGS
+YACC
+LIBREADLINE
+WITH_READLINE_01
+LIBCURSES
+HAVE_STACK_T_01
+HAVE_SYS_RESOURCE_H_01
+HAVE_SIGSTACK_01
+HAVE_SIGALTSTACK_01
+HAVE_SIGACTION_01
+HAVE_GETTIMEOFDAY_01
+HAVE_GETRUSAGE_01
+HAVE_CPUTIME_01
+HAVE_CLOCK_01
+TUNE_SQR_OBJ
+gmp_srclinks
+mpn_objs_in_libgmp
+mpn_objects
+GMP_LIMB_BITS
+M4
+TUNE_LIBS
+TAL_OBJECT
+LIBM
+ENABLE_STATIC_FALSE
+ENABLE_STATIC_TRUE
+LT_SYS_LIBRARY_PATH
+OTOOL64
+OTOOL
+LIPO
+NMEDIT
+DSYMUTIL
+MANIFEST_TOOL
+RANLIB
+ac_ct_AR
+LN_S
+LD
+FGREP
+SED
+LIBTOOL
+LIBGMP_DLL
+OBJDUMP
+DLLTOOL
+AS
+NM
+ac_ct_DUMPBIN
+DUMPBIN
+AR
+ASMFLAGS
+EGREP
+GREP
+CXXCPP
+WANT_CXX_FALSE
+WANT_CXX_TRUE
+ac_ct_CXX
+CXXFLAGS
+CXX
+CCAS
+LIBM_FOR_BUILD
+U_FOR_BUILD
+EXEEXT_FOR_BUILD
+CPP_FOR_BUILD
+CC_FOR_BUILD
+CPP
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+DEFN_LONG_LONG_LIMB
+CALLING_CONVENTIONS_OBJS
+SPEED_CYCLECOUNTER_OBJ
+LIBGMPXX_LDFLAGS
+LIBGMP_LDFLAGS
+GMP_LDFLAGS
+HAVE_HOST_CPU_FAMILY_powerpc
+HAVE_HOST_CPU_FAMILY_power
+ABI
+GMP_NAIL_BITS
+MAINT
+MAINTAINER_MODE_FALSE
+MAINTAINER_MODE_TRUE
+AM_BACKSLASH
+AM_DEFAULT_VERBOSITY
+AM_DEFAULT_V
+AM_V
+am__untar
+am__tar
+AMTAR
+am__leading_dot
+SET_MAKE
+AWK
+mkdir_p
+MKDIR_P
+INSTALL_STRIP_PROGRAM
+STRIP
+install_sh
+MAKEINFO
+AUTOHEADER
+AUTOMAKE
+AUTOCONF
+ACLOCAL
+VERSION
+PACKAGE
+CYGPATH_W
+am__isrc
+INSTALL_DATA
+INSTALL_SCRIPT
+INSTALL_PROGRAM
+host_os
+host_vendor
+host_cpu
+host
+build_os
+build_vendor
+build_cpu
+build
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+enable_silent_rules
+enable_maintainer_mode
+enable_assert
+enable_alloca
+enable_cxx
+enable_assembly
+enable_fft
+enable_old_fft_full
+enable_nails
+enable_profiling
+with_readline
+enable_fat
+enable_minithres
+enable_fake_cpuid
+enable_shared
+enable_static
+with_pic
+enable_fast_install
+with_aix_soname
+with_gnu_ld
+with_sysroot
+enable_libtool_lock
+'
+      ac_precious_vars='build_alias
+host_alias
+target_alias
+ABI
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CPP
+CC_FOR_BUILD
+CPP_FOR_BUILD
+CXX
+CXXFLAGS
+CCC
+CXXCPP
+LT_SYS_LIBRARY_PATH
+M4
+YACC
+YFLAGS'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval $ac_prev=\$ac_option
+    ac_prev=
+    continue
+  fi
+
+  case $ac_option in
+  *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+  *=)   ac_optarg= ;;
+  *)    ac_optarg=yes ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case $ac_dashdash$ac_option in
+  --)
+    ac_dashdash=yes ;;
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir=$ac_optarg ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build_alias ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build_alias=$ac_optarg ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file=$ac_optarg ;;
+
+  --config-cache | -C)
+    cache_file=config.cache ;;
+
+  -datadir | --datadir | --datadi | --datad)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=*)
+    datadir=$ac_optarg ;;
+
+  -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+  | --dataroo | --dataro | --datar)
+    ac_prev=datarootdir ;;
+  -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+  | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+    datarootdir=$ac_optarg ;;
+
+  -disable-* | --disable-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid feature name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=no ;;
+
+  -docdir | --docdir | --docdi | --doc | --do)
+    ac_prev=docdir ;;
+  -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+    docdir=$ac_optarg ;;
+
+  -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+    ac_prev=dvidir ;;
+  -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+    dvidir=$ac_optarg ;;
+
+  -enable-* | --enable-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid feature name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=\$ac_optarg ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix=$ac_optarg ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he | -h)
+    ac_init_help=long ;;
+  -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+    ac_init_help=recursive ;;
+  -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+    ac_init_help=short ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host_alias ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host_alias=$ac_optarg ;;
+
+  -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+    ac_prev=htmldir ;;
+  -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+  | --ht=*)
+    htmldir=$ac_optarg ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir=$ac_optarg ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir=$ac_optarg ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir=$ac_optarg ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir=$ac_optarg ;;
+
+  -localedir | --localedir | --localedi | --localed | --locale)
+    ac_prev=localedir ;;
+  -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+    localedir=$ac_optarg ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst | --locals)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+    localstatedir=$ac_optarg ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir=$ac_optarg ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c | -n)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir=$ac_optarg ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix=$ac_optarg ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix=$ac_optarg ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix=$ac_optarg ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name=$ac_optarg ;;
+
+  -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+    ac_prev=pdfdir ;;
+  -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+    pdfdir=$ac_optarg ;;
+
+  -psdir | --psdir | --psdi | --psd | --ps)
+    ac_prev=psdir ;;
+  -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+    psdir=$ac_optarg ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir=$ac_optarg ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir=$ac_optarg ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site=$ac_optarg ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir=$ac_optarg ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir=$ac_optarg ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target_alias ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target_alias=$ac_optarg ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers | -V)
+    ac_init_version=: ;;
+
+  -with-* | --with-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid package name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=\$ac_optarg ;;
+
+  -without-* | --without-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid package name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=no ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes=$ac_optarg ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries=$ac_optarg ;;
+
+  -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+    ;;
+
+  *=*)
+    ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+    # Reject names that are not valid shell variable names.
+    case $ac_envvar in #(
+      '' | [0-9]* | *[!_$as_cr_alnum]* )
+      as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+    esac
+    eval $ac_envvar=\$ac_optarg
+    export $ac_envvar ;;
+
+  *)
+    # FIXME: should be removed in autoconf 3.0.
+    $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+    expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+    : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+  as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+  case $enable_option_checking in
+    no) ;;
+    fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+    *)     $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+  esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in	exec_prefix prefix bindir sbindir libexecdir datarootdir \
+		datadir sysconfdir sharedstatedir localstatedir includedir \
+		oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+		libdir localedir mandir
+do
+  eval ac_val=\$$ac_var
+  # Remove trailing slashes.
+  case $ac_val in
+    */ )
+      ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+      eval $ac_var=\$ac_val;;
+  esac
+  # Be sure to have absolute directory names.
+  case $ac_val in
+    [\\/$]* | ?:[\\/]* )  continue;;
+    NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+  esac
+  as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+  if test "x$build_alias" = x; then
+    cross_compiling=maybe
+  elif test "x$build_alias" != "x$host_alias"; then
+    cross_compiling=yes
+  fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+  as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+  as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then the parent directory.
+  ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_myself" : 'X\(//\)[^/]' \| \
+	 X"$as_myself" : 'X\(//\)$' \| \
+	 X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+  srcdir=$ac_confdir
+  if test ! -r "$srcdir/$ac_unique_file"; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+  test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+  as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+	cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+	pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+  srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+  eval ac_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_env_${ac_var}_value=\$${ac_var}
+  eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+  # Omit some internal or obsolete options to make the list less imposing.
+  # This message is too long to be a string in the A/UX 3.1 sh.
+  cat <<_ACEOF
+\`configure' configures GNU MP 6.2.0 to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE.  See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+  -h, --help              display this help and exit
+      --help=short        display options specific to this package
+      --help=recursive    display the short help of all the included packages
+  -V, --version           display version information and exit
+  -q, --quiet, --silent   do not print \`checking ...' messages
+      --cache-file=FILE   cache test results in FILE [disabled]
+  -C, --config-cache      alias for \`--cache-file=config.cache'
+  -n, --no-create         do not create output files
+      --srcdir=DIR        find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                          [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                          [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc.  You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+  --bindir=DIR            user executables [EPREFIX/bin]
+  --sbindir=DIR           system admin executables [EPREFIX/sbin]
+  --libexecdir=DIR        program executables [EPREFIX/libexec]
+  --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
+  --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
+  --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
+  --libdir=DIR            object code libraries [EPREFIX/lib]
+  --includedir=DIR        C header files [PREFIX/include]
+  --oldincludedir=DIR     C header files for non-gcc [/usr/include]
+  --datarootdir=DIR       read-only arch.-independent data root [PREFIX/share]
+  --datadir=DIR           read-only architecture-independent data [DATAROOTDIR]
+  --infodir=DIR           info documentation [DATAROOTDIR/info]
+  --localedir=DIR         locale-dependent data [DATAROOTDIR/locale]
+  --mandir=DIR            man documentation [DATAROOTDIR/man]
+  --docdir=DIR            documentation root [DATAROOTDIR/doc/gmp]
+  --htmldir=DIR           html documentation [DOCDIR]
+  --dvidir=DIR            dvi documentation [DOCDIR]
+  --pdfdir=DIR            pdf documentation [DOCDIR]
+  --psdir=DIR             ps documentation [DOCDIR]
+_ACEOF
+
+  cat <<\_ACEOF
+
+Program names:
+  --program-prefix=PREFIX            prepend PREFIX to installed program names
+  --program-suffix=SUFFIX            append SUFFIX to installed program names
+  --program-transform-name=PROGRAM   run sed PROGRAM on installed program names
+
+System types:
+  --build=BUILD     configure for building on BUILD [guessed]
+  --host=HOST       cross-compile to build programs to run on HOST [BUILD]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+  case $ac_init_help in
+     short | recursive ) echo "Configuration of GNU MP 6.2.0:";;
+   esac
+  cat <<\_ACEOF
+
+Optional Features:
+  --disable-option-checking  ignore unrecognized --enable/--with options
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --enable-silent-rules   less verbose build output (undo: "make V=1")
+  --disable-silent-rules  verbose build output (undo: "make V=0")
+  --enable-maintainer-mode
+                          enable make rules and dependencies not useful (and
+                          sometimes confusing) to the casual installer
+  --enable-assert         enable ASSERT checking [default=no]
+  --enable-alloca         how to get temp memory [default=reentrant]
+  --enable-cxx            enable C++ support [default=no]
+  --enable-assembly       enable the use of assembly loops [default=yes]
+  --enable-fft            enable FFTs for multiplication [default=yes]
+  --enable-old-fft-full   enable old mpn_mul_fft_full for multiplication
+                          [default=no]
+  --enable-nails          use nails on limbs [default=no]
+  --enable-profiling      build with profiler support [default=no]
+  --enable-fat            build fat libraries on systems that support it
+                          [default=no]
+  --enable-minithres      choose minimal thresholds for testing [default=no]
+  --enable-fake-cpuid     enable GMP_CPU_TYPE faking cpuid [default=no]
+  --enable-shared[=PKGS]  build shared libraries [default=yes]
+  --enable-static[=PKGS]  build static libraries [default=yes]
+  --enable-fast-install[=PKGS]
+                          optimize for fast installation [default=yes]
+  --disable-libtool-lock  avoid locking (might break parallel builds)
+
+Optional Packages:
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --with-readline         readline support in demo programs [default=detect]
+  --with-pic[=PKGS]       try to use only PIC/non-PIC objects [default=use
+                          both]
+  --with-aix-soname=aix|svr4|both
+                          shared library versioning (aka "SONAME") variant to
+                          provide on AIX, [default=aix].
+  --with-gnu-ld           assume the C compiler uses GNU ld [default=no]
+  --with-sysroot[=DIR]    Search for dependent libraries within DIR (or the
+                          compiler's sysroot if not specified).
+
+Some influential environment variables:
+  ABI         desired ABI (for processors supporting more than one ABI)
+  CC          C compiler command
+  CFLAGS      C compiler flags
+  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
+              nonstandard directory <lib dir>
+  LIBS        libraries to pass to the linker, e.g. -l<library>
+  CPPFLAGS    (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+              you have headers in a nonstandard directory <include dir>
+  CPP         C preprocessor
+  CC_FOR_BUILD
+              build system C compiler
+  CPP_FOR_BUILD
+              build system C preprocessor
+  CXX         C++ compiler command
+  CXXFLAGS    C++ compiler flags
+  CXXCPP      C++ preprocessor
+  LT_SYS_LIBRARY_PATH
+              User-defined run-time library search path.
+  M4          m4 macro processor
+  YACC        The `Yet Another Compiler Compiler' implementation to use.
+              Defaults to the first program found out of: `bison -y', `byacc',
+              `yacc'.
+  YFLAGS      The list of arguments that will be passed by default to $YACC.
+              This script will default YFLAGS to the empty string to avoid a
+              default value of `-d' given by some make applications.
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to <gmp-bugs@gmplib.org, see https://gmplib.org/manual/Reporting-Bugs.html>.
+GNU MP home page: <http://www.gnu.org/software/gmp/>.
+General help using GNU software: <http://www.gnu.org/gethelp/>.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+  # If there are subdirs, report their specific --help.
+  for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+    test -d "$ac_dir" ||
+      { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+      continue
+    ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+    cd "$ac_dir" || { ac_status=$?; continue; }
+    # Check for guested configure.
+    if test -f "$ac_srcdir/configure.gnu"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+    elif test -f "$ac_srcdir/configure"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure" --help=recursive
+    else
+      $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+    fi || ac_status=$?
+    cd "$ac_pwd" || { ac_status=$?; break; }
+  done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+  cat <<\_ACEOF
+GNU MP configure 6.2.0
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+
+
+
+Copyright 1996-2020 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.
+
+_ACEOF
+  exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext
+  if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_retval=1
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_cpp LINENO
+# ----------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_cpp ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } > conftest.i && {
+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+    ac_retval=1
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_cpp
+
+# ac_fn_cxx_try_compile LINENO
+# ----------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_cxx_try_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext
+  if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_retval=1
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_cxx_try_compile
+
+# ac_fn_cxx_try_cpp LINENO
+# ------------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_cxx_try_cpp ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } > conftest.i && {
+	 test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+    ac_retval=1
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_cxx_try_cpp
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext conftest$ac_exeext
+  if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 test -x conftest$ac_exeext
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_retval=1
+fi
+  # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+  # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+  # interfere with the next link command; also delete a directory that is
+  # left behind by Apple's compiler.  We do this before executing the actions.
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+
+# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists and can be compiled using the include files in
+# INCLUDES, setting the cache variable VAR accordingly.
+ac_fn_c_check_header_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_compile
+
+# ac_fn_c_try_run LINENO
+# ----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
+# that executables *can* be run.
+ac_fn_c_try_run ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
+  { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: program exited with status $ac_status" >&5
+       $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_retval=$ac_status
+fi
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_run
+
+# ac_fn_c_check_func LINENO FUNC VAR
+# ----------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_c_check_func ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $2 (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $2
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $2 ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$2 || defined __stub___$2
+choke me
+#endif
+
+int
+main ()
+{
+return $2 ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_func
+
+# ac_fn_cxx_try_link LINENO
+# -------------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_cxx_try_link ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext conftest$ac_exeext
+  if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 test -x conftest$ac_exeext
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_retval=1
+fi
+  # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+  # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+  # interfere with the next link command; also delete a directory that is
+  # left behind by Apple's compiler.  We do this before executing the actions.
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_cxx_try_link
+
+# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists, giving a warning if it cannot be compiled using
+# the include files in INCLUDES and setting the cache variable VAR
+# accordingly.
+ac_fn_c_check_header_mongrel ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if eval \${$3+:} false; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
+$as_echo_n "checking $2 usability... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_header_compiler=yes
+else
+  ac_header_compiler=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
+$as_echo_n "checking $2 presence... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <$2>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  ac_header_preproc=yes
+else
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
+  yes:no: )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+    ;;
+  no:yes:* )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $2:     check for missing prerequisite headers?" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+( $as_echo "## ssssssssssssssssssssssssssssssssss ##
+## Report this to gmp-bugs@gmplib.org ##
+## ssssssssssssssssssssssssssssssssss ##"
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  eval "$3=\$ac_header_compiler"
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_mongrel
+
+# ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES
+# ---------------------------------------------
+# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR
+# accordingly.
+ac_fn_c_check_decl ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  as_decl_name=`echo $2|sed 's/ *(.*//'`
+  as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'`
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5
+$as_echo_n "checking whether $as_decl_name is declared... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+#ifndef $as_decl_name
+#ifdef __cplusplus
+  (void) $as_decl_use;
+#else
+  (void) $as_decl_name;
+#endif
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_decl
+
+# ac_fn_c_check_type LINENO TYPE VAR INCLUDES
+# -------------------------------------------
+# Tests whether TYPE exists after having included INCLUDES, setting cache
+# variable VAR accordingly.
+ac_fn_c_check_type ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  eval "$3=no"
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+if (sizeof ($2))
+	 return 0;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+if (sizeof (($2)))
+	    return 0;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+  eval "$3=yes"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_type
+
+# ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES
+# ----------------------------------------------------
+# Tries to find if the field MEMBER exists in type AGGR, after including
+# INCLUDES, setting cache variable VAR accordingly.
+ac_fn_c_check_member ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5
+$as_echo_n "checking for $2.$3... " >&6; }
+if eval \${$4+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$5
+int
+main ()
+{
+static $2 ac_aggr;
+if (ac_aggr.$3)
+return 0;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "$4=yes"
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$5
+int
+main ()
+{
+static $2 ac_aggr;
+if (sizeof ac_aggr.$3)
+return 0;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "$4=yes"
+else
+  eval "$4=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$4
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_member
+
+# ac_fn_cxx_check_header_mongrel LINENO HEADER VAR INCLUDES
+# ---------------------------------------------------------
+# Tests whether HEADER exists, giving a warning if it cannot be compiled using
+# the include files in INCLUDES and setting the cache variable VAR
+# accordingly.
+ac_fn_cxx_check_header_mongrel ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if eval \${$3+:} false; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
+$as_echo_n "checking $2 usability... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  ac_header_compiler=yes
+else
+  ac_header_compiler=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
+$as_echo_n "checking $2 presence... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <$2>
+_ACEOF
+if ac_fn_cxx_try_cpp "$LINENO"; then :
+  ac_header_preproc=yes
+else
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_cxx_preproc_warn_flag in #((
+  yes:no: )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+    ;;
+  no:yes:* )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $2:     check for missing prerequisite headers?" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+( $as_echo "## ssssssssssssssssssssssssssssssssss ##
+## Report this to gmp-bugs@gmplib.org ##
+## ssssssssssssssssssssssssssssssssss ##"
+     ) | sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  eval "$3=\$ac_header_compiler"
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_cxx_check_header_mongrel
+
+# ac_fn_cxx_check_type LINENO TYPE VAR INCLUDES
+# ---------------------------------------------
+# Tests whether TYPE exists after having included INCLUDES, setting cache
+# variable VAR accordingly.
+ac_fn_cxx_check_type ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  eval "$3=no"
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+if (sizeof ($2))
+	 return 0;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+if (sizeof (($2)))
+	    return 0;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+
+else
+  eval "$3=yes"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_cxx_check_type
+
+# ac_fn_c_compute_int LINENO EXPR VAR INCLUDES
+# --------------------------------------------
+# Tries to find the compile-time value of EXPR in a program that includes
+# INCLUDES, setting VAR accordingly. Returns whether the value could be
+# computed
+ac_fn_c_compute_int ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if test "$cross_compiling" = yes; then
+    # Depending upon the size, compute the lo and hi bounds.
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) >= 0)];
+test_array [0] = 0;
+return test_array [0];
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_lo=0 ac_mid=0
+  while :; do
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) <= $ac_mid)];
+test_array [0] = 0;
+return test_array [0];
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_hi=$ac_mid; break
+else
+  as_fn_arith $ac_mid + 1 && ac_lo=$as_val
+			if test $ac_lo -le $ac_mid; then
+			  ac_lo= ac_hi=
+			  break
+			fi
+			as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) < 0)];
+test_array [0] = 0;
+return test_array [0];
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_hi=-1 ac_mid=-1
+  while :; do
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) >= $ac_mid)];
+test_array [0] = 0;
+return test_array [0];
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_lo=$ac_mid; break
+else
+  as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val
+			if test $ac_mid -le $ac_hi; then
+			  ac_lo= ac_hi=
+			  break
+			fi
+			as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  ac_lo= ac_hi=
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+  as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) <= $ac_mid)];
+test_array [0] = 0;
+return test_array [0];
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_hi=$ac_mid
+else
+  as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in #((
+?*) eval "$3=\$ac_lo"; ac_retval=0 ;;
+'') ac_retval=1 ;;
+esac
+  else
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+static long int longval () { return $2; }
+static unsigned long int ulongval () { return $2; }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+  FILE *f = fopen ("conftest.val", "w");
+  if (! f)
+    return 1;
+  if (($2) < 0)
+    {
+      long int i = longval ();
+      if (i != ($2))
+	return 1;
+      fprintf (f, "%ld", i);
+    }
+  else
+    {
+      unsigned long int i = ulongval ();
+      if (i != ($2))
+	return 1;
+      fprintf (f, "%lu", i);
+    }
+  /* Do not output a trailing newline, as this causes \r\n confusion
+     on some platforms.  */
+  return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  echo >>conftest.val; read $3 <conftest.val; ac_retval=0
+else
+  ac_retval=1
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+rm -f conftest.val
+
+  fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_compute_int
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by GNU MP $as_me 6.2.0, which was
+generated by GNU Autoconf 2.69.  Invocation command line was
+
+  $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null     || echo unknown`
+
+/bin/arch              = `(/bin/arch) 2>/dev/null              || echo unknown`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null       || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo      = `(/usr/bin/hostinfo) 2>/dev/null      || echo unknown`
+/bin/machine           = `(/bin/machine) 2>/dev/null           || echo unknown`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null       || echo unknown`
+/bin/universe          = `(/bin/universe) 2>/dev/null          || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    $as_echo "PATH: $as_dir"
+  done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+  for ac_arg
+  do
+    case $ac_arg in
+    -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+    -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+    | -silent | --silent | --silen | --sile | --sil)
+      continue ;;
+    *\'*)
+      ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    case $ac_pass in
+    1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+    2)
+      as_fn_append ac_configure_args1 " '$ac_arg'"
+      if test $ac_must_keep_next = true; then
+	ac_must_keep_next=false # Got value, back to normal.
+      else
+	case $ac_arg in
+	  *=* | --config-cache | -C | -disable-* | --disable-* \
+	  | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+	  | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+	  | -with-* | --with-* | -without-* | --without-* | --x)
+	    case "$ac_configure_args0 " in
+	      "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+	    esac
+	    ;;
+	  -* ) ac_must_keep_next=true ;;
+	esac
+      fi
+      as_fn_append ac_configure_args " '$ac_arg'"
+      ;;
+    esac
+  done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log.  We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+  # Save into config.log some information that might help in debugging.
+  {
+    echo
+
+    $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+    echo
+    # The following way of writing the cache mishandles newlines in values,
+(
+  for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) { eval $ac_var=; unset $ac_var;} ;;
+      esac ;;
+    esac
+  done
+  (set) 2>&1 |
+    case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      sed -n \
+	"s/'\''/'\''\\\\'\'''\''/g;
+	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+      ;; #(
+    *)
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+)
+    echo
+
+    $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+    echo
+    for ac_var in $ac_subst_vars
+    do
+      eval ac_val=\$$ac_var
+      case $ac_val in
+      *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+      esac
+      $as_echo "$ac_var='\''$ac_val'\''"
+    done | sort
+    echo
+
+    if test -n "$ac_subst_files"; then
+      $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+      echo
+      for ac_var in $ac_subst_files
+      do
+	eval ac_val=\$$ac_var
+	case $ac_val in
+	*\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+	esac
+	$as_echo "$ac_var='\''$ac_val'\''"
+      done | sort
+      echo
+    fi
+
+    if test -s confdefs.h; then
+      $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+      echo
+      cat confdefs.h
+      echo
+    fi
+    test "$ac_signal" != 0 &&
+      $as_echo "$as_me: caught signal $ac_signal"
+    $as_echo "$as_me: exit $exit_status"
+  } >&5
+  rm -f core *.core core.conftest.* &&
+    rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+    exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+  trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+  # We do not want a PATH search for config.site.
+  case $CONFIG_SITE in #((
+    -*)  ac_site_file1=./$CONFIG_SITE;;
+    */*) ac_site_file1=$CONFIG_SITE;;
+    *)   ac_site_file1=./$CONFIG_SITE;;
+  esac
+elif test "x$prefix" != xNONE; then
+  ac_site_file1=$prefix/share/config.site
+  ac_site_file2=$prefix/etc/config.site
+else
+  ac_site_file1=$ac_default_prefix/share/config.site
+  ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+  test "x$ac_site_file" = xNONE && continue
+  if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+    sed 's/^/| /' "$ac_site_file" >&5
+    . "$ac_site_file" \
+      || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+  fi
+done
+
+if test -r "$cache_file"; then
+  # Some versions of bash will fail to source /dev/null (special files
+  # actually), so we avoid doing that.  DJGPP emulates it as a regular file.
+  if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+    case $cache_file in
+      [\\/]* | ?:[\\/]* ) . "$cache_file";;
+      *)                      . "./$cache_file";;
+    esac
+  fi
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+  >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+  eval ac_old_set=\$ac_cv_env_${ac_var}_set
+  eval ac_new_set=\$ac_env_${ac_var}_set
+  eval ac_old_val=\$ac_cv_env_${ac_var}_value
+  eval ac_new_val=\$ac_env_${ac_var}_value
+  case $ac_old_set,$ac_new_set in
+    set,)
+      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,set)
+      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,);;
+    *)
+      if test "x$ac_old_val" != "x$ac_new_val"; then
+	# differences in whitespace do not lead to failure.
+	ac_old_val_w=`echo x $ac_old_val`
+	ac_new_val_w=`echo x $ac_new_val`
+	if test "$ac_old_val_w" != "$ac_new_val_w"; then
+	  { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+	  ac_cache_corrupted=:
+	else
+	  { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+	  eval $ac_var=\$ac_old_val
+	fi
+	{ $as_echo "$as_me:${as_lineno-$LINENO}:   former value:  \`$ac_old_val'" >&5
+$as_echo "$as_me:   former value:  \`$ac_old_val'" >&2;}
+	{ $as_echo "$as_me:${as_lineno-$LINENO}:   current value: \`$ac_new_val'" >&5
+$as_echo "$as_me:   current value: \`$ac_new_val'" >&2;}
+      fi;;
+  esac
+  # Pass precious variables to config.status.
+  if test "$ac_new_set" = set; then
+    case $ac_new_val in
+    *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+    *) ac_arg=$ac_var=$ac_new_val ;;
+    esac
+    case " $ac_configure_args " in
+      *" '$ac_arg' "*) ;; # Avoid dups.  Use of quotes ensures accuracy.
+      *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+    esac
+  fi
+done
+if $ac_cache_corrupted; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+  as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+
+
+
+
+# If --target is not used then $target_alias is empty, but if say
+# "./configure athlon-pc-freebsd3.5" is used, then all three of
+# $build_alias, $host_alias and $target_alias are set to
+# "athlon-pc-freebsd3.5".
+#
+if test -n "$target_alias" && test "$target_alias" != "$host_alias"; then
+  as_fn_error $? "--target is not appropriate for GMP
+Use --build=CPU-VENDOR-OS if you need to specify your CPU and/or system
+explicitly.  Use --host if cross-compiling (see \"Installing GMP\" in the
+manual for more on this)." "$LINENO" 5
+fi
+
+gmp_configm4="config.m4"
+gmp_tmpconfigm4=cnfm4.tmp
+gmp_tmpconfigm4i=cnfm4i.tmp
+gmp_tmpconfigm4p=cnfm4p.tmp
+rm -f $gmp_tmpconfigm4 $gmp_tmpconfigm4i $gmp_tmpconfigm4p
+
+# CONFIG_TOP_SRCDIR is a path from the mpn builddir to the top srcdir.
+# The pattern here tests for an absolute path the same way as
+# _AC_OUTPUT_FILES in autoconf acgeneral.m4.
+case $srcdir in
+[\\/]* | ?:[\\/]* )  tmp="$srcdir"    ;;
+*)                       tmp="../$srcdir" ;;
+esac
+echo "define(<CONFIG_TOP_SRCDIR>,<\`$tmp'>)" >>$gmp_tmpconfigm4
+
+# All CPUs use asm-defs.m4
+echo "include(CONFIG_TOP_SRCDIR\`/mpn/asm-defs.m4')" >>$gmp_tmpconfigm4i
+
+
+ac_aux_dir=
+for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
+  if test -f "$ac_dir/install-sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f "$ac_dir/install.sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  elif test -f "$ac_dir/shtool"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/shtool install -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5
+fi
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"  # Please don't use this var.
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"  # Please don't use this var.
+ac_configure="$SHELL $ac_aux_dir/configure"  # Please don't use this var.
+
+
+# Make sure we can run config.sub.
+$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
+  as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
+$as_echo_n "checking build system type... " >&6; }
+if ${ac_cv_build+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_build_alias=$build_alias
+test "x$ac_build_alias" = x &&
+  ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
+test "x$ac_build_alias" = x &&
+  as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
+ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
+  as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
+$as_echo "$ac_cv_build" >&6; }
+case $ac_cv_build in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
+esac
+build=$ac_cv_build
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_build
+shift
+build_cpu=$1
+build_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+build_os=$*
+IFS=$ac_save_IFS
+case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
+$as_echo_n "checking host system type... " >&6; }
+if ${ac_cv_host+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test "x$host_alias" = x; then
+  ac_cv_host=$ac_cv_build
+else
+  ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
+    as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
+$as_echo "$ac_cv_host" >&6; }
+case $ac_cv_host in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
+esac
+host=$ac_cv_host
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_host
+shift
+host_cpu=$1
+host_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+host_os=$*
+IFS=$ac_save_IFS
+case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
+
+
+
+am__api_version='1.15'
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+# Reject install programs that cannot install multiple files.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
+$as_echo_n "checking for a BSD-compatible install... " >&6; }
+if test -z "$INSTALL"; then
+if ${ac_cv_path_install+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in #((
+  ./ | .// | /[cC]/* | \
+  /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+  ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
+  /usr/ucb/* ) ;;
+  *)
+    # OSF1 and SCO ODT 3.0 have their own names for install.
+    # Don't use installbsd from OSF since it installs stuff as root
+    # by default.
+    for ac_prog in ginstall scoinst install; do
+      for ac_exec_ext in '' $ac_executable_extensions; do
+	if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
+	  if test $ac_prog = install &&
+	    grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+	    # AIX install.  It has an incompatible calling convention.
+	    :
+	  elif test $ac_prog = install &&
+	    grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+	    # program-specific install script used by HP pwplus--don't use.
+	    :
+	  else
+	    rm -rf conftest.one conftest.two conftest.dir
+	    echo one > conftest.one
+	    echo two > conftest.two
+	    mkdir conftest.dir
+	    if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
+	      test -s conftest.one && test -s conftest.two &&
+	      test -s conftest.dir/conftest.one &&
+	      test -s conftest.dir/conftest.two
+	    then
+	      ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+	      break 3
+	    fi
+	  fi
+	fi
+      done
+    done
+    ;;
+esac
+
+  done
+IFS=$as_save_IFS
+
+rm -rf conftest.one conftest.two conftest.dir
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL=$ac_cv_path_install
+  else
+    # As a last resort, use the slow shell script.  Don't cache a
+    # value for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the value is a relative name.
+    INSTALL=$ac_install_sh
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
+$as_echo "$INSTALL" >&6; }
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5
+$as_echo_n "checking whether build environment is sane... " >&6; }
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name.  Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+  *[\\\"\#\$\&\'\`$am_lf]*)
+    as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;;
+esac
+case $srcdir in
+  *[\\\"\#\$\&\'\`$am_lf\ \	]*)
+    as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;;
+esac
+
+# Do 'set' in a subshell so we don't clobber the current shell's
+# arguments.  Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+   am_has_slept=no
+   for am_try in 1 2; do
+     echo "timestamp, slept: $am_has_slept" > conftest.file
+     set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+     if test "$*" = "X"; then
+	# -L didn't work.
+	set X `ls -t "$srcdir/configure" conftest.file`
+     fi
+     if test "$*" != "X $srcdir/configure conftest.file" \
+	&& test "$*" != "X conftest.file $srcdir/configure"; then
+
+	# If neither matched, then we have a broken ls.  This can happen
+	# if, for instance, CONFIG_SHELL is bash and it inherits a
+	# broken ls alias from the environment.  This has actually
+	# happened.  Such a system could not be considered "sane".
+	as_fn_error $? "ls -t appears to fail.  Make sure there is not a broken
+  alias in your environment" "$LINENO" 5
+     fi
+     if test "$2" = conftest.file || test $am_try -eq 2; then
+       break
+     fi
+     # Just in case.
+     sleep 1
+     am_has_slept=yes
+   done
+   test "$2" = conftest.file
+   )
+then
+   # Ok.
+   :
+else
+   as_fn_error $? "newly created file is older than distributed files!
+Check your system clock" "$LINENO" 5
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+# If we didn't sleep, we still need to ensure time stamps of config.status and
+# generated files are strictly newer.
+am_sleep_pid=
+if grep 'slept: no' conftest.file >/dev/null 2>&1; then
+  ( sleep 1 ) &
+  am_sleep_pid=$!
+fi
+
+rm -f conftest.file
+
+test "$program_prefix" != NONE &&
+  program_transform_name="s&^&$program_prefix&;$program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+  program_transform_name="s&\$&$program_suffix&;$program_transform_name"
+# Double any \ or $.
+# By default was `s,x,x', remove it if useless.
+ac_script='s/[\\$]/&&/g;s/;s,x,x,$//'
+program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"`
+
+# Expand $ac_aux_dir to an absolute path.
+am_aux_dir=`cd "$ac_aux_dir" && pwd`
+
+if test x"${MISSING+set}" != xset; then
+  case $am_aux_dir in
+  *\ * | *\	*)
+    MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
+  *)
+    MISSING="\${SHELL} $am_aux_dir/missing" ;;
+  esac
+fi
+# Use eval to expand $SHELL
+if eval "$MISSING --is-lightweight"; then
+  am_missing_run="$MISSING "
+else
+  am_missing_run=
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5
+$as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;}
+fi
+
+if test x"${install_sh+set}" != xset; then
+  case $am_aux_dir in
+  *\ * | *\	*)
+    install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+  *)
+    install_sh="\${SHELL} $am_aux_dir/install-sh"
+  esac
+fi
+
+# Installed binaries are usually stripped using 'strip' when the user
+# run "make install-strip".  However 'strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the 'STRIP' environment variable to overrule this program.
+if test "$cross_compiling" != no; then
+  if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_STRIP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$STRIP"; then
+  ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
+$as_echo "$STRIP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+  ac_ct_STRIP=$STRIP
+  # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_STRIP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_STRIP"; then
+  ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_STRIP="strip"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
+$as_echo "$ac_ct_STRIP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_STRIP" = x; then
+    STRIP=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    STRIP=$ac_ct_STRIP
+  fi
+else
+  STRIP="$ac_cv_prog_STRIP"
+fi
+
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5
+$as_echo_n "checking for a thread-safe mkdir -p... " >&6; }
+if test -z "$MKDIR_P"; then
+  if ${ac_cv_path_mkdir+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in mkdir gmkdir; do
+	 for ac_exec_ext in '' $ac_executable_extensions; do
+	   as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue
+	   case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #(
+	     'mkdir (GNU coreutils) '* | \
+	     'mkdir (coreutils) '* | \
+	     'mkdir (fileutils) '4.1*)
+	       ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext
+	       break 3;;
+	   esac
+	 done
+       done
+  done
+IFS=$as_save_IFS
+
+fi
+
+  test -d ./--version && rmdir ./--version
+  if test "${ac_cv_path_mkdir+set}" = set; then
+    MKDIR_P="$ac_cv_path_mkdir -p"
+  else
+    # As a last resort, use the slow shell script.  Don't cache a
+    # value for MKDIR_P within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the value is a relative name.
+    MKDIR_P="$ac_install_sh -d"
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5
+$as_echo "$MKDIR_P" >&6; }
+
+for ac_prog in gawk mawk nawk awk
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AWK+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$AWK"; then
+  ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_AWK="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+AWK=$ac_cv_prog_AWK
+if test -n "$AWK"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5
+$as_echo "$AWK" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$AWK" && break
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
+set x ${MAKE-make}
+ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
+if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.make <<\_ACEOF
+SHELL = /bin/sh
+all:
+	@echo '@@@%%%=$(MAKE)=@@@%%%'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering ...", which would confuse us.
+case `${MAKE-make} -f conftest.make 2>/dev/null` in
+  *@@@%%%=?*=@@@%%%*)
+    eval ac_cv_prog_make_${ac_make}_set=yes;;
+  *)
+    eval ac_cv_prog_make_${ac_make}_set=no;;
+esac
+rm -f conftest.make
+fi
+if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+  SET_MAKE=
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+  SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+  am__leading_dot=.
+else
+  am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+
+# Check whether --enable-silent-rules was given.
+if test "${enable_silent_rules+set}" = set; then :
+  enableval=$enable_silent_rules;
+fi
+
+case $enable_silent_rules in # (((
+  yes) AM_DEFAULT_VERBOSITY=0;;
+   no) AM_DEFAULT_VERBOSITY=1;;
+    *) AM_DEFAULT_VERBOSITY=1;;
+esac
+am_make=${MAKE-make}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5
+$as_echo_n "checking whether $am_make supports nested variables... " >&6; }
+if ${am_cv_make_support_nested_variables+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if $as_echo 'TRUE=$(BAR$(V))
+BAR0=false
+BAR1=true
+V=1
+am__doit:
+	@$(TRUE)
+.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then
+  am_cv_make_support_nested_variables=yes
+else
+  am_cv_make_support_nested_variables=no
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5
+$as_echo "$am_cv_make_support_nested_variables" >&6; }
+if test $am_cv_make_support_nested_variables = yes; then
+    AM_V='$(V)'
+  AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
+else
+  AM_V=$AM_DEFAULT_VERBOSITY
+  AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
+fi
+AM_BACKSLASH='\'
+
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+  # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+  # is not polluted with repeated "-I."
+  am__isrc=' -I$(srcdir)'
+  # test to see if srcdir already configured
+  if test -f $srcdir/config.status; then
+    as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5
+  fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+  if (cygpath --version) >/dev/null 2>/dev/null; then
+    CYGPATH_W='cygpath -w'
+  else
+    CYGPATH_W=echo
+  fi
+fi
+
+
+# Define the identity of the package.
+ PACKAGE='gmp'
+ VERSION='6.2.0'
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE "$PACKAGE"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define VERSION "$VERSION"
+_ACEOF
+
+# Some tools Automake needs.
+
+ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"}
+
+
+AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"}
+
+
+AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"}
+
+
+AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"}
+
+
+MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
+
+# For better backward compatibility.  To be removed once Automake 1.9.x
+# dies out for good.  For more background, see:
+# <http://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
+# <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
+mkdir_p='$(MKDIR_P)'
+
+# We need awk for the "check" target (and possibly the TAP driver).  The
+# system "awk" is bad on some platforms.
+# Always define AMTAR for backward compatibility.  Yes, it's still used
+# in the wild :-(  We should find a proper way to deprecate it ...
+AMTAR='$${TAR-tar}'
+
+
+# We'll loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar  pax cpio none'
+
+am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'
+
+
+
+
+
+
+# POSIX will say in a future version that running "rm -f" with no argument
+# is OK; and we want to be able to make that assumption in our Makefile
+# recipes.  So use an aggressive probe to check that the usage we want is
+# actually supported "in the wild" to an acceptable degree.
+# See automake bug#10828.
+# To make any issue more visible, cause the running configure to be aborted
+# by default if the 'rm' program in use doesn't match our expectations; the
+# user can still override this though.
+if rm -f && rm -fr && rm -rf; then : OK; else
+  cat >&2 <<'END'
+Oops!
+
+Your 'rm' program seems unable to run without file operands specified
+on the command line, even when the '-f' option is present.  This is contrary
+to the behaviour of most rm programs out there, and not conforming with
+the upcoming POSIX standard: <http://austingroupbugs.net/view.php?id=542>
+
+Please tell bug-automake@gnu.org about your system, including the value
+of your $PATH and any error possibly output before this message.  This
+can help us improve future automake versions.
+
+END
+  if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then
+    echo 'Configuration will proceed anyway, since you have set the' >&2
+    echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2
+    echo >&2
+  else
+    cat >&2 <<'END'
+Aborting the configuration process, to ensure you take notice of the issue.
+
+You can download and install GNU coreutils to get an 'rm' implementation
+that behaves properly: <http://www.gnu.org/software/coreutils/>.
+
+If you want to complete the configuration process using your problematic
+'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM
+to "yes", and re-run configure.
+
+END
+    as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5
+  fi
+fi
+
+ac_config_headers="$ac_config_headers config.h:config.in"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5
+$as_echo_n "checking whether to enable maintainer-specific portions of Makefiles... " >&6; }
+    # Check whether --enable-maintainer-mode was given.
+if test "${enable_maintainer_mode+set}" = set; then :
+  enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval
+else
+  USE_MAINTAINER_MODE=no
+fi
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_MAINTAINER_MODE" >&5
+$as_echo "$USE_MAINTAINER_MODE" >&6; }
+   if test $USE_MAINTAINER_MODE = yes; then
+  MAINTAINER_MODE_TRUE=
+  MAINTAINER_MODE_FALSE='#'
+else
+  MAINTAINER_MODE_TRUE='#'
+  MAINTAINER_MODE_FALSE=
+fi
+
+  MAINT=$MAINTAINER_MODE_TRUE
+
+
+
+
+# Check whether --enable-assert was given.
+if test "${enable_assert+set}" = set; then :
+  enableval=$enable_assert; case $enableval in
+yes|no) ;;
+*) as_fn_error $? "bad value $enableval for --enable-assert, need yes or no" "$LINENO" 5 ;;
+esac
+else
+  enable_assert=no
+fi
+
+
+if test "$enable_assert" = "yes"; then
+
+$as_echo "#define WANT_ASSERT 1" >>confdefs.h
+
+  want_assert_01=1
+else
+  want_assert_01=0
+fi
+
+echo "define(<WANT_ASSERT>,$want_assert_01)" >> $gmp_tmpconfigm4
+
+
+
+# Check whether --enable-alloca was given.
+if test "${enable_alloca+set}" = set; then :
+  enableval=$enable_alloca; case $enableval in
+alloca|malloc-reentrant|malloc-notreentrant) ;;
+yes|no|reentrant|notreentrant) ;;
+debug) ;;
+*)
+  as_fn_error $? "bad value $enableval for --enable-alloca, need one of:
+yes no reentrant notreentrant alloca malloc-reentrant malloc-notreentrant debug" "$LINENO" 5 ;;
+esac
+else
+  enable_alloca=reentrant
+fi
+
+
+
+# IMPROVE ME: The default for C++ is disabled.  The tests currently
+# performed below for a working C++ compiler are not particularly strong,
+# and in general can't be expected to get the right setup on their own.  The
+# most significant problem is getting the ABI the same.  Defaulting CXXFLAGS
+# to CFLAGS takes only a small step towards this.  It's also probably worth
+# worrying whether the C and C++ runtimes from say gcc and a vendor C++ can
+# work together.  Some rather broken C++ installations were encountered
+# during testing, and though such things clearly aren't GMP's problem, if
+# --enable-cxx=detect were to be the default then some careful checks of
+# which, if any, C++ compiler on the system is up to scratch would be
+# wanted.
+#
+# Check whether --enable-cxx was given.
+if test "${enable_cxx+set}" = set; then :
+  enableval=$enable_cxx; case $enableval in
+yes|no|detect) ;;
+*) as_fn_error $? "bad value $enableval for --enable-cxx, need yes/no/detect" "$LINENO" 5 ;;
+esac
+else
+  enable_cxx=no
+fi
+
+
+
+# Check whether --enable-assembly was given.
+if test "${enable_assembly+set}" = set; then :
+  enableval=$enable_assembly; case $enableval in
+yes|no) ;;
+*) as_fn_error $? "bad value $enableval for --enable-assembly, need yes or no" "$LINENO" 5 ;;
+esac
+else
+  enable_assembly=yes
+fi
+
+
+
+# Check whether --enable-fft was given.
+if test "${enable_fft+set}" = set; then :
+  enableval=$enable_fft; case $enableval in
+yes|no) ;;
+*) as_fn_error $? "bad value $enableval for --enable-fft, need yes or no" "$LINENO" 5 ;;
+esac
+else
+  enable_fft=yes
+fi
+
+
+if test "$enable_fft" = "yes"; then
+
+$as_echo "#define WANT_FFT 1" >>confdefs.h
+
+fi
+
+
+# Check whether --enable-old-fft-full was given.
+if test "${enable_old_fft_full+set}" = set; then :
+  enableval=$enable_old_fft_full; case $enableval in
+yes|no) ;;
+*) as_fn_error $? "bad value $enableval for --enable-old-fft-full, need yes or no" "$LINENO" 5 ;;
+esac
+else
+  enable_old_fft_full=no
+fi
+
+
+if test "$enable_old_fft_full" = "yes"; then
+
+$as_echo "#define WANT_OLD_FFT_FULL 1" >>confdefs.h
+
+fi
+
+
+# Check whether --enable-nails was given.
+if test "${enable_nails+set}" = set; then :
+  enableval=$enable_nails; case $enableval in
+yes|no|[02468]|[0-9][02468]) ;;
+*[13579])
+  as_fn_error $? "bad value $enableval for --enable-nails, only even nail sizes supported" "$LINENO" 5 ;;
+*)
+  as_fn_error $? "bad value $enableval for --enable-nails, need yes/no/number" "$LINENO" 5 ;;
+esac
+else
+  enable_nails=no
+fi
+
+
+case $enable_nails in
+yes) GMP_NAIL_BITS=2 ;;
+no)  GMP_NAIL_BITS=0 ;;
+*)   GMP_NAIL_BITS=$enable_nails ;;
+esac
+
+
+
+# Check whether --enable-profiling was given.
+if test "${enable_profiling+set}" = set; then :
+  enableval=$enable_profiling; case $enableval in
+no|prof|gprof|instrument) ;;
+*) as_fn_error $? "bad value $enableval for --enable-profiling, need no/prof/gprof/instrument" "$LINENO" 5 ;;
+esac
+else
+  enable_profiling=no
+fi
+
+
+case $enable_profiling in
+  prof)
+
+$as_echo "#define WANT_PROFILING_PROF 1" >>confdefs.h
+
+    ;;
+  gprof)
+
+$as_echo "#define WANT_PROFILING_GPROF 1" >>confdefs.h
+
+    ;;
+  instrument)
+
+$as_echo "#define WANT_PROFILING_INSTRUMENT 1" >>confdefs.h
+
+    ;;
+esac
+
+
+echo "define(<WANT_PROFILING>,<\`$enable_profiling'>)" >> $gmp_tmpconfigm4
+
+
+# -fomit-frame-pointer is incompatible with -pg on some chips
+if test "$enable_profiling" = gprof; then
+  fomit_frame_pointer=
+else
+  fomit_frame_pointer="-fomit-frame-pointer"
+fi
+
+
+
+# Check whether --with-readline was given.
+if test "${with_readline+set}" = set; then :
+  withval=$with_readline; case $withval in
+yes|no|detect) ;;
+*) as_fn_error $? "bad value $withval for --with-readline, need yes/no/detect" "$LINENO" 5 ;;
+esac
+else
+  with_readline=detect
+fi
+
+
+
+# Check whether --enable-fat was given.
+if test "${enable_fat+set}" = set; then :
+  enableval=$enable_fat; case $enableval in
+yes|no) ;;
+*) as_fn_error $? "bad value $enableval for --enable-fat, need yes or no" "$LINENO" 5 ;;
+esac
+else
+  enable_fat=no
+fi
+
+
+
+# Check whether --enable-minithres was given.
+if test "${enable_minithres+set}" = set; then :
+  enableval=$enable_minithres; case $enableval in
+yes|no) ;;
+*) as_fn_error $? "bad value $enableval for --enable-minithres, need yes or no" "$LINENO" 5 ;;
+esac
+else
+  enable_minithres=no
+fi
+
+
+
+# Check whether --enable-fake-cpuid was given.
+if test "${enable_fake_cpuid+set}" = set; then :
+  enableval=$enable_fake_cpuid; case $enableval in
+yes|no) ;;
+*) as_fn_error $? "bad value $enableval for --enable-fake-cpuid, need yes or no" "$LINENO" 5 ;;
+esac
+else
+  enable_fake_cpuid=no
+fi
+
+
+if test "$enable_fake_cpuid" = "yes"; then
+
+$as_echo "#define WANT_FAKE_CPUID 1" >>confdefs.h
+
+fi
+
+
+if test $enable_fat = yes && test $enable_assembly = no ; then
+  as_fn_error $? "when doing a fat build, disabling assembly will not work" "$LINENO" 5
+fi
+
+if test $enable_fake_cpuid = yes && test $enable_fat = no ; then
+  as_fn_error $? "--enable-fake-cpuid requires --enable-fat" "$LINENO" 5
+fi
+
+
+tmp_host=`echo $host_cpu | sed 's/\./_/'`
+cat >>confdefs.h <<_ACEOF
+#define HAVE_HOST_CPU_$tmp_host 1
+_ACEOF
+
+
+echo "define_not_for_expansion(\`HAVE_HOST_CPU_$tmp_host')" >> $gmp_tmpconfigm4p
+
+
+
+
+
+
+# Table of compilers, options, and mpn paths.  This code has various related
+# purposes
+#
+#   - better default CC/CFLAGS selections than autoconf otherwise gives
+#   - default CC/CFLAGS selections for extra CPU types specific to GMP
+#   - a few tests for known bad compilers
+#   - choice of ABIs on suitable systems
+#   - selection of corresponding mpn search path
+#
+# After GMP specific searches and tests, the standard autoconf AC_PROG_CC is
+# called.  User selections of CC etc are respected.
+#
+# Care is taken not to use macros like AC_TRY_COMPILE during the GMP
+# pre-testing, since they of course depend on AC_PROG_CC, and also some of
+# them cache their results, which is not wanted.
+#
+# The ABI selection mechanism is unique to GMP.  All that reaches autoconf
+# is a different selection of CC/CFLAGS according to the best ABI the system
+# supports, and/or what the user selects.  Naturally the mpn assembler code
+# selected is very dependent on the ABI.
+#
+# The closest the standard tools come to a notion of ABI is something like
+# "sparc64" which encodes a CPU and an ABI together.  This doesn't seem to
+# scale well for GMP, where exact CPU types like "ultrasparc2" are wanted,
+# separate from the ABI used on them.
+#
+#
+# The variables set here are
+#
+#   cclist              the compiler choices
+#   xx_cflags           flags for compiler xx
+#   xx_cflags_maybe     flags for compiler xx, if they work
+#   xx_cppflags         cpp flags for compiler xx
+#   xx_cflags_optlist   list of sets of optional flags
+#   xx_cflags_yyy       set yyy of optional flags for compiler xx
+#   xx_ldflags          -Wc,-foo flags for libtool linking with compiler xx
+#   ar_flags            extra flags for $AR
+#   nm_flags            extra flags for $NM
+#   limb                limb size, can be "longlong"
+#   path                mpn search path
+#   extra_functions     extra mpn functions
+#   fat_path            fat binary mpn search path [if fat binary desired]
+#   fat_functions       fat functions
+#   fat_thresholds      fat thresholds
+#
+# Suppose xx_cflags_optlist="arch", then flags from $xx_cflags_arch are
+# tried, and the first flag that works will be used.  An optlist like "arch
+# cpu optimize" can be used to get multiple independent sets of flags tried.
+# The first that works from each will be used.  If no flag in a set works
+# then nothing from that set is added.
+#
+# For multiple ABIs, the scheme extends as follows.
+#
+#   abilist               set of ABI choices
+#   cclist_aa             compiler choices in ABI aa
+#   xx_aa_cflags          flags for xx in ABI aa
+#   xx_aa_cflags_maybe    flags for xx in ABI aa, if they work
+#   xx_aa_cppflags        cpp flags for xx in ABI aa
+#   xx_aa_cflags_optlist  list of sets of optional flags in ABI aa
+#   xx_aa_cflags_yyy      set yyy of optional flags for compiler xx in ABI aa
+#   xx_aa_ldflags         -Wc,-foo flags for libtool linking
+#   ar_aa_flags           extra flags for $AR in ABI aa
+#   nm_aa_flags           extra flags for $NM in ABI aa
+#   limb_aa               limb size in ABI aa, can be "longlong"
+#   path_aa               mpn search path in ABI aa
+#   extra_functions_aa    extra mpn functions in ABI aa
+#
+# As a convenience, the unadorned xx_cflags (etc) are used for the last ABI
+# in ablist, if an xx_aa_cflags for that ABI isn't given.  For example if
+# abilist="64 32" then $cc_64_cflags will be used for the 64-bit ABI, but
+# for the 32-bit either $cc_32_cflags or $cc_cflags is used, whichever is
+# defined.  This makes it easy to add some 64-bit compilers and flags to an
+# unadorned 32-bit set.
+#
+# limb=longlong (or limb_aa=longlong) applies to all compilers within that
+# ABI.  It won't work to have some needing long long and some not, since a
+# single instantiated gmp.h will be used by both.
+#
+# SPEED_CYCLECOUNTER, cyclecounter_size and CALLING_CONVENTIONS_OBJS are
+# also set here, with an ABI suffix.
+#
+#
+#
+# A table-driven approach like this to mapping cpu type to good compiler
+# options is a bit of a maintenance burden, but there's not much uniformity
+# between options specifications on different compilers.  Some sort of
+# separately updatable tool might be cute.
+#
+# The use of lots of variables like this, direct and indirect, tends to
+# obscure when and how various things are done, but unfortunately it's
+# pretty much the only way.  If shell subroutines were portable then actual
+# code like "if this .. do that" could be written, but attempting the same
+# with full copies of GMP_PROG_CC_WORKS etc expanded at every point would
+# hugely bloat the output.
+
+
+
+
+# abilist needs to be non-empty, "standard" is just a generic name here
+abilist="standard"
+
+# FIXME: We'd like to prefer an ANSI compiler, perhaps by preferring
+# c89 over cc here.  But note that on HP-UX c89 provides a castrated
+# environment, and would want to be excluded somehow.  Maybe
+# AC_PROG_CC_STDC already does enough to stick cc into ANSI mode and
+# we don't need to worry.
+#
+cclist="gcc cc"
+
+gcc_cflags="-O2 -pedantic"
+gcc_64_cflags="-O2 -pedantic"
+cc_cflags="-O"
+cc_64_cflags="-O"
+
+SPEED_CYCLECOUNTER_OBJ=
+cyclecounter_size=2
+
+HAVE_HOST_CPU_FAMILY_power=0
+
+HAVE_HOST_CPU_FAMILY_powerpc=0
+
+
+case $host in
+
+  alpha*-*-*)
+    $as_echo "#define HAVE_HOST_CPU_FAMILY_alpha 1" >>confdefs.h
+
+    case $host_cpu in
+      alphaev5* | alphapca5*)
+	path="alpha/ev5 alpha" ;;
+      alphaev67 | alphaev68 | alphaev7*)
+        path="alpha/ev67 alpha/ev6 alpha" ;;
+      alphaev6)
+	path="alpha/ev6 alpha" ;;
+      *)
+        path="alpha" ;;
+    esac
+    if test "$enable_assembly" = "yes" ; then
+       extra_functions="cntlz"
+    fi
+    gcc_cflags_optlist="asm cpu oldas" # need asm ahead of cpu, see below
+    gcc_cflags_maybe="-mieee"
+    gcc_cflags_oldas="-Wa,-oldas"     # see GMP_GCC_WA_OLDAS.
+
+    # gcc 2.7.2.3 doesn't know any -mcpu= for alpha, apparently.
+    # gcc 2.95 knows -mcpu= ev4, ev5, ev56, pca56, ev6.
+    # gcc 3.0 adds nothing.
+    # gcc 3.1 adds ev45, ev67 (but ev45 is the same as ev4).
+    # gcc 3.2 adds nothing.
+    #
+    # gcc version "2.9-gnupro-99r1" under "-O2 -mcpu=ev6" strikes internal
+    # compiler errors too easily and is rejected by GMP_PROG_CC_WORKS.  Each
+    # -mcpu=ev6 below has a fallback to -mcpu=ev56 for this reason.
+    #
+    case $host_cpu in
+      alpha)        gcc_cflags_cpu="-mcpu=ev4" ;;
+      alphaev5)     gcc_cflags_cpu="-mcpu=ev5" ;;
+      alphaev56)    gcc_cflags_cpu="-mcpu=ev56" ;;
+      alphapca56 | alphapca57)
+                    gcc_cflags_cpu="-mcpu=pca56" ;;
+      alphaev6)     gcc_cflags_cpu="-mcpu=ev6 -mcpu=ev56" ;;
+      alphaev67 | alphaev68 | alphaev7*)
+                    gcc_cflags_cpu="-mcpu=ev67 -mcpu=ev6 -mcpu=ev56" ;;
+    esac
+
+    # gcc version "2.9-gnupro-99r1" on alphaev68-dec-osf5.1 has been seen
+    # accepting -mcpu=ev6, but not putting the assembler in the right mode
+    # for what it produces.  We need to do this for it, and need to do it
+    # before testing the -mcpu options.
+    #
+    # On old versions of gcc, which don't know -mcpu=, we believe an
+    # explicit -Wa,-mev5 etc will be necessary to put the assembler in
+    # the right mode for our .asm files and longlong.h asm blocks.
+    #
+    # On newer versions of gcc, when -mcpu= is known, we must give a -Wa
+    # which is at least as high as the code gcc will generate.  gcc
+    # establishes what it needs with a ".arch" directive, our command line
+    # option seems to override that.
+    #
+    # gas prior to 2.14 doesn't accept -mev67, but -mev6 seems enough for
+    # ctlz and cttz (in 2.10.0 at least).
+    #
+    # OSF `as' accepts ev68 but stupidly treats it as ev4.  -arch only seems
+    # to affect insns like ldbu which are expanded as macros when necessary.
+    # Insns like ctlz which were never available as macros are always
+    # accepted and always generate their plain code.
+    #
+    case $host_cpu in
+      alpha)        gcc_cflags_asm="-Wa,-arch,ev4 -Wa,-mev4" ;;
+      alphaev5)     gcc_cflags_asm="-Wa,-arch,ev5 -Wa,-mev5" ;;
+      alphaev56)    gcc_cflags_asm="-Wa,-arch,ev56 -Wa,-mev56" ;;
+      alphapca56 | alphapca57)
+                    gcc_cflags_asm="-Wa,-arch,pca56 -Wa,-mpca56" ;;
+      alphaev6)     gcc_cflags_asm="-Wa,-arch,ev6 -Wa,-mev6" ;;
+      alphaev67 | alphaev68 | alphaev7*)
+                    gcc_cflags_asm="-Wa,-arch,ev67 -Wa,-mev67 -Wa,-arch,ev6 -Wa,-mev6" ;;
+    esac
+
+    # It might be better to ask "cc" whether it's Cray C or DEC C,
+    # instead of relying on the OS part of $host.  But it's hard to
+    # imagine either of those compilers anywhere except their native
+    # systems.
+    #
+
+echo "include_mpn(\`alpha/alpha-defs.m4')" >> $gmp_tmpconfigm4i
+
+    case $host in
+      *-cray-unicos*)
+        cc_cflags="-O"		# no -g, it silently disables all optimizations
+
+echo "include_mpn(\`alpha/unicos.m4')" >> $gmp_tmpconfigm4i
+
+        # Don't perform any assembly syntax tests on this beast.
+        gmp_asm_syntax_testing=no
+        ;;
+      *-*-osf*)
+
+echo "include_mpn(\`alpha/default.m4')" >> $gmp_tmpconfigm4i
+
+        cc_cflags=""
+        cc_cflags_optlist="opt cpu"
+
+        # not sure if -fast works on old versions, so make it optional
+	cc_cflags_opt="-fast -O2"
+
+	# DEC C V5.9-005 knows ev4, ev5, ev56, pca56, ev6.
+	# Compaq C V6.3-029 adds ev67.
+	#
+	case $host_cpu in
+	  alpha)       cc_cflags_cpu="-arch~ev4~-tune~ev4" ;;
+	  alphaev5)    cc_cflags_cpu="-arch~ev5~-tune~ev5" ;;
+	  alphaev56)   cc_cflags_cpu="-arch~ev56~-tune~ev56" ;;
+	  alphapca56 | alphapca57)
+            cc_cflags_cpu="-arch~pca56~-tune~pca56" ;;
+	  alphaev6)    cc_cflags_cpu="-arch~ev6~-tune~ev6" ;;
+	  alphaev67 | alphaev68 | alphaev7*)
+            cc_cflags_cpu="-arch~ev67~-tune~ev67 -arch~ev6~-tune~ev6" ;;
+	esac
+        ;;
+      *)
+
+echo "include_mpn(\`alpha/default.m4')" >> $gmp_tmpconfigm4i
+
+        ;;
+    esac
+
+    case $host in
+      *-*-unicos*)
+        # tune/alpha.asm assumes int==4bytes but unicos uses int==8bytes
+        ;;
+      *)
+        SPEED_CYCLECOUNTER_OBJ=alpha.lo
+        cyclecounter_size=1 ;;
+    esac
+    ;;
+
+
+  # Cray vector machines.
+  # This must come after alpha* so that we can recognize present and future
+  # vector processors with a wildcard.
+  *-cray-unicos*)
+    gmp_asm_syntax_testing=no
+    cclist="cc"
+    # We used to have -hscalar0 here as a workaround for miscompilation of
+    # mpz/import.c, but let's hope Cray fixes their bugs instead, since
+    # -hscalar0 causes disastrously poor code to be generated.
+    cc_cflags="-O3 -hnofastmd -htask0 -Wa,-B"
+    path="cray"
+    ;;
+
+
+  arm*-*-* | aarch64*-*-*)
+    abilist="32"
+    gcc_cflags="$gcc_cflags $fomit_frame_pointer"
+    gcc_cflags_optlist="arch fpmode neon tune"
+    gcc_64_cflags_optlist="arch tune"
+    gcc_testlist="gcc-arm-umodsi"
+    gcc_64_testlist=""
+    CALLING_CONVENTIONS_OBJS='arm32call.lo arm32check.lo'
+    CALLING_CONVENTIONS_OBJS_64=""
+    cclist_64="gcc cc"
+    any_32_testlist="sizeof-void*-4"
+    any_64_testlist="sizeof-void*-8"
+
+    # This is needed for clang, which is not content with flags like -mfpu=neon
+    # alone.
+    case $host in
+      *-*-*eabi)
+        gcc_cflags_fpmode="-mfloat-abi=softfp" ;;
+      *-*-*eabihf)
+        gcc_cflags_fpmode="-mfloat-abi=hard" ;;
+      *-*-mingw*)
+        limb_64=longlong ;;
+    esac
+
+    # FIXME: We make mandatory compiler options optional here.  We should
+    # either enforce them, or organise to strip paths as the corresponding
+    # options fail.
+    case $host_cpu in
+      armxscale | arm7ej | arm9te | arm9e* | arm10* | armv5*)
+	path="arm/v5 arm"
+	gcc_cflags_arch="-march=armv5"
+	;;
+      armsa1 | arm7t* | arm9t* | armv4t*)
+	path="arm"
+	gcc_cflags_arch="-march=armv4"
+	;;
+      arm1156 | armv6t2*)
+	path="arm/v6t2 arm/v6 arm/v5 arm"
+	gcc_cflags_arch="-march=armv6t2"
+	;;
+      arm11* | armv6*)
+	path="arm/v6 arm/v5 arm"
+	gcc_cflags_arch="-march=armv6"
+	;;
+      armcortexa5 | armv7*)
+	path="arm/v7a/cora5 arm/v6t2 arm/v6 arm/v5 arm"
+	gcc_cflags_arch="-march=armv7-a"
+	gcc_cflags_tune="-mtune=cortex-a5"
+	;;
+      armcortexa5neon)
+	path="arm/neon arm/v7a/cora5 arm/v6t2 arm/v6 arm/v5 arm"
+	gcc_cflags_neon="-mfpu=neon"
+	gcc_cflags_arch="-march=armv7-a"
+	gcc_cflags_tune="-mtune=cortex-a5"
+	;;
+      armcortexa7)
+	path="arm/v7a/cora7 arm/v6t2 arm/v6 arm/v5 arm"
+	gcc_cflags_arch="-march=armv7ve -march=armv7-a"
+	gcc_cflags_tune="-mtune=cortex-a7"
+	;;
+      armcortexa7neon)
+	path="arm/neon arm/v7a/cora7 arm/v6t2 arm/v6 arm/v5 arm"
+	gcc_cflags_arch="-march=armv7ve -march=armv7-a"
+	gcc_cflags_neon="-mfpu=neon"
+	gcc_cflags_tune="-mtune=cortex-a7"
+	;;
+      armcortexa8)
+	path="arm/v7a/cora8 arm/v6t2 arm/v6 arm/v5 arm"
+	gcc_cflags_arch="-march=armv7-a"
+	gcc_cflags_tune="-mtune=cortex-a8"
+	;;
+      armcortexa8neon)
+	path="arm/neon arm/v7a/cora8 arm/v6t2 arm/v6 arm/v5 arm"
+	gcc_cflags_arch="-march=armv7-a"
+	gcc_cflags_neon="-mfpu=neon"
+	gcc_cflags_tune="-mtune=cortex-a8"
+	;;
+      armcortexa9)
+	path="arm/v7a/cora9 arm/v6t2 arm/v6 arm/v5 arm"
+	gcc_cflags_arch="-march=armv7-a"
+	gcc_cflags_tune="-mtune=cortex-a9"
+	;;
+      armcortexa9neon)
+	path="arm/neon arm/v7a/cora9 arm/v6t2 arm/v6 arm/v5 arm"
+	gcc_cflags_arch="-march=armv7-a"
+	gcc_cflags_neon="-mfpu=neon"
+	gcc_cflags_tune="-mtune=cortex-a9"
+	;;
+      armcortexa15)
+	path="arm/v7a/cora15 arm/v6t2 arm/v6 arm/v5 arm"
+	gcc_cflags_arch="-march=armv7ve -march=armv7-a"
+	gcc_cflags_tune="-mtune=cortex-a15 -mtune=cortex-a9"
+	;;
+      armcortexa15neon)
+	path="arm/v7a/cora15/neon arm/neon arm/v7a/cora15 arm/v6t2 arm/v6 arm/v5 arm"
+	gcc_cflags_arch="-march=armv7ve -march=armv7-a"
+	gcc_cflags_neon="-mfpu=neon"
+	gcc_cflags_tune="-mtune=cortex-a15 -mtune=cortex-a9"
+	;;
+      armcortexa12 | armcortexa17)
+	path="arm/v7a/cora17 arm/v7a/cora15 arm/v6t2 arm/v6 arm/v5 arm"
+	gcc_cflags_arch="-march=armv7ve -march=armv7-a"
+	gcc_cflags_tune="-mtune=cortex-a15 -mtune=cortex-a9"
+	;;
+      armcortexa12neon | armcortexa17neon)
+	path="arm/v7a/cora17/neon arm/v7a/cora15/neon arm/neon arm/v7a/cora17 arm/v7a/cora15 arm/v6t2 arm/v6 arm/v5 arm"
+	gcc_cflags_arch="-march=armv7ve -march=armv7-a"
+	gcc_cflags_neon="-mfpu=neon"
+	gcc_cflags_tune="-mtune=cortex-a15 -mtune=cortex-a9"
+	;;
+      armcortexa53 | armcortexa53neon)
+        abilist="64 32"
+	path="arm/neon arm/v7a/cora9 arm/v6t2 arm/v6 arm/v5 arm"
+	path_64="arm64/cora53 arm64"
+	gcc_cflags_arch="-march=armv8-a"
+	gcc_cflags_neon="-mfpu=neon"
+	gcc_cflags_tune="-mtune=cortex-a53"
+	;;
+      armcortexa57 | armcortexa57neon)
+        abilist="64 32"
+	path="arm/v7a/cora15/neon arm/neon arm/v7a/cora15 arm/v6t2 arm/v6 arm/v5 arm"
+	path_64="arm64/cora57 arm64"
+	gcc_cflags_arch="-march=armv8-a"
+	gcc_cflags_neon="-mfpu=neon"
+	gcc_cflags_tune="-mtune=cortex-a57"
+	;;
+      armcortexa7[2-9] | armcortexa7[2-9]neon)
+        abilist="64 32"
+	path="arm/v7a/cora15/neon arm/neon arm/v7a/cora15 arm/v6t2 arm/v6 arm/v5 arm"
+	path_64="arm64/cora57 arm64"
+	gcc_cflags_arch="-march=armv8-a"
+	gcc_cflags_neon="-mfpu=neon"
+	gcc_cflags_tune="-mtune=cortex-a72 -mtune=cortex-a57"
+	;;
+      armexynosm1)
+        abilist="64 32"
+	path="arm/v7a/cora15/neon arm/neon arm/v7a/cora15 arm/v6t2 arm/v6 arm/v5 arm"
+	path_64="arm64"
+	gcc_cflags_arch="-march=armv8-a"
+	gcc_cflags_neon="-mfpu=neon"
+	gcc_cflags_tune="-mtune=exynosm1"
+	;;
+      armthunderx)
+        abilist="64 32"
+	path="arm/v7a/cora15/neon arm/neon arm/v7a/cora15 arm/v6t2 arm/v6 arm/v5 arm"
+	path_64="arm64"
+	gcc_cflags_arch="-march=armv8-a"
+	gcc_cflags_neon="-mfpu=neon"
+	gcc_cflags_tune="-mtune=thunderx"
+	;;
+      armxgene1)
+        abilist="64 32"
+	path="arm/v7a/cora15/neon arm/neon arm/v7a/cora15 arm/v6t2 arm/v6 arm/v5 arm"
+	path_64="arm64/xgene1 arm64"
+	gcc_cflags_arch="-march=armv8-a"
+	gcc_cflags_neon="-mfpu=neon"
+	gcc_cflags_tune="-mtune=xgene1"
+	;;
+      aarch64*)
+        abilist="64 32"
+	path="arm/v7a/cora15/neon arm/neon arm/v7a/cora15 arm/v6t2 arm/v6 arm/v5 arm"
+	path_64="arm64"
+	gcc_cflags_arch="-march=armv8-a"
+	gcc_cflags_neon="-mfpu=neon"
+	gcc_cflags_tune=""
+	;;
+      *)
+	path="arm"
+	gcc_cflags_arch="-march=armv4"
+
+echo "define(<NOTHUMB>,1)" >> $gmp_tmpconfigm4
+
+	;;
+    esac
+    ;;
+
+
+  # Fujitsu
+  f30[01]-fujitsu-sysv*)
+    cclist="gcc vcc"
+    # FIXME: flags for vcc?
+    vcc_cflags="-g"
+    path="fujitsu"
+    ;;
+
+
+  hppa*-*-*)
+    # HP cc (the one sold separately) is K&R by default, but AM_C_PROTOTYPES
+    # will add "-Ae", or "-Aa -D_HPUX_SOURCE", to put it into ansi mode, if
+    # possible.
+    #
+    # gcc for hppa 2.0 can be built either for 2.0n (32-bit) or 2.0w
+    # (64-bit), but not both, so there's no option to choose the desired
+    # mode, we must instead detect which of the two it is.  This is done by
+    # checking sizeof(long), either 4 or 8 bytes respectively.  Do this in
+    # ABI=1.0 too, in case someone tries to build that with a 2.0w gcc.
+    #
+    gcc_cflags_optlist="arch"
+    gcc_testlist="sizeof-long-4"
+    SPEED_CYCLECOUNTER_OBJ=hppa.lo
+    cyclecounter_size=1
+
+    # FIXME: For hppa2.0*, path should be "pa32/hppa2_0 pa32/hppa1_1 pa32".
+    # (Can't remember why this isn't done already, have to check what .asm
+    # files are available in each and how they run on a typical 2.0 cpu.)
+    #
+    case $host_cpu in
+      hppa1.0*)    path="pa32" ;;
+      hppa7000*)   path="pa32/hppa1_1 pa32" ;;
+      hppa2.0* | hppa64)
+                   path="pa32/hppa2_0 pa32/hppa1_1/pa7100 pa32/hppa1_1 pa32" ;;
+      *)           # default to 7100
+                   path="pa32/hppa1_1/pa7100 pa32/hppa1_1 pa32" ;;
+    esac
+
+    # gcc 2.7.2.3 knows -mpa-risc-1-0 and -mpa-risc-1-1
+    # gcc 2.95 adds -mpa-risc-2-0, plus synonyms -march=1.0, 1.1 and 2.0
+    #
+    # We don't use -mpa-risc-2-0 in ABI=1.0 because 64-bit registers may not
+    # be saved by the kernel on an old system.  Actually gcc (as of 3.2)
+    # only adds a few float instructions with -mpa-risc-2-0, so it would
+    # probably be safe, but let's not take the chance.  In any case, a
+    # configuration like --host=hppa2.0 ABI=1.0 is far from optimal.
+    #
+    case $host_cpu in
+      hppa1.0*)           gcc_cflags_arch="-mpa-risc-1-0" ;;
+      *)                  # default to 7100
+                          gcc_cflags_arch="-mpa-risc-1-1" ;;
+    esac
+
+    case $host_cpu in
+      hppa1.0*)    cc_cflags="+O2" ;;
+      *)           # default to 7100
+                   cc_cflags="+DA1.1 +O2" ;;
+    esac
+
+    case $host in
+      hppa2.0*-*-* | hppa64-*-*)
+	cclist_20n="gcc cc"
+        abilist="2.0n 1.0"
+        path_20n="pa64"
+	limb_20n=longlong
+        any_20n_testlist="sizeof-long-4"
+        SPEED_CYCLECOUNTER_OBJ_20n=hppa2.lo
+        cyclecounter_size_20n=2
+
+        # -mpa-risc-2-0 is only an optional flag, in case an old gcc is
+        # used.  Assembler support for 2.0 is essential though, for our asm
+        # files.
+	gcc_20n_cflags="$gcc_cflags"
+	gcc_20n_cflags_optlist="arch"
+        gcc_20n_cflags_arch="-mpa-risc-2-0 -mpa-risc-1-1"
+        gcc_20n_testlist="sizeof-long-4 hppa-level-2.0"
+
+        cc_20n_cflags="+DA2.0 +e +O2 -Wl,+vnocompatwarnings"
+        cc_20n_testlist="hpc-hppa-2-0"
+
+	# ABI=2.0w is available for hppa2.0w and hppa2.0, but not for
+	# hppa2.0n, on the assumption that that the latter indicates a
+	# desire for ABI=2.0n.
+	case $host in
+        hppa2.0n-*-*) ;;
+        *)
+          # HPUX 10 and earlier cannot run 2.0w.  Not sure about other
+          # systems (GNU/Linux for instance), but lets assume they're ok.
+          case $host in
+            *-*-hpux[1-9] | *-*-hpux[1-9].* | *-*-hpux10 | *-*-hpux10.*) ;;
+            *)    abilist="2.0w $abilist" ;;
+          esac
+
+          cclist_20w="gcc cc"
+	  gcc_20w_cflags="$gcc_cflags -mpa-risc-2-0"
+          cc_20w_cflags="+DD64 +O2"
+          cc_20w_testlist="hpc-hppa-2-0"
+          path_20w="pa64"
+	  any_20w_testlist="sizeof-long-8"
+          SPEED_CYCLECOUNTER_OBJ_20w=hppa2w.lo
+          cyclecounter_size_20w=2
+	  ;;
+        esac
+        ;;
+    esac
+    ;;
+
+
+  ia64*-*-* | itanium-*-* | itanium2-*-*)
+    abilist="64"
+
+echo "include_mpn(\`ia64/ia64-defs.m4')" >> $gmp_tmpconfigm4i
+
+    SPEED_CYCLECOUNTER_OBJ=ia64.lo
+    any_32_testlist="sizeof-long-4"
+
+    case $host_cpu in
+      itanium)   path="ia64/itanium  ia64" ;;
+      itanium2)  path="ia64/itanium2 ia64" ;;
+      *)         path="ia64" ;;
+    esac
+
+    gcc_64_cflags_optlist="tune"
+    gcc_32_cflags_optlist=$gcc_64_cflags_optlist
+
+    # gcc pre-release 3.4 adds -mtune itanium and itanium2
+    case $host_cpu in
+      itanium)   gcc_cflags_tune="-mtune=itanium" ;;
+      itanium2)  gcc_cflags_tune="-mtune=itanium2" ;;
+    esac
+
+    case $host in
+      *-*-linux*)
+	cclist="gcc icc"
+	icc_cflags="-no-gcc"
+	icc_cflags_optlist="opt"
+	# Don't use -O3, it is for "large data sets" and also miscompiles GMP.
+	# But icc miscompiles GMP at any optimization level, at higher levels
+	# it miscompiles more files...
+	icc_cflags_opt="-O2 -O1"
+	icc_cflags_opt_maybe="-fp-model~precise"
+	;;
+
+      *-*-hpux*)
+        # HP cc sometimes gets internal errors if the optimization level is
+        # too high.  GMP_PROG_CC_WORKS detects this, the "_opt" fallbacks
+        # let us use whatever seems to work.
+        #
+        abilist="32 64"
+        any_64_testlist="sizeof-long-8"
+
+        cclist_32="gcc cc"
+        path_32="ia64"
+        cc_32_cflags=""
+        cc_32_cflags_optlist="opt"
+        cc_32_cflags_opt="+O2 +O1"
+        gcc_32_cflags="$gcc_cflags -milp32"
+        limb_32=longlong
+        SPEED_CYCLECOUNTER_OBJ_32=ia64.lo
+        cyclecounter_size_32=2
+
+        # Must have +DD64 in CPPFLAGS to get the right __LP64__ for headers,
+        # but also need it in CFLAGS for linking programs, since automake
+        # only uses CFLAGS when linking, not CPPFLAGS.
+        # FIXME: Maybe should use cc_64_ldflags for this, but that would
+        # need GMP_LDFLAGS used consistently by all the programs.
+        #
+        cc_64_cflags="+DD64"
+        cc_64_cppflags="+DD64"
+        cc_64_cflags_optlist="opt"
+        cc_64_cflags_opt="+O2 +O1"
+        gcc_64_cflags="$gcc_cflags -mlp64"
+        ;;
+    esac
+    ;;
+
+
+  # Motorola 68k
+  #
+  m68k-*-* | m68[0-9][0-9][0-9]-*-*)
+    $as_echo "#define HAVE_HOST_CPU_FAMILY_m68k 1" >>confdefs.h
+
+
+echo "include_mpn(\`m68k/m68k-defs.m4')" >> $gmp_tmpconfigm4i
+
+    gcc_cflags="$gcc_cflags $fomit_frame_pointer"
+    gcc_cflags_optlist="arch"
+
+    # gcc 2.7.2 knows -m68000, -m68020, -m68030, -m68040.
+    # gcc 2.95 adds -mcpu32, -m68060.
+    # FIXME: Maybe "-m68020 -mnobitfield" would suit cpu32 on 2.7.2.
+    #
+    case $host_cpu in
+    m68020)  gcc_cflags_arch="-m68020" ;;
+    m68030)  gcc_cflags_arch="-m68030" ;;
+    m68040)  gcc_cflags_arch="-m68040" ;;
+    m68060)  gcc_cflags_arch="-m68060 -m68000" ;;
+    m68360)  gcc_cflags_arch="-mcpu32 -m68000" ;;
+    *)       gcc_cflags_arch="-m68000" ;;
+    esac
+
+    # FIXME: m68k/mc68020 looks like it's ok for cpu32, but this wants to be
+    # tested.  Will need to introduce an m68k/cpu32 if m68k/mc68020 ever uses
+    # the bitfield instructions.
+    case $host_cpu in
+    m680[234]0 | m68360)  path="m68k/mc68020 m68k" ;;
+    *)                      path="m68k" ;;
+    esac
+    ;;
+
+
+  # Motorola 88k
+  m88k*-*-*)
+    path="m88k"
+    ;;
+  m88110*-*-*)
+    gcc_cflags="$gcc_cflags -m88110"
+    path="m88k/mc88110 m88k"
+    ;;
+
+
+  # IRIX 5 and earlier can only run 32-bit o32.
+  #
+  # IRIX 6 and up always has a 64-bit mips CPU can run n32 or 64.  n32 is
+  # preferred over 64, but only because that's been the default in past
+  # versions of GMP.  The two are equally efficient.
+  #
+  # Linux kernel 2.2.13 arch/mips/kernel/irixelf.c has a comment about not
+  # supporting n32 or 64.
+  #
+  # For reference, libtool (eg. 1.5.6) recognises the n32 ABI and knows the
+  # right options to use when linking (both cc and gcc), so no need for
+  # anything special from us.
+  #
+  mips*-*-*)
+    abilist="o32"
+    gcc_cflags_optlist="abi"
+    gcc_cflags_abi="-mabi=32 -m32"
+    gcc_testlist="gcc-mips-o32"
+    path="mips32"
+    cc_cflags="-O2 -o32"   # no -g, it disables all optimizations
+    # this suits both mips32 and mips64
+
+echo "include_mpn(\`mips32/mips-defs.m4')" >> $gmp_tmpconfigm4i
+
+
+    case $host in
+      mips64*-*-* | mipsisa64*-*-* | mips*-*-irix[6789]*)
+        abilist="n32 64 o32"
+
+        cclist_n32="gcc cc"
+        gcc_n32_cflags_optlist="abi"
+        gcc_n32_cflags="$gcc_cflags"
+        gcc_n32_cflags_abi="-mabi=n32 -mn32"
+        cc_n32_cflags="-O2 -n32"	# no -g, it disables all optimizations
+        limb_n32=longlong
+
+        cclist_64="gcc cc"
+        gcc_64_cflags_optlist="abi"
+        gcc_64_cflags="$gcc_cflags"
+        gcc_64_cflags_abi="-mabi=64 -m64"
+        gcc_64_ldflags="-Wc,-mabi=64"
+        cc_64_cflags="-O2 -64"		# no -g, it disables all optimizations
+        cc_64_ldflags="-Wc,-64"
+
+	case $host_cpu in
+	  mips64r[6789]* | mipsisa64r[6789]*)
+	    path_n32="mips64/r6 mips64"
+	    path_64="mips64/r6 mips64"
+	    ;;
+	  *)
+	    path_n32="mips64/hilo mips64"
+	    path_64="mips64/hilo mips64"
+	    ;;
+	esac
+
+        ;;
+    esac
+    ;;
+
+
+  # Darwin (powerpc-apple-darwin1.3) has it's hacked gcc installed as cc.
+  # Our usual "gcc in disguise" detection means gcc_cflags etc here gets
+  # used.
+  #
+  # The darwin pre-compiling preprocessor is disabled with -no-cpp-precomp
+  # since it doesn't like "__attribute__ ((mode (SI)))" etc in gmp-impl.h,
+  # and so always ends up running the plain preprocessor anyway.  This could
+  # be done in CPPFLAGS rather than CFLAGS, but there's not many places
+  # preprocessing is done separately, and this is only a speedup, the normal
+  # preprocessor gets run if there's any problems.
+  #
+  # We used to use -Wa,-mppc with gcc, but can't remember exactly why.
+  # Presumably it was for old versions of gcc where -mpowerpc doesn't put
+  # the assembler in the right mode.  In any case -Wa,-mppc is not good, for
+  # instance -mcpu=604 makes recent gcc use -m604 to get access to the
+  # "fsel" instruction, but a -Wa,-mppc overrides that, making code that
+  # comes out with fsel fail.
+  #
+  # (Note also that the darwin assembler doesn't accept "-mppc", so any
+  # -Wa,-mppc was used only if it worked.  The right flag on darwin would be
+  # "-arch ppc" or some such, but that's already the default.)
+  #
+  powerpc*-*-* | power[3-9]-*-*)
+    $as_echo "#define HAVE_HOST_CPU_FAMILY_powerpc 1" >>confdefs.h
+
+    HAVE_HOST_CPU_FAMILY_powerpc=1
+    abilist="32"
+    cclist="gcc cc"
+    cc_cflags="-O2"
+    gcc_32_cflags_maybe="-m32"
+    gcc_cflags_optlist="precomp subtype asm cpu"
+    gcc_cflags_precomp="-no-cpp-precomp"
+    gcc_cflags_subtype="-force_cpusubtype_ALL"	# for vmx on darwin
+    gcc_cflags_asm=""
+    gcc_cflags_cpu=""
+    vmx_path=""
+
+    # grab this object, though it's not a true cycle counter routine
+    SPEED_CYCLECOUNTER_OBJ=powerpc.lo
+    cyclecounter_size=0
+
+    case $host_cpu in
+      powerpc740 | powerpc750)
+        path="powerpc32/750 powerpc32" ;;
+      powerpc7400 | powerpc7410)
+        path="powerpc32/vmx powerpc32/750 powerpc32" ;;
+      powerpc74[45]?)
+        path="powerpc32/vmx powerpc32" ;;
+      *)
+        path="powerpc32" ;;
+    esac
+
+    case $host_cpu in
+      powerpc401)   gcc_cflags_cpu="-mcpu=401" ;;
+      powerpc403)   gcc_cflags_cpu="-mcpu=403"
+		    xlc_cflags_arch="-qarch=403 -qarch=ppc" ;;
+      powerpc405)   gcc_cflags_cpu="-mcpu=405" ;;
+      powerpc505)   gcc_cflags_cpu="-mcpu=505" ;;
+      powerpc601)   gcc_cflags_cpu="-mcpu=601"
+		    xlc_cflags_arch="-qarch=601 -qarch=ppc" ;;
+      powerpc602)   gcc_cflags_cpu="-mcpu=602"
+		    xlc_cflags_arch="-qarch=602 -qarch=ppc" ;;
+      powerpc603)   gcc_cflags_cpu="-mcpu=603"
+		    xlc_cflags_arch="-qarch=603 -qarch=ppc" ;;
+      powerpc603e)  gcc_cflags_cpu="-mcpu=603e -mcpu=603"
+		    xlc_cflags_arch="-qarch=603 -qarch=ppc" ;;
+      powerpc604)   gcc_cflags_cpu="-mcpu=604"
+		    xlc_cflags_arch="-qarch=604 -qarch=ppc" ;;
+      powerpc604e)  gcc_cflags_cpu="-mcpu=604e -mcpu=604"
+		    xlc_cflags_arch="-qarch=604 -qarch=ppc" ;;
+      powerpc620)   gcc_cflags_cpu="-mcpu=620" ;;
+      powerpc630)   gcc_cflags_cpu="-mcpu=630"
+		    xlc_cflags_arch="-qarch=pwr3"
+		    cpu_path="p3 p3-p7" ;;
+      powerpc740)   gcc_cflags_cpu="-mcpu=740" ;;
+      powerpc7400 | powerpc7410)
+		    gcc_cflags_asm="-Wa,-maltivec"
+		    gcc_cflags_cpu="-mcpu=7400 -mcpu=750" ;;
+      powerpc74[45]?)
+		    gcc_cflags_asm="-Wa,-maltivec"
+		    gcc_cflags_cpu="-mcpu=7450" ;;
+      powerpc750)   gcc_cflags_cpu="-mcpu=750" ;;
+      powerpc801)   gcc_cflags_cpu="-mcpu=801" ;;
+      powerpc821)   gcc_cflags_cpu="-mcpu=821" ;;
+      powerpc823)   gcc_cflags_cpu="-mcpu=823" ;;
+      powerpc860)   gcc_cflags_cpu="-mcpu=860" ;;
+      powerpc970)   gcc_cflags_cpu="-mtune=970"
+		    xlc_cflags_arch="-qarch=970 -qarch=pwr3"
+		    vmx_path="powerpc64/vmx"
+		    cpu_path="p4 p3-p7" ;;
+      power4)	    gcc_cflags_cpu="-mtune=power4"
+		    xlc_cflags_arch="-qarch=pwr4"
+		    cpu_path="p4 p3-p7" ;;
+      power5)	    gcc_cflags_cpu="-mtune=power5 -mtune=power4"
+		    xlc_cflags_arch="-qarch=pwr5"
+		    cpu_path="p5 p4 p3-p7" ;;
+      power6)	    gcc_cflags_cpu="-mtune=power6"
+		    xlc_cflags_arch="-qarch=pwr6"
+		    cpu_path="p6 p3-p7" ;;
+      power7)	    gcc_cflags_cpu="-mtune=power7 -mtune=power5"
+		    xlc_cflags_arch="-qarch=pwr7 -qarch=pwr5"
+		    cpu_path="p7 p5 p4 p3-p7" ;;
+      power8)	    gcc_cflags_cpu="-mtune=power8 -mtune=power7 -mtune=power5"
+		    xlc_cflags_arch="-qarch=pwr8 -qarch=pwr7 -qarch=pwr5"
+		    cpu_path="p8 p7 p5 p4 p3-p7" ;;
+      power9)	    gcc_cflags_cpu="-mtune=power9 -mtune=power8 -mtune=power7 -mtune=power5"
+		    xlc_cflags_arch="-qarch=pwr9 -qarch=pwr8 -qarch=pwr7 -qarch=pwr5"
+		    cpu_path="p9 p8 p7 p5 p4 p3-p7" ;;
+    esac
+
+    case $host in
+      *-*-aix*)
+	cclist="gcc xlc cc"
+	gcc_32_cflags_maybe="-maix32"
+	xlc_cflags="-O2 -qmaxmem=20000"
+	xlc_cflags_optlist="arch"
+	xlc_32_cflags_maybe="-q32"
+	ar_32_flags="-X32"
+	nm_32_flags="-X32"
+    esac
+
+    case $host in
+      powerpc64-*-* | powerpc64le-*-* | powerpc620-*-* | powerpc630-*-* | powerpc970-*-* | power[3-9]-*-*)
+	case $host in
+	  *-*-aix*)
+	    # On AIX a true 64-bit ABI is available.
+	    # Need -Wc to pass object type flags through to the linker.
+	    abilist="mode64 $abilist"
+	    cclist_mode64="gcc xlc"
+	    gcc_mode64_cflags="$gcc_cflags -maix64 -mpowerpc64"
+	    gcc_mode64_cflags_optlist="cpu"
+	    gcc_mode64_ldflags="-Wc,-maix64"
+	    xlc_mode64_cflags="-O2 -q64 -qmaxmem=20000"
+	    xlc_mode64_cflags_optlist="arch"
+	    xlc_mode64_ldflags="-Wc,-q64"
+	    # Must indicate object type to ar and nm
+	    ar_mode64_flags="-X64"
+	    nm_mode64_flags="-X64"
+	    path_mode64=""
+	    p=""
+	    for i in $cpu_path
+	      do path_mode64="${path_mode64}powerpc64/mode64/$i "
+		 path_mode64="${path_mode64}powerpc64/$i "
+		 p="${p} powerpc32/$i "
+	      done
+	    path_mode64="${path_mode64}powerpc64/mode64 $vmx_path powerpc64"
+	    path="$p $path"
+	    # grab this object, though it's not a true cycle counter routine
+	    SPEED_CYCLECOUNTER_OBJ_mode64=powerpc64.lo
+	    cyclecounter_size_mode64=0
+	    ;;
+	  *-*-darwin*)
+	    # On Darwin we can use 64-bit instructions with a longlong limb,
+	    # but the chip still in 32-bit mode.
+	    # In theory this can be used on any OS which knows how to save
+	    # 64-bit registers in a context switch.
+	    #
+	    # Note that we must use -mpowerpc64 with gcc, since the
+	    # longlong.h macros expect limb operands in a single 64-bit
+	    # register, not two 32-bit registers as would be given for a
+	    # long long without -mpowerpc64.  In theory we could detect and
+	    # accommodate both styles, but the proper 64-bit registers will
+	    # be fastest and are what we really want to use.
+	    #
+	    # One would think -mpowerpc64 would set the assembler in the right
+	    # mode to handle 64-bit instructions.  But for that, also
+	    # -force_cpusubtype_ALL is needed.
+	    #
+	    # Do not use -fast for Darwin, it actually adds options
+	    # incompatible with a shared library.
+	    #
+	    abilist="mode64 mode32 $abilist"
+	    gcc_cflags_opt="-O2 -O1"	# will this become used?
+	    cclist_mode32="gcc"
+	    gcc_mode32_cflags_maybe="-m32"
+	    gcc_mode32_cflags="-mpowerpc64"
+	    gcc_mode32_cflags_optlist="subtype cpu opt"
+	    gcc_mode32_cflags_subtype="-force_cpusubtype_ALL"
+	    gcc_mode32_cflags_opt="-O2 -O1"
+	    limb_mode32=longlong
+	    cclist_mode64="gcc"
+	    gcc_mode64_cflags="-m64"
+	    gcc_mode64_cflags_optlist="cpu opt"
+	    gcc_mode64_cflags_opt="-O2 -O1"
+	    path_mode64=""
+	    path_mode32=""
+	    p=""
+	    for i in $cpu_path
+	      do path_mode64="${path_mode64}powerpc64/mode64/$i "
+		 path_mode64="${path_mode64}powerpc64/$i "
+		 path_mode32="${path_mode32}powerpc64/mode32/$i "
+		 path_mode32="${path_mode32}powerpc64/$i "
+		 p="${p} powerpc32/$i "
+	      done
+	    path_mode64="${path_mode64}powerpc64/mode64 $vmx_path powerpc64"
+	    path_mode32="${path_mode32}powerpc64/mode32 $vmx_path powerpc64"
+	    path="$p $path"
+	    SPEED_CYCLECOUNTER_OBJ_mode64=powerpc64.lo
+	    cyclecounter_size_mode64=0
+	    any_mode64_testlist="sizeof-long-8"
+	    ;;
+	  *-*-linux* | *-*-*bsd*)
+	    # On GNU/Linux, assume the processor is in 64-bit mode.  Some
+	    # environments have a gcc that is always in 64-bit mode, while
+	    # others require -m64, hence the use of cflags_maybe.  The
+	    # sizeof-long-8 test checks the mode is right (for the no option
+	    # case).
+	    #
+	    # -mpowerpc64 is not used, since it should be the default in
+	    # 64-bit mode.  (We need its effect for the various longlong.h
+	    # asm macros to be right of course.)
+	    #
+	    # gcc64 was an early port of gcc to 64-bit mode, but should be
+	    # obsolete before too long.  We prefer plain gcc when it knows
+	    # 64-bits.
+	    #
+	    abilist="mode64 mode32 $abilist"
+	    cclist_mode32="gcc"
+	    gcc_mode32_cflags_maybe="-m32"
+	    gcc_mode32_cflags="-mpowerpc64"
+	    gcc_mode32_cflags_optlist="cpu opt"
+	    gcc_mode32_cflags_opt="-O2 -O1"
+	    limb_mode32=longlong
+	    cclist_mode64="gcc gcc64"
+	    gcc_mode64_cflags_maybe="-m64"
+	    gcc_mode64_cflags_optlist="cpu opt"
+	    gcc_mode64_cflags_opt="-O2 -O1"
+	    path_mode64=""
+	    path_mode32=""
+	    p=""
+	    for i in $cpu_path
+	      do path_mode64="${path_mode64}powerpc64/mode64/$i "
+		 path_mode64="${path_mode64}powerpc64/$i "
+		 path_mode32="${path_mode32}powerpc64/mode32/$i "
+		 path_mode32="${path_mode32}powerpc64/$i "
+		 p="${p} powerpc32/$i "
+	      done
+	    path_mode64="${path_mode64}powerpc64/mode64 $vmx_path powerpc64"
+	    path_mode32="${path_mode32}powerpc64/mode32 $vmx_path powerpc64"
+	    path="$p $path"
+	    SPEED_CYCLECOUNTER_OBJ_mode64=powerpc64.lo
+	    cyclecounter_size_mode64=0
+	    any_mode64_testlist="sizeof-long-8"
+	    ;;
+	esac
+	;;
+    esac
+    ;;
+
+
+  # POWER 32-bit
+  power-*-* | power[12]-*-* | power2sc-*-*)
+    $as_echo "#define HAVE_HOST_CPU_FAMILY_power 1" >>confdefs.h
+
+    HAVE_HOST_CPU_FAMILY_power=1
+    cclist="gcc"
+    if test "$enable_assembly" = "yes" ; then
+      extra_functions="udiv_w_sdiv"
+    fi
+    path="power"
+
+    # gcc 2.7.2 knows rios1, rios2, rsc
+    #
+    # -mcpu=rios2 can tickle an AIX assembler bug (see GMP_PROG_CC_WORKS) so
+    # there needs to be a fallback to just -mpower.
+    #
+    gcc_cflags_optlist="cpu"
+    case $host in
+      power-*-*)    gcc_cflags_cpu="-mcpu=power -mpower" ;;
+      power1-*-*)   gcc_cflags_cpu="-mcpu=rios1 -mpower" ;;
+      power2-*-*)   gcc_cflags_cpu="-mcpu=rios2 -mpower" ;;
+      power2sc-*-*) gcc_cflags_cpu="-mcpu=rsc   -mpower" ;;
+    esac
+    case $host in
+    *-*-aix*)
+      cclist="gcc xlc"
+      xlc_cflags="-O2 -qarch=pwr -qmaxmem=20000"
+      ;;
+    esac
+    ;;
+
+
+  # RISC-V
+  riscv64-*-*)
+    cclist="gcc"
+    path="riscv/64"
+    ;;
+
+
+  # IBM System/390 and z/Architecture
+  s390-*-* | z900esa-*-* | z990esa-*-* | z9esa-*-* | z10esa-*-* | z196esa-*-* | s390x-*-* | z900-*-* | z990-*-* | z9-*-* | z10-*-* | z196-*-*)
+    abilist="32"
+    gcc_cflags="$gcc_cflags $fomit_frame_pointer"
+    gcc_cflags_optlist="arch"
+    path="s390_32"
+    if test "$enable_assembly" = "yes" ; then
+       extra_functions="udiv_w_sdiv"
+    fi
+    gcc_32_cflags_maybe="-m31"
+
+    case $host_cpu in
+      s390)
+	;;
+      z900 | z900esa)
+        cpu="z900"
+        gccarch="$cpu"
+	path="s390_32/esame/$cpu s390_32/esame s390_32"
+	gcc_cflags_arch="-march=$gccarch"
+	cat >>confdefs.h <<_ACEOF
+#define HAVE_HOST_CPU_s390_$cpu 1
+_ACEOF
+
+	$as_echo "#define HAVE_HOST_CPU_s390_zarch 1" >>confdefs.h
+
+	extra_functions=""
+        ;;
+      z990 | z990esa)
+        cpu="z990"
+        gccarch="$cpu"
+	path="s390_32/esame/$cpu s390_32/esame s390_32"
+	gcc_cflags_arch="-march=$gccarch"
+	cat >>confdefs.h <<_ACEOF
+#define HAVE_HOST_CPU_s390_$cpu 1
+_ACEOF
+
+	$as_echo "#define HAVE_HOST_CPU_s390_zarch 1" >>confdefs.h
+
+	extra_functions=""
+        ;;
+      z9 | z9esa)
+        cpu="z9"
+	gccarch="z9-109"
+	path="s390_32/esame/$cpu s390_32/esame s390_32"
+	gcc_cflags_arch="-march=$gccarch"
+	cat >>confdefs.h <<_ACEOF
+#define HAVE_HOST_CPU_s390_$cpu 1
+_ACEOF
+
+	$as_echo "#define HAVE_HOST_CPU_s390_zarch 1" >>confdefs.h
+
+	extra_functions=""
+        ;;
+      z10 | z10esa)
+        cpu="z10"
+	gccarch="z10"
+	path="s390_32/esame/$cpu s390_32/esame s390_32"
+	gcc_cflags_arch="-march=$gccarch"
+	cat >>confdefs.h <<_ACEOF
+#define HAVE_HOST_CPU_s390_$cpu 1
+_ACEOF
+
+	$as_echo "#define HAVE_HOST_CPU_s390_zarch 1" >>confdefs.h
+
+	extra_functions=""
+        ;;
+      z196 | z196esa)
+        cpu="z196"
+	gccarch="z196"
+	path="s390_32/esame/$cpu s390_32/esame s390_32"
+	gcc_cflags_arch="-march=$gccarch"
+	cat >>confdefs.h <<_ACEOF
+#define HAVE_HOST_CPU_s390_$cpu 1
+_ACEOF
+
+	$as_echo "#define HAVE_HOST_CPU_s390_zarch 1" >>confdefs.h
+
+	extra_functions=""
+        ;;
+      esac
+
+    case $host in
+      s390x-*-* | z900-*-* | z990-*-* | z9-*-* | z10-*-* | z196-*-*)
+	abilist="64 32"
+	cclist_64="gcc"
+	gcc_64_cflags_optlist="arch"
+	gcc_64_cflags="$gcc_cflags -m64"
+	path_64="s390_64/$host_cpu s390_64"
+	extra_functions=""
+	;;
+      esac
+    ;;
+
+
+  sh-*-*)   path="sh" ;;
+  sh[2-4]-*-*)  path="sh/sh2 sh" ;;
+
+
+  *sparc*-*-*)
+    # sizeof(long)==4 or 8 is tested, to ensure we get the right ABI.  We've
+    # had various bug reports where users have set CFLAGS for their desired
+    # mode, but not set our ABI.  For some reason it's sparc where this
+    # keeps coming up, presumably users there are accustomed to driving the
+    # compiler mode that way.  The effect of our testlist setting is to
+    # reject ABI=64 in favour of ABI=32 if the user has forced the flags to
+    # 32-bit mode.
+    #
+    abilist="32"
+    cclist="gcc acc cc"
+    any_testlist="sizeof-long-4"
+
+echo "include_mpn(\`sparc32/sparc-defs.m4')" >> $gmp_tmpconfigm4i
+
+
+    case $host_cpu in
+      sparcv8 | microsparc | turbosparc)
+        path="sparc32/v8 sparc32" ;;
+      supersparc)
+        path="sparc32/v8/supersparc sparc32/v8 sparc32" ;;
+      sparc64 | sparcv9* | ultrasparc | ultrasparc[234]*)
+        path="sparc32/v9 sparc32/v8 sparc32" ;;
+      ultrasparct[12345])
+        path="sparc32/ultrasparct1 sparc32/v8 sparc32" ;;
+      *)
+        path="sparc32" ;;
+    esac
+
+    # gcc 2.7.2 doesn't know about v9 and doesn't pass -xarch=v8plus to the
+    # assembler.  Add it explicitly since the solaris assembler won't accept
+    # our sparc32/v9 asm code without it.  gas accepts -xarch=v8plus too, so
+    # it can be in the cflags unconditionally (though gas doesn't need it).
+    #
+    # gcc -m32 is needed to force 32-bit mode on a dual-ABI system, but past
+    # gcc doesn't know that flag, hence cflags_maybe.  Note that -m32 cannot
+    # be done through the optlist since the plain cflags would be run first
+    # and we don't want to require the default mode (whatever it is) works.
+    #
+    # Note it's gcc_32_cflags_maybe and not gcc_cflags_maybe because the
+    # latter would be used in the 64-bit ABI on systems like "*bsd" where
+    # abilist="64" only.
+    #
+    gcc_32_cflags_maybe="-m32"
+    gcc_cflags_optlist="cpu asm"
+
+    # gcc 2.7.2 knows -mcypress, -msupersparc, -mv8, -msparclite.
+    # gcc 2.95 knows -mcpu= v7, hypersparc, sparclite86x, f930, f934,
+    #   sparclet, tsc701, v9, ultrasparc.  A warning is given that the
+    #   plain -m forms will disappear.
+    # gcc 3.3 adds ultrasparc3.
+    #
+    case $host_cpu in
+      supersparc*)
+			gcc_cflags_cpu="-mcpu=supersparc -msupersparc"
+			gcc_cflags_asm="-Wa,-Av8 -Wa,-xarch=v8";;
+      sparcv8 | microsparc* | turbosparc | hypersparc*)
+			gcc_cflags_cpu="-mcpu=v8 -mv8"
+			gcc_cflags_asm="-Wa,-Av8 -Wa,-xarch=v8";;
+      sparc64 | sparcv9*)
+			gcc_cflags_cpu="-mcpu=v9"
+			gcc_32_cflags_asm="-Wa,-Av8 -Wa,-xarch=v8plus"
+			gcc_64_cflags_asm="-Wa,-Av9 -Wa,-xarch=v9";;
+      ultrasparc1 | ultrasparc2*)
+			gcc_cflags_cpu="-mcpu=ultrasparc -mcpu=v9"
+			gcc_32_cflags_asm="-Wa,-Av8plusa -Wa,-xarch=v8plusa"
+			gcc_64_cflags_asm="-Wa,-Av9a -Wa,-xarch=v9a";;
+      ultrasparc[34])
+			gcc_cflags_cpu="-mcpu=ultrasparc3 -mcpu=ultrasparc -mcpu=v9"
+			gcc_32_cflags_asm="-Wa,-Av8plusb -Wa,-xarch=v8plusb"
+			gcc_64_cflags_asm="-Wa,-Av9b -Wa,-xarch=v9b";;
+      ultrasparct[12])
+			gcc_cflags_cpu="-mcpu=niagara -mcpu=v9"
+			gcc_32_cflags_asm="-Wa,-Av8plusc -Wa,-xarch=v8plusc"
+			gcc_64_cflags_asm="-Wa,-Av9c -Wa,-xarch=v9c";;
+      ultrasparct3)
+			gcc_cflags_cpu="-mcpu=niagara3 -mcpu=niagara -mcpu=v9"
+			gcc_32_cflags_asm="-Wa,-Av8plusd -Wa,-xarch=v8plusd"
+			gcc_64_cflags_asm="-Wa,-Av9d -Wa,-xarch=v9d";;
+      ultrasparct[45])
+			gcc_cflags_cpu="-mcpu=niagara4 -mcpu=niagara3 -mcpu=niagara -mcpu=v9"
+			gcc_32_cflags_asm="-Wa,-Av8plusd -Wa,-xarch=v8plusd"
+			gcc_64_cflags_asm="-Wa,-Av9d -Wa,-xarch=v9d";;
+      *)
+			gcc_cflags_cpu="-mcpu=v7 -mcypress"
+			gcc_cflags_asm="";;
+    esac
+
+    # SunPRO cc and acc, and SunOS bundled cc
+    case $host in
+      *-*-solaris* | *-*-sunos*)
+	# Note no -g, it disables all optimizations.
+	cc_cflags=
+	cc_cflags_optlist="opt arch cpu"
+
+        # SunOS <= 4 cc doesn't know -xO3, fallback to -O2.
+	cc_cflags_opt="-xO3 -O2"
+
+        # SunOS cc doesn't know -xarch, apparently always generating v7
+        # code, so make this optional
+	case $host_cpu in
+	  sparcv8 | microsparc* | supersparc* | turbosparc | hypersparc*)
+			cc_cflags_arch="-xarch=v8";;
+          ultrasparct[345])
+			cc_cflags_arch="-xarch=v8plusd" ;;
+	  sparc64 | sparcv9* | ultrasparc*)
+			cc_cflags_arch="-xarch=v8plus" ;;
+	  *)
+			cc_cflags_arch="-xarch=v7" ;;
+	esac
+
+        # SunOS cc doesn't know -xchip and doesn't seem to have an equivalent.
+	# SunPRO cc 5 recognises -xchip=generic, old, super, super2, micro,
+	#   micro2, hyper, hyper2, powerup, ultra, ultra2, ultra2i.
+	# SunPRO cc 6 adds -xchip=ultra2e, ultra3cu.
+        #
+	case $host_cpu in
+	  supersparc*)  cc_cflags_cpu="-xchip=super" ;;
+	  microsparc*)  cc_cflags_cpu="-xchip=micro" ;;
+	  turbosparc)   cc_cflags_cpu="-xchip=micro2" ;;
+	  hypersparc*)  cc_cflags_cpu="-xchip=hyper" ;;
+	  ultrasparc)   cc_cflags_cpu="-xchip=ultra" ;;
+	  ultrasparc2)  cc_cflags_cpu="-xchip=ultra2 -xchip=ultra" ;;
+	  ultrasparc2i) cc_cflags_cpu="-xchip=ultra2i -xchip=ultra2 -xchip=ultra" ;;
+	  ultrasparc3)  cc_cflags_cpu="-xchip=ultra3 -xchip=ultra" ;;
+	  ultrasparc4)  cc_cflags_cpu="-xchip=ultra4 -xchip=ultra3 -xchip=ultra" ;;
+	  ultrasparct1) cc_cflags_cpu="-xchip=ultraT1" ;;
+	  ultrasparct2) cc_cflags_cpu="-xchip=ultraT2 -xchip=ultraT1" ;;
+	  ultrasparct3) cc_cflags_cpu="-xchip=ultraT3 -xchip=ultraT2" ;;
+	  ultrasparct4) cc_cflags_cpu="-xchip=T4" ;;
+	  ultrasparct5) cc_cflags_cpu="-xchip=T5 -xchip=T4" ;;
+	  *)            cc_cflags_cpu="-xchip=generic" ;;
+	esac
+    esac
+
+    case $host_cpu in
+      sparc64 | sparcv9* | ultrasparc*)
+        case $host in
+          # Solaris 6 and earlier cannot run ABI=64 since it doesn't save
+          # registers properly, so ABI=32 is left as the only choice.
+          #
+          *-*-solaris2.[0-6] | *-*-solaris2.[0-6].*) ;;
+
+          # BSD sparc64 ports are 64-bit-only systems, so ABI=64 is the only
+          # choice.  In fact they need no special compiler flags, gcc -m64
+          # is the default, but it doesn't hurt to add it.  v9 CPUs always
+          # use the sparc64 port, since the plain 32-bit sparc ports don't
+          # run on a v9.
+          #
+          *-*-*bsd*) abilist="64" ;;
+
+          # For all other systems, we try both 64 and 32.
+          #
+          # GNU/Linux sparc64 has only recently gained a 64-bit user mode.
+          # In the past sparc64 meant a v9 cpu, but there were no 64-bit
+          # operations in user mode.  We assume that if "gcc -m64" works
+          # then the system is suitable.  Hopefully even if someone attempts
+          # to put a new gcc and/or glibc on an old system it won't run.
+          #
+          *) abilist="64 32" ;;
+        esac
+
+	case $host_cpu in
+	  ultrasparc | ultrasparc2 | ultrasparc2i)
+	    path_64="sparc64/ultrasparc1234 sparc64" ;;
+	  ultrasparc[34])
+	    path_64="sparc64/ultrasparc34 sparc64/ultrasparc1234 sparc64" ;;
+	  ultrasparct[12])
+	    path_64="sparc64/ultrasparct1 sparc64" ;;
+	  ultrasparct3)
+	    path_64="sparc64/ultrasparct3 sparc64" ;;
+	  ultrasparct[45])
+	    path_64="sparc64/ultrasparct45 sparc64/ultrasparct3 sparc64" ;;
+	  *)
+	    path_64="sparc64"
+	esac
+
+        cclist_64="gcc"
+        any_64_testlist="sizeof-long-8"
+
+        # gcc -mptr64 is probably implied by -m64, but we're not sure if
+        # this was always so.  On Solaris in the past we always used both
+        # "-m64 -mptr64".
+        #
+        # gcc -Wa,-xarch=v9 is thought to be necessary in some cases on
+        # solaris, but it would seem likely that if gcc is going to generate
+        # 64-bit code it will have to add that option itself where needed.
+        # An extra copy of this option should be harmless though, but leave
+        # it until we're sure.  (Might want -xarch=v9a or -xarch=v9b for the
+        # higher cpu types instead.)
+        #
+        gcc_64_cflags="$gcc_cflags -m64 -mptr64"
+        gcc_64_ldflags="-Wc,-m64"
+        gcc_64_cflags_optlist="cpu asm"
+
+        case $host in
+          *-*-solaris*)
+            # Sun cc.
+            #
+            # We used to have -fast and some fixup options here, but it
+            # recurrently caused problems with miscompilation.  Of course,
+            # -fast is documented as miscompiling things for the sake of speed.
+            #
+            cclist_64="$cclist_64 cc"
+            cc_64_cflags_optlist="cpu"
+            case $host_cpu in
+              ultrasparct[345])
+                cc_64_cflags="$cc_64_cflags -xO3 -xarch=v9d" ;;
+              *)
+                cc_64_cflags="-xO3 -xarch=v9" ;;
+            esac
+            ;;
+        esac
+
+        # using the v9 %tick register
+        SPEED_CYCLECOUNTER_OBJ_32=sparcv9.lo
+        SPEED_CYCLECOUNTER_OBJ_64=sparcv9.lo
+        cyclecounter_size_32=2
+        cyclecounter_size_64=2
+        ;;
+    esac
+    ;;
+
+
+  # VAX
+  vax*-*-*elf*)
+    # Use elf conventions (i.e., '%' register prefix, no global prefix)
+    #
+
+echo "include_mpn(\`vax/elf.m4')" >> $gmp_tmpconfigm4i
+
+    gcc_cflags="$gcc_cflags $fomit_frame_pointer"
+    path="vax"
+    if test "$enable_assembly" = "yes" ; then
+      extra_functions="udiv_w_sdiv"
+    fi
+    ;;
+  vax*-*-*)
+    # Default to aout conventions (i.e., no register prefix, '_' global prefix)
+    #
+    gcc_cflags="$gcc_cflags $fomit_frame_pointer"
+    path="vax"
+    if test "$enable_assembly" = "yes" ; then
+      extra_functions="udiv_w_sdiv"
+    fi
+    ;;
+
+
+  # AMD and Intel x86 configurations, including AMD64
+  #
+  # Rumour has it gcc -O2 used to give worse register allocation than just
+  # -O, but lets assume that's no longer true.
+  #
+  # -m32 forces 32-bit mode on a bi-arch 32/64 amd64 build of gcc.  -m64 is
+  # the default in such a build (we think), so -m32 is essential for ABI=32.
+  # This is, of course, done for any $host_cpu, not just x86_64, so we can
+  # get such a gcc into the right mode to cross-compile to say i486-*-*.
+  #
+  # -m32 is not available in gcc 2.95 and earlier, hence cflags_maybe to use
+  # it when it works.  We check sizeof(long)==4 to ensure we get the right
+  # mode, in case -m32 has failed not because it's an old gcc, but because
+  # it's a dual 32/64-bit gcc without a 32-bit libc, or whatever.
+  #
+  i?86*-*-* | k[5-8]*-*-* | pentium*-*-* | athlon-*-* | viac3*-*-* | geode*-*-* | atom-*-* | athlon64-*-* | k8-*-* | k10-*-* | bobcat-*-* | jaguar*-*-* | bulldozer*-*-* | piledriver*-*-* | steamroller*-*-* | excavator*-*-* | zen*-*-* | pentium4-*-* | atom-*-* | silvermont-*-* | goldmont-*-* | core2-*-* | corei*-*-* | x86_64-*-* | nano-*-* | nehalem*-*-* | westmere*-*-* | sandybridge*-*-* | ivybridge*-*-* | haswell*-*-* | broadwell*-*-* | skylake*-*-* | kabylake*-*-*)
+    abilist="32"
+    cclist="gcc icc cc"
+    gcc_cflags="$gcc_cflags $fomit_frame_pointer"
+    gcc_32_cflags_maybe="-m32"
+    icc_cflags="-no-gcc"
+    icc_cflags_optlist="opt"
+    icc_cflags_opt="-O3 -O2 -O1"
+    icc_cflags_opt_maybe="-fp-model~precise"
+    any_32_testlist="sizeof-long-4"
+    gcc_cflags_optlist="cpu arch noavx"
+    CALLING_CONVENTIONS_OBJS='x86call.lo x86check$U.lo'
+
+    # Availability of rdtsc is checked at run-time.
+    SPEED_CYCLECOUNTER_OBJ=pentium.lo
+
+    # Set to "yes" below on a per-cpu basis. We do that in order to allow for
+    # a relevant warning to be output when using a CPU with mulx on a system
+    # which cannot assemble it.
+    x86_have_mulx=no
+
+    # gcc 2.7.2 only knows i386 and i486, using -m386 or -m486.  These
+    #     represent -mcpu= since -m486 doesn't generate 486 specific insns.
+    # gcc 2.95 adds k6, pentium and pentiumpro, and takes -march= and -mcpu=.
+    # gcc 3.0 adds athlon.
+    # gcc 3.1 adds k6-2, k6-3, pentium-mmx, pentium2, pentium3, pentium4,
+    #     athlon-tbird, athlon-4, athlon-xp, athlon-mp.
+    # gcc 3.2 adds winchip2.
+    # gcc 3.3 adds winchip-c6.
+    # gcc 3.3.1 from mandrake adds k8 and knows -mtune.
+    # gcc 3.4 adds c3, c3-2, k8, and deprecates -mcpu in favour of -mtune.
+    #
+    # In gcc 2.95.[0123], -march=pentiumpro provoked a stack slot bug in an
+    # old version of mpz/powm.c.  Seems to be fine with the current code, so
+    # no need for any restrictions on that option.
+    #
+    # -march=pentiumpro can fail if the assembler doesn't know "cmov"
+    # (eg. solaris 2.8 native "as"), so always have -march=pentium after
+    # that as a fallback.
+    #
+    # -march=pentium4 and -march=k8 enable SSE2 instructions, which may or
+    # may not be supported by the assembler and/or the OS, and is bad in gcc
+    # prior to 3.3.  The tests will reject these if no good, so fallbacks
+    # like "-march=pentium4 -mno-sse2" are given to try also without SSE2.
+    # Note the relevant -march types are listed in the optflags handling
+    # below, be sure to update there if adding new types emitting SSE2.
+    #
+    # -mtune is used at the start of each cpu option list to give something
+    # gcc 3.4 will use, thereby avoiding warnings from -mcpu.  -mcpu forms
+    # are retained for use by prior gcc.  For example pentium has
+    # "-mtune=pentium -mcpu=pentium ...", the -mtune is for 3.4 and the
+    # -mcpu for prior.  If there's a brand new choice in 3.4 for a chip,
+    # like k8 for x86_64, then it can be the -mtune at the start, no need to
+    # duplicate anything.
+    #
+    case $host_cpu in
+      i386*)
+	gcc_cflags_cpu="-mtune=i386 -mcpu=i386 -m386"
+	gcc_cflags_arch="-march=i386"
+	path="x86"
+	;;
+      i486*)
+	gcc_cflags_cpu="-mtune=i486 -mcpu=i486 -m486"
+	gcc_cflags_arch="-march=i486"
+	path="x86/i486 x86"
+	;;
+      i586 | pentium)
+	gcc_cflags_cpu="-mtune=pentium -mcpu=pentium -m486"
+	gcc_cflags_arch="-march=pentium"
+	path="x86/pentium x86"
+	;;
+      pentiummmx)
+	gcc_cflags_cpu="-mtune=pentium-mmx -mcpu=pentium-mmx -mcpu=pentium -m486"
+	gcc_cflags_arch="-march=pentium-mmx -march=pentium"
+	path="x86/pentium/mmx x86/pentium x86/mmx x86"
+	;;
+      i686 | pentiumpro)
+	gcc_cflags_cpu="-mtune=pentiumpro -mcpu=pentiumpro -mcpu=i486 -m486"
+	gcc_cflags_arch="-march=pentiumpro -march=pentium"
+	path="x86/p6 x86"
+	;;
+      pentium2)
+	gcc_cflags_cpu="-mtune=pentium2 -mcpu=pentium2 -mcpu=pentiumpro -mcpu=i486 -m486"
+	gcc_cflags_arch="-march=pentium2 -march=pentiumpro -march=pentium"
+	path="x86/p6/mmx x86/p6 x86/mmx x86"
+	;;
+      pentium3)
+	gcc_cflags_cpu="-mtune=pentium3 -mcpu=pentium3 -mcpu=pentiumpro -mcpu=i486 -m486"
+	gcc_cflags_arch="-march=pentium3 -march=pentiumpro -march=pentium"
+	path="x86/p6/p3mmx x86/p6/mmx x86/p6 x86/mmx x86"
+	;;
+      pentiumm)
+	gcc_cflags_cpu="-mtune=pentium3 -mcpu=pentium3 -mcpu=pentiumpro -mcpu=i486 -m486"
+	gcc_cflags_arch="-march=pentium3 -march=pentiumpro -march=pentium"
+	path="x86/p6/sse2 x86/p6/p3mmx x86/p6/mmx x86/p6 x86/mmx x86"
+	;;
+      k6)
+	gcc_cflags_cpu="-mtune=k6 -mcpu=k6 -mcpu=i486 -m486"
+	gcc_cflags_arch="-march=k6"
+	path="x86/k6/mmx x86/k6 x86/mmx x86"
+	;;
+      k62)
+	gcc_cflags_cpu="-mtune=k6-2 -mcpu=k6-2 -mcpu=k6 -mcpu=i486 -m486"
+	gcc_cflags_arch="-march=k6-2 -march=k6"
+	path="x86/k6/k62mmx x86/k6/mmx x86/k6 x86/mmx x86"
+	;;
+      k63)
+	gcc_cflags_cpu="-mtune=k6-3 -mcpu=k6-3 -mcpu=k6 -mcpu=i486 -m486"
+	gcc_cflags_arch="-march=k6-3 -march=k6"
+	path="x86/k6/k62mmx x86/k6/mmx x86/k6 x86/mmx x86"
+	;;
+      geode)
+	gcc_cflags_cpu="-mtune=k6-3 -mcpu=k6-3 -mcpu=k6 -mcpu=i486 -m486"
+	gcc_cflags_arch="-march=k6-3 -march=k6"
+	path="x86/geode x86/k6/k62mmx x86/k6/mmx x86/k6 x86/mmx x86"
+	;;
+      athlon)
+	# Athlon instruction costs are close to P6 (3 cycle load latency,
+	# 4-6 cycle mul, 40 cycle div, pairable adc, etc) so if gcc doesn't
+	# know athlon (eg. 2.95.2 doesn't) then fall back on pentiumpro.
+	gcc_cflags_cpu="-mtune=athlon -mcpu=athlon -mcpu=pentiumpro -mcpu=i486 -m486"
+	gcc_cflags_arch="-march=athlon -march=pentiumpro -march=pentium"
+	path="x86/k7/mmx x86/k7 x86/mmx x86"
+	;;
+      i786 | pentium4)
+	# pentiumpro is the primary fallback when gcc doesn't know pentium4.
+	# This gets us cmov to eliminate branches.  Maybe "athlon" would be
+	# a possibility on gcc 3.0.
+	#
+	gcc_cflags_cpu="-mtune=pentium4 -mcpu=pentium4 -mcpu=pentiumpro -mcpu=i486 -m486"
+	gcc_cflags_arch="-march=pentium4 -march=pentium4~-mno-sse2 -march=pentiumpro -march=pentium"
+	gcc_64_cflags_cpu="-mtune=nocona"
+	path="x86/pentium4/sse2 x86/pentium4/mmx x86/pentium4 x86/mmx x86"
+	path_64="x86_64/pentium4 x86_64"
+	;;
+      viac32)
+	# Not sure of the best fallbacks here for -mcpu.
+	# c3-2 has sse and mmx, so pentium3 is good for -march.
+	gcc_cflags_cpu="-mtune=c3-2 -mcpu=c3-2 -mcpu=i486 -m486"
+	gcc_cflags_arch="-march=c3-2 -march=pentium3 -march=pentiumpro -march=pentium"
+	path="x86/p6/p3mmx x86/p6/mmx x86/p6 x86/mmx x86"
+	;;
+      viac3*)
+	# Not sure of the best fallbacks here.
+	gcc_cflags_cpu="-mtune=c3 -mcpu=c3 -mcpu=i486 -m486"
+	gcc_cflags_arch="-march=c3 -march=pentium-mmx -march=pentium"
+	path="x86/pentium/mmx x86/pentium x86/mmx x86"
+	;;
+      athlon64 | k8 | x86_64)
+	gcc_cflags_cpu="-mtune=k8 -mcpu=athlon -mcpu=pentiumpro -mcpu=i486 -m486"
+	gcc_cflags_arch="-march=k8 -march=k8~-mno-sse2 -march=athlon -march=pentiumpro -march=pentium"
+	path="x86/k8 x86/k7/mmx x86/k7 x86/mmx x86"
+	path_64="x86_64/k8 x86_64"
+	;;
+      k10)
+	gcc_cflags_cpu="-mtune=amdfam10 -mtune=k8"
+	gcc_cflags_arch="-march=amdfam10 -march=k8 -march=k8~-mno-sse2"
+	path="x86/k10 x86/k8 x86/k7/mmx x86/k7 x86/mmx x86"
+	path_64="x86_64/k10 x86_64/k8 x86_64"
+	;;
+      bobcat)
+	gcc_cflags_cpu="-mtune=btver1 -mtune=amdfam10 -mtune=k8"
+	gcc_cflags_arch="-march=btver1 -march=amdfam10 -march=k8 -march=k8~-mno-sse2"
+	path="x86/bt1 x86/k7/mmx x86/k7 x86/mmx x86"
+	path_64="x86_64/bt1 x86_64/k10 x86_64/k8 x86_64"
+	;;
+      jaguar | jaguarnoavx)
+	gcc_cflags_cpu="-mtune=btver2 -mtune=btver1 -mtune=amdfam10 -mtune=k8"
+	gcc_cflags_arch="-march=btver2 -march=btver1 -march=amdfam10 -march=k8 -march=k8~-mno-sse2"
+	path="x86/bt2 x86/bt1 x86/k7/mmx x86/k7 x86/mmx x86"
+	path_64="x86_64/bt2 x86_64/bt1 x86_64/k10 x86_64/k8 x86_64"
+	;;
+      bulldozer | bd1 | bulldozernoavx | bd1noavx)
+	gcc_cflags_cpu="-mtune=bdver1 -mtune=amdfam10 -mtune=k8"
+	gcc_cflags_arch="-march=bdver1 -march=amdfam10 -march=k8 -march=k8~-mno-sse2"
+	path="x86/bd1 x86/k7/mmx x86/k7 x86/mmx x86"
+	path_64="x86_64/bd1 x86_64/k10 x86_64/k8 x86_64"
+	;;
+      piledriver | bd2 | piledrivernoavx | bd2noavx)
+	gcc_cflags_cpu="-mtune=bdver2 -mtune=bdver1 -mtune=amdfam10 -mtune=k8"
+	gcc_cflags_arch="-march=bdver2 -march=bdver1 -march=amdfam10 -march=k8 -march=k8~-mno-sse2"
+	path="x86/bd2 x86/bd1 x86/k7/mmx x86/k7 x86/mmx x86"
+	path_64="x86_64/bd2 x86_64/bd1 x86_64/k10 x86_64/k8 x86_64"
+	;;
+      steamroller | bd3 | steamrollernoavx | bd3noavx)
+	gcc_cflags_cpu="-mtune=bdver3 -mtune=bdver2 -mtune=bdver1 -mtune=amdfam10 -mtune=k8"
+	gcc_cflags_arch="-march=bdver3 -march=bdver2 -march=bdver1 -march=amdfam10 -march=k8 -march=k8~-mno-sse2"
+	path="x86/bd3 x86/bd2 x86/bd1 x86/k7/mmx x86/k7 x86/mmx x86"
+	path_64="x86_64/bd3 x86_64/bd2 x86_64/bd1 x86_64/k10 x86_64/k8 x86_64"
+	;;
+      excavator | bd4 | excavatornoavx | bd4noavx)
+	gcc_cflags_cpu="-mtune=bdver4 -mtune=bdver3 -mtune=bdver2 -mtune=bdver1 -mtune=amdfam10 -mtune=k8"
+	gcc_cflags_arch="-march=bdver4 -march=bdver3 -march=bdver2 -march=bdver1 -march=amdfam10 -march=k8 -march=k8~-mno-sse2"
+	path="x86/bd4 x86/bd3 x86/bd2 x86/bd1 x86/k7/mmx x86/k7 x86/mmx x86"
+	path_64="x86_64/bd4 x86_64/bd3 x86_64/bd2 x86_64/bd1 x86_64/k10 x86_64/k8 x86_64"
+	x86_have_mulx=yes
+	;;
+      zen | zennoavx)
+	gcc_cflags_cpu="-mtune=znver1 -mtune=amdfam10 -mtune=k8"
+	gcc_cflags_arch="-march=znver1 -march=amdfam10 -march=k8"
+	path="x86/k7/mmx x86/k7 x86/mmx x86"
+	x86_have_mulx=yes
+	path_64="x86_64/zen x86_64"
+	;;
+      zen2 | zen2noavx)
+	gcc_cflags_cpu="-mtune=znver2 -mtune=znver1 -mtune=amdfam10 -mtune=k8"
+	gcc_cflags_arch="-march=znver2 -march=znver1 -march=amdfam10 -march=k8"
+	path="x86/k7/mmx x86/k7 x86/mmx x86"
+	x86_have_mulx=yes
+	path_64="x86_64/zen2 x86_64/zen x86_64"
+	;;
+      core2)
+	gcc_cflags_cpu="-mtune=core2 -mtune=k8"
+	gcc_cflags_arch="-march=core2 -march=core2~-mno-sse2 -march=k8 -march=k8~-mno-sse2"
+	path="x86/core2 x86/p6/sse2 x86/p6/p3mmx x86/p6/mmx x86/p6 x86/mmx x86"
+	path_64="x86_64/core2 x86_64"
+	;;
+      corei | coreinhm | coreiwsm | nehalem | westmere)
+	gcc_cflags_cpu="-mtune=nehalem -mtune=corei7 -mtune=core2 -mtune=k8"
+	gcc_cflags_arch="-march=nehalem -march=corei7 -march=core2 -march=core2~-mno-sse2 -march=k8 -march=k8~-mno-sse2"
+	path="x86/coreinhm x86/p6/sse2 x86/p6/p3mmx x86/p6/mmx x86/p6 x86/mmx x86"
+	path_64="x86_64/coreinhm x86_64/core2 x86_64"
+	;;
+      coreisbr | coreisbrnoavx | coreiibr | coreiibrnoavx | \
+      sandybridge | sandybridgenoavx | ivybridge | ivybridgenoavx)
+	gcc_cflags_cpu="-mtune=sandybridge -mtune=corei7 -mtune=core2 -mtune=k8"
+	gcc_cflags_arch="-march=sandybridge -march=corei7 -march=core2 -march=core2~-mno-sse2 -march=k8 -march=k8~-mno-sse2"
+	path="x86/coreisbr x86/p6/sse2 x86/p6/p3mmx x86/p6/mmx x86/p6 x86/mmx x86"
+	path_64="x86_64/coreisbr x86_64/coreinhm x86_64/core2 x86_64"
+	;;
+      coreihwl | coreihwlnoavx | haswell | haswellnoavx)
+	gcc_cflags_cpu="-mtune=haswell -mtune=corei7 -mtune=core2 -mtune=k8"
+	gcc_cflags_arch="-march=haswell -march=corei7 -march=core2 -march=core2~-mno-sse2 -march=k8 -march=k8~-mno-sse2"
+	path="x86/coreihwl x86/coreisbr x86/p6/sse2 x86/p6/p3mmx x86/p6/mmx x86/p6 x86/mmx x86"
+	path_64="x86_64/coreihwl x86_64/coreisbr x86_64/coreinhm x86_64/core2 x86_64"
+	x86_have_mulx=yes
+	;;
+      coreibwl | coreibwlnoavx | broadwell | broadwellnoavx)
+	gcc_cflags_cpu="-mtune=broadwell -mtune=corei7 -mtune=core2 -mtune=k8"
+	gcc_cflags_arch="-march=broadwell -march=corei7 -march=core2 -march=core2~-mno-sse2 -march=k8 -march=k8~-mno-sse2"
+	path="x86/coreihwl x86/coreisbr x86/p6/sse2 x86/p6/p3mmx x86/p6/mmx x86/p6 x86/mmx x86"
+	path_64="x86_64/coreibwl x86_64/coreihwl x86_64/coreisbr x86_64/coreinhm x86_64/core2 x86_64"
+	# extra_functions_64="missing"	 # enable for bmi2/adx simulation
+	x86_have_mulx=yes
+	;;
+      skylake | skylakenoavx | kabylake | kabylakenoavx)
+	gcc_cflags_cpu="-mtune=skylake -mtune=broadwell -mtune=corei7 -mtune=core2 -mtune=k8"
+	# Don't pass -march=skylake for now as then some compilers emit AVX512.
+	gcc_cflags_arch="-march=broadwell -march=corei7 -march=core2 -march=core2~-mno-sse2 -march=k8 -march=k8~-mno-sse2"
+	path="x86/coreihwl x86/coreisbr x86/p6/sse2 x86/p6/p3mmx x86/p6/mmx x86/p6 x86/mmx x86"
+	path_64="x86_64/skylake x86_64/coreibwl x86_64/coreihwl x86_64/coreisbr x86_64/coreinhm x86_64/core2 x86_64"
+	# extra_functions_64="missing"	 # enable for bmi2/adx simulation
+	x86_have_mulx=yes
+	;;
+      atom)			# in-order pipeline atom
+	gcc_cflags_cpu="-mtune=atom -mtune=pentium3"
+	gcc_cflags_arch="-march=atom -march=pentium3"
+	path="x86/atom/sse2 x86/atom/mmx x86/atom x86/mmx x86"
+	path_64="x86_64/atom x86_64"
+	;;
+      silvermont)		# out-of-order pipeline atom
+	gcc_cflags_cpu="-mtune=slm -mtune=atom -mtune=pentium3"
+	gcc_cflags_arch="-march=slm -march=atom -march=pentium3"
+	path="x86/silvermont x86/atom/sse2 x86/atom/mmx x86/atom x86/mmx x86"
+	path_64="x86_64/silvermont x86_64/atom x86_64"
+	;;
+      goldmont)			# out-of-order pipeline atom
+	gcc_cflags_cpu="-mtune=slm -mtune=atom -mtune=pentium3"
+	gcc_cflags_arch="-march=slm -march=atom -march=pentium3"
+	path="x86/goldmont x86/atom/sse2 x86/atom/mmx x86/atom x86/mmx x86"
+	path_64="x86_64/goldmont x86_64/silvermont x86_64/atom x86_64"
+	;;
+      nano)
+	gcc_cflags_cpu="-mtune=nano"
+	gcc_cflags_arch="-march=nano"
+	path="x86/nano x86/mmx x86"
+	path_64="x86_64/nano x86_64"
+	;;
+      *)
+	gcc_cflags_cpu="-mtune=i486 -mcpu=i486 -m486"
+	gcc_cflags_arch="-march=i486"
+	path="x86"
+	path_64="x86_64"
+	;;
+    esac
+
+    case $host in
+      # Disable AVX if the CPU part tells us AVX is unavailable, but also
+      # unconditionally for NetBSD where they don't work but OSXSAVE is set
+      # to claim the contrary.
+      *noavx-*-* | *-*-netbsd*)
+	gcc_cflags_noavx="-mno-avx"
+
+echo "define(<GMP_AVX_NOT_REALLY_AVAILABLE>,1)" >> $gmp_tmpconfigm4
+
+	;;
+    esac
+
+    case $host in
+      athlon64-*-* | k8-*-* | k10-*-* | bobcat-*-* | jaguar*-*-* | bulldozer*-*-* | piledriver*-*-* | steamroller*-*-* | excavator*-*-* | zen*-*-* | pentium4-*-* | atom-*-* | silvermont-*-* | goldmont-*-* | core2-*-* | corei*-*-* | x86_64-*-* | nano-*-* | nehalem*-*-* | westmere*-*-* | sandybridge*-*-* | ivybridge*-*-* | haswell*-*-* | broadwell*-*-* | skylake*-*-* | kabylake*-*-*)
+	cclist_64="gcc cc"
+	gcc_64_cflags="$gcc_cflags -m64"
+	gcc_64_cflags_optlist="cpu arch noavx"
+	CALLING_CONVENTIONS_OBJS_64='amd64call.lo amd64check$U.lo'
+	SPEED_CYCLECOUNTER_OBJ_64=x86_64.lo
+	cyclecounter_size_64=2
+
+	cclist_x32="gcc cc"
+	gcc_x32_cflags="$gcc_cflags -mx32"
+	gcc_x32_cflags_optlist="$gcc_64_cflags_optlist"
+	CALLING_CONVENTIONS_OBJS_x32="$CALLING_CONVENTIONS_OBJS_64"
+	SPEED_CYCLECOUNTER_OBJ_x32="$SPEED_CYCLECOUNTER_OBJ_64"
+	cyclecounter_size_x32="$cyclecounter_size_64"
+	path_x32="$path_64"
+	limb_x32=longlong
+	any_x32_testlist="sizeof-long-4"
+
+	abilist="64 x32 32"
+	if test "$enable_assembly" = "yes" ; then
+	    extra_functions_64="$extra_functions_64 invert_limb_table"
+	    extra_functions_x32=$extra_functions_64
+	fi
+
+	case $host in
+	  *-*-solaris*)
+	    # Sun cc.
+	    cc_64_cflags="-xO3 -m64"
+	    ;;
+	  *-*-mingw* | *-*-cygwin)
+	    limb_64=longlong
+	    CALLING_CONVENTIONS_OBJS_64=""
+
+$as_echo "#define HOST_DOS64 1" >>confdefs.h
+
+	    GMP_NONSTD_ABI_64=DOS64
+	    ;;
+	esac
+	;;
+    esac
+    ;;
+
+
+  # Special CPU "none" used to select generic C, now this is obsolete.
+  none-*-*)
+    enable_assembly=no
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: the \"none\" host is obsolete, use --disable-assembly" >&5
+$as_echo "$as_me: WARNING: the \"none\" host is obsolete, use --disable-assembly" >&2;}
+    ;;
+
+esac
+
+# mingw can be built by the cygwin gcc if -mno-cygwin is added.  For
+# convenience add this automatically if it works.  Actual mingw gcc accepts
+# -mno-cygwin too, but of course is the default.  mingw only runs on the
+# x86s, but allow any CPU here so as to catch "none" too.
+#
+case $host in
+  *-*-mingw*)
+    gcc_cflags_optlist="$gcc_cflags_optlist nocygwin"
+    gcc_cflags_nocygwin="-mno-cygwin"
+    ;;
+esac
+
+
+CFLAGS_or_unset=${CFLAGS-'(unset)'}
+CPPFLAGS_or_unset=${CPPFLAGS-'(unset)'}
+
+cat >&5 <<EOF
+User:
+ABI=$ABI
+CC=$CC
+CFLAGS=$CFLAGS_or_unset
+CPPFLAGS=$CPPFLAGS_or_unset
+MPN_PATH=$MPN_PATH
+GMP:
+abilist=$abilist
+cclist=$cclist
+EOF
+
+
+test_CFLAGS=${CFLAGS+set}
+test_CPPFLAGS=${CPPFLAGS+set}
+
+for abi in $abilist; do
+  abi_last="$abi"
+done
+
+# If the user specifies an ABI then it must be in $abilist, after that
+# $abilist is restricted to just that choice.
+#
+if test -n "$ABI"; then
+  found=no
+  for abi in $abilist; do
+    if test $abi = "$ABI"; then found=yes; break; fi
+  done
+  if test $found = no; then
+    as_fn_error $? "ABI=$ABI is not among the following valid choices: $abilist" "$LINENO" 5
+  fi
+  abilist="$ABI"
+fi
+
+found_compiler=no
+
+for abi in $abilist; do
+
+  echo "checking ABI=$abi"
+
+  # Suppose abilist="64 32", then for abi=64, will have abi1="_64" and
+  # abi2="_64".  For abi=32, will have abi1="_32" and abi2="".  This is how
+  # $gcc_cflags becomes a fallback for $gcc_32_cflags (the last in the
+  # abilist), but there's no fallback for $gcc_64_cflags.
+  #
+  abi1=`echo _$abi | sed 's/[.]//g'`
+  if test $abi = $abi_last; then abi2=; else abi2="$abi1"; fi
+
+  # Compiler choices under this ABI
+                              eval cclist_chosen=\"\$cclist$abi1\"
+  test -n "$cclist_chosen" || eval cclist_chosen=\"\$cclist$abi2\"
+
+  # If there's a user specified $CC then don't use a list for
+  # $cclist_chosen, just a single value for $ccbase.
+  #
+  if test -n "$CC"; then
+
+    # The first word of $CC, stripped of any directory.  For instance
+    # CC="/usr/local/bin/gcc -pipe" will give "gcc".
+    #
+    for ccbase in $CC; do break; done
+    ccbase=`echo $ccbase | sed 's:.*/::'`
+
+    # If this $ccbase is in $cclist_chosen then it's a compiler we know and
+    # we can do flags defaulting with it.  If not, then $cclist_chosen is
+    # set to "unrecognised" so no default flags are used.
+    #
+    # "unrecognised" is used to avoid bad effects with eval if $ccbase has
+    # non-symbol characters.  For instance ccbase=my+cc would end up with
+    # something like cflags="$my+cc_cflags" which would give
+    # cflags="+cc_cflags" rather than the intended empty string for an
+    # unknown compiler.
+    #
+    found=unrecognised
+    for i in $cclist_chosen; do
+      if test "$ccbase" = $i; then
+        found=$ccbase
+        break
+      fi
+    done
+    cclist_chosen=$found
+  fi
+
+  for ccbase in $cclist_chosen; do
+
+    # When cross compiling, look for a compiler with the $host_alias as a
+    # prefix, the same way that AC_CHECK_TOOL does.  But don't do this to a
+    # user-selected $CC.
+    #
+    # $cross_compiling will be yes/no/maybe at this point.  Do the host
+    # prefixing for "maybe" as well as "yes".
+    #
+    if test "$cross_compiling" != no && test -z "$CC"; then
+      cross_compiling_prefix="${host_alias}-"
+    fi
+
+    for ccprefix in $cross_compiling_prefix ""; do
+
+      cc="$CC"
+      test -n "$cc" || cc="$ccprefix$ccbase"
+
+      # If the compiler is gcc but installed under another name, then change
+      # $ccbase so as to use the flags we know for gcc.  This helps for
+      # instance when specifying CC=gcc272 on Debian GNU/Linux, or the
+      # native cc which is really gcc on NeXT or MacOS-X.
+      #
+      # FIXME: There's a slight misfeature here.  If cc is actually gcc but
+      # gcc is not a known compiler under this $abi then we'll end up
+      # testing it with no flags and it'll work, but chances are it won't be
+      # in the right mode for the ABI we desire.  Let's quietly hope this
+      # doesn't happen.
+      #
+      if test $ccbase != gcc; then
+        cat >conftest.c <<EOF
+#if ! defined (__GNUC__) || defined (__INTEL_COMPILER)
+  choke me
+#endif
+EOF
+gmp_compile="$cc -c conftest.c >&5"
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  rm -f conftest*
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $cc is gcc" >&5
+$as_echo_n "checking whether $cc is gcc... " >&6; }
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+  ccbase=gcc
+else
+  rm -f conftest*
+  :
+fi
+
+      fi
+
+      # Similarly if the compiler is IBM xlc but invoked as cc or whatever
+      # then change $ccbase and make the default xlc flags available.
+      if test $ccbase != xlc; then
+        gmp_command="$cc 2>&1 | grep xlc >/dev/null"
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_command\""; } >&5
+  (eval $gmp_command) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $cc is xlc" >&5
+$as_echo_n "checking whether $cc is xlc... " >&6; }
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+  ccbase=xlc
+else
+  :
+fi
+
+      fi
+
+      # acc was Sun's first unbundled compiler back in the SunOS days, or
+      # something like that, but today its man page says it's not meant to
+      # be used directly (instead via /usr/ucb/cc).  The options are pretty
+      # much the same as the main SunPRO cc, so share those configs.
+      #
+      case $host in
+        *sparc*-*-solaris* | *sparc*-*-sunos*)
+          if test "$ccbase" = acc; then ccbase=cc; fi ;;
+      esac
+
+      for tmp_cflags_maybe in yes no; do
+                             eval cflags=\"\$${ccbase}${abi1}_cflags\"
+        test -n "$cflags" || eval cflags=\"\$${ccbase}${abi2}_cflags\"
+
+	if test "$tmp_cflags_maybe" = yes; then
+          # don't try cflags_maybe when the user set CFLAGS
+          if test "$test_CFLAGS" = set; then continue; fi
+                                     eval cflags_maybe=\"\$${ccbase}${abi1}_cflags_maybe\"
+          test -n "$cflags_maybe" || eval cflags_maybe=\"\$${ccbase}${abi2}_cflags_maybe\"
+          # don't try cflags_maybe if there's nothing set
+          if test -z "$cflags_maybe"; then continue; fi
+          cflags="$cflags_maybe $cflags"
+        fi
+
+        # Any user CFLAGS, even an empty string, takes precedence
+        if test "$test_CFLAGS" = set; then cflags=$CFLAGS; fi
+
+        # Any user CPPFLAGS, even an empty string, takes precedence
+                               eval cppflags=\"\$${ccbase}${abi1}_cppflags\"
+        test -n "$cppflags" || eval cppflags=\"\$${ccbase}${abi2}_cppflags\"
+        if test "$test_CPPFLAGS" = set; then cppflags=$CPPFLAGS; fi
+
+        # --enable-profiling adds -p/-pg even to user-specified CFLAGS.
+        # This is convenient, but it's perhaps a bit naughty to modify user
+        # CFLAGS.
+        case "$enable_profiling" in
+          prof)       cflags="$cflags -p" ;;
+          gprof)      cflags="$cflags -pg" ;;
+          instrument) cflags="$cflags -finstrument-functions" ;;
+        esac
+
+        { $as_echo "$as_me:${as_lineno-$LINENO}: checking compiler $cc $cflags $cppflags" >&5
+$as_echo_n "checking compiler $cc $cflags $cppflags... " >&6; }
+gmp_prog_cc_works=yes
+
+# first see a simple "main()" works, then go on to other checks
+if test "$gmp_prog_cc_works" = yes; then
+  # remove anything that might look like compiler output to our "||" expression
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  cat >conftest.c <<EOF
+
+int main () { return 0; }
+EOF
+  echo "Test compile: " >&5
+  gmp_compile="$cc $cflags $cppflags conftest.c >&5"
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    cc_works_part=yes
+    if test "$cross_compiling" = no; then
+      if { ac_try='./a.out || ./b.out || ./a.exe || ./a_out.exe || ./conftest'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :;
+      else
+        cc_works_part=norun
+      fi
+    fi
+  else
+    cc_works_part=no
+  fi
+  if test "$cc_works_part" != yes; then
+    echo "failed program was:" >&5
+    cat conftest.c >&5
+  fi
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  case $cc_works_part in
+    yes)
+
+      ;;
+    no)
+      gmp_prog_cc_works="no"
+      ;;
+    norun)
+      gmp_prog_cc_works="no, program does not run"
+      ;;
+  esac
+fi
+
+
+
+
+if test "$gmp_prog_cc_works" = yes; then
+  # remove anything that might look like compiler output to our "||" expression
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  cat >conftest.c <<EOF
+/* The following provokes an internal error from gcc 2.95.2 -mpowerpc64
+   (without -maix64), hence detecting an unusable compiler */
+void *g() { return (void *) 0; }
+void *f() { return g(); }
+
+int main () { return 0; }
+EOF
+  echo "Test compile: function pointer return" >&5
+  gmp_compile="$cc $cflags $cppflags conftest.c >&5"
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    cc_works_part=yes
+    if test "$cross_compiling" = no; then
+      if { ac_try='./a.out || ./b.out || ./a.exe || ./a_out.exe || ./conftest'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :;
+      else
+        cc_works_part=norun
+      fi
+    fi
+  else
+    cc_works_part=no
+  fi
+  if test "$cc_works_part" != yes; then
+    echo "failed program was:" >&5
+    cat conftest.c >&5
+  fi
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  case $cc_works_part in
+    yes)
+
+      ;;
+    no)
+      gmp_prog_cc_works="no, function pointer return"
+      ;;
+    norun)
+      gmp_prog_cc_works="no, function pointer return, program does not run"
+      ;;
+  esac
+fi
+
+
+
+
+if test "$gmp_prog_cc_works" = yes; then
+  # remove anything that might look like compiler output to our "||" expression
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  cat >conftest.c <<EOF
+/* The following provokes an invalid instruction syntax from i386 gcc
+   -march=pentiumpro on Solaris 2.8.  The native sun assembler
+   requires a non-standard syntax for cmov which gcc (as of 2.95.2 at
+   least) doesn't know.  */
+int n;
+int cmov () { return (n >= 0 ? n : 0); }
+
+int main () { return 0; }
+EOF
+  echo "Test compile: cmov instruction" >&5
+  gmp_compile="$cc $cflags $cppflags conftest.c >&5"
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    cc_works_part=yes
+    if test "$cross_compiling" = no; then
+      if { ac_try='./a.out || ./b.out || ./a.exe || ./a_out.exe || ./conftest'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :;
+      else
+        cc_works_part=norun
+      fi
+    fi
+  else
+    cc_works_part=no
+  fi
+  if test "$cc_works_part" != yes; then
+    echo "failed program was:" >&5
+    cat conftest.c >&5
+  fi
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  case $cc_works_part in
+    yes)
+
+      ;;
+    no)
+      gmp_prog_cc_works="no, cmov instruction"
+      ;;
+    norun)
+      gmp_prog_cc_works="no, cmov instruction, program does not run"
+      ;;
+  esac
+fi
+
+
+
+
+if test "$gmp_prog_cc_works" = yes; then
+  # remove anything that might look like compiler output to our "||" expression
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  cat >conftest.c <<EOF
+/* The following provokes a linker invocation problem with gcc 3.0.3
+   on AIX 4.3 under "-maix64 -mpowerpc64 -mcpu=630".  The -mcpu=630
+   option causes gcc to incorrectly select the 32-bit libgcc.a, not
+   the 64-bit one, and consequently it misses out on the __fixunsdfdi
+   helper (double -> uint64 conversion).  */
+double d;
+unsigned long gcc303 () { return (unsigned long) d; }
+
+int main () { return 0; }
+EOF
+  echo "Test compile: double -> ulong conversion" >&5
+  gmp_compile="$cc $cflags $cppflags conftest.c >&5"
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    cc_works_part=yes
+    if test "$cross_compiling" = no; then
+      if { ac_try='./a.out || ./b.out || ./a.exe || ./a_out.exe || ./conftest'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :;
+      else
+        cc_works_part=norun
+      fi
+    fi
+  else
+    cc_works_part=no
+  fi
+  if test "$cc_works_part" != yes; then
+    echo "failed program was:" >&5
+    cat conftest.c >&5
+  fi
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  case $cc_works_part in
+    yes)
+
+      ;;
+    no)
+      gmp_prog_cc_works="no, double -> ulong conversion"
+      ;;
+    norun)
+      gmp_prog_cc_works="no, double -> ulong conversion, program does not run"
+      ;;
+  esac
+fi
+
+
+
+
+if test "$gmp_prog_cc_works" = yes; then
+  # remove anything that might look like compiler output to our "||" expression
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  cat >conftest.c <<EOF
+/* The following provokes an error from hppa gcc 2.95 under -mpa-risc-2-0 if
+   the assembler doesn't know hppa 2.0 instructions.  fneg is a 2.0
+   instruction, and a negation like this comes out using it.  */
+double fneg_data;
+unsigned long fneg () { return -fneg_data; }
+
+int main () { return 0; }
+EOF
+  echo "Test compile: double negation" >&5
+  gmp_compile="$cc $cflags $cppflags conftest.c >&5"
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    cc_works_part=yes
+    if test "$cross_compiling" = no; then
+      if { ac_try='./a.out || ./b.out || ./a.exe || ./a_out.exe || ./conftest'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :;
+      else
+        cc_works_part=norun
+      fi
+    fi
+  else
+    cc_works_part=no
+  fi
+  if test "$cc_works_part" != yes; then
+    echo "failed program was:" >&5
+    cat conftest.c >&5
+  fi
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  case $cc_works_part in
+    yes)
+
+      ;;
+    no)
+      gmp_prog_cc_works="no, double negation"
+      ;;
+    norun)
+      gmp_prog_cc_works="no, double negation, program does not run"
+      ;;
+  esac
+fi
+
+
+
+
+if test "$gmp_prog_cc_works" = yes; then
+  # remove anything that might look like compiler output to our "||" expression
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  cat >conftest.c <<EOF
+/* The following makes gcc 3.3 -march=pentium4 generate an SSE2 xmm insn
+   (cvtsd2ss) which will provoke an error if the assembler doesn't recognise
+   those instructions.  Not sure how much of the gmp code will come out
+   wanting sse2, but it's easiest to reject an option we know is bad.  */
+double ftod_data;
+float ftod () { return (float) ftod_data; }
+
+int main () { return 0; }
+EOF
+  echo "Test compile: double -> float conversion" >&5
+  gmp_compile="$cc $cflags $cppflags conftest.c >&5"
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    cc_works_part=yes
+    if test "$cross_compiling" = no; then
+      if { ac_try='./a.out || ./b.out || ./a.exe || ./a_out.exe || ./conftest'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :;
+      else
+        cc_works_part=norun
+      fi
+    fi
+  else
+    cc_works_part=no
+  fi
+  if test "$cc_works_part" != yes; then
+    echo "failed program was:" >&5
+    cat conftest.c >&5
+  fi
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  case $cc_works_part in
+    yes)
+
+      ;;
+    no)
+      gmp_prog_cc_works="no, double -> float conversion"
+      ;;
+    norun)
+      gmp_prog_cc_works="no, double -> float conversion, program does not run"
+      ;;
+  esac
+fi
+
+
+
+
+if test "$gmp_prog_cc_works" = yes; then
+  # remove anything that might look like compiler output to our "||" expression
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  cat >conftest.c <<EOF
+/* The following provokes an internal compiler error from gcc version
+   "2.9-gnupro-99r1" under "-O2 -mcpu=ev6", apparently relating to char
+   values being spilled into floating point registers.  The problem doesn't
+   show up all the time, but has occurred enough in GMP for us to reject
+   this compiler+flags.  */
+#include <string.h>  /* for memcpy */
+struct try_t
+{
+ char dst[2];
+ char size;
+ long d0, d1, d2, d3, d4, d5, d6;
+ char overlap;
+};
+struct try_t param[6];
+int
+param_init ()
+{
+ struct try_t *p;
+ memcpy (p, &param[ 2 ], sizeof (*p));
+ memcpy (p, &param[ 2 ], sizeof (*p));
+ p->size = 2;
+ memcpy (p, &param[ 1 ], sizeof (*p));
+ p->dst[0] = 1;
+ p->overlap = 2;
+ memcpy (p, &param[ 3 ], sizeof (*p));
+ p->dst[0] = 1;
+ p->overlap = 8;
+ memcpy (p, &param[ 4 ], sizeof (*p));
+ memcpy (p, &param[ 4 ], sizeof (*p));
+ p->overlap = 8;
+ memcpy (p, &param[ 5 ], sizeof (*p));
+ memcpy (p, &param[ 5 ], sizeof (*p));
+ memcpy (p, &param[ 5 ], sizeof (*p));
+ return 0;
+}
+
+int main () { return 0; }
+EOF
+  echo "Test compile: gnupro alpha ev6 char spilling" >&5
+  gmp_compile="$cc $cflags $cppflags conftest.c >&5"
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    cc_works_part=yes
+    if test "$cross_compiling" = no; then
+      if { ac_try='./a.out || ./b.out || ./a.exe || ./a_out.exe || ./conftest'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :;
+      else
+        cc_works_part=norun
+      fi
+    fi
+  else
+    cc_works_part=no
+  fi
+  if test "$cc_works_part" != yes; then
+    echo "failed program was:" >&5
+    cat conftest.c >&5
+  fi
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  case $cc_works_part in
+    yes)
+
+      ;;
+    no)
+      gmp_prog_cc_works="no, gnupro alpha ev6 char spilling"
+      ;;
+    norun)
+      gmp_prog_cc_works="no, gnupro alpha ev6 char spilling, program does not run"
+      ;;
+  esac
+fi
+
+
+
+
+# __builtin_alloca is not available everywhere, check it exists before
+# seeing that it works
+if test "$gmp_prog_cc_works" = yes; then
+  # remove anything that might look like compiler output to our "||" expression
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  cat >conftest.c <<EOF
+int k; int foo () { __builtin_alloca (k); }
+EOF
+  echo "Test compile: __builtin_alloca availability" >&5
+  gmp_compile="$cc $cflags $cppflags conftest.c >&5"
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    cc_works_part=yes
+    if test "$cross_compiling" = no; then
+      if { ac_try='./a.out || ./b.out || ./a.exe || ./a_out.exe || ./conftest'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :;
+      else
+        cc_works_part=norun
+      fi
+    fi
+  else
+    cc_works_part=no
+  fi
+  if test "$cc_works_part" != yes; then
+    echo "failed program was:" >&5
+    cat conftest.c >&5
+  fi
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  case $cc_works_part in
+    yes)
+      if test "$gmp_prog_cc_works" = yes; then
+  # remove anything that might look like compiler output to our "||" expression
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  cat >conftest.c <<EOF
+/* The following provokes an internal compiler error from Itanium HP-UX cc
+    under +O2 or higher.  We use this sort of code in mpn/generic/mul_fft.c. */
+int k;
+int foo ()
+{
+  int i, **a;
+  a = __builtin_alloca (k);
+  for (i = 0; i <= k; i++)
+    a[i] = __builtin_alloca (1 << i);
+}
+
+int main () { return 0; }
+EOF
+  echo "Test compile: alloca array" >&5
+  gmp_compile="$cc $cflags $cppflags conftest.c >&5"
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    cc_works_part=yes
+    if test "$cross_compiling" = no; then
+      if { ac_try='./a.out || ./b.out || ./a.exe || ./a_out.exe || ./conftest'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :;
+      else
+        cc_works_part=norun
+      fi
+    fi
+  else
+    cc_works_part=no
+  fi
+  if test "$cc_works_part" != yes; then
+    echo "failed program was:" >&5
+    cat conftest.c >&5
+  fi
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  case $cc_works_part in
+    yes)
+
+      ;;
+    no)
+      gmp_prog_cc_works="no, alloca array"
+      ;;
+    norun)
+      gmp_prog_cc_works="no, alloca array, program does not run"
+      ;;
+  esac
+fi
+
+
+
+      ;;
+    no)
+
+      ;;
+    norun)
+
+      ;;
+  esac
+fi
+
+
+if test "$gmp_prog_cc_works" = yes; then
+  # remove anything that might look like compiler output to our "||" expression
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  cat >conftest.c <<EOF
+/* The following provokes an internal error from the assembler on
+   power2-ibm-aix4.3.1.0.  gcc -mrios2 compiles to nabs+fcirz, and this
+   results in "Internal error related to the source program domain".
+
+   For reference it seems to be the combination of nabs+fcirz which is bad,
+   not either alone.  This sort of thing occurs in mpz/get_str.c with the
+   way double chars_per_bit_exactly is applied in MPN_SIZEINBASE.  Perhaps
+   if that code changes to a scaled-integer style then we won't need this
+   test.  */
+
+double fp[1];
+int x;
+int f ()
+{
+  int a;
+  a = (x >= 0 ? x : -x);
+  return a * fp[0];
+}
+
+int main () { return 0; }
+EOF
+  echo "Test compile: abs int -> double conversion" >&5
+  gmp_compile="$cc $cflags $cppflags conftest.c >&5"
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    cc_works_part=yes
+    if test "$cross_compiling" = no; then
+      if { ac_try='./a.out || ./b.out || ./a.exe || ./a_out.exe || ./conftest'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :;
+      else
+        cc_works_part=norun
+      fi
+    fi
+  else
+    cc_works_part=no
+  fi
+  if test "$cc_works_part" != yes; then
+    echo "failed program was:" >&5
+    cat conftest.c >&5
+  fi
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  case $cc_works_part in
+    yes)
+
+      ;;
+    no)
+      gmp_prog_cc_works="no, abs int -> double conversion"
+      ;;
+    norun)
+      gmp_prog_cc_works="no, abs int -> double conversion, program does not run"
+      ;;
+  esac
+fi
+
+
+
+
+if test "$gmp_prog_cc_works" = yes; then
+  # remove anything that might look like compiler output to our "||" expression
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  cat >conftest.c <<EOF
+/* The following provokes a segfault in the compiler on powerpc-apple-darwin.
+   Extracted from tests/mpn/t-iord_u.c.  Causes Apple's gcc 3.3 build 1640 and
+   1666 to segfault with e.g., -O2 -mpowerpc64.  */
+
+#if defined (__GNUC__) && ! defined (__cplusplus)
+typedef unsigned long long t1;typedef t1*t2;
+void g(){}
+void h(){}
+static __inline__ t1 e(t2 rp,t2 up,int n,t1 v0)
+{t1 c,x,r;int i;if(v0){c=1;for(i=1;i<n;i++){x=up[i];r=x+1;rp[i]=r;}}return c;}
+void f(){static const struct{t1 n;t1 src[9];t1 want[9];}d[]={{1,{0},{1}},};t1 got[9];int i;
+for(i=0;i<1;i++){if(e(got,got,9,d[i].n)==0)h();g(i,d[i].src,d[i].n,got,d[i].want,9);if(d[i].n)h();}}
+#else
+int dummy;
+#endif
+
+int main () { return 0; }
+EOF
+  echo "Test compile: long long reliability test 1" >&5
+  gmp_compile="$cc $cflags $cppflags conftest.c >&5"
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    cc_works_part=yes
+    if test "$cross_compiling" = no; then
+      if { ac_try='./a.out || ./b.out || ./a.exe || ./a_out.exe || ./conftest'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :;
+      else
+        cc_works_part=norun
+      fi
+    fi
+  else
+    cc_works_part=no
+  fi
+  if test "$cc_works_part" != yes; then
+    echo "failed program was:" >&5
+    cat conftest.c >&5
+  fi
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  case $cc_works_part in
+    yes)
+
+      ;;
+    no)
+      gmp_prog_cc_works="no, long long reliability test 1"
+      ;;
+    norun)
+      gmp_prog_cc_works="no, long long reliability test 1, program does not run"
+      ;;
+  esac
+fi
+
+
+
+
+if test "$gmp_prog_cc_works" = yes; then
+  # remove anything that might look like compiler output to our "||" expression
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  cat >conftest.c <<EOF
+/* The following provokes an internal compiler error on powerpc-apple-darwin.
+   Extracted from mpz/cfdiv_q_2exp.c.  Causes Apple's gcc 3.3 build 1640 and
+   1666 to get an ICE with -O1 -mpowerpc64.  */
+
+#if defined (__GNUC__) && ! defined (__cplusplus)
+int g();
+void f(int u){int i;long long x;x=u?~0:0;if(x)for(i=0;i<9;i++);x&=g();if(x)g();}
+int g(){return 0;}
+#else
+int dummy;
+#endif
+
+int main () { return 0; }
+EOF
+  echo "Test compile: long long reliability test 2" >&5
+  gmp_compile="$cc $cflags $cppflags conftest.c >&5"
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    cc_works_part=yes
+    if test "$cross_compiling" = no; then
+      if { ac_try='./a.out || ./b.out || ./a.exe || ./a_out.exe || ./conftest'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :;
+      else
+        cc_works_part=norun
+      fi
+    fi
+  else
+    cc_works_part=no
+  fi
+  if test "$cc_works_part" != yes; then
+    echo "failed program was:" >&5
+    cat conftest.c >&5
+  fi
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  case $cc_works_part in
+    yes)
+
+      ;;
+    no)
+      gmp_prog_cc_works="no, long long reliability test 2"
+      ;;
+    norun)
+      gmp_prog_cc_works="no, long long reliability test 2, program does not run"
+      ;;
+  esac
+fi
+
+
+
+
+if test "$gmp_prog_cc_works" = yes; then
+  # remove anything that might look like compiler output to our "||" expression
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  cat >conftest.c <<EOF
+/* Provokes an ICE on i386-freebsd with the FreeBSD-hacked gcc, under
+   -O2 -march=amdfam10.  We call helper functions here "open" and "close" in
+   order for linking to succeed.  */
+
+#if defined (__GNUC__) && ! defined (__cplusplus)
+int open(int*,int*,int);void*close(int);void g(int*rp,int*up,int un){
+__builtin_expect(un<=0x7f00,1)?__builtin_alloca(un):close(un);if(__builtin_clzl
+(up[un])){open(rp,up,un);while(1){if(rp[un-1]!=0)break;un--;}}}
+#else
+int dummy;
+#endif
+
+int main () { return 0; }
+EOF
+  echo "Test compile: freebsd hacked gcc" >&5
+  gmp_compile="$cc $cflags $cppflags conftest.c >&5"
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    cc_works_part=yes
+    if test "$cross_compiling" = no; then
+      if { ac_try='./a.out || ./b.out || ./a.exe || ./a_out.exe || ./conftest'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :;
+      else
+        cc_works_part=norun
+      fi
+    fi
+  else
+    cc_works_part=no
+  fi
+  if test "$cc_works_part" != yes; then
+    echo "failed program was:" >&5
+    cat conftest.c >&5
+  fi
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  case $cc_works_part in
+    yes)
+
+      ;;
+    no)
+      gmp_prog_cc_works="no, freebsd hacked gcc"
+      ;;
+    norun)
+      gmp_prog_cc_works="no, freebsd hacked gcc, program does not run"
+      ;;
+  esac
+fi
+
+
+
+
+if test "$gmp_prog_cc_works" = yes; then
+  # remove anything that might look like compiler output to our "||" expression
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  cat >conftest.c <<EOF
+/* The following is mis-compiled by HP ia-64 cc version
+        cc: HP aC++/ANSI C B3910B A.05.55 [Dec 04 2003]
+   under "cc +O3", both in +DD32 and +DD64 modes.  The mpn_lshift_com gets
+   inlined and its return value somehow botched to be 0 instead of 1.  This
+   arises in the real mpn_lshift_com in mul_fft.c.  A lower optimization
+   level, like +O2 seems ok.  This code needs to be run to show the problem,
+   but that's fine, the offending cc is a native-only compiler so we don't
+   have to worry about cross compiling.  */
+
+#if ! defined (__cplusplus)
+unsigned long
+lshift_com (rp, up, n, cnt)
+  unsigned long *rp;
+  unsigned long *up;
+  long n;
+  unsigned cnt;
+{
+  unsigned long retval, high_limb, low_limb;
+  unsigned tnc;
+  long i;
+  tnc = 8 * sizeof (unsigned long) - cnt;
+  low_limb = *up++;
+  retval = low_limb >> tnc;
+  high_limb = low_limb << cnt;
+  for (i = n - 1; i != 0; i--)
+    {
+      low_limb = *up++;
+      *rp++ = ~(high_limb | (low_limb >> tnc));
+      high_limb = low_limb << cnt;
+    }
+  return retval;
+}
+int
+main ()
+{
+  unsigned long cy, rp[2], up[2];
+  up[0] = ~ 0L;
+  up[1] = 0;
+  cy = lshift_com (rp, up, 2L, 1);
+  if (cy != 1L)
+    return 1;
+  return 0;
+}
+#else
+int
+main ()
+{
+  return 0;
+}
+#endif
+
+EOF
+  echo "Test compile: mpn_lshift_com optimization" >&5
+  gmp_compile="$cc $cflags $cppflags conftest.c >&5"
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    cc_works_part=yes
+    if test "$cross_compiling" = no; then
+      if { ac_try='./a.out || ./b.out || ./a.exe || ./a_out.exe || ./conftest'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :;
+      else
+        cc_works_part=norun
+      fi
+    fi
+  else
+    cc_works_part=no
+  fi
+  if test "$cc_works_part" != yes; then
+    echo "failed program was:" >&5
+    cat conftest.c >&5
+  fi
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  case $cc_works_part in
+    yes)
+
+      ;;
+    no)
+      gmp_prog_cc_works="no, mpn_lshift_com optimization"
+      ;;
+    norun)
+      gmp_prog_cc_works="no, mpn_lshift_com optimization, program does not run"
+      ;;
+  esac
+fi
+
+
+
+if test "$gmp_prog_cc_works" = yes; then
+  # remove anything that might look like compiler output to our "||" expression
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  cat >conftest.c <<EOF
+/* The following is mis-compiled by Intel ia-64 icc version 1.8 under
+    "icc -O3",  After several calls, the function writes partial garbage to
+    the result vector.  Perhaps relates to the chk.a.nc insn.  This code needs
+    to be run to show the problem, but that's fine, the offending cc is a
+    native-only compiler so we don't have to worry about cross compiling.  */
+
+#if ! defined (__cplusplus)
+#include <stdlib.h>
+void
+lshift_com (rp, up, n, cnt)
+  unsigned long *rp;
+  unsigned long *up;
+  long n;
+  unsigned cnt;
+{
+  unsigned long high_limb, low_limb;
+  unsigned tnc;
+  long i;
+  up += n;
+  rp += n;
+  tnc = 8 * sizeof (unsigned long) - cnt;
+  low_limb = *--up;
+  high_limb = low_limb << cnt;
+  for (i = n - 1; i != 0; i--)
+    {
+      low_limb = *--up;
+      *--rp = ~(high_limb | (low_limb >> tnc));
+      high_limb = low_limb << cnt;
+    }
+  *--rp = ~high_limb;
+}
+int
+main ()
+{
+  unsigned long *r, *r2;
+  unsigned long a[88 + 1];
+  long i;
+  for (i = 0; i < 88 + 1; i++)
+    a[i] = ~0L;
+  r = calloc (10000, sizeof (unsigned long));
+  r2 = r;
+  for (i = 0; i < 528; i += 23)
+    {
+      lshift_com (r2, a,
+		  i / (8 * sizeof (unsigned long)) + 1,
+		  i % (8 * sizeof (unsigned long)));
+      r2 += 88 + 1;
+    }
+  if (r[2048] != 0 || r[2049] != 0 || r[2050] != 0 || r[2051] != 0 ||
+      r[2052] != 0 || r[2053] != 0 || r[2054] != 0)
+    abort ();
+  free (r);
+  return 0;
+}
+#else
+int
+main ()
+{
+  return 0;
+}
+#endif
+
+EOF
+  echo "Test compile: mpn_lshift_com optimization 2" >&5
+  gmp_compile="$cc $cflags $cppflags conftest.c >&5"
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    cc_works_part=yes
+    if test "$cross_compiling" = no; then
+      if { ac_try='./a.out || ./b.out || ./a.exe || ./a_out.exe || ./conftest'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :;
+      else
+        cc_works_part=norun
+      fi
+    fi
+  else
+    cc_works_part=no
+  fi
+  if test "$cc_works_part" != yes; then
+    echo "failed program was:" >&5
+    cat conftest.c >&5
+  fi
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  case $cc_works_part in
+    yes)
+
+      ;;
+    no)
+      gmp_prog_cc_works="no, mpn_lshift_com optimization 2"
+      ;;
+    norun)
+      gmp_prog_cc_works="no, mpn_lshift_com optimization 2, program does not run"
+      ;;
+  esac
+fi
+
+
+
+
+# A certain _GLOBAL_OFFSET_TABLE_ problem in past versions of gas, tickled
+# by recent versions of gcc.
+#
+if test "$gmp_prog_cc_works" = yes; then
+  case $host in
+    i?86*-*-* | k[5-8]*-*-* | pentium*-*-* | athlon-*-* | viac3*-*-* | geode*-*-* | atom-*-*)
+      # this problem only arises in PIC code, so don't need to test when
+      # --disable-shared.  We don't necessarily have $enable_shared set to
+      # yes at this point, it will still be unset for the default (which is
+      # yes); hence the use of "!= no".
+      if test "$enable_shared" != no; then
+        echo "Testing gcc GOT with eax emitted" >&5
+cat >conftest.c <<\EOF
+int foo;
+int bar () { return foo; }
+EOF
+tmp_got_emitted=no
+gmp_compile="$cc $cflags $cppflags -fPIC -S conftest.c >&5 2>&1"
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  if grep "addl.*_GLOBAL_OFFSET_TABLE_.*eax" conftest.s >/dev/null; then
+    tmp_got_emitted=yes
+  fi
+fi
+rm -f conftest.*
+echo "Result: $tmp_got_emitted" >&5
+if test "$tmp_got_emitted" = yes; then
+  echo "Testing gas GOT with eax good" >&5
+cat >conftest.awk <<\EOF
+BEGIN {
+  want[0]  = "001"
+  want[1]  = "043"
+  want[2]  = "105"
+  want[3]  = "147"
+  want[4]  = "211"
+  want[5]  = "253"
+  want[6]  = "315"
+  want[7]  = "357"
+
+  want[8]  = "005"
+  want[9]  = "002"
+  want[10] = "000"
+  want[11] = "000"
+  want[12] = "000"
+
+  want[13] = "376"
+  want[14] = "334"
+  want[15] = "272"
+  want[16] = "230"
+  want[17] = "166"
+  want[18] = "124"
+  want[19] = "062"
+  want[20] = "020"
+
+  result = "yes"
+}
+{
+  for (f = 2; f <= NF; f++)
+    {
+      for (i = 0; i < 20; i++)
+        got[i] = got[i+1];
+      got[20] = $f;
+
+      found = 1
+      for (i = 0; i < 21; i++)
+        if (got[i] != want[i])
+          {
+            found = 0
+            break
+          }
+      if (found)
+        {
+          result = "no"
+          exit
+        }
+    }
+}
+END {
+  print result
+}
+EOF
+cat >conftest.s <<\EOF
+	.text
+	.byte	1, 35, 69, 103, 137, 171, 205, 239
+	addl	$_GLOBAL_OFFSET_TABLE_, %eax
+	.byte	254, 220, 186, 152, 118, 84, 50, 16
+EOF
+tmp_got_good=yes
+gmp_compile="$cc $cflags $cppflags -fPIC -o conftest.o -c conftest.s >&5 2>&1"
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  tmp_got_good=`od -b conftest.o | $AWK -f conftest.awk`
+fi
+rm -f conftest.*
+echo "Result: $tmp_got_good" >&5
+if test "$tmp_got_good" = no; then
+  gmp_prog_cc_works="no, bad gas GOT with eax"
+else
+  :
+fi
+
+else
+  :
+fi
+
+      fi
+      ;;
+  esac
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_prog_cc_works" >&5
+$as_echo "$gmp_prog_cc_works" >&6; }
+case $gmp_prog_cc_works in
+  yes)
+
+    ;;
+  *)
+    continue
+    ;;
+esac
+
+
+        # If we're supposed to be using a "long long" for a limb, check that
+        # it works.
+                                  eval limb_chosen=\"\$limb$abi1\"
+        test -n "$limb_chosen" || eval limb_chosen=\"\$limb$abi2\"
+        if test "$limb_chosen" = longlong; then
+          { $as_echo "$as_me:${as_lineno-$LINENO}: checking compiler $cc $cflags $cppflags has long long" >&5
+$as_echo_n "checking compiler $cc $cflags $cppflags has long long... " >&6; }
+cat >conftest.c <<EOF
+long long  foo;
+long long  bar () { return foo; }
+int main () { return 0; }
+EOF
+gmp_prog_cc_works=no
+gmp_compile="$cc $cflags $cppflags -c conftest.c >&5"
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  gmp_prog_cc_works=yes
+else
+  echo "failed program was:" >&5
+  cat conftest.c >&5
+fi
+rm -f conftest* a.out b.out a.exe a_out.exe
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_prog_cc_works" >&5
+$as_echo "$gmp_prog_cc_works" >&6; }
+if test $gmp_prog_cc_works = yes; then
+  :
+else
+  continue
+fi
+
+        fi
+
+        # The tests to perform on this $cc, if any
+                               eval testlist=\"\$${ccbase}${abi1}_testlist\"
+        test -n "$testlist" || eval testlist=\"\$${ccbase}${abi2}_testlist\"
+        test -n "$testlist" || eval testlist=\"\$any${abi1}_testlist\"
+        test -n "$testlist" || eval testlist=\"\$any${abi2}_testlist\"
+
+        testlist_pass=yes
+        for tst in $testlist; do
+          case $tst in
+          hpc-hppa-2-0)   { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether HP compiler $cc is good for 64-bits" >&5
+$as_echo_n "checking whether HP compiler $cc is good for 64-bits... " >&6; }
+# Bad compiler output:
+#   ccom: HP92453-01 G.10.32.05 HP C Compiler
+# Good compiler output:
+#   ccom: HP92453-01 A.10.32.30 HP C Compiler
+# Let A.10.32.30 or higher be ok.
+echo >conftest.c
+gmp_tmp_vs=`$cc  -V -c -o conftest.$OBJEXT conftest.c 2>&1 | grep "^ccom:"`
+echo "Version string: $gmp_tmp_vs" >&5
+rm conftest*
+gmp_tmp_v1=`echo $gmp_tmp_vs | sed 's/.* .\.\([0-9]*\).*/\1/'`
+gmp_tmp_v2=`echo $gmp_tmp_vs | sed 's/.* .\..*\.\(.*\)\..* HP C.*/\1/'`
+gmp_tmp_v3=`echo $gmp_tmp_vs | sed 's/.* .\..*\..*\.\(.*\) HP C.*/\1/'`
+echo "Version number: $gmp_tmp_v1.$gmp_tmp_v2.$gmp_tmp_v3" >&5
+if test -z "$gmp_tmp_v1"; then
+  gmp_hpc_64bit=not-applicable
+else
+  gmp_compare_ge=no
+if test -n "$gmp_tmp_v1"; then
+  if test "$gmp_tmp_v1" -gt 10; then
+    gmp_compare_ge=yes
+  else
+    if test "$gmp_tmp_v1" -eq 10; then
+      if test -n "$gmp_tmp_v2"; then
+  if test "$gmp_tmp_v2" -gt 32; then
+    gmp_compare_ge=yes
+  else
+    if test "$gmp_tmp_v2" -eq 32; then
+      if test -n "$gmp_tmp_v3" && test "$gmp_tmp_v3" -ge 30; then
+  gmp_compare_ge=yes
+fi
+
+    fi
+  fi
+fi
+
+    fi
+  fi
+fi
+
+
+  gmp_hpc_64bit=$gmp_compare_ge
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_hpc_64bit" >&5
+$as_echo "$gmp_hpc_64bit" >&6; }
+if test $gmp_hpc_64bit = yes; then
+  :
+else
+  testlist_pass=no
+fi
+ ;;
+          gcc-arm-umodsi) { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ARM gcc unsigned division works" >&5
+$as_echo_n "checking whether ARM gcc unsigned division works... " >&6; }
+tmp_version=`$cc --version`
+echo "$tmp_version" >&5
+case $tmp_version in
+  2.95 | 2.95.[123])
+    testlist_pass=no
+    gmp_gcc_arm_umodsi_result="no, gcc 2.95.[0123]" ;;
+  *)
+    :
+    gmp_gcc_arm_umodsi_result=yes ;;
+esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_gcc_arm_umodsi_result" >&5
+$as_echo "$gmp_gcc_arm_umodsi_result" >&6; }
+ ;;
+          gcc-mips-o32)   { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether gcc supports o32" >&5
+$as_echo_n "checking whether gcc supports o32... " >&6; }
+echo 'int x;' >conftest.c
+echo "$cc -mabi=32 -c conftest.c" >&5
+if $cc -mabi=32 -c conftest.c >conftest.out 2>&1; then
+  result=yes
+else
+  cat conftest.out >&5
+  if grep "cc1: Invalid option \`abi=32'" conftest.out >/dev/null; then
+    result=yes
+  else
+    result=no
+  fi
+fi
+rm -f conftest.*
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $result" >&5
+$as_echo "$result" >&6; }
+if test $result = yes; then
+  :
+else
+  testlist_pass=no
+fi
+ ;;
+          hppa-level-2.0) { $as_echo "$as_me:${as_lineno-$LINENO}: checking $cc $cflags assembler knows hppa 2.0" >&5
+$as_echo_n "checking $cc $cflags assembler knows hppa 2.0... " >&6; }
+result=no
+cat >conftest.s <<EOF
+	.level 2.0
+EOF
+gmp_compile="$cc $cflags -c conftest.s >&5 2>&1"
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  result=yes
+else
+  echo "failed program was" >&5
+  cat conftest.s >&5
+fi
+rm -f conftest*
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $result" >&5
+$as_echo "$result" >&6; }
+if test "$result" = yes; then
+  :
+else
+  testlist_pass=no
+fi
+ ;;
+          sizeof*)       echo "configure: testlist $tst" >&5
+gmp_sizeof_type=`echo "$tst" | sed 's/sizeof-\([a-z\*]*\).*/\1/'`
+gmp_sizeof_want=`echo "$tst" | sed 's/sizeof-[a-z\*]*-\([0-9]*\).*/\1/'`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking compiler $cc $cflags has sizeof($gmp_sizeof_type)==$gmp_sizeof_want" >&5
+$as_echo_n "checking compiler $cc $cflags has sizeof($gmp_sizeof_type)==$gmp_sizeof_want... " >&6; }
+cat >conftest.c <<EOF
+int
+main ()
+{
+  static int test_array [1 - 2 * (long) (sizeof ($gmp_sizeof_type) != $gmp_sizeof_want)];
+  test_array[0] = 0;
+  return 0;
+}
+EOF
+gmp_c_testlist_sizeof=no
+gmp_compile="$cc $cflags -c conftest.c >&5"
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  gmp_c_testlist_sizeof=yes
+fi
+rm -f conftest*
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_c_testlist_sizeof" >&5
+$as_echo "$gmp_c_testlist_sizeof" >&6; }
+if test $gmp_c_testlist_sizeof = yes; then
+  :
+else
+  testlist_pass=no
+fi
+ ;;
+          esac
+          if test $testlist_pass = no; then break; fi
+        done
+
+        if test $testlist_pass = yes; then
+          found_compiler=yes
+          break
+        fi
+      done
+
+      if test $found_compiler = yes; then break; fi
+    done
+
+    if test $found_compiler = yes; then break; fi
+  done
+
+  if test $found_compiler = yes; then break; fi
+done
+
+
+# If we recognised the CPU, as indicated by $path being set, then insist
+# that we have a working compiler, either from our $cclist choices or from
+# $CC.  We can't let AC_PROG_CC look around for a compiler because it might
+# find one that we've rejected (for not supporting the modes our asm code
+# demands, etc).
+#
+# If we didn't recognise the CPU (and this includes host_cpu=none), then
+# fall through and let AC_PROG_CC look around for a compiler too.  This is
+# mostly in the interests of following a standard autoconf setup, after all
+# we've already tested cc and gcc adequately (hopefully).  As of autoconf
+# 2.50 the only thing AC_PROG_CC really adds is a check for "cl" (Microsoft
+# C on MS-DOS systems).
+#
+if test $found_compiler = no && test -n "$path"; then
+  as_fn_error $? "could not find a working compiler, see config.log for details" "$LINENO" 5
+fi
+
+case $host in
+  i?86*-*-* | k[5-8]*-*-* | pentium*-*-* | athlon-*-* | viac3*-*-* | geode*-*-* | atom-*-* | athlon64-*-* | k8-*-* | k10-*-* | bobcat-*-* | jaguar*-*-* | bulldozer*-*-* | piledriver*-*-* | steamroller*-*-* | excavator*-*-* | zen*-*-* | pentium4-*-* | atom-*-* | silvermont-*-* | goldmont-*-* | core2-*-* | corei*-*-* | x86_64-*-* | nano-*-* | nehalem*-*-* | westmere*-*-* | sandybridge*-*-* | ivybridge*-*-* | haswell*-*-* | broadwell*-*-* | skylake*-*-* | kabylake*-*-*)
+    # If the user asked for a fat build, override the path and flags set above
+    if test $enable_fat = yes; then
+      gcc_cflags_cpu=""
+      gcc_cflags_arch=""
+
+      fat_functions="add_n addmul_1 bdiv_dbm1c com cnd_add_n cnd_sub_n
+		     copyd copyi dive_1 divrem_1
+		     gcd_11 lshift lshiftc mod_1 mod_1_1 mod_1_1_cps mod_1_2
+		     mod_1_2_cps mod_1_4 mod_1_4_cps mod_34lsub1 mode1o mul_1
+		     mul_basecase mullo_basecase pre_divrem_1 pre_mod_1 redc_1
+		     redc_2 rshift sqr_basecase sub_n submul_1"
+
+      if test "$abi" = 32; then
+	extra_functions="$extra_functions fat fat_entry"
+	path="x86/fat x86"
+	fat_path="x86 x86/fat x86/i486
+		  x86/k6 x86/k6/mmx x86/k6/k62mmx
+		  x86/k7 x86/k7/mmx
+		  x86/k8 x86/k10 x86/bt1
+		  x86/pentium x86/pentium/mmx
+		  x86/p6 x86/p6/mmx x86/p6/p3mmx x86/p6/sse2
+		  x86/pentium4 x86/pentium4/mmx x86/pentium4/sse2
+		  x86/core2 x86/coreinhm x86/coreisbr
+		  x86/atom x86/atom/mmx x86/atom/sse2 x86/nano"
+      fi
+
+      if test "$abi" = 64; then
+	gcc_64_cflags=""
+	extra_functions_64="$extra_functions_64 fat fat_entry"
+	path_64="x86_64/fat x86_64"
+	fat_path="x86_64 x86_64/fat
+		  x86_64/k8 x86_64/k10 x86_64/bd1 x86_64/bt1 x86_64/bt2 x86_64/zen
+		  x86_64/pentium4 x86_64/core2 x86_64/coreinhm x86_64/coreisbr
+		  x86_64/coreihwl x86_64/coreibwl x86_64/skylake x86_64/atom
+		  x86_64/silvermont x86_64/goldmont x86_64/nano"
+	fat_functions="$fat_functions addmul_2 addlsh1_n addlsh2_n sublsh1_n"
+      fi
+
+      fat_thresholds="MUL_TOOM22_THRESHOLD MUL_TOOM33_THRESHOLD
+		      SQR_TOOM2_THRESHOLD SQR_TOOM3_THRESHOLD
+		      BMOD_1_TO_MOD_1_THRESHOLD"
+    fi
+    ;;
+esac
+
+
+if test $found_compiler = yes; then
+
+  # If we're creating CFLAGS, then look for optional additions.  If the user
+  # set CFLAGS then leave it alone.
+  #
+  if test "$test_CFLAGS" != set; then
+                          eval optlist=\"\$${ccbase}${abi1}_cflags_optlist\"
+    test -n "$optlist" || eval optlist=\"\$${ccbase}${abi2}_cflags_optlist\"
+
+    for opt in $optlist; do
+                             eval optflags=\"\$${ccbase}${abi1}_cflags_${opt}\"
+      test -n "$optflags" || eval optflags=\"\$${ccbase}${abi2}_cflags_${opt}\"
+      test -n "$optflags" || eval optflags=\"\$${ccbase}_cflags_${opt}\"
+
+      for flag in $optflags; do
+
+	# ~ represents a space in an option spec
+        flag=`echo "$flag" | tr '~' ' '`
+
+        case $flag in
+          -march=pentium4 | -march=k8)
+            # For -march settings which enable SSE2 we exclude certain bad
+            # gcc versions and we need an OS knowing how to save xmm regs.
+            #
+            # This is only for ABI=32, any 64-bit gcc is good and any OS
+            # knowing x86_64 will know xmm.
+            #
+            # -march=k8 was only introduced in gcc 3.3, so we shouldn't need
+            # the GMP_GCC_PENTIUM4_SSE2 check (for gcc 3.2 and prior).  But
+            # it doesn't hurt to run it anyway, sharing code with the
+            # pentium4 case.
+            #
+            if test "$abi" = 32; then
+              { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether gcc is good for sse2" >&5
+$as_echo_n "checking whether gcc is good for sse2... " >&6; }
+case `$cc $cflags $cppflags -dumpversion` in
+  3.[012] | 3.[012].*) result=no ;;
+  *)                     result=yes ;;
+esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $result" >&5
+$as_echo "$result" >&6; }
+if test "$result" = yes; then
+  :
+else
+  continue
+fi
+
+              { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the operating system supports XMM registers" >&5
+$as_echo_n "checking whether the operating system supports XMM registers... " >&6; }
+if ${gmp_cv_os_x86_xmm+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test "$build" = "$host"; then
+  # remove anything that might look like compiler output to our "||" expression
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  cat >conftest.s <<EOF
+	.text
+main:
+_main:
+	.globl	main
+	.globl	_main
+	.byte	0x0f, 0x57, 0xc0
+	xorl	%eax, %eax
+	ret
+EOF
+  gmp_compile="$cc $cflags $cppflags conftest.s -o conftest >&5"
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    if { ac_try='./a.out || ./b.out || ./a.exe || ./a_out.exe || ./conftest'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then
+      gmp_cv_os_x86_xmm=yes
+    else
+      gmp_cv_os_x86_xmm=no
+    fi
+  else
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Oops, cannot compile test program" >&5
+$as_echo "$as_me: WARNING: Oops, cannot compile test program" >&2;}
+  fi
+  rm -f conftest*
+fi
+
+if test -z "$gmp_cv_os_x86_xmm"; then
+  case $host_os in
+    freebsd[123] | freebsd[123].*)
+      gmp_cv_os_x86_xmm=no ;;
+    freebsd*)
+      gmp_cv_os_x86_xmm=yes ;;
+    *)
+      gmp_cv_os_x86_xmm=probably ;;
+  esac
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_cv_os_x86_xmm" >&5
+$as_echo "$gmp_cv_os_x86_xmm" >&6; }
+
+if test "$gmp_cv_os_x86_xmm" = probably; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Not certain of OS support for xmm when cross compiling." >&5
+$as_echo "$as_me: WARNING: Not certain of OS support for xmm when cross compiling." >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Will assume it's ok, expect a SIGILL if this is wrong." >&5
+$as_echo "$as_me: WARNING: Will assume it's ok, expect a SIGILL if this is wrong." >&2;}
+fi
+
+case $gmp_cv_os_x86_xmm in
+no)
+  continue
+  ;;
+*)
+
+  ;;
+esac
+
+            fi
+            ;;
+          -no-cpp-precomp)
+            # special check, avoiding a warning
+            if test "$ccbase" = gcc; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking compiler $cc $cflags -no-cpp-precomp" >&5
+$as_echo_n "checking compiler $cc $cflags -no-cpp-precomp... " >&6; }
+  result=no
+  cat >conftest.c <<EOF
+int main () { return 0; }
+EOF
+  gmp_compile="$cc $cflags -no-cpp-precomp conftest.c >conftest.out 2>&1"
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    if grep "unrecognized option.*-no-cpp-precomp" conftest.out >/dev/null; then : ;
+    else
+      result=yes
+    fi
+  fi
+  cat conftest.out >&5
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $result" >&5
+$as_echo "$result" >&6; }
+  if test "$result" = yes; then
+      cflags="$cflags $flag"
+                                   break
+  else
+      continue
+  fi
+fi
+
+            ;;
+          -Wa,-m*)
+            case $host in
+              alpha*-*-*)
+                { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler $cc $cflags $flag" >&5
+$as_echo_n "checking assembler $cc $cflags $flag... " >&6; }
+result=no
+cat >conftest.c <<EOF
+int main () {}
+EOF
+gmp_compile="$cc $cflags $flag -c conftest.c >conftest.out 2>&1"
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  if grep "Unknown CPU identifier" conftest.out >/dev/null; then : ;
+  else
+    result=yes
+  fi
+fi
+cat conftest.out >&5
+rm -f conftest*
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $result" >&5
+$as_echo "$result" >&6; }
+if test "$result" = yes; then
+  :
+else
+  continue
+fi
+
+              ;;
+            esac
+            ;;
+          -Wa,-oldas)
+            { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $cc $cflags $cppflags -Wa,-oldas" >&5
+$as_echo_n "checking for $cc $cflags $cppflags -Wa,-oldas... " >&6; }
+result=no
+cat >conftest.c <<EOF
+EOF
+echo "with empty conftest.c" >&5
+gmp_compile="$cc $cflags $cppflags -c conftest.c >&5 2>&1"
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then : ;
+else
+  # empty fails
+  gmp_compile="$cc $cflags $cppflags -Wa,-oldas -c conftest.c >&5 2>&1"
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    # but with -Wa,-oldas it works
+    result=yes
+  fi
+fi
+rm -f conftest*
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $result" >&5
+$as_echo "$result" >&6; }
+if test "$result" = yes; then
+  cflags="$cflags $flag"
+                             break
+else
+  continue
+fi
+
+            ;;
+        esac
+
+        { $as_echo "$as_me:${as_lineno-$LINENO}: checking compiler $cc $cflags $cppflags $flag" >&5
+$as_echo_n "checking compiler $cc $cflags $cppflags $flag... " >&6; }
+gmp_prog_cc_works=yes
+
+# first see a simple "main()" works, then go on to other checks
+if test "$gmp_prog_cc_works" = yes; then
+  # remove anything that might look like compiler output to our "||" expression
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  cat >conftest.c <<EOF
+
+int main () { return 0; }
+EOF
+  echo "Test compile: " >&5
+  gmp_compile="$cc $cflags $cppflags $flag conftest.c >&5"
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    cc_works_part=yes
+    if test "$cross_compiling" = no; then
+      if { ac_try='./a.out || ./b.out || ./a.exe || ./a_out.exe || ./conftest'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :;
+      else
+        cc_works_part=norun
+      fi
+    fi
+  else
+    cc_works_part=no
+  fi
+  if test "$cc_works_part" != yes; then
+    echo "failed program was:" >&5
+    cat conftest.c >&5
+  fi
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  case $cc_works_part in
+    yes)
+
+      ;;
+    no)
+      gmp_prog_cc_works="no"
+      ;;
+    norun)
+      gmp_prog_cc_works="no, program does not run"
+      ;;
+  esac
+fi
+
+
+
+
+if test "$gmp_prog_cc_works" = yes; then
+  # remove anything that might look like compiler output to our "||" expression
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  cat >conftest.c <<EOF
+/* The following provokes an internal error from gcc 2.95.2 -mpowerpc64
+   (without -maix64), hence detecting an unusable compiler */
+void *g() { return (void *) 0; }
+void *f() { return g(); }
+
+int main () { return 0; }
+EOF
+  echo "Test compile: function pointer return" >&5
+  gmp_compile="$cc $cflags $cppflags $flag conftest.c >&5"
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    cc_works_part=yes
+    if test "$cross_compiling" = no; then
+      if { ac_try='./a.out || ./b.out || ./a.exe || ./a_out.exe || ./conftest'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :;
+      else
+        cc_works_part=norun
+      fi
+    fi
+  else
+    cc_works_part=no
+  fi
+  if test "$cc_works_part" != yes; then
+    echo "failed program was:" >&5
+    cat conftest.c >&5
+  fi
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  case $cc_works_part in
+    yes)
+
+      ;;
+    no)
+      gmp_prog_cc_works="no, function pointer return"
+      ;;
+    norun)
+      gmp_prog_cc_works="no, function pointer return, program does not run"
+      ;;
+  esac
+fi
+
+
+
+
+if test "$gmp_prog_cc_works" = yes; then
+  # remove anything that might look like compiler output to our "||" expression
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  cat >conftest.c <<EOF
+/* The following provokes an invalid instruction syntax from i386 gcc
+   -march=pentiumpro on Solaris 2.8.  The native sun assembler
+   requires a non-standard syntax for cmov which gcc (as of 2.95.2 at
+   least) doesn't know.  */
+int n;
+int cmov () { return (n >= 0 ? n : 0); }
+
+int main () { return 0; }
+EOF
+  echo "Test compile: cmov instruction" >&5
+  gmp_compile="$cc $cflags $cppflags $flag conftest.c >&5"
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    cc_works_part=yes
+    if test "$cross_compiling" = no; then
+      if { ac_try='./a.out || ./b.out || ./a.exe || ./a_out.exe || ./conftest'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :;
+      else
+        cc_works_part=norun
+      fi
+    fi
+  else
+    cc_works_part=no
+  fi
+  if test "$cc_works_part" != yes; then
+    echo "failed program was:" >&5
+    cat conftest.c >&5
+  fi
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  case $cc_works_part in
+    yes)
+
+      ;;
+    no)
+      gmp_prog_cc_works="no, cmov instruction"
+      ;;
+    norun)
+      gmp_prog_cc_works="no, cmov instruction, program does not run"
+      ;;
+  esac
+fi
+
+
+
+
+if test "$gmp_prog_cc_works" = yes; then
+  # remove anything that might look like compiler output to our "||" expression
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  cat >conftest.c <<EOF
+/* The following provokes a linker invocation problem with gcc 3.0.3
+   on AIX 4.3 under "-maix64 -mpowerpc64 -mcpu=630".  The -mcpu=630
+   option causes gcc to incorrectly select the 32-bit libgcc.a, not
+   the 64-bit one, and consequently it misses out on the __fixunsdfdi
+   helper (double -> uint64 conversion).  */
+double d;
+unsigned long gcc303 () { return (unsigned long) d; }
+
+int main () { return 0; }
+EOF
+  echo "Test compile: double -> ulong conversion" >&5
+  gmp_compile="$cc $cflags $cppflags $flag conftest.c >&5"
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    cc_works_part=yes
+    if test "$cross_compiling" = no; then
+      if { ac_try='./a.out || ./b.out || ./a.exe || ./a_out.exe || ./conftest'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :;
+      else
+        cc_works_part=norun
+      fi
+    fi
+  else
+    cc_works_part=no
+  fi
+  if test "$cc_works_part" != yes; then
+    echo "failed program was:" >&5
+    cat conftest.c >&5
+  fi
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  case $cc_works_part in
+    yes)
+
+      ;;
+    no)
+      gmp_prog_cc_works="no, double -> ulong conversion"
+      ;;
+    norun)
+      gmp_prog_cc_works="no, double -> ulong conversion, program does not run"
+      ;;
+  esac
+fi
+
+
+
+
+if test "$gmp_prog_cc_works" = yes; then
+  # remove anything that might look like compiler output to our "||" expression
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  cat >conftest.c <<EOF
+/* The following provokes an error from hppa gcc 2.95 under -mpa-risc-2-0 if
+   the assembler doesn't know hppa 2.0 instructions.  fneg is a 2.0
+   instruction, and a negation like this comes out using it.  */
+double fneg_data;
+unsigned long fneg () { return -fneg_data; }
+
+int main () { return 0; }
+EOF
+  echo "Test compile: double negation" >&5
+  gmp_compile="$cc $cflags $cppflags $flag conftest.c >&5"
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    cc_works_part=yes
+    if test "$cross_compiling" = no; then
+      if { ac_try='./a.out || ./b.out || ./a.exe || ./a_out.exe || ./conftest'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :;
+      else
+        cc_works_part=norun
+      fi
+    fi
+  else
+    cc_works_part=no
+  fi
+  if test "$cc_works_part" != yes; then
+    echo "failed program was:" >&5
+    cat conftest.c >&5
+  fi
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  case $cc_works_part in
+    yes)
+
+      ;;
+    no)
+      gmp_prog_cc_works="no, double negation"
+      ;;
+    norun)
+      gmp_prog_cc_works="no, double negation, program does not run"
+      ;;
+  esac
+fi
+
+
+
+
+if test "$gmp_prog_cc_works" = yes; then
+  # remove anything that might look like compiler output to our "||" expression
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  cat >conftest.c <<EOF
+/* The following makes gcc 3.3 -march=pentium4 generate an SSE2 xmm insn
+   (cvtsd2ss) which will provoke an error if the assembler doesn't recognise
+   those instructions.  Not sure how much of the gmp code will come out
+   wanting sse2, but it's easiest to reject an option we know is bad.  */
+double ftod_data;
+float ftod () { return (float) ftod_data; }
+
+int main () { return 0; }
+EOF
+  echo "Test compile: double -> float conversion" >&5
+  gmp_compile="$cc $cflags $cppflags $flag conftest.c >&5"
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    cc_works_part=yes
+    if test "$cross_compiling" = no; then
+      if { ac_try='./a.out || ./b.out || ./a.exe || ./a_out.exe || ./conftest'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :;
+      else
+        cc_works_part=norun
+      fi
+    fi
+  else
+    cc_works_part=no
+  fi
+  if test "$cc_works_part" != yes; then
+    echo "failed program was:" >&5
+    cat conftest.c >&5
+  fi
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  case $cc_works_part in
+    yes)
+
+      ;;
+    no)
+      gmp_prog_cc_works="no, double -> float conversion"
+      ;;
+    norun)
+      gmp_prog_cc_works="no, double -> float conversion, program does not run"
+      ;;
+  esac
+fi
+
+
+
+
+if test "$gmp_prog_cc_works" = yes; then
+  # remove anything that might look like compiler output to our "||" expression
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  cat >conftest.c <<EOF
+/* The following provokes an internal compiler error from gcc version
+   "2.9-gnupro-99r1" under "-O2 -mcpu=ev6", apparently relating to char
+   values being spilled into floating point registers.  The problem doesn't
+   show up all the time, but has occurred enough in GMP for us to reject
+   this compiler+flags.  */
+#include <string.h>  /* for memcpy */
+struct try_t
+{
+ char dst[2];
+ char size;
+ long d0, d1, d2, d3, d4, d5, d6;
+ char overlap;
+};
+struct try_t param[6];
+int
+param_init ()
+{
+ struct try_t *p;
+ memcpy (p, &param[ 2 ], sizeof (*p));
+ memcpy (p, &param[ 2 ], sizeof (*p));
+ p->size = 2;
+ memcpy (p, &param[ 1 ], sizeof (*p));
+ p->dst[0] = 1;
+ p->overlap = 2;
+ memcpy (p, &param[ 3 ], sizeof (*p));
+ p->dst[0] = 1;
+ p->overlap = 8;
+ memcpy (p, &param[ 4 ], sizeof (*p));
+ memcpy (p, &param[ 4 ], sizeof (*p));
+ p->overlap = 8;
+ memcpy (p, &param[ 5 ], sizeof (*p));
+ memcpy (p, &param[ 5 ], sizeof (*p));
+ memcpy (p, &param[ 5 ], sizeof (*p));
+ return 0;
+}
+
+int main () { return 0; }
+EOF
+  echo "Test compile: gnupro alpha ev6 char spilling" >&5
+  gmp_compile="$cc $cflags $cppflags $flag conftest.c >&5"
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    cc_works_part=yes
+    if test "$cross_compiling" = no; then
+      if { ac_try='./a.out || ./b.out || ./a.exe || ./a_out.exe || ./conftest'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :;
+      else
+        cc_works_part=norun
+      fi
+    fi
+  else
+    cc_works_part=no
+  fi
+  if test "$cc_works_part" != yes; then
+    echo "failed program was:" >&5
+    cat conftest.c >&5
+  fi
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  case $cc_works_part in
+    yes)
+
+      ;;
+    no)
+      gmp_prog_cc_works="no, gnupro alpha ev6 char spilling"
+      ;;
+    norun)
+      gmp_prog_cc_works="no, gnupro alpha ev6 char spilling, program does not run"
+      ;;
+  esac
+fi
+
+
+
+
+# __builtin_alloca is not available everywhere, check it exists before
+# seeing that it works
+if test "$gmp_prog_cc_works" = yes; then
+  # remove anything that might look like compiler output to our "||" expression
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  cat >conftest.c <<EOF
+int k; int foo () { __builtin_alloca (k); }
+EOF
+  echo "Test compile: __builtin_alloca availability" >&5
+  gmp_compile="$cc $cflags $cppflags $flag conftest.c >&5"
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    cc_works_part=yes
+    if test "$cross_compiling" = no; then
+      if { ac_try='./a.out || ./b.out || ./a.exe || ./a_out.exe || ./conftest'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :;
+      else
+        cc_works_part=norun
+      fi
+    fi
+  else
+    cc_works_part=no
+  fi
+  if test "$cc_works_part" != yes; then
+    echo "failed program was:" >&5
+    cat conftest.c >&5
+  fi
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  case $cc_works_part in
+    yes)
+      if test "$gmp_prog_cc_works" = yes; then
+  # remove anything that might look like compiler output to our "||" expression
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  cat >conftest.c <<EOF
+/* The following provokes an internal compiler error from Itanium HP-UX cc
+    under +O2 or higher.  We use this sort of code in mpn/generic/mul_fft.c. */
+int k;
+int foo ()
+{
+  int i, **a;
+  a = __builtin_alloca (k);
+  for (i = 0; i <= k; i++)
+    a[i] = __builtin_alloca (1 << i);
+}
+
+int main () { return 0; }
+EOF
+  echo "Test compile: alloca array" >&5
+  gmp_compile="$cc $cflags $cppflags $flag conftest.c >&5"
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    cc_works_part=yes
+    if test "$cross_compiling" = no; then
+      if { ac_try='./a.out || ./b.out || ./a.exe || ./a_out.exe || ./conftest'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :;
+      else
+        cc_works_part=norun
+      fi
+    fi
+  else
+    cc_works_part=no
+  fi
+  if test "$cc_works_part" != yes; then
+    echo "failed program was:" >&5
+    cat conftest.c >&5
+  fi
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  case $cc_works_part in
+    yes)
+
+      ;;
+    no)
+      gmp_prog_cc_works="no, alloca array"
+      ;;
+    norun)
+      gmp_prog_cc_works="no, alloca array, program does not run"
+      ;;
+  esac
+fi
+
+
+
+      ;;
+    no)
+
+      ;;
+    norun)
+
+      ;;
+  esac
+fi
+
+
+if test "$gmp_prog_cc_works" = yes; then
+  # remove anything that might look like compiler output to our "||" expression
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  cat >conftest.c <<EOF
+/* The following provokes an internal error from the assembler on
+   power2-ibm-aix4.3.1.0.  gcc -mrios2 compiles to nabs+fcirz, and this
+   results in "Internal error related to the source program domain".
+
+   For reference it seems to be the combination of nabs+fcirz which is bad,
+   not either alone.  This sort of thing occurs in mpz/get_str.c with the
+   way double chars_per_bit_exactly is applied in MPN_SIZEINBASE.  Perhaps
+   if that code changes to a scaled-integer style then we won't need this
+   test.  */
+
+double fp[1];
+int x;
+int f ()
+{
+  int a;
+  a = (x >= 0 ? x : -x);
+  return a * fp[0];
+}
+
+int main () { return 0; }
+EOF
+  echo "Test compile: abs int -> double conversion" >&5
+  gmp_compile="$cc $cflags $cppflags $flag conftest.c >&5"
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    cc_works_part=yes
+    if test "$cross_compiling" = no; then
+      if { ac_try='./a.out || ./b.out || ./a.exe || ./a_out.exe || ./conftest'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :;
+      else
+        cc_works_part=norun
+      fi
+    fi
+  else
+    cc_works_part=no
+  fi
+  if test "$cc_works_part" != yes; then
+    echo "failed program was:" >&5
+    cat conftest.c >&5
+  fi
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  case $cc_works_part in
+    yes)
+
+      ;;
+    no)
+      gmp_prog_cc_works="no, abs int -> double conversion"
+      ;;
+    norun)
+      gmp_prog_cc_works="no, abs int -> double conversion, program does not run"
+      ;;
+  esac
+fi
+
+
+
+
+if test "$gmp_prog_cc_works" = yes; then
+  # remove anything that might look like compiler output to our "||" expression
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  cat >conftest.c <<EOF
+/* The following provokes a segfault in the compiler on powerpc-apple-darwin.
+   Extracted from tests/mpn/t-iord_u.c.  Causes Apple's gcc 3.3 build 1640 and
+   1666 to segfault with e.g., -O2 -mpowerpc64.  */
+
+#if defined (__GNUC__) && ! defined (__cplusplus)
+typedef unsigned long long t1;typedef t1*t2;
+void g(){}
+void h(){}
+static __inline__ t1 e(t2 rp,t2 up,int n,t1 v0)
+{t1 c,x,r;int i;if(v0){c=1;for(i=1;i<n;i++){x=up[i];r=x+1;rp[i]=r;}}return c;}
+void f(){static const struct{t1 n;t1 src[9];t1 want[9];}d[]={{1,{0},{1}},};t1 got[9];int i;
+for(i=0;i<1;i++){if(e(got,got,9,d[i].n)==0)h();g(i,d[i].src,d[i].n,got,d[i].want,9);if(d[i].n)h();}}
+#else
+int dummy;
+#endif
+
+int main () { return 0; }
+EOF
+  echo "Test compile: long long reliability test 1" >&5
+  gmp_compile="$cc $cflags $cppflags $flag conftest.c >&5"
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    cc_works_part=yes
+    if test "$cross_compiling" = no; then
+      if { ac_try='./a.out || ./b.out || ./a.exe || ./a_out.exe || ./conftest'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :;
+      else
+        cc_works_part=norun
+      fi
+    fi
+  else
+    cc_works_part=no
+  fi
+  if test "$cc_works_part" != yes; then
+    echo "failed program was:" >&5
+    cat conftest.c >&5
+  fi
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  case $cc_works_part in
+    yes)
+
+      ;;
+    no)
+      gmp_prog_cc_works="no, long long reliability test 1"
+      ;;
+    norun)
+      gmp_prog_cc_works="no, long long reliability test 1, program does not run"
+      ;;
+  esac
+fi
+
+
+
+
+if test "$gmp_prog_cc_works" = yes; then
+  # remove anything that might look like compiler output to our "||" expression
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  cat >conftest.c <<EOF
+/* The following provokes an internal compiler error on powerpc-apple-darwin.
+   Extracted from mpz/cfdiv_q_2exp.c.  Causes Apple's gcc 3.3 build 1640 and
+   1666 to get an ICE with -O1 -mpowerpc64.  */
+
+#if defined (__GNUC__) && ! defined (__cplusplus)
+int g();
+void f(int u){int i;long long x;x=u?~0:0;if(x)for(i=0;i<9;i++);x&=g();if(x)g();}
+int g(){return 0;}
+#else
+int dummy;
+#endif
+
+int main () { return 0; }
+EOF
+  echo "Test compile: long long reliability test 2" >&5
+  gmp_compile="$cc $cflags $cppflags $flag conftest.c >&5"
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    cc_works_part=yes
+    if test "$cross_compiling" = no; then
+      if { ac_try='./a.out || ./b.out || ./a.exe || ./a_out.exe || ./conftest'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :;
+      else
+        cc_works_part=norun
+      fi
+    fi
+  else
+    cc_works_part=no
+  fi
+  if test "$cc_works_part" != yes; then
+    echo "failed program was:" >&5
+    cat conftest.c >&5
+  fi
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  case $cc_works_part in
+    yes)
+
+      ;;
+    no)
+      gmp_prog_cc_works="no, long long reliability test 2"
+      ;;
+    norun)
+      gmp_prog_cc_works="no, long long reliability test 2, program does not run"
+      ;;
+  esac
+fi
+
+
+
+
+if test "$gmp_prog_cc_works" = yes; then
+  # remove anything that might look like compiler output to our "||" expression
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  cat >conftest.c <<EOF
+/* Provokes an ICE on i386-freebsd with the FreeBSD-hacked gcc, under
+   -O2 -march=amdfam10.  We call helper functions here "open" and "close" in
+   order for linking to succeed.  */
+
+#if defined (__GNUC__) && ! defined (__cplusplus)
+int open(int*,int*,int);void*close(int);void g(int*rp,int*up,int un){
+__builtin_expect(un<=0x7f00,1)?__builtin_alloca(un):close(un);if(__builtin_clzl
+(up[un])){open(rp,up,un);while(1){if(rp[un-1]!=0)break;un--;}}}
+#else
+int dummy;
+#endif
+
+int main () { return 0; }
+EOF
+  echo "Test compile: freebsd hacked gcc" >&5
+  gmp_compile="$cc $cflags $cppflags $flag conftest.c >&5"
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    cc_works_part=yes
+    if test "$cross_compiling" = no; then
+      if { ac_try='./a.out || ./b.out || ./a.exe || ./a_out.exe || ./conftest'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :;
+      else
+        cc_works_part=norun
+      fi
+    fi
+  else
+    cc_works_part=no
+  fi
+  if test "$cc_works_part" != yes; then
+    echo "failed program was:" >&5
+    cat conftest.c >&5
+  fi
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  case $cc_works_part in
+    yes)
+
+      ;;
+    no)
+      gmp_prog_cc_works="no, freebsd hacked gcc"
+      ;;
+    norun)
+      gmp_prog_cc_works="no, freebsd hacked gcc, program does not run"
+      ;;
+  esac
+fi
+
+
+
+
+if test "$gmp_prog_cc_works" = yes; then
+  # remove anything that might look like compiler output to our "||" expression
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  cat >conftest.c <<EOF
+/* The following is mis-compiled by HP ia-64 cc version
+        cc: HP aC++/ANSI C B3910B A.05.55 [Dec 04 2003]
+   under "cc +O3", both in +DD32 and +DD64 modes.  The mpn_lshift_com gets
+   inlined and its return value somehow botched to be 0 instead of 1.  This
+   arises in the real mpn_lshift_com in mul_fft.c.  A lower optimization
+   level, like +O2 seems ok.  This code needs to be run to show the problem,
+   but that's fine, the offending cc is a native-only compiler so we don't
+   have to worry about cross compiling.  */
+
+#if ! defined (__cplusplus)
+unsigned long
+lshift_com (rp, up, n, cnt)
+  unsigned long *rp;
+  unsigned long *up;
+  long n;
+  unsigned cnt;
+{
+  unsigned long retval, high_limb, low_limb;
+  unsigned tnc;
+  long i;
+  tnc = 8 * sizeof (unsigned long) - cnt;
+  low_limb = *up++;
+  retval = low_limb >> tnc;
+  high_limb = low_limb << cnt;
+  for (i = n - 1; i != 0; i--)
+    {
+      low_limb = *up++;
+      *rp++ = ~(high_limb | (low_limb >> tnc));
+      high_limb = low_limb << cnt;
+    }
+  return retval;
+}
+int
+main ()
+{
+  unsigned long cy, rp[2], up[2];
+  up[0] = ~ 0L;
+  up[1] = 0;
+  cy = lshift_com (rp, up, 2L, 1);
+  if (cy != 1L)
+    return 1;
+  return 0;
+}
+#else
+int
+main ()
+{
+  return 0;
+}
+#endif
+
+EOF
+  echo "Test compile: mpn_lshift_com optimization" >&5
+  gmp_compile="$cc $cflags $cppflags $flag conftest.c >&5"
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    cc_works_part=yes
+    if test "$cross_compiling" = no; then
+      if { ac_try='./a.out || ./b.out || ./a.exe || ./a_out.exe || ./conftest'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :;
+      else
+        cc_works_part=norun
+      fi
+    fi
+  else
+    cc_works_part=no
+  fi
+  if test "$cc_works_part" != yes; then
+    echo "failed program was:" >&5
+    cat conftest.c >&5
+  fi
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  case $cc_works_part in
+    yes)
+
+      ;;
+    no)
+      gmp_prog_cc_works="no, mpn_lshift_com optimization"
+      ;;
+    norun)
+      gmp_prog_cc_works="no, mpn_lshift_com optimization, program does not run"
+      ;;
+  esac
+fi
+
+
+
+if test "$gmp_prog_cc_works" = yes; then
+  # remove anything that might look like compiler output to our "||" expression
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  cat >conftest.c <<EOF
+/* The following is mis-compiled by Intel ia-64 icc version 1.8 under
+    "icc -O3",  After several calls, the function writes partial garbage to
+    the result vector.  Perhaps relates to the chk.a.nc insn.  This code needs
+    to be run to show the problem, but that's fine, the offending cc is a
+    native-only compiler so we don't have to worry about cross compiling.  */
+
+#if ! defined (__cplusplus)
+#include <stdlib.h>
+void
+lshift_com (rp, up, n, cnt)
+  unsigned long *rp;
+  unsigned long *up;
+  long n;
+  unsigned cnt;
+{
+  unsigned long high_limb, low_limb;
+  unsigned tnc;
+  long i;
+  up += n;
+  rp += n;
+  tnc = 8 * sizeof (unsigned long) - cnt;
+  low_limb = *--up;
+  high_limb = low_limb << cnt;
+  for (i = n - 1; i != 0; i--)
+    {
+      low_limb = *--up;
+      *--rp = ~(high_limb | (low_limb >> tnc));
+      high_limb = low_limb << cnt;
+    }
+  *--rp = ~high_limb;
+}
+int
+main ()
+{
+  unsigned long *r, *r2;
+  unsigned long a[88 + 1];
+  long i;
+  for (i = 0; i < 88 + 1; i++)
+    a[i] = ~0L;
+  r = calloc (10000, sizeof (unsigned long));
+  r2 = r;
+  for (i = 0; i < 528; i += 23)
+    {
+      lshift_com (r2, a,
+		  i / (8 * sizeof (unsigned long)) + 1,
+		  i % (8 * sizeof (unsigned long)));
+      r2 += 88 + 1;
+    }
+  if (r[2048] != 0 || r[2049] != 0 || r[2050] != 0 || r[2051] != 0 ||
+      r[2052] != 0 || r[2053] != 0 || r[2054] != 0)
+    abort ();
+  free (r);
+  return 0;
+}
+#else
+int
+main ()
+{
+  return 0;
+}
+#endif
+
+EOF
+  echo "Test compile: mpn_lshift_com optimization 2" >&5
+  gmp_compile="$cc $cflags $cppflags $flag conftest.c >&5"
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    cc_works_part=yes
+    if test "$cross_compiling" = no; then
+      if { ac_try='./a.out || ./b.out || ./a.exe || ./a_out.exe || ./conftest'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :;
+      else
+        cc_works_part=norun
+      fi
+    fi
+  else
+    cc_works_part=no
+  fi
+  if test "$cc_works_part" != yes; then
+    echo "failed program was:" >&5
+    cat conftest.c >&5
+  fi
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  case $cc_works_part in
+    yes)
+
+      ;;
+    no)
+      gmp_prog_cc_works="no, mpn_lshift_com optimization 2"
+      ;;
+    norun)
+      gmp_prog_cc_works="no, mpn_lshift_com optimization 2, program does not run"
+      ;;
+  esac
+fi
+
+
+
+
+# A certain _GLOBAL_OFFSET_TABLE_ problem in past versions of gas, tickled
+# by recent versions of gcc.
+#
+if test "$gmp_prog_cc_works" = yes; then
+  case $host in
+    i?86*-*-* | k[5-8]*-*-* | pentium*-*-* | athlon-*-* | viac3*-*-* | geode*-*-* | atom-*-*)
+      # this problem only arises in PIC code, so don't need to test when
+      # --disable-shared.  We don't necessarily have $enable_shared set to
+      # yes at this point, it will still be unset for the default (which is
+      # yes); hence the use of "!= no".
+      if test "$enable_shared" != no; then
+        echo "Testing gcc GOT with eax emitted" >&5
+cat >conftest.c <<\EOF
+int foo;
+int bar () { return foo; }
+EOF
+tmp_got_emitted=no
+gmp_compile="$cc $cflags $cppflags $flag -fPIC -S conftest.c >&5 2>&1"
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  if grep "addl.*_GLOBAL_OFFSET_TABLE_.*eax" conftest.s >/dev/null; then
+    tmp_got_emitted=yes
+  fi
+fi
+rm -f conftest.*
+echo "Result: $tmp_got_emitted" >&5
+if test "$tmp_got_emitted" = yes; then
+  echo "Testing gas GOT with eax good" >&5
+cat >conftest.awk <<\EOF
+BEGIN {
+  want[0]  = "001"
+  want[1]  = "043"
+  want[2]  = "105"
+  want[3]  = "147"
+  want[4]  = "211"
+  want[5]  = "253"
+  want[6]  = "315"
+  want[7]  = "357"
+
+  want[8]  = "005"
+  want[9]  = "002"
+  want[10] = "000"
+  want[11] = "000"
+  want[12] = "000"
+
+  want[13] = "376"
+  want[14] = "334"
+  want[15] = "272"
+  want[16] = "230"
+  want[17] = "166"
+  want[18] = "124"
+  want[19] = "062"
+  want[20] = "020"
+
+  result = "yes"
+}
+{
+  for (f = 2; f <= NF; f++)
+    {
+      for (i = 0; i < 20; i++)
+        got[i] = got[i+1];
+      got[20] = $f;
+
+      found = 1
+      for (i = 0; i < 21; i++)
+        if (got[i] != want[i])
+          {
+            found = 0
+            break
+          }
+      if (found)
+        {
+          result = "no"
+          exit
+        }
+    }
+}
+END {
+  print result
+}
+EOF
+cat >conftest.s <<\EOF
+	.text
+	.byte	1, 35, 69, 103, 137, 171, 205, 239
+	addl	$_GLOBAL_OFFSET_TABLE_, %eax
+	.byte	254, 220, 186, 152, 118, 84, 50, 16
+EOF
+tmp_got_good=yes
+gmp_compile="$cc $cflags $cppflags $flag -fPIC -o conftest.o -c conftest.s >&5 2>&1"
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  tmp_got_good=`od -b conftest.o | $AWK -f conftest.awk`
+fi
+rm -f conftest.*
+echo "Result: $tmp_got_good" >&5
+if test "$tmp_got_good" = no; then
+  gmp_prog_cc_works="no, bad gas GOT with eax"
+else
+  :
+fi
+
+else
+  :
+fi
+
+      fi
+      ;;
+  esac
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_prog_cc_works" >&5
+$as_echo "$gmp_prog_cc_works" >&6; }
+case $gmp_prog_cc_works in
+  yes)
+    cflags="$cflags $flag"
+          break
+    ;;
+  *)
+
+    ;;
+esac
+
+      done
+    done
+  fi
+
+  ABI="$abi"
+  CC="$cc"
+  CFLAGS="$cflags"
+  CPPFLAGS="$cppflags"
+
+  # Could easily have this in config.h too, if desired.
+  ABI_nodots=`echo $ABI | sed 's/\./_/'`
+
+echo "define_not_for_expansion(\`HAVE_ABI_$ABI_nodots')" >> $gmp_tmpconfigm4p
+
+
+  eval GMP_NONSTD_ABI=\"\$GMP_NONSTD_ABI_$ABI_nodots\"
+
+  # GMP_LDFLAGS substitution, selected according to ABI.
+  # These are needed on libgmp.la and libmp.la, but currently not on
+  # convenience libraries like tune/libspeed.la or mpz/libmpz.la.
+  #
+                            eval GMP_LDFLAGS=\"\$${ccbase}${abi1}_ldflags\"
+  test -n "$GMP_LDFLAGS" || eval GMP_LDFLAGS=\"\$${ccbase}${abi1}_ldflags\"
+
+
+
+
+  # extra_functions, selected according to ABI
+                    eval tmp=\"\$extra_functions$abi1\"
+  test -n "$tmp" || eval tmp=\"\$extra_functions$abi2\"
+  extra_functions="$tmp"
+
+
+  # Cycle counter, selected according to ABI.
+  #
+                    eval tmp=\"\$SPEED_CYCLECOUNTER_OBJ$abi1\"
+  test -n "$tmp" || eval tmp=\"\$SPEED_CYCLECOUNTER_OBJ$abi2\"
+  SPEED_CYCLECOUNTER_OBJ="$tmp"
+                    eval tmp=\"\$cyclecounter_size$abi1\"
+  test -n "$tmp" || eval tmp=\"\$cyclecounter_size$abi2\"
+  cyclecounter_size="$tmp"
+
+  if test -n "$SPEED_CYCLECOUNTER_OBJ"; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_SPEED_CYCLECOUNTER $cyclecounter_size
+_ACEOF
+
+  fi
+
+
+
+  # Calling conventions checking, selected according to ABI.
+  #
+                    eval tmp=\"\$CALLING_CONVENTIONS_OBJS$abi1\"
+  test -n "$tmp" || eval tmp=\"\$CALLING_CONVENTIONS_OBJS$abi2\"
+  if test "$enable_assembly" = "yes"; then
+     CALLING_CONVENTIONS_OBJS="$tmp"
+  else
+     CALLING_CONVENTIONS_OBJS=""
+  fi
+
+  if test -n "$CALLING_CONVENTIONS_OBJS"; then
+
+$as_echo "#define HAVE_CALLING_CONVENTIONS 1" >>confdefs.h
+
+  fi
+
+
+fi
+
+
+# If the user gave an MPN_PATH, use that verbatim, otherwise choose
+# according to the ABI and add "generic".
+#
+if test -n "$MPN_PATH"; then
+  path="$MPN_PATH"
+else
+                    eval tmp=\"\$path$abi1\"
+  test -n "$tmp" || eval tmp=\"\$path$abi2\"
+  path="$tmp generic"
+fi
+
+
+# Long long limb setup for gmp.h.
+case $limb_chosen in
+longlong) DEFN_LONG_LONG_LIMB="#define _LONG_LONG_LIMB 1"    ;;
+*)        DEFN_LONG_LONG_LIMB="/* #undef _LONG_LONG_LIMB */" ;;
+esac
+
+
+
+# The C compiler and preprocessor, put into ANSI mode if possible.
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="${ac_tool_prefix}gcc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+  ac_ct_CC=$CC
+  # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="gcc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+else
+  CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+          if test -n "$ac_tool_prefix"; then
+    # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="${ac_tool_prefix}cc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  fi
+fi
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+       ac_prog_rejected=yes
+       continue
+     fi
+    ac_cv_prog_CC="cc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# != 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+  fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  for ac_prog in cl.exe
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$CC" && break
+  done
+fi
+if test -z "$CC"; then
+  ac_ct_CC=$CC
+  for ac_prog in cl.exe
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_CC" && break
+done
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+  { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    sed '10a\
+... rest of stderr output deleted ...
+         10q' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+  fi
+  rm -f conftest.er1 conftest.err
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+    * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+  esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link_default") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile.  We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+	;;
+    [ab].out )
+	# We found the default executable, but exeext='' is most
+	# certainly right.
+	break;;
+    *.* )
+	if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+	then :; else
+	   ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+	fi
+	# We set ac_cv_exeext here because the later test for it is not
+	# safe: cross compilers may not add the suffix if given an `-o'
+	# argument, so we may need to know it at that point already.
+	# Even if this section looks crufty: it has the advantage of
+	# actually working.
+	break;;
+    * )
+	break;;
+  esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+  ac_file=''
+fi
+if test -z "$ac_file"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'.  For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+    *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+	  break;;
+    * ) break;;
+  esac
+done
+else
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+  { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+  if { ac_try='./conftest$ac_cv_exeext'
+  { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then
+    cross_compiling=no
+  else
+    if test "$cross_compiling" = maybe; then
+	cross_compiling=yes
+    else
+	{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+    fi
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  for ac_file in conftest.o conftest.obj conftest.*; do
+  test -f "$ac_file" || continue;
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+    *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+       break;;
+  esac
+done
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_compiler_gnu=yes
+else
+  ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+  GCC=yes
+else
+  GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_save_c_werror_flag=$ac_c_werror_flag
+   ac_c_werror_flag=yes
+   ac_cv_prog_cc_g=no
+   CFLAGS="-g"
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
+else
+  CFLAGS=""
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+  ac_c_werror_flag=$ac_save_c_werror_flag
+	 CFLAGS="-g"
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdarg.h>
+#include <stdio.h>
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+     char **p;
+     int i;
+{
+  return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+  char *s;
+  va_list v;
+  va_start (v,p);
+  s = g (p, va_arg (v,int));
+  va_end (v);
+  return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
+   function prototypes and stuff, but not '\xHH' hex character constants.
+   These don't provoke an error unfortunately, instead are silently treated
+   as 'x'.  The following induces an error, until -std is added to get
+   proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an
+   array size at least.  It's necessary to write '\x00'==0 to get something
+   that's true only with -std.  */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+   inside strings and character constants.  */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
+  ;
+  return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+	-Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+  CC="$ac_save_CC $ac_arg"
+  if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+  test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+  x)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+  xno)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+  *)
+    CC="$CC $ac_cv_prog_cc_c89"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5
+$as_echo_n "checking whether $CC understands -c and -o together... " >&6; }
+if ${am_cv_prog_cc_c_o+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+  # Make sure it works both with $CC and with simple cc.
+  # Following AC_PROG_CC_C_O, we do the test twice because some
+  # compilers refuse to overwrite an existing .o file with -o,
+  # though they will create one.
+  am_cv_prog_cc_c_o=yes
+  for am_i in 1 2; do
+    if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5
+   ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5
+   ac_status=$?
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   (exit $ac_status); } \
+         && test -f conftest2.$ac_objext; then
+      : OK
+    else
+      am_cv_prog_cc_c_o=no
+      break
+    fi
+  done
+  rm -f core conftest*
+  unset am_i
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5
+$as_echo "$am_cv_prog_cc_c_o" >&6; }
+if test "$am_cv_prog_cc_c_o" != yes; then
+   # Losing compiler, so override with the script.
+   # FIXME: It is wrong to rewrite CC.
+   # But if we don't then we get into trouble of one sort or another.
+   # A longer-term fix would be to have automake use am__CC in this case,
+   # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
+   CC="$am_aux_dir/compile $CC"
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+   { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C99" >&5
+$as_echo_n "checking for $CC option to accept ISO C99... " >&6; }
+if ${ac_cv_prog_cc_c99+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_prog_cc_c99=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include <stdio.h>
+
+// Check varargs macros.  These examples are taken from C99 6.10.3.5.
+#define debug(...) fprintf (stderr, __VA_ARGS__)
+#define showlist(...) puts (#__VA_ARGS__)
+#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__))
+static void
+test_varargs_macros (void)
+{
+  int x = 1234;
+  int y = 5678;
+  debug ("Flag");
+  debug ("X = %d\n", x);
+  showlist (The first, second, and third items.);
+  report (x>y, "x is %d but y is %d", x, y);
+}
+
+// Check long long types.
+#define BIG64 18446744073709551615ull
+#define BIG32 4294967295ul
+#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0)
+#if !BIG_OK
+  your preprocessor is broken;
+#endif
+#if BIG_OK
+#else
+  your preprocessor is broken;
+#endif
+static long long int bignum = -9223372036854775807LL;
+static unsigned long long int ubignum = BIG64;
+
+struct incomplete_array
+{
+  int datasize;
+  double data[];
+};
+
+struct named_init {
+  int number;
+  const wchar_t *name;
+  double average;
+};
+
+typedef const char *ccp;
+
+static inline int
+test_restrict (ccp restrict text)
+{
+  // See if C++-style comments work.
+  // Iterate through items via the restricted pointer.
+  // Also check for declarations in for loops.
+  for (unsigned int i = 0; *(text+i) != '\0'; ++i)
+    continue;
+  return 0;
+}
+
+// Check varargs and va_copy.
+static void
+test_varargs (const char *format, ...)
+{
+  va_list args;
+  va_start (args, format);
+  va_list args_copy;
+  va_copy (args_copy, args);
+
+  const char *str;
+  int number;
+  float fnumber;
+
+  while (*format)
+    {
+      switch (*format++)
+	{
+	case 's': // string
+	  str = va_arg (args_copy, const char *);
+	  break;
+	case 'd': // int
+	  number = va_arg (args_copy, int);
+	  break;
+	case 'f': // float
+	  fnumber = va_arg (args_copy, double);
+	  break;
+	default:
+	  break;
+	}
+    }
+  va_end (args_copy);
+  va_end (args);
+}
+
+int
+main ()
+{
+
+  // Check bool.
+  _Bool success = false;
+
+  // Check restrict.
+  if (test_restrict ("String literal") == 0)
+    success = true;
+  char *restrict newvar = "Another string";
+
+  // Check varargs.
+  test_varargs ("s, d' f .", "string", 65, 34.234);
+  test_varargs_macros ();
+
+  // Check flexible array members.
+  struct incomplete_array *ia =
+    malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10));
+  ia->datasize = 10;
+  for (int i = 0; i < ia->datasize; ++i)
+    ia->data[i] = i * 1.234;
+
+  // Check named initializers.
+  struct named_init ni = {
+    .number = 34,
+    .name = L"Test wide string",
+    .average = 543.34343,
+  };
+
+  ni.number = 58;
+
+  int dynamic_array[ni.number];
+  dynamic_array[ni.number - 1] = 543;
+
+  // work around unused variable warnings
+  return (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == 'x'
+	  || dynamic_array[ni.number - 1] != 543);
+
+  ;
+  return 0;
+}
+_ACEOF
+for ac_arg in '' -std=gnu99 -std=c99 -c99 -AC99 -D_STDC_C99= -qlanglvl=extc99
+do
+  CC="$ac_save_CC $ac_arg"
+  if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_c99=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+  test "x$ac_cv_prog_cc_c99" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c99" in
+  x)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+  xno)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+  *)
+    CC="$CC $ac_cv_prog_cc_c99"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5
+$as_echo "$ac_cv_prog_cc_c99" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c99" != xno; then :
+
+fi
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+  if ${ac_cv_prog_CPP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+      # Double quotes because CPP needs to be expanded
+    for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+    do
+      ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+  break
+fi
+
+    done
+    ac_cv_prog_CPP=$CPP
+
+fi
+  CPP=$ac_cv_prog_CPP
+else
+  ac_cv_prog_CPP=$CPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+#if test "$ac_cv_prog_cc_c99" = no; then
+#  AC_MSG_ERROR([Cannot find a C99 capable compiler])
+#fi
+
+# The C compiler on the build system, and associated tests.
+
+if test -n "$CC_FOR_BUILD"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking build system compiler $CC_FOR_BUILD" >&5
+$as_echo_n "checking build system compiler $CC_FOR_BUILD... " >&6; }
+# remove anything that might look like compiler output to our "||" expression
+rm -f conftest* a.out b.out a.exe a_out.exe
+cat >conftest.c <<EOF
+int
+main ()
+{
+  return 0;
+}
+EOF
+gmp_compile="$CC_FOR_BUILD conftest.c"
+cc_for_build_works=no
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  if (./a.out || ./b.out || ./a.exe || ./a_out.exe || ./conftest) >&5 2>&1; then
+    cc_for_build_works=yes
+  fi
+fi
+rm -f conftest* a.out b.out a.exe a_out.exe
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cc_for_build_works" >&5
+$as_echo "$cc_for_build_works" >&6; }
+if test "$cc_for_build_works" = yes; then
+  :
+else
+  as_fn_error $? "Specified CC_FOR_BUILD doesn't seem to work" "$LINENO" 5
+fi
+
+elif test -n "$HOST_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking build system compiler $HOST_CC" >&5
+$as_echo_n "checking build system compiler $HOST_CC... " >&6; }
+# remove anything that might look like compiler output to our "||" expression
+rm -f conftest* a.out b.out a.exe a_out.exe
+cat >conftest.c <<EOF
+int
+main ()
+{
+  return 0;
+}
+EOF
+gmp_compile="$HOST_CC conftest.c"
+cc_for_build_works=no
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  if (./a.out || ./b.out || ./a.exe || ./a_out.exe || ./conftest) >&5 2>&1; then
+    cc_for_build_works=yes
+  fi
+fi
+rm -f conftest* a.out b.out a.exe a_out.exe
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cc_for_build_works" >&5
+$as_echo "$cc_for_build_works" >&6; }
+if test "$cc_for_build_works" = yes; then
+  CC_FOR_BUILD=$HOST_CC
+else
+  as_fn_error $? "Specified HOST_CC doesn't seem to work" "$LINENO" 5
+fi
+
+else
+  for i in "$CC" "$CC $CFLAGS $CPPFLAGS" cc gcc c89 c99; do
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking build system compiler $i" >&5
+$as_echo_n "checking build system compiler $i... " >&6; }
+# remove anything that might look like compiler output to our "||" expression
+rm -f conftest* a.out b.out a.exe a_out.exe
+cat >conftest.c <<EOF
+int
+main ()
+{
+  return 0;
+}
+EOF
+gmp_compile="$i conftest.c"
+cc_for_build_works=no
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  if (./a.out || ./b.out || ./a.exe || ./a_out.exe || ./conftest) >&5 2>&1; then
+    cc_for_build_works=yes
+  fi
+fi
+rm -f conftest* a.out b.out a.exe a_out.exe
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cc_for_build_works" >&5
+$as_echo "$cc_for_build_works" >&6; }
+if test "$cc_for_build_works" = yes; then
+  CC_FOR_BUILD=$i
+       break
+else
+  :
+fi
+
+  done
+  if test -z "$CC_FOR_BUILD"; then
+    as_fn_error $? "Cannot find a build system compiler" "$LINENO" 5
+  fi
+fi
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for build system preprocessor" >&5
+$as_echo_n "checking for build system preprocessor... " >&6; }
+if test -z "$CPP_FOR_BUILD"; then
+  if ${gmp_cv_prog_cpp_for_build+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.c <<EOF
+#define FOO BAR
+EOF
+  for i in "$CC_FOR_BUILD -E" "$CC_FOR_BUILD -E -traditional-cpp" "/lib/cpp"; do
+    gmp_compile="$i conftest.c"
+    if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } >&5 2>&1; then
+      gmp_cv_prog_cpp_for_build=$i
+      break
+    fi
+  done
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  if test -z "$gmp_cv_prog_cpp_for_build"; then
+    as_fn_error $? "Cannot find build system C preprocessor." "$LINENO" 5
+  fi
+
+fi
+
+  CPP_FOR_BUILD=$gmp_cv_prog_cpp_for_build
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP_FOR_BUILD" >&5
+$as_echo "$CPP_FOR_BUILD" >&6; }
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for build system executable suffix" >&5
+$as_echo_n "checking for build system executable suffix... " >&6; }
+if ${gmp_cv_prog_exeext_for_build+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.c <<EOF
+int
+main ()
+{
+  return 0;
+}
+EOF
+for i in .exe ,ff8 ""; do
+  gmp_compile="$CC_FOR_BUILD conftest.c -o conftest$i"
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    if (./conftest) 2>&5; then
+      gmp_cv_prog_exeext_for_build=$i
+      break
+    fi
+  fi
+done
+rm -f conftest*
+if test "${gmp_cv_prog_exeext_for_build+set}" != set; then
+  as_fn_error $? "Cannot determine executable suffix" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_cv_prog_exeext_for_build" >&5
+$as_echo "$gmp_cv_prog_exeext_for_build" >&6; }
+EXEEXT_FOR_BUILD=$gmp_cv_prog_exeext_for_build
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build system compiler is ANSI" >&5
+$as_echo_n "checking whether build system compiler is ANSI... " >&6; }
+if ${gmp_cv_c_for_build_ansi+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.c <<EOF
+int
+main (int argc, char **argv)
+{
+  return 0;
+}
+EOF
+gmp_compile="$CC_FOR_BUILD conftest.c"
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  gmp_cv_c_for_build_ansi=yes
+else
+  gmp_cv_c_for_build_ansi=no
+fi
+rm -f conftest* a.out b.out a.exe a_out.exe
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_cv_c_for_build_ansi" >&5
+$as_echo "$gmp_cv_c_for_build_ansi" >&6; }
+if test "$gmp_cv_c_for_build_ansi" = yes; then
+  U_FOR_BUILD=
+else
+  U_FOR_BUILD=_
+
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for build system compiler math library" >&5
+$as_echo_n "checking for build system compiler math library... " >&6; }
+if ${gmp_cv_check_libm_for_build+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.c <<EOF
+#include <math.h>
+int
+main ()
+{
+  return 0;
+}
+double d;
+double
+foo ()
+{
+  return log (d);
+}
+EOF
+gmp_compile="$CC_FOR_BUILD conftest.c -lm"
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  gmp_cv_check_libm_for_build=-lm
+else
+  gmp_cv_check_libm_for_build=no
+fi
+rm -f conftest* a.out b.out a.exe a_out.exe
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_cv_check_libm_for_build" >&5
+$as_echo "$gmp_cv_check_libm_for_build" >&6; }
+case $gmp_cv_check_libm_for_build in
+  yes) LIBM_FOR_BUILD=-lm
+ ;;
+  no)  LIBM_FOR_BUILD= ;;
+  *)   LIBM_FOR_BUILD=$gmp_cv_check_libm_for_build ;;
+esac
+
+
+
+# How to assemble, used with CFLAGS etc, see mpn/Makeasm.am.
+# Using the compiler is a lot easier than figuring out how to invoke the
+# assembler directly.
+#
+test -n "$CCAS" || CCAS="$CC -c"
+
+
+
+# The C++ compiler, if desired.
+want_cxx=no
+if test $enable_cxx != no; then
+  test_CXXFLAGS=${CXXFLAGS+set}
+  ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+if test -z "$CXX"; then
+  if test -n "$CCC"; then
+    CXX=$CCC
+  else
+    if test -n "$ac_tool_prefix"; then
+  for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CXX+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CXX"; then
+  ac_cv_prog_CXX="$CXX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CXX="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CXX=$ac_cv_prog_CXX
+if test -n "$CXX"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5
+$as_echo "$CXX" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$CXX" && break
+  done
+fi
+if test -z "$CXX"; then
+  ac_ct_CXX=$CXX
+  for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CXX+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CXX"; then
+  ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CXX="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CXX=$ac_cv_prog_ac_ct_CXX
+if test -n "$ac_ct_CXX"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5
+$as_echo "$ac_ct_CXX" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_CXX" && break
+done
+
+  if test "x$ac_ct_CXX" = x; then
+    CXX="g++"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CXX=$ac_ct_CXX
+  fi
+fi
+
+  fi
+fi
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+  { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    sed '10a\
+... rest of stderr output deleted ...
+         10q' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+  fi
+  rm -f conftest.er1 conftest.err
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5
+$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; }
+if ${ac_cv_cxx_compiler_gnu+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  ac_compiler_gnu=yes
+else
+  ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_cxx_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5
+$as_echo "$ac_cv_cxx_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+  GXX=yes
+else
+  GXX=
+fi
+ac_test_CXXFLAGS=${CXXFLAGS+set}
+ac_save_CXXFLAGS=$CXXFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5
+$as_echo_n "checking whether $CXX accepts -g... " >&6; }
+if ${ac_cv_prog_cxx_g+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_save_cxx_werror_flag=$ac_cxx_werror_flag
+   ac_cxx_werror_flag=yes
+   ac_cv_prog_cxx_g=no
+   CXXFLAGS="-g"
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  ac_cv_prog_cxx_g=yes
+else
+  CXXFLAGS=""
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+
+else
+  ac_cxx_werror_flag=$ac_save_cxx_werror_flag
+	 CXXFLAGS="-g"
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  ac_cv_prog_cxx_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_cxx_werror_flag=$ac_save_cxx_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5
+$as_echo "$ac_cv_prog_cxx_g" >&6; }
+if test "$ac_test_CXXFLAGS" = set; then
+  CXXFLAGS=$ac_save_CXXFLAGS
+elif test $ac_cv_prog_cxx_g = yes; then
+  if test "$GXX" = yes; then
+    CXXFLAGS="-g -O2"
+  else
+    CXXFLAGS="-g"
+  fi
+else
+  if test "$GXX" = yes; then
+    CXXFLAGS="-O2"
+  else
+    CXXFLAGS=
+  fi
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+  echo "CXXFLAGS chosen by autoconf: $CXXFLAGS" >&5
+  cxxflags_ac_prog_cxx=$CXXFLAGS
+  cxxflags_list=ac_prog_cxx
+
+  # If the user didn't specify $CXXFLAGS, then try $CFLAGS, with -g removed
+  # if AC_PROG_CXX thinks that doesn't work.  $CFLAGS stands a good chance
+  # of working, eg. on a GNU system where CC=gcc and CXX=g++.
+  #
+  if test "$test_CXXFLAGS" != set; then
+    cxxflags_cflags=$CFLAGS
+    cxxflags_list="cflags $cxxflags_list"
+    if test "$ac_prog_cxx_g" = no; then
+      cxxflags_cflags=`echo "$cxxflags_cflags" | sed -e 's/ -g //' -e 's/^-g //' -e 's/ -g$//'`
+    fi
+  fi
+
+  # See if the C++ compiler works.  If the user specified CXXFLAGS then all
+  # we're doing is checking whether AC_PROG_CXX succeeded, since it doesn't
+  # give a fatal error, just leaves CXX set to a default g++.  If on the
+  # other hand the user didn't specify CXXFLAGS then we get to try here our
+  # $cxxflags_list alternatives.
+  #
+  # Automake includes $CPPFLAGS in a C++ compile, so we do the same here.
+  #
+  for cxxflags_choice in $cxxflags_list; do
+    eval CXXFLAGS=\"\$cxxflags_$cxxflags_choice\"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking C++ compiler $CXX $CPPFLAGS $CXXFLAGS" >&5
+$as_echo_n "checking C++ compiler $CXX $CPPFLAGS $CXXFLAGS... " >&6; }
+gmp_prog_cxx_works=yes
+
+# start with a plain "main()", then go on to further checks
+if test "$gmp_prog_cxx_works" = yes; then
+  # remove anything that might look like compiler output to our "||" expression
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  cat >conftest.cc <<EOF
+
+int main (void) { return 0; }
+EOF
+  echo "Test compile: " >&5
+  gmp_cxxcompile="$CXX $CPPFLAGS $CXXFLAGS conftest.cc >&5"
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_cxxcompile\""; } >&5
+  (eval $gmp_cxxcompile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    if test "$cross_compiling" = no; then
+      if { ac_try='./a.out || ./b.out || ./a.exe || ./a_out.exe || ./conftest'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :;
+      else
+        gmp_prog_cxx_works="no, program does not run"
+      fi
+    fi
+  else
+    gmp_prog_cxx_works="no"
+  fi
+  case $gmp_prog_cxx_works in
+    no*)
+      echo "failed program was:" >&5
+      cat conftest.cc >&5
+      ;;
+  esac
+  rm -f conftest* a.out b.out a.exe a_out.exe
+fi
+
+
+if test "$gmp_prog_cxx_works" = yes; then
+  # remove anything that might look like compiler output to our "||" expression
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  cat >conftest.cc <<EOF
+namespace foo { }
+using namespace foo;
+
+int main (void) { return 0; }
+EOF
+  echo "Test compile: namespace" >&5
+  gmp_cxxcompile="$CXX $CPPFLAGS $CXXFLAGS conftest.cc >&5"
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_cxxcompile\""; } >&5
+  (eval $gmp_cxxcompile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    if test "$cross_compiling" = no; then
+      if { ac_try='./a.out || ./b.out || ./a.exe || ./a_out.exe || ./conftest'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :;
+      else
+        gmp_prog_cxx_works="no, namespace, program does not run"
+      fi
+    fi
+  else
+    gmp_prog_cxx_works="no, namespace"
+  fi
+  case $gmp_prog_cxx_works in
+    no*)
+      echo "failed program was:" >&5
+      cat conftest.cc >&5
+      ;;
+  esac
+  rm -f conftest* a.out b.out a.exe a_out.exe
+fi
+
+
+# GMP requires the standard C++ iostream classes
+if test "$gmp_prog_cxx_works" = yes; then
+  # remove anything that might look like compiler output to our "||" expression
+  rm -f conftest* a.out b.out a.exe a_out.exe
+  cat >conftest.cc <<EOF
+/* This test rejects g++ 2.7.2 which doesn't have <iostream>, only a
+    pre-standard iostream.h. */
+#include <iostream>
+
+/* This test rejects OSF 5.1 Compaq C++ in its default pre-standard iostream
+   mode, since that mode puts cout in the global namespace, not "std".  */
+void someoutput (void) { std::cout << 123; }
+
+int main (void) { return 0; }
+EOF
+  echo "Test compile: std iostream" >&5
+  gmp_cxxcompile="$CXX $CPPFLAGS $CXXFLAGS conftest.cc >&5"
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_cxxcompile\""; } >&5
+  (eval $gmp_cxxcompile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    if test "$cross_compiling" = no; then
+      if { ac_try='./a.out || ./b.out || ./a.exe || ./a_out.exe || ./conftest'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :;
+      else
+        gmp_prog_cxx_works="no, std iostream, program does not run"
+      fi
+    fi
+  else
+    gmp_prog_cxx_works="no, std iostream"
+  fi
+  case $gmp_prog_cxx_works in
+    no*)
+      echo "failed program was:" >&5
+      cat conftest.cc >&5
+      ;;
+  esac
+  rm -f conftest* a.out b.out a.exe a_out.exe
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_prog_cxx_works" >&5
+$as_echo "$gmp_prog_cxx_works" >&6; }
+case $gmp_prog_cxx_works in
+  yes)
+    want_cxx=yes
+      break
+    ;;
+  *)
+
+    ;;
+esac
+
+  done
+
+  # If --enable-cxx=yes but a C++ compiler can't be found, then abort.
+  if test $want_cxx = no && test $enable_cxx = yes; then
+    as_fn_error $? "C++ compiler not available, see config.log for details" "$LINENO" 5
+  fi
+fi
+
+ if test $want_cxx = yes; then
+  WANT_CXX_TRUE=
+  WANT_CXX_FALSE='#'
+else
+  WANT_CXX_TRUE='#'
+  WANT_CXX_FALSE=
+fi
+
+
+# FIXME: We're not interested in CXXCPP for ourselves, but if we don't do it
+# here then AC_PROG_LIBTOOL will AC_REQUIRE it (via _LT_AC_TAGCONFIG) and
+# hence execute it unconditionally, and that will fail if there's no C++
+# compiler (and no generic /lib/cpp).
+#
+if test $want_cxx = yes; then
+  ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5
+$as_echo_n "checking how to run the C++ preprocessor... " >&6; }
+if test -z "$CXXCPP"; then
+  if ${ac_cv_prog_CXXCPP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+      # Double quotes because CXXCPP needs to be expanded
+    for CXXCPP in "$CXX -E" "/lib/cpp"
+    do
+      ac_preproc_ok=false
+for ac_cxx_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if ac_fn_cxx_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_cxx_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+  break
+fi
+
+    done
+    ac_cv_prog_CXXCPP=$CXXCPP
+
+fi
+  CXXCPP=$ac_cv_prog_CXXCPP
+else
+  ac_cv_prog_CXXCPP=$CXXCPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5
+$as_echo "$CXXCPP" >&6; }
+ac_preproc_ok=false
+for ac_cxx_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if ac_fn_cxx_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_cxx_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C++ preprocessor \"$CXXCPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+fi
+
+
+# Path setups for Cray, according to IEEE or CFP.  These must come after
+# deciding the compiler.
+#
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if ${ac_cv_path_GREP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$GREP"; then
+  ac_path_GREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in grep ggrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_GREP" || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+  # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'GREP' >> "conftest.nl"
+    "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_GREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_GREP="$ac_path_GREP"
+      ac_path_GREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_GREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_GREP"; then
+    as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if ${ac_cv_path_EGREP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+   then ac_cv_path_EGREP="$GREP -E"
+   else
+     if test -z "$EGREP"; then
+  ac_path_EGREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in egrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_EGREP" || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+  # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'EGREP' >> "conftest.nl"
+    "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_EGREP="$ac_path_EGREP"
+      ac_path_EGREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_EGREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_EGREP"; then
+    as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_EGREP=$EGREP
+fi
+
+   fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+case $host_cpu in
+  c90 | t90)
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef _CRAYIEEE
+yes
+#endif
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "yes" >/dev/null 2>&1; then :
+  add_path="cray/ieee"
+else
+  add_path="cray/cfp"; extra_functions="mulwwc90"
+fi
+rm -f conftest*
+
+    ;;
+  j90 | sv1)
+    add_path="cray/cfp"; extra_functions="mulwwj90"
+    ;;
+esac
+
+
+
+if test -z "$MPN_PATH"; then
+  path="$add_path $path"
+fi
+
+# For a nail build, also look in "nails" subdirectories.
+#
+if test $GMP_NAIL_BITS != 0 && test -z "$MPN_PATH"; then
+  new_path=
+  for i in $path; do
+    case $i in
+    generic) new_path="$new_path $i" ;;
+    *)       new_path="$new_path $i/nails $i" ;;
+    esac
+  done
+  path=$new_path
+fi
+
+
+# Put all directories into CPUVEC_list so as to get a full set of
+# CPUVEC_SETUP_$tmp_suffix defines into config.h, even if some of them are
+# empty because mmx and/or sse2 had to be dropped.
+#
+for i in $fat_path; do
+  tmp_suffix=`echo $i | sed -e '/\//s:^[^/]*/::' -e 's:[\\/]:_:g'`
+  CPUVEC_list="$CPUVEC_list CPUVEC_SETUP_$tmp_suffix"
+done
+
+
+# If there's any sse2 or mmx in the path, check whether the assembler
+# supports it, and remove if not.
+#
+# We only need this in ABI=32, for ABI=64 on x86_64 we can assume a new
+# enough assembler.
+#
+case $host in
+  i?86*-*-* | k[5-8]*-*-* | pentium*-*-* | athlon-*-* | viac3*-*-* | geode*-*-* | atom-*-* | athlon64-*-* | k8-*-* | k10-*-* | bobcat-*-* | jaguar*-*-* | bulldozer*-*-* | piledriver*-*-* | steamroller*-*-* | excavator*-*-* | zen*-*-* | pentium4-*-* | atom-*-* | silvermont-*-* | goldmont-*-* | core2-*-* | corei*-*-* | x86_64-*-* | nano-*-* | nehalem*-*-* | westmere*-*-* | sandybridge*-*-* | ivybridge*-*-* | haswell*-*-* | broadwell*-*-* | skylake*-*-* | kabylake*-*-*)
+    if test "$ABI" = 32; then
+      case "$path $fat_path" in
+        *mmx*)   { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the assembler knows about MMX instructions" >&5
+$as_echo_n "checking if the assembler knows about MMX instructions... " >&6; }
+if ${gmp_cv_asm_x86_mmx+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.s <<EOF
+	.text
+	movq	%mm0, %mm1
+EOF
+gmp_assemble="$CCAS $CFLAGS $CPPFLAGS conftest.s >conftest.out 2>&1"
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_assemble\""; } >&5
+  (eval $gmp_assemble) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  cat conftest.out >&5
+  gmp_cv_asm_x86_mmx=yes
+case $host in
+*-*-solaris*)
+  if (dis conftest.$OBJEXT >conftest.out) 2>/dev/null; then
+    if grep "0f 6f c1" conftest.out >/dev/null; then
+      gmp_cv_asm_x86_mmx=movq-bug
+    fi
+  else
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \"dis\" not available to check for \"as\" movq bug" >&5
+$as_echo "$as_me: WARNING: \"dis\" not available to check for \"as\" movq bug" >&2;}
+  fi
+esac
+else
+  cat conftest.out >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.s >&5
+  gmp_cv_asm_x86_mmx=no
+fi
+rm -f conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_cv_asm_x86_mmx" >&5
+$as_echo "$gmp_cv_asm_x86_mmx" >&6; }
+
+case $gmp_cv_asm_x86_mmx in
+movq-bug)
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: +----------------------------------------------------------" >&5
+$as_echo "$as_me: WARNING: +----------------------------------------------------------" >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: | WARNING WARNING WARNING" >&5
+$as_echo "$as_me: WARNING: | WARNING WARNING WARNING" >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: | Host CPU has MMX code, but the assembler" >&5
+$as_echo "$as_me: WARNING: | Host CPU has MMX code, but the assembler" >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: |     $CCAS $CFLAGS $CPPFLAGS" >&5
+$as_echo "$as_me: WARNING: |     $CCAS $CFLAGS $CPPFLAGS" >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: | has the Solaris 2.6 and 2.7 bug where register to register" >&5
+$as_echo "$as_me: WARNING: | has the Solaris 2.6 and 2.7 bug where register to register" >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: | movq operands are reversed." >&5
+$as_echo "$as_me: WARNING: | movq operands are reversed." >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: | Non-MMX replacements will be used." >&5
+$as_echo "$as_me: WARNING: | Non-MMX replacements will be used." >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: | This will be an inferior build." >&5
+$as_echo "$as_me: WARNING: | This will be an inferior build." >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: +----------------------------------------------------------" >&5
+$as_echo "$as_me: WARNING: +----------------------------------------------------------" >&2;}
+  ;;
+no)
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: +----------------------------------------------------------" >&5
+$as_echo "$as_me: WARNING: +----------------------------------------------------------" >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: | WARNING WARNING WARNING" >&5
+$as_echo "$as_me: WARNING: | WARNING WARNING WARNING" >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: | Host CPU has MMX code, but it can't be assembled by" >&5
+$as_echo "$as_me: WARNING: | Host CPU has MMX code, but it can't be assembled by" >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: |     $CCAS $CFLAGS $CPPFLAGS" >&5
+$as_echo "$as_me: WARNING: |     $CCAS $CFLAGS $CPPFLAGS" >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: | Non-MMX replacements will be used." >&5
+$as_echo "$as_me: WARNING: | Non-MMX replacements will be used." >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: | This will be an inferior build." >&5
+$as_echo "$as_me: WARNING: | This will be an inferior build." >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: +----------------------------------------------------------" >&5
+$as_echo "$as_me: WARNING: +----------------------------------------------------------" >&2;}
+  ;;
+esac
+if test "$gmp_cv_asm_x86_mmx" = yes; then
+  :
+else
+  tmp_path=
+for i in $path; do
+  case $i in
+    */*mmx*) ;;
+    *) tmp_path="$tmp_path $i" ;;
+  esac
+done
+path="$tmp_path"
+
+tmp_path=
+for i in $fat_path; do
+  case $i in
+    */*mmx*) ;;
+    *) tmp_path="$tmp_path $i" ;;
+  esac
+done
+fat_path="$tmp_path"
+
+
+fi
+ ;;
+      esac
+      case "$path $fat_path" in
+        *sse2*)  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the assembler knows about SSE2 instructions" >&5
+$as_echo_n "checking if the assembler knows about SSE2 instructions... " >&6; }
+if ${gmp_cv_asm_x86_sse2+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.s <<EOF
+	.text
+	paddq	%mm0, %mm1
+EOF
+gmp_assemble="$CCAS $CFLAGS $CPPFLAGS conftest.s >conftest.out 2>&1"
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_assemble\""; } >&5
+  (eval $gmp_assemble) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  cat conftest.out >&5
+  gmp_cv_asm_x86_sse2=yes
+else
+  cat conftest.out >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.s >&5
+  gmp_cv_asm_x86_sse2=no
+fi
+rm -f conftest*
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_cv_asm_x86_sse2" >&5
+$as_echo "$gmp_cv_asm_x86_sse2" >&6; }
+case $gmp_cv_asm_x86_sse2 in
+yes)
+  :
+  ;;
+*)
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: +----------------------------------------------------------" >&5
+$as_echo "$as_me: WARNING: +----------------------------------------------------------" >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: | WARNING WARNING WARNING" >&5
+$as_echo "$as_me: WARNING: | WARNING WARNING WARNING" >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: | Host CPU has SSE2 code, but it can't be assembled by" >&5
+$as_echo "$as_me: WARNING: | Host CPU has SSE2 code, but it can't be assembled by" >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: |     $CCAS $CFLAGS $CPPFLAGS" >&5
+$as_echo "$as_me: WARNING: |     $CCAS $CFLAGS $CPPFLAGS" >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: | Non-SSE2 replacements will be used." >&5
+$as_echo "$as_me: WARNING: | Non-SSE2 replacements will be used." >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: | This will be an inferior build." >&5
+$as_echo "$as_me: WARNING: | This will be an inferior build." >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: +----------------------------------------------------------" >&5
+$as_echo "$as_me: WARNING: +----------------------------------------------------------" >&2;}
+  tmp_path=
+for i in $path; do
+  case $i in
+    */sse2) ;;
+    *) tmp_path="$tmp_path $i" ;;
+  esac
+done
+path="$tmp_path"
+
+tmp_path=
+for i in $fat_path; do
+  case $i in
+    */sse2) ;;
+    *) tmp_path="$tmp_path $i" ;;
+  esac
+done
+fat_path="$tmp_path"
+
+
+  ;;
+esac
+ ;;
+      esac
+    fi
+    ;;
+esac
+
+
+if test "$enable_assembly" = "no"; then
+  path="generic"
+
+$as_echo "#define NO_ASM 1" >>confdefs.h
+
+#  for abi in $abilist; do
+#    eval unset "path_\$abi"
+#    eval gcc_${abi}_cflags=\"\$gcc_${abi}_cflags -DNO_ASM\"
+#  done
+fi
+
+
+cat >&5 <<EOF
+Decided:
+ABI=$ABI
+CC=$CC
+CFLAGS=$CFLAGS
+CPPFLAGS=$CPPFLAGS
+GMP_LDFLAGS=$GMP_LDFLAGS
+CXX=$CXX
+CXXFLAGS=$CXXFLAGS
+path=$path
+EOF
+echo "using ABI=\"$ABI\""
+echo "      CC=\"$CC\""
+echo "      CFLAGS=\"$CFLAGS\""
+echo "      CPPFLAGS=\"$CPPFLAGS\""
+if test $want_cxx = yes; then
+  echo "      CXX=\"$CXX\""
+  echo "      CXXFLAGS=\"$CXXFLAGS\""
+fi
+echo "      MPN_PATH=\"$path\""
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether assembler supports --noexecstack option" >&5
+$as_echo_n "checking whether assembler supports --noexecstack option... " >&6; }
+if ${cl_cv_as_noexecstack+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+    cat > conftest.c <<EOF
+void foo() {}
+EOF
+  if { ac_try='${CC} $CFLAGS $CPPFLAGS
+                     -S -o conftest.s conftest.c >/dev/null'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; } \
+     && grep .note.GNU-stack conftest.s >/dev/null \
+     && { ac_try='${CC} $CFLAGS $CPPFLAGS -Wa,--noexecstack
+                       -c -o conftest.o conftest.s >/dev/null'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }
+  then
+    cl_cv_as_noexecstack=yes
+  else
+    cl_cv_as_noexecstack=no
+  fi
+  rm -f conftest*
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cl_cv_as_noexecstack" >&5
+$as_echo "$cl_cv_as_noexecstack" >&6; }
+  if test "$cl_cv_as_noexecstack" = yes; then
+    ASMFLAGS="$ASMFLAGS -Wa,--noexecstack"
+  fi
+
+
+
+
+gmp_user_AR=$AR
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ar; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AR+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$AR"; then
+  ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_AR="${ac_tool_prefix}ar"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+AR=$ac_cv_prog_AR
+if test -n "$AR"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5
+$as_echo "$AR" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_AR"; then
+  ac_ct_AR=$AR
+  # Extract the first word of "ar", so it can be a program name with args.
+set dummy ar; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_AR+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_AR"; then
+  ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_AR="ar"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_AR=$ac_cv_prog_ac_ct_AR
+if test -n "$ac_ct_AR"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5
+$as_echo "$ac_ct_AR" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_AR" = x; then
+    AR="ar"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    AR=$ac_ct_AR
+  fi
+else
+  AR="$ac_cv_prog_AR"
+fi
+
+if test -z "$gmp_user_AR"; then
+                        eval arflags=\"\$ar${abi1}_flags\"
+  test -n "$arflags" || eval arflags=\"\$ar${abi2}_flags\"
+  if test -n "$arflags"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for extra ar flags" >&5
+$as_echo_n "checking for extra ar flags... " >&6; }
+    AR="$AR $arflags"
+    ac_cv_prog_AR="$AR $arflags"
+    ac_cv_prog_ac_ct_AR="$AR $arflags"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $arflags" >&5
+$as_echo "$arflags" >&6; }
+  fi
+fi
+if test -z "$AR_FLAGS"; then
+  AR_FLAGS=cq
+fi
+
+
+gmp_user_NM=$NM
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5
+$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; }
+if ${lt_cv_path_NM+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$NM"; then
+  # Let the user override the test.
+  lt_cv_path_NM=$NM
+else
+  lt_nm_to_check=${ac_tool_prefix}nm
+  if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
+    lt_nm_to_check="$lt_nm_to_check nm"
+  fi
+  for lt_tmp_nm in $lt_nm_to_check; do
+    lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
+    for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+      IFS=$lt_save_ifs
+      test -z "$ac_dir" && ac_dir=.
+      tmp_nm=$ac_dir/$lt_tmp_nm
+      if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext"; then
+	# Check to see if the nm accepts a BSD-compat flag.
+	# Adding the 'sed 1q' prevents false positives on HP-UX, which says:
+	#   nm: unknown option "B" ignored
+	# Tru64's nm complains that /dev/null is an invalid object file
+	# MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty
+	case $build_os in
+	mingw*) lt_bad_file=conftest.nm/nofile ;;
+	*) lt_bad_file=/dev/null ;;
+	esac
+	case `"$tmp_nm" -B $lt_bad_file 2>&1 | sed '1q'` in
+	*$lt_bad_file* | *'Invalid file or object type'*)
+	  lt_cv_path_NM="$tmp_nm -B"
+	  break 2
+	  ;;
+	*)
+	  case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+	  */dev/null*)
+	    lt_cv_path_NM="$tmp_nm -p"
+	    break 2
+	    ;;
+	  *)
+	    lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+	    continue # so that we can try to find one that supports BSD flags
+	    ;;
+	  esac
+	  ;;
+	esac
+      fi
+    done
+    IFS=$lt_save_ifs
+  done
+  : ${lt_cv_path_NM=no}
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5
+$as_echo "$lt_cv_path_NM" >&6; }
+if test no != "$lt_cv_path_NM"; then
+  NM=$lt_cv_path_NM
+else
+  # Didn't find any BSD compatible name lister, look for dumpbin.
+  if test -n "$DUMPBIN"; then :
+    # Let the user override the test.
+  else
+    if test -n "$ac_tool_prefix"; then
+  for ac_prog in dumpbin "link -dump"
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DUMPBIN+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$DUMPBIN"; then
+  ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+DUMPBIN=$ac_cv_prog_DUMPBIN
+if test -n "$DUMPBIN"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5
+$as_echo "$DUMPBIN" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$DUMPBIN" && break
+  done
+fi
+if test -z "$DUMPBIN"; then
+  ac_ct_DUMPBIN=$DUMPBIN
+  for ac_prog in dumpbin "link -dump"
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_DUMPBIN"; then
+  ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_DUMPBIN="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN
+if test -n "$ac_ct_DUMPBIN"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5
+$as_echo "$ac_ct_DUMPBIN" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_DUMPBIN" && break
+done
+
+  if test "x$ac_ct_DUMPBIN" = x; then
+    DUMPBIN=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    DUMPBIN=$ac_ct_DUMPBIN
+  fi
+fi
+
+    case `$DUMPBIN -symbols -headers /dev/null 2>&1 | sed '1q'` in
+    *COFF*)
+      DUMPBIN="$DUMPBIN -symbols -headers"
+      ;;
+    *)
+      DUMPBIN=:
+      ;;
+    esac
+  fi
+
+  if test : != "$DUMPBIN"; then
+    NM=$DUMPBIN
+  fi
+fi
+test -z "$NM" && NM=nm
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5
+$as_echo_n "checking the name lister ($NM) interface... " >&6; }
+if ${lt_cv_nm_interface+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_nm_interface="BSD nm"
+  echo "int some_variable = 0;" > conftest.$ac_ext
+  (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5)
+  (eval "$ac_compile" 2>conftest.err)
+  cat conftest.err >&5
+  (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
+  (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
+  cat conftest.err >&5
+  (eval echo "\"\$as_me:$LINENO: output\"" >&5)
+  cat conftest.out >&5
+  if $GREP 'External.*some_variable' conftest.out > /dev/null; then
+    lt_cv_nm_interface="MS dumpbin"
+  fi
+  rm -f conftest*
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5
+$as_echo "$lt_cv_nm_interface" >&6; }
+
+
+# FIXME: When cross compiling (ie. $ac_tool_prefix not empty), libtool
+# defaults to plain "nm" if a "${ac_tool_prefix}nm" is not found.  In this
+# case run it again to try the native "nm", firstly so that likely locations
+# are searched, secondly so that -B or -p are added if necessary for BSD
+# format.  This is necessary for instance on OSF with "./configure
+# --build=alphaev5-dec-osf --host=alphaev6-dec-osf".
+#
+if test -z "$gmp_user_NM" && test -n "$ac_tool_prefix" && test "$NM" = nm; then
+  $as_unset lt_cv_path_NM
+  gmp_save_ac_tool_prefix=$ac_tool_prefix
+  ac_tool_prefix=
+  NM=
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5
+$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; }
+if ${lt_cv_path_NM+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$NM"; then
+  # Let the user override the test.
+  lt_cv_path_NM=$NM
+else
+  lt_nm_to_check=${ac_tool_prefix}nm
+  if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
+    lt_nm_to_check="$lt_nm_to_check nm"
+  fi
+  for lt_tmp_nm in $lt_nm_to_check; do
+    lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
+    for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+      IFS=$lt_save_ifs
+      test -z "$ac_dir" && ac_dir=.
+      tmp_nm=$ac_dir/$lt_tmp_nm
+      if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext"; then
+	# Check to see if the nm accepts a BSD-compat flag.
+	# Adding the 'sed 1q' prevents false positives on HP-UX, which says:
+	#   nm: unknown option "B" ignored
+	# Tru64's nm complains that /dev/null is an invalid object file
+	# MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty
+	case $build_os in
+	mingw*) lt_bad_file=conftest.nm/nofile ;;
+	*) lt_bad_file=/dev/null ;;
+	esac
+	case `"$tmp_nm" -B $lt_bad_file 2>&1 | sed '1q'` in
+	*$lt_bad_file* | *'Invalid file or object type'*)
+	  lt_cv_path_NM="$tmp_nm -B"
+	  break 2
+	  ;;
+	*)
+	  case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+	  */dev/null*)
+	    lt_cv_path_NM="$tmp_nm -p"
+	    break 2
+	    ;;
+	  *)
+	    lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+	    continue # so that we can try to find one that supports BSD flags
+	    ;;
+	  esac
+	  ;;
+	esac
+      fi
+    done
+    IFS=$lt_save_ifs
+  done
+  : ${lt_cv_path_NM=no}
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5
+$as_echo "$lt_cv_path_NM" >&6; }
+if test no != "$lt_cv_path_NM"; then
+  NM=$lt_cv_path_NM
+else
+  # Didn't find any BSD compatible name lister, look for dumpbin.
+  if test -n "$DUMPBIN"; then :
+    # Let the user override the test.
+  else
+    if test -n "$ac_tool_prefix"; then
+  for ac_prog in dumpbin "link -dump"
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DUMPBIN+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$DUMPBIN"; then
+  ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+DUMPBIN=$ac_cv_prog_DUMPBIN
+if test -n "$DUMPBIN"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5
+$as_echo "$DUMPBIN" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$DUMPBIN" && break
+  done
+fi
+if test -z "$DUMPBIN"; then
+  ac_ct_DUMPBIN=$DUMPBIN
+  for ac_prog in dumpbin "link -dump"
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_DUMPBIN"; then
+  ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_DUMPBIN="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN
+if test -n "$ac_ct_DUMPBIN"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5
+$as_echo "$ac_ct_DUMPBIN" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_DUMPBIN" && break
+done
+
+  if test "x$ac_ct_DUMPBIN" = x; then
+    DUMPBIN=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    DUMPBIN=$ac_ct_DUMPBIN
+  fi
+fi
+
+    case `$DUMPBIN -symbols -headers /dev/null 2>&1 | sed '1q'` in
+    *COFF*)
+      DUMPBIN="$DUMPBIN -symbols -headers"
+      ;;
+    *)
+      DUMPBIN=:
+      ;;
+    esac
+  fi
+
+  if test : != "$DUMPBIN"; then
+    NM=$DUMPBIN
+  fi
+fi
+test -z "$NM" && NM=nm
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5
+$as_echo_n "checking the name lister ($NM) interface... " >&6; }
+if ${lt_cv_nm_interface+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_nm_interface="BSD nm"
+  echo "int some_variable = 0;" > conftest.$ac_ext
+  (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5)
+  (eval "$ac_compile" 2>conftest.err)
+  cat conftest.err >&5
+  (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
+  (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
+  cat conftest.err >&5
+  (eval echo "\"\$as_me:$LINENO: output\"" >&5)
+  cat conftest.out >&5
+  if $GREP 'External.*some_variable' conftest.out > /dev/null; then
+    lt_cv_nm_interface="MS dumpbin"
+  fi
+  rm -f conftest*
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5
+$as_echo "$lt_cv_nm_interface" >&6; }
+
+  ac_tool_prefix=$gmp_save_ac_tool_prefix
+fi
+
+if test -z "$gmp_user_NM"; then
+                        eval nmflags=\"\$nm${abi1}_flags\"
+  test -n "$nmflags" || eval nmflags=\"\$nm${abi2}_flags\"
+  if test -n "$nmflags"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for extra nm flags" >&5
+$as_echo_n "checking for extra nm flags... " >&6; }
+    NM="$NM $nmflags"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $nmflags" >&5
+$as_echo "$nmflags" >&6; }
+  fi
+fi
+
+
+case $host in
+  # FIXME: On AIX 3 and 4, $libname.a is included in libtool
+  # $library_names_spec, so libgmp.a becomes a symlink to libgmp.so, making
+  # it impossible to build shared and static libraries simultaneously.
+  # Disable shared libraries by default, but let the user override with
+  # --enable-shared --disable-static.
+  #
+  # FIXME: This $libname.a problem looks like it might apply to *-*-amigaos*
+  # and *-*-os2* too, but wait for someone to test this before worrying
+  # about it.  If there is a problem then of course libtool is the right
+  # place to fix it.
+  #
+  *-*-aix[34]*)
+    if test -z "$enable_shared"; then enable_shared=no; fi ;;
+esac
+
+
+# Configs for Windows DLLs.
+
+enable_win32_dll=yes
+
+case $host in
+*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
+  if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}as", so it can be a program name with args.
+set dummy ${ac_tool_prefix}as; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AS+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$AS"; then
+  ac_cv_prog_AS="$AS" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_AS="${ac_tool_prefix}as"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+AS=$ac_cv_prog_AS
+if test -n "$AS"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AS" >&5
+$as_echo "$AS" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_AS"; then
+  ac_ct_AS=$AS
+  # Extract the first word of "as", so it can be a program name with args.
+set dummy as; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_AS+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_AS"; then
+  ac_cv_prog_ac_ct_AS="$ac_ct_AS" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_AS="as"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_AS=$ac_cv_prog_ac_ct_AS
+if test -n "$ac_ct_AS"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AS" >&5
+$as_echo "$ac_ct_AS" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_AS" = x; then
+    AS="false"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    AS=$ac_ct_AS
+  fi
+else
+  AS="$ac_cv_prog_AS"
+fi
+
+  if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args.
+set dummy ${ac_tool_prefix}dlltool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DLLTOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$DLLTOOL"; then
+  ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+DLLTOOL=$ac_cv_prog_DLLTOOL
+if test -n "$DLLTOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5
+$as_echo "$DLLTOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_DLLTOOL"; then
+  ac_ct_DLLTOOL=$DLLTOOL
+  # Extract the first word of "dlltool", so it can be a program name with args.
+set dummy dlltool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_DLLTOOL"; then
+  ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_DLLTOOL="dlltool"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL
+if test -n "$ac_ct_DLLTOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5
+$as_echo "$ac_ct_DLLTOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_DLLTOOL" = x; then
+    DLLTOOL="false"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    DLLTOOL=$ac_ct_DLLTOOL
+  fi
+else
+  DLLTOOL="$ac_cv_prog_DLLTOOL"
+fi
+
+  if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args.
+set dummy ${ac_tool_prefix}objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_OBJDUMP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$OBJDUMP"; then
+  ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+OBJDUMP=$ac_cv_prog_OBJDUMP
+if test -n "$OBJDUMP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5
+$as_echo "$OBJDUMP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OBJDUMP"; then
+  ac_ct_OBJDUMP=$OBJDUMP
+  # Extract the first word of "objdump", so it can be a program name with args.
+set dummy objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_OBJDUMP"; then
+  ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_OBJDUMP="objdump"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP
+if test -n "$ac_ct_OBJDUMP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5
+$as_echo "$ac_ct_OBJDUMP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_OBJDUMP" = x; then
+    OBJDUMP="false"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    OBJDUMP=$ac_ct_OBJDUMP
+  fi
+else
+  OBJDUMP="$ac_cv_prog_OBJDUMP"
+fi
+
+  ;;
+esac
+
+test -z "$AS" && AS=as
+
+
+
+
+
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+
+
+
+
+
+test -z "$OBJDUMP" && OBJDUMP=objdump
+
+
+
+
+
+
+
+
+LIBGMP_DLL=0
+
+case $host in
+  *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
+    # By default, build only static.
+    if test -z "$enable_shared"; then
+      enable_shared=no
+    fi
+    # Don't allow both static and DLL.
+    if test "$enable_shared" != no && test "$enable_static" != no; then
+      as_fn_error $? "cannot build both static and DLL, since gmp.h is different for each.
+Use \"--disable-static --enable-shared\" to build just a DLL." "$LINENO" 5
+    fi
+
+    # "-no-undefined" is required when building a DLL, see documentation on
+    # AC_LIBTOOL_WIN32_DLL.
+    #
+    # "-Wl,--export-all-symbols" is a bit of a hack, it gets all libgmp and
+    # libgmpxx functions and variables exported.  This is what libtool did
+    # in the past, and it's convenient for us in the test programs.
+    #
+    # Maybe it'd be prudent to check for --export-all-symbols before using
+    # it, but it seems to have been in ld since at least 2000, and there's
+    # not really any alternative we want to take up at the moment.
+    #
+    # "-Wl,output-def" is used to get a .def file for use by MS lib to make
+    # a .lib import library, described in the manual.  libgmp-3.dll.def
+    # corresponds to the libmp-3.dll.def generated by libtool (as a result
+    # of -export-symbols on that library).
+    #
+    # Incidentally, libtool does generate an import library libgmp.dll.a,
+    # but it's "ar" format and cannot be used by the MS linker.  There
+    # doesn't seem to be any GNU tool for generating or converting to .lib.
+    #
+    # FIXME: The .def files produced by -Wl,output-def include isascii,
+    # iscsym, iscsymf and toascii, apparently because mingw ctype.h doesn't
+    # inline isascii (used in gmp).  It gives an extern inline for
+    # __isascii, but for some reason not the plain isascii.
+    #
+    if test "$enable_shared" = yes; then
+      GMP_LDFLAGS="$GMP_LDFLAGS -no-undefined -Wl,--export-all-symbols"
+      LIBGMP_LDFLAGS="$LIBGMP_LDFLAGS -Wl,--output-def,.libs/libgmp-3.dll.def"
+      LIBGMPXX_LDFLAGS="$LIBGMP_LDFLAGS -Wl,--output-def,.libs/libgmpxx-3.dll.def"
+      LIBGMP_DLL=1
+    fi
+    ;;
+esac
+
+
+# Ensure that $CONFIG_SHELL is available for AC_LIBTOOL_SYS_MAX_CMD_LEN.
+# It's often set already by _LT_AC_PROG_ECHO_BACKSLASH or
+# _AS_LINENO_PREPARE, but not always.
+#
+# The symptom of CONFIG_SHELL unset is some "expr" errors during the test,
+# and an empty result.  This only happens when invoked as "sh configure",
+# ie. no path, and can be seen for instance on ia64-*-hpux*.
+#
+# FIXME: Newer libtool should have it's own fix for this.
+#
+if test -z "$CONFIG_SHELL"; then
+  CONFIG_SHELL=$SHELL
+fi
+
+# Enable CXX in libtool only if we want it, and never enable GCJ, nor RC on
+# mingw and cygwin.  Under --disable-cxx this avoids some error messages
+# from libtool arising from the fact we didn't actually run AC_PROG_CXX.
+# Notice that any user-supplied --with-tags setting takes precedence.
+#
+# FIXME: Is this the right way to get this effect?  Very possibly not, but
+# the current _LT_AC_TAGCONFIG doesn't really suggest an alternative.
+#
+if test "${with_tags+set}" != set; then
+  if test $want_cxx = yes; then
+    with_tags=CXX
+  else
+    with_tags=
+  fi
+fi
+
+# The dead hand of AC_REQUIRE makes AC_PROG_LIBTOOL expand and execute
+# AC_PROG_F77, even when F77 is not in the selected with_tags.  This is
+# probably harmless, but it's unsightly and bloats our configure, so pretend
+# AC_PROG_F77 has been expanded already.
+#
+# FIXME: Rumour has it libtool will one day provide a way for a configure.in
+# to say what it wants from among supported languages etc.
+#
+#AC_PROVIDE([AC_PROG_F77])
+
+case `pwd` in
+  *\ * | *\	*)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5
+$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;;
+esac
+
+
+
+macro_version='2.4.6'
+macro_revision='2.4.6'
+
+
+
+
+
+
+
+
+
+
+
+
+
+ltmain=$ac_aux_dir/ltmain.sh
+
+# Backslashify metacharacters that are still active within
+# double-quoted strings.
+sed_quote_subst='s/\(["`$\\]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\(["`\\]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to delay expansion of an escaped single quote.
+delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+
+ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5
+$as_echo_n "checking how to print strings... " >&6; }
+# Test print first, because it will be a builtin if present.
+if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \
+   test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
+  ECHO='print -r --'
+elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
+  ECHO='printf %s\n'
+else
+  # Use this function as a fallback that always works.
+  func_fallback_echo ()
+  {
+    eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+  }
+  ECHO='func_fallback_echo'
+fi
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+    $ECHO ""
+}
+
+case $ECHO in
+  printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5
+$as_echo "printf" >&6; } ;;
+  print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5
+$as_echo "print -r" >&6; } ;;
+  *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5
+$as_echo "cat" >&6; } ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5
+$as_echo_n "checking for a sed that does not truncate output... " >&6; }
+if ${ac_cv_path_SED+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+            ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
+     for ac_i in 1 2 3 4 5 6 7; do
+       ac_script="$ac_script$as_nl$ac_script"
+     done
+     echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed
+     { ac_script=; unset ac_script;}
+     if test -z "$SED"; then
+  ac_path_SED_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in sed gsed; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_SED="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_SED" || continue
+# Check for GNU ac_path_SED and select it if it is found.
+  # Check for GNU $ac_path_SED
+case `"$ac_path_SED" --version 2>&1` in
+*GNU*)
+  ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo '' >> "conftest.nl"
+    "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_SED_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_SED="$ac_path_SED"
+      ac_path_SED_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_SED_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_SED"; then
+    as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5
+  fi
+else
+  ac_cv_path_SED=$SED
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5
+$as_echo "$ac_cv_path_SED" >&6; }
+ SED="$ac_cv_path_SED"
+  rm -f conftest.sed
+
+test -z "$SED" && SED=sed
+Xsed="$SED -e 1s/^X//"
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5
+$as_echo_n "checking for fgrep... " >&6; }
+if ${ac_cv_path_FGREP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1
+   then ac_cv_path_FGREP="$GREP -F"
+   else
+     if test -z "$FGREP"; then
+  ac_path_FGREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in fgrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_FGREP" || continue
+# Check for GNU ac_path_FGREP and select it if it is found.
+  # Check for GNU $ac_path_FGREP
+case `"$ac_path_FGREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'FGREP' >> "conftest.nl"
+    "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_FGREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_FGREP="$ac_path_FGREP"
+      ac_path_FGREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_FGREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_FGREP"; then
+    as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_FGREP=$FGREP
+fi
+
+   fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5
+$as_echo "$ac_cv_path_FGREP" >&6; }
+ FGREP="$ac_cv_path_FGREP"
+
+
+test -z "$GREP" && GREP=grep
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# Check whether --with-gnu-ld was given.
+if test "${with_gnu_ld+set}" = set; then :
+  withval=$with_gnu_ld; test no = "$withval" || with_gnu_ld=yes
+else
+  with_gnu_ld=no
+fi
+
+ac_prog=ld
+if test yes = "$GCC"; then
+  # Check if gcc -print-prog-name=ld gives a path.
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5
+$as_echo_n "checking for ld used by $CC... " >&6; }
+  case $host in
+  *-*-mingw*)
+    # gcc leaves a trailing carriage return, which upsets mingw
+    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+  *)
+    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+  esac
+  case $ac_prog in
+    # Accept absolute paths.
+    [\\/]* | ?:[\\/]*)
+      re_direlt='/[^/][^/]*/\.\./'
+      # Canonicalize the pathname of ld
+      ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+      while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+	ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+      done
+      test -z "$LD" && LD=$ac_prog
+      ;;
+  "")
+    # If it fails, then pretend we aren't using GCC.
+    ac_prog=ld
+    ;;
+  *)
+    # If it is relative, then search for the first ld in PATH.
+    with_gnu_ld=unknown
+    ;;
+  esac
+elif test yes = "$with_gnu_ld"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5
+$as_echo_n "checking for GNU ld... " >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5
+$as_echo_n "checking for non-GNU ld... " >&6; }
+fi
+if ${lt_cv_path_LD+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$LD"; then
+  lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
+  for ac_dir in $PATH; do
+    IFS=$lt_save_ifs
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+      lt_cv_path_LD=$ac_dir/$ac_prog
+      # Check to see if the program is GNU ld.  I'd rather use --version,
+      # but apparently some variants of GNU ld only accept -v.
+      # Break only if it was the GNU/non-GNU ld that we prefer.
+      case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+      *GNU* | *'with BFD'*)
+	test no != "$with_gnu_ld" && break
+	;;
+      *)
+	test yes != "$with_gnu_ld" && break
+	;;
+      esac
+    fi
+  done
+  IFS=$lt_save_ifs
+else
+  lt_cv_path_LD=$LD # Let the user override the test with a path.
+fi
+fi
+
+LD=$lt_cv_path_LD
+if test -n "$LD"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5
+$as_echo "$LD" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5
+$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; }
+if ${lt_cv_prog_gnu_ld+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  # I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+  lt_cv_prog_gnu_ld=yes
+  ;;
+*)
+  lt_cv_prog_gnu_ld=no
+  ;;
+esac
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5
+$as_echo "$lt_cv_prog_gnu_ld" >&6; }
+with_gnu_ld=$lt_cv_prog_gnu_ld
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5
+$as_echo_n "checking whether ln -s works... " >&6; }
+LN_S=$as_ln_s
+if test "$LN_S" = "ln -s"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5
+$as_echo "no, using $LN_S" >&6; }
+fi
+
+# find the maximum length of command line arguments
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5
+$as_echo_n "checking the maximum length of command line arguments... " >&6; }
+if ${lt_cv_sys_max_cmd_len+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+    i=0
+  teststring=ABCD
+
+  case $build_os in
+  msdosdjgpp*)
+    # On DJGPP, this test can blow up pretty badly due to problems in libc
+    # (any single argument exceeding 2000 bytes causes a buffer overrun
+    # during glob expansion).  Even if it were fixed, the result of this
+    # check would be larger than it should be.
+    lt_cv_sys_max_cmd_len=12288;    # 12K is about right
+    ;;
+
+  gnu*)
+    # Under GNU Hurd, this test is not required because there is
+    # no limit to the length of command line arguments.
+    # Libtool will interpret -1 as no limit whatsoever
+    lt_cv_sys_max_cmd_len=-1;
+    ;;
+
+  cygwin* | mingw* | cegcc*)
+    # On Win9x/ME, this test blows up -- it succeeds, but takes
+    # about 5 minutes as the teststring grows exponentially.
+    # Worse, since 9x/ME are not pre-emptively multitasking,
+    # you end up with a "frozen" computer, even though with patience
+    # the test eventually succeeds (with a max line length of 256k).
+    # Instead, let's just punt: use the minimum linelength reported by
+    # all of the supported platforms: 8192 (on NT/2K/XP).
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  mint*)
+    # On MiNT this can take a long time and run out of memory.
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  amigaos*)
+    # On AmigaOS with pdksh, this test takes hours, literally.
+    # So we just punt and use a minimum line length of 8192.
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  bitrig* | darwin* | dragonfly* | freebsd* | netbsd* | openbsd*)
+    # This has been around since 386BSD, at least.  Likely further.
+    if test -x /sbin/sysctl; then
+      lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+    elif test -x /usr/sbin/sysctl; then
+      lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+    else
+      lt_cv_sys_max_cmd_len=65536	# usable default for all BSDs
+    fi
+    # And add a safety zone
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+    ;;
+
+  interix*)
+    # We know the value 262144 and hardcode it with a safety zone (like BSD)
+    lt_cv_sys_max_cmd_len=196608
+    ;;
+
+  os2*)
+    # The test takes a long time on OS/2.
+    lt_cv_sys_max_cmd_len=8192
+    ;;
+
+  osf*)
+    # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+    # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+    # nice to cause kernel panics so lets avoid the loop below.
+    # First set a reasonable default.
+    lt_cv_sys_max_cmd_len=16384
+    #
+    if test -x /sbin/sysconfig; then
+      case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+        *1*) lt_cv_sys_max_cmd_len=-1 ;;
+      esac
+    fi
+    ;;
+  sco3.2v5*)
+    lt_cv_sys_max_cmd_len=102400
+    ;;
+  sysv5* | sco5v6* | sysv4.2uw2*)
+    kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+    if test -n "$kargmax"; then
+      lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[	 ]//'`
+    else
+      lt_cv_sys_max_cmd_len=32768
+    fi
+    ;;
+  *)
+    lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
+    if test -n "$lt_cv_sys_max_cmd_len" && \
+       test undefined != "$lt_cv_sys_max_cmd_len"; then
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+    else
+      # Make teststring a little bigger before we do anything with it.
+      # a 1K string should be a reasonable start.
+      for i in 1 2 3 4 5 6 7 8; do
+        teststring=$teststring$teststring
+      done
+      SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+      # If test is not a shell built-in, we'll probably end up computing a
+      # maximum length that is only half of the actual maximum length, but
+      # we can't tell.
+      while { test X`env echo "$teststring$teststring" 2>/dev/null` \
+	         = "X$teststring$teststring"; } >/dev/null 2>&1 &&
+	      test 17 != "$i" # 1/2 MB should be enough
+      do
+        i=`expr $i + 1`
+        teststring=$teststring$teststring
+      done
+      # Only check the string length outside the loop.
+      lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
+      teststring=
+      # Add a significant safety factor because C++ compilers can tack on
+      # massive amounts of additional arguments before passing them to the
+      # linker.  It appears as though 1/2 is a usable value.
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+    fi
+    ;;
+  esac
+
+fi
+
+if test -n "$lt_cv_sys_max_cmd_len"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5
+$as_echo "$lt_cv_sys_max_cmd_len" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5
+$as_echo "none" >&6; }
+fi
+max_cmd_len=$lt_cv_sys_max_cmd_len
+
+
+
+
+
+
+: ${CP="cp -f"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  lt_unset=unset
+else
+  lt_unset=false
+fi
+
+
+
+
+
+# test EBCDIC or ASCII
+case `echo X|tr X '\101'` in
+ A) # ASCII based system
+    # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
+  lt_SP2NL='tr \040 \012'
+  lt_NL2SP='tr \015\012 \040\040'
+  ;;
+ *) # EBCDIC based system
+  lt_SP2NL='tr \100 \n'
+  lt_NL2SP='tr \r\n \100\100'
+  ;;
+esac
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5
+$as_echo_n "checking how to convert $build file names to $host format... " >&6; }
+if ${lt_cv_to_host_file_cmd+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $host in
+  *-*-mingw* )
+    case $build in
+      *-*-mingw* ) # actually msys
+        lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32
+        ;;
+      *-*-cygwin* )
+        lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32
+        ;;
+      * ) # otherwise, assume *nix
+        lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32
+        ;;
+    esac
+    ;;
+  *-*-cygwin* )
+    case $build in
+      *-*-mingw* ) # actually msys
+        lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin
+        ;;
+      *-*-cygwin* )
+        lt_cv_to_host_file_cmd=func_convert_file_noop
+        ;;
+      * ) # otherwise, assume *nix
+        lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin
+        ;;
+    esac
+    ;;
+  * ) # unhandled hosts (and "normal" native builds)
+    lt_cv_to_host_file_cmd=func_convert_file_noop
+    ;;
+esac
+
+fi
+
+to_host_file_cmd=$lt_cv_to_host_file_cmd
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5
+$as_echo "$lt_cv_to_host_file_cmd" >&6; }
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5
+$as_echo_n "checking how to convert $build file names to toolchain format... " >&6; }
+if ${lt_cv_to_tool_file_cmd+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  #assume ordinary cross tools, or native build.
+lt_cv_to_tool_file_cmd=func_convert_file_noop
+case $host in
+  *-*-mingw* )
+    case $build in
+      *-*-mingw* ) # actually msys
+        lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32
+        ;;
+    esac
+    ;;
+esac
+
+fi
+
+to_tool_file_cmd=$lt_cv_to_tool_file_cmd
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5
+$as_echo "$lt_cv_to_tool_file_cmd" >&6; }
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5
+$as_echo_n "checking for $LD option to reload object files... " >&6; }
+if ${lt_cv_ld_reload_flag+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_ld_reload_flag='-r'
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5
+$as_echo "$lt_cv_ld_reload_flag" >&6; }
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+  cygwin* | mingw* | pw32* | cegcc*)
+    if test yes != "$GCC"; then
+      reload_cmds=false
+    fi
+    ;;
+  darwin*)
+    if test yes = "$GCC"; then
+      reload_cmds='$LTCC $LTCFLAGS -nostdlib $wl-r -o $output$reload_objs'
+    else
+      reload_cmds='$LD$reload_flag -o $output$reload_objs'
+    fi
+    ;;
+esac
+
+
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args.
+set dummy ${ac_tool_prefix}objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_OBJDUMP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$OBJDUMP"; then
+  ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+OBJDUMP=$ac_cv_prog_OBJDUMP
+if test -n "$OBJDUMP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5
+$as_echo "$OBJDUMP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OBJDUMP"; then
+  ac_ct_OBJDUMP=$OBJDUMP
+  # Extract the first word of "objdump", so it can be a program name with args.
+set dummy objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_OBJDUMP"; then
+  ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_OBJDUMP="objdump"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP
+if test -n "$ac_ct_OBJDUMP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5
+$as_echo "$ac_ct_OBJDUMP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_OBJDUMP" = x; then
+    OBJDUMP="false"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    OBJDUMP=$ac_ct_OBJDUMP
+  fi
+else
+  OBJDUMP="$ac_cv_prog_OBJDUMP"
+fi
+
+test -z "$OBJDUMP" && OBJDUMP=objdump
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5
+$as_echo_n "checking how to recognize dependent libraries... " >&6; }
+if ${lt_cv_deplibs_check_method+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# 'unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# that responds to the $file_magic_cmd with a given extended regex.
+# If you have 'file' or equivalent on your system and you're not sure
+# whether 'pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix[4-9]*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+beos*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+bsdi[45]*)
+  lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)'
+  lt_cv_file_magic_cmd='/usr/bin/file -L'
+  lt_cv_file_magic_test_file=/shlib/libc.so
+  ;;
+
+cygwin*)
+  # func_win32_libid is a shell function defined in ltmain.sh
+  lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+  lt_cv_file_magic_cmd='func_win32_libid'
+  ;;
+
+mingw* | pw32*)
+  # Base MSYS/MinGW do not provide the 'file' command needed by
+  # func_win32_libid shell function, so use a weaker test based on 'objdump',
+  # unless we find 'file', for example because we are cross-compiling.
+  if ( file / ) >/dev/null 2>&1; then
+    lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+    lt_cv_file_magic_cmd='func_win32_libid'
+  else
+    # Keep this pattern in sync with the one in func_win32_libid.
+    lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)'
+    lt_cv_file_magic_cmd='$OBJDUMP -f'
+  fi
+  ;;
+
+cegcc*)
+  # use the weaker test based on 'objdump'. See mingw*.
+  lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
+  lt_cv_file_magic_cmd='$OBJDUMP -f'
+  ;;
+
+darwin* | rhapsody*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+freebsd* | dragonfly*)
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+    case $host_cpu in
+    i*86 )
+      # Not sure whether the presence of OpenBSD here was a mistake.
+      # Let's accept both of them until this is cleared up.
+      lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library'
+      lt_cv_file_magic_cmd=/usr/bin/file
+      lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+      ;;
+    esac
+  else
+    lt_cv_deplibs_check_method=pass_all
+  fi
+  ;;
+
+haiku*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+hpux10.20* | hpux11*)
+  lt_cv_file_magic_cmd=/usr/bin/file
+  case $host_cpu in
+  ia64*)
+    lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64'
+    lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+    ;;
+  hppa*64*)
+    lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'
+    lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+    ;;
+  *)
+    lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library'
+    lt_cv_file_magic_test_file=/usr/lib/libc.sl
+    ;;
+  esac
+  ;;
+
+interix[3-9]*)
+  # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+  lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$'
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $LD in
+  *-32|*"-32 ") libmagic=32-bit;;
+  *-n32|*"-n32 ") libmagic=N32;;
+  *-64|*"-64 ") libmagic=64-bit;;
+  *) libmagic=never-match;;
+  esac
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+netbsd*)
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+    lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$'
+  fi
+  ;;
+
+newos6*)
+  lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)'
+  lt_cv_file_magic_cmd=/usr/bin/file
+  lt_cv_file_magic_test_file=/usr/lib/libnls.so
+  ;;
+
+*nto* | *qnx*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+openbsd* | bitrig*)
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
+    lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
+  fi
+  ;;
+
+osf3* | osf4* | osf5*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+rdos*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+solaris*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sysv4 | sysv4.3*)
+  case $host_vendor in
+  motorola)
+    lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]'
+    lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+    ;;
+  ncr)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  sequent)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )'
+    ;;
+  sni)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib"
+    lt_cv_file_magic_test_file=/lib/libc.so
+    ;;
+  siemens)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  pc)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  esac
+  ;;
+
+tpf*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+os2*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+esac
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5
+$as_echo "$lt_cv_deplibs_check_method" >&6; }
+
+file_magic_glob=
+want_nocaseglob=no
+if test "$build" = "$host"; then
+  case $host_os in
+  mingw* | pw32*)
+    if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then
+      want_nocaseglob=yes
+    else
+      file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"`
+    fi
+    ;;
+  esac
+fi
+
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args.
+set dummy ${ac_tool_prefix}dlltool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DLLTOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$DLLTOOL"; then
+  ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+DLLTOOL=$ac_cv_prog_DLLTOOL
+if test -n "$DLLTOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5
+$as_echo "$DLLTOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_DLLTOOL"; then
+  ac_ct_DLLTOOL=$DLLTOOL
+  # Extract the first word of "dlltool", so it can be a program name with args.
+set dummy dlltool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_DLLTOOL"; then
+  ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_DLLTOOL="dlltool"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL
+if test -n "$ac_ct_DLLTOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5
+$as_echo "$ac_ct_DLLTOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_DLLTOOL" = x; then
+    DLLTOOL="false"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    DLLTOOL=$ac_ct_DLLTOOL
+  fi
+else
+  DLLTOOL="$ac_cv_prog_DLLTOOL"
+fi
+
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5
+$as_echo_n "checking how to associate runtime and link libraries... " >&6; }
+if ${lt_cv_sharedlib_from_linklib_cmd+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_sharedlib_from_linklib_cmd='unknown'
+
+case $host_os in
+cygwin* | mingw* | pw32* | cegcc*)
+  # two different shell functions defined in ltmain.sh;
+  # decide which one to use based on capabilities of $DLLTOOL
+  case `$DLLTOOL --help 2>&1` in
+  *--identify-strict*)
+    lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib
+    ;;
+  *)
+    lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback
+    ;;
+  esac
+  ;;
+*)
+  # fallback: assume linklib IS sharedlib
+  lt_cv_sharedlib_from_linklib_cmd=$ECHO
+  ;;
+esac
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5
+$as_echo "$lt_cv_sharedlib_from_linklib_cmd" >&6; }
+sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd
+test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+  for ac_prog in ar
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AR+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$AR"; then
+  ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_AR="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+AR=$ac_cv_prog_AR
+if test -n "$AR"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5
+$as_echo "$AR" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$AR" && break
+  done
+fi
+if test -z "$AR"; then
+  ac_ct_AR=$AR
+  for ac_prog in ar
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_AR+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_AR"; then
+  ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_AR="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_AR=$ac_cv_prog_ac_ct_AR
+if test -n "$ac_ct_AR"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5
+$as_echo "$ac_ct_AR" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_AR" && break
+done
+
+  if test "x$ac_ct_AR" = x; then
+    AR="false"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    AR=$ac_ct_AR
+  fi
+fi
+
+: ${AR=ar}
+: ${AR_FLAGS=cru}
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5
+$as_echo_n "checking for archiver @FILE support... " >&6; }
+if ${lt_cv_ar_at_file+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_ar_at_file=no
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  echo conftest.$ac_objext > conftest.lst
+      lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5'
+      { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5
+  (eval $lt_ar_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+      if test 0 -eq "$ac_status"; then
+	# Ensure the archiver fails upon bogus file names.
+	rm -f conftest.$ac_objext libconftest.a
+	{ { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5
+  (eval $lt_ar_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+	if test 0 -ne "$ac_status"; then
+          lt_cv_ar_at_file=@
+        fi
+      fi
+      rm -f conftest.* libconftest.a
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5
+$as_echo "$lt_cv_ar_at_file" >&6; }
+
+if test no = "$lt_cv_ar_at_file"; then
+  archiver_list_spec=
+else
+  archiver_list_spec=$lt_cv_ar_at_file
+fi
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_STRIP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$STRIP"; then
+  ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
+$as_echo "$STRIP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+  ac_ct_STRIP=$STRIP
+  # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_STRIP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_STRIP"; then
+  ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_STRIP="strip"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
+$as_echo "$ac_ct_STRIP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_STRIP" = x; then
+    STRIP=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    STRIP=$ac_ct_STRIP
+  fi
+else
+  STRIP="$ac_cv_prog_STRIP"
+fi
+
+test -z "$STRIP" && STRIP=:
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_RANLIB+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$RANLIB"; then
+  ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
+$as_echo "$RANLIB" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+  ac_ct_RANLIB=$RANLIB
+  # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_RANLIB+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_RANLIB"; then
+  ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_RANLIB="ranlib"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
+$as_echo "$ac_ct_RANLIB" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_RANLIB" = x; then
+    RANLIB=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    RANLIB=$ac_ct_RANLIB
+  fi
+else
+  RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+test -z "$RANLIB" && RANLIB=:
+
+
+
+
+
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+  case $host_os in
+  bitrig* | openbsd*)
+    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib"
+    ;;
+  *)
+    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib"
+    ;;
+  esac
+  old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib"
+fi
+
+case $host_os in
+  darwin*)
+    lock_old_archive_extraction=yes ;;
+  *)
+    lock_old_archive_extraction=no ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5
+$as_echo_n "checking command to parse $NM output from $compiler object... " >&6; }
+if ${lt_cv_sys_global_symbol_pipe+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix.  What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[BCDEGRST]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([_A-Za-z][_A-Za-z0-9]*\)'
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+  symcode='[BCDT]'
+  ;;
+cygwin* | mingw* | pw32* | cegcc*)
+  symcode='[ABCDGISTW]'
+  ;;
+hpux*)
+  if test ia64 = "$host_cpu"; then
+    symcode='[ABCDEGRST]'
+  fi
+  ;;
+irix* | nonstopux*)
+  symcode='[BCDEGRST]'
+  ;;
+osf*)
+  symcode='[BCDEGQRST]'
+  ;;
+solaris*)
+  symcode='[BDRT]'
+  ;;
+sco3.2v5*)
+  symcode='[DT]'
+  ;;
+sysv4.2uw2*)
+  symcode='[DT]'
+  ;;
+sysv5* | sco5v6* | unixware* | OpenUNIX*)
+  symcode='[ABDT]'
+  ;;
+sysv4)
+  symcode='[DFNSTU]'
+  ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+  symcode='[ABCDGIRSTW]' ;;
+esac
+
+if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+  # Gets list of data symbols to import.
+  lt_cv_sys_global_symbol_to_import="sed -n -e 's/^I .* \(.*\)$/\1/p'"
+  # Adjust the below global symbol transforms to fixup imported variables.
+  lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'"
+  lt_c_name_hook=" -e 's/^I .* \(.*\)$/  {\"\1\", (void *) 0},/p'"
+  lt_c_name_lib_hook="\
+  -e 's/^I .* \(lib.*\)$/  {\"\1\", (void *) 0},/p'\
+  -e 's/^I .* \(.*\)$/  {\"lib\1\", (void *) 0},/p'"
+else
+  # Disable hooks by default.
+  lt_cv_sys_global_symbol_to_import=
+  lt_cdecl_hook=
+  lt_c_name_hook=
+  lt_c_name_lib_hook=
+fi
+
+# Transform an extracted symbol line into a proper C declaration.
+# Some systems (esp. on ia64) link data and code symbols differently,
+# so use this general approach.
+lt_cv_sys_global_symbol_to_cdecl="sed -n"\
+$lt_cdecl_hook\
+" -e 's/^T .* \(.*\)$/extern int \1();/p'"\
+" -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n"\
+$lt_c_name_hook\
+" -e 's/^: \(.*\) .*$/  {\"\1\", (void *) 0},/p'"\
+" -e 's/^$symcode$symcode* .* \(.*\)$/  {\"\1\", (void *) \&\1},/p'"
+
+# Transform an extracted symbol line into symbol name with lib prefix and
+# symbol address.
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n"\
+$lt_c_name_lib_hook\
+" -e 's/^: \(.*\) .*$/  {\"\1\", (void *) 0},/p'"\
+" -e 's/^$symcode$symcode* .* \(lib.*\)$/  {\"\1\", (void *) \&\1},/p'"\
+" -e 's/^$symcode$symcode* .* \(.*\)$/  {\"lib\1\", (void *) \&\1},/p'"
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+  opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+  ;;
+esac
+
+# Try without a prefix underscore, then with it.
+for ac_symprfx in "" "_"; do
+
+  # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+  symxfrm="\\1 $ac_symprfx\\2 \\2"
+
+  # Write the raw and C identifiers.
+  if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+    # Fake it for dumpbin and say T for any non-static function,
+    # D for any global variable and I for any imported variable.
+    # Also find C++ and __fastcall symbols from MSVC++,
+    # which start with @ or ?.
+    lt_cv_sys_global_symbol_pipe="$AWK '"\
+"     {last_section=section; section=\$ 3};"\
+"     /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\
+"     /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
+"     /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\
+"     /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\
+"     /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\
+"     \$ 0!~/External *\|/{next};"\
+"     / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
+"     {if(hide[section]) next};"\
+"     {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\
+"     {split(\$ 0,a,/\||\r/); split(a[2],s)};"\
+"     s[1]~/^[@?]/{print f,s[1],s[1]; next};"\
+"     s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\
+"     ' prfx=^$ac_symprfx"
+  else
+    lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[	 ]\($symcode$symcode*\)[	 ][	 ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+  fi
+  lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'"
+
+  # Check to see that the pipe works correctly.
+  pipe_works=no
+
+  rm -f conftest*
+  cat > conftest.$ac_ext <<_LT_EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(void);
+void nm_test_func(void){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+_LT_EOF
+
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    # Now try to grab the symbols.
+    nlist=conftest.nm
+    if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5
+  (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && test -s "$nlist"; then
+      # Try sorting and uniquifying the output.
+      if sort "$nlist" | uniq > "$nlist"T; then
+	mv -f "$nlist"T "$nlist"
+      else
+	rm -f "$nlist"T
+      fi
+
+      # Make sure that we snagged all the symbols we need.
+      if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
+	if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
+	  cat <<_LT_EOF > conftest.$ac_ext
+/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests.  */
+#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE
+/* DATA imports from DLLs on WIN32 can't be const, because runtime
+   relocations are performed -- see ld's documentation on pseudo-relocs.  */
+# define LT_DLSYM_CONST
+#elif defined __osf__
+/* This system does not cope well with relocations in const data.  */
+# define LT_DLSYM_CONST
+#else
+# define LT_DLSYM_CONST const
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+_LT_EOF
+	  # Now generate the symbol file.
+	  eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
+
+	  cat <<_LT_EOF >> conftest.$ac_ext
+
+/* The mapping between symbol names and symbols.  */
+LT_DLSYM_CONST struct {
+  const char *name;
+  void       *address;
+}
+lt__PROGRAM__LTX_preloaded_symbols[] =
+{
+  { "@PROGRAM@", (void *) 0 },
+_LT_EOF
+	  $SED "s/^$symcode$symcode* .* \(.*\)$/  {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
+	  cat <<\_LT_EOF >> conftest.$ac_ext
+  {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+  return lt__PROGRAM__LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+_LT_EOF
+	  # Now try linking the two files.
+	  mv conftest.$ac_objext conftstm.$ac_objext
+	  lt_globsym_save_LIBS=$LIBS
+	  lt_globsym_save_CFLAGS=$CFLAGS
+	  LIBS=conftstm.$ac_objext
+	  CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag"
+	  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && test -s conftest$ac_exeext; then
+	    pipe_works=yes
+	  fi
+	  LIBS=$lt_globsym_save_LIBS
+	  CFLAGS=$lt_globsym_save_CFLAGS
+	else
+	  echo "cannot find nm_test_func in $nlist" >&5
+	fi
+      else
+	echo "cannot find nm_test_var in $nlist" >&5
+      fi
+    else
+      echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5
+    fi
+  else
+    echo "$progname: failed program was:" >&5
+    cat conftest.$ac_ext >&5
+  fi
+  rm -rf conftest* conftst*
+
+  # Do not use the global_symbol_pipe unless it works.
+  if test yes = "$pipe_works"; then
+    break
+  else
+    lt_cv_sys_global_symbol_pipe=
+  fi
+done
+
+fi
+
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+  lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5
+$as_echo "failed" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
+$as_echo "ok" >&6; }
+fi
+
+# Response file support.
+if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+  nm_file_list_spec='@'
+elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then
+  nm_file_list_spec='@'
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5
+$as_echo_n "checking for sysroot... " >&6; }
+
+# Check whether --with-sysroot was given.
+if test "${with_sysroot+set}" = set; then :
+  withval=$with_sysroot;
+else
+  with_sysroot=no
+fi
+
+
+lt_sysroot=
+case $with_sysroot in #(
+ yes)
+   if test yes = "$GCC"; then
+     lt_sysroot=`$CC --print-sysroot 2>/dev/null`
+   fi
+   ;; #(
+ /*)
+   lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"`
+   ;; #(
+ no|'')
+   ;; #(
+ *)
+   { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_sysroot" >&5
+$as_echo "$with_sysroot" >&6; }
+   as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5
+   ;;
+esac
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5
+$as_echo "${lt_sysroot:-no}" >&6; }
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a working dd" >&5
+$as_echo_n "checking for a working dd... " >&6; }
+if ${ac_cv_path_lt_DD+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  printf 0123456789abcdef0123456789abcdef >conftest.i
+cat conftest.i conftest.i >conftest2.i
+: ${lt_DD:=$DD}
+if test -z "$lt_DD"; then
+  ac_path_lt_DD_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in dd; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_lt_DD="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_lt_DD" || continue
+if "$ac_path_lt_DD" bs=32 count=1 <conftest2.i >conftest.out 2>/dev/null; then
+  cmp -s conftest.i conftest.out \
+  && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=:
+fi
+      $ac_path_lt_DD_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_lt_DD"; then
+    :
+  fi
+else
+  ac_cv_path_lt_DD=$lt_DD
+fi
+
+rm -f conftest.i conftest2.i conftest.out
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_lt_DD" >&5
+$as_echo "$ac_cv_path_lt_DD" >&6; }
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to truncate binary pipes" >&5
+$as_echo_n "checking how to truncate binary pipes... " >&6; }
+if ${lt_cv_truncate_bin+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  printf 0123456789abcdef0123456789abcdef >conftest.i
+cat conftest.i conftest.i >conftest2.i
+lt_cv_truncate_bin=
+if "$ac_cv_path_lt_DD" bs=32 count=1 <conftest2.i >conftest.out 2>/dev/null; then
+  cmp -s conftest.i conftest.out \
+  && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1"
+fi
+rm -f conftest.i conftest2.i conftest.out
+test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q"
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_truncate_bin" >&5
+$as_echo "$lt_cv_truncate_bin" >&6; }
+
+
+
+
+
+
+
+# Calculate cc_basename.  Skip known compiler wrappers and cross-prefix.
+func_cc_basename ()
+{
+    for cc_temp in $*""; do
+      case $cc_temp in
+        compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+        distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+        \-*) ;;
+        *) break;;
+      esac
+    done
+    func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+}
+
+# Check whether --enable-libtool-lock was given.
+if test "${enable_libtool_lock+set}" = set; then :
+  enableval=$enable_libtool_lock;
+fi
+
+test no = "$enable_libtool_lock" || enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+  # Find out what ABI is being produced by ac_compile, and set mode
+  # options accordingly.
+  echo 'int i;' > conftest.$ac_ext
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    case `/usr/bin/file conftest.$ac_objext` in
+      *ELF-32*)
+	HPUX_IA64_MODE=32
+	;;
+      *ELF-64*)
+	HPUX_IA64_MODE=64
+	;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+*-*-irix6*)
+  # Find out what ABI is being produced by ac_compile, and set linker
+  # options accordingly.
+  echo '#line '$LINENO' "configure"' > conftest.$ac_ext
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    if test yes = "$lt_cv_prog_gnu_ld"; then
+      case `/usr/bin/file conftest.$ac_objext` in
+	*32-bit*)
+	  LD="${LD-ld} -melf32bsmip"
+	  ;;
+	*N32*)
+	  LD="${LD-ld} -melf32bmipn32"
+	  ;;
+	*64-bit*)
+	  LD="${LD-ld} -melf64bmip"
+	;;
+      esac
+    else
+      case `/usr/bin/file conftest.$ac_objext` in
+	*32-bit*)
+	  LD="${LD-ld} -32"
+	  ;;
+	*N32*)
+	  LD="${LD-ld} -n32"
+	  ;;
+	*64-bit*)
+	  LD="${LD-ld} -64"
+	  ;;
+      esac
+    fi
+  fi
+  rm -rf conftest*
+  ;;
+
+mips64*-*linux*)
+  # Find out what ABI is being produced by ac_compile, and set linker
+  # options accordingly.
+  echo '#line '$LINENO' "configure"' > conftest.$ac_ext
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    emul=elf
+    case `/usr/bin/file conftest.$ac_objext` in
+      *32-bit*)
+	emul="${emul}32"
+	;;
+      *64-bit*)
+	emul="${emul}64"
+	;;
+    esac
+    case `/usr/bin/file conftest.$ac_objext` in
+      *MSB*)
+	emul="${emul}btsmip"
+	;;
+      *LSB*)
+	emul="${emul}ltsmip"
+	;;
+    esac
+    case `/usr/bin/file conftest.$ac_objext` in
+      *N32*)
+	emul="${emul}n32"
+	;;
+    esac
+    LD="${LD-ld} -m $emul"
+  fi
+  rm -rf conftest*
+  ;;
+
+x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \
+s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
+  # Find out what ABI is being produced by ac_compile, and set linker
+  # options accordingly.  Note that the listed cases only cover the
+  # situations where additional linker options are needed (such as when
+  # doing 32-bit compilation for a host where ld defaults to 64-bit, or
+  # vice versa); the common cases where no linker options are needed do
+  # not appear in the list.
+  echo 'int i;' > conftest.$ac_ext
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    case `/usr/bin/file conftest.o` in
+      *32-bit*)
+	case $host in
+	  x86_64-*kfreebsd*-gnu)
+	    LD="${LD-ld} -m elf_i386_fbsd"
+	    ;;
+	  x86_64-*linux*)
+	    case `/usr/bin/file conftest.o` in
+	      *x86-64*)
+		LD="${LD-ld} -m elf32_x86_64"
+		;;
+	      *)
+		LD="${LD-ld} -m elf_i386"
+		;;
+	    esac
+	    ;;
+	  powerpc64le-*linux*)
+	    LD="${LD-ld} -m elf32lppclinux"
+	    ;;
+	  powerpc64-*linux*)
+	    LD="${LD-ld} -m elf32ppclinux"
+	    ;;
+	  s390x-*linux*)
+	    LD="${LD-ld} -m elf_s390"
+	    ;;
+	  sparc64-*linux*)
+	    LD="${LD-ld} -m elf32_sparc"
+	    ;;
+	esac
+	;;
+      *64-bit*)
+	case $host in
+	  x86_64-*kfreebsd*-gnu)
+	    LD="${LD-ld} -m elf_x86_64_fbsd"
+	    ;;
+	  x86_64-*linux*)
+	    LD="${LD-ld} -m elf_x86_64"
+	    ;;
+	  powerpcle-*linux*)
+	    LD="${LD-ld} -m elf64lppc"
+	    ;;
+	  powerpc-*linux*)
+	    LD="${LD-ld} -m elf64ppc"
+	    ;;
+	  s390*-*linux*|s390*-*tpf*)
+	    LD="${LD-ld} -m elf64_s390"
+	    ;;
+	  sparc*-*linux*)
+	    LD="${LD-ld} -m elf64_sparc"
+	    ;;
+	esac
+	;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+
+*-*-sco3.2v5*)
+  # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+  SAVE_CFLAGS=$CFLAGS
+  CFLAGS="$CFLAGS -belf"
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5
+$as_echo_n "checking whether the C compiler needs -belf... " >&6; }
+if ${lt_cv_cc_needs_belf+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+     cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  lt_cv_cc_needs_belf=yes
+else
+  lt_cv_cc_needs_belf=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+     ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5
+$as_echo "$lt_cv_cc_needs_belf" >&6; }
+  if test yes != "$lt_cv_cc_needs_belf"; then
+    # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+    CFLAGS=$SAVE_CFLAGS
+  fi
+  ;;
+*-*solaris*)
+  # Find out what ABI is being produced by ac_compile, and set linker
+  # options accordingly.
+  echo 'int i;' > conftest.$ac_ext
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    case `/usr/bin/file conftest.o` in
+    *64-bit*)
+      case $lt_cv_prog_gnu_ld in
+      yes*)
+        case $host in
+        i?86-*-solaris*|x86_64-*-solaris*)
+          LD="${LD-ld} -m elf_x86_64"
+          ;;
+        sparc*-*-solaris*)
+          LD="${LD-ld} -m elf64_sparc"
+          ;;
+        esac
+        # GNU ld 2.21 introduced _sol2 emulations.  Use them if available.
+        if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then
+          LD=${LD-ld}_sol2
+        fi
+        ;;
+      *)
+	if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
+	  LD="${LD-ld} -64"
+	fi
+	;;
+      esac
+      ;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+esac
+
+need_locks=$enable_libtool_lock
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args.
+set dummy ${ac_tool_prefix}mt; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_MANIFEST_TOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$MANIFEST_TOOL"; then
+  ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL
+if test -n "$MANIFEST_TOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5
+$as_echo "$MANIFEST_TOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_MANIFEST_TOOL"; then
+  ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL
+  # Extract the first word of "mt", so it can be a program name with args.
+set dummy mt; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_MANIFEST_TOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_MANIFEST_TOOL"; then
+  ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_MANIFEST_TOOL="mt"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL
+if test -n "$ac_ct_MANIFEST_TOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5
+$as_echo "$ac_ct_MANIFEST_TOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_MANIFEST_TOOL" = x; then
+    MANIFEST_TOOL=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL
+  fi
+else
+  MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL"
+fi
+
+test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5
+$as_echo_n "checking if $MANIFEST_TOOL is a manifest tool... " >&6; }
+if ${lt_cv_path_mainfest_tool+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_path_mainfest_tool=no
+  echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5
+  $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out
+  cat conftest.err >&5
+  if $GREP 'Manifest Tool' conftest.out > /dev/null; then
+    lt_cv_path_mainfest_tool=yes
+  fi
+  rm -f conftest*
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5
+$as_echo "$lt_cv_path_mainfest_tool" >&6; }
+if test yes != "$lt_cv_path_mainfest_tool"; then
+  MANIFEST_TOOL=:
+fi
+
+
+
+
+
+
+  case $host_os in
+    rhapsody* | darwin*)
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args.
+set dummy ${ac_tool_prefix}dsymutil; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DSYMUTIL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$DSYMUTIL"; then
+  ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+DSYMUTIL=$ac_cv_prog_DSYMUTIL
+if test -n "$DSYMUTIL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5
+$as_echo "$DSYMUTIL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_DSYMUTIL"; then
+  ac_ct_DSYMUTIL=$DSYMUTIL
+  # Extract the first word of "dsymutil", so it can be a program name with args.
+set dummy dsymutil; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_DSYMUTIL"; then
+  ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_DSYMUTIL="dsymutil"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL
+if test -n "$ac_ct_DSYMUTIL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5
+$as_echo "$ac_ct_DSYMUTIL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_DSYMUTIL" = x; then
+    DSYMUTIL=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    DSYMUTIL=$ac_ct_DSYMUTIL
+  fi
+else
+  DSYMUTIL="$ac_cv_prog_DSYMUTIL"
+fi
+
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args.
+set dummy ${ac_tool_prefix}nmedit; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_NMEDIT+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$NMEDIT"; then
+  ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+NMEDIT=$ac_cv_prog_NMEDIT
+if test -n "$NMEDIT"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5
+$as_echo "$NMEDIT" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_NMEDIT"; then
+  ac_ct_NMEDIT=$NMEDIT
+  # Extract the first word of "nmedit", so it can be a program name with args.
+set dummy nmedit; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_NMEDIT"; then
+  ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_NMEDIT="nmedit"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT
+if test -n "$ac_ct_NMEDIT"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5
+$as_echo "$ac_ct_NMEDIT" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_NMEDIT" = x; then
+    NMEDIT=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    NMEDIT=$ac_ct_NMEDIT
+  fi
+else
+  NMEDIT="$ac_cv_prog_NMEDIT"
+fi
+
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args.
+set dummy ${ac_tool_prefix}lipo; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_LIPO+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$LIPO"; then
+  ac_cv_prog_LIPO="$LIPO" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_LIPO="${ac_tool_prefix}lipo"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+LIPO=$ac_cv_prog_LIPO
+if test -n "$LIPO"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5
+$as_echo "$LIPO" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_LIPO"; then
+  ac_ct_LIPO=$LIPO
+  # Extract the first word of "lipo", so it can be a program name with args.
+set dummy lipo; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_LIPO+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_LIPO"; then
+  ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_LIPO="lipo"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO
+if test -n "$ac_ct_LIPO"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5
+$as_echo "$ac_ct_LIPO" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_LIPO" = x; then
+    LIPO=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    LIPO=$ac_ct_LIPO
+  fi
+else
+  LIPO="$ac_cv_prog_LIPO"
+fi
+
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args.
+set dummy ${ac_tool_prefix}otool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_OTOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$OTOOL"; then
+  ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_OTOOL="${ac_tool_prefix}otool"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+OTOOL=$ac_cv_prog_OTOOL
+if test -n "$OTOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5
+$as_echo "$OTOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OTOOL"; then
+  ac_ct_OTOOL=$OTOOL
+  # Extract the first word of "otool", so it can be a program name with args.
+set dummy otool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_OTOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_OTOOL"; then
+  ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_OTOOL="otool"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL
+if test -n "$ac_ct_OTOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5
+$as_echo "$ac_ct_OTOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_OTOOL" = x; then
+    OTOOL=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    OTOOL=$ac_ct_OTOOL
+  fi
+else
+  OTOOL="$ac_cv_prog_OTOOL"
+fi
+
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args.
+set dummy ${ac_tool_prefix}otool64; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_OTOOL64+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$OTOOL64"; then
+  ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+OTOOL64=$ac_cv_prog_OTOOL64
+if test -n "$OTOOL64"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5
+$as_echo "$OTOOL64" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OTOOL64"; then
+  ac_ct_OTOOL64=$OTOOL64
+  # Extract the first word of "otool64", so it can be a program name with args.
+set dummy otool64; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_OTOOL64"; then
+  ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_OTOOL64="otool64"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64
+if test -n "$ac_ct_OTOOL64"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5
+$as_echo "$ac_ct_OTOOL64" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_OTOOL64" = x; then
+    OTOOL64=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    OTOOL64=$ac_ct_OTOOL64
+  fi
+else
+  OTOOL64="$ac_cv_prog_OTOOL64"
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5
+$as_echo_n "checking for -single_module linker flag... " >&6; }
+if ${lt_cv_apple_cc_single_mod+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_apple_cc_single_mod=no
+      if test -z "$LT_MULTI_MODULE"; then
+	# By default we will add the -single_module flag. You can override
+	# by either setting the environment variable LT_MULTI_MODULE
+	# non-empty at configure time, or by adding -multi_module to the
+	# link flags.
+	rm -rf libconftest.dylib*
+	echo "int foo(void){return 1;}" > conftest.c
+	echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+-dynamiclib -Wl,-single_module conftest.c" >&5
+	$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+	  -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
+        _lt_result=$?
+	# If there is a non-empty error log, and "single_module"
+	# appears in it, assume the flag caused a linker warning
+        if test -s conftest.err && $GREP single_module conftest.err; then
+	  cat conftest.err >&5
+	# Otherwise, if the output was created with a 0 exit code from
+	# the compiler, it worked.
+	elif test -f libconftest.dylib && test 0 = "$_lt_result"; then
+	  lt_cv_apple_cc_single_mod=yes
+	else
+	  cat conftest.err >&5
+	fi
+	rm -rf libconftest.dylib*
+	rm -f conftest.*
+      fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5
+$as_echo "$lt_cv_apple_cc_single_mod" >&6; }
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5
+$as_echo_n "checking for -exported_symbols_list linker flag... " >&6; }
+if ${lt_cv_ld_exported_symbols_list+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_ld_exported_symbols_list=no
+      save_LDFLAGS=$LDFLAGS
+      echo "_main" > conftest.sym
+      LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  lt_cv_ld_exported_symbols_list=yes
+else
+  lt_cv_ld_exported_symbols_list=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+	LDFLAGS=$save_LDFLAGS
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5
+$as_echo "$lt_cv_ld_exported_symbols_list" >&6; }
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5
+$as_echo_n "checking for -force_load linker flag... " >&6; }
+if ${lt_cv_ld_force_load+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_ld_force_load=no
+      cat > conftest.c << _LT_EOF
+int forced_loaded() { return 2;}
+_LT_EOF
+      echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5
+      $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5
+      echo "$AR cru libconftest.a conftest.o" >&5
+      $AR cru libconftest.a conftest.o 2>&5
+      echo "$RANLIB libconftest.a" >&5
+      $RANLIB libconftest.a 2>&5
+      cat > conftest.c << _LT_EOF
+int main() { return 0;}
+_LT_EOF
+      echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5
+      $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
+      _lt_result=$?
+      if test -s conftest.err && $GREP force_load conftest.err; then
+	cat conftest.err >&5
+      elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then
+	lt_cv_ld_force_load=yes
+      else
+	cat conftest.err >&5
+      fi
+        rm -f conftest.err libconftest.a conftest conftest.c
+        rm -rf conftest.dSYM
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5
+$as_echo "$lt_cv_ld_force_load" >&6; }
+    case $host_os in
+    rhapsody* | darwin1.[012])
+      _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;;
+    darwin1.*)
+      _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
+    darwin*) # darwin 5.x on
+      # if running on 10.5 or later, the deployment target defaults
+      # to the OS version, if on x86, and 10.4, the deployment
+      # target defaults to 10.4. Don't you love it?
+      case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
+	10.0,*86*-darwin8*|10.0,*-darwin[91]*)
+	  _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
+	10.[012][,.]*)
+	  _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
+	10.*)
+	  _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
+      esac
+    ;;
+  esac
+    if test yes = "$lt_cv_apple_cc_single_mod"; then
+      _lt_dar_single_mod='$single_module'
+    fi
+    if test yes = "$lt_cv_ld_exported_symbols_list"; then
+      _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym'
+    else
+      _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib'
+    fi
+    if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then
+      _lt_dsymutil='~$DSYMUTIL $lib || :'
+    else
+      _lt_dsymutil=
+    fi
+    ;;
+  esac
+
+# func_munge_path_list VARIABLE PATH
+# -----------------------------------
+# VARIABLE is name of variable containing _space_ separated list of
+# directories to be munged by the contents of PATH, which is string
+# having a format:
+# "DIR[:DIR]:"
+#       string "DIR[ DIR]" will be prepended to VARIABLE
+# ":DIR[:DIR]"
+#       string "DIR[ DIR]" will be appended to VARIABLE
+# "DIRP[:DIRP]::[DIRA:]DIRA"
+#       string "DIRP[ DIRP]" will be prepended to VARIABLE and string
+#       "DIRA[ DIRA]" will be appended to VARIABLE
+# "DIR[:DIR]"
+#       VARIABLE will be replaced by "DIR[ DIR]"
+func_munge_path_list ()
+{
+    case x$2 in
+    x)
+        ;;
+    *:)
+        eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\"
+        ;;
+    x:*)
+        eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\"
+        ;;
+    *::*)
+        eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\"
+        eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\"
+        ;;
+    *)
+        eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\"
+        ;;
+    esac
+}
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if ${ac_cv_header_stdc+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_header_stdc=yes
+else
+  ac_cv_header_stdc=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "memchr" >/dev/null 2>&1; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "free" >/dev/null 2>&1; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+  if test "$cross_compiling" = yes; then :
+  :
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+		   (('a' <= (c) && (c) <= 'i') \
+		     || ('j' <= (c) && (c) <= 'r') \
+		     || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+  int i;
+  for (i = 0; i < 256; i++)
+    if (XOR (islower (i), ISLOWER (i))
+	|| toupper (i) != TOUPPER (i))
+      return 2;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+		  inttypes.h stdint.h unistd.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in dlfcn.h
+do :
+  ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default
+"
+if test "x$ac_cv_header_dlfcn_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_DLFCN_H 1
+_ACEOF
+
+fi
+
+done
+
+
+
+
+func_stripname_cnf ()
+{
+  case $2 in
+  .*) func_stripname_result=`$ECHO "$3" | $SED "s%^$1%%; s%\\\\$2\$%%"`;;
+  *)  func_stripname_result=`$ECHO "$3" | $SED "s%^$1%%; s%$2\$%%"`;;
+  esac
+} # func_stripname_cnf
+
+
+
+
+
+# Set options
+
+
+
+        enable_dlopen=no
+
+
+
+            # Check whether --enable-shared was given.
+if test "${enable_shared+set}" = set; then :
+  enableval=$enable_shared; p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_shared=yes ;;
+    no) enable_shared=no ;;
+    *)
+      enable_shared=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
+      for pkg in $enableval; do
+	IFS=$lt_save_ifs
+	if test "X$pkg" = "X$p"; then
+	  enable_shared=yes
+	fi
+      done
+      IFS=$lt_save_ifs
+      ;;
+    esac
+else
+  enable_shared=yes
+fi
+
+
+
+
+
+
+
+
+
+  # Check whether --enable-static was given.
+if test "${enable_static+set}" = set; then :
+  enableval=$enable_static; p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_static=yes ;;
+    no) enable_static=no ;;
+    *)
+     enable_static=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
+      for pkg in $enableval; do
+	IFS=$lt_save_ifs
+	if test "X$pkg" = "X$p"; then
+	  enable_static=yes
+	fi
+      done
+      IFS=$lt_save_ifs
+      ;;
+    esac
+else
+  enable_static=yes
+fi
+
+
+
+
+
+
+
+
+
+
+# Check whether --with-pic was given.
+if test "${with_pic+set}" = set; then :
+  withval=$with_pic; lt_p=${PACKAGE-default}
+    case $withval in
+    yes|no) pic_mode=$withval ;;
+    *)
+      pic_mode=default
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
+      for lt_pkg in $withval; do
+	IFS=$lt_save_ifs
+	if test "X$lt_pkg" = "X$lt_p"; then
+	  pic_mode=yes
+	fi
+      done
+      IFS=$lt_save_ifs
+      ;;
+    esac
+else
+  pic_mode=default
+fi
+
+
+
+
+
+
+
+
+  # Check whether --enable-fast-install was given.
+if test "${enable_fast_install+set}" = set; then :
+  enableval=$enable_fast_install; p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_fast_install=yes ;;
+    no) enable_fast_install=no ;;
+    *)
+      enable_fast_install=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
+      for pkg in $enableval; do
+	IFS=$lt_save_ifs
+	if test "X$pkg" = "X$p"; then
+	  enable_fast_install=yes
+	fi
+      done
+      IFS=$lt_save_ifs
+      ;;
+    esac
+else
+  enable_fast_install=yes
+fi
+
+
+
+
+
+
+
+
+  shared_archive_member_spec=
+case $host,$enable_shared in
+power*-*-aix[5-9]*,yes)
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking which variant of shared library versioning to provide" >&5
+$as_echo_n "checking which variant of shared library versioning to provide... " >&6; }
+
+# Check whether --with-aix-soname was given.
+if test "${with_aix_soname+set}" = set; then :
+  withval=$with_aix_soname; case $withval in
+    aix|svr4|both)
+      ;;
+    *)
+      as_fn_error $? "Unknown argument to --with-aix-soname" "$LINENO" 5
+      ;;
+    esac
+    lt_cv_with_aix_soname=$with_aix_soname
+else
+  if ${lt_cv_with_aix_soname+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_with_aix_soname=aix
+fi
+
+    with_aix_soname=$lt_cv_with_aix_soname
+fi
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_aix_soname" >&5
+$as_echo "$with_aix_soname" >&6; }
+  if test aix != "$with_aix_soname"; then
+    # For the AIX way of multilib, we name the shared archive member
+    # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o',
+    # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File.
+    # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag,
+    # the AIX toolchain works better with OBJECT_MODE set (default 32).
+    if test 64 = "${OBJECT_MODE-32}"; then
+      shared_archive_member_spec=shr_64
+    else
+      shared_archive_member_spec=shr
+    fi
+  fi
+  ;;
+*)
+  with_aix_soname=aix
+  ;;
+esac
+
+
+
+
+
+
+
+
+
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS=$ltmain
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+test -z "$LN_S" && LN_S="ln -s"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+if test -n "${ZSH_VERSION+set}"; then
+   setopt NO_GLOB_SUBST
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5
+$as_echo_n "checking for objdir... " >&6; }
+if ${lt_cv_objdir+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+  lt_cv_objdir=.libs
+else
+  # MS-DOS does not allow filenames that begin with a dot.
+  lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5
+$as_echo "$lt_cv_objdir" >&6; }
+objdir=$lt_cv_objdir
+
+
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define LT_OBJDIR "$lt_cv_objdir/"
+_ACEOF
+
+
+
+
+case $host_os in
+aix3*)
+  # AIX sometimes has problems with the GCC collect2 program.  For some
+  # reason, if we set the COLLECT_NAMES environment variable, the problems
+  # vanish in a puff of smoke.
+  if test set != "${COLLECT_NAMES+set}"; then
+    COLLECT_NAMES=
+    export COLLECT_NAMES
+  fi
+  ;;
+esac
+
+# Global variables:
+ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a '.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+
+with_gnu_ld=$lt_cv_prog_gnu_ld
+
+old_CC=$CC
+old_CFLAGS=$CFLAGS
+
+# Set sane defaults for various variables
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
+test -z "$LD" && LD=ld
+test -z "$ac_objext" && ac_objext=o
+
+func_cc_basename $compiler
+cc_basename=$func_cc_basename_result
+
+
+# Only perform the check for file, if the check method requires it
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+case $deplibs_check_method in
+file_magic*)
+  if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5
+$as_echo_n "checking for ${ac_tool_prefix}file... " >&6; }
+if ${lt_cv_path_MAGIC_CMD+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $MAGIC_CMD in
+[\\/*] |  ?:[\\/]*)
+  lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path.
+  ;;
+*)
+  lt_save_MAGIC_CMD=$MAGIC_CMD
+  lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
+  ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
+  for ac_dir in $ac_dummy; do
+    IFS=$lt_save_ifs
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/${ac_tool_prefix}file"; then
+      lt_cv_path_MAGIC_CMD=$ac_dir/"${ac_tool_prefix}file"
+      if test -n "$file_magic_test_file"; then
+	case $deplibs_check_method in
+	"file_magic "*)
+	  file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+	  MAGIC_CMD=$lt_cv_path_MAGIC_CMD
+	  if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+	    $EGREP "$file_magic_regex" > /dev/null; then
+	    :
+	  else
+	    cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such.  This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem.  Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+	  fi ;;
+	esac
+      fi
+      break
+    fi
+  done
+  IFS=$lt_save_ifs
+  MAGIC_CMD=$lt_save_MAGIC_CMD
+  ;;
+esac
+fi
+
+MAGIC_CMD=$lt_cv_path_MAGIC_CMD
+if test -n "$MAGIC_CMD"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
+$as_echo "$MAGIC_CMD" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+
+
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+  if test -n "$ac_tool_prefix"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5
+$as_echo_n "checking for file... " >&6; }
+if ${lt_cv_path_MAGIC_CMD+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $MAGIC_CMD in
+[\\/*] |  ?:[\\/]*)
+  lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path.
+  ;;
+*)
+  lt_save_MAGIC_CMD=$MAGIC_CMD
+  lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
+  ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
+  for ac_dir in $ac_dummy; do
+    IFS=$lt_save_ifs
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/file"; then
+      lt_cv_path_MAGIC_CMD=$ac_dir/"file"
+      if test -n "$file_magic_test_file"; then
+	case $deplibs_check_method in
+	"file_magic "*)
+	  file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+	  MAGIC_CMD=$lt_cv_path_MAGIC_CMD
+	  if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+	    $EGREP "$file_magic_regex" > /dev/null; then
+	    :
+	  else
+	    cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such.  This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem.  Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+	  fi ;;
+	esac
+      fi
+      break
+    fi
+  done
+  IFS=$lt_save_ifs
+  MAGIC_CMD=$lt_save_MAGIC_CMD
+  ;;
+esac
+fi
+
+MAGIC_CMD=$lt_cv_path_MAGIC_CMD
+if test -n "$MAGIC_CMD"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
+$as_echo "$MAGIC_CMD" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  else
+    MAGIC_CMD=:
+  fi
+fi
+
+  fi
+  ;;
+esac
+
+# Use C for the default configuration in the libtool script
+
+lt_save_CC=$CC
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+objext=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}'
+
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+# Save the default compiler, since it gets overwritten when the other
+# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
+compiler_DEFAULT=$CC
+
+# save warnings/boilerplate of simple test code
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+
+
+if test -n "$compiler"; then
+
+lt_prog_compiler_no_builtin_flag=
+
+if test yes = "$GCC"; then
+  case $cc_basename in
+  nvcc*)
+    lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;;
+  *)
+    lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;;
+  esac
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5
+$as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; }
+if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_rtti_exceptions=no
+   ac_outfile=conftest.$ac_objext
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+   lt_compiler_flag="-fno-rtti -fno-exceptions"  ## exclude from sc_useless_quotes_in_assignment
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   # The option is referenced via a variable to avoid confusing sed.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s "$ac_outfile"; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings other than the usual output.
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_rtti_exceptions=yes
+     fi
+   fi
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5
+$as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; }
+
+if test yes = "$lt_cv_prog_compiler_rtti_exceptions"; then
+    lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions"
+else
+    :
+fi
+
+fi
+
+
+
+
+
+
+  lt_prog_compiler_wl=
+lt_prog_compiler_pic=
+lt_prog_compiler_static=
+
+
+  if test yes = "$GCC"; then
+    lt_prog_compiler_wl='-Wl,'
+    lt_prog_compiler_static='-static'
+
+    case $host_os in
+      aix*)
+      # All AIX code is PIC.
+      if test ia64 = "$host_cpu"; then
+	# AIX 5 now supports IA64 processor
+	lt_prog_compiler_static='-Bstatic'
+      fi
+      lt_prog_compiler_pic='-fPIC'
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            lt_prog_compiler_pic='-fPIC'
+        ;;
+      m68k)
+            # FIXME: we need at least 68020 code to build shared libraries, but
+            # adding the '-m68020' flag to GCC prevents building anything better,
+            # like '-m68040'.
+            lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4'
+        ;;
+      esac
+      ;;
+
+    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+
+    mingw* | cygwin* | pw32* | os2* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      # Although the cygwin gcc ignores -fPIC, still need this for old-style
+      # (--disable-auto-import) libraries
+      lt_prog_compiler_pic='-DDLL_EXPORT'
+      case $host_os in
+      os2*)
+	lt_prog_compiler_static='$wl-static'
+	;;
+      esac
+      ;;
+
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      lt_prog_compiler_pic='-fno-common'
+      ;;
+
+    haiku*)
+      # PIC is the default for Haiku.
+      # The "-static" flag exists, but is broken.
+      lt_prog_compiler_static=
+      ;;
+
+    hpux*)
+      # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+      # PA HP-UX.  On IA64 HP-UX, PIC is the default but the pic flag
+      # sets the default TLS model and affects inlining.
+      case $host_cpu in
+      hppa*64*)
+	# +Z the default
+	;;
+      *)
+	lt_prog_compiler_pic='-fPIC'
+	;;
+      esac
+      ;;
+
+    interix[3-9]*)
+      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+      # Instead, we relocate shared libraries at runtime.
+      ;;
+
+    msdosdjgpp*)
+      # Just because we use GCC doesn't mean we suddenly get shared libraries
+      # on systems that don't support them.
+      lt_prog_compiler_can_build_shared=no
+      enable_shared=no
+      ;;
+
+    *nto* | *qnx*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      lt_prog_compiler_pic='-fPIC -shared'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	lt_prog_compiler_pic=-Kconform_pic
+      fi
+      ;;
+
+    *)
+      lt_prog_compiler_pic='-fPIC'
+      ;;
+    esac
+
+    case $cc_basename in
+    nvcc*) # Cuda Compiler Driver 2.2
+      lt_prog_compiler_wl='-Xlinker '
+      if test -n "$lt_prog_compiler_pic"; then
+        lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic"
+      fi
+      ;;
+    esac
+  else
+    # PORTME Check for flag to pass linker flags through the system compiler.
+    case $host_os in
+    aix*)
+      lt_prog_compiler_wl='-Wl,'
+      if test ia64 = "$host_cpu"; then
+	# AIX 5 now supports IA64 processor
+	lt_prog_compiler_static='-Bstatic'
+      else
+	lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp'
+      fi
+      ;;
+
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      lt_prog_compiler_pic='-fno-common'
+      case $cc_basename in
+      nagfor*)
+        # NAG Fortran compiler
+        lt_prog_compiler_wl='-Wl,-Wl,,'
+        lt_prog_compiler_pic='-PIC'
+        lt_prog_compiler_static='-Bstatic'
+        ;;
+      esac
+      ;;
+
+    mingw* | cygwin* | pw32* | os2* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      lt_prog_compiler_pic='-DDLL_EXPORT'
+      case $host_os in
+      os2*)
+	lt_prog_compiler_static='$wl-static'
+	;;
+      esac
+      ;;
+
+    hpux9* | hpux10* | hpux11*)
+      lt_prog_compiler_wl='-Wl,'
+      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+      # not for PA HP-UX.
+      case $host_cpu in
+      hppa*64*|ia64*)
+	# +Z the default
+	;;
+      *)
+	lt_prog_compiler_pic='+Z'
+	;;
+      esac
+      # Is there a better lt_prog_compiler_static that works with the bundled CC?
+      lt_prog_compiler_static='$wl-a ${wl}archive'
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      lt_prog_compiler_wl='-Wl,'
+      # PIC (with -KPIC) is the default.
+      lt_prog_compiler_static='-non_shared'
+      ;;
+
+    linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+      case $cc_basename in
+      # old Intel for x86_64, which still supported -KPIC.
+      ecc*)
+	lt_prog_compiler_wl='-Wl,'
+	lt_prog_compiler_pic='-KPIC'
+	lt_prog_compiler_static='-static'
+        ;;
+      # icc used to be incompatible with GCC.
+      # ICC 10 doesn't accept -KPIC any more.
+      icc* | ifort*)
+	lt_prog_compiler_wl='-Wl,'
+	lt_prog_compiler_pic='-fPIC'
+	lt_prog_compiler_static='-static'
+        ;;
+      # Lahey Fortran 8.1.
+      lf95*)
+	lt_prog_compiler_wl='-Wl,'
+	lt_prog_compiler_pic='--shared'
+	lt_prog_compiler_static='--static'
+	;;
+      nagfor*)
+	# NAG Fortran compiler
+	lt_prog_compiler_wl='-Wl,-Wl,,'
+	lt_prog_compiler_pic='-PIC'
+	lt_prog_compiler_static='-Bstatic'
+	;;
+      tcc*)
+	# Fabrice Bellard et al's Tiny C Compiler
+	lt_prog_compiler_wl='-Wl,'
+	lt_prog_compiler_pic='-fPIC'
+	lt_prog_compiler_static='-static'
+	;;
+      pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
+        # Portland Group compilers (*not* the Pentium gcc compiler,
+	# which looks to be a dead project)
+	lt_prog_compiler_wl='-Wl,'
+	lt_prog_compiler_pic='-fpic'
+	lt_prog_compiler_static='-Bstatic'
+        ;;
+      ccc*)
+        lt_prog_compiler_wl='-Wl,'
+        # All Alpha code is PIC.
+        lt_prog_compiler_static='-non_shared'
+        ;;
+      xl* | bgxl* | bgf* | mpixl*)
+	# IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
+	lt_prog_compiler_wl='-Wl,'
+	lt_prog_compiler_pic='-qpic'
+	lt_prog_compiler_static='-qstaticlink'
+	;;
+      *)
+	case `$CC -V 2>&1 | sed 5q` in
+	*Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*)
+	  # Sun Fortran 8.3 passes all unrecognized flags to the linker
+	  lt_prog_compiler_pic='-KPIC'
+	  lt_prog_compiler_static='-Bstatic'
+	  lt_prog_compiler_wl=''
+	  ;;
+	*Sun\ F* | *Sun*Fortran*)
+	  lt_prog_compiler_pic='-KPIC'
+	  lt_prog_compiler_static='-Bstatic'
+	  lt_prog_compiler_wl='-Qoption ld '
+	  ;;
+	*Sun\ C*)
+	  # Sun C 5.9
+	  lt_prog_compiler_pic='-KPIC'
+	  lt_prog_compiler_static='-Bstatic'
+	  lt_prog_compiler_wl='-Wl,'
+	  ;;
+        *Intel*\ [CF]*Compiler*)
+	  lt_prog_compiler_wl='-Wl,'
+	  lt_prog_compiler_pic='-fPIC'
+	  lt_prog_compiler_static='-static'
+	  ;;
+	*Portland\ Group*)
+	  lt_prog_compiler_wl='-Wl,'
+	  lt_prog_compiler_pic='-fpic'
+	  lt_prog_compiler_static='-Bstatic'
+	  ;;
+	esac
+	;;
+      esac
+      ;;
+
+    newsos6)
+      lt_prog_compiler_pic='-KPIC'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    *nto* | *qnx*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      lt_prog_compiler_pic='-fPIC -shared'
+      ;;
+
+    osf3* | osf4* | osf5*)
+      lt_prog_compiler_wl='-Wl,'
+      # All OSF/1 code is PIC.
+      lt_prog_compiler_static='-non_shared'
+      ;;
+
+    rdos*)
+      lt_prog_compiler_static='-non_shared'
+      ;;
+
+    solaris*)
+      lt_prog_compiler_pic='-KPIC'
+      lt_prog_compiler_static='-Bstatic'
+      case $cc_basename in
+      f77* | f90* | f95* | sunf77* | sunf90* | sunf95*)
+	lt_prog_compiler_wl='-Qoption ld ';;
+      *)
+	lt_prog_compiler_wl='-Wl,';;
+      esac
+      ;;
+
+    sunos4*)
+      lt_prog_compiler_wl='-Qoption ld '
+      lt_prog_compiler_pic='-PIC'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    sysv4 | sysv4.2uw2* | sysv4.3*)
+      lt_prog_compiler_wl='-Wl,'
+      lt_prog_compiler_pic='-KPIC'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	lt_prog_compiler_pic='-Kconform_pic'
+	lt_prog_compiler_static='-Bstatic'
+      fi
+      ;;
+
+    sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+      lt_prog_compiler_wl='-Wl,'
+      lt_prog_compiler_pic='-KPIC'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    unicos*)
+      lt_prog_compiler_wl='-Wl,'
+      lt_prog_compiler_can_build_shared=no
+      ;;
+
+    uts4*)
+      lt_prog_compiler_pic='-pic'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    *)
+      lt_prog_compiler_can_build_shared=no
+      ;;
+    esac
+  fi
+
+case $host_os in
+  # For platforms that do not support PIC, -DPIC is meaningless:
+  *djgpp*)
+    lt_prog_compiler_pic=
+    ;;
+  *)
+    lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC"
+    ;;
+esac
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5
+$as_echo_n "checking for $compiler option to produce PIC... " >&6; }
+if ${lt_cv_prog_compiler_pic+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_pic=$lt_prog_compiler_pic
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5
+$as_echo "$lt_cv_prog_compiler_pic" >&6; }
+lt_prog_compiler_pic=$lt_cv_prog_compiler_pic
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$lt_prog_compiler_pic"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5
+$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; }
+if ${lt_cv_prog_compiler_pic_works+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_pic_works=no
+   ac_outfile=conftest.$ac_objext
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+   lt_compiler_flag="$lt_prog_compiler_pic -DPIC"  ## exclude from sc_useless_quotes_in_assignment
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   # The option is referenced via a variable to avoid confusing sed.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s "$ac_outfile"; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings other than the usual output.
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_pic_works=yes
+     fi
+   fi
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5
+$as_echo "$lt_cv_prog_compiler_pic_works" >&6; }
+
+if test yes = "$lt_cv_prog_compiler_pic_works"; then
+    case $lt_prog_compiler_pic in
+     "" | " "*) ;;
+     *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;;
+     esac
+else
+    lt_prog_compiler_pic=
+     lt_prog_compiler_can_build_shared=no
+fi
+
+fi
+
+
+
+
+
+
+
+
+
+
+
+#
+# Check to make sure the static flag actually works.
+#
+wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5
+$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; }
+if ${lt_cv_prog_compiler_static_works+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_static_works=no
+   save_LDFLAGS=$LDFLAGS
+   LDFLAGS="$LDFLAGS $lt_tmp_static_flag"
+   echo "$lt_simple_link_test_code" > conftest.$ac_ext
+   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+     # The linker can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test -s conftest.err; then
+       # Append any errors to the config.log.
+       cat conftest.err 1>&5
+       $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+       if diff conftest.exp conftest.er2 >/dev/null; then
+         lt_cv_prog_compiler_static_works=yes
+       fi
+     else
+       lt_cv_prog_compiler_static_works=yes
+     fi
+   fi
+   $RM -r conftest*
+   LDFLAGS=$save_LDFLAGS
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5
+$as_echo "$lt_cv_prog_compiler_static_works" >&6; }
+
+if test yes = "$lt_cv_prog_compiler_static_works"; then
+    :
+else
+    lt_prog_compiler_static=
+fi
+
+
+
+
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if ${lt_cv_prog_compiler_c_o+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_c_o=no
+   $RM -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_c_o=yes
+     fi
+   fi
+   chmod u+w . 2>&5
+   $RM conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+   $RM out/* && rmdir out
+   cd ..
+   $RM -r conftest
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
+$as_echo "$lt_cv_prog_compiler_c_o" >&6; }
+
+
+
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if ${lt_cv_prog_compiler_c_o+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_c_o=no
+   $RM -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_c_o=yes
+     fi
+   fi
+   chmod u+w . 2>&5
+   $RM conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+   $RM out/* && rmdir out
+   cd ..
+   $RM -r conftest
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
+$as_echo "$lt_cv_prog_compiler_c_o" >&6; }
+
+
+
+
+hard_links=nottested
+if test no = "$lt_cv_prog_compiler_c_o" && test no != "$need_locks"; then
+  # do not overwrite the value of need_locks provided by the user
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5
+$as_echo_n "checking if we can lock with hard links... " >&6; }
+  hard_links=yes
+  $RM conftest*
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  touch conftest.a
+  ln conftest.a conftest.b 2>&5 || hard_links=no
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5
+$as_echo "$hard_links" >&6; }
+  if test no = "$hard_links"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&5
+$as_echo "$as_me: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&2;}
+    need_locks=warn
+  fi
+else
+  need_locks=no
+fi
+
+
+
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
+
+  runpath_var=
+  allow_undefined_flag=
+  always_export_symbols=no
+  archive_cmds=
+  archive_expsym_cmds=
+  compiler_needs_object=no
+  enable_shared_with_static_runtimes=no
+  export_dynamic_flag_spec=
+  export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  hardcode_automatic=no
+  hardcode_direct=no
+  hardcode_direct_absolute=no
+  hardcode_libdir_flag_spec=
+  hardcode_libdir_separator=
+  hardcode_minus_L=no
+  hardcode_shlibpath_var=unsupported
+  inherit_rpath=no
+  link_all_deplibs=unknown
+  module_cmds=
+  module_expsym_cmds=
+  old_archive_from_new_cmds=
+  old_archive_from_expsyms_cmds=
+  thread_safe_flag_spec=
+  whole_archive_flag_spec=
+  # include_expsyms should be a list of space-separated symbols to be *always*
+  # included in the symbol list
+  include_expsyms=
+  # exclude_expsyms can be an extended regexp of symbols to exclude
+  # it will be wrapped by ' (' and ')$', so one must not match beginning or
+  # end of line.  Example: 'a|bc|.*d.*' will exclude the symbols 'a' and 'bc',
+  # as well as any symbol that contains 'd'.
+  exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'
+  # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+  # platforms (ab)use it in PIC code, but their linkers get confused if
+  # the symbol is explicitly referenced.  Since portable code cannot
+  # rely on this symbol name, it's probably fine to never include it in
+  # preloaded symbol tables.
+  # Exclude shared library initialization/finalization symbols.
+  extract_expsyms_cmds=
+
+  case $host_os in
+  cygwin* | mingw* | pw32* | cegcc*)
+    # FIXME: the MSVC++ port hasn't been tested in a loooong time
+    # When not using gcc, we currently assume that we are using
+    # Microsoft Visual C++.
+    if test yes != "$GCC"; then
+      with_gnu_ld=no
+    fi
+    ;;
+  interix*)
+    # we just hope/assume this is gcc and not c89 (= MSVC++)
+    with_gnu_ld=yes
+    ;;
+  openbsd* | bitrig*)
+    with_gnu_ld=no
+    ;;
+  esac
+
+  ld_shlibs=yes
+
+  # On some targets, GNU ld is compatible enough with the native linker
+  # that we're better off using the native interface for both.
+  lt_use_gnu_ld_interface=no
+  if test yes = "$with_gnu_ld"; then
+    case $host_os in
+      aix*)
+	# The AIX port of GNU ld has always aspired to compatibility
+	# with the native linker.  However, as the warning in the GNU ld
+	# block says, versions before 2.19.5* couldn't really create working
+	# shared libraries, regardless of the interface used.
+	case `$LD -v 2>&1` in
+	  *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
+	  *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;;
+	  *\ \(GNU\ Binutils\)\ [3-9]*) ;;
+	  *)
+	    lt_use_gnu_ld_interface=yes
+	    ;;
+	esac
+	;;
+      *)
+	lt_use_gnu_ld_interface=yes
+	;;
+    esac
+  fi
+
+  if test yes = "$lt_use_gnu_ld_interface"; then
+    # If archive_cmds runs LD, not CC, wlarc should be empty
+    wlarc='$wl'
+
+    # Set some defaults for GNU ld with shared library support. These
+    # are reset later if shared libraries are not supported. Putting them
+    # here allows them to be overridden if necessary.
+    runpath_var=LD_RUN_PATH
+    hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
+    export_dynamic_flag_spec='$wl--export-dynamic'
+    # ancient GNU ld didn't support --whole-archive et. al.
+    if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
+      whole_archive_flag_spec=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
+    else
+      whole_archive_flag_spec=
+    fi
+    supports_anon_versioning=no
+    case `$LD -v | $SED -e 's/(^)\+)\s\+//' 2>&1` in
+      *GNU\ gold*) supports_anon_versioning=yes ;;
+      *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
+      *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+      *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+      *\ 2.11.*) ;; # other 2.11 versions
+      *) supports_anon_versioning=yes ;;
+    esac
+
+    # See if GNU ld supports shared libraries.
+    case $host_os in
+    aix[3-9]*)
+      # On AIX/PPC, the GNU linker is very broken
+      if test ia64 != "$host_cpu"; then
+	ld_shlibs=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.19, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support.  If you
+*** really care for shared libraries, you may want to install binutils
+*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
+*** You will then need to restart the configuration process.
+
+_LT_EOF
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+            archive_expsym_cmds=''
+        ;;
+      m68k)
+            archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+            hardcode_libdir_flag_spec='-L$libdir'
+            hardcode_minus_L=yes
+        ;;
+      esac
+      ;;
+
+    beos*)
+      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	allow_undefined_flag=unsupported
+	# Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+	# support --undefined.  This deserves some investigation.  FIXME
+	archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+      else
+	ld_shlibs=no
+      fi
+      ;;
+
+    cygwin* | mingw* | pw32* | cegcc*)
+      # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless,
+      # as there is no search path for DLLs.
+      hardcode_libdir_flag_spec='-L$libdir'
+      export_dynamic_flag_spec='$wl--export-all-symbols'
+      allow_undefined_flag=unsupported
+      always_export_symbols=no
+      enable_shared_with_static_runtimes=yes
+      export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols'
+      exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'
+
+      if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+        archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+	# If the export-symbols file already is a .def file, use it as
+	# is; otherwise, prepend EXPORTS...
+	archive_expsym_cmds='if   test DEF = "`$SED -n     -e '\''s/^[	 ]*//'\''     -e '\''/^\(;.*\)*$/d'\''     -e '\''s/^\(EXPORTS\|LIBRARY\)\([	 ].*\)*$/DEF/p'\''     -e q     $export_symbols`" ; then
+          cp $export_symbols $output_objdir/$soname.def;
+        else
+          echo EXPORTS > $output_objdir/$soname.def;
+          cat $export_symbols >> $output_objdir/$soname.def;
+        fi~
+        $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+      else
+	ld_shlibs=no
+      fi
+      ;;
+
+    haiku*)
+      archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+      link_all_deplibs=yes
+      ;;
+
+    os2*)
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_minus_L=yes
+      allow_undefined_flag=unsupported
+      shrext_cmds=.dll
+      archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+	$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+	$ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+	$ECHO EXPORTS >> $output_objdir/$libname.def~
+	emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
+	$CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+	emximp -o $lib $output_objdir/$libname.def'
+      archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+	$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+	$ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+	$ECHO EXPORTS >> $output_objdir/$libname.def~
+	prefix_cmds="$SED"~
+	if test EXPORTS = "`$SED 1q $export_symbols`"; then
+	  prefix_cmds="$prefix_cmds -e 1d";
+	fi~
+	prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
+	cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
+	$CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+	emximp -o $lib $output_objdir/$libname.def'
+      old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
+      enable_shared_with_static_runtimes=yes
+      ;;
+
+    interix[3-9]*)
+      hardcode_direct=no
+      hardcode_shlibpath_var=no
+      hardcode_libdir_flag_spec='$wl-rpath,$libdir'
+      export_dynamic_flag_spec='$wl-E'
+      # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+      # Instead, shared libraries are loaded at an image base (0x10000000 by
+      # default) and relocated if they conflict, which is a slow very memory
+      # consuming and fragmenting process.  To avoid this, we pick a random,
+      # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+      # time.  Moving up from 0x10000000 also allows more sbrk(2) space.
+      archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      archive_expsym_cmds='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      ;;
+
+    gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
+      tmp_diet=no
+      if test linux-dietlibc = "$host_os"; then
+	case $cc_basename in
+	  diet\ *) tmp_diet=yes;;	# linux-dietlibc with static linking (!diet-dyn)
+	esac
+      fi
+      if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
+	 && test no = "$tmp_diet"
+      then
+	tmp_addflag=' $pic_flag'
+	tmp_sharedflag='-shared'
+	case $cc_basename,$host_cpu in
+        pgcc*)				# Portland Group C compiler
+	  whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+	  tmp_addflag=' $pic_flag'
+	  ;;
+	pgf77* | pgf90* | pgf95* | pgfortran*)
+					# Portland Group f77 and f90 compilers
+	  whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+	  tmp_addflag=' $pic_flag -Mnomain' ;;
+	ecc*,ia64* | icc*,ia64*)	# Intel C compiler on ia64
+	  tmp_addflag=' -i_dynamic' ;;
+	efc*,ia64* | ifort*,ia64*)	# Intel Fortran compiler on ia64
+	  tmp_addflag=' -i_dynamic -nofor_main' ;;
+	ifc* | ifort*)			# Intel Fortran compiler
+	  tmp_addflag=' -nofor_main' ;;
+	lf95*)				# Lahey Fortran 8.1
+	  whole_archive_flag_spec=
+	  tmp_sharedflag='--shared' ;;
+        nagfor*)                        # NAGFOR 5.3
+          tmp_sharedflag='-Wl,-shared' ;;
+	xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below)
+	  tmp_sharedflag='-qmkshrobj'
+	  tmp_addflag= ;;
+	nvcc*)	# Cuda Compiler Driver 2.2
+	  whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+	  compiler_needs_object=yes
+	  ;;
+	esac
+	case `$CC -V 2>&1 | sed 5q` in
+	*Sun\ C*)			# Sun C 5.9
+	  whole_archive_flag_spec='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+	  compiler_needs_object=yes
+	  tmp_sharedflag='-G' ;;
+	*Sun\ F*)			# Sun Fortran 8.3
+	  tmp_sharedflag='-G' ;;
+	esac
+	archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+
+        if test yes = "$supports_anon_versioning"; then
+          archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
+            cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+            echo "local: *; };" >> $output_objdir/$libname.ver~
+            $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib'
+        fi
+
+	case $cc_basename in
+	tcc*)
+	  export_dynamic_flag_spec='-rdynamic'
+	  ;;
+	xlf* | bgf* | bgxlf* | mpixlf*)
+	  # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
+	  whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive'
+	  hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
+	  archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
+	  if test yes = "$supports_anon_versioning"; then
+	    archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
+              cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+              echo "local: *; };" >> $output_objdir/$libname.ver~
+              $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+	  fi
+	  ;;
+	esac
+      else
+        ld_shlibs=no
+      fi
+      ;;
+
+    netbsd*)
+      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+	archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+	wlarc=
+      else
+	archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+	archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+      fi
+      ;;
+
+    solaris*)
+      if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
+	ld_shlibs=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+      elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+	archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+	ld_shlibs=no
+      fi
+      ;;
+
+    sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+      case `$LD -v 2>&1` in
+        *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*)
+	ld_shlibs=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot
+*** reliably create shared libraries on SCO systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+	;;
+	*)
+	  # For security reasons, it is highly recommended that you always
+	  # use absolute paths for naming shared libraries, and exclude the
+	  # DT_RUNPATH tag from executables and libraries.  But doing so
+	  # requires that you compile everything twice, which is a pain.
+	  if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	    hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
+	    archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+	    archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+	  else
+	    ld_shlibs=no
+	  fi
+	;;
+      esac
+      ;;
+
+    sunos4*)
+      archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      wlarc=
+      hardcode_direct=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    *)
+      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+	archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+	ld_shlibs=no
+      fi
+      ;;
+    esac
+
+    if test no = "$ld_shlibs"; then
+      runpath_var=
+      hardcode_libdir_flag_spec=
+      export_dynamic_flag_spec=
+      whole_archive_flag_spec=
+    fi
+  else
+    # PORTME fill in a description of your system's linker (not GNU ld)
+    case $host_os in
+    aix3*)
+      allow_undefined_flag=unsupported
+      always_export_symbols=yes
+      archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+      # Note: this linker hardcodes the directories in LIBPATH if there
+      # are no directories specified by -L.
+      hardcode_minus_L=yes
+      if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then
+	# Neither direct hardcoding nor static linking is supported with a
+	# broken collect2.
+	hardcode_direct=unsupported
+      fi
+      ;;
+
+    aix[4-9]*)
+      if test ia64 = "$host_cpu"; then
+	# On IA64, the linker does run time linking by default, so we don't
+	# have to do anything special.
+	aix_use_runtimelinking=no
+	exp_sym_flag='-Bexport'
+	no_entry_flag=
+      else
+	# If we're using GNU nm, then we don't want the "-C" option.
+	# -C means demangle to GNU nm, but means don't demangle to AIX nm.
+	# Without the "-l" option, or with the "-B" option, AIX nm treats
+	# weak defined symbols like other global defined symbols, whereas
+	# GNU nm marks them as "W".
+	# While the 'weak' keyword is ignored in the Export File, we need
+	# it in the Import File for the 'aix-soname' feature, so we have
+	# to replace the "-B" option with "-P" for AIX nm.
+	if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+	  export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols'
+	else
+	  export_symbols_cmds='`func_echo_all $NM | $SED -e '\''s/B\([^B]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && (substr(\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
+	fi
+	aix_use_runtimelinking=no
+
+	# Test if we are trying to use run time linking or normal
+	# AIX style linking. If -brtl is somewhere in LDFLAGS, we
+	# have runtime linking enabled, and use it for executables.
+	# For shared libraries, we enable/disable runtime linking
+	# depending on the kind of the shared library created -
+	# when "with_aix_soname,aix_use_runtimelinking" is:
+	# "aix,no"   lib.a(lib.so.V) shared, rtl:no,  for executables
+	# "aix,yes"  lib.so          shared, rtl:yes, for executables
+	#            lib.a           static archive
+	# "both,no"  lib.so.V(shr.o) shared, rtl:yes
+	#            lib.a(lib.so.V) shared, rtl:no,  for executables
+	# "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables
+	#            lib.a(lib.so.V) shared, rtl:no
+	# "svr4,*"   lib.so.V(shr.o) shared, rtl:yes, for executables
+	#            lib.a           static archive
+	case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*)
+	  for ld_flag in $LDFLAGS; do
+	  if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then
+	    aix_use_runtimelinking=yes
+	    break
+	  fi
+	  done
+	  if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then
+	    # With aix-soname=svr4, we create the lib.so.V shared archives only,
+	    # so we don't have lib.a shared libs to link our executables.
+	    # We have to force runtime linking in this case.
+	    aix_use_runtimelinking=yes
+	    LDFLAGS="$LDFLAGS -Wl,-brtl"
+	  fi
+	  ;;
+	esac
+
+	exp_sym_flag='-bexport'
+	no_entry_flag='-bnoentry'
+      fi
+
+      # When large executables or shared objects are built, AIX ld can
+      # have problems creating the table of contents.  If linking a library
+      # or program results in "error TOC overflow" add -mminimal-toc to
+      # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+      # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+      archive_cmds=''
+      hardcode_direct=yes
+      hardcode_direct_absolute=yes
+      hardcode_libdir_separator=':'
+      link_all_deplibs=yes
+      file_list_spec='$wl-f,'
+      case $with_aix_soname,$aix_use_runtimelinking in
+      aix,*) ;; # traditional, no import file
+      svr4,* | *,yes) # use import file
+	# The Import File defines what to hardcode.
+	hardcode_direct=no
+	hardcode_direct_absolute=no
+	;;
+      esac
+
+      if test yes = "$GCC"; then
+	case $host_os in aix4.[012]|aix4.[012].*)
+	# We only want to do this on AIX 4.2 and lower, the check
+	# below for broken collect2 doesn't work under 4.3+
+	  collect2name=`$CC -print-prog-name=collect2`
+	  if test -f "$collect2name" &&
+	   strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+	  then
+	  # We have reworked collect2
+	  :
+	  else
+	  # We have old collect2
+	  hardcode_direct=unsupported
+	  # It fails to find uninstalled libraries when the uninstalled
+	  # path is not listed in the libpath.  Setting hardcode_minus_L
+	  # to unsupported forces relinking
+	  hardcode_minus_L=yes
+	  hardcode_libdir_flag_spec='-L$libdir'
+	  hardcode_libdir_separator=
+	  fi
+	  ;;
+	esac
+	shared_flag='-shared'
+	if test yes = "$aix_use_runtimelinking"; then
+	  shared_flag="$shared_flag "'$wl-G'
+	fi
+	# Need to ensure runtime linking is disabled for the traditional
+	# shared library, or the linker may eventually find shared libraries
+	# /with/ Import File - we do not want to mix them.
+	shared_flag_aix='-shared'
+	shared_flag_svr4='-shared $wl-G'
+      else
+	# not using gcc
+	if test ia64 = "$host_cpu"; then
+	# VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+	# chokes on -Wl,-G. The following line is correct:
+	  shared_flag='-G'
+	else
+	  if test yes = "$aix_use_runtimelinking"; then
+	    shared_flag='$wl-G'
+	  else
+	    shared_flag='$wl-bM:SRE'
+	  fi
+	  shared_flag_aix='$wl-bM:SRE'
+	  shared_flag_svr4='$wl-G'
+	fi
+      fi
+
+      export_dynamic_flag_spec='$wl-bexpall'
+      # It seems that -bexpall does not export symbols beginning with
+      # underscore (_), so it is better to generate a list of symbols to export.
+      always_export_symbols=yes
+      if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then
+	# Warning - without using the other runtime loading flags (-brtl),
+	# -berok will link without error, but may produce a broken library.
+	allow_undefined_flag='-berok'
+        # Determine the default libpath from the value encoded in an
+        # empty executable.
+        if test set = "${lt_cv_aix_libpath+set}"; then
+  aix_libpath=$lt_cv_aix_libpath
+else
+  if ${lt_cv_aix_libpath_+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+  lt_aix_libpath_sed='
+      /Import File Strings/,/^$/ {
+	  /^0/ {
+	      s/^0  *\([^ ]*\) *$/\1/
+	      p
+	  }
+      }'
+  lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  # Check for a 64-bit object if we didn't find anything.
+  if test -z "$lt_cv_aix_libpath_"; then
+    lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  if test -z "$lt_cv_aix_libpath_"; then
+    lt_cv_aix_libpath_=/usr/lib:/lib
+  fi
+
+fi
+
+  aix_libpath=$lt_cv_aix_libpath_
+fi
+
+        hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath"
+        archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag
+      else
+	if test ia64 = "$host_cpu"; then
+	  hardcode_libdir_flag_spec='$wl-R $libdir:/usr/lib:/lib'
+	  allow_undefined_flag="-z nodefs"
+	  archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols"
+	else
+	 # Determine the default libpath from the value encoded in an
+	 # empty executable.
+	 if test set = "${lt_cv_aix_libpath+set}"; then
+  aix_libpath=$lt_cv_aix_libpath
+else
+  if ${lt_cv_aix_libpath_+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+  lt_aix_libpath_sed='
+      /Import File Strings/,/^$/ {
+	  /^0/ {
+	      s/^0  *\([^ ]*\) *$/\1/
+	      p
+	  }
+      }'
+  lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  # Check for a 64-bit object if we didn't find anything.
+  if test -z "$lt_cv_aix_libpath_"; then
+    lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  if test -z "$lt_cv_aix_libpath_"; then
+    lt_cv_aix_libpath_=/usr/lib:/lib
+  fi
+
+fi
+
+  aix_libpath=$lt_cv_aix_libpath_
+fi
+
+	 hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath"
+	  # Warning - without using the other run time loading flags,
+	  # -berok will link without error, but may produce a broken library.
+	  no_undefined_flag=' $wl-bernotok'
+	  allow_undefined_flag=' $wl-berok'
+	  if test yes = "$with_gnu_ld"; then
+	    # We only use this code for GNU lds that support --whole-archive.
+	    whole_archive_flag_spec='$wl--whole-archive$convenience $wl--no-whole-archive'
+	  else
+	    # Exported symbols can be pulled into shared objects from archives
+	    whole_archive_flag_spec='$convenience'
+	  fi
+	  archive_cmds_need_lc=yes
+	  archive_expsym_cmds='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d'
+	  # -brtl affects multiple linker settings, -berok does not and is overridden later
+	  compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([, ]\\)%-berok\\1%g"`'
+	  if test svr4 != "$with_aix_soname"; then
+	    # This is similar to how AIX traditionally builds its shared libraries.
+	    archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname'
+	  fi
+	  if test aix != "$with_aix_soname"; then
+	    archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp'
+	  else
+	    # used by -dlpreopen to get the symbols
+	    archive_expsym_cmds="$archive_expsym_cmds"'~$MV  $output_objdir/$realname.d/$soname $output_objdir'
+	  fi
+	  archive_expsym_cmds="$archive_expsym_cmds"'~$RM -r $output_objdir/$realname.d'
+	fi
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+            archive_expsym_cmds=''
+        ;;
+      m68k)
+            archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+            hardcode_libdir_flag_spec='-L$libdir'
+            hardcode_minus_L=yes
+        ;;
+      esac
+      ;;
+
+    bsdi[45]*)
+      export_dynamic_flag_spec=-rdynamic
+      ;;
+
+    cygwin* | mingw* | pw32* | cegcc*)
+      # When not using gcc, we currently assume that we are using
+      # Microsoft Visual C++.
+      # hardcode_libdir_flag_spec is actually meaningless, as there is
+      # no search path for DLLs.
+      case $cc_basename in
+      cl*)
+	# Native MSVC
+	hardcode_libdir_flag_spec=' '
+	allow_undefined_flag=unsupported
+	always_export_symbols=yes
+	file_list_spec='@'
+	# Tell ltmain to make .lib files, not .a files.
+	libext=lib
+	# Tell ltmain to make .dll files, not .so files.
+	shrext_cmds=.dll
+	# FIXME: Setting linknames here is a bad hack.
+	archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames='
+	archive_expsym_cmds='if   test DEF = "`$SED -n     -e '\''s/^[	 ]*//'\''     -e '\''/^\(;.*\)*$/d'\''     -e '\''s/^\(EXPORTS\|LIBRARY\)\([	 ].*\)*$/DEF/p'\''     -e q     $export_symbols`" ; then
+            cp "$export_symbols" "$output_objdir/$soname.def";
+            echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp";
+          else
+            $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp;
+          fi~
+          $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+          linknames='
+	# The linker will not automatically build a static lib if we build a DLL.
+	# _LT_TAGVAR(old_archive_from_new_cmds, )='true'
+	enable_shared_with_static_runtimes=yes
+	exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
+	export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols'
+	# Don't use ranlib
+	old_postinstall_cmds='chmod 644 $oldlib'
+	postlink_cmds='lt_outputfile="@OUTPUT@"~
+          lt_tool_outputfile="@TOOL_OUTPUT@"~
+          case $lt_outputfile in
+            *.exe|*.EXE) ;;
+            *)
+              lt_outputfile=$lt_outputfile.exe
+              lt_tool_outputfile=$lt_tool_outputfile.exe
+              ;;
+          esac~
+          if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then
+            $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+            $RM "$lt_outputfile.manifest";
+          fi'
+	;;
+      *)
+	# Assume MSVC wrapper
+	hardcode_libdir_flag_spec=' '
+	allow_undefined_flag=unsupported
+	# Tell ltmain to make .lib files, not .a files.
+	libext=lib
+	# Tell ltmain to make .dll files, not .so files.
+	shrext_cmds=.dll
+	# FIXME: Setting linknames here is a bad hack.
+	archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
+	# The linker will automatically build a .lib file if we build a DLL.
+	old_archive_from_new_cmds='true'
+	# FIXME: Should let the user specify the lib program.
+	old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs'
+	enable_shared_with_static_runtimes=yes
+	;;
+      esac
+      ;;
+
+    darwin* | rhapsody*)
+
+
+  archive_cmds_need_lc=no
+  hardcode_direct=no
+  hardcode_automatic=yes
+  hardcode_shlibpath_var=unsupported
+  if test yes = "$lt_cv_ld_force_load"; then
+    whole_archive_flag_spec='`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+
+  else
+    whole_archive_flag_spec=''
+  fi
+  link_all_deplibs=yes
+  allow_undefined_flag=$_lt_dar_allow_undefined
+  case $cc_basename in
+     ifort*|nagfor*) _lt_dar_can_shared=yes ;;
+     *) _lt_dar_can_shared=$GCC ;;
+  esac
+  if test yes = "$_lt_dar_can_shared"; then
+    output_verbose_link_cmd=func_echo_all
+    archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil"
+    module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil"
+    archive_expsym_cmds="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil"
+    module_expsym_cmds="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil"
+
+  else
+  ld_shlibs=no
+  fi
+
+      ;;
+
+    dgux*)
+      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_shlibpath_var=no
+      ;;
+
+    # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+    # support.  Future versions do this automatically, but an explicit c++rt0.o
+    # does not break anything, and helps significantly (at the cost of a little
+    # extra space).
+    freebsd2.2*)
+      archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_direct=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+    freebsd2.*)
+      archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_direct=yes
+      hardcode_minus_L=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+    freebsd* | dragonfly*)
+      archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_direct=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    hpux9*)
+      if test yes = "$GCC"; then
+	archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
+      else
+	archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
+      fi
+      hardcode_libdir_flag_spec='$wl+b $wl$libdir'
+      hardcode_libdir_separator=:
+      hardcode_direct=yes
+
+      # hardcode_minus_L: Not really in the search PATH,
+      # but as the default location of the library.
+      hardcode_minus_L=yes
+      export_dynamic_flag_spec='$wl-E'
+      ;;
+
+    hpux10*)
+      if test yes,no = "$GCC,$with_gnu_ld"; then
+	archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      if test no = "$with_gnu_ld"; then
+	hardcode_libdir_flag_spec='$wl+b $wl$libdir'
+	hardcode_libdir_separator=:
+	hardcode_direct=yes
+	hardcode_direct_absolute=yes
+	export_dynamic_flag_spec='$wl-E'
+	# hardcode_minus_L: Not really in the search PATH,
+	# but as the default location of the library.
+	hardcode_minus_L=yes
+      fi
+      ;;
+
+    hpux11*)
+      if test yes,no = "$GCC,$with_gnu_ld"; then
+	case $host_cpu in
+	hppa*64*)
+	  archive_cmds='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	ia64*)
+	  archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+	  archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	esac
+      else
+	case $host_cpu in
+	hppa*64*)
+	  archive_cmds='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	ia64*)
+	  archive_cmds='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+
+	  # Older versions of the 11.00 compiler do not understand -b yet
+	  # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
+	  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5
+$as_echo_n "checking if $CC understands -b... " >&6; }
+if ${lt_cv_prog_compiler__b+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler__b=no
+   save_LDFLAGS=$LDFLAGS
+   LDFLAGS="$LDFLAGS -b"
+   echo "$lt_simple_link_test_code" > conftest.$ac_ext
+   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+     # The linker can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test -s conftest.err; then
+       # Append any errors to the config.log.
+       cat conftest.err 1>&5
+       $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+       if diff conftest.exp conftest.er2 >/dev/null; then
+         lt_cv_prog_compiler__b=yes
+       fi
+     else
+       lt_cv_prog_compiler__b=yes
+     fi
+   fi
+   $RM -r conftest*
+   LDFLAGS=$save_LDFLAGS
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5
+$as_echo "$lt_cv_prog_compiler__b" >&6; }
+
+if test yes = "$lt_cv_prog_compiler__b"; then
+    archive_cmds='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+else
+    archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+fi
+
+	  ;;
+	esac
+      fi
+      if test no = "$with_gnu_ld"; then
+	hardcode_libdir_flag_spec='$wl+b $wl$libdir'
+	hardcode_libdir_separator=:
+
+	case $host_cpu in
+	hppa*64*|ia64*)
+	  hardcode_direct=no
+	  hardcode_shlibpath_var=no
+	  ;;
+	*)
+	  hardcode_direct=yes
+	  hardcode_direct_absolute=yes
+	  export_dynamic_flag_spec='$wl-E'
+
+	  # hardcode_minus_L: Not really in the search PATH,
+	  # but as the default location of the library.
+	  hardcode_minus_L=yes
+	  ;;
+	esac
+      fi
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      if test yes = "$GCC"; then
+	archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+	# Try to use the -exported_symbol ld option, if it does not
+	# work, assume that -exports_file does not work either and
+	# implicitly export all symbols.
+	# This should be the same for all languages, so no per-tag cache variable.
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5
+$as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >&6; }
+if ${lt_cv_irix_exported_symbol+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  save_LDFLAGS=$LDFLAGS
+	   LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null"
+	   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+int foo (void) { return 0; }
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  lt_cv_irix_exported_symbol=yes
+else
+  lt_cv_irix_exported_symbol=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+           LDFLAGS=$save_LDFLAGS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5
+$as_echo "$lt_cv_irix_exported_symbol" >&6; }
+	if test yes = "$lt_cv_irix_exported_symbol"; then
+          archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib'
+	fi
+      else
+	archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+	archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib'
+      fi
+      archive_cmds_need_lc='no'
+      hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
+      hardcode_libdir_separator=:
+      inherit_rpath=yes
+      link_all_deplibs=yes
+      ;;
+
+    linux*)
+      case $cc_basename in
+      tcc*)
+	# Fabrice Bellard et al's Tiny C Compiler
+	ld_shlibs=yes
+	archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	;;
+      esac
+      ;;
+
+    netbsd*)
+      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+	archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'  # a.out
+      else
+	archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags'      # ELF
+      fi
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_direct=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    newsos6)
+      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_direct=yes
+      hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
+      hardcode_libdir_separator=:
+      hardcode_shlibpath_var=no
+      ;;
+
+    *nto* | *qnx*)
+      ;;
+
+    openbsd* | bitrig*)
+      if test -f /usr/libexec/ld.so; then
+	hardcode_direct=yes
+	hardcode_shlibpath_var=no
+	hardcode_direct_absolute=yes
+	if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
+	  archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	  archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols'
+	  hardcode_libdir_flag_spec='$wl-rpath,$libdir'
+	  export_dynamic_flag_spec='$wl-E'
+	else
+	  archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	  hardcode_libdir_flag_spec='$wl-rpath,$libdir'
+	fi
+      else
+	ld_shlibs=no
+      fi
+      ;;
+
+    os2*)
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_minus_L=yes
+      allow_undefined_flag=unsupported
+      shrext_cmds=.dll
+      archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+	$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+	$ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+	$ECHO EXPORTS >> $output_objdir/$libname.def~
+	emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
+	$CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+	emximp -o $lib $output_objdir/$libname.def'
+      archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+	$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+	$ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+	$ECHO EXPORTS >> $output_objdir/$libname.def~
+	prefix_cmds="$SED"~
+	if test EXPORTS = "`$SED 1q $export_symbols`"; then
+	  prefix_cmds="$prefix_cmds -e 1d";
+	fi~
+	prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
+	cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
+	$CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+	emximp -o $lib $output_objdir/$libname.def'
+      old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
+      enable_shared_with_static_runtimes=yes
+      ;;
+
+    osf3*)
+      if test yes = "$GCC"; then
+	allow_undefined_flag=' $wl-expect_unresolved $wl\*'
+	archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+      else
+	allow_undefined_flag=' -expect_unresolved \*'
+	archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+      fi
+      archive_cmds_need_lc='no'
+      hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
+      hardcode_libdir_separator=:
+      ;;
+
+    osf4* | osf5*)	# as osf3* with the addition of -msym flag
+      if test yes = "$GCC"; then
+	allow_undefined_flag=' $wl-expect_unresolved $wl\*'
+	archive_cmds='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+	hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
+      else
+	allow_undefined_flag=' -expect_unresolved \*'
+	archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+	archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
+          $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp'
+
+	# Both c and cxx compiler support -rpath directly
+	hardcode_libdir_flag_spec='-rpath $libdir'
+      fi
+      archive_cmds_need_lc='no'
+      hardcode_libdir_separator=:
+      ;;
+
+    solaris*)
+      no_undefined_flag=' -z defs'
+      if test yes = "$GCC"; then
+	wlarc='$wl'
+	archive_cmds='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+          $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+      else
+	case `$CC -V 2>&1` in
+	*"Compilers 5.0"*)
+	  wlarc=''
+	  archive_cmds='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+            $LD -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+	  ;;
+	*)
+	  wlarc='$wl'
+	  archive_cmds='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+	  archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+            $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+	  ;;
+	esac
+      fi
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_shlibpath_var=no
+      case $host_os in
+      solaris2.[0-5] | solaris2.[0-5].*) ;;
+      *)
+	# The compiler driver will combine and reorder linker options,
+	# but understands '-z linker_flag'.  GCC discards it without '$wl',
+	# but is careful enough not to reorder.
+	# Supported since Solaris 2.6 (maybe 2.5.1?)
+	if test yes = "$GCC"; then
+	  whole_archive_flag_spec='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract'
+	else
+	  whole_archive_flag_spec='-z allextract$convenience -z defaultextract'
+	fi
+	;;
+      esac
+      link_all_deplibs=yes
+      ;;
+
+    sunos4*)
+      if test sequent = "$host_vendor"; then
+	# Use $CC to link under sequent, because it throws in some extra .o
+	# files that make .init and .fini sections work.
+	archive_cmds='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_direct=yes
+      hardcode_minus_L=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    sysv4)
+      case $host_vendor in
+	sni)
+	  archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  hardcode_direct=yes # is this really true???
+	;;
+	siemens)
+	  ## LD is ld it makes a PLAMLIB
+	  ## CC just makes a GrossModule.
+	  archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+	  reload_cmds='$CC -r -o $output$reload_objs'
+	  hardcode_direct=no
+        ;;
+	motorola)
+	  archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  hardcode_direct=no #Motorola manual says yes, but my tests say they lie
+	;;
+      esac
+      runpath_var='LD_RUN_PATH'
+      hardcode_shlibpath_var=no
+      ;;
+
+    sysv4.3*)
+      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_shlibpath_var=no
+      export_dynamic_flag_spec='-Bexport'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	hardcode_shlibpath_var=no
+	runpath_var=LD_RUN_PATH
+	hardcode_runpath_var=yes
+	ld_shlibs=yes
+      fi
+      ;;
+
+    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
+      no_undefined_flag='$wl-z,text'
+      archive_cmds_need_lc=no
+      hardcode_shlibpath_var=no
+      runpath_var='LD_RUN_PATH'
+
+      if test yes = "$GCC"; then
+	archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      ;;
+
+    sysv5* | sco3.2v5* | sco5v6*)
+      # Note: We CANNOT use -z defs as we might desire, because we do not
+      # link with -lc, and that would cause any symbols used from libc to
+      # always be unresolved, which means just about no library would
+      # ever link correctly.  If we're not using GNU ld we use -z text
+      # though, which does catch some bad symbols but isn't as heavy-handed
+      # as -z defs.
+      no_undefined_flag='$wl-z,text'
+      allow_undefined_flag='$wl-z,nodefs'
+      archive_cmds_need_lc=no
+      hardcode_shlibpath_var=no
+      hardcode_libdir_flag_spec='$wl-R,$libdir'
+      hardcode_libdir_separator=':'
+      link_all_deplibs=yes
+      export_dynamic_flag_spec='$wl-Bexport'
+      runpath_var='LD_RUN_PATH'
+
+      if test yes = "$GCC"; then
+	archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      ;;
+
+    uts4*)
+      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_shlibpath_var=no
+      ;;
+
+    *)
+      ld_shlibs=no
+      ;;
+    esac
+
+    if test sni = "$host_vendor"; then
+      case $host in
+      sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+	export_dynamic_flag_spec='$wl-Blargedynsym'
+	;;
+      esac
+    fi
+  fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5
+$as_echo "$ld_shlibs" >&6; }
+test no = "$ld_shlibs" && can_build_shared=no
+
+with_gnu_ld=$with_gnu_ld
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$archive_cmds_need_lc" in
+x|xyes)
+  # Assume -lc should be added
+  archive_cmds_need_lc=yes
+
+  if test yes,yes = "$GCC,$enable_shared"; then
+    case $archive_cmds in
+    *'~'*)
+      # FIXME: we may have to deal with multi-command sequences.
+      ;;
+    '$CC '*)
+      # Test whether the compiler implicitly links with -lc since on some
+      # systems, -lgcc has to come before -lc. If gcc already passes -lc
+      # to ld, don't add -lc before -lgcc.
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5
+$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; }
+if ${lt_cv_archive_cmds_need_lc+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  $RM conftest*
+	echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+	if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } 2>conftest.err; then
+	  soname=conftest
+	  lib=conftest
+	  libobjs=conftest.$ac_objext
+	  deplibs=
+	  wl=$lt_prog_compiler_wl
+	  pic_flag=$lt_prog_compiler_pic
+	  compiler_flags=-v
+	  linker_flags=-v
+	  verstring=
+	  output_objdir=.
+	  libname=conftest
+	  lt_save_allow_undefined_flag=$allow_undefined_flag
+	  allow_undefined_flag=
+	  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5
+  (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+	  then
+	    lt_cv_archive_cmds_need_lc=no
+	  else
+	    lt_cv_archive_cmds_need_lc=yes
+	  fi
+	  allow_undefined_flag=$lt_save_allow_undefined_flag
+	else
+	  cat conftest.err 1>&5
+	fi
+	$RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5
+$as_echo "$lt_cv_archive_cmds_need_lc" >&6; }
+      archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc
+      ;;
+    esac
+  fi
+  ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5
+$as_echo_n "checking dynamic linker characteristics... " >&6; }
+
+if test yes = "$GCC"; then
+  case $host_os in
+    darwin*) lt_awk_arg='/^libraries:/,/LR/' ;;
+    *) lt_awk_arg='/^libraries:/' ;;
+  esac
+  case $host_os in
+    mingw* | cegcc*) lt_sed_strip_eq='s|=\([A-Za-z]:\)|\1|g' ;;
+    *) lt_sed_strip_eq='s|=/|/|g' ;;
+  esac
+  lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
+  case $lt_search_path_spec in
+  *\;*)
+    # if the path contains ";" then we assume it to be the separator
+    # otherwise default to the standard path separator (i.e. ":") - it is
+    # assumed that no part of a normal pathname contains ";" but that should
+    # okay in the real world where ";" in dirpaths is itself problematic.
+    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'`
+    ;;
+  *)
+    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
+    ;;
+  esac
+  # Ok, now we have the path, separated by spaces, we can step through it
+  # and add multilib dir if necessary...
+  lt_tmp_lt_search_path_spec=
+  lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+  # ...but if some path component already ends with the multilib dir we assume
+  # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer).
+  case "$lt_multi_os_dir; $lt_search_path_spec " in
+  "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*)
+    lt_multi_os_dir=
+    ;;
+  esac
+  for lt_sys_path in $lt_search_path_spec; do
+    if test -d "$lt_sys_path$lt_multi_os_dir"; then
+      lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir"
+    elif test -n "$lt_multi_os_dir"; then
+      test -d "$lt_sys_path" && \
+	lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
+    fi
+  done
+  lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
+BEGIN {RS = " "; FS = "/|\n";} {
+  lt_foo = "";
+  lt_count = 0;
+  for (lt_i = NF; lt_i > 0; lt_i--) {
+    if ($lt_i != "" && $lt_i != ".") {
+      if ($lt_i == "..") {
+        lt_count++;
+      } else {
+        if (lt_count == 0) {
+          lt_foo = "/" $lt_i lt_foo;
+        } else {
+          lt_count--;
+        }
+      }
+    }
+  }
+  if (lt_foo != "") { lt_freq[lt_foo]++; }
+  if (lt_freq[lt_foo] == 1) { print lt_foo; }
+}'`
+  # AWK program above erroneously prepends '/' to C:/dos/paths
+  # for these hosts.
+  case $host_os in
+    mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
+      $SED 's|/\([A-Za-z]:\)|\1|g'` ;;
+  esac
+  sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
+else
+  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=.so
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+
+
+case $host_os in
+aix3*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='$libname$release$shared_ext$versuffix $libname.a'
+  shlibpath_var=LIBPATH
+
+  # AIX 3 has no versioning support, so we append a major version to the name.
+  soname_spec='$libname$release$shared_ext$major'
+  ;;
+
+aix[4-9]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  hardcode_into_libs=yes
+  if test ia64 = "$host_cpu"; then
+    # AIX 5 supports IA64
+    library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext'
+    shlibpath_var=LD_LIBRARY_PATH
+  else
+    # With GCC up to 2.95.x, collect2 would create an import file
+    # for dependence libraries.  The import file would start with
+    # the line '#! .'.  This would cause the generated library to
+    # depend on '.', always an invalid library.  This was fixed in
+    # development snapshots of GCC prior to 3.0.
+    case $host_os in
+      aix4 | aix4.[01] | aix4.[01].*)
+      if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+	   echo ' yes '
+	   echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then
+	:
+      else
+	can_build_shared=no
+      fi
+      ;;
+    esac
+    # Using Import Files as archive members, it is possible to support
+    # filename-based versioning of shared library archives on AIX. While
+    # this would work for both with and without runtime linking, it will
+    # prevent static linking of such archives. So we do filename-based
+    # shared library versioning with .so extension only, which is used
+    # when both runtime linking and shared linking is enabled.
+    # Unfortunately, runtime linking may impact performance, so we do
+    # not want this to be the default eventually. Also, we use the
+    # versioned .so libs for executables only if there is the -brtl
+    # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only.
+    # To allow for filename-based versioning support, we need to create
+    # libNAME.so.V as an archive file, containing:
+    # *) an Import File, referring to the versioned filename of the
+    #    archive as well as the shared archive member, telling the
+    #    bitwidth (32 or 64) of that shared object, and providing the
+    #    list of exported symbols of that shared object, eventually
+    #    decorated with the 'weak' keyword
+    # *) the shared object with the F_LOADONLY flag set, to really avoid
+    #    it being seen by the linker.
+    # At run time we better use the real file rather than another symlink,
+    # but for link time we create the symlink libNAME.so -> libNAME.so.V
+
+    case $with_aix_soname,$aix_use_runtimelinking in
+    # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct
+    # soname into executable. Probably we can add versioning support to
+    # collect2, so additional links can be useful in future.
+    aix,yes) # traditional libtool
+      dynamic_linker='AIX unversionable lib.so'
+      # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+      # instead of lib<name>.a to let people know that these are not
+      # typical AIX shared libraries.
+      library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+      ;;
+    aix,no) # traditional AIX only
+      dynamic_linker='AIX lib.a(lib.so.V)'
+      # We preserve .a as extension for shared libraries through AIX4.2
+      # and later when we are not doing run time linking.
+      library_names_spec='$libname$release.a $libname.a'
+      soname_spec='$libname$release$shared_ext$major'
+      ;;
+    svr4,*) # full svr4 only
+      dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o)"
+      library_names_spec='$libname$release$shared_ext$major $libname$shared_ext'
+      # We do not specify a path in Import Files, so LIBPATH fires.
+      shlibpath_overrides_runpath=yes
+      ;;
+    *,yes) # both, prefer svr4
+      dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o), lib.a(lib.so.V)"
+      library_names_spec='$libname$release$shared_ext$major $libname$shared_ext'
+      # unpreferred sharedlib libNAME.a needs extra handling
+      postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"'
+      postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"'
+      # We do not specify a path in Import Files, so LIBPATH fires.
+      shlibpath_overrides_runpath=yes
+      ;;
+    *,no) # both, prefer aix
+      dynamic_linker="AIX lib.a(lib.so.V), lib.so.V($shared_archive_member_spec.o)"
+      library_names_spec='$libname$release.a $libname.a'
+      soname_spec='$libname$release$shared_ext$major'
+      # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling
+      postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)'
+      postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"'
+      ;;
+    esac
+    shlibpath_var=LIBPATH
+  fi
+  ;;
+
+amigaos*)
+  case $host_cpu in
+  powerpc)
+    # Since July 2007 AmigaOS4 officially supports .so libraries.
+    # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+    ;;
+  m68k)
+    library_names_spec='$libname.ixlibrary $libname.a'
+    # Create ${libname}_ixlibrary.a entries in /sys/libs.
+    finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+    ;;
+  esac
+  ;;
+
+beos*)
+  library_names_spec='$libname$shared_ext'
+  dynamic_linker="$host_os ld.so"
+  shlibpath_var=LIBRARY_PATH
+  ;;
+
+bsdi[45]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+  sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+  # the default ld.so.conf also contains /usr/contrib/lib and
+  # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+  # libtool to hard-code these into programs
+  ;;
+
+cygwin* | mingw* | pw32* | cegcc*)
+  version_type=windows
+  shrext_cmds=.dll
+  need_version=no
+  need_lib_prefix=no
+
+  case $GCC,$cc_basename in
+  yes,*)
+    # gcc
+    library_names_spec='$libname.dll.a'
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \$file`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname~
+      chmod a+x \$dldir/$dlname~
+      if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+        eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+      fi'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $RM \$dlpath'
+    shlibpath_overrides_runpath=yes
+
+    case $host_os in
+    cygwin*)
+      # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+      soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
+
+      sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"
+      ;;
+    mingw* | cegcc*)
+      # MinGW DLLs use traditional 'lib' prefix
+      soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
+      ;;
+    pw32*)
+      # pw32 DLLs use 'pw' prefix rather than 'lib'
+      library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
+      ;;
+    esac
+    dynamic_linker='Win32 ld.exe'
+    ;;
+
+  *,cl*)
+    # Native MSVC
+    libname_spec='$name'
+    soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
+    library_names_spec='$libname.dll.lib'
+
+    case $build_os in
+    mingw*)
+      sys_lib_search_path_spec=
+      lt_save_ifs=$IFS
+      IFS=';'
+      for lt_path in $LIB
+      do
+        IFS=$lt_save_ifs
+        # Let DOS variable expansion print the short 8.3 style file name.
+        lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"`
+        sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path"
+      done
+      IFS=$lt_save_ifs
+      # Convert to MSYS style.
+      sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'`
+      ;;
+    cygwin*)
+      # Convert to unix form, then to dos form, then back to unix form
+      # but this time dos style (no spaces!) so that the unix form looks
+      # like /cygdrive/c/PROGRA~1:/cygdr...
+      sys_lib_search_path_spec=`cygpath --path --unix "$LIB"`
+      sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null`
+      sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+      ;;
+    *)
+      sys_lib_search_path_spec=$LIB
+      if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then
+        # It is most probably a Windows format PATH.
+        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+      else
+        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+      fi
+      # FIXME: find the short name or the path components, as spaces are
+      # common. (e.g. "Program Files" -> "PROGRA~1")
+      ;;
+    esac
+
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \$file`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $RM \$dlpath'
+    shlibpath_overrides_runpath=yes
+    dynamic_linker='Win32 link.exe'
+    ;;
+
+  *)
+    # Assume MSVC wrapper
+    library_names_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext $libname.lib'
+    dynamic_linker='Win32 ld.exe'
+    ;;
+  esac
+  # FIXME: first we should search . and the directory the executable is in
+  shlibpath_var=PATH
+  ;;
+
+darwin* | rhapsody*)
+  dynamic_linker="$host_os dyld"
+  version_type=darwin
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$major$shared_ext $libname$shared_ext'
+  soname_spec='$libname$release$major$shared_ext'
+  shlibpath_overrides_runpath=yes
+  shlibpath_var=DYLD_LIBRARY_PATH
+  shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+
+  sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"
+  sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+  ;;
+
+dgux*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+freebsd* | dragonfly*)
+  # DragonFly does not have aout.  When/if they implement a new
+  # versioning mechanism, adjust this.
+  if test -x /usr/bin/objformat; then
+    objformat=`/usr/bin/objformat`
+  else
+    case $host_os in
+    freebsd[23].*) objformat=aout ;;
+    *) objformat=elf ;;
+    esac
+  fi
+  version_type=freebsd-$objformat
+  case $version_type in
+    freebsd-elf*)
+      library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+      soname_spec='$libname$release$shared_ext$major'
+      need_version=no
+      need_lib_prefix=no
+      ;;
+    freebsd-*)
+      library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+      need_version=yes
+      ;;
+  esac
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_os in
+  freebsd2.*)
+    shlibpath_overrides_runpath=yes
+    ;;
+  freebsd3.[01]* | freebsdelf3.[01]*)
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  freebsd3.[2-9]* | freebsdelf3.[2-9]* | \
+  freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1)
+    shlibpath_overrides_runpath=no
+    hardcode_into_libs=yes
+    ;;
+  *) # from 4.6 on, and DragonFly
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  esac
+  ;;
+
+haiku*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  dynamic_linker="$host_os runtime_loader"
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  shlibpath_var=LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
+  hardcode_into_libs=yes
+  ;;
+
+hpux9* | hpux10* | hpux11*)
+  # Give a soname corresponding to the major version so that dld.sl refuses to
+  # link against other versions.
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  case $host_cpu in
+  ia64*)
+    shrext_cmds='.so'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.so"
+    shlibpath_var=LD_LIBRARY_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+    soname_spec='$libname$release$shared_ext$major'
+    if test 32 = "$HPUX_IA64_MODE"; then
+      sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+      sys_lib_dlsearch_path_spec=/usr/lib/hpux32
+    else
+      sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+      sys_lib_dlsearch_path_spec=/usr/lib/hpux64
+    fi
+    ;;
+  hppa*64*)
+    shrext_cmds='.sl'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+    soname_spec='$libname$release$shared_ext$major'
+    sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+  *)
+    shrext_cmds='.sl'
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=SHLIB_PATH
+    shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+    soname_spec='$libname$release$shared_ext$major'
+    ;;
+  esac
+  # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
+  postinstall_cmds='chmod 555 $lib'
+  # or fails outright, so override atomically:
+  install_override_mode=555
+  ;;
+
+interix[3-9]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $host_os in
+    nonstopux*) version_type=nonstopux ;;
+    *)
+	if test yes = "$lt_cv_prog_gnu_ld"; then
+		version_type=linux # correct to gnu/linux during the next big refactor
+	else
+		version_type=irix
+	fi ;;
+  esac
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='$libname$release$shared_ext$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext'
+  case $host_os in
+  irix5* | nonstopux*)
+    libsuff= shlibsuff=
+    ;;
+  *)
+    case $LD in # libtool.m4 will add one of these switches to LD
+    *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+      libsuff= shlibsuff= libmagic=32-bit;;
+    *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+      libsuff=32 shlibsuff=N32 libmagic=N32;;
+    *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+      libsuff=64 shlibsuff=64 libmagic=64-bit;;
+    *) libsuff= shlibsuff= libmagic=never-match;;
+    esac
+    ;;
+  esac
+  shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+  shlibpath_overrides_runpath=no
+  sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff"
+  sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff"
+  hardcode_into_libs=yes
+  ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+  dynamic_linker=no
+  ;;
+
+linux*android*)
+  version_type=none # Android doesn't support versioned libraries.
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext'
+  soname_spec='$libname$release$shared_ext'
+  finish_cmds=
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+
+  # This implies no fast_install, which is unacceptable.
+  # Some rework will be needed to allow for fast_install
+  # before this can be enabled.
+  hardcode_into_libs=yes
+
+  dynamic_linker='Android linker'
+  # Don't embed -rpath directories since the linker doesn't support them.
+  hardcode_libdir_flag_spec='-L$libdir'
+  ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+
+  # Some binutils ld are patched to set DT_RUNPATH
+  if ${lt_cv_shlibpath_overrides_runpath+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_shlibpath_overrides_runpath=no
+    save_LDFLAGS=$LDFLAGS
+    save_libdir=$libdir
+    eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \
+	 LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\""
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  if  ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then :
+  lt_cv_shlibpath_overrides_runpath=yes
+fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+    LDFLAGS=$save_LDFLAGS
+    libdir=$save_libdir
+
+fi
+
+  shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
+
+  # This implies no fast_install, which is unacceptable.
+  # Some rework will be needed to allow for fast_install
+  # before this can be enabled.
+  hardcode_into_libs=yes
+
+  # Ideally, we could use ldconfig to report *all* directores which are
+  # searched for libraries, however this is still not possible.  Aside from not
+  # being certain /sbin/ldconfig is available, command
+  # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64,
+  # even though it is searched at run-time.  Try to do the best guess by
+  # appending ld.so.conf contents (and includes) to the search path.
+  if test -f /etc/ld.so.conf; then
+    lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[	 ]*hwcap[	 ]/d;s/[:,	]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
+    sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+  fi
+
+  # We used to test for /lib/ld.so.1 and disable shared libraries on
+  # powerpc, because MkLinux only supported shared libraries with the
+  # GNU dynamic linker.  Since this was broken with cross compilers,
+  # most powerpc-linux boxes support dynamic linking these days and
+  # people can always --disable-shared, the test was removed, and we
+  # assume the GNU/Linux dynamic linker is in use.
+  dynamic_linker='GNU/Linux ld.so'
+  ;;
+
+netbsd*)
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+    finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+    dynamic_linker='NetBSD (a.out) ld.so'
+  else
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+    soname_spec='$libname$release$shared_ext$major'
+    dynamic_linker='NetBSD ld.elf_so'
+  fi
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  ;;
+
+newsos6)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+*nto* | *qnx*)
+  version_type=qnx
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='ldqnx.so'
+  ;;
+
+openbsd* | bitrig*)
+  version_type=sunos
+  sys_lib_dlsearch_path_spec=/usr/lib
+  need_lib_prefix=no
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
+    need_version=no
+  else
+    need_version=yes
+  fi
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+os2*)
+  libname_spec='$name'
+  version_type=windows
+  shrext_cmds=.dll
+  need_version=no
+  need_lib_prefix=no
+  # OS/2 can only load a DLL with a base name of 8 characters or less.
+  soname_spec='`test -n "$os2dllname" && libname="$os2dllname";
+    v=$($ECHO $release$versuffix | tr -d .-);
+    n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _);
+    $ECHO $n$v`$shared_ext'
+  library_names_spec='${libname}_dll.$libext'
+  dynamic_linker='OS/2 ld.exe'
+  shlibpath_var=BEGINLIBPATH
+  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+  sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+  postinstall_cmds='base_file=`basename \$file`~
+    dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~
+    dldir=$destdir/`dirname \$dlpath`~
+    test -d \$dldir || mkdir -p \$dldir~
+    $install_prog $dir/$dlname \$dldir/$dlname~
+    chmod a+x \$dldir/$dlname~
+    if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+      eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+    fi'
+  postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~
+    dlpath=$dir/\$dldll~
+    $RM \$dlpath'
+  ;;
+
+osf3* | osf4* | osf5*)
+  version_type=osf
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='$libname$release$shared_ext$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+  sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+  ;;
+
+rdos*)
+  dynamic_linker=no
+  ;;
+
+solaris*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  # ldd complains unless libraries are executable
+  postinstall_cmds='chmod +x $lib'
+  ;;
+
+sunos4*)
+  version_type=sunos
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+  finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  if test yes = "$with_gnu_ld"; then
+    need_lib_prefix=no
+  fi
+  need_version=yes
+  ;;
+
+sysv4 | sysv4.3*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_vendor in
+    sni)
+      shlibpath_overrides_runpath=no
+      need_lib_prefix=no
+      runpath_var=LD_RUN_PATH
+      ;;
+    siemens)
+      need_lib_prefix=no
+      ;;
+    motorola)
+      need_lib_prefix=no
+      need_version=no
+      shlibpath_overrides_runpath=no
+      sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+      ;;
+  esac
+  ;;
+
+sysv4*MP*)
+  if test -d /usr/nec; then
+    version_type=linux # correct to gnu/linux during the next big refactor
+    library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext'
+    soname_spec='$libname$shared_ext.$major'
+    shlibpath_var=LD_LIBRARY_PATH
+  fi
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  version_type=sco
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  if test yes = "$with_gnu_ld"; then
+    sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+  else
+    sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+    case $host_os in
+      sco3.2v5*)
+        sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+	;;
+    esac
+  fi
+  sys_lib_dlsearch_path_spec='/usr/lib'
+  ;;
+
+tpf*)
+  # TPF is a cross-target only.  Preferred cross-host = GNU/Linux.
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+uts4*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+*)
+  dynamic_linker=no
+  ;;
+esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5
+$as_echo "$dynamic_linker" >&6; }
+test no = "$dynamic_linker" && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test yes = "$GCC"; then
+  variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then
+  sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec
+fi
+
+if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then
+  sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec
+fi
+
+# remember unaugmented sys_lib_dlsearch_path content for libtool script decls...
+configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec
+
+# ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code
+func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH"
+
+# to be used as default LT_SYS_LIBRARY_PATH value in generated libtool
+configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5
+$as_echo_n "checking how to hardcode library paths into programs... " >&6; }
+hardcode_action=
+if test -n "$hardcode_libdir_flag_spec" ||
+   test -n "$runpath_var" ||
+   test yes = "$hardcode_automatic"; then
+
+  # We can hardcode non-existent directories.
+  if test no != "$hardcode_direct" &&
+     # If the only mechanism to avoid hardcoding is shlibpath_var, we
+     # have to relink, otherwise we might link with an installed library
+     # when we should be linking with a yet-to-be-installed one
+     ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, )" &&
+     test no != "$hardcode_minus_L"; then
+    # Linking always hardcodes the temporary library directory.
+    hardcode_action=relink
+  else
+    # We can link without hardcoding, and we can hardcode nonexisting dirs.
+    hardcode_action=immediate
+  fi
+else
+  # We cannot hardcode anything, or else we can only hardcode existing
+  # directories.
+  hardcode_action=unsupported
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5
+$as_echo "$hardcode_action" >&6; }
+
+if test relink = "$hardcode_action" ||
+   test yes = "$inherit_rpath"; then
+  # Fast installation is not supported
+  enable_fast_install=no
+elif test yes = "$shlibpath_overrides_runpath" ||
+     test no = "$enable_shared"; then
+  # Fast installation is not necessary
+  enable_fast_install=needless
+fi
+
+
+
+
+
+
+  if test yes != "$enable_dlopen"; then
+  enable_dlopen=unknown
+  enable_dlopen_self=unknown
+  enable_dlopen_self_static=unknown
+else
+  lt_cv_dlopen=no
+  lt_cv_dlopen_libs=
+
+  case $host_os in
+  beos*)
+    lt_cv_dlopen=load_add_on
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+    ;;
+
+  mingw* | pw32* | cegcc*)
+    lt_cv_dlopen=LoadLibrary
+    lt_cv_dlopen_libs=
+    ;;
+
+  cygwin*)
+    lt_cv_dlopen=dlopen
+    lt_cv_dlopen_libs=
+    ;;
+
+  darwin*)
+    # if libdl is installed we need to link against it
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
+$as_echo_n "checking for dlopen in -ldl... " >&6; }
+if ${ac_cv_lib_dl_dlopen+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_dl_dlopen=yes
+else
+  ac_cv_lib_dl_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
+$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = xyes; then :
+  lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl
+else
+
+    lt_cv_dlopen=dyld
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+
+fi
+
+    ;;
+
+  tpf*)
+    # Don't try to run any link tests for TPF.  We know it's impossible
+    # because TPF is a cross-compiler, and we know how we open DSOs.
+    lt_cv_dlopen=dlopen
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=no
+    ;;
+
+  *)
+    ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load"
+if test "x$ac_cv_func_shl_load" = xyes; then :
+  lt_cv_dlopen=shl_load
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5
+$as_echo_n "checking for shl_load in -ldld... " >&6; }
+if ${ac_cv_lib_dld_shl_load+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char shl_load ();
+int
+main ()
+{
+return shl_load ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_dld_shl_load=yes
+else
+  ac_cv_lib_dld_shl_load=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5
+$as_echo "$ac_cv_lib_dld_shl_load" >&6; }
+if test "x$ac_cv_lib_dld_shl_load" = xyes; then :
+  lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld
+else
+  ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen"
+if test "x$ac_cv_func_dlopen" = xyes; then :
+  lt_cv_dlopen=dlopen
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
+$as_echo_n "checking for dlopen in -ldl... " >&6; }
+if ${ac_cv_lib_dl_dlopen+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_dl_dlopen=yes
+else
+  ac_cv_lib_dl_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
+$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = xyes; then :
+  lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5
+$as_echo_n "checking for dlopen in -lsvld... " >&6; }
+if ${ac_cv_lib_svld_dlopen+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsvld  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_svld_dlopen=yes
+else
+  ac_cv_lib_svld_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5
+$as_echo "$ac_cv_lib_svld_dlopen" >&6; }
+if test "x$ac_cv_lib_svld_dlopen" = xyes; then :
+  lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5
+$as_echo_n "checking for dld_link in -ldld... " >&6; }
+if ${ac_cv_lib_dld_dld_link+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dld_link ();
+int
+main ()
+{
+return dld_link ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_dld_dld_link=yes
+else
+  ac_cv_lib_dld_dld_link=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5
+$as_echo "$ac_cv_lib_dld_dld_link" >&6; }
+if test "x$ac_cv_lib_dld_dld_link" = xyes; then :
+  lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+    ;;
+  esac
+
+  if test no = "$lt_cv_dlopen"; then
+    enable_dlopen=no
+  else
+    enable_dlopen=yes
+  fi
+
+  case $lt_cv_dlopen in
+  dlopen)
+    save_CPPFLAGS=$CPPFLAGS
+    test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+    save_LDFLAGS=$LDFLAGS
+    wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+    save_LIBS=$LIBS
+    LIBS="$lt_cv_dlopen_libs $LIBS"
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5
+$as_echo_n "checking whether a program can dlopen itself... " >&6; }
+if ${lt_cv_dlopen_self+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  	  if test yes = "$cross_compiling"; then :
+  lt_cv_dlopen_self=cross
+else
+  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+  lt_status=$lt_dlunknown
+  cat > conftest.$ac_ext <<_LT_EOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+#  define LT_DLGLOBAL		RTLD_GLOBAL
+#else
+#  ifdef DL_GLOBAL
+#    define LT_DLGLOBAL		DL_GLOBAL
+#  else
+#    define LT_DLGLOBAL		0
+#  endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+   find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+#  ifdef RTLD_LAZY
+#    define LT_DLLAZY_OR_NOW		RTLD_LAZY
+#  else
+#    ifdef DL_LAZY
+#      define LT_DLLAZY_OR_NOW		DL_LAZY
+#    else
+#      ifdef RTLD_NOW
+#        define LT_DLLAZY_OR_NOW	RTLD_NOW
+#      else
+#        ifdef DL_NOW
+#          define LT_DLLAZY_OR_NOW	DL_NOW
+#        else
+#          define LT_DLLAZY_OR_NOW	0
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+/* When -fvisibility=hidden is used, assume the code has been annotated
+   correspondingly for the symbols needed.  */
+#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+int fnord () __attribute__((visibility("default")));
+#endif
+
+int fnord () { return 42; }
+int main ()
+{
+  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+  int status = $lt_dlunknown;
+
+  if (self)
+    {
+      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
+      else
+        {
+	  if (dlsym( self,"_fnord"))  status = $lt_dlneed_uscore;
+          else puts (dlerror ());
+	}
+      /* dlclose (self); */
+    }
+  else
+    puts (dlerror ());
+
+  return status;
+}
+_LT_EOF
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then
+    (./conftest; exit; ) >&5 2>/dev/null
+    lt_status=$?
+    case x$lt_status in
+      x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;;
+      x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;;
+      x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;;
+    esac
+  else :
+    # compilation failed
+    lt_cv_dlopen_self=no
+  fi
+fi
+rm -fr conftest*
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5
+$as_echo "$lt_cv_dlopen_self" >&6; }
+
+    if test yes = "$lt_cv_dlopen_self"; then
+      wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5
+$as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; }
+if ${lt_cv_dlopen_self_static+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  	  if test yes = "$cross_compiling"; then :
+  lt_cv_dlopen_self_static=cross
+else
+  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+  lt_status=$lt_dlunknown
+  cat > conftest.$ac_ext <<_LT_EOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+#  define LT_DLGLOBAL		RTLD_GLOBAL
+#else
+#  ifdef DL_GLOBAL
+#    define LT_DLGLOBAL		DL_GLOBAL
+#  else
+#    define LT_DLGLOBAL		0
+#  endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+   find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+#  ifdef RTLD_LAZY
+#    define LT_DLLAZY_OR_NOW		RTLD_LAZY
+#  else
+#    ifdef DL_LAZY
+#      define LT_DLLAZY_OR_NOW		DL_LAZY
+#    else
+#      ifdef RTLD_NOW
+#        define LT_DLLAZY_OR_NOW	RTLD_NOW
+#      else
+#        ifdef DL_NOW
+#          define LT_DLLAZY_OR_NOW	DL_NOW
+#        else
+#          define LT_DLLAZY_OR_NOW	0
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+/* When -fvisibility=hidden is used, assume the code has been annotated
+   correspondingly for the symbols needed.  */
+#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+int fnord () __attribute__((visibility("default")));
+#endif
+
+int fnord () { return 42; }
+int main ()
+{
+  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+  int status = $lt_dlunknown;
+
+  if (self)
+    {
+      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
+      else
+        {
+	  if (dlsym( self,"_fnord"))  status = $lt_dlneed_uscore;
+          else puts (dlerror ());
+	}
+      /* dlclose (self); */
+    }
+  else
+    puts (dlerror ());
+
+  return status;
+}
+_LT_EOF
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then
+    (./conftest; exit; ) >&5 2>/dev/null
+    lt_status=$?
+    case x$lt_status in
+      x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;;
+      x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;;
+      x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;;
+    esac
+  else :
+    # compilation failed
+    lt_cv_dlopen_self_static=no
+  fi
+fi
+rm -fr conftest*
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5
+$as_echo "$lt_cv_dlopen_self_static" >&6; }
+    fi
+
+    CPPFLAGS=$save_CPPFLAGS
+    LDFLAGS=$save_LDFLAGS
+    LIBS=$save_LIBS
+    ;;
+  esac
+
+  case $lt_cv_dlopen_self in
+  yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+  *) enable_dlopen_self=unknown ;;
+  esac
+
+  case $lt_cv_dlopen_self_static in
+  yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+  *) enable_dlopen_self_static=unknown ;;
+  esac
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+striplib=
+old_striplib=
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5
+$as_echo_n "checking whether stripping libraries is possible... " >&6; }
+if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
+  test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+  test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+  case $host_os in
+  darwin*)
+    if test -n "$STRIP"; then
+      striplib="$STRIP -x"
+      old_striplib="$STRIP -S"
+      { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+    else
+      { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+    fi
+    ;;
+  *)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+    ;;
+  esac
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+  # Report what library types will actually be built
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5
+$as_echo_n "checking if libtool supports shared libraries... " >&6; }
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5
+$as_echo "$can_build_shared" >&6; }
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5
+$as_echo_n "checking whether to build shared libraries... " >&6; }
+  test no = "$can_build_shared" && enable_shared=no
+
+  # On AIX, shared libraries and static libraries use the same namespace, and
+  # are all built from PIC.
+  case $host_os in
+  aix3*)
+    test yes = "$enable_shared" && enable_static=no
+    if test -n "$RANLIB"; then
+      archive_cmds="$archive_cmds~\$RANLIB \$lib"
+      postinstall_cmds='$RANLIB $lib'
+    fi
+    ;;
+
+  aix[4-9]*)
+    if test ia64 != "$host_cpu"; then
+      case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in
+      yes,aix,yes) ;;			# shared object as lib.so file only
+      yes,svr4,*) ;;			# shared object as lib.so archive member only
+      yes,*) enable_static=no ;;	# shared object in lib.a archive as well
+      esac
+    fi
+    ;;
+  esac
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5
+$as_echo "$enable_shared" >&6; }
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5
+$as_echo_n "checking whether to build static libraries... " >&6; }
+  # Make sure either enable_shared or enable_static is yes.
+  test yes = "$enable_shared" || enable_static=yes
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5
+$as_echo "$enable_static" >&6; }
+
+
+
+
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+CC=$lt_save_CC
+
+      if test -n "$CXX" && ( test no != "$CXX" &&
+    ( (test g++ = "$CXX" && `g++ -v >/dev/null 2>&1` ) ||
+    (test g++ != "$CXX"))); then
+  ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5
+$as_echo_n "checking how to run the C++ preprocessor... " >&6; }
+if test -z "$CXXCPP"; then
+  if ${ac_cv_prog_CXXCPP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+      # Double quotes because CXXCPP needs to be expanded
+    for CXXCPP in "$CXX -E" "/lib/cpp"
+    do
+      ac_preproc_ok=false
+for ac_cxx_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if ac_fn_cxx_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_cxx_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+  break
+fi
+
+    done
+    ac_cv_prog_CXXCPP=$CXXCPP
+
+fi
+  CXXCPP=$ac_cv_prog_CXXCPP
+else
+  ac_cv_prog_CXXCPP=$CXXCPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5
+$as_echo "$CXXCPP" >&6; }
+ac_preproc_ok=false
+for ac_cxx_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if ac_fn_cxx_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_cxx_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C++ preprocessor \"$CXXCPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+else
+  _lt_caught_CXX_error=yes
+fi
+
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+archive_cmds_need_lc_CXX=no
+allow_undefined_flag_CXX=
+always_export_symbols_CXX=no
+archive_expsym_cmds_CXX=
+compiler_needs_object_CXX=no
+export_dynamic_flag_spec_CXX=
+hardcode_direct_CXX=no
+hardcode_direct_absolute_CXX=no
+hardcode_libdir_flag_spec_CXX=
+hardcode_libdir_separator_CXX=
+hardcode_minus_L_CXX=no
+hardcode_shlibpath_var_CXX=unsupported
+hardcode_automatic_CXX=no
+inherit_rpath_CXX=no
+module_cmds_CXX=
+module_expsym_cmds_CXX=
+link_all_deplibs_CXX=unknown
+old_archive_cmds_CXX=$old_archive_cmds
+reload_flag_CXX=$reload_flag
+reload_cmds_CXX=$reload_cmds
+no_undefined_flag_CXX=
+whole_archive_flag_spec_CXX=
+enable_shared_with_static_runtimes_CXX=no
+
+# Source file extension for C++ test sources.
+ac_ext=cpp
+
+# Object file extension for compiled C++ test sources.
+objext=o
+objext_CXX=$objext
+
+# No sense in running all these tests if we already determined that
+# the CXX compiler isn't working.  Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test yes != "$_lt_caught_CXX_error"; then
+  # Code to be used in simple compile tests
+  lt_simple_compile_test_code="int some_variable = 0;"
+
+  # Code to be used in simple link tests
+  lt_simple_link_test_code='int main(int, char *[]) { return(0); }'
+
+  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+  # save warnings/boilerplate of simple test code
+  ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+
+  ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+
+
+  # Allow CC to be a program name with arguments.
+  lt_save_CC=$CC
+  lt_save_CFLAGS=$CFLAGS
+  lt_save_LD=$LD
+  lt_save_GCC=$GCC
+  GCC=$GXX
+  lt_save_with_gnu_ld=$with_gnu_ld
+  lt_save_path_LD=$lt_cv_path_LD
+  if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
+    lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
+  else
+    $as_unset lt_cv_prog_gnu_ld
+  fi
+  if test -n "${lt_cv_path_LDCXX+set}"; then
+    lt_cv_path_LD=$lt_cv_path_LDCXX
+  else
+    $as_unset lt_cv_path_LD
+  fi
+  test -z "${LDCXX+set}" || LD=$LDCXX
+  CC=${CXX-"c++"}
+  CFLAGS=$CXXFLAGS
+  compiler=$CC
+  compiler_CXX=$CC
+  func_cc_basename $compiler
+cc_basename=$func_cc_basename_result
+
+
+  if test -n "$compiler"; then
+    # We don't want -fno-exception when compiling C++ code, so set the
+    # no_builtin_flag separately
+    if test yes = "$GXX"; then
+      lt_prog_compiler_no_builtin_flag_CXX=' -fno-builtin'
+    else
+      lt_prog_compiler_no_builtin_flag_CXX=
+    fi
+
+    if test yes = "$GXX"; then
+      # Set up default GNU C++ configuration
+
+
+
+# Check whether --with-gnu-ld was given.
+if test "${with_gnu_ld+set}" = set; then :
+  withval=$with_gnu_ld; test no = "$withval" || with_gnu_ld=yes
+else
+  with_gnu_ld=no
+fi
+
+ac_prog=ld
+if test yes = "$GCC"; then
+  # Check if gcc -print-prog-name=ld gives a path.
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5
+$as_echo_n "checking for ld used by $CC... " >&6; }
+  case $host in
+  *-*-mingw*)
+    # gcc leaves a trailing carriage return, which upsets mingw
+    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+  *)
+    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+  esac
+  case $ac_prog in
+    # Accept absolute paths.
+    [\\/]* | ?:[\\/]*)
+      re_direlt='/[^/][^/]*/\.\./'
+      # Canonicalize the pathname of ld
+      ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+      while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+	ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+      done
+      test -z "$LD" && LD=$ac_prog
+      ;;
+  "")
+    # If it fails, then pretend we aren't using GCC.
+    ac_prog=ld
+    ;;
+  *)
+    # If it is relative, then search for the first ld in PATH.
+    with_gnu_ld=unknown
+    ;;
+  esac
+elif test yes = "$with_gnu_ld"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5
+$as_echo_n "checking for GNU ld... " >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5
+$as_echo_n "checking for non-GNU ld... " >&6; }
+fi
+if ${lt_cv_path_LD+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$LD"; then
+  lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
+  for ac_dir in $PATH; do
+    IFS=$lt_save_ifs
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+      lt_cv_path_LD=$ac_dir/$ac_prog
+      # Check to see if the program is GNU ld.  I'd rather use --version,
+      # but apparently some variants of GNU ld only accept -v.
+      # Break only if it was the GNU/non-GNU ld that we prefer.
+      case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+      *GNU* | *'with BFD'*)
+	test no != "$with_gnu_ld" && break
+	;;
+      *)
+	test yes != "$with_gnu_ld" && break
+	;;
+      esac
+    fi
+  done
+  IFS=$lt_save_ifs
+else
+  lt_cv_path_LD=$LD # Let the user override the test with a path.
+fi
+fi
+
+LD=$lt_cv_path_LD
+if test -n "$LD"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5
+$as_echo "$LD" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5
+$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; }
+if ${lt_cv_prog_gnu_ld+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  # I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+  lt_cv_prog_gnu_ld=yes
+  ;;
+*)
+  lt_cv_prog_gnu_ld=no
+  ;;
+esac
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5
+$as_echo "$lt_cv_prog_gnu_ld" >&6; }
+with_gnu_ld=$lt_cv_prog_gnu_ld
+
+
+
+
+
+
+
+      # Check if GNU C++ uses GNU ld as the underlying linker, since the
+      # archiving commands below assume that GNU ld is being used.
+      if test yes = "$with_gnu_ld"; then
+        archive_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+        archive_expsym_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+
+        hardcode_libdir_flag_spec_CXX='$wl-rpath $wl$libdir'
+        export_dynamic_flag_spec_CXX='$wl--export-dynamic'
+
+        # If archive_cmds runs LD, not CC, wlarc should be empty
+        # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
+        #     investigate it a little bit more. (MM)
+        wlarc='$wl'
+
+        # ancient GNU ld didn't support --whole-archive et. al.
+        if eval "`$CC -print-prog-name=ld` --help 2>&1" |
+	  $GREP 'no-whole-archive' > /dev/null; then
+          whole_archive_flag_spec_CXX=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
+        else
+          whole_archive_flag_spec_CXX=
+        fi
+      else
+        with_gnu_ld=no
+        wlarc=
+
+        # A generic and very simple default shared library creation
+        # command for GNU C++ for the case where it uses the native
+        # linker, instead of GNU ld.  If possible, this setting should
+        # overridden to take advantage of the native linker features on
+        # the platform it is being used on.
+        archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+      fi
+
+      # Commands to make compiler produce verbose output that lists
+      # what "hidden" libraries, object files and flags are used when
+      # linking a shared library.
+      output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+
+    else
+      GXX=no
+      with_gnu_ld=no
+      wlarc=
+    fi
+
+    # PORTME: fill in a description of your system's C++ link characteristics
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
+    ld_shlibs_CXX=yes
+    case $host_os in
+      aix3*)
+        # FIXME: insert proper C++ library support
+        ld_shlibs_CXX=no
+        ;;
+      aix[4-9]*)
+        if test ia64 = "$host_cpu"; then
+          # On IA64, the linker does run time linking by default, so we don't
+          # have to do anything special.
+          aix_use_runtimelinking=no
+          exp_sym_flag='-Bexport'
+          no_entry_flag=
+        else
+          aix_use_runtimelinking=no
+
+          # Test if we are trying to use run time linking or normal
+          # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+          # have runtime linking enabled, and use it for executables.
+          # For shared libraries, we enable/disable runtime linking
+          # depending on the kind of the shared library created -
+          # when "with_aix_soname,aix_use_runtimelinking" is:
+          # "aix,no"   lib.a(lib.so.V) shared, rtl:no,  for executables
+          # "aix,yes"  lib.so          shared, rtl:yes, for executables
+          #            lib.a           static archive
+          # "both,no"  lib.so.V(shr.o) shared, rtl:yes
+          #            lib.a(lib.so.V) shared, rtl:no,  for executables
+          # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables
+          #            lib.a(lib.so.V) shared, rtl:no
+          # "svr4,*"   lib.so.V(shr.o) shared, rtl:yes, for executables
+          #            lib.a           static archive
+          case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*)
+	    for ld_flag in $LDFLAGS; do
+	      case $ld_flag in
+	      *-brtl*)
+	        aix_use_runtimelinking=yes
+	        break
+	        ;;
+	      esac
+	    done
+	    if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then
+	      # With aix-soname=svr4, we create the lib.so.V shared archives only,
+	      # so we don't have lib.a shared libs to link our executables.
+	      # We have to force runtime linking in this case.
+	      aix_use_runtimelinking=yes
+	      LDFLAGS="$LDFLAGS -Wl,-brtl"
+	    fi
+	    ;;
+          esac
+
+          exp_sym_flag='-bexport'
+          no_entry_flag='-bnoentry'
+        fi
+
+        # When large executables or shared objects are built, AIX ld can
+        # have problems creating the table of contents.  If linking a library
+        # or program results in "error TOC overflow" add -mminimal-toc to
+        # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+        # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+        archive_cmds_CXX=''
+        hardcode_direct_CXX=yes
+        hardcode_direct_absolute_CXX=yes
+        hardcode_libdir_separator_CXX=':'
+        link_all_deplibs_CXX=yes
+        file_list_spec_CXX='$wl-f,'
+        case $with_aix_soname,$aix_use_runtimelinking in
+        aix,*) ;;	# no import file
+        svr4,* | *,yes) # use import file
+          # The Import File defines what to hardcode.
+          hardcode_direct_CXX=no
+          hardcode_direct_absolute_CXX=no
+          ;;
+        esac
+
+        if test yes = "$GXX"; then
+          case $host_os in aix4.[012]|aix4.[012].*)
+          # We only want to do this on AIX 4.2 and lower, the check
+          # below for broken collect2 doesn't work under 4.3+
+	  collect2name=`$CC -print-prog-name=collect2`
+	  if test -f "$collect2name" &&
+	     strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+	  then
+	    # We have reworked collect2
+	    :
+	  else
+	    # We have old collect2
+	    hardcode_direct_CXX=unsupported
+	    # It fails to find uninstalled libraries when the uninstalled
+	    # path is not listed in the libpath.  Setting hardcode_minus_L
+	    # to unsupported forces relinking
+	    hardcode_minus_L_CXX=yes
+	    hardcode_libdir_flag_spec_CXX='-L$libdir'
+	    hardcode_libdir_separator_CXX=
+	  fi
+          esac
+          shared_flag='-shared'
+	  if test yes = "$aix_use_runtimelinking"; then
+	    shared_flag=$shared_flag' $wl-G'
+	  fi
+	  # Need to ensure runtime linking is disabled for the traditional
+	  # shared library, or the linker may eventually find shared libraries
+	  # /with/ Import File - we do not want to mix them.
+	  shared_flag_aix='-shared'
+	  shared_flag_svr4='-shared $wl-G'
+        else
+          # not using gcc
+          if test ia64 = "$host_cpu"; then
+	  # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+	  # chokes on -Wl,-G. The following line is correct:
+	  shared_flag='-G'
+          else
+	    if test yes = "$aix_use_runtimelinking"; then
+	      shared_flag='$wl-G'
+	    else
+	      shared_flag='$wl-bM:SRE'
+	    fi
+	    shared_flag_aix='$wl-bM:SRE'
+	    shared_flag_svr4='$wl-G'
+          fi
+        fi
+
+        export_dynamic_flag_spec_CXX='$wl-bexpall'
+        # It seems that -bexpall does not export symbols beginning with
+        # underscore (_), so it is better to generate a list of symbols to
+	# export.
+        always_export_symbols_CXX=yes
+	if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then
+          # Warning - without using the other runtime loading flags (-brtl),
+          # -berok will link without error, but may produce a broken library.
+          # The "-G" linker flag allows undefined symbols.
+          no_undefined_flag_CXX='-bernotok'
+          # Determine the default libpath from the value encoded in an empty
+          # executable.
+          if test set = "${lt_cv_aix_libpath+set}"; then
+  aix_libpath=$lt_cv_aix_libpath
+else
+  if ${lt_cv_aix_libpath__CXX+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+
+  lt_aix_libpath_sed='
+      /Import File Strings/,/^$/ {
+	  /^0/ {
+	      s/^0  *\([^ ]*\) *$/\1/
+	      p
+	  }
+      }'
+  lt_cv_aix_libpath__CXX=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  # Check for a 64-bit object if we didn't find anything.
+  if test -z "$lt_cv_aix_libpath__CXX"; then
+    lt_cv_aix_libpath__CXX=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  if test -z "$lt_cv_aix_libpath__CXX"; then
+    lt_cv_aix_libpath__CXX=/usr/lib:/lib
+  fi
+
+fi
+
+  aix_libpath=$lt_cv_aix_libpath__CXX
+fi
+
+          hardcode_libdir_flag_spec_CXX='$wl-blibpath:$libdir:'"$aix_libpath"
+
+          archive_expsym_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag
+        else
+          if test ia64 = "$host_cpu"; then
+	    hardcode_libdir_flag_spec_CXX='$wl-R $libdir:/usr/lib:/lib'
+	    allow_undefined_flag_CXX="-z nodefs"
+	    archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols"
+          else
+	    # Determine the default libpath from the value encoded in an
+	    # empty executable.
+	    if test set = "${lt_cv_aix_libpath+set}"; then
+  aix_libpath=$lt_cv_aix_libpath
+else
+  if ${lt_cv_aix_libpath__CXX+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+
+  lt_aix_libpath_sed='
+      /Import File Strings/,/^$/ {
+	  /^0/ {
+	      s/^0  *\([^ ]*\) *$/\1/
+	      p
+	  }
+      }'
+  lt_cv_aix_libpath__CXX=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  # Check for a 64-bit object if we didn't find anything.
+  if test -z "$lt_cv_aix_libpath__CXX"; then
+    lt_cv_aix_libpath__CXX=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  if test -z "$lt_cv_aix_libpath__CXX"; then
+    lt_cv_aix_libpath__CXX=/usr/lib:/lib
+  fi
+
+fi
+
+  aix_libpath=$lt_cv_aix_libpath__CXX
+fi
+
+	    hardcode_libdir_flag_spec_CXX='$wl-blibpath:$libdir:'"$aix_libpath"
+	    # Warning - without using the other run time loading flags,
+	    # -berok will link without error, but may produce a broken library.
+	    no_undefined_flag_CXX=' $wl-bernotok'
+	    allow_undefined_flag_CXX=' $wl-berok'
+	    if test yes = "$with_gnu_ld"; then
+	      # We only use this code for GNU lds that support --whole-archive.
+	      whole_archive_flag_spec_CXX='$wl--whole-archive$convenience $wl--no-whole-archive'
+	    else
+	      # Exported symbols can be pulled into shared objects from archives
+	      whole_archive_flag_spec_CXX='$convenience'
+	    fi
+	    archive_cmds_need_lc_CXX=yes
+	    archive_expsym_cmds_CXX='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d'
+	    # -brtl affects multiple linker settings, -berok does not and is overridden later
+	    compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([, ]\\)%-berok\\1%g"`'
+	    if test svr4 != "$with_aix_soname"; then
+	      # This is similar to how AIX traditionally builds its shared
+	      # libraries. Need -bnortl late, we may have -brtl in LDFLAGS.
+	      archive_expsym_cmds_CXX="$archive_expsym_cmds_CXX"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname'
+	    fi
+	    if test aix != "$with_aix_soname"; then
+	      archive_expsym_cmds_CXX="$archive_expsym_cmds_CXX"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp'
+	    else
+	      # used by -dlpreopen to get the symbols
+	      archive_expsym_cmds_CXX="$archive_expsym_cmds_CXX"'~$MV  $output_objdir/$realname.d/$soname $output_objdir'
+	    fi
+	    archive_expsym_cmds_CXX="$archive_expsym_cmds_CXX"'~$RM -r $output_objdir/$realname.d'
+          fi
+        fi
+        ;;
+
+      beos*)
+	if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	  allow_undefined_flag_CXX=unsupported
+	  # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+	  # support --undefined.  This deserves some investigation.  FIXME
+	  archive_cmds_CXX='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+	else
+	  ld_shlibs_CXX=no
+	fi
+	;;
+
+      chorus*)
+        case $cc_basename in
+          *)
+	  # FIXME: insert proper C++ library support
+	  ld_shlibs_CXX=no
+	  ;;
+        esac
+        ;;
+
+      cygwin* | mingw* | pw32* | cegcc*)
+	case $GXX,$cc_basename in
+	,cl* | no,cl*)
+	  # Native MSVC
+	  # hardcode_libdir_flag_spec is actually meaningless, as there is
+	  # no search path for DLLs.
+	  hardcode_libdir_flag_spec_CXX=' '
+	  allow_undefined_flag_CXX=unsupported
+	  always_export_symbols_CXX=yes
+	  file_list_spec_CXX='@'
+	  # Tell ltmain to make .lib files, not .a files.
+	  libext=lib
+	  # Tell ltmain to make .dll files, not .so files.
+	  shrext_cmds=.dll
+	  # FIXME: Setting linknames here is a bad hack.
+	  archive_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames='
+	  archive_expsym_cmds_CXX='if   test DEF = "`$SED -n     -e '\''s/^[	 ]*//'\''     -e '\''/^\(;.*\)*$/d'\''     -e '\''s/^\(EXPORTS\|LIBRARY\)\([	 ].*\)*$/DEF/p'\''     -e q     $export_symbols`" ; then
+              cp "$export_symbols" "$output_objdir/$soname.def";
+              echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp";
+            else
+              $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp;
+            fi~
+            $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+            linknames='
+	  # The linker will not automatically build a static lib if we build a DLL.
+	  # _LT_TAGVAR(old_archive_from_new_cmds, CXX)='true'
+	  enable_shared_with_static_runtimes_CXX=yes
+	  # Don't use ranlib
+	  old_postinstall_cmds_CXX='chmod 644 $oldlib'
+	  postlink_cmds_CXX='lt_outputfile="@OUTPUT@"~
+            lt_tool_outputfile="@TOOL_OUTPUT@"~
+            case $lt_outputfile in
+              *.exe|*.EXE) ;;
+              *)
+                lt_outputfile=$lt_outputfile.exe
+                lt_tool_outputfile=$lt_tool_outputfile.exe
+                ;;
+            esac~
+            func_to_tool_file "$lt_outputfile"~
+            if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then
+              $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+              $RM "$lt_outputfile.manifest";
+            fi'
+	  ;;
+	*)
+	  # g++
+	  # _LT_TAGVAR(hardcode_libdir_flag_spec, CXX) is actually meaningless,
+	  # as there is no search path for DLLs.
+	  hardcode_libdir_flag_spec_CXX='-L$libdir'
+	  export_dynamic_flag_spec_CXX='$wl--export-all-symbols'
+	  allow_undefined_flag_CXX=unsupported
+	  always_export_symbols_CXX=no
+	  enable_shared_with_static_runtimes_CXX=yes
+
+	  if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+	    archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+	    # If the export-symbols file already is a .def file, use it as
+	    # is; otherwise, prepend EXPORTS...
+	    archive_expsym_cmds_CXX='if   test DEF = "`$SED -n     -e '\''s/^[	 ]*//'\''     -e '\''/^\(;.*\)*$/d'\''     -e '\''s/^\(EXPORTS\|LIBRARY\)\([	 ].*\)*$/DEF/p'\''     -e q     $export_symbols`" ; then
+              cp $export_symbols $output_objdir/$soname.def;
+            else
+              echo EXPORTS > $output_objdir/$soname.def;
+              cat $export_symbols >> $output_objdir/$soname.def;
+            fi~
+            $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+	  else
+	    ld_shlibs_CXX=no
+	  fi
+	  ;;
+	esac
+	;;
+      darwin* | rhapsody*)
+
+
+  archive_cmds_need_lc_CXX=no
+  hardcode_direct_CXX=no
+  hardcode_automatic_CXX=yes
+  hardcode_shlibpath_var_CXX=unsupported
+  if test yes = "$lt_cv_ld_force_load"; then
+    whole_archive_flag_spec_CXX='`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+
+  else
+    whole_archive_flag_spec_CXX=''
+  fi
+  link_all_deplibs_CXX=yes
+  allow_undefined_flag_CXX=$_lt_dar_allow_undefined
+  case $cc_basename in
+     ifort*|nagfor*) _lt_dar_can_shared=yes ;;
+     *) _lt_dar_can_shared=$GCC ;;
+  esac
+  if test yes = "$_lt_dar_can_shared"; then
+    output_verbose_link_cmd=func_echo_all
+    archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil"
+    module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil"
+    archive_expsym_cmds_CXX="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil"
+    module_expsym_cmds_CXX="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil"
+       if test yes != "$lt_cv_apple_cc_single_mod"; then
+      archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dsymutil"
+      archive_expsym_cmds_CXX="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dar_export_syms$_lt_dsymutil"
+    fi
+
+  else
+  ld_shlibs_CXX=no
+  fi
+
+	;;
+
+      os2*)
+	hardcode_libdir_flag_spec_CXX='-L$libdir'
+	hardcode_minus_L_CXX=yes
+	allow_undefined_flag_CXX=unsupported
+	shrext_cmds=.dll
+	archive_cmds_CXX='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+	  $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+	  $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+	  $ECHO EXPORTS >> $output_objdir/$libname.def~
+	  emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
+	  $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+	  emximp -o $lib $output_objdir/$libname.def'
+	archive_expsym_cmds_CXX='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+	  $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+	  $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+	  $ECHO EXPORTS >> $output_objdir/$libname.def~
+	  prefix_cmds="$SED"~
+	  if test EXPORTS = "`$SED 1q $export_symbols`"; then
+	    prefix_cmds="$prefix_cmds -e 1d";
+	  fi~
+	  prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
+	  cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
+	  $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+	  emximp -o $lib $output_objdir/$libname.def'
+	old_archive_From_new_cmds_CXX='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
+	enable_shared_with_static_runtimes_CXX=yes
+	;;
+
+      dgux*)
+        case $cc_basename in
+          ec++*)
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+          ghcx*)
+	    # Green Hills C++ Compiler
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+          *)
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+        esac
+        ;;
+
+      freebsd2.*)
+        # C++ shared libraries reported to be fairly broken before
+	# switch to ELF
+        ld_shlibs_CXX=no
+        ;;
+
+      freebsd-elf*)
+        archive_cmds_need_lc_CXX=no
+        ;;
+
+      freebsd* | dragonfly*)
+        # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
+        # conventions
+        ld_shlibs_CXX=yes
+        ;;
+
+      haiku*)
+        archive_cmds_CXX='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+        link_all_deplibs_CXX=yes
+        ;;
+
+      hpux9*)
+        hardcode_libdir_flag_spec_CXX='$wl+b $wl$libdir'
+        hardcode_libdir_separator_CXX=:
+        export_dynamic_flag_spec_CXX='$wl-E'
+        hardcode_direct_CXX=yes
+        hardcode_minus_L_CXX=yes # Not in the search PATH,
+				             # but as the default
+				             # location of the library.
+
+        case $cc_basename in
+          CC*)
+            # FIXME: insert proper C++ library support
+            ld_shlibs_CXX=no
+            ;;
+          aCC*)
+            archive_cmds_CXX='$RM $output_objdir/$soname~$CC -b $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
+            # Commands to make compiler produce verbose output that lists
+            # what "hidden" libraries, object files and flags are used when
+            # linking a shared library.
+            #
+            # There doesn't appear to be a way to prevent this compiler from
+            # explicitly linking system object files so we need to strip them
+            # from the output so that they don't get included in the library
+            # dependencies.
+            output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+            ;;
+          *)
+            if test yes = "$GXX"; then
+              archive_cmds_CXX='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
+            else
+              # FIXME: insert proper C++ library support
+              ld_shlibs_CXX=no
+            fi
+            ;;
+        esac
+        ;;
+
+      hpux10*|hpux11*)
+        if test no = "$with_gnu_ld"; then
+	  hardcode_libdir_flag_spec_CXX='$wl+b $wl$libdir'
+	  hardcode_libdir_separator_CXX=:
+
+          case $host_cpu in
+            hppa*64*|ia64*)
+              ;;
+            *)
+	      export_dynamic_flag_spec_CXX='$wl-E'
+              ;;
+          esac
+        fi
+        case $host_cpu in
+          hppa*64*|ia64*)
+            hardcode_direct_CXX=no
+            hardcode_shlibpath_var_CXX=no
+            ;;
+          *)
+            hardcode_direct_CXX=yes
+            hardcode_direct_absolute_CXX=yes
+            hardcode_minus_L_CXX=yes # Not in the search PATH,
+					         # but as the default
+					         # location of the library.
+            ;;
+        esac
+
+        case $cc_basename in
+          CC*)
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+          aCC*)
+	    case $host_cpu in
+	      hppa*64*)
+	        archive_cmds_CXX='$CC -b $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	        ;;
+	      ia64*)
+	        archive_cmds_CXX='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	        ;;
+	      *)
+	        archive_cmds_CXX='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	        ;;
+	    esac
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+	    ;;
+          *)
+	    if test yes = "$GXX"; then
+	      if test no = "$with_gnu_ld"; then
+	        case $host_cpu in
+	          hppa*64*)
+	            archive_cmds_CXX='$CC -shared -nostdlib -fPIC $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	            ;;
+	          ia64*)
+	            archive_cmds_CXX='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	            ;;
+	          *)
+	            archive_cmds_CXX='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	            ;;
+	        esac
+	      fi
+	    else
+	      # FIXME: insert proper C++ library support
+	      ld_shlibs_CXX=no
+	    fi
+	    ;;
+        esac
+        ;;
+
+      interix[3-9]*)
+	hardcode_direct_CXX=no
+	hardcode_shlibpath_var_CXX=no
+	hardcode_libdir_flag_spec_CXX='$wl-rpath,$libdir'
+	export_dynamic_flag_spec_CXX='$wl-E'
+	# Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+	# Instead, shared libraries are loaded at an image base (0x10000000 by
+	# default) and relocated if they conflict, which is a slow very memory
+	# consuming and fragmenting process.  To avoid this, we pick a random,
+	# 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+	# time.  Moving up from 0x10000000 also allows more sbrk(2) space.
+	archive_cmds_CXX='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+	archive_expsym_cmds_CXX='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+	;;
+      irix5* | irix6*)
+        case $cc_basename in
+          CC*)
+	    # SGI C++
+	    archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+
+	    # Archives containing C++ object files must be created using
+	    # "CC -ar", where "CC" is the IRIX C++ compiler.  This is
+	    # necessary to make sure instantiated templates are included
+	    # in the archive.
+	    old_archive_cmds_CXX='$CC -ar -WR,-u -o $oldlib $oldobjs'
+	    ;;
+          *)
+	    if test yes = "$GXX"; then
+	      if test no = "$with_gnu_ld"; then
+	        archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+	      else
+	        archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` -o $lib'
+	      fi
+	    fi
+	    link_all_deplibs_CXX=yes
+	    ;;
+        esac
+        hardcode_libdir_flag_spec_CXX='$wl-rpath $wl$libdir'
+        hardcode_libdir_separator_CXX=:
+        inherit_rpath_CXX=yes
+        ;;
+
+      linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+        case $cc_basename in
+          KCC*)
+	    # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+	    # KCC will only create a shared library if the output file
+	    # ends with ".so" (or ".sl" for HP-UX), so rename the library
+	    # to its proper name (with version) after linking.
+	    archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+	    archive_expsym_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib $wl-retain-symbols-file,$export_symbols; mv \$templib $lib'
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+
+	    hardcode_libdir_flag_spec_CXX='$wl-rpath,$libdir'
+	    export_dynamic_flag_spec_CXX='$wl--export-dynamic'
+
+	    # Archives containing C++ object files must be created using
+	    # "CC -Bstatic", where "CC" is the KAI C++ compiler.
+	    old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs'
+	    ;;
+	  icpc* | ecpc* )
+	    # Intel C++
+	    with_gnu_ld=yes
+	    # version 8.0 and above of icpc choke on multiply defined symbols
+	    # if we add $predep_objects and $postdep_objects, however 7.1 and
+	    # earlier do not add the objects themselves.
+	    case `$CC -V 2>&1` in
+	      *"Version 7."*)
+	        archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+		archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+		;;
+	      *)  # Version 8.0 or newer
+	        tmp_idyn=
+	        case $host_cpu in
+		  ia64*) tmp_idyn=' -i_dynamic';;
+		esac
+	        archive_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+		archive_expsym_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+		;;
+	    esac
+	    archive_cmds_need_lc_CXX=no
+	    hardcode_libdir_flag_spec_CXX='$wl-rpath,$libdir'
+	    export_dynamic_flag_spec_CXX='$wl--export-dynamic'
+	    whole_archive_flag_spec_CXX='$wl--whole-archive$convenience $wl--no-whole-archive'
+	    ;;
+          pgCC* | pgcpp*)
+            # Portland Group C++ compiler
+	    case `$CC -V` in
+	    *pgCC\ [1-5].* | *pgcpp\ [1-5].*)
+	      prelink_cmds_CXX='tpldir=Template.dir~
+               rm -rf $tpldir~
+               $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
+               compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
+	      old_archive_cmds_CXX='tpldir=Template.dir~
+                rm -rf $tpldir~
+                $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
+                $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
+                $RANLIB $oldlib'
+	      archive_cmds_CXX='tpldir=Template.dir~
+                rm -rf $tpldir~
+                $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+                $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+	      archive_expsym_cmds_CXX='tpldir=Template.dir~
+                rm -rf $tpldir~
+                $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+                $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+	      ;;
+	    *) # Version 6 and above use weak symbols
+	      archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+	      archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+	      ;;
+	    esac
+
+	    hardcode_libdir_flag_spec_CXX='$wl--rpath $wl$libdir'
+	    export_dynamic_flag_spec_CXX='$wl--export-dynamic'
+	    whole_archive_flag_spec_CXX='$wl--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+            ;;
+	  cxx*)
+	    # Compaq C++
+	    archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+	    archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname  -o $lib $wl-retain-symbols-file $wl$export_symbols'
+
+	    runpath_var=LD_RUN_PATH
+	    hardcode_libdir_flag_spec_CXX='-rpath $libdir'
+	    hardcode_libdir_separator_CXX=:
+
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed'
+	    ;;
+	  xl* | mpixl* | bgxl*)
+	    # IBM XL 8.0 on PPC, with GNU ld
+	    hardcode_libdir_flag_spec_CXX='$wl-rpath $wl$libdir'
+	    export_dynamic_flag_spec_CXX='$wl--export-dynamic'
+	    archive_cmds_CXX='$CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+	    if test yes = "$supports_anon_versioning"; then
+	      archive_expsym_cmds_CXX='echo "{ global:" > $output_objdir/$libname.ver~
+                cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+                echo "local: *; };" >> $output_objdir/$libname.ver~
+                $CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib'
+	    fi
+	    ;;
+	  *)
+	    case `$CC -V 2>&1 | sed 5q` in
+	    *Sun\ C*)
+	      # Sun C++ 5.9
+	      no_undefined_flag_CXX=' -zdefs'
+	      archive_cmds_CXX='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	      archive_expsym_cmds_CXX='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file $wl$export_symbols'
+	      hardcode_libdir_flag_spec_CXX='-R$libdir'
+	      whole_archive_flag_spec_CXX='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+	      compiler_needs_object_CXX=yes
+
+	      # Not sure whether something based on
+	      # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1
+	      # would be better.
+	      output_verbose_link_cmd='func_echo_all'
+
+	      # Archives containing C++ object files must be created using
+	      # "CC -xar", where "CC" is the Sun C++ compiler.  This is
+	      # necessary to make sure instantiated templates are included
+	      # in the archive.
+	      old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs'
+	      ;;
+	    esac
+	    ;;
+	esac
+	;;
+
+      lynxos*)
+        # FIXME: insert proper C++ library support
+	ld_shlibs_CXX=no
+	;;
+
+      m88k*)
+        # FIXME: insert proper C++ library support
+        ld_shlibs_CXX=no
+	;;
+
+      mvs*)
+        case $cc_basename in
+          cxx*)
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+	  *)
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+	esac
+	;;
+
+      netbsd*)
+        if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+	  archive_cmds_CXX='$LD -Bshareable  -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
+	  wlarc=
+	  hardcode_libdir_flag_spec_CXX='-R$libdir'
+	  hardcode_direct_CXX=yes
+	  hardcode_shlibpath_var_CXX=no
+	fi
+	# Workaround some broken pre-1.5 toolchains
+	output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
+	;;
+
+      *nto* | *qnx*)
+        ld_shlibs_CXX=yes
+	;;
+
+      openbsd* | bitrig*)
+	if test -f /usr/libexec/ld.so; then
+	  hardcode_direct_CXX=yes
+	  hardcode_shlibpath_var_CXX=no
+	  hardcode_direct_absolute_CXX=yes
+	  archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+	  hardcode_libdir_flag_spec_CXX='$wl-rpath,$libdir'
+	  if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`"; then
+	    archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file,$export_symbols -o $lib'
+	    export_dynamic_flag_spec_CXX='$wl-E'
+	    whole_archive_flag_spec_CXX=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
+	  fi
+	  output_verbose_link_cmd=func_echo_all
+	else
+	  ld_shlibs_CXX=no
+	fi
+	;;
+
+      osf3* | osf4* | osf5*)
+        case $cc_basename in
+          KCC*)
+	    # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+	    # KCC will only create a shared library if the output file
+	    # ends with ".so" (or ".sl" for HP-UX), so rename the library
+	    # to its proper name (with version) after linking.
+	    archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+	    hardcode_libdir_flag_spec_CXX='$wl-rpath,$libdir'
+	    hardcode_libdir_separator_CXX=:
+
+	    # Archives containing C++ object files must be created using
+	    # the KAI C++ compiler.
+	    case $host in
+	      osf3*) old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' ;;
+	      *) old_archive_cmds_CXX='$CC -o $oldlib $oldobjs' ;;
+	    esac
+	    ;;
+          RCC*)
+	    # Rational C++ 2.4.1
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+          cxx*)
+	    case $host in
+	      osf3*)
+	        allow_undefined_flag_CXX=' $wl-expect_unresolved $wl\*'
+	        archive_cmds_CXX='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $soname `test -n "$verstring" && func_echo_all "$wl-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+	        hardcode_libdir_flag_spec_CXX='$wl-rpath $wl$libdir'
+		;;
+	      *)
+	        allow_undefined_flag_CXX=' -expect_unresolved \*'
+	        archive_cmds_CXX='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+	        archive_expsym_cmds_CXX='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
+                  echo "-hidden">> $lib.exp~
+                  $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname $wl-input $wl$lib.exp  `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~
+                  $RM $lib.exp'
+	        hardcode_libdir_flag_spec_CXX='-rpath $libdir'
+		;;
+	    esac
+
+	    hardcode_libdir_separator_CXX=:
+
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+	    ;;
+	  *)
+	    if test yes,no = "$GXX,$with_gnu_ld"; then
+	      allow_undefined_flag_CXX=' $wl-expect_unresolved $wl\*'
+	      case $host in
+	        osf3*)
+	          archive_cmds_CXX='$CC -shared -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+		  ;;
+	        *)
+	          archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+		  ;;
+	      esac
+
+	      hardcode_libdir_flag_spec_CXX='$wl-rpath $wl$libdir'
+	      hardcode_libdir_separator_CXX=:
+
+	      # Commands to make compiler produce verbose output that lists
+	      # what "hidden" libraries, object files and flags are used when
+	      # linking a shared library.
+	      output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+
+	    else
+	      # FIXME: insert proper C++ library support
+	      ld_shlibs_CXX=no
+	    fi
+	    ;;
+        esac
+        ;;
+
+      psos*)
+        # FIXME: insert proper C++ library support
+        ld_shlibs_CXX=no
+        ;;
+
+      sunos4*)
+        case $cc_basename in
+          CC*)
+	    # Sun C++ 4.x
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+          lcc*)
+	    # Lucid
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+          *)
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+        esac
+        ;;
+
+      solaris*)
+        case $cc_basename in
+          CC* | sunCC*)
+	    # Sun C++ 4.2, 5.x and Centerline C++
+            archive_cmds_need_lc_CXX=yes
+	    no_undefined_flag_CXX=' -zdefs'
+	    archive_cmds_CXX='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	    archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+              $CC -G$allow_undefined_flag $wl-M $wl$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+	    hardcode_libdir_flag_spec_CXX='-R$libdir'
+	    hardcode_shlibpath_var_CXX=no
+	    case $host_os in
+	      solaris2.[0-5] | solaris2.[0-5].*) ;;
+	      *)
+		# The compiler driver will combine and reorder linker options,
+		# but understands '-z linker_flag'.
+	        # Supported since Solaris 2.6 (maybe 2.5.1?)
+		whole_archive_flag_spec_CXX='-z allextract$convenience -z defaultextract'
+	        ;;
+	    esac
+	    link_all_deplibs_CXX=yes
+
+	    output_verbose_link_cmd='func_echo_all'
+
+	    # Archives containing C++ object files must be created using
+	    # "CC -xar", where "CC" is the Sun C++ compiler.  This is
+	    # necessary to make sure instantiated templates are included
+	    # in the archive.
+	    old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs'
+	    ;;
+          gcx*)
+	    # Green Hills C++ Compiler
+	    archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib'
+
+	    # The C++ compiler must be used to create the archive.
+	    old_archive_cmds_CXX='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
+	    ;;
+          *)
+	    # GNU C++ compiler with Solaris linker
+	    if test yes,no = "$GXX,$with_gnu_ld"; then
+	      no_undefined_flag_CXX=' $wl-z ${wl}defs'
+	      if $CC --version | $GREP -v '^2\.7' > /dev/null; then
+	        archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib'
+	        archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+                  $CC -shared $pic_flag -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+	        # Commands to make compiler produce verbose output that lists
+	        # what "hidden" libraries, object files and flags are used when
+	        # linking a shared library.
+	        output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+	      else
+	        # g++ 2.7 appears to require '-G' NOT '-shared' on this
+	        # platform.
+	        archive_cmds_CXX='$CC -G -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib'
+	        archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+                  $CC -G -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+	        # Commands to make compiler produce verbose output that lists
+	        # what "hidden" libraries, object files and flags are used when
+	        # linking a shared library.
+	        output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+	      fi
+
+	      hardcode_libdir_flag_spec_CXX='$wl-R $wl$libdir'
+	      case $host_os in
+		solaris2.[0-5] | solaris2.[0-5].*) ;;
+		*)
+		  whole_archive_flag_spec_CXX='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract'
+		  ;;
+	      esac
+	    fi
+	    ;;
+        esac
+        ;;
+
+    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
+      no_undefined_flag_CXX='$wl-z,text'
+      archive_cmds_need_lc_CXX=no
+      hardcode_shlibpath_var_CXX=no
+      runpath_var='LD_RUN_PATH'
+
+      case $cc_basename in
+        CC*)
+	  archive_cmds_CXX='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  archive_expsym_cmds_CXX='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+	  archive_cmds_CXX='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  archive_expsym_cmds_CXX='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+      esac
+      ;;
+
+      sysv5* | sco3.2v5* | sco5v6*)
+	# Note: We CANNOT use -z defs as we might desire, because we do not
+	# link with -lc, and that would cause any symbols used from libc to
+	# always be unresolved, which means just about no library would
+	# ever link correctly.  If we're not using GNU ld we use -z text
+	# though, which does catch some bad symbols but isn't as heavy-handed
+	# as -z defs.
+	no_undefined_flag_CXX='$wl-z,text'
+	allow_undefined_flag_CXX='$wl-z,nodefs'
+	archive_cmds_need_lc_CXX=no
+	hardcode_shlibpath_var_CXX=no
+	hardcode_libdir_flag_spec_CXX='$wl-R,$libdir'
+	hardcode_libdir_separator_CXX=':'
+	link_all_deplibs_CXX=yes
+	export_dynamic_flag_spec_CXX='$wl-Bexport'
+	runpath_var='LD_RUN_PATH'
+
+	case $cc_basename in
+          CC*)
+	    archive_cmds_CXX='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    archive_expsym_cmds_CXX='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    old_archive_cmds_CXX='$CC -Tprelink_objects $oldobjs~
+              '"$old_archive_cmds_CXX"
+	    reload_cmds_CXX='$CC -Tprelink_objects $reload_objs~
+              '"$reload_cmds_CXX"
+	    ;;
+	  *)
+	    archive_cmds_CXX='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    archive_expsym_cmds_CXX='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    ;;
+	esac
+      ;;
+
+      tandem*)
+        case $cc_basename in
+          NCC*)
+	    # NonStop-UX NCC 3.20
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+          *)
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+        esac
+        ;;
+
+      vxworks*)
+        # FIXME: insert proper C++ library support
+        ld_shlibs_CXX=no
+        ;;
+
+      *)
+        # FIXME: insert proper C++ library support
+        ld_shlibs_CXX=no
+        ;;
+    esac
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5
+$as_echo "$ld_shlibs_CXX" >&6; }
+    test no = "$ld_shlibs_CXX" && can_build_shared=no
+
+    GCC_CXX=$GXX
+    LD_CXX=$LD
+
+    ## CAVEAT EMPTOR:
+    ## There is no encapsulation within the following macros, do not change
+    ## the running order or otherwise move them around unless you know exactly
+    ## what you are doing...
+    # Dependencies to place before and after the object being linked:
+predep_objects_CXX=
+postdep_objects_CXX=
+predeps_CXX=
+postdeps_CXX=
+compiler_lib_search_path_CXX=
+
+cat > conftest.$ac_ext <<_LT_EOF
+class Foo
+{
+public:
+  Foo (void) { a = 0; }
+private:
+  int a;
+};
+_LT_EOF
+
+
+_lt_libdeps_save_CFLAGS=$CFLAGS
+case "$CC $CFLAGS " in #(
+*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;;
+*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;;
+*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;;
+esac
+
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  # Parse the compiler output and extract the necessary
+  # objects, libraries and library flags.
+
+  # Sentinel used to keep track of whether or not we are before
+  # the conftest object file.
+  pre_test_object_deps_done=no
+
+  for p in `eval "$output_verbose_link_cmd"`; do
+    case $prev$p in
+
+    -L* | -R* | -l*)
+       # Some compilers place space between "-{L,R}" and the path.
+       # Remove the space.
+       if test x-L = "$p" ||
+          test x-R = "$p"; then
+	 prev=$p
+	 continue
+       fi
+
+       # Expand the sysroot to ease extracting the directories later.
+       if test -z "$prev"; then
+         case $p in
+         -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;;
+         -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;;
+         -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;;
+         esac
+       fi
+       case $p in
+       =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;;
+       esac
+       if test no = "$pre_test_object_deps_done"; then
+	 case $prev in
+	 -L | -R)
+	   # Internal compiler library paths should come after those
+	   # provided the user.  The postdeps already come after the
+	   # user supplied libs so there is no need to process them.
+	   if test -z "$compiler_lib_search_path_CXX"; then
+	     compiler_lib_search_path_CXX=$prev$p
+	   else
+	     compiler_lib_search_path_CXX="${compiler_lib_search_path_CXX} $prev$p"
+	   fi
+	   ;;
+	 # The "-l" case would never come before the object being
+	 # linked, so don't bother handling this case.
+	 esac
+       else
+	 if test -z "$postdeps_CXX"; then
+	   postdeps_CXX=$prev$p
+	 else
+	   postdeps_CXX="${postdeps_CXX} $prev$p"
+	 fi
+       fi
+       prev=
+       ;;
+
+    *.lto.$objext) ;; # Ignore GCC LTO objects
+    *.$objext)
+       # This assumes that the test object file only shows up
+       # once in the compiler output.
+       if test "$p" = "conftest.$objext"; then
+	 pre_test_object_deps_done=yes
+	 continue
+       fi
+
+       if test no = "$pre_test_object_deps_done"; then
+	 if test -z "$predep_objects_CXX"; then
+	   predep_objects_CXX=$p
+	 else
+	   predep_objects_CXX="$predep_objects_CXX $p"
+	 fi
+       else
+	 if test -z "$postdep_objects_CXX"; then
+	   postdep_objects_CXX=$p
+	 else
+	   postdep_objects_CXX="$postdep_objects_CXX $p"
+	 fi
+       fi
+       ;;
+
+    *) ;; # Ignore the rest.
+
+    esac
+  done
+
+  # Clean up.
+  rm -f a.out a.exe
+else
+  echo "libtool.m4: error: problem compiling CXX test program"
+fi
+
+$RM -f confest.$objext
+CFLAGS=$_lt_libdeps_save_CFLAGS
+
+# PORTME: override above test on systems where it is broken
+case $host_os in
+interix[3-9]*)
+  # Interix 3.5 installs completely hosed .la files for C++, so rather than
+  # hack all around it, let's just trust "g++" to DTRT.
+  predep_objects_CXX=
+  postdep_objects_CXX=
+  postdeps_CXX=
+  ;;
+esac
+
+
+case " $postdeps_CXX " in
+*" -lc "*) archive_cmds_need_lc_CXX=no ;;
+esac
+ compiler_lib_search_dirs_CXX=
+if test -n "${compiler_lib_search_path_CXX}"; then
+ compiler_lib_search_dirs_CXX=`echo " ${compiler_lib_search_path_CXX}" | $SED -e 's! -L! !g' -e 's!^ !!'`
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    lt_prog_compiler_wl_CXX=
+lt_prog_compiler_pic_CXX=
+lt_prog_compiler_static_CXX=
+
+
+  # C++ specific cases for pic, static, wl, etc.
+  if test yes = "$GXX"; then
+    lt_prog_compiler_wl_CXX='-Wl,'
+    lt_prog_compiler_static_CXX='-static'
+
+    case $host_os in
+    aix*)
+      # All AIX code is PIC.
+      if test ia64 = "$host_cpu"; then
+	# AIX 5 now supports IA64 processor
+	lt_prog_compiler_static_CXX='-Bstatic'
+      fi
+      lt_prog_compiler_pic_CXX='-fPIC'
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            lt_prog_compiler_pic_CXX='-fPIC'
+        ;;
+      m68k)
+            # FIXME: we need at least 68020 code to build shared libraries, but
+            # adding the '-m68020' flag to GCC prevents building anything better,
+            # like '-m68040'.
+            lt_prog_compiler_pic_CXX='-m68020 -resident32 -malways-restore-a4'
+        ;;
+      esac
+      ;;
+
+    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+    mingw* | cygwin* | os2* | pw32* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      # Although the cygwin gcc ignores -fPIC, still need this for old-style
+      # (--disable-auto-import) libraries
+      lt_prog_compiler_pic_CXX='-DDLL_EXPORT'
+      case $host_os in
+      os2*)
+	lt_prog_compiler_static_CXX='$wl-static'
+	;;
+      esac
+      ;;
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      lt_prog_compiler_pic_CXX='-fno-common'
+      ;;
+    *djgpp*)
+      # DJGPP does not support shared libraries at all
+      lt_prog_compiler_pic_CXX=
+      ;;
+    haiku*)
+      # PIC is the default for Haiku.
+      # The "-static" flag exists, but is broken.
+      lt_prog_compiler_static_CXX=
+      ;;
+    interix[3-9]*)
+      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+      # Instead, we relocate shared libraries at runtime.
+      ;;
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	lt_prog_compiler_pic_CXX=-Kconform_pic
+      fi
+      ;;
+    hpux*)
+      # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+      # PA HP-UX.  On IA64 HP-UX, PIC is the default but the pic flag
+      # sets the default TLS model and affects inlining.
+      case $host_cpu in
+      hppa*64*)
+	;;
+      *)
+	lt_prog_compiler_pic_CXX='-fPIC'
+	;;
+      esac
+      ;;
+    *qnx* | *nto*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      lt_prog_compiler_pic_CXX='-fPIC -shared'
+      ;;
+    *)
+      lt_prog_compiler_pic_CXX='-fPIC'
+      ;;
+    esac
+  else
+    case $host_os in
+      aix[4-9]*)
+	# All AIX code is PIC.
+	if test ia64 = "$host_cpu"; then
+	  # AIX 5 now supports IA64 processor
+	  lt_prog_compiler_static_CXX='-Bstatic'
+	else
+	  lt_prog_compiler_static_CXX='-bnso -bI:/lib/syscalls.exp'
+	fi
+	;;
+      chorus*)
+	case $cc_basename in
+	cxch68*)
+	  # Green Hills C++ Compiler
+	  # _LT_TAGVAR(lt_prog_compiler_static, CXX)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
+	  ;;
+	esac
+	;;
+      mingw* | cygwin* | os2* | pw32* | cegcc*)
+	# This hack is so that the source file can tell whether it is being
+	# built for inclusion in a dll (and should export symbols for example).
+	lt_prog_compiler_pic_CXX='-DDLL_EXPORT'
+	;;
+      dgux*)
+	case $cc_basename in
+	  ec++*)
+	    lt_prog_compiler_pic_CXX='-KPIC'
+	    ;;
+	  ghcx*)
+	    # Green Hills C++ Compiler
+	    lt_prog_compiler_pic_CXX='-pic'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      freebsd* | dragonfly*)
+	# FreeBSD uses GNU C++
+	;;
+      hpux9* | hpux10* | hpux11*)
+	case $cc_basename in
+	  CC*)
+	    lt_prog_compiler_wl_CXX='-Wl,'
+	    lt_prog_compiler_static_CXX='$wl-a ${wl}archive'
+	    if test ia64 != "$host_cpu"; then
+	      lt_prog_compiler_pic_CXX='+Z'
+	    fi
+	    ;;
+	  aCC*)
+	    lt_prog_compiler_wl_CXX='-Wl,'
+	    lt_prog_compiler_static_CXX='$wl-a ${wl}archive'
+	    case $host_cpu in
+	    hppa*64*|ia64*)
+	      # +Z the default
+	      ;;
+	    *)
+	      lt_prog_compiler_pic_CXX='+Z'
+	      ;;
+	    esac
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      interix*)
+	# This is c89, which is MS Visual C++ (no shared libs)
+	# Anyone wants to do a port?
+	;;
+      irix5* | irix6* | nonstopux*)
+	case $cc_basename in
+	  CC*)
+	    lt_prog_compiler_wl_CXX='-Wl,'
+	    lt_prog_compiler_static_CXX='-non_shared'
+	    # CC pic flag -KPIC is the default.
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+	case $cc_basename in
+	  KCC*)
+	    # KAI C++ Compiler
+	    lt_prog_compiler_wl_CXX='--backend -Wl,'
+	    lt_prog_compiler_pic_CXX='-fPIC'
+	    ;;
+	  ecpc* )
+	    # old Intel C++ for x86_64, which still supported -KPIC.
+	    lt_prog_compiler_wl_CXX='-Wl,'
+	    lt_prog_compiler_pic_CXX='-KPIC'
+	    lt_prog_compiler_static_CXX='-static'
+	    ;;
+	  icpc* )
+	    # Intel C++, used to be incompatible with GCC.
+	    # ICC 10 doesn't accept -KPIC any more.
+	    lt_prog_compiler_wl_CXX='-Wl,'
+	    lt_prog_compiler_pic_CXX='-fPIC'
+	    lt_prog_compiler_static_CXX='-static'
+	    ;;
+	  pgCC* | pgcpp*)
+	    # Portland Group C++ compiler
+	    lt_prog_compiler_wl_CXX='-Wl,'
+	    lt_prog_compiler_pic_CXX='-fpic'
+	    lt_prog_compiler_static_CXX='-Bstatic'
+	    ;;
+	  cxx*)
+	    # Compaq C++
+	    # Make sure the PIC flag is empty.  It appears that all Alpha
+	    # Linux and Compaq Tru64 Unix objects are PIC.
+	    lt_prog_compiler_pic_CXX=
+	    lt_prog_compiler_static_CXX='-non_shared'
+	    ;;
+	  xlc* | xlC* | bgxl[cC]* | mpixl[cC]*)
+	    # IBM XL 8.0, 9.0 on PPC and BlueGene
+	    lt_prog_compiler_wl_CXX='-Wl,'
+	    lt_prog_compiler_pic_CXX='-qpic'
+	    lt_prog_compiler_static_CXX='-qstaticlink'
+	    ;;
+	  *)
+	    case `$CC -V 2>&1 | sed 5q` in
+	    *Sun\ C*)
+	      # Sun C++ 5.9
+	      lt_prog_compiler_pic_CXX='-KPIC'
+	      lt_prog_compiler_static_CXX='-Bstatic'
+	      lt_prog_compiler_wl_CXX='-Qoption ld '
+	      ;;
+	    esac
+	    ;;
+	esac
+	;;
+      lynxos*)
+	;;
+      m88k*)
+	;;
+      mvs*)
+	case $cc_basename in
+	  cxx*)
+	    lt_prog_compiler_pic_CXX='-W c,exportall'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      netbsd*)
+	;;
+      *qnx* | *nto*)
+        # QNX uses GNU C++, but need to define -shared option too, otherwise
+        # it will coredump.
+        lt_prog_compiler_pic_CXX='-fPIC -shared'
+        ;;
+      osf3* | osf4* | osf5*)
+	case $cc_basename in
+	  KCC*)
+	    lt_prog_compiler_wl_CXX='--backend -Wl,'
+	    ;;
+	  RCC*)
+	    # Rational C++ 2.4.1
+	    lt_prog_compiler_pic_CXX='-pic'
+	    ;;
+	  cxx*)
+	    # Digital/Compaq C++
+	    lt_prog_compiler_wl_CXX='-Wl,'
+	    # Make sure the PIC flag is empty.  It appears that all Alpha
+	    # Linux and Compaq Tru64 Unix objects are PIC.
+	    lt_prog_compiler_pic_CXX=
+	    lt_prog_compiler_static_CXX='-non_shared'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      psos*)
+	;;
+      solaris*)
+	case $cc_basename in
+	  CC* | sunCC*)
+	    # Sun C++ 4.2, 5.x and Centerline C++
+	    lt_prog_compiler_pic_CXX='-KPIC'
+	    lt_prog_compiler_static_CXX='-Bstatic'
+	    lt_prog_compiler_wl_CXX='-Qoption ld '
+	    ;;
+	  gcx*)
+	    # Green Hills C++ Compiler
+	    lt_prog_compiler_pic_CXX='-PIC'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      sunos4*)
+	case $cc_basename in
+	  CC*)
+	    # Sun C++ 4.x
+	    lt_prog_compiler_pic_CXX='-pic'
+	    lt_prog_compiler_static_CXX='-Bstatic'
+	    ;;
+	  lcc*)
+	    # Lucid
+	    lt_prog_compiler_pic_CXX='-pic'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+	case $cc_basename in
+	  CC*)
+	    lt_prog_compiler_wl_CXX='-Wl,'
+	    lt_prog_compiler_pic_CXX='-KPIC'
+	    lt_prog_compiler_static_CXX='-Bstatic'
+	    ;;
+	esac
+	;;
+      tandem*)
+	case $cc_basename in
+	  NCC*)
+	    # NonStop-UX NCC 3.20
+	    lt_prog_compiler_pic_CXX='-KPIC'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      vxworks*)
+	;;
+      *)
+	lt_prog_compiler_can_build_shared_CXX=no
+	;;
+    esac
+  fi
+
+case $host_os in
+  # For platforms that do not support PIC, -DPIC is meaningless:
+  *djgpp*)
+    lt_prog_compiler_pic_CXX=
+    ;;
+  *)
+    lt_prog_compiler_pic_CXX="$lt_prog_compiler_pic_CXX -DPIC"
+    ;;
+esac
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5
+$as_echo_n "checking for $compiler option to produce PIC... " >&6; }
+if ${lt_cv_prog_compiler_pic_CXX+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_pic_CXX=$lt_prog_compiler_pic_CXX
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_CXX" >&5
+$as_echo "$lt_cv_prog_compiler_pic_CXX" >&6; }
+lt_prog_compiler_pic_CXX=$lt_cv_prog_compiler_pic_CXX
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$lt_prog_compiler_pic_CXX"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works" >&5
+$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works... " >&6; }
+if ${lt_cv_prog_compiler_pic_works_CXX+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_pic_works_CXX=no
+   ac_outfile=conftest.$ac_objext
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+   lt_compiler_flag="$lt_prog_compiler_pic_CXX -DPIC"  ## exclude from sc_useless_quotes_in_assignment
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   # The option is referenced via a variable to avoid confusing sed.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s "$ac_outfile"; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings other than the usual output.
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_pic_works_CXX=yes
+     fi
+   fi
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works_CXX" >&5
+$as_echo "$lt_cv_prog_compiler_pic_works_CXX" >&6; }
+
+if test yes = "$lt_cv_prog_compiler_pic_works_CXX"; then
+    case $lt_prog_compiler_pic_CXX in
+     "" | " "*) ;;
+     *) lt_prog_compiler_pic_CXX=" $lt_prog_compiler_pic_CXX" ;;
+     esac
+else
+    lt_prog_compiler_pic_CXX=
+     lt_prog_compiler_can_build_shared_CXX=no
+fi
+
+fi
+
+
+
+
+
+#
+# Check to make sure the static flag actually works.
+#
+wl=$lt_prog_compiler_wl_CXX eval lt_tmp_static_flag=\"$lt_prog_compiler_static_CXX\"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5
+$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; }
+if ${lt_cv_prog_compiler_static_works_CXX+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_static_works_CXX=no
+   save_LDFLAGS=$LDFLAGS
+   LDFLAGS="$LDFLAGS $lt_tmp_static_flag"
+   echo "$lt_simple_link_test_code" > conftest.$ac_ext
+   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+     # The linker can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test -s conftest.err; then
+       # Append any errors to the config.log.
+       cat conftest.err 1>&5
+       $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+       if diff conftest.exp conftest.er2 >/dev/null; then
+         lt_cv_prog_compiler_static_works_CXX=yes
+       fi
+     else
+       lt_cv_prog_compiler_static_works_CXX=yes
+     fi
+   fi
+   $RM -r conftest*
+   LDFLAGS=$save_LDFLAGS
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works_CXX" >&5
+$as_echo "$lt_cv_prog_compiler_static_works_CXX" >&6; }
+
+if test yes = "$lt_cv_prog_compiler_static_works_CXX"; then
+    :
+else
+    lt_prog_compiler_static_CXX=
+fi
+
+
+
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if ${lt_cv_prog_compiler_c_o_CXX+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_c_o_CXX=no
+   $RM -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_c_o_CXX=yes
+     fi
+   fi
+   chmod u+w . 2>&5
+   $RM conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+   $RM out/* && rmdir out
+   cd ..
+   $RM -r conftest
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5
+$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; }
+
+
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if ${lt_cv_prog_compiler_c_o_CXX+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_c_o_CXX=no
+   $RM -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_c_o_CXX=yes
+     fi
+   fi
+   chmod u+w . 2>&5
+   $RM conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+   $RM out/* && rmdir out
+   cd ..
+   $RM -r conftest
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5
+$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; }
+
+
+
+
+hard_links=nottested
+if test no = "$lt_cv_prog_compiler_c_o_CXX" && test no != "$need_locks"; then
+  # do not overwrite the value of need_locks provided by the user
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5
+$as_echo_n "checking if we can lock with hard links... " >&6; }
+  hard_links=yes
+  $RM conftest*
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  touch conftest.a
+  ln conftest.a conftest.b 2>&5 || hard_links=no
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5
+$as_echo "$hard_links" >&6; }
+  if test no = "$hard_links"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&5
+$as_echo "$as_me: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&2;}
+    need_locks=warn
+  fi
+else
+  need_locks=no
+fi
+
+
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
+
+  export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  exclude_expsyms_CXX='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'
+  case $host_os in
+  aix[4-9]*)
+    # If we're using GNU nm, then we don't want the "-C" option.
+    # -C means demangle to GNU nm, but means don't demangle to AIX nm.
+    # Without the "-l" option, or with the "-B" option, AIX nm treats
+    # weak defined symbols like other global defined symbols, whereas
+    # GNU nm marks them as "W".
+    # While the 'weak' keyword is ignored in the Export File, we need
+    # it in the Import File for the 'aix-soname' feature, so we have
+    # to replace the "-B" option with "-P" for AIX nm.
+    if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+      export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols'
+    else
+      export_symbols_cmds_CXX='`func_echo_all $NM | $SED -e '\''s/B\([^B]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && (substr(\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
+    fi
+    ;;
+  pw32*)
+    export_symbols_cmds_CXX=$ltdll_cmds
+    ;;
+  cygwin* | mingw* | cegcc*)
+    case $cc_basename in
+    cl*)
+      exclude_expsyms_CXX='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
+      ;;
+    *)
+      export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols'
+      exclude_expsyms_CXX='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'
+      ;;
+    esac
+    ;;
+  *)
+    export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+    ;;
+  esac
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5
+$as_echo "$ld_shlibs_CXX" >&6; }
+test no = "$ld_shlibs_CXX" && can_build_shared=no
+
+with_gnu_ld_CXX=$with_gnu_ld
+
+
+
+
+
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$archive_cmds_need_lc_CXX" in
+x|xyes)
+  # Assume -lc should be added
+  archive_cmds_need_lc_CXX=yes
+
+  if test yes,yes = "$GCC,$enable_shared"; then
+    case $archive_cmds_CXX in
+    *'~'*)
+      # FIXME: we may have to deal with multi-command sequences.
+      ;;
+    '$CC '*)
+      # Test whether the compiler implicitly links with -lc since on some
+      # systems, -lgcc has to come before -lc. If gcc already passes -lc
+      # to ld, don't add -lc before -lgcc.
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5
+$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; }
+if ${lt_cv_archive_cmds_need_lc_CXX+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  $RM conftest*
+	echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+	if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } 2>conftest.err; then
+	  soname=conftest
+	  lib=conftest
+	  libobjs=conftest.$ac_objext
+	  deplibs=
+	  wl=$lt_prog_compiler_wl_CXX
+	  pic_flag=$lt_prog_compiler_pic_CXX
+	  compiler_flags=-v
+	  linker_flags=-v
+	  verstring=
+	  output_objdir=.
+	  libname=conftest
+	  lt_save_allow_undefined_flag=$allow_undefined_flag_CXX
+	  allow_undefined_flag_CXX=
+	  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5
+  (eval $archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+	  then
+	    lt_cv_archive_cmds_need_lc_CXX=no
+	  else
+	    lt_cv_archive_cmds_need_lc_CXX=yes
+	  fi
+	  allow_undefined_flag_CXX=$lt_save_allow_undefined_flag
+	else
+	  cat conftest.err 1>&5
+	fi
+	$RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc_CXX" >&5
+$as_echo "$lt_cv_archive_cmds_need_lc_CXX" >&6; }
+      archive_cmds_need_lc_CXX=$lt_cv_archive_cmds_need_lc_CXX
+      ;;
+    esac
+  fi
+  ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5
+$as_echo_n "checking dynamic linker characteristics... " >&6; }
+
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=.so
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+
+
+case $host_os in
+aix3*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='$libname$release$shared_ext$versuffix $libname.a'
+  shlibpath_var=LIBPATH
+
+  # AIX 3 has no versioning support, so we append a major version to the name.
+  soname_spec='$libname$release$shared_ext$major'
+  ;;
+
+aix[4-9]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  hardcode_into_libs=yes
+  if test ia64 = "$host_cpu"; then
+    # AIX 5 supports IA64
+    library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext'
+    shlibpath_var=LD_LIBRARY_PATH
+  else
+    # With GCC up to 2.95.x, collect2 would create an import file
+    # for dependence libraries.  The import file would start with
+    # the line '#! .'.  This would cause the generated library to
+    # depend on '.', always an invalid library.  This was fixed in
+    # development snapshots of GCC prior to 3.0.
+    case $host_os in
+      aix4 | aix4.[01] | aix4.[01].*)
+      if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+	   echo ' yes '
+	   echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then
+	:
+      else
+	can_build_shared=no
+      fi
+      ;;
+    esac
+    # Using Import Files as archive members, it is possible to support
+    # filename-based versioning of shared library archives on AIX. While
+    # this would work for both with and without runtime linking, it will
+    # prevent static linking of such archives. So we do filename-based
+    # shared library versioning with .so extension only, which is used
+    # when both runtime linking and shared linking is enabled.
+    # Unfortunately, runtime linking may impact performance, so we do
+    # not want this to be the default eventually. Also, we use the
+    # versioned .so libs for executables only if there is the -brtl
+    # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only.
+    # To allow for filename-based versioning support, we need to create
+    # libNAME.so.V as an archive file, containing:
+    # *) an Import File, referring to the versioned filename of the
+    #    archive as well as the shared archive member, telling the
+    #    bitwidth (32 or 64) of that shared object, and providing the
+    #    list of exported symbols of that shared object, eventually
+    #    decorated with the 'weak' keyword
+    # *) the shared object with the F_LOADONLY flag set, to really avoid
+    #    it being seen by the linker.
+    # At run time we better use the real file rather than another symlink,
+    # but for link time we create the symlink libNAME.so -> libNAME.so.V
+
+    case $with_aix_soname,$aix_use_runtimelinking in
+    # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct
+    # soname into executable. Probably we can add versioning support to
+    # collect2, so additional links can be useful in future.
+    aix,yes) # traditional libtool
+      dynamic_linker='AIX unversionable lib.so'
+      # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+      # instead of lib<name>.a to let people know that these are not
+      # typical AIX shared libraries.
+      library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+      ;;
+    aix,no) # traditional AIX only
+      dynamic_linker='AIX lib.a(lib.so.V)'
+      # We preserve .a as extension for shared libraries through AIX4.2
+      # and later when we are not doing run time linking.
+      library_names_spec='$libname$release.a $libname.a'
+      soname_spec='$libname$release$shared_ext$major'
+      ;;
+    svr4,*) # full svr4 only
+      dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o)"
+      library_names_spec='$libname$release$shared_ext$major $libname$shared_ext'
+      # We do not specify a path in Import Files, so LIBPATH fires.
+      shlibpath_overrides_runpath=yes
+      ;;
+    *,yes) # both, prefer svr4
+      dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o), lib.a(lib.so.V)"
+      library_names_spec='$libname$release$shared_ext$major $libname$shared_ext'
+      # unpreferred sharedlib libNAME.a needs extra handling
+      postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"'
+      postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"'
+      # We do not specify a path in Import Files, so LIBPATH fires.
+      shlibpath_overrides_runpath=yes
+      ;;
+    *,no) # both, prefer aix
+      dynamic_linker="AIX lib.a(lib.so.V), lib.so.V($shared_archive_member_spec.o)"
+      library_names_spec='$libname$release.a $libname.a'
+      soname_spec='$libname$release$shared_ext$major'
+      # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling
+      postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)'
+      postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"'
+      ;;
+    esac
+    shlibpath_var=LIBPATH
+  fi
+  ;;
+
+amigaos*)
+  case $host_cpu in
+  powerpc)
+    # Since July 2007 AmigaOS4 officially supports .so libraries.
+    # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+    ;;
+  m68k)
+    library_names_spec='$libname.ixlibrary $libname.a'
+    # Create ${libname}_ixlibrary.a entries in /sys/libs.
+    finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+    ;;
+  esac
+  ;;
+
+beos*)
+  library_names_spec='$libname$shared_ext'
+  dynamic_linker="$host_os ld.so"
+  shlibpath_var=LIBRARY_PATH
+  ;;
+
+bsdi[45]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+  sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+  # the default ld.so.conf also contains /usr/contrib/lib and
+  # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+  # libtool to hard-code these into programs
+  ;;
+
+cygwin* | mingw* | pw32* | cegcc*)
+  version_type=windows
+  shrext_cmds=.dll
+  need_version=no
+  need_lib_prefix=no
+
+  case $GCC,$cc_basename in
+  yes,*)
+    # gcc
+    library_names_spec='$libname.dll.a'
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \$file`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname~
+      chmod a+x \$dldir/$dlname~
+      if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+        eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+      fi'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $RM \$dlpath'
+    shlibpath_overrides_runpath=yes
+
+    case $host_os in
+    cygwin*)
+      # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+      soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
+
+      ;;
+    mingw* | cegcc*)
+      # MinGW DLLs use traditional 'lib' prefix
+      soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
+      ;;
+    pw32*)
+      # pw32 DLLs use 'pw' prefix rather than 'lib'
+      library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
+      ;;
+    esac
+    dynamic_linker='Win32 ld.exe'
+    ;;
+
+  *,cl*)
+    # Native MSVC
+    libname_spec='$name'
+    soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
+    library_names_spec='$libname.dll.lib'
+
+    case $build_os in
+    mingw*)
+      sys_lib_search_path_spec=
+      lt_save_ifs=$IFS
+      IFS=';'
+      for lt_path in $LIB
+      do
+        IFS=$lt_save_ifs
+        # Let DOS variable expansion print the short 8.3 style file name.
+        lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"`
+        sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path"
+      done
+      IFS=$lt_save_ifs
+      # Convert to MSYS style.
+      sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'`
+      ;;
+    cygwin*)
+      # Convert to unix form, then to dos form, then back to unix form
+      # but this time dos style (no spaces!) so that the unix form looks
+      # like /cygdrive/c/PROGRA~1:/cygdr...
+      sys_lib_search_path_spec=`cygpath --path --unix "$LIB"`
+      sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null`
+      sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+      ;;
+    *)
+      sys_lib_search_path_spec=$LIB
+      if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then
+        # It is most probably a Windows format PATH.
+        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+      else
+        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+      fi
+      # FIXME: find the short name or the path components, as spaces are
+      # common. (e.g. "Program Files" -> "PROGRA~1")
+      ;;
+    esac
+
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \$file`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $RM \$dlpath'
+    shlibpath_overrides_runpath=yes
+    dynamic_linker='Win32 link.exe'
+    ;;
+
+  *)
+    # Assume MSVC wrapper
+    library_names_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext $libname.lib'
+    dynamic_linker='Win32 ld.exe'
+    ;;
+  esac
+  # FIXME: first we should search . and the directory the executable is in
+  shlibpath_var=PATH
+  ;;
+
+darwin* | rhapsody*)
+  dynamic_linker="$host_os dyld"
+  version_type=darwin
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$major$shared_ext $libname$shared_ext'
+  soname_spec='$libname$release$major$shared_ext'
+  shlibpath_overrides_runpath=yes
+  shlibpath_var=DYLD_LIBRARY_PATH
+  shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+
+  sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+  ;;
+
+dgux*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+freebsd* | dragonfly*)
+  # DragonFly does not have aout.  When/if they implement a new
+  # versioning mechanism, adjust this.
+  if test -x /usr/bin/objformat; then
+    objformat=`/usr/bin/objformat`
+  else
+    case $host_os in
+    freebsd[23].*) objformat=aout ;;
+    *) objformat=elf ;;
+    esac
+  fi
+  version_type=freebsd-$objformat
+  case $version_type in
+    freebsd-elf*)
+      library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+      soname_spec='$libname$release$shared_ext$major'
+      need_version=no
+      need_lib_prefix=no
+      ;;
+    freebsd-*)
+      library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+      need_version=yes
+      ;;
+  esac
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_os in
+  freebsd2.*)
+    shlibpath_overrides_runpath=yes
+    ;;
+  freebsd3.[01]* | freebsdelf3.[01]*)
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  freebsd3.[2-9]* | freebsdelf3.[2-9]* | \
+  freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1)
+    shlibpath_overrides_runpath=no
+    hardcode_into_libs=yes
+    ;;
+  *) # from 4.6 on, and DragonFly
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  esac
+  ;;
+
+haiku*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  dynamic_linker="$host_os runtime_loader"
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  shlibpath_var=LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
+  hardcode_into_libs=yes
+  ;;
+
+hpux9* | hpux10* | hpux11*)
+  # Give a soname corresponding to the major version so that dld.sl refuses to
+  # link against other versions.
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  case $host_cpu in
+  ia64*)
+    shrext_cmds='.so'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.so"
+    shlibpath_var=LD_LIBRARY_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+    soname_spec='$libname$release$shared_ext$major'
+    if test 32 = "$HPUX_IA64_MODE"; then
+      sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+      sys_lib_dlsearch_path_spec=/usr/lib/hpux32
+    else
+      sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+      sys_lib_dlsearch_path_spec=/usr/lib/hpux64
+    fi
+    ;;
+  hppa*64*)
+    shrext_cmds='.sl'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+    soname_spec='$libname$release$shared_ext$major'
+    sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+  *)
+    shrext_cmds='.sl'
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=SHLIB_PATH
+    shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+    soname_spec='$libname$release$shared_ext$major'
+    ;;
+  esac
+  # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
+  postinstall_cmds='chmod 555 $lib'
+  # or fails outright, so override atomically:
+  install_override_mode=555
+  ;;
+
+interix[3-9]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $host_os in
+    nonstopux*) version_type=nonstopux ;;
+    *)
+	if test yes = "$lt_cv_prog_gnu_ld"; then
+		version_type=linux # correct to gnu/linux during the next big refactor
+	else
+		version_type=irix
+	fi ;;
+  esac
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='$libname$release$shared_ext$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext'
+  case $host_os in
+  irix5* | nonstopux*)
+    libsuff= shlibsuff=
+    ;;
+  *)
+    case $LD in # libtool.m4 will add one of these switches to LD
+    *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+      libsuff= shlibsuff= libmagic=32-bit;;
+    *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+      libsuff=32 shlibsuff=N32 libmagic=N32;;
+    *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+      libsuff=64 shlibsuff=64 libmagic=64-bit;;
+    *) libsuff= shlibsuff= libmagic=never-match;;
+    esac
+    ;;
+  esac
+  shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+  shlibpath_overrides_runpath=no
+  sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff"
+  sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff"
+  hardcode_into_libs=yes
+  ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+  dynamic_linker=no
+  ;;
+
+linux*android*)
+  version_type=none # Android doesn't support versioned libraries.
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext'
+  soname_spec='$libname$release$shared_ext'
+  finish_cmds=
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+
+  # This implies no fast_install, which is unacceptable.
+  # Some rework will be needed to allow for fast_install
+  # before this can be enabled.
+  hardcode_into_libs=yes
+
+  dynamic_linker='Android linker'
+  # Don't embed -rpath directories since the linker doesn't support them.
+  hardcode_libdir_flag_spec_CXX='-L$libdir'
+  ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+
+  # Some binutils ld are patched to set DT_RUNPATH
+  if ${lt_cv_shlibpath_overrides_runpath+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_shlibpath_overrides_runpath=no
+    save_LDFLAGS=$LDFLAGS
+    save_libdir=$libdir
+    eval "libdir=/foo; wl=\"$lt_prog_compiler_wl_CXX\"; \
+	 LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec_CXX\""
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+  if  ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then :
+  lt_cv_shlibpath_overrides_runpath=yes
+fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+    LDFLAGS=$save_LDFLAGS
+    libdir=$save_libdir
+
+fi
+
+  shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
+
+  # This implies no fast_install, which is unacceptable.
+  # Some rework will be needed to allow for fast_install
+  # before this can be enabled.
+  hardcode_into_libs=yes
+
+  # Ideally, we could use ldconfig to report *all* directores which are
+  # searched for libraries, however this is still not possible.  Aside from not
+  # being certain /sbin/ldconfig is available, command
+  # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64,
+  # even though it is searched at run-time.  Try to do the best guess by
+  # appending ld.so.conf contents (and includes) to the search path.
+  if test -f /etc/ld.so.conf; then
+    lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[	 ]*hwcap[	 ]/d;s/[:,	]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
+    sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+  fi
+
+  # We used to test for /lib/ld.so.1 and disable shared libraries on
+  # powerpc, because MkLinux only supported shared libraries with the
+  # GNU dynamic linker.  Since this was broken with cross compilers,
+  # most powerpc-linux boxes support dynamic linking these days and
+  # people can always --disable-shared, the test was removed, and we
+  # assume the GNU/Linux dynamic linker is in use.
+  dynamic_linker='GNU/Linux ld.so'
+  ;;
+
+netbsd*)
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+    finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+    dynamic_linker='NetBSD (a.out) ld.so'
+  else
+    library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+    soname_spec='$libname$release$shared_ext$major'
+    dynamic_linker='NetBSD ld.elf_so'
+  fi
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  ;;
+
+newsos6)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+*nto* | *qnx*)
+  version_type=qnx
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='ldqnx.so'
+  ;;
+
+openbsd* | bitrig*)
+  version_type=sunos
+  sys_lib_dlsearch_path_spec=/usr/lib
+  need_lib_prefix=no
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
+    need_version=no
+  else
+    need_version=yes
+  fi
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+os2*)
+  libname_spec='$name'
+  version_type=windows
+  shrext_cmds=.dll
+  need_version=no
+  need_lib_prefix=no
+  # OS/2 can only load a DLL with a base name of 8 characters or less.
+  soname_spec='`test -n "$os2dllname" && libname="$os2dllname";
+    v=$($ECHO $release$versuffix | tr -d .-);
+    n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _);
+    $ECHO $n$v`$shared_ext'
+  library_names_spec='${libname}_dll.$libext'
+  dynamic_linker='OS/2 ld.exe'
+  shlibpath_var=BEGINLIBPATH
+  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+  sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+  postinstall_cmds='base_file=`basename \$file`~
+    dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~
+    dldir=$destdir/`dirname \$dlpath`~
+    test -d \$dldir || mkdir -p \$dldir~
+    $install_prog $dir/$dlname \$dldir/$dlname~
+    chmod a+x \$dldir/$dlname~
+    if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+      eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+    fi'
+  postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~
+    dlpath=$dir/\$dldll~
+    $RM \$dlpath'
+  ;;
+
+osf3* | osf4* | osf5*)
+  version_type=osf
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='$libname$release$shared_ext$major'
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+  sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+  ;;
+
+rdos*)
+  dynamic_linker=no
+  ;;
+
+solaris*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  # ldd complains unless libraries are executable
+  postinstall_cmds='chmod +x $lib'
+  ;;
+
+sunos4*)
+  version_type=sunos
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+  finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  if test yes = "$with_gnu_ld"; then
+    need_lib_prefix=no
+  fi
+  need_version=yes
+  ;;
+
+sysv4 | sysv4.3*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_vendor in
+    sni)
+      shlibpath_overrides_runpath=no
+      need_lib_prefix=no
+      runpath_var=LD_RUN_PATH
+      ;;
+    siemens)
+      need_lib_prefix=no
+      ;;
+    motorola)
+      need_lib_prefix=no
+      need_version=no
+      shlibpath_overrides_runpath=no
+      sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+      ;;
+  esac
+  ;;
+
+sysv4*MP*)
+  if test -d /usr/nec; then
+    version_type=linux # correct to gnu/linux during the next big refactor
+    library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext'
+    soname_spec='$libname$shared_ext.$major'
+    shlibpath_var=LD_LIBRARY_PATH
+  fi
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  version_type=sco
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  if test yes = "$with_gnu_ld"; then
+    sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+  else
+    sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+    case $host_os in
+      sco3.2v5*)
+        sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+	;;
+    esac
+  fi
+  sys_lib_dlsearch_path_spec='/usr/lib'
+  ;;
+
+tpf*)
+  # TPF is a cross-target only.  Preferred cross-host = GNU/Linux.
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+uts4*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+  soname_spec='$libname$release$shared_ext$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+*)
+  dynamic_linker=no
+  ;;
+esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5
+$as_echo "$dynamic_linker" >&6; }
+test no = "$dynamic_linker" && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test yes = "$GCC"; then
+  variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then
+  sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec
+fi
+
+if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then
+  sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec
+fi
+
+# remember unaugmented sys_lib_dlsearch_path content for libtool script decls...
+configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec
+
+# ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code
+func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH"
+
+# to be used as default LT_SYS_LIBRARY_PATH value in generated libtool
+configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5
+$as_echo_n "checking how to hardcode library paths into programs... " >&6; }
+hardcode_action_CXX=
+if test -n "$hardcode_libdir_flag_spec_CXX" ||
+   test -n "$runpath_var_CXX" ||
+   test yes = "$hardcode_automatic_CXX"; then
+
+  # We can hardcode non-existent directories.
+  if test no != "$hardcode_direct_CXX" &&
+     # If the only mechanism to avoid hardcoding is shlibpath_var, we
+     # have to relink, otherwise we might link with an installed library
+     # when we should be linking with a yet-to-be-installed one
+     ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, CXX)" &&
+     test no != "$hardcode_minus_L_CXX"; then
+    # Linking always hardcodes the temporary library directory.
+    hardcode_action_CXX=relink
+  else
+    # We can link without hardcoding, and we can hardcode nonexisting dirs.
+    hardcode_action_CXX=immediate
+  fi
+else
+  # We cannot hardcode anything, or else we can only hardcode existing
+  # directories.
+  hardcode_action_CXX=unsupported
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action_CXX" >&5
+$as_echo "$hardcode_action_CXX" >&6; }
+
+if test relink = "$hardcode_action_CXX" ||
+   test yes = "$inherit_rpath_CXX"; then
+  # Fast installation is not supported
+  enable_fast_install=no
+elif test yes = "$shlibpath_overrides_runpath" ||
+     test no = "$enable_shared"; then
+  # Fast installation is not necessary
+  enable_fast_install=needless
+fi
+
+
+
+
+
+
+
+  fi # test -n "$compiler"
+
+  CC=$lt_save_CC
+  CFLAGS=$lt_save_CFLAGS
+  LDCXX=$LD
+  LD=$lt_save_LD
+  GCC=$lt_save_GCC
+  with_gnu_ld=$lt_save_with_gnu_ld
+  lt_cv_path_LDCXX=$lt_cv_path_LD
+  lt_cv_path_LD=$lt_save_path_LD
+  lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
+  lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
+fi # test yes != "$_lt_caught_CXX_error"
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+        ac_config_commands="$ac_config_commands libtool"
+
+
+
+
+# Only expand once:
+
+
+
+# Generate an error here if attempting to build both shared and static when
+# $libname.a is in $library_names_spec (as mentioned above), rather than
+# wait for ar or ld to fail.
+#
+if test "$enable_shared" = yes && test "$enable_static" = yes; then
+  case $library_names_spec in
+    *libname.a*)
+      as_fn_error $? "cannot create both shared and static libraries on this system, --disable one of the two" "$LINENO" 5
+      ;;
+  esac
+fi
+
+ if test "$enable_static" = yes; then
+  ENABLE_STATIC_TRUE=
+  ENABLE_STATIC_FALSE='#'
+else
+  ENABLE_STATIC_TRUE='#'
+  ENABLE_STATIC_FALSE=
+fi
+
+
+
+# Many of these library and header checks are for the benefit of
+# supplementary programs.  libgmp doesn't use anything too weird.
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if ${ac_cv_header_stdc+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_header_stdc=yes
+else
+  ac_cv_header_stdc=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "memchr" >/dev/null 2>&1; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "free" >/dev/null 2>&1; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+  if test "$cross_compiling" = yes; then :
+  :
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+		   (('a' <= (c) && (c) <= 'i') \
+		     || ('j' <= (c) && (c) <= 'r') \
+		     || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+  int i;
+  for (i = 0; i < 256; i++)
+    if (XOR (islower (i), ISLOWER (i))
+	|| toupper (i) != TOUPPER (i))
+      return 2;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether time.h and sys/time.h may both be included" >&5
+$as_echo_n "checking whether time.h and sys/time.h may both be included... " >&6; }
+if ${ac_cv_header_time+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+
+int
+main ()
+{
+if ((struct tm *) 0)
+return 0;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_header_time=yes
+else
+  ac_cv_header_time=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_time" >&5
+$as_echo "$ac_cv_header_time" >&6; }
+if test $ac_cv_header_time = yes; then
+
+$as_echo "#define TIME_WITH_SYS_TIME 1" >>confdefs.h
+
+fi
+
+
+# Reasons for testing:
+#   float.h - not in SunOS bundled cc
+#   invent.h - IRIX specific
+#   langinfo.h - X/Open standard only, not in djgpp for instance
+#   locale.h - old systems won't have this
+#   nl_types.h - X/Open standard only, not in djgpp for instance
+#       (usually langinfo.h gives nl_item etc, but not on netbsd 1.4.1)
+#   sys/attributes.h - IRIX specific
+#   sys/iograph.h - IRIX specific
+#   sys/mman.h - not in Cray Unicos
+#   sys/param.h - not in mingw
+#   sys/processor.h - solaris specific, though also present in macos
+#   sys/pstat.h - HPUX specific
+#   sys/resource.h - not in mingw
+#   sys/sysctl.h - not in mingw
+#   sys/sysinfo.h - OSF specific
+#   sys/syssgi.h - IRIX specific
+#   sys/systemcfg.h - AIX specific
+#   sys/time.h - autoconf suggests testing, don't know anywhere without it
+#   sys/times.h - not in mingw
+#   machine/hal_sysinfo.h - OSF specific
+#
+# inttypes.h, stdint.h, unistd.h and sys/types.h are already in the autoconf
+# default tests
+#
+for ac_header in fcntl.h float.h invent.h langinfo.h locale.h nl_types.h sys/attributes.h sys/iograph.h sys/mman.h sys/param.h sys/processor.h sys/pstat.h sys/sysinfo.h sys/syssgi.h sys/systemcfg.h sys/time.h sys/times.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+# On SunOS, sys/resource.h needs sys/time.h (for struct timeval)
+for ac_header in sys/resource.h
+do :
+  ac_fn_c_check_header_compile "$LINENO" "sys/resource.h" "ac_cv_header_sys_resource_h" "#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+"
+if test "x$ac_cv_header_sys_resource_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_SYS_RESOURCE_H 1
+_ACEOF
+
+fi
+
+done
+
+
+# On NetBSD and OpenBSD, sys/sysctl.h needs sys/param.h for various constants
+for ac_header in sys/sysctl.h
+do :
+  ac_fn_c_check_header_compile "$LINENO" "sys/sysctl.h" "ac_cv_header_sys_sysctl_h" "#if HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#endif
+"
+if test "x$ac_cv_header_sys_sysctl_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_SYS_SYSCTL_H 1
+_ACEOF
+
+fi
+
+done
+
+
+# On OSF 4.0, <machine/hal_sysinfo.h> must have <sys/sysinfo.h> for ulong_t
+for ac_header in machine/hal_sysinfo.h
+do :
+  ac_fn_c_check_header_compile "$LINENO" "machine/hal_sysinfo.h" "ac_cv_header_machine_hal_sysinfo_h" "#if HAVE_SYS_SYSINFO_H
+# include <sys/sysinfo.h>
+#endif
+"
+if test "x$ac_cv_header_machine_hal_sysinfo_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_MACHINE_HAL_SYSINFO_H 1
+_ACEOF
+
+fi
+
+done
+
+
+# Reasons for testing:
+#   optarg - not declared in mingw
+#   fgetc, fscanf, ungetc, vfprintf - not declared in SunOS 4
+#   sys_errlist, sys_nerr - not declared in SunOS 4
+#
+# optarg should be in unistd.h and the rest in stdio.h, both of which are
+# in the autoconf default includes.
+#
+# sys_errlist and sys_nerr are supposed to be in <errno.h> on SunOS according
+# to the man page (but aren't), in glibc they're in stdio.h.
+#
+ac_fn_c_check_decl "$LINENO" "fgetc" "ac_cv_have_decl_fgetc" "$ac_includes_default"
+if test "x$ac_cv_have_decl_fgetc" = xyes; then :
+  ac_have_decl=1
+else
+  ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_FGETC $ac_have_decl
+_ACEOF
+ac_fn_c_check_decl "$LINENO" "fscanf" "ac_cv_have_decl_fscanf" "$ac_includes_default"
+if test "x$ac_cv_have_decl_fscanf" = xyes; then :
+  ac_have_decl=1
+else
+  ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_FSCANF $ac_have_decl
+_ACEOF
+ac_fn_c_check_decl "$LINENO" "optarg" "ac_cv_have_decl_optarg" "$ac_includes_default"
+if test "x$ac_cv_have_decl_optarg" = xyes; then :
+  ac_have_decl=1
+else
+  ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_OPTARG $ac_have_decl
+_ACEOF
+ac_fn_c_check_decl "$LINENO" "ungetc" "ac_cv_have_decl_ungetc" "$ac_includes_default"
+if test "x$ac_cv_have_decl_ungetc" = xyes; then :
+  ac_have_decl=1
+else
+  ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_UNGETC $ac_have_decl
+_ACEOF
+ac_fn_c_check_decl "$LINENO" "vfprintf" "ac_cv_have_decl_vfprintf" "$ac_includes_default"
+if test "x$ac_cv_have_decl_vfprintf" = xyes; then :
+  ac_have_decl=1
+else
+  ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_VFPRINTF $ac_have_decl
+_ACEOF
+
+ac_fn_c_check_decl "$LINENO" "sys_errlist" "ac_cv_have_decl_sys_errlist" "#include <stdio.h>
+#include <errno.h>
+"
+if test "x$ac_cv_have_decl_sys_errlist" = xyes; then :
+  ac_have_decl=1
+else
+  ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_SYS_ERRLIST $ac_have_decl
+_ACEOF
+ac_fn_c_check_decl "$LINENO" "sys_nerr" "ac_cv_have_decl_sys_nerr" "#include <stdio.h>
+#include <errno.h>
+"
+if test "x$ac_cv_have_decl_sys_nerr" = xyes; then :
+  ac_have_decl=1
+else
+  ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_SYS_NERR $ac_have_decl
+_ACEOF
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking return type of signal handlers" >&5
+$as_echo_n "checking return type of signal handlers... " >&6; }
+if ${ac_cv_type_signal+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <signal.h>
+
+int
+main ()
+{
+return *(signal (0, 0)) (0) == 1;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_type_signal=int
+else
+  ac_cv_type_signal=void
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_signal" >&5
+$as_echo "$ac_cv_type_signal" >&6; }
+
+cat >>confdefs.h <<_ACEOF
+#define RETSIGTYPE $ac_cv_type_signal
+_ACEOF
+
+
+
+# Reasons for testing:
+#   intmax_t       - C99
+#   long double    - not in the HP bundled K&R cc
+#   long long      - only in reasonably recent compilers
+#   ptrdiff_t      - seems to be everywhere, maybe don't need to check this
+#   quad_t         - BSD specific
+#   uint_least32_t - C99
+#
+# the default includes are sufficient for all these types
+#
+ac_fn_c_check_type "$LINENO" "intmax_t" "ac_cv_type_intmax_t" "$ac_includes_default"
+if test "x$ac_cv_type_intmax_t" = xyes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_INTMAX_T 1
+_ACEOF
+
+
+fi
+ac_fn_c_check_type "$LINENO" "long double" "ac_cv_type_long_double" "$ac_includes_default"
+if test "x$ac_cv_type_long_double" = xyes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_LONG_DOUBLE 1
+_ACEOF
+
+
+fi
+ac_fn_c_check_type "$LINENO" "long long" "ac_cv_type_long_long" "$ac_includes_default"
+if test "x$ac_cv_type_long_long" = xyes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_LONG_LONG 1
+_ACEOF
+
+
+fi
+ac_fn_c_check_type "$LINENO" "ptrdiff_t" "ac_cv_type_ptrdiff_t" "$ac_includes_default"
+if test "x$ac_cv_type_ptrdiff_t" = xyes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_PTRDIFF_T 1
+_ACEOF
+
+
+fi
+ac_fn_c_check_type "$LINENO" "quad_t" "ac_cv_type_quad_t" "$ac_includes_default"
+if test "x$ac_cv_type_quad_t" = xyes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_QUAD_T 1
+_ACEOF
+
+
+fi
+ac_fn_c_check_type "$LINENO" "uint_least32_t" "ac_cv_type_uint_least32_t" "$ac_includes_default"
+if test "x$ac_cv_type_uint_least32_t" = xyes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_UINT_LEAST32_T 1
+_ACEOF
+
+
+fi
+ac_fn_c_check_type "$LINENO" "intptr_t" "ac_cv_type_intptr_t" "$ac_includes_default"
+if test "x$ac_cv_type_intptr_t" = xyes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_INTPTR_T 1
+_ACEOF
+
+
+fi
+
+
+# FIXME: Really want #ifndef __cplusplus around the #define volatile
+# replacement autoconf gives, since volatile is always available in C++.
+# But we don't use it in C++ currently.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working volatile" >&5
+$as_echo_n "checking for working volatile... " >&6; }
+if ${ac_cv_c_volatile+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+volatile int x;
+int * volatile y = (int *) 0;
+return !x && !y;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_c_volatile=yes
+else
+  ac_cv_c_volatile=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_volatile" >&5
+$as_echo "$ac_cv_c_volatile" >&6; }
+if test $ac_cv_c_volatile = no; then
+
+$as_echo "#define volatile /**/" >>confdefs.h
+
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C/C++ restrict keyword" >&5
+$as_echo_n "checking for C/C++ restrict keyword... " >&6; }
+if ${ac_cv_c_restrict+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_c_restrict=no
+   # The order here caters to the fact that C++ does not require restrict.
+   for ac_kw in __restrict __restrict__ _Restrict restrict; do
+     cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+typedef int * int_ptr;
+	int foo (int_ptr $ac_kw ip) {
+	return ip[0];
+       }
+int
+main ()
+{
+int s[1];
+	int * $ac_kw t = s;
+	t[0] = 0;
+	return foo(t)
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_c_restrict=$ac_kw
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+     test "$ac_cv_c_restrict" != no && break
+   done
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_restrict" >&5
+$as_echo "$ac_cv_c_restrict" >&6; }
+
+ case $ac_cv_c_restrict in
+   restrict) ;;
+   no) $as_echo "#define restrict /**/" >>confdefs.h
+ ;;
+   *)  cat >>confdefs.h <<_ACEOF
+#define restrict $ac_cv_c_restrict
+_ACEOF
+ ;;
+ esac
+
+
+# GMP_C_STDARG
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether gcc __attribute__ ((const)) works" >&5
+$as_echo_n "checking whether gcc __attribute__ ((const)) works... " >&6; }
+if ${gmp_cv_c_attribute_const+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+int foo (int x) __attribute__ ((const));
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  gmp_cv_c_attribute_const=yes
+else
+  gmp_cv_c_attribute_const=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_cv_c_attribute_const" >&5
+$as_echo "$gmp_cv_c_attribute_const" >&6; }
+if test $gmp_cv_c_attribute_const = yes; then
+
+$as_echo "#define HAVE_ATTRIBUTE_CONST 1" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether gcc __attribute__ ((malloc)) works" >&5
+$as_echo_n "checking whether gcc __attribute__ ((malloc)) works... " >&6; }
+if ${gmp_cv_c_attribute_malloc+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.c <<EOF
+void *foo (int x) __attribute__ ((malloc));
+EOF
+gmp_compile="$CC $CFLAGS $CPPFLAGS -c conftest.c >conftest.out 2>&1"
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  if grep "attribute directive ignored" conftest.out >/dev/null; then
+    gmp_cv_c_attribute_malloc=no
+  else
+    gmp_cv_c_attribute_malloc=yes
+  fi
+else
+  gmp_cv_c_attribute_malloc=no
+fi
+cat conftest.out >&5
+rm -f conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_cv_c_attribute_malloc" >&5
+$as_echo "$gmp_cv_c_attribute_malloc" >&6; }
+if test $gmp_cv_c_attribute_malloc = yes; then
+
+$as_echo "#define HAVE_ATTRIBUTE_MALLOC 1" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether gcc __attribute__ ((mode (XX))) works" >&5
+$as_echo_n "checking whether gcc __attribute__ ((mode (XX))) works... " >&6; }
+if ${gmp_cv_c_attribute_mode+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+typedef int SItype __attribute__ ((mode (SI)));
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  gmp_cv_c_attribute_mode=yes
+else
+  gmp_cv_c_attribute_mode=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_cv_c_attribute_mode" >&5
+$as_echo "$gmp_cv_c_attribute_mode" >&6; }
+if test $gmp_cv_c_attribute_mode = yes; then
+
+$as_echo "#define HAVE_ATTRIBUTE_MODE 1" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether gcc __attribute__ ((noreturn)) works" >&5
+$as_echo_n "checking whether gcc __attribute__ ((noreturn)) works... " >&6; }
+if ${gmp_cv_c_attribute_noreturn+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+void foo (int x) __attribute__ ((noreturn));
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  gmp_cv_c_attribute_noreturn=yes
+else
+  gmp_cv_c_attribute_noreturn=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_cv_c_attribute_noreturn" >&5
+$as_echo "$gmp_cv_c_attribute_noreturn" >&6; }
+if test $gmp_cv_c_attribute_noreturn = yes; then
+
+$as_echo "#define HAVE_ATTRIBUTE_NORETURN 1" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether gcc hidden aliases work" >&5
+$as_echo_n "checking whether gcc hidden aliases work... " >&6; }
+if ${gmp_cv_c_hidden_alias+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+void hid() __attribute__ ((visibility("hidden")));
+void hid() {}
+void pub() __attribute__ ((alias("hid")));
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  gmp_cv_c_hidden_alias=yes
+else
+  gmp_cv_c_hidden_alias=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_cv_c_hidden_alias" >&5
+$as_echo "$gmp_cv_c_hidden_alias" >&6; }
+if test $gmp_cv_c_hidden_alias = yes; then
+
+$as_echo "#define HAVE_HIDDEN_ALIAS 1" >>confdefs.h
+
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5
+$as_echo_n "checking for inline... " >&6; }
+if ${ac_cv_c_inline+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_c_inline=no
+for ac_kw in inline __inline__ __inline; do
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifndef __cplusplus
+typedef int foo_t;
+static $ac_kw foo_t static_foo () {return 0; }
+$ac_kw foo_t foo () {return 0; }
+#endif
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_c_inline=$ac_kw
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  test "$ac_cv_c_inline" != no && break
+done
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5
+$as_echo "$ac_cv_c_inline" >&6; }
+
+case $ac_cv_c_inline in
+  inline | yes) ;;
+  *)
+    case $ac_cv_c_inline in
+      no) ac_val=;;
+      *) ac_val=$ac_cv_c_inline;;
+    esac
+    cat >>confdefs.h <<_ACEOF
+#ifndef __cplusplus
+#define inline $ac_val
+#endif
+_ACEOF
+    ;;
+esac
+
+
+case $ac_cv_c_inline in
+no) ;;
+*)
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#define __GMP_WITHIN_CONFIGURE_INLINE 1
+#define __GMP_WITHIN_CONFIGURE 1   /* ignore template stuff */
+#define GMP_NAIL_BITS $GMP_NAIL_BITS
+#define GMP_LIMB_BITS 123
+$DEFN_LONG_LONG_LIMB
+#include "$srcdir/gmp-h.in"
+
+#ifndef __GMP_EXTERN_INLINE
+die die die
+#endif
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+  case $ac_cv_c_inline in
+  yes) tmp_inline=inline ;;
+  *)   tmp_inline=$ac_cv_c_inline ;;
+  esac
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: gmp.h doesnt recognise compiler \"$tmp_inline\", inlines will be unavailable" >&5
+$as_echo "$as_me: WARNING: gmp.h doesnt recognise compiler \"$tmp_inline\", inlines will be unavailable" >&2;}
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  ;;
+esac
+
+
+# from libtool
+LIBM=
+case $host in
+*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*)
+  # These system don't have libm, or don't need it
+  ;;
+*-ncr-sysv4.3*)
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _mwvalidcheckl in -lmw" >&5
+$as_echo_n "checking for _mwvalidcheckl in -lmw... " >&6; }
+if ${ac_cv_lib_mw__mwvalidcheckl+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lmw  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char _mwvalidcheckl ();
+int
+main ()
+{
+return _mwvalidcheckl ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_mw__mwvalidcheckl=yes
+else
+  ac_cv_lib_mw__mwvalidcheckl=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_mw__mwvalidcheckl" >&5
+$as_echo "$ac_cv_lib_mw__mwvalidcheckl" >&6; }
+if test "x$ac_cv_lib_mw__mwvalidcheckl" = xyes; then :
+  LIBM=-lmw
+fi
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for cos in -lm" >&5
+$as_echo_n "checking for cos in -lm... " >&6; }
+if ${ac_cv_lib_m_cos+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char cos ();
+int
+main ()
+{
+return cos ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_m_cos=yes
+else
+  ac_cv_lib_m_cos=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_cos" >&5
+$as_echo "$ac_cv_lib_m_cos" >&6; }
+if test "x$ac_cv_lib_m_cos" = xyes; then :
+  LIBM="$LIBM -lm"
+fi
+
+  ;;
+*)
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for cos in -lm" >&5
+$as_echo_n "checking for cos in -lm... " >&6; }
+if ${ac_cv_lib_m_cos+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char cos ();
+int
+main ()
+{
+return cos ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_m_cos=yes
+else
+  ac_cv_lib_m_cos=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_cos" >&5
+$as_echo "$ac_cv_lib_m_cos" >&6; }
+if test "x$ac_cv_lib_m_cos" = xyes; then :
+  LIBM=-lm
+fi
+
+  ;;
+esac
+
+
+
+
+# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works
+# for constant arguments.  Useless!
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working alloca.h" >&5
+$as_echo_n "checking for working alloca.h... " >&6; }
+if ${gmp_cv_header_alloca+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <alloca.h>
+int
+main ()
+{
+char *p = (char *) alloca (2 * sizeof (int));
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  gmp_cv_header_alloca=yes
+else
+  gmp_cv_header_alloca=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_cv_header_alloca" >&5
+$as_echo "$gmp_cv_header_alloca" >&6; }
+if test $gmp_cv_header_alloca = yes; then
+
+$as_echo "#define HAVE_ALLOCA_H 1" >>confdefs.h
+
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for alloca (via gmp-impl.h)" >&5
+$as_echo_n "checking for alloca (via gmp-impl.h)... " >&6; }
+if ${gmp_cv_func_alloca+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#define __GMP_WITHIN_CONFIGURE 1   /* ignore template stuff */
+#define GMP_NAIL_BITS $GMP_NAIL_BITS
+#define GMP_LIMB_BITS 123
+$DEFN_LONG_LONG_LIMB
+#include "$srcdir/gmp-h.in"
+
+#include "$srcdir/gmp-impl.h"
+
+int
+main ()
+{
+char *p = (char *) alloca (1);
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  gmp_cv_func_alloca=yes
+else
+  gmp_cv_func_alloca=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_cv_func_alloca" >&5
+$as_echo "$gmp_cv_func_alloca" >&6; }
+if test $gmp_cv_func_alloca = yes; then
+
+$as_echo "#define HAVE_ALLOCA 1" >>confdefs.h
+
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to allocate temporary memory" >&5
+$as_echo_n "checking how to allocate temporary memory... " >&6; }
+if ${gmp_cv_option_alloca+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $enable_alloca in
+  yes)
+    gmp_cv_option_alloca=alloca
+    ;;
+  no)
+    gmp_cv_option_alloca=malloc-reentrant
+    ;;
+  reentrant | notreentrant)
+    case $gmp_cv_func_alloca in
+    yes)  gmp_cv_option_alloca=alloca ;;
+    *)    gmp_cv_option_alloca=malloc-$enable_alloca ;;
+    esac
+    ;;
+  *)
+    gmp_cv_option_alloca=$enable_alloca
+    ;;
+esac
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_cv_option_alloca" >&5
+$as_echo "$gmp_cv_option_alloca" >&6; }
+
+
+
+case $gmp_cv_option_alloca in
+  alloca)
+    if test $gmp_cv_func_alloca = no; then
+      as_fn_error $? "--enable-alloca=alloca specified, but alloca not available" "$LINENO" 5
+    fi
+    $as_echo "#define WANT_TMP_ALLOCA 1" >>confdefs.h
+
+    TAL_OBJECT=tal-reent$U.lo
+    ;;
+  malloc-reentrant)
+    $as_echo "#define WANT_TMP_REENTRANT 1" >>confdefs.h
+
+    TAL_OBJECT=tal-reent$U.lo
+    ;;
+  malloc-notreentrant)
+    $as_echo "#define WANT_TMP_NOTREENTRANT 1" >>confdefs.h
+
+    TAL_OBJECT=tal-notreent$U.lo
+    ;;
+  debug)
+    $as_echo "#define WANT_TMP_DEBUG 1" >>confdefs.h
+
+    TAL_OBJECT=tal-debug$U.lo
+    ;;
+  *)
+    # checks at the start of configure.in should protect us
+    as_fn_error $? "unrecognised --enable-alloca=$gmp_cv_option_alloca" "$LINENO" 5
+    ;;
+esac
+
+
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdio.h>
+#define __GMP_WITHIN_CONFIGURE 1   /* ignore template stuff */
+#define GMP_NAIL_BITS $GMP_NAIL_BITS
+#define GMP_LIMB_BITS 123
+$DEFN_LONG_LONG_LIMB
+#include "$srcdir/gmp-h.in"
+
+#if ! _GMP_H_HAVE_FILE
+die die die
+#endif
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: gmp.h doesnt recognise <stdio.h>, FILE prototypes will be unavailable" >&5
+$as_echo "$as_me: WARNING: gmp.h doesnt recognise <stdio.h>, FILE prototypes will be unavailable" >&2;}
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5
+$as_echo_n "checking whether byte ordering is bigendian... " >&6; }
+if ${ac_cv_c_bigendian+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_c_bigendian=unknown
+    # See if we're dealing with a universal compiler.
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifndef __APPLE_CC__
+	       not a universal capable compiler
+	     #endif
+	     typedef int dummy;
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+	# Check for potential -arch flags.  It is not universal unless
+	# there are at least two -arch flags with different values.
+	ac_arch=
+	ac_prev=
+	for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do
+	 if test -n "$ac_prev"; then
+	   case $ac_word in
+	     i?86 | x86_64 | ppc | ppc64)
+	       if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then
+		 ac_arch=$ac_word
+	       else
+		 ac_cv_c_bigendian=universal
+		 break
+	       fi
+	       ;;
+	   esac
+	   ac_prev=
+	 elif test "x$ac_word" = "x-arch"; then
+	   ac_prev=arch
+	 fi
+       done
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+    if test $ac_cv_c_bigendian = unknown; then
+      # See if sys/param.h defines the BYTE_ORDER macro.
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+	     #include <sys/param.h>
+
+int
+main ()
+{
+#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \
+		     && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \
+		     && LITTLE_ENDIAN)
+	      bogus endian macros
+	     #endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  # It does; now see whether it defined to BIG_ENDIAN or not.
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+		#include <sys/param.h>
+
+int
+main ()
+{
+#if BYTE_ORDER != BIG_ENDIAN
+		 not big endian
+		#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_c_bigendian=yes
+else
+  ac_cv_c_bigendian=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+    fi
+    if test $ac_cv_c_bigendian = unknown; then
+      # See if <limits.h> defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris).
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <limits.h>
+
+int
+main ()
+{
+#if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN)
+	      bogus endian macros
+	     #endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  # It does; now see whether it defined to _BIG_ENDIAN or not.
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <limits.h>
+
+int
+main ()
+{
+#ifndef _BIG_ENDIAN
+		 not big endian
+		#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_c_bigendian=yes
+else
+  ac_cv_c_bigendian=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+    fi
+    if test $ac_cv_c_bigendian = unknown; then
+      # Compile a test program.
+      if test "$cross_compiling" = yes; then :
+  # Try to guess by grepping values from an object file.
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+short int ascii_mm[] =
+		  { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
+		short int ascii_ii[] =
+		  { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };
+		int use_ascii (int i) {
+		  return ascii_mm[i] + ascii_ii[i];
+		}
+		short int ebcdic_ii[] =
+		  { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };
+		short int ebcdic_mm[] =
+		  { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 };
+		int use_ebcdic (int i) {
+		  return ebcdic_mm[i] + ebcdic_ii[i];
+		}
+		extern int foo;
+
+int
+main ()
+{
+return use_ascii (foo) == use_ebcdic (foo);
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then
+	      ac_cv_c_bigendian=yes
+	    fi
+	    if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then
+	      if test "$ac_cv_c_bigendian" = unknown; then
+		ac_cv_c_bigendian=no
+	      else
+		# finding both strings is unlikely to happen, but who knows?
+		ac_cv_c_bigendian=unknown
+	      fi
+	    fi
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+
+	     /* Are we little or big endian?  From Harbison&Steele.  */
+	     union
+	     {
+	       long int l;
+	       char c[sizeof (long int)];
+	     } u;
+	     u.l = 1;
+	     return u.c[sizeof (long int) - 1] == 1;
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  ac_cv_c_bigendian=no
+else
+  ac_cv_c_bigendian=yes
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+    fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5
+$as_echo "$ac_cv_c_bigendian" >&6; }
+ case $ac_cv_c_bigendian in #(
+   yes)
+     $as_echo "#define HAVE_LIMB_BIG_ENDIAN 1" >>confdefs.h
+
+
+echo "define_not_for_expansion(\`HAVE_LIMB_BIG_ENDIAN')" >> $gmp_tmpconfigm4p
+;; #(
+   no)
+     $as_echo "#define HAVE_LIMB_LITTLE_ENDIAN 1" >>confdefs.h
+
+
+echo "define_not_for_expansion(\`HAVE_LIMB_LITTLE_ENDIAN')" >> $gmp_tmpconfigm4p
+
+   ;; #(
+   universal)
+
+$as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h
+
+     ;; #(
+   *)
+     : ;;
+ esac
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking format of \`double' floating point" >&5
+$as_echo_n "checking format of \`double' floating point... " >&6; }
+if ${gmp_cv_c_double_format+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  gmp_cv_c_double_format=unknown
+cat >conftest.c <<\EOF
+#include <stdio.h>
+struct foo {
+  char    before[8];
+  double  x;
+  char    after[8];
+};
+extern struct foo foo;
+struct foo foo = {
+  { '\001', '\043', '\105', '\147', '\211', '\253', '\315', '\357' },
+  -123456789.0,
+  { '\376', '\334', '\272', '\230', '\166', '\124', '\062', '\020' },
+};
+int main(){
+  int i;
+  for (i = 0; i < 8; i++) {
+    printf ("%d %f\n", foo.before[i] + foo.after[i], foo.x);
+  }
+  return 0;
+}
+EOF
+gmp_compile="$CC $CFLAGS $CPPFLAGS conftest.c -o conftest$EXEEXT >&5 2>&1"
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+cat >conftest.awk <<\EOF
+
+BEGIN {
+  found = 0
+}
+
+{
+  for (f = 2; f <= NF; f++)
+    {
+      for (i = 0; i < 23; i++)
+        got[i] = got[i+1];
+      got[23] = $f;
+
+      # match the special begin and end sequences
+      if (got[0] != "001") continue
+      if (got[1] != "043") continue
+      if (got[2] != "105") continue
+      if (got[3] != "147") continue
+      if (got[4] != "211") continue
+      if (got[5] != "253") continue
+      if (got[6] != "315") continue
+      if (got[7] != "357") continue
+      if (got[16] != "376") continue
+      if (got[17] != "334") continue
+      if (got[18] != "272") continue
+      if (got[19] != "230") continue
+      if (got[20] != "166") continue
+      if (got[21] != "124") continue
+      if (got[22] != "062") continue
+      if (got[23] != "020") continue
+
+      saw = " (" got[8] " " got[9] " " got[10] " " got[11] " " got[12] " " got[13] " " got[14] " " got[15] ")"
+
+      if (got[8]  == "000" &&  \
+          got[9]  == "000" &&  \
+          got[10] == "000" &&  \
+          got[11] == "124" &&  \
+          got[12] == "064" &&  \
+          got[13] == "157" &&  \
+          got[14] == "235" &&  \
+          got[15] == "301")
+        {
+          print "IEEE little endian"
+          found = 1
+          exit
+        }
+
+      # Little endian with the two 4-byte halves swapped, as used by ARM
+      # when the chip is in little endian mode.
+      #
+      if (got[8]  == "064" &&  \
+          got[9]  == "157" &&  \
+          got[10] == "235" &&  \
+          got[11] == "301" &&  \
+          got[12] == "000" &&  \
+          got[13] == "000" &&  \
+          got[14] == "000" &&  \
+          got[15] == "124")
+        {
+          print "IEEE little endian, swapped halves"
+          found = 1
+          exit
+        }
+
+      # gcc 2.95.4 on one GNU/Linux ARM system was seen generating 000 in
+      # the last byte, whereas 124 is correct.  Not sure where the bug
+      # actually lies, but a running program didn't seem to get a full
+      # mantissa worth of working bits.
+      #
+      # We match this case explicitly so we can give a nice result message,
+      # but we deliberately exclude it from the normal IEEE double setups
+      # since it's too broken.
+      #
+      if (got[8]  == "064" &&  \
+          got[9]  == "157" &&  \
+          got[10] == "235" &&  \
+          got[11] == "301" &&  \
+          got[12] == "000" &&  \
+          got[13] == "000" &&  \
+          got[14] == "000" &&  \
+          got[15] == "000")
+        {
+          print "bad ARM software floats"
+          found = 1
+          exit
+        }
+
+      if (got[8]  == "301" &&  \
+          got[9]  == "235" &&  \
+          got[10] == "157" &&  \
+          got[11] == "064" &&  \
+          got[12] == "124" &&  \
+          got[13] == "000" &&  \
+          got[14] == "000" &&  \
+          got[15] == "000")
+        {
+          print "IEEE big endian"
+          found = 1
+          exit
+        }
+
+      if (got[8]  == "353" &&  \
+          got[9]  == "315" &&  \
+          got[10] == "242" &&  \
+          got[11] == "171" &&  \
+          got[12] == "000" &&  \
+          got[13] == "240" &&  \
+          got[14] == "000" &&  \
+          got[15] == "000")
+        {
+          print "VAX D"
+          found = 1
+          exit
+        }
+
+      if (got[8]  == "275" &&  \
+          got[9]  == "301" &&  \
+          got[10] == "064" &&  \
+          got[11] == "157" &&  \
+          got[12] == "000" &&  \
+          got[13] == "124" &&  \
+          got[14] == "000" &&  \
+          got[15] == "000")
+        {
+          print "VAX G"
+          found = 1
+          exit
+        }
+
+      if (got[8]  == "300" &&  \
+          got[9]  == "033" &&  \
+          got[10] == "353" &&  \
+          got[11] == "171" &&  \
+          got[12] == "242" &&  \
+          got[13] == "240" &&  \
+          got[14] == "000" &&  \
+          got[15] == "000")
+        {
+          print "Cray CFP"
+          found = 1
+          exit
+        }
+    }
+}
+
+END {
+  if (! found)
+    print "unknown", saw
+}
+
+EOF
+  gmp_cv_c_double_format=`od -b conftest$EXEEXT | $AWK -f conftest.awk`
+  case $gmp_cv_c_double_format in
+  unknown*)
+    echo "cannot match anything, conftest$EXEEXT contains" >&5
+    od -b conftest$EXEEXT >&5
+    ;;
+  esac
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: oops, cannot compile test program" >&5
+$as_echo "$as_me: WARNING: oops, cannot compile test program" >&2;}
+fi
+rm -f conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_cv_c_double_format" >&5
+$as_echo "$gmp_cv_c_double_format" >&6; }
+
+
+
+case $gmp_cv_c_double_format in
+  "IEEE big endian")
+    $as_echo "#define HAVE_DOUBLE_IEEE_BIG_ENDIAN 1" >>confdefs.h
+
+
+echo "define_not_for_expansion(\`HAVE_DOUBLE_IEEE_BIG_ENDIAN')" >> $gmp_tmpconfigm4p
+
+    ;;
+  "IEEE little endian")
+    $as_echo "#define HAVE_DOUBLE_IEEE_LITTLE_ENDIAN 1" >>confdefs.h
+
+
+echo "define_not_for_expansion(\`HAVE_DOUBLE_IEEE_LITTLE_ENDIAN')" >> $gmp_tmpconfigm4p
+
+    ;;
+  "IEEE little endian, swapped halves")
+    $as_echo "#define HAVE_DOUBLE_IEEE_LITTLE_SWAPPED 1" >>confdefs.h
+ ;;
+  "VAX D")
+    $as_echo "#define HAVE_DOUBLE_VAX_D 1" >>confdefs.h
+ ;;
+  "VAX G")
+    $as_echo "#define HAVE_DOUBLE_VAX_G 1" >>confdefs.h
+ ;;
+  "Cray CFP")
+    $as_echo "#define HAVE_DOUBLE_CRAY_CFP 1" >>confdefs.h
+ ;;
+  "bad ARM software floats")
+    ;;
+  unknown*)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Could not determine float format." >&5
+$as_echo "$as_me: WARNING: Could not determine float format." >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Conversions to and from \"double\" may be slow." >&5
+$as_echo "$as_me: WARNING: Conversions to and from \"double\" may be slow." >&2;}
+    ;;
+  *)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: oops, unrecognised float format: $gmp_cv_c_double_format" >&5
+$as_echo "$as_me: WARNING: oops, unrecognised float format: $gmp_cv_c_double_format" >&2;}
+    ;;
+esac
+
+
+
+# Reasons for testing:
+#   alarm - not in mingw
+#   attr_get - IRIX specific
+#   clock_gettime - not in glibc 2.2.4, only very recent systems
+#   cputime - not in glibc
+#   getsysinfo - OSF specific
+#   getrusage - not in mingw
+#   gettimeofday - not in mingw
+#   mmap - not in mingw, djgpp
+#   nl_langinfo - X/Open standard only, not in djgpp for instance
+#   obstack_vprintf - glibc specific
+#   processor_info - solaris specific
+#   pstat_getprocessor - HPUX specific (10.x and up)
+#   raise - an ANSI-ism, though probably almost universal by now
+#   read_real_time - AIX specific
+#   sigaction - not in mingw
+#   sigaltstack - not in mingw, or old AIX (reputedly)
+#   sigstack - not in mingw
+#   strerror - not in SunOS
+#   strnlen - glibc extension (some other systems too)
+#   syssgi - IRIX specific
+#   times - not in mingw
+#
+# AC_FUNC_STRNLEN is not used because we don't want the AC_LIBOBJ
+# replacement setups it gives.  It detects a faulty strnlen on AIX, but
+# missing out on that test is ok since our only use of strnlen is in
+# __gmp_replacement_vsnprintf which is not required on AIX since it has a
+# vsnprintf.
+#
+for ac_func in alarm attr_get clock cputime getpagesize getrusage gettimeofday getsysinfo localeconv memset mmap mprotect nl_langinfo obstack_vprintf popen processor_info pstat_getprocessor raise read_real_time sigaction sigaltstack sigstack syssgi strchr strerror strnlen strtol strtoul sysconf sysctl sysctlbyname times
+do :
+  as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+# clock_gettime is in librt on *-*-osf5.1 and on glibc, so att -lrt to
+# TUNE_LIBS if needed. On linux (tested on x86_32, 2.6.26),
+# clock_getres reports ns accuracy, while in a quick test on osf
+# clock_getres said only 1 millisecond.
+
+old_LIBS="$LIBS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing clock_gettime" >&5
+$as_echo_n "checking for library containing clock_gettime... " >&6; }
+if ${ac_cv_search_clock_gettime+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char clock_gettime ();
+int
+main ()
+{
+return clock_gettime ();
+  ;
+  return 0;
+}
+_ACEOF
+for ac_lib in '' rt; do
+  if test -z "$ac_lib"; then
+    ac_res="none required"
+  else
+    ac_res=-l$ac_lib
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+  fi
+  if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_search_clock_gettime=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext
+  if ${ac_cv_search_clock_gettime+:} false; then :
+  break
+fi
+done
+if ${ac_cv_search_clock_gettime+:} false; then :
+
+else
+  ac_cv_search_clock_gettime=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_clock_gettime" >&5
+$as_echo "$ac_cv_search_clock_gettime" >&6; }
+ac_res=$ac_cv_search_clock_gettime
+if test "$ac_res" != no; then :
+  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+
+$as_echo "#define HAVE_CLOCK_GETTIME 1" >>confdefs.h
+
+fi
+
+TUNE_LIBS="$LIBS"
+LIBS="$old_LIBS"
+
+
+
+ac_fn_c_check_func "$LINENO" "vsnprintf" "ac_cv_func_vsnprintf"
+if test "x$ac_cv_func_vsnprintf" = xyes; then :
+  gmp_vsnprintf_exists=yes
+else
+  gmp_vsnprintf_exists=no
+fi
+
+if test "$gmp_vsnprintf_exists" = no; then
+  gmp_cv_func_vsnprintf=no
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether vsnprintf works" >&5
+$as_echo_n "checking whether vsnprintf works... " >&6; }
+if ${gmp_cv_func_vsnprintf+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  gmp_cv_func_vsnprintf=yes
+   for i in 'return check ("hello world");' 'int n; return check ("%nhello world", &n);'; do
+     if test "$cross_compiling" = yes; then :
+  gmp_cv_func_vsnprintf=probably; break
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#include <string.h>  /* for strcmp */
+#include <stdio.h>   /* for vsnprintf */
+
+#include <stdarg.h>
+
+int
+check (const char *fmt, ...)
+{
+  static char  buf[128];
+  va_list  ap;
+  int      ret;
+
+  va_start (ap, fmt);
+
+  ret = vsnprintf (buf, 4, fmt, ap);
+
+  if (ret == -1 || strcmp (buf, "hel") != 0)
+    return 1;
+
+  /* allowed return values */
+  if (ret != 3 && ret != 11)
+    return 2;
+
+  return 0;
+}
+
+int
+main ()
+{
+$i
+}
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  :
+else
+  gmp_cv_func_vsnprintf=no; break
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+  done
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_cv_func_vsnprintf" >&5
+$as_echo "$gmp_cv_func_vsnprintf" >&6; }
+  if test "$gmp_cv_func_vsnprintf" = probably; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cannot check for properly working vsnprintf when cross compiling, will assume it's ok" >&5
+$as_echo "$as_me: WARNING: cannot check for properly working vsnprintf when cross compiling, will assume it's ok" >&2;}
+  fi
+  if test "$gmp_cv_func_vsnprintf" != no; then
+
+$as_echo "#define HAVE_VSNPRINTF 1" >>confdefs.h
+
+  fi
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether sscanf needs writable input" >&5
+$as_echo_n "checking whether sscanf needs writable input... " >&6; }
+if ${gmp_cv_func_sscanf_writable_input+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $host in
+  *-*-hpux9 | *-*-hpux9.*)
+     gmp_cv_func_sscanf_writable_input=yes ;;
+  *) gmp_cv_func_sscanf_writable_input=no  ;;
+esac
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_cv_func_sscanf_writable_input" >&5
+$as_echo "$gmp_cv_func_sscanf_writable_input" >&6; }
+case $gmp_cv_func_sscanf_writable_input in
+  yes)
+$as_echo "#define SSCANF_WRITABLE_INPUT 1" >>confdefs.h
+ ;;
+  no)  ;;
+  *)   as_fn_error $? "unrecognised \$gmp_cv_func_sscanf_writable_input" "$LINENO" 5 ;;
+esac
+
+
+# Reasons for checking:
+#   pst_processor psp_iticksperclktick - not in hpux 9
+#
+ac_fn_c_check_member "$LINENO" "struct pst_processor" "psp_iticksperclktick" "ac_cv_member_struct_pst_processor_psp_iticksperclktick" "#include <sys/pstat.h>
+"
+if test "x$ac_cv_member_struct_pst_processor_psp_iticksperclktick" = xyes; then :
+
+$as_echo "#define HAVE_PSP_ITICKSPERCLKTICK 1" >>confdefs.h
+
+fi
+
+
+# C++ tests, when required
+#
+if test $enable_cxx = yes; then
+  ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+
+  # Reasons for testing:
+  #   <sstream> - not in g++ 2.95.2
+  #   std::locale - not in g++ 2.95.4
+  #
+
+for ac_header in sstream
+do :
+  ac_fn_cxx_check_header_mongrel "$LINENO" "sstream" "ac_cv_header_sstream" "$ac_includes_default"
+if test "x$ac_cv_header_sstream" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_SSTREAM 1
+_ACEOF
+
+fi
+
+done
+
+  ac_fn_cxx_check_type "$LINENO" "std::locale" "ac_cv_type_std__locale" "#include <locale>
+"
+if test "x$ac_cv_type_std__locale" = xyes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STD__LOCALE 1
+_ACEOF
+
+
+fi
+
+
+  ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+fi
+
+
+# Pick the correct source files in $path and link them to mpn/.
+# $gmp_mpn_functions lists all functions we need.
+#
+# The rule is to find a file with the function name and a .asm, .S,
+# .s, or .c extension.  Certain multi-function files with special names
+# can provide some functions too.  (mpn/Makefile.am passes
+# -DOPERATION_<func> to get them to generate the right code.)
+
+# Note: $gmp_mpn_functions must have mod_1 before pre_mod_1 so the former
+#       can optionally provide the latter as an extra entrypoint.  Likewise
+#       divrem_1 and pre_divrem_1.
+
+gmp_mpn_functions_optional="umul udiv					\
+  invert_limb sqr_diagonal sqr_diag_addlsh1				\
+  mul_2 mul_3 mul_4 mul_5 mul_6						\
+  addmul_2 addmul_3 addmul_4 addmul_5 addmul_6 addmul_7 addmul_8	\
+  addlsh1_n sublsh1_n rsblsh1_n rsh1add_n rsh1sub_n			\
+  addlsh2_n sublsh2_n rsblsh2_n						\
+  addlsh_n sublsh_n rsblsh_n						\
+  add_n_sub_n addaddmul_1msb0"
+
+gmp_mpn_functions="$extra_functions					   \
+  add add_1 add_n sub sub_1 sub_n cnd_add_n cnd_sub_n cnd_swap neg com	   \
+  mul_1 addmul_1 submul_1						   \
+  add_err1_n add_err2_n add_err3_n sub_err1_n sub_err2_n sub_err3_n	   \
+  lshift rshift dive_1 diveby3 divis divrem divrem_1 divrem_2		   \
+  fib2_ui fib2m mod_1 mod_34lsub1 mode1o pre_divrem_1 pre_mod_1 dump	   \
+  mod_1_1 mod_1_2 mod_1_3 mod_1_4 lshiftc				   \
+  mul mul_fft mul_n sqr mul_basecase sqr_basecase nussbaumer_mul	   \
+  mulmid_basecase toom42_mulmid mulmid_n mulmid				   \
+  random random2 pow_1							   \
+  rootrem sqrtrem sizeinbase get_str set_str compute_powtab		   \
+  scan0 scan1 popcount hamdist cmp zero_p				   \
+  perfsqr perfpow strongfibo						   \
+  gcd_11 gcd_22 gcd_1 gcd gcdext_1 gcdext gcd_subdiv_step		   \
+  gcdext_lehmer								   \
+  div_q tdiv_qr jacbase jacobi_2 jacobi get_d				   \
+  matrix22_mul matrix22_mul1_inverse_vector				   \
+  hgcd_matrix hgcd2 hgcd_step hgcd_reduce hgcd hgcd_appr		   \
+  hgcd2_jacobi hgcd_jacobi						   \
+  mullo_n mullo_basecase sqrlo sqrlo_basecase				   \
+  toom22_mul toom32_mul toom42_mul toom52_mul toom62_mul		   \
+  toom33_mul toom43_mul toom53_mul toom54_mul toom63_mul		   \
+  toom44_mul								   \
+  toom6h_mul toom6_sqr toom8h_mul toom8_sqr				   \
+  toom_couple_handling							   \
+  toom2_sqr toom3_sqr toom4_sqr						   \
+  toom_eval_dgr3_pm1 toom_eval_dgr3_pm2					   \
+  toom_eval_pm1 toom_eval_pm2 toom_eval_pm2exp toom_eval_pm2rexp	   \
+  toom_interpolate_5pts toom_interpolate_6pts toom_interpolate_7pts	   \
+  toom_interpolate_8pts toom_interpolate_12pts toom_interpolate_16pts	   \
+  invertappr invert binvert mulmod_bnm1 sqrmod_bnm1			   \
+  div_qr_1 div_qr_1n_pi1						   \
+  div_qr_2 div_qr_2n_pi1 div_qr_2u_pi1					   \
+  sbpi1_div_q sbpi1_div_qr sbpi1_divappr_q				   \
+  dcpi1_div_q dcpi1_div_qr dcpi1_divappr_q				   \
+  mu_div_qr mu_divappr_q mu_div_q					   \
+  bdiv_q_1								   \
+  sbpi1_bdiv_q sbpi1_bdiv_qr sbpi1_bdiv_r				   \
+  dcpi1_bdiv_q dcpi1_bdiv_qr						   \
+  mu_bdiv_q mu_bdiv_qr							   \
+  bdiv_q bdiv_qr broot brootinv bsqrt bsqrtinv				   \
+  divexact bdiv_dbm1c redc_1 redc_2 redc_n powm powlo sec_powm		   \
+  sec_mul sec_sqr sec_div_qr sec_div_r sec_pi1_div_qr sec_pi1_div_r	   \
+  sec_add_1 sec_sub_1 sec_invert					   \
+  trialdiv remove							   \
+  and_n andn_n nand_n ior_n iorn_n nior_n xor_n xnor_n			   \
+  copyi copyd zero sec_tabselect					   \
+  comb_tables								   \
+  $gmp_mpn_functions_optional"
+
+
+
+# the list of all object files used by mpn/Makefile.in and the
+# top-level Makefile.in, respectively
+mpn_objects=
+mpn_objs_in_libgmp=
+
+# links from the sources, to be removed by "make distclean"
+gmp_srclinks=
+
+
+# mpn_relative_top_srcdir is $top_srcdir, but for use from within the mpn
+# build directory.  If $srcdir is relative then we use a relative path too,
+# so the two trees can be moved together.
+case $srcdir in
+  [\\/]* | ?:[\\/]*)  # absolute, as per autoconf
+    mpn_relative_top_srcdir=$srcdir ;;
+  *)                    # relative
+    mpn_relative_top_srcdir=../$srcdir ;;
+esac
+
+
+
+
+
+
+# Fat binary setups.
+#
+# We proceed through each $fat_path directory, and look for $fat_function
+# routines there.  Those found are incorporated in the build by generating a
+# little mpn/<foo>.asm or mpn/<foo>.c file in the build directory, with
+# suitable function renaming, and adding that to $mpn_objects (the same as a
+# normal mpn file).
+#
+# fat.h is generated with macros to let internal calls to each $fat_function
+# go directly through __gmpn_cpuvec, plus macros and declarations helping to
+# setup that structure, on a per-directory basis ready for
+# mpn/<cpu>/fat/fat.c.
+#
+# fat.h includes thresholds listed in $fat_thresholds, extracted from
+# gmp-mparam.h in each directory.  An overall maximum for each threshold is
+# established, for use in making fixed size arrays of temporary space.
+# (Eg. MUL_TOOM33_THRESHOLD_LIMIT used by mpn/generic/mul.c.)
+#
+# It'd be possible to do some of this manually, but when there's more than a
+# few functions and a few directories it becomes very tedious, and very
+# prone to having some routine accidentally omitted.  On that basis it seems
+# best to automate as much as possible, even if the code to do so is a bit
+# ugly.
+#
+
+if test -n "$fat_path"; then
+  # Usually the mpn build directory is created with mpn/Makefile
+  # instantiation, but we want to write to it sooner.
+  mkdir mpn 2>/dev/null
+
+  echo "/* fat.h - setups for fat binaries." >fat.h
+  echo "   Generated by configure - DO NOT EDIT.  */" >>fat.h
+
+
+$as_echo "#define WANT_FAT_BINARY 1" >>confdefs.h
+
+
+echo 'define(<WANT_FAT_BINARY>, <yes>)' >>$gmp_tmpconfigm4
+
+
+  # Don't want normal copies of fat functions
+  for tmp_fn in $fat_functions; do
+    remove_from_list_tmp=
+for remove_from_list_i in $gmp_mpn_functions; do
+  if test $remove_from_list_i = $tmp_fn; then :;
+  else
+     remove_from_list_tmp="$remove_from_list_tmp $remove_from_list_i"
+  fi
+done
+gmp_mpn_functions=$remove_from_list_tmp
+
+    remove_from_list_tmp=
+for remove_from_list_i in $gmp_mpn_functions_optional; do
+  if test $remove_from_list_i = $tmp_fn; then :;
+  else
+     remove_from_list_tmp="$remove_from_list_tmp $remove_from_list_i"
+  fi
+done
+gmp_mpn_functions_optional=$remove_from_list_tmp
+
+  done
+
+  for tmp_fn in $fat_functions; do
+    case $tmp_fn in
+  dive_1)	tmp_fbase=divexact_1 ;;
+  diveby3)	tmp_fbase=divexact_by3c ;;
+  pre_divrem_1) tmp_fbase=preinv_divrem_1 ;;
+  mode1o)	tmp_fbase=modexact_1c_odd ;;
+  pre_mod_1)	tmp_fbase=preinv_mod_1 ;;
+  mod_1_1)	tmp_fbase=mod_1_1p ;;
+  mod_1_1_cps)	tmp_fbase=mod_1_1p_cps ;;
+  mod_1_2)	tmp_fbase=mod_1s_2p ;;
+  mod_1_2_cps)	tmp_fbase=mod_1s_2p_cps ;;
+  mod_1_3)	tmp_fbase=mod_1s_3p ;;
+  mod_1_3_cps)	tmp_fbase=mod_1s_3p_cps ;;
+  mod_1_4)	tmp_fbase=mod_1s_4p ;;
+  mod_1_4_cps)	tmp_fbase=mod_1s_4p_cps ;;
+  *)		tmp_fbase=$tmp_fn ;;
+esac
+
+    echo "
+#ifndef OPERATION_$tmp_fn
+#undef  mpn_$tmp_fbase
+#define mpn_$tmp_fbase  (*__gmpn_cpuvec.$tmp_fbase)
+#endif
+DECL_$tmp_fbase (__MPN(${tmp_fbase}_init));" >>fat.h
+    # encourage various macros to use fat functions
+    cat >>confdefs.h <<_ACEOF
+#define HAVE_NATIVE_mpn_$tmp_fbase 1
+_ACEOF
+
+  done
+
+  echo "" >>fat.h
+  echo "/* variable thresholds */" >>fat.h
+  for tmp_tn in $fat_thresholds; do
+    echo "#undef  $tmp_tn" >>fat.h
+    echo "#define $tmp_tn  CPUVEC_THRESHOLD (`echo $tmp_tn | tr [A-Z] [a-z]`)" >>fat.h
+  done
+
+  echo "
+/* Copy all fields into __gmpn_cpuvec.
+   memcpy is not used because it might operate byte-wise (depending on its
+   implementation), and we need the function pointer writes to be atomic.
+   "volatile" discourages the compiler from trying to optimize this.  */
+#define CPUVEC_INSTALL(vec) \\
+  do { \\
+    volatile struct cpuvec_t *p = &__gmpn_cpuvec; \\" >>fat.h
+  for tmp_fn in $fat_functions; do
+    case $tmp_fn in
+  dive_1)	tmp_fbase=divexact_1 ;;
+  diveby3)	tmp_fbase=divexact_by3c ;;
+  pre_divrem_1) tmp_fbase=preinv_divrem_1 ;;
+  mode1o)	tmp_fbase=modexact_1c_odd ;;
+  pre_mod_1)	tmp_fbase=preinv_mod_1 ;;
+  mod_1_1)	tmp_fbase=mod_1_1p ;;
+  mod_1_1_cps)	tmp_fbase=mod_1_1p_cps ;;
+  mod_1_2)	tmp_fbase=mod_1s_2p ;;
+  mod_1_2_cps)	tmp_fbase=mod_1s_2p_cps ;;
+  mod_1_3)	tmp_fbase=mod_1s_3p ;;
+  mod_1_3_cps)	tmp_fbase=mod_1s_3p_cps ;;
+  mod_1_4)	tmp_fbase=mod_1s_4p ;;
+  mod_1_4_cps)	tmp_fbase=mod_1s_4p_cps ;;
+  *)		tmp_fbase=$tmp_fn ;;
+esac
+
+    echo "    p->$tmp_fbase = vec.$tmp_fbase; \\" >>fat.h
+  done
+  for tmp_tn in $fat_thresholds; do
+    tmp_field_name=`echo $tmp_tn | tr [A-Z] [a-z]`
+    echo "    p->$tmp_field_name = vec.$tmp_field_name; \\" >>fat.h
+  done
+  echo "  } while (0)" >>fat.h
+
+  echo "
+/* A helper to check all fields are filled. */
+#define ASSERT_CPUVEC(vec) \\
+  do { \\" >>fat.h
+  for tmp_fn in $fat_functions; do
+    case $tmp_fn in
+  dive_1)	tmp_fbase=divexact_1 ;;
+  diveby3)	tmp_fbase=divexact_by3c ;;
+  pre_divrem_1) tmp_fbase=preinv_divrem_1 ;;
+  mode1o)	tmp_fbase=modexact_1c_odd ;;
+  pre_mod_1)	tmp_fbase=preinv_mod_1 ;;
+  mod_1_1)	tmp_fbase=mod_1_1p ;;
+  mod_1_1_cps)	tmp_fbase=mod_1_1p_cps ;;
+  mod_1_2)	tmp_fbase=mod_1s_2p ;;
+  mod_1_2_cps)	tmp_fbase=mod_1s_2p_cps ;;
+  mod_1_3)	tmp_fbase=mod_1s_3p ;;
+  mod_1_3_cps)	tmp_fbase=mod_1s_3p_cps ;;
+  mod_1_4)	tmp_fbase=mod_1s_4p ;;
+  mod_1_4_cps)	tmp_fbase=mod_1s_4p_cps ;;
+  *)		tmp_fbase=$tmp_fn ;;
+esac
+
+    echo "    ASSERT (vec.$tmp_fbase != NULL); \\" >>fat.h
+  done
+  for tmp_tn in $fat_thresholds; do
+    tmp_field_name=`echo $tmp_tn | tr [A-Z] [a-z]`
+    echo "    ASSERT (vec.$tmp_field_name != 0); \\" >>fat.h
+  done
+  echo "  } while (0)" >>fat.h
+
+  echo "
+/* Call ITERATE(field) for each fat threshold field. */
+#define ITERATE_FAT_THRESHOLDS() \\
+  do { \\" >>fat.h
+  for tmp_tn in $fat_thresholds; do
+    tmp_field_name=`echo $tmp_tn | tr [A-Z] [a-z]`
+    echo "    ITERATE ($tmp_tn, $tmp_field_name); \\" >>fat.h
+  done
+  echo "  } while (0)" >>fat.h
+
+  for tmp_dir in $fat_path; do
+    CPUVEC_SETUP=
+    THRESH_ASM_SETUP=
+    echo "" >>fat.h
+    tmp_suffix=`echo $tmp_dir | sed -e '/\//s:^[^/]*/::' -e 's:[\\/]:_:g'`
+
+    # In order to keep names unique on a DOS 8.3 filesystem, use a prefix
+    # (rather than a suffix) for the generated file names, and abbreviate.
+    case $tmp_suffix in
+      pentium)       tmp_prefix=p   ;;
+      pentium_mmx)   tmp_prefix=pm  ;;
+      p6_mmx)        tmp_prefix=p2  ;;
+      p6_p3mmx)      tmp_prefix=p3  ;;
+      pentium4)      tmp_prefix=p4  ;;
+      pentium4_mmx)  tmp_prefix=p4m ;;
+      pentium4_sse2) tmp_prefix=p4s ;;
+      k6_mmx)        tmp_prefix=k6m ;;
+      k6_k62mmx)     tmp_prefix=k62 ;;
+      k7_mmx)        tmp_prefix=k7m ;;
+      *)             tmp_prefix=$tmp_suffix ;;
+    esac
+
+    # Extract desired thresholds from gmp-mparam.h file in this directory,
+    # if present.
+    tmp_mparam=$srcdir/mpn/$tmp_dir/gmp-mparam.h
+    if test -f $tmp_mparam; then
+      for tmp_tn in $fat_thresholds; do
+        tmp_thresh=`sed -n "s/^#define $tmp_tn[ 	]*\\([0-9][0-9]*\\).*$/\\1/p" $tmp_mparam`
+        if test -n "$tmp_thresh"; then
+          THRESH_ASM_SETUP="${THRESH_ASM_SETUP}define($tmp_tn,$tmp_thresh)
+"
+          CPUVEC_SETUP="$CPUVEC_SETUP    decided_cpuvec.`echo $tmp_tn | tr [A-Z] [a-z]` = $tmp_thresh; \\
+"
+          eval tmp_limit=\$${tmp_tn}_LIMIT
+          if test -z "$tmp_limit"; then
+            tmp_limit=0
+          fi
+          if test $tmp_thresh -gt $tmp_limit; then
+            eval ${tmp_tn}_LIMIT=$tmp_thresh
+          fi
+        fi
+      done
+    fi
+
+    for tmp_fn in $fat_functions; do
+      # functions that can be provided by multi-function files
+tmp_mulfunc=
+case $tmp_fn in
+  add_n|sub_n)       tmp_mulfunc="aors_n"    ;;
+  add_err1_n|sub_err1_n)
+		     tmp_mulfunc="aors_err1_n" ;;
+  add_err2_n|sub_err2_n)
+		     tmp_mulfunc="aors_err2_n" ;;
+  add_err3_n|sub_err3_n)
+		     tmp_mulfunc="aors_err3_n" ;;
+  cnd_add_n|cnd_sub_n) tmp_mulfunc="cnd_aors_n"   ;;
+  sec_add_1|sec_sub_1) tmp_mulfunc="sec_aors_1"   ;;
+  addmul_1|submul_1) tmp_mulfunc="aorsmul_1" ;;
+  mul_2|addmul_2)    tmp_mulfunc="aormul_2" ;;
+  mul_3|addmul_3)    tmp_mulfunc="aormul_3" ;;
+  mul_4|addmul_4)    tmp_mulfunc="aormul_4" ;;
+  popcount|hamdist)  tmp_mulfunc="popham"    ;;
+  and_n|andn_n|nand_n | ior_n|iorn_n|nior_n | xor_n|xnor_n)
+                     tmp_mulfunc="logops_n"  ;;
+  lshift|rshift)     tmp_mulfunc="lorrshift";;
+  addlsh1_n)
+		     tmp_mulfunc="aorslsh1_n aorrlsh1_n aorsorrlsh1_n";;
+  sublsh1_n)
+		     tmp_mulfunc="aorslsh1_n sorrlsh1_n aorsorrlsh1_n";;
+  rsblsh1_n)
+		     tmp_mulfunc="aorrlsh1_n sorrlsh1_n aorsorrlsh1_n";;
+  addlsh2_n)
+		     tmp_mulfunc="aorslsh2_n aorrlsh2_n aorsorrlsh2_n";;
+  sublsh2_n)
+		     tmp_mulfunc="aorslsh2_n sorrlsh2_n aorsorrlsh2_n";;
+  rsblsh2_n)
+		     tmp_mulfunc="aorrlsh2_n sorrlsh2_n aorsorrlsh2_n";;
+  addlsh_n)
+		     tmp_mulfunc="aorslsh_n aorrlsh_n aorsorrlsh_n";;
+  sublsh_n)
+		     tmp_mulfunc="aorslsh_n sorrlsh_n aorsorrlsh_n";;
+  rsblsh_n)
+		     tmp_mulfunc="aorrlsh_n sorrlsh_n aorsorrlsh_n";;
+  rsh1add_n|rsh1sub_n)
+		     tmp_mulfunc="rsh1aors_n";;
+  sec_div_qr|sec_div_r)
+		     tmp_mulfunc="sec_div";;
+  sec_pi1_div_qr|sec_pi1_div_r)
+		     tmp_mulfunc="sec_pi1_div";;
+esac
+
+
+      for tmp_base in $tmp_fn $tmp_mulfunc; do
+        for tmp_ext in asm S s c; do
+          tmp_file=$srcdir/mpn/$tmp_dir/$tmp_base.$tmp_ext
+          if test -f $tmp_file; then
+
+	    # If the host uses a non-standard ABI, check if tmp_file supports it
+	    #
+	    if test -n "$GMP_NONSTD_ABI" && test $tmp_ext != "c"; then
+	      abi=`sed -n 's/^[ 	]*ABI_SUPPORT(\(.*\))/\1/p' $tmp_file `
+	      if echo "$abi" | grep -q "\\b${GMP_NONSTD_ABI}\\b"; then
+		true
+	      else
+		continue
+	      fi
+	    fi
+
+            mpn_objects="$mpn_objects ${tmp_prefix}_$tmp_fn.lo"
+            mpn_objs_in_libgmp="$mpn_objs_in_libgmp mpn/${tmp_prefix}_$tmp_fn.lo"
+
+            case $tmp_fn in
+  dive_1)	tmp_fbase=divexact_1 ;;
+  diveby3)	tmp_fbase=divexact_by3c ;;
+  pre_divrem_1) tmp_fbase=preinv_divrem_1 ;;
+  mode1o)	tmp_fbase=modexact_1c_odd ;;
+  pre_mod_1)	tmp_fbase=preinv_mod_1 ;;
+  mod_1_1)	tmp_fbase=mod_1_1p ;;
+  mod_1_1_cps)	tmp_fbase=mod_1_1p_cps ;;
+  mod_1_2)	tmp_fbase=mod_1s_2p ;;
+  mod_1_2_cps)	tmp_fbase=mod_1s_2p_cps ;;
+  mod_1_3)	tmp_fbase=mod_1s_3p ;;
+  mod_1_3_cps)	tmp_fbase=mod_1s_3p_cps ;;
+  mod_1_4)	tmp_fbase=mod_1s_4p ;;
+  mod_1_4_cps)	tmp_fbase=mod_1s_4p_cps ;;
+  *)		tmp_fbase=$tmp_fn ;;
+esac
+
+
+            # carry-in variant, eg. divrem_1c or modexact_1c_odd
+            case $tmp_fbase in
+              *_1*) tmp_fbasec=`echo $tmp_fbase | sed 's/_1/_1c/'` ;;
+              *)    tmp_fbasec=${tmp_fbase}c ;;
+            esac
+
+            # Create a little file doing an include from srcdir.  The
+            # OPERATION and renamings aren't all needed all the time, but
+            # they don't hurt if unused.
+            #
+            # FIXME: Should generate these via config.status commands.
+            # Would need them all in one AC_CONFIG_COMMANDS though, since
+            # that macro doesn't accept a set of separate commands generated
+            # by shell code.
+            #
+            case $tmp_ext in
+              asm)
+                # hide the d-n-l from autoconf's error checking
+                tmp_d_n_l=d""nl
+                echo "$tmp_d_n_l  mpn_$tmp_fbase - from $tmp_dir directory for fat binary.
+$tmp_d_n_l  Generated by configure - DO NOT EDIT.
+
+define(OPERATION_$tmp_fn)
+define(__gmpn_$tmp_fbase, __gmpn_${tmp_fbase}_$tmp_suffix)
+define(__gmpn_$tmp_fbasec,__gmpn_${tmp_fbasec}_${tmp_suffix})
+define(__gmpn_preinv_${tmp_fbase},__gmpn_preinv_${tmp_fbase}_${tmp_suffix})
+define(__gmpn_${tmp_fbase}_cps,__gmpn_${tmp_fbase}_cps_${tmp_suffix})
+
+$tmp_d_n_l  For k6 and k7 gcd_1 calling their corresponding mpn_modexact_1_odd
+ifdef(\`__gmpn_modexact_1_odd',,
+\`define(__gmpn_modexact_1_odd,__gmpn_modexact_1_odd_${tmp_suffix})')
+
+$THRESH_ASM_SETUP
+include($mpn_relative_top_srcdir/mpn/$tmp_dir/$tmp_base.asm)
+" >mpn/${tmp_prefix}_$tmp_fn.asm
+                ;;
+              c)
+                echo "/* mpn_$tmp_fbase - from $tmp_dir directory for fat binary.
+   Generated by configure - DO NOT EDIT. */
+
+#define OPERATION_$tmp_fn 1
+#define __gmpn_$tmp_fbase           __gmpn_${tmp_fbase}_$tmp_suffix
+#define __gmpn_$tmp_fbasec          __gmpn_${tmp_fbasec}_${tmp_suffix}
+#define __gmpn_preinv_${tmp_fbase}  __gmpn_preinv_${tmp_fbase}_${tmp_suffix}
+#define __gmpn_${tmp_fbase}_cps     __gmpn_${tmp_fbase}_cps_${tmp_suffix}
+
+#include \"$mpn_relative_top_srcdir/mpn/$tmp_dir/$tmp_base.c\"
+" >mpn/${tmp_prefix}_$tmp_fn.c
+                ;;
+            esac
+
+            # Prototype, and append to CPUVEC_SETUP for this directory.
+            echo "DECL_$tmp_fbase (__gmpn_${tmp_fbase}_$tmp_suffix);" >>fat.h
+            CPUVEC_SETUP="$CPUVEC_SETUP    decided_cpuvec.$tmp_fbase = __gmpn_${tmp_fbase}_${tmp_suffix}; \\
+"
+            # Ditto for any preinv variant (preinv_divrem_1, preinv_mod_1).
+            if grep "^PROLOGUE(mpn_preinv_$tmp_fn)" $tmp_file >/dev/null; then
+              echo "DECL_preinv_$tmp_fbase (__gmpn_preinv_${tmp_fbase}_$tmp_suffix);" >>fat.h
+              CPUVEC_SETUP="$CPUVEC_SETUP    decided_cpuvec.preinv_$tmp_fbase = __gmpn_preinv_${tmp_fbase}_${tmp_suffix}; \\
+"
+            fi
+
+            # Ditto for any mod_1...cps variant
+            if grep "^PROLOGUE(mpn_${tmp_fbase}_cps)" $tmp_file >/dev/null; then
+              echo "DECL_${tmp_fbase}_cps (__gmpn_${tmp_fbase}_cps_$tmp_suffix);" >>fat.h
+              CPUVEC_SETUP="$CPUVEC_SETUP    decided_cpuvec.${tmp_fbase}_cps = __gmpn_${tmp_fbase}_cps_${tmp_suffix}; \\
+"
+            fi
+          fi
+        done
+      done
+    done
+
+    # Emit CPUVEC_SETUP for this directory
+    echo "" >>fat.h
+    echo "#define CPUVEC_SETUP_$tmp_suffix \\" >>fat.h
+    echo "  do { \\" >>fat.h
+    echo "$CPUVEC_SETUP  } while (0)" >>fat.h
+  done
+
+  # Emit threshold limits
+  echo "" >>fat.h
+  for tmp_tn in $fat_thresholds; do
+    eval tmp_limit=\$${tmp_tn}_LIMIT
+    echo "#define ${tmp_tn}_LIMIT  $tmp_limit" >>fat.h
+  done
+fi
+
+
+# Normal binary setups.
+#
+
+for tmp_ext in asm S s c; do
+  eval found_$tmp_ext=no
+done
+
+for tmp_fn in $gmp_mpn_functions; do
+  for tmp_ext in asm S s c; do
+    test "$no_create" = yes || rm -f mpn/$tmp_fn.$tmp_ext
+  done
+
+  # mpn_preinv_divrem_1 might have been provided by divrem_1.asm, likewise
+  # mpn_preinv_mod_1 by mod_1.asm.
+  case $tmp_fn in
+  pre_divrem_1)
+    if test "$HAVE_NATIVE_mpn_preinv_divrem_1" = yes; then continue; fi ;;
+  pre_mod_1)
+    if test "$HAVE_NATIVE_mpn_preinv_mod_1" = yes; then continue; fi ;;
+  esac
+
+  # functions that can be provided by multi-function files
+tmp_mulfunc=
+case $tmp_fn in
+  add_n|sub_n)       tmp_mulfunc="aors_n"    ;;
+  add_err1_n|sub_err1_n)
+		     tmp_mulfunc="aors_err1_n" ;;
+  add_err2_n|sub_err2_n)
+		     tmp_mulfunc="aors_err2_n" ;;
+  add_err3_n|sub_err3_n)
+		     tmp_mulfunc="aors_err3_n" ;;
+  cnd_add_n|cnd_sub_n) tmp_mulfunc="cnd_aors_n"   ;;
+  sec_add_1|sec_sub_1) tmp_mulfunc="sec_aors_1"   ;;
+  addmul_1|submul_1) tmp_mulfunc="aorsmul_1" ;;
+  mul_2|addmul_2)    tmp_mulfunc="aormul_2" ;;
+  mul_3|addmul_3)    tmp_mulfunc="aormul_3" ;;
+  mul_4|addmul_4)    tmp_mulfunc="aormul_4" ;;
+  popcount|hamdist)  tmp_mulfunc="popham"    ;;
+  and_n|andn_n|nand_n | ior_n|iorn_n|nior_n | xor_n|xnor_n)
+                     tmp_mulfunc="logops_n"  ;;
+  lshift|rshift)     tmp_mulfunc="lorrshift";;
+  addlsh1_n)
+		     tmp_mulfunc="aorslsh1_n aorrlsh1_n aorsorrlsh1_n";;
+  sublsh1_n)
+		     tmp_mulfunc="aorslsh1_n sorrlsh1_n aorsorrlsh1_n";;
+  rsblsh1_n)
+		     tmp_mulfunc="aorrlsh1_n sorrlsh1_n aorsorrlsh1_n";;
+  addlsh2_n)
+		     tmp_mulfunc="aorslsh2_n aorrlsh2_n aorsorrlsh2_n";;
+  sublsh2_n)
+		     tmp_mulfunc="aorslsh2_n sorrlsh2_n aorsorrlsh2_n";;
+  rsblsh2_n)
+		     tmp_mulfunc="aorrlsh2_n sorrlsh2_n aorsorrlsh2_n";;
+  addlsh_n)
+		     tmp_mulfunc="aorslsh_n aorrlsh_n aorsorrlsh_n";;
+  sublsh_n)
+		     tmp_mulfunc="aorslsh_n sorrlsh_n aorsorrlsh_n";;
+  rsblsh_n)
+		     tmp_mulfunc="aorrlsh_n sorrlsh_n aorsorrlsh_n";;
+  rsh1add_n|rsh1sub_n)
+		     tmp_mulfunc="rsh1aors_n";;
+  sec_div_qr|sec_div_r)
+		     tmp_mulfunc="sec_div";;
+  sec_pi1_div_qr|sec_pi1_div_r)
+		     tmp_mulfunc="sec_pi1_div";;
+esac
+
+
+  found=no
+  for tmp_dir in $path; do
+    for tmp_base in $tmp_fn $tmp_mulfunc; do
+      for tmp_ext in asm S s c; do
+        tmp_file=$srcdir/mpn/$tmp_dir/$tmp_base.$tmp_ext
+        if test -f $tmp_file; then
+
+          # For a nails build, check if the file supports our nail bits.
+          # Generic code always supports all nails.
+          #
+          # FIXME: When a multi-function file is selected to provide one of
+          # the nails-neutral routines, like logops_n for and_n, the
+          # PROLOGUE grepping will create HAVE_NATIVE_mpn_<foo> defines for
+          # all functions in that file, even if they haven't all been
+          # nailified.  Not sure what to do about this, it's only really a
+          # problem for logops_n, and it's not too terrible to insist those
+          # get nailified always.
+          #
+          if test $GMP_NAIL_BITS != 0 && test $tmp_dir != generic; then
+            case $tmp_fn in
+              and_n | ior_n | xor_n | andn_n | \
+              copyi | copyd | \
+              popcount | hamdist | \
+              udiv | udiv_w_sdiv | umul | \
+              cntlz | invert_limb)
+                # these operations are either unaffected by nails or defined
+                # to operate on full limbs
+                ;;
+              *)
+                nails=`sed -n 's/^[ 	]*NAILS_SUPPORT(\(.*\))/\1/p' $tmp_file `
+                for n in $nails; do
+                  case $n in
+                  *-*)
+                    n_start=`echo "$n" | sed -n 's/\(.*\)-.*/\1/p'`
+                    n_end=`echo "$n" | sed -n 's/.*-\(.*\)/\1/p'`
+                    ;;
+                  *)
+                    n_start=$n
+                    n_end=$n
+                    ;;
+                  esac
+                  if test $GMP_NAIL_BITS -ge $n_start && test $GMP_NAIL_BITS -le $n_end; then
+                    found=yes
+                    break
+                  fi
+                done
+                if test $found != yes; then
+                  continue
+                fi
+                ;;
+            esac
+          fi
+
+	  # If the host uses a non-standard ABI, check if tmp_file supports it
+	  #
+	  if test -n "$GMP_NONSTD_ABI" && test $tmp_ext != "c"; then
+	    abi=`sed -n 's/^[ 	]*ABI_SUPPORT(\(.*\))/\1/p' $tmp_file `
+	    if echo "$abi" | grep -q "\\b${GMP_NONSTD_ABI}\\b"; then
+	      true
+	    else
+	      continue
+	    fi
+	  fi
+
+          found=yes
+          eval found_$tmp_ext=yes
+
+          if test $tmp_ext = c; then
+            tmp_u='$U'
+          else
+            tmp_u=
+          fi
+
+          mpn_objects="$mpn_objects $tmp_fn$tmp_u.lo"
+          mpn_objs_in_libgmp="$mpn_objs_in_libgmp mpn/$tmp_fn$tmp_u.lo"
+          ac_config_links="$ac_config_links mpn/$tmp_fn.$tmp_ext:mpn/$tmp_dir/$tmp_base.$tmp_ext"
+
+          gmp_srclinks="$gmp_srclinks mpn/$tmp_fn.$tmp_ext"
+
+          # Duplicate AC_DEFINEs are harmless, so it doesn't matter
+          # that multi-function files get grepped here repeatedly.
+          # The PROLOGUE pattern excludes the optional second parameter.
+          gmp_ep=`
+            sed -n 's/^[ 	]*MULFUNC_PROLOGUE(\(.*\))/\1/p' $tmp_file ;
+            sed -n 's/^[ 	]*PROLOGUE(\([^,]*\).*)/\1/p' $tmp_file
+          `
+          for gmp_tmp in $gmp_ep; do
+            cat >>confdefs.h <<_ACEOF
+#define HAVE_NATIVE_$gmp_tmp 1
+_ACEOF
+
+            eval HAVE_NATIVE_$gmp_tmp=yes
+          done
+
+          case $tmp_fn in
+          sqr_basecase) sqr_basecase_source=$tmp_file ;;
+          esac
+
+          break
+        fi
+      done
+      if test $found = yes; then break ; fi
+    done
+    if test $found = yes; then break ; fi
+  done
+
+  if test $found = no; then
+    for tmp_optional in $gmp_mpn_functions_optional; do
+      if test $tmp_optional = $tmp_fn; then
+        found=yes
+      fi
+    done
+    if test $found = no; then
+      as_fn_error $? "no version of $tmp_fn found in path: $path" "$LINENO" 5
+    fi
+  fi
+done
+
+# All cycle counters are .asm files currently
+if test -n "$SPEED_CYCLECOUNTER_OBJ"; then
+  found_asm=yes
+fi
+
+
+
+
+
+# Don't demand an m4 unless it's actually needed.
+if test $found_asm = yes; then
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suitable m4" >&5
+$as_echo_n "checking for suitable m4... " >&6; }
+if ${gmp_cv_prog_m4+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$M4"; then
+  gmp_cv_prog_m4="$M4"
+else
+  cat >conftest.m4 <<\EOF
+define(dollarhash,``$#'')ifelse(dollarhash(x),1,`define(t1,Y)',
+``bad: $# not supported (SunOS /usr/bin/m4)
+'')ifelse(eval(89),89,`define(t2,Y)',
+`bad: eval() doesnt support 8 or 9 in a constant (OpenBSD 2.6 m4)
+')ifelse(eval(9,9),10,`define(t3,Y)',
+`bad: eval() doesnt support radix in eval (FreeBSD 8.x,9.0,9.1,9.2 m4)
+')ifelse(t1`'t2`'t3,YYY,`good
+')
+EOF
+  echo "trying m4" >&5
+  gmp_tmp_val=`(m4 conftest.m4) 2>&5`
+  echo "$gmp_tmp_val" >&5
+  if test "$gmp_tmp_val" = good; then
+    gmp_cv_prog_m4="m4"
+  else
+    IFS="${IFS= 	}"; ac_save_ifs="$IFS"; IFS=":"
+    ac_dummy="$PATH:/usr/5bin"
+    for ac_dir in $ac_dummy; do
+      test -z "$ac_dir" && ac_dir=.
+      echo "trying $ac_dir/m4" >&5
+      gmp_tmp_val=`($ac_dir/m4 conftest.m4) 2>&5`
+      echo "$gmp_tmp_val" >&5
+      if test "$gmp_tmp_val" = good; then
+        gmp_cv_prog_m4="$ac_dir/m4"
+        break
+      fi
+    done
+    IFS="$ac_save_ifs"
+    if test -z "$gmp_cv_prog_m4"; then
+      as_fn_error $? "No usable m4 in \$PATH or /usr/5bin (see config.log for reasons)." "$LINENO" 5
+    fi
+  fi
+  rm -f conftest.m4
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_cv_prog_m4" >&5
+$as_echo "$gmp_cv_prog_m4" >&6; }
+M4="$gmp_cv_prog_m4"
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if m4wrap produces spurious output" >&5
+$as_echo_n "checking if m4wrap produces spurious output... " >&6; }
+if ${gmp_cv_m4_m4wrap_spurious+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  # hide the d-n-l from autoconf's error checking
+tmp_d_n_l=d""nl
+cat >conftest.m4 <<EOF
+changequote({,})define(x,)m4wrap({x})$tmp_d_n_l
+EOF
+echo test input is >&5
+cat conftest.m4 >&5
+tmp_chars=`$M4 conftest.m4 | wc -c`
+echo produces $tmp_chars chars output >&5
+rm -f conftest.m4
+if test $tmp_chars = 0; then
+  gmp_cv_m4_m4wrap_spurious=no
+else
+  gmp_cv_m4_m4wrap_spurious=yes
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_cv_m4_m4wrap_spurious" >&5
+$as_echo "$gmp_cv_m4_m4wrap_spurious" >&6; }
+
+echo "define(<M4WRAP_SPURIOUS>,<$gmp_cv_m4_m4wrap_spurious>)" >> $gmp_tmpconfigm4
+
+
+# else
+# It's unclear why this m4-not-needed stuff was ever done.
+#  if test -z "$M4" ; then
+#    M4=m4-not-needed
+#  fi
+fi
+
+# Only do the GMP_ASM checks if there's a .S or .asm wanting them.
+if test $found_asm = no && test $found_S = no; then
+  gmp_asm_syntax_testing=no
+fi
+
+if test "$gmp_asm_syntax_testing" != no; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to switch to text section" >&5
+$as_echo_n "checking how to switch to text section... " >&6; }
+if ${gmp_cv_asm_text+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  for i in ".text" ".code" ".csect .text[PR]"; do
+  echo "trying $i" >&5
+  cat >conftest.s <<EOF
+	$i
+EOF
+gmp_assemble="$CCAS $CFLAGS $CPPFLAGS conftest.s >conftest.out 2>&1"
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_assemble\""; } >&5
+  (eval $gmp_assemble) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  cat conftest.out >&5
+  gmp_cv_asm_text=$i
+     rm -f conftest*
+     break
+else
+  cat conftest.out >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.s >&5
+  :
+fi
+rm -f conftest*
+
+done
+if test -z "$gmp_cv_asm_text"; then
+  as_fn_error $? "Cannot determine text section directive" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_cv_asm_text" >&5
+$as_echo "$gmp_cv_asm_text" >&6; }
+echo "define(<TEXT>, <$gmp_cv_asm_text>)" >> $gmp_tmpconfigm4
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to switch to data section" >&5
+$as_echo_n "checking how to switch to data section... " >&6; }
+if ${gmp_cv_asm_data+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $host in
+  *-*-aix*) gmp_cv_asm_data=".csect .data[RW]" ;;
+  *)        gmp_cv_asm_data=".data" ;;
+esac
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_cv_asm_data" >&5
+$as_echo "$gmp_cv_asm_data" >&6; }
+echo "define(<DATA>, <$gmp_cv_asm_data>)" >> $gmp_tmpconfigm4
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for assembler label suffix" >&5
+$as_echo_n "checking for assembler label suffix... " >&6; }
+if ${gmp_cv_asm_label_suffix+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  gmp_cv_asm_label_suffix=unknown
+for i in "" ":"; do
+  echo "trying $i" >&5
+  cat >conftest.s <<EOF
+	$gmp_cv_asm_text
+somelabel$i
+EOF
+gmp_assemble="$CCAS $CFLAGS $CPPFLAGS conftest.s >conftest.out 2>&1"
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_assemble\""; } >&5
+  (eval $gmp_assemble) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  cat conftest.out >&5
+  gmp_cv_asm_label_suffix=$i
+     rm -f conftest*
+     break
+else
+  cat conftest.out >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.s >&5
+  cat conftest.out >&5
+fi
+rm -f conftest*
+
+done
+if test "$gmp_cv_asm_label_suffix" = "unknown"; then
+  as_fn_error $? "Cannot determine label suffix" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_cv_asm_label_suffix" >&5
+$as_echo "$gmp_cv_asm_label_suffix" >&6; }
+echo "define(<LABEL_SUFFIX>, <$gmp_cv_asm_label_suffix>)" >> $gmp_tmpconfigm4
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for assembler global directive" >&5
+$as_echo_n "checking for assembler global directive... " >&6; }
+if ${gmp_cv_asm_globl+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $host in
+  hppa*-*-*)     gmp_cv_asm_globl=.export ;;
+  ia64*-*-* | itanium-*-* | itanium2-*-*)  gmp_cv_asm_globl=.global ;;
+  *)             gmp_cv_asm_globl=.globl  ;;
+esac
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_cv_asm_globl" >&5
+$as_echo "$gmp_cv_asm_globl" >&6; }
+echo "define(<GLOBL>, <$gmp_cv_asm_globl>)" >> $gmp_tmpconfigm4
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for assembler global directive attribute" >&5
+$as_echo_n "checking for assembler global directive attribute... " >&6; }
+if ${gmp_cv_asm_globl_attr+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $gmp_cv_asm_globl in
+  .export) gmp_cv_asm_globl_attr=",entry" ;;
+  *)       gmp_cv_asm_globl_attr="" ;;
+esac
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_cv_asm_globl_attr" >&5
+$as_echo "$gmp_cv_asm_globl_attr" >&6; }
+echo "define(<GLOBL_ATTR>, <$gmp_cv_asm_globl_attr>)" >> $gmp_tmpconfigm4
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if globals are prefixed by underscore" >&5
+$as_echo_n "checking if globals are prefixed by underscore... " >&6; }
+if ${gmp_cv_asm_underscore+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  gmp_cv_asm_underscore="unknown"
+cat >conftest.c <<EOF
+int gurkmacka;
+EOF
+gmp_compile="$CC $CFLAGS $CPPFLAGS -c conftest.c >&5"
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  $NM conftest.$OBJEXT >conftest.out
+  if grep "[ 	]_gurkmacka" conftest.out >/dev/null; then
+    gmp_cv_asm_underscore=yes
+  elif grep "[ 	]gurkmacka" conftest.out >/dev/null; then
+    gmp_cv_asm_underscore=no
+  else
+    echo "configure: $NM doesn't have gurkmacka:" >&5
+    cat conftest.out >&5
+  fi
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.c >&5
+fi
+rm -f conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_cv_asm_underscore" >&5
+$as_echo "$gmp_cv_asm_underscore" >&6; }
+case $gmp_cv_asm_underscore in
+  yes)
+
+echo 'define(<GSYM_PREFIX>, <_>)' >>$gmp_tmpconfigm4
+ ;;
+  no)
+
+echo 'define(<GSYM_PREFIX>, <>)' >>$gmp_tmpconfigm4
+ ;;
+  *)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: +----------------------------------------------------------" >&5
+$as_echo "$as_me: WARNING: +----------------------------------------------------------" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: | Cannot determine global symbol prefix." >&5
+$as_echo "$as_me: WARNING: | Cannot determine global symbol prefix." >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: | $NM output doesn't contain a global data symbol." >&5
+$as_echo "$as_me: WARNING: | $NM output doesn't contain a global data symbol." >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: | Will proceed with no underscore." >&5
+$as_echo "$as_me: WARNING: | Will proceed with no underscore." >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: | If this is wrong then you'll get link errors referring" >&5
+$as_echo "$as_me: WARNING: | If this is wrong then you'll get link errors referring" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: | to ___gmpn_add_n (note three underscores)." >&5
+$as_echo "$as_me: WARNING: | to ___gmpn_add_n (note three underscores)." >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: | In this case do a fresh build with an override," >&5
+$as_echo "$as_me: WARNING: | In this case do a fresh build with an override," >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: |     ./configure gmp_cv_asm_underscore=yes" >&5
+$as_echo "$as_me: WARNING: |     ./configure gmp_cv_asm_underscore=yes" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: +----------------------------------------------------------" >&5
+$as_echo "$as_me: WARNING: +----------------------------------------------------------" >&2;}
+
+echo 'define(<GSYM_PREFIX>, <>)' >>$gmp_tmpconfigm4
+
+    ;;
+esac
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to switch to read-only data section" >&5
+$as_echo_n "checking how to switch to read-only data section... " >&6; }
+if ${gmp_cv_asm_rodata+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+case $host in
+i?86*-*-* | k[5-8]*-*-* | pentium*-*-* | athlon-*-* | viac3*-*-* | geode*-*-* | atom-*-* | x86_64-*-*)
+  gmp_cv_asm_rodata="$gmp_cv_asm_data" ;;
+*)
+  gmp_cv_asm_rodata="$gmp_cv_asm_text" ;;
+esac
+
+cat >conftest.c <<EOF
+extern const int foo[];		/* Suppresses C++'s suppression of foo */
+const int foo[] = {1,2,3};
+EOF
+echo "Test program:" >&5
+cat conftest.c >&5
+gmp_compile="$CC $CFLAGS $CPPFLAGS -S conftest.c >&5"
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  echo "Compiler output:" >&5
+  cat conftest.s >&5
+  if test $gmp_cv_asm_underscore = yes; then
+    tmp_gsym_prefix=_
+  else
+    tmp_gsym_prefix=
+  fi
+  # must see our label
+  if grep "^${tmp_gsym_prefix}foo$gmp_cv_asm_label_suffix" conftest.s >/dev/null 2>&5; then
+    # take the last directive before our label (hence skipping segments
+    # getting debugging info etc)
+    tmp_match=`sed -n "/^${tmp_gsym_prefix}foo$gmp_cv_asm_label_suffix/q
+                        /^[. 	]*data/p
+                        /^[. 	]*rdata/p
+                        /^[. 	]*text/p
+                        /^[. 	]*section/p
+                        /^[. 	]*csect/p
+                        /^[. 	]*CSECT/p" conftest.s | sed -n '$p'`
+    echo "Match: $tmp_match" >&5
+    if test -n "$tmp_match"; then
+      gmp_cv_asm_rodata=$tmp_match
+    fi
+  else
+    echo "Couldn't find label: ^${tmp_gsym_prefix}foo$gmp_cv_asm_label_suffix" >&5
+  fi
+fi
+rm -f conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_cv_asm_rodata" >&5
+$as_echo "$gmp_cv_asm_rodata" >&6; }
+echo "define(<RODATA>, <$gmp_cv_asm_rodata>)" >> $gmp_tmpconfigm4
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for assembler .type directive" >&5
+$as_echo_n "checking for assembler .type directive... " >&6; }
+if ${gmp_cv_asm_type+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  gmp_cv_asm_type=
+for gmp_tmp_prefix in @ \# %; do
+  cat >conftest.s <<EOF
+	.type	sym,${gmp_tmp_prefix}function
+EOF
+gmp_assemble="$CCAS $CFLAGS $CPPFLAGS conftest.s >conftest.out 2>&1"
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_assemble\""; } >&5
+  (eval $gmp_assemble) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  cat conftest.out >&5
+  if grep "\.type pseudo-op used outside of \.def/\.endef ignored" conftest.out >/dev/null; then : ;
+    else
+      gmp_cv_asm_type=".type	\$1,${gmp_tmp_prefix}\$2"
+      break
+    fi
+else
+  cat conftest.out >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.s >&5
+  :
+fi
+rm -f conftest*
+
+done
+rm -f conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_cv_asm_type" >&5
+$as_echo "$gmp_cv_asm_type" >&6; }
+echo "define(<TYPE>, <$gmp_cv_asm_type>)" >> $gmp_tmpconfigm4
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for assembler .size directive" >&5
+$as_echo_n "checking for assembler .size directive... " >&6; }
+if ${gmp_cv_asm_size+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  gmp_cv_asm_size=
+cat >conftest.s <<EOF
+	.size	sym,1
+EOF
+gmp_assemble="$CCAS $CFLAGS $CPPFLAGS conftest.s >conftest.out 2>&1"
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_assemble\""; } >&5
+  (eval $gmp_assemble) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  cat conftest.out >&5
+  if grep "\.size pseudo-op used outside of \.def/\.endef ignored" conftest.out >/dev/null; then : ;
+  else
+    gmp_cv_asm_size=".size	\$1,\$2"
+  fi
+else
+  cat conftest.out >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.s >&5
+  :
+fi
+rm -f conftest*
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_cv_asm_size" >&5
+$as_echo "$gmp_cv_asm_size" >&6; }
+echo "define(<SIZE>, <$gmp_cv_asm_size>)" >> $gmp_tmpconfigm4
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for assembler local label prefix" >&5
+$as_echo_n "checking for assembler local label prefix... " >&6; }
+if ${gmp_cv_asm_lsym_prefix+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  gmp_tmp_pre_appears=yes
+for gmp_tmp_pre in L .L $L $ L$; do
+  echo "Trying $gmp_tmp_pre" >&5
+  cat >conftest.s <<EOF
+	$gmp_cv_asm_text
+dummy${gmp_cv_asm_label_suffix}
+${gmp_tmp_pre}gurkmacka${gmp_cv_asm_label_suffix}
+EOF
+gmp_assemble="$CCAS $CFLAGS $CPPFLAGS conftest.s >conftest.out 2>&1"
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_assemble\""; } >&5
+  (eval $gmp_assemble) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  cat conftest.out >&5
+  if $NM conftest.$OBJEXT >conftest.nm 2>&5; then : ; else
+    cat conftest.nm >&5
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \"$NM\" failure" >&5
+$as_echo "$as_me: WARNING: \"$NM\" failure" >&2;}
+    break
+  fi
+  cat conftest.nm >&5
+  if grep gurkmacka conftest.nm >/dev/null; then : ; else
+    # no mention of the symbol, this is good
+    echo "$gmp_tmp_pre label doesn't appear in object file at all (good)" >&5
+    gmp_cv_asm_lsym_prefix="$gmp_tmp_pre"
+    gmp_tmp_pre_appears=no
+    break
+  fi
+  if grep ' [a-zN] .*gurkmacka' conftest.nm >/dev/null; then
+    # symbol mentioned as a local, use this if nothing better
+    echo "$gmp_tmp_pre label is local but still in object file" >&5
+    if test -z "$gmp_cv_asm_lsym_prefix"; then
+      gmp_cv_asm_lsym_prefix="$gmp_tmp_pre"
+    fi
+  else
+    echo "$gmp_tmp_pre label is something unknown" >&5
+  fi
+
+else
+  cat conftest.out >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.s >&5
+  :
+fi
+rm -f conftest*
+
+done
+rm -f conftest*
+if test -z "$gmp_cv_asm_lsym_prefix"; then
+  gmp_cv_asm_lsym_prefix=L
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cannot determine local label, using default $gmp_cv_asm_lsym_prefix" >&5
+$as_echo "$as_me: WARNING: cannot determine local label, using default $gmp_cv_asm_lsym_prefix" >&2;}
+fi
+# for development purposes, note whether we got a purely temporary local label
+echo "Local label appears in object files: $gmp_tmp_pre_appears" >&5
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_cv_asm_lsym_prefix" >&5
+$as_echo "$gmp_cv_asm_lsym_prefix" >&6; }
+echo "define(<LSYM_PREFIX>, <${gmp_cv_asm_lsym_prefix}>)" >> $gmp_tmpconfigm4
+
+cat >>confdefs.h <<_ACEOF
+#define LSYM_PREFIX "$gmp_cv_asm_lsym_prefix"
+_ACEOF
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for assembler byte directive" >&5
+$as_echo_n "checking for assembler byte directive... " >&6; }
+if ${gmp_cv_asm_byte+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  for i in .byte data1; do
+  echo "trying $i" >&5
+  cat >conftest.s <<EOF
+	$gmp_cv_asm_data
+	$i	0
+
+EOF
+gmp_assemble="$CCAS $CFLAGS $CPPFLAGS conftest.s >conftest.out 2>&1"
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_assemble\""; } >&5
+  (eval $gmp_assemble) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  cat conftest.out >&5
+  gmp_cv_asm_byte=$i
+     rm -f conftest*
+     break
+else
+  cat conftest.out >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.s >&5
+  cat conftest.out >&5
+fi
+rm -f conftest*
+
+done
+if test -z "$gmp_cv_asm_byte"; then
+  as_fn_error $? "Cannot determine how to emit a data byte" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_cv_asm_byte" >&5
+$as_echo "$gmp_cv_asm_byte" >&6; }
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to define a 32-bit word" >&5
+$as_echo_n "checking how to define a 32-bit word... " >&6; }
+if ${gmp_cv_asm_w32+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $host in
+  *-*-hpux*)
+    # FIXME: HPUX puts first symbol at 0x40000000, breaking our assumption
+    # that it's at 0x0.  We'll have to declare another symbol before the
+    # .long/.word and look at the distance between the two symbols.  The
+    # only problem is that the sed expression(s) barfs (on Solaris, for
+    # example) for the symbol with value 0.  For now, HPUX uses .word.
+    gmp_cv_asm_w32=".word"
+    ;;
+  *-*-*)
+    gmp_tmp_val=
+    for gmp_tmp_op in .long .word data4; do
+      cat >conftest.s <<EOF
+	$gmp_cv_asm_data
+	$gmp_cv_asm_globl	foo
+	$gmp_tmp_op	0
+foo$gmp_cv_asm_label_suffix
+	$gmp_cv_asm_byte	0
+EOF
+gmp_assemble="$CCAS $CFLAGS $CPPFLAGS conftest.s >conftest.out 2>&1"
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_assemble\""; } >&5
+  (eval $gmp_assemble) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  cat conftest.out >&5
+  gmp_tmp_val=`$NM conftest.$OBJEXT | grep foo | \
+          sed -e 's;[[][0-9][]]\(.*\);\1;' -e 's;[^1-9]*\([0-9]*\).*;\1;'`
+        if test "$gmp_tmp_val" = 4; then
+          gmp_cv_asm_w32="$gmp_tmp_op"
+          break
+        fi
+else
+  cat conftest.out >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.s >&5
+  :
+fi
+rm -f conftest*
+
+    done
+    rm -f conftest*
+    ;;
+esac
+if test -z "$gmp_cv_asm_w32"; then
+  as_fn_error $? "cannot determine how to define a 32-bit word" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_cv_asm_w32" >&5
+$as_echo "$gmp_cv_asm_w32" >&6; }
+echo "define(<W32>, <$gmp_cv_asm_w32>)" >> $gmp_tmpconfigm4
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if .align assembly directive is logarithmic" >&5
+$as_echo_n "checking if .align assembly directive is logarithmic... " >&6; }
+if ${gmp_cv_asm_align_log+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.s <<EOF
+	$gmp_cv_asm_data
+	.align  4
+	$gmp_cv_asm_globl	foo
+	$gmp_cv_asm_byte	1
+	.align	4
+foo$gmp_cv_asm_label_suffix
+	$gmp_cv_asm_byte	2
+EOF
+gmp_assemble="$CCAS $CFLAGS $CPPFLAGS conftest.s >conftest.out 2>&1"
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_assemble\""; } >&5
+  (eval $gmp_assemble) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  cat conftest.out >&5
+  gmp_tmp_val=`$NM conftest.$OBJEXT | grep foo | \
+     sed -e 's;[[][0-9][]]\(.*\);\1;' -e 's;[^1-9]*\([0-9]*\).*;\1;'`
+  if test "$gmp_tmp_val" = "10" || test "$gmp_tmp_val" = "16"; then
+    gmp_cv_asm_align_log=yes
+  else
+    gmp_cv_asm_align_log=no
+  fi
+else
+  cat conftest.out >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.s >&5
+  as_fn_error $? "cannot assemble alignment test" "$LINENO" 5
+fi
+rm -f conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_cv_asm_align_log" >&5
+$as_echo "$gmp_cv_asm_align_log" >&6; }
+
+
+echo "define(<ALIGN_LOGARITHMIC>,<$gmp_cv_asm_align_log>)" >> $gmp_tmpconfigm4
+
+
+
+  case $host in
+    arm*-*-* | aarch64*-*-*)
+      case $ABI in
+        32)
+
+echo "include_mpn(\`arm/arm-defs.m4')" >> $gmp_tmpconfigm4i
+ ;;
+      esac
+      ;;
+    hppa*-*-*)
+      # for both pa32 and pa64
+
+echo "include_mpn(\`pa32/pa-defs.m4')" >> $gmp_tmpconfigm4i
+
+      ;;
+    ia64*-*-* | itanium-*-* | itanium2-*-*)
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether assembler .align padding is good" >&5
+$as_echo_n "checking whether assembler .align padding is good... " >&6; }
+if ${gmp_cv_asm_ia64_align_ok+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.awk <<\EOF
+BEGIN {
+  want[0]  = "011"
+  want[1]  = "160"
+  want[2]  = "074"
+  want[3]  = "040"
+  want[4]  = "000"
+  want[5]  = "040"
+  want[6]  = "020"
+  want[7]  = "221"
+  want[8]  = "114"
+  want[9]  = "000"
+  want[10] = "100"
+  want[11] = "200"
+  want[12] = "122"
+  want[13] = "261"
+  want[14] = "000"
+  want[15] = "200"
+
+  want[16] = "000"
+  want[17] = "004"
+  want[18] = "000"
+  want[19] = "000"
+  want[20] = "000"
+  want[21] = "000"
+  want[22] = "002"
+  want[23] = "000"
+  want[24] = "000"
+  want[25] = "000"
+  want[26] = "000"
+  want[27] = "001"
+  want[28] = "000"
+  want[29] = "000"
+  want[30] = "000"
+  want[31] = "014"
+
+  want[32] = "011"
+  want[33] = "270"
+  want[34] = "140"
+  want[35] = "062"
+  want[36] = "000"
+  want[37] = "040"
+  want[38] = "240"
+  want[39] = "331"
+  want[40] = "160"
+  want[41] = "000"
+  want[42] = "100"
+  want[43] = "240"
+  want[44] = "343"
+  want[45] = "371"
+  want[46] = "000"
+  want[47] = "200"
+
+  result = "yes"
+}
+{
+  for (f = 2; f <= NF; f++)
+    {
+      for (i = 0; i < 47; i++)
+        got[i] = got[i+1];
+      got[47] = $f;
+
+      found = 1
+      for (i = 0; i < 48; i++)
+        if (got[i] != want[i])
+          {
+            found = 0
+            break
+          }
+      if (found)
+        {
+          result = "no"
+          exit
+        }
+    }
+}
+END {
+  print result
+}
+EOF
+cat >conftest.s <<EOF
+	.text
+	.align	32
+{ .mmi;	add	r14 = r15, r16
+	add	r17 = r18, r19
+	add	r20 = r21, r22 ;; }
+	.align	32
+{ .mmi;	add	r23 = r24, r25
+	add	r26 = r27, r28
+	add	r29 = r30, r31 ;; }
+
+EOF
+gmp_assemble="$CCAS $CFLAGS $CPPFLAGS conftest.s >conftest.out 2>&1"
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_assemble\""; } >&5
+  (eval $gmp_assemble) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  cat conftest.out >&5
+  gmp_cv_asm_ia64_align_ok=`od -b conftest.$OBJEXT | $AWK -f conftest.awk`
+else
+  cat conftest.out >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.s >&5
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: oops, cannot compile test program" >&5
+$as_echo "$as_me: WARNING: oops, cannot compile test program" >&2;}
+   gmp_cv_asm_ia64_align_ok=yes
+fi
+rm -f conftest*
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_cv_asm_ia64_align_ok" >&5
+$as_echo "$gmp_cv_asm_ia64_align_ok" >&6; }
+
+echo "define(<IA64_ALIGN_OK>, <\`$gmp_cv_asm_ia64_align_ok'>)" >> $gmp_tmpconfigm4
+
+
+      ;;
+    m68k-*-* | m68[0-9][0-9][0-9]-*-*)
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler instruction and register style" >&5
+$as_echo_n "checking assembler instruction and register style... " >&6; }
+if ${gmp_cv_asm_m68k_instruction+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  for i in "addl %d0,%d1" "add.l %d0,%d1" "addl d0,d1" "add.l d0,d1"; do
+  cat >conftest.s <<EOF
+	$gmp_cv_asm_text
+	$i
+EOF
+gmp_assemble="$CCAS $CFLAGS $CPPFLAGS conftest.s >conftest.out 2>&1"
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_assemble\""; } >&5
+  (eval $gmp_assemble) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  cat conftest.out >&5
+  gmp_cv_asm_m68k_instruction=$i
+    rm -f conftest*
+    break
+else
+  cat conftest.out >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.s >&5
+  :
+fi
+rm -f conftest*
+
+done
+if test -z "$gmp_cv_asm_m68k_instruction"; then
+  as_fn_error $? "cannot determine assembler instruction and register style" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_cv_asm_m68k_instruction" >&5
+$as_echo "$gmp_cv_asm_m68k_instruction" >&6; }
+case $gmp_cv_asm_m68k_instruction in
+"addl d0,d1")    want_dot_size=no;  want_register_percent=no  ;;
+"addl %d0,%d1")  want_dot_size=no;  want_register_percent=yes ;;
+"add.l d0,d1")   want_dot_size=yes; want_register_percent=no  ;;
+"add.l %d0,%d1") want_dot_size=yes; want_register_percent=yes ;;
+*) as_fn_error $? "oops, unrecognised instruction and register style" "$LINENO" 5 ;;
+esac
+
+echo "define(<WANT_REGISTER_PERCENT>, <\`$want_register_percent'>)" >> $gmp_tmpconfigm4
+
+
+echo "define(<WANT_DOT_SIZE>, <\`$want_dot_size'>)" >> $gmp_tmpconfigm4
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler addressing style" >&5
+$as_echo_n "checking assembler addressing style... " >&6; }
+if ${gmp_cv_asm_m68k_addressing+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $gmp_cv_asm_m68k_instruction in
+addl*)  movel=movel ;;
+add.l*) movel=move.l ;;
+*) as_fn_error $? "oops, unrecognised gmp_cv_asm_m68k_instruction" "$LINENO" 5 ;;
+esac
+case $gmp_cv_asm_m68k_instruction in
+*"%d0,%d1") dreg=%d0; areg=%a0 ;;
+*"d0,d1")   dreg=d0;  areg=a0  ;;
+*) as_fn_error $? "oops, unrecognised gmp_cv_asm_m68k_instruction" "$LINENO" 5 ;;
+esac
+cat >conftest.s <<EOF
+	$gmp_cv_asm_text
+	$movel	$dreg, $areg@-
+EOF
+gmp_assemble="$CCAS $CFLAGS $CPPFLAGS conftest.s >conftest.out 2>&1"
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_assemble\""; } >&5
+  (eval $gmp_assemble) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  cat conftest.out >&5
+  gmp_cv_asm_m68k_addressing=mit
+else
+  cat conftest.out >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.s >&5
+  cat >conftest.s <<EOF
+	$gmp_cv_asm_text
+	$movel	$dreg, -($areg)
+EOF
+gmp_assemble="$CCAS $CFLAGS $CPPFLAGS conftest.s >conftest.out 2>&1"
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_assemble\""; } >&5
+  (eval $gmp_assemble) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  cat conftest.out >&5
+  gmp_cv_asm_m68k_addressing=motorola
+else
+  cat conftest.out >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.s >&5
+  as_fn_error $? "cannot determine assembler addressing style" "$LINENO" 5
+fi
+rm -f conftest*
+
+fi
+rm -f conftest*
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_cv_asm_m68k_addressing" >&5
+$as_echo "$gmp_cv_asm_m68k_addressing" >&6; }
+
+echo "define(<WANT_ADDRESSING>, <\`$gmp_cv_asm_m68k_addressing'>)" >> $gmp_tmpconfigm4
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler shortest branches" >&5
+$as_echo_n "checking assembler shortest branches... " >&6; }
+if ${gmp_cv_asm_m68k_branches+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  for i in jra jbra bra; do
+  cat >conftest.s <<EOF
+	$gmp_cv_asm_text
+foo$gmp_cv_asm_label_suffix
+	$i	foo
+EOF
+gmp_assemble="$CCAS $CFLAGS $CPPFLAGS conftest.s >conftest.out 2>&1"
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_assemble\""; } >&5
+  (eval $gmp_assemble) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  cat conftest.out >&5
+  gmp_cv_asm_m68k_branches=$i
+  rm -f conftest*
+  break
+else
+  cat conftest.out >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.s >&5
+  :
+fi
+rm -f conftest*
+
+done
+if test -z "$gmp_cv_asm_m68k_branches"; then
+  as_fn_error $? "cannot determine assembler branching style" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_cv_asm_m68k_branches" >&5
+$as_echo "$gmp_cv_asm_m68k_branches" >&6; }
+
+echo "define(<WANT_BRANCHES>, <\`$gmp_cv_asm_m68k_branches'>)" >> $gmp_tmpconfigm4
+
+
+      ;;
+    powerpc*-*-* | power[3-9]-*-*)
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler output is PIC by default" >&5
+$as_echo_n "checking whether compiler output is PIC by default... " >&6; }
+if ${gmp_cv_asm_powerpc_pic+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  gmp_cv_asm_powerpc_pic=yes
+cat >conftest.c <<EOF
+int foo;
+int *bar() { return &foo; }
+EOF
+echo "Test program:" >&5
+cat conftest.c >&5
+gmp_compile="$CC $CFLAGS $CPPFLAGS -S conftest.c >&5"
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  echo "Compiler output:" >&5
+  cat conftest.s >&5
+  if grep 'foo@ha' conftest.s >/dev/null 2>&5; then
+    gmp_cv_asm_powerpc_pic=no
+  fi
+  if grep 'ha16(_foo)' conftest.s >/dev/null 2>&5; then
+    gmp_cv_asm_powerpc_pic=no
+  fi
+fi
+rm -f conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_cv_asm_powerpc_pic" >&5
+$as_echo "$gmp_cv_asm_powerpc_pic" >&6; }
+
+echo "define(<PIC_ALWAYS>,<$gmp_cv_asm_powerpc_pic>)" >> $gmp_tmpconfigm4
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the assembler needs r on registers" >&5
+$as_echo_n "checking if the assembler needs r on registers... " >&6; }
+if ${gmp_cv_asm_powerpc_r_registers+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.s <<EOF
+	$gmp_cv_asm_text
+	mtctr	6
+EOF
+gmp_assemble="$CCAS $CFLAGS $CPPFLAGS conftest.s >conftest.out 2>&1"
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_assemble\""; } >&5
+  (eval $gmp_assemble) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  cat conftest.out >&5
+  gmp_cv_asm_powerpc_r_registers=no
+else
+  cat conftest.out >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.s >&5
+  cat >conftest.s <<EOF
+	$gmp_cv_asm_text
+	mtctr	r6
+EOF
+gmp_assemble="$CCAS $CFLAGS $CPPFLAGS conftest.s >conftest.out 2>&1"
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_assemble\""; } >&5
+  (eval $gmp_assemble) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  cat conftest.out >&5
+  gmp_cv_asm_powerpc_r_registers=yes
+else
+  cat conftest.out >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.s >&5
+  as_fn_error $? "neither \"mtctr 6\" nor \"mtctr r6\" works" "$LINENO" 5
+fi
+rm -f conftest*
+
+fi
+rm -f conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_cv_asm_powerpc_r_registers" >&5
+$as_echo "$gmp_cv_asm_powerpc_r_registers" >&6; }
+
+
+echo "define(<WANT_R_REGISTERS>,<$gmp_cv_asm_powerpc_r_registers>)" >> $gmp_tmpconfigm4
+
+
+
+echo "include_mpn(\`powerpc32/powerpc-defs.m4')" >> $gmp_tmpconfigm4i
+
+
+      # Check for Linux ELFv1 ABI
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#if _CALL_ELF == 1
+yes
+#endif
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "yes" >/dev/null 2>&1; then :
+
+echo "define(<ELFv1_ABI>)" >> $gmp_tmpconfigm4
+
+fi
+rm -f conftest*
+
+
+      # Check for Linux ELFv2 ABI
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#if _CALL_ELF == 2
+yes
+#endif
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "yes" >/dev/null 2>&1; then :
+
+echo "define(<ELFv2_ABI>)" >> $gmp_tmpconfigm4
+
+fi
+rm -f conftest*
+
+
+      case $host in
+        *-*-aix*)
+	  case $ABI in
+	    mode64)
+echo "include_mpn(\`powerpc64/aix.m4')" >> $gmp_tmpconfigm4i
+ ;;
+            *)
+echo "include_mpn(\`powerpc32/aix.m4')" >> $gmp_tmpconfigm4i
+ ;;
+          esac
+          ;;
+        *-*-linux* | *-*-*bsd*)
+	  case $ABI in
+	    mode64)
+echo "include_mpn(\`powerpc64/elf.m4')" >> $gmp_tmpconfigm4i
+ ;;
+	    mode32 | 32)
+echo "include_mpn(\`powerpc32/elf.m4')" >> $gmp_tmpconfigm4i
+ ;;
+          esac
+          ;;
+        *-*-darwin*)
+	  case $ABI in
+	    mode64)
+echo "include_mpn(\`powerpc64/darwin.m4')" >> $gmp_tmpconfigm4i
+ ;;
+	    mode32 | 32)
+echo "include_mpn(\`powerpc32/darwin.m4')" >> $gmp_tmpconfigm4i
+ ;;
+          esac
+          ;;
+        *)
+	  # Assume unrecognized operating system is the powerpc eABI
+
+echo "include_mpn(\`powerpc32/eabi.m4')" >> $gmp_tmpconfigm4i
+
+	  ;;
+      esac
+      ;;
+    power*-*-aix*)
+
+echo "include_mpn(\`powerpc32/aix.m4')" >> $gmp_tmpconfigm4i
+
+      ;;
+    *sparc*-*-*)
+      case $ABI in
+        64)
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the assembler accepts \".register\"" >&5
+$as_echo_n "checking if the assembler accepts \".register\"... " >&6; }
+if ${gmp_cv_asm_sparc_register+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.s <<EOF
+	$gmp_cv_asm_text
+	.register	%g2,#scratch
+
+EOF
+gmp_assemble="$CCAS $CFLAGS $CPPFLAGS conftest.s >conftest.out 2>&1"
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_assemble\""; } >&5
+  (eval $gmp_assemble) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  cat conftest.out >&5
+  gmp_cv_asm_sparc_register=yes
+else
+  cat conftest.out >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.s >&5
+  gmp_cv_asm_sparc_register=no
+fi
+rm -f conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_cv_asm_sparc_register" >&5
+$as_echo "$gmp_cv_asm_sparc_register" >&6; }
+
+
+echo "define(<HAVE_REGISTER>,<$gmp_cv_asm_sparc_register>)" >> $gmp_tmpconfigm4
+
+
+          ;;
+      esac
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the assembler accepts gotdata relocations" >&5
+$as_echo_n "checking if the assembler accepts gotdata relocations... " >&6; }
+if ${gmp_cv_asm_sparc_gotdata+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.s <<EOF
+	$gmp_cv_asm_text
+	.text
+	sethi	%gdop_hix22(symbol), %g1
+	or	%g1, %gdop_lox10(symbol), %g1
+
+EOF
+gmp_assemble="$CCAS $CFLAGS $CPPFLAGS conftest.s >conftest.out 2>&1"
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_assemble\""; } >&5
+  (eval $gmp_assemble) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  cat conftest.out >&5
+  gmp_cv_asm_sparc_gotdata=yes
+else
+  cat conftest.out >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.s >&5
+  gmp_cv_asm_sparc_gotdata=no
+fi
+rm -f conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_cv_asm_sparc_gotdata" >&5
+$as_echo "$gmp_cv_asm_sparc_gotdata" >&6; }
+
+
+echo "define(<HAVE_GOTDATA>,<$gmp_cv_asm_sparc_gotdata>)" >> $gmp_tmpconfigm4
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the assembler can support shared PIC thunks" >&5
+$as_echo_n "checking if the assembler can support shared PIC thunks... " >&6; }
+if ${gmp_cv_asm_sparc_shared_thunks+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.s <<EOF
+	$gmp_cv_asm_text
+	.section	.text.__sparc_get_pc_thunk.l7,"axG",@progbits,__sparc_get_pc_thunk.l7,comdat
+	.weak	__sparc_get_pc_thunk.l7
+	.hidden	__sparc_get_pc_thunk.l7
+	.type	__sparc_get_pc_thunk.l7, #function
+__sparc_get_pc_thunk.l7:
+	jmp	%o7+8
+	 add	%o7, %l7, %l7
+
+EOF
+gmp_assemble="$CCAS $CFLAGS $CPPFLAGS conftest.s >conftest.out 2>&1"
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_assemble\""; } >&5
+  (eval $gmp_assemble) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  cat conftest.out >&5
+  gmp_cv_asm_sparc_shared_thunks=yes
+else
+  cat conftest.out >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.s >&5
+  gmp_cv_asm_sparc_shared_thunks=no
+fi
+rm -f conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_cv_asm_sparc_shared_thunks" >&5
+$as_echo "$gmp_cv_asm_sparc_shared_thunks" >&6; }
+
+
+echo "define(<HAVE_SHARED_THUNKS>,<$gmp_cv_asm_sparc_shared_thunks>)" >> $gmp_tmpconfigm4
+
+
+      ;;
+    i?86*-*-* | k[5-8]*-*-* | pentium*-*-* | athlon-*-* | viac3*-*-* | geode*-*-* | atom-*-* | athlon64-*-* | k8-*-* | k10-*-* | bobcat-*-* | jaguar*-*-* | bulldozer*-*-* | piledriver*-*-* | steamroller*-*-* | excavator*-*-* | zen*-*-* | pentium4-*-* | atom-*-* | silvermont-*-* | goldmont-*-* | core2-*-* | corei*-*-* | x86_64-*-* | nano-*-* | nehalem*-*-* | westmere*-*-* | sandybridge*-*-* | ivybridge*-*-* | haswell*-*-* | broadwell*-*-* | skylake*-*-* | kabylake*-*-*)
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the .align directive accepts an 0x90 fill in .text" >&5
+$as_echo_n "checking if the .align directive accepts an 0x90 fill in .text... " >&6; }
+if ${gmp_cv_asm_align_fill_0x90+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.s <<EOF
+	$gmp_cv_asm_text
+	.align  4, 0x90
+	.byte   0
+	.align  4, 0x90
+EOF
+gmp_assemble="$CCAS $CFLAGS $CPPFLAGS conftest.s >conftest.out 2>&1"
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_assemble\""; } >&5
+  (eval $gmp_assemble) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  cat conftest.out >&5
+  if grep "Warning: Fill parameter ignored for executable section" conftest.out >/dev/null; then
+  echo "Suppressing this warning by omitting 0x90" 1>&5
+  gmp_cv_asm_align_fill_0x90=no
+else
+  gmp_cv_asm_align_fill_0x90=yes
+fi
+else
+  cat conftest.out >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.s >&5
+  gmp_cv_asm_align_fill_0x90=no
+fi
+rm -f conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_cv_asm_align_fill_0x90" >&5
+$as_echo "$gmp_cv_asm_align_fill_0x90" >&6; }
+
+
+echo "define(<ALIGN_FILL_0x90>,<$gmp_cv_asm_align_fill_0x90>)" >> $gmp_tmpconfigm4
+
+
+      if test "$x86_have_mulx" = yes; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the assembler knows about the mulx instruction" >&5
+$as_echo_n "checking if the assembler knows about the mulx instruction... " >&6; }
+if ${gmp_cv_asm_x86_mulx+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.s <<EOF
+	.text
+	mulx	%r8, %r9, %r10
+EOF
+gmp_assemble="$CCAS $CFLAGS $CPPFLAGS conftest.s >conftest.out 2>&1"
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_assemble\""; } >&5
+  (eval $gmp_assemble) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  cat conftest.out >&5
+  gmp_cv_asm_x86_mulx=yes
+else
+  cat conftest.out >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.s >&5
+  gmp_cv_asm_x86_mulx=no
+fi
+rm -f conftest*
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_cv_asm_x86_mulx" >&5
+$as_echo "$gmp_cv_asm_x86_mulx" >&6; }
+case $gmp_cv_asm_x86_mulx in
+yes)
+
+$as_echo "#define X86_ASM_MULX 1" >>confdefs.h
+
+  :
+  ;;
+*)
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: +----------------------------------------------------------" >&5
+$as_echo "$as_me: WARNING: +----------------------------------------------------------" >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: | WARNING WARNING WARNING" >&5
+$as_echo "$as_me: WARNING: | WARNING WARNING WARNING" >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: | Host CPU has the mulx instruction, but it can't be" >&5
+$as_echo "$as_me: WARNING: | Host CPU has the mulx instruction, but it can't be" >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: | assembled by" >&5
+$as_echo "$as_me: WARNING: | assembled by" >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: |     $CCAS $CFLAGS $CPPFLAGS" >&5
+$as_echo "$as_me: WARNING: |     $CCAS $CFLAGS $CPPFLAGS" >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: | Older x86 instructions will be used." >&5
+$as_echo "$as_me: WARNING: | Older x86 instructions will be used." >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: | This will be an inferior build." >&5
+$as_echo "$as_me: WARNING: | This will be an inferior build." >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: +----------------------------------------------------------" >&5
+$as_echo "$as_me: WARNING: +----------------------------------------------------------" >&2;}
+  :
+  ;;
+esac
+
+      fi
+      case $ABI in
+        32)
+
+echo "include_mpn(\`x86/x86-defs.m4')" >> $gmp_tmpconfigm4i
+
+          $as_echo "#define HAVE_HOST_CPU_FAMILY_x86 1" >>confdefs.h
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for assembler COFF type directives" >&5
+$as_echo_n "checking for assembler COFF type directives... " >&6; }
+if ${gmp_cv_asm_x86_coff_type+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.s <<EOF
+	$gmp_cv_asm_text
+	$gmp_cv_asm_globl ${tmp_gsym_prefix}foo$gmp_cv_asm_globl_attr
+	.def	${tmp_gsym_prefix}foo
+	.scl	2
+	.type	32
+	.endef
+${tmp_gsym_prefix}foo$gmp_cv_asm_label_suffix
+
+EOF
+gmp_assemble="$CCAS $CFLAGS $CPPFLAGS conftest.s >conftest.out 2>&1"
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_assemble\""; } >&5
+  (eval $gmp_assemble) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  cat conftest.out >&5
+  gmp_cv_asm_x86_coff_type=yes
+else
+  cat conftest.out >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.s >&5
+  gmp_cv_asm_x86_coff_type=no
+fi
+rm -f conftest*
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_cv_asm_x86_coff_type" >&5
+$as_echo "$gmp_cv_asm_x86_coff_type" >&6; }
+echo "define(<HAVE_COFF_TYPE>, <$gmp_cv_asm_x86_coff_type>)" >> $gmp_tmpconfigm4
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if _GLOBAL_OFFSET_TABLE_ is prefixed by underscore" >&5
+$as_echo_n "checking if _GLOBAL_OFFSET_TABLE_ is prefixed by underscore... " >&6; }
+if ${gmp_cv_asm_x86_got_underscore+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  gmp_cv_asm_x86_got_underscore="not applicable"
+if test $gmp_cv_asm_underscore = yes; then
+  tmp_gsym_prefix=_
+else
+  tmp_gsym_prefix=
+fi
+for tmp_underscore in "" "_"; do
+  cat >conftest.s <<EOF
+	$gmp_cv_asm_text
+	$gmp_cv_asm_globl ${tmp_gsym_prefix}main$gmp_cv_asm_globl_attr
+${tmp_gsym_prefix}main$gmp_cv_asm_label_suffix
+	addl	$ ${tmp_underscore}_GLOBAL_OFFSET_TABLE_, %ebx
+EOF
+  gmp_compile="$CCAS $CFLAGS $CPPFLAGS $lt_prog_compiler_pic conftest.s >&5 && $CC $CFLAGS $CPPFLAGS $lt_prog_compiler_pic conftest.$OBJEXT >&5"
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_compile\""; } >&5
+  (eval $gmp_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    if test "$tmp_underscore" = "_"; then
+      gmp_cv_asm_x86_got_underscore=yes
+    else
+      gmp_cv_asm_x86_got_underscore=no
+    fi
+    break
+  fi
+done
+rm -f conftest* a.out b.out a.exe a_out.exe
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_cv_asm_x86_got_underscore" >&5
+$as_echo "$gmp_cv_asm_x86_got_underscore" >&6; }
+if test "$gmp_cv_asm_x86_got_underscore" = "yes"; then
+
+echo 'define(<GOT_GSYM_PREFIX>, <_>)' >>$gmp_tmpconfigm4
+
+else
+
+echo 'define(<GOT_GSYM_PREFIX>, <>)' >>$gmp_tmpconfigm4
+
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the assembler takes cl with shldl" >&5
+$as_echo_n "checking if the assembler takes cl with shldl... " >&6; }
+if ${gmp_cv_asm_x86_shldl_cl+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.s <<EOF
+	$gmp_cv_asm_text
+	shldl	%cl, %eax, %ebx
+EOF
+gmp_assemble="$CCAS $CFLAGS $CPPFLAGS conftest.s >conftest.out 2>&1"
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_assemble\""; } >&5
+  (eval $gmp_assemble) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  cat conftest.out >&5
+  gmp_cv_asm_x86_shldl_cl=yes
+else
+  cat conftest.out >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.s >&5
+  gmp_cv_asm_x86_shldl_cl=no
+fi
+rm -f conftest*
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmp_cv_asm_x86_shldl_cl" >&5
+$as_echo "$gmp_cv_asm_x86_shldl_cl" >&6; }
+if test "$gmp_cv_asm_x86_shldl_cl" = "yes"; then
+
+echo 'define(<WANT_SHLDL_CL>, <1>)' >>$gmp_tmpconfigm4
+
+else
+
+echo 'define(<WANT_SHLDL_CL>, <0>)' >>$gmp_tmpconfigm4
+
+fi
+
+	  case $enable_profiling in
+	    prof | gprof)  # Check whether --enable-shared was given.
+if test "${enable_shared+set}" = set; then :
+  enableval=$enable_shared; p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_shared=yes ;;
+    no) enable_shared=no ;;
+    *)
+      enable_shared=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
+      for pkg in $enableval; do
+	IFS=$lt_save_ifs
+	if test "X$pkg" = "X$p"; then
+	  enable_shared=yes
+	fi
+      done
+      IFS=$lt_save_ifs
+      ;;
+    esac
+else
+  enable_shared=yes
+fi
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to call x86 mcount" >&5
+$as_echo_n "checking how to call x86 mcount... " >&6; }
+cat >conftest.c <<EOF
+foo(){bar();}
+EOF
+
+if test "$enable_static" = yes; then
+  gmp_asmout_compile="$CC $CFLAGS $CPPFLAGS -S conftest.c 1>&5"
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_asmout_compile\""; } >&5
+  (eval $gmp_asmout_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    if grep '\.data' conftest.s >/dev/null; then
+      mcount_nonpic_reg=`sed -n '/esp/!s/.*movl.*,\(%[a-z]*\).*$/\1/p' conftest.s`
+    else
+      mcount_nonpic_reg=
+    fi
+    mcount_nonpic_call=`grep 'call.*mcount' conftest.s`
+    if test -z "$mcount_nonpic_call"; then
+      as_fn_error $? "Cannot find mcount call for non-PIC" "$LINENO" 5
+    fi
+  else
+    as_fn_error $? "Cannot compile test program for non-PIC" "$LINENO" 5
+  fi
+fi
+
+if test "$enable_shared" = yes; then
+  gmp_asmout_compile="$CC $CFLAGS $CPPFLAGS $lt_prog_compiler_pic -S conftest.c 1>&5"
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$gmp_asmout_compile\""; } >&5
+  (eval $gmp_asmout_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    if grep '\.data' conftest.s >/dev/null; then
+      case $lt_prog_compiler_pic in
+        *-DDLL_EXPORT*)
+          # Windows DLLs have non-PIC style mcount
+          mcount_pic_reg=`sed -n '/esp/!s/.*movl.*,\(%[a-z]*\).*$/\1/p' conftest.s`
+          ;;
+        *)
+          mcount_pic_reg=`sed -n 's/.*GOTOFF.*,\(%[a-z]*\).*$/\1/p' conftest.s`
+          ;;
+      esac
+    else
+      mcount_pic_reg=
+    fi
+    mcount_pic_call=`grep 'call.*mcount' conftest.s`
+    if test -z "$mcount_pic_call"; then
+      as_fn_error $? "Cannot find mcount call for PIC" "$LINENO" 5
+    fi
+  else
+    as_fn_error $? "Cannot compile test program for PIC" "$LINENO" 5
+  fi
+fi
+
+
+echo "define(<MCOUNT_NONPIC_REG>, <\`$mcount_nonpic_reg'>)" >> $gmp_tmpconfigm4
+
+
+echo "define(<MCOUNT_NONPIC_CALL>,<\`$mcount_nonpic_call'>)" >> $gmp_tmpconfigm4
+
+
+echo "define(<MCOUNT_PIC_REG>,    <\`$mcount_pic_reg'>)" >> $gmp_tmpconfigm4
+
+
+echo "define(<MCOUNT_PIC_CALL>,   <\`$mcount_pic_call'>)" >> $gmp_tmpconfigm4
+
+
+rm -f conftest.*
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: determined" >&5
+$as_echo "determined" >&6; }
+ ;;
+	  esac
+	  case $host in
+	    *-*-darwin*)
+
+echo "include_mpn(\`x86/darwin.m4')" >> $gmp_tmpconfigm4i
+ ;;
+	  esac
+          ;;
+        64|x32)
+
+echo "include_mpn(\`x86_64/x86_64-defs.m4')" >> $gmp_tmpconfigm4i
+
+          $as_echo "#define HAVE_HOST_CPU_FAMILY_x86_64 1" >>confdefs.h
+
+	  case $host in
+	    *-*-darwin*)
+
+echo "include_mpn(\`x86_64/darwin.m4')" >> $gmp_tmpconfigm4i
+ ;;
+	    *-*-mingw* | *-*-cygwin)
+
+echo "include_mpn(\`x86_64/dos64.m4')" >> $gmp_tmpconfigm4i
+ ;;
+	    *-openbsd*)
+
+echo "define(<OPENBSD>,1)" >> $gmp_tmpconfigm4
+ ;;
+	    *-linux*)
+
+echo "define(<LINUX>,1)" >> $gmp_tmpconfigm4
+ ;;
+	  esac
+          ;;
+      esac
+      ;;
+  esac
+fi
+
+# For --enable-minithres, prepend "minithres" to path so that its special
+# gmp-mparam.h will be used.
+if test $enable_minithres = yes; then
+  path="minithres $path"
+fi
+
+# Create link for gmp-mparam.h.
+gmp_mparam_source=
+for gmp_mparam_dir in $path; do
+  test "$no_create" = yes || rm -f gmp-mparam.h
+  tmp_file=$srcdir/mpn/$gmp_mparam_dir/gmp-mparam.h
+  if test -f $tmp_file; then
+    ac_config_links="$ac_config_links gmp-mparam.h:mpn/$gmp_mparam_dir/gmp-mparam.h"
+
+    gmp_srclinks="$gmp_srclinks gmp-mparam.h"
+    gmp_mparam_source=$tmp_file
+    break
+  fi
+done
+if test -z "$gmp_mparam_source"; then
+  as_fn_error $? "no version of gmp-mparam.h found in path: $path" "$LINENO" 5
+fi
+
+# For a helpful message from tune/tuneup.c
+gmp_mparam_suggest=$gmp_mparam_source
+if test "$gmp_mparam_dir" = generic; then
+  for i in $path; do break; done
+  if test "$i" != generic; then
+    gmp_mparam_suggest="new file $srcdir/mpn/$i/gmp-mparam.h"
+  fi
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define GMP_MPARAM_H_SUGGEST "$gmp_mparam_source"
+_ACEOF
+
+
+
+# Copy relevant parameters from gmp-mparam.h to config.m4.
+# We only do this for parameters that are used by some assembly files.
+# Fat binaries do this on a per-file basis, so skip in that case.
+#
+if test -z "$fat_path"; then
+  for i in SQR_TOOM2_THRESHOLD BMOD_1_TO_MOD_1_THRESHOLD SHLD_SLOW SHRD_SLOW; do
+    value=`sed -n 's/^#define '$i'[ 	]*\([0-9A-Z][0-9A-Z_]*\).*$/\1/p' $gmp_mparam_source`
+    if test -n "$value"; then
+
+echo "define(<$i>,<$value>)" >> $gmp_tmpconfigm4
+
+    fi
+  done
+fi
+
+
+# Sizes of some types, needed at preprocessing time.
+#
+# FIXME: The assumption that GMP_LIMB_BITS is 8*sizeof(mp_limb_t) might
+# be slightly rash, but it's true everywhere we know of and ought to be true
+# of any sensible system.  In a generic C build, grepping LONG_BIT out of
+# <limits.h> might be an alternative, for maximum portability.
+#
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5
+$as_echo_n "checking size of void *... " >&6; }
+if ${ac_cv_sizeof_void_p+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p"        "$ac_includes_default"; then :
+
+else
+  if test "$ac_cv_type_void_p" = yes; then
+     { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot compute sizeof (void *)
+See \`config.log' for more details" "$LINENO" 5; }
+   else
+     ac_cv_sizeof_void_p=0
+   fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_void_p" >&5
+$as_echo "$ac_cv_sizeof_void_p" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_VOID_P $ac_cv_sizeof_void_p
+_ACEOF
+
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of unsigned short" >&5
+$as_echo_n "checking size of unsigned short... " >&6; }
+if ${ac_cv_sizeof_unsigned_short+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (unsigned short))" "ac_cv_sizeof_unsigned_short"        "$ac_includes_default"; then :
+
+else
+  if test "$ac_cv_type_unsigned_short" = yes; then
+     { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot compute sizeof (unsigned short)
+See \`config.log' for more details" "$LINENO" 5; }
+   else
+     ac_cv_sizeof_unsigned_short=0
+   fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_unsigned_short" >&5
+$as_echo "$ac_cv_sizeof_unsigned_short" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_UNSIGNED_SHORT $ac_cv_sizeof_unsigned_short
+_ACEOF
+
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of unsigned" >&5
+$as_echo_n "checking size of unsigned... " >&6; }
+if ${ac_cv_sizeof_unsigned+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (unsigned))" "ac_cv_sizeof_unsigned"        "$ac_includes_default"; then :
+
+else
+  if test "$ac_cv_type_unsigned" = yes; then
+     { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot compute sizeof (unsigned)
+See \`config.log' for more details" "$LINENO" 5; }
+   else
+     ac_cv_sizeof_unsigned=0
+   fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_unsigned" >&5
+$as_echo "$ac_cv_sizeof_unsigned" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_UNSIGNED $ac_cv_sizeof_unsigned
+_ACEOF
+
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of unsigned long" >&5
+$as_echo_n "checking size of unsigned long... " >&6; }
+if ${ac_cv_sizeof_unsigned_long+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (unsigned long))" "ac_cv_sizeof_unsigned_long"        "$ac_includes_default"; then :
+
+else
+  if test "$ac_cv_type_unsigned_long" = yes; then
+     { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot compute sizeof (unsigned long)
+See \`config.log' for more details" "$LINENO" 5; }
+   else
+     ac_cv_sizeof_unsigned_long=0
+   fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_unsigned_long" >&5
+$as_echo "$ac_cv_sizeof_unsigned_long" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_UNSIGNED_LONG $ac_cv_sizeof_unsigned_long
+_ACEOF
+
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of mp_limb_t" >&5
+$as_echo_n "checking size of mp_limb_t... " >&6; }
+if ${ac_cv_sizeof_mp_limb_t+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (mp_limb_t))" "ac_cv_sizeof_mp_limb_t"        "#define __GMP_WITHIN_CONFIGURE 1   /* ignore template stuff */
+#define GMP_NAIL_BITS $GMP_NAIL_BITS
+#define GMP_LIMB_BITS 123
+$DEFN_LONG_LONG_LIMB
+#include \"$srcdir/gmp-h.in\"
+
+"; then :
+
+else
+  if test "$ac_cv_type_mp_limb_t" = yes; then
+     { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot compute sizeof (mp_limb_t)
+See \`config.log' for more details" "$LINENO" 5; }
+   else
+     ac_cv_sizeof_mp_limb_t=0
+   fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_mp_limb_t" >&5
+$as_echo "$ac_cv_sizeof_mp_limb_t" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_MP_LIMB_T $ac_cv_sizeof_mp_limb_t
+_ACEOF
+
+
+if test "$ac_cv_sizeof_mp_limb_t" = 0; then
+  as_fn_error $? "Oops, mp_limb_t doesn't seem to work" "$LINENO" 5
+fi
+GMP_LIMB_BITS=`expr 8 \* $ac_cv_sizeof_mp_limb_t`
+
+
+echo "define(<SIZEOF_UNSIGNED>,<$ac_cv_sizeof_unsigned>)" >> $gmp_tmpconfigm4
+
+
+# Check compiler limb size matches gmp-mparam.h
+#
+# FIXME: Some of the cycle counter objects in the tune directory depend on
+# the size of ulong, it'd be possible to check that here, though a mismatch
+# probably wouldn't want to be fatal, none of the libgmp assembler code
+# depends on ulong.
+#
+mparam_bits=`sed -n 's/^#define GMP_LIMB_BITS[ 	][ 	]*\([0-9]*\).*$/\1/p' $gmp_mparam_source`
+if test -n "$mparam_bits" && test "$mparam_bits" -ne $GMP_LIMB_BITS; then
+  if test "$test_CFLAGS" = set; then
+    as_fn_error $? "Oops, mp_limb_t is $GMP_LIMB_BITS bits, but the assembler code
+in this configuration expects $mparam_bits bits.
+You appear to have set \$CFLAGS, perhaps you also need to tell GMP the
+intended ABI, see \"ABI and ISA\" in the manual." "$LINENO" 5
+  else
+    as_fn_error $? "Oops, mp_limb_t is $GMP_LIMB_BITS bits, but the assembler code
+in this configuration expects $mparam_bits bits." "$LINENO" 5
+  fi
+fi
+
+
+echo "define(<GMP_LIMB_BITS>,$GMP_LIMB_BITS)" >> $gmp_tmpconfigm4
+
+
+echo "define(<GMP_NAIL_BITS>,$GMP_NAIL_BITS)" >> $gmp_tmpconfigm4
+
+
+echo "define(<GMP_NUMB_BITS>,eval(GMP_LIMB_BITS-GMP_NAIL_BITS))" >> $gmp_tmpconfigm4
+
+
+
+
+
+
+
+
+# A recompiled sqr_basecase for use in the tune program, if necessary.
+TUNE_SQR_OBJ=
+test -d tune || mkdir tune
+case $sqr_basecase_source in
+  *.asm)
+    sqr_max=`sed -n 's/^def...(SQR_TOOM2_THRESHOLD_MAX, *\([0-9]*\))/\1/p' $sqr_basecase_source`
+    if test -n "$sqr_max"; then
+      TUNE_SQR_OBJ=sqr_asm.o
+
+cat >>confdefs.h <<_ACEOF
+#define TUNE_SQR_TOOM2_MAX $sqr_max
+_ACEOF
+
+    fi
+    cat >tune/sqr_basecase.c <<EOF
+/* not sure that an empty file can compile, so put in a dummy */
+int sqr_basecase_dummy;
+EOF
+    ;;
+  *.c)
+    TUNE_SQR_OBJ=
+    $as_echo "#define TUNE_SQR_TOOM2_MAX SQR_TOOM2_MAX_GENERIC" >>confdefs.h
+
+    cat >tune/sqr_basecase.c <<EOF
+#define TUNE_PROGRAM_BUILD 1
+#define TUNE_PROGRAM_BUILD_SQR 1
+#include "mpn/sqr_basecase.c"
+EOF
+    ;;
+esac
+
+
+
+# Configs for demos/pexpr.c.
+#
+ac_config_files="$ac_config_files demos/pexpr-config.h:demos/pexpr-config-h.in"
+
+case $ac_cv_func_clock in
+yes) HAVE_CLOCK_01=1
+ ;;
+no)  HAVE_CLOCK_01=0 ;;
+esac
+
+case $ac_cv_func_cputime in
+yes) HAVE_CPUTIME_01=1
+ ;;
+no)  HAVE_CPUTIME_01=0 ;;
+esac
+
+case $ac_cv_func_getrusage in
+yes) HAVE_GETRUSAGE_01=1
+ ;;
+no)  HAVE_GETRUSAGE_01=0 ;;
+esac
+
+case $ac_cv_func_gettimeofday in
+yes) HAVE_GETTIMEOFDAY_01=1
+ ;;
+no)  HAVE_GETTIMEOFDAY_01=0 ;;
+esac
+
+case $ac_cv_func_sigaction in
+yes) HAVE_SIGACTION_01=1
+ ;;
+no)  HAVE_SIGACTION_01=0 ;;
+esac
+
+case $ac_cv_func_sigaltstack in
+yes) HAVE_SIGALTSTACK_01=1
+ ;;
+no)  HAVE_SIGALTSTACK_01=0 ;;
+esac
+
+case $ac_cv_func_sigstack in
+yes) HAVE_SIGSTACK_01=1
+ ;;
+no)  HAVE_SIGSTACK_01=0 ;;
+esac
+
+
+case $ac_cv_header_sys_resource_h in
+yes) HAVE_SYS_RESOURCE_H_01=1
+ ;;
+no)  HAVE_SYS_RESOURCE_H_01=0 ;;
+esac
+
+
+ac_fn_c_check_type "$LINENO" "stack_t" "ac_cv_type_stack_t" "#include <signal.h>
+"
+if test "x$ac_cv_type_stack_t" = xyes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_STACK_T 1
+_ACEOF
+
+HAVE_STACK_T_01=1
+else
+  HAVE_STACK_T_01=0
+fi
+
+
+
+# Configs for demos/calc directory
+#
+# AC_SUBST+AC_CONFIG_FILES is used for calc-config.h, rather than AC_DEFINE+
+# AC_CONFIG_HEADERS, since with the latter automake (1.8) will then put the
+# directory (ie. demos/calc) into $(DEFAULT_INCLUDES) for every Makefile.in,
+# which would look very strange.
+#
+# -lcurses is required by libreadline.  On a typical SVR4 style system this
+# normally doesn't have to be given explicitly, since libreadline.so will
+# have a NEEDED record for it.  But if someone for some reason is using only
+# a static libreadline.a then we must give -lcurses.  Readline (as of
+# version 4.3) doesn't use libtool, so we can't rely on a .la to cover
+# necessary dependencies.
+#
+# On a couple of systems we've seen libreadline available, but the headers
+# not in the default include path, so check for readline/readline.h.  We've
+# also seen readline/history.h missing, not sure if that's just a broken
+# install or a very old version, but check that too.
+#
+ac_config_files="$ac_config_files demos/calc/calc-config.h:demos/calc/calc-config-h.in"
+
+LIBCURSES=
+if test $with_readline != no; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tputs in -lncurses" >&5
+$as_echo_n "checking for tputs in -lncurses... " >&6; }
+if ${ac_cv_lib_ncurses_tputs+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lncurses  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char tputs ();
+int
+main ()
+{
+return tputs ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_ncurses_tputs=yes
+else
+  ac_cv_lib_ncurses_tputs=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ncurses_tputs" >&5
+$as_echo "$ac_cv_lib_ncurses_tputs" >&6; }
+if test "x$ac_cv_lib_ncurses_tputs" = xyes; then :
+  LIBCURSES=-lncurses
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for tputs in -lcurses" >&5
+$as_echo_n "checking for tputs in -lcurses... " >&6; }
+if ${ac_cv_lib_curses_tputs+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcurses  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char tputs ();
+int
+main ()
+{
+return tputs ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_curses_tputs=yes
+else
+  ac_cv_lib_curses_tputs=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_curses_tputs" >&5
+$as_echo "$ac_cv_lib_curses_tputs" >&6; }
+if test "x$ac_cv_lib_curses_tputs" = xyes; then :
+  LIBCURSES=-lcurses
+fi
+
+fi
+
+fi
+
+use_readline=$with_readline
+if test $with_readline = detect; then
+  use_readline=no
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for readline in -lreadline" >&5
+$as_echo_n "checking for readline in -lreadline... " >&6; }
+if ${ac_cv_lib_readline_readline+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lreadline $LIBCURSES $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char readline ();
+int
+main ()
+{
+return readline ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_readline_readline=yes
+else
+  ac_cv_lib_readline_readline=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_readline" >&5
+$as_echo "$ac_cv_lib_readline_readline" >&6; }
+if test "x$ac_cv_lib_readline_readline" = xyes; then :
+  ac_fn_c_check_header_mongrel "$LINENO" "readline/readline.h" "ac_cv_header_readline_readline_h" "$ac_includes_default"
+if test "x$ac_cv_header_readline_readline_h" = xyes; then :
+  ac_fn_c_check_header_mongrel "$LINENO" "readline/history.h" "ac_cv_header_readline_history_h" "$ac_includes_default"
+if test "x$ac_cv_header_readline_history_h" = xyes; then :
+  use_readline=yes
+fi
+
+
+fi
+
+
+fi
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking readline detected" >&5
+$as_echo_n "checking readline detected... " >&6; }
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $use_readline" >&5
+$as_echo "$use_readline" >&6; }
+fi
+if test $use_readline = yes; then
+  WITH_READLINE_01=1
+
+  LIBREADLINE=-lreadline
+
+else
+  WITH_READLINE_01=0
+fi
+for ac_prog in 'bison -y' byacc
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_YACC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$YACC"; then
+  ac_cv_prog_YACC="$YACC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_YACC="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+YACC=$ac_cv_prog_YACC
+if test -n "$YACC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $YACC" >&5
+$as_echo "$YACC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$YACC" && break
+done
+test -n "$YACC" || YACC="yacc"
+
+for ac_prog in flex lex
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_LEX+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$LEX"; then
+  ac_cv_prog_LEX="$LEX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_LEX="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+LEX=$ac_cv_prog_LEX
+if test -n "$LEX"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LEX" >&5
+$as_echo "$LEX" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$LEX" && break
+done
+test -n "$LEX" || LEX=":"
+
+if test "x$LEX" != "x:"; then
+  cat >conftest.l <<_ACEOF
+%%
+a { ECHO; }
+b { REJECT; }
+c { yymore (); }
+d { yyless (1); }
+e { /* IRIX 6.5 flex 2.5.4 underquotes its yyless argument.  */
+    yyless ((input () != 0)); }
+f { unput (yytext[0]); }
+. { BEGIN INITIAL; }
+%%
+#ifdef YYTEXT_POINTER
+extern char *yytext;
+#endif
+int
+main (void)
+{
+  return ! yylex () + ! yywrap ();
+}
+_ACEOF
+{ { ac_try="$LEX conftest.l"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$LEX conftest.l") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking lex output file root" >&5
+$as_echo_n "checking lex output file root... " >&6; }
+if ${ac_cv_prog_lex_root+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+if test -f lex.yy.c; then
+  ac_cv_prog_lex_root=lex.yy
+elif test -f lexyy.c; then
+  ac_cv_prog_lex_root=lexyy
+else
+  as_fn_error $? "cannot find output from $LEX; giving up" "$LINENO" 5
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_root" >&5
+$as_echo "$ac_cv_prog_lex_root" >&6; }
+LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root
+
+if test -z "${LEXLIB+set}"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking lex library" >&5
+$as_echo_n "checking lex library... " >&6; }
+if ${ac_cv_lib_lex+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+    ac_save_LIBS=$LIBS
+    ac_cv_lib_lex='none needed'
+    for ac_lib in '' -lfl -ll; do
+      LIBS="$ac_lib $ac_save_LIBS"
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+`cat $LEX_OUTPUT_ROOT.c`
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_lex=$ac_lib
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+      test "$ac_cv_lib_lex" != 'none needed' && break
+    done
+    LIBS=$ac_save_LIBS
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lex" >&5
+$as_echo "$ac_cv_lib_lex" >&6; }
+  test "$ac_cv_lib_lex" != 'none needed' && LEXLIB=$ac_cv_lib_lex
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether yytext is a pointer" >&5
+$as_echo_n "checking whether yytext is a pointer... " >&6; }
+if ${ac_cv_prog_lex_yytext_pointer+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  # POSIX says lex can declare yytext either as a pointer or an array; the
+# default is implementation-dependent.  Figure out which it is, since
+# not all implementations provide the %pointer and %array declarations.
+ac_cv_prog_lex_yytext_pointer=no
+ac_save_LIBS=$LIBS
+LIBS="$LEXLIB $ac_save_LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+  #define YYTEXT_POINTER 1
+`cat $LEX_OUTPUT_ROOT.c`
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_prog_lex_yytext_pointer=yes
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_save_LIBS
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_yytext_pointer" >&5
+$as_echo "$ac_cv_prog_lex_yytext_pointer" >&6; }
+if test $ac_cv_prog_lex_yytext_pointer = yes; then
+
+$as_echo "#define YYTEXT_POINTER 1" >>confdefs.h
+
+fi
+rm -f conftest.l $LEX_OUTPUT_ROOT.c
+
+fi
+if test "$LEX" = :; then
+  LEX=${am_missing_run}flex
+fi
+
+
+
+# Create config.m4.
+
+echo "creating $gmp_configm4"
+echo "d""nl $gmp_configm4.  Generated automatically by configure." > $gmp_configm4
+if test -f $gmp_tmpconfigm4; then
+  echo "changequote(<,>)" >> $gmp_configm4
+  echo "ifdef(<__CONFIG_M4_INCLUDED__>,,<" >> $gmp_configm4
+  cat $gmp_tmpconfigm4 >> $gmp_configm4
+  echo ">)" >> $gmp_configm4
+  echo "changequote(\`,')" >> $gmp_configm4
+  rm $gmp_tmpconfigm4
+fi
+echo "ifdef(\`__CONFIG_M4_INCLUDED__',,\`" >> $gmp_configm4
+if test -f $gmp_tmpconfigm4i; then
+  cat $gmp_tmpconfigm4i >> $gmp_configm4
+  rm $gmp_tmpconfigm4i
+fi
+if test -f $gmp_tmpconfigm4p; then
+  cat $gmp_tmpconfigm4p >> $gmp_configm4
+  rm $gmp_tmpconfigm4p
+fi
+echo "')" >> $gmp_configm4
+echo "define(\`__CONFIG_M4_INCLUDED__')" >> $gmp_configm4
+
+
+# Create Makefiles
+# FIXME: Upcoming version of autoconf/automake may not like broken lines.
+#        Right now automake isn't accepting the new AC_CONFIG_FILES scheme.
+
+ac_config_files="$ac_config_files Makefile mpf/Makefile mpn/Makefile mpq/Makefile mpz/Makefile printf/Makefile scanf/Makefile rand/Makefile cxx/Makefile tests/Makefile tests/devel/Makefile tests/mpf/Makefile tests/mpn/Makefile tests/mpq/Makefile tests/mpz/Makefile tests/rand/Makefile tests/misc/Makefile tests/cxx/Makefile doc/Makefile tune/Makefile demos/Makefile demos/calc/Makefile demos/expr/Makefile gmp.h:gmp-h.in gmp.pc:gmp.pc.in gmpxx.pc:gmpxx.pc.in"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems.  If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+  for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) { eval $ac_var=; unset $ac_var;} ;;
+      esac ;;
+    esac
+  done
+
+  (set) 2>&1 |
+    case $as_nl`(ac_space=' '; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      # `set' does not quote correctly, so add quotes: double-quote
+      # substitution turns \\\\ into \\, and sed turns \\ into \.
+      sed -n \
+	"s/'/'\\\\''/g;
+	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+      ;; #(
+    *)
+      # `set' quotes correctly as required by POSIX, so do not add quotes.
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+) |
+  sed '
+     /^ac_cv_env_/b end
+     t clear
+     :clear
+     s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+     t end
+     s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+     :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+  if test -w "$cache_file"; then
+    if test "x$cache_file" != "x/dev/null"; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+      if test ! -f "$cache_file" || test -h "$cache_file"; then
+	cat confcache >"$cache_file"
+      else
+        case $cache_file in #(
+        */* | ?:*)
+	  mv -f confcache "$cache_file"$$ &&
+	  mv -f "$cache_file"$$ "$cache_file" ;; #(
+        *)
+	  mv -f confcache "$cache_file" ;;
+	esac
+      fi
+    fi
+  else
+    { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+  fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+  # 1. Remove the extension, and $U if already installed.
+  ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+  ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+  # 2. Prepend LIBOBJDIR.  When used with automake>=1.10 LIBOBJDIR
+  #    will be set to the directory where LIBOBJS objects are built.
+  as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+  as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5
+$as_echo_n "checking that generated files are newer than configure... " >&6; }
+   if test -n "$am_sleep_pid"; then
+     # Hide warnings about reused PIDs.
+     wait $am_sleep_pid 2>/dev/null
+   fi
+   { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5
+$as_echo "done" >&6; }
+ if test -n "$EXEEXT"; then
+  am__EXEEXT_TRUE=
+  am__EXEEXT_FALSE='#'
+else
+  am__EXEEXT_TRUE='#'
+  am__EXEEXT_FALSE=
+fi
+
+if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then
+  as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${WANT_CXX_TRUE}" && test -z "${WANT_CXX_FALSE}"; then
+  as_fn_error $? "conditional \"WANT_CXX\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${ENABLE_STATIC_TRUE}" && test -z "${ENABLE_STATIC_FALSE}"; then
+  as_fn_error $? "conditional \"ENABLE_STATIC\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in #(
+      *"$as_nl"*)
+	expr "X$arg" : "X\\(.*\\)$as_nl";
+	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""	$as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$1; test $as_status -eq 0 && as_status=1
+  if test "$4"; then
+    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+  fi
+  $as_echo "$as_me: error: $2" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='	';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -pR'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -pR'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -pR'
+  fi
+else
+  as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_dir" : 'X\(//\)[^/]' \| \
+	 X"$as_dir" : 'X\(//\)$' \| \
+	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p='mkdir -p "$as_dir"'
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+  test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by GNU MP $as_me 6.2.0, which was
+generated by GNU Autoconf 2.69.  Invocation command line was
+
+  CONFIG_FILES    = $CONFIG_FILES
+  CONFIG_HEADERS  = $CONFIG_HEADERS
+  CONFIG_LINKS    = $CONFIG_LINKS
+  CONFIG_COMMANDS = $CONFIG_COMMANDS
+  $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+config_links="$ac_config_links"
+config_commands="$ac_config_commands"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration.  Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+  -h, --help       print this help, then exit
+  -V, --version    print version number and configuration settings, then exit
+      --config     print configuration, then exit
+  -q, --quiet, --silent
+                   do not print progress messages
+  -d, --debug      don't remove temporary files
+      --recheck    update $as_me by reconfiguring in the same conditions
+      --file=FILE[:TEMPLATE]
+                   instantiate the configuration file FILE
+      --header=FILE[:TEMPLATE]
+                   instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Configuration links:
+$config_links
+
+Configuration commands:
+$config_commands
+
+Report bugs to <gmp-bugs@gmplib.org, see https://gmplib.org/manual/Reporting-Bugs.html>.
+GNU MP home page: <http://www.gnu.org/software/gmp/>.
+General help using GNU software: <http://www.gnu.org/gethelp/>."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+GNU MP config.status 6.2.0
+configured by $0, generated by GNU Autoconf 2.69,
+  with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+INSTALL='$INSTALL'
+MKDIR_P='$MKDIR_P'
+AWK='$AWK'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+  case $1 in
+  --*=?*)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+    ac_shift=:
+    ;;
+  --*=)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=
+    ac_shift=:
+    ;;
+  *)
+    ac_option=$1
+    ac_optarg=$2
+    ac_shift=shift
+    ;;
+  esac
+
+  case $ac_option in
+  # Handling of the options.
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    ac_cs_recheck=: ;;
+  --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+    $as_echo "$ac_cs_version"; exit ;;
+  --config | --confi | --conf | --con | --co | --c )
+    $as_echo "$ac_cs_config"; exit ;;
+  --debug | --debu | --deb | --de | --d | -d )
+    debug=: ;;
+  --file | --fil | --fi | --f )
+    $ac_shift
+    case $ac_optarg in
+    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    '') as_fn_error $? "missing file argument" ;;
+    esac
+    as_fn_append CONFIG_FILES " '$ac_optarg'"
+    ac_need_defaults=false;;
+  --header | --heade | --head | --hea )
+    $ac_shift
+    case $ac_optarg in
+    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+    ac_need_defaults=false;;
+  --he | --h)
+    # Conflict between --help and --header
+    as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+  --help | --hel | -h )
+    $as_echo "$ac_cs_usage"; exit ;;
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil | --si | --s)
+    ac_cs_silent=: ;;
+
+  # This is an error.
+  -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+  *) as_fn_append ac_config_targets " $1"
+     ac_need_defaults=false ;;
+
+  esac
+  shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+  exec 6>/dev/null
+  ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+  set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+  shift
+  \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+  CONFIG_SHELL='$SHELL'
+  export CONFIG_SHELL
+  exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+  echo
+  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+  $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+#
+# INIT-COMMANDS
+#
+
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+sed_quote_subst='$sed_quote_subst'
+double_quote_subst='$double_quote_subst'
+delay_variable_subst='$delay_variable_subst'
+NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`'
+AS='`$ECHO "$AS" | $SED "$delay_single_quote_subst"`'
+DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`'
+OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`'
+macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`'
+macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`'
+enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`'
+enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`'
+pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`'
+enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`'
+shared_archive_member_spec='`$ECHO "$shared_archive_member_spec" | $SED "$delay_single_quote_subst"`'
+SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`'
+ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`'
+PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`'
+host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`'
+host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`'
+host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`'
+build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`'
+build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`'
+build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`'
+SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`'
+Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`'
+GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`'
+EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`'
+FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`'
+LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`'
+LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`'
+max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`'
+ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`'
+exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`'
+lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`'
+lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`'
+lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`'
+lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`'
+lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`'
+reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`'
+reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`'
+deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`'
+file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`'
+file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`'
+want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`'
+sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`'
+AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`'
+AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`'
+archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`'
+STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`'
+RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`'
+old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`'
+old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`'
+old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`'
+lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`'
+CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`'
+CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`'
+compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`'
+GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_import='`$ECHO "$lt_cv_sys_global_symbol_to_import" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`'
+lt_cv_nm_interface='`$ECHO "$lt_cv_nm_interface" | $SED "$delay_single_quote_subst"`'
+nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`'
+lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`'
+lt_cv_truncate_bin='`$ECHO "$lt_cv_truncate_bin" | $SED "$delay_single_quote_subst"`'
+objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`'
+MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`'
+lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`'
+need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`'
+MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`'
+DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`'
+NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`'
+LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`'
+OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`'
+OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`'
+libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`'
+shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`'
+extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`'
+archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`'
+enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`'
+export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`'
+whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`'
+compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`'
+old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`'
+old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`'
+archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`'
+archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`'
+module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`'
+module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`'
+with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`'
+allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`'
+no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`'
+hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`'
+hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`'
+hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`'
+hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`'
+hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`'
+inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`'
+link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`'
+always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`'
+export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`'
+exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`'
+include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`'
+prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`'
+postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`'
+file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`'
+variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`'
+need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`'
+need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`'
+version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`'
+runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`'
+shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`'
+shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`'
+libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`'
+library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`'
+soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`'
+install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`'
+postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`'
+postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`'
+finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`'
+finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`'
+hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`'
+sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`'
+configure_time_dlsearch_path='`$ECHO "$configure_time_dlsearch_path" | $SED "$delay_single_quote_subst"`'
+configure_time_lt_sys_library_path='`$ECHO "$configure_time_lt_sys_library_path" | $SED "$delay_single_quote_subst"`'
+hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`'
+enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`'
+enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`'
+enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`'
+old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`'
+striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`'
+compiler_lib_search_dirs='`$ECHO "$compiler_lib_search_dirs" | $SED "$delay_single_quote_subst"`'
+predep_objects='`$ECHO "$predep_objects" | $SED "$delay_single_quote_subst"`'
+postdep_objects='`$ECHO "$postdep_objects" | $SED "$delay_single_quote_subst"`'
+predeps='`$ECHO "$predeps" | $SED "$delay_single_quote_subst"`'
+postdeps='`$ECHO "$postdeps" | $SED "$delay_single_quote_subst"`'
+compiler_lib_search_path='`$ECHO "$compiler_lib_search_path" | $SED "$delay_single_quote_subst"`'
+LD_CXX='`$ECHO "$LD_CXX" | $SED "$delay_single_quote_subst"`'
+reload_flag_CXX='`$ECHO "$reload_flag_CXX" | $SED "$delay_single_quote_subst"`'
+reload_cmds_CXX='`$ECHO "$reload_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+old_archive_cmds_CXX='`$ECHO "$old_archive_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+compiler_CXX='`$ECHO "$compiler_CXX" | $SED "$delay_single_quote_subst"`'
+GCC_CXX='`$ECHO "$GCC_CXX" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_no_builtin_flag_CXX='`$ECHO "$lt_prog_compiler_no_builtin_flag_CXX" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_pic_CXX='`$ECHO "$lt_prog_compiler_pic_CXX" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_wl_CXX='`$ECHO "$lt_prog_compiler_wl_CXX" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_static_CXX='`$ECHO "$lt_prog_compiler_static_CXX" | $SED "$delay_single_quote_subst"`'
+lt_cv_prog_compiler_c_o_CXX='`$ECHO "$lt_cv_prog_compiler_c_o_CXX" | $SED "$delay_single_quote_subst"`'
+archive_cmds_need_lc_CXX='`$ECHO "$archive_cmds_need_lc_CXX" | $SED "$delay_single_quote_subst"`'
+enable_shared_with_static_runtimes_CXX='`$ECHO "$enable_shared_with_static_runtimes_CXX" | $SED "$delay_single_quote_subst"`'
+export_dynamic_flag_spec_CXX='`$ECHO "$export_dynamic_flag_spec_CXX" | $SED "$delay_single_quote_subst"`'
+whole_archive_flag_spec_CXX='`$ECHO "$whole_archive_flag_spec_CXX" | $SED "$delay_single_quote_subst"`'
+compiler_needs_object_CXX='`$ECHO "$compiler_needs_object_CXX" | $SED "$delay_single_quote_subst"`'
+old_archive_from_new_cmds_CXX='`$ECHO "$old_archive_from_new_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+old_archive_from_expsyms_cmds_CXX='`$ECHO "$old_archive_from_expsyms_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+archive_cmds_CXX='`$ECHO "$archive_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+archive_expsym_cmds_CXX='`$ECHO "$archive_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+module_cmds_CXX='`$ECHO "$module_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+module_expsym_cmds_CXX='`$ECHO "$module_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+with_gnu_ld_CXX='`$ECHO "$with_gnu_ld_CXX" | $SED "$delay_single_quote_subst"`'
+allow_undefined_flag_CXX='`$ECHO "$allow_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`'
+no_undefined_flag_CXX='`$ECHO "$no_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec_CXX='`$ECHO "$hardcode_libdir_flag_spec_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_separator_CXX='`$ECHO "$hardcode_libdir_separator_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_direct_CXX='`$ECHO "$hardcode_direct_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_direct_absolute_CXX='`$ECHO "$hardcode_direct_absolute_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_minus_L_CXX='`$ECHO "$hardcode_minus_L_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_shlibpath_var_CXX='`$ECHO "$hardcode_shlibpath_var_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_automatic_CXX='`$ECHO "$hardcode_automatic_CXX" | $SED "$delay_single_quote_subst"`'
+inherit_rpath_CXX='`$ECHO "$inherit_rpath_CXX" | $SED "$delay_single_quote_subst"`'
+link_all_deplibs_CXX='`$ECHO "$link_all_deplibs_CXX" | $SED "$delay_single_quote_subst"`'
+always_export_symbols_CXX='`$ECHO "$always_export_symbols_CXX" | $SED "$delay_single_quote_subst"`'
+export_symbols_cmds_CXX='`$ECHO "$export_symbols_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+exclude_expsyms_CXX='`$ECHO "$exclude_expsyms_CXX" | $SED "$delay_single_quote_subst"`'
+include_expsyms_CXX='`$ECHO "$include_expsyms_CXX" | $SED "$delay_single_quote_subst"`'
+prelink_cmds_CXX='`$ECHO "$prelink_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+postlink_cmds_CXX='`$ECHO "$postlink_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+file_list_spec_CXX='`$ECHO "$file_list_spec_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_action_CXX='`$ECHO "$hardcode_action_CXX" | $SED "$delay_single_quote_subst"`'
+compiler_lib_search_dirs_CXX='`$ECHO "$compiler_lib_search_dirs_CXX" | $SED "$delay_single_quote_subst"`'
+predep_objects_CXX='`$ECHO "$predep_objects_CXX" | $SED "$delay_single_quote_subst"`'
+postdep_objects_CXX='`$ECHO "$postdep_objects_CXX" | $SED "$delay_single_quote_subst"`'
+predeps_CXX='`$ECHO "$predeps_CXX" | $SED "$delay_single_quote_subst"`'
+postdeps_CXX='`$ECHO "$postdeps_CXX" | $SED "$delay_single_quote_subst"`'
+compiler_lib_search_path_CXX='`$ECHO "$compiler_lib_search_path_CXX" | $SED "$delay_single_quote_subst"`'
+
+LTCC='$LTCC'
+LTCFLAGS='$LTCFLAGS'
+compiler='$compiler_DEFAULT'
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+\$1
+_LTECHO_EOF'
+}
+
+# Quote evaled strings.
+for var in NM \
+AS \
+DLLTOOL \
+OBJDUMP \
+SHELL \
+ECHO \
+PATH_SEPARATOR \
+SED \
+GREP \
+EGREP \
+FGREP \
+LD \
+LN_S \
+lt_SP2NL \
+lt_NL2SP \
+reload_flag \
+deplibs_check_method \
+file_magic_cmd \
+file_magic_glob \
+want_nocaseglob \
+sharedlib_from_linklib_cmd \
+AR \
+AR_FLAGS \
+archiver_list_spec \
+STRIP \
+RANLIB \
+CC \
+CFLAGS \
+compiler \
+lt_cv_sys_global_symbol_pipe \
+lt_cv_sys_global_symbol_to_cdecl \
+lt_cv_sys_global_symbol_to_import \
+lt_cv_sys_global_symbol_to_c_name_address \
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \
+lt_cv_nm_interface \
+nm_file_list_spec \
+lt_cv_truncate_bin \
+lt_prog_compiler_no_builtin_flag \
+lt_prog_compiler_pic \
+lt_prog_compiler_wl \
+lt_prog_compiler_static \
+lt_cv_prog_compiler_c_o \
+need_locks \
+MANIFEST_TOOL \
+DSYMUTIL \
+NMEDIT \
+LIPO \
+OTOOL \
+OTOOL64 \
+shrext_cmds \
+export_dynamic_flag_spec \
+whole_archive_flag_spec \
+compiler_needs_object \
+with_gnu_ld \
+allow_undefined_flag \
+no_undefined_flag \
+hardcode_libdir_flag_spec \
+hardcode_libdir_separator \
+exclude_expsyms \
+include_expsyms \
+file_list_spec \
+variables_saved_for_relink \
+libname_spec \
+library_names_spec \
+soname_spec \
+install_override_mode \
+finish_eval \
+old_striplib \
+striplib \
+compiler_lib_search_dirs \
+predep_objects \
+postdep_objects \
+predeps \
+postdeps \
+compiler_lib_search_path \
+LD_CXX \
+reload_flag_CXX \
+compiler_CXX \
+lt_prog_compiler_no_builtin_flag_CXX \
+lt_prog_compiler_pic_CXX \
+lt_prog_compiler_wl_CXX \
+lt_prog_compiler_static_CXX \
+lt_cv_prog_compiler_c_o_CXX \
+export_dynamic_flag_spec_CXX \
+whole_archive_flag_spec_CXX \
+compiler_needs_object_CXX \
+with_gnu_ld_CXX \
+allow_undefined_flag_CXX \
+no_undefined_flag_CXX \
+hardcode_libdir_flag_spec_CXX \
+hardcode_libdir_separator_CXX \
+exclude_expsyms_CXX \
+include_expsyms_CXX \
+file_list_spec_CXX \
+compiler_lib_search_dirs_CXX \
+predep_objects_CXX \
+postdep_objects_CXX \
+predeps_CXX \
+postdeps_CXX \
+compiler_lib_search_path_CXX; do
+    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+    *[\\\\\\\`\\"\\\$]*)
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes
+      ;;
+    *)
+      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+      ;;
+    esac
+done
+
+# Double-quote double-evaled strings.
+for var in reload_cmds \
+old_postinstall_cmds \
+old_postuninstall_cmds \
+old_archive_cmds \
+extract_expsyms_cmds \
+old_archive_from_new_cmds \
+old_archive_from_expsyms_cmds \
+archive_cmds \
+archive_expsym_cmds \
+module_cmds \
+module_expsym_cmds \
+export_symbols_cmds \
+prelink_cmds \
+postlink_cmds \
+postinstall_cmds \
+postuninstall_cmds \
+finish_cmds \
+sys_lib_search_path_spec \
+configure_time_dlsearch_path \
+configure_time_lt_sys_library_path \
+reload_cmds_CXX \
+old_archive_cmds_CXX \
+old_archive_from_new_cmds_CXX \
+old_archive_from_expsyms_cmds_CXX \
+archive_cmds_CXX \
+archive_expsym_cmds_CXX \
+module_cmds_CXX \
+module_expsym_cmds_CXX \
+export_symbols_cmds_CXX \
+prelink_cmds_CXX \
+postlink_cmds_CXX; do
+    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+    *[\\\\\\\`\\"\\\$]*)
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes
+      ;;
+    *)
+      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+      ;;
+    esac
+done
+
+ac_aux_dir='$ac_aux_dir'
+
+# See if we are running on zsh, and set the options that allow our
+# commands through without removal of \ escapes INIT.
+if test -n "\${ZSH_VERSION+set}"; then
+   setopt NO_GLOB_SUBST
+fi
+
+
+    PACKAGE='$PACKAGE'
+    VERSION='$VERSION'
+    RM='$RM'
+    ofile='$ofile'
+
+
+
+
+
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+  case $ac_config_target in
+    "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h:config.in" ;;
+    "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;;
+    "mpn/$tmp_fn.$tmp_ext") CONFIG_LINKS="$CONFIG_LINKS mpn/$tmp_fn.$tmp_ext:mpn/$tmp_dir/$tmp_base.$tmp_ext" ;;
+    "gmp-mparam.h") CONFIG_LINKS="$CONFIG_LINKS gmp-mparam.h:mpn/$gmp_mparam_dir/gmp-mparam.h" ;;
+    "demos/pexpr-config.h") CONFIG_FILES="$CONFIG_FILES demos/pexpr-config.h:demos/pexpr-config-h.in" ;;
+    "demos/calc/calc-config.h") CONFIG_FILES="$CONFIG_FILES demos/calc/calc-config.h:demos/calc/calc-config-h.in" ;;
+    "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+    "mpf/Makefile") CONFIG_FILES="$CONFIG_FILES mpf/Makefile" ;;
+    "mpn/Makefile") CONFIG_FILES="$CONFIG_FILES mpn/Makefile" ;;
+    "mpq/Makefile") CONFIG_FILES="$CONFIG_FILES mpq/Makefile" ;;
+    "mpz/Makefile") CONFIG_FILES="$CONFIG_FILES mpz/Makefile" ;;
+    "printf/Makefile") CONFIG_FILES="$CONFIG_FILES printf/Makefile" ;;
+    "scanf/Makefile") CONFIG_FILES="$CONFIG_FILES scanf/Makefile" ;;
+    "rand/Makefile") CONFIG_FILES="$CONFIG_FILES rand/Makefile" ;;
+    "cxx/Makefile") CONFIG_FILES="$CONFIG_FILES cxx/Makefile" ;;
+    "tests/Makefile") CONFIG_FILES="$CONFIG_FILES tests/Makefile" ;;
+    "tests/devel/Makefile") CONFIG_FILES="$CONFIG_FILES tests/devel/Makefile" ;;
+    "tests/mpf/Makefile") CONFIG_FILES="$CONFIG_FILES tests/mpf/Makefile" ;;
+    "tests/mpn/Makefile") CONFIG_FILES="$CONFIG_FILES tests/mpn/Makefile" ;;
+    "tests/mpq/Makefile") CONFIG_FILES="$CONFIG_FILES tests/mpq/Makefile" ;;
+    "tests/mpz/Makefile") CONFIG_FILES="$CONFIG_FILES tests/mpz/Makefile" ;;
+    "tests/rand/Makefile") CONFIG_FILES="$CONFIG_FILES tests/rand/Makefile" ;;
+    "tests/misc/Makefile") CONFIG_FILES="$CONFIG_FILES tests/misc/Makefile" ;;
+    "tests/cxx/Makefile") CONFIG_FILES="$CONFIG_FILES tests/cxx/Makefile" ;;
+    "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;;
+    "tune/Makefile") CONFIG_FILES="$CONFIG_FILES tune/Makefile" ;;
+    "demos/Makefile") CONFIG_FILES="$CONFIG_FILES demos/Makefile" ;;
+    "demos/calc/Makefile") CONFIG_FILES="$CONFIG_FILES demos/calc/Makefile" ;;
+    "demos/expr/Makefile") CONFIG_FILES="$CONFIG_FILES demos/expr/Makefile" ;;
+    "gmp.h") CONFIG_FILES="$CONFIG_FILES gmp.h:gmp-h.in" ;;
+    "gmp.pc") CONFIG_FILES="$CONFIG_FILES gmp.pc:gmp.pc.in" ;;
+    "gmpxx.pc") CONFIG_FILES="$CONFIG_FILES gmpxx.pc:gmpxx.pc.in" ;;
+
+  *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+  esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used.  Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+  test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+  test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+  test "${CONFIG_LINKS+set}" = set || CONFIG_LINKS=$config_links
+  test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands
+fi
+
+# Have a temporary directory for convenience.  Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+  tmp= ac_tmp=
+  trap 'exit_status=$?
+  : "${ac_tmp:=$tmp}"
+  { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+  trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+  tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+  test -d "$tmp"
+}  ||
+{
+  tmp=./conf$$-$RANDOM
+  (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+  eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+  ac_cs_awk_cr='\\r'
+else
+  ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+  echo "cat >conf$$subs.awk <<_ACEOF" &&
+  echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+  echo "_ACEOF"
+} >conf$$subs.sh ||
+  as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+  . ./conf$$subs.sh ||
+    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+  ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+  if test $ac_delim_n = $ac_delim_num; then
+    break
+  elif $ac_last_try; then
+    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+  N
+  s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+  for (key in S) S_is_set[key] = 1
+  FS = ""
+
+}
+{
+  line = $ 0
+  nfields = split(line, field, "@")
+  substed = 0
+  len = length(field[1])
+  for (i = 2; i < nfields; i++) {
+    key = field[i]
+    keylen = length(key)
+    if (S_is_set[key]) {
+      value = S[key]
+      line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+      len += length(value) + length(field[++i])
+      substed = 1
+    } else
+      len += 1 + keylen
+  }
+
+  print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+  sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+  cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+  || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[	 ]*VPATH[	 ]*=[	 ]*/{
+h
+s///
+s/^/:/
+s/[	 ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[	 ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[	 ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+# Set up the scripts for CONFIG_HEADERS section.
+# No need to generate them if there are no CONFIG_HEADERS.
+# This happens for instance with `./config.status Makefile'.
+if test -n "$CONFIG_HEADERS"; then
+cat >"$ac_tmp/defines.awk" <<\_ACAWK ||
+BEGIN {
+_ACEOF
+
+# Transform confdefs.h into an awk script `defines.awk', embedded as
+# here-document in config.status, that substitutes the proper values into
+# config.h.in to produce config.h.
+
+# Create a delimiter string that does not exist in confdefs.h, to ease
+# handling of long lines.
+ac_delim='%!_!# '
+for ac_last_try in false false :; do
+  ac_tt=`sed -n "/$ac_delim/p" confdefs.h`
+  if test -z "$ac_tt"; then
+    break
+  elif $ac_last_try; then
+    as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+
+# For the awk script, D is an array of macro values keyed by name,
+# likewise P contains macro parameters if any.  Preserve backslash
+# newline sequences.
+
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+sed -n '
+s/.\{148\}/&'"$ac_delim"'/g
+t rset
+:rset
+s/^[	 ]*#[	 ]*define[	 ][	 ]*/ /
+t def
+d
+:def
+s/\\$//
+t bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[	 ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3"/p
+s/^ \('"$ac_word_re"'\)[	 ]*\(.*\)/D["\1"]=" \2"/p
+d
+:bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[	 ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3\\\\\\n"\\/p
+t cont
+s/^ \('"$ac_word_re"'\)[	 ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p
+t cont
+d
+:cont
+n
+s/.\{148\}/&'"$ac_delim"'/g
+t clear
+:clear
+s/\\$//
+t bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/"/p
+d
+:bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
+b cont
+' <confdefs.h | sed '
+s/'"$ac_delim"'/"\\\
+"/g' >>$CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+  for (key in D) D_is_set[key] = 1
+  FS = ""
+}
+/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ {
+  line = \$ 0
+  split(line, arg, " ")
+  if (arg[1] == "#") {
+    defundef = arg[2]
+    mac1 = arg[3]
+  } else {
+    defundef = substr(arg[1], 2)
+    mac1 = arg[2]
+  }
+  split(mac1, mac2, "(") #)
+  macro = mac2[1]
+  prefix = substr(line, 1, index(line, defundef) - 1)
+  if (D_is_set[macro]) {
+    # Preserve the white space surrounding the "#".
+    print prefix "define", macro P[macro] D[macro]
+    next
+  } else {
+    # Replace #undef with comments.  This is necessary, for example,
+    # in the case of _POSIX_SOURCE, which is predefined and required
+    # on some systems where configure will not decide to define it.
+    if (defundef == "undef") {
+      print "/*", prefix defundef, macro, "*/"
+      next
+    }
+  }
+}
+{ print }
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+  as_fn_error $? "could not setup config headers machinery" "$LINENO" 5
+fi # test -n "$CONFIG_HEADERS"
+
+
+eval set X "  :F $CONFIG_FILES  :H $CONFIG_HEADERS  :L $CONFIG_LINKS  :C $CONFIG_COMMANDS"
+shift
+for ac_tag
+do
+  case $ac_tag in
+  :[FHLC]) ac_mode=$ac_tag; continue;;
+  esac
+  case $ac_mode$ac_tag in
+  :[FHL]*:*);;
+  :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+  :[FH]-) ac_tag=-:-;;
+  :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+  esac
+  ac_save_IFS=$IFS
+  IFS=:
+  set x $ac_tag
+  IFS=$ac_save_IFS
+  shift
+  ac_file=$1
+  shift
+
+  case $ac_mode in
+  :L) ac_source=$1;;
+  :[FH])
+    ac_file_inputs=
+    for ac_f
+    do
+      case $ac_f in
+      -) ac_f="$ac_tmp/stdin";;
+      *) # Look for the file first in the build tree, then in the source tree
+	 # (if the path is not absolute).  The absolute path cannot be DOS-style,
+	 # because $ac_f cannot contain `:'.
+	 test -f "$ac_f" ||
+	   case $ac_f in
+	   [\\/$]*) false;;
+	   *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+	   esac ||
+	   as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+      esac
+      case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+      as_fn_append ac_file_inputs " '$ac_f'"
+    done
+
+    # Let's still pretend it is `configure' which instantiates (i.e., don't
+    # use $as_me), people would be surprised to read:
+    #    /* config.h.  Generated by config.status.  */
+    configure_input='Generated from '`
+	  $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+	`' by configure.'
+    if test x"$ac_file" != x-; then
+      configure_input="$ac_file.  $configure_input"
+      { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+    fi
+    # Neutralize special characters interpreted by sed in replacement strings.
+    case $configure_input in #(
+    *\&* | *\|* | *\\* )
+       ac_sed_conf_input=`$as_echo "$configure_input" |
+       sed 's/[\\\\&|]/\\\\&/g'`;; #(
+    *) ac_sed_conf_input=$configure_input;;
+    esac
+
+    case $ac_tag in
+    *:-:* | *:-) cat >"$ac_tmp/stdin" \
+      || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+    esac
+    ;;
+  esac
+
+  ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$ac_file" : 'X\(//\)[^/]' \| \
+	 X"$ac_file" : 'X\(//\)$' \| \
+	 X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+  as_dir="$ac_dir"; as_fn_mkdir_p
+  ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+  case $ac_mode in
+  :F)
+  #
+  # CONFIG_FILE
+  #
+
+  case $INSTALL in
+  [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+  *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
+  esac
+  ac_MKDIR_P=$MKDIR_P
+  case $MKDIR_P in
+  [\\/$]* | ?:[\\/]* ) ;;
+  */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;;
+  esac
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+  p
+  q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+  ac_datarootdir_hack='
+  s&@datadir@&$datadir&g
+  s&@docdir@&$docdir&g
+  s&@infodir@&$infodir&g
+  s&@localedir@&$localedir&g
+  s&@mandir@&$mandir&g
+  s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+s&@INSTALL@&$ac_INSTALL&;t t
+s&@MKDIR_P@&$ac_MKDIR_P&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+  >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+  { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+  { ac_out=`sed -n '/^[	 ]*datarootdir[	 ]*:*=/p' \
+      "$ac_tmp/out"`; test -z "$ac_out"; } &&
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined" >&2;}
+
+  rm -f "$ac_tmp/stdin"
+  case $ac_file in
+  -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+  *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+  esac \
+  || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+  :H)
+  #
+  # CONFIG_HEADER
+  #
+  if test x"$ac_file" != x-; then
+    {
+      $as_echo "/* $configure_input  */" \
+      && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs"
+    } >"$ac_tmp/config.h" \
+      || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+    if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
+$as_echo "$as_me: $ac_file is unchanged" >&6;}
+    else
+      rm -f "$ac_file"
+      mv "$ac_tmp/config.h" "$ac_file" \
+	|| as_fn_error $? "could not create $ac_file" "$LINENO" 5
+    fi
+  else
+    $as_echo "/* $configure_input  */" \
+      && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \
+      || as_fn_error $? "could not create -" "$LINENO" 5
+  fi
+# Compute "$ac_file"'s index in $config_headers.
+_am_arg="$ac_file"
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+  case $_am_header in
+    $_am_arg | $_am_arg:* )
+      break ;;
+    * )
+      _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+  esac
+done
+echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" ||
+$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$_am_arg" : 'X\(//\)[^/]' \| \
+	 X"$_am_arg" : 'X\(//\)$' \| \
+	 X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$_am_arg" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`/stamp-h$_am_stamp_count
+ ;;
+  :L)
+  #
+  # CONFIG_LINK
+  #
+
+  if test "$ac_source" = "$ac_file" && test "$srcdir" = '.'; then
+    :
+  else
+    # Prefer the file from the source tree if names are identical.
+    if test "$ac_source" = "$ac_file" || test ! -r "$ac_source"; then
+      ac_source=$srcdir/$ac_source
+    fi
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: linking $ac_source to $ac_file" >&5
+$as_echo "$as_me: linking $ac_source to $ac_file" >&6;}
+
+    if test ! -r "$ac_source"; then
+      as_fn_error $? "$ac_source: file not found" "$LINENO" 5
+    fi
+    rm -f "$ac_file"
+
+    # Try a relative symlink, then a hard link, then a copy.
+    case $ac_source in
+    [\\/$]* | ?:[\\/]* ) ac_rel_source=$ac_source ;;
+	*) ac_rel_source=$ac_top_build_prefix$ac_source ;;
+    esac
+    ln -s "$ac_rel_source" "$ac_file" 2>/dev/null ||
+      ln "$ac_source" "$ac_file" 2>/dev/null ||
+      cp -p "$ac_source" "$ac_file" ||
+      as_fn_error $? "cannot link or copy $ac_source to $ac_file" "$LINENO" 5
+  fi
+ ;;
+  :C)  { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5
+$as_echo "$as_me: executing $ac_file commands" >&6;}
+ ;;
+  esac
+
+
+  case $ac_file$ac_mode in
+    "libtool":C)
+
+    # See if we are running on zsh, and set the options that allow our
+    # commands through without removal of \ escapes.
+    if test -n "${ZSH_VERSION+set}"; then
+      setopt NO_GLOB_SUBST
+    fi
+
+    cfgfile=${ofile}T
+    trap "$RM \"$cfgfile\"; exit 1" 1 2 15
+    $RM "$cfgfile"
+
+    cat <<_LT_EOF >> "$cfgfile"
+#! $SHELL
+# Generated automatically by $as_me ($PACKAGE) $VERSION
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+
+# Provide generalized library-building support services.
+# Written by Gordon Matzigkeit, 1996
+
+# Copyright (C) 2014 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions.  There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# GNU Libtool is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of of the License, or
+# (at your option) any later version.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program or library that is built
+# using GNU Libtool, you may include this file under the  same
+# distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+
+# The names of the tagged configurations supported by this script.
+available_tags='CXX '
+
+# Configured defaults for sys_lib_dlsearch_path munging.
+: \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"}
+
+# ### BEGIN LIBTOOL CONFIG
+
+# A BSD- or MS-compatible name lister.
+NM=$lt_NM
+
+# Assembler program.
+AS=$lt_AS
+
+# DLL creation program.
+DLLTOOL=$lt_DLLTOOL
+
+# Object dumper program.
+OBJDUMP=$lt_OBJDUMP
+
+# Which release of libtool.m4 was used?
+macro_version=$macro_version
+macro_revision=$macro_revision
+
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
+# Whether or not to build static libraries.
+build_old_libs=$enable_static
+
+# What type of objects to build.
+pic_mode=$pic_mode
+
+# Whether or not to optimize for fast installation.
+fast_install=$enable_fast_install
+
+# Shared archive member basename,for filename based shared library versioning on AIX.
+shared_archive_member_spec=$shared_archive_member_spec
+
+# Shell to use when invoking shell scripts.
+SHELL=$lt_SHELL
+
+# An echo program that protects backslashes.
+ECHO=$lt_ECHO
+
+# The PATH separator for the build system.
+PATH_SEPARATOR=$lt_PATH_SEPARATOR
+
+# The host system.
+host_alias=$host_alias
+host=$host
+host_os=$host_os
+
+# The build system.
+build_alias=$build_alias
+build=$build
+build_os=$build_os
+
+# A sed program that does not truncate output.
+SED=$lt_SED
+
+# Sed that helps us avoid accidentally triggering echo(1) options like -n.
+Xsed="\$SED -e 1s/^X//"
+
+# A grep program that handles long lines.
+GREP=$lt_GREP
+
+# An ERE matcher.
+EGREP=$lt_EGREP
+
+# A literal string matcher.
+FGREP=$lt_FGREP
+
+# Whether we need soft or hard links.
+LN_S=$lt_LN_S
+
+# What is the maximum length of a command?
+max_cmd_len=$max_cmd_len
+
+# Object file suffix (normally "o").
+objext=$ac_objext
+
+# Executable file suffix (normally "").
+exeext=$exeext
+
+# whether the shell understands "unset".
+lt_unset=$lt_unset
+
+# turn spaces into newlines.
+SP2NL=$lt_lt_SP2NL
+
+# turn newlines into spaces.
+NL2SP=$lt_lt_NL2SP
+
+# convert \$build file names to \$host format.
+to_host_file_cmd=$lt_cv_to_host_file_cmd
+
+# convert \$build files to toolchain format.
+to_tool_file_cmd=$lt_cv_to_tool_file_cmd
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method=$lt_deplibs_check_method
+
+# Command to use when deplibs_check_method = "file_magic".
+file_magic_cmd=$lt_file_magic_cmd
+
+# How to find potential files when deplibs_check_method = "file_magic".
+file_magic_glob=$lt_file_magic_glob
+
+# Find potential files using nocaseglob when deplibs_check_method = "file_magic".
+want_nocaseglob=$lt_want_nocaseglob
+
+# Command to associate shared and link libraries.
+sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd
+
+# The archiver.
+AR=$lt_AR
+
+# Flags to create an archive.
+AR_FLAGS=$lt_AR_FLAGS
+
+# How to feed a file listing to the archiver.
+archiver_list_spec=$lt_archiver_list_spec
+
+# A symbol stripping program.
+STRIP=$lt_STRIP
+
+# Commands used to install an old-style archive.
+RANLIB=$lt_RANLIB
+old_postinstall_cmds=$lt_old_postinstall_cmds
+old_postuninstall_cmds=$lt_old_postuninstall_cmds
+
+# Whether to use a lock for old archive extraction.
+lock_old_archive_extraction=$lock_old_archive_extraction
+
+# A C compiler.
+LTCC=$lt_CC
+
+# LTCC compiler flags.
+LTCFLAGS=$lt_CFLAGS
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
+
+# Transform the output of nm in a proper C declaration.
+global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
+
+# Transform the output of nm into a list of symbols to manually relocate.
+global_symbol_to_import=$lt_lt_cv_sys_global_symbol_to_import
+
+# Transform the output of nm in a C name address pair.
+global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
+
+# Transform the output of nm in a C name address pair when lib prefix is needed.
+global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix
+
+# The name lister interface.
+nm_interface=$lt_lt_cv_nm_interface
+
+# Specify filename containing input files for \$NM.
+nm_file_list_spec=$lt_nm_file_list_spec
+
+# The root where to search for dependent libraries,and where our libraries should be installed.
+lt_sysroot=$lt_sysroot
+
+# Command to truncate a binary pipe.
+lt_truncate_bin=$lt_lt_cv_truncate_bin
+
+# The name of the directory that contains temporary libtool files.
+objdir=$objdir
+
+# Used to examine libraries when file_magic_cmd begins with "file".
+MAGIC_CMD=$MAGIC_CMD
+
+# Must we lock files when doing compilation?
+need_locks=$lt_need_locks
+
+# Manifest tool.
+MANIFEST_TOOL=$lt_MANIFEST_TOOL
+
+# Tool to manipulate archived DWARF debug symbol files on Mac OS X.
+DSYMUTIL=$lt_DSYMUTIL
+
+# Tool to change global to local symbols on Mac OS X.
+NMEDIT=$lt_NMEDIT
+
+# Tool to manipulate fat objects and archives on Mac OS X.
+LIPO=$lt_LIPO
+
+# ldd/readelf like tool for Mach-O binaries on Mac OS X.
+OTOOL=$lt_OTOOL
+
+# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4.
+OTOOL64=$lt_OTOOL64
+
+# Old archive suffix (normally "a").
+libext=$libext
+
+# Shared library suffix (normally ".so").
+shrext_cmds=$lt_shrext_cmds
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=$lt_extract_expsyms_cmds
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at link time.
+variables_saved_for_relink=$lt_variables_saved_for_relink
+
+# Do we need the "lib" prefix for modules?
+need_lib_prefix=$need_lib_prefix
+
+# Do we need a version for libraries?
+need_version=$need_version
+
+# Library versioning type.
+version_type=$version_type
+
+# Shared library runtime path variable.
+runpath_var=$runpath_var
+
+# Shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+
+# Format of library name prefix.
+libname_spec=$lt_libname_spec
+
+# List of archive names.  First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME
+library_names_spec=$lt_library_names_spec
+
+# The coded name of the library, if different from the real name.
+soname_spec=$lt_soname_spec
+
+# Permission mode override for installation of shared libraries.
+install_override_mode=$lt_install_override_mode
+
+# Command to use after installation of a shared archive.
+postinstall_cmds=$lt_postinstall_cmds
+
+# Command to use after uninstallation of a shared archive.
+postuninstall_cmds=$lt_postuninstall_cmds
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=$lt_finish_cmds
+
+# As "finish_cmds", except a single script fragment to be evaled but
+# not shown.
+finish_eval=$lt_finish_eval
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=$hardcode_into_libs
+
+# Compile-time system search path for libraries.
+sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
+
+# Detected run-time system search path for libraries.
+sys_lib_dlsearch_path_spec=$lt_configure_time_dlsearch_path
+
+# Explicit LT_SYS_LIBRARY_PATH set during ./configure time.
+configure_time_lt_sys_library_path=$lt_configure_time_lt_sys_library_path
+
+# Whether dlopen is supported.
+dlopen_support=$enable_dlopen
+
+# Whether dlopen of programs is supported.
+dlopen_self=$enable_dlopen_self
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=$enable_dlopen_self_static
+
+# Commands to strip libraries.
+old_striplib=$lt_old_striplib
+striplib=$lt_striplib
+
+
+# The linker used to build libraries.
+LD=$lt_LD
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag
+reload_cmds=$lt_reload_cmds
+
+# Commands used to build an old-style archive.
+old_archive_cmds=$lt_old_archive_cmds
+
+# A language specific compiler.
+CC=$lt_compiler
+
+# Is the compiler the GNU compiler?
+with_gcc=$GCC
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc
+
+# Whether or not to disallow shared libs when runtime libs are static.
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec
+
+# Whether the compiler copes with passing no objects directly.
+compiler_needs_object=$lt_compiler_needs_object
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds
+
+# Commands used to build a shared archive.
+archive_cmds=$lt_archive_cmds
+archive_expsym_cmds=$lt_archive_expsym_cmds
+
+# Commands used to build a loadable module if different from building
+# a shared archive.
+module_cmds=$lt_module_cmds
+module_expsym_cmds=$lt_module_expsym_cmds
+
+# Whether we are building with GNU ld or not.
+with_gnu_ld=$lt_with_gnu_ld
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag
+
+# Flag that enforces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec
+
+# Whether we need a single "-rpath" flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator
+
+# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes
+# DIR into the resulting binary.
+hardcode_direct=$hardcode_direct
+
+# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes
+# DIR into the resulting binary and the resulting library dependency is
+# "absolute",i.e impossible to change by setting \$shlibpath_var if the
+# library is relocated.
+hardcode_direct_absolute=$hardcode_direct_absolute
+
+# Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+# into the resulting binary.
+hardcode_minus_L=$hardcode_minus_L
+
+# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+# into the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var
+
+# Set to "yes" if building a shared library automatically hardcodes DIR
+# into the library and all subsequent libraries and executables linked
+# against it.
+hardcode_automatic=$hardcode_automatic
+
+# Set to yes if linker adds runtime paths of dependent libraries
+# to runtime path list.
+inherit_rpath=$inherit_rpath
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs
+
+# Set to "yes" if exported symbols are required.
+always_export_symbols=$always_export_symbols
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms
+
+# Commands necessary for linking programs (against libraries) with templates.
+prelink_cmds=$lt_prelink_cmds
+
+# Commands necessary for finishing linking programs.
+postlink_cmds=$lt_postlink_cmds
+
+# Specify filename containing input files.
+file_list_spec=$lt_file_list_spec
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action
+
+# The directories searched by this compiler when creating a shared library.
+compiler_lib_search_dirs=$lt_compiler_lib_search_dirs
+
+# Dependencies to place before and after the objects being linked to
+# create a shared library.
+predep_objects=$lt_predep_objects
+postdep_objects=$lt_postdep_objects
+predeps=$lt_predeps
+postdeps=$lt_postdeps
+
+# The library search path used internally by the compiler when linking
+# a shared library.
+compiler_lib_search_path=$lt_compiler_lib_search_path
+
+# ### END LIBTOOL CONFIG
+
+_LT_EOF
+
+    cat <<'_LT_EOF' >> "$cfgfile"
+
+# ### BEGIN FUNCTIONS SHARED WITH CONFIGURE
+
+# func_munge_path_list VARIABLE PATH
+# -----------------------------------
+# VARIABLE is name of variable containing _space_ separated list of
+# directories to be munged by the contents of PATH, which is string
+# having a format:
+# "DIR[:DIR]:"
+#       string "DIR[ DIR]" will be prepended to VARIABLE
+# ":DIR[:DIR]"
+#       string "DIR[ DIR]" will be appended to VARIABLE
+# "DIRP[:DIRP]::[DIRA:]DIRA"
+#       string "DIRP[ DIRP]" will be prepended to VARIABLE and string
+#       "DIRA[ DIRA]" will be appended to VARIABLE
+# "DIR[:DIR]"
+#       VARIABLE will be replaced by "DIR[ DIR]"
+func_munge_path_list ()
+{
+    case x$2 in
+    x)
+        ;;
+    *:)
+        eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\"
+        ;;
+    x:*)
+        eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\"
+        ;;
+    *::*)
+        eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\"
+        eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\"
+        ;;
+    *)
+        eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\"
+        ;;
+    esac
+}
+
+
+# Calculate cc_basename.  Skip known compiler wrappers and cross-prefix.
+func_cc_basename ()
+{
+    for cc_temp in $*""; do
+      case $cc_temp in
+        compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+        distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+        \-*) ;;
+        *) break;;
+      esac
+    done
+    func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+}
+
+
+# ### END FUNCTIONS SHARED WITH CONFIGURE
+
+_LT_EOF
+
+  case $host_os in
+  aix3*)
+    cat <<\_LT_EOF >> "$cfgfile"
+# AIX sometimes has problems with the GCC collect2 program.  For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test set != "${COLLECT_NAMES+set}"; then
+  COLLECT_NAMES=
+  export COLLECT_NAMES
+fi
+_LT_EOF
+    ;;
+  esac
+
+
+ltmain=$ac_aux_dir/ltmain.sh
+
+
+  # We use sed instead of cat because bash on DJGPP gets confused if
+  # if finds mixed CR/LF and LF-only lines.  Since sed operates in
+  # text mode, it properly converts lines to CR/LF.  This bash problem
+  # is reportedly fixed, but why not run on old versions too?
+  sed '$q' "$ltmain" >> "$cfgfile" \
+     || (rm -f "$cfgfile"; exit 1)
+
+   mv -f "$cfgfile" "$ofile" ||
+    (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+  chmod +x "$ofile"
+
+
+    cat <<_LT_EOF >> "$ofile"
+
+# ### BEGIN LIBTOOL TAG CONFIG: CXX
+
+# The linker used to build libraries.
+LD=$lt_LD_CXX
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag_CXX
+reload_cmds=$lt_reload_cmds_CXX
+
+# Commands used to build an old-style archive.
+old_archive_cmds=$lt_old_archive_cmds_CXX
+
+# A language specific compiler.
+CC=$lt_compiler_CXX
+
+# Is the compiler the GNU compiler?
+with_gcc=$GCC_CXX
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_CXX
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic_CXX
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl_CXX
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static_CXX
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc_CXX
+
+# Whether or not to disallow shared libs when runtime libs are static.
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_CXX
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_CXX
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec_CXX
+
+# Whether the compiler copes with passing no objects directly.
+compiler_needs_object=$lt_compiler_needs_object_CXX
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_CXX
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_CXX
+
+# Commands used to build a shared archive.
+archive_cmds=$lt_archive_cmds_CXX
+archive_expsym_cmds=$lt_archive_expsym_cmds_CXX
+
+# Commands used to build a loadable module if different from building
+# a shared archive.
+module_cmds=$lt_module_cmds_CXX
+module_expsym_cmds=$lt_module_expsym_cmds_CXX
+
+# Whether we are building with GNU ld or not.
+with_gnu_ld=$lt_with_gnu_ld_CXX
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag_CXX
+
+# Flag that enforces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag_CXX
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX
+
+# Whether we need a single "-rpath" flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX
+
+# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes
+# DIR into the resulting binary.
+hardcode_direct=$hardcode_direct_CXX
+
+# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes
+# DIR into the resulting binary and the resulting library dependency is
+# "absolute",i.e impossible to change by setting \$shlibpath_var if the
+# library is relocated.
+hardcode_direct_absolute=$hardcode_direct_absolute_CXX
+
+# Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+# into the resulting binary.
+hardcode_minus_L=$hardcode_minus_L_CXX
+
+# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+# into the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var_CXX
+
+# Set to "yes" if building a shared library automatically hardcodes DIR
+# into the library and all subsequent libraries and executables linked
+# against it.
+hardcode_automatic=$hardcode_automatic_CXX
+
+# Set to yes if linker adds runtime paths of dependent libraries
+# to runtime path list.
+inherit_rpath=$inherit_rpath_CXX
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs_CXX
+
+# Set to "yes" if exported symbols are required.
+always_export_symbols=$always_export_symbols_CXX
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds_CXX
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms_CXX
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms_CXX
+
+# Commands necessary for linking programs (against libraries) with templates.
+prelink_cmds=$lt_prelink_cmds_CXX
+
+# Commands necessary for finishing linking programs.
+postlink_cmds=$lt_postlink_cmds_CXX
+
+# Specify filename containing input files.
+file_list_spec=$lt_file_list_spec_CXX
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action_CXX
+
+# The directories searched by this compiler when creating a shared library.
+compiler_lib_search_dirs=$lt_compiler_lib_search_dirs_CXX
+
+# Dependencies to place before and after the objects being linked to
+# create a shared library.
+predep_objects=$lt_predep_objects_CXX
+postdep_objects=$lt_postdep_objects_CXX
+predeps=$lt_predeps_CXX
+postdeps=$lt_postdeps_CXX
+
+# The library search path used internally by the compiler when linking
+# a shared library.
+compiler_lib_search_path=$lt_compiler_lib_search_path_CXX
+
+# ### END LIBTOOL TAG CONFIG: CXX
+_LT_EOF
+
+ ;;
+
+  esac
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+  as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded.  So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status.  When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+  ac_cs_success=:
+  ac_config_status_args=
+  test "$silent" = yes &&
+    ac_config_status_args="$ac_config_status_args --quiet"
+  exec 5>/dev/null
+  $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+  exec 5>>config.log
+  # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+  # would make configure fail if this is the last instruction.
+  $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: summary of build options:
+
+  Version:           ${PACKAGE_STRING}
+  Host type:         ${host}
+  ABI:               ${ABI}
+  Install prefix:    ${prefix}
+  Compiler:          ${CC}
+  Static libraries:  ${enable_static}
+  Shared libraries:  ${enable_shared}
+" >&5
+$as_echo "$as_me: summary of build options:
+
+  Version:           ${PACKAGE_STRING}
+  Host type:         ${host}
+  ABI:               ${ABI}
+  Install prefix:    ${prefix}
+  Compiler:          ${CC}
+  Static libraries:  ${enable_static}
+  Shared libraries:  ${enable_shared}
+" >&6;}
diff --git a/third_party/gmp/configure.ac b/third_party/gmp/configure.ac
new file mode 100644
index 0000000..024cacb
--- /dev/null
+++ b/third_party/gmp/configure.ac
@@ -0,0 +1,4019 @@
+dnl  Process this file with autoconf to produce a configure script.
+
+
+define(GMP_COPYRIGHT,[[
+
+Copyright 1996-2020 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.
+]])
+
+AC_COPYRIGHT(GMP_COPYRIGHT)
+AH_TOP(/*GMP_COPYRIGHT*/)
+
+AC_REVISION($Revision$)
+AC_PREREQ(2.59)
+AC_INIT(GNU MP, GMP_VERSION, [gmp-bugs@gmplib.org, see https://gmplib.org/manual/Reporting-Bugs.html], gmp)
+AC_CONFIG_SRCDIR(gmp-impl.h)
+m4_pattern_forbid([^[ \t]*GMP_])
+m4_pattern_allow(GMP_LDFLAGS)
+m4_pattern_allow(GMP_LIMB_BITS)
+m4_pattern_allow(GMP_MPARAM_H_SUGGEST)
+m4_pattern_allow(GMP_NAIL_BITS)
+m4_pattern_allow(GMP_NUMB_BITS)
+m4_pattern_allow(GMP_NONSTD_ABI)
+m4_pattern_allow(GMP_CPU_TYPE)
+m4_pattern_allow(GMP_AVX_NOT_REALLY_AVAILABLE)
+
+# If --target is not used then $target_alias is empty, but if say
+# "./configure athlon-pc-freebsd3.5" is used, then all three of
+# $build_alias, $host_alias and $target_alias are set to
+# "athlon-pc-freebsd3.5".
+#
+if test -n "$target_alias" && test "$target_alias" != "$host_alias"; then
+  AC_MSG_ERROR([--target is not appropriate for GMP
+Use --build=CPU-VENDOR-OS if you need to specify your CPU and/or system
+explicitly.  Use --host if cross-compiling (see "Installing GMP" in the
+manual for more on this).])
+fi
+
+GMP_INIT(config.m4)
+
+AC_CANONICAL_HOST
+
+dnl  Automake "no-dependencies" is used because include file dependencies
+dnl  are not useful to us.  Pretty much everything depends just on gmp.h,
+dnl  gmp-impl.h and longlong.h, and yet only rarely does everything need to
+dnl  be rebuilt for changes to those files.
+dnl
+dnl  "no-dependencies" also helps with the way we're setup to run
+dnl  AC_PROG_CXX only conditionally.  If dependencies are used then recent
+dnl  automake (eg 1.7.2) appends an AM_CONDITIONAL to AC_PROG_CXX, and then
+dnl  gets upset if it's not actually executed.
+dnl
+dnl  Note that there's a copy of these options in the top-level Makefile.am,
+dnl  so update there too if changing anything.
+dnl
+AM_INIT_AUTOMAKE([1.8 gnu no-dependencies subdir-objects])
+AC_CONFIG_HEADERS(config.h:config.in)
+AM_MAINTAINER_MODE
+
+
+AC_ARG_ENABLE(assert,
+AC_HELP_STRING([--enable-assert],[enable ASSERT checking [default=no]]),
+[case $enableval in
+yes|no) ;;
+*) AC_MSG_ERROR([bad value $enableval for --enable-assert, need yes or no]) ;;
+esac],
+[enable_assert=no])
+
+if test "$enable_assert" = "yes"; then
+  AC_DEFINE(WANT_ASSERT,1,
+  [Define to 1 to enable ASSERT checking, per --enable-assert])
+  want_assert_01=1
+else
+  want_assert_01=0
+fi
+GMP_DEFINE_RAW(["define(<WANT_ASSERT>,$want_assert_01)"])
+
+
+AC_ARG_ENABLE(alloca,
+AC_HELP_STRING([--enable-alloca],[how to get temp memory [default=reentrant]]),
+[case $enableval in
+alloca|malloc-reentrant|malloc-notreentrant) ;;
+yes|no|reentrant|notreentrant) ;;
+debug) ;;
+*)
+  AC_MSG_ERROR([bad value $enableval for --enable-alloca, need one of:
+yes no reentrant notreentrant alloca malloc-reentrant malloc-notreentrant debug]) ;;
+esac],
+[enable_alloca=reentrant])
+
+
+# IMPROVE ME: The default for C++ is disabled.  The tests currently
+# performed below for a working C++ compiler are not particularly strong,
+# and in general can't be expected to get the right setup on their own.  The
+# most significant problem is getting the ABI the same.  Defaulting CXXFLAGS
+# to CFLAGS takes only a small step towards this.  It's also probably worth
+# worrying whether the C and C++ runtimes from say gcc and a vendor C++ can
+# work together.  Some rather broken C++ installations were encountered
+# during testing, and though such things clearly aren't GMP's problem, if
+# --enable-cxx=detect were to be the default then some careful checks of
+# which, if any, C++ compiler on the system is up to scratch would be
+# wanted.
+#
+AC_ARG_ENABLE(cxx,
+AC_HELP_STRING([--enable-cxx],[enable C++ support [default=no]]),
+[case $enableval in
+yes|no|detect) ;;
+*) AC_MSG_ERROR([bad value $enableval for --enable-cxx, need yes/no/detect]) ;;
+esac],
+[enable_cxx=no])
+
+
+AC_ARG_ENABLE(assembly,
+AC_HELP_STRING([--enable-assembly],[enable the use of assembly loops [default=yes]]),
+[case $enableval in
+yes|no) ;;
+*) AC_MSG_ERROR([bad value $enableval for --enable-assembly, need yes or no]) ;;
+esac],
+[enable_assembly=yes])
+
+
+AC_ARG_ENABLE(fft,
+AC_HELP_STRING([--enable-fft],[enable FFTs for multiplication [default=yes]]),
+[case $enableval in
+yes|no) ;;
+*) AC_MSG_ERROR([bad value $enableval for --enable-fft, need yes or no]) ;;
+esac],
+[enable_fft=yes])
+
+if test "$enable_fft" = "yes"; then
+  AC_DEFINE(WANT_FFT,1,
+  [Define to 1 to enable FFTs for multiplication, per --enable-fft])
+fi
+
+
+AC_ARG_ENABLE(old-fft-full,
+AC_HELP_STRING([--enable-old-fft-full],[enable old mpn_mul_fft_full for multiplication [default=no]]),
+[case $enableval in
+yes|no) ;;
+*) AC_MSG_ERROR([bad value $enableval for --enable-old-fft-full, need yes or no]) ;;
+esac],
+[enable_old_fft_full=no])
+
+if test "$enable_old_fft_full" = "yes"; then
+  AC_DEFINE(WANT_OLD_FFT_FULL,1,
+  [Define to 1 to enable old mpn_mul_fft_full for multiplication, per --enable-old-fft-full])
+fi
+
+
+AC_ARG_ENABLE(nails,
+AC_HELP_STRING([--enable-nails],[use nails on limbs [default=no]]),
+[case $enableval in
+[yes|no|[02468]|[0-9][02468]]) ;;
+[*[13579]])
+  AC_MSG_ERROR([bad value $enableval for --enable-nails, only even nail sizes supported]) ;;
+*)
+  AC_MSG_ERROR([bad value $enableval for --enable-nails, need yes/no/number]) ;;
+esac],
+[enable_nails=no])
+
+case $enable_nails in
+yes) GMP_NAIL_BITS=2 ;;
+no)  GMP_NAIL_BITS=0 ;;
+*)   GMP_NAIL_BITS=$enable_nails ;;
+esac
+AC_SUBST(GMP_NAIL_BITS)
+
+
+AC_ARG_ENABLE(profiling,
+AC_HELP_STRING([--enable-profiling],
+               [build with profiler support [default=no]]),
+[case $enableval in
+no|prof|gprof|instrument) ;;
+*) AC_MSG_ERROR([bad value $enableval for --enable-profiling, need no/prof/gprof/instrument]) ;;
+esac],
+[enable_profiling=no])
+
+case $enable_profiling in
+  prof)
+    AC_DEFINE(WANT_PROFILING_PROF, 1,
+              [Define to 1 if --enable-profiling=prof])
+    ;;
+  gprof)
+    AC_DEFINE(WANT_PROFILING_GPROF, 1,
+              [Define to 1 if --enable-profiling=gprof])
+    ;;
+  instrument)
+    AC_DEFINE(WANT_PROFILING_INSTRUMENT, 1,
+              [Define to 1 if --enable-profiling=instrument])
+    ;;
+esac
+
+GMP_DEFINE_RAW(["define(<WANT_PROFILING>,<\`$enable_profiling'>)"])
+
+# -fomit-frame-pointer is incompatible with -pg on some chips
+if test "$enable_profiling" = gprof; then
+  fomit_frame_pointer=
+else
+  fomit_frame_pointer="-fomit-frame-pointer"
+fi
+
+
+AC_ARG_WITH(readline,
+AC_HELP_STRING([--with-readline],
+               [readline support in demo programs [default=detect]]),
+[case $withval in
+yes|no|detect) ;;
+*) AC_MSG_ERROR([bad value $withval for --with-readline, need yes/no/detect]) ;;
+esac],
+[with_readline=detect])
+
+
+AC_ARG_ENABLE(fat,
+AC_HELP_STRING([--enable-fat],
+               [build fat libraries on systems that support it [default=no]]),
+[case $enableval in
+yes|no) ;;
+*) AC_MSG_ERROR([bad value $enableval for --enable-fat, need yes or no]) ;;
+esac],
+[enable_fat=no])
+
+
+AC_ARG_ENABLE(minithres,
+AC_HELP_STRING([--enable-minithres],
+               [choose minimal thresholds for testing [default=no]]),
+[case $enableval in
+yes|no) ;;
+*) AC_MSG_ERROR([bad value $enableval for --enable-minithres, need yes or no]) ;;
+esac],
+[enable_minithres=no])
+
+
+AC_ARG_ENABLE(fake-cpuid,
+AC_HELP_STRING([--enable-fake-cpuid],[enable GMP_CPU_TYPE faking cpuid [default=no]]),
+[case $enableval in
+yes|no) ;;
+*) AC_MSG_ERROR([bad value $enableval for --enable-fake-cpuid, need yes or no]) ;;
+esac],
+[enable_fake_cpuid=no])
+
+if test "$enable_fake_cpuid" = "yes"; then
+  AC_DEFINE(WANT_FAKE_CPUID,1,
+  [Define to 1 to enable GMP_CPU_TYPE faking cpuid, per --enable-fake-cpuid])
+fi
+
+
+if test $enable_fat = yes && test $enable_assembly = no ; then
+  AC_MSG_ERROR([when doing a fat build, disabling assembly will not work])
+fi
+
+if test $enable_fake_cpuid = yes && test $enable_fat = no ; then
+  AC_MSG_ERROR([--enable-fake-cpuid requires --enable-fat])
+fi
+
+
+tmp_host=`echo $host_cpu | sed 's/\./_/'`
+AC_DEFINE_UNQUOTED(HAVE_HOST_CPU_$tmp_host)
+GMP_DEFINE_RAW("define_not_for_expansion(\`HAVE_HOST_CPU_$tmp_host')", POST)
+
+dnl  The HAVE_HOST_CPU_ list here only needs to have entries for those which
+dnl  are going to be tested, not everything that can possibly be selected.
+dnl
+dnl  The HAVE_HOST_CPU_FAMILY_ list similarly, and note that the AC_DEFINEs
+dnl  for these are under the cpu specific setups below.
+
+AH_VERBATIM([HAVE_HOST_CPU_1],
+[/* Define one of these to 1 for the host CPU family.
+   If your CPU is not in any of these families, leave all undefined.
+   For an AMD64 chip, define "x86" in ABI=32, but not in ABI=64. */
+#undef HAVE_HOST_CPU_FAMILY_alpha
+#undef HAVE_HOST_CPU_FAMILY_m68k
+#undef HAVE_HOST_CPU_FAMILY_power
+#undef HAVE_HOST_CPU_FAMILY_powerpc
+#undef HAVE_HOST_CPU_FAMILY_x86
+#undef HAVE_HOST_CPU_FAMILY_x86_64
+
+/* Define one of the following to 1 for the host CPU, as per the output of
+   ./config.guess.  If your CPU is not listed here, leave all undefined.  */
+#undef HAVE_HOST_CPU_alphaev67
+#undef HAVE_HOST_CPU_alphaev68
+#undef HAVE_HOST_CPU_alphaev7
+#undef HAVE_HOST_CPU_m68020
+#undef HAVE_HOST_CPU_m68030
+#undef HAVE_HOST_CPU_m68040
+#undef HAVE_HOST_CPU_m68060
+#undef HAVE_HOST_CPU_m68360
+#undef HAVE_HOST_CPU_powerpc604
+#undef HAVE_HOST_CPU_powerpc604e
+#undef HAVE_HOST_CPU_powerpc750
+#undef HAVE_HOST_CPU_powerpc7400
+#undef HAVE_HOST_CPU_supersparc
+#undef HAVE_HOST_CPU_i386
+#undef HAVE_HOST_CPU_i586
+#undef HAVE_HOST_CPU_i686
+#undef HAVE_HOST_CPU_pentium
+#undef HAVE_HOST_CPU_pentiummmx
+#undef HAVE_HOST_CPU_pentiumpro
+#undef HAVE_HOST_CPU_pentium2
+#undef HAVE_HOST_CPU_pentium3
+#undef HAVE_HOST_CPU_pentium4
+#undef HAVE_HOST_CPU_core2
+#undef HAVE_HOST_CPU_nehalem
+#undef HAVE_HOST_CPU_westmere
+#undef HAVE_HOST_CPU_sandybridge
+#undef HAVE_HOST_CPU_ivybridge
+#undef HAVE_HOST_CPU_haswell
+#undef HAVE_HOST_CPU_broadwell
+#undef HAVE_HOST_CPU_skylake
+#undef HAVE_HOST_CPU_silvermont
+#undef HAVE_HOST_CPU_goldmont
+#undef HAVE_HOST_CPU_k8
+#undef HAVE_HOST_CPU_k10
+#undef HAVE_HOST_CPU_bulldozer
+#undef HAVE_HOST_CPU_piledriver
+#undef HAVE_HOST_CPU_steamroller
+#undef HAVE_HOST_CPU_excavator
+#undef HAVE_HOST_CPU_zen
+#undef HAVE_HOST_CPU_bobcat
+#undef HAVE_HOST_CPU_jaguar
+#undef HAVE_HOST_CPU_s390_z900
+#undef HAVE_HOST_CPU_s390_z990
+#undef HAVE_HOST_CPU_s390_z9
+#undef HAVE_HOST_CPU_s390_z10
+#undef HAVE_HOST_CPU_s390_z196
+
+/* Define to 1 iff we have a s390 with 64-bit registers.  */
+#undef HAVE_HOST_CPU_s390_zarch])
+
+
+# Table of compilers, options, and mpn paths.  This code has various related
+# purposes
+#
+#   - better default CC/CFLAGS selections than autoconf otherwise gives
+#   - default CC/CFLAGS selections for extra CPU types specific to GMP
+#   - a few tests for known bad compilers
+#   - choice of ABIs on suitable systems
+#   - selection of corresponding mpn search path
+#
+# After GMP specific searches and tests, the standard autoconf AC_PROG_CC is
+# called.  User selections of CC etc are respected.
+#
+# Care is taken not to use macros like AC_TRY_COMPILE during the GMP
+# pre-testing, since they of course depend on AC_PROG_CC, and also some of
+# them cache their results, which is not wanted.
+#
+# The ABI selection mechanism is unique to GMP.  All that reaches autoconf
+# is a different selection of CC/CFLAGS according to the best ABI the system
+# supports, and/or what the user selects.  Naturally the mpn assembler code
+# selected is very dependent on the ABI.
+#
+# The closest the standard tools come to a notion of ABI is something like
+# "sparc64" which encodes a CPU and an ABI together.  This doesn't seem to
+# scale well for GMP, where exact CPU types like "ultrasparc2" are wanted,
+# separate from the ABI used on them.
+#
+#
+# The variables set here are
+#
+#   cclist              the compiler choices
+#   xx_cflags           flags for compiler xx
+#   xx_cflags_maybe     flags for compiler xx, if they work
+#   xx_cppflags         cpp flags for compiler xx
+#   xx_cflags_optlist   list of sets of optional flags
+#   xx_cflags_yyy       set yyy of optional flags for compiler xx
+#   xx_ldflags          -Wc,-foo flags for libtool linking with compiler xx
+#   ar_flags            extra flags for $AR
+#   nm_flags            extra flags for $NM
+#   limb                limb size, can be "longlong"
+#   path                mpn search path
+#   extra_functions     extra mpn functions
+#   fat_path            fat binary mpn search path [if fat binary desired]
+#   fat_functions       fat functions
+#   fat_thresholds      fat thresholds
+#
+# Suppose xx_cflags_optlist="arch", then flags from $xx_cflags_arch are
+# tried, and the first flag that works will be used.  An optlist like "arch
+# cpu optimize" can be used to get multiple independent sets of flags tried.
+# The first that works from each will be used.  If no flag in a set works
+# then nothing from that set is added.
+#
+# For multiple ABIs, the scheme extends as follows.
+#
+#   abilist               set of ABI choices
+#   cclist_aa             compiler choices in ABI aa
+#   xx_aa_cflags          flags for xx in ABI aa
+#   xx_aa_cflags_maybe    flags for xx in ABI aa, if they work
+#   xx_aa_cppflags        cpp flags for xx in ABI aa
+#   xx_aa_cflags_optlist  list of sets of optional flags in ABI aa
+#   xx_aa_cflags_yyy      set yyy of optional flags for compiler xx in ABI aa
+#   xx_aa_ldflags         -Wc,-foo flags for libtool linking
+#   ar_aa_flags           extra flags for $AR in ABI aa
+#   nm_aa_flags           extra flags for $NM in ABI aa
+#   limb_aa               limb size in ABI aa, can be "longlong"
+#   path_aa               mpn search path in ABI aa
+#   extra_functions_aa    extra mpn functions in ABI aa
+#
+# As a convenience, the unadorned xx_cflags (etc) are used for the last ABI
+# in ablist, if an xx_aa_cflags for that ABI isn't given.  For example if
+# abilist="64 32" then $cc_64_cflags will be used for the 64-bit ABI, but
+# for the 32-bit either $cc_32_cflags or $cc_cflags is used, whichever is
+# defined.  This makes it easy to add some 64-bit compilers and flags to an
+# unadorned 32-bit set.
+#
+# limb=longlong (or limb_aa=longlong) applies to all compilers within that
+# ABI.  It won't work to have some needing long long and some not, since a
+# single instantiated gmp.h will be used by both.
+#
+# SPEED_CYCLECOUNTER, cyclecounter_size and CALLING_CONVENTIONS_OBJS are
+# also set here, with an ABI suffix.
+#
+#
+#
+# A table-driven approach like this to mapping cpu type to good compiler
+# options is a bit of a maintenance burden, but there's not much uniformity
+# between options specifications on different compilers.  Some sort of
+# separately updatable tool might be cute.
+#
+# The use of lots of variables like this, direct and indirect, tends to
+# obscure when and how various things are done, but unfortunately it's
+# pretty much the only way.  If shell subroutines were portable then actual
+# code like "if this .. do that" could be written, but attempting the same
+# with full copies of GMP_PROG_CC_WORKS etc expanded at every point would
+# hugely bloat the output.
+
+
+AC_ARG_VAR(ABI, [desired ABI (for processors supporting more than one ABI)])
+
+# abilist needs to be non-empty, "standard" is just a generic name here
+abilist="standard"
+
+# FIXME: We'd like to prefer an ANSI compiler, perhaps by preferring
+# c89 over cc here.  But note that on HP-UX c89 provides a castrated
+# environment, and would want to be excluded somehow.  Maybe
+# AC_PROG_CC_STDC already does enough to stick cc into ANSI mode and
+# we don't need to worry.
+#
+cclist="gcc cc"
+
+gcc_cflags="-O2 -pedantic"
+gcc_64_cflags="-O2 -pedantic"
+cc_cflags="-O"
+cc_64_cflags="-O"
+
+SPEED_CYCLECOUNTER_OBJ=
+cyclecounter_size=2
+
+AC_SUBST(HAVE_HOST_CPU_FAMILY_power,  0)
+AC_SUBST(HAVE_HOST_CPU_FAMILY_powerpc,0)
+
+case $host in
+
+  alpha*-*-*)
+    AC_DEFINE(HAVE_HOST_CPU_FAMILY_alpha)
+    case $host_cpu in
+      alphaev5* | alphapca5*)
+	path="alpha/ev5 alpha" ;;
+      alphaev67 | alphaev68 | alphaev7*)
+        path="alpha/ev67 alpha/ev6 alpha" ;;
+      alphaev6)
+	path="alpha/ev6 alpha" ;;
+      *)
+        path="alpha" ;;
+    esac
+    if test "$enable_assembly" = "yes" ; then
+       extra_functions="cntlz"
+    fi
+    gcc_cflags_optlist="asm cpu oldas" # need asm ahead of cpu, see below
+    gcc_cflags_maybe="-mieee"
+    gcc_cflags_oldas="-Wa,-oldas"     # see GMP_GCC_WA_OLDAS.
+
+    # gcc 2.7.2.3 doesn't know any -mcpu= for alpha, apparently.
+    # gcc 2.95 knows -mcpu= ev4, ev5, ev56, pca56, ev6.
+    # gcc 3.0 adds nothing.
+    # gcc 3.1 adds ev45, ev67 (but ev45 is the same as ev4).
+    # gcc 3.2 adds nothing.
+    #
+    # gcc version "2.9-gnupro-99r1" under "-O2 -mcpu=ev6" strikes internal
+    # compiler errors too easily and is rejected by GMP_PROG_CC_WORKS.  Each
+    # -mcpu=ev6 below has a fallback to -mcpu=ev56 for this reason.
+    #
+    case $host_cpu in
+      alpha)        gcc_cflags_cpu="-mcpu=ev4" ;;
+      alphaev5)     gcc_cflags_cpu="-mcpu=ev5" ;;
+      alphaev56)    gcc_cflags_cpu="-mcpu=ev56" ;;
+      alphapca56 | alphapca57)
+                    gcc_cflags_cpu="-mcpu=pca56" ;;
+      alphaev6)     gcc_cflags_cpu="-mcpu=ev6 -mcpu=ev56" ;;
+      alphaev67 | alphaev68 | alphaev7*)
+                    gcc_cflags_cpu="-mcpu=ev67 -mcpu=ev6 -mcpu=ev56" ;;
+    esac
+
+    # gcc version "2.9-gnupro-99r1" on alphaev68-dec-osf5.1 has been seen
+    # accepting -mcpu=ev6, but not putting the assembler in the right mode
+    # for what it produces.  We need to do this for it, and need to do it
+    # before testing the -mcpu options.
+    #
+    # On old versions of gcc, which don't know -mcpu=, we believe an
+    # explicit -Wa,-mev5 etc will be necessary to put the assembler in
+    # the right mode for our .asm files and longlong.h asm blocks.
+    #
+    # On newer versions of gcc, when -mcpu= is known, we must give a -Wa
+    # which is at least as high as the code gcc will generate.  gcc
+    # establishes what it needs with a ".arch" directive, our command line
+    # option seems to override that.
+    #
+    # gas prior to 2.14 doesn't accept -mev67, but -mev6 seems enough for
+    # ctlz and cttz (in 2.10.0 at least).
+    #
+    # OSF `as' accepts ev68 but stupidly treats it as ev4.  -arch only seems
+    # to affect insns like ldbu which are expanded as macros when necessary.
+    # Insns like ctlz which were never available as macros are always
+    # accepted and always generate their plain code.
+    #
+    case $host_cpu in
+      alpha)        gcc_cflags_asm="-Wa,-arch,ev4 -Wa,-mev4" ;;
+      alphaev5)     gcc_cflags_asm="-Wa,-arch,ev5 -Wa,-mev5" ;;
+      alphaev56)    gcc_cflags_asm="-Wa,-arch,ev56 -Wa,-mev56" ;;
+      alphapca56 | alphapca57)
+                    gcc_cflags_asm="-Wa,-arch,pca56 -Wa,-mpca56" ;;
+      alphaev6)     gcc_cflags_asm="-Wa,-arch,ev6 -Wa,-mev6" ;;
+      alphaev67 | alphaev68 | alphaev7*)
+                    gcc_cflags_asm="-Wa,-arch,ev67 -Wa,-mev67 -Wa,-arch,ev6 -Wa,-mev6" ;;
+    esac
+
+    # It might be better to ask "cc" whether it's Cray C or DEC C,
+    # instead of relying on the OS part of $host.  But it's hard to
+    # imagine either of those compilers anywhere except their native
+    # systems.
+    #
+    GMP_INCLUDE_MPN(alpha/alpha-defs.m4)
+    case $host in
+      *-cray-unicos*)
+        cc_cflags="-O"		# no -g, it silently disables all optimizations
+        GMP_INCLUDE_MPN(alpha/unicos.m4)
+        # Don't perform any assembly syntax tests on this beast.
+        gmp_asm_syntax_testing=no
+        ;;
+      *-*-osf*)
+        GMP_INCLUDE_MPN(alpha/default.m4)
+        cc_cflags=""
+        cc_cflags_optlist="opt cpu"
+
+        # not sure if -fast works on old versions, so make it optional
+	cc_cflags_opt="-fast -O2"
+
+	# DEC C V5.9-005 knows ev4, ev5, ev56, pca56, ev6.
+	# Compaq C V6.3-029 adds ev67.
+	#
+	case $host_cpu in
+	  alpha)       cc_cflags_cpu="-arch~ev4~-tune~ev4" ;;
+	  alphaev5)    cc_cflags_cpu="-arch~ev5~-tune~ev5" ;;
+	  alphaev56)   cc_cflags_cpu="-arch~ev56~-tune~ev56" ;;
+	  alphapca56 | alphapca57)
+            cc_cflags_cpu="-arch~pca56~-tune~pca56" ;;
+	  alphaev6)    cc_cflags_cpu="-arch~ev6~-tune~ev6" ;;
+	  alphaev67 | alphaev68 | alphaev7*)
+            cc_cflags_cpu="-arch~ev67~-tune~ev67 -arch~ev6~-tune~ev6" ;;
+	esac
+        ;;
+      *)
+        GMP_INCLUDE_MPN(alpha/default.m4)
+        ;;
+    esac
+
+    case $host in
+      *-*-unicos*)
+        # tune/alpha.asm assumes int==4bytes but unicos uses int==8bytes
+        ;;
+      *)
+        SPEED_CYCLECOUNTER_OBJ=alpha.lo
+        cyclecounter_size=1 ;;
+    esac
+    ;;
+
+
+  # Cray vector machines.
+  # This must come after alpha* so that we can recognize present and future
+  # vector processors with a wildcard.
+  *-cray-unicos*)
+    gmp_asm_syntax_testing=no
+    cclist="cc"
+    # We used to have -hscalar0 here as a workaround for miscompilation of
+    # mpz/import.c, but let's hope Cray fixes their bugs instead, since
+    # -hscalar0 causes disastrously poor code to be generated.
+    cc_cflags="-O3 -hnofastmd -htask0 -Wa,-B"
+    path="cray"
+    ;;
+
+
+  arm*-*-* | aarch64*-*-*)
+    abilist="32"
+    gcc_cflags="$gcc_cflags $fomit_frame_pointer"
+    gcc_cflags_optlist="arch fpmode neon tune"
+    gcc_64_cflags_optlist="arch tune"
+    gcc_testlist="gcc-arm-umodsi"
+    gcc_64_testlist=""
+    CALLING_CONVENTIONS_OBJS='arm32call.lo arm32check.lo'
+    CALLING_CONVENTIONS_OBJS_64=""
+    cclist_64="gcc cc"
+    any_32_testlist="sizeof-void*-4"
+    any_64_testlist="sizeof-void*-8"
+
+    # This is needed for clang, which is not content with flags like -mfpu=neon
+    # alone.
+    case $host in
+      *-*-*eabi)
+        gcc_cflags_fpmode="-mfloat-abi=softfp" ;;
+      *-*-*eabihf)
+        gcc_cflags_fpmode="-mfloat-abi=hard" ;;
+      *-*-mingw*)
+        limb_64=longlong ;;
+    esac
+
+    # FIXME: We make mandatory compiler options optional here.  We should
+    # either enforce them, or organise to strip paths as the corresponding
+    # options fail.
+    case $host_cpu in
+      armxscale | arm7ej | arm9te | arm9e* | arm10* | armv5*)
+	path="arm/v5 arm"
+	gcc_cflags_arch="-march=armv5"
+	;;
+      armsa1 | arm7t* | arm9t* | armv4t*)
+	path="arm"
+	gcc_cflags_arch="-march=armv4"
+	;;
+      arm1156 | armv6t2*)
+	path="arm/v6t2 arm/v6 arm/v5 arm"
+	gcc_cflags_arch="-march=armv6t2"
+	;;
+      arm11* | armv6*)
+	path="arm/v6 arm/v5 arm"
+	gcc_cflags_arch="-march=armv6"
+	;;
+      armcortexa5 | armv7*)
+	path="arm/v7a/cora5 arm/v6t2 arm/v6 arm/v5 arm"
+	gcc_cflags_arch="-march=armv7-a"
+	gcc_cflags_tune="-mtune=cortex-a5"
+	;;
+      armcortexa5neon)
+	path="arm/neon arm/v7a/cora5 arm/v6t2 arm/v6 arm/v5 arm"
+	gcc_cflags_neon="-mfpu=neon"
+	gcc_cflags_arch="-march=armv7-a"
+	gcc_cflags_tune="-mtune=cortex-a5"
+	;;
+      armcortexa7)
+	path="arm/v7a/cora7 arm/v6t2 arm/v6 arm/v5 arm"
+	gcc_cflags_arch="-march=armv7ve -march=armv7-a"
+	gcc_cflags_tune="-mtune=cortex-a7"
+	;;
+      armcortexa7neon)
+	path="arm/neon arm/v7a/cora7 arm/v6t2 arm/v6 arm/v5 arm"
+	gcc_cflags_arch="-march=armv7ve -march=armv7-a"
+	gcc_cflags_neon="-mfpu=neon"
+	gcc_cflags_tune="-mtune=cortex-a7"
+	;;
+      armcortexa8)
+	path="arm/v7a/cora8 arm/v6t2 arm/v6 arm/v5 arm"
+	gcc_cflags_arch="-march=armv7-a"
+	gcc_cflags_tune="-mtune=cortex-a8"
+	;;
+      armcortexa8neon)
+	path="arm/neon arm/v7a/cora8 arm/v6t2 arm/v6 arm/v5 arm"
+	gcc_cflags_arch="-march=armv7-a"
+	gcc_cflags_neon="-mfpu=neon"
+	gcc_cflags_tune="-mtune=cortex-a8"
+	;;
+      armcortexa9)
+	path="arm/v7a/cora9 arm/v6t2 arm/v6 arm/v5 arm"
+	gcc_cflags_arch="-march=armv7-a"
+	gcc_cflags_tune="-mtune=cortex-a9"
+	;;
+      armcortexa9neon)
+	path="arm/neon arm/v7a/cora9 arm/v6t2 arm/v6 arm/v5 arm"
+	gcc_cflags_arch="-march=armv7-a"
+	gcc_cflags_neon="-mfpu=neon"
+	gcc_cflags_tune="-mtune=cortex-a9"
+	;;
+      armcortexa15)
+	path="arm/v7a/cora15 arm/v6t2 arm/v6 arm/v5 arm"
+	gcc_cflags_arch="-march=armv7ve -march=armv7-a"
+	gcc_cflags_tune="-mtune=cortex-a15 -mtune=cortex-a9"
+	;;
+      armcortexa15neon)
+	path="arm/v7a/cora15/neon arm/neon arm/v7a/cora15 arm/v6t2 arm/v6 arm/v5 arm"
+	gcc_cflags_arch="-march=armv7ve -march=armv7-a"
+	gcc_cflags_neon="-mfpu=neon"
+	gcc_cflags_tune="-mtune=cortex-a15 -mtune=cortex-a9"
+	;;
+      armcortexa12 | armcortexa17)
+	path="arm/v7a/cora17 arm/v7a/cora15 arm/v6t2 arm/v6 arm/v5 arm"
+	gcc_cflags_arch="-march=armv7ve -march=armv7-a"
+	gcc_cflags_tune="-mtune=cortex-a15 -mtune=cortex-a9"
+	;;
+      armcortexa12neon | armcortexa17neon)
+	path="arm/v7a/cora17/neon arm/v7a/cora15/neon arm/neon arm/v7a/cora17 arm/v7a/cora15 arm/v6t2 arm/v6 arm/v5 arm"
+	gcc_cflags_arch="-march=armv7ve -march=armv7-a"
+	gcc_cflags_neon="-mfpu=neon"
+	gcc_cflags_tune="-mtune=cortex-a15 -mtune=cortex-a9"
+	;;
+      armcortexa53 | armcortexa53neon)
+        abilist="64 32"
+	path="arm/neon arm/v7a/cora9 arm/v6t2 arm/v6 arm/v5 arm"
+	path_64="arm64/cora53 arm64"
+	gcc_cflags_arch="-march=armv8-a"
+	gcc_cflags_neon="-mfpu=neon"
+	gcc_cflags_tune="-mtune=cortex-a53"
+	;;
+      armcortexa57 | armcortexa57neon)
+        abilist="64 32"
+	path="arm/v7a/cora15/neon arm/neon arm/v7a/cora15 arm/v6t2 arm/v6 arm/v5 arm"
+	path_64="arm64/cora57 arm64"
+	gcc_cflags_arch="-march=armv8-a"
+	gcc_cflags_neon="-mfpu=neon"
+	gcc_cflags_tune="-mtune=cortex-a57"
+	;;
+      [armcortexa7[2-9] | armcortexa7[2-9]neon])
+        abilist="64 32"
+	path="arm/v7a/cora15/neon arm/neon arm/v7a/cora15 arm/v6t2 arm/v6 arm/v5 arm"
+	path_64="arm64/cora57 arm64"
+	gcc_cflags_arch="-march=armv8-a"
+	gcc_cflags_neon="-mfpu=neon"
+	gcc_cflags_tune="-mtune=cortex-a72 -mtune=cortex-a57"
+	;;
+      armexynosm1)
+        abilist="64 32"
+	path="arm/v7a/cora15/neon arm/neon arm/v7a/cora15 arm/v6t2 arm/v6 arm/v5 arm"
+	path_64="arm64"
+	gcc_cflags_arch="-march=armv8-a"
+	gcc_cflags_neon="-mfpu=neon"
+	gcc_cflags_tune="-mtune=exynosm1"
+	;;
+      armthunderx)
+        abilist="64 32"
+	path="arm/v7a/cora15/neon arm/neon arm/v7a/cora15 arm/v6t2 arm/v6 arm/v5 arm"
+	path_64="arm64"
+	gcc_cflags_arch="-march=armv8-a"
+	gcc_cflags_neon="-mfpu=neon"
+	gcc_cflags_tune="-mtune=thunderx"
+	;;
+      armxgene1)
+        abilist="64 32"
+	path="arm/v7a/cora15/neon arm/neon arm/v7a/cora15 arm/v6t2 arm/v6 arm/v5 arm"
+	path_64="arm64/xgene1 arm64"
+	gcc_cflags_arch="-march=armv8-a"
+	gcc_cflags_neon="-mfpu=neon"
+	gcc_cflags_tune="-mtune=xgene1"
+	;;
+      aarch64*)
+        abilist="64 32"
+	path="arm/v7a/cora15/neon arm/neon arm/v7a/cora15 arm/v6t2 arm/v6 arm/v5 arm"
+	path_64="arm64"
+	gcc_cflags_arch="-march=armv8-a"
+	gcc_cflags_neon="-mfpu=neon"
+	gcc_cflags_tune=""
+	;;
+      *)
+	path="arm"
+	gcc_cflags_arch="-march=armv4"
+	GMP_DEFINE_RAW(["define(<NOTHUMB>,1)"])
+	;;
+    esac
+    ;;
+
+
+  # Fujitsu
+  [f30[01]-fujitsu-sysv*])
+    cclist="gcc vcc"
+    # FIXME: flags for vcc?
+    vcc_cflags="-g"
+    path="fujitsu"
+    ;;
+
+
+  hppa*-*-*)
+    # HP cc (the one sold separately) is K&R by default, but AM_C_PROTOTYPES
+    # will add "-Ae", or "-Aa -D_HPUX_SOURCE", to put it into ansi mode, if
+    # possible.
+    #
+    # gcc for hppa 2.0 can be built either for 2.0n (32-bit) or 2.0w
+    # (64-bit), but not both, so there's no option to choose the desired
+    # mode, we must instead detect which of the two it is.  This is done by
+    # checking sizeof(long), either 4 or 8 bytes respectively.  Do this in
+    # ABI=1.0 too, in case someone tries to build that with a 2.0w gcc.
+    #
+    gcc_cflags_optlist="arch"
+    gcc_testlist="sizeof-long-4"
+    SPEED_CYCLECOUNTER_OBJ=hppa.lo
+    cyclecounter_size=1
+
+    # FIXME: For hppa2.0*, path should be "pa32/hppa2_0 pa32/hppa1_1 pa32".
+    # (Can't remember why this isn't done already, have to check what .asm
+    # files are available in each and how they run on a typical 2.0 cpu.)
+    #
+    case $host_cpu in
+      hppa1.0*)    path="pa32" ;;
+      hppa7000*)   path="pa32/hppa1_1 pa32" ;;
+      hppa2.0* | hppa64)
+                   path="pa32/hppa2_0 pa32/hppa1_1/pa7100 pa32/hppa1_1 pa32" ;;
+      *)           # default to 7100
+                   path="pa32/hppa1_1/pa7100 pa32/hppa1_1 pa32" ;;
+    esac
+
+    # gcc 2.7.2.3 knows -mpa-risc-1-0 and -mpa-risc-1-1
+    # gcc 2.95 adds -mpa-risc-2-0, plus synonyms -march=1.0, 1.1 and 2.0
+    #
+    # We don't use -mpa-risc-2-0 in ABI=1.0 because 64-bit registers may not
+    # be saved by the kernel on an old system.  Actually gcc (as of 3.2)
+    # only adds a few float instructions with -mpa-risc-2-0, so it would
+    # probably be safe, but let's not take the chance.  In any case, a
+    # configuration like --host=hppa2.0 ABI=1.0 is far from optimal.
+    #
+    case $host_cpu in
+      hppa1.0*)           gcc_cflags_arch="-mpa-risc-1-0" ;;
+      *)                  # default to 7100
+                          gcc_cflags_arch="-mpa-risc-1-1" ;;
+    esac
+
+    case $host_cpu in
+      hppa1.0*)    cc_cflags="+O2" ;;
+      *)           # default to 7100
+                   cc_cflags="+DA1.1 +O2" ;;
+    esac
+
+    case $host in
+      hppa2.0*-*-* | hppa64-*-*)
+	cclist_20n="gcc cc"
+        abilist="2.0n 1.0"
+        path_20n="pa64"
+	limb_20n=longlong
+        any_20n_testlist="sizeof-long-4"
+        SPEED_CYCLECOUNTER_OBJ_20n=hppa2.lo
+        cyclecounter_size_20n=2
+
+        # -mpa-risc-2-0 is only an optional flag, in case an old gcc is
+        # used.  Assembler support for 2.0 is essential though, for our asm
+        # files.
+	gcc_20n_cflags="$gcc_cflags"
+	gcc_20n_cflags_optlist="arch"
+        gcc_20n_cflags_arch="-mpa-risc-2-0 -mpa-risc-1-1"
+        gcc_20n_testlist="sizeof-long-4 hppa-level-2.0"
+
+        cc_20n_cflags="+DA2.0 +e +O2 -Wl,+vnocompatwarnings"
+        cc_20n_testlist="hpc-hppa-2-0"
+
+	# ABI=2.0w is available for hppa2.0w and hppa2.0, but not for
+	# hppa2.0n, on the assumption that that the latter indicates a
+	# desire for ABI=2.0n.
+	case $host in
+        hppa2.0n-*-*) ;;
+        *)
+          # HPUX 10 and earlier cannot run 2.0w.  Not sure about other
+          # systems (GNU/Linux for instance), but lets assume they're ok.
+          case $host in
+            [*-*-hpux[1-9] | *-*-hpux[1-9].* | *-*-hpux10 | *-*-hpux10.*]) ;;
+            *)    abilist="2.0w $abilist" ;;
+          esac
+
+          cclist_20w="gcc cc"
+	  gcc_20w_cflags="$gcc_cflags -mpa-risc-2-0"
+          cc_20w_cflags="+DD64 +O2"
+          cc_20w_testlist="hpc-hppa-2-0"
+          path_20w="pa64"
+	  any_20w_testlist="sizeof-long-8"
+          SPEED_CYCLECOUNTER_OBJ_20w=hppa2w.lo
+          cyclecounter_size_20w=2
+	  ;;
+        esac
+        ;;
+    esac
+    ;;
+
+
+  IA64_PATTERN)
+    abilist="64"
+    GMP_INCLUDE_MPN(ia64/ia64-defs.m4)
+    SPEED_CYCLECOUNTER_OBJ=ia64.lo
+    any_32_testlist="sizeof-long-4"
+
+    case $host_cpu in
+      itanium)   path="ia64/itanium  ia64" ;;
+      itanium2)  path="ia64/itanium2 ia64" ;;
+      *)         path="ia64" ;;
+    esac
+
+    gcc_64_cflags_optlist="tune"
+    gcc_32_cflags_optlist=$gcc_64_cflags_optlist
+
+    # gcc pre-release 3.4 adds -mtune itanium and itanium2
+    case $host_cpu in
+      itanium)   gcc_cflags_tune="-mtune=itanium" ;;
+      itanium2)  gcc_cflags_tune="-mtune=itanium2" ;;
+    esac
+
+    case $host in
+      *-*-linux*)
+	cclist="gcc icc"
+	icc_cflags="-no-gcc"
+	icc_cflags_optlist="opt"
+	# Don't use -O3, it is for "large data sets" and also miscompiles GMP.
+	# But icc miscompiles GMP at any optimization level, at higher levels
+	# it miscompiles more files...
+	icc_cflags_opt="-O2 -O1"
+	icc_cflags_opt_maybe="-fp-model~precise"
+	;;
+
+      *-*-hpux*)
+        # HP cc sometimes gets internal errors if the optimization level is
+        # too high.  GMP_PROG_CC_WORKS detects this, the "_opt" fallbacks
+        # let us use whatever seems to work.
+        #
+        abilist="32 64"
+        any_64_testlist="sizeof-long-8"
+
+        cclist_32="gcc cc"
+        path_32="ia64"
+        cc_32_cflags=""
+        cc_32_cflags_optlist="opt"
+        cc_32_cflags_opt="+O2 +O1"
+        gcc_32_cflags="$gcc_cflags -milp32"
+        limb_32=longlong
+        SPEED_CYCLECOUNTER_OBJ_32=ia64.lo
+        cyclecounter_size_32=2
+
+        # Must have +DD64 in CPPFLAGS to get the right __LP64__ for headers,
+        # but also need it in CFLAGS for linking programs, since automake
+        # only uses CFLAGS when linking, not CPPFLAGS.
+        # FIXME: Maybe should use cc_64_ldflags for this, but that would
+        # need GMP_LDFLAGS used consistently by all the programs.
+        #
+        cc_64_cflags="+DD64"
+        cc_64_cppflags="+DD64"
+        cc_64_cflags_optlist="opt"
+        cc_64_cflags_opt="+O2 +O1"
+        gcc_64_cflags="$gcc_cflags -mlp64"
+        ;;
+    esac
+    ;;
+
+
+  # Motorola 68k
+  #
+  M68K_PATTERN)
+    AC_DEFINE(HAVE_HOST_CPU_FAMILY_m68k)
+    GMP_INCLUDE_MPN(m68k/m68k-defs.m4)
+    gcc_cflags="$gcc_cflags $fomit_frame_pointer"
+    gcc_cflags_optlist="arch"
+
+    # gcc 2.7.2 knows -m68000, -m68020, -m68030, -m68040.
+    # gcc 2.95 adds -mcpu32, -m68060.
+    # FIXME: Maybe "-m68020 -mnobitfield" would suit cpu32 on 2.7.2.
+    #
+    case $host_cpu in
+    m68020)  gcc_cflags_arch="-m68020" ;;
+    m68030)  gcc_cflags_arch="-m68030" ;;
+    m68040)  gcc_cflags_arch="-m68040" ;;
+    m68060)  gcc_cflags_arch="-m68060 -m68000" ;;
+    m68360)  gcc_cflags_arch="-mcpu32 -m68000" ;;
+    *)       gcc_cflags_arch="-m68000" ;;
+    esac
+
+    # FIXME: m68k/mc68020 looks like it's ok for cpu32, but this wants to be
+    # tested.  Will need to introduce an m68k/cpu32 if m68k/mc68020 ever uses
+    # the bitfield instructions.
+    case $host_cpu in
+    [m680[234]0 | m68360])  path="m68k/mc68020 m68k" ;;
+    *)                      path="m68k" ;;
+    esac
+    ;;
+
+
+  # Motorola 88k
+  m88k*-*-*)
+    path="m88k"
+    ;;
+  m88110*-*-*)
+    gcc_cflags="$gcc_cflags -m88110"
+    path="m88k/mc88110 m88k"
+    ;;
+
+
+  # IRIX 5 and earlier can only run 32-bit o32.
+  #
+  # IRIX 6 and up always has a 64-bit mips CPU can run n32 or 64.  n32 is
+  # preferred over 64, but only because that's been the default in past
+  # versions of GMP.  The two are equally efficient.
+  #
+  # Linux kernel 2.2.13 arch/mips/kernel/irixelf.c has a comment about not
+  # supporting n32 or 64.
+  #
+  # For reference, libtool (eg. 1.5.6) recognises the n32 ABI and knows the
+  # right options to use when linking (both cc and gcc), so no need for
+  # anything special from us.
+  #
+  mips*-*-*)
+    abilist="o32"
+    gcc_cflags_optlist="abi"
+    gcc_cflags_abi="-mabi=32 -m32"
+    gcc_testlist="gcc-mips-o32"
+    path="mips32"
+    cc_cflags="-O2 -o32"   # no -g, it disables all optimizations
+    # this suits both mips32 and mips64
+    GMP_INCLUDE_MPN(mips32/mips-defs.m4)
+
+    case $host in
+      [mips64*-*-* | mipsisa64*-*-* | mips*-*-irix[6789]*])
+        abilist="n32 64 o32"
+
+        cclist_n32="gcc cc"
+        gcc_n32_cflags_optlist="abi"
+        gcc_n32_cflags="$gcc_cflags"
+        gcc_n32_cflags_abi="-mabi=n32 -mn32"
+        cc_n32_cflags="-O2 -n32"	# no -g, it disables all optimizations
+        limb_n32=longlong
+
+        cclist_64="gcc cc"
+        gcc_64_cflags_optlist="abi"
+        gcc_64_cflags="$gcc_cflags"
+        gcc_64_cflags_abi="-mabi=64 -m64"
+        gcc_64_ldflags="-Wc,-mabi=64"
+        cc_64_cflags="-O2 -64"		# no -g, it disables all optimizations
+        cc_64_ldflags="-Wc,-64"
+
+	case $host_cpu in
+	  [mips64r[6789]* | mipsisa64r[6789]*])
+	    path_n32="mips64/r6 mips64"
+	    path_64="mips64/r6 mips64"
+	    ;;
+	  *)
+	    path_n32="mips64/hilo mips64"
+	    path_64="mips64/hilo mips64"
+	    ;;
+	esac
+
+        ;;
+    esac
+    ;;
+
+
+  # Darwin (powerpc-apple-darwin1.3) has it's hacked gcc installed as cc.
+  # Our usual "gcc in disguise" detection means gcc_cflags etc here gets
+  # used.
+  #
+  # The darwin pre-compiling preprocessor is disabled with -no-cpp-precomp
+  # since it doesn't like "__attribute__ ((mode (SI)))" etc in gmp-impl.h,
+  # and so always ends up running the plain preprocessor anyway.  This could
+  # be done in CPPFLAGS rather than CFLAGS, but there's not many places
+  # preprocessing is done separately, and this is only a speedup, the normal
+  # preprocessor gets run if there's any problems.
+  #
+  # We used to use -Wa,-mppc with gcc, but can't remember exactly why.
+  # Presumably it was for old versions of gcc where -mpowerpc doesn't put
+  # the assembler in the right mode.  In any case -Wa,-mppc is not good, for
+  # instance -mcpu=604 makes recent gcc use -m604 to get access to the
+  # "fsel" instruction, but a -Wa,-mppc overrides that, making code that
+  # comes out with fsel fail.
+  #
+  # (Note also that the darwin assembler doesn't accept "-mppc", so any
+  # -Wa,-mppc was used only if it worked.  The right flag on darwin would be
+  # "-arch ppc" or some such, but that's already the default.)
+  #
+  [powerpc*-*-* | power[3-9]-*-*])
+    AC_DEFINE(HAVE_HOST_CPU_FAMILY_powerpc)
+    HAVE_HOST_CPU_FAMILY_powerpc=1
+    abilist="32"
+    cclist="gcc cc"
+    cc_cflags="-O2"
+    gcc_32_cflags_maybe="-m32"
+    gcc_cflags_optlist="precomp subtype asm cpu"
+    gcc_cflags_precomp="-no-cpp-precomp"
+    gcc_cflags_subtype="-force_cpusubtype_ALL"	# for vmx on darwin
+    gcc_cflags_asm=""
+    gcc_cflags_cpu=""
+    vmx_path=""
+
+    # grab this object, though it's not a true cycle counter routine
+    SPEED_CYCLECOUNTER_OBJ=powerpc.lo
+    cyclecounter_size=0
+
+    case $host_cpu in
+      powerpc740 | powerpc750)
+        path="powerpc32/750 powerpc32" ;;
+      powerpc7400 | powerpc7410)
+        path="powerpc32/vmx powerpc32/750 powerpc32" ;;
+      [powerpc74[45]?])
+        path="powerpc32/vmx powerpc32" ;;
+      *)
+        path="powerpc32" ;;
+    esac
+
+    case $host_cpu in
+      powerpc401)   gcc_cflags_cpu="-mcpu=401" ;;
+      powerpc403)   gcc_cflags_cpu="-mcpu=403"
+		    xlc_cflags_arch="-qarch=403 -qarch=ppc" ;;
+      powerpc405)   gcc_cflags_cpu="-mcpu=405" ;;
+      powerpc505)   gcc_cflags_cpu="-mcpu=505" ;;
+      powerpc601)   gcc_cflags_cpu="-mcpu=601"
+		    xlc_cflags_arch="-qarch=601 -qarch=ppc" ;;
+      powerpc602)   gcc_cflags_cpu="-mcpu=602"
+		    xlc_cflags_arch="-qarch=602 -qarch=ppc" ;;
+      powerpc603)   gcc_cflags_cpu="-mcpu=603"
+		    xlc_cflags_arch="-qarch=603 -qarch=ppc" ;;
+      powerpc603e)  gcc_cflags_cpu="-mcpu=603e -mcpu=603"
+		    xlc_cflags_arch="-qarch=603 -qarch=ppc" ;;
+      powerpc604)   gcc_cflags_cpu="-mcpu=604"
+		    xlc_cflags_arch="-qarch=604 -qarch=ppc" ;;
+      powerpc604e)  gcc_cflags_cpu="-mcpu=604e -mcpu=604"
+		    xlc_cflags_arch="-qarch=604 -qarch=ppc" ;;
+      powerpc620)   gcc_cflags_cpu="-mcpu=620" ;;
+      powerpc630)   gcc_cflags_cpu="-mcpu=630"
+		    xlc_cflags_arch="-qarch=pwr3"
+		    cpu_path="p3 p3-p7" ;;
+      powerpc740)   gcc_cflags_cpu="-mcpu=740" ;;
+      powerpc7400 | powerpc7410)
+		    gcc_cflags_asm="-Wa,-maltivec"
+		    gcc_cflags_cpu="-mcpu=7400 -mcpu=750" ;;
+      [powerpc74[45]?])
+		    gcc_cflags_asm="-Wa,-maltivec"
+		    gcc_cflags_cpu="-mcpu=7450" ;;
+      powerpc750)   gcc_cflags_cpu="-mcpu=750" ;;
+      powerpc801)   gcc_cflags_cpu="-mcpu=801" ;;
+      powerpc821)   gcc_cflags_cpu="-mcpu=821" ;;
+      powerpc823)   gcc_cflags_cpu="-mcpu=823" ;;
+      powerpc860)   gcc_cflags_cpu="-mcpu=860" ;;
+      powerpc970)   gcc_cflags_cpu="-mtune=970"
+		    xlc_cflags_arch="-qarch=970 -qarch=pwr3"
+		    vmx_path="powerpc64/vmx"
+		    cpu_path="p4 p3-p7" ;;
+      power4)	    gcc_cflags_cpu="-mtune=power4"
+		    xlc_cflags_arch="-qarch=pwr4"
+		    cpu_path="p4 p3-p7" ;;
+      power5)	    gcc_cflags_cpu="-mtune=power5 -mtune=power4"
+		    xlc_cflags_arch="-qarch=pwr5"
+		    cpu_path="p5 p4 p3-p7" ;;
+      power6)	    gcc_cflags_cpu="-mtune=power6"
+		    xlc_cflags_arch="-qarch=pwr6"
+		    cpu_path="p6 p3-p7" ;;
+      power7)	    gcc_cflags_cpu="-mtune=power7 -mtune=power5"
+		    xlc_cflags_arch="-qarch=pwr7 -qarch=pwr5"
+		    cpu_path="p7 p5 p4 p3-p7" ;;
+      power8)	    gcc_cflags_cpu="-mtune=power8 -mtune=power7 -mtune=power5"
+		    xlc_cflags_arch="-qarch=pwr8 -qarch=pwr7 -qarch=pwr5"
+		    cpu_path="p8 p7 p5 p4 p3-p7" ;;
+      power9)	    gcc_cflags_cpu="-mtune=power9 -mtune=power8 -mtune=power7 -mtune=power5"
+		    xlc_cflags_arch="-qarch=pwr9 -qarch=pwr8 -qarch=pwr7 -qarch=pwr5"
+		    cpu_path="p9 p8 p7 p5 p4 p3-p7" ;;
+    esac
+
+    case $host in
+      *-*-aix*)
+	cclist="gcc xlc cc"
+	gcc_32_cflags_maybe="-maix32"
+	xlc_cflags="-O2 -qmaxmem=20000"
+	xlc_cflags_optlist="arch"
+	xlc_32_cflags_maybe="-q32"
+	ar_32_flags="-X32"
+	nm_32_flags="-X32"
+    esac
+
+    case $host in
+      POWERPC64_PATTERN)
+	case $host in
+	  *-*-aix*)
+	    # On AIX a true 64-bit ABI is available.
+	    # Need -Wc to pass object type flags through to the linker.
+	    abilist="mode64 $abilist"
+	    cclist_mode64="gcc xlc"
+	    gcc_mode64_cflags="$gcc_cflags -maix64 -mpowerpc64"
+	    gcc_mode64_cflags_optlist="cpu"
+	    gcc_mode64_ldflags="-Wc,-maix64"
+	    xlc_mode64_cflags="-O2 -q64 -qmaxmem=20000"
+	    xlc_mode64_cflags_optlist="arch"
+	    xlc_mode64_ldflags="-Wc,-q64"
+	    # Must indicate object type to ar and nm
+	    ar_mode64_flags="-X64"
+	    nm_mode64_flags="-X64"
+	    path_mode64=""
+	    p=""
+	    for i in $cpu_path
+	      do path_mode64="${path_mode64}powerpc64/mode64/$i "
+		 path_mode64="${path_mode64}powerpc64/$i "
+		 p="${p} powerpc32/$i "
+	      done
+	    path_mode64="${path_mode64}powerpc64/mode64 $vmx_path powerpc64"
+	    path="$p $path"
+	    # grab this object, though it's not a true cycle counter routine
+	    SPEED_CYCLECOUNTER_OBJ_mode64=powerpc64.lo
+	    cyclecounter_size_mode64=0
+	    ;;
+	  *-*-darwin*)
+	    # On Darwin we can use 64-bit instructions with a longlong limb,
+	    # but the chip still in 32-bit mode.
+	    # In theory this can be used on any OS which knows how to save
+	    # 64-bit registers in a context switch.
+	    #
+	    # Note that we must use -mpowerpc64 with gcc, since the
+	    # longlong.h macros expect limb operands in a single 64-bit
+	    # register, not two 32-bit registers as would be given for a
+	    # long long without -mpowerpc64.  In theory we could detect and
+	    # accommodate both styles, but the proper 64-bit registers will
+	    # be fastest and are what we really want to use.
+	    #
+	    # One would think -mpowerpc64 would set the assembler in the right
+	    # mode to handle 64-bit instructions.  But for that, also
+	    # -force_cpusubtype_ALL is needed.
+	    #
+	    # Do not use -fast for Darwin, it actually adds options
+	    # incompatible with a shared library.
+	    #
+	    abilist="mode64 mode32 $abilist"
+	    gcc_cflags_opt="-O2 -O1"	# will this become used?
+	    cclist_mode32="gcc"
+	    gcc_mode32_cflags_maybe="-m32"
+	    gcc_mode32_cflags="-mpowerpc64"
+	    gcc_mode32_cflags_optlist="subtype cpu opt"
+	    gcc_mode32_cflags_subtype="-force_cpusubtype_ALL"
+	    gcc_mode32_cflags_opt="-O2 -O1"
+	    limb_mode32=longlong
+	    cclist_mode64="gcc"
+	    gcc_mode64_cflags="-m64"
+	    gcc_mode64_cflags_optlist="cpu opt"
+	    gcc_mode64_cflags_opt="-O2 -O1"
+	    path_mode64=""
+	    path_mode32=""
+	    p=""
+	    for i in $cpu_path
+	      do path_mode64="${path_mode64}powerpc64/mode64/$i "
+		 path_mode64="${path_mode64}powerpc64/$i "
+		 path_mode32="${path_mode32}powerpc64/mode32/$i "
+		 path_mode32="${path_mode32}powerpc64/$i "
+		 p="${p} powerpc32/$i "
+	      done
+	    path_mode64="${path_mode64}powerpc64/mode64 $vmx_path powerpc64"
+	    path_mode32="${path_mode32}powerpc64/mode32 $vmx_path powerpc64"
+	    path="$p $path"
+	    SPEED_CYCLECOUNTER_OBJ_mode64=powerpc64.lo
+	    cyclecounter_size_mode64=0
+	    any_mode64_testlist="sizeof-long-8"
+	    ;;
+	  *-*-linux* | *-*-*bsd*)
+	    # On GNU/Linux, assume the processor is in 64-bit mode.  Some
+	    # environments have a gcc that is always in 64-bit mode, while
+	    # others require -m64, hence the use of cflags_maybe.  The
+	    # sizeof-long-8 test checks the mode is right (for the no option
+	    # case).
+	    #
+	    # -mpowerpc64 is not used, since it should be the default in
+	    # 64-bit mode.  (We need its effect for the various longlong.h
+	    # asm macros to be right of course.)
+	    #
+	    # gcc64 was an early port of gcc to 64-bit mode, but should be
+	    # obsolete before too long.  We prefer plain gcc when it knows
+	    # 64-bits.
+	    #
+	    abilist="mode64 mode32 $abilist"
+	    cclist_mode32="gcc"
+	    gcc_mode32_cflags_maybe="-m32"
+	    gcc_mode32_cflags="-mpowerpc64"
+	    gcc_mode32_cflags_optlist="cpu opt"
+	    gcc_mode32_cflags_opt="-O2 -O1"
+	    limb_mode32=longlong
+	    cclist_mode64="gcc gcc64"
+	    gcc_mode64_cflags_maybe="-m64"
+	    gcc_mode64_cflags_optlist="cpu opt"
+	    gcc_mode64_cflags_opt="-O2 -O1"
+	    path_mode64=""
+	    path_mode32=""
+	    p=""
+	    for i in $cpu_path
+	      do path_mode64="${path_mode64}powerpc64/mode64/$i "
+		 path_mode64="${path_mode64}powerpc64/$i "
+		 path_mode32="${path_mode32}powerpc64/mode32/$i "
+		 path_mode32="${path_mode32}powerpc64/$i "
+		 p="${p} powerpc32/$i "
+	      done
+	    path_mode64="${path_mode64}powerpc64/mode64 $vmx_path powerpc64"
+	    path_mode32="${path_mode32}powerpc64/mode32 $vmx_path powerpc64"
+	    path="$p $path"
+	    SPEED_CYCLECOUNTER_OBJ_mode64=powerpc64.lo
+	    cyclecounter_size_mode64=0
+	    any_mode64_testlist="sizeof-long-8"
+	    ;;
+	esac
+	;;
+    esac
+    ;;
+
+
+  # POWER 32-bit
+  [power-*-* | power[12]-*-* | power2sc-*-*])
+    AC_DEFINE(HAVE_HOST_CPU_FAMILY_power)
+    HAVE_HOST_CPU_FAMILY_power=1
+    cclist="gcc"
+    if test "$enable_assembly" = "yes" ; then
+      extra_functions="udiv_w_sdiv"
+    fi
+    path="power"
+
+    # gcc 2.7.2 knows rios1, rios2, rsc
+    #
+    # -mcpu=rios2 can tickle an AIX assembler bug (see GMP_PROG_CC_WORKS) so
+    # there needs to be a fallback to just -mpower.
+    #
+    gcc_cflags_optlist="cpu"
+    case $host in
+      power-*-*)    gcc_cflags_cpu="-mcpu=power -mpower" ;;
+      power1-*-*)   gcc_cflags_cpu="-mcpu=rios1 -mpower" ;;
+      power2-*-*)   gcc_cflags_cpu="-mcpu=rios2 -mpower" ;;
+      power2sc-*-*) gcc_cflags_cpu="-mcpu=rsc   -mpower" ;;
+    esac
+    case $host in
+    *-*-aix*)
+      cclist="gcc xlc"
+      xlc_cflags="-O2 -qarch=pwr -qmaxmem=20000"
+      ;;
+    esac
+    ;;
+
+
+  # RISC-V
+  [riscv64-*-*])
+    cclist="gcc"
+    path="riscv/64"
+    ;;
+
+
+  # IBM System/390 and z/Architecture
+  S390_PATTERN | S390X_PATTERN)
+    abilist="32"
+    gcc_cflags="$gcc_cflags $fomit_frame_pointer"
+    gcc_cflags_optlist="arch"
+    path="s390_32"
+    if test "$enable_assembly" = "yes" ; then
+       extra_functions="udiv_w_sdiv"
+    fi
+    gcc_32_cflags_maybe="-m31"
+
+    case $host_cpu in
+      s390)
+	;;
+      z900 | z900esa)
+        cpu="z900"
+        gccarch="$cpu"
+	path="s390_32/esame/$cpu s390_32/esame s390_32"
+	gcc_cflags_arch="-march=$gccarch"
+	AC_DEFINE_UNQUOTED(HAVE_HOST_CPU_s390_$cpu)
+	AC_DEFINE(HAVE_HOST_CPU_s390_zarch)
+	extra_functions=""
+        ;;
+      z990 | z990esa)
+        cpu="z990"
+        gccarch="$cpu"
+	path="s390_32/esame/$cpu s390_32/esame s390_32"
+	gcc_cflags_arch="-march=$gccarch"
+	AC_DEFINE_UNQUOTED(HAVE_HOST_CPU_s390_$cpu)
+	AC_DEFINE(HAVE_HOST_CPU_s390_zarch)
+	extra_functions=""
+        ;;
+      z9 | z9esa)
+        cpu="z9"
+	gccarch="z9-109"
+	path="s390_32/esame/$cpu s390_32/esame s390_32"
+	gcc_cflags_arch="-march=$gccarch"
+	AC_DEFINE_UNQUOTED(HAVE_HOST_CPU_s390_$cpu)
+	AC_DEFINE(HAVE_HOST_CPU_s390_zarch)
+	extra_functions=""
+        ;;
+      z10 | z10esa)
+        cpu="z10"
+	gccarch="z10"
+	path="s390_32/esame/$cpu s390_32/esame s390_32"
+	gcc_cflags_arch="-march=$gccarch"
+	AC_DEFINE_UNQUOTED(HAVE_HOST_CPU_s390_$cpu)
+	AC_DEFINE(HAVE_HOST_CPU_s390_zarch)
+	extra_functions=""
+        ;;
+      z196 | z196esa)
+        cpu="z196"
+	gccarch="z196"
+	path="s390_32/esame/$cpu s390_32/esame s390_32"
+	gcc_cflags_arch="-march=$gccarch"
+	AC_DEFINE_UNQUOTED(HAVE_HOST_CPU_s390_$cpu)
+	AC_DEFINE(HAVE_HOST_CPU_s390_zarch)
+	extra_functions=""
+        ;;
+      esac
+
+    case $host in
+      S390X_PATTERN)
+	abilist="64 32"
+	cclist_64="gcc"
+	gcc_64_cflags_optlist="arch"
+	gcc_64_cflags="$gcc_cflags -m64"
+	path_64="s390_64/$host_cpu s390_64"
+	extra_functions=""
+	;;
+      esac
+    ;;
+
+
+  sh-*-*)   path="sh" ;;
+  [sh[2-4]-*-*])  path="sh/sh2 sh" ;;
+
+
+  *sparc*-*-*)
+    # sizeof(long)==4 or 8 is tested, to ensure we get the right ABI.  We've
+    # had various bug reports where users have set CFLAGS for their desired
+    # mode, but not set our ABI.  For some reason it's sparc where this
+    # keeps coming up, presumably users there are accustomed to driving the
+    # compiler mode that way.  The effect of our testlist setting is to
+    # reject ABI=64 in favour of ABI=32 if the user has forced the flags to
+    # 32-bit mode.
+    #
+    abilist="32"
+    cclist="gcc acc cc"
+    any_testlist="sizeof-long-4"
+    GMP_INCLUDE_MPN(sparc32/sparc-defs.m4)
+
+    case $host_cpu in
+      sparcv8 | microsparc | turbosparc)
+        path="sparc32/v8 sparc32" ;;
+      supersparc)
+        path="sparc32/v8/supersparc sparc32/v8 sparc32" ;;
+      [sparc64 | sparcv9* | ultrasparc | ultrasparc[234]*])
+        path="sparc32/v9 sparc32/v8 sparc32" ;;
+      [ultrasparct[12345]])
+        path="sparc32/ultrasparct1 sparc32/v8 sparc32" ;;
+      *)
+        path="sparc32" ;;
+    esac
+
+    # gcc 2.7.2 doesn't know about v9 and doesn't pass -xarch=v8plus to the
+    # assembler.  Add it explicitly since the solaris assembler won't accept
+    # our sparc32/v9 asm code without it.  gas accepts -xarch=v8plus too, so
+    # it can be in the cflags unconditionally (though gas doesn't need it).
+    #
+    # gcc -m32 is needed to force 32-bit mode on a dual-ABI system, but past
+    # gcc doesn't know that flag, hence cflags_maybe.  Note that -m32 cannot
+    # be done through the optlist since the plain cflags would be run first
+    # and we don't want to require the default mode (whatever it is) works.
+    #
+    # Note it's gcc_32_cflags_maybe and not gcc_cflags_maybe because the
+    # latter would be used in the 64-bit ABI on systems like "*bsd" where
+    # abilist="64" only.
+    #
+    gcc_32_cflags_maybe="-m32"
+    gcc_cflags_optlist="cpu asm"
+
+    # gcc 2.7.2 knows -mcypress, -msupersparc, -mv8, -msparclite.
+    # gcc 2.95 knows -mcpu= v7, hypersparc, sparclite86x, f930, f934,
+    #   sparclet, tsc701, v9, ultrasparc.  A warning is given that the
+    #   plain -m forms will disappear.
+    # gcc 3.3 adds ultrasparc3.
+    #
+    case $host_cpu in
+      supersparc*)
+			gcc_cflags_cpu="-mcpu=supersparc -msupersparc"
+			gcc_cflags_asm="-Wa,-Av8 -Wa,-xarch=v8";;
+      sparcv8 | microsparc* | turbosparc | hypersparc*)
+			gcc_cflags_cpu="-mcpu=v8 -mv8"
+			gcc_cflags_asm="-Wa,-Av8 -Wa,-xarch=v8";;
+      sparc64 | sparcv9*)
+			gcc_cflags_cpu="-mcpu=v9"
+			gcc_32_cflags_asm="-Wa,-Av8 -Wa,-xarch=v8plus"
+			gcc_64_cflags_asm="-Wa,-Av9 -Wa,-xarch=v9";;
+      ultrasparc1 | ultrasparc2*)
+			gcc_cflags_cpu="-mcpu=ultrasparc -mcpu=v9"
+			gcc_32_cflags_asm="-Wa,-Av8plusa -Wa,-xarch=v8plusa"
+			gcc_64_cflags_asm="-Wa,-Av9a -Wa,-xarch=v9a";;
+      [ultrasparc[34]])
+			gcc_cflags_cpu="-mcpu=ultrasparc3 -mcpu=ultrasparc -mcpu=v9"
+			gcc_32_cflags_asm="-Wa,-Av8plusb -Wa,-xarch=v8plusb"
+			gcc_64_cflags_asm="-Wa,-Av9b -Wa,-xarch=v9b";;
+      [ultrasparct[12]])
+			gcc_cflags_cpu="-mcpu=niagara -mcpu=v9"
+			gcc_32_cflags_asm="-Wa,-Av8plusc -Wa,-xarch=v8plusc"
+			gcc_64_cflags_asm="-Wa,-Av9c -Wa,-xarch=v9c";;
+      ultrasparct3)
+			gcc_cflags_cpu="-mcpu=niagara3 -mcpu=niagara -mcpu=v9"
+			gcc_32_cflags_asm="-Wa,-Av8plusd -Wa,-xarch=v8plusd"
+			gcc_64_cflags_asm="-Wa,-Av9d -Wa,-xarch=v9d";;
+      [ultrasparct[45]])
+			gcc_cflags_cpu="-mcpu=niagara4 -mcpu=niagara3 -mcpu=niagara -mcpu=v9"
+			gcc_32_cflags_asm="-Wa,-Av8plusd -Wa,-xarch=v8plusd"
+			gcc_64_cflags_asm="-Wa,-Av9d -Wa,-xarch=v9d";;
+      *)
+			gcc_cflags_cpu="-mcpu=v7 -mcypress"
+			gcc_cflags_asm="";;
+    esac
+
+    # SunPRO cc and acc, and SunOS bundled cc
+    case $host in
+      *-*-solaris* | *-*-sunos*)
+	# Note no -g, it disables all optimizations.
+	cc_cflags=
+	cc_cflags_optlist="opt arch cpu"
+
+        # SunOS <= 4 cc doesn't know -xO3, fallback to -O2.
+	cc_cflags_opt="-xO3 -O2"
+
+        # SunOS cc doesn't know -xarch, apparently always generating v7
+        # code, so make this optional
+	case $host_cpu in
+	  sparcv8 | microsparc* | supersparc* | turbosparc | hypersparc*)
+			cc_cflags_arch="-xarch=v8";;
+          [ultrasparct[345]])
+			cc_cflags_arch="-xarch=v8plusd" ;;
+	  sparc64 | sparcv9* | ultrasparc*)
+			cc_cflags_arch="-xarch=v8plus" ;;
+	  *)
+			cc_cflags_arch="-xarch=v7" ;;
+	esac
+
+        # SunOS cc doesn't know -xchip and doesn't seem to have an equivalent.
+	# SunPRO cc 5 recognises -xchip=generic, old, super, super2, micro,
+	#   micro2, hyper, hyper2, powerup, ultra, ultra2, ultra2i.
+	# SunPRO cc 6 adds -xchip=ultra2e, ultra3cu.
+        #
+	case $host_cpu in
+	  supersparc*)  cc_cflags_cpu="-xchip=super" ;;
+	  microsparc*)  cc_cflags_cpu="-xchip=micro" ;;
+	  turbosparc)   cc_cflags_cpu="-xchip=micro2" ;;
+	  hypersparc*)  cc_cflags_cpu="-xchip=hyper" ;;
+	  ultrasparc)   cc_cflags_cpu="-xchip=ultra" ;;
+	  ultrasparc2)  cc_cflags_cpu="-xchip=ultra2 -xchip=ultra" ;;
+	  ultrasparc2i) cc_cflags_cpu="-xchip=ultra2i -xchip=ultra2 -xchip=ultra" ;;
+	  ultrasparc3)  cc_cflags_cpu="-xchip=ultra3 -xchip=ultra" ;;
+	  ultrasparc4)  cc_cflags_cpu="-xchip=ultra4 -xchip=ultra3 -xchip=ultra" ;;
+	  ultrasparct1) cc_cflags_cpu="-xchip=ultraT1" ;;
+	  ultrasparct2) cc_cflags_cpu="-xchip=ultraT2 -xchip=ultraT1" ;;
+	  ultrasparct3) cc_cflags_cpu="-xchip=ultraT3 -xchip=ultraT2" ;;
+	  ultrasparct4) cc_cflags_cpu="-xchip=T4" ;;
+	  ultrasparct5) cc_cflags_cpu="-xchip=T5 -xchip=T4" ;;
+	  *)            cc_cflags_cpu="-xchip=generic" ;;
+	esac
+    esac
+
+    case $host_cpu in
+      sparc64 | sparcv9* | ultrasparc*)
+        case $host in
+          # Solaris 6 and earlier cannot run ABI=64 since it doesn't save
+          # registers properly, so ABI=32 is left as the only choice.
+          #
+          [*-*-solaris2.[0-6] | *-*-solaris2.[0-6].*]) ;;
+
+          # BSD sparc64 ports are 64-bit-only systems, so ABI=64 is the only
+          # choice.  In fact they need no special compiler flags, gcc -m64
+          # is the default, but it doesn't hurt to add it.  v9 CPUs always
+          # use the sparc64 port, since the plain 32-bit sparc ports don't
+          # run on a v9.
+          #
+          *-*-*bsd*) abilist="64" ;;
+
+          # For all other systems, we try both 64 and 32.
+          #
+          # GNU/Linux sparc64 has only recently gained a 64-bit user mode.
+          # In the past sparc64 meant a v9 cpu, but there were no 64-bit
+          # operations in user mode.  We assume that if "gcc -m64" works
+          # then the system is suitable.  Hopefully even if someone attempts
+          # to put a new gcc and/or glibc on an old system it won't run.
+          #
+          *) abilist="64 32" ;;
+        esac
+
+	case $host_cpu in
+	  ultrasparc | ultrasparc2 | ultrasparc2i)
+	    path_64="sparc64/ultrasparc1234 sparc64" ;;
+	  [ultrasparc[34]])
+	    path_64="sparc64/ultrasparc34 sparc64/ultrasparc1234 sparc64" ;;
+	  [ultrasparct[12]])
+	    path_64="sparc64/ultrasparct1 sparc64" ;;
+	  [ultrasparct3])
+	    path_64="sparc64/ultrasparct3 sparc64" ;;
+	  [ultrasparct[45]])
+	    path_64="sparc64/ultrasparct45 sparc64/ultrasparct3 sparc64" ;;
+	  *)
+	    path_64="sparc64"
+	esac
+
+        cclist_64="gcc"
+        any_64_testlist="sizeof-long-8"
+
+        # gcc -mptr64 is probably implied by -m64, but we're not sure if
+        # this was always so.  On Solaris in the past we always used both
+        # "-m64 -mptr64".
+        #
+        # gcc -Wa,-xarch=v9 is thought to be necessary in some cases on
+        # solaris, but it would seem likely that if gcc is going to generate
+        # 64-bit code it will have to add that option itself where needed.
+        # An extra copy of this option should be harmless though, but leave
+        # it until we're sure.  (Might want -xarch=v9a or -xarch=v9b for the
+        # higher cpu types instead.)
+        #
+        gcc_64_cflags="$gcc_cflags -m64 -mptr64"
+        gcc_64_ldflags="-Wc,-m64"
+        gcc_64_cflags_optlist="cpu asm"
+
+        case $host in
+          *-*-solaris*)
+            # Sun cc.
+            #
+            # We used to have -fast and some fixup options here, but it
+            # recurrently caused problems with miscompilation.  Of course,
+            # -fast is documented as miscompiling things for the sake of speed.
+            #
+            cclist_64="$cclist_64 cc"
+            cc_64_cflags_optlist="cpu"
+            case $host_cpu in
+              [ultrasparct[345]])
+                cc_64_cflags="$cc_64_cflags -xO3 -xarch=v9d" ;;
+              *)
+                cc_64_cflags="-xO3 -xarch=v9" ;;
+            esac
+            ;;
+        esac
+
+        # using the v9 %tick register
+        SPEED_CYCLECOUNTER_OBJ_32=sparcv9.lo
+        SPEED_CYCLECOUNTER_OBJ_64=sparcv9.lo
+        cyclecounter_size_32=2
+        cyclecounter_size_64=2
+        ;;
+    esac
+    ;;
+
+
+  # VAX
+  vax*-*-*elf*)
+    # Use elf conventions (i.e., '%' register prefix, no global prefix)
+    #
+    GMP_INCLUDE_MPN(vax/elf.m4)
+    gcc_cflags="$gcc_cflags $fomit_frame_pointer"
+    path="vax"
+    if test "$enable_assembly" = "yes" ; then
+      extra_functions="udiv_w_sdiv"
+    fi
+    ;;
+  vax*-*-*)
+    # Default to aout conventions (i.e., no register prefix, '_' global prefix)
+    #
+    gcc_cflags="$gcc_cflags $fomit_frame_pointer"
+    path="vax"
+    if test "$enable_assembly" = "yes" ; then
+      extra_functions="udiv_w_sdiv"
+    fi
+    ;;
+
+
+  # AMD and Intel x86 configurations, including AMD64
+  #
+  # Rumour has it gcc -O2 used to give worse register allocation than just
+  # -O, but lets assume that's no longer true.
+  #
+  # -m32 forces 32-bit mode on a bi-arch 32/64 amd64 build of gcc.  -m64 is
+  # the default in such a build (we think), so -m32 is essential for ABI=32.
+  # This is, of course, done for any $host_cpu, not just x86_64, so we can
+  # get such a gcc into the right mode to cross-compile to say i486-*-*.
+  #
+  # -m32 is not available in gcc 2.95 and earlier, hence cflags_maybe to use
+  # it when it works.  We check sizeof(long)==4 to ensure we get the right
+  # mode, in case -m32 has failed not because it's an old gcc, but because
+  # it's a dual 32/64-bit gcc without a 32-bit libc, or whatever.
+  #
+  X86_PATTERN | X86_64_PATTERN)
+    abilist="32"
+    cclist="gcc icc cc"
+    gcc_cflags="$gcc_cflags $fomit_frame_pointer"
+    gcc_32_cflags_maybe="-m32"
+    icc_cflags="-no-gcc"
+    icc_cflags_optlist="opt"
+    icc_cflags_opt="-O3 -O2 -O1"
+    icc_cflags_opt_maybe="-fp-model~precise"
+    any_32_testlist="sizeof-long-4"
+    gcc_cflags_optlist="cpu arch noavx"
+    CALLING_CONVENTIONS_OBJS='x86call.lo x86check$U.lo'
+
+    # Availability of rdtsc is checked at run-time.
+    SPEED_CYCLECOUNTER_OBJ=pentium.lo
+
+    # Set to "yes" below on a per-cpu basis. We do that in order to allow for
+    # a relevant warning to be output when using a CPU with mulx on a system
+    # which cannot assemble it.
+    x86_have_mulx=no
+
+    # gcc 2.7.2 only knows i386 and i486, using -m386 or -m486.  These
+    #     represent -mcpu= since -m486 doesn't generate 486 specific insns.
+    # gcc 2.95 adds k6, pentium and pentiumpro, and takes -march= and -mcpu=.
+    # gcc 3.0 adds athlon.
+    # gcc 3.1 adds k6-2, k6-3, pentium-mmx, pentium2, pentium3, pentium4,
+    #     athlon-tbird, athlon-4, athlon-xp, athlon-mp.
+    # gcc 3.2 adds winchip2.
+    # gcc 3.3 adds winchip-c6.
+    # gcc 3.3.1 from mandrake adds k8 and knows -mtune.
+    # gcc 3.4 adds c3, c3-2, k8, and deprecates -mcpu in favour of -mtune.
+    #
+    # In gcc 2.95.[0123], -march=pentiumpro provoked a stack slot bug in an
+    # old version of mpz/powm.c.  Seems to be fine with the current code, so
+    # no need for any restrictions on that option.
+    #
+    # -march=pentiumpro can fail if the assembler doesn't know "cmov"
+    # (eg. solaris 2.8 native "as"), so always have -march=pentium after
+    # that as a fallback.
+    #
+    # -march=pentium4 and -march=k8 enable SSE2 instructions, which may or
+    # may not be supported by the assembler and/or the OS, and is bad in gcc
+    # prior to 3.3.  The tests will reject these if no good, so fallbacks
+    # like "-march=pentium4 -mno-sse2" are given to try also without SSE2.
+    # Note the relevant -march types are listed in the optflags handling
+    # below, be sure to update there if adding new types emitting SSE2.
+    #
+    # -mtune is used at the start of each cpu option list to give something
+    # gcc 3.4 will use, thereby avoiding warnings from -mcpu.  -mcpu forms
+    # are retained for use by prior gcc.  For example pentium has
+    # "-mtune=pentium -mcpu=pentium ...", the -mtune is for 3.4 and the
+    # -mcpu for prior.  If there's a brand new choice in 3.4 for a chip,
+    # like k8 for x86_64, then it can be the -mtune at the start, no need to
+    # duplicate anything.
+    #
+    case $host_cpu in
+      i386*)
+	gcc_cflags_cpu="-mtune=i386 -mcpu=i386 -m386"
+	gcc_cflags_arch="-march=i386"
+	path="x86"
+	;;
+      i486*)
+	gcc_cflags_cpu="-mtune=i486 -mcpu=i486 -m486"
+	gcc_cflags_arch="-march=i486"
+	path="x86/i486 x86"
+	;;
+      i586 | pentium)
+	gcc_cflags_cpu="-mtune=pentium -mcpu=pentium -m486"
+	gcc_cflags_arch="-march=pentium"
+	path="x86/pentium x86"
+	;;
+      pentiummmx)
+	gcc_cflags_cpu="-mtune=pentium-mmx -mcpu=pentium-mmx -mcpu=pentium -m486"
+	gcc_cflags_arch="-march=pentium-mmx -march=pentium"
+	path="x86/pentium/mmx x86/pentium x86/mmx x86"
+	;;
+      i686 | pentiumpro)
+	gcc_cflags_cpu="-mtune=pentiumpro -mcpu=pentiumpro -mcpu=i486 -m486"
+	gcc_cflags_arch="-march=pentiumpro -march=pentium"
+	path="x86/p6 x86"
+	;;
+      pentium2)
+	gcc_cflags_cpu="-mtune=pentium2 -mcpu=pentium2 -mcpu=pentiumpro -mcpu=i486 -m486"
+	gcc_cflags_arch="-march=pentium2 -march=pentiumpro -march=pentium"
+	path="x86/p6/mmx x86/p6 x86/mmx x86"
+	;;
+      pentium3)
+	gcc_cflags_cpu="-mtune=pentium3 -mcpu=pentium3 -mcpu=pentiumpro -mcpu=i486 -m486"
+	gcc_cflags_arch="-march=pentium3 -march=pentiumpro -march=pentium"
+	path="x86/p6/p3mmx x86/p6/mmx x86/p6 x86/mmx x86"
+	;;
+      pentiumm)
+	gcc_cflags_cpu="-mtune=pentium3 -mcpu=pentium3 -mcpu=pentiumpro -mcpu=i486 -m486"
+	gcc_cflags_arch="-march=pentium3 -march=pentiumpro -march=pentium"
+	path="x86/p6/sse2 x86/p6/p3mmx x86/p6/mmx x86/p6 x86/mmx x86"
+	;;
+      k6)
+	gcc_cflags_cpu="-mtune=k6 -mcpu=k6 -mcpu=i486 -m486"
+	gcc_cflags_arch="-march=k6"
+	path="x86/k6/mmx x86/k6 x86/mmx x86"
+	;;
+      k62)
+	gcc_cflags_cpu="-mtune=k6-2 -mcpu=k6-2 -mcpu=k6 -mcpu=i486 -m486"
+	gcc_cflags_arch="-march=k6-2 -march=k6"
+	path="x86/k6/k62mmx x86/k6/mmx x86/k6 x86/mmx x86"
+	;;
+      k63)
+	gcc_cflags_cpu="-mtune=k6-3 -mcpu=k6-3 -mcpu=k6 -mcpu=i486 -m486"
+	gcc_cflags_arch="-march=k6-3 -march=k6"
+	path="x86/k6/k62mmx x86/k6/mmx x86/k6 x86/mmx x86"
+	;;
+      geode)
+	gcc_cflags_cpu="-mtune=k6-3 -mcpu=k6-3 -mcpu=k6 -mcpu=i486 -m486"
+	gcc_cflags_arch="-march=k6-3 -march=k6"
+	path="x86/geode x86/k6/k62mmx x86/k6/mmx x86/k6 x86/mmx x86"
+	;;
+      athlon)
+	# Athlon instruction costs are close to P6 (3 cycle load latency,
+	# 4-6 cycle mul, 40 cycle div, pairable adc, etc) so if gcc doesn't
+	# know athlon (eg. 2.95.2 doesn't) then fall back on pentiumpro.
+	gcc_cflags_cpu="-mtune=athlon -mcpu=athlon -mcpu=pentiumpro -mcpu=i486 -m486"
+	gcc_cflags_arch="-march=athlon -march=pentiumpro -march=pentium"
+	path="x86/k7/mmx x86/k7 x86/mmx x86"
+	;;
+      i786 | pentium4)
+	# pentiumpro is the primary fallback when gcc doesn't know pentium4.
+	# This gets us cmov to eliminate branches.  Maybe "athlon" would be
+	# a possibility on gcc 3.0.
+	#
+	gcc_cflags_cpu="-mtune=pentium4 -mcpu=pentium4 -mcpu=pentiumpro -mcpu=i486 -m486"
+	gcc_cflags_arch="-march=pentium4 -march=pentium4~-mno-sse2 -march=pentiumpro -march=pentium"
+	gcc_64_cflags_cpu="-mtune=nocona"
+	path="x86/pentium4/sse2 x86/pentium4/mmx x86/pentium4 x86/mmx x86"
+	path_64="x86_64/pentium4 x86_64"
+	;;
+      viac32)
+	# Not sure of the best fallbacks here for -mcpu.
+	# c3-2 has sse and mmx, so pentium3 is good for -march.
+	gcc_cflags_cpu="-mtune=c3-2 -mcpu=c3-2 -mcpu=i486 -m486"
+	gcc_cflags_arch="-march=c3-2 -march=pentium3 -march=pentiumpro -march=pentium"
+	path="x86/p6/p3mmx x86/p6/mmx x86/p6 x86/mmx x86"
+	;;
+      viac3*)
+	# Not sure of the best fallbacks here.
+	gcc_cflags_cpu="-mtune=c3 -mcpu=c3 -mcpu=i486 -m486"
+	gcc_cflags_arch="-march=c3 -march=pentium-mmx -march=pentium"
+	path="x86/pentium/mmx x86/pentium x86/mmx x86"
+	;;
+      athlon64 | k8 | x86_64)
+	gcc_cflags_cpu="-mtune=k8 -mcpu=athlon -mcpu=pentiumpro -mcpu=i486 -m486"
+	gcc_cflags_arch="-march=k8 -march=k8~-mno-sse2 -march=athlon -march=pentiumpro -march=pentium"
+	path="x86/k8 x86/k7/mmx x86/k7 x86/mmx x86"
+	path_64="x86_64/k8 x86_64"
+	;;
+      k10)
+	gcc_cflags_cpu="-mtune=amdfam10 -mtune=k8"
+	gcc_cflags_arch="-march=amdfam10 -march=k8 -march=k8~-mno-sse2"
+	path="x86/k10 x86/k8 x86/k7/mmx x86/k7 x86/mmx x86"
+	path_64="x86_64/k10 x86_64/k8 x86_64"
+	;;
+      bobcat)
+	gcc_cflags_cpu="-mtune=btver1 -mtune=amdfam10 -mtune=k8"
+	gcc_cflags_arch="-march=btver1 -march=amdfam10 -march=k8 -march=k8~-mno-sse2"
+	path="x86/bt1 x86/k7/mmx x86/k7 x86/mmx x86"
+	path_64="x86_64/bt1 x86_64/k10 x86_64/k8 x86_64"
+	;;
+      jaguar | jaguarnoavx)
+	gcc_cflags_cpu="-mtune=btver2 -mtune=btver1 -mtune=amdfam10 -mtune=k8"
+	gcc_cflags_arch="-march=btver2 -march=btver1 -march=amdfam10 -march=k8 -march=k8~-mno-sse2"
+	path="x86/bt2 x86/bt1 x86/k7/mmx x86/k7 x86/mmx x86"
+	path_64="x86_64/bt2 x86_64/bt1 x86_64/k10 x86_64/k8 x86_64"
+	;;
+      bulldozer | bd1 | bulldozernoavx | bd1noavx)
+	gcc_cflags_cpu="-mtune=bdver1 -mtune=amdfam10 -mtune=k8"
+	gcc_cflags_arch="-march=bdver1 -march=amdfam10 -march=k8 -march=k8~-mno-sse2"
+	path="x86/bd1 x86/k7/mmx x86/k7 x86/mmx x86"
+	path_64="x86_64/bd1 x86_64/k10 x86_64/k8 x86_64"
+	;;
+      piledriver | bd2 | piledrivernoavx | bd2noavx)
+	gcc_cflags_cpu="-mtune=bdver2 -mtune=bdver1 -mtune=amdfam10 -mtune=k8"
+	gcc_cflags_arch="-march=bdver2 -march=bdver1 -march=amdfam10 -march=k8 -march=k8~-mno-sse2"
+	path="x86/bd2 x86/bd1 x86/k7/mmx x86/k7 x86/mmx x86"
+	path_64="x86_64/bd2 x86_64/bd1 x86_64/k10 x86_64/k8 x86_64"
+	;;
+      steamroller | bd3 | steamrollernoavx | bd3noavx)
+	gcc_cflags_cpu="-mtune=bdver3 -mtune=bdver2 -mtune=bdver1 -mtune=amdfam10 -mtune=k8"
+	gcc_cflags_arch="-march=bdver3 -march=bdver2 -march=bdver1 -march=amdfam10 -march=k8 -march=k8~-mno-sse2"
+	path="x86/bd3 x86/bd2 x86/bd1 x86/k7/mmx x86/k7 x86/mmx x86"
+	path_64="x86_64/bd3 x86_64/bd2 x86_64/bd1 x86_64/k10 x86_64/k8 x86_64"
+	;;
+      excavator | bd4 | excavatornoavx | bd4noavx)
+	gcc_cflags_cpu="-mtune=bdver4 -mtune=bdver3 -mtune=bdver2 -mtune=bdver1 -mtune=amdfam10 -mtune=k8"
+	gcc_cflags_arch="-march=bdver4 -march=bdver3 -march=bdver2 -march=bdver1 -march=amdfam10 -march=k8 -march=k8~-mno-sse2"
+	path="x86/bd4 x86/bd3 x86/bd2 x86/bd1 x86/k7/mmx x86/k7 x86/mmx x86"
+	path_64="x86_64/bd4 x86_64/bd3 x86_64/bd2 x86_64/bd1 x86_64/k10 x86_64/k8 x86_64"
+	x86_have_mulx=yes
+	;;
+      zen | zennoavx)
+	gcc_cflags_cpu="-mtune=znver1 -mtune=amdfam10 -mtune=k8"
+	gcc_cflags_arch="-march=znver1 -march=amdfam10 -march=k8"
+	path="x86/k7/mmx x86/k7 x86/mmx x86"
+	x86_have_mulx=yes
+	path_64="x86_64/zen x86_64"
+	;;
+      zen2 | zen2noavx)
+	gcc_cflags_cpu="-mtune=znver2 -mtune=znver1 -mtune=amdfam10 -mtune=k8"
+	gcc_cflags_arch="-march=znver2 -march=znver1 -march=amdfam10 -march=k8"
+	path="x86/k7/mmx x86/k7 x86/mmx x86"
+	x86_have_mulx=yes
+	path_64="x86_64/zen2 x86_64/zen x86_64"
+	;;
+      core2)
+	gcc_cflags_cpu="-mtune=core2 -mtune=k8"
+	gcc_cflags_arch="-march=core2 -march=core2~-mno-sse2 -march=k8 -march=k8~-mno-sse2"
+	path="x86/core2 x86/p6/sse2 x86/p6/p3mmx x86/p6/mmx x86/p6 x86/mmx x86"
+	path_64="x86_64/core2 x86_64"
+	;;
+      corei | coreinhm | coreiwsm | nehalem | westmere)
+	gcc_cflags_cpu="-mtune=nehalem -mtune=corei7 -mtune=core2 -mtune=k8"
+	gcc_cflags_arch="-march=nehalem -march=corei7 -march=core2 -march=core2~-mno-sse2 -march=k8 -march=k8~-mno-sse2"
+	path="x86/coreinhm x86/p6/sse2 x86/p6/p3mmx x86/p6/mmx x86/p6 x86/mmx x86"
+	path_64="x86_64/coreinhm x86_64/core2 x86_64"
+	;;
+      coreisbr | coreisbrnoavx | coreiibr | coreiibrnoavx | \
+      sandybridge | sandybridgenoavx | ivybridge | ivybridgenoavx)
+	gcc_cflags_cpu="-mtune=sandybridge -mtune=corei7 -mtune=core2 -mtune=k8"
+	gcc_cflags_arch="-march=sandybridge -march=corei7 -march=core2 -march=core2~-mno-sse2 -march=k8 -march=k8~-mno-sse2"
+	path="x86/coreisbr x86/p6/sse2 x86/p6/p3mmx x86/p6/mmx x86/p6 x86/mmx x86"
+	path_64="x86_64/coreisbr x86_64/coreinhm x86_64/core2 x86_64"
+	;;
+      coreihwl | coreihwlnoavx | haswell | haswellnoavx)
+	gcc_cflags_cpu="-mtune=haswell -mtune=corei7 -mtune=core2 -mtune=k8"
+	gcc_cflags_arch="-march=haswell -march=corei7 -march=core2 -march=core2~-mno-sse2 -march=k8 -march=k8~-mno-sse2"
+	path="x86/coreihwl x86/coreisbr x86/p6/sse2 x86/p6/p3mmx x86/p6/mmx x86/p6 x86/mmx x86"
+	path_64="x86_64/coreihwl x86_64/coreisbr x86_64/coreinhm x86_64/core2 x86_64"
+	x86_have_mulx=yes
+	;;
+      coreibwl | coreibwlnoavx | broadwell | broadwellnoavx)
+	gcc_cflags_cpu="-mtune=broadwell -mtune=corei7 -mtune=core2 -mtune=k8"
+	gcc_cflags_arch="-march=broadwell -march=corei7 -march=core2 -march=core2~-mno-sse2 -march=k8 -march=k8~-mno-sse2"
+	path="x86/coreihwl x86/coreisbr x86/p6/sse2 x86/p6/p3mmx x86/p6/mmx x86/p6 x86/mmx x86"
+	path_64="x86_64/coreibwl x86_64/coreihwl x86_64/coreisbr x86_64/coreinhm x86_64/core2 x86_64"
+	# extra_functions_64="missing"	 # enable for bmi2/adx simulation
+	x86_have_mulx=yes
+	;;
+      skylake | skylakenoavx | kabylake | kabylakenoavx)
+	gcc_cflags_cpu="-mtune=skylake -mtune=broadwell -mtune=corei7 -mtune=core2 -mtune=k8"
+	# Don't pass -march=skylake for now as then some compilers emit AVX512.
+	gcc_cflags_arch="-march=broadwell -march=corei7 -march=core2 -march=core2~-mno-sse2 -march=k8 -march=k8~-mno-sse2"
+	path="x86/coreihwl x86/coreisbr x86/p6/sse2 x86/p6/p3mmx x86/p6/mmx x86/p6 x86/mmx x86"
+	path_64="x86_64/skylake x86_64/coreibwl x86_64/coreihwl x86_64/coreisbr x86_64/coreinhm x86_64/core2 x86_64"
+	# extra_functions_64="missing"	 # enable for bmi2/adx simulation
+	x86_have_mulx=yes
+	;;
+      atom)			# in-order pipeline atom
+	gcc_cflags_cpu="-mtune=atom -mtune=pentium3"
+	gcc_cflags_arch="-march=atom -march=pentium3"
+	path="x86/atom/sse2 x86/atom/mmx x86/atom x86/mmx x86"
+	path_64="x86_64/atom x86_64"
+	;;
+      silvermont)		# out-of-order pipeline atom
+	gcc_cflags_cpu="-mtune=slm -mtune=atom -mtune=pentium3"
+	gcc_cflags_arch="-march=slm -march=atom -march=pentium3"
+	path="x86/silvermont x86/atom/sse2 x86/atom/mmx x86/atom x86/mmx x86"
+	path_64="x86_64/silvermont x86_64/atom x86_64"
+	;;
+      goldmont)			# out-of-order pipeline atom
+	gcc_cflags_cpu="-mtune=slm -mtune=atom -mtune=pentium3"
+	gcc_cflags_arch="-march=slm -march=atom -march=pentium3"
+	path="x86/goldmont x86/atom/sse2 x86/atom/mmx x86/atom x86/mmx x86"
+	path_64="x86_64/goldmont x86_64/silvermont x86_64/atom x86_64"
+	;;
+      nano)
+	gcc_cflags_cpu="-mtune=nano"
+	gcc_cflags_arch="-march=nano"
+	path="x86/nano x86/mmx x86"
+	path_64="x86_64/nano x86_64"
+	;;
+      *)
+	gcc_cflags_cpu="-mtune=i486 -mcpu=i486 -m486"
+	gcc_cflags_arch="-march=i486"
+	path="x86"
+	path_64="x86_64"
+	;;
+    esac
+
+    case $host in
+      # Disable AVX if the CPU part tells us AVX is unavailable, but also
+      # unconditionally for NetBSD where they don't work but OSXSAVE is set
+      # to claim the contrary.
+      *noavx-*-* | *-*-netbsd*)
+	gcc_cflags_noavx="-mno-avx"
+	GMP_DEFINE_RAW(["define(<GMP_AVX_NOT_REALLY_AVAILABLE>,1)"])
+	;;
+    esac
+
+    case $host in
+      X86_64_PATTERN)
+	cclist_64="gcc cc"
+	gcc_64_cflags="$gcc_cflags -m64"
+	gcc_64_cflags_optlist="cpu arch noavx"
+	CALLING_CONVENTIONS_OBJS_64='amd64call.lo amd64check$U.lo'
+	SPEED_CYCLECOUNTER_OBJ_64=x86_64.lo
+	cyclecounter_size_64=2
+
+	cclist_x32="gcc cc"
+	gcc_x32_cflags="$gcc_cflags -mx32"
+	gcc_x32_cflags_optlist="$gcc_64_cflags_optlist"
+	CALLING_CONVENTIONS_OBJS_x32="$CALLING_CONVENTIONS_OBJS_64"
+	SPEED_CYCLECOUNTER_OBJ_x32="$SPEED_CYCLECOUNTER_OBJ_64"
+	cyclecounter_size_x32="$cyclecounter_size_64"
+	path_x32="$path_64"
+	limb_x32=longlong
+	any_x32_testlist="sizeof-long-4"
+
+	abilist="64 x32 32"
+	if test "$enable_assembly" = "yes" ; then
+	    extra_functions_64="$extra_functions_64 invert_limb_table"
+	    extra_functions_x32=$extra_functions_64
+	fi
+
+	case $host in
+	  *-*-solaris*)
+	    # Sun cc.
+	    cc_64_cflags="-xO3 -m64"
+	    ;;
+	  *-*-mingw* | *-*-cygwin)
+	    limb_64=longlong
+	    CALLING_CONVENTIONS_OBJS_64=""
+	    AC_DEFINE(HOST_DOS64,1,[Define to 1 for Windos/64])
+	    GMP_NONSTD_ABI_64=DOS64
+	    ;;
+	esac
+	;;
+    esac
+    ;;
+
+
+  # Special CPU "none" used to select generic C, now this is obsolete.
+  none-*-*)
+    enable_assembly=no
+    AC_MSG_WARN([the \"none\" host is obsolete, use --disable-assembly])
+    ;;
+
+esac
+
+# mingw can be built by the cygwin gcc if -mno-cygwin is added.  For
+# convenience add this automatically if it works.  Actual mingw gcc accepts
+# -mno-cygwin too, but of course is the default.  mingw only runs on the
+# x86s, but allow any CPU here so as to catch "none" too.
+#
+case $host in
+  *-*-mingw*)
+    gcc_cflags_optlist="$gcc_cflags_optlist nocygwin"
+    gcc_cflags_nocygwin="-mno-cygwin"
+    ;;
+esac
+
+
+CFLAGS_or_unset=${CFLAGS-'(unset)'}
+CPPFLAGS_or_unset=${CPPFLAGS-'(unset)'}
+
+cat >&AC_FD_CC <<EOF
+User:
+ABI=$ABI
+CC=$CC
+CFLAGS=$CFLAGS_or_unset
+CPPFLAGS=$CPPFLAGS_or_unset
+MPN_PATH=$MPN_PATH
+GMP:
+abilist=$abilist
+cclist=$cclist
+EOF
+
+
+test_CFLAGS=${CFLAGS+set}
+test_CPPFLAGS=${CPPFLAGS+set}
+
+for abi in $abilist; do
+  abi_last="$abi"
+done
+
+# If the user specifies an ABI then it must be in $abilist, after that
+# $abilist is restricted to just that choice.
+#
+if test -n "$ABI"; then
+  found=no
+  for abi in $abilist; do
+    if test $abi = "$ABI"; then found=yes; break; fi
+  done
+  if test $found = no; then
+    AC_MSG_ERROR([ABI=$ABI is not among the following valid choices: $abilist])
+  fi
+  abilist="$ABI"
+fi
+
+found_compiler=no
+
+for abi in $abilist; do
+
+  echo "checking ABI=$abi"
+
+  # Suppose abilist="64 32", then for abi=64, will have abi1="_64" and
+  # abi2="_64".  For abi=32, will have abi1="_32" and abi2="".  This is how
+  # $gcc_cflags becomes a fallback for $gcc_32_cflags (the last in the
+  # abilist), but there's no fallback for $gcc_64_cflags.
+  #
+  abi1=[`echo _$abi | sed 's/[.]//g'`]
+  if test $abi = $abi_last; then abi2=; else abi2="$abi1"; fi
+
+  # Compiler choices under this ABI
+                              eval cclist_chosen=\"\$cclist$abi1\"
+  test -n "$cclist_chosen" || eval cclist_chosen=\"\$cclist$abi2\"
+
+  # If there's a user specified $CC then don't use a list for
+  # $cclist_chosen, just a single value for $ccbase.
+  #
+  if test -n "$CC"; then
+
+    # The first word of $CC, stripped of any directory.  For instance
+    # CC="/usr/local/bin/gcc -pipe" will give "gcc".
+    #
+    for ccbase in $CC; do break; done
+    ccbase=`echo $ccbase | sed 's:.*/::'`
+
+    # If this $ccbase is in $cclist_chosen then it's a compiler we know and
+    # we can do flags defaulting with it.  If not, then $cclist_chosen is
+    # set to "unrecognised" so no default flags are used.
+    #
+    # "unrecognised" is used to avoid bad effects with eval if $ccbase has
+    # non-symbol characters.  For instance ccbase=my+cc would end up with
+    # something like cflags="$my+cc_cflags" which would give
+    # cflags="+cc_cflags" rather than the intended empty string for an
+    # unknown compiler.
+    #
+    found=unrecognised
+    for i in $cclist_chosen; do
+      if test "$ccbase" = $i; then
+        found=$ccbase
+        break
+      fi
+    done
+    cclist_chosen=$found
+  fi
+
+  for ccbase in $cclist_chosen; do
+
+    # When cross compiling, look for a compiler with the $host_alias as a
+    # prefix, the same way that AC_CHECK_TOOL does.  But don't do this to a
+    # user-selected $CC.
+    #
+    # $cross_compiling will be yes/no/maybe at this point.  Do the host
+    # prefixing for "maybe" as well as "yes".
+    #
+    if test "$cross_compiling" != no && test -z "$CC"; then
+      cross_compiling_prefix="${host_alias}-"
+    fi
+
+    for ccprefix in $cross_compiling_prefix ""; do
+
+      cc="$CC"
+      test -n "$cc" || cc="$ccprefix$ccbase"
+
+      # If the compiler is gcc but installed under another name, then change
+      # $ccbase so as to use the flags we know for gcc.  This helps for
+      # instance when specifying CC=gcc272 on Debian GNU/Linux, or the
+      # native cc which is really gcc on NeXT or MacOS-X.
+      #
+      # FIXME: There's a slight misfeature here.  If cc is actually gcc but
+      # gcc is not a known compiler under this $abi then we'll end up
+      # testing it with no flags and it'll work, but chances are it won't be
+      # in the right mode for the ABI we desire.  Let's quietly hope this
+      # doesn't happen.
+      #
+      if test $ccbase != gcc; then
+        GMP_PROG_CC_IS_GNU($cc,ccbase=gcc)
+      fi
+
+      # Similarly if the compiler is IBM xlc but invoked as cc or whatever
+      # then change $ccbase and make the default xlc flags available.
+      if test $ccbase != xlc; then
+        GMP_PROG_CC_IS_XLC($cc,ccbase=xlc)
+      fi
+
+      # acc was Sun's first unbundled compiler back in the SunOS days, or
+      # something like that, but today its man page says it's not meant to
+      # be used directly (instead via /usr/ucb/cc).  The options are pretty
+      # much the same as the main SunPRO cc, so share those configs.
+      #
+      case $host in
+        *sparc*-*-solaris* | *sparc*-*-sunos*)
+          if test "$ccbase" = acc; then ccbase=cc; fi ;;
+      esac
+
+      for tmp_cflags_maybe in yes no; do
+                             eval cflags=\"\$${ccbase}${abi1}_cflags\"
+        test -n "$cflags" || eval cflags=\"\$${ccbase}${abi2}_cflags\"
+
+	if test "$tmp_cflags_maybe" = yes; then
+          # don't try cflags_maybe when the user set CFLAGS
+          if test "$test_CFLAGS" = set; then continue; fi
+                                     eval cflags_maybe=\"\$${ccbase}${abi1}_cflags_maybe\"
+          test -n "$cflags_maybe" || eval cflags_maybe=\"\$${ccbase}${abi2}_cflags_maybe\"
+          # don't try cflags_maybe if there's nothing set
+          if test -z "$cflags_maybe"; then continue; fi
+          cflags="$cflags_maybe $cflags"
+        fi
+
+        # Any user CFLAGS, even an empty string, takes precedence
+        if test "$test_CFLAGS" = set; then cflags=$CFLAGS; fi
+
+        # Any user CPPFLAGS, even an empty string, takes precedence
+                               eval cppflags=\"\$${ccbase}${abi1}_cppflags\"
+        test -n "$cppflags" || eval cppflags=\"\$${ccbase}${abi2}_cppflags\"
+        if test "$test_CPPFLAGS" = set; then cppflags=$CPPFLAGS; fi
+
+        # --enable-profiling adds -p/-pg even to user-specified CFLAGS.
+        # This is convenient, but it's perhaps a bit naughty to modify user
+        # CFLAGS.
+        case "$enable_profiling" in
+          prof)       cflags="$cflags -p" ;;
+          gprof)      cflags="$cflags -pg" ;;
+          instrument) cflags="$cflags -finstrument-functions" ;;
+        esac
+
+        GMP_PROG_CC_WORKS($cc $cflags $cppflags,,continue)
+
+        # If we're supposed to be using a "long long" for a limb, check that
+        # it works.
+                                  eval limb_chosen=\"\$limb$abi1\"
+        test -n "$limb_chosen" || eval limb_chosen=\"\$limb$abi2\"
+        if test "$limb_chosen" = longlong; then
+          GMP_PROG_CC_WORKS_LONGLONG($cc $cflags $cppflags,,continue)
+        fi
+
+        # The tests to perform on this $cc, if any
+                               eval testlist=\"\$${ccbase}${abi1}_testlist\"
+        test -n "$testlist" || eval testlist=\"\$${ccbase}${abi2}_testlist\"
+        test -n "$testlist" || eval testlist=\"\$any${abi1}_testlist\"
+        test -n "$testlist" || eval testlist=\"\$any${abi2}_testlist\"
+
+        testlist_pass=yes
+        for tst in $testlist; do
+          case $tst in
+          hpc-hppa-2-0)   GMP_HPC_HPPA_2_0($cc,,testlist_pass=no) ;;
+          gcc-arm-umodsi) GMP_GCC_ARM_UMODSI($cc,,testlist_pass=no) ;;
+          gcc-mips-o32)   GMP_GCC_MIPS_O32($cc,,testlist_pass=no) ;;
+          hppa-level-2.0) GMP_HPPA_LEVEL_20($cc $cflags,,testlist_pass=no) ;;
+          sizeof*)       GMP_C_TEST_SIZEOF($cc $cflags,$tst,,testlist_pass=no) ;;
+          esac
+          if test $testlist_pass = no; then break; fi
+        done
+
+        if test $testlist_pass = yes; then
+          found_compiler=yes
+          break
+        fi
+      done
+
+      if test $found_compiler = yes; then break; fi
+    done
+
+    if test $found_compiler = yes; then break; fi
+  done
+
+  if test $found_compiler = yes; then break; fi
+done
+
+
+# If we recognised the CPU, as indicated by $path being set, then insist
+# that we have a working compiler, either from our $cclist choices or from
+# $CC.  We can't let AC_PROG_CC look around for a compiler because it might
+# find one that we've rejected (for not supporting the modes our asm code
+# demands, etc).
+#
+# If we didn't recognise the CPU (and this includes host_cpu=none), then
+# fall through and let AC_PROG_CC look around for a compiler too.  This is
+# mostly in the interests of following a standard autoconf setup, after all
+# we've already tested cc and gcc adequately (hopefully).  As of autoconf
+# 2.50 the only thing AC_PROG_CC really adds is a check for "cl" (Microsoft
+# C on MS-DOS systems).
+#
+if test $found_compiler = no && test -n "$path"; then
+  AC_MSG_ERROR([could not find a working compiler, see config.log for details])
+fi
+
+case $host in
+  X86_PATTERN | X86_64_PATTERN)
+    # If the user asked for a fat build, override the path and flags set above
+    if test $enable_fat = yes; then
+      gcc_cflags_cpu=""
+      gcc_cflags_arch=""
+
+      fat_functions="add_n addmul_1 bdiv_dbm1c com cnd_add_n cnd_sub_n
+		     copyd copyi dive_1 divrem_1
+		     gcd_11 lshift lshiftc mod_1 mod_1_1 mod_1_1_cps mod_1_2
+		     mod_1_2_cps mod_1_4 mod_1_4_cps mod_34lsub1 mode1o mul_1
+		     mul_basecase mullo_basecase pre_divrem_1 pre_mod_1 redc_1
+		     redc_2 rshift sqr_basecase sub_n submul_1"
+
+      if test "$abi" = 32; then
+	extra_functions="$extra_functions fat fat_entry"
+	path="x86/fat x86"
+	fat_path="x86 x86/fat x86/i486
+		  x86/k6 x86/k6/mmx x86/k6/k62mmx
+		  x86/k7 x86/k7/mmx
+		  x86/k8 x86/k10 x86/bt1
+		  x86/pentium x86/pentium/mmx
+		  x86/p6 x86/p6/mmx x86/p6/p3mmx x86/p6/sse2
+		  x86/pentium4 x86/pentium4/mmx x86/pentium4/sse2
+		  x86/core2 x86/coreinhm x86/coreisbr
+		  x86/atom x86/atom/mmx x86/atom/sse2 x86/nano"
+      fi
+
+      if test "$abi" = 64; then
+	gcc_64_cflags=""
+	extra_functions_64="$extra_functions_64 fat fat_entry"
+	path_64="x86_64/fat x86_64"
+	fat_path="x86_64 x86_64/fat
+		  x86_64/k8 x86_64/k10 x86_64/bd1 x86_64/bt1 x86_64/bt2 x86_64/zen
+		  x86_64/pentium4 x86_64/core2 x86_64/coreinhm x86_64/coreisbr
+		  x86_64/coreihwl x86_64/coreibwl x86_64/skylake x86_64/atom
+		  x86_64/silvermont x86_64/goldmont x86_64/nano"
+	fat_functions="$fat_functions addmul_2 addlsh1_n addlsh2_n sublsh1_n"
+      fi
+
+      fat_thresholds="MUL_TOOM22_THRESHOLD MUL_TOOM33_THRESHOLD
+		      SQR_TOOM2_THRESHOLD SQR_TOOM3_THRESHOLD
+		      BMOD_1_TO_MOD_1_THRESHOLD"
+    fi
+    ;;
+esac
+
+
+if test $found_compiler = yes; then
+
+  # If we're creating CFLAGS, then look for optional additions.  If the user
+  # set CFLAGS then leave it alone.
+  #
+  if test "$test_CFLAGS" != set; then
+                          eval optlist=\"\$${ccbase}${abi1}_cflags_optlist\"
+    test -n "$optlist" || eval optlist=\"\$${ccbase}${abi2}_cflags_optlist\"
+
+    for opt in $optlist; do
+                             eval optflags=\"\$${ccbase}${abi1}_cflags_${opt}\"
+      test -n "$optflags" || eval optflags=\"\$${ccbase}${abi2}_cflags_${opt}\"
+      test -n "$optflags" || eval optflags=\"\$${ccbase}_cflags_${opt}\"
+
+      for flag in $optflags; do
+
+	# ~ represents a space in an option spec
+        flag=`echo "$flag" | tr '~' ' '`
+
+        case $flag in
+          -march=pentium4 | -march=k8)
+            # For -march settings which enable SSE2 we exclude certain bad
+            # gcc versions and we need an OS knowing how to save xmm regs.
+            #
+            # This is only for ABI=32, any 64-bit gcc is good and any OS
+            # knowing x86_64 will know xmm.
+            #
+            # -march=k8 was only introduced in gcc 3.3, so we shouldn't need
+            # the GMP_GCC_PENTIUM4_SSE2 check (for gcc 3.2 and prior).  But
+            # it doesn't hurt to run it anyway, sharing code with the
+            # pentium4 case.
+            #
+            if test "$abi" = 32; then
+              GMP_GCC_PENTIUM4_SSE2($cc $cflags $cppflags,, continue)
+              GMP_OS_X86_XMM($cc $cflags $cppflags,, continue)
+            fi
+            ;;
+          -no-cpp-precomp)
+            # special check, avoiding a warning
+            GMP_GCC_NO_CPP_PRECOMP($ccbase,$cc,$cflags,
+                                   [cflags="$cflags $flag"
+                                   break],
+                                   [continue])
+            ;;
+          -Wa,-m*)
+            case $host in
+              alpha*-*-*)
+                GMP_GCC_WA_MCPU($cc $cflags, $flag, , [continue])
+              ;;
+            esac
+            ;;
+          -Wa,-oldas)
+            GMP_GCC_WA_OLDAS($cc $cflags $cppflags,
+                             [cflags="$cflags $flag"
+                             break],
+                             [continue])
+            ;;
+        esac
+
+        GMP_PROG_CC_WORKS($cc $cflags $cppflags $flag,
+          [cflags="$cflags $flag"
+          break])
+      done
+    done
+  fi
+
+  ABI="$abi"
+  CC="$cc"
+  CFLAGS="$cflags"
+  CPPFLAGS="$cppflags"
+
+  # Could easily have this in config.h too, if desired.
+  ABI_nodots=`echo $ABI | sed 's/\./_/'`
+  GMP_DEFINE_RAW("define_not_for_expansion(\`HAVE_ABI_$ABI_nodots')", POST)
+
+  eval GMP_NONSTD_ABI=\"\$GMP_NONSTD_ABI_$ABI_nodots\"
+
+  # GMP_LDFLAGS substitution, selected according to ABI.
+  # These are needed on libgmp.la and libmp.la, but currently not on
+  # convenience libraries like tune/libspeed.la or mpz/libmpz.la.
+  #
+                            eval GMP_LDFLAGS=\"\$${ccbase}${abi1}_ldflags\"
+  test -n "$GMP_LDFLAGS" || eval GMP_LDFLAGS=\"\$${ccbase}${abi1}_ldflags\"
+  AC_SUBST(GMP_LDFLAGS)
+  AC_SUBST(LIBGMP_LDFLAGS)
+  AC_SUBST(LIBGMPXX_LDFLAGS)
+
+  # extra_functions, selected according to ABI
+                    eval tmp=\"\$extra_functions$abi1\"
+  test -n "$tmp" || eval tmp=\"\$extra_functions$abi2\"
+  extra_functions="$tmp"
+
+
+  # Cycle counter, selected according to ABI.
+  #
+                    eval tmp=\"\$SPEED_CYCLECOUNTER_OBJ$abi1\"
+  test -n "$tmp" || eval tmp=\"\$SPEED_CYCLECOUNTER_OBJ$abi2\"
+  SPEED_CYCLECOUNTER_OBJ="$tmp"
+                    eval tmp=\"\$cyclecounter_size$abi1\"
+  test -n "$tmp" || eval tmp=\"\$cyclecounter_size$abi2\"
+  cyclecounter_size="$tmp"
+
+  if test -n "$SPEED_CYCLECOUNTER_OBJ"; then
+    AC_DEFINE_UNQUOTED(HAVE_SPEED_CYCLECOUNTER, $cyclecounter_size,
+    [Tune directory speed_cyclecounter, undef=none, 1=32bits, 2=64bits)])
+  fi
+  AC_SUBST(SPEED_CYCLECOUNTER_OBJ)
+
+
+  # Calling conventions checking, selected according to ABI.
+  #
+                    eval tmp=\"\$CALLING_CONVENTIONS_OBJS$abi1\"
+  test -n "$tmp" || eval tmp=\"\$CALLING_CONVENTIONS_OBJS$abi2\"
+  if test "$enable_assembly" = "yes"; then
+     CALLING_CONVENTIONS_OBJS="$tmp"
+  else
+     CALLING_CONVENTIONS_OBJS=""
+  fi
+
+  if test -n "$CALLING_CONVENTIONS_OBJS"; then
+    AC_DEFINE(HAVE_CALLING_CONVENTIONS,1,
+    [Define to 1 if tests/libtests has calling conventions checking for the CPU])
+  fi
+  AC_SUBST(CALLING_CONVENTIONS_OBJS)
+
+fi
+
+
+# If the user gave an MPN_PATH, use that verbatim, otherwise choose
+# according to the ABI and add "generic".
+#
+if test -n "$MPN_PATH"; then
+  path="$MPN_PATH"
+else
+                    eval tmp=\"\$path$abi1\"
+  test -n "$tmp" || eval tmp=\"\$path$abi2\"
+  path="$tmp generic"
+fi
+
+
+# Long long limb setup for gmp.h.
+case $limb_chosen in
+longlong) DEFN_LONG_LONG_LIMB="#define _LONG_LONG_LIMB 1"    ;;
+*)        DEFN_LONG_LONG_LIMB="/* #undef _LONG_LONG_LIMB */" ;;
+esac
+AC_SUBST(DEFN_LONG_LONG_LIMB)
+
+
+# The C compiler and preprocessor, put into ANSI mode if possible.
+AC_PROG_CC
+AC_PROG_CC_C99
+AC_PROG_CPP
+
+#if test "$ac_cv_prog_cc_c99" = no; then
+#  AC_MSG_ERROR([Cannot find a C99 capable compiler])
+#fi
+
+# The C compiler on the build system, and associated tests.
+GMP_PROG_CC_FOR_BUILD
+GMP_PROG_CPP_FOR_BUILD
+GMP_PROG_EXEEXT_FOR_BUILD
+GMP_C_FOR_BUILD_ANSI
+GMP_CHECK_LIBM_FOR_BUILD
+
+
+# How to assemble, used with CFLAGS etc, see mpn/Makeasm.am.
+# Using the compiler is a lot easier than figuring out how to invoke the
+# assembler directly.
+#
+test -n "$CCAS" || CCAS="$CC -c"
+AC_SUBST(CCAS)
+
+
+# The C++ compiler, if desired.
+want_cxx=no
+if test $enable_cxx != no; then
+  test_CXXFLAGS=${CXXFLAGS+set}
+  AC_PROG_CXX
+
+  echo "CXXFLAGS chosen by autoconf: $CXXFLAGS" >&AC_FD_CC
+  cxxflags_ac_prog_cxx=$CXXFLAGS
+  cxxflags_list=ac_prog_cxx
+
+  # If the user didn't specify $CXXFLAGS, then try $CFLAGS, with -g removed
+  # if AC_PROG_CXX thinks that doesn't work.  $CFLAGS stands a good chance
+  # of working, eg. on a GNU system where CC=gcc and CXX=g++.
+  #
+  if test "$test_CXXFLAGS" != set; then
+    cxxflags_cflags=$CFLAGS
+    cxxflags_list="cflags $cxxflags_list"
+    if test "$ac_prog_cxx_g" = no; then
+      cxxflags_cflags=`echo "$cxxflags_cflags" | sed -e 's/ -g //' -e 's/^-g //' -e 's/ -g$//'`
+    fi
+  fi
+
+  # See if the C++ compiler works.  If the user specified CXXFLAGS then all
+  # we're doing is checking whether AC_PROG_CXX succeeded, since it doesn't
+  # give a fatal error, just leaves CXX set to a default g++.  If on the
+  # other hand the user didn't specify CXXFLAGS then we get to try here our
+  # $cxxflags_list alternatives.
+  #
+  # Automake includes $CPPFLAGS in a C++ compile, so we do the same here.
+  #
+  for cxxflags_choice in $cxxflags_list; do
+    eval CXXFLAGS=\"\$cxxflags_$cxxflags_choice\"
+    GMP_PROG_CXX_WORKS($CXX $CPPFLAGS $CXXFLAGS,
+      [want_cxx=yes
+      break])
+  done
+
+  # If --enable-cxx=yes but a C++ compiler can't be found, then abort.
+  if test $want_cxx = no && test $enable_cxx = yes; then
+    AC_MSG_ERROR([C++ compiler not available, see config.log for details])
+  fi
+fi
+
+AM_CONDITIONAL(WANT_CXX, test $want_cxx = yes)
+
+# FIXME: We're not interested in CXXCPP for ourselves, but if we don't do it
+# here then AC_PROG_LIBTOOL will AC_REQUIRE it (via _LT_AC_TAGCONFIG) and
+# hence execute it unconditionally, and that will fail if there's no C++
+# compiler (and no generic /lib/cpp).
+#
+if test $want_cxx = yes; then
+  AC_PROG_CXXCPP
+fi
+
+
+# Path setups for Cray, according to IEEE or CFP.  These must come after
+# deciding the compiler.
+#
+GMP_CRAY_OPTIONS(
+  [add_path="cray/ieee"],
+  [add_path="cray/cfp"; extra_functions="mulwwc90"],
+  [add_path="cray/cfp"; extra_functions="mulwwj90"])
+
+
+if test -z "$MPN_PATH"; then
+  path="$add_path $path"
+fi
+
+# For a nail build, also look in "nails" subdirectories.
+#
+if test $GMP_NAIL_BITS != 0 && test -z "$MPN_PATH"; then
+  new_path=
+  for i in $path; do
+    case $i in
+    generic) new_path="$new_path $i" ;;
+    *)       new_path="$new_path $i/nails $i" ;;
+    esac
+  done
+  path=$new_path
+fi
+
+
+# Put all directories into CPUVEC_list so as to get a full set of
+# CPUVEC_SETUP_$tmp_suffix defines into config.h, even if some of them are
+# empty because mmx and/or sse2 had to be dropped.
+#
+for i in $fat_path; do
+  GMP_FAT_SUFFIX(tmp_suffix, $i)
+  CPUVEC_list="$CPUVEC_list CPUVEC_SETUP_$tmp_suffix"
+done
+
+
+# If there's any sse2 or mmx in the path, check whether the assembler
+# supports it, and remove if not.
+#
+# We only need this in ABI=32, for ABI=64 on x86_64 we can assume a new
+# enough assembler.
+#
+case $host in
+  X86_PATTERN | X86_64_PATTERN)
+    if test "$ABI" = 32; then
+      case "$path $fat_path" in
+        *mmx*)   GMP_ASM_X86_MMX( , [GMP_STRIP_PATH(*mmx*)]) ;;
+      esac
+      case "$path $fat_path" in
+        *sse2*)  GMP_ASM_X86_SSE2( , [GMP_STRIP_PATH(sse2)]) ;;
+      esac
+    fi
+    ;;
+esac
+
+
+if test "$enable_assembly" = "no"; then
+  path="generic"
+  AC_DEFINE([NO_ASM],1,[Define to 1 to disable the use of inline assembly])
+#  for abi in $abilist; do
+#    eval unset "path_\$abi"
+#    eval gcc_${abi}_cflags=\"\$gcc_${abi}_cflags -DNO_ASM\"
+#  done
+fi
+
+
+cat >&AC_FD_CC <<EOF
+Decided:
+ABI=$ABI
+CC=$CC
+CFLAGS=$CFLAGS
+CPPFLAGS=$CPPFLAGS
+GMP_LDFLAGS=$GMP_LDFLAGS
+CXX=$CXX
+CXXFLAGS=$CXXFLAGS
+path=$path
+EOF
+echo "using ABI=\"$ABI\""
+echo "      CC=\"$CC\""
+echo "      CFLAGS=\"$CFLAGS\""
+echo "      CPPFLAGS=\"$CPPFLAGS\""
+if test $want_cxx = yes; then
+  echo "      CXX=\"$CXX\""
+  echo "      CXXFLAGS=\"$CXXFLAGS\""
+fi
+echo "      MPN_PATH=\"$path\""
+
+
+CL_AS_NOEXECSTACK
+
+GMP_PROG_AR
+GMP_PROG_NM
+
+case $host in
+  # FIXME: On AIX 3 and 4, $libname.a is included in libtool
+  # $library_names_spec, so libgmp.a becomes a symlink to libgmp.so, making
+  # it impossible to build shared and static libraries simultaneously.
+  # Disable shared libraries by default, but let the user override with
+  # --enable-shared --disable-static.
+  #
+  # FIXME: This $libname.a problem looks like it might apply to *-*-amigaos*
+  # and *-*-os2* too, but wait for someone to test this before worrying
+  # about it.  If there is a problem then of course libtool is the right
+  # place to fix it.
+  #
+  [*-*-aix[34]*])
+    if test -z "$enable_shared"; then enable_shared=no; fi ;;
+esac
+
+
+# Configs for Windows DLLs.
+
+AC_LIBTOOL_WIN32_DLL
+
+AC_SUBST(LIBGMP_DLL,0)
+case $host in
+  *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
+    # By default, build only static.
+    if test -z "$enable_shared"; then
+      enable_shared=no
+    fi
+    # Don't allow both static and DLL.
+    if test "$enable_shared" != no && test "$enable_static" != no; then
+      AC_MSG_ERROR([cannot build both static and DLL, since gmp.h is different for each.
+Use "--disable-static --enable-shared" to build just a DLL.])
+    fi
+
+    # "-no-undefined" is required when building a DLL, see documentation on
+    # AC_LIBTOOL_WIN32_DLL.
+    #
+    # "-Wl,--export-all-symbols" is a bit of a hack, it gets all libgmp and
+    # libgmpxx functions and variables exported.  This is what libtool did
+    # in the past, and it's convenient for us in the test programs.
+    #
+    # Maybe it'd be prudent to check for --export-all-symbols before using
+    # it, but it seems to have been in ld since at least 2000, and there's
+    # not really any alternative we want to take up at the moment.
+    #
+    # "-Wl,output-def" is used to get a .def file for use by MS lib to make
+    # a .lib import library, described in the manual.  libgmp-3.dll.def
+    # corresponds to the libmp-3.dll.def generated by libtool (as a result
+    # of -export-symbols on that library).
+    #
+    # Incidentally, libtool does generate an import library libgmp.dll.a,
+    # but it's "ar" format and cannot be used by the MS linker.  There
+    # doesn't seem to be any GNU tool for generating or converting to .lib.
+    #
+    # FIXME: The .def files produced by -Wl,output-def include isascii,
+    # iscsym, iscsymf and toascii, apparently because mingw ctype.h doesn't
+    # inline isascii (used in gmp).  It gives an extern inline for
+    # __isascii, but for some reason not the plain isascii.
+    #
+    if test "$enable_shared" = yes; then
+      GMP_LDFLAGS="$GMP_LDFLAGS -no-undefined -Wl,--export-all-symbols"
+      LIBGMP_LDFLAGS="$LIBGMP_LDFLAGS -Wl,--output-def,.libs/libgmp-3.dll.def"
+      LIBGMPXX_LDFLAGS="$LIBGMP_LDFLAGS -Wl,--output-def,.libs/libgmpxx-3.dll.def"
+      LIBGMP_DLL=1
+    fi
+    ;;
+esac
+
+
+# Ensure that $CONFIG_SHELL is available for AC_LIBTOOL_SYS_MAX_CMD_LEN.
+# It's often set already by _LT_AC_PROG_ECHO_BACKSLASH or
+# _AS_LINENO_PREPARE, but not always.
+#
+# The symptom of CONFIG_SHELL unset is some "expr" errors during the test,
+# and an empty result.  This only happens when invoked as "sh configure",
+# ie. no path, and can be seen for instance on ia64-*-hpux*.
+#
+# FIXME: Newer libtool should have it's own fix for this.
+#
+if test -z "$CONFIG_SHELL"; then
+  CONFIG_SHELL=$SHELL
+fi
+
+# Enable CXX in libtool only if we want it, and never enable GCJ, nor RC on
+# mingw and cygwin.  Under --disable-cxx this avoids some error messages
+# from libtool arising from the fact we didn't actually run AC_PROG_CXX.
+# Notice that any user-supplied --with-tags setting takes precedence.
+#
+# FIXME: Is this the right way to get this effect?  Very possibly not, but
+# the current _LT_AC_TAGCONFIG doesn't really suggest an alternative.
+#
+if test "${with_tags+set}" != set; then
+  if test $want_cxx = yes; then
+    with_tags=CXX
+  else
+    with_tags=
+  fi
+fi
+
+# The dead hand of AC_REQUIRE makes AC_PROG_LIBTOOL expand and execute
+# AC_PROG_F77, even when F77 is not in the selected with_tags.  This is
+# probably harmless, but it's unsightly and bloats our configure, so pretend
+# AC_PROG_F77 has been expanded already.
+#
+# FIXME: Rumour has it libtool will one day provide a way for a configure.in
+# to say what it wants from among supported languages etc.
+#
+#AC_PROVIDE([AC_PROG_F77])
+
+AC_PROG_LIBTOOL
+
+# Generate an error here if attempting to build both shared and static when
+# $libname.a is in $library_names_spec (as mentioned above), rather than
+# wait for ar or ld to fail.
+#
+if test "$enable_shared" = yes && test "$enable_static" = yes; then
+  case $library_names_spec in
+    *libname.a*)
+      AC_MSG_ERROR([cannot create both shared and static libraries on this system, --disable one of the two])
+      ;;
+  esac
+fi
+
+AM_CONDITIONAL(ENABLE_STATIC, test "$enable_static" = yes)
+
+
+# Many of these library and header checks are for the benefit of
+# supplementary programs.  libgmp doesn't use anything too weird.
+
+AC_HEADER_STDC
+AC_HEADER_TIME
+
+# Reasons for testing:
+#   float.h - not in SunOS bundled cc
+#   invent.h - IRIX specific
+#   langinfo.h - X/Open standard only, not in djgpp for instance
+#   locale.h - old systems won't have this
+#   nl_types.h - X/Open standard only, not in djgpp for instance
+#       (usually langinfo.h gives nl_item etc, but not on netbsd 1.4.1)
+#   sys/attributes.h - IRIX specific
+#   sys/iograph.h - IRIX specific
+#   sys/mman.h - not in Cray Unicos
+#   sys/param.h - not in mingw
+#   sys/processor.h - solaris specific, though also present in macos
+#   sys/pstat.h - HPUX specific
+#   sys/resource.h - not in mingw
+#   sys/sysctl.h - not in mingw
+#   sys/sysinfo.h - OSF specific
+#   sys/syssgi.h - IRIX specific
+#   sys/systemcfg.h - AIX specific
+#   sys/time.h - autoconf suggests testing, don't know anywhere without it
+#   sys/times.h - not in mingw
+#   machine/hal_sysinfo.h - OSF specific
+#
+# inttypes.h, stdint.h, unistd.h and sys/types.h are already in the autoconf
+# default tests
+#
+AC_CHECK_HEADERS(fcntl.h float.h invent.h langinfo.h locale.h nl_types.h sys/attributes.h sys/iograph.h sys/mman.h sys/param.h sys/processor.h sys/pstat.h sys/sysinfo.h sys/syssgi.h sys/systemcfg.h sys/time.h sys/times.h)
+
+# On SunOS, sys/resource.h needs sys/time.h (for struct timeval)
+AC_CHECK_HEADERS(sys/resource.h,,,
+[#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif])
+
+# On NetBSD and OpenBSD, sys/sysctl.h needs sys/param.h for various constants
+AC_CHECK_HEADERS(sys/sysctl.h,,,
+[#if HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#endif])
+
+# On OSF 4.0, <machine/hal_sysinfo.h> must have <sys/sysinfo.h> for ulong_t
+AC_CHECK_HEADERS(machine/hal_sysinfo.h,,,
+[#if HAVE_SYS_SYSINFO_H
+# include <sys/sysinfo.h>
+#endif])
+
+# Reasons for testing:
+#   optarg - not declared in mingw
+#   fgetc, fscanf, ungetc, vfprintf - not declared in SunOS 4
+#   sys_errlist, sys_nerr - not declared in SunOS 4
+#
+# optarg should be in unistd.h and the rest in stdio.h, both of which are
+# in the autoconf default includes.
+#
+# sys_errlist and sys_nerr are supposed to be in <errno.h> on SunOS according
+# to the man page (but aren't), in glibc they're in stdio.h.
+#
+AC_CHECK_DECLS([fgetc, fscanf, optarg, ungetc, vfprintf])
+AC_CHECK_DECLS([sys_errlist, sys_nerr], , ,
+[#include <stdio.h>
+#include <errno.h>])
+
+AC_TYPE_SIGNAL
+
+# Reasons for testing:
+#   intmax_t       - C99
+#   long double    - not in the HP bundled K&R cc
+#   long long      - only in reasonably recent compilers
+#   ptrdiff_t      - seems to be everywhere, maybe don't need to check this
+#   quad_t         - BSD specific
+#   uint_least32_t - C99
+#
+# the default includes are sufficient for all these types
+#
+AC_CHECK_TYPES([intmax_t, long double, long long, ptrdiff_t, quad_t,
+		uint_least32_t, intptr_t])
+
+# FIXME: Really want #ifndef __cplusplus around the #define volatile
+# replacement autoconf gives, since volatile is always available in C++.
+# But we don't use it in C++ currently.
+AC_C_VOLATILE
+
+AC_C_RESTRICT
+
+# GMP_C_STDARG
+GMP_C_ATTRIBUTE_CONST
+GMP_C_ATTRIBUTE_MALLOC
+GMP_C_ATTRIBUTE_MODE
+GMP_C_ATTRIBUTE_NORETURN
+GMP_C_HIDDEN_ALIAS
+
+GMP_H_EXTERN_INLINE
+
+# from libtool
+AC_CHECK_LIBM
+AC_SUBST(LIBM)
+
+GMP_FUNC_ALLOCA
+GMP_OPTION_ALLOCA
+
+GMP_H_HAVE_FILE
+
+AC_C_BIGENDIAN(
+  [AC_DEFINE(HAVE_LIMB_BIG_ENDIAN, 1)
+   GMP_DEFINE_RAW("define_not_for_expansion(\`HAVE_LIMB_BIG_ENDIAN')", POST)],
+  [AC_DEFINE(HAVE_LIMB_LITTLE_ENDIAN, 1)
+   GMP_DEFINE_RAW("define_not_for_expansion(\`HAVE_LIMB_LITTLE_ENDIAN')", POST)
+  ], [:])
+AH_VERBATIM([HAVE_LIMB],
+[/* Define one of these to 1 for the endianness of `mp_limb_t'.
+   If the endianness is not a simple big or little, or you don't know what
+   it is, then leave both undefined. */
+#undef HAVE_LIMB_BIG_ENDIAN
+#undef HAVE_LIMB_LITTLE_ENDIAN])
+
+GMP_C_DOUBLE_FORMAT
+
+
+# Reasons for testing:
+#   alarm - not in mingw
+#   attr_get - IRIX specific
+#   clock_gettime - not in glibc 2.2.4, only very recent systems
+#   cputime - not in glibc
+#   getsysinfo - OSF specific
+#   getrusage - not in mingw
+#   gettimeofday - not in mingw
+#   mmap - not in mingw, djgpp
+#   nl_langinfo - X/Open standard only, not in djgpp for instance
+#   obstack_vprintf - glibc specific
+#   processor_info - solaris specific
+#   pstat_getprocessor - HPUX specific (10.x and up)
+#   raise - an ANSI-ism, though probably almost universal by now
+#   read_real_time - AIX specific
+#   sigaction - not in mingw
+#   sigaltstack - not in mingw, or old AIX (reputedly)
+#   sigstack - not in mingw
+#   strerror - not in SunOS
+#   strnlen - glibc extension (some other systems too)
+#   syssgi - IRIX specific
+#   times - not in mingw
+#
+# AC_FUNC_STRNLEN is not used because we don't want the AC_LIBOBJ
+# replacement setups it gives.  It detects a faulty strnlen on AIX, but
+# missing out on that test is ok since our only use of strnlen is in
+# __gmp_replacement_vsnprintf which is not required on AIX since it has a
+# vsnprintf.
+#
+AC_CHECK_FUNCS(alarm attr_get clock cputime getpagesize getrusage gettimeofday getsysinfo localeconv memset mmap mprotect nl_langinfo obstack_vprintf popen processor_info pstat_getprocessor raise read_real_time sigaction sigaltstack sigstack syssgi strchr strerror strnlen strtol strtoul sysconf sysctl sysctlbyname times)
+
+# clock_gettime is in librt on *-*-osf5.1 and on glibc, so att -lrt to
+# TUNE_LIBS if needed. On linux (tested on x86_32, 2.6.26),
+# clock_getres reports ns accuracy, while in a quick test on osf
+# clock_getres said only 1 millisecond.
+
+old_LIBS="$LIBS"
+AC_SEARCH_LIBS(clock_gettime, rt, [
+  AC_DEFINE([HAVE_CLOCK_GETTIME],1,[Define to 1 if you have the `clock_gettime' function])])
+TUNE_LIBS="$LIBS"
+LIBS="$old_LIBS"
+
+AC_SUBST(TUNE_LIBS)
+
+GMP_FUNC_VSNPRINTF
+GMP_FUNC_SSCANF_WRITABLE_INPUT
+
+# Reasons for checking:
+#   pst_processor psp_iticksperclktick - not in hpux 9
+#
+AC_CHECK_MEMBER(struct pst_processor.psp_iticksperclktick,
+                [AC_DEFINE(HAVE_PSP_ITICKSPERCLKTICK, 1,
+[Define to 1 if <sys/pstat.h> `struct pst_processor' exists
+and contains `psp_iticksperclktick'.])],,
+                [#include <sys/pstat.h>])
+
+# C++ tests, when required
+#
+if test $enable_cxx = yes; then
+  AC_LANG_PUSH(C++)
+
+  # Reasons for testing:
+  #   <sstream> - not in g++ 2.95.2
+  #   std::locale - not in g++ 2.95.4
+  #
+  AC_CHECK_HEADERS([sstream])
+  AC_CHECK_TYPES([std::locale],,,[#include <locale>])
+
+  AC_LANG_POP(C++)
+fi
+
+
+# Pick the correct source files in $path and link them to mpn/.
+# $gmp_mpn_functions lists all functions we need.
+#
+# The rule is to find a file with the function name and a .asm, .S,
+# .s, or .c extension.  Certain multi-function files with special names
+# can provide some functions too.  (mpn/Makefile.am passes
+# -DOPERATION_<func> to get them to generate the right code.)
+
+# Note: $gmp_mpn_functions must have mod_1 before pre_mod_1 so the former
+#       can optionally provide the latter as an extra entrypoint.  Likewise
+#       divrem_1 and pre_divrem_1.
+
+gmp_mpn_functions_optional="umul udiv					\
+  invert_limb sqr_diagonal sqr_diag_addlsh1				\
+  mul_2 mul_3 mul_4 mul_5 mul_6						\
+  addmul_2 addmul_3 addmul_4 addmul_5 addmul_6 addmul_7 addmul_8	\
+  addlsh1_n sublsh1_n rsblsh1_n rsh1add_n rsh1sub_n			\
+  addlsh2_n sublsh2_n rsblsh2_n						\
+  addlsh_n sublsh_n rsblsh_n						\
+  add_n_sub_n addaddmul_1msb0"
+
+gmp_mpn_functions="$extra_functions					   \
+  add add_1 add_n sub sub_1 sub_n cnd_add_n cnd_sub_n cnd_swap neg com	   \
+  mul_1 addmul_1 submul_1						   \
+  add_err1_n add_err2_n add_err3_n sub_err1_n sub_err2_n sub_err3_n	   \
+  lshift rshift dive_1 diveby3 divis divrem divrem_1 divrem_2		   \
+  fib2_ui fib2m mod_1 mod_34lsub1 mode1o pre_divrem_1 pre_mod_1 dump	   \
+  mod_1_1 mod_1_2 mod_1_3 mod_1_4 lshiftc				   \
+  mul mul_fft mul_n sqr mul_basecase sqr_basecase nussbaumer_mul	   \
+  mulmid_basecase toom42_mulmid mulmid_n mulmid				   \
+  random random2 pow_1							   \
+  rootrem sqrtrem sizeinbase get_str set_str compute_powtab		   \
+  scan0 scan1 popcount hamdist cmp zero_p				   \
+  perfsqr perfpow strongfibo						   \
+  gcd_11 gcd_22 gcd_1 gcd gcdext_1 gcdext gcd_subdiv_step		   \
+  gcdext_lehmer								   \
+  div_q tdiv_qr jacbase jacobi_2 jacobi get_d				   \
+  matrix22_mul matrix22_mul1_inverse_vector				   \
+  hgcd_matrix hgcd2 hgcd_step hgcd_reduce hgcd hgcd_appr		   \
+  hgcd2_jacobi hgcd_jacobi						   \
+  mullo_n mullo_basecase sqrlo sqrlo_basecase				   \
+  toom22_mul toom32_mul toom42_mul toom52_mul toom62_mul		   \
+  toom33_mul toom43_mul toom53_mul toom54_mul toom63_mul		   \
+  toom44_mul								   \
+  toom6h_mul toom6_sqr toom8h_mul toom8_sqr				   \
+  toom_couple_handling							   \
+  toom2_sqr toom3_sqr toom4_sqr						   \
+  toom_eval_dgr3_pm1 toom_eval_dgr3_pm2					   \
+  toom_eval_pm1 toom_eval_pm2 toom_eval_pm2exp toom_eval_pm2rexp	   \
+  toom_interpolate_5pts toom_interpolate_6pts toom_interpolate_7pts	   \
+  toom_interpolate_8pts toom_interpolate_12pts toom_interpolate_16pts	   \
+  invertappr invert binvert mulmod_bnm1 sqrmod_bnm1			   \
+  div_qr_1 div_qr_1n_pi1						   \
+  div_qr_2 div_qr_2n_pi1 div_qr_2u_pi1					   \
+  sbpi1_div_q sbpi1_div_qr sbpi1_divappr_q				   \
+  dcpi1_div_q dcpi1_div_qr dcpi1_divappr_q				   \
+  mu_div_qr mu_divappr_q mu_div_q					   \
+  bdiv_q_1								   \
+  sbpi1_bdiv_q sbpi1_bdiv_qr sbpi1_bdiv_r				   \
+  dcpi1_bdiv_q dcpi1_bdiv_qr						   \
+  mu_bdiv_q mu_bdiv_qr							   \
+  bdiv_q bdiv_qr broot brootinv bsqrt bsqrtinv				   \
+  divexact bdiv_dbm1c redc_1 redc_2 redc_n powm powlo sec_powm		   \
+  sec_mul sec_sqr sec_div_qr sec_div_r sec_pi1_div_qr sec_pi1_div_r	   \
+  sec_add_1 sec_sub_1 sec_invert					   \
+  trialdiv remove							   \
+  and_n andn_n nand_n ior_n iorn_n nior_n xor_n xnor_n			   \
+  copyi copyd zero sec_tabselect					   \
+  comb_tables								   \
+  $gmp_mpn_functions_optional"
+
+define(GMP_MULFUNC_CHOICES,
+[# functions that can be provided by multi-function files
+tmp_mulfunc=
+case $tmp_fn in
+  add_n|sub_n)       tmp_mulfunc="aors_n"    ;;
+  add_err1_n|sub_err1_n)
+		     tmp_mulfunc="aors_err1_n" ;;
+  add_err2_n|sub_err2_n)
+		     tmp_mulfunc="aors_err2_n" ;;
+  add_err3_n|sub_err3_n)
+		     tmp_mulfunc="aors_err3_n" ;;
+  cnd_add_n|cnd_sub_n) tmp_mulfunc="cnd_aors_n"   ;;
+  sec_add_1|sec_sub_1) tmp_mulfunc="sec_aors_1"   ;;
+  addmul_1|submul_1) tmp_mulfunc="aorsmul_1" ;;
+  mul_2|addmul_2)    tmp_mulfunc="aormul_2" ;;
+  mul_3|addmul_3)    tmp_mulfunc="aormul_3" ;;
+  mul_4|addmul_4)    tmp_mulfunc="aormul_4" ;;
+  popcount|hamdist)  tmp_mulfunc="popham"    ;;
+  and_n|andn_n|nand_n | ior_n|iorn_n|nior_n | xor_n|xnor_n)
+                     tmp_mulfunc="logops_n"  ;;
+  lshift|rshift)     tmp_mulfunc="lorrshift";;
+  addlsh1_n)
+		     tmp_mulfunc="aorslsh1_n aorrlsh1_n aorsorrlsh1_n";;
+  sublsh1_n)
+		     tmp_mulfunc="aorslsh1_n sorrlsh1_n aorsorrlsh1_n";;
+  rsblsh1_n)
+		     tmp_mulfunc="aorrlsh1_n sorrlsh1_n aorsorrlsh1_n";;
+  addlsh2_n)
+		     tmp_mulfunc="aorslsh2_n aorrlsh2_n aorsorrlsh2_n";;
+  sublsh2_n)
+		     tmp_mulfunc="aorslsh2_n sorrlsh2_n aorsorrlsh2_n";;
+  rsblsh2_n)
+		     tmp_mulfunc="aorrlsh2_n sorrlsh2_n aorsorrlsh2_n";;
+  addlsh_n)
+		     tmp_mulfunc="aorslsh_n aorrlsh_n aorsorrlsh_n";;
+  sublsh_n)
+		     tmp_mulfunc="aorslsh_n sorrlsh_n aorsorrlsh_n";;
+  rsblsh_n)
+		     tmp_mulfunc="aorrlsh_n sorrlsh_n aorsorrlsh_n";;
+  rsh1add_n|rsh1sub_n)
+		     tmp_mulfunc="rsh1aors_n";;
+  sec_div_qr|sec_div_r)
+		     tmp_mulfunc="sec_div";;
+  sec_pi1_div_qr|sec_pi1_div_r)
+		     tmp_mulfunc="sec_pi1_div";;
+esac
+])
+
+# the list of all object files used by mpn/Makefile.in and the
+# top-level Makefile.in, respectively
+mpn_objects=
+mpn_objs_in_libgmp=
+
+# links from the sources, to be removed by "make distclean"
+gmp_srclinks=
+
+
+# mpn_relative_top_srcdir is $top_srcdir, but for use from within the mpn
+# build directory.  If $srcdir is relative then we use a relative path too,
+# so the two trees can be moved together.
+case $srcdir in
+  [[\\/]* | ?:[\\/]*])  # absolute, as per autoconf
+    mpn_relative_top_srcdir=$srcdir ;;
+  *)                    # relative
+    mpn_relative_top_srcdir=../$srcdir ;;
+esac
+
+
+define(MPN_SUFFIXES,[asm S s c])
+
+dnl  Usage: GMP_FILE_TO_FUNCTION_BASE(func,file)
+dnl
+dnl  Set $func to the function base name for $file, eg. dive_1 gives
+dnl  divexact_1.
+dnl
+define(GMP_FILE_TO_FUNCTION,
+[case $$2 in
+  dive_1)	$1=divexact_1 ;;
+  diveby3)	$1=divexact_by3c ;;
+  pre_divrem_1) $1=preinv_divrem_1 ;;
+  mode1o)	$1=modexact_1c_odd ;;
+  pre_mod_1)	$1=preinv_mod_1 ;;
+  mod_1_1)	$1=mod_1_1p ;;
+  mod_1_1_cps)	$1=mod_1_1p_cps ;;
+  mod_1_2)	$1=mod_1s_2p ;;
+  mod_1_2_cps)	$1=mod_1s_2p_cps ;;
+  mod_1_3)	$1=mod_1s_3p ;;
+  mod_1_3_cps)	$1=mod_1s_3p_cps ;;
+  mod_1_4)	$1=mod_1s_4p ;;
+  mod_1_4_cps)	$1=mod_1s_4p_cps ;;
+  *)		$1=$$2 ;;
+esac
+])
+
+# Fat binary setups.
+#
+# We proceed through each $fat_path directory, and look for $fat_function
+# routines there.  Those found are incorporated in the build by generating a
+# little mpn/<foo>.asm or mpn/<foo>.c file in the build directory, with
+# suitable function renaming, and adding that to $mpn_objects (the same as a
+# normal mpn file).
+#
+# fat.h is generated with macros to let internal calls to each $fat_function
+# go directly through __gmpn_cpuvec, plus macros and declarations helping to
+# setup that structure, on a per-directory basis ready for
+# mpn/<cpu>/fat/fat.c.
+#
+# fat.h includes thresholds listed in $fat_thresholds, extracted from
+# gmp-mparam.h in each directory.  An overall maximum for each threshold is
+# established, for use in making fixed size arrays of temporary space.
+# (Eg. MUL_TOOM33_THRESHOLD_LIMIT used by mpn/generic/mul.c.)
+#
+# It'd be possible to do some of this manually, but when there's more than a
+# few functions and a few directories it becomes very tedious, and very
+# prone to having some routine accidentally omitted.  On that basis it seems
+# best to automate as much as possible, even if the code to do so is a bit
+# ugly.
+#
+
+if test -n "$fat_path"; then
+  # Usually the mpn build directory is created with mpn/Makefile
+  # instantiation, but we want to write to it sooner.
+  mkdir mpn 2>/dev/null
+
+  echo "/* fat.h - setups for fat binaries." >fat.h
+  echo "   Generated by configure - DO NOT EDIT.  */" >>fat.h
+
+  AC_DEFINE(WANT_FAT_BINARY, 1, [Define to 1 when building a fat binary.])
+  GMP_DEFINE(WANT_FAT_BINARY, yes)
+
+  # Don't want normal copies of fat functions
+  for tmp_fn in $fat_functions; do
+    GMP_REMOVE_FROM_LIST(gmp_mpn_functions, $tmp_fn)
+    GMP_REMOVE_FROM_LIST(gmp_mpn_functions_optional, $tmp_fn)
+  done
+
+  for tmp_fn in $fat_functions; do
+    GMP_FILE_TO_FUNCTION(tmp_fbase,tmp_fn)
+    echo "
+#ifndef OPERATION_$tmp_fn
+#undef  mpn_$tmp_fbase
+#define mpn_$tmp_fbase  (*__gmpn_cpuvec.$tmp_fbase)
+#endif
+DECL_$tmp_fbase (__MPN(${tmp_fbase}_init));" >>fat.h
+    # encourage various macros to use fat functions
+    AC_DEFINE_UNQUOTED(HAVE_NATIVE_mpn_$tmp_fbase)
+  done
+
+  echo "" >>fat.h
+  echo "/* variable thresholds */" >>fat.h
+  for tmp_tn in $fat_thresholds; do
+    echo "#undef  $tmp_tn" >>fat.h
+    echo "#define $tmp_tn  CPUVEC_THRESHOLD (`echo $tmp_tn | tr [A-Z] [a-z]`)" >>fat.h
+  done
+
+  echo "
+/* Copy all fields into __gmpn_cpuvec.
+   memcpy is not used because it might operate byte-wise (depending on its
+   implementation), and we need the function pointer writes to be atomic.
+   "volatile" discourages the compiler from trying to optimize this.  */
+#define CPUVEC_INSTALL(vec) \\
+  do { \\
+    volatile struct cpuvec_t *p = &__gmpn_cpuvec; \\" >>fat.h
+  for tmp_fn in $fat_functions; do
+    GMP_FILE_TO_FUNCTION(tmp_fbase,tmp_fn)
+    echo "    p->$tmp_fbase = vec.$tmp_fbase; \\" >>fat.h
+  done
+  for tmp_tn in $fat_thresholds; do
+    tmp_field_name=`echo $tmp_tn | tr [[A-Z]] [[a-z]]`
+    echo "    p->$tmp_field_name = vec.$tmp_field_name; \\" >>fat.h
+  done
+  echo "  } while (0)" >>fat.h
+
+  echo "
+/* A helper to check all fields are filled. */
+#define ASSERT_CPUVEC(vec) \\
+  do { \\" >>fat.h
+  for tmp_fn in $fat_functions; do
+    GMP_FILE_TO_FUNCTION(tmp_fbase,tmp_fn)
+    echo "    ASSERT (vec.$tmp_fbase != NULL); \\" >>fat.h
+  done
+  for tmp_tn in $fat_thresholds; do
+    tmp_field_name=`echo $tmp_tn | tr [[A-Z]] [[a-z]]`
+    echo "    ASSERT (vec.$tmp_field_name != 0); \\" >>fat.h
+  done
+  echo "  } while (0)" >>fat.h
+
+  echo "
+/* Call ITERATE(field) for each fat threshold field. */
+#define ITERATE_FAT_THRESHOLDS() \\
+  do { \\" >>fat.h
+  for tmp_tn in $fat_thresholds; do
+    tmp_field_name=`echo $tmp_tn | tr [[A-Z]] [[a-z]]`
+    echo "    ITERATE ($tmp_tn, $tmp_field_name); \\" >>fat.h
+  done
+  echo "  } while (0)" >>fat.h
+
+  for tmp_dir in $fat_path; do
+    CPUVEC_SETUP=
+    THRESH_ASM_SETUP=
+    echo "" >>fat.h
+    GMP_FAT_SUFFIX(tmp_suffix, $tmp_dir)
+
+    # In order to keep names unique on a DOS 8.3 filesystem, use a prefix
+    # (rather than a suffix) for the generated file names, and abbreviate.
+    case $tmp_suffix in
+      pentium)       tmp_prefix=p   ;;
+      pentium_mmx)   tmp_prefix=pm  ;;
+      p6_mmx)        tmp_prefix=p2  ;;
+      p6_p3mmx)      tmp_prefix=p3  ;;
+      pentium4)      tmp_prefix=p4  ;;
+      pentium4_mmx)  tmp_prefix=p4m ;;
+      pentium4_sse2) tmp_prefix=p4s ;;
+      k6_mmx)        tmp_prefix=k6m ;;
+      k6_k62mmx)     tmp_prefix=k62 ;;
+      k7_mmx)        tmp_prefix=k7m ;;
+      *)             tmp_prefix=$tmp_suffix ;;
+    esac
+
+    # Extract desired thresholds from gmp-mparam.h file in this directory,
+    # if present.
+    tmp_mparam=$srcdir/mpn/$tmp_dir/gmp-mparam.h
+    if test -f $tmp_mparam; then
+      for tmp_tn in $fat_thresholds; do
+        tmp_thresh=`sed -n "s/^#define $tmp_tn[ 	]*\\([0-9][0-9]*\\).*$/\\1/p" $tmp_mparam`
+        if test -n "$tmp_thresh"; then
+          THRESH_ASM_SETUP=["${THRESH_ASM_SETUP}define($tmp_tn,$tmp_thresh)
+"]
+          CPUVEC_SETUP="$CPUVEC_SETUP    decided_cpuvec.`echo $tmp_tn | tr [[A-Z]] [[a-z]]` = $tmp_thresh; \\
+"
+          eval tmp_limit=\$${tmp_tn}_LIMIT
+          if test -z "$tmp_limit"; then
+            tmp_limit=0
+          fi
+          if test $tmp_thresh -gt $tmp_limit; then
+            eval ${tmp_tn}_LIMIT=$tmp_thresh
+          fi
+        fi
+      done
+    fi
+
+    for tmp_fn in $fat_functions; do
+      GMP_MULFUNC_CHOICES
+
+      for tmp_base in $tmp_fn $tmp_mulfunc; do
+        for tmp_ext in MPN_SUFFIXES; do
+          tmp_file=$srcdir/mpn/$tmp_dir/$tmp_base.$tmp_ext
+          if test -f $tmp_file; then
+
+	    # If the host uses a non-standard ABI, check if tmp_file supports it
+	    #
+	    if test -n "$GMP_NONSTD_ABI" && test $tmp_ext != "c"; then
+	      abi=[`sed -n 's/^[ 	]*ABI_SUPPORT(\(.*\))/\1/p' $tmp_file `]
+	      if echo "$abi" | grep -q "\\b${GMP_NONSTD_ABI}\\b"; then
+		true
+	      else
+		continue
+	      fi
+	    fi
+
+            mpn_objects="$mpn_objects ${tmp_prefix}_$tmp_fn.lo"
+            mpn_objs_in_libgmp="$mpn_objs_in_libgmp mpn/${tmp_prefix}_$tmp_fn.lo"
+
+            GMP_FILE_TO_FUNCTION(tmp_fbase,tmp_fn)
+
+            # carry-in variant, eg. divrem_1c or modexact_1c_odd
+            case $tmp_fbase in
+              *_1*) tmp_fbasec=`echo $tmp_fbase | sed 's/_1/_1c/'` ;;
+              *)    tmp_fbasec=${tmp_fbase}c ;;
+            esac
+
+            # Create a little file doing an include from srcdir.  The
+            # OPERATION and renamings aren't all needed all the time, but
+            # they don't hurt if unused.
+            #
+            # FIXME: Should generate these via config.status commands.
+            # Would need them all in one AC_CONFIG_COMMANDS though, since
+            # that macro doesn't accept a set of separate commands generated
+            # by shell code.
+            #
+            case $tmp_ext in
+              asm)
+                # hide the d-n-l from autoconf's error checking
+                tmp_d_n_l=d""nl
+                echo ["$tmp_d_n_l  mpn_$tmp_fbase - from $tmp_dir directory for fat binary.
+$tmp_d_n_l  Generated by configure - DO NOT EDIT.
+
+define(OPERATION_$tmp_fn)
+define(__gmpn_$tmp_fbase, __gmpn_${tmp_fbase}_$tmp_suffix)
+define(__gmpn_$tmp_fbasec,__gmpn_${tmp_fbasec}_${tmp_suffix})
+define(__gmpn_preinv_${tmp_fbase},__gmpn_preinv_${tmp_fbase}_${tmp_suffix})
+define(__gmpn_${tmp_fbase}_cps,__gmpn_${tmp_fbase}_cps_${tmp_suffix})
+
+$tmp_d_n_l  For k6 and k7 gcd_1 calling their corresponding mpn_modexact_1_odd
+ifdef(\`__gmpn_modexact_1_odd',,
+\`define(__gmpn_modexact_1_odd,__gmpn_modexact_1_odd_${tmp_suffix})')
+
+$THRESH_ASM_SETUP
+include][($mpn_relative_top_srcdir/mpn/$tmp_dir/$tmp_base.asm)
+"] >mpn/${tmp_prefix}_$tmp_fn.asm
+                ;;
+              c)
+                echo ["/* mpn_$tmp_fbase - from $tmp_dir directory for fat binary.
+   Generated by configure - DO NOT EDIT. */
+
+#define OPERATION_$tmp_fn 1
+#define __gmpn_$tmp_fbase           __gmpn_${tmp_fbase}_$tmp_suffix
+#define __gmpn_$tmp_fbasec          __gmpn_${tmp_fbasec}_${tmp_suffix}
+#define __gmpn_preinv_${tmp_fbase}  __gmpn_preinv_${tmp_fbase}_${tmp_suffix}
+#define __gmpn_${tmp_fbase}_cps     __gmpn_${tmp_fbase}_cps_${tmp_suffix}
+
+#include \"$mpn_relative_top_srcdir/mpn/$tmp_dir/$tmp_base.c\"
+"] >mpn/${tmp_prefix}_$tmp_fn.c
+                ;;
+            esac
+
+            # Prototype, and append to CPUVEC_SETUP for this directory.
+            echo "DECL_$tmp_fbase (__gmpn_${tmp_fbase}_$tmp_suffix);" >>fat.h
+            CPUVEC_SETUP="$CPUVEC_SETUP    decided_cpuvec.$tmp_fbase = __gmpn_${tmp_fbase}_${tmp_suffix}; \\
+"
+            # Ditto for any preinv variant (preinv_divrem_1, preinv_mod_1).
+            if grep "^PROLOGUE(mpn_preinv_$tmp_fn)" $tmp_file >/dev/null; then
+              echo "DECL_preinv_$tmp_fbase (__gmpn_preinv_${tmp_fbase}_$tmp_suffix);" >>fat.h
+              CPUVEC_SETUP="$CPUVEC_SETUP    decided_cpuvec.preinv_$tmp_fbase = __gmpn_preinv_${tmp_fbase}_${tmp_suffix}; \\
+"
+            fi
+
+            # Ditto for any mod_1...cps variant
+            if grep "^PROLOGUE(mpn_${tmp_fbase}_cps)" $tmp_file >/dev/null; then
+              echo "DECL_${tmp_fbase}_cps (__gmpn_${tmp_fbase}_cps_$tmp_suffix);" >>fat.h
+              CPUVEC_SETUP="$CPUVEC_SETUP    decided_cpuvec.${tmp_fbase}_cps = __gmpn_${tmp_fbase}_cps_${tmp_suffix}; \\
+"
+            fi
+          fi
+        done
+      done
+    done
+
+    # Emit CPUVEC_SETUP for this directory
+    echo "" >>fat.h
+    echo "#define CPUVEC_SETUP_$tmp_suffix \\" >>fat.h
+    echo "  do { \\" >>fat.h
+    echo "$CPUVEC_SETUP  } while (0)" >>fat.h
+  done
+
+  # Emit threshold limits
+  echo "" >>fat.h
+  for tmp_tn in $fat_thresholds; do
+    eval tmp_limit=\$${tmp_tn}_LIMIT
+    echo "#define ${tmp_tn}_LIMIT  $tmp_limit" >>fat.h
+  done
+fi
+
+
+# Normal binary setups.
+#
+
+for tmp_ext in MPN_SUFFIXES; do
+  eval found_$tmp_ext=no
+done
+
+for tmp_fn in $gmp_mpn_functions; do
+  for tmp_ext in MPN_SUFFIXES; do
+    test "$no_create" = yes || rm -f mpn/$tmp_fn.$tmp_ext
+  done
+
+  # mpn_preinv_divrem_1 might have been provided by divrem_1.asm, likewise
+  # mpn_preinv_mod_1 by mod_1.asm.
+  case $tmp_fn in
+  pre_divrem_1)
+    if test "$HAVE_NATIVE_mpn_preinv_divrem_1" = yes; then continue; fi ;;
+  pre_mod_1)
+    if test "$HAVE_NATIVE_mpn_preinv_mod_1" = yes; then continue; fi ;;
+  esac
+
+  GMP_MULFUNC_CHOICES
+
+  found=no
+  for tmp_dir in $path; do
+    for tmp_base in $tmp_fn $tmp_mulfunc; do
+      for tmp_ext in MPN_SUFFIXES; do
+        tmp_file=$srcdir/mpn/$tmp_dir/$tmp_base.$tmp_ext
+        if test -f $tmp_file; then
+
+          # For a nails build, check if the file supports our nail bits.
+          # Generic code always supports all nails.
+          #
+          # FIXME: When a multi-function file is selected to provide one of
+          # the nails-neutral routines, like logops_n for and_n, the
+          # PROLOGUE grepping will create HAVE_NATIVE_mpn_<foo> defines for
+          # all functions in that file, even if they haven't all been
+          # nailified.  Not sure what to do about this, it's only really a
+          # problem for logops_n, and it's not too terrible to insist those
+          # get nailified always.
+          #
+          if test $GMP_NAIL_BITS != 0 && test $tmp_dir != generic; then
+            case $tmp_fn in
+              and_n | ior_n | xor_n | andn_n | \
+              copyi | copyd | \
+              popcount | hamdist | \
+              udiv | udiv_w_sdiv | umul | \
+              cntlz | invert_limb)
+                # these operations are either unaffected by nails or defined
+                # to operate on full limbs
+                ;;
+              *)
+                nails=[`sed -n 's/^[ 	]*NAILS_SUPPORT(\(.*\))/\1/p' $tmp_file `]
+                for n in $nails; do
+                  case $n in
+                  *-*)
+                    n_start=`echo "$n" | sed -n 's/\(.*\)-.*/\1/p'`
+                    n_end=`echo "$n" | sed -n 's/.*-\(.*\)/\1/p'`
+                    ;;
+                  *)
+                    n_start=$n
+                    n_end=$n
+                    ;;
+                  esac
+                  if test $GMP_NAIL_BITS -ge $n_start && test $GMP_NAIL_BITS -le $n_end; then
+                    found=yes
+                    break
+                  fi
+                done
+                if test $found != yes; then
+                  continue
+                fi
+                ;;
+            esac
+          fi
+
+	  # If the host uses a non-standard ABI, check if tmp_file supports it
+	  #
+	  if test -n "$GMP_NONSTD_ABI" && test $tmp_ext != "c"; then
+	    abi=[`sed -n 's/^[ 	]*ABI_SUPPORT(\(.*\))/\1/p' $tmp_file `]
+	    if echo "$abi" | grep -q "\\b${GMP_NONSTD_ABI}\\b"; then
+	      true
+	    else
+	      continue
+	    fi
+	  fi
+
+          found=yes
+          eval found_$tmp_ext=yes
+
+          if test $tmp_ext = c; then
+            tmp_u='$U'
+          else
+            tmp_u=
+          fi
+
+          mpn_objects="$mpn_objects $tmp_fn$tmp_u.lo"
+          mpn_objs_in_libgmp="$mpn_objs_in_libgmp mpn/$tmp_fn$tmp_u.lo"
+          AC_CONFIG_LINKS(mpn/$tmp_fn.$tmp_ext:mpn/$tmp_dir/$tmp_base.$tmp_ext)
+          gmp_srclinks="$gmp_srclinks mpn/$tmp_fn.$tmp_ext"
+
+          # Duplicate AC_DEFINEs are harmless, so it doesn't matter
+          # that multi-function files get grepped here repeatedly.
+          # The PROLOGUE pattern excludes the optional second parameter.
+          gmp_ep=[`
+            sed -n 's/^[ 	]*MULFUNC_PROLOGUE(\(.*\))/\1/p' $tmp_file ;
+            sed -n 's/^[ 	]*PROLOGUE(\([^,]*\).*)/\1/p' $tmp_file
+          `]
+          for gmp_tmp in $gmp_ep; do
+            AC_DEFINE_UNQUOTED(HAVE_NATIVE_$gmp_tmp)
+            eval HAVE_NATIVE_$gmp_tmp=yes
+          done
+
+          case $tmp_fn in
+          sqr_basecase) sqr_basecase_source=$tmp_file ;;
+          esac
+
+          break
+        fi
+      done
+      if test $found = yes; then break ; fi
+    done
+    if test $found = yes; then break ; fi
+  done
+
+  if test $found = no; then
+    for tmp_optional in $gmp_mpn_functions_optional; do
+      if test $tmp_optional = $tmp_fn; then
+        found=yes
+      fi
+    done
+    if test $found = no; then
+      AC_MSG_ERROR([no version of $tmp_fn found in path: $path])
+    fi
+  fi
+done
+
+# All cycle counters are .asm files currently
+if test -n "$SPEED_CYCLECOUNTER_OBJ"; then
+  found_asm=yes
+fi
+
+dnl  The following list only needs to have templates for those defines which
+dnl  are going to be tested by the code, there's no need to have every
+dnl  possible mpn routine.
+
+AH_VERBATIM([HAVE_NATIVE],
+[/* Define to 1 each of the following for which a native (ie. CPU specific)
+    implementation of the corresponding routine exists.  */
+#undef HAVE_NATIVE_mpn_add_n
+#undef HAVE_NATIVE_mpn_add_n_sub_n
+#undef HAVE_NATIVE_mpn_add_nc
+#undef HAVE_NATIVE_mpn_addaddmul_1msb0
+#undef HAVE_NATIVE_mpn_addlsh1_n
+#undef HAVE_NATIVE_mpn_addlsh2_n
+#undef HAVE_NATIVE_mpn_addlsh_n
+#undef HAVE_NATIVE_mpn_addlsh1_nc
+#undef HAVE_NATIVE_mpn_addlsh2_nc
+#undef HAVE_NATIVE_mpn_addlsh_nc
+#undef HAVE_NATIVE_mpn_addlsh1_n_ip1
+#undef HAVE_NATIVE_mpn_addlsh2_n_ip1
+#undef HAVE_NATIVE_mpn_addlsh_n_ip1
+#undef HAVE_NATIVE_mpn_addlsh1_nc_ip1
+#undef HAVE_NATIVE_mpn_addlsh2_nc_ip1
+#undef HAVE_NATIVE_mpn_addlsh_nc_ip1
+#undef HAVE_NATIVE_mpn_addlsh1_n_ip2
+#undef HAVE_NATIVE_mpn_addlsh2_n_ip2
+#undef HAVE_NATIVE_mpn_addlsh_n_ip2
+#undef HAVE_NATIVE_mpn_addlsh1_nc_ip2
+#undef HAVE_NATIVE_mpn_addlsh2_nc_ip2
+#undef HAVE_NATIVE_mpn_addlsh_nc_ip2
+#undef HAVE_NATIVE_mpn_addmul_1c
+#undef HAVE_NATIVE_mpn_addmul_2
+#undef HAVE_NATIVE_mpn_addmul_3
+#undef HAVE_NATIVE_mpn_addmul_4
+#undef HAVE_NATIVE_mpn_addmul_5
+#undef HAVE_NATIVE_mpn_addmul_6
+#undef HAVE_NATIVE_mpn_addmul_7
+#undef HAVE_NATIVE_mpn_addmul_8
+#undef HAVE_NATIVE_mpn_addmul_2s
+#undef HAVE_NATIVE_mpn_and_n
+#undef HAVE_NATIVE_mpn_andn_n
+#undef HAVE_NATIVE_mpn_bdiv_dbm1c
+#undef HAVE_NATIVE_mpn_bdiv_q_1
+#undef HAVE_NATIVE_mpn_pi1_bdiv_q_1
+#undef HAVE_NATIVE_mpn_cnd_add_n
+#undef HAVE_NATIVE_mpn_cnd_sub_n
+#undef HAVE_NATIVE_mpn_com
+#undef HAVE_NATIVE_mpn_copyd
+#undef HAVE_NATIVE_mpn_copyi
+#undef HAVE_NATIVE_mpn_div_qr_1n_pi1
+#undef HAVE_NATIVE_mpn_div_qr_2
+#undef HAVE_NATIVE_mpn_divexact_1
+#undef HAVE_NATIVE_mpn_divexact_by3c
+#undef HAVE_NATIVE_mpn_divrem_1
+#undef HAVE_NATIVE_mpn_divrem_1c
+#undef HAVE_NATIVE_mpn_divrem_2
+#undef HAVE_NATIVE_mpn_gcd_1
+#undef HAVE_NATIVE_mpn_gcd_11
+#undef HAVE_NATIVE_mpn_gcd_22
+#undef HAVE_NATIVE_mpn_hamdist
+#undef HAVE_NATIVE_mpn_invert_limb
+#undef HAVE_NATIVE_mpn_ior_n
+#undef HAVE_NATIVE_mpn_iorn_n
+#undef HAVE_NATIVE_mpn_lshift
+#undef HAVE_NATIVE_mpn_lshiftc
+#undef HAVE_NATIVE_mpn_lshsub_n
+#undef HAVE_NATIVE_mpn_mod_1
+#undef HAVE_NATIVE_mpn_mod_1_1p
+#undef HAVE_NATIVE_mpn_mod_1c
+#undef HAVE_NATIVE_mpn_mod_1s_2p
+#undef HAVE_NATIVE_mpn_mod_1s_4p
+#undef HAVE_NATIVE_mpn_mod_34lsub1
+#undef HAVE_NATIVE_mpn_modexact_1_odd
+#undef HAVE_NATIVE_mpn_modexact_1c_odd
+#undef HAVE_NATIVE_mpn_mul_1
+#undef HAVE_NATIVE_mpn_mul_1c
+#undef HAVE_NATIVE_mpn_mul_2
+#undef HAVE_NATIVE_mpn_mul_3
+#undef HAVE_NATIVE_mpn_mul_4
+#undef HAVE_NATIVE_mpn_mul_5
+#undef HAVE_NATIVE_mpn_mul_6
+#undef HAVE_NATIVE_mpn_mul_basecase
+#undef HAVE_NATIVE_mpn_mullo_basecase
+#undef HAVE_NATIVE_mpn_nand_n
+#undef HAVE_NATIVE_mpn_nior_n
+#undef HAVE_NATIVE_mpn_popcount
+#undef HAVE_NATIVE_mpn_preinv_divrem_1
+#undef HAVE_NATIVE_mpn_preinv_mod_1
+#undef HAVE_NATIVE_mpn_redc_1
+#undef HAVE_NATIVE_mpn_redc_2
+#undef HAVE_NATIVE_mpn_rsblsh1_n
+#undef HAVE_NATIVE_mpn_rsblsh2_n
+#undef HAVE_NATIVE_mpn_rsblsh_n
+#undef HAVE_NATIVE_mpn_rsblsh1_nc
+#undef HAVE_NATIVE_mpn_rsblsh2_nc
+#undef HAVE_NATIVE_mpn_rsblsh_nc
+#undef HAVE_NATIVE_mpn_rsh1add_n
+#undef HAVE_NATIVE_mpn_rsh1add_nc
+#undef HAVE_NATIVE_mpn_rsh1sub_n
+#undef HAVE_NATIVE_mpn_rsh1sub_nc
+#undef HAVE_NATIVE_mpn_rshift
+#undef HAVE_NATIVE_mpn_sbpi1_bdiv_r
+#undef HAVE_NATIVE_mpn_sqr_basecase
+#undef HAVE_NATIVE_mpn_sqr_diagonal
+#undef HAVE_NATIVE_mpn_sqr_diag_addlsh1
+#undef HAVE_NATIVE_mpn_sub_n
+#undef HAVE_NATIVE_mpn_sub_nc
+#undef HAVE_NATIVE_mpn_sublsh1_n
+#undef HAVE_NATIVE_mpn_sublsh2_n
+#undef HAVE_NATIVE_mpn_sublsh_n
+#undef HAVE_NATIVE_mpn_sublsh1_nc
+#undef HAVE_NATIVE_mpn_sublsh2_nc
+#undef HAVE_NATIVE_mpn_sublsh_nc
+#undef HAVE_NATIVE_mpn_sublsh1_n_ip1
+#undef HAVE_NATIVE_mpn_sublsh2_n_ip1
+#undef HAVE_NATIVE_mpn_sublsh_n_ip1
+#undef HAVE_NATIVE_mpn_sublsh1_nc_ip1
+#undef HAVE_NATIVE_mpn_sublsh2_nc_ip1
+#undef HAVE_NATIVE_mpn_sublsh_nc_ip1
+#undef HAVE_NATIVE_mpn_submul_1c
+#undef HAVE_NATIVE_mpn_tabselect
+#undef HAVE_NATIVE_mpn_udiv_qrnnd
+#undef HAVE_NATIVE_mpn_udiv_qrnnd_r
+#undef HAVE_NATIVE_mpn_umul_ppmm
+#undef HAVE_NATIVE_mpn_umul_ppmm_r
+#undef HAVE_NATIVE_mpn_xor_n
+#undef HAVE_NATIVE_mpn_xnor_n])
+
+
+# Don't demand an m4 unless it's actually needed.
+if test $found_asm = yes; then
+  GMP_PROG_M4
+  GMP_M4_M4WRAP_SPURIOUS
+# else
+# It's unclear why this m4-not-needed stuff was ever done.
+#  if test -z "$M4" ; then
+#    M4=m4-not-needed
+#  fi
+fi
+
+# Only do the GMP_ASM checks if there's a .S or .asm wanting them.
+if test $found_asm = no && test $found_S = no; then
+  gmp_asm_syntax_testing=no
+fi
+
+if test "$gmp_asm_syntax_testing" != no; then
+  GMP_ASM_TEXT
+  GMP_ASM_DATA
+  GMP_ASM_LABEL_SUFFIX
+  GMP_ASM_GLOBL
+  GMP_ASM_GLOBL_ATTR
+  GMP_ASM_UNDERSCORE
+  GMP_ASM_RODATA
+  GMP_ASM_TYPE
+  GMP_ASM_SIZE
+  GMP_ASM_LSYM_PREFIX
+  GMP_ASM_W32
+  GMP_ASM_ALIGN_LOG
+
+  case $host in
+    arm*-*-* | aarch64*-*-*)
+      case $ABI in
+        32)
+	  GMP_INCLUDE_MPN(arm/arm-defs.m4) ;;
+      esac
+      ;;
+    hppa*-*-*)
+      # for both pa32 and pa64
+      GMP_INCLUDE_MPN(pa32/pa-defs.m4)
+      ;;
+    IA64_PATTERN)
+      GMP_ASM_IA64_ALIGN_OK
+      ;;
+    M68K_PATTERN)
+      GMP_ASM_M68K_INSTRUCTION
+      GMP_ASM_M68K_ADDRESSING
+      GMP_ASM_M68K_BRANCHES
+      ;;
+    [powerpc*-*-* | power[3-9]-*-*])
+      GMP_ASM_POWERPC_PIC_ALWAYS
+      GMP_ASM_POWERPC_R_REGISTERS
+      GMP_INCLUDE_MPN(powerpc32/powerpc-defs.m4)
+
+      # Check for Linux ELFv1 ABI
+      AC_EGREP_CPP(yes,
+[#if _CALL_ELF == 1
+yes
+#endif],
+      [GMP_DEFINE_RAW(["define(<ELFv1_ABI>)"])])
+
+      # Check for Linux ELFv2 ABI
+      AC_EGREP_CPP(yes,
+[#if _CALL_ELF == 2
+yes
+#endif],
+      [GMP_DEFINE_RAW(["define(<ELFv2_ABI>)"])])
+
+      case $host in
+        *-*-aix*)
+	  case $ABI in
+	    mode64)      GMP_INCLUDE_MPN(powerpc64/aix.m4) ;;
+            *)           GMP_INCLUDE_MPN(powerpc32/aix.m4) ;;
+          esac
+          ;;
+        *-*-linux* | *-*-*bsd*)
+	  case $ABI in
+	    mode64)      GMP_INCLUDE_MPN(powerpc64/elf.m4) ;;
+	    mode32 | 32) GMP_INCLUDE_MPN(powerpc32/elf.m4) ;;
+          esac
+          ;;
+        *-*-darwin*)
+	  case $ABI in
+	    mode64)      GMP_INCLUDE_MPN(powerpc64/darwin.m4) ;;
+	    mode32 | 32) GMP_INCLUDE_MPN(powerpc32/darwin.m4) ;;
+          esac
+          ;;
+        *)
+	  # Assume unrecognized operating system is the powerpc eABI
+          GMP_INCLUDE_MPN(powerpc32/eabi.m4)
+	  ;;
+      esac
+      ;;
+    power*-*-aix*)
+      GMP_INCLUDE_MPN(powerpc32/aix.m4)
+      ;;
+    *sparc*-*-*)
+      case $ABI in
+        64)
+          GMP_ASM_SPARC_REGISTER
+          ;;
+      esac
+      GMP_ASM_SPARC_GOTDATA
+      GMP_ASM_SPARC_SHARED_THUNKS
+      ;;
+    X86_PATTERN | X86_64_PATTERN)
+      GMP_ASM_ALIGN_FILL_0x90
+      if test "$x86_have_mulx" = yes; then
+        GMP_ASM_X86_MULX
+      fi
+      case $ABI in
+        32)
+          GMP_INCLUDE_MPN(x86/x86-defs.m4)
+          AC_DEFINE(HAVE_HOST_CPU_FAMILY_x86)
+          GMP_ASM_COFF_TYPE
+          GMP_ASM_X86_GOT_UNDERSCORE
+          GMP_ASM_X86_SHLDL_CL
+	  case $enable_profiling in
+	    prof | gprof)  GMP_ASM_X86_MCOUNT ;;
+	  esac
+	  case $host in
+	    *-*-darwin*)
+	      GMP_INCLUDE_MPN(x86/darwin.m4) ;;
+	  esac
+          ;;
+        64|x32)
+          GMP_INCLUDE_MPN(x86_64/x86_64-defs.m4)
+          AC_DEFINE(HAVE_HOST_CPU_FAMILY_x86_64)
+	  case $host in
+	    *-*-darwin*)
+	      GMP_INCLUDE_MPN(x86_64/darwin.m4) ;;
+	    *-*-mingw* | *-*-cygwin)
+	      GMP_INCLUDE_MPN(x86_64/dos64.m4) ;;
+	    *-openbsd*)
+	      GMP_DEFINE_RAW(["define(<OPENBSD>,1)"]) ;;
+	    *-linux*)
+	      GMP_DEFINE_RAW(["define(<LINUX>,1)"]) ;;
+	  esac
+          ;;
+      esac
+      ;;
+  esac
+fi
+
+# For --enable-minithres, prepend "minithres" to path so that its special
+# gmp-mparam.h will be used.
+if test $enable_minithres = yes; then
+  path="minithres $path"
+fi
+
+# Create link for gmp-mparam.h.
+gmp_mparam_source=
+for gmp_mparam_dir in $path; do
+  test "$no_create" = yes || rm -f gmp-mparam.h
+  tmp_file=$srcdir/mpn/$gmp_mparam_dir/gmp-mparam.h
+  if test -f $tmp_file; then
+    AC_CONFIG_LINKS(gmp-mparam.h:mpn/$gmp_mparam_dir/gmp-mparam.h)
+    gmp_srclinks="$gmp_srclinks gmp-mparam.h"
+    gmp_mparam_source=$tmp_file
+    break
+  fi
+done
+if test -z "$gmp_mparam_source"; then
+  AC_MSG_ERROR([no version of gmp-mparam.h found in path: $path])
+fi
+
+# For a helpful message from tune/tuneup.c
+gmp_mparam_suggest=$gmp_mparam_source
+if test "$gmp_mparam_dir" = generic; then
+  for i in $path; do break; done
+  if test "$i" != generic; then
+    gmp_mparam_suggest="new file $srcdir/mpn/$i/gmp-mparam.h"
+  fi
+fi
+AC_DEFINE_UNQUOTED(GMP_MPARAM_H_SUGGEST, "$gmp_mparam_source",
+[The gmp-mparam.h file (a string) the tune program should suggest updating.])
+
+
+# Copy relevant parameters from gmp-mparam.h to config.m4.
+# We only do this for parameters that are used by some assembly files.
+# Fat binaries do this on a per-file basis, so skip in that case.
+#
+if test -z "$fat_path"; then
+  for i in SQR_TOOM2_THRESHOLD BMOD_1_TO_MOD_1_THRESHOLD SHLD_SLOW SHRD_SLOW; do
+    value=`sed -n 's/^#define '$i'[ 	]*\([0-9A-Z][0-9A-Z_]*\).*$/\1/p' $gmp_mparam_source`
+    if test -n "$value"; then
+      GMP_DEFINE_RAW(["define(<$i>,<$value>)"])
+    fi
+  done
+fi
+
+
+# Sizes of some types, needed at preprocessing time.
+#
+# FIXME: The assumption that GMP_LIMB_BITS is 8*sizeof(mp_limb_t) might
+# be slightly rash, but it's true everywhere we know of and ought to be true
+# of any sensible system.  In a generic C build, grepping LONG_BIT out of
+# <limits.h> might be an alternative, for maximum portability.
+#
+AC_CHECK_SIZEOF(void *)
+AC_CHECK_SIZEOF(unsigned short)
+AC_CHECK_SIZEOF(unsigned)
+AC_CHECK_SIZEOF(unsigned long)
+AC_CHECK_SIZEOF(mp_limb_t, , GMP_INCLUDE_GMP_H)
+if test "$ac_cv_sizeof_mp_limb_t" = 0; then
+  AC_MSG_ERROR([Oops, mp_limb_t doesn't seem to work])
+fi
+AC_SUBST(GMP_LIMB_BITS, `expr 8 \* $ac_cv_sizeof_mp_limb_t`)
+GMP_DEFINE_RAW(["define(<SIZEOF_UNSIGNED>,<$ac_cv_sizeof_unsigned>)"])
+
+# Check compiler limb size matches gmp-mparam.h
+#
+# FIXME: Some of the cycle counter objects in the tune directory depend on
+# the size of ulong, it'd be possible to check that here, though a mismatch
+# probably wouldn't want to be fatal, none of the libgmp assembler code
+# depends on ulong.
+#
+mparam_bits=[`sed -n 's/^#define GMP_LIMB_BITS[ 	][ 	]*\([0-9]*\).*$/\1/p' $gmp_mparam_source`]
+if test -n "$mparam_bits" && test "$mparam_bits" -ne $GMP_LIMB_BITS; then
+  if test "$test_CFLAGS" = set; then
+    AC_MSG_ERROR([Oops, mp_limb_t is $GMP_LIMB_BITS bits, but the assembler code
+in this configuration expects $mparam_bits bits.
+You appear to have set \$CFLAGS, perhaps you also need to tell GMP the
+intended ABI, see "ABI and ISA" in the manual.])
+  else
+    AC_MSG_ERROR([Oops, mp_limb_t is $GMP_LIMB_BITS bits, but the assembler code
+in this configuration expects $mparam_bits bits.])
+  fi
+fi
+
+GMP_DEFINE_RAW(["define(<GMP_LIMB_BITS>,$GMP_LIMB_BITS)"])
+GMP_DEFINE_RAW(["define(<GMP_NAIL_BITS>,$GMP_NAIL_BITS)"])
+GMP_DEFINE_RAW(["define(<GMP_NUMB_BITS>,eval(GMP_LIMB_BITS-GMP_NAIL_BITS))"])
+
+
+AC_SUBST(mpn_objects)
+AC_SUBST(mpn_objs_in_libgmp)
+AC_SUBST(gmp_srclinks)
+
+
+# A recompiled sqr_basecase for use in the tune program, if necessary.
+TUNE_SQR_OBJ=
+test -d tune || mkdir tune
+case $sqr_basecase_source in
+  *.asm)
+    sqr_max=[`sed -n 's/^def...(SQR_TOOM2_THRESHOLD_MAX, *\([0-9]*\))/\1/p' $sqr_basecase_source`]
+    if test -n "$sqr_max"; then
+      TUNE_SQR_OBJ=sqr_asm.o
+      AC_DEFINE_UNQUOTED(TUNE_SQR_TOOM2_MAX,$sqr_max,
+      [Maximum size the tune program can test for SQR_TOOM2_THRESHOLD])
+    fi
+    cat >tune/sqr_basecase.c <<EOF
+/* not sure that an empty file can compile, so put in a dummy */
+int sqr_basecase_dummy;
+EOF
+    ;;
+  *.c)
+    TUNE_SQR_OBJ=
+    AC_DEFINE(TUNE_SQR_TOOM2_MAX,SQR_TOOM2_MAX_GENERIC)
+    cat >tune/sqr_basecase.c <<EOF
+#define TUNE_PROGRAM_BUILD 1
+#define TUNE_PROGRAM_BUILD_SQR 1
+#include "mpn/sqr_basecase.c"
+EOF
+    ;;
+esac
+AC_SUBST(TUNE_SQR_OBJ)
+
+
+# Configs for demos/pexpr.c.
+#
+AC_CONFIG_FILES(demos/pexpr-config.h:demos/pexpr-config-h.in)
+GMP_SUBST_CHECK_FUNCS(clock, cputime, getrusage, gettimeofday, sigaction, sigaltstack, sigstack)
+GMP_SUBST_CHECK_HEADERS(sys/resource.h)
+AC_CHECK_TYPES([stack_t], HAVE_STACK_T_01=1, HAVE_STACK_T_01=0,
+               [#include <signal.h>])
+AC_SUBST(HAVE_STACK_T_01)
+
+# Configs for demos/calc directory
+#
+# AC_SUBST+AC_CONFIG_FILES is used for calc-config.h, rather than AC_DEFINE+
+# AC_CONFIG_HEADERS, since with the latter automake (1.8) will then put the
+# directory (ie. demos/calc) into $(DEFAULT_INCLUDES) for every Makefile.in,
+# which would look very strange.
+#
+# -lcurses is required by libreadline.  On a typical SVR4 style system this
+# normally doesn't have to be given explicitly, since libreadline.so will
+# have a NEEDED record for it.  But if someone for some reason is using only
+# a static libreadline.a then we must give -lcurses.  Readline (as of
+# version 4.3) doesn't use libtool, so we can't rely on a .la to cover
+# necessary dependencies.
+#
+# On a couple of systems we've seen libreadline available, but the headers
+# not in the default include path, so check for readline/readline.h.  We've
+# also seen readline/history.h missing, not sure if that's just a broken
+# install or a very old version, but check that too.
+#
+AC_CONFIG_FILES(demos/calc/calc-config.h:demos/calc/calc-config-h.in)
+LIBCURSES=
+if test $with_readline != no; then
+  AC_CHECK_LIB(ncurses, tputs, [LIBCURSES=-lncurses],
+    [AC_CHECK_LIB(curses, tputs, [LIBCURSES=-lcurses])])
+fi
+AC_SUBST(LIBCURSES)
+use_readline=$with_readline
+if test $with_readline = detect; then
+  use_readline=no
+  AC_CHECK_LIB(readline, readline,
+    [AC_CHECK_HEADER(readline/readline.h,
+      [AC_CHECK_HEADER(readline/history.h, use_readline=yes)])],
+    , $LIBCURSES)
+  AC_MSG_CHECKING(readline detected)
+  AC_MSG_RESULT($use_readline)
+fi
+if test $use_readline = yes; then
+  AC_SUBST(WITH_READLINE_01, 1)
+  AC_SUBST(LIBREADLINE, -lreadline)
+else
+  WITH_READLINE_01=0
+fi
+AC_PROG_YACC
+AM_PROG_LEX
+
+LT_INIT
+
+# Create config.m4.
+GMP_FINISH
+
+# Create Makefiles
+# FIXME: Upcoming version of autoconf/automake may not like broken lines.
+#        Right now automake isn't accepting the new AC_CONFIG_FILES scheme.
+
+AC_OUTPUT(Makefile							\
+  mpf/Makefile mpn/Makefile mpq/Makefile				\
+  mpz/Makefile printf/Makefile scanf/Makefile rand/Makefile cxx/Makefile \
+  tests/Makefile tests/devel/Makefile					\
+  tests/mpf/Makefile tests/mpn/Makefile tests/mpq/Makefile		\
+  tests/mpz/Makefile tests/rand/Makefile tests/misc/Makefile		\
+  tests/cxx/Makefile							\
+  doc/Makefile tune/Makefile						\
+  demos/Makefile demos/calc/Makefile demos/expr/Makefile		\
+  gmp.h:gmp-h.in gmp.pc:gmp.pc.in gmpxx.pc:gmpxx.pc.in)
+
+AC_MSG_NOTICE([summary of build options:
+
+  Version:           ${PACKAGE_STRING}
+  Host type:         ${host}
+  ABI:               ${ABI}
+  Install prefix:    ${prefix}
+  Compiler:          ${CC}
+  Static libraries:  ${enable_static}
+  Shared libraries:  ${enable_shared}
+])
diff --git a/third_party/gmp/cxx/Makefile.am b/third_party/gmp/cxx/Makefile.am
new file mode 100644
index 0000000..30ed76a
--- /dev/null
+++ b/third_party/gmp/cxx/Makefile.am
@@ -0,0 +1,40 @@
+## Process this file with automake to generate Makefile.in
+
+# Copyright 2001-2003, 2012 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+
+AM_CPPFLAGS = -D__GMP_WITHIN_GMPXX -I$(top_srcdir)
+
+if WANT_CXX
+noinst_LTLIBRARIES = libcxx.la
+endif
+
+libcxx_la_SOURCES = \
+  isfuns.cc ismpf.cc ismpq.cc ismpz.cc ismpznw.cc limits.cc \
+  osdoprnti.cc osfuns.cc osmpf.cc osmpq.cc osmpz.cc
diff --git a/third_party/gmp/cxx/Makefile.in b/third_party/gmp/cxx/Makefile.in
new file mode 100644
index 0000000..b628df6
--- /dev/null
+++ b/third_party/gmp/cxx/Makefile.in
@@ -0,0 +1,643 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Copyright 2001-2003, 2012 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = cxx
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libcxx_la_LIBADD =
+am_libcxx_la_OBJECTS = isfuns.lo ismpf.lo ismpq.lo ismpz.lo ismpznw.lo \
+	limits.lo osdoprnti.lo osfuns.lo osmpf.lo osmpq.lo osmpz.lo
+libcxx_la_OBJECTS = $(am_libcxx_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+@WANT_CXX_TRUE@am_libcxx_la_rpath =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp =
+am__depfiles_maybe =
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo "  CXX     " $@;
+am__v_CXX_1 = 
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+	$(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo "  CXXLD   " $@;
+am__v_CXXLD_1 = 
+SOURCES = $(libcxx_la_SOURCES)
+DIST_SOURCES = $(libcxx_la_SOURCES)
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ABI = @ABI@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+ASMFLAGS = @ASMFLAGS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CALLING_CONVENTIONS_OBJS = @CALLING_CONVENTIONS_OBJS@
+CC = @CC@
+CCAS = @CCAS@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPP_FOR_BUILD = @CPP_FOR_BUILD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFN_LONG_LONG_LIMB = @DEFN_LONG_LONG_LIMB@
+DEFS = @DEFS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@
+FGREP = @FGREP@
+GMP_LDFLAGS = @GMP_LDFLAGS@
+GMP_LIMB_BITS = @GMP_LIMB_BITS@
+GMP_NAIL_BITS = @GMP_NAIL_BITS@
+GREP = @GREP@
+HAVE_CLOCK_01 = @HAVE_CLOCK_01@
+HAVE_CPUTIME_01 = @HAVE_CPUTIME_01@
+HAVE_GETRUSAGE_01 = @HAVE_GETRUSAGE_01@
+HAVE_GETTIMEOFDAY_01 = @HAVE_GETTIMEOFDAY_01@
+HAVE_HOST_CPU_FAMILY_power = @HAVE_HOST_CPU_FAMILY_power@
+HAVE_HOST_CPU_FAMILY_powerpc = @HAVE_HOST_CPU_FAMILY_powerpc@
+HAVE_SIGACTION_01 = @HAVE_SIGACTION_01@
+HAVE_SIGALTSTACK_01 = @HAVE_SIGALTSTACK_01@
+HAVE_SIGSTACK_01 = @HAVE_SIGSTACK_01@
+HAVE_STACK_T_01 = @HAVE_STACK_T_01@
+HAVE_SYS_RESOURCE_H_01 = @HAVE_SYS_RESOURCE_H_01@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCURSES = @LIBCURSES@
+LIBGMPXX_LDFLAGS = @LIBGMPXX_LDFLAGS@
+LIBGMP_DLL = @LIBGMP_DLL@
+LIBGMP_LDFLAGS = @LIBGMP_LDFLAGS@
+LIBM = @LIBM@
+LIBM_FOR_BUILD = @LIBM_FOR_BUILD@
+LIBOBJS = @LIBOBJS@
+LIBREADLINE = @LIBREADLINE@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+M4 = @M4@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPEED_CYCLECOUNTER_OBJ = @SPEED_CYCLECOUNTER_OBJ@
+STRIP = @STRIP@
+TAL_OBJECT = @TAL_OBJECT@
+TUNE_LIBS = @TUNE_LIBS@
+TUNE_SQR_OBJ = @TUNE_SQR_OBJ@
+U_FOR_BUILD = @U_FOR_BUILD@
+VERSION = @VERSION@
+WITH_READLINE_01 = @WITH_READLINE_01@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__leading_dot = @am__leading_dot@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gmp_srclinks = @gmp_srclinks@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+mpn_objects = @mpn_objects@
+mpn_objs_in_libgmp = @mpn_objs_in_libgmp@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_CPPFLAGS = -D__GMP_WITHIN_GMPXX -I$(top_srcdir)
+@WANT_CXX_TRUE@noinst_LTLIBRARIES = libcxx.la
+libcxx_la_SOURCES = \
+  isfuns.cc ismpf.cc ismpq.cc ismpz.cc ismpznw.cc limits.cc \
+  osdoprnti.cc osfuns.cc osmpf.cc osmpq.cc osmpz.cc
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .cc .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu --ignore-deps cxx/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu --ignore-deps cxx/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+	@list='$(noinst_LTLIBRARIES)'; \
+	locs=`for p in $$list; do echo $$p; done | \
+	      sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+	      sort -u`; \
+	test -z "$$locs" || { \
+	  echo rm -f $${locs}; \
+	  rm -f $${locs}; \
+	}
+
+libcxx.la: $(libcxx_la_OBJECTS) $(libcxx_la_DEPENDENCIES) $(EXTRA_libcxx_la_DEPENDENCIES) 
+	$(AM_V_CXXLD)$(CXXLINK) $(am_libcxx_la_rpath) $(libcxx_la_OBJECTS) $(libcxx_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+.cc.o:
+	$(AM_V_CXX)$(CXXCOMPILE) -c -o $@ $<
+
+.cc.obj:
+	$(AM_V_CXX)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cc.lo:
+	$(AM_V_CXX)$(LTCXXCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+	clean-libtool clean-noinstLTLIBRARIES cscopelist-am ctags \
+	ctags-am distclean distclean-compile distclean-generic \
+	distclean-libtool distclean-tags distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-dvi install-dvi-am install-exec \
+	install-exec-am install-html install-html-am install-info \
+	install-info-am install-man install-pdf install-pdf-am \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/third_party/gmp/cxx/dummy.cc b/third_party/gmp/cxx/dummy.cc
new file mode 100644
index 0000000..8b728ca
--- /dev/null
+++ b/third_party/gmp/cxx/dummy.cc
@@ -0,0 +1,33 @@
+/* Dummy file to make automake treat libgmpxx.la as C++.
+
+Copyright 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+/* some compilers reputedly dislike completely empty files */
+typedef int  foo;
diff --git a/third_party/gmp/cxx/isfuns.cc b/third_party/gmp/cxx/isfuns.cc
new file mode 100644
index 0000000..0cc0db0
--- /dev/null
+++ b/third_party/gmp/cxx/isfuns.cc
@@ -0,0 +1,115 @@
+/* Auxiliary functions for C++-style input of GMP types.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <cctype>
+#include <iostream>
+#include <string>
+#include "gmp-impl.h"
+
+using namespace std;
+
+
+int
+__gmp_istream_set_base (istream &i, char &c, bool &zero, bool &showbase)
+{
+  int base;
+
+  zero = showbase = false;
+  switch (i.flags() & ios::basefield)
+    {
+    case ios::dec:
+      base = 10;
+      break;
+    case ios::hex:
+      base = 16;
+      break;
+    case ios::oct:
+      base = 8;
+      break;
+    default:
+      showbase = true; // look for initial "0" or "0x" or "0X"
+      if (c == '0')
+	{
+	  if (! i.get(c))
+	    c = 0; // reset or we might loop indefinitely
+
+	  if (c == 'x' || c == 'X')
+	    {
+	      base = 16;
+	      i.get(c);
+	    }
+	  else
+	    {
+	      base = 8;
+	      zero = true; // if no other digit is read, the "0" counts
+	    }
+	}
+      else
+	base = 10;
+      break;
+    }
+
+  return base;
+}
+
+void
+__gmp_istream_set_digits (string &s, istream &i, char &c, bool &ok, int base)
+{
+  switch (base)
+    {
+    case 10:
+      while (isdigit(c))
+	{
+	  ok = true; // at least a valid digit was read
+	  s += c;
+	  if (! i.get(c))
+	    break;
+	}
+      break;
+    case 8:
+      while (isdigit(c) && c != '8' && c != '9')
+	{
+	  ok = true; // at least a valid digit was read
+	  s += c;
+	  if (! i.get(c))
+	    break;
+	}
+      break;
+    case 16:
+      while (isxdigit(c))
+	{
+	  ok = true; // at least a valid digit was read
+	  s += c;
+	  if (! i.get(c))
+	    break;
+	}
+      break;
+    }
+}
diff --git a/third_party/gmp/cxx/ismpf.cc b/third_party/gmp/cxx/ismpf.cc
new file mode 100644
index 0000000..9ff25eb
--- /dev/null
+++ b/third_party/gmp/cxx/ismpf.cc
@@ -0,0 +1,144 @@
+/* operator>> -- C++-style input of mpf_t.
+
+Copyright 2001, 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <cctype>
+#include <iostream>
+#include <string>
+#include <clocale>    // for localeconv
+
+#include "gmp-impl.h"
+
+using namespace std;
+
+
+// For g++ libstdc++ parsing see num_get<chartype,initer>::_M_extract_float
+// in include/bits/locale_facets.tcc.
+//
+// There are no plans to accept hex or octal floats, not unless the standard
+// C++ library does so.  Although such formats might be of use, it's
+// considered more important to be compatible with what the normal
+// operator>> does on "double"s etc.
+
+istream &
+operator>> (istream &i, mpf_ptr f)
+{
+  int base;
+  char c = 0;
+  string s;
+  bool ok = false;
+
+  // C decimal point, as expected by mpf_set_str
+  const char *lconv_point = GMP_DECIMAL_POINT;
+
+  // C++ decimal point
+#if HAVE_STD__LOCALE
+  const locale& loc = i.getloc();
+  char point_char = use_facet< numpunct<char> >(loc).decimal_point();
+#else
+  const char *point = lconv_point;
+  char point_char = *point;
+#endif
+
+  i.get(c); // start reading
+
+  if (i.flags() & ios::skipws) // skip initial whitespace
+    {
+      // C++ isspace
+#if HAVE_STD__LOCALE
+      const ctype<char>& ct = use_facet< ctype<char> >(loc);
+#define cxx_isspace(c)  (ct.is(ctype_base::space,(c)))
+#else
+#define cxx_isspace(c)  isspace(c)
+#endif
+
+      while (cxx_isspace(c) && i.get(c))
+        ;
+    }
+
+  if (c == '-' || c == '+') // sign
+    {
+      if (c == '-')
+	s = "-";
+      i.get(c);
+    }
+
+  base = 10;
+  __gmp_istream_set_digits(s, i, c, ok, base); // read the number
+
+  // look for the C++ radix point, but put the C one in for mpf_set_str
+  if (c == point_char)
+    {
+#if HAVE_STD__LOCALE
+      i.get(c);
+#else // lconv point can be multi-char
+      for (;;)
+        {
+          i.get(c);
+          point++;
+          if (*point == '\0')
+            break;
+          if (c != *point)
+            goto fail;
+        }
+#endif
+      s += lconv_point;
+      __gmp_istream_set_digits(s, i, c, ok, base); // read the mantissa
+    }
+
+  if (ok && (c == 'e' || c == 'E')) // exponent
+    {
+      s += c;
+      i.get(c);
+      ok = false; // exponent is mandatory
+
+      if (c == '-' || c == '+') // sign
+	{
+	  s += c;
+	  i.get(c);
+	}
+
+      __gmp_istream_set_digits(s, i, c, ok, base); // read the exponent
+    }
+
+  if (i.good()) // last character read was non-numeric
+    i.putback(c);
+  else if (i.eof() && ok) // stopped just before eof
+    i.clear(ios::eofbit);
+
+  if (ok)
+    ASSERT_NOCARRY (mpf_set_str(f, s.c_str(), base)); // extract the number
+  else
+    {
+    fail:
+      i.setstate(ios::failbit); // read failed
+    }
+
+  return i;
+}
diff --git a/third_party/gmp/cxx/ismpq.cc b/third_party/gmp/cxx/ismpq.cc
new file mode 100644
index 0000000..8cd5121
--- /dev/null
+++ b/third_party/gmp/cxx/ismpq.cc
@@ -0,0 +1,66 @@
+/* operator>> -- C++-style input of mpq_t.
+
+Copyright 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <cctype>
+#include <iostream>
+#include <string>
+#include "gmp-impl.h"
+
+using namespace std;
+
+
+istream &
+operator>> (istream &i, mpq_ptr q)
+{
+  if (! (i >> mpq_numref(q)))
+    return i;
+
+  char  c = 0;
+  i.get(c); // start reading
+
+  if (c == '/')
+    {
+      // skip slash, read denominator
+      i.get(c);
+      return __gmpz_operator_in_nowhite (i, mpq_denref(q), c);
+    }
+  else
+    {
+      // no denominator, set 1
+      q->_mp_den._mp_size = 1;
+      q->_mp_den._mp_d[0] = 1;
+      if (i.good())
+        i.putback(c);
+      else if (i.eof())
+        i.clear(ios::eofbit);
+    }
+
+  return i;
+}
diff --git a/third_party/gmp/cxx/ismpz.cc b/third_party/gmp/cxx/ismpz.cc
new file mode 100644
index 0000000..263ced1
--- /dev/null
+++ b/third_party/gmp/cxx/ismpz.cc
@@ -0,0 +1,62 @@
+/* operator>> -- C++-style input of mpz_t.
+
+Copyright 2001, 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <cctype>
+#include <iostream>
+#include <string>
+#include "gmp-impl.h"
+
+using namespace std;
+
+
+// For g++ libstdc++ parsing see num_get<chartype,initer>::_M_extract_int in
+// include/bits/locale_facets.tcc.
+
+istream &
+operator>> (istream &i, mpz_ptr z)
+{
+  char c = 0;
+  i.get(c); // start reading
+
+  if (i.flags() & ios::skipws) // skip initial whitespace
+    {
+#if HAVE_STD__LOCALE
+      const ctype<char>& ct = use_facet< ctype<char> >(i.getloc());
+#define cxx_isspace(c)  (ct.is(ctype_base::space,(c)))
+#else
+#define cxx_isspace(c)  isspace(c)
+#endif
+
+      while (cxx_isspace(c) && i.get(c))
+        ;
+    }
+
+  return __gmpz_operator_in_nowhite (i, z, c);
+}
diff --git a/third_party/gmp/cxx/ismpznw.cc b/third_party/gmp/cxx/ismpznw.cc
new file mode 100644
index 0000000..84f2806
--- /dev/null
+++ b/third_party/gmp/cxx/ismpznw.cc
@@ -0,0 +1,72 @@
+/* __gmpz_operator_in_nowhite -- C++-style input of mpz_t, no whitespace skip.
+
+Copyright 2001, 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <cctype>
+#include <iostream>
+#include <string>
+#include "gmp-impl.h"
+
+using namespace std;
+
+
+// For g++ libstdc++ parsing see num_get<chartype,initer>::_M_extract_int in
+// include/bits/locale_facets.tcc.
+
+istream &
+__gmpz_operator_in_nowhite (istream &i, mpz_ptr z, char c)
+{
+  int base;
+  string s;
+  bool ok = false, zero, showbase;
+
+  if (c == '-' || c == '+') // sign
+    {
+      if (c == '-') // mpz_set_str doesn't accept '+'
+	s = "-";
+      i.get(c);
+    }
+
+  base = __gmp_istream_set_base(i, c, zero, showbase); // select the base
+  __gmp_istream_set_digits(s, i, c, ok, base);         // read the number
+
+  if (i.good()) // last character read was non-numeric
+    i.putback(c);
+  else if (i.eof() && (ok || zero)) // stopped just before eof
+    i.clear(ios::eofbit);
+
+  if (ok)
+    ASSERT_NOCARRY (mpz_set_str (z, s.c_str(), base)); // extract the number
+  else if (zero)
+    mpz_set_ui(z, 0);
+  else
+    i.setstate(ios::failbit); // read failed
+
+  return i;
+}
diff --git a/third_party/gmp/cxx/limits.cc b/third_party/gmp/cxx/limits.cc
new file mode 100644
index 0000000..3004e16
--- /dev/null
+++ b/third_party/gmp/cxx/limits.cc
@@ -0,0 +1,62 @@
+/* instantiation of numeric_limits specializations.
+
+Copyright 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmpxx.h"
+
+namespace std {
+#define GMPXX_INSTANTIATE_LIMITS(T) \
+  const bool numeric_limits<T>::is_specialized; \
+  const int  numeric_limits<T>::digits; \
+  const int  numeric_limits<T>::digits10; \
+  const int  numeric_limits<T>::max_digits10; \
+  const bool numeric_limits<T>::is_signed; \
+  const bool numeric_limits<T>::is_integer; \
+  const bool numeric_limits<T>::is_exact; \
+  const int  numeric_limits<T>::radix; \
+  const int  numeric_limits<T>::min_exponent; \
+  const int  numeric_limits<T>::min_exponent10; \
+  const int  numeric_limits<T>::max_exponent; \
+  const int  numeric_limits<T>::max_exponent10; \
+  const bool numeric_limits<T>::has_infinity; \
+  const bool numeric_limits<T>::has_quiet_NaN; \
+  const bool numeric_limits<T>::has_signaling_NaN; \
+  const float_denorm_style numeric_limits<T>::has_denorm; \
+  const bool numeric_limits<T>::has_denorm_loss; \
+  const bool numeric_limits<T>::is_iec559; \
+  const bool numeric_limits<T>::is_bounded; \
+  const bool numeric_limits<T>::is_modulo; \
+  const bool numeric_limits<T>::traps; \
+  const bool numeric_limits<T>::tinyness_before; \
+  const float_round_style numeric_limits<T>::round_style
+
+  GMPXX_INSTANTIATE_LIMITS(mpz_class);
+  GMPXX_INSTANTIATE_LIMITS(mpq_class);
+  GMPXX_INSTANTIATE_LIMITS(mpf_class);
+}
diff --git a/third_party/gmp/cxx/osdoprnti.cc b/third_party/gmp/cxx/osdoprnti.cc
new file mode 100644
index 0000000..00dee15
--- /dev/null
+++ b/third_party/gmp/cxx/osdoprnti.cc
@@ -0,0 +1,67 @@
+/* __gmp_doprnt_integer_ios -- integer formatted output to an ostream.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <iostream>
+#include <stdarg.h>   /* for va_list and hence doprnt_funs_t */
+#include <string.h>   /* for strlen */
+
+#include "gmp-impl.h"
+
+using namespace std;
+
+
+/* The gmp_asprintf support routines never give an error, so
+   __gmp_doprnt_integer shouldn't fail and it's return can just be checked
+   with an ASSERT.  */
+
+ostream&
+__gmp_doprnt_integer_ostream (ostream &o, struct doprnt_params_t *p,
+                              char *s)
+{
+  struct gmp_asprintf_t   d;
+  char  *result;
+  int   ret;
+
+  /* don't show leading zeros the way printf does */
+  p->prec = -1;
+
+  GMP_ASPRINTF_T_INIT (d, &result);
+  ret = __gmp_doprnt_integer (&__gmp_asprintf_funs_noformat, &d, p, s);
+  ASSERT (ret != -1);
+  __gmp_asprintf_final (&d);
+  (*__gmp_free_func) (s, strlen(s)+1);
+
+  gmp_allocated_string  t (result);
+  return o.write (t.str, t.len);
+}
diff --git a/third_party/gmp/cxx/osfuns.cc b/third_party/gmp/cxx/osfuns.cc
new file mode 100644
index 0000000..81590a8
--- /dev/null
+++ b/third_party/gmp/cxx/osfuns.cc
@@ -0,0 +1,123 @@
+/* Support for operator<< routines.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <iostream>
+#include <stdarg.h>    /* for va_list and hence doprnt_funs_t */
+#include <string.h>
+
+#include "gmp-impl.h"
+
+using namespace std;
+
+
+/* Don't need "format" for operator<< routines, just "memory" and "reps".
+   Omitting gmp_asprintf_format lets us avoid dragging vsnprintf into the
+   link.  __gmp_asprintf_final will be called directly and doesn't need to
+   be in the struct.  */
+
+const struct doprnt_funs_t  __gmp_asprintf_funs_noformat = {
+  NULL,
+  (doprnt_memory_t) __gmp_asprintf_memory,
+  (doprnt_reps_t)   __gmp_asprintf_reps,
+  NULL
+};
+
+
+void
+__gmp_doprnt_params_from_ios (struct doprnt_params_t *p, ios &o)
+{
+  if ((o.flags() & ios::basefield) == ios::hex)
+    {
+      p->expfmt = "@%c%02d";
+      p->base = (o.flags() & ios::uppercase ? -16 : 16);
+    }
+  else
+    {
+      p->expfmt = (o.flags() & ios::uppercase ? "E%c%02d" : "e%c%02d");
+      if ((o.flags() & ios::basefield) == ios::oct)
+        p->base = 8;
+      else
+        p->base = 10;
+    }
+
+  /* "general" if none or more than one bit set */
+  if ((o.flags() & ios::floatfield) == ios::fixed)
+    p->conv = DOPRNT_CONV_FIXED;
+  else if ((o.flags() & ios::floatfield) == ios::scientific)
+    p->conv = DOPRNT_CONV_SCIENTIFIC;
+  else
+    p->conv = DOPRNT_CONV_GENERAL;
+
+  p->exptimes4 = 0;
+
+  p->fill = o.fill();
+
+  /* "right" if more than one bit set */
+  if ((o.flags() & ios::adjustfield) == ios::left)
+    p->justify = DOPRNT_JUSTIFY_LEFT;
+  else if ((o.flags() & ios::adjustfield) == ios::internal)
+    p->justify = DOPRNT_JUSTIFY_INTERNAL;
+  else
+    p->justify = DOPRNT_JUSTIFY_RIGHT;
+
+  /* ios::fixed allows prec==0, others take 0 as the default 6.
+     Don't allow negatives (they do bad things to __gmp_doprnt_float_cxx).  */
+  p->prec = MAX (0, o.precision());
+  if (p->prec == 0 && p->conv != DOPRNT_CONV_FIXED)
+    p->prec = 6;
+
+  /* for hex showbase is always, for octal only non-zero */
+  if (o.flags() & ios::showbase)
+    p->showbase = ((o.flags() & ios::basefield) == ios::hex
+                   ? DOPRNT_SHOWBASE_YES : DOPRNT_SHOWBASE_NONZERO);
+  else
+    p->showbase = DOPRNT_SHOWBASE_NO;
+
+  p->showpoint = ((o.flags() & ios::showpoint) != 0);
+
+  /* in fixed and scientific always show trailing zeros, in general format
+     show them if showpoint is set (or so it seems) */
+  if ((o.flags() & ios::floatfield) == ios::fixed
+      || (o.flags() & ios::floatfield) == ios::scientific)
+    p->showtrailing = 1;
+  else
+    p->showtrailing = p->showpoint;
+
+  p->sign = (o.flags() & ios::showpos ? '+' : '\0');
+
+  p->width = o.width();
+
+  /* reset on each output */
+  o.width (0);
+}
diff --git a/third_party/gmp/cxx/osmpf.cc b/third_party/gmp/cxx/osmpf.cc
new file mode 100644
index 0000000..fd875db
--- /dev/null
+++ b/third_party/gmp/cxx/osmpf.cc
@@ -0,0 +1,70 @@
+/* operator<< -- mpf formatted output to an ostream.
+
+Copyright 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <clocale>
+#include <iostream>
+#include <stdarg.h>    /* for va_list and hence doprnt_funs_t */
+#include <string.h>
+
+#include "gmp-impl.h"
+
+using namespace std;
+
+
+/* The gmp_asprintf support routines never give an error, so
+   __gmp_doprnt_mpf shouldn't fail and it's return can just be checked with
+   an ASSERT.  */
+
+ostream&
+operator<< (ostream &o, mpf_srcptr f)
+{
+  struct doprnt_params_t  param;
+  struct gmp_asprintf_t   d;
+  char  *result;
+  int   ret;
+
+  __gmp_doprnt_params_from_ios (&param, o);
+
+#if HAVE_STD__LOCALE
+  char  point[2];
+  point[0] = use_facet< numpunct<char> >(o.getloc()).decimal_point();
+  point[1] = '\0';
+#else
+  const char *point = GMP_DECIMAL_POINT;
+#endif
+
+  GMP_ASPRINTF_T_INIT (d, &result);
+  ret = __gmp_doprnt_mpf (&__gmp_asprintf_funs_noformat, &d, &param, point, f);
+  ASSERT (ret != -1);
+  __gmp_asprintf_final (&d);
+
+  gmp_allocated_string  t (result);
+  return o.write (t.str, t.len);
+}
diff --git a/third_party/gmp/cxx/osmpq.cc b/third_party/gmp/cxx/osmpq.cc
new file mode 100644
index 0000000..0c97557
--- /dev/null
+++ b/third_party/gmp/cxx/osmpq.cc
@@ -0,0 +1,47 @@
+/* operator<< -- mpq formatted output to an ostream.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <iostream>
+#include <stdarg.h>    /* for va_list and hence doprnt_funs_t */
+#include <string.h>
+
+#include "gmp-impl.h"
+
+using namespace std;
+
+
+ostream&
+operator<< (ostream &o, mpq_srcptr q)
+{
+  struct doprnt_params_t  param;
+  __gmp_doprnt_params_from_ios (&param, o);
+  return __gmp_doprnt_integer_ostream (o, &param,
+                                       mpq_get_str (NULL, param.base, q));
+}
diff --git a/third_party/gmp/cxx/osmpz.cc b/third_party/gmp/cxx/osmpz.cc
new file mode 100644
index 0000000..2ee71d3
--- /dev/null
+++ b/third_party/gmp/cxx/osmpz.cc
@@ -0,0 +1,47 @@
+/* operator<< -- mpz formatted output to an ostream.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <iostream>
+#include <stdarg.h>    /* for va_list and hence doprnt_funs_t */
+#include <string.h>
+
+#include "gmp-impl.h"
+
+using namespace std;
+
+
+ostream&
+operator<< (ostream &o, mpz_srcptr z)
+{
+  struct doprnt_params_t  param;
+  __gmp_doprnt_params_from_ios (&param, o);
+  return __gmp_doprnt_integer_ostream (o, &param,
+                                       mpz_get_str (NULL, param.base, z));
+}
diff --git a/third_party/gmp/demos/Makefile.am b/third_party/gmp/demos/Makefile.am
new file mode 100644
index 0000000..64010a6
--- /dev/null
+++ b/third_party/gmp/demos/Makefile.am
@@ -0,0 +1,50 @@
+## Process this file with automake to generate Makefile.in
+
+# Copyright 2000-2002, 2012 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+
+SUBDIRS = calc expr
+EXTRA_DIST = perl primes.h
+
+AM_CPPFLAGS = -I$(top_srcdir)
+LDADD = $(top_builddir)/libgmp.la
+
+qcn_LDADD = $(LDADD) $(LIBM)
+primes_LDADD = $(LDADD) $(LIBM)
+
+# None of these programs are built by default, but "make <whatever>" will
+# build them once libgmp.la is built.
+#
+EXTRA_PROGRAMS = factorize isprime pexpr primes qcn
+
+CLEANFILES = $(EXTRA_PROGRAMS)
+
+allprogs: $(EXTRA_PROGRAMS)
+	cd calc; $(MAKE) $(AM_MAKEFLAGS) allprogs
+	cd expr; $(MAKE) $(AM_MAKEFLAGS) allprogs
diff --git a/third_party/gmp/demos/Makefile.in b/third_party/gmp/demos/Makefile.in
new file mode 100644
index 0000000..276c96e
--- /dev/null
+++ b/third_party/gmp/demos/Makefile.in
@@ -0,0 +1,785 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Copyright 2000-2002, 2012 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+EXTRA_PROGRAMS = factorize$(EXEEXT) isprime$(EXEEXT) pexpr$(EXEEXT) \
+	primes$(EXEEXT) qcn$(EXEEXT)
+subdir = demos
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES = pexpr-config.h
+CONFIG_CLEAN_VPATH_FILES =
+factorize_SOURCES = factorize.c
+factorize_OBJECTS = factorize.$(OBJEXT)
+factorize_LDADD = $(LDADD)
+factorize_DEPENDENCIES = $(top_builddir)/libgmp.la
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+isprime_SOURCES = isprime.c
+isprime_OBJECTS = isprime.$(OBJEXT)
+isprime_LDADD = $(LDADD)
+isprime_DEPENDENCIES = $(top_builddir)/libgmp.la
+pexpr_SOURCES = pexpr.c
+pexpr_OBJECTS = pexpr.$(OBJEXT)
+pexpr_LDADD = $(LDADD)
+pexpr_DEPENDENCIES = $(top_builddir)/libgmp.la
+primes_SOURCES = primes.c
+primes_OBJECTS = primes.$(OBJEXT)
+am__DEPENDENCIES_1 =
+primes_DEPENDENCIES = $(LDADD) $(am__DEPENDENCIES_1)
+qcn_SOURCES = qcn.c
+qcn_OBJECTS = qcn.$(OBJEXT)
+qcn_DEPENDENCIES = $(LDADD) $(am__DEPENDENCIES_1)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp =
+am__depfiles_maybe =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+SOURCES = factorize.c isprime.c pexpr.c primes.c qcn.c
+DIST_SOURCES = factorize.c isprime.c pexpr.c primes.c qcn.c
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+	ctags-recursive dvi-recursive html-recursive info-recursive \
+	install-data-recursive install-dvi-recursive \
+	install-exec-recursive install-html-recursive \
+	install-info-recursive install-pdf-recursive \
+	install-ps-recursive install-recursive installcheck-recursive \
+	installdirs-recursive pdf-recursive ps-recursive \
+	tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive	\
+  distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+  $(RECURSIVE_TARGETS) \
+  $(RECURSIVE_CLEAN_TARGETS) \
+  $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+	distdir
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/pexpr-config-h.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+  dir0=`pwd`; \
+  sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+  sed_rest='s,^[^/]*/*,,'; \
+  sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+  sed_butlast='s,/*[^/]*$$,,'; \
+  while test -n "$$dir1"; do \
+    first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+    if test "$$first" != "."; then \
+      if test "$$first" = ".."; then \
+        dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+        dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+      else \
+        first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+        if test "$$first2" = "$$first"; then \
+          dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+        else \
+          dir2="../$$dir2"; \
+        fi; \
+        dir0="$$dir0"/"$$first"; \
+      fi; \
+    fi; \
+    dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+  done; \
+  reldir="$$dir2"
+ABI = @ABI@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+ASMFLAGS = @ASMFLAGS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CALLING_CONVENTIONS_OBJS = @CALLING_CONVENTIONS_OBJS@
+CC = @CC@
+CCAS = @CCAS@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPP_FOR_BUILD = @CPP_FOR_BUILD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFN_LONG_LONG_LIMB = @DEFN_LONG_LONG_LIMB@
+DEFS = @DEFS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@
+FGREP = @FGREP@
+GMP_LDFLAGS = @GMP_LDFLAGS@
+GMP_LIMB_BITS = @GMP_LIMB_BITS@
+GMP_NAIL_BITS = @GMP_NAIL_BITS@
+GREP = @GREP@
+HAVE_CLOCK_01 = @HAVE_CLOCK_01@
+HAVE_CPUTIME_01 = @HAVE_CPUTIME_01@
+HAVE_GETRUSAGE_01 = @HAVE_GETRUSAGE_01@
+HAVE_GETTIMEOFDAY_01 = @HAVE_GETTIMEOFDAY_01@
+HAVE_HOST_CPU_FAMILY_power = @HAVE_HOST_CPU_FAMILY_power@
+HAVE_HOST_CPU_FAMILY_powerpc = @HAVE_HOST_CPU_FAMILY_powerpc@
+HAVE_SIGACTION_01 = @HAVE_SIGACTION_01@
+HAVE_SIGALTSTACK_01 = @HAVE_SIGALTSTACK_01@
+HAVE_SIGSTACK_01 = @HAVE_SIGSTACK_01@
+HAVE_STACK_T_01 = @HAVE_STACK_T_01@
+HAVE_SYS_RESOURCE_H_01 = @HAVE_SYS_RESOURCE_H_01@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCURSES = @LIBCURSES@
+LIBGMPXX_LDFLAGS = @LIBGMPXX_LDFLAGS@
+LIBGMP_DLL = @LIBGMP_DLL@
+LIBGMP_LDFLAGS = @LIBGMP_LDFLAGS@
+LIBM = @LIBM@
+LIBM_FOR_BUILD = @LIBM_FOR_BUILD@
+LIBOBJS = @LIBOBJS@
+LIBREADLINE = @LIBREADLINE@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+M4 = @M4@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPEED_CYCLECOUNTER_OBJ = @SPEED_CYCLECOUNTER_OBJ@
+STRIP = @STRIP@
+TAL_OBJECT = @TAL_OBJECT@
+TUNE_LIBS = @TUNE_LIBS@
+TUNE_SQR_OBJ = @TUNE_SQR_OBJ@
+U_FOR_BUILD = @U_FOR_BUILD@
+VERSION = @VERSION@
+WITH_READLINE_01 = @WITH_READLINE_01@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__leading_dot = @am__leading_dot@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gmp_srclinks = @gmp_srclinks@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+mpn_objects = @mpn_objects@
+mpn_objs_in_libgmp = @mpn_objs_in_libgmp@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = calc expr
+EXTRA_DIST = perl primes.h
+AM_CPPFLAGS = -I$(top_srcdir)
+LDADD = $(top_builddir)/libgmp.la
+qcn_LDADD = $(LDADD) $(LIBM)
+primes_LDADD = $(LDADD) $(LIBM)
+CLEANFILES = $(EXTRA_PROGRAMS)
+all: all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu --ignore-deps demos/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu --ignore-deps demos/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+pexpr-config.h: $(top_builddir)/config.status $(srcdir)/pexpr-config-h.in
+	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+
+factorize$(EXEEXT): $(factorize_OBJECTS) $(factorize_DEPENDENCIES) $(EXTRA_factorize_DEPENDENCIES) 
+	@rm -f factorize$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(factorize_OBJECTS) $(factorize_LDADD) $(LIBS)
+
+isprime$(EXEEXT): $(isprime_OBJECTS) $(isprime_DEPENDENCIES) $(EXTRA_isprime_DEPENDENCIES) 
+	@rm -f isprime$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(isprime_OBJECTS) $(isprime_LDADD) $(LIBS)
+
+pexpr$(EXEEXT): $(pexpr_OBJECTS) $(pexpr_DEPENDENCIES) $(EXTRA_pexpr_DEPENDENCIES) 
+	@rm -f pexpr$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(pexpr_OBJECTS) $(pexpr_LDADD) $(LIBS)
+
+primes$(EXEEXT): $(primes_OBJECTS) $(primes_DEPENDENCIES) $(EXTRA_primes_DEPENDENCIES) 
+	@rm -f primes$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(primes_OBJECTS) $(primes_LDADD) $(LIBS)
+
+qcn$(EXEEXT): $(qcn_OBJECTS) $(qcn_DEPENDENCIES) $(EXTRA_qcn_DEPENDENCIES) 
+	@rm -f qcn$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(qcn_OBJECTS) $(qcn_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+.c.o:
+	$(AM_V_CC)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+	$(AM_V_CC)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+	$(AM_V_CC)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+#     (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+	@fail=; \
+	if $(am__make_keepgoing); then \
+	  failcom='fail=yes'; \
+	else \
+	  failcom='exit 1'; \
+	fi; \
+	dot_seen=no; \
+	target=`echo $@ | sed s/-recursive//`; \
+	case "$@" in \
+	  distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+	  *) list='$(SUBDIRS)' ;; \
+	esac; \
+	for subdir in $$list; do \
+	  echo "Making $$target in $$subdir"; \
+	  if test "$$subdir" = "."; then \
+	    dot_seen=yes; \
+	    local_target="$$target-am"; \
+	  else \
+	    local_target="$$target"; \
+	  fi; \
+	  ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+	  || eval $$failcom; \
+	done; \
+	if test "$$dot_seen" = "no"; then \
+	  $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+	fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+	  include_option=--etags-include; \
+	  empty_fix=.; \
+	else \
+	  include_option=--include; \
+	  empty_fix=; \
+	fi; \
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    test ! -f $$subdir/TAGS || \
+	      set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+	  fi; \
+	done; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+	@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    $(am__make_dryrun) \
+	      || test -d "$(distdir)/$$subdir" \
+	      || $(MKDIR_P) "$(distdir)/$$subdir" \
+	      || exit 1; \
+	    dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+	    $(am__relativize); \
+	    new_distdir=$$reldir; \
+	    dir1=$$subdir; dir2="$(top_distdir)"; \
+	    $(am__relativize); \
+	    new_top_distdir=$$reldir; \
+	    echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+	    echo "     am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+	    ($(am__cd) $$subdir && \
+	      $(MAKE) $(AM_MAKEFLAGS) \
+	        top_distdir="$$new_top_distdir" \
+	        distdir="$$new_distdir" \
+		am__remove_distdir=: \
+		am__skip_length_check=: \
+		am__skip_mode_fix=: \
+	        distdir) \
+	      || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-recursive
+all-am: Makefile
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+	-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(am__recursive_targets) install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
+	check-am clean clean-generic clean-libtool cscopelist-am ctags \
+	ctags-am distclean distclean-compile distclean-generic \
+	distclean-libtool distclean-tags distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-dvi install-dvi-am install-exec \
+	install-exec-am install-html install-html-am install-info \
+	install-info-am install-man install-pdf install-pdf-am \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs installdirs-am maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+allprogs: $(EXTRA_PROGRAMS)
+	cd calc; $(MAKE) $(AM_MAKEFLAGS) allprogs
+	cd expr; $(MAKE) $(AM_MAKEFLAGS) allprogs
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/third_party/gmp/demos/calc/Makefile.am b/third_party/gmp/demos/calc/Makefile.am
new file mode 100644
index 0000000..1cb5335
--- /dev/null
+++ b/third_party/gmp/demos/calc/Makefile.am
@@ -0,0 +1,47 @@
+## Process this file with automake to generate Makefile.in
+
+# Copyright 2000-2004 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+
+AM_CPPFLAGS = -I$(top_srcdir)
+
+# $(LEXLIB) is not actually needed for flex (which means the distributed
+# calclex.c), but it's included here for the benefit of anyone rebuilding
+# with some other lex.
+#
+LDADD = $(top_builddir)/libgmp.la $(LIBREADLINE) $(LIBCURSES) $(LEXLIB)
+
+EXTRA_PROGRAMS = calc
+AM_YFLAGS = -d
+calc_SOURCES = calc.y calclex.l calcread.c calc-common.h
+BUILT_SOURCES = calc.h
+
+CLEANFILES = $(EXTRA_PROGRAMS)
+
+allprogs: $(EXTRA_PROGRAMS)
diff --git a/third_party/gmp/demos/calc/Makefile.in b/third_party/gmp/demos/calc/Makefile.in
new file mode 100644
index 0000000..5feb9a8
--- /dev/null
+++ b/third_party/gmp/demos/calc/Makefile.in
@@ -0,0 +1,677 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Copyright 2000-2004 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+EXTRA_PROGRAMS = calc$(EXEEXT)
+subdir = demos/calc
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES = calc-config.h
+CONFIG_CLEAN_VPATH_FILES =
+am_calc_OBJECTS = calc.$(OBJEXT) calclex.$(OBJEXT) calcread.$(OBJEXT)
+calc_OBJECTS = $(am_calc_OBJECTS)
+calc_LDADD = $(LDADD)
+am__DEPENDENCIES_1 =
+calc_DEPENDENCIES = $(top_builddir)/libgmp.la $(am__DEPENDENCIES_1) \
+	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp =
+am__depfiles_maybe =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+@MAINTAINER_MODE_FALSE@am__skiplex = test -f $@ ||
+LEXCOMPILE = $(LEX) $(AM_LFLAGS) $(LFLAGS)
+LTLEXCOMPILE = $(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(LEX) $(AM_LFLAGS) $(LFLAGS)
+AM_V_LEX = $(am__v_LEX_@AM_V@)
+am__v_LEX_ = $(am__v_LEX_@AM_DEFAULT_V@)
+am__v_LEX_0 = @echo "  LEX     " $@;
+am__v_LEX_1 = 
+YLWRAP = $(top_srcdir)/ylwrap
+@MAINTAINER_MODE_FALSE@am__skipyacc = test -f $@ ||
+am__yacc_c2h = sed -e s/cc$$/hh/ -e s/cpp$$/hpp/ -e s/cxx$$/hxx/ \
+		   -e s/c++$$/h++/ -e s/c$$/h/
+YACCCOMPILE = $(YACC) $(AM_YFLAGS) $(YFLAGS)
+LTYACCCOMPILE = $(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(YACC) $(AM_YFLAGS) $(YFLAGS)
+AM_V_YACC = $(am__v_YACC_@AM_V@)
+am__v_YACC_ = $(am__v_YACC_@AM_DEFAULT_V@)
+am__v_YACC_0 = @echo "  YACC    " $@;
+am__v_YACC_1 = 
+SOURCES = $(calc_SOURCES)
+DIST_SOURCES = $(calc_SOURCES)
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/calc-config-h.in \
+	$(top_srcdir)/ylwrap README calc.c calc.h calclex.c
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ABI = @ABI@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+ASMFLAGS = @ASMFLAGS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CALLING_CONVENTIONS_OBJS = @CALLING_CONVENTIONS_OBJS@
+CC = @CC@
+CCAS = @CCAS@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPP_FOR_BUILD = @CPP_FOR_BUILD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFN_LONG_LONG_LIMB = @DEFN_LONG_LONG_LIMB@
+DEFS = @DEFS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@
+FGREP = @FGREP@
+GMP_LDFLAGS = @GMP_LDFLAGS@
+GMP_LIMB_BITS = @GMP_LIMB_BITS@
+GMP_NAIL_BITS = @GMP_NAIL_BITS@
+GREP = @GREP@
+HAVE_CLOCK_01 = @HAVE_CLOCK_01@
+HAVE_CPUTIME_01 = @HAVE_CPUTIME_01@
+HAVE_GETRUSAGE_01 = @HAVE_GETRUSAGE_01@
+HAVE_GETTIMEOFDAY_01 = @HAVE_GETTIMEOFDAY_01@
+HAVE_HOST_CPU_FAMILY_power = @HAVE_HOST_CPU_FAMILY_power@
+HAVE_HOST_CPU_FAMILY_powerpc = @HAVE_HOST_CPU_FAMILY_powerpc@
+HAVE_SIGACTION_01 = @HAVE_SIGACTION_01@
+HAVE_SIGALTSTACK_01 = @HAVE_SIGALTSTACK_01@
+HAVE_SIGSTACK_01 = @HAVE_SIGSTACK_01@
+HAVE_STACK_T_01 = @HAVE_STACK_T_01@
+HAVE_SYS_RESOURCE_H_01 = @HAVE_SYS_RESOURCE_H_01@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCURSES = @LIBCURSES@
+LIBGMPXX_LDFLAGS = @LIBGMPXX_LDFLAGS@
+LIBGMP_DLL = @LIBGMP_DLL@
+LIBGMP_LDFLAGS = @LIBGMP_LDFLAGS@
+LIBM = @LIBM@
+LIBM_FOR_BUILD = @LIBM_FOR_BUILD@
+LIBOBJS = @LIBOBJS@
+LIBREADLINE = @LIBREADLINE@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+M4 = @M4@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPEED_CYCLECOUNTER_OBJ = @SPEED_CYCLECOUNTER_OBJ@
+STRIP = @STRIP@
+TAL_OBJECT = @TAL_OBJECT@
+TUNE_LIBS = @TUNE_LIBS@
+TUNE_SQR_OBJ = @TUNE_SQR_OBJ@
+U_FOR_BUILD = @U_FOR_BUILD@
+VERSION = @VERSION@
+WITH_READLINE_01 = @WITH_READLINE_01@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__leading_dot = @am__leading_dot@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gmp_srclinks = @gmp_srclinks@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+mpn_objects = @mpn_objects@
+mpn_objs_in_libgmp = @mpn_objs_in_libgmp@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_CPPFLAGS = -I$(top_srcdir)
+
+# $(LEXLIB) is not actually needed for flex (which means the distributed
+# calclex.c), but it's included here for the benefit of anyone rebuilding
+# with some other lex.
+#
+LDADD = $(top_builddir)/libgmp.la $(LIBREADLINE) $(LIBCURSES) $(LEXLIB)
+AM_YFLAGS = -d
+calc_SOURCES = calc.y calclex.l calcread.c calc-common.h
+BUILT_SOURCES = calc.h
+CLEANFILES = $(EXTRA_PROGRAMS)
+all: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .l .lo .o .obj .y
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu --ignore-deps demos/calc/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu --ignore-deps demos/calc/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+calc-config.h: $(top_builddir)/config.status $(srcdir)/calc-config-h.in
+	cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+calc.h: calc.c
+	@if test ! -f $@; then rm -f calc.c; else :; fi
+	@if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) calc.c; else :; fi
+
+calc$(EXEEXT): $(calc_OBJECTS) $(calc_DEPENDENCIES) $(EXTRA_calc_DEPENDENCIES) 
+	@rm -f calc$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(calc_OBJECTS) $(calc_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+.c.o:
+	$(AM_V_CC)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+	$(AM_V_CC)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+	$(AM_V_CC)$(LTCOMPILE) -c -o $@ $<
+
+.l.c:
+	$(AM_V_LEX)$(am__skiplex) $(SHELL) $(YLWRAP) $< $(LEX_OUTPUT_ROOT).c $@ -- $(LEXCOMPILE)
+
+.y.c:
+	$(AM_V_YACC)$(am__skipyacc) $(SHELL) $(YLWRAP) $< y.tab.c $@ y.tab.h `echo $@ | $(am__yacc_c2h)` y.output $*.output -- $(YACCCOMPILE)
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile
+installdirs:
+install: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+	-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+	-rm -f calc.c
+	-rm -f calc.h
+	-rm -f calclex.c
+	-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: all check install install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+	clean-libtool cscopelist-am ctags ctags-am distclean \
+	distclean-compile distclean-generic distclean-libtool \
+	distclean-tags distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-ps install-ps-am \
+	install-strip installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+	pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+allprogs: $(EXTRA_PROGRAMS)
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/third_party/gmp/demos/calc/README b/third_party/gmp/demos/calc/README
new file mode 100644
index 0000000..660394e
--- /dev/null
+++ b/third_party/gmp/demos/calc/README
@@ -0,0 +1,65 @@
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 3 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program.  If not, see https://www.gnu.org/licenses/.
+
+
+
+
+                   DEMONSTRATION CALCULATOR PROGRAM
+
+
+This is a simple program, meant only to show one way to use GMP with yacc
+and lex to make a calculator.  Usage and comments on the implementation can
+be found in calc.y.
+
+Within a GMP build tree, the generated Makefile can be used to build the
+program,
+
+	make calc
+
+(or on a DOS system, "make calc.exe").
+
+Elsewhere, once GMP has been installed, the program can be compiled with for
+instance
+
+	gcc calc.c calclex.c -lgmp -o calc
+
+Or if GNU readline is used then
+
+	gcc calc.c calclex.c calcread.c -lgmp -lreadline -o calc
+
+(again, on a DOS system "-o calc.exe").
+
+Readline support can be enabled or disabled in calc-config.h.  That file is
+created by the GMP ./configure based on the --with-readline option.  The
+default is --with-readline=detect, which means to use readline if available.
+"yes" can be used to force it to be used, or "no" to not use it.
+
+The supplied calc.c was generated by GNU bison, but a standard yacc should
+work too.
+
+The supplied calclex.c was generated by GNU flex, but a standard lex should
+work too.  The readline support may or may not work with a standard lex (see
+comments with input() in calcread.c).  Note also that a standard lex will
+require its library "-ll" on the compile command line.  "./configure" sets
+this up in the GMP build tree Makefile.
+
+
+
+----------------
+Local variables:
+mode: text
+fill-column: 76
+End:
diff --git a/third_party/gmp/demos/calc/calc-common.h b/third_party/gmp/demos/calc/calc-common.h
new file mode 100644
index 0000000..7a91878
--- /dev/null
+++ b/third_party/gmp/demos/calc/calc-common.h
@@ -0,0 +1,35 @@
+/* Prototypes etc for calc program.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 3 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stddef.h>  /* for size_t */
+#ifndef NO_CALC_H
+#include "calc.h"
+#endif
+#include "calc-config.h"
+
+struct calc_keywords_t {
+  char  *name;
+  int   value;
+};
+
+extern int  calc_option_readline;
+extern int  calc_more_input;
+extern const struct calc_keywords_t  calc_keywords[];
+
+int calc_input (char *buf, size_t max_size);
+void calc_init_readline (void);
diff --git a/third_party/gmp/demos/calc/calc-config-h.in b/third_party/gmp/demos/calc/calc-config-h.in
new file mode 100644
index 0000000..42cdd44
--- /dev/null
+++ b/third_party/gmp/demos/calc/calc-config-h.in
@@ -0,0 +1,21 @@
+/* Templates for calc program configuration.   -*- mode:c -*-
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 3 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program.  If not, see https://www.gnu.org/licenses/.  */
+
+
+/* Define if GNU readline should be used. */
+#define WITH_READLINE @WITH_READLINE_01@
diff --git a/third_party/gmp/demos/calc/calc.c b/third_party/gmp/demos/calc/calc.c
new file mode 100644
index 0000000..cc653a2
--- /dev/null
+++ b/third_party/gmp/demos/calc/calc.c
@@ -0,0 +1,1148 @@
+/* original parser id follows */
+/* yysccsid[] = "@(#)yaccpar	1.9 (Berkeley) 02/21/93" */
+/* (use YYMAJOR/YYMINOR for ifdefs dependent on parser version) */
+
+#define YYBYACC 1
+#define YYMAJOR 1
+#define YYMINOR 9
+#define YYPATCH 20170201
+
+#define YYEMPTY        (-1)
+#define yyclearin      (yychar = YYEMPTY)
+#define yyerrok        (yyerrflag = 0)
+#define YYRECOVERING() (yyerrflag != 0)
+#define YYENOMEM       (-2)
+#define YYEOF          0
+#define YYPREFIX "yy"
+
+#define YYPURE 0
+
+#line 2 "../../../gmp/demos/calc/calc.y"
+/* A simple integer desk calculator using yacc and gmp.
+
+Copyright 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 3 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program.  If not, see https://www.gnu.org/licenses/.  */
+
+
+/* This is a simple program, meant only to show one way to use GMP for this
+   sort of thing.  There's few features, and error checking is minimal.
+   Standard input is read, calc_help() below shows the inputs accepted.
+
+   Expressions are evaluated as they're read.  If user defined functions
+   were wanted it'd be necessary to build a parse tree like pexpr.c does, or
+   a list of operations for a stack based evaluator.  That would also make
+   it possible to detect and optimize evaluations "mod m" like pexpr.c does.
+
+   A stack is used for intermediate values in the expression evaluation,
+   separate from the yacc parser stack.  This is simple, makes error
+   recovery easy, minimizes the junk around mpz calls in the rules, and
+   saves initializing or clearing "mpz_t"s during a calculation.  A
+   disadvantage though is that variables must be copied to the stack to be
+   worked on.  A more sophisticated calculator or language system might be
+   able to avoid that when executing a compiled or semi-compiled form.
+
+   Avoiding repeated initializing and clearing of "mpz_t"s is important.  In
+   this program the time spent parsing is obviously much greater than any
+   possible saving from this, but a proper calculator or language should
+   take some trouble over it.  Don't be surprised if an init/clear takes 3
+   or more times as long as a 10 limb addition, depending on the system (see
+   the mpz_init_realloc_clear example in tune/README).  */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "gmp.h"
+#define NO_CALC_H /* because it conflicts with normal calc.c stuff */
+#include "calc-common.h"
+
+
+#define numberof(x)  (sizeof (x) / sizeof ((x)[0]))
+
+
+void
+calc_help (void)
+{
+  printf ("Examples:\n");
+  printf ("    2+3*4        expressions are evaluated\n");
+  printf ("    x=5^6        variables a to z can be set and used\n");
+  printf ("Operators:\n");
+  printf ("    + - *        arithmetic\n");
+  printf ("    / %%          division and remainder (rounding towards negative infinity)\n");
+  printf ("    ^            exponentiation\n");
+  printf ("    !            factorial\n");
+  printf ("    << >>        left and right shifts\n");
+  printf ("    <= >= >      \\ comparisons, giving 1 if true, 0 if false\n");
+  printf ("    == != <      /\n");
+  printf ("    && ||        logical and/or, giving 1 if true, 0 if false\n");
+  printf ("Functions:\n");
+  printf ("    abs(n)       absolute value\n");
+  printf ("    bin(n,m)     binomial coefficient\n");
+  printf ("    fib(n)       fibonacci number\n");
+  printf ("    gcd(a,b,..)  greatest common divisor\n");
+  printf ("    kron(a,b)    kronecker symbol\n");
+  printf ("    lcm(a,b,..)  least common multiple\n");
+  printf ("    lucnum(n)    lucas number\n");
+  printf ("    nextprime(n) next prime after n\n");
+  printf ("    powm(b,e,m)  modulo powering, b^e%%m\n");
+  printf ("    root(n,r)    r-th root\n");
+  printf ("    sqrt(n)      square root\n");
+  printf ("Other:\n");
+  printf ("    hex          \\ set hex or decimal for input and output\n");
+  printf ("    decimal      /   (\"0x\" can be used for hex too)\n");
+  printf ("    quit         exit program (EOF works too)\n");
+  printf ("    ;            statements are separated with a ; or newline\n");
+  printf ("    \\            continue expressions with \\ before newline\n");
+  printf ("    # xxx        comments are # though to newline\n");
+  printf ("Hex numbers must be entered in upper case, to distinguish them from the\n");
+  printf ("variables a to f (like in bc).\n");
+}
+
+
+int  ibase = 0;
+int  obase = 10;
+
+
+/* The stack is a fixed size, which means there's a limit on the nesting
+   allowed in expressions.  A more sophisticated program could let it grow
+   dynamically.  */
+
+mpz_t    stack[100];
+mpz_ptr  sp = stack[0];
+
+#define CHECK_OVERFLOW()                                                  \
+  if (sp >= stack[numberof(stack)])	/* FIXME */			\
+    {                                                                     \
+      fprintf (stderr,                                                    \
+               "Value stack overflow, too much nesting in expression\n"); \
+      YYERROR;                                                            \
+    }
+
+#define CHECK_EMPTY()                                                   \
+  if (sp != stack[0])                                                   \
+    {                                                                   \
+      fprintf (stderr, "Oops, expected the value stack to be empty\n"); \
+      sp = stack[0];                                                    \
+    }
+
+
+mpz_t  variable[26];
+
+#define CHECK_VARIABLE(var)                                             \
+  if ((var) < 0 || (var) >= numberof (variable))                        \
+    {                                                                   \
+      fprintf (stderr, "Oops, bad variable somehow: %d\n", var);        \
+      YYERROR;                                                          \
+    }
+
+
+#define CHECK_UI(name,z)                        \
+  if (! mpz_fits_ulong_p (z))                   \
+    {                                           \
+      fprintf (stderr, "%s too big\n", name);   \
+      YYERROR;                                  \
+    }
+
+#ifdef YYSTYPE
+#undef  YYSTYPE_IS_DECLARED
+#define YYSTYPE_IS_DECLARED 1
+#endif
+#ifndef YYSTYPE_IS_DECLARED
+#define YYSTYPE_IS_DECLARED 1
+#line 142 "../../../gmp/demos/calc/calc.y"
+typedef union {
+  char  *str;
+  int   var;
+} YYSTYPE;
+#endif /* !YYSTYPE_IS_DECLARED */
+#line 172 "calc.c"
+
+/* compatibility with bison */
+#ifdef YYPARSE_PARAM
+/* compatibility with FreeBSD */
+# ifdef YYPARSE_PARAM_TYPE
+#  define YYPARSE_DECL() yyparse(YYPARSE_PARAM_TYPE YYPARSE_PARAM)
+# else
+#  define YYPARSE_DECL() yyparse(void *YYPARSE_PARAM)
+# endif
+#else
+# define YYPARSE_DECL() yyparse(void)
+#endif
+
+/* Parameters sent to lex. */
+#ifdef YYLEX_PARAM
+# define YYLEX_DECL() yylex(void *YYLEX_PARAM)
+# define YYLEX yylex(YYLEX_PARAM)
+#else
+# define YYLEX_DECL() yylex(void)
+# define YYLEX yylex()
+#endif
+
+/* Parameters sent to yyerror. */
+#ifndef YYERROR_DECL
+#define YYERROR_DECL() yyerror(const char *s)
+#endif
+#ifndef YYERROR_CALL
+#define YYERROR_CALL(msg) yyerror(msg)
+#endif
+
+extern int YYPARSE_DECL();
+
+#define EOS 257
+#define BAD 258
+#define HELP 259
+#define HEX 260
+#define DECIMAL 261
+#define QUIT 262
+#define ABS 263
+#define BIN 264
+#define FIB 265
+#define GCD 266
+#define KRON 267
+#define LCM 268
+#define LUCNUM 269
+#define NEXTPRIME 270
+#define POWM 271
+#define ROOT 272
+#define SQRT 273
+#define NUMBER 274
+#define VARIABLE 275
+#define LOR 276
+#define LAND 277
+#define EQ 278
+#define NE 279
+#define LE 280
+#define GE 281
+#define LSHIFT 282
+#define RSHIFT 283
+#define UMINUS 284
+#define YYERRCODE 256
+typedef int YYINT;
+static const YYINT yylhs[] = {                           -1,
+    0,    0,    2,    2,    2,    1,    1,    1,    1,    1,
+    1,    1,    3,    3,    3,    3,    3,    3,    3,    3,
+    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,
+    3,    3,    3,    3,    3,    3,    3,    3,    3,    3,
+    3,    3,    3,    3,    4,    4,    5,    5,
+};
+static const YYINT yylen[] = {                            2,
+    1,    2,    2,    3,    2,    0,    1,    3,    1,    1,
+    1,    1,    3,    3,    3,    3,    3,    3,    3,    3,
+    3,    2,    2,    3,    3,    3,    3,    3,    3,    3,
+    3,    4,    6,    4,    4,    6,    4,    4,    4,    8,
+    6,    4,    1,    1,    1,    3,    1,    3,
+};
+static const YYINT yydefred[] = {                         0,
+    0,    9,   10,   11,   12,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,   44,    0,    0,    0,
+    0,    0,    0,    0,    5,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,   43,    0,    0,
+    3,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,   22,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,   13,    4,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,   32,    0,   34,   35,    0,    0,   37,    0,   38,
+   39,    0,    0,   42,    0,    0,    0,    0,    0,    0,
+   33,   36,    0,   41,    0,   40,
+};
+static const YYINT yydgoto[] = {                         21,
+   22,   23,   24,   64,   67,
+};
+static const YYINT yysindex[] = {                       742,
+ -257,    0,    0,    0,    0,  -22,  -20,  -17,   -5,    5,
+   18,   20,   22,   25,   28,   29,    0,  -54,  808,  808,
+    0, -244,  786,  667,    0,  808,  808,  808,  808,  808,
+  808,  808,  808,  808,  808,  808,  808,    0,  -27,  203,
+    0, -217,  808,  808,  808,  808,  808,  808,  808,  808,
+  808,  808,  808,  808,  808,  808,  808,  808,    0,  454,
+  465,  487,  667,  -33,  498,  667,  -16,  520,  531,  542,
+  564,  586,  667,    0,    0,  678,  929,  -28,  -28,  -28,
+  -28,  -28,  -28,  -21,  -21,   -6,   -6,  -27,  -27,  -27,
+  -27,    0,  808,    0,    0,  808,  808,    0,  808,    0,
+    0,  808,  808,    0,  597,  667,  608,  667,  619,  645,
+    0,    0,  808,    0,  656,    0,
+};
+static const YYINT yyrindex[] = {                         2,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    1,    0,    0,
+    0,   50,    2,    3,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,   10,    0,
+    0,   71,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,  -12,    0,    0,  -11,    0,    0,    0,    0,
+    0,    0,    4,    0,    0,  193,   64,  166,  178,  182,
+  187,  189,  191,  139,  151,  112,  124,   37,   49,   76,
+   85,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,   -2,    0,   15,    0,    0,
+    0,    0,    0,    0,    0,    0,
+};
+static const YYINT yygindex[] = {                         0,
+   52,    0, 1065,    0,    0,
+};
+#define YYTABLESIZE 1212
+static const YYINT yytable[] = {                         25,
+   43,    6,    7,    8,   59,   59,   37,   95,   57,   23,
+   96,   59,   41,   55,   53,   57,   54,   26,   56,   27,
+   55,   53,   28,   54,   98,   56,   59,   99,   45,   47,
+   57,   45,   47,   43,   29,   55,   16,   43,   46,   75,
+   56,   46,   43,   43,   30,   43,   23,   43,   17,    1,
+   23,   23,   23,   23,   23,   48,   23,   31,   48,   32,
+   43,   33,   43,   30,   34,   58,   58,   35,   36,   23,
+    2,   23,   58,   16,   42,   18,    0,   16,   16,   16,
+   16,   16,    0,   16,   19,   17,    0,   58,    0,   17,
+   17,   17,   17,   17,   43,   17,   16,    0,   16,    0,
+    0,    0,    0,    0,   30,    0,    0,   30,   17,    0,
+   17,   14,   18,    0,    0,    0,   18,   18,   18,   18,
+   18,   19,   18,   15,    0,   19,   19,   19,   19,   19,
+    0,   19,    0,    0,    0,   18,    0,   18,   20,    0,
+    0,    0,    0,    0,   19,    0,   19,    0,    0,    0,
+   21,    0,   14,    0,   14,   14,   14,    0,    0,    0,
+    0,    0,    0,    0,   15,   24,   15,   15,   15,    0,
+    0,   14,    0,   14,    0,    0,    0,   29,    0,   20,
+    0,   26,   20,   15,    0,   15,   27,    0,   25,    0,
+   28,   21,   31,    0,   21,    0,    0,    0,   20,    0,
+   20,    0,    0,    0,    0,    0,   24,    0,    0,   24,
+   21,    0,   21,    0,    0,    0,    0,    0,   29,    0,
+    0,   29,   26,    0,    0,   26,    0,   27,    0,   25,
+   27,   28,   25,   31,   28,   59,   31,    0,    0,   57,
+    0,    0,    0,   74,   55,   53,    0,   54,    0,   56,
+    0,    0,    0,   51,   52,    0,    0,   43,    6,    7,
+    8,    0,   45,    0,   46,    0,   23,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,   43,   43,   43,   43,
+   43,   43,   43,   43,    0,   23,   23,   23,   23,   23,
+   23,   23,   23,   16,    0,    0,   58,    0,    0,    0,
+    0,    0,    0,    0,    0,   17,    0,    0,    0,    0,
+    0,    0,   16,   16,   16,   16,   16,   16,   16,   16,
+   30,    0,    0,    0,   17,   17,   17,   17,   17,   17,
+   17,   17,   18,    0,    0,    0,    0,    0,    0,   30,
+   30,   19,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,   18,   18,   18,   18,   18,   18,   18,   18,    0,
+   19,   19,   19,   19,   19,   19,   19,   19,   14,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+   15,    0,    0,    0,    0,    0,    0,   14,   14,   14,
+   14,   14,   14,   14,   14,   20,    0,    0,    0,   15,
+   15,   15,   15,   15,   15,   15,   15,   21,    0,    0,
+    0,    0,    0,    0,   20,   20,   20,   20,   20,   20,
+   20,   20,   24,    0,    0,    0,   21,   21,   21,   21,
+   21,   21,   21,   21,   29,    0,    0,    0,   26,    0,
+    0,   24,   24,   27,    0,   25,    0,   28,    0,   31,
+    0,    0,    0,   29,   29,    0,    0,   26,   26,    0,
+    0,    0,   27,   27,   25,   25,   28,   28,   31,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,   43,   44,
+   47,   48,   49,   50,   51,   52,   59,    0,    0,    0,
+   57,    0,    0,    0,   92,   55,   53,   59,   54,    0,
+   56,   57,    0,    0,    0,    0,   55,   53,   93,   54,
+    0,   56,    0,   45,    0,   46,    0,    0,    0,   59,
+    0,    0,    0,   57,   45,    0,   46,   94,   55,   53,
+   59,   54,    0,   56,   57,    0,    0,    0,    0,   55,
+   53,   97,   54,    0,   56,    0,   45,   58,   46,    0,
+    0,    0,   59,    0,    0,    0,   57,   45,   58,   46,
+  100,   55,   53,   59,   54,    0,   56,   57,    0,    0,
+    0,  101,   55,   53,   59,   54,    0,   56,   57,   45,
+   58,   46,    0,   55,   53,  102,   54,    0,   56,    0,
+   45,   58,   46,    0,    0,    0,   59,    0,    0,    0,
+   57,   45,    0,   46,    0,   55,   53,  103,   54,    0,
+   56,    0,    0,   58,    0,    0,    0,    0,   59,    0,
+    0,    0,   57,   45,   58,   46,  104,   55,   53,   59,
+   54,    0,   56,   57,    0,   58,    0,  111,   55,   53,
+   59,   54,    0,   56,   57,   45,    0,   46,  112,   55,
+   53,   59,   54,    0,   56,   57,   45,   58,   46,    0,
+   55,   53,  113,   54,    0,   56,    0,   45,    0,   46,
+    0,    0,    0,    0,    0,    0,    0,   59,   45,   58,
+   46,   57,    0,    0,    0,  114,   55,   53,   59,   54,
+   58,   56,   57,    0,    0,    0,  116,   55,   53,   59,
+   54,   58,   56,   57,   45,    0,   46,    0,   55,   53,
+   59,   54,   58,   56,   57,   45,    0,   46,    0,   55,
+   53,    0,   54,    0,   56,    0,   45,    0,   46,   43,
+   44,   47,   48,   49,   50,   51,   52,   45,   58,   46,
+   43,   44,   47,   48,   49,   50,   51,   52,    0,   58,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+   58,    0,   43,   44,   47,   48,   49,   50,   51,   52,
+    0,   58,    0,   43,   44,   47,   48,   49,   50,   51,
+   52,   20,    0,    0,    0,    0,   19,    0,    0,    0,
+    0,    0,    0,    0,    0,   43,   44,   47,   48,   49,
+   50,   51,   52,    0,    0,    0,   43,   44,   47,   48,
+   49,   50,   51,   52,    0,    0,    0,   43,   44,   47,
+   48,   49,   50,   51,   52,   20,    0,    0,    0,    0,
+   19,    0,    0,    0,    0,    0,    0,    0,    0,   43,
+   44,   47,   48,   49,   50,   51,   52,   20,    0,    0,
+    0,    0,   19,    0,    0,    0,    0,    0,    0,    0,
+    0,   43,   44,   47,   48,   49,   50,   51,   52,    0,
+    0,    0,   43,   44,   47,   48,   49,   50,   51,   52,
+    0,    0,    0,   43,   44,   47,   48,   49,   50,   51,
+   52,    0,    0,    0,   43,   44,   47,   48,   49,   50,
+   51,   52,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+   43,   44,   47,   48,   49,   50,   51,   52,    0,    0,
+    0,   43,   44,   47,   48,   49,   50,   51,   52,    0,
+    0,    0,   43,   44,   47,   48,   49,   50,   51,   52,
+    0,    0,    0,    0,   44,   47,   48,   49,   50,   51,
+   52,   59,    0,    0,    0,   57,    0,    0,    0,    0,
+   55,   53,    0,   54,    0,   56,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,   45,    0,
+   46,    0,    0,    0,    0,    0,    0,    1,    0,    0,
+    2,    3,    4,    5,    6,    7,    8,    9,   10,   11,
+   12,   13,   14,   15,   16,   17,   18,    0,    0,    0,
+    0,    0,   58,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    2,    3,    4,    5,    6,    7,
+    8,    9,   10,   11,   12,   13,   14,   15,   16,   17,
+   18,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    6,    7,    8,    9,   10,   11,   12,   13,   14,   15,
+   16,   17,   38,   39,   40,    0,    0,    0,    0,    0,
+   60,   61,   62,   63,   65,   66,   68,   69,   70,   71,
+   72,   73,    0,    0,    0,    0,    0,   76,   77,   78,
+   79,   80,   81,   82,   83,   84,   85,   86,   87,   88,
+   89,   90,   91,    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,    0,
+    0,    0,    0,    0,    0,    0,    0,  105,    0,    0,
+  106,  107,    0,  108,    0,    0,  109,  110,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,  115,    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,    0,    0,   47,   48,   49,   50,
+   51,   52,
+};
+static const YYINT yycheck[] = {                        257,
+    0,    0,    0,    0,   33,   33,   61,   41,   37,    0,
+   44,   33,  257,   42,   43,   37,   45,   40,   47,   40,
+   42,   43,   40,   45,   41,   47,   33,   44,   41,   41,
+   37,   44,   44,   33,   40,   42,    0,   37,   41,  257,
+   47,   44,   42,   43,   40,   45,   37,   47,    0,    0,
+   41,   42,   43,   44,   45,   41,   47,   40,   44,   40,
+   60,   40,   62,    0,   40,   94,   94,   40,   40,   60,
+    0,   62,   94,   37,   23,    0,   -1,   41,   42,   43,
+   44,   45,   -1,   47,    0,   37,   -1,   94,   -1,   41,
+   42,   43,   44,   45,   94,   47,   60,   -1,   62,   -1,
+   -1,   -1,   -1,   -1,   41,   -1,   -1,   44,   60,   -1,
+   62,    0,   37,   -1,   -1,   -1,   41,   42,   43,   44,
+   45,   37,   47,    0,   -1,   41,   42,   43,   44,   45,
+   -1,   47,   -1,   -1,   -1,   60,   -1,   62,    0,   -1,
+   -1,   -1,   -1,   -1,   60,   -1,   62,   -1,   -1,   -1,
+    0,   -1,   41,   -1,   43,   44,   45,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   41,    0,   43,   44,   45,   -1,
+   -1,   60,   -1,   62,   -1,   -1,   -1,    0,   -1,   41,
+   -1,    0,   44,   60,   -1,   62,    0,   -1,    0,   -1,
+    0,   41,    0,   -1,   44,   -1,   -1,   -1,   60,   -1,
+   62,   -1,   -1,   -1,   -1,   -1,   41,   -1,   -1,   44,
+   60,   -1,   62,   -1,   -1,   -1,   -1,   -1,   41,   -1,
+   -1,   44,   41,   -1,   -1,   44,   -1,   41,   -1,   41,
+   44,   41,   44,   41,   44,   33,   44,   -1,   -1,   37,
+   -1,   -1,   -1,   41,   42,   43,   -1,   45,   -1,   47,
+   -1,   -1,   -1,  282,  283,   -1,   -1,  257,  257,  257,
+  257,   -1,   60,   -1,   62,   -1,  257,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,  276,  277,  278,  279,
+  280,  281,  282,  283,   -1,  276,  277,  278,  279,  280,
+  281,  282,  283,  257,   -1,   -1,   94,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,  257,   -1,   -1,   -1,   -1,
+   -1,   -1,  276,  277,  278,  279,  280,  281,  282,  283,
+  257,   -1,   -1,   -1,  276,  277,  278,  279,  280,  281,
+  282,  283,  257,   -1,   -1,   -1,   -1,   -1,   -1,  276,
+  277,  257,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,  276,  277,  278,  279,  280,  281,  282,  283,   -1,
+  276,  277,  278,  279,  280,  281,  282,  283,  257,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+  257,   -1,   -1,   -1,   -1,   -1,   -1,  276,  277,  278,
+  279,  280,  281,  282,  283,  257,   -1,   -1,   -1,  276,
+  277,  278,  279,  280,  281,  282,  283,  257,   -1,   -1,
+   -1,   -1,   -1,   -1,  276,  277,  278,  279,  280,  281,
+  282,  283,  257,   -1,   -1,   -1,  276,  277,  278,  279,
+  280,  281,  282,  283,  257,   -1,   -1,   -1,  257,   -1,
+   -1,  276,  277,  257,   -1,  257,   -1,  257,   -1,  257,
+   -1,   -1,   -1,  276,  277,   -1,   -1,  276,  277,   -1,
+   -1,   -1,  276,  277,  276,  277,  276,  277,  276,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,  276,  277,
+  278,  279,  280,  281,  282,  283,   33,   -1,   -1,   -1,
+   37,   -1,   -1,   -1,   41,   42,   43,   33,   45,   -1,
+   47,   37,   -1,   -1,   -1,   -1,   42,   43,   44,   45,
+   -1,   47,   -1,   60,   -1,   62,   -1,   -1,   -1,   33,
+   -1,   -1,   -1,   37,   60,   -1,   62,   41,   42,   43,
+   33,   45,   -1,   47,   37,   -1,   -1,   -1,   -1,   42,
+   43,   44,   45,   -1,   47,   -1,   60,   94,   62,   -1,
+   -1,   -1,   33,   -1,   -1,   -1,   37,   60,   94,   62,
+   41,   42,   43,   33,   45,   -1,   47,   37,   -1,   -1,
+   -1,   41,   42,   43,   33,   45,   -1,   47,   37,   60,
+   94,   62,   -1,   42,   43,   44,   45,   -1,   47,   -1,
+   60,   94,   62,   -1,   -1,   -1,   33,   -1,   -1,   -1,
+   37,   60,   -1,   62,   -1,   42,   43,   44,   45,   -1,
+   47,   -1,   -1,   94,   -1,   -1,   -1,   -1,   33,   -1,
+   -1,   -1,   37,   60,   94,   62,   41,   42,   43,   33,
+   45,   -1,   47,   37,   -1,   94,   -1,   41,   42,   43,
+   33,   45,   -1,   47,   37,   60,   -1,   62,   41,   42,
+   43,   33,   45,   -1,   47,   37,   60,   94,   62,   -1,
+   42,   43,   44,   45,   -1,   47,   -1,   60,   -1,   62,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   33,   60,   94,
+   62,   37,   -1,   -1,   -1,   41,   42,   43,   33,   45,
+   94,   47,   37,   -1,   -1,   -1,   41,   42,   43,   33,
+   45,   94,   47,   37,   60,   -1,   62,   -1,   42,   43,
+   33,   45,   94,   47,   37,   60,   -1,   62,   -1,   42,
+   43,   -1,   45,   -1,   47,   -1,   60,   -1,   62,  276,
+  277,  278,  279,  280,  281,  282,  283,   60,   94,   62,
+  276,  277,  278,  279,  280,  281,  282,  283,   -1,   94,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   94,   -1,  276,  277,  278,  279,  280,  281,  282,  283,
+   -1,   94,   -1,  276,  277,  278,  279,  280,  281,  282,
+  283,   40,   -1,   -1,   -1,   -1,   45,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,  276,  277,  278,  279,  280,
+  281,  282,  283,   -1,   -1,   -1,  276,  277,  278,  279,
+  280,  281,  282,  283,   -1,   -1,   -1,  276,  277,  278,
+  279,  280,  281,  282,  283,   40,   -1,   -1,   -1,   -1,
+   45,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,  276,
+  277,  278,  279,  280,  281,  282,  283,   40,   -1,   -1,
+   -1,   -1,   45,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,  276,  277,  278,  279,  280,  281,  282,  283,   -1,
+   -1,   -1,  276,  277,  278,  279,  280,  281,  282,  283,
+   -1,   -1,   -1,  276,  277,  278,  279,  280,  281,  282,
+  283,   -1,   -1,   -1,  276,  277,  278,  279,  280,  281,
+  282,  283,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+  276,  277,  278,  279,  280,  281,  282,  283,   -1,   -1,
+   -1,  276,  277,  278,  279,  280,  281,  282,  283,   -1,
+   -1,   -1,  276,  277,  278,  279,  280,  281,  282,  283,
+   -1,   -1,   -1,   -1,  277,  278,  279,  280,  281,  282,
+  283,   33,   -1,   -1,   -1,   37,   -1,   -1,   -1,   -1,
+   42,   43,   -1,   45,   -1,   47,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   60,   -1,
+   62,   -1,   -1,   -1,   -1,   -1,   -1,  256,   -1,   -1,
+  259,  260,  261,  262,  263,  264,  265,  266,  267,  268,
+  269,  270,  271,  272,  273,  274,  275,   -1,   -1,   -1,
+   -1,   -1,   94,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,  259,  260,  261,  262,  263,  264,
+  265,  266,  267,  268,  269,  270,  271,  272,  273,  274,
+  275,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+  263,  264,  265,  266,  267,  268,  269,  270,  271,  272,
+  273,  274,  275,   19,   20,   -1,   -1,   -1,   -1,   -1,
+   26,   27,   28,   29,   30,   31,   32,   33,   34,   35,
+   36,   37,   -1,   -1,   -1,   -1,   -1,   43,   44,   45,
+   46,   47,   48,   49,   50,   51,   52,   53,   54,   55,
+   56,   57,   58,   -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,   -1,   93,   -1,   -1,
+   96,   97,   -1,   99,   -1,   -1,  102,  103,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,  113,   -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,  278,  279,  280,  281,
+  282,  283,
+};
+#define YYFINAL 21
+#ifndef YYDEBUG
+#define YYDEBUG 0
+#endif
+#define YYMAXTOKEN 284
+#define YYUNDFTOKEN 292
+#define YYTRANSLATE(a) ((a) > YYMAXTOKEN ? YYUNDFTOKEN : (a))
+#if YYDEBUG
+static const char *const yyname[] = {
+
+"end-of-file",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,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,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,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,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,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,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,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,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,0,0,0,0,0,0,0,0,0,"EOS","BAD","HELP","HEX","DECIMAL","QUIT","ABS","BIN","FIB",
+"GCD","KRON","LCM","LUCNUM","NEXTPRIME","POWM","ROOT","SQRT","NUMBER",
+"VARIABLE","LOR","LAND","EQ","NE","LE","GE","LSHIFT","RSHIFT","UMINUS",0,0,0,0,
+0,0,0,"illegal-symbol",
+};
+static const char *const yyrule[] = {
+"$accept : top",
+"top : statement",
+"top : statements statement",
+"statements : statement EOS",
+"statements : statements statement EOS",
+"statements : error EOS",
+"statement :",
+"statement : e",
+"statement : VARIABLE '=' e",
+"statement : HELP",
+"statement : HEX",
+"statement : DECIMAL",
+"statement : QUIT",
+"e : '(' e ')'",
+"e : e '+' e",
+"e : e '-' e",
+"e : e '*' e",
+"e : e '/' e",
+"e : e '%' e",
+"e : e '^' e",
+"e : e LSHIFT e",
+"e : e RSHIFT e",
+"e : e '!'",
+"e : '-' e",
+"e : e '<' e",
+"e : e LE e",
+"e : e EQ e",
+"e : e NE e",
+"e : e GE e",
+"e : e '>' e",
+"e : e LAND e",
+"e : e LOR e",
+"e : ABS '(' e ')'",
+"e : BIN '(' e ',' e ')'",
+"e : FIB '(' e ')'",
+"e : GCD '(' gcdlist ')'",
+"e : KRON '(' e ',' e ')'",
+"e : LCM '(' lcmlist ')'",
+"e : LUCNUM '(' e ')'",
+"e : NEXTPRIME '(' e ')'",
+"e : POWM '(' e ',' e ',' e ')'",
+"e : ROOT '(' e ',' e ')'",
+"e : SQRT '(' e ')'",
+"e : VARIABLE",
+"e : NUMBER",
+"gcdlist : e",
+"gcdlist : gcdlist ',' e",
+"lcmlist : e",
+"lcmlist : lcmlist ',' e",
+
+};
+#endif
+
+int      yydebug;
+int      yynerrs;
+
+int      yyerrflag;
+int      yychar;
+YYSTYPE  yyval;
+YYSTYPE  yylval;
+
+/* define the initial stack-sizes */
+#ifdef YYSTACKSIZE
+#undef YYMAXDEPTH
+#define YYMAXDEPTH  YYSTACKSIZE
+#else
+#ifdef YYMAXDEPTH
+#define YYSTACKSIZE YYMAXDEPTH
+#else
+#define YYSTACKSIZE 10000
+#define YYMAXDEPTH  10000
+#endif
+#endif
+
+#define YYINITSTACKSIZE 200
+
+typedef struct {
+    unsigned stacksize;
+    YYINT    *s_base;
+    YYINT    *s_mark;
+    YYINT    *s_last;
+    YYSTYPE  *l_base;
+    YYSTYPE  *l_mark;
+} YYSTACKDATA;
+/* variables for the parser stack */
+static YYSTACKDATA yystack;
+#line 265 "../../../gmp/demos/calc/calc.y"
+
+yyerror (char *s)
+{
+  fprintf (stderr, "%s\n", s);
+}
+
+int calc_option_readline = -1;
+
+int
+main (int argc, char *argv[])
+{
+  int  i;
+
+  for (i = 1; i < argc; i++)
+    {
+      if (strcmp (argv[i], "--readline") == 0)
+        calc_option_readline = 1;
+      else if (strcmp (argv[i], "--noreadline") == 0)
+        calc_option_readline = 0;
+      else if (strcmp (argv[i], "--help") == 0)
+        {
+          printf ("Usage: calc [--option]...\n");
+          printf ("  --readline    use readline\n");
+          printf ("  --noreadline  don't use readline\n");
+          printf ("  --help        this message\n");
+          printf ("Readline is only available when compiled in,\n");
+          printf ("and in that case it's the default on a tty.\n");
+          exit (0);
+        }
+      else
+        {
+          fprintf (stderr, "Unrecognised option: %s\n", argv[i]);
+          exit (1);
+        }
+    }
+
+#if WITH_READLINE
+  calc_init_readline ();
+#else
+  if (calc_option_readline == 1)
+    {
+      fprintf (stderr, "Readline support not available\n");
+      exit (1);
+    }
+#endif
+
+  for (i = 0; i < numberof (variable); i++)
+    mpz_init (variable[i]);
+
+  for (i = 0; i < numberof (stack); i++)
+    mpz_init (stack[i]);
+
+  return yyparse ();
+}
+#line 710 "calc.c"
+
+#if YYDEBUG
+#include <stdio.h>	/* needed for printf */
+#endif
+
+#include <stdlib.h>	/* needed for malloc, etc */
+#include <string.h>	/* needed for memset */
+
+/* allocate initial stack or double stack size, up to YYMAXDEPTH */
+static int yygrowstack(YYSTACKDATA *data)
+{
+    int i;
+    unsigned newsize;
+    YYINT *newss;
+    YYSTYPE *newvs;
+
+    if ((newsize = data->stacksize) == 0)
+        newsize = YYINITSTACKSIZE;
+    else if (newsize >= YYMAXDEPTH)
+        return YYENOMEM;
+    else if ((newsize *= 2) > YYMAXDEPTH)
+        newsize = YYMAXDEPTH;
+
+    i = (int) (data->s_mark - data->s_base);
+    newss = (YYINT *)realloc(data->s_base, newsize * sizeof(*newss));
+    if (newss == 0)
+        return YYENOMEM;
+
+    data->s_base = newss;
+    data->s_mark = newss + i;
+
+    newvs = (YYSTYPE *)realloc(data->l_base, newsize * sizeof(*newvs));
+    if (newvs == 0)
+        return YYENOMEM;
+
+    data->l_base = newvs;
+    data->l_mark = newvs + i;
+
+    data->stacksize = newsize;
+    data->s_last = data->s_base + newsize - 1;
+    return 0;
+}
+
+#if YYPURE || defined(YY_NO_LEAKS)
+static void yyfreestack(YYSTACKDATA *data)
+{
+    free(data->s_base);
+    free(data->l_base);
+    memset(data, 0, sizeof(*data));
+}
+#else
+#define yyfreestack(data) /* nothing */
+#endif
+
+#define YYABORT  goto yyabort
+#define YYREJECT goto yyabort
+#define YYACCEPT goto yyaccept
+#define YYERROR  goto yyerrlab
+
+int
+YYPARSE_DECL()
+{
+    int yym, yyn, yystate;
+#if YYDEBUG
+    const char *yys;
+
+    if ((yys = getenv("YYDEBUG")) != 0)
+    {
+        yyn = *yys;
+        if (yyn >= '0' && yyn <= '9')
+            yydebug = yyn - '0';
+    }
+#endif
+
+    yym = 0;
+    yyn = 0;
+    yynerrs = 0;
+    yyerrflag = 0;
+    yychar = YYEMPTY;
+    yystate = 0;
+
+#if YYPURE
+    memset(&yystack, 0, sizeof(yystack));
+#endif
+
+    if (yystack.s_base == NULL && yygrowstack(&yystack) == YYENOMEM) goto yyoverflow;
+    yystack.s_mark = yystack.s_base;
+    yystack.l_mark = yystack.l_base;
+    yystate = 0;
+    *yystack.s_mark = 0;
+
+yyloop:
+    if ((yyn = yydefred[yystate]) != 0) goto yyreduce;
+    if (yychar < 0)
+    {
+        yychar = YYLEX;
+        if (yychar < 0) yychar = YYEOF;
+#if YYDEBUG
+        if (yydebug)
+        {
+            if ((yys = yyname[YYTRANSLATE(yychar)]) == NULL) yys = yyname[YYUNDFTOKEN];
+            printf("%sdebug: state %d, reading %d (%s)\n",
+                    YYPREFIX, yystate, yychar, yys);
+        }
+#endif
+    }
+    if (((yyn = yysindex[yystate]) != 0) && (yyn += yychar) >= 0 &&
+            yyn <= YYTABLESIZE && yycheck[yyn] == (YYINT) yychar)
+    {
+#if YYDEBUG
+        if (yydebug)
+            printf("%sdebug: state %d, shifting to state %d\n",
+                    YYPREFIX, yystate, yytable[yyn]);
+#endif
+        if (yystack.s_mark >= yystack.s_last && yygrowstack(&yystack) == YYENOMEM) goto yyoverflow;
+        yystate = yytable[yyn];
+        *++yystack.s_mark = yytable[yyn];
+        *++yystack.l_mark = yylval;
+        yychar = YYEMPTY;
+        if (yyerrflag > 0)  --yyerrflag;
+        goto yyloop;
+    }
+    if (((yyn = yyrindex[yystate]) != 0) && (yyn += yychar) >= 0 &&
+            yyn <= YYTABLESIZE && yycheck[yyn] == (YYINT) yychar)
+    {
+        yyn = yytable[yyn];
+        goto yyreduce;
+    }
+    if (yyerrflag != 0) goto yyinrecovery;
+
+    YYERROR_CALL("syntax error");
+
+    goto yyerrlab; /* redundant goto avoids 'unused label' warning */
+yyerrlab:
+    ++yynerrs;
+
+yyinrecovery:
+    if (yyerrflag < 3)
+    {
+        yyerrflag = 3;
+        for (;;)
+        {
+            if (((yyn = yysindex[*yystack.s_mark]) != 0) && (yyn += YYERRCODE) >= 0 &&
+                    yyn <= YYTABLESIZE && yycheck[yyn] == (YYINT) YYERRCODE)
+            {
+#if YYDEBUG
+                if (yydebug)
+                    printf("%sdebug: state %d, error recovery shifting\
+ to state %d\n", YYPREFIX, *yystack.s_mark, yytable[yyn]);
+#endif
+                if (yystack.s_mark >= yystack.s_last && yygrowstack(&yystack) == YYENOMEM) goto yyoverflow;
+                yystate = yytable[yyn];
+                *++yystack.s_mark = yytable[yyn];
+                *++yystack.l_mark = yylval;
+                goto yyloop;
+            }
+            else
+            {
+#if YYDEBUG
+                if (yydebug)
+                    printf("%sdebug: error recovery discarding state %d\n",
+                            YYPREFIX, *yystack.s_mark);
+#endif
+                if (yystack.s_mark <= yystack.s_base) goto yyabort;
+                --yystack.s_mark;
+                --yystack.l_mark;
+            }
+        }
+    }
+    else
+    {
+        if (yychar == YYEOF) goto yyabort;
+#if YYDEBUG
+        if (yydebug)
+        {
+            if ((yys = yyname[YYTRANSLATE(yychar)]) == NULL) yys = yyname[YYUNDFTOKEN];
+            printf("%sdebug: state %d, error recovery discards token %d (%s)\n",
+                    YYPREFIX, yystate, yychar, yys);
+        }
+#endif
+        yychar = YYEMPTY;
+        goto yyloop;
+    }
+
+yyreduce:
+#if YYDEBUG
+    if (yydebug)
+        printf("%sdebug: state %d, reducing by rule %d (%s)\n",
+                YYPREFIX, yystate, yyn, yyrule[yyn]);
+#endif
+    yym = yylen[yyn];
+    if (yym > 0)
+        yyval = yystack.l_mark[1-yym];
+    else
+        memset(&yyval, 0, sizeof yyval);
+
+    switch (yyn)
+    {
+case 5:
+#line 173 "../../../gmp/demos/calc/calc.y"
+	{ sp = stack[0]; yyerrok; }
+break;
+case 7:
+#line 177 "../../../gmp/demos/calc/calc.y"
+	{
+      mpz_out_str (stdout, obase, sp); putchar ('\n');
+      sp--;
+      CHECK_EMPTY ();
+    }
+break;
+case 8:
+#line 182 "../../../gmp/demos/calc/calc.y"
+	{
+      CHECK_VARIABLE (yystack.l_mark[-2].var);
+      mpz_swap (variable[yystack.l_mark[-2].var], sp);
+      sp--;
+      CHECK_EMPTY ();
+    }
+break;
+case 9:
+#line 188 "../../../gmp/demos/calc/calc.y"
+	{ calc_help (); }
+break;
+case 10:
+#line 189 "../../../gmp/demos/calc/calc.y"
+	{ ibase = 16; obase = -16; }
+break;
+case 11:
+#line 190 "../../../gmp/demos/calc/calc.y"
+	{ ibase = 0;  obase = 10; }
+break;
+case 12:
+#line 191 "../../../gmp/demos/calc/calc.y"
+	{ exit (0); }
+break;
+case 14:
+#line 198 "../../../gmp/demos/calc/calc.y"
+	{ sp--; mpz_add    (sp, sp, sp+1); }
+break;
+case 15:
+#line 199 "../../../gmp/demos/calc/calc.y"
+	{ sp--; mpz_sub    (sp, sp, sp+1); }
+break;
+case 16:
+#line 200 "../../../gmp/demos/calc/calc.y"
+	{ sp--; mpz_mul    (sp, sp, sp+1); }
+break;
+case 17:
+#line 201 "../../../gmp/demos/calc/calc.y"
+	{ sp--; mpz_fdiv_q (sp, sp, sp+1); }
+break;
+case 18:
+#line 202 "../../../gmp/demos/calc/calc.y"
+	{ sp--; mpz_fdiv_r (sp, sp, sp+1); }
+break;
+case 19:
+#line 203 "../../../gmp/demos/calc/calc.y"
+	{ CHECK_UI ("Exponent", sp);
+                    sp--; mpz_pow_ui (sp, sp, mpz_get_ui (sp+1)); }
+break;
+case 20:
+#line 205 "../../../gmp/demos/calc/calc.y"
+	{ CHECK_UI ("Shift count", sp);
+                    sp--; mpz_mul_2exp (sp, sp, mpz_get_ui (sp+1)); }
+break;
+case 21:
+#line 207 "../../../gmp/demos/calc/calc.y"
+	{ CHECK_UI ("Shift count", sp);
+                    sp--; mpz_fdiv_q_2exp (sp, sp, mpz_get_ui (sp+1)); }
+break;
+case 22:
+#line 209 "../../../gmp/demos/calc/calc.y"
+	{ CHECK_UI ("Factorial", sp);
+                    mpz_fac_ui (sp, mpz_get_ui (sp)); }
+break;
+case 23:
+#line 211 "../../../gmp/demos/calc/calc.y"
+	{ mpz_neg (sp, sp); }
+break;
+case 24:
+#line 213 "../../../gmp/demos/calc/calc.y"
+	{ sp--; mpz_set_ui (sp, mpz_cmp (sp, sp+1) <  0); }
+break;
+case 25:
+#line 214 "../../../gmp/demos/calc/calc.y"
+	{ sp--; mpz_set_ui (sp, mpz_cmp (sp, sp+1) <= 0); }
+break;
+case 26:
+#line 215 "../../../gmp/demos/calc/calc.y"
+	{ sp--; mpz_set_ui (sp, mpz_cmp (sp, sp+1) == 0); }
+break;
+case 27:
+#line 216 "../../../gmp/demos/calc/calc.y"
+	{ sp--; mpz_set_ui (sp, mpz_cmp (sp, sp+1) != 0); }
+break;
+case 28:
+#line 217 "../../../gmp/demos/calc/calc.y"
+	{ sp--; mpz_set_ui (sp, mpz_cmp (sp, sp+1) >= 0); }
+break;
+case 29:
+#line 218 "../../../gmp/demos/calc/calc.y"
+	{ sp--; mpz_set_ui (sp, mpz_cmp (sp, sp+1) >  0); }
+break;
+case 30:
+#line 220 "../../../gmp/demos/calc/calc.y"
+	{ sp--; mpz_set_ui (sp, mpz_sgn (sp) && mpz_sgn (sp+1)); }
+break;
+case 31:
+#line 221 "../../../gmp/demos/calc/calc.y"
+	{ sp--; mpz_set_ui (sp, mpz_sgn (sp) || mpz_sgn (sp+1)); }
+break;
+case 32:
+#line 223 "../../../gmp/demos/calc/calc.y"
+	{ mpz_abs (sp, sp); }
+break;
+case 33:
+#line 224 "../../../gmp/demos/calc/calc.y"
+	{ sp--; CHECK_UI ("Binomial base", sp+1);
+                                   mpz_bin_ui (sp, sp, mpz_get_ui (sp+1)); }
+break;
+case 34:
+#line 226 "../../../gmp/demos/calc/calc.y"
+	{ CHECK_UI ("Fibonacci", sp);
+                                   mpz_fib_ui (sp, mpz_get_ui (sp)); }
+break;
+case 36:
+#line 229 "../../../gmp/demos/calc/calc.y"
+	{ sp--; mpz_set_si (sp,
+                                         mpz_kronecker (sp, sp+1)); }
+break;
+case 38:
+#line 232 "../../../gmp/demos/calc/calc.y"
+	{ CHECK_UI ("Lucas number", sp);
+                                   mpz_lucnum_ui (sp, mpz_get_ui (sp)); }
+break;
+case 39:
+#line 234 "../../../gmp/demos/calc/calc.y"
+	{ mpz_nextprime (sp, sp); }
+break;
+case 40:
+#line 235 "../../../gmp/demos/calc/calc.y"
+	{ sp -= 2; mpz_powm (sp, sp, sp+1, sp+2); }
+break;
+case 41:
+#line 236 "../../../gmp/demos/calc/calc.y"
+	{ sp--; CHECK_UI ("Nth-root", sp+1);
+                                   mpz_root (sp, sp, mpz_get_ui (sp+1)); }
+break;
+case 42:
+#line 238 "../../../gmp/demos/calc/calc.y"
+	{ mpz_sqrt (sp, sp); }
+break;
+case 43:
+#line 240 "../../../gmp/demos/calc/calc.y"
+	{
+        sp++;
+        CHECK_OVERFLOW ();
+        CHECK_VARIABLE (yystack.l_mark[0].var);
+        mpz_set (sp, variable[yystack.l_mark[0].var]);
+      }
+break;
+case 44:
+#line 246 "../../../gmp/demos/calc/calc.y"
+	{
+        sp++;
+        CHECK_OVERFLOW ();
+        if (mpz_set_str (sp, yystack.l_mark[0].str, ibase) != 0)
+          {
+            fprintf (stderr, "Invalid number: %s\n", yystack.l_mark[0].str);
+            YYERROR;
+          }
+      }
+break;
+case 46:
+#line 258 "../../../gmp/demos/calc/calc.y"
+	{ sp--; mpz_gcd (sp, sp, sp+1); }
+break;
+case 48:
+#line 262 "../../../gmp/demos/calc/calc.y"
+	{ sp--; mpz_lcm (sp, sp, sp+1); }
+break;
+#line 1092 "calc.c"
+    }
+    yystack.s_mark -= yym;
+    yystate = *yystack.s_mark;
+    yystack.l_mark -= yym;
+    yym = yylhs[yyn];
+    if (yystate == 0 && yym == 0)
+    {
+#if YYDEBUG
+        if (yydebug)
+            printf("%sdebug: after reduction, shifting from state 0 to\
+ state %d\n", YYPREFIX, YYFINAL);
+#endif
+        yystate = YYFINAL;
+        *++yystack.s_mark = YYFINAL;
+        *++yystack.l_mark = yyval;
+        if (yychar < 0)
+        {
+            yychar = YYLEX;
+            if (yychar < 0) yychar = YYEOF;
+#if YYDEBUG
+            if (yydebug)
+            {
+                if ((yys = yyname[YYTRANSLATE(yychar)]) == NULL) yys = yyname[YYUNDFTOKEN];
+                printf("%sdebug: state %d, reading %d (%s)\n",
+                        YYPREFIX, YYFINAL, yychar, yys);
+            }
+#endif
+        }
+        if (yychar == YYEOF) goto yyaccept;
+        goto yyloop;
+    }
+    if (((yyn = yygindex[yym]) != 0) && (yyn += yystate) >= 0 &&
+            yyn <= YYTABLESIZE && yycheck[yyn] == (YYINT) yystate)
+        yystate = yytable[yyn];
+    else
+        yystate = yydgoto[yym];
+#if YYDEBUG
+    if (yydebug)
+        printf("%sdebug: after reduction, shifting from state %d \
+to state %d\n", YYPREFIX, *yystack.s_mark, yystate);
+#endif
+    if (yystack.s_mark >= yystack.s_last && yygrowstack(&yystack) == YYENOMEM) goto yyoverflow;
+    *++yystack.s_mark = (YYINT) yystate;
+    *++yystack.l_mark = yyval;
+    goto yyloop;
+
+yyoverflow:
+    YYERROR_CALL("yacc stack overflow");
+
+yyabort:
+    yyfreestack(&yystack);
+    return (1);
+
+yyaccept:
+    yyfreestack(&yystack);
+    return (0);
+}
diff --git a/third_party/gmp/demos/calc/calc.h b/third_party/gmp/demos/calc/calc.h
new file mode 100644
index 0000000..8c48e2a
--- /dev/null
+++ b/third_party/gmp/demos/calc/calc.h
@@ -0,0 +1,40 @@
+#define EOS 257
+#define BAD 258
+#define HELP 259
+#define HEX 260
+#define DECIMAL 261
+#define QUIT 262
+#define ABS 263
+#define BIN 264
+#define FIB 265
+#define GCD 266
+#define KRON 267
+#define LCM 268
+#define LUCNUM 269
+#define NEXTPRIME 270
+#define POWM 271
+#define ROOT 272
+#define SQRT 273
+#define NUMBER 274
+#define VARIABLE 275
+#define LOR 276
+#define LAND 277
+#define EQ 278
+#define NE 279
+#define LE 280
+#define GE 281
+#define LSHIFT 282
+#define RSHIFT 283
+#define UMINUS 284
+#ifdef YYSTYPE
+#undef  YYSTYPE_IS_DECLARED
+#define YYSTYPE_IS_DECLARED 1
+#endif
+#ifndef YYSTYPE_IS_DECLARED
+#define YYSTYPE_IS_DECLARED 1
+typedef union {
+  char  *str;
+  int   var;
+} YYSTYPE;
+#endif /* !YYSTYPE_IS_DECLARED */
+extern YYSTYPE yylval;
diff --git a/third_party/gmp/demos/calc/calc.y b/third_party/gmp/demos/calc/calc.y
new file mode 100644
index 0000000..0fa1206
--- /dev/null
+++ b/third_party/gmp/demos/calc/calc.y
@@ -0,0 +1,318 @@
+%{
+/* A simple integer desk calculator using yacc and gmp.
+
+Copyright 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 3 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program.  If not, see https://www.gnu.org/licenses/.  */
+
+
+/* This is a simple program, meant only to show one way to use GMP for this
+   sort of thing.  There's few features, and error checking is minimal.
+   Standard input is read, calc_help() below shows the inputs accepted.
+
+   Expressions are evaluated as they're read.  If user defined functions
+   were wanted it'd be necessary to build a parse tree like pexpr.c does, or
+   a list of operations for a stack based evaluator.  That would also make
+   it possible to detect and optimize evaluations "mod m" like pexpr.c does.
+
+   A stack is used for intermediate values in the expression evaluation,
+   separate from the yacc parser stack.  This is simple, makes error
+   recovery easy, minimizes the junk around mpz calls in the rules, and
+   saves initializing or clearing "mpz_t"s during a calculation.  A
+   disadvantage though is that variables must be copied to the stack to be
+   worked on.  A more sophisticated calculator or language system might be
+   able to avoid that when executing a compiled or semi-compiled form.
+
+   Avoiding repeated initializing and clearing of "mpz_t"s is important.  In
+   this program the time spent parsing is obviously much greater than any
+   possible saving from this, but a proper calculator or language should
+   take some trouble over it.  Don't be surprised if an init/clear takes 3
+   or more times as long as a 10 limb addition, depending on the system (see
+   the mpz_init_realloc_clear example in tune/README).  */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "gmp.h"
+#define NO_CALC_H /* because it conflicts with normal calc.c stuff */
+#include "calc-common.h"
+
+
+#define numberof(x)  (sizeof (x) / sizeof ((x)[0]))
+
+
+void
+calc_help (void)
+{
+  printf ("Examples:\n");
+  printf ("    2+3*4        expressions are evaluated\n");
+  printf ("    x=5^6        variables a to z can be set and used\n");
+  printf ("Operators:\n");
+  printf ("    + - *        arithmetic\n");
+  printf ("    / %%          division and remainder (rounding towards negative infinity)\n");
+  printf ("    ^            exponentiation\n");
+  printf ("    !            factorial\n");
+  printf ("    << >>        left and right shifts\n");
+  printf ("    <= >= >      \\ comparisons, giving 1 if true, 0 if false\n");
+  printf ("    == != <      /\n");
+  printf ("    && ||        logical and/or, giving 1 if true, 0 if false\n");
+  printf ("Functions:\n");
+  printf ("    abs(n)       absolute value\n");
+  printf ("    bin(n,m)     binomial coefficient\n");
+  printf ("    fib(n)       fibonacci number\n");
+  printf ("    gcd(a,b,..)  greatest common divisor\n");
+  printf ("    kron(a,b)    kronecker symbol\n");
+  printf ("    lcm(a,b,..)  least common multiple\n");
+  printf ("    lucnum(n)    lucas number\n");
+  printf ("    nextprime(n) next prime after n\n");
+  printf ("    powm(b,e,m)  modulo powering, b^e%%m\n");
+  printf ("    root(n,r)    r-th root\n");
+  printf ("    sqrt(n)      square root\n");
+  printf ("Other:\n");
+  printf ("    hex          \\ set hex or decimal for input and output\n");
+  printf ("    decimal      /   (\"0x\" can be used for hex too)\n");
+  printf ("    quit         exit program (EOF works too)\n");
+  printf ("    ;            statements are separated with a ; or newline\n");
+  printf ("    \\            continue expressions with \\ before newline\n");
+  printf ("    # xxx        comments are # though to newline\n");
+  printf ("Hex numbers must be entered in upper case, to distinguish them from the\n");
+  printf ("variables a to f (like in bc).\n");
+}
+
+
+int  ibase = 0;
+int  obase = 10;
+
+
+/* The stack is a fixed size, which means there's a limit on the nesting
+   allowed in expressions.  A more sophisticated program could let it grow
+   dynamically.  */
+
+mpz_t    stack[100];
+mpz_ptr  sp = stack[0];
+
+#define CHECK_OVERFLOW()                                                  \
+  if (sp >= stack[numberof(stack)])	/* FIXME */			\
+    {                                                                     \
+      fprintf (stderr,                                                    \
+               "Value stack overflow, too much nesting in expression\n"); \
+      YYERROR;                                                            \
+    }
+
+#define CHECK_EMPTY()                                                   \
+  if (sp != stack[0])                                                   \
+    {                                                                   \
+      fprintf (stderr, "Oops, expected the value stack to be empty\n"); \
+      sp = stack[0];                                                    \
+    }
+
+
+mpz_t  variable[26];
+
+#define CHECK_VARIABLE(var)                                             \
+  if ((var) < 0 || (var) >= numberof (variable))                        \
+    {                                                                   \
+      fprintf (stderr, "Oops, bad variable somehow: %d\n", var);        \
+      YYERROR;                                                          \
+    }
+
+
+#define CHECK_UI(name,z)                        \
+  if (! mpz_fits_ulong_p (z))                   \
+    {                                           \
+      fprintf (stderr, "%s too big\n", name);   \
+      YYERROR;                                  \
+    }
+
+%}
+
+%union {
+  char  *str;
+  int   var;
+}
+
+%token EOS BAD
+%token HELP HEX DECIMAL QUIT
+%token ABS BIN FIB GCD KRON LCM LUCNUM NEXTPRIME POWM ROOT SQRT
+%token <str> NUMBER
+%token <var> VARIABLE
+
+/* operators, increasing precedence */
+%left     LOR
+%left     LAND
+%nonassoc '<' '>' EQ NE LE GE
+%left     LSHIFT RSHIFT
+%left     '+' '-'
+%left     '*' '/' '%'
+%nonassoc UMINUS
+%right    '^'
+%nonassoc '!'
+
+%%
+
+top:
+  statement
+  | statements statement;
+
+statements:
+  statement EOS
+  | statements statement EOS
+  | error EOS { sp = stack[0]; yyerrok; };
+
+statement:
+  /* empty */
+  | e {
+      mpz_out_str (stdout, obase, sp); putchar ('\n');
+      sp--;
+      CHECK_EMPTY ();
+    }
+  | VARIABLE '=' e {
+      CHECK_VARIABLE ($1);
+      mpz_swap (variable[$1], sp);
+      sp--;
+      CHECK_EMPTY ();
+    }
+  | HELP    { calc_help (); }
+  | HEX     { ibase = 16; obase = -16; }
+  | DECIMAL { ibase = 0;  obase = 10; }
+  | QUIT    { exit (0); };
+
+/* "e" leaves it's value on the top of the mpz stack.  A rule like "e '+' e"
+   will have done a reduction for the first "e" first and the second "e"
+   second, so the code receives the values in that order on the stack.  */
+e:
+    '(' e ')'     /* value on stack */
+    | e '+' e     { sp--; mpz_add    (sp, sp, sp+1); }
+    | e '-' e     { sp--; mpz_sub    (sp, sp, sp+1); }
+    | e '*' e     { sp--; mpz_mul    (sp, sp, sp+1); }
+    | e '/' e     { sp--; mpz_fdiv_q (sp, sp, sp+1); }
+    | e '%' e     { sp--; mpz_fdiv_r (sp, sp, sp+1); }
+    | e '^' e     { CHECK_UI ("Exponent", sp);
+                    sp--; mpz_pow_ui (sp, sp, mpz_get_ui (sp+1)); }
+    | e LSHIFT e  { CHECK_UI ("Shift count", sp);
+                    sp--; mpz_mul_2exp (sp, sp, mpz_get_ui (sp+1)); }
+    | e RSHIFT e  { CHECK_UI ("Shift count", sp);
+                    sp--; mpz_fdiv_q_2exp (sp, sp, mpz_get_ui (sp+1)); }
+    | e '!'       { CHECK_UI ("Factorial", sp);
+                    mpz_fac_ui (sp, mpz_get_ui (sp)); }
+    | '-' e %prec UMINUS   { mpz_neg (sp, sp); }
+
+    | e '<' e     { sp--; mpz_set_ui (sp, mpz_cmp (sp, sp+1) <  0); }
+    | e LE  e     { sp--; mpz_set_ui (sp, mpz_cmp (sp, sp+1) <= 0); }
+    | e EQ  e     { sp--; mpz_set_ui (sp, mpz_cmp (sp, sp+1) == 0); }
+    | e NE  e     { sp--; mpz_set_ui (sp, mpz_cmp (sp, sp+1) != 0); }
+    | e GE  e     { sp--; mpz_set_ui (sp, mpz_cmp (sp, sp+1) >= 0); }
+    | e '>' e     { sp--; mpz_set_ui (sp, mpz_cmp (sp, sp+1) >  0); }
+
+    | e LAND e    { sp--; mpz_set_ui (sp, mpz_sgn (sp) && mpz_sgn (sp+1)); }
+    | e LOR e     { sp--; mpz_set_ui (sp, mpz_sgn (sp) || mpz_sgn (sp+1)); }
+
+    | ABS '(' e ')'              { mpz_abs (sp, sp); }
+    | BIN '(' e ',' e ')'        { sp--; CHECK_UI ("Binomial base", sp+1);
+                                   mpz_bin_ui (sp, sp, mpz_get_ui (sp+1)); }
+    | FIB '(' e ')'              { CHECK_UI ("Fibonacci", sp);
+                                   mpz_fib_ui (sp, mpz_get_ui (sp)); }
+    | GCD '(' gcdlist ')'        /* value on stack */
+    | KRON '(' e ',' e ')'       { sp--; mpz_set_si (sp,
+                                         mpz_kronecker (sp, sp+1)); }
+    | LCM '(' lcmlist ')'        /* value on stack */
+    | LUCNUM '(' e ')'           { CHECK_UI ("Lucas number", sp);
+                                   mpz_lucnum_ui (sp, mpz_get_ui (sp)); }
+    | NEXTPRIME '(' e ')'        { mpz_nextprime (sp, sp); }
+    | POWM '(' e ',' e ',' e ')' { sp -= 2; mpz_powm (sp, sp, sp+1, sp+2); }
+    | ROOT '(' e ',' e ')'       { sp--; CHECK_UI ("Nth-root", sp+1);
+                                   mpz_root (sp, sp, mpz_get_ui (sp+1)); }
+    | SQRT '(' e ')'             { mpz_sqrt (sp, sp); }
+
+    | VARIABLE {
+        sp++;
+        CHECK_OVERFLOW ();
+        CHECK_VARIABLE ($1);
+        mpz_set (sp, variable[$1]);
+      }
+    | NUMBER {
+        sp++;
+        CHECK_OVERFLOW ();
+        if (mpz_set_str (sp, $1, ibase) != 0)
+          {
+            fprintf (stderr, "Invalid number: %s\n", $1);
+            YYERROR;
+          }
+      };
+
+gcdlist:
+    e                /* value on stack */
+    | gcdlist ',' e  { sp--; mpz_gcd (sp, sp, sp+1); };
+
+lcmlist:
+    e                /* value on stack */
+    | lcmlist ',' e  { sp--; mpz_lcm (sp, sp, sp+1); };
+
+%%
+
+yyerror (char *s)
+{
+  fprintf (stderr, "%s\n", s);
+}
+
+int calc_option_readline = -1;
+
+int
+main (int argc, char *argv[])
+{
+  int  i;
+
+  for (i = 1; i < argc; i++)
+    {
+      if (strcmp (argv[i], "--readline") == 0)
+        calc_option_readline = 1;
+      else if (strcmp (argv[i], "--noreadline") == 0)
+        calc_option_readline = 0;
+      else if (strcmp (argv[i], "--help") == 0)
+        {
+          printf ("Usage: calc [--option]...\n");
+          printf ("  --readline    use readline\n");
+          printf ("  --noreadline  don't use readline\n");
+          printf ("  --help        this message\n");
+          printf ("Readline is only available when compiled in,\n");
+          printf ("and in that case it's the default on a tty.\n");
+          exit (0);
+        }
+      else
+        {
+          fprintf (stderr, "Unrecognised option: %s\n", argv[i]);
+          exit (1);
+        }
+    }
+
+#if WITH_READLINE
+  calc_init_readline ();
+#else
+  if (calc_option_readline == 1)
+    {
+      fprintf (stderr, "Readline support not available\n");
+      exit (1);
+    }
+#endif
+
+  for (i = 0; i < numberof (variable); i++)
+    mpz_init (variable[i]);
+
+  for (i = 0; i < numberof (stack); i++)
+    mpz_init (stack[i]);
+
+  return yyparse ();
+}
diff --git a/third_party/gmp/demos/calc/calclex.c b/third_party/gmp/demos/calc/calclex.c
new file mode 100644
index 0000000..7884001
--- /dev/null
+++ b/third_party/gmp/demos/calc/calclex.c
@@ -0,0 +1,1933 @@
+
+#line 3 "calclex.c"
+
+#define  YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 37
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with  platform-specific or compiler-specific issues. */
+
+#if defined(__FreeBSD__)
+#ifndef __STDC_LIMIT_MACROS
+#define	__STDC_LIMIT_MACROS
+#endif
+#include <sys/cdefs.h>
+#include <stdint.h>
+#else
+#define	__dead2
+#endif
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined(__FreeBSD__) || \
+    (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types. 
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t; 
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN               (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN              (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN              (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX               (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX              (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX              (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX              (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX             (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX             (4294967295U)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else	/* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif	/* defined (__STDC__) */
+#endif	/* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index.  If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition.  This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN (yy_start) = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.  The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START (((yy_start) - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart(yyin  )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE   ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+extern yy_size_t yyleng;
+
+extern FILE *yyin, *yyout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+    #define YY_LESS_LINENO(n)
+    
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up yytext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+		*yy_cp = (yy_hold_char); \
+		YY_RESTORE_YY_MORE_OFFSET \
+		(yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+		YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+		} \
+	while ( 0 )
+
+#define unput(c) yyunput( c, (yytext_ptr)  )
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+	{
+	FILE *yy_input_file;
+
+	char *yy_ch_buf;		/* input buffer */
+	char *yy_buf_pos;		/* current position in input buffer */
+
+	/* Size of input buffer in bytes, not including room for EOB
+	 * characters.
+	 */
+	yy_size_t yy_buf_size;
+
+	/* Number of characters read into yy_ch_buf, not including EOB
+	 * characters.
+	 */
+	yy_size_t yy_n_chars;
+
+	/* Whether we "own" the buffer - i.e., we know we created it,
+	 * and can realloc() it to grow it, and should free() it to
+	 * delete it.
+	 */
+	int yy_is_our_buffer;
+
+	/* Whether this is an "interactive" input source; if so, and
+	 * if we're using stdio for input, then we want to use getc()
+	 * instead of fread(), to make sure we stop fetching input after
+	 * each newline.
+	 */
+	int yy_is_interactive;
+
+	/* Whether we're considered to be at the beginning of a line.
+	 * If so, '^' rules will be active on the next match, otherwise
+	 * not.
+	 */
+	int yy_at_bol;
+
+    int yy_bs_lineno; /**< The line count. */
+    int yy_bs_column; /**< The column count. */
+    
+	/* Whether to try to fill the input buffer when we reach the
+	 * end of it.
+	 */
+	int yy_fill_buffer;
+
+	int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+	/* When an EOF's been seen but there's still some text to process
+	 * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+	 * shouldn't try reading from the input source any more.  We might
+	 * still have a bunch of tokens to match, though, because of
+	 * possible backing-up.
+	 *
+	 * When we actually see the EOF, we change the status to "new"
+	 * (via yyrestart()), so that the user can continue scanning by
+	 * just pointing yyin at a new input file.
+	 */
+#define YY_BUFFER_EOF_PENDING 2
+
+	};
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* Stack of input buffers. */
+static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
+static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
+static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
+                          ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
+                          : NULL)
+#define yy_current_buffer YY_CURRENT_BUFFER
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
+
+/* yy_hold_char holds the character lost when yytext is formed. */
+static char yy_hold_char;
+static yy_size_t yy_n_chars;		/* number of characters read into yy_ch_buf */
+yy_size_t yyleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 0;		/* whether we need to initialize */
+static int yy_start = 0;	/* start state number */
+
+/* Flag which is used to allow yywrap()'s to do buffer switches
+ * instead of setting up a fresh yyin.  A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void yyrestart (FILE *input_file  );
+void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer  );
+YY_BUFFER_STATE yy_create_buffer (FILE *file,int size  );
+void yy_delete_buffer (YY_BUFFER_STATE b  );
+void yy_flush_buffer (YY_BUFFER_STATE b  );
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer  );
+void yypop_buffer_state (void );
+
+static void yyensure_buffer_stack (void );
+static void yy_load_buffer_state (void );
+static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file  );
+
+#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER )
+
+YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size  );
+YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str  );
+YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,yy_size_t len  );
+
+void *yyalloc (yy_size_t  );
+void *yyrealloc (void *,yy_size_t  );
+void yyfree (void *  );
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+	{ \
+	if ( ! YY_CURRENT_BUFFER ){ \
+        yyensure_buffer_stack (); \
+		YY_CURRENT_BUFFER_LVALUE =    \
+            yy_create_buffer(yyin,YY_BUF_SIZE ); \
+	} \
+	YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+	}
+
+#define yy_set_bol(at_bol) \
+	{ \
+	if ( ! YY_CURRENT_BUFFER ){\
+        yyensure_buffer_stack (); \
+		YY_CURRENT_BUFFER_LVALUE =    \
+            yy_create_buffer(yyin,YY_BUF_SIZE ); \
+	} \
+	YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+	}
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+typedef unsigned char YY_CHAR;
+
+FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
+
+typedef int yy_state_type;
+
+extern int yylineno;
+
+int yylineno = 1;
+
+extern char *yytext;
+#define yytext_ptr yytext
+
+static yy_state_type yy_get_previous_state (void );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state  );
+static int yy_get_next_buffer (void );
+static void yy_fatal_error (yyconst char msg[]  ) __dead2;
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+	(yytext_ptr) = yy_bp; \
+	yyleng = (size_t) (yy_cp - yy_bp); \
+	(yy_hold_char) = *yy_cp; \
+	*yy_cp = '\0'; \
+	(yy_c_buf_p) = yy_cp;
+
+#define YY_NUM_RULES 19
+#define YY_END_OF_BUFFER 20
+/* This struct is not used in this scanner,
+   but its presence is necessary. */
+struct yy_trans_info
+	{
+	flex_int32_t yy_verify;
+	flex_int32_t yy_nxt;
+	};
+static yyconst flex_int16_t yy_accept[39] =
+    {   0,
+        0,    0,   20,   18,    1,    2,    7,    6,    7,   18,
+       16,   16,    2,    7,    7,    7,   16,   17,   18,   18,
+       11,    6,    5,    6,   14,   16,    0,   12,    8,   10,
+        9,   13,   16,   17,    3,   15,    4,    0
+    } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
+        1,    2,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    2,    4,    1,    5,    1,    6,    7,    1,    6,
+        6,    6,    6,    6,    6,    1,    6,    8,    9,    9,
+        9,    9,    9,    9,    9,    9,    9,    1,   10,   11,
+       12,   13,    1,    1,   14,   14,   14,   14,   14,   14,
+       15,   15,   15,   15,   15,   15,   15,   15,   15,   15,
+       15,   15,   15,   15,   15,   15,   15,   16,   15,   15,
+        1,   17,    1,    6,    1,    1,   15,   15,   15,   15,
+
+       15,   15,   15,   15,   15,   15,   15,   15,   15,   15,
+       15,   15,   15,   15,   15,   15,   15,   15,   15,   16,
+       15,   15,    1,   18,    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,    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,
+        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,    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
+    } ;
+
+static yyconst flex_int32_t yy_meta[19] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    2,    2,    1,
+        1,    1,    1,    2,    3,    2,    1,    1
+    } ;
+
+static yyconst flex_int16_t yy_base[43] =
+    {   0,
+        0,    0,   39,   49,   49,   49,   26,   16,   49,   30,
+       20,   19,   49,    9,   22,   10,    9,    0,   29,   13,
+       49,   23,   49,   24,   49,    0,    0,   49,   49,   49,
+       49,   49,   13,    0,   49,   49,   49,   49,   41,   28,
+       43,   45
+    } ;
+
+static yyconst flex_int16_t yy_def[43] =
+    {   0,
+       38,    1,   38,   38,   38,   38,   38,   39,   38,   38,
+       40,   40,   38,   38,   38,   38,   41,   42,   38,   38,
+       38,   39,   38,   39,   38,   12,   12,   38,   38,   38,
+       38,   38,   41,   42,   38,   38,   38,    0,   38,   38,
+       38,   38
+    } ;
+
+static yyconst flex_int16_t yy_nxt[68] =
+    {   0,
+        4,    5,    6,    7,    8,    9,   10,   11,   12,   13,
+       14,   15,   16,   17,   18,   18,   19,   20,   23,   28,
+       29,   31,   32,   34,   34,   23,   37,   34,   34,   26,
+       36,   35,   24,   30,   38,   27,   25,   21,   38,   24,
+       24,   22,   22,   22,   33,   33,   34,   34,    3,   38,
+       38,   38,   38,   38,   38,   38,   38,   38,   38,   38,
+       38,   38,   38,   38,   38,   38,   38
+    } ;
+
+static yyconst flex_int16_t yy_chk[68] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    8,   14,
+       14,   16,   16,   17,   17,   22,   24,   33,   33,   40,
+       20,   19,    8,   15,   12,   11,   10,    7,    3,   22,
+       24,   39,   39,   39,   41,   41,   42,   42,   38,   38,
+       38,   38,   38,   38,   38,   38,   38,   38,   38,   38,
+       38,   38,   38,   38,   38,   38,   38
+    } ;
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+extern int yy_flex_debug;
+int yy_flex_debug = 0;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *yytext;
+#line 1 "../../../gmp/demos/calc/calclex.l"
+/* Lexical analyzer for calc program.
+
+Copyright 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 3 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program.  If not, see https://www.gnu.org/licenses/.  */
+#line 20 "../../../gmp/demos/calc/calclex.l"
+#include <string.h>
+#include "calc-common.h"
+
+
+#if WITH_READLINE
+/* Let GNU flex use readline.  See the calcread.c redefined input() for a
+   way that might work for a standard lex too.  */
+#define YY_INPUT(buf,result,max_size)   \
+  result = calc_input (buf, max_size);
+#endif
+
+
+/* Non-zero when reading the second or subsequent line of an expression,
+   used to give a different prompt when using readline.  */
+int  calc_more_input = 0;
+
+
+const struct calc_keywords_t  calc_keywords[] = {
+  { "abs",       ABS },
+  { "bin",       BIN },
+  { "decimal",   DECIMAL },
+  { "fib",       FIB },
+  { "hex",       HEX },
+  { "help",      HELP },
+  { "gcd",       GCD },
+  { "kron",      KRON },
+  { "lcm",       LCM },
+  { "lucnum",    LUCNUM },
+  { "nextprime", NEXTPRIME },
+  { "powm",      POWM },
+  { "quit",      QUIT },
+  { "root",      ROOT },
+  { "sqrt",      SQRT },
+  { NULL }
+};
+#line 539 "calclex.c"
+
+#define INITIAL 0
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+static int yy_init_globals (void );
+
+/* Accessor methods to globals.
+   These are made visible to non-reentrant scanners for convenience. */
+
+int yylex_destroy (void );
+
+int yyget_debug (void );
+
+void yyset_debug (int debug_flag  );
+
+YY_EXTRA_TYPE yyget_extra (void );
+
+void yyset_extra (YY_EXTRA_TYPE user_defined  );
+
+FILE *yyget_in (void );
+
+void yyset_in  (FILE * in_str  );
+
+FILE *yyget_out (void );
+
+void yyset_out  (FILE * out_str  );
+
+yy_size_t yyget_leng (void );
+
+char *yyget_text (void );
+
+int yyget_lineno (void );
+
+void yyset_lineno (int line_number  );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap (void );
+#else
+extern int yywrap (void );
+#endif
+#endif
+
+#ifndef YY_NO_UNPUT
+    static void yyunput (int c,char *buf_ptr  );
+#endif
+    
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * );
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (void );
+#else
+static int input (void );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0)
+#endif
+
+/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+		{ \
+		int c = '*'; \
+		size_t n; \
+		for ( n = 0; n < max_size && \
+			     (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+			buf[n] = (char) c; \
+		if ( c == '\n' ) \
+			buf[n++] = (char) c; \
+		if ( c == EOF && ferror( yyin ) ) \
+			YY_FATAL_ERROR( "input in flex scanner failed" ); \
+		result = n; \
+		} \
+	else \
+		{ \
+		errno=0; \
+		while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
+			{ \
+			if( errno != EINTR) \
+				{ \
+				YY_FATAL_ERROR( "input in flex scanner failed" ); \
+				break; \
+				} \
+			errno=0; \
+			clearerr(yyin); \
+			} \
+		}\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int yylex (void);
+
+#define YY_DECL int yylex (void)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+	YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+	yy_state_type yy_current_state;
+	char *yy_cp, *yy_bp;
+	int yy_act;
+    
+#line 57 "../../../gmp/demos/calc/calclex.l"
+
+
+#line 726 "calclex.c"
+
+	if ( !(yy_init) )
+		{
+		(yy_init) = 1;
+
+#ifdef YY_USER_INIT
+		YY_USER_INIT;
+#endif
+
+		if ( ! (yy_start) )
+			(yy_start) = 1;	/* first start state */
+
+		if ( ! yyin )
+			yyin = stdin;
+
+		if ( ! yyout )
+			yyout = stdout;
+
+		if ( ! YY_CURRENT_BUFFER ) {
+			yyensure_buffer_stack ();
+			YY_CURRENT_BUFFER_LVALUE =
+				yy_create_buffer(yyin,YY_BUF_SIZE );
+		}
+
+		yy_load_buffer_state( );
+		}
+
+	while ( 1 )		/* loops until end-of-file is reached */
+		{
+		yy_cp = (yy_c_buf_p);
+
+		/* Support of yytext. */
+		*yy_cp = (yy_hold_char);
+
+		/* yy_bp points to the position in yy_ch_buf of the start of
+		 * the current run.
+		 */
+		yy_bp = yy_cp;
+
+		yy_current_state = (yy_start);
+yy_match:
+		do
+			{
+			YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ;
+			if ( yy_accept[yy_current_state] )
+				{
+				(yy_last_accepting_state) = yy_current_state;
+				(yy_last_accepting_cpos) = yy_cp;
+				}
+			while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+				{
+				yy_current_state = (int) yy_def[yy_current_state];
+				if ( yy_current_state >= 39 )
+					yy_c = yy_meta[(unsigned int) yy_c];
+				}
+			yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+			++yy_cp;
+			}
+		while ( yy_base[yy_current_state] != 49 );
+
+yy_find_action:
+		yy_act = yy_accept[yy_current_state];
+		if ( yy_act == 0 )
+			{ /* have to back up */
+			yy_cp = (yy_last_accepting_cpos);
+			yy_current_state = (yy_last_accepting_state);
+			yy_act = yy_accept[yy_current_state];
+			}
+
+		YY_DO_BEFORE_ACTION;
+
+do_action:	/* This label is used only to access EOF actions. */
+
+		switch ( yy_act )
+	{ /* beginning of action switch */
+			case 0: /* must back up */
+			/* undo the effects of YY_DO_BEFORE_ACTION */
+			*yy_cp = (yy_hold_char);
+			yy_cp = (yy_last_accepting_cpos);
+			yy_current_state = (yy_last_accepting_state);
+			goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+#line 59 "../../../gmp/demos/calc/calclex.l"
+{ /* white space is skipped */ }
+	YY_BREAK
+case 2:
+/* rule 2 can match eol */
+YY_RULE_SETUP
+#line 61 "../../../gmp/demos/calc/calclex.l"
+{ /* semicolon or newline separates statements */
+          calc_more_input = 0;
+          return EOS; }
+	YY_BREAK
+case 3:
+/* rule 3 can match eol */
+YY_RULE_SETUP
+#line 64 "../../../gmp/demos/calc/calclex.l"
+{ /* escaped newlines are skipped */ }
+	YY_BREAK
+case 4:
+/* rule 4 can match eol */
+YY_RULE_SETUP
+#line 67 "../../../gmp/demos/calc/calclex.l"
+{
+            /* comment through to escaped newline is skipped */ }
+	YY_BREAK
+case 5:
+/* rule 5 can match eol */
+YY_RULE_SETUP
+#line 69 "../../../gmp/demos/calc/calclex.l"
+{ /* comment through to newline is a separator */
+            calc_more_input = 0;
+            return EOS; }
+	YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 72 "../../../gmp/demos/calc/calclex.l"
+{   /* comment through to EOF skipped */ }
+	YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 75 "../../../gmp/demos/calc/calclex.l"
+{ return yytext[0]; }
+	YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 76 "../../../gmp/demos/calc/calclex.l"
+{ return LE; }
+	YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 77 "../../../gmp/demos/calc/calclex.l"
+{ return GE; }
+	YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 78 "../../../gmp/demos/calc/calclex.l"
+{ return EQ; }
+	YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 79 "../../../gmp/demos/calc/calclex.l"
+{ return NE; }
+	YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 80 "../../../gmp/demos/calc/calclex.l"
+{ return LSHIFT; }
+	YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 81 "../../../gmp/demos/calc/calclex.l"
+{ return RSHIFT; }
+	YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 82 "../../../gmp/demos/calc/calclex.l"
+{ return LAND; }
+	YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 83 "../../../gmp/demos/calc/calclex.l"
+{ return LOR; }
+	YY_BREAK
+case 16:
+YY_RULE_SETUP
+#line 85 "../../../gmp/demos/calc/calclex.l"
+{
+        yylval.str = yytext;
+        return NUMBER; }
+	YY_BREAK
+case 17:
+YY_RULE_SETUP
+#line 89 "../../../gmp/demos/calc/calclex.l"
+{
+        int  i;
+
+        for (i = 0; calc_keywords[i].name != NULL; i++)
+          if (strcmp (yytext, calc_keywords[i].name) == 0)
+            return calc_keywords[i].value;
+
+        if (yytext[0] >= 'a' && yytext[0] <= 'z' && yytext[1] == '\0')
+          {
+            yylval.var = yytext[0] - 'a';
+            return VARIABLE;
+          }
+
+        return BAD;
+}
+	YY_BREAK
+case 18:
+YY_RULE_SETUP
+#line 105 "../../../gmp/demos/calc/calclex.l"
+{ return BAD; }
+	YY_BREAK
+case 19:
+YY_RULE_SETUP
+#line 107 "../../../gmp/demos/calc/calclex.l"
+ECHO;
+	YY_BREAK
+#line 929 "calclex.c"
+case YY_STATE_EOF(INITIAL):
+	yyterminate();
+
+	case YY_END_OF_BUFFER:
+		{
+		/* Amount of text matched not including the EOB char. */
+		int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
+
+		/* Undo the effects of YY_DO_BEFORE_ACTION. */
+		*yy_cp = (yy_hold_char);
+		YY_RESTORE_YY_MORE_OFFSET
+
+		if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+			{
+			/* We're scanning a new file or input source.  It's
+			 * possible that this happened because the user
+			 * just pointed yyin at a new source and called
+			 * yylex().  If so, then we have to assure
+			 * consistency between YY_CURRENT_BUFFER and our
+			 * globals.  Here is the right place to do so, because
+			 * this is the first action (other than possibly a
+			 * back-up) that will match for the new input source.
+			 */
+			(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+			YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+			}
+
+		/* Note that here we test for yy_c_buf_p "<=" to the position
+		 * of the first EOB in the buffer, since yy_c_buf_p will
+		 * already have been incremented past the NUL character
+		 * (since all states make transitions on EOB to the
+		 * end-of-buffer state).  Contrast this with the test
+		 * in input().
+		 */
+		if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+			{ /* This was really a NUL. */
+			yy_state_type yy_next_state;
+
+			(yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
+
+			yy_current_state = yy_get_previous_state(  );
+
+			/* Okay, we're now positioned to make the NUL
+			 * transition.  We couldn't have
+			 * yy_get_previous_state() go ahead and do it
+			 * for us because it doesn't know how to deal
+			 * with the possibility of jamming (and we don't
+			 * want to build jamming into it because then it
+			 * will run more slowly).
+			 */
+
+			yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+			yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+
+			if ( yy_next_state )
+				{
+				/* Consume the NUL. */
+				yy_cp = ++(yy_c_buf_p);
+				yy_current_state = yy_next_state;
+				goto yy_match;
+				}
+
+			else
+				{
+				yy_cp = (yy_c_buf_p);
+				goto yy_find_action;
+				}
+			}
+
+		else switch ( yy_get_next_buffer(  ) )
+			{
+			case EOB_ACT_END_OF_FILE:
+				{
+				(yy_did_buffer_switch_on_eof) = 0;
+
+				if ( yywrap( ) )
+					{
+					/* Note: because we've taken care in
+					 * yy_get_next_buffer() to have set up
+					 * yytext, we can now set up
+					 * yy_c_buf_p so that if some total
+					 * hoser (like flex itself) wants to
+					 * call the scanner after we return the
+					 * YY_NULL, it'll still work - another
+					 * YY_NULL will get returned.
+					 */
+					(yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
+
+					yy_act = YY_STATE_EOF(YY_START);
+					goto do_action;
+					}
+
+				else
+					{
+					if ( ! (yy_did_buffer_switch_on_eof) )
+						YY_NEW_FILE;
+					}
+				break;
+				}
+
+			case EOB_ACT_CONTINUE_SCAN:
+				(yy_c_buf_p) =
+					(yytext_ptr) + yy_amount_of_matched_text;
+
+				yy_current_state = yy_get_previous_state(  );
+
+				yy_cp = (yy_c_buf_p);
+				yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+				goto yy_match;
+
+			case EOB_ACT_LAST_MATCH:
+				(yy_c_buf_p) =
+				&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
+
+				yy_current_state = yy_get_previous_state(  );
+
+				yy_cp = (yy_c_buf_p);
+				yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+				goto yy_find_action;
+			}
+		break;
+		}
+
+	default:
+		YY_FATAL_ERROR(
+			"fatal flex scanner internal error--no action found" );
+	} /* end of action switch */
+		} /* end of scanning one token */
+} /* end of yylex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ *	EOB_ACT_LAST_MATCH -
+ *	EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ *	EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (void)
+{
+    	char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+	char *source = (yytext_ptr);
+	int number_to_move, i;
+	int ret_val;
+
+	if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
+		YY_FATAL_ERROR(
+		"fatal flex scanner internal error--end of buffer missed" );
+
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+		{ /* Don't try to fill the buffer, so this is an EOF. */
+		if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
+			{
+			/* We matched a single character, the EOB, so
+			 * treat this as a final EOF.
+			 */
+			return EOB_ACT_END_OF_FILE;
+			}
+
+		else
+			{
+			/* We matched some text prior to the EOB, first
+			 * process it.
+			 */
+			return EOB_ACT_LAST_MATCH;
+			}
+		}
+
+	/* Try to read more data. */
+
+	/* First move last chars to start of buffer. */
+	number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
+
+	for ( i = 0; i < number_to_move; ++i )
+		*(dest++) = *(source++);
+
+	if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+		/* don't do the read, it's not guaranteed to return an EOF,
+		 * just force an EOF
+		 */
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
+
+	else
+		{
+			yy_size_t num_to_read =
+			YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+		while ( num_to_read <= 0 )
+			{ /* Not enough room in the buffer - grow it. */
+
+			/* just a shorter name for the current buffer */
+			YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE;
+
+			int yy_c_buf_p_offset =
+				(int) ((yy_c_buf_p) - b->yy_ch_buf);
+
+			if ( b->yy_is_our_buffer )
+				{
+				yy_size_t new_size = b->yy_buf_size * 2;
+
+				if ( new_size <= 0 )
+					b->yy_buf_size += b->yy_buf_size / 8;
+				else
+					b->yy_buf_size *= 2;
+
+				b->yy_ch_buf = (char *)
+					/* Include room in for 2 EOB chars. */
+					yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2  );
+				}
+			else
+				/* Can't grow it, we don't own it. */
+				b->yy_ch_buf = 0;
+
+			if ( ! b->yy_ch_buf )
+				YY_FATAL_ERROR(
+				"fatal error - scanner input buffer overflow" );
+
+			(yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+			num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+						number_to_move - 1;
+
+			}
+
+		if ( num_to_read > YY_READ_BUF_SIZE )
+			num_to_read = YY_READ_BUF_SIZE;
+
+		/* Read in more data. */
+		YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+			(yy_n_chars), num_to_read );
+
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+		}
+
+	if ( (yy_n_chars) == 0 )
+		{
+		if ( number_to_move == YY_MORE_ADJ )
+			{
+			ret_val = EOB_ACT_END_OF_FILE;
+			yyrestart(yyin  );
+			}
+
+		else
+			{
+			ret_val = EOB_ACT_LAST_MATCH;
+			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+				YY_BUFFER_EOF_PENDING;
+			}
+		}
+
+	else
+		ret_val = EOB_ACT_CONTINUE_SCAN;
+
+	if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+		/* Extend the array by 50%, plus the number we really need. */
+		yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
+		YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size  );
+		if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+			YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+	}
+
+	(yy_n_chars) += number_to_move;
+	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
+	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
+
+	(yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+	return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+    static yy_state_type yy_get_previous_state (void)
+{
+	yy_state_type yy_current_state;
+	char *yy_cp;
+    
+	yy_current_state = (yy_start);
+
+	for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
+		{
+		YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+		if ( yy_accept[yy_current_state] )
+			{
+			(yy_last_accepting_state) = yy_current_state;
+			(yy_last_accepting_cpos) = yy_cp;
+			}
+		while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+			{
+			yy_current_state = (int) yy_def[yy_current_state];
+			if ( yy_current_state >= 39 )
+				yy_c = yy_meta[(unsigned int) yy_c];
+			}
+		yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+		}
+
+	return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ *	next_state = yy_try_NUL_trans( current_state );
+ */
+    static yy_state_type yy_try_NUL_trans  (yy_state_type yy_current_state )
+{
+	int yy_is_jam;
+    	char *yy_cp = (yy_c_buf_p);
+
+	YY_CHAR yy_c = 1;
+	if ( yy_accept[yy_current_state] )
+		{
+		(yy_last_accepting_state) = yy_current_state;
+		(yy_last_accepting_cpos) = yy_cp;
+		}
+	while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+		{
+		yy_current_state = (int) yy_def[yy_current_state];
+		if ( yy_current_state >= 39 )
+			yy_c = yy_meta[(unsigned int) yy_c];
+		}
+	yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+	yy_is_jam = (yy_current_state == 38);
+
+		return yy_is_jam ? 0 : yy_current_state;
+}
+
+#ifndef YY_NO_UNPUT
+    static void yyunput (int c, char * yy_bp )
+{
+	char *yy_cp;
+    
+    yy_cp = (yy_c_buf_p);
+
+	/* undo effects of setting up yytext */
+	*yy_cp = (yy_hold_char);
+
+	if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+		{ /* need to shift things up to make room */
+		/* +2 for EOB chars. */
+		yy_size_t number_to_move = (yy_n_chars) + 2;
+		char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
+					YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
+		char *source =
+				&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
+
+		while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+			*--dest = *--source;
+
+		yy_cp += (int) (dest - source);
+		yy_bp += (int) (dest - source);
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
+			(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
+
+		if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
+			YY_FATAL_ERROR( "flex scanner push-back overflow" );
+		}
+
+	*--yy_cp = (char) c;
+
+	(yytext_ptr) = yy_bp;
+	(yy_hold_char) = *yy_cp;
+	(yy_c_buf_p) = yy_cp;
+}
+#endif	/* ifndef YY_NO_UNPUT */
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+    static int yyinput (void)
+#else
+    static int input  (void)
+#endif
+
+{
+	int c;
+    
+	*(yy_c_buf_p) = (yy_hold_char);
+
+	if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
+		{
+		/* yy_c_buf_p now points to the character we want to return.
+		 * If this occurs *before* the EOB characters, then it's a
+		 * valid NUL; if not, then we've hit the end of the buffer.
+		 */
+		if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+			/* This was really a NUL. */
+			*(yy_c_buf_p) = '\0';
+
+		else
+			{ /* need more input */
+			yy_size_t offset = (yy_c_buf_p) - (yytext_ptr);
+			++(yy_c_buf_p);
+
+			switch ( yy_get_next_buffer(  ) )
+				{
+				case EOB_ACT_LAST_MATCH:
+					/* This happens because yy_g_n_b()
+					 * sees that we've accumulated a
+					 * token and flags that we need to
+					 * try matching the token before
+					 * proceeding.  But for input(),
+					 * there's no matching to consider.
+					 * So convert the EOB_ACT_LAST_MATCH
+					 * to EOB_ACT_END_OF_FILE.
+					 */
+
+					/* Reset buffer status. */
+					yyrestart(yyin );
+
+					/*FALLTHROUGH*/
+
+				case EOB_ACT_END_OF_FILE:
+					{
+					if ( yywrap( ) )
+						return EOF;
+
+					if ( ! (yy_did_buffer_switch_on_eof) )
+						YY_NEW_FILE;
+#ifdef __cplusplus
+					return yyinput();
+#else
+					return input();
+#endif
+					}
+
+				case EOB_ACT_CONTINUE_SCAN:
+					(yy_c_buf_p) = (yytext_ptr) + offset;
+					break;
+				}
+			}
+		}
+
+	c = *(unsigned char *) (yy_c_buf_p);	/* cast for 8-bit char's */
+	*(yy_c_buf_p) = '\0';	/* preserve yytext */
+	(yy_hold_char) = *++(yy_c_buf_p);
+
+	return c;
+}
+#endif	/* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * 
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+    void yyrestart  (FILE * input_file )
+{
+    
+	if ( ! YY_CURRENT_BUFFER ){
+        yyensure_buffer_stack ();
+		YY_CURRENT_BUFFER_LVALUE =
+            yy_create_buffer(yyin,YY_BUF_SIZE );
+	}
+
+	yy_init_buffer(YY_CURRENT_BUFFER,input_file );
+	yy_load_buffer_state( );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * 
+ */
+    void yy_switch_to_buffer  (YY_BUFFER_STATE  new_buffer )
+{
+    
+	/* TODO. We should be able to replace this entire function body
+	 * with
+	 *		yypop_buffer_state();
+	 *		yypush_buffer_state(new_buffer);
+     */
+	yyensure_buffer_stack ();
+	if ( YY_CURRENT_BUFFER == new_buffer )
+		return;
+
+	if ( YY_CURRENT_BUFFER )
+		{
+		/* Flush out information for old buffer. */
+		*(yy_c_buf_p) = (yy_hold_char);
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+		}
+
+	YY_CURRENT_BUFFER_LVALUE = new_buffer;
+	yy_load_buffer_state( );
+
+	/* We don't actually know whether we did this switch during
+	 * EOF (yywrap()) processing, but the only time this flag
+	 * is looked at is after yywrap() is called, so it's safe
+	 * to go ahead and always set it.
+	 */
+	(yy_did_buffer_switch_on_eof) = 1;
+}
+
+static void yy_load_buffer_state  (void)
+{
+    	(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+	(yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+	yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+	(yy_hold_char) = *(yy_c_buf_p);
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * 
+ * @return the allocated buffer state.
+ */
+    YY_BUFFER_STATE yy_create_buffer  (FILE * file, int  size )
+{
+	YY_BUFFER_STATE b;
+    
+	b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state )  );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+	b->yy_buf_size = size;
+
+	/* yy_ch_buf has to be 2 characters longer than the size given because
+	 * we need to put in 2 end-of-buffer characters.
+	 */
+	b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2  );
+	if ( ! b->yy_ch_buf )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+	b->yy_is_our_buffer = 1;
+
+	yy_init_buffer(b,file );
+
+	return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with yy_create_buffer()
+ * 
+ */
+    void yy_delete_buffer (YY_BUFFER_STATE  b )
+{
+    
+	if ( ! b )
+		return;
+
+	if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+		YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+	if ( b->yy_is_our_buffer )
+		yyfree((void *) b->yy_ch_buf  );
+
+	yyfree((void *) b  );
+}
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a yyrestart() or at EOF.
+ */
+    static void yy_init_buffer  (YY_BUFFER_STATE  b, FILE * file )
+
+{
+	int oerrno = errno;
+    
+	yy_flush_buffer(b );
+
+	b->yy_input_file = file;
+	b->yy_fill_buffer = 1;
+
+    /* If b is the current buffer, then yy_init_buffer was _probably_
+     * called from yyrestart() or through yy_get_next_buffer.
+     * In that case, we don't want to reset the lineno or column.
+     */
+    if (b != YY_CURRENT_BUFFER){
+        b->yy_bs_lineno = 1;
+        b->yy_bs_column = 0;
+    }
+
+        b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+    
+	errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * 
+ */
+    void yy_flush_buffer (YY_BUFFER_STATE  b )
+{
+    	if ( ! b )
+		return;
+
+	b->yy_n_chars = 0;
+
+	/* We always need two end-of-buffer characters.  The first causes
+	 * a transition to the end-of-buffer state.  The second causes
+	 * a jam in that state.
+	 */
+	b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+	b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+	b->yy_buf_pos = &b->yy_ch_buf[0];
+
+	b->yy_at_bol = 1;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	if ( b == YY_CURRENT_BUFFER )
+		yy_load_buffer_state( );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ *  the current state. This function will allocate the stack
+ *  if necessary.
+ *  @param new_buffer The new state.
+ *  
+ */
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer )
+{
+    	if (new_buffer == NULL)
+		return;
+
+	yyensure_buffer_stack();
+
+	/* This block is copied from yy_switch_to_buffer. */
+	if ( YY_CURRENT_BUFFER )
+		{
+		/* Flush out information for old buffer. */
+		*(yy_c_buf_p) = (yy_hold_char);
+		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+		}
+
+	/* Only push if top exists. Otherwise, replace top. */
+	if (YY_CURRENT_BUFFER)
+		(yy_buffer_stack_top)++;
+	YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+	/* copied from yy_switch_to_buffer. */
+	yy_load_buffer_state( );
+	(yy_did_buffer_switch_on_eof) = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ *  The next element becomes the new top.
+ *  
+ */
+void yypop_buffer_state (void)
+{
+    	if (!YY_CURRENT_BUFFER)
+		return;
+
+	yy_delete_buffer(YY_CURRENT_BUFFER );
+	YY_CURRENT_BUFFER_LVALUE = NULL;
+	if ((yy_buffer_stack_top) > 0)
+		--(yy_buffer_stack_top);
+
+	if (YY_CURRENT_BUFFER) {
+		yy_load_buffer_state( );
+		(yy_did_buffer_switch_on_eof) = 1;
+	}
+}
+
+/* Allocates the stack if it does not exist.
+ *  Guarantees space for at least one push.
+ */
+static void yyensure_buffer_stack (void)
+{
+	yy_size_t num_to_alloc;
+    
+	if (!(yy_buffer_stack)) {
+
+		/* First allocation is just for 2 elements, since we don't know if this
+		 * scanner will even need a stack. We use 2 instead of 1 to avoid an
+		 * immediate realloc on the next call.
+         */
+		num_to_alloc = 1;
+		(yy_buffer_stack) = (struct yy_buffer_state**)yyalloc
+								(num_to_alloc * sizeof(struct yy_buffer_state*)
+								);
+		if ( ! (yy_buffer_stack) )
+			YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+								  
+		memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+				
+		(yy_buffer_stack_max) = num_to_alloc;
+		(yy_buffer_stack_top) = 0;
+		return;
+	}
+
+	if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
+
+		/* Increase the buffer to prepare for a possible push. */
+		int grow_size = 8 /* arbitrary grow size */;
+
+		num_to_alloc = (yy_buffer_stack_max) + grow_size;
+		(yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc
+								((yy_buffer_stack),
+								num_to_alloc * sizeof(struct yy_buffer_state*)
+								);
+		if ( ! (yy_buffer_stack) )
+			YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+		/* zero only the new slots.*/
+		memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
+		(yy_buffer_stack_max) = num_to_alloc;
+	}
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * 
+ * @return the newly allocated buffer state object. 
+ */
+YY_BUFFER_STATE yy_scan_buffer  (char * base, yy_size_t  size )
+{
+	YY_BUFFER_STATE b;
+    
+	if ( size < 2 ||
+	     base[size-2] != YY_END_OF_BUFFER_CHAR ||
+	     base[size-1] != YY_END_OF_BUFFER_CHAR )
+		/* They forgot to leave room for the EOB's. */
+		return 0;
+
+	b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state )  );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+	b->yy_buf_size = size - 2;	/* "- 2" to take care of EOB's */
+	b->yy_buf_pos = b->yy_ch_buf = base;
+	b->yy_is_our_buffer = 0;
+	b->yy_input_file = 0;
+	b->yy_n_chars = b->yy_buf_size;
+	b->yy_is_interactive = 0;
+	b->yy_at_bol = 1;
+	b->yy_fill_buffer = 0;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	yy_switch_to_buffer(b  );
+
+	return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to yylex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ * 
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ *       yy_scan_bytes() instead.
+ */
+YY_BUFFER_STATE yy_scan_string (yyconst char * yystr )
+{
+    
+	return yy_scan_bytes(yystr,strlen(yystr) );
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to yylex() will
+ * scan from a @e copy of @a bytes.
+ * @param yybytes the byte buffer to scan
+ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
+ * 
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_bytes  (yyconst char * yybytes, yy_size_t  _yybytes_len )
+{
+	YY_BUFFER_STATE b;
+	char *buf;
+	yy_size_t n;
+	yy_size_t i;
+    
+	/* Get memory for full buffer, including space for trailing EOB's. */
+	n = _yybytes_len + 2;
+	buf = (char *) yyalloc(n  );
+	if ( ! buf )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+	for ( i = 0; i < _yybytes_len; ++i )
+		buf[i] = yybytes[i];
+
+	buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+	b = yy_scan_buffer(buf,n );
+	if ( ! b )
+		YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+	/* It's okay to grow etc. this buffer, and we should throw it
+	 * away when we're done.
+	 */
+	b->yy_is_our_buffer = 1;
+
+	return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg )
+{
+    	(void) fprintf( stderr, "%s\n", msg );
+	exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up yytext. */ \
+        int yyless_macro_arg = (n); \
+        YY_LESS_LINENO(yyless_macro_arg);\
+		yytext[yyleng] = (yy_hold_char); \
+		(yy_c_buf_p) = yytext + yyless_macro_arg; \
+		(yy_hold_char) = *(yy_c_buf_p); \
+		*(yy_c_buf_p) = '\0'; \
+		yyleng = yyless_macro_arg; \
+		} \
+	while ( 0 )
+
+/* Accessor  methods (get/set functions) to struct members. */
+
+/** Get the current line number.
+ * 
+ */
+int yyget_lineno  (void)
+{
+        
+    return yylineno;
+}
+
+/** Get the input stream.
+ * 
+ */
+FILE *yyget_in  (void)
+{
+        return yyin;
+}
+
+/** Get the output stream.
+ * 
+ */
+FILE *yyget_out  (void)
+{
+        return yyout;
+}
+
+/** Get the length of the current token.
+ * 
+ */
+yy_size_t yyget_leng  (void)
+{
+        return yyleng;
+}
+
+/** Get the current token.
+ * 
+ */
+
+char *yyget_text  (void)
+{
+        return yytext;
+}
+
+/** Set the current line number.
+ * @param line_number
+ * 
+ */
+void yyset_lineno (int  line_number )
+{
+    
+    yylineno = line_number;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ * 
+ * @see yy_switch_to_buffer
+ */
+void yyset_in (FILE *  in_str )
+{
+        yyin = in_str ;
+}
+
+void yyset_out (FILE *  out_str )
+{
+        yyout = out_str ;
+}
+
+int yyget_debug  (void)
+{
+        return yy_flex_debug;
+}
+
+void yyset_debug (int  bdebug )
+{
+        yy_flex_debug = bdebug ;
+}
+
+static int yy_init_globals (void)
+{
+        /* Initialization is the same as for the non-reentrant scanner.
+     * This function is called from yylex_destroy(), so don't allocate here.
+     */
+
+    (yy_buffer_stack) = 0;
+    (yy_buffer_stack_top) = 0;
+    (yy_buffer_stack_max) = 0;
+    (yy_c_buf_p) = (char *) 0;
+    (yy_init) = 0;
+    (yy_start) = 0;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+    yyin = stdin;
+    yyout = stdout;
+#else
+    yyin = (FILE *) 0;
+    yyout = (FILE *) 0;
+#endif
+
+    /* For future reference: Set errno on error, since we are called by
+     * yylex_init()
+     */
+    return 0;
+}
+
+/* yylex_destroy is for both reentrant and non-reentrant scanners. */
+int yylex_destroy  (void)
+{
+    
+    /* Pop the buffer stack, destroying each element. */
+	while(YY_CURRENT_BUFFER){
+		yy_delete_buffer(YY_CURRENT_BUFFER  );
+		YY_CURRENT_BUFFER_LVALUE = NULL;
+		yypop_buffer_state();
+	}
+
+	/* Destroy the stack itself. */
+	yyfree((yy_buffer_stack) );
+	(yy_buffer_stack) = NULL;
+
+    /* Reset the globals. This is important in a non-reentrant scanner so the next time
+     * yylex() is called, initialization will occur. */
+    yy_init_globals( );
+
+    return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
+{
+	int i;
+	for ( i = 0; i < n; ++i )
+		s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s )
+{
+	int n;
+	for ( n = 0; s[n]; ++n )
+		;
+
+	return n;
+}
+#endif
+
+void *yyalloc (yy_size_t  size )
+{
+	return (void *) malloc( size );
+}
+
+void *yyrealloc  (void * ptr, yy_size_t  size )
+{
+	/* The cast to (char *) in the following accommodates both
+	 * implementations that use char* generic pointers, and those
+	 * that use void* generic pointers.  It works with the latter
+	 * because both ANSI C and C++ allow castless assignment from
+	 * any pointer type to void*, and deal with argument conversions
+	 * as though doing an assignment.
+	 */
+	return (void *) realloc( (char *) ptr, size );
+}
+
+void yyfree (void * ptr )
+{
+	free( (char *) ptr );	/* see yyrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#line 107 "../../../gmp/demos/calc/calclex.l"
+
+
+
+int
+yywrap ()
+{
+  return 1;
+}
+
diff --git a/third_party/gmp/demos/calc/calclex.l b/third_party/gmp/demos/calc/calclex.l
new file mode 100644
index 0000000..44df848
--- /dev/null
+++ b/third_party/gmp/demos/calc/calclex.l
@@ -0,0 +1,113 @@
+/* Lexical analyzer for calc program.
+
+Copyright 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 3 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program.  If not, see https://www.gnu.org/licenses/.  */
+
+%{
+#include <string.h>
+#include "calc-common.h"
+
+
+#if WITH_READLINE
+/* Let GNU flex use readline.  See the calcread.c redefined input() for a
+   way that might work for a standard lex too.  */
+#define YY_INPUT(buf,result,max_size)   \
+  result = calc_input (buf, max_size);
+#endif
+
+
+/* Non-zero when reading the second or subsequent line of an expression,
+   used to give a different prompt when using readline.  */
+int  calc_more_input = 0;
+
+
+const struct calc_keywords_t  calc_keywords[] = {
+  { "abs",       ABS },
+  { "bin",       BIN },
+  { "decimal",   DECIMAL },
+  { "fib",       FIB },
+  { "hex",       HEX },
+  { "help",      HELP },
+  { "gcd",       GCD },
+  { "kron",      KRON },
+  { "lcm",       LCM },
+  { "lucnum",    LUCNUM },
+  { "nextprime", NEXTPRIME },
+  { "powm",      POWM },
+  { "quit",      QUIT },
+  { "root",      ROOT },
+  { "sqrt",      SQRT },
+  { NULL }
+};
+%}
+
+%%
+
+[ \t\f] { /* white space is skipped */ }
+
+[;\n]   { /* semicolon or newline separates statements */
+          calc_more_input = 0;
+          return EOS; }
+\\\n    { /* escaped newlines are skipped */ }
+
+
+#(([^\\\n]*)\\)+\n {
+            /* comment through to escaped newline is skipped */ }
+#[^\n]*\n { /* comment through to newline is a separator */
+            calc_more_input = 0;
+            return EOS; }
+#[^\n]* {   /* comment through to EOF skipped */ }
+
+
+[-+*/%()<>^!=,] { return yytext[0]; }
+"<="    { return LE; }
+">="    { return GE; }
+"=="    { return EQ; }
+"!="    { return NE; }
+"<<"    { return LSHIFT; }
+">>"    { return RSHIFT; }
+"&&"    { return LAND; }
+"||"    { return LOR; }
+
+(0[xX])?[0-9A-F]+ {
+        yylval.str = yytext;
+        return NUMBER; }
+
+[a-zA-Z][a-zA-Z0-9]* {
+        int  i;
+
+        for (i = 0; calc_keywords[i].name != NULL; i++)
+          if (strcmp (yytext, calc_keywords[i].name) == 0)
+            return calc_keywords[i].value;
+
+        if (yytext[0] >= 'a' && yytext[0] <= 'z' && yytext[1] == '\0')
+          {
+            yylval.var = yytext[0] - 'a';
+            return VARIABLE;
+          }
+
+        return BAD;
+}
+
+. { return BAD; }
+
+%%
+
+int
+yywrap ()
+{
+  return 1;
+}
diff --git a/third_party/gmp/demos/calc/calcread.c b/third_party/gmp/demos/calc/calcread.c
new file mode 100644
index 0000000..4043368
--- /dev/null
+++ b/third_party/gmp/demos/calc/calcread.c
@@ -0,0 +1,146 @@
+/* Readline support for calc program.
+
+Copyright 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 3 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "calc-common.h"
+
+#if WITH_READLINE
+#include <stdio.h>   /* for FILE for old versions of readline/readline.h */
+#include <stdlib.h>  /* for free */
+#include <string.h>  /* for strdup */
+#include <unistd.h>  /* for isatty */
+#include <readline/readline.h>
+#include <readline/history.h>
+
+#include "gmp.h"
+
+
+/* change this to "#define TRACE(x) x" for a few diagnostics */
+#define TRACE(x)
+
+
+#define MIN(x,y) ((x) < (y) ? (x) : (y))
+
+char *
+calc_completion_entry (const char *text, int state)
+{
+  static int  index, len;
+  char  *name;
+
+  if (!state)
+    {
+      index = 0;
+      len = strlen (text);
+    }
+  TRACE (printf ("calc_completion_entry %s %d, index=%d len=%d\n",
+		 text, state, index, len));
+  while ((name = calc_keywords[index].name) != NULL)
+    {
+      index++;
+      if (memcmp (name, text, len) == 0)
+	return (strdup (name));
+    }
+  return NULL;
+}
+
+void
+calc_init_readline (void)
+{
+  /* By default use readline when the input is a tty.  It's a bit contrary
+     to the GNU interface conventions to make the behaviour depend on where
+     the input is coming from, but this is pretty convenient.  */
+  if (calc_option_readline == -1)
+    {
+      calc_option_readline = isatty (fileno (stdin));
+      TRACE (printf ("calc_option_readline %d\n", calc_option_readline));
+    }
+
+  if (calc_option_readline)
+    {
+      printf ("GNU MP demo calculator program, gmp version %s\n", gmp_version);
+      printf ("Type \"help\" for help.\n");
+      rl_readline_name = "gmp-calc";
+      rl_completion_entry_function = calc_completion_entry;
+    }
+}
+
+
+/* This function is supposed to return YY_NULL to indicate EOF, but that
+   constant is only in calclex.c and we don't want to clutter calclex.l with
+   this readline stuff, so instead just hard code 0 for YY_NULL.  That's
+   it's defined value on unix anyway.  */
+
+int
+calc_input (char *buf, size_t max_size)
+{
+  if (calc_option_readline)
+    {
+      static char    *line = NULL;
+      static size_t  line_size = 0;
+      static size_t  upto = 0;
+      size_t         copy_size;
+
+      if (upto >= line_size)
+	{
+	  if (line != NULL)
+	    free (line);
+
+	  line = readline (calc_more_input ? "more> " : "> ");
+	  calc_more_input = 1;
+	  if (line == NULL)
+	    return 0;
+	  TRACE (printf ("readline: %s\n", line));
+
+	  if (line[0] != '\0')
+	    add_history (line);
+
+	  line_size = strlen (line);
+	  line[line_size] = '\n';
+	  line_size++;
+	  upto = 0;
+	}
+
+      copy_size = MIN (line_size-upto, max_size);
+      memcpy (buf, line+upto, copy_size);
+      upto += copy_size;
+      return copy_size;
+    }
+  else
+    {
+      /* not readline */
+      return fread (buf, 1, max_size, stdin);
+    }
+}
+
+
+/* This redefined input() might let a traditional lex use the readline
+   support here.  Apparently POSIX doesn't specify whether an override like
+   this will work, so maybe it'll work or maybe it won't.  This function is
+   also not particularly efficient, but don't worry about that, since flex
+   is the preferred parser.  */
+
+int
+input (void)
+{
+  char  c;
+  if (calc_input (&c, 1) != 1)
+    return EOF;
+  else
+    return (int) c;
+}
+
+#endif /* WITH_READLINE */
diff --git a/third_party/gmp/demos/expr/Makefile.am b/third_party/gmp/demos/expr/Makefile.am
new file mode 100644
index 0000000..252300a
--- /dev/null
+++ b/third_party/gmp/demos/expr/Makefile.am
@@ -0,0 +1,54 @@
+## Process this file with automake to generate Makefile.in
+
+# Copyright 2001-2004 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+
+AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/tests
+
+# FIXME: This is a workaround for a bug in automake 1.8.4.  When the only
+# library is in EXTRA_LIBRARIES, $(ARFLAGS) is used but no default setting
+# for that variable is established.  We give an explicit ARFLAGS=cru the
+# same as generated for lib_LIBRARIES or noinst_LIBRARIES.
+#
+ARFLAGS = cru
+
+EXTRA_LIBRARIES = libexpr.a
+libexpr_a_SOURCES = expr.h expr-impl.h \
+  expr.c exprv.c exprz.c exprza.c exprq.c exprqa.c exprf.c exprfa.c
+
+EXTRA_PROGRAMS = run-expr t-expr
+LDADD = libexpr.a $(top_builddir)/libgmp.la
+t_expr_LDADD = $(top_builddir)/tests/libtests.la $(LDADD)
+
+CLEANFILES = $(EXTRA_PROGRAMS) $(EXTRA_LIBRARIES)
+
+allprogs: $(EXTRA_PROGRAMS)
+
+$(top_builddir)/tests/libtests.la:
+	cd $(top_builddir)/tests; $(MAKE) $(AM_MAKEFLAGS) libtests.la
diff --git a/third_party/gmp/demos/expr/Makefile.in b/third_party/gmp/demos/expr/Makefile.in
new file mode 100644
index 0000000..354e239
--- /dev/null
+++ b/third_party/gmp/demos/expr/Makefile.in
@@ -0,0 +1,666 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Copyright 2001-2004 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+EXTRA_PROGRAMS = run-expr$(EXEEXT) t-expr$(EXEEXT)
+subdir = demos/expr
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_AR = $(am__v_AR_@AM_V@)
+am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@)
+am__v_AR_0 = @echo "  AR      " $@;
+am__v_AR_1 = 
+libexpr_a_AR = $(AR) $(ARFLAGS)
+libexpr_a_LIBADD =
+am_libexpr_a_OBJECTS = expr.$(OBJEXT) exprv.$(OBJEXT) exprz.$(OBJEXT) \
+	exprza.$(OBJEXT) exprq.$(OBJEXT) exprqa.$(OBJEXT) \
+	exprf.$(OBJEXT) exprfa.$(OBJEXT)
+libexpr_a_OBJECTS = $(am_libexpr_a_OBJECTS)
+run_expr_SOURCES = run-expr.c
+run_expr_OBJECTS = run-expr.$(OBJEXT)
+run_expr_LDADD = $(LDADD)
+run_expr_DEPENDENCIES = libexpr.a $(top_builddir)/libgmp.la
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+t_expr_SOURCES = t-expr.c
+t_expr_OBJECTS = t-expr.$(OBJEXT)
+t_expr_DEPENDENCIES = $(top_builddir)/tests/libtests.la $(LDADD)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp =
+am__depfiles_maybe =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+SOURCES = $(libexpr_a_SOURCES) run-expr.c t-expr.c
+DIST_SOURCES = $(libexpr_a_SOURCES) run-expr.c t-expr.c
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in README
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ABI = @ABI@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+ASMFLAGS = @ASMFLAGS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CALLING_CONVENTIONS_OBJS = @CALLING_CONVENTIONS_OBJS@
+CC = @CC@
+CCAS = @CCAS@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPP_FOR_BUILD = @CPP_FOR_BUILD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFN_LONG_LONG_LIMB = @DEFN_LONG_LONG_LIMB@
+DEFS = @DEFS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@
+FGREP = @FGREP@
+GMP_LDFLAGS = @GMP_LDFLAGS@
+GMP_LIMB_BITS = @GMP_LIMB_BITS@
+GMP_NAIL_BITS = @GMP_NAIL_BITS@
+GREP = @GREP@
+HAVE_CLOCK_01 = @HAVE_CLOCK_01@
+HAVE_CPUTIME_01 = @HAVE_CPUTIME_01@
+HAVE_GETRUSAGE_01 = @HAVE_GETRUSAGE_01@
+HAVE_GETTIMEOFDAY_01 = @HAVE_GETTIMEOFDAY_01@
+HAVE_HOST_CPU_FAMILY_power = @HAVE_HOST_CPU_FAMILY_power@
+HAVE_HOST_CPU_FAMILY_powerpc = @HAVE_HOST_CPU_FAMILY_powerpc@
+HAVE_SIGACTION_01 = @HAVE_SIGACTION_01@
+HAVE_SIGALTSTACK_01 = @HAVE_SIGALTSTACK_01@
+HAVE_SIGSTACK_01 = @HAVE_SIGSTACK_01@
+HAVE_STACK_T_01 = @HAVE_STACK_T_01@
+HAVE_SYS_RESOURCE_H_01 = @HAVE_SYS_RESOURCE_H_01@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCURSES = @LIBCURSES@
+LIBGMPXX_LDFLAGS = @LIBGMPXX_LDFLAGS@
+LIBGMP_DLL = @LIBGMP_DLL@
+LIBGMP_LDFLAGS = @LIBGMP_LDFLAGS@
+LIBM = @LIBM@
+LIBM_FOR_BUILD = @LIBM_FOR_BUILD@
+LIBOBJS = @LIBOBJS@
+LIBREADLINE = @LIBREADLINE@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+M4 = @M4@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPEED_CYCLECOUNTER_OBJ = @SPEED_CYCLECOUNTER_OBJ@
+STRIP = @STRIP@
+TAL_OBJECT = @TAL_OBJECT@
+TUNE_LIBS = @TUNE_LIBS@
+TUNE_SQR_OBJ = @TUNE_SQR_OBJ@
+U_FOR_BUILD = @U_FOR_BUILD@
+VERSION = @VERSION@
+WITH_READLINE_01 = @WITH_READLINE_01@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__leading_dot = @am__leading_dot@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gmp_srclinks = @gmp_srclinks@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+mpn_objects = @mpn_objects@
+mpn_objs_in_libgmp = @mpn_objs_in_libgmp@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/tests
+
+# FIXME: This is a workaround for a bug in automake 1.8.4.  When the only
+# library is in EXTRA_LIBRARIES, $(ARFLAGS) is used but no default setting
+# for that variable is established.  We give an explicit ARFLAGS=cru the
+# same as generated for lib_LIBRARIES or noinst_LIBRARIES.
+#
+ARFLAGS = cru
+EXTRA_LIBRARIES = libexpr.a
+libexpr_a_SOURCES = expr.h expr-impl.h \
+  expr.c exprv.c exprz.c exprza.c exprq.c exprqa.c exprf.c exprfa.c
+
+LDADD = libexpr.a $(top_builddir)/libgmp.la
+t_expr_LDADD = $(top_builddir)/tests/libtests.la $(LDADD)
+CLEANFILES = $(EXTRA_PROGRAMS) $(EXTRA_LIBRARIES)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu --ignore-deps demos/expr/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu --ignore-deps demos/expr/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+libexpr.a: $(libexpr_a_OBJECTS) $(libexpr_a_DEPENDENCIES) $(EXTRA_libexpr_a_DEPENDENCIES) 
+	$(AM_V_at)-rm -f libexpr.a
+	$(AM_V_AR)$(libexpr_a_AR) libexpr.a $(libexpr_a_OBJECTS) $(libexpr_a_LIBADD)
+	$(AM_V_at)$(RANLIB) libexpr.a
+
+run-expr$(EXEEXT): $(run_expr_OBJECTS) $(run_expr_DEPENDENCIES) $(EXTRA_run_expr_DEPENDENCIES) 
+	@rm -f run-expr$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(run_expr_OBJECTS) $(run_expr_LDADD) $(LIBS)
+
+t-expr$(EXEEXT): $(t_expr_OBJECTS) $(t_expr_DEPENDENCIES) $(EXTRA_t_expr_DEPENDENCIES) 
+	@rm -f t-expr$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_expr_OBJECTS) $(t_expr_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+.c.o:
+	$(AM_V_CC)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+	$(AM_V_CC)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+	$(AM_V_CC)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+	-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+	clean-libtool cscopelist-am ctags ctags-am distclean \
+	distclean-compile distclean-generic distclean-libtool \
+	distclean-tags distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-ps install-ps-am \
+	install-strip installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+	pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+allprogs: $(EXTRA_PROGRAMS)
+
+$(top_builddir)/tests/libtests.la:
+	cd $(top_builddir)/tests; $(MAKE) $(AM_MAKEFLAGS) libtests.la
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/third_party/gmp/demos/expr/README b/third_party/gmp/demos/expr/README
new file mode 100644
index 0000000..a54fe42
--- /dev/null
+++ b/third_party/gmp/demos/expr/README
@@ -0,0 +1,501 @@
+Copyright 2001, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.
+
+
+
+
+
+
+                    GMP EXPRESSION EVALUATION
+                    -------------------------
+
+
+
+THIS CODE IS PRELIMINARY AND MAY BE SUBJECT TO INCOMPATIBLE CHANGES IN
+FUTURE VERSIONS OF GMP.
+
+
+
+The files in this directory implement a simple scheme of string based
+expression parsing and evaluation, supporting mpz, mpq and mpf.
+
+This will be slower than direct GMP library calls, but may be convenient in
+various circumstances, such as while prototyping, or for letting a user
+enter values in symbolic form.  "2**5723-7" for example is a lot easier to
+enter or maintain than the equivalent written out in decimal.
+
+
+
+BUILDING
+
+Nothing in this directory is a normal part of libgmp, and nothing is built
+or installed, but various Makefile rules are available to compile
+everything.
+
+All the functions are available through a little library (there's no shared
+library since upward binary compatibility is not guaranteed).
+
+	make libexpr.a
+
+In a program, prototypes are available using
+
+	#include "expr.h"
+
+run-expr.c is a sample program doing evaluations from the command line.
+
+	make run-expr
+	./run-expr '1+2*3'
+
+t-expr.c is self-test program, it prints nothing if successful.
+
+	make t-expr
+	./t-expr
+
+The expr*.c sources don't depend on gmp-impl.h and can be compiled with just
+a standard installed GMP.  This isn't true of t-expr though, since it uses
+some of the internal tests/libtests.la.
+
+
+
+SIMPLE USAGE
+
+int mpz_expr (mpz_t res, int base, const char *e, ...);
+int mpq_expr (mpq_t res, int base, const char *e, ...);
+int mpf_expr (mpf_t res, int base, const char *e, ...);
+
+These functions evaluate simple arithmetic expressions.  For example,
+
+	mpz_expr (result, 0, "123+456", NULL);
+
+Numbers are parsed by mpz_expr and mpq_expr the same as mpz_set_str with the
+given base.  mpf_expr follows mpf_set_str, but supporting an "0x" prefix for
+hex when base==0.
+
+	mpz_expr (result, 0, "0xAAAA * 0x5555", NULL);
+
+White space, as indicated by <ctype.h> isspace(), is ignored except for the
+purpose of separating tokens.
+
+Variables can be included in expressions by putting them in the stdarg list
+after the string.  "a", "b", "c" etc in the expression string designate
+those values.  For example,
+
+        mpq_t  foo, bar;
+        ...
+	mpq_expr (q, 10, "2/3 + 1/a + b/2", foo, bar, NULL);
+
+Here "a" will be the value from foo and "b" from bar.  Up to 26 variables
+can be included this way.  The NULL must be present to indicate the end of
+the list.
+
+Variables can also be written "$a", "$b" etc.  This is necessary when using
+bases greater than 10 since plain "a", "b" etc will otherwise be interpreted
+as numbers.  For example,
+
+        mpf_t  quux;
+        mpf_expr (f, 16, "F00F@-6 * $a", quux, NULL);
+
+All the standard C operators are available, with the usual precedences, plus
+"**" for exponentiation at the highest precedence (and right associative).
+
+        Operators      Precedence
+         **              220
+         ~ ! - (unary)   210
+         * / %           200
+         + -             190
+         << >>           180
+         <= < >= >       170
+         == !=           160
+         &               150
+         ^               140
+         |               130
+         &&              120
+         ||              110
+         ? :             100/101
+
+Currently only mpz_expr has the bitwise ~ % & ^ and | operators.  The
+precedence numbers are of interest in the advanced usage described below.
+
+Various functions are available too.  For example,
+
+        mpz_expr (res, 10, "gcd(123,456,789) * abs(a)", var, NULL);
+
+The following is the full set of functions,
+
+        mpz_expr
+            abs bin clrbit cmp cmpabs congruent_p divisible_p even_p fib fac
+            gcd hamdist invert jacobi kronecker lcm lucnum max min nextprime
+            odd_p perfect_power_p perfect_square_p popcount powm
+            probab_prime_p root scan0 scan1 setbit sgn sqrt
+
+        mpq_expr
+            abs, cmp, den, max, min, num, sgn
+
+        mpf_expr
+            abs, ceil, cmp, eq, floor, integer_p, max, min, reldiff, sgn,
+            sqrt, trunc
+
+All these are the same as the GMP library functions, except that min and max
+don't exist in the library.  Note also that min, max, gcd and lcm take any
+number of arguments, not just two.
+
+mpf_expr does all calculations to the precision of the destination variable.
+
+
+Expression parsing can succeed or fail.  The return value indicates this,
+and will be one of the following
+
+	MPEXPR_RESULT_OK
+	MPEXPR_RESULT_BAD_VARIABLE
+	MPEXPR_RESULT_BAD_TABLE
+	MPEXPR_RESULT_PARSE_ERROR
+	MPEXPR_RESULT_NOT_UI
+
+BAD_VARIABLE is when a variable is referenced that hasn't been provided.
+For example if "c" is used when only two parameters have been passed.
+BAD_TABLE is applicable to the advanced usage described below.
+
+PARSE_ERROR is a general syntax error, returned for any mal-formed input
+string.
+
+NOT_UI is returned when an attempt is made to use an operand that's bigger
+than an "unsigned long" with a function that's restricted to that range.
+For example "fib" is mpz_fib_ui and only accepts an "unsigned long".
+
+
+
+
+ADVANCED USAGE
+
+int mpz_expr_a (const struct mpexpr_operator_t *table,
+                mpz_ptr res, int base, const char *e, size_t elen,
+                mpz_srcptr var[26])
+int mpq_expr_a (const struct mpexpr_operator_t *table,
+                mpq_ptr res, int base, const char *e, size_t elen,
+                mpq_srcptr var[26])
+int mpf_expr_a (const struct mpexpr_operator_t *table,
+                mpf_ptr res, int base, unsigned long prec,
+                const char *e, size_t elen,
+                mpf_srcptr var[26])
+
+These functions are an advanced interface to expression parsing.
+
+The string is taken as pointer and length.  This makes it possible to parse
+an expression in the middle of somewhere without copying and null
+terminating it.
+
+Variables are an array of 26 pointers to the appropriate operands, or NULL
+for variables that are not available.  Any combination of variables can be
+given, for example just "x" and "y" (var[23] and var[24]) could be set.
+
+Operators and functions are specified with a table.  This makes it possible
+to provide additional operators or functions, or to completely change the
+syntax.  The standard tables used by the simple functions above are
+available as
+
+	const struct mpexpr_operator_t * const mpz_expr_standard_table;
+	const struct mpexpr_operator_t * const mpq_expr_standard_table;
+	const struct mpexpr_operator_t * const mpf_expr_standard_table;
+
+struct mpexpr_operator_t is the following
+
+	struct mpexpr_operator_t {
+	  const char    *name;
+	  mpexpr_fun_t  fun;
+	  int           type;
+	  int           precedence;
+	};
+
+        typedef void (*mpexpr_fun_t) (void);
+
+As an example, the standard mpz_expr table entry for multiplication is as
+follows.  See the source code for the full set of standard entries.
+
+	{ "*", (mpexpr_fun_t) mpz_mul, MPEXPR_TYPE_BINARY, 200 },
+
+"name" is the string to parse, "fun" is the function to call for it, "type"
+indicates what parameters the function takes (among other things), and
+"precedence" sets its operator precedence.
+
+A NULL for "name" indicates the end of the table, so for example an mpf
+table with nothing but addition could be
+
+        struct mpexpr_operator_t  table[] = {
+          { "+", (mpexpr_fun_t) mpf_add, MPEXPR_TYPE_BINARY, 190 },
+          { NULL }
+        };
+
+A special type MPEXPR_TYPE_NEW_TABLE makes it possible to chain from one
+table to another.  For example the following would add a "mod" operator to
+the standard mpz table,
+
+        struct mpexpr_operator_t  table[] = {
+        { "mod", (mpexpr_fun_t) mpz_fdiv_r, MPEXPR_TYPE_BINARY, 125 },
+        { (const char *) mpz_expr_standard_table, NULL, MPEXPR_TYPE_NEW_TABLE }
+        };
+
+Notice the low precedence on "mod", so that for instance "45+26 mod 7"
+parses as "(45+26)mod7".
+
+
+Functions are designated by a precedence of 0.  They always occur as
+"foo(expr)" and so have no need for a precedence level.  mpq_abs in the
+standard mpq table is
+
+	{ "abs", (mpexpr_fun_t) mpq_abs, MPEXPR_TYPE_UNARY },
+
+Functions expecting no arguments as in "foo()" can be given with
+MPEXPR_TYPE_0ARY, or actual constants to be parsed as just "foo" are
+MPEXPR_TYPE_CONSTANT.  For example if a "void mpf_const_pi(mpf_t f)"
+function existed (which it doesn't) it could be,
+
+	{ "pi", (mpexpr_fun_t) mpf_const_pi, MPEXPR_TYPE_CONSTANT },
+
+
+Parsing of operator names is done by seeking the table entry with the
+longest matching name.  So for instance operators "<" and "<=" exist, and
+when presented with "x <= y" the parser matches "<=" because it's longer.
+
+Parsing of function names, on the other hand, is done by requiring a whole
+alphanumeric word to match.  For example presented with "fib2zz(5)" the
+parser will attempt to find a function called "fib2zz".  A function "fib"
+wouldn't be used because it doesn't match the whole word.
+
+The flag MPEXPR_TYPE_WHOLEWORD can be ORed into an operator type to override
+the default parsing style.  Similarly MPEXPR_TYPE_OPERATOR into a function.
+
+
+Binary operators are left associative by default, meaning they're evaluated
+from left to right, so for example "1+2+3" is treated as "(1+2)+3".
+MPEXPR_TYPE_RIGHTASSOC can be ORed into the operator type to work from right
+to left as in "1+(2+3)".  This is generally what's wanted for
+exponentiation, and for example the standard mpz table has
+
+        { "**", (mpexpr_fun_t) mpz_pow_ui,
+          MPEXPR_TYPE_BINARY_UI | MPEXPR_TYPE_RIGHTASSOC, 220 }
+
+Unary operators are postfix by default.  For example a factorial to be used
+as "123!" might be
+
+	{ "!", (mpexpr_fun_t) mpz_fac_ui, MPEXPR_TYPE_UNARY_UI, 215 }
+
+MPEXPR_TYPE_PREFIX can be ORed into the type to get a prefix operator.  For
+instance negation (unary minus) in the standard mpf table is
+
+	{ "-", (mpexpr_fun_t) mpf_neg,
+          MPEXPR_TYPE_UNARY | MPEXPR_TYPE_PREFIX, 210 },
+
+
+The same operator can exist as a prefix unary and a binary, or as a prefix
+and postfix unary, simply by putting two entries in the table.  While
+parsing the context determines which style is sought.  But note that the
+same operator can't be both a postfix unary and a binary, since the parser
+doesn't try to look ahead to decide which ought to be used.
+
+When there's two entries for an operator, both prefix or both postfix (or
+binary), then the first in the table will be used.  This makes it possible
+to override an entry in a standard table, for example to change the function
+it calls, or perhaps its precedence level.  The following would change mpz
+division from tdiv to cdiv,
+
+        struct mpexpr_operator_t  table[] = {
+          { "/", (mpexpr_fun_t) mpz_cdiv_q, MPEXPR_TYPE_BINARY, 200 },
+          { "%", (mpexpr_fun_t) mpz_cdiv_r, MPEXPR_TYPE_BINARY, 200 },
+          { (char *) mpz_expr_standard_table, NULL, MPEXPR_TYPE_NEW_TABLE }
+        };
+
+
+The type field indicates what parameters the given function expects.  The
+following styles of functions are supported.  mpz_t is shown, but of course
+this is mpq_t for mpq_expr_a, mpf_t for mpf_expr_a, etc.
+
+    MPEXPR_TYPE_CONSTANT     void func (mpz_t result);
+
+    MPEXPR_TYPE_0ARY         void func (mpz_t result);
+    MPEXPR_TYPE_I_0ARY       int func (void);
+
+    MPEXPR_TYPE_UNARY        void func (mpz_t result, mpz_t op);
+    MPEXPR_TYPE_UNARY_UI     void func (mpz_t result, unsigned long op);
+    MPEXPR_TYPE_I_UNARY      int func (mpz_t op);
+    MPEXPR_TYPE_I_UNARY_UI   int func (unsigned long op);
+
+    MPEXPR_TYPE_BINARY       void func (mpz_t result, mpz_t op1, mpz_t op2);
+    MPEXPR_TYPE_BINARY_UI    void func (mpz_t result,
+                                        mpz_t op1, unsigned long op2);
+    MPEXPR_TYPE_I_BINARY     int func (mpz_t op1, mpz_t op2);
+    MPEXPR_TYPE_I_BINARY_UI  int func (mpz_t op1, unsigned long op2);
+
+    MPEXPR_TYPE_TERNARY      void func (mpz_t result,
+                                        mpz_t op1, mpz_t op2, mpz_t op3);
+    MPEXPR_TYPE_TERNARY_UI   void func (mpz_t result, mpz_t op1, mpz_t op2,
+                                        unsigned long op3);
+    MPEXPR_TYPE_I_TERNARY    int func (mpz_t op1, mpz_t op2, mpz_t op3);
+    MPEXPR_TYPE_I_TERNARY_UI int func (mpz_t op1, mpz_t op2,
+                                       unsigned long op3);
+
+Notice the pattern of "UI" for the last parameter as an unsigned long, or
+"I" for the result as an "int" return value.
+
+It's important that the declared type for an operator or function matches
+the function pointer given.  Any mismatch will have unpredictable results.
+
+For binary functions, a further type attribute is MPEXPR_TYPE_PAIRWISE which
+indicates that any number of arguments should be accepted, and evaluated by
+applying the given binary function to them pairwise.  This is used by gcd,
+lcm, min and max.  For example the standard mpz gcd is
+
+	{ "gcd", (mpexpr_fun_t) mpz_gcd,
+	  MPEXPR_TYPE_BINARY | MPEXPR_TYPE_PAIRWISE },
+
+Some special types exist for comparison operators (or functions).
+MPEXPR_TYPE_CMP_LT through MPEXPR_TYPE_CMP_GE expect an MPEXPR_TYPE_I_BINARY
+function, returning positive, negative or zero like mpz_cmp and similar.
+For example the standard mpf "!=" operator is
+
+	{ "!=", (mpexpr_fun_t) mpf_cmp, MPEXPR_TYPE_CMP_NE, 160 },
+
+But there's no obligation to use these types, for instance the standard mpq
+table just uses a plain MPEXPR_TYPE_I_BINARY and mpq_equal for "==".
+
+Further special types MPEXPR_TYPE_MIN and MPEXPR_TYPE_MAX exist to implement
+the min and max functions, and they take a function like mpf_cmp similarly.
+The standard mpf max function is
+
+	{ "max",  (mpexpr_fun_t) mpf_cmp,
+          MPEXPR_TYPE_MAX | MPEXPR_TYPE_PAIRWISE },
+
+These can be used as operators too, for instance the following would be the
+>? operator which is a feature of GNU C++,
+
+	{ ">?", (mpexpr_fun_t) mpf_cmp, MPEXPR_TYPE_MAX, 175 },
+
+Other special types are used to define "(" ")" parentheses, "," function
+argument separator, "!" through "||" logical booleans, ternary "?"  ":", and
+the "$" which introduces variables.  See the sources for how they should be
+used.
+
+
+User definable operator tables will have various uses.  For example,
+
+  - a subset of the C operators, to be rid of infrequently used things
+  - a more mathematical syntax like "." for multiply, "^" for powering,
+    and "!" for factorial
+  - a boolean evaluator with "^" for AND, "v" for OR
+  - variables introduced with "%" instead of "$"
+  - brackets as "[" and "]" instead of "(" and ")"
+
+The only fixed parts of the parsing are the treatment of numbers, whitespace
+and the two styles of operator/function name recognition.
+
+As a final example, the following would be a complete mpz table implementing
+some operators with a more mathematical syntax.  Notice there's no need to
+preserve the standard precedence values, anything can be used so long as
+they're in the desired relation to each other.  There's also no need to have
+entries in precedence order, but it's convenient to do so to show what comes
+where.
+
+        static const struct mpexpr_operator_t  table[] = {
+	  { "^",   (mpexpr_fun_t) mpz_pow_ui,
+            MPEXPR_TYPE_BINARY_UI | MPEXPR_TYPE_RIGHTASSOC,           9 },
+
+          { "!",   (mpexpr_fun_t) mpz_fac_ui, MPEXPR_TYPE_UNARY_UI,   8 },
+          { "-",   (mpexpr_fun_t) mpz_neg,
+            MPEXPR_TYPE_UNARY | MPEXPR_TYPE_PREFIX,                   7 },
+
+          { "*",   (mpexpr_fun_t) mpz_mul,    MPEXPR_TYPE_BINARY,     6 },
+          { "/",   (mpexpr_fun_t) mpz_fdiv_q, MPEXPR_TYPE_BINARY,     6 },
+
+          { "+",   (mpexpr_fun_t) mpz_add,    MPEXPR_TYPE_BINARY,     5 },
+          { "-",   (mpexpr_fun_t) mpz_sub,    MPEXPR_TYPE_BINARY,     5 },
+
+          { "mod", (mpexpr_fun_t) mpz_mod,    MPEXPR_TYPE_BINARY,     6 },
+
+          { ")",   NULL,                      MPEXPR_TYPE_CLOSEPAREN, 4 },
+          { "(",   NULL,                      MPEXPR_TYPE_OPENPAREN,  3 },
+          { ",",   NULL,                      MPEXPR_TYPE_ARGSEP,     2 },
+
+          { "$",   NULL,                      MPEXPR_TYPE_VARIABLE,   1 },
+          { NULL }
+        };
+
+
+
+
+INTERNALS
+
+Operator precedence is implemented using a control and data stack, there's
+no C recursion.  When an expression like 1+2*3 is read the "+" is held on
+the control stack and 1 on the data stack until "*" has been parsed and
+applied to 2 and 3.  This happens any time a higher precedence operator
+follows a lower one, or when a right-associative operator like "**" is
+repeated.
+
+Parentheses are handled by making "(" a special prefix unary with a low
+precedence so a whole following expression is read.  The special operator
+")" knows to discard the pending "(".  Function arguments are handled
+similarly, with the function pretending to be a low precedence prefix unary
+operator, and with "," allowed within functions.  The same special ")"
+operator recognises a pending function and will invoke it appropriately.
+
+The ternary "? :" operator is also handled using precedences.  ":" is one
+level higher than "?", so when a valid a?b:c is parsed the ":" finds a "?"
+on the control stack.  It's a parse error for ":" to find anything else.
+
+
+
+FUTURE
+
+The ternary "?:" operator evaluates the "false" side of its pair, which is
+wasteful, though it ought to be harmless.  It'd be better if it could
+evaluate only the "true" side.  Similarly for the logical booleans "&&" and
+"||" if they know their result already.
+
+Functions like MPEXPR_TYPE_BINARY could return a status indicating operand
+out of range or whatever, to get an error back through mpz_expr etc.  That
+would want to be just an option, since plain mpz_add etc have no such
+return.
+
+Could have assignments like "a = b*c" modifying the input variables.
+Assignment could be an operator attribute, making it expect an lvalue.
+There would want to be a standard table without assignments available
+though, so user input could be safely parsed.
+
+The closing parenthesis table entry could specify the type of open paren it
+expects, so that "(" and ")" could match and "[" and "]" match but not a
+mixture of the two.  Currently "[" and "]" can be added, but there's no
+error on writing a mixed expression like "2*(3+4]".  Maybe also there could
+be a way to say that functions can only be written with one or the other
+style of parens.
+
+
+
+----------------
+Local variables:
+mode: text
+fill-column: 76
+End:
diff --git a/third_party/gmp/demos/expr/expr-impl.h b/third_party/gmp/demos/expr/expr-impl.h
new file mode 100644
index 0000000..9b6458f
--- /dev/null
+++ b/third_party/gmp/demos/expr/expr-impl.h
@@ -0,0 +1,125 @@
+/* Implementation specifics for expression evaluation.
+
+Copyright 2000-2002, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+
+#include "expr.h"
+
+
+#define isasciidigit(c)   (isascii (c) && isdigit (c))
+#define isasciicsym(c)    (isascii (c) && (isalnum(c) || (c) == '_'))
+
+#define isasciidigit_in_base(c,base)                    \
+  (isascii (c)                                          \
+   && ((isdigit (c) && (c)-'0' < (base))                \
+       || (isupper (c) && (c)-'A'+10 < (base))          \
+       || (islower (c) && (c)-'a'+10 < (base))))
+
+
+union mpX_t {
+  mpz_t   z;
+  mpq_t   q;
+  mpf_t   f;
+};
+
+typedef union mpX_t *mpX_ptr;
+typedef const union mpX_t *mpX_srcptr;
+
+typedef void (*mpexpr_fun_one_t) (mpX_ptr);
+typedef unsigned long (*mpexpr_fun_ui_one_t) (mpX_ptr);
+
+typedef void (*mpexpr_fun_0ary_t) (mpX_ptr);
+typedef int  (*mpexpr_fun_i_0ary_t) (void);
+
+typedef void (*mpexpr_fun_unary_t) (mpX_ptr, mpX_srcptr);
+typedef void (*mpexpr_fun_unary_ui_t) (mpX_ptr, unsigned long);
+typedef int  (*mpexpr_fun_i_unary_t) (mpX_srcptr);
+typedef int  (*mpexpr_fun_i_unary_ui_t) (unsigned long);
+
+typedef void (*mpexpr_fun_binary_t) (mpX_ptr, mpX_srcptr, mpX_srcptr);
+typedef void (*mpexpr_fun_binary_ui_t) (mpX_ptr, mpX_srcptr, unsigned long);
+typedef int  (*mpexpr_fun_i_binary_t) (mpX_srcptr, mpX_srcptr);
+typedef int  (*mpexpr_fun_i_binary_ui_t) (mpX_srcptr, unsigned long);
+
+typedef void (*mpexpr_fun_ternary_t) (mpX_ptr, mpX_srcptr, mpX_srcptr, mpX_srcptr);
+typedef void (*mpexpr_fun_ternary_ui_t) (mpX_ptr, mpX_srcptr, mpX_srcptr, unsigned long);
+typedef int (*mpexpr_fun_i_ternary_t) (mpX_srcptr, mpX_srcptr, mpX_srcptr);
+typedef int (*mpexpr_fun_i_ternary_ui_t) (mpX_srcptr, mpX_srcptr, unsigned long);
+
+typedef size_t (*mpexpr_fun_number_t) (mpX_ptr, const char *str, size_t len, int base);
+typedef void (*mpexpr_fun_swap_t) (mpX_ptr, mpX_ptr);
+typedef unsigned long (*mpexpr_fun_get_ui_t) (mpX_srcptr);
+typedef void (*mpexpr_fun_set_si_t) (mpX_srcptr, long);
+
+struct mpexpr_control_t {
+  const struct mpexpr_operator_t  *op;
+  int                             argcount;
+};
+
+#define MPEXPR_VARIABLES  26
+
+struct mpexpr_parse_t {
+  const struct mpexpr_operator_t  *table;
+
+  mpX_ptr                         res;
+  int                             base;
+  unsigned long                   prec;
+  const char                      *e;
+  size_t                          elen;
+  mpX_srcptr                      *var;
+  int                             error_code;
+
+  int                             token;
+  const struct mpexpr_operator_t  *token_op;
+
+  union mpX_t                     *data_stack;
+  int                             data_top;
+  int                             data_alloc;
+  int                             data_inited;
+
+  struct mpexpr_control_t         *control_stack;
+  int                             control_top;
+  int                             control_alloc;
+
+  mpexpr_fun_0ary_t               mpX_clear;
+  mpexpr_fun_i_unary_t            mpX_ulong_p;
+  mpexpr_fun_get_ui_t             mpX_get_ui;
+  mpexpr_fun_unary_ui_t           mpX_init;
+  mpexpr_fun_number_t             mpX_number;
+  mpexpr_fun_unary_t              mpX_set;
+  mpexpr_fun_unary_t              mpX_set_or_swap;
+  mpexpr_fun_set_si_t             mpX_set_si;
+  mpexpr_fun_swap_t               mpX_swap;
+};
+
+
+int mpexpr_evaluate (struct mpexpr_parse_t *p);
+int mpexpr_va_to_var (void *var[], va_list ap);
+size_t mpexpr_mpz_number (mpz_ptr res, const char *e, size_t elen, int base);
diff --git a/third_party/gmp/demos/expr/expr.c b/third_party/gmp/demos/expr/expr.c
new file mode 100644
index 0000000..42dd796
--- /dev/null
+++ b/third_party/gmp/demos/expr/expr.c
@@ -0,0 +1,834 @@
+/* mpexpr_evaluate -- shared code for simple expression evaluation
+
+Copyright 2000-2002, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "gmp.h"
+#include "expr-impl.h"
+
+
+/* Change this to "#define TRACE(x) x" to get some traces.  The trace
+   printfs junk up the code a bit, but it's very hard to tell what's going
+   on without them.  Set MPX_TRACE to a suitable output function for the
+   mpz/mpq/mpf being run (if you have the wrong trace function it'll
+   probably segv).  */
+
+#define TRACE(x)
+#define MPX_TRACE  mpz_trace
+
+
+/* A few helper macros copied from gmp-impl.h */
+#define ALLOCATE_FUNC_TYPE(n,type) \
+  ((type *) (*allocate_func) ((n) * sizeof (type)))
+#define ALLOCATE_FUNC_LIMBS(n)   ALLOCATE_FUNC_TYPE (n, mp_limb_t)
+#define REALLOCATE_FUNC_TYPE(p, old_size, new_size, type) \
+  ((type *) (*reallocate_func)                            \
+   (p, (old_size) * sizeof (type), (new_size) * sizeof (type)))
+#define REALLOCATE_FUNC_LIMBS(p, old_size, new_size) \
+  REALLOCATE_FUNC_TYPE(p, old_size, new_size, mp_limb_t)
+#define FREE_FUNC_TYPE(p,n,type) (*free_func) (p, (n) * sizeof (type))
+#define FREE_FUNC_LIMBS(p,n)     FREE_FUNC_TYPE (p, n, mp_limb_t)
+#define ASSERT(x)
+
+
+
+/* All the error strings are just for diagnostic traces.  Only the error
+   code is actually returned.  */
+#define ERROR(str,code)                 \
+  {                                     \
+    TRACE (printf ("%s\n", str));       \
+    p->error_code = (code);             \
+    goto done;                          \
+  }
+
+
+#define REALLOC(ptr, alloc, incr, type)                         \
+  do {                                                          \
+    int  new_alloc = (alloc) + (incr);                          \
+    ptr = REALLOCATE_FUNC_TYPE (ptr, alloc, new_alloc, type);   \
+    (alloc) = new_alloc;                                        \
+  } while (0)
+
+
+/* data stack top element */
+#define SP   (p->data_stack + p->data_top)
+
+/* Make sure there's room for another data element above current top.
+   reallocate_func is fetched for when this macro is used in lookahead(). */
+#define DATA_SPACE()                                                    \
+  do {                                                                  \
+    if (p->data_top + 1 >= p->data_alloc)                               \
+      {                                                                 \
+	void *(*reallocate_func) (void *, size_t, size_t);              \
+	mp_get_memory_functions (NULL, &reallocate_func, NULL);         \
+	TRACE (printf ("grow stack from %d\n", p->data_alloc));         \
+	REALLOC (p->data_stack, p->data_alloc, 20, union mpX_t);        \
+      }                                                                 \
+    ASSERT (p->data_top + 1 <= p->data_inited);                         \
+    if (p->data_top + 1 == p->data_inited)                              \
+      {                                                                 \
+	TRACE (printf ("initialize %d\n", p->data_top + 1));            \
+	(*p->mpX_init) (&p->data_stack[p->data_top + 1], p->prec);      \
+	p->data_inited++;                                               \
+      }                                                                 \
+  } while (0)
+
+#define DATA_PUSH()                             \
+  do {                                          \
+    p->data_top++;                              \
+    ASSERT (p->data_top < p->data_alloc);       \
+    ASSERT (p->data_top < p->data_inited);      \
+  } while (0)
+
+/* the last stack entry is never popped, so top>=0 will be true */
+#define DATA_POP(n)             \
+  do {                          \
+    p->data_top -= (n);         \
+    ASSERT (p->data_top >= 0);  \
+  } while (0)
+
+
+/* lookahead() parses the next token.  Return 1 if successful, with some
+   extra data.  Return 0 if fail, with reason in p->error_code.
+
+   "prefix" is MPEXPR_TYPE_PREFIX if an operator with that attribute is
+   preferred, or 0 if an operator without is preferred. */
+
+#define TOKEN_EOF         -1   /* no extra data */
+#define TOKEN_VALUE       -2   /* pushed onto data stack */
+#define TOKEN_OPERATOR    -3   /* stored in p->token_op */
+#define TOKEN_FUNCTION    -4   /* stored in p->token_op */
+
+#define TOKEN_NAME(n)                           \
+  ((n) == TOKEN_EOF ? "TOKEN_EOF"               \
+   : (n) == TOKEN_VALUE ? "TOKEN_VALUE"         \
+   : (n) == TOKEN_OPERATOR ? "TOKEN_OPERATOR"   \
+   : (n) == TOKEN_VALUE ? "TOKEN_FUNCTION"      \
+   : "UNKNOWN TOKEN")
+
+/* Functions default to being parsed as whole words, operators to match just
+   at the start of the string.  The type flags override this. */
+#define WHOLEWORD(op)                           \
+  (op->precedence == 0                          \
+   ? (! (op->type & MPEXPR_TYPE_OPERATOR))      \
+   :   (op->type & MPEXPR_TYPE_WHOLEWORD))
+
+#define isasciispace(c)   (isascii (c) && isspace (c))
+
+static int
+lookahead (struct mpexpr_parse_t *p, int prefix)
+{
+  const struct mpexpr_operator_t  *op, *op_found;
+  size_t  oplen, oplen_found, wlen;
+  int     i;
+
+  /* skip white space */
+  while (p->elen > 0 && isasciispace (*p->e))
+    p->e++, p->elen--;
+
+  if (p->elen == 0)
+    {
+      TRACE (printf ("lookahead EOF\n"));
+      p->token = TOKEN_EOF;
+      return 1;
+    }
+
+  DATA_SPACE ();
+
+  /* Get extent of whole word. */
+  for (wlen = 0; wlen < p->elen; wlen++)
+    if (! isasciicsym (p->e[wlen]))
+      break;
+
+  TRACE (printf ("lookahead at: \"%.*s\" length %u, word %u\n",
+		 (int) p->elen, p->e, p->elen, wlen));
+
+  op_found = NULL;
+  oplen_found = 0;
+  for (op = p->table; op->name != NULL; op++)
+    {
+      if (op->type == MPEXPR_TYPE_NEW_TABLE)
+	{
+	  printf ("new\n");
+	  op = (struct mpexpr_operator_t *) op->name - 1;
+	  continue;
+	}
+
+      oplen = strlen (op->name);
+      if (! ((WHOLEWORD (op) ? wlen == oplen : p->elen >= oplen)
+	     && memcmp (p->e, op->name, oplen) == 0))
+	continue;
+
+      /* Shorter matches don't replace longer previous ones. */
+      if (op_found && oplen < oplen_found)
+	continue;
+
+      /* On a match of equal length to a previous one, the old match isn't
+	 replaced if it has the preferred prefix, and if it doesn't then
+	 it's not replaced if the new one also doesn't.  */
+      if (op_found && oplen == oplen_found
+	  && ((op_found->type & MPEXPR_TYPE_PREFIX) == prefix
+	      || (op->type & MPEXPR_TYPE_PREFIX) != prefix))
+	continue;
+
+      /* This is now either the first match seen, or a longer than previous
+	 match, or an equal to previous one but with a preferred prefix. */
+      op_found = op;
+      oplen_found = oplen;
+    }
+
+  if (op_found)
+    {
+      p->e += oplen_found, p->elen -= oplen_found;
+
+      if (op_found->type == MPEXPR_TYPE_VARIABLE)
+	{
+	  if (p->elen == 0)
+	    ERROR ("end of string expecting a variable",
+		   MPEXPR_RESULT_PARSE_ERROR);
+	  i = p->e[0] - 'a';
+	  if (i < 0 || i >= MPEXPR_VARIABLES)
+	    ERROR ("bad variable name", MPEXPR_RESULT_BAD_VARIABLE);
+	  goto variable;
+	}
+
+      if (op_found->precedence == 0)
+	{
+	  TRACE (printf ("lookahead function: %s\n", op_found->name));
+	  p->token = TOKEN_FUNCTION;
+	  p->token_op = op_found;
+	  return 1;
+	}
+      else
+	{
+	  TRACE (printf ("lookahead operator: %s\n", op_found->name));
+	  p->token = TOKEN_OPERATOR;
+	  p->token_op = op_found;
+	  return 1;
+	}
+    }
+
+  oplen = (*p->mpX_number) (SP+1, p->e, p->elen, p->base);
+  if (oplen != 0)
+    {
+      p->e += oplen, p->elen -= oplen;
+      p->token = TOKEN_VALUE;
+      DATA_PUSH ();
+      TRACE (MPX_TRACE ("lookahead number", SP));
+      return 1;
+    }
+
+  /* Maybe an unprefixed one character variable */
+  i = p->e[0] - 'a';
+  if (wlen == 1 && i >= 0 && i < MPEXPR_VARIABLES)
+    {
+    variable:
+      p->e++, p->elen--;
+      if (p->var[i] == NULL)
+	ERROR ("NULL variable", MPEXPR_RESULT_BAD_VARIABLE);
+      TRACE (printf ("lookahead variable: var[%d] = ", i);
+	     MPX_TRACE ("", p->var[i]));
+      p->token = TOKEN_VALUE;
+      DATA_PUSH ();
+      (*p->mpX_set) (SP, p->var[i]);
+      return 1;
+    }
+
+  ERROR ("no token matched", MPEXPR_RESULT_PARSE_ERROR);
+
+ done:
+  return 0;
+}
+
+
+/* control stack current top element */
+#define CP   (p->control_stack + p->control_top)
+
+/* make sure there's room for another control element above current top */
+#define CONTROL_SPACE()                                                    \
+  do {                                                                     \
+    if (p->control_top + 1 >= p->control_alloc)                            \
+      {                                                                    \
+	TRACE (printf ("grow control stack from %d\n", p->control_alloc)); \
+	REALLOC (p->control_stack, p->control_alloc, 20,                   \
+		 struct mpexpr_control_t);                                 \
+      }                                                                    \
+  } while (0)
+
+/* Push an operator on the control stack, claiming currently to have the
+   given number of args ready.  Local variable "op" is used in case opptr is
+   a reference through CP.  */
+#define CONTROL_PUSH(opptr,args)                        \
+  do {                                                  \
+    const struct mpexpr_operator_t *op = opptr;		\
+    struct mpexpr_control_t *cp;                        \
+    CONTROL_SPACE ();                                   \
+    p->control_top++;                                   \
+    ASSERT (p->control_top < p->control_alloc);         \
+    cp = CP;                                            \
+    cp->op = op;                                        \
+    cp->argcount = (args);                              \
+    TRACE_CONTROL("control stack push:");               \
+  } while (0)
+
+/* The special operator_done is never popped, so top>=0 will hold. */
+#define CONTROL_POP()                           \
+  do {                                          \
+    p->control_top--;                           \
+    ASSERT (p->control_top >= 0);               \
+    TRACE_CONTROL ("control stack pop:");       \
+  } while (0)
+
+#define TRACE_CONTROL(str)                              \
+  TRACE ({                                              \
+    int  i;                                             \
+    printf ("%s depth %d:", str, p->control_top);       \
+    for (i = 0; i <= p->control_top; i++)               \
+      printf (" \"%s\"(%d)",                            \
+	      p->control_stack[i].op->name,             \
+	      p->control_stack[i].argcount);            \
+    printf ("\n");                                      \
+  });
+
+
+#define LOOKAHEAD(prefix)               \
+  do {                                  \
+    if (! lookahead (p, prefix))        \
+      goto done;                        \
+  } while (0)
+
+#define CHECK_UI(n)                                                     \
+  do {                                                                  \
+    if (! (*p->mpX_ulong_p) (n))                                        \
+      ERROR ("operand doesn't fit ulong", MPEXPR_RESULT_NOT_UI);        \
+  } while (0)
+
+#define CHECK_ARGCOUNT(str,n)                                              \
+  do {                                                                     \
+    if (CP->argcount != (n))                                               \
+      {                                                                    \
+	TRACE (printf ("wrong number of arguments for %s, got %d want %d", \
+		       str, CP->argcount, n));                             \
+	ERROR ("", MPEXPR_RESULT_PARSE_ERROR);                             \
+      }                                                                    \
+  } while (0)
+
+
+/* There's two basic states here.  In both p->token is the next token.
+
+   "another_expr" is when a whole expression should be parsed.  This means a
+   literal or variable value possibly followed by an operator, or a function
+   or prefix operator followed by a further whole expression.
+
+   "another_operator" is when an expression has been parsed and its value is
+   on the top of the data stack (SP) and an optional further postfix or
+   infix operator should be parsed.
+
+   In "another_operator" precedences determine whether to push the operator
+   onto the control stack, or instead go to "apply_control" to reduce the
+   operator currently on top of the control stack.
+
+   When an operator has both a prefix and postfix/infix form, a LOOKAHEAD()
+   for "another_expr" will seek the prefix form, a LOOKAHEAD() for
+   "another_operator" will seek the postfix/infix form.  The grammar is
+   simple enough that the next state is known before reading the next token.
+
+   Argument count checking guards against functions consuming the wrong
+   number of operands from the data stack.  The same checks are applied to
+   operators, but will always pass since a UNARY or BINARY will only ever
+   parse with the correct operands.  */
+
+int
+mpexpr_evaluate (struct mpexpr_parse_t *p)
+{
+  void *(*allocate_func) (size_t);
+  void *(*reallocate_func) (void *, size_t, size_t);
+  void (*free_func) (void *, size_t);
+
+  mp_get_memory_functions (&allocate_func, &reallocate_func, &free_func);
+
+  TRACE (printf ("mpexpr_evaluate() base %d \"%.*s\"\n",
+		 p->base, (int) p->elen, p->e));
+
+  /* "done" is a special sentinel at the bottom of the control stack,
+     precedence -1 is lower than any normal operator.  */
+  {
+    static const struct mpexpr_operator_t  operator_done
+      = { "DONE", NULL, MPEXPR_TYPE_DONE, -1 };
+
+    p->control_alloc = 20;
+    p->control_stack = ALLOCATE_FUNC_TYPE (p->control_alloc,
+					   struct mpexpr_control_t);
+    p->control_top = 0;
+    CP->op = &operator_done;
+    CP->argcount = 1;
+  }
+
+  p->data_inited = 0;
+  p->data_alloc = 20;
+  p->data_stack = ALLOCATE_FUNC_TYPE (p->data_alloc, union mpX_t);
+  p->data_top = -1;
+
+  p->error_code = MPEXPR_RESULT_OK;
+
+
+ another_expr_lookahead:
+  LOOKAHEAD (MPEXPR_TYPE_PREFIX);
+  TRACE (printf ("another expr\n"));
+
+  /*another_expr:*/
+  switch (p->token) {
+  case TOKEN_VALUE:
+    goto another_operator_lookahead;
+
+  case TOKEN_OPERATOR:
+    TRACE (printf ("operator %s\n", p->token_op->name));
+    if (! (p->token_op->type & MPEXPR_TYPE_PREFIX))
+      ERROR ("expected a prefix operator", MPEXPR_RESULT_PARSE_ERROR);
+
+    CONTROL_PUSH (p->token_op, 1);
+    goto another_expr_lookahead;
+
+  case TOKEN_FUNCTION:
+    CONTROL_PUSH (p->token_op, 1);
+
+    if (p->token_op->type & MPEXPR_TYPE_CONSTANT)
+      goto apply_control_lookahead;
+
+    LOOKAHEAD (MPEXPR_TYPE_PREFIX);
+    if (! (p->token == TOKEN_OPERATOR
+	   && p->token_op->type == MPEXPR_TYPE_OPENPAREN))
+      ERROR ("expected open paren for function", MPEXPR_RESULT_PARSE_ERROR);
+
+    TRACE (printf ("open paren for function \"%s\"\n", CP->op->name));
+
+    if ((CP->op->type & MPEXPR_TYPE_MASK_ARGCOUNT) == MPEXPR_TYPE_NARY(0))
+      {
+	LOOKAHEAD (0);
+	if (! (p->token == TOKEN_OPERATOR
+	       && p->token_op->type == MPEXPR_TYPE_CLOSEPAREN))
+	  ERROR ("expected close paren for 0ary function",
+		 MPEXPR_RESULT_PARSE_ERROR);
+	goto apply_control_lookahead;
+      }
+
+    goto another_expr_lookahead;
+  }
+  ERROR ("unrecognised start of expression", MPEXPR_RESULT_PARSE_ERROR);
+
+
+ another_operator_lookahead:
+  LOOKAHEAD (0);
+ another_operator:
+  TRACE (printf ("another operator maybe: %s\n", TOKEN_NAME(p->token)));
+
+  switch (p->token) {
+  case TOKEN_EOF:
+    goto apply_control;
+
+  case TOKEN_OPERATOR:
+    /* The next operator is compared to the one on top of the control stack.
+       If the next is lower precedence, or the same precedence and not
+       right-associative, then reduce using the control stack and look at
+       the next operator again later.  */
+
+#define PRECEDENCE_TEST_REDUCE(tprec,cprec,ttype,ctype)                 \
+    ((tprec) < (cprec)                                                  \
+     || ((tprec) == (cprec) && ! ((ttype) & MPEXPR_TYPE_RIGHTASSOC)))
+
+    if (PRECEDENCE_TEST_REDUCE (p->token_op->precedence, CP->op->precedence,
+				p->token_op->type,       CP->op->type))
+      {
+	TRACE (printf ("defer operator: %s (prec %d vs %d, type 0x%X)\n",
+		       p->token_op->name,
+		       p->token_op->precedence, CP->op->precedence,
+		       p->token_op->type));
+	goto apply_control;
+      }
+
+    /* An argsep is a binary operator, but is never pushed on the control
+       stack, it just accumulates an extra argument for a function. */
+    if (p->token_op->type == MPEXPR_TYPE_ARGSEP)
+      {
+	if (CP->op->precedence != 0)
+	  ERROR ("ARGSEP not in a function call", MPEXPR_RESULT_PARSE_ERROR);
+
+	TRACE (printf ("argsep for function \"%s\"(%d)\n",
+		       CP->op->name, CP->argcount));
+
+#define IS_PAIRWISE(type)                                               \
+	(((type) & (MPEXPR_TYPE_MASK_ARGCOUNT | MPEXPR_TYPE_PAIRWISE))  \
+	 == (MPEXPR_TYPE_BINARY | MPEXPR_TYPE_PAIRWISE))
+
+	if (IS_PAIRWISE (CP->op->type) && CP->argcount >= 2)
+	  {
+	    TRACE (printf ("    will reduce pairwise now\n"));
+	    CP->argcount--;
+	    CONTROL_PUSH (CP->op, 2);
+	    goto apply_control;
+	  }
+
+	CP->argcount++;
+	goto another_expr_lookahead;
+      }
+
+    switch (p->token_op->type & MPEXPR_TYPE_MASK_ARGCOUNT) {
+    case MPEXPR_TYPE_NARY(1):
+      /* Postfix unary operators can always be applied immediately.  The
+	 easiest way to do this is just push it on the control stack and go
+	 to the normal control stack reduction code. */
+
+      TRACE (printf ("postfix unary operator: %s\n", p->token_op->name));
+      if (p->token_op->type & MPEXPR_TYPE_PREFIX)
+	ERROR ("prefix unary operator used postfix",
+	       MPEXPR_RESULT_PARSE_ERROR);
+      CONTROL_PUSH (p->token_op, 1);
+      goto apply_control_lookahead;
+
+    case MPEXPR_TYPE_NARY(2):
+      CONTROL_PUSH (p->token_op, 2);
+      goto another_expr_lookahead;
+
+    case MPEXPR_TYPE_NARY(3):
+      CONTROL_PUSH (p->token_op, 1);
+      goto another_expr_lookahead;
+    }
+
+    TRACE (printf ("unrecognised operator \"%s\" type: 0x%X",
+		   CP->op->name, CP->op->type));
+    ERROR ("", MPEXPR_RESULT_PARSE_ERROR);
+    break;
+
+  default:
+    TRACE (printf ("expecting an operator, got token %d", p->token));
+    ERROR ("", MPEXPR_RESULT_PARSE_ERROR);
+  }
+
+
+ apply_control_lookahead:
+  LOOKAHEAD (0);
+ apply_control:
+  /* Apply the top element CP of the control stack.  Data values are SP,
+     SP-1, etc.  Result is left as stack top SP after popping consumed
+     values.
+
+     The use of sp as a duplicate of SP will help compilers that can't
+     otherwise recognise the various uses of SP as common subexpressions.  */
+
+  TRACE (printf ("apply control: nested %d, \"%s\" 0x%X, %d args\n",
+		 p->control_top, CP->op->name, CP->op->type, CP->argcount));
+
+  TRACE (printf ("apply 0x%X-ary\n",
+		 CP->op->type & MPEXPR_TYPE_MASK_ARGCOUNT));
+  switch (CP->op->type & MPEXPR_TYPE_MASK_ARGCOUNT) {
+  case MPEXPR_TYPE_NARY(0):
+    {
+      mpX_ptr  sp;
+      DATA_SPACE ();
+      DATA_PUSH ();
+      sp = SP;
+      switch (CP->op->type & MPEXPR_TYPE_MASK_ARGSTYLE) {
+      case 0:
+	(* (mpexpr_fun_0ary_t) CP->op->fun) (sp);
+	break;
+      case MPEXPR_TYPE_RESULT_INT:
+	(*p->mpX_set_si) (sp, (long) (* (mpexpr_fun_i_0ary_t) CP->op->fun) ());
+	break;
+      default:
+	ERROR ("unrecognised 0ary argument calling style",
+	       MPEXPR_RESULT_BAD_TABLE);
+      }
+    }
+    break;
+
+  case MPEXPR_TYPE_NARY(1):
+    {
+      mpX_ptr  sp = SP;
+      CHECK_ARGCOUNT ("unary", 1);
+      TRACE (MPX_TRACE ("before", sp));
+
+      switch (CP->op->type & MPEXPR_TYPE_MASK_SPECIAL) {
+      case 0:
+	/* not a special */
+	break;
+
+      case MPEXPR_TYPE_DONE & MPEXPR_TYPE_MASK_SPECIAL:
+	TRACE (printf ("special done\n"));
+	goto done;
+
+      case MPEXPR_TYPE_LOGICAL_NOT & MPEXPR_TYPE_MASK_SPECIAL:
+	TRACE (printf ("special logical not\n"));
+	(*p->mpX_set_si)
+	  (sp, (long) ((* (mpexpr_fun_i_unary_t) CP->op->fun) (sp) == 0));
+	goto apply_control_done;
+
+      case MPEXPR_TYPE_CLOSEPAREN & MPEXPR_TYPE_MASK_SPECIAL:
+	CONTROL_POP ();
+	if (CP->op->type == MPEXPR_TYPE_OPENPAREN)
+	  {
+	    TRACE (printf ("close paren matching open paren\n"));
+	    CONTROL_POP ();
+	    goto another_operator;
+	  }
+	if (CP->op->precedence == 0)
+	  {
+	    TRACE (printf ("close paren for function\n"));
+	    goto apply_control;
+	  }
+	ERROR ("unexpected close paren", MPEXPR_RESULT_PARSE_ERROR);
+
+      default:
+	TRACE (printf ("unrecognised special unary operator 0x%X",
+		       CP->op->type & MPEXPR_TYPE_MASK_SPECIAL));
+	ERROR ("", MPEXPR_RESULT_BAD_TABLE);
+      }
+
+      switch (CP->op->type & MPEXPR_TYPE_MASK_ARGSTYLE) {
+      case 0:
+	(* (mpexpr_fun_unary_t) CP->op->fun) (sp, sp);
+	break;
+      case MPEXPR_TYPE_LAST_UI:
+	CHECK_UI (sp);
+	(* (mpexpr_fun_unary_ui_t) CP->op->fun)
+	  (sp, (*p->mpX_get_ui) (sp));
+	break;
+      case MPEXPR_TYPE_RESULT_INT:
+	(*p->mpX_set_si)
+	  (sp, (long) (* (mpexpr_fun_i_unary_t) CP->op->fun) (sp));
+	break;
+      case MPEXPR_TYPE_RESULT_INT | MPEXPR_TYPE_LAST_UI:
+	CHECK_UI (sp);
+	(*p->mpX_set_si)
+	  (sp,
+	   (long) (* (mpexpr_fun_i_unary_ui_t) CP->op->fun)
+	   ((*p->mpX_get_ui) (sp)));
+	break;
+      default:
+	ERROR ("unrecognised unary argument calling style",
+	       MPEXPR_RESULT_BAD_TABLE);
+      }
+    }
+    break;
+
+  case MPEXPR_TYPE_NARY(2):
+    {
+      mpX_ptr  sp;
+
+      /* pairwise functions are allowed to have just one argument */
+      if ((CP->op->type & MPEXPR_TYPE_PAIRWISE)
+	  && CP->op->precedence == 0
+	  && CP->argcount == 1)
+	goto apply_control_done;
+
+      CHECK_ARGCOUNT ("binary", 2);
+      DATA_POP (1);
+      sp = SP;
+      TRACE (MPX_TRACE ("lhs", sp);
+	     MPX_TRACE ("rhs", sp+1));
+
+      if (CP->op->type & MPEXPR_TYPE_MASK_CMP)
+	{
+	  int  type = CP->op->type;
+	  int  cmp = (* (mpexpr_fun_i_binary_t) CP->op->fun)
+	    (sp, sp+1);
+	  (*p->mpX_set_si)
+	    (sp,
+	     (long)
+	     ((  (cmp  < 0) & ((type & MPEXPR_TYPE_MASK_CMP_LT) != 0))
+	      | ((cmp == 0) & ((type & MPEXPR_TYPE_MASK_CMP_EQ) != 0))
+	      | ((cmp  > 0) & ((type & MPEXPR_TYPE_MASK_CMP_GT) != 0))));
+	  goto apply_control_done;
+	}
+
+      switch (CP->op->type & MPEXPR_TYPE_MASK_SPECIAL) {
+      case 0:
+	/* not a special */
+	break;
+
+      case MPEXPR_TYPE_QUESTION & MPEXPR_TYPE_MASK_SPECIAL:
+	ERROR ("'?' without ':'", MPEXPR_RESULT_PARSE_ERROR);
+
+      case MPEXPR_TYPE_COLON & MPEXPR_TYPE_MASK_SPECIAL:
+	TRACE (printf ("special colon\n"));
+	CONTROL_POP ();
+	if (CP->op->type != MPEXPR_TYPE_QUESTION)
+	  ERROR ("':' without '?'", MPEXPR_RESULT_PARSE_ERROR);
+
+	CP->argcount--;
+	DATA_POP (1);
+	sp--;
+	TRACE (MPX_TRACE ("query", sp);
+	       MPX_TRACE ("true",  sp+1);
+	       MPX_TRACE ("false", sp+2));
+	(*p->mpX_set)
+	  (sp, (* (mpexpr_fun_i_unary_t) CP->op->fun) (sp)
+	   ? sp+1 : sp+2);
+	goto apply_control_done;
+
+      case MPEXPR_TYPE_LOGICAL_AND & MPEXPR_TYPE_MASK_SPECIAL:
+	TRACE (printf ("special logical and\n"));
+	(*p->mpX_set_si)
+	  (sp,
+	   (long)
+	   ((* (mpexpr_fun_i_unary_t) CP->op->fun) (sp)
+	    && (* (mpexpr_fun_i_unary_t) CP->op->fun) (sp+1)));
+	goto apply_control_done;
+
+      case MPEXPR_TYPE_LOGICAL_OR & MPEXPR_TYPE_MASK_SPECIAL:
+	TRACE (printf ("special logical and\n"));
+	(*p->mpX_set_si)
+	  (sp,
+	   (long)
+	   ((* (mpexpr_fun_i_unary_t) CP->op->fun) (sp)
+	    || (* (mpexpr_fun_i_unary_t) CP->op->fun) (sp+1)));
+	goto apply_control_done;
+
+      case MPEXPR_TYPE_MAX & MPEXPR_TYPE_MASK_SPECIAL:
+	TRACE (printf ("special max\n"));
+	if ((* (mpexpr_fun_i_binary_t) CP->op->fun) (sp, sp+1) < 0)
+	  (*p->mpX_swap) (sp, sp+1);
+	goto apply_control_done;
+      case MPEXPR_TYPE_MIN & MPEXPR_TYPE_MASK_SPECIAL:
+	TRACE (printf ("special min\n"));
+	if ((* (mpexpr_fun_i_binary_t) CP->op->fun) (sp, sp+1) > 0)
+	  (*p->mpX_swap) (sp, sp+1);
+	goto apply_control_done;
+
+      default:
+	ERROR ("unrecognised special binary operator",
+	       MPEXPR_RESULT_BAD_TABLE);
+      }
+
+      switch (CP->op->type & MPEXPR_TYPE_MASK_ARGSTYLE) {
+      case 0:
+	(* (mpexpr_fun_binary_t) CP->op->fun) (sp, sp, sp+1);
+	break;
+      case MPEXPR_TYPE_LAST_UI:
+	CHECK_UI (sp+1);
+	(* (mpexpr_fun_binary_ui_t) CP->op->fun)
+	  (sp, sp, (*p->mpX_get_ui) (sp+1));
+	break;
+      case MPEXPR_TYPE_RESULT_INT:
+	(*p->mpX_set_si)
+	  (sp,
+	   (long) (* (mpexpr_fun_i_binary_t) CP->op->fun) (sp, sp+1));
+	break;
+      case MPEXPR_TYPE_LAST_UI | MPEXPR_TYPE_RESULT_INT:
+	CHECK_UI (sp+1);
+	(*p->mpX_set_si)
+	  (sp,
+	   (long) (* (mpexpr_fun_i_binary_ui_t) CP->op->fun)
+	   (sp, (*p->mpX_get_ui) (sp+1)));
+	break;
+      default:
+	ERROR ("unrecognised binary argument calling style",
+	       MPEXPR_RESULT_BAD_TABLE);
+      }
+    }
+    break;
+
+  case MPEXPR_TYPE_NARY(3):
+    {
+      mpX_ptr  sp;
+
+      CHECK_ARGCOUNT ("ternary", 3);
+      DATA_POP (2);
+      sp = SP;
+      TRACE (MPX_TRACE ("arg1", sp);
+	     MPX_TRACE ("arg2", sp+1);
+	     MPX_TRACE ("arg3", sp+1));
+
+      switch (CP->op->type & MPEXPR_TYPE_MASK_ARGSTYLE) {
+      case 0:
+	(* (mpexpr_fun_ternary_t) CP->op->fun) (sp, sp, sp+1, sp+2);
+	break;
+      case MPEXPR_TYPE_LAST_UI:
+	CHECK_UI (sp+2);
+	(* (mpexpr_fun_ternary_ui_t) CP->op->fun)
+	  (sp, sp, sp+1, (*p->mpX_get_ui) (sp+2));
+	break;
+      case MPEXPR_TYPE_RESULT_INT:
+	(*p->mpX_set_si)
+	  (sp,
+	   (long) (* (mpexpr_fun_i_ternary_t) CP->op->fun)
+	   (sp, sp+1, sp+2));
+	break;
+      case MPEXPR_TYPE_LAST_UI | MPEXPR_TYPE_RESULT_INT:
+	CHECK_UI (sp+2);
+	(*p->mpX_set_si)
+	  (sp,
+	   (long) (* (mpexpr_fun_i_ternary_ui_t) CP->op->fun)
+	   (sp, sp+1, (*p->mpX_get_ui) (sp+2)));
+	break;
+      default:
+	ERROR ("unrecognised binary argument calling style",
+	       MPEXPR_RESULT_BAD_TABLE);
+      }
+    }
+    break;
+
+  default:
+    TRACE (printf ("unrecognised operator type: 0x%X\n", CP->op->type));
+    ERROR ("", MPEXPR_RESULT_PARSE_ERROR);
+  }
+
+ apply_control_done:
+  TRACE (MPX_TRACE ("result", SP));
+  CONTROL_POP ();
+  goto another_operator;
+
+ done:
+  if (p->error_code == MPEXPR_RESULT_OK)
+    {
+      if (p->data_top != 0)
+	{
+	  TRACE (printf ("data stack want top at 0, got %d\n", p->data_top));
+	  p->error_code = MPEXPR_RESULT_PARSE_ERROR;
+	}
+      else
+	(*p->mpX_set_or_swap) (p->res, SP);
+    }
+
+  {
+    int  i;
+    for (i = 0; i < p->data_inited; i++)
+      {
+	TRACE (printf ("clear %d\n", i));
+	(*p->mpX_clear) (p->data_stack+i);
+      }
+  }
+
+  FREE_FUNC_TYPE (p->data_stack, p->data_alloc, union mpX_t);
+  FREE_FUNC_TYPE (p->control_stack, p->control_alloc, struct mpexpr_control_t);
+
+  return p->error_code;
+}
diff --git a/third_party/gmp/demos/expr/expr.h b/third_party/gmp/demos/expr/expr.h
new file mode 100644
index 0000000..d3b7c77
--- /dev/null
+++ b/third_party/gmp/demos/expr/expr.h
@@ -0,0 +1,142 @@
+/* Header for expression evaluation.
+
+Copyright 2000-2002, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#ifndef __EXPR_H__
+#define __EXPR_H__
+
+#define MPEXPR_RESULT_OK            0
+#define MPEXPR_RESULT_BAD_VARIABLE  1
+#define MPEXPR_RESULT_BAD_TABLE     2
+#define MPEXPR_RESULT_PARSE_ERROR   3
+#define MPEXPR_RESULT_NOT_UI        4
+
+
+/* basic types */
+#define MPEXPR_TYPE_NARY(n)       ((n) * 0x0100)
+#define MPEXPR_TYPE_MASK_ARGCOUNT MPEXPR_TYPE_NARY(0xF)
+#define MPEXPR_TYPE_0ARY          MPEXPR_TYPE_NARY(0)
+#define MPEXPR_TYPE_UNARY         MPEXPR_TYPE_NARY(1)
+#define MPEXPR_TYPE_BINARY        MPEXPR_TYPE_NARY(2)
+#define MPEXPR_TYPE_TERNARY       MPEXPR_TYPE_NARY(3)
+
+/* options for all */
+#define MPEXPR_TYPE_LAST_UI       0x0010
+#define MPEXPR_TYPE_RESULT_INT    0x0020
+#define MPEXPR_TYPE_MASK_ARGSTYLE 0x0030
+
+#define MPEXPR_TYPE_UNARY_UI     (MPEXPR_TYPE_UNARY   | MPEXPR_TYPE_LAST_UI)
+#define MPEXPR_TYPE_I_UNARY      (MPEXPR_TYPE_UNARY   | MPEXPR_TYPE_RESULT_INT)
+#define MPEXPR_TYPE_I_UNARY_UI   (MPEXPR_TYPE_I_UNARY | MPEXPR_TYPE_LAST_UI)
+#define MPEXPR_TYPE_BINARY_UI    (MPEXPR_TYPE_BINARY  | MPEXPR_TYPE_LAST_UI)
+#define MPEXPR_TYPE_I_BINARY     (MPEXPR_TYPE_BINARY  | MPEXPR_TYPE_RESULT_INT)
+#define MPEXPR_TYPE_I_BINARY_UI  (MPEXPR_TYPE_I_BINARY| MPEXPR_TYPE_LAST_UI)
+#define MPEXPR_TYPE_TERNARY_UI   (MPEXPR_TYPE_TERNARY | MPEXPR_TYPE_LAST_UI)
+#define MPEXPR_TYPE_I_TERNARY    (MPEXPR_TYPE_TERNARY | MPEXPR_TYPE_RESULT_INT)
+#define MPEXPR_TYPE_I_TERNARY_UI (MPEXPR_TYPE_I_TERNARY|MPEXPR_TYPE_LAST_UI)
+
+/* 0ary with options */
+#define MPEXPR_TYPE_CONSTANT      (MPEXPR_TYPE_0ARY | 0x0040)
+
+/* unary options */
+#define MPEXPR_TYPE_PREFIX        0x0040
+
+/* binary options */
+#define MPEXPR_TYPE_RIGHTASSOC    0x0040
+#define MPEXPR_TYPE_PAIRWISE      0x0080
+
+#define MPEXPR_TYPE_MASK_SPECIAL  0x000F
+
+/* unary specials */
+#define MPEXPR_TYPE_NEW_TABLE     (MPEXPR_TYPE_UNARY | 0x001)
+#define MPEXPR_TYPE_DONE          (MPEXPR_TYPE_UNARY | 0x002)
+#define MPEXPR_TYPE_VARIABLE      (MPEXPR_TYPE_UNARY | 0x003)
+#define MPEXPR_TYPE_LOGICAL_NOT   (MPEXPR_TYPE_UNARY | 0x004)
+#define MPEXPR_TYPE_CLOSEPAREN    (MPEXPR_TYPE_UNARY | 0x005)
+#define MPEXPR_TYPE_OPENPAREN     (MPEXPR_TYPE_CLOSEPAREN | MPEXPR_TYPE_PREFIX)
+
+/* binary specials */
+#define MPEXPR_TYPE_LOGICAL_AND   (MPEXPR_TYPE_BINARY | 0x001)
+#define MPEXPR_TYPE_LOGICAL_OR    (MPEXPR_TYPE_BINARY | 0x002)
+#define MPEXPR_TYPE_ARGSEP        (MPEXPR_TYPE_BINARY | 0x003)
+#define MPEXPR_TYPE_QUESTION      (MPEXPR_TYPE_BINARY | 0x004)
+#define MPEXPR_TYPE_COLON         (MPEXPR_TYPE_BINARY | 0x005)
+#define MPEXPR_TYPE_MAX           (MPEXPR_TYPE_BINARY | 0x006)
+#define MPEXPR_TYPE_MIN           (MPEXPR_TYPE_BINARY | 0x007)
+#define MPEXPR_TYPE_MASK_CMP      0x008
+#define MPEXPR_TYPE_MASK_CMP_LT   0x001
+#define MPEXPR_TYPE_MASK_CMP_EQ   0x002
+#define MPEXPR_TYPE_MASK_CMP_GT   0x004
+#define MPEXPR_TYPE_CMP_LT       (MPEXPR_TYPE_BINARY | MPEXPR_TYPE_MASK_CMP \
+				  | MPEXPR_TYPE_MASK_CMP_LT)
+#define MPEXPR_TYPE_CMP_EQ       (MPEXPR_TYPE_BINARY | MPEXPR_TYPE_MASK_CMP \
+				  | MPEXPR_TYPE_MASK_CMP_EQ)
+#define MPEXPR_TYPE_CMP_GT       (MPEXPR_TYPE_BINARY | MPEXPR_TYPE_MASK_CMP \
+				  | MPEXPR_TYPE_MASK_CMP_GT)
+#define MPEXPR_TYPE_CMP_LE       (MPEXPR_TYPE_CMP_LT | MPEXPR_TYPE_MASK_CMP_EQ)
+#define MPEXPR_TYPE_CMP_NE       (MPEXPR_TYPE_CMP_LT | MPEXPR_TYPE_MASK_CMP_GT)
+#define MPEXPR_TYPE_CMP_GE       (MPEXPR_TYPE_CMP_GT | MPEXPR_TYPE_MASK_CMP_EQ)
+
+/* parse options */
+#define MPEXPR_TYPE_WHOLEWORD      0x1000
+#define MPEXPR_TYPE_OPERATOR       0x2000
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void (*mpexpr_fun_t) (void);
+
+struct mpexpr_operator_t {
+  const char   *name;
+  mpexpr_fun_t fun;
+  int          type;
+  int          precedence;
+};
+
+
+int mpf_expr_a (const struct mpexpr_operator_t *, mpf_ptr, int,
+		unsigned long, const char *, size_t, mpf_srcptr [26]);
+int mpf_expr (mpf_ptr, int, const char *, ...);
+
+int mpq_expr_a (const struct mpexpr_operator_t *, mpq_ptr,
+		int, const char *, size_t, mpq_srcptr [26]);
+int mpq_expr (mpq_ptr, int, const char *, ...);
+
+int mpz_expr_a (const struct mpexpr_operator_t *, mpz_ptr, int,
+		const char *, size_t, mpz_srcptr [26]);
+int mpz_expr (mpz_ptr, int, const char *, ...);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
diff --git a/third_party/gmp/demos/expr/exprf.c b/third_party/gmp/demos/expr/exprf.c
new file mode 100644
index 0000000..1f7e21f
--- /dev/null
+++ b/third_party/gmp/demos/expr/exprf.c
@@ -0,0 +1,123 @@
+/* mpf expression evaluation
+
+Copyright 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <string.h>
+#include "gmp.h"
+#include "expr-impl.h"
+
+
+/* Change this to "#define TRACE(x) x" to get some traces. */
+#define TRACE(x)
+
+
+static int
+e_mpf_sgn (mpf_srcptr x)
+{
+  return mpf_sgn (x);
+}
+
+
+static const struct mpexpr_operator_t  _mpf_expr_standard_table[] = {
+
+  { "**",  (mpexpr_fun_t) mpf_pow_ui,
+    MPEXPR_TYPE_BINARY_UI | MPEXPR_TYPE_RIGHTASSOC,                   220 },
+
+  { "!",   (mpexpr_fun_t) e_mpf_sgn,
+    MPEXPR_TYPE_LOGICAL_NOT | MPEXPR_TYPE_PREFIX,                     210 },
+  { "-",   (mpexpr_fun_t) mpf_neg,
+    MPEXPR_TYPE_UNARY | MPEXPR_TYPE_PREFIX,                           210 },
+
+  { "*",   (mpexpr_fun_t) mpf_mul,           MPEXPR_TYPE_BINARY,      200 },
+  { "/",   (mpexpr_fun_t) mpf_div,           MPEXPR_TYPE_BINARY,      200 },
+
+  { "+",   (mpexpr_fun_t) mpf_add,           MPEXPR_TYPE_BINARY,      190 },
+  { "-",   (mpexpr_fun_t) mpf_sub,           MPEXPR_TYPE_BINARY,      190 },
+
+  { "<<",  (mpexpr_fun_t) mpf_mul_2exp,      MPEXPR_TYPE_BINARY_UI,   180 },
+  { ">>",  (mpexpr_fun_t) mpf_div_2exp,      MPEXPR_TYPE_BINARY_UI,   180 },
+
+  { "<=",  (mpexpr_fun_t) mpf_cmp,           MPEXPR_TYPE_CMP_LE,      170 },
+  { "<",   (mpexpr_fun_t) mpf_cmp,           MPEXPR_TYPE_CMP_LT,      170 },
+  { ">=",  (mpexpr_fun_t) mpf_cmp,           MPEXPR_TYPE_CMP_GE,      170 },
+  { ">",   (mpexpr_fun_t) mpf_cmp,           MPEXPR_TYPE_CMP_GT,      170 },
+
+  { "==",  (mpexpr_fun_t) mpf_cmp,           MPEXPR_TYPE_CMP_EQ,      160 },
+  { "!=",  (mpexpr_fun_t) mpf_cmp,           MPEXPR_TYPE_CMP_NE,      160 },
+
+  { "&&",  (mpexpr_fun_t) e_mpf_sgn,         MPEXPR_TYPE_LOGICAL_AND, 120 },
+  { "||",  (mpexpr_fun_t) e_mpf_sgn,         MPEXPR_TYPE_LOGICAL_OR,  110 },
+
+  { ":",   NULL,                             MPEXPR_TYPE_COLON,       101 },
+  { "?",   (mpexpr_fun_t) e_mpf_sgn,         MPEXPR_TYPE_QUESTION,    100 },
+
+  { ")",   NULL,                             MPEXPR_TYPE_CLOSEPAREN,    4 },
+  { "(",   NULL,                             MPEXPR_TYPE_OPENPAREN,     3 },
+  { ",",   NULL,                             MPEXPR_TYPE_ARGSEP,        2 },
+  { "$",   NULL,                             MPEXPR_TYPE_VARIABLE,      1 },
+
+  { "abs",      (mpexpr_fun_t) mpf_abs,          MPEXPR_TYPE_UNARY        },
+  { "ceil",     (mpexpr_fun_t) mpf_ceil,         MPEXPR_TYPE_UNARY        },
+  { "cmp",      (mpexpr_fun_t) mpf_cmp,          MPEXPR_TYPE_I_BINARY     },
+  { "eq",       (mpexpr_fun_t) mpf_eq,           MPEXPR_TYPE_I_TERNARY_UI },
+  { "floor",    (mpexpr_fun_t) mpf_floor,        MPEXPR_TYPE_UNARY        },
+  { "integer_p",(mpexpr_fun_t) mpf_integer_p,    MPEXPR_TYPE_I_UNARY      },
+  { "max",   (mpexpr_fun_t) mpf_cmp, MPEXPR_TYPE_MAX | MPEXPR_TYPE_PAIRWISE },
+  { "min",   (mpexpr_fun_t) mpf_cmp, MPEXPR_TYPE_MIN | MPEXPR_TYPE_PAIRWISE },
+  { "reldiff",  (mpexpr_fun_t) mpf_reldiff,      MPEXPR_TYPE_BINARY       },
+  { "sgn",      (mpexpr_fun_t) e_mpf_sgn,        MPEXPR_TYPE_I_UNARY      },
+  { "sqrt",     (mpexpr_fun_t) mpf_sqrt,         MPEXPR_TYPE_UNARY        },
+  { "trunc",    (mpexpr_fun_t) mpf_trunc,        MPEXPR_TYPE_UNARY        },
+
+  { NULL }
+};
+
+const struct mpexpr_operator_t * const mpf_expr_standard_table
+= _mpf_expr_standard_table;
+
+
+int
+mpf_expr (mpf_ptr res, int base, const char *e, ...)
+{
+  mpf_srcptr  var[MPEXPR_VARIABLES];
+  va_list     ap;
+  int         ret;
+  va_start (ap, e);
+
+  TRACE (printf ("mpf_expr(): base %d, %s\n", base, e));
+  ret = mpexpr_va_to_var ((void **) var, ap);
+  va_end (ap);
+
+  if (ret != MPEXPR_RESULT_OK)
+    return ret;
+
+  return mpf_expr_a (mpf_expr_standard_table, res, base,
+		     mpf_get_prec (res), e, strlen(e), var);
+}
diff --git a/third_party/gmp/demos/expr/exprfa.c b/third_party/gmp/demos/expr/exprfa.c
new file mode 100644
index 0000000..1918cb5
--- /dev/null
+++ b/third_party/gmp/demos/expr/exprfa.c
@@ -0,0 +1,191 @@
+/* mpf expression evaluation
+
+Copyright 2000-2002, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+/* Future: Bitwise "&", "|" and "&" could be done, if desired.  Not sure
+   those functions would be much value though.  */
+
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "gmp.h"
+#include "expr-impl.h"
+
+
+/* Change this to "#define TRACE(x) x" to get some traces. */
+#define TRACE(x)
+
+
+static size_t
+e_mpf_number (mpf_ptr res, const char *e, size_t elen, int base)
+{
+  char    *edup;
+  size_t  i, ret, extra=0;
+  int     mant_base, exp_base;
+  void    *(*allocate_func) (size_t);
+  void    (*free_func) (void *, size_t);
+
+  TRACE (printf ("mpf_number base=%d \"%.*s\"\n", base, (int) elen, e));
+
+  /* mpf_set_str doesn't currently accept 0x for hex in base==0, so do it
+     here instead.  FIXME: Would prefer to let mpf_set_str handle this.  */
+  if (base == 0 && elen >= 2 && e[0] == '0' && (e[1] == 'x' || e[1] == 'X'))
+    {
+      base = 16;
+      extra = 2;
+      e += extra;
+      elen -= extra;
+    }
+
+  if (base == 0)
+    mant_base = 10;
+  else if (base < 0)
+    mant_base = -base;
+  else
+    mant_base = base;
+
+  /* exponent in decimal if base is negative */
+  if (base < 0)
+    exp_base = 10;
+  else if (base == 0)
+    exp_base = 10;
+  else
+    exp_base = base;
+
+#define IS_EXPONENT(c) \
+  (c == '@' || (base <= 10 && base >= -10 && (e[i] == 'e' || e[i] == 'E')))
+
+  i = 0;
+  for (;;)
+    {
+      if (i >= elen)
+        goto parsed;
+      if (e[i] == '.')
+        break;
+      if (IS_EXPONENT (e[i]))
+        goto exponent;
+      if (! isasciidigit_in_base (e[i], mant_base))
+        goto parsed;
+      i++;
+    }
+
+  /* fraction */
+  i++;
+  for (;;)
+    {
+      if (i >= elen)
+        goto parsed;
+      if (IS_EXPONENT (e[i]))
+        goto exponent;
+      if (! isasciidigit_in_base (e[i], mant_base))
+        goto parsed;
+      i++;
+    }
+
+ exponent:
+  i++;
+  if (i >= elen)
+    goto parsed;
+  if (e[i] == '-')
+    i++;
+  for (;;)
+    {
+      if (i >= elen)
+        goto parsed;
+      if (! isasciidigit_in_base (e[i], exp_base))
+        break;
+      i++;
+    }
+
+ parsed:
+  TRACE (printf ("  parsed i=%u \"%.*s\"\n", i, (int) i, e));
+
+  mp_get_memory_functions (&allocate_func, NULL, &free_func);
+  edup = (*allocate_func) (i+1);
+  memcpy (edup, e, i);
+  edup[i] = '\0';
+
+  if (mpf_set_str (res, edup, base) == 0)
+    ret = i + extra;
+  else
+    ret = 0;
+
+  (*free_func) (edup, i+1);
+  return ret;
+}
+
+static int
+e_mpf_ulong_p (mpf_srcptr f)
+{
+  return mpf_integer_p (f) && mpf_fits_ulong_p (f);
+}
+
+/* Don't want to change the precision of w, can only do an actual swap when
+   w and x have the same precision.  */
+static void
+e_mpf_set_or_swap (mpf_ptr w, mpf_ptr x)
+{
+  if (mpf_get_prec (w) == mpf_get_prec (x))
+    mpf_swap (w, x);
+  else
+    mpf_set (w, x);
+}
+
+
+int
+mpf_expr_a (const struct mpexpr_operator_t *table,
+            mpf_ptr res, int base, unsigned long prec,
+            const char *e, size_t elen,
+            mpf_srcptr var[26])
+{
+  struct mpexpr_parse_t  p;
+
+  p.table = table;
+  p.res = (mpX_ptr) res;
+  p.base = base;
+  p.prec = prec;
+  p.e = e;
+  p.elen = elen;
+  p.var = (mpX_srcptr *) var;
+
+  p.mpX_clear       = (mpexpr_fun_one_t)      mpf_clear;
+  p.mpX_ulong_p     = (mpexpr_fun_i_unary_t)  e_mpf_ulong_p;
+  p.mpX_get_ui      = (mpexpr_fun_get_ui_t)   mpf_get_ui;
+  p.mpX_init        = (mpexpr_fun_unary_ui_t) mpf_init2;
+  p.mpX_number      = (mpexpr_fun_number_t)   e_mpf_number;
+  p.mpX_set         = (mpexpr_fun_unary_t)    mpf_set;
+  p.mpX_set_or_swap = (mpexpr_fun_unary_t)    e_mpf_set_or_swap;
+  p.mpX_set_si      = (mpexpr_fun_set_si_t)   mpf_set_si;
+  p.mpX_swap        = (mpexpr_fun_swap_t)     mpf_swap;
+
+  return mpexpr_evaluate (&p);
+}
diff --git a/third_party/gmp/demos/expr/exprq.c b/third_party/gmp/demos/expr/exprq.c
new file mode 100644
index 0000000..9643200
--- /dev/null
+++ b/third_party/gmp/demos/expr/exprq.c
@@ -0,0 +1,155 @@
+/* mpq expression evaluation
+
+Copyright 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <string.h>
+#include "gmp.h"
+#include "expr-impl.h"
+
+
+/* Change this to "#define TRACE(x) x" to get some traces. */
+#define TRACE(x)
+
+
+static void
+e_mpq_pow_ui (mpq_ptr r, mpq_srcptr b, unsigned long e)
+{
+  mpz_pow_ui (mpq_numref(r), mpq_numref(b), e);
+  mpz_pow_ui (mpq_denref(r), mpq_denref(b), e);
+}
+
+/* Wrapped because mpq_sgn is a macro. */
+static int
+e_mpq_sgn (mpq_srcptr x)
+{
+  return mpq_sgn (x);
+}
+
+/* Wrapped because mpq_equal only guarantees a non-zero return, whereas we
+   want 1 or 0 for == and !=. */
+static int
+e_mpq_equal (mpq_srcptr x, mpq_srcptr y)
+{
+  return mpq_equal (x, y) != 0;
+}
+static int
+e_mpq_notequal (mpq_srcptr x, mpq_srcptr y)
+{
+  return ! mpq_equal (x, y);
+}
+
+static void
+e_mpq_num (mpq_ptr w, mpq_srcptr x)
+{
+  if (w != x)
+    mpz_set (mpq_numref(w), mpq_numref(x));
+  mpz_set_ui (mpq_denref(w), 1L);
+}
+static void
+e_mpq_den (mpq_ptr w, mpq_srcptr x)
+{
+  if (w == x)
+    mpz_swap (mpq_numref(w), mpq_denref(w));
+  else
+    mpz_set (mpq_numref(w), mpq_denref(x));
+  mpz_set_ui (mpq_denref(w), 1L);
+}
+
+
+static const struct mpexpr_operator_t  _mpq_expr_standard_table[] = {
+
+  { "**",  (mpexpr_fun_t) e_mpq_pow_ui,
+    MPEXPR_TYPE_BINARY_UI | MPEXPR_TYPE_RIGHTASSOC,                   220 },
+
+  { "!",   (mpexpr_fun_t) e_mpq_sgn,
+    MPEXPR_TYPE_LOGICAL_NOT | MPEXPR_TYPE_PREFIX,                     210 },
+  { "-",   (mpexpr_fun_t) mpq_neg,
+    MPEXPR_TYPE_UNARY | MPEXPR_TYPE_PREFIX,                           210 },
+
+  { "*",   (mpexpr_fun_t) mpq_mul,           MPEXPR_TYPE_BINARY,      200 },
+  { "/",   (mpexpr_fun_t) mpq_div,           MPEXPR_TYPE_BINARY,      200 },
+
+  { "+",   (mpexpr_fun_t) mpq_add,           MPEXPR_TYPE_BINARY,      190 },
+  { "-",   (mpexpr_fun_t) mpq_sub,           MPEXPR_TYPE_BINARY,      190 },
+
+  { "<<",  (mpexpr_fun_t) mpq_mul_2exp,      MPEXPR_TYPE_BINARY_UI,   180 },
+  { ">>",  (mpexpr_fun_t) mpq_div_2exp,      MPEXPR_TYPE_BINARY_UI,   180 },
+
+  { "<=",  (mpexpr_fun_t) mpq_cmp,           MPEXPR_TYPE_CMP_LE,      170 },
+  { "<",   (mpexpr_fun_t) mpq_cmp,           MPEXPR_TYPE_CMP_LT,      170 },
+  { ">=",  (mpexpr_fun_t) mpq_cmp,           MPEXPR_TYPE_CMP_GE,      170 },
+  { ">",   (mpexpr_fun_t) mpq_cmp,           MPEXPR_TYPE_CMP_GT,      170 },
+
+  { "==",  (mpexpr_fun_t) e_mpq_equal,       MPEXPR_TYPE_I_BINARY,    160 },
+  { "!=",  (mpexpr_fun_t) e_mpq_notequal,    MPEXPR_TYPE_I_BINARY,    160 },
+
+  { "&&",  (mpexpr_fun_t) e_mpq_sgn,         MPEXPR_TYPE_LOGICAL_AND, 120 },
+  { "||",  (mpexpr_fun_t) e_mpq_sgn,         MPEXPR_TYPE_LOGICAL_OR,  110 },
+
+  { ":",   NULL,                             MPEXPR_TYPE_COLON,       101 },
+  { "?",   (mpexpr_fun_t) e_mpq_sgn,         MPEXPR_TYPE_QUESTION,    100 },
+
+  { ")",   (mpexpr_fun_t) e_mpq_sgn,         MPEXPR_TYPE_CLOSEPAREN,    4 },
+  { "(",   (mpexpr_fun_t) e_mpq_sgn,         MPEXPR_TYPE_OPENPAREN,     3 },
+  { ",",   (mpexpr_fun_t) e_mpq_sgn,         MPEXPR_TYPE_ARGSEP,        2 },
+  { "$",   NULL,                             MPEXPR_TYPE_VARIABLE,      1 },
+
+  { "abs",  (mpexpr_fun_t) mpq_abs,          MPEXPR_TYPE_UNARY            },
+  { "cmp",  (mpexpr_fun_t) mpq_cmp,          MPEXPR_TYPE_I_BINARY         },
+  { "den",  (mpexpr_fun_t) e_mpq_den,        MPEXPR_TYPE_UNARY            },
+  { "max",  (mpexpr_fun_t) mpq_cmp,  MPEXPR_TYPE_MAX | MPEXPR_TYPE_PAIRWISE },
+  { "min",  (mpexpr_fun_t) mpq_cmp,  MPEXPR_TYPE_MIN | MPEXPR_TYPE_PAIRWISE },
+  { "num",  (mpexpr_fun_t) e_mpq_num,        MPEXPR_TYPE_UNARY            },
+  { "sgn",  (mpexpr_fun_t) e_mpq_sgn,        MPEXPR_TYPE_I_UNARY          },
+
+  { NULL }
+};
+
+const struct mpexpr_operator_t * const mpq_expr_standard_table
+= _mpq_expr_standard_table;
+
+
+int
+mpq_expr (mpq_ptr res, int base, const char *e, ...)
+{
+  mpq_srcptr  var[MPEXPR_VARIABLES];
+  va_list     ap;
+  int         ret;
+  va_start (ap, e);
+
+  TRACE (printf ("mpq_expr(): base %d, %s\n", base, e));
+  ret = mpexpr_va_to_var ((void **) var, ap);
+  va_end (ap);
+
+  if (ret != MPEXPR_RESULT_OK)
+    return ret;
+
+  return mpq_expr_a (mpq_expr_standard_table, res, base, e, strlen(e), var);
+}
diff --git a/third_party/gmp/demos/expr/exprqa.c b/third_party/gmp/demos/expr/exprqa.c
new file mode 100644
index 0000000..f3b6ecb
--- /dev/null
+++ b/third_party/gmp/demos/expr/exprqa.c
@@ -0,0 +1,100 @@
+/* mpq expression evaluation
+
+Copyright 2000, 2001, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include <stdio.h>
+#include "gmp.h"
+#include "expr-impl.h"
+
+
+static int
+e_mpq_ulong_p (mpq_srcptr q)
+{
+  return mpz_fits_ulong_p (mpq_numref (q))
+    && mpz_cmp_ui (mpq_denref (q), 1L) == 0;
+}
+
+/* get value as a ui, on the assumption it fits */
+static int
+e_mpq_get_ui_fits (mpq_srcptr q)
+{
+  return mpz_get_ui (mpq_numref (q));
+}
+
+static void
+e_mpq_set_si1 (mpq_ptr q, long num)
+{
+  mpq_set_si (q, num, 1L);
+}
+
+/* The same as mpz, but putting the result in the numerator.  Negatives and
+   fractions aren't parsed here because '-' and '/' are operators. */
+static size_t
+e_mpq_number (mpq_ptr res, const char *e, size_t elen, int base)
+{
+  mpz_set_ui (mpq_denref (res), 1L);
+  return mpexpr_mpz_number (mpq_numref (res), e, elen, base);
+}
+
+
+/* ignoring prec */
+static void
+e_mpq_init (mpq_ptr q, unsigned long prec)
+{
+  mpq_init (q);
+}
+
+int
+mpq_expr_a (const struct mpexpr_operator_t *table,
+            mpq_ptr res, int base,
+            const char *e, size_t elen,
+            mpq_srcptr var[26])
+{
+  struct mpexpr_parse_t  p;
+
+  p.table = table;
+  p.res = (mpX_ptr) res;
+  p.base = base;
+  p.e = e;
+  p.elen = elen;
+  p.var = (mpX_srcptr *) var;
+
+  p.mpX_clear       = (mpexpr_fun_one_t)      mpq_clear;
+  p.mpX_ulong_p     = (mpexpr_fun_i_unary_t)  e_mpq_ulong_p;
+  p.mpX_get_ui      = (mpexpr_fun_get_ui_t)   e_mpq_get_ui_fits;
+  p.mpX_init        = (mpexpr_fun_unary_ui_t) e_mpq_init;
+  p.mpX_number      = (mpexpr_fun_number_t)   e_mpq_number;
+  p.mpX_set         = (mpexpr_fun_unary_t)    mpq_set;
+  p.mpX_set_or_swap = (mpexpr_fun_unary_t)    mpq_swap;
+  p.mpX_set_si      = (mpexpr_fun_set_si_t)   e_mpq_set_si1;
+  p.mpX_swap        = (mpexpr_fun_swap_t)     mpq_swap;
+
+  return mpexpr_evaluate (&p);
+}
diff --git a/third_party/gmp/demos/expr/exprv.c b/third_party/gmp/demos/expr/exprv.c
new file mode 100644
index 0000000..c25741b
--- /dev/null
+++ b/third_party/gmp/demos/expr/exprv.c
@@ -0,0 +1,57 @@
+/* mpz expression evaluation, simple part */
+
+/*
+Copyright 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp.h"
+#include "expr-impl.h"
+
+
+int
+mpexpr_va_to_var (void *var[], va_list ap)
+{
+  int   i = 0;
+  void  *v;
+
+  for (;;)
+    {
+      v = va_arg (ap, void *);
+      if (v == NULL)
+	break;
+      if (i >= MPEXPR_VARIABLES)
+	return MPEXPR_RESULT_BAD_VARIABLE;
+      var[i++] = v;
+    }
+
+  while (i < MPEXPR_VARIABLES)
+    var[i++] = NULL;
+
+  return MPEXPR_RESULT_OK;
+}
diff --git a/third_party/gmp/demos/expr/exprz.c b/third_party/gmp/demos/expr/exprz.c
new file mode 100644
index 0000000..bac1a99
--- /dev/null
+++ b/third_party/gmp/demos/expr/exprz.c
@@ -0,0 +1,206 @@
+/* mpz expression evaluation, simple part
+
+Copyright 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include "gmp.h"
+#include "expr-impl.h"
+
+
+/* Change this to "#define TRACE(x) x" to get some traces. */
+#define TRACE(x)
+
+
+/* These are macros, so need function wrappers. */
+static int
+e_mpz_sgn (mpz_srcptr x)
+{
+  return mpz_sgn (x);
+}
+static int
+e_mpz_odd_p (mpz_srcptr x)
+{
+  return mpz_odd_p (x);
+}
+static int
+e_mpz_even_p (mpz_srcptr x)
+{
+  return mpz_even_p (x);
+}
+
+/* These wrapped because MPEXPR_TYPE_I_ functions are expected to return
+   "int" whereas these return "unsigned long".  */
+static void
+e_mpz_hamdist (mpz_ptr w, mpz_srcptr x, mpz_srcptr y)
+{
+  mpz_set_ui (w, mpz_hamdist (x, y));
+}
+static void
+e_mpz_popcount (mpz_ptr w, mpz_srcptr x)
+{
+  mpz_set_ui (w, mpz_popcount (x));
+}
+static void
+e_mpz_scan0 (mpz_ptr w, mpz_srcptr x, unsigned long start)
+{
+  mpz_set_ui (w, mpz_scan0 (x, start));
+}
+static void
+e_mpz_scan1 (mpz_ptr w, mpz_srcptr x, unsigned long start)
+{
+  mpz_set_ui (w, mpz_scan1 (x, start));
+}
+
+/* These wrapped because they're in-place whereas MPEXPR_TYPE_BINARY_UI
+   expects a separate source and destination.  Actually the parser will
+   normally pass w==x anyway.  */
+static void
+e_mpz_setbit (mpz_ptr w, mpz_srcptr x, unsigned long n)
+{
+  if (w != x)
+    mpz_set (w, x);
+  mpz_setbit (w, n);
+}
+static void
+e_mpz_clrbit (mpz_ptr w, mpz_srcptr x, unsigned long n)
+{
+  if (w != x)
+    mpz_set (w, x);
+  mpz_clrbit (w, n);
+}
+
+static const struct mpexpr_operator_t  _mpz_expr_standard_table[] = {
+
+  { "**",  (mpexpr_fun_t) mpz_pow_ui,
+    MPEXPR_TYPE_BINARY_UI | MPEXPR_TYPE_RIGHTASSOC,                  220 },
+
+  { "~",   (mpexpr_fun_t) mpz_com,
+    MPEXPR_TYPE_UNARY | MPEXPR_TYPE_PREFIX,                          210 },
+  { "!",   (mpexpr_fun_t) e_mpz_sgn,
+    MPEXPR_TYPE_LOGICAL_NOT | MPEXPR_TYPE_PREFIX,                    210 },
+  { "-",   (mpexpr_fun_t) mpz_neg,
+    MPEXPR_TYPE_UNARY | MPEXPR_TYPE_PREFIX,                          210 },
+
+  { "*",   (mpexpr_fun_t) mpz_mul,          MPEXPR_TYPE_BINARY,      200 },
+  { "/",   (mpexpr_fun_t) mpz_tdiv_q,       MPEXPR_TYPE_BINARY,      200 },
+  { "%",   (mpexpr_fun_t) mpz_tdiv_r,       MPEXPR_TYPE_BINARY,      200 },
+
+  { "+",   (mpexpr_fun_t) mpz_add,          MPEXPR_TYPE_BINARY,      190 },
+  { "-",   (mpexpr_fun_t) mpz_sub,          MPEXPR_TYPE_BINARY,      190 },
+
+  { "<<",  (mpexpr_fun_t) mpz_mul_2exp,     MPEXPR_TYPE_BINARY_UI,   180 },
+  { ">>",  (mpexpr_fun_t) mpz_tdiv_q_2exp,  MPEXPR_TYPE_BINARY_UI,   180 },
+
+  { "<=",  (mpexpr_fun_t) mpz_cmp,          MPEXPR_TYPE_CMP_LE,      170 },
+  { "<",   (mpexpr_fun_t) mpz_cmp,          MPEXPR_TYPE_CMP_LT,      170 },
+  { ">=",  (mpexpr_fun_t) mpz_cmp,          MPEXPR_TYPE_CMP_GE,      170 },
+  { ">",   (mpexpr_fun_t) mpz_cmp,          MPEXPR_TYPE_CMP_GT,      170 },
+
+  { "==",  (mpexpr_fun_t) mpz_cmp,          MPEXPR_TYPE_CMP_EQ,      160 },
+  { "!=",  (mpexpr_fun_t) mpz_cmp,          MPEXPR_TYPE_CMP_NE,      160 },
+
+  { "&",   (mpexpr_fun_t) mpz_and,          MPEXPR_TYPE_BINARY,      150 },
+  { "^",   (mpexpr_fun_t) mpz_xor,          MPEXPR_TYPE_BINARY,      140 },
+  { "|",   (mpexpr_fun_t) mpz_ior,          MPEXPR_TYPE_BINARY,      130 },
+  { "&&",  (mpexpr_fun_t) e_mpz_sgn, MPEXPR_TYPE_LOGICAL_AND, 120 },
+  { "||",  (mpexpr_fun_t) e_mpz_sgn, MPEXPR_TYPE_LOGICAL_OR,  110 },
+
+  { ":",   NULL,                            MPEXPR_TYPE_COLON,       101 },
+  { "?",   (mpexpr_fun_t) e_mpz_sgn, MPEXPR_TYPE_QUESTION,    100 },
+
+  { ")",   NULL,                            MPEXPR_TYPE_CLOSEPAREN,   4 },
+  { "(",   NULL,                            MPEXPR_TYPE_OPENPAREN,    3 },
+  { ",",   NULL,                            MPEXPR_TYPE_ARGSEP,       2 },
+  { "$",   NULL,                            MPEXPR_TYPE_VARIABLE,     1 },
+
+  { "abs",       (mpexpr_fun_t) mpz_abs,           MPEXPR_TYPE_UNARY         },
+  { "bin",       (mpexpr_fun_t) mpz_bin_ui,        MPEXPR_TYPE_BINARY_UI     },
+  { "clrbit",    (mpexpr_fun_t) e_mpz_clrbit,      MPEXPR_TYPE_BINARY_UI     },
+  { "cmp",       (mpexpr_fun_t) mpz_cmp,           MPEXPR_TYPE_I_BINARY      },
+  { "cmpabs",    (mpexpr_fun_t) mpz_cmpabs,        MPEXPR_TYPE_I_BINARY      },
+  { "congruent_p",(mpexpr_fun_t)mpz_congruent_p,   MPEXPR_TYPE_I_TERNARY     },
+  { "divisible_p",(mpexpr_fun_t)mpz_divisible_p,   MPEXPR_TYPE_I_BINARY      },
+  { "even_p",    (mpexpr_fun_t) e_mpz_even_p,      MPEXPR_TYPE_I_UNARY       },
+  { "fib",       (mpexpr_fun_t) mpz_fib_ui,        MPEXPR_TYPE_UNARY_UI      },
+  { "fac",       (mpexpr_fun_t) mpz_fac_ui,        MPEXPR_TYPE_UNARY_UI      },
+  { "gcd",       (mpexpr_fun_t) mpz_gcd,           MPEXPR_TYPE_BINARY
+						   | MPEXPR_TYPE_PAIRWISE    },
+  { "hamdist",   (mpexpr_fun_t) e_mpz_hamdist,     MPEXPR_TYPE_BINARY        },
+  { "invert",    (mpexpr_fun_t) mpz_invert,        MPEXPR_TYPE_BINARY        },
+  { "jacobi",    (mpexpr_fun_t) mpz_jacobi,        MPEXPR_TYPE_I_BINARY      },
+  { "kronecker", (mpexpr_fun_t) mpz_kronecker,     MPEXPR_TYPE_I_BINARY      },
+  { "lcm",       (mpexpr_fun_t) mpz_lcm,           MPEXPR_TYPE_BINARY
+						   | MPEXPR_TYPE_PAIRWISE    },
+  { "lucnum",    (mpexpr_fun_t) mpz_lucnum_ui,     MPEXPR_TYPE_UNARY_UI      },
+  { "max",       (mpexpr_fun_t) mpz_cmp,           MPEXPR_TYPE_MAX
+						   | MPEXPR_TYPE_PAIRWISE    },
+  { "min",       (mpexpr_fun_t) mpz_cmp,           MPEXPR_TYPE_MIN
+						   | MPEXPR_TYPE_PAIRWISE    },
+  { "nextprime", (mpexpr_fun_t) mpz_nextprime,     MPEXPR_TYPE_UNARY         },
+  { "odd_p",     (mpexpr_fun_t) e_mpz_odd_p,       MPEXPR_TYPE_I_UNARY       },
+  { "perfect_power_p", (mpexpr_fun_t)mpz_perfect_power_p, MPEXPR_TYPE_I_UNARY},
+  { "perfect_square_p",(mpexpr_fun_t)mpz_perfect_square_p,MPEXPR_TYPE_I_UNARY},
+  { "popcount",  (mpexpr_fun_t) e_mpz_popcount,    MPEXPR_TYPE_UNARY         },
+  { "powm",      (mpexpr_fun_t) mpz_powm,          MPEXPR_TYPE_TERNARY       },
+  { "probab_prime_p",  (mpexpr_fun_t)mpz_probab_prime_p,  MPEXPR_TYPE_I_UNARY},
+  { "root",      (mpexpr_fun_t) mpz_root,          MPEXPR_TYPE_BINARY_UI     },
+  { "scan0",     (mpexpr_fun_t) e_mpz_scan0,       MPEXPR_TYPE_BINARY_UI     },
+  { "scan1",     (mpexpr_fun_t) e_mpz_scan1,       MPEXPR_TYPE_BINARY_UI     },
+  { "setbit",    (mpexpr_fun_t) e_mpz_setbit,      MPEXPR_TYPE_BINARY_UI     },
+  { "tstbit",    (mpexpr_fun_t) mpz_tstbit,        MPEXPR_TYPE_I_BINARY_UI   },
+  { "sgn",       (mpexpr_fun_t) e_mpz_sgn,         MPEXPR_TYPE_I_UNARY       },
+  { "sqrt",      (mpexpr_fun_t) mpz_sqrt,          MPEXPR_TYPE_UNARY         },
+  { NULL }
+};
+
+/* The table is available globally only through a pointer, so the table size
+   can change without breaking binary compatibility. */
+const struct mpexpr_operator_t * const mpz_expr_standard_table
+= _mpz_expr_standard_table;
+
+
+int
+mpz_expr (mpz_ptr res, int base, const char *e, ...)
+{
+  mpz_srcptr  var[MPEXPR_VARIABLES];
+  va_list     ap;
+  int         ret;
+  va_start (ap, e);
+
+  TRACE (printf ("mpz_expr(): base %d, %s\n", base, e));
+  ret = mpexpr_va_to_var ((void **) var, ap);
+  va_end (ap);
+
+  if (ret != MPEXPR_RESULT_OK)
+    return ret;
+
+  return mpz_expr_a (mpz_expr_standard_table, res, base, e, strlen(e), var);
+}
diff --git a/third_party/gmp/demos/expr/exprza.c b/third_party/gmp/demos/expr/exprza.c
new file mode 100644
index 0000000..eda830d
--- /dev/null
+++ b/third_party/gmp/demos/expr/exprza.c
@@ -0,0 +1,108 @@
+/* mpz expression evaluation
+
+Copyright 2000-2002, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include "gmp.h"
+#include "expr-impl.h"
+
+
+/* No need to parse '-' since that's handled as an operator.
+   This function also by mpq_expr_a, so it's not static.  */
+size_t
+mpexpr_mpz_number (mpz_ptr res, const char *e, size_t elen, int base)
+{
+  char    *edup;
+  size_t  i, ret;
+  int     base_effective = (base == 0 ? 10 : base);
+  void    *(*allocate_func) (size_t);
+  void    (*free_func) (void *, size_t);
+
+  i = 0;
+  if (e[i] == '0')
+    {
+      i++;
+      if (e[i] == 'x' || e[i] == 'b')
+        i++;
+    }
+
+  for ( ; i < elen; i++)
+    if (! isasciidigit_in_base (e[i], base_effective))
+      break;
+
+  mp_get_memory_functions (&allocate_func, NULL, &free_func);
+  edup = (*allocate_func) (i+1);
+  memcpy (edup, e, i);
+  edup[i] = '\0';
+
+  if (mpz_set_str (res, edup, base) == 0)
+    ret = i;
+  else
+    ret = 0;
+
+  (*free_func) (edup, i+1);
+  return ret;
+}
+
+/* ignoring prec */
+static void
+e_mpz_init (mpz_ptr z, unsigned long prec)
+{
+  mpz_init (z);
+}
+
+int
+mpz_expr_a (const struct mpexpr_operator_t *table,
+            mpz_ptr res, int base,
+            const char *e, size_t elen,
+            mpz_srcptr var[26])
+{
+  struct mpexpr_parse_t  p;
+
+  p.table = table;
+  p.res = (mpX_ptr) res;
+  p.base = base;
+  p.e = e;
+  p.elen = elen;
+  p.var = (mpX_srcptr *) var;
+
+  p.mpX_clear       = (mpexpr_fun_one_t)      mpz_clear;
+  p.mpX_ulong_p     = (mpexpr_fun_i_unary_t)  mpz_fits_ulong_p;
+  p.mpX_get_ui      = (mpexpr_fun_get_ui_t)   mpz_get_ui;
+  p.mpX_init        = (mpexpr_fun_unary_ui_t) e_mpz_init;
+  p.mpX_number      = (mpexpr_fun_number_t)   mpexpr_mpz_number;
+  p.mpX_set         = (mpexpr_fun_unary_t)    mpz_set;
+  p.mpX_set_or_swap = (mpexpr_fun_unary_t)    mpz_swap;
+  p.mpX_set_si      = (mpexpr_fun_set_si_t)   mpz_set_si;
+  p.mpX_swap        = (mpexpr_fun_swap_t)     mpz_swap;
+
+  return mpexpr_evaluate (&p);
+}
diff --git a/third_party/gmp/demos/expr/run-expr.c b/third_party/gmp/demos/expr/run-expr.c
new file mode 100644
index 0000000..706b910
--- /dev/null
+++ b/third_party/gmp/demos/expr/run-expr.c
@@ -0,0 +1,242 @@
+/* Demo program to run expression evaluation.
+
+Copyright 2000-2002, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+/* Usage: ./run-expr [-z] [-q] [-f] [-p prec] [-b base] expression...
+
+   Evaluate each argument as a simple expression.  By default this is in mpz
+   integers, but -q selects mpq or -f selects mpf.  For mpf the float
+   precision can be set with -p.  In all cases the input base can be set
+   with -b, or the default is "0" meaning decimal with "0x" allowed.
+
+   This is a pretty trivial program, it's just an easy way to experiment
+   with the evaluation functions.  */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp.h"
+#include "expr.h"
+
+
+void
+run_expr (int type, int base, unsigned long prec, char *str)
+{
+  int  outbase = (base == 0 ? 10 : base);
+  int  ret;
+
+  switch (type) {
+  case 'z':
+  default:
+    {
+      mpz_t  res, var_a, var_b;
+
+      mpz_init (res);
+      mpz_init_set_ui (var_a, 55L);
+      mpz_init_set_ui (var_b, 99L);
+
+      ret = mpz_expr (res, base, str, var_a, var_b, NULL);
+      printf ("\"%s\" base %d: ", str, base);
+      if (ret == MPEXPR_RESULT_OK)
+        {
+          printf ("result ");
+          mpz_out_str (stdout, outbase, res);
+          printf ("\n");
+        }
+      else
+        printf ("invalid (return code %d)\n", ret);
+
+      mpz_clear (res);
+      mpz_clear (var_a);
+      mpz_clear (var_b);
+    }
+    break;
+
+  case 'q':
+    {
+      mpq_t  res, var_a, var_b;
+
+      mpq_init (res);
+      mpq_init (var_a);
+      mpq_init (var_b);
+
+      mpq_set_ui (var_a, 55L, 1);
+      mpq_set_ui (var_b, 99L, 1);
+
+      ret = mpq_expr (res, base, str, var_a, var_b, NULL);
+      printf ("\"%s\" base %d: ", str, base);
+      if (ret == MPEXPR_RESULT_OK)
+        {
+          printf ("result ");
+          mpq_out_str (stdout, outbase, res);
+          printf ("\n");
+        }
+      else
+        printf ("invalid (return code %d)\n", ret);
+
+      mpq_clear (res);
+      mpq_clear (var_a);
+      mpq_clear (var_b);
+    }
+    break;
+
+  case 'f':
+    {
+      mpf_t  res, var_a, var_b;
+
+      mpf_init2 (res, prec);
+      mpf_init_set_ui (var_a, 55L);
+      mpf_init_set_ui (var_b, 99L);
+
+      ret = mpf_expr (res, base, str, var_a, var_b, NULL);
+      printf ("\"%s\" base %d: ", str, base);
+      if (ret == MPEXPR_RESULT_OK)
+        {
+          printf ("result ");
+          mpf_out_str (stdout, outbase, (size_t) 0, res);
+          printf ("\n");
+        }
+      else
+        printf ("invalid (return code %d)\n", ret);
+
+      mpf_clear (res);
+      mpf_clear (var_a);
+      mpf_clear (var_b);
+    }
+    break;
+  }
+}
+
+int
+main (int argc, char *argv[])
+{
+  int            type = 'z';
+  int            base = 0;
+  unsigned long  prec = 64;
+  int            seen_expr = 0;
+  int            opt;
+  char           *arg;
+
+  for (;;)
+    {
+      argv++;
+      arg = argv[0];
+      if (arg == NULL)
+        break;
+
+      if (arg[0] == '-')
+        {
+          for (;;)
+            {
+              arg++;
+              opt = arg[0];
+
+              switch (opt) {
+              case '\0':
+                goto end_opt;
+
+              case 'f':
+              case 'q':
+              case 'z':
+                type = opt;
+                break;
+
+              case 'b':
+                arg++;
+                if (arg[0] == '\0')
+                  {
+                    argv++;
+                    arg = argv[0];
+                    if (arg == NULL)
+                      {
+                      need_arg:
+                        fprintf (stderr, "Need argument for -%c\n", opt);
+                        exit (1);
+                      }
+                  }
+                base = atoi (arg);
+                goto end_opt;
+
+              case 'p':
+                arg++;
+                if (arg[0] == '\0')
+                  {
+                    argv++;
+                    arg = argv[0];
+                    if (arg == NULL)
+                      goto need_arg;
+                  }
+                prec = atoi (arg);
+                goto end_opt;
+
+              case '-':
+                arg++;
+                if (arg[0] != '\0')
+                  {
+                    /* no "--foo" options */
+                    fprintf (stderr, "Unrecognised option --%s\n", arg);
+                    exit (1);
+                  }
+                /* stop option interpretation at "--" */
+                for (;;)
+                  {
+                    argv++;
+                    arg = argv[0];
+                    if (arg == NULL)
+                      goto done;
+                    run_expr (type, base, prec, arg);
+                    seen_expr = 1;
+                  }
+
+              default:
+                fprintf (stderr, "Unrecognised option -%c\n", opt);
+                exit (1);
+              }
+            }
+        end_opt:
+          ;
+        }
+      else
+        {
+          run_expr (type, base, prec, arg);
+          seen_expr = 1;
+        }
+    }
+
+ done:
+  if (! seen_expr)
+    {
+      printf ("Usage: %s [-z] [-q] [-f] [-p prec] [-b base] expression...\n", argv[0]);
+      exit (1);
+    }
+
+  return 0;
+}
diff --git a/third_party/gmp/demos/expr/t-expr.c b/third_party/gmp/demos/expr/t-expr.c
new file mode 100644
index 0000000..64fbfab
--- /dev/null
+++ b/third_party/gmp/demos/expr/t-expr.c
@@ -0,0 +1,510 @@
+/* Test expression evaluation (print nothing and exit 0 if successful).
+
+Copyright 2000-2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+#include "expr-impl.h"
+
+
+int  option_trace = 0;
+
+
+struct data_t {
+  int         base;
+  const char  *expr;
+  const char  *want;
+};
+
+#define numberof(x)  (sizeof (x) / sizeof ((x)[0]))
+
+
+/* These data_xxx[] arrays are tables to be tested with one or more of the
+   mp?_t types.  z=mpz_t, q=mpz_t, f=mpf_t.  */
+
+struct data_t  data_zqf[] = {
+
+  /* various deliberately wrong expressions */
+  { 0, "", NULL },
+  { 0, "1+", NULL },
+  { 0, "+2", NULL },
+  { 0, "1,2", NULL },
+  { 0, "foo(1,2)", NULL },
+  { 0, "1+foo", NULL },
+  { 10, "0fff", NULL },
+  { 0, "!", NULL },
+  { 0, "10!", NULL },
+  { 0, "-10!", NULL },
+  { 0, "gcd((4,6))", NULL },
+  { 0, "()", NULL },
+  { 0, "fac(2**1000)", NULL },
+  { 0, "$", NULL },
+  { 0, "$-", NULL },
+
+  /* some basics */
+  { 10, "123", "123" },
+  { 10, "-123", "-123" },
+  { 10, "1+2", "3" },
+  { 10, "1+2+3", "6" },
+  { 10, "1+2*3", "7" },
+  { 10, "3*2+1", "7" },
+  { 10, "$a", "55" },
+  { 10, "b", "99" },
+  { 16, "b", "11" },
+  { 10, "4**3 * 2 + 1", "129" },
+  { 10, "1<2", "1" },
+  { 10, "1>2", "0" },
+
+  { 10, "(123)", "123" },
+
+  { 10, "sgn(-123)", "-1" },
+  { 10, "5-7", "-2" },
+
+  { 0, "cmp(0,0)", "0" },
+  { 0, "cmp(1,0)", "1" },
+  { 0, "cmp(0,1)", "-1" },
+  { 0, "cmp(-1,0)", "-1" },
+  { 0, "cmp(0,-1)", "1" },
+
+  { 10, "0 ? 123 : 456", "456" },
+  { 10, "1 ? 4+5 : 6+7", "9" },
+
+  { 10, "(123)", "123" },
+  { 10, "(2+3)", "5" },
+  { 10, "(4+5)*(5+6)", "99" },
+
+  { 0, "1 << 16", "65536" },
+  { 0, "256 >> 4", "16" },
+  { 0, "-256 >> 4", "-16" },
+
+  { 0, "!1", "0" },
+  { 0, "!9", "0" },
+  { 0, "!0", "1" },
+
+  { 0, "2**2**2", "16" },
+  { 0, "-2**2**2", "-16" },
+
+  { 0, "0x100", "256" },
+  { 10, "0x100", NULL },
+  { 10, "0x 100", NULL },
+
+  { 0, " max ( 1, 2, 3, 4, 5, 6, 7, 8)", "8" },
+  { 0, " max ( 1, 9, 2, 3, 4, 5, 6, 7, 8)", "9" },
+  { 0, " min ( 1, 9, 2, 3, 4, 5, 6, 7, 8)", "1" },
+
+  { 10, "abs(123)",  "123" },
+  { 10, "abs(-123)", "123" },
+  { 10, "abs(0)",    "0" },
+
+  /* filling data stack */
+  { 0, "1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+1))))))))))))))", "16" },
+
+  /* filling control stack */
+  { 0, "----------------------------------------------------1", "1" },
+};
+
+
+const struct data_t  data_z[] = {
+  { 0, "divisible_p(333,3)", "1" },
+  { 0, "congruent_p(7,1,3)", "1" },
+
+  { 0, "cmpabs(0,0)", "0" },
+  { 0, "cmpabs(1,0)", "1" },
+  { 0, "cmpabs(0,1)", "-1" },
+  { 0, "cmpabs(-1,0)", "1" },
+  { 0, "cmpabs(0,-1)", "-1" },
+
+  { 0, "odd_p(1)", "1" },
+  { 0, "odd_p(0)", "0" },
+  { 0, "odd_p(-1)", "1" },
+
+  { 0, "even_p(1)", "0" },
+  { 0, "even_p(0)", "1" },
+  { 0, "even_p(-1)", "0" },
+
+  { 0, "fac(0)",  "1" },
+  { 0, "fac(1)",  "1" },
+  { 0, "fac(2)",  "2" },
+  { 0, "fac(3)",  "6" },
+  { 0, "fac(10)", "3628800" },
+
+  { 10, "root(81,4)", "3" },
+
+  { 10, "gcd(4,6)", "2" },
+  { 10, "gcd(4,6,9)", "1" },
+
+  { 10, "powm(3,2,9)", "0" },
+  { 10, "powm(3,2,8)", "1" },
+
+  /* filling data stack */
+  { 0, "1 ? 1 : 1 || 1 && 1 | 1 ^ 1 & 1 == 1 >= 1 << 1 - 1 * 1 ** 1", "1" },
+
+  /* filling control stack */
+  { 0, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~1", "1" },
+
+  { 0, "fib(10)", "55" },
+
+  { 0, "setbit(0,5)", "32" },
+  { 0, "clrbit(32,5)", "0" },
+  { 0, "tstbit(32,5)", "1" },
+  { 0, "tstbit(32,4)", "0" },
+  { 0, "scan0(7,0)", "3" },
+  { 0, "scan1(7,0)", "0" },
+};
+
+const struct data_t  data_zq[] = {
+  /* expecting failure */
+  { 0, "1.2", NULL },
+};
+
+const struct data_t  data_q[] = {
+  { 10,  "(1/2 + 1/3 + 1/4 + 1/5 + 1/6)*20", "29" },
+  { 0, "num(5/9)", "5" },
+  { 0, "den(5/9)", "9" },
+};
+
+const struct data_t  data_zf[] = {
+  { 10, "sqrt ( 49 )", "7" },
+  { 10, "sqrt ( 49 ) + 1", "8" },
+  { 10, "sqrt((49))", "7" },
+  { 10, "sqrt((((((((49))))))))", "7" },
+};
+
+const struct data_t  data_f[] = {
+  { 0, "1@10",    "10000000000" },
+  { 0, "1.5@10",  "15000000000" },
+  { 0, "1000@-1", "100" },
+  { 0, "10.00@-1", "1" },
+
+  { 0, "1e10",     "10000000000" },
+  { 0, "1.5e10",   "15000000000" },
+  { 0, "1000e-1",  "100" },
+  { 0, "10.00e-1", "1" },
+
+  { 16, "1@9",  "68719476736" },
+
+  { 16,  "1@10", "18446744073709551616" },
+  { -16, "1@10", "1099511627776" },
+
+  { 0, "ceil(0)",           "0" },
+  { 0, "ceil(0.25)",        "1" },
+  { 0, "ceil(0.5)",         "1" },
+  { 0, "ceil(1.5)",         "2" },
+  { 0, "ceil(-0.5)",        "0" },
+  { 0, "ceil(-1.5)",        "-1" },
+
+  /* only simple cases because mpf_eq currently only works on whole limbs */
+  { 0, "eq(0xFFFFFFFFFFFFFFFF1111111111111111,0xFFFFFFFFFFFFFFFF2222222222222222,64)", "1" },
+  { 0, "eq(0xFFFFFFFFFFFFFFFF1111111111111111,0xFFFFFFFFFFFFFFFF2222222222222222,128)", "0" },
+
+  { 0, "floor(0)",           "0" },
+  { 0, "floor(0.25)",        "0" },
+  { 0, "floor(0.5)",         "0" },
+  { 0, "floor(1.5)",         "1" },
+  { 0, "floor(-0.5)",        "-1" },
+  { 0, "floor(-1.5)",        "-2" },
+
+  { 0, "integer_p(1)",   "1" },
+  { 0, "integer_p(0.5)", "0" },
+
+  { 0, "trunc(0)",           "0" },
+  { 0, "trunc(0.25)",        "0" },
+  { 0, "trunc(0.5)",         "0" },
+  { 0, "trunc(1.5)",         "1" },
+  { 0, "trunc(-0.5)",        "0" },
+  { 0, "trunc(-1.5)",        "-1" },
+};
+
+struct datalist_t {
+  const struct data_t  *data;
+  int                  num;
+};
+
+#define DATALIST(data)  { data, numberof (data) }
+
+struct datalist_t  list_z[] = {
+  DATALIST (data_z),
+  DATALIST (data_zq),
+  DATALIST (data_zf),
+  DATALIST (data_zqf),
+};
+
+struct datalist_t  list_q[] = {
+  DATALIST (data_q),
+  DATALIST (data_zq),
+  DATALIST (data_zqf),
+};
+
+struct datalist_t  list_f[] = {
+  DATALIST (data_zf),
+  DATALIST (data_zqf),
+  DATALIST (data_f),
+};
+
+
+void
+check_z (void)
+{
+  const struct data_t  *data;
+  mpz_t  a, b, got, want;
+  int    l, i, ret;
+
+  mpz_init (got);
+  mpz_init (want);
+  mpz_init_set_ui (a, 55);
+  mpz_init_set_ui (b, 99);
+
+  for (l = 0; l < numberof (list_z); l++)
+    {
+      data = list_z[l].data;
+
+      for (i = 0; i < list_z[l].num; i++)
+        {
+          if (option_trace)
+            printf ("mpz_expr \"%s\"\n", data[i].expr);
+
+          ret = mpz_expr (got, data[i].base, data[i].expr, a, b, NULL);
+
+          if (data[i].want == NULL)
+            {
+              /* expect to fail */
+              if (ret == MPEXPR_RESULT_OK)
+                {
+                  printf ("mpz_expr wrong return value, got %d, expected failure\n", ret);
+                  goto error;
+                }
+            }
+          else
+            {
+              if (mpz_set_str (want, data[i].want, 0) != 0)
+                {
+                  printf ("Cannot parse wanted value string\n");
+                  goto error;
+                }
+              if (ret != MPEXPR_RESULT_OK)
+                {
+                  printf ("mpz_expr failed unexpectedly\n");
+                  printf ("   return value %d\n", ret);
+                  goto error;
+                }
+              if (mpz_cmp (got, want) != 0)
+                {
+                  printf ("mpz_expr wrong result\n");
+                  printf ("   got  "); mpz_out_str (stdout, 10, got);
+                  printf ("\n");
+                  printf ("   want "); mpz_out_str (stdout, 10, want);
+                  printf ("\n");
+                  goto error;
+                }
+            }
+        }
+    }
+  mpz_clear (a);
+  mpz_clear (b);
+  mpz_clear (got);
+  mpz_clear (want);
+  return;
+
+ error:
+  printf ("   base %d\n", data[i].base);
+  printf ("   expr \"%s\"\n", data[i].expr);
+  if (data[i].want != NULL)
+    printf ("   want \"%s\"\n", data[i].want);
+  abort ();
+}
+
+void
+check_q (void)
+{
+  const struct data_t  *data;
+  mpq_t  a, b, got, want;
+  int    l, i, ret;
+
+  mpq_init (got);
+  mpq_init (want);
+  mpq_init (a);
+  mpq_init (b);
+
+  mpq_set_ui (a, 55, 1);
+  mpq_set_ui (b, 99, 1);
+
+  for (l = 0; l < numberof (list_q); l++)
+    {
+      data = list_q[l].data;
+
+      for (i = 0; i < list_q[l].num; i++)
+        {
+          if (option_trace)
+            printf ("mpq_expr \"%s\"\n", data[i].expr);
+
+          ret = mpq_expr (got, data[i].base, data[i].expr, a, b, NULL);
+
+          if (data[i].want == NULL)
+            {
+              /* expect to fail */
+              if (ret == MPEXPR_RESULT_OK)
+                {
+                  printf ("mpq_expr wrong return value, got %d, expected failure\n", ret);
+                  goto error;
+                }
+            }
+          else
+            {
+              if (mpz_set_str (mpq_numref(want), data[i].want, 0) != 0)
+                {
+                  printf ("Cannot parse wanted value string\n");
+                  goto error;
+                }
+              mpz_set_ui (mpq_denref(want), 1);
+
+              if (ret != MPEXPR_RESULT_OK)
+                {
+                  printf ("mpq_expr failed unexpectedly\n");
+                  printf ("   return value %d\n", ret);
+                  goto error;
+                }
+              if (mpq_cmp (got, want) != 0)
+                {
+                  printf ("mpq_expr wrong result\n");
+                  printf ("   got  "); mpq_out_str (stdout, 10, got);
+                  printf ("\n");
+                  printf ("   want "); mpq_out_str (stdout, 10, want);
+                  printf ("\n");
+                  goto error;
+                }
+            }
+        }
+    }
+  mpq_clear (a);
+  mpq_clear (b);
+  mpq_clear (got);
+  mpq_clear (want);
+  return;
+
+ error:
+  printf ("   base %d\n", data[i].base);
+  printf ("   expr \"%s\"\n", data[i].expr);
+  if (data[i].want != NULL)
+    printf ("   want \"%s\"\n", data[i].want);
+  abort ();
+}
+
+void
+check_f (void)
+{
+  const struct data_t  *data;
+  mpf_t  a, b, got, want;
+  int    l, i, ret;
+
+  mpf_set_default_prec (200L);
+
+  mpf_init (got);
+  mpf_init (want);
+  mpf_init_set_ui (a, 55);
+  mpf_init_set_ui (b, 99);
+
+  for (l = 0; l < numberof (list_f); l++)
+    {
+      data = list_f[l].data;
+
+      for (i = 0; i < list_f[l].num; i++)
+        {
+          if (option_trace)
+            printf ("mpf_expr \"%s\"\n", data[i].expr);
+
+          ret = mpf_expr (got, data[i].base, data[i].expr, a, b, NULL);
+
+          if (data[i].want == NULL)
+            {
+              /* expect to fail */
+              if (ret == MPEXPR_RESULT_OK)
+                {
+                  printf ("mpf_expr wrong return value, got %d, expected failure\n", ret);
+                  goto error;
+                }
+            }
+          else
+            {
+              if (mpf_set_str (want, data[i].want, 0) != 0)
+                {
+                  printf ("Cannot parse wanted value string\n");
+                  goto error;
+                }
+
+              if (ret != MPEXPR_RESULT_OK)
+                {
+                  printf ("mpf_expr failed unexpectedly\n");
+                  printf ("   return value %d\n", ret);
+                  goto error;
+                }
+              if (mpf_cmp (got, want) != 0)
+                {
+                  printf ("mpf_expr wrong result\n");
+                  printf ("   got  "); mpf_out_str (stdout, 10, 20, got);
+                  printf ("\n");
+                  printf ("   want "); mpf_out_str (stdout, 10, 20, want);
+                  printf ("\n");
+                  goto error;
+                }
+            }
+        }
+    }
+  mpf_clear (a);
+  mpf_clear (b);
+  mpf_clear (got);
+  mpf_clear (want);
+  return;
+
+ error:
+  printf ("   base %d\n", data[i].base);
+  printf ("   expr \"%s\"\n", data[i].expr);
+  if (data[i].want != NULL)
+    printf ("   want \"%s\"\n", data[i].want);
+  abort ();
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  tests_start ();
+
+  if (argc >= 2)
+    option_trace = 1;
+
+  check_z ();
+  check_q ();
+  check_f ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/demos/factorize.c b/third_party/gmp/demos/factorize.c
new file mode 100644
index 0000000..91e6455
--- /dev/null
+++ b/third_party/gmp/demos/factorize.c
@@ -0,0 +1,447 @@
+/* Factoring with Pollard's rho method.
+
+Copyright 1995, 1997-2003, 2005, 2009, 2012, 2015 Free Software
+Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 3 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program.  If not, see https://www.gnu.org/licenses/.  */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "gmp.h"
+
+static unsigned char primes_diff[] = {
+#define P(a,b,c) a,
+#include "primes.h"
+#undef P
+};
+#define PRIMES_PTAB_ENTRIES (sizeof(primes_diff) / sizeof(primes_diff[0]))
+
+int flag_verbose = 0;
+
+/* Prove primality or run probabilistic tests.  */
+int flag_prove_primality = 1;
+
+/* Number of Miller-Rabin tests to run when not proving primality. */
+#define MR_REPS 25
+
+struct factors
+{
+  mpz_t         *p;
+  unsigned long *e;
+  long nfactors;
+};
+
+void factor (mpz_t, struct factors *);
+
+void
+factor_init (struct factors *factors)
+{
+  factors->p = malloc (1);
+  factors->e = malloc (1);
+  factors->nfactors = 0;
+}
+
+void
+factor_clear (struct factors *factors)
+{
+  int i;
+
+  for (i = 0; i < factors->nfactors; i++)
+    mpz_clear (factors->p[i]);
+
+  free (factors->p);
+  free (factors->e);
+}
+
+void
+factor_insert (struct factors *factors, mpz_t prime)
+{
+  long    nfactors  = factors->nfactors;
+  mpz_t         *p  = factors->p;
+  unsigned long *e  = factors->e;
+  long i, j;
+
+  /* Locate position for insert new or increment e.  */
+  for (i = nfactors - 1; i >= 0; i--)
+    {
+      if (mpz_cmp (p[i], prime) <= 0)
+	break;
+    }
+
+  if (i < 0 || mpz_cmp (p[i], prime) != 0)
+    {
+      p = realloc (p, (nfactors + 1) * sizeof p[0]);
+      e = realloc (e, (nfactors + 1) * sizeof e[0]);
+
+      mpz_init (p[nfactors]);
+      for (j = nfactors - 1; j > i; j--)
+	{
+	  mpz_set (p[j + 1], p[j]);
+	  e[j + 1] = e[j];
+	}
+      mpz_set (p[i + 1], prime);
+      e[i + 1] = 1;
+
+      factors->p = p;
+      factors->e = e;
+      factors->nfactors = nfactors + 1;
+    }
+  else
+    {
+      e[i] += 1;
+    }
+}
+
+void
+factor_insert_ui (struct factors *factors, unsigned long prime)
+{
+  mpz_t pz;
+
+  mpz_init_set_ui (pz, prime);
+  factor_insert (factors, pz);
+  mpz_clear (pz);
+}
+
+
+void
+factor_using_division (mpz_t t, struct factors *factors)
+{
+  mpz_t q;
+  unsigned long int p;
+  int i;
+
+  if (flag_verbose > 0)
+    {
+      printf ("[trial division] ");
+    }
+
+  mpz_init (q);
+
+  p = mpz_scan1 (t, 0);
+  mpz_fdiv_q_2exp (t, t, p);
+  while (p)
+    {
+      factor_insert_ui (factors, 2);
+      --p;
+    }
+
+  p = 3;
+  for (i = 1; i <= PRIMES_PTAB_ENTRIES;)
+    {
+      if (! mpz_divisible_ui_p (t, p))
+	{
+	  p += primes_diff[i++];
+	  if (mpz_cmp_ui (t, p * p) < 0)
+	    break;
+	}
+      else
+	{
+	  mpz_tdiv_q_ui (t, t, p);
+	  factor_insert_ui (factors, p);
+	}
+    }
+
+  mpz_clear (q);
+}
+
+static int
+mp_millerrabin (mpz_srcptr n, mpz_srcptr nm1, mpz_ptr x, mpz_ptr y,
+		mpz_srcptr q, unsigned long int k)
+{
+  unsigned long int i;
+
+  mpz_powm (y, x, q, n);
+
+  if (mpz_cmp_ui (y, 1) == 0 || mpz_cmp (y, nm1) == 0)
+    return 1;
+
+  for (i = 1; i < k; i++)
+    {
+      mpz_powm_ui (y, y, 2, n);
+      if (mpz_cmp (y, nm1) == 0)
+	return 1;
+      if (mpz_cmp_ui (y, 1) == 0)
+	return 0;
+    }
+  return 0;
+}
+
+int
+mp_prime_p (mpz_t n)
+{
+  int k, r, is_prime;
+  mpz_t q, a, nm1, tmp;
+  struct factors factors;
+
+  if (mpz_cmp_ui (n, 1) <= 0)
+    return 0;
+
+  /* We have already casted out small primes. */
+  if (mpz_cmp_ui (n, (long) FIRST_OMITTED_PRIME * FIRST_OMITTED_PRIME) < 0)
+    return 1;
+
+  mpz_inits (q, a, nm1, tmp, NULL);
+
+  /* Precomputation for Miller-Rabin.  */
+  mpz_sub_ui (nm1, n, 1);
+
+  /* Find q and k, where q is odd and n = 1 + 2**k * q.  */
+  k = mpz_scan1 (nm1, 0);
+  mpz_tdiv_q_2exp (q, nm1, k);
+
+  mpz_set_ui (a, 2);
+
+  /* Perform a Miller-Rabin test, finds most composites quickly.  */
+  if (!mp_millerrabin (n, nm1, a, tmp, q, k))
+    {
+      is_prime = 0;
+      goto ret2;
+    }
+
+  if (flag_prove_primality)
+    {
+      /* Factor n-1 for Lucas.  */
+      mpz_set (tmp, nm1);
+      factor (tmp, &factors);
+    }
+
+  /* Loop until Lucas proves our number prime, or Miller-Rabin proves our
+     number composite.  */
+  for (r = 0; r < PRIMES_PTAB_ENTRIES; r++)
+    {
+      int i;
+
+      if (flag_prove_primality)
+	{
+	  is_prime = 1;
+	  for (i = 0; i < factors.nfactors && is_prime; i++)
+	    {
+	      mpz_divexact (tmp, nm1, factors.p[i]);
+	      mpz_powm (tmp, a, tmp, n);
+	      is_prime = mpz_cmp_ui (tmp, 1) != 0;
+	    }
+	}
+      else
+	{
+	  /* After enough Miller-Rabin runs, be content. */
+	  is_prime = (r == MR_REPS - 1);
+	}
+
+      if (is_prime)
+	goto ret1;
+
+      mpz_add_ui (a, a, primes_diff[r]);	/* Establish new base.  */
+
+      if (!mp_millerrabin (n, nm1, a, tmp, q, k))
+	{
+	  is_prime = 0;
+	  goto ret1;
+	}
+    }
+
+  fprintf (stderr, "Lucas prime test failure.  This should not happen\n");
+  abort ();
+
+ ret1:
+  if (flag_prove_primality)
+    factor_clear (&factors);
+ ret2:
+  mpz_clears (q, a, nm1, tmp, NULL);
+
+  return is_prime;
+}
+
+void
+factor_using_pollard_rho (mpz_t n, unsigned long a, struct factors *factors)
+{
+  mpz_t x, z, y, P;
+  mpz_t t, t2;
+  unsigned long long k, l, i;
+
+  if (flag_verbose > 0)
+    {
+      printf ("[pollard-rho (%lu)] ", a);
+    }
+
+  mpz_inits (t, t2, NULL);
+  mpz_init_set_si (y, 2);
+  mpz_init_set_si (x, 2);
+  mpz_init_set_si (z, 2);
+  mpz_init_set_ui (P, 1);
+  k = 1;
+  l = 1;
+
+  while (mpz_cmp_ui (n, 1) != 0)
+    {
+      for (;;)
+	{
+	  do
+	    {
+	      mpz_mul (t, x, x);
+	      mpz_mod (x, t, n);
+	      mpz_add_ui (x, x, a);
+
+	      mpz_sub (t, z, x);
+	      mpz_mul (t2, P, t);
+	      mpz_mod (P, t2, n);
+
+	      if (k % 32 == 1)
+		{
+		  mpz_gcd (t, P, n);
+		  if (mpz_cmp_ui (t, 1) != 0)
+		    goto factor_found;
+		  mpz_set (y, x);
+		}
+	    }
+	  while (--k != 0);
+
+	  mpz_set (z, x);
+	  k = l;
+	  l = 2 * l;
+	  for (i = 0; i < k; i++)
+	    {
+	      mpz_mul (t, x, x);
+	      mpz_mod (x, t, n);
+	      mpz_add_ui (x, x, a);
+	    }
+	  mpz_set (y, x);
+	}
+
+    factor_found:
+      do
+	{
+	  mpz_mul (t, y, y);
+	  mpz_mod (y, t, n);
+	  mpz_add_ui (y, y, a);
+
+	  mpz_sub (t, z, y);
+	  mpz_gcd (t, t, n);
+	}
+      while (mpz_cmp_ui (t, 1) == 0);
+
+      mpz_divexact (n, n, t);	/* divide by t, before t is overwritten */
+
+      if (!mp_prime_p (t))
+	{
+	  if (flag_verbose > 0)
+	    {
+	      printf ("[composite factor--restarting pollard-rho] ");
+	    }
+	  factor_using_pollard_rho (t, a + 1, factors);
+	}
+      else
+	{
+	  factor_insert (factors, t);
+	}
+
+      if (mp_prime_p (n))
+	{
+	  factor_insert (factors, n);
+	  break;
+	}
+
+      mpz_mod (x, x, n);
+      mpz_mod (z, z, n);
+      mpz_mod (y, y, n);
+    }
+
+  mpz_clears (P, t2, t, z, x, y, NULL);
+}
+
+void
+factor (mpz_t t, struct factors *factors)
+{
+  factor_init (factors);
+
+  if (mpz_sgn (t) != 0)
+    {
+      factor_using_division (t, factors);
+
+      if (mpz_cmp_ui (t, 1) != 0)
+	{
+	  if (flag_verbose > 0)
+	    {
+	      printf ("[is number prime?] ");
+	    }
+	  if (mp_prime_p (t))
+	    factor_insert (factors, t);
+	  else
+	    factor_using_pollard_rho (t, 1, factors);
+	}
+    }
+}
+
+int
+main (int argc, char *argv[])
+{
+  mpz_t t;
+  int i, j, k;
+  struct factors factors;
+
+  while (argc > 1)
+    {
+      if (!strcmp (argv[1], "-v"))
+	flag_verbose = 1;
+      else if (!strcmp (argv[1], "-w"))
+	flag_prove_primality = 0;
+      else
+	break;
+
+      argv++;
+      argc--;
+    }
+
+  mpz_init (t);
+  if (argc > 1)
+    {
+      for (i = 1; i < argc; i++)
+	{
+	  mpz_set_str (t, argv[i], 0);
+
+	  gmp_printf ("%Zd:", t);
+	  factor (t, &factors);
+
+	  for (j = 0; j < factors.nfactors; j++)
+	    for (k = 0; k < factors.e[j]; k++)
+	      gmp_printf (" %Zd", factors.p[j]);
+
+	  puts ("");
+	  factor_clear (&factors);
+	}
+    }
+  else
+    {
+      for (;;)
+	{
+	  mpz_inp_str (t, stdin, 0);
+	  if (feof (stdin))
+	    break;
+
+	  gmp_printf ("%Zd:", t);
+	  factor (t, &factors);
+
+	  for (j = 0; j < factors.nfactors; j++)
+	    for (k = 0; k < factors.e[j]; k++)
+	      gmp_printf (" %Zd", factors.p[j]);
+
+	  puts ("");
+	  factor_clear (&factors);
+	}
+    }
+
+  exit (0);
+}
diff --git a/third_party/gmp/demos/isprime.c b/third_party/gmp/demos/isprime.c
new file mode 100644
index 0000000..bf06945
--- /dev/null
+++ b/third_party/gmp/demos/isprime.c
@@ -0,0 +1,69 @@
+/* Classify numbers as probable primes, primes or composites.
+   With -q return true if the following argument is a (probable) prime.
+
+Copyright 1999, 2000, 2002, 2005, 2012 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 3 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "gmp.h"
+
+char *progname;
+
+void
+print_usage_and_exit ()
+{
+  fprintf (stderr, "usage: %s -q nnn\n", progname);
+  fprintf (stderr, "usage: %s nnn ...\n", progname);
+  exit (-1);
+}
+
+int
+main (int argc, char **argv)
+{
+  mpz_t n;
+  int i;
+
+  progname = argv[0];
+
+  if (argc < 2)
+    print_usage_and_exit ();
+
+  mpz_init (n);
+
+  if (argc == 3 && strcmp (argv[1], "-q") == 0)
+    {
+      if (mpz_set_str (n, argv[2], 0) != 0)
+	print_usage_and_exit ();
+      exit (mpz_probab_prime_p (n, 25) == 0);
+    }
+
+  for (i = 1; i < argc; i++)
+    {
+      int class;
+      if (mpz_set_str (n, argv[i], 0) != 0)
+	print_usage_and_exit ();
+      class = mpz_probab_prime_p (n, 25);
+      mpz_out_str (stdout, 10, n);
+      if (class == 0)
+	puts (" is composite");
+      else if (class == 1)
+	puts (" is a probable prime");
+      else /* class == 2 */
+	puts (" is a prime");
+    }
+  exit (0);
+}
diff --git a/third_party/gmp/demos/perl/GMP.pm b/third_party/gmp/demos/perl/GMP.pm
new file mode 100644
index 0000000..46bc707
--- /dev/null
+++ b/third_party/gmp/demos/perl/GMP.pm
@@ -0,0 +1,671 @@
+# GMP perl module
+
+# Copyright 2001-2004 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+# [Note: The above copyright notice is repeated in the documentation section
+# below, in order to get it into man pages etc generated by the various pod
+# conversions.  When changing, be sure to update below too.]
+
+
+# This code is designed to work with perl 5.005, so it and the sub-packages
+# aren't as modern as they could be.
+
+package GMP;
+
+require Symbol;
+require Exporter;
+require DynaLoader;
+@ISA = qw(Exporter DynaLoader);
+
+@EXPORT = qw();
+@EXPORT_OK = qw(version);
+%EXPORT_TAGS = ('all' => [qw(
+                             get_d get_d_2exp get_si get_str integer_p
+                             printf sgn sprintf)],
+		'constants' => [()]);
+Exporter::export_ok_tags('all');
+
+$VERSION = '2.00';
+bootstrap GMP $VERSION;
+
+
+# The format string is cut up into "%" specifiers so GMP types can be
+# passed to GMP::sprintf_internal.  Any "*"s are interpolated before
+# calling sprintf_internal, which saves worrying about variable
+# argument lists there.
+#
+# Because sprintf_internal is only called after the conversion and
+# operand have been checked there won't be any crashes from a bad
+# format string.
+#
+sub sprintf {
+  my $fmt = shift;
+  my $out = '';
+  my ($pre, $dummy, $pat, $rest);
+
+  while (($pre, $dummy, $pat, $rest) = ($fmt =~ /^((%%|[^%])*)(%[- +#.*hlLqv\d]*[bcdfeEgGinopsuxX])(.*)$/s)) {
+
+    $out .= $pre;
+
+    my $pat2 = $pat;    # $pat with "*"s expanded
+    my @params = ();    # arguments per "*"s
+    while ($pat2 =~ /[*]/) {
+      my $arg = shift;
+      $pat2 =~ s/[*]/$arg/;
+      push @params, $arg;
+    }
+
+    if (UNIVERSAL::isa($_[0],"GMP::Mpz")) {
+      if ($pat2 !~ /[dioxX]$/) {
+	die "GMP::sprintf: unsupported output format for mpz: $pat2\n";
+      }
+      $pat2 =~ s/(.)$/Z$1/;
+      $out .= sprintf_internal ($pat2, shift);
+
+    } elsif (UNIVERSAL::isa($_[0],"GMP::Mpq")) {
+      if ($pat2 !~ /[dioxX]$/) {
+	die "GMP::sprintf: unsupported output format for mpq: $pat2\n";
+      }
+      $pat2 =~ s/(.)$/Q$1/;
+      $out .= sprintf_internal ($pat2, shift);
+
+    } elsif (UNIVERSAL::isa($_[0],"GMP::Mpf")) {
+      if ($pat2 !~ /[eEfgG]$/) {
+	die "GMP::sprintf: unsupported output format for mpf: $pat2\n";
+      }
+      $pat2 =~ s/(.)$/F$1/;
+      $out .= sprintf_internal ($pat2, shift);
+
+    } elsif ($pat =~ /n$/) {
+      # do it this way so h, l or V type modifiers are respected, and use a
+      # dummy variable to avoid a warning about discarding the value
+      my $dummy = sprintf "%s$pat", $out, $_[0];
+      shift;
+
+    } else {
+      $out .= sprintf $pat, @params, shift;
+    }
+
+    $fmt = $rest;
+  }
+  $out .= $fmt;
+  return $out;
+}
+
+sub printf {
+  if (ref($_[0]) eq 'GLOB') {
+    my $h = Symbol::qualify_to_ref(shift, caller);
+    print $h GMP::sprintf(@_);
+  } else {
+    print STDOUT GMP::sprintf(@_);
+  }
+}
+
+1;
+__END__
+
+
+
+=head1 NAME
+
+GMP - Perl interface to the GNU Multiple Precision Arithmetic Library
+
+=head1 SYNOPSIS
+
+    use GMP;
+    use GMP::Mpz;
+    use GMP::Mpq;
+    use GMP::Mpf;
+    use GMP::Rand;
+
+=head1 DESCRIPTION
+
+This module provides access to GNU MP arbitrary precision integers,
+rationals and floating point.
+
+No functions are exported from these packages by default, but can be
+selected in the usual way, or the tag :all for everything.
+
+    use GMP::Mpz qw(gcd, lcm);   # just these functions
+    use GMP::Mpq qw(:all);       # everything in mpq
+
+=head2 GMP::Mpz
+
+This class provides arbitrary precision integers.  A new mpz can be
+constructed with C<mpz>.  The initial value can be an integer, float,
+string, mpz, mpq or mpf.  Floats, mpq and mpf will be automatically
+truncated to an integer.
+
+    use GMP::Mpz qw(:all);
+    my $a = mpz(123);
+    my $b = mpz("0xFFFF");
+    my $c = mpz(1.5);       # truncated
+
+The following overloaded operators are available, and corresponding
+assignment forms like C<+=>,
+
+=over 4
+
+=item
+
++ - * / % E<lt>E<lt> E<gt>E<gt> ** & | ^ ! E<lt> E<lt>= == != E<gt> E<gt>=
+E<lt>=E<gt> abs not sqrt
+
+=back
+
+C</> and C<%> round towards zero (as per the C<tdiv> functions in GMP).
+
+The following functions are available, behaving the same as the
+corresponding GMP mpz functions,
+
+=over 4
+
+=item
+
+bin, cdiv, cdiv_2exp, clrbit, combit, congruent_p, congruent_2exp_p,
+divexact, divisible_p, divisible_2exp_p, even_p, fac, fdiv, fdiv_2exp, fib,
+fib2, gcd, gcdext, hamdist, invert, jacobi, kronecker, lcm, lucnum, lucnum2,
+mod, mpz_export, mpz_import, nextprime, odd_p, perfect_power_p,
+perfect_square_p, popcount, powm, probab_prime_p, realloc, remove, root,
+roote, scan0, scan1, setbit, sizeinbase, sqrtrem, tdiv, tdiv_2exp, tstbit
+
+=back
+
+C<cdiv>, C<fdiv> and C<tdiv> and their C<2exp> variants return a
+quotient/remainder pair.  C<fib2> returns a pair F[n] and F[n-1], similarly
+C<lucnum2>.  C<gcd> and C<lcm> accept a variable number of arguments (one or
+more).  C<gcdext> returns a triplet of gcd and two cofactors, for example
+
+    use GMP::Mpz qw(:all);
+    $a = 7257;
+    $b = 10701;
+    ($g, $x, $y) = gcdext ($a, $b);
+    print "gcd($a,$b) is $g, and $g == $a*$x + $b*$y\n";
+
+C<mpz_import> and C<mpz_export> are so named to avoid the C<import> keyword.
+Their parameters are as follows,
+
+    $z = mpz_import ($order, $size, $endian, $nails, $string);
+    $string = mpz_export ($order, $size, $endian, $nails, $z);
+
+The order, size, endian and nails parameters are as per the corresponding C
+functions.  The string input for C<mpz_import> is interpreted as byte data
+and must be a multiple of $size bytes.  C<mpz_export> conversely returns a
+string of byte data, which will be a multiple of $size bytes.
+
+C<invert> returns the inverse, or undef if it doesn't exist.  C<remove>
+returns a remainder/multiplicity pair.  C<root> returns the nth root, and
+C<roote> returns a root/bool pair, the bool indicating whether the root is
+exact.  C<sqrtrem> and C<rootrem> return a root/remainder pair.
+
+C<clrbit>, C<combit> and C<setbit> expect a variable which they can modify,
+it doesn't make sense to pass a literal constant.  Only the given variable
+is modified, if other variables are referencing the same mpz object then a
+new copy is made of it.  If the variable isn't an mpz it will be coerced to
+one.  For instance,
+
+    use GMP::Mpz qw(setbit);
+    setbit (123, 0);  # wrong, don't pass a constant
+    $a = mpz(6);
+    $b = $a;
+    setbit ($a, 0);   # $a becomes 7, $b stays at 6
+
+C<scan0> and C<scan1> return ~0 if no 0 or 1 bit respectively is found.
+
+=head2 GMP::Mpq
+
+This class provides rationals with arbitrary precision numerators and
+denominators.  A new mpq can be constructed with C<mpq>.  The initial value
+can be an integer, float, string, mpz, mpq or mpf, or a pair of integers or
+mpz's.  No precision is lost when converting a float or mpf, the exact value
+is retained.
+
+    use GMP::Mpq qw(:all);
+    $a = mpq();              # zero
+    $b = mpq(0.5);           # gives 1/2
+    $b = mpq(14);            # integer 14
+    $b = mpq(3,4);           # fraction 3/4
+    $b = mpq("7/12");        # fraction 7/12
+    $b = mpq("0xFF/0x100");  # fraction 255/256
+
+When a fraction is given, it should be in the canonical form specified in
+the GMP manual, which is denominator positive, no common factors, and zero
+always represented as 0/1.  If not then C<canonicalize> can be called to put
+it in that form.  For example,
+
+    use GMP::Mpq qw(:all);
+    $q = mpq(21,15);   # eek! common factor 3
+    canonicalize($q);  # get rid of it
+
+The following overloaded operators are available, and corresponding
+assignment forms like C<+=>,
+
+=over 4
+
+=item
+
++ - * / E<lt>E<lt> E<gt>E<gt> ** ! E<lt> E<lt>= == != E<gt> E<gt>=
+E<lt>=E<gt> abs not
+
+=back
+
+The following functions are available,
+
+=over 4
+
+=item
+
+den, inv, num
+
+=back
+
+C<inv> calculates 1/q, as per the corresponding GMP function.  C<num> and
+C<den> return an mpz copy of the numerator or denominator respectively.  In
+the future C<num> and C<den> might give lvalues so the original mpq can be
+modified through them, but this is not done currently.
+
+=head2 GMP::Mpf
+
+This class provides arbitrary precision floating point numbers.  The
+mantissa is an arbitrary user-selected precision and the exponent is a fixed
+size (one machine word).
+
+A new mpf can be constructed with C<mpf>.  The initial value can be an
+integer, float, string, mpz, mpq or mpf.  The second argument specifies the
+desired precision in bits, or if omitted then the default precision is used.
+
+    use GMP::Mpf qw(:all);
+    $a = mpf();         # zero
+    $b = mpf(-7.5);     # default precision
+    $c = mpf(1.5, 500); # 500 bits precision
+    $d = mpf("1.0000000000000001");
+
+The following overloaded operators are available, with the corresponding
+assignment forms like C<+=>,
+
+=over 4
+
+=item
+
++ - * / E<lt>E<lt> E<gt>E<gt> ** ! E<lt> E<lt>= == != E<gt> E<gt>=
+E<lt>=E<gt> abs not sqrt
+
+=back
+
+The following functions are available, behaving the same as the
+corresponding GMP mpf functions,
+
+=over 4
+
+=item
+
+ceil, floor, get_default_prec, get_prec, mpf_eq, set_default_prec, set_prec,
+trunc
+
+=back
+
+C<mpf_eq> is so named to avoid clashing with the perl C<eq> operator.
+
+C<set_prec> expects a variable which it can modify, it doesn't make sense to
+pass a literal constant.  Only the given variable is modified, if other
+variables are referencing the same mpf object then a new copy is made of it.
+If the variable isn't an mpf it will be coerced to one.
+
+Results are the same precision as inputs, or if two mpf's are given to a
+binary operator then the precision of the first is used.  For example,
+
+    use GMP::Mpf qw(mpf);
+    $a = mpf(2.0, 100);
+    $b = mpf(2.0, 500);
+    $c = $a + $b;         # gives 100 bits precision
+
+Mpf to string conversion via "" or the usual string contexts uses C<$#> the
+same as normal float to string conversions, or defaults to C<%.g> if C<$#>
+is not defined.  C<%.g> means all significant digits in the selected
+precision.
+
+=head2 GMP class
+
+The following functions are available in the GMP class,
+
+=over 4
+
+=item
+
+fits_slong_p, get_d, get_d_2exp, get_si, get_str, integer_p, printf, sgn,
+sprintf, version
+
+=back
+
+C<get_d_2exp> accepts any integer, string, float, mpz, mpq or mpf operands
+and returns a float and an integer exponent,
+
+    ($dbl, $exp) = get_d_2exp (mpf ("3.0"));
+    # dbl is 0.75, exp is 2
+
+C<get_str> takes an optional second argument which is the base, defaulting
+to decimal.  A negative base means upper case, as per the C functions.  For
+integer, integer string, mpz or mpq operands a string is returned.
+
+    use GMP qw(:all);
+    use GMP::Mpq qw(:all);
+    print get_str(mpq(-5,8)),"\n";      # -5/8
+    print get_str(255,16),"\n";         # ff
+
+For float, float strings or mpf operands, C<get_str> accepts an optional
+third parameter being how many digits to produce, defaulting to 0 which
+means all digits.  (Only as many digits as can be accurately represented by
+the float precision are ever produced though.)  A string/exponent pair is
+returned, as per the C mpf_get_str function.  For example,
+
+    use GMP qw(:all);
+    use GMP::Mpf qw(:all);
+    ($s, $e) = get_str(111.111111111, 10, 4);
+    printf ".$se$e\n";                  # .1111e3
+    ($s, $e) = get_str(1.625, 10);
+    print "0.$s*10^$e\n";               # 0.1625*10^1
+    ($s, $e) = get_str(mpf(2)**20, 16);
+    printf ".%s@%x\n", $s, $e;          # .1@14
+
+C<printf> and C<sprintf> allow formatted output of GMP types.  mpz and mpq
+values can be used with integer conversions (d, o, x, X) and mpf with float
+conversions (f, e, E, g, G).  All the standard perl printf features are
+available too.  For example,
+
+    use GMP::Mpz qw(mpz);
+    use GMP::Mpf qw(mpf);
+    GMP::printf ("%d %d %s", 123, mpz(2)**128, 'foo');
+    GMP::printf STDERR "%.40f", mpf(1.234);
+
+In perl 5.6.1 it doesn't seem to work to export C<printf>, the plain builtin
+C<printf> is reached unless calls are C<&printf()> style.  Explicit use of
+C<GMP::printf> is suggested.  C<sprintf> doesn't suffer this problem.
+
+    use GMP qw(sprintf);
+    use GMP::Mpq qw(mpq);
+    $s = sprintf "%x", mpq(15,16);
+
+C<version> is not exported by default or by tag :all, calling it as
+C<GMP::version()> is recommended.  It returns the GMP library version
+string, which is not to be confused with the module version number.
+
+The other GMP module functions behave as per the corresponding GMP routines,
+and accept any integer, string, float, mpz, mpq or mpf.  For example,
+
+    use GMP qw(:all);
+    use GMP::Mpz qw(mpz);
+    $z = mpz(123);
+    print sgn($z);    # gives 1
+
+Because each of GMP::Mpz, GMP::Mpq and GMP::Mpf is a sub-class of GMP,
+C<-E<gt>> style calls work too.
+
+    use GMP qw(:all);
+    use GMP::Mpq qw(mpf);
+    $q = mpq(-5,7);
+    if ($q->integer_p())   # false
+      ...
+
+=head2 GMP::Rand
+
+This class provides objects holding an algorithm and state for random number
+generation.  C<randstate> creates a new object, for example,
+
+    use GMP::Rand qw(randstate);
+    $r = randstate();
+    $r = randstate('lc_2exp_size', 64);
+    $r = randstate('lc_2exp', 43840821, 1, 32);
+    $r = randstate('mt');
+    $r = randstate($another_r);
+
+With no parameters this corresponds to the C function
+C<gmp_randinit_default>, and is a compromise between speed and randomness.
+'lc_2exp_size' corresponds to C<gmp_randinit_lc_2exp_size>, 'lc_2exp'
+corresponds to C<gmp_randinit_lc_2exp>, and 'mt' corresponds to
+C<gmp_randinit_mt>.  Or when passed another randstate object, a copy of that
+object is made.
+
+'lc_2exp_size' can fail if the requested size is bigger than the internal
+table provides for, in which case undef is returned.  The maximum size
+currently supported is 128.  The other forms always succeed.
+
+A randstate can be seeded with an integer or mpz, using the C<seed> method.
+/dev/random might be a good source of randomness, or time() or
+Time::HiRes::time() might be adequate, depending on the application.
+
+    $r->seed(time()));
+
+Random numbers can be generated with the following functions,
+
+=over 4
+
+=item
+
+mpf_urandomb, mpz_rrandomb, mpz_urandomb, mpz_urandomm,
+gmp_urandomb_ui, gmp_urandomm_ui
+
+=back
+
+Each constructs a new mpz or mpf and with a distribution per the
+corresponding GMP function.  For example,
+
+    use GMP::Rand (:all);
+    $r = randstate();
+    $a = mpz_urandomb($r,256);         # uniform mpz, 256 bits
+    $b = mpz_urandomm($r,mpz(3)**100); # uniform mpz, 0 to 3**100-1
+    $c = mpz_rrandomb($r,1024);        # special mpz, 1024 bits
+    $f = mpf_urandomb($r,128);         # uniform mpf, 128 bits, 0<=$f<1
+    $f = gmp_urandomm_ui($r,56);       # uniform int, 0 to 55
+
+=head2 Coercion
+
+Arguments to operators and functions are converted as necessary to the
+appropriate type.  For instance C<**> requires an unsigned integer exponent,
+and an mpq argument will be converted, so long as it's an integer in the
+appropriate range.
+
+    use GMP::Mpz (mpz);
+    use GMP::Mpq (mpq);
+    $p = mpz(3) ** mpq(45);   # allowed, 45 is an integer
+
+It's an error if a conversion to an integer or mpz would cause any
+truncation.  For example,
+
+    use GMP::Mpz (mpz);
+    $p = mpz(3) + 1.25;       # not allowed
+    $p = mpz(3) + mpz(1.25);  # allowed, explicit truncation
+
+Comparisons, however, accept any combination of operands and are always done
+exactly.  For example,
+
+    use GMP::Mpz (mpz);
+    print mpz(3) < 3.1;       # true
+
+Variables used on the left of an assignment operator like C<+=> are subject
+to coercion too.  An integer, float or string will change type when an mpz,
+mpq or mpf is applied to it.  For example,
+
+    use GMP::Mpz (mpz);
+    $a = 1;
+    $a += mpz(1234);   # $a becomes an mpz
+
+=head2 Overloading
+
+The rule for binary operators in the C<overload> mechanism is that if both
+operands are class objects then the method from the first is used.  This
+determines the result type when mixing GMP classes.  For example,
+
+    use GMP::Mpz (mpz);
+    use GMP::Mpq (mpq);
+    use GMP::Mpf (mpf);
+    $z = mpz(123);
+    $q = mpq(3,2);
+    $f = mpf(1.375)
+    print $q+$f;     # gives an mpq
+    print $f+$z;     # gives an mpf
+    print $z+$f;     # not allowed, would lose precision
+
+=head2 Constants
+
+A special tag C<:constants> is recognised in the module exports list.  It
+doesn't select any functions, but indicates that perl constants should be
+GMP objects.  This can only be used on one of GMP::Mpz, GMP::Mpq or GMP::Mpf
+at any one time, since they apply different rules.
+
+GMP::Mpz will treat constants as mpz's if they're integers, or ordinary
+floats if not.  For example,
+
+    use GMP::Mpz qw(:constants);
+    print 764861287634126387126378128,"\n";   # an mpz
+    print 1.25,"\n";                          # a float
+
+GMP::Mpq is similar, treating integers as mpq's and leaving floats to the
+normal perl handling.  Something like 3/4 is read as two integer mpq's and a
+division, but that's fine since it gives the intended fraction.
+
+    use GMP::Mpq qw(:constants);
+    print 3/4,"\n";    # an mpq
+    print 1.25,"\n";   # a float
+
+GMP::Mpf will treat all constants as mpf's using the default precision.
+BEGIN blocks can be used to set that precision while the code is parsed.
+For example,
+
+    use GMP::Mpf qw(:constants);
+    BEGIN { GMP::Mpf::set_default_prec(256); }
+    print 1/3;
+    BEGIN { GMP::Mpf::set_default_prec(64); }
+    print 5/7;
+
+A similar special tag :noconstants is recognised to turn off the constants
+feature.  For example,
+
+    use GMP::Mpz qw(:constants);
+    print 438249738748174928193,"\n";   # an mpz
+    use GMP::Mpz qw(:noconstants);
+    print 438249738748174928193,"\n";   # now a float
+
+All three 'integer', 'binary' and 'float' constant methods are captured.
+'float' is captured even for GMP::Mpz and GMP::Mpq since perl by default
+treats integer strings as floats if they don't fit a plain integer.
+
+=head1 SEE ALSO
+
+GMP manual, L<perl>, L<overload>.
+
+=head1 BUGS
+
+In perl 5.005_03 on i386 FreeBSD, the overloaded constants sometimes provoke
+seg faults.  Don't know if that's a perl bug or a GMP module bug, though it
+does seem to go bad before reaching anything in GMP.xs.
+
+There's no way to specify an arbitrary base when converting a string to an
+mpz (or mpq or mpf), only hex or octal with 0x or 0 (for mpz and mpq, but
+not for mpf).
+
+These modules are not reentrant or thread safe, due to the implementation of
+the XSUBs.
+
+Returning a new object from the various functions is convenient, but
+assignment versions could avoid creating new objects.  Perhaps they could be
+named after the C language functions, eg. mpq_inv($q,$q);
+
+It'd be good if C<num> and C<den> gave lvalues so the underlying mpq could
+be manipulated.
+
+C<printf> could usefully accept %b for mpz, mpq and mpf, and perhaps %x for
+mpf too.
+
+C<get_str> returning different style values for integer versus float is a
+bit unfortunate.  With mpz, mpq and mpf objects there's no doubt what it
+will do, but on a plain scalar its action depends on whether the scalar was
+promoted to a float at any stage, and then on the GMP module rules about
+using the integer or float part.
+
+=head1 INTERNALS
+
+In usual perl object style, an mpz is a reference to an object blessed into
+class C<GMP::Mpz>.  The object holds a pointer to the C language C<mpz_t>
+structure.  Similarly for mpq, mpf and randstate.
+
+A free list of mpz and mpq values is kept to avoid repeated initializing and
+clearing when objects are created and destroyed.  This aims to help speed,
+but it's not clear whether it's really needed.
+
+mpf doesn't use a free list because the precision of new objects can be
+different each time.
+
+No interface to C<mpf_set_prec_raw> is provided.  It wouldn't be very useful
+since there's no way to make an operation store its result in a particular
+object.  The plain C<set_prec> is useful though, for truncating to a lower
+precision, or as a sort of directive that subsequent calculations involving
+that variable should use a higher precision.
+
+The overheads of perl dynamic typing (operator dispatch, operand type
+checking or coercion) will mean this interface is slower than using C
+directly.
+
+Some assertion checking is available as a compile-time option.
+
+=head1 COPYRIGHT
+
+Copyright 2001-2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.
+
+=cut
+
+# Local variables:
+# perl-indent-level: 2
+# fill-column: 76
+# End:
diff --git a/third_party/gmp/demos/perl/GMP.xs b/third_party/gmp/demos/perl/GMP.xs
new file mode 100644
index 0000000..8f5acc9
--- /dev/null
+++ b/third_party/gmp/demos/perl/GMP.xs
@@ -0,0 +1,3212 @@
+/* GMP module external subroutines.
+
+Copyright 2001-2003, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.
+
+
+/* Notes:
+
+   Routines are grouped with the alias feature and a table of function
+   pointers where possible, since each xsub routine ends up with quite a bit
+   of code size.  Different combinations of arguments and return values have
+   to be separate though.
+
+   The "INTERFACE:" feature isn't available in perl 5.005 and so isn't used.
+   "ALIAS:" requires a table lookup with CvXSUBANY(cv).any_i32 (which is
+   "ix") whereas "INTERFACE:" would have CvXSUBANY(cv).any_dptr as the
+   function pointer immediately.
+
+   Mixed-type swapped-order assignments like "$a = 123; $a += mpz(456);"
+   invoke the plain overloaded "+", not "+=", which makes life easier.
+
+   mpz_assume etc types are used with the overloaded operators since such
+   operators are always called with a class object as the first argument, we
+   don't need an sv_derived_from() lookup to check.  There's assert()s in
+   MPX_ASSUME() for this though.
+
+   The overload_constant routines reached via overload::constant get 4
+   arguments in perl 5.6, not the 3 as documented.  This is apparently a
+   bug, using "..." lets us ignore the extra one.
+
+   There's only a few "si" functions in gmp, so usually SvIV values get
+   handled with an mpz_set_si into a temporary and then a full precision mpz
+   routine.  This is reasonably efficient.
+
+   Argument types are checked, with a view to preserving all bits in the
+   operand.  Perl is a bit looser in its arithmetic, allowing rounding or
+   truncation to an intended operand type (IV, UV or NV).
+
+   Bugs:
+
+   The memory leak detection attempted in GMP::END() doesn't work when mpz's
+   are created as constants because END() is called before they're
+   destroyed.  What's the right place to hook such a check?
+
+   See the bugs section of GMP.pm too.  */
+
+
+/* Comment this out to get assertion checking. */
+#define NDEBUG
+
+/* Change this to "#define TRACE(x) x" for some diagnostics. */
+#define TRACE(x)
+
+
+#include <assert.h>
+#include <float.h>
+
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+#include "patchlevel.h"
+
+#include "gmp.h"
+
+
+/* Perl 5.005 doesn't have SvIsUV, only 5.6 and up.
+   Perl 5.8 has SvUOK, but not 5.6, so we don't use that.  */
+#ifndef SvIsUV
+#define SvIsUV(sv)  0
+#endif
+#ifndef SvUVX
+#define SvUVX(sv)  (croak("GMP: oops, shouldn't be using SvUVX"), 0)
+#endif
+
+
+/* Code which doesn't check anything itself, but exists to support other
+   assert()s.  */
+#ifdef NDEBUG
+#define assert_support(x)
+#else
+#define assert_support(x) x
+#endif
+
+/* LONG_MAX + 1 and ULONG_MAX + 1, as a doubles */
+#define LONG_MAX_P1_AS_DOUBLE   ((double) ((unsigned long) LONG_MAX + 1))
+#define ULONG_MAX_P1_AS_DOUBLE  (2.0 * (double) ((unsigned long) ULONG_MAX/2 + 1))
+
+/* Check for perl version "major.minor".
+   Perl 5.004 doesn't have PERL_REVISION and PERL_VERSION, but that's ok,
+   we're only interested in tests above that.  */
+#if defined (PERL_REVISION) && defined (PERL_VERSION)
+#define PERL_GE(major,minor)                                    \
+    (PERL_REVISION > (major)                                    \
+     || ((major) == PERL_REVISION && PERL_VERSION >= (minor)))
+#else
+#define PERL_GE(major,minor)  (0)
+#endif
+#define PERL_LT(major,minor)  (! PERL_GE(major,minor))
+
+/* sv_derived_from etc in 5.005 took "char *" rather than "const char *".
+   Avoid some compiler warnings by using const only where it works.  */
+#if PERL_LT (5,6)
+#define classconst
+#else
+#define classconst const
+#endif
+
+/* In a MINGW or Cygwin DLL build of gmp, the various gmp functions are
+   given with dllimport directives, which prevents them being used as
+   initializers for constant data.  We give function tables as
+   "static_functable const ...", which is normally "static const", but for
+   mingw expands to just "const" making the table an automatic with a
+   run-time initializer.
+
+   In gcc 3.3.1, the function tables initialized like this end up getting
+   all the __imp__foo values fetched, even though just one or two will be
+   used.  This is wasteful, but probably not too bad.  */
+
+#if defined (__MINGW32__) || defined (__CYGWIN__)
+#define static_functable
+#else
+#define static_functable  static
+#endif
+
+#define GMP_MALLOC_ID  42
+
+static classconst char mpz_class[]  = "GMP::Mpz";
+static classconst char mpq_class[]  = "GMP::Mpq";
+static classconst char mpf_class[]  = "GMP::Mpf";
+static classconst char rand_class[] = "GMP::Rand";
+
+static HV *mpz_class_hv;
+static HV *mpq_class_hv;
+static HV *mpf_class_hv;
+
+assert_support (static long mpz_count = 0;)
+assert_support (static long mpq_count = 0;)
+assert_support (static long mpf_count = 0;)
+assert_support (static long rand_count = 0;)
+
+#define TRACE_ACTIVE()                                                   \
+  assert_support                                                         \
+  (TRACE (printf ("  active %ld mpz, %ld mpq, %ld mpf, %ld randstate\n", \
+                  mpz_count, mpq_count, mpf_count, rand_count)))
+
+
+/* Each "struct mpz_elem" etc is an mpz_t with a link field tacked on the
+   end so they can be held on a linked list.  */
+
+#define CREATE_MPX(type)                                \
+                                                        \
+  /* must have mpz_t etc first, for sprintf below */    \
+  struct type##_elem {                                  \
+    type##_t            m;                              \
+    struct type##_elem  *next;                          \
+  };                                                    \
+  typedef struct type##_elem  *type;                    \
+  typedef struct type##_elem  *type##_assume;           \
+  typedef type##_ptr          type##_coerce;            \
+                                                        \
+  static type type##_freelist = NULL;                   \
+                                                        \
+  static type                                           \
+  new_##type (void)                                     \
+  {                                                     \
+    type p;                                             \
+    TRACE (printf ("new %s\n", type##_class));          \
+    if (type##_freelist != NULL)                        \
+      {                                                 \
+        p = type##_freelist;                            \
+        type##_freelist = type##_freelist->next;        \
+      }                                                 \
+    else                                                \
+      {                                                 \
+        New (GMP_MALLOC_ID, p, 1, struct type##_elem);  \
+        type##_init (p->m);                             \
+      }                                                 \
+    TRACE (printf ("  p=%p\n", p));                     \
+    assert_support (type##_count++);                    \
+    TRACE_ACTIVE ();                                    \
+    return p;                                           \
+  }                                                     \
+
+CREATE_MPX (mpz)
+CREATE_MPX (mpq)
+
+typedef mpf_ptr  mpf;
+typedef mpf_ptr  mpf_assume;
+typedef mpf_ptr  mpf_coerce_st0;
+typedef mpf_ptr  mpf_coerce_def;
+
+
+static mpf
+new_mpf (unsigned long prec)
+{
+  mpf p;
+  New (GMP_MALLOC_ID, p, 1, __mpf_struct);
+  mpf_init2 (p, prec);
+  TRACE (printf ("  mpf p=%p\n", p));
+  assert_support (mpf_count++);
+  TRACE_ACTIVE ();
+  return p;
+}
+
+
+/* tmp_mpf_t records an allocated precision with an mpf_t so changes of
+   precision can be done with just an mpf_set_prec_raw.  */
+
+struct tmp_mpf_struct {
+  mpf_t          m;
+  unsigned long  allocated_prec;
+};
+typedef const struct tmp_mpf_struct  *tmp_mpf_srcptr;
+typedef struct tmp_mpf_struct        *tmp_mpf_ptr;
+typedef struct tmp_mpf_struct        tmp_mpf_t[1];
+
+#define tmp_mpf_init(f)                         \
+  do {                                          \
+    mpf_init (f->m);                            \
+    f->allocated_prec = mpf_get_prec (f->m);    \
+  } while (0)
+
+static void
+tmp_mpf_grow (tmp_mpf_ptr f, unsigned long prec)
+{
+  mpf_set_prec_raw (f->m, f->allocated_prec);
+  mpf_set_prec (f->m, prec);
+  f->allocated_prec = mpf_get_prec (f->m);
+}
+
+#define tmp_mpf_shrink(f)  tmp_mpf_grow (f, 1L)
+
+#define tmp_mpf_set_prec(f,prec)        \
+  do {                                  \
+    if (prec > f->allocated_prec)       \
+      tmp_mpf_grow (f, prec);           \
+    else                                \
+      mpf_set_prec_raw (f->m, prec);    \
+  } while (0)
+
+
+static mpz_t  tmp_mpz_0, tmp_mpz_1, tmp_mpz_2;
+static mpq_t  tmp_mpq_0, tmp_mpq_1;
+static tmp_mpf_t tmp_mpf_0, tmp_mpf_1;
+
+/* for GMP::Mpz::export */
+#define tmp_mpz_4  tmp_mpz_2
+
+
+#define FREE_MPX_FREELIST(p,type)               \
+  do {                                          \
+    TRACE (printf ("free %s\n", type##_class)); \
+    p->next = type##_freelist;                  \
+    type##_freelist = p;                        \
+    assert_support (type##_count--);            \
+    TRACE_ACTIVE ();                            \
+    assert (type##_count >= 0);                 \
+  } while (0)
+
+/* this version for comparison, if desired */
+#define FREE_MPX_NOFREELIST(p,type)             \
+  do {                                          \
+    TRACE (printf ("free %s\n", type##_class)); \
+    type##_clear (p->m);                        \
+    Safefree (p);                               \
+    assert_support (type##_count--);            \
+    TRACE_ACTIVE ();                            \
+    assert (type##_count >= 0);                 \
+  } while (0)
+
+#define free_mpz(z)    FREE_MPX_FREELIST (z, mpz)
+#define free_mpq(q)    FREE_MPX_FREELIST (q, mpq)
+
+
+/* Return a new mortal SV holding the given mpx_ptr pointer.
+   class_hv should be one of mpz_class_hv etc.  */
+#define MPX_NEWMORTAL(mpx_ptr, class_hv)                                \
+    sv_bless (sv_setref_pv (sv_newmortal(), NULL, mpx_ptr), class_hv)
+
+/* Aliases for use in typemaps */
+typedef char           *malloced_string;
+typedef const char     *const_string;
+typedef const char     *const_string_assume;
+typedef char           *string;
+typedef SV             *order_noswap;
+typedef SV             *dummy;
+typedef SV             *SV_copy_0;
+typedef unsigned long  ulong_coerce;
+typedef __gmp_randstate_struct *randstate;
+typedef UV             gmp_UV;
+
+#define SvMPX(s,type)  ((type) SvIV((SV*) SvRV(s)))
+#define SvMPZ(s)       SvMPX(s,mpz)
+#define SvMPQ(s)       SvMPX(s,mpq)
+#define SvMPF(s)       SvMPX(s,mpf)
+#define SvRANDSTATE(s) SvMPX(s,randstate)
+
+#define MPX_ASSUME(x,sv,type)                           \
+  do {                                                  \
+    assert (sv_derived_from (sv, type##_class));        \
+    x = SvMPX(sv,type);                                 \
+  } while (0)
+
+#define MPZ_ASSUME(z,sv)    MPX_ASSUME(z,sv,mpz)
+#define MPQ_ASSUME(q,sv)    MPX_ASSUME(q,sv,mpq)
+#define MPF_ASSUME(f,sv)    MPX_ASSUME(f,sv,mpf)
+
+#define numberof(x)  (sizeof (x) / sizeof ((x)[0]))
+#define SGN(x)       ((x)<0 ? -1 : (x) != 0)
+#define ABS(x)       ((x)>=0 ? (x) : -(x))
+#define double_integer_p(d)  (floor (d) == (d))
+
+#define x_mpq_integer_p(q) \
+  (mpz_cmp_ui (mpq_denref(q), 1L) == 0)
+
+#define assert_table(ix)  assert (ix >= 0 && ix < numberof (table))
+
+#define SV_PTR_SWAP(x,y) \
+  do { SV *__tmp = (x); (x) = (y); (y) = __tmp; } while (0)
+#define MPF_PTR_SWAP(x,y) \
+  do { mpf_ptr __tmp = (x); (x) = (y); (y) = __tmp; } while (0)
+
+
+static void
+class_or_croak (SV *sv, classconst char *cl)
+{
+  if (! sv_derived_from (sv, cl))
+    croak("not type %s", cl);
+}
+
+
+/* These are macros, wrap them in functions. */
+static int
+x_mpz_odd_p (mpz_srcptr z)
+{
+  return mpz_odd_p (z);
+}
+static int
+x_mpz_even_p (mpz_srcptr z)
+{
+  return mpz_even_p (z);
+}
+
+static void
+x_mpq_pow_ui (mpq_ptr r, mpq_srcptr b, unsigned long e)
+{
+  mpz_pow_ui (mpq_numref(r), mpq_numref(b), e);
+  mpz_pow_ui (mpq_denref(r), mpq_denref(b), e);
+}
+
+
+static void *
+my_gmp_alloc (size_t n)
+{
+  void *p;
+  TRACE (printf ("my_gmp_alloc %u\n", n));
+  New (GMP_MALLOC_ID, p, n, char);
+  TRACE (printf ("  p=%p\n", p));
+  return p;
+}
+
+static void *
+my_gmp_realloc (void *p, size_t oldsize, size_t newsize)
+{
+  TRACE (printf ("my_gmp_realloc %p, %u to %u\n", p, oldsize, newsize));
+  Renew (p, newsize, char);
+  TRACE (printf ("  p=%p\n", p));
+  return p;
+}
+
+static void
+my_gmp_free (void *p, size_t n)
+{
+  TRACE (printf ("my_gmp_free %p %u\n", p, n));
+  Safefree (p);
+}
+
+
+#define my_mpx_set_svstr(type)                                  \
+  static void                                                   \
+  my_##type##_set_svstr (type##_ptr x, SV *sv)                  \
+  {                                                             \
+    const char  *str;                                           \
+    STRLEN      len;                                            \
+    TRACE (printf ("  my_" #type "_set_svstr\n"));              \
+    assert (SvPOK(sv) || SvPOKp(sv));                           \
+    str = SvPV (sv, len);                                       \
+    TRACE (printf ("  str \"%s\"\n", str));                     \
+    if (type##_set_str (x, str, 0) != 0)                        \
+      croak ("%s: invalid string: %s", type##_class, str);      \
+  }
+
+my_mpx_set_svstr(mpz)
+my_mpx_set_svstr(mpq)
+my_mpx_set_svstr(mpf)
+
+
+/* very slack */
+static int
+x_mpq_cmp_si (mpq_srcptr x, long yn, unsigned long yd)
+{
+  mpq  y;
+  int  ret;
+  y = new_mpq ();
+  mpq_set_si (y->m, yn, yd);
+  ret = mpq_cmp (x, y->m);
+  free_mpq (y);
+  return ret;
+}
+
+static int
+x_mpq_fits_slong_p (mpq_srcptr q)
+{
+  return x_mpq_cmp_si (q, LONG_MIN, 1L) >= 0
+    && mpq_cmp_ui (q, LONG_MAX, 1L) <= 0;
+}
+
+static int
+x_mpz_cmp_q (mpz_ptr x, mpq_srcptr y)
+{
+  int  ret;
+  mpz_set_ui (mpq_denref(tmp_mpq_0), 1L);
+  mpz_swap (mpq_numref(tmp_mpq_0), x);
+  ret = mpq_cmp (tmp_mpq_0, y);
+  mpz_swap (mpq_numref(tmp_mpq_0), x);
+  return ret;
+}
+
+static int
+x_mpz_cmp_f (mpz_srcptr x, mpf_srcptr y)
+{
+  tmp_mpf_set_prec (tmp_mpf_0, mpz_sizeinbase (x, 2));
+  mpf_set_z (tmp_mpf_0->m, x);
+  return mpf_cmp (tmp_mpf_0->m, y);
+}
+
+
+#define USE_UNKNOWN  0
+#define USE_IVX      1
+#define USE_UVX      2
+#define USE_NVX      3
+#define USE_PVX      4
+#define USE_MPZ      5
+#define USE_MPQ      6
+#define USE_MPF      7
+
+/* mg_get is called every time we get a value, even if the private flags are
+   still set from a previous such call.  This is the same as as SvIV and
+   friends do.
+
+   When POK, we use the PV, even if there's an IV or NV available.  This is
+   because it's hard to be sure there wasn't any rounding in establishing
+   the IV and/or NV.  Cases of overflow, where the PV should definitely be
+   used, are easy enough to spot, but rounding is hard.  So although IV or
+   NV would be more efficient, we must use the PV to be sure of getting all
+   the data.  Applications should convert once to mpz, mpq or mpf when using
+   a value repeatedly.
+
+   Zany dual-type scalars like $! where the IV is an error code and the PV
+   is an error description string won't work with this preference for PV,
+   but that's too bad.  Such scalars should be rare, and unlikely to be used
+   in bignum calculations.
+
+   When IOK and NOK are both set, we would prefer to use the IV since it can
+   be converted more efficiently, and because on a 64-bit system the NV may
+   have less bits than the IV.  The following rules are applied,
+
+   - If the NV is not an integer, then we must use that NV, since clearly
+     the IV was merely established by rounding and is not the full value.
+
+   - In perl prior to 5.8, an NV too big for an IV leaves an overflow value
+     0xFFFFFFFF.  If the NV is too big to fit an IV then clearly it's the NV
+     which is the true value and must be used.
+
+   - In perl 5.8 and up, such an overflow doesn't set IOK, so that test is
+     unnecessary.  However when coming from get-magic, IOKp _is_ set, and we
+     must check for overflow the same as in older perl.
+
+   FIXME:
+
+   We'd like to call mg_get just once, but unfortunately sv_derived_from()
+   will call it for each of our checks.  We could do a string compare like
+   sv_isa ourselves, but that only tests the exact class, it doesn't
+   recognise subclassing.  There doesn't seem to be a public interface to
+   the subclassing tests (in the internal isa_lookup() function).  */
+
+int
+use_sv (SV *sv)
+{
+  double  d;
+
+  if (SvGMAGICAL(sv))
+    {
+      mg_get(sv);
+
+      if (SvPOKp(sv))
+        return USE_PVX;
+
+      if (SvIOKp(sv))
+        {
+          if (SvIsUV(sv))
+            {
+              if (SvNOKp(sv))
+                goto u_or_n;
+              return USE_UVX;
+            }
+          else
+            {
+              if (SvNOKp(sv))
+                goto i_or_n;
+              return USE_IVX;
+            }
+        }
+
+      if (SvNOKp(sv))
+        return USE_NVX;
+
+      goto rok_or_unknown;
+    }
+
+  if (SvPOK(sv))
+    return USE_PVX;
+
+  if (SvIOK(sv))
+    {
+      if (SvIsUV(sv))
+        {
+          if (SvNOK(sv))
+            {
+              if (PERL_LT (5, 8))
+                {
+                u_or_n:
+                  d = SvNVX(sv);
+                  if (d >= ULONG_MAX_P1_AS_DOUBLE || d < 0.0)
+                    return USE_NVX;
+                }
+              d = SvNVX(sv);
+              if (d != floor (d))
+                return USE_NVX;
+            }
+          return USE_UVX;
+        }
+      else
+        {
+          if (SvNOK(sv))
+            {
+              if (PERL_LT (5, 8))
+                {
+                i_or_n:
+                  d = SvNVX(sv);
+                  if (d >= LONG_MAX_P1_AS_DOUBLE || d < (double) LONG_MIN)
+                    return USE_NVX;
+                }
+              d = SvNVX(sv);
+              if (d != floor (d))
+                return USE_NVX;
+            }
+          return USE_IVX;
+        }
+    }
+
+  if (SvNOK(sv))
+    return USE_NVX;
+
+ rok_or_unknown:
+  if (SvROK(sv))
+    {
+      if (sv_derived_from (sv, mpz_class))
+        return USE_MPZ;
+      if (sv_derived_from (sv, mpq_class))
+        return USE_MPQ;
+      if (sv_derived_from (sv, mpf_class))
+        return USE_MPF;
+    }
+
+  return USE_UNKNOWN;
+}
+
+
+/* Coerce sv to an mpz.  Use tmp to hold the converted value if sv isn't
+   already an mpz (or an mpq of which the numerator can be used).  Return
+   the chosen mpz (tmp or the contents of sv).  */
+
+static mpz_ptr
+coerce_mpz_using (mpz_ptr tmp, SV *sv, int use)
+{
+  switch (use) {
+  case USE_IVX:
+    mpz_set_si (tmp, SvIVX(sv));
+    return tmp;
+
+  case USE_UVX:
+    mpz_set_ui (tmp, SvUVX(sv));
+    return tmp;
+
+  case USE_NVX:
+    {
+      double d;
+      d = SvNVX(sv);
+      if (! double_integer_p (d))
+        croak ("cannot coerce non-integer double to mpz");
+      mpz_set_d (tmp, d);
+      return tmp;
+    }
+
+  case USE_PVX:
+    my_mpz_set_svstr (tmp, sv);
+    return tmp;
+
+  case USE_MPZ:
+    return SvMPZ(sv)->m;
+
+  case USE_MPQ:
+    {
+      mpq q = SvMPQ(sv);
+      if (! x_mpq_integer_p (q->m))
+        croak ("cannot coerce non-integer mpq to mpz");
+      return mpq_numref(q->m);
+    }
+
+  case USE_MPF:
+    {
+      mpf f = SvMPF(sv);
+      if (! mpf_integer_p (f))
+        croak ("cannot coerce non-integer mpf to mpz");
+      mpz_set_f (tmp, f);
+      return tmp;
+    }
+
+  default:
+    croak ("cannot coerce to mpz");
+  }
+}
+static mpz_ptr
+coerce_mpz (mpz_ptr tmp, SV *sv)
+{
+  return coerce_mpz_using (tmp, sv, use_sv (sv));
+}
+
+
+/* Coerce sv to an mpq.  If sv is an mpq then just return that, otherwise
+   use tmp to hold the converted value and return that.  */
+
+static mpq_ptr
+coerce_mpq_using (mpq_ptr tmp, SV *sv, int use)
+{
+  TRACE (printf ("coerce_mpq_using %p %d\n", tmp, use));
+  switch (use) {
+  case USE_IVX:
+    mpq_set_si (tmp, SvIVX(sv), 1L);
+    return tmp;
+
+  case USE_UVX:
+    mpq_set_ui (tmp, SvUVX(sv), 1L);
+    return tmp;
+
+  case USE_NVX:
+    mpq_set_d (tmp, SvNVX(sv));
+    return tmp;
+
+  case USE_PVX:
+    my_mpq_set_svstr (tmp, sv);
+    return tmp;
+
+  case USE_MPZ:
+    mpq_set_z (tmp, SvMPZ(sv)->m);
+    return tmp;
+
+  case USE_MPQ:
+    return SvMPQ(sv)->m;
+
+  case USE_MPF:
+    mpq_set_f (tmp, SvMPF(sv));
+    return tmp;
+
+  default:
+    croak ("cannot coerce to mpq");
+  }
+}
+static mpq_ptr
+coerce_mpq (mpq_ptr tmp, SV *sv)
+{
+  return coerce_mpq_using (tmp, sv, use_sv (sv));
+}
+
+
+static void
+my_mpf_set_sv_using (mpf_ptr f, SV *sv, int use)
+{
+  switch (use) {
+  case USE_IVX:
+    mpf_set_si (f, SvIVX(sv));
+    break;
+
+  case USE_UVX:
+    mpf_set_ui (f, SvUVX(sv));
+    break;
+
+  case USE_NVX:
+    mpf_set_d (f, SvNVX(sv));
+    break;
+
+  case USE_PVX:
+    my_mpf_set_svstr (f, sv);
+    break;
+
+  case USE_MPZ:
+    mpf_set_z (f, SvMPZ(sv)->m);
+    break;
+
+  case USE_MPQ:
+    mpf_set_q (f, SvMPQ(sv)->m);
+    break;
+
+  case USE_MPF:
+    mpf_set (f, SvMPF(sv));
+    break;
+
+  default:
+    croak ("cannot coerce to mpf");
+  }
+}
+
+/* Coerce sv to an mpf.  If sv is an mpf then just return that, otherwise
+   use tmp to hold the converted value (with prec precision).  */
+static mpf_ptr
+coerce_mpf_using (tmp_mpf_ptr tmp, SV *sv, unsigned long prec, int use)
+{
+  if (use == USE_MPF)
+    return SvMPF(sv);
+
+  tmp_mpf_set_prec (tmp, prec);
+  my_mpf_set_sv_using (tmp->m, sv, use);
+  return tmp->m;
+}
+static mpf_ptr
+coerce_mpf (tmp_mpf_ptr tmp, SV *sv, unsigned long prec)
+{
+  return coerce_mpf_using (tmp, sv, prec, use_sv (sv));
+}
+
+
+/* Coerce xv to an mpf and store the pointer in x, ditto for yv to x.  If
+   one of xv or yv is an mpf then use it for the precision, otherwise use
+   the default precision.  */
+unsigned long
+coerce_mpf_pair (mpf *xp, SV *xv, mpf *yp, SV *yv)
+{
+  int x_use = use_sv (xv);
+  int y_use = use_sv (yv);
+  unsigned long  prec;
+  mpf  x, y;
+
+  if (x_use == USE_MPF)
+    {
+      x = SvMPF(xv);
+      prec = mpf_get_prec (x);
+      y = coerce_mpf_using (tmp_mpf_0, yv, prec, y_use);
+    }
+  else
+    {
+      y = coerce_mpf_using (tmp_mpf_0, yv, mpf_get_default_prec(), y_use);
+      prec = mpf_get_prec (y);
+      x = coerce_mpf_using (tmp_mpf_1, xv, prec, x_use);
+    }
+  *xp = x;
+  *yp = y;
+  return prec;
+}
+
+
+/* Note that SvUV is not used, since it merely treats the signed IV as if it
+   was unsigned.  We get an IV and check its sign. */
+static unsigned long
+coerce_ulong (SV *sv)
+{
+  long  n;
+
+  switch (use_sv (sv)) {
+  case USE_IVX:
+    n = SvIVX(sv);
+  negative_check:
+    if (n < 0)
+      goto range_error;
+    return n;
+
+  case USE_UVX:
+    return SvUVX(sv);
+
+  case USE_NVX:
+    {
+      double d;
+      d = SvNVX(sv);
+      if (! double_integer_p (d))
+        goto integer_error;
+      n = SvIV(sv);
+    }
+    goto negative_check;
+
+  case USE_PVX:
+    /* FIXME: Check the string is an integer. */
+    n = SvIV(sv);
+    goto negative_check;
+
+  case USE_MPZ:
+    {
+      mpz z = SvMPZ(sv);
+      if (! mpz_fits_ulong_p (z->m))
+        goto range_error;
+      return mpz_get_ui (z->m);
+    }
+
+  case USE_MPQ:
+    {
+      mpq q = SvMPQ(sv);
+      if (! x_mpq_integer_p (q->m))
+        goto integer_error;
+      if (! mpz_fits_ulong_p (mpq_numref (q->m)))
+        goto range_error;
+      return mpz_get_ui (mpq_numref (q->m));
+    }
+
+  case USE_MPF:
+    {
+      mpf f = SvMPF(sv);
+      if (! mpf_integer_p (f))
+        goto integer_error;
+      if (! mpf_fits_ulong_p (f))
+        goto range_error;
+      return mpf_get_ui (f);
+    }
+
+  default:
+    croak ("cannot coerce to ulong");
+  }
+
+ integer_error:
+  croak ("not an integer");
+
+ range_error:
+  croak ("out of range for ulong");
+}
+
+
+static long
+coerce_long (SV *sv)
+{
+  switch (use_sv (sv)) {
+  case USE_IVX:
+    return SvIVX(sv);
+
+  case USE_UVX:
+    {
+      UV u = SvUVX(sv);
+      if (u > (UV) LONG_MAX)
+        goto range_error;
+      return u;
+    }
+
+  case USE_NVX:
+    {
+      double d = SvNVX(sv);
+      if (! double_integer_p (d))
+        goto integer_error;
+      return SvIV(sv);
+    }
+
+  case USE_PVX:
+    /* FIXME: Check the string is an integer. */
+    return SvIV(sv);
+
+  case USE_MPZ:
+    {
+      mpz z = SvMPZ(sv);
+      if (! mpz_fits_slong_p (z->m))
+        goto range_error;
+      return mpz_get_si (z->m);
+    }
+
+  case USE_MPQ:
+    {
+      mpq q = SvMPQ(sv);
+      if (! x_mpq_integer_p (q->m))
+        goto integer_error;
+      if (! mpz_fits_slong_p (mpq_numref (q->m)))
+        goto range_error;
+      return mpz_get_si (mpq_numref (q->m));
+    }
+
+  case USE_MPF:
+    {
+      mpf f = SvMPF(sv);
+      if (! mpf_integer_p (f))
+        goto integer_error;
+      if (! mpf_fits_slong_p (f))
+        goto range_error;
+      return mpf_get_si (f);
+    }
+
+  default:
+    croak ("cannot coerce to long");
+  }
+
+ integer_error:
+  croak ("not an integer");
+
+ range_error:
+  croak ("out of range for ulong");
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+MODULE = GMP         PACKAGE = GMP
+
+BOOT:
+    TRACE (printf ("GMP boot\n"));
+    mp_set_memory_functions (my_gmp_alloc, my_gmp_realloc, my_gmp_free);
+    mpz_init (tmp_mpz_0);
+    mpz_init (tmp_mpz_1);
+    mpz_init (tmp_mpz_2);
+    mpq_init (tmp_mpq_0);
+    mpq_init (tmp_mpq_1);
+    tmp_mpf_init (tmp_mpf_0);
+    tmp_mpf_init (tmp_mpf_1);
+    mpz_class_hv = gv_stashpv (mpz_class, 1);
+    mpq_class_hv = gv_stashpv (mpq_class, 1);
+    mpf_class_hv = gv_stashpv (mpf_class, 1);
+
+
+void
+END()
+CODE:
+    TRACE (printf ("GMP end\n"));
+    TRACE_ACTIVE ();
+    /* These are not always true, see Bugs at the top of the file. */
+    /* assert (mpz_count == 0); */
+    /* assert (mpq_count == 0); */
+    /* assert (mpf_count == 0); */
+    /* assert (rand_count == 0); */
+
+
+const_string
+version()
+CODE:
+    RETVAL = gmp_version;
+OUTPUT:
+    RETVAL
+
+
+bool
+fits_slong_p (sv)
+    SV *sv
+CODE:
+    switch (use_sv (sv)) {
+    case USE_IVX:
+      RETVAL = 1;
+      break;
+
+    case USE_UVX:
+      {
+        UV u = SvUVX(sv);
+        RETVAL = (u <= LONG_MAX);
+      }
+      break;
+
+    case USE_NVX:
+      {
+        double  d = SvNVX(sv);
+        RETVAL = (d >= (double) LONG_MIN && d < LONG_MAX_P1_AS_DOUBLE);
+      }
+      break;
+
+    case USE_PVX:
+      {
+        STRLEN len;
+        const char *str = SvPV (sv, len);
+        if (mpq_set_str (tmp_mpq_0, str, 0) == 0)
+          RETVAL = x_mpq_fits_slong_p (tmp_mpq_0);
+        else
+          {
+            /* enough precision for a long */
+            tmp_mpf_set_prec (tmp_mpf_0, 2*mp_bits_per_limb);
+            if (mpf_set_str (tmp_mpf_0->m, str, 10) != 0)
+              croak ("GMP::fits_slong_p invalid string format");
+            RETVAL = mpf_fits_slong_p (tmp_mpf_0->m);
+          }
+      }
+      break;
+
+    case USE_MPZ:
+      RETVAL = mpz_fits_slong_p (SvMPZ(sv)->m);
+      break;
+
+    case USE_MPQ:
+      RETVAL = x_mpq_fits_slong_p (SvMPQ(sv)->m);
+      break;
+
+    case USE_MPF:
+      RETVAL = mpf_fits_slong_p (SvMPF(sv));
+      break;
+
+    default:
+      croak ("GMP::fits_slong_p invalid argument");
+    }
+OUTPUT:
+    RETVAL
+
+
+double
+get_d (sv)
+    SV *sv
+CODE:
+    switch (use_sv (sv)) {
+    case USE_IVX:
+      RETVAL = (double) SvIVX(sv);
+      break;
+
+    case USE_UVX:
+      RETVAL = (double) SvUVX(sv);
+      break;
+
+    case USE_NVX:
+      RETVAL = SvNVX(sv);
+      break;
+
+    case USE_PVX:
+      {
+        STRLEN len;
+        RETVAL = atof(SvPV(sv, len));
+      }
+      break;
+
+    case USE_MPZ:
+      RETVAL = mpz_get_d (SvMPZ(sv)->m);
+      break;
+
+    case USE_MPQ:
+      RETVAL = mpq_get_d (SvMPQ(sv)->m);
+      break;
+
+    case USE_MPF:
+      RETVAL = mpf_get_d (SvMPF(sv));
+      break;
+
+    default:
+      croak ("GMP::get_d invalid argument");
+    }
+OUTPUT:
+    RETVAL
+
+
+void
+get_d_2exp (sv)
+    SV *sv
+PREINIT:
+    double ret;
+    long   exp;
+PPCODE:
+    switch (use_sv (sv)) {
+    case USE_IVX:
+      ret = (double) SvIVX(sv);
+      goto use_frexp;
+
+    case USE_UVX:
+      ret = (double) SvUVX(sv);
+      goto use_frexp;
+
+    case USE_NVX:
+      {
+        int i_exp;
+        ret = SvNVX(sv);
+      use_frexp:
+        ret = frexp (ret, &i_exp);
+        exp = i_exp;
+      }
+      break;
+
+    case USE_PVX:
+      /* put strings through mpf to give full exp range */
+      tmp_mpf_set_prec (tmp_mpf_0, DBL_MANT_DIG);
+      my_mpf_set_svstr (tmp_mpf_0->m, sv);
+      ret = mpf_get_d_2exp (&exp, tmp_mpf_0->m);
+      break;
+
+    case USE_MPZ:
+      ret = mpz_get_d_2exp (&exp, SvMPZ(sv)->m);
+      break;
+
+    case USE_MPQ:
+      tmp_mpf_set_prec (tmp_mpf_0, DBL_MANT_DIG);
+      mpf_set_q (tmp_mpf_0->m, SvMPQ(sv)->m);
+      ret = mpf_get_d_2exp (&exp, tmp_mpf_0->m);
+      break;
+
+    case USE_MPF:
+      ret = mpf_get_d_2exp (&exp, SvMPF(sv));
+      break;
+
+    default:
+      croak ("GMP::get_d_2exp invalid argument");
+    }
+    PUSHs (sv_2mortal (newSVnv (ret)));
+    PUSHs (sv_2mortal (newSViv (exp)));
+
+
+long
+get_si (sv)
+    SV *sv
+CODE:
+    switch (use_sv (sv)) {
+    case USE_IVX:
+      RETVAL = SvIVX(sv);
+      break;
+
+    case USE_UVX:
+      RETVAL = SvUVX(sv);
+      break;
+
+    case USE_NVX:
+      RETVAL = (long) SvNVX(sv);
+      break;
+
+    case USE_PVX:
+      RETVAL = SvIV(sv);
+      break;
+
+    case USE_MPZ:
+      RETVAL = mpz_get_si (SvMPZ(sv)->m);
+      break;
+
+    case USE_MPQ:
+      mpz_set_q (tmp_mpz_0, SvMPQ(sv)->m);
+      RETVAL = mpz_get_si (tmp_mpz_0);
+      break;
+
+    case USE_MPF:
+      RETVAL = mpf_get_si (SvMPF(sv));
+      break;
+
+    default:
+      croak ("GMP::get_si invalid argument");
+    }
+OUTPUT:
+    RETVAL
+
+
+void
+get_str (sv, ...)
+    SV *sv
+PREINIT:
+    char      *str;
+    mp_exp_t  exp;
+    mpz_ptr   z;
+    mpq_ptr   q;
+    mpf       f;
+    int       base;
+    int       ndigits;
+PPCODE:
+    TRACE (printf ("GMP::get_str\n"));
+
+    if (items >= 2)
+      base = coerce_long (ST(1));
+    else
+      base = 10;
+    TRACE (printf (" base=%d\n", base));
+
+    if (items >= 3)
+      ndigits = coerce_long (ST(2));
+    else
+      ndigits = 10;
+    TRACE (printf (" ndigits=%d\n", ndigits));
+
+    EXTEND (SP, 2);
+
+    switch (use_sv (sv)) {
+    case USE_IVX:
+      mpz_set_si (tmp_mpz_0, SvIVX(sv));
+    get_tmp_mpz_0:
+      z = tmp_mpz_0;
+      goto get_mpz;
+
+    case USE_UVX:
+      mpz_set_ui (tmp_mpz_0, SvUVX(sv));
+      goto get_tmp_mpz_0;
+
+    case USE_NVX:
+      /* only digits in the original double, not in the coerced form */
+      if (ndigits == 0)
+        ndigits = DBL_DIG;
+      mpf_set_d (tmp_mpf_0->m, SvNVX(sv));
+      f = tmp_mpf_0->m;
+      goto get_mpf;
+
+    case USE_PVX:
+      {
+        /* get_str on a string is not much more than a base conversion */
+        STRLEN len;
+        str = SvPV (sv, len);
+        if (mpz_set_str (tmp_mpz_0, str, 0) == 0)
+          {
+            z = tmp_mpz_0;
+            goto get_mpz;
+          }
+        else if (mpq_set_str (tmp_mpq_0, str, 0) == 0)
+          {
+            q = tmp_mpq_0;
+            goto get_mpq;
+          }
+        else
+          {
+            /* FIXME: Would like perhaps a precision equivalent to the
+               number of significant digits of the string, in its given
+               base.  */
+            tmp_mpf_set_prec (tmp_mpf_0, strlen(str));
+            if (mpf_set_str (tmp_mpf_0->m, str, 10) == 0)
+              {
+                f = tmp_mpf_0->m;
+                goto get_mpf;
+              }
+            else
+              croak ("GMP::get_str invalid string format");
+          }
+      }
+      break;
+
+    case USE_MPZ:
+      z = SvMPZ(sv)->m;
+    get_mpz:
+      str = mpz_get_str (NULL, base, z);
+    push_str:
+      PUSHs (sv_2mortal (newSVpv (str, 0)));
+      break;
+
+    case USE_MPQ:
+      q = SvMPQ(sv)->m;
+    get_mpq:
+      str = mpq_get_str (NULL, base, q);
+      goto push_str;
+
+    case USE_MPF:
+      f = SvMPF(sv);
+    get_mpf:
+      str = mpf_get_str (NULL, &exp, base, 0, f);
+      PUSHs (sv_2mortal (newSVpv (str, 0)));
+      PUSHs (sv_2mortal (newSViv (exp)));
+      break;
+
+    default:
+      croak ("GMP::get_str invalid argument");
+    }
+
+
+bool
+integer_p (sv)
+    SV *sv
+CODE:
+    switch (use_sv (sv)) {
+    case USE_IVX:
+    case USE_UVX:
+      RETVAL = 1;
+      break;
+
+    case USE_NVX:
+      RETVAL = double_integer_p (SvNVX(sv));
+      break;
+
+    case USE_PVX:
+      {
+        /* FIXME: Maybe this should be done by parsing the string, not by an
+           actual conversion.  */
+        STRLEN len;
+        const char *str = SvPV (sv, len);
+        if (mpq_set_str (tmp_mpq_0, str, 0) == 0)
+          RETVAL = x_mpq_integer_p (tmp_mpq_0);
+        else
+          {
+            /* enough for all digits of the string */
+            tmp_mpf_set_prec (tmp_mpf_0, strlen(str)+64);
+            if (mpf_set_str (tmp_mpf_0->m, str, 10) == 0)
+              RETVAL = mpf_integer_p (tmp_mpf_0->m);
+            else
+              croak ("GMP::integer_p invalid string format");
+          }
+      }
+      break;
+
+    case USE_MPZ:
+      RETVAL = 1;
+      break;
+
+    case USE_MPQ:
+      RETVAL = x_mpq_integer_p (SvMPQ(sv)->m);
+      break;
+
+    case USE_MPF:
+      RETVAL = mpf_integer_p (SvMPF(sv));
+      break;
+
+    default:
+      croak ("GMP::integer_p invalid argument");
+    }
+OUTPUT:
+    RETVAL
+
+
+int
+sgn (sv)
+    SV *sv
+CODE:
+    switch (use_sv (sv)) {
+    case USE_IVX:
+      RETVAL = SGN (SvIVX(sv));
+      break;
+
+    case USE_UVX:
+      RETVAL = (SvUVX(sv) > 0);
+      break;
+
+    case USE_NVX:
+      RETVAL = SGN (SvNVX(sv));
+      break;
+
+    case USE_PVX:
+      {
+        /* FIXME: Maybe this should be done by parsing the string, not by an
+           actual conversion.  */
+        STRLEN len;
+        const char *str = SvPV (sv, len);
+        if (mpq_set_str (tmp_mpq_0, str, 0) == 0)
+          RETVAL = mpq_sgn (tmp_mpq_0);
+        else
+          {
+            /* enough for all digits of the string */
+            tmp_mpf_set_prec (tmp_mpf_0, strlen(str)+64);
+            if (mpf_set_str (tmp_mpf_0->m, str, 10) == 0)
+              RETVAL = mpf_sgn (tmp_mpf_0->m);
+            else
+              croak ("GMP::sgn invalid string format");
+          }
+      }
+      break;
+
+    case USE_MPZ:
+      RETVAL = mpz_sgn (SvMPZ(sv)->m);
+      break;
+
+    case USE_MPQ:
+      RETVAL = mpq_sgn (SvMPQ(sv)->m);
+      break;
+
+    case USE_MPF:
+      RETVAL = mpf_sgn (SvMPF(sv));
+      break;
+
+    default:
+      croak ("GMP::sgn invalid argument");
+    }
+OUTPUT:
+    RETVAL
+
+
+# currently undocumented
+void
+shrink ()
+CODE:
+#define x_mpz_shrink(z) \
+    mpz_set_ui (z, 0L); _mpz_realloc (z, 1)
+#define x_mpq_shrink(q) \
+    x_mpz_shrink (mpq_numref(q)); x_mpz_shrink (mpq_denref(q))
+
+    x_mpz_shrink (tmp_mpz_0);
+    x_mpz_shrink (tmp_mpz_1);
+    x_mpz_shrink (tmp_mpz_2);
+    x_mpq_shrink (tmp_mpq_0);
+    x_mpq_shrink (tmp_mpq_1);
+    tmp_mpf_shrink (tmp_mpf_0);
+    tmp_mpf_shrink (tmp_mpf_1);
+
+
+
+malloced_string
+sprintf_internal (fmt, sv)
+    const_string fmt
+    SV           *sv
+CODE:
+    assert (strlen (fmt) >= 3);
+    assert (SvROK(sv));
+    assert ((sv_derived_from (sv, mpz_class)    && fmt[strlen(fmt)-2] == 'Z')
+            || (sv_derived_from (sv, mpq_class) && fmt[strlen(fmt)-2] == 'Q')
+            || (sv_derived_from (sv, mpf_class) && fmt[strlen(fmt)-2] == 'F'));
+    TRACE (printf ("GMP::sprintf_internal\n");
+           printf ("  fmt  |%s|\n", fmt);
+           printf ("  sv   |%p|\n", SvMPZ(sv)));
+
+    /* cheat a bit here, SvMPZ works for mpq and mpf too */
+    gmp_asprintf (&RETVAL, fmt, SvMPZ(sv));
+
+    TRACE (printf ("  result |%s|\n", RETVAL));
+OUTPUT:
+    RETVAL
+
+
+
+#------------------------------------------------------------------------------
+
+MODULE = GMP         PACKAGE = GMP::Mpz
+
+mpz
+mpz (...)
+ALIAS:
+    GMP::Mpz::new = 1
+PREINIT:
+    SV *sv;
+CODE:
+    TRACE (printf ("%s new, ix=%ld, items=%d\n", mpz_class, ix, (int) items));
+    RETVAL = new_mpz();
+
+    switch (items) {
+    case 0:
+      mpz_set_ui (RETVAL->m, 0L);
+      break;
+
+    case 1:
+      sv = ST(0);
+      TRACE (printf ("  use %d\n", use_sv (sv)));
+      switch (use_sv (sv)) {
+      case USE_IVX:
+        mpz_set_si (RETVAL->m, SvIVX(sv));
+        break;
+
+      case USE_UVX:
+        mpz_set_ui (RETVAL->m, SvUVX(sv));
+        break;
+
+      case USE_NVX:
+        mpz_set_d (RETVAL->m, SvNVX(sv));
+        break;
+
+      case USE_PVX:
+        my_mpz_set_svstr (RETVAL->m, sv);
+        break;
+
+      case USE_MPZ:
+        mpz_set (RETVAL->m, SvMPZ(sv)->m);
+        break;
+
+      case USE_MPQ:
+        mpz_set_q (RETVAL->m, SvMPQ(sv)->m);
+        break;
+
+      case USE_MPF:
+        mpz_set_f (RETVAL->m, SvMPF(sv));
+        break;
+
+      default:
+        goto invalid;
+      }
+      break;
+
+    default:
+    invalid:
+      croak ("%s new: invalid arguments", mpz_class);
+    }
+OUTPUT:
+    RETVAL
+
+
+void
+overload_constant (str, pv, d1, ...)
+    const_string_assume str
+    SV                  *pv
+    dummy               d1
+PREINIT:
+    mpz z;
+PPCODE:
+    TRACE (printf ("%s constant: %s\n", mpz_class, str));
+    z = new_mpz();
+    if (mpz_set_str (z->m, str, 0) == 0)
+      {
+        PUSHs (MPX_NEWMORTAL (z, mpz_class_hv));
+      }
+    else
+      {
+        free_mpz (z);
+        PUSHs(pv);
+      }
+
+
+mpz
+overload_copy (z, d1, d2)
+    mpz_assume z
+    dummy      d1
+    dummy      d2
+CODE:
+    RETVAL = new_mpz();
+    mpz_set (RETVAL->m, z->m);
+OUTPUT:
+    RETVAL
+
+
+void
+DESTROY (z)
+    mpz_assume z
+CODE:
+    TRACE (printf ("%s DESTROY %p\n", mpz_class, z));
+    free_mpz (z);
+
+
+malloced_string
+overload_string (z, d1, d2)
+    mpz_assume z
+    dummy      d1
+    dummy      d2
+CODE:
+    TRACE (printf ("%s overload_string %p\n", mpz_class, z));
+    RETVAL = mpz_get_str (NULL, 10, z->m);
+OUTPUT:
+    RETVAL
+
+
+mpz
+overload_add (xv, yv, order)
+    SV *xv
+    SV *yv
+    SV *order
+ALIAS:
+    GMP::Mpz::overload_sub = 1
+    GMP::Mpz::overload_mul = 2
+    GMP::Mpz::overload_div = 3
+    GMP::Mpz::overload_rem = 4
+    GMP::Mpz::overload_and = 5
+    GMP::Mpz::overload_ior = 6
+    GMP::Mpz::overload_xor = 7
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpz_ptr, mpz_srcptr, mpz_srcptr);
+    } table[] = {
+      { mpz_add    }, /* 0 */
+      { mpz_sub    }, /* 1 */
+      { mpz_mul    }, /* 2 */
+      { mpz_tdiv_q }, /* 3 */
+      { mpz_tdiv_r }, /* 4 */
+      { mpz_and    }, /* 5 */
+      { mpz_ior    }, /* 6 */
+      { mpz_xor    }, /* 7 */
+    };
+CODE:
+    assert_table (ix);
+    if (order == &PL_sv_yes)
+      SV_PTR_SWAP (xv, yv);
+    RETVAL = new_mpz();
+    (*table[ix].op) (RETVAL->m,
+                     coerce_mpz (tmp_mpz_0, xv),
+                     coerce_mpz (tmp_mpz_1, yv));
+OUTPUT:
+    RETVAL
+
+
+void
+overload_addeq (x, y, o)
+    mpz_assume   x
+    mpz_coerce   y
+    order_noswap o
+ALIAS:
+    GMP::Mpz::overload_subeq = 1
+    GMP::Mpz::overload_muleq = 2
+    GMP::Mpz::overload_diveq = 3
+    GMP::Mpz::overload_remeq = 4
+    GMP::Mpz::overload_andeq = 5
+    GMP::Mpz::overload_ioreq = 6
+    GMP::Mpz::overload_xoreq = 7
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpz_ptr, mpz_srcptr, mpz_srcptr);
+    } table[] = {
+      { mpz_add    }, /* 0 */
+      { mpz_sub    }, /* 1 */
+      { mpz_mul    }, /* 2 */
+      { mpz_tdiv_q }, /* 3 */
+      { mpz_tdiv_r }, /* 4 */
+      { mpz_and    }, /* 5 */
+      { mpz_ior    }, /* 6 */
+      { mpz_xor    }, /* 7 */
+    };
+PPCODE:
+    assert_table (ix);
+    (*table[ix].op) (x->m, x->m, y);
+    XPUSHs (ST(0));
+
+
+mpz
+overload_lshift (zv, nv, order)
+    SV *zv
+    SV *nv
+    SV *order
+ALIAS:
+    GMP::Mpz::overload_rshift   = 1
+    GMP::Mpz::overload_pow      = 2
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpz_ptr, mpz_srcptr, unsigned long);
+    } table[] = {
+      { mpz_mul_2exp }, /* 0 */
+      { mpz_fdiv_q_2exp }, /* 1 */
+      { mpz_pow_ui   }, /* 2 */
+    };
+CODE:
+    assert_table (ix);
+    if (order == &PL_sv_yes)
+      SV_PTR_SWAP (zv, nv);
+    RETVAL = new_mpz();
+    (*table[ix].op) (RETVAL->m, coerce_mpz (RETVAL->m, zv), coerce_ulong (nv));
+OUTPUT:
+    RETVAL
+
+
+void
+overload_lshifteq (z, n, o)
+    mpz_assume   z
+    ulong_coerce n
+    order_noswap o
+ALIAS:
+    GMP::Mpz::overload_rshifteq   = 1
+    GMP::Mpz::overload_poweq      = 2
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpz_ptr, mpz_srcptr, unsigned long);
+    } table[] = {
+      { mpz_mul_2exp }, /* 0 */
+      { mpz_fdiv_q_2exp }, /* 1 */
+      { mpz_pow_ui   }, /* 2 */
+    };
+PPCODE:
+    assert_table (ix);
+    (*table[ix].op) (z->m, z->m, n);
+    XPUSHs(ST(0));
+
+
+mpz
+overload_abs (z, d1, d2)
+    mpz_assume z
+    dummy      d1
+    dummy      d2
+ALIAS:
+    GMP::Mpz::overload_neg  = 1
+    GMP::Mpz::overload_com  = 2
+    GMP::Mpz::overload_sqrt = 3
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpz_ptr w, mpz_srcptr x);
+    } table[] = {
+      { mpz_abs  }, /* 0 */
+      { mpz_neg  }, /* 1 */
+      { mpz_com  }, /* 2 */
+      { mpz_sqrt }, /* 3 */
+    };
+CODE:
+    assert_table (ix);
+    RETVAL = new_mpz();
+    (*table[ix].op) (RETVAL->m, z->m);
+OUTPUT:
+    RETVAL
+
+
+void
+overload_inc (z, d1, d2)
+    mpz_assume z
+    dummy      d1
+    dummy      d2
+ALIAS:
+    GMP::Mpz::overload_dec = 1
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpz_ptr w, mpz_srcptr x, unsigned long y);
+    } table[] = {
+      { mpz_add_ui }, /* 0 */
+      { mpz_sub_ui }, /* 1 */
+    };
+CODE:
+    assert_table (ix);
+    (*table[ix].op) (z->m, z->m, 1L);
+
+
+int
+overload_spaceship (xv, yv, order)
+    SV *xv
+    SV *yv
+    SV *order
+PREINIT:
+    mpz x;
+CODE:
+    TRACE (printf ("%s overload_spaceship\n", mpz_class));
+    MPZ_ASSUME (x, xv);
+    switch (use_sv (yv)) {
+    case USE_IVX:
+      RETVAL = mpz_cmp_si (x->m, SvIVX(yv));
+      break;
+    case USE_UVX:
+      RETVAL = mpz_cmp_ui (x->m, SvUVX(yv));
+      break;
+    case USE_PVX:
+      RETVAL = mpz_cmp (x->m, coerce_mpz (tmp_mpz_0, yv));
+      break;
+    case USE_NVX:
+      RETVAL = mpz_cmp_d (x->m, SvNVX(yv));
+      break;
+    case USE_MPZ:
+      RETVAL = mpz_cmp (x->m, SvMPZ(yv)->m);
+      break;
+    case USE_MPQ:
+      RETVAL = x_mpz_cmp_q (x->m, SvMPQ(yv)->m);
+      break;
+    case USE_MPF:
+      RETVAL = x_mpz_cmp_f (x->m, SvMPF(yv));
+      break;
+    default:
+      croak ("%s <=>: invalid operand", mpz_class);
+    }
+    RETVAL = SGN (RETVAL);
+    if (order == &PL_sv_yes)
+      RETVAL = -RETVAL;
+OUTPUT:
+    RETVAL
+
+
+bool
+overload_bool (z, d1, d2)
+    mpz_assume z
+    dummy      d1
+    dummy      d2
+ALIAS:
+    GMP::Mpz::overload_not = 1
+CODE:
+    RETVAL = (mpz_sgn (z->m) != 0) ^ ix;
+OUTPUT:
+    RETVAL
+
+
+mpz
+bin (n, k)
+    mpz_coerce   n
+    ulong_coerce k
+ALIAS:
+    GMP::Mpz::root = 1
+PREINIT:
+    /* mpz_root returns an int, hence the cast */
+    static_functable const struct {
+      void (*op) (mpz_ptr, mpz_srcptr, unsigned long);
+    } table[] = {
+      {                                                mpz_bin_ui }, /* 0 */
+      { (void (*)(mpz_ptr, mpz_srcptr, unsigned long)) mpz_root   }, /* 1 */
+    };
+CODE:
+    assert_table (ix);
+    RETVAL = new_mpz();
+    (*table[ix].op) (RETVAL->m, n, k);
+OUTPUT:
+    RETVAL
+
+
+void
+cdiv (a, d)
+    mpz_coerce a
+    mpz_coerce d
+ALIAS:
+    GMP::Mpz::fdiv = 1
+    GMP::Mpz::tdiv = 2
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr);
+    } table[] = {
+      { mpz_cdiv_qr }, /* 0 */
+      { mpz_fdiv_qr }, /* 1 */
+      { mpz_tdiv_qr }, /* 2 */
+    };
+    mpz q, r;
+PPCODE:
+    assert_table (ix);
+    q = new_mpz();
+    r = new_mpz();
+    (*table[ix].op) (q->m, r->m, a, d);
+    EXTEND (SP, 2);
+    PUSHs (MPX_NEWMORTAL (q, mpz_class_hv));
+    PUSHs (MPX_NEWMORTAL (r, mpz_class_hv));
+
+
+void
+cdiv_2exp (a, d)
+    mpz_coerce   a
+    ulong_coerce d
+ALIAS:
+    GMP::Mpz::fdiv_2exp = 1
+    GMP::Mpz::tdiv_2exp = 2
+PREINIT:
+    static_functable const struct {
+      void (*q) (mpz_ptr, mpz_srcptr, unsigned long);
+      void (*r) (mpz_ptr, mpz_srcptr, unsigned long);
+    } table[] = {
+      { mpz_cdiv_q_2exp, mpz_cdiv_r_2exp }, /* 0 */
+      { mpz_fdiv_q_2exp, mpz_fdiv_r_2exp }, /* 1 */
+      { mpz_tdiv_q_2exp, mpz_tdiv_r_2exp }, /* 2 */
+    };
+    mpz q, r;
+PPCODE:
+    assert_table (ix);
+    q = new_mpz();
+    r = new_mpz();
+    (*table[ix].q) (q->m, a, d);
+    (*table[ix].r) (r->m, a, d);
+    EXTEND (SP, 2);
+    PUSHs (MPX_NEWMORTAL (q, mpz_class_hv));
+    PUSHs (MPX_NEWMORTAL (r, mpz_class_hv));
+
+
+bool
+congruent_p (a, c, d)
+    mpz_coerce a
+    mpz_coerce c
+    mpz_coerce d
+PREINIT:
+CODE:
+    RETVAL = mpz_congruent_p (a, c, d);
+OUTPUT:
+    RETVAL
+
+
+bool
+congruent_2exp_p (a, c, d)
+    mpz_coerce   a
+    mpz_coerce   c
+    ulong_coerce d
+PREINIT:
+CODE:
+    RETVAL = mpz_congruent_2exp_p (a, c, d);
+OUTPUT:
+    RETVAL
+
+
+mpz
+divexact (a, d)
+    mpz_coerce a
+    mpz_coerce d
+ALIAS:
+    GMP::Mpz::mod = 1
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpz_ptr, mpz_srcptr, mpz_srcptr);
+    } table[] = {
+      { mpz_divexact }, /* 0 */
+      { mpz_mod      }, /* 1 */
+    };
+CODE:
+    assert_table (ix);
+    RETVAL = new_mpz();
+    (*table[ix].op) (RETVAL->m, a, d);
+OUTPUT:
+    RETVAL
+
+
+bool
+divisible_p (a, d)
+    mpz_coerce a
+    mpz_coerce d
+CODE:
+    RETVAL = mpz_divisible_p (a, d);
+OUTPUT:
+    RETVAL
+
+
+bool
+divisible_2exp_p (a, d)
+    mpz_coerce   a
+    ulong_coerce d
+CODE:
+    RETVAL = mpz_divisible_2exp_p (a, d);
+OUTPUT:
+    RETVAL
+
+
+bool
+even_p (z)
+    mpz_coerce z
+ALIAS:
+    GMP::Mpz::odd_p            = 1
+    GMP::Mpz::perfect_square_p = 2
+    GMP::Mpz::perfect_power_p  = 3
+PREINIT:
+    static_functable const struct {
+      int (*op) (mpz_srcptr z);
+    } table[] = {
+      { x_mpz_even_p         }, /* 0 */
+      { x_mpz_odd_p          }, /* 1 */
+      { mpz_perfect_square_p }, /* 2 */
+      { mpz_perfect_power_p  }, /* 3 */
+    };
+CODE:
+    assert_table (ix);
+    RETVAL = (*table[ix].op) (z);
+OUTPUT:
+    RETVAL
+
+
+mpz
+fac (n)
+    ulong_coerce n
+ALIAS:
+    GMP::Mpz::fib    = 1
+    GMP::Mpz::lucnum = 2
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpz_ptr r, unsigned long n);
+    } table[] = {
+      { mpz_fac_ui },    /* 0 */
+      { mpz_fib_ui },    /* 1 */
+      { mpz_lucnum_ui }, /* 2 */
+    };
+CODE:
+    assert_table (ix);
+    RETVAL = new_mpz();
+    (*table[ix].op) (RETVAL->m, n);
+OUTPUT:
+    RETVAL
+
+
+void
+fib2 (n)
+    ulong_coerce n
+ALIAS:
+    GMP::Mpz::lucnum2 = 1
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpz_ptr r, mpz_ptr r2, unsigned long n);
+    } table[] = {
+      { mpz_fib2_ui },    /* 0 */
+      { mpz_lucnum2_ui }, /* 1 */
+    };
+    mpz  r, r2;
+PPCODE:
+    assert_table (ix);
+    r = new_mpz();
+    r2 = new_mpz();
+    (*table[ix].op) (r->m, r2->m, n);
+    EXTEND (SP, 2);
+    PUSHs (MPX_NEWMORTAL (r,  mpz_class_hv));
+    PUSHs (MPX_NEWMORTAL (r2, mpz_class_hv));
+
+
+mpz
+gcd (x, ...)
+    mpz_coerce x
+ALIAS:
+    GMP::Mpz::lcm = 1
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpz_ptr w, mpz_srcptr x, mpz_srcptr y);
+      void (*op_ui) (mpz_ptr w, mpz_srcptr x, unsigned long y);
+    } table[] = {
+      /* cast to ignore ulong return from mpz_gcd_ui */
+      { mpz_gcd,
+        (void (*) (mpz_ptr, mpz_srcptr, unsigned long)) mpz_gcd_ui }, /* 0 */
+      { mpz_lcm, mpz_lcm_ui },                                        /* 1 */
+    };
+    int  i;
+    SV   *yv;
+CODE:
+    assert_table (ix);
+    RETVAL = new_mpz();
+    if (items == 1)
+      mpz_set (RETVAL->m, x);
+    else
+      {
+        for (i = 1; i < items; i++)
+          {
+            yv = ST(i);
+            if (SvIOK(yv))
+              (*table[ix].op_ui) (RETVAL->m, x, ABS(SvIVX(yv)));
+            else
+              (*table[ix].op) (RETVAL->m, x, coerce_mpz (tmp_mpz_1, yv));
+            x = RETVAL->m;
+          }
+      }
+OUTPUT:
+    RETVAL
+
+
+void
+gcdext (a, b)
+    mpz_coerce a
+    mpz_coerce b
+PREINIT:
+    mpz g, x, y;
+    SV  *sv;
+PPCODE:
+    g = new_mpz();
+    x = new_mpz();
+    y = new_mpz();
+    mpz_gcdext (g->m, x->m, y->m, a, b);
+    EXTEND (SP, 3);
+    PUSHs (MPX_NEWMORTAL (g, mpz_class_hv));
+    PUSHs (MPX_NEWMORTAL (x, mpz_class_hv));
+    PUSHs (MPX_NEWMORTAL (y, mpz_class_hv));
+
+
+unsigned long
+hamdist (x, y)
+    mpz_coerce x
+    mpz_coerce y
+CODE:
+    RETVAL = mpz_hamdist (x, y);
+OUTPUT:
+    RETVAL
+
+
+mpz
+invert (a, m)
+    mpz_coerce a
+    mpz_coerce m
+CODE:
+    RETVAL = new_mpz();
+    if (! mpz_invert (RETVAL->m, a, m))
+      {
+        free_mpz (RETVAL);
+        XSRETURN_UNDEF;
+      }
+OUTPUT:
+    RETVAL
+
+
+int
+jacobi (a, b)
+    mpz_coerce a
+    mpz_coerce b
+CODE:
+    RETVAL = mpz_jacobi (a, b);
+OUTPUT:
+    RETVAL
+
+
+int
+kronecker (a, b)
+    SV *a
+    SV *b
+CODE:
+    if (SvIOK(b))
+      RETVAL = mpz_kronecker_si (coerce_mpz(tmp_mpz_0,a), SvIVX(b));
+    else if (SvIOK(a))
+      RETVAL = mpz_si_kronecker (SvIVX(a), coerce_mpz(tmp_mpz_0,b));
+    else
+      RETVAL = mpz_kronecker (coerce_mpz(tmp_mpz_0,a),
+                              coerce_mpz(tmp_mpz_1,b));
+OUTPUT:
+    RETVAL
+
+
+void
+mpz_export (order, size, endian, nails, z)
+    int        order
+    size_t     size
+    int        endian
+    size_t     nails
+    mpz_coerce z
+PREINIT:
+    size_t  numb, count, bytes, actual_count;
+    char    *data;
+    SV      *sv;
+PPCODE:
+    numb = 8*size - nails;
+    count = (mpz_sizeinbase (z, 2) + numb-1) / numb;
+    bytes = count * size;
+    New (GMP_MALLOC_ID, data, bytes+1, char);
+    mpz_export (data, &actual_count, order, size, endian, nails, z);
+    assert (count == actual_count);
+    data[bytes] = '\0';
+    sv = sv_newmortal(); sv_usepvn_mg (sv, data, bytes); PUSHs(sv);
+
+
+mpz
+mpz_import (order, size, endian, nails, sv)
+    int     order
+    size_t  size
+    int     endian
+    size_t  nails
+    SV      *sv
+PREINIT:
+    size_t      count;
+    const char  *data;
+    STRLEN      len;
+CODE:
+    data = SvPV (sv, len);
+    if ((len % size) != 0)
+      croak ("%s mpz_import: string not a multiple of the given size",
+             mpz_class);
+    count = len / size;
+    RETVAL = new_mpz();
+    mpz_import (RETVAL->m, count, order, size, endian, nails, data);
+OUTPUT:
+    RETVAL
+
+
+mpz
+nextprime (z)
+    mpz_coerce z
+CODE:
+    RETVAL = new_mpz();
+    mpz_nextprime (RETVAL->m, z);
+OUTPUT:
+    RETVAL
+
+
+unsigned long
+popcount (x)
+    mpz_coerce x
+CODE:
+    RETVAL = mpz_popcount (x);
+OUTPUT:
+    RETVAL
+
+
+mpz
+powm (b, e, m)
+    mpz_coerce b
+    mpz_coerce e
+    mpz_coerce m
+CODE:
+    RETVAL = new_mpz();
+    mpz_powm (RETVAL->m, b, e, m);
+OUTPUT:
+    RETVAL
+
+
+bool
+probab_prime_p (z, n)
+    mpz_coerce   z
+    ulong_coerce n
+CODE:
+    RETVAL = mpz_probab_prime_p (z, n);
+OUTPUT:
+    RETVAL
+
+
+# No attempt to coerce here, only an mpz makes sense.
+void
+realloc (z, limbs)
+    mpz z
+    int limbs
+CODE:
+    _mpz_realloc (z->m, limbs);
+
+
+void
+remove (z, f)
+    mpz_coerce z
+    mpz_coerce f
+PREINIT:
+    SV             *sv;
+    mpz            rem;
+    unsigned long  mult;
+PPCODE:
+    rem = new_mpz();
+    mult = mpz_remove (rem->m, z, f);
+    EXTEND (SP, 2);
+    PUSHs (MPX_NEWMORTAL (rem, mpz_class_hv));
+    PUSHs (sv_2mortal (newSViv (mult)));
+
+
+void
+roote (z, n)
+    mpz_coerce   z
+    ulong_coerce n
+PREINIT:
+    SV  *sv;
+    mpz root;
+    int exact;
+PPCODE:
+    root = new_mpz();
+    exact = mpz_root (root->m, z, n);
+    EXTEND (SP, 2);
+    PUSHs (MPX_NEWMORTAL (root, mpz_class_hv));
+    sv = (exact ? &PL_sv_yes : &PL_sv_no); sv_2mortal(sv); PUSHs(sv);
+
+
+void
+rootrem (z, n)
+    mpz_coerce   z
+    ulong_coerce n
+PREINIT:
+    SV  *sv;
+    mpz root;
+    mpz rem;
+PPCODE:
+    root = new_mpz();
+    rem = new_mpz();
+    mpz_rootrem (root->m, rem->m, z, n);
+    EXTEND (SP, 2);
+    PUSHs (MPX_NEWMORTAL (root, mpz_class_hv));
+    PUSHs (MPX_NEWMORTAL (rem,  mpz_class_hv));
+
+
+# In the past scan0 and scan1 were described as returning ULONG_MAX which
+# could be obtained in perl with ~0.  That wasn't true on 64-bit systems
+# (eg. alpha) with perl 5.005, since in that version IV and UV were still
+# 32-bits.
+#
+# We changed in gmp 4.2 to just say ~0 for the not-found return.  It's
+# likely most people have used ~0 rather than POSIX::ULONG_MAX(), so this
+# change should match existing usage.  It only actually makes a difference
+# in old perl, since recent versions have gone to 64-bits for IV and UV, the
+# same as a ulong.
+#
+# In perl 5.005 we explicitly mask the mpz return down to 32-bits to get ~0.
+# UV_MAX is no good, it reflects the size of the UV type (64-bits), rather
+# than the size of the values one ought to be storing in an SV (32-bits).
+
+gmp_UV
+scan0 (z, start)
+    mpz_coerce   z
+    ulong_coerce start
+ALIAS:
+    GMP::Mpz::scan1 = 1
+PREINIT:
+    static_functable const struct {
+      unsigned long (*op) (mpz_srcptr, unsigned long);
+    } table[] = {
+      { mpz_scan0  }, /* 0 */
+      { mpz_scan1  }, /* 1 */
+    };
+CODE:
+    assert_table (ix);
+    RETVAL = (*table[ix].op) (z, start);
+    if (PERL_LT (5,6))
+      RETVAL &= 0xFFFFFFFF;
+OUTPUT:
+    RETVAL
+
+
+void
+setbit (sv, bit)
+    SV           *sv
+    ulong_coerce bit
+ALIAS:
+    GMP::Mpz::clrbit = 1
+    GMP::Mpz::combit = 2
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpz_ptr, unsigned long);
+    } table[] = {
+      { mpz_setbit }, /* 0 */
+      { mpz_clrbit }, /* 1 */
+      { mpz_combit }, /* 2 */
+    };
+    int  use;
+    mpz  z;
+CODE:
+    use = use_sv (sv);
+    if (use == USE_MPZ && SvREFCNT(SvRV(sv)) == 1 && ! SvSMAGICAL(sv))
+      {
+        /* our operand is a non-magical mpz with a reference count of 1, so
+           we can just modify it */
+        (*table[ix].op) (SvMPZ(sv)->m, bit);
+      }
+    else
+      {
+        /* otherwise we need to make a new mpz, from whatever we have, and
+           operate on that, possibly invoking magic when storing back */
+        SV   *new_sv;
+        mpz  z = new_mpz ();
+        mpz_ptr  coerce_ptr = coerce_mpz_using (z->m, sv, use);
+        if (coerce_ptr != z->m)
+          mpz_set (z->m, coerce_ptr);
+        (*table[ix].op) (z->m, bit);
+        new_sv = sv_bless (sv_setref_pv (sv_newmortal(), NULL, z),
+                           mpz_class_hv);
+        SvSetMagicSV (sv, new_sv);
+      }
+
+
+void
+sqrtrem (z)
+    mpz_coerce z
+PREINIT:
+    SV  *sv;
+    mpz root;
+    mpz rem;
+PPCODE:
+    root = new_mpz();
+    rem = new_mpz();
+    mpz_sqrtrem (root->m, rem->m, z);
+    EXTEND (SP, 2);
+    PUSHs (MPX_NEWMORTAL (root, mpz_class_hv));
+    PUSHs (MPX_NEWMORTAL (rem,  mpz_class_hv));
+
+
+size_t
+sizeinbase (z, base)
+    mpz_coerce z
+    int        base
+CODE:
+    RETVAL = mpz_sizeinbase (z, base);
+OUTPUT:
+    RETVAL
+
+
+int
+tstbit (z, bit)
+    mpz_coerce   z
+    ulong_coerce bit
+CODE:
+    RETVAL = mpz_tstbit (z, bit);
+OUTPUT:
+    RETVAL
+
+
+
+#------------------------------------------------------------------------------
+
+MODULE = GMP         PACKAGE = GMP::Mpq
+
+
+mpq
+mpq (...)
+ALIAS:
+    GMP::Mpq::new = 1
+CODE:
+    TRACE (printf ("%s new, ix=%ld, items=%d\n", mpq_class, ix, (int) items));
+    RETVAL = new_mpq();
+    switch (items) {
+    case 0:
+      mpq_set_ui (RETVAL->m, 0L, 1L);
+      break;
+    case 1:
+      {
+        mpq_ptr rp = RETVAL->m;
+        mpq_ptr cp = coerce_mpq (rp, ST(0));
+        if (cp != rp)
+          mpq_set (rp, cp);
+      }
+      break;
+    case 2:
+      {
+        mpz_ptr rp, cp;
+        rp = mpq_numref (RETVAL->m);
+        cp = coerce_mpz (rp, ST(0));
+        if (cp != rp)
+          mpz_set (rp, cp);
+        rp = mpq_denref (RETVAL->m);
+        cp = coerce_mpz (rp, ST(1));
+        if (cp != rp)
+          mpz_set (rp, cp);
+      }
+      break;
+    default:
+      croak ("%s new: invalid arguments", mpq_class);
+    }
+OUTPUT:
+    RETVAL
+
+
+void
+overload_constant (str, pv, d1, ...)
+    const_string_assume str
+    SV                  *pv
+    dummy               d1
+PREINIT:
+    SV  *sv;
+    mpq q;
+PPCODE:
+    TRACE (printf ("%s constant: %s\n", mpq_class, str));
+    q = new_mpq();
+    if (mpq_set_str (q->m, str, 0) == 0)
+      { sv = sv_bless (sv_setref_pv (sv_newmortal(), NULL, q), mpq_class_hv); }
+    else
+      { free_mpq (q); sv = pv; }
+    XPUSHs(sv);
+
+
+mpq
+overload_copy (q, d1, d2)
+    mpq_assume q
+    dummy      d1
+    dummy      d2
+CODE:
+    RETVAL = new_mpq();
+    mpq_set (RETVAL->m, q->m);
+OUTPUT:
+    RETVAL
+
+
+void
+DESTROY (q)
+    mpq_assume q
+CODE:
+    TRACE (printf ("%s DESTROY %p\n", mpq_class, q));
+    free_mpq (q);
+
+
+malloced_string
+overload_string (q, d1, d2)
+    mpq_assume q
+    dummy      d1
+    dummy      d2
+CODE:
+    TRACE (printf ("%s overload_string %p\n", mpq_class, q));
+    RETVAL = mpq_get_str (NULL, 10, q->m);
+OUTPUT:
+    RETVAL
+
+
+mpq
+overload_add (xv, yv, order)
+    SV *xv
+    SV *yv
+    SV *order
+ALIAS:
+    GMP::Mpq::overload_sub   = 1
+    GMP::Mpq::overload_mul   = 2
+    GMP::Mpq::overload_div   = 3
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpq_ptr, mpq_srcptr, mpq_srcptr);
+    } table[] = {
+      { mpq_add }, /* 0 */
+      { mpq_sub }, /* 1 */
+      { mpq_mul }, /* 2 */
+      { mpq_div }, /* 3 */
+    };
+CODE:
+    TRACE (printf ("%s binary\n", mpf_class));
+    assert_table (ix);
+    if (order == &PL_sv_yes)
+      SV_PTR_SWAP (xv, yv);
+    RETVAL = new_mpq();
+    (*table[ix].op) (RETVAL->m,
+                     coerce_mpq (tmp_mpq_0, xv),
+                     coerce_mpq (tmp_mpq_1, yv));
+OUTPUT:
+    RETVAL
+
+
+void
+overload_addeq (x, y, o)
+    mpq_assume   x
+    mpq_coerce   y
+    order_noswap o
+ALIAS:
+    GMP::Mpq::overload_subeq = 1
+    GMP::Mpq::overload_muleq = 2
+    GMP::Mpq::overload_diveq = 3
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpq_ptr, mpq_srcptr, mpq_srcptr);
+    } table[] = {
+      { mpq_add    }, /* 0 */
+      { mpq_sub    }, /* 1 */
+      { mpq_mul    }, /* 2 */
+      { mpq_div    }, /* 3 */
+    };
+PPCODE:
+    assert_table (ix);
+    (*table[ix].op) (x->m, x->m, y);
+    XPUSHs(ST(0));
+
+
+mpq
+overload_lshift (qv, nv, order)
+    SV *qv
+    SV *nv
+    SV *order
+ALIAS:
+    GMP::Mpq::overload_rshift   = 1
+    GMP::Mpq::overload_pow      = 2
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpq_ptr, mpq_srcptr, unsigned long);
+    } table[] = {
+      { mpq_mul_2exp }, /* 0 */
+      { mpq_div_2exp }, /* 1 */
+      { x_mpq_pow_ui }, /* 2 */
+    };
+CODE:
+    assert_table (ix);
+    if (order == &PL_sv_yes)
+      SV_PTR_SWAP (qv, nv);
+    RETVAL = new_mpq();
+    (*table[ix].op) (RETVAL->m, coerce_mpq (RETVAL->m, qv), coerce_ulong (nv));
+OUTPUT:
+    RETVAL
+
+
+void
+overload_lshifteq (q, n, o)
+    mpq_assume   q
+    ulong_coerce n
+    order_noswap o
+ALIAS:
+    GMP::Mpq::overload_rshifteq   = 1
+    GMP::Mpq::overload_poweq      = 2
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpq_ptr, mpq_srcptr, unsigned long);
+    } table[] = {
+      { mpq_mul_2exp }, /* 0 */
+      { mpq_div_2exp }, /* 1 */
+      { x_mpq_pow_ui }, /* 2 */
+    };
+PPCODE:
+    assert_table (ix);
+    (*table[ix].op) (q->m, q->m, n);
+    XPUSHs(ST(0));
+
+
+void
+overload_inc (q, d1, d2)
+    mpq_assume q
+    dummy      d1
+    dummy      d2
+ALIAS:
+    GMP::Mpq::overload_dec = 1
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpz_ptr, mpz_srcptr, mpz_srcptr);
+    } table[] = {
+      { mpz_add }, /* 0 */
+      { mpz_sub }, /* 1 */
+    };
+CODE:
+    assert_table (ix);
+    (*table[ix].op) (mpq_numref(q->m), mpq_numref(q->m), mpq_denref(q->m));
+
+
+mpq
+overload_abs (q, d1, d2)
+    mpq_assume q
+    dummy      d1
+    dummy      d2
+ALIAS:
+    GMP::Mpq::overload_neg = 1
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpq_ptr w, mpq_srcptr x);
+    } table[] = {
+      { mpq_abs }, /* 0 */
+      { mpq_neg }, /* 1 */
+    };
+CODE:
+    assert_table (ix);
+    RETVAL = new_mpq();
+    (*table[ix].op) (RETVAL->m, q->m);
+OUTPUT:
+    RETVAL
+
+
+int
+overload_spaceship (x, y, order)
+    mpq_assume x
+    mpq_coerce y
+    SV         *order
+CODE:
+    RETVAL = mpq_cmp (x->m, y);
+    RETVAL = SGN (RETVAL);
+    if (order == &PL_sv_yes)
+      RETVAL = -RETVAL;
+OUTPUT:
+    RETVAL
+
+
+bool
+overload_bool (q, d1, d2)
+    mpq_assume q
+    dummy      d1
+    dummy      d2
+ALIAS:
+    GMP::Mpq::overload_not = 1
+CODE:
+    RETVAL = (mpq_sgn (q->m) != 0) ^ ix;
+OUTPUT:
+    RETVAL
+
+
+bool
+overload_eq (x, yv, d)
+    mpq_assume x
+    SV         *yv
+    dummy      d
+ALIAS:
+    GMP::Mpq::overload_ne = 1
+PREINIT:
+    int  use;
+CODE:
+    use = use_sv (yv);
+    switch (use) {
+    case USE_IVX:
+    case USE_UVX:
+    case USE_MPZ:
+      RETVAL = 0;
+      if (x_mpq_integer_p (x->m))
+        {
+          switch (use) {
+          case USE_IVX:
+            RETVAL = (mpz_cmp_si (mpq_numref(x->m), SvIVX(yv)) == 0);
+            break;
+          case USE_UVX:
+            RETVAL = (mpz_cmp_ui (mpq_numref(x->m), SvUVX(yv)) == 0);
+            break;
+          case USE_MPZ:
+            RETVAL = (mpz_cmp (mpq_numref(x->m), SvMPZ(yv)->m) == 0);
+            break;
+          }
+        }
+      break;
+
+    case USE_MPQ:
+      RETVAL = (mpq_equal (x->m, SvMPQ(yv)->m) != 0);
+      break;
+
+    default:
+      RETVAL = (mpq_equal (x->m, coerce_mpq_using (tmp_mpq_0, yv, use)) != 0);
+      break;
+    }
+    RETVAL ^= ix;
+OUTPUT:
+    RETVAL
+
+
+void
+canonicalize (q)
+    mpq q
+CODE:
+    mpq_canonicalize (q->m);
+
+
+mpq
+inv (q)
+    mpq_coerce q
+CODE:
+    RETVAL = new_mpq();
+    mpq_inv (RETVAL->m, q);
+OUTPUT:
+    RETVAL
+
+
+mpz
+num (q)
+    mpq q
+ALIAS:
+    GMP::Mpq::den = 1
+CODE:
+    RETVAL = new_mpz();
+    mpz_set (RETVAL->m, (ix == 0 ? mpq_numref(q->m) : mpq_denref(q->m)));
+OUTPUT:
+    RETVAL
+
+
+
+#------------------------------------------------------------------------------
+
+MODULE = GMP         PACKAGE = GMP::Mpf
+
+
+mpf
+mpf (...)
+ALIAS:
+    GMP::Mpf::new = 1
+PREINIT:
+    unsigned long  prec;
+CODE:
+    TRACE (printf ("%s new\n", mpf_class));
+    if (items > 2)
+      croak ("%s new: invalid arguments", mpf_class);
+    prec = (items == 2 ? coerce_ulong (ST(1)) : mpf_get_default_prec());
+    RETVAL = new_mpf (prec);
+    if (items >= 1)
+      {
+        SV *sv = ST(0);
+        my_mpf_set_sv_using (RETVAL, sv, use_sv(sv));
+      }
+OUTPUT:
+    RETVAL
+
+
+mpf
+overload_constant (sv, d1, d2, ...)
+    SV     *sv
+    dummy  d1
+    dummy  d2
+CODE:
+    assert (SvPOK (sv));
+    TRACE (printf ("%s constant: %s\n", mpq_class, SvPVX(sv)));
+    RETVAL = new_mpf (mpf_get_default_prec());
+    my_mpf_set_svstr (RETVAL, sv);
+OUTPUT:
+    RETVAL
+
+
+mpf
+overload_copy (f, d1, d2)
+    mpf_assume f
+    dummy      d1
+    dummy      d2
+CODE:
+    TRACE (printf ("%s copy\n", mpf_class));
+    RETVAL = new_mpf (mpf_get_prec (f));
+    mpf_set (RETVAL, f);
+OUTPUT:
+    RETVAL
+
+
+void
+DESTROY (f)
+    mpf_assume f
+CODE:
+    TRACE (printf ("%s DESTROY %p\n", mpf_class, f));
+    mpf_clear (f);
+    Safefree (f);
+    assert_support (mpf_count--);
+    TRACE_ACTIVE ();
+
+
+mpf
+overload_add (x, y, order)
+    mpf_assume     x
+    mpf_coerce_st0 y
+    SV             *order
+ALIAS:
+    GMP::Mpf::overload_sub   = 1
+    GMP::Mpf::overload_mul   = 2
+    GMP::Mpf::overload_div   = 3
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpf_ptr, mpf_srcptr, mpf_srcptr);
+    } table[] = {
+      { mpf_add }, /* 0 */
+      { mpf_sub }, /* 1 */
+      { mpf_mul }, /* 2 */
+      { mpf_div }, /* 3 */
+    };
+CODE:
+    assert_table (ix);
+    RETVAL = new_mpf (mpf_get_prec (x));
+    if (order == &PL_sv_yes)
+      MPF_PTR_SWAP (x, y);
+    (*table[ix].op) (RETVAL, x, y);
+OUTPUT:
+    RETVAL
+
+
+void
+overload_addeq (x, y, o)
+    mpf_assume     x
+    mpf_coerce_st0 y
+    order_noswap   o
+ALIAS:
+    GMP::Mpf::overload_subeq = 1
+    GMP::Mpf::overload_muleq = 2
+    GMP::Mpf::overload_diveq = 3
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpf_ptr, mpf_srcptr, mpf_srcptr);
+    } table[] = {
+      { mpf_add }, /* 0 */
+      { mpf_sub }, /* 1 */
+      { mpf_mul }, /* 2 */
+      { mpf_div }, /* 3 */
+    };
+PPCODE:
+    assert_table (ix);
+    (*table[ix].op) (x, x, y);
+    XPUSHs(ST(0));
+
+
+mpf
+overload_lshift (fv, nv, order)
+    SV *fv
+    SV *nv
+    SV *order
+ALIAS:
+    GMP::Mpf::overload_rshift = 1
+    GMP::Mpf::overload_pow    = 2
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpf_ptr, mpf_srcptr, unsigned long);
+    } table[] = {
+      { mpf_mul_2exp }, /* 0 */
+      { mpf_div_2exp }, /* 1 */
+      { mpf_pow_ui   }, /* 2 */
+    };
+    mpf f;
+    unsigned long prec;
+CODE:
+    assert_table (ix);
+    MPF_ASSUME (f, fv);
+    prec = mpf_get_prec (f);
+    if (order == &PL_sv_yes)
+      SV_PTR_SWAP (fv, nv);
+    f = coerce_mpf (tmp_mpf_0, fv, prec);
+    RETVAL = new_mpf (prec);
+    (*table[ix].op) (RETVAL, f, coerce_ulong (nv));
+OUTPUT:
+    RETVAL
+
+
+void
+overload_lshifteq (f, n, o)
+    mpf_assume   f
+    ulong_coerce n
+    order_noswap o
+ALIAS:
+    GMP::Mpf::overload_rshifteq   = 1
+    GMP::Mpf::overload_poweq      = 2
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpf_ptr, mpf_srcptr, unsigned long);
+    } table[] = {
+      { mpf_mul_2exp }, /* 0 */
+      { mpf_div_2exp }, /* 1 */
+      { mpf_pow_ui   }, /* 2 */
+    };
+PPCODE:
+    assert_table (ix);
+    (*table[ix].op) (f, f, n);
+    XPUSHs(ST(0));
+
+
+mpf
+overload_abs (f, d1, d2)
+    mpf_assume f
+    dummy      d1
+    dummy      d2
+ALIAS:
+    GMP::Mpf::overload_neg   = 1
+    GMP::Mpf::overload_sqrt  = 2
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpf_ptr w, mpf_srcptr x);
+    } table[] = {
+      { mpf_abs  }, /* 0 */
+      { mpf_neg  }, /* 1 */
+      { mpf_sqrt }, /* 2 */
+    };
+CODE:
+    assert_table (ix);
+    RETVAL = new_mpf (mpf_get_prec (f));
+    (*table[ix].op) (RETVAL, f);
+OUTPUT:
+    RETVAL
+
+
+void
+overload_inc (f, d1, d2)
+    mpf_assume f
+    dummy      d1
+    dummy      d2
+ALIAS:
+    GMP::Mpf::overload_dec = 1
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpf_ptr w, mpf_srcptr x, unsigned long y);
+    } table[] = {
+      { mpf_add_ui }, /* 0 */
+      { mpf_sub_ui }, /* 1 */
+    };
+CODE:
+    assert_table (ix);
+    (*table[ix].op) (f, f, 1L);
+
+
+int
+overload_spaceship (xv, yv, order)
+    SV *xv
+    SV *yv
+    SV *order
+PREINIT:
+    mpf x;
+CODE:
+    MPF_ASSUME (x, xv);
+    switch (use_sv (yv)) {
+    case USE_IVX:
+      RETVAL = mpf_cmp_si (x, SvIVX(yv));
+      break;
+    case USE_UVX:
+      RETVAL = mpf_cmp_ui (x, SvUVX(yv));
+      break;
+    case USE_NVX:
+      RETVAL = mpf_cmp_d (x, SvNVX(yv));
+      break;
+    case USE_PVX:
+      {
+        STRLEN len;
+        const char *str = SvPV (yv, len);
+        /* enough for all digits of the string */
+        tmp_mpf_set_prec (tmp_mpf_0, strlen(str)+64);
+        if (mpf_set_str (tmp_mpf_0->m, str, 10) != 0)
+          croak ("%s <=>: invalid string format", mpf_class);
+        RETVAL = mpf_cmp (x, tmp_mpf_0->m);
+      }
+      break;
+    case USE_MPZ:
+      RETVAL = - x_mpz_cmp_f (SvMPZ(yv)->m, x);
+      break;
+    case USE_MPF:
+      RETVAL = mpf_cmp (x, SvMPF(yv));
+      break;
+    default:
+      RETVAL = mpq_cmp (coerce_mpq (tmp_mpq_0, xv),
+                        coerce_mpq (tmp_mpq_1, yv));
+      break;
+    }
+    RETVAL = SGN (RETVAL);
+    if (order == &PL_sv_yes)
+      RETVAL = -RETVAL;
+OUTPUT:
+    RETVAL
+
+
+bool
+overload_bool (f, d1, d2)
+    mpf_assume f
+    dummy      d1
+    dummy      d2
+ALIAS:
+    GMP::Mpf::overload_not = 1
+CODE:
+    RETVAL = (mpf_sgn (f) != 0) ^ ix;
+OUTPUT:
+    RETVAL
+
+
+mpf
+ceil (f)
+    mpf_coerce_def f
+ALIAS:
+    GMP::Mpf::floor = 1
+    GMP::Mpf::trunc = 2
+PREINIT:
+    static_functable const struct {
+      void (*op) (mpf_ptr w, mpf_srcptr x);
+    } table[] = {
+      { mpf_ceil  }, /* 0 */
+      { mpf_floor }, /* 1 */
+      { mpf_trunc }, /* 2 */
+    };
+CODE:
+    assert_table (ix);
+    RETVAL = new_mpf (mpf_get_prec (f));
+    (*table[ix].op) (RETVAL, f);
+OUTPUT:
+    RETVAL
+
+
+unsigned long
+get_default_prec ()
+CODE:
+    RETVAL = mpf_get_default_prec();
+OUTPUT:
+    RETVAL
+
+
+unsigned long
+get_prec (f)
+    mpf_coerce_def f
+CODE:
+    RETVAL = mpf_get_prec (f);
+OUTPUT:
+    RETVAL
+
+
+bool
+mpf_eq (xv, yv, bits)
+    SV           *xv
+    SV           *yv
+    ulong_coerce bits
+PREINIT:
+    mpf  x, y;
+CODE:
+    TRACE (printf ("%s eq\n", mpf_class));
+    coerce_mpf_pair (&x,xv, &y,yv);
+    RETVAL = mpf_eq (x, y, bits);
+OUTPUT:
+    RETVAL
+
+
+mpf
+reldiff (xv, yv)
+    SV *xv
+    SV *yv
+PREINIT:
+    mpf  x, y;
+    unsigned long prec;
+CODE:
+    TRACE (printf ("%s reldiff\n", mpf_class));
+    prec = coerce_mpf_pair (&x,xv, &y,yv);
+    RETVAL = new_mpf (prec);
+    mpf_reldiff (RETVAL, x, y);
+OUTPUT:
+    RETVAL
+
+
+void
+set_default_prec (prec)
+    ulong_coerce prec
+CODE:
+    TRACE (printf ("%s set_default_prec %lu\n", mpf_class, prec));
+    mpf_set_default_prec (prec);
+
+
+void
+set_prec (sv, prec)
+    SV           *sv
+    ulong_coerce prec
+PREINIT:
+    mpf_ptr  old_f, new_f;
+    int      use;
+CODE:
+    TRACE (printf ("%s set_prec to %lu\n", mpf_class, prec));
+    use = use_sv (sv);
+    if (use == USE_MPF)
+      {
+        old_f = SvMPF(sv);
+        if (SvREFCNT(SvRV(sv)) == 1)
+          mpf_set_prec (old_f, prec);
+        else
+          {
+            TRACE (printf ("  fork new mpf\n"));
+            new_f = new_mpf (prec);
+            mpf_set (new_f, old_f);
+            goto setref;
+          }
+      }
+    else
+      {
+        TRACE (printf ("  coerce to mpf\n"));
+        new_f = new_mpf (prec);
+        my_mpf_set_sv_using (new_f, sv, use);
+      setref:
+        sv_bless (sv_setref_pv (sv, NULL, new_f), mpf_class_hv);
+      }
+
+
+
+#------------------------------------------------------------------------------
+
+MODULE = GMP         PACKAGE = GMP::Rand
+
+randstate
+new (...)
+ALIAS:
+    GMP::Rand::randstate = 1
+CODE:
+    TRACE (printf ("%s new\n", rand_class));
+    New (GMP_MALLOC_ID, RETVAL, 1, __gmp_randstate_struct);
+    TRACE (printf ("  RETVAL %p\n", RETVAL));
+    assert_support (rand_count++);
+    TRACE_ACTIVE ();
+
+    if (items == 0)
+      {
+        gmp_randinit_default (RETVAL);
+      }
+    else
+      {
+        if (SvROK (ST(0)) && sv_derived_from (ST(0), rand_class))
+          {
+            if (items != 1)
+              goto invalid;
+            gmp_randinit_set (RETVAL, SvRANDSTATE (ST(0)));
+          }
+        else
+          {
+            STRLEN      len;
+            const char  *method = SvPV (ST(0), len);
+            assert (len == strlen (method));
+            if (strcmp (method, "lc_2exp") == 0)
+              {
+                if (items != 4)
+                  goto invalid;
+                gmp_randinit_lc_2exp (RETVAL,
+                                      coerce_mpz (tmp_mpz_0, ST(1)),
+                                      coerce_ulong (ST(2)),
+                                      coerce_ulong (ST(3)));
+              }
+            else if (strcmp (method, "lc_2exp_size") == 0)
+              {
+                if (items != 2)
+                  goto invalid;
+                if (! gmp_randinit_lc_2exp_size (RETVAL, coerce_ulong (ST(1))))
+                  {
+                    Safefree (RETVAL);
+                    XSRETURN_UNDEF;
+                  }
+              }
+            else if (strcmp (method, "mt") == 0)
+              {
+                if (items != 1)
+                  goto invalid;
+                gmp_randinit_mt (RETVAL);
+              }
+            else
+              {
+              invalid:
+                croak ("%s new: invalid arguments", rand_class);
+              }
+          }
+      }
+OUTPUT:
+    RETVAL
+
+
+void
+DESTROY (r)
+    randstate r
+CODE:
+    TRACE (printf ("%s DESTROY\n", rand_class));
+    gmp_randclear (r);
+    Safefree (r);
+    assert_support (rand_count--);
+    TRACE_ACTIVE ();
+
+
+void
+seed (r, z)
+    randstate  r
+    mpz_coerce z
+CODE:
+    gmp_randseed (r, z);
+
+
+mpz
+mpz_urandomb (r, bits)
+    randstate    r
+    ulong_coerce bits
+ALIAS:
+    GMP::Rand::mpz_rrandomb = 1
+PREINIT:
+    static_functable const struct {
+      void (*fun) (mpz_ptr, gmp_randstate_t r, unsigned long bits);
+    } table[] = {
+      { mpz_urandomb }, /* 0 */
+      { mpz_rrandomb }, /* 1 */
+    };
+CODE:
+    assert_table (ix);
+    RETVAL = new_mpz();
+    (*table[ix].fun) (RETVAL->m, r, bits);
+OUTPUT:
+    RETVAL
+
+
+mpz
+mpz_urandomm (r, m)
+    randstate  r
+    mpz_coerce m
+CODE:
+    RETVAL = new_mpz();
+    mpz_urandomm (RETVAL->m, r, m);
+OUTPUT:
+    RETVAL
+
+
+mpf
+mpf_urandomb (r, bits)
+    randstate    r
+    ulong_coerce bits
+CODE:
+    RETVAL = new_mpf (bits);
+    mpf_urandomb (RETVAL, r, bits);
+OUTPUT:
+    RETVAL
+
+
+unsigned long
+gmp_urandomb_ui (r, bits)
+    randstate    r
+    ulong_coerce bits
+ALIAS:
+    GMP::Rand::gmp_urandomm_ui = 1
+PREINIT:
+    static_functable const struct {
+      unsigned long (*fun) (gmp_randstate_t r, unsigned long bits);
+    } table[] = {
+      { gmp_urandomb_ui }, /* 0 */
+      { gmp_urandomm_ui }, /* 1 */
+    };
+CODE:
+    assert_table (ix);
+    RETVAL = (*table[ix].fun) (r, bits);
+OUTPUT:
+    RETVAL
diff --git a/third_party/gmp/demos/perl/GMP/Mpf.pm b/third_party/gmp/demos/perl/GMP/Mpf.pm
new file mode 100644
index 0000000..4c0dec6
--- /dev/null
+++ b/third_party/gmp/demos/perl/GMP/Mpf.pm
@@ -0,0 +1,106 @@
+# GMP mpf module.
+
+# Copyright 2001, 2003 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+
+package GMP::Mpf;
+
+require GMP;
+require Exporter;
+@ISA = qw(GMP Exporter);
+@EXPORT = qw();
+@EXPORT_OK = qw();
+%EXPORT_TAGS = ('all' => [qw(
+			     ceil floor get_default_prec get_prec mpf mpf_eq
+			     reldiff set_default_prec set_prec trunc)],
+		'constants'   => [@EXPORT],
+		'noconstants' => [@EXPORT]);
+Exporter::export_ok_tags('all');
+
+use overload
+    '+'   => \&overload_add,     '+='  => \&overload_addeq,
+    '-'   => \&overload_sub,     '-='  => \&overload_subeq,
+    '*'   => \&overload_mul,     '*='  => \&overload_muleq,
+    '/'   => \&overload_div,     '/='  => \&overload_diveq,
+    '**'  => \&overload_pow,     '**=' => \&overload_poweq,
+    '<<'  => \&overload_lshift,  '<<=' => \&overload_lshifteq,
+    '>>'  => \&overload_rshift,  '>>=' => \&overload_rshifteq,
+
+    'bool' => \&overload_bool,
+    'not'  => \&overload_not,
+    '!'    => \&overload_not,
+    '<=>'  => \&overload_spaceship,
+    '++'   => \&overload_inc,
+    '--'   => \&overload_dec,
+    'abs'  => \&overload_abs,
+    'neg'  => \&overload_neg,
+    'sqrt' => \&overload_sqrt,
+    '='    => \&overload_copy,
+    '""'   => \&overload_string;
+
+sub import {
+  foreach (@_) {
+    if ($_ eq ':constants') {
+      overload::constant ('integer' => \&overload_constant,
+			  'binary'  => \&overload_constant,
+			  'float'   => \&overload_constant);
+    } elsif ($_ eq ':noconstants') {
+      overload::remove_constant ('integer' => \&overload_constant,
+				 'binary'  => \&overload_constant,
+				 'float'   => \&overload_constant);
+    }
+  }
+  goto &Exporter::import;
+}
+
+
+sub overload_string {
+  my $fmt;
+  BEGIN { $^W = 0; }
+  if (defined ($#)) {
+    $fmt = $#;
+    BEGIN { $^W = 1; }
+    # protect against calling sprintf_internal with a bad format
+    if ($fmt !~ /^((%%|[^%])*%[-+ .\d]*)([eEfgG](%%|[^%])*)$/) {
+      die "GMP::Mpf: invalid \$# format: $#\n";
+    }
+    $fmt = $1 . 'F' . $3;
+  } else {
+    $fmt = '%.Fg';
+  }
+  GMP::sprintf_internal ($fmt, $_[0]);
+}
+
+1;
+__END__
+
+
+# Local variables:
+# perl-indent-level: 2
+# End:
diff --git a/third_party/gmp/demos/perl/GMP/Mpq.pm b/third_party/gmp/demos/perl/GMP/Mpq.pm
new file mode 100644
index 0000000..fe01084
--- /dev/null
+++ b/third_party/gmp/demos/perl/GMP/Mpq.pm
@@ -0,0 +1,89 @@
+# GMP mpq module.
+
+# Copyright 2001 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+
+package GMP::Mpq;
+
+require GMP;
+require Exporter;
+@ISA = qw(GMP Exporter);
+@EXPORT = qw();
+@EXPORT_OK = qw();
+%EXPORT_TAGS = ('all' => [qw(canonicalize den inv mpq num)],
+		'constants'   => [@EXPORT],
+		'noconstants' => [@EXPORT] );
+Exporter::export_ok_tags('all');
+
+use overload
+    '+'   => \&overload_add,     '+='  => \&overload_addeq,
+    '-'   => \&overload_sub,     '-='  => \&overload_subeq,
+    '*'   => \&overload_mul,     '*='  => \&overload_muleq,
+    '/'   => \&overload_div,     '/='  => \&overload_diveq,
+    '**'  => \&overload_pow,     '**=' => \&overload_poweq,
+    '<<'  => \&overload_lshift,  '<<=' => \&overload_lshifteq,
+    '>>'  => \&overload_rshift,  '>>=' => \&overload_rshifteq,
+
+    'bool' => \&overload_bool,
+    'not'  => \&overload_not,
+    '!'    => \&overload_not,
+    '=='   => \&overload_eq,
+    '!='   => \&overload_ne,
+    '<=>'  => \&overload_spaceship,
+    '++'   => \&overload_inc,
+    '--'   => \&overload_dec,
+    'abs'  => \&overload_abs,
+    'neg'  => \&overload_neg,
+    '='    => \&overload_copy,
+    '""'   => \&overload_string;
+
+my $constants = { };
+
+sub import {
+  foreach (@_) {
+    if ($_ eq ':constants') {
+      overload::constant ('integer' => \&overload_constant,
+			  'binary'  => \&overload_constant,
+			  'float'   => \&overload_constant);
+    } elsif ($_ eq ':noconstants') {
+      overload::remove_constant ('integer' => \&overload_constant,
+				 'binary'  => \&overload_constant,
+				 'float'   => \&overload_constant);
+    }
+  }
+  goto &Exporter::import;
+}
+
+1;
+__END__
+
+
+# Local variables:
+# perl-indent-level: 2
+# End:
diff --git a/third_party/gmp/demos/perl/GMP/Mpz.pm b/third_party/gmp/demos/perl/GMP/Mpz.pm
new file mode 100644
index 0000000..27e6336
--- /dev/null
+++ b/third_party/gmp/demos/perl/GMP/Mpz.pm
@@ -0,0 +1,101 @@
+# GMP mpz module.
+
+# Copyright 2001-2003 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+
+package GMP::Mpz;
+
+require GMP;
+require Exporter;
+@ISA = qw(GMP Exporter);
+@EXPORT = qw();
+@EXPORT_OK = qw();
+%EXPORT_TAGS = ('all' => [qw(
+			     bin cdiv cdiv_2exp clrbit combit congruent_p
+			     congruent_2exp_p divexact divisible_p
+			     divisible_2exp_p even_p fac fdiv fdiv_2exp fib
+			     fib2 gcd gcdext hamdist invert jacobi kronecker
+			     lcm lucnum lucnum2 mod mpz mpz_export
+			     mpz_import nextprime odd_p perfect_power_p
+			     perfect_square_p popcount powm probab_prime_p
+			     realloc remove root roote rootrem scan0 scan1
+			     setbit sizeinbase sqrtrem tdiv tdiv_2exp
+			     tstbit)],
+		'constants'   => [@EXPORT],
+		'noconstants' => [@EXPORT]);
+Exporter::export_ok_tags('all');
+
+use overload
+    '+'    => \&overload_add,     '+='   => \&overload_addeq,
+    '-'    => \&overload_sub,     '-='   => \&overload_subeq,
+    '*'    => \&overload_mul,     '*='   => \&overload_muleq,
+    '/'    => \&overload_div,     '/='   => \&overload_diveq,
+    '%'    => \&overload_rem,     '%='   => \&overload_remeq,
+    '<<'   => \&overload_lshift,  '<<='  => \&overload_lshifteq,
+    '>>'   => \&overload_rshift,  '>>='  => \&overload_rshifteq,
+    '**'   => \&overload_pow,     '**='  => \&overload_poweq,
+    '&'    => \&overload_and,     '&='   => \&overload_andeq,
+    '|'    => \&overload_ior,     '|='   => \&overload_ioreq,
+    '^'    => \&overload_xor,     '^='   => \&overload_xoreq,
+
+    'bool' => \&overload_bool,
+    'not'  => \&overload_not,
+    '!'    => \&overload_not,
+    '~'    => \&overload_com,
+    '<=>'  => \&overload_spaceship,
+    '++'   => \&overload_inc,
+    '--'   => \&overload_dec,
+    '='    => \&overload_copy,
+    'abs'  => \&overload_abs,
+    'neg'  => \&overload_neg,
+    'sqrt' => \&overload_sqrt,
+    '""'   => \&overload_string;
+
+sub import {
+  foreach (@_) {
+    if ($_ eq ':constants') {
+      overload::constant ('integer' => \&overload_constant,
+			  'binary'  => \&overload_constant,
+			  'float'   => \&overload_constant);
+    } elsif ($_ eq ':noconstants') {
+      overload::remove_constant ('integer' => \&overload_constant,
+				 'binary'  => \&overload_constant,
+				 'float'   => \&overload_constant);
+    }
+  }
+  goto &Exporter::import;
+}
+
+1;
+__END__
+
+
+# Local variables:
+# perl-indent-level: 2
+# End:
diff --git a/third_party/gmp/demos/perl/GMP/Rand.pm b/third_party/gmp/demos/perl/GMP/Rand.pm
new file mode 100644
index 0000000..9f7d763
--- /dev/null
+++ b/third_party/gmp/demos/perl/GMP/Rand.pm
@@ -0,0 +1,44 @@
+# GMP random numbers module.
+
+# Copyright 2001, 2003 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+
+package GMP::Rand;
+
+require GMP;
+require Exporter;
+@ISA = qw(GMP Exporter);
+@EXPORT = qw();
+%EXPORT_TAGS = ('all' => [qw(
+			     randstate mpf_urandomb mpz_rrandomb
+			     mpz_urandomb mpz_urandomm gmp_urandomb_ui
+			     gmp_urandomm_ui)]);
+Exporter::export_ok_tags('all');
+1;
+__END__
diff --git a/third_party/gmp/demos/perl/INSTALL b/third_party/gmp/demos/perl/INSTALL
new file mode 100644
index 0000000..f3d7c53
--- /dev/null
+++ b/third_party/gmp/demos/perl/INSTALL
@@ -0,0 +1,88 @@
+Copyright 2001, 2003, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.
+
+
+
+
+
+                  GMP PERL MODULE INSTALLATION
+
+
+This module can be compiled within the GMP source directory or moved
+elsewhere and compiled.  An installed GMP can be used, or a specified
+GMP build tree.  Both static and shared GMP builds will work.
+
+The simplest case is when GMP has been installed to a standard system
+location
+
+	perl Makefile.PL
+	make
+
+If not yet installed then the top-level GMP build directory must be
+specified
+
+	perl Makefile.PL GMP_BUILDDIR=/my/gmp/build
+	make
+
+In any case, with the module built, the sample program provided can be
+run
+
+	perl -Iblib/arch sample.pl
+
+If you built a shared version of libgmp but haven't yet installed it,
+then it might be necessary to add a run-time path to it.  For example
+
+	LD_LIBRARY_PATH=/my/gmp/build/.libs perl -Iblib/arch sample.pl
+
+Documentation is provided in pod format in GMP.pm, and will have been
+"man"-ified in the module build
+
+	man -l blib/man3/GMP.3pm
+or
+	man -M`pwd`/blib GMP
+
+A test script is provided, running a large number of more or less
+trivial checks
+
+	make test
+
+The module and its documentation can be installed in the usual way
+
+	make install
+
+This will be into /usr/local or wherever the perl Config module
+directs, but that can be controlled back at the Makefile.PL stage with
+the usual ExtUtils::MakeMaker options.
+
+Once installed, programs using the GMP module become simply
+
+	perl sample.pl
+
+And the documentation read directly too
+
+	man GMP
diff --git a/third_party/gmp/demos/perl/Makefile.PL b/third_party/gmp/demos/perl/Makefile.PL
new file mode 100644
index 0000000..a676710
--- /dev/null
+++ b/third_party/gmp/demos/perl/Makefile.PL
@@ -0,0 +1,82 @@
+# Makefile for GMP perl module.
+
+# Copyright 2001, 2003, 2004 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+
+# Bugs:
+#
+# When the generated Makefile re-runs "perl Makefile.PL" the GMP_BUILDDIR
+# parameter is lost.
+
+
+use ExtUtils::MakeMaker;
+
+
+# Find and remove our parameters
+@ARGV = map {
+  if (/^GMP_BUILDDIR=(.*)/) {
+    $GMP_BUILDDIR=$1; ();
+  } else {
+    $_;
+  }
+} (@ARGV);
+
+$INC = "";
+$LIBS = "-lgmp";
+$OBJECT = "GMP.o";
+
+if (defined $GMP_BUILDDIR) {
+  if (! -f "$GMP_BUILDDIR/libgmp.la") {
+    die "$GMP_BUILDDIR doesn't contain libgmp.la\n" .
+	"if it's really a gmp build directory then go there and run \"make libgmp.la\"\n";
+  }
+  $INC = "-I$GMP_BUILDDIR $INC";
+  $LIBS = "-L$GMP_BUILDDIR/.libs $LIBS";
+}
+
+WriteMakefile(
+	      NAME         => 'GMP',
+	      VERSION      => '2.00',
+	      LIBS         => [$LIBS],
+	      OBJECT       => $OBJECT,
+	      INC          => $INC,
+	      clean        => { FILES => 'test.tmp' },
+	      PM => {
+		'GMP.pm'      => '$(INST_LIBDIR)/GMP.pm',
+		'GMP/Mpz.pm'  => '$(INST_LIBDIR)/GMP/Mpz.pm',
+		'GMP/Mpq.pm'  => '$(INST_LIBDIR)/GMP/Mpq.pm',
+		'GMP/Mpf.pm'  => '$(INST_LIBDIR)/GMP/Mpf.pm',
+		'GMP/Rand.pm' => '$(INST_LIBDIR)/GMP/Rand.pm',
+	      }
+	      );
+
+
+# Local variables:
+# perl-indent-level: 2
+# End:
diff --git a/third_party/gmp/demos/perl/sample.pl b/third_party/gmp/demos/perl/sample.pl
new file mode 100644
index 0000000..8a10ee1
--- /dev/null
+++ b/third_party/gmp/demos/perl/sample.pl
@@ -0,0 +1,54 @@
+#!/usr/bin/perl -w
+
+# Some sample GMP module operations
+
+# Copyright 2001, 2004 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+use strict;
+
+
+use GMP;
+print "using GMP module $GMP::VERSION and GMP library ",GMP::version(),"\n";
+
+
+use GMP::Mpz qw(:all);
+print "the 200th fibonacci number is ", fib(200), "\n";
+print "next prime after 10**30 is (probably) ", nextprime(mpz(10)**30), "\n";
+
+
+use GMP::Mpq qw(:constants);
+print "the 7th harmonic number is ", 1+1/2+1/3+1/4+1/5+1/6+1/7, "\n";
+use GMP::Mpq qw(:noconstants);
+
+
+use GMP::Mpf qw(mpf);
+my $f = mpf(1,180);
+$f >>= 180;
+$f += 1;
+print "a sample mpf is $f\n";
diff --git a/third_party/gmp/demos/perl/test.pl b/third_party/gmp/demos/perl/test.pl
new file mode 100644
index 0000000..2b54089
--- /dev/null
+++ b/third_party/gmp/demos/perl/test.pl
@@ -0,0 +1,2179 @@
+#!/usr/bin/perl -w
+
+# GMP perl module tests
+
+# Copyright 2001-2003 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+
+# These tests aim to exercise the many possible combinations of operands
+# etc, and to run all functions at least once, which if nothing else will
+# check everything intended is in the :all list.
+#
+# Use the following in .emacs to match test failure messages.
+#
+# ;; perl "Test" module error messages
+# (eval-after-load "compile"
+#   '(add-to-list
+#     'compilation-error-regexp-alist
+#     '("^.*Failed test [0-9]+ in \\([^ ]+\\) at line \\([0-9]+\\)" 1 2)))
+
+
+use strict;
+use Test;
+
+BEGIN {
+  plan tests => 123,
+  onfail => sub { print "there were failures\n" },
+}
+
+use GMP qw(:all);
+use GMP::Mpz qw(:all);
+use GMP::Mpq qw(:all);
+use GMP::Mpf qw(:all);
+use GMP::Rand qw(:all);
+
+use GMP::Mpz qw(:constants);
+use GMP::Mpz qw(:noconstants);
+use GMP::Mpq qw(:constants);
+use GMP::Mpq qw(:noconstants);
+use GMP::Mpf qw(:constants);
+use GMP::Mpf qw(:noconstants);
+
+package Mytie;
+use Exporter;
+use vars  qw($val $fetched $stored);
+$val = 0;
+$fetched = 0;
+$stored = 0;
+sub TIESCALAR {
+  my ($class, $newval) = @_;
+  my $var = 'mytie dummy refed var';
+  $val = $newval;
+  $fetched = 0;
+  $stored = 0;
+  return bless \$var, $class;
+}
+sub FETCH {
+  my ($self) = @_;
+  $fetched++;
+  return $val;
+}
+sub STORE {
+  my ($self, $newval) = @_;
+  $val = $newval;
+  $stored++;
+}
+package main;
+
+# check Mytie does what it should
+{ tie my $t, 'Mytie', 123;
+  ok ($Mytie::val == 123);
+  $Mytie::val = 456;
+  ok ($t == 456);
+  $t = 789;
+  ok ($Mytie::val == 789);
+}
+
+
+# Usage: str(x)
+# Return x forced to a string, not a PVIV.
+#
+sub str {
+  my $s = "$_[0]" . "";
+  return $s;
+}
+
+my $ivnv_2p128 = 65536.0 * 65536.0 * 65536.0 * 65536.0
+               * 65536.0 * 65536.0 * 65536.0 * 65536.0;
+kill (0, $ivnv_2p128);
+my $str_2p128 = '340282366920938463463374607431768211456';
+
+my $uv_max = ~ 0;
+my $uv_max_str = ~ 0;
+$uv_max_str = "$uv_max_str";
+$uv_max_str = "" . "$uv_max_str";
+
+
+#------------------------------------------------------------------------------
+# GMP::version
+
+use GMP qw(version);
+print '$GMP::VERSION ',$GMP::VERSION,' GMP::version() ',version(),"\n";
+
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::new
+
+ok (mpz(0) == 0);
+ok (mpz('0') == 0);
+ok (mpz(substr('101',1,1)) == 0);
+ok (mpz(0.0) == 0);
+ok (mpz(mpz(0)) == 0);
+ok (mpz(mpq(0)) == 0);
+ok (mpz(mpf(0)) == 0);
+
+{ tie my $t, 'Mytie', 0;
+  ok (mpz($t) == 0);
+  ok ($Mytie::fetched > 0);
+}
+{ tie my $t, 'Mytie', '0';
+  ok (mpz($t) == 0);
+  ok ($Mytie::fetched > 0);
+}
+{ tie my $t, 'Mytie', substr('101',1,1); ok (mpz($t) == 0); }
+{ tie my $t, 'Mytie', 0.0; ok (mpz($t) == 0); }
+{ tie my $t, 'Mytie', mpz(0); ok (mpz($t) == 0); }
+{ tie my $t, 'Mytie', mpq(0); ok (mpz($t) == 0); }
+{ tie my $t, 'Mytie', mpf(0); ok (mpz($t) == 0); }
+
+ok (mpz(-123) == -123);
+ok (mpz('-123') == -123);
+ok (mpz(substr('1-1231',1,4)) == -123);
+ok (mpz(-123.0) == -123);
+ok (mpz(mpz(-123)) == -123);
+ok (mpz(mpq(-123)) == -123);
+ok (mpz(mpf(-123)) == -123);
+
+{ tie my $t, 'Mytie', -123; ok (mpz($t) == -123); }
+{ tie my $t, 'Mytie', '-123'; ok (mpz($t) == -123); }
+{ tie my $t, 'Mytie', substr('1-1231',1,4); ok (mpz($t) == -123); }
+{ tie my $t, 'Mytie', -123.0; ok (mpz($t) == -123); }
+{ tie my $t, 'Mytie', mpz(-123); ok (mpz($t) == -123); }
+{ tie my $t, 'Mytie', mpq(-123); ok (mpz($t) == -123); }
+{ tie my $t, 'Mytie', mpf(-123); ok (mpz($t) == -123); }
+
+ok (mpz($ivnv_2p128) == $str_2p128);
+{ tie my $t, 'Mytie', $ivnv_2p128; ok (mpz($t) == $str_2p128); }
+
+ok (mpz($uv_max) > 0);
+ok (mpz($uv_max) == mpz($uv_max_str));
+{ tie my $t, 'Mytie', $uv_max; ok (mpz($t) > 0); }
+{ tie my $t, 'Mytie', $uv_max; ok (mpz($t) == mpz($uv_max_str)); }
+
+{ my $s = '999999999999999999999999999999';
+  kill (0, $s);
+  ok (mpz($s) == '999999999999999999999999999999');
+  tie my $t, 'Mytie', $s;
+  ok (mpz($t) == '999999999999999999999999999999');
+}
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_abs
+
+ok (abs(mpz(0)) == 0);
+ok (abs(mpz(123)) == 123);
+ok (abs(mpz(-123)) == 123);
+
+{ my $x = mpz(-123); $x = abs($x); ok ($x == 123); }
+{ my $x = mpz(0);    $x = abs($x); ok ($x == 0);   }
+{ my $x = mpz(123);  $x = abs($x); ok ($x == 123); }
+
+{ tie my $t, 'Mytie', mpz(0); ok (abs($t) == 0); }
+{ tie my $t, 'Mytie', mpz(123); ok (abs($t) == 123); }
+{ tie my $t, 'Mytie', mpz(-123); ok (abs($t) == 123); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_add
+
+ok (mpz(0) + 1 == 1);
+ok (mpz(-1) + 1 == 0);
+ok (1 + mpz(0) == 1);
+ok (1 + mpz(-1) == 0);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_addeq
+
+{ my $a = mpz(7); $a += 1; ok ($a == 8); }
+{ my $a = mpz(7); my $b = $a; $a += 1; ok ($a == 8); ok ($b == 7); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_and
+
+ok ((mpz(3) & 1) == 1);
+ok ((mpz(3) & 4) == 0);
+
+{ my $a = mpz(3); $a &= 1; ok ($a == 1); }
+{ my $a = mpz(3); $a &= 4; ok ($a == 0); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_bool
+
+if (mpz(0))   { ok (0); } else { ok (1); }
+if (mpz(123)) { ok (1); } else { ok (0); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_com
+
+ok (~ mpz(0) == -1);
+ok (~ mpz(1) == -2);
+ok (~ mpz(-2) == 1);
+ok (~ mpz(0xFF) == -0x100);
+ok (~ mpz(-0x100) == 0xFF);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_dec
+
+{ my $a = mpz(0); ok ($a-- == 0); ok ($a == -1); }
+{ my $a = mpz(0); ok (--$a == -1); }
+
+{ my $a = mpz(0); my $b = $a; $a--; ok ($a == -1); ok ($b == 0); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_div
+
+ok (mpz(6) / 2 == 3);
+ok (mpz(-6) / 2 == -3);
+ok (mpz(6) / -2 == -3);
+ok (mpz(-6) / -2 == 3);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_diveq
+
+{ my $a = mpz(21); $a /= 3; ok ($a == 7); }
+{ my $a = mpz(21); my $b = $a; $a /= 3; ok ($a == 7); ok ($b == 21); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_eq
+
+{ my $a = mpz(0);
+  my $b = $a;
+  $a = mpz(1);
+  ok ($a == 1);
+  ok ($b == 0); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_inc
+
+{ my $a = mpz(0); ok ($a++ == 0); ok ($a == 1); }
+{ my $a = mpz(0); ok (++$a == 1); }
+
+{ my $a = mpz(0); my $b = $a; $a++; ok ($a == 1); ok ($b == 0); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_ior
+
+ok ((mpz(3) | 1) == 3);
+ok ((mpz(3) | 4) == 7);
+
+{ my $a = mpz(3); $a |= 1; ok ($a == 3); }
+{ my $a = mpz(3); $a |= 4; ok ($a == 7); }
+
+ok ((mpz("0xAA") | mpz("0x55")) == mpz("0xFF"));
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_lshift
+
+{ my $a = mpz(7) << 1; ok ($a == 14); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_lshifteq
+
+{ my $a = mpz(7); $a <<= 1; ok ($a == 14); }
+{ my $a = mpz(7); my $b = $a; $a <<= 1; ok ($a == 14); ok ($b == 7); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_mul
+
+ok (mpz(2) * 3 == 6);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_muleq
+
+{ my $a = mpz(7); $a *= 3;  ok ($a == 21); }
+{ my $a = mpz(7); my $b = $a; $a *= 3;  ok ($a == 21); ok ($b == 7); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_neg
+
+ok (- mpz(0) == 0);
+ok (- mpz(123) == -123);
+ok (- mpz(-123) == 123);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_not
+
+if (not mpz(0))   { ok (1); } else { ok (0); }
+if (not mpz(123)) { ok (0); } else { ok (1); }
+
+ok ((! mpz(0)) == 1);
+ok ((! mpz(123)) == 0);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_pow
+
+ok (mpz(0) ** 1 == 0);
+ok (mpz(1) ** 1 == 1);
+ok (mpz(2) ** 0 == 1);
+ok (mpz(2) ** 1 == 2);
+ok (mpz(2) ** 2 == 4);
+ok (mpz(2) ** 3 == 8);
+ok (mpz(2) ** 4 == 16);
+
+ok (mpz(0) ** mpz(1) == 0);
+ok (mpz(1) ** mpz(1) == 1);
+ok (mpz(2) ** mpz(0) == 1);
+ok (mpz(2) ** mpz(1) == 2);
+ok (mpz(2) ** mpz(2) == 4);
+ok (mpz(2) ** mpz(3) == 8);
+ok (mpz(2) ** mpz(4) == 16);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_poweq
+
+{ my $a = mpz(3); $a **= 4; ok ($a == 81); }
+{ my $a = mpz(3); my $b = $a; $a **= 4; ok ($a == 81); ok ($b == 3); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_rem
+
+ok (mpz(-8) % 3 == -2);
+ok (mpz(-7) % 3 == -1);
+ok (mpz(-6) % 3 == 0);
+ok (mpz(6) % 3 == 0);
+ok (mpz(7) % 3 == 1);
+ok (mpz(8) % 3 == 2);
+
+{ my $a = mpz(24); $a %= 7; ok ($a == 3); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_rshift
+
+{ my $a = mpz(32) >> 1; ok ($a == 16); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_rshifteq
+
+{ my $a = mpz(32); $a >>= 1; ok ($a == 16); }
+{ my $a = mpz(32); my $b = $a; $a >>= 1; ok ($a == 16); ok ($b == 32); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_spaceship
+
+ok (mpz(0) < 1);
+ok (mpz(0) > -1);
+
+ok (mpz(0) != 1);
+ok (mpz(0) != -1);
+ok (mpz(1) != 0);
+ok (mpz(1) != -1);
+ok (mpz(-1) != 0);
+ok (mpz(-1) != 1);
+
+ok (mpz(0) < 1.0);
+ok (mpz(0) < '1');
+ok (mpz(0) < substr('-1',1,1));
+ok (mpz(0) < mpz(1));
+ok (mpz(0) < mpq(1));
+ok (mpz(0) < mpf(1));
+ok (mpz(0) < $uv_max);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_sqrt
+
+ok (sqrt(mpz(0)) == 0);
+ok (sqrt(mpz(1)) == 1);
+ok (sqrt(mpz(4)) == 2);
+ok (sqrt(mpz(81)) == 9);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_string
+
+{ my $x = mpz(0);    ok("$x" eq "0"); }
+{ my $x = mpz(123);  ok("$x" eq "123"); }
+{ my $x = mpz(-123); ok("$x" eq "-123"); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_sub
+
+ok (mpz(0) - 1 == -1);
+ok (mpz(1) - 1 == 0);
+ok (1 - mpz(0) == 1);
+ok (1 - mpz(1) == 0);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_subeq
+
+{ my $a = mpz(7); $a -= 1; ok ($a == 6); }
+{ my $a = mpz(7); my $b = $a; $a -= 1; ok ($a == 6); ok ($b == 7); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::overload_xor
+
+ok ((mpz(3) ^ 1) == 2);
+ok ((mpz(3) ^ 4) == 7);
+
+{ my $a = mpz(3); $a ^= 1; ok ($a == 2); }
+{ my $a = mpz(3); $a ^= 4; ok ($a == 7); }
+
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::bin
+
+ok (bin(2,0) == 1);
+ok (bin(2,1) == 2);
+ok (bin(2,2) == 1);
+
+ok (bin(3,0) == 1);
+ok (bin(3,1) == 3);
+ok (bin(3,2) == 3);
+ok (bin(3,3) == 1);
+
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::cdiv
+
+{ my ($q, $r);
+  ($q, $r) = cdiv (16, 3);
+  ok ($q == 6);
+  ok ($r == -2);
+  ($q, $r) = cdiv (16, -3);
+  ok ($q == -5);
+  ok ($r == 1);
+  ($q, $r) = cdiv (-16, 3);
+  ok ($q == -5);
+  ok ($r == -1);
+  ($q, $r) = cdiv (-16, -3);
+  ok ($q == 6);
+  ok ($r == 2);
+}
+
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::cdiv_2exp
+
+{ my ($q, $r);
+  ($q, $r) = cdiv_2exp (23, 2);
+  ok ($q == 6);
+  ok ($r == -1);
+  ($q, $r) = cdiv_2exp (-23, 2);
+  ok ($q == -5);
+  ok ($r == -3);
+}
+
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::clrbit
+
+{ my $a = mpz(3); clrbit ($a, 1); ok ($a == 1);
+  ok (UNIVERSAL::isa($a,"GMP::Mpz")); }
+{ my $a = mpz(3); clrbit ($a, 2); ok ($a == 3);
+  ok (UNIVERSAL::isa($a,"GMP::Mpz")); }
+
+{ my $a = 3; clrbit ($a, 1); ok ($a == 1);
+  ok (UNIVERSAL::isa($a,"GMP::Mpz")); }
+{ my $a = 3; clrbit ($a, 2); ok ($a == 3);
+  ok (UNIVERSAL::isa($a,"GMP::Mpz")); }
+
+# mutate only given variable
+{ my $a = mpz(3);
+  my $b = $a;
+  clrbit ($a, 0);
+  ok ($a == 2);
+  ok ($b == 3);
+}
+{ my $a = 3;
+  my $b = $a;
+  clrbit ($a, 0);
+  ok ($a == 2);
+  ok ($b == 3);
+}
+
+{ tie my $a, 'Mytie', mpz(3);
+  clrbit ($a, 1);
+  ok ($Mytie::fetched > 0);    # used fetch
+  ok ($Mytie::stored > 0);     # used store
+  ok ($a == 1);                # expected result
+  ok (UNIVERSAL::isa($a,"GMP::Mpz"));
+  ok (tied($a));               # still tied
+}
+{ tie my $a, 'Mytie', 3;
+  clrbit ($a, 1);
+  ok ($Mytie::fetched > 0);    # used fetch
+  ok ($Mytie::stored > 0);     # used store
+  ok ($a == 1);                # expected result
+  ok (UNIVERSAL::isa($a,"GMP::Mpz"));
+  ok (tied($a));               # still tied
+}
+
+{ my $b = mpz(3);
+  tie my $a, 'Mytie', $b;
+  clrbit ($a, 0);
+  ok ($a == 2);
+  ok ($b == 3);
+  ok (tied($a));
+}
+{ my $b = 3;
+  tie my $a, 'Mytie', $b;
+  clrbit ($a, 0);
+  ok ($a == 2);
+  ok ($b == 3);
+  ok (tied($a));
+}
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::combit
+
+{ my $a = mpz(3); combit ($a, 1); ok ($a == 1);
+  ok (UNIVERSAL::isa($a,"GMP::Mpz")); }
+{ my $a = mpz(3); combit ($a, 2); ok ($a == 7);
+  ok (UNIVERSAL::isa($a,"GMP::Mpz")); }
+
+{ my $a = 3; combit ($a, 1); ok ($a == 1);
+  ok (UNIVERSAL::isa($a,"GMP::Mpz")); }
+{ my $a = 3; combit ($a, 2); ok ($a == 7);
+  ok (UNIVERSAL::isa($a,"GMP::Mpz")); }
+
+# mutate only given variable
+{ my $a = mpz(3);
+  my $b = $a;
+  combit ($a, 0);
+  ok ($a == 2);
+  ok ($b == 3);
+}
+{ my $a = 3;
+  my $b = $a;
+  combit ($a, 0);
+  ok ($a == 2);
+  ok ($b == 3);
+}
+
+{ tie my $a, 'Mytie', mpz(3);
+  combit ($a, 2);
+  ok ($Mytie::fetched > 0);    # used fetch
+  ok ($Mytie::stored > 0);     # used store
+  ok ($a == 7);                # expected result
+  ok (UNIVERSAL::isa($a,"GMP::Mpz"));
+  ok (tied($a));               # still tied
+}
+{ tie my $a, 'Mytie', 3;
+  combit ($a, 2);
+  ok ($Mytie::fetched > 0);    # used fetch
+  ok ($Mytie::stored > 0);     # used store
+  ok ($a == 7);                # expected result
+  ok (UNIVERSAL::isa($a,"GMP::Mpz"));
+  ok (tied($a));               # still tied
+}
+
+{ my $b = mpz(3);
+  tie my $a, 'Mytie', $b;
+  combit ($a, 0);
+  ok ($a == 2);
+  ok ($b == 3);
+  ok (tied($a));
+}
+{ my $b = 3;
+  tie my $a, 'Mytie', $b;
+  combit ($a, 0);
+  ok ($a == 2);
+  ok ($b == 3);
+  ok (tied($a));
+}
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::congruent_p
+
+ok (  congruent_p (21, 0, 7));
+ok (! congruent_p (21, 1, 7));
+ok (  congruent_p (21, 5, 8));
+ok (! congruent_p (21, 6, 8));
+
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::congruent_2exp_p
+
+ok (  congruent_2exp_p (20, 0, 2));
+ok (! congruent_2exp_p (21, 0, 2));
+ok (! congruent_2exp_p (20, 1, 2));
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::divexact
+
+ok (divexact(27,3) == 9);
+ok (divexact(27,-3) == -9);
+ok (divexact(-27,3) == -9);
+ok (divexact(-27,-3) == 9);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::divisible_p
+
+ok (  divisible_p (21, 7));
+ok (! divisible_p (21, 8));
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::divisible_2exp_p
+
+ok (  divisible_2exp_p (20, 2));
+ok (! divisible_2exp_p (21, 2));
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::even_p
+
+ok (! even_p(mpz(-3)));
+ok (  even_p(mpz(-2)));
+ok (! even_p(mpz(-1)));
+ok (  even_p(mpz(0)));
+ok (! even_p(mpz(1)));
+ok (  even_p(mpz(2)));
+ok (! even_p(mpz(3)));
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::export
+
+{ my $s = mpz_export (1, 2, 1, 0, "0x61626364");
+  ok ($s eq 'abcd'); }
+{ my $s = mpz_export (-1, 2, 1, 0, "0x61626364");
+  ok ($s eq 'cdab'); }
+{ my $s = mpz_export (1, 2, -1, 0, "0x61626364");
+  ok ($s eq 'badc'); }
+{ my $s = mpz_export (-1, 2, -1, 0, "0x61626364");
+  ok ($s eq 'dcba'); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::fac
+
+ok (fac(0) == 1);
+ok (fac(1) == 1);
+ok (fac(2) == 2);
+ok (fac(3) == 6);
+ok (fac(4) == 24);
+ok (fac(5) == 120);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::fdiv
+
+{ my ($q, $r);
+  ($q, $r) = fdiv (16, 3);
+  ok ($q == 5);
+  ok ($r == 1);
+  ($q, $r) = fdiv (16, -3);
+  ok ($q == -6);
+  ok ($r == -2);
+  ($q, $r) = fdiv (-16, 3);
+  ok ($q == -6);
+  ok ($r == 2);
+  ($q, $r) = fdiv (-16, -3);
+  ok ($q == 5);
+  ok ($r == -1);
+}
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::fdiv_2exp
+
+{ my ($q, $r);
+  ($q, $r) = fdiv_2exp (23, 2);
+  ok ($q == 5);
+  ok ($r == 3);
+  ($q, $r) = fdiv_2exp (-23, 2);
+  ok ($q == -6);
+  ok ($r == 1);
+}
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::fib
+
+ok (fib(0) == 0);
+ok (fib(1) == 1);
+ok (fib(2) == 1);
+ok (fib(3) == 2);
+ok (fib(4) == 3);
+ok (fib(5) == 5);
+ok (fib(6) == 8);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::fib2
+
+{ my ($a, $b) = fib2(0); ok($a==0); ok($b==1); }
+{ my ($a, $b) = fib2(1); ok($a==1); ok($b==0); }
+{ my ($a, $b) = fib2(2); ok($a==1); ok($b==1); }
+{ my ($a, $b) = fib2(3); ok($a==2); ok($b==1); }
+{ my ($a, $b) = fib2(4); ok($a==3); ok($b==2); }
+{ my ($a, $b) = fib2(5); ok($a==5); ok($b==3); }
+{ my ($a, $b) = fib2(6); ok($a==8); ok($b==5); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::gcd
+
+ok (gcd (21) == 21);
+ok (gcd (21,15) == 3);
+ok (gcd (21,15,30,57) == 3);
+ok (gcd (21,-15) == 3);
+ok (gcd (-21,15) == 3);
+ok (gcd (-21,-15) == 3);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::gcdext
+
+{
+  my ($g, $x, $y) = gcdext (3,5);
+  ok ($g == 1);
+  ok ($x == 2);
+  ok ($y == -1);
+}
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::hamdist
+
+ok (hamdist(5,7) == 1);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::import
+
+{ my $z = mpz_import (1, 2, 1, 0, 'abcd');
+  ok ($z == 0x61626364); }
+{ my $z = mpz_import (-1, 2, 1, 0, 'abcd');
+  ok ($z == 0x63646162); }
+{ my $z = mpz_import (1, 2, -1, 0, 'abcd');
+  ok ($z == 0x62616463); }
+{ my $z = mpz_import (-1, 2, -1, 0, 'abcd');
+  ok ($z == 0x64636261); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::invert
+
+ok (invert(1,123) == 1);
+ok (invert(6,7) == 6);
+ok (! defined invert(2,8));
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::jacobi, GMP::Mpz::kronecker
+
+foreach my $i ([  1, 19,  1 ],
+	       [  4, 19,  1 ],
+	       [  5, 19,  1 ],
+	       [  6, 19,  1 ],
+	       [  7, 19,  1 ],
+	       [  9, 19,  1 ],
+	       [ 11, 19,  1 ],
+	       [ 16, 19,  1 ],
+	       [ 17, 19,  1 ],
+	       [  2, 19, -1 ],
+	       [  3, 19, -1 ],
+	       [  8, 19, -1 ],
+	       [ 10, 19, -1 ],
+	       [ 12, 19, -1 ],
+	       [ 13, 19, -1 ],
+	       [ 14, 19, -1 ],
+	       [ 15, 19, -1 ],
+	       [ 18, 19, -1 ]) {
+  foreach my $fun (\&jacobi, \&kronecker) {
+    ok (&$fun ($$i[0], $$i[1]) == $$i[2]);
+
+    ok (&$fun ($$i[0],      str($$i[1])) == $$i[2]);
+    ok (&$fun (str($$i[0]),     $$i[1])  == $$i[2]);
+    ok (&$fun (str($$i[0]), str($$i[1])) == $$i[2]);
+
+    ok (&$fun ($$i[0],      mpz($$i[1])) == $$i[2]);
+    ok (&$fun (mpz($$i[0]), $$i[1]) == $$i[2]);
+    ok (&$fun (mpz($$i[0]), mpz($$i[1])) == $$i[2]);
+  }
+}
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::lcm
+
+ok (lcm (2) == 2);
+ok (lcm (0) == 0);
+ok (lcm (0,0) == 0);
+ok (lcm (0,0,0) == 0);
+ok (lcm (0,0,0,0) == 0);
+ok (lcm (2,0) == 0);
+ok (lcm (-2,0) == 0);
+ok (lcm (2,3) == 6);
+ok (lcm (2,3,4) == 12);
+ok (lcm (2,-3) == 6);
+ok (lcm (-2,3) == 6);
+ok (lcm (-2,-3) == 6);
+ok (lcm (mpz(2)**512,1) == mpz(2)**512);
+ok (lcm (mpz(2)**512,-1) == mpz(2)**512);
+ok (lcm (-mpz(2)**512,1) == mpz(2)**512);
+ok (lcm (-mpz(2)**512,-1) == mpz(2)**512);
+ok (lcm (mpz(2)**512,mpz(2)**512) == mpz(2)**512);
+ok (lcm (mpz(2)**512,-mpz(2)**512) == mpz(2)**512);
+ok (lcm (-mpz(2)**512,mpz(2)**512) == mpz(2)**512);
+ok (lcm (-mpz(2)**512,-mpz(2)**512) == mpz(2)**512);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::lucnum
+
+ok (lucnum(0) == 2);
+ok (lucnum(1) == 1);
+ok (lucnum(2) == 3);
+ok (lucnum(3) == 4);
+ok (lucnum(4) == 7);
+ok (lucnum(5) == 11);
+ok (lucnum(6) == 18);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::lucnum2
+
+{ my ($a, $b) = lucnum2(0); ok($a==2);  ok($b==-1); }
+{ my ($a, $b) = lucnum2(1); ok($a==1);  ok($b==2); }
+{ my ($a, $b) = lucnum2(2); ok($a==3);  ok($b==1); }
+{ my ($a, $b) = lucnum2(3); ok($a==4);  ok($b==3); }
+{ my ($a, $b) = lucnum2(4); ok($a==7);  ok($b==4); }
+{ my ($a, $b) = lucnum2(5); ok($a==11); ok($b==7); }
+{ my ($a, $b) = lucnum2(6); ok($a==18); ok($b==11); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::nextprime
+
+ok (nextprime(2) == 3);
+ok (nextprime(3) == 5);
+ok (nextprime(5) == 7);
+ok (nextprime(7) == 11);
+ok (nextprime(11) == 13);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::perfect_power_p
+
+# ok (  perfect_power_p(mpz(-27)));
+# ok (! perfect_power_p(mpz(-9)));
+# ok (! perfect_power_p(mpz(-1)));
+ok (  perfect_power_p(mpz(0)));
+ok (  perfect_power_p(mpz(1)));
+ok (! perfect_power_p(mpz(2)));
+ok (! perfect_power_p(mpz(3)));
+ok (  perfect_power_p(mpz(4)));
+ok (  perfect_power_p(mpz(9)));
+ok (  perfect_power_p(mpz(27)));
+ok (  perfect_power_p(mpz(81)));
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::perfect_square_p
+
+ok (! perfect_square_p(mpz(-9)));
+ok (! perfect_square_p(mpz(-1)));
+ok (  perfect_square_p(mpz(0)));
+ok (  perfect_square_p(mpz(1)));
+ok (! perfect_square_p(mpz(2)));
+ok (! perfect_square_p(mpz(3)));
+ok (  perfect_square_p(mpz(4)));
+ok (  perfect_square_p(mpz(9)));
+ok (! perfect_square_p(mpz(27)));
+ok (  perfect_square_p(mpz(81)));
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::popcount
+
+ok (popcount(7) == 3);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::powm
+
+ok (powm (3,2,8) == 1);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::probab_prime_p
+
+ok (  probab_prime_p(89,1));
+ok (! probab_prime_p(81,1));
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::realloc
+
+{ my $z = mpz(123);
+  realloc ($z, 512); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::remove
+
+{
+  my ($rem, $mult);
+  ($rem, $mult) = remove(12,3);
+  ok ($rem == 4);
+  ok ($mult == 1);
+  ($rem, $mult) = remove(12,2);
+  ok ($rem == 3);
+  ok ($mult == 2);
+}
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::root
+
+ok (root(0,2) == 0);
+ok (root(8,3) == 2);
+ok (root(-8,3) == -2);
+ok (root(81,4) == 3);
+ok (root(243,5) == 3);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::roote
+
+{ my ($r,$e);
+  ($r, $e) = roote(0,2);
+  ok ($r == 0);
+  ok ($e);
+  ($r, $e) = roote(81,4);
+  ok ($r == 3);
+  ok ($e);
+  ($r, $e) = roote(85,4);
+  ok ($r == 3);
+  ok (! $e);
+}
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::rootrem
+
+{ my ($root, $rem) = rootrem (mpz(0), 1);
+  ok ($root == 0); ok ($rem == 0); }
+{ my ($root, $rem) = rootrem (mpz(0), 2);
+  ok ($root == 0); ok ($rem == 0); }
+{ my ($root, $rem) = rootrem (mpz(64), 2);
+  ok ($root == 8); ok ($rem == 0); }
+{ my ($root, $rem) = rootrem (mpz(64), 3);
+  ok ($root == 4); ok ($rem == 0); }
+{ my ($root, $rem) = rootrem (mpz(65), 3);
+  ok ($root == 4); ok ($rem == 1); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::scan0
+
+ok (scan0 (0, 0) == 0);
+ok (scan0 (1, 0) == 1);
+ok (scan0 (3, 0) == 2);
+ok (scan0 (-1, 0) == ~0);
+ok (scan0 (-2, 1) == ~0);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::scan1
+
+ok (scan1 (1, 0) == 0);
+ok (scan1 (2, 0) == 1);
+ok (scan1 (4, 0) == 2);
+ok (scan1 (0, 0) == ~0);
+ok (scan1 (3, 2) == ~0);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::setbit
+
+{ my $a = mpz(3); setbit ($a, 1); ok ($a == 3); }
+{ my $a = mpz(3); setbit ($a, 2); ok ($a == 7); }
+
+{ my $a = 3; setbit ($a, 1); ok ($a == 3); }
+{ my $a = 3; setbit ($a, 2); ok ($a == 7); }
+
+# mutate only given variable
+{ my $a = mpz(0);
+  my $b = $a;
+  setbit ($a, 0);
+  ok ($a == 1);
+  ok ($b == 0);
+}
+{ my $a = 0;
+  my $b = $a;
+  setbit ($a, 0);
+  ok ($a == 1);
+  ok ($b == 0);
+}
+
+{ tie my $a, 'Mytie', mpz(3);
+  setbit ($a, 2);
+  ok ($Mytie::fetched > 0);    # used fetch
+  ok ($Mytie::stored > 0);     # used store
+  ok ($a == 7);                # expected result
+  ok (UNIVERSAL::isa($a,"GMP::Mpz"));
+  ok (tied($a));               # still tied
+}
+{ tie my $a, 'Mytie', 3;
+  setbit ($a, 2);
+  ok ($Mytie::fetched > 0);    # used fetch
+  ok ($Mytie::stored > 0);     # used store
+  ok ($a == 7);                # expected result
+  ok (UNIVERSAL::isa($a,"GMP::Mpz"));
+  ok (tied($a));               # still tied
+}
+
+{ my $b = mpz(2);
+  tie my $a, 'Mytie', $b;
+  setbit ($a, 0);
+  ok ($a == 3);
+  ok ($b == 2);
+  ok (tied($a));
+}
+{ my $b = 2;
+  tie my $a, 'Mytie', $b;
+  setbit ($a, 0);
+  ok ($a == 3);
+  ok ($b == 2);
+  ok (tied($a));
+}
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::sizeinbase
+
+ok (sizeinbase(1,10) == 1);
+ok (sizeinbase(100,10) == 3);
+ok (sizeinbase(9999,10) == 5);
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::sqrtrem
+
+{
+  my ($root, $rem) = sqrtrem(mpz(0));
+  ok ($root == 0);
+  ok ($rem == 0);
+}
+{
+  my ($root, $rem) = sqrtrem(mpz(1));
+  ok ($root == 1);
+  ok ($rem == 0);
+}
+{
+  my ($root, $rem) = sqrtrem(mpz(2));
+  ok ($root == 1);
+  ok ($rem == 1);
+}
+{
+  my ($root, $rem) = sqrtrem(mpz(9));
+  ok ($root == 3);
+  ok ($rem == 0);
+}
+{
+  my ($root, $rem) = sqrtrem(mpz(35));
+  ok ($root == 5);
+  ok ($rem == 10);
+}
+{
+  my ($root, $rem) = sqrtrem(mpz(0));
+  ok ($root == 0);
+  ok ($rem == 0);
+}
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::tdiv
+
+{ my ($q, $r);
+  ($q, $r) = tdiv (16, 3);
+  ok ($q == 5);
+  ok ($r == 1);
+  ($q, $r) = tdiv (16, -3);
+  ok ($q == -5);
+  ok ($r == 1);
+  ($q, $r) = tdiv (-16, 3);
+  ok ($q == -5);
+  ok ($r == -1);
+  ($q, $r) = tdiv (-16, -3);
+  ok ($q == 5);
+  ok ($r == -1);
+}
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::tdiv_2exp
+
+{ my ($q, $r);
+  ($q, $r) = tdiv_2exp (23, 2);
+  ok ($q == 5);
+  ok ($r == 3);
+  ($q, $r) = tdiv_2exp (-23, 2);
+  ok ($q == -5);
+  ok ($r == -3);
+}
+
+#------------------------------------------------------------------------------
+# GMP::Mpz::tstbit
+
+ok (tstbit (6, 0) == 0);
+ok (tstbit (6, 1) == 1);
+ok (tstbit (6, 2) == 1);
+ok (tstbit (6, 3) == 0);
+
+
+
+
+#------------------------------------------------------------------------------
+# GMP::Mpq
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::new
+
+ok (mpq(0) == 0);
+ok (mpq('0') == 0);
+ok (mpq(substr('101',1,1)) == 0);
+ok (mpq(0.0) == 0);
+ok (mpq(mpz(0)) == 0);
+ok (mpq(mpq(0)) == 0);
+ok (mpq(mpf(0)) == 0);
+
+{ tie my $t, 'Mytie', 0; ok (mpq($t) == 0); }
+{ tie my $t, 'Mytie', '0'; ok (mpq($t) == 0); }
+{ tie my $t, 'Mytie', substr('101',1,1); ok (mpq($t) == 0); }
+{ tie my $t, 'Mytie', 0.0; ok (mpq($t) == 0); }
+{ tie my $t, 'Mytie', mpz(0); ok (mpq($t) == 0); }
+{ tie my $t, 'Mytie', mpq(0); ok (mpq($t) == 0); }
+{ tie my $t, 'Mytie', mpf(0); ok (mpq($t) == 0); }
+
+ok (mpq(-123) == -123);
+ok (mpq('-123') == -123);
+ok (mpq(substr('1-1231',1,4)) == -123);
+ok (mpq(-123.0) == -123);
+ok (mpq(mpz(-123)) == -123);
+ok (mpq(mpq(-123)) == -123);
+ok (mpq(mpf(-123)) == -123);
+
+{ tie my $t, 'Mytie', -123; ok (mpq($t) == -123); }
+{ tie my $t, 'Mytie', '-123'; ok (mpq($t) == -123); }
+{ tie my $t, 'Mytie', substr('1-1231',1,4); ok (mpq($t) == -123); }
+{ tie my $t, 'Mytie', -123.0; ok (mpq($t) == -123); }
+{ tie my $t, 'Mytie', mpz(-123); ok (mpq($t) == -123); }
+{ tie my $t, 'Mytie', mpq(-123); ok (mpq($t) == -123); }
+{ tie my $t, 'Mytie', mpf(-123); ok (mpq($t) == -123); }
+
+ok (mpq($ivnv_2p128) == $str_2p128);
+{ tie my $t, 'Mytie', $ivnv_2p128; ok (mpq($t) == $str_2p128); }
+
+ok (mpq('3/2') == mpq(3,2));
+ok (mpq('3/1') == mpq(3,1));
+ok (mpq('-3/2') == mpq(-3,2));
+ok (mpq('-3/1') == mpq(-3,1));
+ok (mpq('0x3') == mpq(3,1));
+ok (mpq('0b111') == mpq(7,1));
+ok (mpq('0b0') == mpq(0,1));
+
+ok (mpq($uv_max) > 0);
+ok (mpq($uv_max) == mpq($uv_max_str));
+{ tie my $t, 'Mytie', $uv_max; ok (mpq($t) > 0); }
+{ tie my $t, 'Mytie', $uv_max; ok (mpq($t) == mpq($uv_max_str)); }
+
+{ my $x = 123.5;
+  kill (0, $x);
+  ok (mpq($x) == 123.5);
+  tie my $t, 'Mytie', $x;
+  ok (mpq($t) == 123.5);
+}
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::overload_abs
+
+ok (abs(mpq(0)) == 0);
+ok (abs(mpq(123)) == 123);
+ok (abs(mpq(-123)) == 123);
+
+{ my $x = mpq(-123); $x = abs($x); ok ($x == 123); }
+{ my $x = mpq(0);    $x = abs($x); ok ($x == 0);   }
+{ my $x = mpq(123);  $x = abs($x); ok ($x == 123); }
+
+{ tie my $t, 'Mytie', mpq(0); ok (abs($t) == 0); }
+{ tie my $t, 'Mytie', mpq(123); ok (abs($t) == 123); }
+{ tie my $t, 'Mytie', mpq(-123); ok (abs($t) == 123); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::overload_add
+
+ok (mpq(0) + 1 == 1);
+ok (mpq(-1) + 1 == 0);
+ok (1 + mpq(0) == 1);
+ok (1 + mpq(-1) == 0);
+
+ok (mpq(1,2)+mpq(1,3) == mpq(5,6));
+ok (mpq(1,2)+mpq(-1,3) == mpq(1,6));
+ok (mpq(-1,2)+mpq(1,3) == mpq(-1,6));
+ok (mpq(-1,2)+mpq(-1,3) == mpq(-5,6));
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::overload_addeq
+
+{ my $a = mpq(7); $a += 1; ok ($a == 8); }
+{ my $a = mpq(7); my $b = $a; $a += 1; ok ($a == 8); ok ($b == 7); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::overload_bool
+
+if (mpq(0))   { ok (0); } else { ok (1); }
+if (mpq(123)) { ok (1); } else { ok (0); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::overload_dec
+
+{ my $a = mpq(0); ok ($a-- == 0); ok ($a == -1); }
+{ my $a = mpq(0); ok (--$a == -1); }
+
+{ my $a = mpq(0); my $b = $a; $a--; ok ($a == -1); ok ($b == 0); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::overload_div
+
+ok (mpq(6) / 2 == 3);
+ok (mpq(-6) / 2 == -3);
+ok (mpq(6) / -2 == -3);
+ok (mpq(-6) / -2 == 3);
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::overload_diveq
+
+{ my $a = mpq(21); $a /= 3; ok ($a == 7); }
+{ my $a = mpq(21); my $b = $a; $a /= 3; ok ($a == 7); ok ($b == 21); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::overload_eq
+
+{ my $a = mpq(0);
+  my $b = $a;
+  $a = mpq(1);
+  ok ($a == 1);
+  ok ($b == 0); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::overload_inc
+
+{ my $a = mpq(0); ok ($a++ == 0); ok ($a == 1); }
+{ my $a = mpq(0); ok (++$a == 1); }
+
+{ my $a = mpq(0); my $b = $a; $a++; ok ($a == 1); ok ($b == 0); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::overload_lshift
+
+{ my $a = mpq(7) << 1; ok ($a == 14); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::overload_lshifteq
+
+{ my $a = mpq(7); $a <<= 1; ok ($a == 14); }
+{ my $a = mpq(7); my $b = $a; $a <<= 1; ok ($a == 14); ok ($b == 7); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::overload_mul
+
+ok (mpq(2) * 3 == 6);
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::overload_muleq
+
+{ my $a = mpq(7); $a *= 3;  ok ($a == 21); }
+{ my $a = mpq(7); my $b = $a; $a *= 3;  ok ($a == 21); ok ($b == 7); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::overload_neg
+
+ok (- mpq(0) == 0);
+ok (- mpq(123) == -123);
+ok (- mpq(-123) == 123);
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::overload_not
+
+if (not mpq(0))   { ok (1); } else { ok (0); }
+if (not mpq(123)) { ok (0); } else { ok (1); }
+
+ok ((! mpq(0)) == 1);
+ok ((! mpq(123)) == 0);
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::overload_pow
+
+ok (mpq(0) ** 1 == 0);
+ok (mpq(1) ** 1 == 1);
+ok (mpq(2) ** 0 == 1);
+ok (mpq(2) ** 1 == 2);
+ok (mpq(2) ** 2 == 4);
+ok (mpq(2) ** 3 == 8);
+ok (mpq(2) ** 4 == 16);
+
+ok (mpq(0) ** mpq(1) == 0);
+ok (mpq(1) ** mpq(1) == 1);
+ok (mpq(2) ** mpq(0) == 1);
+ok (mpq(2) ** mpq(1) == 2);
+ok (mpq(2) ** mpq(2) == 4);
+ok (mpq(2) ** mpq(3) == 8);
+ok (mpq(2) ** mpq(4) == 16);
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::overload_poweq
+
+{ my $a = mpq(3); $a **= 4; ok ($a == 81); }
+{ my $a = mpq(3); my $b = $a; $a **= 4; ok ($a == 81); ok ($b == 3); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::overload_rshift
+
+{ my $a = mpq(32) >> 1; ok ($a == 16); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::overload_rshifteq
+
+{ my $a = mpq(32); $a >>= 1; ok ($a == 16); }
+{ my $a = mpq(32); my $b = $a; $a >>= 1; ok ($a == 16); ok ($b == 32); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::overload_spaceship
+
+ok (mpq(0) < 1);
+ok (mpq(0) > -1);
+
+ok (mpq(0) != 1);
+ok (mpq(0) != -1);
+ok (mpq(1) != 0);
+ok (mpq(1) != -1);
+ok (mpq(-1) != 0);
+ok (mpq(-1) != 1);
+
+ok (mpq(3,2) > 1);
+ok (mpq(3,2) < 2);
+
+ok (mpq(0) < 1.0);
+ok (mpq(0) < '1');
+ok (mpq(0) < substr('-1',1,1));
+ok (mpq(0) < mpz(1));
+ok (mpq(0) < mpq(1));
+ok (mpq(0) < mpf(1));
+ok (mpq(0) < $uv_max);
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::overload_string
+
+{ my $x = mpq(0);    ok("$x" eq "0"); }
+{ my $x = mpq(123);  ok("$x" eq "123"); }
+{ my $x = mpq(-123); ok("$x" eq "-123"); }
+
+{ my $q = mpq(5,7);  ok("$q" eq "5/7"); }
+{ my $q = mpq(-5,7); ok("$q" eq "-5/7"); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::overload_sub
+
+ok (mpq(0) - 1 == -1);
+ok (mpq(1) - 1 == 0);
+ok (1 - mpq(0) == 1);
+ok (1 - mpq(1) == 0);
+
+ok (mpq(1,2)-mpq(1,3) == mpq(1,6));
+ok (mpq(1,2)-mpq(-1,3) == mpq(5,6));
+ok (mpq(-1,2)-mpq(1,3) == mpq(-5,6));
+ok (mpq(-1,2)-mpq(-1,3) == mpq(-1,6));
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::overload_subeq
+
+{ my $a = mpq(7); $a -= 1; ok ($a == 6); }
+{ my $a = mpq(7); my $b = $a; $a -= 1; ok ($a == 6); ok ($b == 7); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::canonicalize
+
+{ my $q = mpq(21,15); canonicalize($q);
+  ok (num($q) == 7);
+  ok (den($q) == 5);
+}
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::den
+
+{ my $q = mpq(5,9); ok (den($q) == 9); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpq::num
+
+{ my $q = mpq(5,9); ok (num($q) == 5); }
+
+
+
+
+#------------------------------------------------------------------------------
+# GMP::Mpf
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::new
+
+ok (mpf(0) == 0);
+ok (mpf('0') == 0);
+ok (mpf(substr('101',1,1)) == 0);
+ok (mpf(0.0) == 0);
+ok (mpf(mpz(0)) == 0);
+ok (mpf(mpq(0)) == 0);
+ok (mpf(mpf(0)) == 0);
+
+{ tie my $t, 'Mytie', 0; ok (mpf($t) == 0); }
+{ tie my $t, 'Mytie', '0'; ok (mpf($t) == 0); }
+{ tie my $t, 'Mytie', substr('101',1,1); ok (mpf($t) == 0); }
+{ tie my $t, 'Mytie', 0.0; ok (mpf($t) == 0); }
+{ tie my $t, 'Mytie', mpz(0); ok (mpf($t) == 0); }
+{ tie my $t, 'Mytie', mpq(0); ok (mpf($t) == 0); }
+{ tie my $t, 'Mytie', mpf(0); ok (mpf($t) == 0); }
+
+ok (mpf(-123) == -123);
+ok (mpf('-123') == -123);
+ok (mpf(substr('1-1231',1,4)) == -123);
+ok (mpf(-123.0) == -123);
+ok (mpf(mpz(-123)) == -123);
+ok (mpf(mpq(-123)) == -123);
+ok (mpf(mpf(-123)) == -123);
+
+{ tie my $t, 'Mytie', -123; ok (mpf($t) == -123); }
+{ tie my $t, 'Mytie', '-123'; ok (mpf($t) == -123); }
+{ tie my $t, 'Mytie', substr('1-1231',1,4); ok (mpf($t) == -123); }
+{ tie my $t, 'Mytie', -123.0; ok (mpf($t) == -123); }
+{ tie my $t, 'Mytie', mpz(-123); ok (mpf($t) == -123); }
+{ tie my $t, 'Mytie', mpq(-123); ok (mpf($t) == -123); }
+{ tie my $t, 'Mytie', mpf(-123); ok (mpf($t) == -123); }
+
+ok (mpf($ivnv_2p128) == $str_2p128);
+{ tie my $t, 'Mytie', $ivnv_2p128; ok (mpf($t) == $str_2p128); }
+
+ok (mpf(-1.5) == -1.5);
+ok (mpf(-1.0) == -1.0);
+ok (mpf(-0.5) == -0.5);
+ok (mpf(0) == 0);
+ok (mpf(0.5) == 0.5);
+ok (mpf(1.0) == 1.0);
+ok (mpf(1.5) == 1.5);
+
+ok (mpf("-1.5") == -1.5);
+ok (mpf("-1.0") == -1.0);
+ok (mpf("-0.5") == -0.5);
+ok (mpf("0") == 0);
+ok (mpf("0.5") == 0.5);
+ok (mpf("1.0") == 1.0);
+ok (mpf("1.5") == 1.5);
+
+ok (mpf($uv_max) > 0);
+ok (mpf($uv_max) == mpf($uv_max_str));
+{ tie my $t, 'Mytie', $uv_max; ok (mpf($t) > 0); }
+{ tie my $t, 'Mytie', $uv_max; ok (mpf($t) == mpf($uv_max_str)); }
+
+{ my $x = 123.5;
+  kill (0, $x);
+  ok (mpf($x) == 123.5);
+  tie my $t, 'Mytie', $x;
+  ok (mpf($t) == 123.5);
+}
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_abs
+
+ok (abs(mpf(0)) == 0);
+ok (abs(mpf(123)) == 123);
+ok (abs(mpf(-123)) == 123);
+
+{ my $x = mpf(-123); $x = abs($x); ok ($x == 123); }
+{ my $x = mpf(0);    $x = abs($x); ok ($x == 0);   }
+{ my $x = mpf(123);  $x = abs($x); ok ($x == 123); }
+
+{ tie my $t, 'Mytie', mpf(0); ok (abs($t) == 0); }
+{ tie my $t, 'Mytie', mpf(123); ok (abs($t) == 123); }
+{ tie my $t, 'Mytie', mpf(-123); ok (abs($t) == 123); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_add
+
+ok (mpf(0) + 1 == 1);
+ok (mpf(-1) + 1 == 0);
+ok (1 + mpf(0) == 1);
+ok (1 + mpf(-1) == 0);
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_addeq
+
+{ my $a = mpf(7); $a += 1; ok ($a == 8); }
+{ my $a = mpf(7); my $b = $a; $a += 1; ok ($a == 8); ok ($b == 7); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_bool
+
+if (mpf(0))   { ok (0); } else { ok (1); }
+if (mpf(123)) { ok (1); } else { ok (0); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_dec
+
+{ my $a = mpf(0); ok ($a-- == 0); ok ($a == -1); }
+{ my $a = mpf(0); ok (--$a == -1); }
+
+{ my $a = mpf(0); my $b = $a; $a--; ok ($a == -1); ok ($b == 0); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_div
+
+ok (mpf(6) / 2 == 3);
+ok (mpf(-6) / 2 == -3);
+ok (mpf(6) / -2 == -3);
+ok (mpf(-6) / -2 == 3);
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_diveq
+
+{ my $a = mpf(21); $a /= 3; ok ($a == 7); }
+{ my $a = mpf(21); my $b = $a; $a /= 3; ok ($a == 7); ok ($b == 21); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_eq
+
+{ my $a = mpf(0);
+  my $b = $a;
+  $a = mpf(1);
+  ok ($a == 1);
+  ok ($b == 0); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_inc
+
+{ my $a = mpf(0); ok ($a++ == 0); ok ($a == 1); }
+{ my $a = mpf(0); ok (++$a == 1); }
+
+{ my $a = mpf(0); my $b = $a; $a++; ok ($a == 1); ok ($b == 0); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_lshift
+
+{ my $a = mpf(7) << 1; ok ($a == 14); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_lshifteq
+
+{ my $a = mpf(7); $a <<= 1; ok ($a == 14); }
+{ my $a = mpf(7); my $b = $a; $a <<= 1; ok ($a == 14); ok ($b == 7); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_mul
+
+ok (mpf(2) * 3 == 6);
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_muleq
+
+{ my $a = mpf(7); $a *= 3;  ok ($a == 21); }
+{ my $a = mpf(7); my $b = $a; $a *= 3;  ok ($a == 21); ok ($b == 7); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_neg
+
+ok (- mpf(0) == 0);
+ok (- mpf(123) == -123);
+ok (- mpf(-123) == 123);
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_not
+
+if (not mpf(0))   { ok (1); } else { ok (0); }
+if (not mpf(123)) { ok (0); } else { ok (1); }
+
+ok ((! mpf(0)) == 1);
+ok ((! mpf(123)) == 0);
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_pow
+
+ok (mpf(0) ** 1 == 0);
+ok (mpf(1) ** 1 == 1);
+ok (mpf(2) ** 0 == 1);
+ok (mpf(2) ** 1 == 2);
+ok (mpf(2) ** 2 == 4);
+ok (mpf(2) ** 3 == 8);
+ok (mpf(2) ** 4 == 16);
+
+ok (mpf(0) ** mpf(1) == 0);
+ok (mpf(1) ** mpf(1) == 1);
+ok (mpf(2) ** mpf(0) == 1);
+ok (mpf(2) ** mpf(1) == 2);
+ok (mpf(2) ** mpf(2) == 4);
+ok (mpf(2) ** mpf(3) == 8);
+ok (mpf(2) ** mpf(4) == 16);
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_poweq
+
+{ my $a = mpf(3); $a **= 4; ok ($a == 81); }
+{ my $a = mpf(3); my $b = $a; $a **= 4; ok ($a == 81); ok ($b == 3); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_rshift
+
+{ my $a = mpf(32) >> 1; ok ($a == 16); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_rshifteq
+
+{ my $a = mpf(32); $a >>= 1; ok ($a == 16); }
+{ my $a = mpf(32); my $b = $a; $a >>= 1; ok ($a == 16); ok ($b == 32); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_sqrt
+
+ok (sqrt(mpf(0)) == 0);
+ok (sqrt(mpf(1)) == 1);
+ok (sqrt(mpf(4)) == 2);
+ok (sqrt(mpf(81)) == 9);
+
+ok (sqrt(mpf(0.25)) == 0.5);
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_spaceship
+
+ok (mpf(0) < 1);
+ok (mpf(0) > -1);
+
+ok (mpf(0) != 1);
+ok (mpf(0) != -1);
+ok (mpf(1) != 0);
+ok (mpf(1) != -1);
+ok (mpf(-1) != 0);
+ok (mpf(-1) != 1);
+
+ok (mpf(0) < 1.0);
+ok (mpf(0) < '1');
+ok (mpf(0) < substr('-1',1,1));
+ok (mpf(0) < mpz(1));
+ok (mpf(0) < mpq(1));
+ok (mpf(0) < mpf(1));
+ok (mpf(0) < $uv_max);
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_string
+
+{ my $x = mpf(0);    ok ("$x" eq "0"); }
+{ my $x = mpf(123);  ok ("$x" eq "123"); }
+{ my $x = mpf(-123); ok ("$x" eq "-123"); }
+
+{ my $f = mpf(0.25);   	 ok ("$f" eq "0.25"); }
+{ my $f = mpf(-0.25);  	 ok ("$f" eq "-0.25"); }
+{ my $f = mpf(1.25);   	 ok ("$f" eq "1.25"); }
+{ my $f = mpf(-1.25);  	 ok ("$f" eq "-1.25"); }
+{ my $f = mpf(1000000);	 ok ("$f" eq "1000000"); }
+{ my $f = mpf(-1000000); ok ("$f" eq "-1000000"); }
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_sub
+
+ok (mpf(0) - 1 == -1);
+ok (mpf(1) - 1 == 0);
+ok (1 - mpf(0) == 1);
+ok (1 - mpf(1) == 0);
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::overload_subeq
+
+{ my $a = mpf(7); $a -= 1; ok ($a == 6); }
+{ my $a = mpf(7); my $b = $a; $a -= 1; ok ($a == 6); ok ($b == 7); }
+
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::ceil
+
+ok (ceil (mpf(-7.5)) == -7.0);
+ok (ceil (mpf(7.5)) == 8.0);
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::floor
+
+ok (floor(mpf(-7.5)) == -8.0);
+ok (floor(mpf(7.5)) == 7.0);
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::mpf_eq
+
+{ my $old_prec = get_default_prec();
+  set_default_prec(128);
+
+  ok (  mpf_eq (mpz("0x10000000000000001"), mpz("0x10000000000000002"), 1));
+  ok (! mpf_eq (mpz("0x11"), mpz("0x12"), 128));
+
+  set_default_prec($old_prec);
+}
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::get_default_prec
+
+get_default_prec();
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::get_prec
+
+{ my $x = mpf(1.0, 512);
+  ok (get_prec ($x) == 512);
+}
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::reldiff
+
+ok (reldiff (2,4) == 1);
+ok (reldiff (4,2) == 0.5);
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::set_default_prec
+
+{ my $old_prec = get_default_prec();
+
+  set_default_prec(512);
+  ok (get_default_prec () == 512);
+
+  set_default_prec($old_prec);
+}
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::set_prec
+
+{ my $x = mpf(1.0, 512);
+  my $y = $x;
+  set_prec ($x, 1024);
+  ok (get_prec ($x) == 1024);
+  ok (get_prec ($y) == 512);
+}
+
+#------------------------------------------------------------------------------
+# GMP::Mpf::trunc
+
+ok (trunc(mpf(-7.5)) == -7.0);
+ok (trunc(mpf(7.5)) == 7.0);
+
+
+
+#------------------------------------------------------------------------------
+# GMP::Rand
+
+#------------------------------------------------------------------------------
+# GMP::Rand::new
+
+{ my $r = randstate();                          ok (defined $r); }
+{ my $r = randstate('lc_2exp', 1, 2, 3);        ok (defined $r); }
+{ my $r = randstate('lc_2exp_size', 64);        ok (defined $r); }
+{ my $r = randstate('lc_2exp_size', 999999999); ok (! defined $r); }
+{ my $r = randstate('mt');                      ok (defined $r); }
+
+{ # copying a randstate results in same sequence
+  my $r1 = randstate('lc_2exp_size', 64);
+  $r1->seed(123);
+  my $r2 = randstate($r1);
+  for (1 .. 20) {
+    my $z1 = mpz_urandomb($r1, 20);
+    my $z2 = mpz_urandomb($r2, 20);
+    ok ($z1 == $z2);
+  }
+}
+
+#------------------------------------------------------------------------------
+# GMP::Rand::seed
+
+{ my $r = randstate();
+  $r->seed(123);
+  $r->seed(time());
+}
+
+#------------------------------------------------------------------------------
+# GMP::Rand::mpf_urandomb
+
+{ my $r = randstate();
+  my $f = mpf_urandomb($r,1024);
+  ok (UNIVERSAL::isa($f,"GMP::Mpf")); }
+
+#------------------------------------------------------------------------------
+# GMP::Rand::mpz_urandomb
+
+{ my $r = randstate();
+  my $z = mpz_urandomb($r, 1024);
+  ok (UNIVERSAL::isa($z,"GMP::Mpz")); }
+
+#------------------------------------------------------------------------------
+# GMP::Rand::mpz_rrandomb
+
+{ my $r = randstate();
+  my $z = mpz_rrandomb($r, 1024);
+  ok (UNIVERSAL::isa($z,"GMP::Mpz")); }
+
+#------------------------------------------------------------------------------
+# GMP::Rand::mpz_urandomm
+
+{ my $r = randstate();
+  my $z = mpz_urandomm($r, mpz(3)**100);
+  ok (UNIVERSAL::isa($z,"GMP::Mpz")); }
+
+#------------------------------------------------------------------------------
+# GMP::Rand::mpz_urandomb_ui
+
+{ my $r = randstate();
+  foreach (1 .. 20) {
+    my $u = gmp_urandomb_ui($r,8);
+    ok ($u >= 0);
+    ok ($u < 256);
+  }
+}
+
+#------------------------------------------------------------------------------
+# GMP::Rand::mpz_urandomm_ui
+
+{ my $r = randstate();
+  foreach (1 .. 20) {
+    my $u = gmp_urandomm_ui($r,8);
+    ok ($u >= 0);
+    ok ($u < 8);
+  }
+}
+
+
+
+
+#------------------------------------------------------------------------------
+# GMP module
+
+#------------------------------------------------------------------------------
+# GMP::fits_slong_p
+
+ok (GMP::fits_slong_p(0));
+
+# in perl 5.005 uv_max is only 32-bits on a 64-bit system, so won't exceed a
+# long
+# ok (! GMP::fits_slong_p($uv_max));
+
+ok (GMP::fits_slong_p(0.0));
+
+ok (GMP::fits_slong_p('0'));
+
+ok (GMP::fits_slong_p(substr('999999999999999999999999999999',1,1)));
+
+ok (! mpz("-9999999999999999999999999999999999999999999")->fits_slong_p());
+ok (  mpz(-123)->fits_slong_p());
+ok (  mpz(0)->fits_slong_p());
+ok (  mpz(123)->fits_slong_p());
+ok (! mpz("9999999999999999999999999999999999999999999")->fits_slong_p());
+
+ok (! mpq("-9999999999999999999999999999999999999999999")->fits_slong_p());
+ok (  mpq(-123)->fits_slong_p());
+ok (  mpq(0)->fits_slong_p());
+ok (  mpq(123)->fits_slong_p());
+ok (! mpq("9999999999999999999999999999999999999999999")->fits_slong_p());
+
+ok (! mpf("-9999999999999999999999999999999999999999999")->fits_slong_p());
+ok (  mpf(-123)->fits_slong_p());
+ok (  mpf(0)->fits_slong_p());
+ok (  mpf(123)->fits_slong_p());
+ok (! mpf("9999999999999999999999999999999999999999999")->fits_slong_p());
+
+#------------------------------------------------------------------------------
+# GMP::get_d
+
+ok (GMP::get_d(123) == 123.0);
+
+ok (GMP::get_d($uv_max) > 0);
+
+ok (GMP::get_d(123.0) == 123.0);
+
+ok (GMP::get_d('123') == 123.0);
+
+ok (GMP::get_d(mpz(123)) == 123.0);
+
+ok (GMP::get_d(mpq(123)) == 123.0);
+
+ok (GMP::get_d(mpf(123)) == 123.0);
+
+#------------------------------------------------------------------------------
+# GMP::get_d_2exp
+
+{ my ($dbl, $exp) = get_d_2exp (0);
+  ok ($dbl == 0); ok ($exp == 0); }
+{ my ($dbl, $exp) = get_d_2exp (1);
+  ok ($dbl == 0.5); ok ($exp == 1); }
+
+{ my ($dbl, $exp) = get_d_2exp ($uv_max);
+  ok ($dbl > 0.0); ok ($exp > 0); }
+
+{ my ($dbl, $exp) = get_d_2exp (0.5);
+  ok ($dbl == 0.5); ok ($exp == 0); }
+{ my ($dbl, $exp) = get_d_2exp (0.25);
+  ok ($dbl == 0.5); ok ($exp == -1); }
+
+{ my ($dbl, $exp) = get_d_2exp ("1.0");
+  ok ($dbl == 0.5); ok ($exp == 1); }
+
+{ my ($dbl, $exp) = get_d_2exp (mpz ("256"));
+  ok ($dbl == 0.5); ok ($exp == 9); }
+
+{ my ($dbl, $exp) = get_d_2exp (mpq ("1/16"));
+  ok ($dbl == 0.5); ok ($exp == -3); }
+
+{ my ($dbl, $exp) = get_d_2exp (mpf ("1.5"));
+  ok ($dbl == 0.75); ok ($exp == 1); }
+{ my ($dbl, $exp) = get_d_2exp (mpf ("3.0"));
+  ok ($dbl == 0.75); ok ($exp == 2); }
+
+#------------------------------------------------------------------------------
+# GMP::get_str
+
+ok (get_str(-123) eq '-123');
+ok (get_str('-123') eq '-123');
+ok (get_str(substr('x-123x',1,4)) eq '-123');
+ok (get_str(mpz(-123)) eq '-123');
+ok (get_str(mpq(-123)) eq '-123');
+
+ok (get_str(-123,10) eq '-123');
+ok (get_str('-123',10) eq '-123');
+ok (get_str(substr('x-123x',1,4),10) eq '-123');
+ok (get_str(mpz(-123),10) eq '-123');
+ok (get_str(mpq(-123),10) eq '-123');
+
+ok (get_str(-123,16) eq '-7b');
+ok (get_str('-123',16) eq '-7b');
+ok (get_str(substr('x-123x',1,4),16) eq '-7b');
+ok (get_str(mpz(-123),16) eq '-7b');
+ok (get_str(mpq(-123),16) eq '-7b');
+
+ok (get_str(-123,-16) eq '-7B');
+ok (get_str('-123',-16) eq '-7B');
+ok (get_str(substr('x-123x',1,4),-16) eq '-7B');
+ok (get_str(mpz(-123),-16) eq '-7B');
+ok (get_str(mpq(-123),-16) eq '-7B');
+
+# is a float in past versions of perl without UV type
+{ my ($str, $exp) = get_str($uv_max);
+  ok ($str eq $uv_max_str); }
+
+ok (get_str(mpq(5/8)) eq "5/8");
+ok (get_str(mpq(-5/8)) eq "-5/8");
+ok (get_str(mpq(255/256),16) eq "ff/100");
+ok (get_str(mpq(255/256),-16) eq "FF/100");
+ok (get_str(mpq(-255/256),16) eq "-ff/100");
+ok (get_str(mpq(-255/256),-16) eq "-FF/100");
+
+{ my ($s,$e) = get_str(1.5, 10);      ok ($s eq '15'); ok ($e == 1); }
+{ my ($s,$e) = get_str(mpf(1.5), 10); ok ($s eq '15'); ok ($e == 1); }
+
+{ my ($s,$e) = get_str(-1.5, 10);      ok ($s eq '-15'); ok ($e == 1); }
+{ my ($s,$e) = get_str(mpf(-1.5), 10); ok ($s eq '-15'); ok ($e == 1); }
+
+{ my ($s,$e) = get_str(1.5, 16);      ok ($s eq '18'); ok ($e == 1); }
+{ my ($s,$e) = get_str(mpf(1.5), 16); ok ($s eq '18'); ok ($e == 1); }
+
+{ my ($s,$e) = get_str(-1.5, 16);      ok ($s eq '-18'); ok ($e == 1); }
+{ my ($s,$e) = get_str(mpf(-1.5), 16); ok ($s eq '-18'); ok ($e == 1); }
+
+{ my ($s,$e) = get_str(65536.0, 16);      ok ($s eq '1'); ok ($e == 5); }
+{ my ($s,$e) = get_str(mpf(65536.0), 16); ok ($s eq '1'); ok ($e == 5); }
+
+{ my ($s,$e) = get_str(1.625, 16);      ok ($s eq '1a'); ok ($e == 1); }
+{ my ($s,$e) = get_str(mpf(1.625), 16); ok ($s eq '1a'); ok ($e == 1); }
+
+{ my ($s,$e) = get_str(1.625, -16);      ok ($s eq '1A'); ok ($e == 1); }
+{ my ($s,$e) = get_str(mpf(1.625), -16); ok ($s eq '1A'); ok ($e == 1); }
+
+{ my ($s, $e) = get_str(255.0,16,0);      ok ($s eq "ff"); ok ($e == 2); }
+{ my ($s, $e) = get_str(mpf(255.0),16,0); ok ($s eq "ff"); ok ($e == 2); }
+
+{ my ($s, $e) = get_str(255.0,-16,0);      ok ($s eq "FF"); ok ($e == 2); }
+{ my ($s, $e) = get_str(mpf(255.0),-16,0); ok ($s eq "FF"); ok ($e == 2); }
+
+#------------------------------------------------------------------------------
+# GMP::get_si
+
+ok (GMP::get_si(123) == 123.0);
+
+# better not assume anything about the relatives sizes of long and UV
+ok (GMP::get_si($uv_max) != 0);
+
+ok (GMP::get_si(123.0) == 123.0);
+
+ok (GMP::get_si('123') == 123.0);
+
+ok (GMP::get_si(mpz(123)) == 123.0);
+
+ok (GMP::get_si(mpq(123)) == 123.0);
+
+ok (GMP::get_si(mpf(123)) == 123.0);
+
+#------------------------------------------------------------------------------
+# GMP::integer_p
+
+ok (  GMP::integer_p (0));
+ok (  GMP::integer_p (123));
+ok (  GMP::integer_p (-123));
+
+ok (  GMP::integer_p ($uv_max));
+
+ok (  GMP::integer_p (0.0));
+ok (  GMP::integer_p (123.0));
+ok (  GMP::integer_p (-123.0));
+ok (! GMP::integer_p (0.5));
+ok (! GMP::integer_p (123.5));
+ok (! GMP::integer_p (-123.5));
+
+ok (  GMP::integer_p ('0'));
+ok (  GMP::integer_p ('123'));
+ok (  GMP::integer_p ('-123'));
+ok (! GMP::integer_p ('0.5'));
+ok (! GMP::integer_p ('123.5'));
+ok (! GMP::integer_p ('-123.5'));
+ok (! GMP::integer_p ('5/8'));
+
+ok (  GMP::integer_p (mpz(1)));
+
+ok (  GMP::integer_p (mpq(1)));
+ok (! GMP::integer_p (mpq(1,2)));
+
+ok (  GMP::integer_p (mpf(1.0)));
+ok (! GMP::integer_p (mpf(1.5)));
+
+#------------------------------------------------------------------------------
+# GMP::odd_p
+
+ok (! odd_p(0));
+ok (  odd_p(1));
+ok (! odd_p(2));
+
+ok (  odd_p($uv_max));
+
+ok (  odd_p(mpz(-3)));
+ok (! odd_p(mpz(-2)));
+ok (  odd_p(mpz(-1)));
+ok (! odd_p(mpz(0)));
+ok (  odd_p(mpz(1)));
+ok (! odd_p(mpz(2)));
+ok (  odd_p(mpz(3)));
+
+#------------------------------------------------------------------------------
+# GMP::printf
+
+GMP::printf ("hello world\n");
+
+sub via_printf {
+  my $s;
+  open TEMP, ">test.tmp" or die;
+  GMP::printf TEMP @_;
+  close TEMP or die;
+  open TEMP, "<test.tmp" or die;
+  read (TEMP, $s, 1024);
+  close TEMP or die;
+  unlink 'test.tmp';
+  return $s;
+}
+
+ok (sprintf ("%d", mpz(123)) eq '123');
+ok (sprintf ("%d %d %d", 456, mpz(123), 789) eq '456 123 789');
+ok (sprintf ("%d", mpq(15,16)) eq '15/16');
+ok (sprintf ("%f", mpf(1.5)) eq '1.500000');
+ok (sprintf ("%.2f", mpf(1.5)) eq '1.50');
+
+ok (sprintf ("%*d", 6, 123) eq '   123');
+ok (sprintf ("%*d", 6, mpz(123))  eq '   123');
+ok (sprintf ("%*d", 6, mpq(15,16))  eq ' 15/16');
+
+ok (sprintf ("%x", 123) eq '7b');
+ok (sprintf ("%x", mpz(123))  eq '7b');
+ok (sprintf ("%X", 123) eq '7B');
+ok (sprintf ("%X", mpz(123))  eq '7B');
+ok (sprintf ("%#x", 123) eq '0x7b');
+ok (sprintf ("%#x", mpz(123))  eq '0x7b');
+ok (sprintf ("%#X", 123) eq '0X7B');
+ok (sprintf ("%#X", mpz(123))  eq '0X7B');
+
+ok (sprintf ("%x", mpq(15,16))  eq 'f/10');
+ok (sprintf ("%X", mpq(15,16))  eq 'F/10');
+ok (sprintf ("%#x", mpq(15,16))  eq '0xf/0x10');
+ok (sprintf ("%#X", mpq(15,16))  eq '0XF/0X10');
+
+ok (sprintf ("%*.*f", 10, 3, 1.25) eq '     1.250');
+ok (sprintf ("%*.*f", 10, 3, mpf(1.5))   eq '     1.500');
+
+ok (via_printf ("%d", mpz(123)) eq '123');
+ok (via_printf ("%d %d %d", 456, mpz(123), 789) eq '456 123 789');
+ok (via_printf ("%d", mpq(15,16)) eq '15/16');
+ok (via_printf ("%f", mpf(1.5)) eq '1.500000');
+ok (via_printf ("%.2f", mpf(1.5)) eq '1.50');
+
+ok (via_printf ("%*d", 6, 123) eq '   123');
+ok (via_printf ("%*d", 6, mpz(123))  eq '   123');
+ok (via_printf ("%*d", 6, mpq(15,16))  eq ' 15/16');
+
+ok (via_printf ("%x", 123) eq '7b');
+ok (via_printf ("%x", mpz(123))  eq '7b');
+ok (via_printf ("%X", 123) eq '7B');
+ok (via_printf ("%X", mpz(123))  eq '7B');
+ok (via_printf ("%#x", 123) eq '0x7b');
+ok (via_printf ("%#x", mpz(123))  eq '0x7b');
+ok (via_printf ("%#X", 123) eq '0X7B');
+ok (via_printf ("%#X", mpz(123))  eq '0X7B');
+
+ok (via_printf ("%x", mpq(15,16))  eq 'f/10');
+ok (via_printf ("%X", mpq(15,16))  eq 'F/10');
+ok (via_printf ("%#x", mpq(15,16))  eq '0xf/0x10');
+ok (via_printf ("%#X", mpq(15,16))  eq '0XF/0X10');
+
+ok (via_printf ("%*.*f", 10, 3, 1.25) eq '     1.250');
+ok (via_printf ("%*.*f", 10, 3, mpf(1.5))   eq '     1.500');
+
+#------------------------------------------------------------------------------
+# GMP::sgn
+
+ok (sgn(-123) == -1);
+ok (sgn(0)    == 0);
+ok (sgn(123)  == 1);
+
+ok (sgn($uv_max) == 1);
+
+ok (sgn(-123.0) == -1);
+ok (sgn(0.0)    == 0);
+ok (sgn(123.0)  == 1);
+
+ok (sgn('-123') == -1);
+ok (sgn('0')    == 0);
+ok (sgn('123')  == 1);
+ok (sgn('-123.0') == -1);
+ok (sgn('0.0')    == 0);
+ok (sgn('123.0')  == 1);
+
+ok (sgn(substr('x-123x',1,4)) == -1);
+ok (sgn(substr('x0x',1,1))    == 0);
+ok (sgn(substr('x123x',1,3))  == 1);
+
+ok (mpz(-123)->sgn() == -1);
+ok (mpz(0)   ->sgn() == 0);
+ok (mpz(123) ->sgn() == 1);
+
+ok (mpq(-123)->sgn() == -1);
+ok (mpq(0)   ->sgn() == 0);
+ok (mpq(123) ->sgn() == 1);
+
+ok (mpf(-123)->sgn() == -1);
+ok (mpf(0)   ->sgn() == 0);
+ok (mpf(123) ->sgn() == 1);
+
+
+
+#------------------------------------------------------------------------------
+# overloaded constants
+
+if ($] > 5.00503) {
+  if (! do 'test2.pl') {
+    die "Cannot run test2.pl\n";
+  }
+}
+
+
+
+
+#------------------------------------------------------------------------------
+# $# stuff
+#
+# For some reason "local $#" doesn't leave $# back at its default undefined
+# state when exiting the block.
+
+{ local $# = 'hi %.0f there';
+  my $f = mpf(123);
+  ok ("$f" eq 'hi 123 there'); }
+
+
+
+# Local variables:
+# perl-indent-level: 2
+# End:
diff --git a/third_party/gmp/demos/perl/test2.pl b/third_party/gmp/demos/perl/test2.pl
new file mode 100644
index 0000000..31a1d6b
--- /dev/null
+++ b/third_party/gmp/demos/perl/test2.pl
@@ -0,0 +1,75 @@
+# GMP perl module tests (part 2)
+
+# Copyright 2001 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+
+# The following uses of :constants seem to provoke segvs in perl 5.005_03,
+# so they're kept separate file to be run only on suitable perl versions.
+
+
+use GMP::Mpz qw(:constants);
+{
+  my $a = 123;
+  ok (UNIVERSAL::isa ($a, "GMP::Mpz"));
+}
+use GMP::Mpz qw(:noconstants);
+
+use GMP::Mpq qw(:constants);
+{
+  my $a = 123;
+  ok (UNIVERSAL::isa ($a, "GMP::Mpq"));
+}
+use GMP::Mpq qw(:noconstants);
+
+use GMP::Mpf qw(:constants);
+{
+  my $a = 123;
+  ok (UNIVERSAL::isa ($a, "GMP::Mpf"));
+}
+use GMP::Mpf qw(:noconstants);
+
+
+# compiled constants unchanged by clrbit etc when re-executed
+foreach (0, 1, 2) {
+  use GMP::Mpz qw(:constants);
+  my $a = 15;
+  my $b = 6;
+  use GMP::Mpz qw(:noconstants);
+  clrbit ($a, 0);
+  ok ($a == 14);
+  setbit ($b, 0);
+  ok ($b == 7);
+}
+
+1;
+
+
+# Local variables:
+# perl-indent-level: 2
+# End:
diff --git a/third_party/gmp/demos/perl/typemap b/third_party/gmp/demos/perl/typemap
new file mode 100644
index 0000000..e863a9c
--- /dev/null
+++ b/third_party/gmp/demos/perl/typemap
@@ -0,0 +1,108 @@
+# GMP module external subroutine type mappings.
+
+# Copyright 2001, 2003 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+
+TYPEMAP
+const_string		T_PV
+const_string_assume	CONST_STRING_ASSUME
+mpz			MPZ
+mpq			MPQ
+mpf			MPF
+mpz_assume		MPZ_ASSUME
+mpq_assume		MPQ_ASSUME
+mpf_assume		MPF_ASSUME
+mpz_coerce		MPZ_COERCE
+mpq_coerce		MPQ_COERCE
+mpf_coerce_st0		MPF_COERCE_ST0
+mpf_coerce_def		MPF_COERCE_DEF
+randstate		RANDSTATE
+ulong_coerce		ULONG_COERCE
+malloced_string		MALLOCED_STRING
+order_noswap		ORDER_NOSWAP
+dummy			DUMMY
+# perl 5.005 doesn't have UV in its standard typemap, so use this instead
+gmp_UV			GMP_UV
+
+
+INPUT
+MPZ
+	class_or_croak ($arg, mpz_class); $var = SvMPZ($arg);
+MPQ
+	class_or_croak ($arg, mpq_class); $var = SvMPQ($arg);
+MPF
+	class_or_croak ($arg, mpf_class); $var = SvMPF($arg);
+MPZ_ASSUME
+        MPZ_ASSUME ($var, $arg)
+MPQ_ASSUME
+        MPQ_ASSUME ($var, $arg)
+MPF_ASSUME
+        MPF_ASSUME ($var, $arg)
+MPZ_COERCE
+	$var = coerce_mpz (tmp_mpz_${(my $stnum=$arg)=~s/[^0-9]//g;\$stnum}, $arg)
+MPQ_COERCE
+	$var = coerce_mpq (tmp_mpq_${(my $stnum=$arg)=~s/[^0-9]//g;\$stnum}, $arg)
+MPF_COERCE_ST0
+        /* precision follows ST(0) */
+        assert (sv_derived_from (ST(0), mpf_class));
+	$var = coerce_mpf (tmp_mpf_${(my $stnum=$arg)=~s/[^0-9]//g;\$stnum},
+	                   $arg, mpf_get_prec (SvMPF(ST(0))))
+MPF_COERCE_DEF
+        /* default precision used */
+	$var = coerce_mpf (tmp_mpf_${(my $stnum=$arg)=~s/[^0-9]//g;\$stnum},
+	                   $arg, mpf_get_default_prec())
+RANDSTATE
+	class_or_croak ($arg, rand_class); $var = SvRANDSTATE($arg);
+ULONG_COERCE
+	$var = coerce_ulong ($arg)
+ORDER_NOSWAP
+	assert ($arg != &PL_sv_yes);
+DUMMY
+	/* dummy $var */
+CONST_STRING_ASSUME
+        /* No need to check for SvPOKp and use SvPV, this mapping is
+           only used for overload_constant, which always gets literal
+           strings.  */
+	assert (SvPOK ($arg));
+	$var = SvPVX ($arg);
+
+
+OUTPUT
+MPZ
+    sv_bless (sv_setref_pv ($arg, NULL, $var), mpz_class_hv);
+MPQ
+    sv_bless (sv_setref_pv ($arg, NULL, $var), mpq_class_hv);
+MPF
+    sv_bless (sv_setref_pv ($arg, NULL, $var), mpf_class_hv);
+RANDSTATE
+    sv_setref_pv ($arg, rand_class, $var);
+MALLOCED_STRING
+    sv_usepvn_mg ($arg, $var, strlen($var));
+GMP_UV
+    sv_setuv ($arg, (UV) ($var));
diff --git a/third_party/gmp/demos/pexpr-config-h.in b/third_party/gmp/demos/pexpr-config-h.in
new file mode 100644
index 0000000..b3e7f5d
--- /dev/null
+++ b/third_party/gmp/demos/pexpr-config-h.in
@@ -0,0 +1,45 @@
+/* Templates for pexpr program configuration.   -*- mode:c -*-
+
+Copyright 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 3 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program.  If not, see https://www.gnu.org/licenses/.  */
+
+
+/* Define if you have the <sys/resource.h> header file. */
+#define HAVE_SYS_RESOURCE_H  @HAVE_SYS_RESOURCE_H_01@
+
+/* Define if you have the `clock' function. */
+#define HAVE_CLOCK  @HAVE_CLOCK_01@
+
+/* Define if you have the `cputime' function. */
+#define HAVE_CPUTIME  @HAVE_CPUTIME_01@
+
+/* Define if you have the `getrusage' function. */
+#define HAVE_GETRUSAGE  @HAVE_GETRUSAGE_01@
+
+/* Define if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY  @HAVE_GETTIMEOFDAY_01@
+
+/* Define if you have the `sigaction' function. */
+#define HAVE_SIGACTION  @HAVE_SIGACTION_01@
+
+/* Define if you have the `sigaltstack' function. */
+#define HAVE_SIGALTSTACK  @HAVE_SIGALTSTACK_01@
+
+/* Define if you have the `sigstack' function. */
+#define HAVE_SIGSTACK  @HAVE_SIGSTACK_01@
+
+/* Define if the system has the type `stack_t'. */
+#define HAVE_STACK_T  @HAVE_STACK_T_01@
diff --git a/third_party/gmp/demos/pexpr.c b/third_party/gmp/demos/pexpr.c
new file mode 100644
index 0000000..d5009e9
--- /dev/null
+++ b/third_party/gmp/demos/pexpr.c
@@ -0,0 +1,1380 @@
+/* Program for computing integer expressions using the GNU Multiple Precision
+   Arithmetic Library.
+
+Copyright 1997, 1999-2002, 2005, 2008, 2012, 2015 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 3 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program.  If not, see https://www.gnu.org/licenses/.  */
+
+
+/* This expressions evaluator works by building an expression tree (using a
+   recursive descent parser) which is then evaluated.  The expression tree is
+   useful since we want to optimize certain expressions (like a^b % c).
+
+   Usage: pexpr [options] expr ...
+   (Assuming you called the executable `pexpr' of course.)
+
+   Command line options:
+
+   -b        print output in binary
+   -o        print output in octal
+   -d        print output in decimal (the default)
+   -x        print output in hexadecimal
+   -b<NUM>   print output in base NUM
+   -t        print timing information
+   -html     output html
+   -wml      output wml
+   -split    split long lines each 80th digit
+*/
+
+/* Define LIMIT_RESOURCE_USAGE if you want to make sure the program doesn't
+   use up extensive resources (cpu, memory).  Useful for the GMP demo on the
+   GMP web site, since we cannot load the server too much.  */
+
+#include "pexpr-config.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <ctype.h>
+
+#include <time.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#if HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+
+#include "gmp.h"
+
+/* SunOS 4 and HPUX 9 don't define a canonical SIGSTKSZ, use a default. */
+#ifndef SIGSTKSZ
+#define SIGSTKSZ  4096
+#endif
+
+
+#define TIME(t,func)							\
+  do { int __t0, __tmp;							\
+    __t0 = cputime ();							\
+    {func;}								\
+    __tmp = cputime () - __t0;						\
+    (t) = __tmp;							\
+  } while (0)
+
+/* GMP version 1.x compatibility.  */
+#if ! (__GNU_MP_VERSION >= 2)
+typedef MP_INT __mpz_struct;
+typedef __mpz_struct mpz_t[1];
+typedef __mpz_struct *mpz_ptr;
+#define mpz_fdiv_q	mpz_div
+#define mpz_fdiv_r	mpz_mod
+#define mpz_tdiv_q_2exp	mpz_div_2exp
+#define mpz_sgn(Z) ((Z)->size < 0 ? -1 : (Z)->size > 0)
+#endif
+
+/* GMP version 2.0 compatibility.  */
+#if ! (__GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1)
+#define mpz_swap(a,b) \
+  do { __mpz_struct __t; __t = *a; *a = *b; *b = __t;} while (0)
+#endif
+
+jmp_buf errjmpbuf;
+
+enum op_t {NOP, LIT, NEG, NOT, PLUS, MINUS, MULT, DIV, MOD, REM, INVMOD, POW,
+	   AND, IOR, XOR, SLL, SRA, POPCNT, HAMDIST, GCD, LCM, SQRT, ROOT, FAC,
+	   LOG, LOG2, FERMAT, MERSENNE, FIBONACCI, RANDOM, NEXTPRIME, BINOM,
+	   TIMING};
+
+/* Type for the expression tree.  */
+struct expr
+{
+  enum op_t op;
+  union
+  {
+    struct {struct expr *lhs, *rhs;} ops;
+    mpz_t val;
+  } operands;
+};
+
+typedef struct expr *expr_t;
+
+void cleanup_and_exit (int);
+
+char *skipspace (char *);
+void makeexp (expr_t *, enum op_t, expr_t, expr_t);
+void free_expr (expr_t);
+char *expr (char *, expr_t *);
+char *term (char *, expr_t *);
+char *power (char *, expr_t *);
+char *factor (char *, expr_t *);
+int match (char *, char *);
+int matchp (char *, char *);
+int cputime (void);
+
+void mpz_eval_expr (mpz_ptr, expr_t);
+void mpz_eval_mod_expr (mpz_ptr, expr_t, mpz_ptr);
+
+char *error;
+int flag_print = 1;
+int print_timing = 0;
+int flag_html = 0;
+int flag_wml = 0;
+int flag_splitup_output = 0;
+char *newline = "";
+gmp_randstate_t rstate;
+
+
+
+/* cputime() returns user CPU time measured in milliseconds.  */
+#if ! HAVE_CPUTIME
+#if HAVE_GETRUSAGE
+int
+cputime (void)
+{
+  struct rusage rus;
+
+  getrusage (0, &rus);
+  return rus.ru_utime.tv_sec * 1000 + rus.ru_utime.tv_usec / 1000;
+}
+#else
+#if HAVE_CLOCK
+int
+cputime (void)
+{
+  if (CLOCKS_PER_SEC < 100000)
+    return clock () * 1000 / CLOCKS_PER_SEC;
+  return clock () / (CLOCKS_PER_SEC / 1000);
+}
+#else
+int
+cputime (void)
+{
+  return 0;
+}
+#endif
+#endif
+#endif
+
+
+int
+stack_downwards_helper (char *xp)
+{
+  char  y;
+  return &y < xp;
+}
+int
+stack_downwards_p (void)
+{
+  char  x;
+  return stack_downwards_helper (&x);
+}
+
+
+void
+setup_error_handler (void)
+{
+#if HAVE_SIGACTION
+  struct sigaction act;
+  act.sa_handler = cleanup_and_exit;
+  sigemptyset (&(act.sa_mask));
+#define SIGNAL(sig)  sigaction (sig, &act, NULL)
+#else
+  struct { int sa_flags; } act;
+#define SIGNAL(sig)  signal (sig, cleanup_and_exit)
+#endif
+  act.sa_flags = 0;
+
+  /* Set up a stack for signal handling.  A typical cause of error is stack
+     overflow, and in such situation a signal can not be delivered on the
+     overflown stack.  */
+#if HAVE_SIGALTSTACK
+  {
+    /* AIX uses stack_t, MacOS uses struct sigaltstack, various other
+       systems have both. */
+#if HAVE_STACK_T
+    stack_t s;
+#else
+    struct sigaltstack s;
+#endif
+    s.ss_sp = malloc (SIGSTKSZ);
+    s.ss_size = SIGSTKSZ;
+    s.ss_flags = 0;
+    if (sigaltstack (&s, NULL) != 0)
+      perror("sigaltstack");
+    act.sa_flags = SA_ONSTACK;
+  }
+#else
+#if HAVE_SIGSTACK
+  {
+    struct sigstack s;
+    s.ss_sp = malloc (SIGSTKSZ);
+    if (stack_downwards_p ())
+      s.ss_sp += SIGSTKSZ;
+    s.ss_onstack = 0;
+    if (sigstack (&s, NULL) != 0)
+      perror("sigstack");
+    act.sa_flags = SA_ONSTACK;
+  }
+#else
+#endif
+#endif
+
+#ifdef LIMIT_RESOURCE_USAGE
+  {
+    struct rlimit limit;
+
+    limit.rlim_cur = limit.rlim_max = 0;
+    setrlimit (RLIMIT_CORE, &limit);
+
+    limit.rlim_cur = 3;
+    limit.rlim_max = 4;
+    setrlimit (RLIMIT_CPU, &limit);
+
+    limit.rlim_cur = limit.rlim_max = 16 * 1024 * 1024;
+    setrlimit (RLIMIT_DATA, &limit);
+
+    getrlimit (RLIMIT_STACK, &limit);
+    limit.rlim_cur = 4 * 1024 * 1024;
+    setrlimit (RLIMIT_STACK, &limit);
+
+    SIGNAL (SIGXCPU);
+  }
+#endif /* LIMIT_RESOURCE_USAGE */
+
+  SIGNAL (SIGILL);
+  SIGNAL (SIGSEGV);
+#ifdef SIGBUS /* not in mingw */
+  SIGNAL (SIGBUS);
+#endif
+  SIGNAL (SIGFPE);
+  SIGNAL (SIGABRT);
+}
+
+int
+main (int argc, char **argv)
+{
+  struct expr *e;
+  int i;
+  mpz_t r;
+  int errcode = 0;
+  char *str;
+  int base = 10;
+
+  setup_error_handler ();
+
+  gmp_randinit (rstate, GMP_RAND_ALG_LC, 128);
+
+  {
+#if HAVE_GETTIMEOFDAY
+    struct timeval tv;
+    gettimeofday (&tv, NULL);
+    gmp_randseed_ui (rstate, tv.tv_sec + tv.tv_usec);
+#else
+    time_t t;
+    time (&t);
+    gmp_randseed_ui (rstate, t);
+#endif
+  }
+
+  mpz_init (r);
+
+  while (argc > 1 && argv[1][0] == '-')
+    {
+      char *arg = argv[1];
+
+      if (arg[1] >= '0' && arg[1] <= '9')
+	break;
+
+      if (arg[1] == 't')
+	print_timing = 1;
+      else if (arg[1] == 'b' && arg[2] >= '0' && arg[2] <= '9')
+	{
+	  base = atoi (arg + 2);
+	  if (base < 2 || base > 62)
+	    {
+	      fprintf (stderr, "error: invalid output base\n");
+	      exit (-1);
+	    }
+	}
+      else if (arg[1] == 'b' && arg[2] == 0)
+	base = 2;
+      else if (arg[1] == 'x' && arg[2] == 0)
+	base = 16;
+      else if (arg[1] == 'X' && arg[2] == 0)
+	base = -16;
+      else if (arg[1] == 'o' && arg[2] == 0)
+	base = 8;
+      else if (arg[1] == 'd' && arg[2] == 0)
+	base = 10;
+      else if (arg[1] == 'v' && arg[2] == 0)
+	{
+	  printf ("pexpr linked to gmp %s\n", __gmp_version);
+	}
+      else if (strcmp (arg, "-html") == 0)
+	{
+	  flag_html = 1;
+	  newline = "<br>";
+	}
+      else if (strcmp (arg, "-wml") == 0)
+	{
+	  flag_wml = 1;
+	  newline = "<br/>";
+	}
+      else if (strcmp (arg, "-split") == 0)
+	{
+	  flag_splitup_output = 1;
+	}
+      else if (strcmp (arg, "-noprint") == 0)
+	{
+	  flag_print = 0;
+	}
+      else
+	{
+	  fprintf (stderr, "error: unknown option `%s'\n", arg);
+	  exit (-1);
+	}
+      argv++;
+      argc--;
+    }
+
+  for (i = 1; i < argc; i++)
+    {
+      int s;
+      int jmpval;
+
+      /* Set up error handler for parsing expression.  */
+      jmpval = setjmp (errjmpbuf);
+      if (jmpval != 0)
+	{
+	  fprintf (stderr, "error: %s%s\n", error, newline);
+	  fprintf (stderr, "       %s%s\n", argv[i], newline);
+	  if (! flag_html)
+	    {
+	      /* ??? Dunno how to align expression position with arrow in
+		 HTML ??? */
+	      fprintf (stderr, "       ");
+	      for (s = jmpval - (long) argv[i]; --s >= 0; )
+		putc (' ', stderr);
+	      fprintf (stderr, "^\n");
+	    }
+
+	  errcode |= 1;
+	  continue;
+	}
+
+      str = expr (argv[i], &e);
+
+      if (str[0] != 0)
+	{
+	  fprintf (stderr,
+		   "error: garbage where end of expression expected%s\n",
+		   newline);
+	  fprintf (stderr, "       %s%s\n", argv[i], newline);
+	  if (! flag_html)
+	    {
+	      /* ??? Dunno how to align expression position with arrow in
+		 HTML ??? */
+	      fprintf (stderr, "        ");
+	      for (s = str - argv[i]; --s; )
+		putc (' ', stderr);
+	      fprintf (stderr, "^\n");
+	    }
+
+	  errcode |= 1;
+	  free_expr (e);
+	  continue;
+	}
+
+      /* Set up error handler for evaluating expression.  */
+      if (setjmp (errjmpbuf))
+	{
+	  fprintf (stderr, "error: %s%s\n", error, newline);
+	  fprintf (stderr, "       %s%s\n", argv[i], newline);
+	  if (! flag_html)
+	    {
+	      /* ??? Dunno how to align expression position with arrow in
+		 HTML ??? */
+	      fprintf (stderr, "       ");
+	      for (s = str - argv[i]; --s >= 0; )
+		putc (' ', stderr);
+	      fprintf (stderr, "^\n");
+	    }
+
+	  errcode |= 2;
+	  continue;
+	}
+
+      if (print_timing)
+	{
+	  int t;
+	  TIME (t, mpz_eval_expr (r, e));
+	  printf ("computation took %d ms%s\n", t, newline);
+	}
+      else
+	mpz_eval_expr (r, e);
+
+      if (flag_print)
+	{
+	  size_t out_len;
+	  char *tmp, *s;
+
+	  out_len = mpz_sizeinbase (r, base >= 0 ? base : -base) + 2;
+#ifdef LIMIT_RESOURCE_USAGE
+	  if (out_len > 100000)
+	    {
+	      printf ("result is about %ld digits, not printing it%s\n",
+		      (long) out_len - 3, newline);
+	      exit (-2);
+	    }
+#endif
+	  tmp = malloc (out_len);
+
+	  if (print_timing)
+	    {
+	      int t;
+	      printf ("output conversion ");
+	      TIME (t, mpz_get_str (tmp, base, r));
+	      printf ("took %d ms%s\n", t, newline);
+	    }
+	  else
+	    mpz_get_str (tmp, base, r);
+
+	  out_len = strlen (tmp);
+	  if (flag_splitup_output)
+	    {
+	      for (s = tmp; out_len > 80; s += 80)
+		{
+		  fwrite (s, 1, 80, stdout);
+		  printf ("%s\n", newline);
+		  out_len -= 80;
+		}
+
+	      fwrite (s, 1, out_len, stdout);
+	    }
+	  else
+	    {
+	      fwrite (tmp, 1, out_len, stdout);
+	    }
+
+	  free (tmp);
+	  printf ("%s\n", newline);
+	}
+      else
+	{
+	  printf ("result is approximately %ld digits%s\n",
+		  (long) mpz_sizeinbase (r, base >= 0 ? base : -base),
+		  newline);
+	}
+
+      free_expr (e);
+    }
+
+  mpz_clear (r);
+
+  exit (errcode);
+}
+
+char *
+expr (char *str, expr_t *e)
+{
+  expr_t e2;
+
+  str = skipspace (str);
+  if (str[0] == '+')
+    {
+      str = term (str + 1, e);
+    }
+  else if (str[0] == '-')
+    {
+      str = term (str + 1, e);
+      makeexp (e, NEG, *e, NULL);
+    }
+  else if (str[0] == '~')
+    {
+      str = term (str + 1, e);
+      makeexp (e, NOT, *e, NULL);
+    }
+  else
+    {
+      str = term (str, e);
+    }
+
+  for (;;)
+    {
+      str = skipspace (str);
+      switch (str[0])
+	{
+	case 'p':
+	  if (match ("plus", str))
+	    {
+	      str = term (str + 4, &e2);
+	      makeexp (e, PLUS, *e, e2);
+	    }
+	  else
+	    return str;
+	  break;
+	case 'm':
+	  if (match ("minus", str))
+	    {
+	      str = term (str + 5, &e2);
+	      makeexp (e, MINUS, *e, e2);
+	    }
+	  else
+	    return str;
+	  break;
+	case '+':
+	  str = term (str + 1, &e2);
+	  makeexp (e, PLUS, *e, e2);
+	  break;
+	case '-':
+	  str = term (str + 1, &e2);
+	  makeexp (e, MINUS, *e, e2);
+	  break;
+	default:
+	  return str;
+	}
+    }
+}
+
+char *
+term (char *str, expr_t *e)
+{
+  expr_t e2;
+
+  str = power (str, e);
+  for (;;)
+    {
+      str = skipspace (str);
+      switch (str[0])
+	{
+	case 'm':
+	  if (match ("mul", str))
+	    {
+	      str = power (str + 3, &e2);
+	      makeexp (e, MULT, *e, e2);
+	      break;
+	    }
+	  if (match ("mod", str))
+	    {
+	      str = power (str + 3, &e2);
+	      makeexp (e, MOD, *e, e2);
+	      break;
+	    }
+	  return str;
+	case 'd':
+	  if (match ("div", str))
+	    {
+	      str = power (str + 3, &e2);
+	      makeexp (e, DIV, *e, e2);
+	      break;
+	    }
+	  return str;
+	case 'r':
+	  if (match ("rem", str))
+	    {
+	      str = power (str + 3, &e2);
+	      makeexp (e, REM, *e, e2);
+	      break;
+	    }
+	  return str;
+	case 'i':
+	  if (match ("invmod", str))
+	    {
+	      str = power (str + 6, &e2);
+	      makeexp (e, REM, *e, e2);
+	      break;
+	    }
+	  return str;
+	case 't':
+	  if (match ("times", str))
+	    {
+	      str = power (str + 5, &e2);
+	      makeexp (e, MULT, *e, e2);
+	      break;
+	    }
+	  if (match ("thru", str))
+	    {
+	      str = power (str + 4, &e2);
+	      makeexp (e, DIV, *e, e2);
+	      break;
+	    }
+	  if (match ("through", str))
+	    {
+	      str = power (str + 7, &e2);
+	      makeexp (e, DIV, *e, e2);
+	      break;
+	    }
+	  return str;
+	case '*':
+	  str = power (str + 1, &e2);
+	  makeexp (e, MULT, *e, e2);
+	  break;
+	case '/':
+	  str = power (str + 1, &e2);
+	  makeexp (e, DIV, *e, e2);
+	  break;
+	case '%':
+	  str = power (str + 1, &e2);
+	  makeexp (e, MOD, *e, e2);
+	  break;
+	default:
+	  return str;
+	}
+    }
+}
+
+char *
+power (char *str, expr_t *e)
+{
+  expr_t e2;
+
+  str = factor (str, e);
+  while (str[0] == '!')
+    {
+      str++;
+      makeexp (e, FAC, *e, NULL);
+    }
+  str = skipspace (str);
+  if (str[0] == '^')
+    {
+      str = power (str + 1, &e2);
+      makeexp (e, POW, *e, e2);
+    }
+  return str;
+}
+
+int
+match (char *s, char *str)
+{
+  char *ostr = str;
+  int i;
+
+  for (i = 0; s[i] != 0; i++)
+    {
+      if (str[i] != s[i])
+	return 0;
+    }
+  str = skipspace (str + i);
+  return str - ostr;
+}
+
+int
+matchp (char *s, char *str)
+{
+  char *ostr = str;
+  int i;
+
+  for (i = 0; s[i] != 0; i++)
+    {
+      if (str[i] != s[i])
+	return 0;
+    }
+  str = skipspace (str + i);
+  if (str[0] == '(')
+    return str - ostr + 1;
+  return 0;
+}
+
+struct functions
+{
+  char *spelling;
+  enum op_t op;
+  int arity; /* 1 or 2 means real arity; 0 means arbitrary.  */
+};
+
+struct functions fns[] =
+{
+  {"sqrt", SQRT, 1},
+#if __GNU_MP_VERSION >= 2
+  {"root", ROOT, 2},
+  {"popc", POPCNT, 1},
+  {"hamdist", HAMDIST, 2},
+#endif
+  {"gcd", GCD, 0},
+#if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1
+  {"lcm", LCM, 0},
+#endif
+  {"and", AND, 0},
+  {"ior", IOR, 0},
+#if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1
+  {"xor", XOR, 0},
+#endif
+  {"plus", PLUS, 0},
+  {"pow", POW, 2},
+  {"minus", MINUS, 2},
+  {"mul", MULT, 0},
+  {"div", DIV, 2},
+  {"mod", MOD, 2},
+  {"rem", REM, 2},
+#if __GNU_MP_VERSION >= 2
+  {"invmod", INVMOD, 2},
+#endif
+  {"log", LOG, 2},
+  {"log2", LOG2, 1},
+  {"F", FERMAT, 1},
+  {"M", MERSENNE, 1},
+  {"fib", FIBONACCI, 1},
+  {"Fib", FIBONACCI, 1},
+  {"random", RANDOM, 1},
+  {"nextprime", NEXTPRIME, 1},
+  {"binom", BINOM, 2},
+  {"binomial", BINOM, 2},
+  {"fac", FAC, 1},
+  {"fact", FAC, 1},
+  {"factorial", FAC, 1},
+  {"time", TIMING, 1},
+  {"", NOP, 0}
+};
+
+char *
+factor (char *str, expr_t *e)
+{
+  expr_t e1, e2;
+
+  str = skipspace (str);
+
+  if (isalpha (str[0]))
+    {
+      int i;
+      int cnt;
+
+      for (i = 0; fns[i].op != NOP; i++)
+	{
+	  if (fns[i].arity == 1)
+	    {
+	      cnt = matchp (fns[i].spelling, str);
+	      if (cnt != 0)
+		{
+		  str = expr (str + cnt, &e1);
+		  str = skipspace (str);
+		  if (str[0] != ')')
+		    {
+		      error = "expected `)'";
+		      longjmp (errjmpbuf, (int) (long) str);
+		    }
+		  makeexp (e, fns[i].op, e1, NULL);
+		  return str + 1;
+		}
+	    }
+	}
+
+      for (i = 0; fns[i].op != NOP; i++)
+	{
+	  if (fns[i].arity != 1)
+	    {
+	      cnt = matchp (fns[i].spelling, str);
+	      if (cnt != 0)
+		{
+		  str = expr (str + cnt, &e1);
+		  str = skipspace (str);
+
+		  if (str[0] != ',')
+		    {
+		      error = "expected `,' and another operand";
+		      longjmp (errjmpbuf, (int) (long) str);
+		    }
+
+		  str = skipspace (str + 1);
+		  str = expr (str, &e2);
+		  str = skipspace (str);
+
+		  if (fns[i].arity == 0)
+		    {
+		      while (str[0] == ',')
+			{
+			  makeexp (&e1, fns[i].op, e1, e2);
+			  str = skipspace (str + 1);
+			  str = expr (str, &e2);
+			  str = skipspace (str);
+			}
+		    }
+
+		  if (str[0] != ')')
+		    {
+		      error = "expected `)'";
+		      longjmp (errjmpbuf, (int) (long) str);
+		    }
+
+		  makeexp (e, fns[i].op, e1, e2);
+		  return str + 1;
+		}
+	    }
+	}
+    }
+
+  if (str[0] == '(')
+    {
+      str = expr (str + 1, e);
+      str = skipspace (str);
+      if (str[0] != ')')
+	{
+	  error = "expected `)'";
+	  longjmp (errjmpbuf, (int) (long) str);
+	}
+      str++;
+    }
+  else if (str[0] >= '0' && str[0] <= '9')
+    {
+      expr_t res;
+      char *s, *sc;
+
+      res = malloc (sizeof (struct expr));
+      res -> op = LIT;
+      mpz_init (res->operands.val);
+
+      s = str;
+      while (isalnum (str[0]))
+	str++;
+      sc = malloc (str - s + 1);
+      memcpy (sc, s, str - s);
+      sc[str - s] = 0;
+
+      mpz_set_str (res->operands.val, sc, 0);
+      *e = res;
+      free (sc);
+    }
+  else
+    {
+      error = "operand expected";
+      longjmp (errjmpbuf, (int) (long) str);
+    }
+  return str;
+}
+
+char *
+skipspace (char *str)
+{
+  while (str[0] == ' ')
+    str++;
+  return str;
+}
+
+/* Make a new expression with operation OP and right hand side
+   RHS and left hand side lhs.  Put the result in R.  */
+void
+makeexp (expr_t *r, enum op_t op, expr_t lhs, expr_t rhs)
+{
+  expr_t res;
+  res = malloc (sizeof (struct expr));
+  res -> op = op;
+  res -> operands.ops.lhs = lhs;
+  res -> operands.ops.rhs = rhs;
+  *r = res;
+  return;
+}
+
+/* Free the memory used by expression E.  */
+void
+free_expr (expr_t e)
+{
+  if (e->op != LIT)
+    {
+      free_expr (e->operands.ops.lhs);
+      if (e->operands.ops.rhs != NULL)
+	free_expr (e->operands.ops.rhs);
+    }
+  else
+    {
+      mpz_clear (e->operands.val);
+    }
+}
+
+/* Evaluate the expression E and put the result in R.  */
+void
+mpz_eval_expr (mpz_ptr r, expr_t e)
+{
+  mpz_t lhs, rhs;
+
+  switch (e->op)
+    {
+    case LIT:
+      mpz_set (r, e->operands.val);
+      return;
+    case PLUS:
+      mpz_init (lhs); mpz_init (rhs);
+      mpz_eval_expr (lhs, e->operands.ops.lhs);
+      mpz_eval_expr (rhs, e->operands.ops.rhs);
+      mpz_add (r, lhs, rhs);
+      mpz_clear (lhs); mpz_clear (rhs);
+      return;
+    case MINUS:
+      mpz_init (lhs); mpz_init (rhs);
+      mpz_eval_expr (lhs, e->operands.ops.lhs);
+      mpz_eval_expr (rhs, e->operands.ops.rhs);
+      mpz_sub (r, lhs, rhs);
+      mpz_clear (lhs); mpz_clear (rhs);
+      return;
+    case MULT:
+      mpz_init (lhs); mpz_init (rhs);
+      mpz_eval_expr (lhs, e->operands.ops.lhs);
+      mpz_eval_expr (rhs, e->operands.ops.rhs);
+      mpz_mul (r, lhs, rhs);
+      mpz_clear (lhs); mpz_clear (rhs);
+      return;
+    case DIV:
+      mpz_init (lhs); mpz_init (rhs);
+      mpz_eval_expr (lhs, e->operands.ops.lhs);
+      mpz_eval_expr (rhs, e->operands.ops.rhs);
+      mpz_fdiv_q (r, lhs, rhs);
+      mpz_clear (lhs); mpz_clear (rhs);
+      return;
+    case MOD:
+      mpz_init (rhs);
+      mpz_eval_expr (rhs, e->operands.ops.rhs);
+      mpz_abs (rhs, rhs);
+      mpz_eval_mod_expr (r, e->operands.ops.lhs, rhs);
+      mpz_clear (rhs);
+      return;
+    case REM:
+      /* Check if lhs operand is POW expression and optimize for that case.  */
+      if (e->operands.ops.lhs->op == POW)
+	{
+	  mpz_t powlhs, powrhs;
+	  mpz_init (powlhs);
+	  mpz_init (powrhs);
+	  mpz_init (rhs);
+	  mpz_eval_expr (powlhs, e->operands.ops.lhs->operands.ops.lhs);
+	  mpz_eval_expr (powrhs, e->operands.ops.lhs->operands.ops.rhs);
+	  mpz_eval_expr (rhs, e->operands.ops.rhs);
+	  mpz_powm (r, powlhs, powrhs, rhs);
+	  if (mpz_cmp_si (rhs, 0L) < 0)
+	    mpz_neg (r, r);
+	  mpz_clear (powlhs);
+	  mpz_clear (powrhs);
+	  mpz_clear (rhs);
+	  return;
+	}
+
+      mpz_init (lhs); mpz_init (rhs);
+      mpz_eval_expr (lhs, e->operands.ops.lhs);
+      mpz_eval_expr (rhs, e->operands.ops.rhs);
+      mpz_fdiv_r (r, lhs, rhs);
+      mpz_clear (lhs); mpz_clear (rhs);
+      return;
+#if __GNU_MP_VERSION >= 2
+    case INVMOD:
+      mpz_init (lhs); mpz_init (rhs);
+      mpz_eval_expr (lhs, e->operands.ops.lhs);
+      mpz_eval_expr (rhs, e->operands.ops.rhs);
+      mpz_invert (r, lhs, rhs);
+      mpz_clear (lhs); mpz_clear (rhs);
+      return;
+#endif
+    case POW:
+      mpz_init (lhs); mpz_init (rhs);
+      mpz_eval_expr (lhs, e->operands.ops.lhs);
+      if (mpz_cmpabs_ui (lhs, 1) <= 0)
+	{
+	  /* For 0^rhs and 1^rhs, we just need to verify that
+	     rhs is well-defined.  For (-1)^rhs we need to
+	     determine (rhs mod 2).  For simplicity, compute
+	     (rhs mod 2) for all three cases.  */
+	  expr_t two, et;
+	  two = malloc (sizeof (struct expr));
+	  two -> op = LIT;
+	  mpz_init_set_ui (two->operands.val, 2L);
+	  makeexp (&et, MOD, e->operands.ops.rhs, two);
+	  e->operands.ops.rhs = et;
+	}
+
+      mpz_eval_expr (rhs, e->operands.ops.rhs);
+      if (mpz_cmp_si (rhs, 0L) == 0)
+	/* x^0 is 1 */
+	mpz_set_ui (r, 1L);
+      else if (mpz_cmp_si (lhs, 0L) == 0)
+	/* 0^y (where y != 0) is 0 */
+	mpz_set_ui (r, 0L);
+      else if (mpz_cmp_ui (lhs, 1L) == 0)
+	/* 1^y is 1 */
+	mpz_set_ui (r, 1L);
+      else if (mpz_cmp_si (lhs, -1L) == 0)
+	/* (-1)^y just depends on whether y is even or odd */
+	mpz_set_si (r, (mpz_get_ui (rhs) & 1) ? -1L : 1L);
+      else if (mpz_cmp_si (rhs, 0L) < 0)
+	/* x^(-n) is 0 */
+	mpz_set_ui (r, 0L);
+      else
+	{
+	  unsigned long int cnt;
+	  unsigned long int y;
+	  /* error if exponent does not fit into an unsigned long int.  */
+	  if (mpz_cmp_ui (rhs, ~(unsigned long int) 0) > 0)
+	    goto pow_err;
+
+	  y = mpz_get_ui (rhs);
+	  /* x^y == (x/(2^c))^y * 2^(c*y) */
+#if __GNU_MP_VERSION >= 2
+	  cnt = mpz_scan1 (lhs, 0);
+#else
+	  cnt = 0;
+#endif
+	  if (cnt != 0)
+	    {
+	      if (y * cnt / cnt != y)
+		goto pow_err;
+	      mpz_tdiv_q_2exp (lhs, lhs, cnt);
+	      mpz_pow_ui (r, lhs, y);
+	      mpz_mul_2exp (r, r, y * cnt);
+	    }
+	  else
+	    mpz_pow_ui (r, lhs, y);
+	}
+      mpz_clear (lhs); mpz_clear (rhs);
+      return;
+    pow_err:
+      error = "result of `pow' operator too large";
+      mpz_clear (lhs); mpz_clear (rhs);
+      longjmp (errjmpbuf, 1);
+    case GCD:
+      mpz_init (lhs); mpz_init (rhs);
+      mpz_eval_expr (lhs, e->operands.ops.lhs);
+      mpz_eval_expr (rhs, e->operands.ops.rhs);
+      mpz_gcd (r, lhs, rhs);
+      mpz_clear (lhs); mpz_clear (rhs);
+      return;
+#if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1
+    case LCM:
+      mpz_init (lhs); mpz_init (rhs);
+      mpz_eval_expr (lhs, e->operands.ops.lhs);
+      mpz_eval_expr (rhs, e->operands.ops.rhs);
+      mpz_lcm (r, lhs, rhs);
+      mpz_clear (lhs); mpz_clear (rhs);
+      return;
+#endif
+    case AND:
+      mpz_init (lhs); mpz_init (rhs);
+      mpz_eval_expr (lhs, e->operands.ops.lhs);
+      mpz_eval_expr (rhs, e->operands.ops.rhs);
+      mpz_and (r, lhs, rhs);
+      mpz_clear (lhs); mpz_clear (rhs);
+      return;
+    case IOR:
+      mpz_init (lhs); mpz_init (rhs);
+      mpz_eval_expr (lhs, e->operands.ops.lhs);
+      mpz_eval_expr (rhs, e->operands.ops.rhs);
+      mpz_ior (r, lhs, rhs);
+      mpz_clear (lhs); mpz_clear (rhs);
+      return;
+#if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1
+    case XOR:
+      mpz_init (lhs); mpz_init (rhs);
+      mpz_eval_expr (lhs, e->operands.ops.lhs);
+      mpz_eval_expr (rhs, e->operands.ops.rhs);
+      mpz_xor (r, lhs, rhs);
+      mpz_clear (lhs); mpz_clear (rhs);
+      return;
+#endif
+    case NEG:
+      mpz_eval_expr (r, e->operands.ops.lhs);
+      mpz_neg (r, r);
+      return;
+    case NOT:
+      mpz_eval_expr (r, e->operands.ops.lhs);
+      mpz_com (r, r);
+      return;
+    case SQRT:
+      mpz_init (lhs);
+      mpz_eval_expr (lhs, e->operands.ops.lhs);
+      if (mpz_sgn (lhs) < 0)
+	{
+	  error = "cannot take square root of negative numbers";
+	  mpz_clear (lhs);
+	  longjmp (errjmpbuf, 1);
+	}
+      mpz_sqrt (r, lhs);
+      return;
+#if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1
+    case ROOT:
+      mpz_init (lhs); mpz_init (rhs);
+      mpz_eval_expr (lhs, e->operands.ops.lhs);
+      mpz_eval_expr (rhs, e->operands.ops.rhs);
+      if (mpz_sgn (rhs) <= 0)
+	{
+	  error = "cannot take non-positive root orders";
+	  mpz_clear (lhs); mpz_clear (rhs);
+	  longjmp (errjmpbuf, 1);
+	}
+      if (mpz_sgn (lhs) < 0 && (mpz_get_ui (rhs) & 1) == 0)
+	{
+	  error = "cannot take even root orders of negative numbers";
+	  mpz_clear (lhs); mpz_clear (rhs);
+	  longjmp (errjmpbuf, 1);
+	}
+
+      {
+	unsigned long int nth = mpz_get_ui (rhs);
+	if (mpz_cmp_ui (rhs, ~(unsigned long int) 0) > 0)
+	  {
+	    /* If we are asked to take an awfully large root order, cheat and
+	       ask for the largest order we can pass to mpz_root.  This saves
+	       some error prone special cases.  */
+	    nth = ~(unsigned long int) 0;
+	  }
+	mpz_root (r, lhs, nth);
+      }
+      mpz_clear (lhs); mpz_clear (rhs);
+      return;
+#endif
+    case FAC:
+      mpz_eval_expr (r, e->operands.ops.lhs);
+      if (mpz_size (r) > 1)
+	{
+	  error = "result of `!' operator too large";
+	  longjmp (errjmpbuf, 1);
+	}
+      mpz_fac_ui (r, mpz_get_ui (r));
+      return;
+#if __GNU_MP_VERSION >= 2
+    case POPCNT:
+      mpz_eval_expr (r, e->operands.ops.lhs);
+      { long int cnt;
+	cnt = mpz_popcount (r);
+	mpz_set_si (r, cnt);
+      }
+      return;
+    case HAMDIST:
+      { long int cnt;
+	mpz_init (lhs); mpz_init (rhs);
+	mpz_eval_expr (lhs, e->operands.ops.lhs);
+	mpz_eval_expr (rhs, e->operands.ops.rhs);
+	cnt = mpz_hamdist (lhs, rhs);
+	mpz_clear (lhs); mpz_clear (rhs);
+	mpz_set_si (r, cnt);
+      }
+      return;
+#endif
+    case LOG2:
+      mpz_eval_expr (r, e->operands.ops.lhs);
+      { unsigned long int cnt;
+	if (mpz_sgn (r) <= 0)
+	  {
+	    error = "logarithm of non-positive number";
+	    longjmp (errjmpbuf, 1);
+	  }
+	cnt = mpz_sizeinbase (r, 2);
+	mpz_set_ui (r, cnt - 1);
+      }
+      return;
+    case LOG:
+      { unsigned long int cnt;
+	mpz_init (lhs); mpz_init (rhs);
+	mpz_eval_expr (lhs, e->operands.ops.lhs);
+	mpz_eval_expr (rhs, e->operands.ops.rhs);
+	if (mpz_sgn (lhs) <= 0)
+	  {
+	    error = "logarithm of non-positive number";
+	    mpz_clear (lhs); mpz_clear (rhs);
+	    longjmp (errjmpbuf, 1);
+	  }
+	if (mpz_cmp_ui (rhs, 256) >= 0)
+	  {
+	    error = "logarithm base too large";
+	    mpz_clear (lhs); mpz_clear (rhs);
+	    longjmp (errjmpbuf, 1);
+	  }
+	cnt = mpz_sizeinbase (lhs, mpz_get_ui (rhs));
+	mpz_set_ui (r, cnt - 1);
+	mpz_clear (lhs); mpz_clear (rhs);
+      }
+      return;
+    case FERMAT:
+      {
+	unsigned long int t;
+	mpz_init (lhs);
+	mpz_eval_expr (lhs, e->operands.ops.lhs);
+	t = (unsigned long int) 1 << mpz_get_ui (lhs);
+	if (mpz_cmp_ui (lhs, ~(unsigned long int) 0) > 0 || t == 0)
+	  {
+	    error = "too large Mersenne number index";
+	    mpz_clear (lhs);
+	    longjmp (errjmpbuf, 1);
+	  }
+	mpz_set_ui (r, 1);
+	mpz_mul_2exp (r, r, t);
+	mpz_add_ui (r, r, 1);
+	mpz_clear (lhs);
+      }
+      return;
+    case MERSENNE:
+      mpz_init (lhs);
+      mpz_eval_expr (lhs, e->operands.ops.lhs);
+      if (mpz_cmp_ui (lhs, ~(unsigned long int) 0) > 0)
+	{
+	  error = "too large Mersenne number index";
+	  mpz_clear (lhs);
+	  longjmp (errjmpbuf, 1);
+	}
+      mpz_set_ui (r, 1);
+      mpz_mul_2exp (r, r, mpz_get_ui (lhs));
+      mpz_sub_ui (r, r, 1);
+      mpz_clear (lhs);
+      return;
+    case FIBONACCI:
+      { mpz_t t;
+	unsigned long int n, i;
+	mpz_init (lhs);
+	mpz_eval_expr (lhs, e->operands.ops.lhs);
+	if (mpz_sgn (lhs) <= 0 || mpz_cmp_si (lhs, 1000000000) > 0)
+	  {
+	    error = "Fibonacci index out of range";
+	    mpz_clear (lhs);
+	    longjmp (errjmpbuf, 1);
+	  }
+	n = mpz_get_ui (lhs);
+	mpz_clear (lhs);
+
+#if __GNU_MP_VERSION > 2 || __GNU_MP_VERSION_MINOR >= 1
+	mpz_fib_ui (r, n);
+#else
+	mpz_init_set_ui (t, 1);
+	mpz_set_ui (r, 1);
+
+	if (n <= 2)
+	  mpz_set_ui (r, 1);
+	else
+	  {
+	    for (i = 3; i <= n; i++)
+	      {
+		mpz_add (t, t, r);
+		mpz_swap (t, r);
+	      }
+	  }
+	mpz_clear (t);
+#endif
+      }
+      return;
+    case RANDOM:
+      {
+	unsigned long int n;
+	mpz_init (lhs);
+	mpz_eval_expr (lhs, e->operands.ops.lhs);
+	if (mpz_sgn (lhs) <= 0 || mpz_cmp_si (lhs, 1000000000) > 0)
+	  {
+	    error = "random number size out of range";
+	    mpz_clear (lhs);
+	    longjmp (errjmpbuf, 1);
+	  }
+	n = mpz_get_ui (lhs);
+	mpz_clear (lhs);
+	mpz_urandomb (r, rstate, n);
+      }
+      return;
+    case NEXTPRIME:
+      {
+	mpz_eval_expr (r, e->operands.ops.lhs);
+	mpz_nextprime (r, r);
+      }
+      return;
+    case BINOM:
+      mpz_init (lhs); mpz_init (rhs);
+      mpz_eval_expr (lhs, e->operands.ops.lhs);
+      mpz_eval_expr (rhs, e->operands.ops.rhs);
+      {
+	unsigned long int k;
+	if (mpz_cmp_ui (rhs, ~(unsigned long int) 0) > 0)
+	  {
+	    error = "k too large in (n over k) expression";
+	    mpz_clear (lhs); mpz_clear (rhs);
+	    longjmp (errjmpbuf, 1);
+	  }
+	k = mpz_get_ui (rhs);
+	mpz_bin_ui (r, lhs, k);
+      }
+      mpz_clear (lhs); mpz_clear (rhs);
+      return;
+    case TIMING:
+      {
+	int t0;
+	t0 = cputime ();
+	mpz_eval_expr (r, e->operands.ops.lhs);
+	printf ("time: %d\n", cputime () - t0);
+      }
+      return;
+    default:
+      abort ();
+    }
+}
+
+/* Evaluate the expression E modulo MOD and put the result in R.  */
+void
+mpz_eval_mod_expr (mpz_ptr r, expr_t e, mpz_ptr mod)
+{
+  mpz_t lhs, rhs;
+
+  switch (e->op)
+    {
+      case POW:
+	mpz_init (lhs); mpz_init (rhs);
+	mpz_eval_mod_expr (lhs, e->operands.ops.lhs, mod);
+	mpz_eval_expr (rhs, e->operands.ops.rhs);
+	mpz_powm (r, lhs, rhs, mod);
+	mpz_clear (lhs); mpz_clear (rhs);
+	return;
+      case PLUS:
+	mpz_init (lhs); mpz_init (rhs);
+	mpz_eval_mod_expr (lhs, e->operands.ops.lhs, mod);
+	mpz_eval_mod_expr (rhs, e->operands.ops.rhs, mod);
+	mpz_add (r, lhs, rhs);
+	if (mpz_cmp_si (r, 0L) < 0)
+	  mpz_add (r, r, mod);
+	else if (mpz_cmp (r, mod) >= 0)
+	  mpz_sub (r, r, mod);
+	mpz_clear (lhs); mpz_clear (rhs);
+	return;
+      case MINUS:
+	mpz_init (lhs); mpz_init (rhs);
+	mpz_eval_mod_expr (lhs, e->operands.ops.lhs, mod);
+	mpz_eval_mod_expr (rhs, e->operands.ops.rhs, mod);
+	mpz_sub (r, lhs, rhs);
+	if (mpz_cmp_si (r, 0L) < 0)
+	  mpz_add (r, r, mod);
+	else if (mpz_cmp (r, mod) >= 0)
+	  mpz_sub (r, r, mod);
+	mpz_clear (lhs); mpz_clear (rhs);
+	return;
+      case MULT:
+	mpz_init (lhs); mpz_init (rhs);
+	mpz_eval_mod_expr (lhs, e->operands.ops.lhs, mod);
+	mpz_eval_mod_expr (rhs, e->operands.ops.rhs, mod);
+	mpz_mul (r, lhs, rhs);
+	mpz_mod (r, r, mod);
+	mpz_clear (lhs); mpz_clear (rhs);
+	return;
+      default:
+	mpz_init (lhs);
+	mpz_eval_expr (lhs, e);
+	mpz_mod (r, lhs, mod);
+	mpz_clear (lhs);
+	return;
+    }
+}
+
+void
+cleanup_and_exit (int sig)
+{
+  switch (sig) {
+#ifdef LIMIT_RESOURCE_USAGE
+  case SIGXCPU:
+    printf ("expression took too long to evaluate%s\n", newline);
+    break;
+#endif
+  case SIGFPE:
+    printf ("divide by zero%s\n", newline);
+    break;
+  default:
+    printf ("expression required too much memory to evaluate%s\n", newline);
+    break;
+  }
+  exit (-2);
+}
diff --git a/third_party/gmp/demos/primes.c b/third_party/gmp/demos/primes.c
new file mode 100644
index 0000000..3cb32e2
--- /dev/null
+++ b/third_party/gmp/demos/primes.c
@@ -0,0 +1,387 @@
+/* List and count primes.
+   Written by tege while on holiday in Rodupp, August 2001.
+   Between 10 and 500 times faster than previous program.
+
+Copyright 2001, 2002, 2006, 2012 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 3 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+
+/* IDEAS:
+ * Do not fill primes[] with real primes when the range [fr,to] is small,
+   when fr,to are relatively large.  Fill primes[] with odd numbers instead.
+   [Probably a bad idea, since the primes[] array would become very large.]
+ * Separate small primes and large primes when sieving.  Either the Montgomery
+   way (i.e., having a large array a multiple of L1 cache size), or just
+   separate loops for primes <= S and primes > S.  The latter primes do not
+   require an inner loop, since they will touch the sieving array at most once.
+ * Pre-fill sieving array with an appropriately aligned ...00100100... pattern,
+   then omit 3 from primes array.  (May require similar special handling of 3
+   as we now have for 2.)
+ * A large SIEVE_LIMIT currently implies very large memory usage, mainly due
+   to the sieving array in make_primelist, but also because of the primes[]
+   array.  We might want to stage the program, using sieve_region/find_primes
+   to build primes[].  Make report() a function pointer, as part of achieving
+   this.
+ * Store primes[] as two arrays, one array with primes represented as delta
+   values using just 8 bits (if gaps are too big, store bogus primes!)
+   and one array with "rem" values.  The latter needs 32-bit values.
+ * A new entry point, mpz_probab_prime_likely_p, would be useful.
+ * Improve command line syntax and versatility.  "primes -f FROM -t TO",
+   allow either to be omitted for open interval.  (But disallow
+   "primes -c -f FROM" since that would be infinity.)  Allow printing a
+   limited *number* of primes using syntax like "primes -f FROM -n NUMBER".
+ * When looking for maxgaps, we should not perform any primality testing until
+   we find possible record gaps.  Should speed up the searches tremendously.
+ */
+
+#include "gmp.h"
+
+struct primes
+{
+  unsigned int prime;
+  int rem;
+};
+
+struct primes *primes;
+unsigned long n_primes;
+
+void find_primes (unsigned char *, mpz_t, unsigned long, mpz_t);
+void sieve_region (unsigned char *, mpz_t, unsigned long);
+void make_primelist (unsigned long);
+
+int flag_print = 1;
+int flag_count = 0;
+int flag_maxgap = 0;
+unsigned long maxgap = 0;
+unsigned long total_primes = 0;
+
+void
+report (mpz_t prime)
+{
+  total_primes += 1;
+  if (flag_print)
+    {
+      mpz_out_str (stdout, 10, prime);
+      printf ("\n");
+    }
+  if (flag_maxgap)
+    {
+      static unsigned long prev_prime_low = 0;
+      unsigned long gap;
+      if (prev_prime_low != 0)
+	{
+	  gap = mpz_get_ui (prime) - prev_prime_low;
+	  if (maxgap < gap)
+	    maxgap = gap;
+	}
+      prev_prime_low = mpz_get_ui (prime);
+    }
+}
+
+int
+main (int argc, char *argv[])
+{
+  char *progname = argv[0];
+  mpz_t fr, to;
+  mpz_t fr2, to2;
+  unsigned long sieve_lim;
+  unsigned long est_n_primes;
+  unsigned char *s;
+  mpz_t tmp;
+  mpz_t siev_sqr_lim;
+
+  while (argc != 1)
+    {
+      if (strcmp (argv[1], "-c") == 0)
+	{
+	  flag_count = 1;
+	  argv++;
+	  argc--;
+	}
+      else if (strcmp (argv[1], "-p") == 0)
+	{
+	  flag_print = 2;
+	  argv++;
+	  argc--;
+	}
+      else if (strcmp (argv[1], "-g") == 0)
+	{
+	  flag_maxgap = 1;
+	  argv++;
+	  argc--;
+	}
+      else
+	break;
+    }
+
+  if (flag_count || flag_maxgap)
+    flag_print--;		/* clear unless an explicit -p  */
+
+  mpz_init (fr);
+  mpz_init (to);
+  mpz_init (fr2);
+  mpz_init (to2);
+
+  if (argc == 3)
+    {
+      mpz_set_str (fr, argv[1], 0);
+      if (argv[2][0] == '+')
+	{
+	  mpz_set_str (to, argv[2] + 1, 0);
+	  mpz_add (to, to, fr);
+	}
+      else
+	mpz_set_str (to, argv[2], 0);
+    }
+  else if (argc == 2)
+    {
+      mpz_set_ui (fr, 0);
+      mpz_set_str (to, argv[1], 0);
+    }
+  else
+    {
+      fprintf (stderr, "usage: %s [-c] [-p] [-g] [from [+]]to\n", progname);
+      exit (1);
+    }
+
+  mpz_set (fr2, fr);
+  if (mpz_cmp_ui (fr2, 3) < 0)
+    {
+      mpz_set_ui (fr2, 2);
+      report (fr2);
+      mpz_set_ui (fr2, 3);
+    }
+  mpz_setbit (fr2, 0);				/* make odd */
+  mpz_sub_ui (to2, to, 1);
+  mpz_setbit (to2, 0);				/* make odd */
+
+  mpz_init (tmp);
+  mpz_init (siev_sqr_lim);
+
+  mpz_sqrt (tmp, to2);
+#define SIEVE_LIMIT 10000000
+  if (mpz_cmp_ui (tmp, SIEVE_LIMIT) < 0)
+    {
+      sieve_lim = mpz_get_ui (tmp);
+    }
+  else
+    {
+      sieve_lim = SIEVE_LIMIT;
+      mpz_sub (tmp, to2, fr2);
+      if (mpz_cmp_ui (tmp, sieve_lim) < 0)
+	sieve_lim = mpz_get_ui (tmp);	/* limit sieving for small ranges */
+    }
+  mpz_set_ui (siev_sqr_lim, sieve_lim + 1);
+  mpz_mul_ui (siev_sqr_lim, siev_sqr_lim, sieve_lim + 1);
+
+  est_n_primes = (size_t) (sieve_lim / log((double) sieve_lim) * 1.13) + 10;
+  primes = malloc (est_n_primes * sizeof primes[0]);
+  make_primelist (sieve_lim);
+  assert (est_n_primes >= n_primes);
+
+#if DEBUG
+  printf ("sieve_lim = %lu\n", sieve_lim);
+  printf ("n_primes = %lu (3..%u)\n",
+	  n_primes, primes[n_primes - 1].prime);
+#endif
+
+#define S (1 << 15)		/* FIXME: Figure out L1 cache size */
+  s = malloc (S/2);
+  while (mpz_cmp (fr2, to2) <= 0)
+    {
+      unsigned long rsize;
+      rsize = S;
+      mpz_add_ui (tmp, fr2, rsize);
+      if (mpz_cmp (tmp, to2) > 0)
+	{
+	  mpz_sub (tmp, to2, fr2);
+	  rsize = mpz_get_ui (tmp) + 2;
+	}
+#if DEBUG
+      printf ("Sieving region ["); mpz_out_str (stdout, 10, fr2);
+      printf (","); mpz_add_ui (tmp, fr2, rsize - 2);
+      mpz_out_str (stdout, 10, tmp); printf ("]\n");
+#endif
+      sieve_region (s, fr2, rsize);
+      find_primes (s, fr2, rsize / 2, siev_sqr_lim);
+
+      mpz_add_ui (fr2, fr2, S);
+    }
+  free (s);
+
+  if (flag_count)
+    printf ("Pi(interval) = %lu\n", total_primes);
+
+  if (flag_maxgap)
+    printf ("max gap: %lu\n", maxgap);
+
+  return 0;
+}
+
+/* Find primes in region [fr,fr+rsize).  Requires that fr is odd and that
+   rsize is even.  The sieving array s should be aligned for "long int" and
+   have rsize/2 entries, rounded up to the nearest multiple of "long int".  */
+void
+sieve_region (unsigned char *s, mpz_t fr, unsigned long rsize)
+{
+  unsigned long ssize = rsize / 2;
+  unsigned long start, start2, prime;
+  unsigned long i;
+  mpz_t tmp;
+
+  mpz_init (tmp);
+
+#if 0
+  /* initialize sieving array */
+  for (ii = 0; ii < (ssize + sizeof (long) - 1) / sizeof (long); ii++)
+    ((long *) s) [ii] = ~0L;
+#else
+  {
+    long k;
+    long *se = (long *) (s + ((ssize + sizeof (long) - 1) & -sizeof (long)));
+    for (k = -((ssize + sizeof (long) - 1) / sizeof (long)); k < 0; k++)
+      se[k] = ~0L;
+  }
+#endif
+
+  for (i = 0; i < n_primes; i++)
+    {
+      prime = primes[i].prime;
+
+      if (primes[i].rem >= 0)
+	{
+	  start2 = primes[i].rem;
+	}
+      else
+	{
+	  mpz_set_ui (tmp, prime);
+	  mpz_mul_ui (tmp, tmp, prime);
+	  if (mpz_cmp (fr, tmp) <= 0)
+	    {
+	      mpz_sub (tmp, tmp, fr);
+	      if (mpz_cmp_ui (tmp, 2 * ssize) > 0)
+		break;		/* avoid overflow at next line, also speedup */
+	      start = mpz_get_ui (tmp);
+	    }
+	  else
+	    {
+	      start = (prime - mpz_tdiv_ui (fr, prime)) % prime;
+	      if (start % 2 != 0)
+		start += prime;		/* adjust if even divisible */
+	    }
+	  start2 = start / 2;
+	}
+
+#if 0
+      for (ii = start2; ii < ssize; ii += prime)
+	s[ii] = 0;
+      primes[i].rem = ii - ssize;
+#else
+      {
+	long k;
+	unsigned char *se = s + ssize; /* point just beyond sieving range */
+	for (k = start2 - ssize; k < 0; k += prime)
+	  se[k] = 0;
+	primes[i].rem = k;
+      }
+#endif
+    }
+  mpz_clear (tmp);
+}
+
+/* Find primes in region [fr,fr+rsize), using the previously sieved s[].  */
+void
+find_primes (unsigned char *s, mpz_t  fr, unsigned long ssize,
+	     mpz_t siev_sqr_lim)
+{
+  unsigned long j, ij;
+  mpz_t tmp;
+
+  mpz_init (tmp);
+  for (j = 0; j < (ssize + sizeof (long) - 1) / sizeof (long); j++)
+    {
+      if (((long *) s) [j] != 0)
+	{
+	  for (ij = 0; ij < sizeof (long); ij++)
+	    {
+	      if (s[j * sizeof (long) + ij] != 0)
+		{
+		  if (j * sizeof (long) + ij >= ssize)
+		    goto out;
+		  mpz_add_ui (tmp, fr, (j * sizeof (long) + ij) * 2);
+		  if (mpz_cmp (tmp, siev_sqr_lim) < 0 ||
+		      mpz_probab_prime_p (tmp, 10))
+		    report (tmp);
+		}
+	    }
+	}
+    }
+ out:
+  mpz_clear (tmp);
+}
+
+/* Generate a list of primes and store in the global array primes[].  */
+void
+make_primelist (unsigned long maxprime)
+{
+#if 1
+  unsigned char *s;
+  unsigned long ssize = maxprime / 2;
+  unsigned long i, ii, j;
+
+  s = malloc (ssize);
+  memset (s, ~0, ssize);
+  for (i = 3; ; i += 2)
+    {
+      unsigned long isqr = i * i;
+      if (isqr >= maxprime)
+	break;
+      if (s[i * i / 2 - 1] == 0)
+	continue;				/* only sieve with primes */
+      for (ii = i * i / 2 - 1; ii < ssize; ii += i)
+	s[ii] = 0;
+    }
+  n_primes = 0;
+  for (j = 0; j < ssize; j++)
+    {
+      if (s[j] != 0)
+	{
+	  primes[n_primes].prime = j * 2 + 3;
+	  primes[n_primes].rem = -1;
+	  n_primes++;
+	}
+    }
+  /* FIXME: This should not be needed if fencepost errors were fixed... */
+  if (primes[n_primes - 1].prime > maxprime)
+    n_primes--;
+  free (s);
+#else
+  unsigned long i;
+  n_primes = 0;
+  for (i = 3; i <= maxprime; i += 2)
+    {
+      if (i < 7 || (i % 3 != 0 && i % 5 != 0 && i % 7 != 0))
+	{
+	  primes[n_primes].prime = i;
+	  primes[n_primes].rem = -1;
+	  n_primes++;
+	}
+    }
+#endif
+}
diff --git a/third_party/gmp/demos/primes.h b/third_party/gmp/demos/primes.h
new file mode 100644
index 0000000..b85c7e1
--- /dev/null
+++ b/third_party/gmp/demos/primes.h
@@ -0,0 +1,552 @@
+P( 1, 0xaaaaaaaaaaaaaaabUL, 0x5555555555555555UL) /* 3 */
+P( 2, 0xcccccccccccccccdUL, 0x3333333333333333UL) /* 5 */
+P( 2, 0x6db6db6db6db6db7UL, 0x2492492492492492UL) /* 7 */
+P( 4, 0x2e8ba2e8ba2e8ba3UL, 0x1745d1745d1745d1UL) /* 11 */
+P( 2, 0x4ec4ec4ec4ec4ec5UL, 0x13b13b13b13b13b1UL) /* 13 */
+P( 4, 0xf0f0f0f0f0f0f0f1UL, 0x0f0f0f0f0f0f0f0fUL) /* 17 */
+P( 2, 0x86bca1af286bca1bUL, 0x0d79435e50d79435UL) /* 19 */
+P( 4, 0xd37a6f4de9bd37a7UL, 0x0b21642c8590b216UL) /* 23 */
+P( 6, 0x34f72c234f72c235UL, 0x08d3dcb08d3dcb08UL) /* 29 */
+P( 2, 0xef7bdef7bdef7bdfUL, 0x0842108421084210UL) /* 31 */
+P( 6, 0x14c1bacf914c1badUL, 0x06eb3e45306eb3e4UL) /* 37 */
+P( 4, 0x8f9c18f9c18f9c19UL, 0x063e7063e7063e70UL) /* 41 */
+P( 2, 0x82fa0be82fa0be83UL, 0x05f417d05f417d05UL) /* 43 */
+P( 4, 0x51b3bea3677d46cfUL, 0x0572620ae4c415c9UL) /* 47 */
+P( 6, 0x21cfb2b78c13521dUL, 0x04d4873ecade304dUL) /* 53 */
+P( 6, 0xcbeea4e1a08ad8f3UL, 0x0456c797dd49c341UL) /* 59 */
+P( 2, 0x4fbcda3ac10c9715UL, 0x04325c53ef368eb0UL) /* 61 */
+P( 6, 0xf0b7672a07a44c6bUL, 0x03d226357e16ece5UL) /* 67 */
+P( 4, 0x193d4bb7e327a977UL, 0x039b0ad12073615aUL) /* 71 */
+P( 2, 0x7e3f1f8fc7e3f1f9UL, 0x0381c0e070381c0eUL) /* 73 */
+P( 6, 0x9b8b577e613716afUL, 0x033d91d2a2067b23UL) /* 79 */
+P( 4, 0xa3784a062b2e43dbUL, 0x03159721ed7e7534UL) /* 83 */
+P( 6, 0xf47e8fd1fa3f47e9UL, 0x02e05c0b81702e05UL) /* 89 */
+P( 8, 0xa3a0fd5c5f02a3a1UL, 0x02a3a0fd5c5f02a3UL) /* 97 */
+P( 4, 0x3a4c0a237c32b16dUL, 0x0288df0cac5b3f5dUL) /* 101 */
+P( 2, 0xdab7ec1dd3431b57UL, 0x027c45979c95204fUL) /* 103 */
+P( 4, 0x77a04c8f8d28ac43UL, 0x02647c69456217ecUL) /* 107 */
+P( 2, 0xa6c0964fda6c0965UL, 0x02593f69b02593f6UL) /* 109 */
+P( 4, 0x90fdbc090fdbc091UL, 0x0243f6f0243f6f02UL) /* 113 */
+P(14, 0x7efdfbf7efdfbf7fUL, 0x0204081020408102UL) /* 127 */
+P( 4, 0x03e88cb3c9484e2bUL, 0x01f44659e4a42715UL) /* 131 */
+P( 6, 0xe21a291c077975b9UL, 0x01de5d6e3f8868a4UL) /* 137 */
+P( 2, 0x3aef6ca970586723UL, 0x01d77b654b82c339UL) /* 139 */
+P(10, 0xdf5b0f768ce2cabdUL, 0x01b7d6c3dda338b2UL) /* 149 */
+P( 2, 0x6fe4dfc9bf937f27UL, 0x01b2036406c80d90UL) /* 151 */
+P( 6, 0x5b4fe5e92c0685b5UL, 0x01a16d3f97a4b01aUL) /* 157 */
+P( 6, 0x1f693a1c451ab30bUL, 0x01920fb49d0e228dUL) /* 163 */
+P( 4, 0x8d07aa27db35a717UL, 0x01886e5f0abb0499UL) /* 167 */
+P( 6, 0x882383b30d516325UL, 0x017ad2208e0ecc35UL) /* 173 */
+P( 6, 0xed6866f8d962ae7bUL, 0x016e1f76b4337c6cUL) /* 179 */
+P( 2, 0x3454dca410f8ed9dUL, 0x016a13cd15372904UL) /* 181 */
+P(10, 0x1d7ca632ee936f3fUL, 0x01571ed3c506b39aUL) /* 191 */
+P( 2, 0x70bf015390948f41UL, 0x015390948f40feacUL) /* 193 */
+P( 4, 0xc96bdb9d3d137e0dUL, 0x014cab88725af6e7UL) /* 197 */
+P( 2, 0x2697cc8aef46c0f7UL, 0x0149539e3b2d066eUL) /* 199 */
+P(12, 0xc0e8f2a76e68575bUL, 0x013698df3de07479UL) /* 211 */
+P(12, 0x687763dfdb43bb1fUL, 0x0125e22708092f11UL) /* 223 */
+P( 4, 0x1b10ea929ba144cbUL, 0x0120b470c67c0d88UL) /* 227 */
+P( 2, 0x1d10c4c0478bbcedUL, 0x011e2ef3b3fb8744UL) /* 229 */
+P( 4, 0x63fb9aeb1fdcd759UL, 0x0119453808ca29c0UL) /* 233 */
+P( 6, 0x64afaa4f437b2e0fUL, 0x0112358e75d30336UL) /* 239 */
+P( 2, 0xf010fef010fef011UL, 0x010fef010fef010fUL) /* 241 */
+P(10, 0x28cbfbeb9a020a33UL, 0x0105197f7d734041UL) /* 251 */
+P( 6, 0xff00ff00ff00ff01UL, 0x00ff00ff00ff00ffUL) /* 257 */
+P( 6, 0xd624fd1470e99cb7UL, 0x00f92fb2211855a8UL) /* 263 */
+P( 6, 0x8fb3ddbd6205b5c5UL, 0x00f3a0d52cba8723UL) /* 269 */
+P( 2, 0xd57da36ca27acdefUL, 0x00f1d48bcee0d399UL) /* 271 */
+P( 6, 0xee70c03b25e4463dUL, 0x00ec979118f3fc4dUL) /* 277 */
+P( 4, 0xc5b1a6b80749cb29UL, 0x00e939651fe2d8d3UL) /* 281 */
+P( 2, 0x47768073c9b97113UL, 0x00e79372e225fe30UL) /* 283 */
+P(10, 0x2591e94884ce32adUL, 0x00dfac1f74346c57UL) /* 293 */
+P(14, 0xf02806abc74be1fbUL, 0x00d578e97c3f5fe5UL) /* 307 */
+P( 4, 0x7ec3e8f3a7198487UL, 0x00d2ba083b445250UL) /* 311 */
+P( 2, 0x58550f8a39409d09UL, 0x00d161543e28e502UL) /* 313 */
+P( 4, 0xec9e48ae6f71de15UL, 0x00cebcf8bb5b4169UL) /* 317 */
+P(14, 0x2ff3a018bfce8063UL, 0x00c5fe740317f9d0UL) /* 331 */
+P( 6, 0x7f9ec3fcf61fe7b1UL, 0x00c2780613c0309eUL) /* 337 */
+P(10, 0x89f5abe570e046d3UL, 0x00bcdd535db1cc5bUL) /* 347 */
+P( 2, 0xda971b23f1545af5UL, 0x00bbc8408cd63069UL) /* 349 */
+P( 4, 0x79d5f00b9a7862a1UL, 0x00b9a7862a0ff465UL) /* 353 */
+P( 6, 0x4dba1df32a128a57UL, 0x00b68d31340e4307UL) /* 359 */
+P( 8, 0x87530217b7747d8fUL, 0x00b2927c29da5519UL) /* 367 */
+P( 6, 0x30baae53bb5e06ddUL, 0x00afb321a1496fdfUL) /* 373 */
+P( 6, 0xee70206c12e9b5b3UL, 0x00aceb0f891e6551UL) /* 379 */
+P( 4, 0xcdde9462ec9dbe7fUL, 0x00ab1cbdd3e2970fUL) /* 383 */
+P( 6, 0xafb64b05ec41cf4dUL, 0x00a87917088e262bUL) /* 389 */
+P( 8, 0x02944ff5aec02945UL, 0x00a513fd6bb00a51UL) /* 397 */
+P( 4, 0x2cb033128382df71UL, 0x00a36e71a2cb0331UL) /* 401 */
+P( 8, 0x1ccacc0c84b1c2a9UL, 0x00a03c1688732b30UL) /* 409 */
+P(10, 0x19a93db575eb3a0bUL, 0x009c69169b30446dUL) /* 419 */
+P( 2, 0xcebeef94fa86fe2dUL, 0x009baade8e4a2f6eUL) /* 421 */
+P(10, 0x6faa77fb3f8df54fUL, 0x00980e4156201301UL) /* 431 */
+P( 2, 0x68a58af00975a751UL, 0x00975a750ff68a58UL) /* 433 */
+P( 6, 0xd56e36d0c3efac07UL, 0x009548e4979e0829UL) /* 439 */
+P( 4, 0xd8b44c47a8299b73UL, 0x0093efd1c50e726bUL) /* 443 */
+P( 6, 0x02d9ccaf9ba70e41UL, 0x0091f5bcb8bb02d9UL) /* 449 */
+P( 8, 0x0985e1c023d9e879UL, 0x008f67a1e3fdc261UL) /* 457 */
+P( 4, 0x2a343316c494d305UL, 0x008e2917e0e702c6UL) /* 461 */
+P( 2, 0x70cb7916ab67652fUL, 0x008d8be33f95d715UL) /* 463 */
+P( 4, 0xd398f132fb10fe5bUL, 0x008c55841c815ed5UL) /* 467 */
+P(12, 0x6f2a38a6bf54fa1fUL, 0x0088d180cd3a4133UL) /* 479 */
+P( 8, 0x211df689b98f81d7UL, 0x00869222b1acf1ceUL) /* 487 */
+P( 4, 0x0e994983e90f1ec3UL, 0x0085797b917765abUL) /* 491 */
+P( 8, 0xad671e44bed87f3bUL, 0x008355ace3c897dbUL) /* 499 */
+P( 4, 0xf9623a0516e70fc7UL, 0x00824a4e60b3262bUL) /* 503 */
+P( 6, 0x4b7129be9dece355UL, 0x0080c121b28bd1baUL) /* 509 */
+P(12, 0x190f3b7473f62c39UL, 0x007dc9f3397d4c29UL) /* 521 */
+P( 2, 0x63dacc9aad46f9a3UL, 0x007d4ece8fe88139UL) /* 523 */
+P(18, 0xc1108fda24e8d035UL, 0x0079237d65bcce50UL) /* 541 */
+P( 6, 0xb77578472319bd8bUL, 0x0077cf53c5f7936cUL) /* 547 */
+P(10, 0x473d20a1c7ed9da5UL, 0x0075a8accfbdd11eUL) /* 557 */
+P( 6, 0xfbe85af0fea2c8fbUL, 0x007467ac557c228eUL) /* 563 */
+P( 6, 0x58a1f7e6ce0f4c09UL, 0x00732d70ed8db8e9UL) /* 569 */
+P( 2, 0x1a00e58c544986f3UL, 0x0072c62a24c3797fUL) /* 571 */
+P( 6, 0x7194a17f55a10dc1UL, 0x007194a17f55a10dUL) /* 577 */
+P(10, 0x7084944785e33763UL, 0x006fa549b41da7e7UL) /* 587 */
+P( 6, 0xba10679bd84886b1UL, 0x006e8419e6f61221UL) /* 593 */
+P( 6, 0xebe9c6bb31260967UL, 0x006d68b5356c207bUL) /* 599 */
+P( 2, 0x97a3fe4bd1ff25e9UL, 0x006d0b803685c01bUL) /* 601 */
+P( 6, 0x6c6388395b84d99fUL, 0x006bf790a8b2d207UL) /* 607 */
+P( 6, 0x8c51da6a1335df6dUL, 0x006ae907ef4b96c2UL) /* 613 */
+P( 4, 0x46f3234475d5add9UL, 0x006a37991a23aeadUL) /* 617 */
+P( 2, 0x905605ca3c619a43UL, 0x0069dfbdd4295b66UL) /* 619 */
+P(12, 0xcee8dff304767747UL, 0x0067dc4c45c8033eUL) /* 631 */
+P(10, 0xff99c27f00663d81UL, 0x00663d80ff99c27fUL) /* 641 */
+P( 2, 0xacca407f671ddc2bUL, 0x0065ec17e3559948UL) /* 643 */
+P( 4, 0xe71298bac1e12337UL, 0x00654ac835cfba5cUL) /* 647 */
+P( 6, 0xfa1e94309cd09045UL, 0x00645c854ae10772UL) /* 653 */
+P( 6, 0xbebccb8e91496b9bUL, 0x006372990e5f901fUL) /* 659 */
+P( 2, 0x312fa30cc7d7b8bdUL, 0x006325913c07beefUL) /* 661 */
+P(12, 0x6160ff9e9f006161UL, 0x006160ff9e9f0061UL) /* 673 */
+P( 4, 0x6b03673b5e28152dUL, 0x0060cdb520e5e88eUL) /* 677 */
+P( 6, 0xfe802ffa00bfe803UL, 0x005ff4017fd005ffUL) /* 683 */
+P( 8, 0xe66fe25c9e907c7bUL, 0x005ed79e31a4dccdUL) /* 691 */
+P(10, 0x3f8b236c76528895UL, 0x005d7d42d48ac5efUL) /* 701 */
+P( 8, 0xf6f923bf01ce2c0dUL, 0x005c6f35ccba5028UL) /* 709 */
+P(10, 0x6c3d3d98bed7c42fUL, 0x005b2618ec6ad0a5UL) /* 719 */
+P( 8, 0x30981efcd4b010e7UL, 0x005a2553748e42e7UL) /* 727 */
+P( 6, 0x6f691fc81ebbe575UL, 0x0059686cf744cd5bUL) /* 733 */
+P( 6, 0xb10480ddb47b52cbUL, 0x0058ae97bab79976UL) /* 739 */
+P( 4, 0x74cd59ed64f3f0d7UL, 0x0058345f1876865fUL) /* 743 */
+P( 8, 0x0105cb81316d6c0fUL, 0x005743d5bb24795aUL) /* 751 */
+P( 6, 0x9be64c6d91c1195dUL, 0x005692c4d1ab74abUL) /* 757 */
+P( 4, 0x71b3f945a27b1f49UL, 0x00561e46a4d5f337UL) /* 761 */
+P( 8, 0x77d80d50e508fd01UL, 0x005538ed06533997UL) /* 769 */
+P( 4, 0xa5eb778e133551cdUL, 0x0054c807f2c0bec2UL) /* 773 */
+P(14, 0x18657d3c2d8a3f1bUL, 0x005345efbc572d36UL) /* 787 */
+P(10, 0x2e40e220c34ad735UL, 0x00523a758f941345UL) /* 797 */
+P(12, 0xa76593c70a714919UL, 0x005102370f816c89UL) /* 809 */
+P( 2, 0x1eef452124eea383UL, 0x0050cf129fb94acfUL) /* 811 */
+P(10, 0x38206dc242ba771dUL, 0x004fd31941cafdd1UL) /* 821 */
+P( 2, 0x4cd4c35807772287UL, 0x004fa1704aa75945UL) /* 823 */
+P( 4, 0x83de917d5e69ddf3UL, 0x004f3ed6d45a63adUL) /* 827 */
+P( 2, 0x882ef0403b4a6c15UL, 0x004f0de57154ebedUL) /* 829 */
+P(10, 0xf8fb6c51c606b677UL, 0x004e1cae8815f811UL) /* 839 */
+P(14, 0xb4abaac446d3e1fdUL, 0x004cd47ba5f6ff19UL) /* 853 */
+P( 4, 0xa9f83bbe484a14e9UL, 0x004c78ae734df709UL) /* 857 */
+P( 2, 0x0bebbc0d1ce874d3UL, 0x004c4b19ed85cfb8UL) /* 859 */
+P( 4, 0xbd418eaf0473189fUL, 0x004bf093221d1218UL) /* 863 */
+P(14, 0x44e3af6f372b7e65UL, 0x004aba3c21dc633fUL) /* 877 */
+P( 4, 0xc87fdace4f9e5d91UL, 0x004a6360c344de00UL) /* 881 */
+P( 2, 0xec93479c446bd9bbUL, 0x004a383e9f74d68aUL) /* 883 */
+P( 4, 0xdac4d592e777c647UL, 0x0049e28fbabb9940UL) /* 887 */
+P(20, 0xa63ea8c8f61f0c23UL, 0x0048417b57c78cd7UL) /* 907 */
+P( 4, 0xe476062ea5cbbb6fUL, 0x0047f043713f3a2bUL) /* 911 */
+P( 8, 0xdf68761c69daac27UL, 0x00474ff2a10281cfUL) /* 919 */
+P(10, 0xb813d737637aa061UL, 0x00468b6f9a978f91UL) /* 929 */
+P( 8, 0xa3a77aac1fb15099UL, 0x0045f13f1caff2e2UL) /* 937 */
+P( 4, 0x17f0c3e0712c5825UL, 0x0045a5228cec23e9UL) /* 941 */
+P( 6, 0xfd912a70ff30637bUL, 0x0045342c556c66b9UL) /* 947 */
+P( 6, 0xfbb3b5dc01131289UL, 0x0044c4a23feeced7UL) /* 953 */
+P(14, 0x856d560a0f5acdf7UL, 0x0043c5c20d3c9fe6UL) /* 967 */
+P( 4, 0x96472f314d3f89e3UL, 0x00437e494b239798UL) /* 971 */
+P( 6, 0xa76f5c7ed2253531UL, 0x0043142d118e47cbUL) /* 977 */
+P( 6, 0x816eae7c7bf69fe7UL, 0x0042ab5c73a13458UL) /* 983 */
+P( 8, 0xb6a2bea4cfb1781fUL, 0x004221950db0f3dbUL) /* 991 */
+P( 6, 0xa3900c53318e81edUL, 0x0041bbb2f80a4553UL) /* 997 */
+P(12, 0x60aa7f5d9f148d11UL, 0x0040f391612c6680UL) /* 1009 */
+P( 4, 0x6be8c0102c7a505dUL, 0x0040b1e94173fefdUL) /* 1013 */
+P( 6, 0x8ff3f0ed28728f33UL, 0x004050647d9d0445UL) /* 1019 */
+P( 2, 0x680e0a87e5ec7155UL, 0x004030241b144f3bUL) /* 1021 */
+P(10, 0xbbf70fa49fe829b7UL, 0x003f90c2ab542cb1UL) /* 1031 */
+P( 2, 0xd69d1e7b6a50ca39UL, 0x003f71412d59f597UL) /* 1033 */
+P( 6, 0x1a1e0f46b6d26aefUL, 0x003f137701b98841UL) /* 1039 */
+P(10, 0x7429f9a7a8251829UL, 0x003e79886b60e278UL) /* 1049 */
+P( 2, 0xd9c2219d1b863613UL, 0x003e5b1916a7181dUL) /* 1051 */
+P(10, 0x91406c1820d077adUL, 0x003dc4a50968f524UL) /* 1061 */
+P( 2, 0x521f4ec02e3d2b97UL, 0x003da6e4c9550321UL) /* 1063 */
+P( 6, 0xbb8283b63dc8eba5UL, 0x003d4e4f06f1def3UL) /* 1069 */
+P(18, 0x431eda153229ebbfUL, 0x003c4a6bdd24f9a4UL) /* 1087 */
+P( 4, 0xaf0bf78d7e01686bUL, 0x003c11d54b525c73UL) /* 1091 */
+P( 2, 0xa9ced0742c086e8dUL, 0x003bf5b1c5721065UL) /* 1093 */
+P( 4, 0xc26458ad9f632df9UL, 0x003bbdb9862f23b4UL) /* 1097 */
+P( 6, 0xbbff1255dff892afUL, 0x003b6a8801db5440UL) /* 1103 */
+P( 6, 0xcbd49a333f04d8fdUL, 0x003b183cf0fed886UL) /* 1109 */
+P( 8, 0xec84ed6f9cfdeff5UL, 0x003aabe394bdc3f4UL) /* 1117 */
+P( 6, 0x97980cc40bda9d4bUL, 0x003a5ba3e76156daUL) /* 1123 */
+P( 6, 0x777f34d524f5cbd9UL, 0x003a0c3e953378dbUL) /* 1129 */
+P(22, 0x2797051d94cbbb7fUL, 0x0038f03561320b1eUL) /* 1151 */
+P( 2, 0xea769051b4f43b81UL, 0x0038d6ecaef5908aUL) /* 1153 */
+P(10, 0xce7910f3034d4323UL, 0x003859cf221e6069UL) /* 1163 */
+P( 8, 0x92791d1374f5b99bUL, 0x0037f7415dc9588aUL) /* 1171 */
+P(10, 0x89a5645cc68ea1b5UL, 0x00377df0d3902626UL) /* 1181 */
+P( 6, 0x5f8aacf796c0cf0bUL, 0x00373622136907faUL) /* 1187 */
+P( 6, 0xf2e90a15e33edf99UL, 0x0036ef0c3b39b92fUL) /* 1193 */
+P( 8, 0x8e99e5feb897c451UL, 0x0036915f47d55e6dUL) /* 1201 */
+P(12, 0xaca2eda38fb91695UL, 0x0036072cf3f866fdUL) /* 1213 */
+P( 4, 0x5d9b737be5ea8b41UL, 0x0035d9b737be5ea8UL) /* 1217 */
+P( 6, 0x4aefe1db93fd7cf7UL, 0x0035961559cc81c7UL) /* 1223 */
+P( 6, 0xa0994ef20b3f8805UL, 0x0035531c897a4592UL) /* 1229 */
+P( 2, 0x103890bda912822fUL, 0x00353ceebd3e98a4UL) /* 1231 */
+P( 6, 0xb441659d13a9147dUL, 0x0034fad381585e5eUL) /* 1237 */
+P(12, 0x1e2134440c4c3f21UL, 0x00347884d1103130UL) /* 1249 */
+P(10, 0x263a27727a6883c3UL, 0x00340dd3ac39bf56UL) /* 1259 */
+P(18, 0x78e221472ab33855UL, 0x003351fdfecc140cUL) /* 1277 */
+P( 2, 0x95eac88e82e6faffUL, 0x00333d72b089b524UL) /* 1279 */
+P( 4, 0xf66c258317be8dabUL, 0x0033148d44d6b261UL) /* 1283 */
+P( 6, 0x09ee202c7cb91939UL, 0x0032d7aef8412458UL) /* 1289 */
+P( 2, 0x8d2fca1042a09ea3UL, 0x0032c3850e79c0f1UL) /* 1291 */
+P( 6, 0x82779c856d8b8bf1UL, 0x00328766d59048a2UL) /* 1297 */
+P( 4, 0x3879361cba8a223dUL, 0x00325fa18cb11833UL) /* 1301 */
+P( 2, 0xf23f43639c3182a7UL, 0x00324bd659327e22UL) /* 1303 */
+P( 4, 0xa03868fc474bcd13UL, 0x0032246e784360f4UL) /* 1307 */
+P(12, 0x651e78b8c5311a97UL, 0x0031afa5f1a33a08UL) /* 1319 */
+P( 2, 0x8ffce639c00c6719UL, 0x00319c63ff398e70UL) /* 1321 */
+P( 6, 0xf7b460754b0b61cfUL, 0x003162f7519a86a7UL) /* 1327 */
+P(34, 0x7b03f3359b8e63b1UL, 0x0030271fc9d3fc3cUL) /* 1361 */
+P( 6, 0xa55c5326041eb667UL, 0x002ff104ae89750bUL) /* 1367 */
+P( 6, 0x647f88ab896a76f5UL, 0x002fbb62a236d133UL) /* 1373 */
+P( 8, 0x8fd971434a55a46dUL, 0x002f74997d2070b4UL) /* 1381 */
+P(18, 0x9fbf969958046447UL, 0x002ed84aa8b6fce3UL) /* 1399 */
+P(10, 0x9986feba69be3a81UL, 0x002e832df7a46dbdUL) /* 1409 */
+P(14, 0xa668b3e6d053796fUL, 0x002e0e0846857cabUL) /* 1423 */
+P( 4, 0x97694e6589f4e09bUL, 0x002decfbdfb55ee6UL) /* 1427 */
+P( 2, 0x37890c00b7721dbdUL, 0x002ddc876f3ff488UL) /* 1429 */
+P( 4, 0x5ac094a235f37ea9UL, 0x002dbbc1d4c482c4UL) /* 1433 */
+P( 6, 0x31cff775f2d5d65fUL, 0x002d8af0e0de0556UL) /* 1439 */
+P( 8, 0xddad8e6b36505217UL, 0x002d4a7b7d14b30aUL) /* 1447 */
+P( 4, 0x5a27df897062cd03UL, 0x002d2a85073bcf4eUL) /* 1451 */
+P( 2, 0xe2396fe0fdb5a625UL, 0x002d1a9ab13e8be4UL) /* 1453 */
+P( 6, 0xb352a4957e82317bUL, 0x002ceb1eb4b9fd8bUL) /* 1459 */
+P(12, 0xd8ab3f2c60c2ea3fUL, 0x002c8d503a79794cUL) /* 1471 */
+P(10, 0x6893f702f0452479UL, 0x002c404d708784edUL) /* 1481 */
+P( 2, 0x9686fdc182acf7e3UL, 0x002c31066315ec52UL) /* 1483 */
+P( 4, 0x6854037173dce12fUL, 0x002c1297d80f2664UL) /* 1487 */
+P( 2, 0x7f0ded1685c27331UL, 0x002c037044c55f6bUL) /* 1489 */
+P( 4, 0xeeda72e1fe490b7dUL, 0x002be5404cd13086UL) /* 1493 */
+P( 6, 0x9e7bfc959a8e6e53UL, 0x002bb845adaf0cceUL) /* 1499 */
+P(12, 0x49b314d6d4753dd7UL, 0x002b5f62c639f16dUL) /* 1511 */
+P(12, 0x2e8f8c5ac4aa1b3bUL, 0x002b07e6734f2b88UL) /* 1523 */
+P( 8, 0xb8ef723481163d33UL, 0x002ace569d8342b7UL) /* 1531 */
+P(12, 0x6a2ec96a594287b7UL, 0x002a791d5dbd4dcfUL) /* 1543 */
+P( 6, 0xdba41c6d13aab8c5UL, 0x002a4eff8113017cUL) /* 1549 */
+P( 4, 0xc2adbe648dc3aaf1UL, 0x002a3319e156df32UL) /* 1553 */
+P( 6, 0x87a2bade565f91a7UL, 0x002a0986286526eaUL) /* 1559 */
+P( 8, 0x4d6fe8798c01f5dfUL, 0x0029d29551d91e39UL) /* 1567 */
+P( 4, 0x3791310c8c23d98bUL, 0x0029b7529e109f0aUL) /* 1571 */
+P( 8, 0xf80e446b01228883UL, 0x00298137491ea465UL) /* 1579 */
+P( 4, 0x9aed1436fbf500cfUL, 0x0029665e1eb9f9daUL) /* 1583 */
+P(14, 0x7839b54cc8b24115UL, 0x002909752e019a5eUL) /* 1597 */
+P( 4, 0xc128c646ad0309c1UL, 0x0028ef35e2e5efb0UL) /* 1601 */
+P( 6, 0x14de631624a3c377UL, 0x0028c815aa4b8278UL) /* 1607 */
+P( 2, 0x3f7b9fe68b0ecbf9UL, 0x0028bb1b867199daUL) /* 1609 */
+P( 4, 0x284ffd75ec00a285UL, 0x0028a13ff5d7b002UL) /* 1613 */
+P( 6, 0x37803cb80dea2ddbUL, 0x00287ab3f173e755UL) /* 1619 */
+P( 2, 0x86b63f7c9ac4c6fdUL, 0x00286dead67713bdUL) /* 1621 */
+P( 6, 0x8b6851d1bd99b9d3UL, 0x002847bfcda6503eUL) /* 1627 */
+P(10, 0xb62fda77ca343b6dUL, 0x002808c1ea6b4777UL) /* 1637 */
+P(20, 0x1f0dc009e34383c9UL, 0x00278d0e0f23ff61UL) /* 1657 */
+P( 6, 0x496dc21ddd35b97fUL, 0x002768863c093c7fUL) /* 1663 */
+P( 4, 0xb0e96ce17090f82bUL, 0x0027505115a73ca8UL) /* 1667 */
+P( 2, 0xaadf05acdd7d024dUL, 0x00274441a61dc1b9UL) /* 1669 */
+P(24, 0xcb138196746eafb5UL, 0x0026b5c166113cf0UL) /* 1693 */
+P( 4, 0x347f523736755d61UL, 0x00269e65ad07b18eUL) /* 1697 */
+P( 2, 0xd14a48a051f7dd0bUL, 0x002692c25f877560UL) /* 1699 */
+P(10, 0x474d71b1ce914d25UL, 0x002658fa7523cd11UL) /* 1709 */
+P(12, 0x386063f5e28c1f89UL, 0x0026148710cf0f9eUL) /* 1721 */
+P( 2, 0x1db7325e32d04e73UL, 0x002609363b22524fUL) /* 1723 */
+P(10, 0xfef748d3893b880dUL, 0x0025d1065a1c1122UL) /* 1733 */
+P( 8, 0x2f3351506e935605UL, 0x0025a48a382b863fUL) /* 1741 */
+P( 6, 0x7a3637fa2376415bUL, 0x0025837190eccdbcUL) /* 1747 */
+P( 6, 0x4ac525d2baa21969UL, 0x00256292e95d510cUL) /* 1753 */
+P( 6, 0x3a11c16b42cd351fUL, 0x002541eda98d068cUL) /* 1759 */
+P(18, 0x6c7abde0049c2a11UL, 0x0024e15087fed8f5UL) /* 1777 */
+P( 6, 0x54dad0303e069ac7UL, 0x0024c18b20979e5dUL) /* 1783 */
+P( 4, 0xebf1ac9fdfe91433UL, 0x0024ac7b336de0c5UL) /* 1787 */
+P( 2, 0xfafdda8237cec655UL, 0x0024a1fc478c60bbUL) /* 1789 */
+P(12, 0xdce3ff6e71ffb739UL, 0x002463801231c009UL) /* 1801 */
+P(10, 0xbed5737d6286db1bUL, 0x0024300fd506ed33UL) /* 1811 */
+P(12, 0xe479e431fe08b4dfUL, 0x0023f314a494da81UL) /* 1823 */
+P( 8, 0x9dd9b0dd7742f897UL, 0x0023cadedd2fad3aUL) /* 1831 */
+P(16, 0x8f09d7402c5a5e87UL, 0x00237b7ed2664a03UL) /* 1847 */
+P(14, 0x9216d5c4d958738dUL, 0x0023372967dbaf1dUL) /* 1861 */
+P( 6, 0xb3139ba11d34ca63UL, 0x00231a308a371f20UL) /* 1867 */
+P( 4, 0x47d54f7ed644afafUL, 0x002306fa63e1e600UL) /* 1871 */
+P( 2, 0x92a81d85cf11a1b1UL, 0x0022fd6731575684UL) /* 1873 */
+P( 4, 0x754b26533253bdfdUL, 0x0022ea507805749cUL) /* 1877 */
+P( 2, 0xbbe0efc980bfd467UL, 0x0022e0cce8b3d720UL) /* 1879 */
+P(10, 0xc0d8d594f024dca1UL, 0x0022b1887857d161UL) /* 1889 */
+P(12, 0x8238d43bcaac1a65UL, 0x00227977fcc49cc0UL) /* 1901 */
+P( 6, 0x27779c1fae6175bbUL, 0x00225db37b5e5f4fUL) /* 1907 */
+P( 6, 0xa746ca9af708b2c9UL, 0x0022421b91322ed6UL) /* 1913 */
+P(18, 0x93f3cd9f389be823UL, 0x0021f05b35f52102UL) /* 1931 */
+P( 2, 0x5cb4a4c04c489345UL, 0x0021e75de5c70d60UL) /* 1933 */
+P(16, 0xbf6047743e85b6b5UL, 0x0021a01d6c19be96UL) /* 1949 */
+P( 2, 0x61c147831563545fUL, 0x0021974a6615c81aUL) /* 1951 */
+P(22, 0xedb47c0ae62dee9dUL, 0x00213767697cf36aUL) /* 1973 */
+P( 6, 0x0a3824386673a573UL, 0x00211d9f7fad35f1UL) /* 1979 */
+P( 8, 0xa4a77d19e575a0ebUL, 0x0020fb7d9dd36c18UL) /* 1987 */
+P( 6, 0xa2bee045e066c279UL, 0x0020e2123d661e0eUL) /* 1993 */
+P( 4, 0xc23618de8ab43d05UL, 0x0020d135b66ae990UL) /* 1997 */
+P( 2, 0x266b515216cb9f2fUL, 0x0020c8cded4d7a8eUL) /* 1999 */
+P( 4, 0xe279edd9e9c2e85bUL, 0x0020b80b3f43ddbfUL) /* 2003 */
+P( 8, 0xd0c591c221dc9c53UL, 0x002096b9180f46a6UL) /* 2011 */
+P( 6, 0x06da8ee9c9ee7c21UL, 0x00207de7e28de5daUL) /* 2017 */
+P(10, 0x9dfebcaf4c27e8c3UL, 0x002054dec8cf1fb3UL) /* 2027 */
+P( 2, 0x49aeff9f19dd6de5UL, 0x00204cb630b3aab5UL) /* 2029 */
+P(10, 0x86976a57a296e9c7UL, 0x00202428adc37bebUL) /* 2039 */
+P(14, 0xa3b9abf4872b84cdUL, 0x001fec0c7834def4UL) /* 2053 */
+P(10, 0x34fca6483895e6efUL, 0x001fc46fae98a1d0UL) /* 2063 */
+P( 6, 0x34b5a333988f873dUL, 0x001facda430ff619UL) /* 2069 */
+P(12, 0xd9dd4f19b5f17be1UL, 0x001f7e17dd8e15e5UL) /* 2081 */
+P( 2, 0xb935b507fd0ce78bUL, 0x001f765a3556a4eeUL) /* 2083 */
+P( 4, 0xb450f5540660e797UL, 0x001f66ea49d802f1UL) /* 2087 */
+P( 2, 0x63ff82831ffc1419UL, 0x001f5f3800faf9c0UL) /* 2089 */
+P(10, 0x8992f718c22a32fbUL, 0x001f38f4e6c0f1f9UL) /* 2099 */
+P(12, 0x5f3253ad0d37e7bfUL, 0x001f0b8546752578UL) /* 2111 */
+P( 2, 0x007c0ffe0fc007c1UL, 0x001f03ff83f001f0UL) /* 2113 */
+P(16, 0x4d8ebadc0c0640b1UL, 0x001ec853b0a3883cUL) /* 2129 */
+P( 2, 0xe2729af831037bdbUL, 0x001ec0ee573723ebUL) /* 2131 */
+P( 6, 0xb8f64bf30feebfe9UL, 0x001eaad38e6f6894UL) /* 2137 */
+P( 4, 0xda93124b544c0bf5UL, 0x001e9c28a765fe53UL) /* 2141 */
+P( 2, 0x9cf7ff0b593c539fUL, 0x001e94d8758c2003UL) /* 2143 */
+P(10, 0xd6bd8861fa0e07d9UL, 0x001e707ba8f65e68UL) /* 2153 */
+P( 8, 0x5cfe75c0bd8ab891UL, 0x001e53a2a68f574eUL) /* 2161 */
+P(18, 0x43e808757c2e862bUL, 0x001e1380a56b438dUL) /* 2179 */
+P(24, 0x90caa96d595c9d93UL, 0x001dbf9f513a3802UL) /* 2203 */
+P( 4, 0x8fd550625d07135fUL, 0x001db1d1d58bc600UL) /* 2207 */
+P( 6, 0x76b010a86e209f2dUL, 0x001d9d358f53de38UL) /* 2213 */
+P( 8, 0xecc0426447769b25UL, 0x001d81e6df6165c7UL) /* 2221 */
+P(16, 0xe381339caabe3295UL, 0x001d4bdf7fd40e30UL) /* 2237 */
+P( 2, 0xd1b190a2d0c7673fUL, 0x001d452c7a1c958dUL) /* 2239 */
+P( 4, 0xc3bce3cf26b0e7ebUL, 0x001d37cf9b902659UL) /* 2243 */
+P( 8, 0x5f87e76f56c61ce3UL, 0x001d1d3a5791e97bUL) /* 2251 */
+P(16, 0xc06c6857a124b353UL, 0x001ce89fe6b47416UL) /* 2267 */
+P( 2, 0x38c040fcba630f75UL, 0x001ce219f3235071UL) /* 2269 */
+P( 4, 0xd078bc4fbd533b21UL, 0x001cd516dcf92139UL) /* 2273 */
+P( 8, 0xde8e15c5dd354f59UL, 0x001cbb33bd1c2b8bUL) /* 2281 */
+P( 6, 0xca61d53d7414260fUL, 0x001ca7e7d2546688UL) /* 2287 */
+P( 6, 0xb56bf5ba8eae635dUL, 0x001c94b5c1b3dbd3UL) /* 2293 */
+P( 4, 0x44a72cb0fb6e3949UL, 0x001c87f7f9c241c1UL) /* 2297 */
+P(12, 0x879839a714f45bcdUL, 0x001c6202706c35a9UL) /* 2309 */
+P( 2, 0x02a8994fde5314b7UL, 0x001c5bb8a9437632UL) /* 2311 */
+P(22, 0xb971920cf2b90135UL, 0x001c174343b4111eUL) /* 2333 */
+P( 6, 0x8a8fd0b7df9a6e8bUL, 0x001c04d0d3e46b42UL) /* 2339 */
+P( 2, 0xb31f9a84c1c6eaadUL, 0x001bfeb00fbf4308UL) /* 2341 */
+P( 6, 0x92293b02823c6d83UL, 0x001bec5dce0b202dUL) /* 2347 */
+P( 4, 0xeee77ff20fe5ddcfUL, 0x001be03444620037UL) /* 2351 */
+P( 6, 0x0e1ea0f6c496c11dUL, 0x001bce09c66f6fc3UL) /* 2357 */
+P(14, 0xfdf2d3d6f88ccb6bUL, 0x001ba40228d02b30UL) /* 2371 */
+P( 6, 0xfa9d74a3457738f9UL, 0x001b9225b1cf8919UL) /* 2377 */
+P( 4, 0xefc3ca3db71a5785UL, 0x001b864a2ff3f53fUL) /* 2381 */
+P( 2, 0x8e2071718d0d6dafUL, 0x001b80604150e49bUL) /* 2383 */
+P( 6, 0xbc0fdbfeb6cfabfdUL, 0x001b6eb1aaeaacf3UL) /* 2389 */
+P( 4, 0x1eeab613e5e5aee9UL, 0x001b62f48da3c8ccUL) /* 2393 */
+P( 6, 0x2d2388e90e9e929fUL, 0x001b516babe96092UL) /* 2399 */
+P(12, 0x81dbafba588ddb43UL, 0x001b2e9cef1e0c87UL) /* 2411 */
+P( 6, 0x52eebc51c4799791UL, 0x001b1d56bedc849bUL) /* 2417 */
+P( 6, 0x1c6bc4693b45a047UL, 0x001b0c267546aec0UL) /* 2423 */
+P(14, 0x06eee0974498874dUL, 0x001ae45f62024fa0UL) /* 2437 */
+P( 4, 0xd85b7377a9953cb9UL, 0x001ad917631b5f54UL) /* 2441 */
+P( 6, 0x4b6df412d4caf56fUL, 0x001ac83d18cb608fUL) /* 2447 */
+P(12, 0x6b8afbbb4a053493UL, 0x001aa6c7ad8c063fUL) /* 2459 */
+P( 8, 0xcc5299c96ac7720bUL, 0x001a90a7b1228e2aUL) /* 2467 */
+P( 6, 0xadce84b5c710aa99UL, 0x001a8027c03ba059UL) /* 2473 */
+P( 4, 0x9d673f5aa3804225UL, 0x001a7533289deb89UL) /* 2477 */
+P(26, 0xe6541268efbce7f7UL, 0x001a2ed7ce16b49fUL) /* 2503 */
+P(18, 0xfcf41e76cf5be669UL, 0x0019fefc0a279a73UL) /* 2521 */
+P(10, 0x5c3eb5dc31c383cbUL, 0x0019e4b0cd873b5fUL) /* 2531 */
+P( 8, 0x301832d11d8ad6c3UL, 0x0019cfcdfd60e514UL) /* 2539 */
+P( 4, 0x2e9c0942f1ce450fUL, 0x0019c56932d66c85UL) /* 2543 */
+P( 6, 0x97f3f2be37a39a5dUL, 0x0019b5e1ab6fc7c2UL) /* 2549 */
+P( 2, 0xe8b7d8a9654187c7UL, 0x0019b0b8a62f2a73UL) /* 2551 */
+P( 6, 0xb5d024d7da5b1b55UL, 0x0019a149fc98942cUL) /* 2557 */
+P(22, 0xb8ba9d6e7ae3501bUL, 0x001969517ec25b85UL) /* 2579 */
+P(12, 0xf50865f71b90f1dfUL, 0x00194b3083360ba8UL) /* 2591 */
+P( 2, 0x739c1682847df9e1UL, 0x00194631f4bebdc1UL) /* 2593 */
+P(16, 0xc470a4d842b90ed1UL, 0x00191e84127268fdUL) /* 2609 */
+P( 8, 0x1fb1be11698cc409UL, 0x00190adbb543984fUL) /* 2617 */
+P( 4, 0xd8d5512a7cd35d15UL, 0x001901130bd18200UL) /* 2621 */
+P(12, 0xa5496821723e07f9UL, 0x0018e3e6b889ac94UL) /* 2633 */
+P(14, 0xbcc8c6d7abaa8167UL, 0x0018c233420e1ec1UL) /* 2647 */
+P(10, 0x52c396c95eb619a1UL, 0x0018aa5872d92bd6UL) /* 2657 */
+P( 2, 0x6eb7e380878ec74bUL, 0x0018a5989945ccf9UL) /* 2659 */
+P( 4, 0x3d5513b504537157UL, 0x00189c1e60b57f60UL) /* 2663 */
+P( 8, 0x314391f8862e948fUL, 0x0018893fbc8690b9UL) /* 2671 */
+P( 6, 0xdc0b17cfcd81f5ddUL, 0x00187b2bb3e1041cUL) /* 2677 */
+P( 6, 0x2f6bea3ec89044b3UL, 0x00186d27c9cdcfb8UL) /* 2683 */
+P( 4, 0xce13a05869f1b57fUL, 0x001863d8bf4f2c1cUL) /* 2687 */
+P( 2, 0x7593474e8ace3581UL, 0x00185f33e2ad7593UL) /* 2689 */
+P( 4, 0x07fc329295a05e4dUL, 0x001855ef75973e13UL) /* 2693 */
+P( 6, 0xb05377cba4908d23UL, 0x001848160153f134UL) /* 2699 */
+P( 8, 0xe7b2131a628aa39bUL, 0x001835b72e6f0656UL) /* 2707 */
+P( 4, 0x9031dbed7de01527UL, 0x00182c922d83eb39UL) /* 2711 */
+P( 2, 0x76844b1c670aa9a9UL, 0x0018280243c0365aUL) /* 2713 */
+P( 6, 0x6a03f4533b08915fUL, 0x00181a5cd5898e73UL) /* 2719 */
+P(10, 0x1dbca579db0a3999UL, 0x001803c0961773aaUL) /* 2729 */
+P( 2, 0x002ffe800bffa003UL, 0x0017ff4005ffd001UL) /* 2731 */
+P(10, 0x478ab1a3e936139dUL, 0x0017e8d670433edbUL) /* 2741 */
+P( 8, 0x66e722bc4c5cc095UL, 0x0017d7066cf4bb5dUL) /* 2749 */
+P( 4, 0x7a8f63c717278541UL, 0x0017ce285b806b1fUL) /* 2753 */
+P(14, 0xdf6eee24d292bc2fUL, 0x0017af52cdf27e02UL) /* 2767 */
+P(10, 0x9fc20d17237dd569UL, 0x0017997d47d01039UL) /* 2777 */
+P(12, 0xcdf9932356bda2edUL, 0x00177f7ec2c6d0baUL) /* 2789 */
+P( 2, 0x97b5e332e80f68d7UL, 0x00177b2f3cd00756UL) /* 2791 */
+P( 6, 0x46eee26fd875e2e5UL, 0x00176e4a22f692a0UL) /* 2797 */
+P( 4, 0x3548a8e65157a611UL, 0x001765b94271e11bUL) /* 2801 */
+P( 2, 0xc288d03be9b71e3bUL, 0x001761732b044ae4UL) /* 2803 */
+P(16, 0x8151186db38937abUL, 0x00173f7a5300a2bcUL) /* 2819 */
+P(14, 0x7800b910895a45f1UL, 0x001722112b48be1fUL) /* 2833 */
+P( 4, 0xaee0b024182eec3dUL, 0x001719b7a16eb843UL) /* 2837 */
+P( 6, 0x96323eda173b5713UL, 0x00170d3c99cc5052UL) /* 2843 */
+P( 8, 0x0ed0dbd03ae77c8bUL, 0x0016fcad7aed3bb6UL) /* 2851 */
+P( 6, 0xf73800b7828dc119UL, 0x0016f051b8231ffdUL) /* 2857 */
+P( 4, 0x1b61715ec22b7ca5UL, 0x0016e81beae20643UL) /* 2861 */
+P(18, 0xa8533a991ead64bfUL, 0x0016c3721584c1d8UL) /* 2879 */
+P( 8, 0x7f6c7290e46c2e77UL, 0x0016b34c2ba09663UL) /* 2887 */
+P(10, 0x6325e8d907b01db1UL, 0x00169f3ce292ddcdUL) /* 2897 */
+P( 6, 0x28909f70152a1067UL, 0x00169344b2220a0dUL) /* 2903 */
+P( 6, 0xea7077af0997a0f5UL, 0x001687592593c1b1UL) /* 2909 */
+P( 8, 0x7e605cad10c32e6dUL, 0x00167787f1418ec9UL) /* 2917 */
+P(10, 0x471b33570635b38fUL, 0x001663e190395ff2UL) /* 2927 */
+P(12, 0xab559fa997a61bb3UL, 0x00164c7a4b6eb5b3UL) /* 2939 */
+P(14, 0xad4bdae562bddab9UL, 0x0016316a061182fdUL) /* 2953 */
+P( 4, 0x055e1b2f2ed62f45UL, 0x001629ba914584e4UL) /* 2957 */
+P( 6, 0x03cd328b1a2dca9bUL, 0x00161e3d57de21b2UL) /* 2963 */
+P( 6, 0xd28f4e08733218a9UL, 0x001612cc01b977f0UL) /* 2969 */
+P( 2, 0xb6800b077f186293UL, 0x00160efe30c525ffUL) /* 2971 */
+P(28, 0x6fbd138c3fd9c207UL, 0x0015da45249ec5deUL) /* 2999 */
+P( 2, 0xb117ccd12ae88a89UL, 0x0015d68ab4acff92UL) /* 3001 */
+P(10, 0x2f1a1a044046bcebUL, 0x0015c3f989d1eb15UL) /* 3011 */
+P( 8, 0x548aba0b060541e3UL, 0x0015b535ad11b8f0UL) /* 3019 */
+P( 4, 0xcf4e808cea111b2fUL, 0x0015addb3f424ec1UL) /* 3023 */
+P(14, 0xdbec1b4fa855a475UL, 0x00159445cb91be6bUL) /* 3037 */
+P( 4, 0xe3f794eb600d7821UL, 0x00158d0199771e63UL) /* 3041 */
+P( 8, 0x34fae0d9a11f7c59UL, 0x00157e87d9b69e04UL) /* 3049 */
+P(12, 0xf006b0ccbbac085dUL, 0x001568f58bc01ac3UL) /* 3061 */
+P( 6, 0x3f45076dc3114733UL, 0x00155e3c993fda9bUL) /* 3067 */
+P(12, 0xeef49bfa58a1a1b7UL, 0x001548eacc5e1e6eUL) /* 3079 */
+P( 4, 0x12c4218bea691fa3UL, 0x001541d8f91ba6a7UL) /* 3083 */
+P( 6, 0xbc7504e3bd5e64f1UL, 0x00153747060cc340UL) /* 3089 */
+P(20, 0x4ee21c292bb92fadUL, 0x001514569f93f7c4UL) /* 3109 */
+P(10, 0x34338b7327a4bacfUL, 0x00150309705d3d79UL) /* 3119 */
+P( 2, 0x3fe5c0833d6fccd1UL, 0x0014ff97020cf5bfUL) /* 3121 */
+P(16, 0xb1e70743535203c1UL, 0x0014e42c114cf47eUL) /* 3137 */
+P(26, 0xefbb5dcdfb4e43d3UL, 0x0014b835bdcb6447UL) /* 3163 */
+P( 4, 0xca68467ca5394f9fUL, 0x0014b182b53a9ab7UL) /* 3167 */
+P( 2, 0x8c51c081408b97a1UL, 0x0014ae2ad094a3d3UL) /* 3169 */
+P(12, 0x3275a899dfa5dd65UL, 0x00149a320ea59f96UL) /* 3181 */
+P( 6, 0x9e674cb62e1b78bbUL, 0x001490441de1a2fbUL) /* 3187 */
+P( 4, 0xa37ff5bb2a998d47UL, 0x001489aacce57200UL) /* 3191 */
+P(12, 0x792a999db131a22bUL, 0x001475f82ad6ff99UL) /* 3203 */
+P( 6, 0x1b48841bc30d29b9UL, 0x00146c2cfe53204fUL) /* 3209 */
+P( 8, 0xf06721d2011d3471UL, 0x00145f2ca490d4a1UL) /* 3217 */
+P( 4, 0x93fd2386dff85ebdUL, 0x001458b2aae0ec87UL) /* 3221 */
+P( 8, 0x4ce72f54c07ed9b5UL, 0x00144bcb0a3a3150UL) /* 3229 */
+P(22, 0xd6d0fd3e71dd827bUL, 0x001428a1e65441d4UL) /* 3251 */
+P( 2, 0x856405fb1eed819dUL, 0x00142575a6c210d7UL) /* 3253 */
+P( 4, 0x8ea8aceb7c443989UL, 0x00141f2025ba5c46UL) /* 3257 */
+P( 2, 0x34a13026f62e5873UL, 0x00141bf6e35420fdUL) /* 3259 */
+P(12, 0x1eea0208ec0af4f7UL, 0x001409141d1d313aUL) /* 3271 */
+P(28, 0x63679853cea598cbUL, 0x0013dd8bc19c3513UL) /* 3299 */
+P( 2, 0xc30b3ebd61f2d0edUL, 0x0013da76f714dc8fUL) /* 3301 */
+P( 6, 0x7eb9037bc7f43bc3UL, 0x0013d13e50f8f49eUL) /* 3307 */
+P( 6, 0xa583e6f6ce016411UL, 0x0013c80e37ca3819UL) /* 3313 */
+P( 6, 0xf1938d895f1a74c7UL, 0x0013bee69fa99ccfUL) /* 3319 */
+P( 4, 0x80cf1491c1e81e33UL, 0x0013b8d0ede55835UL) /* 3323 */
+P( 6, 0x3c0f12886ba8f301UL, 0x0013afb7680bb054UL) /* 3329 */
+P( 2, 0x0e4b786e0dfcc5abUL, 0x0013acb0c3841c96UL) /* 3331 */
+P(12, 0x672684c93f2d41efUL, 0x00139a9c5f434fdeUL) /* 3343 */
+P( 4, 0xe00757badb35c51bUL, 0x0013949cf33a0d9dUL) /* 3347 */
+P(12, 0xd6d84afe66472edfUL, 0x001382b4a00c31b0UL) /* 3359 */
+P( 2, 0xfbbc0eedcbbfb6e1UL, 0x00137fbbc0eedcbbUL) /* 3361 */
+P(10, 0x250f43aa08a84983UL, 0x001370ecf047b069UL) /* 3371 */
+P( 2, 0x04400e927b1acaa5UL, 0x00136df9790e3155UL) /* 3373 */
+P(16, 0x56572be34b9d3215UL, 0x0013567dd8defd5bUL) /* 3389 */
+P( 2, 0x87964ef7781c62bfUL, 0x0013539261fdbc34UL) /* 3391 */
+P(16, 0x29ed84051c06e9afUL, 0x00133c564292d28aUL) /* 3407 */
+P( 6, 0xb00acd11ed3f87fdUL, 0x001333ae178d6388UL) /* 3413 */
+P(20, 0x06307881744152d9UL, 0x0013170ad00d1fd7UL) /* 3433 */
+P(16, 0x7a786459f5c1ccc9UL, 0x0013005f01db0947UL) /* 3449 */
+P( 8, 0x1308125d74563281UL, 0x0012f51d40342210UL) /* 3457 */
+P( 4, 0x395310a480b3e34dUL, 0x0012ef815e4ed950UL) /* 3461 */
+P( 2, 0x35985baa8b202837UL, 0x0012ecb4abccd827UL) /* 3463 */
+P( 4, 0x96304a6e052b3223UL, 0x0012e71dc1d3d820UL) /* 3467 */
+P( 2, 0xbd8265fc9af8fd45UL, 0x0012e45389a16495UL) /* 3469 */
+P(22, 0x1b6d0b383ec58e0bUL, 0x0012c5d9226476ccUL) /* 3491 */
+P( 8, 0xc21a7c3b68b28503UL, 0x0012badc391156fdUL) /* 3499 */
+P(12, 0x236fa180fbfd6007UL, 0x0012aa78e412f522UL) /* 3511 */
+P( 6, 0xc42accd440ed9595UL, 0x0012a251f5f47fd1UL) /* 3517 */
+P(10, 0x7acf7128236ba3f7UL, 0x001294cb85c53534UL) /* 3527 */
+P( 2, 0xf909367a987b9c79UL, 0x0012921963beb65eUL) /* 3529 */
+P( 4, 0xb64efb252bfba705UL, 0x00128cb777c69ca8UL) /* 3533 */
+P( 6, 0x980d4f5a7e4cd25bUL, 0x001284aa6cf07294UL) /* 3539 */
+P( 2, 0xe1ecc4ef27b0c37dUL, 0x001281fcf6ac7f87UL) /* 3541 */
+P( 6, 0x9111aebb81d72653UL, 0x001279f937367db9UL) /* 3547 */
+P(10, 0x8951f985cb2c67edUL, 0x00126cad0488be94UL) /* 3557 */
+P( 2, 0xc439d4fc54e0b5d7UL, 0x00126a06794646a2UL) /* 3559 */
+P(12, 0xe857bf31896d533bUL, 0x00125a2f2bcd3e95UL) /* 3571 */
+P(10, 0xb614bb4cb5023755UL, 0x00124d108389e6b1UL) /* 3581 */
+P( 2, 0x938a89e5473bf1ffUL, 0x00124a73083771acUL) /* 3583 */
+P(10, 0xeac481aca34de039UL, 0x00123d6acda0620aUL) /* 3593 */
+P(14, 0x14b961badf4809a7UL, 0x00122b4b2917eafdUL) /* 3607 */
+P( 6, 0x76784fecba352435UL, 0x00122391bfce1e2fUL) /* 3613 */
+P( 4, 0xefa689bb58aef5e1UL, 0x00121e6f1ea579f2UL) /* 3617 */
+P( 6, 0xb2b2c4db9c3a8197UL, 0x001216c09e471568UL) /* 3623 */
+P( 8, 0x2503bc992279f8cfUL, 0x00120c8cb9d93909UL) /* 3631 */
+P( 6, 0xd2ab9aec5ca1541dUL, 0x001204ed58e64ef9UL) /* 3637 */
+P( 6, 0x3e78ba1460f99af3UL, 0x0011fd546578f00cUL) /* 3643 */
+P(16, 0x0a01426572cfcb63UL, 0x0011e9310b8b4c9cUL) /* 3659 */
+P(12, 0xbea857968f3cbd67UL, 0x0011da3405db9911UL) /* 3671 */
+P( 2, 0x78db213eefe659e9UL, 0x0011d7b6f4eb055dUL) /* 3673 */
+P( 4, 0x963e8541a74d35f5UL, 0x0011d2bee748c145UL) /* 3677 */
+P(14, 0x9e22d152776f2e43UL, 0x0011c1706ddce7a7UL) /* 3691 */
+P( 6, 0x05d10d39d1e1f291UL, 0x0011ba0fed2a4f14UL) /* 3697 */
+P( 4, 0x374468dccaced1ddUL, 0x0011b528538ed64aUL) /* 3701 */
+P( 8, 0x8d145c7d110c5ad5UL, 0x0011ab61404242acUL) /* 3709 */
+P(10, 0x3251a39f5acb5737UL, 0x00119f378ce81d2fUL) /* 3719 */
+P( 8, 0xa66e50171443506fUL, 0x001195889ece79daUL) /* 3727 */
+P( 6, 0x124f69ad91dd4cbdUL, 0x00118e4c65387077UL) /* 3733 */
+P( 6, 0xec24f8f2a61a2793UL, 0x001187161d70e725UL) /* 3739 */
+P(22, 0xb472148e656b7a51UL, 0x00116cd6d1c85239UL) /* 3761 */
+P( 6, 0x0adf9570e1142f07UL, 0x001165bbe7ce86b1UL) /* 3767 */
+P( 2, 0x89bf33b065119789UL, 0x0011635ee344ce36UL) /* 3769 */
+P(10, 0x8f0149803cb291ebUL, 0x0011579767b6d679UL) /* 3779 */
+P(14, 0x8334b63afd190a31UL, 0x00114734711e2b54UL) /* 3793 */
+P( 4, 0x920908d50d6aba7dUL, 0x0011428b90147f05UL) /* 3797 */
+P( 6, 0x57d8b018c5a33d53UL, 0x00113b92f3021636UL) /* 3803 */
+P(18, 0xea1773092dc27ee5UL, 0x001126cabc886884UL) /* 3821 */
+P( 2, 0xcae5f38b7bf2e00fUL, 0x0011247eb1b85976UL) /* 3823 */
+P(10, 0x2bd02df34f695349UL, 0x0011190bb01efd65UL) /* 3833 */
+P(14, 0xddfecd5be62e2eb7UL, 0x0011091de0fd679cUL) /* 3847 */
+P( 4, 0xdbf849ebec96c4a3UL, 0x001104963c7e4e0bUL) /* 3851 */
+P( 2, 0xda31d4d0187357c5UL, 0x00110253516420b0UL) /* 3853 */
+P(10, 0xe34e21cc2d5418a7UL, 0x0010f70db7c41797UL) /* 3863 */
+P(14, 0x68ca5137a9e574adUL, 0x0010e75ee2bf9ecdUL) /* 3877 */
+P( 4, 0x3eaa0d0f804bfd19UL, 0x0010e2e91c6e0676UL) /* 3881 */
+P( 8, 0x554fb753cc20e9d1UL, 0x0010da049b9d428dUL) /* 3889 */
+P(18, 0x797afcca1300756bUL, 0x0010c6248fe3b1a2UL) /* 3907 */
+P( 4, 0x8b8d950b52eeea77UL, 0x0010c1c03ed690ebUL) /* 3911 */
+P( 6, 0xfb6cd166acabc185UL, 0x0010bb2e1379e3a2UL) /* 3917 */
+P( 2, 0x4eb6c5ed9437a7afUL, 0x0010b8fe7f61228eUL) /* 3919 */
+P( 4, 0xd1eddbd91b790cdbUL, 0x0010b4a10d60a4f7UL) /* 3923 */
+P( 6, 0x93d714ea4d8948e9UL, 0x0010ae192681ec0fUL) /* 3929 */
+P( 2, 0x3ca13ed8145188d3UL, 0x0010abecfbe5b0aeUL) /* 3931 */
+P(12, 0x829086016da89c57UL, 0x00109eefd568b96dUL) /* 3943 */
+P( 4, 0xd7da1f432124a543UL, 0x00109a9ff178b40cUL) /* 3947 */
+P(20, 0x7ead5581632fb07fUL, 0x00108531e22f9ff9UL) /* 3967 */
+P(22, 0x35443837f63ec3bdUL, 0x00106ddec1af4417UL) /* 3989 */
+
+#undef FIRST_OMITTED_PRIME
+#define FIRST_OMITTED_PRIME 4001
diff --git a/third_party/gmp/demos/qcn.c b/third_party/gmp/demos/qcn.c
new file mode 100644
index 0000000..9d76446
--- /dev/null
+++ b/third_party/gmp/demos/qcn.c
@@ -0,0 +1,172 @@
+/* Use mpz_kronecker_ui() to calculate an estimate for the quadratic
+   class number h(d), for a given negative fundamental discriminant, using
+   Dirichlet's analytic formula.
+
+Copyright 1999-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3 of the License, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+more details.
+
+You should have received a copy of the GNU General Public License along with
+this program.  If not, see https://www.gnu.org/licenses/.  */
+
+
+/* Usage: qcn [-p limit] <discriminant>...
+
+   A fundamental discriminant means one of the form D or 4*D with D
+   square-free.  Each argument is checked to see it's congruent to 0 or 1
+   mod 4 (as all discriminants must be), and that it's negative, but there's
+   no check on D being square-free.
+
+   This program is a bit of a toy, there are better methods for calculating
+   the class number and class group structure.
+
+   Reference:
+
+   Daniel Shanks, "Class Number, A Theory of Factorization, and Genera",
+   Proc. Symp. Pure Math., vol 20, 1970, pages 415-440.
+
+*/
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gmp.h"
+
+#ifndef M_PI
+#define M_PI  3.14159265358979323846
+#endif
+
+
+/* A simple but slow primality test.  */
+int
+prime_p (unsigned long n)
+{
+  unsigned long  i, limit;
+
+  if (n == 2)
+    return 1;
+  if (n < 2 || !(n&1))
+    return 0;
+
+  limit = (unsigned long) floor (sqrt ((double) n));
+  for (i = 3; i <= limit; i+=2)
+    if ((n % i) == 0)
+      return 0;
+
+  return 1;
+}
+
+
+/* The formula is as follows, with d < 0.
+
+	       w * sqrt(-d)      inf      p
+	h(d) = ------------ *  product --------
+		  2 * pi         p=2   p - (d/p)
+
+
+   (d/p) is the Kronecker symbol and the product is over primes p.  w is 6
+   when d=-3, 4 when d=-4, or 2 otherwise.
+
+   Calculating the product up to p=infinity would take a long time, so for
+   the estimate primes up to 132,000 are used.  Shanks found this giving an
+   accuracy of about 1 part in 1000, in normal cases.  */
+
+unsigned long  p_limit = 132000;
+
+double
+qcn_estimate (mpz_t d)
+{
+  double  h;
+  unsigned long  p;
+
+  /* p=2 */
+  h = sqrt (-mpz_get_d (d)) / M_PI
+    * 2.0 / (2.0 - mpz_kronecker_ui (d, 2));
+
+  if (mpz_cmp_si (d, -3) == 0)       h *= 3;
+  else if (mpz_cmp_si (d, -4) == 0)  h *= 2;
+
+  for (p = 3; p <= p_limit; p += 2)
+    if (prime_p (p))
+      h *= (double) p / (double) (p - mpz_kronecker_ui (d, p));
+
+  return h;
+}
+
+
+void
+qcn_str (char *num)
+{
+  mpz_t  z;
+
+  mpz_init_set_str (z, num, 0);
+
+  if (mpz_sgn (z) >= 0)
+    {
+      mpz_out_str (stdout, 0, z);
+      printf (" is not supported (negatives only)\n");
+    }
+  else if (mpz_fdiv_ui (z, 4) != 0 && mpz_fdiv_ui (z, 4) != 1)
+    {
+      mpz_out_str (stdout, 0, z);
+      printf (" is not a discriminant (must == 0 or 1 mod 4)\n");
+    }
+  else
+    {
+      printf ("h(");
+      mpz_out_str (stdout, 0, z);
+      printf (") approx %.1f\n", qcn_estimate (z));
+    }
+  mpz_clear (z);
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  int  i;
+  int  saw_number = 0;
+
+  for (i = 1; i < argc; i++)
+    {
+      if (strcmp (argv[i], "-p") == 0)
+	{
+	  i++;
+	  if (i >= argc)
+	    {
+	      fprintf (stderr, "Missing argument to -p\n");
+	      exit (1);
+	    }
+	  p_limit = atoi (argv[i]);
+	}
+      else
+	{
+	  qcn_str (argv[i]);
+	  saw_number = 1;
+	}
+    }
+
+  if (! saw_number)
+    {
+      /* some default output */
+      qcn_str ("-85702502803");           /* is 16259   */
+      qcn_str ("-328878692999");          /* is 1499699 */
+      qcn_str ("-928185925902146563");    /* is 52739552 */
+      qcn_str ("-84148631888752647283");  /* is 496652272 */
+      return 0;
+    }
+
+  return 0;
+}
diff --git a/third_party/gmp/doc/Makefile.am b/third_party/gmp/doc/Makefile.am
new file mode 100644
index 0000000..083f25a
--- /dev/null
+++ b/third_party/gmp/doc/Makefile.am
@@ -0,0 +1,36 @@
+## Process this file with automake to generate Makefile.in
+
+
+# Copyright 2003 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+
+EXTRA_DIST = configuration isa_abi_headache projects.html tasks.html
+
+info_TEXINFOS = gmp.texi
+gmp_TEXINFOS = fdl-1.3.texi
diff --git a/third_party/gmp/doc/Makefile.in b/third_party/gmp/doc/Makefile.in
new file mode 100644
index 0000000..2d342b8
--- /dev/null
+++ b/third_party/gmp/doc/Makefile.in
@@ -0,0 +1,847 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Copyright 2003 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = doc
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/version.texi \
+	$(srcdir)/stamp-vti $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+depcomp =
+am__depfiles_maybe =
+SOURCES =
+DIST_SOURCES =
+AM_V_DVIPS = $(am__v_DVIPS_@AM_V@)
+am__v_DVIPS_ = $(am__v_DVIPS_@AM_DEFAULT_V@)
+am__v_DVIPS_0 = @echo "  DVIPS   " $@;
+am__v_DVIPS_1 = 
+AM_V_MAKEINFO = $(am__v_MAKEINFO_@AM_V@)
+am__v_MAKEINFO_ = $(am__v_MAKEINFO_@AM_DEFAULT_V@)
+am__v_MAKEINFO_0 = @echo "  MAKEINFO" $@;
+am__v_MAKEINFO_1 = 
+AM_V_INFOHTML = $(am__v_INFOHTML_@AM_V@)
+am__v_INFOHTML_ = $(am__v_INFOHTML_@AM_DEFAULT_V@)
+am__v_INFOHTML_0 = @echo "  INFOHTML" $@;
+am__v_INFOHTML_1 = 
+AM_V_TEXI2DVI = $(am__v_TEXI2DVI_@AM_V@)
+am__v_TEXI2DVI_ = $(am__v_TEXI2DVI_@AM_DEFAULT_V@)
+am__v_TEXI2DVI_0 = @echo "  TEXI2DVI" $@;
+am__v_TEXI2DVI_1 = 
+AM_V_TEXI2PDF = $(am__v_TEXI2PDF_@AM_V@)
+am__v_TEXI2PDF_ = $(am__v_TEXI2PDF_@AM_DEFAULT_V@)
+am__v_TEXI2PDF_0 = @echo "  TEXI2PDF" $@;
+am__v_TEXI2PDF_1 = 
+AM_V_texinfo = $(am__v_texinfo_@AM_V@)
+am__v_texinfo_ = $(am__v_texinfo_@AM_DEFAULT_V@)
+am__v_texinfo_0 = -q
+am__v_texinfo_1 = 
+AM_V_texidevnull = $(am__v_texidevnull_@AM_V@)
+am__v_texidevnull_ = $(am__v_texidevnull_@AM_DEFAULT_V@)
+am__v_texidevnull_0 = > /dev/null
+am__v_texidevnull_1 = 
+INFO_DEPS = $(srcdir)/gmp.info
+am__TEXINFO_TEX_DIR = $(srcdir)
+DVIS = gmp.dvi
+PDFS = gmp.pdf
+PSS = gmp.ps
+HTMLS = gmp.html
+TEXINFOS = gmp.texi
+TEXI2DVI = texi2dvi
+TEXI2PDF = $(TEXI2DVI) --pdf --batch
+MAKEINFOHTML = $(MAKEINFO) --html
+AM_MAKEINFOHTMLFLAGS = $(AM_MAKEINFOFLAGS)
+DVIPS = dvips
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__installdirs = "$(DESTDIR)$(infodir)"
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+  test -z "$$files" \
+    || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+    || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+         $(am__cd) "$$dir" && rm -f $$files; }; \
+  }
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(gmp_TEXINFOS) $(srcdir)/Makefile.in mdate-sh \
+	texinfo.tex
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ABI = @ABI@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+ASMFLAGS = @ASMFLAGS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CALLING_CONVENTIONS_OBJS = @CALLING_CONVENTIONS_OBJS@
+CC = @CC@
+CCAS = @CCAS@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPP_FOR_BUILD = @CPP_FOR_BUILD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFN_LONG_LONG_LIMB = @DEFN_LONG_LONG_LIMB@
+DEFS = @DEFS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@
+FGREP = @FGREP@
+GMP_LDFLAGS = @GMP_LDFLAGS@
+GMP_LIMB_BITS = @GMP_LIMB_BITS@
+GMP_NAIL_BITS = @GMP_NAIL_BITS@
+GREP = @GREP@
+HAVE_CLOCK_01 = @HAVE_CLOCK_01@
+HAVE_CPUTIME_01 = @HAVE_CPUTIME_01@
+HAVE_GETRUSAGE_01 = @HAVE_GETRUSAGE_01@
+HAVE_GETTIMEOFDAY_01 = @HAVE_GETTIMEOFDAY_01@
+HAVE_HOST_CPU_FAMILY_power = @HAVE_HOST_CPU_FAMILY_power@
+HAVE_HOST_CPU_FAMILY_powerpc = @HAVE_HOST_CPU_FAMILY_powerpc@
+HAVE_SIGACTION_01 = @HAVE_SIGACTION_01@
+HAVE_SIGALTSTACK_01 = @HAVE_SIGALTSTACK_01@
+HAVE_SIGSTACK_01 = @HAVE_SIGSTACK_01@
+HAVE_STACK_T_01 = @HAVE_STACK_T_01@
+HAVE_SYS_RESOURCE_H_01 = @HAVE_SYS_RESOURCE_H_01@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCURSES = @LIBCURSES@
+LIBGMPXX_LDFLAGS = @LIBGMPXX_LDFLAGS@
+LIBGMP_DLL = @LIBGMP_DLL@
+LIBGMP_LDFLAGS = @LIBGMP_LDFLAGS@
+LIBM = @LIBM@
+LIBM_FOR_BUILD = @LIBM_FOR_BUILD@
+LIBOBJS = @LIBOBJS@
+LIBREADLINE = @LIBREADLINE@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+M4 = @M4@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPEED_CYCLECOUNTER_OBJ = @SPEED_CYCLECOUNTER_OBJ@
+STRIP = @STRIP@
+TAL_OBJECT = @TAL_OBJECT@
+TUNE_LIBS = @TUNE_LIBS@
+TUNE_SQR_OBJ = @TUNE_SQR_OBJ@
+U_FOR_BUILD = @U_FOR_BUILD@
+VERSION = @VERSION@
+WITH_READLINE_01 = @WITH_READLINE_01@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__leading_dot = @am__leading_dot@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gmp_srclinks = @gmp_srclinks@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+mpn_objects = @mpn_objects@
+mpn_objs_in_libgmp = @mpn_objs_in_libgmp@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+EXTRA_DIST = configuration isa_abi_headache projects.html tasks.html
+info_TEXINFOS = gmp.texi
+gmp_TEXINFOS = fdl-1.3.texi
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .dvi .html .info .pdf .ps .texi
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu --ignore-deps doc/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu --ignore-deps doc/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+.texi.info:
+	$(AM_V_MAKEINFO)restore=: && backupdir="$(am__leading_dot)am$$$$" && \
+	am__cwd=`pwd` && $(am__cd) $(srcdir) && \
+	rm -rf $$backupdir && mkdir $$backupdir && \
+	if ($(MAKEINFO) --version) >/dev/null 2>&1; then \
+	  for f in $@ $@-[0-9] $@-[0-9][0-9] $(@:.info=).i[0-9] $(@:.info=).i[0-9][0-9]; do \
+	    if test -f $$f; then mv $$f $$backupdir; restore=mv; else :; fi; \
+	  done; \
+	else :; fi && \
+	cd "$$am__cwd"; \
+	if $(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \
+	 -o $@ $<; \
+	then \
+	  rc=0; \
+	  $(am__cd) $(srcdir); \
+	else \
+	  rc=$$?; \
+	  $(am__cd) $(srcdir) && \
+	  $$restore $$backupdir/* `echo "./$@" | sed 's|[^/]*$$||'`; \
+	fi; \
+	rm -rf $$backupdir; exit $$rc
+
+.texi.dvi:
+	$(AM_V_TEXI2DVI)TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \
+	MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \
+	$(TEXI2DVI) $(AM_V_texinfo) --build-dir=$(@:.dvi=.t2d) -o $@ $(AM_V_texidevnull) \
+	$<
+
+.texi.pdf:
+	$(AM_V_TEXI2PDF)TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \
+	MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \
+	$(TEXI2PDF) $(AM_V_texinfo) --build-dir=$(@:.pdf=.t2p) -o $@ $(AM_V_texidevnull) \
+	$<
+
+.texi.html:
+	$(AM_V_MAKEINFO)rm -rf $(@:.html=.htp)
+	$(AM_V_at)if $(MAKEINFOHTML) $(AM_MAKEINFOHTMLFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \
+	 -o $(@:.html=.htp) $<; \
+	then \
+	  rm -rf $@ && mv $(@:.html=.htp) $@; \
+	else \
+	  rm -rf $(@:.html=.htp); exit 1; \
+	fi
+$(srcdir)/gmp.info: gmp.texi $(srcdir)/version.texi $(gmp_TEXINFOS)
+gmp.dvi: gmp.texi $(srcdir)/version.texi $(gmp_TEXINFOS)
+gmp.pdf: gmp.texi $(srcdir)/version.texi $(gmp_TEXINFOS)
+gmp.html: gmp.texi $(srcdir)/version.texi $(gmp_TEXINFOS)
+$(srcdir)/version.texi: @MAINTAINER_MODE_TRUE@ $(srcdir)/stamp-vti
+$(srcdir)/stamp-vti: gmp.texi $(top_srcdir)/configure
+	@(dir=.; test -f ./gmp.texi || dir=$(srcdir); \
+	set `$(SHELL) $(srcdir)/mdate-sh $$dir/gmp.texi`; \
+	echo "@set UPDATED $$1 $$2 $$3"; \
+	echo "@set UPDATED-MONTH $$2 $$3"; \
+	echo "@set EDITION $(VERSION)"; \
+	echo "@set VERSION $(VERSION)") > vti.tmp$$$$ && \
+	(cmp -s vti.tmp$$$$ $(srcdir)/version.texi \
+	  || (echo "Updating $(srcdir)/version.texi" && \
+	      cp vti.tmp$$$$ $(srcdir)/version.texi.tmp$$$$ && \
+	      mv $(srcdir)/version.texi.tmp$$$$ $(srcdir)/version.texi)) && \
+	rm -f vti.tmp$$$$ $(srcdir)/version.texi.$$$$
+	@cp $(srcdir)/version.texi $@
+
+mostlyclean-vti:
+	-rm -f vti.tmp* $(srcdir)/version.texi.tmp*
+
+maintainer-clean-vti:
+@MAINTAINER_MODE_TRUE@	-rm -f $(srcdir)/stamp-vti $(srcdir)/version.texi
+.dvi.ps:
+	$(AM_V_DVIPS)TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \
+	$(DVIPS) $(AM_V_texinfo) -o $@ $<
+
+uninstall-dvi-am:
+	@$(NORMAL_UNINSTALL)
+	@list='$(DVIS)'; test -n "$(dvidir)" || list=; \
+	for p in $$list; do \
+	  $(am__strip_dir) \
+	  echo " rm -f '$(DESTDIR)$(dvidir)/$$f'"; \
+	  rm -f "$(DESTDIR)$(dvidir)/$$f"; \
+	done
+
+uninstall-html-am:
+	@$(NORMAL_UNINSTALL)
+	@list='$(HTMLS)'; test -n "$(htmldir)" || list=; \
+	for p in $$list; do \
+	  $(am__strip_dir) \
+	  echo " rm -rf '$(DESTDIR)$(htmldir)/$$f'"; \
+	  rm -rf "$(DESTDIR)$(htmldir)/$$f"; \
+	done
+
+uninstall-info-am:
+	@$(PRE_UNINSTALL)
+	@if test -d '$(DESTDIR)$(infodir)' && $(am__can_run_installinfo); then \
+	  list='$(INFO_DEPS)'; \
+	  for file in $$list; do \
+	    relfile=`echo "$$file" | sed 's|^.*/||'`; \
+	    echo " install-info --info-dir='$(DESTDIR)$(infodir)' --remove '$(DESTDIR)$(infodir)/$$relfile'"; \
+	    if install-info --info-dir="$(DESTDIR)$(infodir)" --remove "$(DESTDIR)$(infodir)/$$relfile"; \
+	    then :; else test ! -f "$(DESTDIR)$(infodir)/$$relfile" || exit 1; fi; \
+	  done; \
+	else :; fi
+	@$(NORMAL_UNINSTALL)
+	@list='$(INFO_DEPS)'; \
+	for file in $$list; do \
+	  relfile=`echo "$$file" | sed 's|^.*/||'`; \
+	  relfile_i=`echo "$$relfile" | sed 's|\.info$$||;s|$$|.i|'`; \
+	  (if test -d "$(DESTDIR)$(infodir)" && cd "$(DESTDIR)$(infodir)"; then \
+	     echo " cd '$(DESTDIR)$(infodir)' && rm -f $$relfile $$relfile-[0-9] $$relfile-[0-9][0-9] $$relfile_i[0-9] $$relfile_i[0-9][0-9]"; \
+	     rm -f $$relfile $$relfile-[0-9] $$relfile-[0-9][0-9] $$relfile_i[0-9] $$relfile_i[0-9][0-9]; \
+	   else :; fi); \
+	done
+
+uninstall-pdf-am:
+	@$(NORMAL_UNINSTALL)
+	@list='$(PDFS)'; test -n "$(pdfdir)" || list=; \
+	for p in $$list; do \
+	  $(am__strip_dir) \
+	  echo " rm -f '$(DESTDIR)$(pdfdir)/$$f'"; \
+	  rm -f "$(DESTDIR)$(pdfdir)/$$f"; \
+	done
+
+uninstall-ps-am:
+	@$(NORMAL_UNINSTALL)
+	@list='$(PSS)'; test -n "$(psdir)" || list=; \
+	for p in $$list; do \
+	  $(am__strip_dir) \
+	  echo " rm -f '$(DESTDIR)$(psdir)/$$f'"; \
+	  rm -f "$(DESTDIR)$(psdir)/$$f"; \
+	done
+
+dist-info: $(INFO_DEPS)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+	list='$(INFO_DEPS)'; \
+	for base in $$list; do \
+	  case $$base in \
+	    $(srcdir)/*) base=`echo "$$base" | sed "s|^$$srcdirstrip/||"`;; \
+	  esac; \
+	  if test -f $$base; then d=.; else d=$(srcdir); fi; \
+	  base_i=`echo "$$base" | sed 's|\.info$$||;s|$$|.i|'`; \
+	  for file in $$d/$$base $$d/$$base-[0-9] $$d/$$base-[0-9][0-9] $$d/$$base_i[0-9] $$d/$$base_i[0-9][0-9]; do \
+	    if test -f $$file; then \
+	      relfile=`expr "$$file" : "$$d/\(.*\)"`; \
+	      test -f "$(distdir)/$$relfile" || \
+		cp -p $$file "$(distdir)/$$relfile"; \
+	    else :; fi; \
+	  done; \
+	done
+
+mostlyclean-aminfo:
+	-rm -rf gmp.t2d gmp.t2p
+
+clean-aminfo:
+	-test -z "gmp.dvi gmp.pdf gmp.ps gmp.html" \
+	|| rm -rf gmp.dvi gmp.pdf gmp.ps gmp.html
+
+maintainer-clean-aminfo:
+	@list='$(INFO_DEPS)'; for i in $$list; do \
+	  i_i=`echo "$$i" | sed 's|\.info$$||;s|$$|.i|'`; \
+	  echo " rm -f $$i $$i-[0-9] $$i-[0-9][0-9] $$i_i[0-9] $$i_i[0-9][0-9]"; \
+	  rm -f $$i $$i-[0-9] $$i-[0-9][0-9] $$i_i[0-9] $$i_i[0-9][0-9]; \
+	done
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+	$(MAKE) $(AM_MAKEFLAGS) \
+	  top_distdir="$(top_distdir)" distdir="$(distdir)" \
+	  dist-info
+check-am: all-am
+check: check-am
+all-am: Makefile $(INFO_DEPS)
+installdirs:
+	for dir in "$(DESTDIR)$(infodir)"; do \
+	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+	done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-aminfo clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am: $(DVIS)
+
+html: html-am
+
+html-am: $(HTMLS)
+
+info: info-am
+
+info-am: $(INFO_DEPS)
+
+install-data-am: install-info-am
+
+install-dvi: install-dvi-am
+
+install-dvi-am: $(DVIS)
+	@$(NORMAL_INSTALL)
+	@list='$(DVIS)'; test -n "$(dvidir)" || list=; \
+	if test -n "$$list"; then \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(dvidir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(dvidir)" || exit 1; \
+	fi; \
+	for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  echo "$$d$$p"; \
+	done | $(am__base_list) | \
+	while read files; do \
+	  echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(dvidir)'"; \
+	  $(INSTALL_DATA) $$files "$(DESTDIR)$(dvidir)" || exit $$?; \
+	done
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am: $(HTMLS)
+	@$(NORMAL_INSTALL)
+	@list='$(HTMLS)'; list2=; test -n "$(htmldir)" || list=; \
+	if test -n "$$list"; then \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(htmldir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(htmldir)" || exit 1; \
+	fi; \
+	for p in $$list; do \
+	  if test -f "$$p" || test -d "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  $(am__strip_dir) \
+	  d2=$$d$$p; \
+	  if test -d "$$d2"; then \
+	    echo " $(MKDIR_P) '$(DESTDIR)$(htmldir)/$$f'"; \
+	    $(MKDIR_P) "$(DESTDIR)$(htmldir)/$$f" || exit 1; \
+	    echo " $(INSTALL_DATA) '$$d2'/* '$(DESTDIR)$(htmldir)/$$f'"; \
+	    $(INSTALL_DATA) "$$d2"/* "$(DESTDIR)$(htmldir)/$$f" || exit $$?; \
+	  else \
+	    list2="$$list2 $$d2"; \
+	  fi; \
+	done; \
+	test -z "$$list2" || { echo "$$list2" | $(am__base_list) | \
+	while read files; do \
+	  echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(htmldir)'"; \
+	  $(INSTALL_DATA) $$files "$(DESTDIR)$(htmldir)" || exit $$?; \
+	done; }
+install-info: install-info-am
+
+install-info-am: $(INFO_DEPS)
+	@$(NORMAL_INSTALL)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+	list='$(INFO_DEPS)'; test -n "$(infodir)" || list=; \
+	if test -n "$$list"; then \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(infodir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(infodir)" || exit 1; \
+	fi; \
+	for file in $$list; do \
+	  case $$file in \
+	    $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+	  esac; \
+	  if test -f $$file; then d=.; else d=$(srcdir); fi; \
+	  file_i=`echo "$$file" | sed 's|\.info$$||;s|$$|.i|'`; \
+	  for ifile in $$d/$$file $$d/$$file-[0-9] $$d/$$file-[0-9][0-9] \
+	               $$d/$$file_i[0-9] $$d/$$file_i[0-9][0-9] ; do \
+	    if test -f $$ifile; then \
+	      echo "$$ifile"; \
+	    else : ; fi; \
+	  done; \
+	done | $(am__base_list) | \
+	while read files; do \
+	  echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(infodir)'"; \
+	  $(INSTALL_DATA) $$files "$(DESTDIR)$(infodir)" || exit $$?; done
+	@$(POST_INSTALL)
+	@if $(am__can_run_installinfo); then \
+	  list='$(INFO_DEPS)'; test -n "$(infodir)" || list=; \
+	  for file in $$list; do \
+	    relfile=`echo "$$file" | sed 's|^.*/||'`; \
+	    echo " install-info --info-dir='$(DESTDIR)$(infodir)' '$(DESTDIR)$(infodir)/$$relfile'";\
+	    install-info --info-dir="$(DESTDIR)$(infodir)" "$(DESTDIR)$(infodir)/$$relfile" || :;\
+	  done; \
+	else : ; fi
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am: $(PDFS)
+	@$(NORMAL_INSTALL)
+	@list='$(PDFS)'; test -n "$(pdfdir)" || list=; \
+	if test -n "$$list"; then \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(pdfdir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(pdfdir)" || exit 1; \
+	fi; \
+	for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  echo "$$d$$p"; \
+	done | $(am__base_list) | \
+	while read files; do \
+	  echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pdfdir)'"; \
+	  $(INSTALL_DATA) $$files "$(DESTDIR)$(pdfdir)" || exit $$?; done
+install-ps: install-ps-am
+
+install-ps-am: $(PSS)
+	@$(NORMAL_INSTALL)
+	@list='$(PSS)'; test -n "$(psdir)" || list=; \
+	if test -n "$$list"; then \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(psdir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(psdir)" || exit 1; \
+	fi; \
+	for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  echo "$$d$$p"; \
+	done | $(am__base_list) | \
+	while read files; do \
+	  echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(psdir)'"; \
+	  $(INSTALL_DATA) $$files "$(DESTDIR)$(psdir)" || exit $$?; done
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-aminfo \
+	maintainer-clean-generic maintainer-clean-vti
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-aminfo mostlyclean-generic \
+	mostlyclean-libtool mostlyclean-vti
+
+pdf: pdf-am
+
+pdf-am: $(PDFS)
+
+ps: ps-am
+
+ps-am: $(PSS)
+
+uninstall-am: uninstall-dvi-am uninstall-html-am uninstall-info-am \
+	uninstall-pdf-am uninstall-ps-am
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-aminfo clean-generic \
+	clean-libtool cscopelist-am ctags-am dist-info distclean \
+	distclean-generic distclean-libtool distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-dvi install-dvi-am install-exec \
+	install-exec-am install-html install-html-am install-info \
+	install-info-am install-man install-pdf install-pdf-am \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-aminfo maintainer-clean-generic \
+	maintainer-clean-vti mostlyclean mostlyclean-aminfo \
+	mostlyclean-generic mostlyclean-libtool mostlyclean-vti pdf \
+	pdf-am ps ps-am tags-am uninstall uninstall-am \
+	uninstall-dvi-am uninstall-html-am uninstall-info-am \
+	uninstall-pdf-am uninstall-ps-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/third_party/gmp/doc/configuration b/third_party/gmp/doc/configuration
new file mode 100644
index 0000000..f3a541b
--- /dev/null
+++ b/third_party/gmp/doc/configuration
@@ -0,0 +1,389 @@
+/* doc/configuration (in Emacs -*-outline-*- format). */
+
+Copyright 2000-2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.
+
+
+
+* Adding a new file
+
+** Adding a top-level file
+
+  i) Add it to libgmp_la_SOURCES in Makefile.am.
+
+  ii) If libmp.la needs it (usually doesn't), then add it to
+      libmp_la_SOURCES too.
+
+** Adding a subdirectory file
+
+For instance for mpz,
+
+  i) Add file.c to libmpz_la_SOURCES in mpz/Makefile.am.
+
+  ii) Add mpz/file$U.lo to MPZ_OBJECTS in the top-level Makefile.am
+
+  iii) If for some reason libmp.la needs it (usually doesn't) then add
+       mpz/file$U.lo to libmp_la_DEPENDENCIES in the top-level
+       Makefile.am too.
+
+The same applies to mpf, mpq, scanf and printf.
+
+** Adding an mpn file
+
+The way we build libmpn (in the `mpn' subdirectory) is quite special.
+
+Currently only mpn/mp_bases.c is truly generic and included in every
+configuration.  All other files are linked at build time into the mpn
+build directory from one of the CPU specific sub-directories, or from
+the mpn/generic directory.
+
+There are four types of mpn source files.
+
+  .asm	  Assembly code preprocessed with m4
+  .S	  Assembly code preprocessed with cpp
+  .s	  Assembly code not preprocessed at all
+  .c	  C code
+
+There are two types of .asm files.
+
+  i) ``Normal'' files containing one function, though possibly with
+     more than one entry point.
+
+  ii) Multi-function files that generate one of a set of functions
+      according to build options.
+
+To add a new implementation of an existing function,
+
+  i) Put it in the appropriate CPU-specific mpn subdirectory, it'll be
+     detected and used.
+
+  ii) Any entrypoints tested by HAVE_NATIVE_func in other code must
+      have PROLOGUE(func) for configure to grep.  This is normal for
+      .asm or .S files, but for .c files a dummy comment like the
+      following will be needed.
+
+              /*
+              PROLOGUE(func)
+              */
+
+To add a new implementation using a multi-function file, in addition
+do the following,
+
+  i) Use a MULFUNC_PROLOGUE(func1 func2 ...) in the .asm, declaring
+     all the functions implemented, including carry-in variants.
+
+     If there's a separate PROLOGUE(func) for each possible function
+     (but this is usually not the case), then MULFUNC_PROLOGUE isn't
+     necessary.
+
+To add a new style of multi-function file, in addition do the
+following,
+
+  i) Add to the GMP_MULFUNC_CHOICES "case" statement in configure.in
+     which lists each multi-function filename and what function files
+     it can provide.
+
+To add a completely new mpn function file, do the following,
+
+  i) Ensure the filename is a valid C identifier, due to the
+     -DOPERATION_$* used to support multi-function files.  This means
+     "-" can't be used (but "_" can).
+
+  ii) Add it to configure.in under one of the following
+
+      a) `gmp_mpn_functions' if it exists for every target.  This
+         means there must be a C version in mpn/generic.  (Eg. mul_1)
+
+      b) `gmp_mpn_functions_optional' if it's a standard function, but
+         doesn't need to exist for every target.  Code wanting to use
+         this will test HAVE_NATIVE_func to see if it's available.
+         (Eg. copyi)
+
+      c) `extra_functions' for some targets, if it's a special
+         function that only ever needs to exist for certain targets.
+         Code wanting to use it can test either HAVE_NATIVE_func or
+         HAVE_HOST_CPU_foo, as desired.
+
+  iii) If HAVE_NATIVE_func is going to be used, then add a #undef to
+       the AH_VERBATIM([HAVE_NATIVE] block in configure.in.
+
+  iv) If the function can be provided by a multi-function file, then
+      add to the "case" statement in configure.in which lists each
+      multi-function filename and what function files it can provide.
+
+
+** Adding a test program
+
+  i) Tests to be run early in the testing can be added to the main
+     "tests" sub-directory.
+
+  ii) Tests for mpn, mpz, mpq and mpf can be added under the
+      corresponding tests subdirectory.
+
+  iii) Generic tests for late in the testing can be added to
+       "tests/misc".  printf and scanf tests currently live there too.
+
+  iv) Random number function tests can be added to "tests/rand".  That
+      directory has some development-time programs too.
+
+  v) C++ test programs can be added to "tests/cxx".  A line like the
+     following must be added for each, since by default automake looks
+     for a .c file.
+
+             t_foo_SOURCES = t-foo.cc
+
+In all cases the name of the program should be added to check_PROGRAMS
+in the Makefile.am.  TESTS is equal to check_PROGRAMS, so all those
+programs get run.
+
+"tests/devel" has a number of programs which are only for development
+purposes and are not for use in "make check".  These should be listed
+in EXTRA_PROGRAMS to get Makefile rules created, but they're never
+built or run unless an explicit "make someprog" is used.
+
+
+* Adding a new CPU
+
+In general it's policy to use proper names for each CPU type
+supported.  If two CPUs are quite similar and perhaps don't have any
+actual differences in GMP then they're still given separate names, for
+example alphaev67 and alphaev68.
+
+Canonical names:
+
+  i) Decide the canonical CPU names GMP will accept.
+
+  ii) Add these to the config.sub wrapper if configfsf.sub doesn't
+      already accept them.
+
+  iii) Document the names in gmp.texi.
+
+Aliases (optional):
+
+  i) Any aliases can be added to the config.sub wrapper, unless
+     configfsf.sub already does the right thing with them.
+
+  ii) Leave configure.in and everywhere else using only the canonical
+      names.  Aliases shouldn't appear anywhere except config.sub.
+
+  iii) Document in gmp.texi, if desired.  Usually this isn't a good
+       idea, better encourage users to know just the canonical
+       names.
+
+Configure:
+
+  i) Add patterns to configure.in for the new CPU names.  Include the
+     following (see configure.in for the variables to set up),
+
+     a) ABI choices (if any).
+     b) Compiler choices.
+     c) mpn path for CPU specific code.
+     d) Good default CFLAGS for each likely compiler.
+     d) Any special tests necessary on the compiler or assembler
+        capabilities.
+
+  ii) M4 macros to be shared by asm files in a CPU family are by
+      convention in a foo-defs.m4 like mpn/x86/x86-defs.m4.  They're
+      likely to use settings from config.m4 generated by configure.
+
+Fat binaries:
+
+  i) In configure.in, add CPU specific directory(s) to fat_path.
+
+  ii) In mpn/<cpu>/fat.c, identify the CPU at runtime and use suitable
+      CPUVEC_SETUP_subdir macros to select the function pointers for it.
+
+  iii) For the x86s, add to the "$tmp_prefix" setups in configure.in
+       which abbreviates subdirectory names to fit an 8.3 filesystem.
+       (No need to restrict to 8.3, just ensure uniqueness when
+       truncated.)
+
+
+* The configure system
+
+** Installing tools
+
+The current versions of automake, autoconf and libtool in use can be
+checked in the ChangeLog.  Look for "Update to ...".  Patches may have
+been applied, look for "Regenerate ...".
+
+The GMP build system is in places somewhat dependent on the internals
+of the build tools.  Obviously that's avoided as much as possible, but
+where it can't it creates a problem when upgrading or attempting to
+use different tools versions.
+
+** Updating gmp
+
+The following files need to be updated when going to a new version of
+the build tools.  Unfortunately the tools generally don't identify
+when an out-of-date version is present.
+
+aclocal.m4 is updated by running "aclocal".  (Only needed for a new
+automake or libtool.)
+
+INSTALL.autoconf can be copied from INSTALL in autoconf.
+
+ltmain.sh comes from libtool.  Remove it and run "libtoolize --copy",
+or just copy the file by hand.
+
+texinfo.tex can be updated from ftp.gnu.org.  Check it still works
+with "make gmp.dvi", "make gmp.ps" and "make gmp.pdf".
+
+configfsf.guess and configfsf.sub can be updated from ftp.gnu.org (or
+from the "config" cvs module at subversions.gnu.org).  The gmp
+config.guess and config.sub wrappers are supposed to make such an
+update fairly painless.
+
+depcomp from automake is not needed because configure.in specifies
+automake with "no-dependencies".
+
+** How it works
+
+During development:
+
+    Input files                       Tool       Output files
+    ---------------------------------------------------------
+
+                                     aclocal
+    $prefix/share/aclocal*/*.m4 ----------------> aclocal.m4
+
+
+    configure.in \                   autoconf
+    aclocal.m4   / -----------------------------> configure
+
+
+    */Makefile.am \                  automake
+    configure.in  | ----------------------------> Makefile.in
+    aclocal.m4    /
+
+    configure.in \                  autoheader
+    aclocal.m4   / -----------------------------> config.in
+
+At build time:
+
+    Input files          Tool       Output files
+    --------------------------------------------
+
+    */Makefile.in  \   configure    / */Makefile
+    config.in      | -------------> | config.h
+    gmp-h.in       /                | config.m4
+                                    | gmp.h
+                                    \ fat.h  (fat binary build only)
+
+When configured with --enable-maintainer-mode the Makefiles include
+rules to re-run the necessary tools if the input files are changed.
+This can end up running a lot more things than are really necessary.
+
+If a build tree is in too much of a mess for those rules to work
+properly then a bootstrap can be done from the source directory with
+
+	aclocal
+	autoconf
+	automake
+	autoheader
+
+The autom4te.cache directory is created by autoconf to save some work
+in subsequent automake or autoheader runs.  It's recreated
+automatically if removed, it doesn't get distributed.
+
+** C++ configuration
+
+It's intended that the contents of libgmp.la won't vary according to
+whether --enable-cxx is selected.  This means that if C++ shared
+libraries don't work properly then a shared+static with --disable-cxx
+can be done for the C parts, then a static-only with --enable-cxx to
+get libgmpxx.
+
+libgmpxx.la uses some internals from libgmp.la, in order to share code
+between C and C++.  It's intended that libgmpxx can only be expected
+to work with libgmp from the same version of GMP.  If some of the
+shared internals change their interface, then it's proposed to rename
+them, for instance __gmp_doprint2 or the like, so as to provoke link
+errors rather than mysterious failures from a mismatch.
+
+* Development setups
+
+** General
+
+--disable-shared will make builds go much faster, though of course
+shared or shared+static should be tested too.
+
+--prefix to a dummy directory followed by "make install" will show
+what's installed.
+
+"make check" acts on the libgmp just built, and will ignore any other
+/usr/lib/libgmp, or at least it should do.  Libtool does various hairy
+things to ensure it hits the just-built library.
+
+** Long long limb testing
+
+On systems where gcc supports long long, but a limb is normally just a
+long, the following can be used to force long long for testing
+purposes.  It will probably run quite slowly.
+
+	./configure --host=none ABI=longlong
+
+** Function argument conversions
+
+When using gcc, configuring with something like
+
+	./configure CFLAGS="-g -Wall -Wconversion -Wno-sign-compare"
+
+can show where function parameters are being converted due to having
+function prototypes available, which won't happen in a K&R compiler.
+Doing this in combination with the long long limb setups above is
+good.
+
+Conversions between int and long aren't warned about by gcc when
+they're the same size, which is unfortunate because casts should be
+used in such cases, for the benefit of K&R compilers with int!=long
+and where the difference matters in function calls.
+
+* Other Notes
+
+** Compatibility
+
+compat.c is the home of functions retained for binary compatibility,
+    but now done by other means (like a macro).
+
+struct __mpz_struct etc - this must be retained for C++ compatibility.
+    C++ applications defining functions taking mpz_t etc parameters
+    will get this in the mangled name because C++ "sees though" the
+    typedef mpz_t to the underlying struct.
+
+__gmpn - note that glibc defines some __mpn symbols, old versions of
+    some mpn routines, which it uses for floating point printfs.
+
+
+
+
+Local variables:
+mode: outline
+fill-column: 70
+End:
+/* eof doc/configuration */
diff --git a/third_party/gmp/doc/fdl-1.3.texi b/third_party/gmp/doc/fdl-1.3.texi
new file mode 100644
index 0000000..05804ee
--- /dev/null
+++ b/third_party/gmp/doc/fdl-1.3.texi
@@ -0,0 +1,506 @@
+@c The GNU Free Documentation License.
+@center Version 1.3, 3 November 2008
+
+@c This file is intended to be included within another document,
+@c hence no sectioning command or @node.
+
+@display
+Copyright @copyright{} 2000-2002, 2007, 2008 Free Software Foundation, Inc.
+@uref{http://fsf.org/}
+
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+@end display
+
+@enumerate 0
+@item
+PREAMBLE
+
+The purpose of this License is to make a manual, textbook, or other
+functional and useful document @dfn{free} in the sense of freedom: to
+assure everyone the effective freedom to copy and redistribute it,
+with or without modifying it, either commercially or noncommercially.
+Secondarily, this License preserves for the author and publisher a way
+to get credit for their work, while not being considered responsible
+for modifications made by others.
+
+This License is a kind of ``copyleft'', which means that derivative
+works of the document must themselves be free in the same sense.  It
+complements the GNU General Public License, which is a copyleft
+license designed for free software.
+
+We have designed this License in order to use it for manuals for free
+software, because free software needs free documentation: a free
+program should come with manuals providing the same freedoms that the
+software does.  But this License is not limited to software manuals;
+it can be used for any textual work, regardless of subject matter or
+whether it is published as a printed book.  We recommend this License
+principally for works whose purpose is instruction or reference.
+
+@item
+APPLICABILITY AND DEFINITIONS
+
+This License applies to any manual or other work, in any medium, that
+contains a notice placed by the copyright holder saying it can be
+distributed under the terms of this License.  Such a notice grants a
+world-wide, royalty-free license, unlimited in duration, to use that
+work under the conditions stated herein.  The ``Document'', below,
+refers to any such manual or work.  Any member of the public is a
+licensee, and is addressed as ``you''.  You accept the license if you
+copy, modify or distribute the work in a way requiring permission
+under copyright law.
+
+A ``Modified Version'' of the Document means any work containing the
+Document or a portion of it, either copied verbatim, or with
+modifications and/or translated into another language.
+
+A ``Secondary Section'' is a named appendix or a front-matter section
+of the Document that deals exclusively with the relationship of the
+publishers or authors of the Document to the Document's overall
+subject (or to related matters) and contains nothing that could fall
+directly within that overall subject.  (Thus, if the Document is in
+part a textbook of mathematics, a Secondary Section may not explain
+any mathematics.)  The relationship could be a matter of historical
+connection with the subject or with related matters, or of legal,
+commercial, philosophical, ethical or political position regarding
+them.
+
+The ``Invariant Sections'' are certain Secondary Sections whose titles
+are designated, as being those of Invariant Sections, in the notice
+that says that the Document is released under this License.  If a
+section does not fit the above definition of Secondary then it is not
+allowed to be designated as Invariant.  The Document may contain zero
+Invariant Sections.  If the Document does not identify any Invariant
+Sections then there are none.
+
+The ``Cover Texts'' are certain short passages of text that are listed,
+as Front-Cover Texts or Back-Cover Texts, in the notice that says that
+the Document is released under this License.  A Front-Cover Text may
+be at most 5 words, and a Back-Cover Text may be at most 25 words.
+
+A ``Transparent'' copy of the Document means a machine-readable copy,
+represented in a format whose specification is available to the
+general public, that is suitable for revising the document
+straightforwardly with generic text editors or (for images composed of
+pixels) generic paint programs or (for drawings) some widely available
+drawing editor, and that is suitable for input to text formatters or
+for automatic translation to a variety of formats suitable for input
+to text formatters.  A copy made in an otherwise Transparent file
+format whose markup, or absence of markup, has been arranged to thwart
+or discourage subsequent modification by readers is not Transparent.
+An image format is not Transparent if used for any substantial amount
+of text.  A copy that is not ``Transparent'' is called ``Opaque''.
+
+Examples of suitable formats for Transparent copies include plain
+@sc{ascii} without markup, Texinfo input format, La@TeX{} input
+format, @acronym{SGML} or @acronym{XML} using a publicly available
+@acronym{DTD}, and standard-conforming simple @acronym{HTML},
+PostScript or @acronym{PDF} designed for human modification.  Examples
+of transparent image formats include @acronym{PNG}, @acronym{XCF} and
+@acronym{JPG}.  Opaque formats include proprietary formats that can be
+read and edited only by proprietary word processors, @acronym{SGML} or
+@acronym{XML} for which the @acronym{DTD} and/or processing tools are
+not generally available, and the machine-generated @acronym{HTML},
+PostScript or @acronym{PDF} produced by some word processors for
+output purposes only.
+
+The ``Title Page'' means, for a printed book, the title page itself,
+plus such following pages as are needed to hold, legibly, the material
+this License requires to appear in the title page.  For works in
+formats which do not have any title page as such, ``Title Page'' means
+the text near the most prominent appearance of the work's title,
+preceding the beginning of the body of the text.
+
+The ``publisher'' means any person or entity that distributes copies
+of the Document to the public.
+
+A section ``Entitled XYZ'' means a named subunit of the Document whose
+title either is precisely XYZ or contains XYZ in parentheses following
+text that translates XYZ in another language.  (Here XYZ stands for a
+specific section name mentioned below, such as ``Acknowledgements'',
+``Dedications'', ``Endorsements'', or ``History''.)  To ``Preserve the Title''
+of such a section when you modify the Document means that it remains a
+section ``Entitled XYZ'' according to this definition.
+
+The Document may include Warranty Disclaimers next to the notice which
+states that this License applies to the Document.  These Warranty
+Disclaimers are considered to be included by reference in this
+License, but only as regards disclaiming warranties: any other
+implication that these Warranty Disclaimers may have is void and has
+no effect on the meaning of this License.
+
+@item
+VERBATIM COPYING
+
+You may copy and distribute the Document in any medium, either
+commercially or noncommercially, provided that this License, the
+copyright notices, and the license notice saying this License applies
+to the Document are reproduced in all copies, and that you add no other
+conditions whatsoever to those of this License.  You may not use
+technical measures to obstruct or control the reading or further
+copying of the copies you make or distribute.  However, you may accept
+compensation in exchange for copies.  If you distribute a large enough
+number of copies you must also follow the conditions in section 3.
+
+You may also lend copies, under the same conditions stated above, and
+you may publicly display copies.
+
+@item
+COPYING IN QUANTITY
+
+If you publish printed copies (or copies in media that commonly have
+printed covers) of the Document, numbering more than 100, and the
+Document's license notice requires Cover Texts, you must enclose the
+copies in covers that carry, clearly and legibly, all these Cover
+Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on
+the back cover.  Both covers must also clearly and legibly identify
+you as the publisher of these copies.  The front cover must present
+the full title with all words of the title equally prominent and
+visible.  You may add other material on the covers in addition.
+Copying with changes limited to the covers, as long as they preserve
+the title of the Document and satisfy these conditions, can be treated
+as verbatim copying in other respects.
+
+If the required texts for either cover are too voluminous to fit
+legibly, you should put the first ones listed (as many as fit
+reasonably) on the actual cover, and continue the rest onto adjacent
+pages.
+
+If you publish or distribute Opaque copies of the Document numbering
+more than 100, you must either include a machine-readable Transparent
+copy along with each Opaque copy, or state in or with each Opaque copy
+a computer-network location from which the general network-using
+public has access to download using public-standard network protocols
+a complete Transparent copy of the Document, free of added material.
+If you use the latter option, you must take reasonably prudent steps,
+when you begin distribution of Opaque copies in quantity, to ensure
+that this Transparent copy will remain thus accessible at the stated
+location until at least one year after the last time you distribute an
+Opaque copy (directly or through your agents or retailers) of that
+edition to the public.
+
+It is requested, but not required, that you contact the authors of the
+Document well before redistributing any large number of copies, to give
+them a chance to provide you with an updated version of the Document.
+
+@item
+MODIFICATIONS
+
+You may copy and distribute a Modified Version of the Document under
+the conditions of sections 2 and 3 above, provided that you release
+the Modified Version under precisely this License, with the Modified
+Version filling the role of the Document, thus licensing distribution
+and modification of the Modified Version to whoever possesses a copy
+of it.  In addition, you must do these things in the Modified Version:
+
+@enumerate A
+@item
+Use in the Title Page (and on the covers, if any) a title distinct
+from that of the Document, and from those of previous versions
+(which should, if there were any, be listed in the History section
+of the Document).  You may use the same title as a previous version
+if the original publisher of that version gives permission.
+
+@item
+List on the Title Page, as authors, one or more persons or entities
+responsible for authorship of the modifications in the Modified
+Version, together with at least five of the principal authors of the
+Document (all of its principal authors, if it has fewer than five),
+unless they release you from this requirement.
+
+@item
+State on the Title page the name of the publisher of the
+Modified Version, as the publisher.
+
+@item
+Preserve all the copyright notices of the Document.
+
+@item
+Add an appropriate copyright notice for your modifications
+adjacent to the other copyright notices.
+
+@item
+Include, immediately after the copyright notices, a license notice
+giving the public permission to use the Modified Version under the
+terms of this License, in the form shown in the Addendum below.
+
+@item
+Preserve in that license notice the full lists of Invariant Sections
+and required Cover Texts given in the Document's license notice.
+
+@item
+Include an unaltered copy of this License.
+
+@item
+Preserve the section Entitled ``History'', Preserve its Title, and add
+to it an item stating at least the title, year, new authors, and
+publisher of the Modified Version as given on the Title Page.  If
+there is no section Entitled ``History'' in the Document, create one
+stating the title, year, authors, and publisher of the Document as
+given on its Title Page, then add an item describing the Modified
+Version as stated in the previous sentence.
+
+@item
+Preserve the network location, if any, given in the Document for
+public access to a Transparent copy of the Document, and likewise
+the network locations given in the Document for previous versions
+it was based on.  These may be placed in the ``History'' section.
+You may omit a network location for a work that was published at
+least four years before the Document itself, or if the original
+publisher of the version it refers to gives permission.
+
+@item
+For any section Entitled ``Acknowledgements'' or ``Dedications'', Preserve
+the Title of the section, and preserve in the section all the
+substance and tone of each of the contributor acknowledgements and/or
+dedications given therein.
+
+@item
+Preserve all the Invariant Sections of the Document,
+unaltered in their text and in their titles.  Section numbers
+or the equivalent are not considered part of the section titles.
+
+@item
+Delete any section Entitled ``Endorsements''.  Such a section
+may not be included in the Modified Version.
+
+@item
+Do not retitle any existing section to be Entitled ``Endorsements'' or
+to conflict in title with any Invariant Section.
+
+@item
+Preserve any Warranty Disclaimers.
+@end enumerate
+
+If the Modified Version includes new front-matter sections or
+appendices that qualify as Secondary Sections and contain no material
+copied from the Document, you may at your option designate some or all
+of these sections as invariant.  To do this, add their titles to the
+list of Invariant Sections in the Modified Version's license notice.
+These titles must be distinct from any other section titles.
+
+You may add a section Entitled ``Endorsements'', provided it contains
+nothing but endorsements of your Modified Version by various
+parties---for example, statements of peer review or that the text has
+been approved by an organization as the authoritative definition of a
+standard.
+
+You may add a passage of up to five words as a Front-Cover Text, and a
+passage of up to 25 words as a Back-Cover Text, to the end of the list
+of Cover Texts in the Modified Version.  Only one passage of
+Front-Cover Text and one of Back-Cover Text may be added by (or
+through arrangements made by) any one entity.  If the Document already
+includes a cover text for the same cover, previously added by you or
+by arrangement made by the same entity you are acting on behalf of,
+you may not add another; but you may replace the old one, on explicit
+permission from the previous publisher that added the old one.
+
+The author(s) and publisher(s) of the Document do not by this License
+give permission to use their names for publicity for or to assert or
+imply endorsement of any Modified Version.
+
+@item
+COMBINING DOCUMENTS
+
+You may combine the Document with other documents released under this
+License, under the terms defined in section 4 above for modified
+versions, provided that you include in the combination all of the
+Invariant Sections of all of the original documents, unmodified, and
+list them all as Invariant Sections of your combined work in its
+license notice, and that you preserve all their Warranty Disclaimers.
+
+The combined work need only contain one copy of this License, and
+multiple identical Invariant Sections may be replaced with a single
+copy.  If there are multiple Invariant Sections with the same name but
+different contents, make the title of each such section unique by
+adding at the end of it, in parentheses, the name of the original
+author or publisher of that section if known, or else a unique number.
+Make the same adjustment to the section titles in the list of
+Invariant Sections in the license notice of the combined work.
+
+In the combination, you must combine any sections Entitled ``History''
+in the various original documents, forming one section Entitled
+``History''; likewise combine any sections Entitled ``Acknowledgements'',
+and any sections Entitled ``Dedications''.  You must delete all
+sections Entitled ``Endorsements.''
+
+@item
+COLLECTIONS OF DOCUMENTS
+
+You may make a collection consisting of the Document and other documents
+released under this License, and replace the individual copies of this
+License in the various documents with a single copy that is included in
+the collection, provided that you follow the rules of this License for
+verbatim copying of each of the documents in all other respects.
+
+You may extract a single document from such a collection, and distribute
+it individually under this License, provided you insert a copy of this
+License into the extracted document, and follow this License in all
+other respects regarding verbatim copying of that document.
+
+@item
+AGGREGATION WITH INDEPENDENT WORKS
+
+A compilation of the Document or its derivatives with other separate
+and independent documents or works, in or on a volume of a storage or
+distribution medium, is called an ``aggregate'' if the copyright
+resulting from the compilation is not used to limit the legal rights
+of the compilation's users beyond what the individual works permit.
+When the Document is included in an aggregate, this License does not
+apply to the other works in the aggregate which are not themselves
+derivative works of the Document.
+
+If the Cover Text requirement of section 3 is applicable to these
+copies of the Document, then if the Document is less than one half of
+the entire aggregate, the Document's Cover Texts may be placed on
+covers that bracket the Document within the aggregate, or the
+electronic equivalent of covers if the Document is in electronic form.
+Otherwise they must appear on printed covers that bracket the whole
+aggregate.
+
+@item
+TRANSLATION
+
+Translation is considered a kind of modification, so you may
+distribute translations of the Document under the terms of section 4.
+Replacing Invariant Sections with translations requires special
+permission from their copyright holders, but you may include
+translations of some or all Invariant Sections in addition to the
+original versions of these Invariant Sections.  You may include a
+translation of this License, and all the license notices in the
+Document, and any Warranty Disclaimers, provided that you also include
+the original English version of this License and the original versions
+of those notices and disclaimers.  In case of a disagreement between
+the translation and the original version of this License or a notice
+or disclaimer, the original version will prevail.
+
+If a section in the Document is Entitled ``Acknowledgements'',
+``Dedications'', or ``History'', the requirement (section 4) to Preserve
+its Title (section 1) will typically require changing the actual
+title.
+
+@item
+TERMINATION
+
+You may not copy, modify, sublicense, or distribute the Document
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense, or distribute it is void, and
+will automatically terminate your rights under this License.
+
+However, if you cease all violation of this License, then your license
+from a particular copyright holder is reinstated (a) provisionally,
+unless and until the copyright holder explicitly and finally
+terminates your license, and (b) permanently, if the copyright holder
+fails to notify you of the violation by some reasonable means prior to
+60 days after the cessation.
+
+Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, receipt of a copy of some or all of the same material does
+not give you any rights to use it.
+
+@item
+FUTURE REVISIONS OF THIS LICENSE
+
+The Free Software Foundation may publish new, revised versions
+of the GNU Free Documentation License from time to time.  Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.  See
+@uref{https://www.gnu.org/copyleft/}.
+
+Each version of the License is given a distinguishing version number.
+If the Document specifies that a particular numbered version of this
+License ``or any later version'' applies to it, you have the option of
+following the terms and conditions either of that specified version or
+of any later version that has been published (not as a draft) by the
+Free Software Foundation.  If the Document does not specify a version
+number of this License, you may choose any version ever published (not
+as a draft) by the Free Software Foundation.  If the Document
+specifies that a proxy can decide which future versions of this
+License can be used, that proxy's public statement of acceptance of a
+version permanently authorizes you to choose that version for the
+Document.
+
+@item
+RELICENSING
+
+``Massive Multiauthor Collaboration Site'' (or ``MMC Site'') means any
+World Wide Web server that publishes copyrightable works and also
+provides prominent facilities for anybody to edit those works.  A
+public wiki that anybody can edit is an example of such a server.  A
+``Massive Multiauthor Collaboration'' (or ``MMC'') contained in the
+site means any set of copyrightable works thus published on the MMC
+site.
+
+``CC-BY-SA'' means the Creative Commons Attribution-Share Alike 3.0
+license published by Creative Commons Corporation, a not-for-profit
+corporation with a principal place of business in San Francisco,
+California, as well as future copyleft versions of that license
+published by that same organization.
+
+``Incorporate'' means to publish or republish a Document, in whole or
+in part, as part of another Document.
+
+An MMC is ``eligible for relicensing'' if it is licensed under this
+License, and if all works that were first published under this License
+somewhere other than this MMC, and subsequently incorporated in whole
+or in part into the MMC, (1) had no cover texts or invariant sections,
+and (2) were thus incorporated prior to November 1, 2008.
+
+The operator of an MMC Site may republish an MMC contained in the site
+under CC-BY-SA on the same site at any time before August 1, 2009,
+provided the MMC is eligible for relicensing.
+
+@end enumerate
+
+@page
+@heading ADDENDUM: How to use this License for your documents
+
+To use this License in a document you have written, include a copy of
+the License in the document and put the following copyright and
+license notices just after the title page:
+
+@smallexample
+@group
+  Copyright (C)  @var{year}  @var{your name}.
+  Permission is granted to copy, distribute and/or modify this document
+  under the terms of the GNU Free Documentation License, Version 1.3
+  or any later version published by the Free Software Foundation;
+  with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
+  Texts.  A copy of the license is included in the section entitled ``GNU
+  Free Documentation License''.
+@end group
+@end smallexample
+
+If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts,
+replace the ``with@dots{}Texts.'' line with this:
+
+@smallexample
+@group
+    with the Invariant Sections being @var{list their titles}, with
+    the Front-Cover Texts being @var{list}, and with the Back-Cover Texts
+    being @var{list}.
+@end group
+@end smallexample
+
+If you have Invariant Sections without Cover Texts, or some other
+combination of the three, merge those two alternatives to suit the
+situation.
+
+If your document contains nontrivial examples of program code, we
+recommend releasing these examples in parallel under your choice of
+free software license, such as the GNU General Public License,
+to permit their use in free software.
+
+@c Local Variables:
+@c ispell-local-pdict: "ispell-dict"
+@c End:
+
diff --git a/third_party/gmp/doc/gmp.info b/third_party/gmp/doc/gmp.info
new file mode 100644
index 0000000..775f9e2
--- /dev/null
+++ b/third_party/gmp/doc/gmp.info
@@ -0,0 +1,179 @@
+This is gmp.info, produced by makeinfo version 6.6 from gmp.texi.
+
+This manual describes how to install and use the GNU multiple precision
+arithmetic library, version 6.2.0.
+
+   Copyright 1991, 1993-2016, 2018 Free Software Foundation, Inc.
+
+   Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.3 or
+any later version published by the Free Software Foundation; with no
+Invariant Sections, with the Front-Cover Texts being "A GNU Manual", and
+with the Back-Cover Texts being "You have freedom to copy and modify
+this GNU Manual, like GNU software".  A copy of the license is included
+in *note GNU Free Documentation License::.
+INFO-DIR-SECTION GNU libraries
+START-INFO-DIR-ENTRY
+* gmp: (gmp).                   GNU Multiple Precision Arithmetic Library.
+END-INFO-DIR-ENTRY
+
+
+Indirect:
+gmp.info-1: 858
+gmp.info-2: 303730
+
+Tag Table:
+(Indirect)
+Node: Top858
+Node: Copying2931
+Node: Introduction to GMP5278
+Node: Installing GMP7994
+Node: Build Options8726
+Node: ABI and ISA24435
+Node: Notes for Package Builds34276
+Node: Notes for Particular Systems37363
+Node: Known Build Problems45114
+Node: Performance optimization48646
+Node: GMP Basics49775
+Node: Headers and Libraries50423
+Node: Nomenclature and Types51828
+Node: Function Classes53824
+Node: Variable Conventions55359
+Node: Parameter Conventions57599
+Node: Memory Management59406
+Node: Reentrancy60534
+Node: Useful Macros and Constants62402
+Node: Compatibility with older versions63393
+Node: Demonstration Programs64303
+Node: Efficiency66162
+Node: Debugging73776
+Node: Profiling80551
+Node: Autoconf84542
+Node: Emacs86323
+Node: Reporting Bugs86929
+Node: Integer Functions89555
+Node: Initializing Integers90331
+Node: Assigning Integers92707
+Node: Simultaneous Integer Init & Assign94318
+Node: Converting Integers95965
+Node: Integer Arithmetic98905
+Node: Integer Division100641
+Node: Integer Exponentiation107400
+Node: Integer Roots108897
+Node: Number Theoretic Functions110614
+Node: Integer Comparisons118109
+Node: Integer Logic and Bit Fiddling119547
+Node: I/O of Integers122187
+Node: Integer Random Numbers125178
+Node: Integer Import and Export127801
+Node: Miscellaneous Integer Functions131817
+Node: Integer Special Functions133731
+Node: Rational Number Functions137904
+Node: Initializing Rationals139097
+Node: Rational Conversions141570
+Node: Rational Arithmetic143592
+Node: Comparing Rationals145004
+Node: Applying Integer Functions146475
+Node: I/O of Rationals147994
+Node: Floating-point Functions150353
+Node: Initializing Floats153398
+Node: Assigning Floats157490
+Node: Simultaneous Float Init & Assign160078
+Node: Converting Floats161628
+Node: Float Arithmetic164893
+Node: Float Comparison167046
+Node: I/O of Floats168617
+Node: Miscellaneous Float Functions171306
+Node: Low-level Functions173308
+Node: Random Number Functions207556
+Node: Random State Initialization208624
+Node: Random State Seeding211489
+Node: Random State Miscellaneous212894
+Node: Formatted Output213536
+Node: Formatted Output Strings213781
+Node: Formatted Output Functions219176
+Node: C++ Formatted Output223240
+Node: Formatted Input225940
+Node: Formatted Input Strings226176
+Node: Formatted Input Functions230836
+Node: C++ Formatted Input233805
+Node: C++ Class Interface235708
+Node: C++ Interface General236659
+Node: C++ Interface Integers239728
+Node: C++ Interface Rationals243961
+Node: C++ Interface Floats247985
+Node: C++ Interface Random Numbers254002
+Node: C++ Interface Limitations256402
+Node: Custom Allocation259977
+Node: Language Bindings264196
+Node: Algorithms267509
+Node: Multiplication Algorithms268209
+Node: Basecase Multiplication269298
+Node: Karatsuba Multiplication271206
+Node: Toom 3-Way Multiplication274830
+Node: Toom 4-Way Multiplication281249
+Node: Higher degree Toom'n'half282628
+Node: FFT Multiplication283920
+Node: Other Multiplication289256
+Node: Unbalanced Multiplication291730
+Node: Division Algorithms292518
+Node: Single Limb Division292897
+Node: Basecase Division295785
+Node: Divide and Conquer Division296988
+Node: Block-Wise Barrett Division299056
+Node: Exact Division299708
+Node: Exact Remainder303730
+Node: Small Quotient Division305980
+Node: Greatest Common Divisor Algorithms307578
+Node: Binary GCD307875
+Node: Lehmer's Algorithm310725
+Node: Subquadratic GCD312955
+Node: Extended GCD315424
+Node: Jacobi Symbol316742
+Node: Powering Algorithms318651
+Node: Normal Powering Algorithm318914
+Node: Modular Powering Algorithm319442
+Node: Root Extraction Algorithms320224
+Node: Square Root Algorithm320539
+Node: Nth Root Algorithm322680
+Node: Perfect Square Algorithm323465
+Node: Perfect Power Algorithm325552
+Node: Radix Conversion Algorithms326173
+Node: Binary to Radix326549
+Node: Radix to Binary330170
+Node: Other Algorithms332258
+Node: Prime Testing Algorithm332610
+Node: Factorial Algorithm333794
+Node: Binomial Coefficients Algorithm336194
+Node: Fibonacci Numbers Algorithm337088
+Node: Lucas Numbers Algorithm339562
+Node: Random Number Algorithms340283
+Node: Assembly Coding342403
+Node: Assembly Code Organisation343363
+Node: Assembly Basics344330
+Node: Assembly Carry Propagation345480
+Node: Assembly Cache Handling347310
+Node: Assembly Functional Units349471
+Node: Assembly Floating Point351084
+Node: Assembly SIMD Instructions354863
+Node: Assembly Software Pipelining355845
+Node: Assembly Loop Unrolling356908
+Node: Assembly Writing Guide359123
+Node: Internals361888
+Node: Integer Internals362400
+Node: Rational Internals364864
+Node: Float Internals366102
+Node: Raw Output Internals373502
+Node: C++ Interface Internals374696
+Node: Contributors378017
+Node: References384248
+Node: GNU Free Documentation License390167
+Node: Concept Index415309
+Node: Function Index463123
+
+End Tag Table
+
+
+Local Variables:
+coding: iso-8859-1
+End:
diff --git a/third_party/gmp/doc/gmp.info-1 b/third_party/gmp/doc/gmp.info-1
new file mode 100644
index 0000000..5440fff
--- /dev/null
+++ b/third_party/gmp/doc/gmp.info-1
@@ -0,0 +1,7071 @@
+This is gmp.info, produced by makeinfo version 6.6 from gmp.texi.
+
+This manual describes how to install and use the GNU multiple precision
+arithmetic library, version 6.2.0.
+
+   Copyright 1991, 1993-2016, 2018 Free Software Foundation, Inc.
+
+   Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.3 or
+any later version published by the Free Software Foundation; with no
+Invariant Sections, with the Front-Cover Texts being "A GNU Manual", and
+with the Back-Cover Texts being "You have freedom to copy and modify
+this GNU Manual, like GNU software".  A copy of the license is included
+in *note GNU Free Documentation License::.
+INFO-DIR-SECTION GNU libraries
+START-INFO-DIR-ENTRY
+* gmp: (gmp).                   GNU Multiple Precision Arithmetic Library.
+END-INFO-DIR-ENTRY
+
+
+File: gmp.info,  Node: Top,  Next: Copying,  Prev: (dir),  Up: (dir)
+
+GNU MP
+******
+
+This manual describes how to install and use the GNU multiple precision
+arithmetic library, version 6.2.0.
+
+   Copyright 1991, 1993-2016, 2018 Free Software Foundation, Inc.
+
+   Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.3 or
+any later version published by the Free Software Foundation; with no
+Invariant Sections, with the Front-Cover Texts being "A GNU Manual", and
+with the Back-Cover Texts being "You have freedom to copy and modify
+this GNU Manual, like GNU software".  A copy of the license is included
+in *note GNU Free Documentation License::.
+
+* Menu:
+
+* Copying::                    GMP Copying Conditions (LGPL).
+* Introduction to GMP::        Brief introduction to GNU MP.
+* Installing GMP::             How to configure and compile the GMP library.
+* GMP Basics::                 What every GMP user should know.
+* Reporting Bugs::             How to usefully report bugs.
+* Integer Functions::          Functions for arithmetic on signed integers.
+* Rational Number Functions::  Functions for arithmetic on rational numbers.
+* Floating-point Functions::   Functions for arithmetic on floats.
+* Low-level Functions::        Fast functions for natural numbers.
+* Random Number Functions::    Functions for generating random numbers.
+* Formatted Output::           'printf' style output.
+* Formatted Input::            'scanf' style input.
+* C++ Class Interface::        Class wrappers around GMP types.
+* Custom Allocation::          How to customize the internal allocation.
+* Language Bindings::          Using GMP from other languages.
+* Algorithms::                 What happens behind the scenes.
+* Internals::                  How values are represented behind the scenes.
+
+* Contributors::               Who brings you this library?
+* References::                 Some useful papers and books to read.
+* GNU Free Documentation License::
+* Concept Index::
+* Function Index::
+
+
+File: gmp.info,  Node: Copying,  Next: Introduction to GMP,  Prev: Top,  Up: Top
+
+GNU MP Copying Conditions
+*************************
+
+This library is "free"; this means that everyone is free to use it and
+free to redistribute it on a free basis.  The library is not in the
+public domain; it is copyrighted and there are restrictions on its
+distribution, but these restrictions are designed to permit everything
+that a good cooperating citizen would want to do.  What is not allowed
+is to try to prevent others from further sharing any version of this
+library that they might get from you.
+
+   Specifically, we want to make sure that you have the right to give
+away copies of the library, that you receive source code or else can get
+it if you want it, that you can change this library or use pieces of it
+in new free programs, and that you know you can do these things.
+
+   To make sure that everyone has such rights, we have to forbid you to
+deprive anyone else of these rights.  For example, if you distribute
+copies of the GNU MP library, you must give the recipients all the
+rights that you have.  You must make sure that they, too, receive or can
+get the source code.  And you must tell them their rights.
+
+   Also, for our own protection, we must make certain that everyone
+finds out that there is no warranty for the GNU MP library.  If it is
+modified by someone else and passed on, we want their recipients to know
+that what they have is not what we distributed, so that any problems
+introduced by others will not reflect on our reputation.
+
+   More precisely, the GNU MP library is dual licensed, under the
+conditions of the GNU Lesser General Public License version 3 (see
+'COPYING.LESSERv3'), or the GNU General Public License version 2 (see
+'COPYINGv2').  This is the recipient's choice, and the recipient also
+has the additional option of applying later versions of these licenses.
+(The reason for this dual licensing is to make it possible to use the
+library with programs which are licensed under GPL version 2, but which
+for historical or other reasons do not allow use under later versions of
+the GPL).
+
+   Programs which are not part of the library itself, such as
+demonstration programs and the GMP testsuite, are licensed under the
+terms of the GNU General Public License version 3 (see 'COPYINGv3'), or
+any later version.
+
+
+File: gmp.info,  Node: Introduction to GMP,  Next: Installing GMP,  Prev: Copying,  Up: Top
+
+1 Introduction to GNU MP
+************************
+
+GNU MP is a portable library written in C for arbitrary precision
+arithmetic on integers, rational numbers, and floating-point numbers.
+It aims to provide the fastest possible arithmetic for all applications
+that need higher precision than is directly supported by the basic C
+types.
+
+   Many applications use just a few hundred bits of precision; but some
+applications may need thousands or even millions of bits.  GMP is
+designed to give good performance for both, by choosing algorithms based
+on the sizes of the operands, and by carefully keeping the overhead at a
+minimum.
+
+   The speed of GMP is achieved by using fullwords as the basic
+arithmetic type, by using sophisticated algorithms, by including
+carefully optimized assembly code for the most common inner loops for
+many different CPUs, and by a general emphasis on speed (as opposed to
+simplicity or elegance).
+
+   There is assembly code for these CPUs: ARM Cortex-A9, Cortex-A15, and
+generic ARM, DEC Alpha 21064, 21164, and 21264, AMD K8 and K10 (sold
+under many brands, e.g.  Athlon64, Phenom, Opteron) Bulldozer, and
+Bobcat, Intel Pentium, Pentium Pro/II/III, Pentium 4, Core2, Nehalem,
+Sandy bridge, Haswell, generic x86, Intel IA-64, Motorola/IBM PowerPC 32
+and 64 such as POWER970, POWER5, POWER6, and POWER7, MIPS 32-bit and
+64-bit, SPARC 32-bit ad 64-bit with special support for all UltraSPARC
+models.  There is also assembly code for many obsolete CPUs.
+
+For up-to-date information on GMP, please see the GMP web pages at
+
+     <https://gmplib.org/>
+
+The latest version of the library is available at
+
+     <https://ftp.gnu.org/gnu/gmp/>
+
+   Many sites around the world mirror 'ftp.gnu.org', please use a mirror
+near you, see <https://www.gnu.org/order/ftp.html> for a full list.
+
+   There are three public mailing lists of interest.  One for release
+announcements, one for general questions and discussions about usage of
+the GMP library and one for bug reports.  For more information, see
+
+     <https://gmplib.org/mailman/listinfo/>.
+
+   The proper place for bug reports is <gmp-bugs@gmplib.org>.  See *note
+Reporting Bugs:: for information about reporting bugs.
+
+
+1.1 How to use this Manual
+==========================
+
+Everyone should read *note GMP Basics::.  If you need to install the
+library yourself, then read *note Installing GMP::.  If you have a
+system with multiple ABIs, then read *note ABI and ISA::, for the
+compiler options that must be used on applications.
+
+   The rest of the manual can be used for later reference, although it
+is probably a good idea to glance through it.
+
+
+File: gmp.info,  Node: Installing GMP,  Next: GMP Basics,  Prev: Introduction to GMP,  Up: Top
+
+2 Installing GMP
+****************
+
+GMP has an autoconf/automake/libtool based configuration system.  On a
+Unix-like system a basic build can be done with
+
+     ./configure
+     make
+
+Some self-tests can be run with
+
+     make check
+
+And you can install (under '/usr/local' by default) with
+
+     make install
+
+   If you experience problems, please report them to
+<gmp-bugs@gmplib.org>.  See *note Reporting Bugs::, for information on
+what to include in useful bug reports.
+
+* Menu:
+
+* Build Options::
+* ABI and ISA::
+* Notes for Package Builds::
+* Notes for Particular Systems::
+* Known Build Problems::
+* Performance optimization::
+
+
+File: gmp.info,  Node: Build Options,  Next: ABI and ISA,  Prev: Installing GMP,  Up: Installing GMP
+
+2.1 Build Options
+=================
+
+All the usual autoconf configure options are available, run './configure
+--help' for a summary.  The file 'INSTALL.autoconf' has some generic
+installation information too.
+
+Tools
+     'configure' requires various Unix-like tools.  See *note Notes for
+     Particular Systems::, for some options on non-Unix systems.
+
+     It might be possible to build without the help of 'configure',
+     certainly all the code is there, but unfortunately you'll be on
+     your own.
+
+Build Directory
+     To compile in a separate build directory, 'cd' to that directory,
+     and prefix the configure command with the path to the GMP source
+     directory.  For example
+
+          cd /my/build/dir
+          /my/sources/gmp-6.2.0/configure
+
+     Not all 'make' programs have the necessary features ('VPATH') to
+     support this.  In particular, SunOS and Slowaris 'make' have bugs
+     that make them unable to build in a separate directory.  Use GNU
+     'make' instead.
+
+'--prefix' and '--exec-prefix'
+     The '--prefix' option can be used in the normal way to direct GMP
+     to install under a particular tree.  The default is '/usr/local'.
+
+     '--exec-prefix' can be used to direct architecture-dependent files
+     like 'libgmp.a' to a different location.  This can be used to share
+     architecture-independent parts like the documentation, but separate
+     the dependent parts.  Note however that 'gmp.h' is
+     architecture-dependent since it encodes certain aspects of
+     'libgmp', so it will be necessary to ensure both '$prefix/include'
+     and '$exec_prefix/include' are available to the compiler.
+
+'--disable-shared', '--disable-static'
+     By default both shared and static libraries are built (where
+     possible), but one or other can be disabled.  Shared libraries
+     result in smaller executables and permit code sharing between
+     separate running processes, but on some CPUs are slightly slower,
+     having a small cost on each function call.
+
+Native Compilation, '--build=CPU-VENDOR-OS'
+     For normal native compilation, the system can be specified with
+     '--build'.  By default './configure' uses the output from running
+     './config.guess'.  On some systems './config.guess' can determine
+     the exact CPU type, on others it will be necessary to give it
+     explicitly.  For example,
+
+          ./configure --build=ultrasparc-sun-solaris2.7
+
+     In all cases the 'OS' part is important, since it controls how
+     libtool generates shared libraries.  Running './config.guess' is
+     the simplest way to see what it should be, if you don't know
+     already.
+
+Cross Compilation, '--host=CPU-VENDOR-OS'
+     When cross-compiling, the system used for compiling is given by
+     '--build' and the system where the library will run is given by
+     '--host'.  For example when using a FreeBSD Athlon system to build
+     GNU/Linux m68k binaries,
+
+          ./configure --build=athlon-pc-freebsd3.5 --host=m68k-mac-linux-gnu
+
+     Compiler tools are sought first with the host system type as a
+     prefix.  For example 'm68k-mac-linux-gnu-ranlib' is tried, then
+     plain 'ranlib'.  This makes it possible for a set of
+     cross-compiling tools to co-exist with native tools.  The prefix is
+     the argument to '--host', and this can be an alias, such as
+     'm68k-linux'.  But note that tools don't have to be setup this way,
+     it's enough to just have a 'PATH' with a suitable cross-compiling
+     'cc' etc.
+
+     Compiling for a different CPU in the same family as the build
+     system is a form of cross-compilation, though very possibly this
+     would merely be special options on a native compiler.  In any case
+     './configure' avoids depending on being able to run code on the
+     build system, which is important when creating binaries for a newer
+     CPU since they very possibly won't run on the build system.
+
+     In all cases the compiler must be able to produce an executable (of
+     whatever format) from a standard C 'main'.  Although only object
+     files will go to make up 'libgmp', './configure' uses linking tests
+     for various purposes, such as determining what functions are
+     available on the host system.
+
+     Currently a warning is given unless an explicit '--build' is used
+     when cross-compiling, because it may not be possible to correctly
+     guess the build system type if the 'PATH' has only a
+     cross-compiling 'cc'.
+
+     Note that the '--target' option is not appropriate for GMP.  It's
+     for use when building compiler tools, with '--host' being where
+     they will run, and '--target' what they'll produce code for.
+     Ordinary programs or libraries like GMP are only interested in the
+     '--host' part, being where they'll run.  (Some past versions of GMP
+     used '--target' incorrectly.)
+
+CPU types
+     In general, if you want a library that runs as fast as possible,
+     you should configure GMP for the exact CPU type your system uses.
+     However, this may mean the binaries won't run on older members of
+     the family, and might run slower on other members, older or newer.
+     The best idea is always to build GMP for the exact machine type you
+     intend to run it on.
+
+     The following CPUs have specific support.  See 'configure.ac' for
+     details of what code and compiler options they select.
+
+        * Alpha: alpha, alphaev5, alphaev56, alphapca56, alphapca57,
+          alphaev6, alphaev67, alphaev68 alphaev7
+
+        * Cray: c90, j90, t90, sv1
+
+        * HPPA: hppa1.0, hppa1.1, hppa2.0, hppa2.0n, hppa2.0w, hppa64
+
+        * IA-64: ia64, itanium, itanium2
+
+        * MIPS: mips, mips3, mips64
+
+        * Motorola: m68k, m68000, m68010, m68020, m68030, m68040,
+          m68060, m68302, m68360, m88k, m88110
+
+        * POWER: power, power1, power2, power2sc
+
+        * PowerPC: powerpc, powerpc64, powerpc401, powerpc403,
+          powerpc405, powerpc505, powerpc601, powerpc602, powerpc603,
+          powerpc603e, powerpc604, powerpc604e, powerpc620, powerpc630,
+          powerpc740, powerpc7400, powerpc7450, powerpc750, powerpc801,
+          powerpc821, powerpc823, powerpc860, powerpc970
+
+        * SPARC: sparc, sparcv8, microsparc, supersparc, sparcv9,
+          ultrasparc, ultrasparc2, ultrasparc2i, ultrasparc3, sparc64
+
+        * x86 family: i386, i486, i586, pentium, pentiummmx, pentiumpro,
+          pentium2, pentium3, pentium4, k6, k62, k63, athlon, amd64,
+          viac3, viac32
+
+        * Other: arm, sh, sh2, vax,
+
+     CPUs not listed will use generic C code.
+
+Generic C Build
+     If some of the assembly code causes problems, or if otherwise
+     desired, the generic C code can be selected with the configure
+     '--disable-assembly'.
+
+     Note that this will run quite slowly, but it should be portable and
+     should at least make it possible to get something running if all
+     else fails.
+
+Fat binary, '--enable-fat'
+     Using '--enable-fat' selects a "fat binary" build on x86, where
+     optimized low level subroutines are chosen at runtime according to
+     the CPU detected.  This means more code, but gives good performance
+     on all x86 chips.  (This option might become available for more
+     architectures in the future.)
+
+'ABI'
+     On some systems GMP supports multiple ABIs (application binary
+     interfaces), meaning data type sizes and calling conventions.  By
+     default GMP chooses the best ABI available, but a particular ABI
+     can be selected.  For example
+
+          ./configure --host=mips64-sgi-irix6 ABI=n32
+
+     See *note ABI and ISA::, for the available choices on relevant
+     CPUs, and what applications need to do.
+
+'CC', 'CFLAGS'
+     By default the C compiler used is chosen from among some likely
+     candidates, with 'gcc' normally preferred if it's present.  The
+     usual 'CC=whatever' can be passed to './configure' to choose
+     something different.
+
+     For various systems, default compiler flags are set based on the
+     CPU and compiler.  The usual 'CFLAGS="-whatever"' can be passed to
+     './configure' to use something different or to set good flags for
+     systems GMP doesn't otherwise know.
+
+     The 'CC' and 'CFLAGS' used are printed during './configure', and
+     can be found in each generated 'Makefile'.  This is the easiest way
+     to check the defaults when considering changing or adding
+     something.
+
+     Note that when 'CC' and 'CFLAGS' are specified on a system
+     supporting multiple ABIs it's important to give an explicit
+     'ABI=whatever', since GMP can't determine the ABI just from the
+     flags and won't be able to select the correct assembly code.
+
+     If just 'CC' is selected then normal default 'CFLAGS' for that
+     compiler will be used (if GMP recognises it).  For example 'CC=gcc'
+     can be used to force the use of GCC, with default flags (and
+     default ABI).
+
+'CPPFLAGS'
+     Any flags like '-D' defines or '-I' includes required by the
+     preprocessor should be set in 'CPPFLAGS' rather than 'CFLAGS'.
+     Compiling is done with both 'CPPFLAGS' and 'CFLAGS', but
+     preprocessing uses just 'CPPFLAGS'.  This distinction is because
+     most preprocessors won't accept all the flags the compiler does.
+     Preprocessing is done separately in some configure tests.
+
+'CC_FOR_BUILD'
+     Some build-time programs are compiled and run to generate
+     host-specific data tables.  'CC_FOR_BUILD' is the compiler used for
+     this.  It doesn't need to be in any particular ABI or mode, it
+     merely needs to generate executables that can run.  The default is
+     to try the selected 'CC' and some likely candidates such as 'cc'
+     and 'gcc', looking for something that works.
+
+     No flags are used with 'CC_FOR_BUILD' because a simple invocation
+     like 'cc foo.c' should be enough.  If some particular options are
+     required they can be included as for instance 'CC_FOR_BUILD="cc
+     -whatever"'.
+
+C++ Support, '--enable-cxx'
+     C++ support in GMP can be enabled with '--enable-cxx', in which
+     case a C++ compiler will be required.  As a convenience
+     '--enable-cxx=detect' can be used to enable C++ support only if a
+     compiler can be found.  The C++ support consists of a library
+     'libgmpxx.la' and header file 'gmpxx.h' (*note Headers and
+     Libraries::).
+
+     A separate 'libgmpxx.la' has been adopted rather than having C++
+     objects within 'libgmp.la' in order to ensure dynamic linked C
+     programs aren't bloated by a dependency on the C++ standard
+     library, and to avoid any chance that the C++ compiler could be
+     required when linking plain C programs.
+
+     'libgmpxx.la' will use certain internals from 'libgmp.la' and can
+     only be expected to work with 'libgmp.la' from the same GMP
+     version.  Future changes to the relevant internals will be
+     accompanied by renaming, so a mismatch will cause unresolved
+     symbols rather than perhaps mysterious misbehaviour.
+
+     In general 'libgmpxx.la' will be usable only with the C++ compiler
+     that built it, since name mangling and runtime support are usually
+     incompatible between different compilers.
+
+'CXX', 'CXXFLAGS'
+     When C++ support is enabled, the C++ compiler and its flags can be
+     set with variables 'CXX' and 'CXXFLAGS' in the usual way.  The
+     default for 'CXX' is the first compiler that works from a list of
+     likely candidates, with 'g++' normally preferred when available.
+     The default for 'CXXFLAGS' is to try 'CFLAGS', 'CFLAGS' without
+     '-g', then for 'g++' either '-g -O2' or '-O2', or for other
+     compilers '-g' or nothing.  Trying 'CFLAGS' this way is convenient
+     when using 'gcc' and 'g++' together, since the flags for 'gcc' will
+     usually suit 'g++'.
+
+     It's important that the C and C++ compilers match, meaning their
+     startup and runtime support routines are compatible and that they
+     generate code in the same ABI (if there's a choice of ABIs on the
+     system).  './configure' isn't currently able to check these things
+     very well itself, so for that reason '--disable-cxx' is the
+     default, to avoid a build failure due to a compiler mismatch.
+     Perhaps this will change in the future.
+
+     Incidentally, it's normally not good enough to set 'CXX' to the
+     same as 'CC'.  Although 'gcc' for instance recognises 'foo.cc' as
+     C++ code, only 'g++' will invoke the linker the right way when
+     building an executable or shared library from C++ object files.
+
+Temporary Memory, '--enable-alloca=<choice>'
+     GMP allocates temporary workspace using one of the following three
+     methods, which can be selected with for instance
+     '--enable-alloca=malloc-reentrant'.
+
+        * 'alloca' - C library or compiler builtin.
+        * 'malloc-reentrant' - the heap, in a re-entrant fashion.
+        * 'malloc-notreentrant' - the heap, with global variables.
+
+     For convenience, the following choices are also available.
+     '--disable-alloca' is the same as 'no'.
+
+        * 'yes' - a synonym for 'alloca'.
+        * 'no' - a synonym for 'malloc-reentrant'.
+        * 'reentrant' - 'alloca' if available, otherwise
+          'malloc-reentrant'.  This is the default.
+        * 'notreentrant' - 'alloca' if available, otherwise
+          'malloc-notreentrant'.
+
+     'alloca' is reentrant and fast, and is recommended.  It actually
+     allocates just small blocks on the stack; larger ones use
+     malloc-reentrant.
+
+     'malloc-reentrant' is, as the name suggests, reentrant and thread
+     safe, but 'malloc-notreentrant' is faster and should be used if
+     reentrancy is not required.
+
+     The two malloc methods in fact use the memory allocation functions
+     selected by 'mp_set_memory_functions', these being 'malloc' and
+     friends by default.  *Note Custom Allocation::.
+
+     An additional choice '--enable-alloca=debug' is available, to help
+     when debugging memory related problems (*note Debugging::).
+
+FFT Multiplication, '--disable-fft'
+     By default multiplications are done using Karatsuba, 3-way Toom,
+     higher degree Toom, and Fermat FFT.  The FFT is only used on large
+     to very large operands and can be disabled to save code size if
+     desired.
+
+Assertion Checking, '--enable-assert'
+     This option enables some consistency checking within the library.
+     This can be of use while debugging, *note Debugging::.
+
+Execution Profiling, '--enable-profiling=prof/gprof/instrument'
+     Enable profiling support, in one of various styles, *note
+     Profiling::.
+
+'MPN_PATH'
+     Various assembly versions of each mpn subroutines are provided.
+     For a given CPU, a search is made though a path to choose a version
+     of each.  For example 'sparcv8' has
+
+          MPN_PATH="sparc32/v8 sparc32 generic"
+
+     which means look first for v8 code, then plain sparc32 (which is
+     v7), and finally fall back on generic C.  Knowledgeable users with
+     special requirements can specify a different path.  Normally this
+     is completely unnecessary.
+
+Documentation
+     The source for the document you're now reading is 'doc/gmp.texi',
+     in Texinfo format, see *note Texinfo: (texinfo)Top.
+
+     Info format 'doc/gmp.info' is included in the distribution.  The
+     usual automake targets are available to make PostScript, DVI, PDF
+     and HTML (these will require various TeX and Texinfo tools).
+
+     DocBook and XML can be generated by the Texinfo 'makeinfo' program
+     too, see *note Options for 'makeinfo': (texinfo)makeinfo options.
+
+     Some supplementary notes can also be found in the 'doc'
+     subdirectory.
+
+
+File: gmp.info,  Node: ABI and ISA,  Next: Notes for Package Builds,  Prev: Build Options,  Up: Installing GMP
+
+2.2 ABI and ISA
+===============
+
+ABI (Application Binary Interface) refers to the calling conventions
+between functions, meaning what registers are used and what sizes the
+various C data types are.  ISA (Instruction Set Architecture) refers to
+the instructions and registers a CPU has available.
+
+   Some 64-bit ISA CPUs have both a 64-bit ABI and a 32-bit ABI defined,
+the latter for compatibility with older CPUs in the family.  GMP
+supports some CPUs like this in both ABIs.  In fact within GMP 'ABI'
+means a combination of chip ABI, plus how GMP chooses to use it.  For
+example in some 32-bit ABIs, GMP may support a limb as either a 32-bit
+'long' or a 64-bit 'long long'.
+
+   By default GMP chooses the best ABI available for a given system, and
+this generally gives significantly greater speed.  But an ABI can be
+chosen explicitly to make GMP compatible with other libraries, or
+particular application requirements.  For example,
+
+     ./configure ABI=32
+
+   In all cases it's vital that all object code used in a given program
+is compiled for the same ABI.
+
+   Usually a limb is implemented as a 'long'.  When a 'long long' limb
+is used this is encoded in the generated 'gmp.h'.  This is convenient
+for applications, but it does mean that 'gmp.h' will vary, and can't be
+just copied around.  'gmp.h' remains compiler independent though, since
+all compilers for a particular ABI will be expected to use the same limb
+type.
+
+   Currently no attempt is made to follow whatever conventions a system
+has for installing library or header files built for a particular ABI.
+This will probably only matter when installing multiple builds of GMP,
+and it might be as simple as configuring with a special 'libdir', or it
+might require more than that.  Note that builds for different ABIs need
+to done separately, with a fresh './configure' and 'make' each.
+
+
+AMD64 ('x86_64')
+     On AMD64 systems supporting both 32-bit and 64-bit modes for
+     applications, the following ABI choices are available.
+
+     'ABI=64'
+          The 64-bit ABI uses 64-bit limbs and pointers and makes full
+          use of the chip architecture.  This is the default.
+          Applications will usually not need special compiler flags, but
+          for reference the option is
+
+               gcc  -m64
+
+     'ABI=32'
+          The 32-bit ABI is the usual i386 conventions.  This will be
+          slower, and is not recommended except for inter-operating with
+          other code not yet 64-bit capable.  Applications must be
+          compiled with
+
+               gcc  -m32
+
+          (In GCC 2.95 and earlier there's no '-m32' option, it's the
+          only mode.)
+
+     'ABI=x32'
+          The x32 ABI uses 64-bit limbs but 32-bit pointers.  Like the
+          64-bit ABI, it makes full use of the chip's arithmetic
+          capabilities.  This ABI is not supported by all operating
+          systems.
+
+               gcc  -mx32
+
+
+HPPA 2.0 ('hppa2.0*', 'hppa64')
+     'ABI=2.0w'
+          The 2.0w ABI uses 64-bit limbs and pointers and is available
+          on HP-UX 11 or up.  Applications must be compiled with
+
+               gcc [built for 2.0w]
+               cc  +DD64
+
+     'ABI=2.0n'
+          The 2.0n ABI means the 32-bit HPPA 1.0 ABI and all its normal
+          calling conventions, but with 64-bit instructions permitted
+          within functions.  GMP uses a 64-bit 'long long' for a limb.
+          This ABI is available on hppa64 GNU/Linux and on HP-UX 10 or
+          higher.  Applications must be compiled with
+
+               gcc [built for 2.0n]
+               cc  +DA2.0 +e
+
+          Note that current versions of GCC (eg. 3.2) don't generate
+          64-bit instructions for 'long long' operations and so may be
+          slower than for 2.0w.  (The GMP assembly code is the same
+          though.)
+
+     'ABI=1.0'
+          HPPA 2.0 CPUs can run all HPPA 1.0 and 1.1 code in the 32-bit
+          HPPA 1.0 ABI.  No special compiler options are needed for
+          applications.
+
+     All three ABIs are available for CPU types 'hppa2.0w', 'hppa2.0'
+     and 'hppa64', but for CPU type 'hppa2.0n' only 2.0n or 1.0 are
+     considered.
+
+     Note that GCC on HP-UX has no options to choose between 2.0n and
+     2.0w modes, unlike HP 'cc'.  Instead it must be built for one or
+     the other ABI.  GMP will detect how it was built, and skip to the
+     corresponding 'ABI'.
+
+
+IA-64 under HP-UX ('ia64*-*-hpux*', 'itanium*-*-hpux*')
+     HP-UX supports two ABIs for IA-64.  GMP performance is the same in
+     both.
+
+     'ABI=32'
+          In the 32-bit ABI, pointers, 'int's and 'long's are 32 bits
+          and GMP uses a 64 bit 'long long' for a limb.  Applications
+          can be compiled without any special flags since this ABI is
+          the default in both HP C and GCC, but for reference the flags
+          are
+
+               gcc  -milp32
+               cc   +DD32
+
+     'ABI=64'
+          In the 64-bit ABI, 'long's and pointers are 64 bits and GMP
+          uses a 'long' for a limb.  Applications must be compiled with
+
+               gcc  -mlp64
+               cc   +DD64
+
+     On other IA-64 systems, GNU/Linux for instance, 'ABI=64' is the
+     only choice.
+
+
+MIPS under IRIX 6 ('mips*-*-irix[6789]')
+     IRIX 6 always has a 64-bit MIPS 3 or better CPU, and supports ABIs
+     o32, n32, and 64.  n32 or 64 are recommended, and GMP performance
+     will be the same in each.  The default is n32.
+
+     'ABI=o32'
+          The o32 ABI is 32-bit pointers and integers, and no 64-bit
+          operations.  GMP will be slower than in n32 or 64, this option
+          only exists to support old compilers, eg. GCC 2.7.2.
+          Applications can be compiled with no special flags on an old
+          compiler, or on a newer compiler with
+
+               gcc  -mabi=32
+               cc   -32
+
+     'ABI=n32'
+          The n32 ABI is 32-bit pointers and integers, but with a 64-bit
+          limb using a 'long long'.  Applications must be compiled with
+
+               gcc  -mabi=n32
+               cc   -n32
+
+     'ABI=64'
+          The 64-bit ABI is 64-bit pointers and integers.  Applications
+          must be compiled with
+
+               gcc  -mabi=64
+               cc   -64
+
+     Note that MIPS GNU/Linux, as of kernel version 2.2, doesn't have
+     the necessary support for n32 or 64 and so only gets a 32-bit limb
+     and the MIPS 2 code.
+
+
+PowerPC 64 ('powerpc64', 'powerpc620', 'powerpc630', 'powerpc970', 'power4', 'power5')
+     'ABI=mode64'
+          The AIX 64 ABI uses 64-bit limbs and pointers and is the
+          default on PowerPC 64 '*-*-aix*' systems.  Applications must
+          be compiled with
+
+               gcc  -maix64
+               xlc  -q64
+
+          On 64-bit GNU/Linux, BSD, and Mac OS X/Darwin systems, the
+          applications must be compiled with
+
+               gcc  -m64
+
+     'ABI=mode32'
+          The 'mode32' ABI uses a 64-bit 'long long' limb but with the
+          chip still in 32-bit mode and using 32-bit calling
+          conventions.  This is the default for systems where the true
+          64-bit ABI is unavailable.  No special compiler options are
+          typically needed for applications.  This ABI is not available
+          under AIX.
+
+     'ABI=32'
+          This is the basic 32-bit PowerPC ABI, with a 32-bit limb.  No
+          special compiler options are needed for applications.
+
+     GMP's speed is greatest for the 'mode64' ABI, the 'mode32' ABI is
+     2nd best.  In 'ABI=32' only the 32-bit ISA is used and this doesn't
+     make full use of a 64-bit chip.
+
+
+Sparc V9 ('sparc64', 'sparcv9', 'ultrasparc*')
+     'ABI=64'
+          The 64-bit V9 ABI is available on the various BSD sparc64
+          ports, recent versions of Sparc64 GNU/Linux, and Solaris 2.7
+          and up (when the kernel is in 64-bit mode).  GCC 3.2 or
+          higher, or Sun 'cc' is required.  On GNU/Linux, depending on
+          the default 'gcc' mode, applications must be compiled with
+
+               gcc  -m64
+
+          On Solaris applications must be compiled with
+
+               gcc  -m64 -mptr64 -Wa,-xarch=v9 -mcpu=v9
+               cc   -xarch=v9
+
+          On the BSD sparc64 systems no special options are required,
+          since 64-bits is the only ABI available.
+
+     'ABI=32'
+          For the basic 32-bit ABI, GMP still uses as much of the V9 ISA
+          as it can.  In the Sun documentation this combination is known
+          as "v8plus".  On GNU/Linux, depending on the default 'gcc'
+          mode, applications may need to be compiled with
+
+               gcc  -m32
+
+          On Solaris, no special compiler options are required for
+          applications, though using something like the following is
+          recommended.  ('gcc' 2.8 and earlier only support '-mv8'
+          though.)
+
+               gcc  -mv8plus
+               cc   -xarch=v8plus
+
+     GMP speed is greatest in 'ABI=64', so it's the default where
+     available.  The speed is partly because there are extra registers
+     available and partly because 64-bits is considered the more
+     important case and has therefore had better code written for it.
+
+     Don't be confused by the names of the '-m' and '-x' compiler
+     options, they're called 'arch' but effectively control both ABI and
+     ISA.
+
+     On Solaris 2.6 and earlier, only 'ABI=32' is available since the
+     kernel doesn't save all registers.
+
+     On Solaris 2.7 with the kernel in 32-bit mode, a normal native
+     build will reject 'ABI=64' because the resulting executables won't
+     run.  'ABI=64' can still be built if desired by making it look like
+     a cross-compile, for example
+
+          ./configure --build=none --host=sparcv9-sun-solaris2.7 ABI=64
+
+
+File: gmp.info,  Node: Notes for Package Builds,  Next: Notes for Particular Systems,  Prev: ABI and ISA,  Up: Installing GMP
+
+2.3 Notes for Package Builds
+============================
+
+GMP should present no great difficulties for packaging in a binary
+distribution.
+
+   Libtool is used to build the library and '-version-info' is set
+appropriately, having started from '3:0:0' in GMP 3.0 (*note Library
+interface versions: (libtool)Versioning.).
+
+   The GMP 4 series will be upwardly binary compatible in each release
+and will be upwardly binary compatible with all of the GMP 3 series.
+Additional function interfaces may be added in each release, so on
+systems where libtool versioning is not fully checked by the loader an
+auxiliary mechanism may be needed to express that a dynamic linked
+application depends on a new enough GMP.
+
+   An auxiliary mechanism may also be needed to express that
+'libgmpxx.la' (from '--enable-cxx', *note Build Options::) requires
+'libgmp.la' from the same GMP version, since this is not done by the
+libtool versioning, nor otherwise.  A mismatch will result in unresolved
+symbols from the linker, or perhaps the loader.
+
+   When building a package for a CPU family, care should be taken to use
+'--host' (or '--build') to choose the least common denominator among the
+CPUs which might use the package.  For example this might mean plain
+'sparc' (meaning V7) for SPARCs.
+
+   For x86s, '--enable-fat' sets things up for a fat binary build,
+making a runtime selection of optimized low level routines.  This is a
+good choice for packaging to run on a range of x86 chips.
+
+   Users who care about speed will want GMP built for their exact CPU
+type, to make best use of the available optimizations.  Providing a way
+to suitably rebuild a package may be useful.  This could be as simple as
+making it possible for a user to omit '--build' (and '--host') so
+'./config.guess' will detect the CPU.  But a way to manually specify a
+'--build' will be wanted for systems where './config.guess' is inexact.
+
+   On systems with multiple ABIs, a packaged build will need to decide
+which among the choices is to be provided, see *note ABI and ISA::.  A
+given run of './configure' etc will only build one ABI.  If a second ABI
+is also required then a second run of './configure' etc must be made,
+starting from a clean directory tree ('make distclean').
+
+   As noted under "ABI and ISA", currently no attempt is made to follow
+system conventions for install locations that vary with ABI, such as
+'/usr/lib/sparcv9' for 'ABI=64' as opposed to '/usr/lib' for 'ABI=32'.
+A package build can override 'libdir' and other standard variables as
+necessary.
+
+   Note that 'gmp.h' is a generated file, and will be architecture and
+ABI dependent.  When attempting to install two ABIs simultaneously it
+will be important that an application compile gets the correct 'gmp.h'
+for its desired ABI.  If compiler include paths don't vary with ABI
+options then it might be necessary to create a '/usr/include/gmp.h'
+which tests preprocessor symbols and chooses the correct actual 'gmp.h'.
+
+
+File: gmp.info,  Node: Notes for Particular Systems,  Next: Known Build Problems,  Prev: Notes for Package Builds,  Up: Installing GMP
+
+2.4 Notes for Particular Systems
+================================
+
+AIX 3 and 4
+     On systems '*-*-aix[34]*' shared libraries are disabled by default,
+     since some versions of the native 'ar' fail on the convenience
+     libraries used.  A shared build can be attempted with
+
+          ./configure --enable-shared --disable-static
+
+     Note that the '--disable-static' is necessary because in a shared
+     build libtool makes 'libgmp.a' a symlink to 'libgmp.so', apparently
+     for the benefit of old versions of 'ld' which only recognise '.a',
+     but unfortunately this is done even if a fully functional 'ld' is
+     available.
+
+ARM
+     On systems 'arm*-*-*', versions of GCC up to and including 2.95.3
+     have a bug in unsigned division, giving wrong results for some
+     operands.  GMP './configure' will demand GCC 2.95.4 or later.
+
+Compaq C++
+     Compaq C++ on OSF 5.1 has two flavours of 'iostream', a standard
+     one and an old pre-standard one (see 'man iostream_intro').  GMP
+     can only use the standard one, which unfortunately is not the
+     default but must be selected by defining '__USE_STD_IOSTREAM'.
+     Configure with for instance
+
+          ./configure --enable-cxx CPPFLAGS=-D__USE_STD_IOSTREAM
+
+Floating Point Mode
+     On some systems, the hardware floating point has a control mode
+     which can set all operations to be done in a particular precision,
+     for instance single, double or extended on x86 systems (x87
+     floating point).  The GMP functions involving a 'double' cannot be
+     expected to operate to their full precision when the hardware is in
+     single precision mode.  Of course this affects all code, including
+     application code, not just GMP.
+
+FreeBSD 7.x, 8.x, 9.0, 9.1, 9.2
+     'm4' in these releases of FreeBSD has an eval function which
+     ignores its 2nd and 3rd arguments, which makes it unsuitable for
+     '.asm' file processing.  './configure' will detect the problem and
+     either abort or choose another m4 in the 'PATH'.  The bug is fixed
+     in FreeBSD 9.3 and 10.0, so either upgrade or use GNU m4.  Note
+     that the FreeBSD package system installs GNU m4 under the name
+     'gm4', which GMP cannot guess.
+
+FreeBSD 7.x, 8.x, 9.x
+     GMP releases starting with 6.0 do not support 'ABI=32' on
+     FreeBSD/amd64 prior to release 10.0 of the system.  The cause is a
+     broken 'limits.h', which GMP no longer works around.
+
+MS-DOS and MS Windows
+     On an MS-DOS system DJGPP can be used to build GMP, and on an MS
+     Windows system Cygwin, DJGPP and MINGW can be used.  All three are
+     excellent ports of GCC and the various GNU tools.
+
+          <https://www.cygwin.com/>
+          <http://www.delorie.com/djgpp/>
+          <http://www.mingw.org/>
+
+     Microsoft also publishes an Interix "Services for Unix" which can
+     be used to build GMP on Windows (with a normal './configure'), but
+     it's not free software.
+
+MS Windows DLLs
+     On systems '*-*-cygwin*', '*-*-mingw*' and '*-*-pw32*' by default
+     GMP builds only a static library, but a DLL can be built instead
+     using
+
+          ./configure --disable-static --enable-shared
+
+     Static and DLL libraries can't both be built, since certain export
+     directives in 'gmp.h' must be different.
+
+     A MINGW DLL build of GMP can be used with Microsoft C.  Libtool
+     doesn't install a '.lib' format import library, but it can be
+     created with MS 'lib' as follows, and copied to the install
+     directory.  Similarly for 'libmp' and 'libgmpxx'.
+
+          cd .libs
+          lib /def:libgmp-3.dll.def /out:libgmp-3.lib
+
+     MINGW uses the C runtime library 'msvcrt.dll' for I/O, so
+     applications wanting to use the GMP I/O routines must be compiled
+     with 'cl /MD' to do the same.  If one of the other C runtime
+     library choices provided by MS C is desired then the suggestion is
+     to use the GMP string functions and confine I/O to the application.
+
+Motorola 68k CPU Types
+     'm68k' is taken to mean 68000.  'm68020' or higher will give a
+     performance boost on applicable CPUs.  'm68360' can be used for
+     CPU32 series chips.  'm68302' can be used for "Dragonball" series
+     chips, though this is merely a synonym for 'm68000'.
+
+NetBSD 5.x
+     'm4' in these releases of NetBSD has an eval function which ignores
+     its 2nd and 3rd arguments, which makes it unsuitable for '.asm'
+     file processing.  './configure' will detect the problem and either
+     abort or choose another m4 in the 'PATH'.  The bug is fixed in
+     NetBSD 6, so either upgrade or use GNU m4.  Note that the NetBSD
+     package system installs GNU m4 under the name 'gm4', which GMP
+     cannot guess.
+
+OpenBSD 2.6
+     'm4' in this release of OpenBSD has a bug in 'eval' that makes it
+     unsuitable for '.asm' file processing.  './configure' will detect
+     the problem and either abort or choose another m4 in the 'PATH'.
+     The bug is fixed in OpenBSD 2.7, so either upgrade or use GNU m4.
+
+Power CPU Types
+     In GMP, CPU types 'power*' and 'powerpc*' will each use
+     instructions not available on the other, so it's important to
+     choose the right one for the CPU that will be used.  Currently GMP
+     has no assembly code support for using just the common instruction
+     subset.  To get executables that run on both, the current
+     suggestion is to use the generic C code ('--disable-assembly'),
+     possibly with appropriate compiler options (like '-mcpu=common' for
+     'gcc').  CPU 'rs6000' (which is not a CPU but a family of
+     workstations) is accepted by 'config.sub', but is currently
+     equivalent to '--disable-assembly'.
+
+Sparc CPU Types
+     'sparcv8' or 'supersparc' on relevant systems will give a
+     significant performance increase over the V7 code selected by plain
+     'sparc'.
+
+Sparc App Regs
+     The GMP assembly code for both 32-bit and 64-bit Sparc clobbers the
+     "application registers" 'g2', 'g3' and 'g4', the same way that the
+     GCC default '-mapp-regs' does (*note SPARC Options: (gcc)SPARC
+     Options.).
+
+     This makes that code unsuitable for use with the special V9
+     '-mcmodel=embmedany' (which uses 'g4' as a data segment pointer),
+     and for applications wanting to use those registers for special
+     purposes.  In these cases the only suggestion currently is to build
+     GMP with '--disable-assembly' to avoid the assembly code.
+
+SunOS 4
+     '/usr/bin/m4' lacks various features needed to process '.asm'
+     files, and instead './configure' will automatically use
+     '/usr/5bin/m4', which we believe is always available (if not then
+     use GNU m4).
+
+x86 CPU Types
+     'i586', 'pentium' or 'pentiummmx' code is good for its intended P5
+     Pentium chips, but quite slow when run on Intel P6 class chips
+     (PPro, P-II, P-III).  'i386' is a better choice when making
+     binaries that must run on both.
+
+x86 MMX and SSE2 Code
+     If the CPU selected has MMX code but the assembler doesn't support
+     it, a warning is given and non-MMX code is used instead.  This will
+     be an inferior build, since the MMX code that's present is there
+     because it's faster than the corresponding plain integer code.  The
+     same applies to SSE2.
+
+     Old versions of 'gas' don't support MMX instructions, in particular
+     version 1.92.3 that comes with FreeBSD 2.2.8 or the more recent
+     OpenBSD 3.1 doesn't.
+
+     Solaris 2.6 and 2.7 'as' generate incorrect object code for
+     register to register 'movq' instructions, and so can't be used for
+     MMX code.  Install a recent 'gas' if MMX code is wanted on these
+     systems.
+
+
+File: gmp.info,  Node: Known Build Problems,  Next: Performance optimization,  Prev: Notes for Particular Systems,  Up: Installing GMP
+
+2.5 Known Build Problems
+========================
+
+You might find more up-to-date information at <https://gmplib.org/>.
+
+Compiler link options
+     The version of libtool currently in use rather aggressively strips
+     compiler options when linking a shared library.  This will
+     hopefully be relaxed in the future, but for now if this is a
+     problem the suggestion is to create a little script to hide them,
+     and for instance configure with
+
+          ./configure CC=gcc-with-my-options
+
+DJGPP ('*-*-msdosdjgpp*')
+     The DJGPP port of 'bash' 2.03 is unable to run the 'configure'
+     script, it exits silently, having died writing a preamble to
+     'config.log'.  Use 'bash' 2.04 or higher.
+
+     'make all' was found to run out of memory during the final
+     'libgmp.la' link on one system tested, despite having 64Mb
+     available.  Running 'make libgmp.la' directly helped, perhaps
+     recursing into the various subdirectories uses up memory.
+
+GNU binutils 'strip' prior to 2.12
+     'strip' from GNU binutils 2.11 and earlier should not be used on
+     the static libraries 'libgmp.a' and 'libmp.a' since it will discard
+     all but the last of multiple archive members with the same name,
+     like the three versions of 'init.o' in 'libgmp.a'.  Binutils 2.12
+     or higher can be used successfully.
+
+     The shared libraries 'libgmp.so' and 'libmp.so' are not affected by
+     this and any version of 'strip' can be used on them.
+
+'make' syntax error
+     On certain versions of SCO OpenServer 5 and IRIX 6.5 the native
+     'make' is unable to handle the long dependencies list for
+     'libgmp.la'.  The symptom is a "syntax error" on the following line
+     of the top-level 'Makefile'.
+
+          libgmp.la: $(libgmp_la_OBJECTS) $(libgmp_la_DEPENDENCIES)
+
+     Either use GNU Make, or as a workaround remove
+     '$(libgmp_la_DEPENDENCIES)' from that line (which will make the
+     initial build work, but if any recompiling is done 'libgmp.la'
+     might not be rebuilt).
+
+MacOS X ('*-*-darwin*')
+     Libtool currently only knows how to create shared libraries on
+     MacOS X using the native 'cc' (which is a modified GCC), not a
+     plain GCC.  A static-only build should work though
+     ('--disable-shared').
+
+NeXT prior to 3.3
+     The system compiler on old versions of NeXT was a massacred and old
+     GCC, even if it called itself 'cc'.  This compiler cannot be used
+     to build GMP, you need to get a real GCC, and install that.  (NeXT
+     may have fixed this in release 3.3 of their system.)
+
+POWER and PowerPC
+     Bugs in GCC 2.7.2 (and 2.6.3) mean it can't be used to compile GMP
+     on POWER or PowerPC.  If you want to use GCC for these machines,
+     get GCC 2.7.2.1 (or later).
+
+Sequent Symmetry
+     Use the GNU assembler instead of the system assembler, since the
+     latter has serious bugs.
+
+Solaris 2.6
+     The system 'sed' prints an error "Output line too long" when
+     libtool builds 'libgmp.la'.  This doesn't seem to cause any obvious
+     ill effects, but GNU 'sed' is recommended, to avoid any doubt.
+
+Sparc Solaris 2.7 with gcc 2.95.2 in 'ABI=32'
+     A shared library build of GMP seems to fail in this combination, it
+     builds but then fails the tests, apparently due to some incorrect
+     data relocations within 'gmp_randinit_lc_2exp_size'.  The exact
+     cause is unknown, '--disable-shared' is recommended.
+
+
+File: gmp.info,  Node: Performance optimization,  Prev: Known Build Problems,  Up: Installing GMP
+
+2.6 Performance optimization
+============================
+
+For optimal performance, build GMP for the exact CPU type of the target
+computer, see *note Build Options::.
+
+   Unlike what is the case for most other programs, the compiler
+typically doesn't matter much, since GMP uses assembly language for the
+most critical operation.
+
+   In particular for long-running GMP applications, and applications
+demanding extremely large numbers, building and running the 'tuneup'
+program in the 'tune' subdirectory, can be important.  For example,
+
+     cd tune
+     make tuneup
+     ./tuneup
+
+   will generate better contents for the 'gmp-mparam.h' parameter file.
+
+   To use the results, put the output in the file indicated in the
+'Parameters for ...' header.  Then recompile from scratch.
+
+   The 'tuneup' program takes one useful parameter, '-f NNN', which
+instructs the program how long to check FFT multiply parameters.  If
+you're going to use GMP for extremely large numbers, you may want to run
+'tuneup' with a large NNN value.
+
+
+File: gmp.info,  Node: GMP Basics,  Next: Reporting Bugs,  Prev: Installing GMP,  Up: Top
+
+3 GMP Basics
+************
+
+*Using functions, macros, data types, etc. not documented in this manual
+is strongly discouraged.  If you do so your application is guaranteed to
+be incompatible with future versions of GMP.*
+
+* Menu:
+
+* Headers and Libraries::
+* Nomenclature and Types::
+* Function Classes::
+* Variable Conventions::
+* Parameter Conventions::
+* Memory Management::
+* Reentrancy::
+* Useful Macros and Constants::
+* Compatibility with older versions::
+* Demonstration Programs::
+* Efficiency::
+* Debugging::
+* Profiling::
+* Autoconf::
+* Emacs::
+
+
+File: gmp.info,  Node: Headers and Libraries,  Next: Nomenclature and Types,  Prev: GMP Basics,  Up: GMP Basics
+
+3.1 Headers and Libraries
+=========================
+
+All declarations needed to use GMP are collected in the include file
+'gmp.h'.  It is designed to work with both C and C++ compilers.
+
+     #include <gmp.h>
+
+   Note however that prototypes for GMP functions with 'FILE *'
+parameters are only provided if '<stdio.h>' is included too.
+
+     #include <stdio.h>
+     #include <gmp.h>
+
+   Likewise '<stdarg.h>' is required for prototypes with 'va_list'
+parameters, such as 'gmp_vprintf'.  And '<obstack.h>' for prototypes
+with 'struct obstack' parameters, such as 'gmp_obstack_printf', when
+available.
+
+   All programs using GMP must link against the 'libgmp' library.  On a
+typical Unix-like system this can be done with '-lgmp', for example
+
+     gcc myprogram.c -lgmp
+
+   GMP C++ functions are in a separate 'libgmpxx' library.  This is
+built and installed if C++ support has been enabled (*note Build
+Options::).  For example,
+
+     g++ mycxxprog.cc -lgmpxx -lgmp
+
+   GMP is built using Libtool and an application can use that to link if
+desired, *note GNU Libtool: (libtool)Top.
+
+   If GMP has been installed to a non-standard location then it may be
+necessary to use '-I' and '-L' compiler options to point to the right
+directories, and some sort of run-time path for a shared library.
+
+
+File: gmp.info,  Node: Nomenclature and Types,  Next: Function Classes,  Prev: Headers and Libraries,  Up: GMP Basics
+
+3.2 Nomenclature and Types
+==========================
+
+In this manual, "integer" usually means a multiple precision integer, as
+defined by the GMP library.  The C data type for such integers is
+'mpz_t'.  Here are some examples of how to declare such integers:
+
+     mpz_t sum;
+
+     struct foo { mpz_t x, y; };
+
+     mpz_t vec[20];
+
+   "Rational number" means a multiple precision fraction.  The C data
+type for these fractions is 'mpq_t'.  For example:
+
+     mpq_t quotient;
+
+   "Floating point number" or "Float" for short, is an arbitrary
+precision mantissa with a limited precision exponent.  The C data type
+for such objects is 'mpf_t'.  For example:
+
+     mpf_t fp;
+
+   The floating point functions accept and return exponents in the C
+type 'mp_exp_t'.  Currently this is usually a 'long', but on some
+systems it's an 'int' for efficiency.
+
+   A "limb" means the part of a multi-precision number that fits in a
+single machine word.  (We chose this word because a limb of the human
+body is analogous to a digit, only larger, and containing several
+digits.)  Normally a limb is 32 or 64 bits.  The C data type for a limb
+is 'mp_limb_t'.
+
+   Counts of limbs of a multi-precision number represented in the C type
+'mp_size_t'.  Currently this is normally a 'long', but on some systems
+it's an 'int' for efficiency, and on some systems it will be 'long long'
+in the future.
+
+   Counts of bits of a multi-precision number are represented in the C
+type 'mp_bitcnt_t'.  Currently this is always an 'unsigned long', but on
+some systems it will be an 'unsigned long long' in the future.
+
+   "Random state" means an algorithm selection and current state data.
+The C data type for such objects is 'gmp_randstate_t'.  For example:
+
+     gmp_randstate_t rstate;
+
+   Also, in general 'mp_bitcnt_t' is used for bit counts and ranges, and
+'size_t' is used for byte or character counts.
+
+
+File: gmp.info,  Node: Function Classes,  Next: Variable Conventions,  Prev: Nomenclature and Types,  Up: GMP Basics
+
+3.3 Function Classes
+====================
+
+There are six classes of functions in the GMP library:
+
+  1. Functions for signed integer arithmetic, with names beginning with
+     'mpz_'.  The associated type is 'mpz_t'.  There are about 150
+     functions in this class.  (*note Integer Functions::)
+
+  2. Functions for rational number arithmetic, with names beginning with
+     'mpq_'.  The associated type is 'mpq_t'.  There are about 35
+     functions in this class, but the integer functions can be used for
+     arithmetic on the numerator and denominator separately.  (*note
+     Rational Number Functions::)
+
+  3. Functions for floating-point arithmetic, with names beginning with
+     'mpf_'.  The associated type is 'mpf_t'.  There are about 70
+     functions is this class.  (*note Floating-point Functions::)
+
+  4. Fast low-level functions that operate on natural numbers.  These
+     are used by the functions in the preceding groups, and you can also
+     call them directly from very time-critical user programs.  These
+     functions' names begin with 'mpn_'.  The associated type is array
+     of 'mp_limb_t'.  There are about 60 (hard-to-use) functions in this
+     class.  (*note Low-level Functions::)
+
+  5. Miscellaneous functions.  Functions for setting up custom
+     allocation and functions for generating random numbers.  (*note
+     Custom Allocation::, and *note Random Number Functions::)
+
+
+File: gmp.info,  Node: Variable Conventions,  Next: Parameter Conventions,  Prev: Function Classes,  Up: GMP Basics
+
+3.4 Variable Conventions
+========================
+
+GMP functions generally have output arguments before input arguments.
+This notation is by analogy with the assignment operator.
+
+   GMP lets you use the same variable for both input and output in one
+call.  For example, the main function for integer multiplication,
+'mpz_mul', can be used to square 'x' and put the result back in 'x' with
+
+     mpz_mul (x, x, x);
+
+   Before you can assign to a GMP variable, you need to initialize it by
+calling one of the special initialization functions.  When you're done
+with a variable, you need to clear it out, using one of the functions
+for that purpose.  Which function to use depends on the type of
+variable.  See the chapters on integer functions, rational number
+functions, and floating-point functions for details.
+
+   A variable should only be initialized once, or at least cleared
+between each initialization.  After a variable has been initialized, it
+may be assigned to any number of times.
+
+   For efficiency reasons, avoid excessive initializing and clearing.
+In general, initialize near the start of a function and clear near the
+end.  For example,
+
+     void
+     foo (void)
+     {
+       mpz_t  n;
+       int    i;
+       mpz_init (n);
+       for (i = 1; i < 100; i++)
+         {
+           mpz_mul (n, ...);
+           mpz_fdiv_q (n, ...);
+           ...
+         }
+       mpz_clear (n);
+     }
+
+   GMP types like 'mpz_t' are implemented as one-element arrays of
+certain structures.  Declaring a variable creates an object with the
+fields GMP needs, but variables are normally manipulated by using the
+pointer to the object.  For both behavior and efficiency reasons, it is
+discouraged to make copies of the GMP object itself (either directly or
+via aggregate objects containing such GMP objects).  If copies are done,
+all of them must be used read-only; using a copy as the output of some
+function will invalidate all the other copies.  Note that the actual
+fields in each 'mpz_t' etc are for internal use only and should not be
+accessed directly by code that expects to be compatible with future GMP
+releases.
+
+
+File: gmp.info,  Node: Parameter Conventions,  Next: Memory Management,  Prev: Variable Conventions,  Up: GMP Basics
+
+3.5 Parameter Conventions
+=========================
+
+When a GMP variable is used as a function parameter, it's effectively a
+call-by-reference, meaning that when the function stores a value there
+it will change the original in the caller.  Parameters which are
+input-only can be designated 'const' to provoke a compiler error or
+warning on attempting to modify them.
+
+   When a function is going to return a GMP result, it should designate
+a parameter that it sets, like the library functions do.  More than one
+value can be returned by having more than one output parameter, again
+like the library functions.  A 'return' of an 'mpz_t' etc doesn't return
+the object, only a pointer, and this is almost certainly not what's
+wanted.
+
+   Here's an example accepting an 'mpz_t' parameter, doing a
+calculation, and storing the result to the indicated parameter.
+
+     void
+     foo (mpz_t result, const mpz_t param, unsigned long n)
+     {
+       unsigned long  i;
+       mpz_mul_ui (result, param, n);
+       for (i = 1; i < n; i++)
+         mpz_add_ui (result, result, i*7);
+     }
+
+     int
+     main (void)
+     {
+       mpz_t  r, n;
+       mpz_init (r);
+       mpz_init_set_str (n, "123456", 0);
+       foo (r, n, 20L);
+       gmp_printf ("%Zd\n", r);
+       return 0;
+     }
+
+   Our function 'foo' works even if its caller passes the same variable
+for 'param' and 'result', just like the library functions.  But
+sometimes it's tricky to make that work, and an application might not
+want to bother supporting that sort of thing.
+
+   Since GMP types are implemented as one-element arrays, using a GMP
+variable as a parameter passes a pointer to the object.  Hence the
+call-by-reference.
+
+
+File: gmp.info,  Node: Memory Management,  Next: Reentrancy,  Prev: Parameter Conventions,  Up: GMP Basics
+
+3.6 Memory Management
+=====================
+
+The GMP types like 'mpz_t' are small, containing only a couple of sizes,
+and pointers to allocated data.  Once a variable is initialized, GMP
+takes care of all space allocation.  Additional space is allocated
+whenever a variable doesn't have enough.
+
+   'mpz_t' and 'mpq_t' variables never reduce their allocated space.
+Normally this is the best policy, since it avoids frequent reallocation.
+Applications that need to return memory to the heap at some particular
+point can use 'mpz_realloc2', or clear variables no longer needed.
+
+   'mpf_t' variables, in the current implementation, use a fixed amount
+of space, determined by the chosen precision and allocated at
+initialization, so their size doesn't change.
+
+   All memory is allocated using 'malloc' and friends by default, but
+this can be changed, see *note Custom Allocation::.  Temporary memory on
+the stack is also used (via 'alloca'), but this can be changed at
+build-time if desired, see *note Build Options::.
+
+
+File: gmp.info,  Node: Reentrancy,  Next: Useful Macros and Constants,  Prev: Memory Management,  Up: GMP Basics
+
+3.7 Reentrancy
+==============
+
+GMP is reentrant and thread-safe, with some exceptions:
+
+   * If configured with '--enable-alloca=malloc-notreentrant' (or with
+     '--enable-alloca=notreentrant' when 'alloca' is not available),
+     then naturally GMP is not reentrant.
+
+   * 'mpf_set_default_prec' and 'mpf_init' use a global variable for the
+     selected precision.  'mpf_init2' can be used instead, and in the
+     C++ interface an explicit precision to the 'mpf_class' constructor.
+
+   * 'mpz_random' and the other old random number functions use a global
+     random state and are hence not reentrant.  The newer random number
+     functions that accept a 'gmp_randstate_t' parameter can be used
+     instead.
+
+   * 'gmp_randinit' (obsolete) returns an error indication through a
+     global variable, which is not thread safe.  Applications are
+     advised to use 'gmp_randinit_default' or 'gmp_randinit_lc_2exp'
+     instead.
+
+   * 'mp_set_memory_functions' uses global variables to store the
+     selected memory allocation functions.
+
+   * If the memory allocation functions set by a call to
+     'mp_set_memory_functions' (or 'malloc' and friends by default) are
+     not reentrant, then GMP will not be reentrant either.
+
+   * If the standard I/O functions such as 'fwrite' are not reentrant
+     then the GMP I/O functions using them will not be reentrant either.
+
+   * It's safe for two threads to read from the same GMP variable
+     simultaneously, but it's not safe for one to read while another
+     might be writing, nor for two threads to write simultaneously.
+     It's not safe for two threads to generate a random number from the
+     same 'gmp_randstate_t' simultaneously, since this involves an
+     update of that variable.
+
+
+File: gmp.info,  Node: Useful Macros and Constants,  Next: Compatibility with older versions,  Prev: Reentrancy,  Up: GMP Basics
+
+3.8 Useful Macros and Constants
+===============================
+
+ -- Global Constant: const int mp_bits_per_limb
+     The number of bits per limb.
+
+ -- Macro: __GNU_MP_VERSION
+ -- Macro: __GNU_MP_VERSION_MINOR
+ -- Macro: __GNU_MP_VERSION_PATCHLEVEL
+     The major and minor GMP version, and patch level, respectively, as
+     integers.  For GMP i.j, these numbers will be i, j, and 0,
+     respectively.  For GMP i.j.k, these numbers will be i, j, and k,
+     respectively.
+
+ -- Global Constant: const char * const gmp_version
+     The GMP version number, as a null-terminated string, in the form
+     "i.j.k".  This release is "6.2.0".  Note that the format "i.j" was
+     used, before version 4.3.0, when k was zero.
+
+ -- Macro: __GMP_CC
+ -- Macro: __GMP_CFLAGS
+     The compiler and compiler flags, respectively, used when compiling
+     GMP, as strings.
+
+
+File: gmp.info,  Node: Compatibility with older versions,  Next: Demonstration Programs,  Prev: Useful Macros and Constants,  Up: GMP Basics
+
+3.9 Compatibility with older versions
+=====================================
+
+This version of GMP is upwardly binary compatible with all 5.x, 4.x, and
+3.x versions, and upwardly compatible at the source level with all 2.x
+versions, with the following exceptions.
+
+   * 'mpn_gcd' had its source arguments swapped as of GMP 3.0, for
+     consistency with other 'mpn' functions.
+
+   * 'mpf_get_prec' counted precision slightly differently in GMP 3.0
+     and 3.0.1, but in 3.1 reverted to the 2.x style.
+
+   * 'mpn_bdivmod', documented as preliminary in GMP 4, has been
+     removed.
+
+   There are a number of compatibility issues between GMP 1 and GMP 2
+that of course also apply when porting applications from GMP 1 to GMP 5.
+Please see the GMP 2 manual for details.
+
+
+File: gmp.info,  Node: Demonstration Programs,  Next: Efficiency,  Prev: Compatibility with older versions,  Up: GMP Basics
+
+3.10 Demonstration programs
+===========================
+
+The 'demos' subdirectory has some sample programs using GMP.  These
+aren't built or installed, but there's a 'Makefile' with rules for them.
+For instance,
+
+     make pexpr
+     ./pexpr 68^975+10
+
+The following programs are provided
+
+   * 'pexpr' is an expression evaluator, the program used on the GMP web
+     page.
+   * The 'calc' subdirectory has a similar but simpler evaluator using
+     'lex' and 'yacc'.
+   * The 'expr' subdirectory is yet another expression evaluator, a
+     library designed for ease of use within a C program.  See
+     'demos/expr/README' for more information.
+   * 'factorize' is a Pollard-Rho factorization program.
+   * 'isprime' is a command-line interface to the 'mpz_probab_prime_p'
+     function.
+   * 'primes' counts or lists primes in an interval, using a sieve.
+   * 'qcn' is an example use of 'mpz_kronecker_ui' to estimate quadratic
+     class numbers.
+   * The 'perl' subdirectory is a comprehensive perl interface to GMP.
+     See 'demos/perl/INSTALL' for more information.  Documentation is in
+     POD format in 'demos/perl/GMP.pm'.
+
+   As an aside, consideration has been given at various times to some
+sort of expression evaluation within the main GMP library.  Going beyond
+something minimal quickly leads to matters like user-defined functions,
+looping, fixnums for control variables, etc, which are considered
+outside the scope of GMP (much closer to language interpreters or
+compilers, *Note Language Bindings::.)  Something simple for program
+input convenience may yet be a possibility, a combination of the 'expr'
+demo and the 'pexpr' tree back-end perhaps.  But for now the above
+evaluators are offered as illustrations.
+
+
+File: gmp.info,  Node: Efficiency,  Next: Debugging,  Prev: Demonstration Programs,  Up: GMP Basics
+
+3.11 Efficiency
+===============
+
+Small Operands
+     On small operands, the time for function call overheads and memory
+     allocation can be significant in comparison to actual calculation.
+     This is unavoidable in a general purpose variable precision
+     library, although GMP attempts to be as efficient as it can on both
+     large and small operands.
+
+Static Linking
+     On some CPUs, in particular the x86s, the static 'libgmp.a' should
+     be used for maximum speed, since the PIC code in the shared
+     'libgmp.so' will have a small overhead on each function call and
+     global data address.  For many programs this will be insignificant,
+     but for long calculations there's a gain to be had.
+
+Initializing and Clearing
+     Avoid excessive initializing and clearing of variables, since this
+     can be quite time consuming, especially in comparison to otherwise
+     fast operations like addition.
+
+     A language interpreter might want to keep a free list or stack of
+     initialized variables ready for use.  It should be possible to
+     integrate something like that with a garbage collector too.
+
+Reallocations
+     An 'mpz_t' or 'mpq_t' variable used to hold successively increasing
+     values will have its memory repeatedly 'realloc'ed, which could be
+     quite slow or could fragment memory, depending on the C library.
+     If an application can estimate the final size then 'mpz_init2' or
+     'mpz_realloc2' can be called to allocate the necessary space from
+     the beginning (*note Initializing Integers::).
+
+     It doesn't matter if a size set with 'mpz_init2' or 'mpz_realloc2'
+     is too small, since all functions will do a further reallocation if
+     necessary.  Badly overestimating memory required will waste space
+     though.
+
+'2exp' Functions
+     It's up to an application to call functions like 'mpz_mul_2exp'
+     when appropriate.  General purpose functions like 'mpz_mul' make no
+     attempt to identify powers of two or other special forms, because
+     such inputs will usually be very rare and testing every time would
+     be wasteful.
+
+'ui' and 'si' Functions
+     The 'ui' functions and the small number of 'si' functions exist for
+     convenience and should be used where applicable.  But if for
+     example an 'mpz_t' contains a value that fits in an 'unsigned long'
+     there's no need extract it and call a 'ui' function, just use the
+     regular 'mpz' function.
+
+In-Place Operations
+     'mpz_abs', 'mpq_abs', 'mpf_abs', 'mpz_neg', 'mpq_neg' and 'mpf_neg'
+     are fast when used for in-place operations like 'mpz_abs(x,x)',
+     since in the current implementation only a single field of 'x'
+     needs changing.  On suitable compilers (GCC for instance) this is
+     inlined too.
+
+     'mpz_add_ui', 'mpz_sub_ui', 'mpf_add_ui' and 'mpf_sub_ui' benefit
+     from an in-place operation like 'mpz_add_ui(x,x,y)', since usually
+     only one or two limbs of 'x' will need to be changed.  The same
+     applies to the full precision 'mpz_add' etc if 'y' is small.  If
+     'y' is big then cache locality may be helped, but that's all.
+
+     'mpz_mul' is currently the opposite, a separate destination is
+     slightly better.  A call like 'mpz_mul(x,x,y)' will, unless 'y' is
+     only one limb, make a temporary copy of 'x' before forming the
+     result.  Normally that copying will only be a tiny fraction of the
+     time for the multiply, so this is not a particularly important
+     consideration.
+
+     'mpz_set', 'mpq_set', 'mpq_set_num', 'mpf_set', etc, make no
+     attempt to recognise a copy of something to itself, so a call like
+     'mpz_set(x,x)' will be wasteful.  Naturally that would never be
+     written deliberately, but if it might arise from two pointers to
+     the same object then a test to avoid it might be desirable.
+
+          if (x != y)
+            mpz_set (x, y);
+
+     Note that it's never worth introducing extra 'mpz_set' calls just
+     to get in-place operations.  If a result should go to a particular
+     variable then just direct it there and let GMP take care of data
+     movement.
+
+Divisibility Testing (Small Integers)
+     'mpz_divisible_ui_p' and 'mpz_congruent_ui_p' are the best
+     functions for testing whether an 'mpz_t' is divisible by an
+     individual small integer.  They use an algorithm which is faster
+     than 'mpz_tdiv_ui', but which gives no useful information about the
+     actual remainder, only whether it's zero (or a particular value).
+
+     However when testing divisibility by several small integers, it's
+     best to take a remainder modulo their product, to save
+     multi-precision operations.  For instance to test whether a number
+     is divisible by any of 23, 29 or 31 take a remainder modulo
+     23*29*31 = 20677 and then test that.
+
+     The division functions like 'mpz_tdiv_q_ui' which give a quotient
+     as well as a remainder are generally a little slower than the
+     remainder-only functions like 'mpz_tdiv_ui'.  If the quotient is
+     only rarely wanted then it's probably best to just take a remainder
+     and then go back and calculate the quotient if and when it's wanted
+     ('mpz_divexact_ui' can be used if the remainder is zero).
+
+Rational Arithmetic
+     The 'mpq' functions operate on 'mpq_t' values with no common
+     factors in the numerator and denominator.  Common factors are
+     checked-for and cast out as necessary.  In general, cancelling
+     factors every time is the best approach since it minimizes the
+     sizes for subsequent operations.
+
+     However, applications that know something about the factorization
+     of the values they're working with might be able to avoid some of
+     the GCDs used for canonicalization, or swap them for divisions.
+     For example when multiplying by a prime it's enough to check for
+     factors of it in the denominator instead of doing a full GCD.  Or
+     when forming a big product it might be known that very little
+     cancellation will be possible, and so canonicalization can be left
+     to the end.
+
+     The 'mpq_numref' and 'mpq_denref' macros give access to the
+     numerator and denominator to do things outside the scope of the
+     supplied 'mpq' functions.  *Note Applying Integer Functions::.
+
+     The canonical form for rationals allows mixed-type 'mpq_t' and
+     integer additions or subtractions to be done directly with
+     multiples of the denominator.  This will be somewhat faster than
+     'mpq_add'.  For example,
+
+          /* mpq increment */
+          mpz_add (mpq_numref(q), mpq_numref(q), mpq_denref(q));
+
+          /* mpq += unsigned long */
+          mpz_addmul_ui (mpq_numref(q), mpq_denref(q), 123UL);
+
+          /* mpq -= mpz */
+          mpz_submul (mpq_numref(q), mpq_denref(q), z);
+
+Number Sequences
+     Functions like 'mpz_fac_ui', 'mpz_fib_ui' and 'mpz_bin_uiui' are
+     designed for calculating isolated values.  If a range of values is
+     wanted it's probably best to call to get a starting point and
+     iterate from there.
+
+Text Input/Output
+     Hexadecimal or octal are suggested for input or output in text
+     form.  Power-of-2 bases like these can be converted much more
+     efficiently than other bases, like decimal.  For big numbers
+     there's usually nothing of particular interest to be seen in the
+     digits, so the base doesn't matter much.
+
+     Maybe we can hope octal will one day become the normal base for
+     everyday use, as proposed by King Charles XII of Sweden and later
+     reformers.
+
+
+File: gmp.info,  Node: Debugging,  Next: Profiling,  Prev: Efficiency,  Up: GMP Basics
+
+3.12 Debugging
+==============
+
+Stack Overflow
+     Depending on the system, a segmentation violation or bus error
+     might be the only indication of stack overflow.  See
+     '--enable-alloca' choices in *note Build Options::, for how to
+     address this.
+
+     In new enough versions of GCC, '-fstack-check' may be able to
+     ensure an overflow is recognised by the system before too much
+     damage is done, or '-fstack-limit-symbol' or
+     '-fstack-limit-register' may be able to add checking if the system
+     itself doesn't do any (*note Options for Code Generation: (gcc)Code
+     Gen Options.).  These options must be added to the 'CFLAGS' used in
+     the GMP build (*note Build Options::), adding them just to an
+     application will have no effect.  Note also they're a slowdown,
+     adding overhead to each function call and each stack allocation.
+
+Heap Problems
+     The most likely cause of application problems with GMP is heap
+     corruption.  Failing to 'init' GMP variables will have
+     unpredictable effects, and corruption arising elsewhere in a
+     program may well affect GMP.  Initializing GMP variables more than
+     once or failing to clear them will cause memory leaks.
+
+     In all such cases a 'malloc' debugger is recommended.  On a GNU or
+     BSD system the standard C library 'malloc' has some diagnostic
+     facilities, see *note Allocation Debugging: (libc)Allocation
+     Debugging, or 'man 3 malloc'.  Other possibilities, in no
+     particular order, include
+
+          <http://cs.ecs.baylor.edu/~donahoo/tools/ccmalloc/>
+          <http://dmalloc.com/>
+          <https://wiki.gnome.org/Apps/MemProf>
+
+     The GMP default allocation routines in 'memory.c' also have a
+     simple sentinel scheme which can be enabled with '#define DEBUG' in
+     that file.  This is mainly designed for detecting buffer overruns
+     during GMP development, but might find other uses.
+
+Stack Backtraces
+     On some systems the compiler options GMP uses by default can
+     interfere with debugging.  In particular on x86 and 68k systems
+     '-fomit-frame-pointer' is used and this generally inhibits stack
+     backtracing.  Recompiling without such options may help while
+     debugging, though the usual caveats about it potentially moving a
+     memory problem or hiding a compiler bug will apply.
+
+GDB, the GNU Debugger
+     A sample '.gdbinit' is included in the distribution, showing how to
+     call some undocumented dump functions to print GMP variables from
+     within GDB.  Note that these functions shouldn't be used in final
+     application code since they're undocumented and may be subject to
+     incompatible changes in future versions of GMP.
+
+Source File Paths
+     GMP has multiple source files with the same name, in different
+     directories.  For example 'mpz', 'mpq' and 'mpf' each have an
+     'init.c'.  If the debugger can't already determine the right one it
+     may help to build with absolute paths on each C file.  One way to
+     do that is to use a separate object directory with an absolute path
+     to the source directory.
+
+          cd /my/build/dir
+          /my/source/dir/gmp-6.2.0/configure
+
+     This works via 'VPATH', and might require GNU 'make'.  Alternately
+     it might be possible to change the '.c.lo' rules appropriately.
+
+Assertion Checking
+     The build option '--enable-assert' is available to add some
+     consistency checks to the library (see *note Build Options::).
+     These are likely to be of limited value to most applications.
+     Assertion failures are just as likely to indicate memory corruption
+     as a library or compiler bug.
+
+     Applications using the low-level 'mpn' functions, however, will
+     benefit from '--enable-assert' since it adds checks on the
+     parameters of most such functions, many of which have subtle
+     restrictions on their usage.  Note however that only the generic C
+     code has checks, not the assembly code, so '--disable-assembly'
+     should be used for maximum checking.
+
+Temporary Memory Checking
+     The build option '--enable-alloca=debug' arranges that each block
+     of temporary memory in GMP is allocated with a separate call to
+     'malloc' (or the allocation function set with
+     'mp_set_memory_functions').
+
+     This can help a malloc debugger detect accesses outside the
+     intended bounds, or detect memory not released.  In a normal build,
+     on the other hand, temporary memory is allocated in blocks which
+     GMP divides up for its own use, or may be allocated with a compiler
+     builtin 'alloca' which will go nowhere near any malloc debugger
+     hooks.
+
+Maximum Debuggability
+     To summarize the above, a GMP build for maximum debuggability would
+     be
+
+          ./configure --disable-shared --enable-assert \
+            --enable-alloca=debug --disable-assembly CFLAGS=-g
+
+     For C++, add '--enable-cxx CXXFLAGS=-g'.
+
+Checker
+     The GCC checker (<https://savannah.nongnu.org/projects/checker/>)
+     can be used with GMP.  It contains a stub library which means GMP
+     applications compiled with checker can use a normal GMP build.
+
+     A build of GMP with checking within GMP itself can be made.  This
+     will run very very slowly.  On GNU/Linux for example,
+
+          ./configure --disable-assembly CC=checkergcc
+
+     '--disable-assembly' must be used, since the GMP assembly code
+     doesn't support the checking scheme.  The GMP C++ features cannot
+     be used, since current versions of checker (0.9.9.1) don't yet
+     support the standard C++ library.
+
+Valgrind
+     Valgrind (<http://valgrind.org/>) is a memory checker for x86, ARM,
+     MIPS, PowerPC, and S/390.  It translates and emulates machine
+     instructions to do strong checks for uninitialized data (at the
+     level of individual bits), memory accesses through bad pointers,
+     and memory leaks.
+
+     Valgrind does not always support every possible instruction, in
+     particular ones recently added to an ISA. Valgrind might therefore
+     be incompatible with a recent GMP or even a less recent GMP which
+     is compiled using a recent GCC.
+
+     GMP's assembly code sometimes promotes a read of the limbs to some
+     larger size, for efficiency.  GMP will do this even at the start
+     and end of a multilimb operand, using naturally aligned operations
+     on the larger type.  This may lead to benign reads outside of
+     allocated areas, triggering complaints from Valgrind.  Valgrind's
+     option '--partial-loads-ok=yes' should help.
+
+Other Problems
+     Any suspected bug in GMP itself should be isolated to make sure
+     it's not an application problem, see *note Reporting Bugs::.
+
+
+File: gmp.info,  Node: Profiling,  Next: Autoconf,  Prev: Debugging,  Up: GMP Basics
+
+3.13 Profiling
+==============
+
+Running a program under a profiler is a good way to find where it's
+spending most time and where improvements can be best sought.  The
+profiling choices for a GMP build are as follows.
+
+'--disable-profiling'
+     The default is to add nothing special for profiling.
+
+     It should be possible to just compile the mainline of a program
+     with '-p' and use 'prof' to get a profile consisting of timer-based
+     sampling of the program counter.  Most of the GMP assembly code has
+     the necessary symbol information.
+
+     This approach has the advantage of minimizing interference with
+     normal program operation, but on most systems the resolution of the
+     sampling is quite low (10 milliseconds for instance), requiring
+     long runs to get accurate information.
+
+'--enable-profiling=prof'
+     Build with support for the system 'prof', which means '-p' added to
+     the 'CFLAGS'.
+
+     This provides call counting in addition to program counter
+     sampling, which allows the most frequently called routines to be
+     identified, and an average time spent in each routine to be
+     determined.
+
+     The x86 assembly code has support for this option, but on other
+     processors the assembly routines will be as if compiled without
+     '-p' and therefore won't appear in the call counts.
+
+     On some systems, such as GNU/Linux, '-p' in fact means '-pg' and in
+     this case '--enable-profiling=gprof' described below should be used
+     instead.
+
+'--enable-profiling=gprof'
+     Build with support for 'gprof', which means '-pg' added to the
+     'CFLAGS'.
+
+     This provides call graph construction in addition to call counting
+     and program counter sampling, which makes it possible to count
+     calls coming from different locations.  For example the number of
+     calls to 'mpn_mul' from 'mpz_mul' versus the number from 'mpf_mul'.
+     The program counter sampling is still flat though, so only a total
+     time in 'mpn_mul' would be accumulated, not a separate amount for
+     each call site.
+
+     The x86 assembly code has support for this option, but on other
+     processors the assembly routines will be as if compiled without
+     '-pg' and therefore not be included in the call counts.
+
+     On x86 and m68k systems '-pg' and '-fomit-frame-pointer' are
+     incompatible, so the latter is omitted from the default flags in
+     that case, which might result in poorer code generation.
+
+     Incidentally, it should be possible to use the 'gprof' program with
+     a plain '--enable-profiling=prof' build.  But in that case only the
+     'gprof -p' flat profile and call counts can be expected to be
+     valid, not the 'gprof -q' call graph.
+
+'--enable-profiling=instrument'
+     Build with the GCC option '-finstrument-functions' added to the
+     'CFLAGS' (*note Options for Code Generation: (gcc)Code Gen
+     Options.).
+
+     This inserts special instrumenting calls at the start and end of
+     each function, allowing exact timing and full call graph
+     construction.
+
+     This instrumenting is not normally a standard system feature and
+     will require support from an external library, such as
+
+          <https://sourceforge.net/projects/fnccheck/>
+
+     This should be included in 'LIBS' during the GMP configure so that
+     test programs will link.  For example,
+
+          ./configure --enable-profiling=instrument LIBS=-lfc
+
+     On a GNU system the C library provides dummy instrumenting
+     functions, so programs compiled with this option will link.  In
+     this case it's only necessary to ensure the correct library is
+     added when linking an application.
+
+     The x86 assembly code supports this option, but on other processors
+     the assembly routines will be as if compiled without
+     '-finstrument-functions' meaning time spent in them will
+     effectively be attributed to their caller.
+
+
+File: gmp.info,  Node: Autoconf,  Next: Emacs,  Prev: Profiling,  Up: GMP Basics
+
+3.14 Autoconf
+=============
+
+Autoconf based applications can easily check whether GMP is installed.
+The only thing to be noted is that GMP library symbols from version 3
+onwards have prefixes like '__gmpz'.  The following therefore would be a
+simple test,
+
+     AC_CHECK_LIB(gmp, __gmpz_init)
+
+   This just uses the default 'AC_CHECK_LIB' actions for found or not
+found, but an application that must have GMP would want to generate an
+error if not found.  For example,
+
+     AC_CHECK_LIB(gmp, __gmpz_init, ,
+       [AC_MSG_ERROR([GNU MP not found, see https://gmplib.org/])])
+
+   If functions added in some particular version of GMP are required,
+then one of those can be used when checking.  For example 'mpz_mul_si'
+was added in GMP 3.1,
+
+     AC_CHECK_LIB(gmp, __gmpz_mul_si, ,
+       [AC_MSG_ERROR(
+       [GNU MP not found, or not 3.1 or up, see https://gmplib.org/])])
+
+   An alternative would be to test the version number in 'gmp.h' using
+say 'AC_EGREP_CPP'.  That would make it possible to test the exact
+version, if some particular sub-minor release is known to be necessary.
+
+   In general it's recommended that applications should simply demand a
+new enough GMP rather than trying to provide supplements for features
+not available in past versions.
+
+   Occasionally an application will need or want to know the size of a
+type at configuration or preprocessing time, not just with 'sizeof' in
+the code.  This can be done in the normal way with 'mp_limb_t' etc, but
+GMP 4.0 or up is best for this, since prior versions needed certain '-D'
+defines on systems using a 'long long' limb.  The following would suit
+Autoconf 2.50 or up,
+
+     AC_CHECK_SIZEOF(mp_limb_t, , [#include <gmp.h>])
+
+
+File: gmp.info,  Node: Emacs,  Prev: Autoconf,  Up: GMP Basics
+
+3.15 Emacs
+==========
+
+<C-h C-i> ('info-lookup-symbol') is a good way to find documentation on
+C functions while editing (*note Info Documentation Lookup: (emacs)Info
+Lookup.).
+
+   The GMP manual can be included in such lookups by putting the
+following in your '.emacs',
+
+     (eval-after-load "info-look"
+       '(let ((mode-value (assoc 'c-mode (assoc 'symbol info-lookup-alist))))
+          (setcar (nthcdr 3 mode-value)
+                  (cons '("(gmp)Function Index" nil "^ -.* " "\\>")
+                        (nth 3 mode-value)))))
+
+
+File: gmp.info,  Node: Reporting Bugs,  Next: Integer Functions,  Prev: GMP Basics,  Up: Top
+
+4 Reporting Bugs
+****************
+
+If you think you have found a bug in the GMP library, please investigate
+it and report it.  We have made this library available to you, and it is
+not too much to ask you to report the bugs you find.
+
+   Before you report a bug, check it's not already addressed in *note
+Known Build Problems::, or perhaps *note Notes for Particular Systems::.
+You may also want to check <https://gmplib.org/> for patches for this
+release.
+
+   Please include the following in any report,
+
+   * The GMP version number, and if pre-packaged or patched then say so.
+
+   * A test program that makes it possible for us to reproduce the bug.
+     Include instructions on how to run the program.
+
+   * A description of what is wrong.  If the results are incorrect, in
+     what way.  If you get a crash, say so.
+
+   * If you get a crash, include a stack backtrace from the debugger if
+     it's informative ('where' in 'gdb', or '$C' in 'adb').
+
+   * Please do not send core dumps, executables or 'strace's.
+
+   * The 'configure' options you used when building GMP, if any.
+
+   * The output from 'configure', as printed to stdout, with any options
+     used.
+
+   * The name of the compiler and its version.  For 'gcc', get the
+     version with 'gcc -v', otherwise perhaps 'what `which cc`', or
+     similar.
+
+   * The output from running 'uname -a'.
+
+   * The output from running './config.guess', and from running
+     './configfsf.guess' (might be the same).
+
+   * If the bug is related to 'configure', then the compressed contents
+     of 'config.log'.
+
+   * If the bug is related to an 'asm' file not assembling, then the
+     contents of 'config.m4' and the offending line or lines from the
+     temporary 'mpn/tmp-<file>.s'.
+
+   Please make an effort to produce a self-contained report, with
+something definite that can be tested or debugged.  Vague queries or
+piecemeal messages are difficult to act on and don't help the
+development effort.
+
+   It is not uncommon that an observed problem is actually due to a bug
+in the compiler; the GMP code tends to explore interesting corners in
+compilers.
+
+   If your bug report is good, we will do our best to help you get a
+corrected version of the library; if the bug report is poor, we won't do
+anything about it (except maybe ask you to send a better report).
+
+   Send your report to: <gmp-bugs@gmplib.org>.
+
+   If you think something in this manual is unclear, or downright
+incorrect, or if the language needs to be improved, please send a note
+to the same address.
+
+
+File: gmp.info,  Node: Integer Functions,  Next: Rational Number Functions,  Prev: Reporting Bugs,  Up: Top
+
+5 Integer Functions
+*******************
+
+This chapter describes the GMP functions for performing integer
+arithmetic.  These functions start with the prefix 'mpz_'.
+
+   GMP integers are stored in objects of type 'mpz_t'.
+
+* Menu:
+
+* Initializing Integers::
+* Assigning Integers::
+* Simultaneous Integer Init & Assign::
+* Converting Integers::
+* Integer Arithmetic::
+* Integer Division::
+* Integer Exponentiation::
+* Integer Roots::
+* Number Theoretic Functions::
+* Integer Comparisons::
+* Integer Logic and Bit Fiddling::
+* I/O of Integers::
+* Integer Random Numbers::
+* Integer Import and Export::
+* Miscellaneous Integer Functions::
+* Integer Special Functions::
+
+
+File: gmp.info,  Node: Initializing Integers,  Next: Assigning Integers,  Prev: Integer Functions,  Up: Integer Functions
+
+5.1 Initialization Functions
+============================
+
+The functions for integer arithmetic assume that all integer objects are
+initialized.  You do that by calling the function 'mpz_init'.  For
+example,
+
+     {
+       mpz_t integ;
+       mpz_init (integ);
+       ...
+       mpz_add (integ, ...);
+       ...
+       mpz_sub (integ, ...);
+
+       /* Unless the program is about to exit, do ... */
+       mpz_clear (integ);
+     }
+
+   As you can see, you can store new values any number of times, once an
+object is initialized.
+
+ -- Function: void mpz_init (mpz_t X)
+     Initialize X, and set its value to 0.
+
+ -- Function: void mpz_inits (mpz_t X, ...)
+     Initialize a NULL-terminated list of 'mpz_t' variables, and set
+     their values to 0.
+
+ -- Function: void mpz_init2 (mpz_t X, mp_bitcnt_t N)
+     Initialize X, with space for N-bit numbers, and set its value to 0.
+     Calling this function instead of 'mpz_init' or 'mpz_inits' is never
+     necessary; reallocation is handled automatically by GMP when
+     needed.
+
+     While N defines the initial space, X will grow automatically in the
+     normal way, if necessary, for subsequent values stored.
+     'mpz_init2' makes it possible to avoid such reallocations if a
+     maximum size is known in advance.
+
+     In preparation for an operation, GMP often allocates one limb more
+     than ultimately needed.  To make sure GMP will not perform
+     reallocation for X, you need to add the number of bits in
+     'mp_limb_t' to N.
+
+ -- Function: void mpz_clear (mpz_t X)
+     Free the space occupied by X.  Call this function for all 'mpz_t'
+     variables when you are done with them.
+
+ -- Function: void mpz_clears (mpz_t X, ...)
+     Free the space occupied by a NULL-terminated list of 'mpz_t'
+     variables.
+
+ -- Function: void mpz_realloc2 (mpz_t X, mp_bitcnt_t N)
+     Change the space allocated for X to N bits.  The value in X is
+     preserved if it fits, or is set to 0 if not.
+
+     Calling this function is never necessary; reallocation is handled
+     automatically by GMP when needed.  But this function can be used to
+     increase the space for a variable in order to avoid repeated
+     automatic reallocations, or to decrease it to give memory back to
+     the heap.
+
+
+File: gmp.info,  Node: Assigning Integers,  Next: Simultaneous Integer Init & Assign,  Prev: Initializing Integers,  Up: Integer Functions
+
+5.2 Assignment Functions
+========================
+
+These functions assign new values to already initialized integers (*note
+Initializing Integers::).
+
+ -- Function: void mpz_set (mpz_t ROP, const mpz_t OP)
+ -- Function: void mpz_set_ui (mpz_t ROP, unsigned long int OP)
+ -- Function: void mpz_set_si (mpz_t ROP, signed long int OP)
+ -- Function: void mpz_set_d (mpz_t ROP, double OP)
+ -- Function: void mpz_set_q (mpz_t ROP, const mpq_t OP)
+ -- Function: void mpz_set_f (mpz_t ROP, const mpf_t OP)
+     Set the value of ROP from OP.
+
+     'mpz_set_d', 'mpz_set_q' and 'mpz_set_f' truncate OP to make it an
+     integer.
+
+ -- Function: int mpz_set_str (mpz_t ROP, const char *STR, int BASE)
+     Set the value of ROP from STR, a null-terminated C string in base
+     BASE.  White space is allowed in the string, and is simply ignored.
+
+     The BASE may vary from 2 to 62, or if BASE is 0, then the leading
+     characters are used: '0x' and '0X' for hexadecimal, '0b' and '0B'
+     for binary, '0' for octal, or decimal otherwise.
+
+     For bases up to 36, case is ignored; upper-case and lower-case
+     letters have the same value.  For bases 37 to 62, upper-case letter
+     represent the usual 10..35 while lower-case letter represent
+     36..61.
+
+     This function returns 0 if the entire string is a valid number in
+     base BASE.  Otherwise it returns -1.
+
+ -- Function: void mpz_swap (mpz_t ROP1, mpz_t ROP2)
+     Swap the values ROP1 and ROP2 efficiently.
+
+
+File: gmp.info,  Node: Simultaneous Integer Init & Assign,  Next: Converting Integers,  Prev: Assigning Integers,  Up: Integer Functions
+
+5.3 Combined Initialization and Assignment Functions
+====================================================
+
+For convenience, GMP provides a parallel series of initialize-and-set
+functions which initialize the output and then store the value there.
+These functions' names have the form 'mpz_init_set...'
+
+   Here is an example of using one:
+
+     {
+       mpz_t pie;
+       mpz_init_set_str (pie, "3141592653589793238462643383279502884", 10);
+       ...
+       mpz_sub (pie, ...);
+       ...
+       mpz_clear (pie);
+     }
+
+Once the integer has been initialized by any of the 'mpz_init_set...'
+functions, it can be used as the source or destination operand for the
+ordinary integer functions.  Don't use an initialize-and-set function on
+a variable already initialized!
+
+ -- Function: void mpz_init_set (mpz_t ROP, const mpz_t OP)
+ -- Function: void mpz_init_set_ui (mpz_t ROP, unsigned long int OP)
+ -- Function: void mpz_init_set_si (mpz_t ROP, signed long int OP)
+ -- Function: void mpz_init_set_d (mpz_t ROP, double OP)
+     Initialize ROP with limb space and set the initial numeric value
+     from OP.
+
+ -- Function: int mpz_init_set_str (mpz_t ROP, const char *STR, int
+          BASE)
+     Initialize ROP and set its value like 'mpz_set_str' (see its
+     documentation above for details).
+
+     If the string is a correct base BASE number, the function returns
+     0; if an error occurs it returns -1.  ROP is initialized even if an
+     error occurs.  (I.e., you have to call 'mpz_clear' for it.)
+
+
+File: gmp.info,  Node: Converting Integers,  Next: Integer Arithmetic,  Prev: Simultaneous Integer Init & Assign,  Up: Integer Functions
+
+5.4 Conversion Functions
+========================
+
+This section describes functions for converting GMP integers to standard
+C types.  Functions for converting _to_ GMP integers are described in
+*note Assigning Integers:: and *note I/O of Integers::.
+
+ -- Function: unsigned long int mpz_get_ui (const mpz_t OP)
+     Return the value of OP as an 'unsigned long'.
+
+     If OP is too big to fit an 'unsigned long' then just the least
+     significant bits that do fit are returned.  The sign of OP is
+     ignored, only the absolute value is used.
+
+ -- Function: signed long int mpz_get_si (const mpz_t OP)
+     If OP fits into a 'signed long int' return the value of OP.
+     Otherwise return the least significant part of OP, with the same
+     sign as OP.
+
+     If OP is too big to fit in a 'signed long int', the returned result
+     is probably not very useful.  To find out if the value will fit,
+     use the function 'mpz_fits_slong_p'.
+
+ -- Function: double mpz_get_d (const mpz_t OP)
+     Convert OP to a 'double', truncating if necessary (i.e. rounding
+     towards zero).
+
+     If the exponent from the conversion is too big, the result is
+     system dependent.  An infinity is returned where available.  A
+     hardware overflow trap may or may not occur.
+
+ -- Function: double mpz_get_d_2exp (signed long int *EXP, const mpz_t
+          OP)
+     Convert OP to a 'double', truncating if necessary (i.e. rounding
+     towards zero), and returning the exponent separately.
+
+     The return value is in the range 0.5<=abs(D)<1 and the exponent is
+     stored to '*EXP'.  D * 2^EXP is the (truncated) OP value.  If OP is
+     zero, the return is 0.0 and 0 is stored to '*EXP'.
+
+     This is similar to the standard C 'frexp' function (*note
+     (libc)Normalization Functions::).
+
+ -- Function: char * mpz_get_str (char *STR, int BASE, const mpz_t OP)
+     Convert OP to a string of digits in base BASE.  The base argument
+     may vary from 2 to 62 or from -2 to -36.
+
+     For BASE in the range 2..36, digits and lower-case letters are
+     used; for -2..-36, digits and upper-case letters are used; for
+     37..62, digits, upper-case letters, and lower-case letters (in that
+     significance order) are used.
+
+     If STR is 'NULL', the result string is allocated using the current
+     allocation function (*note Custom Allocation::).  The block will be
+     'strlen(str)+1' bytes, that being exactly enough for the string and
+     null-terminator.
+
+     If STR is not 'NULL', it should point to a block of storage large
+     enough for the result, that being 'mpz_sizeinbase (OP, BASE) + 2'.
+     The two extra bytes are for a possible minus sign, and the
+     null-terminator.
+
+     A pointer to the result string is returned, being either the
+     allocated block, or the given STR.
+
+
+File: gmp.info,  Node: Integer Arithmetic,  Next: Integer Division,  Prev: Converting Integers,  Up: Integer Functions
+
+5.5 Arithmetic Functions
+========================
+
+ -- Function: void mpz_add (mpz_t ROP, const mpz_t OP1, const mpz_t OP2)
+ -- Function: void mpz_add_ui (mpz_t ROP, const mpz_t OP1, unsigned long
+          int OP2)
+     Set ROP to OP1 + OP2.
+
+ -- Function: void mpz_sub (mpz_t ROP, const mpz_t OP1, const mpz_t OP2)
+ -- Function: void mpz_sub_ui (mpz_t ROP, const mpz_t OP1, unsigned long
+          int OP2)
+ -- Function: void mpz_ui_sub (mpz_t ROP, unsigned long int OP1, const
+          mpz_t OP2)
+     Set ROP to OP1 - OP2.
+
+ -- Function: void mpz_mul (mpz_t ROP, const mpz_t OP1, const mpz_t OP2)
+ -- Function: void mpz_mul_si (mpz_t ROP, const mpz_t OP1, long int OP2)
+ -- Function: void mpz_mul_ui (mpz_t ROP, const mpz_t OP1, unsigned long
+          int OP2)
+     Set ROP to OP1 times OP2.
+
+ -- Function: void mpz_addmul (mpz_t ROP, const mpz_t OP1, const mpz_t
+          OP2)
+ -- Function: void mpz_addmul_ui (mpz_t ROP, const mpz_t OP1, unsigned
+          long int OP2)
+     Set ROP to ROP + OP1 times OP2.
+
+ -- Function: void mpz_submul (mpz_t ROP, const mpz_t OP1, const mpz_t
+          OP2)
+ -- Function: void mpz_submul_ui (mpz_t ROP, const mpz_t OP1, unsigned
+          long int OP2)
+     Set ROP to ROP - OP1 times OP2.
+
+ -- Function: void mpz_mul_2exp (mpz_t ROP, const mpz_t OP1, mp_bitcnt_t
+          OP2)
+     Set ROP to OP1 times 2 raised to OP2.  This operation can also be
+     defined as a left shift by OP2 bits.
+
+ -- Function: void mpz_neg (mpz_t ROP, const mpz_t OP)
+     Set ROP to -OP.
+
+ -- Function: void mpz_abs (mpz_t ROP, const mpz_t OP)
+     Set ROP to the absolute value of OP.
+
+
+File: gmp.info,  Node: Integer Division,  Next: Integer Exponentiation,  Prev: Integer Arithmetic,  Up: Integer Functions
+
+5.6 Division Functions
+======================
+
+Division is undefined if the divisor is zero.  Passing a zero divisor to
+the division or modulo functions (including the modular powering
+functions 'mpz_powm' and 'mpz_powm_ui'), will cause an intentional
+division by zero.  This lets a program handle arithmetic exceptions in
+these functions the same way as for normal C 'int' arithmetic.
+
+ -- Function: void mpz_cdiv_q (mpz_t Q, const mpz_t N, const mpz_t D)
+ -- Function: void mpz_cdiv_r (mpz_t R, const mpz_t N, const mpz_t D)
+ -- Function: void mpz_cdiv_qr (mpz_t Q, mpz_t R, const mpz_t N, const
+          mpz_t D)
+
+ -- Function: unsigned long int mpz_cdiv_q_ui (mpz_t Q, const mpz_t N,
+          unsigned long int D)
+ -- Function: unsigned long int mpz_cdiv_r_ui (mpz_t R, const mpz_t N,
+          unsigned long int D)
+ -- Function: unsigned long int mpz_cdiv_qr_ui (mpz_t Q, mpz_t R,
+          const mpz_t N, unsigned long int D)
+ -- Function: unsigned long int mpz_cdiv_ui (const mpz_t N,
+          unsigned long int D)
+
+ -- Function: void mpz_cdiv_q_2exp (mpz_t Q, const mpz_t N,
+          mp_bitcnt_t B)
+ -- Function: void mpz_cdiv_r_2exp (mpz_t R, const mpz_t N,
+          mp_bitcnt_t B)
+
+ -- Function: void mpz_fdiv_q (mpz_t Q, const mpz_t N, const mpz_t D)
+ -- Function: void mpz_fdiv_r (mpz_t R, const mpz_t N, const mpz_t D)
+ -- Function: void mpz_fdiv_qr (mpz_t Q, mpz_t R, const mpz_t N, const
+          mpz_t D)
+
+ -- Function: unsigned long int mpz_fdiv_q_ui (mpz_t Q, const mpz_t N,
+          unsigned long int D)
+ -- Function: unsigned long int mpz_fdiv_r_ui (mpz_t R, const mpz_t N,
+          unsigned long int D)
+ -- Function: unsigned long int mpz_fdiv_qr_ui (mpz_t Q, mpz_t R,
+          const mpz_t N, unsigned long int D)
+ -- Function: unsigned long int mpz_fdiv_ui (const mpz_t N,
+          unsigned long int D)
+
+ -- Function: void mpz_fdiv_q_2exp (mpz_t Q, const mpz_t N,
+          mp_bitcnt_t B)
+ -- Function: void mpz_fdiv_r_2exp (mpz_t R, const mpz_t N,
+          mp_bitcnt_t B)
+
+ -- Function: void mpz_tdiv_q (mpz_t Q, const mpz_t N, const mpz_t D)
+ -- Function: void mpz_tdiv_r (mpz_t R, const mpz_t N, const mpz_t D)
+ -- Function: void mpz_tdiv_qr (mpz_t Q, mpz_t R, const mpz_t N, const
+          mpz_t D)
+
+ -- Function: unsigned long int mpz_tdiv_q_ui (mpz_t Q, const mpz_t N,
+          unsigned long int D)
+ -- Function: unsigned long int mpz_tdiv_r_ui (mpz_t R, const mpz_t N,
+          unsigned long int D)
+ -- Function: unsigned long int mpz_tdiv_qr_ui (mpz_t Q, mpz_t R,
+          const mpz_t N, unsigned long int D)
+ -- Function: unsigned long int mpz_tdiv_ui (const mpz_t N,
+          unsigned long int D)
+
+ -- Function: void mpz_tdiv_q_2exp (mpz_t Q, const mpz_t N,
+          mp_bitcnt_t B)
+ -- Function: void mpz_tdiv_r_2exp (mpz_t R, const mpz_t N,
+          mp_bitcnt_t B)
+
+
+     Divide N by D, forming a quotient Q and/or remainder R.  For the
+     '2exp' functions, D=2^B.  The rounding is in three styles, each
+     suiting different applications.
+
+        * 'cdiv' rounds Q up towards +infinity, and R will have the
+          opposite sign to D.  The 'c' stands for "ceil".
+
+        * 'fdiv' rounds Q down towards -infinity, and R will have the
+          same sign as D.  The 'f' stands for "floor".
+
+        * 'tdiv' rounds Q towards zero, and R will have the same sign as
+          N.  The 't' stands for "truncate".
+
+     In all cases Q and R will satisfy N=Q*D+R, and R will satisfy
+     0<=abs(R)<abs(D).
+
+     The 'q' functions calculate only the quotient, the 'r' functions
+     only the remainder, and the 'qr' functions calculate both.  Note
+     that for 'qr' the same variable cannot be passed for both Q and R,
+     or results will be unpredictable.
+
+     For the 'ui' variants the return value is the remainder, and in
+     fact returning the remainder is all the 'div_ui' functions do.  For
+     'tdiv' and 'cdiv' the remainder can be negative, so for those the
+     return value is the absolute value of the remainder.
+
+     For the '2exp' variants the divisor is 2^B.  These functions are
+     implemented as right shifts and bit masks, but of course they round
+     the same as the other functions.
+
+     For positive N both 'mpz_fdiv_q_2exp' and 'mpz_tdiv_q_2exp' are
+     simple bitwise right shifts.  For negative N, 'mpz_fdiv_q_2exp' is
+     effectively an arithmetic right shift treating N as twos complement
+     the same as the bitwise logical functions do, whereas
+     'mpz_tdiv_q_2exp' effectively treats N as sign and magnitude.
+
+ -- Function: void mpz_mod (mpz_t R, const mpz_t N, const mpz_t D)
+ -- Function: unsigned long int mpz_mod_ui (mpz_t R, const mpz_t N,
+          unsigned long int D)
+     Set R to N 'mod' D.  The sign of the divisor is ignored; the result
+     is always non-negative.
+
+     'mpz_mod_ui' is identical to 'mpz_fdiv_r_ui' above, returning the
+     remainder as well as setting R.  See 'mpz_fdiv_ui' above if only
+     the return value is wanted.
+
+ -- Function: void mpz_divexact (mpz_t Q, const mpz_t N, const mpz_t D)
+ -- Function: void mpz_divexact_ui (mpz_t Q, const mpz_t N, unsigned
+          long D)
+     Set Q to N/D.  These functions produce correct results only when it
+     is known in advance that D divides N.
+
+     These routines are much faster than the other division functions,
+     and are the best choice when exact division is known to occur, for
+     example reducing a rational to lowest terms.
+
+ -- Function: int mpz_divisible_p (const mpz_t N, const mpz_t D)
+ -- Function: int mpz_divisible_ui_p (const mpz_t N, unsigned long int
+          D)
+ -- Function: int mpz_divisible_2exp_p (const mpz_t N, mp_bitcnt_t B)
+     Return non-zero if N is exactly divisible by D, or in the case of
+     'mpz_divisible_2exp_p' by 2^B.
+
+     N is divisible by D if there exists an integer Q satisfying N =
+     Q*D.  Unlike the other division functions, D=0 is accepted and
+     following the rule it can be seen that only 0 is considered
+     divisible by 0.
+
+ -- Function: int mpz_congruent_p (const mpz_t N, const mpz_t C, const
+          mpz_t D)
+ -- Function: int mpz_congruent_ui_p (const mpz_t N, unsigned long int
+          C, unsigned long int D)
+ -- Function: int mpz_congruent_2exp_p (const mpz_t N, const mpz_t C,
+          mp_bitcnt_t B)
+     Return non-zero if N is congruent to C modulo D, or in the case of
+     'mpz_congruent_2exp_p' modulo 2^B.
+
+     N is congruent to C mod D if there exists an integer Q satisfying N
+     = C + Q*D.  Unlike the other division functions, D=0 is accepted
+     and following the rule it can be seen that N and C are considered
+     congruent mod 0 only when exactly equal.
+
+
+File: gmp.info,  Node: Integer Exponentiation,  Next: Integer Roots,  Prev: Integer Division,  Up: Integer Functions
+
+5.7 Exponentiation Functions
+============================
+
+ -- Function: void mpz_powm (mpz_t ROP, const mpz_t BASE, const mpz_t
+          EXP, const mpz_t MOD)
+ -- Function: void mpz_powm_ui (mpz_t ROP, const mpz_t BASE, unsigned
+          long int EXP, const mpz_t MOD)
+     Set ROP to (BASE raised to EXP) modulo MOD.
+
+     Negative EXP is supported if the inverse BASE^(-1) mod MOD exists
+     (see 'mpz_invert' in *note Number Theoretic Functions::).  If an
+     inverse doesn't exist then a divide by zero is raised.
+
+ -- Function: void mpz_powm_sec (mpz_t ROP, const mpz_t BASE, const
+          mpz_t EXP, const mpz_t MOD)
+     Set ROP to (BASE raised to EXP) modulo MOD.
+
+     It is required that EXP > 0 and that MOD is odd.
+
+     This function is designed to take the same time and have the same
+     cache access patterns for any two same-size arguments, assuming
+     that function arguments are placed at the same position and that
+     the machine state is identical upon function entry.  This function
+     is intended for cryptographic purposes, where resilience to
+     side-channel attacks is desired.
+
+ -- Function: void mpz_pow_ui (mpz_t ROP, const mpz_t BASE, unsigned
+          long int EXP)
+ -- Function: void mpz_ui_pow_ui (mpz_t ROP, unsigned long int BASE,
+          unsigned long int EXP)
+     Set ROP to BASE raised to EXP.  The case 0^0 yields 1.
+
+
+File: gmp.info,  Node: Integer Roots,  Next: Number Theoretic Functions,  Prev: Integer Exponentiation,  Up: Integer Functions
+
+5.8 Root Extraction Functions
+=============================
+
+ -- Function: int mpz_root (mpz_t ROP, const mpz_t OP, unsigned long int
+          N)
+     Set ROP to the truncated integer part of the Nth root of OP.
+     Return non-zero if the computation was exact, i.e., if OP is ROP to
+     the Nth power.
+
+ -- Function: void mpz_rootrem (mpz_t ROOT, mpz_t REM, const mpz_t U,
+          unsigned long int N)
+     Set ROOT to the truncated integer part of the Nth root of U.  Set
+     REM to the remainder, U-ROOT**N.
+
+ -- Function: void mpz_sqrt (mpz_t ROP, const mpz_t OP)
+     Set ROP to the truncated integer part of the square root of OP.
+
+ -- Function: void mpz_sqrtrem (mpz_t ROP1, mpz_t ROP2, const mpz_t OP)
+     Set ROP1 to the truncated integer part of the square root of OP,
+     like 'mpz_sqrt'.  Set ROP2 to the remainder OP-ROP1*ROP1, which
+     will be zero if OP is a perfect square.
+
+     If ROP1 and ROP2 are the same variable, the results are undefined.
+
+ -- Function: int mpz_perfect_power_p (const mpz_t OP)
+     Return non-zero if OP is a perfect power, i.e., if there exist
+     integers A and B, with B>1, such that OP equals A raised to the
+     power B.
+
+     Under this definition both 0 and 1 are considered to be perfect
+     powers.  Negative values of OP are accepted, but of course can only
+     be odd perfect powers.
+
+ -- Function: int mpz_perfect_square_p (const mpz_t OP)
+     Return non-zero if OP is a perfect square, i.e., if the square root
+     of OP is an integer.  Under this definition both 0 and 1 are
+     considered to be perfect squares.
+
+
+File: gmp.info,  Node: Number Theoretic Functions,  Next: Integer Comparisons,  Prev: Integer Roots,  Up: Integer Functions
+
+5.9 Number Theoretic Functions
+==============================
+
+ -- Function: int mpz_probab_prime_p (const mpz_t N, int REPS)
+     Determine whether N is prime.  Return 2 if N is definitely prime,
+     return 1 if N is probably prime (without being certain), or return
+     0 if N is definitely non-prime.
+
+     This function performs some trial divisions, a Baillie-PSW probable
+     prime test, then REPS-24 Miller-Rabin probabilistic primality
+     tests.  A higher REPS value will reduce the chances of a non-prime
+     being identified as "probably prime".  A composite number will be
+     identified as a prime with an asymptotic probability of less than
+     4^(-REPS).  Reasonable values of REPS are between 15 and 50.
+
+     GMP versions up to and including 6.1.2 did not use the Baillie-PSW
+     primality test.  In those older versions of GMP, this function
+     performed REPS Miller-Rabin tests.
+
+ -- Function: void mpz_nextprime (mpz_t ROP, const mpz_t OP)
+     Set ROP to the next prime greater than OP.
+
+     This function uses a probabilistic algorithm to identify primes.
+     For practical purposes it's adequate, the chance of a composite
+     passing will be extremely small.
+
+ -- Function: void mpz_gcd (mpz_t ROP, const mpz_t OP1, const mpz_t OP2)
+     Set ROP to the greatest common divisor of OP1 and OP2.  The result
+     is always positive even if one or both input operands are negative.
+     Except if both inputs are zero; then this function defines gcd(0,0)
+     = 0.
+
+ -- Function: unsigned long int mpz_gcd_ui (mpz_t ROP, const mpz_t OP1,
+          unsigned long int OP2)
+     Compute the greatest common divisor of OP1 and OP2.  If ROP is not
+     'NULL', store the result there.
+
+     If the result is small enough to fit in an 'unsigned long int', it
+     is returned.  If the result does not fit, 0 is returned, and the
+     result is equal to the argument OP1.  Note that the result will
+     always fit if OP2 is non-zero.
+
+ -- Function: void mpz_gcdext (mpz_t G, mpz_t S, mpz_t T, const mpz_t A,
+          const mpz_t B)
+     Set G to the greatest common divisor of A and B, and in addition
+     set S and T to coefficients satisfying A*S + B*T = G.  The value in
+     G is always positive, even if one or both of A and B are negative
+     (or zero if both inputs are zero).  The values in S and T are
+     chosen such that normally, abs(S) < abs(B) / (2 G) and abs(T) <
+     abs(A) / (2 G), and these relations define S and T uniquely.  There
+     are a few exceptional cases:
+
+     If abs(A) = abs(B), then S = 0, T = sgn(B).
+
+     Otherwise, S = sgn(A) if B = 0 or abs(B) = 2 G, and T = sgn(B) if A
+     = 0 or abs(A) = 2 G.
+
+     In all cases, S = 0 if and only if G = abs(B), i.e., if B divides A
+     or A = B = 0.
+
+     If T or G is 'NULL' then that value is not computed.
+
+ -- Function: void mpz_lcm (mpz_t ROP, const mpz_t OP1, const mpz_t OP2)
+ -- Function: void mpz_lcm_ui (mpz_t ROP, const mpz_t OP1, unsigned long
+          OP2)
+     Set ROP to the least common multiple of OP1 and OP2.  ROP is always
+     positive, irrespective of the signs of OP1 and OP2.  ROP will be
+     zero if either OP1 or OP2 is zero.
+
+ -- Function: int mpz_invert (mpz_t ROP, const mpz_t OP1, const mpz_t
+          OP2)
+     Compute the inverse of OP1 modulo OP2 and put the result in ROP.
+     If the inverse exists, the return value is non-zero and ROP will
+     satisfy 0 <= ROP < abs(OP2) (with ROP = 0 possible only when
+     abs(OP2) = 1, i.e., in the somewhat degenerate zero ring).  If an
+     inverse doesn't exist the return value is zero and ROP is
+     undefined.  The behaviour of this function is undefined when OP2 is
+     zero.
+
+ -- Function: int mpz_jacobi (const mpz_t A, const mpz_t B)
+     Calculate the Jacobi symbol (A/B).  This is defined only for B odd.
+
+ -- Function: int mpz_legendre (const mpz_t A, const mpz_t P)
+     Calculate the Legendre symbol (A/P).  This is defined only for P an
+     odd positive prime, and for such P it's identical to the Jacobi
+     symbol.
+
+ -- Function: int mpz_kronecker (const mpz_t A, const mpz_t B)
+ -- Function: int mpz_kronecker_si (const mpz_t A, long B)
+ -- Function: int mpz_kronecker_ui (const mpz_t A, unsigned long B)
+ -- Function: int mpz_si_kronecker (long A, const mpz_t B)
+ -- Function: int mpz_ui_kronecker (unsigned long A, const mpz_t B)
+     Calculate the Jacobi symbol (A/B) with the Kronecker extension
+     (a/2)=(2/a) when a odd, or (a/2)=0 when a even.
+
+     When B is odd the Jacobi symbol and Kronecker symbol are identical,
+     so 'mpz_kronecker_ui' etc can be used for mixed precision Jacobi
+     symbols too.
+
+     For more information see Henri Cohen section 1.4.2 (*note
+     References::), or any number theory textbook.  See also the example
+     program 'demos/qcn.c' which uses 'mpz_kronecker_ui'.
+
+ -- Function: mp_bitcnt_t mpz_remove (mpz_t ROP, const mpz_t OP, const
+          mpz_t F)
+     Remove all occurrences of the factor F from OP and store the result
+     in ROP.  The return value is how many such occurrences were
+     removed.
+
+ -- Function: void mpz_fac_ui (mpz_t ROP, unsigned long int N)
+ -- Function: void mpz_2fac_ui (mpz_t ROP, unsigned long int N)
+ -- Function: void mpz_mfac_uiui (mpz_t ROP, unsigned long int N,
+          unsigned long int M)
+     Set ROP to the factorial of N: 'mpz_fac_ui' computes the plain
+     factorial N!, 'mpz_2fac_ui' computes the double-factorial N!!, and
+     'mpz_mfac_uiui' the M-multi-factorial N!^(M).
+
+ -- Function: void mpz_primorial_ui (mpz_t ROP, unsigned long int N)
+     Set ROP to the primorial of N, i.e.  the product of all positive
+     prime numbers <=N.
+
+ -- Function: void mpz_bin_ui (mpz_t ROP, const mpz_t N, unsigned long
+          int K)
+ -- Function: void mpz_bin_uiui (mpz_t ROP, unsigned long int N,
+          unsigned long int K)
+     Compute the binomial coefficient N over K and store the result in
+     ROP.  Negative values of N are supported by 'mpz_bin_ui', using the
+     identity bin(-n,k) = (-1)^k * bin(n+k-1,k), see Knuth volume 1
+     section 1.2.6 part G.
+
+ -- Function: void mpz_fib_ui (mpz_t FN, unsigned long int N)
+ -- Function: void mpz_fib2_ui (mpz_t FN, mpz_t FNSUB1, unsigned long
+          int N)
+     'mpz_fib_ui' sets FN to to F[n], the N'th Fibonacci number.
+     'mpz_fib2_ui' sets FN to F[n], and FNSUB1 to F[n-1].
+
+     These functions are designed for calculating isolated Fibonacci
+     numbers.  When a sequence of values is wanted it's best to start
+     with 'mpz_fib2_ui' and iterate the defining F[n+1]=F[n]+F[n-1] or
+     similar.
+
+ -- Function: void mpz_lucnum_ui (mpz_t LN, unsigned long int N)
+ -- Function: void mpz_lucnum2_ui (mpz_t LN, mpz_t LNSUB1, unsigned long
+          int N)
+     'mpz_lucnum_ui' sets LN to to L[n], the N'th Lucas number.
+     'mpz_lucnum2_ui' sets LN to L[n], and LNSUB1 to L[n-1].
+
+     These functions are designed for calculating isolated Lucas
+     numbers.  When a sequence of values is wanted it's best to start
+     with 'mpz_lucnum2_ui' and iterate the defining L[n+1]=L[n]+L[n-1]
+     or similar.
+
+     The Fibonacci numbers and Lucas numbers are related sequences, so
+     it's never necessary to call both 'mpz_fib2_ui' and
+     'mpz_lucnum2_ui'.  The formulas for going from Fibonacci to Lucas
+     can be found in *note Lucas Numbers Algorithm::, the reverse is
+     straightforward too.
+
+
+File: gmp.info,  Node: Integer Comparisons,  Next: Integer Logic and Bit Fiddling,  Prev: Number Theoretic Functions,  Up: Integer Functions
+
+5.10 Comparison Functions
+=========================
+
+ -- Function: int mpz_cmp (const mpz_t OP1, const mpz_t OP2)
+ -- Function: int mpz_cmp_d (const mpz_t OP1, double OP2)
+ -- Macro: int mpz_cmp_si (const mpz_t OP1, signed long int OP2)
+ -- Macro: int mpz_cmp_ui (const mpz_t OP1, unsigned long int OP2)
+     Compare OP1 and OP2.  Return a positive value if OP1 > OP2, zero if
+     OP1 = OP2, or a negative value if OP1 < OP2.
+
+     'mpz_cmp_ui' and 'mpz_cmp_si' are macros and will evaluate their
+     arguments more than once.  'mpz_cmp_d' can be called with an
+     infinity, but results are undefined for a NaN.
+
+ -- Function: int mpz_cmpabs (const mpz_t OP1, const mpz_t OP2)
+ -- Function: int mpz_cmpabs_d (const mpz_t OP1, double OP2)
+ -- Function: int mpz_cmpabs_ui (const mpz_t OP1, unsigned long int OP2)
+     Compare the absolute values of OP1 and OP2.  Return a positive
+     value if abs(OP1) > abs(OP2), zero if abs(OP1) = abs(OP2), or a
+     negative value if abs(OP1) < abs(OP2).
+
+     'mpz_cmpabs_d' can be called with an infinity, but results are
+     undefined for a NaN.
+
+ -- Macro: int mpz_sgn (const mpz_t OP)
+     Return +1 if OP > 0, 0 if OP = 0, and -1 if OP < 0.
+
+     This function is actually implemented as a macro.  It evaluates its
+     argument multiple times.
+
+
+File: gmp.info,  Node: Integer Logic and Bit Fiddling,  Next: I/O of Integers,  Prev: Integer Comparisons,  Up: Integer Functions
+
+5.11 Logical and Bit Manipulation Functions
+===========================================
+
+These functions behave as if twos complement arithmetic were used
+(although sign-magnitude is the actual implementation).  The least
+significant bit is number 0.
+
+ -- Function: void mpz_and (mpz_t ROP, const mpz_t OP1, const mpz_t OP2)
+     Set ROP to OP1 bitwise-and OP2.
+
+ -- Function: void mpz_ior (mpz_t ROP, const mpz_t OP1, const mpz_t OP2)
+     Set ROP to OP1 bitwise inclusive-or OP2.
+
+ -- Function: void mpz_xor (mpz_t ROP, const mpz_t OP1, const mpz_t OP2)
+     Set ROP to OP1 bitwise exclusive-or OP2.
+
+ -- Function: void mpz_com (mpz_t ROP, const mpz_t OP)
+     Set ROP to the one's complement of OP.
+
+ -- Function: mp_bitcnt_t mpz_popcount (const mpz_t OP)
+     If OP>=0, return the population count of OP, which is the number of
+     1 bits in the binary representation.  If OP<0, the number of 1s is
+     infinite, and the return value is the largest possible
+     'mp_bitcnt_t'.
+
+ -- Function: mp_bitcnt_t mpz_hamdist (const mpz_t OP1, const mpz_t OP2)
+     If OP1 and OP2 are both >=0 or both <0, return the hamming distance
+     between the two operands, which is the number of bit positions
+     where OP1 and OP2 have different bit values.  If one operand is >=0
+     and the other <0 then the number of bits different is infinite, and
+     the return value is the largest possible 'mp_bitcnt_t'.
+
+ -- Function: mp_bitcnt_t mpz_scan0 (const mpz_t OP, mp_bitcnt_t
+          STARTING_BIT)
+ -- Function: mp_bitcnt_t mpz_scan1 (const mpz_t OP, mp_bitcnt_t
+          STARTING_BIT)
+     Scan OP, starting from bit STARTING_BIT, towards more significant
+     bits, until the first 0 or 1 bit (respectively) is found.  Return
+     the index of the found bit.
+
+     If the bit at STARTING_BIT is already what's sought, then
+     STARTING_BIT is returned.
+
+     If there's no bit found, then the largest possible 'mp_bitcnt_t' is
+     returned.  This will happen in 'mpz_scan0' past the end of a
+     negative number, or 'mpz_scan1' past the end of a nonnegative
+     number.
+
+ -- Function: void mpz_setbit (mpz_t ROP, mp_bitcnt_t BIT_INDEX)
+     Set bit BIT_INDEX in ROP.
+
+ -- Function: void mpz_clrbit (mpz_t ROP, mp_bitcnt_t BIT_INDEX)
+     Clear bit BIT_INDEX in ROP.
+
+ -- Function: void mpz_combit (mpz_t ROP, mp_bitcnt_t BIT_INDEX)
+     Complement bit BIT_INDEX in ROP.
+
+ -- Function: int mpz_tstbit (const mpz_t OP, mp_bitcnt_t BIT_INDEX)
+     Test bit BIT_INDEX in OP and return 0 or 1 accordingly.
+
+
+File: gmp.info,  Node: I/O of Integers,  Next: Integer Random Numbers,  Prev: Integer Logic and Bit Fiddling,  Up: Integer Functions
+
+5.12 Input and Output Functions
+===============================
+
+Functions that perform input from a stdio stream, and functions that
+output to a stdio stream, of 'mpz' numbers.  Passing a 'NULL' pointer
+for a STREAM argument to any of these functions will make them read from
+'stdin' and write to 'stdout', respectively.
+
+   When using any of these functions, it is a good idea to include
+'stdio.h' before 'gmp.h', since that will allow 'gmp.h' to define
+prototypes for these functions.
+
+   See also *note Formatted Output:: and *note Formatted Input::.
+
+ -- Function: size_t mpz_out_str (FILE *STREAM, int BASE, const mpz_t
+          OP)
+     Output OP on stdio stream STREAM, as a string of digits in base
+     BASE.  The base argument may vary from 2 to 62 or from -2 to -36.
+
+     For BASE in the range 2..36, digits and lower-case letters are
+     used; for -2..-36, digits and upper-case letters are used; for
+     37..62, digits, upper-case letters, and lower-case letters (in that
+     significance order) are used.
+
+     Return the number of bytes written, or if an error occurred, return
+     0.
+
+ -- Function: size_t mpz_inp_str (mpz_t ROP, FILE *STREAM, int BASE)
+     Input a possibly white-space preceded string in base BASE from
+     stdio stream STREAM, and put the read integer in ROP.
+
+     The BASE may vary from 2 to 62, or if BASE is 0, then the leading
+     characters are used: '0x' and '0X' for hexadecimal, '0b' and '0B'
+     for binary, '0' for octal, or decimal otherwise.
+
+     For bases up to 36, case is ignored; upper-case and lower-case
+     letters have the same value.  For bases 37 to 62, upper-case letter
+     represent the usual 10..35 while lower-case letter represent
+     36..61.
+
+     Return the number of bytes read, or if an error occurred, return 0.
+
+ -- Function: size_t mpz_out_raw (FILE *STREAM, const mpz_t OP)
+     Output OP on stdio stream STREAM, in raw binary format.  The
+     integer is written in a portable format, with 4 bytes of size
+     information, and that many bytes of limbs.  Both the size and the
+     limbs are written in decreasing significance order (i.e., in
+     big-endian).
+
+     The output can be read with 'mpz_inp_raw'.
+
+     Return the number of bytes written, or if an error occurred, return
+     0.
+
+     The output of this can not be read by 'mpz_inp_raw' from GMP 1,
+     because of changes necessary for compatibility between 32-bit and
+     64-bit machines.
+
+ -- Function: size_t mpz_inp_raw (mpz_t ROP, FILE *STREAM)
+     Input from stdio stream STREAM in the format written by
+     'mpz_out_raw', and put the result in ROP.  Return the number of
+     bytes read, or if an error occurred, return 0.
+
+     This routine can read the output from 'mpz_out_raw' also from GMP
+     1, in spite of changes necessary for compatibility between 32-bit
+     and 64-bit machines.
+
+
+File: gmp.info,  Node: Integer Random Numbers,  Next: Integer Import and Export,  Prev: I/O of Integers,  Up: Integer Functions
+
+5.13 Random Number Functions
+============================
+
+The random number functions of GMP come in two groups; older function
+that rely on a global state, and newer functions that accept a state
+parameter that is read and modified.  Please see the *note Random Number
+Functions:: for more information on how to use and not to use random
+number functions.
+
+ -- Function: void mpz_urandomb (mpz_t ROP, gmp_randstate_t STATE,
+          mp_bitcnt_t N)
+     Generate a uniformly distributed random integer in the range 0 to
+     2^N-1, inclusive.
+
+     The variable STATE must be initialized by calling one of the
+     'gmp_randinit' functions (*note Random State Initialization::)
+     before invoking this function.
+
+ -- Function: void mpz_urandomm (mpz_t ROP, gmp_randstate_t STATE, const
+          mpz_t N)
+     Generate a uniform random integer in the range 0 to N-1, inclusive.
+
+     The variable STATE must be initialized by calling one of the
+     'gmp_randinit' functions (*note Random State Initialization::)
+     before invoking this function.
+
+ -- Function: void mpz_rrandomb (mpz_t ROP, gmp_randstate_t STATE,
+          mp_bitcnt_t N)
+     Generate a random integer with long strings of zeros and ones in
+     the binary representation.  Useful for testing functions and
+     algorithms, since this kind of random numbers have proven to be
+     more likely to trigger corner-case bugs.  The random number will be
+     in the range 2^(N-1) to 2^N-1, inclusive.
+
+     The variable STATE must be initialized by calling one of the
+     'gmp_randinit' functions (*note Random State Initialization::)
+     before invoking this function.
+
+ -- Function: void mpz_random (mpz_t ROP, mp_size_t MAX_SIZE)
+     Generate a random integer of at most MAX_SIZE limbs.  The generated
+     random number doesn't satisfy any particular requirements of
+     randomness.  Negative random numbers are generated when MAX_SIZE is
+     negative.
+
+     This function is obsolete.  Use 'mpz_urandomb' or 'mpz_urandomm'
+     instead.
+
+ -- Function: void mpz_random2 (mpz_t ROP, mp_size_t MAX_SIZE)
+     Generate a random integer of at most MAX_SIZE limbs, with long
+     strings of zeros and ones in the binary representation.  Useful for
+     testing functions and algorithms, since this kind of random numbers
+     have proven to be more likely to trigger corner-case bugs.
+     Negative random numbers are generated when MAX_SIZE is negative.
+
+     This function is obsolete.  Use 'mpz_rrandomb' instead.
+
+
+File: gmp.info,  Node: Integer Import and Export,  Next: Miscellaneous Integer Functions,  Prev: Integer Random Numbers,  Up: Integer Functions
+
+5.14 Integer Import and Export
+==============================
+
+'mpz_t' variables can be converted to and from arbitrary words of binary
+data with the following functions.
+
+ -- Function: void mpz_import (mpz_t ROP, size_t COUNT, int ORDER,
+          size_t SIZE, int ENDIAN, size_t NAILS, const void *OP)
+     Set ROP from an array of word data at OP.
+
+     The parameters specify the format of the data.  COUNT many words
+     are read, each SIZE bytes.  ORDER can be 1 for most significant
+     word first or -1 for least significant first.  Within each word
+     ENDIAN can be 1 for most significant byte first, -1 for least
+     significant first, or 0 for the native endianness of the host CPU.
+     The most significant NAILS bits of each word are skipped, this can
+     be 0 to use the full words.
+
+     There is no sign taken from the data, ROP will simply be a positive
+     integer.  An application can handle any sign itself, and apply it
+     for instance with 'mpz_neg'.
+
+     There are no data alignment restrictions on OP, any address is
+     allowed.
+
+     Here's an example converting an array of 'unsigned long' data, most
+     significant element first, and host byte order within each value.
+
+          unsigned long  a[20];
+          /* Initialize Z and A */
+          mpz_import (z, 20, 1, sizeof(a[0]), 0, 0, a);
+
+     This example assumes the full 'sizeof' bytes are used for data in
+     the given type, which is usually true, and certainly true for
+     'unsigned long' everywhere we know of.  However on Cray vector
+     systems it may be noted that 'short' and 'int' are always stored in
+     8 bytes (and with 'sizeof' indicating that) but use only 32 or 46
+     bits.  The NAILS feature can account for this, by passing for
+     instance '8*sizeof(int)-INT_BIT'.
+
+ -- Function: void * mpz_export (void *ROP, size_t *COUNTP, int ORDER,
+          size_t SIZE, int ENDIAN, size_t NAILS, const mpz_t OP)
+     Fill ROP with word data from OP.
+
+     The parameters specify the format of the data produced.  Each word
+     will be SIZE bytes and ORDER can be 1 for most significant word
+     first or -1 for least significant first.  Within each word ENDIAN
+     can be 1 for most significant byte first, -1 for least significant
+     first, or 0 for the native endianness of the host CPU.  The most
+     significant NAILS bits of each word are unused and set to zero,
+     this can be 0 to produce full words.
+
+     The number of words produced is written to '*COUNTP', or COUNTP can
+     be 'NULL' to discard the count.  ROP must have enough space for the
+     data, or if ROP is 'NULL' then a result array of the necessary size
+     is allocated using the current GMP allocation function (*note
+     Custom Allocation::).  In either case the return value is the
+     destination used, either ROP or the allocated block.
+
+     If OP is non-zero then the most significant word produced will be
+     non-zero.  If OP is zero then the count returned will be zero and
+     nothing written to ROP.  If ROP is 'NULL' in this case, no block is
+     allocated, just 'NULL' is returned.
+
+     The sign of OP is ignored, just the absolute value is exported.  An
+     application can use 'mpz_sgn' to get the sign and handle it as
+     desired.  (*note Integer Comparisons::)
+
+     There are no data alignment restrictions on ROP, any address is
+     allowed.
+
+     When an application is allocating space itself the required size
+     can be determined with a calculation like the following.  Since
+     'mpz_sizeinbase' always returns at least 1, 'count' here will be at
+     least one, which avoids any portability problems with 'malloc(0)',
+     though if 'z' is zero no space at all is actually needed (or
+     written).
+
+          numb = 8*size - nail;
+          count = (mpz_sizeinbase (z, 2) + numb-1) / numb;
+          p = malloc (count * size);
+
+
+File: gmp.info,  Node: Miscellaneous Integer Functions,  Next: Integer Special Functions,  Prev: Integer Import and Export,  Up: Integer Functions
+
+5.15 Miscellaneous Functions
+============================
+
+ -- Function: int mpz_fits_ulong_p (const mpz_t OP)
+ -- Function: int mpz_fits_slong_p (const mpz_t OP)
+ -- Function: int mpz_fits_uint_p (const mpz_t OP)
+ -- Function: int mpz_fits_sint_p (const mpz_t OP)
+ -- Function: int mpz_fits_ushort_p (const mpz_t OP)
+ -- Function: int mpz_fits_sshort_p (const mpz_t OP)
+     Return non-zero iff the value of OP fits in an 'unsigned long int',
+     'signed long int', 'unsigned int', 'signed int', 'unsigned short
+     int', or 'signed short int', respectively.  Otherwise, return zero.
+
+ -- Macro: int mpz_odd_p (const mpz_t OP)
+ -- Macro: int mpz_even_p (const mpz_t OP)
+     Determine whether OP is odd or even, respectively.  Return non-zero
+     if yes, zero if no.  These macros evaluate their argument more than
+     once.
+
+ -- Function: size_t mpz_sizeinbase (const mpz_t OP, int BASE)
+     Return the size of OP measured in number of digits in the given
+     BASE.  BASE can vary from 2 to 62.  The sign of OP is ignored, just
+     the absolute value is used.  The result will be either exact or 1
+     too big.  If BASE is a power of 2, the result is always exact.  If
+     OP is zero the return value is always 1.
+
+     This function can be used to determine the space required when
+     converting OP to a string.  The right amount of allocation is
+     normally two more than the value returned by 'mpz_sizeinbase', one
+     extra for a minus sign and one for the null-terminator.
+
+     It will be noted that 'mpz_sizeinbase(OP,2)' can be used to locate
+     the most significant 1 bit in OP, counting from 1.  (Unlike the
+     bitwise functions which start from 0, *Note Logical and Bit
+     Manipulation Functions: Integer Logic and Bit Fiddling.)
+
+
+File: gmp.info,  Node: Integer Special Functions,  Prev: Miscellaneous Integer Functions,  Up: Integer Functions
+
+5.16 Special Functions
+======================
+
+The functions in this section are for various special purposes.  Most
+applications will not need them.
+
+ -- Function: void mpz_array_init (mpz_t INTEGER_ARRAY, mp_size_t
+          ARRAY_SIZE, mp_size_t FIXED_NUM_BITS)
+     *This is an obsolete function.  Do not use it.*
+
+ -- Function: void * _mpz_realloc (mpz_t INTEGER, mp_size_t NEW_ALLOC)
+     Change the space for INTEGER to NEW_ALLOC limbs.  The value in
+     INTEGER is preserved if it fits, or is set to 0 if not.  The return
+     value is not useful to applications and should be ignored.
+
+     'mpz_realloc2' is the preferred way to accomplish allocation
+     changes like this.  'mpz_realloc2' and '_mpz_realloc' are the same
+     except that '_mpz_realloc' takes its size in limbs.
+
+ -- Function: mp_limb_t mpz_getlimbn (const mpz_t OP, mp_size_t N)
+     Return limb number N from OP.  The sign of OP is ignored, just the
+     absolute value is used.  The least significant limb is number 0.
+
+     'mpz_size' can be used to find how many limbs make up OP.
+     'mpz_getlimbn' returns zero if N is outside the range 0 to
+     'mpz_size(OP)-1'.
+
+ -- Function: size_t mpz_size (const mpz_t OP)
+     Return the size of OP measured in number of limbs.  If OP is zero,
+     the returned value will be zero.
+
+ -- Function: const mp_limb_t * mpz_limbs_read (const mpz_t X)
+     Return a pointer to the limb array representing the absolute value
+     of X.  The size of the array is 'mpz_size(X)'.  Intended for read
+     access only.
+
+ -- Function: mp_limb_t * mpz_limbs_write (mpz_t X, mp_size_t N)
+ -- Function: mp_limb_t * mpz_limbs_modify (mpz_t X, mp_size_t N)
+     Return a pointer to the limb array, intended for write access.  The
+     array is reallocated as needed, to make room for N limbs.  Requires
+     N > 0.  The 'mpz_limbs_modify' function returns an array that holds
+     the old absolute value of X, while 'mpz_limbs_write' may destroy
+     the old value and return an array with unspecified contents.
+
+ -- Function: void mpz_limbs_finish (mpz_t X, mp_size_t S)
+     Updates the internal size field of X.  Used after writing to the
+     limb array pointer returned by 'mpz_limbs_write' or
+     'mpz_limbs_modify' is completed.  The array should contain abs(S)
+     valid limbs, representing the new absolute value for X, and the
+     sign of X is taken from the sign of S.  This function never
+     reallocates X, so the limb pointer remains valid.
+
+     void foo (mpz_t x)
+     {
+       mp_size_t n, i;
+       mp_limb_t *xp;
+
+       n = mpz_size (x);
+       xp = mpz_limbs_modify (x, 2*n);
+       for (i = 0; i < n; i++)
+         xp[n+i] = xp[n-1-i];
+       mpz_limbs_finish (x, mpz_sgn (x) < 0 ? - 2*n : 2*n);
+     }
+
+ -- Function: mpz_srcptr mpz_roinit_n (mpz_t X, const mp_limb_t *XP,
+          mp_size_t XS)
+     Special initialization of X, using the given limb array and size.
+     X should be treated as read-only: it can be passed safely as input
+     to any mpz function, but not as an output.  The array XP must point
+     to at least a readable limb, its size is abs(XS), and the sign of X
+     is the sign of XS.  For convenience, the function returns X, but
+     cast to a const pointer type.
+
+     void foo (mpz_t x)
+     {
+       static const mp_limb_t y[3] = { 0x1, 0x2, 0x3 };
+       mpz_t tmp;
+       mpz_add (x, x, mpz_roinit_n (tmp, y, 3));
+     }
+
+ -- Macro: mpz_t MPZ_ROINIT_N (mp_limb_t *XP, mp_size_t XS)
+     This macro expands to an initializer which can be assigned to an
+     mpz_t variable.  The limb array XP must point to at least a
+     readable limb, moreover, unlike the 'mpz_roinit_n' function, the
+     array must be normalized: if XS is non-zero, then 'XP[abs(XS)-1]'
+     must be non-zero.  Intended primarily for constant values.  Using
+     it for non-constant values requires a C compiler supporting C99.
+
+     void foo (mpz_t x)
+     {
+       static const mp_limb_t ya[3] = { 0x1, 0x2, 0x3 };
+       static const mpz_t y = MPZ_ROINIT_N ((mp_limb_t *) ya, 3);
+
+       mpz_add (x, x, y);
+     }
+
+
+File: gmp.info,  Node: Rational Number Functions,  Next: Floating-point Functions,  Prev: Integer Functions,  Up: Top
+
+6 Rational Number Functions
+***************************
+
+This chapter describes the GMP functions for performing arithmetic on
+rational numbers.  These functions start with the prefix 'mpq_'.
+
+   Rational numbers are stored in objects of type 'mpq_t'.
+
+   All rational arithmetic functions assume operands have a canonical
+form, and canonicalize their result.  The canonical form means that the
+denominator and the numerator have no common factors, and that the
+denominator is positive.  Zero has the unique representation 0/1.
+
+   Pure assignment functions do not canonicalize the assigned variable.
+It is the responsibility of the user to canonicalize the assigned
+variable before any arithmetic operations are performed on that
+variable.
+
+ -- Function: void mpq_canonicalize (mpq_t OP)
+     Remove any factors that are common to the numerator and denominator
+     of OP, and make the denominator positive.
+
+* Menu:
+
+* Initializing Rationals::
+* Rational Conversions::
+* Rational Arithmetic::
+* Comparing Rationals::
+* Applying Integer Functions::
+* I/O of Rationals::
+
+
+File: gmp.info,  Node: Initializing Rationals,  Next: Rational Conversions,  Prev: Rational Number Functions,  Up: Rational Number Functions
+
+6.1 Initialization and Assignment Functions
+===========================================
+
+ -- Function: void mpq_init (mpq_t X)
+     Initialize X and set it to 0/1.  Each variable should normally only
+     be initialized once, or at least cleared out (using the function
+     'mpq_clear') between each initialization.
+
+ -- Function: void mpq_inits (mpq_t X, ...)
+     Initialize a NULL-terminated list of 'mpq_t' variables, and set
+     their values to 0/1.
+
+ -- Function: void mpq_clear (mpq_t X)
+     Free the space occupied by X.  Make sure to call this function for
+     all 'mpq_t' variables when you are done with them.
+
+ -- Function: void mpq_clears (mpq_t X, ...)
+     Free the space occupied by a NULL-terminated list of 'mpq_t'
+     variables.
+
+ -- Function: void mpq_set (mpq_t ROP, const mpq_t OP)
+ -- Function: void mpq_set_z (mpq_t ROP, const mpz_t OP)
+     Assign ROP from OP.
+
+ -- Function: void mpq_set_ui (mpq_t ROP, unsigned long int OP1,
+          unsigned long int OP2)
+ -- Function: void mpq_set_si (mpq_t ROP, signed long int OP1, unsigned
+          long int OP2)
+     Set the value of ROP to OP1/OP2.  Note that if OP1 and OP2 have
+     common factors, ROP has to be passed to 'mpq_canonicalize' before
+     any operations are performed on ROP.
+
+ -- Function: int mpq_set_str (mpq_t ROP, const char *STR, int BASE)
+     Set ROP from a null-terminated string STR in the given BASE.
+
+     The string can be an integer like "41" or a fraction like "41/152".
+     The fraction must be in canonical form (*note Rational Number
+     Functions::), or if not then 'mpq_canonicalize' must be called.
+
+     The numerator and optional denominator are parsed the same as in
+     'mpz_set_str' (*note Assigning Integers::).  White space is allowed
+     in the string, and is simply ignored.  The BASE can vary from 2 to
+     62, or if BASE is 0 then the leading characters are used: '0x' or
+     '0X' for hex, '0b' or '0B' for binary, '0' for octal, or decimal
+     otherwise.  Note that this is done separately for the numerator and
+     denominator, so for instance '0xEF/100' is 239/100, whereas
+     '0xEF/0x100' is 239/256.
+
+     The return value is 0 if the entire string is a valid number, or -1
+     if not.
+
+ -- Function: void mpq_swap (mpq_t ROP1, mpq_t ROP2)
+     Swap the values ROP1 and ROP2 efficiently.
+
+
+File: gmp.info,  Node: Rational Conversions,  Next: Rational Arithmetic,  Prev: Initializing Rationals,  Up: Rational Number Functions
+
+6.2 Conversion Functions
+========================
+
+ -- Function: double mpq_get_d (const mpq_t OP)
+     Convert OP to a 'double', truncating if necessary (i.e. rounding
+     towards zero).
+
+     If the exponent from the conversion is too big or too small to fit
+     a 'double' then the result is system dependent.  For too big an
+     infinity is returned when available.  For too small 0.0 is normally
+     returned.  Hardware overflow, underflow and denorm traps may or may
+     not occur.
+
+ -- Function: void mpq_set_d (mpq_t ROP, double OP)
+ -- Function: void mpq_set_f (mpq_t ROP, const mpf_t OP)
+     Set ROP to the value of OP.  There is no rounding, this conversion
+     is exact.
+
+ -- Function: char * mpq_get_str (char *STR, int BASE, const mpq_t OP)
+     Convert OP to a string of digits in base BASE.  The base argument
+     may vary from 2 to 62 or from -2 to -36.  The string will be of the
+     form 'num/den', or if the denominator is 1 then just 'num'.
+
+     For BASE in the range 2..36, digits and lower-case letters are
+     used; for -2..-36, digits and upper-case letters are used; for
+     37..62, digits, upper-case letters, and lower-case letters (in that
+     significance order) are used.
+
+     If STR is 'NULL', the result string is allocated using the current
+     allocation function (*note Custom Allocation::).  The block will be
+     'strlen(str)+1' bytes, that being exactly enough for the string and
+     null-terminator.
+
+     If STR is not 'NULL', it should point to a block of storage large
+     enough for the result, that being
+
+          mpz_sizeinbase (mpq_numref(OP), BASE)
+          + mpz_sizeinbase (mpq_denref(OP), BASE) + 3
+
+     The three extra bytes are for a possible minus sign, possible
+     slash, and the null-terminator.
+
+     A pointer to the result string is returned, being either the
+     allocated block, or the given STR.
+
+
+File: gmp.info,  Node: Rational Arithmetic,  Next: Comparing Rationals,  Prev: Rational Conversions,  Up: Rational Number Functions
+
+6.3 Arithmetic Functions
+========================
+
+ -- Function: void mpq_add (mpq_t SUM, const mpq_t ADDEND1, const mpq_t
+          ADDEND2)
+     Set SUM to ADDEND1 + ADDEND2.
+
+ -- Function: void mpq_sub (mpq_t DIFFERENCE, const mpq_t MINUEND, const
+          mpq_t SUBTRAHEND)
+     Set DIFFERENCE to MINUEND - SUBTRAHEND.
+
+ -- Function: void mpq_mul (mpq_t PRODUCT, const mpq_t MULTIPLIER, const
+          mpq_t MULTIPLICAND)
+     Set PRODUCT to MULTIPLIER times MULTIPLICAND.
+
+ -- Function: void mpq_mul_2exp (mpq_t ROP, const mpq_t OP1, mp_bitcnt_t
+          OP2)
+     Set ROP to OP1 times 2 raised to OP2.
+
+ -- Function: void mpq_div (mpq_t QUOTIENT, const mpq_t DIVIDEND, const
+          mpq_t DIVISOR)
+     Set QUOTIENT to DIVIDEND/DIVISOR.
+
+ -- Function: void mpq_div_2exp (mpq_t ROP, const mpq_t OP1, mp_bitcnt_t
+          OP2)
+     Set ROP to OP1 divided by 2 raised to OP2.
+
+ -- Function: void mpq_neg (mpq_t NEGATED_OPERAND, const mpq_t OPERAND)
+     Set NEGATED_OPERAND to -OPERAND.
+
+ -- Function: void mpq_abs (mpq_t ROP, const mpq_t OP)
+     Set ROP to the absolute value of OP.
+
+ -- Function: void mpq_inv (mpq_t INVERTED_NUMBER, const mpq_t NUMBER)
+     Set INVERTED_NUMBER to 1/NUMBER.  If the new denominator is zero,
+     this routine will divide by zero.
+
+
+File: gmp.info,  Node: Comparing Rationals,  Next: Applying Integer Functions,  Prev: Rational Arithmetic,  Up: Rational Number Functions
+
+6.4 Comparison Functions
+========================
+
+ -- Function: int mpq_cmp (const mpq_t OP1, const mpq_t OP2)
+ -- Function: int mpq_cmp_z (const mpq_t OP1, const mpz_t OP2)
+     Compare OP1 and OP2.  Return a positive value if OP1 > OP2, zero if
+     OP1 = OP2, and a negative value if OP1 < OP2.
+
+     To determine if two rationals are equal, 'mpq_equal' is faster than
+     'mpq_cmp'.
+
+ -- Macro: int mpq_cmp_ui (const mpq_t OP1, unsigned long int NUM2,
+          unsigned long int DEN2)
+ -- Macro: int mpq_cmp_si (const mpq_t OP1, long int NUM2, unsigned long
+          int DEN2)
+     Compare OP1 and NUM2/DEN2.  Return a positive value if OP1 >
+     NUM2/DEN2, zero if OP1 = NUM2/DEN2, and a negative value if OP1 <
+     NUM2/DEN2.
+
+     NUM2 and DEN2 are allowed to have common factors.
+
+     These functions are implemented as a macros and evaluate their
+     arguments multiple times.
+
+ -- Macro: int mpq_sgn (const mpq_t OP)
+     Return +1 if OP > 0, 0 if OP = 0, and -1 if OP < 0.
+
+     This function is actually implemented as a macro.  It evaluates its
+     argument multiple times.
+
+ -- Function: int mpq_equal (const mpq_t OP1, const mpq_t OP2)
+     Return non-zero if OP1 and OP2 are equal, zero if they are
+     non-equal.  Although 'mpq_cmp' can be used for the same purpose,
+     this function is much faster.
+
+
+File: gmp.info,  Node: Applying Integer Functions,  Next: I/O of Rationals,  Prev: Comparing Rationals,  Up: Rational Number Functions
+
+6.5 Applying Integer Functions to Rationals
+===========================================
+
+The set of 'mpq' functions is quite small.  In particular, there are few
+functions for either input or output.  The following functions give
+direct access to the numerator and denominator of an 'mpq_t'.
+
+   Note that if an assignment to the numerator and/or denominator could
+take an 'mpq_t' out of the canonical form described at the start of this
+chapter (*note Rational Number Functions::) then 'mpq_canonicalize' must
+be called before any other 'mpq' functions are applied to that 'mpq_t'.
+
+ -- Macro: mpz_t mpq_numref (const mpq_t OP)
+ -- Macro: mpz_t mpq_denref (const mpq_t OP)
+     Return a reference to the numerator and denominator of OP,
+     respectively.  The 'mpz' functions can be used on the result of
+     these macros.
+
+ -- Function: void mpq_get_num (mpz_t NUMERATOR, const mpq_t RATIONAL)
+ -- Function: void mpq_get_den (mpz_t DENOMINATOR, const mpq_t RATIONAL)
+ -- Function: void mpq_set_num (mpq_t RATIONAL, const mpz_t NUMERATOR)
+ -- Function: void mpq_set_den (mpq_t RATIONAL, const mpz_t DENOMINATOR)
+     Get or set the numerator or denominator of a rational.  These
+     functions are equivalent to calling 'mpz_set' with an appropriate
+     'mpq_numref' or 'mpq_denref'.  Direct use of 'mpq_numref' or
+     'mpq_denref' is recommended instead of these functions.
+
+
+File: gmp.info,  Node: I/O of Rationals,  Prev: Applying Integer Functions,  Up: Rational Number Functions
+
+6.6 Input and Output Functions
+==============================
+
+Functions that perform input from a stdio stream, and functions that
+output to a stdio stream, of 'mpq' numbers.  Passing a 'NULL' pointer
+for a STREAM argument to any of these functions will make them read from
+'stdin' and write to 'stdout', respectively.
+
+   When using any of these functions, it is a good idea to include
+'stdio.h' before 'gmp.h', since that will allow 'gmp.h' to define
+prototypes for these functions.
+
+   See also *note Formatted Output:: and *note Formatted Input::.
+
+ -- Function: size_t mpq_out_str (FILE *STREAM, int BASE, const mpq_t
+          OP)
+     Output OP on stdio stream STREAM, as a string of digits in base
+     BASE.  The base argument may vary from 2 to 62 or from -2 to -36.
+     Output is in the form 'num/den' or if the denominator is 1 then
+     just 'num'.
+
+     For BASE in the range 2..36, digits and lower-case letters are
+     used; for -2..-36, digits and upper-case letters are used; for
+     37..62, digits, upper-case letters, and lower-case letters (in that
+     significance order) are used.
+
+     Return the number of bytes written, or if an error occurred, return
+     0.
+
+ -- Function: size_t mpq_inp_str (mpq_t ROP, FILE *STREAM, int BASE)
+     Read a string of digits from STREAM and convert them to a rational
+     in ROP.  Any initial white-space characters are read and discarded.
+     Return the number of characters read (including white space), or 0
+     if a rational could not be read.
+
+     The input can be a fraction like '17/63' or just an integer like
+     '123'.  Reading stops at the first character not in this form, and
+     white space is not permitted within the string.  If the input might
+     not be in canonical form, then 'mpq_canonicalize' must be called
+     (*note Rational Number Functions::).
+
+     The BASE can be between 2 and 62, or can be 0 in which case the
+     leading characters of the string determine the base, '0x' or '0X'
+     for hexadecimal, '0b' and '0B' for binary, '0' for octal, or
+     decimal otherwise.  The leading characters are examined separately
+     for the numerator and denominator of a fraction, so for instance
+     '0x10/11' is 16/11, whereas '0x10/0x11' is 16/17.
+
+
+File: gmp.info,  Node: Floating-point Functions,  Next: Low-level Functions,  Prev: Rational Number Functions,  Up: Top
+
+7 Floating-point Functions
+**************************
+
+GMP floating point numbers are stored in objects of type 'mpf_t' and
+functions operating on them have an 'mpf_' prefix.
+
+   The mantissa of each float has a user-selectable precision, in
+practice only limited by available memory.  Each variable has its own
+precision, and that can be increased or decreased at any time.  This
+selectable precision is a minimum value, GMP rounds it up to a whole
+limb.
+
+   The accuracy of a calculation is determined by the priorly set
+precision of the destination variable and the numeric values of the
+input variables.  Input variables' set precisions do not affect
+calculations (except indirectly as their values might have been affected
+when they were assigned).
+
+   The exponent of each float has fixed precision, one machine word on
+most systems.  In the current implementation the exponent is a count of
+limbs, so for example on a 32-bit system this means a range of roughly
+2^-68719476768 to 2^68719476736, or on a 64-bit system this will be much
+greater.  Note however that 'mpf_get_str' can only return an exponent
+which fits an 'mp_exp_t' and currently 'mpf_set_str' doesn't accept
+exponents bigger than a 'long'.
+
+   Each variable keeps track of the mantissa data actually in use.  This
+means that if a float is exactly represented in only a few bits then
+only those bits will be used in a calculation, even if the variable's
+selected precision is high.  This is a performance optimization; it does
+not affect the numeric results.
+
+   Internally, GMP sometimes calculates with higher precision than that
+of the destination variable in order to limit errors.  Final results are
+always truncated to the destination variable's precision.
+
+   The mantissa is stored in binary.  One consequence of this is that
+decimal fractions like 0.1 cannot be represented exactly.  The same is
+true of plain IEEE 'double' floats.  This makes both highly unsuitable
+for calculations involving money or other values that should be exact
+decimal fractions.  (Suitably scaled integers, or perhaps rationals, are
+better choices.)
+
+   The 'mpf' functions and variables have no special notion of infinity
+or not-a-number, and applications must take care not to overflow the
+exponent or results will be unpredictable.
+
+   Note that the 'mpf' functions are _not_ intended as a smooth
+extension to IEEE P754 arithmetic.  In particular results obtained on
+one computer often differ from the results on a computer with a
+different word size.
+
+   New projects should consider using the GMP extension library MPFR
+(<http://mpfr.org>) instead.  MPFR provides well-defined precision and
+accurate rounding, and thereby naturally extends IEEE P754.
+
+* Menu:
+
+* Initializing Floats::
+* Assigning Floats::
+* Simultaneous Float Init & Assign::
+* Converting Floats::
+* Float Arithmetic::
+* Float Comparison::
+* I/O of Floats::
+* Miscellaneous Float Functions::
+
+
+File: gmp.info,  Node: Initializing Floats,  Next: Assigning Floats,  Prev: Floating-point Functions,  Up: Floating-point Functions
+
+7.1 Initialization Functions
+============================
+
+ -- Function: void mpf_set_default_prec (mp_bitcnt_t PREC)
+     Set the default precision to be *at least* PREC bits.  All
+     subsequent calls to 'mpf_init' will use this precision, but
+     previously initialized variables are unaffected.
+
+ -- Function: mp_bitcnt_t mpf_get_default_prec (void)
+     Return the default precision actually used.
+
+   An 'mpf_t' object must be initialized before storing the first value
+in it.  The functions 'mpf_init' and 'mpf_init2' are used for that
+purpose.
+
+ -- Function: void mpf_init (mpf_t X)
+     Initialize X to 0.  Normally, a variable should be initialized once
+     only or at least be cleared, using 'mpf_clear', between
+     initializations.  The precision of X is undefined unless a default
+     precision has already been established by a call to
+     'mpf_set_default_prec'.
+
+ -- Function: void mpf_init2 (mpf_t X, mp_bitcnt_t PREC)
+     Initialize X to 0 and set its precision to be *at least* PREC bits.
+     Normally, a variable should be initialized once only or at least be
+     cleared, using 'mpf_clear', between initializations.
+
+ -- Function: void mpf_inits (mpf_t X, ...)
+     Initialize a NULL-terminated list of 'mpf_t' variables, and set
+     their values to 0.  The precision of the initialized variables is
+     undefined unless a default precision has already been established
+     by a call to 'mpf_set_default_prec'.
+
+ -- Function: void mpf_clear (mpf_t X)
+     Free the space occupied by X.  Make sure to call this function for
+     all 'mpf_t' variables when you are done with them.
+
+ -- Function: void mpf_clears (mpf_t X, ...)
+     Free the space occupied by a NULL-terminated list of 'mpf_t'
+     variables.
+
+   Here is an example on how to initialize floating-point variables:
+     {
+       mpf_t x, y;
+       mpf_init (x);           /* use default precision */
+       mpf_init2 (y, 256);     /* precision _at least_ 256 bits */
+       ...
+       /* Unless the program is about to exit, do ... */
+       mpf_clear (x);
+       mpf_clear (y);
+     }
+
+   The following three functions are useful for changing the precision
+during a calculation.  A typical use would be for adjusting the
+precision gradually in iterative algorithms like Newton-Raphson, making
+the computation precision closely match the actual accurate part of the
+numbers.
+
+ -- Function: mp_bitcnt_t mpf_get_prec (const mpf_t OP)
+     Return the current precision of OP, in bits.
+
+ -- Function: void mpf_set_prec (mpf_t ROP, mp_bitcnt_t PREC)
+     Set the precision of ROP to be *at least* PREC bits.  The value in
+     ROP will be truncated to the new precision.
+
+     This function requires a call to 'realloc', and so should not be
+     used in a tight loop.
+
+ -- Function: void mpf_set_prec_raw (mpf_t ROP, mp_bitcnt_t PREC)
+     Set the precision of ROP to be *at least* PREC bits, without
+     changing the memory allocated.
+
+     PREC must be no more than the allocated precision for ROP, that
+     being the precision when ROP was initialized, or in the most recent
+     'mpf_set_prec'.
+
+     The value in ROP is unchanged, and in particular if it had a higher
+     precision than PREC it will retain that higher precision.  New
+     values written to ROP will use the new PREC.
+
+     Before calling 'mpf_clear' or the full 'mpf_set_prec', another
+     'mpf_set_prec_raw' call must be made to restore ROP to its original
+     allocated precision.  Failing to do so will have unpredictable
+     results.
+
+     'mpf_get_prec' can be used before 'mpf_set_prec_raw' to get the
+     original allocated precision.  After 'mpf_set_prec_raw' it reflects
+     the PREC value set.
+
+     'mpf_set_prec_raw' is an efficient way to use an 'mpf_t' variable
+     at different precisions during a calculation, perhaps to gradually
+     increase precision in an iteration, or just to use various
+     different precisions for different purposes during a calculation.
+
+
+File: gmp.info,  Node: Assigning Floats,  Next: Simultaneous Float Init & Assign,  Prev: Initializing Floats,  Up: Floating-point Functions
+
+7.2 Assignment Functions
+========================
+
+These functions assign new values to already initialized floats (*note
+Initializing Floats::).
+
+ -- Function: void mpf_set (mpf_t ROP, const mpf_t OP)
+ -- Function: void mpf_set_ui (mpf_t ROP, unsigned long int OP)
+ -- Function: void mpf_set_si (mpf_t ROP, signed long int OP)
+ -- Function: void mpf_set_d (mpf_t ROP, double OP)
+ -- Function: void mpf_set_z (mpf_t ROP, const mpz_t OP)
+ -- Function: void mpf_set_q (mpf_t ROP, const mpq_t OP)
+     Set the value of ROP from OP.
+
+ -- Function: int mpf_set_str (mpf_t ROP, const char *STR, int BASE)
+     Set the value of ROP from the string in STR.  The string is of the
+     form 'M@N' or, if the base is 10 or less, alternatively 'MeN'.  'M'
+     is the mantissa and 'N' is the exponent.  The mantissa is always in
+     the specified base.  The exponent is either in the specified base
+     or, if BASE is negative, in decimal.  The decimal point expected is
+     taken from the current locale, on systems providing 'localeconv'.
+
+     The argument BASE may be in the ranges 2 to 62, or -62 to -2.
+     Negative values are used to specify that the exponent is in
+     decimal.
+
+     For bases up to 36, case is ignored; upper-case and lower-case
+     letters have the same value; for bases 37 to 62, upper-case letter
+     represent the usual 10..35 while lower-case letter represent
+     36..61.
+
+     Unlike the corresponding 'mpz' function, the base will not be
+     determined from the leading characters of the string if BASE is 0.
+     This is so that numbers like '0.23' are not interpreted as octal.
+
+     White space is allowed in the string, and is simply ignored.  [This
+     is not really true; white-space is ignored in the beginning of the
+     string and within the mantissa, but not in other places, such as
+     after a minus sign or in the exponent.  We are considering changing
+     the definition of this function, making it fail when there is any
+     white-space in the input, since that makes a lot of sense.  Please
+     tell us your opinion about this change.  Do you really want it to
+     accept "3 14" as meaning 314 as it does now?]
+
+     This function returns 0 if the entire string is a valid number in
+     base BASE.  Otherwise it returns -1.
+
+ -- Function: void mpf_swap (mpf_t ROP1, mpf_t ROP2)
+     Swap ROP1 and ROP2 efficiently.  Both the values and the precisions
+     of the two variables are swapped.
+
+
+File: gmp.info,  Node: Simultaneous Float Init & Assign,  Next: Converting Floats,  Prev: Assigning Floats,  Up: Floating-point Functions
+
+7.3 Combined Initialization and Assignment Functions
+====================================================
+
+For convenience, GMP provides a parallel series of initialize-and-set
+functions which initialize the output and then store the value there.
+These functions' names have the form 'mpf_init_set...'
+
+   Once the float has been initialized by any of the 'mpf_init_set...'
+functions, it can be used as the source or destination operand for the
+ordinary float functions.  Don't use an initialize-and-set function on a
+variable already initialized!
+
+ -- Function: void mpf_init_set (mpf_t ROP, const mpf_t OP)
+ -- Function: void mpf_init_set_ui (mpf_t ROP, unsigned long int OP)
+ -- Function: void mpf_init_set_si (mpf_t ROP, signed long int OP)
+ -- Function: void mpf_init_set_d (mpf_t ROP, double OP)
+     Initialize ROP and set its value from OP.
+
+     The precision of ROP will be taken from the active default
+     precision, as set by 'mpf_set_default_prec'.
+
+ -- Function: int mpf_init_set_str (mpf_t ROP, const char *STR, int
+          BASE)
+     Initialize ROP and set its value from the string in STR.  See
+     'mpf_set_str' above for details on the assignment operation.
+
+     Note that ROP is initialized even if an error occurs.  (I.e., you
+     have to call 'mpf_clear' for it.)
+
+     The precision of ROP will be taken from the active default
+     precision, as set by 'mpf_set_default_prec'.
+
+
+File: gmp.info,  Node: Converting Floats,  Next: Float Arithmetic,  Prev: Simultaneous Float Init & Assign,  Up: Floating-point Functions
+
+7.4 Conversion Functions
+========================
+
+ -- Function: double mpf_get_d (const mpf_t OP)
+     Convert OP to a 'double', truncating if necessary (i.e. rounding
+     towards zero).
+
+     If the exponent in OP is too big or too small to fit a 'double'
+     then the result is system dependent.  For too big an infinity is
+     returned when available.  For too small 0.0 is normally returned.
+     Hardware overflow, underflow and denorm traps may or may not occur.
+
+ -- Function: double mpf_get_d_2exp (signed long int *EXP, const mpf_t
+          OP)
+     Convert OP to a 'double', truncating if necessary (i.e. rounding
+     towards zero), and with an exponent returned separately.
+
+     The return value is in the range 0.5<=abs(D)<1 and the exponent is
+     stored to '*EXP'.  D * 2^EXP is the (truncated) OP value.  If OP is
+     zero, the return is 0.0 and 0 is stored to '*EXP'.
+
+     This is similar to the standard C 'frexp' function (*note
+     (libc)Normalization Functions::).
+
+ -- Function: long mpf_get_si (const mpf_t OP)
+ -- Function: unsigned long mpf_get_ui (const mpf_t OP)
+     Convert OP to a 'long' or 'unsigned long', truncating any fraction
+     part.  If OP is too big for the return type, the result is
+     undefined.
+
+     See also 'mpf_fits_slong_p' and 'mpf_fits_ulong_p' (*note
+     Miscellaneous Float Functions::).
+
+ -- Function: char * mpf_get_str (char *STR, mp_exp_t *EXPPTR, int BASE,
+          size_t N_DIGITS, const mpf_t OP)
+     Convert OP to a string of digits in base BASE.  The base argument
+     may vary from 2 to 62 or from -2 to -36.  Up to N_DIGITS digits
+     will be generated.  Trailing zeros are not returned.  No more
+     digits than can be accurately represented by OP are ever generated.
+     If N_DIGITS is 0 then that accurate maximum number of digits are
+     generated.
+
+     For BASE in the range 2..36, digits and lower-case letters are
+     used; for -2..-36, digits and upper-case letters are used; for
+     37..62, digits, upper-case letters, and lower-case letters (in that
+     significance order) are used.
+
+     If STR is 'NULL', the result string is allocated using the current
+     allocation function (*note Custom Allocation::).  The block will be
+     'strlen(str)+1' bytes, that being exactly enough for the string and
+     null-terminator.
+
+     If STR is not 'NULL', it should point to a block of N_DIGITS + 2
+     bytes, that being enough for the mantissa, a possible minus sign,
+     and a null-terminator.  When N_DIGITS is 0 to get all significant
+     digits, an application won't be able to know the space required,
+     and STR should be 'NULL' in that case.
+
+     The generated string is a fraction, with an implicit radix point
+     immediately to the left of the first digit.  The applicable
+     exponent is written through the EXPPTR pointer.  For example, the
+     number 3.1416 would be returned as string "31416" and exponent 1.
+
+     When OP is zero, an empty string is produced and the exponent
+     returned is 0.
+
+     A pointer to the result string is returned, being either the
+     allocated block or the given STR.
+
+
+File: gmp.info,  Node: Float Arithmetic,  Next: Float Comparison,  Prev: Converting Floats,  Up: Floating-point Functions
+
+7.5 Arithmetic Functions
+========================
+
+ -- Function: void mpf_add (mpf_t ROP, const mpf_t OP1, const mpf_t OP2)
+ -- Function: void mpf_add_ui (mpf_t ROP, const mpf_t OP1, unsigned long
+          int OP2)
+     Set ROP to OP1 + OP2.
+
+ -- Function: void mpf_sub (mpf_t ROP, const mpf_t OP1, const mpf_t OP2)
+ -- Function: void mpf_ui_sub (mpf_t ROP, unsigned long int OP1, const
+          mpf_t OP2)
+ -- Function: void mpf_sub_ui (mpf_t ROP, const mpf_t OP1, unsigned long
+          int OP2)
+     Set ROP to OP1 - OP2.
+
+ -- Function: void mpf_mul (mpf_t ROP, const mpf_t OP1, const mpf_t OP2)
+ -- Function: void mpf_mul_ui (mpf_t ROP, const mpf_t OP1, unsigned long
+          int OP2)
+     Set ROP to OP1 times OP2.
+
+   Division is undefined if the divisor is zero, and passing a zero
+divisor to the divide functions will make these functions intentionally
+divide by zero.  This lets the user handle arithmetic exceptions in
+these functions in the same manner as other arithmetic exceptions.
+
+ -- Function: void mpf_div (mpf_t ROP, const mpf_t OP1, const mpf_t OP2)
+ -- Function: void mpf_ui_div (mpf_t ROP, unsigned long int OP1, const
+          mpf_t OP2)
+ -- Function: void mpf_div_ui (mpf_t ROP, const mpf_t OP1, unsigned long
+          int OP2)
+     Set ROP to OP1/OP2.
+
+ -- Function: void mpf_sqrt (mpf_t ROP, const mpf_t OP)
+ -- Function: void mpf_sqrt_ui (mpf_t ROP, unsigned long int OP)
+     Set ROP to the square root of OP.
+
+ -- Function: void mpf_pow_ui (mpf_t ROP, const mpf_t OP1, unsigned long
+          int OP2)
+     Set ROP to OP1 raised to the power OP2.
+
+ -- Function: void mpf_neg (mpf_t ROP, const mpf_t OP)
+     Set ROP to -OP.
+
+ -- Function: void mpf_abs (mpf_t ROP, const mpf_t OP)
+     Set ROP to the absolute value of OP.
+
+ -- Function: void mpf_mul_2exp (mpf_t ROP, const mpf_t OP1, mp_bitcnt_t
+          OP2)
+     Set ROP to OP1 times 2 raised to OP2.
+
+ -- Function: void mpf_div_2exp (mpf_t ROP, const mpf_t OP1, mp_bitcnt_t
+          OP2)
+     Set ROP to OP1 divided by 2 raised to OP2.
+
+
+File: gmp.info,  Node: Float Comparison,  Next: I/O of Floats,  Prev: Float Arithmetic,  Up: Floating-point Functions
+
+7.6 Comparison Functions
+========================
+
+ -- Function: int mpf_cmp (const mpf_t OP1, const mpf_t OP2)
+ -- Function: int mpf_cmp_z (const mpf_t OP1, const mpz_t OP2)
+ -- Function: int mpf_cmp_d (const mpf_t OP1, double OP2)
+ -- Function: int mpf_cmp_ui (const mpf_t OP1, unsigned long int OP2)
+ -- Function: int mpf_cmp_si (const mpf_t OP1, signed long int OP2)
+     Compare OP1 and OP2.  Return a positive value if OP1 > OP2, zero if
+     OP1 = OP2, and a negative value if OP1 < OP2.
+
+     'mpf_cmp_d' can be called with an infinity, but results are
+     undefined for a NaN.
+
+ -- Function: int mpf_eq (const mpf_t OP1, const mpf_t OP2, mp_bitcnt_t
+          op3)
+     *This function is mathematically ill-defined and should not be
+     used.*
+
+     Return non-zero if the first OP3 bits of OP1 and OP2 are equal,
+     zero otherwise.  Note that numbers like e.g., 256 (binary
+     100000000) and 255 (binary 11111111) will never be equal by this
+     function's measure, and furthermore that 0 will only be equal to
+     itself.
+
+ -- Function: void mpf_reldiff (mpf_t ROP, const mpf_t OP1, const mpf_t
+          OP2)
+     Compute the relative difference between OP1 and OP2 and store the
+     result in ROP.  This is abs(OP1-OP2)/OP1.
+
+ -- Macro: int mpf_sgn (const mpf_t OP)
+     Return +1 if OP > 0, 0 if OP = 0, and -1 if OP < 0.
+
+     This function is actually implemented as a macro.  It evaluates its
+     argument multiple times.
+
+
+File: gmp.info,  Node: I/O of Floats,  Next: Miscellaneous Float Functions,  Prev: Float Comparison,  Up: Floating-point Functions
+
+7.7 Input and Output Functions
+==============================
+
+Functions that perform input from a stdio stream, and functions that
+output to a stdio stream, of 'mpf' numbers.  Passing a 'NULL' pointer
+for a STREAM argument to any of these functions will make them read from
+'stdin' and write to 'stdout', respectively.
+
+   When using any of these functions, it is a good idea to include
+'stdio.h' before 'gmp.h', since that will allow 'gmp.h' to define
+prototypes for these functions.
+
+   See also *note Formatted Output:: and *note Formatted Input::.
+
+ -- Function: size_t mpf_out_str (FILE *STREAM, int BASE, size_t
+          N_DIGITS, const mpf_t OP)
+     Print OP to STREAM, as a string of digits.  Return the number of
+     bytes written, or if an error occurred, return 0.
+
+     The mantissa is prefixed with an '0.' and is in the given BASE,
+     which may vary from 2 to 62 or from -2 to -36.  An exponent is then
+     printed, separated by an 'e', or if the base is greater than 10
+     then by an '@'.  The exponent is always in decimal.  The decimal
+     point follows the current locale, on systems providing
+     'localeconv'.
+
+     For BASE in the range 2..36, digits and lower-case letters are
+     used; for -2..-36, digits and upper-case letters are used; for
+     37..62, digits, upper-case letters, and lower-case letters (in that
+     significance order) are used.
+
+     Up to N_DIGITS will be printed from the mantissa, except that no
+     more digits than are accurately representable by OP will be
+     printed.  N_DIGITS can be 0 to select that accurate maximum.
+
+ -- Function: size_t mpf_inp_str (mpf_t ROP, FILE *STREAM, int BASE)
+     Read a string in base BASE from STREAM, and put the read float in
+     ROP.  The string is of the form 'M@N' or, if the base is 10 or
+     less, alternatively 'MeN'.  'M' is the mantissa and 'N' is the
+     exponent.  The mantissa is always in the specified base.  The
+     exponent is either in the specified base or, if BASE is negative,
+     in decimal.  The decimal point expected is taken from the current
+     locale, on systems providing 'localeconv'.
+
+     The argument BASE may be in the ranges 2 to 36, or -36 to -2.
+     Negative values are used to specify that the exponent is in
+     decimal.
+
+     Unlike the corresponding 'mpz' function, the base will not be
+     determined from the leading characters of the string if BASE is 0.
+     This is so that numbers like '0.23' are not interpreted as octal.
+
+     Return the number of bytes read, or if an error occurred, return 0.
+
+
+File: gmp.info,  Node: Miscellaneous Float Functions,  Prev: I/O of Floats,  Up: Floating-point Functions
+
+7.8 Miscellaneous Functions
+===========================
+
+ -- Function: void mpf_ceil (mpf_t ROP, const mpf_t OP)
+ -- Function: void mpf_floor (mpf_t ROP, const mpf_t OP)
+ -- Function: void mpf_trunc (mpf_t ROP, const mpf_t OP)
+     Set ROP to OP rounded to an integer.  'mpf_ceil' rounds to the next
+     higher integer, 'mpf_floor' to the next lower, and 'mpf_trunc' to
+     the integer towards zero.
+
+ -- Function: int mpf_integer_p (const mpf_t OP)
+     Return non-zero if OP is an integer.
+
+ -- Function: int mpf_fits_ulong_p (const mpf_t OP)
+ -- Function: int mpf_fits_slong_p (const mpf_t OP)
+ -- Function: int mpf_fits_uint_p (const mpf_t OP)
+ -- Function: int mpf_fits_sint_p (const mpf_t OP)
+ -- Function: int mpf_fits_ushort_p (const mpf_t OP)
+ -- Function: int mpf_fits_sshort_p (const mpf_t OP)
+     Return non-zero if OP would fit in the respective C data type, when
+     truncated to an integer.
+
+ -- Function: void mpf_urandomb (mpf_t ROP, gmp_randstate_t STATE,
+          mp_bitcnt_t NBITS)
+     Generate a uniformly distributed random float in ROP, such that 0
+     <= ROP < 1, with NBITS significant bits in the mantissa or less if
+     the precision of ROP is smaller.
+
+     The variable STATE must be initialized by calling one of the
+     'gmp_randinit' functions (*note Random State Initialization::)
+     before invoking this function.
+
+ -- Function: void mpf_random2 (mpf_t ROP, mp_size_t MAX_SIZE, mp_exp_t
+          EXP)
+     Generate a random float of at most MAX_SIZE limbs, with long
+     strings of zeros and ones in the binary representation.  The
+     exponent of the number is in the interval -EXP to EXP (in limbs).
+     This function is useful for testing functions and algorithms, since
+     these kind of random numbers have proven to be more likely to
+     trigger corner-case bugs.  Negative random numbers are generated
+     when MAX_SIZE is negative.
+
+
+File: gmp.info,  Node: Low-level Functions,  Next: Random Number Functions,  Prev: Floating-point Functions,  Up: Top
+
+8 Low-level Functions
+*********************
+
+This chapter describes low-level GMP functions, used to implement the
+high-level GMP functions, but also intended for time-critical user code.
+
+   These functions start with the prefix 'mpn_'.
+
+   The 'mpn' functions are designed to be as fast as possible, *not* to
+provide a coherent calling interface.  The different functions have
+somewhat similar interfaces, but there are variations that make them
+hard to use.  These functions do as little as possible apart from the
+real multiple precision computation, so that no time is spent on things
+that not all callers need.
+
+   A source operand is specified by a pointer to the least significant
+limb and a limb count.  A destination operand is specified by just a
+pointer.  It is the responsibility of the caller to ensure that the
+destination has enough space for storing the result.
+
+   With this way of specifying operands, it is possible to perform
+computations on subranges of an argument, and store the result into a
+subrange of a destination.
+
+   A common requirement for all functions is that each source area needs
+at least one limb.  No size argument may be zero.  Unless otherwise
+stated, in-place operations are allowed where source and destination are
+the same, but not where they only partly overlap.
+
+   The 'mpn' functions are the base for the implementation of the
+'mpz_', 'mpf_', and 'mpq_' functions.
+
+   This example adds the number beginning at S1P and the number
+beginning at S2P and writes the sum at DESTP.  All areas have N limbs.
+
+     cy = mpn_add_n (destp, s1p, s2p, n)
+
+   It should be noted that the 'mpn' functions make no attempt to
+identify high or low zero limbs on their operands, or other special
+forms.  On random data such cases will be unlikely and it'd be wasteful
+for every function to check every time.  An application knowing
+something about its data can take steps to trim or perhaps split its
+calculations.
+
+
+In the notation used below, a source operand is identified by the
+pointer to the least significant limb, and the limb count in braces.
+For example, {S1P, S1N}.
+
+ -- Function: mp_limb_t mpn_add_n (mp_limb_t *RP, const mp_limb_t *S1P,
+          const mp_limb_t *S2P, mp_size_t N)
+     Add {S1P, N} and {S2P, N}, and write the N least significant limbs
+     of the result to RP.  Return carry, either 0 or 1.
+
+     This is the lowest-level function for addition.  It is the
+     preferred function for addition, since it is written in assembly
+     for most CPUs.  For addition of a variable to itself (i.e., S1P
+     equals S2P) use 'mpn_lshift' with a count of 1 for optimal speed.
+
+ -- Function: mp_limb_t mpn_add_1 (mp_limb_t *RP, const mp_limb_t *S1P,
+          mp_size_t N, mp_limb_t S2LIMB)
+     Add {S1P, N} and S2LIMB, and write the N least significant limbs of
+     the result to RP.  Return carry, either 0 or 1.
+
+ -- Function: mp_limb_t mpn_add (mp_limb_t *RP, const mp_limb_t *S1P,
+          mp_size_t S1N, const mp_limb_t *S2P, mp_size_t S2N)
+     Add {S1P, S1N} and {S2P, S2N}, and write the S1N least significant
+     limbs of the result to RP.  Return carry, either 0 or 1.
+
+     This function requires that S1N is greater than or equal to S2N.
+
+ -- Function: mp_limb_t mpn_sub_n (mp_limb_t *RP, const mp_limb_t *S1P,
+          const mp_limb_t *S2P, mp_size_t N)
+     Subtract {S2P, N} from {S1P, N}, and write the N least significant
+     limbs of the result to RP.  Return borrow, either 0 or 1.
+
+     This is the lowest-level function for subtraction.  It is the
+     preferred function for subtraction, since it is written in assembly
+     for most CPUs.
+
+ -- Function: mp_limb_t mpn_sub_1 (mp_limb_t *RP, const mp_limb_t *S1P,
+          mp_size_t N, mp_limb_t S2LIMB)
+     Subtract S2LIMB from {S1P, N}, and write the N least significant
+     limbs of the result to RP.  Return borrow, either 0 or 1.
+
+ -- Function: mp_limb_t mpn_sub (mp_limb_t *RP, const mp_limb_t *S1P,
+          mp_size_t S1N, const mp_limb_t *S2P, mp_size_t S2N)
+     Subtract {S2P, S2N} from {S1P, S1N}, and write the S1N least
+     significant limbs of the result to RP.  Return borrow, either 0 or
+     1.
+
+     This function requires that S1N is greater than or equal to S2N.
+
+ -- Function: mp_limb_t mpn_neg (mp_limb_t *RP, const mp_limb_t *SP,
+          mp_size_t N)
+     Perform the negation of {SP, N}, and write the result to {RP, N}.
+     This is equivalent to calling 'mpn_sub_n' with a N-limb zero
+     minuend and passing {SP, N} as subtrahend.  Return borrow, either 0
+     or 1.
+
+ -- Function: void mpn_mul_n (mp_limb_t *RP, const mp_limb_t *S1P, const
+          mp_limb_t *S2P, mp_size_t N)
+     Multiply {S1P, N} and {S2P, N}, and write the 2*N-limb result to
+     RP.
+
+     The destination has to have space for 2*N limbs, even if the
+     product's most significant limb is zero.  No overlap is permitted
+     between the destination and either source.
+
+     If the two input operands are the same, use 'mpn_sqr'.
+
+ -- Function: mp_limb_t mpn_mul (mp_limb_t *RP, const mp_limb_t *S1P,
+          mp_size_t S1N, const mp_limb_t *S2P, mp_size_t S2N)
+     Multiply {S1P, S1N} and {S2P, S2N}, and write the (S1N+S2N)-limb
+     result to RP.  Return the most significant limb of the result.
+
+     The destination has to have space for S1N + S2N limbs, even if the
+     product's most significant limb is zero.  No overlap is permitted
+     between the destination and either source.
+
+     This function requires that S1N is greater than or equal to S2N.
+
+ -- Function: void mpn_sqr (mp_limb_t *RP, const mp_limb_t *S1P,
+          mp_size_t N)
+     Compute the square of {S1P, N} and write the 2*N-limb result to RP.
+
+     The destination has to have space for 2N limbs, even if the
+     result's most significant limb is zero.  No overlap is permitted
+     between the destination and the source.
+
+ -- Function: mp_limb_t mpn_mul_1 (mp_limb_t *RP, const mp_limb_t *S1P,
+          mp_size_t N, mp_limb_t S2LIMB)
+     Multiply {S1P, N} by S2LIMB, and write the N least significant
+     limbs of the product to RP.  Return the most significant limb of
+     the product.  {S1P, N} and {RP, N} are allowed to overlap provided
+     RP <= S1P.
+
+     This is a low-level function that is a building block for general
+     multiplication as well as other operations in GMP.  It is written
+     in assembly for most CPUs.
+
+     Don't call this function if S2LIMB is a power of 2; use
+     'mpn_lshift' with a count equal to the logarithm of S2LIMB instead,
+     for optimal speed.
+
+ -- Function: mp_limb_t mpn_addmul_1 (mp_limb_t *RP, const mp_limb_t
+          *S1P, mp_size_t N, mp_limb_t S2LIMB)
+     Multiply {S1P, N} and S2LIMB, and add the N least significant limbs
+     of the product to {RP, N} and write the result to RP.  Return the
+     most significant limb of the product, plus carry-out from the
+     addition.  {S1P, N} and {RP, N} are allowed to overlap provided RP
+     <= S1P.
+
+     This is a low-level function that is a building block for general
+     multiplication as well as other operations in GMP.  It is written
+     in assembly for most CPUs.
+
+ -- Function: mp_limb_t mpn_submul_1 (mp_limb_t *RP, const mp_limb_t
+          *S1P, mp_size_t N, mp_limb_t S2LIMB)
+     Multiply {S1P, N} and S2LIMB, and subtract the N least significant
+     limbs of the product from {RP, N} and write the result to RP.
+     Return the most significant limb of the product, plus borrow-out
+     from the subtraction.  {S1P, N} and {RP, N} are allowed to overlap
+     provided RP <= S1P.
+
+     This is a low-level function that is a building block for general
+     multiplication and division as well as other operations in GMP.  It
+     is written in assembly for most CPUs.
+
+ -- Function: void mpn_tdiv_qr (mp_limb_t *QP, mp_limb_t *RP, mp_size_t
+          QXN, const mp_limb_t *NP, mp_size_t NN, const mp_limb_t *DP,
+          mp_size_t DN)
+     Divide {NP, NN} by {DP, DN} and put the quotient at {QP, NN-DN+1}
+     and the remainder at {RP, DN}.  The quotient is rounded towards 0.
+
+     No overlap is permitted between arguments, except that NP might
+     equal RP.  The dividend size NN must be greater than or equal to
+     divisor size DN.  The most significant limb of the divisor must be
+     non-zero.  The QXN operand must be zero.
+
+ -- Function: mp_limb_t mpn_divrem (mp_limb_t *R1P, mp_size_t QXN,
+          mp_limb_t *RS2P, mp_size_t RS2N, const mp_limb_t *S3P,
+          mp_size_t S3N)
+     [This function is obsolete.  Please call 'mpn_tdiv_qr' instead for
+     best performance.]
+
+     Divide {RS2P, RS2N} by {S3P, S3N}, and write the quotient at R1P,
+     with the exception of the most significant limb, which is returned.
+     The remainder replaces the dividend at RS2P; it will be S3N limbs
+     long (i.e., as many limbs as the divisor).
+
+     In addition to an integer quotient, QXN fraction limbs are
+     developed, and stored after the integral limbs.  For most usages,
+     QXN will be zero.
+
+     It is required that RS2N is greater than or equal to S3N.  It is
+     required that the most significant bit of the divisor is set.
+
+     If the quotient is not needed, pass RS2P + S3N as R1P.  Aside from
+     that special case, no overlap between arguments is permitted.
+
+     Return the most significant limb of the quotient, either 0 or 1.
+
+     The area at R1P needs to be RS2N - S3N + QXN limbs large.
+
+ -- Function: mp_limb_t mpn_divrem_1 (mp_limb_t *R1P, mp_size_t QXN,
+          mp_limb_t *S2P, mp_size_t S2N, mp_limb_t S3LIMB)
+ -- Macro: mp_limb_t mpn_divmod_1 (mp_limb_t *R1P, mp_limb_t *S2P,
+          mp_size_t S2N, mp_limb_t S3LIMB)
+     Divide {S2P, S2N} by S3LIMB, and write the quotient at R1P.  Return
+     the remainder.
+
+     The integer quotient is written to {R1P+QXN, S2N} and in addition
+     QXN fraction limbs are developed and written to {R1P, QXN}.  Either
+     or both S2N and QXN can be zero.  For most usages, QXN will be
+     zero.
+
+     'mpn_divmod_1' exists for upward source compatibility and is simply
+     a macro calling 'mpn_divrem_1' with a QXN of 0.
+
+     The areas at R1P and S2P have to be identical or completely
+     separate, not partially overlapping.
+
+ -- Function: mp_limb_t mpn_divmod (mp_limb_t *R1P, mp_limb_t *RS2P,
+          mp_size_t RS2N, const mp_limb_t *S3P, mp_size_t S3N)
+     [This function is obsolete.  Please call 'mpn_tdiv_qr' instead for
+     best performance.]
+
+ -- Function: void mpn_divexact_1 (mp_limb_t * RP, const mp_limb_t * SP,
+          mp_size_t N, mp_limb_t D)
+     Divide {SP, N} by D, expecting it to divide exactly, and writing
+     the result to {RP, N}.  If D doesn't divide exactly, the value
+     written to {RP, N} is undefined.  The areas at RP and SP have to be
+     identical or completely separate, not partially overlapping.
+
+ -- Macro: mp_limb_t mpn_divexact_by3 (mp_limb_t *RP, mp_limb_t *SP,
+          mp_size_t N)
+ -- Function: mp_limb_t mpn_divexact_by3c (mp_limb_t *RP, mp_limb_t *SP,
+          mp_size_t N, mp_limb_t CARRY)
+     Divide {SP, N} by 3, expecting it to divide exactly, and writing
+     the result to {RP, N}.  If 3 divides exactly, the return value is
+     zero and the result is the quotient.  If not, the return value is
+     non-zero and the result won't be anything useful.
+
+     'mpn_divexact_by3c' takes an initial carry parameter, which can be
+     the return value from a previous call, so a large calculation can
+     be done piece by piece from low to high.  'mpn_divexact_by3' is
+     simply a macro calling 'mpn_divexact_by3c' with a 0 carry
+     parameter.
+
+     These routines use a multiply-by-inverse and will be faster than
+     'mpn_divrem_1' on CPUs with fast multiplication but slow division.
+
+     The source a, result q, size n, initial carry i, and return value c
+     satisfy c*b^n + a-i = 3*q, where b=2^GMP_NUMB_BITS. The return c is
+     always 0, 1 or 2, and the initial carry i must also be 0, 1 or 2
+     (these are both borrows really).  When c=0 clearly q=(a-i)/3.  When
+     c!=0, the remainder (a-i) mod 3 is given by 3-c, because b == 1 mod
+     3 (when 'mp_bits_per_limb' is even, which is always so currently).
+
+ -- Function: mp_limb_t mpn_mod_1 (const mp_limb_t *S1P, mp_size_t S1N,
+          mp_limb_t S2LIMB)
+     Divide {S1P, S1N} by S2LIMB, and return the remainder.  S1N can be
+     zero.
+
+ -- Function: mp_limb_t mpn_lshift (mp_limb_t *RP, const mp_limb_t *SP,
+          mp_size_t N, unsigned int COUNT)
+     Shift {SP, N} left by COUNT bits, and write the result to {RP, N}.
+     The bits shifted out at the left are returned in the least
+     significant COUNT bits of the return value (the rest of the return
+     value is zero).
+
+     COUNT must be in the range 1 to mp_bits_per_limb-1.  The regions
+     {SP, N} and {RP, N} may overlap, provided RP >= SP.
+
+     This function is written in assembly for most CPUs.
+
+ -- Function: mp_limb_t mpn_rshift (mp_limb_t *RP, const mp_limb_t *SP,
+          mp_size_t N, unsigned int COUNT)
+     Shift {SP, N} right by COUNT bits, and write the result to {RP, N}.
+     The bits shifted out at the right are returned in the most
+     significant COUNT bits of the return value (the rest of the return
+     value is zero).
+
+     COUNT must be in the range 1 to mp_bits_per_limb-1.  The regions
+     {SP, N} and {RP, N} may overlap, provided RP <= SP.
+
+     This function is written in assembly for most CPUs.
+
+ -- Function: int mpn_cmp (const mp_limb_t *S1P, const mp_limb_t *S2P,
+          mp_size_t N)
+     Compare {S1P, N} and {S2P, N} and return a positive value if S1 >
+     S2, 0 if they are equal, or a negative value if S1 < S2.
+
+ -- Function: int mpn_zero_p (const mp_limb_t *SP, mp_size_t N)
+     Test {SP, N} and return 1 if the operand is zero, 0 otherwise.
+
+ -- Function: mp_size_t mpn_gcd (mp_limb_t *RP, mp_limb_t *XP, mp_size_t
+          XN, mp_limb_t *YP, mp_size_t YN)
+     Set {RP, RETVAL} to the greatest common divisor of {XP, XN} and
+     {YP, YN}.  The result can be up to YN limbs, the return value is
+     the actual number produced.  Both source operands are destroyed.
+
+     It is required that XN >= YN > 0, the most significant limb of {YP,
+     YN} must be non-zero, and at least one of the two operands must be
+     odd.  No overlap is permitted between {XP, XN} and {YP, YN}.
+
+ -- Function: mp_limb_t mpn_gcd_1 (const mp_limb_t *XP, mp_size_t XN,
+          mp_limb_t YLIMB)
+     Return the greatest common divisor of {XP, XN} and YLIMB.  Both
+     operands must be non-zero.
+
+ -- Function: mp_size_t mpn_gcdext (mp_limb_t *GP, mp_limb_t *SP,
+          mp_size_t *SN, mp_limb_t *UP, mp_size_t UN, mp_limb_t *VP,
+          mp_size_t VN)
+     Let U be defined by {UP, UN} and let V be defined by {VP, VN}.
+
+     Compute the greatest common divisor G of U and V. Compute a
+     cofactor S such that G = US + VT. The second cofactor T is not
+     computed but can easily be obtained from (G - U*S) / V (the
+     division will be exact).  It is required that UN >= VN > 0, and the
+     most significant limb of {VP, VN} must be non-zero.
+
+     S satisfies S = 1 or abs(S) < V / (2 G). S = 0 if and only if V
+     divides U (i.e., G = V).
+
+     Store G at GP and let the return value define its limb count.
+     Store S at SP and let |*SN| define its limb count.  S can be
+     negative; when this happens *SN will be negative.  The area at GP
+     should have room for VN limbs and the area at SP should have room
+     for VN+1 limbs.
+
+     Both source operands are destroyed.
+
+     Compatibility notes: GMP 4.3.0 and 4.3.1 defined S less strictly.
+     Earlier as well as later GMP releases define S as described here.
+     GMP releases before GMP 4.3.0 required additional space for both
+     input and output areas.  More precisely, the areas {UP, UN+1} and
+     {VP, VN+1} were destroyed (i.e. the operands plus an extra limb
+     past the end of each), and the areas pointed to by GP and SP should
+     each have room for UN+1 limbs.
+
+ -- Function: mp_size_t mpn_sqrtrem (mp_limb_t *R1P, mp_limb_t *R2P,
+          const mp_limb_t *SP, mp_size_t N)
+     Compute the square root of {SP, N} and put the result at {R1P,
+     ceil(N/2)} and the remainder at {R2P, RETVAL}.  R2P needs space for
+     N limbs, but the return value indicates how many are produced.
+
+     The most significant limb of {SP, N} must be non-zero.  The areas
+     {R1P, ceil(N/2)} and {SP, N} must be completely separate.  The
+     areas {R2P, N} and {SP, N} must be either identical or completely
+     separate.
+
+     If the remainder is not wanted then R2P can be 'NULL', and in this
+     case the return value is zero or non-zero according to whether the
+     remainder would have been zero or non-zero.
+
+     A return value of zero indicates a perfect square.  See also
+     'mpn_perfect_square_p'.
+
+ -- Function: size_t mpn_sizeinbase (const mp_limb_t *XP, mp_size_t N,
+          int BASE)
+     Return the size of {XP,N} measured in number of digits in the given
+     BASE.  BASE can vary from 2 to 62.  Requires N > 0 and XP[N-1] > 0.
+     The result will be either exact or 1 too big.  If BASE is a power
+     of 2, the result is always exact.
+
+ -- Function: mp_size_t mpn_get_str (unsigned char *STR, int BASE,
+          mp_limb_t *S1P, mp_size_t S1N)
+     Convert {S1P, S1N} to a raw unsigned char array at STR in base
+     BASE, and return the number of characters produced.  There may be
+     leading zeros in the string.  The string is not in ASCII; to
+     convert it to printable format, add the ASCII codes for '0' or 'A',
+     depending on the base and range.  BASE can vary from 2 to 256.
+
+     The most significant limb of the input {S1P, S1N} must be non-zero.
+     The input {S1P, S1N} is clobbered, except when BASE is a power of
+     2, in which case it's unchanged.
+
+     The area at STR has to have space for the largest possible number
+     represented by a S1N long limb array, plus one extra character.
+
+ -- Function: mp_size_t mpn_set_str (mp_limb_t *RP, const unsigned char
+          *STR, size_t STRSIZE, int BASE)
+     Convert bytes {STR,STRSIZE} in the given BASE to limbs at RP.
+
+     STR[0] is the most significant input byte and STR[STRSIZE-1] is the
+     least significant input byte.  Each byte should be a value in the
+     range 0 to BASE-1, not an ASCII character.  BASE can vary from 2 to
+     256.
+
+     The converted value is {RP,RN} where RN is the return value.  If
+     the most significant input byte STR[0] is non-zero, then RP[RN-1]
+     will be non-zero, else RP[RN-1] and some number of subsequent limbs
+     may be zero.
+
+     The area at RP has to have space for the largest possible number
+     with STRSIZE digits in the chosen base, plus one extra limb.
+
+     The input must have at least one byte, and no overlap is permitted
+     between {STR,STRSIZE} and the result at RP.
+
+ -- Function: mp_bitcnt_t mpn_scan0 (const mp_limb_t *S1P, mp_bitcnt_t
+          BIT)
+     Scan S1P from bit position BIT for the next clear bit.
+
+     It is required that there be a clear bit within the area at S1P at
+     or beyond bit position BIT, so that the function has something to
+     return.
+
+ -- Function: mp_bitcnt_t mpn_scan1 (const mp_limb_t *S1P, mp_bitcnt_t
+          BIT)
+     Scan S1P from bit position BIT for the next set bit.
+
+     It is required that there be a set bit within the area at S1P at or
+     beyond bit position BIT, so that the function has something to
+     return.
+
+ -- Function: void mpn_random (mp_limb_t *R1P, mp_size_t R1N)
+ -- Function: void mpn_random2 (mp_limb_t *R1P, mp_size_t R1N)
+     Generate a random number of length R1N and store it at R1P.  The
+     most significant limb is always non-zero.  'mpn_random' generates
+     uniformly distributed limb data, 'mpn_random2' generates long
+     strings of zeros and ones in the binary representation.
+
+     'mpn_random2' is intended for testing the correctness of the 'mpn'
+     routines.
+
+ -- Function: mp_bitcnt_t mpn_popcount (const mp_limb_t *S1P, mp_size_t
+          N)
+     Count the number of set bits in {S1P, N}.
+
+ -- Function: mp_bitcnt_t mpn_hamdist (const mp_limb_t *S1P, const
+          mp_limb_t *S2P, mp_size_t N)
+     Compute the hamming distance between {S1P, N} and {S2P, N}, which
+     is the number of bit positions where the two operands have
+     different bit values.
+
+ -- Function: int mpn_perfect_square_p (const mp_limb_t *S1P, mp_size_t
+          N)
+     Return non-zero iff {S1P, N} is a perfect square.  The most
+     significant limb of the input {S1P, N} must be non-zero.
+
+ -- Function: void mpn_and_n (mp_limb_t *RP, const mp_limb_t *S1P, const
+          mp_limb_t *S2P, mp_size_t N)
+     Perform the bitwise logical and of {S1P, N} and {S2P, N}, and write
+     the result to {RP, N}.
+
+ -- Function: void mpn_ior_n (mp_limb_t *RP, const mp_limb_t *S1P, const
+          mp_limb_t *S2P, mp_size_t N)
+     Perform the bitwise logical inclusive or of {S1P, N} and {S2P, N},
+     and write the result to {RP, N}.
+
+ -- Function: void mpn_xor_n (mp_limb_t *RP, const mp_limb_t *S1P, const
+          mp_limb_t *S2P, mp_size_t N)
+     Perform the bitwise logical exclusive or of {S1P, N} and {S2P, N},
+     and write the result to {RP, N}.
+
+ -- Function: void mpn_andn_n (mp_limb_t *RP, const mp_limb_t *S1P,
+          const mp_limb_t *S2P, mp_size_t N)
+     Perform the bitwise logical and of {S1P, N} and the bitwise
+     complement of {S2P, N}, and write the result to {RP, N}.
+
+ -- Function: void mpn_iorn_n (mp_limb_t *RP, const mp_limb_t *S1P,
+          const mp_limb_t *S2P, mp_size_t N)
+     Perform the bitwise logical inclusive or of {S1P, N} and the
+     bitwise complement of {S2P, N}, and write the result to {RP, N}.
+
+ -- Function: void mpn_nand_n (mp_limb_t *RP, const mp_limb_t *S1P,
+          const mp_limb_t *S2P, mp_size_t N)
+     Perform the bitwise logical and of {S1P, N} and {S2P, N}, and write
+     the bitwise complement of the result to {RP, N}.
+
+ -- Function: void mpn_nior_n (mp_limb_t *RP, const mp_limb_t *S1P,
+          const mp_limb_t *S2P, mp_size_t N)
+     Perform the bitwise logical inclusive or of {S1P, N} and {S2P, N},
+     and write the bitwise complement of the result to {RP, N}.
+
+ -- Function: void mpn_xnor_n (mp_limb_t *RP, const mp_limb_t *S1P,
+          const mp_limb_t *S2P, mp_size_t N)
+     Perform the bitwise logical exclusive or of {S1P, N} and {S2P, N},
+     and write the bitwise complement of the result to {RP, N}.
+
+ -- Function: void mpn_com (mp_limb_t *RP, const mp_limb_t *SP,
+          mp_size_t N)
+     Perform the bitwise complement of {SP, N}, and write the result to
+     {RP, N}.
+
+ -- Function: void mpn_copyi (mp_limb_t *RP, const mp_limb_t *S1P,
+          mp_size_t N)
+     Copy from {S1P, N} to {RP, N}, increasingly.
+
+ -- Function: void mpn_copyd (mp_limb_t *RP, const mp_limb_t *S1P,
+          mp_size_t N)
+     Copy from {S1P, N} to {RP, N}, decreasingly.
+
+ -- Function: void mpn_zero (mp_limb_t *RP, mp_size_t N)
+     Zero {RP, N}.
+
+
+8.1 Low-level functions for cryptography
+========================================
+
+The functions prefixed with 'mpn_sec_' and 'mpn_cnd_' are designed to
+perform the exact same low-level operations and have the same cache
+access patterns for any two same-size arguments, assuming that function
+arguments are placed at the same position and that the machine state is
+identical upon function entry.  These functions are intended for
+cryptographic purposes, where resilience to side-channel attacks is
+desired.
+
+   These functions are less efficient than their "leaky" counterparts;
+their performance for operands of the sizes typically used for
+cryptographic applications is between 15% and 100% worse.  For larger
+operands, these functions might be inadequate, since they rely on
+asymptotically elementary algorithms.
+
+   These functions do not make any explicit allocations.  Those of these
+functions that need scratch space accept a scratch space operand.  This
+convention allows callers to keep sensitive data in designated memory
+areas.  Note however that compilers may choose to spill scalar values
+used within these functions to their stack frame and that such scalars
+may contain sensitive data.
+
+   In addition to these specially crafted functions, the following 'mpn'
+functions are naturally side-channel resistant: 'mpn_add_n',
+'mpn_sub_n', 'mpn_lshift', 'mpn_rshift', 'mpn_zero', 'mpn_copyi',
+'mpn_copyd', 'mpn_com', and the logical function ('mpn_and_n', etc).
+
+   There are some exceptions from the side-channel resilience: (1) Some
+assembly implementations of 'mpn_lshift' identify shift-by-one as a
+special case.  This is a problem iff the shift count is a function of
+sensitive data.  (2) Alpha ev6 and Pentium4 using 64-bit limbs have
+leaky 'mpn_add_n' and 'mpn_sub_n'.  (3) Alpha ev6 has a leaky
+'mpn_mul_1' which also makes 'mpn_sec_mul' on those systems unsafe.
+
+ -- Function: mp_limb_t mpn_cnd_add_n (mp_limb_t CND, mp_limb_t *RP,
+          const mp_limb_t *S1P, const mp_limb_t *S2P, mp_size_t N)
+ -- Function: mp_limb_t mpn_cnd_sub_n (mp_limb_t CND, mp_limb_t *RP,
+          const mp_limb_t *S1P, const mp_limb_t *S2P, mp_size_t N)
+     These functions do conditional addition and subtraction.  If CND is
+     non-zero, they produce the same result as a regular 'mpn_add_n' or
+     'mpn_sub_n', and if CND is zero, they copy {S1P,N} to the result
+     area and return zero.  The functions are designed to have timing
+     and memory access patterns depending only on size and location of
+     the data areas, but independent of the condition CND.  Like for
+     'mpn_add_n' and 'mpn_sub_n', on most machines, the timing will also
+     be independent of the actual limb values.
+
+ -- Function: mp_limb_t mpn_sec_add_1 (mp_limb_t *RP, const mp_limb_t
+          *AP, mp_size_t N, mp_limb_t B, mp_limb_t *TP)
+ -- Function: mp_limb_t mpn_sec_sub_1 (mp_limb_t *RP, const mp_limb_t
+          *AP, mp_size_t N, mp_limb_t B, mp_limb_t *TP)
+     Set R to A + B or A - B, respectively, where R = {RP,N}, A =
+     {AP,N}, and B is a single limb.  Returns carry.
+
+     These functions take O(N) time, unlike the leaky functions
+     'mpn_add_1' which are O(1) on average.  They require scratch space
+     of 'mpn_sec_add_1_itch(N)' and 'mpn_sec_sub_1_itch(N)' limbs,
+     respectively, to be passed in the TP parameter.  The scratch space
+     requirements are guaranteed to be at most N limbs, and increase
+     monotonously in the operand size.
+
+ -- Function: void mpn_cnd_swap (mp_limb_t CND, volatile mp_limb_t *AP,
+          volatile mp_limb_t *BP, mp_size_t N)
+     If CND is non-zero, swaps the contents of the areas {AP,N} and
+     {BP,N}.  Otherwise, the areas are left unmodified.  Implemented
+     using logical operations on the limbs, with the same memory
+     accesses independent of the value of CND.
+
+ -- Function: void mpn_sec_mul (mp_limb_t *RP, const mp_limb_t *AP,
+          mp_size_t AN, const mp_limb_t *BP, mp_size_t BN, mp_limb_t
+          *TP)
+ -- Function: mp_size_t mpn_sec_mul_itch (mp_size_t AN, mp_size_t BN)
+     Set R to A * B, where A = {AP,AN}, B = {BP,BN}, and R = {RP,AN+BN}.
+
+     It is required that AN >= BN > 0.
+
+     No overlapping between R and the input operands is allowed.  For A
+     = B, use 'mpn_sec_sqr' for optimal performance.
+
+     This function requires scratch space of 'mpn_sec_mul_itch(AN, BN)'
+     limbs to be passed in the TP parameter.  The scratch space
+     requirements are guaranteed to increase monotonously in the operand
+     sizes.
+
+ -- Function: void mpn_sec_sqr (mp_limb_t *RP, const mp_limb_t *AP,
+          mp_size_t AN, mp_limb_t *TP)
+ -- Function: mp_size_t mpn_sec_sqr_itch (mp_size_t AN)
+     Set R to A^2, where A = {AP,AN}, and R = {RP,2AN}.
+
+     It is required that AN > 0.
+
+     No overlapping between R and the input operands is allowed.
+
+     This function requires scratch space of 'mpn_sec_sqr_itch(AN)'
+     limbs to be passed in the TP parameter.  The scratch space
+     requirements are guaranteed to increase monotonously in the operand
+     size.
+
+ -- Function: void mpn_sec_powm (mp_limb_t *RP, const mp_limb_t *BP,
+          mp_size_t BN, const mp_limb_t *EP, mp_bitcnt_t ENB, const
+          mp_limb_t *MP, mp_size_t N, mp_limb_t *TP)
+ -- Function: mp_size_t mpn_sec_powm_itch (mp_size_t BN, mp_bitcnt_t
+          ENB, size_t N)
+     Set R to (B raised to E) modulo M, where R = {RP,N}, M = {MP,N},
+     and E = {EP,ceil(ENB / 'GMP\_NUMB\_BITS')}.
+
+     It is required that B > 0, that M > 0 is odd, and that E < 2^ENB,
+     with ENB > 0.
+
+     No overlapping between R and the input operands is allowed.
+
+     This function requires scratch space of 'mpn_sec_powm_itch(BN, ENB,
+     N)' limbs to be passed in the TP parameter.  The scratch space
+     requirements are guaranteed to increase monotonously in the operand
+     sizes.
+
+ -- Function: void mpn_sec_tabselect (mp_limb_t *RP, const mp_limb_t
+          *TAB, mp_size_t N, mp_size_t NENTS, mp_size_t WHICH)
+     Select entry WHICH from table TAB, which has NENTS entries, each N
+     limbs.  Store the selected entry at RP.
+
+     This function reads the entire table to avoid side-channel
+     information leaks.
+
+ -- Function: mp_limb_t mpn_sec_div_qr (mp_limb_t *QP, mp_limb_t *NP,
+          mp_size_t NN, const mp_limb_t *DP, mp_size_t DN, mp_limb_t
+          *TP)
+ -- Function: mp_size_t mpn_sec_div_qr_itch (mp_size_t NN, mp_size_t DN)
+
+     Set Q to the truncated quotient N / D and R to N modulo D, where N
+     = {NP,NN}, D = {DP,DN}, Q's most significant limb is the function
+     return value and the remaining limbs are {QP,NN-DN}, and R =
+     {NP,DN}.
+
+     It is required that NN >= DN >= 1, and that DP[DN-1] != 0.  This
+     does not imply that N >= D since N might be zero-padded.
+
+     Note the overlapping between N and R.  No other operand overlapping
+     is allowed.  The entire space occupied by N is overwritten.
+
+     This function requires scratch space of 'mpn_sec_div_qr_itch(NN,
+     DN)' limbs to be passed in the TP parameter.
+
+ -- Function: void mpn_sec_div_r (mp_limb_t *NP, mp_size_t NN, const
+          mp_limb_t *DP, mp_size_t DN, mp_limb_t *TP)
+ -- Function: mp_size_t mpn_sec_div_r_itch (mp_size_t NN, mp_size_t DN)
+
+     Set R to N modulo D, where N = {NP,NN}, D = {DP,DN}, and R =
+     {NP,DN}.
+
+     It is required that NN >= DN >= 1, and that DP[DN-1] != 0.  This
+     does not imply that N >= D since N might be zero-padded.
+
+     Note the overlapping between N and R.  No other operand overlapping
+     is allowed.  The entire space occupied by N is overwritten.
+
+     This function requires scratch space of 'mpn_sec_div_r_itch(NN,
+     DN)' limbs to be passed in the TP parameter.
+
+ -- Function: int mpn_sec_invert (mp_limb_t *RP, mp_limb_t *AP, const
+          mp_limb_t *MP, mp_size_t N, mp_bitcnt_t NBCNT, mp_limb_t *TP)
+ -- Function: mp_size_t mpn_sec_invert_itch (mp_size_t N)
+     Set R to the inverse of A modulo M, where R = {RP,N}, A = {AP,N},
+     and M = {MP,N}.  *This function's interface is preliminary.*
+
+     If an inverse exists, return 1, otherwise return 0 and leave R
+     undefined.  In either case, the input A is destroyed.
+
+     It is required that M is odd, and that NBCNT >= ceil(\log(A+1)) +
+     ceil(\log(M+1)).  A safe choice is NBCNT = 2 * N * GMP_NUMB_BITS,
+     but a smaller value might improve performance if M or A are known
+     to have leading zero bits.
+
+     This function requires scratch space of 'mpn_sec_invert_itch(N)'
+     limbs to be passed in the TP parameter.
+
+
+8.2 Nails
+=========
+
+*Everything in this section is highly experimental and may disappear or
+be subject to incompatible changes in a future version of GMP.*
+
+   Nails are an experimental feature whereby a few bits are left unused
+at the top of each 'mp_limb_t'.  This can significantly improve carry
+handling on some processors.
+
+   All the 'mpn' functions accepting limb data will expect the nail bits
+to be zero on entry, and will return data with the nails similarly all
+zero.  This applies both to limb vectors and to single limb arguments.
+
+   Nails can be enabled by configuring with '--enable-nails'.  By
+default the number of bits will be chosen according to what suits the
+host processor, but a particular number can be selected with
+'--enable-nails=N'.
+
+   At the mpn level, a nail build is neither source nor binary
+compatible with a non-nail build, strictly speaking.  But programs
+acting on limbs only through the mpn functions are likely to work
+equally well with either build, and judicious use of the definitions
+below should make any program compatible with either build, at the
+source level.
+
+   For the higher level routines, meaning 'mpz' etc, a nail build should
+be fully source and binary compatible with a non-nail build.
+
+ -- Macro: GMP_NAIL_BITS
+ -- Macro: GMP_NUMB_BITS
+ -- Macro: GMP_LIMB_BITS
+     'GMP_NAIL_BITS' is the number of nail bits, or 0 when nails are not
+     in use.  'GMP_NUMB_BITS' is the number of data bits in a limb.
+     'GMP_LIMB_BITS' is the total number of bits in an 'mp_limb_t'.  In
+     all cases
+
+          GMP_LIMB_BITS == GMP_NAIL_BITS + GMP_NUMB_BITS
+
+ -- Macro: GMP_NAIL_MASK
+ -- Macro: GMP_NUMB_MASK
+     Bit masks for the nail and number parts of a limb.  'GMP_NAIL_MASK'
+     is 0 when nails are not in use.
+
+     'GMP_NAIL_MASK' is not often needed, since the nail part can be
+     obtained with 'x >> GMP_NUMB_BITS', and that means one less large
+     constant, which can help various RISC chips.
+
+ -- Macro: GMP_NUMB_MAX
+     The maximum value that can be stored in the number part of a limb.
+     This is the same as 'GMP_NUMB_MASK', but can be used for clarity
+     when doing comparisons rather than bit-wise operations.
+
+   The term "nails" comes from finger or toe nails, which are at the
+ends of a limb (arm or leg).  "numb" is short for number, but is also
+how the developers felt after trying for a long time to come up with
+sensible names for these things.
+
+   In the future (the distant future most likely) a non-zero nail might
+be permitted, giving non-unique representations for numbers in a limb
+vector.  This would help vector processors since carries would only ever
+need to propagate one or two limbs.
+
+
+File: gmp.info,  Node: Random Number Functions,  Next: Formatted Output,  Prev: Low-level Functions,  Up: Top
+
+9 Random Number Functions
+*************************
+
+Sequences of pseudo-random numbers in GMP are generated using a variable
+of type 'gmp_randstate_t', which holds an algorithm selection and a
+current state.  Such a variable must be initialized by a call to one of
+the 'gmp_randinit' functions, and can be seeded with one of the
+'gmp_randseed' functions.
+
+   The functions actually generating random numbers are described in
+*note Integer Random Numbers::, and *note Miscellaneous Float
+Functions::.
+
+   The older style random number functions don't accept a
+'gmp_randstate_t' parameter but instead share a global variable of that
+type.  They use a default algorithm and are currently not seeded (though
+perhaps that will change in the future).  The new functions accepting a
+'gmp_randstate_t' are recommended for applications that care about
+randomness.
+
+* Menu:
+
+* Random State Initialization::
+* Random State Seeding::
+* Random State Miscellaneous::
+
+
+File: gmp.info,  Node: Random State Initialization,  Next: Random State Seeding,  Prev: Random Number Functions,  Up: Random Number Functions
+
+9.1 Random State Initialization
+===============================
+
+ -- Function: void gmp_randinit_default (gmp_randstate_t STATE)
+     Initialize STATE with a default algorithm.  This will be a
+     compromise between speed and randomness, and is recommended for
+     applications with no special requirements.  Currently this is
+     'gmp_randinit_mt'.
+
+ -- Function: void gmp_randinit_mt (gmp_randstate_t STATE)
+     Initialize STATE for a Mersenne Twister algorithm.  This algorithm
+     is fast and has good randomness properties.
+
+ -- Function: void gmp_randinit_lc_2exp (gmp_randstate_t STATE, const
+          mpz_t A, unsigned long C, mp_bitcnt_t M2EXP)
+     Initialize STATE with a linear congruential algorithm X = (A*X + C)
+     mod 2^M2EXP.
+
+     The low bits of X in this algorithm are not very random.  The least
+     significant bit will have a period no more than 2, and the second
+     bit no more than 4, etc.  For this reason only the high half of
+     each X is actually used.
+
+     When a random number of more than M2EXP/2 bits is to be generated,
+     multiple iterations of the recurrence are used and the results
+     concatenated.
+
+ -- Function: int gmp_randinit_lc_2exp_size (gmp_randstate_t STATE,
+          mp_bitcnt_t SIZE)
+     Initialize STATE for a linear congruential algorithm as per
+     'gmp_randinit_lc_2exp'.  A, C and M2EXP are selected from a table,
+     chosen so that SIZE bits (or more) of each X will be used, i.e.
+     M2EXP/2 >= SIZE.
+
+     If successful the return value is non-zero.  If SIZE is bigger than
+     the table data provides then the return value is zero.  The maximum
+     SIZE currently supported is 128.
+
+ -- Function: void gmp_randinit_set (gmp_randstate_t ROP,
+          gmp_randstate_t OP)
+     Initialize ROP with a copy of the algorithm and state from OP.
+
+ -- Function: void gmp_randinit (gmp_randstate_t STATE,
+          gmp_randalg_t ALG, ...)
+     *This function is obsolete.*
+
+     Initialize STATE with an algorithm selected by ALG.  The only
+     choice is 'GMP_RAND_ALG_LC', which is 'gmp_randinit_lc_2exp_size'
+     described above.  A third parameter of type 'unsigned long' is
+     required, this is the SIZE for that function.
+     'GMP_RAND_ALG_DEFAULT' or 0 are the same as 'GMP_RAND_ALG_LC'.
+
+     'gmp_randinit' sets bits in the global variable 'gmp_errno' to
+     indicate an error.  'GMP_ERROR_UNSUPPORTED_ARGUMENT' if ALG is
+     unsupported, or 'GMP_ERROR_INVALID_ARGUMENT' if the SIZE parameter
+     is too big.  It may be noted this error reporting is not thread
+     safe (a good reason to use 'gmp_randinit_lc_2exp_size' instead).
+
+ -- Function: void gmp_randclear (gmp_randstate_t STATE)
+     Free all memory occupied by STATE.
+
+
+File: gmp.info,  Node: Random State Seeding,  Next: Random State Miscellaneous,  Prev: Random State Initialization,  Up: Random Number Functions
+
+9.2 Random State Seeding
+========================
+
+ -- Function: void gmp_randseed (gmp_randstate_t STATE, const mpz_t
+          SEED)
+ -- Function: void gmp_randseed_ui (gmp_randstate_t STATE,
+          unsigned long int SEED)
+     Set an initial seed value into STATE.
+
+     The size of a seed determines how many different sequences of
+     random numbers that it's possible to generate.  The "quality" of
+     the seed is the randomness of a given seed compared to the previous
+     seed used, and this affects the randomness of separate number
+     sequences.  The method for choosing a seed is critical if the
+     generated numbers are to be used for important applications, such
+     as generating cryptographic keys.
+
+     Traditionally the system time has been used to seed, but care needs
+     to be taken with this.  If an application seeds often and the
+     resolution of the system clock is low, then the same sequence of
+     numbers might be repeated.  Also, the system time is quite easy to
+     guess, so if unpredictability is required then it should definitely
+     not be the only source for the seed value.  On some systems there's
+     a special device '/dev/random' which provides random data better
+     suited for use as a seed.
+
+
+File: gmp.info,  Node: Random State Miscellaneous,  Prev: Random State Seeding,  Up: Random Number Functions
+
+9.3 Random State Miscellaneous
+==============================
+
+ -- Function: unsigned long gmp_urandomb_ui (gmp_randstate_t STATE,
+          unsigned long N)
+     Return a uniformly distributed random number of N bits, i.e. in the
+     range 0 to 2^N-1 inclusive.  N must be less than or equal to the
+     number of bits in an 'unsigned long'.
+
+ -- Function: unsigned long gmp_urandomm_ui (gmp_randstate_t STATE,
+          unsigned long N)
+     Return a uniformly distributed random number in the range 0 to N-1,
+     inclusive.
+
+
+File: gmp.info,  Node: Formatted Output,  Next: Formatted Input,  Prev: Random Number Functions,  Up: Top
+
+10 Formatted Output
+*******************
+
+* Menu:
+
+* Formatted Output Strings::
+* Formatted Output Functions::
+* C++ Formatted Output::
+
+
+File: gmp.info,  Node: Formatted Output Strings,  Next: Formatted Output Functions,  Prev: Formatted Output,  Up: Formatted Output
+
+10.1 Format Strings
+===================
+
+'gmp_printf' and friends accept format strings similar to the standard C
+'printf' (*note Formatted Output: (libc)Formatted Output.).  A format
+specification is of the form
+
+     % [flags] [width] [.[precision]] [type] conv
+
+   GMP adds types 'Z', 'Q' and 'F' for 'mpz_t', 'mpq_t' and 'mpf_t'
+respectively, 'M' for 'mp_limb_t', and 'N' for an 'mp_limb_t' array.
+'Z', 'Q', 'M' and 'N' behave like integers.  'Q' will print a '/' and a
+denominator, if needed.  'F' behaves like a float.  For example,
+
+     mpz_t z;
+     gmp_printf ("%s is an mpz %Zd\n", "here", z);
+
+     mpq_t q;
+     gmp_printf ("a hex rational: %#40Qx\n", q);
+
+     mpf_t f;
+     int   n;
+     gmp_printf ("fixed point mpf %.*Ff with %d digits\n", n, f, n);
+
+     mp_limb_t l;
+     gmp_printf ("limb %Mu\n", l);
+
+     const mp_limb_t *ptr;
+     mp_size_t       size;
+     gmp_printf ("limb array %Nx\n", ptr, size);
+
+   For 'N' the limbs are expected least significant first, as per the
+'mpn' functions (*note Low-level Functions::).  A negative size can be
+given to print the value as a negative.
+
+   All the standard C 'printf' types behave the same as the C library
+'printf', and can be freely intermixed with the GMP extensions.  In the
+current implementation the standard parts of the format string are
+simply handed to 'printf' and only the GMP extensions handled directly.
+
+   The flags accepted are as follows.  GLIBC style ' is only for the
+standard C types (not the GMP types), and only if the C library supports
+it.
+
+     0         pad with zeros (rather than spaces)
+     #         show the base with '0x', '0X' or '0'
+     +         always show a sign
+     (space)   show a space or a '-' sign
+     '         group digits, GLIBC style (not GMP
+               types)
+
+   The optional width and precision can be given as a number within the
+format string, or as a '*' to take an extra parameter of type 'int', the
+same as the standard 'printf'.
+
+   The standard types accepted are as follows.  'h' and 'l' are
+portable, the rest will depend on the compiler (or include files) for
+the type and the C library for the output.
+
+     h         short
+     hh        char
+     j         intmax_t or uintmax_t
+     l         long or wchar_t
+     ll        long long
+     L         long double
+     q         quad_t or u_quad_t
+     t         ptrdiff_t
+     z         size_t
+
+The GMP types are
+
+     F         mpf_t, float conversions
+     Q         mpq_t, integer conversions
+     M         mp_limb_t, integer conversions
+     N         mp_limb_t array, integer conversions
+     Z         mpz_t, integer conversions
+
+   The conversions accepted are as follows.  'a' and 'A' are always
+supported for 'mpf_t' but depend on the C library for standard C float
+types.  'm' and 'p' depend on the C library.
+
+     a A       hex floats, C99 style
+     c         character
+     d         decimal integer
+     e E       scientific format float
+     f         fixed point float
+     i         same as d
+     g G       fixed or scientific float
+     m         'strerror' string, GLIBC style
+     n         store characters written so far
+     o         octal integer
+     p         pointer
+     s         string
+     u         unsigned integer
+     x X       hex integer
+
+   'o', 'x' and 'X' are unsigned for the standard C types, but for types
+'Z', 'Q' and 'N' they are signed.  'u' is not meaningful for 'Z', 'Q'
+and 'N'.
+
+   'M' is a proxy for the C library 'l' or 'L', according to the size of
+'mp_limb_t'.  Unsigned conversions will be usual, but a signed
+conversion can be used and will interpret the value as a twos complement
+negative.
+
+   'n' can be used with any type, even the GMP types.
+
+   Other types or conversions that might be accepted by the C library
+'printf' cannot be used through 'gmp_printf', this includes for instance
+extensions registered with GLIBC 'register_printf_function'.  Also
+currently there's no support for POSIX '$' style numbered arguments
+(perhaps this will be added in the future).
+
+   The precision field has its usual meaning for integer 'Z' and float
+'F' types, but is currently undefined for 'Q' and should not be used
+with that.
+
+   'mpf_t' conversions only ever generate as many digits as can be
+accurately represented by the operand, the same as 'mpf_get_str' does.
+Zeros will be used if necessary to pad to the requested precision.  This
+happens even for an 'f' conversion of an 'mpf_t' which is an integer,
+for instance 2^1024 in an 'mpf_t' of 128 bits precision will only
+produce about 40 digits, then pad with zeros to the decimal point.  An
+empty precision field like '%.Fe' or '%.Ff' can be used to specifically
+request just the significant digits.  Without any dot and thus no
+precision field, a precision value of 6 will be used.  Note that these
+rules mean that '%Ff', '%.Ff', and '%.0Ff' will all be different.
+
+   The decimal point character (or string) is taken from the current
+locale settings on systems which provide 'localeconv' (*note Locales and
+Internationalization: (libc)Locales.).  The C library will normally do
+the same for standard float output.
+
+   The format string is only interpreted as plain 'char's, multibyte
+characters are not recognised.  Perhaps this will change in the future.
+
+
+File: gmp.info,  Node: Formatted Output Functions,  Next: C++ Formatted Output,  Prev: Formatted Output Strings,  Up: Formatted Output
+
+10.2 Functions
+==============
+
+Each of the following functions is similar to the corresponding C
+library function.  The basic 'printf' forms take a variable argument
+list.  The 'vprintf' forms take an argument pointer, see *note Variadic
+Functions: (libc)Variadic Functions, or 'man 3 va_start'.
+
+   It should be emphasised that if a format string is invalid, or the
+arguments don't match what the format specifies, then the behaviour of
+any of these functions will be unpredictable.  GCC format string
+checking is not available, since it doesn't recognise the GMP
+extensions.
+
+   The file based functions 'gmp_printf' and 'gmp_fprintf' will return
+-1 to indicate a write error.  Output is not "atomic", so partial output
+may be produced if a write error occurs.  All the functions can return
+-1 if the C library 'printf' variant in use returns -1, but this
+shouldn't normally occur.
+
+ -- Function: int gmp_printf (const char *FMT, ...)
+ -- Function: int gmp_vprintf (const char *FMT, va_list AP)
+     Print to the standard output 'stdout'.  Return the number of
+     characters written, or -1 if an error occurred.
+
+ -- Function: int gmp_fprintf (FILE *FP, const char *FMT, ...)
+ -- Function: int gmp_vfprintf (FILE *FP, const char *FMT, va_list AP)
+     Print to the stream FP.  Return the number of characters written,
+     or -1 if an error occurred.
+
+ -- Function: int gmp_sprintf (char *BUF, const char *FMT, ...)
+ -- Function: int gmp_vsprintf (char *BUF, const char *FMT, va_list AP)
+     Form a null-terminated string in BUF.  Return the number of
+     characters written, excluding the terminating null.
+
+     No overlap is permitted between the space at BUF and the string
+     FMT.
+
+     These functions are not recommended, since there's no protection
+     against exceeding the space available at BUF.
+
+ -- Function: int gmp_snprintf (char *BUF, size_t SIZE, const char *FMT,
+          ...)
+ -- Function: int gmp_vsnprintf (char *BUF, size_t SIZE, const char
+          *FMT, va_list AP)
+     Form a null-terminated string in BUF.  No more than SIZE bytes will
+     be written.  To get the full output, SIZE must be enough for the
+     string and null-terminator.
+
+     The return value is the total number of characters which ought to
+     have been produced, excluding the terminating null.  If RETVAL >=
+     SIZE then the actual output has been truncated to the first SIZE-1
+     characters, and a null appended.
+
+     No overlap is permitted between the region {BUF,SIZE} and the FMT
+     string.
+
+     Notice the return value is in ISO C99 'snprintf' style.  This is so
+     even if the C library 'vsnprintf' is the older GLIBC 2.0.x style.
+
+ -- Function: int gmp_asprintf (char **PP, const char *FMT, ...)
+ -- Function: int gmp_vasprintf (char **PP, const char *FMT, va_list AP)
+     Form a null-terminated string in a block of memory obtained from
+     the current memory allocation function (*note Custom Allocation::).
+     The block will be the size of the string and null-terminator.  The
+     address of the block in stored to *PP.  The return value is the
+     number of characters produced, excluding the null-terminator.
+
+     Unlike the C library 'asprintf', 'gmp_asprintf' doesn't return -1
+     if there's no more memory available, it lets the current allocation
+     function handle that.
+
+ -- Function: int gmp_obstack_printf (struct obstack *OB, const char
+          *FMT, ...)
+ -- Function: int gmp_obstack_vprintf (struct obstack *OB, const char
+          *FMT, va_list AP)
+     Append to the current object in OB.  The return value is the number
+     of characters written.  A null-terminator is not written.
+
+     FMT cannot be within the current object in OB, since that object
+     might move as it grows.
+
+     These functions are available only when the C library provides the
+     obstack feature, which probably means only on GNU systems, see
+     *note Obstacks: (libc)Obstacks.
+
+
+File: gmp.info,  Node: C++ Formatted Output,  Prev: Formatted Output Functions,  Up: Formatted Output
+
+10.3 C++ Formatted Output
+=========================
+
+The following functions are provided in 'libgmpxx' (*note Headers and
+Libraries::), which is built if C++ support is enabled (*note Build
+Options::).  Prototypes are available from '<gmp.h>'.
+
+ -- Function: ostream& operator<< (ostream& STREAM, const mpz_t OP)
+     Print OP to STREAM, using its 'ios' formatting settings.
+     'ios::width' is reset to 0 after output, the same as the standard
+     'ostream operator<<' routines do.
+
+     In hex or octal, OP is printed as a signed number, the same as for
+     decimal.  This is unlike the standard 'operator<<' routines on
+     'int' etc, which instead give twos complement.
+
+ -- Function: ostream& operator<< (ostream& STREAM, const mpq_t OP)
+     Print OP to STREAM, using its 'ios' formatting settings.
+     'ios::width' is reset to 0 after output, the same as the standard
+     'ostream operator<<' routines do.
+
+     Output will be a fraction like '5/9', or if the denominator is 1
+     then just a plain integer like '123'.
+
+     In hex or octal, OP is printed as a signed value, the same as for
+     decimal.  If 'ios::showbase' is set then a base indicator is shown
+     on both the numerator and denominator (if the denominator is
+     required).
+
+ -- Function: ostream& operator<< (ostream& STREAM, const mpf_t OP)
+     Print OP to STREAM, using its 'ios' formatting settings.
+     'ios::width' is reset to 0 after output, the same as the standard
+     'ostream operator<<' routines do.
+
+     The decimal point follows the standard library float 'operator<<',
+     which on recent systems means the 'std::locale' imbued on STREAM.
+
+     Hex and octal are supported, unlike the standard 'operator<<' on
+     'double'.  The mantissa will be in hex or octal, the exponent will
+     be in decimal.  For hex the exponent delimiter is an '@'.  This is
+     as per 'mpf_out_str'.
+
+     'ios::showbase' is supported, and will put a base on the mantissa,
+     for example hex '0x1.8' or '0x0.8', or octal '01.4' or '00.4'.
+     This last form is slightly strange, but at least differentiates
+     itself from decimal.
+
+   These operators mean that GMP types can be printed in the usual C++
+way, for example,
+
+     mpz_t  z;
+     int    n;
+     ...
+     cout << "iteration " << n << " value " << z << "\n";
+
+   But note that 'ostream' output (and 'istream' input, *note C++
+Formatted Input::) is the only overloading available for the GMP types
+and that for instance using '+' with an 'mpz_t' will have unpredictable
+results.  For classes with overloading, see *note C++ Class Interface::.
+
+
+File: gmp.info,  Node: Formatted Input,  Next: C++ Class Interface,  Prev: Formatted Output,  Up: Top
+
+11 Formatted Input
+******************
+
+* Menu:
+
+* Formatted Input Strings::
+* Formatted Input Functions::
+* C++ Formatted Input::
+
+
+File: gmp.info,  Node: Formatted Input Strings,  Next: Formatted Input Functions,  Prev: Formatted Input,  Up: Formatted Input
+
+11.1 Formatted Input Strings
+============================
+
+'gmp_scanf' and friends accept format strings similar to the standard C
+'scanf' (*note Formatted Input: (libc)Formatted Input.).  A format
+specification is of the form
+
+     % [flags] [width] [type] conv
+
+   GMP adds types 'Z', 'Q' and 'F' for 'mpz_t', 'mpq_t' and 'mpf_t'
+respectively.  'Z' and 'Q' behave like integers.  'Q' will read a '/'
+and a denominator, if present.  'F' behaves like a float.
+
+   GMP variables don't require an '&' when passed to 'gmp_scanf', since
+they're already "call-by-reference".  For example,
+
+     /* to read say "a(5) = 1234" */
+     int   n;
+     mpz_t z;
+     gmp_scanf ("a(%d) = %Zd\n", &n, z);
+
+     mpq_t q1, q2;
+     gmp_sscanf ("0377 + 0x10/0x11", "%Qi + %Qi", q1, q2);
+
+     /* to read say "topleft (1.55,-2.66)" */
+     mpf_t x, y;
+     char  buf[32];
+     gmp_scanf ("%31s (%Ff,%Ff)", buf, x, y);
+
+   All the standard C 'scanf' types behave the same as in the C library
+'scanf', and can be freely intermixed with the GMP extensions.  In the
+current implementation the standard parts of the format string are
+simply handed to 'scanf' and only the GMP extensions handled directly.
+
+   The flags accepted are as follows.  'a' and ''' will depend on
+support from the C library, and ''' cannot be used with GMP types.
+
+     *         read but don't store
+     a         allocate a buffer (string conversions)
+     '         grouped digits, GLIBC style (not GMP
+               types)
+
+   The standard types accepted are as follows.  'h' and 'l' are
+portable, the rest will depend on the compiler (or include files) for
+the type and the C library for the input.
+
+     h         short
+     hh        char
+     j         intmax_t or uintmax_t
+     l         long int, double or wchar_t
+     ll        long long
+     L         long double
+     q         quad_t or u_quad_t
+     t         ptrdiff_t
+     z         size_t
+
+The GMP types are
+
+     F         mpf_t, float conversions
+     Q         mpq_t, integer conversions
+     Z         mpz_t, integer conversions
+
+   The conversions accepted are as follows.  'p' and '[' will depend on
+support from the C library, the rest are standard.
+
+     c         character or characters
+     d         decimal integer
+     e E f g   float
+     G
+     i         integer with base indicator
+     n         characters read so far
+     o         octal integer
+     p         pointer
+     s         string of non-whitespace characters
+     u         decimal integer
+     x X       hex integer
+     [         string of characters in a set
+
+   'e', 'E', 'f', 'g' and 'G' are identical, they all read either fixed
+point or scientific format, and either upper or lower case 'e' for the
+exponent in scientific format.
+
+   C99 style hex float format ('printf %a', *note Formatted Output
+Strings::) is always accepted for 'mpf_t', but for the standard float
+types it will depend on the C library.
+
+   'x' and 'X' are identical, both accept both upper and lower case
+hexadecimal.
+
+   'o', 'u', 'x' and 'X' all read positive or negative values.  For the
+standard C types these are described as "unsigned" conversions, but that
+merely affects certain overflow handling, negatives are still allowed
+(per 'strtoul', *note Parsing of Integers: (libc)Parsing of Integers.).
+For GMP types there are no overflows, so 'd' and 'u' are identical.
+
+   'Q' type reads the numerator and (optional) denominator as given.  If
+the value might not be in canonical form then 'mpq_canonicalize' must be
+called before using it in any calculations (*note Rational Number
+Functions::).
+
+   'Qi' will read a base specification separately for the numerator and
+denominator.  For example '0x10/11' would be 16/11, whereas '0x10/0x11'
+would be 16/17.
+
+   'n' can be used with any of the types above, even the GMP types.  '*'
+to suppress assignment is allowed, though in that case it would do
+nothing at all.
+
+   Other conversions or types that might be accepted by the C library
+'scanf' cannot be used through 'gmp_scanf'.
+
+   Whitespace is read and discarded before a field, except for 'c' and
+'[' conversions.
+
+   For float conversions, the decimal point character (or string)
+expected is taken from the current locale settings on systems which
+provide 'localeconv' (*note Locales and Internationalization:
+(libc)Locales.).  The C library will normally do the same for standard
+float input.
+
+   The format string is only interpreted as plain 'char's, multibyte
+characters are not recognised.  Perhaps this will change in the future.
+
+
+File: gmp.info,  Node: Formatted Input Functions,  Next: C++ Formatted Input,  Prev: Formatted Input Strings,  Up: Formatted Input
+
+11.2 Formatted Input Functions
+==============================
+
+Each of the following functions is similar to the corresponding C
+library function.  The plain 'scanf' forms take a variable argument
+list.  The 'vscanf' forms take an argument pointer, see *note Variadic
+Functions: (libc)Variadic Functions, or 'man 3 va_start'.
+
+   It should be emphasised that if a format string is invalid, or the
+arguments don't match what the format specifies, then the behaviour of
+any of these functions will be unpredictable.  GCC format string
+checking is not available, since it doesn't recognise the GMP
+extensions.
+
+   No overlap is permitted between the FMT string and any of the results
+produced.
+
+ -- Function: int gmp_scanf (const char *FMT, ...)
+ -- Function: int gmp_vscanf (const char *FMT, va_list AP)
+     Read from the standard input 'stdin'.
+
+ -- Function: int gmp_fscanf (FILE *FP, const char *FMT, ...)
+ -- Function: int gmp_vfscanf (FILE *FP, const char *FMT, va_list AP)
+     Read from the stream FP.
+
+ -- Function: int gmp_sscanf (const char *S, const char *FMT, ...)
+ -- Function: int gmp_vsscanf (const char *S, const char *FMT, va_list
+          AP)
+     Read from a null-terminated string S.
+
+   The return value from each of these functions is the same as the
+standard C99 'scanf', namely the number of fields successfully parsed
+and stored.  '%n' fields and fields read but suppressed by '*' don't
+count towards the return value.
+
+   If end of input (or a file error) is reached before a character for a
+field or a literal, and if no previous non-suppressed fields have
+matched, then the return value is 'EOF' instead of 0.  A whitespace
+character in the format string is only an optional match and doesn't
+induce an 'EOF' in this fashion.  Leading whitespace read and discarded
+for a field don't count as characters for that field.
+
+   For the GMP types, input parsing follows C99 rules, namely one
+character of lookahead is used and characters are read while they
+continue to meet the format requirements.  If this doesn't provide a
+complete number then the function terminates, with that field not stored
+nor counted towards the return value.  For instance with 'mpf_t' an
+input '1.23e-XYZ' would be read up to the 'X' and that character pushed
+back since it's not a digit.  The string '1.23e-' would then be
+considered invalid since an 'e' must be followed by at least one digit.
+
+   For the standard C types, in the current implementation GMP calls the
+C library 'scanf' functions, which might have looser rules about what
+constitutes a valid input.
+
+   Note that 'gmp_sscanf' is the same as 'gmp_fscanf' and only does one
+character of lookahead when parsing.  Although clearly it could look at
+its entire input, it is deliberately made identical to 'gmp_fscanf', the
+same way C99 'sscanf' is the same as 'fscanf'.
+
+
+File: gmp.info,  Node: C++ Formatted Input,  Prev: Formatted Input Functions,  Up: Formatted Input
+
+11.3 C++ Formatted Input
+========================
+
+The following functions are provided in 'libgmpxx' (*note Headers and
+Libraries::), which is built only if C++ support is enabled (*note Build
+Options::).  Prototypes are available from '<gmp.h>'.
+
+ -- Function: istream& operator>> (istream& STREAM, mpz_t ROP)
+     Read ROP from STREAM, using its 'ios' formatting settings.
+
+ -- Function: istream& operator>> (istream& STREAM, mpq_t ROP)
+     An integer like '123' will be read, or a fraction like '5/9'.  No
+     whitespace is allowed around the '/'.  If the fraction is not in
+     canonical form then 'mpq_canonicalize' must be called (*note
+     Rational Number Functions::) before operating on it.
+
+     As per integer input, an '0' or '0x' base indicator is read when
+     none of 'ios::dec', 'ios::oct' or 'ios::hex' are set.  This is done
+     separately for numerator and denominator, so that for instance
+     '0x10/11' is 16/11 and '0x10/0x11' is 16/17.
+
+ -- Function: istream& operator>> (istream& STREAM, mpf_t ROP)
+     Read ROP from STREAM, using its 'ios' formatting settings.
+
+     Hex or octal floats are not supported, but might be in the future,
+     or perhaps it's best to accept only what the standard float
+     'operator>>' does.
+
+   Note that digit grouping specified by the 'istream' locale is
+currently not accepted.  Perhaps this will change in the future.
+
+
+   These operators mean that GMP types can be read in the usual C++ way,
+for example,
+
+     mpz_t  z;
+     ...
+     cin >> z;
+
+   But note that 'istream' input (and 'ostream' output, *note C++
+Formatted Output::) is the only overloading available for the GMP types
+and that for instance using '+' with an 'mpz_t' will have unpredictable
+results.  For classes with overloading, see *note C++ Class Interface::.
+
+
+File: gmp.info,  Node: C++ Class Interface,  Next: Custom Allocation,  Prev: Formatted Input,  Up: Top
+
+12 C++ Class Interface
+**********************
+
+This chapter describes the C++ class based interface to GMP.
+
+   All GMP C language types and functions can be used in C++ programs,
+since 'gmp.h' has 'extern "C"' qualifiers, but the class interface
+offers overloaded functions and operators which may be more convenient.
+
+   Due to the implementation of this interface, a reasonably recent C++
+compiler is required, one supporting namespaces, partial specialization
+of templates and member templates.
+
+   *Everything described in this chapter is to be considered preliminary
+and might be subject to incompatible changes if some unforeseen
+difficulty reveals itself.*
+
+* Menu:
+
+* C++ Interface General::
+* C++ Interface Integers::
+* C++ Interface Rationals::
+* C++ Interface Floats::
+* C++ Interface Random Numbers::
+* C++ Interface Limitations::
+
+
+File: gmp.info,  Node: C++ Interface General,  Next: C++ Interface Integers,  Prev: C++ Class Interface,  Up: C++ Class Interface
+
+12.1 C++ Interface General
+==========================
+
+All the C++ classes and functions are available with
+
+     #include <gmpxx.h>
+
+   Programs should be linked with the 'libgmpxx' and 'libgmp' libraries.
+For example,
+
+     g++ mycxxprog.cc -lgmpxx -lgmp
+
+The classes defined are
+
+ -- Class: mpz_class
+ -- Class: mpq_class
+ -- Class: mpf_class
+
+   The standard operators and various standard functions are overloaded
+to allow arithmetic with these classes.  For example,
+
+     int
+     main (void)
+     {
+       mpz_class a, b, c;
+
+       a = 1234;
+       b = "-5678";
+       c = a+b;
+       cout << "sum is " << c << "\n";
+       cout << "absolute value is " << abs(c) << "\n";
+
+       return 0;
+     }
+
+   An important feature of the implementation is that an expression like
+'a=b+c' results in a single call to the corresponding 'mpz_add', without
+using a temporary for the 'b+c' part.  Expressions which by their nature
+imply intermediate values, like 'a=b*c+d*e', still use temporaries
+though.
+
+   The classes can be freely intermixed in expressions, as can the
+classes and the standard types 'long', 'unsigned long' and 'double'.
+Smaller types like 'int' or 'float' can also be intermixed, since C++
+will promote them.
+
+   Note that 'bool' is not accepted directly, but must be explicitly
+cast to an 'int' first.  This is because C++ will automatically convert
+any pointer to a 'bool', so if GMP accepted 'bool' it would make all
+sorts of invalid class and pointer combinations compile but almost
+certainly not do anything sensible.
+
+   Conversions back from the classes to standard C++ types aren't done
+automatically, instead member functions like 'get_si' are provided (see
+the following sections for details).
+
+   Also there are no automatic conversions from the classes to the
+corresponding GMP C types, instead a reference to the underlying C
+object can be obtained with the following functions,
+
+ -- Function: mpz_t mpz_class::get_mpz_t ()
+ -- Function: mpq_t mpq_class::get_mpq_t ()
+ -- Function: mpf_t mpf_class::get_mpf_t ()
+
+   These can be used to call a C function which doesn't have a C++ class
+interface.  For example to set 'a' to the GCD of 'b' and 'c',
+
+     mpz_class a, b, c;
+     ...
+     mpz_gcd (a.get_mpz_t(), b.get_mpz_t(), c.get_mpz_t());
+
+   In the other direction, a class can be initialized from the
+corresponding GMP C type, or assigned to if an explicit constructor is
+used.  In both cases this makes a copy of the value, it doesn't create
+any sort of association.  For example,
+
+     mpz_t z;
+     // ... init and calculate z ...
+     mpz_class x(z);
+     mpz_class y;
+     y = mpz_class (z);
+
+   There are no namespace setups in 'gmpxx.h', all types and functions
+are simply put into the global namespace.  This is what 'gmp.h' has done
+in the past, and continues to do for compatibility.  The extras provided
+by 'gmpxx.h' follow GMP naming conventions and are unlikely to clash
+with anything.
+
+
+File: gmp.info,  Node: C++ Interface Integers,  Next: C++ Interface Rationals,  Prev: C++ Interface General,  Up: C++ Class Interface
+
+12.2 C++ Interface Integers
+===========================
+
+ -- Function: mpz_class::mpz_class (type N)
+     Construct an 'mpz_class'.  All the standard C++ types may be used,
+     except 'long long' and 'long double', and all the GMP C++ classes
+     can be used, although conversions from 'mpq_class' and 'mpf_class'
+     are 'explicit'.  Any necessary conversion follows the corresponding
+     C function, for example 'double' follows 'mpz_set_d' (*note
+     Assigning Integers::).
+
+ -- Function: explicit mpz_class::mpz_class (const mpz_t Z)
+     Construct an 'mpz_class' from an 'mpz_t'.  The value in Z is copied
+     into the new 'mpz_class', there won't be any permanent association
+     between it and Z.
+
+ -- Function: explicit mpz_class::mpz_class (const char *S, int BASE =
+          0)
+ -- Function: explicit mpz_class::mpz_class (const string& S, int BASE =
+          0)
+     Construct an 'mpz_class' converted from a string using
+     'mpz_set_str' (*note Assigning Integers::).
+
+     If the string is not a valid integer, an 'std::invalid_argument'
+     exception is thrown.  The same applies to 'operator='.
+
+ -- Function: mpz_class operator"" _mpz (const char *STR)
+     With C++11 compilers, integers can be constructed with the syntax
+     '123_mpz' which is equivalent to 'mpz_class("123")'.
+
+ -- Function: mpz_class operator/ (mpz_class A, mpz_class D)
+ -- Function: mpz_class operator% (mpz_class A, mpz_class D)
+     Divisions involving 'mpz_class' round towards zero, as per the
+     'mpz_tdiv_q' and 'mpz_tdiv_r' functions (*note Integer Division::).
+     This is the same as the C99 '/' and '%' operators.
+
+     The 'mpz_fdiv...' or 'mpz_cdiv...' functions can always be called
+     directly if desired.  For example,
+
+          mpz_class q, a, d;
+          ...
+          mpz_fdiv_q (q.get_mpz_t(), a.get_mpz_t(), d.get_mpz_t());
+
+ -- Function: mpz_class abs (mpz_class OP)
+ -- Function: int cmp (mpz_class OP1, type OP2)
+ -- Function: int cmp (type OP1, mpz_class OP2)
+
+ -- Function: bool mpz_class::fits_sint_p (void)
+ -- Function: bool mpz_class::fits_slong_p (void)
+ -- Function: bool mpz_class::fits_sshort_p (void)
+
+ -- Function: bool mpz_class::fits_uint_p (void)
+ -- Function: bool mpz_class::fits_ulong_p (void)
+ -- Function: bool mpz_class::fits_ushort_p (void)
+
+ -- Function: double mpz_class::get_d (void)
+ -- Function: long mpz_class::get_si (void)
+ -- Function: string mpz_class::get_str (int BASE = 10)
+ -- Function: unsigned long mpz_class::get_ui (void)
+
+ -- Function: int mpz_class::set_str (const char *STR, int BASE)
+ -- Function: int mpz_class::set_str (const string& STR, int BASE)
+ -- Function: int sgn (mpz_class OP)
+ -- Function: mpz_class sqrt (mpz_class OP)
+
+ -- Function: mpz_class gcd (mpz_class OP1, mpz_class OP2)
+ -- Function: mpz_class lcm (mpz_class OP1, mpz_class OP2)
+ -- Function: mpz_class mpz_class::factorial (type OP)
+ -- Function: mpz_class factorial (mpz_class OP)
+ -- Function: mpz_class mpz_class::primorial (type OP)
+ -- Function: mpz_class primorial (mpz_class OP)
+ -- Function: mpz_class mpz_class::fibonacci (type OP)
+ -- Function: mpz_class fibonacci (mpz_class OP)
+
+ -- Function: void mpz_class::swap (mpz_class& OP)
+ -- Function: void swap (mpz_class& OP1, mpz_class& OP2)
+     These functions provide a C++ class interface to the corresponding
+     GMP C routines.  Calling 'factorial' or 'primorial' on a negative
+     number is undefined.
+
+     'cmp' can be used with any of the classes or the standard C++
+     types, except 'long long' and 'long double'.
+
+
+   Overloaded operators for combinations of 'mpz_class' and 'double' are
+provided for completeness, but it should be noted that if the given
+'double' is not an integer then the way any rounding is done is
+currently unspecified.  The rounding might take place at the start, in
+the middle, or at the end of the operation, and it might change in the
+future.
+
+   Conversions between 'mpz_class' and 'double', however, are defined to
+follow the corresponding C functions 'mpz_get_d' and 'mpz_set_d'.  And
+comparisons are always made exactly, as per 'mpz_cmp_d'.
+
+
+File: gmp.info,  Node: C++ Interface Rationals,  Next: C++ Interface Floats,  Prev: C++ Interface Integers,  Up: C++ Class Interface
+
+12.3 C++ Interface Rationals
+============================
+
+In all the following constructors, if a fraction is given then it should
+be in canonical form, or if not then 'mpq_class::canonicalize' called.
+
+ -- Function: mpq_class::mpq_class (type OP)
+ -- Function: mpq_class::mpq_class (integer NUM, integer DEN)
+     Construct an 'mpq_class'.  The initial value can be a single value
+     of any type (conversion from 'mpf_class' is 'explicit'), or a pair
+     of integers ('mpz_class' or standard C++ integer types)
+     representing a fraction, except that 'long long' and 'long double'
+     are not supported.  For example,
+
+          mpq_class q (99);
+          mpq_class q (1.75);
+          mpq_class q (1, 3);
+
+ -- Function: explicit mpq_class::mpq_class (const mpq_t Q)
+     Construct an 'mpq_class' from an 'mpq_t'.  The value in Q is copied
+     into the new 'mpq_class', there won't be any permanent association
+     between it and Q.
+
+ -- Function: explicit mpq_class::mpq_class (const char *S, int BASE =
+          0)
+ -- Function: explicit mpq_class::mpq_class (const string& S, int BASE =
+          0)
+     Construct an 'mpq_class' converted from a string using
+     'mpq_set_str' (*note Initializing Rationals::).
+
+     If the string is not a valid rational, an 'std::invalid_argument'
+     exception is thrown.  The same applies to 'operator='.
+
+ -- Function: mpq_class operator"" _mpq (const char *STR)
+     With C++11 compilers, integral rationals can be constructed with
+     the syntax '123_mpq' which is equivalent to 'mpq_class(123_mpz)'.
+     Other rationals can be built as '-1_mpq/2' or '0xb_mpq/123456_mpz'.
+
+ -- Function: void mpq_class::canonicalize ()
+     Put an 'mpq_class' into canonical form, as per *note Rational
+     Number Functions::.  All arithmetic operators require their
+     operands in canonical form, and will return results in canonical
+     form.
+
+ -- Function: mpq_class abs (mpq_class OP)
+ -- Function: int cmp (mpq_class OP1, type OP2)
+ -- Function: int cmp (type OP1, mpq_class OP2)
+
+ -- Function: double mpq_class::get_d (void)
+ -- Function: string mpq_class::get_str (int BASE = 10)
+
+ -- Function: int mpq_class::set_str (const char *STR, int BASE)
+ -- Function: int mpq_class::set_str (const string& STR, int BASE)
+ -- Function: int sgn (mpq_class OP)
+
+ -- Function: void mpq_class::swap (mpq_class& OP)
+ -- Function: void swap (mpq_class& OP1, mpq_class& OP2)
+     These functions provide a C++ class interface to the corresponding
+     GMP C routines.
+
+     'cmp' can be used with any of the classes or the standard C++
+     types, except 'long long' and 'long double'.
+
+ -- Function: mpz_class& mpq_class::get_num ()
+ -- Function: mpz_class& mpq_class::get_den ()
+     Get a reference to an 'mpz_class' which is the numerator or
+     denominator of an 'mpq_class'.  This can be used both for read and
+     write access.  If the object returned is modified, it modifies the
+     original 'mpq_class'.
+
+     If direct manipulation might produce a non-canonical value, then
+     'mpq_class::canonicalize' must be called before further operations.
+
+ -- Function: mpz_t mpq_class::get_num_mpz_t ()
+ -- Function: mpz_t mpq_class::get_den_mpz_t ()
+     Get a reference to the underlying 'mpz_t' numerator or denominator
+     of an 'mpq_class'.  This can be passed to C functions expecting an
+     'mpz_t'.  Any modifications made to the 'mpz_t' will modify the
+     original 'mpq_class'.
+
+     If direct manipulation might produce a non-canonical value, then
+     'mpq_class::canonicalize' must be called before further operations.
+
+ -- Function: istream& operator>> (istream& STREAM, mpq_class& ROP);
+     Read ROP from STREAM, using its 'ios' formatting settings, the same
+     as 'mpq_t operator>>' (*note C++ Formatted Input::).
+
+     If the ROP read might not be in canonical form then
+     'mpq_class::canonicalize' must be called.
+
+
+File: gmp.info,  Node: C++ Interface Floats,  Next: C++ Interface Random Numbers,  Prev: C++ Interface Rationals,  Up: C++ Class Interface
+
+12.4 C++ Interface Floats
+=========================
+
+When an expression requires the use of temporary intermediate
+'mpf_class' values, like 'f=g*h+x*y', those temporaries will have the
+same precision as the destination 'f'.  Explicit constructors can be
+used if this doesn't suit.
+
+ -- Function: mpf_class::mpf_class (type OP)
+ -- Function: mpf_class::mpf_class (type OP, mp_bitcnt_t PREC)
+     Construct an 'mpf_class'.  Any standard C++ type can be used,
+     except 'long long' and 'long double', and any of the GMP C++
+     classes can be used.
+
+     If PREC is given, the initial precision is that value, in bits.  If
+     PREC is not given, then the initial precision is determined by the
+     type of OP given.  An 'mpz_class', 'mpq_class', or C++ builtin type
+     will give the default 'mpf' precision (*note Initializing
+     Floats::).  An 'mpf_class' or expression will give the precision of
+     that value.  The precision of a binary expression is the higher of
+     the two operands.
+
+          mpf_class f(1.5);        // default precision
+          mpf_class f(1.5, 500);   // 500 bits (at least)
+          mpf_class f(x);          // precision of x
+          mpf_class f(abs(x));     // precision of x
+          mpf_class f(-g, 1000);   // 1000 bits (at least)
+          mpf_class f(x+y);        // greater of precisions of x and y
+
+ -- Function: explicit mpf_class::mpf_class (const mpf_t F)
+ -- Function: mpf_class::mpf_class (const mpf_t F, mp_bitcnt_t PREC)
+     Construct an 'mpf_class' from an 'mpf_t'.  The value in F is copied
+     into the new 'mpf_class', there won't be any permanent association
+     between it and F.
+
+     If PREC is given, the initial precision is that value, in bits.  If
+     PREC is not given, then the initial precision is that of F.
+
+ -- Function: explicit mpf_class::mpf_class (const char *S)
+ -- Function: mpf_class::mpf_class (const char *S, mp_bitcnt_t PREC, int
+          BASE = 0)
+ -- Function: explicit mpf_class::mpf_class (const string& S)
+ -- Function: mpf_class::mpf_class (const string& S, mp_bitcnt_t PREC,
+          int BASE = 0)
+     Construct an 'mpf_class' converted from a string using
+     'mpf_set_str' (*note Assigning Floats::).  If PREC is given, the
+     initial precision is that value, in bits.  If not, the default
+     'mpf' precision (*note Initializing Floats::) is used.
+
+     If the string is not a valid float, an 'std::invalid_argument'
+     exception is thrown.  The same applies to 'operator='.
+
+ -- Function: mpf_class operator"" _mpf (const char *STR)
+     With C++11 compilers, floats can be constructed with the syntax
+     '1.23e-1_mpf' which is equivalent to 'mpf_class("1.23e-1")'.
+
+ -- Function: mpf_class& mpf_class::operator= (type OP)
+     Convert and store the given OP value to an 'mpf_class' object.  The
+     same types are accepted as for the constructors above.
+
+     Note that 'operator=' only stores a new value, it doesn't copy or
+     change the precision of the destination, instead the value is
+     truncated if necessary.  This is the same as 'mpf_set' etc.  Note
+     in particular this means for 'mpf_class' a copy constructor is not
+     the same as a default constructor plus assignment.
+
+          mpf_class x (y);   // x created with precision of y
+
+          mpf_class x;       // x created with default precision
+          x = y;             // value truncated to that precision
+
+     Applications using templated code may need to be careful about the
+     assumptions the code makes in this area, when working with
+     'mpf_class' values of various different or non-default precisions.
+     For instance implementations of the standard 'complex' template
+     have been seen in both styles above, though of course 'complex' is
+     normally only actually specified for use with the builtin float
+     types.
+
+ -- Function: mpf_class abs (mpf_class OP)
+ -- Function: mpf_class ceil (mpf_class OP)
+ -- Function: int cmp (mpf_class OP1, type OP2)
+ -- Function: int cmp (type OP1, mpf_class OP2)
+
+ -- Function: bool mpf_class::fits_sint_p (void)
+ -- Function: bool mpf_class::fits_slong_p (void)
+ -- Function: bool mpf_class::fits_sshort_p (void)
+
+ -- Function: bool mpf_class::fits_uint_p (void)
+ -- Function: bool mpf_class::fits_ulong_p (void)
+ -- Function: bool mpf_class::fits_ushort_p (void)
+
+ -- Function: mpf_class floor (mpf_class OP)
+ -- Function: mpf_class hypot (mpf_class OP1, mpf_class OP2)
+
+ -- Function: double mpf_class::get_d (void)
+ -- Function: long mpf_class::get_si (void)
+ -- Function: string mpf_class::get_str (mp_exp_t& EXP, int BASE = 10,
+          size_t DIGITS = 0)
+ -- Function: unsigned long mpf_class::get_ui (void)
+
+ -- Function: int mpf_class::set_str (const char *STR, int BASE)
+ -- Function: int mpf_class::set_str (const string& STR, int BASE)
+ -- Function: int sgn (mpf_class OP)
+ -- Function: mpf_class sqrt (mpf_class OP)
+
+ -- Function: void mpf_class::swap (mpf_class& OP)
+ -- Function: void swap (mpf_class& OP1, mpf_class& OP2)
+ -- Function: mpf_class trunc (mpf_class OP)
+     These functions provide a C++ class interface to the corresponding
+     GMP C routines.
+
+     'cmp' can be used with any of the classes or the standard C++
+     types, except 'long long' and 'long double'.
+
+     The accuracy provided by 'hypot' is not currently guaranteed.
+
+ -- Function: mp_bitcnt_t mpf_class::get_prec ()
+ -- Function: void mpf_class::set_prec (mp_bitcnt_t PREC)
+ -- Function: void mpf_class::set_prec_raw (mp_bitcnt_t PREC)
+     Get or set the current precision of an 'mpf_class'.
+
+     The restrictions described for 'mpf_set_prec_raw' (*note
+     Initializing Floats::) apply to 'mpf_class::set_prec_raw'.  Note in
+     particular that the 'mpf_class' must be restored to it's allocated
+     precision before being destroyed.  This must be done by application
+     code, there's no automatic mechanism for it.
+
+
+File: gmp.info,  Node: C++ Interface Random Numbers,  Next: C++ Interface Limitations,  Prev: C++ Interface Floats,  Up: C++ Class Interface
+
+12.5 C++ Interface Random Numbers
+=================================
+
+ -- Class: gmp_randclass
+     The C++ class interface to the GMP random number functions uses
+     'gmp_randclass' to hold an algorithm selection and current state,
+     as per 'gmp_randstate_t'.
+
+ -- Function: gmp_randclass::gmp_randclass (void (*RANDINIT)
+          (gmp_randstate_t, ...), ...)
+     Construct a 'gmp_randclass', using a call to the given RANDINIT
+     function (*note Random State Initialization::).  The arguments
+     expected are the same as RANDINIT, but with 'mpz_class' instead of
+     'mpz_t'.  For example,
+
+          gmp_randclass r1 (gmp_randinit_default);
+          gmp_randclass r2 (gmp_randinit_lc_2exp_size, 32);
+          gmp_randclass r3 (gmp_randinit_lc_2exp, a, c, m2exp);
+          gmp_randclass r4 (gmp_randinit_mt);
+
+     'gmp_randinit_lc_2exp_size' will fail if the size requested is too
+     big, an 'std::length_error' exception is thrown in that case.
+
+ -- Function: gmp_randclass::gmp_randclass (gmp_randalg_t ALG, ...)
+     Construct a 'gmp_randclass' using the same parameters as
+     'gmp_randinit' (*note Random State Initialization::).  This
+     function is obsolete and the above RANDINIT style should be
+     preferred.
+
+ -- Function: void gmp_randclass::seed (unsigned long int S)
+ -- Function: void gmp_randclass::seed (mpz_class S)
+     Seed a random number generator.  See *note Random Number
+     Functions::, for how to choose a good seed.
+
+ -- Function: mpz_class gmp_randclass::get_z_bits (mp_bitcnt_t BITS)
+ -- Function: mpz_class gmp_randclass::get_z_bits (mpz_class BITS)
+     Generate a random integer with a specified number of bits.
+
+ -- Function: mpz_class gmp_randclass::get_z_range (mpz_class N)
+     Generate a random integer in the range 0 to N-1 inclusive.
+
+ -- Function: mpf_class gmp_randclass::get_f ()
+ -- Function: mpf_class gmp_randclass::get_f (mp_bitcnt_t PREC)
+     Generate a random float F in the range 0 <= F < 1.  F will be to
+     PREC bits precision, or if PREC is not given then to the precision
+     of the destination.  For example,
+
+          gmp_randclass  r;
+          ...
+          mpf_class  f (0, 512);   // 512 bits precision
+          f = r.get_f();           // random number, 512 bits
+
+
+File: gmp.info,  Node: C++ Interface Limitations,  Prev: C++ Interface Random Numbers,  Up: C++ Class Interface
+
+12.6 C++ Interface Limitations
+==============================
+
+'mpq_class' and Templated Reading
+     A generic piece of template code probably won't know that
+     'mpq_class' requires a 'canonicalize' call if inputs read with
+     'operator>>' might be non-canonical.  This can lead to incorrect
+     results.
+
+     'operator>>' behaves as it does for reasons of efficiency.  A
+     canonicalize can be quite time consuming on large operands, and is
+     best avoided if it's not necessary.
+
+     But this potential difficulty reduces the usefulness of
+     'mpq_class'.  Perhaps a mechanism to tell 'operator>>' what to do
+     will be adopted in the future, maybe a preprocessor define, a
+     global flag, or an 'ios' flag pressed into service.  Or maybe, at
+     the risk of inconsistency, the 'mpq_class' 'operator>>' could
+     canonicalize and leave 'mpq_t' 'operator>>' not doing so, for use
+     on those occasions when that's acceptable.  Send feedback or
+     alternate ideas to <gmp-bugs@gmplib.org>.
+
+Subclassing
+     Subclassing the GMP C++ classes works, but is not currently
+     recommended.
+
+     Expressions involving subclasses resolve correctly (or seem to),
+     but in normal C++ fashion the subclass doesn't inherit constructors
+     and assignments.  There's many of those in the GMP classes, and a
+     good way to reestablish them in a subclass is not yet provided.
+
+Templated Expressions
+     A subtle difficulty exists when using expressions together with
+     application-defined template functions.  Consider the following,
+     with 'T' intended to be some numeric type,
+
+          template <class T>
+          T fun (const T &, const T &);
+
+     When used with, say, plain 'mpz_class' variables, it works fine:
+     'T' is resolved as 'mpz_class'.
+
+          mpz_class f(1), g(2);
+          fun (f, g);    // Good
+
+     But when one of the arguments is an expression, it doesn't work.
+
+          mpz_class f(1), g(2), h(3);
+          fun (f, g+h);  // Bad
+
+     This is because 'g+h' ends up being a certain expression template
+     type internal to 'gmpxx.h', which the C++ template resolution rules
+     are unable to automatically convert to 'mpz_class'.  The workaround
+     is simply to add an explicit cast.
+
+          mpz_class f(1), g(2), h(3);
+          fun (f, mpz_class(g+h));  // Good
+
+     Similarly, within 'fun' it may be necessary to cast an expression
+     to type 'T' when calling a templated 'fun2'.
+
+          template <class T>
+          void fun (T f, T g)
+          {
+            fun2 (f, f+g);     // Bad
+          }
+
+          template <class T>
+          void fun (T f, T g)
+          {
+            fun2 (f, T(f+g));  // Good
+          }
+
+C++11
+     C++11 provides several new ways in which types can be inferred:
+     'auto', 'decltype', etc.  While they can be very convenient, they
+     don't mix well with expression templates.  In this example, the
+     addition is performed twice, as if we had defined 'sum' as a macro.
+
+          mpz_class z = 33;
+          auto sum = z + z;
+          mpz_class prod = sum * sum;
+
+     This other example may crash, though some compilers might make it
+     look like it is working, because the expression 'z+z' goes out of
+     scope before it is evaluated.
+
+          mpz_class z = 33;
+          auto sum = z + z + z;
+          mpz_class prod = sum * 2;
+
+     It is thus strongly recommended to avoid 'auto' anywhere a GMP C++
+     expression may appear.
+
+
+File: gmp.info,  Node: Custom Allocation,  Next: Language Bindings,  Prev: C++ Class Interface,  Up: Top
+
+13 Custom Allocation
+********************
+
+By default GMP uses 'malloc', 'realloc' and 'free' for memory
+allocation, and if they fail GMP prints a message to the standard error
+output and terminates the program.
+
+   Alternate functions can be specified, to allocate memory in a
+different way or to have a different error action on running out of
+memory.
+
+ -- Function: void mp_set_memory_functions (
+          void *(*ALLOC_FUNC_PTR) (size_t),
+          void *(*REALLOC_FUNC_PTR) (void *, size_t, size_t),
+          void (*FREE_FUNC_PTR) (void *, size_t))
+     Replace the current allocation functions from the arguments.  If an
+     argument is 'NULL', the corresponding default function is used.
+
+     These functions will be used for all memory allocation done by GMP,
+     apart from temporary space from 'alloca' if that function is
+     available and GMP is configured to use it (*note Build Options::).
+
+     *Be sure to call 'mp_set_memory_functions' only when there are no
+     active GMP objects allocated using the previous memory functions!
+     Usually that means calling it before any other GMP function.*
+
+   The functions supplied should fit the following declarations:
+
+ -- Function: void * allocate_function (size_t ALLOC_SIZE)
+     Return a pointer to newly allocated space with at least ALLOC_SIZE
+     bytes.
+
+ -- Function: void * reallocate_function (void *PTR, size_t OLD_SIZE,
+          size_t NEW_SIZE)
+     Resize a previously allocated block PTR of OLD_SIZE bytes to be
+     NEW_SIZE bytes.
+
+     The block may be moved if necessary or if desired, and in that case
+     the smaller of OLD_SIZE and NEW_SIZE bytes must be copied to the
+     new location.  The return value is a pointer to the resized block,
+     that being the new location if moved or just PTR if not.
+
+     PTR is never 'NULL', it's always a previously allocated block.
+     NEW_SIZE may be bigger or smaller than OLD_SIZE.
+
+ -- Function: void free_function (void *PTR, size_t SIZE)
+     De-allocate the space pointed to by PTR.
+
+     PTR is never 'NULL', it's always a previously allocated block of
+     SIZE bytes.
+
+   A "byte" here means the unit used by the 'sizeof' operator.
+
+   The REALLOCATE_FUNCTION parameter OLD_SIZE and the FREE_FUNCTION
+parameter SIZE are passed for convenience, but of course they can be
+ignored if not needed by an implementation.  The default functions using
+'malloc' and friends for instance don't use them.
+
+   No error return is allowed from any of these functions, if they
+return then they must have performed the specified operation.  In
+particular note that ALLOCATE_FUNCTION or REALLOCATE_FUNCTION mustn't
+return 'NULL'.
+
+   Getting a different fatal error action is a good use for custom
+allocation functions, for example giving a graphical dialog rather than
+the default print to 'stderr'.  How much is possible when genuinely out
+of memory is another question though.
+
+   There's currently no defined way for the allocation functions to
+recover from an error such as out of memory, they must terminate program
+execution.  A 'longjmp' or throwing a C++ exception will have undefined
+results.  This may change in the future.
+
+   GMP may use allocated blocks to hold pointers to other allocated
+blocks.  This will limit the assumptions a conservative garbage
+collection scheme can make.
+
+   Since the default GMP allocation uses 'malloc' and friends, those
+functions will be linked in even if the first thing a program does is an
+'mp_set_memory_functions'.  It's necessary to change the GMP sources if
+this is a problem.
+
+
+ -- Function: void mp_get_memory_functions (
+          void *(**ALLOC_FUNC_PTR) (size_t),
+          void *(**REALLOC_FUNC_PTR) (void *, size_t, size_t),
+          void (**FREE_FUNC_PTR) (void *, size_t))
+     Get the current allocation functions, storing function pointers to
+     the locations given by the arguments.  If an argument is 'NULL',
+     that function pointer is not stored.
+
+     For example, to get just the current free function,
+
+          void (*freefunc) (void *, size_t);
+
+          mp_get_memory_functions (NULL, NULL, &freefunc);
+
+
+File: gmp.info,  Node: Language Bindings,  Next: Algorithms,  Prev: Custom Allocation,  Up: Top
+
+14 Language Bindings
+********************
+
+The following packages and projects offer access to GMP from languages
+other than C, though perhaps with varying levels of functionality and
+efficiency.
+
+
+C++
+        * GMP C++ class interface, *note C++ Class Interface::
+          Straightforward interface, expression templates to eliminate
+          temporaries.
+        * ALP <https://www-sop.inria.fr/saga/logiciels/ALP/>
+          Linear algebra and polynomials using templates.
+        * CLN <https://www.ginac.de/CLN/>
+          High level classes for arithmetic.
+        * Linbox <http://www.linalg.org/>
+          Sparse vectors and matrices.
+        * NTL <http://www.shoup.net/ntl/>
+          A C++ number theory library.
+
+Eiffel
+        * Eiffelroom <http://www.eiffelroom.org/node/442>
+
+Haskell
+        * Glasgow Haskell Compiler <https://www.haskell.org/ghc/>
+
+Java
+        * Kaffe <https://github.com/kaffe/kaffe>
+
+Lisp
+        * GNU Common Lisp <https://www.gnu.org/software/gcl/gcl.html>
+        * Librep <http://librep.sourceforge.net/>
+        * XEmacs (21.5.18 beta and up) <https://www.xemacs.org>
+          Optional big integers, rationals and floats using GMP.
+
+ML
+        * MLton compiler <http://mlton.org/>
+
+Objective Caml
+        * MLGMP <https://opam.ocaml.org/packages/mlgmp/>
+        * Numerix <http://pauillac.inria.fr/~quercia/>
+          Optionally using GMP.
+
+Oz
+        * Mozart <https://mozart.github.io/>
+
+Pascal
+        * GNU Pascal Compiler <http://www.gnu-pascal.de/>
+          GMP unit.
+        * Numerix <http://pauillac.inria.fr/~quercia/>
+          For Free Pascal, optionally using GMP.
+
+Perl
+        * GMP module, see 'demos/perl' in the GMP sources (*note
+          Demonstration Programs::).
+        * Math::GMP <https://www.cpan.org/>
+          Compatible with Math::BigInt, but not as many functions as the
+          GMP module above.
+        * Math::BigInt::GMP <https://www.cpan.org/>
+          Plug Math::GMP into normal Math::BigInt operations.
+
+Pike
+        * pikempz module in the standard distribution,
+          <https://pike.lysator.liu.se/>
+
+Prolog
+        * SWI Prolog <http://www.swi-prolog.org/>
+          Arbitrary precision floats.
+
+Python
+        * GMPY <https://code.google.com/p/gmpy/>
+
+Ruby
+        * <https://rubygems.org/gems/gmp>
+
+Scheme
+        * GNU Guile <https://www.gnu.org/software/guile/guile.html>
+        * RScheme <https://www.rscheme.org/>
+        * STklos <http://www.stklos.net/>
+
+Smalltalk
+        * GNU Smalltalk <http://smalltalk.gnu.org/>
+
+Other
+        * Axiom <https://savannah.nongnu.org/projects/axiom>
+          Computer algebra using GCL.
+        * DrGenius <http://drgenius.seul.org/>
+          Geometry system and mathematical programming language.
+        * GiNaC <httsp://www.ginac.de/>
+          C++ computer algebra using CLN.
+        * GOO <https://www.eecs.berkeley.edu/~jrb/goo/>
+          Dynamic object oriented language.
+        * Maxima <https://www.ma.utexas.edu/users/wfs/maxima.html>
+          Macsyma computer algebra using GCL.
+        * Regina <http://regina.sourceforge.net/>
+          Topological calculator.
+        * Yacas <http://yacas.sourceforge.net>
+          Yet another computer algebra system.
+
+
+File: gmp.info,  Node: Algorithms,  Next: Internals,  Prev: Language Bindings,  Up: Top
+
+15 Algorithms
+*************
+
+This chapter is an introduction to some of the algorithms used for
+various GMP operations.  The code is likely to be hard to understand
+without knowing something about the algorithms.
+
+   Some GMP internals are mentioned, but applications that expect to be
+compatible with future GMP releases should take care to use only the
+documented functions.
+
+* Menu:
+
+* Multiplication Algorithms::
+* Division Algorithms::
+* Greatest Common Divisor Algorithms::
+* Powering Algorithms::
+* Root Extraction Algorithms::
+* Radix Conversion Algorithms::
+* Other Algorithms::
+* Assembly Coding::
+
+
+File: gmp.info,  Node: Multiplication Algorithms,  Next: Division Algorithms,  Prev: Algorithms,  Up: Algorithms
+
+15.1 Multiplication
+===================
+
+NxN limb multiplications and squares are done using one of seven
+algorithms, as the size N increases.
+
+     Algorithm      Threshold
+     Basecase       (none)
+     Karatsuba      'MUL_TOOM22_THRESHOLD'
+     Toom-3         'MUL_TOOM33_THRESHOLD'
+     Toom-4         'MUL_TOOM44_THRESHOLD'
+     Toom-6.5       'MUL_TOOM6H_THRESHOLD'
+     Toom-8.5       'MUL_TOOM8H_THRESHOLD'
+     FFT            'MUL_FFT_THRESHOLD'
+
+   Similarly for squaring, with the 'SQR' thresholds.
+
+   NxM multiplications of operands with different sizes above
+'MUL_TOOM22_THRESHOLD' are currently done by special Toom-inspired
+algorithms or directly with FFT, depending on operand size (*note
+Unbalanced Multiplication::).
+
+* Menu:
+
+* Basecase Multiplication::
+* Karatsuba Multiplication::
+* Toom 3-Way Multiplication::
+* Toom 4-Way Multiplication::
+* Higher degree Toom'n'half::
+* FFT Multiplication::
+* Other Multiplication::
+* Unbalanced Multiplication::
+
+
+File: gmp.info,  Node: Basecase Multiplication,  Next: Karatsuba Multiplication,  Prev: Multiplication Algorithms,  Up: Multiplication Algorithms
+
+15.1.1 Basecase Multiplication
+------------------------------
+
+Basecase NxM multiplication is a straightforward rectangular set of
+cross-products, the same as long multiplication done by hand and for
+that reason sometimes known as the schoolbook or grammar school method.
+This is an O(N*M) algorithm.  See Knuth section 4.3.1 algorithm M (*note
+References::), and the 'mpn/generic/mul_basecase.c' code.
+
+   Assembly implementations of 'mpn_mul_basecase' are essentially the
+same as the generic C code, but have all the usual assembly tricks and
+obscurities introduced for speed.
+
+   A square can be done in roughly half the time of a multiply, by using
+the fact that the cross products above and below the diagonal are the
+same.  A triangle of products below the diagonal is formed, doubled
+(left shift by one bit), and then the products on the diagonal added.
+This can be seen in 'mpn/generic/sqr_basecase.c'.  Again the assembly
+implementations take essentially the same approach.
+
+          u0  u1  u2  u3  u4
+        +---+---+---+---+---+
+     u0 | d |   |   |   |   |
+        +---+---+---+---+---+
+     u1 |   | d |   |   |   |
+        +---+---+---+---+---+
+     u2 |   |   | d |   |   |
+        +---+---+---+---+---+
+     u3 |   |   |   | d |   |
+        +---+---+---+---+---+
+     u4 |   |   |   |   | d |
+        +---+---+---+---+---+
+
+   In practice squaring isn't a full 2x faster than multiplying, it's
+usually around 1.5x.  Less than 1.5x probably indicates
+'mpn_sqr_basecase' wants improving on that CPU.
+
+   On some CPUs 'mpn_mul_basecase' can be faster than the generic C
+'mpn_sqr_basecase' on some small sizes.  'SQR_BASECASE_THRESHOLD' is the
+size at which to use 'mpn_sqr_basecase', this will be zero if that
+routine should be used always.
+
+
+File: gmp.info,  Node: Karatsuba Multiplication,  Next: Toom 3-Way Multiplication,  Prev: Basecase Multiplication,  Up: Multiplication Algorithms
+
+15.1.2 Karatsuba Multiplication
+-------------------------------
+
+The Karatsuba multiplication algorithm is described in Knuth section
+4.3.3 part A, and various other textbooks.  A brief description is given
+here.
+
+   The inputs x and y are treated as each split into two parts of equal
+length (or the most significant part one limb shorter if N is odd).
+
+      high              low
+     +----------+----------+
+     |    x1    |    x0    |
+     +----------+----------+
+
+     +----------+----------+
+     |    y1    |    y0    |
+     +----------+----------+
+
+   Let b be the power of 2 where the split occurs, i.e. if x0 is k limbs
+(y0 the same) then b=2^(k*mp_bits_per_limb).  With that x=x1*b+x0 and
+y=y1*b+y0, and the following holds,
+
+     x*y = (b^2+b)*x1*y1 - b*(x1-x0)*(y1-y0) + (b+1)*x0*y0
+
+   This formula means doing only three multiplies of (N/2)x(N/2) limbs,
+whereas a basecase multiply of NxN limbs is equivalent to four
+multiplies of (N/2)x(N/2).  The factors (b^2+b) etc represent the
+positions where the three products must be added.
+
+      high                              low
+     +--------+--------+ +--------+--------+
+     |      x1*y1      | |      x0*y0      |
+     +--------+--------+ +--------+--------+
+               +--------+--------+
+           add |      x1*y1      |
+               +--------+--------+
+               +--------+--------+
+           add |      x0*y0      |
+               +--------+--------+
+               +--------+--------+
+           sub | (x1-x0)*(y1-y0) |
+               +--------+--------+
+
+   The term (x1-x0)*(y1-y0) is best calculated as an absolute value, and
+the sign used to choose to add or subtract.  Notice the sum
+high(x0*y0)+low(x1*y1) occurs twice, so it's possible to do 5*k limb
+additions, rather than 6*k, but in GMP extra function call overheads
+outweigh the saving.
+
+   Squaring is similar to multiplying, but with x=y the formula reduces
+to an equivalent with three squares,
+
+     x^2 = (b^2+b)*x1^2 - b*(x1-x0)^2 + (b+1)*x0^2
+
+   The final result is accumulated from those three squares the same way
+as for the three multiplies above.  The middle term (x1-x0)^2 is now
+always positive.
+
+   A similar formula for both multiplying and squaring can be
+constructed with a middle term (x1+x0)*(y1+y0).  But those sums can
+exceed k limbs, leading to more carry handling and additions than the
+form above.
+
+   Karatsuba multiplication is asymptotically an O(N^1.585) algorithm,
+the exponent being log(3)/log(2), representing 3 multiplies each 1/2 the
+size of the inputs.  This is a big improvement over the basecase
+multiply at O(N^2) and the advantage soon overcomes the extra additions
+Karatsuba performs.  'MUL_TOOM22_THRESHOLD' can be as little as 10
+limbs.  The 'SQR' threshold is usually about twice the 'MUL'.
+
+   The basecase algorithm will take a time of the form M(N) = a*N^2 +
+b*N + c and the Karatsuba algorithm K(N) = 3*M(N/2) + d*N + e, which
+expands to K(N) = 3/4*a*N^2 + 3/2*b*N + 3*c + d*N + e.  The factor 3/4
+for a means per-crossproduct speedups in the basecase code will increase
+the threshold since they benefit M(N) more than K(N). And conversely the
+3/2 for b means linear style speedups of b will increase the threshold
+since they benefit K(N) more than M(N). The latter can be seen for
+instance when adding an optimized 'mpn_sqr_diagonal' to
+'mpn_sqr_basecase'.  Of course all speedups reduce total time, and in
+that sense the algorithm thresholds are merely of academic interest.
+
+
+File: gmp.info,  Node: Toom 3-Way Multiplication,  Next: Toom 4-Way Multiplication,  Prev: Karatsuba Multiplication,  Up: Multiplication Algorithms
+
+15.1.3 Toom 3-Way Multiplication
+--------------------------------
+
+The Karatsuba formula is the simplest case of a general approach to
+splitting inputs that leads to both Toom and FFT algorithms.  A
+description of Toom can be found in Knuth section 4.3.3, with an example
+3-way calculation after Theorem A.  The 3-way form used in GMP is
+described here.
+
+   The operands are each considered split into 3 pieces of equal length
+(or the most significant part 1 or 2 limbs shorter than the other two).
+
+      high                         low
+     +----------+----------+----------+
+     |    x2    |    x1    |    x0    |
+     +----------+----------+----------+
+
+     +----------+----------+----------+
+     |    y2    |    y1    |    y0    |
+     +----------+----------+----------+
+
+These parts are treated as the coefficients of two polynomials
+
+     X(t) = x2*t^2 + x1*t + x0
+     Y(t) = y2*t^2 + y1*t + y0
+
+   Let b equal the power of 2 which is the size of the x0, x1, y0 and y1
+pieces, i.e. if they're k limbs each then b=2^(k*mp_bits_per_limb).
+With this x=X(b) and y=Y(b).
+
+   Let a polynomial W(t)=X(t)*Y(t) and suppose its coefficients are
+
+     W(t) = w4*t^4 + w3*t^3 + w2*t^2 + w1*t + w0
+
+   The w[i] are going to be determined, and when they are they'll give
+the final result using w=W(b), since x*y=X(b)*Y(b)=W(b).  The
+coefficients will be roughly b^2 each, and the final W(b) will be an
+addition like,
+
+      high                                        low
+     +-------+-------+
+     |       w4      |
+     +-------+-------+
+            +--------+-------+
+            |        w3      |
+            +--------+-------+
+                    +--------+-------+
+                    |        w2      |
+                    +--------+-------+
+                            +--------+-------+
+                            |        w1      |
+                            +--------+-------+
+                                     +-------+-------+
+                                     |       w0      |
+                                     +-------+-------+
+
+   The w[i] coefficients could be formed by a simple set of cross
+products, like w4=x2*y2, w3=x2*y1+x1*y2, w2=x2*y0+x1*y1+x0*y2 etc, but
+this would need all nine x[i]*y[j] for i,j=0,1,2, and would be
+equivalent merely to a basecase multiply.  Instead the following
+approach is used.
+
+   X(t) and Y(t) are evaluated and multiplied at 5 points, giving values
+of W(t) at those points.  In GMP the following points are used,
+
+     Point    Value
+     t=0      x0 * y0, which gives w0 immediately
+     t=1      (x2+x1+x0) * (y2+y1+y0)
+     t=-1     (x2-x1+x0) * (y2-y1+y0)
+     t=2      (4*x2+2*x1+x0) * (4*y2+2*y1+y0)
+     t=inf    x2 * y2, which gives w4 immediately
+
+   At t=-1 the values can be negative and that's handled using the
+absolute values and tracking the sign separately.  At t=inf the value is
+actually X(t)*Y(t)/t^4 in the limit as t approaches infinity, but it's
+much easier to think of as simply x2*y2 giving w4 immediately (much like
+x0*y0 at t=0 gives w0 immediately).
+
+   Each of the points substituted into W(t)=w4*t^4+...+w0 gives a linear
+combination of the w[i] coefficients, and the value of those
+combinations has just been calculated.
+
+     W(0)   =                              w0
+     W(1)   =    w4 +   w3 +   w2 +   w1 + w0
+     W(-1)  =    w4 -   w3 +   w2 -   w1 + w0
+     W(2)   = 16*w4 + 8*w3 + 4*w2 + 2*w1 + w0
+     W(inf) =    w4
+
+   This is a set of five equations in five unknowns, and some elementary
+linear algebra quickly isolates each w[i].  This involves adding or
+subtracting one W(t) value from another, and a couple of divisions by
+powers of 2 and one division by 3, the latter using the special
+'mpn_divexact_by3' (*note Exact Division::).
+
+   The conversion of W(t) values to the coefficients is interpolation.
+A polynomial of degree 4 like W(t) is uniquely determined by values
+known at 5 different points.  The points are arbitrary and can be chosen
+to make the linear equations come out with a convenient set of steps for
+quickly isolating the w[i].
+
+   Squaring follows the same procedure as multiplication, but there's
+only one X(t) and it's evaluated at the 5 points, and those values
+squared to give values of W(t).  The interpolation is then identical,
+and in fact the same 'toom_interpolate_5pts' subroutine is used for both
+squaring and multiplying.
+
+   Toom-3 is asymptotically O(N^1.465), the exponent being
+log(5)/log(3), representing 5 recursive multiplies of 1/3 the original
+size each.  This is an improvement over Karatsuba at O(N^1.585), though
+Toom does more work in the evaluation and interpolation and so it only
+realizes its advantage above a certain size.
+
+   Near the crossover between Toom-3 and Karatsuba there's generally a
+range of sizes where the difference between the two is small.
+'MUL_TOOM33_THRESHOLD' is a somewhat arbitrary point in that range and
+successive runs of the tune program can give different values due to
+small variations in measuring.  A graph of time versus size for the two
+shows the effect, see 'tune/README'.
+
+   At the fairly small sizes where the Toom-3 thresholds occur it's
+worth remembering that the asymptotic behaviour for Karatsuba and Toom-3
+can't be expected to make accurate predictions, due of course to the big
+influence of all sorts of overheads, and the fact that only a few
+recursions of each are being performed.  Even at large sizes there's a
+good chance machine dependent effects like cache architecture will mean
+actual performance deviates from what might be predicted.
+
+   The formula given for the Karatsuba algorithm (*note Karatsuba
+Multiplication::) has an equivalent for Toom-3 involving only five
+multiplies, but this would be complicated and unenlightening.
+
+   An alternate view of Toom-3 can be found in Zuras (*note
+References::), using a vector to represent the x and y splits and a
+matrix multiplication for the evaluation and interpolation stages.  The
+matrix inverses are not meant to be actually used, and they have
+elements with values much greater than in fact arise in the
+interpolation steps.  The diagram shown for the 3-way is attractive, but
+again doesn't have to be implemented that way and for example with a bit
+of rearrangement just one division by 6 can be done.
+
+
+File: gmp.info,  Node: Toom 4-Way Multiplication,  Next: Higher degree Toom'n'half,  Prev: Toom 3-Way Multiplication,  Up: Multiplication Algorithms
+
+15.1.4 Toom 4-Way Multiplication
+--------------------------------
+
+Karatsuba and Toom-3 split the operands into 2 and 3 coefficients,
+respectively.  Toom-4 analogously splits the operands into 4
+coefficients.  Using the notation from the section on Toom-3
+multiplication, we form two polynomials:
+
+     X(t) = x3*t^3 + x2*t^2 + x1*t + x0
+     Y(t) = y3*t^3 + y2*t^2 + y1*t + y0
+
+   X(t) and Y(t) are evaluated and multiplied at 7 points, giving values
+of W(t) at those points.  In GMP the following points are used,
+
+     Point    Value
+     t=0      x0 * y0, which gives w0 immediately
+     t=1/2    (x3+2*x2+4*x1+8*x0) * (y3+2*y2+4*y1+8*y0)
+     t=-1/2   (-x3+2*x2-4*x1+8*x0) * (-y3+2*y2-4*y1+8*y0)
+     t=1      (x3+x2+x1+x0) * (y3+y2+y1+y0)
+     t=-1     (-x3+x2-x1+x0) * (-y3+y2-y1+y0)
+     t=2      (8*x3+4*x2+2*x1+x0) * (8*y3+4*y2+2*y1+y0)
+     t=inf    x3 * y3, which gives w6 immediately
+
+   The number of additions and subtractions for Toom-4 is much larger
+than for Toom-3.  But several subexpressions occur multiple times, for
+example x2+x0, occurs for both t=1 and t=-1.
+
+   Toom-4 is asymptotically O(N^1.404), the exponent being
+log(7)/log(4), representing 7 recursive multiplies of 1/4 the original
+size each.
+
+
+File: gmp.info,  Node: Higher degree Toom'n'half,  Next: FFT Multiplication,  Prev: Toom 4-Way Multiplication,  Up: Multiplication Algorithms
+
+15.1.5 Higher degree Toom'n'half
+--------------------------------
+
+The Toom algorithms described above (*note Toom 3-Way Multiplication::,
+*note Toom 4-Way Multiplication::) generalizes to split into an
+arbitrary number of pieces.  In general a split of two equally long
+operands into r pieces leads to evaluations and pointwise
+multiplications done at 2*r-1 points.  To fully exploit symmetries it
+would be better to have a multiple of 4 points, that's why for higher
+degree Toom'n'half is used.
+
+   Toom'n'half means that the existence of one more piece is considered
+for a single operand.  It can be virtual, i.e.  zero, or real, when the
+two operand are not exactly balanced.  By choosing an even r, Toom-r+1/2
+requires 2r points, a multiple of four.
+
+   The quadruplets of points include 0, inf, +1, -1 and +-2^i, +-2^-i .
+Each of them giving shortcuts for the evaluation phase and for some
+steps in the interpolation phase.  Further tricks are used to reduce the
+memory footprint of the whole multiplication algorithm to a memory
+buffer equal in size to the result of the product.
+
+   Current GMP uses both Toom-6'n'half and Toom-8'n'half.
+
+
+File: gmp.info,  Node: FFT Multiplication,  Next: Other Multiplication,  Prev: Higher degree Toom'n'half,  Up: Multiplication Algorithms
+
+15.1.6 FFT Multiplication
+-------------------------
+
+At large to very large sizes a Fermat style FFT multiplication is used,
+following Schönhage and Strassen (*note References::).  Descriptions of
+FFTs in various forms can be found in many textbooks, for instance Knuth
+section 4.3.3 part C or Lipson chapter IX.  A brief description of the
+form used in GMP is given here.
+
+   The multiplication done is x*y mod 2^N+1, for a given N. A full
+product x*y is obtained by choosing N>=bits(x)+bits(y) and padding x and
+y with high zero limbs.  The modular product is the native form for the
+algorithm, so padding to get a full product is unavoidable.
+
+   The algorithm follows a split, evaluate, pointwise multiply,
+interpolate and combine similar to that described above for Karatsuba
+and Toom-3.  A k parameter controls the split, with an FFT-k splitting
+into 2^k pieces of M=N/2^k bits each.  N must be a multiple of
+(2^k)*mp_bits_per_limb so the split falls on limb boundaries, avoiding
+bit shifts in the split and combine stages.
+
+   The evaluations, pointwise multiplications, and interpolation, are
+all done modulo 2^N'+1 where N' is 2M+k+3 rounded up to a multiple of
+2^k and of 'mp_bits_per_limb'.  The results of interpolation will be the
+following negacyclic convolution of the input pieces, and the choice of
+N' ensures these sums aren't truncated.
+
+                ---
+                \         b
+     w[n] =     /     (-1) * x[i] * y[j]
+                ---
+            i+j==b*2^k+n
+               b=0,1
+
+   The points used for the evaluation are g^i for i=0 to 2^k-1 where
+g=2^(2N'/2^k).  g is a 2^k'th root of unity mod 2^N'+1, which produces
+necessary cancellations at the interpolation stage, and it's also a
+power of 2 so the fast Fourier transforms used for the evaluation and
+interpolation do only shifts, adds and negations.
+
+   The pointwise multiplications are done modulo 2^N'+1 and either
+recurse into a further FFT or use a plain multiplication (Toom-3,
+Karatsuba or basecase), whichever is optimal at the size N'. The
+interpolation is an inverse fast Fourier transform.  The resulting set
+of sums of x[i]*y[j] are added at appropriate offsets to give the final
+result.
+
+   Squaring is the same, but x is the only input so it's one transform
+at the evaluate stage and the pointwise multiplies are squares.  The
+interpolation is the same.
+
+   For a mod 2^N+1 product, an FFT-k is an O(N^(k/(k-1))) algorithm, the
+exponent representing 2^k recursed modular multiplies each 1/2^(k-1) the
+size of the original.  Each successive k is an asymptotic improvement,
+but overheads mean each is only faster at bigger and bigger sizes.  In
+the code, 'MUL_FFT_TABLE' and 'SQR_FFT_TABLE' are the thresholds where
+each k is used.  Each new k effectively swaps some multiplying for some
+shifts, adds and overheads.
+
+   A mod 2^N+1 product can be formed with a normal NxN->2N bit multiply
+plus a subtraction, so an FFT and Toom-3 etc can be compared directly.
+A k=4 FFT at O(N^1.333) can be expected to be the first faster than
+Toom-3 at O(N^1.465).  In practice this is what's found, with
+'MUL_FFT_MODF_THRESHOLD' and 'SQR_FFT_MODF_THRESHOLD' being between 300
+and 1000 limbs, depending on the CPU.  So far it's been found that only
+very large FFTs recurse into pointwise multiplies above these sizes.
+
+   When an FFT is to give a full product, the change of N to 2N doesn't
+alter the theoretical complexity for a given k, but for the purposes of
+considering where an FFT might be first used it can be assumed that the
+FFT is recursing into a normal multiply and that on that basis it's
+doing 2^k recursed multiplies each 1/2^(k-2) the size of the inputs,
+making it O(N^(k/(k-2))).  This would mean k=7 at O(N^1.4) would be the
+first FFT faster than Toom-3.  In practice 'MUL_FFT_THRESHOLD' and
+'SQR_FFT_THRESHOLD' have been found to be in the k=8 range, somewhere
+between 3000 and 10000 limbs.
+
+   The way N is split into 2^k pieces and then 2M+k+3 is rounded up to a
+multiple of 2^k and 'mp_bits_per_limb' means that when
+2^k>=mp\_bits\_per\_limb the effective N is a multiple of 2^(2k-1) bits.
+The +k+3 means some values of N just under such a multiple will be
+rounded to the next.  The complexity calculations above assume that a
+favourable size is used, meaning one which isn't padded through
+rounding, and it's also assumed that the extra +k+3 bits are negligible
+at typical FFT sizes.
+
+   The practical effect of the 2^(2k-1) constraint is to introduce a
+step-effect into measured speeds.  For example k=8 will round N up to a
+multiple of 32768 bits, so for a 32-bit limb there'll be 512 limb groups
+of sizes for which 'mpn_mul_n' runs at the same speed.  Or for k=9
+groups of 2048 limbs, k=10 groups of 8192 limbs, etc.  In practice it's
+been found each k is used at quite small multiples of its size
+constraint and so the step effect is quite noticeable in a time versus
+size graph.
+
+   The threshold determinations currently measure at the mid-points of
+size steps, but this is sub-optimal since at the start of a new step it
+can happen that it's better to go back to the previous k for a while.
+Something more sophisticated for 'MUL_FFT_TABLE' and 'SQR_FFT_TABLE'
+will be needed.
+
+
+File: gmp.info,  Node: Other Multiplication,  Next: Unbalanced Multiplication,  Prev: FFT Multiplication,  Up: Multiplication Algorithms
+
+15.1.7 Other Multiplication
+---------------------------
+
+The Toom algorithms described above (*note Toom 3-Way Multiplication::,
+*note Toom 4-Way Multiplication::) generalizes to split into an
+arbitrary number of pieces, as per Knuth section 4.3.3 algorithm C.
+This is not currently used.  The notes here are merely for interest.
+
+   In general a split into r+1 pieces is made, and evaluations and
+pointwise multiplications done at 2*r+1 points.  A 4-way split does 7
+pointwise multiplies, 5-way does 9, etc.  Asymptotically an (r+1)-way
+algorithm is O(N^(log(2*r+1)/log(r+1))).  Only the pointwise
+multiplications count towards big-O complexity, but the time spent in
+the evaluate and interpolate stages grows with r and has a significant
+practical impact, with the asymptotic advantage of each r realized only
+at bigger and bigger sizes.  The overheads grow as O(N*r), whereas in an
+r=2^k FFT they grow only as O(N*log(r)).
+
+   Knuth algorithm C evaluates at points 0,1,2,...,2*r, but exercise 4
+uses -r,...,0,...,r and the latter saves some small multiplies in the
+evaluate stage (or rather trades them for additions), and has a further
+saving of nearly half the interpolate steps.  The idea is to separate
+odd and even final coefficients and then perform algorithm C steps C7
+and C8 on them separately.  The divisors at step C7 become j^2 and the
+multipliers at C8 become 2*t*j-j^2.
+
+   Splitting odd and even parts through positive and negative points can
+be thought of as using -1 as a square root of unity.  If a 4th root of
+unity was available then a further split and speedup would be possible,
+but no such root exists for plain integers.  Going to complex integers
+with i=sqrt(-1) doesn't help, essentially because in Cartesian form it
+takes three real multiplies to do a complex multiply.  The existence of
+2^k'th roots of unity in a suitable ring or field lets the fast Fourier
+transform keep splitting and get to O(N*log(r)).
+
+   Floating point FFTs use complex numbers approximating Nth roots of
+unity.  Some processors have special support for such FFTs.  But these
+are not used in GMP since it's very difficult to guarantee an exact
+result (to some number of bits).  An occasional difference of 1 in the
+last bit might not matter to a typical signal processing algorithm, but
+is of course of vital importance to GMP.
+
+
+File: gmp.info,  Node: Unbalanced Multiplication,  Prev: Other Multiplication,  Up: Multiplication Algorithms
+
+15.1.8 Unbalanced Multiplication
+--------------------------------
+
+Multiplication of operands with different sizes, both below
+'MUL_TOOM22_THRESHOLD' are done with plain schoolbook multiplication
+(*note Basecase Multiplication::).
+
+   For really large operands, we invoke FFT directly.
+
+   For operands between these sizes, we use Toom inspired algorithms
+suggested by Alberto Zanoni and Marco Bodrato.  The idea is to split the
+operands into polynomials of different degree.  GMP currently splits the
+smaller operand onto 2 coefficients, i.e., a polynomial of degree 1, but
+the larger operand can be split into 2, 3, or 4 coefficients, i.e., a
+polynomial of degree 1 to 3.
+
+
+File: gmp.info,  Node: Division Algorithms,  Next: Greatest Common Divisor Algorithms,  Prev: Multiplication Algorithms,  Up: Algorithms
+
+15.2 Division Algorithms
+========================
+
+* Menu:
+
+* Single Limb Division::
+* Basecase Division::
+* Divide and Conquer Division::
+* Block-Wise Barrett Division::
+* Exact Division::
+* Exact Remainder::
+* Small Quotient Division::
+
+
+File: gmp.info,  Node: Single Limb Division,  Next: Basecase Division,  Prev: Division Algorithms,  Up: Division Algorithms
+
+15.2.1 Single Limb Division
+---------------------------
+
+Nx1 division is implemented using repeated 2x1 divisions from high to
+low, either with a hardware divide instruction or a multiplication by
+inverse, whichever is best on a given CPU.
+
+   The multiply by inverse follows "Improved division by invariant
+integers" by Möller and Granlund (*note References::) and is implemented
+as 'udiv_qrnnd_preinv' in 'gmp-impl.h'.  The idea is to have a
+fixed-point approximation to 1/d (see 'invert_limb') and then multiply
+by the high limb (plus one bit) of the dividend to get a quotient q.
+With d normalized (high bit set), q is no more than 1 too small.
+Subtracting q*d from the dividend gives a remainder, and reveals whether
+q or q-1 is correct.
+
+   The result is a division done with two multiplications and four or
+five arithmetic operations.  On CPUs with low latency multipliers this
+can be much faster than a hardware divide, though the cost of
+calculating the inverse at the start may mean it's only better on inputs
+bigger than say 4 or 5 limbs.
+
+   When a divisor must be normalized, either for the generic C
+'__udiv_qrnnd_c' or the multiply by inverse, the division performed is
+actually a*2^k by d*2^k where a is the dividend and k is the power
+necessary to have the high bit of d*2^k set.  The bit shifts for the
+dividend are usually accomplished "on the fly" meaning by extracting the
+appropriate bits at each step.  Done this way the quotient limbs come
+out aligned ready to store.  When only the remainder is wanted, an
+alternative is to take the dividend limbs unshifted and calculate r = a
+mod d*2^k followed by an extra final step r*2^k mod d*2^k.  This can
+help on CPUs with poor bit shifts or few registers.
+
+   The multiply by inverse can be done two limbs at a time.  The
+calculation is basically the same, but the inverse is two limbs and the
+divisor treated as if padded with a low zero limb.  This means more
+work, since the inverse will need a 2x2 multiply, but the four 1x1s to
+do that are independent and can therefore be done partly or wholly in
+parallel.  Likewise for a 2x1 calculating q*d.  The net effect is to
+process two limbs with roughly the same two multiplies worth of latency
+that one limb at a time gives.  This extends to 3 or 4 limbs at a time,
+though the extra work to apply the inverse will almost certainly soon
+reach the limits of multiplier throughput.
+
+   A similar approach in reverse can be taken to process just half a
+limb at a time if the divisor is only a half limb.  In this case the 1x1
+multiply for the inverse effectively becomes two (1/2)x1 for each limb,
+which can be a saving on CPUs with a fast half limb multiply, or in fact
+if the only multiply is a half limb, and especially if it's not
+pipelined.
+
+
+File: gmp.info,  Node: Basecase Division,  Next: Divide and Conquer Division,  Prev: Single Limb Division,  Up: Division Algorithms
+
+15.2.2 Basecase Division
+------------------------
+
+Basecase NxM division is like long division done by hand, but in base
+2^mp_bits_per_limb.  See Knuth section 4.3.1 algorithm D, and
+'mpn/generic/sb_divrem_mn.c'.
+
+   Briefly stated, while the dividend remains larger than the divisor, a
+high quotient limb is formed and the Nx1 product q*d subtracted at the
+top end of the dividend.  With a normalized divisor (most significant
+bit set), each quotient limb can be formed with a 2x1 division and a 1x1
+multiplication plus some subtractions.  The 2x1 division is by the high
+limb of the divisor and is done either with a hardware divide or a
+multiply by inverse (the same as in *note Single Limb Division::)
+whichever is faster.  Such a quotient is sometimes one too big,
+requiring an addback of the divisor, but that happens rarely.
+
+   With Q=N-M being the number of quotient limbs, this is an O(Q*M)
+algorithm and will run at a speed similar to a basecase QxM
+multiplication, differing in fact only in the extra multiply and divide
+for each of the Q quotient limbs.
+
+
+File: gmp.info,  Node: Divide and Conquer Division,  Next: Block-Wise Barrett Division,  Prev: Basecase Division,  Up: Division Algorithms
+
+15.2.3 Divide and Conquer Division
+----------------------------------
+
+For divisors larger than 'DC_DIV_QR_THRESHOLD', division is done by
+dividing.  Or to be precise by a recursive divide and conquer algorithm
+based on work by Moenck and Borodin, Jebelean, and Burnikel and Ziegler
+(*note References::).
+
+   The algorithm consists essentially of recognising that a 2NxN
+division can be done with the basecase division algorithm (*note
+Basecase Division::), but using N/2 limbs as a base, not just a single
+limb.  This way the multiplications that arise are (N/2)x(N/2) and can
+take advantage of Karatsuba and higher multiplication algorithms (*note
+Multiplication Algorithms::).  The two "digits" of the quotient are
+formed by recursive Nx(N/2) divisions.
+
+   If the (N/2)x(N/2) multiplies are done with a basecase multiplication
+then the work is about the same as a basecase division, but with more
+function call overheads and with some subtractions separated from the
+multiplies.  These overheads mean that it's only when N/2 is above
+'MUL_TOOM22_THRESHOLD' that divide and conquer is of use.
+
+   'DC_DIV_QR_THRESHOLD' is based on the divisor size N, so it will be
+somewhere above twice 'MUL_TOOM22_THRESHOLD', but how much above depends
+on the CPU.  An optimized 'mpn_mul_basecase' can lower
+'DC_DIV_QR_THRESHOLD' a little by offering a ready-made advantage over
+repeated 'mpn_submul_1' calls.
+
+   Divide and conquer is asymptotically O(M(N)*log(N)) where M(N) is the
+time for an NxN multiplication done with FFTs.  The actual time is a sum
+over multiplications of the recursed sizes, as can be seen near the end
+of section 2.2 of Burnikel and Ziegler.  For example, within the Toom-3
+range, divide and conquer is 2.63*M(N). With higher algorithms the M(N)
+term improves and the multiplier tends to log(N). In practice, at
+moderate to large sizes, a 2NxN division is about 2 to 4 times slower
+than an NxN multiplication.
+
+
+File: gmp.info,  Node: Block-Wise Barrett Division,  Next: Exact Division,  Prev: Divide and Conquer Division,  Up: Division Algorithms
+
+15.2.4 Block-Wise Barrett Division
+----------------------------------
+
+For the largest divisions, a block-wise Barrett division algorithm is
+used.  Here, the divisor is inverted to a precision determined by the
+relative size of the dividend and divisor.  Blocks of quotient limbs are
+then generated by multiplying blocks from the dividend by the inverse.
+
+   Our block-wise algorithm computes a smaller inverse than in the plain
+Barrett algorithm.  For a 2n/n division, the inverse will be just
+ceil(n/2) limbs.
+
+
+File: gmp.info,  Node: Exact Division,  Next: Exact Remainder,  Prev: Block-Wise Barrett Division,  Up: Division Algorithms
+
+15.2.5 Exact Division
+---------------------
+
+A so-called exact division is when the dividend is known to be an exact
+multiple of the divisor.  Jebelean's exact division algorithm uses this
+knowledge to make some significant optimizations (*note References::).
+
+   The idea can be illustrated in decimal for example with 368154
+divided by 543.  Because the low digit of the dividend is 4, the low
+digit of the quotient must be 8.  This is arrived at from 4*7 mod 10,
+using the fact 7 is the modular inverse of 3 (the low digit of the
+divisor), since 3*7 == 1 mod 10.  So 8*543=4344 can be subtracted from
+the dividend leaving 363810.  Notice the low digit has become zero.
+
+   The procedure is repeated at the second digit, with the next quotient
+digit 7 (7 == 1*7 mod 10), subtracting 7*543=3801, leaving 325800.  And
+finally at the third digit with quotient digit 6 (8*7 mod 10),
+subtracting 6*543=3258 leaving 0.  So the quotient is 678.
+
+   Notice however that the multiplies and subtractions don't need to
+extend past the low three digits of the dividend, since that's enough to
+determine the three quotient digits.  For the last quotient digit no
+subtraction is needed at all.  On a 2NxN division like this one, only
+about half the work of a normal basecase division is necessary.
+
+   For an NxM exact division producing Q=N-M quotient limbs, the saving
+over a normal basecase division is in two parts.  Firstly, each of the Q
+quotient limbs needs only one multiply, not a 2x1 divide and multiply.
+Secondly, the crossproducts are reduced when Q>M to Q*M-M*(M+1)/2, or
+when Q<=M to Q*(Q-1)/2.  Notice the savings are complementary.  If Q is
+big then many divisions are saved, or if Q is small then the
+crossproducts reduce to a small number.
+
+   The modular inverse used is calculated efficiently by 'binvert_limb'
+in 'gmp-impl.h'.  This does four multiplies for a 32-bit limb, or six
+for a 64-bit limb.  'tune/modlinv.c' has some alternate implementations
+that might suit processors better at bit twiddling than multiplying.
+
+   The sub-quadratic exact division described by Jebelean in "Exact
+Division with Karatsuba Complexity" is not currently implemented.  It
+uses a rearrangement similar to the divide and conquer for normal
+division (*note Divide and Conquer Division::), but operating from low
+to high.  A further possibility not currently implemented is
+"Bidirectional Exact Integer Division" by Krandick and Jebelean which
+forms quotient limbs from both the high and low ends of the dividend,
+and can halve once more the number of crossproducts needed in a 2NxN
+division.
+
+   A special case exact division by 3 exists in 'mpn_divexact_by3',
+supporting Toom-3 multiplication and 'mpq' canonicalizations.  It forms
+quotient digits with a multiply by the modular inverse of 3 (which is
+'0xAA..AAB') and uses two comparisons to determine a borrow for the next
+limb.  The multiplications don't need to be on the dependent chain, as
+long as the effect of the borrows is applied, which can help chips with
+pipelined multipliers.
+
diff --git a/third_party/gmp/doc/gmp.info-2 b/third_party/gmp/doc/gmp.info-2
new file mode 100644
index 0000000..de53785
--- /dev/null
+++ b/third_party/gmp/doc/gmp.info-2
Binary files differ
diff --git a/third_party/gmp/doc/gmp.texi b/third_party/gmp/doc/gmp.texi
new file mode 100644
index 0000000..a69d0e9
--- /dev/null
+++ b/third_party/gmp/doc/gmp.texi
@@ -0,0 +1,10989 @@
+\input texinfo    @c -*-texinfo-*-
+@c %**start of header
+@setfilename gmp.info
+@documentencoding ISO-8859-1
+@include version.texi
+@settitle GNU MP @value{VERSION}
+@synindex tp fn
+@iftex
+@afourpaper
+@end iftex
+@comment %**end of header
+
+@copying
+This manual describes how to install and use the GNU multiple precision
+arithmetic library, version @value{VERSION}.
+
+Copyright 1991, 1993-2016, 2018 Free Software Foundation, Inc.
+
+Permission is granted to copy, distribute and/or modify this document under
+the terms of the GNU Free Documentation License, Version 1.3 or any later
+version published by the Free Software Foundation; with no Invariant Sections,
+with the Front-Cover Texts being ``A GNU Manual'', and with the Back-Cover
+Texts being ``You have freedom to copy and modify this GNU Manual, like GNU
+software''.  A copy of the license is included in
+@ref{GNU Free Documentation License}.
+@end copying
+@c  Note the @ref above must be on one line, a line break in an @ref within
+@c  @copying will bomb in recent texinfo.tex (eg. 2004-04-07.08 which comes
+@c  with texinfo 4.7), with messages about missing @endcsname.
+
+
+@c  Texinfo version 4.2 or up will be needed to process this file.
+@c
+@c  The version number and edition number are taken from version.texi provided
+@c  by automake (note that it's regenerated only if you configure with
+@c  --enable-maintainer-mode).
+@c
+@c  Notes discussing the present version number of GMP in relation to previous
+@c  ones (for instance in the "Compatibility" section) must be updated at
+@c  manually though.
+@c
+@c  @cindex entries have been made for function categories and programming
+@c  topics.  The "mpn" section is not included in this, because a beginner
+@c  looking for "GCD" or something is only going to be confused by pointers to
+@c  low level routines.
+@c
+@c  @cindex entries are present for processors and systems when there's
+@c  particular notes concerning them, but not just for everything GMP
+@c  supports.
+@c
+@c  Index entries for files use @code rather than @file, @samp or @option,
+@c  since the latter come out with quotes in TeX, which are nice in the text
+@c  but don't look so good in index columns.
+@c
+@c  Tex:
+@c
+@c  A suitable texinfo.tex is supplied, a newer one should work equally well.
+@c
+@c  HTML:
+@c
+@c  Nothing special is done for links to external manuals, they just come out
+@c  in the usual makeinfo style, eg. "../libc/Locales.html".  If you have
+@c  local copies of such manuals then this is a good thing, if not then you
+@c  may want to search-and-replace to some online source.
+@c
+
+@dircategory GNU libraries
+@direntry
+* gmp: (gmp).                   GNU Multiple Precision Arithmetic Library.
+@end direntry
+
+@c  html <meta name="description" content="...">
+@documentdescription
+How to install and use the GNU multiple precision arithmetic library, version @value{VERSION}.
+@end documentdescription
+
+@c smallbook
+@finalout
+@setchapternewpage on
+
+@ifnottex
+@node Top, Copying, (dir), (dir)
+@top GNU MP
+@end ifnottex
+
+@iftex
+@titlepage
+@title GNU MP
+@subtitle The GNU Multiple Precision Arithmetic Library
+@subtitle Edition @value{EDITION}
+@subtitle @value{UPDATED}
+
+@author by Torbj@"orn Granlund and the GMP development team
+@c @email{tg@@gmplib.org}
+
+@c Include the Distribution inside the titlepage so
+@c that headings are turned off.
+
+@tex
+\global\parindent=0pt
+\global\parskip=8pt
+\global\baselineskip=13pt
+@end tex
+
+@page
+@vskip 0pt plus 1filll
+@end iftex
+
+@insertcopying
+@ifnottex
+@sp 1
+@end ifnottex
+
+@iftex
+@end titlepage
+@headings double
+@end iftex
+
+@c  Don't bother with contents for html, the menus seem adequate.
+@ifnothtml
+@contents
+@end ifnothtml
+
+@menu
+* Copying::                    GMP Copying Conditions (LGPL).
+* Introduction to GMP::        Brief introduction to GNU MP.
+* Installing GMP::             How to configure and compile the GMP library.
+* GMP Basics::                 What every GMP user should know.
+* Reporting Bugs::             How to usefully report bugs.
+* Integer Functions::          Functions for arithmetic on signed integers.
+* Rational Number Functions::  Functions for arithmetic on rational numbers.
+* Floating-point Functions::   Functions for arithmetic on floats.
+* Low-level Functions::        Fast functions for natural numbers.
+* Random Number Functions::    Functions for generating random numbers.
+* Formatted Output::           @code{printf} style output.
+* Formatted Input::            @code{scanf} style input.
+* C++ Class Interface::        Class wrappers around GMP types.
+* Custom Allocation::          How to customize the internal allocation.
+* Language Bindings::          Using GMP from other languages.
+* Algorithms::                 What happens behind the scenes.
+* Internals::                  How values are represented behind the scenes.
+
+* Contributors::               Who brings you this library?
+* References::                 Some useful papers and books to read.
+* GNU Free Documentation License::
+* Concept Index::
+* Function Index::
+@end menu
+
+
+@c  @m{T,N} is $T$ in tex or @math{N} otherwise.  Commas in N or T don't work,
+@c  but @C{} can be used instead.
+@iftex
+@macro m {T,N}
+@tex$\T\$@end tex
+@end macro
+@end iftex
+@ifnottex
+@macro m {T,N}
+@math{\N\}
+@end macro
+@end ifnottex
+
+@c  @mm{T,N} is $T$ tex and html and @math{N} in info.  Commas in N or T don't
+@c  work, but @C{} can be used instead.
+@iftex
+@macro mm {T,N}
+@tex$\T\$@end tex
+@end macro
+@end iftex
+
+@ifhtml
+@macro mm {T,N}
+@math{\T\}
+@end macro
+@end ifhtml
+
+@ifinfo
+@macro mm {T,N}
+@math{\N\}
+@end macro
+@end ifinfo
+
+
+@macro C {}
+,
+@end macro
+
+@c  @ms{V,N} is $V_N$ in tex or just vn otherwise.  This suits simple
+@c  subscripts like @ms{x,0}.
+@iftex
+@macro ms {V,N}
+@tex$\V\_{\N\}$@end tex
+@end macro
+@end iftex
+@ifnottex
+@macro ms {V,N}
+\V\\N\
+@end macro
+@end ifnottex
+
+@c  @nicode{S} is plain S in info, or @code{S} elsewhere.  This can be used
+@c  when the quotes that @code{} gives in info aren't wanted, but the
+@c  fontification in tex or html is wanted.  Doesn't work as @nicode{'\\0'}
+@c  though (gives two backslashes in tex).
+@ifinfo
+@macro nicode {S}
+\S\
+@end macro
+@end ifinfo
+@ifnotinfo
+@macro nicode {S}
+@code{\S\}
+@end macro
+@end ifnotinfo
+
+@c  @nisamp{S} is plain S in info, or @samp{S} elsewhere.  This can be used
+@c  when the quotes that @samp{} gives in info aren't wanted, but the
+@c  fontification in tex or html is wanted.
+@ifinfo
+@macro nisamp {S}
+\S\
+@end macro
+@end ifinfo
+@ifnotinfo
+@macro nisamp {S}
+@samp{\S\}
+@end macro
+@end ifnotinfo
+
+@c  Usage: @GMPtimes{}
+@c  Give either \times or the word "times".
+@tex
+\gdef\GMPtimes{\times}
+@end tex
+@ifnottex
+@macro GMPtimes
+times
+@end macro
+@end ifnottex
+
+@c  Usage: @GMPmultiply{}
+@c  Give * in info, or nothing in tex.
+@tex
+\gdef\GMPmultiply{}
+@end tex
+@ifnottex
+@macro GMPmultiply
+*
+@end macro
+@end ifnottex
+
+@c  Usage: @GMPabs{x}
+@c  Give either |x| in tex, or abs(x) in info or html.
+@tex
+\gdef\GMPabs#1{|#1|}
+@end tex
+@ifnottex
+@macro GMPabs {X}
+@abs{}(\X\)
+@end macro
+@end ifnottex
+
+@c  Usage: @GMPfloor{x}
+@c  Give either \lfloor x\rfloor in tex, or floor(x) in info or html.
+@tex
+\gdef\GMPfloor#1{\lfloor #1\rfloor}
+@end tex
+@ifnottex
+@macro GMPfloor {X}
+floor(\X\)
+@end macro
+@end ifnottex
+
+@c  Usage: @GMPceil{x}
+@c  Give either \lceil x\rceil in tex, or ceil(x) in info or html.
+@tex
+\gdef\GMPceil#1{\lceil #1 \rceil}
+@end tex
+@ifnottex
+@macro GMPceil {X}
+ceil(\X\)
+@end macro
+@end ifnottex
+
+@c  Math operators already available in tex, made available in info too.
+@c  For example @bmod{} can be used in both tex and info.
+@ifnottex
+@macro bmod
+mod
+@end macro
+@macro gcd
+gcd
+@end macro
+@macro ge
+>=
+@end macro
+@macro le
+<=
+@end macro
+@macro log
+log
+@end macro
+@macro min
+min
+@end macro
+@macro leftarrow
+<-
+@end macro
+@macro rightarrow
+->
+@end macro
+@end ifnottex
+
+@c  New math operators.
+@c  @abs{} can be used in both tex and info, or just \abs in tex.
+@tex
+\gdef\abs{\mathop{\rm abs}}
+@end tex
+@ifnottex
+@macro abs
+abs
+@end macro
+@end ifnottex
+
+@c  @cross{} is a \times symbol in tex, or an "x" in info.  In tex it works
+@c  inside or outside $ $.
+@tex
+\gdef\cross{\ifmmode\times\else$\times$\fi}
+@end tex
+@ifnottex
+@macro cross
+x
+@end macro
+@end ifnottex
+
+@c  @times{} made available as a "*" in info and html (already works in tex).
+@ifnottex
+@macro times
+*
+@end macro
+@end ifnottex
+
+@c  Usage: @W{text}
+@c  Like @w{} but working in math mode too.
+@tex
+\gdef\W#1{\ifmmode{#1}\else\w{#1}\fi}
+@end tex
+@ifnottex
+@macro W {S}
+@w{\S\}
+@end macro
+@end ifnottex
+
+@c  Usage: \GMPdisplay{text}
+@c  Put the given text in an @display style indent, but without turning off
+@c  paragraph reflow etc.
+@tex
+\gdef\GMPdisplay#1{%
+\noindent
+\advance\leftskip by \lispnarrowing
+#1\par}
+@end tex
+
+@c  Usage: \GMPhat
+@c  A new \hat that will work in math mode, unlike the texinfo redefined
+@c  version.
+@tex
+\gdef\GMPhat{\mathaccent"705E}
+@end tex
+
+@c  Usage: \GMPraise{text}
+@c  For use in a $ $ math expression as an alternative to "^".  This is good
+@c  for @code{} in an exponent, since there seems to be no superscript font
+@c  for that.
+@tex
+\gdef\GMPraise#1{\mskip0.5\thinmuskip\hbox{\raise0.8ex\hbox{#1}}}
+@end tex
+
+@c  Usage: @texlinebreak{}
+@c  A line break as per @*, but only in tex.
+@iftex
+@macro texlinebreak
+@*
+@end macro
+@end iftex
+@ifnottex
+@macro texlinebreak
+@end macro
+@end ifnottex
+
+@c  Usage: @maybepagebreak
+@c  Allow tex to insert a page break, if it feels the urge.
+@c  Normally blocks of @deftypefun/funx are kept together, which can lead to
+@c  some poor page break positioning if it's a big block, like the sets of
+@c  division functions etc.
+@tex
+\gdef\maybepagebreak{\penalty0}
+@end tex
+@ifnottex
+@macro maybepagebreak
+@end macro
+@end ifnottex
+
+@c  Usage: @GMPreftop{info,title}
+@c  Usage: @GMPpxreftop{info,title}
+@c
+@c  Like @ref{} and @pxref{}, but designed for a reference to the top of a
+@c  document, not a particular section.  The TeX output for plain @ref insists
+@c  on printing a particular section, GMPreftop gives just the title.
+@c
+@c  The texinfo manual recommends putting a likely section name in references
+@c  like this, eg. "Introduction", but it seems better to just give the title.
+@c
+@iftex
+@macro GMPreftop{info,title}
+@i{\title\}
+@end macro
+@macro GMPpxreftop{info,title}
+see @i{\title\}
+@end macro
+@end iftex
+@c
+@ifnottex
+@macro GMPreftop{info,title}
+@ref{Top,\title\,\title\,\info\,\title\}
+@end macro
+@macro GMPpxreftop{info,title}
+@pxref{Top,\title\,\title\,\info\,\title\}
+@end macro
+@end ifnottex
+
+
+@node Copying, Introduction to GMP, Top, Top
+@comment  node-name, next, previous,  up
+@unnumbered GNU MP Copying Conditions
+@cindex Copying conditions
+@cindex Conditions for copying GNU MP
+@cindex License conditions
+
+This library is @dfn{free}; this means that everyone is free to use it and
+free to redistribute it on a free basis.  The library is not in the public
+domain; it is copyrighted and there are restrictions on its distribution, but
+these restrictions are designed to permit everything that a good cooperating
+citizen would want to do.  What is not allowed is to try to prevent others
+from further sharing any version of this library that they might get from
+you.@refill
+
+Specifically, we want to make sure that you have the right to give away copies
+of the library, that you receive source code or else can get it if you want
+it, that you can change this library or use pieces of it in new free programs,
+and that you know you can do these things.@refill
+
+To make sure that everyone has such rights, we have to forbid you to deprive
+anyone else of these rights.  For example, if you distribute copies of the GNU
+MP library, you must give the recipients all the rights that you have.  You
+must make sure that they, too, receive or can get the source code.  And you
+must tell them their rights.@refill
+
+Also, for our own protection, we must make certain that everyone finds out
+that there is no warranty for the GNU MP library.  If it is modified by
+someone else and passed on, we want their recipients to know that what they
+have is not what we distributed, so that any problems introduced by others
+will not reflect on our reputation.@refill
+
+More precisely, the GNU MP library is dual licensed, under the conditions of
+the GNU Lesser General Public License version 3 (see
+@file{COPYING.LESSERv3}), or the GNU General Public License version 2 (see
+@file{COPYINGv2}). This is the recipient's choice, and the recipient also has
+the additional option of applying later versions of these licenses. (The
+reason for this dual licensing is to make it possible to use the library with
+programs which are licensed under GPL version 2, but which for historical or
+other reasons do not allow use under later versions of the GPL).
+
+Programs which are not part of the library itself, such as demonstration
+programs and the GMP testsuite, are licensed under the terms of the GNU
+General Public License version 3 (see @file{COPYINGv3}), or any later
+version.
+
+
+@node Introduction to GMP, Installing GMP, Copying, Top
+@comment  node-name,  next,  previous,  up
+@chapter Introduction to GNU MP
+@cindex Introduction
+
+GNU MP is a portable library written in C for arbitrary precision arithmetic
+on integers, rational numbers, and floating-point numbers.  It aims to provide
+the fastest possible arithmetic for all applications that need higher
+precision than is directly supported by the basic C types.
+
+Many applications use just a few hundred bits of precision; but some
+applications may need thousands or even millions of bits.  GMP is designed to
+give good performance for both, by choosing algorithms based on the sizes of
+the operands, and by carefully keeping the overhead at a minimum.
+
+The speed of GMP is achieved by using fullwords as the basic arithmetic type,
+by using sophisticated algorithms, by including carefully optimized assembly
+code for the most common inner loops for many different CPUs, and by a general
+emphasis on speed (as opposed to simplicity or elegance).
+
+There is assembly code for these CPUs:
+@cindex CPU types
+ARM Cortex-A9, Cortex-A15, and generic ARM,
+DEC Alpha 21064, 21164, and 21264,
+AMD K8 and K10 (sold under many brands, e.g. Athlon64, Phenom, Opteron)
+Bulldozer, and Bobcat,
+Intel Pentium, Pentium Pro/II/III, Pentium 4, Core2, Nehalem, Sandy bridge, Haswell, generic x86,
+Intel IA-64,
+Motorola/IBM PowerPC 32 and 64 such as POWER970, POWER5, POWER6, and POWER7,
+MIPS 32-bit and 64-bit,
+SPARC 32-bit ad 64-bit with special support for all UltraSPARC models.
+There is also assembly code for many obsolete CPUs.
+
+
+@cindex Home page
+@cindex Web page
+@noindent
+For up-to-date information on GMP, please see the GMP web pages at
+
+@display
+@uref{https://gmplib.org/}
+@end display
+
+@cindex Latest version of GMP
+@cindex Anonymous FTP of latest version
+@cindex FTP of latest version
+@noindent
+The latest version of the library is available at
+
+@display
+@uref{https://ftp.gnu.org/gnu/gmp/}
+@end display
+
+Many sites around the world mirror @samp{ftp.gnu.org}, please use a mirror
+near you, see @uref{https://www.gnu.org/order/ftp.html} for a full list.
+
+@cindex Mailing lists
+There are three public mailing lists of interest.  One for release
+announcements, one for general questions and discussions about usage of the GMP
+library and one for bug reports.  For more information, see
+
+@display
+@uref{https://gmplib.org/mailman/listinfo/}.
+@end display
+
+The proper place for bug reports is @email{gmp-bugs@@gmplib.org}.  See
+@ref{Reporting Bugs} for information about reporting bugs.
+
+@sp 1
+@section How to use this Manual
+@cindex About this manual
+
+Everyone should read @ref{GMP Basics}.  If you need to install the library
+yourself, then read @ref{Installing GMP}.  If you have a system with multiple
+ABIs, then read @ref{ABI and ISA}, for the compiler options that must be used
+on applications.
+
+The rest of the manual can be used for later reference, although it is
+probably a good idea to glance through it.
+
+
+@node Installing GMP, GMP Basics, Introduction to GMP, Top
+@comment  node-name,  next,  previous,  up
+@chapter Installing GMP
+@cindex Installing GMP
+@cindex Configuring GMP
+@cindex Building GMP
+
+GMP has an autoconf/automake/libtool based configuration system.  On a
+Unix-like system a basic build can be done with
+
+@example
+./configure
+make
+@end example
+
+@noindent
+Some self-tests can be run with
+
+@example
+make check
+@end example
+
+@noindent
+And you can install (under @file{/usr/local} by default) with
+
+@example
+make install
+@end example
+
+If you experience problems, please report them to @email{gmp-bugs@@gmplib.org}.
+See @ref{Reporting Bugs}, for information on what to include in useful bug
+reports.
+
+@menu
+* Build Options::
+* ABI and ISA::
+* Notes for Package Builds::
+* Notes for Particular Systems::
+* Known Build Problems::
+* Performance optimization::
+@end menu
+
+
+@node Build Options, ABI and ISA, Installing GMP, Installing GMP
+@section Build Options
+@cindex Build options
+
+All the usual autoconf configure options are available, run @samp{./configure
+--help} for a summary.  The file @file{INSTALL.autoconf} has some generic
+installation information too.
+
+@table @asis
+@item Tools
+@cindex Non-Unix systems
+@samp{configure} requires various Unix-like tools.  See @ref{Notes for
+Particular Systems}, for some options on non-Unix systems.
+
+It might be possible to build without the help of @samp{configure}, certainly
+all the code is there, but unfortunately you'll be on your own.
+
+@item Build Directory
+@cindex Build directory
+To compile in a separate build directory, @command{cd} to that directory, and
+prefix the configure command with the path to the GMP source directory.  For
+example
+
+@example
+cd /my/build/dir
+/my/sources/gmp-@value{VERSION}/configure
+@end example
+
+Not all @samp{make} programs have the necessary features (@code{VPATH}) to
+support this.  In particular, SunOS and Slowaris @command{make} have bugs that
+make them unable to build in a separate directory.  Use GNU @command{make}
+instead.
+
+@item @option{--prefix} and @option{--exec-prefix}
+@cindex Prefix
+@cindex Exec prefix
+@cindex Install prefix
+@cindex @code{--prefix}
+@cindex @code{--exec-prefix}
+The @option{--prefix} option can be used in the normal way to direct GMP to
+install under a particular tree.  The default is @samp{/usr/local}.
+
+@option{--exec-prefix} can be used to direct architecture-dependent files like
+@file{libgmp.a} to a different location.  This can be used to share
+architecture-independent parts like the documentation, but separate the
+dependent parts.  Note however that @file{gmp.h} is
+architecture-dependent since it encodes certain aspects of @file{libgmp}, so
+it will be necessary to ensure both @file{$prefix/include} and
+@file{$exec_prefix/include} are available to the compiler.
+
+@item @option{--disable-shared}, @option{--disable-static}
+@cindex @code{--disable-shared}
+@cindex @code{--disable-static}
+By default both shared and static libraries are built (where possible), but
+one or other can be disabled.  Shared libraries result in smaller executables
+and permit code sharing between separate running processes, but on some CPUs
+are slightly slower, having a small cost on each function call.
+
+@item Native Compilation, @option{--build=CPU-VENDOR-OS}
+@cindex Native compilation
+@cindex Build system
+@cindex @code{--build}
+For normal native compilation, the system can be specified with
+@samp{--build}.  By default @samp{./configure} uses the output from running
+@samp{./config.guess}.  On some systems @samp{./config.guess} can determine
+the exact CPU type, on others it will be necessary to give it explicitly.  For
+example,
+
+@example
+./configure --build=ultrasparc-sun-solaris2.7
+@end example
+
+In all cases the @samp{OS} part is important, since it controls how libtool
+generates shared libraries.  Running @samp{./config.guess} is the simplest way
+to see what it should be, if you don't know already.
+
+@item Cross Compilation, @option{--host=CPU-VENDOR-OS}
+@cindex Cross compiling
+@cindex Host system
+@cindex @code{--host}
+When cross-compiling, the system used for compiling is given by @samp{--build}
+and the system where the library will run is given by @samp{--host}.  For
+example when using a FreeBSD Athlon system to build GNU/Linux m68k binaries,
+
+@example
+./configure --build=athlon-pc-freebsd3.5 --host=m68k-mac-linux-gnu
+@end example
+
+Compiler tools are sought first with the host system type as a prefix.  For
+example @command{m68k-mac-linux-gnu-ranlib} is tried, then plain
+@command{ranlib}.  This makes it possible for a set of cross-compiling tools
+to co-exist with native tools.  The prefix is the argument to @samp{--host},
+and this can be an alias, such as @samp{m68k-linux}.  But note that tools
+don't have to be setup this way, it's enough to just have a @env{PATH} with a
+suitable cross-compiling @command{cc} etc.
+
+Compiling for a different CPU in the same family as the build system is a form
+of cross-compilation, though very possibly this would merely be special
+options on a native compiler.  In any case @samp{./configure} avoids depending
+on being able to run code on the build system, which is important when
+creating binaries for a newer CPU since they very possibly won't run on the
+build system.
+
+In all cases the compiler must be able to produce an executable (of whatever
+format) from a standard C @code{main}.  Although only object files will go to
+make up @file{libgmp}, @samp{./configure} uses linking tests for various
+purposes, such as determining what functions are available on the host system.
+
+Currently a warning is given unless an explicit @samp{--build} is used when
+cross-compiling, because it may not be possible to correctly guess the build
+system type if the @env{PATH} has only a cross-compiling @command{cc}.
+
+Note that the @samp{--target} option is not appropriate for GMP@.  It's for use
+when building compiler tools, with @samp{--host} being where they will run,
+and @samp{--target} what they'll produce code for.  Ordinary programs or
+libraries like GMP are only interested in the @samp{--host} part, being where
+they'll run.  (Some past versions of GMP used @samp{--target} incorrectly.)
+
+@item CPU types
+@cindex CPU types
+In general, if you want a library that runs as fast as possible, you should
+configure GMP for the exact CPU type your system uses.  However, this may mean
+the binaries won't run on older members of the family, and might run slower on
+other members, older or newer.  The best idea is always to build GMP for the
+exact machine type you intend to run it on.
+
+The following CPUs have specific support.  See @file{configure.ac} for details
+of what code and compiler options they select.
+
+@itemize @bullet
+
+@c Keep this formatting, it's easy to read and it can be grepped to
+@c automatically test that CPUs listed get through ./config.sub
+
+@item
+Alpha:
+@nisamp{alpha},
+@nisamp{alphaev5},
+@nisamp{alphaev56},
+@nisamp{alphapca56},
+@nisamp{alphapca57},
+@nisamp{alphaev6},
+@nisamp{alphaev67},
+@nisamp{alphaev68}
+@nisamp{alphaev7}
+
+@item
+Cray:
+@nisamp{c90},
+@nisamp{j90},
+@nisamp{t90},
+@nisamp{sv1}
+
+@item
+HPPA:
+@nisamp{hppa1.0},
+@nisamp{hppa1.1},
+@nisamp{hppa2.0},
+@nisamp{hppa2.0n},
+@nisamp{hppa2.0w},
+@nisamp{hppa64}
+
+@item
+IA-64:
+@nisamp{ia64},
+@nisamp{itanium},
+@nisamp{itanium2}
+
+@item
+MIPS:
+@nisamp{mips},
+@nisamp{mips3},
+@nisamp{mips64}
+
+@item
+Motorola:
+@nisamp{m68k},
+@nisamp{m68000},
+@nisamp{m68010},
+@nisamp{m68020},
+@nisamp{m68030},
+@nisamp{m68040},
+@nisamp{m68060},
+@nisamp{m68302},
+@nisamp{m68360},
+@nisamp{m88k},
+@nisamp{m88110}
+
+@item
+POWER:
+@nisamp{power},
+@nisamp{power1},
+@nisamp{power2},
+@nisamp{power2sc}
+
+@item
+PowerPC:
+@nisamp{powerpc},
+@nisamp{powerpc64},
+@nisamp{powerpc401},
+@nisamp{powerpc403},
+@nisamp{powerpc405},
+@nisamp{powerpc505},
+@nisamp{powerpc601},
+@nisamp{powerpc602},
+@nisamp{powerpc603},
+@nisamp{powerpc603e},
+@nisamp{powerpc604},
+@nisamp{powerpc604e},
+@nisamp{powerpc620},
+@nisamp{powerpc630},
+@nisamp{powerpc740},
+@nisamp{powerpc7400},
+@nisamp{powerpc7450},
+@nisamp{powerpc750},
+@nisamp{powerpc801},
+@nisamp{powerpc821},
+@nisamp{powerpc823},
+@nisamp{powerpc860},
+@nisamp{powerpc970}
+
+@item
+SPARC:
+@nisamp{sparc},
+@nisamp{sparcv8},
+@nisamp{microsparc},
+@nisamp{supersparc},
+@nisamp{sparcv9},
+@nisamp{ultrasparc},
+@nisamp{ultrasparc2},
+@nisamp{ultrasparc2i},
+@nisamp{ultrasparc3},
+@nisamp{sparc64}
+
+@item
+x86 family:
+@nisamp{i386},
+@nisamp{i486},
+@nisamp{i586},
+@nisamp{pentium},
+@nisamp{pentiummmx},
+@nisamp{pentiumpro},
+@nisamp{pentium2},
+@nisamp{pentium3},
+@nisamp{pentium4},
+@nisamp{k6},
+@nisamp{k62},
+@nisamp{k63},
+@nisamp{athlon},
+@nisamp{amd64},
+@nisamp{viac3},
+@nisamp{viac32}
+
+@item
+Other:
+@nisamp{arm},
+@nisamp{sh},
+@nisamp{sh2},
+@nisamp{vax},
+@end itemize
+
+CPUs not listed will use generic C code.
+
+@item Generic C Build
+@cindex Generic C
+If some of the assembly code causes problems, or if otherwise desired, the
+generic C code can be selected with the configure @option{--disable-assembly}.
+
+Note that this will run quite slowly, but it should be portable and should at
+least make it possible to get something running if all else fails.
+
+@item Fat binary, @option{--enable-fat}
+@cindex Fat binary
+@cindex @code{--enable-fat}
+Using @option{--enable-fat} selects a ``fat binary'' build on x86, where
+optimized low level subroutines are chosen at runtime according to the CPU
+detected.  This means more code, but gives good performance on all x86 chips.
+(This option might become available for more architectures in the future.)
+
+@item @option{ABI}
+@cindex ABI
+On some systems GMP supports multiple ABIs (application binary interfaces),
+meaning data type sizes and calling conventions.  By default GMP chooses the
+best ABI available, but a particular ABI can be selected.  For example
+
+@example
+./configure --host=mips64-sgi-irix6 ABI=n32
+@end example
+
+See @ref{ABI and ISA}, for the available choices on relevant CPUs, and what
+applications need to do.
+
+@item @option{CC}, @option{CFLAGS}
+@cindex C compiler
+@cindex @code{CC}
+@cindex @code{CFLAGS}
+By default the C compiler used is chosen from among some likely candidates,
+with @command{gcc} normally preferred if it's present.  The usual
+@samp{CC=whatever} can be passed to @samp{./configure} to choose something
+different.
+
+For various systems, default compiler flags are set based on the CPU and
+compiler.  The usual @samp{CFLAGS="-whatever"} can be passed to
+@samp{./configure} to use something different or to set good flags for systems
+GMP doesn't otherwise know.
+
+The @samp{CC} and @samp{CFLAGS} used are printed during @samp{./configure},
+and can be found in each generated @file{Makefile}.  This is the easiest way
+to check the defaults when considering changing or adding something.
+
+Note that when @samp{CC} and @samp{CFLAGS} are specified on a system
+supporting multiple ABIs it's important to give an explicit
+@samp{ABI=whatever}, since GMP can't determine the ABI just from the flags and
+won't be able to select the correct assembly code.
+
+If just @samp{CC} is selected then normal default @samp{CFLAGS} for that
+compiler will be used (if GMP recognises it).  For example @samp{CC=gcc} can
+be used to force the use of GCC, with default flags (and default ABI).
+
+@item @option{CPPFLAGS}
+@cindex @code{CPPFLAGS}
+Any flags like @samp{-D} defines or @samp{-I} includes required by the
+preprocessor should be set in @samp{CPPFLAGS} rather than @samp{CFLAGS}.
+Compiling is done with both @samp{CPPFLAGS} and @samp{CFLAGS}, but
+preprocessing uses just @samp{CPPFLAGS}.  This distinction is because most
+preprocessors won't accept all the flags the compiler does.  Preprocessing is
+done separately in some configure tests.
+
+@item @option{CC_FOR_BUILD}
+@cindex @code{CC_FOR_BUILD}
+Some build-time programs are compiled and run to generate host-specific data
+tables.  @samp{CC_FOR_BUILD} is the compiler used for this.  It doesn't need
+to be in any particular ABI or mode, it merely needs to generate executables
+that can run.  The default is to try the selected @samp{CC} and some likely
+candidates such as @samp{cc} and @samp{gcc}, looking for something that works.
+
+No flags are used with @samp{CC_FOR_BUILD} because a simple invocation like
+@samp{cc foo.c} should be enough.  If some particular options are required
+they can be included as for instance @samp{CC_FOR_BUILD="cc -whatever"}.
+
+@item C++ Support, @option{--enable-cxx}
+@cindex C++ support
+@cindex @code{--enable-cxx}
+C++ support in GMP can be enabled with @samp{--enable-cxx}, in which case a
+C++ compiler will be required.  As a convenience @samp{--enable-cxx=detect}
+can be used to enable C++ support only if a compiler can be found.  The C++
+support consists of a library @file{libgmpxx.la} and header file
+@file{gmpxx.h} (@pxref{Headers and Libraries}).
+
+A separate @file{libgmpxx.la} has been adopted rather than having C++ objects
+within @file{libgmp.la} in order to ensure dynamic linked C programs aren't
+bloated by a dependency on the C++ standard library, and to avoid any chance
+that the C++ compiler could be required when linking plain C programs.
+
+@file{libgmpxx.la} will use certain internals from @file{libgmp.la} and can
+only be expected to work with @file{libgmp.la} from the same GMP version.
+Future changes to the relevant internals will be accompanied by renaming, so a
+mismatch will cause unresolved symbols rather than perhaps mysterious
+misbehaviour.
+
+In general @file{libgmpxx.la} will be usable only with the C++ compiler that
+built it, since name mangling and runtime support are usually incompatible
+between different compilers.
+
+@item @option{CXX}, @option{CXXFLAGS}
+@cindex C++ compiler
+@cindex @code{CXX}
+@cindex @code{CXXFLAGS}
+When C++ support is enabled, the C++ compiler and its flags can be set with
+variables @samp{CXX} and @samp{CXXFLAGS} in the usual way.  The default for
+@samp{CXX} is the first compiler that works from a list of likely candidates,
+with @command{g++} normally preferred when available.  The default for
+@samp{CXXFLAGS} is to try @samp{CFLAGS}, @samp{CFLAGS} without @samp{-g}, then
+for @command{g++} either @samp{-g -O2} or @samp{-O2}, or for other compilers
+@samp{-g} or nothing.  Trying @samp{CFLAGS} this way is convenient when using
+@samp{gcc} and @samp{g++} together, since the flags for @samp{gcc} will
+usually suit @samp{g++}.
+
+It's important that the C and C++ compilers match, meaning their startup and
+runtime support routines are compatible and that they generate code in the
+same ABI (if there's a choice of ABIs on the system).  @samp{./configure}
+isn't currently able to check these things very well itself, so for that
+reason @samp{--disable-cxx} is the default, to avoid a build failure due to a
+compiler mismatch.  Perhaps this will change in the future.
+
+Incidentally, it's normally not good enough to set @samp{CXX} to the same as
+@samp{CC}.  Although @command{gcc} for instance recognises @file{foo.cc} as
+C++ code, only @command{g++} will invoke the linker the right way when
+building an executable or shared library from C++ object files.
+
+@item Temporary Memory, @option{--enable-alloca=<choice>}
+@cindex Temporary memory
+@cindex Stack overflow
+@cindex @code{alloca}
+@cindex @code{--enable-alloca}
+GMP allocates temporary workspace using one of the following three methods,
+which can be selected with for instance
+@samp{--enable-alloca=malloc-reentrant}.
+
+@itemize @bullet
+@item
+@samp{alloca} - C library or compiler builtin.
+@item
+@samp{malloc-reentrant} - the heap, in a re-entrant fashion.
+@item
+@samp{malloc-notreentrant} - the heap, with global variables.
+@end itemize
+
+For convenience, the following choices are also available.
+@samp{--disable-alloca} is the same as @samp{no}.
+
+@itemize @bullet
+@item
+@samp{yes} - a synonym for @samp{alloca}.
+@item
+@samp{no} - a synonym for @samp{malloc-reentrant}.
+@item
+@samp{reentrant} - @code{alloca} if available, otherwise
+@samp{malloc-reentrant}.  This is the default.
+@item
+@samp{notreentrant} - @code{alloca} if available, otherwise
+@samp{malloc-notreentrant}.
+@end itemize
+
+@code{alloca} is reentrant and fast, and is recommended.  It actually allocates
+just small blocks on the stack; larger ones use malloc-reentrant.
+
+@samp{malloc-reentrant} is, as the name suggests, reentrant and thread safe,
+but @samp{malloc-notreentrant} is faster and should be used if reentrancy is
+not required.
+
+The two malloc methods in fact use the memory allocation functions selected by
+@code{mp_set_memory_functions}, these being @code{malloc} and friends by
+default.  @xref{Custom Allocation}.
+
+An additional choice @samp{--enable-alloca=debug} is available, to help when
+debugging memory related problems (@pxref{Debugging}).
+
+@item FFT Multiplication, @option{--disable-fft}
+@cindex FFT multiplication
+@cindex @code{--disable-fft}
+By default multiplications are done using Karatsuba, 3-way Toom, higher degree
+Toom, and Fermat FFT@.  The FFT is only used on large to very large operands
+and can be disabled to save code size if desired.
+
+@item Assertion Checking, @option{--enable-assert}
+@cindex Assertion checking
+@cindex @code{--enable-assert}
+This option enables some consistency checking within the library.  This can be
+of use while debugging, @pxref{Debugging}.
+
+@item Execution Profiling, @option{--enable-profiling=prof/gprof/instrument}
+@cindex Execution profiling
+@cindex @code{--enable-profiling}
+Enable profiling support, in one of various styles, @pxref{Profiling}.
+
+@item @option{MPN_PATH}
+@cindex @code{MPN_PATH}
+Various assembly versions of each mpn subroutines are provided.  For a given
+CPU, a search is made though a path to choose a version of each.  For example
+@samp{sparcv8} has
+
+@example
+MPN_PATH="sparc32/v8 sparc32 generic"
+@end example
+
+which means look first for v8 code, then plain sparc32 (which is v7), and
+finally fall back on generic C@.  Knowledgeable users with special requirements
+can specify a different path.  Normally this is completely unnecessary.
+
+@item Documentation
+@cindex Documentation formats
+@cindex Texinfo
+The source for the document you're now reading is @file{doc/gmp.texi}, in
+Texinfo format, see @GMPreftop{texinfo, Texinfo}.
+
+@cindex Postscript
+@cindex DVI
+@cindex PDF
+Info format @samp{doc/gmp.info} is included in the distribution.  The usual
+automake targets are available to make PostScript, DVI, PDF and HTML (these
+will require various @TeX{} and Texinfo tools).
+
+@cindex DocBook
+@cindex XML
+DocBook and XML can be generated by the Texinfo @command{makeinfo} program
+too, see @ref{makeinfo options,, Options for @command{makeinfo}, texinfo,
+Texinfo}.
+
+Some supplementary notes can also be found in the @file{doc} subdirectory.
+
+@end table
+
+
+@need 2000
+@node ABI and ISA, Notes for Package Builds, Build Options, Installing GMP
+@section ABI and ISA
+@cindex ABI
+@cindex Application Binary Interface
+@cindex ISA
+@cindex Instruction Set Architecture
+
+ABI (Application Binary Interface) refers to the calling conventions between
+functions, meaning what registers are used and what sizes the various C data
+types are.  ISA (Instruction Set Architecture) refers to the instructions and
+registers a CPU has available.
+
+Some 64-bit ISA CPUs have both a 64-bit ABI and a 32-bit ABI defined, the
+latter for compatibility with older CPUs in the family.  GMP supports some
+CPUs like this in both ABIs.  In fact within GMP @samp{ABI} means a
+combination of chip ABI, plus how GMP chooses to use it.  For example in some
+32-bit ABIs, GMP may support a limb as either a 32-bit @code{long} or a 64-bit
+@code{long long}.
+
+By default GMP chooses the best ABI available for a given system, and this
+generally gives significantly greater speed.  But an ABI can be chosen
+explicitly to make GMP compatible with other libraries, or particular
+application requirements.  For example,
+
+@example
+./configure ABI=32
+@end example
+
+In all cases it's vital that all object code used in a given program is
+compiled for the same ABI.
+
+Usually a limb is implemented as a @code{long}.  When a @code{long long} limb
+is used this is encoded in the generated @file{gmp.h}.  This is convenient for
+applications, but it does mean that @file{gmp.h} will vary, and can't be just
+copied around.  @file{gmp.h} remains compiler independent though, since all
+compilers for a particular ABI will be expected to use the same limb type.
+
+Currently no attempt is made to follow whatever conventions a system has for
+installing library or header files built for a particular ABI@.  This will
+probably only matter when installing multiple builds of GMP, and it might be
+as simple as configuring with a special @samp{libdir}, or it might require
+more than that.  Note that builds for different ABIs need to done separately,
+with a fresh @command{./configure} and @command{make} each.
+
+@sp 1
+@table @asis
+@need 1000
+@item AMD64 (@samp{x86_64})
+@cindex AMD64
+On AMD64 systems supporting both 32-bit and 64-bit modes for applications, the
+following ABI choices are available.
+
+@table @asis
+@item @samp{ABI=64}
+The 64-bit ABI uses 64-bit limbs and pointers and makes full use of the chip
+architecture.  This is the default.  Applications will usually not need
+special compiler flags, but for reference the option is
+
+@example
+gcc  -m64
+@end example
+
+@item @samp{ABI=32}
+The 32-bit ABI is the usual i386 conventions.  This will be slower, and is not
+recommended except for inter-operating with other code not yet 64-bit capable.
+Applications must be compiled with
+
+@example
+gcc  -m32
+@end example
+
+(In GCC 2.95 and earlier there's no @samp{-m32} option, it's the only mode.)
+
+@item @samp{ABI=x32}
+The x32 ABI uses 64-bit limbs but 32-bit pointers.  Like the 64-bit ABI, it
+makes full use of the chip's arithmetic capabilities.  This ABI is not
+supported by all operating systems.
+
+@example
+gcc  -mx32
+@end example
+
+@end table
+
+@sp 1
+@need 1000
+@item HPPA 2.0 (@samp{hppa2.0*}, @samp{hppa64})
+@cindex HPPA
+@cindex HP-UX
+@table @asis
+@item @samp{ABI=2.0w}
+The 2.0w ABI uses 64-bit limbs and pointers and is available on HP-UX 11 or
+up.  Applications must be compiled with
+
+@example
+gcc [built for 2.0w]
+cc  +DD64
+@end example
+
+@item @samp{ABI=2.0n}
+The 2.0n ABI means the 32-bit HPPA 1.0 ABI and all its normal calling
+conventions, but with 64-bit instructions permitted within functions.  GMP
+uses a 64-bit @code{long long} for a limb.  This ABI is available on hppa64
+GNU/Linux and on HP-UX 10 or higher.  Applications must be compiled with
+
+@example
+gcc [built for 2.0n]
+cc  +DA2.0 +e
+@end example
+
+Note that current versions of GCC (eg.@: 3.2) don't generate 64-bit
+instructions for @code{long long} operations and so may be slower than for
+2.0w.  (The GMP assembly code is the same though.)
+
+@item @samp{ABI=1.0}
+HPPA 2.0 CPUs can run all HPPA 1.0 and 1.1 code in the 32-bit HPPA 1.0 ABI@.
+No special compiler options are needed for applications.
+@end table
+
+All three ABIs are available for CPU types @samp{hppa2.0w}, @samp{hppa2.0} and
+@samp{hppa64}, but for CPU type @samp{hppa2.0n} only 2.0n or 1.0 are
+considered.
+
+Note that GCC on HP-UX has no options to choose between 2.0n and 2.0w modes,
+unlike HP @command{cc}.  Instead it must be built for one or the other ABI@.
+GMP will detect how it was built, and skip to the corresponding @samp{ABI}.
+
+@sp 1
+@need 1500
+@item IA-64 under HP-UX (@samp{ia64*-*-hpux*}, @samp{itanium*-*-hpux*})
+@cindex IA-64
+@cindex HP-UX
+HP-UX supports two ABIs for IA-64.  GMP performance is the same in both.
+
+@table @asis
+@item @samp{ABI=32}
+In the 32-bit ABI, pointers, @code{int}s and @code{long}s are 32 bits and GMP
+uses a 64 bit @code{long long} for a limb.  Applications can be compiled
+without any special flags since this ABI is the default in both HP C and GCC,
+but for reference the flags are
+
+@example
+gcc  -milp32
+cc   +DD32
+@end example
+
+@item @samp{ABI=64}
+In the 64-bit ABI, @code{long}s and pointers are 64 bits and GMP uses a
+@code{long} for a limb.  Applications must be compiled with
+
+@example
+gcc  -mlp64
+cc   +DD64
+@end example
+@end table
+
+On other IA-64 systems, GNU/Linux for instance, @samp{ABI=64} is the only
+choice.
+
+@sp 1
+@need 1000
+@item MIPS under IRIX 6 (@samp{mips*-*-irix[6789]})
+@cindex MIPS
+@cindex IRIX
+IRIX 6 always has a 64-bit MIPS 3 or better CPU, and supports ABIs o32, n32,
+and 64.  n32 or 64 are recommended, and GMP performance will be the same in
+each.  The default is n32.
+
+@table @asis
+@item @samp{ABI=o32}
+The o32 ABI is 32-bit pointers and integers, and no 64-bit operations.  GMP
+will be slower than in n32 or 64, this option only exists to support old
+compilers, eg.@: GCC 2.7.2.  Applications can be compiled with no special
+flags on an old compiler, or on a newer compiler with
+
+@example
+gcc  -mabi=32
+cc   -32
+@end example
+
+@item @samp{ABI=n32}
+The n32 ABI is 32-bit pointers and integers, but with a 64-bit limb using a
+@code{long long}.  Applications must be compiled with
+
+@example
+gcc  -mabi=n32
+cc   -n32
+@end example
+
+@item @samp{ABI=64}
+The 64-bit ABI is 64-bit pointers and integers.  Applications must be compiled
+with
+
+@example
+gcc  -mabi=64
+cc   -64
+@end example
+@end table
+
+Note that MIPS GNU/Linux, as of kernel version 2.2, doesn't have the necessary
+support for n32 or 64 and so only gets a 32-bit limb and the MIPS 2 code.
+
+@sp 1
+@need 1000
+@item PowerPC 64 (@samp{powerpc64}, @samp{powerpc620}, @samp{powerpc630}, @samp{powerpc970}, @samp{power4}, @samp{power5})
+@cindex PowerPC
+@table @asis
+@item @samp{ABI=mode64}
+@cindex AIX
+The AIX 64 ABI uses 64-bit limbs and pointers and is the default on PowerPC 64
+@samp{*-*-aix*} systems.  Applications must be compiled with
+
+@example
+gcc  -maix64
+xlc  -q64
+@end example
+
+On 64-bit GNU/Linux, BSD, and Mac OS X/Darwin systems, the applications must
+be compiled with
+
+@example
+gcc  -m64
+@end example
+
+@item @samp{ABI=mode32}
+The @samp{mode32} ABI uses a 64-bit @code{long long} limb but with the chip
+still in 32-bit mode and using 32-bit calling conventions.  This is the default
+for systems where the true 64-bit ABI is unavailable.  No special compiler
+options are typically needed for applications.  This ABI is not available under
+AIX.
+
+@item @samp{ABI=32}
+This is the basic 32-bit PowerPC ABI, with a 32-bit limb.  No special compiler
+options are needed for applications.
+@end table
+
+GMP's speed is greatest for the @samp{mode64} ABI, the @samp{mode32} ABI is 2nd
+best.  In @samp{ABI=32} only the 32-bit ISA is used and this doesn't make full
+use of a 64-bit chip.
+
+@sp 1
+@need 1000
+@item Sparc V9 (@samp{sparc64}, @samp{sparcv9}, @samp{ultrasparc*})
+@cindex Sparc V9
+@cindex Solaris
+@cindex Sun
+@table @asis
+@item @samp{ABI=64}
+The 64-bit V9 ABI is available on the various BSD sparc64 ports, recent
+versions of Sparc64 GNU/Linux, and Solaris 2.7 and up (when the kernel is in
+64-bit mode).  GCC 3.2 or higher, or Sun @command{cc} is required.  On
+GNU/Linux, depending on the default @command{gcc} mode, applications must be
+compiled with
+
+@example
+gcc  -m64
+@end example
+
+On Solaris applications must be compiled with
+
+@example
+gcc  -m64 -mptr64 -Wa,-xarch=v9 -mcpu=v9
+cc   -xarch=v9
+@end example
+
+On the BSD sparc64 systems no special options are required, since 64-bits is
+the only ABI available.
+
+@item @samp{ABI=32}
+For the basic 32-bit ABI, GMP still uses as much of the V9 ISA as it can.  In
+the Sun documentation this combination is known as ``v8plus''.  On GNU/Linux,
+depending on the default @command{gcc} mode, applications may need to be
+compiled with
+
+@example
+gcc  -m32
+@end example
+
+On Solaris, no special compiler options are required for applications, though
+using something like the following is recommended.  (@command{gcc} 2.8 and
+earlier only support @samp{-mv8} though.)
+
+@example
+gcc  -mv8plus
+cc   -xarch=v8plus
+@end example
+@end table
+
+GMP speed is greatest in @samp{ABI=64}, so it's the default where available.
+The speed is partly because there are extra registers available and partly
+because 64-bits is considered the more important case and has therefore had
+better code written for it.
+
+Don't be confused by the names of the @samp{-m} and @samp{-x} compiler
+options, they're called @samp{arch} but effectively control both ABI and ISA@.
+
+On Solaris 2.6 and earlier, only @samp{ABI=32} is available since the kernel
+doesn't save all registers.
+
+On Solaris 2.7 with the kernel in 32-bit mode, a normal native build will
+reject @samp{ABI=64} because the resulting executables won't run.
+@samp{ABI=64} can still be built if desired by making it look like a
+cross-compile, for example
+
+@example
+./configure --build=none --host=sparcv9-sun-solaris2.7 ABI=64
+@end example
+@end table
+
+
+@need 2000
+@node Notes for Package Builds, Notes for Particular Systems, ABI and ISA, Installing GMP
+@section Notes for Package Builds
+@cindex Build notes for binary packaging
+@cindex Packaged builds
+
+GMP should present no great difficulties for packaging in a binary
+distribution.
+
+@cindex Libtool versioning
+@cindex Shared library versioning
+Libtool is used to build the library and @samp{-version-info} is set
+appropriately, having started from @samp{3:0:0} in GMP 3.0 (@pxref{Versioning,
+Library interface versions, Library interface versions, libtool, GNU
+Libtool}).
+
+The GMP 4 series will be upwardly binary compatible in each release and will
+be upwardly binary compatible with all of the GMP 3 series.  Additional
+function interfaces may be added in each release, so on systems where libtool
+versioning is not fully checked by the loader an auxiliary mechanism may be
+needed to express that a dynamic linked application depends on a new enough
+GMP.
+
+An auxiliary mechanism may also be needed to express that @file{libgmpxx.la}
+(from @option{--enable-cxx}, @pxref{Build Options}) requires @file{libgmp.la}
+from the same GMP version, since this is not done by the libtool versioning,
+nor otherwise.  A mismatch will result in unresolved symbols from the linker,
+or perhaps the loader.
+
+When building a package for a CPU family, care should be taken to use
+@samp{--host} (or @samp{--build}) to choose the least common denominator among
+the CPUs which might use the package.  For example this might mean plain
+@samp{sparc} (meaning V7) for SPARCs.
+
+For x86s, @option{--enable-fat} sets things up for a fat binary build, making a
+runtime selection of optimized low level routines.  This is a good choice for
+packaging to run on a range of x86 chips.
+
+Users who care about speed will want GMP built for their exact CPU type, to
+make best use of the available optimizations.  Providing a way to suitably
+rebuild a package may be useful.  This could be as simple as making it
+possible for a user to omit @samp{--build} (and @samp{--host}) so
+@samp{./config.guess} will detect the CPU@.  But a way to manually specify a
+@samp{--build} will be wanted for systems where @samp{./config.guess} is
+inexact.
+
+On systems with multiple ABIs, a packaged build will need to decide which
+among the choices is to be provided, see @ref{ABI and ISA}.  A given run of
+@samp{./configure} etc will only build one ABI@.  If a second ABI is also
+required then a second run of @samp{./configure} etc must be made, starting
+from a clean directory tree (@samp{make distclean}).
+
+As noted under ``ABI and ISA'', currently no attempt is made to follow system
+conventions for install locations that vary with ABI, such as
+@file{/usr/lib/sparcv9} for @samp{ABI=64} as opposed to @file{/usr/lib} for
+@samp{ABI=32}.  A package build can override @samp{libdir} and other standard
+variables as necessary.
+
+Note that @file{gmp.h} is a generated file, and will be architecture and ABI
+dependent.  When attempting to install two ABIs simultaneously it will be
+important that an application compile gets the correct @file{gmp.h} for its
+desired ABI@.  If compiler include paths don't vary with ABI options then it
+might be necessary to create a @file{/usr/include/gmp.h} which tests
+preprocessor symbols and chooses the correct actual @file{gmp.h}.
+
+
+@need 2000
+@node Notes for Particular Systems, Known Build Problems, Notes for Package Builds, Installing GMP
+@section Notes for Particular Systems
+@cindex Build notes for particular systems
+@cindex Particular systems
+@cindex Systems
+@table @asis
+
+@c This section is more or less meant for notes about performance or about
+@c build problems that have been worked around but might leave a user
+@c scratching their head.  Fun with different ABIs on a system belongs in the
+@c above section.
+
+@item AIX 3 and 4
+@cindex AIX
+On systems @samp{*-*-aix[34]*} shared libraries are disabled by default, since
+some versions of the native @command{ar} fail on the convenience libraries
+used.  A shared build can be attempted with
+
+@example
+./configure --enable-shared --disable-static
+@end example
+
+Note that the @samp{--disable-static} is necessary because in a shared build
+libtool makes @file{libgmp.a} a symlink to @file{libgmp.so}, apparently for
+the benefit of old versions of @command{ld} which only recognise @file{.a},
+but unfortunately this is done even if a fully functional @command{ld} is
+available.
+
+@item ARM
+@cindex ARM
+On systems @samp{arm*-*-*}, versions of GCC up to and including 2.95.3 have a
+bug in unsigned division, giving wrong results for some operands.  GMP
+@samp{./configure} will demand GCC 2.95.4 or later.
+
+@item Compaq C++
+@cindex Compaq C++
+Compaq C++ on OSF 5.1 has two flavours of @code{iostream}, a standard one and
+an old pre-standard one (see @samp{man iostream_intro}).  GMP can only use the
+standard one, which unfortunately is not the default but must be selected by
+defining @code{__USE_STD_IOSTREAM}.  Configure with for instance
+
+@example
+./configure --enable-cxx CPPFLAGS=-D__USE_STD_IOSTREAM
+@end example
+
+@item Floating Point Mode
+@cindex Floating point mode
+@cindex Hardware floating point mode
+@cindex Precision of hardware floating point
+@cindex x87
+On some systems, the hardware floating point has a control mode which can set
+all operations to be done in a particular precision, for instance single,
+double or extended on x86 systems (x87 floating point).  The GMP functions
+involving a @code{double} cannot be expected to operate to their full
+precision when the hardware is in single precision mode.  Of course this
+affects all code, including application code, not just GMP.
+
+@item FreeBSD 7.x, 8.x, 9.0, 9.1, 9.2
+@cindex FreeBSD
+@command{m4} in these releases of FreeBSD has an eval function which ignores
+its 2nd and 3rd arguments, which makes it unsuitable for @file{.asm} file
+processing.  @samp{./configure} will detect the problem and either abort or
+choose another m4 in the @env{PATH}.  The bug is fixed in FreeBSD 9.3 and 10.0,
+so either upgrade or use GNU m4.  Note that the FreeBSD package system installs
+GNU m4 under the name @samp{gm4}, which GMP cannot guess.
+
+@item FreeBSD 7.x, 8.x, 9.x
+@cindex FreeBSD
+GMP releases starting with 6.0 do not support @samp{ABI=32} on FreeBSD/amd64
+prior to release 10.0 of the system.  The cause is a broken @code{limits.h},
+which GMP no longer works around.
+
+@item MS-DOS and MS Windows
+@cindex MS-DOS
+@cindex MS Windows
+@cindex Windows
+@cindex Cygwin
+@cindex DJGPP
+@cindex MINGW
+On an MS-DOS system DJGPP can be used to build GMP, and on an MS Windows
+system Cygwin, DJGPP and MINGW can be used.  All three are excellent ports of
+GCC and the various GNU tools.
+
+@display
+@uref{https://www.cygwin.com/}
+@uref{http://www.delorie.com/djgpp/}
+@uref{http://www.mingw.org/}
+@end display
+
+@cindex Interix
+@cindex Services for Unix
+Microsoft also publishes an Interix ``Services for Unix'' which can be used to
+build GMP on Windows (with a normal @samp{./configure}), but it's not free
+software.
+
+@item MS Windows DLLs
+@cindex DLLs
+@cindex MS Windows
+@cindex Windows
+On systems @samp{*-*-cygwin*}, @samp{*-*-mingw*} and @samp{*-*-pw32*} by
+default GMP builds only a static library, but a DLL can be built instead using
+
+@example
+./configure --disable-static --enable-shared
+@end example
+
+Static and DLL libraries can't both be built, since certain export directives
+in @file{gmp.h} must be different.
+
+A MINGW DLL build of GMP can be used with Microsoft C@.  Libtool doesn't
+install a @file{.lib} format import library, but it can be created with MS
+@command{lib} as follows, and copied to the install directory.  Similarly for
+@file{libmp} and @file{libgmpxx}.
+
+@example
+cd .libs
+lib /def:libgmp-3.dll.def /out:libgmp-3.lib
+@end example
+
+MINGW uses the C runtime library @samp{msvcrt.dll} for I/O, so applications
+wanting to use the GMP I/O routines must be compiled with @samp{cl /MD} to do
+the same.  If one of the other C runtime library choices provided by MS C is
+desired then the suggestion is to use the GMP string functions and confine I/O
+to the application.
+
+@item Motorola 68k CPU Types
+@cindex 68000
+@samp{m68k} is taken to mean 68000.  @samp{m68020} or higher will give a
+performance boost on applicable CPUs.  @samp{m68360} can be used for CPU32
+series chips.  @samp{m68302} can be used for ``Dragonball'' series chips,
+though this is merely a synonym for @samp{m68000}.
+
+@item NetBSD 5.x
+@cindex NetBSD
+@command{m4} in these releases of NetBSD has an eval function which ignores its
+2nd and 3rd arguments, which makes it unsuitable for @file{.asm} file
+processing.  @samp{./configure} will detect the problem and either abort or
+choose another m4 in the @env{PATH}.  The bug is fixed in NetBSD 6, so either
+upgrade or use GNU m4.  Note that the NetBSD package system installs GNU m4
+under the name @samp{gm4}, which GMP cannot guess.
+
+@item OpenBSD 2.6
+@cindex OpenBSD
+@command{m4} in this release of OpenBSD has a bug in @code{eval} that makes it
+unsuitable for @file{.asm} file processing.  @samp{./configure} will detect
+the problem and either abort or choose another m4 in the @env{PATH}.  The bug
+is fixed in OpenBSD 2.7, so either upgrade or use GNU m4.
+
+@item Power CPU Types
+@cindex Power/PowerPC
+In GMP, CPU types @samp{power*} and @samp{powerpc*} will each use instructions
+not available on the other, so it's important to choose the right one for the
+CPU that will be used.  Currently GMP has no assembly code support for using
+just the common instruction subset.  To get executables that run on both, the
+current suggestion is to use the generic C code (@option{--disable-assembly}),
+possibly with appropriate compiler options (like @samp{-mcpu=common} for
+@command{gcc}).  CPU @samp{rs6000} (which is not a CPU but a family of
+workstations) is accepted by @file{config.sub}, but is currently equivalent to
+@option{--disable-assembly}.
+
+@item Sparc CPU Types
+@cindex Sparc
+@samp{sparcv8} or @samp{supersparc} on relevant systems will give a
+significant performance increase over the V7 code selected by plain
+@samp{sparc}.
+
+@item Sparc App Regs
+@cindex Sparc
+The GMP assembly code for both 32-bit and 64-bit Sparc clobbers the
+``application registers'' @code{g2}, @code{g3} and @code{g4}, the same way
+that the GCC default @samp{-mapp-regs} does (@pxref{SPARC Options,, SPARC
+Options, gcc, Using the GNU Compiler Collection (GCC)}).
+
+This makes that code unsuitable for use with the special V9
+@samp{-mcmodel=embmedany} (which uses @code{g4} as a data segment pointer), and
+for applications wanting to use those registers for special purposes.  In these
+cases the only suggestion currently is to build GMP with
+@option{--disable-assembly} to avoid the assembly code.
+
+@item SunOS 4
+@cindex SunOS
+@command{/usr/bin/m4} lacks various features needed to process @file{.asm}
+files, and instead @samp{./configure} will automatically use
+@command{/usr/5bin/m4}, which we believe is always available (if not then use
+GNU m4).
+
+@item x86 CPU Types
+@cindex x86
+@cindex 80x86
+@cindex i386
+@samp{i586}, @samp{pentium} or @samp{pentiummmx} code is good for its intended
+P5 Pentium chips, but quite slow when run on Intel P6 class chips (PPro, P-II,
+P-III)@.  @samp{i386} is a better choice when making binaries that must run on
+both.
+
+@item x86 MMX and SSE2 Code
+@cindex MMX
+@cindex SSE2
+If the CPU selected has MMX code but the assembler doesn't support it, a
+warning is given and non-MMX code is used instead.  This will be an inferior
+build, since the MMX code that's present is there because it's faster than the
+corresponding plain integer code.  The same applies to SSE2.
+
+Old versions of @samp{gas} don't support MMX instructions, in particular
+version 1.92.3 that comes with FreeBSD 2.2.8 or the more recent OpenBSD 3.1
+doesn't.
+
+Solaris 2.6 and 2.7 @command{as} generate incorrect object code for register
+to register @code{movq} instructions, and so can't be used for MMX code.
+Install a recent @command{gas} if MMX code is wanted on these systems.
+@end table
+
+
+@need 2000
+@node Known Build Problems, Performance optimization, Notes for Particular Systems, Installing GMP
+@section Known Build Problems
+@cindex Build problems known
+
+@c This section is more or less meant for known build problems that are not
+@c otherwise worked around and require some sort of manual intervention.
+
+You might find more up-to-date information at @uref{https://gmplib.org/}.
+
+@table @asis
+@item Compiler link options
+The version of libtool currently in use rather aggressively strips compiler
+options when linking a shared library.  This will hopefully be relaxed in the
+future, but for now if this is a problem the suggestion is to create a little
+script to hide them, and for instance configure with
+
+@example
+./configure CC=gcc-with-my-options
+@end example
+
+@item DJGPP (@samp{*-*-msdosdjgpp*})
+@cindex DJGPP
+The DJGPP port of @command{bash} 2.03 is unable to run the @samp{configure}
+script, it exits silently, having died writing a preamble to
+@file{config.log}.  Use @command{bash} 2.04 or higher.
+
+@samp{make all} was found to run out of memory during the final
+@file{libgmp.la} link on one system tested, despite having 64Mb available.
+Running @samp{make libgmp.la} directly helped, perhaps recursing into the
+various subdirectories uses up memory.
+
+@item GNU binutils @command{strip} prior to 2.12
+@cindex Stripped libraries
+@cindex Binutils @command{strip}
+@cindex GNU @command{strip}
+@command{strip} from GNU binutils 2.11 and earlier should not be used on the
+static libraries @file{libgmp.a} and @file{libmp.a} since it will discard all
+but the last of multiple archive members with the same name, like the three
+versions of @file{init.o} in @file{libgmp.a}.  Binutils 2.12 or higher can be
+used successfully.
+
+The shared libraries @file{libgmp.so} and @file{libmp.so} are not affected by
+this and any version of @command{strip} can be used on them.
+
+@item @command{make} syntax error
+@cindex SCO
+@cindex IRIX
+On certain versions of SCO OpenServer 5 and IRIX 6.5 the native @command{make}
+is unable to handle the long dependencies list for @file{libgmp.la}.  The
+symptom is a ``syntax error'' on the following line of the top-level
+@file{Makefile}.
+
+@example
+libgmp.la: $(libgmp_la_OBJECTS) $(libgmp_la_DEPENDENCIES)
+@end example
+
+Either use GNU Make, or as a workaround remove
+@code{$(libgmp_la_DEPENDENCIES)} from that line (which will make the initial
+build work, but if any recompiling is done @file{libgmp.la} might not be
+rebuilt).
+
+@item MacOS X (@samp{*-*-darwin*})
+@cindex MacOS X
+@cindex Darwin
+Libtool currently only knows how to create shared libraries on MacOS X using
+the native @command{cc} (which is a modified GCC), not a plain GCC@.  A
+static-only build should work though (@samp{--disable-shared}).
+
+@item NeXT prior to 3.3
+@cindex NeXT
+The system compiler on old versions of NeXT was a massacred and old GCC, even
+if it called itself @file{cc}.  This compiler cannot be used to build GMP, you
+need to get a real GCC, and install that.  (NeXT may have fixed this in
+release 3.3 of their system.)
+
+@item POWER and PowerPC
+@cindex Power/PowerPC
+Bugs in GCC 2.7.2 (and 2.6.3) mean it can't be used to compile GMP on POWER or
+PowerPC@.  If you want to use GCC for these machines, get GCC 2.7.2.1 (or
+later).
+
+@item Sequent Symmetry
+@cindex Sequent Symmetry
+Use the GNU assembler instead of the system assembler, since the latter has
+serious bugs.
+
+@item Solaris 2.6
+@cindex Solaris
+The system @command{sed} prints an error ``Output line too long'' when libtool
+builds @file{libgmp.la}.  This doesn't seem to cause any obvious ill effects,
+but GNU @command{sed} is recommended, to avoid any doubt.
+
+@item Sparc Solaris 2.7 with gcc 2.95.2 in @samp{ABI=32}
+@cindex Solaris
+A shared library build of GMP seems to fail in this combination, it builds but
+then fails the tests, apparently due to some incorrect data relocations within
+@code{gmp_randinit_lc_2exp_size}.  The exact cause is unknown,
+@samp{--disable-shared} is recommended.
+@end table
+
+
+@need 2000
+@node Performance optimization, , Known Build Problems, Installing GMP
+@section Performance optimization
+@cindex Optimizing performance
+
+@c At some point, this should perhaps move to a separate chapter on optimizing
+@c performance.
+
+For optimal performance, build GMP for the exact CPU type of the target
+computer, see @ref{Build Options}.
+
+Unlike what is the case for most other programs, the compiler typically
+doesn't matter much, since GMP uses assembly language for the most critical
+operation.
+
+In particular for long-running GMP applications, and applications demanding
+extremely large numbers, building and running the @code{tuneup} program in the
+@file{tune} subdirectory, can be important.  For example,
+
+@example
+cd tune
+make tuneup
+./tuneup
+@end example
+
+will generate better contents for the @file{gmp-mparam.h} parameter file.
+
+To use the results, put the output in the file indicated in the
+@samp{Parameters for ...} header.  Then recompile from scratch.
+
+The @code{tuneup} program takes one useful parameter, @samp{-f NNN}, which
+instructs the program how long to check FFT multiply parameters.  If you're
+going to use GMP for extremely large numbers, you may want to run @code{tuneup}
+with a large NNN value.
+
+
+@node GMP Basics, Reporting Bugs, Installing GMP, Top
+@comment  node-name,  next,  previous,  up
+@chapter GMP Basics
+@cindex Basics
+
+@strong{Using functions, macros, data types, etc.@: not documented in this
+manual is strongly discouraged.  If you do so your application is guaranteed
+to be incompatible with future versions of GMP.}
+
+@menu
+* Headers and Libraries::
+* Nomenclature and Types::
+* Function Classes::
+* Variable Conventions::
+* Parameter Conventions::
+* Memory Management::
+* Reentrancy::
+* Useful Macros and Constants::
+* Compatibility with older versions::
+* Demonstration Programs::
+* Efficiency::
+* Debugging::
+* Profiling::
+* Autoconf::
+* Emacs::
+@end menu
+
+@node Headers and Libraries, Nomenclature and Types, GMP Basics, GMP Basics
+@section Headers and Libraries
+@cindex Headers
+
+@cindex @file{gmp.h}
+@cindex Include files
+@cindex @code{#include}
+All declarations needed to use GMP are collected in the include file
+@file{gmp.h}.  It is designed to work with both C and C++ compilers.
+
+@example
+#include <gmp.h>
+@end example
+
+@cindex @code{stdio.h}
+Note however that prototypes for GMP functions with @code{FILE *} parameters
+are only provided if @code{<stdio.h>} is included too.
+
+@example
+#include <stdio.h>
+#include <gmp.h>
+@end example
+
+@cindex @code{stdarg.h}
+Likewise @code{<stdarg.h>} is required for prototypes with @code{va_list}
+parameters, such as @code{gmp_vprintf}.  And @code{<obstack.h>} for prototypes
+with @code{struct obstack} parameters, such as @code{gmp_obstack_printf}, when
+available.
+
+@cindex Libraries
+@cindex Linking
+@cindex @code{libgmp}
+All programs using GMP must link against the @file{libgmp} library.  On a
+typical Unix-like system this can be done with @samp{-lgmp}, for example
+
+@example
+gcc myprogram.c -lgmp
+@end example
+
+@cindex @code{libgmpxx}
+GMP C++ functions are in a separate @file{libgmpxx} library.  This is built
+and installed if C++ support has been enabled (@pxref{Build Options}).  For
+example,
+
+@example
+g++ mycxxprog.cc -lgmpxx -lgmp
+@end example
+
+@cindex Libtool
+GMP is built using Libtool and an application can use that to link if desired,
+@GMPpxreftop{libtool, GNU Libtool}.
+
+If GMP has been installed to a non-standard location then it may be necessary
+to use @samp{-I} and @samp{-L} compiler options to point to the right
+directories, and some sort of run-time path for a shared library.
+
+
+@node Nomenclature and Types, Function Classes, Headers and Libraries, GMP Basics
+@section Nomenclature and Types
+@cindex Nomenclature
+@cindex Types
+
+@cindex Integer
+@tindex @code{mpz_t}
+In this manual, @dfn{integer} usually means a multiple precision integer, as
+defined by the GMP library.  The C data type for such integers is @code{mpz_t}.
+Here are some examples of how to declare such integers:
+
+@example
+mpz_t sum;
+
+struct foo @{ mpz_t x, y; @};
+
+mpz_t vec[20];
+@end example
+
+@cindex Rational number
+@tindex @code{mpq_t}
+@dfn{Rational number} means a multiple precision fraction.  The C data type
+for these fractions is @code{mpq_t}.  For example:
+
+@example
+mpq_t quotient;
+@end example
+
+@cindex Floating-point number
+@tindex @code{mpf_t}
+@dfn{Floating point number} or @dfn{Float} for short, is an arbitrary precision
+mantissa with a limited precision exponent.  The C data type for such objects
+is @code{mpf_t}.  For example:
+
+@example
+mpf_t fp;
+@end example
+
+@tindex @code{mp_exp_t}
+The floating point functions accept and return exponents in the C type
+@code{mp_exp_t}.  Currently this is usually a @code{long}, but on some systems
+it's an @code{int} for efficiency.
+
+@cindex Limb
+@tindex @code{mp_limb_t}
+A @dfn{limb} means the part of a multi-precision number that fits in a single
+machine word.  (We chose this word because a limb of the human body is
+analogous to a digit, only larger, and containing several digits.)  Normally a
+limb is 32 or 64 bits.  The C data type for a limb is @code{mp_limb_t}.
+
+@tindex @code{mp_size_t}
+Counts of limbs of a multi-precision number represented in the C type
+@code{mp_size_t}.  Currently this is normally a @code{long}, but on some
+systems it's an @code{int} for efficiency, and on some systems it will be
+@code{long long} in the future.
+
+@tindex @code{mp_bitcnt_t}
+Counts of bits of a multi-precision number are represented in the C type
+@code{mp_bitcnt_t}.  Currently this is always an @code{unsigned long}, but on
+some systems it will be an @code{unsigned long long} in the future.
+
+@cindex Random state
+@tindex @code{gmp_randstate_t}
+@dfn{Random state} means an algorithm selection and current state data.  The C
+data type for such objects is @code{gmp_randstate_t}.  For example:
+
+@example
+gmp_randstate_t rstate;
+@end example
+
+Also, in general @code{mp_bitcnt_t} is used for bit counts and ranges, and
+@code{size_t} is used for byte or character counts.
+
+
+@node Function Classes, Variable Conventions, Nomenclature and Types, GMP Basics
+@section Function Classes
+@cindex Function classes
+
+There are six classes of functions in the GMP library:
+
+@enumerate
+@item
+Functions for signed integer arithmetic, with names beginning with
+@code{mpz_}.  The associated type is @code{mpz_t}.  There are about 150
+functions in this class.  (@pxref{Integer Functions})
+
+@item
+Functions for rational number arithmetic, with names beginning with
+@code{mpq_}.  The associated type is @code{mpq_t}.  There are about 35
+functions in this class, but the integer functions can be used for arithmetic
+on the numerator and denominator separately.  (@pxref{Rational Number
+Functions})
+
+@item
+Functions for floating-point arithmetic, with names beginning with
+@code{mpf_}.  The associated type is @code{mpf_t}.  There are about 70
+functions is this class.  (@pxref{Floating-point Functions})
+
+@item
+Fast low-level functions that operate on natural numbers.  These are used by
+the functions in the preceding groups, and you can also call them directly
+from very time-critical user programs.  These functions' names begin with
+@code{mpn_}.  The associated type is array of @code{mp_limb_t}.  There are
+about 60 (hard-to-use) functions in this class.  (@pxref{Low-level Functions})
+
+@item
+Miscellaneous functions.  Functions for setting up custom allocation and
+functions for generating random numbers.  (@pxref{Custom Allocation}, and
+@pxref{Random Number Functions})
+@end enumerate
+
+
+@node Variable Conventions, Parameter Conventions, Function Classes, GMP Basics
+@section Variable Conventions
+@cindex Variable conventions
+@cindex Conventions for variables
+
+GMP functions generally have output arguments before input arguments.  This
+notation is by analogy with the assignment operator.
+
+GMP lets you use the same variable for both input and output in one call.  For
+example, the main function for integer multiplication, @code{mpz_mul}, can be
+used to square @code{x} and put the result back in @code{x} with
+
+@example
+mpz_mul (x, x, x);
+@end example
+
+Before you can assign to a GMP variable, you need to initialize it by calling
+one of the special initialization functions.  When you're done with a
+variable, you need to clear it out, using one of the functions for that
+purpose.  Which function to use depends on the type of variable.  See the
+chapters on integer functions, rational number functions, and floating-point
+functions for details.
+
+A variable should only be initialized once, or at least cleared between each
+initialization.  After a variable has been initialized, it may be assigned to
+any number of times.
+
+For efficiency reasons, avoid excessive initializing and clearing.  In
+general, initialize near the start of a function and clear near the end.  For
+example,
+
+@example
+void
+foo (void)
+@{
+  mpz_t  n;
+  int    i;
+  mpz_init (n);
+  for (i = 1; i < 100; i++)
+    @{
+      mpz_mul (n, @dots{});
+      mpz_fdiv_q (n, @dots{});
+      @dots{}
+    @}
+  mpz_clear (n);
+@}
+@end example
+
+GMP types like @code{mpz_t} are implemented as one-element arrays of certain
+structures.  Declaring a variable creates an object with the fields GMP needs,
+but variables are normally manipulated by using the pointer to the object.  For
+both behavior and efficiency reasons, it is discouraged to make copies of the
+GMP object itself (either directly or via aggregate objects containing such GMP
+objects).  If copies are done, all of them must be used read-only; using a copy
+as the output of some function will invalidate all the other copies.  Note that
+the actual fields in each @code{mpz_t} etc are for internal use only and should
+not be accessed directly by code that expects to be compatible with future GMP
+releases.
+
+@node Parameter Conventions, Memory Management, Variable Conventions, GMP Basics
+@section Parameter Conventions
+@cindex Parameter conventions
+@cindex Conventions for parameters
+
+When a GMP variable is used as a function parameter, it's effectively a
+call-by-reference, meaning that when the function stores a value there it will
+change the original in the caller.  Parameters which are input-only can be
+designated @code{const} to provoke a compiler error or warning on attempting to
+modify them.
+
+When a function is going to return a GMP result, it should designate a
+parameter that it sets, like the library functions do.  More than one value
+can be returned by having more than one output parameter, again like the
+library functions.  A @code{return} of an @code{mpz_t} etc doesn't return the
+object, only a pointer, and this is almost certainly not what's wanted.
+
+Here's an example accepting an @code{mpz_t} parameter, doing a calculation,
+and storing the result to the indicated parameter.
+
+@example
+void
+foo (mpz_t result, const mpz_t param, unsigned long n)
+@{
+  unsigned long  i;
+  mpz_mul_ui (result, param, n);
+  for (i = 1; i < n; i++)
+    mpz_add_ui (result, result, i*7);
+@}
+
+int
+main (void)
+@{
+  mpz_t  r, n;
+  mpz_init (r);
+  mpz_init_set_str (n, "123456", 0);
+  foo (r, n, 20L);
+  gmp_printf ("%Zd\n", r);
+  return 0;
+@}
+@end example
+
+Our function @code{foo} works even if its caller passes the same variable for
+@code{param} and @code{result}, just like the library functions.  But
+sometimes it's tricky to make that work, and an application might not want to
+bother supporting that sort of thing.
+
+Since GMP types are implemented as one-element arrays, using a GMP variable as
+a parameter passes a pointer to the object. Hence the call-by-reference.
+
+
+@need 1000
+@node Memory Management, Reentrancy, Parameter Conventions, GMP Basics
+@section Memory Management
+@cindex Memory management
+
+The GMP types like @code{mpz_t} are small, containing only a couple of sizes,
+and pointers to allocated data.  Once a variable is initialized, GMP takes
+care of all space allocation.  Additional space is allocated whenever a
+variable doesn't have enough.
+
+@code{mpz_t} and @code{mpq_t} variables never reduce their allocated space.
+Normally this is the best policy, since it avoids frequent reallocation.
+Applications that need to return memory to the heap at some particular point
+can use @code{mpz_realloc2}, or clear variables no longer needed.
+
+@code{mpf_t} variables, in the current implementation, use a fixed amount of
+space, determined by the chosen precision and allocated at initialization, so
+their size doesn't change.
+
+All memory is allocated using @code{malloc} and friends by default, but this
+can be changed, see @ref{Custom Allocation}.  Temporary memory on the stack is
+also used (via @code{alloca}), but this can be changed at build-time if
+desired, see @ref{Build Options}.
+
+
+@node Reentrancy, Useful Macros and Constants, Memory Management, GMP Basics
+@section Reentrancy
+@cindex Reentrancy
+@cindex Thread safety
+@cindex Multi-threading
+
+@noindent
+GMP is reentrant and thread-safe, with some exceptions:
+
+@itemize @bullet
+@item
+If configured with @option{--enable-alloca=malloc-notreentrant} (or with
+@option{--enable-alloca=notreentrant} when @code{alloca} is not available),
+then naturally GMP is not reentrant.
+
+@item
+@code{mpf_set_default_prec} and @code{mpf_init} use a global variable for the
+selected precision.  @code{mpf_init2} can be used instead, and in the C++
+interface an explicit precision to the @code{mpf_class} constructor.
+
+@item
+@code{mpz_random} and the other old random number functions use a global
+random state and are hence not reentrant.  The newer random number functions
+that accept a @code{gmp_randstate_t} parameter can be used instead.
+
+@item
+@code{gmp_randinit} (obsolete) returns an error indication through a global
+variable, which is not thread safe.  Applications are advised to use
+@code{gmp_randinit_default} or @code{gmp_randinit_lc_2exp} instead.
+
+@item
+@code{mp_set_memory_functions} uses global variables to store the selected
+memory allocation functions.
+
+@item
+If the memory allocation functions set by a call to
+@code{mp_set_memory_functions} (or @code{malloc} and friends by default) are
+not reentrant, then GMP will not be reentrant either.
+
+@item
+If the standard I/O functions such as @code{fwrite} are not reentrant then the
+GMP I/O functions using them will not be reentrant either.
+
+@item
+It's safe for two threads to read from the same GMP variable simultaneously,
+but it's not safe for one to read while another might be writing, nor for
+two threads to write simultaneously.  It's not safe for two threads to
+generate a random number from the same @code{gmp_randstate_t} simultaneously,
+since this involves an update of that variable.
+@end itemize
+
+
+@need 2000
+@node Useful Macros and Constants, Compatibility with older versions, Reentrancy, GMP Basics
+@section Useful Macros and Constants
+@cindex Useful macros and constants
+@cindex Constants
+
+@deftypevr {Global Constant} {const int} mp_bits_per_limb
+@findex mp_bits_per_limb
+@cindex Bits per limb
+@cindex Limb size
+The number of bits per limb.
+@end deftypevr
+
+@defmac __GNU_MP_VERSION
+@defmacx __GNU_MP_VERSION_MINOR
+@defmacx __GNU_MP_VERSION_PATCHLEVEL
+@cindex Version number
+@cindex GMP version number
+The major and minor GMP version, and patch level, respectively, as integers.
+For GMP i.j, these numbers will be i, j, and 0, respectively.
+For GMP i.j.k, these numbers will be i, j, and k, respectively.
+@end defmac
+
+@deftypevr {Global Constant} {const char * const} gmp_version
+@findex gmp_version
+The GMP version number, as a null-terminated string, in the form ``i.j.k''.
+This release is @nicode{"@value{VERSION}"}.  Note that the format ``i.j'' was
+used, before version 4.3.0, when k was zero.
+@end deftypevr
+
+@defmac __GMP_CC
+@defmacx __GMP_CFLAGS
+The compiler and compiler flags, respectively, used when compiling GMP, as
+strings.
+@end defmac
+
+
+@node Compatibility with older versions, Demonstration Programs, Useful Macros and Constants, GMP Basics
+@section Compatibility with older versions
+@cindex Compatibility with older versions
+@cindex Past GMP versions
+@cindex Upward compatibility
+
+This version of GMP is upwardly binary compatible with all 5.x, 4.x, and 3.x
+versions, and upwardly compatible at the source level with all 2.x versions,
+with the following exceptions.
+
+@itemize @bullet
+@item
+@code{mpn_gcd} had its source arguments swapped as of GMP 3.0, for consistency
+with other @code{mpn} functions.
+
+@item
+@code{mpf_get_prec} counted precision slightly differently in GMP 3.0 and
+3.0.1, but in 3.1 reverted to the 2.x style.
+
+@item
+@code{mpn_bdivmod}, documented as preliminary in GMP 4, has been removed.
+@end itemize
+
+There are a number of compatibility issues between GMP 1 and GMP 2 that of
+course also apply when porting applications from GMP 1 to GMP 5.  Please
+see the GMP 2 manual for details.
+
+@c @item Integer division functions round the result differently.  The obsolete
+@c functions (@code{mpz_div}, @code{mpz_divmod}, @code{mpz_mdiv},
+@c @code{mpz_mdivmod}, etc) now all use floor rounding (i.e., they round the
+@c quotient towards
+@c @ifinfo
+@c @minus{}infinity).
+@c @end ifinfo
+@c @iftex
+@c @tex
+@c $-\infty$).
+@c @end tex
+@c @end iftex
+@c There are a lot of functions for integer division, giving the user better
+@c control over the rounding.
+
+@c @item The function @code{mpz_mod} now compute the true @strong{mod} function.
+
+@c @item The functions @code{mpz_powm} and @code{mpz_powm_ui} now use
+@c @strong{mod} for reduction.
+
+@c @item The assignment functions for rational numbers do no longer canonicalize
+@c their results.  In the case a non-canonical result could arise from an
+@c assignment, the user need to insert an explicit call to
+@c @code{mpq_canonicalize}.  This change was made for efficiency.
+
+@c @item Output generated by @code{mpz_out_raw} in this release cannot be read
+@c by @code{mpz_inp_raw} in previous releases.  This change was made for making
+@c the file format truly portable between machines with different word sizes.
+
+@c @item Several @code{mpn} functions have changed.  But they were intentionally
+@c undocumented in previous releases.
+
+@c @item The functions @code{mpz_cmp_ui}, @code{mpz_cmp_si}, and @code{mpq_cmp_ui}
+@c are now implemented as macros, and thereby sometimes evaluate their
+@c arguments multiple times.
+
+@c @item The functions @code{mpz_pow_ui} and @code{mpz_ui_pow_ui} now yield 1
+@c for 0^0.  (In version 1, they yielded 0.)
+
+@c In version 1 of the library, @code{mpq_set_den} handled negative
+@c denominators by copying the sign to the numerator.  That is no longer done.
+
+@c Pure assignment functions do not canonicalize the assigned variable.  It is
+@c the responsibility of the user to canonicalize the assigned variable before
+@c any arithmetic operations are performed on that variable.
+@c Note that this is an incompatible change from version 1 of the library.
+
+@c @end enumerate
+
+
+@need 1000
+@node Demonstration Programs, Efficiency, Compatibility with older versions, GMP Basics
+@section Demonstration programs
+@cindex Demonstration programs
+@cindex Example programs
+@cindex Sample programs
+The @file{demos} subdirectory has some sample programs using GMP@.  These
+aren't built or installed, but there's a @file{Makefile} with rules for them.
+For instance,
+
+@example
+make pexpr
+./pexpr 68^975+10
+@end example
+
+@noindent
+The following programs are provided
+
+@itemize @bullet
+@item
+@cindex Expression parsing demo
+@cindex Parsing expressions demo
+@samp{pexpr} is an expression evaluator, the program used on the GMP web page.
+@item
+@cindex Expression parsing demo
+@cindex Parsing expressions demo
+The @samp{calc} subdirectory has a similar but simpler evaluator using
+@command{lex} and @command{yacc}.
+@item
+@cindex Expression parsing demo
+@cindex Parsing expressions demo
+The @samp{expr} subdirectory is yet another expression evaluator, a library
+designed for ease of use within a C program.  See @file{demos/expr/README} for
+more information.
+@item
+@cindex Factorization demo
+@samp{factorize} is a Pollard-Rho factorization program.
+@item
+@samp{isprime} is a command-line interface to the @code{mpz_probab_prime_p}
+function.
+@item
+@samp{primes} counts or lists primes in an interval, using a sieve.
+@item
+@samp{qcn} is an example use of @code{mpz_kronecker_ui} to estimate quadratic
+class numbers.
+@item
+@cindex @code{perl}
+@cindex GMP Perl module
+@cindex Perl module
+The @samp{perl} subdirectory is a comprehensive perl interface to GMP@.  See
+@file{demos/perl/INSTALL} for more information.  Documentation is in POD
+format in @file{demos/perl/GMP.pm}.
+@end itemize
+
+As an aside, consideration has been given at various times to some sort of
+expression evaluation within the main GMP library.  Going beyond something
+minimal quickly leads to matters like user-defined functions, looping, fixnums
+for control variables, etc, which are considered outside the scope of GMP
+(much closer to language interpreters or compilers, @xref{Language Bindings}.)
+Something simple for program input convenience may yet be a possibility, a
+combination of the @file{expr} demo and the @file{pexpr} tree back-end
+perhaps.  But for now the above evaluators are offered as illustrations.
+
+
+@need 1000
+@node Efficiency, Debugging, Demonstration Programs, GMP Basics
+@section Efficiency
+@cindex Efficiency
+
+@table @asis
+@item Small Operands
+@cindex Small operands
+On small operands, the time for function call overheads and memory allocation
+can be significant in comparison to actual calculation.  This is unavoidable
+in a general purpose variable precision library, although GMP attempts to be
+as efficient as it can on both large and small operands.
+
+@item Static Linking
+@cindex Static linking
+On some CPUs, in particular the x86s, the static @file{libgmp.a} should be
+used for maximum speed, since the PIC code in the shared @file{libgmp.so} will
+have a small overhead on each function call and global data address.  For many
+programs this will be insignificant, but for long calculations there's a gain
+to be had.
+
+@item Initializing and Clearing
+@cindex Initializing and clearing
+Avoid excessive initializing and clearing of variables, since this can be
+quite time consuming, especially in comparison to otherwise fast operations
+like addition.
+
+A language interpreter might want to keep a free list or stack of
+initialized variables ready for use.  It should be possible to integrate
+something like that with a garbage collector too.
+
+@item Reallocations
+@cindex Reallocations
+An @code{mpz_t} or @code{mpq_t} variable used to hold successively increasing
+values will have its memory repeatedly @code{realloc}ed, which could be quite
+slow or could fragment memory, depending on the C library.  If an application
+can estimate the final size then @code{mpz_init2} or @code{mpz_realloc2} can
+be called to allocate the necessary space from the beginning
+(@pxref{Initializing Integers}).
+
+It doesn't matter if a size set with @code{mpz_init2} or @code{mpz_realloc2}
+is too small, since all functions will do a further reallocation if necessary.
+Badly overestimating memory required will waste space though.
+
+@item @code{2exp} Functions
+@cindex @code{2exp} functions
+It's up to an application to call functions like @code{mpz_mul_2exp} when
+appropriate.  General purpose functions like @code{mpz_mul} make no attempt to
+identify powers of two or other special forms, because such inputs will
+usually be very rare and testing every time would be wasteful.
+
+@item @code{ui} and @code{si} Functions
+@cindex @code{ui} and @code{si} functions
+The @code{ui} functions and the small number of @code{si} functions exist for
+convenience and should be used where applicable.  But if for example an
+@code{mpz_t} contains a value that fits in an @code{unsigned long} there's no
+need extract it and call a @code{ui} function, just use the regular @code{mpz}
+function.
+
+@item In-Place Operations
+@cindex In-place operations
+@code{mpz_abs}, @code{mpq_abs}, @code{mpf_abs}, @code{mpz_neg}, @code{mpq_neg}
+and @code{mpf_neg} are fast when used for in-place operations like
+@code{mpz_abs(x,x)}, since in the current implementation only a single field
+of @code{x} needs changing.  On suitable compilers (GCC for instance) this is
+inlined too.
+
+@code{mpz_add_ui}, @code{mpz_sub_ui}, @code{mpf_add_ui} and @code{mpf_sub_ui}
+benefit from an in-place operation like @code{mpz_add_ui(x,x,y)}, since
+usually only one or two limbs of @code{x} will need to be changed.  The same
+applies to the full precision @code{mpz_add} etc if @code{y} is small.  If
+@code{y} is big then cache locality may be helped, but that's all.
+
+@code{mpz_mul} is currently the opposite, a separate destination is slightly
+better.  A call like @code{mpz_mul(x,x,y)} will, unless @code{y} is only one
+limb, make a temporary copy of @code{x} before forming the result.  Normally
+that copying will only be a tiny fraction of the time for the multiply, so
+this is not a particularly important consideration.
+
+@code{mpz_set}, @code{mpq_set}, @code{mpq_set_num}, @code{mpf_set}, etc, make
+no attempt to recognise a copy of something to itself, so a call like
+@code{mpz_set(x,x)} will be wasteful.  Naturally that would never be written
+deliberately, but if it might arise from two pointers to the same object then
+a test to avoid it might be desirable.
+
+@example
+if (x != y)
+  mpz_set (x, y);
+@end example
+
+Note that it's never worth introducing extra @code{mpz_set} calls just to get
+in-place operations.  If a result should go to a particular variable then just
+direct it there and let GMP take care of data movement.
+
+@item Divisibility Testing (Small Integers)
+@cindex Divisibility testing
+@code{mpz_divisible_ui_p} and @code{mpz_congruent_ui_p} are the best functions
+for testing whether an @code{mpz_t} is divisible by an individual small
+integer.  They use an algorithm which is faster than @code{mpz_tdiv_ui}, but
+which gives no useful information about the actual remainder, only whether
+it's zero (or a particular value).
+
+However when testing divisibility by several small integers, it's best to take
+a remainder modulo their product, to save multi-precision operations.  For
+instance to test whether a number is divisible by any of 23, 29 or 31 take a
+remainder modulo @math{23@times{}29@times{}31 = 20677} and then test that.
+
+The division functions like @code{mpz_tdiv_q_ui} which give a quotient as well
+as a remainder are generally a little slower than the remainder-only functions
+like @code{mpz_tdiv_ui}.  If the quotient is only rarely wanted then it's
+probably best to just take a remainder and then go back and calculate the
+quotient if and when it's wanted (@code{mpz_divexact_ui} can be used if the
+remainder is zero).
+
+@item Rational Arithmetic
+@cindex Rational arithmetic
+The @code{mpq} functions operate on @code{mpq_t} values with no common factors
+in the numerator and denominator.  Common factors are checked-for and cast out
+as necessary.  In general, cancelling factors every time is the best approach
+since it minimizes the sizes for subsequent operations.
+
+However, applications that know something about the factorization of the
+values they're working with might be able to avoid some of the GCDs used for
+canonicalization, or swap them for divisions.  For example when multiplying by
+a prime it's enough to check for factors of it in the denominator instead of
+doing a full GCD@.  Or when forming a big product it might be known that very
+little cancellation will be possible, and so canonicalization can be left to
+the end.
+
+The @code{mpq_numref} and @code{mpq_denref} macros give access to the
+numerator and denominator to do things outside the scope of the supplied
+@code{mpq} functions.  @xref{Applying Integer Functions}.
+
+The canonical form for rationals allows mixed-type @code{mpq_t} and integer
+additions or subtractions to be done directly with multiples of the
+denominator.  This will be somewhat faster than @code{mpq_add}.  For example,
+
+@example
+/* mpq increment */
+mpz_add (mpq_numref(q), mpq_numref(q), mpq_denref(q));
+
+/* mpq += unsigned long */
+mpz_addmul_ui (mpq_numref(q), mpq_denref(q), 123UL);
+
+/* mpq -= mpz */
+mpz_submul (mpq_numref(q), mpq_denref(q), z);
+@end example
+
+@item Number Sequences
+@cindex Number sequences
+Functions like @code{mpz_fac_ui}, @code{mpz_fib_ui} and @code{mpz_bin_uiui}
+are designed for calculating isolated values.  If a range of values is wanted
+it's probably best to call to get a starting point and iterate from there.
+
+@item Text Input/Output
+@cindex Text input/output
+Hexadecimal or octal are suggested for input or output in text form.
+Power-of-2 bases like these can be converted much more efficiently than other
+bases, like decimal.  For big numbers there's usually nothing of particular
+interest to be seen in the digits, so the base doesn't matter much.
+
+Maybe we can hope octal will one day become the normal base for everyday use,
+as proposed by King Charles XII of Sweden and later reformers.
+@c Reference: Knuth volume 2 section 4.1, page 184 of second edition.  :-)
+@end table
+
+
+@node Debugging, Profiling, Efficiency, GMP Basics
+@section Debugging
+@cindex Debugging
+
+@table @asis
+@item Stack Overflow
+@cindex Stack overflow
+@cindex Segmentation violation
+@cindex Bus error
+Depending on the system, a segmentation violation or bus error might be the
+only indication of stack overflow.  See @samp{--enable-alloca} choices in
+@ref{Build Options}, for how to address this.
+
+In new enough versions of GCC, @samp{-fstack-check} may be able to ensure an
+overflow is recognised by the system before too much damage is done, or
+@samp{-fstack-limit-symbol} or @samp{-fstack-limit-register} may be able to
+add checking if the system itself doesn't do any (@pxref{Code Gen Options,,
+Options for Code Generation, gcc, Using the GNU Compiler Collection (GCC)}).
+These options must be added to the @samp{CFLAGS} used in the GMP build
+(@pxref{Build Options}), adding them just to an application will have no
+effect.  Note also they're a slowdown, adding overhead to each function call
+and each stack allocation.
+
+@item Heap Problems
+@cindex Heap problems
+@cindex Malloc problems
+The most likely cause of application problems with GMP is heap corruption.
+Failing to @code{init} GMP variables will have unpredictable effects, and
+corruption arising elsewhere in a program may well affect GMP@.  Initializing
+GMP variables more than once or failing to clear them will cause memory leaks.
+
+@cindex Malloc debugger
+In all such cases a @code{malloc} debugger is recommended.  On a GNU or BSD
+system the standard C library @code{malloc} has some diagnostic facilities,
+see @ref{Allocation Debugging,, Allocation Debugging, libc, The GNU C Library
+Reference Manual}, or @samp{man 3 malloc}.  Other possibilities, in no
+particular order, include
+
+@display
+@uref{http://cs.ecs.baylor.edu/~donahoo/tools/ccmalloc/}
+@uref{http://dmalloc.com/}
+@uref{https://wiki.gnome.org/Apps/MemProf}
+@end display
+
+The GMP default allocation routines in @file{memory.c} also have a simple
+sentinel scheme which can be enabled with @code{#define DEBUG} in that file.
+This is mainly designed for detecting buffer overruns during GMP development,
+but might find other uses.
+
+@item Stack Backtraces
+@cindex Stack backtrace
+On some systems the compiler options GMP uses by default can interfere with
+debugging.  In particular on x86 and 68k systems @samp{-fomit-frame-pointer}
+is used and this generally inhibits stack backtracing.  Recompiling without
+such options may help while debugging, though the usual caveats about it
+potentially moving a memory problem or hiding a compiler bug will apply.
+
+@item GDB, the GNU Debugger
+@cindex GDB
+@cindex GNU Debugger
+A sample @file{.gdbinit} is included in the distribution, showing how to call
+some undocumented dump functions to print GMP variables from within GDB@.  Note
+that these functions shouldn't be used in final application code since they're
+undocumented and may be subject to incompatible changes in future versions of
+GMP.
+
+@item Source File Paths
+GMP has multiple source files with the same name, in different directories.
+For example @file{mpz}, @file{mpq} and @file{mpf} each have an
+@file{init.c}.  If the debugger can't already determine the right one it may
+help to build with absolute paths on each C file.  One way to do that is to
+use a separate object directory with an absolute path to the source directory.
+
+@example
+cd /my/build/dir
+/my/source/dir/gmp-@value{VERSION}/configure
+@end example
+
+This works via @code{VPATH}, and might require GNU @command{make}.
+Alternately it might be possible to change the @code{.c.lo} rules
+appropriately.
+
+@item Assertion Checking
+@cindex Assertion checking
+The build option @option{--enable-assert} is available to add some consistency
+checks to the library (see @ref{Build Options}).  These are likely to be of
+limited value to most applications.  Assertion failures are just as likely to
+indicate memory corruption as a library or compiler bug.
+
+Applications using the low-level @code{mpn} functions, however, will benefit
+from @option{--enable-assert} since it adds checks on the parameters of most
+such functions, many of which have subtle restrictions on their usage.  Note
+however that only the generic C code has checks, not the assembly code, so
+@option{--disable-assembly} should be used for maximum checking.
+
+@item Temporary Memory Checking
+The build option @option{--enable-alloca=debug} arranges that each block of
+temporary memory in GMP is allocated with a separate call to @code{malloc} (or
+the allocation function set with @code{mp_set_memory_functions}).
+
+This can help a malloc debugger detect accesses outside the intended bounds,
+or detect memory not released.  In a normal build, on the other hand,
+temporary memory is allocated in blocks which GMP divides up for its own use,
+or may be allocated with a compiler builtin @code{alloca} which will go
+nowhere near any malloc debugger hooks.
+
+@item Maximum Debuggability
+To summarize the above, a GMP build for maximum debuggability would be
+
+@example
+./configure --disable-shared --enable-assert \
+  --enable-alloca=debug --disable-assembly CFLAGS=-g
+@end example
+
+For C++, add @samp{--enable-cxx CXXFLAGS=-g}.
+
+@item Checker
+@cindex Checker
+@cindex GCC Checker
+The GCC checker (@uref{https://savannah.nongnu.org/projects/checker/}) can be
+used with GMP@.  It contains a stub library which means GMP applications
+compiled with checker can use a normal GMP build.
+
+A build of GMP with checking within GMP itself can be made.  This will run
+very very slowly.  On GNU/Linux for example,
+
+@cindex @command{checkergcc}
+@example
+./configure --disable-assembly CC=checkergcc
+@end example
+
+@option{--disable-assembly} must be used, since the GMP assembly code doesn't
+support the checking scheme.  The GMP C++ features cannot be used, since
+current versions of checker (0.9.9.1) don't yet support the standard C++
+library.
+
+@item Valgrind
+@cindex Valgrind
+Valgrind (@uref{http://valgrind.org/}) is a memory checker for x86, ARM, MIPS,
+PowerPC, and S/390.  It translates and emulates machine instructions to do
+strong checks for uninitialized data (at the level of individual bits), memory
+accesses through bad pointers, and memory leaks.
+
+Valgrind does not always support every possible instruction, in particular
+ones recently added to an ISA.  Valgrind might therefore be incompatible with
+a recent GMP or even a less recent GMP which is compiled using a recent GCC.
+
+GMP's assembly code sometimes promotes a read of the limbs to some larger size,
+for efficiency.  GMP will do this even at the start and end of a multilimb
+operand, using naturally aligned operations on the larger type.  This may lead
+to benign reads outside of allocated areas, triggering complaints from
+Valgrind.  Valgrind's option @samp{--partial-loads-ok=yes} should help.
+
+@item Other Problems
+Any suspected bug in GMP itself should be isolated to make sure it's not an
+application problem, see @ref{Reporting Bugs}.
+@end table
+
+
+@node Profiling, Autoconf, Debugging, GMP Basics
+@section Profiling
+@cindex Profiling
+@cindex Execution profiling
+@cindex @code{--enable-profiling}
+
+Running a program under a profiler is a good way to find where it's spending
+most time and where improvements can be best sought.  The profiling choices
+for a GMP build are as follows.
+
+@table @asis
+@item @samp{--disable-profiling}
+The default is to add nothing special for profiling.
+
+It should be possible to just compile the mainline of a program with @code{-p}
+and use @command{prof} to get a profile consisting of timer-based sampling of
+the program counter.  Most of the GMP assembly code has the necessary symbol
+information.
+
+This approach has the advantage of minimizing interference with normal program
+operation, but on most systems the resolution of the sampling is quite low (10
+milliseconds for instance), requiring long runs to get accurate information.
+
+@item @samp{--enable-profiling=prof}
+@cindex @code{prof}
+Build with support for the system @command{prof}, which means @samp{-p} added
+to the @samp{CFLAGS}.
+
+This provides call counting in addition to program counter sampling, which
+allows the most frequently called routines to be identified, and an average
+time spent in each routine to be determined.
+
+The x86 assembly code has support for this option, but on other processors
+the assembly routines will be as if compiled without @samp{-p} and therefore
+won't appear in the call counts.
+
+On some systems, such as GNU/Linux, @samp{-p} in fact means @samp{-pg} and in
+this case @samp{--enable-profiling=gprof} described below should be used
+instead.
+
+@item @samp{--enable-profiling=gprof}
+@cindex @code{gprof}
+Build with support for @command{gprof}, which means @samp{-pg} added to the
+@samp{CFLAGS}.
+
+This provides call graph construction in addition to call counting and program
+counter sampling, which makes it possible to count calls coming from different
+locations.  For example the number of calls to @code{mpn_mul} from
+@code{mpz_mul} versus the number from @code{mpf_mul}.  The program counter
+sampling is still flat though, so only a total time in @code{mpn_mul} would be
+accumulated, not a separate amount for each call site.
+
+The x86 assembly code has support for this option, but on other processors
+the assembly routines will be as if compiled without @samp{-pg} and therefore
+not be included in the call counts.
+
+On x86 and m68k systems @samp{-pg} and @samp{-fomit-frame-pointer} are
+incompatible, so the latter is omitted from the default flags in that case,
+which might result in poorer code generation.
+
+Incidentally, it should be possible to use the @command{gprof} program with a
+plain @samp{--enable-profiling=prof} build.  But in that case only the
+@samp{gprof -p} flat profile and call counts can be expected to be valid, not
+the @samp{gprof -q} call graph.
+
+@item @samp{--enable-profiling=instrument}
+@cindex @code{-finstrument-functions}
+@cindex @code{instrument-functions}
+Build with the GCC option @samp{-finstrument-functions} added to the
+@samp{CFLAGS} (@pxref{Code Gen Options,, Options for Code Generation, gcc,
+Using the GNU Compiler Collection (GCC)}).
+
+This inserts special instrumenting calls at the start and end of each
+function, allowing exact timing and full call graph construction.
+
+This instrumenting is not normally a standard system feature and will require
+support from an external library, such as
+
+@cindex FunctionCheck
+@cindex fnccheck
+@display
+@uref{https://sourceforge.net/projects/fnccheck/}
+@end display
+
+This should be included in @samp{LIBS} during the GMP configure so that test
+programs will link.  For example,
+
+@example
+./configure --enable-profiling=instrument LIBS=-lfc
+@end example
+
+On a GNU system the C library provides dummy instrumenting functions, so
+programs compiled with this option will link.  In this case it's only
+necessary to ensure the correct library is added when linking an application.
+
+The x86 assembly code supports this option, but on other processors the
+assembly routines will be as if compiled without
+@samp{-finstrument-functions} meaning time spent in them will effectively be
+attributed to their caller.
+@end table
+
+
+@node Autoconf, Emacs, Profiling, GMP Basics
+@section Autoconf
+@cindex Autoconf
+
+Autoconf based applications can easily check whether GMP is installed.  The
+only thing to be noted is that GMP library symbols from version 3 onwards have
+prefixes like @code{__gmpz}.  The following therefore would be a simple test,
+
+@cindex @code{AC_CHECK_LIB}
+@example
+AC_CHECK_LIB(gmp, __gmpz_init)
+@end example
+
+This just uses the default @code{AC_CHECK_LIB} actions for found or not found,
+but an application that must have GMP would want to generate an error if not
+found.  For example,
+
+@example
+AC_CHECK_LIB(gmp, __gmpz_init, ,
+  [AC_MSG_ERROR([GNU MP not found, see https://gmplib.org/])])
+@end example
+
+If functions added in some particular version of GMP are required, then one of
+those can be used when checking.  For example @code{mpz_mul_si} was added in
+GMP 3.1,
+
+@example
+AC_CHECK_LIB(gmp, __gmpz_mul_si, ,
+  [AC_MSG_ERROR(
+  [GNU MP not found, or not 3.1 or up, see https://gmplib.org/])])
+@end example
+
+An alternative would be to test the version number in @file{gmp.h} using say
+@code{AC_EGREP_CPP}.  That would make it possible to test the exact version,
+if some particular sub-minor release is known to be necessary.
+
+In general it's recommended that applications should simply demand a new
+enough GMP rather than trying to provide supplements for features not
+available in past versions.
+
+Occasionally an application will need or want to know the size of a type at
+configuration or preprocessing time, not just with @code{sizeof} in the code.
+This can be done in the normal way with @code{mp_limb_t} etc, but GMP 4.0 or
+up is best for this, since prior versions needed certain @samp{-D} defines on
+systems using a @code{long long} limb.  The following would suit Autoconf 2.50
+or up,
+
+@example
+AC_CHECK_SIZEOF(mp_limb_t, , [#include <gmp.h>])
+@end example
+
+
+@node Emacs,  , Autoconf, GMP Basics
+@section Emacs
+@cindex Emacs
+@cindex @code{info-lookup-symbol}
+
+@key{C-h C-i} (@code{info-lookup-symbol}) is a good way to find documentation
+on C functions while editing (@pxref{Info Lookup, , Info Documentation Lookup,
+emacs, The Emacs Editor}).
+
+The GMP manual can be included in such lookups by putting the following in
+your @file{.emacs},
+
+@c  This isn't pretty, but there doesn't seem to be a better way (in emacs
+@c  21.2 at least).  info-lookup->mode-value could be used for the "assoc"s,
+@c  but that function isn't documented, whereas info-lookup-alist is.
+@c
+@example
+(eval-after-load "info-look"
+  '(let ((mode-value (assoc 'c-mode (assoc 'symbol info-lookup-alist))))
+     (setcar (nthcdr 3 mode-value)
+             (cons '("(gmp)Function Index" nil "^ -.* " "\\>")
+                   (nth 3 mode-value)))))
+@end example
+
+
+@node Reporting Bugs, Integer Functions, GMP Basics, Top
+@comment  node-name,  next,  previous,  up
+@chapter Reporting Bugs
+@cindex Reporting bugs
+@cindex Bug reporting
+
+If you think you have found a bug in the GMP library, please investigate it
+and report it.  We have made this library available to you, and it is not too
+much to ask you to report the bugs you find.
+
+Before you report a bug, check it's not already addressed in @ref{Known Build
+Problems}, or perhaps @ref{Notes for Particular Systems}.  You may also want
+to check @uref{https://gmplib.org/} for patches for this release.
+
+Please include the following in any report,
+
+@itemize @bullet
+@item
+The GMP version number, and if pre-packaged or patched then say so.
+
+@item
+A test program that makes it possible for us to reproduce the bug.  Include
+instructions on how to run the program.
+
+@item
+A description of what is wrong.  If the results are incorrect, in what way.
+If you get a crash, say so.
+
+@item
+If you get a crash, include a stack backtrace from the debugger if it's
+informative (@samp{where} in @command{gdb}, or @samp{$C} in @command{adb}).
+
+@item
+Please do not send core dumps, executables or @command{strace}s.
+
+@item
+The @samp{configure} options you used when building GMP, if any.
+
+@item
+The output from @samp{configure}, as printed to stdout, with any options used.
+
+@item
+The name of the compiler and its version.  For @command{gcc}, get the version
+with @samp{gcc -v}, otherwise perhaps @samp{what `which cc`}, or similar.
+
+@item
+The output from running @samp{uname -a}.
+
+@item
+The output from running @samp{./config.guess}, and from running
+@samp{./configfsf.guess} (might be the same).
+
+@item
+If the bug is related to @samp{configure}, then the compressed contents of
+@file{config.log}.
+
+@item
+If the bug is related to an @file{asm} file not assembling, then the contents
+of @file{config.m4} and the offending line or lines from the temporary
+@file{mpn/tmp-<file>.s}.
+@end itemize
+
+Please make an effort to produce a self-contained report, with something
+definite that can be tested or debugged.  Vague queries or piecemeal messages
+are difficult to act on and don't help the development effort.
+
+It is not uncommon that an observed problem is actually due to a bug in the
+compiler; the GMP code tends to explore interesting corners in compilers.
+
+If your bug report is good, we will do our best to help you get a corrected
+version of the library; if the bug report is poor, we won't do anything about
+it (except maybe ask you to send a better report).
+
+Send your report to: @email{gmp-bugs@@gmplib.org}.
+
+If you think something in this manual is unclear, or downright incorrect, or if
+the language needs to be improved, please send a note to the same address.
+
+
+@node Integer Functions, Rational Number Functions, Reporting Bugs, Top
+@comment  node-name,  next,  previous,  up
+@chapter Integer Functions
+@cindex Integer functions
+
+This chapter describes the GMP functions for performing integer arithmetic.
+These functions start with the prefix @code{mpz_}.
+
+GMP integers are stored in objects of type @code{mpz_t}.
+
+@menu
+* Initializing Integers::
+* Assigning Integers::
+* Simultaneous Integer Init & Assign::
+* Converting Integers::
+* Integer Arithmetic::
+* Integer Division::
+* Integer Exponentiation::
+* Integer Roots::
+* Number Theoretic Functions::
+* Integer Comparisons::
+* Integer Logic and Bit Fiddling::
+* I/O of Integers::
+* Integer Random Numbers::
+* Integer Import and Export::
+* Miscellaneous Integer Functions::
+* Integer Special Functions::
+@end menu
+
+@node Initializing Integers, Assigning Integers, Integer Functions, Integer Functions
+@comment  node-name,  next,  previous,  up
+@section Initialization Functions
+@cindex Integer initialization functions
+@cindex Initialization functions
+
+The functions for integer arithmetic assume that all integer objects are
+initialized.  You do that by calling the function @code{mpz_init}.  For
+example,
+
+@example
+@{
+  mpz_t integ;
+  mpz_init (integ);
+  @dots{}
+  mpz_add (integ, @dots{});
+  @dots{}
+  mpz_sub (integ, @dots{});
+
+  /* Unless the program is about to exit, do ... */
+  mpz_clear (integ);
+@}
+@end example
+
+As you can see, you can store new values any number of times, once an
+object is initialized.
+
+@deftypefun void mpz_init (mpz_t @var{x})
+Initialize @var{x}, and set its value to 0.
+@end deftypefun
+
+@deftypefun void mpz_inits (mpz_t @var{x}, ...)
+Initialize a NULL-terminated list of @code{mpz_t} variables, and set their
+values to 0.
+@end deftypefun
+
+@deftypefun void mpz_init2 (mpz_t @var{x}, mp_bitcnt_t @var{n})
+Initialize @var{x}, with space for @var{n}-bit numbers, and set its value to 0.
+Calling this function instead of @code{mpz_init} or @code{mpz_inits} is never
+necessary; reallocation is handled automatically by GMP when needed.
+
+While @var{n} defines the initial space, @var{x} will grow automatically in the
+normal way, if necessary, for subsequent values stored.  @code{mpz_init2} makes
+it possible to avoid such reallocations if a maximum size is known in advance.
+
+In preparation for an operation, GMP often allocates one limb more than
+ultimately needed.  To make sure GMP will not perform reallocation for
+@var{x}, you need to add the number of bits in @code{mp_limb_t} to @var{n}.
+@end deftypefun
+
+@deftypefun void mpz_clear (mpz_t @var{x})
+Free the space occupied by @var{x}.  Call this function for all @code{mpz_t}
+variables when you are done with them.
+@end deftypefun
+
+@deftypefun void mpz_clears (mpz_t @var{x}, ...)
+Free the space occupied by a NULL-terminated list of @code{mpz_t} variables.
+@end deftypefun
+
+@deftypefun void mpz_realloc2 (mpz_t @var{x}, mp_bitcnt_t @var{n})
+Change the space allocated for @var{x} to @var{n} bits.  The value in @var{x}
+is preserved if it fits, or is set to 0 if not.
+
+Calling this function is never necessary; reallocation is handled automatically
+by GMP when needed.  But this function can be used to increase the space for a
+variable in order to avoid repeated automatic reallocations, or to decrease it
+to give memory back to the heap.
+@end deftypefun
+
+
+@node Assigning Integers, Simultaneous Integer Init & Assign, Initializing Integers, Integer Functions
+@comment  node-name,  next,  previous,  up
+@section Assignment Functions
+@cindex Integer assignment functions
+@cindex Assignment functions
+
+These functions assign new values to already initialized integers
+(@pxref{Initializing Integers}).
+
+@deftypefun void mpz_set (mpz_t @var{rop}, const mpz_t @var{op})
+@deftypefunx void mpz_set_ui (mpz_t @var{rop}, unsigned long int @var{op})
+@deftypefunx void mpz_set_si (mpz_t @var{rop}, signed long int @var{op})
+@deftypefunx void mpz_set_d (mpz_t @var{rop}, double @var{op})
+@deftypefunx void mpz_set_q (mpz_t @var{rop}, const mpq_t @var{op})
+@deftypefunx void mpz_set_f (mpz_t @var{rop}, const mpf_t @var{op})
+Set the value of @var{rop} from @var{op}.
+
+@code{mpz_set_d}, @code{mpz_set_q} and @code{mpz_set_f} truncate @var{op} to
+make it an integer.
+@end deftypefun
+
+@deftypefun int mpz_set_str (mpz_t @var{rop}, const char *@var{str}, int @var{base})
+Set the value of @var{rop} from @var{str}, a null-terminated C string in base
+@var{base}.  White space is allowed in the string, and is simply ignored.
+
+The @var{base} may vary from 2 to 62, or if @var{base} is 0, then the leading
+characters are used: @code{0x} and @code{0X} for hexadecimal, @code{0b} and
+@code{0B} for binary, @code{0} for octal, or decimal otherwise.
+
+For bases up to 36, case is ignored; upper-case and lower-case letters have
+the same value.  For bases 37 to 62, upper-case letter represent the usual
+10..35 while lower-case letter represent 36..61.
+
+This function returns 0 if the entire string is a valid number in base
+@var{base}.  Otherwise it returns @minus{}1.
+@c
+@c  It turns out that it is not entirely true that this function ignores
+@c  white-space.  It does ignore it between digits, but not after a minus sign
+@c  or within or after ``0x''.  Some thought was given to disallowing all
+@c  whitespace, but that would be an incompatible change, whitespace has been
+@c  documented as ignored ever since GMP 1.
+@c
+@end deftypefun
+
+@deftypefun void mpz_swap (mpz_t @var{rop1}, mpz_t @var{rop2})
+Swap the values @var{rop1} and @var{rop2} efficiently.
+@end deftypefun
+
+
+@node Simultaneous Integer Init & Assign, Converting Integers, Assigning Integers, Integer Functions
+@comment  node-name,  next,  previous,  up
+@section Combined Initialization and Assignment Functions
+@cindex Integer assignment functions
+@cindex Assignment functions
+@cindex Integer initialization functions
+@cindex Initialization functions
+
+For convenience, GMP provides a parallel series of initialize-and-set functions
+which initialize the output and then store the value there.  These functions'
+names have the form @code{mpz_init_set@dots{}}
+
+Here is an example of using one:
+
+@example
+@{
+  mpz_t pie;
+  mpz_init_set_str (pie, "3141592653589793238462643383279502884", 10);
+  @dots{}
+  mpz_sub (pie, @dots{});
+  @dots{}
+  mpz_clear (pie);
+@}
+@end example
+
+@noindent
+Once the integer has been initialized by any of the @code{mpz_init_set@dots{}}
+functions, it can be used as the source or destination operand for the ordinary
+integer functions.  Don't use an initialize-and-set function on a variable
+already initialized!
+
+@deftypefun void mpz_init_set (mpz_t @var{rop}, const mpz_t @var{op})
+@deftypefunx void mpz_init_set_ui (mpz_t @var{rop}, unsigned long int @var{op})
+@deftypefunx void mpz_init_set_si (mpz_t @var{rop}, signed long int @var{op})
+@deftypefunx void mpz_init_set_d (mpz_t @var{rop}, double @var{op})
+Initialize @var{rop} with limb space and set the initial numeric value from
+@var{op}.
+@end deftypefun
+
+@deftypefun int mpz_init_set_str (mpz_t @var{rop}, const char *@var{str}, int @var{base})
+Initialize @var{rop} and set its value like @code{mpz_set_str} (see its
+documentation above for details).
+
+If the string is a correct base @var{base} number, the function returns 0;
+if an error occurs it returns @minus{}1.  @var{rop} is initialized even if
+an error occurs.  (I.e., you have to call @code{mpz_clear} for it.)
+@end deftypefun
+
+
+@node Converting Integers, Integer Arithmetic, Simultaneous Integer Init & Assign, Integer Functions
+@comment  node-name,  next,  previous,  up
+@section Conversion Functions
+@cindex Integer conversion functions
+@cindex Conversion functions
+
+This section describes functions for converting GMP integers to standard C
+types.  Functions for converting @emph{to} GMP integers are described in
+@ref{Assigning Integers} and @ref{I/O of Integers}.
+
+@deftypefun {unsigned long int} mpz_get_ui (const mpz_t @var{op})
+Return the value of @var{op} as an @code{unsigned long}.
+
+If @var{op} is too big to fit an @code{unsigned long} then just the least
+significant bits that do fit are returned.  The sign of @var{op} is ignored,
+only the absolute value is used.
+@end deftypefun
+
+@deftypefun {signed long int} mpz_get_si (const mpz_t @var{op})
+If @var{op} fits into a @code{signed long int} return the value of @var{op}.
+Otherwise return the least significant part of @var{op}, with the same sign
+as @var{op}.
+
+If @var{op} is too big to fit in a @code{signed long int}, the returned
+result is probably not very useful.  To find out if the value will fit, use
+the function @code{mpz_fits_slong_p}.
+@end deftypefun
+
+@deftypefun double mpz_get_d (const mpz_t @var{op})
+Convert @var{op} to a @code{double}, truncating if necessary (i.e.@: rounding
+towards zero).
+
+If the exponent from the conversion is too big, the result is system
+dependent.  An infinity is returned where available.  A hardware overflow trap
+may or may not occur.
+@end deftypefun
+
+@deftypefun double mpz_get_d_2exp (signed long int *@var{exp}, const mpz_t @var{op})
+Convert @var{op} to a @code{double}, truncating if necessary (i.e.@: rounding
+towards zero), and returning the exponent separately.
+
+The return value is in the range @math{0.5@le{}@GMPabs{@var{d}}<1} and the
+exponent is stored to @code{*@var{exp}}.  @m{@var{d} * 2^{exp}, @var{d} *
+2^@var{exp}} is the (truncated) @var{op} value.  If @var{op} is zero, the
+return is @math{0.0} and 0 is stored to @code{*@var{exp}}.
+
+@cindex @code{frexp}
+This is similar to the standard C @code{frexp} function (@pxref{Normalization
+Functions,,, libc, The GNU C Library Reference Manual}).
+@end deftypefun
+
+@deftypefun {char *} mpz_get_str (char *@var{str}, int @var{base}, const mpz_t @var{op})
+Convert @var{op} to a string of digits in base @var{base}.  The base argument
+may vary from 2 to 62 or from @minus{}2 to @minus{}36.
+
+For @var{base} in the range 2..36, digits and lower-case letters are used; for
+@minus{}2..@minus{}36, digits and upper-case letters are used; for 37..62,
+digits, upper-case letters, and lower-case letters (in that significance order)
+are used.
+
+If @var{str} is @code{NULL}, the result string is allocated using the current
+allocation function (@pxref{Custom Allocation}).  The block will be
+@code{strlen(str)+1} bytes, that being exactly enough for the string and
+null-terminator.
+
+If @var{str} is not @code{NULL}, it should point to a block of storage large
+enough for the result, that being @code{mpz_sizeinbase (@var{op}, @var{base})
++ 2}.  The two extra bytes are for a possible minus sign, and the
+null-terminator.
+
+A pointer to the result string is returned, being either the allocated block,
+or the given @var{str}.
+@end deftypefun
+
+
+@need 2000
+@node Integer Arithmetic, Integer Division, Converting Integers, Integer Functions
+@comment  node-name,  next,  previous,  up
+@section Arithmetic Functions
+@cindex Integer arithmetic functions
+@cindex Arithmetic functions
+
+@deftypefun void mpz_add (mpz_t @var{rop}, const mpz_t @var{op1}, const mpz_t @var{op2})
+@deftypefunx void mpz_add_ui (mpz_t @var{rop}, const mpz_t @var{op1}, unsigned long int @var{op2})
+Set @var{rop} to @math{@var{op1} + @var{op2}}.
+@end deftypefun
+
+@deftypefun void mpz_sub (mpz_t @var{rop}, const mpz_t @var{op1}, const mpz_t @var{op2})
+@deftypefunx void mpz_sub_ui (mpz_t @var{rop}, const mpz_t @var{op1}, unsigned long int @var{op2})
+@deftypefunx void mpz_ui_sub (mpz_t @var{rop}, unsigned long int @var{op1}, const mpz_t @var{op2})
+Set @var{rop} to @var{op1} @minus{} @var{op2}.
+@end deftypefun
+
+@deftypefun void mpz_mul (mpz_t @var{rop}, const mpz_t @var{op1}, const mpz_t @var{op2})
+@deftypefunx void mpz_mul_si (mpz_t @var{rop}, const mpz_t @var{op1}, long int @var{op2})
+@deftypefunx void mpz_mul_ui (mpz_t @var{rop}, const mpz_t @var{op1}, unsigned long int @var{op2})
+Set @var{rop} to @math{@var{op1} @GMPtimes{} @var{op2}}.
+@end deftypefun
+
+@deftypefun void mpz_addmul (mpz_t @var{rop}, const mpz_t @var{op1}, const mpz_t @var{op2})
+@deftypefunx void mpz_addmul_ui (mpz_t @var{rop}, const mpz_t @var{op1}, unsigned long int @var{op2})
+Set @var{rop} to @math{@var{rop} + @var{op1} @GMPtimes{} @var{op2}}.
+@end deftypefun
+
+@deftypefun void mpz_submul (mpz_t @var{rop}, const mpz_t @var{op1}, const mpz_t @var{op2})
+@deftypefunx void mpz_submul_ui (mpz_t @var{rop}, const mpz_t @var{op1}, unsigned long int @var{op2})
+Set @var{rop} to @math{@var{rop} - @var{op1} @GMPtimes{} @var{op2}}.
+@end deftypefun
+
+@deftypefun void mpz_mul_2exp (mpz_t @var{rop}, const mpz_t @var{op1}, mp_bitcnt_t @var{op2})
+@cindex Bit shift left
+Set @var{rop} to @m{@var{op1} \times 2^{op2}, @var{op1} times 2 raised to
+@var{op2}}.  This operation can also be defined as a left shift by @var{op2}
+bits.
+@end deftypefun
+
+@deftypefun void mpz_neg (mpz_t @var{rop}, const mpz_t @var{op})
+Set @var{rop} to @minus{}@var{op}.
+@end deftypefun
+
+@deftypefun void mpz_abs (mpz_t @var{rop}, const mpz_t @var{op})
+Set @var{rop} to the absolute value of @var{op}.
+@end deftypefun
+
+
+@need 2000
+@node Integer Division, Integer Exponentiation, Integer Arithmetic, Integer Functions
+@section Division Functions
+@cindex Integer division functions
+@cindex Division functions
+
+Division is undefined if the divisor is zero.  Passing a zero divisor to the
+division or modulo functions (including the modular powering functions
+@code{mpz_powm} and @code{mpz_powm_ui}), will cause an intentional division by
+zero.  This lets a program handle arithmetic exceptions in these functions the
+same way as for normal C @code{int} arithmetic.
+
+@c  Separate deftypefun groups for cdiv, fdiv and tdiv produce a blank line
+@c  between each, and seem to let tex do a better job of page breaks than an
+@c  @sp 1 in the middle of one big set.
+
+@deftypefun void mpz_cdiv_q (mpz_t @var{q}, const mpz_t @var{n}, const mpz_t @var{d})
+@deftypefunx void mpz_cdiv_r (mpz_t @var{r}, const mpz_t @var{n}, const mpz_t @var{d})
+@deftypefunx void mpz_cdiv_qr (mpz_t @var{q}, mpz_t @var{r}, const mpz_t @var{n}, const mpz_t @var{d})
+@maybepagebreak
+@deftypefunx {unsigned long int} mpz_cdiv_q_ui (mpz_t @var{q}, const mpz_t @var{n}, @w{unsigned long int @var{d}})
+@deftypefunx {unsigned long int} mpz_cdiv_r_ui (mpz_t @var{r}, const mpz_t @var{n}, @w{unsigned long int @var{d}})
+@deftypefunx {unsigned long int} mpz_cdiv_qr_ui (mpz_t @var{q}, mpz_t @var{r}, @w{const mpz_t @var{n}}, @w{unsigned long int @var{d}})
+@deftypefunx {unsigned long int} mpz_cdiv_ui (const mpz_t @var{n}, @w{unsigned long int @var{d}})
+@maybepagebreak
+@deftypefunx void mpz_cdiv_q_2exp (mpz_t @var{q}, const mpz_t @var{n}, @w{mp_bitcnt_t @var{b}})
+@deftypefunx void mpz_cdiv_r_2exp (mpz_t @var{r}, const mpz_t @var{n}, @w{mp_bitcnt_t @var{b}})
+@end deftypefun
+
+@deftypefun void mpz_fdiv_q (mpz_t @var{q}, const mpz_t @var{n}, const mpz_t @var{d})
+@deftypefunx void mpz_fdiv_r (mpz_t @var{r}, const mpz_t @var{n}, const mpz_t @var{d})
+@deftypefunx void mpz_fdiv_qr (mpz_t @var{q}, mpz_t @var{r}, const mpz_t @var{n}, const mpz_t @var{d})
+@maybepagebreak
+@deftypefunx {unsigned long int} mpz_fdiv_q_ui (mpz_t @var{q}, const mpz_t @var{n}, @w{unsigned long int @var{d}})
+@deftypefunx {unsigned long int} mpz_fdiv_r_ui (mpz_t @var{r}, const mpz_t @var{n}, @w{unsigned long int @var{d}})
+@deftypefunx {unsigned long int} mpz_fdiv_qr_ui (mpz_t @var{q}, mpz_t @var{r}, @w{const mpz_t @var{n}}, @w{unsigned long int @var{d}})
+@deftypefunx {unsigned long int} mpz_fdiv_ui (const mpz_t @var{n}, @w{unsigned long int @var{d}})
+@maybepagebreak
+@deftypefunx void mpz_fdiv_q_2exp (mpz_t @var{q}, const mpz_t @var{n}, @w{mp_bitcnt_t @var{b}})
+@deftypefunx void mpz_fdiv_r_2exp (mpz_t @var{r}, const mpz_t @var{n}, @w{mp_bitcnt_t @var{b}})
+@end deftypefun
+
+@deftypefun void mpz_tdiv_q (mpz_t @var{q}, const mpz_t @var{n}, const mpz_t @var{d})
+@deftypefunx void mpz_tdiv_r (mpz_t @var{r}, const mpz_t @var{n}, const mpz_t @var{d})
+@deftypefunx void mpz_tdiv_qr (mpz_t @var{q}, mpz_t @var{r}, const mpz_t @var{n}, const mpz_t @var{d})
+@maybepagebreak
+@deftypefunx {unsigned long int} mpz_tdiv_q_ui (mpz_t @var{q}, const mpz_t @var{n}, @w{unsigned long int @var{d}})
+@deftypefunx {unsigned long int} mpz_tdiv_r_ui (mpz_t @var{r}, const mpz_t @var{n}, @w{unsigned long int @var{d}})
+@deftypefunx {unsigned long int} mpz_tdiv_qr_ui (mpz_t @var{q}, mpz_t @var{r}, @w{const mpz_t @var{n}}, @w{unsigned long int @var{d}})
+@deftypefunx {unsigned long int} mpz_tdiv_ui (const mpz_t @var{n}, @w{unsigned long int @var{d}})
+@maybepagebreak
+@deftypefunx void mpz_tdiv_q_2exp (mpz_t @var{q}, const mpz_t @var{n}, @w{mp_bitcnt_t @var{b}})
+@deftypefunx void mpz_tdiv_r_2exp (mpz_t @var{r}, const mpz_t @var{n}, @w{mp_bitcnt_t @var{b}})
+@cindex Bit shift right
+
+@sp 1
+Divide @var{n} by @var{d}, forming a quotient @var{q} and/or remainder
+@var{r}.  For the @code{2exp} functions, @m{@var{d}=2^b, @var{d}=2^@var{b}}.
+The rounding is in three styles, each suiting different applications.
+
+@itemize @bullet
+@item
+@code{cdiv} rounds @var{q} up towards @m{+\infty, +infinity}, and @var{r} will
+have the opposite sign to @var{d}.  The @code{c} stands for ``ceil''.
+
+@item
+@code{fdiv} rounds @var{q} down towards @m{-\infty, @minus{}infinity}, and
+@var{r} will have the same sign as @var{d}.  The @code{f} stands for
+``floor''.
+
+@item
+@code{tdiv} rounds @var{q} towards zero, and @var{r} will have the same sign
+as @var{n}.  The @code{t} stands for ``truncate''.
+@end itemize
+
+In all cases @var{q} and @var{r} will satisfy
+@m{@var{n}=@var{q}@var{d}+@var{r}, @var{n}=@var{q}*@var{d}+@var{r}}, and
+@var{r} will satisfy @math{0@le{}@GMPabs{@var{r}}<@GMPabs{@var{d}}}.
+
+The @code{q} functions calculate only the quotient, the @code{r} functions
+only the remainder, and the @code{qr} functions calculate both.  Note that for
+@code{qr} the same variable cannot be passed for both @var{q} and @var{r}, or
+results will be unpredictable.
+
+For the @code{ui} variants the return value is the remainder, and in fact
+returning the remainder is all the @code{div_ui} functions do.  For
+@code{tdiv} and @code{cdiv} the remainder can be negative, so for those the
+return value is the absolute value of the remainder.
+
+For the @code{2exp} variants the divisor is @m{2^b,2^@var{b}}.  These
+functions are implemented as right shifts and bit masks, but of course they
+round the same as the other functions.
+
+For positive @var{n} both @code{mpz_fdiv_q_2exp} and @code{mpz_tdiv_q_2exp}
+are simple bitwise right shifts.  For negative @var{n}, @code{mpz_fdiv_q_2exp}
+is effectively an arithmetic right shift treating @var{n} as twos complement
+the same as the bitwise logical functions do, whereas @code{mpz_tdiv_q_2exp}
+effectively treats @var{n} as sign and magnitude.
+@end deftypefun
+
+@deftypefun void mpz_mod (mpz_t @var{r}, const mpz_t @var{n}, const mpz_t @var{d})
+@deftypefunx {unsigned long int} mpz_mod_ui (mpz_t @var{r}, const mpz_t @var{n}, @w{unsigned long int @var{d}})
+Set @var{r} to @var{n} @code{mod} @var{d}.  The sign of the divisor is
+ignored; the result is always non-negative.
+
+@code{mpz_mod_ui} is identical to @code{mpz_fdiv_r_ui} above, returning the
+remainder as well as setting @var{r}.  See @code{mpz_fdiv_ui} above if only
+the return value is wanted.
+@end deftypefun
+
+@deftypefun void mpz_divexact (mpz_t @var{q}, const mpz_t @var{n}, const mpz_t @var{d})
+@deftypefunx void mpz_divexact_ui (mpz_t @var{q}, const mpz_t @var{n}, unsigned long @var{d})
+@cindex Exact division functions
+Set @var{q} to @var{n}/@var{d}.  These functions produce correct results only
+when it is known in advance that @var{d} divides @var{n}.
+
+These routines are much faster than the other division functions, and are the
+best choice when exact division is known to occur, for example reducing a
+rational to lowest terms.
+@end deftypefun
+
+@deftypefun int mpz_divisible_p (const mpz_t @var{n}, const mpz_t @var{d})
+@deftypefunx int mpz_divisible_ui_p (const mpz_t @var{n}, unsigned long int @var{d})
+@deftypefunx int mpz_divisible_2exp_p (const mpz_t @var{n}, mp_bitcnt_t @var{b})
+@cindex Divisibility functions
+Return non-zero if @var{n} is exactly divisible by @var{d}, or in the case of
+@code{mpz_divisible_2exp_p} by @m{2^b,2^@var{b}}.
+
+@var{n} is divisible by @var{d} if there exists an integer @var{q} satisfying
+@math{@var{n} = @var{q}@GMPmultiply{}@var{d}}.  Unlike the other division
+functions, @math{@var{d}=0} is accepted and following the rule it can be seen
+that only 0 is considered divisible by 0.
+@end deftypefun
+
+@deftypefun int mpz_congruent_p (const mpz_t @var{n}, const mpz_t @var{c}, const mpz_t @var{d})
+@deftypefunx int mpz_congruent_ui_p (const mpz_t @var{n}, unsigned long int @var{c}, unsigned long int @var{d})
+@deftypefunx int mpz_congruent_2exp_p (const mpz_t @var{n}, const mpz_t @var{c}, mp_bitcnt_t @var{b})
+@cindex Divisibility functions
+@cindex Congruence functions
+Return non-zero if @var{n} is congruent to @var{c} modulo @var{d}, or in the
+case of @code{mpz_congruent_2exp_p} modulo @m{2^b,2^@var{b}}.
+
+@var{n} is congruent to @var{c} mod @var{d} if there exists an integer @var{q}
+satisfying @math{@var{n} = @var{c} + @var{q}@GMPmultiply{}@var{d}}.  Unlike
+the other division functions, @math{@var{d}=0} is accepted and following the
+rule it can be seen that @var{n} and @var{c} are considered congruent mod 0
+only when exactly equal.
+@end deftypefun
+
+
+@need 2000
+@node Integer Exponentiation, Integer Roots, Integer Division, Integer Functions
+@section Exponentiation Functions
+@cindex Integer exponentiation functions
+@cindex Exponentiation functions
+@cindex Powering functions
+
+@deftypefun void mpz_powm (mpz_t @var{rop}, const mpz_t @var{base}, const mpz_t @var{exp}, const mpz_t @var{mod})
+@deftypefunx void mpz_powm_ui (mpz_t @var{rop}, const mpz_t @var{base}, unsigned long int @var{exp}, const mpz_t @var{mod})
+Set @var{rop} to @m{base^{exp} \bmod mod, (@var{base} raised to @var{exp})
+modulo @var{mod}}.
+
+Negative @var{exp} is supported if the inverse @mm{@var{base}@sup{-1} @bmod
+@var{mod}, @var{base}^(-1) @bmod @var{mod}} exists (see @code{mpz_invert} in
+@ref{Number Theoretic Functions}).  If an inverse doesn't exist then a divide
+by zero is raised.
+@end deftypefun
+
+@deftypefun void mpz_powm_sec (mpz_t @var{rop}, const mpz_t @var{base}, const mpz_t @var{exp}, const mpz_t @var{mod})
+Set @var{rop} to @m{base^{exp} \bmod @var{mod}, (@var{base} raised to @var{exp})
+modulo @var{mod}}.
+
+It is required that @math{@var{exp} > 0} and that @var{mod} is odd.
+
+This function is designed to take the same time and have the same cache access
+patterns for any two same-size arguments, assuming that function arguments are
+placed at the same position and that the machine state is identical upon
+function entry.  This function is intended for cryptographic purposes, where
+resilience to side-channel attacks is desired.
+@end deftypefun
+
+@deftypefun void mpz_pow_ui (mpz_t @var{rop}, const mpz_t @var{base}, unsigned long int @var{exp})
+@deftypefunx void mpz_ui_pow_ui (mpz_t @var{rop}, unsigned long int @var{base}, unsigned long int @var{exp})
+Set @var{rop} to @m{base^{exp}, @var{base} raised to @var{exp}}.  The case
+@math{0^0} yields 1.
+@end deftypefun
+
+
+@need 2000
+@node Integer Roots, Number Theoretic Functions, Integer Exponentiation, Integer Functions
+@section Root Extraction Functions
+@cindex Integer root functions
+@cindex Root extraction functions
+
+@deftypefun int mpz_root (mpz_t @var{rop}, const mpz_t @var{op}, unsigned long int @var{n})
+Set @var{rop} to @m{\lfloor\root n \of {op}\rfloor@C{},} the truncated integer
+part of the @var{n}th root of @var{op}.  Return non-zero if the computation
+was exact, i.e., if @var{op} is @var{rop} to the @var{n}th power.
+@end deftypefun
+
+@deftypefun void mpz_rootrem (mpz_t @var{root}, mpz_t @var{rem}, const mpz_t @var{u}, unsigned long int @var{n})
+Set @var{root} to @m{\lfloor\root n \of {u}\rfloor@C{},} the truncated
+integer part of the @var{n}th root of @var{u}.  Set @var{rem} to the
+remainder, @m{(@var{u} - @var{root}^n),
+@var{u}@minus{}@var{root}**@var{n}}.
+@end deftypefun
+
+@deftypefun void mpz_sqrt (mpz_t @var{rop}, const mpz_t @var{op})
+Set @var{rop} to @m{\lfloor\sqrt{@var{op}}\rfloor@C{},} the truncated
+integer part of the square root of @var{op}.
+@end deftypefun
+
+@deftypefun void mpz_sqrtrem (mpz_t @var{rop1}, mpz_t @var{rop2}, const mpz_t @var{op})
+Set @var{rop1} to @m{\lfloor\sqrt{@var{op}}\rfloor, the truncated integer part
+of the square root of @var{op}}, like @code{mpz_sqrt}.  Set @var{rop2} to the
+remainder @m{(@var{op} - @var{rop1}^2),
+@var{op}@minus{}@var{rop1}*@var{rop1}}, which will be zero if @var{op} is a
+perfect square.
+
+If @var{rop1} and @var{rop2} are the same variable, the results are
+undefined.
+@end deftypefun
+
+@deftypefun int mpz_perfect_power_p (const mpz_t @var{op})
+@cindex Perfect power functions
+@cindex Root testing functions
+Return non-zero if @var{op} is a perfect power, i.e., if there exist integers
+@m{a,@var{a}} and @m{b,@var{b}}, with @m{b>1, @var{b}>1}, such that
+@m{@var{op}=a^b, @var{op} equals @var{a} raised to the power @var{b}}.
+
+Under this definition both 0 and 1 are considered to be perfect powers.
+Negative values of @var{op} are accepted, but of course can only be odd
+perfect powers.
+@end deftypefun
+
+@deftypefun int mpz_perfect_square_p (const mpz_t @var{op})
+@cindex Perfect square functions
+@cindex Root testing functions
+Return non-zero if @var{op} is a perfect square, i.e., if the square root of
+@var{op} is an integer.  Under this definition both 0 and 1 are considered to
+be perfect squares.
+@end deftypefun
+
+
+@need 2000
+@node Number Theoretic Functions, Integer Comparisons, Integer Roots, Integer Functions
+@section Number Theoretic Functions
+@cindex Number theoretic functions
+
+@deftypefun int mpz_probab_prime_p (const mpz_t @var{n}, int @var{reps})
+@cindex Prime testing functions
+@cindex Probable prime testing functions
+Determine whether @var{n} is prime.  Return 2 if @var{n} is definitely prime,
+return 1 if @var{n} is probably prime (without being certain), or return 0 if
+@var{n} is definitely non-prime.
+
+This function performs some trial divisions, a Baillie-PSW probable prime
+test, then @var{reps-24} Miller-Rabin probabilistic primality tests.  A
+higher @var{reps} value will reduce the chances of a non-prime being
+identified as ``probably prime''.  A composite number will be identified as a
+prime with an asymptotic probability of less than @m{4^{-reps},4^(-@var{reps})}.
+Reasonable values of @var{reps} are between 15 and 50.
+
+GMP versions up to and including 6.1.2 did not use the Baillie-PSW
+primality test. In those older versions of GMP, this function performed
+@var{reps} Miller-Rabin tests.
+@end deftypefun
+
+@deftypefun void mpz_nextprime (mpz_t @var{rop}, const mpz_t @var{op})
+@cindex Next prime function
+Set @var{rop} to the next prime greater than @var{op}.
+
+This function uses a probabilistic algorithm to identify primes.  For
+practical purposes it's adequate, the chance of a composite passing will be
+extremely small.
+@end deftypefun
+
+@c mpz_prime_p not implemented as of gmp 3.0.
+
+@c @deftypefun int mpz_prime_p (const mpz_t @var{n})
+@c Return non-zero if @var{n} is prime and zero if @var{n} is a non-prime.
+@c This function is far slower than @code{mpz_probab_prime_p}, but then it
+@c never returns non-zero for composite numbers.
+
+@c (For practical purposes, using @code{mpz_probab_prime_p} is adequate.
+@c The likelihood of a programming error or hardware malfunction is orders
+@c of magnitudes greater than the likelihood for a composite to pass as a
+@c prime, if the @var{reps} argument is in the suggested range.)
+@c @end deftypefun
+
+@deftypefun void mpz_gcd (mpz_t @var{rop}, const mpz_t @var{op1}, const mpz_t @var{op2})
+@cindex Greatest common divisor functions
+@cindex GCD functions
+Set @var{rop} to the greatest common divisor of @var{op1} and @var{op2}.  The
+result is always positive even if one or both input operands are negative.
+Except if both inputs are zero; then this function defines @math{gcd(0,0) = 0}.
+@end deftypefun
+
+@deftypefun {unsigned long int} mpz_gcd_ui (mpz_t @var{rop}, const mpz_t @var{op1}, unsigned long int @var{op2})
+Compute the greatest common divisor of @var{op1} and @var{op2}.  If
+@var{rop} is not @code{NULL}, store the result there.
+
+If the result is small enough to fit in an @code{unsigned long int}, it is
+returned.  If the result does not fit, 0 is returned, and the result is equal
+to the argument @var{op1}.  Note that the result will always fit if @var{op2}
+is non-zero.
+@end deftypefun
+
+@deftypefun void mpz_gcdext (mpz_t @var{g}, mpz_t @var{s}, mpz_t @var{t}, const mpz_t @var{a}, const mpz_t @var{b})
+@cindex Extended GCD
+@cindex GCD extended
+Set @var{g} to the greatest common divisor of @var{a} and @var{b}, and in
+addition set @var{s} and @var{t} to coefficients satisfying
+@math{@var{a}@GMPmultiply{}@var{s} + @var{b}@GMPmultiply{}@var{t} = @var{g}}.
+The value in @var{g} is always positive, even if one or both of @var{a} and
+@var{b} are negative (or zero if both inputs are zero).  The values in @var{s}
+and @var{t} are chosen such that normally, @math{@GMPabs{@var{s}} <
+@GMPabs{@var{b}} / (2 @var{g})} and @math{@GMPabs{@var{t}} < @GMPabs{@var{a}}
+/ (2 @var{g})}, and these relations define @var{s} and @var{t} uniquely.  There
+are a few exceptional cases:
+
+If @math{@GMPabs{@var{a}} = @GMPabs{@var{b}}}, then @math{@var{s} = 0},
+@math{@var{t} = sgn(@var{b})}.
+
+Otherwise, @math{@var{s} = sgn(@var{a})} if @math{@var{b} = 0} or
+@math{@GMPabs{@var{b}} = 2 @var{g}}, and @math{@var{t} = sgn(@var{b})} if
+@math{@var{a} = 0} or @math{@GMPabs{@var{a}} = 2 @var{g}}.
+
+In all cases, @math{@var{s} = 0} if and only if @math{@var{g} =
+@GMPabs{@var{b}}}, i.e., if @var{b} divides @var{a} or @math{@var{a} = @var{b}
+= 0}.
+
+If @var{t} or @var{g} is @code{NULL} then that value is not computed.
+@end deftypefun
+
+@deftypefun void mpz_lcm (mpz_t @var{rop}, const mpz_t @var{op1}, const mpz_t @var{op2})
+@deftypefunx void mpz_lcm_ui (mpz_t @var{rop}, const mpz_t @var{op1}, unsigned long @var{op2})
+@cindex Least common multiple functions
+@cindex LCM functions
+Set @var{rop} to the least common multiple of @var{op1} and @var{op2}.
+@var{rop} is always positive, irrespective of the signs of @var{op1} and
+@var{op2}.  @var{rop} will be zero if either @var{op1} or @var{op2} is zero.
+@end deftypefun
+
+@deftypefun int mpz_invert (mpz_t @var{rop}, const mpz_t @var{op1}, const mpz_t @var{op2})
+@cindex Modular inverse functions
+@cindex Inverse modulo functions
+Compute the inverse of @var{op1} modulo @var{op2} and put the result in
+@var{rop}.  If the inverse exists, the return value is non-zero and @var{rop}
+will satisfy @math{0 @le{} @var{rop} < @GMPabs{@var{op2}}} (with @math{@var{rop}
+= 0} possible only when @math{@GMPabs{@var{op2}} = 1}, i.e., in the
+somewhat degenerate zero ring).  If an inverse doesn't
+exist the return value is zero and @var{rop} is undefined.  The behaviour of
+this function is undefined when @var{op2} is zero.
+@end deftypefun
+
+@deftypefun int mpz_jacobi (const mpz_t @var{a}, const mpz_t @var{b})
+@cindex Jacobi symbol functions
+Calculate the Jacobi symbol @m{\left(a \over b\right),
+(@var{a}/@var{b})}.  This is defined only for @var{b} odd.
+@end deftypefun
+
+@deftypefun int mpz_legendre (const mpz_t @var{a}, const mpz_t @var{p})
+@cindex Legendre symbol functions
+Calculate the Legendre symbol @m{\left(a \over p\right),
+(@var{a}/@var{p})}.  This is defined only for @var{p} an odd positive
+prime, and for such @var{p} it's identical to the Jacobi symbol.
+@end deftypefun
+
+@deftypefun int mpz_kronecker (const mpz_t @var{a}, const mpz_t @var{b})
+@deftypefunx int mpz_kronecker_si (const mpz_t @var{a}, long @var{b})
+@deftypefunx int mpz_kronecker_ui (const mpz_t @var{a}, unsigned long @var{b})
+@deftypefunx int mpz_si_kronecker (long @var{a}, const mpz_t @var{b})
+@deftypefunx int mpz_ui_kronecker (unsigned long @var{a}, const mpz_t @var{b})
+@cindex Kronecker symbol functions
+Calculate the Jacobi symbol @m{\left(a \over b\right),
+(@var{a}/@var{b})} with the Kronecker extension @m{\left(a \over
+2\right) = \left(2 \over a\right), (a/2)=(2/a)} when @math{a} odd, or
+@m{\left(a \over 2\right) = 0, (a/2)=0} when @math{a} even.
+
+When @var{b} is odd the Jacobi symbol and Kronecker symbol are
+identical, so @code{mpz_kronecker_ui} etc can be used for mixed
+precision Jacobi symbols too.
+
+For more information see Henri Cohen section 1.4.2 (@pxref{References}),
+or any number theory textbook.  See also the example program
+@file{demos/qcn.c} which uses @code{mpz_kronecker_ui}.
+@end deftypefun
+
+@deftypefun {mp_bitcnt_t} mpz_remove (mpz_t @var{rop}, const mpz_t @var{op}, const mpz_t @var{f})
+@cindex Remove factor functions
+@cindex Factor removal functions
+Remove all occurrences of the factor @var{f} from @var{op} and store the
+result in @var{rop}.  The return value is how many such occurrences were
+removed.
+@end deftypefun
+
+@deftypefun void mpz_fac_ui (mpz_t @var{rop}, unsigned long int @var{n})
+@deftypefunx void mpz_2fac_ui (mpz_t @var{rop}, unsigned long int @var{n})
+@deftypefunx void mpz_mfac_uiui (mpz_t @var{rop}, unsigned long int @var{n}, unsigned long int @var{m})
+@cindex Factorial functions
+Set @var{rop} to the factorial of @var{n}: @code{mpz_fac_ui} computes the plain factorial @var{n}!,
+@code{mpz_2fac_ui} computes the double-factorial @var{n}!!, and @code{mpz_mfac_uiui} the
+@var{m}-multi-factorial @m{n!^{(m)}, @var{n}!^(@var{m})}.
+@end deftypefun
+
+@deftypefun void mpz_primorial_ui (mpz_t @var{rop}, unsigned long int @var{n})
+@cindex Primorial functions
+Set @var{rop} to the primorial of @var{n}, i.e. the product of all positive
+prime numbers @math{@le{}@var{n}}.
+@end deftypefun
+
+@deftypefun void mpz_bin_ui (mpz_t @var{rop}, const mpz_t @var{n}, unsigned long int @var{k})
+@deftypefunx void mpz_bin_uiui (mpz_t @var{rop}, unsigned long int @var{n}, @w{unsigned long int @var{k}})
+@cindex Binomial coefficient functions
+Compute the binomial coefficient @m{\left({n}\atop{k}\right), @var{n} over
+@var{k}} and store the result in @var{rop}.  Negative values of @var{n} are
+supported by @code{mpz_bin_ui}, using the identity
+@m{\left({-n}\atop{k}\right) = (-1)^k \left({n+k-1}\atop{k}\right),
+bin(-n@C{}k) = (-1)^k * bin(n+k-1@C{}k)}, see Knuth volume 1 section 1.2.6
+part G.
+@end deftypefun
+
+@deftypefun void mpz_fib_ui (mpz_t @var{fn}, unsigned long int @var{n})
+@deftypefunx void mpz_fib2_ui (mpz_t @var{fn}, mpz_t @var{fnsub1}, unsigned long int @var{n})
+@cindex Fibonacci sequence functions
+@code{mpz_fib_ui} sets @var{fn} to to @m{F_n,F[n]}, the @var{n}'th Fibonacci
+number.  @code{mpz_fib2_ui} sets @var{fn} to @m{F_n,F[n]}, and @var{fnsub1} to
+@m{F_{n-1},F[n-1]}.
+
+These functions are designed for calculating isolated Fibonacci numbers.  When
+a sequence of values is wanted it's best to start with @code{mpz_fib2_ui} and
+iterate the defining @m{F_{n+1} = F_n + F_{n-1}, F[n+1]=F[n]+F[n-1]} or
+similar.
+@end deftypefun
+
+@deftypefun void mpz_lucnum_ui (mpz_t @var{ln}, unsigned long int @var{n})
+@deftypefunx void mpz_lucnum2_ui (mpz_t @var{ln}, mpz_t @var{lnsub1}, unsigned long int @var{n})
+@cindex Lucas number functions
+@code{mpz_lucnum_ui} sets @var{ln} to to @m{L_n,L[n]}, the @var{n}'th Lucas
+number.  @code{mpz_lucnum2_ui} sets @var{ln} to @m{L_n,L[n]}, and @var{lnsub1}
+to @m{L_{n-1},L[n-1]}.
+
+These functions are designed for calculating isolated Lucas numbers.  When a
+sequence of values is wanted it's best to start with @code{mpz_lucnum2_ui} and
+iterate the defining @m{L_{n+1} = L_n + L_{n-1}, L[n+1]=L[n]+L[n-1]} or
+similar.
+
+The Fibonacci numbers and Lucas numbers are related sequences, so it's never
+necessary to call both @code{mpz_fib2_ui} and @code{mpz_lucnum2_ui}.  The
+formulas for going from Fibonacci to Lucas can be found in @ref{Lucas Numbers
+Algorithm}, the reverse is straightforward too.
+@end deftypefun
+
+
+@node Integer Comparisons, Integer Logic and Bit Fiddling, Number Theoretic Functions, Integer Functions
+@comment  node-name,  next,  previous,  up
+@section Comparison Functions
+@cindex Integer comparison functions
+@cindex Comparison functions
+
+@deftypefn Function int mpz_cmp (const mpz_t @var{op1}, const mpz_t @var{op2})
+@deftypefnx Function int mpz_cmp_d (const mpz_t @var{op1}, double @var{op2})
+@deftypefnx Macro int mpz_cmp_si (const mpz_t @var{op1}, signed long int @var{op2})
+@deftypefnx Macro int mpz_cmp_ui (const mpz_t @var{op1}, unsigned long int @var{op2})
+Compare @var{op1} and @var{op2}.  Return a positive value if @math{@var{op1} >
+@var{op2}}, zero if @math{@var{op1} = @var{op2}}, or a negative value if
+@math{@var{op1} < @var{op2}}.
+
+@code{mpz_cmp_ui} and @code{mpz_cmp_si} are macros and will evaluate their
+arguments more than once.  @code{mpz_cmp_d} can be called with an infinity,
+but results are undefined for a NaN.
+@end deftypefn
+
+@deftypefn Function int mpz_cmpabs (const mpz_t @var{op1}, const mpz_t @var{op2})
+@deftypefnx Function int mpz_cmpabs_d (const mpz_t @var{op1}, double @var{op2})
+@deftypefnx Function int mpz_cmpabs_ui (const mpz_t @var{op1}, unsigned long int @var{op2})
+Compare the absolute values of @var{op1} and @var{op2}.  Return a positive
+value if @math{@GMPabs{@var{op1}} > @GMPabs{@var{op2}}}, zero if
+@math{@GMPabs{@var{op1}} = @GMPabs{@var{op2}}}, or a negative value if
+@math{@GMPabs{@var{op1}} < @GMPabs{@var{op2}}}.
+
+@code{mpz_cmpabs_d} can be called with an infinity, but results are undefined
+for a NaN.
+@end deftypefn
+
+@deftypefn Macro int mpz_sgn (const mpz_t @var{op})
+@cindex Sign tests
+@cindex Integer sign tests
+Return @math{+1} if @math{@var{op} > 0}, 0 if @math{@var{op} = 0}, and
+@math{-1} if @math{@var{op} < 0}.
+
+This function is actually implemented as a macro.  It evaluates its argument
+multiple times.
+@end deftypefn
+
+
+@node Integer Logic and Bit Fiddling, I/O of Integers, Integer Comparisons, Integer Functions
+@comment  node-name,  next,  previous,  up
+@section Logical and Bit Manipulation Functions
+@cindex Logical functions
+@cindex Bit manipulation functions
+@cindex Integer logical functions
+@cindex Integer bit manipulation functions
+
+These functions behave as if twos complement arithmetic were used (although
+sign-magnitude is the actual implementation).  The least significant bit is
+number 0.
+
+@deftypefun void mpz_and (mpz_t @var{rop}, const mpz_t @var{op1}, const mpz_t @var{op2})
+Set @var{rop} to @var{op1} bitwise-and @var{op2}.
+@end deftypefun
+
+@deftypefun void mpz_ior (mpz_t @var{rop}, const mpz_t @var{op1}, const mpz_t @var{op2})
+Set @var{rop} to @var{op1} bitwise inclusive-or @var{op2}.
+@end deftypefun
+
+@deftypefun void mpz_xor (mpz_t @var{rop}, const mpz_t @var{op1}, const mpz_t @var{op2})
+Set @var{rop} to @var{op1} bitwise exclusive-or @var{op2}.
+@end deftypefun
+
+@deftypefun void mpz_com (mpz_t @var{rop}, const mpz_t @var{op})
+Set @var{rop} to the one's complement of @var{op}.
+@end deftypefun
+
+@deftypefun {mp_bitcnt_t} mpz_popcount (const mpz_t @var{op})
+If @math{@var{op}@ge{}0}, return the population count of @var{op}, which is the
+number of 1 bits in the binary representation.  If @math{@var{op}<0}, the
+number of 1s is infinite, and the return value is the largest possible
+@code{mp_bitcnt_t}.
+@end deftypefun
+
+@deftypefun {mp_bitcnt_t} mpz_hamdist (const mpz_t @var{op1}, const mpz_t @var{op2})
+If @var{op1} and @var{op2} are both @math{@ge{}0} or both @math{<0}, return the
+hamming distance between the two operands, which is the number of bit positions
+where @var{op1} and @var{op2} have different bit values.  If one operand is
+@math{@ge{}0} and the other @math{<0} then the number of bits different is
+infinite, and the return value is the largest possible @code{mp_bitcnt_t}.
+@end deftypefun
+
+@deftypefun {mp_bitcnt_t} mpz_scan0 (const mpz_t @var{op}, mp_bitcnt_t @var{starting_bit})
+@deftypefunx {mp_bitcnt_t} mpz_scan1 (const mpz_t @var{op}, mp_bitcnt_t @var{starting_bit})
+@cindex Bit scanning functions
+@cindex Scan bit functions
+Scan @var{op}, starting from bit @var{starting_bit}, towards more significant
+bits, until the first 0 or 1 bit (respectively) is found.  Return the index of
+the found bit.
+
+If the bit at @var{starting_bit} is already what's sought, then
+@var{starting_bit} is returned.
+
+If there's no bit found, then the largest possible @code{mp_bitcnt_t} is
+returned.  This will happen in @code{mpz_scan0} past the end of a negative
+number, or @code{mpz_scan1} past the end of a nonnegative number.
+@end deftypefun
+
+@deftypefun void mpz_setbit (mpz_t @var{rop}, mp_bitcnt_t @var{bit_index})
+Set bit @var{bit_index} in @var{rop}.
+@end deftypefun
+
+@deftypefun void mpz_clrbit (mpz_t @var{rop}, mp_bitcnt_t @var{bit_index})
+Clear bit @var{bit_index} in @var{rop}.
+@end deftypefun
+
+@deftypefun void mpz_combit (mpz_t @var{rop}, mp_bitcnt_t @var{bit_index})
+Complement bit @var{bit_index} in @var{rop}.
+@end deftypefun
+
+@deftypefun int mpz_tstbit (const mpz_t @var{op}, mp_bitcnt_t @var{bit_index})
+Test bit @var{bit_index} in @var{op} and return 0 or 1 accordingly.
+@end deftypefun
+
+@node I/O of Integers, Integer Random Numbers, Integer Logic and Bit Fiddling, Integer Functions
+@comment  node-name,  next,  previous,  up
+@section Input and Output Functions
+@cindex Integer input and output functions
+@cindex Input functions
+@cindex Output functions
+@cindex I/O functions
+
+Functions that perform input from a stdio stream, and functions that output to
+a stdio stream, of @code{mpz} numbers.  Passing a @code{NULL} pointer for a
+@var{stream} argument to any of these functions will make them read from
+@code{stdin} and write to @code{stdout}, respectively.
+
+When using any of these functions, it is a good idea to include @file{stdio.h}
+before @file{gmp.h}, since that will allow @file{gmp.h} to define prototypes
+for these functions.
+
+See also @ref{Formatted Output} and @ref{Formatted Input}.
+
+@deftypefun size_t mpz_out_str (FILE *@var{stream}, int @var{base}, const mpz_t @var{op})
+Output @var{op} on stdio stream @var{stream}, as a string of digits in base
+@var{base}.  The base argument may vary from 2 to 62 or from @minus{}2 to
+@minus{}36.
+
+For @var{base} in the range 2..36, digits and lower-case letters are used; for
+@minus{}2..@minus{}36, digits and upper-case letters are used; for 37..62,
+digits, upper-case letters, and lower-case letters (in that significance order)
+are used.
+
+Return the number of bytes written, or if an error occurred, return 0.
+@end deftypefun
+
+@deftypefun size_t mpz_inp_str (mpz_t @var{rop}, FILE *@var{stream}, int @var{base})
+Input a possibly white-space preceded string in base @var{base} from stdio
+stream @var{stream}, and put the read integer in @var{rop}.
+
+The @var{base} may vary from 2 to 62, or if @var{base} is 0, then the leading
+characters are used: @code{0x} and @code{0X} for hexadecimal, @code{0b} and
+@code{0B} for binary, @code{0} for octal, or decimal otherwise.
+
+For bases up to 36, case is ignored; upper-case and lower-case letters have
+the same value.  For bases 37 to 62, upper-case letter represent the usual
+10..35 while lower-case letter represent 36..61.
+
+Return the number of bytes read, or if an error occurred, return 0.
+@end deftypefun
+
+@deftypefun size_t mpz_out_raw (FILE *@var{stream}, const mpz_t @var{op})
+Output @var{op} on stdio stream @var{stream}, in raw binary format.  The
+integer is written in a portable format, with 4 bytes of size information, and
+that many bytes of limbs.  Both the size and the limbs are written in
+decreasing significance order (i.e., in big-endian).
+
+The output can be read with @code{mpz_inp_raw}.
+
+Return the number of bytes written, or if an error occurred, return 0.
+
+The output of this can not be read by @code{mpz_inp_raw} from GMP 1, because
+of changes necessary for compatibility between 32-bit and 64-bit machines.
+@end deftypefun
+
+@deftypefun size_t mpz_inp_raw (mpz_t @var{rop}, FILE *@var{stream})
+Input from stdio stream @var{stream} in the format written by
+@code{mpz_out_raw}, and put the result in @var{rop}.  Return the number of
+bytes read, or if an error occurred, return 0.
+
+This routine can read the output from @code{mpz_out_raw} also from GMP 1, in
+spite of changes necessary for compatibility between 32-bit and 64-bit
+machines.
+@end deftypefun
+
+
+@need 2000
+@node Integer Random Numbers, Integer Import and Export, I/O of Integers, Integer Functions
+@comment  node-name,  next,  previous,  up
+@section Random Number Functions
+@cindex Integer random number functions
+@cindex Random number functions
+
+The random number functions of GMP come in two groups; older function
+that rely on a global state, and newer functions that accept a state
+parameter that is read and modified.  Please see the @ref{Random Number
+Functions} for more information on how to use and not to use random
+number functions.
+
+@deftypefun void mpz_urandomb (mpz_t @var{rop}, gmp_randstate_t @var{state}, mp_bitcnt_t @var{n})
+Generate a uniformly distributed random integer in the range 0 to
+@mm{2@sup{n}-1, 2^@var{n}@minus{}1}, inclusive.
+
+The variable @var{state} must be initialized by calling one of the
+@code{gmp_randinit} functions (@ref{Random State Initialization}) before
+invoking this function.
+@end deftypefun
+
+@deftypefun void mpz_urandomm (mpz_t @var{rop}, gmp_randstate_t @var{state}, const mpz_t @var{n})
+Generate a uniform random integer in the range 0 to @math{@var{n}-1},
+inclusive.
+
+The variable @var{state} must be initialized by calling one of the
+@code{gmp_randinit} functions (@ref{Random State Initialization})
+before invoking this function.
+@end deftypefun
+
+@deftypefun void mpz_rrandomb (mpz_t @var{rop}, gmp_randstate_t @var{state}, mp_bitcnt_t @var{n})
+Generate a random integer with long strings of zeros and ones in the
+binary representation.  Useful for testing functions and algorithms,
+since this kind of random numbers have proven to be more likely to
+trigger corner-case bugs.  The random number will be in the range
+@mm{2@sup{n-1}, 2^(@var{n}@minus{}1)} to @mm{2@sup{n}-1,
+2^@var{n}@minus{}1}, inclusive.
+
+The variable @var{state} must be initialized by calling one of the
+@code{gmp_randinit} functions (@ref{Random State Initialization})
+before invoking this function.
+@end deftypefun
+
+@deftypefun void mpz_random (mpz_t @var{rop}, mp_size_t @var{max_size})
+Generate a random integer of at most @var{max_size} limbs.  The generated
+random number doesn't satisfy any particular requirements of randomness.
+Negative random numbers are generated when @var{max_size} is negative.
+
+This function is obsolete.  Use @code{mpz_urandomb} or
+@code{mpz_urandomm} instead.
+@end deftypefun
+
+@deftypefun void mpz_random2 (mpz_t @var{rop}, mp_size_t @var{max_size})
+Generate a random integer of at most @var{max_size} limbs, with long strings
+of zeros and ones in the binary representation.  Useful for testing functions
+and algorithms, since this kind of random numbers have proven to be more
+likely to trigger corner-case bugs.  Negative random numbers are generated
+when @var{max_size} is negative.
+
+This function is obsolete.  Use @code{mpz_rrandomb} instead.
+@end deftypefun
+
+
+@node Integer Import and Export, Miscellaneous Integer Functions, Integer Random Numbers, Integer Functions
+@section Integer Import and Export
+
+@code{mpz_t} variables can be converted to and from arbitrary words of binary
+data with the following functions.
+
+@deftypefun void mpz_import (mpz_t @var{rop}, size_t @var{count}, int @var{order}, size_t @var{size}, int @var{endian}, size_t @var{nails}, const void *@var{op})
+@cindex Integer import
+@cindex Import
+Set @var{rop} from an array of word data at @var{op}.
+
+The parameters specify the format of the data.  @var{count} many words are
+read, each @var{size} bytes.  @var{order} can be 1 for most significant word
+first or -1 for least significant first.  Within each word @var{endian} can be
+1 for most significant byte first, -1 for least significant first, or 0 for
+the native endianness of the host CPU@.  The most significant @var{nails} bits
+of each word are skipped, this can be 0 to use the full words.
+
+There is no sign taken from the data, @var{rop} will simply be a positive
+integer.  An application can handle any sign itself, and apply it for instance
+with @code{mpz_neg}.
+
+There are no data alignment restrictions on @var{op}, any address is allowed.
+
+Here's an example converting an array of @code{unsigned long} data, most
+significant element first, and host byte order within each value.
+
+@example
+unsigned long  a[20];
+/* Initialize @var{z} and @var{a} */
+mpz_import (z, 20, 1, sizeof(a[0]), 0, 0, a);
+@end example
+
+This example assumes the full @code{sizeof} bytes are used for data in the
+given type, which is usually true, and certainly true for @code{unsigned long}
+everywhere we know of.  However on Cray vector systems it may be noted that
+@code{short} and @code{int} are always stored in 8 bytes (and with
+@code{sizeof} indicating that) but use only 32 or 46 bits.  The @var{nails}
+feature can account for this, by passing for instance
+@code{8*sizeof(int)-INT_BIT}.
+@end deftypefun
+
+@deftypefun {void *} mpz_export (void *@var{rop}, size_t *@var{countp}, int @var{order}, size_t @var{size}, int @var{endian}, size_t @var{nails}, const mpz_t @var{op})
+@cindex Integer export
+@cindex Export
+Fill @var{rop} with word data from @var{op}.
+
+The parameters specify the format of the data produced.  Each word will be
+@var{size} bytes and @var{order} can be 1 for most significant word first or
+-1 for least significant first.  Within each word @var{endian} can be 1 for
+most significant byte first, -1 for least significant first, or 0 for the
+native endianness of the host CPU@.  The most significant @var{nails} bits of
+each word are unused and set to zero, this can be 0 to produce full words.
+
+The number of words produced is written to @code{*@var{countp}}, or
+@var{countp} can be @code{NULL} to discard the count.  @var{rop} must have
+enough space for the data, or if @var{rop} is @code{NULL} then a result array
+of the necessary size is allocated using the current GMP allocation function
+(@pxref{Custom Allocation}).  In either case the return value is the
+destination used, either @var{rop} or the allocated block.
+
+If @var{op} is non-zero then the most significant word produced will be
+non-zero.  If @var{op} is zero then the count returned will be zero and
+nothing written to @var{rop}.  If @var{rop} is @code{NULL} in this case, no
+block is allocated, just @code{NULL} is returned.
+
+The sign of @var{op} is ignored, just the absolute value is exported.  An
+application can use @code{mpz_sgn} to get the sign and handle it as desired.
+(@pxref{Integer Comparisons})
+
+There are no data alignment restrictions on @var{rop}, any address is allowed.
+
+When an application is allocating space itself the required size can be
+determined with a calculation like the following.  Since @code{mpz_sizeinbase}
+always returns at least 1, @code{count} here will be at least one, which
+avoids any portability problems with @code{malloc(0)}, though if @code{z} is
+zero no space at all is actually needed (or written).
+
+@example
+numb = 8*size - nail;
+count = (mpz_sizeinbase (z, 2) + numb-1) / numb;
+p = malloc (count * size);
+@end example
+@end deftypefun
+
+
+@need 2000
+@node Miscellaneous Integer Functions, Integer Special Functions, Integer Import and Export, Integer Functions
+@comment  node-name,  next,  previous,  up
+@section Miscellaneous Functions
+@cindex Miscellaneous integer functions
+@cindex Integer miscellaneous functions
+
+@deftypefun int mpz_fits_ulong_p (const mpz_t @var{op})
+@deftypefunx int mpz_fits_slong_p (const mpz_t @var{op})
+@deftypefunx int mpz_fits_uint_p (const mpz_t @var{op})
+@deftypefunx int mpz_fits_sint_p (const mpz_t @var{op})
+@deftypefunx int mpz_fits_ushort_p (const mpz_t @var{op})
+@deftypefunx int mpz_fits_sshort_p (const mpz_t @var{op})
+Return non-zero iff the value of @var{op} fits in an @code{unsigned long int},
+@code{signed long int}, @code{unsigned int}, @code{signed int}, @code{unsigned
+short int}, or @code{signed short int}, respectively.  Otherwise, return zero.
+@end deftypefun
+
+@deftypefn Macro int mpz_odd_p (const mpz_t @var{op})
+@deftypefnx Macro int mpz_even_p (const mpz_t @var{op})
+Determine whether @var{op} is odd or even, respectively.  Return non-zero if
+yes, zero if no.  These macros evaluate their argument more than once.
+@end deftypefn
+
+@deftypefun size_t mpz_sizeinbase (const mpz_t @var{op}, int @var{base})
+@cindex Size in digits
+@cindex Digits in an integer
+Return the size of @var{op} measured in number of digits in the given
+@var{base}.  @var{base} can vary from 2 to 62.  The sign of @var{op} is
+ignored, just the absolute value is used.  The result will be either exact or
+1 too big.  If @var{base} is a power of 2, the result is always exact.  If
+@var{op} is zero the return value is always 1.
+
+This function can be used to determine the space required when converting
+@var{op} to a string.  The right amount of allocation is normally two more
+than the value returned by @code{mpz_sizeinbase}, one extra for a minus sign
+and one for the null-terminator.
+
+@cindex Most significant bit
+It will be noted that @code{mpz_sizeinbase(@var{op},2)} can be used to locate
+the most significant 1 bit in @var{op}, counting from 1.  (Unlike the bitwise
+functions which start from 0, @xref{Integer Logic and Bit Fiddling,, Logical
+and Bit Manipulation Functions}.)
+@end deftypefun
+
+
+@node Integer Special Functions,  , Miscellaneous Integer Functions, Integer Functions
+@section Special Functions
+@cindex Special integer functions
+@cindex Integer special functions
+
+The functions in this section are for various special purposes.  Most
+applications will not need them.
+
+@deftypefun void mpz_array_init (mpz_t @var{integer_array}, mp_size_t @var{array_size}, @w{mp_size_t @var{fixed_num_bits}})
+@strong{This is an obsolete function.  Do not use it.}
+@end deftypefun
+
+@deftypefun {void *} _mpz_realloc (mpz_t @var{integer}, mp_size_t @var{new_alloc})
+Change the space for @var{integer} to @var{new_alloc} limbs.  The value in
+@var{integer} is preserved if it fits, or is set to 0 if not.  The return
+value is not useful to applications and should be ignored.
+
+@code{mpz_realloc2} is the preferred way to accomplish allocation changes like
+this.  @code{mpz_realloc2} and @code{_mpz_realloc} are the same except that
+@code{_mpz_realloc} takes its size in limbs.
+@end deftypefun
+
+@deftypefun mp_limb_t mpz_getlimbn (const mpz_t @var{op}, mp_size_t @var{n})
+Return limb number @var{n} from @var{op}.  The sign of @var{op} is ignored,
+just the absolute value is used.  The least significant limb is number 0.
+
+@code{mpz_size} can be used to find how many limbs make up @var{op}.
+@code{mpz_getlimbn} returns zero if @var{n} is outside the range 0 to
+@code{mpz_size(@var{op})-1}.
+@end deftypefun
+
+@deftypefun size_t mpz_size (const mpz_t @var{op})
+Return the size of @var{op} measured in number of limbs.  If @var{op} is zero,
+the returned value will be zero.
+@c (@xref{Nomenclature}, for an explanation of the concept @dfn{limb}.)
+@end deftypefun
+
+@deftypefun {const mp_limb_t *} mpz_limbs_read (const mpz_t @var{x})
+Return a pointer to the limb array representing the absolute value of @var{x}.
+The size of the array is @code{mpz_size(@var{x})}. Intended for read access
+only.
+@end deftypefun
+
+@deftypefun {mp_limb_t *} mpz_limbs_write (mpz_t @var{x}, mp_size_t @var{n})
+@deftypefunx {mp_limb_t *} mpz_limbs_modify (mpz_t @var{x}, mp_size_t @var{n})
+Return a pointer to the limb array, intended for write access. The array is
+reallocated as needed, to make room for @var{n} limbs. Requires @math{@var{n}
+> 0}. The @code{mpz_limbs_modify} function returns an array that holds the old
+absolute value of @var{x}, while @code{mpz_limbs_write} may destroy the old
+value and return an array with unspecified contents.
+@end deftypefun
+
+@deftypefun void mpz_limbs_finish (mpz_t @var{x}, mp_size_t @var{s})
+Updates the internal size field of @var{x}. Used after writing to the limb
+array pointer returned by @code{mpz_limbs_write} or @code{mpz_limbs_modify} is
+completed. The array should contain @math{@GMPabs{@var{s}}} valid limbs,
+representing the new absolute value for @var{x}, and the sign of @var{x} is
+taken from the sign of @var{s}. This function never reallocates @var{x}, so
+the limb pointer remains valid.
+@end deftypefun
+
+@c FIXME: Some more useful and less silly example?
+@example
+void foo (mpz_t x)
+@{
+  mp_size_t n, i;
+  mp_limb_t *xp;
+
+  n = mpz_size (x);
+  xp = mpz_limbs_modify (x, 2*n);
+  for (i = 0; i < n; i++)
+    xp[n+i] = xp[n-1-i];
+  mpz_limbs_finish (x, mpz_sgn (x) < 0 ? - 2*n : 2*n);
+@}
+@end example
+
+@deftypefun mpz_srcptr mpz_roinit_n (mpz_t @var{x}, const mp_limb_t *@var{xp}, mp_size_t @var{xs})
+Special initialization of @var{x}, using the given limb array and size.
+@var{x} should be treated as read-only: it can be passed safely as input to
+any mpz function, but not as an output. The array @var{xp} must point to at
+least a readable limb, its size is
+@math{@GMPabs{@var{xs}}}, and the sign of @var{x} is the sign of @var{xs}. For
+convenience, the function returns @var{x}, but cast to a const pointer type.
+@end deftypefun
+
+@example
+void foo (mpz_t x)
+@{
+  static const mp_limb_t y[3] = @{ 0x1, 0x2, 0x3 @};
+  mpz_t tmp;
+  mpz_add (x, x, mpz_roinit_n (tmp, y, 3));
+@}
+@end example
+
+@deftypefn Macro mpz_t MPZ_ROINIT_N (mp_limb_t *@var{xp}, mp_size_t @var{xs})
+This macro expands to an initializer which can be assigned to an mpz_t
+variable. The limb array @var{xp} must point to at least a readable limb,
+moreover, unlike the @code{mpz_roinit_n} function, the array must be
+normalized: if @var{xs} is non-zero, then
+@code{@var{xp}[@math{@GMPabs{@var{xs}}-1}]} must be non-zero. Intended
+primarily for constant values. Using it for non-constant values requires a C
+compiler supporting C99.
+@end deftypefn
+
+@example
+void foo (mpz_t x)
+@{
+  static const mp_limb_t ya[3] = @{ 0x1, 0x2, 0x3 @};
+  static const mpz_t y = MPZ_ROINIT_N ((mp_limb_t *) ya, 3);
+
+  mpz_add (x, x, y);
+@}
+@end example
+
+
+@node Rational Number Functions, Floating-point Functions, Integer Functions, Top
+@comment  node-name,  next,  previous,  up
+@chapter Rational Number Functions
+@cindex Rational number functions
+
+This chapter describes the GMP functions for performing arithmetic on rational
+numbers.  These functions start with the prefix @code{mpq_}.
+
+Rational numbers are stored in objects of type @code{mpq_t}.
+
+All rational arithmetic functions assume operands have a canonical form, and
+canonicalize their result.  The canonical form means that the denominator and
+the numerator have no common factors, and that the denominator is positive.
+Zero has the unique representation 0/1.
+
+Pure assignment functions do not canonicalize the assigned variable.  It is
+the responsibility of the user to canonicalize the assigned variable before
+any arithmetic operations are performed on that variable.
+
+@deftypefun void mpq_canonicalize (mpq_t @var{op})
+Remove any factors that are common to the numerator and denominator of
+@var{op}, and make the denominator positive.
+@end deftypefun
+
+@menu
+* Initializing Rationals::
+* Rational Conversions::
+* Rational Arithmetic::
+* Comparing Rationals::
+* Applying Integer Functions::
+* I/O of Rationals::
+@end menu
+
+@node Initializing Rationals, Rational Conversions, Rational Number Functions, Rational Number Functions
+@comment  node-name,  next,  previous,  up
+@section Initialization and Assignment Functions
+@cindex Rational assignment functions
+@cindex Assignment functions
+@cindex Rational initialization functions
+@cindex Initialization functions
+
+@deftypefun void mpq_init (mpq_t @var{x})
+Initialize @var{x} and set it to 0/1.  Each variable should normally only be
+initialized once, or at least cleared out (using the function @code{mpq_clear})
+between each initialization.
+@end deftypefun
+
+@deftypefun void mpq_inits (mpq_t @var{x}, ...)
+Initialize a NULL-terminated list of @code{mpq_t} variables, and set their
+values to 0/1.
+@end deftypefun
+
+@deftypefun void mpq_clear (mpq_t @var{x})
+Free the space occupied by @var{x}.  Make sure to call this function for all
+@code{mpq_t} variables when you are done with them.
+@end deftypefun
+
+@deftypefun void mpq_clears (mpq_t @var{x}, ...)
+Free the space occupied by a NULL-terminated list of @code{mpq_t} variables.
+@end deftypefun
+
+@deftypefun void mpq_set (mpq_t @var{rop}, const mpq_t @var{op})
+@deftypefunx void mpq_set_z (mpq_t @var{rop}, const mpz_t @var{op})
+Assign @var{rop} from @var{op}.
+@end deftypefun
+
+@deftypefun void mpq_set_ui (mpq_t @var{rop}, unsigned long int @var{op1}, unsigned long int @var{op2})
+@deftypefunx void mpq_set_si (mpq_t @var{rop}, signed long int @var{op1}, unsigned long int @var{op2})
+Set the value of @var{rop} to @var{op1}/@var{op2}.  Note that if @var{op1} and
+@var{op2} have common factors, @var{rop} has to be passed to
+@code{mpq_canonicalize} before any operations are performed on @var{rop}.
+@end deftypefun
+
+@deftypefun int mpq_set_str (mpq_t @var{rop}, const char *@var{str}, int @var{base})
+Set @var{rop} from a null-terminated string @var{str} in the given @var{base}.
+
+The string can be an integer like ``41'' or a fraction like ``41/152''.  The
+fraction must be in canonical form (@pxref{Rational Number Functions}), or if
+not then @code{mpq_canonicalize} must be called.
+
+The numerator and optional denominator are parsed the same as in
+@code{mpz_set_str} (@pxref{Assigning Integers}).  White space is allowed in
+the string, and is simply ignored.  The @var{base} can vary from 2 to 62, or
+if @var{base} is 0 then the leading characters are used: @code{0x} or @code{0X} for hex,
+@code{0b} or @code{0B} for binary,
+@code{0} for octal, or decimal otherwise.  Note that this is done separately
+for the numerator and denominator, so for instance @code{0xEF/100} is 239/100,
+whereas @code{0xEF/0x100} is 239/256.
+
+The return value is 0 if the entire string is a valid number, or @minus{}1 if
+not.
+@end deftypefun
+
+@deftypefun void mpq_swap (mpq_t @var{rop1}, mpq_t @var{rop2})
+Swap the values @var{rop1} and @var{rop2} efficiently.
+@end deftypefun
+
+
+@need 2000
+@node Rational Conversions, Rational Arithmetic, Initializing Rationals, Rational Number Functions
+@comment  node-name,  next,  previous,  up
+@section Conversion Functions
+@cindex Rational conversion functions
+@cindex Conversion functions
+
+@deftypefun double mpq_get_d (const mpq_t @var{op})
+Convert @var{op} to a @code{double}, truncating if necessary (i.e.@: rounding
+towards zero).
+
+If the exponent from the conversion is too big or too small to fit a
+@code{double} then the result is system dependent.  For too big an infinity is
+returned when available.  For too small @math{0.0} is normally returned.
+Hardware overflow, underflow and denorm traps may or may not occur.
+@end deftypefun
+
+@deftypefun void mpq_set_d (mpq_t @var{rop}, double @var{op})
+@deftypefunx void mpq_set_f (mpq_t @var{rop}, const mpf_t @var{op})
+Set @var{rop} to the value of @var{op}.  There is no rounding, this conversion
+is exact.
+@end deftypefun
+
+@deftypefun {char *} mpq_get_str (char *@var{str}, int @var{base}, const mpq_t @var{op})
+Convert @var{op} to a string of digits in base @var{base}.  The base argument
+may vary from 2 to 62 or from @minus{}2 to @minus{}36.  The string will be of
+the form @samp{num/den}, or if the denominator is 1 then just @samp{num}.
+
+For @var{base} in the range 2..36, digits and lower-case letters are used; for
+@minus{}2..@minus{}36, digits and upper-case letters are used; for 37..62,
+digits, upper-case letters, and lower-case letters (in that significance order)
+are used.
+
+If @var{str} is @code{NULL}, the result string is allocated using the current
+allocation function (@pxref{Custom Allocation}).  The block will be
+@code{strlen(str)+1} bytes, that being exactly enough for the string and
+null-terminator.
+
+If @var{str} is not @code{NULL}, it should point to a block of storage large
+enough for the result, that being
+
+@example
+mpz_sizeinbase (mpq_numref(@var{op}), @var{base})
++ mpz_sizeinbase (mpq_denref(@var{op}), @var{base}) + 3
+@end example
+
+The three extra bytes are for a possible minus sign, possible slash, and the
+null-terminator.
+
+A pointer to the result string is returned, being either the allocated block,
+or the given @var{str}.
+@end deftypefun
+
+
+@node Rational Arithmetic, Comparing Rationals, Rational Conversions, Rational Number Functions
+@comment  node-name,  next,  previous,  up
+@section Arithmetic Functions
+@cindex Rational arithmetic functions
+@cindex Arithmetic functions
+
+@deftypefun void mpq_add (mpq_t @var{sum}, const mpq_t @var{addend1}, const mpq_t @var{addend2})
+Set @var{sum} to @var{addend1} + @var{addend2}.
+@end deftypefun
+
+@deftypefun void mpq_sub (mpq_t @var{difference}, const mpq_t @var{minuend}, const mpq_t @var{subtrahend})
+Set @var{difference} to @var{minuend} @minus{} @var{subtrahend}.
+@end deftypefun
+
+@deftypefun void mpq_mul (mpq_t @var{product}, const mpq_t @var{multiplier}, const mpq_t @var{multiplicand})
+Set @var{product} to @math{@var{multiplier} @GMPtimes{} @var{multiplicand}}.
+@end deftypefun
+
+@deftypefun void mpq_mul_2exp (mpq_t @var{rop}, const mpq_t @var{op1}, mp_bitcnt_t @var{op2})
+Set @var{rop} to @m{@var{op1} \times 2^{op2}, @var{op1} times 2 raised to
+@var{op2}}.
+@end deftypefun
+
+@deftypefun void mpq_div (mpq_t @var{quotient}, const mpq_t @var{dividend}, const mpq_t @var{divisor})
+@cindex Division functions
+Set @var{quotient} to @var{dividend}/@var{divisor}.
+@end deftypefun
+
+@deftypefun void mpq_div_2exp (mpq_t @var{rop}, const mpq_t @var{op1}, mp_bitcnt_t @var{op2})
+Set @var{rop} to @m{@var{op1}/2^{op2}, @var{op1} divided by 2 raised to
+@var{op2}}.
+@end deftypefun
+
+@deftypefun void mpq_neg (mpq_t @var{negated_operand}, const mpq_t @var{operand})
+Set @var{negated_operand} to @minus{}@var{operand}.
+@end deftypefun
+
+@deftypefun void mpq_abs (mpq_t @var{rop}, const mpq_t @var{op})
+Set @var{rop} to the absolute value of @var{op}.
+@end deftypefun
+
+@deftypefun void mpq_inv (mpq_t @var{inverted_number}, const mpq_t @var{number})
+Set @var{inverted_number} to 1/@var{number}.  If the new denominator is
+zero, this routine will divide by zero.
+@end deftypefun
+
+@node Comparing Rationals, Applying Integer Functions, Rational Arithmetic, Rational Number Functions
+@comment  node-name,  next,  previous,  up
+@section Comparison Functions
+@cindex Rational comparison functions
+@cindex Comparison functions
+
+@deftypefun int mpq_cmp (const mpq_t @var{op1}, const mpq_t @var{op2})
+@deftypefunx int mpq_cmp_z (const mpq_t @var{op1}, const mpz_t @var{op2})
+Compare @var{op1} and @var{op2}.  Return a positive value if @math{@var{op1} >
+@var{op2}}, zero if @math{@var{op1} = @var{op2}}, and a negative value if
+@math{@var{op1} < @var{op2}}.
+
+To determine if two rationals are equal, @code{mpq_equal} is faster than
+@code{mpq_cmp}.
+@end deftypefun
+
+@deftypefn Macro int mpq_cmp_ui (const mpq_t @var{op1}, unsigned long int @var{num2}, unsigned long int @var{den2})
+@deftypefnx Macro int mpq_cmp_si (const mpq_t @var{op1}, long int @var{num2}, unsigned long int @var{den2})
+Compare @var{op1} and @var{num2}/@var{den2}.  Return a positive value if
+@math{@var{op1} > @var{num2}/@var{den2}}, zero if @math{@var{op1} =
+@var{num2}/@var{den2}}, and a negative value if @math{@var{op1} <
+@var{num2}/@var{den2}}.
+
+@var{num2} and @var{den2} are allowed to have common factors.
+
+These functions are implemented as a macros and evaluate their arguments
+multiple times.
+@end deftypefn
+
+@deftypefn Macro int mpq_sgn (const mpq_t @var{op})
+@cindex Sign tests
+@cindex Rational sign tests
+Return @math{+1} if @math{@var{op} > 0}, 0 if @math{@var{op} = 0}, and
+@math{-1} if @math{@var{op} < 0}.
+
+This function is actually implemented as a macro.  It evaluates its
+argument multiple times.
+@end deftypefn
+
+@deftypefun int mpq_equal (const mpq_t @var{op1}, const mpq_t @var{op2})
+Return non-zero if @var{op1} and @var{op2} are equal, zero if they are
+non-equal.  Although @code{mpq_cmp} can be used for the same purpose, this
+function is much faster.
+@end deftypefun
+
+@node Applying Integer Functions, I/O of Rationals, Comparing Rationals, Rational Number Functions
+@comment  node-name,  next,  previous,  up
+@section Applying Integer Functions to Rationals
+@cindex Rational numerator and denominator
+@cindex Numerator and denominator
+
+The set of @code{mpq} functions is quite small.  In particular, there are few
+functions for either input or output.  The following functions give direct
+access to the numerator and denominator of an @code{mpq_t}.
+
+Note that if an assignment to the numerator and/or denominator could take an
+@code{mpq_t} out of the canonical form described at the start of this chapter
+(@pxref{Rational Number Functions}) then @code{mpq_canonicalize} must be
+called before any other @code{mpq} functions are applied to that @code{mpq_t}.
+
+@deftypefn Macro mpz_t mpq_numref (const mpq_t @var{op})
+@deftypefnx Macro mpz_t mpq_denref (const mpq_t @var{op})
+Return a reference to the numerator and denominator of @var{op}, respectively.
+The @code{mpz} functions can be used on the result of these macros.
+@end deftypefn
+
+@deftypefun void mpq_get_num (mpz_t @var{numerator}, const mpq_t @var{rational})
+@deftypefunx void mpq_get_den (mpz_t @var{denominator}, const mpq_t @var{rational})
+@deftypefunx void mpq_set_num (mpq_t @var{rational}, const mpz_t @var{numerator})
+@deftypefunx void mpq_set_den (mpq_t @var{rational}, const mpz_t @var{denominator})
+Get or set the numerator or denominator of a rational.  These functions are
+equivalent to calling @code{mpz_set} with an appropriate @code{mpq_numref} or
+@code{mpq_denref}.  Direct use of @code{mpq_numref} or @code{mpq_denref} is
+recommended instead of these functions.
+@end deftypefun
+
+
+@need 2000
+@node I/O of Rationals,  , Applying Integer Functions, Rational Number Functions
+@comment  node-name,  next,  previous,  up
+@section Input and Output Functions
+@cindex Rational input and output functions
+@cindex Input functions
+@cindex Output functions
+@cindex I/O functions
+
+Functions that perform input from a stdio stream, and functions that output to
+a stdio stream, of @code{mpq} numbers.  Passing a @code{NULL} pointer for a
+@var{stream} argument to any of these functions will make them read from
+@code{stdin} and write to @code{stdout}, respectively.
+
+When using any of these functions, it is a good idea to include @file{stdio.h}
+before @file{gmp.h}, since that will allow @file{gmp.h} to define prototypes
+for these functions.
+
+See also @ref{Formatted Output} and @ref{Formatted Input}.
+
+@deftypefun size_t mpq_out_str (FILE *@var{stream}, int @var{base}, const mpq_t @var{op})
+Output @var{op} on stdio stream @var{stream}, as a string of digits in base
+@var{base}.  The base argument may vary from 2 to 62 or from @minus{}2 to
+@minus{}36. Output is in the form
+@samp{num/den} or if the denominator is 1 then just @samp{num}.
+
+For @var{base} in the range 2..36, digits and lower-case letters are used; for
+@minus{}2..@minus{}36, digits and upper-case letters are used; for 37..62,
+digits, upper-case letters, and lower-case letters (in that significance order)
+are used.
+
+Return the number of bytes written, or if an error occurred, return 0.
+@end deftypefun
+
+@deftypefun size_t mpq_inp_str (mpq_t @var{rop}, FILE *@var{stream}, int @var{base})
+Read a string of digits from @var{stream} and convert them to a rational in
+@var{rop}.  Any initial white-space characters are read and discarded.  Return
+the number of characters read (including white space), or 0 if a rational
+could not be read.
+
+The input can be a fraction like @samp{17/63} or just an integer like
+@samp{123}.  Reading stops at the first character not in this form, and white
+space is not permitted within the string.  If the input might not be in
+canonical form, then @code{mpq_canonicalize} must be called (@pxref{Rational
+Number Functions}).
+
+The @var{base} can be between 2 and 62, or can be 0 in which case the leading
+characters of the string determine the base, @samp{0x} or @samp{0X} for
+hexadecimal, @code{0b} and @code{0B} for binary, @samp{0} for octal, or
+decimal otherwise.  The leading characters
+are examined separately for the numerator and denominator of a fraction, so
+for instance @samp{0x10/11} is @math{16/11}, whereas @samp{0x10/0x11} is
+@math{16/17}.
+@end deftypefun
+
+
+@node Floating-point Functions, Low-level Functions, Rational Number Functions, Top
+@comment  node-name,  next,  previous,  up
+@chapter Floating-point Functions
+@cindex Floating-point functions
+@cindex Float functions
+@cindex User-defined precision
+@cindex Precision of floats
+
+GMP floating point numbers are stored in objects of type @code{mpf_t} and
+functions operating on them have an @code{mpf_} prefix.
+
+The mantissa of each float has a user-selectable precision, in practice only
+limited by available memory.  Each variable has its own precision, and that can
+be increased or decreased at any time.  This selectable precision is a minimum
+value, GMP rounds it up to a whole limb.
+
+The accuracy of a calculation is determined by the priorly set precision of the
+destination variable and the numeric values of the input variables.  Input
+variables' set precisions do not affect calculations (except indirectly as
+their values might have been affected when they were assigned).
+
+The exponent of each float has fixed precision, one machine word on most
+systems.  In the current implementation the exponent is a count of limbs, so
+for example on a 32-bit system this means a range of roughly
+@math{2^@W{-68719476768}} to @math{2^@W{68719476736}}, or on a 64-bit system
+this will be much greater.  Note however that @code{mpf_get_str} can only
+return an exponent which fits an @code{mp_exp_t} and currently
+@code{mpf_set_str} doesn't accept exponents bigger than a @code{long}.
+
+Each variable keeps track of the mantissa data actually in use.  This means
+that if a float is exactly represented in only a few bits then only those bits
+will be used in a calculation, even if the variable's selected precision is
+high.  This is a performance optimization; it does not affect the numeric
+results.
+
+Internally, GMP sometimes calculates with higher precision than that of the
+destination variable in order to limit errors.  Final results are always
+truncated to the destination variable's precision.
+
+The mantissa is stored in binary.  One consequence of this is that decimal
+fractions like @math{0.1} cannot be represented exactly.  The same is true of
+plain IEEE @code{double} floats.  This makes both highly unsuitable for
+calculations involving money or other values that should be exact decimal
+fractions.  (Suitably scaled integers, or perhaps rationals, are better
+choices.)
+
+The @code{mpf} functions and variables have no special notion of infinity or
+not-a-number, and applications must take care not to overflow the exponent or
+results will be unpredictable.
+
+Note that the @code{mpf} functions are @emph{not} intended as a smooth
+extension to IEEE P754 arithmetic.  In particular results obtained on one
+computer often differ from the results on a computer with a different word
+size.
+
+New projects should consider using the GMP extension library MPFR
+(@url{http://mpfr.org}) instead.  MPFR provides well-defined precision and
+accurate rounding, and thereby naturally extends IEEE P754.
+
+@menu
+* Initializing Floats::
+* Assigning Floats::
+* Simultaneous Float Init & Assign::
+* Converting Floats::
+* Float Arithmetic::
+* Float Comparison::
+* I/O of Floats::
+* Miscellaneous Float Functions::
+@end menu
+
+@node Initializing Floats, Assigning Floats, Floating-point Functions, Floating-point Functions
+@comment  node-name,  next,  previous,  up
+@section Initialization Functions
+@cindex Float initialization functions
+@cindex Initialization functions
+
+@deftypefun void mpf_set_default_prec (mp_bitcnt_t @var{prec})
+Set the default precision to be @strong{at least} @var{prec} bits.  All
+subsequent calls to @code{mpf_init} will use this precision, but previously
+initialized variables are unaffected.
+@end deftypefun
+
+@deftypefun {mp_bitcnt_t} mpf_get_default_prec (void)
+Return the default precision actually used.
+@end deftypefun
+
+An @code{mpf_t} object must be initialized before storing the first value in
+it.  The functions @code{mpf_init} and @code{mpf_init2} are used for that
+purpose.
+
+@deftypefun void mpf_init (mpf_t @var{x})
+Initialize @var{x} to 0.  Normally, a variable should be initialized once only
+or at least be cleared, using @code{mpf_clear}, between initializations.  The
+precision of @var{x} is undefined unless a default precision has already been
+established by a call to @code{mpf_set_default_prec}.
+@end deftypefun
+
+@deftypefun void mpf_init2 (mpf_t @var{x}, mp_bitcnt_t @var{prec})
+Initialize @var{x} to 0 and set its precision to be @strong{at least}
+@var{prec} bits.  Normally, a variable should be initialized once only or at
+least be cleared, using @code{mpf_clear}, between initializations.
+@end deftypefun
+
+@deftypefun void mpf_inits (mpf_t @var{x}, ...)
+Initialize a NULL-terminated list of @code{mpf_t} variables, and set their
+values to 0.  The precision of the initialized variables is undefined unless a
+default precision has already been established by a call to
+@code{mpf_set_default_prec}.
+@end deftypefun
+
+@deftypefun void mpf_clear (mpf_t @var{x})
+Free the space occupied by @var{x}.  Make sure to call this function for all
+@code{mpf_t} variables when you are done with them.
+@end deftypefun
+
+@deftypefun void mpf_clears (mpf_t @var{x}, ...)
+Free the space occupied by a NULL-terminated list of @code{mpf_t} variables.
+@end deftypefun
+
+@need 2000
+Here is an example on how to initialize floating-point variables:
+@example
+@{
+  mpf_t x, y;
+  mpf_init (x);           /* use default precision */
+  mpf_init2 (y, 256);     /* precision @emph{at least} 256 bits */
+  @dots{}
+  /* Unless the program is about to exit, do ... */
+  mpf_clear (x);
+  mpf_clear (y);
+@}
+@end example
+
+The following three functions are useful for changing the precision during a
+calculation.  A typical use would be for adjusting the precision gradually in
+iterative algorithms like Newton-Raphson, making the computation precision
+closely match the actual accurate part of the numbers.
+
+@deftypefun {mp_bitcnt_t} mpf_get_prec (const mpf_t @var{op})
+Return the current precision of @var{op}, in bits.
+@end deftypefun
+
+@deftypefun void mpf_set_prec (mpf_t @var{rop}, mp_bitcnt_t @var{prec})
+Set the precision of @var{rop} to be @strong{at least} @var{prec} bits.  The
+value in @var{rop} will be truncated to the new precision.
+
+This function requires a call to @code{realloc}, and so should not be used in
+a tight loop.
+@end deftypefun
+
+@deftypefun void mpf_set_prec_raw (mpf_t @var{rop}, mp_bitcnt_t @var{prec})
+Set the precision of @var{rop} to be @strong{at least} @var{prec} bits,
+without changing the memory allocated.
+
+@var{prec} must be no more than the allocated precision for @var{rop}, that
+being the precision when @var{rop} was initialized, or in the most recent
+@code{mpf_set_prec}.
+
+The value in @var{rop} is unchanged, and in particular if it had a higher
+precision than @var{prec} it will retain that higher precision.  New values
+written to @var{rop} will use the new @var{prec}.
+
+Before calling @code{mpf_clear} or the full @code{mpf_set_prec}, another
+@code{mpf_set_prec_raw} call must be made to restore @var{rop} to its original
+allocated precision.  Failing to do so will have unpredictable results.
+
+@code{mpf_get_prec} can be used before @code{mpf_set_prec_raw} to get the
+original allocated precision.  After @code{mpf_set_prec_raw} it reflects the
+@var{prec} value set.
+
+@code{mpf_set_prec_raw} is an efficient way to use an @code{mpf_t} variable at
+different precisions during a calculation, perhaps to gradually increase
+precision in an iteration, or just to use various different precisions for
+different purposes during a calculation.
+@end deftypefun
+
+
+@need 2000
+@node Assigning Floats, Simultaneous Float Init & Assign, Initializing Floats, Floating-point Functions
+@comment  node-name,  next,  previous,  up
+@section Assignment Functions
+@cindex Float assignment functions
+@cindex Assignment functions
+
+These functions assign new values to already initialized floats
+(@pxref{Initializing Floats}).
+
+@deftypefun void mpf_set (mpf_t @var{rop}, const mpf_t @var{op})
+@deftypefunx void mpf_set_ui (mpf_t @var{rop}, unsigned long int @var{op})
+@deftypefunx void mpf_set_si (mpf_t @var{rop}, signed long int @var{op})
+@deftypefunx void mpf_set_d (mpf_t @var{rop}, double @var{op})
+@deftypefunx void mpf_set_z (mpf_t @var{rop}, const mpz_t @var{op})
+@deftypefunx void mpf_set_q (mpf_t @var{rop}, const mpq_t @var{op})
+Set the value of @var{rop} from @var{op}.
+@end deftypefun
+
+@deftypefun int mpf_set_str (mpf_t @var{rop}, const char *@var{str}, int @var{base})
+Set the value of @var{rop} from the string in @var{str}.  The string is of the
+form @samp{M@@N} or, if the base is 10 or less, alternatively @samp{MeN}.
+@samp{M} is the mantissa and @samp{N} is the exponent.  The mantissa is always
+in the specified base.  The exponent is either in the specified base or, if
+@var{base} is negative, in decimal.  The decimal point expected is taken from
+the current locale, on systems providing @code{localeconv}.
+
+The argument @var{base} may be in the ranges 2 to 62, or @minus{}62 to
+@minus{}2.  Negative values are used to specify that the exponent is in
+decimal.
+
+For bases up to 36, case is ignored; upper-case and lower-case letters have
+the same value; for bases 37 to 62, upper-case letter represent the usual
+10..35 while lower-case letter represent 36..61.
+
+Unlike the corresponding @code{mpz} function, the base will not be determined
+from the leading characters of the string if @var{base} is 0.  This is so that
+numbers like @samp{0.23} are not interpreted as octal.
+
+White space is allowed in the string, and is simply ignored.  [This is not
+really true; white-space is ignored in the beginning of the string and within
+the mantissa, but not in other places, such as after a minus sign or in the
+exponent.  We are considering changing the definition of this function, making
+it fail when there is any white-space in the input, since that makes a lot of
+sense.  Please tell us your opinion about this change.  Do you really want it
+to accept @nicode{"3 14"} as meaning 314 as it does now?]
+
+This function returns 0 if the entire string is a valid number in base
+@var{base}.  Otherwise it returns @minus{}1.
+@end deftypefun
+
+@deftypefun void mpf_swap (mpf_t @var{rop1}, mpf_t @var{rop2})
+Swap @var{rop1} and @var{rop2} efficiently.  Both the values and the
+precisions of the two variables are swapped.
+@end deftypefun
+
+
+@node Simultaneous Float Init & Assign, Converting Floats, Assigning Floats, Floating-point Functions
+@comment  node-name,  next,  previous,  up
+@section Combined Initialization and Assignment Functions
+@cindex Float assignment functions
+@cindex Assignment functions
+@cindex Float initialization functions
+@cindex Initialization functions
+
+For convenience, GMP provides a parallel series of initialize-and-set functions
+which initialize the output and then store the value there.  These functions'
+names have the form @code{mpf_init_set@dots{}}
+
+Once the float has been initialized by any of the @code{mpf_init_set@dots{}}
+functions, it can be used as the source or destination operand for the ordinary
+float functions.  Don't use an initialize-and-set function on a variable
+already initialized!
+
+@deftypefun void mpf_init_set (mpf_t @var{rop}, const mpf_t @var{op})
+@deftypefunx void mpf_init_set_ui (mpf_t @var{rop}, unsigned long int @var{op})
+@deftypefunx void mpf_init_set_si (mpf_t @var{rop}, signed long int @var{op})
+@deftypefunx void mpf_init_set_d (mpf_t @var{rop}, double @var{op})
+Initialize @var{rop} and set its value from @var{op}.
+
+The precision of @var{rop} will be taken from the active default precision, as
+set by @code{mpf_set_default_prec}.
+@end deftypefun
+
+@deftypefun int mpf_init_set_str (mpf_t @var{rop}, const char *@var{str}, int @var{base})
+Initialize @var{rop} and set its value from the string in @var{str}.  See
+@code{mpf_set_str} above for details on the assignment operation.
+
+Note that @var{rop} is initialized even if an error occurs.  (I.e., you have to
+call @code{mpf_clear} for it.)
+
+The precision of @var{rop} will be taken from the active default precision, as
+set by @code{mpf_set_default_prec}.
+@end deftypefun
+
+
+@node Converting Floats, Float Arithmetic, Simultaneous Float Init & Assign, Floating-point Functions
+@comment  node-name,  next,  previous,  up
+@section Conversion Functions
+@cindex Float conversion functions
+@cindex Conversion functions
+
+@deftypefun double mpf_get_d (const mpf_t @var{op})
+Convert @var{op} to a @code{double}, truncating if necessary (i.e.@: rounding
+towards zero).
+
+If the exponent in @var{op} is too big or too small to fit a @code{double}
+then the result is system dependent.  For too big an infinity is returned when
+available.  For too small @math{0.0} is normally returned.  Hardware overflow,
+underflow and denorm traps may or may not occur.
+@end deftypefun
+
+@deftypefun double mpf_get_d_2exp (signed long int *@var{exp}, const mpf_t @var{op})
+Convert @var{op} to a @code{double}, truncating if necessary (i.e.@: rounding
+towards zero), and with an exponent returned separately.
+
+The return value is in the range @math{0.5@le{}@GMPabs{@var{d}}<1} and the
+exponent is stored to @code{*@var{exp}}.  @m{@var{d} \times 2^{exp},
+@var{d} * 2^@var{exp}} is the (truncated) @var{op} value.  If @var{op} is zero,
+the return is @math{0.0} and 0 is stored to @code{*@var{exp}}.
+
+@cindex @code{frexp}
+This is similar to the standard C @code{frexp} function (@pxref{Normalization
+Functions,,, libc, The GNU C Library Reference Manual}).
+@end deftypefun
+
+@deftypefun long mpf_get_si (const mpf_t @var{op})
+@deftypefunx {unsigned long} mpf_get_ui (const mpf_t @var{op})
+Convert @var{op} to a @code{long} or @code{unsigned long}, truncating any
+fraction part.  If @var{op} is too big for the return type, the result is
+undefined.
+
+See also @code{mpf_fits_slong_p} and @code{mpf_fits_ulong_p}
+(@pxref{Miscellaneous Float Functions}).
+@end deftypefun
+
+@deftypefun {char *} mpf_get_str (char *@var{str}, mp_exp_t *@var{expptr}, int @var{base}, size_t @var{n_digits}, const mpf_t @var{op})
+Convert @var{op} to a string of digits in base @var{base}.  The base argument
+may vary from 2 to 62 or from @minus{}2 to @minus{}36.  Up to @var{n_digits}
+digits will be generated.  Trailing zeros are not returned.  No more digits
+than can be accurately represented by @var{op} are ever generated.  If
+@var{n_digits} is 0 then that accurate maximum number of digits are generated.
+
+For @var{base} in the range 2..36, digits and lower-case letters are used; for
+@minus{}2..@minus{}36, digits and upper-case letters are used; for 37..62,
+digits, upper-case letters, and lower-case letters (in that significance order)
+are used.
+
+If @var{str} is @code{NULL}, the result string is allocated using the current
+allocation function (@pxref{Custom Allocation}).  The block will be
+@code{strlen(str)+1} bytes, that being exactly enough for the string and
+null-terminator.
+
+If @var{str} is not @code{NULL}, it should point to a block of
+@math{@var{n_digits} + 2} bytes, that being enough for the mantissa, a
+possible minus sign, and a null-terminator.  When @var{n_digits} is 0 to get
+all significant digits, an application won't be able to know the space
+required, and @var{str} should be @code{NULL} in that case.
+
+The generated string is a fraction, with an implicit radix point immediately
+to the left of the first digit.  The applicable exponent is written through
+the @var{expptr} pointer.  For example, the number 3.1416 would be returned as
+string @nicode{"31416"} and exponent 1.
+
+When @var{op} is zero, an empty string is produced and the exponent returned
+is 0.
+
+A pointer to the result string is returned, being either the allocated block
+or the given @var{str}.
+@end deftypefun
+
+
+@node Float Arithmetic, Float Comparison, Converting Floats, Floating-point Functions
+@comment  node-name,  next,  previous,  up
+@section Arithmetic Functions
+@cindex Float arithmetic functions
+@cindex Arithmetic functions
+
+@deftypefun void mpf_add (mpf_t @var{rop}, const mpf_t @var{op1}, const mpf_t @var{op2})
+@deftypefunx void mpf_add_ui (mpf_t @var{rop}, const mpf_t @var{op1}, unsigned long int @var{op2})
+Set @var{rop} to @math{@var{op1} + @var{op2}}.
+@end deftypefun
+
+@deftypefun void mpf_sub (mpf_t @var{rop}, const mpf_t @var{op1}, const mpf_t @var{op2})
+@deftypefunx void mpf_ui_sub (mpf_t @var{rop}, unsigned long int @var{op1}, const mpf_t @var{op2})
+@deftypefunx void mpf_sub_ui (mpf_t @var{rop}, const mpf_t @var{op1}, unsigned long int @var{op2})
+Set @var{rop} to @var{op1} @minus{} @var{op2}.
+@end deftypefun
+
+@deftypefun void mpf_mul (mpf_t @var{rop}, const mpf_t @var{op1}, const mpf_t @var{op2})
+@deftypefunx void mpf_mul_ui (mpf_t @var{rop}, const mpf_t @var{op1}, unsigned long int @var{op2})
+Set @var{rop} to @math{@var{op1} @GMPtimes{} @var{op2}}.
+@end deftypefun
+
+Division is undefined if the divisor is zero, and passing a zero divisor to the
+divide functions will make these functions intentionally divide by zero.  This
+lets the user handle arithmetic exceptions in these functions in the same
+manner as other arithmetic exceptions.
+
+@deftypefun void mpf_div (mpf_t @var{rop}, const mpf_t @var{op1}, const mpf_t @var{op2})
+@deftypefunx void mpf_ui_div (mpf_t @var{rop}, unsigned long int @var{op1}, const mpf_t @var{op2})
+@deftypefunx void mpf_div_ui (mpf_t @var{rop}, const mpf_t @var{op1}, unsigned long int @var{op2})
+@cindex Division functions
+Set @var{rop} to @var{op1}/@var{op2}.
+@end deftypefun
+
+@deftypefun void mpf_sqrt (mpf_t @var{rop}, const mpf_t @var{op})
+@deftypefunx void mpf_sqrt_ui (mpf_t @var{rop}, unsigned long int @var{op})
+@cindex Root extraction functions
+Set @var{rop} to @m{\sqrt{@var{op}}, the square root of @var{op}}.
+@end deftypefun
+
+@deftypefun void mpf_pow_ui (mpf_t @var{rop}, const mpf_t @var{op1}, unsigned long int @var{op2})
+@cindex Exponentiation functions
+@cindex Powering functions
+Set @var{rop} to @m{@var{op1}^{op2}, @var{op1} raised to the power @var{op2}}.
+@end deftypefun
+
+@deftypefun void mpf_neg (mpf_t @var{rop}, const mpf_t @var{op})
+Set @var{rop} to @minus{}@var{op}.
+@end deftypefun
+
+@deftypefun void mpf_abs (mpf_t @var{rop}, const mpf_t @var{op})
+Set @var{rop} to the absolute value of @var{op}.
+@end deftypefun
+
+@deftypefun void mpf_mul_2exp (mpf_t @var{rop}, const mpf_t @var{op1}, mp_bitcnt_t @var{op2})
+Set @var{rop} to @m{@var{op1} \times 2^{op2}, @var{op1} times 2 raised to
+@var{op2}}.
+@end deftypefun
+
+@deftypefun void mpf_div_2exp (mpf_t @var{rop}, const mpf_t @var{op1}, mp_bitcnt_t @var{op2})
+Set @var{rop} to @m{@var{op1}/2^{op2}, @var{op1} divided by 2 raised to
+@var{op2}}.
+@end deftypefun
+
+@node Float Comparison, I/O of Floats, Float Arithmetic, Floating-point Functions
+@comment  node-name,  next,  previous,  up
+@section Comparison Functions
+@cindex Float comparison functions
+@cindex Comparison functions
+
+@deftypefun int mpf_cmp (const mpf_t @var{op1}, const mpf_t @var{op2})
+@deftypefunx int mpf_cmp_z (const mpf_t @var{op1}, const mpz_t @var{op2})
+@deftypefunx int mpf_cmp_d (const mpf_t @var{op1}, double @var{op2})
+@deftypefunx int mpf_cmp_ui (const mpf_t @var{op1}, unsigned long int @var{op2})
+@deftypefunx int mpf_cmp_si (const mpf_t @var{op1}, signed long int @var{op2})
+Compare @var{op1} and @var{op2}.  Return a positive value if @math{@var{op1} >
+@var{op2}}, zero if @math{@var{op1} = @var{op2}}, and a negative value if
+@math{@var{op1} < @var{op2}}.
+
+@code{mpf_cmp_d} can be called with an infinity, but results are undefined for
+a NaN.
+@end deftypefun
+
+@deftypefun int mpf_eq (const mpf_t @var{op1}, const mpf_t @var{op2}, mp_bitcnt_t op3)
+@strong{This function is mathematically ill-defined and should not be used.}
+
+Return non-zero if the first @var{op3} bits of @var{op1} and @var{op2} are
+equal, zero otherwise.  Note that numbers like e.g., 256 (binary 100000000) and
+255 (binary 11111111) will never be equal by this function's measure, and
+furthermore that 0 will only be equal to itself.
+@end deftypefun
+
+@deftypefun void mpf_reldiff (mpf_t @var{rop}, const mpf_t @var{op1}, const mpf_t @var{op2})
+Compute the relative difference between @var{op1} and @var{op2} and store the
+result in @var{rop}.  This is @math{@GMPabs{@var{op1}-@var{op2}}/@var{op1}}.
+@end deftypefun
+
+@deftypefn Macro int mpf_sgn (const mpf_t @var{op})
+@cindex Sign tests
+@cindex Float sign tests
+Return @math{+1} if @math{@var{op} > 0}, 0 if @math{@var{op} = 0}, and
+@math{-1} if @math{@var{op} < 0}.
+
+This function is actually implemented as a macro.  It evaluates its argument
+multiple times.
+@end deftypefn
+
+@node I/O of Floats, Miscellaneous Float Functions, Float Comparison, Floating-point Functions
+@comment  node-name,  next,  previous,  up
+@section Input and Output Functions
+@cindex Float input and output functions
+@cindex Input functions
+@cindex Output functions
+@cindex I/O functions
+
+Functions that perform input from a stdio stream, and functions that output to
+a stdio stream, of @code{mpf} numbers.  Passing a @code{NULL} pointer for a
+@var{stream} argument to any of these functions will make them read from
+@code{stdin} and write to @code{stdout}, respectively.
+
+When using any of these functions, it is a good idea to include @file{stdio.h}
+before @file{gmp.h}, since that will allow @file{gmp.h} to define prototypes
+for these functions.
+
+See also @ref{Formatted Output} and @ref{Formatted Input}.
+
+@deftypefun size_t mpf_out_str (FILE *@var{stream}, int @var{base}, size_t @var{n_digits}, const mpf_t @var{op})
+Print @var{op} to @var{stream}, as a string of digits.  Return the number of
+bytes written, or if an error occurred, return 0.
+
+The mantissa is prefixed with an @samp{0.} and is in the given @var{base},
+which may vary from 2 to 62 or from @minus{}2 to @minus{}36.  An exponent is
+then printed, separated by an @samp{e}, or if the base is greater than 10 then
+by an @samp{@@}.  The exponent is always in decimal.  The decimal point follows
+the current locale, on systems providing @code{localeconv}.
+
+For @var{base} in the range 2..36, digits and lower-case letters are used; for
+@minus{}2..@minus{}36, digits and upper-case letters are used; for 37..62,
+digits, upper-case letters, and lower-case letters (in that significance order)
+are used.
+
+Up to @var{n_digits} will be printed from the mantissa, except that no more
+digits than are accurately representable by @var{op} will be printed.
+@var{n_digits} can be 0 to select that accurate maximum.
+@end deftypefun
+
+@deftypefun size_t mpf_inp_str (mpf_t @var{rop}, FILE *@var{stream}, int @var{base})
+Read a string in base @var{base} from @var{stream}, and put the read float in
+@var{rop}.  The string is of the form @samp{M@@N} or, if the base is 10 or
+less, alternatively @samp{MeN}.  @samp{M} is the mantissa and @samp{N} is the
+exponent.  The mantissa is always in the specified base.  The exponent is
+either in the specified base or, if @var{base} is negative, in decimal.  The
+decimal point expected is taken from the current locale, on systems providing
+@code{localeconv}.
+
+The argument @var{base} may be in the ranges 2 to 36, or @minus{}36 to
+@minus{}2.  Negative values are used to specify that the exponent is in
+decimal.
+
+Unlike the corresponding @code{mpz} function, the base will not be determined
+from the leading characters of the string if @var{base} is 0.  This is so that
+numbers like @samp{0.23} are not interpreted as octal.
+
+Return the number of bytes read, or if an error occurred, return 0.
+@end deftypefun
+
+@c @deftypefun void mpf_out_raw (FILE *@var{stream}, const mpf_t @var{float})
+@c Output @var{float} on stdio stream @var{stream}, in raw binary
+@c format.  The float is written in a portable format, with 4 bytes of
+@c size information, and that many bytes of limbs.  Both the size and the
+@c limbs are written in decreasing significance order.
+@c @end deftypefun
+
+@c @deftypefun void mpf_inp_raw (mpf_t @var{float}, FILE *@var{stream})
+@c Input from stdio stream @var{stream} in the format written by
+@c @code{mpf_out_raw}, and put the result in @var{float}.
+@c @end deftypefun
+
+
+@node Miscellaneous Float Functions,  , I/O of Floats, Floating-point Functions
+@comment  node-name,  next,  previous,  up
+@section Miscellaneous Functions
+@cindex Miscellaneous float functions
+@cindex Float miscellaneous functions
+
+@deftypefun void mpf_ceil (mpf_t @var{rop}, const mpf_t @var{op})
+@deftypefunx void mpf_floor (mpf_t @var{rop}, const mpf_t @var{op})
+@deftypefunx void mpf_trunc (mpf_t @var{rop}, const mpf_t @var{op})
+@cindex Rounding functions
+@cindex Float rounding functions
+Set @var{rop} to @var{op} rounded to an integer.  @code{mpf_ceil} rounds to the
+next higher integer, @code{mpf_floor} to the next lower, and @code{mpf_trunc}
+to the integer towards zero.
+@end deftypefun
+
+@deftypefun int mpf_integer_p (const mpf_t @var{op})
+Return non-zero if @var{op} is an integer.
+@end deftypefun
+
+@deftypefun int mpf_fits_ulong_p (const mpf_t @var{op})
+@deftypefunx int mpf_fits_slong_p (const mpf_t @var{op})
+@deftypefunx int mpf_fits_uint_p (const mpf_t @var{op})
+@deftypefunx int mpf_fits_sint_p (const mpf_t @var{op})
+@deftypefunx int mpf_fits_ushort_p (const mpf_t @var{op})
+@deftypefunx int mpf_fits_sshort_p (const mpf_t @var{op})
+Return non-zero if @var{op} would fit in the respective C data type, when
+truncated to an integer.
+@end deftypefun
+
+@deftypefun void mpf_urandomb (mpf_t @var{rop}, gmp_randstate_t @var{state}, mp_bitcnt_t @var{nbits})
+@cindex Random number functions
+@cindex Float random number functions
+Generate a uniformly distributed random float in @var{rop}, such that @math{0
+@le{} @var{rop} < 1}, with @var{nbits} significant bits in the mantissa or
+less if the precision of @var{rop} is smaller.
+
+The variable @var{state} must be initialized by calling one of the
+@code{gmp_randinit} functions (@ref{Random State Initialization}) before
+invoking this function.
+@end deftypefun
+
+@deftypefun void mpf_random2 (mpf_t @var{rop}, mp_size_t @var{max_size}, mp_exp_t @var{exp})
+Generate a random float of at most @var{max_size} limbs, with long strings of
+zeros and ones in the binary representation.  The exponent of the number is in
+the interval @minus{}@var{exp} to @var{exp} (in limbs).  This function is
+useful for testing functions and algorithms, since these kind of random
+numbers have proven to be more likely to trigger corner-case bugs.  Negative
+random numbers are generated when @var{max_size} is negative.
+@end deftypefun
+
+@c @deftypefun size_t mpf_size (const mpf_t @var{op})
+@c Return the size of @var{op} measured in number of limbs.  If @var{op} is
+@c zero, the returned value will be zero.  (@xref{Nomenclature}, for an
+@c explanation of the concept @dfn{limb}.)
+@c
+@c @strong{This function is obsolete.  It will disappear from future GMP
+@c releases.}
+@c @end deftypefun
+
+
+@node Low-level Functions, Random Number Functions, Floating-point Functions, Top
+@comment  node-name,  next,  previous,  up
+@chapter Low-level Functions
+@cindex Low-level functions
+
+This chapter describes low-level GMP functions, used to implement the
+high-level GMP functions, but also intended for time-critical user code.
+
+These functions start with the prefix @code{mpn_}.
+
+@c 1. Some of these function clobber input operands.
+@c
+
+The @code{mpn} functions are designed to be as fast as possible, @strong{not}
+to provide a coherent calling interface.  The different functions have somewhat
+similar interfaces, but there are variations that make them hard to use.  These
+functions do as little as possible apart from the real multiple precision
+computation, so that no time is spent on things that not all callers need.
+
+A source operand is specified by a pointer to the least significant limb and a
+limb count.  A destination operand is specified by just a pointer.  It is the
+responsibility of the caller to ensure that the destination has enough space
+for storing the result.
+
+With this way of specifying operands, it is possible to perform computations on
+subranges of an argument, and store the result into a subrange of a
+destination.
+
+A common requirement for all functions is that each source area needs at least
+one limb.  No size argument may be zero.  Unless otherwise stated, in-place
+operations are allowed where source and destination are the same, but not where
+they only partly overlap.
+
+The @code{mpn} functions are the base for the implementation of the
+@code{mpz_}, @code{mpf_}, and @code{mpq_} functions.
+
+This example adds the number beginning at @var{s1p} and the number beginning at
+@var{s2p} and writes the sum at @var{destp}.  All areas have @var{n} limbs.
+
+@example
+cy = mpn_add_n (destp, s1p, s2p, n)
+@end example
+
+It should be noted that the @code{mpn} functions make no attempt to identify
+high or low zero limbs on their operands, or other special forms.  On random
+data such cases will be unlikely and it'd be wasteful for every function to
+check every time.  An application knowing something about its data can take
+steps to trim or perhaps split its calculations.
+@c
+@c  For reference, within gmp mpz_t operands never have high zero limbs, and
+@c  we rate low zero limbs as unlikely too (or something an application should
+@c  handle).  This is a prime motivation for not stripping zero limbs in say
+@c  mpn_mul_n etc.
+@c
+@c  Other applications doing variable-length calculations will quite likely do
+@c  something similar to mpz.  And even if not then it's highly likely zero
+@c  limb stripping can be done at just a few judicious points, which will be
+@c  more efficient than having lots of mpn functions checking every time.
+
+@sp 1
+@noindent
+In the notation used below, a source operand is identified by the pointer to
+the least significant limb, and the limb count in braces.  For example,
+@{@var{s1p}, @var{s1n}@}.
+
+@deftypefun mp_limb_t mpn_add_n (mp_limb_t *@var{rp}, const mp_limb_t *@var{s1p}, const mp_limb_t *@var{s2p}, mp_size_t @var{n})
+Add @{@var{s1p}, @var{n}@} and @{@var{s2p}, @var{n}@}, and write the @var{n}
+least significant limbs of the result to @var{rp}.  Return carry, either 0 or
+1.
+
+This is the lowest-level function for addition.  It is the preferred function
+for addition, since it is written in assembly for most CPUs.  For addition of
+a variable to itself (i.e., @var{s1p} equals @var{s2p}) use @code{mpn_lshift}
+with a count of 1 for optimal speed.
+@end deftypefun
+
+@deftypefun mp_limb_t mpn_add_1 (mp_limb_t *@var{rp}, const mp_limb_t *@var{s1p}, mp_size_t @var{n}, mp_limb_t @var{s2limb})
+Add @{@var{s1p}, @var{n}@} and @var{s2limb}, and write the @var{n} least
+significant limbs of the result to @var{rp}.  Return carry, either 0 or 1.
+@end deftypefun
+
+@deftypefun mp_limb_t mpn_add (mp_limb_t *@var{rp}, const mp_limb_t *@var{s1p}, mp_size_t @var{s1n}, const mp_limb_t *@var{s2p}, mp_size_t @var{s2n})
+Add @{@var{s1p}, @var{s1n}@} and @{@var{s2p}, @var{s2n}@}, and write the
+@var{s1n} least significant limbs of the result to @var{rp}.  Return carry,
+either 0 or 1.
+
+This function requires that @var{s1n} is greater than or equal to @var{s2n}.
+@end deftypefun
+
+@deftypefun mp_limb_t mpn_sub_n (mp_limb_t *@var{rp}, const mp_limb_t *@var{s1p}, const mp_limb_t *@var{s2p}, mp_size_t @var{n})
+Subtract @{@var{s2p}, @var{n}@} from @{@var{s1p}, @var{n}@}, and write the
+@var{n} least significant limbs of the result to @var{rp}.  Return borrow,
+either 0 or 1.
+
+This is the lowest-level function for subtraction.  It is the preferred
+function for subtraction, since it is written in assembly for most CPUs.
+@end deftypefun
+
+@deftypefun mp_limb_t mpn_sub_1 (mp_limb_t *@var{rp}, const mp_limb_t *@var{s1p}, mp_size_t @var{n}, mp_limb_t @var{s2limb})
+Subtract @var{s2limb} from @{@var{s1p}, @var{n}@}, and write the @var{n} least
+significant limbs of the result to @var{rp}.  Return borrow, either 0 or 1.
+@end deftypefun
+
+@deftypefun mp_limb_t mpn_sub (mp_limb_t *@var{rp}, const mp_limb_t *@var{s1p}, mp_size_t @var{s1n}, const mp_limb_t *@var{s2p}, mp_size_t @var{s2n})
+Subtract @{@var{s2p}, @var{s2n}@} from @{@var{s1p}, @var{s1n}@}, and write the
+@var{s1n} least significant limbs of the result to @var{rp}.  Return borrow,
+either 0 or 1.
+
+This function requires that @var{s1n} is greater than or equal to
+@var{s2n}.
+@end deftypefun
+
+@deftypefun mp_limb_t mpn_neg (mp_limb_t *@var{rp}, const mp_limb_t *@var{sp}, mp_size_t @var{n})
+Perform the negation of @{@var{sp}, @var{n}@}, and write the result to
+@{@var{rp}, @var{n}@}.  This is equivalent to calling @code{mpn_sub_n} with a
+@var{n}-limb zero minuend and passing @{@var{sp}, @var{n}@} as subtrahend.
+Return borrow, either 0 or 1.
+@end deftypefun
+
+@deftypefun void mpn_mul_n (mp_limb_t *@var{rp}, const mp_limb_t *@var{s1p}, const mp_limb_t *@var{s2p}, mp_size_t @var{n})
+Multiply @{@var{s1p}, @var{n}@} and @{@var{s2p}, @var{n}@}, and write the
+2*@var{n}-limb result to @var{rp}.
+
+The destination has to have space for 2*@var{n} limbs, even if the product's
+most significant limb is zero.  No overlap is permitted between the
+destination and either source.
+
+If the two input operands are the same, use @code{mpn_sqr}.
+@end deftypefun
+
+@deftypefun mp_limb_t mpn_mul (mp_limb_t *@var{rp}, const mp_limb_t *@var{s1p}, mp_size_t @var{s1n}, const mp_limb_t *@var{s2p}, mp_size_t @var{s2n})
+Multiply @{@var{s1p}, @var{s1n}@} and @{@var{s2p}, @var{s2n}@}, and write the
+(@var{s1n}+@var{s2n})-limb result to @var{rp}.  Return the most significant
+limb of the result.
+
+The destination has to have space for @var{s1n} + @var{s2n} limbs, even if the
+product's most significant limb is zero.  No overlap is permitted between the
+destination and either source.
+
+This function requires that @var{s1n} is greater than or equal to @var{s2n}.
+@end deftypefun
+
+@deftypefun void mpn_sqr (mp_limb_t *@var{rp}, const mp_limb_t *@var{s1p}, mp_size_t @var{n})
+Compute the square of @{@var{s1p}, @var{n}@} and write the 2*@var{n}-limb
+result to @var{rp}.
+
+The destination has to have space for 2@var{n} limbs, even if the result's
+most significant limb is zero.  No overlap is permitted between the
+destination and the source.
+@end deftypefun
+
+@deftypefun mp_limb_t mpn_mul_1 (mp_limb_t *@var{rp}, const mp_limb_t *@var{s1p}, mp_size_t @var{n}, mp_limb_t @var{s2limb})
+Multiply @{@var{s1p}, @var{n}@} by @var{s2limb}, and write the @var{n} least
+significant limbs of the product to @var{rp}.  Return the most significant
+limb of the product.  @{@var{s1p}, @var{n}@} and @{@var{rp}, @var{n}@} are
+allowed to overlap provided @math{@var{rp} @le{} @var{s1p}}.
+
+This is a low-level function that is a building block for general
+multiplication as well as other operations in GMP@.  It is written in assembly
+for most CPUs.
+
+Don't call this function if @var{s2limb} is a power of 2; use @code{mpn_lshift}
+with a count equal to the logarithm of @var{s2limb} instead, for optimal speed.
+@end deftypefun
+
+@deftypefun mp_limb_t mpn_addmul_1 (mp_limb_t *@var{rp}, const mp_limb_t *@var{s1p}, mp_size_t @var{n}, mp_limb_t @var{s2limb})
+Multiply @{@var{s1p}, @var{n}@} and @var{s2limb}, and add the @var{n} least
+significant limbs of the product to @{@var{rp}, @var{n}@} and write the result
+to @var{rp}.  Return the most significant limb of the product, plus carry-out
+from the addition.  @{@var{s1p}, @var{n}@} and @{@var{rp}, @var{n}@} are
+allowed to overlap provided @math{@var{rp} @le{} @var{s1p}}.
+
+This is a low-level function that is a building block for general
+multiplication as well as other operations in GMP@.  It is written in assembly
+for most CPUs.
+@end deftypefun
+
+@deftypefun mp_limb_t mpn_submul_1 (mp_limb_t *@var{rp}, const mp_limb_t *@var{s1p}, mp_size_t @var{n}, mp_limb_t @var{s2limb})
+Multiply @{@var{s1p}, @var{n}@} and @var{s2limb}, and subtract the @var{n}
+least significant limbs of the product from @{@var{rp}, @var{n}@} and write the
+result to @var{rp}.  Return the most significant limb of the product, plus
+borrow-out from the subtraction.  @{@var{s1p}, @var{n}@} and @{@var{rp},
+@var{n}@} are allowed to overlap provided @math{@var{rp} @le{} @var{s1p}}.
+
+This is a low-level function that is a building block for general
+multiplication and division as well as other operations in GMP@.  It is written
+in assembly for most CPUs.
+@end deftypefun
+
+@deftypefun void mpn_tdiv_qr (mp_limb_t *@var{qp}, mp_limb_t *@var{rp}, mp_size_t @var{qxn}, const mp_limb_t *@var{np}, mp_size_t @var{nn}, const mp_limb_t *@var{dp}, mp_size_t @var{dn})
+Divide @{@var{np}, @var{nn}@} by @{@var{dp}, @var{dn}@} and put the quotient
+at @{@var{qp}, @var{nn}@minus{}@var{dn}+1@} and the remainder at @{@var{rp},
+@var{dn}@}.  The quotient is rounded towards 0.
+
+No overlap is permitted between arguments, except that @var{np} might equal
+@var{rp}.  The dividend size @var{nn} must be greater than or equal to divisor
+size @var{dn}.  The most significant limb of the divisor must be non-zero.  The
+@var{qxn} operand must be zero.
+@end deftypefun
+
+@deftypefun mp_limb_t mpn_divrem (mp_limb_t *@var{r1p}, mp_size_t @var{qxn}, mp_limb_t *@var{rs2p}, mp_size_t @var{rs2n}, const mp_limb_t *@var{s3p}, mp_size_t @var{s3n})
+[This function is obsolete.  Please call @code{mpn_tdiv_qr} instead for best
+performance.]
+
+Divide @{@var{rs2p}, @var{rs2n}@} by @{@var{s3p}, @var{s3n}@}, and write the
+quotient at @var{r1p}, with the exception of the most significant limb, which
+is returned.  The remainder replaces the dividend at @var{rs2p}; it will be
+@var{s3n} limbs long (i.e., as many limbs as the divisor).
+
+In addition to an integer quotient, @var{qxn} fraction limbs are developed, and
+stored after the integral limbs.  For most usages, @var{qxn} will be zero.
+
+It is required that @var{rs2n} is greater than or equal to @var{s3n}.  It is
+required that the most significant bit of the divisor is set.
+
+If the quotient is not needed, pass @var{rs2p} + @var{s3n} as @var{r1p}.  Aside
+from that special case, no overlap between arguments is permitted.
+
+Return the most significant limb of the quotient, either 0 or 1.
+
+The area at @var{r1p} needs to be @var{rs2n} @minus{} @var{s3n} + @var{qxn}
+limbs large.
+@end deftypefun
+
+@deftypefn Function mp_limb_t mpn_divrem_1 (mp_limb_t *@var{r1p}, mp_size_t @var{qxn}, @w{mp_limb_t *@var{s2p}}, mp_size_t @var{s2n}, mp_limb_t @var{s3limb})
+@deftypefnx Macro mp_limb_t mpn_divmod_1 (mp_limb_t *@var{r1p}, mp_limb_t *@var{s2p}, @w{mp_size_t @var{s2n}}, @w{mp_limb_t @var{s3limb}})
+Divide @{@var{s2p}, @var{s2n}@} by @var{s3limb}, and write the quotient at
+@var{r1p}.  Return the remainder.
+
+The integer quotient is written to @{@var{r1p}+@var{qxn}, @var{s2n}@} and in
+addition @var{qxn} fraction limbs are developed and written to @{@var{r1p},
+@var{qxn}@}.  Either or both @var{s2n} and @var{qxn} can be zero.  For most
+usages, @var{qxn} will be zero.
+
+@code{mpn_divmod_1} exists for upward source compatibility and is simply a
+macro calling @code{mpn_divrem_1} with a @var{qxn} of 0.
+
+The areas at @var{r1p} and @var{s2p} have to be identical or completely
+separate, not partially overlapping.
+@end deftypefn
+
+@deftypefun mp_limb_t mpn_divmod (mp_limb_t *@var{r1p}, mp_limb_t *@var{rs2p}, mp_size_t @var{rs2n}, const mp_limb_t *@var{s3p}, mp_size_t @var{s3n})
+[This function is obsolete.  Please call @code{mpn_tdiv_qr} instead for best
+performance.]
+@end deftypefun
+
+@deftypefun void mpn_divexact_1 (mp_limb_t * @var{rp}, const mp_limb_t * @var{sp}, mp_size_t @var{n}, mp_limb_t @var{d})
+Divide @{@var{sp}, @var{n}@} by @var{d}, expecting it to divide exactly, and
+writing the result to @{@var{rp}, @var{n}@}. If @var{d} doesn't divide
+exactly, the value written to @{@var{rp}, @var{n}@} is undefined. The areas at
+@var{rp} and @var{sp} have to be identical or completely separate, not
+partially overlapping.
+@end deftypefun
+
+@deftypefn Macro mp_limb_t mpn_divexact_by3 (mp_limb_t *@var{rp}, mp_limb_t *@var{sp}, @w{mp_size_t @var{n}})
+@deftypefnx Function mp_limb_t mpn_divexact_by3c (mp_limb_t *@var{rp}, mp_limb_t *@var{sp}, @w{mp_size_t @var{n}}, mp_limb_t @var{carry})
+Divide @{@var{sp}, @var{n}@} by 3, expecting it to divide exactly, and writing
+the result to @{@var{rp}, @var{n}@}.  If 3 divides exactly, the return value is
+zero and the result is the quotient.  If not, the return value is non-zero and
+the result won't be anything useful.
+
+@code{mpn_divexact_by3c} takes an initial carry parameter, which can be the
+return value from a previous call, so a large calculation can be done piece by
+piece from low to high.  @code{mpn_divexact_by3} is simply a macro calling
+@code{mpn_divexact_by3c} with a 0 carry parameter.
+
+These routines use a multiply-by-inverse and will be faster than
+@code{mpn_divrem_1} on CPUs with fast multiplication but slow division.
+
+The source @math{a}, result @math{q}, size @math{n}, initial carry @math{i},
+and return value @math{c} satisfy @m{cb^n+a-i=3q, c*b^n + a-i = 3*q}, where
+@m{b=2\GMPraise{@code{GMP\_NUMB\_BITS}}, b=2^GMP_NUMB_BITS}.  The
+return @math{c} is always 0, 1 or 2, and the initial carry @math{i} must also
+be 0, 1 or 2 (these are both borrows really).  When @math{c=0} clearly
+@math{q=(a-i)/3}.  When @m{c \neq 0, c!=0}, the remainder @math{(a-i) @bmod{}
+3} is given by @math{3-c}, because @math{b @equiv{} 1 @bmod{} 3} (when
+@code{mp_bits_per_limb} is even, which is always so currently).
+@end deftypefn
+
+@deftypefun mp_limb_t mpn_mod_1 (const mp_limb_t *@var{s1p}, mp_size_t @var{s1n}, mp_limb_t @var{s2limb})
+Divide @{@var{s1p}, @var{s1n}@} by @var{s2limb}, and return the remainder.
+@var{s1n} can be zero.
+@end deftypefun
+
+@deftypefun mp_limb_t mpn_lshift (mp_limb_t *@var{rp}, const mp_limb_t *@var{sp}, mp_size_t @var{n}, unsigned int @var{count})
+Shift @{@var{sp}, @var{n}@} left by @var{count} bits, and write the result to
+@{@var{rp}, @var{n}@}.  The bits shifted out at the left are returned in the
+least significant @var{count} bits of the return value (the rest of the return
+value is zero).
+
+@var{count} must be in the range 1 to @nicode{mp_bits_per_limb}@minus{}1.  The
+regions @{@var{sp}, @var{n}@} and @{@var{rp}, @var{n}@} may overlap, provided
+@math{@var{rp} @ge{} @var{sp}}.
+
+This function is written in assembly for most CPUs.
+@end deftypefun
+
+@deftypefun mp_limb_t mpn_rshift (mp_limb_t *@var{rp}, const mp_limb_t *@var{sp}, mp_size_t @var{n}, unsigned int @var{count})
+Shift @{@var{sp}, @var{n}@} right by @var{count} bits, and write the result to
+@{@var{rp}, @var{n}@}.  The bits shifted out at the right are returned in the
+most significant @var{count} bits of the return value (the rest of the return
+value is zero).
+
+@var{count} must be in the range 1 to @nicode{mp_bits_per_limb}@minus{}1.  The
+regions @{@var{sp}, @var{n}@} and @{@var{rp}, @var{n}@} may overlap, provided
+@math{@var{rp} @le{} @var{sp}}.
+
+This function is written in assembly for most CPUs.
+@end deftypefun
+
+@deftypefun int mpn_cmp (const mp_limb_t *@var{s1p}, const mp_limb_t *@var{s2p}, mp_size_t @var{n})
+Compare @{@var{s1p}, @var{n}@} and @{@var{s2p}, @var{n}@} and return a
+positive value if @math{@var{s1} > @var{s2}}, 0 if they are equal, or a
+negative value if @math{@var{s1} < @var{s2}}.
+@end deftypefun
+
+@deftypefun int mpn_zero_p (const mp_limb_t *@var{sp}, mp_size_t @var{n})
+Test @{@var{sp}, @var{n}@} and return 1 if the operand is zero, 0 otherwise.
+@end deftypefun
+
+@deftypefun mp_size_t mpn_gcd (mp_limb_t *@var{rp}, mp_limb_t *@var{xp}, mp_size_t @var{xn}, mp_limb_t *@var{yp}, mp_size_t @var{yn})
+Set @{@var{rp}, @var{retval}@} to the greatest common divisor of @{@var{xp},
+@var{xn}@} and @{@var{yp}, @var{yn}@}.  The result can be up to @var{yn} limbs,
+the return value is the actual number produced.  Both source operands are
+destroyed.
+
+It is required that @math{@var{xn} @ge @var{yn} > 0}, the most significant
+limb of @{@var{yp}, @var{yn}@} must be non-zero, and at least one of
+the two operands must be odd.  No overlap is permitted
+between @{@var{xp}, @var{xn}@} and @{@var{yp}, @var{yn}@}.
+@end deftypefun
+
+@deftypefun mp_limb_t mpn_gcd_1 (const mp_limb_t *@var{xp}, mp_size_t @var{xn}, mp_limb_t @var{ylimb})
+Return the greatest common divisor of @{@var{xp}, @var{xn}@} and @var{ylimb}.
+Both operands must be non-zero.
+@end deftypefun
+
+@deftypefun mp_size_t mpn_gcdext (mp_limb_t *@var{gp}, mp_limb_t *@var{sp}, mp_size_t *@var{sn}, mp_limb_t *@var{up}, mp_size_t @var{un}, mp_limb_t *@var{vp}, mp_size_t @var{vn})
+Let @m{U,@var{U}} be defined by @{@var{up}, @var{un}@} and let @m{V,@var{V}} be
+defined by @{@var{vp}, @var{vn}@}.
+
+Compute the greatest common divisor @math{G} of @math{U} and @math{V}.  Compute
+a cofactor @math{S} such that @math{G = US + VT}.  The second cofactor @var{T}
+is not computed but can easily be obtained from @m{(G - US) / V, (@var{G} -
+@var{U}*@var{S}) / @var{V}} (the division will be exact).  It is required that
+@math{@var{un} @ge @var{vn} > 0}, and the most significant
+limb of @{@var{vp}, @var{vn}@} must be non-zero.
+
+@math{S} satisfies @math{S = 1} or @math{@GMPabs{S} < V / (2 G)}. @math{S =
+0} if and only if @math{V} divides @math{U} (i.e., @math{G = V}).
+
+Store @math{G} at @var{gp} and let the return value define its limb count.
+Store @math{S} at @var{sp} and let |*@var{sn}| define its limb count.  @math{S}
+can be negative; when this happens *@var{sn} will be negative.  The area at
+@var{gp} should have room for @var{vn} limbs and the area at @var{sp} should
+have room for @math{@var{vn}+1} limbs.
+
+Both source operands are destroyed.
+
+Compatibility notes: GMP 4.3.0 and 4.3.1 defined @math{S} less strictly.
+Earlier as well as later GMP releases define @math{S} as described here.
+GMP releases before GMP 4.3.0 required additional space for both input and output
+areas. More precisely, the areas @{@var{up}, @math{@var{un}+1}@} and
+@{@var{vp}, @math{@var{vn}+1}@} were destroyed (i.e.@: the operands plus an
+extra limb past the end of each), and the areas pointed to by @var{gp} and
+@var{sp} should each have room for @math{@var{un}+1} limbs.
+@end deftypefun
+
+@deftypefun mp_size_t mpn_sqrtrem (mp_limb_t *@var{r1p}, mp_limb_t *@var{r2p}, const mp_limb_t *@var{sp}, mp_size_t @var{n})
+Compute the square root of @{@var{sp}, @var{n}@} and put the result at
+@{@var{r1p}, @math{@GMPceil{@var{n}/2}}@} and the remainder at @{@var{r2p},
+@var{retval}@}.  @var{r2p} needs space for @var{n} limbs, but the return value
+indicates how many are produced.
+
+The most significant limb of @{@var{sp}, @var{n}@} must be non-zero.  The
+areas @{@var{r1p}, @math{@GMPceil{@var{n}/2}}@} and @{@var{sp}, @var{n}@} must
+be completely separate.  The areas @{@var{r2p}, @var{n}@} and @{@var{sp},
+@var{n}@} must be either identical or completely separate.
+
+If the remainder is not wanted then @var{r2p} can be @code{NULL}, and in this
+case the return value is zero or non-zero according to whether the remainder
+would have been zero or non-zero.
+
+A return value of zero indicates a perfect square.  See also
+@code{mpn_perfect_square_p}.
+@end deftypefun
+
+@deftypefun size_t mpn_sizeinbase (const mp_limb_t *@var{xp}, mp_size_t @var{n}, int @var{base})
+Return the size of @{@var{xp},@var{n}@} measured in number of digits in the
+given @var{base}.  @var{base} can vary from 2 to 62.  Requires @math{@var{n} > 0}
+and @math{@var{xp}[@var{n}-1] > 0}.  The result will be either exact or
+1 too big.  If @var{base} is a power of 2, the result is always exact.
+@end deftypefun
+
+@deftypefun mp_size_t mpn_get_str (unsigned char *@var{str}, int @var{base}, mp_limb_t *@var{s1p}, mp_size_t @var{s1n})
+Convert @{@var{s1p}, @var{s1n}@} to a raw unsigned char array at @var{str} in
+base @var{base}, and return the number of characters produced.  There may be
+leading zeros in the string.  The string is not in ASCII; to convert it to
+printable format, add the ASCII codes for @samp{0} or @samp{A}, depending on
+the base and range.  @var{base} can vary from 2 to 256.
+
+The most significant limb of the input @{@var{s1p}, @var{s1n}@} must be
+non-zero.  The input @{@var{s1p}, @var{s1n}@} is clobbered, except when
+@var{base} is a power of 2, in which case it's unchanged.
+
+The area at @var{str} has to have space for the largest possible number
+represented by a @var{s1n} long limb array, plus one extra character.
+@end deftypefun
+
+@deftypefun mp_size_t mpn_set_str (mp_limb_t *@var{rp}, const unsigned char *@var{str}, size_t @var{strsize}, int @var{base})
+Convert bytes @{@var{str},@var{strsize}@} in the given @var{base} to limbs at
+@var{rp}.
+
+@math{@var{str}[0]} is the most significant input byte and
+@math{@var{str}[@var{strsize}-1]} is the least significant input byte.  Each
+byte should be a value in the range 0 to @math{@var{base}-1}, not an ASCII
+character.  @var{base} can vary from 2 to 256.
+
+The converted value is @{@var{rp},@var{rn}@} where @var{rn} is the return
+value.  If the most significant input byte @math{@var{str}[0]} is non-zero,
+then @math{@var{rp}[@var{rn}-1]} will be non-zero, else
+@math{@var{rp}[@var{rn}-1]} and some number of subsequent limbs may be zero.
+
+The area at @var{rp} has to have space for the largest possible number with
+@var{strsize} digits in the chosen base, plus one extra limb.
+
+The input must have at least one byte, and no overlap is permitted between
+@{@var{str},@var{strsize}@} and the result at @var{rp}.
+@end deftypefun
+
+@deftypefun {mp_bitcnt_t} mpn_scan0 (const mp_limb_t *@var{s1p}, mp_bitcnt_t @var{bit})
+Scan @var{s1p} from bit position @var{bit} for the next clear bit.
+
+It is required that there be a clear bit within the area at @var{s1p} at or
+beyond bit position @var{bit}, so that the function has something to return.
+@end deftypefun
+
+@deftypefun {mp_bitcnt_t} mpn_scan1 (const mp_limb_t *@var{s1p}, mp_bitcnt_t @var{bit})
+Scan @var{s1p} from bit position @var{bit} for the next set bit.
+
+It is required that there be a set bit within the area at @var{s1p} at or
+beyond bit position @var{bit}, so that the function has something to return.
+@end deftypefun
+
+@deftypefun void mpn_random (mp_limb_t *@var{r1p}, mp_size_t @var{r1n})
+@deftypefunx void mpn_random2 (mp_limb_t *@var{r1p}, mp_size_t @var{r1n})
+Generate a random number of length @var{r1n} and store it at @var{r1p}.  The
+most significant limb is always non-zero.  @code{mpn_random} generates
+uniformly distributed limb data, @code{mpn_random2} generates long strings of
+zeros and ones in the binary representation.
+
+@code{mpn_random2} is intended for testing the correctness of the @code{mpn}
+routines.
+@end deftypefun
+
+@deftypefun {mp_bitcnt_t} mpn_popcount (const mp_limb_t *@var{s1p}, mp_size_t @var{n})
+Count the number of set bits in @{@var{s1p}, @var{n}@}.
+@end deftypefun
+
+@deftypefun {mp_bitcnt_t} mpn_hamdist (const mp_limb_t *@var{s1p}, const mp_limb_t *@var{s2p}, mp_size_t @var{n})
+Compute the hamming distance between @{@var{s1p}, @var{n}@} and @{@var{s2p},
+@var{n}@}, which is the number of bit positions where the two operands have
+different bit values.
+@end deftypefun
+
+@deftypefun int mpn_perfect_square_p (const mp_limb_t *@var{s1p}, mp_size_t @var{n})
+Return non-zero iff @{@var{s1p}, @var{n}@} is a perfect square.
+The most significant limb of the input @{@var{s1p}, @var{n}@} must be
+non-zero.
+@end deftypefun
+
+@deftypefun void mpn_and_n (mp_limb_t *@var{rp}, const mp_limb_t *@var{s1p}, const mp_limb_t *@var{s2p}, mp_size_t @var{n})
+Perform the bitwise logical and of @{@var{s1p}, @var{n}@} and @{@var{s2p},
+@var{n}@}, and write the result to @{@var{rp}, @var{n}@}.
+@end deftypefun
+
+@deftypefun void mpn_ior_n (mp_limb_t *@var{rp}, const mp_limb_t *@var{s1p}, const mp_limb_t *@var{s2p}, mp_size_t @var{n})
+Perform the bitwise logical inclusive or of @{@var{s1p}, @var{n}@} and
+@{@var{s2p}, @var{n}@}, and write the result to @{@var{rp}, @var{n}@}.
+@end deftypefun
+
+@deftypefun void mpn_xor_n (mp_limb_t *@var{rp}, const mp_limb_t *@var{s1p}, const mp_limb_t *@var{s2p}, mp_size_t @var{n})
+Perform the bitwise logical exclusive or of @{@var{s1p}, @var{n}@} and
+@{@var{s2p}, @var{n}@}, and write the result to @{@var{rp}, @var{n}@}.
+@end deftypefun
+
+@deftypefun void mpn_andn_n (mp_limb_t *@var{rp}, const mp_limb_t *@var{s1p}, const mp_limb_t *@var{s2p}, mp_size_t @var{n})
+Perform the bitwise logical and of @{@var{s1p}, @var{n}@} and the bitwise
+complement of @{@var{s2p}, @var{n}@}, and write the result to @{@var{rp}, @var{n}@}.
+@end deftypefun
+
+@deftypefun void mpn_iorn_n (mp_limb_t *@var{rp}, const mp_limb_t *@var{s1p}, const mp_limb_t *@var{s2p}, mp_size_t @var{n})
+Perform the bitwise logical inclusive or of @{@var{s1p}, @var{n}@} and the bitwise
+complement of @{@var{s2p}, @var{n}@}, and write the result to @{@var{rp}, @var{n}@}.
+@end deftypefun
+
+@deftypefun void mpn_nand_n (mp_limb_t *@var{rp}, const mp_limb_t *@var{s1p}, const mp_limb_t *@var{s2p}, mp_size_t @var{n})
+Perform the bitwise logical and of @{@var{s1p}, @var{n}@} and @{@var{s2p},
+@var{n}@}, and write the bitwise complement of the result to @{@var{rp}, @var{n}@}.
+@end deftypefun
+
+@deftypefun void mpn_nior_n (mp_limb_t *@var{rp}, const mp_limb_t *@var{s1p}, const mp_limb_t *@var{s2p}, mp_size_t @var{n})
+Perform the bitwise logical inclusive or of @{@var{s1p}, @var{n}@} and
+@{@var{s2p}, @var{n}@}, and write the bitwise complement of the result to
+@{@var{rp}, @var{n}@}.
+@end deftypefun
+
+@deftypefun void mpn_xnor_n (mp_limb_t *@var{rp}, const mp_limb_t *@var{s1p}, const mp_limb_t *@var{s2p}, mp_size_t @var{n})
+Perform the bitwise logical exclusive or of @{@var{s1p}, @var{n}@} and
+@{@var{s2p}, @var{n}@}, and write the bitwise complement of the result to
+@{@var{rp}, @var{n}@}.
+@end deftypefun
+
+@deftypefun void mpn_com (mp_limb_t *@var{rp}, const mp_limb_t *@var{sp}, mp_size_t @var{n})
+Perform the bitwise complement of @{@var{sp}, @var{n}@}, and write the result
+to @{@var{rp}, @var{n}@}.
+@end deftypefun
+
+@deftypefun void mpn_copyi (mp_limb_t *@var{rp}, const mp_limb_t *@var{s1p}, mp_size_t @var{n})
+Copy from @{@var{s1p}, @var{n}@} to @{@var{rp}, @var{n}@}, increasingly.
+@end deftypefun
+
+@deftypefun void mpn_copyd (mp_limb_t *@var{rp}, const mp_limb_t *@var{s1p}, mp_size_t @var{n})
+Copy from @{@var{s1p}, @var{n}@} to @{@var{rp}, @var{n}@}, decreasingly.
+@end deftypefun
+
+@deftypefun void mpn_zero (mp_limb_t *@var{rp}, mp_size_t @var{n})
+Zero @{@var{rp}, @var{n}@}.
+@end deftypefun
+
+@sp 1
+@section Low-level functions for cryptography
+@cindex Low-level functions for cryptography
+@cindex Cryptography functions, low-level
+
+The functions prefixed with @code{mpn_sec_} and @code{mpn_cnd_} are designed to
+perform the exact same low-level operations and have the same cache access
+patterns for any two same-size arguments, assuming that function arguments are
+placed at the same position and that the machine state is identical upon
+function entry.  These functions are intended for cryptographic purposes, where
+resilience to side-channel attacks is desired.
+
+These functions are less efficient than their ``leaky'' counterparts; their
+performance for operands of the sizes typically used for cryptographic
+applications is between 15% and 100% worse.  For larger operands, these
+functions might be inadequate, since they rely on asymptotically elementary
+algorithms.
+
+These functions do not make any explicit allocations.  Those of these functions
+that need scratch space accept a scratch space operand.  This convention allows
+callers to keep sensitive data in designated memory areas.  Note however that
+compilers may choose to spill scalar values used within these functions to
+their stack frame and that such scalars may contain sensitive data.
+
+In addition to these specially crafted functions, the following @code{mpn}
+functions are naturally side-channel resistant: @code{mpn_add_n},
+@code{mpn_sub_n}, @code{mpn_lshift}, @code{mpn_rshift}, @code{mpn_zero},
+@code{mpn_copyi}, @code{mpn_copyd}, @code{mpn_com}, and the logical function
+(@code{mpn_and_n}, etc).
+
+There are some exceptions from the side-channel resilience: (1) Some assembly
+implementations of @code{mpn_lshift} identify shift-by-one as a special case.
+This is a problem iff the shift count is a function of sensitive data.  (2)
+Alpha ev6 and Pentium4 using 64-bit limbs have leaky @code{mpn_add_n} and
+@code{mpn_sub_n}.  (3) Alpha ev6 has a leaky @code{mpn_mul_1} which also makes
+@code{mpn_sec_mul} on those systems unsafe.
+
+@deftypefun mp_limb_t mpn_cnd_add_n (mp_limb_t @var{cnd}, mp_limb_t *@var{rp}, const mp_limb_t *@var{s1p}, const mp_limb_t *@var{s2p}, mp_size_t @var{n})
+@deftypefunx mp_limb_t mpn_cnd_sub_n (mp_limb_t @var{cnd}, mp_limb_t *@var{rp}, const mp_limb_t *@var{s1p}, const mp_limb_t *@var{s2p}, mp_size_t @var{n})
+These functions do conditional addition and subtraction.  If @var{cnd} is
+non-zero, they produce the same result as a regular @code{mpn_add_n} or
+@code{mpn_sub_n}, and if @var{cnd} is zero, they copy @{@var{s1p},@var{n}@} to
+the result area and return zero.  The functions are designed to have timing and
+memory access patterns depending only on size and location of the data areas,
+but independent of the condition @var{cnd}.  Like for @code{mpn_add_n} and
+@code{mpn_sub_n}, on most machines, the timing will also be independent of the
+actual limb values.
+@end deftypefun
+
+@deftypefun mp_limb_t mpn_sec_add_1 (mp_limb_t *@var{rp}, const mp_limb_t *@var{ap}, mp_size_t @var{n}, mp_limb_t @var{b}, mp_limb_t *@var{tp})
+@deftypefunx mp_limb_t mpn_sec_sub_1 (mp_limb_t *@var{rp}, const mp_limb_t *@var{ap}, mp_size_t @var{n}, mp_limb_t @var{b}, mp_limb_t *@var{tp})
+Set @var{R} to @var{A} + @var{b} or @var{A} - @var{b}, respectively, where
+@var{R} = @{@var{rp},@var{n}@}, @var{A} = @{@var{ap},@var{n}@}, and @var{b} is
+a single limb. Returns carry.
+
+These functions take @math{O(N)} time, unlike the leaky functions
+@code{mpn_add_1} which are @math{O(1)} on average. They require scratch space
+of @code{mpn_sec_add_1_itch(@var{n})} and @code{mpn_sec_sub_1_itch(@var{n})}
+limbs, respectively, to be passed in the @var{tp} parameter. The scratch space
+requirements are guaranteed to be at most @var{n} limbs, and increase
+monotonously in the operand size.
+@end deftypefun
+
+@deftypefun void mpn_cnd_swap (mp_limb_t @var{cnd}, volatile mp_limb_t *@var{ap}, volatile mp_limb_t *@var{bp}, mp_size_t @var{n})
+If @var{cnd} is non-zero, swaps the contents of the areas @{@var{ap},@var{n}@}
+and @{@var{bp},@var{n}@}. Otherwise, the areas are left unmodified.
+Implemented using logical operations on the limbs, with the same memory
+accesses independent of the value of @var{cnd}.
+@end deftypefun
+
+@deftypefun void mpn_sec_mul (mp_limb_t *@var{rp}, const mp_limb_t *@var{ap}, mp_size_t @var{an}, const mp_limb_t *@var{bp}, mp_size_t @var{bn}, mp_limb_t *@var{tp})
+@deftypefunx mp_size_t mpn_sec_mul_itch (mp_size_t @var{an}, mp_size_t @var{bn})
+Set @var{R} to @math{A @times{} B}, where @var{A} = @{@var{ap},@var{an}@},
+@var{B} = @{@var{bp},@var{bn}@}, and @var{R} =
+@{@var{rp},@math{@var{an}+@var{bn}}@}.
+
+It is required that @math{@var{an} @ge @var{bn} > 0}.
+
+No overlapping between @var{R} and the input operands is allowed.  For
+@math{@var{A} = @var{B}}, use @code{mpn_sec_sqr} for optimal performance.
+
+This function requires scratch space of @code{mpn_sec_mul_itch(@var{an},
+@var{bn})} limbs to be passed in the @var{tp} parameter.  The scratch space
+requirements are guaranteed to increase monotonously in the operand sizes.
+@end deftypefun
+
+
+@deftypefun void mpn_sec_sqr (mp_limb_t *@var{rp}, const mp_limb_t *@var{ap}, mp_size_t @var{an}, mp_limb_t *@var{tp})
+@deftypefunx mp_size_t mpn_sec_sqr_itch (mp_size_t @var{an})
+Set @var{R} to @math{A^2}, where @var{A} = @{@var{ap},@var{an}@}, and @var{R} =
+@{@var{rp},@math{2@var{an}}@}.
+
+It is required that @math{@var{an} > 0}.
+
+No overlapping between @var{R} and the input operands is allowed.
+
+This function requires scratch space of @code{mpn_sec_sqr_itch(@var{an})} limbs
+to be passed in the @var{tp} parameter.  The scratch space requirements are
+guaranteed to increase monotonously in the operand size.
+@end deftypefun
+
+
+@deftypefun void mpn_sec_powm (mp_limb_t *@var{rp}, const mp_limb_t *@var{bp}, mp_size_t @var{bn}, const mp_limb_t *@var{ep}, mp_bitcnt_t @var{enb},  const mp_limb_t *@var{mp}, mp_size_t @var{n}, mp_limb_t *@var{tp})
+@deftypefunx mp_size_t mpn_sec_powm_itch (mp_size_t @var{bn}, mp_bitcnt_t @var{enb}, size_t @var{n})
+Set @var{R} to @m{B^E \bmod @var{M}, (@var{B} raised to @var{E}) modulo
+@var{M}}, where @var{R} = @{@var{rp},@var{n}@}, @var{M} = @{@var{mp},@var{n}@},
+and @var{E} = @{@var{ep},@math{@GMPceil{@var{enb} /
+@code{GMP\_NUMB\_BITS}}}@}.
+
+It is required that @math{@var{B} > 0}, that @math{@var{M} > 0} is odd, and
+that @m{@var{E} < 2@GMPraise{@var{enb}}, @var{E} < 2^@var{enb}}, with @math{@var{enb} > 0}.
+
+No overlapping between @var{R} and the input operands is allowed.
+
+This function requires scratch space of @code{mpn_sec_powm_itch(@var{bn},
+@var{enb}, @var{n})} limbs to be passed in the @var{tp} parameter.  The scratch
+space requirements are guaranteed to increase monotonously in the operand
+sizes.
+@end deftypefun
+
+@deftypefun void mpn_sec_tabselect (mp_limb_t *@var{rp}, const mp_limb_t *@var{tab}, mp_size_t @var{n}, mp_size_t @var{nents}, mp_size_t @var{which})
+Select entry @var{which} from table @var{tab}, which has @var{nents} entries, each @var{n}
+limbs.  Store the selected entry at @var{rp}.
+
+This function reads the entire table to avoid side-channel information leaks.
+@end deftypefun
+
+@deftypefun mp_limb_t mpn_sec_div_qr (mp_limb_t *@var{qp}, mp_limb_t *@var{np}, mp_size_t @var{nn}, const mp_limb_t *@var{dp}, mp_size_t @var{dn}, mp_limb_t *@var{tp})
+@deftypefunx mp_size_t mpn_sec_div_qr_itch (mp_size_t @var{nn}, mp_size_t @var{dn})
+
+Set @var{Q} to @m{\lfloor @var{N} / @var{D}\rfloor, the truncated quotient
+@var{N} / @var{D}} and @var{R} to @m{@var{N} \bmod @var{D}, @var{N} modulo
+@var{D}}, where @var{N} = @{@var{np},@var{nn}@}, @var{D} =
+@{@var{dp},@var{dn}@}, @var{Q}'s most significant limb is the function return
+value and the remaining limbs are @{@var{qp},@var{nn-dn}@}, and @var{R} =
+@{@var{np},@var{dn}@}.
+
+It is required that @math{@var{nn} @ge @var{dn} @ge 1}, and that
+@m{@var{dp}[@var{dn}-1] @neq 0, @var{dp}[@var{dn}-1] != 0}.  This does not
+imply that @math{@var{N} @ge @var{D}} since @var{N} might be zero-padded.
+
+Note the overlapping between @var{N} and @var{R}.  No other operand overlapping
+is allowed.  The entire space occupied by @var{N} is overwritten.
+
+This function requires scratch space of @code{mpn_sec_div_qr_itch(@var{nn},
+@var{dn})} limbs to be passed in the @var{tp} parameter.
+@end deftypefun
+
+@deftypefun void mpn_sec_div_r (mp_limb_t *@var{np}, mp_size_t @var{nn}, const mp_limb_t *@var{dp}, mp_size_t @var{dn}, mp_limb_t *@var{tp})
+@deftypefunx mp_size_t mpn_sec_div_r_itch (mp_size_t @var{nn}, mp_size_t @var{dn})
+
+Set @var{R} to @m{@var{N} \bmod @var{D}, @var{N} modulo @var{D}}, where @var{N}
+= @{@var{np},@var{nn}@}, @var{D} = @{@var{dp},@var{dn}@}, and @var{R} =
+@{@var{np},@var{dn}@}.
+
+It is required that @math{@var{nn} @ge @var{dn} @ge 1}, and that
+@m{@var{dp}[@var{dn}-1] @neq 0, @var{dp}[@var{dn}-1] != 0}.  This does not
+imply that @math{@var{N} @ge @var{D}} since @var{N} might be zero-padded.
+
+Note the overlapping between @var{N} and @var{R}.  No other operand overlapping
+is allowed.  The entire space occupied by @var{N} is overwritten.
+
+This function requires scratch space of @code{mpn_sec_div_r_itch(@var{nn},
+@var{dn})} limbs to be passed in the @var{tp} parameter.
+@end deftypefun
+
+@deftypefun int mpn_sec_invert (mp_limb_t *@var{rp}, mp_limb_t *@var{ap}, const mp_limb_t *@var{mp}, mp_size_t @var{n}, mp_bitcnt_t @var{nbcnt}, mp_limb_t *@var{tp})
+@deftypefunx mp_size_t mpn_sec_invert_itch (mp_size_t @var{n})
+Set @var{R} to @m{@var{A}^{-1} \bmod @var{M}, the inverse of @var{A} modulo
+@var{M}}, where @var{R} = @{@var{rp},@var{n}@}, @var{A} = @{@var{ap},@var{n}@},
+and @var{M} = @{@var{mp},@var{n}@}.  @strong{This function's interface is
+preliminary.}
+
+If an inverse exists, return 1, otherwise return 0 and leave @var{R}
+undefined. In either case, the input @var{A} is destroyed.
+
+It is required that @var{M} is odd, and that @math{@var{nbcnt} @ge
+@GMPceil{\log(@var{A}+1)} + @GMPceil{\log(@var{M}+1)}}.  A safe choice is
+@m{@var{nbcnt} = 2@var{n} @times{} @code{GMP\_NUMB\_BITS}, @var{nbcnt} = 2
+@times{} @var{n} @times{} GMP_NUMB_BITS}, but a smaller value might improve
+performance if @var{M} or @var{A} are known to have leading zero bits.
+
+This function requires scratch space of @code{mpn_sec_invert_itch(@var{n})}
+limbs to be passed in the @var{tp} parameter.
+@end deftypefun
+
+
+@sp 1
+@section Nails
+@cindex Nails
+
+@strong{Everything in this section is highly experimental and may disappear or
+be subject to incompatible changes in a future version of GMP.}
+
+Nails are an experimental feature whereby a few bits are left unused at the
+top of each @code{mp_limb_t}.  This can significantly improve carry handling
+on some processors.
+
+All the @code{mpn} functions accepting limb data will expect the nail bits to
+be zero on entry, and will return data with the nails similarly all zero.
+This applies both to limb vectors and to single limb arguments.
+
+Nails can be enabled by configuring with @samp{--enable-nails}.  By default
+the number of bits will be chosen according to what suits the host processor,
+but a particular number can be selected with @samp{--enable-nails=N}.
+
+At the mpn level, a nail build is neither source nor binary compatible with a
+non-nail build, strictly speaking.  But programs acting on limbs only through
+the mpn functions are likely to work equally well with either build, and
+judicious use of the definitions below should make any program compatible with
+either build, at the source level.
+
+For the higher level routines, meaning @code{mpz} etc, a nail build should be
+fully source and binary compatible with a non-nail build.
+
+@defmac GMP_NAIL_BITS
+@defmacx GMP_NUMB_BITS
+@defmacx GMP_LIMB_BITS
+@code{GMP_NAIL_BITS} is the number of nail bits, or 0 when nails are not in
+use.  @code{GMP_NUMB_BITS} is the number of data bits in a limb.
+@code{GMP_LIMB_BITS} is the total number of bits in an @code{mp_limb_t}.  In
+all cases
+
+@example
+GMP_LIMB_BITS == GMP_NAIL_BITS + GMP_NUMB_BITS
+@end example
+@end defmac
+
+@defmac GMP_NAIL_MASK
+@defmacx GMP_NUMB_MASK
+Bit masks for the nail and number parts of a limb.  @code{GMP_NAIL_MASK} is 0
+when nails are not in use.
+
+@code{GMP_NAIL_MASK} is not often needed, since the nail part can be obtained
+with @code{x >> GMP_NUMB_BITS}, and that means one less large constant, which
+can help various RISC chips.
+@end defmac
+
+@defmac GMP_NUMB_MAX
+The maximum value that can be stored in the number part of a limb.  This is
+the same as @code{GMP_NUMB_MASK}, but can be used for clarity when doing
+comparisons rather than bit-wise operations.
+@end defmac
+
+The term ``nails'' comes from finger or toe nails, which are at the ends of a
+limb (arm or leg).  ``numb'' is short for number, but is also how the
+developers felt after trying for a long time to come up with sensible names
+for these things.
+
+In the future (the distant future most likely) a non-zero nail might be
+permitted, giving non-unique representations for numbers in a limb vector.
+This would help vector processors since carries would only ever need to
+propagate one or two limbs.
+
+
+@node Random Number Functions, Formatted Output, Low-level Functions, Top
+@chapter Random Number Functions
+@cindex Random number functions
+
+Sequences of pseudo-random numbers in GMP are generated using a variable of
+type @code{gmp_randstate_t}, which holds an algorithm selection and a current
+state.  Such a variable must be initialized by a call to one of the
+@code{gmp_randinit} functions, and can be seeded with one of the
+@code{gmp_randseed} functions.
+
+The functions actually generating random numbers are described in @ref{Integer
+Random Numbers}, and @ref{Miscellaneous Float Functions}.
+
+The older style random number functions don't accept a @code{gmp_randstate_t}
+parameter but instead share a global variable of that type.  They use a
+default algorithm and are currently not seeded (though perhaps that will
+change in the future).  The new functions accepting a @code{gmp_randstate_t}
+are recommended for applications that care about randomness.
+
+@menu
+* Random State Initialization::
+* Random State Seeding::
+* Random State Miscellaneous::
+@end menu
+
+@node Random State Initialization, Random State Seeding, Random Number Functions, Random Number Functions
+@section Random State Initialization
+@cindex Random number state
+@cindex Initialization functions
+
+@deftypefun void gmp_randinit_default (gmp_randstate_t @var{state})
+Initialize @var{state} with a default algorithm.  This will be a compromise
+between speed and randomness, and is recommended for applications with no
+special requirements.  Currently this is @code{gmp_randinit_mt}.
+@end deftypefun
+
+@deftypefun void gmp_randinit_mt (gmp_randstate_t @var{state})
+@cindex Mersenne twister random numbers
+Initialize @var{state} for a Mersenne Twister algorithm.  This algorithm is
+fast and has good randomness properties.
+@end deftypefun
+
+@deftypefun void gmp_randinit_lc_2exp (gmp_randstate_t @var{state}, const mpz_t @var{a}, @w{unsigned long @var{c}}, @w{mp_bitcnt_t @var{m2exp}})
+@cindex Linear congruential random numbers
+Initialize @var{state} with a linear congruential algorithm @m{X = (@var{a}X +
+@var{c}) @bmod 2^{m2exp}, X = (@var{a}*X + @var{c}) mod 2^@var{m2exp}}.
+
+The low bits of @math{X} in this algorithm are not very random.  The least
+significant bit will have a period no more than 2, and the second bit no more
+than 4, etc.  For this reason only the high half of each @math{X} is actually
+used.
+
+When a random number of more than @math{@var{m2exp}/2} bits is to be
+generated, multiple iterations of the recurrence are used and the results
+concatenated.
+@end deftypefun
+
+@deftypefun int gmp_randinit_lc_2exp_size (gmp_randstate_t @var{state}, mp_bitcnt_t @var{size})
+@cindex Linear congruential random numbers
+Initialize @var{state} for a linear congruential algorithm as per
+@code{gmp_randinit_lc_2exp}.  @var{a}, @var{c} and @var{m2exp} are selected
+from a table, chosen so that @var{size} bits (or more) of each @math{X} will
+be used, i.e.@: @math{@var{m2exp}/2 @ge{} @var{size}}.
+
+If successful the return value is non-zero.  If @var{size} is bigger than the
+table data provides then the return value is zero.  The maximum @var{size}
+currently supported is 128.
+@end deftypefun
+
+@deftypefun void gmp_randinit_set (gmp_randstate_t @var{rop}, gmp_randstate_t @var{op})
+Initialize @var{rop} with a copy of the algorithm and state from @var{op}.
+@end deftypefun
+
+@c  Although gmp_randinit, gmp_errno and related constants are obsolete, we
+@c  still put @findex entries for them, since they're still documented and
+@c  someone might be looking them up when perusing old application code.
+
+@deftypefun void gmp_randinit (gmp_randstate_t @var{state}, @w{gmp_randalg_t @var{alg}}, @dots{})
+@strong{This function is obsolete.}
+
+@findex GMP_RAND_ALG_LC
+@findex GMP_RAND_ALG_DEFAULT
+Initialize @var{state} with an algorithm selected by @var{alg}.  The only
+choice is @code{GMP_RAND_ALG_LC}, which is @code{gmp_randinit_lc_2exp_size}
+described above.  A third parameter of type @code{unsigned long} is required,
+this is the @var{size} for that function.  @code{GMP_RAND_ALG_DEFAULT} or 0
+are the same as @code{GMP_RAND_ALG_LC}.
+
+@c  For reference, this is the only place gmp_errno has been documented, and
+@c  due to being non thread safe we won't be adding to it's uses.
+@findex gmp_errno
+@findex GMP_ERROR_UNSUPPORTED_ARGUMENT
+@findex GMP_ERROR_INVALID_ARGUMENT
+@code{gmp_randinit} sets bits in the global variable @code{gmp_errno} to
+indicate an error.  @code{GMP_ERROR_UNSUPPORTED_ARGUMENT} if @var{alg} is
+unsupported, or @code{GMP_ERROR_INVALID_ARGUMENT} if the @var{size} parameter
+is too big.  It may be noted this error reporting is not thread safe (a good
+reason to use @code{gmp_randinit_lc_2exp_size} instead).
+@end deftypefun
+
+@deftypefun void gmp_randclear (gmp_randstate_t @var{state})
+Free all memory occupied by @var{state}.
+@end deftypefun
+
+
+@node Random State Seeding, Random State Miscellaneous, Random State Initialization, Random Number Functions
+@section Random State Seeding
+@cindex Random number seeding
+@cindex Seeding random numbers
+
+@deftypefun void gmp_randseed (gmp_randstate_t @var{state}, const mpz_t @var{seed})
+@deftypefunx void gmp_randseed_ui (gmp_randstate_t @var{state}, @w{unsigned long int @var{seed}})
+Set an initial seed value into @var{state}.
+
+The size of a seed determines how many different sequences of random numbers
+that it's possible to generate.  The ``quality'' of the seed is the randomness
+of a given seed compared to the previous seed used, and this affects the
+randomness of separate number sequences.  The method for choosing a seed is
+critical if the generated numbers are to be used for important applications,
+such as generating cryptographic keys.
+
+Traditionally the system time has been used to seed, but care needs to be
+taken with this.  If an application seeds often and the resolution of the
+system clock is low, then the same sequence of numbers might be repeated.
+Also, the system time is quite easy to guess, so if unpredictability is
+required then it should definitely not be the only source for the seed value.
+On some systems there's a special device @file{/dev/random} which provides
+random data better suited for use as a seed.
+@end deftypefun
+
+
+@node Random State Miscellaneous,  , Random State Seeding, Random Number Functions
+@section Random State Miscellaneous
+
+@deftypefun {unsigned long} gmp_urandomb_ui (gmp_randstate_t @var{state}, unsigned long @var{n})
+Return a uniformly distributed random number of @var{n} bits, i.e.@: in the
+range 0 to @m{2^n-1,2^@var{n}-1} inclusive.  @var{n} must be less than or
+equal to the number of bits in an @code{unsigned long}.
+@end deftypefun
+
+@deftypefun {unsigned long} gmp_urandomm_ui (gmp_randstate_t @var{state}, unsigned long @var{n})
+Return a uniformly distributed random number in the range 0 to
+@math{@var{n}-1}, inclusive.
+@end deftypefun
+
+
+@node Formatted Output, Formatted Input, Random Number Functions, Top
+@chapter Formatted Output
+@cindex Formatted output
+@cindex @code{printf} formatted output
+
+@menu
+* Formatted Output Strings::
+* Formatted Output Functions::
+* C++ Formatted Output::
+@end menu
+
+@node Formatted Output Strings, Formatted Output Functions, Formatted Output, Formatted Output
+@section Format Strings
+
+@code{gmp_printf} and friends accept format strings similar to the standard C
+@code{printf} (@pxref{Formatted Output,, Formatted Output, libc, The GNU C
+Library Reference Manual}).  A format specification is of the form
+
+@example
+% [flags] [width] [.[precision]] [type] conv
+@end example
+
+GMP adds types @samp{Z}, @samp{Q} and @samp{F} for @code{mpz_t}, @code{mpq_t}
+and @code{mpf_t} respectively, @samp{M} for @code{mp_limb_t}, and @samp{N} for
+an @code{mp_limb_t} array.  @samp{Z}, @samp{Q}, @samp{M} and @samp{N} behave
+like integers.  @samp{Q} will print a @samp{/} and a denominator, if needed.
+@samp{F} behaves like a float.  For example,
+
+@example
+mpz_t z;
+gmp_printf ("%s is an mpz %Zd\n", "here", z);
+
+mpq_t q;
+gmp_printf ("a hex rational: %#40Qx\n", q);
+
+mpf_t f;
+int   n;
+gmp_printf ("fixed point mpf %.*Ff with %d digits\n", n, f, n);
+
+mp_limb_t l;
+gmp_printf ("limb %Mu\n", l);
+
+const mp_limb_t *ptr;
+mp_size_t       size;
+gmp_printf ("limb array %Nx\n", ptr, size);
+@end example
+
+For @samp{N} the limbs are expected least significant first, as per the
+@code{mpn} functions (@pxref{Low-level Functions}).  A negative size can be
+given to print the value as a negative.
+
+All the standard C @code{printf} types behave the same as the C library
+@code{printf}, and can be freely intermixed with the GMP extensions.  In the
+current implementation the standard parts of the format string are simply
+handed to @code{printf} and only the GMP extensions handled directly.
+
+The flags accepted are as follows.  GLIBC style @nisamp{'} is only for the
+standard C types (not the GMP types), and only if the C library supports it.
+
+@quotation
+@multitable {(space)} {MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM}
+@item @nicode{0} @tab pad with zeros (rather than spaces)
+@item @nicode{#} @tab show the base with @samp{0x}, @samp{0X} or @samp{0}
+@item @nicode{+} @tab always show a sign
+@item (space)    @tab show a space or a @samp{-} sign
+@item @nicode{'} @tab group digits, GLIBC style (not GMP types)
+@end multitable
+@end quotation
+
+The optional width and precision can be given as a number within the format
+string, or as a @samp{*} to take an extra parameter of type @code{int}, the
+same as the standard @code{printf}.
+
+The standard types accepted are as follows.  @samp{h} and @samp{l} are
+portable, the rest will depend on the compiler (or include files) for the type
+and the C library for the output.
+
+@quotation
+@multitable {(space)} {MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM}
+@item @nicode{h}  @tab @nicode{short}
+@item @nicode{hh} @tab @nicode{char}
+@item @nicode{j}  @tab @nicode{intmax_t} or @nicode{uintmax_t}
+@item @nicode{l}  @tab @nicode{long} or @nicode{wchar_t}
+@item @nicode{ll} @tab @nicode{long long}
+@item @nicode{L}  @tab @nicode{long double}
+@item @nicode{q}  @tab @nicode{quad_t} or @nicode{u_quad_t}
+@item @nicode{t}  @tab @nicode{ptrdiff_t}
+@item @nicode{z}  @tab @nicode{size_t}
+@end multitable
+@end quotation
+
+@noindent
+The GMP types are
+
+@quotation
+@multitable {(space)} {MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM}
+@item @nicode{F}  @tab @nicode{mpf_t}, float conversions
+@item @nicode{Q}  @tab @nicode{mpq_t}, integer conversions
+@item @nicode{M}  @tab @nicode{mp_limb_t}, integer conversions
+@item @nicode{N}  @tab @nicode{mp_limb_t} array, integer conversions
+@item @nicode{Z}  @tab @nicode{mpz_t}, integer conversions
+@end multitable
+@end quotation
+
+The conversions accepted are as follows.  @samp{a} and @samp{A} are always
+supported for @code{mpf_t} but depend on the C library for standard C float
+types.  @samp{m} and @samp{p} depend on the C library.
+
+@quotation
+@multitable {(space)} {MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM}
+@item @nicode{a} @nicode{A} @tab hex floats, C99 style
+@item @nicode{c}            @tab character
+@item @nicode{d}            @tab decimal integer
+@item @nicode{e} @nicode{E} @tab scientific format float
+@item @nicode{f}            @tab fixed point float
+@item @nicode{i}            @tab same as @nicode{d}
+@item @nicode{g} @nicode{G} @tab fixed or scientific float
+@item @nicode{m}            @tab @code{strerror} string, GLIBC style
+@item @nicode{n}            @tab store characters written so far
+@item @nicode{o}            @tab octal integer
+@item @nicode{p}            @tab pointer
+@item @nicode{s}            @tab string
+@item @nicode{u}            @tab unsigned integer
+@item @nicode{x} @nicode{X} @tab hex integer
+@end multitable
+@end quotation
+
+@samp{o}, @samp{x} and @samp{X} are unsigned for the standard C types, but for
+types @samp{Z}, @samp{Q} and @samp{N} they are signed.  @samp{u} is not
+meaningful for @samp{Z}, @samp{Q} and @samp{N}.
+
+@samp{M} is a proxy for the C library @samp{l} or @samp{L}, according to the
+size of @code{mp_limb_t}.  Unsigned conversions will be usual, but a signed
+conversion can be used and will interpret the value as a twos complement
+negative.
+
+@samp{n} can be used with any type, even the GMP types.
+
+Other types or conversions that might be accepted by the C library
+@code{printf} cannot be used through @code{gmp_printf}, this includes for
+instance extensions registered with GLIBC @code{register_printf_function}.
+Also currently there's no support for POSIX @samp{$} style numbered arguments
+(perhaps this will be added in the future).
+
+The precision field has its usual meaning for integer @samp{Z} and float
+@samp{F} types, but is currently undefined for @samp{Q} and should not be used
+with that.
+
+@code{mpf_t} conversions only ever generate as many digits as can be
+accurately represented by the operand, the same as @code{mpf_get_str} does.
+Zeros will be used if necessary to pad to the requested precision.  This
+happens even for an @samp{f} conversion of an @code{mpf_t} which is an
+integer, for instance @math{2^@W{1024}} in an @code{mpf_t} of 128 bits
+precision will only produce about 40 digits, then pad with zeros to the
+decimal point.  An empty precision field like @samp{%.Fe} or @samp{%.Ff} can
+be used to specifically request just the significant digits.  Without any dot
+and thus no precision field, a precision value of 6 will be used.  Note that
+these rules mean that @samp{%Ff}, @samp{%.Ff}, and @samp{%.0Ff} will all be
+different.
+
+The decimal point character (or string) is taken from the current locale
+settings on systems which provide @code{localeconv} (@pxref{Locales,, Locales
+and Internationalization, libc, The GNU C Library Reference Manual}).  The C
+library will normally do the same for standard float output.
+
+The format string is only interpreted as plain @code{char}s, multibyte
+characters are not recognised.  Perhaps this will change in the future.
+
+
+@node Formatted Output Functions, C++ Formatted Output, Formatted Output Strings, Formatted Output
+@section Functions
+@cindex Output functions
+
+Each of the following functions is similar to the corresponding C library
+function.  The basic @code{printf} forms take a variable argument list.  The
+@code{vprintf} forms take an argument pointer, see @ref{Variadic Functions,,
+Variadic Functions, libc, The GNU C Library Reference Manual}, or @samp{man 3
+va_start}.
+
+It should be emphasised that if a format string is invalid, or the arguments
+don't match what the format specifies, then the behaviour of any of these
+functions will be unpredictable.  GCC format string checking is not available,
+since it doesn't recognise the GMP extensions.
+
+The file based functions @code{gmp_printf} and @code{gmp_fprintf} will return
+@math{-1} to indicate a write error.  Output is not ``atomic'', so partial
+output may be produced if a write error occurs.  All the functions can return
+@math{-1} if the C library @code{printf} variant in use returns @math{-1}, but
+this shouldn't normally occur.
+
+@deftypefun int gmp_printf (const char *@var{fmt}, @dots{})
+@deftypefunx int gmp_vprintf (const char *@var{fmt}, va_list @var{ap})
+Print to the standard output @code{stdout}.  Return the number of characters
+written, or @math{-1} if an error occurred.
+@end deftypefun
+
+@deftypefun int gmp_fprintf (FILE *@var{fp}, const char *@var{fmt}, @dots{})
+@deftypefunx int gmp_vfprintf (FILE *@var{fp}, const char *@var{fmt}, va_list @var{ap})
+Print to the stream @var{fp}.  Return the number of characters written, or
+@math{-1} if an error occurred.
+@end deftypefun
+
+@deftypefun int gmp_sprintf (char *@var{buf}, const char *@var{fmt}, @dots{})
+@deftypefunx int gmp_vsprintf (char *@var{buf}, const char *@var{fmt}, va_list @var{ap})
+Form a null-terminated string in @var{buf}.  Return the number of characters
+written, excluding the terminating null.
+
+No overlap is permitted between the space at @var{buf} and the string
+@var{fmt}.
+
+These functions are not recommended, since there's no protection against
+exceeding the space available at @var{buf}.
+@end deftypefun
+
+@deftypefun int gmp_snprintf (char *@var{buf}, size_t @var{size}, const char *@var{fmt}, @dots{})
+@deftypefunx int gmp_vsnprintf (char *@var{buf}, size_t @var{size}, const char *@var{fmt}, va_list @var{ap})
+Form a null-terminated string in @var{buf}.  No more than @var{size} bytes
+will be written.  To get the full output, @var{size} must be enough for the
+string and null-terminator.
+
+The return value is the total number of characters which ought to have been
+produced, excluding the terminating null.  If @math{@var{retval} @ge{}
+@var{size}} then the actual output has been truncated to the first
+@math{@var{size}-1} characters, and a null appended.
+
+No overlap is permitted between the region @{@var{buf},@var{size}@} and the
+@var{fmt} string.
+
+Notice the return value is in ISO C99 @code{snprintf} style.  This is so even
+if the C library @code{vsnprintf} is the older GLIBC 2.0.x style.
+@end deftypefun
+
+@deftypefun int gmp_asprintf (char **@var{pp}, const char *@var{fmt}, @dots{})
+@deftypefunx int gmp_vasprintf (char **@var{pp}, const char *@var{fmt}, va_list @var{ap})
+Form a null-terminated string in a block of memory obtained from the current
+memory allocation function (@pxref{Custom Allocation}).  The block will be the
+size of the string and null-terminator.  The address of the block in stored to
+*@var{pp}.  The return value is the number of characters produced, excluding
+the null-terminator.
+
+Unlike the C library @code{asprintf}, @code{gmp_asprintf} doesn't return
+@math{-1} if there's no more memory available, it lets the current allocation
+function handle that.
+@end deftypefun
+
+@deftypefun int gmp_obstack_printf (struct obstack *@var{ob}, const char *@var{fmt}, @dots{})
+@deftypefunx int gmp_obstack_vprintf (struct obstack *@var{ob}, const char *@var{fmt}, va_list @var{ap})
+@cindex @code{obstack} output
+Append to the current object in @var{ob}.  The return value is the number of
+characters written.  A null-terminator is not written.
+
+@var{fmt} cannot be within the current object in @var{ob}, since that object
+might move as it grows.
+
+These functions are available only when the C library provides the obstack
+feature, which probably means only on GNU systems, see @ref{Obstacks,,
+Obstacks, libc, The GNU C Library Reference Manual}.
+@end deftypefun
+
+
+@node C++ Formatted Output,  , Formatted Output Functions, Formatted Output
+@section C++ Formatted Output
+@cindex C++ @code{ostream} output
+@cindex @code{ostream} output
+
+The following functions are provided in @file{libgmpxx} (@pxref{Headers and
+Libraries}), which is built if C++ support is enabled (@pxref{Build Options}).
+Prototypes are available from @code{<gmp.h>}.
+
+@deftypefun ostream& operator<< (ostream& @var{stream}, const mpz_t @var{op})
+Print @var{op} to @var{stream}, using its @code{ios} formatting settings.
+@code{ios::width} is reset to 0 after output, the same as the standard
+@code{ostream operator<<} routines do.
+
+In hex or octal, @var{op} is printed as a signed number, the same as for
+decimal.  This is unlike the standard @code{operator<<} routines on @code{int}
+etc, which instead give twos complement.
+@end deftypefun
+
+@deftypefun ostream& operator<< (ostream& @var{stream}, const mpq_t @var{op})
+Print @var{op} to @var{stream}, using its @code{ios} formatting settings.
+@code{ios::width} is reset to 0 after output, the same as the standard
+@code{ostream operator<<} routines do.
+
+Output will be a fraction like @samp{5/9}, or if the denominator is 1 then
+just a plain integer like @samp{123}.
+
+In hex or octal, @var{op} is printed as a signed value, the same as for
+decimal.  If @code{ios::showbase} is set then a base indicator is shown on
+both the numerator and denominator (if the denominator is required).
+@end deftypefun
+
+@deftypefun ostream& operator<< (ostream& @var{stream}, const mpf_t @var{op})
+Print @var{op} to @var{stream}, using its @code{ios} formatting settings.
+@code{ios::width} is reset to 0 after output, the same as the standard
+@code{ostream operator<<} routines do.
+
+The decimal point follows the standard library float @code{operator<<}, which
+on recent systems means the @code{std::locale} imbued on @var{stream}.
+
+Hex and octal are supported, unlike the standard @code{operator<<} on
+@code{double}.  The mantissa will be in hex or octal, the exponent will be in
+decimal.  For hex the exponent delimiter is an @samp{@@}.  This is as per
+@code{mpf_out_str}.
+
+@code{ios::showbase} is supported, and will put a base on the mantissa, for
+example hex @samp{0x1.8} or @samp{0x0.8}, or octal @samp{01.4} or @samp{00.4}.
+This last form is slightly strange, but at least differentiates itself from
+decimal.
+@end deftypefun
+
+These operators mean that GMP types can be printed in the usual C++ way, for
+example,
+
+@example
+mpz_t  z;
+int    n;
+...
+cout << "iteration " << n << " value " << z << "\n";
+@end example
+
+But note that @code{ostream} output (and @code{istream} input, @pxref{C++
+Formatted Input}) is the only overloading available for the GMP types and that
+for instance using @code{+} with an @code{mpz_t} will have unpredictable
+results.  For classes with overloading, see @ref{C++ Class Interface}.
+
+
+@node Formatted Input, C++ Class Interface, Formatted Output, Top
+@chapter Formatted Input
+@cindex Formatted input
+@cindex @code{scanf} formatted input
+
+@menu
+* Formatted Input Strings::
+* Formatted Input Functions::
+* C++ Formatted Input::
+@end menu
+
+
+@node Formatted Input Strings, Formatted Input Functions, Formatted Input, Formatted Input
+@section Formatted Input Strings
+
+@code{gmp_scanf} and friends accept format strings similar to the standard C
+@code{scanf} (@pxref{Formatted Input,, Formatted Input, libc, The GNU C
+Library Reference Manual}).  A format specification is of the form
+
+@example
+% [flags] [width] [type] conv
+@end example
+
+GMP adds types @samp{Z}, @samp{Q} and @samp{F} for @code{mpz_t}, @code{mpq_t}
+and @code{mpf_t} respectively.  @samp{Z} and @samp{Q} behave like integers.
+@samp{Q} will read a @samp{/} and a denominator, if present.  @samp{F} behaves
+like a float.
+
+GMP variables don't require an @code{&} when passed to @code{gmp_scanf}, since
+they're already ``call-by-reference''.  For example,
+
+@example
+/* to read say "a(5) = 1234" */
+int   n;
+mpz_t z;
+gmp_scanf ("a(%d) = %Zd\n", &n, z);
+
+mpq_t q1, q2;
+gmp_sscanf ("0377 + 0x10/0x11", "%Qi + %Qi", q1, q2);
+
+/* to read say "topleft (1.55,-2.66)" */
+mpf_t x, y;
+char  buf[32];
+gmp_scanf ("%31s (%Ff,%Ff)", buf, x, y);
+@end example
+
+All the standard C @code{scanf} types behave the same as in the C library
+@code{scanf}, and can be freely intermixed with the GMP extensions.  In the
+current implementation the standard parts of the format string are simply
+handed to @code{scanf} and only the GMP extensions handled directly.
+
+The flags accepted are as follows.  @samp{a} and @samp{'} will depend on
+support from the C library, and @samp{'} cannot be used with GMP types.
+
+@quotation
+@multitable {(space)} {MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM}
+@item @nicode{*} @tab read but don't store
+@item @nicode{a} @tab allocate a buffer (string conversions)
+@item @nicode{'} @tab grouped digits, GLIBC style (not GMP types)
+@end multitable
+@end quotation
+
+The standard types accepted are as follows.  @samp{h} and @samp{l} are
+portable, the rest will depend on the compiler (or include files) for the type
+and the C library for the input.
+
+@quotation
+@multitable {(space)} {MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM}
+@item @nicode{h}  @tab @nicode{short}
+@item @nicode{hh} @tab @nicode{char}
+@item @nicode{j}  @tab @nicode{intmax_t} or @nicode{uintmax_t}
+@item @nicode{l}  @tab @nicode{long int}, @nicode{double} or @nicode{wchar_t}
+@item @nicode{ll} @tab @nicode{long long}
+@item @nicode{L}  @tab @nicode{long double}
+@item @nicode{q}  @tab @nicode{quad_t} or @nicode{u_quad_t}
+@item @nicode{t}  @tab @nicode{ptrdiff_t}
+@item @nicode{z}  @tab @nicode{size_t}
+@end multitable
+@end quotation
+
+@noindent
+The GMP types are
+
+@quotation
+@multitable {(space)} {MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM}
+@item @nicode{F}  @tab @nicode{mpf_t}, float conversions
+@item @nicode{Q}  @tab @nicode{mpq_t}, integer conversions
+@item @nicode{Z}  @tab @nicode{mpz_t}, integer conversions
+@end multitable
+@end quotation
+
+The conversions accepted are as follows.  @samp{p} and @samp{[} will depend on
+support from the C library, the rest are standard.
+
+@quotation
+@multitable {(space)} {MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM}
+@item @nicode{c}            @tab character or characters
+@item @nicode{d}            @tab decimal integer
+@item @nicode{e} @nicode{E} @nicode{f} @nicode{g} @nicode{G}
+                            @tab float
+@item @nicode{i}            @tab integer with base indicator
+@item @nicode{n}            @tab characters read so far
+@item @nicode{o}            @tab octal integer
+@item @nicode{p}            @tab pointer
+@item @nicode{s}            @tab string of non-whitespace characters
+@item @nicode{u}            @tab decimal integer
+@item @nicode{x} @nicode{X} @tab hex integer
+@item @nicode{[}            @tab string of characters in a set
+@end multitable
+@end quotation
+
+@samp{e}, @samp{E}, @samp{f}, @samp{g} and @samp{G} are identical, they all
+read either fixed point or scientific format, and either upper or lower case
+@samp{e} for the exponent in scientific format.
+
+C99 style hex float format (@code{printf %a}, @pxref{Formatted Output
+Strings}) is always accepted for @code{mpf_t}, but for the standard float
+types it will depend on the C library.
+
+@samp{x} and @samp{X} are identical, both accept both upper and lower case
+hexadecimal.
+
+@samp{o}, @samp{u}, @samp{x} and @samp{X} all read positive or negative
+values.  For the standard C types these are described as ``unsigned''
+conversions, but that merely affects certain overflow handling, negatives are
+still allowed (per @code{strtoul}, @pxref{Parsing of Integers,, Parsing of
+Integers, libc, The GNU C Library Reference Manual}).  For GMP types there are
+no overflows, so @samp{d} and @samp{u} are identical.
+
+@samp{Q} type reads the numerator and (optional) denominator as given.  If the
+value might not be in canonical form then @code{mpq_canonicalize} must be
+called before using it in any calculations (@pxref{Rational Number
+Functions}).
+
+@samp{Qi} will read a base specification separately for the numerator and
+denominator.  For example @samp{0x10/11} would be 16/11, whereas
+@samp{0x10/0x11} would be 16/17.
+
+@samp{n} can be used with any of the types above, even the GMP types.
+@samp{*} to suppress assignment is allowed, though in that case it would do
+nothing at all.
+
+Other conversions or types that might be accepted by the C library
+@code{scanf} cannot be used through @code{gmp_scanf}.
+
+Whitespace is read and discarded before a field, except for @samp{c} and
+@samp{[} conversions.
+
+For float conversions, the decimal point character (or string) expected is
+taken from the current locale settings on systems which provide
+@code{localeconv} (@pxref{Locales,, Locales and Internationalization, libc,
+The GNU C Library Reference Manual}).  The C library will normally do the same
+for standard float input.
+
+The format string is only interpreted as plain @code{char}s, multibyte
+characters are not recognised.  Perhaps this will change in the future.
+
+
+@node Formatted Input Functions, C++ Formatted Input, Formatted Input Strings, Formatted Input
+@section Formatted Input Functions
+@cindex Input functions
+
+Each of the following functions is similar to the corresponding C library
+function.  The plain @code{scanf} forms take a variable argument list.  The
+@code{vscanf} forms take an argument pointer, see @ref{Variadic Functions,,
+Variadic Functions, libc, The GNU C Library Reference Manual}, or @samp{man 3
+va_start}.
+
+It should be emphasised that if a format string is invalid, or the arguments
+don't match what the format specifies, then the behaviour of any of these
+functions will be unpredictable.  GCC format string checking is not available,
+since it doesn't recognise the GMP extensions.
+
+No overlap is permitted between the @var{fmt} string and any of the results
+produced.
+
+@deftypefun int gmp_scanf (const char *@var{fmt}, @dots{})
+@deftypefunx int gmp_vscanf (const char *@var{fmt}, va_list @var{ap})
+Read from the standard input @code{stdin}.
+@end deftypefun
+
+@deftypefun int gmp_fscanf (FILE *@var{fp}, const char *@var{fmt}, @dots{})
+@deftypefunx int gmp_vfscanf (FILE *@var{fp}, const char *@var{fmt}, va_list @var{ap})
+Read from the stream @var{fp}.
+@end deftypefun
+
+@deftypefun int gmp_sscanf (const char *@var{s}, const char *@var{fmt}, @dots{})
+@deftypefunx int gmp_vsscanf (const char *@var{s}, const char *@var{fmt}, va_list @var{ap})
+Read from a null-terminated string @var{s}.
+@end deftypefun
+
+The return value from each of these functions is the same as the standard C99
+@code{scanf}, namely the number of fields successfully parsed and stored.
+@samp{%n} fields and fields read but suppressed by @samp{*} don't count
+towards the return value.
+
+If end of input (or a file error) is reached before a character for a field or
+a literal, and if no previous non-suppressed fields have matched, then the
+return value is @code{EOF} instead of 0.  A whitespace character in the format
+string is only an optional match and doesn't induce an @code{EOF} in this
+fashion.  Leading whitespace read and discarded for a field don't count as
+characters for that field.
+
+For the GMP types, input parsing follows C99 rules, namely one character of
+lookahead is used and characters are read while they continue to meet the
+format requirements.  If this doesn't provide a complete number then the
+function terminates, with that field not stored nor counted towards the return
+value.  For instance with @code{mpf_t} an input @samp{1.23e-XYZ} would be read
+up to the @samp{X} and that character pushed back since it's not a digit.  The
+string @samp{1.23e-} would then be considered invalid since an @samp{e} must
+be followed by at least one digit.
+
+For the standard C types, in the current implementation GMP calls the C
+library @code{scanf} functions, which might have looser rules about what
+constitutes a valid input.
+
+Note that @code{gmp_sscanf} is the same as @code{gmp_fscanf} and only does one
+character of lookahead when parsing.  Although clearly it could look at its
+entire input, it is deliberately made identical to @code{gmp_fscanf}, the same
+way C99 @code{sscanf} is the same as @code{fscanf}.
+
+
+@node C++ Formatted Input,  , Formatted Input Functions, Formatted Input
+@section C++ Formatted Input
+@cindex C++ @code{istream} input
+@cindex @code{istream} input
+
+The following functions are provided in @file{libgmpxx} (@pxref{Headers and
+Libraries}), which is built only if C++ support is enabled (@pxref{Build
+Options}).  Prototypes are available from @code{<gmp.h>}.
+
+@deftypefun istream& operator>> (istream& @var{stream}, mpz_t @var{rop})
+Read @var{rop} from @var{stream}, using its @code{ios} formatting settings.
+@end deftypefun
+
+@deftypefun istream& operator>> (istream& @var{stream}, mpq_t @var{rop})
+An integer like @samp{123} will be read, or a fraction like @samp{5/9}.  No
+whitespace is allowed around the @samp{/}.  If the fraction is not in
+canonical form then @code{mpq_canonicalize} must be called (@pxref{Rational
+Number Functions}) before operating on it.
+
+As per integer input, an @samp{0} or @samp{0x} base indicator is read when
+none of @code{ios::dec}, @code{ios::oct} or @code{ios::hex} are set.  This is
+done separately for numerator and denominator, so that for instance
+@samp{0x10/11} is @math{16/11} and @samp{0x10/0x11} is @math{16/17}.
+@end deftypefun
+
+@deftypefun istream& operator>> (istream& @var{stream}, mpf_t @var{rop})
+Read @var{rop} from @var{stream}, using its @code{ios} formatting settings.
+
+Hex or octal floats are not supported, but might be in the future, or perhaps
+it's best to accept only what the standard float @code{operator>>} does.
+@end deftypefun
+
+Note that digit grouping specified by the @code{istream} locale is currently
+not accepted.  Perhaps this will change in the future.
+
+@sp 1
+These operators mean that GMP types can be read in the usual C++ way, for
+example,
+
+@example
+mpz_t  z;
+...
+cin >> z;
+@end example
+
+But note that @code{istream} input (and @code{ostream} output, @pxref{C++
+Formatted Output}) is the only overloading available for the GMP types and
+that for instance using @code{+} with an @code{mpz_t} will have unpredictable
+results.  For classes with overloading, see @ref{C++ Class Interface}.
+
+
+
+@node C++ Class Interface, Custom Allocation, Formatted Input, Top
+@chapter C++ Class Interface
+@cindex C++ interface
+
+This chapter describes the C++ class based interface to GMP.
+
+All GMP C language types and functions can be used in C++ programs, since
+@file{gmp.h} has @code{extern "C"} qualifiers, but the class interface offers
+overloaded functions and operators which may be more convenient.
+
+Due to the implementation of this interface, a reasonably recent C++ compiler
+is required, one supporting namespaces, partial specialization of templates
+and member templates.
+
+@strong{Everything described in this chapter is to be considered preliminary
+and might be subject to incompatible changes if some unforeseen difficulty
+reveals itself.}
+
+@menu
+* C++ Interface General::
+* C++ Interface Integers::
+* C++ Interface Rationals::
+* C++ Interface Floats::
+* C++ Interface Random Numbers::
+* C++ Interface Limitations::
+@end menu
+
+
+@node C++ Interface General, C++ Interface Integers, C++ Class Interface, C++ Class Interface
+@section C++ Interface General
+
+@noindent
+All the C++ classes and functions are available with
+
+@cindex @code{gmpxx.h}
+@example
+#include <gmpxx.h>
+@end example
+
+Programs should be linked with the @file{libgmpxx} and @file{libgmp}
+libraries.  For example,
+
+@example
+g++ mycxxprog.cc -lgmpxx -lgmp
+@end example
+
+@noindent
+The classes defined are
+
+@deftp Class mpz_class
+@deftpx Class mpq_class
+@deftpx Class mpf_class
+@end deftp
+
+The standard operators and various standard functions are overloaded to allow
+arithmetic with these classes.  For example,
+
+@example
+int
+main (void)
+@{
+  mpz_class a, b, c;
+
+  a = 1234;
+  b = "-5678";
+  c = a+b;
+  cout << "sum is " << c << "\n";
+  cout << "absolute value is " << abs(c) << "\n";
+
+  return 0;
+@}
+@end example
+
+An important feature of the implementation is that an expression like
+@code{a=b+c} results in a single call to the corresponding @code{mpz_add},
+without using a temporary for the @code{b+c} part.  Expressions which by their
+nature imply intermediate values, like @code{a=b*c+d*e}, still use temporaries
+though.
+
+The classes can be freely intermixed in expressions, as can the classes and
+the standard types @code{long}, @code{unsigned long} and @code{double}.
+Smaller types like @code{int} or @code{float} can also be intermixed, since
+C++ will promote them.
+
+Note that @code{bool} is not accepted directly, but must be explicitly cast to
+an @code{int} first.  This is because C++ will automatically convert any
+pointer to a @code{bool}, so if GMP accepted @code{bool} it would make all
+sorts of invalid class and pointer combinations compile but almost certainly
+not do anything sensible.
+
+Conversions back from the classes to standard C++ types aren't done
+automatically, instead member functions like @code{get_si} are provided (see
+the following sections for details).
+
+Also there are no automatic conversions from the classes to the corresponding
+GMP C types, instead a reference to the underlying C object can be obtained
+with the following functions,
+
+@deftypefun mpz_t mpz_class::get_mpz_t ()
+@deftypefunx mpq_t mpq_class::get_mpq_t ()
+@deftypefunx mpf_t mpf_class::get_mpf_t ()
+@end deftypefun
+
+These can be used to call a C function which doesn't have a C++ class
+interface.  For example to set @code{a} to the GCD of @code{b} and @code{c},
+
+@example
+mpz_class a, b, c;
+...
+mpz_gcd (a.get_mpz_t(), b.get_mpz_t(), c.get_mpz_t());
+@end example
+
+In the other direction, a class can be initialized from the corresponding GMP
+C type, or assigned to if an explicit constructor is used.  In both cases this
+makes a copy of the value, it doesn't create any sort of association.  For
+example,
+
+@example
+mpz_t z;
+// ... init and calculate z ...
+mpz_class x(z);
+mpz_class y;
+y = mpz_class (z);
+@end example
+
+There are no namespace setups in @file{gmpxx.h}, all types and functions are
+simply put into the global namespace.  This is what @file{gmp.h} has done in
+the past, and continues to do for compatibility.  The extras provided by
+@file{gmpxx.h} follow GMP naming conventions and are unlikely to clash with
+anything.
+
+
+@node C++ Interface Integers, C++ Interface Rationals, C++ Interface General, C++ Class Interface
+@section C++ Interface Integers
+
+@deftypefun {} mpz_class::mpz_class (type @var{n})
+Construct an @code{mpz_class}.  All the standard C++ types may be used, except
+@code{long long} and @code{long double}, and all the GMP C++ classes can be
+used, although conversions from @code{mpq_class} and @code{mpf_class} are
+@code{explicit}.  Any necessary conversion follows the corresponding C
+function, for example @code{double} follows @code{mpz_set_d}
+(@pxref{Assigning Integers}).
+@end deftypefun
+
+@deftypefun explicit mpz_class::mpz_class (const mpz_t @var{z})
+Construct an @code{mpz_class} from an @code{mpz_t}.  The value in @var{z} is
+copied into the new @code{mpz_class}, there won't be any permanent association
+between it and @var{z}.
+@end deftypefun
+
+@deftypefun explicit mpz_class::mpz_class (const char *@var{s}, int @var{base} = 0)
+@deftypefunx explicit mpz_class::mpz_class (const string& @var{s}, int @var{base} = 0)
+Construct an @code{mpz_class} converted from a string using @code{mpz_set_str}
+(@pxref{Assigning Integers}).
+
+If the string is not a valid integer, an @code{std::invalid_argument}
+exception is thrown.  The same applies to @code{operator=}.
+@end deftypefun
+
+@deftypefun mpz_class operator"" _mpz (const char *@var{str})
+With C++11 compilers, integers can be constructed with the syntax
+@code{123_mpz} which is equivalent to @code{mpz_class("123")}.
+@end deftypefun
+
+@deftypefun mpz_class operator/ (mpz_class @var{a}, mpz_class @var{d})
+@deftypefunx mpz_class operator% (mpz_class @var{a}, mpz_class @var{d})
+Divisions involving @code{mpz_class} round towards zero, as per the
+@code{mpz_tdiv_q} and @code{mpz_tdiv_r} functions (@pxref{Integer Division}).
+This is the same as the C99 @code{/} and @code{%} operators.
+
+The @code{mpz_fdiv@dots{}} or @code{mpz_cdiv@dots{}} functions can always be called
+directly if desired.  For example,
+
+@example
+mpz_class q, a, d;
+...
+mpz_fdiv_q (q.get_mpz_t(), a.get_mpz_t(), d.get_mpz_t());
+@end example
+@end deftypefun
+
+@deftypefun mpz_class abs (mpz_class @var{op})
+@deftypefunx int cmp (mpz_class @var{op1}, type @var{op2})
+@deftypefunx int cmp (type @var{op1}, mpz_class @var{op2})
+@maybepagebreak
+@deftypefunx bool mpz_class::fits_sint_p (void)
+@deftypefunx bool mpz_class::fits_slong_p (void)
+@deftypefunx bool mpz_class::fits_sshort_p (void)
+@maybepagebreak
+@deftypefunx bool mpz_class::fits_uint_p (void)
+@deftypefunx bool mpz_class::fits_ulong_p (void)
+@deftypefunx bool mpz_class::fits_ushort_p (void)
+@maybepagebreak
+@deftypefunx double mpz_class::get_d (void)
+@deftypefunx long mpz_class::get_si (void)
+@deftypefunx string mpz_class::get_str (int @var{base} = 10)
+@deftypefunx {unsigned long} mpz_class::get_ui (void)
+@maybepagebreak
+@deftypefunx int mpz_class::set_str (const char *@var{str}, int @var{base})
+@deftypefunx int mpz_class::set_str (const string& @var{str}, int @var{base})
+@deftypefunx int sgn (mpz_class @var{op})
+@deftypefunx mpz_class sqrt (mpz_class @var{op})
+@maybepagebreak
+@deftypefunx mpz_class gcd (mpz_class @var{op1}, mpz_class @var{op2})
+@deftypefunx mpz_class lcm (mpz_class @var{op1}, mpz_class @var{op2})
+@deftypefunx mpz_class mpz_class::factorial (type @var{op})
+@deftypefunx mpz_class factorial (mpz_class @var{op})
+@deftypefunx mpz_class mpz_class::primorial (type @var{op})
+@deftypefunx mpz_class primorial (mpz_class @var{op})
+@deftypefunx mpz_class mpz_class::fibonacci (type @var{op})
+@deftypefunx mpz_class fibonacci (mpz_class @var{op})
+@maybepagebreak
+@deftypefunx void mpz_class::swap (mpz_class& @var{op})
+@deftypefunx void swap (mpz_class& @var{op1}, mpz_class& @var{op2})
+These functions provide a C++ class interface to the corresponding GMP C
+routines.  Calling @code{factorial} or @code{primorial} on a negative number
+is undefined.
+
+@code{cmp} can be used with any of the classes or the standard C++ types,
+except @code{long long} and @code{long double}.
+@end deftypefun
+
+@sp 1
+Overloaded operators for combinations of @code{mpz_class} and @code{double}
+are provided for completeness, but it should be noted that if the given
+@code{double} is not an integer then the way any rounding is done is currently
+unspecified.  The rounding might take place at the start, in the middle, or at
+the end of the operation, and it might change in the future.
+
+Conversions between @code{mpz_class} and @code{double}, however, are defined
+to follow the corresponding C functions @code{mpz_get_d} and @code{mpz_set_d}.
+And comparisons are always made exactly, as per @code{mpz_cmp_d}.
+
+
+@node C++ Interface Rationals, C++ Interface Floats, C++ Interface Integers, C++ Class Interface
+@section C++ Interface Rationals
+
+In all the following constructors, if a fraction is given then it should be in
+canonical form, or if not then @code{mpq_class::canonicalize} called.
+
+@deftypefun {} mpq_class::mpq_class (type @var{op})
+@deftypefunx {} mpq_class::mpq_class (integer @var{num}, integer @var{den})
+Construct an @code{mpq_class}.  The initial value can be a single value of any
+type (conversion from @code{mpf_class} is @code{explicit}), or a pair of
+integers (@code{mpz_class} or standard C++ integer types) representing a
+fraction, except that @code{long long} and @code{long double} are not
+supported.  For example,
+
+@example
+mpq_class q (99);
+mpq_class q (1.75);
+mpq_class q (1, 3);
+@end example
+@end deftypefun
+
+@deftypefun explicit mpq_class::mpq_class (const mpq_t @var{q})
+Construct an @code{mpq_class} from an @code{mpq_t}.  The value in @var{q} is
+copied into the new @code{mpq_class}, there won't be any permanent association
+between it and @var{q}.
+@end deftypefun
+
+@deftypefun explicit mpq_class::mpq_class (const char *@var{s}, int @var{base} = 0)
+@deftypefunx explicit mpq_class::mpq_class (const string& @var{s}, int @var{base} = 0)
+Construct an @code{mpq_class} converted from a string using @code{mpq_set_str}
+(@pxref{Initializing Rationals}).
+
+If the string is not a valid rational, an @code{std::invalid_argument}
+exception is thrown.  The same applies to @code{operator=}.
+@end deftypefun
+
+@deftypefun mpq_class operator"" _mpq (const char *@var{str})
+With C++11 compilers, integral rationals can be constructed with the syntax
+@code{123_mpq} which is equivalent to @code{mpq_class(123_mpz)}. Other
+rationals can be built as @code{-1_mpq/2} or @code{0xb_mpq/123456_mpz}.
+@end deftypefun
+
+@deftypefun void mpq_class::canonicalize ()
+Put an @code{mpq_class} into canonical form, as per @ref{Rational Number
+Functions}.  All arithmetic operators require their operands in canonical
+form, and will return results in canonical form.
+@end deftypefun
+
+@deftypefun mpq_class abs (mpq_class @var{op})
+@deftypefunx int cmp (mpq_class @var{op1}, type @var{op2})
+@deftypefunx int cmp (type @var{op1}, mpq_class @var{op2})
+@maybepagebreak
+@deftypefunx double mpq_class::get_d (void)
+@deftypefunx string mpq_class::get_str (int @var{base} = 10)
+@maybepagebreak
+@deftypefunx int mpq_class::set_str (const char *@var{str}, int @var{base})
+@deftypefunx int mpq_class::set_str (const string& @var{str}, int @var{base})
+@deftypefunx int sgn (mpq_class @var{op})
+@maybepagebreak
+@deftypefunx void mpq_class::swap (mpq_class& @var{op})
+@deftypefunx void swap (mpq_class& @var{op1}, mpq_class& @var{op2})
+These functions provide a C++ class interface to the corresponding GMP C
+routines.
+
+@code{cmp} can be used with any of the classes or the standard C++ types,
+except @code{long long} and @code{long double}.
+@end deftypefun
+
+@deftypefun {mpz_class&} mpq_class::get_num ()
+@deftypefunx {mpz_class&} mpq_class::get_den ()
+Get a reference to an @code{mpz_class} which is the numerator or denominator
+of an @code{mpq_class}.  This can be used both for read and write access.  If
+the object returned is modified, it modifies the original @code{mpq_class}.
+
+If direct manipulation might produce a non-canonical value, then
+@code{mpq_class::canonicalize} must be called before further operations.
+@end deftypefun
+
+@deftypefun mpz_t mpq_class::get_num_mpz_t ()
+@deftypefunx mpz_t mpq_class::get_den_mpz_t ()
+Get a reference to the underlying @code{mpz_t} numerator or denominator of an
+@code{mpq_class}.  This can be passed to C functions expecting an
+@code{mpz_t}.  Any modifications made to the @code{mpz_t} will modify the
+original @code{mpq_class}.
+
+If direct manipulation might produce a non-canonical value, then
+@code{mpq_class::canonicalize} must be called before further operations.
+@end deftypefun
+
+@deftypefun istream& operator>> (istream& @var{stream}, mpq_class& @var{rop});
+Read @var{rop} from @var{stream}, using its @code{ios} formatting settings,
+the same as @code{mpq_t operator>>} (@pxref{C++ Formatted Input}).
+
+If the @var{rop} read might not be in canonical form then
+@code{mpq_class::canonicalize} must be called.
+@end deftypefun
+
+
+@node C++ Interface Floats, C++ Interface Random Numbers, C++ Interface Rationals, C++ Class Interface
+@section C++ Interface Floats
+
+When an expression requires the use of temporary intermediate @code{mpf_class}
+values, like @code{f=g*h+x*y}, those temporaries will have the same precision
+as the destination @code{f}.  Explicit constructors can be used if this
+doesn't suit.
+
+@deftypefun {} mpf_class::mpf_class (type @var{op})
+@deftypefunx {} mpf_class::mpf_class (type @var{op}, mp_bitcnt_t @var{prec})
+Construct an @code{mpf_class}.  Any standard C++ type can be used, except
+@code{long long} and @code{long double}, and any of the GMP C++ classes can be
+used.
+
+If @var{prec} is given, the initial precision is that value, in bits.  If
+@var{prec} is not given, then the initial precision is determined by the type
+of @var{op} given.  An @code{mpz_class}, @code{mpq_class}, or C++
+builtin type will give the default @code{mpf} precision (@pxref{Initializing
+Floats}).  An @code{mpf_class} or expression will give the precision of that
+value.  The precision of a binary expression is the higher of the two
+operands.
+
+@example
+mpf_class f(1.5);        // default precision
+mpf_class f(1.5, 500);   // 500 bits (at least)
+mpf_class f(x);          // precision of x
+mpf_class f(abs(x));     // precision of x
+mpf_class f(-g, 1000);   // 1000 bits (at least)
+mpf_class f(x+y);        // greater of precisions of x and y
+@end example
+@end deftypefun
+
+@deftypefun explicit mpf_class::mpf_class (const mpf_t @var{f})
+@deftypefunx {} mpf_class::mpf_class (const mpf_t @var{f}, mp_bitcnt_t @var{prec})
+Construct an @code{mpf_class} from an @code{mpf_t}.  The value in @var{f} is
+copied into the new @code{mpf_class}, there won't be any permanent association
+between it and @var{f}.
+
+If @var{prec} is given, the initial precision is that value, in bits.  If
+@var{prec} is not given, then the initial precision is that of @var{f}.
+@end deftypefun
+
+@deftypefun explicit mpf_class::mpf_class (const char *@var{s})
+@deftypefunx {} mpf_class::mpf_class (const char *@var{s}, mp_bitcnt_t @var{prec}, int @var{base} = 0)
+@deftypefunx explicit mpf_class::mpf_class (const string& @var{s})
+@deftypefunx {} mpf_class::mpf_class (const string& @var{s}, mp_bitcnt_t @var{prec}, int @var{base} = 0)
+Construct an @code{mpf_class} converted from a string using @code{mpf_set_str}
+(@pxref{Assigning Floats}).  If @var{prec} is given, the initial precision is
+that value, in bits.  If not, the default @code{mpf} precision
+(@pxref{Initializing Floats}) is used.
+
+If the string is not a valid float, an @code{std::invalid_argument} exception
+is thrown.  The same applies to @code{operator=}.
+@end deftypefun
+
+@deftypefun mpf_class operator"" _mpf (const char *@var{str})
+With C++11 compilers, floats can be constructed with the syntax
+@code{1.23e-1_mpf} which is equivalent to @code{mpf_class("1.23e-1")}.
+@end deftypefun
+
+@deftypefun {mpf_class&} mpf_class::operator= (type @var{op})
+Convert and store the given @var{op} value to an @code{mpf_class} object.  The
+same types are accepted as for the constructors above.
+
+Note that @code{operator=} only stores a new value, it doesn't copy or change
+the precision of the destination, instead the value is truncated if necessary.
+This is the same as @code{mpf_set} etc.  Note in particular this means for
+@code{mpf_class} a copy constructor is not the same as a default constructor
+plus assignment.
+
+@example
+mpf_class x (y);   // x created with precision of y
+
+mpf_class x;       // x created with default precision
+x = y;             // value truncated to that precision
+@end example
+
+Applications using templated code may need to be careful about the assumptions
+the code makes in this area, when working with @code{mpf_class} values of
+various different or non-default precisions.  For instance implementations of
+the standard @code{complex} template have been seen in both styles above,
+though of course @code{complex} is normally only actually specified for use
+with the builtin float types.
+@end deftypefun
+
+@deftypefun mpf_class abs (mpf_class @var{op})
+@deftypefunx mpf_class ceil (mpf_class @var{op})
+@deftypefunx int cmp (mpf_class @var{op1}, type @var{op2})
+@deftypefunx int cmp (type @var{op1}, mpf_class @var{op2})
+@maybepagebreak
+@deftypefunx bool mpf_class::fits_sint_p (void)
+@deftypefunx bool mpf_class::fits_slong_p (void)
+@deftypefunx bool mpf_class::fits_sshort_p (void)
+@maybepagebreak
+@deftypefunx bool mpf_class::fits_uint_p (void)
+@deftypefunx bool mpf_class::fits_ulong_p (void)
+@deftypefunx bool mpf_class::fits_ushort_p (void)
+@maybepagebreak
+@deftypefunx mpf_class floor (mpf_class @var{op})
+@deftypefunx mpf_class hypot (mpf_class @var{op1}, mpf_class @var{op2})
+@maybepagebreak
+@deftypefunx double mpf_class::get_d (void)
+@deftypefunx long mpf_class::get_si (void)
+@deftypefunx string mpf_class::get_str (mp_exp_t& @var{exp}, int @var{base} = 10, size_t @var{digits} = 0)
+@deftypefunx {unsigned long} mpf_class::get_ui (void)
+@maybepagebreak
+@deftypefunx int mpf_class::set_str (const char *@var{str}, int @var{base})
+@deftypefunx int mpf_class::set_str (const string& @var{str}, int @var{base})
+@deftypefunx int sgn (mpf_class @var{op})
+@deftypefunx mpf_class sqrt (mpf_class @var{op})
+@maybepagebreak
+@deftypefunx void mpf_class::swap (mpf_class& @var{op})
+@deftypefunx void swap (mpf_class& @var{op1}, mpf_class& @var{op2})
+@deftypefunx mpf_class trunc (mpf_class @var{op})
+These functions provide a C++ class interface to the corresponding GMP C
+routines.
+
+@code{cmp} can be used with any of the classes or the standard C++ types,
+except @code{long long} and @code{long double}.
+
+The accuracy provided by @code{hypot} is not currently guaranteed.
+@end deftypefun
+
+@deftypefun {mp_bitcnt_t} mpf_class::get_prec ()
+@deftypefunx void mpf_class::set_prec (mp_bitcnt_t @var{prec})
+@deftypefunx void mpf_class::set_prec_raw (mp_bitcnt_t @var{prec})
+Get or set the current precision of an @code{mpf_class}.
+
+The restrictions described for @code{mpf_set_prec_raw} (@pxref{Initializing
+Floats}) apply to @code{mpf_class::set_prec_raw}.  Note in particular that the
+@code{mpf_class} must be restored to it's allocated precision before being
+destroyed.  This must be done by application code, there's no automatic
+mechanism for it.
+@end deftypefun
+
+
+@node C++ Interface Random Numbers, C++ Interface Limitations, C++ Interface Floats, C++ Class Interface
+@section C++ Interface Random Numbers
+
+@deftp Class gmp_randclass
+The C++ class interface to the GMP random number functions uses
+@code{gmp_randclass} to hold an algorithm selection and current state, as per
+@code{gmp_randstate_t}.
+@end deftp
+
+@deftypefun {} gmp_randclass::gmp_randclass (void (*@var{randinit}) (gmp_randstate_t, @dots{}), @dots{})
+Construct a @code{gmp_randclass}, using a call to the given @var{randinit}
+function (@pxref{Random State Initialization}).  The arguments expected are
+the same as @var{randinit}, but with @code{mpz_class} instead of @code{mpz_t}.
+For example,
+
+@example
+gmp_randclass r1 (gmp_randinit_default);
+gmp_randclass r2 (gmp_randinit_lc_2exp_size, 32);
+gmp_randclass r3 (gmp_randinit_lc_2exp, a, c, m2exp);
+gmp_randclass r4 (gmp_randinit_mt);
+@end example
+
+@code{gmp_randinit_lc_2exp_size} will fail if the size requested is too big,
+an @code{std::length_error} exception is thrown in that case.
+@end deftypefun
+
+@deftypefun {} gmp_randclass::gmp_randclass (gmp_randalg_t @var{alg}, @dots{})
+Construct a @code{gmp_randclass} using the same parameters as
+@code{gmp_randinit} (@pxref{Random State Initialization}).  This function is
+obsolete and the above @var{randinit} style should be preferred.
+@end deftypefun
+
+@deftypefun void gmp_randclass::seed (unsigned long int @var{s})
+@deftypefunx void gmp_randclass::seed (mpz_class @var{s})
+Seed a random number generator.  See @pxref{Random Number Functions}, for how
+to choose a good seed.
+@end deftypefun
+
+@deftypefun mpz_class gmp_randclass::get_z_bits (mp_bitcnt_t @var{bits})
+@deftypefunx mpz_class gmp_randclass::get_z_bits (mpz_class @var{bits})
+Generate a random integer with a specified number of bits.
+@end deftypefun
+
+@deftypefun mpz_class gmp_randclass::get_z_range (mpz_class @var{n})
+Generate a random integer in the range 0 to @math{@var{n}-1} inclusive.
+@end deftypefun
+
+@deftypefun mpf_class gmp_randclass::get_f ()
+@deftypefunx mpf_class gmp_randclass::get_f (mp_bitcnt_t @var{prec})
+Generate a random float @var{f} in the range @math{0 <= @var{f} < 1}.  @var{f}
+will be to @var{prec} bits precision, or if @var{prec} is not given then to
+the precision of the destination.  For example,
+
+@example
+gmp_randclass  r;
+...
+mpf_class  f (0, 512);   // 512 bits precision
+f = r.get_f();           // random number, 512 bits
+@end example
+@end deftypefun
+
+
+
+@node C++ Interface Limitations,  , C++ Interface Random Numbers, C++ Class Interface
+@section C++ Interface Limitations
+
+@table @asis
+@item @code{mpq_class} and Templated Reading
+A generic piece of template code probably won't know that @code{mpq_class}
+requires a @code{canonicalize} call if inputs read with @code{operator>>}
+might be non-canonical.  This can lead to incorrect results.
+
+@code{operator>>} behaves as it does for reasons of efficiency.  A
+canonicalize can be quite time consuming on large operands, and is best
+avoided if it's not necessary.
+
+But this potential difficulty reduces the usefulness of @code{mpq_class}.
+Perhaps a mechanism to tell @code{operator>>} what to do will be adopted in
+the future, maybe a preprocessor define, a global flag, or an @code{ios} flag
+pressed into service.  Or maybe, at the risk of inconsistency, the
+@code{mpq_class} @code{operator>>} could canonicalize and leave @code{mpq_t}
+@code{operator>>} not doing so, for use on those occasions when that's
+acceptable.  Send feedback or alternate ideas to @email{gmp-bugs@@gmplib.org}.
+
+@item Subclassing
+Subclassing the GMP C++ classes works, but is not currently recommended.
+
+Expressions involving subclasses resolve correctly (or seem to), but in normal
+C++ fashion the subclass doesn't inherit constructors and assignments.
+There's many of those in the GMP classes, and a good way to reestablish them
+in a subclass is not yet provided.
+
+@item Templated Expressions
+A subtle difficulty exists when using expressions together with
+application-defined template functions.  Consider the following, with @code{T}
+intended to be some numeric type,
+
+@example
+template <class T>
+T fun (const T &, const T &);
+@end example
+
+@noindent
+When used with, say, plain @code{mpz_class} variables, it works fine: @code{T}
+is resolved as @code{mpz_class}.
+
+@example
+mpz_class f(1), g(2);
+fun (f, g);    // Good
+@end example
+
+@noindent
+But when one of the arguments is an expression, it doesn't work.
+
+@example
+mpz_class f(1), g(2), h(3);
+fun (f, g+h);  // Bad
+@end example
+
+This is because @code{g+h} ends up being a certain expression template type
+internal to @code{gmpxx.h}, which the C++ template resolution rules are unable
+to automatically convert to @code{mpz_class}.  The workaround is simply to add
+an explicit cast.
+
+@example
+mpz_class f(1), g(2), h(3);
+fun (f, mpz_class(g+h));  // Good
+@end example
+
+Similarly, within @code{fun} it may be necessary to cast an expression to type
+@code{T} when calling a templated @code{fun2}.
+
+@example
+template <class T>
+void fun (T f, T g)
+@{
+  fun2 (f, f+g);     // Bad
+@}
+
+template <class T>
+void fun (T f, T g)
+@{
+  fun2 (f, T(f+g));  // Good
+@}
+@end example
+
+@item C++11
+C++11 provides several new ways in which types can be inferred: @code{auto},
+@code{decltype}, etc. While they can be very convenient, they don't mix well
+with expression templates. In this example, the addition is performed twice,
+as if we had defined @code{sum} as a macro.
+
+@example
+mpz_class z = 33;
+auto sum = z + z;
+mpz_class prod = sum * sum;
+@end example
+
+This other example may crash, though some compilers might make it look like
+it is working, because the expression @code{z+z} goes out of scope before it
+is evaluated.
+
+@example
+mpz_class z = 33;
+auto sum = z + z + z;
+mpz_class prod = sum * 2;
+@end example
+
+It is thus strongly recommended to avoid @code{auto} anywhere a GMP C++
+expression may appear.
+@end table
+
+
+@node Custom Allocation, Language Bindings, C++ Class Interface, Top
+@comment  node-name,  next,  previous,  up
+@chapter Custom Allocation
+@cindex Custom allocation
+@cindex Memory allocation
+@cindex Allocation of memory
+
+By default GMP uses @code{malloc}, @code{realloc} and @code{free} for memory
+allocation, and if they fail GMP prints a message to the standard error output
+and terminates the program.
+
+Alternate functions can be specified, to allocate memory in a different way or
+to have a different error action on running out of memory.
+
+@deftypefun void mp_set_memory_functions (@* void *(*@var{alloc_func_ptr}) (size_t), @* void *(*@var{realloc_func_ptr}) (void *, size_t, size_t), @* void (*@var{free_func_ptr}) (void *, size_t))
+Replace the current allocation functions from the arguments.  If an argument
+is @code{NULL}, the corresponding default function is used.
+
+These functions will be used for all memory allocation done by GMP, apart from
+temporary space from @code{alloca} if that function is available and GMP is
+configured to use it (@pxref{Build Options}).
+
+@strong{Be sure to call @code{mp_set_memory_functions} only when there are no
+active GMP objects allocated using the previous memory functions!  Usually
+that means calling it before any other GMP function.}
+@end deftypefun
+
+The functions supplied should fit the following declarations:
+
+@deftypevr Function {void *} allocate_function (size_t @var{alloc_size})
+Return a pointer to newly allocated space with at least @var{alloc_size}
+bytes.
+@end deftypevr
+
+@deftypevr Function {void *} reallocate_function (void *@var{ptr}, size_t @var{old_size}, size_t @var{new_size})
+Resize a previously allocated block @var{ptr} of @var{old_size} bytes to be
+@var{new_size} bytes.
+
+The block may be moved if necessary or if desired, and in that case the
+smaller of @var{old_size} and @var{new_size} bytes must be copied to the new
+location.  The return value is a pointer to the resized block, that being the
+new location if moved or just @var{ptr} if not.
+
+@var{ptr} is never @code{NULL}, it's always a previously allocated block.
+@var{new_size} may be bigger or smaller than @var{old_size}.
+@end deftypevr
+
+@deftypevr Function void free_function (void *@var{ptr}, size_t @var{size})
+De-allocate the space pointed to by @var{ptr}.
+
+@var{ptr} is never @code{NULL}, it's always a previously allocated block of
+@var{size} bytes.
+@end deftypevr
+
+A @dfn{byte} here means the unit used by the @code{sizeof} operator.
+
+The @var{reallocate_function} parameter @var{old_size} and the
+@var{free_function} parameter @var{size} are passed for convenience, but of
+course they can be ignored if not needed by an implementation.  The default
+functions using @code{malloc} and friends for instance don't use them.
+
+No error return is allowed from any of these functions, if they return then
+they must have performed the specified operation.  In particular note that
+@var{allocate_function} or @var{reallocate_function} mustn't return
+@code{NULL}.
+
+Getting a different fatal error action is a good use for custom allocation
+functions, for example giving a graphical dialog rather than the default print
+to @code{stderr}.  How much is possible when genuinely out of memory is
+another question though.
+
+There's currently no defined way for the allocation functions to recover from
+an error such as out of memory, they must terminate program execution.  A
+@code{longjmp} or throwing a C++ exception will have undefined results.  This
+may change in the future.
+
+GMP may use allocated blocks to hold pointers to other allocated blocks.  This
+will limit the assumptions a conservative garbage collection scheme can make.
+
+Since the default GMP allocation uses @code{malloc} and friends, those
+functions will be linked in even if the first thing a program does is an
+@code{mp_set_memory_functions}.  It's necessary to change the GMP sources if
+this is a problem.
+
+@sp 1
+@deftypefun void mp_get_memory_functions (@* void *(**@var{alloc_func_ptr}) (size_t), @* void *(**@var{realloc_func_ptr}) (void *, size_t, size_t), @* void (**@var{free_func_ptr}) (void *, size_t))
+Get the current allocation functions, storing function pointers to the
+locations given by the arguments.  If an argument is @code{NULL}, that
+function pointer is not stored.
+
+@need 1000
+For example, to get just the current free function,
+
+@example
+void (*freefunc) (void *, size_t);
+
+mp_get_memory_functions (NULL, NULL, &freefunc);
+@end example
+@end deftypefun
+
+@node Language Bindings, Algorithms, Custom Allocation, Top
+@chapter Language Bindings
+@cindex Language bindings
+@cindex Other languages
+
+The following packages and projects offer access to GMP from languages other
+than C, though perhaps with varying levels of functionality and efficiency.
+
+@c  @spaceuref{U} is the same as @uref{U}, but with a couple of extra spaces
+@c  in tex, just to separate the URL from the preceding text a bit.
+@iftex
+@macro spaceuref {U}
+@ @ @uref{\U\}
+@end macro
+@end iftex
+@ifnottex
+@macro spaceuref {U}
+@uref{\U\}
+@end macro
+@end ifnottex
+
+@sp 1
+@table @asis
+@item C++
+@itemize @bullet
+@item
+GMP C++ class interface, @pxref{C++ Class Interface} @* Straightforward
+interface, expression templates to eliminate temporaries.
+@item
+ALP @spaceuref{https://www-sop.inria.fr/saga/logiciels/ALP/} @* Linear algebra and
+polynomials using templates.
+@item
+CLN @spaceuref{https://www.ginac.de/CLN/} @* High level classes for arithmetic.
+@item
+Linbox @spaceuref{http://www.linalg.org/} @* Sparse vectors and matrices.
+@item
+NTL @spaceuref{http://www.shoup.net/ntl/} @* A C++ number theory library.
+@end itemize
+
+@c @item D
+@c @itemize @bullet
+@c @item
+@c gmp-d @spaceuref{http://home.comcast.net/~benhinkle/gmp-d/}
+@c @end itemize
+
+@item Eiffel
+@itemize @bullet
+@item
+Eiffelroom @spaceuref{http://www.eiffelroom.org/node/442}
+@end itemize
+
+@c @item Fortran
+@c @itemize @bullet
+@c @item
+@c Omni F77 @spaceuref{http://phase.hpcc.jp/Omni/home.html} @* Arbitrary
+@c precision floats.
+@c @end itemize
+
+@item Haskell
+@itemize @bullet
+@item
+Glasgow Haskell Compiler @spaceuref{https://www.haskell.org/ghc/}
+@end itemize
+
+@item Java
+@itemize @bullet
+@item
+Kaffe @spaceuref{https://github.com/kaffe/kaffe}
+@end itemize
+
+@item Lisp
+@itemize @bullet
+@item
+GNU Common Lisp @spaceuref{https://www.gnu.org/software/gcl/gcl.html}
+@item
+Librep @spaceuref{http://librep.sourceforge.net/}
+@item
+@c  FIXME: When there's a stable release with gmp support, just refer to it
+@c  rather than bothering to talk about betas.
+XEmacs (21.5.18 beta and up) @spaceuref{https://www.xemacs.org} @* Optional
+big integers, rationals and floats using GMP.
+@end itemize
+
+@item ML
+@itemize @bullet
+@item
+MLton compiler @spaceuref{http://mlton.org/}
+@end itemize
+
+@item Objective Caml
+@itemize @bullet
+@item
+MLGMP @spaceuref{https://opam.ocaml.org/packages/mlgmp/}
+@item
+Numerix @spaceuref{http://pauillac.inria.fr/~quercia/} @* Optionally using
+GMP.
+@end itemize
+
+@item Oz
+@itemize @bullet
+@item
+Mozart @spaceuref{https://mozart.github.io/}
+@end itemize
+
+@item Pascal
+@itemize @bullet
+@item
+GNU Pascal Compiler @spaceuref{http://www.gnu-pascal.de/} @* GMP unit.
+@item
+Numerix @spaceuref{http://pauillac.inria.fr/~quercia/} @* For Free Pascal,
+optionally using GMP.
+@end itemize
+
+@item Perl
+@itemize @bullet
+@item
+GMP module, see @file{demos/perl} in the GMP sources (@pxref{Demonstration
+Programs}).
+@item
+Math::GMP @spaceuref{https://www.cpan.org/} @* Compatible with Math::BigInt, but
+not as many functions as the GMP module above.
+@item
+Math::BigInt::GMP @spaceuref{https://www.cpan.org/} @* Plug Math::GMP into
+normal Math::BigInt operations.
+@end itemize
+
+@need 1000
+@item Pike
+@itemize @bullet
+@item
+pikempz module in the standard distribution, @uref{https://pike.lysator.liu.se/}
+@end itemize
+
+@need 500
+@item Prolog
+@itemize @bullet
+@item
+SWI Prolog @spaceuref{http://www.swi-prolog.org/} @*
+Arbitrary precision floats.
+@end itemize
+
+@item Python
+@itemize @bullet
+@item
+GMPY @uref{https://code.google.com/p/gmpy/}
+@end itemize
+
+@item Ruby
+@itemize @bullet
+@item
+@uref{https://rubygems.org/gems/gmp}
+@end itemize
+
+@item Scheme
+@itemize @bullet
+@item
+GNU Guile @spaceuref{https://www.gnu.org/software/guile/guile.html}
+@item
+RScheme @spaceuref{https://www.rscheme.org/}
+@item
+STklos @spaceuref{http://www.stklos.net/}
+@c
+@c  For reference, MzScheme uses some of gmp, but (as of version 205) it only
+@c  has copies of some of the generic C code, and we don't consider that a
+@c  language binding to gmp.
+@c
+@end itemize
+
+@item Smalltalk
+@itemize @bullet
+@item
+GNU Smalltalk @spaceuref{http://smalltalk.gnu.org/}
+@end itemize
+
+@item Other
+@itemize @bullet
+@item
+Axiom @uref{https://savannah.nongnu.org/projects/axiom} @* Computer algebra
+using GCL.
+@item
+DrGenius @spaceuref{http://drgenius.seul.org/} @* Geometry system and
+mathematical programming language.
+@item
+GiNaC @spaceuref{httsp://www.ginac.de/} @* C++ computer algebra using CLN.
+@item
+GOO @spaceuref{https://www.eecs.berkeley.edu/~jrb/goo/} @* Dynamic object oriented
+language.
+@item
+Maxima @uref{https://www.ma.utexas.edu/users/wfs/maxima.html} @* Macsyma
+computer algebra using GCL.
+@c @item
+@c Q @spaceuref{http://q-lang.sourceforge.net/} @* Equational programming system.
+@item
+Regina @spaceuref{http://regina.sourceforge.net/} @* Topological calculator.
+@item
+Yacas @spaceuref{http://yacas.sourceforge.net} @* Yet another computer algebra system.
+@end itemize
+
+@end table
+
+
+@node Algorithms, Internals, Language Bindings, Top
+@chapter Algorithms
+@cindex Algorithms
+
+This chapter is an introduction to some of the algorithms used for various GMP
+operations.  The code is likely to be hard to understand without knowing
+something about the algorithms.
+
+Some GMP internals are mentioned, but applications that expect to be
+compatible with future GMP releases should take care to use only the
+documented functions.
+
+@menu
+* Multiplication Algorithms::
+* Division Algorithms::
+* Greatest Common Divisor Algorithms::
+* Powering Algorithms::
+* Root Extraction Algorithms::
+* Radix Conversion Algorithms::
+* Other Algorithms::
+* Assembly Coding::
+@end menu
+
+
+@node Multiplication Algorithms, Division Algorithms, Algorithms, Algorithms
+@section Multiplication
+@cindex Multiplication algorithms
+
+N@cross{}N limb multiplications and squares are done using one of seven
+algorithms, as the size N increases.
+
+@quotation
+@multitable {KaratsubaMMM} {MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM}
+@item Algorithm @tab Threshold
+@item Basecase  @tab (none)
+@item Karatsuba @tab @code{MUL_TOOM22_THRESHOLD}
+@item Toom-3    @tab @code{MUL_TOOM33_THRESHOLD}
+@item Toom-4    @tab @code{MUL_TOOM44_THRESHOLD}
+@item Toom-6.5  @tab @code{MUL_TOOM6H_THRESHOLD}
+@item Toom-8.5  @tab @code{MUL_TOOM8H_THRESHOLD}
+@item FFT       @tab @code{MUL_FFT_THRESHOLD}
+@end multitable
+@end quotation
+
+Similarly for squaring, with the @code{SQR} thresholds.
+
+N@cross{}M multiplications of operands with different sizes above
+@code{MUL_TOOM22_THRESHOLD} are currently done by special Toom-inspired
+algorithms or directly with FFT, depending on operand size (@pxref{Unbalanced
+Multiplication}).
+
+@menu
+* Basecase Multiplication::
+* Karatsuba Multiplication::
+* Toom 3-Way Multiplication::
+* Toom 4-Way Multiplication::
+* Higher degree Toom'n'half::
+* FFT Multiplication::
+* Other Multiplication::
+* Unbalanced Multiplication::
+@end menu
+
+
+@node Basecase Multiplication, Karatsuba Multiplication, Multiplication Algorithms, Multiplication Algorithms
+@subsection Basecase Multiplication
+
+Basecase N@cross{}M multiplication is a straightforward rectangular set of
+cross-products, the same as long multiplication done by hand and for that
+reason sometimes known as the schoolbook or grammar school method.  This is an
+@m{O(NM),O(N*M)} algorithm.  See Knuth section 4.3.1 algorithm M
+(@pxref{References}), and the @file{mpn/generic/mul_basecase.c} code.
+
+Assembly implementations of @code{mpn_mul_basecase} are essentially the same
+as the generic C code, but have all the usual assembly tricks and
+obscurities introduced for speed.
+
+A square can be done in roughly half the time of a multiply, by using the fact
+that the cross products above and below the diagonal are the same.  A triangle
+of products below the diagonal is formed, doubled (left shift by one bit), and
+then the products on the diagonal added.  This can be seen in
+@file{mpn/generic/sqr_basecase.c}.  Again the assembly implementations take
+essentially the same approach.
+
+@tex
+\def\GMPline#1#2#3#4#5#6{%
+  \hbox {%
+    \vrule height 2.5ex depth 1ex
+           \hbox to 2em {\hfil{#2}\hfil}%
+    \vrule \hbox to 2em {\hfil{#3}\hfil}%
+    \vrule \hbox to 2em {\hfil{#4}\hfil}%
+    \vrule \hbox to 2em {\hfil{#5}\hfil}%
+    \vrule \hbox to 2em {\hfil{#6}\hfil}%
+    \vrule}}
+\GMPdisplay{
+  \hbox{%
+    \vbox{%
+      \hbox to 1.5em {\vrule height 2.5ex depth 1ex width 0pt}%
+      \hbox {\vrule height 2.5ex depth 1ex width 0pt u0\hfil}%
+      \hbox {\vrule height 2.5ex depth 1ex width 0pt u1\hfil}%
+      \hbox {\vrule height 2.5ex depth 1ex width 0pt u2\hfil}%
+      \hbox {\vrule height 2.5ex depth 1ex width 0pt u3\hfil}%
+      \hbox {\vrule height 2.5ex depth 1ex width 0pt u4\hfil}%
+      \vfill}%
+    \vbox{%
+      \hbox{%
+        \hbox to 2em {\hfil u0\hfil}%
+        \hbox to 2em {\hfil u1\hfil}%
+        \hbox to 2em {\hfil u2\hfil}%
+        \hbox to 2em {\hfil u3\hfil}%
+        \hbox to 2em {\hfil u4\hfil}}%
+      \vskip 0.7ex
+      \hrule
+      \GMPline{u0}{d}{}{}{}{}%
+      \hrule
+      \GMPline{u1}{}{d}{}{}{}%
+      \hrule
+      \GMPline{u2}{}{}{d}{}{}%
+      \hrule
+      \GMPline{u3}{}{}{}{d}{}%
+      \hrule
+      \GMPline{u4}{}{}{}{}{d}%
+      \hrule}}}
+@end tex
+@ifnottex
+@example
+@group
+     u0  u1  u2  u3  u4
+   +---+---+---+---+---+
+u0 | d |   |   |   |   |
+   +---+---+---+---+---+
+u1 |   | d |   |   |   |
+   +---+---+---+---+---+
+u2 |   |   | d |   |   |
+   +---+---+---+---+---+
+u3 |   |   |   | d |   |
+   +---+---+---+---+---+
+u4 |   |   |   |   | d |
+   +---+---+---+---+---+
+@end group
+@end example
+@end ifnottex
+
+In practice squaring isn't a full 2@cross{} faster than multiplying, it's
+usually around 1.5@cross{}.  Less than 1.5@cross{} probably indicates
+@code{mpn_sqr_basecase} wants improving on that CPU.
+
+On some CPUs @code{mpn_mul_basecase} can be faster than the generic C
+@code{mpn_sqr_basecase} on some small sizes.  @code{SQR_BASECASE_THRESHOLD} is
+the size at which to use @code{mpn_sqr_basecase}, this will be zero if that
+routine should be used always.
+
+
+@node Karatsuba Multiplication, Toom 3-Way Multiplication, Basecase Multiplication, Multiplication Algorithms
+@subsection Karatsuba Multiplication
+@cindex Karatsuba multiplication
+
+The Karatsuba multiplication algorithm is described in Knuth section 4.3.3
+part A, and various other textbooks.  A brief description is given here.
+
+The inputs @math{x} and @math{y} are treated as each split into two parts of
+equal length (or the most significant part one limb shorter if N is odd).
+
+@tex
+% GMPboxwidth used for all the multiplication pictures
+\global\newdimen\GMPboxwidth \global\GMPboxwidth=5em
+% GMPboxdepth and GMPboxheight are also used for the float pictures
+\global\newdimen\GMPboxdepth  \global\GMPboxdepth=1ex
+\global\newdimen\GMPboxheight \global\GMPboxheight=2ex
+\gdef\GMPvrule{\vrule height \GMPboxheight depth \GMPboxdepth}
+\def\GMPbox#1#2{%
+  \vbox {%
+    \hrule
+    \hbox to 2\GMPboxwidth{%
+      \GMPvrule \hfil $#1$\hfil \vrule \hfil $#2$\hfil \vrule}%
+    \hrule}}
+\GMPdisplay{%
+\vbox{%
+  \hbox to 2\GMPboxwidth {high \hfil low}
+  \vskip 0.7ex
+  \GMPbox{x_1}{x_0}
+  \vskip 0.5ex
+  \GMPbox{y_1}{y_0}
+}}
+@end tex
+@ifnottex
+@example
+@group
+ high              low
++----------+----------+
+|    x1    |    x0    |
++----------+----------+
+
++----------+----------+
+|    y1    |    y0    |
++----------+----------+
+@end group
+@end example
+@end ifnottex
+
+Let @math{b} be the power of 2 where the split occurs, i.e.@: if @ms{x,0} is
+@math{k} limbs (@ms{y,0} the same) then
+@m{b=2\GMPraise{$k*$@code{mp\_bits\_per\_limb}}, b=2^(k*mp_bits_per_limb)}.
+With that @m{x=x_1b+x_0,x=x1*b+x0} and @m{y=y_1b+y_0,y=y1*b+y0}, and the
+following holds,
+
+@display
+@m{xy = (b^2+b)x_1y_1 - b(x_1-x_0)(y_1-y_0) + (b+1)x_0y_0,
+  x*y = (b^2+b)*x1*y1 - b*(x1-x0)*(y1-y0) + (b+1)*x0*y0}
+@end display
+
+This formula means doing only three multiplies of (N/2)@cross{}(N/2) limbs,
+whereas a basecase multiply of N@cross{}N limbs is equivalent to four
+multiplies of (N/2)@cross{}(N/2).  The factors @math{(b^2+b)} etc represent
+the positions where the three products must be added.
+
+@tex
+\def\GMPboxA#1#2{%
+  \vbox{%
+    \hrule
+    \hbox{%
+      \GMPvrule
+      \hbox to 2\GMPboxwidth {\hfil\hbox{$#1$}\hfil}%
+      \vrule
+      \hbox to 2\GMPboxwidth {\hfil\hbox{$#2$}\hfil}%
+      \vrule}
+    \hrule}}
+\def\GMPboxB#1#2{%
+  \hbox{%
+    \raise \GMPboxdepth \hbox to \GMPboxwidth {\hfil #1\hskip 0.5em}%
+    \vbox{%
+      \hrule
+      \hbox{%
+        \GMPvrule
+        \hbox to 2\GMPboxwidth {\hfil\hbox{$#2$}\hfil}%
+        \vrule}%
+      \hrule}}}
+\GMPdisplay{%
+\vbox{%
+  \hbox to 4\GMPboxwidth {high \hfil low}
+  \vskip 0.7ex
+  \GMPboxA{x_1y_1}{x_0y_0}
+  \vskip 0.5ex
+  \GMPboxB{$+$}{x_1y_1}
+  \vskip 0.5ex
+  \GMPboxB{$+$}{x_0y_0}
+  \vskip 0.5ex
+  \GMPboxB{$-$}{(x_1-x_0)(y_1-y_0)}
+}}
+@end tex
+@ifnottex
+@example
+@group
+ high                              low
++--------+--------+ +--------+--------+
+|      x1*y1      | |      x0*y0      |
++--------+--------+ +--------+--------+
+          +--------+--------+
+      add |      x1*y1      |
+          +--------+--------+
+          +--------+--------+
+      add |      x0*y0      |
+          +--------+--------+
+          +--------+--------+
+      sub | (x1-x0)*(y1-y0) |
+          +--------+--------+
+@end group
+@end example
+@end ifnottex
+
+The term @m{(x_1-x_0)(y_1-y_0),(x1-x0)*(y1-y0)} is best calculated as an
+absolute value, and the sign used to choose to add or subtract.  Notice the
+sum @m{\mathop{\rm high}(x_0y_0)+\mathop{\rm low}(x_1y_1),
+high(x0*y0)+low(x1*y1)} occurs twice, so it's possible to do @m{5k,5*k} limb
+additions, rather than @m{6k,6*k}, but in GMP extra function call overheads
+outweigh the saving.
+
+Squaring is similar to multiplying, but with @math{x=y} the formula reduces to
+an equivalent with three squares,
+
+@display
+@m{x^2 = (b^2+b)x_1^2 - b(x_1-x_0)^2 + (b+1)x_0^2,
+   x^2 = (b^2+b)*x1^2 - b*(x1-x0)^2 + (b+1)*x0^2}
+@end display
+
+The final result is accumulated from those three squares the same way as for
+the three multiplies above.  The middle term @m{(x_1-x_0)^2,(x1-x0)^2} is now
+always positive.
+
+A similar formula for both multiplying and squaring can be constructed with a
+middle term @m{(x_1+x_0)(y_1+y_0),(x1+x0)*(y1+y0)}.  But those sums can exceed
+@math{k} limbs, leading to more carry handling and additions than the form
+above.
+
+Karatsuba multiplication is asymptotically an @math{O(N^@W{1.585})} algorithm,
+the exponent being @m{\log3/\log2,log(3)/log(2)}, representing 3 multiplies
+each @math{1/2} the size of the inputs.  This is a big improvement over the
+basecase multiply at @math{O(N^2)} and the advantage soon overcomes the extra
+additions Karatsuba performs.  @code{MUL_TOOM22_THRESHOLD} can be as little
+as 10 limbs.  The @code{SQR} threshold is usually about twice the @code{MUL}.
+
+The basecase algorithm will take a time of the form @m{M(N) = aN^2 + bN + c,
+M(N) = a*N^2 + b*N + c} and the Karatsuba algorithm @m{K(N) = 3M(N/2) + dN +
+e, K(N) = 3*M(N/2) + d*N + e}, which expands to @m{K(N) = {3\over4} aN^2 +
+{3\over2} bN + 3c + dN + e, K(N) = 3/4*a*N^2 + 3/2*b*N + 3*c + d*N + e}.  The
+factor @m{3\over4, 3/4} for @math{a} means per-crossproduct speedups in the
+basecase code will increase the threshold since they benefit @math{M(N)} more
+than @math{K(N)}.  And conversely the @m{3\over2, 3/2} for @math{b} means
+linear style speedups of @math{b} will increase the threshold since they
+benefit @math{K(N)} more than @math{M(N)}.  The latter can be seen for
+instance when adding an optimized @code{mpn_sqr_diagonal} to
+@code{mpn_sqr_basecase}.  Of course all speedups reduce total time, and in
+that sense the algorithm thresholds are merely of academic interest.
+
+
+@node Toom 3-Way Multiplication, Toom 4-Way Multiplication, Karatsuba Multiplication, Multiplication Algorithms
+@subsection Toom 3-Way Multiplication
+@cindex Toom multiplication
+
+The Karatsuba formula is the simplest case of a general approach to splitting
+inputs that leads to both Toom and FFT algorithms.  A description of
+Toom can be found in Knuth section 4.3.3, with an example 3-way
+calculation after Theorem A@.  The 3-way form used in GMP is described here.
+
+The operands are each considered split into 3 pieces of equal length (or the
+most significant part 1 or 2 limbs shorter than the other two).
+
+@tex
+\def\GMPbox#1#2#3{%
+  \vbox{%
+    \hrule \vfil
+    \hbox to 3\GMPboxwidth {%
+      \GMPvrule
+      \hfil$#1$\hfil
+      \vrule
+      \hfil$#2$\hfil
+      \vrule
+      \hfil$#3$\hfil
+      \vrule}%
+    \vfil \hrule
+}}
+\GMPdisplay{%
+\vbox{%
+  \hbox to 3\GMPboxwidth {high \hfil low}
+  \vskip 0.7ex
+  \GMPbox{x_2}{x_1}{x_0}
+  \vskip 0.5ex
+  \GMPbox{y_2}{y_1}{y_0}
+  \vskip 0.5ex
+}}
+@end tex
+@ifnottex
+@example
+@group
+ high                         low
++----------+----------+----------+
+|    x2    |    x1    |    x0    |
++----------+----------+----------+
+
++----------+----------+----------+
+|    y2    |    y1    |    y0    |
++----------+----------+----------+
+@end group
+@end example
+@end ifnottex
+
+@noindent
+These parts are treated as the coefficients of two polynomials
+
+@display
+@group
+@m{X(t) = x_2t^2 + x_1t + x_0,
+   X(t) = x2*t^2 + x1*t + x0}
+@m{Y(t) = y_2t^2 + y_1t + y_0,
+   Y(t) = y2*t^2 + y1*t + y0}
+@end group
+@end display
+
+Let @math{b} equal the power of 2 which is the size of the @ms{x,0}, @ms{x,1},
+@ms{y,0} and @ms{y,1} pieces, i.e.@: if they're @math{k} limbs each then
+@m{b=2\GMPraise{$k*$@code{mp\_bits\_per\_limb}}, b=2^(k*mp_bits_per_limb)}.
+With this @math{x=X(b)} and @math{y=Y(b)}.
+
+Let a polynomial @m{W(t)=X(t)Y(t),W(t)=X(t)*Y(t)} and suppose its coefficients
+are
+
+@display
+@m{W(t) = w_4t^4 + w_3t^3 + w_2t^2 + w_1t + w_0,
+   W(t) = w4*t^4 + w3*t^3 + w2*t^2 + w1*t + w0}
+@end display
+
+The @m{w_i,w[i]} are going to be determined, and when they are they'll give
+the final result using @math{w=W(b)}, since
+@m{xy=X(b)Y(b),x*y=X(b)*Y(b)=W(b)}.  The coefficients will be roughly
+@math{b^2} each, and the final @math{W(b)} will be an addition like,
+
+@tex
+\def\GMPbox#1#2{%
+  \moveright #1\GMPboxwidth
+  \vbox{%
+    \hrule
+    \hbox{%
+      \GMPvrule
+      \hbox to 2\GMPboxwidth {\hfil$#2$\hfil}%
+      \vrule}%
+    \hrule
+}}
+\GMPdisplay{%
+\vbox{%
+  \hbox to 6\GMPboxwidth {high \hfil low}%
+  \vskip 0.7ex
+  \GMPbox{0}{w_4}
+  \vskip 0.5ex
+  \GMPbox{1}{w_3}
+  \vskip 0.5ex
+  \GMPbox{2}{w_2}
+  \vskip 0.5ex
+  \GMPbox{3}{w_1}
+  \vskip 0.5ex
+  \GMPbox{4}{w_0}
+}}
+@end tex
+@ifnottex
+@example
+@group
+ high                                        low
++-------+-------+
+|       w4      |
++-------+-------+
+       +--------+-------+
+       |        w3      |
+       +--------+-------+
+               +--------+-------+
+               |        w2      |
+               +--------+-------+
+                       +--------+-------+
+                       |        w1      |
+                       +--------+-------+
+                                +-------+-------+
+                                |       w0      |
+                                +-------+-------+
+@end group
+@end example
+@end ifnottex
+
+The @m{w_i,w[i]} coefficients could be formed by a simple set of cross
+products, like @m{w_4=x_2y_2,w4=x2*y2}, @m{w_3=x_2y_1+x_1y_2,w3=x2*y1+x1*y2},
+@m{w_2=x_2y_0+x_1y_1+x_0y_2,w2=x2*y0+x1*y1+x0*y2} etc, but this would need all
+nine @m{x_iy_j,x[i]*y[j]} for @math{i,j=0,1,2}, and would be equivalent merely
+to a basecase multiply.  Instead the following approach is used.
+
+@math{X(t)} and @math{Y(t)} are evaluated and multiplied at 5 points, giving
+values of @math{W(t)} at those points.  In GMP the following points are used,
+
+@quotation
+@multitable {@m{t=\infty,t=inf}M} {MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM}
+@item Point                 @tab Value
+@item @math{t=0}            @tab @m{x_0y_0,x0 * y0}, which gives @ms{w,0} immediately
+@item @math{t=1}            @tab @m{(x_2+x_1+x_0)(y_2+y_1+y_0),(x2+x1+x0) * (y2+y1+y0)}
+@item @math{t=-1}           @tab @m{(x_2-x_1+x_0)(y_2-y_1+y_0),(x2-x1+x0) * (y2-y1+y0)}
+@item @math{t=2}            @tab @m{(4x_2+2x_1+x_0)(4y_2+2y_1+y_0),(4*x2+2*x1+x0) * (4*y2+2*y1+y0)}
+@item @m{t=\infty,t=inf}    @tab @m{x_2y_2,x2 * y2}, which gives @ms{w,4} immediately
+@end multitable
+@end quotation
+
+At @math{t=-1} the values can be negative and that's handled using the
+absolute values and tracking the sign separately.  At @m{t=\infty,t=inf} the
+value is actually @m{\lim_{t\to\infty} {X(t)Y(t)\over t^4}, X(t)*Y(t)/t^4 in
+the limit as t approaches infinity}, but it's much easier to think of as
+simply @m{x_2y_2,x2*y2} giving @ms{w,4} immediately (much like
+@m{x_0y_0,x0*y0} at @math{t=0} gives @ms{w,0} immediately).
+
+Each of the points substituted into
+@m{W(t)=w_4t^4+\cdots+w_0,W(t)=w4*t^4+@dots{}+w0} gives a linear combination
+of the @m{w_i,w[i]} coefficients, and the value of those combinations has just
+been calculated.
+
+@tex
+\GMPdisplay{%
+$\matrix{%
+W(0)      & = &       &   &      &   &      &   &      &   & w_0 \cr
+W(1)      & = &   w_4 & + &  w_3 & + &  w_2 & + &  w_1 & + & w_0 \cr
+W(-1)     & = &   w_4 & - &  w_3 & + &  w_2 & - &  w_1 & + & w_0 \cr
+W(2)      & = & 16w_4 & + & 8w_3 & + & 4w_2 & + & 2w_1 & + & w_0 \cr
+W(\infty) & = &   w_4 \cr
+}$}
+@end tex
+@ifnottex
+@example
+@group
+W(0)   =                              w0
+W(1)   =    w4 +   w3 +   w2 +   w1 + w0
+W(-1)  =    w4 -   w3 +   w2 -   w1 + w0
+W(2)   = 16*w4 + 8*w3 + 4*w2 + 2*w1 + w0
+W(inf) =    w4
+@end group
+@end example
+@end ifnottex
+
+This is a set of five equations in five unknowns, and some elementary linear
+algebra quickly isolates each @m{w_i,w[i]}.  This involves adding or
+subtracting one @math{W(t)} value from another, and a couple of divisions by
+powers of 2 and one division by 3, the latter using the special
+@code{mpn_divexact_by3} (@pxref{Exact Division}).
+
+The conversion of @math{W(t)} values to the coefficients is interpolation.  A
+polynomial of degree 4 like @math{W(t)} is uniquely determined by values known
+at 5 different points.  The points are arbitrary and can be chosen to make the
+linear equations come out with a convenient set of steps for quickly isolating
+the @m{w_i,w[i]}.
+
+Squaring follows the same procedure as multiplication, but there's only one
+@math{X(t)} and it's evaluated at the 5 points, and those values squared to
+give values of @math{W(t)}.  The interpolation is then identical, and in fact
+the same @code{toom_interpolate_5pts} subroutine is used for both squaring and
+multiplying.
+
+Toom-3 is asymptotically @math{O(N^@W{1.465})}, the exponent being
+@m{\log5/\log3,log(5)/log(3)}, representing 5 recursive multiplies of 1/3 the
+original size each.  This is an improvement over Karatsuba at
+@math{O(N^@W{1.585})}, though Toom does more work in the evaluation and
+interpolation and so it only realizes its advantage above a certain size.
+
+Near the crossover between Toom-3 and Karatsuba there's generally a range of
+sizes where the difference between the two is small.
+@code{MUL_TOOM33_THRESHOLD} is a somewhat arbitrary point in that range and
+successive runs of the tune program can give different values due to small
+variations in measuring.  A graph of time versus size for the two shows the
+effect, see @file{tune/README}.
+
+At the fairly small sizes where the Toom-3 thresholds occur it's worth
+remembering that the asymptotic behaviour for Karatsuba and Toom-3 can't be
+expected to make accurate predictions, due of course to the big influence of
+all sorts of overheads, and the fact that only a few recursions of each are
+being performed.  Even at large sizes there's a good chance machine dependent
+effects like cache architecture will mean actual performance deviates from
+what might be predicted.
+
+The formula given for the Karatsuba algorithm (@pxref{Karatsuba
+Multiplication}) has an equivalent for Toom-3 involving only five multiplies,
+but this would be complicated and unenlightening.
+
+An alternate view of Toom-3 can be found in Zuras (@pxref{References}), using
+a vector to represent the @math{x} and @math{y} splits and a matrix
+multiplication for the evaluation and interpolation stages.  The matrix
+inverses are not meant to be actually used, and they have elements with values
+much greater than in fact arise in the interpolation steps.  The diagram shown
+for the 3-way is attractive, but again doesn't have to be implemented that way
+and for example with a bit of rearrangement just one division by 6 can be
+done.
+
+
+@node Toom 4-Way Multiplication, Higher degree Toom'n'half, Toom 3-Way Multiplication, Multiplication Algorithms
+@subsection Toom 4-Way Multiplication
+@cindex Toom multiplication
+
+Karatsuba and Toom-3 split the operands into 2 and 3 coefficients,
+respectively.  Toom-4 analogously splits the operands into 4 coefficients.
+Using the notation from the section on Toom-3 multiplication, we form two
+polynomials:
+
+@display
+@group
+@m{X(t) = x_3t^3 + x_2t^2 + x_1t + x_0,
+   X(t) = x3*t^3 + x2*t^2 + x1*t + x0}
+@m{Y(t) = y_3t^3 + y_2t^2 + y_1t + y_0,
+   Y(t) = y3*t^3 + y2*t^2 + y1*t + y0}
+@end group
+@end display
+
+@math{X(t)} and @math{Y(t)} are evaluated and multiplied at 7 points, giving
+values of @math{W(t)} at those points.  In GMP the following points are used,
+
+@quotation
+@multitable {@m{t=-1/2,t=inf}M} {MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM}
+@item Point              @tab Value
+@item @math{t=0}         @tab @m{x_0y_0,x0 * y0}, which gives @ms{w,0} immediately
+@item @math{t=1/2}       @tab @m{(x_3+2x_2+4x_1+8x_0)(y_3+2y_2+4y_1+8y_0),(x3+2*x2+4*x1+8*x0) * (y3+2*y2+4*y1+8*y0)}
+@item @math{t=-1/2}      @tab @m{(-x_3+2x_2-4x_1+8x_0)(-y_3+2y_2-4y_1+8y_0),(-x3+2*x2-4*x1+8*x0) * (-y3+2*y2-4*y1+8*y0)}
+@item @math{t=1}         @tab @m{(x_3+x_2+x_1+x_0)(y_3+y_2+y_1+y_0),(x3+x2+x1+x0) * (y3+y2+y1+y0)}
+@item @math{t=-1}        @tab @m{(-x_3+x_2-x_1+x_0)(-y_3+y_2-y_1+y_0),(-x3+x2-x1+x0) * (-y3+y2-y1+y0)}
+@item @math{t=2}         @tab @m{(8x_3+4x_2+2x_1+x_0)(8y_3+4y_2+2y_1+y_0),(8*x3+4*x2+2*x1+x0) * (8*y3+4*y2+2*y1+y0)}
+@item @m{t=\infty,t=inf} @tab @m{x_3y_3,x3 * y3}, which gives @ms{w,6} immediately
+@end multitable
+@end quotation
+
+The number of additions and subtractions for Toom-4 is much larger than for Toom-3.
+But several subexpressions occur multiple times, for example @m{x_2+x_0,x2+x0}, occurs
+for both @math{t=1} and @math{t=-1}.
+
+Toom-4 is asymptotically @math{O(N^@W{1.404})}, the exponent being
+@m{\log7/\log4,log(7)/log(4)}, representing 7 recursive multiplies of 1/4 the
+original size each.
+
+
+@node Higher degree Toom'n'half, FFT Multiplication, Toom 4-Way Multiplication, Multiplication Algorithms
+@subsection Higher degree Toom'n'half
+@cindex Toom multiplication
+
+The Toom algorithms described above (@pxref{Toom 3-Way Multiplication},
+@pxref{Toom 4-Way Multiplication}) generalizes to split into an arbitrary
+number of pieces. In general a split of two equally long operands into
+@math{r} pieces leads to evaluations and pointwise multiplications done at
+@m{2r-1,2*r-1} points. To fully exploit symmetries it would be better to have
+a multiple of 4 points, that's why for higher degree Toom'n'half is used.
+
+Toom'n'half means that the existence of one more piece is considered for a
+single operand. It can be virtual, i.e. zero, or real, when the two operand
+are not exactly balanced. By choosing an even @math{r},
+Toom-@m{r{1\over2},r+1/2} requires @math{2r} points, a multiple of four.
+
+The quadruplets of points include 0, @m{\infty,inf}, +1, -1 and
+@m{\pm2^i,+-2^i}, @m{\pm2^{-i},+-2^-i} . Each of them giving shortcuts for the
+evaluation phase and for some steps in the interpolation phase. Further tricks
+are used to reduce the memory footprint of the whole multiplication algorithm
+to a memory buffer equal in size to the result of the product.
+
+Current GMP uses both Toom-6'n'half and Toom-8'n'half.
+
+
+@node FFT Multiplication, Other Multiplication, Higher degree Toom'n'half, Multiplication Algorithms
+@subsection FFT Multiplication
+@cindex FFT multiplication
+@cindex Fast Fourier Transform
+
+At large to very large sizes a Fermat style FFT multiplication is used,
+following Sch@"onhage and Strassen (@pxref{References}).  Descriptions of FFTs
+in various forms can be found in many textbooks, for instance Knuth section
+4.3.3 part C or Lipson chapter IX@.  A brief description of the form used in
+GMP is given here.
+
+The multiplication done is @m{xy \bmod 2^N+1, x*y mod 2^N+1}, for a given
+@math{N}.  A full product @m{xy,x*y} is obtained by choosing @m{N \ge
+\mathop{\rm bits}(x)+\mathop{\rm bits}(y), N>=bits(x)+bits(y)} and padding
+@math{x} and @math{y} with high zero limbs.  The modular product is the native
+form for the algorithm, so padding to get a full product is unavoidable.
+
+The algorithm follows a split, evaluate, pointwise multiply, interpolate and
+combine similar to that described above for Karatsuba and Toom-3.  A @math{k}
+parameter controls the split, with an FFT-@math{k} splitting into @math{2^k}
+pieces of @math{M=N/2^k} bits each.  @math{N} must be a multiple of
+@m{2^k\times@code{mp\_bits\_per\_limb}, (2^k)*@nicode{mp_bits_per_limb}} so
+the split falls on limb boundaries, avoiding bit shifts in the split and
+combine stages.
+
+The evaluations, pointwise multiplications, and interpolation, are all done
+modulo @m{2^{N'}+1, 2^N'+1} where @math{N'} is @math{2M+k+3} rounded up to a
+multiple of @math{2^k} and of @code{mp_bits_per_limb}.  The results of
+interpolation will be the following negacyclic convolution of the input
+pieces, and the choice of @math{N'} ensures these sums aren't truncated.
+@tex
+$$ w_n = \sum_{{i+j = b2^k+n}\atop{b=0,1}} (-1)^b x_i y_j $$
+@end tex
+@ifnottex
+
+@example
+           ---
+           \         b
+w[n] =     /     (-1) * x[i] * y[j]
+           ---
+       i+j==b*2^k+n
+          b=0,1
+@end example
+
+@end ifnottex
+The points used for the evaluation are @math{g^i} for @math{i=0} to
+@math{2^k-1} where @m{g=2^{2N'/2^k}, g=2^(2N'/2^k)}.  @math{g} is a
+@m{2^k,2^k'}th root of unity mod @m{2^{N'}+1,2^N'+1}, which produces necessary
+cancellations at the interpolation stage, and it's also a power of 2 so the
+fast Fourier transforms used for the evaluation and interpolation do only
+shifts, adds and negations.
+
+The pointwise multiplications are done modulo @m{2^{N'}+1, 2^N'+1} and either
+recurse into a further FFT or use a plain multiplication (Toom-3, Karatsuba or
+basecase), whichever is optimal at the size @math{N'}.  The interpolation is
+an inverse fast Fourier transform.  The resulting set of sums of @m{x_iy_j,
+x[i]*y[j]} are added at appropriate offsets to give the final result.
+
+Squaring is the same, but @math{x} is the only input so it's one transform at
+the evaluate stage and the pointwise multiplies are squares.  The
+interpolation is the same.
+
+For a mod @math{2^N+1} product, an FFT-@math{k} is an @m{O(N^{k/(k-1)}),
+O(N^(k/(k-1)))} algorithm, the exponent representing @math{2^k} recursed
+modular multiplies each @m{1/2^{k-1},1/2^(k-1)} the size of the original.
+Each successive @math{k} is an asymptotic improvement, but overheads mean each
+is only faster at bigger and bigger sizes.  In the code, @code{MUL_FFT_TABLE}
+and @code{SQR_FFT_TABLE} are the thresholds where each @math{k} is used.  Each
+new @math{k} effectively swaps some multiplying for some shifts, adds and
+overheads.
+
+A mod @math{2^N+1} product can be formed with a normal
+@math{N@cross{}N@rightarrow{}2N} bit multiply plus a subtraction, so an FFT
+and Toom-3 etc can be compared directly.  A @math{k=4} FFT at
+@math{O(N^@W{1.333})} can be expected to be the first faster than Toom-3 at
+@math{O(N^@W{1.465})}.  In practice this is what's found, with
+@code{MUL_FFT_MODF_THRESHOLD} and @code{SQR_FFT_MODF_THRESHOLD} being between
+300 and 1000 limbs, depending on the CPU@.  So far it's been found that only
+very large FFTs recurse into pointwise multiplies above these sizes.
+
+When an FFT is to give a full product, the change of @math{N} to @math{2N}
+doesn't alter the theoretical complexity for a given @math{k}, but for the
+purposes of considering where an FFT might be first used it can be assumed
+that the FFT is recursing into a normal multiply and that on that basis it's
+doing @math{2^k} recursed multiplies each @m{1/2^{k-2},1/2^(k-2)} the size of
+the inputs, making it @m{O(N^{k/(k-2)}), O(N^(k/(k-2)))}.  This would mean
+@math{k=7} at @math{O(N^@W{1.4})} would be the first FFT faster than Toom-3.
+In practice @code{MUL_FFT_THRESHOLD} and @code{SQR_FFT_THRESHOLD} have been
+found to be in the @math{k=8} range, somewhere between 3000 and 10000 limbs.
+
+The way @math{N} is split into @math{2^k} pieces and then @math{2M+k+3} is
+rounded up to a multiple of @math{2^k} and @code{mp_bits_per_limb} means that
+when @math{2^k@ge{}@nicode{mp\_bits\_per\_limb}} the effective @math{N} is a
+multiple of @m{2^{2k-1},2^(2k-1)} bits.  The @math{+k+3} means some values of
+@math{N} just under such a multiple will be rounded to the next.  The
+complexity calculations above assume that a favourable size is used, meaning
+one which isn't padded through rounding, and it's also assumed that the extra
+@math{+k+3} bits are negligible at typical FFT sizes.
+
+The practical effect of the @m{2^{2k-1},2^(2k-1)} constraint is to introduce a
+step-effect into measured speeds.  For example @math{k=8} will round @math{N}
+up to a multiple of 32768 bits, so for a 32-bit limb there'll be 512 limb
+groups of sizes for which @code{mpn_mul_n} runs at the same speed.  Or for
+@math{k=9} groups of 2048 limbs, @math{k=10} groups of 8192 limbs, etc.  In
+practice it's been found each @math{k} is used at quite small multiples of its
+size constraint and so the step effect is quite noticeable in a time versus
+size graph.
+
+The threshold determinations currently measure at the mid-points of size
+steps, but this is sub-optimal since at the start of a new step it can happen
+that it's better to go back to the previous @math{k} for a while.  Something
+more sophisticated for @code{MUL_FFT_TABLE} and @code{SQR_FFT_TABLE} will be
+needed.
+
+
+@node Other Multiplication, Unbalanced Multiplication, FFT Multiplication, Multiplication Algorithms
+@subsection Other Multiplication
+@cindex Toom multiplication
+
+The Toom algorithms described above (@pxref{Toom 3-Way Multiplication},
+@pxref{Toom 4-Way Multiplication}) generalizes to split into an arbitrary
+number of pieces, as per Knuth section 4.3.3 algorithm C@.  This is not
+currently used.  The notes here are merely for interest.
+
+In general a split into @math{r+1} pieces is made, and evaluations and
+pointwise multiplications done at @m{2r+1,2*r+1} points.  A 4-way split does 7
+pointwise multiplies, 5-way does 9, etc.  Asymptotically an @math{(r+1)}-way
+algorithm is @m{O(N^{log(2r+1)/log(r+1)}), O(N^(log(2*r+1)/log(r+1)))}.  Only
+the pointwise multiplications count towards big-@math{O} complexity, but the
+time spent in the evaluate and interpolate stages grows with @math{r} and has
+a significant practical impact, with the asymptotic advantage of each @math{r}
+realized only at bigger and bigger sizes.  The overheads grow as
+@m{O(Nr),O(N*r)}, whereas in an @math{r=2^k} FFT they grow only as @m{O(N \log
+r), O(N*log(r))}.
+
+Knuth algorithm C evaluates at points 0,1,2,@dots{},@m{2r,2*r}, but exercise 4
+uses @math{-r},@dots{},0,@dots{},@math{r} and the latter saves some small
+multiplies in the evaluate stage (or rather trades them for additions), and
+has a further saving of nearly half the interpolate steps.  The idea is to
+separate odd and even final coefficients and then perform algorithm C steps C7
+and C8 on them separately.  The divisors at step C7 become @math{j^2} and the
+multipliers at C8 become @m{2tj-j^2,2*t*j-j^2}.
+
+Splitting odd and even parts through positive and negative points can be
+thought of as using @math{-1} as a square root of unity.  If a 4th root of
+unity was available then a further split and speedup would be possible, but no
+such root exists for plain integers.  Going to complex integers with
+@m{i=\sqrt{-1}, i=sqrt(-1)} doesn't help, essentially because in Cartesian
+form it takes three real multiplies to do a complex multiply.  The existence
+of @m{2^k,2^k'}th roots of unity in a suitable ring or field lets the fast
+Fourier transform keep splitting and get to @m{O(N \log r), O(N*log(r))}.
+
+Floating point FFTs use complex numbers approximating Nth roots of unity.
+Some processors have special support for such FFTs.  But these are not used in
+GMP since it's very difficult to guarantee an exact result (to some number of
+bits).  An occasional difference of 1 in the last bit might not matter to a
+typical signal processing algorithm, but is of course of vital importance to
+GMP.
+
+
+@node Unbalanced Multiplication,  , Other Multiplication, Multiplication Algorithms
+@subsection Unbalanced Multiplication
+@cindex Unbalanced multiplication
+
+Multiplication of operands with different sizes, both below
+@code{MUL_TOOM22_THRESHOLD} are done with plain schoolbook multiplication
+(@pxref{Basecase Multiplication}).
+
+For really large operands, we invoke FFT directly.
+
+For operands between these sizes, we use Toom inspired algorithms suggested by
+Alberto Zanoni and Marco Bodrato.  The idea is to split the operands into
+polynomials of different degree.  GMP currently splits the smaller operand
+onto 2 coefficients, i.e., a polynomial of degree 1, but the larger operand
+can be split into 2, 3, or 4 coefficients, i.e., a polynomial of degree 1 to
+3.
+
+@c FIXME: This is mighty ugly, but a cleaner @need triggers texinfo bugs that
+@c screws up layout here and there in the rest of the manual.
+@c @tex
+@c \goodbreak
+@c @end tex
+@node Division Algorithms, Greatest Common Divisor Algorithms, Multiplication Algorithms, Algorithms
+@section Division Algorithms
+@cindex Division algorithms
+
+@menu
+* Single Limb Division::
+* Basecase Division::
+* Divide and Conquer Division::
+* Block-Wise Barrett Division::
+* Exact Division::
+* Exact Remainder::
+* Small Quotient Division::
+@end menu
+
+
+@node Single Limb Division, Basecase Division, Division Algorithms, Division Algorithms
+@subsection Single Limb Division
+
+N@cross{}1 division is implemented using repeated 2@cross{}1 divisions from
+high to low, either with a hardware divide instruction or a multiplication by
+inverse, whichever is best on a given CPU.
+
+The multiply by inverse follows ``Improved division by invariant integers'' by
+M@"oller and Granlund (@pxref{References}) and is implemented as
+@code{udiv_qrnnd_preinv} in @file{gmp-impl.h}.  The idea is to have a
+fixed-point approximation to @math{1/d} (see @code{invert_limb}) and then
+multiply by the high limb (plus one bit) of the dividend to get a quotient
+@math{q}.  With @math{d} normalized (high bit set), @math{q} is no more than 1
+too small.  Subtracting @m{qd,q*d} from the dividend gives a remainder, and
+reveals whether @math{q} or @math{q-1} is correct.
+
+The result is a division done with two multiplications and four or five
+arithmetic operations.  On CPUs with low latency multipliers this can be much
+faster than a hardware divide, though the cost of calculating the inverse at
+the start may mean it's only better on inputs bigger than say 4 or 5 limbs.
+
+When a divisor must be normalized, either for the generic C
+@code{__udiv_qrnnd_c} or the multiply by inverse, the division performed is
+actually @m{a2^k,a*2^k} by @m{d2^k,d*2^k} where @math{a} is the dividend and
+@math{k} is the power necessary to have the high bit of @m{d2^k,d*2^k} set.
+The bit shifts for the dividend are usually accomplished ``on the fly''
+meaning by extracting the appropriate bits at each step.  Done this way the
+quotient limbs come out aligned ready to store.  When only the remainder is
+wanted, an alternative is to take the dividend limbs unshifted and calculate
+@m{r = a \bmod d2^k, r = a mod d*2^k} followed by an extra final step @m{r2^k
+\bmod d2^k, r*2^k mod d*2^k}.  This can help on CPUs with poor bit shifts or
+few registers.
+
+The multiply by inverse can be done two limbs at a time.  The calculation is
+basically the same, but the inverse is two limbs and the divisor treated as if
+padded with a low zero limb.  This means more work, since the inverse will
+need a 2@cross{}2 multiply, but the four 1@cross{}1s to do that are
+independent and can therefore be done partly or wholly in parallel.  Likewise
+for a 2@cross{}1 calculating @m{qd,q*d}.  The net effect is to process two
+limbs with roughly the same two multiplies worth of latency that one limb at a
+time gives.  This extends to 3 or 4 limbs at a time, though the extra work to
+apply the inverse will almost certainly soon reach the limits of multiplier
+throughput.
+
+A similar approach in reverse can be taken to process just half a limb at a
+time if the divisor is only a half limb.  In this case the 1@cross{}1 multiply
+for the inverse effectively becomes two @m{{1\over2}\times1, (1/2)x1} for each
+limb, which can be a saving on CPUs with a fast half limb multiply, or in fact
+if the only multiply is a half limb, and especially if it's not pipelined.
+
+
+@node Basecase Division, Divide and Conquer Division, Single Limb Division, Division Algorithms
+@subsection Basecase Division
+
+Basecase N@cross{}M division is like long division done by hand, but in base
+@m{2\GMPraise{@code{mp\_bits\_per\_limb}}, 2^mp_bits_per_limb}.  See Knuth
+section 4.3.1 algorithm D, and @file{mpn/generic/sb_divrem_mn.c}.
+
+Briefly stated, while the dividend remains larger than the divisor, a high
+quotient limb is formed and the N@cross{}1 product @m{qd,q*d} subtracted at
+the top end of the dividend.  With a normalized divisor (most significant bit
+set), each quotient limb can be formed with a 2@cross{}1 division and a
+1@cross{}1 multiplication plus some subtractions.  The 2@cross{}1 division is
+by the high limb of the divisor and is done either with a hardware divide or a
+multiply by inverse (the same as in @ref{Single Limb Division}) whichever is
+faster.  Such a quotient is sometimes one too big, requiring an addback of the
+divisor, but that happens rarely.
+
+With Q=N@minus{}M being the number of quotient limbs, this is an
+@m{O(QM),O(Q*M)} algorithm and will run at a speed similar to a basecase
+Q@cross{}M multiplication, differing in fact only in the extra multiply and
+divide for each of the Q quotient limbs.
+
+
+@node Divide and Conquer Division, Block-Wise Barrett Division, Basecase Division, Division Algorithms
+@subsection Divide and Conquer Division
+
+For divisors larger than @code{DC_DIV_QR_THRESHOLD}, division is done by dividing.
+Or to be precise by a recursive divide and conquer algorithm based on work by
+Moenck and Borodin, Jebelean, and Burnikel and Ziegler (@pxref{References}).
+
+The algorithm consists essentially of recognising that a 2N@cross{}N division
+can be done with the basecase division algorithm (@pxref{Basecase Division}),
+but using N/2 limbs as a base, not just a single limb.  This way the
+multiplications that arise are (N/2)@cross{}(N/2) and can take advantage of
+Karatsuba and higher multiplication algorithms (@pxref{Multiplication
+Algorithms}).  The two ``digits'' of the quotient are formed by recursive
+N@cross{}(N/2) divisions.
+
+If the (N/2)@cross{}(N/2) multiplies are done with a basecase multiplication
+then the work is about the same as a basecase division, but with more function
+call overheads and with some subtractions separated from the multiplies.
+These overheads mean that it's only when N/2 is above
+@code{MUL_TOOM22_THRESHOLD} that divide and conquer is of use.
+
+@code{DC_DIV_QR_THRESHOLD} is based on the divisor size N, so it will be somewhere
+above twice @code{MUL_TOOM22_THRESHOLD}, but how much above depends on the
+CPU@.  An optimized @code{mpn_mul_basecase} can lower @code{DC_DIV_QR_THRESHOLD} a
+little by offering a ready-made advantage over repeated @code{mpn_submul_1}
+calls.
+
+Divide and conquer is asymptotically @m{O(M(N)\log N),O(M(N)*log(N))} where
+@math{M(N)} is the time for an N@cross{}N multiplication done with FFTs.  The
+actual time is a sum over multiplications of the recursed sizes, as can be
+seen near the end of section 2.2 of Burnikel and Ziegler.  For example, within
+the Toom-3 range, divide and conquer is @m{2.63M(N), 2.63*M(N)}.  With higher
+algorithms the @math{M(N)} term improves and the multiplier tends to @m{\log
+N, log(N)}.  In practice, at moderate to large sizes, a 2N@cross{}N division
+is about 2 to 4 times slower than an N@cross{}N multiplication.
+
+
+@node Block-Wise Barrett Division, Exact Division, Divide and Conquer Division, Division Algorithms
+@subsection Block-Wise Barrett Division
+
+For the largest divisions, a block-wise Barrett division algorithm is used.
+Here, the divisor is inverted to a precision determined by the relative size of
+the dividend and divisor.  Blocks of quotient limbs are then generated by
+multiplying blocks from the dividend by the inverse.
+
+Our block-wise algorithm computes a smaller inverse than in the plain Barrett
+algorithm.  For a @math{2n/n} division, the inverse will be just @m{\lceil n/2
+\rceil, ceil(n/2)} limbs.
+
+
+@node Exact Division, Exact Remainder, Block-Wise Barrett Division, Division Algorithms
+@subsection Exact Division
+
+
+A so-called exact division is when the dividend is known to be an exact
+multiple of the divisor.  Jebelean's exact division algorithm uses this
+knowledge to make some significant optimizations (@pxref{References}).
+
+The idea can be illustrated in decimal for example with 368154 divided by
+543.  Because the low digit of the dividend is 4, the low digit of the
+quotient must be 8.  This is arrived at from @m{4 \mathord{\times} 7 \bmod 10,
+4*7 mod 10}, using the fact 7 is the modular inverse of 3 (the low digit of
+the divisor), since @m{3 \mathord{\times} 7 \mathop{\equiv} 1 \bmod 10, 3*7
+@equiv{} 1 mod 10}.  So @m{8\mathord{\times}543 = 4344,8*543=4344} can be
+subtracted from the dividend leaving 363810.  Notice the low digit has become
+zero.
+
+The procedure is repeated at the second digit, with the next quotient digit 7
+(@m{1 \mathord{\times} 7 \bmod 10, 7 @equiv{} 1*7 mod 10}), subtracting
+@m{7\mathord{\times}543 = 3801,7*543=3801}, leaving 325800.  And finally at
+the third digit with quotient digit 6 (@m{8 \mathord{\times} 7 \bmod 10, 8*7
+mod 10}), subtracting @m{6\mathord{\times}543 = 3258,6*543=3258} leaving 0.
+So the quotient is 678.
+
+Notice however that the multiplies and subtractions don't need to extend past
+the low three digits of the dividend, since that's enough to determine the
+three quotient digits.  For the last quotient digit no subtraction is needed
+at all.  On a 2N@cross{}N division like this one, only about half the work of
+a normal basecase division is necessary.
+
+For an N@cross{}M exact division producing Q=N@minus{}M quotient limbs, the
+saving over a normal basecase division is in two parts.  Firstly, each of the
+Q quotient limbs needs only one multiply, not a 2@cross{}1 divide and
+multiply.  Secondly, the crossproducts are reduced when @math{Q>M} to
+@m{QM-M(M+1)/2,Q*M-M*(M+1)/2}, or when @math{Q@le{}M} to @m{Q(Q-1)/2,
+Q*(Q-1)/2}.  Notice the savings are complementary.  If Q is big then many
+divisions are saved, or if Q is small then the crossproducts reduce to a small
+number.
+
+The modular inverse used is calculated efficiently by @code{binvert_limb} in
+@file{gmp-impl.h}.  This does four multiplies for a 32-bit limb, or six for a
+64-bit limb.  @file{tune/modlinv.c} has some alternate implementations that
+might suit processors better at bit twiddling than multiplying.
+
+The sub-quadratic exact division described by Jebelean in ``Exact Division
+with Karatsuba Complexity'' is not currently implemented.  It uses a
+rearrangement similar to the divide and conquer for normal division
+(@pxref{Divide and Conquer Division}), but operating from low to high.  A
+further possibility not currently implemented is ``Bidirectional Exact Integer
+Division'' by Krandick and Jebelean which forms quotient limbs from both the
+high and low ends of the dividend, and can halve once more the number of
+crossproducts needed in a 2N@cross{}N division.
+
+A special case exact division by 3 exists in @code{mpn_divexact_by3},
+supporting Toom-3 multiplication and @code{mpq} canonicalizations.  It forms
+quotient digits with a multiply by the modular inverse of 3 (which is
+@code{0xAA..AAB}) and uses two comparisons to determine a borrow for the next
+limb.  The multiplications don't need to be on the dependent chain, as long as
+the effect of the borrows is applied, which can help chips with pipelined
+multipliers.
+
+
+@node Exact Remainder, Small Quotient Division, Exact Division, Division Algorithms
+@subsection Exact Remainder
+@cindex Exact remainder
+
+If the exact division algorithm is done with a full subtraction at each stage
+and the dividend isn't a multiple of the divisor, then low zero limbs are
+produced but with a remainder in the high limbs.  For dividend @math{a},
+divisor @math{d}, quotient @math{q}, and @m{b = 2
+\GMPraise{@code{mp\_bits\_per\_limb}}, b = 2^mp_bits_per_limb}, this remainder
+@math{r} is of the form
+@tex
+$$ a = qd + r b^n $$
+@end tex
+@ifnottex
+
+@example
+a = q*d + r*b^n
+@end example
+
+@end ifnottex
+@math{n} represents the number of zero limbs produced by the subtractions,
+that being the number of limbs produced for @math{q}.  @math{r} will be in the
+range @math{0@le{}r<d} and can be viewed as a remainder, but one shifted up by
+a factor of @math{b^n}.
+
+Carrying out full subtractions at each stage means the same number of cross
+products must be done as a normal division, but there's still some single limb
+divisions saved.  When @math{d} is a single limb some simplifications arise,
+providing good speedups on a number of processors.
+
+The functions @code{mpn_divexact_by3}, @code{mpn_modexact_1_odd} and the
+internal @code{mpn_redc_X} functions differ subtly in how they return @math{r},
+leading to some negations in the above formula, but all are essentially the
+same.
+
+@cindex Divisibility algorithm
+@cindex Congruence algorithm
+Clearly @math{r} is zero when @math{a} is a multiple of @math{d}, and this
+leads to divisibility or congruence tests which are potentially more efficient
+than a normal division.
+
+The factor of @math{b^n} on @math{r} can be ignored in a GCD when @math{d} is
+odd, hence the use of @code{mpn_modexact_1_odd} by @code{mpn_gcd_1} and
+@code{mpz_kronecker_ui} etc (@pxref{Greatest Common Divisor Algorithms}).
+
+Montgomery's REDC method for modular multiplications uses operands of the form
+of @m{xb^{-n}, x*b^-n} and @m{yb^{-n}, y*b^-n} and on calculating @m{(xb^{-n})
+(yb^{-n}), (x*b^-n)*(y*b^-n)} uses the factor of @math{b^n} in the exact
+remainder to reach a product in the same form @m{(xy)b^{-n}, (x*y)*b^-n}
+(@pxref{Modular Powering Algorithm}).
+
+Notice that @math{r} generally gives no useful information about the ordinary
+remainder @math{a @bmod d} since @math{b^n @bmod d} could be anything.  If
+however @math{b^n @equiv{} 1 @bmod d}, then @math{r} is the negative of the
+ordinary remainder.  This occurs whenever @math{d} is a factor of
+@math{b^n-1}, as for example with 3 in @code{mpn_divexact_by3}.  For a 32 or
+64 bit limb other such factors include 5, 17 and 257, but no particular use
+has been found for this.
+
+
+@node Small Quotient Division,  , Exact Remainder, Division Algorithms
+@subsection Small Quotient Division
+
+An N@cross{}M division where the number of quotient limbs Q=N@minus{}M is
+small can be optimized somewhat.
+
+An ordinary basecase division normalizes the divisor by shifting it to make
+the high bit set, shifting the dividend accordingly, and shifting the
+remainder back down at the end of the calculation.  This is wasteful if only a
+few quotient limbs are to be formed.  Instead a division of just the top
+@m{\rm2Q,2*Q} limbs of the dividend by the top Q limbs of the divisor can be
+used to form a trial quotient.  This requires only those limbs normalized, not
+the whole of the divisor and dividend.
+
+A multiply and subtract then applies the trial quotient to the M@minus{}Q
+unused limbs of the divisor and N@minus{}Q dividend limbs (which includes Q
+limbs remaining from the trial quotient division).  The starting trial
+quotient can be 1 or 2 too big, but all cases of 2 too big and most cases of 1
+too big are detected by first comparing the most significant limbs that will
+arise from the subtraction.  An addback is done if the quotient still turns
+out to be 1 too big.
+
+This whole procedure is essentially the same as one step of the basecase
+algorithm done in a Q limb base, though with the trial quotient test done only
+with the high limbs, not an entire Q limb ``digit'' product.  The correctness
+of this weaker test can be established by following the argument of Knuth
+section 4.3.1 exercise 20 but with the @m{v_2 \GMPhat q > b \GMPhat r
++ u_2, v2*q>b*r+u2} condition appropriately relaxed.
+
+
+@need 1000
+@node Greatest Common Divisor Algorithms, Powering Algorithms, Division Algorithms, Algorithms
+@section Greatest Common Divisor
+@cindex Greatest common divisor algorithms
+@cindex GCD algorithms
+
+@menu
+* Binary GCD::
+* Lehmer's Algorithm::
+* Subquadratic GCD::
+* Extended GCD::
+* Jacobi Symbol::
+@end menu
+
+
+@node Binary GCD, Lehmer's Algorithm, Greatest Common Divisor Algorithms, Greatest Common Divisor Algorithms
+@subsection Binary GCD
+
+At small sizes GMP uses an @math{O(N^2)} binary style GCD@.  This is described
+in many textbooks, for example Knuth section 4.5.2 algorithm B@.  It simply
+consists of successively reducing odd operands @math{a} and @math{b} using
+
+@quotation
+@math{a,b = @abs{}(a-b),@min{}(a,b)} @*
+strip factors of 2 from @math{a}
+@end quotation
+
+The Euclidean GCD algorithm, as per Knuth algorithms E and A, repeatedly
+computes the quotient @m{q = \lfloor a/b \rfloor, q = floor(a/b)} and replaces
+@math{a,b} by @math{v, u - q v}. The binary algorithm has so far been found to
+be faster than the Euclidean algorithm everywhere.  One reason the binary
+method does well is that the implied quotient at each step is usually small,
+so often only one or two subtractions are needed to get the same effect as a
+division.  Quotients 1, 2 and 3 for example occur 67.7% of the time, see Knuth
+section 4.5.3 Theorem E.
+
+When the implied quotient is large, meaning @math{b} is much smaller than
+@math{a}, then a division is worthwhile.  This is the basis for the initial
+@math{a @bmod b} reductions in @code{mpn_gcd} and @code{mpn_gcd_1} (the latter
+for both N@cross{}1 and 1@cross{}1 cases).  But after that initial reduction,
+big quotients occur too rarely to make it worth checking for them.
+
+@sp 1
+The final @math{1@cross{}1} GCD in @code{mpn_gcd_1} is done in the generic C
+code as described above.  For two N-bit operands, the algorithm takes about
+0.68 iterations per bit.  For optimum performance some attention needs to be
+paid to the way the factors of 2 are stripped from @math{a}.
+
+Firstly it may be noted that in twos complement the number of low zero bits on
+@math{a-b} is the same as @math{b-a}, so counting or testing can begin on
+@math{a-b} without waiting for @math{@abs{}(a-b)} to be determined.
+
+A loop stripping low zero bits tends not to branch predict well, since the
+condition is data dependent.  But on average there's only a few low zeros, so
+an option is to strip one or two bits arithmetically then loop for more (as
+done for AMD K6).  Or use a lookup table to get a count for several bits then
+loop for more (as done for AMD K7).  An alternative approach is to keep just
+one of @math{a} or @math{b} odd and iterate
+
+@quotation
+@math{a,b = @abs{}(a-b), @min{}(a,b)} @*
+@math{a = a/2} if even @*
+@math{b = b/2} if even
+@end quotation
+
+This requires about 1.25 iterations per bit, but stripping of a single bit at
+each step avoids any branching.  Repeating the bit strip reduces to about 0.9
+iterations per bit, which may be a worthwhile tradeoff.
+
+Generally with the above approaches a speed of perhaps 6 cycles per bit can be
+achieved, which is still not terribly fast with for instance a 64-bit GCD
+taking nearly 400 cycles.  It's this sort of time which means it's not usually
+advantageous to combine a set of divisibility tests into a GCD.
+
+Currently, the binary algorithm is used for GCD only when @math{N < 3}.
+
+@node Lehmer's Algorithm, Subquadratic GCD, Binary GCD, Greatest Common Divisor Algorithms
+@comment  node-name,  next,  previous,  up
+@subsection Lehmer's algorithm
+
+Lehmer's improvement of the Euclidean algorithms is based on the observation
+that the initial part of the quotient sequence depends only on the most
+significant parts of the inputs. The variant of Lehmer's algorithm used in GMP
+splits off the most significant two limbs, as suggested, e.g., in ``A
+Double-Digit Lehmer-Euclid Algorithm'' by Jebelean (@pxref{References}). The
+quotients of two double-limb inputs are collected as a 2 by 2 matrix with
+single-limb elements. This is done by the function @code{mpn_hgcd2}. The
+resulting matrix is applied to the inputs using @code{mpn_mul_1} and
+@code{mpn_submul_1}. Each iteration usually reduces the inputs by almost one
+limb. In the rare case of a large quotient, no progress can be made by
+examining just the most significant two limbs, and the quotient is computed
+using plain division.
+
+The resulting algorithm is asymptotically @math{O(N^2)}, just as the Euclidean
+algorithm and the binary algorithm. The quadratic part of the work are
+the calls to @code{mpn_mul_1} and @code{mpn_submul_1}. For small sizes, the
+linear work is also significant. There are roughly @math{N} calls to the
+@code{mpn_hgcd2} function. This function uses a couple of important
+optimizations:
+
+@itemize
+@item
+It uses the same relaxed notion of correctness as @code{mpn_hgcd} (see next
+section). This means that when called with the most significant two limbs of
+two large numbers, the returned matrix does not always correspond exactly to
+the initial quotient sequence for the two large numbers; the final quotient
+may sometimes be one off.
+
+@item
+It takes advantage of the fact the quotients are usually small. The division
+operator is not used, since the corresponding assembler instruction is very
+slow on most architectures. (This code could probably be improved further, it
+uses many branches that are unfriendly to prediction).
+
+@item
+It switches from double-limb calculations to single-limb calculations half-way
+through, when the input numbers have been reduced in size from two limbs to
+one and a half.
+
+@end itemize
+
+@node Subquadratic GCD, Extended GCD, Lehmer's Algorithm, Greatest Common Divisor Algorithms
+@subsection Subquadratic GCD
+
+For inputs larger than @code{GCD_DC_THRESHOLD}, GCD is computed via the HGCD
+(Half GCD) function, as a generalization to Lehmer's algorithm.
+
+Let the inputs @math{a,b} be of size @math{N} limbs each. Put @m{S=\lfloor N/2
+\rfloor + 1, S = floor(N/2) + 1}. Then HGCD(a,b) returns a transformation
+matrix @math{T} with non-negative elements, and reduced numbers @math{(c;d) =
+T^{-1} (a;b)}. The reduced numbers @math{c,d} must be larger than @math{S}
+limbs, while their difference @math{abs(c-d)} must fit in @math{S} limbs. The
+matrix elements will also be of size roughly @math{N/2}.
+
+The HGCD base case uses Lehmer's algorithm, but with the above stop condition
+that returns reduced numbers and the corresponding transformation matrix
+half-way through. For inputs larger than @code{HGCD_THRESHOLD}, HGCD is
+computed recursively, using the divide and conquer algorithm in ``On
+Sch@"onhage's algorithm and subquadratic integer GCD computation'' by M@"oller
+(@pxref{References}). The recursive algorithm consists of these main
+steps.
+
+@itemize
+
+@item
+Call HGCD recursively, on the most significant @math{N/2} limbs. Apply the
+resulting matrix @math{T_1} to the full numbers, reducing them to a size just
+above @math{3N/2}.
+
+@item
+Perform a small number of division or subtraction steps to reduce the numbers
+to size below @math{3N/2}. This is essential mainly for the unlikely case of
+large quotients.
+
+@item
+Call HGCD recursively, on the most significant @math{N/2} limbs of the reduced
+numbers. Apply the resulting matrix @math{T_2} to the full numbers, reducing
+them to a size just above @math{N/2}.
+
+@item
+Compute @math{T = T_1 T_2}.
+
+@item
+Perform a small number of division and subtraction steps to satisfy the
+requirements, and return.
+@end itemize
+
+GCD is then implemented as a loop around HGCD, similarly to Lehmer's
+algorithm. Where Lehmer repeatedly chops off the top two limbs, calls
+@code{mpn_hgcd2}, and applies the resulting matrix to the full numbers, the
+sub-quadratic GCD chops off the most significant third of the limbs (the
+proportion is a tuning parameter, and @math{1/3} seems to be more efficient
+than, e.g, @math{1/2}), calls @code{mpn_hgcd}, and applies the resulting
+matrix. Once the input numbers are reduced to size below
+@code{GCD_DC_THRESHOLD}, Lehmer's algorithm is used for the rest of the work.
+
+The asymptotic running time of both HGCD and GCD is @m{O(M(N)\log N),O(M(N)*log(N))},
+where @math{M(N)} is the time for multiplying two @math{N}-limb numbers.
+
+@comment  node-name,  next,  previous,  up
+
+@node Extended GCD, Jacobi Symbol, Subquadratic GCD, Greatest Common Divisor Algorithms
+@subsection Extended GCD
+
+The extended GCD function, or GCDEXT, calculates @math{@gcd{}(a,b)} and also
+cofactors @math{x} and @math{y} satisfying @m{ax+by=\gcd(a@C{}b),
+a*x+b*y=gcd(a@C{}b)}. All the algorithms used for plain GCD are extended to
+handle this case. The binary algorithm is used only for single-limb GCDEXT.
+Lehmer's algorithm is used for sizes up to @code{GCDEXT_DC_THRESHOLD}. Above
+this threshold, GCDEXT is implemented as a loop around HGCD, but with more
+book-keeping to keep track of the cofactors. This gives the same asymptotic
+running time as for GCD and HGCD, @m{O(M(N)\log N),O(M(N)*log(N))}
+
+One difference to plain GCD is that while the inputs @math{a} and @math{b} are
+reduced as the algorithm proceeds, the cofactors @math{x} and @math{y} grow in
+size. This makes the tuning of the chopping-point more difficult. The current
+code chops off the most significant half of the inputs for the call to HGCD in
+the first iteration, and the most significant two thirds for the remaining
+calls. This strategy could surely be improved. Also the stop condition for the
+loop, where Lehmer's algorithm is invoked once the inputs are reduced below
+@code{GCDEXT_DC_THRESHOLD}, could maybe be improved by taking into account the
+current size of the cofactors.
+
+@node Jacobi Symbol,  , Extended GCD, Greatest Common Divisor Algorithms
+@subsection Jacobi Symbol
+@cindex Jacobi symbol algorithm
+
+@c Editor Note: I don't see other people defining the inputs, it would be nice
+@c here because the code uses (a/b) where other references use (n/k)
+
+Jacobi symbol @m{\left(a \over b\right), (@var{a}/@var{b})}
+
+Initially if either operand fits in a single limb, a reduction is done with
+either @code{mpn_mod_1} or @code{mpn_modexact_1_odd}, followed by the binary
+algorithm on a single limb.  The binary algorithm is well suited to a single limb,
+and the whole calculation in this case is quite efficient.
+
+For inputs larger than @code{GCD_DC_THRESHOLD}, @code{mpz_jacobi},
+@code{mpz_legendre} and @code{mpz_kronecker} are computed via the HGCD (Half
+GCD) function, as a generalization to Lehmer's algorithm.
+
+Most GCD algorithms reduce @math{a} and @math{b} by repeatatily computing the
+quotient @m{q = \lfloor a/b \rfloor, q = floor(a/b)} and iteratively replacing
+
+@c Couldn't figure out macros with commas.
+@tex
+$$ a, b = b, a - q * b$$
+@end tex
+@ifnottex
+@math{a, b = b, a - q * b}
+@end ifnottex
+
+Different algorithms use different methods for calculating q, but the core
+algorithm is the same if we use @ref{Lehmer's Algorithm} or
+@ref{Subquadratic GCD, HGCD}.
+
+At each step it is possible to compute if the reduction inverts the Jacobi
+symbol based on the two least significant bits of @var{a} and @var{b}.  For
+more details see ``Efficient computation of the Jacobi symbol'' by
+M@"oller (@pxref{References}).
+
+A small set of bits is thus used to track state
+@itemize
+@item
+current sign of result (1 bit)
+
+@item
+two least significant bits of @var{a} and @var{b} (4 bits)
+
+@item
+a pointer to which input is currently the denominator (1 bit)
+@end itemize
+
+In all the routines sign changes for the result are accumulated using fast bit
+twiddling which avoids conditional jumps.
+
+The final result is calculated after verifying the inputs are coprime (GCD = 1)
+by raising @m{(-1)^e,(-1)^e}
+
+Much of the HGCD code is shared directly with the HGCD implementations, such
+as the 2x2 matrix calculation, @xref{Lehmer's Algorithm} basecase and
+@code{GCD_DC_THRESHOLD}.
+
+The asymptotic running time is @m{O(M(N)\log N),O(M(N)*log(N))}, where
+@math{M(N)} is the time for multiplying two @math{N}-limb numbers.
+
+@need 1000
+@node Powering Algorithms, Root Extraction Algorithms, Greatest Common Divisor Algorithms, Algorithms
+@section Powering Algorithms
+@cindex Powering algorithms
+
+@menu
+* Normal Powering Algorithm::
+* Modular Powering Algorithm::
+@end menu
+
+
+@node Normal Powering Algorithm, Modular Powering Algorithm, Powering Algorithms, Powering Algorithms
+@subsection Normal Powering
+
+Normal @code{mpz} or @code{mpf} powering uses a simple binary algorithm,
+successively squaring and then multiplying by the base when a 1 bit is seen in
+the exponent, as per Knuth section 4.6.3.  The ``left to right''
+variant described there is used rather than algorithm A, since it's just as
+easy and can be done with somewhat less temporary memory.
+
+
+@node Modular Powering Algorithm,  , Normal Powering Algorithm, Powering Algorithms
+@subsection Modular Powering
+
+Modular powering is implemented using a @math{2^k}-ary sliding window
+algorithm, as per ``Handbook of Applied Cryptography'' algorithm 14.85
+(@pxref{References}).  @math{k} is chosen according to the size of the
+exponent.  Larger exponents use larger values of @math{k}, the choice being
+made to minimize the average number of multiplications that must supplement
+the squaring.
+
+The modular multiplies and squarings use either a simple division or the REDC
+method by Montgomery (@pxref{References}).  REDC is a little faster,
+essentially saving N single limb divisions in a fashion similar to an exact
+remainder (@pxref{Exact Remainder}).
+
+
+@node Root Extraction Algorithms, Radix Conversion Algorithms, Powering Algorithms, Algorithms
+@section Root Extraction Algorithms
+@cindex Root extraction algorithms
+
+@menu
+* Square Root Algorithm::
+* Nth Root Algorithm::
+* Perfect Square Algorithm::
+* Perfect Power Algorithm::
+@end menu
+
+
+@node Square Root Algorithm, Nth Root Algorithm, Root Extraction Algorithms, Root Extraction Algorithms
+@subsection Square Root
+@cindex Square root algorithm
+@cindex Karatsuba square root algorithm
+
+Square roots are taken using the ``Karatsuba Square Root'' algorithm by Paul
+Zimmermann (@pxref{References}).
+
+An input @math{n} is split into four parts of @math{k} bits each, so with
+@math{b=2^k} we have @m{n = a_3b^3 + a_2b^2 + a_1b + a_0, n = a3*b^3 + a2*b^2
++ a1*b + a0}.  Part @ms{a,3} must be ``normalized'' so that either the high or
+second highest bit is set.  In GMP, @math{k} is kept on a limb boundary and
+the input is left shifted (by an even number of bits) to normalize.
+
+The square root of the high two parts is taken, by recursive application of
+the algorithm (bottoming out in a one-limb Newton's method),
+@tex
+$$ s',r' = \mathop{\rm sqrtrem} \> (a_3b + a_2) $$
+@end tex
+@ifnottex
+
+@example
+s1,r1 = sqrtrem (a3*b + a2)
+@end example
+
+@end ifnottex
+This is an approximation to the desired root and is extended by a division to
+give @math{s},@math{r},
+@tex
+$$\eqalign{
+q,u &= \mathop{\rm divrem} \> (r'b + a_1, 2s') \cr
+s &= s'b + q \cr
+r &= ub + a_0 - q^2
+}$$
+@end tex
+@ifnottex
+
+@example
+q,u = divrem (r1*b + a1, 2*s1)
+s = s1*b + q
+r = u*b + a0 - q^2
+@end example
+
+@end ifnottex
+The normalization requirement on @ms{a,3} means at this point @math{s} is
+either correct or 1 too big.  @math{r} is negative in the latter case, so
+@tex
+$$\eqalign{
+\mathop{\rm if} \; r &< 0 \; \mathop{\rm then} \cr
+r &\leftarrow r + 2s - 1 \cr
+s &\leftarrow s - 1
+}$$
+@end tex
+@ifnottex
+
+@example
+if r < 0 then
+  r = r + 2*s - 1
+  s = s - 1
+@end example
+
+@end ifnottex
+The algorithm is expressed in a divide and conquer form, but as noted in the
+paper it can also be viewed as a discrete variant of Newton's method, or as a
+variation on the schoolboy method (no longer taught) for square roots two
+digits at a time.
+
+If the remainder @math{r} is not required then usually only a few high limbs
+of @math{r} and @math{u} need to be calculated to determine whether an
+adjustment to @math{s} is required.  This optimization is not currently
+implemented.
+
+In the Karatsuba multiplication range this algorithm is @m{O({3\over2}
+M(N/2)),O(1.5*M(N/2))}, where @math{M(n)} is the time to multiply two numbers
+of @math{n} limbs.  In the FFT multiplication range this grows to a bound of
+@m{O(6 M(N/2)),O(6*M(N/2))}.  In practice a factor of about 1.5 to 1.8 is
+found in the Karatsuba and Toom-3 ranges, growing to 2 or 3 in the FFT range.
+
+The algorithm does all its calculations in integers and the resulting
+@code{mpn_sqrtrem} is used for both @code{mpz_sqrt} and @code{mpf_sqrt}.
+The extended precision given by @code{mpf_sqrt_ui} is obtained by
+padding with zero limbs.
+
+
+@node Nth Root Algorithm, Perfect Square Algorithm, Square Root Algorithm, Root Extraction Algorithms
+@subsection Nth Root
+@cindex Root extraction algorithm
+@cindex Nth root algorithm
+
+Integer Nth roots are taken using Newton's method with the following
+iteration, where @math{A} is the input and @math{n} is the root to be taken.
+@tex
+$$a_{i+1} = {1\over n} \left({A \over a_i^{n-1}} + (n-1)a_i \right)$$
+@end tex
+@ifnottex
+
+@example
+         1         A
+a[i+1] = - * ( --------- + (n-1)*a[i] )
+         n     a[i]^(n-1)
+@end example
+
+@end ifnottex
+The initial approximation @m{a_1,a[1]} is generated bitwise by successively
+powering a trial root with or without new 1 bits, aiming to be just above the
+true root.  The iteration converges quadratically when started from a good
+approximation.  When @math{n} is large more initial bits are needed to get
+good convergence.  The current implementation is not particularly well
+optimized.
+
+
+@node Perfect Square Algorithm, Perfect Power Algorithm, Nth Root Algorithm, Root Extraction Algorithms
+@subsection Perfect Square
+@cindex Perfect square algorithm
+
+A significant fraction of non-squares can be quickly identified by checking
+whether the input is a quadratic residue modulo small integers.
+
+@code{mpz_perfect_square_p} first tests the input mod 256, which means just
+examining the low byte.  Only 44 different values occur for squares mod 256,
+so 82.8% of inputs can be immediately identified as non-squares.
+
+On a 32-bit system similar tests are done mod 9, 5, 7, 13 and 17, for a total
+99.25% of inputs identified as non-squares.  On a 64-bit system 97 is tested
+too, for a total 99.62%.
+
+These moduli are chosen because they're factors of @math{2^@W{24}-1} (or
+@math{2^@W{48}-1} for 64-bits), and such a remainder can be quickly taken just
+using additions (see @code{mpn_mod_34lsub1}).
+
+When nails are in use moduli are instead selected by the @file{gen-psqr.c}
+program and applied with an @code{mpn_mod_1}.  The same @math{2^@W{24}-1} or
+@math{2^@W{48}-1} could be done with nails using some extra bit shifts, but
+this is not currently implemented.
+
+In any case each modulus is applied to the @code{mpn_mod_34lsub1} or
+@code{mpn_mod_1} remainder and a table lookup identifies non-squares.  By
+using a ``modexact'' style calculation, and suitably permuted tables, just one
+multiply each is required, see the code for details.  Moduli are also combined
+to save operations, so long as the lookup tables don't become too big.
+@file{gen-psqr.c} does all the pre-calculations.
+
+A square root must still be taken for any value that passes these tests, to
+verify it's really a square and not one of the small fraction of non-squares
+that get through (i.e.@: a pseudo-square to all the tested bases).
+
+Clearly more residue tests could be done, @code{mpz_perfect_square_p} only
+uses a compact and efficient set.  Big inputs would probably benefit from more
+residue testing, small inputs might be better off with less.  The assumed
+distribution of squares versus non-squares in the input would affect such
+considerations.
+
+
+@node Perfect Power Algorithm,  , Perfect Square Algorithm, Root Extraction Algorithms
+@subsection Perfect Power
+@cindex Perfect power algorithm
+
+Detecting perfect powers is required by some factorization algorithms.
+Currently @code{mpz_perfect_power_p} is implemented using repeated Nth root
+extractions, though naturally only prime roots need to be considered.
+(@xref{Nth Root Algorithm}.)
+
+If a prime divisor @math{p} with multiplicity @math{e} can be found, then only
+roots which are divisors of @math{e} need to be considered, much reducing the
+work necessary.  To this end divisibility by a set of small primes is checked.
+
+
+@node Radix Conversion Algorithms, Other Algorithms, Root Extraction Algorithms, Algorithms
+@section Radix Conversion
+@cindex Radix conversion algorithms
+
+Radix conversions are less important than other algorithms.  A program
+dominated by conversions should probably use a different data representation.
+
+@menu
+* Binary to Radix::
+* Radix to Binary::
+@end menu
+
+
+@node Binary to Radix, Radix to Binary, Radix Conversion Algorithms, Radix Conversion Algorithms
+@subsection Binary to Radix
+
+Conversions from binary to a power-of-2 radix use a simple and fast
+@math{O(N)} bit extraction algorithm.
+
+Conversions from binary to other radices use one of two algorithms.  Sizes
+below @code{GET_STR_PRECOMPUTE_THRESHOLD} use a basic @math{O(N^2)} method.
+Repeated divisions by @math{b^n} are made, where @math{b} is the radix and
+@math{n} is the biggest power that fits in a limb.  But instead of simply
+using the remainder @math{r} from such divisions, an extra divide step is done
+to give a fractional limb representing @math{r/b^n}.  The digits of @math{r}
+can then be extracted using multiplications by @math{b} rather than divisions.
+Special case code is provided for decimal, allowing multiplications by 10 to
+optimize to shifts and adds.
+
+Above @code{GET_STR_PRECOMPUTE_THRESHOLD} a sub-quadratic algorithm is used.
+For an input @math{t}, powers @m{b^{n2^i},b^(n*2^i)} of the radix are
+calculated, until a power between @math{t} and @m{\sqrt{t},sqrt(t)} is
+reached.  @math{t} is then divided by that largest power, giving a quotient
+which is the digits above that power, and a remainder which is those below.
+These two parts are in turn divided by the second highest power, and so on
+recursively.  When a piece has been divided down to less than
+@code{GET_STR_DC_THRESHOLD} limbs, the basecase algorithm described above is
+used.
+
+The advantage of this algorithm is that big divisions can make use of the
+sub-quadratic divide and conquer division (@pxref{Divide and Conquer
+Division}), and big divisions tend to have less overheads than lots of
+separate single limb divisions anyway.  But in any case the cost of
+calculating the powers @m{b^{n2^i},b^(n*2^i)} must first be overcome.
+
+@code{GET_STR_PRECOMPUTE_THRESHOLD} and @code{GET_STR_DC_THRESHOLD} represent
+the same basic thing, the point where it becomes worth doing a big division to
+cut the input in half.  @code{GET_STR_PRECOMPUTE_THRESHOLD} includes the cost
+of calculating the radix power required, whereas @code{GET_STR_DC_THRESHOLD}
+assumes that's already available, which is the case when recursing.
+
+Since the base case produces digits from least to most significant but they
+want to be stored from most to least, it's necessary to calculate in advance
+how many digits there will be, or at least be sure not to underestimate that.
+For GMP the number of input bits is multiplied by @code{chars_per_bit_exactly}
+from @code{mp_bases}, rounding up.  The result is either correct or one too
+big.
+
+Examining some of the high bits of the input could increase the chance of
+getting the exact number of digits, but an exact result every time would not
+be practical, since in general the difference between numbers 100@dots{} and
+99@dots{} is only in the last few bits and the work to identify 99@dots{}
+might well be almost as much as a full conversion.
+
+The @math{r/b^n} scheme described above for using multiplications to bring out
+digits might be useful for more than a single limb.  Some brief experiments
+with it on the base case when recursing didn't give a noticeable improvement,
+but perhaps that was only due to the implementation.  Something similar would
+work for the sub-quadratic divisions too, though there would be the cost of
+calculating a bigger radix power.
+
+Another possible improvement for the sub-quadratic part would be to arrange
+for radix powers that balanced the sizes of quotient and remainder produced,
+i.e.@: the highest power would be an @m{b^{nk},b^(n*k)} approximately equal to
+@m{\sqrt{t},sqrt(t)}, not restricted to a @math{2^i} factor.  That ought to
+smooth out a graph of times against sizes, but may or may not be a net
+speedup.
+
+
+@node Radix to Binary,  , Binary to Radix, Radix Conversion Algorithms
+@subsection Radix to Binary
+
+@strong{This section needs to be rewritten, it currently describes the
+algorithms used before GMP 4.3.}
+
+Conversions from a power-of-2 radix into binary use a simple and fast
+@math{O(N)} bitwise concatenation algorithm.
+
+Conversions from other radices use one of two algorithms.  Sizes below
+@code{SET_STR_PRECOMPUTE_THRESHOLD} use a basic @math{O(N^2)} method.  Groups
+of @math{n} digits are converted to limbs, where @math{n} is the biggest
+power of the base @math{b} which will fit in a limb, then those groups are
+accumulated into the result by multiplying by @math{b^n} and adding.  This
+saves multi-precision operations, as per Knuth section 4.4 part E
+(@pxref{References}).  Some special case code is provided for decimal, giving
+the compiler a chance to optimize multiplications by 10.
+
+Above @code{SET_STR_PRECOMPUTE_THRESHOLD} a sub-quadratic algorithm is used.
+First groups of @math{n} digits are converted into limbs.  Then adjacent
+limbs are combined into limb pairs with @m{xb^n+y,x*b^n+y}, where @math{x}
+and @math{y} are the limbs.  Adjacent limb pairs are combined into quads
+similarly with @m{xb^{2n}+y,x*b^(2n)+y}.  This continues until a single block
+remains, that being the result.
+
+The advantage of this method is that the multiplications for each @math{x} are
+big blocks, allowing Karatsuba and higher algorithms to be used.  But the cost
+of calculating the powers @m{b^{n2^i},b^(n*2^i)} must be overcome.
+@code{SET_STR_PRECOMPUTE_THRESHOLD} usually ends up quite big, around 5000 digits, and on
+some processors much bigger still.
+
+@code{SET_STR_PRECOMPUTE_THRESHOLD} is based on the input digits (and tuned
+for decimal), though it might be better based on a limb count, so as to be
+independent of the base.  But that sort of count isn't used by the base case
+and so would need some sort of initial calculation or estimate.
+
+The main reason @code{SET_STR_PRECOMPUTE_THRESHOLD} is so much bigger than the
+corresponding @code{GET_STR_PRECOMPUTE_THRESHOLD} is that @code{mpn_mul_1} is
+much faster than @code{mpn_divrem_1} (often by a factor of 5, or more).
+
+
+@need 1000
+@node Other Algorithms, Assembly Coding, Radix Conversion Algorithms, Algorithms
+@section Other Algorithms
+
+@menu
+* Prime Testing Algorithm::
+* Factorial Algorithm::
+* Binomial Coefficients Algorithm::
+* Fibonacci Numbers Algorithm::
+* Lucas Numbers Algorithm::
+* Random Number Algorithms::
+@end menu
+
+
+@node Prime Testing Algorithm, Factorial Algorithm, Other Algorithms, Other Algorithms
+@subsection Prime Testing
+@cindex Prime testing algorithms
+
+The primality testing in @code{mpz_probab_prime_p} (@pxref{Number Theoretic
+Functions}) first does some trial division by small factors and then uses the
+Miller-Rabin probabilistic primality testing algorithm, as described in Knuth
+section 4.5.4 algorithm P (@pxref{References}).
+
+For an odd input @math{n}, and with @math{n = q@GMPmultiply{}2^k+1} where
+@math{q} is odd, this algorithm selects a random base @math{x} and tests
+whether @math{x^q @bmod{} n} is 1 or @math{-1}, or an @m{x^{q2^j} \bmod n,
+x^(q*2^j) mod n} is @math{1}, for @math{1@le{}j@le{}k}.  If so then @math{n}
+is probably prime, if not then @math{n} is definitely composite.
+
+Any prime @math{n} will pass the test, but some composites do too.  Such
+composites are known as strong pseudoprimes to base @math{x}.  No @math{n} is
+a strong pseudoprime to more than @math{1/4} of all bases (see Knuth exercise
+22), hence with @math{x} chosen at random there's no more than a @math{1/4}
+chance a ``probable prime'' will in fact be composite.
+
+In fact strong pseudoprimes are quite rare, making the test much more
+powerful than this analysis would suggest, but @math{1/4} is all that's proven
+for an arbitrary @math{n}.
+
+
+@node Factorial Algorithm, Binomial Coefficients Algorithm, Prime Testing Algorithm, Other Algorithms
+@subsection Factorial
+@cindex Factorial algorithm
+
+Factorials are calculated by a combination of two algorithms. An idea is
+shared among them: to compute the odd part of the factorial; a final step
+takes account of the power of @math{2} term, by shifting.
+
+For small @math{n}, the odd factor of @math{n!} is computed with the simple
+observation that it is equal to the product of all positive odd numbers
+smaller than @math{n} times the odd factor of @m{\lfloor n/2\rfloor!, [n/2]!},
+where @m{\lfloor x\rfloor, [x]} is the integer part of @math{x}, and so on
+recursively. The procedure can be best illustrated with an example,
+
+@quotation
+@math{23! = (23.21.19.17.15.13.11.9.7.5.3)(11.9.7.5.3)(5.3)2^{19}}
+@end quotation
+
+Current code collects all the factors in a single list, with a loop and no
+recursion, and compute the product, with no special care for repeated chunks.
+
+When @math{n} is larger, computation pass trough prime sieving. An helper
+function is used, as suggested by Peter Luschny:
+@tex
+$$\mathop{\rm msf}(n) = {n!\over\lfloor n/2\rfloor!^2\cdot2^k} = \prod_{p=3}^{n}
+p^{\mathop{\rm L}(p,n)} $$
+@end tex
+@ifnottex
+
+@example
+                            n
+                          -----
+               n!          | |   L(p,n)
+msf(n) = -------------- =  | |  p
+          [n/2]!^2.2^k     p=3
+@end example
+@end ifnottex
+
+Where @math{p} ranges on odd prime numbers. The exponent @math{k} is chosen to
+obtain an odd integer number: @math{k} is the number of 1 bits in the binary
+representation of @m{\lfloor n/2\rfloor, [n/2]}. The function L@math{(p,n)}
+can be defined as zero when @math{p} is composite, and, for any prime
+@math{p}, it is computed with:
+@tex
+$$\mathop{\rm L}(p,n) = \sum_{i>0}\left\lfloor{n\over p^i}\right\rfloor\bmod2
+\leq\log_p(n)$$
+@end tex
+@ifnottex
+
+@example
+          ---
+           \    n
+L(p,n) =   /  [---] mod 2   <=  log (n) .
+          ---  p^i                p
+          i>0
+@end example
+@end ifnottex
+
+With this helper function, we are able to compute the odd part of @math{n!}
+using the recursion implied by @m{n!=\lfloor n/2\rfloor!^2\cdot\mathop{\rm
+msf}(n)\cdot2^k , n!=[n/2]!^2*msf(n)*2^k}. The recursion stops using the
+small-@math{n} algorithm on some @m{\lfloor n/2^i\rfloor, [n/2^i]}.
+
+Both the above algorithms use binary splitting to compute the product of many
+small factors. At first as many products as possible are accumulated in a
+single register, generating a list of factors that fit in a machine word. This
+list is then split into halves, and the product is computed recursively.
+
+Such splitting is more efficient than repeated N@cross{}1 multiplies since it
+forms big multiplies, allowing Karatsuba and higher algorithms to be used.
+And even below the Karatsuba threshold a big block of work can be more
+efficient for the basecase algorithm.
+
+
+@node Binomial Coefficients Algorithm, Fibonacci Numbers Algorithm, Factorial Algorithm, Other Algorithms
+@subsection Binomial Coefficients
+@cindex Binomial coefficient algorithm
+
+Binomial coefficients @m{\left({n}\atop{k}\right), C(n@C{}k)} are calculated
+by first arranging @math{k @le{} n/2} using @m{\left({n}\atop{k}\right) =
+\left({n}\atop{n-k}\right), C(n@C{}k) = C(n@C{}n-k)} if necessary, and then
+evaluating the following product simply from @math{i=2} to @math{i=k}.
+@tex
+$$ \left({n}\atop{k}\right) = (n-k+1) \prod_{i=2}^{k} {{n-k+i} \over i} $$
+@end tex
+@ifnottex
+
+@example
+                      k  (n-k+i)
+C(n,k) =  (n-k+1) * prod -------
+                     i=2    i
+@end example
+
+@end ifnottex
+It's easy to show that each denominator @math{i} will divide the product so
+far, so the exact division algorithm is used (@pxref{Exact Division}).
+
+The numerators @math{n-k+i} and denominators @math{i} are first accumulated
+into as many fit a limb, to save multi-precision operations, though for
+@code{mpz_bin_ui} this applies only to the divisors, since @math{n} is an
+@code{mpz_t} and @math{n-k+i} in general won't fit in a limb at all.
+
+
+@node Fibonacci Numbers Algorithm, Lucas Numbers Algorithm, Binomial Coefficients Algorithm, Other Algorithms
+@subsection Fibonacci Numbers
+@cindex Fibonacci number algorithm
+
+The Fibonacci functions @code{mpz_fib_ui} and @code{mpz_fib2_ui} are designed
+for calculating isolated @m{F_n,F[n]} or @m{F_n,F[n]},@m{F_{n-1},F[n-1]}
+values efficiently.
+
+For small @math{n}, a table of single limb values in @code{__gmp_fib_table} is
+used.  On a 32-bit limb this goes up to @m{F_{47},F[47]}, or on a 64-bit limb
+up to @m{F_{93},F[93]}.  For convenience the table starts at @m{F_{-1},F[-1]}.
+
+Beyond the table, values are generated with a binary powering algorithm,
+calculating a pair @m{F_n,F[n]} and @m{F_{n-1},F[n-1]} working from high to
+low across the bits of @math{n}.  The formulas used are
+@tex
+$$\eqalign{
+  F_{2k+1} &= 4F_k^2 - F_{k-1}^2 + 2(-1)^k \cr
+  F_{2k-1} &=  F_k^2 + F_{k-1}^2           \cr
+  F_{2k}   &= F_{2k+1} - F_{2k-1}
+}$$
+@end tex
+@ifnottex
+
+@example
+F[2k+1] = 4*F[k]^2 - F[k-1]^2 + 2*(-1)^k
+F[2k-1] =   F[k]^2 + F[k-1]^2
+
+F[2k] = F[2k+1] - F[2k-1]
+@end example
+
+@end ifnottex
+At each step, @math{k} is the high @math{b} bits of @math{n}.  If the next bit
+of @math{n} is 0 then @m{F_{2k},F[2k]},@m{F_{2k-1},F[2k-1]} is used, or if
+it's a 1 then @m{F_{2k+1},F[2k+1]},@m{F_{2k},F[2k]} is used, and the process
+repeated until all bits of @math{n} are incorporated.  Notice these formulas
+require just two squares per bit of @math{n}.
+
+It'd be possible to handle the first few @math{n} above the single limb table
+with simple additions, using the defining Fibonacci recurrence @m{F_{k+1} =
+F_k + F_{k-1}, F[k+1]=F[k]+F[k-1]}, but this is not done since it usually
+turns out to be faster for only about 10 or 20 values of @math{n}, and
+including a block of code for just those doesn't seem worthwhile.  If they
+really mattered it'd be better to extend the data table.
+
+Using a table avoids lots of calculations on small numbers, and makes small
+@math{n} go fast.  A bigger table would make more small @math{n} go fast, it's
+just a question of balancing size against desired speed.  For GMP the code is
+kept compact, with the emphasis primarily on a good powering algorithm.
+
+@code{mpz_fib2_ui} returns both @m{F_n,F[n]} and @m{F_{n-1},F[n-1]}, but
+@code{mpz_fib_ui} is only interested in @m{F_n,F[n]}.  In this case the last
+step of the algorithm can become one multiply instead of two squares.  One of
+the following two formulas is used, according as @math{n} is odd or even.
+@tex
+$$\eqalign{
+  F_{2k}   &= F_k (F_k + 2F_{k-1}) \cr
+  F_{2k+1} &= (2F_k + F_{k-1}) (2F_k - F_{k-1}) + 2(-1)^k
+}$$
+@end tex
+@ifnottex
+
+@example
+F[2k]   = F[k]*(F[k]+2F[k-1])
+
+F[2k+1] = (2F[k]+F[k-1])*(2F[k]-F[k-1]) + 2*(-1)^k
+@end example
+
+@end ifnottex
+@m{F_{2k+1},F[2k+1]} here is the same as above, just rearranged to be a
+multiply.  For interest, the @m{2(-1)^k, 2*(-1)^k} term both here and above
+can be applied just to the low limb of the calculation, without a carry or
+borrow into further limbs, which saves some code size.  See comments with
+@code{mpz_fib_ui} and the internal @code{mpn_fib2_ui} for how this is done.
+
+
+@node Lucas Numbers Algorithm, Random Number Algorithms, Fibonacci Numbers Algorithm, Other Algorithms
+@subsection Lucas Numbers
+@cindex Lucas number algorithm
+
+@code{mpz_lucnum2_ui} derives a pair of Lucas numbers from a pair of Fibonacci
+numbers with the following simple formulas.
+@tex
+$$\eqalign{
+  L_k     &=  F_k + 2F_{k-1} \cr
+  L_{k-1} &= 2F_k -  F_{k-1}
+}$$
+@end tex
+@ifnottex
+
+@example
+L[k]   =   F[k] + 2*F[k-1]
+L[k-1] = 2*F[k] -   F[k-1]
+@end example
+
+@end ifnottex
+@code{mpz_lucnum_ui} is only interested in @m{L_n,L[n]}, and some work can be
+saved.  Trailing zero bits on @math{n} can be handled with a single square
+each.
+@tex
+$$ L_{2k} = L_k^2 - 2(-1)^k $$
+@end tex
+@ifnottex
+
+@example
+L[2k] = L[k]^2 - 2*(-1)^k
+@end example
+
+@end ifnottex
+And the lowest 1 bit can be handled with one multiply of a pair of Fibonacci
+numbers, similar to what @code{mpz_fib_ui} does.
+@tex
+$$ L_{2k+1} = 5F_{k-1} (2F_k + F_{k-1}) - 4(-1)^k $$
+@end tex
+@ifnottex
+
+@example
+L[2k+1] = 5*F[k-1]*(2*F[k]+F[k-1]) - 4*(-1)^k
+@end example
+
+@end ifnottex
+
+
+@node Random Number Algorithms,  , Lucas Numbers Algorithm, Other Algorithms
+@subsection Random Numbers
+@cindex Random number algorithms
+
+For the @code{urandomb} functions, random numbers are generated simply by
+concatenating bits produced by the generator.  As long as the generator has
+good randomness properties this will produce well-distributed @math{N} bit
+numbers.
+
+For the @code{urandomm} functions, random numbers in a range @math{0@le{}R<N}
+are generated by taking values @math{R} of @m{\lceil \log_2 N \rceil,
+ceil(log2(N))} bits each until one satisfies @math{R<N}.  This will normally
+require only one or two attempts, but the attempts are limited in case the
+generator is somehow degenerate and produces only 1 bits or similar.
+
+@cindex Mersenne twister algorithm
+The Mersenne Twister generator is by Matsumoto and Nishimura
+(@pxref{References}).  It has a non-repeating period of @math{2^@W{19937}-1},
+which is a Mersenne prime, hence the name of the generator.  The state is 624
+words of 32-bits each, which is iterated with one XOR and shift for each
+32-bit word generated, making the algorithm very fast.  Randomness properties
+are also very good and this is the default algorithm used by GMP.
+
+@cindex Linear congruential algorithm
+Linear congruential generators are described in many text books, for instance
+Knuth volume 2 (@pxref{References}).  With a modulus @math{M} and parameters
+@math{A} and @math{C}, an integer state @math{S} is iterated by the formula
+@math{S @leftarrow{} A@GMPmultiply{}S+C @bmod{} M}.  At each step the new
+state is a linear function of the previous, mod @math{M}, hence the name of
+the generator.
+
+In GMP only moduli of the form @math{2^N} are supported, and the current
+implementation is not as well optimized as it could be.  Overheads are
+significant when @math{N} is small, and when @math{N} is large clearly the
+multiply at each step will become slow.  This is not a big concern, since the
+Mersenne Twister generator is better in every respect and is therefore
+recommended for all normal applications.
+
+For both generators the current state can be deduced by observing enough
+output and applying some linear algebra (over GF(2) in the case of the
+Mersenne Twister).  This generally means raw output is unsuitable for
+cryptographic applications without further hashing or the like.
+
+
+@node Assembly Coding,  , Other Algorithms, Algorithms
+@section Assembly Coding
+@cindex Assembly coding
+
+The assembly subroutines in GMP are the most significant source of speed at
+small to moderate sizes.  At larger sizes algorithm selection becomes more
+important, but of course speedups in low level routines will still speed up
+everything proportionally.
+
+Carry handling and widening multiplies that are important for GMP can't be
+easily expressed in C@.  GCC @code{asm} blocks help a lot and are provided in
+@file{longlong.h}, but hand coding low level routines invariably offers a
+speedup over generic C by a factor of anything from 2 to 10.
+
+@menu
+* Assembly Code Organisation::
+* Assembly Basics::
+* Assembly Carry Propagation::
+* Assembly Cache Handling::
+* Assembly Functional Units::
+* Assembly Floating Point::
+* Assembly SIMD Instructions::
+* Assembly Software Pipelining::
+* Assembly Loop Unrolling::
+* Assembly Writing Guide::
+@end menu
+
+
+@node Assembly Code Organisation, Assembly Basics, Assembly Coding, Assembly Coding
+@subsection Code Organisation
+@cindex Assembly code organisation
+@cindex Code organisation
+
+The various @file{mpn} subdirectories contain machine-dependent code, written
+in C or assembly.  The @file{mpn/generic} subdirectory contains default code,
+used when there's no machine-specific version of a particular file.
+
+Each @file{mpn} subdirectory is for an ISA family.  Generally 32-bit and
+64-bit variants in a family cannot share code and have separate directories.
+Within a family further subdirectories may exist for CPU variants.
+
+In each directory a @file{nails} subdirectory may exist, holding code with
+nails support for that CPU variant.  A @code{NAILS_SUPPORT} directive in each
+file indicates the nails values the code handles.  Nails code only exists
+where it's faster, or promises to be faster, than plain code.  There's no
+effort put into nails if they're not going to enhance a given CPU.
+
+
+@node Assembly Basics, Assembly Carry Propagation, Assembly Code Organisation, Assembly Coding
+@subsection Assembly Basics
+
+@code{mpn_addmul_1} and @code{mpn_submul_1} are the most important routines
+for overall GMP performance.  All multiplications and divisions come down to
+repeated calls to these.  @code{mpn_add_n}, @code{mpn_sub_n},
+@code{mpn_lshift} and @code{mpn_rshift} are next most important.
+
+On some CPUs assembly versions of the internal functions
+@code{mpn_mul_basecase} and @code{mpn_sqr_basecase} give significant speedups,
+mainly through avoiding function call overheads.  They can also potentially
+make better use of a wide superscalar processor, as can bigger primitives like
+@code{mpn_addmul_2} or @code{mpn_addmul_4}.
+
+The restrictions on overlaps between sources and destinations
+(@pxref{Low-level Functions}) are designed to facilitate a variety of
+implementations.  For example, knowing @code{mpn_add_n} won't have partly
+overlapping sources and destination means reading can be done far ahead of
+writing on superscalar processors, and loops can be vectorized on a vector
+processor, depending on the carry handling.
+
+
+@node Assembly Carry Propagation, Assembly Cache Handling, Assembly Basics, Assembly Coding
+@subsection Carry Propagation
+@cindex Assembly carry propagation
+
+The problem that presents most challenges in GMP is propagating carries from
+one limb to the next.  In functions like @code{mpn_addmul_1} and
+@code{mpn_add_n}, carries are the only dependencies between limb operations.
+
+On processors with carry flags, a straightforward CISC style @code{adc} is
+generally best.  AMD K6 @code{mpn_addmul_1} however is an example of an
+unusual set of circumstances where a branch works out better.
+
+On RISC processors generally an add and compare for overflow is used.  This
+sort of thing can be seen in @file{mpn/generic/aors_n.c}.  Some carry
+propagation schemes require 4 instructions, meaning at least 4 cycles per
+limb, but other schemes may use just 1 or 2.  On wide superscalar processors
+performance may be completely determined by the number of dependent
+instructions between carry-in and carry-out for each limb.
+
+On vector processors good use can be made of the fact that a carry bit only
+very rarely propagates more than one limb.  When adding a single bit to a
+limb, there's only a carry out if that limb was @code{0xFF@dots{}FF} which on
+random data will be only 1 in @m{2\GMPraise{@code{mp\_bits\_per\_limb}},
+2^mp_bits_per_limb}.  @file{mpn/cray/add_n.c} is an example of this, it adds
+all limbs in parallel, adds one set of carry bits in parallel and then only
+rarely needs to fall through to a loop propagating further carries.
+
+On the x86s, GCC (as of version 2.95.2) doesn't generate particularly good code
+for the RISC style idioms that are necessary to handle carry bits in
+C@.  Often conditional jumps are generated where @code{adc} or @code{sbb} forms
+would be better.  And so unfortunately almost any loop involving carry bits
+needs to be coded in assembly for best results.
+
+
+@node Assembly Cache Handling, Assembly Functional Units, Assembly Carry Propagation, Assembly Coding
+@subsection Cache Handling
+@cindex Assembly cache handling
+
+GMP aims to perform well both on operands that fit entirely in L1 cache and
+those which don't.
+
+Basic routines like @code{mpn_add_n} or @code{mpn_lshift} are often used on
+large operands, so L2 and main memory performance is important for them.
+@code{mpn_mul_1} and @code{mpn_addmul_1} are mostly used for multiply and
+square basecases, so L1 performance matters most for them, unless assembly
+versions of @code{mpn_mul_basecase} and @code{mpn_sqr_basecase} exist, in
+which case the remaining uses are mostly for larger operands.
+
+For L2 or main memory operands, memory access times will almost certainly be
+more than the calculation time.  The aim therefore is to maximize memory
+throughput, by starting a load of the next cache line while processing the
+contents of the previous one.  Clearly this is only possible if the chip has a
+lock-up free cache or some sort of prefetch instruction.  Most current chips
+have both these features.
+
+Prefetching sources combines well with loop unrolling, since a prefetch can be
+initiated once per unrolled loop (or more than once if the loop covers more
+than one cache line).
+
+On CPUs without write-allocate caches, prefetching destinations will ensure
+individual stores don't go further down the cache hierarchy, limiting
+bandwidth.  Of course for calculations which are slow anyway, like
+@code{mpn_divrem_1}, write-throughs might be fine.
+
+The distance ahead to prefetch will be determined by memory latency versus
+throughput.  The aim of course is to have data arriving continuously, at peak
+throughput.  Some CPUs have limits on the number of fetches or prefetches in
+progress.
+
+If a special prefetch instruction doesn't exist then a plain load can be used,
+but in that case care must be taken not to attempt to read past the end of an
+operand, since that might produce a segmentation violation.
+
+Some CPUs or systems have hardware that detects sequential memory accesses and
+initiates suitable cache movements automatically, making life easy.
+
+
+@node Assembly Functional Units, Assembly Floating Point, Assembly Cache Handling, Assembly Coding
+@subsection Functional Units
+
+When choosing an approach for an assembly loop, consideration is given to
+what operations can execute simultaneously and what throughput can thereby be
+achieved.  In some cases an algorithm can be tweaked to accommodate available
+resources.
+
+Loop control will generally require a counter and pointer updates, costing as
+much as 5 instructions, plus any delays a branch introduces.  CPU addressing
+modes might reduce pointer updates, perhaps by allowing just one updating
+pointer and others expressed as offsets from it, or on CISC chips with all
+addressing done with the loop counter as a scaled index.
+
+The final loop control cost can be amortised by processing several limbs in
+each iteration (@pxref{Assembly Loop Unrolling}).  This at least ensures loop
+control isn't a big fraction the work done.
+
+Memory throughput is always a limit.  If perhaps only one load or one store
+can be done per cycle then 3 cycles/limb will the top speed for ``binary''
+operations like @code{mpn_add_n}, and any code achieving that is optimal.
+
+Integer resources can be freed up by having the loop counter in a float
+register, or by pressing the float units into use for some multiplying,
+perhaps doing every second limb on the float side (@pxref{Assembly Floating
+Point}).
+
+Float resources can be freed up by doing carry propagation on the integer
+side, or even by doing integer to float conversions in integers using bit
+twiddling.
+
+
+@node Assembly Floating Point, Assembly SIMD Instructions, Assembly Functional Units, Assembly Coding
+@subsection Floating Point
+@cindex Assembly floating Point
+
+Floating point arithmetic is used in GMP for multiplications on CPUs with poor
+integer multipliers.  It's mostly useful for @code{mpn_mul_1},
+@code{mpn_addmul_1} and @code{mpn_submul_1} on 64-bit machines, and
+@code{mpn_mul_basecase} on both 32-bit and 64-bit machines.
+
+With IEEE 53-bit double precision floats, integer multiplications producing up
+to 53 bits will give exact results.  Breaking a 64@cross{}64 multiplication
+into eight 16@cross{}@math{32@rightarrow{}48} bit pieces is convenient.  With
+some care though six 21@cross{}@math{32@rightarrow{}53} bit products can be
+used, if one of the lower two 21-bit pieces also uses the sign bit.
+
+For the @code{mpn_mul_1} family of functions on a 64-bit machine, the
+invariant single limb is split at the start, into 3 or 4 pieces.  Inside the
+loop, the bignum operand is split into 32-bit pieces.  Fast conversion of
+these unsigned 32-bit pieces to floating point is highly machine-dependent.
+In some cases, reading the data into the integer unit, zero-extending to
+64-bits, then transferring to the floating point unit back via memory is the
+only option.
+
+Converting partial products back to 64-bit limbs is usually best done as a
+signed conversion.  Since all values are smaller than @m{2^{53},2^53}, signed
+and unsigned are the same, but most processors lack unsigned conversions.
+
+@sp 2
+
+Here is a diagram showing 16@cross{}32 bit products for an @code{mpn_mul_1} or
+@code{mpn_addmul_1} with a 64-bit limb.  The single limb operand V is split
+into four 16-bit parts.  The multi-limb operand U is split in the loop into
+two 32-bit parts.
+
+@tex
+\global\newdimen\GMPbits      \global\GMPbits=0.18em
+\def\GMPbox#1#2#3{%
+  \hbox{%
+    \hbox to 128\GMPbits{\hfil
+      \vbox{%
+        \hrule
+        \hbox to 48\GMPbits {\GMPvrule \hfil$#2$\hfil \vrule}%
+        \hrule}%
+      \hskip #1\GMPbits}%
+    \raise \GMPboxdepth \hbox{\hskip 2em #3}}}
+%
+\GMPdisplay{%
+  \vbox{%
+    \hbox{%
+      \hbox to 128\GMPbits {\hfil
+        \vbox{%
+          \hrule
+          \hbox to 64\GMPbits{%
+            \GMPvrule \hfil$v48$\hfil
+            \vrule    \hfil$v32$\hfil
+            \vrule    \hfil$v16$\hfil
+            \vrule    \hfil$v00$\hfil
+            \vrule}
+          \hrule}}%
+       \raise \GMPboxdepth \hbox{\hskip 2em V Operand}}
+    \vskip 0.5ex
+    \hbox{%
+      \hbox to 128\GMPbits {\hfil
+        \raise \GMPboxdepth \hbox{$\times$\hskip 1.5em}%
+        \vbox{%
+          \hrule
+          \hbox to 64\GMPbits {%
+            \GMPvrule \hfil$u32$\hfil
+            \vrule \hfil$u00$\hfil
+            \vrule}%
+          \hrule}}%
+       \raise \GMPboxdepth \hbox{\hskip 2em U Operand (one limb)}}%
+    \vskip 0.5ex
+    \hbox{\vbox to 2ex{\hrule width 128\GMPbits}}%
+    \GMPbox{0}{u00 \times v00}{$p00$\hskip 1.5em 48-bit products}%
+    \vskip 0.5ex
+    \GMPbox{16}{u00 \times v16}{$p16$}
+    \vskip 0.5ex
+    \GMPbox{32}{u00 \times v32}{$p32$}
+    \vskip 0.5ex
+    \GMPbox{48}{u00 \times v48}{$p48$}
+    \vskip 0.5ex
+    \GMPbox{32}{u32 \times v00}{$r32$}
+    \vskip 0.5ex
+    \GMPbox{48}{u32 \times v16}{$r48$}
+    \vskip 0.5ex
+    \GMPbox{64}{u32 \times v32}{$r64$}
+    \vskip 0.5ex
+    \GMPbox{80}{u32 \times v48}{$r80$}
+}}
+@end tex
+@ifnottex
+@example
+@group
+                +---+---+---+---+
+                |v48|v32|v16|v00|    V operand
+                +---+---+---+---+
+
+                +-------+---+---+
+            x   |  u32  |  u00  |    U operand (one limb)
+                +---------------+
+
+---------------------------------
+
+                    +-----------+
+                    | u00 x v00 |    p00    48-bit products
+                    +-----------+
+                +-----------+
+                | u00 x v16 |        p16
+                +-----------+
+            +-----------+
+            | u00 x v32 |            p32
+            +-----------+
+        +-----------+
+        | u00 x v48 |                p48
+        +-----------+
+            +-----------+
+            | u32 x v00 |            r32
+            +-----------+
+        +-----------+
+        | u32 x v16 |                r48
+        +-----------+
+    +-----------+
+    | u32 x v32 |                    r64
+    +-----------+
++-----------+
+| u32 x v48 |                        r80
++-----------+
+@end group
+@end example
+@end ifnottex
+
+@math{p32} and @math{r32} can be summed using floating-point addition, and
+likewise @math{p48} and @math{r48}.  @math{p00} and @math{p16} can be summed
+with @math{r64} and @math{r80} from the previous iteration.
+
+For each loop then, four 49-bit quantities are transferred to the integer unit,
+aligned as follows,
+
+@tex
+% GMPbox here should be 49 bits wide, but use 51 to better show p16+r80'
+% crossing into the upper 64 bits.
+\def\GMPbox#1#2#3{%
+  \hbox{%
+    \hbox to 128\GMPbits {%
+      \hfil
+      \vbox{%
+        \hrule
+        \hbox to 51\GMPbits {\GMPvrule \hfil$#2$\hfil \vrule}%
+        \hrule}%
+      \hskip #1\GMPbits}%
+    \raise \GMPboxdepth \hbox{\hskip 1.5em $#3$\hfil}%
+}}
+\newbox\b \setbox\b\hbox{64 bits}%
+\newdimen\bw \bw=\wd\b \advance\bw by 2em
+\newdimen\x \x=128\GMPbits
+\advance\x by -2\bw
+\divide\x by4
+\GMPdisplay{%
+  \vbox{%
+    \hbox to 128\GMPbits {%
+      \GMPvrule
+      \raise 0.5ex \vbox{\hrule \hbox to \x {}}%
+      \hfil 64 bits\hfil
+      \raise 0.5ex \vbox{\hrule \hbox to \x {}}%
+      \vrule
+      \raise 0.5ex \vbox{\hrule \hbox to \x {}}%
+      \hfil 64 bits\hfil
+      \raise 0.5ex \vbox{\hrule \hbox to \x {}}%
+      \vrule}%
+    \vskip 0.7ex
+    \GMPbox{0}{p00+r64'}{i00}
+    \vskip 0.5ex
+    \GMPbox{16}{p16+r80'}{i16}
+    \vskip 0.5ex
+    \GMPbox{32}{p32+r32}{i32}
+    \vskip 0.5ex
+    \GMPbox{48}{p48+r48}{i48}
+}}
+@end tex
+@ifnottex
+@example
+@group
+|-----64bits----|-----64bits----|
+                   +------------+
+                   | p00 + r64' |    i00
+                   +------------+
+               +------------+
+               | p16 + r80' |        i16
+               +------------+
+           +------------+
+           | p32 + r32  |            i32
+           +------------+
+       +------------+
+       | p48 + r48  |                i48
+       +------------+
+@end group
+@end example
+@end ifnottex
+
+The challenge then is to sum these efficiently and add in a carry limb,
+generating a low 64-bit result limb and a high 33-bit carry limb (@math{i48}
+extends 33 bits into the high half).
+
+
+@node Assembly SIMD Instructions, Assembly Software Pipelining, Assembly Floating Point, Assembly Coding
+@subsection SIMD Instructions
+@cindex Assembly SIMD
+
+The single-instruction multiple-data support in current microprocessors is
+aimed at signal processing algorithms where each data point can be treated
+more or less independently.  There's generally not much support for
+propagating the sort of carries that arise in GMP.
+
+SIMD multiplications of say four 16@cross{}16 bit multiplies only do as much
+work as one 32@cross{}32 from GMP's point of view, and need some shifts and
+adds besides.  But of course if say the SIMD form is fully pipelined and uses
+less instruction decoding then it may still be worthwhile.
+
+On the x86 chips, MMX has so far found a use in @code{mpn_rshift} and
+@code{mpn_lshift}, and is used in a special case for 16-bit multipliers in the
+P55 @code{mpn_mul_1}.  SSE2 is used for Pentium 4 @code{mpn_mul_1},
+@code{mpn_addmul_1}, and @code{mpn_submul_1}.
+
+
+@node Assembly Software Pipelining, Assembly Loop Unrolling, Assembly SIMD Instructions, Assembly Coding
+@subsection Software Pipelining
+@cindex Assembly software pipelining
+
+Software pipelining consists of scheduling instructions around the branch
+point in a loop.  For example a loop might issue a load not for use in the
+present iteration but the next, thereby allowing extra cycles for the data to
+arrive from memory.
+
+Naturally this is wanted only when doing things like loads or multiplies that
+take several cycles to complete, and only where a CPU has multiple functional
+units so that other work can be done in the meantime.
+
+A pipeline with several stages will have a data value in progress at each
+stage and each loop iteration moves them along one stage.  This is like
+juggling.
+
+If the latency of some instruction is greater than the loop time then it will
+be necessary to unroll, so one register has a result ready to use while
+another (or multiple others) are still in progress.  (@pxref{Assembly Loop
+Unrolling}).
+
+
+@node Assembly Loop Unrolling, Assembly Writing Guide, Assembly Software Pipelining, Assembly Coding
+@subsection Loop Unrolling
+@cindex Assembly loop unrolling
+
+Loop unrolling consists of replicating code so that several limbs are
+processed in each loop.  At a minimum this reduces loop overheads by a
+corresponding factor, but it can also allow better register usage, for example
+alternately using one register combination and then another.  Judicious use of
+@command{m4} macros can help avoid lots of duplication in the source code.
+
+Any amount of unrolling can be handled with a loop counter that's decremented
+by @math{N} each time, stopping when the remaining count is less than the
+further @math{N} the loop will process.  Or by subtracting @math{N} at the
+start, the termination condition becomes when the counter @math{C} is less
+than 0 (and the count of remaining limbs is @math{C+N}).
+
+Alternately for a power of 2 unroll the loop count and remainder can be
+established with a shift and mask.  This is convenient if also making a
+computed jump into the middle of a large loop.
+
+The limbs not a multiple of the unrolling can be handled in various ways, for
+example
+
+@itemize @bullet
+@item
+A simple loop at the end (or the start) to process the excess.  Care will be
+wanted that it isn't too much slower than the unrolled part.
+
+@item
+A set of binary tests, for example after an 8-limb unrolling, test for 4 more
+limbs to process, then a further 2 more or not, and finally 1 more or not.
+This will probably take more code space than a simple loop.
+
+@item
+A @code{switch} statement, providing separate code for each possible excess,
+for example an 8-limb unrolling would have separate code for 0 remaining, 1
+remaining, etc, up to 7 remaining.  This might take a lot of code, but may be
+the best way to optimize all cases in combination with a deep pipelined loop.
+
+@item
+A computed jump into the middle of the loop, thus making the first iteration
+handle the excess.  This should make times smoothly increase with size, which
+is attractive, but setups for the jump and adjustments for pointers can be
+tricky and could become quite difficult in combination with deep pipelining.
+@end itemize
+
+
+@node Assembly Writing Guide,  , Assembly Loop Unrolling, Assembly Coding
+@subsection Writing Guide
+@cindex Assembly writing guide
+
+This is a guide to writing software pipelined loops for processing limb
+vectors in assembly.
+
+First determine the algorithm and which instructions are needed.  Code it
+without unrolling or scheduling, to make sure it works.  On a 3-operand CPU
+try to write each new value to a new register, this will greatly simplify later
+steps.
+
+Then note for each instruction the functional unit and/or issue port
+requirements.  If an instruction can use either of two units, like U0 or U1
+then make a category ``U0/U1''.  Count the total using each unit (or combined
+unit), and count all instructions.
+
+Figure out from those counts the best possible loop time.  The goal will be to
+find a perfect schedule where instruction latencies are completely hidden.
+The total instruction count might be the limiting factor, or perhaps a
+particular functional unit.  It might be possible to tweak the instructions to
+help the limiting factor.
+
+Suppose the loop time is @math{N}, then make @math{N} issue buckets, with the
+final loop branch at the end of the last.  Now fill the buckets with dummy
+instructions using the functional units desired.  Run this to make sure the
+intended speed is reached.
+
+Now replace the dummy instructions with the real instructions from the slow
+but correct loop you started with.  The first will typically be a load
+instruction.  Then the instruction using that value is placed in a bucket an
+appropriate distance down.  Run the loop again, to check it still runs at
+target speed.
+
+Keep placing instructions, frequently measuring the loop.  After a few you
+will need to wrap around from the last bucket back to the top of the loop.  If
+you used the new-register for new-value strategy above then there will be no
+register conflicts.  If not then take care not to clobber something already in
+use.  Changing registers at this time is very error prone.
+
+The loop will overlap two or more of the original loop iterations, and the
+computation of one vector element result will be started in one iteration of
+the new loop, and completed one or several iterations later.
+
+The final step is to create feed-in and wind-down code for the loop.  A good
+way to do this is to make a copy (or copies) of the loop at the start and
+delete those instructions which don't have valid antecedents, and at the end
+replicate and delete those whose results are unwanted (including any further
+loads).
+
+The loop will have a minimum number of limbs loaded and processed, so the
+feed-in code must test if the request size is smaller and skip either to a
+suitable part of the wind-down or to special code for small sizes.
+
+
+@node Internals, Contributors, Algorithms, Top
+@chapter Internals
+@cindex Internals
+
+@strong{This chapter is provided only for informational purposes and the
+various internals described here may change in future GMP releases.
+Applications expecting to be compatible with future releases should use only
+the documented interfaces described in previous chapters.}
+
+@menu
+* Integer Internals::
+* Rational Internals::
+* Float Internals::
+* Raw Output Internals::
+* C++ Interface Internals::
+@end menu
+
+@node Integer Internals, Rational Internals, Internals, Internals
+@section Integer Internals
+@cindex Integer internals
+
+@code{mpz_t} variables represent integers using sign and magnitude, in space
+dynamically allocated and reallocated.  The fields are as follows.
+
+@table @asis
+@item @code{_mp_size}
+The number of limbs, or the negative of that when representing a negative
+integer.  Zero is represented by @code{_mp_size} set to zero, in which case
+the @code{_mp_d} data is undefined.
+
+@item @code{_mp_d}
+A pointer to an array of limbs which is the magnitude.  These are stored
+``little endian'' as per the @code{mpn} functions, so @code{_mp_d[0]} is the
+least significant limb and @code{_mp_d[ABS(_mp_size)-1]} is the most
+significant.  Whenever @code{_mp_size} is non-zero, the most significant limb
+is non-zero.
+
+Currently there's always at least one readable limb, so for instance
+@code{mpz_get_ui} can fetch @code{_mp_d[0]} unconditionally (though its value
+is undefined if @code{_mp_size} is zero).
+
+@item @code{_mp_alloc}
+@code{_mp_alloc} is the number of limbs currently allocated at @code{_mp_d},
+and normally @code{_mp_alloc >= ABS(_mp_size)}.  When an @code{mpz} routine
+is about to (or might be about to) increase @code{_mp_size}, it checks
+@code{_mp_alloc} to see whether there's enough space, and reallocates if not.
+@code{MPZ_REALLOC} is generally used for this.
+
+@code{mpz_t} variables initialised with the @code{mpz_roinit_n} function or
+the @code{MPZ_ROINIT_N} macro have @code{_mp_alloc = 0} but can have a
+non-zero @code{_mp_size}.  They can only be used as read-only constants. See
+@ref{Integer Special Functions} for details.
+@end table
+
+The various bitwise logical functions like @code{mpz_and} behave as if
+negative values were twos complement.  But sign and magnitude is always used
+internally, and necessary adjustments are made during the calculations.
+Sometimes this isn't pretty, but sign and magnitude are best for other
+routines.
+
+Some internal temporary variables are setup with @code{MPZ_TMP_INIT} and these
+have @code{_mp_d} space obtained from @code{TMP_ALLOC} rather than the memory
+allocation functions.  Care is taken to ensure that these are big enough that
+no reallocation is necessary (since it would have unpredictable consequences).
+
+@code{_mp_size} and @code{_mp_alloc} are @code{int}, although @code{mp_size_t}
+is usually a @code{long}.  This is done to make the fields just 32 bits on
+some 64 bits systems, thereby saving a few bytes of data space but still
+providing plenty of range.
+
+
+@node Rational Internals, Float Internals, Integer Internals, Internals
+@section Rational Internals
+@cindex Rational internals
+
+@code{mpq_t} variables represent rationals using an @code{mpz_t} numerator and
+denominator (@pxref{Integer Internals}).
+
+The canonical form adopted is denominator positive (and non-zero), no common
+factors between numerator and denominator, and zero uniquely represented as
+0/1.
+
+It's believed that casting out common factors at each stage of a calculation
+is best in general.  A GCD is an @math{O(N^2)} operation so it's better to do
+a few small ones immediately than to delay and have to do a big one later.
+Knowing the numerator and denominator have no common factors can be used for
+example in @code{mpq_mul} to make only two cross GCDs necessary, not four.
+
+This general approach to common factors is badly sub-optimal in the presence
+of simple factorizations or little prospect for cancellation, but GMP has no
+way to know when this will occur.  As per @ref{Efficiency}, that's left to
+applications.  The @code{mpq_t} framework might still suit, with
+@code{mpq_numref} and @code{mpq_denref} for direct access to the numerator and
+denominator, or of course @code{mpz_t} variables can be used directly.
+
+
+@node Float Internals, Raw Output Internals, Rational Internals, Internals
+@section Float Internals
+@cindex Float internals
+
+Efficient calculation is the primary aim of GMP floats and the use of whole
+limbs and simple rounding facilitates this.
+
+@code{mpf_t} floats have a variable precision mantissa and a single machine
+word signed exponent.  The mantissa is represented using sign and magnitude.
+
+@c FIXME: The arrow heads don't join to the lines exactly.
+@tex
+\global\newdimen\GMPboxwidth \GMPboxwidth=5em
+\global\newdimen\GMPboxheight \GMPboxheight=3ex
+\def\centreline{\hbox{\raise 0.8ex \vbox{\hrule \hbox{\hfil}}}}
+\GMPdisplay{%
+\vbox{%
+  \hbox to 5\GMPboxwidth {most significant limb \hfil least significant limb}
+  \vskip 0.7ex
+  \def\GMPcentreline#1{\hbox{\raise 0.5 ex \vbox{\hrule \hbox to #1 {}}}}
+  \hbox {
+    \hbox to 3\GMPboxwidth {%
+      \setbox 0 = \hbox{@code{\_mp\_exp}}%
+      \dimen0=3\GMPboxwidth
+      \advance\dimen0 by -\wd0
+      \divide\dimen0 by 2
+      \advance\dimen0 by -1em
+      \setbox1 = \hbox{$\rightarrow$}%
+      \dimen1=\dimen0
+      \advance\dimen1 by -\wd1
+      \GMPcentreline{\dimen0}%
+      \hfil
+      \box0%
+      \hfil
+      \GMPcentreline{\dimen1{}}%
+      \box1}
+    \hbox to 2\GMPboxwidth {\hfil @code{\_mp\_d}}}
+  \vskip 0.5ex
+  \vbox {%
+    \hrule
+    \hbox{%
+      \vrule height 2ex depth 1ex
+      \hbox to \GMPboxwidth {}%
+      \vrule
+      \hbox to \GMPboxwidth {}%
+      \vrule
+      \hbox to \GMPboxwidth {}%
+      \vrule
+      \hbox to \GMPboxwidth {}%
+      \vrule
+      \hbox to \GMPboxwidth {}%
+      \vrule}
+    \hrule
+  }
+  \hbox {%
+    \hbox to 0.8 pt {}
+    \hbox to 3\GMPboxwidth {%
+      \hfil $\cdot$} \hbox {$\leftarrow$ radix point\hfil}}
+  \hbox to 5\GMPboxwidth{%
+    \setbox 0 = \hbox{@code{\_mp\_size}}%
+    \dimen0 = 5\GMPboxwidth
+    \advance\dimen0 by -\wd0
+    \divide\dimen0 by 2
+    \advance\dimen0 by -1em
+    \dimen1 = \dimen0
+    \setbox1 = \hbox{$\leftarrow$}%
+    \setbox2 = \hbox{$\rightarrow$}%
+    \advance\dimen0 by -\wd1
+    \advance\dimen1 by -\wd2
+    \hbox to 0.3 em {}%
+    \box1
+    \GMPcentreline{\dimen0}%
+    \hfil
+    \box0
+    \hfil
+    \GMPcentreline{\dimen1}%
+    \box2}
+}}
+@end tex
+@ifnottex
+@example
+   most                   least
+significant            significant
+   limb                   limb
+
+                            _mp_d
+ |---- _mp_exp --->           |
+  _____ _____ _____ _____ _____
+ |_____|_____|_____|_____|_____|
+                   . <------------ radix point
+
+  <-------- _mp_size --------->
+@sp 1
+@end example
+@end ifnottex
+
+@noindent
+The fields are as follows.
+
+@table @asis
+@item @code{_mp_size}
+The number of limbs currently in use, or the negative of that when
+representing a negative value.  Zero is represented by @code{_mp_size} and
+@code{_mp_exp} both set to zero, and in that case the @code{_mp_d} data is
+unused.  (In the future @code{_mp_exp} might be undefined when representing
+zero.)
+
+@item @code{_mp_prec}
+The precision of the mantissa, in limbs.  In any calculation the aim is to
+produce @code{_mp_prec} limbs of result (the most significant being non-zero).
+
+@item @code{_mp_d}
+A pointer to the array of limbs which is the absolute value of the mantissa.
+These are stored ``little endian'' as per the @code{mpn} functions, so
+@code{_mp_d[0]} is the least significant limb and
+@code{_mp_d[ABS(_mp_size)-1]} the most significant.
+
+The most significant limb is always non-zero, but there are no other
+restrictions on its value, in particular the highest 1 bit can be anywhere
+within the limb.
+
+@code{_mp_prec+1} limbs are allocated to @code{_mp_d}, the extra limb being
+for convenience (see below).  There are no reallocations during a calculation,
+only in a change of precision with @code{mpf_set_prec}.
+
+@item @code{_mp_exp}
+The exponent, in limbs, determining the location of the implied radix point.
+Zero means the radix point is just above the most significant limb.  Positive
+values mean a radix point offset towards the lower limbs and hence a value
+@math{@ge{} 1}, as for example in the diagram above.  Negative exponents mean
+a radix point further above the highest limb.
+
+Naturally the exponent can be any value, it doesn't have to fall within the
+limbs as the diagram shows, it can be a long way above or a long way below.
+Limbs other than those included in the @code{@{_mp_d,_mp_size@}} data
+are treated as zero.
+@end table
+
+The @code{_mp_size} and @code{_mp_prec} fields are @code{int}, although the
+@code{mp_size_t} type is usually a @code{long}.  The @code{_mp_exp} field is
+usually @code{long}.  This is done to make some fields just 32 bits on some 64
+bits systems, thereby saving a few bytes of data space but still providing
+plenty of precision and a very large range.
+
+
+@sp 1
+@noindent
+The following various points should be noted.
+
+@table @asis
+@item Low Zeros
+The least significant limbs @code{_mp_d[0]} etc can be zero, though such low
+zeros can always be ignored.  Routines likely to produce low zeros check and
+avoid them to save time in subsequent calculations, but for most routines
+they're quite unlikely and aren't checked.
+
+@item Mantissa Size Range
+The @code{_mp_size} count of limbs in use can be less than @code{_mp_prec} if
+the value can be represented in less.  This means low precision values or
+small integers stored in a high precision @code{mpf_t} can still be operated
+on efficiently.
+
+@code{_mp_size} can also be greater than @code{_mp_prec}.  Firstly a value is
+allowed to use all of the @code{_mp_prec+1} limbs available at @code{_mp_d},
+and secondly when @code{mpf_set_prec_raw} lowers @code{_mp_prec} it leaves
+@code{_mp_size} unchanged and so the size can be arbitrarily bigger than
+@code{_mp_prec}.
+
+@item Rounding
+All rounding is done on limb boundaries.  Calculating @code{_mp_prec} limbs
+with the high non-zero will ensure the application requested minimum precision
+is obtained.
+
+The use of simple ``trunc'' rounding towards zero is efficient, since there's
+no need to examine extra limbs and increment or decrement.
+
+@item Bit Shifts
+Since the exponent is in limbs, there are no bit shifts in basic operations
+like @code{mpf_add} and @code{mpf_mul}.  When differing exponents are
+encountered all that's needed is to adjust pointers to line up the relevant
+limbs.
+
+Of course @code{mpf_mul_2exp} and @code{mpf_div_2exp} will require bit shifts,
+but the choice is between an exponent in limbs which requires shifts there, or
+one in bits which requires them almost everywhere else.
+
+@item Use of @code{_mp_prec+1} Limbs
+The extra limb on @code{_mp_d} (@code{_mp_prec+1} rather than just
+@code{_mp_prec}) helps when an @code{mpf} routine might get a carry from its
+operation.  @code{mpf_add} for instance will do an @code{mpn_add} of
+@code{_mp_prec} limbs.  If there's no carry then that's the result, but if
+there is a carry then it's stored in the extra limb of space and
+@code{_mp_size} becomes @code{_mp_prec+1}.
+
+Whenever @code{_mp_prec+1} limbs are held in a variable, the low limb is not
+needed for the intended precision, only the @code{_mp_prec} high limbs.  But
+zeroing it out or moving the rest down is unnecessary.  Subsequent routines
+reading the value will simply take the high limbs they need, and this will be
+@code{_mp_prec} if their target has that same precision.  This is no more than
+a pointer adjustment, and must be checked anyway since the destination
+precision can be different from the sources.
+
+Copy functions like @code{mpf_set} will retain a full @code{_mp_prec+1} limbs
+if available.  This ensures that a variable which has @code{_mp_size} equal to
+@code{_mp_prec+1} will get its full exact value copied.  Strictly speaking
+this is unnecessary since only @code{_mp_prec} limbs are needed for the
+application's requested precision, but it's considered that an @code{mpf_set}
+from one variable into another of the same precision ought to produce an exact
+copy.
+
+@item Application Precisions
+@code{__GMPF_BITS_TO_PREC} converts an application requested precision to an
+@code{_mp_prec}.  The value in bits is rounded up to a whole limb then an
+extra limb is added since the most significant limb of @code{_mp_d} is only
+non-zero and therefore might contain only one bit.
+
+@code{__GMPF_PREC_TO_BITS} does the reverse conversion, and removes the extra
+limb from @code{_mp_prec} before converting to bits.  The net effect of
+reading back with @code{mpf_get_prec} is simply the precision rounded up to a
+multiple of @code{mp_bits_per_limb}.
+
+Note that the extra limb added here for the high only being non-zero is in
+addition to the extra limb allocated to @code{_mp_d}.  For example with a
+32-bit limb, an application request for 250 bits will be rounded up to 8
+limbs, then an extra added for the high being only non-zero, giving an
+@code{_mp_prec} of 9.  @code{_mp_d} then gets 10 limbs allocated.  Reading
+back with @code{mpf_get_prec} will take @code{_mp_prec} subtract 1 limb and
+multiply by 32, giving 256 bits.
+
+Strictly speaking, the fact the high limb has at least one bit means that a
+float with, say, 3 limbs of 32-bits each will be holding at least 65 bits, but
+for the purposes of @code{mpf_t} it's considered simply to be 64 bits, a nice
+multiple of the limb size.
+@end table
+
+
+@node Raw Output Internals, C++ Interface Internals, Float Internals, Internals
+@section Raw Output Internals
+@cindex Raw output internals
+
+@noindent
+@code{mpz_out_raw} uses the following format.
+
+@tex
+\global\newdimen\GMPboxwidth \GMPboxwidth=5em
+\global\newdimen\GMPboxheight \GMPboxheight=3ex
+\def\centreline{\hbox{\raise 0.8ex \vbox{\hrule \hbox{\hfil}}}}
+\GMPdisplay{%
+\vbox{%
+  \def\GMPcentreline#1{\hbox{\raise 0.5 ex \vbox{\hrule \hbox to #1 {}}}}
+  \vbox {%
+    \hrule
+    \hbox{%
+      \vrule height 2.5ex depth 1.5ex
+      \hbox to \GMPboxwidth {\hfil size\hfil}%
+      \vrule
+      \hbox to 3\GMPboxwidth {\hfil data bytes\hfil}%
+      \vrule}
+    \hrule}
+}}
+@end tex
+@ifnottex
+@example
++------+------------------------+
+| size |       data bytes       |
++------+------------------------+
+@end example
+@end ifnottex
+
+The size is 4 bytes written most significant byte first, being the number of
+subsequent data bytes, or the twos complement negative of that when a negative
+integer is represented.  The data bytes are the absolute value of the integer,
+written most significant byte first.
+
+The most significant data byte is always non-zero, so the output is the same
+on all systems, irrespective of limb size.
+
+In GMP 1, leading zero bytes were written to pad the data bytes to a multiple
+of the limb size.  @code{mpz_inp_raw} will still accept this, for
+compatibility.
+
+The use of ``big endian'' for both the size and data fields is deliberate, it
+makes the data easy to read in a hex dump of a file.  Unfortunately it also
+means that the limb data must be reversed when reading or writing, so neither
+a big endian nor little endian system can just read and write @code{_mp_d}.
+
+
+@node C++ Interface Internals,  , Raw Output Internals, Internals
+@section C++ Interface Internals
+@cindex C++ interface internals
+
+A system of expression templates is used to ensure something like @code{a=b+c}
+turns into a simple call to @code{mpz_add} etc.  For @code{mpf_class}
+the scheme also ensures the precision of the final
+destination is used for any temporaries within a statement like
+@code{f=w*x+y*z}.  These are important features which a naive implementation
+cannot provide.
+
+A simplified description of the scheme follows.  The true scheme is
+complicated by the fact that expressions have different return types.  For
+detailed information, refer to the source code.
+
+To perform an operation, say, addition, we first define a ``function object''
+evaluating it,
+
+@example
+struct __gmp_binary_plus
+@{
+  static void eval(mpf_t f, const mpf_t g, const mpf_t h)
+  @{
+    mpf_add(f, g, h);
+  @}
+@};
+@end example
+
+@noindent
+And an ``additive expression'' object,
+
+@example
+__gmp_expr<__gmp_binary_expr<mpf_class, mpf_class, __gmp_binary_plus> >
+operator+(const mpf_class &f, const mpf_class &g)
+@{
+  return __gmp_expr
+    <__gmp_binary_expr<mpf_class, mpf_class, __gmp_binary_plus> >(f, g);
+@}
+@end example
+
+The seemingly redundant @code{__gmp_expr<__gmp_binary_expr<@dots{}>>} is used to
+encapsulate any possible kind of expression into a single template type.  In
+fact even @code{mpf_class} etc are @code{typedef} specializations of
+@code{__gmp_expr}.
+
+Next we define assignment of @code{__gmp_expr} to @code{mpf_class}.
+
+@example
+template <class T>
+mpf_class & mpf_class::operator=(const __gmp_expr<T> &expr)
+@{
+  expr.eval(this->get_mpf_t(), this->precision());
+  return *this;
+@}
+
+template <class Op>
+void __gmp_expr<__gmp_binary_expr<mpf_class, mpf_class, Op> >::eval
+(mpf_t f, mp_bitcnt_t precision)
+@{
+  Op::eval(f, expr.val1.get_mpf_t(), expr.val2.get_mpf_t());
+@}
+@end example
+
+where @code{expr.val1} and @code{expr.val2} are references to the expression's
+operands (here @code{expr} is the @code{__gmp_binary_expr} stored within the
+@code{__gmp_expr}).
+
+This way, the expression is actually evaluated only at the time of assignment,
+when the required precision (that of @code{f}) is known.  Furthermore the
+target @code{mpf_t} is now available, thus we can call @code{mpf_add} directly
+with @code{f} as the output argument.
+
+Compound expressions are handled by defining operators taking subexpressions
+as their arguments, like this:
+
+@example
+template <class T, class U>
+__gmp_expr
+<__gmp_binary_expr<__gmp_expr<T>, __gmp_expr<U>, __gmp_binary_plus> >
+operator+(const __gmp_expr<T> &expr1, const __gmp_expr<U> &expr2)
+@{
+  return __gmp_expr
+    <__gmp_binary_expr<__gmp_expr<T>, __gmp_expr<U>, __gmp_binary_plus> >
+    (expr1, expr2);
+@}
+@end example
+
+And the corresponding specializations of @code{__gmp_expr::eval}:
+
+@example
+template <class T, class U, class Op>
+void __gmp_expr
+<__gmp_binary_expr<__gmp_expr<T>, __gmp_expr<U>, Op> >::eval
+(mpf_t f, mp_bitcnt_t precision)
+@{
+  // declare two temporaries
+  mpf_class temp1(expr.val1, precision), temp2(expr.val2, precision);
+  Op::eval(f, temp1.get_mpf_t(), temp2.get_mpf_t());
+@}
+@end example
+
+The expression is thus recursively evaluated to any level of complexity and
+all subexpressions are evaluated to the precision of @code{f}.
+
+
+@node Contributors, References, Internals, Top
+@comment  node-name,  next,  previous,  up
+@appendix Contributors
+@cindex Contributors
+
+Torbj@"orn Granlund wrote the original GMP library and is still the main
+developer.  Code not explicitly attributed to others, was contributed by
+Torbj@"orn.  Several other individuals and organizations have contributed
+GMP.  Here is a list in chronological order on first contribution:
+
+Gunnar Sj@"odin and Hans Riesel helped with mathematical problems in early
+versions of the library.
+
+Richard Stallman helped with the interface design and revised the first
+version of this manual.
+
+Brian Beuning and Doug Lea helped with testing of early versions of the
+library and made creative suggestions.
+
+John Amanatides of York University in Canada contributed the function
+@code{mpz_probab_prime_p}.
+
+Paul Zimmermann wrote the REDC-based mpz_powm code, the Sch@"onhage-Strassen
+FFT multiply code, and the Karatsuba square root code.  He also improved the
+Toom3 code for GMP 4.2.  Paul sparked the development of GMP 2, with his
+comparisons between bignum packages.  The ECMNET project Paul is organizing
+was a driving force behind many of the optimizations in GMP 3.  Paul also
+wrote the new GMP 4.3 nth root code (with Torbj@"orn).
+
+Ken Weber (Kent State University, Universidade Federal do Rio Grande do Sul)
+contributed now defunct versions of @code{mpz_gcd}, @code{mpz_divexact},
+@code{mpn_gcd}, and @code{mpn_bdivmod}, partially supported by CNPq (Brazil)
+grant 301314194-2.
+
+Per Bothner of Cygnus Support helped to set up GMP to use Cygnus' configure.
+He has also made valuable suggestions and tested numerous intermediary
+releases.
+
+Joachim Hollman was involved in the design of the @code{mpf} interface, and in
+the @code{mpz} design revisions for version 2.
+
+Bennet Yee contributed the initial versions of @code{mpz_jacobi} and
+@code{mpz_legendre}.
+
+Andreas Schwab contributed the files @file{mpn/m68k/lshift.S} and
+@file{mpn/m68k/rshift.S} (now in @file{.asm} form).
+
+Robert Harley of Inria, France and David Seal of ARM, England, suggested clever
+improvements for population count.  Robert also wrote highly optimized
+Karatsuba and 3-way Toom multiplication functions for GMP 3, and contributed
+the ARM assembly code.
+
+Torsten Ekedahl of the Mathematical department of Stockholm University provided
+significant inspiration during several phases of the GMP development.  His
+mathematical expertise helped improve several algorithms.
+
+Linus Nordberg wrote the new configure system based on autoconf and
+implemented the new random functions.
+
+Kevin Ryde worked on a large number of things: optimized x86 code, m4 asm
+macros, parameter tuning, speed measuring, the configure system, function
+inlining, divisibility tests, bit scanning, Jacobi symbols, Fibonacci and Lucas
+number functions, printf and scanf functions, perl interface, demo expression
+parser, the algorithms chapter in the manual, @file{gmpasm-mode.el}, and
+various miscellaneous improvements elsewhere.
+
+Kent Boortz made the Mac OS 9 port.
+
+Steve Root helped write the optimized alpha 21264 assembly code.
+
+Gerardo Ballabio wrote the @file{gmpxx.h} C++ class interface and the C++
+@code{istream} input routines.
+
+Jason Moxham rewrote @code{mpz_fac_ui}.
+
+Pedro Gimeno implemented the Mersenne Twister and made other random number
+improvements.
+
+Niels M@"oller wrote the sub-quadratic GCD, extended GCD and jacobi code, the
+quadratic Hensel division code, and (with Torbj@"orn) the new divide and
+conquer division code for GMP 4.3.  Niels also helped implement the new Toom
+multiply code for GMP 4.3 and implemented helper functions to simplify Toom
+evaluations for GMP 5.0.  He wrote the original version of mpn_mulmod_bnm1, and
+he is the main author of the mini-gmp package used for gmp bootstrapping.
+
+Alberto Zanoni and Marco Bodrato suggested the unbalanced multiply strategy,
+and found the optimal strategies for evaluation and interpolation in Toom
+multiplication.
+
+Marco Bodrato helped implement the new Toom multiply code for GMP 4.3 and
+implemented most of the new Toom multiply and squaring code for 5.0.
+He is the main author of the current mpn_mulmod_bnm1, mpn_mullo_n, and
+mpn_sqrlo.  Marco also wrote the functions mpn_invert and mpn_invertappr,
+and improved the speed of integer root extraction.  He is the author of
+mini-mpq, an additional layer to mini-gmp; of most of the combinatorial
+functions and the BPSW primality testing implementation, for both the
+main library and the mini-gmp package.
+
+David Harvey suggested the internal function @code{mpn_bdiv_dbm1}, implementing
+division relevant to Toom multiplication.  He also worked on fast assembly
+sequences, in particular on a fast AMD64 @code{mpn_mul_basecase}. He wrote
+the internal middle product functions @code{mpn_mulmid_basecase},
+@code{mpn_toom42_mulmid}, @code{mpn_mulmid_n} and related helper routines.
+
+Martin Boij wrote @code{mpn_perfect_power_p}.
+
+Marc Glisse improved @file{gmpxx.h}: use fewer temporaries (faster),
+specializations of @code{numeric_limits} and @code{common_type}, C++11
+features (move constructors, explicit bool conversion, UDL), make the
+conversion from @code{mpq_class} to @code{mpz_class} explicit, optimize
+operations where one argument is a small compile-time constant, replace
+some heap allocations by stack allocations.  He also fixed the eofbit
+handling of C++ streams, and removed one division from @file{mpq/aors.c}.
+
+David S Miller wrote assembly code for SPARC T3 and T4.
+
+Mark Sofroniou cleaned up the types of mul_fft.c, letting it work for huge
+operands.
+
+Ulrich Weigand ported GMP to the powerpc64le ABI.
+
+(This list is chronological, not ordered after significance.  If you have
+contributed to GMP but are not listed above, please tell
+@email{gmp-devel@@gmplib.org} about the omission!)
+
+The development of floating point functions of GNU MP 2, were supported in part
+by the ESPRIT-BRA (Basic Research Activities) 6846 project POSSO (POlynomial
+System SOlving).
+
+The development of GMP 2, 3, and 4.0 was supported in part by the IDA Center
+for Computing Sciences.
+
+The development of GMP 4.3, 5.0, and 5.1 was supported in part by the Swedish
+Foundation for Strategic Research.
+
+Thanks go to Hans Thorsen for donating an SGI system for the GMP test system
+environment.
+
+@node References, GNU Free Documentation License, Contributors, Top
+@comment  node-name,  next,  previous,  up
+@appendix References
+@cindex References
+
+@c  FIXME: In tex, the @uref's are unhyphenated, which is good for clarity,
+@c  but being long words they upset paragraph formatting (the preceding line
+@c  can get badly stretched).  Would like an conditional @* style line break
+@c  if the uref is too long to fit on the last line of the paragraph, but it's
+@c  not clear how to do that.  For now explicit @texlinebreak{}s are used on
+@c  paragraphs that come out bad.
+
+@section Books
+
+@itemize @bullet
+@item
+Jonathan M. Borwein and Peter B. Borwein, ``Pi and the AGM: A Study in
+Analytic Number Theory and Computational Complexity'', Wiley, 1998.
+
+@item
+Richard Crandall and Carl Pomerance, ``Prime Numbers: A Computational
+Perspective'', 2nd edition, Springer-Verlag, 2005.
+@texlinebreak{} @uref{https://www.math.dartmouth.edu/~carlp/}
+
+@item
+Henri Cohen, ``A Course in Computational Algebraic Number Theory'', Graduate
+Texts in Mathematics number 138, Springer-Verlag, 1993.
+@texlinebreak{} @uref{https://www.math.u-bordeaux.fr/~cohen/}
+
+@item
+Donald E. Knuth, ``The Art of Computer Programming'', volume 2,
+``Seminumerical Algorithms'', 3rd edition, Addison-Wesley, 1998.
+@texlinebreak{} @uref{https://www-cs-faculty.stanford.edu/~knuth/taocp.html}
+
+@item
+John D. Lipson, ``Elements of Algebra and Algebraic Computing'',
+The Benjamin Cummings Publishing Company Inc, 1981.
+
+@item
+Alfred J. Menezes, Paul C. van Oorschot and Scott A. Vanstone, ``Handbook of
+Applied Cryptography'', @uref{http://www.cacr.math.uwaterloo.ca/hac/}
+
+@item
+Richard M. Stallman and the GCC Developer Community, ``Using the GNU Compiler
+Collection'', Free Software Foundation, 2008, available online
+@uref{https://gcc.gnu.org/onlinedocs/}, and in the GCC package
+@uref{https://ftp.gnu.org/gnu/gcc/}
+@end itemize
+
+@section Papers
+
+@itemize @bullet
+@item
+Yves Bertot, Nicolas Magaud and Paul Zimmermann, ``A Proof of GMP Square
+Root'', Journal of Automated Reasoning, volume 29, 2002, pp.@: 225-252.  Also
+available online as INRIA Research Report 4475, June 2002,
+@uref{https://hal.inria.fr/docs/00/07/21/13/PDF/RR-4475.pdf}
+
+@item
+Christoph Burnikel and Joachim Ziegler, ``Fast Recursive Division'',
+Max-Planck-Institut fuer Informatik Research Report MPI-I-98-1-022,
+@texlinebreak{} @uref{https://www.mpi-inf.mpg.de/~ziegler/TechRep.ps.gz}
+
+@item
+Torbj@"orn Granlund and Peter L. Montgomery, ``Division by Invariant Integers
+using Multiplication'', in Proceedings of the SIGPLAN PLDI'94 Conference, June
+1994.  Also available @uref{https://gmplib.org/~tege/divcnst-pldi94.pdf}.
+
+@item
+Niels M@"oller and Torbj@"orn Granlund, ``Improved division by invariant
+integers'', IEEE Transactions on Computers, 11 June 2010.
+@uref{https://gmplib.org/~tege/division-paper.pdf}
+
+@item
+Torbj@"orn Granlund and Niels M@"oller, ``Division of integers large and
+small'', to appear.
+
+@item
+Tudor Jebelean,
+``An algorithm for exact division'',
+Journal of Symbolic Computation,
+volume 15, 1993, pp.@: 169-180.
+Research report version available @texlinebreak{}
+@uref{ftp://ftp.risc.uni-linz.ac.at/pub/techreports/1992/92-35.ps.gz}
+
+@item
+Tudor Jebelean, ``Exact Division with Karatsuba Complexity - Extended
+Abstract'', RISC-Linz technical report 96-31, @texlinebreak{}
+@uref{ftp://ftp.risc.uni-linz.ac.at/pub/techreports/1996/96-31.ps.gz}
+
+@item
+Tudor Jebelean, ``Practical Integer Division with Karatsuba Complexity'',
+ISSAC 97, pp.@: 339-341.  Technical report available @texlinebreak{}
+@uref{ftp://ftp.risc.uni-linz.ac.at/pub/techreports/1996/96-29.ps.gz}
+
+@item
+Tudor Jebelean, ``A Generalization of the Binary GCD Algorithm'', ISSAC 93,
+pp.@: 111-116.  Technical report version available @texlinebreak{}
+@uref{ftp://ftp.risc.uni-linz.ac.at/pub/techreports/1993/93-01.ps.gz}
+
+@item
+Tudor Jebelean, ``A Double-Digit Lehmer-Euclid Algorithm for Finding the GCD
+of Long Integers'', Journal of Symbolic Computation, volume 19, 1995,
+pp.@: 145-157.  Technical report version also available @texlinebreak{}
+@uref{ftp://ftp.risc.uni-linz.ac.at/pub/techreports/1992/92-69.ps.gz}
+
+@item
+Werner Krandick and Tudor Jebelean, ``Bidirectional Exact Integer Division'',
+Journal of Symbolic Computation, volume 21, 1996, pp.@: 441-455.  Early
+technical report version also available
+@uref{ftp://ftp.risc.uni-linz.ac.at/pub/techreports/1994/94-50.ps.gz}
+
+@item
+Makoto Matsumoto and Takuji Nishimura, ``Mersenne Twister: A 623-dimensionally
+equidistributed uniform pseudorandom number generator'', ACM Transactions on
+Modelling and Computer Simulation, volume 8, January 1998, pp.@: 3-30.
+Available online @texlinebreak{}
+@uref{http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/ARTICLES/mt.pdf}
+
+@item
+R. Moenck and A. Borodin, ``Fast Modular Transforms via Division'',
+Proceedings of the 13th Annual IEEE Symposium on Switching and Automata
+Theory, October 1972, pp.@: 90-96.  Reprinted as ``Fast Modular Transforms'',
+Journal of Computer and System Sciences, volume 8, number 3, June 1974,
+pp.@: 366-386.
+
+@item
+Niels M@"oller, ``On Sch@"onhage's algorithm and subquadratic integer GCD
+  computation'', in Mathematics of Computation, volume 77, January 2008, pp.@:
+  589-607, @uref{https://www.ams.org/journals/mcom/2008-77-261/S0025-5718-07-02017-0/home.html}
+
+@item
+Peter L. Montgomery, ``Modular Multiplication Without Trial Division'', in
+Mathematics of Computation, volume 44, number 170, April 1985.
+
+@item
+Arnold Sch@"onhage and Volker Strassen, ``Schnelle Multiplikation grosser
+Zahlen'', Computing 7, 1971, pp.@: 281-292.
+
+@item
+Kenneth Weber, ``The accelerated integer GCD algorithm'',
+ACM Transactions on Mathematical Software,
+volume 21, number 1, March 1995, pp.@: 111-122.
+
+@item
+Paul Zimmermann, ``Karatsuba Square Root'', INRIA Research Report 3805,
+November 1999, @uref{https://hal.inria.fr/inria-00072854/PDF/RR-3805.pdf}
+
+@item
+Paul Zimmermann, ``A Proof of GMP Fast Division and Square Root
+Implementations'', @texlinebreak{}
+@uref{https://homepages.loria.fr/PZimmermann/papers/proof-div-sqrt.ps.gz}
+
+@item
+Dan Zuras, ``On Squaring and Multiplying Large Integers'', ARITH-11: IEEE
+Symposium on Computer Arithmetic, 1993, pp.@: 260 to 271.  Reprinted as ``More
+on Multiplying and Squaring Large Integers'', IEEE Transactions on Computers,
+volume 43, number 8, August 1994, pp.@: 899-908.
+
+@item
+Niels M@"oller, ``Efficient computation of the Jacobi symbol'', @texlinebreak{}
+@uref{https://arxiv.org/abs/1907.07795}
+@end itemize
+
+@node GNU Free Documentation License, Concept Index, References, Top
+@appendix GNU Free Documentation License
+@cindex GNU Free Documentation License
+@cindex Free Documentation License
+@cindex Documentation license
+@include fdl-1.3.texi
+
+
+@node Concept Index, Function Index, GNU Free Documentation License, Top
+@comment  node-name,  next,  previous,  up
+@unnumbered Concept Index
+@printindex cp
+
+@node Function Index,  , Concept Index, Top
+@comment  node-name,  next,  previous,  up
+@unnumbered Function and Type Index
+@printindex fn
+
+@bye
+
+@c Local variables:
+@c fill-column: 78
+@c compile-command: "make gmp.info"
+@c End:
diff --git a/third_party/gmp/doc/isa_abi_headache b/third_party/gmp/doc/isa_abi_headache
new file mode 100644
index 0000000..7e1430d
--- /dev/null
+++ b/third_party/gmp/doc/isa_abi_headache
@@ -0,0 +1,128 @@
+Copyright 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.
+
+
+
+
+Terms Used In This Document:
+  ISA = Instruction Set Architecture.   The instructions the current
+        processor provides.
+  ABI = Application Binary Interface.  Specifies calling convention,
+        type sizes, etc.
+  AR64 = Arithmetic operations are 64-bit using 64-bit instructions
+	 (E.g., addition, subtraction, load, store, of 64-bit integer types
+	 are done with single instructions, not 32 bits at a time.)
+  Environment = The operating system and compiler.
+
+GMP is a very complex package to build since its speed is very
+sensitive to the ISA and ABI.  For example, if the ISA provides 64-bit
+instructions, it is crucial that GMP is configured to use them.
+
+Most environments that run on a 64-bit ISA provide more than one ABI.
+Typically one of the supported ABI's is a backward compatible 32-bit
+ABI, and one ABI provides 64-bit addressing and `long' (sometimes
+known as LP64).  But a few environments (IRIX, HP-UX) provide
+intermediate ABI's using 32-bit addressing but allow efficient 64-bit
+operations through a `long long' type.  For the latter to be useful to
+GMP, the ABI must allow operations using the native 64-bit
+instructions provided by the ISA, and allow passing of 64-bit
+quantities atomically.
+
+The ABI is typically chosen by means of command line options to the
+compiler tools (gcc, cc, c89, nm, ar, ld, as).  Different environments
+use different defaults, but as of this writing (May 2000) the
+dominating default is to the plain 32-bit ABI in its most arcane form.
+
+The GMP 3.0.x approach was to compile using the ABI that gives the
+best performance.  That places the burden on users to pass special
+options to the compiler when they compile their GMP applications.
+That approach has its advantages and disadvantages.  The main
+advantage is that users don't unknowingly get bad GMP performance.
+The main disadvantage is that users' compiles (actually links) will
+fail unless they pass special compiler options.
+
+** SPARC
+
+System vendors often confuse ABI, ISA, and implementation.  The worst
+case is Solaris, were the unbundled compiler confuses ISA and ABI, and
+the options have very confusing names.
+
+     option		interpretation
+     ======		==============
+cc   -xarch=v8plus	ISA=sparcv9, ABI=V8plus (PTR=32, see below)
+gcc  -mv8plus		ISA=sparcv9, ABI=V8plus (see below)
+cc   -xarch=v9		ISA=sparcv9, ABI=V9 (implying AR=64, PTR=64)
+
+It's hard to believe, but the option v8plus really means ISA=V9!
+
+Solaris releases prior to version 7 running on a V9 CPU fails to
+save/restore the upper 32 bits of the `i' and `l' registers.  The
+`v8plus' option generates code that use as many V9 features as
+possible under such circumstances.
+
+** MIPS
+
+The IRIX 6 compilers gets things right.  They have a clear
+understanding of the differences between ABI and ISA.  The option
+names are descriptive.
+
+     option		interpretation
+     ======		==============
+cc   -n32		ABI=n32 (implying AR=64, PTR=32)
+gcc  -mabi=n32		ABI=n32 (implying AR=64, PTR=32)
+cc   -64		ABI=64 (implying AR=64, PTR=64)
+gcc  -mabi=64		ABI=64 (implying AR=64, PTR=64)
+cc   -mips3		ISA=mips3
+gcc  -mips3		ISA=mips3
+cc   -mips4		ISA=mips4
+gcc  -mips4		ISA=mips4
+
+** HP-PA
+
+HP-UX is somewhat weird, but not as broken as Solaris.
+
+     option		interpretation
+     ======		==============
+cc   +DA2.0		ABI=32bit (implying AR=64, PTR=32)
+cc   +DD64		ABI=64bit (implying AR=64, PTR=64)
+
+Code performing 64-bit arithmetic in the HP-UX 32-bit is not
+compatible with the 64-bit ABI; the former has a calling convention
+that passes/returns 64-bit integer quantities as two 32-bit chunks.
+
+** PowerPC
+
+While the PowerPC ABI's are capable of supporting 64-bit
+registers/operations, the compilers under AIX are similar to Solaris'
+cc in that they don't currently provide any 32-bit addressing with
+64-bit arithmetic.
+
+     option			interpretation
+     ======			==============
+cc   -q64			ABI=64bit (implying AR=64, PTR=64)
+gcc  -maix64 -mpowerpc64	ABI=64bit (implying AR=64, PTR=64)
diff --git a/third_party/gmp/doc/mdate-sh b/third_party/gmp/doc/mdate-sh
new file mode 100755
index 0000000..e8dfaca
--- /dev/null
+++ b/third_party/gmp/doc/mdate-sh
@@ -0,0 +1,224 @@
+#!/bin/sh
+# Get modification time of a file or directory and pretty-print it.
+
+scriptversion=2010-08-21.06; # UTC
+
+# Copyright (C) 1995-2014 Free Software Foundation, Inc.
+# written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, June 1995
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+fi
+
+case $1 in
+  '')
+     echo "$0: No file.  Try '$0 --help' for more information." 1>&2
+     exit 1;
+     ;;
+  -h | --h*)
+    cat <<\EOF
+Usage: mdate-sh [--help] [--version] FILE
+
+Pretty-print the modification day of FILE, in the format:
+1 January 1970
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+    exit $?
+    ;;
+  -v | --v*)
+    echo "mdate-sh $scriptversion"
+    exit $?
+    ;;
+esac
+
+error ()
+{
+  echo "$0: $1" >&2
+  exit 1
+}
+
+
+# Prevent date giving response in another language.
+LANG=C
+export LANG
+LC_ALL=C
+export LC_ALL
+LC_TIME=C
+export LC_TIME
+
+# GNU ls changes its time format in response to the TIME_STYLE
+# variable.  Since we cannot assume 'unset' works, revert this
+# variable to its documented default.
+if test "${TIME_STYLE+set}" = set; then
+  TIME_STYLE=posix-long-iso
+  export TIME_STYLE
+fi
+
+save_arg1=$1
+
+# Find out how to get the extended ls output of a file or directory.
+if ls -L /dev/null 1>/dev/null 2>&1; then
+  ls_command='ls -L -l -d'
+else
+  ls_command='ls -l -d'
+fi
+# Avoid user/group names that might have spaces, when possible.
+if ls -n /dev/null 1>/dev/null 2>&1; then
+  ls_command="$ls_command -n"
+fi
+
+# A 'ls -l' line looks as follows on OS/2.
+#  drwxrwx---        0 Aug 11  2001 foo
+# This differs from Unix, which adds ownership information.
+#  drwxrwx---   2 root  root      4096 Aug 11  2001 foo
+#
+# To find the date, we split the line on spaces and iterate on words
+# until we find a month.  This cannot work with files whose owner is a
+# user named "Jan", or "Feb", etc.  However, it's unlikely that '/'
+# will be owned by a user whose name is a month.  So we first look at
+# the extended ls output of the root directory to decide how many
+# words should be skipped to get the date.
+
+# On HPUX /bin/sh, "set" interprets "-rw-r--r--" as options, so the "x" below.
+set x`$ls_command /`
+
+# Find which argument is the month.
+month=
+command=
+until test $month
+do
+  test $# -gt 0 || error "failed parsing '$ls_command /' output"
+  shift
+  # Add another shift to the command.
+  command="$command shift;"
+  case $1 in
+    Jan) month=January; nummonth=1;;
+    Feb) month=February; nummonth=2;;
+    Mar) month=March; nummonth=3;;
+    Apr) month=April; nummonth=4;;
+    May) month=May; nummonth=5;;
+    Jun) month=June; nummonth=6;;
+    Jul) month=July; nummonth=7;;
+    Aug) month=August; nummonth=8;;
+    Sep) month=September; nummonth=9;;
+    Oct) month=October; nummonth=10;;
+    Nov) month=November; nummonth=11;;
+    Dec) month=December; nummonth=12;;
+  esac
+done
+
+test -n "$month" || error "failed parsing '$ls_command /' output"
+
+# Get the extended ls output of the file or directory.
+set dummy x`eval "$ls_command \"\\\$save_arg1\""`
+
+# Remove all preceding arguments
+eval $command
+
+# Because of the dummy argument above, month is in $2.
+#
+# On a POSIX system, we should have
+#
+# $# = 5
+# $1 = file size
+# $2 = month
+# $3 = day
+# $4 = year or time
+# $5 = filename
+#
+# On Darwin 7.7.0 and 7.6.0, we have
+#
+# $# = 4
+# $1 = day
+# $2 = month
+# $3 = year or time
+# $4 = filename
+
+# Get the month.
+case $2 in
+  Jan) month=January; nummonth=1;;
+  Feb) month=February; nummonth=2;;
+  Mar) month=March; nummonth=3;;
+  Apr) month=April; nummonth=4;;
+  May) month=May; nummonth=5;;
+  Jun) month=June; nummonth=6;;
+  Jul) month=July; nummonth=7;;
+  Aug) month=August; nummonth=8;;
+  Sep) month=September; nummonth=9;;
+  Oct) month=October; nummonth=10;;
+  Nov) month=November; nummonth=11;;
+  Dec) month=December; nummonth=12;;
+esac
+
+case $3 in
+  ???*) day=$1;;
+  *) day=$3; shift;;
+esac
+
+# Here we have to deal with the problem that the ls output gives either
+# the time of day or the year.
+case $3 in
+  *:*) set `date`; eval year=\$$#
+       case $2 in
+	 Jan) nummonthtod=1;;
+	 Feb) nummonthtod=2;;
+	 Mar) nummonthtod=3;;
+	 Apr) nummonthtod=4;;
+	 May) nummonthtod=5;;
+	 Jun) nummonthtod=6;;
+	 Jul) nummonthtod=7;;
+	 Aug) nummonthtod=8;;
+	 Sep) nummonthtod=9;;
+	 Oct) nummonthtod=10;;
+	 Nov) nummonthtod=11;;
+	 Dec) nummonthtod=12;;
+       esac
+       # For the first six month of the year the time notation can also
+       # be used for files modified in the last year.
+       if (expr $nummonth \> $nummonthtod) > /dev/null;
+       then
+	 year=`expr $year - 1`
+       fi;;
+  *) year=$3;;
+esac
+
+# The result.
+echo $day $month $year
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/third_party/gmp/doc/projects.html b/third_party/gmp/doc/projects.html
new file mode 100644
index 0000000..4a10514
--- /dev/null
+++ b/third_party/gmp/doc/projects.html
@@ -0,0 +1,476 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+  <title>GMP Development Projects</title>
+  <link rel="shortcut icon" href="favicon.ico">
+  <link rel="stylesheet" href="gmp.css">
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+</head>
+
+<center>
+  <h1>
+    GMP Development Projects
+  </h1>
+</center>
+
+<font size=-1>
+<pre>
+Copyright 2000-2006, 2008-2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.
+</pre>
+</font>
+
+<hr>
+<!-- NB. timestamp updated automatically by emacs -->
+  This file current as of 29 Jan 2014.  An up-to-date version is available at
+  <a href="https://gmplib.org/projects.html">https://gmplib.org/projects.html</a>.
+  Please send comments about this page to gmp-devel<font>@</font>gmplib.org.
+
+<p> This file lists projects suitable for volunteers.  Please see the
+    <a href="tasks.html">tasks file</a> for smaller tasks.
+
+<p> If you want to work on any of the projects below, please let
+    gmp-devel<font>@</font>gmplib.org know.  If you want to help with a project
+    that already somebody else is working on, you will get in touch through
+    gmp-devel<font>@</font>gmplib.org.  (There are no email addresses of
+    volunteers below, due to spamming problems.)
+
+<ul>
+<li> <strong>Faster multiplication</strong>
+
+  <ol>
+
+    <li> Work on the algorithm selection code for unbalanced multiplication.
+
+    <li> Implement an FFT variant computing the coefficients mod m different
+	 limb size primes of the form l*2^k+1. i.e., compute m separate FFTs.
+	 The wanted coefficients will at the end be found by lifting with CRT
+	 (Chinese Remainder Theorem).  If we let m = 3, i.e., use 3 primes, we
+	 can split the operands into coefficients at limb boundaries, and if
+	 our machine uses b-bit limbs, we can multiply numbers with close to
+	 2^b limbs without coefficient overflow.  For smaller multiplication,
+	 we might perhaps let m = 1, and instead of splitting our operands at
+	 limb boundaries, split them in much smaller pieces.  We might also use
+	 4 or more primes, and split operands into bigger than b-bit chunks.
+	 By using more primes, the gain in shorter transform length, but lose
+	 in having to do more FFTs, but that is a slight total save.  We then
+	 lose in more expensive CRT. <br><br>
+
+	 <p> [We now have two implementations of this algorithm, one by Tommy
+	 Färnqvist and one by Niels Möller.]
+
+    <li> Work on short products.  Our mullo and mulmid are probably K, but we
+         lack mulhi.
+
+  </ol>
+
+  <p> Another possibility would be an optimized cube.  In the basecase that
+      should definitely be able to save cross-products in a similar fashion to
+      squaring, but some investigation might be needed for how best to adapt
+      the higher-order algorithms.  Not sure whether cubing or further small
+      powers have any particularly important uses though.
+
+
+<li> <strong>Assembly routines</strong>
+
+  <p> Write new and improve existing assembly routines.  The tests/devel
+      programs and the tune/speed.c and tune/many.pl programs are useful for
+      testing and timing the routines you write.  See the README files in those
+      directories for more information.
+
+  <p> Please make sure your new routines are fast for these three situations:
+      <ol>
+	<li> Small operands of less than, say, 10 limbs.
+	<li> Medium size operands, that fit into the cache.
+	<li> Huge operands that does not fit into the cache.
+      </ol>
+
+  <p> The most important routines are mpn_addmul_1, mpn_mul_basecase and
+      mpn_sqr_basecase.  The latter two don't exist for all machines, while
+      mpn_addmul_1 exists for almost all machines.
+
+  <p> Standard techniques for these routines are unrolling, software
+      pipelining, and specialization for common operand values.  For machines
+      with poor integer multiplication, it is sometimes possible to remedy the
+      situation using floating-point operations or SIMD operations such as MMX
+      (x86) (x86), SSE (x86), VMX (PowerPC), VIS (Sparc).
+
+  <p> Using floating-point operations is interesting but somewhat tricky.
+      Since IEEE double has 53 bit of mantissa, one has to split the operands
+      in small pieces, so that no intermediates are greater than 2^53.  For
+      32-bit computers, splitting one operand into 16-bit pieces works.  For
+      64-bit machines, one operand can be split into 21-bit pieces and the
+      other into 32-bit pieces.  (A 64-bit operand can be split into just three
+      21-bit pieces if one allows the split operands to be negative!)
+
+
+<li> <strong>Faster sqrt</strong>
+
+  <p> The current code uses divisions, which are reasonably fast, but it'd be
+      possible to use only multiplications by computing 1/sqrt(A) using this
+      iteration:
+      <pre>
+				    2
+		   x   = x  (3 &minus; A x )/2
+		    i+1	  i	    i  </pre>
+      The square root can then be computed like this:
+      <pre>
+		     sqrt(A) = A x
+				  n  </pre>
+  <p> That final multiply might be the full size of the input (though it might
+      only need the high half of that), so there may or may not be any speedup
+      overall.
+
+  <p> We should probably allow a special exponent-like parameter, to speed
+      computations of a precise square root of a small number in mpf and mpfr.
+
+
+<li> <strong>Nth root</strong>
+
+  <p> Improve mpn_rootrem.  The current code is not too bad, but its time
+      complexity is a function of the input, while it is possible to make
+      the <i>average</i> complexity a function of the output.
+
+
+<li> <strong>Fat binaries</strong>
+
+  <p> Add more functions to the set of fat functions.
+
+  <p> The speed of multiplication is today highly dependent on combination
+  functions like <code>addlsh1_n</code>.  A fat binary will never use any such
+  functions, since they are classified as optional.  Ideally, we should use
+  them, but making the current compile-time selections of optional functions
+  become run-time selections for fat binaries.
+
+  <p> If we make fat binaries work really well, we should move away frm tehe
+  current configure scheme (at least by default) and instead include all code
+  always.
+
+
+<li> <strong>Exceptions</strong>
+
+  <p> Some sort of scheme for exceptions handling would be desirable.
+      Presently the only thing documented is that divide by zero in GMP
+      functions provokes a deliberate machine divide by zero (on those systems
+      where such a thing exists at least).  The global <code>gmp_errno</code>
+      is not actually documented, except for the old <code>gmp_randinit</code>
+      function.  Being currently just a plain global means it's not
+      thread-safe.
+
+  <p> The basic choices for exceptions are returning an error code or having a
+      handler function to be called.  The disadvantage of error returns is they
+      have to be checked, leading to tedious and rarely executed code, and
+      strictly speaking such a scheme wouldn't be source or binary compatible.
+      The disadvantage of a handler function is that a <code>longjmp</code> or
+      similar recovery from it may be difficult.  A combination would be
+      possible, for instance by allowing the handler to return an error code.
+
+  <p> Divide-by-zero, sqrt-of-negative, and similar operand range errors can
+      normally be detected at the start of functions, so exception handling
+      would have a clean state.  What's worth considering though is that the
+      GMP function detecting the exception may have been called via some third
+      party library or self contained application module, and hence have
+      various bits of state to be cleaned up above it.  It'd be highly
+      desirable for an exceptions scheme to allow for such cleanups.
+
+  <p> The C++ destructor mechanism could help with cleanups both internally and
+      externally, but being a plain C library we don't want to depend on that.
+
+  <p> A C++ <code>throw</code> might be a good optional extra exceptions
+      mechanism, perhaps under a build option.  For
+      GCC <code>-fexceptions</code> will add the necessary frame information to
+      plain C code, or GMP could be compiled as C++.
+
+  <p> Out-of-memory exceptions are expected to be handled by the
+      <code>mp_set_memory_functions</code> routines, rather than being a
+      prospective part of divide-by-zero etc.  Some similar considerations
+      apply but what differs is that out-of-memory can arise deep within GMP
+      internals.  Even fundamental routines like <code>mpn_add_n</code> and
+      <code>mpn_addmul_1</code> can use temporary memory (for instance on Cray
+      vector systems).  Allowing for an error code return would require an
+      awful lot of checking internally.  Perhaps it'd still be worthwhile, but
+      it'd be a lot of changes and the extra code would probably be rather
+      rarely executed in normal usages.
+
+  <p> A <code>longjmp</code> recovery for out-of-memory will currently, in
+      general, lead to memory leaks and may leave GMP variables operated on in
+      inconsistent states.  Maybe it'd be possible to record recovery
+      information for use by the relevant allocate or reallocate function, but
+      that too would be a lot of changes.
+
+  <p> One scheme for out-of-memory would be to note that all GMP allocations go
+      through the <code>mp_set_memory_functions</code> routines.  So if the
+      application has an intended <code>setjmp</code> recovery point it can
+      record memory activity by GMP and abandon space allocated and variables
+      initialized after that point.  This might be as simple as directing the
+      allocation functions to a separate pool, but in general would have the
+      disadvantage of needing application-level bookkeeping on top of the
+      normal system <code>malloc</code>.  An advantage however is that it needs
+      nothing from GMP itself and on that basis doesn't burden applications not
+      needing recovery.  Note that there's probably some details to be worked
+      out here about reallocs of existing variables, and perhaps about copying
+      or swapping between "permanent" and "temporary" variables.
+
+  <p> Applications desiring a fine-grained error control, for instance a
+      language interpreter, would very possibly not be well served by a scheme
+      requiring <code>longjmp</code>.  Wrapping every GMP function call with a
+      <code>setjmp</code> would be very inconvenient.
+
+  <p> Another option would be to let <code>mpz_t</code> etc hold a sort of NaN,
+      a special value indicating an out-of-memory or other failure.  This would
+      be similar to NaNs in mpfr.  Unfortunately such a scheme could only be
+      used by programs prepared to handle such special values, since for
+      instance a program waiting for some condition to be satisfied could
+      become an infinite loop if it wasn't also watching for NaNs.  The work to
+      implement this would be significant too, lots of checking of inputs and
+      intermediate results.  And if <code>mpn</code> routines were to
+      participate in this (which they would have to internally) a lot of new
+      return values would need to be added, since of course there's no
+      <code>mpz_t</code> etc structure for them to indicate failure in.
+
+  <p> Stack overflow is another possible exception, but perhaps not one that
+      can be easily detected in general.  On i386 GNU/Linux for instance GCC
+      normally doesn't generate stack probes for an <code>alloca</code>, but
+      merely adjusts <code>%esp</code>.  A big enough <code>alloca</code> can
+      miss the stack redzone and hit arbitrary data.  GMP stack usage is
+      normally a function of operand size, which might be enough for some
+      applications to know they'll be safe.  Otherwise a fixed maximum usage
+      can probably be obtained by building with
+      <code>--enable-alloca=malloc-reentrant</code> (or
+      <code>notreentrant</code>).  Arranging the default to be
+      <code>alloca</code> only on blocks up to a certain size and
+      <code>malloc</code> thereafter might be a better approach and would have
+      the advantage of not having calculations limited by available stack.
+
+  <p> Actually recovering from stack overflow is of course another problem.  It
+      might be possible to catch a <code>SIGSEGV</code> in the stack redzone
+      and do something in a <code>sigaltstack</code>, on systems which have
+      that, but recovery might otherwise not be possible.  This is worth
+      bearing in mind because there's no point worrying about tight and careful
+      out-of-memory recovery if an out-of-stack is fatal.
+
+  <p> Operand overflow is another exception to be addressed.  It's easy for
+      instance to ask <code>mpz_pow_ui</code> for a result bigger than an
+      <code>mpz_t</code> can possibly represent.  Currently overflows in limb
+      or byte count calculations will go undetected.  Often they'll still end
+      up asking the memory functions for blocks bigger than available memory,
+      but that's by no means certain and results are unpredictable in general.
+      It'd be desirable to tighten up such size calculations.  Probably only
+      selected routines would need checks, if it's assumed say that no input
+      will be more than half of all memory and hence size additions like say
+      <code>mpz_mul</code> won't overflow.
+
+
+<li> <strong>Performance Tool</strong>
+
+  <p> It'd be nice to have some sort of tool for getting an overview of
+      performance.  Clearly a great many things could be done, but some primary
+      uses would be,
+
+      <ol>
+	<li> Checking speed variations between compilers.
+	<li> Checking relative performance between systems or CPUs.
+      </ol>
+
+  <p> A combination of measuring some fundamental routines and some
+      representative application routines might satisfy these.
+
+  <p> The tune/time.c routines would be the easiest way to get good accurate
+      measurements on lots of different systems.  The high level
+      <code>speed_measure</code> may or may not suit, but the basic
+      <code>speed_starttime</code> and <code>speed_endtime</code> would cover
+      lots of portability and accuracy questions.
+
+
+<li> <strong>Using <code>restrict</code></strong>
+
+  <p> There might be some value in judicious use of C99 style
+      <code>restrict</code> on various pointers, but this would need some
+      careful thought about what it implies for the various operand overlaps
+      permitted in GMP.
+
+  <p> Rumour has it some pre-C99 compilers had <code>restrict</code>, but
+      expressing tighter (or perhaps looser) requirements.  Might be worth
+      investigating that before using <code>restrict</code> unconditionally.
+
+  <p> Loops are presumably where the greatest benefit would be had, by allowing
+      the compiler to advance reads ahead of writes, perhaps as part of loop
+      unrolling.  However critical loops are generally coded in assembler, so
+      there might not be very much to gain.  And on Cray systems the explicit
+      use of <code>_Pragma</code> gives an equivalent effect.
+
+  <p> One thing to note is that Microsoft C headers (on ia64 at least) contain
+      <code>__declspec(restrict)</code>, so a <code>#define</code> of
+      <code>restrict</code> should be avoided.  It might be wisest to setup a
+      <code>gmp_restrict</code>.
+
+
+<li> <strong>Prime Testing</strong>
+
+  <p> GMP is not really a number theory library and probably shouldn't have
+      large amounts of code dedicated to sophisticated prime testing
+      algorithms, but basic things well-implemented would suit.  Tests offering
+      certainty are probably all too big or too slow (or both!) to justify
+      inclusion in the main library.  Demo programs showing some possibilities
+      would be good though.
+
+  <p> The present "repetitions" argument to <code>mpz_probab_prime_p</code> is
+      rather specific to the Miller-Rabin tests of the current implementation.
+      Better would be some sort of parameter asking perhaps for a maximum
+      chance 1/2^x of a probable prime in fact being composite.  If
+      applications follow the advice that the present reps gives 1/4^reps
+      chance then perhaps such a change is unnecessary, but an explicitly
+      described 1/2^x would allow for changes in the implementation or even for
+      new proofs about the theory.
+
+  <p> <code>mpz_probab_prime_p</code> always initializes a new
+      <code>gmp_randstate_t</code> for randomized tests, which unfortunately
+      means it's not really very random and in particular always runs the same
+      tests for a given input.  Perhaps a new interface could accept an rstate
+      to use, so successive tests could increase confidence in the result.
+
+  <p> <code>mpn_mod_34lsub1</code> is an obvious and easy improvement to the
+      trial divisions.  And since the various prime factors are constants, the
+      remainder can be tested with something like
+<pre>
+#define MP_LIMB_DIVISIBLE_7_P(n) \
+  ((n) * MODLIMB_INVERSE_7 &lt;= MP_LIMB_T_MAX/7)
+</pre>
+      Which would help compilers that don't know how to optimize divisions by
+      constants, and is even an improvement on current gcc 3.2 code.  This
+      technique works for any modulus, see Granlund and Montgomery "Division by
+      Invariant Integers" section 9.
+
+  <p> The trial divisions are done with primes generated and grouped at
+      runtime.  This could instead be a table of data, with pre-calculated
+      inverses too.  Storing deltas, ie. amounts to add, rather than actual
+      primes would save space.  <code>udiv_qrnnd_preinv</code> style inverses
+      can be made to exist by adding dummy factors of 2 if necessary.  Some
+      thought needs to be given as to how big such a table should be, based on
+      how much dividing would be profitable for what sort of size inputs.  The
+      data could be shared by the perfect power testing.
+
+  <p> Jason Moxham points out that if a sqrt(-1) mod N exists then any factor
+      of N must be == 1 mod 4, saving half the work in trial dividing.  (If
+      x^2==-1 mod N then for a prime factor p we have x^2==-1 mod p and so the
+      jacobi symbol (-1/p)=1.  But also (-1/p)=(-1)^((p-1)/2), hence must have
+      p==1 mod 4.)  But knowing whether sqrt(-1) mod N exists is not too easy.
+      A strong pseudoprime test can reveal one, so perhaps such a test could be
+      inserted part way though the dividing.
+
+  <p> Jon Grantham "Frobenius Pseudoprimes" (www.pseudoprime.com) describes a
+      quadratic pseudoprime test taking about 3x longer than a plain test, but
+      with only a 1/7710 chance of error (whereas 3 plain Miller-Rabin tests
+      would offer only (1/4)^3 == 1/64).  Such a test needs completely random
+      parameters to satisfy the theory, though single-limb values would run
+      faster.  It's probably best to do at least one plain Miller-Rabin before
+      any quadratic tests, since that can identify composites in less total
+      time.
+
+  <p> Some thought needs to be given to the structure of which tests (trial
+      division, Miller-Rabin, quadratic) and how many are done, based on what
+      sort of inputs we expect, with a view to minimizing average time.
+
+  <p> It might be a good idea to break out subroutines for the various tests,
+      so that an application can combine them in ways it prefers, if sensible
+      defaults in <code>mpz_probab_prime_p</code> don't suit.  In particular
+      this would let applications skip tests it knew would be unprofitable,
+      like trial dividing when an input is already known to have no small
+      factors.
+
+  <p> For small inputs, combinations of theory and explicit search make it
+      relatively easy to offer certainty.  For instance numbers up to 2^32
+      could be handled with a strong pseudoprime test and table lookup.  But
+      it's rather doubtful whether a smallnum prime test belongs in a bignum
+      library.  Perhaps if it had other internal uses.
+
+  <p> An <code>mpz_nthprime</code> might be cute, but is almost certainly
+      impractical for anything but small n.
+
+
+<li> <strong>Intra-Library Calls</strong>
+
+  <p> On various systems, calls within libgmp still go through the PLT, TOC or
+      other mechanism, which makes the code bigger and slower than it needs to
+      be.
+
+  <p> The theory would be to have all GMP intra-library calls resolved directly
+      to the routines in the library.  An application wouldn't be able to
+      replace a routine, the way it can normally, but there seems no good
+      reason to do that, in normal circumstances.
+
+  <p> The <code>visibility</code> attribute in recent gcc is good for this,
+      because it lets gcc omit unnecessary GOT pointer setups or whatever if it
+      finds all calls are local and there's no global data references.
+      Documented entrypoints would be <code>protected</code>, and purely
+      internal things not wanted by test programs or anything can be
+      <code>internal</code>.
+
+  <p> Unfortunately, on i386 it seems <code>protected</code> ends up causing
+      text segment relocations within libgmp.so, meaning the library code can't
+      be shared between processes, defeating the purpose of a shared library.
+      Perhaps this is just a gremlin in binutils (debian packaged
+      2.13.90.0.16-1).
+
+  <p> The linker can be told directly (with a link script, or options) to do
+      the same sort of thing.  This doesn't change the code emitted by gcc of
+      course, but it does mean calls are resolved directly to their targets,
+      avoiding a PLT entry.
+
+  <p> Keeping symbols private to libgmp.so is probably a good thing in general
+      too, to stop anyone even attempting to access them.  But some
+      undocumented things will need or want to be kept visible, for use by
+      mpfr, or the test and tune programs.  Libtool has a standard option for
+      selecting public symbols (used now for libmp).
+
+
+<li> <strong>Math functions for the mpf layer</strong>
+
+  <p> Implement the functions of math.h for the GMP mpf layer!	Check the book
+      "Pi and the AGM" by Borwein and Borwein for ideas how to do this.  These
+      functions are desirable: acos, acosh, asin, asinh, atan, atanh, atan2,
+      cos, cosh, exp, log, log10, pow, sin, sinh, tan, tanh.
+
+  <p> Note that the <a href="http://mpfr.org">mpfr</a> functions already
+  provide these functions, and that we usually recommend new programs to use
+  mpfr instead of mpf.
+</ul>
+<hr>
+
+</body>
+</html>
+
+<!--
+Local variables:
+eval: (add-hook 'write-file-hooks 'time-stamp)
+time-stamp-start: "This file current as of "
+time-stamp-format: "%:d %3b %:y"
+time-stamp-end: "\\."
+time-stamp-line-limit: 50
+End:
+-->
diff --git a/third_party/gmp/doc/stamp-vti b/third_party/gmp/doc/stamp-vti
new file mode 100644
index 0000000..e62c3db
--- /dev/null
+++ b/third_party/gmp/doc/stamp-vti
@@ -0,0 +1,4 @@
+@set UPDATED 17 January 2020
+@set UPDATED-MONTH January 2020
+@set EDITION 6.2.0
+@set VERSION 6.2.0
diff --git a/third_party/gmp/doc/tasks.html b/third_party/gmp/doc/tasks.html
new file mode 100644
index 0000000..9a25bef
--- /dev/null
+++ b/third_party/gmp/doc/tasks.html
@@ -0,0 +1,896 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+  <title>GMP Itemized Development Tasks</title>
+  <link rel="shortcut icon" href="favicon.ico">
+  <link rel="stylesheet" href="gmp.css">
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+</head>
+
+<center>
+  <h1>
+    GMP Itemized Development Tasks
+  </h1>
+</center>
+
+<font size=-1>
+<pre>
+Copyright 2000-2004, 2006, 2008, 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.
+</pre>
+</font>
+
+<hr>
+<!-- NB. timestamp updated automatically by emacs -->
+  This file current as of 29 Jan 2014.  An up-to-date version is available at
+  <a href="https://gmplib.org/tasks.html">https://gmplib.org/tasks.html</a>.
+  Please send comments about this page to gmp-devel<font>@</font>gmplib.org.
+
+<p> These are itemized GMP development tasks.  Not all the tasks
+    listed here are suitable for volunteers, but many of them are.
+    Please see the <a href="projects.html">projects file</a> for more
+    sizeable projects.
+
+<p> CAUTION: This file needs updating.  Many of the tasks here have
+either already been taken care of, or have become irrelevant.
+
+<h4>Correctness and Completeness</h4>
+<ul>
+<li> <code>_LONG_LONG_LIMB</code> in gmp.h is not namespace clean.  Reported
+     by Patrick Pelissier.
+     <br>
+     We sort of mentioned <code>_LONG_LONG_LIMB</code> in past releases, so
+     need to be careful about changing it.  It used to be a define
+     applications had to set for long long limb systems, but that in
+     particular is no longer relevant now that it's established automatically.
+<li> The various reuse.c tests need to force reallocation by calling
+     <code>_mpz_realloc</code> with a small (1 limb) size.
+<li> One reuse case is missing from mpX/tests/reuse.c:
+     <code>mpz_XXX(a,a,a)</code>.
+<li> Make the string reading functions allow the `0x' prefix when the base is
+     explicitly 16.  They currently only allow that prefix when the base is
+     unspecified (zero).
+<li> <code>mpf_eq</code> is not always correct, when one operand is
+     1000000000... and the other operand is 0111111111..., i.e., extremely
+     close.  There is a special case in <code>mpf_sub</code> for this
+     situation; put similar code in <code>mpf_eq</code>.  [In progress.]
+<li> <code>mpf_eq</code> doesn't implement what gmp.texi specifies.  It should
+     not use just whole limbs, but partial limbs.  [In progress.]
+<li> <code>mpf_set_str</code> doesn't validate it's exponent, for instance
+     garbage 123.456eX789X is accepted (and an exponent 0 used), and overflow
+     of a <code>long</code> is not detected.
+<li> <code>mpf_add</code> doesn't check for a carry from truncated portions of
+     the inputs, and in that respect doesn't implement the "infinite precision
+     followed by truncate" specified in the manual.
+<li> Windows DLLs: tests/mpz/reuse.c and tests/mpf/reuse.c initialize global
+     variables with pointers to <code>mpz_add</code> etc, which doesn't work
+     when those routines are coming from a DLL (because they're effectively
+     function pointer global variables themselves).  Need to rearrange perhaps
+     to a set of calls to a test function rather than iterating over an array.
+<li> <code>mpz_pow_ui</code>: Detect when the result would be more memory than
+     a <code>size_t</code> can represent and raise some suitable exception,
+     probably an alloc call asking for <code>SIZE_T_MAX</code>, and if that
+     somehow succeeds then an <code>abort</code>.  Various size overflows of
+     this kind are not handled gracefully, probably resulting in segvs.
+     <br>
+     In <code>mpz_n_pow_ui</code>, detect when the count of low zero bits
+     exceeds an <code>unsigned long</code>.  There's a (small) chance of this
+     happening but still having enough memory to represent the value.
+     Reported by Winfried Dreckmann in for instance <code>mpz_ui_pow_ui (x,
+     4UL, 1431655766UL)</code>.
+<li> <code>mpf</code>: Detect exponent overflow and raise some exception.
+     It'd be nice to allow the full <code>mp_exp_t</code> range since that's
+     how it's been in the past, but maybe dropping one bit would make it
+     easier to test if e1+e2 goes out of bounds.
+</ul>
+
+
+
+<h4>Machine Independent Optimization</h4>
+<ul>
+<li> <code>mpf_cmp</code>: For better cache locality, don't test for low zero
+     limbs until the high limbs fail to give an ordering.  Reduce code size by
+     turning the three <code>mpn_cmp</code>'s into a single loop stopping when
+     the end of one operand is reached (and then looking for a non-zero in the
+     rest of the other).
+<li> <code>mpf_mul_2exp</code>, <code>mpf_div_2exp</code>: The use of
+     <code>mpn_lshift</code> for any size&lt;=prec means repeated
+     <code>mul_2exp</code> and <code>div_2exp</code> calls accumulate low zero
+     limbs until size==prec+1 is reached.  Those zeros will slow down
+     subsequent operations, especially if the value is otherwise only small.
+     If low bits of the low limb are zero, use <code>mpn_rshift</code> so as
+     to not increase the size.
+<li> <code>mpn_dc_sqrtrem</code>, <code>mpn_sqrtrem2</code>: Don't use
+     <code>mpn_add_1</code> and <code>mpn_sub_1</code> for 1 limb operations,
+     instead <code>ADDC_LIMB</code> and <code>SUBC_LIMB</code>.
+<li> <code>mpn_sqrtrem2</code>: Use plain variables for <code>sp[0]</code> and
+     <code>rp[0]</code> calculations, so the compiler needn't worry about
+     aliasing between <code>sp</code> and <code>rp</code>.
+<li> <code>mpn_sqrtrem</code>: Some work can be saved in the last step when
+     the remainder is not required, as noted in Paul's paper.
+<li> <code>mpq_add</code>, <code>mpq_sub</code>: The gcd fits a single limb
+     with high probability and in this case <code>binvert_limb</code> could
+     be used to calculate the inverse just once for the two exact divisions
+     "op1.den / gcd" and "op2.den / gcd", rather than letting
+     <code>mpn_bdiv_q_1</code> do it each time.  This would require calling
+     <code>mpn_pi1_bdiv_q_1</code>.
+<li> <code>mpn_gcdext</code>: Don't test <code>count_leading_zeros</code> for
+     zero, instead check the high bit of the operand and avoid invoking
+     <code>count_leading_zeros</code>.  This is an optimization on all
+     machines, and significant on machines with slow
+     <code>count_leading_zeros</code>, though it's possible an already
+     normalized operand might not be encountered very often.
+<li> Rewrite <code>umul_ppmm</code> to use floating-point for generating the
+     most significant limb (if <code>GMP_LIMB_BITS</code> &lt= 52 bits).
+     (Peter Montgomery has some ideas on this subject.)
+<li> Improve the default <code>umul_ppmm</code> code in longlong.h: Add partial
+     products with fewer operations.
+<li> Consider inlining <code>mpz_set_ui</code>.  This would be both small and
+     fast, especially for compile-time constants, but would make application
+     binaries depend on having 1 limb allocated to an <code>mpz_t</code>,
+     preventing the "lazy" allocation scheme below.
+<li> Consider inlining <code>mpz_[cft]div_ui</code> and maybe
+     <code>mpz_[cft]div_r_ui</code>.  A <code>__gmp_divide_by_zero</code>
+     would be needed for the divide by zero test, unless that could be left to
+     <code>mpn_mod_1</code> (not sure currently whether all the risc chips
+     provoke the right exception there if using mul-by-inverse).
+<li> Consider inlining: <code>mpz_fits_s*_p</code>.  The setups for
+     <code>LONG_MAX</code> etc would need to go into gmp.h, and on Cray it
+     might, unfortunately, be necessary to forcibly include &lt;limits.h&gt;
+     since there's no apparent way to get <code>SHRT_MAX</code> with an
+     expression (since <code>short</code> and <code>unsigned short</code> can
+     be different sizes).
+<li> <code>mpz_powm</code> and <code>mpz_powm_ui</code> aren't very fast on one
+     or two limb moduli, due to a lot of function call overheads.  These could
+     perhaps be handled as special cases.
+<li> Make sure <code>mpz_powm_ui</code> is never slower than the corresponding
+     computation using <code>mpz_powm</code>.
+<li> <code>mpz_powm</code> REDC should do multiplications by <code>g[]</code>
+     using the division method when they're small, since the REDC form of a
+     small multiplier is normally a full size product.  Probably would need a
+     new tuned parameter to say what size multiplier is "small", as a function
+     of the size of the modulus.
+<li> <code>mpn_gcd</code> might be able to be sped up on small to moderate
+     sizes by improving <code>find_a</code>, possibly just by providing an
+     alternate implementation for CPUs with slowish
+     <code>count_leading_zeros</code>.
+<li> <code>mpf_set_str</code> produces low zero limbs when a string has a
+     fraction but is exactly representable, eg. 0.5 in decimal.  These could be
+     stripped to save work in later operations.
+<li> <code>mpz_and</code>, <code>mpz_ior</code> and <code>mpz_xor</code> should
+     use <code>mpn_and_n</code> etc for the benefit of the small number of
+     targets with native versions of those routines.  Need to be careful not to
+     pass size==0.  Is some code sharing possible between the <code>mpz</code>
+     routines?
+<li> <code>mpf_add</code>: Don't do a copy to avoid overlapping operands
+     unless it's really necessary (currently only sizes are tested, not
+     whether r really is u or v).
+<li> <code>mpf_add</code>: Under the check for v having no effect on the
+     result, perhaps test for r==u and do nothing in that case, rather than
+     currently it looks like an <code>MPN_COPY_INCR</code> will be done to
+     reduce prec+1 limbs to prec.
+<li> <code>mpf_div_ui</code>: Instead of padding with low zeros, call
+     <code>mpn_divrem_1</code> asking for fractional quotient limbs.
+<li> <code>mpf_div_ui</code>: Eliminate <code>TMP_ALLOC</code>.  When r!=u
+     there's no overlap and the division can be called on those operands.
+     When r==u and is prec+1 limbs, then it's an in-place division.  If r==u
+     and not prec+1 limbs, then move the available limbs up to prec+1 and do
+     an in-place there.
+<li> <code>mpf_div_ui</code>: Whether the high quotient limb is zero can be
+     determined by testing the dividend for high&lt;divisor.  When non-zero, the
+     division can be done on prec dividend limbs instead of prec+1.  The result
+     size is also known before the division, so that can be a tail call (once
+     the <code>TMP_ALLOC</code> is eliminated).
+<li> <code>mpn_divrem_2</code> could usefully accept unnormalized divisors and
+     shift the dividend on-the-fly, since this should cost nothing on
+     superscalar processors and avoid the need for temporary copying in
+     <code>mpn_tdiv_qr</code>.
+<li> <code>mpf_sqrt</code>: If r!=u, and if u doesn't need to be padded with
+     zeros, then there's no need for the tp temporary.
+<li> <code>mpq_cmp_ui</code> could form the <code>num1*den2</code> and
+     <code>num2*den1</code> products limb-by-limb from high to low and look at
+     each step for values differing by more than the possible carry bit from
+     the uncalculated portion.
+<li> <code>mpq_cmp</code> could do the same high-to-low progressive multiply
+     and compare.  The benefits of karatsuba and higher multiplication
+     algorithms are lost, but if it's assumed only a few high limbs will be
+     needed to determine an order then that's fine.
+<li> <code>mpn_add_1</code>, <code>mpn_sub_1</code>, <code>mpn_add</code>,
+     <code>mpn_sub</code>: Internally use <code>__GMPN_ADD_1</code> etc
+     instead of the functions, so they get inlined on all compilers, not just
+     gcc and others with <code>inline</code> recognised in gmp.h.
+     <code>__GMPN_ADD_1</code> etc are meant mostly to support application
+     inline <code>mpn_add_1</code> etc and if they don't come out good for
+     internal uses then special forms can be introduced, for instance many
+     internal uses are in-place.  Sometimes a block of code is executed based
+     on the carry-out, rather than using it arithmetically, and those places
+     might want to do their own loops entirely.
+<li> <code>__gmp_extract_double</code> on 64-bit systems could use just one
+     bitfield for the mantissa extraction, not two, when endianness permits.
+     Might depend on the compiler allowing <code>long long</code> bit fields
+     when that's the only actual 64-bit type.
+<li> tal-notreent.c could keep a block of memory permanently allocated.
+     Currently the last nested <code>TMP_FREE</code> releases all memory, so
+     there's an allocate and free every time a top-level function using
+     <code>TMP</code> is called.  Would need
+     <code>mp_set_memory_functions</code> to tell tal-notreent.c to release
+     any cached memory when changing allocation functions though.
+<li> <code>__gmp_tmp_alloc</code> from tal-notreent.c could be partially
+     inlined.  If the current chunk has enough room then a couple of pointers
+     can be updated.  Only if more space is required then a call to some sort
+     of <code>__gmp_tmp_increase</code> would be needed.  The requirement that
+     <code>TMP_ALLOC</code> is an expression might make the implementation a
+     bit ugly and/or a bit sub-optimal.
+<pre>
+#define TMP_ALLOC(n)
+  ((ROUND_UP(n) &gt; current-&gt;end - current-&gt;point ?
+     __gmp_tmp_increase (ROUND_UP (n)) : 0),
+     current-&gt;point += ROUND_UP (n),
+     current-&gt;point - ROUND_UP (n))
+</pre>
+<li> <code>__mp_bases</code> has a lot of data for bases which are pretty much
+     never used.  Perhaps the table should just go up to base 16, and have
+     code to generate data above that, if and when required.  Naturally this
+     assumes the code would be smaller than the data saved.
+<li> <code>__mp_bases</code> field <code>big_base_inverted</code> is only used
+     if <code>USE_PREINV_DIVREM_1</code> is true, and could be omitted
+     otherwise, to save space.
+<li> <code>mpz_get_str</code>, <code>mtox</code>: For power-of-2 bases, which
+     are of course fast, it seems a little silly to make a second pass over
+     the <code>mpn_get_str</code> output to convert to ASCII.  Perhaps combine
+     that with the bit extractions.
+<li> <code>mpz_gcdext</code>: If the caller requests only the S cofactor (of
+     A), and A&lt;B, then the code ends up generating the cofactor T (of B) and
+     deriving S from that.  Perhaps it'd be possible to arrange to get S in
+     the first place by calling <code>mpn_gcdext</code> with A+B,B.  This
+     might only be an advantage if A and B are about the same size.
+<li> <code>mpz_n_pow_ui</code> does a good job with small bases and stripping
+     powers of 2, but it's perhaps a bit too complicated for what it gains.
+     The simpler <code>mpn_pow_1</code> is a little faster on small exponents.
+     (Note some of the ugliness in <code>mpz_n_pow_ui</code> is due to
+     supporting <code>mpn_mul_2</code>.)
+     <br>
+     Perhaps the stripping of 2s in <code>mpz_n_pow_ui</code> should be
+     confined to single limb operands for simplicity and since that's where
+     the greatest gain would be.
+     <br>
+     Ideally <code>mpn_pow_1</code> and <code>mpz_n_pow_ui</code> would be
+     merged.  The reason <code>mpz_n_pow_ui</code> writes to an
+     <code>mpz_t</code> is that its callers leave it to make a good estimate
+     of the result size.  Callers of <code>mpn_pow_1</code> already know the
+     size by separate means (<code>mp_bases</code>).
+<li> <code>mpz_invert</code> should call <code>mpn_gcdext</code> directly.
+</ul>
+
+
+<h4>Machine Dependent Optimization</h4>
+<ul>
+<li> <code>invert_limb</code> on various processors might benefit from the
+     little Newton iteration done for alpha and ia64.
+<li> Alpha 21264: <code>mpn_addlsh1_n</code> could be implemented with
+     <code>mpn_addmul_1</code>, since that code at 3.5 is a touch faster than
+     a separate <code>lshift</code> and <code>add_n</code> at
+     1.75+2.125=3.875.  Or very likely some specific <code>addlsh1_n</code>
+     code could beat both.
+<li> Alpha 21264: Improve feed-in code for <code>mpn_mul_1</code>,
+     <code>mpn_addmul_1</code>, and <code>mpn_submul_1</code>.
+<li> Alpha 21164: Rewrite <code>mpn_mul_1</code>, <code>mpn_addmul_1</code>,
+     and <code>mpn_submul_1</code> for the 21164.  This should use both integer
+     multiplies and floating-point multiplies.  For the floating-point
+     operations, the single-limb multiplier should be split into three 21-bit
+     chunks, or perhaps even better in four 16-bit chunks.  Probably possible
+     to reach 9 cycles/limb.
+<li> Alpha: GCC 3.4 will introduce <code>__builtin_ctzl</code>,
+     <code>__builtin_clzl</code> and <code>__builtin_popcountl</code> using
+     the corresponding CIX <code>ct</code> instructions, and
+     <code>__builtin_alpha_cmpbge</code>.  These should give GCC more
+     information about scheduling etc than the <code>asm</code> blocks
+     currently used in longlong.h and gmp-impl.h.
+<li> Alpha Unicos: Apparently there's no <code>alloca</code> on this system,
+     making <code>configure</code> choose the slower
+     <code>malloc-reentrant</code> allocation method.  Is there a better way?
+     Maybe variable-length arrays per notes below.
+<li> Alpha Unicos 21164, 21264: <code>.align</code> is not used since it pads
+     with garbage.  Does the code get the intended slotting required for the
+     claimed speeds?  <code>.align</code> at the start of a function would
+     presumably be safe no matter how it pads.
+<li> ARM V5: <code>count_leading_zeros</code> can use the <code>clz</code>
+     instruction.  For GCC 3.4 and up, do this via <code>__builtin_clzl</code>
+     since then gcc knows it's "predicable".
+<li> Itanium: GCC 3.4 introduces <code>__builtin_popcount</code> which can be
+     used instead of an <code>asm</code> block.  The builtin should give gcc
+     more opportunities for scheduling, bundling and predication.
+     <code>__builtin_ctz</code> similarly (it just uses popcount as per
+     current longlong.h).
+<li> UltraSPARC/64: Optimize <code>mpn_mul_1</code>, <code>mpn_addmul_1</code>,
+     for s2 &lt; 2^32 (or perhaps for any zero 16-bit s2 chunk).  Not sure how
+     much this can improve the speed, though, since the symmetry that we rely
+     on is lost.  Perhaps we can just gain cycles when s2 &lt; 2^16, or more
+     accurately, when two 16-bit s2 chunks which are 16 bits apart are zero.
+<li> UltraSPARC/64: Write native <code>mpn_submul_1</code>, analogous to
+     <code>mpn_addmul_1</code>.
+<li> UltraSPARC/64: Write <code>umul_ppmm</code>.  Using four
+     "<code>mulx</code>"s either with an asm block or via the generic C code is
+     about 90 cycles.  Try using fp operations, and also try using karatsuba
+     for just three "<code>mulx</code>"s.
+<li> UltraSPARC/32: Rewrite <code>mpn_lshift</code>, <code>mpn_rshift</code>.
+     Will give 2 cycles/limb.  Trivial modifications of mpn/sparc64 should do.
+<li> UltraSPARC/32: Write special mpn_Xmul_1 loops for s2 &lt; 2^16.
+<li> UltraSPARC/32: Use <code>mulx</code> for <code>umul_ppmm</code> if
+     possible (see commented out code in longlong.h).  This is unlikely to
+     save more than a couple of cycles, so perhaps isn't worth bothering with.
+<li> UltraSPARC/32: On Solaris gcc doesn't give us <code>__sparc_v9__</code>
+     or anything to indicate V9 support when -mcpu=v9 is selected.  See
+     gcc/config/sol2-sld-64.h.  Will need to pass something through from
+     ./configure to select the right code in longlong.h.  (Currently nothing
+     is lost because <code>mulx</code> for multiplying is commented out.)
+<li> UltraSPARC/32: <code>mpn_divexact_1</code> and
+     <code>mpn_modexact_1c_odd</code> can use a 64-bit inverse and take
+     64-bits at a time from the dividend, as per the 32-bit divisor case in
+     mpn/sparc64/mode1o.c.  This must be done in assembler, since the full
+     64-bit registers (<code>%gN</code>) are not available from C.
+<li> UltraSPARC/32: <code>mpn_divexact_by3c</code> can work 64-bits at a time
+     using <code>mulx</code>, in assembler.  This would be the same as for
+     sparc64.
+<li> UltraSPARC: <code>binvert_limb</code> might save a few cycles from
+     masking down to just the useful bits at each point in the calculation,
+     since <code>mulx</code> speed depends on the highest bit set.  Either
+     explicit masks or small types like <code>short</code> and
+     <code>int</code> ought to work.
+<li> Sparc64 HAL R1 <code>popc</code>: This chip reputedly implements
+     <code>popc</code> properly (see gcc sparc.md).  Would need to recognise
+     it as <code>sparchalr1</code> or something in configure / config.sub /
+     config.guess.  <code>popc_limb</code> in gmp-impl.h could use this (per
+     commented out code).  <code>count_trailing_zeros</code> could use it too.
+<li> PA64: Improve <code>mpn_addmul_1</code>, <code>mpn_submul_1</code>, and
+     <code>mpn_mul_1</code>.  The current code runs at 11 cycles/limb.  It
+     should be possible to saturate the cache, which will happen at 8
+     cycles/limb (7.5 for mpn_mul_1).  Write special loops for s2 &lt; 2^32;
+     it should be possible to make them run at about 5 cycles/limb.
+<li> PPC601: See which of the power or powerpc32 code runs better.  Currently
+     the powerpc32 is used, but only because it's the default for
+     <code>powerpc*</code>.
+<li> PPC630: Rewrite <code>mpn_addmul_1</code>, <code>mpn_submul_1</code>, and
+     <code>mpn_mul_1</code>.  Use both integer and floating-point operations,
+     possibly two floating-point and one integer limb per loop.  Split operands
+     into four 16-bit chunks for fast fp operations.  Should easily reach 9
+     cycles/limb (using one int + one fp), but perhaps even 7 cycles/limb
+     (using one int + two fp).
+<li> PPC630: <code>mpn_rshift</code> could do the same sort of unrolled loop
+     as <code>mpn_lshift</code>.  Some judicious use of m4 might let the two
+     share source code, or with a register to control the loop direction
+     perhaps even share object code.
+<li> Implement <code>mpn_mul_basecase</code> and <code>mpn_sqr_basecase</code>
+     for important machines.  Helping the generic sqr_basecase.c with an
+     <code>mpn_sqr_diagonal</code> might be enough for some of the RISCs.
+<li> POWER2/POWER2SC: Schedule <code>mpn_lshift</code>/<code>mpn_rshift</code>.
+     Will bring time from 1.75 to 1.25 cycles/limb.
+<li> X86: Optimize non-MMX <code>mpn_lshift</code> for shifts by 1.  (See
+     Pentium code.)
+<li> X86: Good authority has it that in the past an inline <code>rep
+     movs</code> would upset GCC register allocation for the whole function.
+     Is this still true in GCC 3?  It uses <code>rep movs</code> itself for
+     <code>__builtin_memcpy</code>.  Examine the code for some simple and
+     complex functions to find out.  Inlining <code>rep movs</code> would be
+     desirable, it'd be both smaller and faster.
+<li> Pentium P54: <code>mpn_lshift</code> and <code>mpn_rshift</code> can come
+     down from 6.0 c/l to 5.5 or 5.375 by paying attention to pairing after
+     <code>shrdl</code> and <code>shldl</code>, see mpn/x86/pentium/README.
+<li> Pentium P55 MMX: <code>mpn_lshift</code> and <code>mpn_rshift</code>
+     might benefit from some destination prefetching.
+<li> PentiumPro: <code>mpn_divrem_1</code> might be able to use a
+     mul-by-inverse, hoping for maybe 30 c/l.
+<li> K7: <code>mpn_lshift</code> and <code>mpn_rshift</code> might be able to
+     do something branch-free for unaligned startups, and shaving one insn
+     from the loop with alternative indexing might save a cycle.
+<li> PPC32: Try using fewer registers in the current <code>mpn_lshift</code>.
+     The pipeline is now extremely deep, perhaps unnecessarily deep.
+<li> Fujitsu VPP: Vectorize main functions, perhaps in assembly language.
+<li> Fujitsu VPP: Write <code>mpn_mul_basecase</code> and
+     <code>mpn_sqr_basecase</code>.  This should use a "vertical multiplication
+     method", to avoid carry propagation.  splitting one of the operands in
+     11-bit chunks.
+<li> Pentium: <code>mpn_lshift</code> by 31 should use the special rshift
+     by 1 code, and vice versa <code>mpn_rshift</code> by 31 should use the
+     special lshift by 1.  This would be best as a jump across to the other
+     routine, could let both live in lshift.asm and omit rshift.asm on finding
+     <code>mpn_rshift</code> already provided.
+<li> Cray T3E: Experiment with optimization options.  In particular,
+     -hpipeline3 seems promising.  We should at least up -O to -O2 or -O3.
+<li> Cray: <code>mpn_com</code> and <code>mpn_and_n</code> etc very probably
+     wants a pragma like <code>MPN_COPY_INCR</code>.
+<li> Cray vector systems: <code>mpn_lshift</code>, <code>mpn_rshift</code>,
+     <code>mpn_popcount</code> and <code>mpn_hamdist</code> are nice and small
+     and could be inlined to avoid function calls.
+<li> Cray: Variable length arrays seem to be faster than the tal-notreent.c
+     scheme.  Not sure why, maybe they merely give the compiler more
+     information about aliasing (or the lack thereof).  Would like to modify
+     <code>TMP_ALLOC</code> to use them, or introduce a new scheme.  Memory
+     blocks wanted unconditionally are easy enough, those wanted only
+     sometimes are a problem.  Perhaps a special size calculation to ask for a
+     dummy length 1 when unwanted, or perhaps an inlined subroutine
+     duplicating code under each conditional.  Don't really want to turn
+     everything into a dog's dinner just because Cray don't offer an
+     <code>alloca</code>.
+<li> Cray: <code>mpn_get_str</code> on power-of-2 bases ought to vectorize.
+     Does it?  <code>bits_per_digit</code> and the inner loop over bits in a
+     limb might prevent it.  Perhaps special cases for binary, octal and hex
+     would be worthwhile (very possibly for all processors too).
+<li> S390: <code>BSWAP_LIMB_FETCH</code> looks like it could be done with
+     <code>lrvg</code>, as per glibc sysdeps/s390/s390-64/bits/byteswap.h.
+     This is only for 64-bit mode or something is it, since 32-bit mode has
+     other code?  Also, is it worth using for <code>BSWAP_LIMB</code> too, or
+     would that mean a store and re-fetch?  Presumably that's what comes out
+     in glibc.
+<li> Improve <code>count_leading_zeros</code> for 64-bit machines:
+  <pre>
+	   if ((x &gt&gt 32) == 0) { x &lt&lt= 32; cnt += 32; }
+	   if ((x &gt&gt 48) == 0) { x &lt&lt= 16; cnt += 16; }
+	   ... </pre>
+<li> IRIX 6 MIPSpro compiler has an <code>__inline</code> which could perhaps
+     be used in <code>__GMP_EXTERN_INLINE</code>.  What would be the right way
+     to identify suitable versions of that compiler?
+<li> IRIX <code>cc</code> is rumoured to have an <code>_int_mult_upper</code>
+     (in <code>&lt;intrinsics.h&gt;</code> like Cray), but it didn't seem to
+     exist on some IRIX 6.5 systems tried.  If it does actually exist
+     somewhere it would very likely be an improvement over a function call to
+     umul.asm.
+<li> <code>mpn_get_str</code> final divisions by the base with
+     <code>udiv_qrnd_unnorm</code> could use some sort of multiply-by-inverse
+     on suitable machines.  This ends up happening for decimal by presenting
+     the compiler with a run-time constant, but the same for other bases would
+     be good.  Perhaps use could be made of the fact base&lt;256.
+<li> <code>mpn_umul_ppmm</code>, <code>mpn_udiv_qrnnd</code>: Return a
+     structure like <code>div_t</code> to avoid going through memory, in
+     particular helping RISCs that don't do store-to-load forwarding.  Clearly
+     this is only possible if the ABI returns a structure of two
+     <code>mp_limb_t</code>s in registers.
+     <br>
+     On PowerPC, structures are returned in memory on AIX and Darwin.  In SVR4
+     they're returned in registers, except that draft SVR4 had said memory, so
+     it'd be prudent to check which is done.  We can jam the compiler into the
+     right mode if we know how, since all this is purely internal to libgmp.
+     (gcc has an option, though of course gcc doesn't matter since we use
+     inline asm there.)
+</ul>
+
+<h4>New Functionality</h4>
+<ul>
+<li> Maybe add <code>mpz_crr</code> (Chinese Remainder Reconstruction).
+<li> Let `0b' and `0B' mean binary input everywhere.
+<li> <code>mpz_init</code> and <code>mpq_init</code> could do lazy allocation.
+     Set <code>ALLOC(var)</code> to 0 to indicate nothing allocated, and let
+     <code>_mpz_realloc</code> do the initial alloc.  Set
+     <code>z-&gt;_mp_d</code> to a dummy that <code>mpz_get_ui</code> and
+     similar can unconditionally fetch from.  Niels Möller has had a go at
+     this.
+     <br>
+     The advantages of the lazy scheme would be:
+     <ul>
+     <li> Initial allocate would be the size required for the first value
+          stored, rather than getting 1 limb in <code>mpz_init</code> and then
+          more or less immediately reallocating.
+     <li> <code>mpz_init</code> would only store magic values in the
+          <code>mpz_t</code> fields, and could be inlined.
+     <li> A fixed initializer could even be used by applications, like
+          <code>mpz_t z = MPZ_INITIALIZER;</code>, which might be convenient
+          for globals.
+     </ul>
+     The advantages of the current scheme are:
+     <ul>
+     <li> <code>mpz_set_ui</code> and other similar routines needn't check the
+          size allocated and can just store unconditionally.
+     <li> <code>mpz_set_ui</code> and perhaps others like
+          <code>mpz_tdiv_r_ui</code> and a prospective
+          <code>mpz_set_ull</code> could be inlined.
+     </ul>
+<li> Add <code>mpf_out_raw</code> and <code>mpf_inp_raw</code>.  Make sure
+     format is portable between 32-bit and 64-bit machines, and between
+     little-endian and big-endian machines.  A format which MPFR can use too
+     would be good.
+<li> <code>mpn_and_n</code> ... <code>mpn_copyd</code>: Perhaps make the mpn
+     logops and copys available in gmp.h, either as library functions or
+     inlines, with the availability of library functions instantiated in the
+     generated gmp.h at build time.
+<li> <code>mpz_set_str</code> etc variants taking string lengths rather than
+     null-terminators.
+<li> <code>mpz_andn</code>, <code>mpz_iorn</code>, <code>mpz_nand</code>,
+     <code>mpz_nior</code>, <code>mpz_xnor</code> might be useful additions,
+     if they could share code with the current such functions (which should be
+     possible).
+<li> <code>mpz_and_ui</code> etc might be of use sometimes.  Suggested by
+     Niels Möller.
+<li> <code>mpf_set_str</code> and <code>mpf_inp_str</code> could usefully
+     accept 0x, 0b etc when base==0.  Perhaps the exponent could default to
+     decimal in this case, with a further 0x, 0b etc allowed there.
+     Eg. 0xFFAA@0x5A.  A leading "0" for octal would match the integers, but
+     probably something like "0.123" ought not mean octal.
+<li> <code>GMP_LONG_LONG_LIMB</code> or some such could become a documented
+     feature of gmp.h, so applications could know whether to
+     <code>printf</code> a limb using <code>%lu</code> or <code>%Lu</code>.
+<li> <code>GMP_PRIdMP_LIMB</code> and similar defines following C99
+     &lt;inttypes.h&gt; might be of use to applications printing limbs.  But
+     if <code>GMP_LONG_LONG_LIMB</code> or whatever is added then perhaps this
+     can easily enough be left to applications.
+<li> <code>gmp_printf</code> could accept <code>%b</code> for binary output.
+     It'd be nice if it worked for plain <code>int</code> etc too, not just
+     <code>mpz_t</code> etc.
+<li> <code>gmp_printf</code> in fact could usefully accept an arbitrary base,
+     for both integer and float conversions.  A base either in the format
+     string or as a parameter with <code>*</code> should be allowed.  Maybe
+     <code>&amp;13b</code> (b for base) or something like that.
+<li> <code>gmp_printf</code> could perhaps accept <code>mpq_t</code> for float
+     conversions, eg. <code>"%.4Qf"</code>.  This would be merely for
+     convenience, but still might be useful.  Rounding would be the same as
+     for an <code>mpf_t</code> (ie. currently round-to-nearest, but not
+     actually documented).  Alternately, perhaps a separate
+     <code>mpq_get_str_point</code> or some such might be more use.  Suggested
+     by Pedro Gimeno.
+<li> <code>mpz_rscan0</code> or <code>mpz_revscan0</code> or some such
+     searching towards the low end of an integer might match
+     <code>mpz_scan0</code> nicely.  Likewise for <code>scan1</code>.
+     Suggested by Roberto Bagnara.
+<li> <code>mpz_bit_subset</code> or some such to test whether one integer is a
+     bitwise subset of another might be of use.  Some sort of return value
+     indicating whether it's a proper or non-proper subset would be good and
+     wouldn't cost anything in the implementation.  Suggested by Roberto
+     Bagnara.
+<li> <code>mpf_get_ld</code>, <code>mpf_set_ld</code>: Conversions between
+     <code>mpf_t</code> and <code>long double</code>, suggested by Dan
+     Christensen.  Other <code>long double</code> routines might be desirable
+     too, but <code>mpf</code> would be a start.
+     <br>
+     <code>long double</code> is an ANSI-ism, so everything involving it would
+     need to be suppressed on a K&amp;R compiler.
+     <br>
+     There'd be some work to be done by <code>configure</code> to recognise
+     the format in use, MPFR has a start on this.  Often <code>long
+     double</code> is the same as <code>double</code>, which is easy but
+     pretty pointless.  A single float format detector macro could look at
+     <code>double</code> then <code>long double</code>
+     <br>
+     Sometimes there's a compiler option for the size of a <code>long
+     double</code>, eg. xlc on AIX can use either 64-bit or 128-bit.  It's
+     probably simplest to regard this as a compiler compatibility issue, and
+     leave it to users or sysadmins to ensure application and library code is
+     built the same.
+<li> <code>mpz_sqrt_if_perfect_square</code>: When
+     <code>mpz_perfect_square_p</code> does its tests it calculates a square
+     root and then discards it.  For some applications it might be useful to
+     return that root.  Suggested by Jason Moxham.
+<li> <code>mpz_get_ull</code>, <code>mpz_set_ull</code>,
+     <code>mpz_get_sll</code>, <code>mpz_get_sll</code>: Conversions for
+     <code>long long</code>.  These would aid interoperability, though a
+     mixture of GMP and <code>long long</code> would probably not be too
+     common.  Since <code>long long</code> is not always available (it's in
+     C99 and GCC though), disadvantages of using <code>long long</code> in
+     libgmp.a would be
+     <ul>
+     <li> Library contents vary according to the build compiler.
+     <li> gmp.h would need an ugly <code>#ifdef</code> block to decide if the
+          application compiler could take the <code>long long</code>
+          prototypes.
+     <li> Some sort of <code>LIBGMP_HAS_LONGLONG</code> might be wanted to
+          indicate whether the functions are available.  (Applications using
+          autoconf could probe the library too.)
+     </ul>
+     It'd be possible to defer the need for <code>long long</code> to
+     application compile time, by having something like
+     <code>mpz_set_2ui</code> called with two halves of a <code>long
+     long</code>.  Disadvantages of this would be,
+     <ul>
+     <li> Bigger code in the application, though perhaps not if a <code>long
+          long</code> is normally passed as two halves anyway.
+     <li> <code>mpz_get_ull</code> would be a rather big inline, or would have
+          to be two function calls.
+     <li> <code>mpz_get_sll</code> would be a worse inline, and would put the
+          treatment of <code>-0x10..00</code> into applications (see
+          <code>mpz_get_si</code> correctness above).
+     <li> Although having libgmp.a independent of the build compiler is nice,
+          it sort of sacrifices the capabilities of a good compiler to
+          uniformity with inferior ones.
+     </ul>
+     Plain use of <code>long long</code> is probably the lesser evil, if only
+     because it makes best use of gcc.  In fact perhaps it would suffice to
+     guarantee <code>long long</code> conversions only when using GCC for both
+     application and library.  That would cover free software, and we can
+     worry about selected vendor compilers later.
+     <br>
+     In C++ the situation is probably clearer, we demand fairly recent C++ so
+     <code>long long</code> should be available always.  We'd probably prefer
+     to have the C and C++ the same in respect of <code>long long</code>
+     support, but it would be possible to have it unconditionally in gmpxx.h,
+     by some means or another.
+<li> <code>mpz_strtoz</code> parsing the same as <code>strtol</code>.
+     Suggested by Alexander Kruppa.
+</ul>
+
+
+<h4>Configuration</h4>
+
+<ul>
+<li> Alpha ev7, ev79: Add code to config.guess to detect these.  Believe ev7
+     will be "3-1307" in the current switch, but need to verify that.  (On
+     OSF, current configfsf.guess identifies ev7 using psrinfo, we need to do
+     it ourselves for other systems.)
+<li> Alpha OSF: Libtool (version 1.5) doesn't seem to recognise this system is
+     "pic always" and ends up running gcc twice with the same options.  This
+     is wasteful, but harmless.  Perhaps a newer libtool will be better.
+<li> ARM: <code>umul_ppmm</code> in longlong.h always uses <code>umull</code>,
+     but is that available only for M series chips or some such?  Perhaps it
+     should be configured in some way.
+<li> HPPA: config.guess should recognize 7000, 7100, 7200, and 8x00.
+<li> HPPA: gcc 3.2 introduces a <code>-mschedule=7200</code> etc parameter,
+     which could be driven by an exact hppa cpu type.
+<li> Mips: config.guess should say mipsr3000, mipsr4000, mipsr10000, etc.
+     "hinv -c processor" gives lots of information on Irix.  Standard
+     config.guess appends "el" to indicate endianness, but
+     <code>AC_C_BIGENDIAN</code> seems the best way to handle that for GMP.
+<li> PowerPC: The function descriptor nonsense for AIX is currently driven by
+     <code>*-*-aix*</code>.  It might be more reliable to do some sort of
+     feature test, examining the compiler output perhaps.  It might also be
+     nice to merge the aix.m4 files into powerpc-defs.m4.
+<li> config.m4 is generated only by the configure script, it won't be
+     regenerated by config.status.  Creating it as an <code>AC_OUTPUT</code>
+     would work, but it might upset "make" to have things like <code>L$</code>
+     get into the Makefiles through <code>AC_SUBST</code>.
+     <code>AC_CONFIG_COMMANDS</code> would be the alternative.  With some
+     careful m4 quoting the <code>changequote</code> calls might not be
+     needed, which might free up the order in which things had to be output.
+<li> Automake: Latest automake has a <code>CCAS</code>, <code>CCASFLAGS</code>
+     scheme.  Though we probably wouldn't be using its assembler support we
+     could try to use those variables in compatible ways.
+<li> <code>GMP_LDFLAGS</code> could probably be done with plain
+     <code>LDFLAGS</code> already used by automake for all linking.  But with
+     a bit of luck the next libtool will pass pretty much all
+     <code>CFLAGS</code> through to the compiler when linking, making
+     <code>GMP_LDFLAGS</code> unnecessary.
+<li> mpn/Makeasm.am uses <code>-c</code> and <code>-o</code> together in the
+     .S and .asm rules, but apparently that isn't completely portable (there's
+     an autoconf <code>AC_PROG_CC_C_O</code> test for it).  So far we've not
+     had problems, but perhaps the rules could be rewritten to use "foo.s" as
+     the temporary, or to do a suitable "mv" of the result.  The only danger
+     from using foo.s would be if a compile failed and the temporary foo.s
+     then looked like the primary source.  Hopefully if the
+     <code>SUFFIXES</code> are ordered to have .S and .asm ahead of .s that
+     wouldn't happen.  Might need to check.
+</ul>
+
+
+<h4>Random Numbers</h4>
+<ul>
+<li> <code>_gmp_rand</code> is not particularly fast on the linear
+     congruential algorithm and could stand various improvements.
+     <ul>
+     <li> Make a second seed area within <code>gmp_randstate_t</code> (or
+          <code>_mp_algdata</code> rather) to save some copying.
+     <li> Make a special case for a single limb <code>2exp</code> modulus, to
+          avoid <code>mpn_mul</code> calls.  Perhaps the same for two limbs.
+     <li> Inline the <code>lc</code> code, to avoid a function call and
+          <code>TMP_ALLOC</code> for every chunk.
+     <li> Perhaps the <code>2exp</code> and general LC cases should be split,
+          for clarity (if the general case is retained).
+     </ul>
+<li> <code>gmp_randstate_t</code> used for parameters perhaps should become
+     <code>gmp_randstate_ptr</code> the same as other types.
+<li> Some of the empirical randomness tests could be included in a "make
+     check".  They ought to work everywhere, for a given seed at least.
+</ul>
+
+
+<h4>C++</h4>
+<ul>
+<li> <code>mpz_class(string)</code>, etc: Use the C++ global locale to
+     identify whitespace.
+     <br>
+     <code>mpf_class(string)</code>: Use the C++ global locale decimal point,
+     rather than the C one.
+     <br>
+     Consider making these variant <code>mpz_set_str</code> etc forms
+     available for <code>mpz_t</code> too, not just <code>mpz_class</code>
+     etc.
+<li> <code>mpq_class operator+=</code>: Don't emit an unnecessary
+     <code>mpq_set(q,q)</code> before <code>mpz_addmul</code> etc.
+<li> Put various bits of gmpxx.h into libgmpxx, to avoid excessive inlining.
+     Candidates for this would be,
+     <ul>
+     <li> <code>mpz_class(const char *)</code>, etc: since they're normally
+          not fast anyway, and we can hide the exception <code>throw</code>.
+     <li> <code>mpz_class(string)</code>, etc: to hide the <code>cstr</code>
+          needed to get to the C conversion function.
+     <li> <code>mpz_class string, char*</code> etc constructors: likewise to
+          hide the throws and conversions.
+     <li> <code>mpz_class::get_str</code>, etc: to hide the <code>char*</code>
+          to <code>string</code> conversion and free.  Perhaps
+          <code>mpz_get_str</code> can write directly into a
+          <code>string</code>, to avoid copying.
+          <br>
+          Consider making such <code>string</code> returning variants
+          available for use with plain <code>mpz_t</code> etc too.
+     </ul>
+</ul>
+
+<h4>Miscellaneous</h4>
+<ul>
+<li> <code>mpz_gcdext</code> and <code>mpn_gcdext</code> ought to document
+     what range of values the generated cofactors can take, and preferably
+     ensure the definition uniquely specifies the cofactors for given inputs.
+     A basic extended Euclidean algorithm or multi-step variant leads to
+     |x|&lt;|b| and |y|&lt;|a| or something like that, but there's probably
+     two solutions under just those restrictions.
+<li> demos/factorize.c: use <code>mpz_divisible_ui_p</code> rather than
+     <code>mpz_tdiv_qr_ui</code>.  (Of course dividing multiple primes at a
+     time would be better still.)
+<li> The various test programs use quite a bit of the main
+     <code>libgmp</code>.  This establishes good cross-checks, but it might be
+     better to use simple reference routines where possible.  Where it's not
+     possible some attention could be paid to the order of the tests, so a
+     <code>libgmp</code> routine is only used for tests once it seems to be
+     good.
+<li> <code>MUL_FFT_THRESHOLD</code> etc: the FFT thresholds should allow a
+     return to a previous k at certain sizes.  This arises basically due to
+     the step effect caused by size multiples effectively used for each k.
+     Looking at a graph makes it fairly clear.
+<li> <code>__gmp_doprnt_mpf</code> does a rather unattractive round-to-nearest
+     on the string returned by <code>mpf_get_str</code>.  Perhaps some variant
+     of <code>mpf_get_str</code> could be made which would better suit.
+</ul>
+
+
+<h4>Aids to Development</h4>
+<ul>
+<li> Add <code>ASSERT</code>s at the start of each user-visible mpz/mpq/mpf
+     function to check the validity of each <code>mp?_t</code> parameter, in
+     particular to check they've been <code>mp?_init</code>ed.  This might
+     catch elementary mistakes in user programs.  Care would need to be taken
+     over <code>MPZ_TMP_INIT</code>ed variables used internally.  If nothing
+     else then consistency checks like size&lt;=alloc, ptr not
+     <code>NULL</code> and ptr+size not wrapping around the address space,
+     would be possible.  A more sophisticated scheme could track
+     <code>_mp_d</code> pointers and ensure only a valid one is used.  Such a
+     scheme probably wouldn't be reentrant, not without some help from the
+     system.
+<li> tune/time.c could try to determine at runtime whether
+     <code>getrusage</code> and <code>gettimeofday</code> are reliable.
+     Currently we pretend in configure that the dodgy m68k netbsd 1.4.1
+     <code>getrusage</code> doesn't exist.  If a test might take a long time
+     to run then perhaps cache the result in a file somewhere.
+<li> tune/time.c could choose the default precision based on the
+     <code>speed_unittime</code> determined, independent of the method in use.
+<li> Cray vector systems: CPU frequency could be determined from
+     <code>sysconf(_SC_CLK_TCK)</code>, since it seems to be clock cycle
+     based.  Is this true for all Cray systems?  Would like some documentation
+     or something to confirm.
+</ul>
+
+
+<h4>Documentation</h4>
+<ul>
+<li> <code>mpz_inp_str</code> (etc) doesn't say when it stops reading digits.
+<li> <code>mpn_get_str</code> isn't terribly clear about how many digits it
+     produces.  It'd probably be possible to say at most one leading zero,
+     which is what both it and <code>mpz_get_str</code> currently do.  But
+     want to be careful not to bind ourselves to something that might not suit
+     another implementation.
+<li> <code>va_arg</code> doesn't do the right thing with <code>mpz_t</code>
+     etc directly, but instead needs a pointer type like <code>MP_INT*</code>.
+     It'd be good to show how to do this, but we'd either need to document
+     <code>mpz_ptr</code> and friends, or perhaps fallback on something
+     slightly nasty with <code>void*</code>.
+</ul>
+
+
+<h4>Bright Ideas</h4>
+
+<p> The following may or may not be feasible, and aren't likely to get done in the
+near future, but are at least worth thinking about.
+
+<ul>
+<li> Reorganize longlong.h so that we can inline the operations even for the
+     system compiler.  When there is no such compiler feature, make calls to
+     stub functions.  Write such stub functions for as many machines as
+     possible.
+<li> longlong.h could declare when it's using, or would like to use,
+     <code>mpn_umul_ppmm</code>, and the corresponding umul.asm file could be
+     included in libgmp only in that case, the same as is effectively done for
+     <code>__clz_tab</code>.  Likewise udiv.asm and perhaps cntlz.asm.  This
+     would only be a very small space saving, so perhaps not worth the
+     complexity.
+<li> longlong.h could be built at configure time by concatenating or
+     #including fragments from each directory in the mpn path.  This would
+     select CPU specific macros the same way as CPU specific assembler code.
+     Code used would no longer depend on cpp predefines, and the current
+     nested conditionals could be flattened out.
+<li> <code>mpz_get_si</code> returns 0x80000000 for -0x100000000, whereas it's
+     sort of supposed to return the low 31 (or 63) bits.  But this is
+     undocumented, and perhaps not too important.
+<li> <code>mpz_init_set*</code> and <code>mpz_realloc</code> could allocate
+     say an extra 16 limbs over what's needed, so as to reduce the chance of
+     having to do a reallocate if the <code>mpz_t</code> grows a bit more.
+     This could only be an option, since it'd badly bloat memory usage in
+     applications using many small values.
+<li> <code>mpq</code> functions could perhaps check for numerator or
+     denominator equal to 1, on the assumption that integers or
+     denominator-only values might be expected to occur reasonably often.
+<li> <code>count_trailing_zeros</code> is used on more or less uniformly
+     distributed numbers in a couple of places.  For some CPUs
+     <code>count_trailing_zeros</code> is slow and it's probably worth handling
+     the frequently occurring 0 to 2 trailing zeros cases specially.
+<li> <code>mpf_t</code> might like to let the exponent be undefined when
+     size==0, instead of requiring it 0 as now.  It should be possible to do
+     size==0 tests before paying attention to the exponent.  The advantage is
+     not needing to set exp in the various places a zero result can arise,
+     which avoids some tedium but is otherwise perhaps not too important.
+     Currently <code>mpz_set_f</code> and <code>mpf_cmp_ui</code> depend on
+     exp==0, maybe elsewhere too.
+<li> <code>__gmp_allocate_func</code>: Could use GCC <code>__attribute__
+     ((malloc))</code> on this, though don't know if it'd do much.  GCC 3.0
+     allows that attribute on functions, but not function pointers (see info
+     node "Attribute Syntax"), so would need a new autoconf test.  This can
+     wait until there's a GCC that supports it.
+<li> <code>mpz_add_ui</code> contains two <code>__GMPN_COPY</code>s, one from
+     <code>mpn_add_1</code> and one from <code>mpn_sub_1</code>.  If those two
+     routines were opened up a bit maybe that code could be shared.  When a
+     copy needs to be done there's no carry to append for the add, and if the
+     copy is non-empty no high zero for the sub.
+</ul>
+
+
+<h4>Old and Obsolete Stuff</h4>
+
+<p> The following tasks apply to chips or systems that are old and/or obsolete.
+It's unlikely anything will be done about them unless anyone is actively using
+them.
+
+<ul>
+<li> Sparc32: The integer based udiv_nfp.asm used to be selected by
+     <code>configure --nfp</code> but that option is gone now that autoconf is
+     used.  The file could go somewhere suitable in the mpn search if any
+     chips might benefit from it, though it's possible we don't currently
+     differentiate enough exact cpu types to do this properly.
+<li> VAX D and G format <code>double</code> floats are straightforward and
+     could perhaps be handled directly in <code>__gmp_extract_double</code>
+     and maybe in <code>mpn_get_d</code>, rather than falling back on the
+     generic code.  (Both formats are detected by <code>configure</code>.)
+</ul>
+
+
+<hr>
+
+</body>
+</html>
+
+<!--
+Local variables:
+eval: (add-hook 'write-file-hooks 'time-stamp)
+time-stamp-start: "This file current as of "
+time-stamp-format: "%:d %3b %:y"
+time-stamp-end: "\\."
+time-stamp-line-limit: 50
+End:
+-->
diff --git a/third_party/gmp/doc/texinfo.tex b/third_party/gmp/doc/texinfo.tex
new file mode 100644
index 0000000..85f184c
--- /dev/null
+++ b/third_party/gmp/doc/texinfo.tex
@@ -0,0 +1,10079 @@
+% texinfo.tex -- TeX macros to handle Texinfo files.
+% 
+% Load plain if necessary, i.e., if running under initex.
+\expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi
+%
+\def\texinfoversion{2013-02-01.11}
+%
+% Copyright 1985, 1986, 1988, 1990, 1991, 1992, 1993, 1994, 1995,
+% 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+% 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
+%
+% This texinfo.tex file is free software: you can redistribute it and/or
+% modify it under the terms of the GNU General Public License as
+% published by the Free Software Foundation, either version 3 of the
+% License, or (at your option) any later version.
+%
+% This texinfo.tex file is distributed in the hope that it will be
+% useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+% of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+% General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program.  If not, see <http://www.gnu.org/licenses/>.
+%
+% As a special exception, when this file is read by TeX when processing
+% a Texinfo source document, you may use the result without
+% restriction. This Exception is an additional permission under section 7
+% of the GNU General Public License, version 3 ("GPLv3").
+%
+% Please try the latest version of texinfo.tex before submitting bug
+% reports; you can get the latest version from:
+%   http://ftp.gnu.org/gnu/texinfo/ (the Texinfo release area), or
+%   http://ftpmirror.gnu.org/texinfo/ (same, via a mirror), or
+%   http://www.gnu.org/software/texinfo/ (the Texinfo home page)
+% The texinfo.tex in any given distribution could well be out
+% of date, so if that's what you're using, please check.
+%
+% Send bug reports to bug-texinfo@gnu.org.  Please include including a
+% complete document in each bug report with which we can reproduce the
+% problem.  Patches are, of course, greatly appreciated.
+%
+% To process a Texinfo manual with TeX, it's most reliable to use the
+% texi2dvi shell script that comes with the distribution.  For a simple
+% manual foo.texi, however, you can get away with this:
+%   tex foo.texi
+%   texindex foo.??
+%   tex foo.texi
+%   tex foo.texi
+%   dvips foo.dvi -o  # or whatever; this makes foo.ps.
+% The extra TeX runs get the cross-reference information correct.
+% Sometimes one run after texindex suffices, and sometimes you need more
+% than two; texi2dvi does it as many times as necessary.
+%
+% It is possible to adapt texinfo.tex for other languages, to some
+% extent.  You can get the existing language-specific files from the
+% full Texinfo distribution.
+%
+% The GNU Texinfo home page is http://www.gnu.org/software/texinfo.
+
+
+\message{Loading texinfo [version \texinfoversion]:}
+
+% If in a .fmt file, print the version number
+% and turn on active characters that we couldn't do earlier because
+% they might have appeared in the input file name.
+\everyjob{\message{[Texinfo version \texinfoversion]}%
+  \catcode`+=\active \catcode`\_=\active}
+
+\chardef\other=12
+
+% We never want plain's \outer definition of \+ in Texinfo.
+% For @tex, we can use \tabalign.
+\let\+ = \relax
+
+% Save some plain tex macros whose names we will redefine.
+\let\ptexb=\b
+\let\ptexbullet=\bullet
+\let\ptexc=\c
+\let\ptexcomma=\,
+\let\ptexdot=\.
+\let\ptexdots=\dots
+\let\ptexend=\end
+\let\ptexequiv=\equiv
+\let\ptexexclam=\!
+\let\ptexfootnote=\footnote
+\let\ptexgtr=>
+\let\ptexhat=^
+\let\ptexi=\i
+\let\ptexindent=\indent
+\let\ptexinsert=\insert
+\let\ptexlbrace=\{
+\let\ptexless=<
+\let\ptexnewwrite\newwrite
+\let\ptexnoindent=\noindent
+\let\ptexplus=+
+\let\ptexraggedright=\raggedright
+\let\ptexrbrace=\}
+\let\ptexslash=\/
+\let\ptexstar=\*
+\let\ptext=\t
+\let\ptextop=\top
+{\catcode`\'=\active \global\let\ptexquoteright'}% active in plain's math mode
+
+% If this character appears in an error message or help string, it
+% starts a new line in the output.
+\newlinechar = `^^J
+
+% Use TeX 3.0's \inputlineno to get the line number, for better error
+% messages, but if we're using an old version of TeX, don't do anything.
+%
+\ifx\inputlineno\thisisundefined
+  \let\linenumber = \empty % Pre-3.0.
+\else
+  \def\linenumber{l.\the\inputlineno:\space}
+\fi
+
+% Set up fixed words for English if not already set.
+\ifx\putwordAppendix\undefined  \gdef\putwordAppendix{Appendix}\fi
+\ifx\putwordChapter\undefined   \gdef\putwordChapter{Chapter}\fi
+\ifx\putworderror\undefined     \gdef\putworderror{error}\fi
+\ifx\putwordfile\undefined      \gdef\putwordfile{file}\fi
+\ifx\putwordin\undefined        \gdef\putwordin{in}\fi
+\ifx\putwordIndexIsEmpty\undefined       \gdef\putwordIndexIsEmpty{(Index is empty)}\fi
+\ifx\putwordIndexNonexistent\undefined   \gdef\putwordIndexNonexistent{(Index is nonexistent)}\fi
+\ifx\putwordInfo\undefined      \gdef\putwordInfo{Info}\fi
+\ifx\putwordInstanceVariableof\undefined \gdef\putwordInstanceVariableof{Instance Variable of}\fi
+\ifx\putwordMethodon\undefined  \gdef\putwordMethodon{Method on}\fi
+\ifx\putwordNoTitle\undefined   \gdef\putwordNoTitle{No Title}\fi
+\ifx\putwordof\undefined        \gdef\putwordof{of}\fi
+\ifx\putwordon\undefined        \gdef\putwordon{on}\fi
+\ifx\putwordpage\undefined      \gdef\putwordpage{page}\fi
+\ifx\putwordsection\undefined   \gdef\putwordsection{section}\fi
+\ifx\putwordSection\undefined   \gdef\putwordSection{Section}\fi
+\ifx\putwordsee\undefined       \gdef\putwordsee{see}\fi
+\ifx\putwordSee\undefined       \gdef\putwordSee{See}\fi
+\ifx\putwordShortTOC\undefined  \gdef\putwordShortTOC{Short Contents}\fi
+\ifx\putwordTOC\undefined       \gdef\putwordTOC{Table of Contents}\fi
+%
+\ifx\putwordMJan\undefined \gdef\putwordMJan{January}\fi
+\ifx\putwordMFeb\undefined \gdef\putwordMFeb{February}\fi
+\ifx\putwordMMar\undefined \gdef\putwordMMar{March}\fi
+\ifx\putwordMApr\undefined \gdef\putwordMApr{April}\fi
+\ifx\putwordMMay\undefined \gdef\putwordMMay{May}\fi
+\ifx\putwordMJun\undefined \gdef\putwordMJun{June}\fi
+\ifx\putwordMJul\undefined \gdef\putwordMJul{July}\fi
+\ifx\putwordMAug\undefined \gdef\putwordMAug{August}\fi
+\ifx\putwordMSep\undefined \gdef\putwordMSep{September}\fi
+\ifx\putwordMOct\undefined \gdef\putwordMOct{October}\fi
+\ifx\putwordMNov\undefined \gdef\putwordMNov{November}\fi
+\ifx\putwordMDec\undefined \gdef\putwordMDec{December}\fi
+%
+\ifx\putwordDefmac\undefined    \gdef\putwordDefmac{Macro}\fi
+\ifx\putwordDefspec\undefined   \gdef\putwordDefspec{Special Form}\fi
+\ifx\putwordDefvar\undefined    \gdef\putwordDefvar{Variable}\fi
+\ifx\putwordDefopt\undefined    \gdef\putwordDefopt{User Option}\fi
+\ifx\putwordDeffunc\undefined   \gdef\putwordDeffunc{Function}\fi
+
+% Since the category of space is not known, we have to be careful.
+\chardef\spacecat = 10
+\def\spaceisspace{\catcode`\ =\spacecat}
+
+% sometimes characters are active, so we need control sequences.
+\chardef\ampChar   = `\&
+\chardef\colonChar = `\:
+\chardef\commaChar = `\,
+\chardef\dashChar  = `\-
+\chardef\dotChar   = `\.
+\chardef\exclamChar= `\!
+\chardef\hashChar  = `\#
+\chardef\lquoteChar= `\`
+\chardef\questChar = `\?
+\chardef\rquoteChar= `\'
+\chardef\semiChar  = `\;
+\chardef\slashChar = `\/
+\chardef\underChar = `\_
+
+% Ignore a token.
+%
+\def\gobble#1{}
+
+% The following is used inside several \edef's.
+\def\makecsname#1{\expandafter\noexpand\csname#1\endcsname}
+
+% Hyphenation fixes.
+\hyphenation{
+  Flor-i-da Ghost-script Ghost-view Mac-OS Post-Script
+  ap-pen-dix bit-map bit-maps
+  data-base data-bases eshell fall-ing half-way long-est man-u-script
+  man-u-scripts mini-buf-fer mini-buf-fers over-view par-a-digm
+  par-a-digms rath-er rec-tan-gu-lar ro-bot-ics se-vere-ly set-up spa-ces
+  spell-ing spell-ings
+  stand-alone strong-est time-stamp time-stamps which-ever white-space
+  wide-spread wrap-around
+}
+
+% Margin to add to right of even pages, to left of odd pages.
+\newdimen\bindingoffset
+\newdimen\normaloffset
+\newdimen\pagewidth \newdimen\pageheight
+
+% For a final copy, take out the rectangles
+% that mark overfull boxes (in case you have decided
+% that the text looks ok even though it passes the margin).
+%
+\def\finalout{\overfullrule=0pt }
+
+% Sometimes it is convenient to have everything in the transcript file
+% and nothing on the terminal.  We don't just call \tracingall here,
+% since that produces some useless output on the terminal.  We also make
+% some effort to order the tracing commands to reduce output in the log
+% file; cf. trace.sty in LaTeX.
+%
+\def\gloggingall{\begingroup \globaldefs = 1 \loggingall \endgroup}%
+\def\loggingall{%
+  \tracingstats2
+  \tracingpages1
+  \tracinglostchars2  % 2 gives us more in etex
+  \tracingparagraphs1
+  \tracingoutput1
+  \tracingmacros2
+  \tracingrestores1
+  \showboxbreadth\maxdimen \showboxdepth\maxdimen
+  \ifx\eTeXversion\thisisundefined\else % etex gives us more logging
+    \tracingscantokens1
+    \tracingifs1
+    \tracinggroups1
+    \tracingnesting2
+    \tracingassigns1
+  \fi
+  \tracingcommands3  % 3 gives us more in etex
+  \errorcontextlines16
+}%
+
+% @errormsg{MSG}.  Do the index-like expansions on MSG, but if things
+% aren't perfect, it's not the end of the world, being an error message,
+% after all.
+% 
+\def\errormsg{\begingroup \indexnofonts \doerrormsg}
+\def\doerrormsg#1{\errmessage{#1}}
+
+% add check for \lastpenalty to plain's definitions.  If the last thing
+% we did was a \nobreak, we don't want to insert more space.
+%
+\def\smallbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\smallskipamount
+  \removelastskip\penalty-50\smallskip\fi\fi}
+\def\medbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\medskipamount
+  \removelastskip\penalty-100\medskip\fi\fi}
+\def\bigbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\bigskipamount
+  \removelastskip\penalty-200\bigskip\fi\fi}
+
+% Do @cropmarks to get crop marks.
+%
+\newif\ifcropmarks
+\let\cropmarks = \cropmarkstrue
+%
+% Dimensions to add cropmarks at corners.
+% Added by P. A. MacKay, 12 Nov. 1986
+%
+\newdimen\outerhsize \newdimen\outervsize % set by the paper size routines
+\newdimen\cornerlong  \cornerlong=1pc
+\newdimen\cornerthick \cornerthick=.3pt
+\newdimen\topandbottommargin \topandbottommargin=.75in
+
+% Output a mark which sets \thischapter, \thissection and \thiscolor.
+% We dump everything together because we only have one kind of mark.
+% This works because we only use \botmark / \topmark, not \firstmark.
+%
+% A mark contains a subexpression of the \ifcase ... \fi construct.
+% \get*marks macros below extract the needed part using \ifcase.
+%
+% Another complication is to let the user choose whether \thischapter
+% (\thissection) refers to the chapter (section) in effect at the top
+% of a page, or that at the bottom of a page.  The solution is
+% described on page 260 of The TeXbook.  It involves outputting two
+% marks for the sectioning macros, one before the section break, and
+% one after.  I won't pretend I can describe this better than DEK...
+\def\domark{%
+  \toks0=\expandafter{\lastchapterdefs}%
+  \toks2=\expandafter{\lastsectiondefs}%
+  \toks4=\expandafter{\prevchapterdefs}%
+  \toks6=\expandafter{\prevsectiondefs}%
+  \toks8=\expandafter{\lastcolordefs}%
+  \mark{%
+                   \the\toks0 \the\toks2
+      \noexpand\or \the\toks4 \the\toks6
+    \noexpand\else \the\toks8
+  }%
+}
+% \topmark doesn't work for the very first chapter (after the title
+% page or the contents), so we use \firstmark there -- this gets us
+% the mark with the chapter defs, unless the user sneaks in, e.g.,
+% @setcolor (or @url, or @link, etc.) between @contents and the very
+% first @chapter.
+\def\gettopheadingmarks{%
+  \ifcase0\topmark\fi
+  \ifx\thischapter\empty \ifcase0\firstmark\fi \fi
+}
+\def\getbottomheadingmarks{\ifcase1\botmark\fi}
+\def\getcolormarks{\ifcase2\topmark\fi}
+
+% Avoid "undefined control sequence" errors.
+\def\lastchapterdefs{}
+\def\lastsectiondefs{}
+\def\prevchapterdefs{}
+\def\prevsectiondefs{}
+\def\lastcolordefs{}
+
+% Main output routine.
+\chardef\PAGE = 255
+\output = {\onepageout{\pagecontents\PAGE}}
+
+\newbox\headlinebox
+\newbox\footlinebox
+
+% \onepageout takes a vbox as an argument.  Note that \pagecontents
+% does insertions, but you have to call it yourself.
+\def\onepageout#1{%
+  \ifcropmarks \hoffset=0pt \else \hoffset=\normaloffset \fi
+  %
+  \ifodd\pageno  \advance\hoffset by \bindingoffset
+  \else \advance\hoffset by -\bindingoffset\fi
+  %
+  % Do this outside of the \shipout so @code etc. will be expanded in
+  % the headline as they should be, not taken literally (outputting ''code).
+  \ifodd\pageno \getoddheadingmarks \else \getevenheadingmarks \fi
+  \setbox\headlinebox = \vbox{\let\hsize=\pagewidth \makeheadline}%
+  \ifodd\pageno \getoddfootingmarks \else \getevenfootingmarks \fi
+  \setbox\footlinebox = \vbox{\let\hsize=\pagewidth \makefootline}%
+  %
+  {%
+    % Have to do this stuff outside the \shipout because we want it to
+    % take effect in \write's, yet the group defined by the \vbox ends
+    % before the \shipout runs.
+    %
+    \indexdummies         % don't expand commands in the output.
+    \normalturnoffactive  % \ in index entries must not stay \, e.g., if
+               % the page break happens to be in the middle of an example.
+               % We don't want .vr (or whatever) entries like this:
+               % \entry{{\tt \indexbackslash }acronym}{32}{\code {\acronym}}
+               % "\acronym" won't work when it's read back in;
+               % it needs to be
+               % {\code {{\tt \backslashcurfont }acronym}
+    \shipout\vbox{%
+      % Do this early so pdf references go to the beginning of the page.
+      \ifpdfmakepagedest \pdfdest name{\the\pageno} xyz\fi
+      %
+      \ifcropmarks \vbox to \outervsize\bgroup
+        \hsize = \outerhsize
+        \vskip-\topandbottommargin
+        \vtop to0pt{%
+          \line{\ewtop\hfil\ewtop}%
+          \nointerlineskip
+          \line{%
+            \vbox{\moveleft\cornerthick\nstop}%
+            \hfill
+            \vbox{\moveright\cornerthick\nstop}%
+          }%
+          \vss}%
+        \vskip\topandbottommargin
+        \line\bgroup
+          \hfil % center the page within the outer (page) hsize.
+          \ifodd\pageno\hskip\bindingoffset\fi
+          \vbox\bgroup
+      \fi
+      %
+      \unvbox\headlinebox
+      \pagebody{#1}%
+      \ifdim\ht\footlinebox > 0pt
+        % Only leave this space if the footline is nonempty.
+        % (We lessened \vsize for it in \oddfootingyyy.)
+        % The \baselineskip=24pt in plain's \makefootline has no effect.
+        \vskip 24pt
+        \unvbox\footlinebox
+      \fi
+      %
+      \ifcropmarks
+          \egroup % end of \vbox\bgroup
+        \hfil\egroup % end of (centering) \line\bgroup
+        \vskip\topandbottommargin plus1fill minus1fill
+        \boxmaxdepth = \cornerthick
+        \vbox to0pt{\vss
+          \line{%
+            \vbox{\moveleft\cornerthick\nsbot}%
+            \hfill
+            \vbox{\moveright\cornerthick\nsbot}%
+          }%
+          \nointerlineskip
+          \line{\ewbot\hfil\ewbot}%
+        }%
+      \egroup % \vbox from first cropmarks clause
+      \fi
+    }% end of \shipout\vbox
+  }% end of group with \indexdummies
+  \advancepageno
+  \ifnum\outputpenalty>-20000 \else\dosupereject\fi
+}
+
+\newinsert\margin \dimen\margin=\maxdimen
+
+\def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}}
+{\catcode`\@ =11
+\gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi
+% marginal hacks, juha@viisa.uucp (Juha Takala)
+\ifvoid\margin\else % marginal info is present
+  \rlap{\kern\hsize\vbox to\z@{\kern1pt\box\margin \vss}}\fi
+\dimen@=\dp#1\relax \unvbox#1\relax
+\ifvoid\footins\else\vskip\skip\footins\footnoterule \unvbox\footins\fi
+\ifr@ggedbottom \kern-\dimen@ \vfil \fi}
+}
+
+% Here are the rules for the cropmarks.  Note that they are
+% offset so that the space between them is truly \outerhsize or \outervsize
+% (P. A. MacKay, 12 November, 1986)
+%
+\def\ewtop{\vrule height\cornerthick depth0pt width\cornerlong}
+\def\nstop{\vbox
+  {\hrule height\cornerthick depth\cornerlong width\cornerthick}}
+\def\ewbot{\vrule height0pt depth\cornerthick width\cornerlong}
+\def\nsbot{\vbox
+  {\hrule height\cornerlong depth\cornerthick width\cornerthick}}
+
+% Parse an argument, then pass it to #1.  The argument is the rest of
+% the input line (except we remove a trailing comment).  #1 should be a
+% macro which expects an ordinary undelimited TeX argument.
+%
+\def\parsearg{\parseargusing{}}
+\def\parseargusing#1#2{%
+  \def\argtorun{#2}%
+  \begingroup
+    \obeylines
+    \spaceisspace
+    #1%
+    \parseargline\empty% Insert the \empty token, see \finishparsearg below.
+}
+
+{\obeylines %
+  \gdef\parseargline#1^^M{%
+    \endgroup % End of the group started in \parsearg.
+    \argremovecomment #1\comment\ArgTerm%
+  }%
+}
+
+% First remove any @comment, then any @c comment.
+\def\argremovecomment#1\comment#2\ArgTerm{\argremovec #1\c\ArgTerm}
+\def\argremovec#1\c#2\ArgTerm{\argcheckspaces#1\^^M\ArgTerm}
+
+% Each occurrence of `\^^M' or `<space>\^^M' is replaced by a single space.
+%
+% \argremovec might leave us with trailing space, e.g.,
+%    @end itemize  @c foo
+% This space token undergoes the same procedure and is eventually removed
+% by \finishparsearg.
+%
+\def\argcheckspaces#1\^^M{\argcheckspacesX#1\^^M \^^M}
+\def\argcheckspacesX#1 \^^M{\argcheckspacesY#1\^^M}
+\def\argcheckspacesY#1\^^M#2\^^M#3\ArgTerm{%
+  \def\temp{#3}%
+  \ifx\temp\empty
+    % Do not use \next, perhaps the caller of \parsearg uses it; reuse \temp:
+    \let\temp\finishparsearg
+  \else
+    \let\temp\argcheckspaces
+  \fi
+  % Put the space token in:
+  \temp#1 #3\ArgTerm
+}
+
+% If a _delimited_ argument is enclosed in braces, they get stripped; so
+% to get _exactly_ the rest of the line, we had to prevent such situation.
+% We prepended an \empty token at the very beginning and we expand it now,
+% just before passing the control to \argtorun.
+% (Similarly, we have to think about #3 of \argcheckspacesY above: it is
+% either the null string, or it ends with \^^M---thus there is no danger
+% that a pair of braces would be stripped.
+%
+% But first, we have to remove the trailing space token.
+%
+\def\finishparsearg#1 \ArgTerm{\expandafter\argtorun\expandafter{#1}}
+
+% \parseargdef\foo{...}
+%	is roughly equivalent to
+% \def\foo{\parsearg\Xfoo}
+% \def\Xfoo#1{...}
+%
+% Actually, I use \csname\string\foo\endcsname, ie. \\foo, as it is my
+% favourite TeX trick.  --kasal, 16nov03
+
+\def\parseargdef#1{%
+  \expandafter \doparseargdef \csname\string#1\endcsname #1%
+}
+\def\doparseargdef#1#2{%
+  \def#2{\parsearg#1}%
+  \def#1##1%
+}
+
+% Several utility definitions with active space:
+{
+  \obeyspaces
+  \gdef\obeyedspace{ }
+
+  % Make each space character in the input produce a normal interword
+  % space in the output.  Don't allow a line break at this space, as this
+  % is used only in environments like @example, where each line of input
+  % should produce a line of output anyway.
+  %
+  \gdef\sepspaces{\obeyspaces\let =\tie}
+
+  % If an index command is used in an @example environment, any spaces
+  % therein should become regular spaces in the raw index file, not the
+  % expansion of \tie (\leavevmode \penalty \@M \ ).
+  \gdef\unsepspaces{\let =\space}
+}
+
+
+\def\flushcr{\ifx\par\lisppar \def\next##1{}\else \let\next=\relax \fi \next}
+
+% Define the framework for environments in texinfo.tex.  It's used like this:
+%
+%   \envdef\foo{...}
+%   \def\Efoo{...}
+%
+% It's the responsibility of \envdef to insert \begingroup before the
+% actual body; @end closes the group after calling \Efoo.  \envdef also
+% defines \thisenv, so the current environment is known; @end checks
+% whether the environment name matches.  The \checkenv macro can also be
+% used to check whether the current environment is the one expected.
+%
+% Non-false conditionals (@iftex, @ifset) don't fit into this, so they
+% are not treated as environments; they don't open a group.  (The
+% implementation of @end takes care not to call \endgroup in this
+% special case.)
+
+
+% At run-time, environments start with this:
+\def\startenvironment#1{\begingroup\def\thisenv{#1}}
+% initialize
+\let\thisenv\empty
+
+% ... but they get defined via ``\envdef\foo{...}'':
+\long\def\envdef#1#2{\def#1{\startenvironment#1#2}}
+\def\envparseargdef#1#2{\parseargdef#1{\startenvironment#1#2}}
+
+% Check whether we're in the right environment:
+\def\checkenv#1{%
+  \def\temp{#1}%
+  \ifx\thisenv\temp
+  \else
+    \badenverr
+  \fi
+}
+
+% Environment mismatch, #1 expected:
+\def\badenverr{%
+  \errhelp = \EMsimple
+  \errmessage{This command can appear only \inenvironment\temp,
+    not \inenvironment\thisenv}%
+}
+\def\inenvironment#1{%
+  \ifx#1\empty
+    outside of any environment%
+  \else
+    in environment \expandafter\string#1%
+  \fi
+}
+
+% @end foo executes the definition of \Efoo.
+% But first, it executes a specialized version of \checkenv
+%
+\parseargdef\end{%
+  \if 1\csname iscond.#1\endcsname
+  \else
+    % The general wording of \badenverr may not be ideal.
+    \expandafter\checkenv\csname#1\endcsname
+    \csname E#1\endcsname
+    \endgroup
+  \fi
+}
+
+\newhelp\EMsimple{Press RETURN to continue.}
+
+
+% Be sure we're in horizontal mode when doing a tie, since we make space
+% equivalent to this in @example-like environments. Otherwise, a space
+% at the beginning of a line will start with \penalty -- and
+% since \penalty is valid in vertical mode, we'd end up putting the
+% penalty on the vertical list instead of in the new paragraph.
+{\catcode`@ = 11
+ % Avoid using \@M directly, because that causes trouble
+ % if the definition is written into an index file.
+ \global\let\tiepenalty = \@M
+ \gdef\tie{\leavevmode\penalty\tiepenalty\ }
+}
+
+% @: forces normal size whitespace following.
+\def\:{\spacefactor=1000 }
+
+% @* forces a line break.
+\def\*{\unskip\hfil\break\hbox{}\ignorespaces}
+
+% @/ allows a line break.
+\let\/=\allowbreak
+
+% @. is an end-of-sentence period.
+\def\.{.\spacefactor=\endofsentencespacefactor\space}
+
+% @! is an end-of-sentence bang.
+\def\!{!\spacefactor=\endofsentencespacefactor\space}
+
+% @? is an end-of-sentence query.
+\def\?{?\spacefactor=\endofsentencespacefactor\space}
+
+% @frenchspacing on|off  says whether to put extra space after punctuation.
+%
+\def\onword{on}
+\def\offword{off}
+%
+\parseargdef\frenchspacing{%
+  \def\temp{#1}%
+  \ifx\temp\onword \plainfrenchspacing
+  \else\ifx\temp\offword \plainnonfrenchspacing
+  \else
+    \errhelp = \EMsimple
+    \errmessage{Unknown @frenchspacing option `\temp', must be on|off}%
+  \fi\fi
+}
+
+% @w prevents a word break.  Without the \leavevmode, @w at the
+% beginning of a paragraph, when TeX is still in vertical mode, would
+% produce a whole line of output instead of starting the paragraph.
+\def\w#1{\leavevmode\hbox{#1}}
+
+% @group ... @end group forces ... to be all on one page, by enclosing
+% it in a TeX vbox.  We use \vtop instead of \vbox to construct the box
+% to keep its height that of a normal line.  According to the rules for
+% \topskip (p.114 of the TeXbook), the glue inserted is
+% max (\topskip - \ht (first item), 0).  If that height is large,
+% therefore, no glue is inserted, and the space between the headline and
+% the text is small, which looks bad.
+%
+% Another complication is that the group might be very large.  This can
+% cause the glue on the previous page to be unduly stretched, because it
+% does not have much material.  In this case, it's better to add an
+% explicit \vfill so that the extra space is at the bottom.  The
+% threshold for doing this is if the group is more than \vfilllimit
+% percent of a page (\vfilllimit can be changed inside of @tex).
+%
+\newbox\groupbox
+\def\vfilllimit{0.7}
+%
+\envdef\group{%
+  \ifnum\catcode`\^^M=\active \else
+    \errhelp = \groupinvalidhelp
+    \errmessage{@group invalid in context where filling is enabled}%
+  \fi
+  \startsavinginserts
+  %
+  \setbox\groupbox = \vtop\bgroup
+    % Do @comment since we are called inside an environment such as
+    % @example, where each end-of-line in the input causes an
+    % end-of-line in the output.  We don't want the end-of-line after
+    % the `@group' to put extra space in the output.  Since @group
+    % should appear on a line by itself (according to the Texinfo
+    % manual), we don't worry about eating any user text.
+    \comment
+}
+%
+% The \vtop produces a box with normal height and large depth; thus, TeX puts
+% \baselineskip glue before it, and (when the next line of text is done)
+% \lineskip glue after it.  Thus, space below is not quite equal to space
+% above.  But it's pretty close.
+\def\Egroup{%
+    % To get correct interline space between the last line of the group
+    % and the first line afterwards, we have to propagate \prevdepth.
+    \endgraf % Not \par, as it may have been set to \lisppar.
+    \global\dimen1 = \prevdepth
+  \egroup           % End the \vtop.
+  % \dimen0 is the vertical size of the group's box.
+  \dimen0 = \ht\groupbox  \advance\dimen0 by \dp\groupbox
+  % \dimen2 is how much space is left on the page (more or less).
+  \dimen2 = \pageheight   \advance\dimen2 by -\pagetotal
+  % if the group doesn't fit on the current page, and it's a big big
+  % group, force a page break.
+  \ifdim \dimen0 > \dimen2
+    \ifdim \pagetotal < \vfilllimit\pageheight
+      \page
+    \fi
+  \fi
+  \box\groupbox
+  \prevdepth = \dimen1
+  \checkinserts
+}
+%
+% TeX puts in an \escapechar (i.e., `@') at the beginning of the help
+% message, so this ends up printing `@group can only ...'.
+%
+\newhelp\groupinvalidhelp{%
+group can only be used in environments such as @example,^^J%
+where each line of input produces a line of output.}
+
+% @need space-in-mils
+% forces a page break if there is not space-in-mils remaining.
+
+\newdimen\mil  \mil=0.001in
+
+\parseargdef\need{%
+  % Ensure vertical mode, so we don't make a big box in the middle of a
+  % paragraph.
+  \par
+  %
+  % If the @need value is less than one line space, it's useless.
+  \dimen0 = #1\mil
+  \dimen2 = \ht\strutbox
+  \advance\dimen2 by \dp\strutbox
+  \ifdim\dimen0 > \dimen2
+    %
+    % Do a \strut just to make the height of this box be normal, so the
+    % normal leading is inserted relative to the preceding line.
+    % And a page break here is fine.
+    \vtop to #1\mil{\strut\vfil}%
+    %
+    % TeX does not even consider page breaks if a penalty added to the
+    % main vertical list is 10000 or more.  But in order to see if the
+    % empty box we just added fits on the page, we must make it consider
+    % page breaks.  On the other hand, we don't want to actually break the
+    % page after the empty box.  So we use a penalty of 9999.
+    %
+    % There is an extremely small chance that TeX will actually break the
+    % page at this \penalty, if there are no other feasible breakpoints in
+    % sight.  (If the user is using lots of big @group commands, which
+    % almost-but-not-quite fill up a page, TeX will have a hard time doing
+    % good page breaking, for example.)  However, I could not construct an
+    % example where a page broke at this \penalty; if it happens in a real
+    % document, then we can reconsider our strategy.
+    \penalty9999
+    %
+    % Back up by the size of the box, whether we did a page break or not.
+    \kern -#1\mil
+    %
+    % Do not allow a page break right after this kern.
+    \nobreak
+  \fi
+}
+
+% @br   forces paragraph break (and is undocumented).
+
+\let\br = \par
+
+% @page forces the start of a new page.
+%
+\def\page{\par\vfill\supereject}
+
+% @exdent text....
+% outputs text on separate line in roman font, starting at standard page margin
+
+% This records the amount of indent in the innermost environment.
+% That's how much \exdent should take out.
+\newskip\exdentamount
+
+% This defn is used inside fill environments such as @defun.
+\parseargdef\exdent{\hfil\break\hbox{\kern -\exdentamount{\rm#1}}\hfil\break}
+
+% This defn is used inside nofill environments such as @example.
+\parseargdef\nofillexdent{{\advance \leftskip by -\exdentamount
+  \leftline{\hskip\leftskip{\rm#1}}}}
+
+% @inmargin{WHICH}{TEXT} puts TEXT in the WHICH margin next to the current
+% paragraph.  For more general purposes, use the \margin insertion
+% class.  WHICH is `l' or `r'.  Not documented, written for gawk manual.
+%
+\newskip\inmarginspacing \inmarginspacing=1cm
+\def\strutdepth{\dp\strutbox}
+%
+\def\doinmargin#1#2{\strut\vadjust{%
+  \nobreak
+  \kern-\strutdepth
+  \vtop to \strutdepth{%
+    \baselineskip=\strutdepth
+    \vss
+    % if you have multiple lines of stuff to put here, you'll need to
+    % make the vbox yourself of the appropriate size.
+    \ifx#1l%
+      \llap{\ignorespaces #2\hskip\inmarginspacing}%
+    \else
+      \rlap{\hskip\hsize \hskip\inmarginspacing \ignorespaces #2}%
+    \fi
+    \null
+  }%
+}}
+\def\inleftmargin{\doinmargin l}
+\def\inrightmargin{\doinmargin r}
+%
+% @inmargin{TEXT [, RIGHT-TEXT]}
+% (if RIGHT-TEXT is given, use TEXT for left page, RIGHT-TEXT for right;
+% else use TEXT for both).
+%
+\def\inmargin#1{\parseinmargin #1,,\finish}
+\def\parseinmargin#1,#2,#3\finish{% not perfect, but better than nothing.
+  \setbox0 = \hbox{\ignorespaces #2}%
+  \ifdim\wd0 > 0pt
+    \def\lefttext{#1}%  have both texts
+    \def\righttext{#2}%
+  \else
+    \def\lefttext{#1}%  have only one text
+    \def\righttext{#1}%
+  \fi
+  %
+  \ifodd\pageno
+    \def\temp{\inrightmargin\righttext}% odd page -> outside is right margin
+  \else
+    \def\temp{\inleftmargin\lefttext}%
+  \fi
+  \temp
+}
+
+% @| inserts a changebar to the left of the current line.  It should
+% surround any changed text.  This approach does *not* work if the
+% change spans more than two lines of output.  To handle that, we would
+% have adopt a much more difficult approach (putting marks into the main
+% vertical list for the beginning and end of each change).  This command
+% is not documented, not supported, and doesn't work.
+%
+\def\|{%
+  % \vadjust can only be used in horizontal mode.
+  \leavevmode
+  %
+  % Append this vertical mode material after the current line in the output.
+  \vadjust{%
+    % We want to insert a rule with the height and depth of the current
+    % leading; that is exactly what \strutbox is supposed to record.
+    \vskip-\baselineskip
+    %
+    % \vadjust-items are inserted at the left edge of the type.  So
+    % the \llap here moves out into the left-hand margin.
+    \llap{%
+      %
+      % For a thicker or thinner bar, change the `1pt'.
+      \vrule height\baselineskip width1pt
+      %
+      % This is the space between the bar and the text.
+      \hskip 12pt
+    }%
+  }%
+}
+
+% @include FILE -- \input text of FILE.
+%
+\def\include{\parseargusing\filenamecatcodes\includezzz}
+\def\includezzz#1{%
+  \pushthisfilestack
+  \def\thisfile{#1}%
+  {%
+    \makevalueexpandable  % we want to expand any @value in FILE.
+    \turnoffactive        % and allow special characters in the expansion
+    \indexnofonts         % Allow `@@' and other weird things in file names.
+    \wlog{texinfo.tex: doing @include of #1^^J}%
+    \edef\temp{\noexpand\input #1 }%
+    %
+    % This trickery is to read FILE outside of a group, in case it makes
+    % definitions, etc.
+    \expandafter
+  }\temp
+  \popthisfilestack
+}
+\def\filenamecatcodes{%
+  \catcode`\\=\other
+  \catcode`~=\other
+  \catcode`^=\other
+  \catcode`_=\other
+  \catcode`|=\other
+  \catcode`<=\other
+  \catcode`>=\other
+  \catcode`+=\other
+  \catcode`-=\other
+  \catcode`\`=\other
+  \catcode`\'=\other
+}
+
+\def\pushthisfilestack{%
+  \expandafter\pushthisfilestackX\popthisfilestack\StackTerm
+}
+\def\pushthisfilestackX{%
+  \expandafter\pushthisfilestackY\thisfile\StackTerm
+}
+\def\pushthisfilestackY #1\StackTerm #2\StackTerm {%
+  \gdef\popthisfilestack{\gdef\thisfile{#1}\gdef\popthisfilestack{#2}}%
+}
+
+\def\popthisfilestack{\errthisfilestackempty}
+\def\errthisfilestackempty{\errmessage{Internal error:
+  the stack of filenames is empty.}}
+%
+\def\thisfile{}
+
+% @center line
+% outputs that line, centered.
+%
+\parseargdef\center{%
+  \ifhmode
+    \let\centersub\centerH
+  \else
+    \let\centersub\centerV
+  \fi
+  \centersub{\hfil \ignorespaces#1\unskip \hfil}%
+  \let\centersub\relax % don't let the definition persist, just in case
+}
+\def\centerH#1{{%
+  \hfil\break
+  \advance\hsize by -\leftskip
+  \advance\hsize by -\rightskip
+  \line{#1}%
+  \break
+}}
+%
+\newcount\centerpenalty
+\def\centerV#1{%
+  % The idea here is the same as in \startdefun, \cartouche, etc.: if
+  % @center is the first thing after a section heading, we need to wipe
+  % out the negative parskip inserted by \sectionheading, but still
+  % prevent a page break here.
+  \centerpenalty = \lastpenalty
+  \ifnum\centerpenalty>10000 \vskip\parskip \fi
+  \ifnum\centerpenalty>9999 \penalty\centerpenalty \fi
+  \line{\kern\leftskip #1\kern\rightskip}%
+}
+
+% @sp n   outputs n lines of vertical space
+%
+\parseargdef\sp{\vskip #1\baselineskip}
+
+% @comment ...line which is ignored...
+% @c is the same as @comment
+% @ignore ... @end ignore  is another way to write a comment
+%
+\def\comment{\begingroup \catcode`\^^M=\other%
+\catcode`\@=\other \catcode`\{=\other \catcode`\}=\other%
+\commentxxx}
+{\catcode`\^^M=\other \gdef\commentxxx#1^^M{\endgroup}}
+%
+\let\c=\comment
+
+% @paragraphindent NCHARS
+% We'll use ems for NCHARS, close enough.
+% NCHARS can also be the word `asis' or `none'.
+% We cannot feasibly implement @paragraphindent asis, though.
+%
+\def\asisword{asis} % no translation, these are keywords
+\def\noneword{none}
+%
+\parseargdef\paragraphindent{%
+  \def\temp{#1}%
+  \ifx\temp\asisword
+  \else
+    \ifx\temp\noneword
+      \defaultparindent = 0pt
+    \else
+      \defaultparindent = #1em
+    \fi
+  \fi
+  \parindent = \defaultparindent
+}
+
+% @exampleindent NCHARS
+% We'll use ems for NCHARS like @paragraphindent.
+% It seems @exampleindent asis isn't necessary, but
+% I preserve it to make it similar to @paragraphindent.
+\parseargdef\exampleindent{%
+  \def\temp{#1}%
+  \ifx\temp\asisword
+  \else
+    \ifx\temp\noneword
+      \lispnarrowing = 0pt
+    \else
+      \lispnarrowing = #1em
+    \fi
+  \fi
+}
+
+% @firstparagraphindent WORD
+% If WORD is `none', then suppress indentation of the first paragraph
+% after a section heading.  If WORD is `insert', then do indent at such
+% paragraphs.
+%
+% The paragraph indentation is suppressed or not by calling
+% \suppressfirstparagraphindent, which the sectioning commands do.
+% We switch the definition of this back and forth according to WORD.
+% By default, we suppress indentation.
+%
+\def\suppressfirstparagraphindent{\dosuppressfirstparagraphindent}
+\def\insertword{insert}
+%
+\parseargdef\firstparagraphindent{%
+  \def\temp{#1}%
+  \ifx\temp\noneword
+    \let\suppressfirstparagraphindent = \dosuppressfirstparagraphindent
+  \else\ifx\temp\insertword
+    \let\suppressfirstparagraphindent = \relax
+  \else
+    \errhelp = \EMsimple
+    \errmessage{Unknown @firstparagraphindent option `\temp'}%
+  \fi\fi
+}
+
+% Here is how we actually suppress indentation.  Redefine \everypar to
+% \kern backwards by \parindent, and then reset itself to empty.
+%
+% We also make \indent itself not actually do anything until the next
+% paragraph.
+%
+\gdef\dosuppressfirstparagraphindent{%
+  \gdef\indent{%
+    \restorefirstparagraphindent
+    \indent
+  }%
+  \gdef\noindent{%
+    \restorefirstparagraphindent
+    \noindent
+  }%
+  \global\everypar = {%
+    \kern -\parindent
+    \restorefirstparagraphindent
+  }%
+}
+
+\gdef\restorefirstparagraphindent{%
+  \global \let \indent = \ptexindent
+  \global \let \noindent = \ptexnoindent
+  \global \everypar = {}%
+}
+
+
+% @refill is a no-op.
+\let\refill=\relax
+
+% If working on a large document in chapters, it is convenient to
+% be able to disable indexing, cross-referencing, and contents, for test runs.
+% This is done with @novalidate (before @setfilename).
+%
+\newif\iflinks \linkstrue % by default we want the aux files.
+\let\novalidate = \linksfalse
+
+% @setfilename is done at the beginning of every texinfo file.
+% So open here the files we need to have open while reading the input.
+% This makes it possible to make a .fmt file for texinfo.
+\def\setfilename{%
+   \fixbackslash  % Turn off hack to swallow `\input texinfo'.
+   \iflinks
+     \tryauxfile
+     % Open the new aux file.  TeX will close it automatically at exit.
+     \immediate\openout\auxfile=\jobname.aux
+   \fi % \openindices needs to do some work in any case.
+   \openindices
+   \let\setfilename=\comment % Ignore extra @setfilename cmds.
+   %
+   % If texinfo.cnf is present on the system, read it.
+   % Useful for site-wide @afourpaper, etc.
+   \openin 1 texinfo.cnf
+   \ifeof 1 \else \input texinfo.cnf \fi
+   \closein 1
+   %
+   \comment % Ignore the actual filename.
+}
+
+% Called from \setfilename.
+%
+\def\openindices{%
+  \newindex{cp}%
+  \newcodeindex{fn}%
+  \newcodeindex{vr}%
+  \newcodeindex{tp}%
+  \newcodeindex{ky}%
+  \newcodeindex{pg}%
+}
+
+% @bye.
+\outer\def\bye{\pagealignmacro\tracingstats=1\ptexend}
+
+
+\message{pdf,}
+% adobe `portable' document format
+\newcount\tempnum
+\newcount\lnkcount
+\newtoks\filename
+\newcount\filenamelength
+\newcount\pgn
+\newtoks\toksA
+\newtoks\toksB
+\newtoks\toksC
+\newtoks\toksD
+\newbox\boxA
+\newcount\countA
+\newif\ifpdf
+\newif\ifpdfmakepagedest
+
+% when pdftex is run in dvi mode, \pdfoutput is defined (so \pdfoutput=1
+% can be set).  So we test for \relax and 0 as well as being undefined.
+\ifx\pdfoutput\thisisundefined
+\else
+  \ifx\pdfoutput\relax
+  \else
+    \ifcase\pdfoutput
+    \else
+      \pdftrue
+    \fi
+  \fi
+\fi
+
+% PDF uses PostScript string constants for the names of xref targets,
+% for display in the outlines, and in other places.  Thus, we have to
+% double any backslashes.  Otherwise, a name like "\node" will be
+% interpreted as a newline (\n), followed by o, d, e.  Not good.
+% 
+% See http://www.ntg.nl/pipermail/ntg-pdftex/2004-July/000654.html and
+% related messages.  The final outcome is that it is up to the TeX user
+% to double the backslashes and otherwise make the string valid, so
+% that's what we do.  pdftex 1.30.0 (ca.2005) introduced a primitive to
+% do this reliably, so we use it.
+
+% #1 is a control sequence in which to do the replacements,
+% which we \xdef.
+\def\txiescapepdf#1{%
+  \ifx\pdfescapestring\thisisundefined
+    % No primitive available; should we give a warning or log?
+    % Many times it won't matter.
+  \else
+    % The expandable \pdfescapestring primitive escapes parentheses,
+    % backslashes, and other special chars.
+    \xdef#1{\pdfescapestring{#1}}%
+  \fi
+}
+
+\newhelp\nopdfimagehelp{Texinfo supports .png, .jpg, .jpeg, and .pdf images
+with PDF output, and none of those formats could be found.  (.eps cannot
+be supported due to the design of the PDF format; use regular TeX (DVI
+output) for that.)}
+
+\ifpdf
+  %
+  % Color manipulation macros based on pdfcolor.tex,
+  % except using rgb instead of cmyk; the latter is said to render as a
+  % very dark gray on-screen and a very dark halftone in print, instead
+  % of actual black.
+  \def\rgbDarkRed{0.50 0.09 0.12}
+  \def\rgbBlack{0 0 0}
+  %
+  % k sets the color for filling (usual text, etc.);
+  % K sets the color for stroking (thin rules, e.g., normal _'s).
+  \def\pdfsetcolor#1{\pdfliteral{#1 rg  #1 RG}}
+  %
+  % Set color, and create a mark which defines \thiscolor accordingly,
+  % so that \makeheadline knows which color to restore.
+  \def\setcolor#1{%
+    \xdef\lastcolordefs{\gdef\noexpand\thiscolor{#1}}%
+    \domark
+    \pdfsetcolor{#1}%
+  }
+  %
+  \def\maincolor{\rgbBlack}
+  \pdfsetcolor{\maincolor}
+  \edef\thiscolor{\maincolor}
+  \def\lastcolordefs{}
+  %
+  \def\makefootline{%
+    \baselineskip24pt
+    \line{\pdfsetcolor{\maincolor}\the\footline}%
+  }
+  %
+  \def\makeheadline{%
+    \vbox to 0pt{%
+      \vskip-22.5pt
+      \line{%
+        \vbox to8.5pt{}%
+        % Extract \thiscolor definition from the marks.
+        \getcolormarks
+        % Typeset the headline with \maincolor, then restore the color.
+        \pdfsetcolor{\maincolor}\the\headline\pdfsetcolor{\thiscolor}%
+      }%
+      \vss
+    }%
+    \nointerlineskip
+  }
+  %
+  %
+  \pdfcatalog{/PageMode /UseOutlines}
+  %
+  % #1 is image name, #2 width (might be empty/whitespace), #3 height (ditto).
+  \def\dopdfimage#1#2#3{%
+    \def\pdfimagewidth{#2}\setbox0 = \hbox{\ignorespaces #2}%
+    \def\pdfimageheight{#3}\setbox2 = \hbox{\ignorespaces #3}%
+    %
+    % pdftex (and the PDF format) support .pdf, .png, .jpg (among
+    % others).  Let's try in that order, PDF first since if
+    % someone has a scalable image, presumably better to use that than a
+    % bitmap.
+    \let\pdfimgext=\empty
+    \begingroup
+      \openin 1 #1.pdf \ifeof 1
+        \openin 1 #1.PDF \ifeof 1
+          \openin 1 #1.png \ifeof 1
+            \openin 1 #1.jpg \ifeof 1
+              \openin 1 #1.jpeg \ifeof 1
+                \openin 1 #1.JPG \ifeof 1
+                  \errhelp = \nopdfimagehelp
+                  \errmessage{Could not find image file #1 for pdf}%
+                \else \gdef\pdfimgext{JPG}%
+                \fi
+              \else \gdef\pdfimgext{jpeg}%
+              \fi
+            \else \gdef\pdfimgext{jpg}%
+            \fi
+          \else \gdef\pdfimgext{png}%
+          \fi
+        \else \gdef\pdfimgext{PDF}%
+        \fi
+      \else \gdef\pdfimgext{pdf}%
+      \fi
+      \closein 1
+    \endgroup
+    %
+    % without \immediate, ancient pdftex seg faults when the same image is
+    % included twice.  (Version 3.14159-pre-1.0-unofficial-20010704.)
+    \ifnum\pdftexversion < 14
+      \immediate\pdfimage
+    \else
+      \immediate\pdfximage
+    \fi
+      \ifdim \wd0 >0pt width \pdfimagewidth \fi
+      \ifdim \wd2 >0pt height \pdfimageheight \fi
+      \ifnum\pdftexversion<13
+         #1.\pdfimgext
+       \else
+         {#1.\pdfimgext}%
+       \fi
+    \ifnum\pdftexversion < 14 \else
+      \pdfrefximage \pdflastximage
+    \fi}
+  %
+  \def\pdfmkdest#1{{%
+    % We have to set dummies so commands such as @code, and characters
+    % such as \, aren't expanded when present in a section title.
+    \indexnofonts
+    \turnoffactive
+    \makevalueexpandable
+    \def\pdfdestname{#1}%
+    \txiescapepdf\pdfdestname
+    \safewhatsit{\pdfdest name{\pdfdestname} xyz}%
+  }}
+  %
+  % used to mark target names; must be expandable.
+  \def\pdfmkpgn#1{#1}
+  %
+  % by default, use a color that is dark enough to print on paper as
+  % nearly black, but still distinguishable for online viewing.
+  \def\urlcolor{\rgbDarkRed}
+  \def\linkcolor{\rgbDarkRed}
+  \def\endlink{\setcolor{\maincolor}\pdfendlink}
+  %
+  % Adding outlines to PDF; macros for calculating structure of outlines
+  % come from Petr Olsak
+  \def\expnumber#1{\expandafter\ifx\csname#1\endcsname\relax 0%
+    \else \csname#1\endcsname \fi}
+  \def\advancenumber#1{\tempnum=\expnumber{#1}\relax
+    \advance\tempnum by 1
+    \expandafter\xdef\csname#1\endcsname{\the\tempnum}}
+  %
+  % #1 is the section text, which is what will be displayed in the
+  % outline by the pdf viewer.  #2 is the pdf expression for the number
+  % of subentries (or empty, for subsubsections).  #3 is the node text,
+  % which might be empty if this toc entry had no corresponding node.
+  % #4 is the page number
+  %
+  \def\dopdfoutline#1#2#3#4{%
+    % Generate a link to the node text if that exists; else, use the
+    % page number.  We could generate a destination for the section
+    % text in the case where a section has no node, but it doesn't
+    % seem worth the trouble, since most documents are normally structured.
+    \edef\pdfoutlinedest{#3}%
+    \ifx\pdfoutlinedest\empty
+      \def\pdfoutlinedest{#4}%
+    \else
+      \txiescapepdf\pdfoutlinedest
+    \fi
+    %
+    % Also escape PDF chars in the display string.
+    \edef\pdfoutlinetext{#1}%
+    \txiescapepdf\pdfoutlinetext
+    %
+    \pdfoutline goto name{\pdfmkpgn{\pdfoutlinedest}}#2{\pdfoutlinetext}%
+  }
+  %
+  \def\pdfmakeoutlines{%
+    \begingroup
+      % Read toc silently, to get counts of subentries for \pdfoutline.
+      \def\partentry##1##2##3##4{}% ignore parts in the outlines
+      \def\numchapentry##1##2##3##4{%
+	\def\thischapnum{##2}%
+	\def\thissecnum{0}%
+	\def\thissubsecnum{0}%
+      }%
+      \def\numsecentry##1##2##3##4{%
+	\advancenumber{chap\thischapnum}%
+	\def\thissecnum{##2}%
+	\def\thissubsecnum{0}%
+      }%
+      \def\numsubsecentry##1##2##3##4{%
+	\advancenumber{sec\thissecnum}%
+	\def\thissubsecnum{##2}%
+      }%
+      \def\numsubsubsecentry##1##2##3##4{%
+	\advancenumber{subsec\thissubsecnum}%
+      }%
+      \def\thischapnum{0}%
+      \def\thissecnum{0}%
+      \def\thissubsecnum{0}%
+      %
+      % use \def rather than \let here because we redefine \chapentry et
+      % al. a second time, below.
+      \def\appentry{\numchapentry}%
+      \def\appsecentry{\numsecentry}%
+      \def\appsubsecentry{\numsubsecentry}%
+      \def\appsubsubsecentry{\numsubsubsecentry}%
+      \def\unnchapentry{\numchapentry}%
+      \def\unnsecentry{\numsecentry}%
+      \def\unnsubsecentry{\numsubsecentry}%
+      \def\unnsubsubsecentry{\numsubsubsecentry}%
+      \readdatafile{toc}%
+      %
+      % Read toc second time, this time actually producing the outlines.
+      % The `-' means take the \expnumber as the absolute number of
+      % subentries, which we calculated on our first read of the .toc above.
+      %
+      % We use the node names as the destinations.
+      \def\numchapentry##1##2##3##4{%
+        \dopdfoutline{##1}{count-\expnumber{chap##2}}{##3}{##4}}%
+      \def\numsecentry##1##2##3##4{%
+        \dopdfoutline{##1}{count-\expnumber{sec##2}}{##3}{##4}}%
+      \def\numsubsecentry##1##2##3##4{%
+        \dopdfoutline{##1}{count-\expnumber{subsec##2}}{##3}{##4}}%
+      \def\numsubsubsecentry##1##2##3##4{% count is always zero
+        \dopdfoutline{##1}{}{##3}{##4}}%
+      %
+      % PDF outlines are displayed using system fonts, instead of
+      % document fonts.  Therefore we cannot use special characters,
+      % since the encoding is unknown.  For example, the eogonek from
+      % Latin 2 (0xea) gets translated to a | character.  Info from
+      % Staszek Wawrykiewicz, 19 Jan 2004 04:09:24 +0100.
+      %
+      % TODO this right, we have to translate 8-bit characters to
+      % their "best" equivalent, based on the @documentencoding.  Too
+      % much work for too little return.  Just use the ASCII equivalents
+      % we use for the index sort strings.
+      % 
+      \indexnofonts
+      \setupdatafile
+      % We can have normal brace characters in the PDF outlines, unlike
+      % Texinfo index files.  So set that up.
+      \def\{{\lbracecharliteral}%
+      \def\}{\rbracecharliteral}%
+      \catcode`\\=\active \otherbackslash
+      \input \tocreadfilename
+    \endgroup
+  }
+  {\catcode`[=1 \catcode`]=2
+   \catcode`{=\other \catcode`}=\other
+   \gdef\lbracecharliteral[{]%
+   \gdef\rbracecharliteral[}]%
+  ]
+  %
+  \def\skipspaces#1{\def\PP{#1}\def\D{|}%
+    \ifx\PP\D\let\nextsp\relax
+    \else\let\nextsp\skipspaces
+      \addtokens{\filename}{\PP}%
+      \advance\filenamelength by 1
+    \fi
+    \nextsp}
+  \def\getfilename#1{%
+    \filenamelength=0
+    % If we don't expand the argument now, \skipspaces will get
+    % snagged on things like "@value{foo}".
+    \edef\temp{#1}%
+    \expandafter\skipspaces\temp|\relax
+  }
+  \ifnum\pdftexversion < 14
+    \let \startlink \pdfannotlink
+  \else
+    \let \startlink \pdfstartlink
+  \fi
+  % make a live url in pdf output.
+  \def\pdfurl#1{%
+    \begingroup
+      % it seems we really need yet another set of dummies; have not
+      % tried to figure out what each command should do in the context
+      % of @url.  for now, just make @/ a no-op, that's the only one
+      % people have actually reported a problem with.
+      %
+      \normalturnoffactive
+      \def\@{@}%
+      \let\/=\empty
+      \makevalueexpandable
+      % do we want to go so far as to use \indexnofonts instead of just
+      % special-casing \var here?
+      \def\var##1{##1}%
+      %
+      \leavevmode\setcolor{\urlcolor}%
+      \startlink attr{/Border [0 0 0]}%
+        user{/Subtype /Link /A << /S /URI /URI (#1) >>}%
+    \endgroup}
+  \def\pdfgettoks#1.{\setbox\boxA=\hbox{\toksA={#1.}\toksB={}\maketoks}}
+  \def\addtokens#1#2{\edef\addtoks{\noexpand#1={\the#1#2}}\addtoks}
+  \def\adn#1{\addtokens{\toksC}{#1}\global\countA=1\let\next=\maketoks}
+  \def\poptoks#1#2|ENDTOKS|{\let\first=#1\toksD={#1}\toksA={#2}}
+  \def\maketoks{%
+    \expandafter\poptoks\the\toksA|ENDTOKS|\relax
+    \ifx\first0\adn0
+    \else\ifx\first1\adn1 \else\ifx\first2\adn2 \else\ifx\first3\adn3
+    \else\ifx\first4\adn4 \else\ifx\first5\adn5 \else\ifx\first6\adn6
+    \else\ifx\first7\adn7 \else\ifx\first8\adn8 \else\ifx\first9\adn9
+    \else
+      \ifnum0=\countA\else\makelink\fi
+      \ifx\first.\let\next=\done\else
+        \let\next=\maketoks
+        \addtokens{\toksB}{\the\toksD}
+        \ifx\first,\addtokens{\toksB}{\space}\fi
+      \fi
+    \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi
+    \next}
+  \def\makelink{\addtokens{\toksB}%
+    {\noexpand\pdflink{\the\toksC}}\toksC={}\global\countA=0}
+  \def\pdflink#1{%
+    \startlink attr{/Border [0 0 0]} goto name{\pdfmkpgn{#1}}
+    \setcolor{\linkcolor}#1\endlink}
+  \def\done{\edef\st{\global\noexpand\toksA={\the\toksB}}\st}
+\else
+  % non-pdf mode
+  \let\pdfmkdest = \gobble
+  \let\pdfurl = \gobble
+  \let\endlink = \relax
+  \let\setcolor = \gobble
+  \let\pdfsetcolor = \gobble
+  \let\pdfmakeoutlines = \relax
+\fi  % \ifx\pdfoutput
+
+
+\message{fonts,}
+
+% Change the current font style to #1, remembering it in \curfontstyle.
+% For now, we do not accumulate font styles: @b{@i{foo}} prints foo in
+% italics, not bold italics.
+%
+\def\setfontstyle#1{%
+  \def\curfontstyle{#1}% not as a control sequence, because we are \edef'd.
+  \csname ten#1\endcsname  % change the current font
+}
+
+% Select #1 fonts with the current style.
+%
+\def\selectfonts#1{\csname #1fonts\endcsname \csname\curfontstyle\endcsname}
+
+\def\rm{\fam=0 \setfontstyle{rm}}
+\def\it{\fam=\itfam \setfontstyle{it}}
+\def\sl{\fam=\slfam \setfontstyle{sl}}
+\def\bf{\fam=\bffam \setfontstyle{bf}}\def\bfstylename{bf}
+\def\tt{\fam=\ttfam \setfontstyle{tt}}
+
+% Unfortunately, we have to override this for titles and the like, since
+% in those cases "rm" is bold.  Sigh.
+\def\rmisbold{\rm\def\curfontstyle{bf}}
+
+% Texinfo sort of supports the sans serif font style, which plain TeX does not.
+% So we set up a \sf.
+\newfam\sffam
+\def\sf{\fam=\sffam \setfontstyle{sf}}
+\let\li = \sf % Sometimes we call it \li, not \sf.
+
+% We don't need math for this font style.
+\def\ttsl{\setfontstyle{ttsl}}
+
+
+% Set the baselineskip to #1, and the lineskip and strut size
+% correspondingly.  There is no deep meaning behind these magic numbers
+% used as factors; they just match (closely enough) what Knuth defined.
+%
+\def\lineskipfactor{.08333}
+\def\strutheightpercent{.70833}
+\def\strutdepthpercent {.29167}
+%
+% can get a sort of poor man's double spacing by redefining this.
+\def\baselinefactor{1}
+%
+\newdimen\textleading
+\def\setleading#1{%
+  \dimen0 = #1\relax
+  \normalbaselineskip = \baselinefactor\dimen0
+  \normallineskip = \lineskipfactor\normalbaselineskip
+  \normalbaselines
+  \setbox\strutbox =\hbox{%
+    \vrule width0pt height\strutheightpercent\baselineskip
+                    depth \strutdepthpercent \baselineskip
+  }%
+}
+
+% PDF CMaps.  See also LaTeX's t1.cmap.
+%
+% do nothing with this by default.
+\expandafter\let\csname cmapOT1\endcsname\gobble
+\expandafter\let\csname cmapOT1IT\endcsname\gobble
+\expandafter\let\csname cmapOT1TT\endcsname\gobble
+
+% if we are producing pdf, and we have \pdffontattr, then define cmaps.
+% (\pdffontattr was introduced many years ago, but people still run
+% older pdftex's; it's easy to conditionalize, so we do.)
+\ifpdf \ifx\pdffontattr\thisisundefined \else
+  \begingroup
+    \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char.
+    \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap
+%%DocumentNeededResources: ProcSet (CIDInit)
+%%IncludeResource: ProcSet (CIDInit)
+%%BeginResource: CMap (TeX-OT1-0)
+%%Title: (TeX-OT1-0 TeX OT1 0)
+%%Version: 1.000
+%%EndComments
+/CIDInit /ProcSet findresource begin
+12 dict begin
+begincmap
+/CIDSystemInfo
+<< /Registry (TeX)
+/Ordering (OT1)
+/Supplement 0
+>> def
+/CMapName /TeX-OT1-0 def
+/CMapType 2 def
+1 begincodespacerange
+<00> <7F>
+endcodespacerange
+8 beginbfrange
+<00> <01> <0393>
+<09> <0A> <03A8>
+<23> <26> <0023>
+<28> <3B> <0028>
+<3F> <5B> <003F>
+<5D> <5E> <005D>
+<61> <7A> <0061>
+<7B> <7C> <2013>
+endbfrange
+40 beginbfchar
+<02> <0398>
+<03> <039B>
+<04> <039E>
+<05> <03A0>
+<06> <03A3>
+<07> <03D2>
+<08> <03A6>
+<0B> <00660066>
+<0C> <00660069>
+<0D> <0066006C>
+<0E> <006600660069>
+<0F> <00660066006C>
+<10> <0131>
+<11> <0237>
+<12> <0060>
+<13> <00B4>
+<14> <02C7>
+<15> <02D8>
+<16> <00AF>
+<17> <02DA>
+<18> <00B8>
+<19> <00DF>
+<1A> <00E6>
+<1B> <0153>
+<1C> <00F8>
+<1D> <00C6>
+<1E> <0152>
+<1F> <00D8>
+<21> <0021>
+<22> <201D>
+<27> <2019>
+<3C> <00A1>
+<3D> <003D>
+<3E> <00BF>
+<5C> <201C>
+<5F> <02D9>
+<60> <2018>
+<7D> <02DD>
+<7E> <007E>
+<7F> <00A8>
+endbfchar
+endcmap
+CMapName currentdict /CMap defineresource pop
+end
+end
+%%EndResource
+%%EOF
+    }\endgroup
+  \expandafter\edef\csname cmapOT1\endcsname#1{%
+    \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}%
+  }%
+%
+% \cmapOT1IT
+  \begingroup
+    \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char.
+    \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap
+%%DocumentNeededResources: ProcSet (CIDInit)
+%%IncludeResource: ProcSet (CIDInit)
+%%BeginResource: CMap (TeX-OT1IT-0)
+%%Title: (TeX-OT1IT-0 TeX OT1IT 0)
+%%Version: 1.000
+%%EndComments
+/CIDInit /ProcSet findresource begin
+12 dict begin
+begincmap
+/CIDSystemInfo
+<< /Registry (TeX)
+/Ordering (OT1IT)
+/Supplement 0
+>> def
+/CMapName /TeX-OT1IT-0 def
+/CMapType 2 def
+1 begincodespacerange
+<00> <7F>
+endcodespacerange
+8 beginbfrange
+<00> <01> <0393>
+<09> <0A> <03A8>
+<25> <26> <0025>
+<28> <3B> <0028>
+<3F> <5B> <003F>
+<5D> <5E> <005D>
+<61> <7A> <0061>
+<7B> <7C> <2013>
+endbfrange
+42 beginbfchar
+<02> <0398>
+<03> <039B>
+<04> <039E>
+<05> <03A0>
+<06> <03A3>
+<07> <03D2>
+<08> <03A6>
+<0B> <00660066>
+<0C> <00660069>
+<0D> <0066006C>
+<0E> <006600660069>
+<0F> <00660066006C>
+<10> <0131>
+<11> <0237>
+<12> <0060>
+<13> <00B4>
+<14> <02C7>
+<15> <02D8>
+<16> <00AF>
+<17> <02DA>
+<18> <00B8>
+<19> <00DF>
+<1A> <00E6>
+<1B> <0153>
+<1C> <00F8>
+<1D> <00C6>
+<1E> <0152>
+<1F> <00D8>
+<21> <0021>
+<22> <201D>
+<23> <0023>
+<24> <00A3>
+<27> <2019>
+<3C> <00A1>
+<3D> <003D>
+<3E> <00BF>
+<5C> <201C>
+<5F> <02D9>
+<60> <2018>
+<7D> <02DD>
+<7E> <007E>
+<7F> <00A8>
+endbfchar
+endcmap
+CMapName currentdict /CMap defineresource pop
+end
+end
+%%EndResource
+%%EOF
+    }\endgroup
+  \expandafter\edef\csname cmapOT1IT\endcsname#1{%
+    \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}%
+  }%
+%
+% \cmapOT1TT
+  \begingroup
+    \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char.
+    \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap
+%%DocumentNeededResources: ProcSet (CIDInit)
+%%IncludeResource: ProcSet (CIDInit)
+%%BeginResource: CMap (TeX-OT1TT-0)
+%%Title: (TeX-OT1TT-0 TeX OT1TT 0)
+%%Version: 1.000
+%%EndComments
+/CIDInit /ProcSet findresource begin
+12 dict begin
+begincmap
+/CIDSystemInfo
+<< /Registry (TeX)
+/Ordering (OT1TT)
+/Supplement 0
+>> def
+/CMapName /TeX-OT1TT-0 def
+/CMapType 2 def
+1 begincodespacerange
+<00> <7F>
+endcodespacerange
+5 beginbfrange
+<00> <01> <0393>
+<09> <0A> <03A8>
+<21> <26> <0021>
+<28> <5F> <0028>
+<61> <7E> <0061>
+endbfrange
+32 beginbfchar
+<02> <0398>
+<03> <039B>
+<04> <039E>
+<05> <03A0>
+<06> <03A3>
+<07> <03D2>
+<08> <03A6>
+<0B> <2191>
+<0C> <2193>
+<0D> <0027>
+<0E> <00A1>
+<0F> <00BF>
+<10> <0131>
+<11> <0237>
+<12> <0060>
+<13> <00B4>
+<14> <02C7>
+<15> <02D8>
+<16> <00AF>
+<17> <02DA>
+<18> <00B8>
+<19> <00DF>
+<1A> <00E6>
+<1B> <0153>
+<1C> <00F8>
+<1D> <00C6>
+<1E> <0152>
+<1F> <00D8>
+<20> <2423>
+<27> <2019>
+<60> <2018>
+<7F> <00A8>
+endbfchar
+endcmap
+CMapName currentdict /CMap defineresource pop
+end
+end
+%%EndResource
+%%EOF
+    }\endgroup
+  \expandafter\edef\csname cmapOT1TT\endcsname#1{%
+    \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}%
+  }%
+\fi\fi
+
+
+% Set the font macro #1 to the font named \fontprefix#2.
+% #3 is the font's design size, #4 is a scale factor, #5 is the CMap
+% encoding (only OT1, OT1IT and OT1TT are allowed, or empty to omit).
+% Example:
+% #1 = \textrm
+% #2 = \rmshape
+% #3 = 10
+% #4 = \mainmagstep
+% #5 = OT1
+%
+\def\setfont#1#2#3#4#5{%
+  \font#1=\fontprefix#2#3 scaled #4
+  \csname cmap#5\endcsname#1%
+}
+% This is what gets called when #5 of \setfont is empty.
+\let\cmap\gobble
+%
+% (end of cmaps)
+
+% Use cm as the default font prefix.
+% To specify the font prefix, you must define \fontprefix
+% before you read in texinfo.tex.
+\ifx\fontprefix\thisisundefined
+\def\fontprefix{cm}
+\fi
+% Support font families that don't use the same naming scheme as CM.
+\def\rmshape{r}
+\def\rmbshape{bx}               % where the normal face is bold
+\def\bfshape{b}
+\def\bxshape{bx}
+\def\ttshape{tt}
+\def\ttbshape{tt}
+\def\ttslshape{sltt}
+\def\itshape{ti}
+\def\itbshape{bxti}
+\def\slshape{sl}
+\def\slbshape{bxsl}
+\def\sfshape{ss}
+\def\sfbshape{ss}
+\def\scshape{csc}
+\def\scbshape{csc}
+
+% Definitions for a main text size of 11pt.  (The default in Texinfo.)
+%
+\def\definetextfontsizexi{%
+% Text fonts (11.2pt, magstep1).
+\def\textnominalsize{11pt}
+\edef\mainmagstep{\magstephalf}
+\setfont\textrm\rmshape{10}{\mainmagstep}{OT1}
+\setfont\texttt\ttshape{10}{\mainmagstep}{OT1TT}
+\setfont\textbf\bfshape{10}{\mainmagstep}{OT1}
+\setfont\textit\itshape{10}{\mainmagstep}{OT1IT}
+\setfont\textsl\slshape{10}{\mainmagstep}{OT1}
+\setfont\textsf\sfshape{10}{\mainmagstep}{OT1}
+\setfont\textsc\scshape{10}{\mainmagstep}{OT1}
+\setfont\textttsl\ttslshape{10}{\mainmagstep}{OT1TT}
+\font\texti=cmmi10 scaled \mainmagstep
+\font\textsy=cmsy10 scaled \mainmagstep
+\def\textecsize{1095}
+
+% A few fonts for @defun names and args.
+\setfont\defbf\bfshape{10}{\magstep1}{OT1}
+\setfont\deftt\ttshape{10}{\magstep1}{OT1TT}
+\setfont\defttsl\ttslshape{10}{\magstep1}{OT1TT}
+\def\df{\let\tentt=\deftt \let\tenbf = \defbf \let\tenttsl=\defttsl \bf}
+
+% Fonts for indices, footnotes, small examples (9pt).
+\def\smallnominalsize{9pt}
+\setfont\smallrm\rmshape{9}{1000}{OT1}
+\setfont\smalltt\ttshape{9}{1000}{OT1TT}
+\setfont\smallbf\bfshape{10}{900}{OT1}
+\setfont\smallit\itshape{9}{1000}{OT1IT}
+\setfont\smallsl\slshape{9}{1000}{OT1}
+\setfont\smallsf\sfshape{9}{1000}{OT1}
+\setfont\smallsc\scshape{10}{900}{OT1}
+\setfont\smallttsl\ttslshape{10}{900}{OT1TT}
+\font\smalli=cmmi9
+\font\smallsy=cmsy9
+\def\smallecsize{0900}
+
+% Fonts for small examples (8pt).
+\def\smallernominalsize{8pt}
+\setfont\smallerrm\rmshape{8}{1000}{OT1}
+\setfont\smallertt\ttshape{8}{1000}{OT1TT}
+\setfont\smallerbf\bfshape{10}{800}{OT1}
+\setfont\smallerit\itshape{8}{1000}{OT1IT}
+\setfont\smallersl\slshape{8}{1000}{OT1}
+\setfont\smallersf\sfshape{8}{1000}{OT1}
+\setfont\smallersc\scshape{10}{800}{OT1}
+\setfont\smallerttsl\ttslshape{10}{800}{OT1TT}
+\font\smalleri=cmmi8
+\font\smallersy=cmsy8
+\def\smallerecsize{0800}
+
+% Fonts for title page (20.4pt):
+\def\titlenominalsize{20pt}
+\setfont\titlerm\rmbshape{12}{\magstep3}{OT1}
+\setfont\titleit\itbshape{10}{\magstep4}{OT1IT}
+\setfont\titlesl\slbshape{10}{\magstep4}{OT1}
+\setfont\titlett\ttbshape{12}{\magstep3}{OT1TT}
+\setfont\titlettsl\ttslshape{10}{\magstep4}{OT1TT}
+\setfont\titlesf\sfbshape{17}{\magstep1}{OT1}
+\let\titlebf=\titlerm
+\setfont\titlesc\scbshape{10}{\magstep4}{OT1}
+\font\titlei=cmmi12 scaled \magstep3
+\font\titlesy=cmsy10 scaled \magstep4
+\def\titleecsize{2074}
+
+% Chapter (and unnumbered) fonts (17.28pt).
+\def\chapnominalsize{17pt}
+\setfont\chaprm\rmbshape{12}{\magstep2}{OT1}
+\setfont\chapit\itbshape{10}{\magstep3}{OT1IT}
+\setfont\chapsl\slbshape{10}{\magstep3}{OT1}
+\setfont\chaptt\ttbshape{12}{\magstep2}{OT1TT}
+\setfont\chapttsl\ttslshape{10}{\magstep3}{OT1TT}
+\setfont\chapsf\sfbshape{17}{1000}{OT1}
+\let\chapbf=\chaprm
+\setfont\chapsc\scbshape{10}{\magstep3}{OT1}
+\font\chapi=cmmi12 scaled \magstep2
+\font\chapsy=cmsy10 scaled \magstep3
+\def\chapecsize{1728}
+
+% Section fonts (14.4pt).
+\def\secnominalsize{14pt}
+\setfont\secrm\rmbshape{12}{\magstep1}{OT1}
+\setfont\secit\itbshape{10}{\magstep2}{OT1IT}
+\setfont\secsl\slbshape{10}{\magstep2}{OT1}
+\setfont\sectt\ttbshape{12}{\magstep1}{OT1TT}
+\setfont\secttsl\ttslshape{10}{\magstep2}{OT1TT}
+\setfont\secsf\sfbshape{12}{\magstep1}{OT1}
+\let\secbf\secrm
+\setfont\secsc\scbshape{10}{\magstep2}{OT1}
+\font\seci=cmmi12 scaled \magstep1
+\font\secsy=cmsy10 scaled \magstep2
+\def\sececsize{1440}
+
+% Subsection fonts (13.15pt).
+\def\ssecnominalsize{13pt}
+\setfont\ssecrm\rmbshape{12}{\magstephalf}{OT1}
+\setfont\ssecit\itbshape{10}{1315}{OT1IT}
+\setfont\ssecsl\slbshape{10}{1315}{OT1}
+\setfont\ssectt\ttbshape{12}{\magstephalf}{OT1TT}
+\setfont\ssecttsl\ttslshape{10}{1315}{OT1TT}
+\setfont\ssecsf\sfbshape{12}{\magstephalf}{OT1}
+\let\ssecbf\ssecrm
+\setfont\ssecsc\scbshape{10}{1315}{OT1}
+\font\sseci=cmmi12 scaled \magstephalf
+\font\ssecsy=cmsy10 scaled 1315
+\def\ssececsize{1200}
+
+% Reduced fonts for @acro in text (10pt).
+\def\reducednominalsize{10pt}
+\setfont\reducedrm\rmshape{10}{1000}{OT1}
+\setfont\reducedtt\ttshape{10}{1000}{OT1TT}
+\setfont\reducedbf\bfshape{10}{1000}{OT1}
+\setfont\reducedit\itshape{10}{1000}{OT1IT}
+\setfont\reducedsl\slshape{10}{1000}{OT1}
+\setfont\reducedsf\sfshape{10}{1000}{OT1}
+\setfont\reducedsc\scshape{10}{1000}{OT1}
+\setfont\reducedttsl\ttslshape{10}{1000}{OT1TT}
+\font\reducedi=cmmi10
+\font\reducedsy=cmsy10
+\def\reducedecsize{1000}
+
+\textleading = 13.2pt % line spacing for 11pt CM
+\textfonts            % reset the current fonts
+\rm
+} % end of 11pt text font size definitions, \definetextfontsizexi
+
+
+% Definitions to make the main text be 10pt Computer Modern, with
+% section, chapter, etc., sizes following suit.  This is for the GNU
+% Press printing of the Emacs 22 manual.  Maybe other manuals in the
+% future.  Used with @smallbook, which sets the leading to 12pt.
+%
+\def\definetextfontsizex{%
+% Text fonts (10pt).
+\def\textnominalsize{10pt}
+\edef\mainmagstep{1000}
+\setfont\textrm\rmshape{10}{\mainmagstep}{OT1}
+\setfont\texttt\ttshape{10}{\mainmagstep}{OT1TT}
+\setfont\textbf\bfshape{10}{\mainmagstep}{OT1}
+\setfont\textit\itshape{10}{\mainmagstep}{OT1IT}
+\setfont\textsl\slshape{10}{\mainmagstep}{OT1}
+\setfont\textsf\sfshape{10}{\mainmagstep}{OT1}
+\setfont\textsc\scshape{10}{\mainmagstep}{OT1}
+\setfont\textttsl\ttslshape{10}{\mainmagstep}{OT1TT}
+\font\texti=cmmi10 scaled \mainmagstep
+\font\textsy=cmsy10 scaled \mainmagstep
+\def\textecsize{1000}
+
+% A few fonts for @defun names and args.
+\setfont\defbf\bfshape{10}{\magstephalf}{OT1}
+\setfont\deftt\ttshape{10}{\magstephalf}{OT1TT}
+\setfont\defttsl\ttslshape{10}{\magstephalf}{OT1TT}
+\def\df{\let\tentt=\deftt \let\tenbf = \defbf \let\tenttsl=\defttsl \bf}
+
+% Fonts for indices, footnotes, small examples (9pt).
+\def\smallnominalsize{9pt}
+\setfont\smallrm\rmshape{9}{1000}{OT1}
+\setfont\smalltt\ttshape{9}{1000}{OT1TT}
+\setfont\smallbf\bfshape{10}{900}{OT1}
+\setfont\smallit\itshape{9}{1000}{OT1IT}
+\setfont\smallsl\slshape{9}{1000}{OT1}
+\setfont\smallsf\sfshape{9}{1000}{OT1}
+\setfont\smallsc\scshape{10}{900}{OT1}
+\setfont\smallttsl\ttslshape{10}{900}{OT1TT}
+\font\smalli=cmmi9
+\font\smallsy=cmsy9
+\def\smallecsize{0900}
+
+% Fonts for small examples (8pt).
+\def\smallernominalsize{8pt}
+\setfont\smallerrm\rmshape{8}{1000}{OT1}
+\setfont\smallertt\ttshape{8}{1000}{OT1TT}
+\setfont\smallerbf\bfshape{10}{800}{OT1}
+\setfont\smallerit\itshape{8}{1000}{OT1IT}
+\setfont\smallersl\slshape{8}{1000}{OT1}
+\setfont\smallersf\sfshape{8}{1000}{OT1}
+\setfont\smallersc\scshape{10}{800}{OT1}
+\setfont\smallerttsl\ttslshape{10}{800}{OT1TT}
+\font\smalleri=cmmi8
+\font\smallersy=cmsy8
+\def\smallerecsize{0800}
+
+% Fonts for title page (20.4pt):
+\def\titlenominalsize{20pt}
+\setfont\titlerm\rmbshape{12}{\magstep3}{OT1}
+\setfont\titleit\itbshape{10}{\magstep4}{OT1IT}
+\setfont\titlesl\slbshape{10}{\magstep4}{OT1}
+\setfont\titlett\ttbshape{12}{\magstep3}{OT1TT}
+\setfont\titlettsl\ttslshape{10}{\magstep4}{OT1TT}
+\setfont\titlesf\sfbshape{17}{\magstep1}{OT1}
+\let\titlebf=\titlerm
+\setfont\titlesc\scbshape{10}{\magstep4}{OT1}
+\font\titlei=cmmi12 scaled \magstep3
+\font\titlesy=cmsy10 scaled \magstep4
+\def\titleecsize{2074}
+
+% Chapter fonts (14.4pt).
+\def\chapnominalsize{14pt}
+\setfont\chaprm\rmbshape{12}{\magstep1}{OT1}
+\setfont\chapit\itbshape{10}{\magstep2}{OT1IT}
+\setfont\chapsl\slbshape{10}{\magstep2}{OT1}
+\setfont\chaptt\ttbshape{12}{\magstep1}{OT1TT}
+\setfont\chapttsl\ttslshape{10}{\magstep2}{OT1TT}
+\setfont\chapsf\sfbshape{12}{\magstep1}{OT1}
+\let\chapbf\chaprm
+\setfont\chapsc\scbshape{10}{\magstep2}{OT1}
+\font\chapi=cmmi12 scaled \magstep1
+\font\chapsy=cmsy10 scaled \magstep2
+\def\chapecsize{1440}
+
+% Section fonts (12pt).
+\def\secnominalsize{12pt}
+\setfont\secrm\rmbshape{12}{1000}{OT1}
+\setfont\secit\itbshape{10}{\magstep1}{OT1IT}
+\setfont\secsl\slbshape{10}{\magstep1}{OT1}
+\setfont\sectt\ttbshape{12}{1000}{OT1TT}
+\setfont\secttsl\ttslshape{10}{\magstep1}{OT1TT}
+\setfont\secsf\sfbshape{12}{1000}{OT1}
+\let\secbf\secrm
+\setfont\secsc\scbshape{10}{\magstep1}{OT1}
+\font\seci=cmmi12
+\font\secsy=cmsy10 scaled \magstep1
+\def\sececsize{1200}
+
+% Subsection fonts (10pt).
+\def\ssecnominalsize{10pt}
+\setfont\ssecrm\rmbshape{10}{1000}{OT1}
+\setfont\ssecit\itbshape{10}{1000}{OT1IT}
+\setfont\ssecsl\slbshape{10}{1000}{OT1}
+\setfont\ssectt\ttbshape{10}{1000}{OT1TT}
+\setfont\ssecttsl\ttslshape{10}{1000}{OT1TT}
+\setfont\ssecsf\sfbshape{10}{1000}{OT1}
+\let\ssecbf\ssecrm
+\setfont\ssecsc\scbshape{10}{1000}{OT1}
+\font\sseci=cmmi10
+\font\ssecsy=cmsy10
+\def\ssececsize{1000}
+
+% Reduced fonts for @acro in text (9pt).
+\def\reducednominalsize{9pt}
+\setfont\reducedrm\rmshape{9}{1000}{OT1}
+\setfont\reducedtt\ttshape{9}{1000}{OT1TT}
+\setfont\reducedbf\bfshape{10}{900}{OT1}
+\setfont\reducedit\itshape{9}{1000}{OT1IT}
+\setfont\reducedsl\slshape{9}{1000}{OT1}
+\setfont\reducedsf\sfshape{9}{1000}{OT1}
+\setfont\reducedsc\scshape{10}{900}{OT1}
+\setfont\reducedttsl\ttslshape{10}{900}{OT1TT}
+\font\reducedi=cmmi9
+\font\reducedsy=cmsy9
+\def\reducedecsize{0900}
+
+\divide\parskip by 2  % reduce space between paragraphs
+\textleading = 12pt   % line spacing for 10pt CM
+\textfonts            % reset the current fonts
+\rm
+} % end of 10pt text font size definitions, \definetextfontsizex
+
+
+% We provide the user-level command
+%   @fonttextsize 10
+% (or 11) to redefine the text font size.  pt is assumed.
+%
+\def\xiword{11}
+\def\xword{10}
+\def\xwordpt{10pt}
+%
+\parseargdef\fonttextsize{%
+  \def\textsizearg{#1}%
+  %\wlog{doing @fonttextsize \textsizearg}%
+  %
+  % Set \globaldefs so that documents can use this inside @tex, since
+  % makeinfo 4.8 does not support it, but we need it nonetheless.
+  %
+ \begingroup \globaldefs=1
+  \ifx\textsizearg\xword \definetextfontsizex
+  \else \ifx\textsizearg\xiword \definetextfontsizexi
+  \else
+    \errhelp=\EMsimple
+    \errmessage{@fonttextsize only supports `10' or `11', not `\textsizearg'}
+  \fi\fi
+ \endgroup
+}
+
+
+% In order for the font changes to affect most math symbols and letters,
+% we have to define the \textfont of the standard families.  Since
+% texinfo doesn't allow for producing subscripts and superscripts except
+% in the main text, we don't bother to reset \scriptfont and
+% \scriptscriptfont (which would also require loading a lot more fonts).
+%
+\def\resetmathfonts{%
+  \textfont0=\tenrm \textfont1=\teni \textfont2=\tensy
+  \textfont\itfam=\tenit \textfont\slfam=\tensl \textfont\bffam=\tenbf
+  \textfont\ttfam=\tentt \textfont\sffam=\tensf
+}
+
+% The font-changing commands redefine the meanings of \tenSTYLE, instead
+% of just \STYLE.  We do this because \STYLE needs to also set the
+% current \fam for math mode.  Our \STYLE (e.g., \rm) commands hardwire
+% \tenSTYLE to set the current font.
+%
+% Each font-changing command also sets the names \lsize (one size lower)
+% and \lllsize (three sizes lower).  These relative commands are used in
+% the LaTeX logo and acronyms.
+%
+% This all needs generalizing, badly.
+%
+\def\textfonts{%
+  \let\tenrm=\textrm \let\tenit=\textit \let\tensl=\textsl
+  \let\tenbf=\textbf \let\tentt=\texttt \let\smallcaps=\textsc
+  \let\tensf=\textsf \let\teni=\texti \let\tensy=\textsy
+  \let\tenttsl=\textttsl
+  \def\curfontsize{text}%
+  \def\lsize{reduced}\def\lllsize{smaller}%
+  \resetmathfonts \setleading{\textleading}}
+\def\titlefonts{%
+  \let\tenrm=\titlerm \let\tenit=\titleit \let\tensl=\titlesl
+  \let\tenbf=\titlebf \let\tentt=\titlett \let\smallcaps=\titlesc
+  \let\tensf=\titlesf \let\teni=\titlei \let\tensy=\titlesy
+  \let\tenttsl=\titlettsl
+  \def\curfontsize{title}%
+  \def\lsize{chap}\def\lllsize{subsec}%
+  \resetmathfonts \setleading{27pt}}
+\def\titlefont#1{{\titlefonts\rmisbold #1}}
+\def\chapfonts{%
+  \let\tenrm=\chaprm \let\tenit=\chapit \let\tensl=\chapsl
+  \let\tenbf=\chapbf \let\tentt=\chaptt \let\smallcaps=\chapsc
+  \let\tensf=\chapsf \let\teni=\chapi \let\tensy=\chapsy
+  \let\tenttsl=\chapttsl
+  \def\curfontsize{chap}%
+  \def\lsize{sec}\def\lllsize{text}%
+  \resetmathfonts \setleading{19pt}}
+\def\secfonts{%
+  \let\tenrm=\secrm \let\tenit=\secit \let\tensl=\secsl
+  \let\tenbf=\secbf \let\tentt=\sectt \let\smallcaps=\secsc
+  \let\tensf=\secsf \let\teni=\seci \let\tensy=\secsy
+  \let\tenttsl=\secttsl
+  \def\curfontsize{sec}%
+  \def\lsize{subsec}\def\lllsize{reduced}%
+  \resetmathfonts \setleading{16pt}}
+\def\subsecfonts{%
+  \let\tenrm=\ssecrm \let\tenit=\ssecit \let\tensl=\ssecsl
+  \let\tenbf=\ssecbf \let\tentt=\ssectt \let\smallcaps=\ssecsc
+  \let\tensf=\ssecsf \let\teni=\sseci \let\tensy=\ssecsy
+  \let\tenttsl=\ssecttsl
+  \def\curfontsize{ssec}%
+  \def\lsize{text}\def\lllsize{small}%
+  \resetmathfonts \setleading{15pt}}
+\let\subsubsecfonts = \subsecfonts
+\def\reducedfonts{%
+  \let\tenrm=\reducedrm \let\tenit=\reducedit \let\tensl=\reducedsl
+  \let\tenbf=\reducedbf \let\tentt=\reducedtt \let\reducedcaps=\reducedsc
+  \let\tensf=\reducedsf \let\teni=\reducedi \let\tensy=\reducedsy
+  \let\tenttsl=\reducedttsl
+  \def\curfontsize{reduced}%
+  \def\lsize{small}\def\lllsize{smaller}%
+  \resetmathfonts \setleading{10.5pt}}
+\def\smallfonts{%
+  \let\tenrm=\smallrm \let\tenit=\smallit \let\tensl=\smallsl
+  \let\tenbf=\smallbf \let\tentt=\smalltt \let\smallcaps=\smallsc
+  \let\tensf=\smallsf \let\teni=\smalli \let\tensy=\smallsy
+  \let\tenttsl=\smallttsl
+  \def\curfontsize{small}%
+  \def\lsize{smaller}\def\lllsize{smaller}%
+  \resetmathfonts \setleading{10.5pt}}
+\def\smallerfonts{%
+  \let\tenrm=\smallerrm \let\tenit=\smallerit \let\tensl=\smallersl
+  \let\tenbf=\smallerbf \let\tentt=\smallertt \let\smallcaps=\smallersc
+  \let\tensf=\smallersf \let\teni=\smalleri \let\tensy=\smallersy
+  \let\tenttsl=\smallerttsl
+  \def\curfontsize{smaller}%
+  \def\lsize{smaller}\def\lllsize{smaller}%
+  \resetmathfonts \setleading{9.5pt}}
+
+% Fonts for short table of contents.
+\setfont\shortcontrm\rmshape{12}{1000}{OT1}
+\setfont\shortcontbf\bfshape{10}{\magstep1}{OT1}  % no cmb12
+\setfont\shortcontsl\slshape{12}{1000}{OT1}
+\setfont\shortconttt\ttshape{12}{1000}{OT1TT}
+
+% Define these just so they can be easily changed for other fonts.
+\def\angleleft{$\langle$}
+\def\angleright{$\rangle$}
+
+% Set the fonts to use with the @small... environments.
+\let\smallexamplefonts = \smallfonts
+
+% About \smallexamplefonts.  If we use \smallfonts (9pt), @smallexample
+% can fit this many characters:
+%   8.5x11=86   smallbook=72  a4=90  a5=69
+% If we use \scriptfonts (8pt), then we can fit this many characters:
+%   8.5x11=90+  smallbook=80  a4=90+  a5=77
+% For me, subjectively, the few extra characters that fit aren't worth
+% the additional smallness of 8pt.  So I'm making the default 9pt.
+%
+% By the way, for comparison, here's what fits with @example (10pt):
+%   8.5x11=71  smallbook=60  a4=75  a5=58
+% --karl, 24jan03.
+
+% Set up the default fonts, so we can use them for creating boxes.
+%
+\definetextfontsizexi
+
+
+\message{markup,}
+
+% Check if we are currently using a typewriter font.  Since all the
+% Computer Modern typewriter fonts have zero interword stretch (and
+% shrink), and it is reasonable to expect all typewriter fonts to have
+% this property, we can check that font parameter.
+%
+\def\ifmonospace{\ifdim\fontdimen3\font=0pt }
+
+% Markup style infrastructure.  \defmarkupstylesetup\INITMACRO will
+% define and register \INITMACRO to be called on markup style changes.
+% \INITMACRO can check \currentmarkupstyle for the innermost
+% style and the set of \ifmarkupSTYLE switches for all styles
+% currently in effect.
+\newif\ifmarkupvar
+\newif\ifmarkupsamp
+\newif\ifmarkupkey
+%\newif\ifmarkupfile % @file == @samp.
+%\newif\ifmarkupoption % @option == @samp.
+\newif\ifmarkupcode
+\newif\ifmarkupkbd
+%\newif\ifmarkupenv % @env == @code.
+%\newif\ifmarkupcommand % @command == @code.
+\newif\ifmarkuptex % @tex (and part of @math, for now).
+\newif\ifmarkupexample
+\newif\ifmarkupverb
+\newif\ifmarkupverbatim
+
+\let\currentmarkupstyle\empty
+
+\def\setupmarkupstyle#1{%
+  \csname markup#1true\endcsname
+  \def\currentmarkupstyle{#1}%
+  \markupstylesetup
+}
+
+\let\markupstylesetup\empty
+
+\def\defmarkupstylesetup#1{%
+  \expandafter\def\expandafter\markupstylesetup
+    \expandafter{\markupstylesetup #1}%
+  \def#1%
+}
+
+% Markup style setup for left and right quotes.
+\defmarkupstylesetup\markupsetuplq{%
+  \expandafter\let\expandafter \temp
+    \csname markupsetuplq\currentmarkupstyle\endcsname
+  \ifx\temp\relax \markupsetuplqdefault \else \temp \fi
+}
+
+\defmarkupstylesetup\markupsetuprq{%
+  \expandafter\let\expandafter \temp
+    \csname markupsetuprq\currentmarkupstyle\endcsname
+  \ifx\temp\relax \markupsetuprqdefault \else \temp \fi
+}
+
+{
+\catcode`\'=\active
+\catcode`\`=\active
+
+\gdef\markupsetuplqdefault{\let`\lq}
+\gdef\markupsetuprqdefault{\let'\rq}
+
+\gdef\markupsetcodequoteleft{\let`\codequoteleft}
+\gdef\markupsetcodequoteright{\let'\codequoteright}
+}
+
+\let\markupsetuplqcode \markupsetcodequoteleft
+\let\markupsetuprqcode \markupsetcodequoteright
+%
+\let\markupsetuplqexample \markupsetcodequoteleft
+\let\markupsetuprqexample \markupsetcodequoteright
+%
+\let\markupsetuplqkbd     \markupsetcodequoteleft
+\let\markupsetuprqkbd     \markupsetcodequoteright
+%
+\let\markupsetuplqsamp \markupsetcodequoteleft
+\let\markupsetuprqsamp \markupsetcodequoteright
+%
+\let\markupsetuplqverb \markupsetcodequoteleft
+\let\markupsetuprqverb \markupsetcodequoteright
+%
+\let\markupsetuplqverbatim \markupsetcodequoteleft
+\let\markupsetuprqverbatim \markupsetcodequoteright
+
+% Allow an option to not use regular directed right quote/apostrophe
+% (char 0x27), but instead the undirected quote from cmtt (char 0x0d).
+% The undirected quote is ugly, so don't make it the default, but it
+% works for pasting with more pdf viewers (at least evince), the
+% lilypond developers report.  xpdf does work with the regular 0x27.
+%
+\def\codequoteright{%
+  \expandafter\ifx\csname SETtxicodequoteundirected\endcsname\relax
+    \expandafter\ifx\csname SETcodequoteundirected\endcsname\relax
+      '%
+    \else \char'15 \fi
+  \else \char'15 \fi
+}
+%
+% and a similar option for the left quote char vs. a grave accent.
+% Modern fonts display ASCII 0x60 as a grave accent, so some people like
+% the code environments to do likewise.
+%
+\def\codequoteleft{%
+  \expandafter\ifx\csname SETtxicodequotebacktick\endcsname\relax
+    \expandafter\ifx\csname SETcodequotebacktick\endcsname\relax
+      % [Knuth] pp. 380,381,391
+      % \relax disables Spanish ligatures ?` and !` of \tt font.
+      \relax`%
+    \else \char'22 \fi
+  \else \char'22 \fi
+}
+
+% Commands to set the quote options.
+% 
+\parseargdef\codequoteundirected{%
+  \def\temp{#1}%
+  \ifx\temp\onword
+    \expandafter\let\csname SETtxicodequoteundirected\endcsname
+      = t%
+  \else\ifx\temp\offword
+    \expandafter\let\csname SETtxicodequoteundirected\endcsname
+      = \relax
+  \else
+    \errhelp = \EMsimple
+    \errmessage{Unknown @codequoteundirected value `\temp', must be on|off}%
+  \fi\fi
+}
+%
+\parseargdef\codequotebacktick{%
+  \def\temp{#1}%
+  \ifx\temp\onword
+    \expandafter\let\csname SETtxicodequotebacktick\endcsname
+      = t%
+  \else\ifx\temp\offword
+    \expandafter\let\csname SETtxicodequotebacktick\endcsname
+      = \relax
+  \else
+    \errhelp = \EMsimple
+    \errmessage{Unknown @codequotebacktick value `\temp', must be on|off}%
+  \fi\fi
+}
+
+% [Knuth] pp. 380,381,391, disable Spanish ligatures ?` and !` of \tt font.
+\def\noligaturesquoteleft{\relax\lq}
+
+% Count depth in font-changes, for error checks
+\newcount\fontdepth \fontdepth=0
+
+% Font commands.
+
+% #1 is the font command (\sl or \it), #2 is the text to slant.
+% If we are in a monospaced environment, however, 1) always use \ttsl,
+% and 2) do not add an italic correction.
+\def\dosmartslant#1#2{%
+  \ifusingtt 
+    {{\ttsl #2}\let\next=\relax}%
+    {\def\next{{#1#2}\futurelet\next\smartitaliccorrection}}%
+  \next
+}
+\def\smartslanted{\dosmartslant\sl}
+\def\smartitalic{\dosmartslant\it}
+
+% Output an italic correction unless \next (presumed to be the following
+% character) is such as not to need one.
+\def\smartitaliccorrection{%
+  \ifx\next,%
+  \else\ifx\next-%
+  \else\ifx\next.%
+  \else\ptexslash
+  \fi\fi\fi
+  \aftersmartic
+}
+
+% Unconditional use \ttsl, and no ic.  @var is set to this for defuns.
+\def\ttslanted#1{{\ttsl #1}}
+
+% @cite is like \smartslanted except unconditionally use \sl.  We never want
+% ttsl for book titles, do we?
+\def\cite#1{{\sl #1}\futurelet\next\smartitaliccorrection}
+
+\def\aftersmartic{}
+\def\var#1{%
+  \let\saveaftersmartic = \aftersmartic
+  \def\aftersmartic{\null\let\aftersmartic=\saveaftersmartic}%
+  \smartslanted{#1}%
+}
+
+\let\i=\smartitalic
+\let\slanted=\smartslanted
+\let\dfn=\smartslanted
+\let\emph=\smartitalic
+
+% Explicit font changes: @r, @sc, undocumented @ii.
+\def\r#1{{\rm #1}}              % roman font
+\def\sc#1{{\smallcaps#1}}       % smallcaps font
+\def\ii#1{{\it #1}}             % italic font
+
+% @b, explicit bold.  Also @strong.
+\def\b#1{{\bf #1}}
+\let\strong=\b
+
+% @sansserif, explicit sans.
+\def\sansserif#1{{\sf #1}}
+
+% We can't just use \exhyphenpenalty, because that only has effect at
+% the end of a paragraph.  Restore normal hyphenation at the end of the
+% group within which \nohyphenation is presumably called.
+%
+\def\nohyphenation{\hyphenchar\font = -1  \aftergroup\restorehyphenation}
+\def\restorehyphenation{\hyphenchar\font = `- }
+
+% Set sfcode to normal for the chars that usually have another value.
+% Can't use plain's \frenchspacing because it uses the `\x notation, and
+% sometimes \x has an active definition that messes things up.
+%
+\catcode`@=11
+  \def\plainfrenchspacing{%
+    \sfcode\dotChar  =\@m \sfcode\questChar=\@m \sfcode\exclamChar=\@m
+    \sfcode\colonChar=\@m \sfcode\semiChar =\@m \sfcode\commaChar =\@m
+    \def\endofsentencespacefactor{1000}% for @. and friends
+  }
+  \def\plainnonfrenchspacing{%
+    \sfcode`\.3000\sfcode`\?3000\sfcode`\!3000
+    \sfcode`\:2000\sfcode`\;1500\sfcode`\,1250
+    \def\endofsentencespacefactor{3000}% for @. and friends
+  }
+\catcode`@=\other
+\def\endofsentencespacefactor{3000}% default
+
+% @t, explicit typewriter.
+\def\t#1{%
+  {\tt \rawbackslash \plainfrenchspacing #1}%
+  \null
+}
+
+% @samp.
+\def\samp#1{{\setupmarkupstyle{samp}\lq\tclose{#1}\rq\null}}
+
+% @indicateurl is \samp, that is, with quotes.
+\let\indicateurl=\samp
+
+% @code (and similar) prints in typewriter, but with spaces the same
+% size as normal in the surrounding text, without hyphenation, etc.
+% This is a subroutine for that.
+\def\tclose#1{%
+  {%
+    % Change normal interword space to be same as for the current font.
+    \spaceskip = \fontdimen2\font
+    %
+    % Switch to typewriter.
+    \tt
+    %
+    % But `\ ' produces the large typewriter interword space.
+    \def\ {{\spaceskip = 0pt{} }}%
+    %
+    % Turn off hyphenation.
+    \nohyphenation
+    %
+    \rawbackslash
+    \plainfrenchspacing
+    #1%
+  }%
+  \null % reset spacefactor to 1000
+}
+
+% We *must* turn on hyphenation at `-' and `_' in @code.
+% Otherwise, it is too hard to avoid overfull hboxes
+% in the Emacs manual, the Library manual, etc.
+%
+% Unfortunately, TeX uses one parameter (\hyphenchar) to control
+% both hyphenation at - and hyphenation within words.
+% We must therefore turn them both off (\tclose does that)
+% and arrange explicitly to hyphenate at a dash.
+%  -- rms.
+{
+  \catcode`\-=\active \catcode`\_=\active
+  \catcode`\'=\active \catcode`\`=\active
+  \global\let'=\rq \global\let`=\lq  % default definitions
+  %
+  \global\def\code{\begingroup
+    \setupmarkupstyle{code}%
+    % The following should really be moved into \setupmarkupstyle handlers.
+    \catcode\dashChar=\active  \catcode\underChar=\active
+    \ifallowcodebreaks
+     \let-\codedash
+     \let_\codeunder
+    \else
+     \let-\normaldash
+     \let_\realunder
+    \fi
+    \codex
+  }
+}
+
+\def\codex #1{\tclose{#1}\endgroup}
+
+\def\normaldash{-}
+\def\codedash{-\discretionary{}{}{}}
+\def\codeunder{%
+  % this is all so @math{@code{var_name}+1} can work.  In math mode, _
+  % is "active" (mathcode"8000) and \normalunderscore (or \char95, etc.)
+  % will therefore expand the active definition of _, which is us
+  % (inside @code that is), therefore an endless loop.
+  \ifusingtt{\ifmmode
+               \mathchar"075F % class 0=ordinary, family 7=ttfam, pos 0x5F=_.
+             \else\normalunderscore \fi
+             \discretionary{}{}{}}%
+            {\_}%
+}
+
+% An additional complication: the above will allow breaks after, e.g.,
+% each of the four underscores in __typeof__.  This is bad.
+% @allowcodebreaks provides a document-level way to turn breaking at -
+% and _ on and off.
+%
+\newif\ifallowcodebreaks  \allowcodebreakstrue
+
+\def\keywordtrue{true}
+\def\keywordfalse{false}
+
+\parseargdef\allowcodebreaks{%
+  \def\txiarg{#1}%
+  \ifx\txiarg\keywordtrue
+    \allowcodebreakstrue
+  \else\ifx\txiarg\keywordfalse
+    \allowcodebreaksfalse
+  \else
+    \errhelp = \EMsimple
+    \errmessage{Unknown @allowcodebreaks option `\txiarg', must be true|false}%
+  \fi\fi
+}
+
+% For @command, @env, @file, @option quotes seem unnecessary,
+% so use \code rather than \samp.
+\let\command=\code
+\let\env=\code
+\let\file=\code
+\let\option=\code
+
+% @uref (abbreviation for `urlref') takes an optional (comma-separated)
+% second argument specifying the text to display and an optional third
+% arg as text to display instead of (rather than in addition to) the url
+% itself.  First (mandatory) arg is the url.
+% (This \urefnobreak definition isn't used now, leaving it for a while
+% for comparison.)
+\def\urefnobreak#1{\dourefnobreak #1,,,\finish}
+\def\dourefnobreak#1,#2,#3,#4\finish{\begingroup
+  \unsepspaces
+  \pdfurl{#1}%
+  \setbox0 = \hbox{\ignorespaces #3}%
+  \ifdim\wd0 > 0pt
+    \unhbox0 % third arg given, show only that
+  \else
+    \setbox0 = \hbox{\ignorespaces #2}%
+    \ifdim\wd0 > 0pt
+      \ifpdf
+        \unhbox0             % PDF: 2nd arg given, show only it
+      \else
+        \unhbox0\ (\code{#1})% DVI: 2nd arg given, show both it and url
+      \fi
+    \else
+      \code{#1}% only url given, so show it
+    \fi
+  \fi
+  \endlink
+\endgroup}
+
+% This \urefbreak definition is the active one.
+\def\urefbreak{\begingroup \urefcatcodes \dourefbreak}
+\let\uref=\urefbreak
+\def\dourefbreak#1{\urefbreakfinish #1,,,\finish}
+\def\urefbreakfinish#1,#2,#3,#4\finish{% doesn't work in @example
+  \unsepspaces
+  \pdfurl{#1}%
+  \setbox0 = \hbox{\ignorespaces #3}%
+  \ifdim\wd0 > 0pt
+    \unhbox0 % third arg given, show only that
+  \else
+    \setbox0 = \hbox{\ignorespaces #2}%
+    \ifdim\wd0 > 0pt
+      \ifpdf
+        \unhbox0             % PDF: 2nd arg given, show only it
+      \else
+        \unhbox0\ (\urefcode{#1})% DVI: 2nd arg given, show both it and url
+      \fi
+    \else
+      \urefcode{#1}% only url given, so show it
+    \fi
+  \fi
+  \endlink
+\endgroup}
+
+% Allow line breaks around only a few characters (only).
+\def\urefcatcodes{%
+  \catcode\ampChar=\active   \catcode\dotChar=\active
+  \catcode\hashChar=\active  \catcode\questChar=\active
+  \catcode\slashChar=\active
+}
+{
+  \urefcatcodes
+  %
+  \global\def\urefcode{\begingroup
+    \setupmarkupstyle{code}%
+    \urefcatcodes
+    \let&\urefcodeamp
+    \let.\urefcodedot
+    \let#\urefcodehash
+    \let?\urefcodequest
+    \let/\urefcodeslash
+    \codex
+  }
+  %
+  % By default, they are just regular characters.
+  \global\def&{\normalamp}
+  \global\def.{\normaldot}
+  \global\def#{\normalhash}
+  \global\def?{\normalquest}
+  \global\def/{\normalslash}
+}
+
+% we put a little stretch before and after the breakable chars, to help
+% line breaking of long url's.  The unequal skips make look better in
+% cmtt at least, especially for dots.
+\def\urefprestretch{\urefprebreak \hskip0pt plus.13em }
+\def\urefpoststretch{\urefpostbreak \hskip0pt plus.1em }
+%
+\def\urefcodeamp{\urefprestretch \&\urefpoststretch}
+\def\urefcodedot{\urefprestretch .\urefpoststretch}
+\def\urefcodehash{\urefprestretch \#\urefpoststretch}
+\def\urefcodequest{\urefprestretch ?\urefpoststretch}
+\def\urefcodeslash{\futurelet\next\urefcodeslashfinish}
+{
+  \catcode`\/=\active
+  \global\def\urefcodeslashfinish{%
+    \urefprestretch \slashChar
+    % Allow line break only after the final / in a sequence of
+    % slashes, to avoid line break between the slashes in http://.
+    \ifx\next/\else \urefpoststretch \fi
+  }
+}
+
+% One more complication: by default we'll break after the special
+% characters, but some people like to break before the special chars, so
+% allow that.  Also allow no breaking at all, for manual control.
+% 
+\parseargdef\urefbreakstyle{%
+  \def\txiarg{#1}%
+  \ifx\txiarg\wordnone
+    \def\urefprebreak{\nobreak}\def\urefpostbreak{\nobreak}
+  \else\ifx\txiarg\wordbefore
+    \def\urefprebreak{\allowbreak}\def\urefpostbreak{\nobreak}
+  \else\ifx\txiarg\wordafter
+    \def\urefprebreak{\nobreak}\def\urefpostbreak{\allowbreak}
+  \else
+    \errhelp = \EMsimple
+    \errmessage{Unknown @urefbreakstyle setting `\txiarg'}%
+  \fi\fi\fi
+}
+\def\wordafter{after}
+\def\wordbefore{before}
+\def\wordnone{none}
+
+\urefbreakstyle after
+
+% @url synonym for @uref, since that's how everyone uses it.
+%
+\let\url=\uref
+
+% rms does not like angle brackets --karl, 17may97.
+% So now @email is just like @uref, unless we are pdf.
+%
+%\def\email#1{\angleleft{\tt #1}\angleright}
+\ifpdf
+  \def\email#1{\doemail#1,,\finish}
+  \def\doemail#1,#2,#3\finish{\begingroup
+    \unsepspaces
+    \pdfurl{mailto:#1}%
+    \setbox0 = \hbox{\ignorespaces #2}%
+    \ifdim\wd0>0pt\unhbox0\else\code{#1}\fi
+    \endlink
+  \endgroup}
+\else
+  \let\email=\uref
+\fi
+
+% @kbdinputstyle -- arg is `distinct' (@kbd uses slanted tty font always),
+%   `example' (@kbd uses ttsl only inside of @example and friends),
+%   or `code' (@kbd uses normal tty font always).
+\parseargdef\kbdinputstyle{%
+  \def\txiarg{#1}%
+  \ifx\txiarg\worddistinct
+    \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\ttsl}%
+  \else\ifx\txiarg\wordexample
+    \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\tt}%
+  \else\ifx\txiarg\wordcode
+    \gdef\kbdexamplefont{\tt}\gdef\kbdfont{\tt}%
+  \else
+    \errhelp = \EMsimple
+    \errmessage{Unknown @kbdinputstyle setting `\txiarg'}%
+  \fi\fi\fi
+}
+\def\worddistinct{distinct}
+\def\wordexample{example}
+\def\wordcode{code}
+
+% Default is `distinct'.
+\kbdinputstyle distinct
+
+% @kbd is like @code, except that if the argument is just one @key command,
+% then @kbd has no effect.
+\def\kbd#1{{\def\look{#1}\expandafter\kbdsub\look??\par}}
+
+\def\xkey{\key}
+\def\kbdsub#1#2#3\par{%
+  \def\one{#1}\def\three{#3}\def\threex{??}%
+  \ifx\one\xkey\ifx\threex\three \key{#2}%
+  \else{\tclose{\kbdfont\setupmarkupstyle{kbd}\look}}\fi
+  \else{\tclose{\kbdfont\setupmarkupstyle{kbd}\look}}\fi
+}
+
+% definition of @key that produces a lozenge.  Doesn't adjust to text size.
+%\setfont\keyrm\rmshape{8}{1000}{OT1}
+%\font\keysy=cmsy9
+%\def\key#1{{\keyrm\textfont2=\keysy \leavevmode\hbox{%
+%  \raise0.4pt\hbox{\angleleft}\kern-.08em\vtop{%
+%    \vbox{\hrule\kern-0.4pt
+%     \hbox{\raise0.4pt\hbox{\vphantom{\angleleft}}#1}}%
+%    \kern-0.4pt\hrule}%
+%  \kern-.06em\raise0.4pt\hbox{\angleright}}}}
+
+% definition of @key with no lozenge.  If the current font is already
+% monospace, don't change it; that way, we respect @kbdinputstyle.  But
+% if it isn't monospace, then use \tt.
+%
+\def\key#1{{\setupmarkupstyle{key}%
+  \nohyphenation
+  \ifmonospace\else\tt\fi
+  #1}\null}
+
+% @clicksequence{File @click{} Open ...}
+\def\clicksequence#1{\begingroup #1\endgroup}
+
+% @clickstyle @arrow   (by default)
+\parseargdef\clickstyle{\def\click{#1}}
+\def\click{\arrow}
+
+% Typeset a dimension, e.g., `in' or `pt'.  The only reason for the
+% argument is to make the input look right: @dmn{pt} instead of @dmn{}pt.
+%
+\def\dmn#1{\thinspace #1}
+
+% @l was never documented to mean ``switch to the Lisp font'',
+% and it is not used as such in any manual I can find.  We need it for
+% Polish suppressed-l.  --karl, 22sep96.
+%\def\l#1{{\li #1}\null}
+
+% @acronym for "FBI", "NATO", and the like.
+% We print this one point size smaller, since it's intended for
+% all-uppercase.
+%
+\def\acronym#1{\doacronym #1,,\finish}
+\def\doacronym#1,#2,#3\finish{%
+  {\selectfonts\lsize #1}%
+  \def\temp{#2}%
+  \ifx\temp\empty \else
+    \space ({\unsepspaces \ignorespaces \temp \unskip})%
+  \fi
+  \null % reset \spacefactor=1000
+}
+
+% @abbr for "Comput. J." and the like.
+% No font change, but don't do end-of-sentence spacing.
+%
+\def\abbr#1{\doabbr #1,,\finish}
+\def\doabbr#1,#2,#3\finish{%
+  {\plainfrenchspacing #1}%
+  \def\temp{#2}%
+  \ifx\temp\empty \else
+    \space ({\unsepspaces \ignorespaces \temp \unskip})%
+  \fi
+  \null % reset \spacefactor=1000
+}
+
+% @asis just yields its argument.  Used with @table, for example.
+%
+\def\asis#1{#1}
+
+% @math outputs its argument in math mode.
+%
+% One complication: _ usually means subscripts, but it could also mean
+% an actual _ character, as in @math{@var{some_variable} + 1}.  So make
+% _ active, and distinguish by seeing if the current family is \slfam,
+% which is what @var uses.
+{
+  \catcode`\_ = \active
+  \gdef\mathunderscore{%
+    \catcode`\_=\active
+    \def_{\ifnum\fam=\slfam \_\else\sb\fi}%
+  }
+}
+% Another complication: we want \\ (and @\) to output a math (or tt) \.
+% FYI, plain.tex uses \\ as a temporary control sequence (for no
+% particular reason), but this is not advertised and we don't care.
+%
+% The \mathchar is class=0=ordinary, family=7=ttfam, position=5C=\.
+\def\mathbackslash{\ifnum\fam=\ttfam \mathchar"075C \else\backslash \fi}
+%
+\def\math{%
+  \tex
+  \mathunderscore
+  \let\\ = \mathbackslash
+  \mathactive
+  % make the texinfo accent commands work in math mode
+  \let\"=\ddot
+  \let\'=\acute
+  \let\==\bar
+  \let\^=\hat
+  \let\`=\grave
+  \let\u=\breve
+  \let\v=\check
+  \let\~=\tilde
+  \let\dotaccent=\dot
+  $\finishmath
+}
+\def\finishmath#1{#1$\endgroup}  % Close the group opened by \tex.
+
+% Some active characters (such as <) are spaced differently in math.
+% We have to reset their definitions in case the @math was an argument
+% to a command which sets the catcodes (such as @item or @section).
+%
+{
+  \catcode`^ = \active
+  \catcode`< = \active
+  \catcode`> = \active
+  \catcode`+ = \active
+  \catcode`' = \active
+  \gdef\mathactive{%
+    \let^ = \ptexhat
+    \let< = \ptexless
+    \let> = \ptexgtr
+    \let+ = \ptexplus
+    \let' = \ptexquoteright
+  }
+}
+
+% ctrl is no longer a Texinfo command, but leave this definition for fun.
+\def\ctrl #1{{\tt \rawbackslash \hat}#1}
+
+% @inlinefmt{FMTNAME,PROCESSED-TEXT} and @inlineraw{FMTNAME,RAW-TEXT}.
+% Ignore unless FMTNAME == tex; then it is like @iftex and @tex,
+% except specified as a normal braced arg, so no newlines to worry about.
+% 
+\def\outfmtnametex{tex}
+%
+\long\def\inlinefmt#1{\doinlinefmt #1,\finish}
+\long\def\doinlinefmt#1,#2,\finish{%
+  \def\inlinefmtname{#1}%
+  \ifx\inlinefmtname\outfmtnametex \ignorespaces #2\fi
+}
+% For raw, must switch into @tex before parsing the argument, to avoid
+% setting catcodes prematurely.  Doing it this way means that, for
+% example, @inlineraw{html, foo{bar} gets a parse error instead of being
+% ignored.  But this isn't important because if people want a literal
+% *right* brace they would have to use a command anyway, so they may as
+% well use a command to get a left brace too.  We could re-use the
+% delimiter character idea from \verb, but it seems like overkill.
+% 
+\long\def\inlineraw{\tex \doinlineraw}
+\long\def\doinlineraw#1{\doinlinerawtwo #1,\finish}
+\def\doinlinerawtwo#1,#2,\finish{%
+  \def\inlinerawname{#1}%
+  \ifx\inlinerawname\outfmtnametex \ignorespaces #2\fi
+  \endgroup % close group opened by \tex.
+}
+
+
+\message{glyphs,}
+% and logos.
+
+% @@ prints an @, as does @atchar{}.
+\def\@{\char64 }
+\let\atchar=\@
+
+% @{ @} @lbracechar{} @rbracechar{} all generate brace characters.
+% Unless we're in typewriter, use \ecfont because the CM text fonts do
+% not have braces, and we don't want to switch into math.
+\def\mylbrace{{\ifmonospace\else\ecfont\fi \char123}}
+\def\myrbrace{{\ifmonospace\else\ecfont\fi \char125}}
+\let\{=\mylbrace \let\lbracechar=\{
+\let\}=\myrbrace \let\rbracechar=\}
+\begingroup
+  % Definitions to produce \{ and \} commands for indices,
+  % and @{ and @} for the aux/toc files.
+  \catcode`\{ = \other \catcode`\} = \other
+  \catcode`\[ = 1 \catcode`\] = 2
+  \catcode`\! = 0 \catcode`\\ = \other
+  !gdef!lbracecmd[\{]%
+  !gdef!rbracecmd[\}]%
+  !gdef!lbraceatcmd[@{]%
+  !gdef!rbraceatcmd[@}]%
+!endgroup
+
+% @comma{} to avoid , parsing problems.
+\let\comma = ,
+
+% Accents: @, @dotaccent @ringaccent @ubaraccent @udotaccent
+% Others are defined by plain TeX: @` @' @" @^ @~ @= @u @v @H.
+\let\, = \ptexc
+\let\dotaccent = \ptexdot
+\def\ringaccent#1{{\accent23 #1}}
+\let\tieaccent = \ptext
+\let\ubaraccent = \ptexb
+\let\udotaccent = \d
+
+% Other special characters: @questiondown @exclamdown @ordf @ordm
+% Plain TeX defines: @AA @AE @O @OE @L (plus lowercase versions) @ss.
+\def\questiondown{?`}
+\def\exclamdown{!`}
+\def\ordf{\leavevmode\raise1ex\hbox{\selectfonts\lllsize \underbar{a}}}
+\def\ordm{\leavevmode\raise1ex\hbox{\selectfonts\lllsize \underbar{o}}}
+
+% Dotless i and dotless j, used for accents.
+\def\imacro{i}
+\def\jmacro{j}
+\def\dotless#1{%
+  \def\temp{#1}%
+  \ifx\temp\imacro \ifmmode\imath \else\ptexi \fi
+  \else\ifx\temp\jmacro \ifmmode\jmath \else\j \fi
+  \else \errmessage{@dotless can be used only with i or j}%
+  \fi\fi
+}
+
+% The \TeX{} logo, as in plain, but resetting the spacing so that a
+% period following counts as ending a sentence.  (Idea found in latex.)
+%
+\edef\TeX{\TeX \spacefactor=1000 }
+
+% @LaTeX{} logo.  Not quite the same results as the definition in
+% latex.ltx, since we use a different font for the raised A; it's most
+% convenient for us to use an explicitly smaller font, rather than using
+% the \scriptstyle font (since we don't reset \scriptstyle and
+% \scriptscriptstyle).
+%
+\def\LaTeX{%
+  L\kern-.36em
+  {\setbox0=\hbox{T}%
+   \vbox to \ht0{\hbox{%
+     \ifx\textnominalsize\xwordpt
+       % for 10pt running text, \lllsize (8pt) is too small for the A in LaTeX.
+       % Revert to plain's \scriptsize, which is 7pt.
+       \count255=\the\fam $\fam\count255 \scriptstyle A$%
+     \else
+       % For 11pt, we can use our lllsize.
+       \selectfonts\lllsize A%
+     \fi
+     }%
+     \vss
+  }}%
+  \kern-.15em
+  \TeX
+}
+
+% Some math mode symbols.
+\def\bullet{$\ptexbullet$}
+\def\geq{\ifmmode \ge\else $\ge$\fi}
+\def\leq{\ifmmode \le\else $\le$\fi}
+\def\minus{\ifmmode -\else $-$\fi}
+
+% @dots{} outputs an ellipsis using the current font.
+% We do .5em per period so that it has the same spacing in the cm
+% typewriter fonts as three actual period characters; on the other hand,
+% in other typewriter fonts three periods are wider than 1.5em.  So do
+% whichever is larger.
+%
+\def\dots{%
+  \leavevmode
+  \setbox0=\hbox{...}% get width of three periods
+  \ifdim\wd0 > 1.5em
+    \dimen0 = \wd0
+  \else
+    \dimen0 = 1.5em
+  \fi
+  \hbox to \dimen0{%
+    \hskip 0pt plus.25fil
+    .\hskip 0pt plus1fil
+    .\hskip 0pt plus1fil
+    .\hskip 0pt plus.5fil
+  }%
+}
+
+% @enddots{} is an end-of-sentence ellipsis.
+%
+\def\enddots{%
+  \dots
+  \spacefactor=\endofsentencespacefactor
+}
+
+% @point{}, @result{}, @expansion{}, @print{}, @equiv{}.
+%
+% Since these characters are used in examples, they should be an even number of
+% \tt widths. Each \tt character is 1en, so two makes it 1em.
+%
+\def\point{$\star$}
+\def\arrow{\leavevmode\raise.05ex\hbox to 1em{\hfil$\rightarrow$\hfil}}
+\def\result{\leavevmode\raise.05ex\hbox to 1em{\hfil$\Rightarrow$\hfil}}
+\def\expansion{\leavevmode\hbox to 1em{\hfil$\mapsto$\hfil}}
+\def\print{\leavevmode\lower.1ex\hbox to 1em{\hfil$\dashv$\hfil}}
+\def\equiv{\leavevmode\hbox to 1em{\hfil$\ptexequiv$\hfil}}
+
+% The @error{} command.
+% Adapted from the TeXbook's \boxit.
+%
+\newbox\errorbox
+%
+{\tentt \global\dimen0 = 3em}% Width of the box.
+\dimen2 = .55pt % Thickness of rules
+% The text. (`r' is open on the right, `e' somewhat less so on the left.)
+\setbox0 = \hbox{\kern-.75pt \reducedsf \putworderror\kern-1.5pt}
+%
+\setbox\errorbox=\hbox to \dimen0{\hfil
+   \hsize = \dimen0 \advance\hsize by -5.8pt % Space to left+right.
+   \advance\hsize by -2\dimen2 % Rules.
+   \vbox{%
+      \hrule height\dimen2
+      \hbox{\vrule width\dimen2 \kern3pt          % Space to left of text.
+         \vtop{\kern2.4pt \box0 \kern2.4pt}% Space above/below.
+         \kern3pt\vrule width\dimen2}% Space to right.
+      \hrule height\dimen2}
+    \hfil}
+%
+\def\error{\leavevmode\lower.7ex\copy\errorbox}
+
+% @pounds{} is a sterling sign, which Knuth put in the CM italic font.
+%
+\def\pounds{{\it\$}}
+
+% @euro{} comes from a separate font, depending on the current style.
+% We use the free feym* fonts from the eurosym package by Henrik
+% Theiling, which support regular, slanted, bold and bold slanted (and
+% "outlined" (blackboard board, sort of) versions, which we don't need).
+% It is available from http://www.ctan.org/tex-archive/fonts/eurosym.
+%
+% Although only regular is the truly official Euro symbol, we ignore
+% that.  The Euro is designed to be slightly taller than the regular
+% font height.
+%
+% feymr - regular
+% feymo - slanted
+% feybr - bold
+% feybo - bold slanted
+%
+% There is no good (free) typewriter version, to my knowledge.
+% A feymr10 euro is ~7.3pt wide, while a normal cmtt10 char is ~5.25pt wide.
+% Hmm.
+%
+% Also doesn't work in math.  Do we need to do math with euro symbols?
+% Hope not.
+%
+%
+\def\euro{{\eurofont e}}
+\def\eurofont{%
+  % We set the font at each command, rather than predefining it in
+  % \textfonts and the other font-switching commands, so that
+  % installations which never need the symbol don't have to have the
+  % font installed.
+  %
+  % There is only one designed size (nominal 10pt), so we always scale
+  % that to the current nominal size.
+  %
+  % By the way, simply using "at 1em" works for cmr10 and the like, but
+  % does not work for cmbx10 and other extended/shrunken fonts.
+  %
+  \def\eurosize{\csname\curfontsize nominalsize\endcsname}%
+  %
+  \ifx\curfontstyle\bfstylename
+    % bold:
+    \font\thiseurofont = \ifusingit{feybo10}{feybr10} at \eurosize
+  \else
+    % regular:
+    \font\thiseurofont = \ifusingit{feymo10}{feymr10} at \eurosize
+  \fi
+  \thiseurofont
+}
+
+% Glyphs from the EC fonts.  We don't use \let for the aliases, because
+% sometimes we redefine the original macro, and the alias should reflect
+% the redefinition.
+%
+% Use LaTeX names for the Icelandic letters.
+\def\DH{{\ecfont \char"D0}} % Eth
+\def\dh{{\ecfont \char"F0}} % eth
+\def\TH{{\ecfont \char"DE}} % Thorn
+\def\th{{\ecfont \char"FE}} % thorn
+%
+\def\guillemetleft{{\ecfont \char"13}}
+\def\guillemotleft{\guillemetleft}
+\def\guillemetright{{\ecfont \char"14}}
+\def\guillemotright{\guillemetright}
+\def\guilsinglleft{{\ecfont \char"0E}}
+\def\guilsinglright{{\ecfont \char"0F}}
+\def\quotedblbase{{\ecfont \char"12}}
+\def\quotesinglbase{{\ecfont \char"0D}}
+%
+% This positioning is not perfect (see the ogonek LaTeX package), but
+% we have the precomposed glyphs for the most common cases.  We put the
+% tests to use those glyphs in the single \ogonek macro so we have fewer
+% dummy definitions to worry about for index entries, etc.
+%
+% ogonek is also used with other letters in Lithuanian (IOU), but using
+% the precomposed glyphs for those is not so easy since they aren't in
+% the same EC font.
+\def\ogonek#1{{%
+  \def\temp{#1}%
+  \ifx\temp\macrocharA\Aogonek
+  \else\ifx\temp\macrochara\aogonek
+  \else\ifx\temp\macrocharE\Eogonek
+  \else\ifx\temp\macrochare\eogonek
+  \else
+    \ecfont \setbox0=\hbox{#1}%
+    \ifdim\ht0=1ex\accent"0C #1%
+    \else\ooalign{\unhbox0\crcr\hidewidth\char"0C \hidewidth}%
+    \fi
+  \fi\fi\fi\fi
+  }%
+}
+\def\Aogonek{{\ecfont \char"81}}\def\macrocharA{A}
+\def\aogonek{{\ecfont \char"A1}}\def\macrochara{a}
+\def\Eogonek{{\ecfont \char"86}}\def\macrocharE{E}
+\def\eogonek{{\ecfont \char"A6}}\def\macrochare{e}
+%
+% Use the ec* fonts (cm-super in outline format) for non-CM glyphs.
+\def\ecfont{%
+  % We can't distinguish serif/sans and italic/slanted, but this
+  % is used for crude hacks anyway (like adding French and German
+  % quotes to documents typeset with CM, where we lose kerning), so
+  % hopefully nobody will notice/care.
+  \edef\ecsize{\csname\curfontsize ecsize\endcsname}%
+  \edef\nominalsize{\csname\curfontsize nominalsize\endcsname}%
+  \ifmonospace
+    % typewriter:
+    \font\thisecfont = ectt\ecsize \space at \nominalsize
+  \else
+    \ifx\curfontstyle\bfstylename
+      % bold:
+      \font\thisecfont = ecb\ifusingit{i}{x}\ecsize \space at \nominalsize
+    \else
+      % regular:
+      \font\thisecfont = ec\ifusingit{ti}{rm}\ecsize \space at \nominalsize
+    \fi
+  \fi
+  \thisecfont
+}
+
+% @registeredsymbol - R in a circle.  The font for the R should really
+% be smaller yet, but lllsize is the best we can do for now.
+% Adapted from the plain.tex definition of \copyright.
+%
+\def\registeredsymbol{%
+  $^{{\ooalign{\hfil\raise.07ex\hbox{\selectfonts\lllsize R}%
+               \hfil\crcr\Orb}}%
+    }$%
+}
+
+% @textdegree - the normal degrees sign.
+%
+\def\textdegree{$^\circ$}
+
+% Laurent Siebenmann reports \Orb undefined with:
+%  Textures 1.7.7 (preloaded format=plain 93.10.14)  (68K)  16 APR 2004 02:38
+% so we'll define it if necessary.
+%
+\ifx\Orb\thisisundefined
+\def\Orb{\mathhexbox20D}
+\fi
+
+% Quotes.
+\chardef\quotedblleft="5C
+\chardef\quotedblright=`\"
+\chardef\quoteleft=`\`
+\chardef\quoteright=`\'
+
+
+\message{page headings,}
+
+\newskip\titlepagetopglue \titlepagetopglue = 1.5in
+\newskip\titlepagebottomglue \titlepagebottomglue = 2pc
+
+% First the title page.  Must do @settitle before @titlepage.
+\newif\ifseenauthor
+\newif\iffinishedtitlepage
+
+% Do an implicit @contents or @shortcontents after @end titlepage if the
+% user says @setcontentsaftertitlepage or @setshortcontentsaftertitlepage.
+%
+\newif\ifsetcontentsaftertitlepage
+ \let\setcontentsaftertitlepage = \setcontentsaftertitlepagetrue
+\newif\ifsetshortcontentsaftertitlepage
+ \let\setshortcontentsaftertitlepage = \setshortcontentsaftertitlepagetrue
+
+\parseargdef\shorttitlepage{%
+  \begingroup \hbox{}\vskip 1.5in \chaprm \centerline{#1}%
+  \endgroup\page\hbox{}\page}
+
+\envdef\titlepage{%
+  % Open one extra group, as we want to close it in the middle of \Etitlepage.
+  \begingroup
+    \parindent=0pt \textfonts
+    % Leave some space at the very top of the page.
+    \vglue\titlepagetopglue
+    % No rule at page bottom unless we print one at the top with @title.
+    \finishedtitlepagetrue
+    %
+    % Most title ``pages'' are actually two pages long, with space
+    % at the top of the second.  We don't want the ragged left on the second.
+    \let\oldpage = \page
+    \def\page{%
+      \iffinishedtitlepage\else
+	 \finishtitlepage
+      \fi
+      \let\page = \oldpage
+      \page
+      \null
+    }%
+}
+
+\def\Etitlepage{%
+    \iffinishedtitlepage\else
+	\finishtitlepage
+    \fi
+    % It is important to do the page break before ending the group,
+    % because the headline and footline are only empty inside the group.
+    % If we use the new definition of \page, we always get a blank page
+    % after the title page, which we certainly don't want.
+    \oldpage
+  \endgroup
+  %
+  % Need this before the \...aftertitlepage checks so that if they are
+  % in effect the toc pages will come out with page numbers.
+  \HEADINGSon
+  %
+  % If they want short, they certainly want long too.
+  \ifsetshortcontentsaftertitlepage
+    \shortcontents
+    \contents
+    \global\let\shortcontents = \relax
+    \global\let\contents = \relax
+  \fi
+  %
+  \ifsetcontentsaftertitlepage
+    \contents
+    \global\let\contents = \relax
+    \global\let\shortcontents = \relax
+  \fi
+}
+
+\def\finishtitlepage{%
+  \vskip4pt \hrule height 2pt width \hsize
+  \vskip\titlepagebottomglue
+  \finishedtitlepagetrue
+}
+
+% Settings used for typesetting titles: no hyphenation, no indentation,
+% don't worry much about spacing, ragged right.  This should be used
+% inside a \vbox, and fonts need to be set appropriately first.  Because
+% it is always used for titles, nothing else, we call \rmisbold.  \par
+% should be specified before the end of the \vbox, since a vbox is a group.
+% 
+\def\raggedtitlesettings{%
+  \rmisbold
+  \hyphenpenalty=10000
+  \parindent=0pt
+  \tolerance=5000
+  \ptexraggedright
+}
+
+% Macros to be used within @titlepage:
+
+\let\subtitlerm=\tenrm
+\def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines}
+
+\parseargdef\title{%
+  \checkenv\titlepage
+  \vbox{\titlefonts \raggedtitlesettings #1\par}%
+  % print a rule at the page bottom also.
+  \finishedtitlepagefalse
+  \vskip4pt \hrule height 4pt width \hsize \vskip4pt
+}
+
+\parseargdef\subtitle{%
+  \checkenv\titlepage
+  {\subtitlefont \rightline{#1}}%
+}
+
+% @author should come last, but may come many times.
+% It can also be used inside @quotation.
+%
+\parseargdef\author{%
+  \def\temp{\quotation}%
+  \ifx\thisenv\temp
+    \def\quotationauthor{#1}% printed in \Equotation.
+  \else
+    \checkenv\titlepage
+    \ifseenauthor\else \vskip 0pt plus 1filll \seenauthortrue \fi
+    {\secfonts\rmisbold \leftline{#1}}%
+  \fi
+}
+
+
+% Set up page headings and footings.
+
+\let\thispage=\folio
+
+\newtoks\evenheadline    % headline on even pages
+\newtoks\oddheadline     % headline on odd pages
+\newtoks\evenfootline    % footline on even pages
+\newtoks\oddfootline     % footline on odd pages
+
+% Now make TeX use those variables
+\headline={{\textfonts\rm \ifodd\pageno \the\oddheadline
+                            \else \the\evenheadline \fi}}
+\footline={{\textfonts\rm \ifodd\pageno \the\oddfootline
+                            \else \the\evenfootline \fi}\HEADINGShook}
+\let\HEADINGShook=\relax
+
+% Commands to set those variables.
+% For example, this is what  @headings on  does
+% @evenheading @thistitle|@thispage|@thischapter
+% @oddheading @thischapter|@thispage|@thistitle
+% @evenfooting @thisfile||
+% @oddfooting ||@thisfile
+
+
+\def\evenheading{\parsearg\evenheadingxxx}
+\def\evenheadingxxx #1{\evenheadingyyy #1\|\|\|\|\finish}
+\def\evenheadingyyy #1\|#2\|#3\|#4\finish{%
+\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\def\oddheading{\parsearg\oddheadingxxx}
+\def\oddheadingxxx #1{\oddheadingyyy #1\|\|\|\|\finish}
+\def\oddheadingyyy #1\|#2\|#3\|#4\finish{%
+\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\parseargdef\everyheading{\oddheadingxxx{#1}\evenheadingxxx{#1}}%
+
+\def\evenfooting{\parsearg\evenfootingxxx}
+\def\evenfootingxxx #1{\evenfootingyyy #1\|\|\|\|\finish}
+\def\evenfootingyyy #1\|#2\|#3\|#4\finish{%
+\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\def\oddfooting{\parsearg\oddfootingxxx}
+\def\oddfootingxxx #1{\oddfootingyyy #1\|\|\|\|\finish}
+\def\oddfootingyyy #1\|#2\|#3\|#4\finish{%
+  \global\oddfootline = {\rlap{\centerline{#2}}\line{#1\hfil#3}}%
+  %
+  % Leave some space for the footline.  Hopefully ok to assume
+  % @evenfooting will not be used by itself.
+  \global\advance\pageheight by -12pt
+  \global\advance\vsize by -12pt
+}
+
+\parseargdef\everyfooting{\oddfootingxxx{#1}\evenfootingxxx{#1}}
+
+% @evenheadingmarks top     \thischapter <- chapter at the top of a page
+% @evenheadingmarks bottom  \thischapter <- chapter at the bottom of a page
+%
+% The same set of arguments for:
+%
+% @oddheadingmarks
+% @evenfootingmarks
+% @oddfootingmarks
+% @everyheadingmarks
+% @everyfootingmarks
+
+\def\evenheadingmarks{\headingmarks{even}{heading}}
+\def\oddheadingmarks{\headingmarks{odd}{heading}}
+\def\evenfootingmarks{\headingmarks{even}{footing}}
+\def\oddfootingmarks{\headingmarks{odd}{footing}}
+\def\everyheadingmarks#1 {\headingmarks{even}{heading}{#1}
+                          \headingmarks{odd}{heading}{#1} }
+\def\everyfootingmarks#1 {\headingmarks{even}{footing}{#1}
+                          \headingmarks{odd}{footing}{#1} }
+% #1 = even/odd, #2 = heading/footing, #3 = top/bottom.
+\def\headingmarks#1#2#3 {%
+  \expandafter\let\expandafter\temp \csname get#3headingmarks\endcsname
+  \global\expandafter\let\csname get#1#2marks\endcsname \temp
+}
+
+\everyheadingmarks bottom
+\everyfootingmarks bottom
+
+% @headings double      turns headings on for double-sided printing.
+% @headings single      turns headings on for single-sided printing.
+% @headings off         turns them off.
+% @headings on          same as @headings double, retained for compatibility.
+% @headings after       turns on double-sided headings after this page.
+% @headings doubleafter turns on double-sided headings after this page.
+% @headings singleafter turns on single-sided headings after this page.
+% By default, they are off at the start of a document,
+% and turned `on' after @end titlepage.
+
+\def\headings #1 {\csname HEADINGS#1\endcsname}
+
+\def\headingsoff{% non-global headings elimination
+  \evenheadline={\hfil}\evenfootline={\hfil}%
+   \oddheadline={\hfil}\oddfootline={\hfil}%
+}
+
+\def\HEADINGSoff{{\globaldefs=1 \headingsoff}} % global setting
+\HEADINGSoff  % it's the default
+
+% When we turn headings on, set the page number to 1.
+% For double-sided printing, put current file name in lower left corner,
+% chapter name on inside top of right hand pages, document
+% title on inside top of left hand pages, and page numbers on outside top
+% edge of all pages.
+\def\HEADINGSdouble{%
+\global\pageno=1
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\folio\hfil\thistitle}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+\global\let\contentsalignmacro = \chapoddpage
+}
+\let\contentsalignmacro = \chappager
+
+% For single-sided printing, chapter title goes across top left of page,
+% page number on top right.
+\def\HEADINGSsingle{%
+\global\pageno=1
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\thischapter\hfil\folio}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+\global\let\contentsalignmacro = \chappager
+}
+\def\HEADINGSon{\HEADINGSdouble}
+
+\def\HEADINGSafter{\let\HEADINGShook=\HEADINGSdoublex}
+\let\HEADINGSdoubleafter=\HEADINGSafter
+\def\HEADINGSdoublex{%
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\folio\hfil\thistitle}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+\global\let\contentsalignmacro = \chapoddpage
+}
+
+\def\HEADINGSsingleafter{\let\HEADINGShook=\HEADINGSsinglex}
+\def\HEADINGSsinglex{%
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\thischapter\hfil\folio}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+\global\let\contentsalignmacro = \chappager
+}
+
+% Subroutines used in generating headings
+% This produces Day Month Year style of output.
+% Only define if not already defined, in case a txi-??.tex file has set
+% up a different format (e.g., txi-cs.tex does this).
+\ifx\today\thisisundefined
+\def\today{%
+  \number\day\space
+  \ifcase\month
+  \or\putwordMJan\or\putwordMFeb\or\putwordMMar\or\putwordMApr
+  \or\putwordMMay\or\putwordMJun\or\putwordMJul\or\putwordMAug
+  \or\putwordMSep\or\putwordMOct\or\putwordMNov\or\putwordMDec
+  \fi
+  \space\number\year}
+\fi
+
+% @settitle line...  specifies the title of the document, for headings.
+% It generates no output of its own.
+\def\thistitle{\putwordNoTitle}
+\def\settitle{\parsearg{\gdef\thistitle}}
+
+
+\message{tables,}
+% Tables -- @table, @ftable, @vtable, @item(x).
+
+% default indentation of table text
+\newdimen\tableindent \tableindent=.8in
+% default indentation of @itemize and @enumerate text
+\newdimen\itemindent  \itemindent=.3in
+% margin between end of table item and start of table text.
+\newdimen\itemmargin  \itemmargin=.1in
+
+% used internally for \itemindent minus \itemmargin
+\newdimen\itemmax
+
+% Note @table, @ftable, and @vtable define @item, @itemx, etc., with
+% these defs.
+% They also define \itemindex
+% to index the item name in whatever manner is desired (perhaps none).
+
+\newif\ifitemxneedsnegativevskip
+
+\def\itemxpar{\par\ifitemxneedsnegativevskip\nobreak\vskip-\parskip\nobreak\fi}
+
+\def\internalBitem{\smallbreak \parsearg\itemzzz}
+\def\internalBitemx{\itemxpar \parsearg\itemzzz}
+
+\def\itemzzz #1{\begingroup %
+  \advance\hsize by -\rightskip
+  \advance\hsize by -\tableindent
+  \setbox0=\hbox{\itemindicate{#1}}%
+  \itemindex{#1}%
+  \nobreak % This prevents a break before @itemx.
+  %
+  % If the item text does not fit in the space we have, put it on a line
+  % by itself, and do not allow a page break either before or after that
+  % line.  We do not start a paragraph here because then if the next
+  % command is, e.g., @kindex, the whatsit would get put into the
+  % horizontal list on a line by itself, resulting in extra blank space.
+  \ifdim \wd0>\itemmax
+    %
+    % Make this a paragraph so we get the \parskip glue and wrapping,
+    % but leave it ragged-right.
+    \begingroup
+      \advance\leftskip by-\tableindent
+      \advance\hsize by\tableindent
+      \advance\rightskip by0pt plus1fil\relax
+      \leavevmode\unhbox0\par
+    \endgroup
+    %
+    % We're going to be starting a paragraph, but we don't want the
+    % \parskip glue -- logically it's part of the @item we just started.
+    \nobreak \vskip-\parskip
+    %
+    % Stop a page break at the \parskip glue coming up.  However, if
+    % what follows is an environment such as @example, there will be no
+    % \parskip glue; then the negative vskip we just inserted would
+    % cause the example and the item to crash together.  So we use this
+    % bizarre value of 10001 as a signal to \aboveenvbreak to insert
+    % \parskip glue after all.  Section titles are handled this way also.
+    %
+    \penalty 10001
+    \endgroup
+    \itemxneedsnegativevskipfalse
+  \else
+    % The item text fits into the space.  Start a paragraph, so that the
+    % following text (if any) will end up on the same line.
+    \noindent
+    % Do this with kerns and \unhbox so that if there is a footnote in
+    % the item text, it can migrate to the main vertical list and
+    % eventually be printed.
+    \nobreak\kern-\tableindent
+    \dimen0 = \itemmax  \advance\dimen0 by \itemmargin \advance\dimen0 by -\wd0
+    \unhbox0
+    \nobreak\kern\dimen0
+    \endgroup
+    \itemxneedsnegativevskiptrue
+  \fi
+}
+
+\def\item{\errmessage{@item while not in a list environment}}
+\def\itemx{\errmessage{@itemx while not in a list environment}}
+
+% @table, @ftable, @vtable.
+\envdef\table{%
+  \let\itemindex\gobble
+  \tablecheck{table}%
+}
+\envdef\ftable{%
+  \def\itemindex ##1{\doind {fn}{\code{##1}}}%
+  \tablecheck{ftable}%
+}
+\envdef\vtable{%
+  \def\itemindex ##1{\doind {vr}{\code{##1}}}%
+  \tablecheck{vtable}%
+}
+\def\tablecheck#1{%
+  \ifnum \the\catcode`\^^M=\active
+    \endgroup
+    \errmessage{This command won't work in this context; perhaps the problem is
+      that we are \inenvironment\thisenv}%
+    \def\next{\doignore{#1}}%
+  \else
+    \let\next\tablex
+  \fi
+  \next
+}
+\def\tablex#1{%
+  \def\itemindicate{#1}%
+  \parsearg\tabley
+}
+\def\tabley#1{%
+  {%
+    \makevalueexpandable
+    \edef\temp{\noexpand\tablez #1\space\space\space}%
+    \expandafter
+  }\temp \endtablez
+}
+\def\tablez #1 #2 #3 #4\endtablez{%
+  \aboveenvbreak
+  \ifnum 0#1>0 \advance \leftskip by #1\mil \fi
+  \ifnum 0#2>0 \tableindent=#2\mil \fi
+  \ifnum 0#3>0 \advance \rightskip by #3\mil \fi
+  \itemmax=\tableindent
+  \advance \itemmax by -\itemmargin
+  \advance \leftskip by \tableindent
+  \exdentamount=\tableindent
+  \parindent = 0pt
+  \parskip = \smallskipamount
+  \ifdim \parskip=0pt \parskip=2pt \fi
+  \let\item = \internalBitem
+  \let\itemx = \internalBitemx
+}
+\def\Etable{\endgraf\afterenvbreak}
+\let\Eftable\Etable
+\let\Evtable\Etable
+\let\Eitemize\Etable
+\let\Eenumerate\Etable
+
+% This is the counter used by @enumerate, which is really @itemize
+
+\newcount \itemno
+
+\envdef\itemize{\parsearg\doitemize}
+
+\def\doitemize#1{%
+  \aboveenvbreak
+  \itemmax=\itemindent
+  \advance\itemmax by -\itemmargin
+  \advance\leftskip by \itemindent
+  \exdentamount=\itemindent
+  \parindent=0pt
+  \parskip=\smallskipamount
+  \ifdim\parskip=0pt \parskip=2pt \fi
+  %
+  % Try typesetting the item mark that if the document erroneously says
+  % something like @itemize @samp (intending @table), there's an error
+  % right away at the @itemize.  It's not the best error message in the
+  % world, but it's better than leaving it to the @item.  This means if
+  % the user wants an empty mark, they have to say @w{} not just @w.
+  \def\itemcontents{#1}%
+  \setbox0 = \hbox{\itemcontents}%
+  %
+  % @itemize with no arg is equivalent to @itemize @bullet.
+  \ifx\itemcontents\empty\def\itemcontents{\bullet}\fi
+  %
+  \let\item=\itemizeitem
+}
+
+% Definition of @item while inside @itemize and @enumerate.
+%
+\def\itemizeitem{%
+  \advance\itemno by 1  % for enumerations
+  {\let\par=\endgraf \smallbreak}% reasonable place to break
+  {%
+   % If the document has an @itemize directly after a section title, a
+   % \nobreak will be last on the list, and \sectionheading will have
+   % done a \vskip-\parskip.  In that case, we don't want to zero
+   % parskip, or the item text will crash with the heading.  On the
+   % other hand, when there is normal text preceding the item (as there
+   % usually is), we do want to zero parskip, or there would be too much
+   % space.  In that case, we won't have a \nobreak before.  At least
+   % that's the theory.
+   \ifnum\lastpenalty<10000 \parskip=0in \fi
+   \noindent
+   \hbox to 0pt{\hss \itemcontents \kern\itemmargin}%
+   %
+   \vadjust{\penalty 1200}}% not good to break after first line of item.
+  \flushcr
+}
+
+% \splitoff TOKENS\endmark defines \first to be the first token in
+% TOKENS, and \rest to be the remainder.
+%
+\def\splitoff#1#2\endmark{\def\first{#1}\def\rest{#2}}%
+
+% Allow an optional argument of an uppercase letter, lowercase letter,
+% or number, to specify the first label in the enumerated list.  No
+% argument is the same as `1'.
+%
+\envparseargdef\enumerate{\enumeratey #1  \endenumeratey}
+\def\enumeratey #1 #2\endenumeratey{%
+  % If we were given no argument, pretend we were given `1'.
+  \def\thearg{#1}%
+  \ifx\thearg\empty \def\thearg{1}\fi
+  %
+  % Detect if the argument is a single token.  If so, it might be a
+  % letter.  Otherwise, the only valid thing it can be is a number.
+  % (We will always have one token, because of the test we just made.
+  % This is a good thing, since \splitoff doesn't work given nothing at
+  % all -- the first parameter is undelimited.)
+  \expandafter\splitoff\thearg\endmark
+  \ifx\rest\empty
+    % Only one token in the argument.  It could still be anything.
+    % A ``lowercase letter'' is one whose \lccode is nonzero.
+    % An ``uppercase letter'' is one whose \lccode is both nonzero, and
+    %   not equal to itself.
+    % Otherwise, we assume it's a number.
+    %
+    % We need the \relax at the end of the \ifnum lines to stop TeX from
+    % continuing to look for a <number>.
+    %
+    \ifnum\lccode\expandafter`\thearg=0\relax
+      \numericenumerate % a number (we hope)
+    \else
+      % It's a letter.
+      \ifnum\lccode\expandafter`\thearg=\expandafter`\thearg\relax
+        \lowercaseenumerate % lowercase letter
+      \else
+        \uppercaseenumerate % uppercase letter
+      \fi
+    \fi
+  \else
+    % Multiple tokens in the argument.  We hope it's a number.
+    \numericenumerate
+  \fi
+}
+
+% An @enumerate whose labels are integers.  The starting integer is
+% given in \thearg.
+%
+\def\numericenumerate{%
+  \itemno = \thearg
+  \startenumeration{\the\itemno}%
+}
+
+% The starting (lowercase) letter is in \thearg.
+\def\lowercaseenumerate{%
+  \itemno = \expandafter`\thearg
+  \startenumeration{%
+    % Be sure we're not beyond the end of the alphabet.
+    \ifnum\itemno=0
+      \errmessage{No more lowercase letters in @enumerate; get a bigger
+                  alphabet}%
+    \fi
+    \char\lccode\itemno
+  }%
+}
+
+% The starting (uppercase) letter is in \thearg.
+\def\uppercaseenumerate{%
+  \itemno = \expandafter`\thearg
+  \startenumeration{%
+    % Be sure we're not beyond the end of the alphabet.
+    \ifnum\itemno=0
+      \errmessage{No more uppercase letters in @enumerate; get a bigger
+                  alphabet}
+    \fi
+    \char\uccode\itemno
+  }%
+}
+
+% Call \doitemize, adding a period to the first argument and supplying the
+% common last two arguments.  Also subtract one from the initial value in
+% \itemno, since @item increments \itemno.
+%
+\def\startenumeration#1{%
+  \advance\itemno by -1
+  \doitemize{#1.}\flushcr
+}
+
+% @alphaenumerate and @capsenumerate are abbreviations for giving an arg
+% to @enumerate.
+%
+\def\alphaenumerate{\enumerate{a}}
+\def\capsenumerate{\enumerate{A}}
+\def\Ealphaenumerate{\Eenumerate}
+\def\Ecapsenumerate{\Eenumerate}
+
+
+% @multitable macros
+% Amy Hendrickson, 8/18/94, 3/6/96
+%
+% @multitable ... @end multitable will make as many columns as desired.
+% Contents of each column will wrap at width given in preamble.  Width
+% can be specified either with sample text given in a template line,
+% or in percent of \hsize, the current width of text on page.
+
+% Table can continue over pages but will only break between lines.
+
+% To make preamble:
+%
+% Either define widths of columns in terms of percent of \hsize:
+%   @multitable @columnfractions .25 .3 .45
+%   @item ...
+%
+%   Numbers following @columnfractions are the percent of the total
+%   current hsize to be used for each column. You may use as many
+%   columns as desired.
+
+
+% Or use a template:
+%   @multitable {Column 1 template} {Column 2 template} {Column 3 template}
+%   @item ...
+%   using the widest term desired in each column.
+
+% Each new table line starts with @item, each subsequent new column
+% starts with @tab. Empty columns may be produced by supplying @tab's
+% with nothing between them for as many times as empty columns are needed,
+% ie, @tab@tab@tab will produce two empty columns.
+
+% @item, @tab do not need to be on their own lines, but it will not hurt
+% if they are.
+
+% Sample multitable:
+
+%   @multitable {Column 1 template} {Column 2 template} {Column 3 template}
+%   @item first col stuff @tab second col stuff @tab third col
+%   @item
+%   first col stuff
+%   @tab
+%   second col stuff
+%   @tab
+%   third col
+%   @item first col stuff @tab second col stuff
+%   @tab Many paragraphs of text may be used in any column.
+%
+%         They will wrap at the width determined by the template.
+%   @item@tab@tab This will be in third column.
+%   @end multitable
+
+% Default dimensions may be reset by user.
+% @multitableparskip is vertical space between paragraphs in table.
+% @multitableparindent is paragraph indent in table.
+% @multitablecolmargin is horizontal space to be left between columns.
+% @multitablelinespace is space to leave between table items, baseline
+%                                                            to baseline.
+%   0pt means it depends on current normal line spacing.
+%
+\newskip\multitableparskip
+\newskip\multitableparindent
+\newdimen\multitablecolspace
+\newskip\multitablelinespace
+\multitableparskip=0pt
+\multitableparindent=6pt
+\multitablecolspace=12pt
+\multitablelinespace=0pt
+
+% Macros used to set up halign preamble:
+%
+\let\endsetuptable\relax
+\def\xendsetuptable{\endsetuptable}
+\let\columnfractions\relax
+\def\xcolumnfractions{\columnfractions}
+\newif\ifsetpercent
+
+% #1 is the @columnfraction, usually a decimal number like .5, but might
+% be just 1.  We just use it, whatever it is.
+%
+\def\pickupwholefraction#1 {%
+  \global\advance\colcount by 1
+  \expandafter\xdef\csname col\the\colcount\endcsname{#1\hsize}%
+  \setuptable
+}
+
+\newcount\colcount
+\def\setuptable#1{%
+  \def\firstarg{#1}%
+  \ifx\firstarg\xendsetuptable
+    \let\go = \relax
+  \else
+    \ifx\firstarg\xcolumnfractions
+      \global\setpercenttrue
+    \else
+      \ifsetpercent
+         \let\go\pickupwholefraction
+      \else
+         \global\advance\colcount by 1
+         \setbox0=\hbox{#1\unskip\space}% Add a normal word space as a
+                   % separator; typically that is always in the input, anyway.
+         \expandafter\xdef\csname col\the\colcount\endcsname{\the\wd0}%
+      \fi
+    \fi
+    \ifx\go\pickupwholefraction
+      % Put the argument back for the \pickupwholefraction call, so
+      % we'll always have a period there to be parsed.
+      \def\go{\pickupwholefraction#1}%
+    \else
+      \let\go = \setuptable
+    \fi%
+  \fi
+  \go
+}
+
+% multitable-only commands.
+%
+% @headitem starts a heading row, which we typeset in bold.
+% Assignments have to be global since we are inside the implicit group
+% of an alignment entry.  \everycr resets \everytab so we don't have to
+% undo it ourselves.
+\def\headitemfont{\b}% for people to use in the template row; not changeable
+\def\headitem{%
+  \checkenv\multitable
+  \crcr
+  \global\everytab={\bf}% can't use \headitemfont since the parsing differs
+  \the\everytab % for the first item
+}%
+%
+% A \tab used to include \hskip1sp.  But then the space in a template
+% line is not enough.  That is bad.  So let's go back to just `&' until
+% we again encounter the problem the 1sp was intended to solve.
+%					--karl, nathan@acm.org, 20apr99.
+\def\tab{\checkenv\multitable &\the\everytab}%
+
+% @multitable ... @end multitable definitions:
+%
+\newtoks\everytab  % insert after every tab.
+%
+\envdef\multitable{%
+  \vskip\parskip
+  \startsavinginserts
+  %
+  % @item within a multitable starts a normal row.
+  % We use \def instead of \let so that if one of the multitable entries
+  % contains an @itemize, we don't choke on the \item (seen as \crcr aka
+  % \endtemplate) expanding \doitemize.
+  \def\item{\crcr}%
+  %
+  \tolerance=9500
+  \hbadness=9500
+  \setmultitablespacing
+  \parskip=\multitableparskip
+  \parindent=\multitableparindent
+  \overfullrule=0pt
+  \global\colcount=0
+  %
+  \everycr = {%
+    \noalign{%
+      \global\everytab={}%
+      \global\colcount=0 % Reset the column counter.
+      % Check for saved footnotes, etc.
+      \checkinserts
+      % Keeps underfull box messages off when table breaks over pages.
+      %\filbreak
+	% Maybe so, but it also creates really weird page breaks when the
+	% table breaks over pages. Wouldn't \vfil be better?  Wait until the
+	% problem manifests itself, so it can be fixed for real --karl.
+    }%
+  }%
+  %
+  \parsearg\domultitable
+}
+\def\domultitable#1{%
+  % To parse everything between @multitable and @item:
+  \setuptable#1 \endsetuptable
+  %
+  % This preamble sets up a generic column definition, which will
+  % be used as many times as user calls for columns.
+  % \vtop will set a single line and will also let text wrap and
+  % continue for many paragraphs if desired.
+  \halign\bgroup &%
+    \global\advance\colcount by 1
+    \multistrut
+    \vtop{%
+      % Use the current \colcount to find the correct column width:
+      \hsize=\expandafter\csname col\the\colcount\endcsname
+      %
+      % In order to keep entries from bumping into each other
+      % we will add a \leftskip of \multitablecolspace to all columns after
+      % the first one.
+      %
+      % If a template has been used, we will add \multitablecolspace
+      % to the width of each template entry.
+      %
+      % If the user has set preamble in terms of percent of \hsize we will
+      % use that dimension as the width of the column, and the \leftskip
+      % will keep entries from bumping into each other.  Table will start at
+      % left margin and final column will justify at right margin.
+      %
+      % Make sure we don't inherit \rightskip from the outer environment.
+      \rightskip=0pt
+      \ifnum\colcount=1
+	% The first column will be indented with the surrounding text.
+	\advance\hsize by\leftskip
+      \else
+	\ifsetpercent \else
+	  % If user has not set preamble in terms of percent of \hsize
+	  % we will advance \hsize by \multitablecolspace.
+	  \advance\hsize by \multitablecolspace
+	\fi
+       % In either case we will make \leftskip=\multitablecolspace:
+      \leftskip=\multitablecolspace
+      \fi
+      % Ignoring space at the beginning and end avoids an occasional spurious
+      % blank line, when TeX decides to break the line at the space before the
+      % box from the multistrut, so the strut ends up on a line by itself.
+      % For example:
+      % @multitable @columnfractions .11 .89
+      % @item @code{#}
+      % @tab Legal holiday which is valid in major parts of the whole country.
+      % Is automatically provided with highlighting sequences respectively
+      % marking characters.
+      \noindent\ignorespaces##\unskip\multistrut
+    }\cr
+}
+\def\Emultitable{%
+  \crcr
+  \egroup % end the \halign
+  \global\setpercentfalse
+}
+
+\def\setmultitablespacing{%
+  \def\multistrut{\strut}% just use the standard line spacing
+  %
+  % Compute \multitablelinespace (if not defined by user) for use in
+  % \multitableparskip calculation.  We used define \multistrut based on
+  % this, but (ironically) that caused the spacing to be off.
+  % See bug-texinfo report from Werner Lemberg, 31 Oct 2004 12:52:20 +0100.
+\ifdim\multitablelinespace=0pt
+\setbox0=\vbox{X}\global\multitablelinespace=\the\baselineskip
+\global\advance\multitablelinespace by-\ht0
+\fi
+% Test to see if parskip is larger than space between lines of
+% table. If not, do nothing.
+%        If so, set to same dimension as multitablelinespace.
+\ifdim\multitableparskip>\multitablelinespace
+\global\multitableparskip=\multitablelinespace
+\global\advance\multitableparskip-7pt % to keep parskip somewhat smaller
+                                      % than skip between lines in the table.
+\fi%
+\ifdim\multitableparskip=0pt
+\global\multitableparskip=\multitablelinespace
+\global\advance\multitableparskip-7pt % to keep parskip somewhat smaller
+                                      % than skip between lines in the table.
+\fi}
+
+
+\message{conditionals,}
+
+% @iftex, @ifnotdocbook, @ifnothtml, @ifnotinfo, @ifnotplaintext,
+% @ifnotxml always succeed.  They currently do nothing; we don't
+% attempt to check whether the conditionals are properly nested.  But we
+% have to remember that they are conditionals, so that @end doesn't
+% attempt to close an environment group.
+%
+\def\makecond#1{%
+  \expandafter\let\csname #1\endcsname = \relax
+  \expandafter\let\csname iscond.#1\endcsname = 1
+}
+\makecond{iftex}
+\makecond{ifnotdocbook}
+\makecond{ifnothtml}
+\makecond{ifnotinfo}
+\makecond{ifnotplaintext}
+\makecond{ifnotxml}
+
+% Ignore @ignore, @ifhtml, @ifinfo, and the like.
+%
+\def\direntry{\doignore{direntry}}
+\def\documentdescription{\doignore{documentdescription}}
+\def\docbook{\doignore{docbook}}
+\def\html{\doignore{html}}
+\def\ifdocbook{\doignore{ifdocbook}}
+\def\ifhtml{\doignore{ifhtml}}
+\def\ifinfo{\doignore{ifinfo}}
+\def\ifnottex{\doignore{ifnottex}}
+\def\ifplaintext{\doignore{ifplaintext}}
+\def\ifxml{\doignore{ifxml}}
+\def\ignore{\doignore{ignore}}
+\def\menu{\doignore{menu}}
+\def\xml{\doignore{xml}}
+
+% Ignore text until a line `@end #1', keeping track of nested conditionals.
+%
+% A count to remember the depth of nesting.
+\newcount\doignorecount
+
+\def\doignore#1{\begingroup
+  % Scan in ``verbatim'' mode:
+  \obeylines
+  \catcode`\@ = \other
+  \catcode`\{ = \other
+  \catcode`\} = \other
+  %
+  % Make sure that spaces turn into tokens that match what \doignoretext wants.
+  \spaceisspace
+  %
+  % Count number of #1's that we've seen.
+  \doignorecount = 0
+  %
+  % Swallow text until we reach the matching `@end #1'.
+  \dodoignore{#1}%
+}
+
+{ \catcode`_=11 % We want to use \_STOP_ which cannot appear in texinfo source.
+  \obeylines %
+  %
+  \gdef\dodoignore#1{%
+    % #1 contains the command name as a string, e.g., `ifinfo'.
+    %
+    % Define a command to find the next `@end #1'.
+    \long\def\doignoretext##1^^M@end #1{%
+      \doignoretextyyy##1^^M@#1\_STOP_}%
+    %
+    % And this command to find another #1 command, at the beginning of a
+    % line.  (Otherwise, we would consider a line `@c @ifset', for
+    % example, to count as an @ifset for nesting.)
+    \long\def\doignoretextyyy##1^^M@#1##2\_STOP_{\doignoreyyy{##2}\_STOP_}%
+    %
+    % And now expand that command.
+    \doignoretext ^^M%
+  }%
+}
+
+\def\doignoreyyy#1{%
+  \def\temp{#1}%
+  \ifx\temp\empty			% Nothing found.
+    \let\next\doignoretextzzz
+  \else					% Found a nested condition, ...
+    \advance\doignorecount by 1
+    \let\next\doignoretextyyy		% ..., look for another.
+    % If we're here, #1 ends with ^^M\ifinfo (for example).
+  \fi
+  \next #1% the token \_STOP_ is present just after this macro.
+}
+
+% We have to swallow the remaining "\_STOP_".
+%
+\def\doignoretextzzz#1{%
+  \ifnum\doignorecount = 0	% We have just found the outermost @end.
+    \let\next\enddoignore
+  \else				% Still inside a nested condition.
+    \advance\doignorecount by -1
+    \let\next\doignoretext      % Look for the next @end.
+  \fi
+  \next
+}
+
+% Finish off ignored text.
+{ \obeylines%
+  % Ignore anything after the last `@end #1'; this matters in verbatim
+  % environments, where otherwise the newline after an ignored conditional
+  % would result in a blank line in the output.
+  \gdef\enddoignore#1^^M{\endgroup\ignorespaces}%
+}
+
+
+% @set VAR sets the variable VAR to an empty value.
+% @set VAR REST-OF-LINE sets VAR to the value REST-OF-LINE.
+%
+% Since we want to separate VAR from REST-OF-LINE (which might be
+% empty), we can't just use \parsearg; we have to insert a space of our
+% own to delimit the rest of the line, and then take it out again if we
+% didn't need it.
+% We rely on the fact that \parsearg sets \catcode`\ =10.
+%
+\parseargdef\set{\setyyy#1 \endsetyyy}
+\def\setyyy#1 #2\endsetyyy{%
+  {%
+    \makevalueexpandable
+    \def\temp{#2}%
+    \edef\next{\gdef\makecsname{SET#1}}%
+    \ifx\temp\empty
+      \next{}%
+    \else
+      \setzzz#2\endsetzzz
+    \fi
+  }%
+}
+% Remove the trailing space \setxxx inserted.
+\def\setzzz#1 \endsetzzz{\next{#1}}
+
+% @clear VAR clears (i.e., unsets) the variable VAR.
+%
+\parseargdef\clear{%
+  {%
+    \makevalueexpandable
+    \global\expandafter\let\csname SET#1\endcsname=\relax
+  }%
+}
+
+% @value{foo} gets the text saved in variable foo.
+\def\value{\begingroup\makevalueexpandable\valuexxx}
+\def\valuexxx#1{\expandablevalue{#1}\endgroup}
+{
+  \catcode`\- = \active \catcode`\_ = \active
+  %
+  \gdef\makevalueexpandable{%
+    \let\value = \expandablevalue
+    % We don't want these characters active, ...
+    \catcode`\-=\other \catcode`\_=\other
+    % ..., but we might end up with active ones in the argument if
+    % we're called from @code, as @code{@value{foo-bar_}}, though.
+    % So \let them to their normal equivalents.
+    \let-\normaldash \let_\normalunderscore
+  }
+}
+
+% We have this subroutine so that we can handle at least some @value's
+% properly in indexes (we call \makevalueexpandable in \indexdummies).
+% The command has to be fully expandable (if the variable is set), since
+% the result winds up in the index file.  This means that if the
+% variable's value contains other Texinfo commands, it's almost certain
+% it will fail (although perhaps we could fix that with sufficient work
+% to do a one-level expansion on the result, instead of complete).
+%
+\def\expandablevalue#1{%
+  \expandafter\ifx\csname SET#1\endcsname\relax
+    {[No value for ``#1'']}%
+    \message{Variable `#1', used in @value, is not set.}%
+  \else
+    \csname SET#1\endcsname
+  \fi
+}
+
+% @ifset VAR ... @end ifset reads the `...' iff VAR has been defined
+% with @set.
+%
+% To get special treatment of `@end ifset,' call \makeond and the redefine.
+%
+\makecond{ifset}
+\def\ifset{\parsearg{\doifset{\let\next=\ifsetfail}}}
+\def\doifset#1#2{%
+  {%
+    \makevalueexpandable
+    \let\next=\empty
+    \expandafter\ifx\csname SET#2\endcsname\relax
+      #1% If not set, redefine \next.
+    \fi
+    \expandafter
+  }\next
+}
+\def\ifsetfail{\doignore{ifset}}
+
+% @ifclear VAR ... @end executes the `...' iff VAR has never been
+% defined with @set, or has been undefined with @clear.
+%
+% The `\else' inside the `\doifset' parameter is a trick to reuse the
+% above code: if the variable is not set, do nothing, if it is set,
+% then redefine \next to \ifclearfail.
+%
+\makecond{ifclear}
+\def\ifclear{\parsearg{\doifset{\else \let\next=\ifclearfail}}}
+\def\ifclearfail{\doignore{ifclear}}
+
+% @ifcommandisdefined CMD ... @end executes the `...' if CMD (written
+% without the @) is in fact defined.  We can only feasibly check at the
+% TeX level, so something like `mathcode' is going to considered
+% defined even though it is not a Texinfo command.
+% 
+\makecond{ifcommanddefined}
+\def\ifcommanddefined{\parsearg{\doifcmddefined{\let\next=\ifcmddefinedfail}}}
+%
+\def\doifcmddefined#1#2{{%
+    \makevalueexpandable
+    \let\next=\empty
+    \expandafter\ifx\csname #2\endcsname\relax
+      #1% If not defined, \let\next as above.
+    \fi
+    \expandafter
+  }\next
+}
+\def\ifcmddefinedfail{\doignore{ifcommanddefined}}
+
+% @ifcommandnotdefined CMD ... handled similar to @ifclear above.
+\makecond{ifcommandnotdefined}
+\def\ifcommandnotdefined{%
+  \parsearg{\doifcmddefined{\else \let\next=\ifcmdnotdefinedfail}}}
+\def\ifcmdnotdefinedfail{\doignore{ifcommandnotdefined}}
+
+% Set the `txicommandconditionals' variable, so documents have a way to
+% test if the @ifcommand...defined conditionals are available.
+\set txicommandconditionals
+
+% @dircategory CATEGORY  -- specify a category of the dir file
+% which this file should belong to.  Ignore this in TeX.
+\let\dircategory=\comment
+
+% @defininfoenclose.
+\let\definfoenclose=\comment
+
+
+\message{indexing,}
+% Index generation facilities
+
+% Define \newwrite to be identical to plain tex's \newwrite
+% except not \outer, so it can be used within macros and \if's.
+\edef\newwrite{\makecsname{ptexnewwrite}}
+
+% \newindex {foo} defines an index named foo.
+% It automatically defines \fooindex such that
+% \fooindex ...rest of line... puts an entry in the index foo.
+% It also defines \fooindfile to be the number of the output channel for
+% the file that accumulates this index.  The file's extension is foo.
+% The name of an index should be no more than 2 characters long
+% for the sake of vms.
+%
+\def\newindex#1{%
+  \iflinks
+    \expandafter\newwrite \csname#1indfile\endcsname
+    \openout \csname#1indfile\endcsname \jobname.#1 % Open the file
+  \fi
+  \expandafter\xdef\csname#1index\endcsname{%     % Define @#1index
+    \noexpand\doindex{#1}}
+}
+
+% @defindex foo  ==  \newindex{foo}
+%
+\def\defindex{\parsearg\newindex}
+
+% Define @defcodeindex, like @defindex except put all entries in @code.
+%
+\def\defcodeindex{\parsearg\newcodeindex}
+%
+\def\newcodeindex#1{%
+  \iflinks
+    \expandafter\newwrite \csname#1indfile\endcsname
+    \openout \csname#1indfile\endcsname \jobname.#1
+  \fi
+  \expandafter\xdef\csname#1index\endcsname{%
+    \noexpand\docodeindex{#1}}%
+}
+
+
+% @synindex foo bar    makes index foo feed into index bar.
+% Do this instead of @defindex foo if you don't want it as a separate index.
+%
+% @syncodeindex foo bar   similar, but put all entries made for index foo
+% inside @code.
+%
+\def\synindex#1 #2 {\dosynindex\doindex{#1}{#2}}
+\def\syncodeindex#1 #2 {\dosynindex\docodeindex{#1}{#2}}
+
+% #1 is \doindex or \docodeindex, #2 the index getting redefined (foo),
+% #3 the target index (bar).
+\def\dosynindex#1#2#3{%
+  % Only do \closeout if we haven't already done it, else we'll end up
+  % closing the target index.
+  \expandafter \ifx\csname donesynindex#2\endcsname \relax
+    % The \closeout helps reduce unnecessary open files; the limit on the
+    % Acorn RISC OS is a mere 16 files.
+    \expandafter\closeout\csname#2indfile\endcsname
+    \expandafter\let\csname donesynindex#2\endcsname = 1
+  \fi
+  % redefine \fooindfile:
+  \expandafter\let\expandafter\temp\expandafter=\csname#3indfile\endcsname
+  \expandafter\let\csname#2indfile\endcsname=\temp
+  % redefine \fooindex:
+  \expandafter\xdef\csname#2index\endcsname{\noexpand#1{#3}}%
+}
+
+% Define \doindex, the driver for all \fooindex macros.
+% Argument #1 is generated by the calling \fooindex macro,
+%  and it is "foo", the name of the index.
+
+% \doindex just uses \parsearg; it calls \doind for the actual work.
+% This is because \doind is more useful to call from other macros.
+
+% There is also \dosubind {index}{topic}{subtopic}
+% which makes an entry in a two-level index such as the operation index.
+
+\def\doindex#1{\edef\indexname{#1}\parsearg\singleindexer}
+\def\singleindexer #1{\doind{\indexname}{#1}}
+
+% like the previous two, but they put @code around the argument.
+\def\docodeindex#1{\edef\indexname{#1}\parsearg\singlecodeindexer}
+\def\singlecodeindexer #1{\doind{\indexname}{\code{#1}}}
+
+% Take care of Texinfo commands that can appear in an index entry.
+% Since there are some commands we want to expand, and others we don't,
+% we have to laboriously prevent expansion for those that we don't.
+%
+\def\indexdummies{%
+  \escapechar = `\\     % use backslash in output files.
+  \def\@{@}% change to @@ when we switch to @ as escape char in index files.
+  \def\ {\realbackslash\space }%
+  %
+  % Need these unexpandable (because we define \tt as a dummy)
+  % definitions when @{ or @} appear in index entry text.  Also, more
+  % complicated, when \tex is in effect and \{ is a \delimiter again.
+  % We can't use \lbracecmd and \rbracecmd because texindex assumes
+  % braces and backslashes are used only as delimiters.  Perhaps we
+  % should define @lbrace and @rbrace commands a la @comma.
+  \def\{{{\tt\char123}}%
+  \def\}{{\tt\char125}}%
+  %
+  % I don't entirely understand this, but when an index entry is
+  % generated from a macro call, the \endinput which \scanmacro inserts
+  % causes processing to be prematurely terminated.  This is,
+  % apparently, because \indexsorttmp is fully expanded, and \endinput
+  % is an expandable command.  The redefinition below makes \endinput
+  % disappear altogether for that purpose -- although logging shows that
+  % processing continues to some further point.  On the other hand, it
+  % seems \endinput does not hurt in the printed index arg, since that
+  % is still getting written without apparent harm.
+  %
+  % Sample source (mac-idx3.tex, reported by Graham Percival to
+  % help-texinfo, 22may06):
+  % @macro funindex {WORD}
+  % @findex xyz
+  % @end macro
+  % ...
+  % @funindex commtest
+  %
+  % The above is not enough to reproduce the bug, but it gives the flavor.
+  %
+  % Sample whatsit resulting:
+  % .@write3{\entry{xyz}{@folio }{@code {xyz@endinput }}}
+  %
+  % So:
+  \let\endinput = \empty
+  %
+  % Do the redefinitions.
+  \commondummies
+}
+
+% For the aux and toc files, @ is the escape character.  So we want to
+% redefine everything using @ as the escape character (instead of
+% \realbackslash, still used for index files).  When everything uses @,
+% this will be simpler.
+%
+\def\atdummies{%
+  \def\@{@@}%
+  \def\ {@ }%
+  \let\{ = \lbraceatcmd
+  \let\} = \rbraceatcmd
+  %
+  % Do the redefinitions.
+  \commondummies
+  \otherbackslash
+}
+
+% Called from \indexdummies and \atdummies.
+%
+\def\commondummies{%
+  %
+  % \definedummyword defines \#1 as \string\#1\space, thus effectively
+  % preventing its expansion.  This is used only for control words,
+  % not control letters, because the \space would be incorrect for
+  % control characters, but is needed to separate the control word
+  % from whatever follows.
+  %
+  % For control letters, we have \definedummyletter, which omits the
+  % space.
+  %
+  % These can be used both for control words that take an argument and
+  % those that do not.  If it is followed by {arg} in the input, then
+  % that will dutifully get written to the index (or wherever).
+  %
+  \def\definedummyword  ##1{\def##1{\string##1\space}}%
+  \def\definedummyletter##1{\def##1{\string##1}}%
+  \let\definedummyaccent\definedummyletter
+  %
+  \commondummiesnofonts
+  %
+  \definedummyletter\_%
+  \definedummyletter\-%
+  %
+  % Non-English letters.
+  \definedummyword\AA
+  \definedummyword\AE
+  \definedummyword\DH
+  \definedummyword\L
+  \definedummyword\O
+  \definedummyword\OE
+  \definedummyword\TH
+  \definedummyword\aa
+  \definedummyword\ae
+  \definedummyword\dh
+  \definedummyword\exclamdown
+  \definedummyword\l
+  \definedummyword\o
+  \definedummyword\oe
+  \definedummyword\ordf
+  \definedummyword\ordm
+  \definedummyword\questiondown
+  \definedummyword\ss
+  \definedummyword\th
+  %
+  % Although these internal commands shouldn't show up, sometimes they do.
+  \definedummyword\bf
+  \definedummyword\gtr
+  \definedummyword\hat
+  \definedummyword\less
+  \definedummyword\sf
+  \definedummyword\sl
+  \definedummyword\tclose
+  \definedummyword\tt
+  %
+  \definedummyword\LaTeX
+  \definedummyword\TeX
+  %
+  % Assorted special characters.
+  \definedummyword\arrow
+  \definedummyword\bullet
+  \definedummyword\comma
+  \definedummyword\copyright
+  \definedummyword\registeredsymbol
+  \definedummyword\dots
+  \definedummyword\enddots
+  \definedummyword\entrybreak
+  \definedummyword\equiv
+  \definedummyword\error
+  \definedummyword\euro
+  \definedummyword\expansion
+  \definedummyword\geq
+  \definedummyword\guillemetleft
+  \definedummyword\guillemetright
+  \definedummyword\guilsinglleft
+  \definedummyword\guilsinglright
+  \definedummyword\lbracechar
+  \definedummyword\leq
+  \definedummyword\minus
+  \definedummyword\ogonek
+  \definedummyword\pounds
+  \definedummyword\point
+  \definedummyword\print
+  \definedummyword\quotedblbase
+  \definedummyword\quotedblleft
+  \definedummyword\quotedblright
+  \definedummyword\quoteleft
+  \definedummyword\quoteright
+  \definedummyword\quotesinglbase
+  \definedummyword\rbracechar
+  \definedummyword\result
+  \definedummyword\textdegree
+  %
+  % We want to disable all macros so that they are not expanded by \write.
+  \macrolist
+  %
+  \normalturnoffactive
+  %
+  % Handle some cases of @value -- where it does not contain any
+  % (non-fully-expandable) commands.
+  \makevalueexpandable
+}
+
+% \commondummiesnofonts: common to \commondummies and \indexnofonts.
+%
+\def\commondummiesnofonts{%
+  % Control letters and accents.
+  \definedummyletter\!%
+  \definedummyaccent\"%
+  \definedummyaccent\'%
+  \definedummyletter\*%
+  \definedummyaccent\,%
+  \definedummyletter\.%
+  \definedummyletter\/%
+  \definedummyletter\:%
+  \definedummyaccent\=%
+  \definedummyletter\?%
+  \definedummyaccent\^%
+  \definedummyaccent\`%
+  \definedummyaccent\~%
+  \definedummyword\u
+  \definedummyword\v
+  \definedummyword\H
+  \definedummyword\dotaccent
+  \definedummyword\ogonek
+  \definedummyword\ringaccent
+  \definedummyword\tieaccent
+  \definedummyword\ubaraccent
+  \definedummyword\udotaccent
+  \definedummyword\dotless
+  %
+  % Texinfo font commands.
+  \definedummyword\b
+  \definedummyword\i
+  \definedummyword\r
+  \definedummyword\sansserif
+  \definedummyword\sc
+  \definedummyword\slanted
+  \definedummyword\t
+  %
+  % Commands that take arguments.
+  \definedummyword\abbr
+  \definedummyword\acronym
+  \definedummyword\anchor
+  \definedummyword\cite
+  \definedummyword\code
+  \definedummyword\command
+  \definedummyword\dfn
+  \definedummyword\dmn
+  \definedummyword\email
+  \definedummyword\emph
+  \definedummyword\env
+  \definedummyword\file
+  \definedummyword\image
+  \definedummyword\indicateurl
+  \definedummyword\inforef
+  \definedummyword\kbd
+  \definedummyword\key
+  \definedummyword\math
+  \definedummyword\option
+  \definedummyword\pxref
+  \definedummyword\ref
+  \definedummyword\samp
+  \definedummyword\strong
+  \definedummyword\tie
+  \definedummyword\uref
+  \definedummyword\url
+  \definedummyword\var
+  \definedummyword\verb
+  \definedummyword\w
+  \definedummyword\xref
+}
+
+% \indexnofonts is used when outputting the strings to sort the index
+% by, and when constructing control sequence names.  It eliminates all
+% control sequences and just writes whatever the best ASCII sort string
+% would be for a given command (usually its argument).
+%
+\def\indexnofonts{%
+  % Accent commands should become @asis.
+  \def\definedummyaccent##1{\let##1\asis}%
+  % We can just ignore other control letters.
+  \def\definedummyletter##1{\let##1\empty}%
+  % All control words become @asis by default; overrides below.
+  \let\definedummyword\definedummyaccent
+  %
+  \commondummiesnofonts
+  %
+  % Don't no-op \tt, since it isn't a user-level command
+  % and is used in the definitions of the active chars like <, >, |, etc.
+  % Likewise with the other plain tex font commands.
+  %\let\tt=\asis
+  %
+  \def\ { }%
+  \def\@{@}%
+  \def\_{\normalunderscore}%
+  \def\-{}% @- shouldn't affect sorting
+  %
+  % Unfortunately, texindex is not prepared to handle braces in the
+  % content at all.  So for index sorting, we map @{ and @} to strings
+  % starting with |, since that ASCII character is between ASCII { and }.
+  \def\{{|a}%
+  \def\lbracechar{|a}%
+  %
+  \def\}{|b}%
+  \def\rbracechar{|b}%
+  %
+  % Non-English letters.
+  \def\AA{AA}%
+  \def\AE{AE}%
+  \def\DH{DZZ}%
+  \def\L{L}%
+  \def\OE{OE}%
+  \def\O{O}%
+  \def\TH{ZZZ}%
+  \def\aa{aa}%
+  \def\ae{ae}%
+  \def\dh{dzz}%
+  \def\exclamdown{!}%
+  \def\l{l}%
+  \def\oe{oe}%
+  \def\ordf{a}%
+  \def\ordm{o}%
+  \def\o{o}%
+  \def\questiondown{?}%
+  \def\ss{ss}%
+  \def\th{zzz}%
+  %
+  \def\LaTeX{LaTeX}%
+  \def\TeX{TeX}%
+  %
+  % Assorted special characters.
+  % (The following {} will end up in the sort string, but that's ok.)
+  \def\arrow{->}%
+  \def\bullet{bullet}%
+  \def\comma{,}%
+  \def\copyright{copyright}%
+  \def\dots{...}%
+  \def\enddots{...}%
+  \def\equiv{==}%
+  \def\error{error}%
+  \def\euro{euro}%
+  \def\expansion{==>}%
+  \def\geq{>=}%
+  \def\guillemetleft{<<}%
+  \def\guillemetright{>>}%
+  \def\guilsinglleft{<}%
+  \def\guilsinglright{>}%
+  \def\leq{<=}%
+  \def\minus{-}%
+  \def\point{.}%
+  \def\pounds{pounds}%
+  \def\print{-|}%
+  \def\quotedblbase{"}%
+  \def\quotedblleft{"}%
+  \def\quotedblright{"}%
+  \def\quoteleft{`}%
+  \def\quoteright{'}%
+  \def\quotesinglbase{,}%
+  \def\registeredsymbol{R}%
+  \def\result{=>}%
+  \def\textdegree{o}%
+  %
+  \expandafter\ifx\csname SETtxiindexlquoteignore\endcsname\relax
+  \else \indexlquoteignore \fi
+  %
+  % We need to get rid of all macros, leaving only the arguments (if present).
+  % Of course this is not nearly correct, but it is the best we can do for now.
+  % makeinfo does not expand macros in the argument to @deffn, which ends up
+  % writing an index entry, and texindex isn't prepared for an index sort entry
+  % that starts with \.
+  %
+  % Since macro invocations are followed by braces, we can just redefine them
+  % to take a single TeX argument.  The case of a macro invocation that
+  % goes to end-of-line is not handled.
+  %
+  \macrolist
+}
+
+% Undocumented (for FSFS 2nd ed.): @set txiindexlquoteignore makes us
+% ignore left quotes in the sort term.
+{\catcode`\`=\active
+ \gdef\indexlquoteignore{\let`=\empty}}
+
+\let\indexbackslash=0  %overridden during \printindex.
+\let\SETmarginindex=\relax % put index entries in margin (undocumented)?
+
+% Most index entries go through here, but \dosubind is the general case.
+% #1 is the index name, #2 is the entry text.
+\def\doind#1#2{\dosubind{#1}{#2}{}}
+
+% Workhorse for all \fooindexes.
+% #1 is name of index, #2 is stuff to put there, #3 is subentry --
+% empty if called from \doind, as we usually are (the main exception
+% is with most defuns, which call us directly).
+%
+\def\dosubind#1#2#3{%
+  \iflinks
+  {%
+    % Store the main index entry text (including the third arg).
+    \toks0 = {#2}%
+    % If third arg is present, precede it with a space.
+    \def\thirdarg{#3}%
+    \ifx\thirdarg\empty \else
+      \toks0 = \expandafter{\the\toks0 \space #3}%
+    \fi
+    %
+    \edef\writeto{\csname#1indfile\endcsname}%
+    %
+    \safewhatsit\dosubindwrite
+  }%
+  \fi
+}
+
+% Write the entry in \toks0 to the index file:
+%
+\def\dosubindwrite{%
+  % Put the index entry in the margin if desired.
+  \ifx\SETmarginindex\relax\else
+    \insert\margin{\hbox{\vrule height8pt depth3pt width0pt \the\toks0}}%
+  \fi
+  %
+  % Remember, we are within a group.
+  \indexdummies % Must do this here, since \bf, etc expand at this stage
+  \def\backslashcurfont{\indexbackslash}% \indexbackslash isn't defined now
+      % so it will be output as is; and it will print as backslash.
+  %
+  % Process the index entry with all font commands turned off, to
+  % get the string to sort by.
+  {\indexnofonts
+   \edef\temp{\the\toks0}% need full expansion
+   \xdef\indexsorttmp{\temp}%
+  }%
+  %
+  % Set up the complete index entry, with both the sort key and
+  % the original text, including any font commands.  We write
+  % three arguments to \entry to the .?? file (four in the
+  % subentry case), texindex reduces to two when writing the .??s
+  % sorted result.
+  \edef\temp{%
+    \write\writeto{%
+      \string\entry{\indexsorttmp}{\noexpand\folio}{\the\toks0}}%
+  }%
+  \temp
+}
+
+% Take care of unwanted page breaks/skips around a whatsit:
+%
+% If a skip is the last thing on the list now, preserve it
+% by backing up by \lastskip, doing the \write, then inserting
+% the skip again.  Otherwise, the whatsit generated by the
+% \write or \pdfdest will make \lastskip zero.  The result is that
+% sequences like this:
+% @end defun
+% @tindex whatever
+% @defun ...
+% will have extra space inserted, because the \medbreak in the
+% start of the @defun won't see the skip inserted by the @end of
+% the previous defun.
+%
+% But don't do any of this if we're not in vertical mode.  We
+% don't want to do a \vskip and prematurely end a paragraph.
+%
+% Avoid page breaks due to these extra skips, too.
+%
+% But wait, there is a catch there:
+% We'll have to check whether \lastskip is zero skip.  \ifdim is not
+% sufficient for this purpose, as it ignores stretch and shrink parts
+% of the skip.  The only way seems to be to check the textual
+% representation of the skip.
+%
+% The following is almost like \def\zeroskipmacro{0.0pt} except that
+% the ``p'' and ``t'' characters have catcode \other, not 11 (letter).
+%
+\edef\zeroskipmacro{\expandafter\the\csname z@skip\endcsname}
+%
+\newskip\whatsitskip
+\newcount\whatsitpenalty
+%
+% ..., ready, GO:
+%
+\def\safewhatsit#1{\ifhmode
+  #1%
+ \else
+  % \lastskip and \lastpenalty cannot both be nonzero simultaneously.
+  \whatsitskip = \lastskip
+  \edef\lastskipmacro{\the\lastskip}%
+  \whatsitpenalty = \lastpenalty
+  %
+  % If \lastskip is nonzero, that means the last item was a
+  % skip.  And since a skip is discardable, that means this
+  % -\whatsitskip glue we're inserting is preceded by a
+  % non-discardable item, therefore it is not a potential
+  % breakpoint, therefore no \nobreak needed.
+  \ifx\lastskipmacro\zeroskipmacro
+  \else
+    \vskip-\whatsitskip
+  \fi
+  %
+  #1%
+  %
+  \ifx\lastskipmacro\zeroskipmacro
+    % If \lastskip was zero, perhaps the last item was a penalty, and
+    % perhaps it was >=10000, e.g., a \nobreak.  In that case, we want
+    % to re-insert the same penalty (values >10000 are used for various
+    % signals); since we just inserted a non-discardable item, any
+    % following glue (such as a \parskip) would be a breakpoint.  For example:
+    %   @deffn deffn-whatever
+    %   @vindex index-whatever
+    %   Description.
+    % would allow a break between the index-whatever whatsit
+    % and the "Description." paragraph.
+    \ifnum\whatsitpenalty>9999 \penalty\whatsitpenalty \fi
+  \else
+    % On the other hand, if we had a nonzero \lastskip,
+    % this make-up glue would be preceded by a non-discardable item
+    % (the whatsit from the \write), so we must insert a \nobreak.
+    \nobreak\vskip\whatsitskip
+  \fi
+\fi}
+
+% The index entry written in the file actually looks like
+%  \entry {sortstring}{page}{topic}
+% or
+%  \entry {sortstring}{page}{topic}{subtopic}
+% The texindex program reads in these files and writes files
+% containing these kinds of lines:
+%  \initial {c}
+%     before the first topic whose initial is c
+%  \entry {topic}{pagelist}
+%     for a topic that is used without subtopics
+%  \primary {topic}
+%     for the beginning of a topic that is used with subtopics
+%  \secondary {subtopic}{pagelist}
+%     for each subtopic.
+
+% Define the user-accessible indexing commands
+% @findex, @vindex, @kindex, @cindex.
+
+\def\findex {\fnindex}
+\def\kindex {\kyindex}
+\def\cindex {\cpindex}
+\def\vindex {\vrindex}
+\def\tindex {\tpindex}
+\def\pindex {\pgindex}
+
+\def\cindexsub {\begingroup\obeylines\cindexsub}
+{\obeylines %
+\gdef\cindexsub "#1" #2^^M{\endgroup %
+\dosubind{cp}{#2}{#1}}}
+
+% Define the macros used in formatting output of the sorted index material.
+
+% @printindex causes a particular index (the ??s file) to get printed.
+% It does not print any chapter heading (usually an @unnumbered).
+%
+\parseargdef\printindex{\begingroup
+  \dobreak \chapheadingskip{10000}%
+  %
+  \smallfonts \rm
+  \tolerance = 9500
+  \plainfrenchspacing
+  \everypar = {}% don't want the \kern\-parindent from indentation suppression.
+  %
+  % See if the index file exists and is nonempty.
+  % Change catcode of @ here so that if the index file contains
+  % \initial {@}
+  % as its first line, TeX doesn't complain about mismatched braces
+  % (because it thinks @} is a control sequence).
+  \catcode`\@ = 11
+  \openin 1 \jobname.#1s
+  \ifeof 1
+    % \enddoublecolumns gets confused if there is no text in the index,
+    % and it loses the chapter title and the aux file entries for the
+    % index.  The easiest way to prevent this problem is to make sure
+    % there is some text.
+    \putwordIndexNonexistent
+  \else
+    %
+    % If the index file exists but is empty, then \openin leaves \ifeof
+    % false.  We have to make TeX try to read something from the file, so
+    % it can discover if there is anything in it.
+    \read 1 to \temp
+    \ifeof 1
+      \putwordIndexIsEmpty
+    \else
+      % Index files are almost Texinfo source, but we use \ as the escape
+      % character.  It would be better to use @, but that's too big a change
+      % to make right now.
+      \def\indexbackslash{\backslashcurfont}%
+      \catcode`\\ = 0
+      \escapechar = `\\
+      \begindoublecolumns
+      \input \jobname.#1s
+      \enddoublecolumns
+    \fi
+  \fi
+  \closein 1
+\endgroup}
+
+% These macros are used by the sorted index file itself.
+% Change them to control the appearance of the index.
+
+\def\initial#1{{%
+  % Some minor font changes for the special characters.
+  \let\tentt=\sectt \let\tt=\sectt \let\sf=\sectt
+  %
+  % Remove any glue we may have, we'll be inserting our own.
+  \removelastskip
+  %
+  % We like breaks before the index initials, so insert a bonus.
+  \nobreak
+  \vskip 0pt plus 3\baselineskip
+  \penalty 0
+  \vskip 0pt plus -3\baselineskip
+  %
+  % Typeset the initial.  Making this add up to a whole number of
+  % baselineskips increases the chance of the dots lining up from column
+  % to column.  It still won't often be perfect, because of the stretch
+  % we need before each entry, but it's better.
+  %
+  % No shrink because it confuses \balancecolumns.
+  \vskip 1.67\baselineskip plus .5\baselineskip
+  \leftline{\secbf #1}%
+  % Do our best not to break after the initial.
+  \nobreak
+  \vskip .33\baselineskip plus .1\baselineskip
+}}
+
+% \entry typesets a paragraph consisting of the text (#1), dot leaders, and
+% then page number (#2) flushed to the right margin.  It is used for index
+% and table of contents entries.  The paragraph is indented by \leftskip.
+%
+% A straightforward implementation would start like this:
+%	\def\entry#1#2{...
+% But this freezes the catcodes in the argument, and can cause problems to
+% @code, which sets - active.  This problem was fixed by a kludge---
+% ``-'' was active throughout whole index, but this isn't really right.
+% The right solution is to prevent \entry from swallowing the whole text.
+%                                 --kasal, 21nov03
+\def\entry{%
+  \begingroup
+    %
+    % Start a new paragraph if necessary, so our assignments below can't
+    % affect previous text.
+    \par
+    %
+    % Do not fill out the last line with white space.
+    \parfillskip = 0in
+    %
+    % No extra space above this paragraph.
+    \parskip = 0in
+    %
+    % Do not prefer a separate line ending with a hyphen to fewer lines.
+    \finalhyphendemerits = 0
+    %
+    % \hangindent is only relevant when the entry text and page number
+    % don't both fit on one line.  In that case, bob suggests starting the
+    % dots pretty far over on the line.  Unfortunately, a large
+    % indentation looks wrong when the entry text itself is broken across
+    % lines.  So we use a small indentation and put up with long leaders.
+    %
+    % \hangafter is reset to 1 (which is the value we want) at the start
+    % of each paragraph, so we need not do anything with that.
+    \hangindent = 2em
+    %
+    % When the entry text needs to be broken, just fill out the first line
+    % with blank space.
+    \rightskip = 0pt plus1fil
+    %
+    % A bit of stretch before each entry for the benefit of balancing
+    % columns.
+    \vskip 0pt plus1pt
+    %
+    % When reading the text of entry, convert explicit line breaks
+    % from @* into spaces.  The user might give these in long section
+    % titles, for instance.
+    \def\*{\unskip\space\ignorespaces}%
+    \def\entrybreak{\hfil\break}%
+    %
+    % Swallow the left brace of the text (first parameter):
+    \afterassignment\doentry
+    \let\temp =
+}
+\def\entrybreak{\unskip\space\ignorespaces}%
+\def\doentry{%
+    \bgroup % Instead of the swallowed brace.
+      \noindent
+      \aftergroup\finishentry
+      % And now comes the text of the entry.
+}
+\def\finishentry#1{%
+    % #1 is the page number.
+    %
+    % The following is kludged to not output a line of dots in the index if
+    % there are no page numbers.  The next person who breaks this will be
+    % cursed by a Unix daemon.
+    \setbox\boxA = \hbox{#1}%
+    \ifdim\wd\boxA = 0pt
+      \ %
+    \else
+      %
+      % If we must, put the page number on a line of its own, and fill out
+      % this line with blank space.  (The \hfil is overwhelmed with the
+      % fill leaders glue in \indexdotfill if the page number does fit.)
+      \hfil\penalty50
+      \null\nobreak\indexdotfill % Have leaders before the page number.
+      %
+      % The `\ ' here is removed by the implicit \unskip that TeX does as
+      % part of (the primitive) \par.  Without it, a spurious underfull
+      % \hbox ensues.
+      \ifpdf
+	\pdfgettoks#1.%
+	\ \the\toksA
+      \else
+	\ #1%
+      \fi
+    \fi
+    \par
+  \endgroup
+}
+
+% Like plain.tex's \dotfill, except uses up at least 1 em.
+\def\indexdotfill{\cleaders
+  \hbox{$\mathsurround=0pt \mkern1.5mu.\mkern1.5mu$}\hskip 1em plus 1fill}
+
+\def\primary #1{\line{#1\hfil}}
+
+\newskip\secondaryindent \secondaryindent=0.5cm
+\def\secondary#1#2{{%
+  \parfillskip=0in
+  \parskip=0in
+  \hangindent=1in
+  \hangafter=1
+  \noindent\hskip\secondaryindent\hbox{#1}\indexdotfill
+  \ifpdf
+    \pdfgettoks#2.\ \the\toksA % The page number ends the paragraph.
+  \else
+    #2
+  \fi
+  \par
+}}
+
+% Define two-column mode, which we use to typeset indexes.
+% Adapted from the TeXbook, page 416, which is to say,
+% the manmac.tex format used to print the TeXbook itself.
+\catcode`\@=11
+
+\newbox\partialpage
+\newdimen\doublecolumnhsize
+
+\def\begindoublecolumns{\begingroup % ended by \enddoublecolumns
+  % Grab any single-column material above us.
+  \output = {%
+    %
+    % Here is a possibility not foreseen in manmac: if we accumulate a
+    % whole lot of material, we might end up calling this \output
+    % routine twice in a row (see the doublecol-lose test, which is
+    % essentially a couple of indexes with @setchapternewpage off).  In
+    % that case we just ship out what is in \partialpage with the normal
+    % output routine.  Generally, \partialpage will be empty when this
+    % runs and this will be a no-op.  See the indexspread.tex test case.
+    \ifvoid\partialpage \else
+      \onepageout{\pagecontents\partialpage}%
+    \fi
+    %
+    \global\setbox\partialpage = \vbox{%
+      % Unvbox the main output page.
+      \unvbox\PAGE
+      \kern-\topskip \kern\baselineskip
+    }%
+  }%
+  \eject % run that output routine to set \partialpage
+  %
+  % Use the double-column output routine for subsequent pages.
+  \output = {\doublecolumnout}%
+  %
+  % Change the page size parameters.  We could do this once outside this
+  % routine, in each of @smallbook, @afourpaper, and the default 8.5x11
+  % format, but then we repeat the same computation.  Repeating a couple
+  % of assignments once per index is clearly meaningless for the
+  % execution time, so we may as well do it in one place.
+  %
+  % First we halve the line length, less a little for the gutter between
+  % the columns.  We compute the gutter based on the line length, so it
+  % changes automatically with the paper format.  The magic constant
+  % below is chosen so that the gutter has the same value (well, +-<1pt)
+  % as it did when we hard-coded it.
+  %
+  % We put the result in a separate register, \doublecolumhsize, so we
+  % can restore it in \pagesofar, after \hsize itself has (potentially)
+  % been clobbered.
+  %
+  \doublecolumnhsize = \hsize
+    \advance\doublecolumnhsize by -.04154\hsize
+    \divide\doublecolumnhsize by 2
+  \hsize = \doublecolumnhsize
+  %
+  % Double the \vsize as well.  (We don't need a separate register here,
+  % since nobody clobbers \vsize.)
+  \vsize = 2\vsize
+}
+
+% The double-column output routine for all double-column pages except
+% the last.
+%
+\def\doublecolumnout{%
+  \splittopskip=\topskip \splitmaxdepth=\maxdepth
+  % Get the available space for the double columns -- the normal
+  % (undoubled) page height minus any material left over from the
+  % previous page.
+  \dimen@ = \vsize
+  \divide\dimen@ by 2
+  \advance\dimen@ by -\ht\partialpage
+  %
+  % box0 will be the left-hand column, box2 the right.
+  \setbox0=\vsplit255 to\dimen@ \setbox2=\vsplit255 to\dimen@
+  \onepageout\pagesofar
+  \unvbox255
+  \penalty\outputpenalty
+}
+%
+% Re-output the contents of the output page -- any previous material,
+% followed by the two boxes we just split, in box0 and box2.
+\def\pagesofar{%
+  \unvbox\partialpage
+  %
+  \hsize = \doublecolumnhsize
+  \wd0=\hsize \wd2=\hsize
+  \hbox to\pagewidth{\box0\hfil\box2}%
+}
+%
+% All done with double columns.
+\def\enddoublecolumns{%
+  % The following penalty ensures that the page builder is exercised
+  % _before_ we change the output routine.  This is necessary in the
+  % following situation:
+  %
+  % The last section of the index consists only of a single entry.
+  % Before this section, \pagetotal is less than \pagegoal, so no
+  % break occurs before the last section starts.  However, the last
+  % section, consisting of \initial and the single \entry, does not
+  % fit on the page and has to be broken off.  Without the following
+  % penalty the page builder will not be exercised until \eject
+  % below, and by that time we'll already have changed the output
+  % routine to the \balancecolumns version, so the next-to-last
+  % double-column page will be processed with \balancecolumns, which
+  % is wrong:  The two columns will go to the main vertical list, with
+  % the broken-off section in the recent contributions.  As soon as
+  % the output routine finishes, TeX starts reconsidering the page
+  % break.  The two columns and the broken-off section both fit on the
+  % page, because the two columns now take up only half of the page
+  % goal.  When TeX sees \eject from below which follows the final
+  % section, it invokes the new output routine that we've set after
+  % \balancecolumns below; \onepageout will try to fit the two columns
+  % and the final section into the vbox of \pageheight (see
+  % \pagebody), causing an overfull box.
+  %
+  % Note that glue won't work here, because glue does not exercise the
+  % page builder, unlike penalties (see The TeXbook, pp. 280-281).
+  \penalty0
+  %
+  \output = {%
+    % Split the last of the double-column material.  Leave it on the
+    % current page, no automatic page break.
+    \balancecolumns
+    %
+    % If we end up splitting too much material for the current page,
+    % though, there will be another page break right after this \output
+    % invocation ends.  Having called \balancecolumns once, we do not
+    % want to call it again.  Therefore, reset \output to its normal
+    % definition right away.  (We hope \balancecolumns will never be
+    % called on to balance too much material, but if it is, this makes
+    % the output somewhat more palatable.)
+    \global\output = {\onepageout{\pagecontents\PAGE}}%
+  }%
+  \eject
+  \endgroup % started in \begindoublecolumns
+  %
+  % \pagegoal was set to the doubled \vsize above, since we restarted
+  % the current page.  We're now back to normal single-column
+  % typesetting, so reset \pagegoal to the normal \vsize (after the
+  % \endgroup where \vsize got restored).
+  \pagegoal = \vsize
+}
+%
+% Called at the end of the double column material.
+\def\balancecolumns{%
+  \setbox0 = \vbox{\unvbox255}% like \box255 but more efficient, see p.120.
+  \dimen@ = \ht0
+  \advance\dimen@ by \topskip
+  \advance\dimen@ by-\baselineskip
+  \divide\dimen@ by 2 % target to split to
+  %debug\message{final 2-column material height=\the\ht0, target=\the\dimen@.}%
+  \splittopskip = \topskip
+  % Loop until we get a decent breakpoint.
+  {%
+    \vbadness = 10000
+    \loop
+      \global\setbox3 = \copy0
+      \global\setbox1 = \vsplit3 to \dimen@
+    \ifdim\ht3>\dimen@
+      \global\advance\dimen@ by 1pt
+    \repeat
+  }%
+  %debug\message{split to \the\dimen@, column heights: \the\ht1, \the\ht3.}%
+  \setbox0=\vbox to\dimen@{\unvbox1}%
+  \setbox2=\vbox to\dimen@{\unvbox3}%
+  %
+  \pagesofar
+}
+\catcode`\@ = \other
+
+
+\message{sectioning,}
+% Chapters, sections, etc.
+
+% Let's start with @part.
+\outer\parseargdef\part{\partzzz{#1}}
+\def\partzzz#1{%
+  \chapoddpage
+  \null
+  \vskip.3\vsize  % move it down on the page a bit
+  \begingroup
+    \noindent \titlefonts\rmisbold #1\par % the text
+    \let\lastnode=\empty      % no node to associate with
+    \writetocentry{part}{#1}{}% but put it in the toc
+    \headingsoff              % no headline or footline on the part page
+    \chapoddpage
+  \endgroup
+}
+
+% \unnumberedno is an oxymoron.  But we count the unnumbered
+% sections so that we can refer to them unambiguously in the pdf
+% outlines by their "section number".  We avoid collisions with chapter
+% numbers by starting them at 10000.  (If a document ever has 10000
+% chapters, we're in trouble anyway, I'm sure.)
+\newcount\unnumberedno \unnumberedno = 10000
+\newcount\chapno
+\newcount\secno        \secno=0
+\newcount\subsecno     \subsecno=0
+\newcount\subsubsecno  \subsubsecno=0
+
+% This counter is funny since it counts through charcodes of letters A, B, ...
+\newcount\appendixno  \appendixno = `\@
+%
+% \def\appendixletter{\char\the\appendixno}
+% We do the following ugly conditional instead of the above simple
+% construct for the sake of pdftex, which needs the actual
+% letter in the expansion, not just typeset.
+%
+\def\appendixletter{%
+  \ifnum\appendixno=`A A%
+  \else\ifnum\appendixno=`B B%
+  \else\ifnum\appendixno=`C C%
+  \else\ifnum\appendixno=`D D%
+  \else\ifnum\appendixno=`E E%
+  \else\ifnum\appendixno=`F F%
+  \else\ifnum\appendixno=`G G%
+  \else\ifnum\appendixno=`H H%
+  \else\ifnum\appendixno=`I I%
+  \else\ifnum\appendixno=`J J%
+  \else\ifnum\appendixno=`K K%
+  \else\ifnum\appendixno=`L L%
+  \else\ifnum\appendixno=`M M%
+  \else\ifnum\appendixno=`N N%
+  \else\ifnum\appendixno=`O O%
+  \else\ifnum\appendixno=`P P%
+  \else\ifnum\appendixno=`Q Q%
+  \else\ifnum\appendixno=`R R%
+  \else\ifnum\appendixno=`S S%
+  \else\ifnum\appendixno=`T T%
+  \else\ifnum\appendixno=`U U%
+  \else\ifnum\appendixno=`V V%
+  \else\ifnum\appendixno=`W W%
+  \else\ifnum\appendixno=`X X%
+  \else\ifnum\appendixno=`Y Y%
+  \else\ifnum\appendixno=`Z Z%
+  % The \the is necessary, despite appearances, because \appendixletter is
+  % expanded while writing the .toc file.  \char\appendixno is not
+  % expandable, thus it is written literally, thus all appendixes come out
+  % with the same letter (or @) in the toc without it.
+  \else\char\the\appendixno
+  \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi
+  \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi}
+
+% Each @chapter defines these (using marks) as the number+name, number
+% and name of the chapter.  Page headings and footings can use
+% these.  @section does likewise.
+\def\thischapter{}
+\def\thischapternum{}
+\def\thischaptername{}
+\def\thissection{}
+\def\thissectionnum{}
+\def\thissectionname{}
+
+\newcount\absseclevel % used to calculate proper heading level
+\newcount\secbase\secbase=0 % @raisesections/@lowersections modify this count
+
+% @raisesections: treat @section as chapter, @subsection as section, etc.
+\def\raisesections{\global\advance\secbase by -1}
+\let\up=\raisesections % original BFox name
+
+% @lowersections: treat @chapter as section, @section as subsection, etc.
+\def\lowersections{\global\advance\secbase by 1}
+\let\down=\lowersections % original BFox name
+
+% we only have subsub.
+\chardef\maxseclevel = 3
+%
+% A numbered section within an unnumbered changes to unnumbered too.
+% To achieve this, remember the "biggest" unnum. sec. we are currently in:
+\chardef\unnlevel = \maxseclevel
+%
+% Trace whether the current chapter is an appendix or not:
+% \chapheadtype is "N" or "A", unnumbered chapters are ignored.
+\def\chapheadtype{N}
+
+% Choose a heading macro
+% #1 is heading type
+% #2 is heading level
+% #3 is text for heading
+\def\genhead#1#2#3{%
+  % Compute the abs. sec. level:
+  \absseclevel=#2
+  \advance\absseclevel by \secbase
+  % Make sure \absseclevel doesn't fall outside the range:
+  \ifnum \absseclevel < 0
+    \absseclevel = 0
+  \else
+    \ifnum \absseclevel > 3
+      \absseclevel = 3
+    \fi
+  \fi
+  % The heading type:
+  \def\headtype{#1}%
+  \if \headtype U%
+    \ifnum \absseclevel < \unnlevel
+      \chardef\unnlevel = \absseclevel
+    \fi
+  \else
+    % Check for appendix sections:
+    \ifnum \absseclevel = 0
+      \edef\chapheadtype{\headtype}%
+    \else
+      \if \headtype A\if \chapheadtype N%
+	\errmessage{@appendix... within a non-appendix chapter}%
+      \fi\fi
+    \fi
+    % Check for numbered within unnumbered:
+    \ifnum \absseclevel > \unnlevel
+      \def\headtype{U}%
+    \else
+      \chardef\unnlevel = 3
+    \fi
+  \fi
+  % Now print the heading:
+  \if \headtype U%
+    \ifcase\absseclevel
+	\unnumberedzzz{#3}%
+    \or \unnumberedseczzz{#3}%
+    \or \unnumberedsubseczzz{#3}%
+    \or \unnumberedsubsubseczzz{#3}%
+    \fi
+  \else
+    \if \headtype A%
+      \ifcase\absseclevel
+	  \appendixzzz{#3}%
+      \or \appendixsectionzzz{#3}%
+      \or \appendixsubseczzz{#3}%
+      \or \appendixsubsubseczzz{#3}%
+      \fi
+    \else
+      \ifcase\absseclevel
+	  \chapterzzz{#3}%
+      \or \seczzz{#3}%
+      \or \numberedsubseczzz{#3}%
+      \or \numberedsubsubseczzz{#3}%
+      \fi
+    \fi
+  \fi
+  \suppressfirstparagraphindent
+}
+
+% an interface:
+\def\numhead{\genhead N}
+\def\apphead{\genhead A}
+\def\unnmhead{\genhead U}
+
+% @chapter, @appendix, @unnumbered.  Increment top-level counter, reset
+% all lower-level sectioning counters to zero.
+%
+% Also set \chaplevelprefix, which we prepend to @float sequence numbers
+% (e.g., figures), q.v.  By default (before any chapter), that is empty.
+\let\chaplevelprefix = \empty
+%
+\outer\parseargdef\chapter{\numhead0{#1}} % normally numhead0 calls chapterzzz
+\def\chapterzzz#1{%
+  % section resetting is \global in case the chapter is in a group, such
+  % as an @include file.
+  \global\secno=0 \global\subsecno=0 \global\subsubsecno=0
+    \global\advance\chapno by 1
+  %
+  % Used for \float.
+  \gdef\chaplevelprefix{\the\chapno.}%
+  \resetallfloatnos
+  %
+  % \putwordChapter can contain complex things in translations.
+  \toks0=\expandafter{\putwordChapter}%
+  \message{\the\toks0 \space \the\chapno}%
+  %
+  % Write the actual heading.
+  \chapmacro{#1}{Ynumbered}{\the\chapno}%
+  %
+  % So @section and the like are numbered underneath this chapter.
+  \global\let\section = \numberedsec
+  \global\let\subsection = \numberedsubsec
+  \global\let\subsubsection = \numberedsubsubsec
+}
+
+\outer\parseargdef\appendix{\apphead0{#1}} % normally calls appendixzzz
+%
+\def\appendixzzz#1{%
+  \global\secno=0 \global\subsecno=0 \global\subsubsecno=0
+    \global\advance\appendixno by 1
+  \gdef\chaplevelprefix{\appendixletter.}%
+  \resetallfloatnos
+  %
+  % \putwordAppendix can contain complex things in translations.
+  \toks0=\expandafter{\putwordAppendix}%
+  \message{\the\toks0 \space \appendixletter}%
+  %
+  \chapmacro{#1}{Yappendix}{\appendixletter}%
+  %
+  \global\let\section = \appendixsec
+  \global\let\subsection = \appendixsubsec
+  \global\let\subsubsection = \appendixsubsubsec
+}
+
+% normally unnmhead0 calls unnumberedzzz:
+\outer\parseargdef\unnumbered{\unnmhead0{#1}}
+\def\unnumberedzzz#1{%
+  \global\secno=0 \global\subsecno=0 \global\subsubsecno=0
+    \global\advance\unnumberedno by 1
+  %
+  % Since an unnumbered has no number, no prefix for figures.
+  \global\let\chaplevelprefix = \empty
+  \resetallfloatnos
+  %
+  % This used to be simply \message{#1}, but TeX fully expands the
+  % argument to \message.  Therefore, if #1 contained @-commands, TeX
+  % expanded them.  For example, in `@unnumbered The @cite{Book}', TeX
+  % expanded @cite (which turns out to cause errors because \cite is meant
+  % to be executed, not expanded).
+  %
+  % Anyway, we don't want the fully-expanded definition of @cite to appear
+  % as a result of the \message, we just want `@cite' itself.  We use
+  % \the<toks register> to achieve this: TeX expands \the<toks> only once,
+  % simply yielding the contents of <toks register>.  (We also do this for
+  % the toc entries.)
+  \toks0 = {#1}%
+  \message{(\the\toks0)}%
+  %
+  \chapmacro{#1}{Ynothing}{\the\unnumberedno}%
+  %
+  \global\let\section = \unnumberedsec
+  \global\let\subsection = \unnumberedsubsec
+  \global\let\subsubsection = \unnumberedsubsubsec
+}
+
+% @centerchap is like @unnumbered, but the heading is centered.
+\outer\parseargdef\centerchap{%
+  % Well, we could do the following in a group, but that would break
+  % an assumption that \chapmacro is called at the outermost level.
+  % Thus we are safer this way:		--kasal, 24feb04
+  \let\centerparametersmaybe = \centerparameters
+  \unnmhead0{#1}%
+  \let\centerparametersmaybe = \relax
+}
+
+% @top is like @unnumbered.
+\let\top\unnumbered
+
+% Sections.
+% 
+\outer\parseargdef\numberedsec{\numhead1{#1}} % normally calls seczzz
+\def\seczzz#1{%
+  \global\subsecno=0 \global\subsubsecno=0  \global\advance\secno by 1
+  \sectionheading{#1}{sec}{Ynumbered}{\the\chapno.\the\secno}%
+}
+
+% normally calls appendixsectionzzz:
+\outer\parseargdef\appendixsection{\apphead1{#1}}
+\def\appendixsectionzzz#1{%
+  \global\subsecno=0 \global\subsubsecno=0  \global\advance\secno by 1
+  \sectionheading{#1}{sec}{Yappendix}{\appendixletter.\the\secno}%
+}
+\let\appendixsec\appendixsection
+
+% normally calls unnumberedseczzz:
+\outer\parseargdef\unnumberedsec{\unnmhead1{#1}}
+\def\unnumberedseczzz#1{%
+  \global\subsecno=0 \global\subsubsecno=0  \global\advance\secno by 1
+  \sectionheading{#1}{sec}{Ynothing}{\the\unnumberedno.\the\secno}%
+}
+
+% Subsections.
+% 
+% normally calls numberedsubseczzz:
+\outer\parseargdef\numberedsubsec{\numhead2{#1}}
+\def\numberedsubseczzz#1{%
+  \global\subsubsecno=0  \global\advance\subsecno by 1
+  \sectionheading{#1}{subsec}{Ynumbered}{\the\chapno.\the\secno.\the\subsecno}%
+}
+
+% normally calls appendixsubseczzz:
+\outer\parseargdef\appendixsubsec{\apphead2{#1}}
+\def\appendixsubseczzz#1{%
+  \global\subsubsecno=0  \global\advance\subsecno by 1
+  \sectionheading{#1}{subsec}{Yappendix}%
+                 {\appendixletter.\the\secno.\the\subsecno}%
+}
+
+% normally calls unnumberedsubseczzz:
+\outer\parseargdef\unnumberedsubsec{\unnmhead2{#1}}
+\def\unnumberedsubseczzz#1{%
+  \global\subsubsecno=0  \global\advance\subsecno by 1
+  \sectionheading{#1}{subsec}{Ynothing}%
+                 {\the\unnumberedno.\the\secno.\the\subsecno}%
+}
+
+% Subsubsections.
+% 
+% normally numberedsubsubseczzz:
+\outer\parseargdef\numberedsubsubsec{\numhead3{#1}}
+\def\numberedsubsubseczzz#1{%
+  \global\advance\subsubsecno by 1
+  \sectionheading{#1}{subsubsec}{Ynumbered}%
+                 {\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno}%
+}
+
+% normally appendixsubsubseczzz:
+\outer\parseargdef\appendixsubsubsec{\apphead3{#1}}
+\def\appendixsubsubseczzz#1{%
+  \global\advance\subsubsecno by 1
+  \sectionheading{#1}{subsubsec}{Yappendix}%
+                 {\appendixletter.\the\secno.\the\subsecno.\the\subsubsecno}%
+}
+
+% normally unnumberedsubsubseczzz:
+\outer\parseargdef\unnumberedsubsubsec{\unnmhead3{#1}}
+\def\unnumberedsubsubseczzz#1{%
+  \global\advance\subsubsecno by 1
+  \sectionheading{#1}{subsubsec}{Ynothing}%
+                 {\the\unnumberedno.\the\secno.\the\subsecno.\the\subsubsecno}%
+}
+
+% These macros control what the section commands do, according
+% to what kind of chapter we are in (ordinary, appendix, or unnumbered).
+% Define them by default for a numbered chapter.
+\let\section = \numberedsec
+\let\subsection = \numberedsubsec
+\let\subsubsection = \numberedsubsubsec
+
+% Define @majorheading, @heading and @subheading
+
+\def\majorheading{%
+  {\advance\chapheadingskip by 10pt \chapbreak }%
+  \parsearg\chapheadingzzz
+}
+
+\def\chapheading{\chapbreak \parsearg\chapheadingzzz}
+\def\chapheadingzzz#1{%
+  \vbox{\chapfonts \raggedtitlesettings #1\par}%
+  \nobreak\bigskip \nobreak
+  \suppressfirstparagraphindent
+}
+
+% @heading, @subheading, @subsubheading.
+\parseargdef\heading{\sectionheading{#1}{sec}{Yomitfromtoc}{}
+  \suppressfirstparagraphindent}
+\parseargdef\subheading{\sectionheading{#1}{subsec}{Yomitfromtoc}{}
+  \suppressfirstparagraphindent}
+\parseargdef\subsubheading{\sectionheading{#1}{subsubsec}{Yomitfromtoc}{}
+  \suppressfirstparagraphindent}
+
+% These macros generate a chapter, section, etc. heading only
+% (including whitespace, linebreaking, etc. around it),
+% given all the information in convenient, parsed form.
+
+% Args are the skip and penalty (usually negative)
+\def\dobreak#1#2{\par\ifdim\lastskip<#1\removelastskip\penalty#2\vskip#1\fi}
+
+% Parameter controlling skip before chapter headings (if needed)
+\newskip\chapheadingskip
+
+% Define plain chapter starts, and page on/off switching for it.
+\def\chapbreak{\dobreak \chapheadingskip {-4000}}
+\def\chappager{\par\vfill\supereject}
+% Because \domark is called before \chapoddpage, the filler page will
+% get the headings for the next chapter, which is wrong.  But we don't
+% care -- we just disable all headings on the filler page.
+\def\chapoddpage{%
+  \chappager
+  \ifodd\pageno \else
+    \begingroup
+      \headingsoff
+      \null
+      \chappager
+    \endgroup
+  \fi
+}
+
+\def\setchapternewpage #1 {\csname CHAPPAG#1\endcsname}
+
+\def\CHAPPAGoff{%
+\global\let\contentsalignmacro = \chappager
+\global\let\pchapsepmacro=\chapbreak
+\global\let\pagealignmacro=\chappager}
+
+\def\CHAPPAGon{%
+\global\let\contentsalignmacro = \chappager
+\global\let\pchapsepmacro=\chappager
+\global\let\pagealignmacro=\chappager
+\global\def\HEADINGSon{\HEADINGSsingle}}
+
+\def\CHAPPAGodd{%
+\global\let\contentsalignmacro = \chapoddpage
+\global\let\pchapsepmacro=\chapoddpage
+\global\let\pagealignmacro=\chapoddpage
+\global\def\HEADINGSon{\HEADINGSdouble}}
+
+\CHAPPAGon
+
+% Chapter opening.
+%
+% #1 is the text, #2 is the section type (Ynumbered, Ynothing,
+% Yappendix, Yomitfromtoc), #3 the chapter number.
+%
+% To test against our argument.
+\def\Ynothingkeyword{Ynothing}
+\def\Yomitfromtockeyword{Yomitfromtoc}
+\def\Yappendixkeyword{Yappendix}
+%
+\def\chapmacro#1#2#3{%
+  % Insert the first mark before the heading break (see notes for \domark).
+  \let\prevchapterdefs=\lastchapterdefs
+  \let\prevsectiondefs=\lastsectiondefs
+  \gdef\lastsectiondefs{\gdef\thissectionname{}\gdef\thissectionnum{}%
+                        \gdef\thissection{}}%
+  %
+  \def\temptype{#2}%
+  \ifx\temptype\Ynothingkeyword
+    \gdef\lastchapterdefs{\gdef\thischaptername{#1}\gdef\thischapternum{}%
+                          \gdef\thischapter{\thischaptername}}%
+  \else\ifx\temptype\Yomitfromtockeyword
+    \gdef\lastchapterdefs{\gdef\thischaptername{#1}\gdef\thischapternum{}%
+                          \gdef\thischapter{}}%
+  \else\ifx\temptype\Yappendixkeyword
+    \toks0={#1}%
+    \xdef\lastchapterdefs{%
+      \gdef\noexpand\thischaptername{\the\toks0}%
+      \gdef\noexpand\thischapternum{\appendixletter}%
+      % \noexpand\putwordAppendix avoids expanding indigestible
+      % commands in some of the translations.
+      \gdef\noexpand\thischapter{\noexpand\putwordAppendix{}
+                                 \noexpand\thischapternum:
+                                 \noexpand\thischaptername}%
+    }%
+  \else
+    \toks0={#1}%
+    \xdef\lastchapterdefs{%
+      \gdef\noexpand\thischaptername{\the\toks0}%
+      \gdef\noexpand\thischapternum{\the\chapno}%
+      % \noexpand\putwordChapter avoids expanding indigestible
+      % commands in some of the translations.
+      \gdef\noexpand\thischapter{\noexpand\putwordChapter{}
+                                 \noexpand\thischapternum:
+                                 \noexpand\thischaptername}%
+    }%
+  \fi\fi\fi
+  %
+  % Output the mark.  Pass it through \safewhatsit, to take care of
+  % the preceding space.
+  \safewhatsit\domark
+  %
+  % Insert the chapter heading break.
+  \pchapsepmacro
+  %
+  % Now the second mark, after the heading break.  No break points
+  % between here and the heading.
+  \let\prevchapterdefs=\lastchapterdefs
+  \let\prevsectiondefs=\lastsectiondefs
+  \domark
+  %
+  {%
+    \chapfonts \rmisbold
+    %
+    % Have to define \lastsection before calling \donoderef, because the
+    % xref code eventually uses it.  On the other hand, it has to be called
+    % after \pchapsepmacro, or the headline will change too soon.
+    \gdef\lastsection{#1}%
+    %
+    % Only insert the separating space if we have a chapter/appendix
+    % number, and don't print the unnumbered ``number''.
+    \ifx\temptype\Ynothingkeyword
+      \setbox0 = \hbox{}%
+      \def\toctype{unnchap}%
+    \else\ifx\temptype\Yomitfromtockeyword
+      \setbox0 = \hbox{}% contents like unnumbered, but no toc entry
+      \def\toctype{omit}%
+    \else\ifx\temptype\Yappendixkeyword
+      \setbox0 = \hbox{\putwordAppendix{} #3\enspace}%
+      \def\toctype{app}%
+    \else
+      \setbox0 = \hbox{#3\enspace}%
+      \def\toctype{numchap}%
+    \fi\fi\fi
+    %
+    % Write the toc entry for this chapter.  Must come before the
+    % \donoderef, because we include the current node name in the toc
+    % entry, and \donoderef resets it to empty.
+    \writetocentry{\toctype}{#1}{#3}%
+    %
+    % For pdftex, we have to write out the node definition (aka, make
+    % the pdfdest) after any page break, but before the actual text has
+    % been typeset.  If the destination for the pdf outline is after the
+    % text, then jumping from the outline may wind up with the text not
+    % being visible, for instance under high magnification.
+    \donoderef{#2}%
+    %
+    % Typeset the actual heading.
+    \nobreak % Avoid page breaks at the interline glue.
+    \vbox{\raggedtitlesettings \hangindent=\wd0 \centerparametersmaybe
+          \unhbox0 #1\par}%
+  }%
+  \nobreak\bigskip % no page break after a chapter title
+  \nobreak
+}
+
+% @centerchap -- centered and unnumbered.
+\let\centerparametersmaybe = \relax
+\def\centerparameters{%
+  \advance\rightskip by 3\rightskip
+  \leftskip = \rightskip
+  \parfillskip = 0pt
+}
+
+
+% I don't think this chapter style is supported any more, so I'm not
+% updating it with the new noderef stuff.  We'll see.  --karl, 11aug03.
+%
+\def\setchapterstyle #1 {\csname CHAPF#1\endcsname}
+%
+\def\unnchfopen #1{%
+  \chapoddpage
+  \vbox{\chapfonts \raggedtitlesettings #1\par}%
+  \nobreak\bigskip\nobreak
+}
+\def\chfopen #1#2{\chapoddpage {\chapfonts
+\vbox to 3in{\vfil \hbox to\hsize{\hfil #2} \hbox to\hsize{\hfil #1} \vfil}}%
+\par\penalty 5000 %
+}
+\def\centerchfopen #1{%
+  \chapoddpage
+  \vbox{\chapfonts \raggedtitlesettings \hfill #1\hfill}%
+  \nobreak\bigskip \nobreak
+}
+\def\CHAPFopen{%
+  \global\let\chapmacro=\chfopen
+  \global\let\centerchapmacro=\centerchfopen}
+
+
+% Section titles.  These macros combine the section number parts and
+% call the generic \sectionheading to do the printing.
+%
+\newskip\secheadingskip
+\def\secheadingbreak{\dobreak \secheadingskip{-1000}}
+
+% Subsection titles.
+\newskip\subsecheadingskip
+\def\subsecheadingbreak{\dobreak \subsecheadingskip{-500}}
+
+% Subsubsection titles.
+\def\subsubsecheadingskip{\subsecheadingskip}
+\def\subsubsecheadingbreak{\subsecheadingbreak}
+
+
+% Print any size, any type, section title.
+%
+% #1 is the text, #2 is the section level (sec/subsec/subsubsec), #3 is
+% the section type for xrefs (Ynumbered, Ynothing, Yappendix), #4 is the
+% section number.
+%
+\def\seckeyword{sec}
+%
+\def\sectionheading#1#2#3#4{%
+  {%
+    \checkenv{}% should not be in an environment.
+    %
+    % Switch to the right set of fonts.
+    \csname #2fonts\endcsname \rmisbold
+    %
+    \def\sectionlevel{#2}%
+    \def\temptype{#3}%
+    %
+    % Insert first mark before the heading break (see notes for \domark).
+    \let\prevsectiondefs=\lastsectiondefs
+    \ifx\temptype\Ynothingkeyword
+      \ifx\sectionlevel\seckeyword
+        \gdef\lastsectiondefs{\gdef\thissectionname{#1}\gdef\thissectionnum{}%
+                              \gdef\thissection{\thissectionname}}%
+      \fi
+    \else\ifx\temptype\Yomitfromtockeyword
+      % Don't redefine \thissection.
+    \else\ifx\temptype\Yappendixkeyword
+      \ifx\sectionlevel\seckeyword
+        \toks0={#1}%
+        \xdef\lastsectiondefs{%
+          \gdef\noexpand\thissectionname{\the\toks0}%
+          \gdef\noexpand\thissectionnum{#4}%
+          % \noexpand\putwordSection avoids expanding indigestible
+          % commands in some of the translations.
+          \gdef\noexpand\thissection{\noexpand\putwordSection{}
+                                     \noexpand\thissectionnum:
+                                     \noexpand\thissectionname}%
+        }%
+      \fi
+    \else
+      \ifx\sectionlevel\seckeyword
+        \toks0={#1}%
+        \xdef\lastsectiondefs{%
+          \gdef\noexpand\thissectionname{\the\toks0}%
+          \gdef\noexpand\thissectionnum{#4}%
+          % \noexpand\putwordSection avoids expanding indigestible
+          % commands in some of the translations.
+          \gdef\noexpand\thissection{\noexpand\putwordSection{}
+                                     \noexpand\thissectionnum:
+                                     \noexpand\thissectionname}%
+        }%
+      \fi
+    \fi\fi\fi
+    %
+    % Go into vertical mode.  Usually we'll already be there, but we
+    % don't want the following whatsit to end up in a preceding paragraph
+    % if the document didn't happen to have a blank line.
+    \par
+    %
+    % Output the mark.  Pass it through \safewhatsit, to take care of
+    % the preceding space.
+    \safewhatsit\domark
+    %
+    % Insert space above the heading.
+    \csname #2headingbreak\endcsname
+    %
+    % Now the second mark, after the heading break.  No break points
+    % between here and the heading.
+    \let\prevsectiondefs=\lastsectiondefs
+    \domark
+    %
+    % Only insert the space after the number if we have a section number.
+    \ifx\temptype\Ynothingkeyword
+      \setbox0 = \hbox{}%
+      \def\toctype{unn}%
+      \gdef\lastsection{#1}%
+    \else\ifx\temptype\Yomitfromtockeyword
+      % for @headings -- no section number, don't include in toc,
+      % and don't redefine \lastsection.
+      \setbox0 = \hbox{}%
+      \def\toctype{omit}%
+      \let\sectionlevel=\empty
+    \else\ifx\temptype\Yappendixkeyword
+      \setbox0 = \hbox{#4\enspace}%
+      \def\toctype{app}%
+      \gdef\lastsection{#1}%
+    \else
+      \setbox0 = \hbox{#4\enspace}%
+      \def\toctype{num}%
+      \gdef\lastsection{#1}%
+    \fi\fi\fi
+    %
+    % Write the toc entry (before \donoderef).  See comments in \chapmacro.
+    \writetocentry{\toctype\sectionlevel}{#1}{#4}%
+    %
+    % Write the node reference (= pdf destination for pdftex).
+    % Again, see comments in \chapmacro.
+    \donoderef{#3}%
+    %
+    % Interline glue will be inserted when the vbox is completed.
+    % That glue will be a valid breakpoint for the page, since it'll be
+    % preceded by a whatsit (usually from the \donoderef, or from the
+    % \writetocentry if there was no node).  We don't want to allow that
+    % break, since then the whatsits could end up on page n while the
+    % section is on page n+1, thus toc/etc. are wrong.  Debian bug 276000.
+    \nobreak
+    %
+    % Output the actual section heading.
+    \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \ptexraggedright
+          \hangindent=\wd0  % zero if no section number
+          \unhbox0 #1}%
+  }%
+  % Add extra space after the heading -- half of whatever came above it.
+  % Don't allow stretch, though.
+  \kern .5 \csname #2headingskip\endcsname
+  %
+  % Do not let the kern be a potential breakpoint, as it would be if it
+  % was followed by glue.
+  \nobreak
+  %
+  % We'll almost certainly start a paragraph next, so don't let that
+  % glue accumulate.  (Not a breakpoint because it's preceded by a
+  % discardable item.)  However, when a paragraph is not started next
+  % (\startdefun, \cartouche, \center, etc.), this needs to be wiped out
+  % or the negative glue will cause weirdly wrong output, typically
+  % obscuring the section heading with something else.
+  \vskip-\parskip
+  %
+  % This is so the last item on the main vertical list is a known
+  % \penalty > 10000, so \startdefun, etc., can recognize the situation
+  % and do the needful.
+  \penalty 10001
+}
+
+
+\message{toc,}
+% Table of contents.
+\newwrite\tocfile
+
+% Write an entry to the toc file, opening it if necessary.
+% Called from @chapter, etc.
+%
+% Example usage: \writetocentry{sec}{Section Name}{\the\chapno.\the\secno}
+% We append the current node name (if any) and page number as additional
+% arguments for the \{chap,sec,...}entry macros which will eventually
+% read this.  The node name is used in the pdf outlines as the
+% destination to jump to.
+%
+% We open the .toc file for writing here instead of at @setfilename (or
+% any other fixed time) so that @contents can be anywhere in the document.
+% But if #1 is `omit', then we don't do anything.  This is used for the
+% table of contents chapter openings themselves.
+%
+\newif\iftocfileopened
+\def\omitkeyword{omit}%
+%
+\def\writetocentry#1#2#3{%
+  \edef\writetoctype{#1}%
+  \ifx\writetoctype\omitkeyword \else
+    \iftocfileopened\else
+      \immediate\openout\tocfile = \jobname.toc
+      \global\tocfileopenedtrue
+    \fi
+    %
+    \iflinks
+      {\atdummies
+       \edef\temp{%
+         \write\tocfile{@#1entry{#2}{#3}{\lastnode}{\noexpand\folio}}}%
+       \temp
+      }%
+    \fi
+  \fi
+  %
+  % Tell \shipout to create a pdf destination on each page, if we're
+  % writing pdf.  These are used in the table of contents.  We can't
+  % just write one on every page because the title pages are numbered
+  % 1 and 2 (the page numbers aren't printed), and so are the first
+  % two pages of the document.  Thus, we'd have two destinations named
+  % `1', and two named `2'.
+  \ifpdf \global\pdfmakepagedesttrue \fi
+}
+
+
+% These characters do not print properly in the Computer Modern roman
+% fonts, so we must take special care.  This is more or less redundant
+% with the Texinfo input format setup at the end of this file.
+%
+\def\activecatcodes{%
+  \catcode`\"=\active
+  \catcode`\$=\active
+  \catcode`\<=\active
+  \catcode`\>=\active
+  \catcode`\\=\active
+  \catcode`\^=\active
+  \catcode`\_=\active
+  \catcode`\|=\active
+  \catcode`\~=\active
+}
+
+
+% Read the toc file, which is essentially Texinfo input.
+\def\readtocfile{%
+  \setupdatafile
+  \activecatcodes
+  \input \tocreadfilename
+}
+
+\newskip\contentsrightmargin \contentsrightmargin=1in
+\newcount\savepageno
+\newcount\lastnegativepageno \lastnegativepageno = -1
+
+% Prepare to read what we've written to \tocfile.
+%
+\def\startcontents#1{%
+  % If @setchapternewpage on, and @headings double, the contents should
+  % start on an odd page, unlike chapters.  Thus, we maintain
+  % \contentsalignmacro in parallel with \pagealignmacro.
+  % From: Torbjorn Granlund <tege@matematik.su.se>
+  \contentsalignmacro
+  \immediate\closeout\tocfile
+  %
+  % Don't need to put `Contents' or `Short Contents' in the headline.
+  % It is abundantly clear what they are.
+  \chapmacro{#1}{Yomitfromtoc}{}%
+  %
+  \savepageno = \pageno
+  \begingroup                  % Set up to handle contents files properly.
+    \raggedbottom              % Worry more about breakpoints than the bottom.
+    \advance\hsize by -\contentsrightmargin % Don't use the full line length.
+    %
+    % Roman numerals for page numbers.
+    \ifnum \pageno>0 \global\pageno = \lastnegativepageno \fi
+}
+
+% redefined for the two-volume lispref.  We always output on
+% \jobname.toc even if this is redefined.
+%
+\def\tocreadfilename{\jobname.toc}
+
+% Normal (long) toc.
+%
+\def\contents{%
+  \startcontents{\putwordTOC}%
+    \openin 1 \tocreadfilename\space
+    \ifeof 1 \else
+      \readtocfile
+    \fi
+    \vfill \eject
+    \contentsalignmacro % in case @setchapternewpage odd is in effect
+    \ifeof 1 \else
+      \pdfmakeoutlines
+    \fi
+    \closein 1
+  \endgroup
+  \lastnegativepageno = \pageno
+  \global\pageno = \savepageno
+}
+
+% And just the chapters.
+\def\summarycontents{%
+  \startcontents{\putwordShortTOC}%
+    %
+    \let\partentry = \shortpartentry
+    \let\numchapentry = \shortchapentry
+    \let\appentry = \shortchapentry
+    \let\unnchapentry = \shortunnchapentry
+    % We want a true roman here for the page numbers.
+    \secfonts
+    \let\rm=\shortcontrm \let\bf=\shortcontbf
+    \let\sl=\shortcontsl \let\tt=\shortconttt
+    \rm
+    \hyphenpenalty = 10000
+    \advance\baselineskip by 1pt % Open it up a little.
+    \def\numsecentry##1##2##3##4{}
+    \let\appsecentry = \numsecentry
+    \let\unnsecentry = \numsecentry
+    \let\numsubsecentry = \numsecentry
+    \let\appsubsecentry = \numsecentry
+    \let\unnsubsecentry = \numsecentry
+    \let\numsubsubsecentry = \numsecentry
+    \let\appsubsubsecentry = \numsecentry
+    \let\unnsubsubsecentry = \numsecentry
+    \openin 1 \tocreadfilename\space
+    \ifeof 1 \else
+      \readtocfile
+    \fi
+    \closein 1
+    \vfill \eject
+    \contentsalignmacro % in case @setchapternewpage odd is in effect
+  \endgroup
+  \lastnegativepageno = \pageno
+  \global\pageno = \savepageno
+}
+\let\shortcontents = \summarycontents
+
+% Typeset the label for a chapter or appendix for the short contents.
+% The arg is, e.g., `A' for an appendix, or `3' for a chapter.
+%
+\def\shortchaplabel#1{%
+  % This space should be enough, since a single number is .5em, and the
+  % widest letter (M) is 1em, at least in the Computer Modern fonts.
+  % But use \hss just in case.
+  % (This space doesn't include the extra space that gets added after
+  % the label; that gets put in by \shortchapentry above.)
+  %
+  % We'd like to right-justify chapter numbers, but that looks strange
+  % with appendix letters.  And right-justifying numbers and
+  % left-justifying letters looks strange when there is less than 10
+  % chapters.  Have to read the whole toc once to know how many chapters
+  % there are before deciding ...
+  \hbox to 1em{#1\hss}%
+}
+
+% These macros generate individual entries in the table of contents.
+% The first argument is the chapter or section name.
+% The last argument is the page number.
+% The arguments in between are the chapter number, section number, ...
+
+% Parts, in the main contents.  Replace the part number, which doesn't
+% exist, with an empty box.  Let's hope all the numbers have the same width.
+% Also ignore the page number, which is conventionally not printed.
+\def\numeralbox{\setbox0=\hbox{8}\hbox to \wd0{\hfil}}
+\def\partentry#1#2#3#4{\dochapentry{\numeralbox\labelspace#1}{}}
+%
+% Parts, in the short toc.
+\def\shortpartentry#1#2#3#4{%
+  \penalty-300
+  \vskip.5\baselineskip plus.15\baselineskip minus.1\baselineskip
+  \shortchapentry{{\bf #1}}{\numeralbox}{}{}%
+}
+
+% Chapters, in the main contents.
+\def\numchapentry#1#2#3#4{\dochapentry{#2\labelspace#1}{#4}}
+%
+% Chapters, in the short toc.
+% See comments in \dochapentry re vbox and related settings.
+\def\shortchapentry#1#2#3#4{%
+  \tocentry{\shortchaplabel{#2}\labelspace #1}{\doshortpageno\bgroup#4\egroup}%
+}
+
+% Appendices, in the main contents.
+% Need the word Appendix, and a fixed-size box.
+%
+\def\appendixbox#1{%
+  % We use M since it's probably the widest letter.
+  \setbox0 = \hbox{\putwordAppendix{} M}%
+  \hbox to \wd0{\putwordAppendix{} #1\hss}}
+%
+\def\appentry#1#2#3#4{\dochapentry{\appendixbox{#2}\labelspace#1}{#4}}
+
+% Unnumbered chapters.
+\def\unnchapentry#1#2#3#4{\dochapentry{#1}{#4}}
+\def\shortunnchapentry#1#2#3#4{\tocentry{#1}{\doshortpageno\bgroup#4\egroup}}
+
+% Sections.
+\def\numsecentry#1#2#3#4{\dosecentry{#2\labelspace#1}{#4}}
+\let\appsecentry=\numsecentry
+\def\unnsecentry#1#2#3#4{\dosecentry{#1}{#4}}
+
+% Subsections.
+\def\numsubsecentry#1#2#3#4{\dosubsecentry{#2\labelspace#1}{#4}}
+\let\appsubsecentry=\numsubsecentry
+\def\unnsubsecentry#1#2#3#4{\dosubsecentry{#1}{#4}}
+
+% And subsubsections.
+\def\numsubsubsecentry#1#2#3#4{\dosubsubsecentry{#2\labelspace#1}{#4}}
+\let\appsubsubsecentry=\numsubsubsecentry
+\def\unnsubsubsecentry#1#2#3#4{\dosubsubsecentry{#1}{#4}}
+
+% This parameter controls the indentation of the various levels.
+% Same as \defaultparindent.
+\newdimen\tocindent \tocindent = 15pt
+
+% Now for the actual typesetting. In all these, #1 is the text and #2 is the
+% page number.
+%
+% If the toc has to be broken over pages, we want it to be at chapters
+% if at all possible; hence the \penalty.
+\def\dochapentry#1#2{%
+   \penalty-300 \vskip1\baselineskip plus.33\baselineskip minus.25\baselineskip
+   \begingroup
+     \chapentryfonts
+     \tocentry{#1}{\dopageno\bgroup#2\egroup}%
+   \endgroup
+   \nobreak\vskip .25\baselineskip plus.1\baselineskip
+}
+
+\def\dosecentry#1#2{\begingroup
+  \secentryfonts \leftskip=\tocindent
+  \tocentry{#1}{\dopageno\bgroup#2\egroup}%
+\endgroup}
+
+\def\dosubsecentry#1#2{\begingroup
+  \subsecentryfonts \leftskip=2\tocindent
+  \tocentry{#1}{\dopageno\bgroup#2\egroup}%
+\endgroup}
+
+\def\dosubsubsecentry#1#2{\begingroup
+  \subsubsecentryfonts \leftskip=3\tocindent
+  \tocentry{#1}{\dopageno\bgroup#2\egroup}%
+\endgroup}
+
+% We use the same \entry macro as for the index entries.
+\let\tocentry = \entry
+
+% Space between chapter (or whatever) number and the title.
+\def\labelspace{\hskip1em \relax}
+
+\def\dopageno#1{{\rm #1}}
+\def\doshortpageno#1{{\rm #1}}
+
+\def\chapentryfonts{\secfonts \rm}
+\def\secentryfonts{\textfonts}
+\def\subsecentryfonts{\textfonts}
+\def\subsubsecentryfonts{\textfonts}
+
+
+\message{environments,}
+% @foo ... @end foo.
+
+% @tex ... @end tex    escapes into raw TeX temporarily.
+% One exception: @ is still an escape character, so that @end tex works.
+% But \@ or @@ will get a plain @ character.
+
+\envdef\tex{%
+  \setupmarkupstyle{tex}%
+  \catcode `\\=0 \catcode `\{=1 \catcode `\}=2
+  \catcode `\$=3 \catcode `\&=4 \catcode `\#=6
+  \catcode `\^=7 \catcode `\_=8 \catcode `\~=\active \let~=\tie
+  \catcode `\%=14
+  \catcode `\+=\other
+  \catcode `\"=\other
+  \catcode `\|=\other
+  \catcode `\<=\other
+  \catcode `\>=\other
+  \catcode`\`=\other
+  \catcode`\'=\other
+  \escapechar=`\\
+  %
+  % ' is active in math mode (mathcode"8000).  So reset it, and all our
+  % other math active characters (just in case), to plain's definitions.
+  \mathactive
+  %
+  \let\b=\ptexb
+  \let\bullet=\ptexbullet
+  \let\c=\ptexc
+  \let\,=\ptexcomma
+  \let\.=\ptexdot
+  \let\dots=\ptexdots
+  \let\equiv=\ptexequiv
+  \let\!=\ptexexclam
+  \let\i=\ptexi
+  \let\indent=\ptexindent
+  \let\noindent=\ptexnoindent
+  \let\{=\ptexlbrace
+  \let\+=\tabalign
+  \let\}=\ptexrbrace
+  \let\/=\ptexslash
+  \let\*=\ptexstar
+  \let\t=\ptext
+  \expandafter \let\csname top\endcsname=\ptextop  % outer
+  \let\frenchspacing=\plainfrenchspacing
+  %
+  \def\endldots{\mathinner{\ldots\ldots\ldots\ldots}}%
+  \def\enddots{\relax\ifmmode\endldots\else$\mathsurround=0pt \endldots\,$\fi}%
+  \def\@{@}%
+}
+% There is no need to define \Etex.
+
+% Define @lisp ... @end lisp.
+% @lisp environment forms a group so it can rebind things,
+% including the definition of @end lisp (which normally is erroneous).
+
+% Amount to narrow the margins by for @lisp.
+\newskip\lispnarrowing \lispnarrowing=0.4in
+
+% This is the definition that ^^M gets inside @lisp, @example, and other
+% such environments.  \null is better than a space, since it doesn't
+% have any width.
+\def\lisppar{\null\endgraf}
+
+% This space is always present above and below environments.
+\newskip\envskipamount \envskipamount = 0pt
+
+% Make spacing and below environment symmetrical.  We use \parskip here
+% to help in doing that, since in @example-like environments \parskip
+% is reset to zero; thus the \afterenvbreak inserts no space -- but the
+% start of the next paragraph will insert \parskip.
+%
+\def\aboveenvbreak{{%
+  % =10000 instead of <10000 because of a special case in \itemzzz and
+  % \sectionheading, q.v.
+  \ifnum \lastpenalty=10000 \else
+    \advance\envskipamount by \parskip
+    \endgraf
+    \ifdim\lastskip<\envskipamount
+      \removelastskip
+      % it's not a good place to break if the last penalty was \nobreak
+      % or better ...
+      \ifnum\lastpenalty<10000 \penalty-50 \fi
+      \vskip\envskipamount
+    \fi
+  \fi
+}}
+
+\let\afterenvbreak = \aboveenvbreak
+
+% \nonarrowing is a flag.  If "set", @lisp etc don't narrow margins; it will
+% also clear it, so that its embedded environments do the narrowing again.
+\let\nonarrowing=\relax
+
+% @cartouche ... @end cartouche: draw rectangle w/rounded corners around
+% environment contents.
+\font\circle=lcircle10
+\newdimen\circthick
+\newdimen\cartouter\newdimen\cartinner
+\newskip\normbskip\newskip\normpskip\newskip\normlskip
+\circthick=\fontdimen8\circle
+%
+\def\ctl{{\circle\char'013\hskip -6pt}}% 6pt from pl file: 1/2charwidth
+\def\ctr{{\hskip 6pt\circle\char'010}}
+\def\cbl{{\circle\char'012\hskip -6pt}}
+\def\cbr{{\hskip 6pt\circle\char'011}}
+\def\carttop{\hbox to \cartouter{\hskip\lskip
+        \ctl\leaders\hrule height\circthick\hfil\ctr
+        \hskip\rskip}}
+\def\cartbot{\hbox to \cartouter{\hskip\lskip
+        \cbl\leaders\hrule height\circthick\hfil\cbr
+        \hskip\rskip}}
+%
+\newskip\lskip\newskip\rskip
+
+\envdef\cartouche{%
+  \ifhmode\par\fi  % can't be in the midst of a paragraph.
+  \startsavinginserts
+  \lskip=\leftskip \rskip=\rightskip
+  \leftskip=0pt\rightskip=0pt % we want these *outside*.
+  \cartinner=\hsize \advance\cartinner by-\lskip
+  \advance\cartinner by-\rskip
+  \cartouter=\hsize
+  \advance\cartouter by 18.4pt	% allow for 3pt kerns on either
+				% side, and for 6pt waste from
+				% each corner char, and rule thickness
+  \normbskip=\baselineskip \normpskip=\parskip \normlskip=\lineskip
+  % Flag to tell @lisp, etc., not to narrow margin.
+  \let\nonarrowing = t%
+  %
+  % If this cartouche directly follows a sectioning command, we need the
+  % \parskip glue (backspaced over by default) or the cartouche can
+  % collide with the section heading.
+  \ifnum\lastpenalty>10000 \vskip\parskip \penalty\lastpenalty \fi
+  %
+  \vbox\bgroup
+      \baselineskip=0pt\parskip=0pt\lineskip=0pt
+      \carttop
+      \hbox\bgroup
+	  \hskip\lskip
+	  \vrule\kern3pt
+	  \vbox\bgroup
+	      \kern3pt
+	      \hsize=\cartinner
+	      \baselineskip=\normbskip
+	      \lineskip=\normlskip
+	      \parskip=\normpskip
+	      \vskip -\parskip
+	      \comment % For explanation, see the end of def\group.
+}
+\def\Ecartouche{%
+              \ifhmode\par\fi
+	      \kern3pt
+	  \egroup
+	  \kern3pt\vrule
+	  \hskip\rskip
+      \egroup
+      \cartbot
+  \egroup
+  \checkinserts
+}
+
+
+% This macro is called at the beginning of all the @example variants,
+% inside a group.
+\newdimen\nonfillparindent
+\def\nonfillstart{%
+  \aboveenvbreak
+  \hfuzz = 12pt % Don't be fussy
+  \sepspaces % Make spaces be word-separators rather than space tokens.
+  \let\par = \lisppar % don't ignore blank lines
+  \obeylines % each line of input is a line of output
+  \parskip = 0pt
+  % Turn off paragraph indentation but redefine \indent to emulate
+  % the normal \indent.
+  \nonfillparindent=\parindent
+  \parindent = 0pt
+  \let\indent\nonfillindent
+  %
+  \emergencystretch = 0pt % don't try to avoid overfull boxes
+  \ifx\nonarrowing\relax
+    \advance \leftskip by \lispnarrowing
+    \exdentamount=\lispnarrowing
+  \else
+    \let\nonarrowing = \relax
+  \fi
+  \let\exdent=\nofillexdent
+}
+
+\begingroup
+\obeyspaces
+% We want to swallow spaces (but not other tokens) after the fake
+% @indent in our nonfill-environments, where spaces are normally
+% active and set to @tie, resulting in them not being ignored after
+% @indent.
+\gdef\nonfillindent{\futurelet\temp\nonfillindentcheck}%
+\gdef\nonfillindentcheck{%
+\ifx\temp %
+\expandafter\nonfillindentgobble%
+\else%
+\leavevmode\nonfillindentbox%
+\fi%
+}%
+\endgroup
+\def\nonfillindentgobble#1{\nonfillindent}
+\def\nonfillindentbox{\hbox to \nonfillparindent{\hss}}
+
+% If you want all examples etc. small: @set dispenvsize small.
+% If you want even small examples the full size: @set dispenvsize nosmall.
+% This affects the following displayed environments:
+%    @example, @display, @format, @lisp
+%
+\def\smallword{small}
+\def\nosmallword{nosmall}
+\let\SETdispenvsize\relax
+\def\setnormaldispenv{%
+  \ifx\SETdispenvsize\smallword
+    % end paragraph for sake of leading, in case document has no blank
+    % line.  This is redundant with what happens in \aboveenvbreak, but
+    % we need to do it before changing the fonts, and it's inconvenient
+    % to change the fonts afterward.
+    \ifnum \lastpenalty=10000 \else \endgraf \fi
+    \smallexamplefonts \rm
+  \fi
+}
+\def\setsmalldispenv{%
+  \ifx\SETdispenvsize\nosmallword
+  \else
+    \ifnum \lastpenalty=10000 \else \endgraf \fi
+    \smallexamplefonts \rm
+  \fi
+}
+
+% We often define two environments, @foo and @smallfoo.
+% Let's do it in one command.  #1 is the env name, #2 the definition.
+\def\makedispenvdef#1#2{%
+  \expandafter\envdef\csname#1\endcsname {\setnormaldispenv #2}%
+  \expandafter\envdef\csname small#1\endcsname {\setsmalldispenv #2}%
+  \expandafter\let\csname E#1\endcsname \afterenvbreak
+  \expandafter\let\csname Esmall#1\endcsname \afterenvbreak
+}
+
+% Define two environment synonyms (#1 and #2) for an environment.
+\def\maketwodispenvdef#1#2#3{%
+  \makedispenvdef{#1}{#3}%
+  \makedispenvdef{#2}{#3}%
+}
+%
+% @lisp: indented, narrowed, typewriter font;
+% @example: same as @lisp.
+%
+% @smallexample and @smalllisp: use smaller fonts.
+% Originally contributed by Pavel@xerox.
+%
+\maketwodispenvdef{lisp}{example}{%
+  \nonfillstart
+  \tt\setupmarkupstyle{example}%
+  \let\kbdfont = \kbdexamplefont % Allow @kbd to do something special.
+  \gobble % eat return
+}
+% @display/@smalldisplay: same as @lisp except keep current font.
+%
+\makedispenvdef{display}{%
+  \nonfillstart
+  \gobble
+}
+
+% @format/@smallformat: same as @display except don't narrow margins.
+%
+\makedispenvdef{format}{%
+  \let\nonarrowing = t%
+  \nonfillstart
+  \gobble
+}
+
+% @flushleft: same as @format, but doesn't obey \SETdispenvsize.
+\envdef\flushleft{%
+  \let\nonarrowing = t%
+  \nonfillstart
+  \gobble
+}
+\let\Eflushleft = \afterenvbreak
+
+% @flushright.
+%
+\envdef\flushright{%
+  \let\nonarrowing = t%
+  \nonfillstart
+  \advance\leftskip by 0pt plus 1fill\relax
+  \gobble
+}
+\let\Eflushright = \afterenvbreak
+
+
+% @raggedright does more-or-less normal line breaking but no right
+% justification.  From plain.tex.
+\envdef\raggedright{%
+  \rightskip0pt plus2em \spaceskip.3333em \xspaceskip.5em\relax
+}
+\let\Eraggedright\par
+
+\envdef\raggedleft{%
+  \parindent=0pt \leftskip0pt plus2em
+  \spaceskip.3333em \xspaceskip.5em \parfillskip=0pt
+  \hbadness=10000 % Last line will usually be underfull, so turn off
+                  % badness reporting.
+}
+\let\Eraggedleft\par
+
+\envdef\raggedcenter{%
+  \parindent=0pt \rightskip0pt plus1em \leftskip0pt plus1em
+  \spaceskip.3333em \xspaceskip.5em \parfillskip=0pt
+  \hbadness=10000 % Last line will usually be underfull, so turn off
+                  % badness reporting.
+}
+\let\Eraggedcenter\par
+
+
+% @quotation does normal linebreaking (hence we can't use \nonfillstart)
+% and narrows the margins.  We keep \parskip nonzero in general, since
+% we're doing normal filling.  So, when using \aboveenvbreak and
+% \afterenvbreak, temporarily make \parskip 0.
+%
+\makedispenvdef{quotation}{\quotationstart}
+%
+\def\quotationstart{%
+  \indentedblockstart % same as \indentedblock, but increase right margin too.
+  \ifx\nonarrowing\relax
+    \advance\rightskip by \lispnarrowing
+  \fi
+  \parsearg\quotationlabel
+}
+
+% We have retained a nonzero parskip for the environment, since we're
+% doing normal filling.
+%
+\def\Equotation{%
+  \par
+  \ifx\quotationauthor\thisisundefined\else
+    % indent a bit.
+    \leftline{\kern 2\leftskip \sl ---\quotationauthor}%
+  \fi
+  {\parskip=0pt \afterenvbreak}%
+}
+\def\Esmallquotation{\Equotation}
+
+% If we're given an argument, typeset it in bold with a colon after.
+\def\quotationlabel#1{%
+  \def\temp{#1}%
+  \ifx\temp\empty \else
+    {\bf #1: }%
+  \fi
+}
+
+% @indentedblock is like @quotation, but indents only on the left and
+% has no optional argument.
+% 
+\makedispenvdef{indentedblock}{\indentedblockstart}
+%
+\def\indentedblockstart{%
+  {\parskip=0pt \aboveenvbreak}% because \aboveenvbreak inserts \parskip
+  \parindent=0pt
+  %
+  % @cartouche defines \nonarrowing to inhibit narrowing at next level down.
+  \ifx\nonarrowing\relax
+    \advance\leftskip by \lispnarrowing
+    \exdentamount = \lispnarrowing
+  \else
+    \let\nonarrowing = \relax
+  \fi
+}
+
+% Keep a nonzero parskip for the environment, since we're doing normal filling.
+%
+\def\Eindentedblock{%
+  \par
+  {\parskip=0pt \afterenvbreak}%
+}
+\def\Esmallindentedblock{\Eindentedblock}
+
+
+% LaTeX-like @verbatim...@end verbatim and @verb{<char>...<char>}
+% If we want to allow any <char> as delimiter,
+% we need the curly braces so that makeinfo sees the @verb command, eg:
+% `@verbx...x' would look like the '@verbx' command.  --janneke@gnu.org
+%
+% [Knuth]: Donald Ervin Knuth, 1996.  The TeXbook.
+%
+% [Knuth] p.344; only we need to do the other characters Texinfo sets
+% active too.  Otherwise, they get lost as the first character on a
+% verbatim line.
+\def\dospecials{%
+  \do\ \do\\\do\{\do\}\do\$\do\&%
+  \do\#\do\^\do\^^K\do\_\do\^^A\do\%\do\~%
+  \do\<\do\>\do\|\do\@\do+\do\"%
+  % Don't do the quotes -- if we do, @set txicodequoteundirected and
+  % @set txicodequotebacktick will not have effect on @verb and
+  % @verbatim, and ?` and !` ligatures won't get disabled.
+  %\do\`\do\'%
+}
+%
+% [Knuth] p. 380
+\def\uncatcodespecials{%
+  \def\do##1{\catcode`##1=\other}\dospecials}
+%
+% Setup for the @verb command.
+%
+% Eight spaces for a tab
+\begingroup
+  \catcode`\^^I=\active
+  \gdef\tabeightspaces{\catcode`\^^I=\active\def^^I{\ \ \ \ \ \ \ \ }}
+\endgroup
+%
+\def\setupverb{%
+  \tt  % easiest (and conventionally used) font for verbatim
+  \def\par{\leavevmode\endgraf}%
+  \setupmarkupstyle{verb}%
+  \tabeightspaces
+  % Respect line breaks,
+  % print special symbols as themselves, and
+  % make each space count
+  % must do in this order:
+  \obeylines \uncatcodespecials \sepspaces
+}
+
+% Setup for the @verbatim environment
+%
+% Real tab expansion.
+\newdimen\tabw \setbox0=\hbox{\tt\space} \tabw=8\wd0 % tab amount
+%
+% We typeset each line of the verbatim in an \hbox, so we can handle
+% tabs.  The \global is in case the verbatim line starts with an accent,
+% or some other command that starts with a begin-group.  Otherwise, the
+% entire \verbbox would disappear at the corresponding end-group, before
+% it is typeset.  Meanwhile, we can't have nested verbatim commands
+% (can we?), so the \global won't be overwriting itself.
+\newbox\verbbox
+\def\starttabbox{\global\setbox\verbbox=\hbox\bgroup}
+%
+\begingroup
+  \catcode`\^^I=\active
+  \gdef\tabexpand{%
+    \catcode`\^^I=\active
+    \def^^I{\leavevmode\egroup
+      \dimen\verbbox=\wd\verbbox % the width so far, or since the previous tab
+      \divide\dimen\verbbox by\tabw
+      \multiply\dimen\verbbox by\tabw % compute previous multiple of \tabw
+      \advance\dimen\verbbox by\tabw  % advance to next multiple of \tabw
+      \wd\verbbox=\dimen\verbbox \box\verbbox \starttabbox
+    }%
+  }
+\endgroup
+
+% start the verbatim environment.
+\def\setupverbatim{%
+  \let\nonarrowing = t%
+  \nonfillstart
+  \tt % easiest (and conventionally used) font for verbatim
+  % The \leavevmode here is for blank lines.  Otherwise, we would
+  % never \starttabox and the \egroup would end verbatim mode.
+  \def\par{\leavevmode\egroup\box\verbbox\endgraf}%
+  \tabexpand
+  \setupmarkupstyle{verbatim}%
+  % Respect line breaks,
+  % print special symbols as themselves, and
+  % make each space count.
+  % Must do in this order:
+  \obeylines \uncatcodespecials \sepspaces
+  \everypar{\starttabbox}%
+}
+
+% Do the @verb magic: verbatim text is quoted by unique
+% delimiter characters.  Before first delimiter expect a
+% right brace, after last delimiter expect closing brace:
+%
+%    \def\doverb'{'<char>#1<char>'}'{#1}
+%
+% [Knuth] p. 382; only eat outer {}
+\begingroup
+  \catcode`[=1\catcode`]=2\catcode`\{=\other\catcode`\}=\other
+  \gdef\doverb{#1[\def\next##1#1}[##1\endgroup]\next]
+\endgroup
+%
+\def\verb{\begingroup\setupverb\doverb}
+%
+%
+% Do the @verbatim magic: define the macro \doverbatim so that
+% the (first) argument ends when '@end verbatim' is reached, ie:
+%
+%     \def\doverbatim#1@end verbatim{#1}
+%
+% For Texinfo it's a lot easier than for LaTeX,
+% because texinfo's \verbatim doesn't stop at '\end{verbatim}':
+% we need not redefine '\', '{' and '}'.
+%
+% Inspired by LaTeX's verbatim command set [latex.ltx]
+%
+\begingroup
+  \catcode`\ =\active
+  \obeylines %
+  % ignore everything up to the first ^^M, that's the newline at the end
+  % of the @verbatim input line itself.  Otherwise we get an extra blank
+  % line in the output.
+  \xdef\doverbatim#1^^M#2@end verbatim{#2\noexpand\end\gobble verbatim}%
+  % We really want {...\end verbatim} in the body of the macro, but
+  % without the active space; thus we have to use \xdef and \gobble.
+\endgroup
+%
+\envdef\verbatim{%
+    \setupverbatim\doverbatim
+}
+\let\Everbatim = \afterenvbreak
+
+
+% @verbatiminclude FILE - insert text of file in verbatim environment.
+%
+\def\verbatiminclude{\parseargusing\filenamecatcodes\doverbatiminclude}
+%
+\def\doverbatiminclude#1{%
+  {%
+    \makevalueexpandable
+    \setupverbatim
+    \indexnofonts       % Allow `@@' and other weird things in file names.
+    \wlog{texinfo.tex: doing @verbatiminclude of #1^^J}%
+    \input #1
+    \afterenvbreak
+  }%
+}
+
+% @copying ... @end copying.
+% Save the text away for @insertcopying later.
+%
+% We save the uninterpreted tokens, rather than creating a box.
+% Saving the text in a box would be much easier, but then all the
+% typesetting commands (@smallbook, font changes, etc.) have to be done
+% beforehand -- and a) we want @copying to be done first in the source
+% file; b) letting users define the frontmatter in as flexible order as
+% possible is very desirable.
+%
+\def\copying{\checkenv{}\begingroup\scanargctxt\docopying}
+\def\docopying#1@end copying{\endgroup\def\copyingtext{#1}}
+%
+\def\insertcopying{%
+  \begingroup
+    \parindent = 0pt  % paragraph indentation looks wrong on title page
+    \scanexp\copyingtext
+  \endgroup
+}
+
+
+\message{defuns,}
+% @defun etc.
+
+\newskip\defbodyindent \defbodyindent=.4in
+\newskip\defargsindent \defargsindent=50pt
+\newskip\deflastargmargin \deflastargmargin=18pt
+\newcount\defunpenalty
+
+% Start the processing of @deffn:
+\def\startdefun{%
+  \ifnum\lastpenalty<10000
+    \medbreak
+    \defunpenalty=10003 % Will keep this @deffn together with the
+                        % following @def command, see below.
+  \else
+    % If there are two @def commands in a row, we'll have a \nobreak,
+    % which is there to keep the function description together with its
+    % header.  But if there's nothing but headers, we need to allow a
+    % break somewhere.  Check specifically for penalty 10002, inserted
+    % by \printdefunline, instead of 10000, since the sectioning
+    % commands also insert a nobreak penalty, and we don't want to allow
+    % a break between a section heading and a defun.
+    %
+    % As a further refinement, we avoid "club" headers by signalling
+    % with penalty of 10003 after the very first @deffn in the
+    % sequence (see above), and penalty of 10002 after any following
+    % @def command.
+    \ifnum\lastpenalty=10002 \penalty2000 \else \defunpenalty=10002 \fi
+    %
+    % Similarly, after a section heading, do not allow a break.
+    % But do insert the glue.
+    \medskip  % preceded by discardable penalty, so not a breakpoint
+  \fi
+  %
+  \parindent=0in
+  \advance\leftskip by \defbodyindent
+  \exdentamount=\defbodyindent
+}
+
+\def\dodefunx#1{%
+  % First, check whether we are in the right environment:
+  \checkenv#1%
+  %
+  % As above, allow line break if we have multiple x headers in a row.
+  % It's not a great place, though.
+  \ifnum\lastpenalty=10002 \penalty3000 \else \defunpenalty=10002 \fi
+  %
+  % And now, it's time to reuse the body of the original defun:
+  \expandafter\gobbledefun#1%
+}
+\def\gobbledefun#1\startdefun{}
+
+% \printdefunline \deffnheader{text}
+%
+\def\printdefunline#1#2{%
+  \begingroup
+    % call \deffnheader:
+    #1#2 \endheader
+    % common ending:
+    \interlinepenalty = 10000
+    \advance\rightskip by 0pt plus 1fil\relax
+    \endgraf
+    \nobreak\vskip -\parskip
+    \penalty\defunpenalty  % signal to \startdefun and \dodefunx
+    % Some of the @defun-type tags do not enable magic parentheses,
+    % rendering the following check redundant.  But we don't optimize.
+    \checkparencounts
+  \endgroup
+}
+
+\def\Edefun{\endgraf\medbreak}
+
+% \makedefun{deffn} creates \deffn, \deffnx and \Edeffn;
+% the only thing remaining is to define \deffnheader.
+%
+\def\makedefun#1{%
+  \expandafter\let\csname E#1\endcsname = \Edefun
+  \edef\temp{\noexpand\domakedefun
+    \makecsname{#1}\makecsname{#1x}\makecsname{#1header}}%
+  \temp
+}
+
+% \domakedefun \deffn \deffnx \deffnheader
+%
+% Define \deffn and \deffnx, without parameters.
+% \deffnheader has to be defined explicitly.
+%
+\def\domakedefun#1#2#3{%
+  \envdef#1{%
+    \startdefun
+    \doingtypefnfalse    % distinguish typed functions from all else
+    \parseargusing\activeparens{\printdefunline#3}%
+  }%
+  \def#2{\dodefunx#1}%
+  \def#3%
+}
+
+\newif\ifdoingtypefn       % doing typed function?
+\newif\ifrettypeownline    % typeset return type on its own line?
+
+% @deftypefnnewline on|off says whether the return type of typed functions
+% are printed on their own line.  This affects @deftypefn, @deftypefun,
+% @deftypeop, and @deftypemethod.
+% 
+\parseargdef\deftypefnnewline{%
+  \def\temp{#1}%
+  \ifx\temp\onword
+    \expandafter\let\csname SETtxideftypefnnl\endcsname
+      = \empty
+  \else\ifx\temp\offword
+    \expandafter\let\csname SETtxideftypefnnl\endcsname
+      = \relax
+  \else
+    \errhelp = \EMsimple
+    \errmessage{Unknown @txideftypefnnl value `\temp',
+                must be on|off}%
+  \fi\fi
+}
+
+% Untyped functions:
+
+% @deffn category name args
+\makedefun{deffn}{\deffngeneral{}}
+
+% @deffn category class name args
+\makedefun{defop}#1 {\defopon{#1\ \putwordon}}
+
+% \defopon {category on}class name args
+\def\defopon#1#2 {\deffngeneral{\putwordon\ \code{#2}}{#1\ \code{#2}} }
+
+% \deffngeneral {subind}category name args
+%
+\def\deffngeneral#1#2 #3 #4\endheader{%
+  % Remember that \dosubind{fn}{foo}{} is equivalent to \doind{fn}{foo}.
+  \dosubind{fn}{\code{#3}}{#1}%
+  \defname{#2}{}{#3}\magicamp\defunargs{#4\unskip}%
+}
+
+% Typed functions:
+
+% @deftypefn category type name args
+\makedefun{deftypefn}{\deftypefngeneral{}}
+
+% @deftypeop category class type name args
+\makedefun{deftypeop}#1 {\deftypeopon{#1\ \putwordon}}
+
+% \deftypeopon {category on}class type name args
+\def\deftypeopon#1#2 {\deftypefngeneral{\putwordon\ \code{#2}}{#1\ \code{#2}} }
+
+% \deftypefngeneral {subind}category type name args
+%
+\def\deftypefngeneral#1#2 #3 #4 #5\endheader{%
+  \dosubind{fn}{\code{#4}}{#1}%
+  \doingtypefntrue
+  \defname{#2}{#3}{#4}\defunargs{#5\unskip}%
+}
+
+% Typed variables:
+
+% @deftypevr category type var args
+\makedefun{deftypevr}{\deftypecvgeneral{}}
+
+% @deftypecv category class type var args
+\makedefun{deftypecv}#1 {\deftypecvof{#1\ \putwordof}}
+
+% \deftypecvof {category of}class type var args
+\def\deftypecvof#1#2 {\deftypecvgeneral{\putwordof\ \code{#2}}{#1\ \code{#2}} }
+
+% \deftypecvgeneral {subind}category type var args
+%
+\def\deftypecvgeneral#1#2 #3 #4 #5\endheader{%
+  \dosubind{vr}{\code{#4}}{#1}%
+  \defname{#2}{#3}{#4}\defunargs{#5\unskip}%
+}
+
+% Untyped variables:
+
+% @defvr category var args
+\makedefun{defvr}#1 {\deftypevrheader{#1} {} }
+
+% @defcv category class var args
+\makedefun{defcv}#1 {\defcvof{#1\ \putwordof}}
+
+% \defcvof {category of}class var args
+\def\defcvof#1#2 {\deftypecvof{#1}#2 {} }
+
+% Types:
+
+% @deftp category name args
+\makedefun{deftp}#1 #2 #3\endheader{%
+  \doind{tp}{\code{#2}}%
+  \defname{#1}{}{#2}\defunargs{#3\unskip}%
+}
+
+% Remaining @defun-like shortcuts:
+\makedefun{defun}{\deffnheader{\putwordDeffunc} }
+\makedefun{defmac}{\deffnheader{\putwordDefmac} }
+\makedefun{defspec}{\deffnheader{\putwordDefspec} }
+\makedefun{deftypefun}{\deftypefnheader{\putwordDeffunc} }
+\makedefun{defvar}{\defvrheader{\putwordDefvar} }
+\makedefun{defopt}{\defvrheader{\putwordDefopt} }
+\makedefun{deftypevar}{\deftypevrheader{\putwordDefvar} }
+\makedefun{defmethod}{\defopon\putwordMethodon}
+\makedefun{deftypemethod}{\deftypeopon\putwordMethodon}
+\makedefun{defivar}{\defcvof\putwordInstanceVariableof}
+\makedefun{deftypeivar}{\deftypecvof\putwordInstanceVariableof}
+
+% \defname, which formats the name of the @def (not the args).
+% #1 is the category, such as "Function".
+% #2 is the return type, if any.
+% #3 is the function name.
+%
+% We are followed by (but not passed) the arguments, if any.
+%
+\def\defname#1#2#3{%
+  \par
+  % Get the values of \leftskip and \rightskip as they were outside the @def...
+  \advance\leftskip by -\defbodyindent
+  %
+  % Determine if we are typesetting the return type of a typed function
+  % on a line by itself.
+  \rettypeownlinefalse
+  \ifdoingtypefn  % doing a typed function specifically?
+    % then check user option for putting return type on its own line:
+    \expandafter\ifx\csname SETtxideftypefnnl\endcsname\relax \else
+      \rettypeownlinetrue
+    \fi
+  \fi
+  %
+  % How we'll format the category name.  Putting it in brackets helps
+  % distinguish it from the body text that may end up on the next line
+  % just below it.
+  \def\temp{#1}%
+  \setbox0=\hbox{\kern\deflastargmargin \ifx\temp\empty\else [\rm\temp]\fi}
+  %
+  % Figure out line sizes for the paragraph shape.  We'll always have at
+  % least two.
+  \tempnum = 2
+  %
+  % The first line needs space for \box0; but if \rightskip is nonzero,
+  % we need only space for the part of \box0 which exceeds it:
+  \dimen0=\hsize  \advance\dimen0 by -\wd0  \advance\dimen0 by \rightskip
+  %
+  % If doing a return type on its own line, we'll have another line.
+  \ifrettypeownline
+    \advance\tempnum by 1
+    \def\maybeshapeline{0in \hsize}%
+  \else
+    \def\maybeshapeline{}%
+  \fi
+  %
+  % The continuations:
+  \dimen2=\hsize  \advance\dimen2 by -\defargsindent
+  %
+  % The final paragraph shape:
+  \parshape \tempnum  0in \dimen0  \maybeshapeline  \defargsindent \dimen2
+  %
+  % Put the category name at the right margin.
+  \noindent
+  \hbox to 0pt{%
+    \hfil\box0 \kern-\hsize
+    % \hsize has to be shortened this way:
+    \kern\leftskip
+    % Intentionally do not respect \rightskip, since we need the space.
+  }%
+  %
+  % Allow all lines to be underfull without complaint:
+  \tolerance=10000 \hbadness=10000
+  \exdentamount=\defbodyindent
+  {%
+    % defun fonts. We use typewriter by default (used to be bold) because:
+    % . we're printing identifiers, they should be in tt in principle.
+    % . in languages with many accents, such as Czech or French, it's
+    %   common to leave accents off identifiers.  The result looks ok in
+    %   tt, but exceedingly strange in rm.
+    % . we don't want -- and --- to be treated as ligatures.
+    % . this still does not fix the ?` and !` ligatures, but so far no
+    %   one has made identifiers using them :).
+    \df \tt
+    \def\temp{#2}% text of the return type
+    \ifx\temp\empty\else
+      \tclose{\temp}% typeset the return type
+      \ifrettypeownline
+        % put return type on its own line; prohibit line break following:
+        \hfil\vadjust{\nobreak}\break  
+      \else
+        \space  % type on same line, so just followed by a space
+      \fi
+    \fi           % no return type
+    #3% output function name
+  }%
+  {\rm\enskip}% hskip 0.5 em of \tenrm
+  %
+  \boldbrax
+  % arguments will be output next, if any.
+}
+
+% Print arguments in slanted roman (not ttsl), inconsistently with using
+% tt for the name.  This is because literal text is sometimes needed in
+% the argument list (groff manual), and ttsl and tt are not very
+% distinguishable.  Prevent hyphenation at `-' chars.
+%
+\def\defunargs#1{%
+  % use sl by default (not ttsl),
+  % tt for the names.
+  \df \sl \hyphenchar\font=0
+  %
+  % On the other hand, if an argument has two dashes (for instance), we
+  % want a way to get ttsl.  We used to recommend @var for that, so
+  % leave the code in, but it's strange for @var to lead to typewriter.
+  % Nowadays we recommend @code, since the difference between a ttsl hyphen
+  % and a tt hyphen is pretty tiny.  @code also disables ?` !`.
+  \def\var##1{{\setupmarkupstyle{var}\ttslanted{##1}}}%
+  #1%
+  \sl\hyphenchar\font=45
+}
+
+% We want ()&[] to print specially on the defun line.
+%
+\def\activeparens{%
+  \catcode`\(=\active \catcode`\)=\active
+  \catcode`\[=\active \catcode`\]=\active
+  \catcode`\&=\active
+}
+
+% Make control sequences which act like normal parenthesis chars.
+\let\lparen = ( \let\rparen = )
+
+% Be sure that we always have a definition for `(', etc.  For example,
+% if the fn name has parens in it, \boldbrax will not be in effect yet,
+% so TeX would otherwise complain about undefined control sequence.
+{
+  \activeparens
+  \global\let(=\lparen \global\let)=\rparen
+  \global\let[=\lbrack \global\let]=\rbrack
+  \global\let& = \&
+
+  \gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb}
+  \gdef\magicamp{\let&=\amprm}
+}
+
+\newcount\parencount
+
+% If we encounter &foo, then turn on ()-hacking afterwards
+\newif\ifampseen
+\def\amprm#1 {\ampseentrue{\bf\&#1 }}
+
+\def\parenfont{%
+  \ifampseen
+    % At the first level, print parens in roman,
+    % otherwise use the default font.
+    \ifnum \parencount=1 \rm \fi
+  \else
+    % The \sf parens (in \boldbrax) actually are a little bolder than
+    % the contained text.  This is especially needed for [ and ] .
+    \sf
+  \fi
+}
+\def\infirstlevel#1{%
+  \ifampseen
+    \ifnum\parencount=1
+      #1%
+    \fi
+  \fi
+}
+\def\bfafterword#1 {#1 \bf}
+
+\def\opnr{%
+  \global\advance\parencount by 1
+  {\parenfont(}%
+  \infirstlevel \bfafterword
+}
+\def\clnr{%
+  {\parenfont)}%
+  \infirstlevel \sl
+  \global\advance\parencount by -1
+}
+
+\newcount\brackcount
+\def\lbrb{%
+  \global\advance\brackcount by 1
+  {\bf[}%
+}
+\def\rbrb{%
+  {\bf]}%
+  \global\advance\brackcount by -1
+}
+
+\def\checkparencounts{%
+  \ifnum\parencount=0 \else \badparencount \fi
+  \ifnum\brackcount=0 \else \badbrackcount \fi
+}
+% these should not use \errmessage; the glibc manual, at least, actually
+% has such constructs (when documenting function pointers).
+\def\badparencount{%
+  \message{Warning: unbalanced parentheses in @def...}%
+  \global\parencount=0
+}
+\def\badbrackcount{%
+  \message{Warning: unbalanced square brackets in @def...}%
+  \global\brackcount=0
+}
+
+
+\message{macros,}
+% @macro.
+
+% To do this right we need a feature of e-TeX, \scantokens,
+% which we arrange to emulate with a temporary file in ordinary TeX.
+\ifx\eTeXversion\thisisundefined
+  \newwrite\macscribble
+  \def\scantokens#1{%
+    \toks0={#1}%
+    \immediate\openout\macscribble=\jobname.tmp
+    \immediate\write\macscribble{\the\toks0}%
+    \immediate\closeout\macscribble
+    \input \jobname.tmp
+  }
+\fi
+
+\def\scanmacro#1{\begingroup
+  \newlinechar`\^^M
+  \let\xeatspaces\eatspaces
+  %
+  % Undo catcode changes of \startcontents and \doprintindex
+  % When called from @insertcopying or (short)caption, we need active
+  % backslash to get it printed correctly.  Previously, we had
+  % \catcode`\\=\other instead.  We'll see whether a problem appears
+  % with macro expansion.				--kasal, 19aug04
+  \catcode`\@=0 \catcode`\\=\active \escapechar=`\@
+  %
+  % ... and for \example:
+  \spaceisspace
+  %
+  % The \empty here causes a following catcode 5 newline to be eaten as
+  % part of reading whitespace after a control sequence.  It does not
+  % eat a catcode 13 newline.  There's no good way to handle the two
+  % cases (untried: maybe e-TeX's \everyeof could help, though plain TeX
+  % would then have different behavior).  See the Macro Details node in
+  % the manual for the workaround we recommend for macros and
+  % line-oriented commands.
+  % 
+  \scantokens{#1\empty}%
+\endgroup}
+
+\def\scanexp#1{%
+  \edef\temp{\noexpand\scanmacro{#1}}%
+  \temp
+}
+
+\newcount\paramno   % Count of parameters
+\newtoks\macname    % Macro name
+\newif\ifrecursive  % Is it recursive?
+
+% List of all defined macros in the form
+%    \definedummyword\macro1\definedummyword\macro2...
+% Currently is also contains all @aliases; the list can be split
+% if there is a need.
+\def\macrolist{}
+
+% Add the macro to \macrolist
+\def\addtomacrolist#1{\expandafter \addtomacrolistxxx \csname#1\endcsname}
+\def\addtomacrolistxxx#1{%
+     \toks0 = \expandafter{\macrolist\definedummyword#1}%
+     \xdef\macrolist{\the\toks0}%
+}
+
+% Utility routines.
+% This does \let #1 = #2, with \csnames; that is,
+%   \let \csname#1\endcsname = \csname#2\endcsname
+% (except of course we have to play expansion games).
+%
+\def\cslet#1#2{%
+  \expandafter\let
+  \csname#1\expandafter\endcsname
+  \csname#2\endcsname
+}
+
+% Trim leading and trailing spaces off a string.
+% Concepts from aro-bend problem 15 (see CTAN).
+{\catcode`\@=11
+\gdef\eatspaces #1{\expandafter\trim@\expandafter{#1 }}
+\gdef\trim@ #1{\trim@@ @#1 @ #1 @ @@}
+\gdef\trim@@ #1@ #2@ #3@@{\trim@@@\empty #2 @}
+\def\unbrace#1{#1}
+\unbrace{\gdef\trim@@@ #1 } #2@{#1}
+}
+
+% Trim a single trailing ^^M off a string.
+{\catcode`\^^M=\other \catcode`\Q=3%
+\gdef\eatcr #1{\eatcra #1Q^^MQ}%
+\gdef\eatcra#1^^MQ{\eatcrb#1Q}%
+\gdef\eatcrb#1Q#2Q{#1}%
+}
+
+% Macro bodies are absorbed as an argument in a context where
+% all characters are catcode 10, 11 or 12, except \ which is active
+% (as in normal texinfo). It is necessary to change the definition of \
+% to recognize macro arguments; this is the job of \mbodybackslash.
+%
+% Non-ASCII encodings make 8-bit characters active, so un-activate
+% them to avoid their expansion.  Must do this non-globally, to
+% confine the change to the current group.
+%
+% It's necessary to have hard CRs when the macro is executed. This is
+% done by making ^^M (\endlinechar) catcode 12 when reading the macro
+% body, and then making it the \newlinechar in \scanmacro.
+%
+\def\scanctxt{% used as subroutine
+  \catcode`\"=\other
+  \catcode`\+=\other
+  \catcode`\<=\other
+  \catcode`\>=\other
+  \catcode`\@=\other
+  \catcode`\^=\other
+  \catcode`\_=\other
+  \catcode`\|=\other
+  \catcode`\~=\other
+  \ifx\declaredencoding\ascii \else \setnonasciicharscatcodenonglobal\other \fi
+}
+
+\def\scanargctxt{% used for copying and captions, not macros.
+  \scanctxt
+  \catcode`\\=\other
+  \catcode`\^^M=\other
+}
+
+\def\macrobodyctxt{% used for @macro definitions
+  \scanctxt
+  \catcode`\{=\other
+  \catcode`\}=\other
+  \catcode`\^^M=\other
+  \usembodybackslash
+}
+
+\def\macroargctxt{% used when scanning invocations
+  \scanctxt
+  \catcode`\\=0
+}
+% why catcode 0 for \ in the above?  To recognize \\ \{ \} as "escapes"
+% for the single characters \ { }.  Thus, we end up with the "commands"
+% that would be written @\ @{ @} in a Texinfo document.
+% 
+% We already have @{ and @}.  For @\, we define it here, and only for
+% this purpose, to produce a typewriter backslash (so, the @\ that we
+% define for @math can't be used with @macro calls):
+%
+\def\\{\normalbackslash}%
+% 
+% We would like to do this for \, too, since that is what makeinfo does.
+% But it is not possible, because Texinfo already has a command @, for a
+% cedilla accent.  Documents must use @comma{} instead.
+%
+% \anythingelse will almost certainly be an error of some kind.
+
+
+% \mbodybackslash is the definition of \ in @macro bodies.
+% It maps \foo\ => \csname macarg.foo\endcsname => #N
+% where N is the macro parameter number.
+% We define \csname macarg.\endcsname to be \realbackslash, so
+% \\ in macro replacement text gets you a backslash.
+%
+{\catcode`@=0 @catcode`@\=@active
+ @gdef@usembodybackslash{@let\=@mbodybackslash}
+ @gdef@mbodybackslash#1\{@csname macarg.#1@endcsname}
+}
+\expandafter\def\csname macarg.\endcsname{\realbackslash}
+
+\def\margbackslash#1{\char`\#1 }
+
+\def\macro{\recursivefalse\parsearg\macroxxx}
+\def\rmacro{\recursivetrue\parsearg\macroxxx}
+
+\def\macroxxx#1{%
+  \getargs{#1}% now \macname is the macname and \argl the arglist
+  \ifx\argl\empty       % no arguments
+     \paramno=0\relax
+  \else
+     \expandafter\parsemargdef \argl;%
+     \if\paramno>256\relax
+       \ifx\eTeXversion\thisisundefined
+         \errhelp = \EMsimple
+         \errmessage{You need eTeX to compile a file with macros with more than 256 arguments}
+       \fi
+     \fi
+  \fi
+  \if1\csname ismacro.\the\macname\endcsname
+     \message{Warning: redefining \the\macname}%
+  \else
+     \expandafter\ifx\csname \the\macname\endcsname \relax
+     \else \errmessage{Macro name \the\macname\space already defined}\fi
+     \global\cslet{macsave.\the\macname}{\the\macname}%
+     \global\expandafter\let\csname ismacro.\the\macname\endcsname=1%
+     \addtomacrolist{\the\macname}%
+  \fi
+  \begingroup \macrobodyctxt
+  \ifrecursive \expandafter\parsermacbody
+  \else \expandafter\parsemacbody
+  \fi}
+
+\parseargdef\unmacro{%
+  \if1\csname ismacro.#1\endcsname
+    \global\cslet{#1}{macsave.#1}%
+    \global\expandafter\let \csname ismacro.#1\endcsname=0%
+    % Remove the macro name from \macrolist:
+    \begingroup
+      \expandafter\let\csname#1\endcsname \relax
+      \let\definedummyword\unmacrodo
+      \xdef\macrolist{\macrolist}%
+    \endgroup
+  \else
+    \errmessage{Macro #1 not defined}%
+  \fi
+}
+
+% Called by \do from \dounmacro on each macro.  The idea is to omit any
+% macro definitions that have been changed to \relax.
+%
+\def\unmacrodo#1{%
+  \ifx #1\relax
+    % remove this
+  \else
+    \noexpand\definedummyword \noexpand#1%
+  \fi
+}
+
+% This makes use of the obscure feature that if the last token of a
+% <parameter list> is #, then the preceding argument is delimited by
+% an opening brace, and that opening brace is not consumed.
+\def\getargs#1{\getargsxxx#1{}}
+\def\getargsxxx#1#{\getmacname #1 \relax\getmacargs}
+\def\getmacname#1 #2\relax{\macname={#1}}
+\def\getmacargs#1{\def\argl{#1}}
+
+% For macro processing make @ a letter so that we can make Texinfo private macro names.
+\edef\texiatcatcode{\the\catcode`\@}
+\catcode `@=11\relax
+
+% Parse the optional {params} list.  Set up \paramno and \paramlist
+% so \defmacro knows what to do.  Define \macarg.BLAH for each BLAH
+% in the params list to some hook where the argument si to be expanded.  If
+% there are less than 10 arguments that hook is to be replaced by ##N where N
+% is the position in that list, that is to say the macro arguments are to be
+% defined `a la TeX in the macro body.  
+%
+% That gets used by \mbodybackslash (above).
+%
+% We need to get `macro parameter char #' into several definitions.
+% The technique used is stolen from LaTeX: let \hash be something
+% unexpandable, insert that wherever you need a #, and then redefine
+% it to # just before using the token list produced.
+%
+% The same technique is used to protect \eatspaces till just before
+% the macro is used.
+%
+% If there are 10 or more arguments, a different technique is used, where the
+% hook remains in the body, and when macro is to be expanded the body is
+% processed again to replace the arguments.
+%
+% In that case, the hook is \the\toks N-1, and we simply set \toks N-1 to the
+% argument N value and then \edef  the body (nothing else will expand because of
+% the catcode regime underwhich the body was input).
+%
+% If you compile with TeX (not eTeX), and you have macros with 10 or more
+% arguments, you need that no macro has more than 256 arguments, otherwise an
+% error is produced.
+\def\parsemargdef#1;{%
+  \paramno=0\def\paramlist{}%
+  \let\hash\relax
+  \let\xeatspaces\relax
+  \parsemargdefxxx#1,;,%
+  % In case that there are 10 or more arguments we parse again the arguments
+  % list to set new definitions for the \macarg.BLAH macros corresponding to
+  % each BLAH argument. It was anyhow needed to parse already once this list
+  % in order to count the arguments, and as macros with at most 9 arguments
+  % are by far more frequent than macro with 10 or more arguments, defining
+  % twice the \macarg.BLAH macros does not cost too much processing power.
+  \ifnum\paramno<10\relax\else
+    \paramno0\relax
+    \parsemmanyargdef@@#1,;,% 10 or more arguments
+  \fi
+}
+\def\parsemargdefxxx#1,{%
+  \if#1;\let\next=\relax
+  \else \let\next=\parsemargdefxxx
+    \advance\paramno by 1
+    \expandafter\edef\csname macarg.\eatspaces{#1}\endcsname
+        {\xeatspaces{\hash\the\paramno}}%
+    \edef\paramlist{\paramlist\hash\the\paramno,}%
+  \fi\next}
+
+\def\parsemmanyargdef@@#1,{%
+  \if#1;\let\next=\relax
+  \else 
+    \let\next=\parsemmanyargdef@@
+    \edef\tempb{\eatspaces{#1}}%
+    \expandafter\def\expandafter\tempa
+       \expandafter{\csname macarg.\tempb\endcsname}%
+    % Note that we need some extra \noexpand\noexpand, this is because we
+    % don't want \the  to be expanded in the \parsermacbody  as it uses an
+    % \xdef .
+    \expandafter\edef\tempa
+      {\noexpand\noexpand\noexpand\the\toks\the\paramno}%
+    \advance\paramno by 1\relax
+  \fi\next}
+
+% These two commands read recursive and nonrecursive macro bodies.
+% (They're different since rec and nonrec macros end differently.)
+%
+
+\catcode `\@\texiatcatcode
+\long\def\parsemacbody#1@end macro%
+{\xdef\temp{\eatcr{#1}}\endgroup\defmacro}%
+\long\def\parsermacbody#1@end rmacro%
+{\xdef\temp{\eatcr{#1}}\endgroup\defmacro}%
+\catcode `\@=11\relax
+
+\let\endargs@\relax
+\let\nil@\relax
+\def\nilm@{\nil@}%
+\long\def\nillm@{\nil@}%
+
+% This macro is expanded during the Texinfo macro expansion, not during its
+% definition.  It gets all the arguments values and assigns them to macros
+% macarg.ARGNAME
+%
+% #1 is the macro name
+% #2 is the list of argument names
+% #3 is the list of argument values
+\def\getargvals@#1#2#3{%
+  \def\macargdeflist@{}%
+  \def\saveparamlist@{#2}% Need to keep a copy for parameter expansion.
+  \def\paramlist{#2,\nil@}%
+  \def\macroname{#1}%
+  \begingroup
+  \macroargctxt
+  \def\argvaluelist{#3,\nil@}%
+  \def\@tempa{#3}%
+  \ifx\@tempa\empty
+    \setemptyargvalues@
+  \else
+    \getargvals@@
+  \fi
+}
+
+% 
+\def\getargvals@@{%
+  \ifx\paramlist\nilm@
+      % Some sanity check needed here that \argvaluelist is also empty.
+      \ifx\argvaluelist\nillm@
+      \else
+        \errhelp = \EMsimple
+        \errmessage{Too many arguments in macro `\macroname'!}%
+      \fi
+      \let\next\macargexpandinbody@
+  \else
+    \ifx\argvaluelist\nillm@
+       % No more arguments values passed to macro.  Set remaining named-arg
+       % macros to empty.
+       \let\next\setemptyargvalues@
+    \else
+      % pop current arg name into \@tempb
+      \def\@tempa##1{\pop@{\@tempb}{\paramlist}##1\endargs@}%
+      \expandafter\@tempa\expandafter{\paramlist}%
+       % pop current argument value into \@tempc
+      \def\@tempa##1{\longpop@{\@tempc}{\argvaluelist}##1\endargs@}%
+      \expandafter\@tempa\expandafter{\argvaluelist}%
+       % Here \@tempb is the current arg name and \@tempc is the current arg value.
+       % First place the new argument macro definition into \@tempd
+       \expandafter\macname\expandafter{\@tempc}%
+       \expandafter\let\csname macarg.\@tempb\endcsname\relax
+       \expandafter\def\expandafter\@tempe\expandafter{%
+         \csname macarg.\@tempb\endcsname}%
+       \edef\@tempd{\long\def\@tempe{\the\macname}}%
+       \push@\@tempd\macargdeflist@
+       \let\next\getargvals@@
+    \fi
+  \fi
+  \next
+}
+
+\def\push@#1#2{%
+  \expandafter\expandafter\expandafter\def
+  \expandafter\expandafter\expandafter#2%
+  \expandafter\expandafter\expandafter{%
+  \expandafter#1#2}%
+}
+
+% Replace arguments by their values in the macro body, and place the result
+% in macro \@tempa
+\def\macvalstoargs@{%
+  %  To do this we use the property that token registers that are \the'ed
+  % within an \edef  expand only once. So we are going to place all argument
+  % values into respective token registers.
+  %
+  % First we save the token context, and initialize argument numbering.
+  \begingroup
+    \paramno0\relax
+    % Then, for each argument number #N, we place the corresponding argument
+    % value into a new token list register \toks#N
+    \expandafter\putargsintokens@\saveparamlist@,;,%
+    % Then, we expand the body so that argument are replaced by their
+    % values. The trick for values not to be expanded themselves is that they
+    % are within tokens and that tokens expand only once in an \edef .
+    \edef\@tempc{\csname mac.\macroname .body\endcsname}%
+    % Now we restore the token stack pointer to free the token list registers
+    % which we have used, but we make sure that expanded body is saved after
+    % group.
+    \expandafter
+  \endgroup
+  \expandafter\def\expandafter\@tempa\expandafter{\@tempc}%
+  }
+
+\def\macargexpandinbody@{% 
+  %% Define the named-macro outside of this group and then close this group. 
+  \expandafter
+  \endgroup
+  \macargdeflist@
+  % First the replace in body the macro arguments by their values, the result
+  % is in \@tempa .
+  \macvalstoargs@
+  % Then we point at the \norecurse or \gobble (for recursive) macro value
+  % with \@tempb .
+  \expandafter\let\expandafter\@tempb\csname mac.\macroname .recurse\endcsname
+  % Depending on whether it is recursive or not, we need some tailing
+  % \egroup .
+  \ifx\@tempb\gobble
+     \let\@tempc\relax
+  \else
+     \let\@tempc\egroup
+  \fi
+  % And now we do the real job:
+  \edef\@tempd{\noexpand\@tempb{\macroname}\noexpand\scanmacro{\@tempa}\@tempc}%
+  \@tempd
+}
+
+\def\putargsintokens@#1,{%
+  \if#1;\let\next\relax
+  \else
+    \let\next\putargsintokens@
+    % First we allocate the new token list register, and give it a temporary
+    % alias \@tempb .
+    \toksdef\@tempb\the\paramno
+    % Then we place the argument value into that token list register.
+    \expandafter\let\expandafter\@tempa\csname macarg.#1\endcsname
+    \expandafter\@tempb\expandafter{\@tempa}%
+    \advance\paramno by 1\relax
+  \fi
+  \next
+}
+
+% Save the token stack pointer into macro #1
+\def\texisavetoksstackpoint#1{\edef#1{\the\@cclvi}}
+% Restore the token stack pointer from number in macro #1
+\def\texirestoretoksstackpoint#1{\expandafter\mathchardef\expandafter\@cclvi#1\relax}
+% newtoks that can be used non \outer .
+\def\texinonouternewtoks{\alloc@ 5\toks \toksdef \@cclvi}
+
+% Tailing missing arguments are set to empty
+\def\setemptyargvalues@{%
+  \ifx\paramlist\nilm@
+    \let\next\macargexpandinbody@
+  \else
+    \expandafter\setemptyargvaluesparser@\paramlist\endargs@
+    \let\next\setemptyargvalues@
+  \fi
+  \next
+}
+
+\def\setemptyargvaluesparser@#1,#2\endargs@{%
+  \expandafter\def\expandafter\@tempa\expandafter{%
+    \expandafter\def\csname macarg.#1\endcsname{}}%
+  \push@\@tempa\macargdeflist@
+  \def\paramlist{#2}%
+}
+
+% #1 is the element target macro
+% #2 is the list macro
+% #3,#4\endargs@ is the list value
+\def\pop@#1#2#3,#4\endargs@{%
+   \def#1{#3}%
+   \def#2{#4}%
+}
+\long\def\longpop@#1#2#3,#4\endargs@{%
+   \long\def#1{#3}%
+   \long\def#2{#4}%
+}
+
+% This defines a Texinfo @macro. There are eight cases: recursive and
+% nonrecursive macros of zero, one, up to nine, and many arguments.
+% Much magic with \expandafter here.
+% \xdef is used so that macro definitions will survive the file
+% they're defined in; @include reads the file inside a group.
+%
+\def\defmacro{%
+  \let\hash=##% convert placeholders to macro parameter chars
+  \ifrecursive
+    \ifcase\paramno
+    % 0
+      \expandafter\xdef\csname\the\macname\endcsname{%
+        \noexpand\scanmacro{\temp}}%
+    \or % 1
+      \expandafter\xdef\csname\the\macname\endcsname{%
+         \bgroup\noexpand\macroargctxt
+         \noexpand\braceorline
+         \expandafter\noexpand\csname\the\macname xxx\endcsname}%
+      \expandafter\xdef\csname\the\macname xxx\endcsname##1{%
+         \egroup\noexpand\scanmacro{\temp}}%
+    \else
+      \ifnum\paramno<10\relax % at most 9
+        \expandafter\xdef\csname\the\macname\endcsname{%
+           \bgroup\noexpand\macroargctxt
+           \noexpand\csname\the\macname xx\endcsname}%
+        \expandafter\xdef\csname\the\macname xx\endcsname##1{%
+            \expandafter\noexpand\csname\the\macname xxx\endcsname ##1,}%
+        \expandafter\expandafter
+        \expandafter\xdef
+        \expandafter\expandafter
+          \csname\the\macname xxx\endcsname
+            \paramlist{\egroup\noexpand\scanmacro{\temp}}%
+      \else % 10 or more
+        \expandafter\xdef\csname\the\macname\endcsname{%
+          \noexpand\getargvals@{\the\macname}{\argl}%
+        }%    
+        \global\expandafter\let\csname mac.\the\macname .body\endcsname\temp
+        \global\expandafter\let\csname mac.\the\macname .recurse\endcsname\gobble
+      \fi
+    \fi
+  \else
+    \ifcase\paramno
+    % 0
+      \expandafter\xdef\csname\the\macname\endcsname{%
+        \noexpand\norecurse{\the\macname}%
+        \noexpand\scanmacro{\temp}\egroup}%
+    \or % 1
+      \expandafter\xdef\csname\the\macname\endcsname{%
+         \bgroup\noexpand\macroargctxt
+         \noexpand\braceorline
+         \expandafter\noexpand\csname\the\macname xxx\endcsname}%
+      \expandafter\xdef\csname\the\macname xxx\endcsname##1{%
+        \egroup
+        \noexpand\norecurse{\the\macname}%
+        \noexpand\scanmacro{\temp}\egroup}%
+    \else % at most 9
+      \ifnum\paramno<10\relax
+        \expandafter\xdef\csname\the\macname\endcsname{%
+           \bgroup\noexpand\macroargctxt
+           \expandafter\noexpand\csname\the\macname xx\endcsname}%
+        \expandafter\xdef\csname\the\macname xx\endcsname##1{%
+            \expandafter\noexpand\csname\the\macname xxx\endcsname ##1,}%
+        \expandafter\expandafter
+        \expandafter\xdef
+        \expandafter\expandafter
+        \csname\the\macname xxx\endcsname
+        \paramlist{%
+            \egroup
+            \noexpand\norecurse{\the\macname}%
+            \noexpand\scanmacro{\temp}\egroup}%
+      \else % 10 or more:
+        \expandafter\xdef\csname\the\macname\endcsname{%
+          \noexpand\getargvals@{\the\macname}{\argl}%
+        }%
+        \global\expandafter\let\csname mac.\the\macname .body\endcsname\temp
+        \global\expandafter\let\csname mac.\the\macname .recurse\endcsname\norecurse
+      \fi
+    \fi
+  \fi}
+
+\catcode `\@\texiatcatcode\relax
+
+\def\norecurse#1{\bgroup\cslet{#1}{macsave.#1}}
+
+% \braceorline decides whether the next nonwhitespace character is a
+% {.  If so it reads up to the closing }, if not, it reads the whole
+% line.  Whatever was read is then fed to the next control sequence
+% as an argument (by \parsebrace or \parsearg).
+% 
+\def\braceorline#1{\let\macnamexxx=#1\futurelet\nchar\braceorlinexxx}
+\def\braceorlinexxx{%
+  \ifx\nchar\bgroup\else
+    \expandafter\parsearg
+  \fi \macnamexxx}
+
+
+% @alias.
+% We need some trickery to remove the optional spaces around the equal
+% sign.  Make them active and then expand them all to nothing.
+%
+\def\alias{\parseargusing\obeyspaces\aliasxxx}
+\def\aliasxxx #1{\aliasyyy#1\relax}
+\def\aliasyyy #1=#2\relax{%
+  {%
+    \expandafter\let\obeyedspace=\empty
+    \addtomacrolist{#1}%
+    \xdef\next{\global\let\makecsname{#1}=\makecsname{#2}}%
+  }%
+  \next
+}
+
+
+\message{cross references,}
+
+\newwrite\auxfile
+\newif\ifhavexrefs    % True if xref values are known.
+\newif\ifwarnedxrefs  % True if we warned once that they aren't known.
+
+% @inforef is relatively simple.
+\def\inforef #1{\inforefzzz #1,,,,**}
+\def\inforefzzz #1,#2,#3,#4**{%
+  \putwordSee{} \putwordInfo{} \putwordfile{} \file{\ignorespaces #3{}},
+  node \samp{\ignorespaces#1{}}}
+
+% @node's only job in TeX is to define \lastnode, which is used in
+% cross-references.  The @node line might or might not have commas, and
+% might or might not have spaces before the first comma, like:
+% @node foo , bar , ...
+% We don't want such trailing spaces in the node name.
+%
+\parseargdef\node{\checkenv{}\donode #1 ,\finishnodeparse}
+%
+% also remove a trailing comma, in case of something like this:
+% @node Help-Cross,  ,  , Cross-refs
+\def\donode#1 ,#2\finishnodeparse{\dodonode #1,\finishnodeparse}
+\def\dodonode#1,#2\finishnodeparse{\gdef\lastnode{#1}}
+
+\let\nwnode=\node
+\let\lastnode=\empty
+
+% Write a cross-reference definition for the current node.  #1 is the
+% type (Ynumbered, Yappendix, Ynothing).
+%
+\def\donoderef#1{%
+  \ifx\lastnode\empty\else
+    \setref{\lastnode}{#1}%
+    \global\let\lastnode=\empty
+  \fi
+}
+
+% @anchor{NAME} -- define xref target at arbitrary point.
+%
+\newcount\savesfregister
+%
+\def\savesf{\relax \ifhmode \savesfregister=\spacefactor \fi}
+\def\restoresf{\relax \ifhmode \spacefactor=\savesfregister \fi}
+\def\anchor#1{\savesf \setref{#1}{Ynothing}\restoresf \ignorespaces}
+
+% \setref{NAME}{SNT} defines a cross-reference point NAME (a node or an
+% anchor), which consists of three parts:
+% 1) NAME-title - the current sectioning name taken from \lastsection,
+%                 or the anchor name.
+% 2) NAME-snt   - section number and type, passed as the SNT arg, or
+%                 empty for anchors.
+% 3) NAME-pg    - the page number.
+%
+% This is called from \donoderef, \anchor, and \dofloat.  In the case of
+% floats, there is an additional part, which is not written here:
+% 4) NAME-lof   - the text as it should appear in a @listoffloats.
+%
+\def\setref#1#2{%
+  \pdfmkdest{#1}%
+  \iflinks
+    {%
+      \atdummies  % preserve commands, but don't expand them
+      \edef\writexrdef##1##2{%
+	\write\auxfile{@xrdef{#1-% #1 of \setref, expanded by the \edef
+	  ##1}{##2}}% these are parameters of \writexrdef
+      }%
+      \toks0 = \expandafter{\lastsection}%
+      \immediate \writexrdef{title}{\the\toks0 }%
+      \immediate \writexrdef{snt}{\csname #2\endcsname}% \Ynumbered etc.
+      \safewhatsit{\writexrdef{pg}{\folio}}% will be written later, at \shipout
+    }%
+  \fi
+}
+
+% @xrefautosectiontitle on|off says whether @section(ing) names are used
+% automatically in xrefs, if the third arg is not explicitly specified.
+% This was provided as a "secret" @set xref-automatic-section-title
+% variable, now it's official.
+% 
+\parseargdef\xrefautomaticsectiontitle{%
+  \def\temp{#1}%
+  \ifx\temp\onword
+    \expandafter\let\csname SETxref-automatic-section-title\endcsname
+      = \empty
+  \else\ifx\temp\offword
+    \expandafter\let\csname SETxref-automatic-section-title\endcsname
+      = \relax
+  \else
+    \errhelp = \EMsimple
+    \errmessage{Unknown @xrefautomaticsectiontitle value `\temp',
+                must be on|off}%
+  \fi\fi
+}
+
+% 
+% @xref, @pxref, and @ref generate cross-references.  For \xrefX, #1 is
+% the node name, #2 the name of the Info cross-reference, #3 the printed
+% node name, #4 the name of the Info file, #5 the name of the printed
+% manual.  All but the node name can be omitted.
+%
+\def\pxref#1{\putwordsee{} \xrefX[#1,,,,,,,]}
+\def\xref#1{\putwordSee{} \xrefX[#1,,,,,,,]}
+\def\ref#1{\xrefX[#1,,,,,,,]}
+%
+\newbox\toprefbox
+\newbox\printedrefnamebox
+\newbox\infofilenamebox
+\newbox\printedmanualbox
+%
+\def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup
+  \unsepspaces
+  %
+  % Get args without leading/trailing spaces.
+  \def\printedrefname{\ignorespaces #3}%
+  \setbox\printedrefnamebox = \hbox{\printedrefname\unskip}%
+  %
+  \def\infofilename{\ignorespaces #4}%
+  \setbox\infofilenamebox = \hbox{\infofilename\unskip}%
+  %
+  \def\printedmanual{\ignorespaces #5}%
+  \setbox\printedmanualbox  = \hbox{\printedmanual\unskip}%
+  %
+  % If the printed reference name (arg #3) was not explicitly given in
+  % the @xref, figure out what we want to use.
+  \ifdim \wd\printedrefnamebox = 0pt
+    % No printed node name was explicitly given.
+    \expandafter\ifx\csname SETxref-automatic-section-title\endcsname \relax
+      % Not auto section-title: use node name inside the square brackets.
+      \def\printedrefname{\ignorespaces #1}%
+    \else
+      % Auto section-title: use chapter/section title inside
+      % the square brackets if we have it.
+      \ifdim \wd\printedmanualbox > 0pt
+        % It is in another manual, so we don't have it; use node name.
+        \def\printedrefname{\ignorespaces #1}%
+      \else
+        \ifhavexrefs
+          % We (should) know the real title if we have the xref values.
+          \def\printedrefname{\refx{#1-title}{}}%
+        \else
+          % Otherwise just copy the Info node name.
+          \def\printedrefname{\ignorespaces #1}%
+        \fi%
+      \fi
+    \fi
+  \fi
+  %
+  % Make link in pdf output.
+  \ifpdf
+    {\indexnofonts
+     \turnoffactive
+     \makevalueexpandable
+     % This expands tokens, so do it after making catcode changes, so _
+     % etc. don't get their TeX definitions.  This ignores all spaces in
+     % #4, including (wrongly) those in the middle of the filename.
+     \getfilename{#4}%
+     %
+     % This (wrongly) does not take account of leading or trailing
+     % spaces in #1, which should be ignored.
+     \edef\pdfxrefdest{#1}%
+     \ifx\pdfxrefdest\empty
+       \def\pdfxrefdest{Top}% no empty targets
+     \else
+       \txiescapepdf\pdfxrefdest  % escape PDF special chars
+     \fi
+     %
+     \leavevmode
+     \startlink attr{/Border [0 0 0]}%
+     \ifnum\filenamelength>0
+       goto file{\the\filename.pdf} name{\pdfxrefdest}%
+     \else
+       goto name{\pdfmkpgn{\pdfxrefdest}}%
+     \fi
+    }%
+    \setcolor{\linkcolor}%
+  \fi
+  %
+  % Float references are printed completely differently: "Figure 1.2"
+  % instead of "[somenode], p.3".  We distinguish them by the
+  % LABEL-title being set to a magic string.
+  {%
+    % Have to otherify everything special to allow the \csname to
+    % include an _ in the xref name, etc.
+    \indexnofonts
+    \turnoffactive
+    \expandafter\global\expandafter\let\expandafter\Xthisreftitle
+      \csname XR#1-title\endcsname
+  }%
+  \iffloat\Xthisreftitle
+    % If the user specified the print name (third arg) to the ref,
+    % print it instead of our usual "Figure 1.2".
+    \ifdim\wd\printedrefnamebox = 0pt
+      \refx{#1-snt}{}%
+    \else
+      \printedrefname
+    \fi
+    %
+    % If the user also gave the printed manual name (fifth arg), append
+    % "in MANUALNAME".
+    \ifdim \wd\printedmanualbox > 0pt
+      \space \putwordin{} \cite{\printedmanual}%
+    \fi
+  \else
+    % node/anchor (non-float) references.
+    % 
+    % If we use \unhbox to print the node names, TeX does not insert
+    % empty discretionaries after hyphens, which means that it will not
+    % find a line break at a hyphen in a node names.  Since some manuals
+    % are best written with fairly long node names, containing hyphens,
+    % this is a loss.  Therefore, we give the text of the node name
+    % again, so it is as if TeX is seeing it for the first time.
+    % 
+    \ifdim \wd\printedmanualbox > 0pt
+      % Cross-manual reference with a printed manual name.
+      % 
+      \crossmanualxref{\cite{\printedmanual\unskip}}%
+    %
+    \else\ifdim \wd\infofilenamebox > 0pt
+      % Cross-manual reference with only an info filename (arg 4), no
+      % printed manual name (arg 5).  This is essentially the same as
+      % the case above; we output the filename, since we have nothing else.
+      % 
+      \crossmanualxref{\code{\infofilename\unskip}}%
+    %
+    \else
+      % Reference within this manual.
+      %
+      % _ (for example) has to be the character _ for the purposes of the
+      % control sequence corresponding to the node, but it has to expand
+      % into the usual \leavevmode...\vrule stuff for purposes of
+      % printing. So we \turnoffactive for the \refx-snt, back on for the
+      % printing, back off for the \refx-pg.
+      {\turnoffactive
+       % Only output a following space if the -snt ref is nonempty; for
+       % @unnumbered and @anchor, it won't be.
+       \setbox2 = \hbox{\ignorespaces \refx{#1-snt}{}}%
+       \ifdim \wd2 > 0pt \refx{#1-snt}\space\fi
+      }%
+      % output the `[mynode]' via the macro below so it can be overridden.
+      \xrefprintnodename\printedrefname
+      %
+      % But we always want a comma and a space:
+      ,\space
+      %
+      % output the `page 3'.
+      \turnoffactive \putwordpage\tie\refx{#1-pg}{}%
+    \fi\fi
+  \fi
+  \endlink
+\endgroup}
+
+% Output a cross-manual xref to #1.  Used just above (twice).
+% 
+% Only include the text "Section ``foo'' in" if the foo is neither
+% missing or Top.  Thus, @xref{,,,foo,The Foo Manual} outputs simply
+% "see The Foo Manual", the idea being to refer to the whole manual.
+% 
+% But, this being TeX, we can't easily compare our node name against the
+% string "Top" while ignoring the possible spaces before and after in
+% the input.  By adding the arbitrary 7sp below, we make it much less
+% likely that a real node name would have the same width as "Top" (e.g.,
+% in a monospaced font).  Hopefully it will never happen in practice.
+% 
+% For the same basic reason, we retypeset the "Top" at every
+% reference, since the current font is indeterminate.
+% 
+\def\crossmanualxref#1{%
+  \setbox\toprefbox = \hbox{Top\kern7sp}%
+  \setbox2 = \hbox{\ignorespaces \printedrefname \unskip \kern7sp}%
+  \ifdim \wd2 > 7sp  % nonempty?
+    \ifdim \wd2 = \wd\toprefbox \else  % same as Top?
+      \putwordSection{} ``\printedrefname'' \putwordin{}\space
+    \fi
+  \fi
+  #1%
+}
+
+% This macro is called from \xrefX for the `[nodename]' part of xref
+% output.  It's a separate macro only so it can be changed more easily,
+% since square brackets don't work well in some documents.  Particularly
+% one that Bob is working on :).
+%
+\def\xrefprintnodename#1{[#1]}
+
+% Things referred to by \setref.
+%
+\def\Ynothing{}
+\def\Yomitfromtoc{}
+\def\Ynumbered{%
+  \ifnum\secno=0
+    \putwordChapter@tie \the\chapno
+  \else \ifnum\subsecno=0
+    \putwordSection@tie \the\chapno.\the\secno
+  \else \ifnum\subsubsecno=0
+    \putwordSection@tie \the\chapno.\the\secno.\the\subsecno
+  \else
+    \putwordSection@tie \the\chapno.\the\secno.\the\subsecno.\the\subsubsecno
+  \fi\fi\fi
+}
+\def\Yappendix{%
+  \ifnum\secno=0
+     \putwordAppendix@tie @char\the\appendixno{}%
+  \else \ifnum\subsecno=0
+     \putwordSection@tie @char\the\appendixno.\the\secno
+  \else \ifnum\subsubsecno=0
+    \putwordSection@tie @char\the\appendixno.\the\secno.\the\subsecno
+  \else
+    \putwordSection@tie
+      @char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno
+  \fi\fi\fi
+}
+
+% Define \refx{NAME}{SUFFIX} to reference a cross-reference string named NAME.
+% If its value is nonempty, SUFFIX is output afterward.
+%
+\def\refx#1#2{%
+  {%
+    \indexnofonts
+    \otherbackslash
+    \expandafter\global\expandafter\let\expandafter\thisrefX
+      \csname XR#1\endcsname
+  }%
+  \ifx\thisrefX\relax
+    % If not defined, say something at least.
+    \angleleft un\-de\-fined\angleright
+    \iflinks
+      \ifhavexrefs
+        {\toks0 = {#1}% avoid expansion of possibly-complex value
+         \message{\linenumber Undefined cross reference `\the\toks0'.}}%
+      \else
+        \ifwarnedxrefs\else
+          \global\warnedxrefstrue
+          \message{Cross reference values unknown; you must run TeX again.}%
+        \fi
+      \fi
+    \fi
+  \else
+    % It's defined, so just use it.
+    \thisrefX
+  \fi
+  #2% Output the suffix in any case.
+}
+
+% This is the macro invoked by entries in the aux file.  Usually it's
+% just a \def (we prepend XR to the control sequence name to avoid
+% collisions).  But if this is a float type, we have more work to do.
+%
+\def\xrdef#1#2{%
+  {% The node name might contain 8-bit characters, which in our current
+   % implementation are changed to commands like @'e.  Don't let these
+   % mess up the control sequence name.
+    \indexnofonts
+    \turnoffactive
+    \xdef\safexrefname{#1}%
+  }%
+  %
+  \expandafter\gdef\csname XR\safexrefname\endcsname{#2}% remember this xref
+  %
+  % Was that xref control sequence that we just defined for a float?
+  \expandafter\iffloat\csname XR\safexrefname\endcsname
+    % it was a float, and we have the (safe) float type in \iffloattype.
+    \expandafter\let\expandafter\floatlist
+      \csname floatlist\iffloattype\endcsname
+    %
+    % Is this the first time we've seen this float type?
+    \expandafter\ifx\floatlist\relax
+      \toks0 = {\do}% yes, so just \do
+    \else
+      % had it before, so preserve previous elements in list.
+      \toks0 = \expandafter{\floatlist\do}%
+    \fi
+    %
+    % Remember this xref in the control sequence \floatlistFLOATTYPE,
+    % for later use in \listoffloats.
+    \expandafter\xdef\csname floatlist\iffloattype\endcsname{\the\toks0
+      {\safexrefname}}%
+  \fi
+}
+
+% Read the last existing aux file, if any.  No error if none exists.
+%
+\def\tryauxfile{%
+  \openin 1 \jobname.aux
+  \ifeof 1 \else
+    \readdatafile{aux}%
+    \global\havexrefstrue
+  \fi
+  \closein 1
+}
+
+\def\setupdatafile{%
+  \catcode`\^^@=\other
+  \catcode`\^^A=\other
+  \catcode`\^^B=\other
+  \catcode`\^^C=\other
+  \catcode`\^^D=\other
+  \catcode`\^^E=\other
+  \catcode`\^^F=\other
+  \catcode`\^^G=\other
+  \catcode`\^^H=\other
+  \catcode`\^^K=\other
+  \catcode`\^^L=\other
+  \catcode`\^^N=\other
+  \catcode`\^^P=\other
+  \catcode`\^^Q=\other
+  \catcode`\^^R=\other
+  \catcode`\^^S=\other
+  \catcode`\^^T=\other
+  \catcode`\^^U=\other
+  \catcode`\^^V=\other
+  \catcode`\^^W=\other
+  \catcode`\^^X=\other
+  \catcode`\^^Z=\other
+  \catcode`\^^[=\other
+  \catcode`\^^\=\other
+  \catcode`\^^]=\other
+  \catcode`\^^^=\other
+  \catcode`\^^_=\other
+  % It was suggested to set the catcode of ^ to 7, which would allow ^^e4 etc.
+  % in xref tags, i.e., node names.  But since ^^e4 notation isn't
+  % supported in the main text, it doesn't seem desirable.  Furthermore,
+  % that is not enough: for node names that actually contain a ^
+  % character, we would end up writing a line like this: 'xrdef {'hat
+  % b-title}{'hat b} and \xrdef does a \csname...\endcsname on the first
+  % argument, and \hat is not an expandable control sequence.  It could
+  % all be worked out, but why?  Either we support ^^ or we don't.
+  %
+  % The other change necessary for this was to define \auxhat:
+  % \def\auxhat{\def^{'hat }}% extra space so ok if followed by letter
+  % and then to call \auxhat in \setq.
+  %
+  \catcode`\^=\other
+  %
+  % Special characters.  Should be turned off anyway, but...
+  \catcode`\~=\other
+  \catcode`\[=\other
+  \catcode`\]=\other
+  \catcode`\"=\other
+  \catcode`\_=\other
+  \catcode`\|=\other
+  \catcode`\<=\other
+  \catcode`\>=\other
+  \catcode`\$=\other
+  \catcode`\#=\other
+  \catcode`\&=\other
+  \catcode`\%=\other
+  \catcode`+=\other % avoid \+ for paranoia even though we've turned it off
+  %
+  % This is to support \ in node names and titles, since the \
+  % characters end up in a \csname.  It's easier than
+  % leaving it active and making its active definition an actual \
+  % character.  What I don't understand is why it works in the *value*
+  % of the xrdef.  Seems like it should be a catcode12 \, and that
+  % should not typeset properly.  But it works, so I'm moving on for
+  % now.  --karl, 15jan04.
+  \catcode`\\=\other
+  %
+  % Make the characters 128-255 be printing characters.
+  {%
+    \count1=128
+    \def\loop{%
+      \catcode\count1=\other
+      \advance\count1 by 1
+      \ifnum \count1<256 \loop \fi
+    }%
+  }%
+  %
+  % @ is our escape character in .aux files, and we need braces.
+  \catcode`\{=1
+  \catcode`\}=2
+  \catcode`\@=0
+}
+
+\def\readdatafile#1{%
+\begingroup
+  \setupdatafile
+  \input\jobname.#1
+\endgroup}
+
+
+\message{insertions,}
+% including footnotes.
+
+\newcount \footnoteno
+
+% The trailing space in the following definition for supereject is
+% vital for proper filling; pages come out unaligned when you do a
+% pagealignmacro call if that space before the closing brace is
+% removed. (Generally, numeric constants should always be followed by a
+% space to prevent strange expansion errors.)
+\def\supereject{\par\penalty -20000\footnoteno =0 }
+
+% @footnotestyle is meaningful for Info output only.
+\let\footnotestyle=\comment
+
+{\catcode `\@=11
+%
+% Auto-number footnotes.  Otherwise like plain.
+\gdef\footnote{%
+  \let\indent=\ptexindent
+  \let\noindent=\ptexnoindent
+  \global\advance\footnoteno by \@ne
+  \edef\thisfootno{$^{\the\footnoteno}$}%
+  %
+  % In case the footnote comes at the end of a sentence, preserve the
+  % extra spacing after we do the footnote number.
+  \let\@sf\empty
+  \ifhmode\edef\@sf{\spacefactor\the\spacefactor}\ptexslash\fi
+  %
+  % Remove inadvertent blank space before typesetting the footnote number.
+  \unskip
+  \thisfootno\@sf
+  \dofootnote
+}%
+
+% Don't bother with the trickery in plain.tex to not require the
+% footnote text as a parameter.  Our footnotes don't need to be so general.
+%
+% Oh yes, they do; otherwise, @ifset (and anything else that uses
+% \parseargline) fails inside footnotes because the tokens are fixed when
+% the footnote is read.  --karl, 16nov96.
+%
+\gdef\dofootnote{%
+  \insert\footins\bgroup
+  % We want to typeset this text as a normal paragraph, even if the
+  % footnote reference occurs in (for example) a display environment.
+  % So reset some parameters.
+  \hsize=\pagewidth
+  \interlinepenalty\interfootnotelinepenalty
+  \splittopskip\ht\strutbox % top baseline for broken footnotes
+  \splitmaxdepth\dp\strutbox
+  \floatingpenalty\@MM
+  \leftskip\z@skip
+  \rightskip\z@skip
+  \spaceskip\z@skip
+  \xspaceskip\z@skip
+  \parindent\defaultparindent
+  %
+  \smallfonts \rm
+  %
+  % Because we use hanging indentation in footnotes, a @noindent appears
+  % to exdent this text, so make it be a no-op.  makeinfo does not use
+  % hanging indentation so @noindent can still be needed within footnote
+  % text after an @example or the like (not that this is good style).
+  \let\noindent = \relax
+  %
+  % Hang the footnote text off the number.  Use \everypar in case the
+  % footnote extends for more than one paragraph.
+  \everypar = {\hang}%
+  \textindent{\thisfootno}%
+  %
+  % Don't crash into the line above the footnote text.  Since this
+  % expands into a box, it must come within the paragraph, lest it
+  % provide a place where TeX can split the footnote.
+  \footstrut
+  %
+  % Invoke rest of plain TeX footnote routine.
+  \futurelet\next\fo@t
+}
+}%end \catcode `\@=11
+
+% In case a @footnote appears in a vbox, save the footnote text and create
+% the real \insert just after the vbox finished.  Otherwise, the insertion
+% would be lost.
+% Similarly, if a @footnote appears inside an alignment, save the footnote
+% text to a box and make the \insert when a row of the table is finished.
+% And the same can be done for other insert classes.  --kasal, 16nov03.
+
+% Replace the \insert primitive by a cheating macro.
+% Deeper inside, just make sure that the saved insertions are not spilled
+% out prematurely.
+%
+\def\startsavinginserts{%
+  \ifx \insert\ptexinsert
+    \let\insert\saveinsert
+  \else
+    \let\checkinserts\relax
+  \fi
+}
+
+% This \insert replacement works for both \insert\footins{foo} and
+% \insert\footins\bgroup foo\egroup, but it doesn't work for \insert27{foo}.
+%
+\def\saveinsert#1{%
+  \edef\next{\noexpand\savetobox \makeSAVEname#1}%
+  \afterassignment\next
+  % swallow the left brace
+  \let\temp =
+}
+\def\makeSAVEname#1{\makecsname{SAVE\expandafter\gobble\string#1}}
+\def\savetobox#1{\global\setbox#1 = \vbox\bgroup \unvbox#1}
+
+\def\checksaveins#1{\ifvoid#1\else \placesaveins#1\fi}
+
+\def\placesaveins#1{%
+  \ptexinsert \csname\expandafter\gobblesave\string#1\endcsname
+    {\box#1}%
+}
+
+% eat @SAVE -- beware, all of them have catcode \other:
+{
+  \def\dospecials{\do S\do A\do V\do E} \uncatcodespecials  %  ;-)
+  \gdef\gobblesave @SAVE{}
+}
+
+% initialization:
+\def\newsaveins #1{%
+  \edef\next{\noexpand\newsaveinsX \makeSAVEname#1}%
+  \next
+}
+\def\newsaveinsX #1{%
+  \csname newbox\endcsname #1%
+  \expandafter\def\expandafter\checkinserts\expandafter{\checkinserts
+    \checksaveins #1}%
+}
+
+% initialize:
+\let\checkinserts\empty
+\newsaveins\footins
+\newsaveins\margin
+
+
+% @image.  We use the macros from epsf.tex to support this.
+% If epsf.tex is not installed and @image is used, we complain.
+%
+% Check for and read epsf.tex up front.  If we read it only at @image
+% time, we might be inside a group, and then its definitions would get
+% undone and the next image would fail.
+\openin 1 = epsf.tex
+\ifeof 1 \else
+  % Do not bother showing banner with epsf.tex v2.7k (available in
+  % doc/epsf.tex and on ctan).
+  \def\epsfannounce{\toks0 = }%
+  \input epsf.tex
+\fi
+\closein 1
+%
+% We will only complain once about lack of epsf.tex.
+\newif\ifwarnednoepsf
+\newhelp\noepsfhelp{epsf.tex must be installed for images to
+  work.  It is also included in the Texinfo distribution, or you can get
+  it from ftp://tug.org/tex/epsf.tex.}
+%
+\def\image#1{%
+  \ifx\epsfbox\thisisundefined
+    \ifwarnednoepsf \else
+      \errhelp = \noepsfhelp
+      \errmessage{epsf.tex not found, images will be ignored}%
+      \global\warnednoepsftrue
+    \fi
+  \else
+    \imagexxx #1,,,,,\finish
+  \fi
+}
+%
+% Arguments to @image:
+% #1 is (mandatory) image filename; we tack on .eps extension.
+% #2 is (optional) width, #3 is (optional) height.
+% #4 is (ignored optional) html alt text.
+% #5 is (ignored optional) extension.
+% #6 is just the usual extra ignored arg for parsing stuff.
+\newif\ifimagevmode
+\def\imagexxx#1,#2,#3,#4,#5,#6\finish{\begingroup
+  \catcode`\^^M = 5     % in case we're inside an example
+  \normalturnoffactive  % allow _ et al. in names
+  % If the image is by itself, center it.
+  \ifvmode
+    \imagevmodetrue
+  \else \ifx\centersub\centerV
+    % for @center @image, we need a vbox so we can have our vertical space
+    \imagevmodetrue
+    \vbox\bgroup % vbox has better behavior than vtop herev
+  \fi\fi
+  %
+  \ifimagevmode
+    \nobreak\medskip
+    % Usually we'll have text after the image which will insert
+    % \parskip glue, so insert it here too to equalize the space
+    % above and below.
+    \nobreak\vskip\parskip
+    \nobreak
+  \fi
+  %
+  % Leave vertical mode so that indentation from an enclosing
+  %  environment such as @quotation is respected.
+  % However, if we're at the top level, we don't want the
+  %  normal paragraph indentation.
+  % On the other hand, if we are in the case of @center @image, we don't
+  %  want to start a paragraph, which will create a hsize-width box and
+  %  eradicate the centering.
+  \ifx\centersub\centerV\else \noindent \fi
+  %
+  % Output the image.
+  \ifpdf
+    \dopdfimage{#1}{#2}{#3}%
+  \else
+    % \epsfbox itself resets \epsf?size at each figure.
+    \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \epsfxsize=#2\relax \fi
+    \setbox0 = \hbox{\ignorespaces #3}\ifdim\wd0 > 0pt \epsfysize=#3\relax \fi
+    \epsfbox{#1.eps}%
+  \fi
+  %
+  \ifimagevmode
+    \medskip  % space after a standalone image
+  \fi  
+  \ifx\centersub\centerV \egroup \fi
+\endgroup}
+
+
+% @float FLOATTYPE,LABEL,LOC ... @end float for displayed figures, tables,
+% etc.  We don't actually implement floating yet, we always include the
+% float "here".  But it seemed the best name for the future.
+%
+\envparseargdef\float{\eatcommaspace\eatcommaspace\dofloat#1, , ,\finish}
+
+% There may be a space before second and/or third parameter; delete it.
+\def\eatcommaspace#1, {#1,}
+
+% #1 is the optional FLOATTYPE, the text label for this float, typically
+% "Figure", "Table", "Example", etc.  Can't contain commas.  If omitted,
+% this float will not be numbered and cannot be referred to.
+%
+% #2 is the optional xref label.  Also must be present for the float to
+% be referable.
+%
+% #3 is the optional positioning argument; for now, it is ignored.  It
+% will somehow specify the positions allowed to float to (here, top, bottom).
+%
+% We keep a separate counter for each FLOATTYPE, which we reset at each
+% chapter-level command.
+\let\resetallfloatnos=\empty
+%
+\def\dofloat#1,#2,#3,#4\finish{%
+  \let\thiscaption=\empty
+  \let\thisshortcaption=\empty
+  %
+  % don't lose footnotes inside @float.
+  %
+  % BEWARE: when the floats start float, we have to issue warning whenever an
+  % insert appears inside a float which could possibly float. --kasal, 26may04
+  %
+  \startsavinginserts
+  %
+  % We can't be used inside a paragraph.
+  \par
+  %
+  \vtop\bgroup
+    \def\floattype{#1}%
+    \def\floatlabel{#2}%
+    \def\floatloc{#3}% we do nothing with this yet.
+    %
+    \ifx\floattype\empty
+      \let\safefloattype=\empty
+    \else
+      {%
+        % the floattype might have accents or other special characters,
+        % but we need to use it in a control sequence name.
+        \indexnofonts
+        \turnoffactive
+        \xdef\safefloattype{\floattype}%
+      }%
+    \fi
+    %
+    % If label is given but no type, we handle that as the empty type.
+    \ifx\floatlabel\empty \else
+      % We want each FLOATTYPE to be numbered separately (Figure 1,
+      % Table 1, Figure 2, ...).  (And if no label, no number.)
+      %
+      \expandafter\getfloatno\csname\safefloattype floatno\endcsname
+      \global\advance\floatno by 1
+      %
+      {%
+        % This magic value for \lastsection is output by \setref as the
+        % XREFLABEL-title value.  \xrefX uses it to distinguish float
+        % labels (which have a completely different output format) from
+        % node and anchor labels.  And \xrdef uses it to construct the
+        % lists of floats.
+        %
+        \edef\lastsection{\floatmagic=\safefloattype}%
+        \setref{\floatlabel}{Yfloat}%
+      }%
+    \fi
+    %
+    % start with \parskip glue, I guess.
+    \vskip\parskip
+    %
+    % Don't suppress indentation if a float happens to start a section.
+    \restorefirstparagraphindent
+}
+
+% we have these possibilities:
+% @float Foo,lbl & @caption{Cap}: Foo 1.1: Cap
+% @float Foo,lbl & no caption:    Foo 1.1
+% @float Foo & @caption{Cap}:     Foo: Cap
+% @float Foo & no caption:        Foo
+% @float ,lbl & Caption{Cap}:     1.1: Cap
+% @float ,lbl & no caption:       1.1
+% @float & @caption{Cap}:         Cap
+% @float & no caption:
+%
+\def\Efloat{%
+    \let\floatident = \empty
+    %
+    % In all cases, if we have a float type, it comes first.
+    \ifx\floattype\empty \else \def\floatident{\floattype}\fi
+    %
+    % If we have an xref label, the number comes next.
+    \ifx\floatlabel\empty \else
+      \ifx\floattype\empty \else % if also had float type, need tie first.
+        \appendtomacro\floatident{\tie}%
+      \fi
+      % the number.
+      \appendtomacro\floatident{\chaplevelprefix\the\floatno}%
+    \fi
+    %
+    % Start the printed caption with what we've constructed in
+    % \floatident, but keep it separate; we need \floatident again.
+    \let\captionline = \floatident
+    %
+    \ifx\thiscaption\empty \else
+      \ifx\floatident\empty \else
+	\appendtomacro\captionline{: }% had ident, so need a colon between
+      \fi
+      %
+      % caption text.
+      \appendtomacro\captionline{\scanexp\thiscaption}%
+    \fi
+    %
+    % If we have anything to print, print it, with space before.
+    % Eventually this needs to become an \insert.
+    \ifx\captionline\empty \else
+      \vskip.5\parskip
+      \captionline
+      %
+      % Space below caption.
+      \vskip\parskip
+    \fi
+    %
+    % If have an xref label, write the list of floats info.  Do this
+    % after the caption, to avoid chance of it being a breakpoint.
+    \ifx\floatlabel\empty \else
+      % Write the text that goes in the lof to the aux file as
+      % \floatlabel-lof.  Besides \floatident, we include the short
+      % caption if specified, else the full caption if specified, else nothing.
+      {%
+        \atdummies
+        %
+        % since we read the caption text in the macro world, where ^^M
+        % is turned into a normal character, we have to scan it back, so
+        % we don't write the literal three characters "^^M" into the aux file.
+	\scanexp{%
+	  \xdef\noexpand\gtemp{%
+	    \ifx\thisshortcaption\empty
+	      \thiscaption
+	    \else
+	      \thisshortcaption
+	    \fi
+	  }%
+	}%
+        \immediate\write\auxfile{@xrdef{\floatlabel-lof}{\floatident
+	  \ifx\gtemp\empty \else : \gtemp \fi}}%
+      }%
+    \fi
+  \egroup  % end of \vtop
+  %
+  % place the captured inserts
+  %
+  % BEWARE: when the floats start floating, we have to issue warning
+  % whenever an insert appears inside a float which could possibly
+  % float. --kasal, 26may04
+  %
+  \checkinserts
+}
+
+% Append the tokens #2 to the definition of macro #1, not expanding either.
+%
+\def\appendtomacro#1#2{%
+  \expandafter\def\expandafter#1\expandafter{#1#2}%
+}
+
+% @caption, @shortcaption
+%
+\def\caption{\docaption\thiscaption}
+\def\shortcaption{\docaption\thisshortcaption}
+\def\docaption{\checkenv\float \bgroup\scanargctxt\defcaption}
+\def\defcaption#1#2{\egroup \def#1{#2}}
+
+% The parameter is the control sequence identifying the counter we are
+% going to use.  Create it if it doesn't exist and assign it to \floatno.
+\def\getfloatno#1{%
+  \ifx#1\relax
+      % Haven't seen this figure type before.
+      \csname newcount\endcsname #1%
+      %
+      % Remember to reset this floatno at the next chap.
+      \expandafter\gdef\expandafter\resetallfloatnos
+        \expandafter{\resetallfloatnos #1=0 }%
+  \fi
+  \let\floatno#1%
+}
+
+% \setref calls this to get the XREFLABEL-snt value.  We want an @xref
+% to the FLOATLABEL to expand to "Figure 3.1".  We call \setref when we
+% first read the @float command.
+%
+\def\Yfloat{\floattype@tie \chaplevelprefix\the\floatno}%
+
+% Magic string used for the XREFLABEL-title value, so \xrefX can
+% distinguish floats from other xref types.
+\def\floatmagic{!!float!!}
+
+% #1 is the control sequence we are passed; we expand into a conditional
+% which is true if #1 represents a float ref.  That is, the magic
+% \lastsection value which we \setref above.
+%
+\def\iffloat#1{\expandafter\doiffloat#1==\finish}
+%
+% #1 is (maybe) the \floatmagic string.  If so, #2 will be the
+% (safe) float type for this float.  We set \iffloattype to #2.
+%
+\def\doiffloat#1=#2=#3\finish{%
+  \def\temp{#1}%
+  \def\iffloattype{#2}%
+  \ifx\temp\floatmagic
+}
+
+% @listoffloats FLOATTYPE - print a list of floats like a table of contents.
+%
+\parseargdef\listoffloats{%
+  \def\floattype{#1}% floattype
+  {%
+    % the floattype might have accents or other special characters,
+    % but we need to use it in a control sequence name.
+    \indexnofonts
+    \turnoffactive
+    \xdef\safefloattype{\floattype}%
+  }%
+  %
+  % \xrdef saves the floats as a \do-list in \floatlistSAFEFLOATTYPE.
+  \expandafter\ifx\csname floatlist\safefloattype\endcsname \relax
+    \ifhavexrefs
+      % if the user said @listoffloats foo but never @float foo.
+      \message{\linenumber No `\safefloattype' floats to list.}%
+    \fi
+  \else
+    \begingroup
+      \leftskip=\tocindent  % indent these entries like a toc
+      \let\do=\listoffloatsdo
+      \csname floatlist\safefloattype\endcsname
+    \endgroup
+  \fi
+}
+
+% This is called on each entry in a list of floats.  We're passed the
+% xref label, in the form LABEL-title, which is how we save it in the
+% aux file.  We strip off the -title and look up \XRLABEL-lof, which
+% has the text we're supposed to typeset here.
+%
+% Figures without xref labels will not be included in the list (since
+% they won't appear in the aux file).
+%
+\def\listoffloatsdo#1{\listoffloatsdoentry#1\finish}
+\def\listoffloatsdoentry#1-title\finish{{%
+  % Can't fully expand XR#1-lof because it can contain anything.  Just
+  % pass the control sequence.  On the other hand, XR#1-pg is just the
+  % page number, and we want to fully expand that so we can get a link
+  % in pdf output.
+  \toksA = \expandafter{\csname XR#1-lof\endcsname}%
+  %
+  % use the same \entry macro we use to generate the TOC and index.
+  \edef\writeentry{\noexpand\entry{\the\toksA}{\csname XR#1-pg\endcsname}}%
+  \writeentry
+}}
+
+
+\message{localization,}
+
+% For single-language documents, @documentlanguage is usually given very
+% early, just after @documentencoding.  Single argument is the language
+% (de) or locale (de_DE) abbreviation.
+%
+{
+  \catcode`\_ = \active
+  \globaldefs=1
+\parseargdef\documentlanguage{\begingroup
+  \let_=\normalunderscore  % normal _ character for filenames
+  \tex % read txi-??.tex file in plain TeX.
+    % Read the file by the name they passed if it exists.
+    \openin 1 txi-#1.tex
+    \ifeof 1
+      \documentlanguagetrywithoutunderscore{#1_\finish}%
+    \else
+      \globaldefs = 1  % everything in the txi-LL files needs to persist
+      \input txi-#1.tex
+    \fi
+    \closein 1
+  \endgroup % end raw TeX
+\endgroup}
+%
+% If they passed de_DE, and txi-de_DE.tex doesn't exist,
+% try txi-de.tex.
+%
+\gdef\documentlanguagetrywithoutunderscore#1_#2\finish{%
+  \openin 1 txi-#1.tex
+  \ifeof 1
+    \errhelp = \nolanghelp
+    \errmessage{Cannot read language file txi-#1.tex}%
+  \else
+    \globaldefs = 1  % everything in the txi-LL files needs to persist
+    \input txi-#1.tex
+  \fi
+  \closein 1
+}
+}% end of special _ catcode
+%
+\newhelp\nolanghelp{The given language definition file cannot be found or
+is empty.  Maybe you need to install it?  Putting it in the current
+directory should work if nowhere else does.}
+
+% This macro is called from txi-??.tex files; the first argument is the
+% \language name to set (without the "\lang@" prefix), the second and
+% third args are \{left,right}hyphenmin.
+%
+% The language names to pass are determined when the format is built.
+% See the etex.log file created at that time, e.g.,
+% /usr/local/texlive/2008/texmf-var/web2c/pdftex/etex.log.
+%
+% With TeX Live 2008, etex now includes hyphenation patterns for all
+% available languages.  This means we can support hyphenation in
+% Texinfo, at least to some extent.  (This still doesn't solve the
+% accented characters problem.)
+%
+\catcode`@=11
+\def\txisetlanguage#1#2#3{%
+  % do not set the language if the name is undefined in the current TeX.
+  \expandafter\ifx\csname lang@#1\endcsname \relax
+    \message{no patterns for #1}%
+  \else
+    \global\language = \csname lang@#1\endcsname
+  \fi
+  % but there is no harm in adjusting the hyphenmin values regardless.
+  \global\lefthyphenmin = #2\relax
+  \global\righthyphenmin = #3\relax
+}
+
+% Helpers for encodings.
+% Set the catcode of characters 128 through 255 to the specified number.
+%
+\def\setnonasciicharscatcode#1{%
+   \count255=128
+   \loop\ifnum\count255<256
+      \global\catcode\count255=#1\relax
+      \advance\count255 by 1
+   \repeat
+}
+
+\def\setnonasciicharscatcodenonglobal#1{%
+   \count255=128
+   \loop\ifnum\count255<256
+      \catcode\count255=#1\relax
+      \advance\count255 by 1
+   \repeat
+}
+
+% @documentencoding sets the definition of non-ASCII characters
+% according to the specified encoding.
+%
+\parseargdef\documentencoding{%
+  % Encoding being declared for the document.
+  \def\declaredencoding{\csname #1.enc\endcsname}%
+  %
+  % Supported encodings: names converted to tokens in order to be able
+  % to compare them with \ifx.
+  \def\ascii{\csname US-ASCII.enc\endcsname}%
+  \def\latnine{\csname ISO-8859-15.enc\endcsname}%
+  \def\latone{\csname ISO-8859-1.enc\endcsname}%
+  \def\lattwo{\csname ISO-8859-2.enc\endcsname}%
+  \def\utfeight{\csname UTF-8.enc\endcsname}%
+  %
+  \ifx \declaredencoding \ascii
+     \asciichardefs
+  %
+  \else \ifx \declaredencoding \lattwo
+     \setnonasciicharscatcode\active
+     \lattwochardefs
+  %
+  \else \ifx \declaredencoding \latone
+     \setnonasciicharscatcode\active
+     \latonechardefs
+  %
+  \else \ifx \declaredencoding \latnine
+     \setnonasciicharscatcode\active
+     \latninechardefs
+  %
+  \else \ifx \declaredencoding \utfeight
+     \setnonasciicharscatcode\active
+     \utfeightchardefs
+  %
+  \else
+    \message{Unknown document encoding #1, ignoring.}%
+  %
+  \fi % utfeight
+  \fi % latnine
+  \fi % latone
+  \fi % lattwo
+  \fi % ascii
+}
+
+% A message to be logged when using a character that isn't available
+% the default font encoding (OT1).
+%
+\def\missingcharmsg#1{\message{Character missing in OT1 encoding: #1.}}
+
+% Take account of \c (plain) vs. \, (Texinfo) difference.
+\def\cedilla#1{\ifx\c\ptexc\c{#1}\else\,{#1}\fi}
+
+% First, make active non-ASCII characters in order for them to be
+% correctly categorized when TeX reads the replacement text of
+% macros containing the character definitions.
+\setnonasciicharscatcode\active
+%
+% Latin1 (ISO-8859-1) character definitions.
+\def\latonechardefs{%
+  \gdef^^a0{\tie}
+  \gdef^^a1{\exclamdown}
+  \gdef^^a2{\missingcharmsg{CENT SIGN}}
+  \gdef^^a3{{\pounds}}
+  \gdef^^a4{\missingcharmsg{CURRENCY SIGN}}
+  \gdef^^a5{\missingcharmsg{YEN SIGN}}
+  \gdef^^a6{\missingcharmsg{BROKEN BAR}}
+  \gdef^^a7{\S}
+  \gdef^^a8{\"{}}
+  \gdef^^a9{\copyright}
+  \gdef^^aa{\ordf}
+  \gdef^^ab{\guillemetleft}
+  \gdef^^ac{$\lnot$}
+  \gdef^^ad{\-}
+  \gdef^^ae{\registeredsymbol}
+  \gdef^^af{\={}}
+  %
+  \gdef^^b0{\textdegree}
+  \gdef^^b1{$\pm$}
+  \gdef^^b2{$^2$}
+  \gdef^^b3{$^3$}
+  \gdef^^b4{\'{}}
+  \gdef^^b5{$\mu$}
+  \gdef^^b6{\P}
+  %
+  \gdef^^b7{$^.$}
+  \gdef^^b8{\cedilla\ }
+  \gdef^^b9{$^1$}
+  \gdef^^ba{\ordm}
+  %
+  \gdef^^bb{\guillemetright}
+  \gdef^^bc{$1\over4$}
+  \gdef^^bd{$1\over2$}
+  \gdef^^be{$3\over4$}
+  \gdef^^bf{\questiondown}
+  %
+  \gdef^^c0{\`A}
+  \gdef^^c1{\'A}
+  \gdef^^c2{\^A}
+  \gdef^^c3{\~A}
+  \gdef^^c4{\"A}
+  \gdef^^c5{\ringaccent A}
+  \gdef^^c6{\AE}
+  \gdef^^c7{\cedilla C}
+  \gdef^^c8{\`E}
+  \gdef^^c9{\'E}
+  \gdef^^ca{\^E}
+  \gdef^^cb{\"E}
+  \gdef^^cc{\`I}
+  \gdef^^cd{\'I}
+  \gdef^^ce{\^I}
+  \gdef^^cf{\"I}
+  %
+  \gdef^^d0{\DH}
+  \gdef^^d1{\~N}
+  \gdef^^d2{\`O}
+  \gdef^^d3{\'O}
+  \gdef^^d4{\^O}
+  \gdef^^d5{\~O}
+  \gdef^^d6{\"O}
+  \gdef^^d7{$\times$}
+  \gdef^^d8{\O}
+  \gdef^^d9{\`U}
+  \gdef^^da{\'U}
+  \gdef^^db{\^U}
+  \gdef^^dc{\"U}
+  \gdef^^dd{\'Y}
+  \gdef^^de{\TH}
+  \gdef^^df{\ss}
+  %
+  \gdef^^e0{\`a}
+  \gdef^^e1{\'a}
+  \gdef^^e2{\^a}
+  \gdef^^e3{\~a}
+  \gdef^^e4{\"a}
+  \gdef^^e5{\ringaccent a}
+  \gdef^^e6{\ae}
+  \gdef^^e7{\cedilla c}
+  \gdef^^e8{\`e}
+  \gdef^^e9{\'e}
+  \gdef^^ea{\^e}
+  \gdef^^eb{\"e}
+  \gdef^^ec{\`{\dotless i}}
+  \gdef^^ed{\'{\dotless i}}
+  \gdef^^ee{\^{\dotless i}}
+  \gdef^^ef{\"{\dotless i}}
+  %
+  \gdef^^f0{\dh}
+  \gdef^^f1{\~n}
+  \gdef^^f2{\`o}
+  \gdef^^f3{\'o}
+  \gdef^^f4{\^o}
+  \gdef^^f5{\~o}
+  \gdef^^f6{\"o}
+  \gdef^^f7{$\div$}
+  \gdef^^f8{\o}
+  \gdef^^f9{\`u}
+  \gdef^^fa{\'u}
+  \gdef^^fb{\^u}
+  \gdef^^fc{\"u}
+  \gdef^^fd{\'y}
+  \gdef^^fe{\th}
+  \gdef^^ff{\"y}
+}
+
+% Latin9 (ISO-8859-15) encoding character definitions.
+\def\latninechardefs{%
+  % Encoding is almost identical to Latin1.
+  \latonechardefs
+  %
+  \gdef^^a4{\euro}
+  \gdef^^a6{\v S}
+  \gdef^^a8{\v s}
+  \gdef^^b4{\v Z}
+  \gdef^^b8{\v z}
+  \gdef^^bc{\OE}
+  \gdef^^bd{\oe}
+  \gdef^^be{\"Y}
+}
+
+% Latin2 (ISO-8859-2) character definitions.
+\def\lattwochardefs{%
+  \gdef^^a0{\tie}
+  \gdef^^a1{\ogonek{A}}
+  \gdef^^a2{\u{}}
+  \gdef^^a3{\L}
+  \gdef^^a4{\missingcharmsg{CURRENCY SIGN}}
+  \gdef^^a5{\v L}
+  \gdef^^a6{\'S}
+  \gdef^^a7{\S}
+  \gdef^^a8{\"{}}
+  \gdef^^a9{\v S}
+  \gdef^^aa{\cedilla S}
+  \gdef^^ab{\v T}
+  \gdef^^ac{\'Z}
+  \gdef^^ad{\-}
+  \gdef^^ae{\v Z}
+  \gdef^^af{\dotaccent Z}
+  %
+  \gdef^^b0{\textdegree}
+  \gdef^^b1{\ogonek{a}}
+  \gdef^^b2{\ogonek{ }}
+  \gdef^^b3{\l}
+  \gdef^^b4{\'{}}
+  \gdef^^b5{\v l}
+  \gdef^^b6{\'s}
+  \gdef^^b7{\v{}}
+  \gdef^^b8{\cedilla\ }
+  \gdef^^b9{\v s}
+  \gdef^^ba{\cedilla s}
+  \gdef^^bb{\v t}
+  \gdef^^bc{\'z}
+  \gdef^^bd{\H{}}
+  \gdef^^be{\v z}
+  \gdef^^bf{\dotaccent z}
+  %
+  \gdef^^c0{\'R}
+  \gdef^^c1{\'A}
+  \gdef^^c2{\^A}
+  \gdef^^c3{\u A}
+  \gdef^^c4{\"A}
+  \gdef^^c5{\'L}
+  \gdef^^c6{\'C}
+  \gdef^^c7{\cedilla C}
+  \gdef^^c8{\v C}
+  \gdef^^c9{\'E}
+  \gdef^^ca{\ogonek{E}}
+  \gdef^^cb{\"E}
+  \gdef^^cc{\v E}
+  \gdef^^cd{\'I}
+  \gdef^^ce{\^I}
+  \gdef^^cf{\v D}
+  %
+  \gdef^^d0{\DH}
+  \gdef^^d1{\'N}
+  \gdef^^d2{\v N}
+  \gdef^^d3{\'O}
+  \gdef^^d4{\^O}
+  \gdef^^d5{\H O}
+  \gdef^^d6{\"O}
+  \gdef^^d7{$\times$}
+  \gdef^^d8{\v R}
+  \gdef^^d9{\ringaccent U}
+  \gdef^^da{\'U}
+  \gdef^^db{\H U}
+  \gdef^^dc{\"U}
+  \gdef^^dd{\'Y}
+  \gdef^^de{\cedilla T}
+  \gdef^^df{\ss}
+  %
+  \gdef^^e0{\'r}
+  \gdef^^e1{\'a}
+  \gdef^^e2{\^a}
+  \gdef^^e3{\u a}
+  \gdef^^e4{\"a}
+  \gdef^^e5{\'l}
+  \gdef^^e6{\'c}
+  \gdef^^e7{\cedilla c}
+  \gdef^^e8{\v c}
+  \gdef^^e9{\'e}
+  \gdef^^ea{\ogonek{e}}
+  \gdef^^eb{\"e}
+  \gdef^^ec{\v e}
+  \gdef^^ed{\'{\dotless{i}}}
+  \gdef^^ee{\^{\dotless{i}}}
+  \gdef^^ef{\v d}
+  %
+  \gdef^^f0{\dh}
+  \gdef^^f1{\'n}
+  \gdef^^f2{\v n}
+  \gdef^^f3{\'o}
+  \gdef^^f4{\^o}
+  \gdef^^f5{\H o}
+  \gdef^^f6{\"o}
+  \gdef^^f7{$\div$}
+  \gdef^^f8{\v r}
+  \gdef^^f9{\ringaccent u}
+  \gdef^^fa{\'u}
+  \gdef^^fb{\H u}
+  \gdef^^fc{\"u}
+  \gdef^^fd{\'y}
+  \gdef^^fe{\cedilla t}
+  \gdef^^ff{\dotaccent{}}
+}
+
+% UTF-8 character definitions.
+%
+% This code to support UTF-8 is based on LaTeX's utf8.def, with some
+% changes for Texinfo conventions.  It is included here under the GPL by
+% permission from Frank Mittelbach and the LaTeX team.
+%
+\newcount\countUTFx
+\newcount\countUTFy
+\newcount\countUTFz
+
+\gdef\UTFviiiTwoOctets#1#2{\expandafter
+   \UTFviiiDefined\csname u8:#1\string #2\endcsname}
+%
+\gdef\UTFviiiThreeOctets#1#2#3{\expandafter
+   \UTFviiiDefined\csname u8:#1\string #2\string #3\endcsname}
+%
+\gdef\UTFviiiFourOctets#1#2#3#4{\expandafter
+   \UTFviiiDefined\csname u8:#1\string #2\string #3\string #4\endcsname}
+
+\gdef\UTFviiiDefined#1{%
+  \ifx #1\relax
+    \message{\linenumber Unicode char \string #1 not defined for Texinfo}%
+  \else
+    \expandafter #1%
+  \fi
+}
+
+\begingroup
+  \catcode`\~13
+  \catcode`\"12
+
+  \def\UTFviiiLoop{%
+    \global\catcode\countUTFx\active
+    \uccode`\~\countUTFx
+    \uppercase\expandafter{\UTFviiiTmp}%
+    \advance\countUTFx by 1
+    \ifnum\countUTFx < \countUTFy
+      \expandafter\UTFviiiLoop
+    \fi}
+
+  \countUTFx = "C2
+  \countUTFy = "E0
+  \def\UTFviiiTmp{%
+    \xdef~{\noexpand\UTFviiiTwoOctets\string~}}
+  \UTFviiiLoop
+
+  \countUTFx = "E0
+  \countUTFy = "F0
+  \def\UTFviiiTmp{%
+    \xdef~{\noexpand\UTFviiiThreeOctets\string~}}
+  \UTFviiiLoop
+
+  \countUTFx = "F0
+  \countUTFy = "F4
+  \def\UTFviiiTmp{%
+    \xdef~{\noexpand\UTFviiiFourOctets\string~}}
+  \UTFviiiLoop
+\endgroup
+
+\begingroup
+  \catcode`\"=12
+  \catcode`\<=12
+  \catcode`\.=12
+  \catcode`\,=12
+  \catcode`\;=12
+  \catcode`\!=12
+  \catcode`\~=13
+
+  \gdef\DeclareUnicodeCharacter#1#2{%
+    \countUTFz = "#1\relax
+    %\wlog{\space\space defining Unicode char U+#1 (decimal \the\countUTFz)}%
+    \begingroup
+      \parseXMLCharref
+      \def\UTFviiiTwoOctets##1##2{%
+        \csname u8:##1\string ##2\endcsname}%
+      \def\UTFviiiThreeOctets##1##2##3{%
+        \csname u8:##1\string ##2\string ##3\endcsname}%
+      \def\UTFviiiFourOctets##1##2##3##4{%
+        \csname u8:##1\string ##2\string ##3\string ##4\endcsname}%
+      \expandafter\expandafter\expandafter\expandafter
+       \expandafter\expandafter\expandafter
+       \gdef\UTFviiiTmp{#2}%
+    \endgroup}
+
+  \gdef\parseXMLCharref{%
+    \ifnum\countUTFz < "A0\relax
+      \errhelp = \EMsimple
+      \errmessage{Cannot define Unicode char value < 00A0}%
+    \else\ifnum\countUTFz < "800\relax
+      \parseUTFviiiA,%
+      \parseUTFviiiB C\UTFviiiTwoOctets.,%
+    \else\ifnum\countUTFz < "10000\relax
+      \parseUTFviiiA;%
+      \parseUTFviiiA,%
+      \parseUTFviiiB E\UTFviiiThreeOctets.{,;}%
+    \else
+      \parseUTFviiiA;%
+      \parseUTFviiiA,%
+      \parseUTFviiiA!%
+      \parseUTFviiiB F\UTFviiiFourOctets.{!,;}%
+    \fi\fi\fi
+  }
+
+  \gdef\parseUTFviiiA#1{%
+    \countUTFx = \countUTFz
+    \divide\countUTFz by 64
+    \countUTFy = \countUTFz
+    \multiply\countUTFz by 64
+    \advance\countUTFx by -\countUTFz
+    \advance\countUTFx by 128
+    \uccode `#1\countUTFx
+    \countUTFz = \countUTFy}
+
+  \gdef\parseUTFviiiB#1#2#3#4{%
+    \advance\countUTFz by "#10\relax
+    \uccode `#3\countUTFz
+    \uppercase{\gdef\UTFviiiTmp{#2#3#4}}}
+\endgroup
+
+\def\utfeightchardefs{%
+  \DeclareUnicodeCharacter{00A0}{\tie}
+  \DeclareUnicodeCharacter{00A1}{\exclamdown}
+  \DeclareUnicodeCharacter{00A3}{\pounds}
+  \DeclareUnicodeCharacter{00A8}{\"{ }}
+  \DeclareUnicodeCharacter{00A9}{\copyright}
+  \DeclareUnicodeCharacter{00AA}{\ordf}
+  \DeclareUnicodeCharacter{00AB}{\guillemetleft}
+  \DeclareUnicodeCharacter{00AD}{\-}
+  \DeclareUnicodeCharacter{00AE}{\registeredsymbol}
+  \DeclareUnicodeCharacter{00AF}{\={ }}
+
+  \DeclareUnicodeCharacter{00B0}{\ringaccent{ }}
+  \DeclareUnicodeCharacter{00B4}{\'{ }}
+  \DeclareUnicodeCharacter{00B8}{\cedilla{ }}
+  \DeclareUnicodeCharacter{00BA}{\ordm}
+  \DeclareUnicodeCharacter{00BB}{\guillemetright}
+  \DeclareUnicodeCharacter{00BF}{\questiondown}
+
+  \DeclareUnicodeCharacter{00C0}{\`A}
+  \DeclareUnicodeCharacter{00C1}{\'A}
+  \DeclareUnicodeCharacter{00C2}{\^A}
+  \DeclareUnicodeCharacter{00C3}{\~A}
+  \DeclareUnicodeCharacter{00C4}{\"A}
+  \DeclareUnicodeCharacter{00C5}{\AA}
+  \DeclareUnicodeCharacter{00C6}{\AE}
+  \DeclareUnicodeCharacter{00C7}{\cedilla{C}}
+  \DeclareUnicodeCharacter{00C8}{\`E}
+  \DeclareUnicodeCharacter{00C9}{\'E}
+  \DeclareUnicodeCharacter{00CA}{\^E}
+  \DeclareUnicodeCharacter{00CB}{\"E}
+  \DeclareUnicodeCharacter{00CC}{\`I}
+  \DeclareUnicodeCharacter{00CD}{\'I}
+  \DeclareUnicodeCharacter{00CE}{\^I}
+  \DeclareUnicodeCharacter{00CF}{\"I}
+
+  \DeclareUnicodeCharacter{00D0}{\DH}
+  \DeclareUnicodeCharacter{00D1}{\~N}
+  \DeclareUnicodeCharacter{00D2}{\`O}
+  \DeclareUnicodeCharacter{00D3}{\'O}
+  \DeclareUnicodeCharacter{00D4}{\^O}
+  \DeclareUnicodeCharacter{00D5}{\~O}
+  \DeclareUnicodeCharacter{00D6}{\"O}
+  \DeclareUnicodeCharacter{00D8}{\O}
+  \DeclareUnicodeCharacter{00D9}{\`U}
+  \DeclareUnicodeCharacter{00DA}{\'U}
+  \DeclareUnicodeCharacter{00DB}{\^U}
+  \DeclareUnicodeCharacter{00DC}{\"U}
+  \DeclareUnicodeCharacter{00DD}{\'Y}
+  \DeclareUnicodeCharacter{00DE}{\TH}
+  \DeclareUnicodeCharacter{00DF}{\ss}
+
+  \DeclareUnicodeCharacter{00E0}{\`a}
+  \DeclareUnicodeCharacter{00E1}{\'a}
+  \DeclareUnicodeCharacter{00E2}{\^a}
+  \DeclareUnicodeCharacter{00E3}{\~a}
+  \DeclareUnicodeCharacter{00E4}{\"a}
+  \DeclareUnicodeCharacter{00E5}{\aa}
+  \DeclareUnicodeCharacter{00E6}{\ae}
+  \DeclareUnicodeCharacter{00E7}{\cedilla{c}}
+  \DeclareUnicodeCharacter{00E8}{\`e}
+  \DeclareUnicodeCharacter{00E9}{\'e}
+  \DeclareUnicodeCharacter{00EA}{\^e}
+  \DeclareUnicodeCharacter{00EB}{\"e}
+  \DeclareUnicodeCharacter{00EC}{\`{\dotless{i}}}
+  \DeclareUnicodeCharacter{00ED}{\'{\dotless{i}}}
+  \DeclareUnicodeCharacter{00EE}{\^{\dotless{i}}}
+  \DeclareUnicodeCharacter{00EF}{\"{\dotless{i}}}
+
+  \DeclareUnicodeCharacter{00F0}{\dh}
+  \DeclareUnicodeCharacter{00F1}{\~n}
+  \DeclareUnicodeCharacter{00F2}{\`o}
+  \DeclareUnicodeCharacter{00F3}{\'o}
+  \DeclareUnicodeCharacter{00F4}{\^o}
+  \DeclareUnicodeCharacter{00F5}{\~o}
+  \DeclareUnicodeCharacter{00F6}{\"o}
+  \DeclareUnicodeCharacter{00F8}{\o}
+  \DeclareUnicodeCharacter{00F9}{\`u}
+  \DeclareUnicodeCharacter{00FA}{\'u}
+  \DeclareUnicodeCharacter{00FB}{\^u}
+  \DeclareUnicodeCharacter{00FC}{\"u}
+  \DeclareUnicodeCharacter{00FD}{\'y}
+  \DeclareUnicodeCharacter{00FE}{\th}
+  \DeclareUnicodeCharacter{00FF}{\"y}
+
+  \DeclareUnicodeCharacter{0100}{\=A}
+  \DeclareUnicodeCharacter{0101}{\=a}
+  \DeclareUnicodeCharacter{0102}{\u{A}}
+  \DeclareUnicodeCharacter{0103}{\u{a}}
+  \DeclareUnicodeCharacter{0104}{\ogonek{A}}
+  \DeclareUnicodeCharacter{0105}{\ogonek{a}}
+  \DeclareUnicodeCharacter{0106}{\'C}
+  \DeclareUnicodeCharacter{0107}{\'c}
+  \DeclareUnicodeCharacter{0108}{\^C}
+  \DeclareUnicodeCharacter{0109}{\^c}
+  \DeclareUnicodeCharacter{0118}{\ogonek{E}}
+  \DeclareUnicodeCharacter{0119}{\ogonek{e}}
+  \DeclareUnicodeCharacter{010A}{\dotaccent{C}}
+  \DeclareUnicodeCharacter{010B}{\dotaccent{c}}
+  \DeclareUnicodeCharacter{010C}{\v{C}}
+  \DeclareUnicodeCharacter{010D}{\v{c}}
+  \DeclareUnicodeCharacter{010E}{\v{D}}
+
+  \DeclareUnicodeCharacter{0112}{\=E}
+  \DeclareUnicodeCharacter{0113}{\=e}
+  \DeclareUnicodeCharacter{0114}{\u{E}}
+  \DeclareUnicodeCharacter{0115}{\u{e}}
+  \DeclareUnicodeCharacter{0116}{\dotaccent{E}}
+  \DeclareUnicodeCharacter{0117}{\dotaccent{e}}
+  \DeclareUnicodeCharacter{011A}{\v{E}}
+  \DeclareUnicodeCharacter{011B}{\v{e}}
+  \DeclareUnicodeCharacter{011C}{\^G}
+  \DeclareUnicodeCharacter{011D}{\^g}
+  \DeclareUnicodeCharacter{011E}{\u{G}}
+  \DeclareUnicodeCharacter{011F}{\u{g}}
+
+  \DeclareUnicodeCharacter{0120}{\dotaccent{G}}
+  \DeclareUnicodeCharacter{0121}{\dotaccent{g}}
+  \DeclareUnicodeCharacter{0124}{\^H}
+  \DeclareUnicodeCharacter{0125}{\^h}
+  \DeclareUnicodeCharacter{0128}{\~I}
+  \DeclareUnicodeCharacter{0129}{\~{\dotless{i}}}
+  \DeclareUnicodeCharacter{012A}{\=I}
+  \DeclareUnicodeCharacter{012B}{\={\dotless{i}}}
+  \DeclareUnicodeCharacter{012C}{\u{I}}
+  \DeclareUnicodeCharacter{012D}{\u{\dotless{i}}}
+
+  \DeclareUnicodeCharacter{0130}{\dotaccent{I}}
+  \DeclareUnicodeCharacter{0131}{\dotless{i}}
+  \DeclareUnicodeCharacter{0132}{IJ}
+  \DeclareUnicodeCharacter{0133}{ij}
+  \DeclareUnicodeCharacter{0134}{\^J}
+  \DeclareUnicodeCharacter{0135}{\^{\dotless{j}}}
+  \DeclareUnicodeCharacter{0139}{\'L}
+  \DeclareUnicodeCharacter{013A}{\'l}
+
+  \DeclareUnicodeCharacter{0141}{\L}
+  \DeclareUnicodeCharacter{0142}{\l}
+  \DeclareUnicodeCharacter{0143}{\'N}
+  \DeclareUnicodeCharacter{0144}{\'n}
+  \DeclareUnicodeCharacter{0147}{\v{N}}
+  \DeclareUnicodeCharacter{0148}{\v{n}}
+  \DeclareUnicodeCharacter{014C}{\=O}
+  \DeclareUnicodeCharacter{014D}{\=o}
+  \DeclareUnicodeCharacter{014E}{\u{O}}
+  \DeclareUnicodeCharacter{014F}{\u{o}}
+
+  \DeclareUnicodeCharacter{0150}{\H{O}}
+  \DeclareUnicodeCharacter{0151}{\H{o}}
+  \DeclareUnicodeCharacter{0152}{\OE}
+  \DeclareUnicodeCharacter{0153}{\oe}
+  \DeclareUnicodeCharacter{0154}{\'R}
+  \DeclareUnicodeCharacter{0155}{\'r}
+  \DeclareUnicodeCharacter{0158}{\v{R}}
+  \DeclareUnicodeCharacter{0159}{\v{r}}
+  \DeclareUnicodeCharacter{015A}{\'S}
+  \DeclareUnicodeCharacter{015B}{\'s}
+  \DeclareUnicodeCharacter{015C}{\^S}
+  \DeclareUnicodeCharacter{015D}{\^s}
+  \DeclareUnicodeCharacter{015E}{\cedilla{S}}
+  \DeclareUnicodeCharacter{015F}{\cedilla{s}}
+
+  \DeclareUnicodeCharacter{0160}{\v{S}}
+  \DeclareUnicodeCharacter{0161}{\v{s}}
+  \DeclareUnicodeCharacter{0162}{\cedilla{t}}
+  \DeclareUnicodeCharacter{0163}{\cedilla{T}}
+  \DeclareUnicodeCharacter{0164}{\v{T}}
+
+  \DeclareUnicodeCharacter{0168}{\~U}
+  \DeclareUnicodeCharacter{0169}{\~u}
+  \DeclareUnicodeCharacter{016A}{\=U}
+  \DeclareUnicodeCharacter{016B}{\=u}
+  \DeclareUnicodeCharacter{016C}{\u{U}}
+  \DeclareUnicodeCharacter{016D}{\u{u}}
+  \DeclareUnicodeCharacter{016E}{\ringaccent{U}}
+  \DeclareUnicodeCharacter{016F}{\ringaccent{u}}
+
+  \DeclareUnicodeCharacter{0170}{\H{U}}
+  \DeclareUnicodeCharacter{0171}{\H{u}}
+  \DeclareUnicodeCharacter{0174}{\^W}
+  \DeclareUnicodeCharacter{0175}{\^w}
+  \DeclareUnicodeCharacter{0176}{\^Y}
+  \DeclareUnicodeCharacter{0177}{\^y}
+  \DeclareUnicodeCharacter{0178}{\"Y}
+  \DeclareUnicodeCharacter{0179}{\'Z}
+  \DeclareUnicodeCharacter{017A}{\'z}
+  \DeclareUnicodeCharacter{017B}{\dotaccent{Z}}
+  \DeclareUnicodeCharacter{017C}{\dotaccent{z}}
+  \DeclareUnicodeCharacter{017D}{\v{Z}}
+  \DeclareUnicodeCharacter{017E}{\v{z}}
+
+  \DeclareUnicodeCharacter{01C4}{D\v{Z}}
+  \DeclareUnicodeCharacter{01C5}{D\v{z}}
+  \DeclareUnicodeCharacter{01C6}{d\v{z}}
+  \DeclareUnicodeCharacter{01C7}{LJ}
+  \DeclareUnicodeCharacter{01C8}{Lj}
+  \DeclareUnicodeCharacter{01C9}{lj}
+  \DeclareUnicodeCharacter{01CA}{NJ}
+  \DeclareUnicodeCharacter{01CB}{Nj}
+  \DeclareUnicodeCharacter{01CC}{nj}
+  \DeclareUnicodeCharacter{01CD}{\v{A}}
+  \DeclareUnicodeCharacter{01CE}{\v{a}}
+  \DeclareUnicodeCharacter{01CF}{\v{I}}
+
+  \DeclareUnicodeCharacter{01D0}{\v{\dotless{i}}}
+  \DeclareUnicodeCharacter{01D1}{\v{O}}
+  \DeclareUnicodeCharacter{01D2}{\v{o}}
+  \DeclareUnicodeCharacter{01D3}{\v{U}}
+  \DeclareUnicodeCharacter{01D4}{\v{u}}
+
+  \DeclareUnicodeCharacter{01E2}{\={\AE}}
+  \DeclareUnicodeCharacter{01E3}{\={\ae}}
+  \DeclareUnicodeCharacter{01E6}{\v{G}}
+  \DeclareUnicodeCharacter{01E7}{\v{g}}
+  \DeclareUnicodeCharacter{01E8}{\v{K}}
+  \DeclareUnicodeCharacter{01E9}{\v{k}}
+
+  \DeclareUnicodeCharacter{01F0}{\v{\dotless{j}}}
+  \DeclareUnicodeCharacter{01F1}{DZ}
+  \DeclareUnicodeCharacter{01F2}{Dz}
+  \DeclareUnicodeCharacter{01F3}{dz}
+  \DeclareUnicodeCharacter{01F4}{\'G}
+  \DeclareUnicodeCharacter{01F5}{\'g}
+  \DeclareUnicodeCharacter{01F8}{\`N}
+  \DeclareUnicodeCharacter{01F9}{\`n}
+  \DeclareUnicodeCharacter{01FC}{\'{\AE}}
+  \DeclareUnicodeCharacter{01FD}{\'{\ae}}
+  \DeclareUnicodeCharacter{01FE}{\'{\O}}
+  \DeclareUnicodeCharacter{01FF}{\'{\o}}
+
+  \DeclareUnicodeCharacter{021E}{\v{H}}
+  \DeclareUnicodeCharacter{021F}{\v{h}}
+
+  \DeclareUnicodeCharacter{0226}{\dotaccent{A}}
+  \DeclareUnicodeCharacter{0227}{\dotaccent{a}}
+  \DeclareUnicodeCharacter{0228}{\cedilla{E}}
+  \DeclareUnicodeCharacter{0229}{\cedilla{e}}
+  \DeclareUnicodeCharacter{022E}{\dotaccent{O}}
+  \DeclareUnicodeCharacter{022F}{\dotaccent{o}}
+
+  \DeclareUnicodeCharacter{0232}{\=Y}
+  \DeclareUnicodeCharacter{0233}{\=y}
+  \DeclareUnicodeCharacter{0237}{\dotless{j}}
+
+  \DeclareUnicodeCharacter{02DB}{\ogonek{ }}
+
+  \DeclareUnicodeCharacter{1E02}{\dotaccent{B}}
+  \DeclareUnicodeCharacter{1E03}{\dotaccent{b}}
+  \DeclareUnicodeCharacter{1E04}{\udotaccent{B}}
+  \DeclareUnicodeCharacter{1E05}{\udotaccent{b}}
+  \DeclareUnicodeCharacter{1E06}{\ubaraccent{B}}
+  \DeclareUnicodeCharacter{1E07}{\ubaraccent{b}}
+  \DeclareUnicodeCharacter{1E0A}{\dotaccent{D}}
+  \DeclareUnicodeCharacter{1E0B}{\dotaccent{d}}
+  \DeclareUnicodeCharacter{1E0C}{\udotaccent{D}}
+  \DeclareUnicodeCharacter{1E0D}{\udotaccent{d}}
+  \DeclareUnicodeCharacter{1E0E}{\ubaraccent{D}}
+  \DeclareUnicodeCharacter{1E0F}{\ubaraccent{d}}
+
+  \DeclareUnicodeCharacter{1E1E}{\dotaccent{F}}
+  \DeclareUnicodeCharacter{1E1F}{\dotaccent{f}}
+
+  \DeclareUnicodeCharacter{1E20}{\=G}
+  \DeclareUnicodeCharacter{1E21}{\=g}
+  \DeclareUnicodeCharacter{1E22}{\dotaccent{H}}
+  \DeclareUnicodeCharacter{1E23}{\dotaccent{h}}
+  \DeclareUnicodeCharacter{1E24}{\udotaccent{H}}
+  \DeclareUnicodeCharacter{1E25}{\udotaccent{h}}
+  \DeclareUnicodeCharacter{1E26}{\"H}
+  \DeclareUnicodeCharacter{1E27}{\"h}
+
+  \DeclareUnicodeCharacter{1E30}{\'K}
+  \DeclareUnicodeCharacter{1E31}{\'k}
+  \DeclareUnicodeCharacter{1E32}{\udotaccent{K}}
+  \DeclareUnicodeCharacter{1E33}{\udotaccent{k}}
+  \DeclareUnicodeCharacter{1E34}{\ubaraccent{K}}
+  \DeclareUnicodeCharacter{1E35}{\ubaraccent{k}}
+  \DeclareUnicodeCharacter{1E36}{\udotaccent{L}}
+  \DeclareUnicodeCharacter{1E37}{\udotaccent{l}}
+  \DeclareUnicodeCharacter{1E3A}{\ubaraccent{L}}
+  \DeclareUnicodeCharacter{1E3B}{\ubaraccent{l}}
+  \DeclareUnicodeCharacter{1E3E}{\'M}
+  \DeclareUnicodeCharacter{1E3F}{\'m}
+
+  \DeclareUnicodeCharacter{1E40}{\dotaccent{M}}
+  \DeclareUnicodeCharacter{1E41}{\dotaccent{m}}
+  \DeclareUnicodeCharacter{1E42}{\udotaccent{M}}
+  \DeclareUnicodeCharacter{1E43}{\udotaccent{m}}
+  \DeclareUnicodeCharacter{1E44}{\dotaccent{N}}
+  \DeclareUnicodeCharacter{1E45}{\dotaccent{n}}
+  \DeclareUnicodeCharacter{1E46}{\udotaccent{N}}
+  \DeclareUnicodeCharacter{1E47}{\udotaccent{n}}
+  \DeclareUnicodeCharacter{1E48}{\ubaraccent{N}}
+  \DeclareUnicodeCharacter{1E49}{\ubaraccent{n}}
+
+  \DeclareUnicodeCharacter{1E54}{\'P}
+  \DeclareUnicodeCharacter{1E55}{\'p}
+  \DeclareUnicodeCharacter{1E56}{\dotaccent{P}}
+  \DeclareUnicodeCharacter{1E57}{\dotaccent{p}}
+  \DeclareUnicodeCharacter{1E58}{\dotaccent{R}}
+  \DeclareUnicodeCharacter{1E59}{\dotaccent{r}}
+  \DeclareUnicodeCharacter{1E5A}{\udotaccent{R}}
+  \DeclareUnicodeCharacter{1E5B}{\udotaccent{r}}
+  \DeclareUnicodeCharacter{1E5E}{\ubaraccent{R}}
+  \DeclareUnicodeCharacter{1E5F}{\ubaraccent{r}}
+
+  \DeclareUnicodeCharacter{1E60}{\dotaccent{S}}
+  \DeclareUnicodeCharacter{1E61}{\dotaccent{s}}
+  \DeclareUnicodeCharacter{1E62}{\udotaccent{S}}
+  \DeclareUnicodeCharacter{1E63}{\udotaccent{s}}
+  \DeclareUnicodeCharacter{1E6A}{\dotaccent{T}}
+  \DeclareUnicodeCharacter{1E6B}{\dotaccent{t}}
+  \DeclareUnicodeCharacter{1E6C}{\udotaccent{T}}
+  \DeclareUnicodeCharacter{1E6D}{\udotaccent{t}}
+  \DeclareUnicodeCharacter{1E6E}{\ubaraccent{T}}
+  \DeclareUnicodeCharacter{1E6F}{\ubaraccent{t}}
+
+  \DeclareUnicodeCharacter{1E7C}{\~V}
+  \DeclareUnicodeCharacter{1E7D}{\~v}
+  \DeclareUnicodeCharacter{1E7E}{\udotaccent{V}}
+  \DeclareUnicodeCharacter{1E7F}{\udotaccent{v}}
+
+  \DeclareUnicodeCharacter{1E80}{\`W}
+  \DeclareUnicodeCharacter{1E81}{\`w}
+  \DeclareUnicodeCharacter{1E82}{\'W}
+  \DeclareUnicodeCharacter{1E83}{\'w}
+  \DeclareUnicodeCharacter{1E84}{\"W}
+  \DeclareUnicodeCharacter{1E85}{\"w}
+  \DeclareUnicodeCharacter{1E86}{\dotaccent{W}}
+  \DeclareUnicodeCharacter{1E87}{\dotaccent{w}}
+  \DeclareUnicodeCharacter{1E88}{\udotaccent{W}}
+  \DeclareUnicodeCharacter{1E89}{\udotaccent{w}}
+  \DeclareUnicodeCharacter{1E8A}{\dotaccent{X}}
+  \DeclareUnicodeCharacter{1E8B}{\dotaccent{x}}
+  \DeclareUnicodeCharacter{1E8C}{\"X}
+  \DeclareUnicodeCharacter{1E8D}{\"x}
+  \DeclareUnicodeCharacter{1E8E}{\dotaccent{Y}}
+  \DeclareUnicodeCharacter{1E8F}{\dotaccent{y}}
+
+  \DeclareUnicodeCharacter{1E90}{\^Z}
+  \DeclareUnicodeCharacter{1E91}{\^z}
+  \DeclareUnicodeCharacter{1E92}{\udotaccent{Z}}
+  \DeclareUnicodeCharacter{1E93}{\udotaccent{z}}
+  \DeclareUnicodeCharacter{1E94}{\ubaraccent{Z}}
+  \DeclareUnicodeCharacter{1E95}{\ubaraccent{z}}
+  \DeclareUnicodeCharacter{1E96}{\ubaraccent{h}}
+  \DeclareUnicodeCharacter{1E97}{\"t}
+  \DeclareUnicodeCharacter{1E98}{\ringaccent{w}}
+  \DeclareUnicodeCharacter{1E99}{\ringaccent{y}}
+
+  \DeclareUnicodeCharacter{1EA0}{\udotaccent{A}}
+  \DeclareUnicodeCharacter{1EA1}{\udotaccent{a}}
+
+  \DeclareUnicodeCharacter{1EB8}{\udotaccent{E}}
+  \DeclareUnicodeCharacter{1EB9}{\udotaccent{e}}
+  \DeclareUnicodeCharacter{1EBC}{\~E}
+  \DeclareUnicodeCharacter{1EBD}{\~e}
+
+  \DeclareUnicodeCharacter{1ECA}{\udotaccent{I}}
+  \DeclareUnicodeCharacter{1ECB}{\udotaccent{i}}
+  \DeclareUnicodeCharacter{1ECC}{\udotaccent{O}}
+  \DeclareUnicodeCharacter{1ECD}{\udotaccent{o}}
+
+  \DeclareUnicodeCharacter{1EE4}{\udotaccent{U}}
+  \DeclareUnicodeCharacter{1EE5}{\udotaccent{u}}
+
+  \DeclareUnicodeCharacter{1EF2}{\`Y}
+  \DeclareUnicodeCharacter{1EF3}{\`y}
+  \DeclareUnicodeCharacter{1EF4}{\udotaccent{Y}}
+
+  \DeclareUnicodeCharacter{1EF8}{\~Y}
+  \DeclareUnicodeCharacter{1EF9}{\~y}
+
+  \DeclareUnicodeCharacter{2013}{--}
+  \DeclareUnicodeCharacter{2014}{---}
+  \DeclareUnicodeCharacter{2018}{\quoteleft}
+  \DeclareUnicodeCharacter{2019}{\quoteright}
+  \DeclareUnicodeCharacter{201A}{\quotesinglbase}
+  \DeclareUnicodeCharacter{201C}{\quotedblleft}
+  \DeclareUnicodeCharacter{201D}{\quotedblright}
+  \DeclareUnicodeCharacter{201E}{\quotedblbase}
+  \DeclareUnicodeCharacter{2022}{\bullet}
+  \DeclareUnicodeCharacter{2026}{\dots}
+  \DeclareUnicodeCharacter{2039}{\guilsinglleft}
+  \DeclareUnicodeCharacter{203A}{\guilsinglright}
+  \DeclareUnicodeCharacter{20AC}{\euro}
+
+  \DeclareUnicodeCharacter{2192}{\expansion}
+  \DeclareUnicodeCharacter{21D2}{\result}
+
+  \DeclareUnicodeCharacter{2212}{\minus}
+  \DeclareUnicodeCharacter{2217}{\point}
+  \DeclareUnicodeCharacter{2261}{\equiv}
+}% end of \utfeightchardefs
+
+
+% US-ASCII character definitions.
+\def\asciichardefs{% nothing need be done
+   \relax
+}
+
+% Make non-ASCII characters printable again for compatibility with
+% existing Texinfo documents that may use them, even without declaring a
+% document encoding.
+%
+\setnonasciicharscatcode \other
+
+
+\message{formatting,}
+
+\newdimen\defaultparindent \defaultparindent = 15pt
+
+\chapheadingskip = 15pt plus 4pt minus 2pt
+\secheadingskip = 12pt plus 3pt minus 2pt
+\subsecheadingskip = 9pt plus 2pt minus 2pt
+
+% Prevent underfull vbox error messages.
+\vbadness = 10000
+
+% Don't be very finicky about underfull hboxes, either.
+\hbadness = 6666
+
+% Following George Bush, get rid of widows and orphans.
+\widowpenalty=10000
+\clubpenalty=10000
+
+% Use TeX 3.0's \emergencystretch to help line breaking, but if we're
+% using an old version of TeX, don't do anything.  We want the amount of
+% stretch added to depend on the line length, hence the dependence on
+% \hsize.  We call this whenever the paper size is set.
+%
+\def\setemergencystretch{%
+  \ifx\emergencystretch\thisisundefined
+    % Allow us to assign to \emergencystretch anyway.
+    \def\emergencystretch{\dimen0}%
+  \else
+    \emergencystretch = .15\hsize
+  \fi
+}
+
+% Parameters in order: 1) textheight; 2) textwidth;
+% 3) voffset; 4) hoffset; 5) binding offset; 6) topskip;
+% 7) physical page height; 8) physical page width.
+%
+% We also call \setleading{\textleading}, so the caller should define
+% \textleading.  The caller should also set \parskip.
+%
+\def\internalpagesizes#1#2#3#4#5#6#7#8{%
+  \voffset = #3\relax
+  \topskip = #6\relax
+  \splittopskip = \topskip
+  %
+  \vsize = #1\relax
+  \advance\vsize by \topskip
+  \outervsize = \vsize
+  \advance\outervsize by 2\topandbottommargin
+  \pageheight = \vsize
+  %
+  \hsize = #2\relax
+  \outerhsize = \hsize
+  \advance\outerhsize by 0.5in
+  \pagewidth = \hsize
+  %
+  \normaloffset = #4\relax
+  \bindingoffset = #5\relax
+  %
+  \ifpdf
+    \pdfpageheight #7\relax
+    \pdfpagewidth #8\relax
+    % if we don't reset these, they will remain at "1 true in" of
+    % whatever layout pdftex was dumped with.
+    \pdfhorigin = 1 true in
+    \pdfvorigin = 1 true in
+  \fi
+  %
+  \setleading{\textleading}
+  %
+  \parindent = \defaultparindent
+  \setemergencystretch
+}
+
+% @letterpaper (the default).
+\def\letterpaper{{\globaldefs = 1
+  \parskip = 3pt plus 2pt minus 1pt
+  \textleading = 13.2pt
+  %
+  % If page is nothing but text, make it come out even.
+  \internalpagesizes{607.2pt}{6in}% that's 46 lines
+                    {\voffset}{.25in}%
+                    {\bindingoffset}{36pt}%
+                    {11in}{8.5in}%
+}}
+
+% Use @smallbook to reset parameters for 7x9.25 trim size.
+\def\smallbook{{\globaldefs = 1
+  \parskip = 2pt plus 1pt
+  \textleading = 12pt
+  %
+  \internalpagesizes{7.5in}{5in}%
+                    {-.2in}{0in}%
+                    {\bindingoffset}{16pt}%
+                    {9.25in}{7in}%
+  %
+  \lispnarrowing = 0.3in
+  \tolerance = 700
+  \hfuzz = 1pt
+  \contentsrightmargin = 0pt
+  \defbodyindent = .5cm
+}}
+
+% Use @smallerbook to reset parameters for 6x9 trim size.
+% (Just testing, parameters still in flux.)
+\def\smallerbook{{\globaldefs = 1
+  \parskip = 1.5pt plus 1pt
+  \textleading = 12pt
+  %
+  \internalpagesizes{7.4in}{4.8in}%
+                    {-.2in}{-.4in}%
+                    {0pt}{14pt}%
+                    {9in}{6in}%
+  %
+  \lispnarrowing = 0.25in
+  \tolerance = 700
+  \hfuzz = 1pt
+  \contentsrightmargin = 0pt
+  \defbodyindent = .4cm
+}}
+
+% Use @afourpaper to print on European A4 paper.
+\def\afourpaper{{\globaldefs = 1
+  \parskip = 3pt plus 2pt minus 1pt
+  \textleading = 13.2pt
+  %
+  % Double-side printing via postscript on Laserjet 4050
+  % prints double-sided nicely when \bindingoffset=10mm and \hoffset=-6mm.
+  % To change the settings for a different printer or situation, adjust
+  % \normaloffset until the front-side and back-side texts align.  Then
+  % do the same for \bindingoffset.  You can set these for testing in
+  % your texinfo source file like this:
+  % @tex
+  % \global\normaloffset = -6mm
+  % \global\bindingoffset = 10mm
+  % @end tex
+  \internalpagesizes{673.2pt}{160mm}% that's 51 lines
+                    {\voffset}{\hoffset}%
+                    {\bindingoffset}{44pt}%
+                    {297mm}{210mm}%
+  %
+  \tolerance = 700
+  \hfuzz = 1pt
+  \contentsrightmargin = 0pt
+  \defbodyindent = 5mm
+}}
+
+% Use @afivepaper to print on European A5 paper.
+% From romildo@urano.iceb.ufop.br, 2 July 2000.
+% He also recommends making @example and @lisp be small.
+\def\afivepaper{{\globaldefs = 1
+  \parskip = 2pt plus 1pt minus 0.1pt
+  \textleading = 12.5pt
+  %
+  \internalpagesizes{160mm}{120mm}%
+                    {\voffset}{\hoffset}%
+                    {\bindingoffset}{8pt}%
+                    {210mm}{148mm}%
+  %
+  \lispnarrowing = 0.2in
+  \tolerance = 800
+  \hfuzz = 1.2pt
+  \contentsrightmargin = 0pt
+  \defbodyindent = 2mm
+  \tableindent = 12mm
+}}
+
+% A specific text layout, 24x15cm overall, intended for A4 paper.
+\def\afourlatex{{\globaldefs = 1
+  \afourpaper
+  \internalpagesizes{237mm}{150mm}%
+                    {\voffset}{4.6mm}%
+                    {\bindingoffset}{7mm}%
+                    {297mm}{210mm}%
+  %
+  % Must explicitly reset to 0 because we call \afourpaper.
+  \globaldefs = 0
+}}
+
+% Use @afourwide to print on A4 paper in landscape format.
+\def\afourwide{{\globaldefs = 1
+  \afourpaper
+  \internalpagesizes{241mm}{165mm}%
+                    {\voffset}{-2.95mm}%
+                    {\bindingoffset}{7mm}%
+                    {297mm}{210mm}%
+  \globaldefs = 0
+}}
+
+% @pagesizes TEXTHEIGHT[,TEXTWIDTH]
+% Perhaps we should allow setting the margins, \topskip, \parskip,
+% and/or leading, also. Or perhaps we should compute them somehow.
+%
+\parseargdef\pagesizes{\pagesizesyyy #1,,\finish}
+\def\pagesizesyyy#1,#2,#3\finish{{%
+  \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \hsize=#2\relax \fi
+  \globaldefs = 1
+  %
+  \parskip = 3pt plus 2pt minus 1pt
+  \setleading{\textleading}%
+  %
+  \dimen0 = #1\relax
+  \advance\dimen0 by \voffset
+  %
+  \dimen2 = \hsize
+  \advance\dimen2 by \normaloffset
+  %
+  \internalpagesizes{#1}{\hsize}%
+                    {\voffset}{\normaloffset}%
+                    {\bindingoffset}{44pt}%
+                    {\dimen0}{\dimen2}%
+}}
+
+% Set default to letter.
+%
+\letterpaper
+
+
+\message{and turning on texinfo input format.}
+
+\def^^L{\par} % remove \outer, so ^L can appear in an @comment
+
+% DEL is a comment character, in case @c does not suffice.
+\catcode`\^^? = 14
+
+% Define macros to output various characters with catcode for normal text.
+\catcode`\"=\other \def\normaldoublequote{"}
+\catcode`\$=\other \def\normaldollar{$}%$ font-lock fix
+\catcode`\+=\other \def\normalplus{+}
+\catcode`\<=\other \def\normalless{<}
+\catcode`\>=\other \def\normalgreater{>}
+\catcode`\^=\other \def\normalcaret{^}
+\catcode`\_=\other \def\normalunderscore{_}
+\catcode`\|=\other \def\normalverticalbar{|}
+\catcode`\~=\other \def\normaltilde{~}
+
+% This macro is used to make a character print one way in \tt
+% (where it can probably be output as-is), and another way in other fonts,
+% where something hairier probably needs to be done.
+%
+% #1 is what to print if we are indeed using \tt; #2 is what to print
+% otherwise.  Since all the Computer Modern typewriter fonts have zero
+% interword stretch (and shrink), and it is reasonable to expect all
+% typewriter fonts to have this, we can check that font parameter.
+%
+\def\ifusingtt#1#2{\ifdim \fontdimen3\font=0pt #1\else #2\fi}
+
+% Same as above, but check for italic font.  Actually this also catches
+% non-italic slanted fonts since it is impossible to distinguish them from
+% italic fonts.  But since this is only used by $ and it uses \sl anyway
+% this is not a problem.
+\def\ifusingit#1#2{\ifdim \fontdimen1\font>0pt #1\else #2\fi}
+
+% Turn off all special characters except @
+% (and those which the user can use as if they were ordinary).
+% Most of these we simply print from the \tt font, but for some, we can
+% use math or other variants that look better in normal text.
+
+\catcode`\"=\active
+\def\activedoublequote{{\tt\char34}}
+\let"=\activedoublequote
+\catcode`\~=\active
+\def~{{\tt\char126}}
+\chardef\hat=`\^
+\catcode`\^=\active
+\def^{{\tt \hat}}
+
+\catcode`\_=\active
+\def_{\ifusingtt\normalunderscore\_}
+\let\realunder=_
+% Subroutine for the previous macro.
+\def\_{\leavevmode \kern.07em \vbox{\hrule width.3em height.1ex}\kern .07em }
+
+\catcode`\|=\active
+\def|{{\tt\char124}}
+\chardef \less=`\<
+\catcode`\<=\active
+\def<{{\tt \less}}
+\chardef \gtr=`\>
+\catcode`\>=\active
+\def>{{\tt \gtr}}
+\catcode`\+=\active
+\def+{{\tt \char 43}}
+\catcode`\$=\active
+\def${\ifusingit{{\sl\$}}\normaldollar}%$ font-lock fix
+
+% If a .fmt file is being used, characters that might appear in a file
+% name cannot be active until we have parsed the command line.
+% So turn them off again, and have \everyjob (or @setfilename) turn them on.
+% \otherifyactive is called near the end of this file.
+\def\otherifyactive{\catcode`+=\other \catcode`\_=\other}
+
+% Used sometimes to turn off (effectively) the active characters even after
+% parsing them.
+\def\turnoffactive{%
+  \normalturnoffactive
+  \otherbackslash
+}
+
+\catcode`\@=0
+
+% \backslashcurfont outputs one backslash character in current font,
+% as in \char`\\.
+\global\chardef\backslashcurfont=`\\
+\global\let\rawbackslashxx=\backslashcurfont  % let existing .??s files work
+
+% \realbackslash is an actual character `\' with catcode other, and
+% \doublebackslash is two of them (for the pdf outlines).
+{\catcode`\\=\other @gdef@realbackslash{\} @gdef@doublebackslash{\\}}
+
+% In texinfo, backslash is an active character; it prints the backslash
+% in fixed width font.
+\catcode`\\=\active  % @ for escape char from now on.
+
+% The story here is that in math mode, the \char of \backslashcurfont
+% ends up printing the roman \ from the math symbol font (because \char
+% in math mode uses the \mathcode, and plain.tex sets
+% \mathcode`\\="026E).  It seems better for @backslashchar{} to always
+% print a typewriter backslash, hence we use an explicit \mathchar,
+% which is the decimal equivalent of "715c (class 7, e.g., use \fam;
+% ignored family value; char position "5C).  We can't use " for the
+% usual hex value because it has already been made active.
+@def@normalbackslash{{@tt @ifmmode @mathchar29020 @else @backslashcurfont @fi}}
+@let@backslashchar = @normalbackslash % @backslashchar{} is for user documents.
+
+% On startup, @fixbackslash assigns:
+%  @let \ = @normalbackslash
+% \rawbackslash defines an active \ to do \backslashcurfont.
+% \otherbackslash defines an active \ to be a literal `\' character with
+% catcode other.  We switch back and forth between these.
+@gdef@rawbackslash{@let\=@backslashcurfont}
+@gdef@otherbackslash{@let\=@realbackslash}
+
+% Same as @turnoffactive except outputs \ as {\tt\char`\\} instead of
+% the literal character `\'.  Also revert - to its normal character, in
+% case the active - from code has slipped in.
+%
+{@catcode`- = @active
+ @gdef@normalturnoffactive{%
+   @let-=@normaldash
+   @let"=@normaldoublequote
+   @let$=@normaldollar %$ font-lock fix
+   @let+=@normalplus
+   @let<=@normalless
+   @let>=@normalgreater
+   @let\=@normalbackslash
+   @let^=@normalcaret
+   @let_=@normalunderscore
+   @let|=@normalverticalbar
+   @let~=@normaltilde
+   @markupsetuplqdefault
+   @markupsetuprqdefault
+   @unsepspaces
+ }
+}
+
+% Make _ and + \other characters, temporarily.
+% This is canceled by @fixbackslash.
+@otherifyactive
+
+% If a .fmt file is being used, we don't want the `\input texinfo' to show up.
+% That is what \eatinput is for; after that, the `\' should revert to printing
+% a backslash.
+%
+@gdef@eatinput input texinfo{@fixbackslash}
+@global@let\ = @eatinput
+
+% On the other hand, perhaps the file did not have a `\input texinfo'. Then
+% the first `\' in the file would cause an error. This macro tries to fix
+% that, assuming it is called before the first `\' could plausibly occur.
+% Also turn back on active characters that might appear in the input
+% file name, in case not using a pre-dumped format.
+%
+@gdef@fixbackslash{%
+  @ifx\@eatinput @let\ = @normalbackslash @fi
+  @catcode`+=@active
+  @catcode`@_=@active
+}
+
+% Say @foo, not \foo, in error messages.
+@escapechar = `@@
+
+% These (along with & and #) are made active for url-breaking, so need
+% active definitions as the normal characters.
+@def@normaldot{.}
+@def@normalquest{?}
+@def@normalslash{/}
+
+% These look ok in all fonts, so just make them not special.
+% @hashchar{} gets its own user-level command, because of #line.
+@catcode`@& = @other @def@normalamp{&}
+@catcode`@# = @other @def@normalhash{#}
+@catcode`@% = @other @def@normalpercent{%}
+
+@let @hashchar = @normalhash
+
+@c Finally, make ` and ' active, so that txicodequoteundirected and
+@c txicodequotebacktick work right in, e.g., @w{@code{`foo'}}.  If we
+@c don't make ` and ' active, @code will not get them as active chars.
+@c Do this last of all since we use ` in the previous @catcode assignments.
+@catcode`@'=@active
+@catcode`@`=@active
+@markupsetuplqdefault
+@markupsetuprqdefault
+
+@c Local variables:
+@c eval: (add-hook 'write-file-hooks 'time-stamp)
+@c page-delimiter: "^\\\\message"
+@c time-stamp-start: "def\\\\texinfoversion{"
+@c time-stamp-format: "%:y-%02m-%02d.%02H"
+@c time-stamp-end: "}"
+@c End:
+
+@c vim:sw=2:
+
+@ignore
+   arch-tag: e1b36e32-c96e-4135-a41a-0b2efa2ea115
+@end ignore
diff --git a/third_party/gmp/doc/version.texi b/third_party/gmp/doc/version.texi
new file mode 100644
index 0000000..e62c3db
--- /dev/null
+++ b/third_party/gmp/doc/version.texi
@@ -0,0 +1,4 @@
+@set UPDATED 17 January 2020
+@set UPDATED-MONTH January 2020
+@set EDITION 6.2.0
+@set VERSION 6.2.0
diff --git a/third_party/gmp/errno.c b/third_party/gmp/errno.c
new file mode 100644
index 0000000..b4be555
--- /dev/null
+++ b/third_party/gmp/errno.c
@@ -0,0 +1,72 @@
+/* gmp_errno, __gmp_exception -- exception handling and reporting.
+
+   THE FUNCTIONS IN THIS FILE, APART FROM gmp_errno, ARE FOR INTERNAL USE
+   ONLY.  THEY'RE ALMOST CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR
+   DISAPPEAR COMPLETELY IN FUTURE GNU MP RELEASES.
+
+Copyright 2000, 2001, 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdlib.h>
+
+#include <signal.h>
+
+#include "gmp-impl.h"
+
+int gmp_errno = 0;
+
+
+/* Use SIGFPE on systems which have it. Otherwise, deliberate divide
+   by zero, which triggers an exception on most systems. On those
+   where it doesn't, for example power and powerpc, use abort instead. */
+void
+__gmp_exception (int error_bit)
+{
+  gmp_errno |= error_bit;
+#ifdef SIGFPE
+  raise (SIGFPE);
+#else
+  __gmp_junk = 10 / __gmp_0;
+#endif
+  abort ();
+}
+
+
+/* These functions minimize the amount of code required in functions raising
+   exceptions.  Since they're "noreturn" and don't take any parameters, a
+   test and call might even come out as a simple conditional jump.  */
+void
+__gmp_sqrt_of_negative (void)
+{
+  __gmp_exception (GMP_ERROR_SQRT_OF_NEGATIVE);
+}
+void
+__gmp_divide_by_zero (void)
+{
+  __gmp_exception (GMP_ERROR_DIVISION_BY_ZERO);
+}
diff --git a/third_party/gmp/extract-dbl.c b/third_party/gmp/extract-dbl.c
new file mode 100644
index 0000000..e44d6fa
--- /dev/null
+++ b/third_party/gmp/extract-dbl.c
@@ -0,0 +1,310 @@
+/* __gmp_extract_double -- convert from double to array of mp_limb_t.
+
+Copyright 1996, 1999-2002, 2006, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#ifdef XDEBUG
+#undef _GMP_IEEE_FLOATS
+#endif
+
+#ifndef _GMP_IEEE_FLOATS
+#define _GMP_IEEE_FLOATS 0
+#endif
+
+/* Extract a non-negative double in d.  */
+
+int
+__gmp_extract_double (mp_ptr rp, double d)
+{
+  long exp;
+  unsigned sc;
+#ifdef _LONG_LONG_LIMB
+#define BITS_PER_PART 64	/* somewhat bogus */
+  unsigned long long int manl;
+#else
+#define BITS_PER_PART GMP_LIMB_BITS
+  unsigned long int manh, manl;
+#endif
+
+  /* BUGS
+
+     1. Should handle Inf and NaN in IEEE specific code.
+     2. Handle Inf and NaN also in default code, to avoid hangs.
+     3. Generalize to handle all GMP_LIMB_BITS >= 32.
+     4. This lits is incomplete and misspelled.
+   */
+
+  ASSERT (d >= 0.0);
+
+  if (d == 0.0)
+    {
+      MPN_ZERO (rp, LIMBS_PER_DOUBLE);
+      return 0;
+    }
+
+#if _GMP_IEEE_FLOATS
+  {
+#if defined (__alpha) && __GNUC__ == 2 && __GNUC_MINOR__ == 8
+    /* Work around alpha-specific bug in GCC 2.8.x.  */
+    volatile
+#endif
+    union ieee_double_extract x;
+    x.d = d;
+    exp = x.s.exp;
+#if BITS_PER_PART == 64		/* generalize this to BITS_PER_PART > BITS_IN_MANTISSA */
+    manl = (((mp_limb_t) 1 << 63)
+	    | ((mp_limb_t) x.s.manh << 43) | ((mp_limb_t) x.s.manl << 11));
+    if (exp == 0)
+      {
+	/* Denormalized number.  Don't try to be clever about this,
+	   since it is not an important case to make fast.  */
+	exp = 1;
+	do
+	  {
+	    manl = manl << 1;
+	    exp--;
+	  }
+	while ((manl & GMP_LIMB_HIGHBIT) == 0);
+      }
+#endif
+#if BITS_PER_PART == 32
+    manh = ((mp_limb_t) 1 << 31) | (x.s.manh << 11) | (x.s.manl >> 21);
+    manl = x.s.manl << 11;
+    if (exp == 0)
+      {
+	/* Denormalized number.  Don't try to be clever about this,
+	   since it is not an important case to make fast.  */
+	exp = 1;
+	do
+	  {
+	    manh = (manh << 1) | (manl >> 31);
+	    manl = manl << 1;
+	    exp--;
+	  }
+	while ((manh & GMP_LIMB_HIGHBIT) == 0);
+      }
+#endif
+#if BITS_PER_PART != 32 && BITS_PER_PART != 64
+  You need to generalize the code above to handle this.
+#endif
+    exp -= 1022;		/* Remove IEEE bias.  */
+  }
+#else
+  {
+    /* Unknown (or known to be non-IEEE) double format.  */
+    exp = 0;
+    if (d >= 1.0)
+      {
+	ASSERT_ALWAYS (d * 0.5 != d);
+
+	while (d >= 32768.0)
+	  {
+	    d *= (1.0 / 65536.0);
+	    exp += 16;
+	  }
+	while (d >= 1.0)
+	  {
+	    d *= 0.5;
+	    exp += 1;
+	  }
+      }
+    else if (d < 0.5)
+      {
+	while (d < (1.0 / 65536.0))
+	  {
+	    d *=  65536.0;
+	    exp -= 16;
+	  }
+	while (d < 0.5)
+	  {
+	    d *= 2.0;
+	    exp -= 1;
+	  }
+      }
+
+    d *= (4.0 * ((unsigned long int) 1 << (BITS_PER_PART - 2)));
+#if BITS_PER_PART == 64
+    manl = d;
+#endif
+#if BITS_PER_PART == 32
+    manh = d;
+    manl = (d - manh) * (4.0 * ((unsigned long int) 1 << (BITS_PER_PART - 2)));
+#endif
+  }
+#endif /* IEEE */
+
+  sc = (unsigned) (exp + 64 * GMP_NUMB_BITS) % GMP_NUMB_BITS;
+
+  /* We add something here to get rounding right.  */
+  exp = (exp + 64 * GMP_NUMB_BITS) / GMP_NUMB_BITS - 64 * GMP_NUMB_BITS / GMP_NUMB_BITS + 1;
+
+#if BITS_PER_PART == 64 && LIMBS_PER_DOUBLE == 2
+#if GMP_NAIL_BITS == 0
+  if (sc != 0)
+    {
+      rp[1] = manl >> (GMP_LIMB_BITS - sc);
+      rp[0] = manl << sc;
+    }
+  else
+    {
+      rp[1] = manl;
+      rp[0] = 0;
+      exp--;
+    }
+#else
+  if (sc > GMP_NAIL_BITS)
+    {
+      rp[1] = manl >> (GMP_LIMB_BITS - sc);
+      rp[0] = (manl << (sc - GMP_NAIL_BITS)) & GMP_NUMB_MASK;
+    }
+  else
+    {
+      if (sc == 0)
+	{
+	  rp[1] = manl >> GMP_NAIL_BITS;
+	  rp[0] = (manl << GMP_NUMB_BITS - GMP_NAIL_BITS) & GMP_NUMB_MASK;
+	  exp--;
+	}
+      else
+	{
+	  rp[1] = manl >> (GMP_LIMB_BITS - sc);
+	  rp[0] = (manl >> (GMP_NAIL_BITS - sc)) & GMP_NUMB_MASK;
+	}
+    }
+#endif
+#endif
+
+#if BITS_PER_PART == 64 && LIMBS_PER_DOUBLE == 3
+  if (sc > GMP_NAIL_BITS)
+    {
+      rp[2] = manl >> (GMP_LIMB_BITS - sc);
+      rp[1] = (manl << sc - GMP_NAIL_BITS) & GMP_NUMB_MASK;
+      if (sc >= 2 * GMP_NAIL_BITS)
+	rp[0] = 0;
+      else
+	rp[0] = (manl << GMP_NUMB_BITS - GMP_NAIL_BITS + sc) & GMP_NUMB_MASK;
+    }
+  else
+    {
+      if (sc == 0)
+	{
+	  rp[2] = manl >> GMP_NAIL_BITS;
+	  rp[1] = (manl << GMP_NUMB_BITS - GMP_NAIL_BITS) & GMP_NUMB_MASK;
+	  rp[0] = 0;
+	  exp--;
+	}
+      else
+	{
+	  rp[2] = manl >> (GMP_LIMB_BITS - sc);
+	  rp[1] = (manl >> GMP_NAIL_BITS - sc) & GMP_NUMB_MASK;
+	  rp[0] = (manl << GMP_NUMB_BITS - GMP_NAIL_BITS + sc) & GMP_NUMB_MASK;
+	}
+    }
+#endif
+
+#if BITS_PER_PART == 32 && LIMBS_PER_DOUBLE == 3
+#if GMP_NAIL_BITS == 0
+  if (sc != 0)
+    {
+      rp[2] = manh >> (GMP_LIMB_BITS - sc);
+      rp[1] = (manh << sc) | (manl >> (GMP_LIMB_BITS - sc));
+      rp[0] = manl << sc;
+    }
+  else
+    {
+      rp[2] = manh;
+      rp[1] = manl;
+      rp[0] = 0;
+      exp--;
+    }
+#else
+  if (sc > GMP_NAIL_BITS)
+    {
+      rp[2] = (manh >> (GMP_LIMB_BITS - sc));
+      rp[1] = ((manh << (sc - GMP_NAIL_BITS)) |
+	       (manl >> (GMP_LIMB_BITS - sc + GMP_NAIL_BITS))) & GMP_NUMB_MASK;
+      if (sc >= 2 * GMP_NAIL_BITS)
+	rp[0] = (manl << sc - 2 * GMP_NAIL_BITS) & GMP_NUMB_MASK;
+      else
+	rp[0] = manl >> (2 * GMP_NAIL_BITS - sc) & GMP_NUMB_MASK;
+    }
+  else
+    {
+      if (sc == 0)
+	{
+	  rp[2] = manh >> GMP_NAIL_BITS;
+	  rp[1] = ((manh << GMP_NUMB_BITS - GMP_NAIL_BITS) | (manl >> 2 * GMP_NAIL_BITS)) & GMP_NUMB_MASK;
+	  rp[0] = (manl << GMP_NUMB_BITS - 2 * GMP_NAIL_BITS) & GMP_NUMB_MASK;
+	  exp--;
+	}
+      else
+	{
+	  rp[2] = (manh >> (GMP_LIMB_BITS - sc));
+	  rp[1] = (manh >> (GMP_NAIL_BITS - sc)) & GMP_NUMB_MASK;
+	  rp[0] = ((manh << (GMP_NUMB_BITS - GMP_NAIL_BITS + sc))
+		   | (manl >> (GMP_LIMB_BITS - (GMP_NUMB_BITS - GMP_NAIL_BITS + sc)))) & GMP_NUMB_MASK;
+	}
+    }
+#endif
+#endif
+
+#if BITS_PER_PART == 32 && LIMBS_PER_DOUBLE > 3
+  if (sc == 0)
+    {
+      int i;
+
+      for (i = LIMBS_PER_DOUBLE - 1; i >= 0; i--)
+	{
+	  rp[i] = manh >> (BITS_PER_ULONG - GMP_NUMB_BITS);
+	  manh = ((manh << GMP_NUMB_BITS)
+		  | (manl >> (BITS_PER_ULONG - GMP_NUMB_BITS)));
+	  manl = manl << GMP_NUMB_BITS;
+	}
+      exp--;
+    }
+  else
+    {
+      int i;
+
+      rp[LIMBS_PER_DOUBLE - 1] = (manh >> (GMP_LIMB_BITS - sc));
+      manh = (manh << sc) | (manl >> (GMP_LIMB_BITS - sc));
+      manl = (manl << sc);
+      for (i = LIMBS_PER_DOUBLE - 2; i >= 0; i--)
+	{
+	  rp[i] = manh >> (BITS_PER_ULONG - GMP_NUMB_BITS);
+	  manh = ((manh << GMP_NUMB_BITS)
+		  | (manl >> (BITS_PER_ULONG - GMP_NUMB_BITS)));
+	  manl = manl << GMP_NUMB_BITS;
+	}
+  }
+#endif
+
+  return exp;
+}
diff --git a/third_party/gmp/gen-bases.c b/third_party/gmp/gen-bases.c
new file mode 100644
index 0000000..5f5e7ed
--- /dev/null
+++ b/third_party/gmp/gen-bases.c
@@ -0,0 +1,265 @@
+/* Generate mp_bases data.
+
+Copyright 1991, 1993, 1994, 1996, 2000, 2002, 2004, 2011, 2012,
+2015-2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "bootstrap.c"
+
+
+int    chars_per_limb;
+int    big_base_ctz;
+mpz_t  big_base;
+int    normalization_steps;
+mpz_t  big_base_inverted;
+mpz_t  big_base_binverted;
+
+mpz_t  t;
+
+#define POW2_P(n)  (((n) & ((n) - 1)) == 0)
+
+unsigned int
+ulog2 (unsigned int x)
+{
+  unsigned int i;
+  for (i = 0;  x != 0;  i++)
+    x >>= 1;
+  return i;
+}
+
+void
+binvert (int numb_bits)
+{
+  mpz_t bbo;
+
+  mpz_init_set (bbo, big_base);
+  big_base_ctz = mpz_make_odd (bbo);
+  mpz_invert_2exp (big_base_binverted, bbo, numb_bits);
+}
+
+void
+generate (int limb_bits, int nail_bits, int base)
+{
+  int  numb_bits = limb_bits - nail_bits;
+
+  mpz_set_ui (t, 1L);
+  mpz_mul_2exp (t, t, numb_bits);
+  mpz_set_ui (big_base, (long) base);
+  chars_per_limb = 0;
+  while (mpz_cmp (big_base, t) <= 0)
+    {
+      mpz_mul_ui (big_base, big_base, (long) base);
+      chars_per_limb++;
+    }
+
+  mpz_ui_pow_ui (big_base, (long) base, (long) chars_per_limb);
+
+  normalization_steps = limb_bits - mpz_sizeinbase (big_base, 2);
+
+  mpz_set_ui (t, 1L);
+  mpz_mul_2exp (t, t, 2*limb_bits - normalization_steps);
+  mpz_tdiv_q (big_base_inverted, t, big_base);
+  mpz_clrbit (big_base_inverted, limb_bits);
+
+  binvert (numb_bits);
+}
+
+void
+header (int limb_bits, int nail_bits)
+{
+  int  numb_bits = limb_bits - nail_bits;
+
+  generate (limb_bits, nail_bits, 10);
+
+  printf ("/* This file generated by gen-bases.c - DO NOT EDIT. */\n");
+  printf ("\n");
+  printf ("#if GMP_NUMB_BITS != %d\n", numb_bits);
+  printf ("Error, error, this data is for %d bits\n", numb_bits);
+  printf ("#endif\n");
+  printf ("\n");
+  printf ("/* mp_bases[10] data, as literal values */\n");
+  printf ("#define MP_BASES_CHARS_PER_LIMB_10      %d\n", chars_per_limb);
+  printf ("#define MP_BASES_BIG_BASE_CTZ_10        %d\n", big_base_ctz);
+  printf ("#define MP_BASES_BIG_BASE_10            CNST_LIMB(0x");
+  mpz_out_str (stdout, 16, big_base);
+  printf (")\n");
+  printf ("#define MP_BASES_BIG_BASE_INVERTED_10   CNST_LIMB(0x");
+  mpz_out_str (stdout, 16, big_base_inverted);
+  printf (")\n");
+  printf ("#define MP_BASES_BIG_BASE_BINVERTED_10  CNST_LIMB(0x");
+  mpz_out_str (stdout, 16, big_base_binverted);
+  printf (")\n");
+  printf ("#define MP_BASES_NORMALIZATION_STEPS_10 %d\n", normalization_steps);
+}
+
+
+#define EXTRA 16
+
+/* Compute log(2)/log(b) as a fixnum. */
+void
+mp_2logb (mpz_t r, int bi, int prec)
+{
+  mpz_t t, t2, two, b;
+  int i;
+
+  mpz_init (t);
+  mpz_setbit (t, prec + EXTRA);
+
+  mpz_init (t2);
+
+  mpz_init (two);
+  mpz_setbit (two, prec + EXTRA + 1);
+
+  mpz_set_ui (r, 0);
+
+  mpz_init_set_ui (b, bi);
+  mpz_mul_2exp (b, b, prec+EXTRA);
+
+  for (i = prec-1; i >= 0; i--)
+    {
+      mpz_mul_2exp (b, b, prec+EXTRA);
+      mpz_sqrt (b, b);
+
+      mpz_mul (t2, t, b);
+      mpz_tdiv_q_2exp (t2, t2, prec+EXTRA);
+
+      if (mpz_cmp (t2, two) < 0)	/* not too large? */
+	{
+	  mpz_setbit (r, i);		/* set next less significant bit */
+	  mpz_swap (t, t2);		/* new value acceptable */
+	}
+    }
+
+  mpz_clear (t);
+  mpz_clear (t2);
+  mpz_clear (two);
+  mpz_clear (b);
+}
+
+void
+table (int limb_bits, int nail_bits)
+{
+  int  numb_bits = limb_bits - nail_bits;
+  int  base;
+  mpz_t r, t, logb2, log2b;
+
+  mpz_init (r);
+  mpz_init (t);
+  mpz_init (logb2);
+  mpz_init (log2b);
+
+  printf ("/* This file generated by gen-bases.c - DO NOT EDIT. */\n");
+  printf ("\n");
+  printf ("#include \"gmp-impl.h\"\n");
+  printf ("\n");
+  printf ("#if GMP_NUMB_BITS != %d\n", numb_bits);
+  printf ("Error, error, this data is for %d bits\n", numb_bits);
+  printf ("#endif\n");
+  printf ("\n");
+  puts ("const struct bases mp_bases[257] =\n{");
+  puts ("  /*   0 */ { 0, 0, 0, 0, 0 },");
+  puts ("  /*   1 */ { 0, 0, 0, 0, 0 },");
+  for (base = 2; base <= 256; base++)
+    {
+      generate (limb_bits, nail_bits, base);
+      mp_2logb (r, base, limb_bits + 8);
+      mpz_tdiv_q_2exp (logb2, r, 8);
+      mpz_set_ui (t, 1);
+      mpz_mul_2exp (t, t, 2*limb_bits + 5);
+      mpz_sub_ui (t, t, 1);
+      mpz_add_ui (r, r, 1);
+      mpz_tdiv_q (log2b, t, r);
+
+      printf ("  /* %3u */ { ", base);
+      if (POW2_P (base))
+	{
+          mpz_set_ui (big_base, ulog2 (base) - 1);
+	  mpz_set_ui (big_base_inverted, 0);
+	}
+
+      printf ("%u,", chars_per_limb);
+      printf (" CNST_LIMB(0x");
+      mpz_out_str (stdout, 16, logb2);
+      printf ("), CNST_LIMB(0x");
+      mpz_out_str (stdout, 16, log2b);
+      printf ("), CNST_LIMB(0x");
+      mpz_out_str (stdout, 16, big_base);
+      printf ("), CNST_LIMB(0x");
+      mpz_out_str (stdout, 16, big_base_inverted);
+      printf (") },\n");
+    }
+
+  puts ("};");
+
+  mpz_clear (r);
+  mpz_clear (t);
+  mpz_clear (logb2);
+  mpz_clear (log2b);
+
+}
+
+int
+main (int argc, char **argv)
+{
+  int  limb_bits, nail_bits;
+
+  mpz_init (big_base);
+  mpz_init (big_base_inverted);
+  mpz_init (big_base_binverted);
+  mpz_init (t);
+
+  if (argc != 4)
+    {
+      fprintf (stderr, "Usage: gen-bases <header|table> <limbbits> <nailbits>\n");
+      exit (1);
+    }
+
+  limb_bits = atoi (argv[2]);
+  nail_bits = atoi (argv[3]);
+
+  if (limb_bits <= 0
+      || nail_bits < 0
+      || nail_bits >= limb_bits)
+    {
+      fprintf (stderr, "Invalid limb/nail bits: %d %d\n",
+               limb_bits, nail_bits);
+      exit (1);
+    }
+
+  if (strcmp (argv[1], "header") == 0)
+    header (limb_bits, nail_bits);
+  else if (strcmp (argv[1], "table") == 0)
+    table (limb_bits, nail_bits);
+  else
+    {
+      fprintf (stderr, "Invalid header/table choice: %s\n", argv[1]);
+      exit (1);
+    }
+
+  return 0;
+}
diff --git a/third_party/gmp/gen-fac.c b/third_party/gmp/gen-fac.c
new file mode 100644
index 0000000..93ebf7b
--- /dev/null
+++ b/third_party/gmp/gen-fac.c
@@ -0,0 +1,285 @@
+/* Generate data for combinatorics: fac_ui, bin_uiui, ...
+
+Copyright 2002, 2011-2016 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "bootstrap.c"
+
+int
+mpz_remove_twos (mpz_t x)
+{
+  mp_bitcnt_t r = mpz_scan1(x, 0);
+  mpz_tdiv_q_2exp (x, x, r);
+  return r;
+}
+
+/* returns 0 on success		*/
+int
+gen_consts (unsigned numb, unsigned limb)
+{
+  mpz_t x, mask, y, last;
+  unsigned long a, b;
+  unsigned long ofl, ofe;
+
+  printf ("/* This file is automatically generated by gen-fac.c */\n\n");
+  printf ("#if GMP_NUMB_BITS != %u\n", numb);
+  printf ("Error , error this data is for %u GMP_NUMB_BITS only\n", numb);
+  printf ("#endif\n");
+#if 0
+  printf ("#if GMP_LIMB_BITS != %u\n", limb);
+  printf ("Error , error this data is for %u GMP_LIMB_BITS only\n", limb);
+  printf ("#endif\n");
+#endif
+
+  printf
+    ("/* This table is 0!,1!,2!,3!,...,n! where n! has <= GMP_NUMB_BITS bits */\n");
+  printf
+    ("#define ONE_LIMB_FACTORIAL_TABLE CNST_LIMB(0x1),CNST_LIMB(0x1");
+  mpz_init_set_ui (x, 1);
+  mpz_init (last);
+  for (b = 2;; b++)
+    {
+      mpz_mul_ui (x, x, b);	/* so b!=a       */
+      if (mpz_sizeinbase (x, 2) > numb)
+	break;
+      printf ("),CNST_LIMB(0x");
+      mpz_out_str (stdout, 16, x);
+    }
+  printf (")\n");
+
+  printf
+    ("\n/* This table is 0!,1!,2!/2,3!/2,...,n!/2^sn where n!/2^sn is an */\n");
+  printf
+    ("/* odd integer for each n, and n!/2^sn has <= GMP_NUMB_BITS bits */\n");
+  printf
+    ("#define ONE_LIMB_ODD_FACTORIAL_TABLE CNST_LIMB(0x1),CNST_LIMB(0x1),CNST_LIMB(0x1");
+  mpz_set_ui (x, 1);
+  for (b = 3;; b++)
+    {
+      for (a = b; (a & 1) == 0; a >>= 1);
+      mpz_swap (last, x);
+      mpz_mul_ui (x, last, a);
+      if (mpz_sizeinbase (x, 2) > numb)
+	break;
+      printf ("),CNST_LIMB(0x");
+      mpz_out_str (stdout, 16, x);
+    }
+  printf (")\n");
+  printf
+    ("#define ODD_FACTORIAL_TABLE_MAX CNST_LIMB(0x");
+  mpz_out_str (stdout, 16, last);
+  printf (")\n");
+
+  ofl = b - 1;
+  printf
+    ("#define ODD_FACTORIAL_TABLE_LIMIT (%lu)\n", ofl);
+  mpz_init (mask);
+  mpz_setbit (mask, numb);
+  mpz_sub_ui (mask, mask, 1);
+  printf
+    ("\n/* Previous table, continued, values modulo 2^GMP_NUMB_BITS */\n");
+  printf
+    ("#define ONE_LIMB_ODD_FACTORIAL_EXTTABLE CNST_LIMB(0x");
+  mpz_and (x, x, mask);
+  mpz_out_str (stdout, 16, x);
+  mpz_init (y);
+  mpz_bin_uiui (y, b, b/2);
+  b++;
+  for (;; b++)
+    {
+      for (a = b; (a & 1) == 0; a >>= 1);
+      if (a == b) {
+	mpz_divexact_ui (y, y, a/2+1);
+	mpz_mul_ui (y, y, a);
+      } else
+	mpz_mul_2exp (y, y, 1);
+      if (mpz_sizeinbase (y, 2) > numb)
+	break;
+      mpz_mul_ui (x, x, a);
+      mpz_and (x, x, mask);
+      printf ("),CNST_LIMB(0x");
+      mpz_out_str (stdout, 16, x);
+    }
+  printf (")\n");
+  ofe = b - 1;
+  printf
+    ("#define ODD_FACTORIAL_EXTTABLE_LIMIT (%lu)\n", ofe);
+
+  printf
+    ("\n/* This table is 1!!,3!!,...,(2n+1)!! where (2n+1)!! has <= GMP_NUMB_BITS bits */\n");
+  printf
+    ("#define ONE_LIMB_ODD_DOUBLEFACTORIAL_TABLE CNST_LIMB(0x1");
+  mpz_set_ui (x, 1);
+  for (b = 3;; b+=2)
+    {
+      mpz_swap (last, x);
+      mpz_mul_ui (x, last, b);
+      if (mpz_sizeinbase (x, 2) > numb)
+	break;
+      printf ("),CNST_LIMB(0x");
+      mpz_out_str (stdout, 16, x);
+    }
+  printf (")\n");
+  printf
+    ("#define ODD_DOUBLEFACTORIAL_TABLE_MAX CNST_LIMB(0x");
+  mpz_out_str (stdout, 16, last);
+  printf (")\n");
+
+  printf
+    ("#define ODD_DOUBLEFACTORIAL_TABLE_LIMIT (%lu)\n", b - 2);
+
+  printf
+    ("\n/* This table x_1, x_2,... contains values s.t. x_n^n has <= GMP_NUMB_BITS bits */\n");
+  printf
+    ("#define NTH_ROOT_NUMB_MASK_TABLE (GMP_NUMB_MASK");
+  for (b = 2;b <= 8; b++)
+    {
+      mpz_root (x, mask, b);
+      printf ("),CNST_LIMB(0x");
+      mpz_out_str (stdout, 16, x);
+    }
+  printf (")\n");
+
+  mpz_add_ui (mask, mask, 1);
+  printf
+    ("\n/* This table contains inverses of odd factorials, modulo 2^GMP_NUMB_BITS */\n");
+  printf
+    ("\n/* It begins with (2!/2)^-1=1 */\n");
+  printf
+    ("#define ONE_LIMB_ODD_FACTORIAL_INVERSES_TABLE CNST_LIMB(0x1");
+  mpz_set_ui (x, 1);
+  for (b = 3;b <= ofe - 2; b++)
+    {
+      for (a = b; (a & 1) == 0; a >>= 1);
+      mpz_mul_ui (x, x, a);
+      mpz_invert (y, x, mask);
+      printf ("),CNST_LIMB(0x");
+      mpz_out_str (stdout, 16, y);
+    }
+  printf (")\n");
+
+  ofe = (ofe / 16 + 1) * 16;
+
+  printf
+    ("\n/* This table contains 2n-popc(2n) for small n */\n");
+  printf
+    ("\n/* It begins with 2-1=1 (n=1) */\n");
+  printf
+    ("#define TABLE_2N_MINUS_POPC_2N 1");
+  for (b = 4; b <= ofe; b += 2)
+    {
+      mpz_set_ui (x, b);
+      printf (",%lu",b - mpz_popcount (x));
+    }
+  printf ("\n");
+  printf
+    ("#define TABLE_LIMIT_2N_MINUS_POPC_2N %lu\n", ofe + 1);
+
+
+  ofl = (ofl + 1) / 2;
+  printf
+    ("#define ODD_CENTRAL_BINOMIAL_OFFSET (%lu)\n", ofl);
+  printf
+    ("\n/* This table contains binomial(2k,k)/2^t */\n");
+  printf
+    ("\n/* It begins with ODD_CENTRAL_BINOMIAL_TABLE_MIN */\n");
+  printf
+    ("#define ONE_LIMB_ODD_CENTRAL_BINOMIAL_TABLE ");
+  for (b = ofl;; b++)
+    {
+      mpz_bin_uiui (x, 2 * b, b);
+      mpz_remove_twos (x);
+      if (mpz_sizeinbase (x, 2) > numb)
+	break;
+      if (b != ofl)
+	printf ("),");
+      printf("CNST_LIMB(0x");
+      mpz_out_str (stdout, 16, x);
+    }
+  printf (")\n");
+
+  ofe = b - 1;
+  printf
+    ("#define ODD_CENTRAL_BINOMIAL_TABLE_LIMIT (%lu)\n", ofe);
+
+  printf
+    ("\n/* This table contains the inverses of elements in the previous table. */\n");
+  printf
+    ("#define ONE_LIMB_ODD_CENTRAL_BINOMIAL_INVERSE_TABLE CNST_LIMB(0x");
+  for (b = ofl; b <= ofe; b++)
+    {
+      mpz_bin_uiui (x, 2 * b, b);
+      mpz_remove_twos (x);
+      mpz_invert (x, x, mask);
+      mpz_out_str (stdout, 16, x);
+      if (b != ofe)
+	printf ("),CNST_LIMB(0x");
+    }
+  printf (")\n");
+
+  printf
+    ("\n/* This table contains the values t in the formula binomial(2k,k)/2^t */\n");
+  printf
+    ("#define CENTRAL_BINOMIAL_2FAC_TABLE ");
+  for (b = ofl; b <= ofe; b++)
+    {
+      mpz_bin_uiui (x, 2 * b, b);
+      printf ("%d", mpz_remove_twos (x));
+      if (b != ofe)
+	printf (",");
+    }
+  printf ("\n");
+
+  return 0;
+}
+
+int
+main (int argc, char *argv[])
+{
+  int nail_bits, limb_bits, numb_bits;
+
+  if (argc != 3)
+    {
+      fprintf (stderr, "Usage: gen-fac limbbits nailbits\n");
+      exit (1);
+    }
+  limb_bits = atoi (argv[1]);
+  nail_bits = atoi (argv[2]);
+  numb_bits = limb_bits - nail_bits;
+  if (limb_bits < 2 || nail_bits < 0 || numb_bits < 1)
+    {
+      fprintf (stderr, "Invalid limb/nail bits %d,%d\n", limb_bits,
+	       nail_bits);
+      exit (1);
+    }
+  gen_consts (numb_bits, limb_bits);
+  return 0;
+}
diff --git a/third_party/gmp/gen-fib.c b/third_party/gmp/gen-fib.c
new file mode 100644
index 0000000..647a6bb
--- /dev/null
+++ b/third_party/gmp/gen-fib.c
@@ -0,0 +1,156 @@
+/* Generate Fibonacci table data.
+
+Copyright 2001, 2002, 2004, 2012, 2014, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "bootstrap.c"
+
+mpz_t  *f;
+int    fnum, fib_limit, luc_limit;
+
+void
+generate (int numb_bits)
+{
+  mpz_t  limit, l;
+  int    falloc, i;
+
+  mpz_init2 (limit, numb_bits + 1);
+  mpz_setbit (limit, numb_bits);
+
+  /* fib(2n) > 2^n, so use 2n as a limit for the table size */
+  falloc = 2 * numb_bits;
+  f = (mpz_t*) xmalloc (falloc * sizeof (*f));
+
+  mpz_init_set_ui (f[0], 1L);  /* F[-1] */
+  mpz_init_set_ui (f[1], 0L);  /* F[0] */
+
+  mpz_init (l);
+
+  for (i = 2; ; i++)
+    {
+      assert (i < falloc);
+
+      /* F[i] = F[i-1] + F[i-2] */
+      mpz_init (f[i]);
+      mpz_add (f[i], f[i-1], f[i-2]);
+      if (mpz_cmp (f[i], limit) >= 0)
+        break;
+
+      fnum = i+1;
+      fib_limit = i-1;
+
+      /* L[i] = F[i]+2*F[i-1] */
+      mpz_add (l, f[i], f[i-1]);
+      mpz_add (l, l, f[i-1]);
+
+      if (mpz_cmp (l, limit) < 0)
+        luc_limit = i-1;
+    }
+
+  mpz_clear (limit);
+}
+
+
+void
+header (int numb_bits)
+{
+  printf ("/* This file generated by gen-fib.c - DO NOT EDIT. */\n");
+  printf ("\n");
+  printf ("#if GMP_NUMB_BITS != %d\n", numb_bits);
+  printf ("Error, error, this data is for %d bits\n", numb_bits);
+  printf ("#endif\n");
+  printf ("\n");
+  printf ("#define FIB_TABLE_LIMIT         %d\n", fib_limit);
+  printf ("#define FIB_TABLE_LUCNUM_LIMIT  %d\n", luc_limit);
+}
+
+void
+table (int numb_bits)
+{
+  int  i;
+
+  printf ("/* This file generated by gen-fib.c - DO NOT EDIT. */\n");
+  printf ("\n");
+  printf ("#include \"gmp.h\"\n");
+  printf ("#include \"gmp-impl.h\"\n");
+  printf ("\n");
+  printf ("#if GMP_NUMB_BITS != %d\n", numb_bits);
+  printf ("Error, error, this data is for %d bits\n", numb_bits);
+  printf ("#endif\n");
+  printf ("\n");
+  printf ("const mp_limb_t\n");
+  printf ("__gmp_fib_table[FIB_TABLE_LIMIT+2] = {\n");
+
+  for (i = 0; i < fnum; i++)
+    {
+      printf ("  CNST_LIMB (0x");
+      mpz_out_str (stdout, 16, f[i]);
+      printf ("),  /* %d */\n", i-1);
+    }
+  printf ("};\n");
+}
+
+int
+main (int argc, char *argv[])
+{
+  int  limb_bits, nail_bits, numb_bits;
+
+  if (argc != 4)
+    {
+      fprintf (stderr, "Usage: gen-fib <header|table> <limbbits> <nailbits>\n");
+      exit (1);
+    }
+
+  limb_bits = atoi (argv[2]);
+  nail_bits = atoi (argv[3]);
+
+  if (limb_bits <= 0
+      || nail_bits < 0
+      || nail_bits >= limb_bits)
+    {
+      fprintf (stderr, "Invalid limb/nail bits: %d %d\n",
+               limb_bits, nail_bits);
+      exit (1);
+    }
+  numb_bits = limb_bits - nail_bits;
+
+  generate (numb_bits);
+
+  if (strcmp (argv[1], "header") == 0)
+    header (numb_bits);
+  else if (strcmp (argv[1], "table") == 0)
+    table (numb_bits);
+  else
+    {
+      fprintf (stderr, "Invalid header/table choice: %s\n", argv[1]);
+      exit (1);
+    }
+
+  return 0;
+}
diff --git a/third_party/gmp/gen-jacobitab.c b/third_party/gmp/gen-jacobitab.c
new file mode 100644
index 0000000..537994b
--- /dev/null
+++ b/third_party/gmp/gen-jacobitab.c
@@ -0,0 +1,128 @@
+/* gen-jacobi.c
+
+   Contributed to the GNU project by Niels Möller.
+
+Copyright 2010 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+/* Generate the lookup table needed for fast left-to-right computation
+   of the Jacobi symbol. */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static const struct
+{
+  unsigned char a;
+  unsigned char b;
+} decode_table[13] = {
+  /*  0 */ { 0, 1 },
+  /*  1 */ { 0, 3 },
+  /*  2 */ { 1, 1 },
+  /*  3 */ { 1, 3 },
+  /*  4 */ { 2, 1 },
+  /*  5 */ { 2, 3 },
+  /*  6 */ { 3, 1 },
+  /*  7 */ { 3, 3 }, /* d = 1 */
+  /*  8 */ { 1, 0 },
+  /*  9 */ { 1, 2 },
+  /* 10 */ { 3, 0 },
+  /* 11 */ { 3, 2 },
+  /* 12 */ { 3, 3 }, /* d = 0 */
+
+};
+#define JACOBI_A(bits) (decode_table[(bits)>>1].a)
+#define JACOBI_B(bits) (decode_table[(bits)>>1].b)
+
+#define JACOBI_E(bits) ((bits) & 1)
+#define JACOBI_D(bits) (((bits)>>1) == 7) /* Gives 0 for don't care states. */
+
+static unsigned
+encode (unsigned a, unsigned b, unsigned d)
+{
+  unsigned i;
+
+  assert (d < 2);
+  assert (a < 4);
+  assert (b < 4);
+  assert ( (a | b ) & 1);
+
+  if (a == 3 && b == 3)
+    return d ? 7 : 12;
+
+  for (i = 0; i < 12; i++)
+    if (decode_table[i].a == a
+	&& decode_table[i].b == b)
+      return i;
+
+  abort ();
+}
+
+int
+main (int argc, char **argv)
+{
+  unsigned bits;
+
+  for (bits = 0; bits < 208; bits++)
+    {
+      unsigned e, a, b, d_old, d, q;
+
+      if (bits && !(bits & 0xf))
+	printf("\n");
+
+      q = bits & 3;
+      d = (bits >> 2) & 1;
+
+      e = JACOBI_E (bits >> 3);
+      a = JACOBI_A (bits >> 3);
+      b = JACOBI_B (bits >> 3);
+      d_old = JACOBI_D (bits >> 3);
+
+      if (d != d_old && a == 3 && b == 3)
+	e ^= 1;
+
+      if (d == 1)
+	{
+	  if (b == 2)
+	    e ^= (q & (a >> 1)) ^ (q >> 1);
+	  a = (a - q * b) & 3;
+	}
+      else
+	{
+	  if (a == 2)
+	    e ^= (q & (b >> 1)) ^ (q >> 1);
+	  b = (b - q * a) & 3;
+	}
+
+      printf("%2d,", (encode (a, b, d) << 1) | e);
+    }
+  printf("\n");
+
+  return 0;
+}
diff --git a/third_party/gmp/gen-psqr.c b/third_party/gmp/gen-psqr.c
new file mode 100644
index 0000000..a5054c6
--- /dev/null
+++ b/third_party/gmp/gen-psqr.c
@@ -0,0 +1,585 @@
+/* Generate perfect square testing data.
+
+Copyright 2002-2004, 2012, 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "bootstrap.c"
+
+
+/* The aim of this program is to choose either mpn_mod_34lsub1 or mpn_mod_1
+   (plus a PERFSQR_PP modulus), and generate tables indicating quadratic
+   residues and non-residues modulo small factors of that modulus.
+
+   For the usual 32 or 64 bit cases mpn_mod_34lsub1 gets used.  That
+   function exists specifically because 2^24-1 and 2^48-1 have nice sets of
+   prime factors.  For other limb sizes it's considered, but if it doesn't
+   have good factors then mpn_mod_1 will be used instead.
+
+   When mpn_mod_1 is used, the modulus PERFSQR_PP is created from a
+   selection of small primes, chosen to fill PERFSQR_MOD_BITS of a limb,
+   with that bit count chosen so (2*GMP_LIMB_BITS)*2^PERFSQR_MOD_BITS <=
+   GMP_LIMB_MAX, allowing PERFSQR_MOD_IDX in mpn/generic/perfsqr.c to do its
+   calculation within a single limb.
+
+   In either case primes can be combined to make divisors.  The table data
+   then effectively indicates remainders which are quadratic residues mod
+   all the primes.  This sort of combining reduces the number of steps
+   needed after mpn_mod_34lsub1 or mpn_mod_1, saving code size and time.
+   Nothing is gained or lost in terms of detections, the same total fraction
+   of non-residues will be identified.
+
+   Nothing particularly sophisticated is attempted for combining factors to
+   make divisors.  This is probably a kind of knapsack problem so it'd be
+   too hard to attempt anything completely general.  For the usual 32 and 64
+   bit limbs we get a good enough result just pairing the biggest and
+   smallest which fit together, repeatedly.
+
+   Another aim is to get powerful combinations, ie. divisors which identify
+   biggest fraction of non-residues, and have those run first.  Again for
+   the usual 32 and 64 bits it seems good enough just to pair for big
+   divisors then sort according to the resulting fraction of non-residues
+   identified.
+
+   Also in this program, a table sq_res_0x100 of residues modulo 256 is
+   generated.  This simply fills bits into limbs of the appropriate
+   build-time GMP_LIMB_BITS each.
+
+*/
+
+
+/* Normally we aren't using const in gen*.c programs, so as not to have to
+   bother figuring out if it works, but using it with f_cmp_divisor and
+   f_cmp_fraction avoids warnings from the qsort calls. */
+
+/* Same tests as gmp.h. */
+#if  defined (__STDC__)                                 \
+  || defined (__cplusplus)                              \
+  || defined (_AIX)                                     \
+  || defined (__DECC)                                   \
+  || (defined (__mips) && defined (_SYSTYPE_SVR4))      \
+  || defined (_MSC_VER)                                 \
+  || defined (_WIN32)
+#define HAVE_CONST        1
+#endif
+
+#if ! HAVE_CONST
+#define const
+#endif
+
+
+mpz_t  *sq_res_0x100;          /* table of limbs */
+int    nsq_res_0x100;          /* elements in sq_res_0x100 array */
+int    sq_res_0x100_num;       /* squares in sq_res_0x100 */
+double sq_res_0x100_fraction;  /* sq_res_0x100_num / 256 */
+
+int     mod34_bits;        /* 3*GMP_NUMB_BITS/4 */
+int     mod_bits;          /* bits from PERFSQR_MOD_34 or MOD_PP */
+int     max_divisor;       /* all divisors <= max_divisor */
+int     max_divisor_bits;  /* ceil(log2(max_divisor)) */
+double  total_fraction;    /* of squares */
+mpz_t   pp;                /* product of primes, or 0 if mod_34lsub1 used */
+mpz_t   pp_norm;           /* pp shifted so NUMB high bit set */
+mpz_t   pp_inverted;       /* invert_limb style inverse */
+mpz_t   mod_mask;          /* 2^mod_bits-1 */
+char    mod34_excuse[128]; /* why mod_34lsub1 not used (if it's not) */
+
+/* raw list of divisors of 2^mod34_bits-1 or pp, just to show in a comment */
+struct rawfactor_t {
+  int     divisor;
+  int     multiplicity;
+};
+struct rawfactor_t  *rawfactor;
+int                 nrawfactor;
+
+/* factors of 2^mod34_bits-1 or pp and associated data, after combining etc */
+struct factor_t {
+  int     divisor;
+  mpz_t   inverse;   /* 1/divisor mod 2^mod_bits */
+  mpz_t   mask;      /* indicating squares mod divisor */
+  double  fraction;  /* squares/total */
+};
+struct factor_t  *factor;
+int              nfactor;       /* entries in use in factor array */
+int              factor_alloc;  /* entries allocated to factor array */
+
+
+int
+f_cmp_divisor (const void *parg, const void *qarg)
+{
+  const struct factor_t *p, *q;
+  p = (const struct factor_t *) parg;
+  q = (const struct factor_t *) qarg;
+  if (p->divisor > q->divisor)
+    return 1;
+  else if (p->divisor < q->divisor)
+    return -1;
+  else
+    return 0;
+}
+
+int
+f_cmp_fraction (const void *parg, const void *qarg)
+{
+  const struct factor_t *p, *q;
+  p = (const struct factor_t *) parg;
+  q = (const struct factor_t *) qarg;
+  if (p->fraction > q->fraction)
+    return 1;
+  else if (p->fraction < q->fraction)
+    return -1;
+  else
+    return 0;
+}
+
+/* Remove array[idx] by copying the remainder down, and adjust narray
+   accordingly.  */
+#define COLLAPSE_ELEMENT(array, idx, narray)                    \
+  do {                                                          \
+    memmove (&(array)[idx],					\
+	     &(array)[idx+1],					\
+	     ((narray)-((idx)+1)) * sizeof (array[0]));		\
+    (narray)--;                                                 \
+  } while (0)
+
+
+/* return n*2^p mod m */
+int
+mul_2exp_mod (int n, int p, int m)
+{
+  while (--p >= 0)
+    n = (2 * n) % m;
+  return n;
+}
+
+/* return -n mod m */
+int
+neg_mod (int n, int m)
+{
+  assert (n >= 0 && n < m);
+  return (n == 0 ? 0 : m-n);
+}
+
+/* Set "mask" to a value such that "mask & (1<<idx)" is non-zero if
+   "-(idx<<mod_bits)" can be a square modulo m.  */
+void
+square_mask (mpz_t mask, int m)
+{
+  int    p, i, r, idx;
+
+  p = mul_2exp_mod (1, mod_bits, m);
+  p = neg_mod (p, m);
+
+  mpz_set_ui (mask, 0L);
+  for (i = 0; i < m; i++)
+    {
+      r = (i * i) % m;
+      idx = (r * p) % m;
+      mpz_setbit (mask, (unsigned long) idx);
+    }
+}
+
+void
+generate_sq_res_0x100 (int limb_bits)
+{
+  int  i, res;
+
+  nsq_res_0x100 = (0x100 + limb_bits - 1) / limb_bits;
+  sq_res_0x100 = (mpz_t *) xmalloc (nsq_res_0x100 * sizeof (*sq_res_0x100));
+
+  for (i = 0; i < nsq_res_0x100; i++)
+    mpz_init_set_ui (sq_res_0x100[i], 0L);
+
+  for (i = 0; i < 0x100; i++)
+    {
+      res = (i * i) % 0x100;
+      mpz_setbit (sq_res_0x100[res / limb_bits],
+                  (unsigned long) (res % limb_bits));
+    }
+
+  sq_res_0x100_num = 0;
+  for (i = 0; i < nsq_res_0x100; i++)
+    sq_res_0x100_num += mpz_popcount (sq_res_0x100[i]);
+  sq_res_0x100_fraction = (double) sq_res_0x100_num / 256.0;
+}
+
+void
+generate_mod (int limb_bits, int nail_bits)
+{
+  int    numb_bits = limb_bits - nail_bits;
+  int    i, divisor;
+
+  mpz_init_set_ui (pp, 0L);
+  mpz_init_set_ui (pp_norm, 0L);
+  mpz_init_set_ui (pp_inverted, 0L);
+
+  /* no more than limb_bits many factors in a one limb modulus (and of
+     course in reality nothing like that many) */
+  factor_alloc = limb_bits;
+  factor = (struct factor_t *) xmalloc (factor_alloc * sizeof (*factor));
+  rawfactor = (struct rawfactor_t *) xmalloc (factor_alloc * sizeof (*rawfactor));
+
+  if (numb_bits % 4 != 0)
+    {
+      strcpy (mod34_excuse, "GMP_NUMB_BITS % 4 != 0");
+      goto use_pp;
+    }
+
+  max_divisor = 2*limb_bits;
+  max_divisor_bits = log2_ceil (max_divisor);
+
+  if (numb_bits / 4 < max_divisor_bits)
+    {
+      /* Wind back to one limb worth of max_divisor, if that will let us use
+         mpn_mod_34lsub1.  */
+      max_divisor = limb_bits;
+      max_divisor_bits = log2_ceil (max_divisor);
+
+      if (numb_bits / 4 < max_divisor_bits)
+        {
+          strcpy (mod34_excuse, "GMP_NUMB_BITS / 4 too small");
+          goto use_pp;
+        }
+    }
+
+  {
+    /* Can use mpn_mod_34lsub1, find small factors of 2^mod34_bits-1. */
+    mpz_t  m, q, r;
+    int    multiplicity;
+
+    mod34_bits = (numb_bits / 4) * 3;
+
+    /* mpn_mod_34lsub1 returns a full limb value, PERFSQR_MOD_34 folds it at
+       the mod34_bits mark, adding the two halves for a remainder of at most
+       mod34_bits+1 many bits */
+    mod_bits = mod34_bits + 1;
+
+    mpz_init_set_ui (m, 1L);
+    mpz_mul_2exp (m, m, mod34_bits);
+    mpz_sub_ui (m, m, 1L);
+
+    mpz_init (q);
+    mpz_init (r);
+
+    for (i = 3; i <= max_divisor; i+=2)
+      {
+        if (! isprime (i))
+          continue;
+
+        mpz_tdiv_qr_ui (q, r, m, (unsigned long) i);
+        if (mpz_sgn (r) != 0)
+          continue;
+
+        /* if a repeated prime is found it's used as an i^n in one factor */
+        divisor = 1;
+        multiplicity = 0;
+        do
+          {
+            if (divisor > max_divisor / i)
+              break;
+            multiplicity++;
+            mpz_set (m, q);
+            mpz_tdiv_qr_ui (q, r, m, (unsigned long) i);
+          }
+        while (mpz_sgn (r) == 0);
+
+        assert (nrawfactor < factor_alloc);
+        rawfactor[nrawfactor].divisor = i;
+        rawfactor[nrawfactor].multiplicity = multiplicity;
+        nrawfactor++;
+      }
+
+    mpz_clear (m);
+    mpz_clear (q);
+    mpz_clear (r);
+  }
+
+  if (nrawfactor <= 2)
+    {
+      mpz_t  new_pp;
+
+      sprintf (mod34_excuse, "only %d small factor%s",
+               nrawfactor, nrawfactor == 1 ? "" : "s");
+
+    use_pp:
+      /* reset to two limbs of max_divisor, in case the mpn_mod_34lsub1 code
+         tried with just one */
+      max_divisor = 2*limb_bits;
+      max_divisor_bits = log2_ceil (max_divisor);
+
+      mpz_init (new_pp);
+      nrawfactor = 0;
+      mod_bits = MIN (numb_bits, limb_bits - max_divisor_bits);
+
+      /* one copy of each small prime */
+      mpz_set_ui (pp, 1L);
+      for (i = 3; i <= max_divisor; i+=2)
+        {
+          if (! isprime (i))
+            continue;
+
+          mpz_mul_ui (new_pp, pp, (unsigned long) i);
+          if (mpz_sizeinbase (new_pp, 2) > mod_bits)
+            break;
+          mpz_set (pp, new_pp);
+
+          assert (nrawfactor < factor_alloc);
+          rawfactor[nrawfactor].divisor = i;
+          rawfactor[nrawfactor].multiplicity = 1;
+          nrawfactor++;
+        }
+
+      /* Plus an extra copy of one or more of the primes selected, if that
+         still fits in max_divisor and the total in mod_bits.  Usually only
+         3 or 5 will be candidates */
+      for (i = nrawfactor-1; i >= 0; i--)
+        {
+          if (rawfactor[i].divisor > max_divisor / rawfactor[i].divisor)
+            continue;
+          mpz_mul_ui (new_pp, pp, (unsigned long) rawfactor[i].divisor);
+          if (mpz_sizeinbase (new_pp, 2) > mod_bits)
+            continue;
+          mpz_set (pp, new_pp);
+
+          rawfactor[i].multiplicity++;
+        }
+
+      mod_bits = mpz_sizeinbase (pp, 2);
+
+      mpz_set (pp_norm, pp);
+      while (mpz_sizeinbase (pp_norm, 2) < numb_bits)
+        mpz_add (pp_norm, pp_norm, pp_norm);
+
+      mpz_preinv_invert (pp_inverted, pp_norm, numb_bits);
+
+      mpz_clear (new_pp);
+    }
+
+  /* start the factor array */
+  for (i = 0; i < nrawfactor; i++)
+    {
+      int  j;
+      assert (nfactor < factor_alloc);
+      factor[nfactor].divisor = 1;
+      for (j = 0; j < rawfactor[i].multiplicity; j++)
+        factor[nfactor].divisor *= rawfactor[i].divisor;
+      nfactor++;
+    }
+
+ combine:
+  /* Combine entries in the factor array.  Combine the smallest entry with
+     the biggest one that will fit with it (ie. under max_divisor), then
+     repeat that with the new smallest entry. */
+  qsort (factor, nfactor, sizeof (factor[0]), f_cmp_divisor);
+  for (i = nfactor-1; i >= 1; i--)
+    {
+      if (factor[i].divisor <= max_divisor / factor[0].divisor)
+        {
+          factor[0].divisor *= factor[i].divisor;
+          COLLAPSE_ELEMENT (factor, i, nfactor);
+          goto combine;
+        }
+    }
+
+  total_fraction = 1.0;
+  for (i = 0; i < nfactor; i++)
+    {
+      mpz_init (factor[i].inverse);
+      mpz_invert_ui_2exp (factor[i].inverse,
+                          (unsigned long) factor[i].divisor,
+                          (unsigned long) mod_bits);
+
+      mpz_init (factor[i].mask);
+      square_mask (factor[i].mask, factor[i].divisor);
+
+      /* fraction of possible squares */
+      factor[i].fraction = (double) mpz_popcount (factor[i].mask)
+        / factor[i].divisor;
+
+      /* total fraction of possible squares */
+      total_fraction *= factor[i].fraction;
+    }
+
+  /* best tests first (ie. smallest fraction) */
+  qsort (factor, nfactor, sizeof (factor[0]), f_cmp_fraction);
+}
+
+void
+print (int limb_bits, int nail_bits)
+{
+  int    i;
+  mpz_t  mhi, mlo;
+
+  printf ("/* This file generated by gen-psqr.c - DO NOT EDIT. */\n");
+  printf ("\n");
+
+  printf ("#if GMP_LIMB_BITS != %d || GMP_NAIL_BITS != %d\n",
+          limb_bits, nail_bits);
+  printf ("Error, error, this data is for %d bit limb and %d bit nail\n",
+          limb_bits, nail_bits);
+  printf ("#endif\n");
+  printf ("\n");
+
+  printf ("/* Non-zero bit indicates a quadratic residue mod 0x100.\n");
+  printf ("   This test identifies %.2f%% as non-squares (%d/256). */\n",
+          (1.0 - sq_res_0x100_fraction) * 100.0,
+          0x100 - sq_res_0x100_num);
+  printf ("static const mp_limb_t\n");
+  printf ("sq_res_0x100[%d] = {\n", nsq_res_0x100);
+  for (i = 0; i < nsq_res_0x100; i++)
+    {
+      printf ("  CNST_LIMB(0x");
+      mpz_out_str (stdout, 16, sq_res_0x100[i]);
+      printf ("),\n");
+    }
+  printf ("};\n");
+  printf ("\n");
+
+  if (mpz_sgn (pp) != 0)
+    {
+      printf ("/* mpn_mod_34lsub1 not used due to %s */\n", mod34_excuse);
+      printf ("/* PERFSQR_PP = ");
+    }
+  else
+    printf ("/* 2^%d-1 = ", mod34_bits);
+  for (i = 0; i < nrawfactor; i++)
+    {
+      if (i != 0)
+        printf (" * ");
+      printf ("%d", rawfactor[i].divisor);
+      if (rawfactor[i].multiplicity != 1)
+        printf ("^%d", rawfactor[i].multiplicity);
+    }
+  printf (" %s*/\n", mpz_sgn (pp) == 0 ? "... " : "");
+
+  printf ("#define PERFSQR_MOD_BITS  %d\n", mod_bits);
+  if (mpz_sgn (pp) != 0)
+    {
+      printf ("#define PERFSQR_PP            CNST_LIMB(0x");
+      mpz_out_str (stdout, 16, pp);
+      printf (")\n");
+      printf ("#define PERFSQR_PP_NORM       CNST_LIMB(0x");
+      mpz_out_str (stdout, 16, pp_norm);
+      printf (")\n");
+      printf ("#define PERFSQR_PP_INVERTED   CNST_LIMB(0x");
+      mpz_out_str (stdout, 16, pp_inverted);
+      printf (")\n");
+    }
+  printf ("\n");
+
+  mpz_init (mhi);
+  mpz_init (mlo);
+
+  printf ("/* This test identifies %.2f%% as non-squares. */\n",
+          (1.0 - total_fraction) * 100.0);
+  printf ("#define PERFSQR_MOD_TEST(up, usize) \\\n");
+  printf ("  do {                              \\\n");
+  printf ("    mp_limb_t  r;                   \\\n");
+  if (mpz_sgn (pp) != 0)
+    printf ("    PERFSQR_MOD_PP (r, up, usize);  \\\n");
+  else
+    printf ("    PERFSQR_MOD_34 (r, up, usize);  \\\n");
+
+  for (i = 0; i < nfactor; i++)
+    {
+      printf ("                                    \\\n");
+      printf ("    /* %5.2f%% */                    \\\n",
+              (1.0 - factor[i].fraction) * 100.0);
+
+      printf ("    PERFSQR_MOD_%d (r, CNST_LIMB(%2d), CNST_LIMB(0x",
+              factor[i].divisor <= limb_bits ? 1 : 2,
+              factor[i].divisor);
+      mpz_out_str (stdout, 16, factor[i].inverse);
+      printf ("), \\\n");
+      printf ("                   CNST_LIMB(0x");
+
+      if ( factor[i].divisor <= limb_bits)
+        {
+          mpz_out_str (stdout, 16, factor[i].mask);
+        }
+      else
+        {
+          mpz_tdiv_r_2exp (mlo, factor[i].mask, (unsigned long) limb_bits);
+          mpz_tdiv_q_2exp (mhi, factor[i].mask, (unsigned long) limb_bits);
+          mpz_out_str (stdout, 16, mhi);
+          printf ("), CNST_LIMB(0x");
+          mpz_out_str (stdout, 16, mlo);
+        }
+      printf (")); \\\n");
+    }
+
+  printf ("  } while (0)\n");
+  printf ("\n");
+
+  printf ("/* Grand total sq_res_0x100 and PERFSQR_MOD_TEST, %.2f%% non-squares. */\n",
+          (1.0 - (total_fraction * 44.0/256.0)) * 100.0);
+  printf ("\n");
+
+  printf ("/* helper for tests/mpz/t-perfsqr.c */\n");
+  printf ("#define PERFSQR_DIVISORS  { 256,");
+  for (i = 0; i < nfactor; i++)
+      printf (" %d,", factor[i].divisor);
+  printf (" }\n");
+
+
+  mpz_clear (mhi);
+  mpz_clear (mlo);
+}
+
+int
+main (int argc, char *argv[])
+{
+  int  limb_bits, nail_bits;
+
+  if (argc != 3)
+    {
+      fprintf (stderr, "Usage: gen-psqr <limbbits> <nailbits>\n");
+      exit (1);
+    }
+
+  limb_bits = atoi (argv[1]);
+  nail_bits = atoi (argv[2]);
+
+  if (limb_bits <= 0
+      || nail_bits < 0
+      || nail_bits >= limb_bits)
+    {
+      fprintf (stderr, "Invalid limb/nail bits: %d %d\n",
+               limb_bits, nail_bits);
+      exit (1);
+    }
+
+  generate_sq_res_0x100 (limb_bits);
+  generate_mod (limb_bits, nail_bits);
+
+  print (limb_bits, nail_bits);
+
+  return 0;
+}
diff --git a/third_party/gmp/gen-trialdivtab.c b/third_party/gmp/gen-trialdivtab.c
new file mode 100644
index 0000000..218c322
--- /dev/null
+++ b/third_party/gmp/gen-trialdivtab.c
@@ -0,0 +1,301 @@
+/* gen-trialdivtab.c
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+Copyright 2009, 2012, 2013, 2016, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+/*
+  Generate tables for fast, division-free trial division for GMP.
+
+  There is one main table, ptab.  It contains primes, multiplied together, and
+  several types of pre-computed inverses.  It refers to tables of the type
+  dtab, via the last two indices.  That table contains the individual primes in
+  the range, except that the primes are not actually included in the table (see
+  the P macro; it sneakingly excludes the primes themselves).  Instead, the
+  dtab tables contains tuples for each prime (modular-inverse, limit) used for
+  divisibility checks.
+
+  This interface is not intended for division of very many primes, since then
+  other algorithms apply.
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "bootstrap.c"
+
+int sumspills (mpz_t, mpz_t *, int);
+void mpn_mod_1s_4p_cps (mpz_t [7], mpz_t);
+
+int limb_bits;
+
+mpz_t B;
+
+int
+main (int argc, char *argv[])
+{
+  int t, p;
+  mpz_t ppp, acc, inv, gmp_numb_max, tmp, Bhalf;
+  mpz_t pre[7];
+  int i;
+  int start_p, end_p, interval_start, interval_end, omitted_p;
+  const char *endtok;
+  int stop;
+  int np, start_idx;
+
+  if (argc < 2)
+    {
+      fprintf (stderr, "usage: %s bits endprime\n", argv[0]);
+      exit (1);
+    }
+
+  limb_bits = atoi (argv[1]);
+
+  end_p = 1290;			/* default end prime */
+  if (argc == 3)
+    end_p = atoi (argv[2]);
+
+  printf ("#if GMP_LIMB_BITS != %d\n", limb_bits);
+  printf ("#error This table is for GMP_LIMB_BITS = %d\n", limb_bits);
+  printf ("#endif\n\n");
+
+  printf ("#if GMP_NAIL_BITS != 0\n");
+  printf ("#error This table does not support nails\n");
+  printf ("#endif\n\n");
+
+  for (i = 0; i < 7; i++)
+    mpz_init (pre[i]);
+
+  mpz_init (B);
+  mpz_setbit (B, limb_bits);
+  mpz_init_set (gmp_numb_max, B);
+  mpz_sub_ui (gmp_numb_max, gmp_numb_max, 1);
+
+  mpz_init (tmp);
+  mpz_init (inv);
+
+  mpz_init (Bhalf);
+  mpz_setbit (Bhalf, limb_bits - 1);
+
+  start_p = 3;
+
+  mpz_init_set_ui (ppp, 1);
+  mpz_init (acc);
+  interval_start = start_p;
+  omitted_p = 3;
+  interval_end = 0;
+
+/*  printf ("static struct gmp_primes_dtab gmp_primes_dtab[] = {\n"); */
+
+  printf ("#ifdef WANT_dtab\n");
+
+  for (t = start_p; t <= end_p; t += 2)
+    {
+      if (! isprime (t))
+	continue;
+
+      mpz_mul_ui (acc, ppp, t);
+      stop = mpz_cmp (acc, Bhalf) >= 0;
+      if (!stop)
+	{
+	  mpn_mod_1s_4p_cps (pre, acc);
+	  stop = sumspills (acc, pre + 2, 5);
+	}
+
+      if (stop)
+	{
+	  for (p = interval_start; p <= interval_end; p += 2)
+	    {
+	      if (! isprime (p))
+		continue;
+
+	      printf ("  P(%d,", (int) p);
+	      mpz_invert_ui_2exp (inv, p, limb_bits);
+	      printf ("CNST_LIMB(0x");  mpz_out_str (stdout, 16, inv);  printf ("),");
+
+	      mpz_tdiv_q_ui (tmp, gmp_numb_max, p);
+	      printf ("CNST_LIMB(0x");  mpz_out_str (stdout, 16, tmp);
+	      printf (")),\n");
+	    }
+	  mpz_set_ui (ppp, t);
+	  interval_start = t;
+	  omitted_p = t;
+	}
+      else
+	{
+	  mpz_set (ppp, acc);
+	}
+      interval_end = t;
+    }
+  printf ("#define SMALLEST_OMITTED_PRIME %d\n", (int) omitted_p);
+  printf ("#endif\n");
+
+  printf ("#ifdef WANT_ptab\n");
+
+/*  printf ("static struct gmp_primes_ptab gmp_primes_ptab[] = {\n"); */
+
+  endtok = "";
+
+  mpz_set_ui (ppp, 1);
+  interval_start = start_p;
+  interval_end = 0;
+  np = 0;
+  start_idx = 0;
+  for (t = start_p; t <= end_p; t += 2)
+    {
+      if (! isprime (t))
+	continue;
+
+      mpz_mul_ui (acc, ppp, t);
+
+      stop = mpz_cmp (acc, Bhalf) >= 0;
+      if (!stop)
+	{
+	  mpn_mod_1s_4p_cps (pre, acc);
+	  stop = sumspills (acc, pre + 2, 5);
+	}
+
+      if (stop)
+	{
+	  mpn_mod_1s_4p_cps (pre, ppp);
+	  printf ("%s", endtok);
+	  printf ("  {CNST_LIMB(0x");  mpz_out_str (stdout, 16, ppp);
+	  printf ("),{CNST_LIMB(0x");  mpz_out_str (stdout, 16, pre[0]);
+	  printf ("),%d", (int) PTR(pre[1])[0]);
+	  for (i = 0; i < 5; i++)
+	    {
+	      printf (",");
+	      printf ("CNST_LIMB(0x");  mpz_out_str (stdout, 16, pre[2 + i]);
+	      printf (")");
+	    }
+	  printf ("},");
+	  printf ("%d,", start_idx);
+	  printf ("%d}", np - start_idx);
+
+	  endtok = ",\n";
+	  mpz_set_ui (ppp, t);
+	  interval_start = t;
+	  start_idx = np;
+	}
+      else
+	{
+	  mpz_set (ppp, acc);
+	}
+      interval_end = t;
+      np++;
+    }
+
+  printf ("\n");
+  printf ("#endif\n");
+
+  return 0;
+}
+
+unsigned long
+mpz_log2 (mpz_t x)
+{
+  return mpz_sgn (x) ? mpz_sizeinbase (x, 2) : 0;
+}
+
+void
+mpn_mod_1s_4p_cps (mpz_t cps[7], mpz_t bparm)
+{
+  mpz_t b, bi;
+  mpz_t B1modb, B2modb, B3modb, B4modb, B5modb;
+  mpz_t t;
+  int cnt;
+
+  mpz_init_set (b, bparm);
+
+  cnt = limb_bits - mpz_log2 (b);
+
+  mpz_init (bi);
+  mpz_init (t);
+  mpz_init (B1modb);
+  mpz_init (B2modb);
+  mpz_init (B3modb);
+  mpz_init (B4modb);
+  mpz_init (B5modb);
+
+  mpz_set_ui (t, 1);
+  mpz_mul_2exp (t, t, limb_bits - cnt);
+  mpz_sub (t, t, b);
+  mpz_mul_2exp (t, t, limb_bits);
+  mpz_tdiv_q (bi, t, b);		/* bi = B^2/b, except msb */
+
+  mpz_set_ui (t, 1);
+  mpz_mul_2exp (t, t, limb_bits);	/* t = B */
+  mpz_tdiv_r (B1modb, t, b);
+
+  mpz_mul_2exp (t, B1modb, limb_bits);
+  mpz_tdiv_r (B2modb, t, b);
+
+  mpz_mul_2exp (t, B2modb, limb_bits);
+  mpz_tdiv_r (B3modb, t, b);
+
+  mpz_mul_2exp (t, B3modb, limb_bits);
+  mpz_tdiv_r (B4modb, t, b);
+
+  mpz_mul_2exp (t, B4modb, limb_bits);
+  mpz_tdiv_r (B5modb, t, b);
+
+  mpz_set (cps[0], bi);
+  mpz_set_ui (cps[1], cnt);
+  mpz_tdiv_q_2exp (cps[2], B1modb, 0);
+  mpz_tdiv_q_2exp (cps[3], B2modb, 0);
+  mpz_tdiv_q_2exp (cps[4], B3modb, 0);
+  mpz_tdiv_q_2exp (cps[5], B4modb, 0);
+  mpz_tdiv_q_2exp (cps[6], B5modb, 0);
+
+  mpz_clear (b);
+  mpz_clear (bi);
+  mpz_clear (t);
+  mpz_clear (B1modb);
+  mpz_clear (B2modb);
+  mpz_clear (B3modb);
+  mpz_clear (B4modb);
+  mpz_clear (B5modb);
+}
+
+int
+sumspills (mpz_t ppp, mpz_t *a, int n)
+{
+  mpz_t s;
+  int i, ret;
+
+  mpz_init_set (s, a[0]);
+
+  for (i = 1; i < n; i++)
+    {
+      mpz_add (s, s, a[i]);
+    }
+  ret = mpz_cmp (s, B) >= 0;
+  mpz_clear (s);
+
+  return ret;
+}
diff --git a/third_party/gmp/gmp-h.in b/third_party/gmp/gmp-h.in
new file mode 100644
index 0000000..d8ce7fd
--- /dev/null
+++ b/third_party/gmp/gmp-h.in
@@ -0,0 +1,2336 @@
+/* Definitions for GNU multiple precision functions.   -*- mode: c -*-
+
+Copyright 1991, 1993-1997, 1999-2016, 2020 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#ifndef __GMP_H__
+
+#if defined (__cplusplus)
+#include <iosfwd>   /* for std::istream, std::ostream, std::string */
+#include <cstdio>
+#endif
+
+
+/* Instantiated by configure. */
+#if ! defined (__GMP_WITHIN_CONFIGURE)
+#define __GMP_HAVE_HOST_CPU_FAMILY_power   @HAVE_HOST_CPU_FAMILY_power@
+#define __GMP_HAVE_HOST_CPU_FAMILY_powerpc @HAVE_HOST_CPU_FAMILY_powerpc@
+#define GMP_LIMB_BITS                      @GMP_LIMB_BITS@
+#define GMP_NAIL_BITS                      @GMP_NAIL_BITS@
+#endif
+#define GMP_NUMB_BITS     (GMP_LIMB_BITS - GMP_NAIL_BITS)
+#define GMP_NUMB_MASK     ((~ __GMP_CAST (mp_limb_t, 0)) >> GMP_NAIL_BITS)
+#define GMP_NUMB_MAX      GMP_NUMB_MASK
+#define GMP_NAIL_MASK     (~ GMP_NUMB_MASK)
+
+
+#ifndef __GNU_MP__
+#define __GNU_MP__ 6
+
+#include <stddef.h>    /* for size_t */
+#include <limits.h>
+
+/* Instantiated by configure. */
+#if ! defined (__GMP_WITHIN_CONFIGURE)
+@DEFN_LONG_LONG_LIMB@
+#define __GMP_LIBGMP_DLL  @LIBGMP_DLL@
+#endif
+
+
+/* __GMP_DECLSPEC supports Windows DLL versions of libgmp, and is empty in
+   all other circumstances.
+
+   When compiling objects for libgmp, __GMP_DECLSPEC is an export directive,
+   or when compiling for an application it's an import directive.  The two
+   cases are differentiated by __GMP_WITHIN_GMP defined by the GMP Makefiles
+   (and not defined from an application).
+
+   __GMP_DECLSPEC_XX is similarly used for libgmpxx.  __GMP_WITHIN_GMPXX
+   indicates when building libgmpxx, and in that case libgmpxx functions are
+   exports, but libgmp functions which might get called are imports.
+
+   Libtool DLL_EXPORT define is not used.
+
+   There's no attempt to support GMP built both static and DLL.  Doing so
+   would mean applications would have to tell us which of the two is going
+   to be used when linking, and that seems very tedious and error prone if
+   using GMP by hand, and equally tedious from a package since autoconf and
+   automake don't give much help.
+
+   __GMP_DECLSPEC is required on all documented global functions and
+   variables, the various internals in gmp-impl.h etc can be left unadorned.
+   But internals used by the test programs or speed measuring programs
+   should have __GMP_DECLSPEC, and certainly constants or variables must
+   have it or the wrong address will be resolved.
+
+   In gcc __declspec can go at either the start or end of a prototype.
+
+   In Microsoft C __declspec must go at the start, or after the type like
+   void __declspec(...) *foo()".  There's no __dllexport or anything to
+   guard against someone foolish #defining dllexport.  _export used to be
+   available, but no longer.
+
+   In Borland C _export still exists, but needs to go after the type, like
+   "void _export foo();".  Would have to change the __GMP_DECLSPEC syntax to
+   make use of that.  Probably more trouble than it's worth.  */
+
+#if defined (__GNUC__)
+#define __GMP_DECLSPEC_EXPORT  __declspec(__dllexport__)
+#define __GMP_DECLSPEC_IMPORT  __declspec(__dllimport__)
+#endif
+#if defined (_MSC_VER) || defined (__BORLANDC__)
+#define __GMP_DECLSPEC_EXPORT  __declspec(dllexport)
+#define __GMP_DECLSPEC_IMPORT  __declspec(dllimport)
+#endif
+#ifdef __WATCOMC__
+#define __GMP_DECLSPEC_EXPORT  __export
+#define __GMP_DECLSPEC_IMPORT  __import
+#endif
+#ifdef __IBMC__
+#define __GMP_DECLSPEC_EXPORT  _Export
+#define __GMP_DECLSPEC_IMPORT  _Import
+#endif
+
+#if __GMP_LIBGMP_DLL
+#ifdef __GMP_WITHIN_GMP
+/* compiling to go into a DLL libgmp */
+#define __GMP_DECLSPEC  __GMP_DECLSPEC_EXPORT
+#else
+/* compiling to go into an application which will link to a DLL libgmp */
+#define __GMP_DECLSPEC  __GMP_DECLSPEC_IMPORT
+#endif
+#else
+/* all other cases */
+#define __GMP_DECLSPEC
+#endif
+
+
+#ifdef __GMP_SHORT_LIMB
+typedef unsigned int		mp_limb_t;
+typedef int			mp_limb_signed_t;
+#else
+#ifdef _LONG_LONG_LIMB
+typedef unsigned long long int	mp_limb_t;
+typedef long long int		mp_limb_signed_t;
+#else
+typedef unsigned long int	mp_limb_t;
+typedef long int		mp_limb_signed_t;
+#endif
+#endif
+typedef unsigned long int	mp_bitcnt_t;
+
+/* For reference, note that the name __mpz_struct gets into C++ mangled
+   function names, which means although the "__" suggests an internal, we
+   must leave this name for binary compatibility.  */
+typedef struct
+{
+  int _mp_alloc;		/* Number of *limbs* allocated and pointed
+				   to by the _mp_d field.  */
+  int _mp_size;			/* abs(_mp_size) is the number of limbs the
+				   last field points to.  If _mp_size is
+				   negative this is a negative number.  */
+  mp_limb_t *_mp_d;		/* Pointer to the limbs.  */
+} __mpz_struct;
+
+#endif /* __GNU_MP__ */
+
+
+typedef __mpz_struct MP_INT;    /* gmp 1 source compatibility */
+typedef __mpz_struct mpz_t[1];
+
+typedef mp_limb_t *		mp_ptr;
+typedef const mp_limb_t *	mp_srcptr;
+#if defined (_CRAY) && ! defined (_CRAYMPP)
+/* plain `int' is much faster (48 bits) */
+#define __GMP_MP_SIZE_T_INT     1
+typedef int			mp_size_t;
+typedef int			mp_exp_t;
+#else
+#define __GMP_MP_SIZE_T_INT     0
+typedef long int		mp_size_t;
+typedef long int		mp_exp_t;
+#endif
+
+typedef struct
+{
+  __mpz_struct _mp_num;
+  __mpz_struct _mp_den;
+} __mpq_struct;
+
+typedef __mpq_struct MP_RAT;    /* gmp 1 source compatibility */
+typedef __mpq_struct mpq_t[1];
+
+typedef struct
+{
+  int _mp_prec;			/* Max precision, in number of `mp_limb_t's.
+				   Set by mpf_init and modified by
+				   mpf_set_prec.  The area pointed to by the
+				   _mp_d field contains `prec' + 1 limbs.  */
+  int _mp_size;			/* abs(_mp_size) is the number of limbs the
+				   last field points to.  If _mp_size is
+				   negative this is a negative number.  */
+  mp_exp_t _mp_exp;		/* Exponent, in the base of `mp_limb_t'.  */
+  mp_limb_t *_mp_d;		/* Pointer to the limbs.  */
+} __mpf_struct;
+
+/* typedef __mpf_struct MP_FLOAT; */
+typedef __mpf_struct mpf_t[1];
+
+/* Available random number generation algorithms.  */
+typedef enum
+{
+  GMP_RAND_ALG_DEFAULT = 0,
+  GMP_RAND_ALG_LC = GMP_RAND_ALG_DEFAULT /* Linear congruential.  */
+} gmp_randalg_t;
+
+/* Random state struct.  */
+typedef struct
+{
+  mpz_t _mp_seed;	  /* _mp_d member points to state of the generator. */
+  gmp_randalg_t _mp_alg;  /* Currently unused. */
+  union {
+    void *_mp_lc;         /* Pointer to function pointers structure.  */
+  } _mp_algdata;
+} __gmp_randstate_struct;
+typedef __gmp_randstate_struct gmp_randstate_t[1];
+
+/* Types for function declarations in gmp files.  */
+/* ??? Should not pollute user name space with these ??? */
+typedef const __mpz_struct *mpz_srcptr;
+typedef __mpz_struct *mpz_ptr;
+typedef const __mpf_struct *mpf_srcptr;
+typedef __mpf_struct *mpf_ptr;
+typedef const __mpq_struct *mpq_srcptr;
+typedef __mpq_struct *mpq_ptr;
+
+
+#if __GMP_LIBGMP_DLL
+#ifdef __GMP_WITHIN_GMPXX
+/* compiling to go into a DLL libgmpxx */
+#define __GMP_DECLSPEC_XX  __GMP_DECLSPEC_EXPORT
+#else
+/* compiling to go into a application which will link to a DLL libgmpxx */
+#define __GMP_DECLSPEC_XX  __GMP_DECLSPEC_IMPORT
+#endif
+#else
+/* all other cases */
+#define __GMP_DECLSPEC_XX
+#endif
+
+
+#ifndef __MPN
+#define __MPN(x) __gmpn_##x
+#endif
+
+/* For reference, "defined(EOF)" cannot be used here.  In g++ 2.95.4,
+   <iostream> defines EOF but not FILE.  */
+#if defined (FILE)                                              \
+  || defined (H_STDIO)                                          \
+  || defined (_H_STDIO)               /* AIX */                 \
+  || defined (_STDIO_H)               /* glibc, Sun, SCO */     \
+  || defined (_STDIO_H_)              /* BSD, OSF */            \
+  || defined (__STDIO_H)              /* Borland */             \
+  || defined (__STDIO_H__)            /* IRIX */                \
+  || defined (_STDIO_INCLUDED)        /* HPUX */                \
+  || defined (__dj_include_stdio_h_)  /* DJGPP */               \
+  || defined (_FILE_DEFINED)          /* Microsoft */           \
+  || defined (__STDIO__)              /* Apple MPW MrC */       \
+  || defined (_MSL_STDIO_H)           /* Metrowerks */          \
+  || defined (_STDIO_H_INCLUDED)      /* QNX4 */		\
+  || defined (_ISO_STDIO_ISO_H)       /* Sun C++ */		\
+  || defined (__STDIO_LOADED)         /* VMS */			\
+  || defined (__DEFINED_FILE)         /* musl */
+#define _GMP_H_HAVE_FILE 1
+#endif
+
+/* In ISO C, if a prototype involving "struct obstack *" is given without
+   that structure defined, then the struct is scoped down to just the
+   prototype, causing a conflict if it's subsequently defined for real.  So
+   only give prototypes if we've got obstack.h.  */
+#if defined (_OBSTACK_H)   /* glibc <obstack.h> */
+#define _GMP_H_HAVE_OBSTACK 1
+#endif
+
+/* The prototypes for gmp_vprintf etc are provided only if va_list is defined,
+   via an application having included <stdarg.h>.  Usually va_list is a typedef
+   so can't be tested directly, but C99 specifies that va_start is a macro.
+
+   <stdio.h> will define some sort of va_list for vprintf and vfprintf, but
+   let's not bother trying to use that since it's not standard and since
+   application uses for gmp_vprintf etc will almost certainly require the
+   whole <stdarg.h> anyway.  */
+
+#ifdef va_start
+#define _GMP_H_HAVE_VA_LIST 1
+#endif
+
+/* Test for gcc >= maj.min, as per __GNUC_PREREQ in glibc */
+#if defined (__GNUC__) && defined (__GNUC_MINOR__)
+#define __GMP_GNUC_PREREQ(maj, min) \
+  ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
+#else
+#define __GMP_GNUC_PREREQ(maj, min)  0
+#endif
+
+/* "pure" is in gcc 2.96 and up, see "(gcc)Function Attributes".  Basically
+   it means a function does nothing but examine its arguments and memory
+   (global or via arguments) to generate a return value, but changes nothing
+   and has no side-effects.  __GMP_NO_ATTRIBUTE_CONST_PURE lets
+   tune/common.c etc turn this off when trying to write timing loops.  */
+#if __GMP_GNUC_PREREQ (2,96) && ! defined (__GMP_NO_ATTRIBUTE_CONST_PURE)
+#define __GMP_ATTRIBUTE_PURE   __attribute__ ((__pure__))
+#else
+#define __GMP_ATTRIBUTE_PURE
+#endif
+
+
+/* __GMP_CAST allows us to use static_cast in C++, so our macros are clean
+   to "g++ -Wold-style-cast".
+
+   Casts in "extern inline" code within an extern "C" block don't induce
+   these warnings, so __GMP_CAST only needs to be used on documented
+   macros.  */
+
+#ifdef __cplusplus
+#define __GMP_CAST(type, expr)  (static_cast<type> (expr))
+#else
+#define __GMP_CAST(type, expr)  ((type) (expr))
+#endif
+
+
+/* An empty "throw ()" means the function doesn't throw any C++ exceptions,
+   this can save some stack frame info in applications.
+
+   Currently it's given only on functions which never divide-by-zero etc,
+   don't allocate memory, and are expected to never need to allocate memory.
+   This leaves open the possibility of a C++ throw from a future GMP
+   exceptions scheme.
+
+   mpz_set_ui etc are omitted to leave open the lazy allocation scheme
+   described in doc/tasks.html.  mpz_get_d etc are omitted to leave open
+   exceptions for float overflows.
+
+   Note that __GMP_NOTHROW must be given on any inlines the same as on their
+   prototypes (for g++ at least, where they're used together).  Note also
+   that g++ 3.0 demands that __GMP_NOTHROW is before other attributes like
+   __GMP_ATTRIBUTE_PURE.  */
+
+#if defined (__cplusplus)
+#if __cplusplus >= 201103L
+#define __GMP_NOTHROW  noexcept
+#else
+#define __GMP_NOTHROW  throw ()
+#endif
+#else
+#define __GMP_NOTHROW
+#endif
+
+
+/* PORTME: What other compilers have a useful "extern inline"?  "static
+   inline" would be an acceptable substitute if the compiler (or linker)
+   discards unused statics.  */
+
+ /* gcc has __inline__ in all modes, including strict ansi.  Give a prototype
+    for an inline too, so as to correctly specify "dllimport" on windows, in
+    case the function is called rather than inlined.
+    GCC 4.3 and above with -std=c99 or -std=gnu99 implements ISO C99
+    inline semantics, unless -fgnu89-inline is used.  */
+#ifdef __GNUC__
+#if (defined __GNUC_STDC_INLINE__) || (__GNUC__ == 4 && __GNUC_MINOR__ == 2) \
+  || (defined __GNUC_GNU_INLINE__ && defined __cplusplus)
+#define __GMP_EXTERN_INLINE extern __inline__ __attribute__ ((__gnu_inline__))
+#else
+#define __GMP_EXTERN_INLINE      extern __inline__
+#endif
+#define __GMP_INLINE_PROTOTYPES  1
+#endif
+
+/* DEC C (eg. version 5.9) supports "static __inline foo()", even in -std1
+   strict ANSI mode.  Inlining is done even when not optimizing (ie. -O0
+   mode, which is the default), but an unnecessary local copy of foo is
+   emitted unless -O is used.  "extern __inline" is accepted, but the
+   "extern" appears to be ignored, ie. it becomes a plain global function
+   but which is inlined within its file.  Don't know if all old versions of
+   DEC C supported __inline, but as a start let's do the right thing for
+   current versions.  */
+#ifdef __DECC
+#define __GMP_EXTERN_INLINE  static __inline
+#endif
+
+/* SCO OpenUNIX 8 cc supports "static inline foo()" but not in -Xc strict
+   ANSI mode (__STDC__ is 1 in that mode).  Inlining only actually takes
+   place under -O.  Without -O "foo" seems to be emitted whether it's used
+   or not, which is wasteful.  "extern inline foo()" isn't useful, the
+   "extern" is apparently ignored, so foo is inlined if possible but also
+   emitted as a global, which causes multiple definition errors when
+   building a shared libgmp.  */
+#ifdef __SCO_VERSION__
+#if __SCO_VERSION__ > 400000000 && __STDC__ != 1 \
+  && ! defined (__GMP_EXTERN_INLINE)
+#define __GMP_EXTERN_INLINE  static inline
+#endif
+#endif
+
+/* Microsoft's C compiler accepts __inline */
+#ifdef _MSC_VER
+#define __GMP_EXTERN_INLINE  __inline
+#endif
+
+/* Recent enough Sun C compilers want "inline" */
+#if defined (__SUNPRO_C) && __SUNPRO_C >= 0x560 \
+  && ! defined (__GMP_EXTERN_INLINE)
+#define __GMP_EXTERN_INLINE  inline
+#endif
+
+/* Somewhat older Sun C compilers want "static inline" */
+#if defined (__SUNPRO_C) && __SUNPRO_C >= 0x540 \
+  && ! defined (__GMP_EXTERN_INLINE)
+#define __GMP_EXTERN_INLINE  static inline
+#endif
+
+
+/* C++ always has "inline" and since it's a normal feature the linker should
+   discard duplicate non-inlined copies, or if it doesn't then that's a
+   problem for everyone, not just GMP.  */
+#if defined (__cplusplus) && ! defined (__GMP_EXTERN_INLINE)
+#define __GMP_EXTERN_INLINE  inline
+#endif
+
+/* Don't do any inlining within a configure run, since if the compiler ends
+   up emitting copies of the code into the object file it can end up
+   demanding the various support routines (like mpn_popcount) for linking,
+   making the "alloca" test and perhaps others fail.  And on hppa ia64 a
+   pre-release gcc 3.2 was seen not respecting the "extern" in "extern
+   __inline__", triggering this problem too.  */
+#if defined (__GMP_WITHIN_CONFIGURE) && ! __GMP_WITHIN_CONFIGURE_INLINE
+#undef __GMP_EXTERN_INLINE
+#endif
+
+/* By default, don't give a prototype when there's going to be an inline
+   version.  Note in particular that Cray C++ objects to the combination of
+   prototype and inline.  */
+#ifdef __GMP_EXTERN_INLINE
+#ifndef __GMP_INLINE_PROTOTYPES
+#define __GMP_INLINE_PROTOTYPES  0
+#endif
+#else
+#define __GMP_INLINE_PROTOTYPES  1
+#endif
+
+
+#define __GMP_ABS(x)   ((x) >= 0 ? (x) : -(x))
+#define __GMP_MAX(h,i) ((h) > (i) ? (h) : (i))
+
+
+/* __builtin_expect is in gcc 3.0, and not in 2.95. */
+#if __GMP_GNUC_PREREQ (3,0)
+#define __GMP_LIKELY(cond)    __builtin_expect ((cond) != 0, 1)
+#define __GMP_UNLIKELY(cond)  __builtin_expect ((cond) != 0, 0)
+#else
+#define __GMP_LIKELY(cond)    (cond)
+#define __GMP_UNLIKELY(cond)  (cond)
+#endif
+
+#ifdef _CRAY
+#define __GMP_CRAY_Pragma(str)  _Pragma (str)
+#else
+#define __GMP_CRAY_Pragma(str)
+#endif
+
+
+/* Allow direct user access to numerator and denominator of an mpq_t object.  */
+#define mpq_numref(Q) (&((Q)->_mp_num))
+#define mpq_denref(Q) (&((Q)->_mp_den))
+
+
+#if defined (__cplusplus)
+extern "C" {
+using std::FILE;
+#endif
+
+#define mp_set_memory_functions __gmp_set_memory_functions
+__GMP_DECLSPEC void mp_set_memory_functions (void *(*) (size_t),
+				      void *(*) (void *, size_t, size_t),
+				      void (*) (void *, size_t)) __GMP_NOTHROW;
+
+#define mp_get_memory_functions __gmp_get_memory_functions
+__GMP_DECLSPEC void mp_get_memory_functions (void *(**) (size_t),
+				      void *(**) (void *, size_t, size_t),
+				      void (**) (void *, size_t)) __GMP_NOTHROW;
+
+#define mp_bits_per_limb __gmp_bits_per_limb
+__GMP_DECLSPEC extern const int mp_bits_per_limb;
+
+#define gmp_errno __gmp_errno
+__GMP_DECLSPEC extern int gmp_errno;
+
+#define gmp_version __gmp_version
+__GMP_DECLSPEC extern const char * const gmp_version;
+
+
+/**************** Random number routines.  ****************/
+
+/* obsolete */
+#define gmp_randinit __gmp_randinit
+__GMP_DECLSPEC void gmp_randinit (gmp_randstate_t, gmp_randalg_t, ...);
+
+#define gmp_randinit_default __gmp_randinit_default
+__GMP_DECLSPEC void gmp_randinit_default (gmp_randstate_t);
+
+#define gmp_randinit_lc_2exp __gmp_randinit_lc_2exp
+__GMP_DECLSPEC void gmp_randinit_lc_2exp (gmp_randstate_t, mpz_srcptr, unsigned long int, mp_bitcnt_t);
+
+#define gmp_randinit_lc_2exp_size __gmp_randinit_lc_2exp_size
+__GMP_DECLSPEC int gmp_randinit_lc_2exp_size (gmp_randstate_t, mp_bitcnt_t);
+
+#define gmp_randinit_mt __gmp_randinit_mt
+__GMP_DECLSPEC void gmp_randinit_mt (gmp_randstate_t);
+
+#define gmp_randinit_set __gmp_randinit_set
+__GMP_DECLSPEC void gmp_randinit_set (gmp_randstate_t, const __gmp_randstate_struct *);
+
+#define gmp_randseed __gmp_randseed
+__GMP_DECLSPEC void gmp_randseed (gmp_randstate_t, mpz_srcptr);
+
+#define gmp_randseed_ui __gmp_randseed_ui
+__GMP_DECLSPEC void gmp_randseed_ui (gmp_randstate_t, unsigned long int);
+
+#define gmp_randclear __gmp_randclear
+__GMP_DECLSPEC void gmp_randclear (gmp_randstate_t);
+
+#define gmp_urandomb_ui __gmp_urandomb_ui
+__GMP_DECLSPEC unsigned long gmp_urandomb_ui (gmp_randstate_t, unsigned long);
+
+#define gmp_urandomm_ui __gmp_urandomm_ui
+__GMP_DECLSPEC unsigned long gmp_urandomm_ui (gmp_randstate_t, unsigned long);
+
+
+/**************** Formatted output routines.  ****************/
+
+#define gmp_asprintf __gmp_asprintf
+__GMP_DECLSPEC int gmp_asprintf (char **, const char *, ...);
+
+#define gmp_fprintf __gmp_fprintf
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC int gmp_fprintf (FILE *, const char *, ...);
+#endif
+
+#define gmp_obstack_printf __gmp_obstack_printf
+#if defined (_GMP_H_HAVE_OBSTACK)
+__GMP_DECLSPEC int gmp_obstack_printf (struct obstack *, const char *, ...);
+#endif
+
+#define gmp_obstack_vprintf __gmp_obstack_vprintf
+#if defined (_GMP_H_HAVE_OBSTACK) && defined (_GMP_H_HAVE_VA_LIST)
+__GMP_DECLSPEC int gmp_obstack_vprintf (struct obstack *, const char *, va_list);
+#endif
+
+#define gmp_printf __gmp_printf
+__GMP_DECLSPEC int gmp_printf (const char *, ...);
+
+#define gmp_snprintf __gmp_snprintf
+__GMP_DECLSPEC int gmp_snprintf (char *, size_t, const char *, ...);
+
+#define gmp_sprintf __gmp_sprintf
+__GMP_DECLSPEC int gmp_sprintf (char *, const char *, ...);
+
+#define gmp_vasprintf __gmp_vasprintf
+#if defined (_GMP_H_HAVE_VA_LIST)
+__GMP_DECLSPEC int gmp_vasprintf (char **, const char *, va_list);
+#endif
+
+#define gmp_vfprintf __gmp_vfprintf
+#if defined (_GMP_H_HAVE_FILE) && defined (_GMP_H_HAVE_VA_LIST)
+__GMP_DECLSPEC int gmp_vfprintf (FILE *, const char *, va_list);
+#endif
+
+#define gmp_vprintf __gmp_vprintf
+#if defined (_GMP_H_HAVE_VA_LIST)
+__GMP_DECLSPEC int gmp_vprintf (const char *, va_list);
+#endif
+
+#define gmp_vsnprintf __gmp_vsnprintf
+#if defined (_GMP_H_HAVE_VA_LIST)
+__GMP_DECLSPEC int gmp_vsnprintf (char *, size_t, const char *, va_list);
+#endif
+
+#define gmp_vsprintf __gmp_vsprintf
+#if defined (_GMP_H_HAVE_VA_LIST)
+__GMP_DECLSPEC int gmp_vsprintf (char *, const char *, va_list);
+#endif
+
+
+/**************** Formatted input routines.  ****************/
+
+#define gmp_fscanf __gmp_fscanf
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC int gmp_fscanf (FILE *, const char *, ...);
+#endif
+
+#define gmp_scanf __gmp_scanf
+__GMP_DECLSPEC int gmp_scanf (const char *, ...);
+
+#define gmp_sscanf __gmp_sscanf
+__GMP_DECLSPEC int gmp_sscanf (const char *, const char *, ...);
+
+#define gmp_vfscanf __gmp_vfscanf
+#if defined (_GMP_H_HAVE_FILE) && defined (_GMP_H_HAVE_VA_LIST)
+__GMP_DECLSPEC int gmp_vfscanf (FILE *, const char *, va_list);
+#endif
+
+#define gmp_vscanf __gmp_vscanf
+#if defined (_GMP_H_HAVE_VA_LIST)
+__GMP_DECLSPEC int gmp_vscanf (const char *, va_list);
+#endif
+
+#define gmp_vsscanf __gmp_vsscanf
+#if defined (_GMP_H_HAVE_VA_LIST)
+__GMP_DECLSPEC int gmp_vsscanf (const char *, const char *, va_list);
+#endif
+
+
+/**************** Integer (i.e. Z) routines.  ****************/
+
+#define _mpz_realloc __gmpz_realloc
+#define mpz_realloc __gmpz_realloc
+__GMP_DECLSPEC void *_mpz_realloc (mpz_ptr, mp_size_t);
+
+#define mpz_abs __gmpz_abs
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_abs)
+__GMP_DECLSPEC void mpz_abs (mpz_ptr, mpz_srcptr);
+#endif
+
+#define mpz_add __gmpz_add
+__GMP_DECLSPEC void mpz_add (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_add_ui __gmpz_add_ui
+__GMP_DECLSPEC void mpz_add_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_addmul __gmpz_addmul
+__GMP_DECLSPEC void mpz_addmul (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_addmul_ui __gmpz_addmul_ui
+__GMP_DECLSPEC void mpz_addmul_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_and __gmpz_and
+__GMP_DECLSPEC void mpz_and (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_array_init __gmpz_array_init
+__GMP_DECLSPEC void mpz_array_init (mpz_ptr, mp_size_t, mp_size_t);
+
+#define mpz_bin_ui __gmpz_bin_ui
+__GMP_DECLSPEC void mpz_bin_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_bin_uiui __gmpz_bin_uiui
+__GMP_DECLSPEC void mpz_bin_uiui (mpz_ptr, unsigned long int, unsigned long int);
+
+#define mpz_cdiv_q __gmpz_cdiv_q
+__GMP_DECLSPEC void mpz_cdiv_q (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_cdiv_q_2exp __gmpz_cdiv_q_2exp
+__GMP_DECLSPEC void mpz_cdiv_q_2exp (mpz_ptr, mpz_srcptr, mp_bitcnt_t);
+
+#define mpz_cdiv_q_ui __gmpz_cdiv_q_ui
+__GMP_DECLSPEC unsigned long int mpz_cdiv_q_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_cdiv_qr __gmpz_cdiv_qr
+__GMP_DECLSPEC void mpz_cdiv_qr (mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_cdiv_qr_ui __gmpz_cdiv_qr_ui
+__GMP_DECLSPEC unsigned long int mpz_cdiv_qr_ui (mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_cdiv_r __gmpz_cdiv_r
+__GMP_DECLSPEC void mpz_cdiv_r (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_cdiv_r_2exp __gmpz_cdiv_r_2exp
+__GMP_DECLSPEC void mpz_cdiv_r_2exp (mpz_ptr, mpz_srcptr, mp_bitcnt_t);
+
+#define mpz_cdiv_r_ui __gmpz_cdiv_r_ui
+__GMP_DECLSPEC unsigned long int mpz_cdiv_r_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_cdiv_ui __gmpz_cdiv_ui
+__GMP_DECLSPEC unsigned long int mpz_cdiv_ui (mpz_srcptr, unsigned long int) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_clear __gmpz_clear
+__GMP_DECLSPEC void mpz_clear (mpz_ptr);
+
+#define mpz_clears __gmpz_clears
+__GMP_DECLSPEC void mpz_clears (mpz_ptr, ...);
+
+#define mpz_clrbit __gmpz_clrbit
+__GMP_DECLSPEC void mpz_clrbit (mpz_ptr, mp_bitcnt_t);
+
+#define mpz_cmp __gmpz_cmp
+__GMP_DECLSPEC int mpz_cmp (mpz_srcptr, mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_cmp_d __gmpz_cmp_d
+__GMP_DECLSPEC int mpz_cmp_d (mpz_srcptr, double) __GMP_ATTRIBUTE_PURE;
+
+#define _mpz_cmp_si __gmpz_cmp_si
+__GMP_DECLSPEC int _mpz_cmp_si (mpz_srcptr, signed long int) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define _mpz_cmp_ui __gmpz_cmp_ui
+__GMP_DECLSPEC int _mpz_cmp_ui (mpz_srcptr, unsigned long int) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_cmpabs __gmpz_cmpabs
+__GMP_DECLSPEC int mpz_cmpabs (mpz_srcptr, mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_cmpabs_d __gmpz_cmpabs_d
+__GMP_DECLSPEC int mpz_cmpabs_d (mpz_srcptr, double) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_cmpabs_ui __gmpz_cmpabs_ui
+__GMP_DECLSPEC int mpz_cmpabs_ui (mpz_srcptr, unsigned long int) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_com __gmpz_com
+__GMP_DECLSPEC void mpz_com (mpz_ptr, mpz_srcptr);
+
+#define mpz_combit __gmpz_combit
+__GMP_DECLSPEC void mpz_combit (mpz_ptr, mp_bitcnt_t);
+
+#define mpz_congruent_p __gmpz_congruent_p
+__GMP_DECLSPEC int mpz_congruent_p (mpz_srcptr, mpz_srcptr, mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_congruent_2exp_p __gmpz_congruent_2exp_p
+__GMP_DECLSPEC int mpz_congruent_2exp_p (mpz_srcptr, mpz_srcptr, mp_bitcnt_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_congruent_ui_p __gmpz_congruent_ui_p
+__GMP_DECLSPEC int mpz_congruent_ui_p (mpz_srcptr, unsigned long, unsigned long) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_divexact __gmpz_divexact
+__GMP_DECLSPEC void mpz_divexact (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_divexact_ui __gmpz_divexact_ui
+__GMP_DECLSPEC void mpz_divexact_ui (mpz_ptr, mpz_srcptr, unsigned long);
+
+#define mpz_divisible_p __gmpz_divisible_p
+__GMP_DECLSPEC int mpz_divisible_p (mpz_srcptr, mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_divisible_ui_p __gmpz_divisible_ui_p
+__GMP_DECLSPEC int mpz_divisible_ui_p (mpz_srcptr, unsigned long) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_divisible_2exp_p __gmpz_divisible_2exp_p
+__GMP_DECLSPEC int mpz_divisible_2exp_p (mpz_srcptr, mp_bitcnt_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_dump __gmpz_dump
+__GMP_DECLSPEC void mpz_dump (mpz_srcptr);
+
+#define mpz_export __gmpz_export
+__GMP_DECLSPEC void *mpz_export (void *, size_t *, int, size_t, int, size_t, mpz_srcptr);
+
+#define mpz_fac_ui __gmpz_fac_ui
+__GMP_DECLSPEC void mpz_fac_ui (mpz_ptr, unsigned long int);
+
+#define mpz_2fac_ui __gmpz_2fac_ui
+__GMP_DECLSPEC void mpz_2fac_ui (mpz_ptr, unsigned long int);
+
+#define mpz_mfac_uiui __gmpz_mfac_uiui
+__GMP_DECLSPEC void mpz_mfac_uiui (mpz_ptr, unsigned long int, unsigned long int);
+
+#define mpz_primorial_ui __gmpz_primorial_ui
+__GMP_DECLSPEC void mpz_primorial_ui (mpz_ptr, unsigned long int);
+
+#define mpz_fdiv_q __gmpz_fdiv_q
+__GMP_DECLSPEC void mpz_fdiv_q (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_fdiv_q_2exp __gmpz_fdiv_q_2exp
+__GMP_DECLSPEC void mpz_fdiv_q_2exp (mpz_ptr, mpz_srcptr, mp_bitcnt_t);
+
+#define mpz_fdiv_q_ui __gmpz_fdiv_q_ui
+__GMP_DECLSPEC unsigned long int mpz_fdiv_q_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_fdiv_qr __gmpz_fdiv_qr
+__GMP_DECLSPEC void mpz_fdiv_qr (mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_fdiv_qr_ui __gmpz_fdiv_qr_ui
+__GMP_DECLSPEC unsigned long int mpz_fdiv_qr_ui (mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_fdiv_r __gmpz_fdiv_r
+__GMP_DECLSPEC void mpz_fdiv_r (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_fdiv_r_2exp __gmpz_fdiv_r_2exp
+__GMP_DECLSPEC void mpz_fdiv_r_2exp (mpz_ptr, mpz_srcptr, mp_bitcnt_t);
+
+#define mpz_fdiv_r_ui __gmpz_fdiv_r_ui
+__GMP_DECLSPEC unsigned long int mpz_fdiv_r_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_fdiv_ui __gmpz_fdiv_ui
+__GMP_DECLSPEC unsigned long int mpz_fdiv_ui (mpz_srcptr, unsigned long int) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_fib_ui __gmpz_fib_ui
+__GMP_DECLSPEC void mpz_fib_ui (mpz_ptr, unsigned long int);
+
+#define mpz_fib2_ui __gmpz_fib2_ui
+__GMP_DECLSPEC void mpz_fib2_ui (mpz_ptr, mpz_ptr, unsigned long int);
+
+#define mpz_fits_sint_p __gmpz_fits_sint_p
+__GMP_DECLSPEC int mpz_fits_sint_p (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_fits_slong_p __gmpz_fits_slong_p
+__GMP_DECLSPEC int mpz_fits_slong_p (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_fits_sshort_p __gmpz_fits_sshort_p
+__GMP_DECLSPEC int mpz_fits_sshort_p (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_fits_uint_p __gmpz_fits_uint_p
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_fits_uint_p)
+__GMP_DECLSPEC int mpz_fits_uint_p (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpz_fits_ulong_p __gmpz_fits_ulong_p
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_fits_ulong_p)
+__GMP_DECLSPEC int mpz_fits_ulong_p (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpz_fits_ushort_p __gmpz_fits_ushort_p
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_fits_ushort_p)
+__GMP_DECLSPEC int mpz_fits_ushort_p (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpz_gcd __gmpz_gcd
+__GMP_DECLSPEC void mpz_gcd (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_gcd_ui __gmpz_gcd_ui
+__GMP_DECLSPEC unsigned long int mpz_gcd_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_gcdext __gmpz_gcdext
+__GMP_DECLSPEC void mpz_gcdext (mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_get_d __gmpz_get_d
+__GMP_DECLSPEC double mpz_get_d (mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_get_d_2exp __gmpz_get_d_2exp
+__GMP_DECLSPEC double mpz_get_d_2exp (signed long int *, mpz_srcptr);
+
+#define mpz_get_si __gmpz_get_si
+__GMP_DECLSPEC /* signed */ long int mpz_get_si (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_get_str __gmpz_get_str
+__GMP_DECLSPEC char *mpz_get_str (char *, int, mpz_srcptr);
+
+#define mpz_get_ui __gmpz_get_ui
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_get_ui)
+__GMP_DECLSPEC unsigned long int mpz_get_ui (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpz_getlimbn __gmpz_getlimbn
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_getlimbn)
+__GMP_DECLSPEC mp_limb_t mpz_getlimbn (mpz_srcptr, mp_size_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpz_hamdist __gmpz_hamdist
+__GMP_DECLSPEC mp_bitcnt_t mpz_hamdist (mpz_srcptr, mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_import __gmpz_import
+__GMP_DECLSPEC void mpz_import (mpz_ptr, size_t, int, size_t, int, size_t, const void *);
+
+#define mpz_init __gmpz_init
+__GMP_DECLSPEC void mpz_init (mpz_ptr) __GMP_NOTHROW;
+
+#define mpz_init2 __gmpz_init2
+__GMP_DECLSPEC void mpz_init2 (mpz_ptr, mp_bitcnt_t);
+
+#define mpz_inits __gmpz_inits
+__GMP_DECLSPEC void mpz_inits (mpz_ptr, ...) __GMP_NOTHROW;
+
+#define mpz_init_set __gmpz_init_set
+__GMP_DECLSPEC void mpz_init_set (mpz_ptr, mpz_srcptr);
+
+#define mpz_init_set_d __gmpz_init_set_d
+__GMP_DECLSPEC void mpz_init_set_d (mpz_ptr, double);
+
+#define mpz_init_set_si __gmpz_init_set_si
+__GMP_DECLSPEC void mpz_init_set_si (mpz_ptr, signed long int);
+
+#define mpz_init_set_str __gmpz_init_set_str
+__GMP_DECLSPEC int mpz_init_set_str (mpz_ptr, const char *, int);
+
+#define mpz_init_set_ui __gmpz_init_set_ui
+__GMP_DECLSPEC void mpz_init_set_ui (mpz_ptr, unsigned long int);
+
+#define mpz_inp_raw __gmpz_inp_raw
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC size_t mpz_inp_raw (mpz_ptr, FILE *);
+#endif
+
+#define mpz_inp_str __gmpz_inp_str
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC size_t mpz_inp_str (mpz_ptr, FILE *, int);
+#endif
+
+#define mpz_invert __gmpz_invert
+__GMP_DECLSPEC int mpz_invert (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_ior __gmpz_ior
+__GMP_DECLSPEC void mpz_ior (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_jacobi __gmpz_jacobi
+__GMP_DECLSPEC int mpz_jacobi (mpz_srcptr, mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_kronecker mpz_jacobi  /* alias */
+
+#define mpz_kronecker_si __gmpz_kronecker_si
+__GMP_DECLSPEC int mpz_kronecker_si (mpz_srcptr, long) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_kronecker_ui __gmpz_kronecker_ui
+__GMP_DECLSPEC int mpz_kronecker_ui (mpz_srcptr, unsigned long) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_si_kronecker __gmpz_si_kronecker
+__GMP_DECLSPEC int mpz_si_kronecker (long, mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_ui_kronecker __gmpz_ui_kronecker
+__GMP_DECLSPEC int mpz_ui_kronecker (unsigned long, mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_lcm __gmpz_lcm
+__GMP_DECLSPEC void mpz_lcm (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_lcm_ui __gmpz_lcm_ui
+__GMP_DECLSPEC void mpz_lcm_ui (mpz_ptr, mpz_srcptr, unsigned long);
+
+#define mpz_legendre mpz_jacobi  /* alias */
+
+#define mpz_lucnum_ui __gmpz_lucnum_ui
+__GMP_DECLSPEC void mpz_lucnum_ui (mpz_ptr, unsigned long int);
+
+#define mpz_lucnum2_ui __gmpz_lucnum2_ui
+__GMP_DECLSPEC void mpz_lucnum2_ui (mpz_ptr, mpz_ptr, unsigned long int);
+
+#define mpz_millerrabin __gmpz_millerrabin
+__GMP_DECLSPEC int mpz_millerrabin (mpz_srcptr, int) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_mod __gmpz_mod
+__GMP_DECLSPEC void mpz_mod (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_mod_ui mpz_fdiv_r_ui /* same as fdiv_r because divisor unsigned */
+
+#define mpz_mul __gmpz_mul
+__GMP_DECLSPEC void mpz_mul (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_mul_2exp __gmpz_mul_2exp
+__GMP_DECLSPEC void mpz_mul_2exp (mpz_ptr, mpz_srcptr, mp_bitcnt_t);
+
+#define mpz_mul_si __gmpz_mul_si
+__GMP_DECLSPEC void mpz_mul_si (mpz_ptr, mpz_srcptr, long int);
+
+#define mpz_mul_ui __gmpz_mul_ui
+__GMP_DECLSPEC void mpz_mul_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_neg __gmpz_neg
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_neg)
+__GMP_DECLSPEC void mpz_neg (mpz_ptr, mpz_srcptr);
+#endif
+
+#define mpz_nextprime __gmpz_nextprime
+__GMP_DECLSPEC void mpz_nextprime (mpz_ptr, mpz_srcptr);
+
+#define mpz_out_raw __gmpz_out_raw
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC size_t mpz_out_raw (FILE *, mpz_srcptr);
+#endif
+
+#define mpz_out_str __gmpz_out_str
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC size_t mpz_out_str (FILE *, int, mpz_srcptr);
+#endif
+
+#define mpz_perfect_power_p __gmpz_perfect_power_p
+__GMP_DECLSPEC int mpz_perfect_power_p (mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_perfect_square_p __gmpz_perfect_square_p
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_perfect_square_p)
+__GMP_DECLSPEC int mpz_perfect_square_p (mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpz_popcount __gmpz_popcount
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_popcount)
+__GMP_DECLSPEC mp_bitcnt_t mpz_popcount (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpz_pow_ui __gmpz_pow_ui
+__GMP_DECLSPEC void mpz_pow_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_powm __gmpz_powm
+__GMP_DECLSPEC void mpz_powm (mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_powm_sec __gmpz_powm_sec
+__GMP_DECLSPEC void mpz_powm_sec (mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_powm_ui __gmpz_powm_ui
+__GMP_DECLSPEC void mpz_powm_ui (mpz_ptr, mpz_srcptr, unsigned long int, mpz_srcptr);
+
+#define mpz_probab_prime_p __gmpz_probab_prime_p
+__GMP_DECLSPEC int mpz_probab_prime_p (mpz_srcptr, int) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_random __gmpz_random
+__GMP_DECLSPEC void mpz_random (mpz_ptr, mp_size_t);
+
+#define mpz_random2 __gmpz_random2
+__GMP_DECLSPEC void mpz_random2 (mpz_ptr, mp_size_t);
+
+#define mpz_realloc2 __gmpz_realloc2
+__GMP_DECLSPEC void mpz_realloc2 (mpz_ptr, mp_bitcnt_t);
+
+#define mpz_remove __gmpz_remove
+__GMP_DECLSPEC mp_bitcnt_t mpz_remove (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_root __gmpz_root
+__GMP_DECLSPEC int mpz_root (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_rootrem __gmpz_rootrem
+__GMP_DECLSPEC void mpz_rootrem (mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_rrandomb __gmpz_rrandomb
+__GMP_DECLSPEC void mpz_rrandomb (mpz_ptr, gmp_randstate_t, mp_bitcnt_t);
+
+#define mpz_scan0 __gmpz_scan0
+__GMP_DECLSPEC mp_bitcnt_t mpz_scan0 (mpz_srcptr, mp_bitcnt_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_scan1 __gmpz_scan1
+__GMP_DECLSPEC mp_bitcnt_t mpz_scan1 (mpz_srcptr, mp_bitcnt_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_set __gmpz_set
+__GMP_DECLSPEC void mpz_set (mpz_ptr, mpz_srcptr);
+
+#define mpz_set_d __gmpz_set_d
+__GMP_DECLSPEC void mpz_set_d (mpz_ptr, double);
+
+#define mpz_set_f __gmpz_set_f
+__GMP_DECLSPEC void mpz_set_f (mpz_ptr, mpf_srcptr);
+
+#define mpz_set_q __gmpz_set_q
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_set_q)
+__GMP_DECLSPEC void mpz_set_q (mpz_ptr, mpq_srcptr);
+#endif
+
+#define mpz_set_si __gmpz_set_si
+__GMP_DECLSPEC void mpz_set_si (mpz_ptr, signed long int);
+
+#define mpz_set_str __gmpz_set_str
+__GMP_DECLSPEC int mpz_set_str (mpz_ptr, const char *, int);
+
+#define mpz_set_ui __gmpz_set_ui
+__GMP_DECLSPEC void mpz_set_ui (mpz_ptr, unsigned long int);
+
+#define mpz_setbit __gmpz_setbit
+__GMP_DECLSPEC void mpz_setbit (mpz_ptr, mp_bitcnt_t);
+
+#define mpz_size __gmpz_size
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpz_size)
+__GMP_DECLSPEC size_t mpz_size (mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpz_sizeinbase __gmpz_sizeinbase
+__GMP_DECLSPEC size_t mpz_sizeinbase (mpz_srcptr, int) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_sqrt __gmpz_sqrt
+__GMP_DECLSPEC void mpz_sqrt (mpz_ptr, mpz_srcptr);
+
+#define mpz_sqrtrem __gmpz_sqrtrem
+__GMP_DECLSPEC void mpz_sqrtrem (mpz_ptr, mpz_ptr, mpz_srcptr);
+
+#define mpz_sub __gmpz_sub
+__GMP_DECLSPEC void mpz_sub (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_sub_ui __gmpz_sub_ui
+__GMP_DECLSPEC void mpz_sub_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_ui_sub __gmpz_ui_sub
+__GMP_DECLSPEC void mpz_ui_sub (mpz_ptr, unsigned long int, mpz_srcptr);
+
+#define mpz_submul __gmpz_submul
+__GMP_DECLSPEC void mpz_submul (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_submul_ui __gmpz_submul_ui
+__GMP_DECLSPEC void mpz_submul_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_swap __gmpz_swap
+__GMP_DECLSPEC void mpz_swap (mpz_ptr, mpz_ptr) __GMP_NOTHROW;
+
+#define mpz_tdiv_ui __gmpz_tdiv_ui
+__GMP_DECLSPEC unsigned long int mpz_tdiv_ui (mpz_srcptr, unsigned long int) __GMP_ATTRIBUTE_PURE;
+
+#define mpz_tdiv_q __gmpz_tdiv_q
+__GMP_DECLSPEC void mpz_tdiv_q (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_tdiv_q_2exp __gmpz_tdiv_q_2exp
+__GMP_DECLSPEC void mpz_tdiv_q_2exp (mpz_ptr, mpz_srcptr, mp_bitcnt_t);
+
+#define mpz_tdiv_q_ui __gmpz_tdiv_q_ui
+__GMP_DECLSPEC unsigned long int mpz_tdiv_q_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_tdiv_qr __gmpz_tdiv_qr
+__GMP_DECLSPEC void mpz_tdiv_qr (mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_tdiv_qr_ui __gmpz_tdiv_qr_ui
+__GMP_DECLSPEC unsigned long int mpz_tdiv_qr_ui (mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_tdiv_r __gmpz_tdiv_r
+__GMP_DECLSPEC void mpz_tdiv_r (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_tdiv_r_2exp __gmpz_tdiv_r_2exp
+__GMP_DECLSPEC void mpz_tdiv_r_2exp (mpz_ptr, mpz_srcptr, mp_bitcnt_t);
+
+#define mpz_tdiv_r_ui __gmpz_tdiv_r_ui
+__GMP_DECLSPEC unsigned long int mpz_tdiv_r_ui (mpz_ptr, mpz_srcptr, unsigned long int);
+
+#define mpz_tstbit __gmpz_tstbit
+__GMP_DECLSPEC int mpz_tstbit (mpz_srcptr, mp_bitcnt_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpz_ui_pow_ui __gmpz_ui_pow_ui
+__GMP_DECLSPEC void mpz_ui_pow_ui (mpz_ptr, unsigned long int, unsigned long int);
+
+#define mpz_urandomb __gmpz_urandomb
+__GMP_DECLSPEC void mpz_urandomb (mpz_ptr, gmp_randstate_t, mp_bitcnt_t);
+
+#define mpz_urandomm __gmpz_urandomm
+__GMP_DECLSPEC void mpz_urandomm (mpz_ptr, gmp_randstate_t, mpz_srcptr);
+
+#define mpz_xor __gmpz_xor
+#define mpz_eor __gmpz_xor
+__GMP_DECLSPEC void mpz_xor (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_limbs_read __gmpz_limbs_read
+__GMP_DECLSPEC mp_srcptr mpz_limbs_read (mpz_srcptr);
+
+#define mpz_limbs_write __gmpz_limbs_write
+__GMP_DECLSPEC mp_ptr mpz_limbs_write (mpz_ptr, mp_size_t);
+
+#define mpz_limbs_modify __gmpz_limbs_modify
+__GMP_DECLSPEC mp_ptr mpz_limbs_modify (mpz_ptr, mp_size_t);
+
+#define mpz_limbs_finish __gmpz_limbs_finish
+__GMP_DECLSPEC void mpz_limbs_finish (mpz_ptr, mp_size_t);
+
+#define mpz_roinit_n __gmpz_roinit_n
+__GMP_DECLSPEC mpz_srcptr mpz_roinit_n (mpz_ptr, mp_srcptr, mp_size_t);
+
+#define MPZ_ROINIT_N(xp, xs) {{0, (xs),(xp) }}
+
+/**************** Rational (i.e. Q) routines.  ****************/
+
+#define mpq_abs __gmpq_abs
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpq_abs)
+__GMP_DECLSPEC void mpq_abs (mpq_ptr, mpq_srcptr);
+#endif
+
+#define mpq_add __gmpq_add
+__GMP_DECLSPEC void mpq_add (mpq_ptr, mpq_srcptr, mpq_srcptr);
+
+#define mpq_canonicalize __gmpq_canonicalize
+__GMP_DECLSPEC void mpq_canonicalize (mpq_ptr);
+
+#define mpq_clear __gmpq_clear
+__GMP_DECLSPEC void mpq_clear (mpq_ptr);
+
+#define mpq_clears __gmpq_clears
+__GMP_DECLSPEC void mpq_clears (mpq_ptr, ...);
+
+#define mpq_cmp __gmpq_cmp
+__GMP_DECLSPEC int mpq_cmp (mpq_srcptr, mpq_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define _mpq_cmp_si __gmpq_cmp_si
+__GMP_DECLSPEC int _mpq_cmp_si (mpq_srcptr, long, unsigned long) __GMP_ATTRIBUTE_PURE;
+
+#define _mpq_cmp_ui __gmpq_cmp_ui
+__GMP_DECLSPEC int _mpq_cmp_ui (mpq_srcptr, unsigned long int, unsigned long int) __GMP_ATTRIBUTE_PURE;
+
+#define mpq_cmp_z __gmpq_cmp_z
+__GMP_DECLSPEC int mpq_cmp_z (mpq_srcptr, mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpq_div __gmpq_div
+__GMP_DECLSPEC void mpq_div (mpq_ptr, mpq_srcptr, mpq_srcptr);
+
+#define mpq_div_2exp __gmpq_div_2exp
+__GMP_DECLSPEC void mpq_div_2exp (mpq_ptr, mpq_srcptr, mp_bitcnt_t);
+
+#define mpq_equal __gmpq_equal
+__GMP_DECLSPEC int mpq_equal (mpq_srcptr, mpq_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpq_get_num __gmpq_get_num
+__GMP_DECLSPEC void mpq_get_num (mpz_ptr, mpq_srcptr);
+
+#define mpq_get_den __gmpq_get_den
+__GMP_DECLSPEC void mpq_get_den (mpz_ptr, mpq_srcptr);
+
+#define mpq_get_d __gmpq_get_d
+__GMP_DECLSPEC double mpq_get_d (mpq_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpq_get_str __gmpq_get_str
+__GMP_DECLSPEC char *mpq_get_str (char *, int, mpq_srcptr);
+
+#define mpq_init __gmpq_init
+__GMP_DECLSPEC void mpq_init (mpq_ptr);
+
+#define mpq_inits __gmpq_inits
+__GMP_DECLSPEC void mpq_inits (mpq_ptr, ...);
+
+#define mpq_inp_str __gmpq_inp_str
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC size_t mpq_inp_str (mpq_ptr, FILE *, int);
+#endif
+
+#define mpq_inv __gmpq_inv
+__GMP_DECLSPEC void mpq_inv (mpq_ptr, mpq_srcptr);
+
+#define mpq_mul __gmpq_mul
+__GMP_DECLSPEC void mpq_mul (mpq_ptr, mpq_srcptr, mpq_srcptr);
+
+#define mpq_mul_2exp __gmpq_mul_2exp
+__GMP_DECLSPEC void mpq_mul_2exp (mpq_ptr, mpq_srcptr, mp_bitcnt_t);
+
+#define mpq_neg __gmpq_neg
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpq_neg)
+__GMP_DECLSPEC void mpq_neg (mpq_ptr, mpq_srcptr);
+#endif
+
+#define mpq_out_str __gmpq_out_str
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC size_t mpq_out_str (FILE *, int, mpq_srcptr);
+#endif
+
+#define mpq_set __gmpq_set
+__GMP_DECLSPEC void mpq_set (mpq_ptr, mpq_srcptr);
+
+#define mpq_set_d __gmpq_set_d
+__GMP_DECLSPEC void mpq_set_d (mpq_ptr, double);
+
+#define mpq_set_den __gmpq_set_den
+__GMP_DECLSPEC void mpq_set_den (mpq_ptr, mpz_srcptr);
+
+#define mpq_set_f __gmpq_set_f
+__GMP_DECLSPEC void mpq_set_f (mpq_ptr, mpf_srcptr);
+
+#define mpq_set_num __gmpq_set_num
+__GMP_DECLSPEC void mpq_set_num (mpq_ptr, mpz_srcptr);
+
+#define mpq_set_si __gmpq_set_si
+__GMP_DECLSPEC void mpq_set_si (mpq_ptr, signed long int, unsigned long int);
+
+#define mpq_set_str __gmpq_set_str
+__GMP_DECLSPEC int mpq_set_str (mpq_ptr, const char *, int);
+
+#define mpq_set_ui __gmpq_set_ui
+__GMP_DECLSPEC void mpq_set_ui (mpq_ptr, unsigned long int, unsigned long int);
+
+#define mpq_set_z __gmpq_set_z
+__GMP_DECLSPEC void mpq_set_z (mpq_ptr, mpz_srcptr);
+
+#define mpq_sub __gmpq_sub
+__GMP_DECLSPEC void mpq_sub (mpq_ptr, mpq_srcptr, mpq_srcptr);
+
+#define mpq_swap __gmpq_swap
+__GMP_DECLSPEC void mpq_swap (mpq_ptr, mpq_ptr) __GMP_NOTHROW;
+
+
+/**************** Float (i.e. F) routines.  ****************/
+
+#define mpf_abs __gmpf_abs
+__GMP_DECLSPEC void mpf_abs (mpf_ptr, mpf_srcptr);
+
+#define mpf_add __gmpf_add
+__GMP_DECLSPEC void mpf_add (mpf_ptr, mpf_srcptr, mpf_srcptr);
+
+#define mpf_add_ui __gmpf_add_ui
+__GMP_DECLSPEC void mpf_add_ui (mpf_ptr, mpf_srcptr, unsigned long int);
+#define mpf_ceil __gmpf_ceil
+__GMP_DECLSPEC void mpf_ceil (mpf_ptr, mpf_srcptr);
+
+#define mpf_clear __gmpf_clear
+__GMP_DECLSPEC void mpf_clear (mpf_ptr);
+
+#define mpf_clears __gmpf_clears
+__GMP_DECLSPEC void mpf_clears (mpf_ptr, ...);
+
+#define mpf_cmp __gmpf_cmp
+__GMP_DECLSPEC int mpf_cmp (mpf_srcptr, mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_cmp_z __gmpf_cmp_z
+__GMP_DECLSPEC int mpf_cmp_z (mpf_srcptr, mpz_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_cmp_d __gmpf_cmp_d
+__GMP_DECLSPEC int mpf_cmp_d (mpf_srcptr, double) __GMP_ATTRIBUTE_PURE;
+
+#define mpf_cmp_si __gmpf_cmp_si
+__GMP_DECLSPEC int mpf_cmp_si (mpf_srcptr, signed long int) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_cmp_ui __gmpf_cmp_ui
+__GMP_DECLSPEC int mpf_cmp_ui (mpf_srcptr, unsigned long int) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_div __gmpf_div
+__GMP_DECLSPEC void mpf_div (mpf_ptr, mpf_srcptr, mpf_srcptr);
+
+#define mpf_div_2exp __gmpf_div_2exp
+__GMP_DECLSPEC void mpf_div_2exp (mpf_ptr, mpf_srcptr, mp_bitcnt_t);
+
+#define mpf_div_ui __gmpf_div_ui
+__GMP_DECLSPEC void mpf_div_ui (mpf_ptr, mpf_srcptr, unsigned long int);
+
+#define mpf_dump __gmpf_dump
+__GMP_DECLSPEC void mpf_dump (mpf_srcptr);
+
+#define mpf_eq __gmpf_eq
+__GMP_DECLSPEC int mpf_eq (mpf_srcptr, mpf_srcptr, mp_bitcnt_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpf_fits_sint_p __gmpf_fits_sint_p
+__GMP_DECLSPEC int mpf_fits_sint_p (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_fits_slong_p __gmpf_fits_slong_p
+__GMP_DECLSPEC int mpf_fits_slong_p (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_fits_sshort_p __gmpf_fits_sshort_p
+__GMP_DECLSPEC int mpf_fits_sshort_p (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_fits_uint_p __gmpf_fits_uint_p
+__GMP_DECLSPEC int mpf_fits_uint_p (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_fits_ulong_p __gmpf_fits_ulong_p
+__GMP_DECLSPEC int mpf_fits_ulong_p (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_fits_ushort_p __gmpf_fits_ushort_p
+__GMP_DECLSPEC int mpf_fits_ushort_p (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_floor __gmpf_floor
+__GMP_DECLSPEC void mpf_floor (mpf_ptr, mpf_srcptr);
+
+#define mpf_get_d __gmpf_get_d
+__GMP_DECLSPEC double mpf_get_d (mpf_srcptr) __GMP_ATTRIBUTE_PURE;
+
+#define mpf_get_d_2exp __gmpf_get_d_2exp
+__GMP_DECLSPEC double mpf_get_d_2exp (signed long int *, mpf_srcptr);
+
+#define mpf_get_default_prec __gmpf_get_default_prec
+__GMP_DECLSPEC mp_bitcnt_t mpf_get_default_prec (void) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_get_prec __gmpf_get_prec
+__GMP_DECLSPEC mp_bitcnt_t mpf_get_prec (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_get_si __gmpf_get_si
+__GMP_DECLSPEC long mpf_get_si (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_get_str __gmpf_get_str
+__GMP_DECLSPEC char *mpf_get_str (char *, mp_exp_t *, int, size_t, mpf_srcptr);
+
+#define mpf_get_ui __gmpf_get_ui
+__GMP_DECLSPEC unsigned long mpf_get_ui (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_init __gmpf_init
+__GMP_DECLSPEC void mpf_init (mpf_ptr);
+
+#define mpf_init2 __gmpf_init2
+__GMP_DECLSPEC void mpf_init2 (mpf_ptr, mp_bitcnt_t);
+
+#define mpf_inits __gmpf_inits
+__GMP_DECLSPEC void mpf_inits (mpf_ptr, ...);
+
+#define mpf_init_set __gmpf_init_set
+__GMP_DECLSPEC void mpf_init_set (mpf_ptr, mpf_srcptr);
+
+#define mpf_init_set_d __gmpf_init_set_d
+__GMP_DECLSPEC void mpf_init_set_d (mpf_ptr, double);
+
+#define mpf_init_set_si __gmpf_init_set_si
+__GMP_DECLSPEC void mpf_init_set_si (mpf_ptr, signed long int);
+
+#define mpf_init_set_str __gmpf_init_set_str
+__GMP_DECLSPEC int mpf_init_set_str (mpf_ptr, const char *, int);
+
+#define mpf_init_set_ui __gmpf_init_set_ui
+__GMP_DECLSPEC void mpf_init_set_ui (mpf_ptr, unsigned long int);
+
+#define mpf_inp_str __gmpf_inp_str
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC size_t mpf_inp_str (mpf_ptr, FILE *, int);
+#endif
+
+#define mpf_integer_p __gmpf_integer_p
+__GMP_DECLSPEC int mpf_integer_p (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_mul __gmpf_mul
+__GMP_DECLSPEC void mpf_mul (mpf_ptr, mpf_srcptr, mpf_srcptr);
+
+#define mpf_mul_2exp __gmpf_mul_2exp
+__GMP_DECLSPEC void mpf_mul_2exp (mpf_ptr, mpf_srcptr, mp_bitcnt_t);
+
+#define mpf_mul_ui __gmpf_mul_ui
+__GMP_DECLSPEC void mpf_mul_ui (mpf_ptr, mpf_srcptr, unsigned long int);
+
+#define mpf_neg __gmpf_neg
+__GMP_DECLSPEC void mpf_neg (mpf_ptr, mpf_srcptr);
+
+#define mpf_out_str __gmpf_out_str
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC size_t mpf_out_str (FILE *, int, size_t, mpf_srcptr);
+#endif
+
+#define mpf_pow_ui __gmpf_pow_ui
+__GMP_DECLSPEC void mpf_pow_ui (mpf_ptr, mpf_srcptr, unsigned long int);
+
+#define mpf_random2 __gmpf_random2
+__GMP_DECLSPEC void mpf_random2 (mpf_ptr, mp_size_t, mp_exp_t);
+
+#define mpf_reldiff __gmpf_reldiff
+__GMP_DECLSPEC void mpf_reldiff (mpf_ptr, mpf_srcptr, mpf_srcptr);
+
+#define mpf_set __gmpf_set
+__GMP_DECLSPEC void mpf_set (mpf_ptr, mpf_srcptr);
+
+#define mpf_set_d __gmpf_set_d
+__GMP_DECLSPEC void mpf_set_d (mpf_ptr, double);
+
+#define mpf_set_default_prec __gmpf_set_default_prec
+__GMP_DECLSPEC void mpf_set_default_prec (mp_bitcnt_t) __GMP_NOTHROW;
+
+#define mpf_set_prec __gmpf_set_prec
+__GMP_DECLSPEC void mpf_set_prec (mpf_ptr, mp_bitcnt_t);
+
+#define mpf_set_prec_raw __gmpf_set_prec_raw
+__GMP_DECLSPEC void mpf_set_prec_raw (mpf_ptr, mp_bitcnt_t) __GMP_NOTHROW;
+
+#define mpf_set_q __gmpf_set_q
+__GMP_DECLSPEC void mpf_set_q (mpf_ptr, mpq_srcptr);
+
+#define mpf_set_si __gmpf_set_si
+__GMP_DECLSPEC void mpf_set_si (mpf_ptr, signed long int);
+
+#define mpf_set_str __gmpf_set_str
+__GMP_DECLSPEC int mpf_set_str (mpf_ptr, const char *, int);
+
+#define mpf_set_ui __gmpf_set_ui
+__GMP_DECLSPEC void mpf_set_ui (mpf_ptr, unsigned long int);
+
+#define mpf_set_z __gmpf_set_z
+__GMP_DECLSPEC void mpf_set_z (mpf_ptr, mpz_srcptr);
+
+#define mpf_size __gmpf_size
+__GMP_DECLSPEC size_t mpf_size (mpf_srcptr) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpf_sqrt __gmpf_sqrt
+__GMP_DECLSPEC void mpf_sqrt (mpf_ptr, mpf_srcptr);
+
+#define mpf_sqrt_ui __gmpf_sqrt_ui
+__GMP_DECLSPEC void mpf_sqrt_ui (mpf_ptr, unsigned long int);
+
+#define mpf_sub __gmpf_sub
+__GMP_DECLSPEC void mpf_sub (mpf_ptr, mpf_srcptr, mpf_srcptr);
+
+#define mpf_sub_ui __gmpf_sub_ui
+__GMP_DECLSPEC void mpf_sub_ui (mpf_ptr, mpf_srcptr, unsigned long int);
+
+#define mpf_swap __gmpf_swap
+__GMP_DECLSPEC void mpf_swap (mpf_ptr, mpf_ptr) __GMP_NOTHROW;
+
+#define mpf_trunc __gmpf_trunc
+__GMP_DECLSPEC void mpf_trunc (mpf_ptr, mpf_srcptr);
+
+#define mpf_ui_div __gmpf_ui_div
+__GMP_DECLSPEC void mpf_ui_div (mpf_ptr, unsigned long int, mpf_srcptr);
+
+#define mpf_ui_sub __gmpf_ui_sub
+__GMP_DECLSPEC void mpf_ui_sub (mpf_ptr, unsigned long int, mpf_srcptr);
+
+#define mpf_urandomb __gmpf_urandomb
+__GMP_DECLSPEC void mpf_urandomb (mpf_t, gmp_randstate_t, mp_bitcnt_t);
+
+
+/************ Low level positive-integer (i.e. N) routines.  ************/
+
+/* This is ugly, but we need to make user calls reach the prefixed function. */
+
+#define mpn_add __MPN(add)
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_add)
+__GMP_DECLSPEC mp_limb_t mpn_add (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+#endif
+
+#define mpn_add_1 __MPN(add_1)
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_add_1)
+__GMP_DECLSPEC mp_limb_t mpn_add_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t) __GMP_NOTHROW;
+#endif
+
+#define mpn_add_n __MPN(add_n)
+__GMP_DECLSPEC mp_limb_t mpn_add_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+
+#define mpn_addmul_1 __MPN(addmul_1)
+__GMP_DECLSPEC mp_limb_t mpn_addmul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_cmp __MPN(cmp)
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_cmp)
+__GMP_DECLSPEC int mpn_cmp (mp_srcptr, mp_srcptr, mp_size_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpn_zero_p __MPN(zero_p)
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_zero_p)
+__GMP_DECLSPEC int mpn_zero_p (mp_srcptr, mp_size_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpn_divexact_1 __MPN(divexact_1)
+__GMP_DECLSPEC void mpn_divexact_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_divexact_by3(dst,src,size) \
+  mpn_divexact_by3c (dst, src, size, __GMP_CAST (mp_limb_t, 0))
+
+#define mpn_divexact_by3c __MPN(divexact_by3c)
+__GMP_DECLSPEC mp_limb_t mpn_divexact_by3c (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_divmod_1(qp,np,nsize,dlimb) \
+  mpn_divrem_1 (qp, __GMP_CAST (mp_size_t, 0), np, nsize, dlimb)
+
+#define mpn_divrem __MPN(divrem)
+__GMP_DECLSPEC mp_limb_t mpn_divrem (mp_ptr, mp_size_t, mp_ptr, mp_size_t, mp_srcptr, mp_size_t);
+
+#define mpn_divrem_1 __MPN(divrem_1)
+__GMP_DECLSPEC mp_limb_t mpn_divrem_1 (mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_divrem_2 __MPN(divrem_2)
+__GMP_DECLSPEC mp_limb_t mpn_divrem_2 (mp_ptr, mp_size_t, mp_ptr, mp_size_t, mp_srcptr);
+
+#define mpn_div_qr_1 __MPN(div_qr_1)
+__GMP_DECLSPEC mp_limb_t mpn_div_qr_1 (mp_ptr, mp_limb_t *, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_div_qr_2 __MPN(div_qr_2)
+__GMP_DECLSPEC mp_limb_t mpn_div_qr_2 (mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+
+#define mpn_gcd __MPN(gcd)
+__GMP_DECLSPEC mp_size_t mpn_gcd (mp_ptr, mp_ptr, mp_size_t, mp_ptr, mp_size_t);
+
+#define mpn_gcd_11 __MPN(gcd_11)
+__GMP_DECLSPEC mp_limb_t mpn_gcd_11 (mp_limb_t, mp_limb_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_gcd_1 __MPN(gcd_1)
+__GMP_DECLSPEC mp_limb_t mpn_gcd_1 (mp_srcptr, mp_size_t, mp_limb_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_gcdext_1 __MPN(gcdext_1)
+__GMP_DECLSPEC mp_limb_t mpn_gcdext_1 (mp_limb_signed_t *, mp_limb_signed_t *, mp_limb_t, mp_limb_t);
+
+#define mpn_gcdext __MPN(gcdext)
+__GMP_DECLSPEC mp_size_t mpn_gcdext (mp_ptr, mp_ptr, mp_size_t *, mp_ptr, mp_size_t, mp_ptr, mp_size_t);
+
+#define mpn_get_str __MPN(get_str)
+__GMP_DECLSPEC size_t mpn_get_str (unsigned char *, int, mp_ptr, mp_size_t);
+
+#define mpn_hamdist __MPN(hamdist)
+__GMP_DECLSPEC mp_bitcnt_t mpn_hamdist (mp_srcptr, mp_srcptr, mp_size_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpn_lshift __MPN(lshift)
+__GMP_DECLSPEC mp_limb_t mpn_lshift (mp_ptr, mp_srcptr, mp_size_t, unsigned int);
+
+#define mpn_mod_1 __MPN(mod_1)
+__GMP_DECLSPEC mp_limb_t mpn_mod_1 (mp_srcptr, mp_size_t, mp_limb_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_mul __MPN(mul)
+__GMP_DECLSPEC mp_limb_t mpn_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+
+#define mpn_mul_1 __MPN(mul_1)
+__GMP_DECLSPEC mp_limb_t mpn_mul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_mul_n __MPN(mul_n)
+__GMP_DECLSPEC void mpn_mul_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+
+#define mpn_sqr __MPN(sqr)
+__GMP_DECLSPEC void mpn_sqr (mp_ptr, mp_srcptr, mp_size_t);
+
+#define mpn_neg __MPN(neg)
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_neg)
+__GMP_DECLSPEC mp_limb_t mpn_neg (mp_ptr, mp_srcptr, mp_size_t);
+#endif
+
+#define mpn_com __MPN(com)
+__GMP_DECLSPEC void mpn_com (mp_ptr, mp_srcptr, mp_size_t);
+
+#define mpn_perfect_square_p __MPN(perfect_square_p)
+__GMP_DECLSPEC int mpn_perfect_square_p (mp_srcptr, mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_perfect_power_p __MPN(perfect_power_p)
+__GMP_DECLSPEC int mpn_perfect_power_p (mp_srcptr, mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_popcount __MPN(popcount)
+__GMP_DECLSPEC mp_bitcnt_t mpn_popcount (mp_srcptr, mp_size_t) __GMP_NOTHROW __GMP_ATTRIBUTE_PURE;
+
+#define mpn_pow_1 __MPN(pow_1)
+__GMP_DECLSPEC mp_size_t mpn_pow_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_ptr);
+
+/* undocumented now, but retained here for upward compatibility */
+#define mpn_preinv_mod_1 __MPN(preinv_mod_1)
+__GMP_DECLSPEC mp_limb_t mpn_preinv_mod_1 (mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_random __MPN(random)
+__GMP_DECLSPEC void mpn_random (mp_ptr, mp_size_t);
+
+#define mpn_random2 __MPN(random2)
+__GMP_DECLSPEC void mpn_random2 (mp_ptr, mp_size_t);
+
+#define mpn_rshift __MPN(rshift)
+__GMP_DECLSPEC mp_limb_t mpn_rshift (mp_ptr, mp_srcptr, mp_size_t, unsigned int);
+
+#define mpn_scan0 __MPN(scan0)
+__GMP_DECLSPEC mp_bitcnt_t mpn_scan0 (mp_srcptr, mp_bitcnt_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_scan1 __MPN(scan1)
+__GMP_DECLSPEC mp_bitcnt_t mpn_scan1 (mp_srcptr, mp_bitcnt_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_set_str __MPN(set_str)
+__GMP_DECLSPEC mp_size_t mpn_set_str (mp_ptr, const unsigned char *, size_t, int);
+
+#define mpn_sizeinbase __MPN(sizeinbase)
+__GMP_DECLSPEC size_t mpn_sizeinbase (mp_srcptr, mp_size_t, int);
+
+#define mpn_sqrtrem __MPN(sqrtrem)
+__GMP_DECLSPEC mp_size_t mpn_sqrtrem (mp_ptr, mp_ptr, mp_srcptr, mp_size_t);
+
+#define mpn_sub __MPN(sub)
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_sub)
+__GMP_DECLSPEC mp_limb_t mpn_sub (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+#endif
+
+#define mpn_sub_1 __MPN(sub_1)
+#if __GMP_INLINE_PROTOTYPES || defined (__GMP_FORCE_mpn_sub_1)
+__GMP_DECLSPEC mp_limb_t mpn_sub_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t) __GMP_NOTHROW;
+#endif
+
+#define mpn_sub_n __MPN(sub_n)
+__GMP_DECLSPEC mp_limb_t mpn_sub_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+
+#define mpn_submul_1 __MPN(submul_1)
+__GMP_DECLSPEC mp_limb_t mpn_submul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_tdiv_qr __MPN(tdiv_qr)
+__GMP_DECLSPEC void mpn_tdiv_qr (mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+
+#define mpn_and_n __MPN(and_n)
+__GMP_DECLSPEC void mpn_and_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_andn_n __MPN(andn_n)
+__GMP_DECLSPEC void mpn_andn_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_nand_n __MPN(nand_n)
+__GMP_DECLSPEC void mpn_nand_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_ior_n __MPN(ior_n)
+__GMP_DECLSPEC void mpn_ior_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_iorn_n __MPN(iorn_n)
+__GMP_DECLSPEC void mpn_iorn_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_nior_n __MPN(nior_n)
+__GMP_DECLSPEC void mpn_nior_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_xor_n __MPN(xor_n)
+__GMP_DECLSPEC void mpn_xor_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_xnor_n __MPN(xnor_n)
+__GMP_DECLSPEC void mpn_xnor_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+
+#define mpn_copyi __MPN(copyi)
+__GMP_DECLSPEC void mpn_copyi (mp_ptr, mp_srcptr, mp_size_t);
+#define mpn_copyd __MPN(copyd)
+__GMP_DECLSPEC void mpn_copyd (mp_ptr, mp_srcptr, mp_size_t);
+#define mpn_zero __MPN(zero)
+__GMP_DECLSPEC void mpn_zero (mp_ptr, mp_size_t);
+
+#define mpn_cnd_add_n __MPN(cnd_add_n)
+__GMP_DECLSPEC mp_limb_t mpn_cnd_add_n (mp_limb_t, mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_cnd_sub_n __MPN(cnd_sub_n)
+__GMP_DECLSPEC mp_limb_t mpn_cnd_sub_n (mp_limb_t, mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+
+#define mpn_sec_add_1 __MPN(sec_add_1)
+__GMP_DECLSPEC mp_limb_t mpn_sec_add_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_ptr);
+#define mpn_sec_add_1_itch __MPN(sec_add_1_itch)
+__GMP_DECLSPEC mp_size_t mpn_sec_add_1_itch (mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_sec_sub_1 __MPN(sec_sub_1)
+__GMP_DECLSPEC mp_limb_t mpn_sec_sub_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_ptr);
+#define mpn_sec_sub_1_itch __MPN(sec_sub_1_itch)
+__GMP_DECLSPEC mp_size_t mpn_sec_sub_1_itch (mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_cnd_swap  __MPN(cnd_swap)
+__GMP_DECLSPEC void mpn_cnd_swap (mp_limb_t, volatile mp_limb_t *, volatile mp_limb_t *, mp_size_t);
+
+#define mpn_sec_mul __MPN(sec_mul)
+__GMP_DECLSPEC void mpn_sec_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+#define mpn_sec_mul_itch __MPN(sec_mul_itch)
+__GMP_DECLSPEC mp_size_t mpn_sec_mul_itch (mp_size_t, mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_sec_sqr __MPN(sec_sqr)
+__GMP_DECLSPEC void mpn_sec_sqr (mp_ptr, mp_srcptr, mp_size_t, mp_ptr);
+#define mpn_sec_sqr_itch __MPN(sec_sqr_itch)
+__GMP_DECLSPEC mp_size_t mpn_sec_sqr_itch (mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_sec_powm __MPN(sec_powm)
+__GMP_DECLSPEC void mpn_sec_powm (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_bitcnt_t, mp_srcptr, mp_size_t, mp_ptr);
+#define mpn_sec_powm_itch __MPN(sec_powm_itch)
+__GMP_DECLSPEC mp_size_t mpn_sec_powm_itch (mp_size_t, mp_bitcnt_t, mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_sec_tabselect __MPN(sec_tabselect)
+__GMP_DECLSPEC void mpn_sec_tabselect (volatile mp_limb_t *, volatile const mp_limb_t *, mp_size_t, mp_size_t, mp_size_t);
+
+#define mpn_sec_div_qr __MPN(sec_div_qr)
+__GMP_DECLSPEC mp_limb_t mpn_sec_div_qr (mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+#define mpn_sec_div_qr_itch __MPN(sec_div_qr_itch)
+__GMP_DECLSPEC mp_size_t mpn_sec_div_qr_itch (mp_size_t, mp_size_t) __GMP_ATTRIBUTE_PURE;
+#define mpn_sec_div_r __MPN(sec_div_r)
+__GMP_DECLSPEC void mpn_sec_div_r (mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+#define mpn_sec_div_r_itch __MPN(sec_div_r_itch)
+__GMP_DECLSPEC mp_size_t mpn_sec_div_r_itch (mp_size_t, mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_sec_invert __MPN(sec_invert)
+__GMP_DECLSPEC int mpn_sec_invert (mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_bitcnt_t, mp_ptr);
+#define mpn_sec_invert_itch __MPN(sec_invert_itch)
+__GMP_DECLSPEC mp_size_t mpn_sec_invert_itch (mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+
+/**************** mpz inlines ****************/
+
+/* The following are provided as inlines where possible, but always exist as
+   library functions too, for binary compatibility.
+
+   Within gmp itself this inlining generally isn't relied on, since it
+   doesn't get done for all compilers, whereas if something is worth
+   inlining then it's worth arranging always.
+
+   There are two styles of inlining here.  When the same bit of code is
+   wanted for the inline as for the library version, then __GMP_FORCE_foo
+   arranges for that code to be emitted and the __GMP_EXTERN_INLINE
+   directive suppressed, eg. mpz_fits_uint_p.  When a different bit of code
+   is wanted for the inline than for the library version, then
+   __GMP_FORCE_foo arranges the inline to be suppressed, eg. mpz_abs.  */
+
+#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpz_abs)
+__GMP_EXTERN_INLINE void
+mpz_abs (mpz_ptr __gmp_w, mpz_srcptr __gmp_u)
+{
+  if (__gmp_w != __gmp_u)
+    mpz_set (__gmp_w, __gmp_u);
+  __gmp_w->_mp_size = __GMP_ABS (__gmp_w->_mp_size);
+}
+#endif
+
+#if GMP_NAIL_BITS == 0
+#define __GMPZ_FITS_UTYPE_P(z,maxval)					\
+  mp_size_t  __gmp_n = z->_mp_size;					\
+  mp_ptr  __gmp_p = z->_mp_d;						\
+  return (__gmp_n == 0 || (__gmp_n == 1 && __gmp_p[0] <= maxval));
+#else
+#define __GMPZ_FITS_UTYPE_P(z,maxval)					\
+  mp_size_t  __gmp_n = z->_mp_size;					\
+  mp_ptr  __gmp_p = z->_mp_d;						\
+  return (__gmp_n == 0 || (__gmp_n == 1 && __gmp_p[0] <= maxval)	\
+	  || (__gmp_n == 2 && __gmp_p[1] <= ((mp_limb_t) maxval >> GMP_NUMB_BITS)));
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_fits_uint_p)
+#if ! defined (__GMP_FORCE_mpz_fits_uint_p)
+__GMP_EXTERN_INLINE
+#endif
+int
+mpz_fits_uint_p (mpz_srcptr __gmp_z) __GMP_NOTHROW
+{
+  __GMPZ_FITS_UTYPE_P (__gmp_z, UINT_MAX);
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_fits_ulong_p)
+#if ! defined (__GMP_FORCE_mpz_fits_ulong_p)
+__GMP_EXTERN_INLINE
+#endif
+int
+mpz_fits_ulong_p (mpz_srcptr __gmp_z) __GMP_NOTHROW
+{
+  __GMPZ_FITS_UTYPE_P (__gmp_z, ULONG_MAX);
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_fits_ushort_p)
+#if ! defined (__GMP_FORCE_mpz_fits_ushort_p)
+__GMP_EXTERN_INLINE
+#endif
+int
+mpz_fits_ushort_p (mpz_srcptr __gmp_z) __GMP_NOTHROW
+{
+  __GMPZ_FITS_UTYPE_P (__gmp_z, USHRT_MAX);
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_get_ui)
+#if ! defined (__GMP_FORCE_mpz_get_ui)
+__GMP_EXTERN_INLINE
+#endif
+unsigned long
+mpz_get_ui (mpz_srcptr __gmp_z) __GMP_NOTHROW
+{
+  mp_ptr __gmp_p = __gmp_z->_mp_d;
+  mp_size_t __gmp_n = __gmp_z->_mp_size;
+  mp_limb_t __gmp_l = __gmp_p[0];
+  /* This is a "#if" rather than a plain "if" so as to avoid gcc warnings
+     about "<< GMP_NUMB_BITS" exceeding the type size, and to avoid Borland
+     C++ 6.0 warnings about condition always true for something like
+     "ULONG_MAX < GMP_NUMB_MASK".  */
+#if GMP_NAIL_BITS == 0 || defined (_LONG_LONG_LIMB)
+  /* limb==long and no nails, or limb==longlong, one limb is enough */
+  return (__gmp_n != 0 ? __gmp_l : 0);
+#else
+  /* limb==long and nails, need two limbs when available */
+  __gmp_n = __GMP_ABS (__gmp_n);
+  if (__gmp_n <= 1)
+    return (__gmp_n != 0 ? __gmp_l : 0);
+  else
+    return __gmp_l + (__gmp_p[1] << GMP_NUMB_BITS);
+#endif
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_getlimbn)
+#if ! defined (__GMP_FORCE_mpz_getlimbn)
+__GMP_EXTERN_INLINE
+#endif
+mp_limb_t
+mpz_getlimbn (mpz_srcptr __gmp_z, mp_size_t __gmp_n) __GMP_NOTHROW
+{
+  mp_limb_t  __gmp_result = 0;
+  if (__GMP_LIKELY (__gmp_n >= 0 && __gmp_n < __GMP_ABS (__gmp_z->_mp_size)))
+    __gmp_result = __gmp_z->_mp_d[__gmp_n];
+  return __gmp_result;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpz_neg)
+__GMP_EXTERN_INLINE void
+mpz_neg (mpz_ptr __gmp_w, mpz_srcptr __gmp_u)
+{
+  if (__gmp_w != __gmp_u)
+    mpz_set (__gmp_w, __gmp_u);
+  __gmp_w->_mp_size = - __gmp_w->_mp_size;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_perfect_square_p)
+#if ! defined (__GMP_FORCE_mpz_perfect_square_p)
+__GMP_EXTERN_INLINE
+#endif
+int
+mpz_perfect_square_p (mpz_srcptr __gmp_a)
+{
+  mp_size_t __gmp_asize;
+  int       __gmp_result;
+
+  __gmp_asize = __gmp_a->_mp_size;
+  __gmp_result = (__gmp_asize >= 0);  /* zero is a square, negatives are not */
+  if (__GMP_LIKELY (__gmp_asize > 0))
+    __gmp_result = mpn_perfect_square_p (__gmp_a->_mp_d, __gmp_asize);
+  return __gmp_result;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_popcount)
+#if ! defined (__GMP_FORCE_mpz_popcount)
+__GMP_EXTERN_INLINE
+#endif
+mp_bitcnt_t
+mpz_popcount (mpz_srcptr __gmp_u) __GMP_NOTHROW
+{
+  mp_size_t      __gmp_usize;
+  mp_bitcnt_t    __gmp_result;
+
+  __gmp_usize = __gmp_u->_mp_size;
+  __gmp_result = (__gmp_usize < 0 ? ~ __GMP_CAST (mp_bitcnt_t, 0) : __GMP_CAST (mp_bitcnt_t, 0));
+  if (__GMP_LIKELY (__gmp_usize > 0))
+    __gmp_result =  mpn_popcount (__gmp_u->_mp_d, __gmp_usize);
+  return __gmp_result;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_set_q)
+#if ! defined (__GMP_FORCE_mpz_set_q)
+__GMP_EXTERN_INLINE
+#endif
+void
+mpz_set_q (mpz_ptr __gmp_w, mpq_srcptr __gmp_u)
+{
+  mpz_tdiv_q (__gmp_w, mpq_numref (__gmp_u), mpq_denref (__gmp_u));
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpz_size)
+#if ! defined (__GMP_FORCE_mpz_size)
+__GMP_EXTERN_INLINE
+#endif
+size_t
+mpz_size (mpz_srcptr __gmp_z) __GMP_NOTHROW
+{
+  return __GMP_ABS (__gmp_z->_mp_size);
+}
+#endif
+
+
+/**************** mpq inlines ****************/
+
+#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpq_abs)
+__GMP_EXTERN_INLINE void
+mpq_abs (mpq_ptr __gmp_w, mpq_srcptr __gmp_u)
+{
+  if (__gmp_w != __gmp_u)
+    mpq_set (__gmp_w, __gmp_u);
+  __gmp_w->_mp_num._mp_size = __GMP_ABS (__gmp_w->_mp_num._mp_size);
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) && ! defined (__GMP_FORCE_mpq_neg)
+__GMP_EXTERN_INLINE void
+mpq_neg (mpq_ptr __gmp_w, mpq_srcptr __gmp_u)
+{
+  if (__gmp_w != __gmp_u)
+    mpq_set (__gmp_w, __gmp_u);
+  __gmp_w->_mp_num._mp_size = - __gmp_w->_mp_num._mp_size;
+}
+#endif
+
+
+/**************** mpn inlines ****************/
+
+/* The comments with __GMPN_ADD_1 below apply here too.
+
+   The test for FUNCTION returning 0 should predict well.  If it's assumed
+   {yp,ysize} will usually have a random number of bits then the high limb
+   won't be full and a carry out will occur a good deal less than 50% of the
+   time.
+
+   ysize==0 isn't a documented feature, but is used internally in a few
+   places.
+
+   Producing cout last stops it using up a register during the main part of
+   the calculation, though gcc (as of 3.0) on an "if (mpn_add (...))"
+   doesn't seem able to move the true and false legs of the conditional up
+   to the two places cout is generated.  */
+
+#define __GMPN_AORS(cout, wp, xp, xsize, yp, ysize, FUNCTION, TEST)     \
+  do {                                                                  \
+    mp_size_t  __gmp_i;                                                 \
+    mp_limb_t  __gmp_x;                                                 \
+                                                                        \
+    /* ASSERT ((ysize) >= 0); */                                        \
+    /* ASSERT ((xsize) >= (ysize)); */                                  \
+    /* ASSERT (MPN_SAME_OR_SEPARATE2_P (wp, xsize, xp, xsize)); */      \
+    /* ASSERT (MPN_SAME_OR_SEPARATE2_P (wp, xsize, yp, ysize)); */      \
+                                                                        \
+    __gmp_i = (ysize);                                                  \
+    if (__gmp_i != 0)                                                   \
+      {                                                                 \
+        if (FUNCTION (wp, xp, yp, __gmp_i))                             \
+          {                                                             \
+            do                                                          \
+              {                                                         \
+                if (__gmp_i >= (xsize))                                 \
+                  {                                                     \
+                    (cout) = 1;                                         \
+                    goto __gmp_done;                                    \
+                  }                                                     \
+                __gmp_x = (xp)[__gmp_i];                                \
+              }                                                         \
+            while (TEST);                                               \
+          }                                                             \
+      }                                                                 \
+    if ((wp) != (xp))                                                   \
+      __GMPN_COPY_REST (wp, xp, xsize, __gmp_i);                        \
+    (cout) = 0;                                                         \
+  __gmp_done:                                                           \
+    ;                                                                   \
+  } while (0)
+
+#define __GMPN_ADD(cout, wp, xp, xsize, yp, ysize)              \
+  __GMPN_AORS (cout, wp, xp, xsize, yp, ysize, mpn_add_n,       \
+               (((wp)[__gmp_i++] = (__gmp_x + 1) & GMP_NUMB_MASK) == 0))
+#define __GMPN_SUB(cout, wp, xp, xsize, yp, ysize)              \
+  __GMPN_AORS (cout, wp, xp, xsize, yp, ysize, mpn_sub_n,       \
+               (((wp)[__gmp_i++] = (__gmp_x - 1) & GMP_NUMB_MASK), __gmp_x == 0))
+
+
+/* The use of __gmp_i indexing is designed to ensure a compile time src==dst
+   remains nice and clear to the compiler, so that __GMPN_COPY_REST can
+   disappear, and the load/add/store gets a chance to become a
+   read-modify-write on CISC CPUs.
+
+   Alternatives:
+
+   Using a pair of pointers instead of indexing would be possible, but gcc
+   isn't able to recognise compile-time src==dst in that case, even when the
+   pointers are incremented more or less together.  Other compilers would
+   very likely have similar difficulty.
+
+   gcc could use "if (__builtin_constant_p(src==dst) && src==dst)" or
+   similar to detect a compile-time src==dst.  This works nicely on gcc
+   2.95.x, it's not good on gcc 3.0 where __builtin_constant_p(p==p) seems
+   to be always false, for a pointer p.  But the current code form seems
+   good enough for src==dst anyway.
+
+   gcc on x86 as usual doesn't give particularly good flags handling for the
+   carry/borrow detection.  It's tempting to want some multi instruction asm
+   blocks to help it, and this was tried, but in truth there's only a few
+   instructions to save and any gain is all too easily lost by register
+   juggling setting up for the asm.  */
+
+#if GMP_NAIL_BITS == 0
+#define __GMPN_AORS_1(cout, dst, src, n, v, OP, CB)		\
+  do {								\
+    mp_size_t  __gmp_i;						\
+    mp_limb_t  __gmp_x, __gmp_r;                                \
+								\
+    /* ASSERT ((n) >= 1); */					\
+    /* ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, n)); */	\
+								\
+    __gmp_x = (src)[0];						\
+    __gmp_r = __gmp_x OP (v);                                   \
+    (dst)[0] = __gmp_r;						\
+    if (CB (__gmp_r, __gmp_x, (v)))                             \
+      {								\
+	(cout) = 1;						\
+	for (__gmp_i = 1; __gmp_i < (n);)                       \
+	  {							\
+	    __gmp_x = (src)[__gmp_i];                           \
+	    __gmp_r = __gmp_x OP 1;                             \
+	    (dst)[__gmp_i] = __gmp_r;                           \
+	    ++__gmp_i;						\
+	    if (!CB (__gmp_r, __gmp_x, 1))                      \
+	      {							\
+		if ((src) != (dst))				\
+		  __GMPN_COPY_REST (dst, src, n, __gmp_i);      \
+		(cout) = 0;					\
+		break;						\
+	      }							\
+	  }							\
+      }								\
+    else							\
+      {								\
+	if ((src) != (dst))					\
+	  __GMPN_COPY_REST (dst, src, n, 1);			\
+	(cout) = 0;						\
+      }								\
+  } while (0)
+#endif
+
+#if GMP_NAIL_BITS >= 1
+#define __GMPN_AORS_1(cout, dst, src, n, v, OP, CB)		\
+  do {								\
+    mp_size_t  __gmp_i;						\
+    mp_limb_t  __gmp_x, __gmp_r;				\
+								\
+    /* ASSERT ((n) >= 1); */					\
+    /* ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, n)); */	\
+								\
+    __gmp_x = (src)[0];						\
+    __gmp_r = __gmp_x OP (v);					\
+    (dst)[0] = __gmp_r & GMP_NUMB_MASK;				\
+    if (__gmp_r >> GMP_NUMB_BITS != 0)				\
+      {								\
+	(cout) = 1;						\
+	for (__gmp_i = 1; __gmp_i < (n);)			\
+	  {							\
+	    __gmp_x = (src)[__gmp_i];				\
+	    __gmp_r = __gmp_x OP 1;				\
+	    (dst)[__gmp_i] = __gmp_r & GMP_NUMB_MASK;		\
+	    ++__gmp_i;						\
+	    if (__gmp_r >> GMP_NUMB_BITS == 0)			\
+	      {							\
+		if ((src) != (dst))				\
+		  __GMPN_COPY_REST (dst, src, n, __gmp_i);	\
+		(cout) = 0;					\
+		break;						\
+	      }							\
+	  }							\
+      }								\
+    else							\
+      {								\
+	if ((src) != (dst))					\
+	  __GMPN_COPY_REST (dst, src, n, 1);			\
+	(cout) = 0;						\
+      }								\
+  } while (0)
+#endif
+
+#define __GMPN_ADDCB(r,x,y) ((r) < (y))
+#define __GMPN_SUBCB(r,x,y) ((x) < (y))
+
+#define __GMPN_ADD_1(cout, dst, src, n, v)	     \
+  __GMPN_AORS_1(cout, dst, src, n, v, +, __GMPN_ADDCB)
+#define __GMPN_SUB_1(cout, dst, src, n, v)	     \
+  __GMPN_AORS_1(cout, dst, src, n, v, -, __GMPN_SUBCB)
+
+
+/* Compare {xp,size} and {yp,size}, setting "result" to positive, zero or
+   negative.  size==0 is allowed.  On random data usually only one limb will
+   need to be examined to get a result, so it's worth having it inline.  */
+#define __GMPN_CMP(result, xp, yp, size)                                \
+  do {                                                                  \
+    mp_size_t  __gmp_i;                                                 \
+    mp_limb_t  __gmp_x, __gmp_y;                                        \
+                                                                        \
+    /* ASSERT ((size) >= 0); */                                         \
+                                                                        \
+    (result) = 0;                                                       \
+    __gmp_i = (size);                                                   \
+    while (--__gmp_i >= 0)                                              \
+      {                                                                 \
+        __gmp_x = (xp)[__gmp_i];                                        \
+        __gmp_y = (yp)[__gmp_i];                                        \
+        if (__gmp_x != __gmp_y)                                         \
+          {                                                             \
+            /* Cannot use __gmp_x - __gmp_y, may overflow an "int" */   \
+            (result) = (__gmp_x > __gmp_y ? 1 : -1);                    \
+            break;                                                      \
+          }                                                             \
+      }                                                                 \
+  } while (0)
+
+
+#if defined (__GMPN_COPY) && ! defined (__GMPN_COPY_REST)
+#define __GMPN_COPY_REST(dst, src, size, start)                 \
+  do {                                                          \
+    /* ASSERT ((start) >= 0); */                                \
+    /* ASSERT ((start) <= (size)); */                           \
+    __GMPN_COPY ((dst)+(start), (src)+(start), (size)-(start)); \
+  } while (0)
+#endif
+
+/* Copy {src,size} to {dst,size}, starting at "start".  This is designed to
+   keep the indexing dst[j] and src[j] nice and simple for __GMPN_ADD_1,
+   __GMPN_ADD, etc.  */
+#if ! defined (__GMPN_COPY_REST)
+#define __GMPN_COPY_REST(dst, src, size, start)                 \
+  do {                                                          \
+    mp_size_t __gmp_j;                                          \
+    /* ASSERT ((size) >= 0); */                                 \
+    /* ASSERT ((start) >= 0); */                                \
+    /* ASSERT ((start) <= (size)); */                           \
+    /* ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, size)); */     \
+    __GMP_CRAY_Pragma ("_CRI ivdep");                           \
+    for (__gmp_j = (start); __gmp_j < (size); __gmp_j++)        \
+      (dst)[__gmp_j] = (src)[__gmp_j];                          \
+  } while (0)
+#endif
+
+/* Enhancement: Use some of the smarter code from gmp-impl.h.  Maybe use
+   mpn_copyi if there's a native version, and if we don't mind demanding
+   binary compatibility for it (on targets which use it).  */
+
+#if ! defined (__GMPN_COPY)
+#define __GMPN_COPY(dst, src, size)   __GMPN_COPY_REST (dst, src, size, 0)
+#endif
+
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_add)
+#if ! defined (__GMP_FORCE_mpn_add)
+__GMP_EXTERN_INLINE
+#endif
+mp_limb_t
+mpn_add (mp_ptr __gmp_wp, mp_srcptr __gmp_xp, mp_size_t __gmp_xsize, mp_srcptr __gmp_yp, mp_size_t __gmp_ysize)
+{
+  mp_limb_t  __gmp_c;
+  __GMPN_ADD (__gmp_c, __gmp_wp, __gmp_xp, __gmp_xsize, __gmp_yp, __gmp_ysize);
+  return __gmp_c;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_add_1)
+#if ! defined (__GMP_FORCE_mpn_add_1)
+__GMP_EXTERN_INLINE
+#endif
+mp_limb_t
+mpn_add_1 (mp_ptr __gmp_dst, mp_srcptr __gmp_src, mp_size_t __gmp_size, mp_limb_t __gmp_n) __GMP_NOTHROW
+{
+  mp_limb_t  __gmp_c;
+  __GMPN_ADD_1 (__gmp_c, __gmp_dst, __gmp_src, __gmp_size, __gmp_n);
+  return __gmp_c;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_cmp)
+#if ! defined (__GMP_FORCE_mpn_cmp)
+__GMP_EXTERN_INLINE
+#endif
+int
+mpn_cmp (mp_srcptr __gmp_xp, mp_srcptr __gmp_yp, mp_size_t __gmp_size) __GMP_NOTHROW
+{
+  int __gmp_result;
+  __GMPN_CMP (__gmp_result, __gmp_xp, __gmp_yp, __gmp_size);
+  return __gmp_result;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_zero_p)
+#if ! defined (__GMP_FORCE_mpn_zero_p)
+__GMP_EXTERN_INLINE
+#endif
+int
+mpn_zero_p (mp_srcptr __gmp_p, mp_size_t __gmp_n) __GMP_NOTHROW
+{
+  /* if (__GMP_LIKELY (__gmp_n > 0)) */
+    do {
+      if (__gmp_p[--__gmp_n] != 0)
+	return 0;
+    } while (__gmp_n != 0);
+  return 1;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_sub)
+#if ! defined (__GMP_FORCE_mpn_sub)
+__GMP_EXTERN_INLINE
+#endif
+mp_limb_t
+mpn_sub (mp_ptr __gmp_wp, mp_srcptr __gmp_xp, mp_size_t __gmp_xsize, mp_srcptr __gmp_yp, mp_size_t __gmp_ysize)
+{
+  mp_limb_t  __gmp_c;
+  __GMPN_SUB (__gmp_c, __gmp_wp, __gmp_xp, __gmp_xsize, __gmp_yp, __gmp_ysize);
+  return __gmp_c;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_sub_1)
+#if ! defined (__GMP_FORCE_mpn_sub_1)
+__GMP_EXTERN_INLINE
+#endif
+mp_limb_t
+mpn_sub_1 (mp_ptr __gmp_dst, mp_srcptr __gmp_src, mp_size_t __gmp_size, mp_limb_t __gmp_n) __GMP_NOTHROW
+{
+  mp_limb_t  __gmp_c;
+  __GMPN_SUB_1 (__gmp_c, __gmp_dst, __gmp_src, __gmp_size, __gmp_n);
+  return __gmp_c;
+}
+#endif
+
+#if defined (__GMP_EXTERN_INLINE) || defined (__GMP_FORCE_mpn_neg)
+#if ! defined (__GMP_FORCE_mpn_neg)
+__GMP_EXTERN_INLINE
+#endif
+mp_limb_t
+mpn_neg (mp_ptr __gmp_rp, mp_srcptr __gmp_up, mp_size_t __gmp_n)
+{
+  while (*__gmp_up == 0) /* Low zero limbs are unchanged by negation. */
+    {
+      *__gmp_rp = 0;
+      if (!--__gmp_n) /* All zero */
+	return 0;
+      ++__gmp_up; ++__gmp_rp;
+    }
+
+  *__gmp_rp = (- *__gmp_up) & GMP_NUMB_MASK;
+
+  if (--__gmp_n) /* Higher limbs get complemented. */
+    mpn_com (++__gmp_rp, ++__gmp_up, __gmp_n);
+
+  return 1;
+}
+#endif
+
+#if defined (__cplusplus)
+}
+#endif
+
+
+/* Allow faster testing for negative, zero, and positive.  */
+#define mpz_sgn(Z) ((Z)->_mp_size < 0 ? -1 : (Z)->_mp_size > 0)
+#define mpf_sgn(F) ((F)->_mp_size < 0 ? -1 : (F)->_mp_size > 0)
+#define mpq_sgn(Q) ((Q)->_mp_num._mp_size < 0 ? -1 : (Q)->_mp_num._mp_size > 0)
+
+/* When using GCC, optimize certain common comparisons.  */
+#if defined (__GNUC__) && __GNUC__ >= 2
+#define mpz_cmp_ui(Z,UI) \
+  (__builtin_constant_p (UI) && (UI) == 0				\
+   ? mpz_sgn (Z) : _mpz_cmp_ui (Z,UI))
+#define mpz_cmp_si(Z,SI)						\
+  (__builtin_constant_p ((SI) >= 0) && (SI) >= 0			\
+   ? mpz_cmp_ui (Z, __GMP_CAST (unsigned long, SI))			\
+   : _mpz_cmp_si (Z,SI))
+#define mpq_cmp_ui(Q,NUI,DUI)					\
+  (__builtin_constant_p (NUI) && (NUI) == 0 ? mpq_sgn (Q)	\
+   : __builtin_constant_p ((NUI) == (DUI)) && (NUI) == (DUI)	\
+   ? mpz_cmp (mpq_numref (Q), mpq_denref (Q))			\
+   : _mpq_cmp_ui (Q,NUI,DUI))
+#define mpq_cmp_si(q,n,d)				\
+  (__builtin_constant_p ((n) >= 0) && (n) >= 0		\
+   ? mpq_cmp_ui (q, __GMP_CAST (unsigned long, n), d)	\
+   : _mpq_cmp_si (q, n, d))
+#else
+#define mpz_cmp_ui(Z,UI) _mpz_cmp_ui (Z,UI)
+#define mpz_cmp_si(Z,UI) _mpz_cmp_si (Z,UI)
+#define mpq_cmp_ui(Q,NUI,DUI) _mpq_cmp_ui (Q,NUI,DUI)
+#define mpq_cmp_si(q,n,d)  _mpq_cmp_si(q,n,d)
+#endif
+
+
+/* Using "&" rather than "&&" means these can come out branch-free.  Every
+   mpz_t has at least one limb allocated, so fetching the low limb is always
+   allowed.  */
+#define mpz_odd_p(z)   (((z)->_mp_size != 0) & __GMP_CAST (int, (z)->_mp_d[0]))
+#define mpz_even_p(z)  (! mpz_odd_p (z))
+
+
+/**************** C++ routines ****************/
+
+#ifdef __cplusplus
+__GMP_DECLSPEC_XX std::ostream& operator<< (std::ostream &, mpz_srcptr);
+__GMP_DECLSPEC_XX std::ostream& operator<< (std::ostream &, mpq_srcptr);
+__GMP_DECLSPEC_XX std::ostream& operator<< (std::ostream &, mpf_srcptr);
+__GMP_DECLSPEC_XX std::istream& operator>> (std::istream &, mpz_ptr);
+__GMP_DECLSPEC_XX std::istream& operator>> (std::istream &, mpq_ptr);
+__GMP_DECLSPEC_XX std::istream& operator>> (std::istream &, mpf_ptr);
+#endif
+
+
+/* Source-level compatibility with GMP 2 and earlier. */
+#define mpn_divmod(qp,np,nsize,dp,dsize) \
+  mpn_divrem (qp, __GMP_CAST (mp_size_t, 0), np, nsize, dp, dsize)
+
+/* Source-level compatibility with GMP 1.  */
+#define mpz_mdiv	mpz_fdiv_q
+#define mpz_mdivmod	mpz_fdiv_qr
+#define mpz_mmod	mpz_fdiv_r
+#define mpz_mdiv_ui	mpz_fdiv_q_ui
+#define mpz_mdivmod_ui(q,r,n,d) \
+  (((r) == 0) ? mpz_fdiv_q_ui (q,n,d) : mpz_fdiv_qr_ui (q,r,n,d))
+#define mpz_mmod_ui(r,n,d) \
+  (((r) == 0) ? mpz_fdiv_ui (n,d) : mpz_fdiv_r_ui (r,n,d))
+
+/* Useful synonyms, but not quite compatible with GMP 1.  */
+#define mpz_div		mpz_fdiv_q
+#define mpz_divmod	mpz_fdiv_qr
+#define mpz_div_ui	mpz_fdiv_q_ui
+#define mpz_divmod_ui	mpz_fdiv_qr_ui
+#define mpz_div_2exp	mpz_fdiv_q_2exp
+#define mpz_mod_2exp	mpz_fdiv_r_2exp
+
+enum
+{
+  GMP_ERROR_NONE = 0,
+  GMP_ERROR_UNSUPPORTED_ARGUMENT = 1,
+  GMP_ERROR_DIVISION_BY_ZERO = 2,
+  GMP_ERROR_SQRT_OF_NEGATIVE = 4,
+  GMP_ERROR_INVALID_ARGUMENT = 8
+};
+
+/* Define CC and CFLAGS which were used to build this version of GMP */
+#define __GMP_CC "@CC@"
+#define __GMP_CFLAGS "@CFLAGS@"
+
+/* Major version number is the value of __GNU_MP__ too, above. */
+#define __GNU_MP_VERSION            6
+#define __GNU_MP_VERSION_MINOR      2
+#define __GNU_MP_VERSION_PATCHLEVEL 0
+#define __GNU_MP_RELEASE (__GNU_MP_VERSION * 10000 + __GNU_MP_VERSION_MINOR * 100 + __GNU_MP_VERSION_PATCHLEVEL)
+
+#define __GMP_H__
+#endif /* __GMP_H__ */
diff --git a/third_party/gmp/gmp-impl.h b/third_party/gmp/gmp-impl.h
new file mode 100644
index 0000000..8192dac
--- /dev/null
+++ b/third_party/gmp/gmp-impl.h
@@ -0,0 +1,5278 @@
+/* Include file for internal GNU MP types and definitions.
+
+   THE CONTENTS OF THIS FILE ARE FOR INTERNAL USE AND ARE ALMOST CERTAIN TO
+   BE SUBJECT TO INCOMPATIBLE CHANGES IN FUTURE GNU MP RELEASES.
+
+Copyright 1991-2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+/* __GMP_DECLSPEC must be given on any global data that will be accessed
+   from outside libgmp, meaning from the test or development programs, or
+   from libgmpxx.  Failing to do this will result in an incorrect address
+   being used for the accesses.  On functions __GMP_DECLSPEC makes calls
+   from outside libgmp more efficient, but they'll still work fine without
+   it.  */
+
+
+#ifndef __GMP_IMPL_H__
+#define __GMP_IMPL_H__
+
+#if defined _CRAY
+#include <intrinsics.h>  /* for _popcnt */
+#endif
+
+/* For INT_MAX, etc. We used to avoid it because of a bug (on solaris,
+   gcc 2.95 under -mcpu=ultrasparc in ABI=32 ends up getting wrong
+   values (the ABI=64 values)), but it should be safe now.
+
+   On Cray vector systems, however, we need the system limits.h since sizes
+   of signed and unsigned types can differ there, depending on compiler
+   options (eg. -hnofastmd), making our SHRT_MAX etc expressions fail.  For
+   reference, int can be 46 or 64 bits, whereas uint is always 64 bits; and
+   short can be 24, 32, 46 or 64 bits, and different for ushort.  */
+
+#include <limits.h>
+
+/* For fat.h and other fat binary stuff.
+   No need for __GMP_ATTRIBUTE_PURE or __GMP_NOTHROW, since functions
+   declared this way are only used to set function pointers in __gmpn_cpuvec,
+   they're not called directly.  */
+#define DECL_add_n(name) \
+  __GMP_DECLSPEC mp_limb_t name (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)
+#define DECL_addlsh1_n(name) \
+  DECL_add_n (name)
+#define DECL_addlsh2_n(name) \
+  DECL_add_n (name)
+#define DECL_addmul_1(name) \
+  __GMP_DECLSPEC mp_limb_t name (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)
+#define DECL_addmul_2(name) \
+  __GMP_DECLSPEC mp_limb_t name (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr)
+#define DECL_bdiv_dbm1c(name) \
+  __GMP_DECLSPEC mp_limb_t name (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t)
+#define DECL_cnd_add_n(name) \
+  __GMP_DECLSPEC mp_limb_t name (mp_limb_t, mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)
+#define DECL_cnd_sub_n(name) \
+  __GMP_DECLSPEC mp_limb_t name (mp_limb_t, mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)
+#define DECL_com(name) \
+  __GMP_DECLSPEC void name (mp_ptr, mp_srcptr, mp_size_t)
+#define DECL_copyd(name) \
+  __GMP_DECLSPEC void name (mp_ptr, mp_srcptr, mp_size_t)
+#define DECL_copyi(name) \
+  DECL_copyd (name)
+#define DECL_divexact_1(name) \
+  __GMP_DECLSPEC void name (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)
+#define DECL_divexact_by3c(name) \
+  __GMP_DECLSPEC mp_limb_t name (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)
+#define DECL_divrem_1(name) \
+  __GMP_DECLSPEC mp_limb_t name (mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t)
+#define DECL_gcd_11(name) \
+  __GMP_DECLSPEC mp_limb_t name (mp_limb_t, mp_limb_t)
+#define DECL_lshift(name) \
+  __GMP_DECLSPEC mp_limb_t name (mp_ptr, mp_srcptr, mp_size_t, unsigned)
+#define DECL_lshiftc(name) \
+  DECL_lshift (name)
+#define DECL_mod_1(name) \
+  __GMP_DECLSPEC mp_limb_t name (mp_srcptr, mp_size_t, mp_limb_t)
+#define DECL_mod_1_1p(name) \
+  __GMP_DECLSPEC mp_limb_t name (mp_srcptr, mp_size_t, mp_limb_t, const mp_limb_t [])
+#define DECL_mod_1_1p_cps(name) \
+  __GMP_DECLSPEC void name (mp_limb_t cps[], mp_limb_t b)
+#define DECL_mod_1s_2p(name) \
+  DECL_mod_1_1p (name)
+#define DECL_mod_1s_2p_cps(name) \
+  DECL_mod_1_1p_cps (name)
+#define DECL_mod_1s_4p(name) \
+  DECL_mod_1_1p (name)
+#define DECL_mod_1s_4p_cps(name) \
+  DECL_mod_1_1p_cps (name)
+#define DECL_mod_34lsub1(name) \
+  __GMP_DECLSPEC mp_limb_t name (mp_srcptr, mp_size_t)
+#define DECL_modexact_1c_odd(name) \
+  __GMP_DECLSPEC mp_limb_t name (mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t)
+#define DECL_mul_1(name) \
+  DECL_addmul_1 (name)
+#define DECL_mul_basecase(name) \
+  __GMP_DECLSPEC void name (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t)
+#define DECL_mullo_basecase(name) \
+  __GMP_DECLSPEC void name (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)
+#define DECL_preinv_divrem_1(name) \
+  __GMP_DECLSPEC mp_limb_t name (mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t, int)
+#define DECL_preinv_mod_1(name) \
+  __GMP_DECLSPEC mp_limb_t name (mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t)
+#define DECL_redc_1(name) \
+  __GMP_DECLSPEC mp_limb_t name (mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_limb_t)
+#define DECL_redc_2(name) \
+  __GMP_DECLSPEC mp_limb_t name (mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_srcptr)
+#define DECL_rshift(name) \
+  DECL_lshift (name)
+#define DECL_sqr_basecase(name) \
+  __GMP_DECLSPEC void name (mp_ptr, mp_srcptr, mp_size_t)
+#define DECL_sub_n(name) \
+  DECL_add_n (name)
+#define DECL_sublsh1_n(name) \
+  DECL_add_n (name)
+#define DECL_submul_1(name) \
+  DECL_addmul_1 (name)
+
+#if ! defined (__GMP_WITHIN_CONFIGURE)
+#include "config.h"
+#include "gmp.h"
+#include "gmp-mparam.h"
+#include "fib_table.h"
+#include "fac_table.h"
+#include "mp_bases.h"
+#if WANT_FAT_BINARY
+#include "fat.h"
+#endif
+#endif
+
+#if HAVE_INTTYPES_H      /* for uint_least32_t */
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+#  include <stdint.h>
+# endif
+#endif
+
+#ifdef __cplusplus
+#include <cstring>  /* for strlen */
+#include <string>   /* for std::string */
+#endif
+
+
+#ifndef WANT_TMP_DEBUG  /* for TMP_ALLOC_LIMBS_2 and others */
+#define WANT_TMP_DEBUG 0
+#endif
+
+/* The following tries to get a good version of alloca.  The tests are
+   adapted from autoconf AC_FUNC_ALLOCA, with a couple of additions.
+   Whether this succeeds is tested by GMP_FUNC_ALLOCA and HAVE_ALLOCA will
+   be setup appropriately.
+
+   ifndef alloca - a cpp define might already exist.
+       glibc <stdlib.h> includes <alloca.h> which uses GCC __builtin_alloca.
+       HP cc +Olibcalls adds a #define of alloca to __builtin_alloca.
+
+   GCC __builtin_alloca - preferred whenever available.
+
+   _AIX pragma - IBM compilers need a #pragma in "each module that needs to
+       use alloca".  Pragma indented to protect pre-ANSI cpp's.  _IBMR2 was
+       used in past versions of GMP, retained still in case it matters.
+
+       The autoconf manual says this pragma needs to be at the start of a C
+       file, apart from comments and preprocessor directives.  Is that true?
+       xlc on aix 4.xxx doesn't seem to mind it being after prototypes etc
+       from gmp.h.
+*/
+
+#ifndef alloca
+# ifdef __GNUC__
+#  define alloca __builtin_alloca
+# else
+#  ifdef __DECC
+#   define alloca(x) __ALLOCA(x)
+#  else
+#   ifdef _MSC_VER
+#    include <malloc.h>
+#    define alloca _alloca
+#   else
+#    if HAVE_ALLOCA_H
+#     include <alloca.h>
+#    else
+#     if defined (_AIX) || defined (_IBMR2)
+ #pragma alloca
+#     else
+       char *alloca ();
+#     endif
+#    endif
+#   endif
+#  endif
+# endif
+#endif
+
+
+/* if not provided by gmp-mparam.h */
+#ifndef GMP_LIMB_BYTES
+#define GMP_LIMB_BYTES  SIZEOF_MP_LIMB_T
+#endif
+#ifndef GMP_LIMB_BITS
+#define GMP_LIMB_BITS  (8 * SIZEOF_MP_LIMB_T)
+#endif
+
+#define BITS_PER_ULONG  (8 * SIZEOF_UNSIGNED_LONG)
+
+
+/* gmp_uint_least32_t is an unsigned integer type with at least 32 bits. */
+#if HAVE_UINT_LEAST32_T
+typedef uint_least32_t      gmp_uint_least32_t;
+#else
+#if SIZEOF_UNSIGNED_SHORT >= 4
+typedef unsigned short      gmp_uint_least32_t;
+#else
+#if SIZEOF_UNSIGNED >= 4
+typedef unsigned            gmp_uint_least32_t;
+#else
+typedef unsigned long       gmp_uint_least32_t;
+#endif
+#endif
+#endif
+
+
+/* gmp_intptr_t, for pointer to integer casts */
+#if HAVE_INTPTR_T
+typedef intptr_t            gmp_intptr_t;
+#else /* fallback */
+typedef size_t              gmp_intptr_t;
+#endif
+
+
+/* pre-inverse types for truncating division and modulo */
+typedef struct {mp_limb_t inv32;} gmp_pi1_t;
+typedef struct {mp_limb_t inv21, inv32, inv53;} gmp_pi2_t;
+
+
+/* "const" basically means a function does nothing but examine its arguments
+   and give a return value, it doesn't read or write any memory (neither
+   global nor pointed to by arguments), and has no other side-effects.  This
+   is more restrictive than "pure".  See info node "(gcc)Function
+   Attributes".  __GMP_NO_ATTRIBUTE_CONST_PURE lets tune/common.c etc turn
+   this off when trying to write timing loops.  */
+#if HAVE_ATTRIBUTE_CONST && ! defined (__GMP_NO_ATTRIBUTE_CONST_PURE)
+#define ATTRIBUTE_CONST  __attribute__ ((const))
+#else
+#define ATTRIBUTE_CONST
+#endif
+
+#if HAVE_ATTRIBUTE_NORETURN
+#define ATTRIBUTE_NORETURN  __attribute__ ((noreturn))
+#else
+#define ATTRIBUTE_NORETURN
+#endif
+
+/* "malloc" means a function behaves like malloc in that the pointer it
+   returns doesn't alias anything.  */
+#if HAVE_ATTRIBUTE_MALLOC
+#define ATTRIBUTE_MALLOC  __attribute__ ((malloc))
+#else
+#define ATTRIBUTE_MALLOC
+#endif
+
+
+#if ! HAVE_STRCHR
+#define strchr(s,c)  index(s,c)
+#endif
+
+#if ! HAVE_MEMSET
+#define memset(p, c, n)			\
+  do {					\
+    ASSERT ((n) >= 0);			\
+    char *__memset__p = (p);		\
+    int	 __i;				\
+    for (__i = 0; __i < (n); __i++)	\
+      __memset__p[__i] = (c);		\
+  } while (0)
+#endif
+
+/* va_copy is standard in C99, and gcc provides __va_copy when in strict C89
+   mode.  Falling back to a memcpy will give maximum portability, since it
+   works no matter whether va_list is a pointer, struct or array.  */
+#if ! defined (va_copy) && defined (__va_copy)
+#define va_copy(dst,src)  __va_copy(dst,src)
+#endif
+#if ! defined (va_copy)
+#define va_copy(dst,src) \
+  do { memcpy (&(dst), &(src), sizeof (va_list)); } while (0)
+#endif
+
+
+/* HAVE_HOST_CPU_alpha_CIX is 1 on an alpha with the CIX instructions
+   (ie. ctlz, ctpop, cttz).  */
+#if HAVE_HOST_CPU_alphaev67 || HAVE_HOST_CPU_alphaev68  \
+  || HAVE_HOST_CPU_alphaev7
+#define HAVE_HOST_CPU_alpha_CIX 1
+#endif
+
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+
+/* Usage: TMP_DECL;
+	  TMP_MARK;
+	  ptr = TMP_ALLOC (bytes);
+	  TMP_FREE;
+
+   Small allocations should use TMP_SALLOC, big allocations should use
+   TMP_BALLOC.  Allocations that might be small or big should use TMP_ALLOC.
+
+   Functions that use just TMP_SALLOC should use TMP_SDECL, TMP_SMARK, and
+   TMP_SFREE.
+
+   TMP_DECL just declares a variable, but might be empty and so must be last
+   in a list of variables.  TMP_MARK must be done before any TMP_ALLOC.
+   TMP_ALLOC(0) is not allowed.  TMP_FREE doesn't need to be done if a
+   TMP_MARK was made, but then no TMP_ALLOCs.  */
+
+/* The alignment in bytes, used for TMP_ALLOCed blocks, when alloca or
+   __gmp_allocate_func doesn't already determine it.  */
+union tmp_align_t {
+  mp_limb_t  l;
+  double     d;
+  char       *p;
+};
+#define __TMP_ALIGN  sizeof (union tmp_align_t)
+
+/* Return "a" rounded upwards to a multiple of "m", if it isn't already.
+   "a" must be an unsigned type.
+   This is designed for use with a compile-time constant "m".
+   The POW2 case is expected to be usual, and gcc 3.0 and up recognises
+   "(-(8*n))%8" or the like is always zero, which means the rounding up in
+   the WANT_TMP_NOTREENTRANT version of TMP_ALLOC below will be a noop.  */
+#define ROUND_UP_MULTIPLE(a,m)          \
+  (POW2_P(m) ? (a) + (-(a))%(m)         \
+   : (a)+(m)-1 - (((a)+(m)-1) % (m)))
+
+#if defined (WANT_TMP_ALLOCA) || defined (WANT_TMP_REENTRANT)
+struct tmp_reentrant_t {
+  struct tmp_reentrant_t  *next;
+  size_t		  size;	  /* bytes, including header */
+};
+__GMP_DECLSPEC void *__gmp_tmp_reentrant_alloc (struct tmp_reentrant_t **, size_t) ATTRIBUTE_MALLOC;
+__GMP_DECLSPEC void  __gmp_tmp_reentrant_free (struct tmp_reentrant_t *);
+#endif
+
+#if WANT_TMP_ALLOCA
+#define TMP_SDECL
+#define TMP_DECL		struct tmp_reentrant_t *__tmp_marker
+#define TMP_SMARK
+#define TMP_MARK		__tmp_marker = 0
+#define TMP_SALLOC(n)		alloca(n)
+#define TMP_BALLOC(n)		__gmp_tmp_reentrant_alloc (&__tmp_marker, n)
+/* The peculiar stack allocation limit here is chosen for efficient asm.  */
+#define TMP_ALLOC(n)							\
+  (LIKELY ((n) <= 0x7f00) ? TMP_SALLOC(n) : TMP_BALLOC(n))
+#define TMP_SFREE
+#define TMP_FREE							\
+  do {									\
+    if (UNLIKELY (__tmp_marker != 0))					\
+      __gmp_tmp_reentrant_free (__tmp_marker);				\
+  } while (0)
+#endif
+
+#if WANT_TMP_REENTRANT
+#define TMP_SDECL		TMP_DECL
+#define TMP_DECL		struct tmp_reentrant_t *__tmp_marker
+#define TMP_SMARK		TMP_MARK
+#define TMP_MARK		__tmp_marker = 0
+#define TMP_SALLOC(n)		TMP_ALLOC(n)
+#define TMP_BALLOC(n)		TMP_ALLOC(n)
+#define TMP_ALLOC(n)		__gmp_tmp_reentrant_alloc (&__tmp_marker, n)
+#define TMP_SFREE		TMP_FREE
+#define TMP_FREE		__gmp_tmp_reentrant_free (__tmp_marker)
+#endif
+
+#if WANT_TMP_NOTREENTRANT
+struct tmp_marker
+{
+  struct tmp_stack *which_chunk;
+  void *alloc_point;
+};
+__GMP_DECLSPEC void *__gmp_tmp_alloc (unsigned long) ATTRIBUTE_MALLOC;
+__GMP_DECLSPEC void __gmp_tmp_mark (struct tmp_marker *);
+__GMP_DECLSPEC void __gmp_tmp_free (struct tmp_marker *);
+#define TMP_SDECL		TMP_DECL
+#define TMP_DECL		struct tmp_marker __tmp_marker
+#define TMP_SMARK		TMP_MARK
+#define TMP_MARK		__gmp_tmp_mark (&__tmp_marker)
+#define TMP_SALLOC(n)		TMP_ALLOC(n)
+#define TMP_BALLOC(n)		TMP_ALLOC(n)
+#define TMP_ALLOC(n)							\
+  __gmp_tmp_alloc (ROUND_UP_MULTIPLE ((unsigned long) (n), __TMP_ALIGN))
+#define TMP_SFREE		TMP_FREE
+#define TMP_FREE		__gmp_tmp_free (&__tmp_marker)
+#endif
+
+#if WANT_TMP_DEBUG
+/* See tal-debug.c for some comments. */
+struct tmp_debug_t {
+  struct tmp_debug_entry_t  *list;
+  const char                *file;
+  int                       line;
+};
+struct tmp_debug_entry_t {
+  struct tmp_debug_entry_t  *next;
+  void                      *block;
+  size_t                    size;
+};
+__GMP_DECLSPEC void  __gmp_tmp_debug_mark (const char *, int, struct tmp_debug_t **,
+					   struct tmp_debug_t *,
+					   const char *, const char *);
+__GMP_DECLSPEC void *__gmp_tmp_debug_alloc (const char *, int, int,
+					    struct tmp_debug_t **, const char *,
+					    size_t) ATTRIBUTE_MALLOC;
+__GMP_DECLSPEC void  __gmp_tmp_debug_free (const char *, int, int,
+					   struct tmp_debug_t **,
+					   const char *, const char *);
+#define TMP_SDECL TMP_DECL_NAME(__tmp_xmarker, "__tmp_marker")
+#define TMP_DECL TMP_DECL_NAME(__tmp_xmarker, "__tmp_marker")
+#define TMP_SMARK TMP_MARK_NAME(__tmp_xmarker, "__tmp_marker")
+#define TMP_MARK TMP_MARK_NAME(__tmp_xmarker, "__tmp_marker")
+#define TMP_SFREE TMP_FREE_NAME(__tmp_xmarker, "__tmp_marker")
+#define TMP_FREE TMP_FREE_NAME(__tmp_xmarker, "__tmp_marker")
+/* The marker variable is designed to provoke an uninitialized variable
+   warning from the compiler if TMP_FREE is used without a TMP_MARK.
+   __tmp_marker_inscope does the same for TMP_ALLOC.  Runtime tests pick
+   these things up too.  */
+#define TMP_DECL_NAME(marker, marker_name)				\
+  int marker;								\
+  int __tmp_marker_inscope;						\
+  const char *__tmp_marker_name = marker_name;				\
+  struct tmp_debug_t  __tmp_marker_struct;				\
+  /* don't demand NULL, just cast a zero */				\
+  struct tmp_debug_t  *__tmp_marker = (struct tmp_debug_t *) 0
+#define TMP_MARK_NAME(marker, marker_name)				\
+  do {									\
+    marker = 1;								\
+    __tmp_marker_inscope = 1;						\
+    __gmp_tmp_debug_mark  (ASSERT_FILE, ASSERT_LINE,			\
+			   &__tmp_marker, &__tmp_marker_struct,		\
+			   __tmp_marker_name, marker_name);		\
+  } while (0)
+#define TMP_SALLOC(n)		TMP_ALLOC(n)
+#define TMP_BALLOC(n)		TMP_ALLOC(n)
+#define TMP_ALLOC(size)							\
+  __gmp_tmp_debug_alloc (ASSERT_FILE, ASSERT_LINE,			\
+			 __tmp_marker_inscope,				\
+			 &__tmp_marker, __tmp_marker_name, size)
+#define TMP_FREE_NAME(marker, marker_name)				\
+  do {									\
+    __gmp_tmp_debug_free  (ASSERT_FILE, ASSERT_LINE,			\
+			   marker, &__tmp_marker,			\
+			   __tmp_marker_name, marker_name);		\
+  } while (0)
+#endif /* WANT_TMP_DEBUG */
+
+
+/* Allocating various types. */
+#define TMP_ALLOC_TYPE(n,type)  ((type *) TMP_ALLOC ((n) * sizeof (type)))
+#define TMP_SALLOC_TYPE(n,type) ((type *) TMP_SALLOC ((n) * sizeof (type)))
+#define TMP_BALLOC_TYPE(n,type) ((type *) TMP_BALLOC ((n) * sizeof (type)))
+#define TMP_ALLOC_LIMBS(n)      TMP_ALLOC_TYPE(n,mp_limb_t)
+#define TMP_SALLOC_LIMBS(n)     TMP_SALLOC_TYPE(n,mp_limb_t)
+#define TMP_BALLOC_LIMBS(n)     TMP_BALLOC_TYPE(n,mp_limb_t)
+#define TMP_ALLOC_MP_PTRS(n)    TMP_ALLOC_TYPE(n,mp_ptr)
+#define TMP_SALLOC_MP_PTRS(n)   TMP_SALLOC_TYPE(n,mp_ptr)
+#define TMP_BALLOC_MP_PTRS(n)   TMP_BALLOC_TYPE(n,mp_ptr)
+
+/* It's more efficient to allocate one block than many.  This is certainly
+   true of the malloc methods, but it can even be true of alloca if that
+   involves copying a chunk of stack (various RISCs), or a call to a stack
+   bounds check (mingw).  In any case, when debugging keep separate blocks
+   so a redzoning malloc debugger can protect each individually.  */
+#define TMP_ALLOC_LIMBS_2(xp,xsize, yp,ysize)				\
+  do {									\
+    if (WANT_TMP_DEBUG)							\
+      {									\
+	(xp) = TMP_ALLOC_LIMBS (xsize);					\
+	(yp) = TMP_ALLOC_LIMBS (ysize);					\
+      }									\
+    else								\
+      {									\
+	(xp) = TMP_ALLOC_LIMBS ((xsize) + (ysize));			\
+	(yp) = (xp) + (xsize);						\
+      }									\
+  } while (0)
+#define TMP_ALLOC_LIMBS_3(xp,xsize, yp,ysize, zp,zsize)			\
+  do {									\
+    if (WANT_TMP_DEBUG)							\
+      {									\
+	(xp) = TMP_ALLOC_LIMBS (xsize);					\
+	(yp) = TMP_ALLOC_LIMBS (ysize);					\
+	(zp) = TMP_ALLOC_LIMBS (zsize);					\
+      }									\
+    else								\
+      {									\
+	(xp) = TMP_ALLOC_LIMBS ((xsize) + (ysize) + (zsize));		\
+	(yp) = (xp) + (xsize);						\
+	(zp) = (yp) + (ysize);						\
+      }									\
+  } while (0)
+
+/* From gmp.h, nicer names for internal use. */
+#define CRAY_Pragma(str)               __GMP_CRAY_Pragma(str)
+#define MPN_CMP(result, xp, yp, size)  __GMPN_CMP(result, xp, yp, size)
+#define LIKELY(cond)                   __GMP_LIKELY(cond)
+#define UNLIKELY(cond)                 __GMP_UNLIKELY(cond)
+
+#define ABS(x) ((x) >= 0 ? (x) : -(x))
+#define NEG_CAST(T,x) (- (__GMP_CAST (T, (x) + 1) - 1))
+#define ABS_CAST(T,x) ((x) >= 0 ? __GMP_CAST (T, x) : NEG_CAST (T,x))
+#undef MIN
+#define MIN(l,o) ((l) < (o) ? (l) : (o))
+#undef MAX
+#define MAX(h,i) ((h) > (i) ? (h) : (i))
+#define numberof(x)  (sizeof (x) / sizeof ((x)[0]))
+
+/* Field access macros.  */
+#define SIZ(x) ((x)->_mp_size)
+#define ABSIZ(x) ABS (SIZ (x))
+#define PTR(x) ((x)->_mp_d)
+#define EXP(x) ((x)->_mp_exp)
+#define PREC(x) ((x)->_mp_prec)
+#define ALLOC(x) ((x)->_mp_alloc)
+#define NUM(x) mpq_numref(x)
+#define DEN(x) mpq_denref(x)
+
+/* n-1 inverts any low zeros and the lowest one bit.  If n&(n-1) leaves zero
+   then that lowest one bit must have been the only bit set.  n==0 will
+   return true though, so avoid that.  */
+#define POW2_P(n)  (((n) & ((n) - 1)) == 0)
+
+/* This is intended for constant THRESHOLDs only, where the compiler
+   can completely fold the result.  */
+#define LOG2C(n) \
+ (((n) >=    0x1) + ((n) >=    0x2) + ((n) >=    0x4) + ((n) >=    0x8) + \
+  ((n) >=   0x10) + ((n) >=   0x20) + ((n) >=   0x40) + ((n) >=   0x80) + \
+  ((n) >=  0x100) + ((n) >=  0x200) + ((n) >=  0x400) + ((n) >=  0x800) + \
+  ((n) >= 0x1000) + ((n) >= 0x2000) + ((n) >= 0x4000) + ((n) >= 0x8000))
+
+#define MP_LIMB_T_MAX      (~ (mp_limb_t) 0)
+
+/* Must cast ULONG_MAX etc to unsigned long etc, since they might not be
+   unsigned on a K&R compiler.  In particular the HP-UX 10 bundled K&R cc
+   treats the plain decimal values in <limits.h> as signed.  */
+#define ULONG_HIGHBIT      (ULONG_MAX ^ ((unsigned long) ULONG_MAX >> 1))
+#define UINT_HIGHBIT       (UINT_MAX ^ ((unsigned) UINT_MAX >> 1))
+#define USHRT_HIGHBIT      (USHRT_MAX ^ ((unsigned short) USHRT_MAX >> 1))
+#define GMP_LIMB_HIGHBIT  (MP_LIMB_T_MAX ^ (MP_LIMB_T_MAX >> 1))
+
+#if __GMP_MP_SIZE_T_INT
+#define MP_SIZE_T_MAX      INT_MAX
+#define MP_SIZE_T_MIN      INT_MIN
+#else
+#define MP_SIZE_T_MAX      LONG_MAX
+#define MP_SIZE_T_MIN      LONG_MIN
+#endif
+
+/* mp_exp_t is the same as mp_size_t */
+#define MP_EXP_T_MAX   MP_SIZE_T_MAX
+#define MP_EXP_T_MIN   MP_SIZE_T_MIN
+
+#define LONG_HIGHBIT       LONG_MIN
+#define INT_HIGHBIT        INT_MIN
+#define SHRT_HIGHBIT       SHRT_MIN
+
+
+#define GMP_NUMB_HIGHBIT  (CNST_LIMB(1) << (GMP_NUMB_BITS-1))
+
+#if GMP_NAIL_BITS == 0
+#define GMP_NAIL_LOWBIT   CNST_LIMB(0)
+#else
+#define GMP_NAIL_LOWBIT   (CNST_LIMB(1) << GMP_NUMB_BITS)
+#endif
+
+#if GMP_NAIL_BITS != 0
+/* Set various *_THRESHOLD values to be used for nails.  Thus we avoid using
+   code that has not yet been qualified.  */
+
+#undef  DC_DIV_QR_THRESHOLD
+#define DC_DIV_QR_THRESHOLD              50
+
+#undef DIVREM_1_NORM_THRESHOLD
+#undef DIVREM_1_UNNORM_THRESHOLD
+#undef MOD_1_NORM_THRESHOLD
+#undef MOD_1_UNNORM_THRESHOLD
+#undef USE_PREINV_DIVREM_1
+#undef DIVREM_2_THRESHOLD
+#undef DIVEXACT_1_THRESHOLD
+#define DIVREM_1_NORM_THRESHOLD           MP_SIZE_T_MAX  /* no preinv */
+#define DIVREM_1_UNNORM_THRESHOLD         MP_SIZE_T_MAX  /* no preinv */
+#define MOD_1_NORM_THRESHOLD              MP_SIZE_T_MAX  /* no preinv */
+#define MOD_1_UNNORM_THRESHOLD            MP_SIZE_T_MAX  /* no preinv */
+#define USE_PREINV_DIVREM_1               0  /* no preinv */
+#define DIVREM_2_THRESHOLD                MP_SIZE_T_MAX  /* no preinv */
+
+/* mpn/generic/mul_fft.c is not nails-capable. */
+#undef  MUL_FFT_THRESHOLD
+#undef  SQR_FFT_THRESHOLD
+#define MUL_FFT_THRESHOLD                MP_SIZE_T_MAX
+#define SQR_FFT_THRESHOLD                MP_SIZE_T_MAX
+#endif
+
+/* Swap macros. */
+
+#define MP_LIMB_T_SWAP(x, y)						\
+  do {									\
+    mp_limb_t __mp_limb_t_swap__tmp = (x);				\
+    (x) = (y);								\
+    (y) = __mp_limb_t_swap__tmp;					\
+  } while (0)
+#define MP_SIZE_T_SWAP(x, y)						\
+  do {									\
+    mp_size_t __mp_size_t_swap__tmp = (x);				\
+    (x) = (y);								\
+    (y) = __mp_size_t_swap__tmp;					\
+  } while (0)
+
+#define MP_PTR_SWAP(x, y)						\
+  do {									\
+    mp_ptr __mp_ptr_swap__tmp = (x);					\
+    (x) = (y);								\
+    (y) = __mp_ptr_swap__tmp;						\
+  } while (0)
+#define MP_SRCPTR_SWAP(x, y)						\
+  do {									\
+    mp_srcptr __mp_srcptr_swap__tmp = (x);				\
+    (x) = (y);								\
+    (y) = __mp_srcptr_swap__tmp;					\
+  } while (0)
+
+#define MPN_PTR_SWAP(xp,xs, yp,ys)					\
+  do {									\
+    MP_PTR_SWAP (xp, yp);						\
+    MP_SIZE_T_SWAP (xs, ys);						\
+  } while(0)
+#define MPN_SRCPTR_SWAP(xp,xs, yp,ys)					\
+  do {									\
+    MP_SRCPTR_SWAP (xp, yp);						\
+    MP_SIZE_T_SWAP (xs, ys);						\
+  } while(0)
+
+#define MPZ_PTR_SWAP(x, y)						\
+  do {									\
+    mpz_ptr __mpz_ptr_swap__tmp = (x);					\
+    (x) = (y);								\
+    (y) = __mpz_ptr_swap__tmp;						\
+  } while (0)
+#define MPZ_SRCPTR_SWAP(x, y)						\
+  do {									\
+    mpz_srcptr __mpz_srcptr_swap__tmp = (x);				\
+    (x) = (y);								\
+    (y) = __mpz_srcptr_swap__tmp;					\
+  } while (0)
+
+#define MPQ_PTR_SWAP(x, y)						\
+  do {                                                                  \
+    mpq_ptr __mpq_ptr_swap__tmp = (x);					\
+    (x) = (y);                                                          \
+    (y) = __mpq_ptr_swap__tmp;						\
+  } while (0)
+#define MPQ_SRCPTR_SWAP(x, y)                                           \
+  do {                                                                  \
+    mpq_srcptr __mpq_srcptr_swap__tmp = (x);                            \
+    (x) = (y);                                                          \
+    (y) = __mpq_srcptr_swap__tmp;                                       \
+  } while (0)
+
+
+/* Enhancement: __gmp_allocate_func could have "__attribute__ ((malloc))",
+   but current gcc (3.0) doesn't seem to support that.  */
+__GMP_DECLSPEC extern void * (*__gmp_allocate_func) (size_t);
+__GMP_DECLSPEC extern void * (*__gmp_reallocate_func) (void *, size_t, size_t);
+__GMP_DECLSPEC extern void   (*__gmp_free_func) (void *, size_t);
+
+__GMP_DECLSPEC void *__gmp_default_allocate (size_t);
+__GMP_DECLSPEC void *__gmp_default_reallocate (void *, size_t, size_t);
+__GMP_DECLSPEC void __gmp_default_free (void *, size_t);
+
+#define __GMP_ALLOCATE_FUNC_TYPE(n,type) \
+  ((type *) (*__gmp_allocate_func) ((n) * sizeof (type)))
+#define __GMP_ALLOCATE_FUNC_LIMBS(n)   __GMP_ALLOCATE_FUNC_TYPE (n, mp_limb_t)
+
+#define __GMP_REALLOCATE_FUNC_TYPE(p, old_size, new_size, type)		\
+  ((type *) (*__gmp_reallocate_func)					\
+   (p, (old_size) * sizeof (type), (new_size) * sizeof (type)))
+#define __GMP_REALLOCATE_FUNC_LIMBS(p, old_size, new_size)		\
+  __GMP_REALLOCATE_FUNC_TYPE(p, old_size, new_size, mp_limb_t)
+
+#define __GMP_FREE_FUNC_TYPE(p,n,type) (*__gmp_free_func) (p, (n) * sizeof (type))
+#define __GMP_FREE_FUNC_LIMBS(p,n)     __GMP_FREE_FUNC_TYPE (p, n, mp_limb_t)
+
+#define __GMP_REALLOCATE_FUNC_MAYBE(ptr, oldsize, newsize)		\
+  do {									\
+    if ((oldsize) != (newsize))						\
+      (ptr) = (*__gmp_reallocate_func) (ptr, oldsize, newsize);		\
+  } while (0)
+
+#define __GMP_REALLOCATE_FUNC_MAYBE_TYPE(ptr, oldsize, newsize, type)	\
+  do {									\
+    if ((oldsize) != (newsize))						\
+      (ptr) = (type *) (*__gmp_reallocate_func)				\
+	(ptr, (oldsize) * sizeof (type), (newsize) * sizeof (type));	\
+  } while (0)
+
+
+/* Dummy for non-gcc, code involving it will go dead. */
+#if ! defined (__GNUC__) || __GNUC__ < 2
+#define __builtin_constant_p(x)   0
+#endif
+
+
+/* In gcc 2.96 and up on i386, tail calls are optimized to jumps if the
+   stack usage is compatible.  __attribute__ ((regparm (N))) helps by
+   putting leading parameters in registers, avoiding extra stack.
+
+   regparm cannot be used with calls going through the PLT, because the
+   binding code there may clobber the registers (%eax, %edx, %ecx) used for
+   the regparm parameters.  Calls to local (ie. static) functions could
+   still use this, if we cared to differentiate locals and globals.
+
+   On athlon-unknown-freebsd4.9 with gcc 3.3.3, regparm cannot be used with
+   -p or -pg profiling, since that version of gcc doesn't realize the
+   .mcount calls will clobber the parameter registers.  Other systems are
+   ok, like debian with glibc 2.3.2 (mcount doesn't clobber), but we don't
+   bother to try to detect this.  regparm is only an optimization so we just
+   disable it when profiling (profiling being a slowdown anyway).  */
+
+#if HAVE_HOST_CPU_FAMILY_x86 && __GMP_GNUC_PREREQ (2,96) && ! defined (PIC) \
+  && ! WANT_PROFILING_PROF && ! WANT_PROFILING_GPROF
+#define USE_LEADING_REGPARM 1
+#else
+#define USE_LEADING_REGPARM 0
+#endif
+
+/* Macros for altering parameter order according to regparm usage. */
+#if USE_LEADING_REGPARM
+#define REGPARM_2_1(a,b,x)    x,a,b
+#define REGPARM_3_1(a,b,c,x)  x,a,b,c
+#define REGPARM_ATTR(n) __attribute__ ((regparm (n)))
+#else
+#define REGPARM_2_1(a,b,x)    a,b,x
+#define REGPARM_3_1(a,b,c,x)  a,b,c,x
+#define REGPARM_ATTR(n)
+#endif
+
+
+/* ASM_L gives a local label for a gcc asm block, for use when temporary
+   local labels like "1:" might not be available, which is the case for
+   instance on the x86s (the SCO assembler doesn't support them).
+
+   The label generated is made unique by including "%=" which is a unique
+   number for each insn.  This ensures the same name can be used in multiple
+   asm blocks, perhaps via a macro.  Since jumps between asm blocks are not
+   allowed there's no need for a label to be usable outside a single
+   block.  */
+
+#define ASM_L(name)  LSYM_PREFIX "asm_%=_" #name
+
+
+#if defined (__GNUC__) && HAVE_HOST_CPU_FAMILY_x86
+#if 0
+/* FIXME: Check that these actually improve things.
+   FIXME: Need a cld after each std.
+   FIXME: Can't have inputs in clobbered registers, must describe them as
+   dummy outputs, and add volatile. */
+#define MPN_COPY_INCR(DST, SRC, N)					\
+  __asm__ ("cld\n\trep\n\tmovsl" : :					\
+	   "D" (DST), "S" (SRC), "c" (N) :				\
+	   "cx", "di", "si", "memory")
+#define MPN_COPY_DECR(DST, SRC, N)					\
+  __asm__ ("std\n\trep\n\tmovsl" : :					\
+	   "D" ((DST) + (N) - 1), "S" ((SRC) + (N) - 1), "c" (N) :	\
+	   "cx", "di", "si", "memory")
+#endif
+#endif
+
+
+__GMP_DECLSPEC void __gmpz_aorsmul_1 (REGPARM_3_1 (mpz_ptr, mpz_srcptr, mp_limb_t, mp_size_t)) REGPARM_ATTR(1);
+#define mpz_aorsmul_1(w,u,v,sub)  __gmpz_aorsmul_1 (REGPARM_3_1 (w, u, v, sub))
+
+#define mpz_n_pow_ui __gmpz_n_pow_ui
+__GMP_DECLSPEC void    mpz_n_pow_ui (mpz_ptr, mp_srcptr, mp_size_t, unsigned long);
+
+
+#define mpn_addmul_1c __MPN(addmul_1c)
+__GMP_DECLSPEC mp_limb_t mpn_addmul_1c (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t);
+
+#ifndef mpn_addmul_2  /* if not done with cpuvec in a fat binary */
+#define mpn_addmul_2 __MPN(addmul_2)
+__GMP_DECLSPEC mp_limb_t mpn_addmul_2 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+#endif
+
+#define mpn_addmul_3 __MPN(addmul_3)
+__GMP_DECLSPEC mp_limb_t mpn_addmul_3 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+
+#define mpn_addmul_4 __MPN(addmul_4)
+__GMP_DECLSPEC mp_limb_t mpn_addmul_4 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+
+#define mpn_addmul_5 __MPN(addmul_5)
+__GMP_DECLSPEC mp_limb_t mpn_addmul_5 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+
+#define mpn_addmul_6 __MPN(addmul_6)
+__GMP_DECLSPEC mp_limb_t mpn_addmul_6 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+
+#define mpn_addmul_7 __MPN(addmul_7)
+__GMP_DECLSPEC mp_limb_t mpn_addmul_7 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+
+#define mpn_addmul_8 __MPN(addmul_8)
+__GMP_DECLSPEC mp_limb_t mpn_addmul_8 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+
+/* Alternative entry point in mpn_addmul_2 for the benefit of mpn_sqr_basecase.  */
+#define mpn_addmul_2s __MPN(addmul_2s)
+__GMP_DECLSPEC mp_limb_t mpn_addmul_2s (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+
+/* Override mpn_addlsh1_n, mpn_addlsh2_n, mpn_sublsh1_n, etc with mpn_addlsh_n,
+   etc when !HAVE_NATIVE the former but HAVE_NATIVE_ the latter.  Similarly,
+   override foo_ip1 functions with foo.  We then lie and say these macros
+   represent native functions, but leave a trace by using the value 2 rather
+   than 1.  */
+
+#if HAVE_NATIVE_mpn_addlsh_n && ! HAVE_NATIVE_mpn_addlsh1_n
+#define mpn_addlsh1_n(a,b,c,d)          mpn_addlsh_n(a,b,c,d,1)
+#define HAVE_NATIVE_mpn_addlsh1_n       2
+#endif
+
+#if HAVE_NATIVE_mpn_addlsh_nc && ! HAVE_NATIVE_mpn_addlsh1_nc
+#define mpn_addlsh1_nc(a,b,c,d,x)       mpn_addlsh_nc(a,b,c,d,1,x)
+#define HAVE_NATIVE_mpn_addlsh1_nc      2
+#endif
+
+#if HAVE_NATIVE_mpn_addlsh1_n && ! HAVE_NATIVE_mpn_addlsh1_n_ip1
+#define mpn_addlsh1_n_ip1(a,b,n)        mpn_addlsh1_n(a,a,b,n)
+#define HAVE_NATIVE_mpn_addlsh1_n_ip1   2
+#endif
+
+#if HAVE_NATIVE_mpn_addlsh1_nc && ! HAVE_NATIVE_mpn_addlsh1_nc_ip1
+#define mpn_addlsh1_nc_ip1(a,b,n,c)     mpn_addlsh1_nc(a,a,b,n,c)
+#define HAVE_NATIVE_mpn_addlsh1_nc_ip1  2
+#endif
+
+#if HAVE_NATIVE_mpn_addlsh_n && ! HAVE_NATIVE_mpn_addlsh2_n
+#define mpn_addlsh2_n(a,b,c,d)          mpn_addlsh_n(a,b,c,d,2)
+#define HAVE_NATIVE_mpn_addlsh2_n       2
+#endif
+
+#if HAVE_NATIVE_mpn_addlsh_nc && ! HAVE_NATIVE_mpn_addlsh2_nc
+#define mpn_addlsh2_nc(a,b,c,d,x)       mpn_addlsh_nc(a,b,c,d,2,x)
+#define HAVE_NATIVE_mpn_addlsh2_nc      2
+#endif
+
+#if HAVE_NATIVE_mpn_addlsh2_n && ! HAVE_NATIVE_mpn_addlsh2_n_ip1
+#define mpn_addlsh2_n_ip1(a,b,n)        mpn_addlsh2_n(a,a,b,n)
+#define HAVE_NATIVE_mpn_addlsh2_n_ip1   2
+#endif
+
+#if HAVE_NATIVE_mpn_addlsh2_nc && ! HAVE_NATIVE_mpn_addlsh2_nc_ip1
+#define mpn_addlsh2_nc_ip1(a,b,n,c)     mpn_addlsh2_nc(a,a,b,n,c)
+#define HAVE_NATIVE_mpn_addlsh2_nc_ip1  2
+#endif
+
+#if HAVE_NATIVE_mpn_sublsh_n && ! HAVE_NATIVE_mpn_sublsh1_n
+#define mpn_sublsh1_n(a,b,c,d)          mpn_sublsh_n(a,b,c,d,1)
+#define HAVE_NATIVE_mpn_sublsh1_n       2
+#endif
+
+#if HAVE_NATIVE_mpn_sublsh_nc && ! HAVE_NATIVE_mpn_sublsh1_nc
+#define mpn_sublsh1_nc(a,b,c,d,x)       mpn_sublsh_nc(a,b,c,d,1,x)
+#define HAVE_NATIVE_mpn_sublsh1_nc      2
+#endif
+
+#if HAVE_NATIVE_mpn_sublsh1_n && ! HAVE_NATIVE_mpn_sublsh1_n_ip1
+#define mpn_sublsh1_n_ip1(a,b,n)        mpn_sublsh1_n(a,a,b,n)
+#define HAVE_NATIVE_mpn_sublsh1_n_ip1   2
+#endif
+
+#if HAVE_NATIVE_mpn_sublsh1_nc && ! HAVE_NATIVE_mpn_sublsh1_nc_ip1
+#define mpn_sublsh1_nc_ip1(a,b,n,c)     mpn_sublsh1_nc(a,a,b,n,c)
+#define HAVE_NATIVE_mpn_sublsh1_nc_ip1  2
+#endif
+
+#if HAVE_NATIVE_mpn_sublsh_n && ! HAVE_NATIVE_mpn_sublsh2_n
+#define mpn_sublsh2_n(a,b,c,d)          mpn_sublsh_n(a,b,c,d,2)
+#define HAVE_NATIVE_mpn_sublsh2_n       2
+#endif
+
+#if HAVE_NATIVE_mpn_sublsh_nc && ! HAVE_NATIVE_mpn_sublsh2_nc
+#define mpn_sublsh2_nc(a,b,c,d,x)       mpn_sublsh_nc(a,b,c,d,2,x)
+#define HAVE_NATIVE_mpn_sublsh2_nc      2
+#endif
+
+#if HAVE_NATIVE_mpn_sublsh2_n && ! HAVE_NATIVE_mpn_sublsh2_n_ip1
+#define mpn_sublsh2_n_ip1(a,b,n)        mpn_sublsh2_n(a,a,b,n)
+#define HAVE_NATIVE_mpn_sublsh2_n_ip1   2
+#endif
+
+#if HAVE_NATIVE_mpn_sublsh2_nc && ! HAVE_NATIVE_mpn_sublsh2_nc_ip1
+#define mpn_sublsh2_nc_ip1(a,b,n,c)     mpn_sublsh2_nc(a,a,b,n,c)
+#define HAVE_NATIVE_mpn_sublsh2_nc_ip1  2
+#endif
+
+#if HAVE_NATIVE_mpn_rsblsh_n && ! HAVE_NATIVE_mpn_rsblsh1_n
+#define mpn_rsblsh1_n(a,b,c,d)          mpn_rsblsh_n(a,b,c,d,1)
+#define HAVE_NATIVE_mpn_rsblsh1_n       2
+#endif
+
+#if HAVE_NATIVE_mpn_rsblsh_nc && ! HAVE_NATIVE_mpn_rsblsh1_nc
+#define mpn_rsblsh1_nc(a,b,c,d,x)       mpn_rsblsh_nc(a,b,c,d,1,x)
+#define HAVE_NATIVE_mpn_rsblsh1_nc      2
+#endif
+
+#if HAVE_NATIVE_mpn_rsblsh1_n && ! HAVE_NATIVE_mpn_rsblsh1_n_ip1
+#define mpn_rsblsh1_n_ip1(a,b,n)        mpn_rsblsh1_n(a,a,b,n)
+#define HAVE_NATIVE_mpn_rsblsh1_n_ip1   2
+#endif
+
+#if HAVE_NATIVE_mpn_rsblsh1_nc && ! HAVE_NATIVE_mpn_rsblsh1_nc_ip1
+#define mpn_rsblsh1_nc_ip1(a,b,n,c)     mpn_rsblsh1_nc(a,a,b,n,c)
+#define HAVE_NATIVE_mpn_rsblsh1_nc_ip1  2
+#endif
+
+#if HAVE_NATIVE_mpn_rsblsh_n && ! HAVE_NATIVE_mpn_rsblsh2_n
+#define mpn_rsblsh2_n(a,b,c,d)          mpn_rsblsh_n(a,b,c,d,2)
+#define HAVE_NATIVE_mpn_rsblsh2_n       2
+#endif
+
+#if HAVE_NATIVE_mpn_rsblsh_nc && ! HAVE_NATIVE_mpn_rsblsh2_nc
+#define mpn_rsblsh2_nc(a,b,c,d,x)       mpn_rsblsh_nc(a,b,c,d,2,x)
+#define HAVE_NATIVE_mpn_rsblsh2_nc      2
+#endif
+
+#if HAVE_NATIVE_mpn_rsblsh2_n && ! HAVE_NATIVE_mpn_rsblsh2_n_ip1
+#define mpn_rsblsh2_n_ip1(a,b,n)        mpn_rsblsh2_n(a,a,b,n)
+#define HAVE_NATIVE_mpn_rsblsh2_n_ip1   2
+#endif
+
+#if HAVE_NATIVE_mpn_rsblsh2_nc && ! HAVE_NATIVE_mpn_rsblsh2_nc_ip1
+#define mpn_rsblsh2_nc_ip1(a,b,n,c)     mpn_rsblsh2_nc(a,a,b,n,c)
+#define HAVE_NATIVE_mpn_rsblsh2_nc_ip1  2
+#endif
+
+
+#ifndef mpn_addlsh1_n
+#define mpn_addlsh1_n __MPN(addlsh1_n)
+__GMP_DECLSPEC mp_limb_t mpn_addlsh1_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#endif
+#ifndef mpn_addlsh1_nc
+#define mpn_addlsh1_nc __MPN(addlsh1_nc)
+__GMP_DECLSPEC mp_limb_t mpn_addlsh1_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+#endif
+#ifndef mpn_addlsh1_n_ip1
+#define mpn_addlsh1_n_ip1 __MPN(addlsh1_n_ip1)
+__GMP_DECLSPEC mp_limb_t mpn_addlsh1_n_ip1 (mp_ptr, mp_srcptr, mp_size_t);
+#endif
+#ifndef mpn_addlsh1_nc_ip1
+#define mpn_addlsh1_nc_ip1 __MPN(addlsh1_nc_ip1)
+__GMP_DECLSPEC mp_limb_t mpn_addlsh1_nc_ip1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+#endif
+
+#ifndef mpn_addlsh2_n
+#define mpn_addlsh2_n __MPN(addlsh2_n)
+__GMP_DECLSPEC mp_limb_t mpn_addlsh2_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#endif
+#ifndef mpn_addlsh2_nc
+#define mpn_addlsh2_nc __MPN(addlsh2_nc)
+__GMP_DECLSPEC mp_limb_t mpn_addlsh2_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+#endif
+#ifndef mpn_addlsh2_n_ip1
+#define mpn_addlsh2_n_ip1 __MPN(addlsh2_n_ip1)
+__GMP_DECLSPEC mp_limb_t mpn_addlsh2_n_ip1 (mp_ptr, mp_srcptr, mp_size_t);
+#endif
+#ifndef mpn_addlsh2_nc_ip1
+#define mpn_addlsh2_nc_ip1 __MPN(addlsh2_nc_ip1)
+__GMP_DECLSPEC mp_limb_t mpn_addlsh2_nc_ip1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+#endif
+
+#ifndef mpn_addlsh_n
+#define mpn_addlsh_n __MPN(addlsh_n)
+__GMP_DECLSPEC mp_limb_t mpn_addlsh_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, unsigned int);
+#endif
+#ifndef mpn_addlsh_nc
+#define mpn_addlsh_nc __MPN(addlsh_nc)
+__GMP_DECLSPEC mp_limb_t mpn_addlsh_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, unsigned int, mp_limb_t);
+#endif
+#ifndef mpn_addlsh_n_ip1
+#define mpn_addlsh_n_ip1 __MPN(addlsh_n_ip1)
+  __GMP_DECLSPEC mp_limb_t mpn_addlsh_n_ip1 (mp_ptr, mp_srcptr, mp_size_t, unsigned int);
+#endif
+#ifndef mpn_addlsh_nc_ip1
+#define mpn_addlsh_nc_ip1 __MPN(addlsh_nc_ip1)
+__GMP_DECLSPEC mp_limb_t mpn_addlsh_nc_ip1 (mp_ptr, mp_srcptr, mp_size_t, unsigned int, mp_limb_t);
+#endif
+
+#ifndef mpn_sublsh1_n
+#define mpn_sublsh1_n __MPN(sublsh1_n)
+__GMP_DECLSPEC mp_limb_t mpn_sublsh1_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#endif
+#ifndef mpn_sublsh1_nc
+#define mpn_sublsh1_nc __MPN(sublsh1_nc)
+__GMP_DECLSPEC mp_limb_t mpn_sublsh1_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+#endif
+#ifndef mpn_sublsh1_n_ip1
+#define mpn_sublsh1_n_ip1 __MPN(sublsh1_n_ip1)
+__GMP_DECLSPEC mp_limb_t mpn_sublsh1_n_ip1 (mp_ptr, mp_srcptr, mp_size_t);
+#endif
+#ifndef mpn_sublsh1_nc_ip1
+#define mpn_sublsh1_nc_ip1 __MPN(sublsh1_nc_ip1)
+__GMP_DECLSPEC mp_limb_t mpn_sublsh1_nc_ip1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+#endif
+
+#ifndef mpn_sublsh2_n
+#define mpn_sublsh2_n __MPN(sublsh2_n)
+__GMP_DECLSPEC mp_limb_t mpn_sublsh2_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#endif
+#ifndef mpn_sublsh2_nc
+#define mpn_sublsh2_nc __MPN(sublsh2_nc)
+__GMP_DECLSPEC mp_limb_t mpn_sublsh2_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+#endif
+#ifndef mpn_sublsh2_n_ip1
+#define mpn_sublsh2_n_ip1 __MPN(sublsh2_n_ip1)
+__GMP_DECLSPEC mp_limb_t mpn_sublsh2_n_ip1 (mp_ptr, mp_srcptr, mp_size_t);
+#endif
+#ifndef mpn_sublsh2_nc_ip1
+#define mpn_sublsh2_nc_ip1 __MPN(sublsh2_nc_ip1)
+__GMP_DECLSPEC mp_limb_t mpn_sublsh2_nc_ip1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+#endif
+
+#ifndef mpn_sublsh_n
+#define mpn_sublsh_n __MPN(sublsh_n)
+__GMP_DECLSPEC mp_limb_t mpn_sublsh_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, unsigned int);
+#endif
+#ifndef mpn_sublsh_nc
+#define mpn_sublsh_nc __MPN(sublsh_nc)
+__GMP_DECLSPEC mp_limb_t mpn_sublsh_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, unsigned int, mp_limb_t);
+#endif
+#ifndef mpn_sublsh_n_ip1
+#define mpn_sublsh_n_ip1 __MPN(sublsh_n_ip1)
+  __GMP_DECLSPEC mp_limb_t mpn_sublsh_n_ip1 (mp_ptr, mp_srcptr, mp_size_t, unsigned int);
+#endif
+#ifndef mpn_sublsh_nc_ip1
+#define mpn_sublsh_nc_ip1 __MPN(sublsh_nc_ip1)
+__GMP_DECLSPEC mp_limb_t mpn_sublsh_nc_ip1 (mp_ptr, mp_srcptr, mp_size_t, unsigned int, mp_limb_t);
+#endif
+
+#define mpn_rsblsh1_n __MPN(rsblsh1_n)
+__GMP_DECLSPEC mp_limb_signed_t mpn_rsblsh1_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_rsblsh1_nc __MPN(rsblsh1_nc)
+__GMP_DECLSPEC mp_limb_signed_t mpn_rsblsh1_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_rsblsh2_n __MPN(rsblsh2_n)
+__GMP_DECLSPEC mp_limb_signed_t mpn_rsblsh2_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_rsblsh2_nc __MPN(rsblsh2_nc)
+__GMP_DECLSPEC mp_limb_signed_t mpn_rsblsh2_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_rsblsh_n __MPN(rsblsh_n)
+__GMP_DECLSPEC mp_limb_signed_t mpn_rsblsh_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, unsigned int);
+#define mpn_rsblsh_nc __MPN(rsblsh_nc)
+__GMP_DECLSPEC mp_limb_signed_t mpn_rsblsh_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, unsigned int, mp_limb_t);
+
+#define mpn_rsh1add_n __MPN(rsh1add_n)
+__GMP_DECLSPEC mp_limb_t mpn_rsh1add_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_rsh1add_nc __MPN(rsh1add_nc)
+__GMP_DECLSPEC mp_limb_t mpn_rsh1add_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_rsh1sub_n __MPN(rsh1sub_n)
+__GMP_DECLSPEC mp_limb_t mpn_rsh1sub_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#define mpn_rsh1sub_nc __MPN(rsh1sub_nc)
+__GMP_DECLSPEC mp_limb_t mpn_rsh1sub_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#ifndef mpn_lshiftc  /* if not done with cpuvec in a fat binary */
+#define mpn_lshiftc __MPN(lshiftc)
+__GMP_DECLSPEC mp_limb_t mpn_lshiftc (mp_ptr, mp_srcptr, mp_size_t, unsigned int);
+#endif
+
+#define mpn_add_err1_n  __MPN(add_err1_n)
+__GMP_DECLSPEC mp_limb_t mpn_add_err1_n (mp_ptr, mp_srcptr, mp_srcptr, mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_add_err2_n  __MPN(add_err2_n)
+__GMP_DECLSPEC mp_limb_t mpn_add_err2_n (mp_ptr, mp_srcptr, mp_srcptr, mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_add_err3_n  __MPN(add_err3_n)
+__GMP_DECLSPEC mp_limb_t mpn_add_err3_n (mp_ptr, mp_srcptr, mp_srcptr, mp_ptr, mp_srcptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_sub_err1_n  __MPN(sub_err1_n)
+__GMP_DECLSPEC mp_limb_t mpn_sub_err1_n (mp_ptr, mp_srcptr, mp_srcptr, mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_sub_err2_n  __MPN(sub_err2_n)
+__GMP_DECLSPEC mp_limb_t mpn_sub_err2_n (mp_ptr, mp_srcptr, mp_srcptr, mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_sub_err3_n  __MPN(sub_err3_n)
+__GMP_DECLSPEC mp_limb_t mpn_sub_err3_n (mp_ptr, mp_srcptr, mp_srcptr, mp_ptr, mp_srcptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_add_n_sub_n __MPN(add_n_sub_n)
+__GMP_DECLSPEC mp_limb_t mpn_add_n_sub_n (mp_ptr, mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+
+#define mpn_add_n_sub_nc __MPN(add_n_sub_nc)
+__GMP_DECLSPEC mp_limb_t mpn_add_n_sub_nc (mp_ptr, mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_addaddmul_1msb0 __MPN(addaddmul_1msb0)
+__GMP_DECLSPEC mp_limb_t mpn_addaddmul_1msb0 (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t);
+
+#define mpn_divrem_1c __MPN(divrem_1c)
+__GMP_DECLSPEC mp_limb_t mpn_divrem_1c (mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t);
+
+#define mpn_dump __MPN(dump)
+__GMP_DECLSPEC void mpn_dump (mp_srcptr, mp_size_t);
+
+#define mpn_fib2_ui __MPN(fib2_ui)
+__GMP_DECLSPEC mp_size_t mpn_fib2_ui (mp_ptr, mp_ptr, unsigned long);
+
+#define mpn_fib2m __MPN(fib2m)
+__GMP_DECLSPEC int mpn_fib2m (mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+
+#define mpn_strongfibo __MPN(strongfibo)
+__GMP_DECLSPEC int mpn_strongfibo (mp_srcptr, mp_size_t, mp_ptr);
+
+/* Remap names of internal mpn functions.  */
+#define __clz_tab               __MPN(clz_tab)
+#define mpn_udiv_w_sdiv		__MPN(udiv_w_sdiv)
+
+#define mpn_jacobi_base __MPN(jacobi_base)
+__GMP_DECLSPEC int mpn_jacobi_base (mp_limb_t, mp_limb_t, int) ATTRIBUTE_CONST;
+
+#define mpn_jacobi_2 __MPN(jacobi_2)
+__GMP_DECLSPEC int mpn_jacobi_2 (mp_srcptr, mp_srcptr, unsigned);
+
+#define mpn_jacobi_n __MPN(jacobi_n)
+__GMP_DECLSPEC int mpn_jacobi_n (mp_ptr, mp_ptr, mp_size_t, unsigned);
+
+#define mpn_mod_1c __MPN(mod_1c)
+__GMP_DECLSPEC mp_limb_t mpn_mod_1c (mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t) __GMP_ATTRIBUTE_PURE;
+
+#define mpn_mul_1c __MPN(mul_1c)
+__GMP_DECLSPEC mp_limb_t mpn_mul_1c (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t);
+
+#define mpn_mul_2 __MPN(mul_2)
+__GMP_DECLSPEC mp_limb_t mpn_mul_2 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+
+#define mpn_mul_3 __MPN(mul_3)
+__GMP_DECLSPEC mp_limb_t mpn_mul_3 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+
+#define mpn_mul_4 __MPN(mul_4)
+__GMP_DECLSPEC mp_limb_t mpn_mul_4 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+
+#define mpn_mul_5 __MPN(mul_5)
+__GMP_DECLSPEC mp_limb_t mpn_mul_5 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+
+#define mpn_mul_6 __MPN(mul_6)
+__GMP_DECLSPEC mp_limb_t mpn_mul_6 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+
+#ifndef mpn_mul_basecase  /* if not done with cpuvec in a fat binary */
+#define mpn_mul_basecase __MPN(mul_basecase)
+__GMP_DECLSPEC void mpn_mul_basecase (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+#endif
+
+#define mpn_mullo_n __MPN(mullo_n)
+__GMP_DECLSPEC void mpn_mullo_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+
+#ifndef mpn_mullo_basecase  /* if not done with cpuvec in a fat binary */
+#define mpn_mullo_basecase __MPN(mullo_basecase)
+__GMP_DECLSPEC void mpn_mullo_basecase (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+#endif
+
+#ifndef mpn_sqr_basecase  /* if not done with cpuvec in a fat binary */
+#define mpn_sqr_basecase __MPN(sqr_basecase)
+__GMP_DECLSPEC void mpn_sqr_basecase (mp_ptr, mp_srcptr, mp_size_t);
+#endif
+
+#define mpn_sqrlo __MPN(sqrlo)
+__GMP_DECLSPEC void mpn_sqrlo (mp_ptr, mp_srcptr, mp_size_t);
+
+#define mpn_sqrlo_basecase __MPN(sqrlo_basecase)
+__GMP_DECLSPEC void mpn_sqrlo_basecase (mp_ptr, mp_srcptr, mp_size_t);
+
+#define mpn_mulmid_basecase __MPN(mulmid_basecase)
+__GMP_DECLSPEC void mpn_mulmid_basecase (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+
+#define mpn_mulmid_n __MPN(mulmid_n)
+__GMP_DECLSPEC void mpn_mulmid_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+
+#define mpn_mulmid __MPN(mulmid)
+__GMP_DECLSPEC void mpn_mulmid (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+
+#define mpn_submul_1c __MPN(submul_1c)
+__GMP_DECLSPEC mp_limb_t mpn_submul_1c (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t);
+
+#ifndef mpn_redc_1  /* if not done with cpuvec in a fat binary */
+#define mpn_redc_1 __MPN(redc_1)
+__GMP_DECLSPEC mp_limb_t mpn_redc_1 (mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+#endif
+
+#ifndef mpn_redc_2  /* if not done with cpuvec in a fat binary */
+#define mpn_redc_2 __MPN(redc_2)
+__GMP_DECLSPEC mp_limb_t mpn_redc_2 (mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+#endif
+
+#define mpn_redc_n __MPN(redc_n)
+__GMP_DECLSPEC void mpn_redc_n (mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+
+
+#ifndef mpn_mod_1_1p_cps  /* if not done with cpuvec in a fat binary */
+#define mpn_mod_1_1p_cps __MPN(mod_1_1p_cps)
+__GMP_DECLSPEC void mpn_mod_1_1p_cps (mp_limb_t [4], mp_limb_t);
+#endif
+#ifndef mpn_mod_1_1p  /* if not done with cpuvec in a fat binary */
+#define mpn_mod_1_1p __MPN(mod_1_1p)
+__GMP_DECLSPEC mp_limb_t mpn_mod_1_1p (mp_srcptr, mp_size_t, mp_limb_t, const mp_limb_t [4]) __GMP_ATTRIBUTE_PURE;
+#endif
+
+#ifndef mpn_mod_1s_2p_cps  /* if not done with cpuvec in a fat binary */
+#define mpn_mod_1s_2p_cps __MPN(mod_1s_2p_cps)
+__GMP_DECLSPEC void mpn_mod_1s_2p_cps (mp_limb_t [5], mp_limb_t);
+#endif
+#ifndef mpn_mod_1s_2p  /* if not done with cpuvec in a fat binary */
+#define mpn_mod_1s_2p __MPN(mod_1s_2p)
+__GMP_DECLSPEC mp_limb_t mpn_mod_1s_2p (mp_srcptr, mp_size_t, mp_limb_t, const mp_limb_t [5]) __GMP_ATTRIBUTE_PURE;
+#endif
+
+#ifndef mpn_mod_1s_3p_cps  /* if not done with cpuvec in a fat binary */
+#define mpn_mod_1s_3p_cps __MPN(mod_1s_3p_cps)
+__GMP_DECLSPEC void mpn_mod_1s_3p_cps (mp_limb_t [6], mp_limb_t);
+#endif
+#ifndef mpn_mod_1s_3p  /* if not done with cpuvec in a fat binary */
+#define mpn_mod_1s_3p __MPN(mod_1s_3p)
+__GMP_DECLSPEC mp_limb_t mpn_mod_1s_3p (mp_srcptr, mp_size_t, mp_limb_t, const mp_limb_t [6]) __GMP_ATTRIBUTE_PURE;
+#endif
+
+#ifndef mpn_mod_1s_4p_cps  /* if not done with cpuvec in a fat binary */
+#define mpn_mod_1s_4p_cps __MPN(mod_1s_4p_cps)
+__GMP_DECLSPEC void mpn_mod_1s_4p_cps (mp_limb_t [7], mp_limb_t);
+#endif
+#ifndef mpn_mod_1s_4p  /* if not done with cpuvec in a fat binary */
+#define mpn_mod_1s_4p __MPN(mod_1s_4p)
+__GMP_DECLSPEC mp_limb_t mpn_mod_1s_4p (mp_srcptr, mp_size_t, mp_limb_t, const mp_limb_t [7]) __GMP_ATTRIBUTE_PURE;
+#endif
+
+#define mpn_bc_mulmod_bnm1 __MPN(bc_mulmod_bnm1)
+__GMP_DECLSPEC void mpn_bc_mulmod_bnm1 (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_ptr);
+#define mpn_mulmod_bnm1 __MPN(mulmod_bnm1)
+__GMP_DECLSPEC void mpn_mulmod_bnm1 (mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+#define mpn_mulmod_bnm1_next_size __MPN(mulmod_bnm1_next_size)
+__GMP_DECLSPEC mp_size_t mpn_mulmod_bnm1_next_size (mp_size_t) ATTRIBUTE_CONST;
+static inline mp_size_t
+mpn_mulmod_bnm1_itch (mp_size_t rn, mp_size_t an, mp_size_t bn) {
+  mp_size_t n, itch;
+  n = rn >> 1;
+  itch = rn + 4 +
+    (an > n ? (bn > n ? rn : n) : 0);
+  return itch;
+}
+
+#define mpn_sqrmod_bnm1 __MPN(sqrmod_bnm1)
+__GMP_DECLSPEC void mpn_sqrmod_bnm1 (mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+#define mpn_sqrmod_bnm1_next_size __MPN(sqrmod_bnm1_next_size)
+__GMP_DECLSPEC mp_size_t mpn_sqrmod_bnm1_next_size (mp_size_t) ATTRIBUTE_CONST;
+static inline mp_size_t
+mpn_sqrmod_bnm1_itch (mp_size_t rn, mp_size_t an) {
+  mp_size_t n, itch;
+  n = rn >> 1;
+  itch = rn + 3 +
+    (an > n ? an : 0);
+  return itch;
+}
+
+typedef __gmp_randstate_struct *gmp_randstate_ptr;
+typedef const __gmp_randstate_struct *gmp_randstate_srcptr;
+
+/* Pseudo-random number generator function pointers structure.  */
+typedef struct {
+  void (*randseed_fn) (gmp_randstate_t, mpz_srcptr);
+  void (*randget_fn) (gmp_randstate_t, mp_ptr, unsigned long int);
+  void (*randclear_fn) (gmp_randstate_t);
+  void (*randiset_fn) (gmp_randstate_ptr, gmp_randstate_srcptr);
+} gmp_randfnptr_t;
+
+/* Macro to obtain a void pointer to the function pointers structure.  */
+#define RNG_FNPTR(rstate) ((rstate)->_mp_algdata._mp_lc)
+
+/* Macro to obtain a pointer to the generator's state.
+   When used as a lvalue the rvalue needs to be cast to mp_ptr.  */
+#define RNG_STATE(rstate) ((rstate)->_mp_seed->_mp_d)
+
+/* Write a given number of random bits to rp.  */
+#define _gmp_rand(rp, state, bits)					\
+  do {									\
+    gmp_randstate_ptr  __rstate = (state);				\
+    (*((gmp_randfnptr_t *) RNG_FNPTR (__rstate))->randget_fn)		\
+      (__rstate, rp, bits);						\
+  } while (0)
+
+__GMP_DECLSPEC void __gmp_randinit_mt_noseed (gmp_randstate_t);
+
+
+/* __gmp_rands is the global state for the old-style random functions, and
+   is also used in the test programs (hence the __GMP_DECLSPEC).
+
+   There's no seeding here, so mpz_random etc will generate the same
+   sequence every time.  This is not unlike the C library random functions
+   if you don't seed them, so perhaps it's acceptable.  Digging up a seed
+   from /dev/random or the like would work on many systems, but might
+   encourage a false confidence, since it'd be pretty much impossible to do
+   something that would work reliably everywhere.  In any case the new style
+   functions are recommended to applications which care about randomness, so
+   the old functions aren't too important.  */
+
+__GMP_DECLSPEC extern char             __gmp_rands_initialized;
+__GMP_DECLSPEC extern gmp_randstate_t  __gmp_rands;
+
+#define RANDS								\
+  ((__gmp_rands_initialized ? 0						\
+    : (__gmp_rands_initialized = 1,					\
+       __gmp_randinit_mt_noseed (__gmp_rands), 0)),			\
+   __gmp_rands)
+
+/* this is used by the test programs, to free memory */
+#define RANDS_CLEAR()							\
+  do {									\
+    if (__gmp_rands_initialized)					\
+      {									\
+	__gmp_rands_initialized = 0;					\
+	gmp_randclear (__gmp_rands);					\
+      }									\
+  } while (0)
+
+
+/* For a threshold between algorithms A and B, size>=thresh is where B
+   should be used.  Special value MP_SIZE_T_MAX means only ever use A, or
+   value 0 means only ever use B.  The tests for these special values will
+   be compile-time constants, so the compiler should be able to eliminate
+   the code for the unwanted algorithm.  */
+
+#if ! defined (__GNUC__) || __GNUC__ < 2
+#define ABOVE_THRESHOLD(size,thresh)					\
+  ((thresh) == 0							\
+   || ((thresh) != MP_SIZE_T_MAX					\
+       && (size) >= (thresh)))
+#else
+#define ABOVE_THRESHOLD(size,thresh)					\
+  ((__builtin_constant_p (thresh) && (thresh) == 0)			\
+   || (!(__builtin_constant_p (thresh) && (thresh) == MP_SIZE_T_MAX)	\
+       && (size) >= (thresh)))
+#endif
+#define BELOW_THRESHOLD(size,thresh)  (! ABOVE_THRESHOLD (size, thresh))
+
+/* The minimal supported value for Toom22 depends also on Toom32 and
+   Toom42 implementations. */
+#define MPN_TOOM22_MUL_MINSIZE    6
+#define MPN_TOOM2_SQR_MINSIZE     4
+
+#define MPN_TOOM33_MUL_MINSIZE   17
+#define MPN_TOOM3_SQR_MINSIZE    17
+
+#define MPN_TOOM44_MUL_MINSIZE   30
+#define MPN_TOOM4_SQR_MINSIZE    30
+
+#define MPN_TOOM6H_MUL_MINSIZE   46
+#define MPN_TOOM6_SQR_MINSIZE    46
+
+#define MPN_TOOM8H_MUL_MINSIZE   86
+#define MPN_TOOM8_SQR_MINSIZE    86
+
+#define MPN_TOOM32_MUL_MINSIZE   10
+#define MPN_TOOM42_MUL_MINSIZE   10
+#define MPN_TOOM43_MUL_MINSIZE   25
+#define MPN_TOOM53_MUL_MINSIZE   17
+#define MPN_TOOM54_MUL_MINSIZE   31
+#define MPN_TOOM63_MUL_MINSIZE   49
+
+#define MPN_TOOM42_MULMID_MINSIZE    4
+
+#define   mpn_sqr_diagonal __MPN(sqr_diagonal)
+__GMP_DECLSPEC void      mpn_sqr_diagonal (mp_ptr, mp_srcptr, mp_size_t);
+
+#define mpn_sqr_diag_addlsh1 __MPN(sqr_diag_addlsh1)
+__GMP_DECLSPEC void      mpn_sqr_diag_addlsh1 (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+
+#define   mpn_toom_interpolate_5pts __MPN(toom_interpolate_5pts)
+__GMP_DECLSPEC void      mpn_toom_interpolate_5pts (mp_ptr, mp_ptr, mp_ptr, mp_size_t, mp_size_t, int, mp_limb_t);
+
+enum toom6_flags {toom6_all_pos = 0, toom6_vm1_neg = 1, toom6_vm2_neg = 2};
+#define   mpn_toom_interpolate_6pts __MPN(toom_interpolate_6pts)
+__GMP_DECLSPEC void      mpn_toom_interpolate_6pts (mp_ptr, mp_size_t, enum toom6_flags, mp_ptr, mp_ptr, mp_ptr, mp_size_t);
+
+enum toom7_flags { toom7_w1_neg = 1, toom7_w3_neg = 2 };
+#define   mpn_toom_interpolate_7pts __MPN(toom_interpolate_7pts)
+__GMP_DECLSPEC void      mpn_toom_interpolate_7pts (mp_ptr, mp_size_t, enum toom7_flags, mp_ptr, mp_ptr, mp_ptr, mp_ptr, mp_size_t, mp_ptr);
+
+#define mpn_toom_interpolate_8pts __MPN(toom_interpolate_8pts)
+__GMP_DECLSPEC void      mpn_toom_interpolate_8pts (mp_ptr, mp_size_t, mp_ptr, mp_ptr, mp_size_t, mp_ptr);
+
+#define mpn_toom_interpolate_12pts __MPN(toom_interpolate_12pts)
+__GMP_DECLSPEC void      mpn_toom_interpolate_12pts (mp_ptr, mp_ptr, mp_ptr, mp_ptr, mp_size_t, mp_size_t, int, mp_ptr);
+
+#define mpn_toom_interpolate_16pts __MPN(toom_interpolate_16pts)
+__GMP_DECLSPEC void      mpn_toom_interpolate_16pts (mp_ptr, mp_ptr, mp_ptr, mp_ptr, mp_ptr, mp_size_t, mp_size_t, int, mp_ptr);
+
+#define   mpn_toom_couple_handling __MPN(toom_couple_handling)
+__GMP_DECLSPEC void mpn_toom_couple_handling (mp_ptr, mp_size_t, mp_ptr, int, mp_size_t, int, int);
+
+#define   mpn_toom_eval_dgr3_pm1 __MPN(toom_eval_dgr3_pm1)
+__GMP_DECLSPEC int mpn_toom_eval_dgr3_pm1 (mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_size_t, mp_ptr);
+
+#define   mpn_toom_eval_dgr3_pm2 __MPN(toom_eval_dgr3_pm2)
+__GMP_DECLSPEC int mpn_toom_eval_dgr3_pm2 (mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_size_t, mp_ptr);
+
+#define   mpn_toom_eval_pm1 __MPN(toom_eval_pm1)
+__GMP_DECLSPEC int mpn_toom_eval_pm1 (mp_ptr, mp_ptr, unsigned, mp_srcptr, mp_size_t, mp_size_t, mp_ptr);
+
+#define   mpn_toom_eval_pm2 __MPN(toom_eval_pm2)
+__GMP_DECLSPEC int mpn_toom_eval_pm2 (mp_ptr, mp_ptr, unsigned, mp_srcptr, mp_size_t, mp_size_t, mp_ptr);
+
+#define   mpn_toom_eval_pm2exp __MPN(toom_eval_pm2exp)
+__GMP_DECLSPEC int mpn_toom_eval_pm2exp (mp_ptr, mp_ptr, unsigned, mp_srcptr, mp_size_t, mp_size_t, unsigned, mp_ptr);
+
+#define   mpn_toom_eval_pm2rexp __MPN(toom_eval_pm2rexp)
+__GMP_DECLSPEC int mpn_toom_eval_pm2rexp (mp_ptr, mp_ptr, unsigned, mp_srcptr, mp_size_t, mp_size_t, unsigned, mp_ptr);
+
+#define   mpn_toom22_mul __MPN(toom22_mul)
+__GMP_DECLSPEC void      mpn_toom22_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+
+#define   mpn_toom32_mul __MPN(toom32_mul)
+__GMP_DECLSPEC void      mpn_toom32_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+
+#define   mpn_toom42_mul __MPN(toom42_mul)
+__GMP_DECLSPEC void      mpn_toom42_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+
+#define   mpn_toom52_mul __MPN(toom52_mul)
+__GMP_DECLSPEC void      mpn_toom52_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+
+#define   mpn_toom62_mul __MPN(toom62_mul)
+__GMP_DECLSPEC void      mpn_toom62_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+
+#define   mpn_toom2_sqr __MPN(toom2_sqr)
+__GMP_DECLSPEC void      mpn_toom2_sqr (mp_ptr, mp_srcptr, mp_size_t, mp_ptr);
+
+#define   mpn_toom33_mul __MPN(toom33_mul)
+__GMP_DECLSPEC void      mpn_toom33_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+
+#define   mpn_toom43_mul __MPN(toom43_mul)
+__GMP_DECLSPEC void      mpn_toom43_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+
+#define   mpn_toom53_mul __MPN(toom53_mul)
+__GMP_DECLSPEC void      mpn_toom53_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+
+#define   mpn_toom54_mul __MPN(toom54_mul)
+__GMP_DECLSPEC void      mpn_toom54_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+
+#define   mpn_toom63_mul __MPN(toom63_mul)
+__GMP_DECLSPEC void      mpn_toom63_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+
+#define   mpn_toom3_sqr __MPN(toom3_sqr)
+__GMP_DECLSPEC void      mpn_toom3_sqr (mp_ptr, mp_srcptr, mp_size_t, mp_ptr);
+
+#define   mpn_toom44_mul __MPN(toom44_mul)
+__GMP_DECLSPEC void      mpn_toom44_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+
+#define   mpn_toom4_sqr __MPN(toom4_sqr)
+__GMP_DECLSPEC void      mpn_toom4_sqr (mp_ptr, mp_srcptr, mp_size_t, mp_ptr);
+
+#define   mpn_toom6h_mul __MPN(toom6h_mul)
+__GMP_DECLSPEC void      mpn_toom6h_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+
+#define   mpn_toom6_sqr __MPN(toom6_sqr)
+__GMP_DECLSPEC void      mpn_toom6_sqr (mp_ptr, mp_srcptr, mp_size_t, mp_ptr);
+
+#define   mpn_toom8h_mul __MPN(toom8h_mul)
+__GMP_DECLSPEC void      mpn_toom8h_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+
+#define   mpn_toom8_sqr __MPN(toom8_sqr)
+__GMP_DECLSPEC void      mpn_toom8_sqr (mp_ptr, mp_srcptr, mp_size_t, mp_ptr);
+
+#define   mpn_toom42_mulmid __MPN(toom42_mulmid)
+__GMP_DECLSPEC void      mpn_toom42_mulmid (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_ptr);
+
+#define   mpn_fft_best_k __MPN(fft_best_k)
+__GMP_DECLSPEC int       mpn_fft_best_k (mp_size_t, int) ATTRIBUTE_CONST;
+
+#define   mpn_mul_fft __MPN(mul_fft)
+__GMP_DECLSPEC mp_limb_t mpn_mul_fft (mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, int);
+
+#define   mpn_mul_fft_full __MPN(mul_fft_full)
+__GMP_DECLSPEC void      mpn_mul_fft_full (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+
+#define   mpn_nussbaumer_mul __MPN(nussbaumer_mul)
+__GMP_DECLSPEC void      mpn_nussbaumer_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+
+#define   mpn_fft_next_size __MPN(fft_next_size)
+__GMP_DECLSPEC mp_size_t mpn_fft_next_size (mp_size_t, int) ATTRIBUTE_CONST;
+
+#define   mpn_div_qr_1n_pi1 __MPN(div_qr_1n_pi1)
+  __GMP_DECLSPEC mp_limb_t mpn_div_qr_1n_pi1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t, mp_limb_t);
+
+#define   mpn_div_qr_2n_pi1 __MPN(div_qr_2n_pi1)
+  __GMP_DECLSPEC mp_limb_t mpn_div_qr_2n_pi1 (mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t, mp_limb_t);
+
+#define   mpn_div_qr_2u_pi1 __MPN(div_qr_2u_pi1)
+  __GMP_DECLSPEC mp_limb_t mpn_div_qr_2u_pi1 (mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t, int, mp_limb_t);
+
+#define   mpn_sbpi1_div_qr __MPN(sbpi1_div_qr)
+__GMP_DECLSPEC mp_limb_t mpn_sbpi1_div_qr (mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define   mpn_sbpi1_div_q __MPN(sbpi1_div_q)
+__GMP_DECLSPEC mp_limb_t mpn_sbpi1_div_q (mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define   mpn_sbpi1_divappr_q __MPN(sbpi1_divappr_q)
+__GMP_DECLSPEC mp_limb_t mpn_sbpi1_divappr_q (mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define   mpn_dcpi1_div_qr __MPN(dcpi1_div_qr)
+__GMP_DECLSPEC mp_limb_t mpn_dcpi1_div_qr (mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, gmp_pi1_t *);
+#define   mpn_dcpi1_div_qr_n __MPN(dcpi1_div_qr_n)
+__GMP_DECLSPEC mp_limb_t mpn_dcpi1_div_qr_n (mp_ptr, mp_ptr, mp_srcptr, mp_size_t, gmp_pi1_t *, mp_ptr);
+
+#define   mpn_dcpi1_div_q __MPN(dcpi1_div_q)
+__GMP_DECLSPEC mp_limb_t mpn_dcpi1_div_q (mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, gmp_pi1_t *);
+
+#define   mpn_dcpi1_divappr_q __MPN(dcpi1_divappr_q)
+__GMP_DECLSPEC mp_limb_t mpn_dcpi1_divappr_q (mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, gmp_pi1_t *);
+
+#define   mpn_mu_div_qr __MPN(mu_div_qr)
+__GMP_DECLSPEC mp_limb_t mpn_mu_div_qr (mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+#define   mpn_mu_div_qr_itch __MPN(mu_div_qr_itch)
+__GMP_DECLSPEC mp_size_t mpn_mu_div_qr_itch (mp_size_t, mp_size_t, int) ATTRIBUTE_CONST;
+
+#define   mpn_preinv_mu_div_qr __MPN(preinv_mu_div_qr)
+__GMP_DECLSPEC mp_limb_t mpn_preinv_mu_div_qr (mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+#define   mpn_preinv_mu_div_qr_itch __MPN(preinv_mu_div_qr_itch)
+__GMP_DECLSPEC mp_size_t mpn_preinv_mu_div_qr_itch (mp_size_t, mp_size_t, mp_size_t) ATTRIBUTE_CONST;
+
+#define   mpn_mu_divappr_q __MPN(mu_divappr_q)
+__GMP_DECLSPEC mp_limb_t mpn_mu_divappr_q (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+#define   mpn_mu_divappr_q_itch __MPN(mu_divappr_q_itch)
+__GMP_DECLSPEC mp_size_t mpn_mu_divappr_q_itch (mp_size_t, mp_size_t, int) ATTRIBUTE_CONST;
+
+#define   mpn_mu_div_q __MPN(mu_div_q)
+__GMP_DECLSPEC mp_limb_t mpn_mu_div_q (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+#define   mpn_mu_div_q_itch __MPN(mu_div_q_itch)
+__GMP_DECLSPEC mp_size_t mpn_mu_div_q_itch (mp_size_t, mp_size_t, int) ATTRIBUTE_CONST;
+
+#define  mpn_div_q __MPN(div_q)
+__GMP_DECLSPEC void mpn_div_q (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+
+#define   mpn_invert __MPN(invert)
+__GMP_DECLSPEC void      mpn_invert (mp_ptr, mp_srcptr, mp_size_t, mp_ptr);
+#define mpn_invert_itch(n)  mpn_invertappr_itch(n)
+
+#define   mpn_ni_invertappr __MPN(ni_invertappr)
+__GMP_DECLSPEC mp_limb_t mpn_ni_invertappr (mp_ptr, mp_srcptr, mp_size_t, mp_ptr);
+#define   mpn_invertappr __MPN(invertappr)
+__GMP_DECLSPEC mp_limb_t mpn_invertappr (mp_ptr, mp_srcptr, mp_size_t, mp_ptr);
+#define mpn_invertappr_itch(n)  (2 * (n))
+
+#define   mpn_binvert __MPN(binvert)
+__GMP_DECLSPEC void      mpn_binvert (mp_ptr, mp_srcptr, mp_size_t, mp_ptr);
+#define   mpn_binvert_itch __MPN(binvert_itch)
+__GMP_DECLSPEC mp_size_t mpn_binvert_itch (mp_size_t) ATTRIBUTE_CONST;
+
+#define mpn_bdiv_q_1 __MPN(bdiv_q_1)
+__GMP_DECLSPEC mp_limb_t mpn_bdiv_q_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_pi1_bdiv_q_1 __MPN(pi1_bdiv_q_1)
+__GMP_DECLSPEC mp_limb_t mpn_pi1_bdiv_q_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t, int);
+
+#define   mpn_sbpi1_bdiv_qr __MPN(sbpi1_bdiv_qr)
+__GMP_DECLSPEC mp_limb_t mpn_sbpi1_bdiv_qr (mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define   mpn_sbpi1_bdiv_q __MPN(sbpi1_bdiv_q)
+__GMP_DECLSPEC void      mpn_sbpi1_bdiv_q (mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define   mpn_sbpi1_bdiv_r __MPN(sbpi1_bdiv_r)
+__GMP_DECLSPEC mp_limb_t mpn_sbpi1_bdiv_r (mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define   mpn_dcpi1_bdiv_qr __MPN(dcpi1_bdiv_qr)
+__GMP_DECLSPEC mp_limb_t mpn_dcpi1_bdiv_qr (mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t);
+#define   mpn_dcpi1_bdiv_qr_n_itch __MPN(dcpi1_bdiv_qr_n_itch)
+__GMP_DECLSPEC mp_size_t mpn_dcpi1_bdiv_qr_n_itch (mp_size_t) ATTRIBUTE_CONST;
+
+#define   mpn_dcpi1_bdiv_qr_n __MPN(dcpi1_bdiv_qr_n)
+__GMP_DECLSPEC mp_limb_t mpn_dcpi1_bdiv_qr_n (mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_ptr);
+#define   mpn_dcpi1_bdiv_q __MPN(dcpi1_bdiv_q)
+__GMP_DECLSPEC void      mpn_dcpi1_bdiv_q (mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define   mpn_mu_bdiv_qr __MPN(mu_bdiv_qr)
+__GMP_DECLSPEC mp_limb_t mpn_mu_bdiv_qr (mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+#define   mpn_mu_bdiv_qr_itch __MPN(mu_bdiv_qr_itch)
+__GMP_DECLSPEC mp_size_t mpn_mu_bdiv_qr_itch (mp_size_t, mp_size_t) ATTRIBUTE_CONST;
+
+#define   mpn_mu_bdiv_q __MPN(mu_bdiv_q)
+__GMP_DECLSPEC void      mpn_mu_bdiv_q (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+#define   mpn_mu_bdiv_q_itch __MPN(mu_bdiv_q_itch)
+__GMP_DECLSPEC mp_size_t mpn_mu_bdiv_q_itch (mp_size_t, mp_size_t) ATTRIBUTE_CONST;
+
+#define   mpn_bdiv_qr __MPN(bdiv_qr)
+__GMP_DECLSPEC mp_limb_t mpn_bdiv_qr (mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+#define   mpn_bdiv_qr_itch __MPN(bdiv_qr_itch)
+__GMP_DECLSPEC mp_size_t mpn_bdiv_qr_itch (mp_size_t, mp_size_t) ATTRIBUTE_CONST;
+
+#define   mpn_bdiv_q __MPN(bdiv_q)
+__GMP_DECLSPEC void      mpn_bdiv_q (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+#define   mpn_bdiv_q_itch __MPN(bdiv_q_itch)
+__GMP_DECLSPEC mp_size_t mpn_bdiv_q_itch (mp_size_t, mp_size_t) ATTRIBUTE_CONST;
+
+#define   mpn_divexact __MPN(divexact)
+__GMP_DECLSPEC void      mpn_divexact (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+#define   mpn_divexact_itch __MPN(divexact_itch)
+__GMP_DECLSPEC mp_size_t mpn_divexact_itch (mp_size_t, mp_size_t) ATTRIBUTE_CONST;
+
+#ifndef mpn_bdiv_dbm1c  /* if not done with cpuvec in a fat binary */
+#define   mpn_bdiv_dbm1c __MPN(bdiv_dbm1c)
+__GMP_DECLSPEC mp_limb_t mpn_bdiv_dbm1c (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t);
+#endif
+
+#define   mpn_bdiv_dbm1(dst, src, size, divisor) \
+  mpn_bdiv_dbm1c (dst, src, size, divisor, __GMP_CAST (mp_limb_t, 0))
+
+#define   mpn_powm __MPN(powm)
+__GMP_DECLSPEC void      mpn_powm (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+#define   mpn_powlo __MPN(powlo)
+__GMP_DECLSPEC void      mpn_powlo (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_size_t, mp_ptr);
+
+#define mpn_sec_pi1_div_qr __MPN(sec_pi1_div_qr)
+__GMP_DECLSPEC mp_limb_t mpn_sec_pi1_div_qr (mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t, mp_ptr);
+#define mpn_sec_pi1_div_r __MPN(sec_pi1_div_r)
+__GMP_DECLSPEC void mpn_sec_pi1_div_r (mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t, mp_ptr);
+
+
+#ifndef DIVEXACT_BY3_METHOD
+#if GMP_NUMB_BITS % 2 == 0 && ! defined (HAVE_NATIVE_mpn_divexact_by3c)
+#define DIVEXACT_BY3_METHOD 0	/* default to using mpn_bdiv_dbm1c */
+#else
+#define DIVEXACT_BY3_METHOD 1
+#endif
+#endif
+
+#if DIVEXACT_BY3_METHOD == 0
+#undef mpn_divexact_by3
+#define mpn_divexact_by3(dst,src,size) \
+  (3 & mpn_bdiv_dbm1 (dst, src, size, __GMP_CAST (mp_limb_t, GMP_NUMB_MASK / 3)))
+/* override mpn_divexact_by3c defined in gmp.h */
+/*
+#undef mpn_divexact_by3c
+#define mpn_divexact_by3c(dst,src,size,cy) \
+  (3 & mpn_bdiv_dbm1c (dst, src, size, __GMP_CAST (mp_limb_t, GMP_NUMB_MASK / 3, GMP_NUMB_MASK / 3 * cy)))
+*/
+#endif
+
+#if GMP_NUMB_BITS % 4 == 0
+#define mpn_divexact_by5(dst,src,size) \
+  (7 & 3 * mpn_bdiv_dbm1 (dst, src, size, __GMP_CAST (mp_limb_t, GMP_NUMB_MASK / 5)))
+#endif
+
+#if GMP_NUMB_BITS % 3 == 0
+#define mpn_divexact_by7(dst,src,size) \
+  (7 & 1 * mpn_bdiv_dbm1 (dst, src, size, __GMP_CAST (mp_limb_t, GMP_NUMB_MASK / 7)))
+#endif
+
+#if GMP_NUMB_BITS % 6 == 0
+#define mpn_divexact_by9(dst,src,size) \
+  (15 & 7 * mpn_bdiv_dbm1 (dst, src, size, __GMP_CAST (mp_limb_t, GMP_NUMB_MASK / 9)))
+#endif
+
+#if GMP_NUMB_BITS % 10 == 0
+#define mpn_divexact_by11(dst,src,size) \
+  (15 & 5 * mpn_bdiv_dbm1 (dst, src, size, __GMP_CAST (mp_limb_t, GMP_NUMB_MASK / 11)))
+#endif
+
+#if GMP_NUMB_BITS % 12 == 0
+#define mpn_divexact_by13(dst,src,size) \
+  (15 & 3 * mpn_bdiv_dbm1 (dst, src, size, __GMP_CAST (mp_limb_t, GMP_NUMB_MASK / 13)))
+#endif
+
+#if GMP_NUMB_BITS % 4 == 0
+#define mpn_divexact_by15(dst,src,size) \
+  (15 & 1 * mpn_bdiv_dbm1 (dst, src, size, __GMP_CAST (mp_limb_t, GMP_NUMB_MASK / 15)))
+#endif
+
+#define mpz_divexact_gcd  __gmpz_divexact_gcd
+__GMP_DECLSPEC void    mpz_divexact_gcd (mpz_ptr, mpz_srcptr, mpz_srcptr);
+
+#define mpz_prodlimbs  __gmpz_prodlimbs
+__GMP_DECLSPEC mp_size_t mpz_prodlimbs (mpz_ptr, mp_ptr, mp_size_t);
+
+#define mpz_oddfac_1  __gmpz_oddfac_1
+__GMP_DECLSPEC void mpz_oddfac_1 (mpz_ptr, mp_limb_t, unsigned);
+
+#define mpz_stronglucas  __gmpz_stronglucas
+__GMP_DECLSPEC int mpz_stronglucas (mpz_srcptr, mpz_ptr, mpz_ptr);
+
+#define mpz_lucas_mod  __gmpz_lucas_mod
+__GMP_DECLSPEC int mpz_lucas_mod (mpz_ptr, mpz_ptr, long, mp_bitcnt_t, mpz_srcptr, mpz_ptr, mpz_ptr);
+
+#define mpz_inp_str_nowhite __gmpz_inp_str_nowhite
+#ifdef _GMP_H_HAVE_FILE
+__GMP_DECLSPEC size_t  mpz_inp_str_nowhite (mpz_ptr, FILE *, int, int, size_t);
+#endif
+
+#define mpn_divisible_p __MPN(divisible_p)
+__GMP_DECLSPEC int     mpn_divisible_p (mp_srcptr, mp_size_t, mp_srcptr, mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+#define   mpn_rootrem __MPN(rootrem)
+__GMP_DECLSPEC mp_size_t mpn_rootrem (mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_broot __MPN(broot)
+__GMP_DECLSPEC void mpn_broot (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_broot_invm1 __MPN(broot_invm1)
+__GMP_DECLSPEC void mpn_broot_invm1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+#define mpn_brootinv __MPN(brootinv)
+__GMP_DECLSPEC void mpn_brootinv (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_ptr);
+
+#define mpn_bsqrt __MPN(bsqrt)
+__GMP_DECLSPEC void mpn_bsqrt (mp_ptr, mp_srcptr, mp_bitcnt_t, mp_ptr);
+
+#define mpn_bsqrtinv __MPN(bsqrtinv)
+__GMP_DECLSPEC int mpn_bsqrtinv (mp_ptr, mp_srcptr, mp_bitcnt_t, mp_ptr);
+
+#if defined (_CRAY)
+#define MPN_COPY_INCR(dst, src, n)					\
+  do {									\
+    int __i;		/* Faster on some Crays with plain int */	\
+    _Pragma ("_CRI ivdep");						\
+    for (__i = 0; __i < (n); __i++)					\
+      (dst)[__i] = (src)[__i];						\
+  } while (0)
+#endif
+
+/* used by test programs, hence __GMP_DECLSPEC */
+#ifndef mpn_copyi  /* if not done with cpuvec in a fat binary */
+#define mpn_copyi __MPN(copyi)
+__GMP_DECLSPEC void mpn_copyi (mp_ptr, mp_srcptr, mp_size_t);
+#endif
+
+#if ! defined (MPN_COPY_INCR) && HAVE_NATIVE_mpn_copyi
+#define MPN_COPY_INCR(dst, src, size)					\
+  do {									\
+    ASSERT ((size) >= 0);						\
+    ASSERT (MPN_SAME_OR_INCR_P (dst, src, size));			\
+    mpn_copyi (dst, src, size);						\
+  } while (0)
+#endif
+
+/* Copy N limbs from SRC to DST incrementing, N==0 allowed.  */
+#if ! defined (MPN_COPY_INCR)
+#define MPN_COPY_INCR(dst, src, n)					\
+  do {									\
+    ASSERT ((n) >= 0);							\
+    ASSERT (MPN_SAME_OR_INCR_P (dst, src, n));				\
+    if ((n) != 0)							\
+      {									\
+	mp_size_t __n = (n) - 1;					\
+	mp_ptr __dst = (dst);						\
+	mp_srcptr __src = (src);					\
+	mp_limb_t __x;							\
+	__x = *__src++;							\
+	if (__n != 0)							\
+	  {								\
+	    do								\
+	      {								\
+		*__dst++ = __x;						\
+		__x = *__src++;						\
+	      }								\
+	    while (--__n);						\
+	  }								\
+	*__dst++ = __x;							\
+      }									\
+  } while (0)
+#endif
+
+
+#if defined (_CRAY)
+#define MPN_COPY_DECR(dst, src, n)					\
+  do {									\
+    int __i;		/* Faster on some Crays with plain int */	\
+    _Pragma ("_CRI ivdep");						\
+    for (__i = (n) - 1; __i >= 0; __i--)				\
+      (dst)[__i] = (src)[__i];						\
+  } while (0)
+#endif
+
+/* used by test programs, hence __GMP_DECLSPEC */
+#ifndef mpn_copyd  /* if not done with cpuvec in a fat binary */
+#define mpn_copyd __MPN(copyd)
+__GMP_DECLSPEC void mpn_copyd (mp_ptr, mp_srcptr, mp_size_t);
+#endif
+
+#if ! defined (MPN_COPY_DECR) && HAVE_NATIVE_mpn_copyd
+#define MPN_COPY_DECR(dst, src, size)					\
+  do {									\
+    ASSERT ((size) >= 0);						\
+    ASSERT (MPN_SAME_OR_DECR_P (dst, src, size));			\
+    mpn_copyd (dst, src, size);						\
+  } while (0)
+#endif
+
+/* Copy N limbs from SRC to DST decrementing, N==0 allowed.  */
+#if ! defined (MPN_COPY_DECR)
+#define MPN_COPY_DECR(dst, src, n)					\
+  do {									\
+    ASSERT ((n) >= 0);							\
+    ASSERT (MPN_SAME_OR_DECR_P (dst, src, n));				\
+    if ((n) != 0)							\
+      {									\
+	mp_size_t __n = (n) - 1;					\
+	mp_ptr __dst = (dst) + __n;					\
+	mp_srcptr __src = (src) + __n;					\
+	mp_limb_t __x;							\
+	__x = *__src--;							\
+	if (__n != 0)							\
+	  {								\
+	    do								\
+	      {								\
+		*__dst-- = __x;						\
+		__x = *__src--;						\
+	      }								\
+	    while (--__n);						\
+	  }								\
+	*__dst-- = __x;							\
+      }									\
+  } while (0)
+#endif
+
+
+#ifndef MPN_COPY
+#define MPN_COPY(d,s,n)							\
+  do {									\
+    ASSERT (MPN_SAME_OR_SEPARATE_P (d, s, n));				\
+    MPN_COPY_INCR (d, s, n);						\
+  } while (0)
+#endif
+
+
+/* Set {dst,size} to the limbs of {src,size} in reverse order. */
+#define MPN_REVERSE(dst, src, size)					\
+  do {									\
+    mp_ptr     __dst = (dst);						\
+    mp_size_t  __size = (size);						\
+    mp_srcptr  __src = (src) + __size - 1;				\
+    mp_size_t  __i;							\
+    ASSERT ((size) >= 0);						\
+    ASSERT (! MPN_OVERLAP_P (dst, size, src, size));			\
+    CRAY_Pragma ("_CRI ivdep");						\
+    for (__i = 0; __i < __size; __i++)					\
+      {									\
+	*__dst = *__src;						\
+	__dst++;							\
+	__src--;							\
+      }									\
+  } while (0)
+
+
+/* Zero n limbs at dst.
+
+   For power and powerpc we want an inline stu/bdnz loop for zeroing.  On
+   ppc630 for instance this is optimal since it can sustain only 1 store per
+   cycle.
+
+   gcc 2.95.x (for powerpc64 -maix64, or powerpc32) doesn't recognise the
+   "for" loop in the generic code below can become stu/bdnz.  The do/while
+   here helps it get to that.  The same caveat about plain -mpowerpc64 mode
+   applies here as to __GMPN_COPY_INCR in gmp.h.
+
+   xlc 3.1 already generates stu/bdnz from the generic C, and does so from
+   this loop too.
+
+   Enhancement: GLIBC does some trickery with dcbz to zero whole cache lines
+   at a time.  MPN_ZERO isn't all that important in GMP, so it might be more
+   trouble than it's worth to do the same, though perhaps a call to memset
+   would be good when on a GNU system.  */
+
+#if HAVE_HOST_CPU_FAMILY_power || HAVE_HOST_CPU_FAMILY_powerpc
+#define MPN_FILL(dst, n, f)						\
+  do {									\
+    mp_ptr __dst = (dst) - 1;						\
+    mp_size_t __n = (n);						\
+    ASSERT (__n > 0);							\
+    do									\
+      *++__dst = (f);							\
+    while (--__n);							\
+  } while (0)
+#endif
+
+#ifndef MPN_FILL
+#define MPN_FILL(dst, n, f)						\
+  do {									\
+    mp_ptr __dst = (dst);						\
+    mp_size_t __n = (n);						\
+    ASSERT (__n > 0);							\
+    do									\
+      *__dst++ = (f);							\
+    while (--__n);							\
+  } while (0)
+#endif
+
+#define MPN_ZERO(dst, n)						\
+  do {									\
+    ASSERT ((n) >= 0);							\
+    if ((n) != 0)							\
+      MPN_FILL (dst, n, CNST_LIMB (0));					\
+  } while (0)
+
+/* On the x86s repe/scasl doesn't seem useful, since it takes many cycles to
+   start up and would need to strip a lot of zeros before it'd be faster
+   than a simple cmpl loop.  Here are some times in cycles for
+   std/repe/scasl/cld and cld/repe/scasl (the latter would be for stripping
+   low zeros).
+
+		std   cld
+	   P5    18    16
+	   P6    46    38
+	   K6    36    13
+	   K7    21    20
+*/
+#ifndef MPN_NORMALIZE
+#define MPN_NORMALIZE(DST, NLIMBS) \
+  do {									\
+    while ((NLIMBS) > 0)						\
+      {									\
+	if ((DST)[(NLIMBS) - 1] != 0)					\
+	  break;							\
+	(NLIMBS)--;							\
+      }									\
+  } while (0)
+#endif
+#ifndef MPN_NORMALIZE_NOT_ZERO
+#define MPN_NORMALIZE_NOT_ZERO(DST, NLIMBS)				\
+  do {									\
+    while (1)								\
+      {									\
+	ASSERT ((NLIMBS) >= 1);						\
+	if ((DST)[(NLIMBS) - 1] != 0)					\
+	  break;							\
+	(NLIMBS)--;							\
+      }									\
+  } while (0)
+#endif
+
+/* Strip least significant zero limbs from {ptr,size} by incrementing ptr
+   and decrementing size.  low should be ptr[0], and will be the new ptr[0]
+   on returning.  The number in {ptr,size} must be non-zero, ie. size!=0 and
+   somewhere a non-zero limb.  */
+#define MPN_STRIP_LOW_ZEROS_NOT_ZERO(ptr, size, low)			\
+  do {									\
+    ASSERT ((size) >= 1);						\
+    ASSERT ((low) == (ptr)[0]);						\
+									\
+    while ((low) == 0)							\
+      {									\
+	(size)--;							\
+	ASSERT ((size) >= 1);						\
+	(ptr)++;							\
+	(low) = *(ptr);							\
+      }									\
+  } while (0)
+
+/* Initialize X of type mpz_t with space for NLIMBS limbs.  X should be a
+   temporary variable; it will be automatically cleared out at function
+   return.  We use __x here to make it possible to accept both mpz_ptr and
+   mpz_t arguments.  */
+#define MPZ_TMP_INIT(X, NLIMBS)						\
+  do {									\
+    mpz_ptr __x = (X);							\
+    ASSERT ((NLIMBS) >= 1);						\
+    __x->_mp_alloc = (NLIMBS);						\
+    __x->_mp_d = TMP_ALLOC_LIMBS (NLIMBS);				\
+  } while (0)
+
+#if WANT_ASSERT
+static inline void *
+_mpz_newalloc (mpz_ptr z, mp_size_t n)
+{
+  void * res = _mpz_realloc(z,n);
+  /* If we are checking the code, force a random change to limbs. */
+  ((mp_ptr) res)[0] = ~ ((mp_ptr) res)[ALLOC (z) - 1];
+  return res;
+}
+#else
+#define _mpz_newalloc _mpz_realloc
+#endif
+/* Realloc for an mpz_t WHAT if it has less than NEEDED limbs.  */
+#define MPZ_REALLOC(z,n) (UNLIKELY ((n) > ALLOC(z))			\
+			  ? (mp_ptr) _mpz_realloc(z,n)			\
+			  : PTR(z))
+#define MPZ_NEWALLOC(z,n) (UNLIKELY ((n) > ALLOC(z))			\
+			   ? (mp_ptr) _mpz_newalloc(z,n)		\
+			   : PTR(z))
+
+#define MPZ_EQUAL_1_P(z)  (SIZ(z)==1 && PTR(z)[0] == 1)
+
+
+/* MPN_FIB2_SIZE(n) is the size in limbs required by mpn_fib2_ui for fp and
+   f1p.
+
+   From Knuth vol 1 section 1.2.8, F[n] = phi^n/sqrt(5) rounded to the
+   nearest integer, where phi=(1+sqrt(5))/2 is the golden ratio.  So the
+   number of bits required is n*log_2((1+sqrt(5))/2) = n*0.6942419.
+
+   The multiplier used is 23/32=0.71875 for efficient calculation on CPUs
+   without good floating point.  There's +2 for rounding up, and a further
+   +2 since at the last step x limbs are doubled into a 2x+1 limb region
+   whereas the actual F[2k] value might be only 2x-1 limbs.
+
+   Note that a division is done first, since on a 32-bit system it's at
+   least conceivable to go right up to n==ULONG_MAX.  (F[2^32-1] would be
+   about 380Mbytes, plus temporary workspace of about 1.2Gbytes here and
+   whatever a multiply of two 190Mbyte numbers takes.)
+
+   Enhancement: When GMP_NUMB_BITS is not a power of 2 the division could be
+   worked into the multiplier.  */
+
+#define MPN_FIB2_SIZE(n) \
+  ((mp_size_t) ((n) / 32 * 23 / GMP_NUMB_BITS) + 4)
+
+
+/* FIB_TABLE(n) returns the Fibonacci number F[n].  Must have n in the range
+   -1 <= n <= FIB_TABLE_LIMIT (that constant in fib_table.h).
+
+   FIB_TABLE_LUCNUM_LIMIT (in fib_table.h) is the largest n for which L[n] =
+   F[n] + 2*F[n-1] fits in a limb.  */
+
+__GMP_DECLSPEC extern const mp_limb_t __gmp_fib_table[];
+#define FIB_TABLE(n)  (__gmp_fib_table[(n)+1])
+
+extern const mp_limb_t __gmp_oddfac_table[];
+extern const mp_limb_t __gmp_odd2fac_table[];
+extern const unsigned char __gmp_fac2cnt_table[];
+extern const mp_limb_t __gmp_limbroots_table[];
+
+/* n^log <= GMP_NUMB_MAX, a limb can store log factors less than n */
+static inline unsigned
+log_n_max (mp_limb_t n)
+{
+  unsigned log;
+  for (log = 8; n > __gmp_limbroots_table[log - 1]; log--);
+  return log;
+}
+
+#define SIEVESIZE 512		/* FIXME: Allow gmp_init_primesieve to choose */
+typedef struct
+{
+  unsigned long d;		   /* current index in s[] */
+  unsigned long s0;		   /* number corresponding to s[0] */
+  unsigned long sqrt_s0;	   /* misnomer for sqrt(s[SIEVESIZE-1]) */
+  unsigned char s[SIEVESIZE + 1];  /* sieve table */
+} gmp_primesieve_t;
+
+#define gmp_init_primesieve __gmp_init_primesieve
+__GMP_DECLSPEC void gmp_init_primesieve (gmp_primesieve_t *);
+
+#define gmp_nextprime __gmp_nextprime
+__GMP_DECLSPEC unsigned long int gmp_nextprime (gmp_primesieve_t *);
+
+#define gmp_primesieve __gmp_primesieve
+__GMP_DECLSPEC mp_limb_t gmp_primesieve (mp_ptr, mp_limb_t);
+
+
+#ifndef MUL_TOOM22_THRESHOLD
+#define MUL_TOOM22_THRESHOLD             30
+#endif
+
+#ifndef MUL_TOOM33_THRESHOLD
+#define MUL_TOOM33_THRESHOLD            100
+#endif
+
+#ifndef MUL_TOOM44_THRESHOLD
+#define MUL_TOOM44_THRESHOLD            300
+#endif
+
+#ifndef MUL_TOOM6H_THRESHOLD
+#define MUL_TOOM6H_THRESHOLD            350
+#endif
+
+#ifndef SQR_TOOM6_THRESHOLD
+#define SQR_TOOM6_THRESHOLD MUL_TOOM6H_THRESHOLD
+#endif
+
+#ifndef MUL_TOOM8H_THRESHOLD
+#define MUL_TOOM8H_THRESHOLD            450
+#endif
+
+#ifndef SQR_TOOM8_THRESHOLD
+#define SQR_TOOM8_THRESHOLD MUL_TOOM8H_THRESHOLD
+#endif
+
+#ifndef MUL_TOOM32_TO_TOOM43_THRESHOLD
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD  100
+#endif
+
+#ifndef MUL_TOOM32_TO_TOOM53_THRESHOLD
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD  110
+#endif
+
+#ifndef MUL_TOOM42_TO_TOOM53_THRESHOLD
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD  100
+#endif
+
+#ifndef MUL_TOOM42_TO_TOOM63_THRESHOLD
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD  110
+#endif
+
+#ifndef MUL_TOOM43_TO_TOOM54_THRESHOLD
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD  150
+#endif
+
+/* MUL_TOOM22_THRESHOLD_LIMIT is the maximum for MUL_TOOM22_THRESHOLD.  In a
+   normal build MUL_TOOM22_THRESHOLD is a constant and we use that.  In a fat
+   binary or tune program build MUL_TOOM22_THRESHOLD is a variable and a
+   separate hard limit will have been defined.  Similarly for TOOM3.  */
+#ifndef MUL_TOOM22_THRESHOLD_LIMIT
+#define MUL_TOOM22_THRESHOLD_LIMIT  MUL_TOOM22_THRESHOLD
+#endif
+#ifndef MUL_TOOM33_THRESHOLD_LIMIT
+#define MUL_TOOM33_THRESHOLD_LIMIT  MUL_TOOM33_THRESHOLD
+#endif
+#ifndef MULLO_BASECASE_THRESHOLD_LIMIT
+#define MULLO_BASECASE_THRESHOLD_LIMIT  MULLO_BASECASE_THRESHOLD
+#endif
+#ifndef SQRLO_BASECASE_THRESHOLD_LIMIT
+#define SQRLO_BASECASE_THRESHOLD_LIMIT  SQRLO_BASECASE_THRESHOLD
+#endif
+#ifndef SQRLO_DC_THRESHOLD_LIMIT
+#define SQRLO_DC_THRESHOLD_LIMIT  SQRLO_DC_THRESHOLD
+#endif
+
+/* SQR_BASECASE_THRESHOLD is where mpn_sqr_basecase should take over from
+   mpn_mul_basecase.  Default is to use mpn_sqr_basecase from 0.  (Note that we
+   certainly always want it if there's a native assembler mpn_sqr_basecase.)
+
+   If it turns out that mpn_toom2_sqr becomes faster than mpn_mul_basecase
+   before mpn_sqr_basecase does, then SQR_BASECASE_THRESHOLD is the toom2
+   threshold and SQR_TOOM2_THRESHOLD is 0.  This oddity arises more or less
+   because SQR_TOOM2_THRESHOLD represents the size up to which mpn_sqr_basecase
+   should be used, and that may be never.  */
+
+#ifndef SQR_BASECASE_THRESHOLD
+#define SQR_BASECASE_THRESHOLD            0  /* never use mpn_mul_basecase */
+#endif
+
+#ifndef SQR_TOOM2_THRESHOLD
+#define SQR_TOOM2_THRESHOLD              50
+#endif
+
+#ifndef SQR_TOOM3_THRESHOLD
+#define SQR_TOOM3_THRESHOLD             120
+#endif
+
+#ifndef SQR_TOOM4_THRESHOLD
+#define SQR_TOOM4_THRESHOLD             400
+#endif
+
+/* See comments above about MUL_TOOM33_THRESHOLD_LIMIT.  */
+#ifndef SQR_TOOM3_THRESHOLD_LIMIT
+#define SQR_TOOM3_THRESHOLD_LIMIT  SQR_TOOM3_THRESHOLD
+#endif
+
+#ifndef MULMID_TOOM42_THRESHOLD
+#define MULMID_TOOM42_THRESHOLD     MUL_TOOM22_THRESHOLD
+#endif
+
+#ifndef MULLO_BASECASE_THRESHOLD
+#define MULLO_BASECASE_THRESHOLD          0  /* never use mpn_mul_basecase */
+#endif
+
+#ifndef MULLO_DC_THRESHOLD
+#define MULLO_DC_THRESHOLD         (2*MUL_TOOM22_THRESHOLD)
+#endif
+
+#ifndef MULLO_MUL_N_THRESHOLD
+#define MULLO_MUL_N_THRESHOLD      (2*MUL_FFT_THRESHOLD)
+#endif
+
+#ifndef SQRLO_BASECASE_THRESHOLD
+#define SQRLO_BASECASE_THRESHOLD          0  /* never use mpn_sqr_basecase */
+#endif
+
+#ifndef SQRLO_DC_THRESHOLD
+#define SQRLO_DC_THRESHOLD         (MULLO_DC_THRESHOLD)
+#endif
+
+#ifndef SQRLO_SQR_THRESHOLD
+#define SQRLO_SQR_THRESHOLD        (MULLO_MUL_N_THRESHOLD)
+#endif
+
+#ifndef DC_DIV_QR_THRESHOLD
+#define DC_DIV_QR_THRESHOLD        (2*MUL_TOOM22_THRESHOLD)
+#endif
+
+#ifndef DC_DIVAPPR_Q_THRESHOLD
+#define DC_DIVAPPR_Q_THRESHOLD          200
+#endif
+
+#ifndef DC_BDIV_QR_THRESHOLD
+#define DC_BDIV_QR_THRESHOLD       (2*MUL_TOOM22_THRESHOLD)
+#endif
+
+#ifndef DC_BDIV_Q_THRESHOLD
+#define DC_BDIV_Q_THRESHOLD             180
+#endif
+
+#ifndef DIVEXACT_JEB_THRESHOLD
+#define DIVEXACT_JEB_THRESHOLD           25
+#endif
+
+#ifndef INV_MULMOD_BNM1_THRESHOLD
+#define INV_MULMOD_BNM1_THRESHOLD  (4*MULMOD_BNM1_THRESHOLD)
+#endif
+
+#ifndef INV_APPR_THRESHOLD
+#define INV_APPR_THRESHOLD         INV_NEWTON_THRESHOLD
+#endif
+
+#ifndef INV_NEWTON_THRESHOLD
+#define INV_NEWTON_THRESHOLD            200
+#endif
+
+#ifndef BINV_NEWTON_THRESHOLD
+#define BINV_NEWTON_THRESHOLD           300
+#endif
+
+#ifndef MU_DIVAPPR_Q_THRESHOLD
+#define MU_DIVAPPR_Q_THRESHOLD         2000
+#endif
+
+#ifndef MU_DIV_QR_THRESHOLD
+#define MU_DIV_QR_THRESHOLD            2000
+#endif
+
+#ifndef MUPI_DIV_QR_THRESHOLD
+#define MUPI_DIV_QR_THRESHOLD           200
+#endif
+
+#ifndef MU_BDIV_Q_THRESHOLD
+#define MU_BDIV_Q_THRESHOLD            2000
+#endif
+
+#ifndef MU_BDIV_QR_THRESHOLD
+#define MU_BDIV_QR_THRESHOLD           2000
+#endif
+
+#ifndef MULMOD_BNM1_THRESHOLD
+#define MULMOD_BNM1_THRESHOLD            16
+#endif
+
+#ifndef SQRMOD_BNM1_THRESHOLD
+#define SQRMOD_BNM1_THRESHOLD            16
+#endif
+
+#ifndef MUL_TO_MULMOD_BNM1_FOR_2NXN_THRESHOLD
+#define MUL_TO_MULMOD_BNM1_FOR_2NXN_THRESHOLD  (INV_MULMOD_BNM1_THRESHOLD/2)
+#endif
+
+#if HAVE_NATIVE_mpn_addmul_2 || HAVE_NATIVE_mpn_redc_2
+
+#ifndef REDC_1_TO_REDC_2_THRESHOLD
+#define REDC_1_TO_REDC_2_THRESHOLD       15
+#endif
+#ifndef REDC_2_TO_REDC_N_THRESHOLD
+#define REDC_2_TO_REDC_N_THRESHOLD      100
+#endif
+
+#else
+
+#ifndef REDC_1_TO_REDC_N_THRESHOLD
+#define REDC_1_TO_REDC_N_THRESHOLD      100
+#endif
+
+#endif /* HAVE_NATIVE_mpn_addmul_2 || HAVE_NATIVE_mpn_redc_2 */
+
+
+/* First k to use for an FFT modF multiply.  A modF FFT is an order
+   log(2^k)/log(2^(k-1)) algorithm, so k=3 is merely 1.5 like karatsuba,
+   whereas k=4 is 1.33 which is faster than toom3 at 1.485.    */
+#define FFT_FIRST_K  4
+
+/* Threshold at which FFT should be used to do a modF NxN -> N multiply. */
+#ifndef MUL_FFT_MODF_THRESHOLD
+#define MUL_FFT_MODF_THRESHOLD   (MUL_TOOM33_THRESHOLD * 3)
+#endif
+#ifndef SQR_FFT_MODF_THRESHOLD
+#define SQR_FFT_MODF_THRESHOLD   (SQR_TOOM3_THRESHOLD * 3)
+#endif
+
+/* Threshold at which FFT should be used to do an NxN -> 2N multiply.  This
+   will be a size where FFT is using k=7 or k=8, since an FFT-k used for an
+   NxN->2N multiply and not recursing into itself is an order
+   log(2^k)/log(2^(k-2)) algorithm, so it'll be at least k=7 at 1.39 which
+   is the first better than toom3.  */
+#ifndef MUL_FFT_THRESHOLD
+#define MUL_FFT_THRESHOLD   (MUL_FFT_MODF_THRESHOLD * 10)
+#endif
+#ifndef SQR_FFT_THRESHOLD
+#define SQR_FFT_THRESHOLD   (SQR_FFT_MODF_THRESHOLD * 10)
+#endif
+
+/* Table of thresholds for successive modF FFT "k"s.  The first entry is
+   where FFT_FIRST_K+1 should be used, the second FFT_FIRST_K+2,
+   etc.  See mpn_fft_best_k(). */
+#ifndef MUL_FFT_TABLE
+#define MUL_FFT_TABLE							\
+  { MUL_TOOM33_THRESHOLD * 4,   /* k=5 */				\
+    MUL_TOOM33_THRESHOLD * 8,   /* k=6 */				\
+    MUL_TOOM33_THRESHOLD * 16,  /* k=7 */				\
+    MUL_TOOM33_THRESHOLD * 32,  /* k=8 */				\
+    MUL_TOOM33_THRESHOLD * 96,  /* k=9 */				\
+    MUL_TOOM33_THRESHOLD * 288, /* k=10 */				\
+    0 }
+#endif
+#ifndef SQR_FFT_TABLE
+#define SQR_FFT_TABLE							\
+  { SQR_TOOM3_THRESHOLD * 4,   /* k=5 */				\
+    SQR_TOOM3_THRESHOLD * 8,   /* k=6 */				\
+    SQR_TOOM3_THRESHOLD * 16,  /* k=7 */				\
+    SQR_TOOM3_THRESHOLD * 32,  /* k=8 */				\
+    SQR_TOOM3_THRESHOLD * 96,  /* k=9 */				\
+    SQR_TOOM3_THRESHOLD * 288, /* k=10 */				\
+    0 }
+#endif
+
+struct fft_table_nk
+{
+  gmp_uint_least32_t n:27;
+  gmp_uint_least32_t k:5;
+};
+
+#ifndef FFT_TABLE_ATTRS
+#define FFT_TABLE_ATTRS   static const
+#endif
+
+#define MPN_FFT_TABLE_SIZE  16
+
+
+#ifndef DC_DIV_QR_THRESHOLD
+#define DC_DIV_QR_THRESHOLD    (3 * MUL_TOOM22_THRESHOLD)
+#endif
+
+#ifndef GET_STR_DC_THRESHOLD
+#define GET_STR_DC_THRESHOLD             18
+#endif
+
+#ifndef GET_STR_PRECOMPUTE_THRESHOLD
+#define GET_STR_PRECOMPUTE_THRESHOLD     35
+#endif
+
+#ifndef SET_STR_DC_THRESHOLD
+#define SET_STR_DC_THRESHOLD            750
+#endif
+
+#ifndef SET_STR_PRECOMPUTE_THRESHOLD
+#define SET_STR_PRECOMPUTE_THRESHOLD   2000
+#endif
+
+#ifndef FAC_ODD_THRESHOLD
+#define FAC_ODD_THRESHOLD    35
+#endif
+
+#ifndef FAC_DSC_THRESHOLD
+#define FAC_DSC_THRESHOLD   400
+#endif
+
+/* Return non-zero if xp,xsize and yp,ysize overlap.
+   If xp+xsize<=yp there's no overlap, or if yp+ysize<=xp there's no
+   overlap.  If both these are false, there's an overlap. */
+#define MPN_OVERLAP_P(xp, xsize, yp, ysize)				\
+  ((xp) + (xsize) > (yp) && (yp) + (ysize) > (xp))
+#define MEM_OVERLAP_P(xp, xsize, yp, ysize)				\
+  (   (char *) (xp) + (xsize) > (char *) (yp)				\
+   && (char *) (yp) + (ysize) > (char *) (xp))
+
+/* Return non-zero if xp,xsize and yp,ysize are either identical or not
+   overlapping.  Return zero if they're partially overlapping. */
+#define MPN_SAME_OR_SEPARATE_P(xp, yp, size)				\
+  MPN_SAME_OR_SEPARATE2_P(xp, size, yp, size)
+#define MPN_SAME_OR_SEPARATE2_P(xp, xsize, yp, ysize)			\
+  ((xp) == (yp) || ! MPN_OVERLAP_P (xp, xsize, yp, ysize))
+
+/* Return non-zero if dst,dsize and src,ssize are either identical or
+   overlapping in a way suitable for an incrementing/decrementing algorithm.
+   Return zero if they're partially overlapping in an unsuitable fashion. */
+#define MPN_SAME_OR_INCR2_P(dst, dsize, src, ssize)			\
+  ((dst) <= (src) || ! MPN_OVERLAP_P (dst, dsize, src, ssize))
+#define MPN_SAME_OR_INCR_P(dst, src, size)				\
+  MPN_SAME_OR_INCR2_P(dst, size, src, size)
+#define MPN_SAME_OR_DECR2_P(dst, dsize, src, ssize)			\
+  ((dst) >= (src) || ! MPN_OVERLAP_P (dst, dsize, src, ssize))
+#define MPN_SAME_OR_DECR_P(dst, src, size)				\
+  MPN_SAME_OR_DECR2_P(dst, size, src, size)
+
+
+/* ASSERT() is a private assertion checking scheme, similar to <assert.h>.
+   ASSERT() does the check only if WANT_ASSERT is selected, ASSERT_ALWAYS()
+   does it always.  Generally assertions are meant for development, but
+   might help when looking for a problem later too.  */
+
+#ifdef __LINE__
+#define ASSERT_LINE  __LINE__
+#else
+#define ASSERT_LINE  -1
+#endif
+
+#ifdef __FILE__
+#define ASSERT_FILE  __FILE__
+#else
+#define ASSERT_FILE  ""
+#endif
+
+__GMP_DECLSPEC void __gmp_assert_header (const char *, int);
+__GMP_DECLSPEC void __gmp_assert_fail (const char *, int, const char *) ATTRIBUTE_NORETURN;
+
+#define ASSERT_FAIL(expr)  __gmp_assert_fail (ASSERT_FILE, ASSERT_LINE, #expr)
+
+#define ASSERT_ALWAYS(expr)						\
+  do {									\
+    if (UNLIKELY (!(expr)))						\
+      ASSERT_FAIL (expr);						\
+  } while (0)
+
+#if WANT_ASSERT
+#define ASSERT(expr)   ASSERT_ALWAYS (expr)
+#else
+#define ASSERT(expr)   do {} while (0)
+#endif
+
+
+/* ASSERT_CARRY checks the expression is non-zero, and ASSERT_NOCARRY checks
+   that it's zero.  In both cases if assertion checking is disabled the
+   expression is still evaluated.  These macros are meant for use with
+   routines like mpn_add_n() where the return value represents a carry or
+   whatever that should or shouldn't occur in some context.  For example,
+   ASSERT_NOCARRY (mpn_add_n (rp, s1p, s2p, size)); */
+#if WANT_ASSERT
+#define ASSERT_CARRY(expr)     ASSERT_ALWAYS ((expr) != 0)
+#define ASSERT_NOCARRY(expr)   ASSERT_ALWAYS ((expr) == 0)
+#else
+#define ASSERT_CARRY(expr)     (expr)
+#define ASSERT_NOCARRY(expr)   (expr)
+#endif
+
+
+/* ASSERT_CODE includes code when assertion checking is wanted.  This is the
+   same as writing "#if WANT_ASSERT", but more compact.  */
+#if WANT_ASSERT
+#define ASSERT_CODE(expr)  expr
+#else
+#define ASSERT_CODE(expr)
+#endif
+
+
+/* Test that an mpq_t is in fully canonical form.  This can be used as
+   protection on routines like mpq_equal which give wrong results on
+   non-canonical inputs.  */
+#if WANT_ASSERT
+#define ASSERT_MPQ_CANONICAL(q)						\
+  do {									\
+    ASSERT (q->_mp_den._mp_size > 0);					\
+    if (q->_mp_num._mp_size == 0)					\
+      {									\
+	/* zero should be 0/1 */					\
+	ASSERT (mpz_cmp_ui (mpq_denref(q), 1L) == 0);			\
+      }									\
+    else								\
+      {									\
+	/* no common factors */						\
+	mpz_t  __g;							\
+	mpz_init (__g);							\
+	mpz_gcd (__g, mpq_numref(q), mpq_denref(q));			\
+	ASSERT (mpz_cmp_ui (__g, 1) == 0);				\
+	mpz_clear (__g);						\
+      }									\
+  } while (0)
+#else
+#define ASSERT_MPQ_CANONICAL(q)	 do {} while (0)
+#endif
+
+/* Check that the nail parts are zero. */
+#define ASSERT_ALWAYS_LIMB(limb)					\
+  do {									\
+    mp_limb_t  __nail = (limb) & GMP_NAIL_MASK;				\
+    ASSERT_ALWAYS (__nail == 0);					\
+  } while (0)
+#define ASSERT_ALWAYS_MPN(ptr, size)					\
+  do {									\
+    /* let whole loop go dead when no nails */				\
+    if (GMP_NAIL_BITS != 0)						\
+      {									\
+	mp_size_t  __i;							\
+	for (__i = 0; __i < (size); __i++)				\
+	  ASSERT_ALWAYS_LIMB ((ptr)[__i]);				\
+      }									\
+  } while (0)
+#if WANT_ASSERT
+#define ASSERT_LIMB(limb)       ASSERT_ALWAYS_LIMB (limb)
+#define ASSERT_MPN(ptr, size)   ASSERT_ALWAYS_MPN (ptr, size)
+#else
+#define ASSERT_LIMB(limb)       do {} while (0)
+#define ASSERT_MPN(ptr, size)   do {} while (0)
+#endif
+
+
+/* Assert that an mpn region {ptr,size} is zero, or non-zero.
+   size==0 is allowed, and in that case {ptr,size} considered to be zero.  */
+#if WANT_ASSERT
+#define ASSERT_MPN_ZERO_P(ptr,size)					\
+  do {									\
+    mp_size_t  __i;							\
+    ASSERT ((size) >= 0);						\
+    for (__i = 0; __i < (size); __i++)					\
+      ASSERT ((ptr)[__i] == 0);						\
+  } while (0)
+#define ASSERT_MPN_NONZERO_P(ptr,size)					\
+  do {									\
+    mp_size_t  __i;							\
+    int	       __nonzero = 0;						\
+    ASSERT ((size) >= 0);						\
+    for (__i = 0; __i < (size); __i++)					\
+      if ((ptr)[__i] != 0)						\
+	{								\
+	  __nonzero = 1;						\
+	  break;							\
+	}								\
+    ASSERT (__nonzero);							\
+  } while (0)
+#else
+#define ASSERT_MPN_ZERO_P(ptr,size)     do {} while (0)
+#define ASSERT_MPN_NONZERO_P(ptr,size)  do {} while (0)
+#endif
+
+
+#if ! HAVE_NATIVE_mpn_com
+#undef mpn_com
+#define mpn_com(d,s,n)							\
+  do {									\
+    mp_ptr     __d = (d);						\
+    mp_srcptr  __s = (s);						\
+    mp_size_t  __n = (n);						\
+    ASSERT (__n >= 1);							\
+    ASSERT (MPN_SAME_OR_SEPARATE_P (__d, __s, __n));			\
+    do									\
+      *__d++ = (~ *__s++) & GMP_NUMB_MASK;				\
+    while (--__n);							\
+  } while (0)
+#endif
+
+#define MPN_LOGOPS_N_INLINE(rp, up, vp, n, operation)			\
+  do {									\
+    mp_srcptr	__up = (up);						\
+    mp_srcptr	__vp = (vp);						\
+    mp_ptr	__rp = (rp);						\
+    mp_size_t	__n = (n);						\
+    mp_limb_t __a, __b;							\
+    ASSERT (__n > 0);							\
+    ASSERT (MPN_SAME_OR_SEPARATE_P (__rp, __up, __n));			\
+    ASSERT (MPN_SAME_OR_SEPARATE_P (__rp, __vp, __n));			\
+    __up += __n;							\
+    __vp += __n;							\
+    __rp += __n;							\
+    __n = -__n;								\
+    do {								\
+      __a = __up[__n];							\
+      __b = __vp[__n];							\
+      __rp[__n] = operation;						\
+    } while (++__n);							\
+  } while (0)
+
+
+#if ! HAVE_NATIVE_mpn_and_n
+#undef mpn_and_n
+#define mpn_and_n(rp, up, vp, n) \
+  MPN_LOGOPS_N_INLINE (rp, up, vp, n, __a & __b)
+#endif
+
+#if ! HAVE_NATIVE_mpn_andn_n
+#undef mpn_andn_n
+#define mpn_andn_n(rp, up, vp, n) \
+  MPN_LOGOPS_N_INLINE (rp, up, vp, n, __a & ~__b)
+#endif
+
+#if ! HAVE_NATIVE_mpn_nand_n
+#undef mpn_nand_n
+#define mpn_nand_n(rp, up, vp, n) \
+  MPN_LOGOPS_N_INLINE (rp, up, vp, n, ~(__a & __b) & GMP_NUMB_MASK)
+#endif
+
+#if ! HAVE_NATIVE_mpn_ior_n
+#undef mpn_ior_n
+#define mpn_ior_n(rp, up, vp, n) \
+  MPN_LOGOPS_N_INLINE (rp, up, vp, n, __a | __b)
+#endif
+
+#if ! HAVE_NATIVE_mpn_iorn_n
+#undef mpn_iorn_n
+#define mpn_iorn_n(rp, up, vp, n) \
+  MPN_LOGOPS_N_INLINE (rp, up, vp, n, (__a | ~__b) & GMP_NUMB_MASK)
+#endif
+
+#if ! HAVE_NATIVE_mpn_nior_n
+#undef mpn_nior_n
+#define mpn_nior_n(rp, up, vp, n) \
+  MPN_LOGOPS_N_INLINE (rp, up, vp, n, ~(__a | __b) & GMP_NUMB_MASK)
+#endif
+
+#if ! HAVE_NATIVE_mpn_xor_n
+#undef mpn_xor_n
+#define mpn_xor_n(rp, up, vp, n) \
+  MPN_LOGOPS_N_INLINE (rp, up, vp, n, __a ^ __b)
+#endif
+
+#if ! HAVE_NATIVE_mpn_xnor_n
+#undef mpn_xnor_n
+#define mpn_xnor_n(rp, up, vp, n) \
+  MPN_LOGOPS_N_INLINE (rp, up, vp, n, ~(__a ^ __b) & GMP_NUMB_MASK)
+#endif
+
+#define mpn_trialdiv __MPN(trialdiv)
+__GMP_DECLSPEC mp_limb_t mpn_trialdiv (mp_srcptr, mp_size_t, mp_size_t, int *);
+
+#define mpn_remove __MPN(remove)
+__GMP_DECLSPEC mp_bitcnt_t mpn_remove (mp_ptr, mp_size_t *, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_bitcnt_t);
+
+
+/* ADDC_LIMB sets w=x+y and cout to 0 or 1 for a carry from that addition. */
+#if GMP_NAIL_BITS == 0
+#define ADDC_LIMB(cout, w, x, y)					\
+  do {									\
+    mp_limb_t  __x = (x);						\
+    mp_limb_t  __y = (y);						\
+    mp_limb_t  __w = __x + __y;						\
+    (w) = __w;								\
+    (cout) = __w < __x;							\
+  } while (0)
+#else
+#define ADDC_LIMB(cout, w, x, y)					\
+  do {									\
+    mp_limb_t  __w;							\
+    ASSERT_LIMB (x);							\
+    ASSERT_LIMB (y);							\
+    __w = (x) + (y);							\
+    (w) = __w & GMP_NUMB_MASK;						\
+    (cout) = __w >> GMP_NUMB_BITS;					\
+  } while (0)
+#endif
+
+/* SUBC_LIMB sets w=x-y and cout to 0 or 1 for a borrow from that
+   subtract.  */
+#if GMP_NAIL_BITS == 0
+#define SUBC_LIMB(cout, w, x, y)					\
+  do {									\
+    mp_limb_t  __x = (x);						\
+    mp_limb_t  __y = (y);						\
+    mp_limb_t  __w = __x - __y;						\
+    (w) = __w;								\
+    (cout) = __w > __x;							\
+  } while (0)
+#else
+#define SUBC_LIMB(cout, w, x, y)					\
+  do {									\
+    mp_limb_t  __w = (x) - (y);						\
+    (w) = __w & GMP_NUMB_MASK;						\
+    (cout) = __w >> (GMP_LIMB_BITS-1);					\
+  } while (0)
+#endif
+
+
+/* MPN_INCR_U does {ptr,size} += n, MPN_DECR_U does {ptr,size} -= n, both
+   expecting no carry (or borrow) from that.
+
+   The size parameter is only for the benefit of assertion checking.  In a
+   normal build it's unused and the carry/borrow is just propagated as far
+   as it needs to go.
+
+   On random data, usually only one or two limbs of {ptr,size} get updated,
+   so there's no need for any sophisticated looping, just something compact
+   and sensible.
+
+   FIXME: Switch all code from mpn_{incr,decr}_u to MPN_{INCR,DECR}_U,
+   declaring their operand sizes, then remove the former.  This is purely
+   for the benefit of assertion checking.  */
+
+#if defined (__GNUC__) && GMP_NAIL_BITS == 0 && ! defined (NO_ASM)	\
+  && (defined(HAVE_HOST_CPU_FAMILY_x86) || defined(HAVE_HOST_CPU_FAMILY_x86_64)) \
+  && ! WANT_ASSERT
+/* Better flags handling than the generic C gives on i386, saving a few
+   bytes of code and maybe a cycle or two.  */
+
+#define MPN_IORD_U(ptr, incr, aors)					\
+  do {									\
+    mp_ptr  __ptr_dummy;						\
+    if (__builtin_constant_p (incr) && (incr) == 0)			\
+      {									\
+      }									\
+    else if (__builtin_constant_p (incr) && (incr) == 1)		\
+      {									\
+	__asm__ __volatile__						\
+	  ("\n" ASM_L(top) ":\n"					\
+	   "\t" aors "\t$1, (%0)\n"					\
+	   "\tlea\t%c2(%0), %0\n"					\
+	   "\tjc\t" ASM_L(top)						\
+	   : "=r" (__ptr_dummy)						\
+	   : "0"  (ptr), "n" (sizeof(mp_limb_t))			\
+	   : "memory");							\
+      }									\
+    else								\
+      {									\
+	__asm__ __volatile__						\
+	  (   aors  "\t%2, (%0)\n"					\
+	   "\tjnc\t" ASM_L(done) "\n"					\
+	   ASM_L(top) ":\n"						\
+	   "\t" aors "\t$1, %c3(%0)\n"					\
+	   "\tlea\t%c3(%0), %0\n"					\
+	   "\tjc\t" ASM_L(top) "\n"					\
+	   ASM_L(done) ":\n"						\
+	   : "=r" (__ptr_dummy)						\
+	   : "0"  (ptr),						\
+	     "re" ((mp_limb_t) (incr)), "n" (sizeof(mp_limb_t))		\
+	   : "memory");							\
+      }									\
+  } while (0)
+
+#if GMP_LIMB_BITS == 32
+#define MPN_INCR_U(ptr, size, incr)  MPN_IORD_U (ptr, incr, "addl")
+#define MPN_DECR_U(ptr, size, incr)  MPN_IORD_U (ptr, incr, "subl")
+#endif
+#if GMP_LIMB_BITS == 64
+#define MPN_INCR_U(ptr, size, incr)  MPN_IORD_U (ptr, incr, "addq")
+#define MPN_DECR_U(ptr, size, incr)  MPN_IORD_U (ptr, incr, "subq")
+#endif
+#define mpn_incr_u(ptr, incr)  MPN_INCR_U (ptr, 0, incr)
+#define mpn_decr_u(ptr, incr)  MPN_DECR_U (ptr, 0, incr)
+#endif
+
+#if GMP_NAIL_BITS == 0
+#ifndef mpn_incr_u
+#define mpn_incr_u(p,incr)						\
+  do {									\
+    mp_limb_t __x;							\
+    mp_ptr __p = (p);							\
+    if (__builtin_constant_p (incr) && (incr) == 1)			\
+      {									\
+	while (++(*(__p++)) == 0)					\
+	  ;								\
+      }									\
+    else								\
+      {									\
+	__x = *__p + (incr);						\
+	*__p = __x;							\
+	if (__x < (incr))						\
+	  while (++(*(++__p)) == 0)					\
+	    ;								\
+      }									\
+  } while (0)
+#endif
+#ifndef mpn_decr_u
+#define mpn_decr_u(p,incr)						\
+  do {									\
+    mp_limb_t __x;							\
+    mp_ptr __p = (p);							\
+    if (__builtin_constant_p (incr) && (incr) == 1)			\
+      {									\
+	while ((*(__p++))-- == 0)					\
+	  ;								\
+      }									\
+    else								\
+      {									\
+	__x = *__p;							\
+	*__p = __x - (incr);						\
+	if (__x < (incr))						\
+	  while ((*(++__p))-- == 0)					\
+	    ;								\
+      }									\
+  } while (0)
+#endif
+#endif
+
+#if GMP_NAIL_BITS >= 1
+#ifndef mpn_incr_u
+#define mpn_incr_u(p,incr)						\
+  do {									\
+    mp_limb_t __x;							\
+    mp_ptr __p = (p);							\
+    if (__builtin_constant_p (incr) && (incr) == 1)			\
+      {									\
+	do								\
+	  {								\
+	    __x = (*__p + 1) & GMP_NUMB_MASK;				\
+	    *__p++ = __x;						\
+	  }								\
+	while (__x == 0);						\
+      }									\
+    else								\
+      {									\
+	__x = (*__p + (incr));						\
+	*__p++ = __x & GMP_NUMB_MASK;					\
+	if (__x >> GMP_NUMB_BITS != 0)					\
+	  {								\
+	    do								\
+	      {								\
+		__x = (*__p + 1) & GMP_NUMB_MASK;			\
+		*__p++ = __x;						\
+	      }								\
+	    while (__x == 0);						\
+	  }								\
+      }									\
+  } while (0)
+#endif
+#ifndef mpn_decr_u
+#define mpn_decr_u(p,incr)						\
+  do {									\
+    mp_limb_t __x;							\
+    mp_ptr __p = (p);							\
+    if (__builtin_constant_p (incr) && (incr) == 1)			\
+      {									\
+	do								\
+	  {								\
+	    __x = *__p;							\
+	    *__p++ = (__x - 1) & GMP_NUMB_MASK;				\
+	  }								\
+	while (__x == 0);						\
+      }									\
+    else								\
+      {									\
+	__x = *__p - (incr);						\
+	*__p++ = __x & GMP_NUMB_MASK;					\
+	if (__x >> GMP_NUMB_BITS != 0)					\
+	  {								\
+	    do								\
+	      {								\
+		__x = *__p;						\
+		*__p++ = (__x - 1) & GMP_NUMB_MASK;			\
+	      }								\
+	    while (__x == 0);						\
+	  }								\
+      }									\
+  } while (0)
+#endif
+#endif
+
+#ifndef MPN_INCR_U
+#if WANT_ASSERT
+#define MPN_INCR_U(ptr, size, n)					\
+  do {									\
+    ASSERT ((size) >= 1);						\
+    ASSERT_NOCARRY (mpn_add_1 (ptr, ptr, size, n));			\
+  } while (0)
+#else
+#define MPN_INCR_U(ptr, size, n)   mpn_incr_u (ptr, n)
+#endif
+#endif
+
+#ifndef MPN_DECR_U
+#if WANT_ASSERT
+#define MPN_DECR_U(ptr, size, n)					\
+  do {									\
+    ASSERT ((size) >= 1);						\
+    ASSERT_NOCARRY (mpn_sub_1 (ptr, ptr, size, n));			\
+  } while (0)
+#else
+#define MPN_DECR_U(ptr, size, n)   mpn_decr_u (ptr, n)
+#endif
+#endif
+
+
+/* Structure for conversion between internal binary format and strings.  */
+struct bases
+{
+  /* Number of digits in the conversion base that always fits in an mp_limb_t.
+     For example, for base 10 on a machine where an mp_limb_t has 32 bits this
+     is 9, since 10**9 is the largest number that fits into an mp_limb_t.  */
+  int chars_per_limb;
+
+  /* log(2)/log(conversion_base) */
+  mp_limb_t logb2;
+
+  /* log(conversion_base)/log(2) */
+  mp_limb_t log2b;
+
+  /* base**chars_per_limb, i.e. the biggest number that fits a word, built by
+     factors of base.  Exception: For 2, 4, 8, etc, big_base is log2(base),
+     i.e. the number of bits used to represent each digit in the base.  */
+  mp_limb_t big_base;
+
+  /* A GMP_LIMB_BITS bit approximation to 1/big_base, represented as a
+     fixed-point number.  Instead of dividing by big_base an application can
+     choose to multiply by big_base_inverted.  */
+  mp_limb_t big_base_inverted;
+};
+
+#define   mp_bases __MPN(bases)
+__GMP_DECLSPEC extern const struct bases mp_bases[257];
+
+
+/* Compute the number of digits in base for nbits bits, making sure the result
+   is never too small.  The two variants of the macro implement the same
+   function; the GT2 variant below works just for bases > 2.  */
+#define DIGITS_IN_BASE_FROM_BITS(res, nbits, b)				\
+  do {									\
+    mp_limb_t _ph, _dummy;						\
+    size_t _nbits = (nbits);						\
+    umul_ppmm (_ph, _dummy, mp_bases[b].logb2, _nbits);			\
+    _ph += (_dummy + _nbits < _dummy);					\
+    res = _ph + 1;							\
+  } while (0)
+#define DIGITS_IN_BASEGT2_FROM_BITS(res, nbits, b)			\
+  do {									\
+    mp_limb_t _ph, _dummy;						\
+    size_t _nbits = (nbits);						\
+    umul_ppmm (_ph, _dummy, mp_bases[b].logb2 + 1, _nbits);		\
+    res = _ph + 1;							\
+  } while (0)
+
+/* For power of 2 bases this is exact.  For other bases the result is either
+   exact or one too big.
+
+   To be exact always it'd be necessary to examine all the limbs of the
+   operand, since numbers like 100..000 and 99...999 generally differ only
+   in the lowest limb.  It'd be possible to examine just a couple of high
+   limbs to increase the probability of being exact, but that doesn't seem
+   worth bothering with.  */
+
+#define MPN_SIZEINBASE(result, ptr, size, base)				\
+  do {									\
+    int	   __lb_base, __cnt;						\
+    size_t __totbits;							\
+									\
+    ASSERT ((size) >= 0);						\
+    ASSERT ((base) >= 2);						\
+    ASSERT ((base) < numberof (mp_bases));				\
+									\
+    /* Special case for X == 0.  */					\
+    if ((size) == 0)							\
+      (result) = 1;							\
+    else								\
+      {									\
+	/* Calculate the total number of significant bits of X.  */	\
+	count_leading_zeros (__cnt, (ptr)[(size)-1]);			\
+	__totbits = (size_t) (size) * GMP_NUMB_BITS - (__cnt - GMP_NAIL_BITS);\
+									\
+	if (POW2_P (base))						\
+	  {								\
+	    __lb_base = mp_bases[base].big_base;			\
+	    (result) = (__totbits + __lb_base - 1) / __lb_base;		\
+	  }								\
+	else								\
+	  {								\
+	    DIGITS_IN_BASEGT2_FROM_BITS (result, __totbits, base);	\
+	  }								\
+      }									\
+  } while (0)
+
+#define MPN_SIZEINBASE_2EXP(result, ptr, size, base2exp)			\
+  do {										\
+    int          __cnt;								\
+    mp_bitcnt_t  __totbits;							\
+    ASSERT ((size) > 0);							\
+    ASSERT ((ptr)[(size)-1] != 0);						\
+    count_leading_zeros (__cnt, (ptr)[(size)-1]);				\
+    __totbits = (mp_bitcnt_t) (size) * GMP_NUMB_BITS - (__cnt - GMP_NAIL_BITS);	\
+    (result) = (__totbits + (base2exp)-1) / (base2exp);				\
+  } while (0)
+
+
+/* bit count to limb count, rounding up */
+#define BITS_TO_LIMBS(n)  (((n) + (GMP_NUMB_BITS - 1)) / GMP_NUMB_BITS)
+
+/* MPN_SET_UI sets an mpn (ptr, cnt) to given ui.  MPZ_FAKE_UI creates fake
+   mpz_t from ui.  The zp argument must have room for LIMBS_PER_ULONG limbs
+   in both cases (LIMBS_PER_ULONG is also defined here.) */
+#if BITS_PER_ULONG <= GMP_NUMB_BITS /* need one limb per ulong */
+
+#define LIMBS_PER_ULONG 1
+#define MPN_SET_UI(zp, zn, u)						\
+  (zp)[0] = (u);							\
+  (zn) = ((zp)[0] != 0);
+#define MPZ_FAKE_UI(z, zp, u)						\
+  (zp)[0] = (u);							\
+  PTR (z) = (zp);							\
+  SIZ (z) = ((zp)[0] != 0);						\
+  ASSERT_CODE (ALLOC (z) = 1);
+
+#else /* need two limbs per ulong */
+
+#define LIMBS_PER_ULONG 2
+#define MPN_SET_UI(zp, zn, u)						\
+  (zp)[0] = (u) & GMP_NUMB_MASK;					\
+  (zp)[1] = (u) >> GMP_NUMB_BITS;					\
+  (zn) = ((zp)[1] != 0 ? 2 : (zp)[0] != 0 ? 1 : 0);
+#define MPZ_FAKE_UI(z, zp, u)						\
+  (zp)[0] = (u) & GMP_NUMB_MASK;					\
+  (zp)[1] = (u) >> GMP_NUMB_BITS;					\
+  SIZ (z) = ((zp)[1] != 0 ? 2 : (zp)[0] != 0 ? 1 : 0);			\
+  PTR (z) = (zp);							\
+  ASSERT_CODE (ALLOC (z) = 2);
+
+#endif
+
+
+#if HAVE_HOST_CPU_FAMILY_x86
+#define TARGET_REGISTER_STARVED 1
+#else
+#define TARGET_REGISTER_STARVED 0
+#endif
+
+
+/* LIMB_HIGHBIT_TO_MASK(n) examines the high bit of a limb value and turns 1
+   or 0 there into a limb 0xFF..FF or 0 respectively.
+
+   On most CPUs this is just an arithmetic right shift by GMP_LIMB_BITS-1,
+   but C99 doesn't guarantee signed right shifts are arithmetic, so we have
+   a little compile-time test and a fallback to a "? :" form.  The latter is
+   necessary for instance on Cray vector systems.
+
+   Recent versions of gcc (eg. 3.3) will in fact optimize a "? :" like this
+   to an arithmetic right shift anyway, but it's good to get the desired
+   shift on past versions too (in particular since an important use of
+   LIMB_HIGHBIT_TO_MASK is in udiv_qrnnd_preinv).  */
+
+#define LIMB_HIGHBIT_TO_MASK(n)						\
+  (((mp_limb_signed_t) -1 >> 1) < 0					\
+   ? (mp_limb_signed_t) (n) >> (GMP_LIMB_BITS - 1)			\
+   : (n) & GMP_LIMB_HIGHBIT ? MP_LIMB_T_MAX : CNST_LIMB(0))
+
+
+/* Use a library function for invert_limb, if available. */
+#define  mpn_invert_limb __MPN(invert_limb)
+__GMP_DECLSPEC mp_limb_t mpn_invert_limb (mp_limb_t) ATTRIBUTE_CONST;
+#if ! defined (invert_limb) && HAVE_NATIVE_mpn_invert_limb
+#define invert_limb(invxl,xl)						\
+  do {									\
+    (invxl) = mpn_invert_limb (xl);					\
+  } while (0)
+#endif
+
+#ifndef invert_limb
+#define invert_limb(invxl,xl)						\
+  do {									\
+    mp_limb_t _dummy;							\
+    ASSERT ((xl) != 0);							\
+    udiv_qrnnd (invxl, _dummy, ~(xl), ~CNST_LIMB(0), xl);		\
+  } while (0)
+#endif
+
+#define invert_pi1(dinv, d1, d0)					\
+  do {									\
+    mp_limb_t _v, _p, _t1, _t0, _mask;					\
+    invert_limb (_v, d1);						\
+    _p = (d1) * _v;							\
+    _p += (d0);								\
+    if (_p < (d0))							\
+      {									\
+	_v--;								\
+	_mask = -(mp_limb_t) (_p >= (d1));				\
+	_p -= (d1);							\
+	_v += _mask;							\
+	_p -= _mask & (d1);						\
+      }									\
+    umul_ppmm (_t1, _t0, d0, _v);					\
+    _p += _t1;								\
+    if (_p < _t1)							\
+      {									\
+	_v--;								\
+	if (UNLIKELY (_p >= (d1)))					\
+	  {								\
+	    if (_p > (d1) || _t0 >= (d0))				\
+	      _v--;							\
+	  }								\
+      }									\
+    (dinv).inv32 = _v;							\
+  } while (0)
+
+
+/* udiv_qrnnd_preinv -- Based on work by Niels Möller and Torbjörn Granlund.
+   We write things strangely below, to help gcc.  A more straightforward
+   version:
+	_r = (nl) - _qh * (d);
+	_t = _r + (d);
+	if (_r >= _ql)
+	  {
+	    _qh--;
+	    _r = _t;
+	  }
+   For one operation shorter critical path, one may want to use this form:
+	_p = _qh * (d)
+	_s = (nl) + (d);
+	_r = (nl) - _p;
+	_t = _s - _p;
+	if (_r >= _ql)
+	  {
+	    _qh--;
+	    _r = _t;
+	  }
+*/
+#define udiv_qrnnd_preinv(q, r, nh, nl, d, di)				\
+  do {									\
+    mp_limb_t _qh, _ql, _r, _mask;					\
+    umul_ppmm (_qh, _ql, (nh), (di));					\
+    if (__builtin_constant_p (nl) && (nl) == 0)				\
+      {									\
+	_qh += (nh) + 1;						\
+	_r = - _qh * (d);						\
+	_mask = -(mp_limb_t) (_r > _ql); /* both > and >= are OK */	\
+	_qh += _mask;							\
+	_r += _mask & (d);						\
+      }									\
+    else								\
+      {									\
+	add_ssaaaa (_qh, _ql, _qh, _ql, (nh) + 1, (nl));		\
+	_r = (nl) - _qh * (d);						\
+	_mask = -(mp_limb_t) (_r > _ql); /* both > and >= are OK */	\
+	_qh += _mask;							\
+	_r += _mask & (d);						\
+	if (UNLIKELY (_r >= (d)))					\
+	  {								\
+	    _r -= (d);							\
+	    _qh++;							\
+	  }								\
+      }									\
+    (r) = _r;								\
+    (q) = _qh;								\
+  } while (0)
+
+/* Dividing (NH, NL) by D, returning the remainder only. Unlike
+   udiv_qrnnd_preinv, works also for the case NH == D, where the
+   quotient doesn't quite fit in a single limb. */
+#define udiv_rnnd_preinv(r, nh, nl, d, di)				\
+  do {									\
+    mp_limb_t _qh, _ql, _r, _mask;					\
+    umul_ppmm (_qh, _ql, (nh), (di));					\
+    if (__builtin_constant_p (nl) && (nl) == 0)				\
+      {									\
+	_r = ~(_qh + (nh)) * (d);					\
+	_mask = -(mp_limb_t) (_r > _ql); /* both > and >= are OK */	\
+	_r += _mask & (d);						\
+      }									\
+    else								\
+      {									\
+	add_ssaaaa (_qh, _ql, _qh, _ql, (nh) + 1, (nl));		\
+	_r = (nl) - _qh * (d);						\
+	_mask = -(mp_limb_t) (_r > _ql); /* both > and >= are OK */	\
+	_r += _mask & (d);						\
+	if (UNLIKELY (_r >= (d)))					\
+	  _r -= (d);							\
+      }									\
+    (r) = _r;								\
+  } while (0)
+
+/* Compute quotient the quotient and remainder for n / d. Requires d
+   >= B^2 / 2 and n < d B. di is the inverse
+
+     floor ((B^3 - 1) / (d0 + d1 B)) - B.
+
+   NOTE: Output variables are updated multiple times. Only some inputs
+   and outputs may overlap.
+*/
+#define udiv_qr_3by2(q, r1, r0, n2, n1, n0, d1, d0, dinv)		\
+  do {									\
+    mp_limb_t _q0, _t1, _t0, _mask;					\
+    umul_ppmm ((q), _q0, (n2), (dinv));					\
+    add_ssaaaa ((q), _q0, (q), _q0, (n2), (n1));			\
+									\
+    /* Compute the two most significant limbs of n - q'd */		\
+    (r1) = (n1) - (d1) * (q);						\
+    sub_ddmmss ((r1), (r0), (r1), (n0), (d1), (d0));			\
+    umul_ppmm (_t1, _t0, (d0), (q));					\
+    sub_ddmmss ((r1), (r0), (r1), (r0), _t1, _t0);			\
+    (q)++;								\
+									\
+    /* Conditionally adjust q and the remainders */			\
+    _mask = - (mp_limb_t) ((r1) >= _q0);				\
+    (q) += _mask;							\
+    add_ssaaaa ((r1), (r0), (r1), (r0), _mask & (d1), _mask & (d0));	\
+    if (UNLIKELY ((r1) >= (d1)))					\
+      {									\
+	if ((r1) > (d1) || (r0) >= (d0))				\
+	  {								\
+	    (q)++;							\
+	    sub_ddmmss ((r1), (r0), (r1), (r0), (d1), (d0));		\
+	  }								\
+      }									\
+  } while (0)
+
+#ifndef mpn_preinv_divrem_1  /* if not done with cpuvec in a fat binary */
+#define   mpn_preinv_divrem_1 __MPN(preinv_divrem_1)
+__GMP_DECLSPEC mp_limb_t mpn_preinv_divrem_1 (mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t, int);
+#endif
+
+
+/* USE_PREINV_DIVREM_1 is whether to use mpn_preinv_divrem_1, as opposed to the
+   plain mpn_divrem_1.  The default is yes, since the few CISC chips where
+   preinv is not good have defines saying so.  */
+#ifndef USE_PREINV_DIVREM_1
+#define USE_PREINV_DIVREM_1   1
+#endif
+
+#if USE_PREINV_DIVREM_1
+#define MPN_DIVREM_OR_PREINV_DIVREM_1(qp,xsize,ap,size,d,dinv,shift)    \
+  mpn_preinv_divrem_1 (qp, xsize, ap, size, d, dinv, shift)
+#else
+#define MPN_DIVREM_OR_PREINV_DIVREM_1(qp,xsize,ap,size,d,dinv,shift)    \
+  mpn_divrem_1 (qp, xsize, ap, size, d)
+#endif
+
+#ifndef PREINV_MOD_1_TO_MOD_1_THRESHOLD
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD 10
+#endif
+
+/* This selection may seem backwards.  The reason mpn_mod_1 typically takes
+   over for larger sizes is that it uses the mod_1_1 function.  */
+#define MPN_MOD_OR_PREINV_MOD_1(src,size,divisor,inverse)		\
+  (BELOW_THRESHOLD (size, PREINV_MOD_1_TO_MOD_1_THRESHOLD)		\
+   ? mpn_preinv_mod_1 (src, size, divisor, inverse)			\
+   : mpn_mod_1 (src, size, divisor))
+
+
+#ifndef mpn_mod_34lsub1  /* if not done with cpuvec in a fat binary */
+#define mpn_mod_34lsub1 __MPN(mod_34lsub1)
+__GMP_DECLSPEC mp_limb_t mpn_mod_34lsub1 (mp_srcptr, mp_size_t) __GMP_ATTRIBUTE_PURE;
+#endif
+
+
+/* DIVEXACT_1_THRESHOLD is at what size to use mpn_divexact_1, as opposed to
+   plain mpn_divrem_1.  Likewise BMOD_1_TO_MOD_1_THRESHOLD for
+   mpn_modexact_1_odd against plain mpn_mod_1.  On most CPUs divexact and
+   modexact are faster at all sizes, so the defaults are 0.  Those CPUs
+   where this is not right have a tuned threshold.  */
+#ifndef DIVEXACT_1_THRESHOLD
+#define DIVEXACT_1_THRESHOLD  0
+#endif
+#ifndef BMOD_1_TO_MOD_1_THRESHOLD
+#define BMOD_1_TO_MOD_1_THRESHOLD  10
+#endif
+
+#define MPN_DIVREM_OR_DIVEXACT_1(rp, up, n, d)				\
+  do {									\
+    if (BELOW_THRESHOLD (n, DIVEXACT_1_THRESHOLD))			\
+      ASSERT_NOCARRY (mpn_divrem_1 (rp, (mp_size_t) 0, up, n, d));	\
+    else								\
+      {									\
+	ASSERT (mpn_mod_1 (up, n, d) == 0);				\
+	mpn_divexact_1 (rp, up, n, d);					\
+      }									\
+  } while (0)
+
+#ifndef mpn_modexact_1c_odd  /* if not done with cpuvec in a fat binary */
+#define mpn_modexact_1c_odd __MPN(modexact_1c_odd)
+__GMP_DECLSPEC mp_limb_t mpn_modexact_1c_odd (mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t) __GMP_ATTRIBUTE_PURE;
+#endif
+
+#if HAVE_NATIVE_mpn_modexact_1_odd
+#define   mpn_modexact_1_odd  __MPN(modexact_1_odd)
+__GMP_DECLSPEC mp_limb_t mpn_modexact_1_odd (mp_srcptr, mp_size_t, mp_limb_t) __GMP_ATTRIBUTE_PURE;
+#else
+#define mpn_modexact_1_odd(src,size,divisor) \
+  mpn_modexact_1c_odd (src, size, divisor, CNST_LIMB(0))
+#endif
+
+#define MPN_MOD_OR_MODEXACT_1_ODD(src,size,divisor)			\
+  (BELOW_THRESHOLD (size, BMOD_1_TO_MOD_1_THRESHOLD)			\
+   ? mpn_modexact_1_odd (src, size, divisor)				\
+   : mpn_mod_1 (src, size, divisor))
+
+/* binvert_limb() sets inv to the multiplicative inverse of n modulo
+   2^GMP_NUMB_BITS, ie. satisfying inv*n == 1 mod 2^GMP_NUMB_BITS.
+   n must be odd (otherwise such an inverse doesn't exist).
+
+   This is not to be confused with invert_limb(), which is completely
+   different.
+
+   The table lookup gives an inverse with the low 8 bits valid, and each
+   multiply step doubles the number of bits.  See Jebelean "An algorithm for
+   exact division" end of section 4 (reference in gmp.texi).
+
+   Possible enhancement: Could use UHWtype until the last step, if half-size
+   multiplies are faster (might help under _LONG_LONG_LIMB).
+
+   Alternative: As noted in Granlund and Montgomery "Division by Invariant
+   Integers using Multiplication" (reference in gmp.texi), n itself gives a
+   3-bit inverse immediately, and could be used instead of a table lookup.
+   A 4-bit inverse can be obtained effectively from xoring bits 1 and 2 into
+   bit 3, for instance with (((n + 2) & 4) << 1) ^ n.  */
+
+#define binvert_limb_table  __gmp_binvert_limb_table
+__GMP_DECLSPEC extern const unsigned char  binvert_limb_table[128];
+
+#define binvert_limb(inv,n)						\
+  do {									\
+    mp_limb_t  __n = (n);						\
+    mp_limb_t  __inv;							\
+    ASSERT ((__n & 1) == 1);						\
+									\
+    __inv = binvert_limb_table[(__n/2) & 0x7F]; /*  8 */		\
+    if (GMP_NUMB_BITS > 8)   __inv = 2 * __inv - __inv * __inv * __n;	\
+    if (GMP_NUMB_BITS > 16)  __inv = 2 * __inv - __inv * __inv * __n;	\
+    if (GMP_NUMB_BITS > 32)  __inv = 2 * __inv - __inv * __inv * __n;	\
+									\
+    if (GMP_NUMB_BITS > 64)						\
+      {									\
+	int  __invbits = 64;						\
+	do {								\
+	  __inv = 2 * __inv - __inv * __inv * __n;			\
+	  __invbits *= 2;						\
+	} while (__invbits < GMP_NUMB_BITS);				\
+      }									\
+									\
+    ASSERT ((__inv * __n & GMP_NUMB_MASK) == 1);			\
+    (inv) = __inv & GMP_NUMB_MASK;					\
+  } while (0)
+#define modlimb_invert binvert_limb  /* backward compatibility */
+
+/* Multiplicative inverse of 3, modulo 2^GMP_NUMB_BITS.
+   Eg. 0xAAAAAAAB for 32 bits, 0xAAAAAAAAAAAAAAAB for 64 bits.
+   GMP_NUMB_MAX/3*2+1 is right when GMP_NUMB_BITS is even, but when it's odd
+   we need to start from GMP_NUMB_MAX>>1. */
+#define MODLIMB_INVERSE_3 (((GMP_NUMB_MAX >> (GMP_NUMB_BITS % 2)) / 3) * 2 + 1)
+
+/* ceil(GMP_NUMB_MAX/3) and ceil(2*GMP_NUMB_MAX/3).
+   These expressions work because GMP_NUMB_MAX%3 != 0 for all GMP_NUMB_BITS. */
+#define GMP_NUMB_CEIL_MAX_DIV3   (GMP_NUMB_MAX / 3 + 1)
+#define GMP_NUMB_CEIL_2MAX_DIV3  ((GMP_NUMB_MAX>>1) / 3 + 1 + GMP_NUMB_HIGHBIT)
+
+
+/* Set r to -a mod d.  a>=d is allowed.  Can give r>d.  All should be limbs.
+
+   It's not clear whether this is the best way to do this calculation.
+   Anything congruent to -a would be fine for the one limb congruence
+   tests.  */
+
+#define NEG_MOD(r, a, d)						\
+  do {									\
+    ASSERT ((d) != 0);							\
+    ASSERT_LIMB (a);							\
+    ASSERT_LIMB (d);							\
+									\
+    if ((a) <= (d))							\
+      {									\
+	/* small a is reasonably likely */				\
+	(r) = (d) - (a);						\
+      }									\
+    else								\
+      {									\
+	unsigned   __twos;						\
+	mp_limb_t  __dnorm;						\
+	count_leading_zeros (__twos, d);				\
+	__twos -= GMP_NAIL_BITS;					\
+	__dnorm = (d) << __twos;					\
+	(r) = ((a) <= __dnorm ? __dnorm : 2*__dnorm) - (a);		\
+      }									\
+									\
+    ASSERT_LIMB (r);							\
+  } while (0)
+
+/* A bit mask of all the least significant zero bits of n, or -1 if n==0. */
+#define LOW_ZEROS_MASK(n)  (((n) & -(n)) - 1)
+
+
+/* ULONG_PARITY sets "p" to 1 if there's an odd number of 1 bits in "n", or
+   to 0 if there's an even number.  "n" should be an unsigned long and "p"
+   an int.  */
+
+#if defined (__GNUC__) && ! defined (NO_ASM) && HAVE_HOST_CPU_alpha_CIX
+#define ULONG_PARITY(p, n)						\
+  do {									\
+    int __p;								\
+    __asm__ ("ctpop %1, %0" : "=r" (__p) : "r" (n));			\
+    (p) = __p & 1;							\
+  } while (0)
+#endif
+
+/* Cray intrinsic _popcnt. */
+#ifdef _CRAY
+#define ULONG_PARITY(p, n)      \
+  do {                          \
+    (p) = _popcnt (n) & 1;      \
+  } while (0)
+#endif
+
+#if defined (__GNUC__) && ! defined (__INTEL_COMPILER)			\
+    && ! defined (NO_ASM) && defined (__ia64)
+/* unsigned long is either 32 or 64 bits depending on the ABI, zero extend
+   to a 64 bit unsigned long long for popcnt */
+#define ULONG_PARITY(p, n)						\
+  do {									\
+    unsigned long long  __n = (unsigned long) (n);			\
+    int  __p;								\
+    __asm__ ("popcnt %0 = %1" : "=r" (__p) : "r" (__n));		\
+    (p) = __p & 1;							\
+  } while (0)
+#endif
+
+#if defined (__GNUC__) && ! defined (__INTEL_COMPILER)			\
+    && ! defined (NO_ASM) && HAVE_HOST_CPU_FAMILY_x86
+#if __GMP_GNUC_PREREQ (3,1)
+#define __GMP_qm "=Qm"
+#define __GMP_q "=Q"
+#else
+#define __GMP_qm "=qm"
+#define __GMP_q "=q"
+#endif
+#define ULONG_PARITY(p, n)						\
+  do {									\
+    char	   __p;							\
+    unsigned long  __n = (n);						\
+    __n ^= (__n >> 16);							\
+    __asm__ ("xorb %h1, %b1\n\t"					\
+	     "setpo %0"							\
+	 : __GMP_qm (__p), __GMP_q (__n)				\
+	 : "1" (__n));							\
+    (p) = __p;								\
+  } while (0)
+#endif
+
+#if ! defined (ULONG_PARITY)
+#define ULONG_PARITY(p, n)						\
+  do {									\
+    unsigned long  __n = (n);						\
+    int  __p = 0;							\
+    do									\
+      {									\
+	__p ^= 0x96696996L >> (__n & 0x1F);				\
+	__n >>= 5;							\
+      }									\
+    while (__n != 0);							\
+									\
+    (p) = __p & 1;							\
+  } while (0)
+#endif
+
+
+/* 3 cycles on 604 or 750 since shifts and rlwimi's can pair.  gcc (as of
+   version 3.1 at least) doesn't seem to know how to generate rlwimi for
+   anything other than bit-fields, so use "asm".  */
+#if defined (__GNUC__) && ! defined (NO_ASM)                    \
+  && HAVE_HOST_CPU_FAMILY_powerpc && GMP_LIMB_BITS == 32
+#define BSWAP_LIMB(dst, src)						\
+  do {									\
+    mp_limb_t  __bswapl_src = (src);					\
+    mp_limb_t  __tmp1 = __bswapl_src >> 24;		/* low byte */	\
+    mp_limb_t  __tmp2 = __bswapl_src << 24;		/* high byte */	\
+    __asm__ ("rlwimi %0, %2, 24, 16, 23"		/* 2nd low */	\
+	 : "=r" (__tmp1) : "0" (__tmp1), "r" (__bswapl_src));		\
+    __asm__ ("rlwimi %0, %2,  8,  8, 15"		/* 3nd high */	\
+	 : "=r" (__tmp2) : "0" (__tmp2), "r" (__bswapl_src));		\
+    (dst) = __tmp1 | __tmp2;				/* whole */	\
+  } while (0)
+#endif
+
+/* bswap is available on i486 and up and is fast.  A combination rorw $8 /
+   roll $16 / rorw $8 is used in glibc for plain i386 (and in the linux
+   kernel with xchgb instead of rorw), but this is not done here, because
+   i386 means generic x86 and mixing word and dword operations will cause
+   partial register stalls on P6 chips.  */
+#if defined (__GNUC__) && ! defined (NO_ASM)            \
+  && HAVE_HOST_CPU_FAMILY_x86 && ! HAVE_HOST_CPU_i386   \
+  && GMP_LIMB_BITS == 32
+#define BSWAP_LIMB(dst, src)						\
+  do {									\
+    __asm__ ("bswap %0" : "=r" (dst) : "0" (src));			\
+  } while (0)
+#endif
+
+#if defined (__GNUC__) && ! defined (NO_ASM)            \
+  && defined (__amd64__) && GMP_LIMB_BITS == 64
+#define BSWAP_LIMB(dst, src)						\
+  do {									\
+    __asm__ ("bswap %q0" : "=r" (dst) : "0" (src));			\
+  } while (0)
+#endif
+
+#if defined (__GNUC__) && ! defined (__INTEL_COMPILER)			\
+    && ! defined (NO_ASM) && defined (__ia64) && GMP_LIMB_BITS == 64
+#define BSWAP_LIMB(dst, src)						\
+  do {									\
+    __asm__ ("mux1 %0 = %1, @rev" : "=r" (dst) :  "r" (src));		\
+  } while (0)
+#endif
+
+/* As per glibc. */
+#if defined (__GNUC__) && ! defined (NO_ASM)                    \
+  && HAVE_HOST_CPU_FAMILY_m68k && GMP_LIMB_BITS == 32
+#define BSWAP_LIMB(dst, src)						\
+  do {									\
+    mp_limb_t  __bswapl_src = (src);					\
+    __asm__ ("ror%.w %#8, %0\n\t"					\
+	     "swap   %0\n\t"						\
+	     "ror%.w %#8, %0"						\
+	     : "=d" (dst)						\
+	     : "0" (__bswapl_src));					\
+  } while (0)
+#endif
+
+#if ! defined (BSWAP_LIMB)
+#if GMP_LIMB_BITS == 8
+#define BSWAP_LIMB(dst, src)				\
+  do { (dst) = (src); } while (0)
+#endif
+#if GMP_LIMB_BITS == 16
+#define BSWAP_LIMB(dst, src)						\
+  do {									\
+    (dst) = ((src) << 8) + ((src) >> 8);				\
+  } while (0)
+#endif
+#if GMP_LIMB_BITS == 32
+#define BSWAP_LIMB(dst, src)						\
+  do {									\
+    (dst) =								\
+      ((src) << 24)							\
+      + (((src) & 0xFF00) << 8)						\
+      + (((src) >> 8) & 0xFF00)						\
+      + ((src) >> 24);							\
+  } while (0)
+#endif
+#if GMP_LIMB_BITS == 64
+#define BSWAP_LIMB(dst, src)						\
+  do {									\
+    (dst) =								\
+      ((src) << 56)							\
+      + (((src) & 0xFF00) << 40)					\
+      + (((src) & 0xFF0000) << 24)					\
+      + (((src) & 0xFF000000) << 8)					\
+      + (((src) >> 8) & 0xFF000000)					\
+      + (((src) >> 24) & 0xFF0000)					\
+      + (((src) >> 40) & 0xFF00)					\
+      + ((src) >> 56);							\
+  } while (0)
+#endif
+#endif
+
+#if ! defined (BSWAP_LIMB)
+#define BSWAP_LIMB(dst, src)						\
+  do {									\
+    mp_limb_t  __bswapl_src = (src);					\
+    mp_limb_t  __dstl = 0;						\
+    int	       __i;							\
+    for (__i = 0; __i < GMP_LIMB_BYTES; __i++)			\
+      {									\
+	__dstl = (__dstl << 8) | (__bswapl_src & 0xFF);			\
+	__bswapl_src >>= 8;						\
+      }									\
+    (dst) = __dstl;							\
+  } while (0)
+#endif
+
+
+/* Apparently lwbrx might be slow on some PowerPC chips, so restrict it to
+   those we know are fast.  */
+#if defined (__GNUC__) && ! defined (NO_ASM)				\
+  && GMP_LIMB_BITS == 32 && HAVE_LIMB_BIG_ENDIAN			\
+  && (HAVE_HOST_CPU_powerpc604						\
+      || HAVE_HOST_CPU_powerpc604e					\
+      || HAVE_HOST_CPU_powerpc750					\
+      || HAVE_HOST_CPU_powerpc7400)
+#define BSWAP_LIMB_FETCH(limb, src)					\
+  do {									\
+    mp_srcptr  __blf_src = (src);					\
+    mp_limb_t  __limb;							\
+    __asm__ ("lwbrx %0, 0, %1"						\
+	     : "=r" (__limb)						\
+	     : "r" (__blf_src),						\
+	       "m" (*__blf_src));					\
+    (limb) = __limb;							\
+  } while (0)
+#endif
+
+#if ! defined (BSWAP_LIMB_FETCH)
+#define BSWAP_LIMB_FETCH(limb, src)  BSWAP_LIMB (limb, *(src))
+#endif
+
+
+/* On the same basis that lwbrx might be slow, restrict stwbrx to those we
+   know are fast.  FIXME: Is this necessary?  */
+#if defined (__GNUC__) && ! defined (NO_ASM)				\
+  && GMP_LIMB_BITS == 32 && HAVE_LIMB_BIG_ENDIAN			\
+  && (HAVE_HOST_CPU_powerpc604						\
+      || HAVE_HOST_CPU_powerpc604e					\
+      || HAVE_HOST_CPU_powerpc750					\
+      || HAVE_HOST_CPU_powerpc7400)
+#define BSWAP_LIMB_STORE(dst, limb)					\
+  do {									\
+    mp_ptr     __dst = (dst);						\
+    mp_limb_t  __limb = (limb);						\
+    __asm__ ("stwbrx %1, 0, %2"						\
+	     : "=m" (*__dst)						\
+	     : "r" (__limb),						\
+	       "r" (__dst));						\
+  } while (0)
+#endif
+
+#if ! defined (BSWAP_LIMB_STORE)
+#define BSWAP_LIMB_STORE(dst, limb)  BSWAP_LIMB (*(dst), limb)
+#endif
+
+
+/* Byte swap limbs from {src,size} and store at {dst,size}. */
+#define MPN_BSWAP(dst, src, size)					\
+  do {									\
+    mp_ptr     __dst = (dst);						\
+    mp_srcptr  __src = (src);						\
+    mp_size_t  __size = (size);						\
+    mp_size_t  __i;							\
+    ASSERT ((size) >= 0);						\
+    ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, size));			\
+    CRAY_Pragma ("_CRI ivdep");						\
+    for (__i = 0; __i < __size; __i++)					\
+      {									\
+	BSWAP_LIMB_FETCH (*__dst, __src);				\
+	__dst++;							\
+	__src++;							\
+      }									\
+  } while (0)
+
+/* Byte swap limbs from {dst,size} and store in reverse order at {src,size}. */
+#define MPN_BSWAP_REVERSE(dst, src, size)				\
+  do {									\
+    mp_ptr     __dst = (dst);						\
+    mp_size_t  __size = (size);						\
+    mp_srcptr  __src = (src) + __size - 1;				\
+    mp_size_t  __i;							\
+    ASSERT ((size) >= 0);						\
+    ASSERT (! MPN_OVERLAP_P (dst, size, src, size));			\
+    CRAY_Pragma ("_CRI ivdep");						\
+    for (__i = 0; __i < __size; __i++)					\
+      {									\
+	BSWAP_LIMB_FETCH (*__dst, __src);				\
+	__dst++;							\
+	__src--;							\
+      }									\
+  } while (0)
+
+
+/* No processor claiming to be SPARC v9 compliant seems to
+   implement the POPC instruction.  Disable pattern for now.  */
+#if 0
+#if defined __GNUC__ && defined __sparc_v9__ && GMP_LIMB_BITS == 64
+#define popc_limb(result, input)					\
+  do {									\
+    DItype __res;							\
+    __asm__ ("popc %1,%0" : "=r" (result) : "rI" (input));		\
+  } while (0)
+#endif
+#endif
+
+#if defined (__GNUC__) && ! defined (NO_ASM) && HAVE_HOST_CPU_alpha_CIX
+#define popc_limb(result, input)					\
+  do {									\
+    __asm__ ("ctpop %1, %0" : "=r" (result) : "r" (input));		\
+  } while (0)
+#endif
+
+/* Cray intrinsic. */
+#ifdef _CRAY
+#define popc_limb(result, input)					\
+  do {									\
+    (result) = _popcnt (input);						\
+  } while (0)
+#endif
+
+#if defined (__GNUC__) && ! defined (__INTEL_COMPILER)			\
+    && ! defined (NO_ASM) && defined (__ia64) && GMP_LIMB_BITS == 64
+#define popc_limb(result, input)					\
+  do {									\
+    __asm__ ("popcnt %0 = %1" : "=r" (result) : "r" (input));		\
+  } while (0)
+#endif
+
+/* Cool population count of an mp_limb_t.
+   You have to figure out how this works, We won't tell you!
+
+   The constants could also be expressed as:
+     0x55... = [2^N / 3]     = [(2^N-1)/3]
+     0x33... = [2^N / 5]     = [(2^N-1)/5]
+     0x0f... = [2^N / 17]    = [(2^N-1)/17]
+     (N is GMP_LIMB_BITS, [] denotes truncation.) */
+
+#if ! defined (popc_limb) && GMP_LIMB_BITS == 8
+#define popc_limb(result, input)					\
+  do {									\
+    mp_limb_t  __x = (input);						\
+    __x -= (__x >> 1) & MP_LIMB_T_MAX/3;				\
+    __x = ((__x >> 2) & MP_LIMB_T_MAX/5) + (__x & MP_LIMB_T_MAX/5);	\
+    __x = ((__x >> 4) + __x);						\
+    (result) = __x & 0x0f;						\
+  } while (0)
+#endif
+
+#if ! defined (popc_limb) && GMP_LIMB_BITS == 16
+#define popc_limb(result, input)					\
+  do {									\
+    mp_limb_t  __x = (input);						\
+    __x -= (__x >> 1) & MP_LIMB_T_MAX/3;				\
+    __x = ((__x >> 2) & MP_LIMB_T_MAX/5) + (__x & MP_LIMB_T_MAX/5);	\
+    __x += (__x >> 4);							\
+    __x = ((__x >> 8) & MP_LIMB_T_MAX/4369)+(__x & MP_LIMB_T_MAX/4369);	\
+    (result) = __x;							\
+  } while (0)
+#endif
+
+#if ! defined (popc_limb) && GMP_LIMB_BITS == 32
+#define popc_limb(result, input)					\
+  do {									\
+    mp_limb_t  __x = (input);						\
+    __x -= (__x >> 1) & MP_LIMB_T_MAX/3;				\
+    __x = ((__x >> 2) & MP_LIMB_T_MAX/5) + (__x & MP_LIMB_T_MAX/5);	\
+    __x = ((__x >> 4) + __x) & MP_LIMB_T_MAX/17;			\
+    __x = ((__x >> 8) + __x);						\
+    __x = ((__x >> 16) + __x);						\
+    (result) = __x & 0xff;						\
+  } while (0)
+#endif
+
+#if ! defined (popc_limb) && GMP_LIMB_BITS == 64
+#define popc_limb(result, input)					\
+  do {									\
+    mp_limb_t  __x = (input);						\
+    __x -= (__x >> 1) & MP_LIMB_T_MAX/3;				\
+    __x = ((__x >> 2) & MP_LIMB_T_MAX/5) + (__x & MP_LIMB_T_MAX/5);	\
+    __x = ((__x >> 4) + __x) & MP_LIMB_T_MAX/17;			\
+    __x = ((__x >> 8) + __x);						\
+    __x = ((__x >> 16) + __x);						\
+    __x = ((__x >> 32) + __x);						\
+    (result) = __x & 0xff;						\
+  } while (0)
+#endif
+
+
+/* Define stuff for longlong.h.  */
+#if HAVE_ATTRIBUTE_MODE
+typedef unsigned int UQItype	__attribute__ ((mode (QI)));
+typedef		 int SItype	__attribute__ ((mode (SI)));
+typedef unsigned int USItype	__attribute__ ((mode (SI)));
+typedef		 int DItype	__attribute__ ((mode (DI)));
+typedef unsigned int UDItype	__attribute__ ((mode (DI)));
+#else
+typedef unsigned char UQItype;
+typedef		 long SItype;
+typedef unsigned long USItype;
+#if HAVE_LONG_LONG
+typedef	long long int DItype;
+typedef unsigned long long int UDItype;
+#else /* Assume `long' gives us a wide enough type.  Needed for hppa2.0w.  */
+typedef long int DItype;
+typedef unsigned long int UDItype;
+#endif
+#endif
+
+typedef mp_limb_t UWtype;
+typedef unsigned int UHWtype;
+#define W_TYPE_SIZE GMP_LIMB_BITS
+
+/* Define ieee_double_extract and _GMP_IEEE_FLOATS.
+
+   Bit field packing is "implementation defined" according to C99, which
+   leaves us at the compiler's mercy here.  For some systems packing is
+   defined in the ABI (eg. x86).  In any case so far it seems universal that
+   little endian systems pack from low to high, and big endian from high to
+   low within the given type.
+
+   Within the fields we rely on the integer endianness being the same as the
+   float endianness, this is true everywhere we know of and it'd be a fairly
+   strange system that did anything else.  */
+
+#if HAVE_DOUBLE_IEEE_LITTLE_SWAPPED
+#define _GMP_IEEE_FLOATS 1
+union ieee_double_extract
+{
+  struct
+    {
+      gmp_uint_least32_t manh:20;
+      gmp_uint_least32_t exp:11;
+      gmp_uint_least32_t sig:1;
+      gmp_uint_least32_t manl:32;
+    } s;
+  double d;
+};
+#endif
+
+#if HAVE_DOUBLE_IEEE_LITTLE_ENDIAN
+#define _GMP_IEEE_FLOATS 1
+union ieee_double_extract
+{
+  struct
+    {
+      gmp_uint_least32_t manl:32;
+      gmp_uint_least32_t manh:20;
+      gmp_uint_least32_t exp:11;
+      gmp_uint_least32_t sig:1;
+    } s;
+  double d;
+};
+#endif
+
+#if HAVE_DOUBLE_IEEE_BIG_ENDIAN
+#define _GMP_IEEE_FLOATS 1
+union ieee_double_extract
+{
+  struct
+    {
+      gmp_uint_least32_t sig:1;
+      gmp_uint_least32_t exp:11;
+      gmp_uint_least32_t manh:20;
+      gmp_uint_least32_t manl:32;
+    } s;
+  double d;
+};
+#endif
+
+#if HAVE_DOUBLE_VAX_D
+union double_extract
+{
+  struct
+    {
+      gmp_uint_least32_t man3:7;	/* highest 7 bits */
+      gmp_uint_least32_t exp:8;		/* excess-128 exponent */
+      gmp_uint_least32_t sig:1;
+      gmp_uint_least32_t man2:16;
+      gmp_uint_least32_t man1:16;
+      gmp_uint_least32_t man0:16;	/* lowest 16 bits */
+    } s;
+  double d;
+};
+#endif
+
+/* Use (4.0 * ...) instead of (2.0 * ...) to work around buggy compilers
+   that don't convert ulong->double correctly (eg. SunOS 4 native cc).  */
+#define MP_BASE_AS_DOUBLE (4.0 * ((mp_limb_t) 1 << (GMP_NUMB_BITS - 2)))
+/* Maximum number of limbs it will take to store any `double'.
+   We assume doubles have 53 mantissa bits.  */
+#define LIMBS_PER_DOUBLE ((53 + GMP_NUMB_BITS - 2) / GMP_NUMB_BITS + 1)
+
+__GMP_DECLSPEC int __gmp_extract_double (mp_ptr, double);
+
+#define mpn_get_d __gmpn_get_d
+__GMP_DECLSPEC double mpn_get_d (mp_srcptr, mp_size_t, mp_size_t, long) __GMP_ATTRIBUTE_PURE;
+
+
+/* DOUBLE_NAN_INF_ACTION executes code a_nan if x is a NaN, or executes
+   a_inf if x is an infinity.  Both are considered unlikely values, for
+   branch prediction.  */
+
+#if _GMP_IEEE_FLOATS
+#define DOUBLE_NAN_INF_ACTION(x, a_nan, a_inf)				\
+  do {									\
+    union ieee_double_extract  u;					\
+    u.d = (x);								\
+    if (UNLIKELY (u.s.exp == 0x7FF))					\
+      {									\
+	if (u.s.manl == 0 && u.s.manh == 0)				\
+	  { a_inf; }							\
+	else								\
+	  { a_nan; }							\
+      }									\
+  } while (0)
+#endif
+
+#if HAVE_DOUBLE_VAX_D || HAVE_DOUBLE_VAX_G || HAVE_DOUBLE_CRAY_CFP
+/* no nans or infs in these formats */
+#define DOUBLE_NAN_INF_ACTION(x, a_nan, a_inf)  \
+  do { } while (0)
+#endif
+
+#ifndef DOUBLE_NAN_INF_ACTION
+/* Unknown format, try something generic.
+   NaN should be "unordered", so x!=x.
+   Inf should be bigger than DBL_MAX.  */
+#define DOUBLE_NAN_INF_ACTION(x, a_nan, a_inf)				\
+  do {									\
+    {									\
+      if (UNLIKELY ((x) != (x)))					\
+	{ a_nan; }							\
+      else if (UNLIKELY ((x) > DBL_MAX || (x) < -DBL_MAX))		\
+	{ a_inf; }							\
+    }									\
+  } while (0)
+#endif
+
+/* On m68k, x86 and amd64, gcc (and maybe other compilers) can hold doubles
+   in the coprocessor, which means a bigger exponent range than normal, and
+   depending on the rounding mode, a bigger mantissa than normal.  (See
+   "Disappointments" in the gcc manual.)  FORCE_DOUBLE stores and fetches
+   "d" through memory to force any rounding and overflows to occur.
+
+   On amd64, and on x86s with SSE2, gcc (depending on options) uses the xmm
+   registers, where there's no such extra precision and no need for the
+   FORCE_DOUBLE.  We don't bother to detect this since the present uses for
+   FORCE_DOUBLE are only in test programs and default generic C code.
+
+   Not quite sure that an "automatic volatile" will use memory, but it does
+   in gcc.  An asm("":"=m"(d):"0"(d)) can't be used to trick gcc, since
+   apparently matching operands like "0" are only allowed on a register
+   output.  gcc 3.4 warns about this, though in fact it and past versions
+   seem to put the operand through memory as hoped.  */
+
+#if (HAVE_HOST_CPU_FAMILY_m68k || HAVE_HOST_CPU_FAMILY_x86      \
+     || defined (__amd64__))
+#define FORCE_DOUBLE(d) \
+  do { volatile double __gmp_force = (d); (d) = __gmp_force; } while (0)
+#else
+#define FORCE_DOUBLE(d)  do { } while (0)
+#endif
+
+
+__GMP_DECLSPEC extern const unsigned char __gmp_digit_value_tab[];
+
+__GMP_DECLSPEC extern int __gmp_junk;
+__GMP_DECLSPEC extern const int __gmp_0;
+__GMP_DECLSPEC void __gmp_exception (int) ATTRIBUTE_NORETURN;
+__GMP_DECLSPEC void __gmp_divide_by_zero (void) ATTRIBUTE_NORETURN;
+__GMP_DECLSPEC void __gmp_sqrt_of_negative (void) ATTRIBUTE_NORETURN;
+__GMP_DECLSPEC void __gmp_invalid_operation (void) ATTRIBUTE_NORETURN;
+#define GMP_ERROR(code)   __gmp_exception (code)
+#define DIVIDE_BY_ZERO    __gmp_divide_by_zero ()
+#define SQRT_OF_NEGATIVE  __gmp_sqrt_of_negative ()
+
+#if defined _LONG_LONG_LIMB
+#define CNST_LIMB(C) ((mp_limb_t) C##LL)
+#else /* not _LONG_LONG_LIMB */
+#define CNST_LIMB(C) ((mp_limb_t) C##L)
+#endif /* _LONG_LONG_LIMB */
+
+/* Stuff used by mpn/generic/perfsqr.c and mpz/prime_p.c */
+#if GMP_NUMB_BITS == 2
+#define PP 0x3					/* 3 */
+#define PP_FIRST_OMITTED 5
+#endif
+#if GMP_NUMB_BITS == 4
+#define PP 0xF					/* 3 x 5 */
+#define PP_FIRST_OMITTED 7
+#endif
+#if GMP_NUMB_BITS == 8
+#define PP 0x69					/* 3 x 5 x 7 */
+#define PP_FIRST_OMITTED 11
+#endif
+#if GMP_NUMB_BITS == 16
+#define PP 0x3AA7				/* 3 x 5 x 7 x 11 x 13 */
+#define PP_FIRST_OMITTED 17
+#endif
+#if GMP_NUMB_BITS == 32
+#define PP 0xC0CFD797L				/* 3 x 5 x 7 x 11 x ... x 29 */
+#define PP_INVERTED 0x53E5645CL
+#define PP_FIRST_OMITTED 31
+#endif
+#if GMP_NUMB_BITS == 64
+#define PP CNST_LIMB(0xE221F97C30E94E1D)	/* 3 x 5 x 7 x 11 x ... x 53 */
+#define PP_INVERTED CNST_LIMB(0x21CFE6CFC938B36B)
+#define PP_FIRST_OMITTED 59
+#endif
+#ifndef PP_FIRST_OMITTED
+#define PP_FIRST_OMITTED 3
+#endif
+
+typedef struct
+{
+  mp_limb_t d0, d1;
+} mp_double_limb_t;
+
+#define mpn_gcd_22 __MPN (gcd_22)
+__GMP_DECLSPEC mp_double_limb_t mpn_gcd_22 (mp_limb_t, mp_limb_t, mp_limb_t, mp_limb_t);
+
+/* BIT1 means a result value in bit 1 (second least significant bit), with a
+   zero bit representing +1 and a one bit representing -1.  Bits other than
+   bit 1 are garbage.  These are meant to be kept in "int"s, and casts are
+   used to ensure the expressions are "int"s even if a and/or b might be
+   other types.
+
+   JACOBI_TWOS_U_BIT1 and JACOBI_RECIP_UU_BIT1 are used in mpn_jacobi_base
+   and their speed is important.  Expressions are used rather than
+   conditionals to accumulate sign changes, which effectively means XORs
+   instead of conditional JUMPs. */
+
+/* (a/0), with a signed; is 1 if a=+/-1, 0 otherwise */
+#define JACOBI_S0(a)   (((a) == 1) | ((a) == -1))
+
+/* (a/0), with a unsigned; is 1 if a=+/-1, 0 otherwise */
+#define JACOBI_U0(a)   ((a) == 1)
+
+/* FIXME: JACOBI_LS0 and JACOBI_0LS are the same, so delete one and
+   come up with a better name. */
+
+/* (a/0), with a given by low and size;
+   is 1 if a=+/-1, 0 otherwise */
+#define JACOBI_LS0(alow,asize) \
+  (((asize) == 1 || (asize) == -1) && (alow) == 1)
+
+/* (a/0), with a an mpz_t;
+   fetch of low limb always valid, even if size is zero */
+#define JACOBI_Z0(a)   JACOBI_LS0 (PTR(a)[0], SIZ(a))
+
+/* (0/b), with b unsigned; is 1 if b=1, 0 otherwise */
+#define JACOBI_0U(b)   ((b) == 1)
+
+/* (0/b), with b unsigned; is 1 if b=+/-1, 0 otherwise */
+#define JACOBI_0S(b)   ((b) == 1 || (b) == -1)
+
+/* (0/b), with b given by low and size; is 1 if b=+/-1, 0 otherwise */
+#define JACOBI_0LS(blow,bsize) \
+  (((bsize) == 1 || (bsize) == -1) && (blow) == 1)
+
+/* Convert a bit1 to +1 or -1. */
+#define JACOBI_BIT1_TO_PN(result_bit1) \
+  (1 - ((int) (result_bit1) & 2))
+
+/* (2/b), with b unsigned and odd;
+   is (-1)^((b^2-1)/8) which is 1 if b==1,7mod8 or -1 if b==3,5mod8 and
+   hence obtained from (b>>1)^b */
+#define JACOBI_TWO_U_BIT1(b) \
+  ((int) (((b) >> 1) ^ (b)))
+
+/* (2/b)^twos, with b unsigned and odd */
+#define JACOBI_TWOS_U_BIT1(twos, b) \
+  ((int) ((twos) << 1) & JACOBI_TWO_U_BIT1 (b))
+
+/* (2/b)^twos, with b unsigned and odd */
+#define JACOBI_TWOS_U(twos, b) \
+  (JACOBI_BIT1_TO_PN (JACOBI_TWOS_U_BIT1 (twos, b)))
+
+/* (-1/b), with b odd (signed or unsigned);
+   is (-1)^((b-1)/2) */
+#define JACOBI_N1B_BIT1(b) \
+  ((int) (b))
+
+/* (a/b) effect due to sign of a: signed/unsigned, b odd;
+   is (-1/b) if a<0, or +1 if a>=0 */
+#define JACOBI_ASGN_SU_BIT1(a, b) \
+  ((((a) < 0) << 1) & JACOBI_N1B_BIT1(b))
+
+/* (a/b) effect due to sign of b: signed/signed;
+   is -1 if a and b both negative, +1 otherwise */
+#define JACOBI_BSGN_SS_BIT1(a, b) \
+  ((((a)<0) & ((b)<0)) << 1)
+
+/* (a/b) effect due to sign of b: signed/mpz;
+   is -1 if a and b both negative, +1 otherwise */
+#define JACOBI_BSGN_SZ_BIT1(a, b) \
+  JACOBI_BSGN_SS_BIT1 (a, SIZ(b))
+
+/* (a/b) effect due to sign of b: mpz/signed;
+   is -1 if a and b both negative, +1 otherwise */
+#define JACOBI_BSGN_ZS_BIT1(a, b) \
+  JACOBI_BSGN_SZ_BIT1 (b, a)
+
+/* (a/b) reciprocity to switch to (b/a), a,b both unsigned and odd;
+   is (-1)^((a-1)*(b-1)/4), which means +1 if either a,b==1mod4, or -1 if
+   both a,b==3mod4, achieved in bit 1 by a&b.  No ASSERT()s about a,b odd
+   because this is used in a couple of places with only bit 1 of a or b
+   valid. */
+#define JACOBI_RECIP_UU_BIT1(a, b) \
+  ((int) ((a) & (b)))
+
+/* Strip low zero limbs from {b_ptr,b_size} by incrementing b_ptr and
+   decrementing b_size.  b_low should be b_ptr[0] on entry, and will be
+   updated for the new b_ptr.  result_bit1 is updated according to the
+   factors of 2 stripped, as per (a/2).  */
+#define JACOBI_STRIP_LOW_ZEROS(result_bit1, a, b_ptr, b_size, b_low)	\
+  do {									\
+    ASSERT ((b_size) >= 1);						\
+    ASSERT ((b_low) == (b_ptr)[0]);					\
+									\
+    while (UNLIKELY ((b_low) == 0))					\
+      {									\
+	(b_size)--;							\
+	ASSERT ((b_size) >= 1);						\
+	(b_ptr)++;							\
+	(b_low) = *(b_ptr);						\
+									\
+	ASSERT (((a) & 1) != 0);					\
+	if ((GMP_NUMB_BITS % 2) == 1)					\
+	  (result_bit1) ^= JACOBI_TWO_U_BIT1(a);			\
+      }									\
+  } while (0)
+
+/* Set a_rem to {a_ptr,a_size} reduced modulo b, either using mod_1 or
+   modexact_1_odd, but in either case leaving a_rem<b.  b must be odd and
+   unsigned.  modexact_1_odd effectively calculates -a mod b, and
+   result_bit1 is adjusted for the factor of -1.
+
+   The way mpn_modexact_1_odd sometimes bases its remainder on a_size and
+   sometimes on a_size-1 means if GMP_NUMB_BITS is odd we can't know what
+   factor to introduce into result_bit1, so for that case use mpn_mod_1
+   unconditionally.
+
+   FIXME: mpn_modexact_1_odd is more efficient, so some way to get it used
+   for odd GMP_NUMB_BITS would be good.  Perhaps it could mung its result,
+   or not skip a divide step, or something. */
+
+#define JACOBI_MOD_OR_MODEXACT_1_ODD(result_bit1, a_rem, a_ptr, a_size, b) \
+  do {									   \
+    mp_srcptr  __a_ptr	= (a_ptr);					   \
+    mp_size_t  __a_size = (a_size);					   \
+    mp_limb_t  __b	= (b);						   \
+									   \
+    ASSERT (__a_size >= 1);						   \
+    ASSERT (__b & 1);							   \
+									   \
+    if ((GMP_NUMB_BITS % 2) != 0					   \
+	|| ABOVE_THRESHOLD (__a_size, BMOD_1_TO_MOD_1_THRESHOLD))	   \
+      {									   \
+	(a_rem) = mpn_mod_1 (__a_ptr, __a_size, __b);			   \
+      }									   \
+    else								   \
+      {									   \
+	(result_bit1) ^= JACOBI_N1B_BIT1 (__b);				   \
+	(a_rem) = mpn_modexact_1_odd (__a_ptr, __a_size, __b);		   \
+      }									   \
+  } while (0)
+
+/* State for the Jacobi computation using Lehmer. */
+#define jacobi_table __gmp_jacobi_table
+__GMP_DECLSPEC extern const unsigned char jacobi_table[208];
+
+/* Bit layout for the initial state. b must be odd.
+
+      3  2  1 0
+   +--+--+--+--+
+   |a1|a0|b1| s|
+   +--+--+--+--+
+
+ */
+static inline unsigned
+mpn_jacobi_init (unsigned a, unsigned b, unsigned s)
+{
+  ASSERT (b & 1);
+  ASSERT (s <= 1);
+  return ((a & 3) << 2) + (b & 2) + s;
+}
+
+static inline int
+mpn_jacobi_finish (unsigned bits)
+{
+  /* (a, b) = (1,0) or (0,1) */
+  ASSERT ( (bits & 14) == 0);
+
+  return 1-2*(bits & 1);
+}
+
+static inline unsigned
+mpn_jacobi_update (unsigned bits, unsigned denominator, unsigned q)
+{
+  /* FIXME: Could halve table size by not including the e bit in the
+   * index, and instead xor when updating. Then the lookup would be
+   * like
+   *
+   *   bits ^= table[((bits & 30) << 2) + (denominator << 2) + q];
+   */
+
+  ASSERT (bits < 26);
+  ASSERT (denominator < 2);
+  ASSERT (q < 4);
+
+  /* For almost all calls, denominator is constant and quite often q
+     is constant too. So use addition rather than or, so the compiler
+     can put the constant part can into the offset of an indexed
+     addressing instruction.
+
+     With constant denominator, the below table lookup is compiled to
+
+       C Constant q = 1, constant denominator = 1
+       movzbl table+5(%eax,8), %eax
+
+     or
+
+       C q in %edx, constant denominator = 1
+       movzbl table+4(%edx,%eax,8), %eax
+
+     One could maintain the state preshifted 3 bits, to save a shift
+     here, but at least on x86, that's no real saving.
+  */
+  return bits = jacobi_table[(bits << 3) + (denominator << 2) + q];
+}
+
+/* Matrix multiplication */
+#define   mpn_matrix22_mul __MPN(matrix22_mul)
+__GMP_DECLSPEC void      mpn_matrix22_mul (mp_ptr, mp_ptr, mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_srcptr, mp_srcptr, mp_srcptr, mp_size_t, mp_ptr);
+#define   mpn_matrix22_mul_itch __MPN(matrix22_mul_itch)
+__GMP_DECLSPEC mp_size_t mpn_matrix22_mul_itch (mp_size_t, mp_size_t) ATTRIBUTE_CONST;
+
+#ifndef MATRIX22_STRASSEN_THRESHOLD
+#define MATRIX22_STRASSEN_THRESHOLD 30
+#endif
+
+/* HGCD definitions */
+
+/* Extract one numb, shifting count bits left
+    ________  ________
+   |___xh___||___xl___|
+	  |____r____|
+   >count <
+
+   The count includes any nail bits, so it should work fine if count
+   is computed using count_leading_zeros. If GMP_NAIL_BITS > 0, all of
+   xh, xl and r include nail bits. Must have 0 < count < GMP_LIMB_BITS.
+
+   FIXME: Omit masking with GMP_NUMB_MASK, and let callers do that for
+   those calls where the count high bits of xh may be non-zero.
+*/
+
+#define MPN_EXTRACT_NUMB(count, xh, xl)				\
+  ((((xh) << ((count) - GMP_NAIL_BITS)) & GMP_NUMB_MASK) |	\
+   ((xl) >> (GMP_LIMB_BITS - (count))))
+
+
+/* The matrix non-negative M = (u, u'; v,v') keeps track of the
+   reduction (a;b) = M (alpha; beta) where alpha, beta are smaller
+   than a, b. The determinant must always be one, so that M has an
+   inverse (v', -u'; -v, u). Elements always fit in GMP_NUMB_BITS - 1
+   bits. */
+struct hgcd_matrix1
+{
+  mp_limb_t u[2][2];
+};
+
+#define mpn_hgcd2 __MPN (hgcd2)
+__GMP_DECLSPEC int mpn_hgcd2 (mp_limb_t, mp_limb_t, mp_limb_t, mp_limb_t,	struct hgcd_matrix1 *);
+
+#define mpn_hgcd_mul_matrix1_vector __MPN (hgcd_mul_matrix1_vector)
+__GMP_DECLSPEC mp_size_t mpn_hgcd_mul_matrix1_vector (const struct hgcd_matrix1 *, mp_ptr, mp_srcptr, mp_ptr, mp_size_t);
+
+#define mpn_matrix22_mul1_inverse_vector __MPN (matrix22_mul1_inverse_vector)
+__GMP_DECLSPEC mp_size_t mpn_matrix22_mul1_inverse_vector (const struct hgcd_matrix1 *, mp_ptr, mp_srcptr, mp_ptr, mp_size_t);
+
+#define mpn_hgcd2_jacobi __MPN (hgcd2_jacobi)
+__GMP_DECLSPEC int mpn_hgcd2_jacobi (mp_limb_t, mp_limb_t, mp_limb_t, mp_limb_t, struct hgcd_matrix1 *, unsigned *);
+
+struct hgcd_matrix
+{
+  mp_size_t alloc;		/* for sanity checking only */
+  mp_size_t n;
+  mp_ptr p[2][2];
+};
+
+#define MPN_HGCD_MATRIX_INIT_ITCH(n) (4 * ((n+1)/2 + 1))
+
+#define mpn_hgcd_matrix_init __MPN (hgcd_matrix_init)
+__GMP_DECLSPEC void mpn_hgcd_matrix_init (struct hgcd_matrix *, mp_size_t, mp_ptr);
+
+#define mpn_hgcd_matrix_update_q __MPN (hgcd_matrix_update_q)
+__GMP_DECLSPEC void mpn_hgcd_matrix_update_q (struct hgcd_matrix *, mp_srcptr, mp_size_t, unsigned, mp_ptr);
+
+#define mpn_hgcd_matrix_mul_1 __MPN (hgcd_matrix_mul_1)
+__GMP_DECLSPEC void mpn_hgcd_matrix_mul_1 (struct hgcd_matrix *, const struct hgcd_matrix1 *, mp_ptr);
+
+#define mpn_hgcd_matrix_mul __MPN (hgcd_matrix_mul)
+__GMP_DECLSPEC void mpn_hgcd_matrix_mul (struct hgcd_matrix *, const struct hgcd_matrix *, mp_ptr);
+
+#define mpn_hgcd_matrix_adjust __MPN (hgcd_matrix_adjust)
+__GMP_DECLSPEC mp_size_t mpn_hgcd_matrix_adjust (const struct hgcd_matrix *, mp_size_t, mp_ptr, mp_ptr, mp_size_t, mp_ptr);
+
+#define mpn_hgcd_step __MPN(hgcd_step)
+__GMP_DECLSPEC mp_size_t mpn_hgcd_step (mp_size_t, mp_ptr, mp_ptr, mp_size_t, struct hgcd_matrix *, mp_ptr);
+
+#define mpn_hgcd_reduce __MPN(hgcd_reduce)
+__GMP_DECLSPEC mp_size_t mpn_hgcd_reduce (struct hgcd_matrix *, mp_ptr, mp_ptr, mp_size_t, mp_size_t, mp_ptr);
+
+#define mpn_hgcd_reduce_itch __MPN(hgcd_reduce_itch)
+__GMP_DECLSPEC mp_size_t mpn_hgcd_reduce_itch (mp_size_t, mp_size_t) ATTRIBUTE_CONST;
+
+#define mpn_hgcd_itch __MPN (hgcd_itch)
+__GMP_DECLSPEC mp_size_t mpn_hgcd_itch (mp_size_t) ATTRIBUTE_CONST;
+
+#define mpn_hgcd __MPN (hgcd)
+__GMP_DECLSPEC mp_size_t mpn_hgcd (mp_ptr, mp_ptr, mp_size_t, struct hgcd_matrix *, mp_ptr);
+
+#define mpn_hgcd_appr_itch __MPN (hgcd_appr_itch)
+__GMP_DECLSPEC mp_size_t mpn_hgcd_appr_itch (mp_size_t) ATTRIBUTE_CONST;
+
+#define mpn_hgcd_appr __MPN (hgcd_appr)
+__GMP_DECLSPEC int mpn_hgcd_appr (mp_ptr, mp_ptr, mp_size_t, struct hgcd_matrix *, mp_ptr);
+
+#define mpn_hgcd_jacobi __MPN (hgcd_jacobi)
+__GMP_DECLSPEC mp_size_t mpn_hgcd_jacobi (mp_ptr, mp_ptr, mp_size_t, struct hgcd_matrix *, unsigned *, mp_ptr);
+
+typedef void gcd_subdiv_step_hook(void *, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, int);
+
+/* Needs storage for the quotient */
+#define MPN_GCD_SUBDIV_STEP_ITCH(n) (n)
+
+#define mpn_gcd_subdiv_step __MPN(gcd_subdiv_step)
+__GMP_DECLSPEC mp_size_t mpn_gcd_subdiv_step (mp_ptr, mp_ptr, mp_size_t, mp_size_t, gcd_subdiv_step_hook *, void *, mp_ptr);
+
+struct gcdext_ctx
+{
+  /* Result parameters. */
+  mp_ptr gp;
+  mp_size_t gn;
+  mp_ptr up;
+  mp_size_t *usize;
+
+  /* Cofactors updated in each step. */
+  mp_size_t un;
+  mp_ptr u0, u1, tp;
+};
+
+#define mpn_gcdext_hook __MPN (gcdext_hook)
+gcd_subdiv_step_hook mpn_gcdext_hook;
+
+#define MPN_GCDEXT_LEHMER_N_ITCH(n) (4*(n) + 3)
+
+#define mpn_gcdext_lehmer_n __MPN(gcdext_lehmer_n)
+__GMP_DECLSPEC mp_size_t mpn_gcdext_lehmer_n (mp_ptr, mp_ptr, mp_size_t *, mp_ptr, mp_ptr, mp_size_t, mp_ptr);
+
+/* 4*(an + 1) + 4*(bn + 1) + an */
+#define MPN_GCDEXT_LEHMER_ITCH(an, bn) (5*(an) + 4*(bn) + 8)
+
+#ifndef HGCD_THRESHOLD
+#define HGCD_THRESHOLD 400
+#endif
+
+#ifndef HGCD_APPR_THRESHOLD
+#define HGCD_APPR_THRESHOLD 400
+#endif
+
+#ifndef HGCD_REDUCE_THRESHOLD
+#define HGCD_REDUCE_THRESHOLD 1000
+#endif
+
+#ifndef GCD_DC_THRESHOLD
+#define GCD_DC_THRESHOLD 1000
+#endif
+
+#ifndef GCDEXT_DC_THRESHOLD
+#define GCDEXT_DC_THRESHOLD 600
+#endif
+
+/* Definitions for mpn_set_str and mpn_get_str */
+struct powers
+{
+  mp_ptr p;			/* actual power value */
+  mp_size_t n;			/* # of limbs at p */
+  mp_size_t shift;		/* weight of lowest limb, in limb base B */
+  size_t digits_in_base;	/* number of corresponding digits */
+  int base;
+};
+typedef struct powers powers_t;
+#define mpn_str_powtab_alloc(n) ((n) + 2 * GMP_LIMB_BITS) /* FIXME: This can perhaps be trimmed */
+#define mpn_dc_set_str_itch(n) ((n) + GMP_LIMB_BITS)
+#define mpn_dc_get_str_itch(n) ((n) + GMP_LIMB_BITS)
+
+#define mpn_compute_powtab __MPN(compute_powtab)
+__GMP_DECLSPEC size_t mpn_compute_powtab (powers_t *, mp_ptr, mp_size_t, int);
+#define   mpn_dc_set_str __MPN(dc_set_str)
+__GMP_DECLSPEC mp_size_t mpn_dc_set_str (mp_ptr, const unsigned char *, size_t, const powers_t *, mp_ptr);
+#define   mpn_bc_set_str __MPN(bc_set_str)
+__GMP_DECLSPEC mp_size_t mpn_bc_set_str (mp_ptr, const unsigned char *, size_t, int);
+
+
+/* __GMPF_BITS_TO_PREC applies a minimum 53 bits, rounds upwards to a whole
+   limb and adds an extra limb.  __GMPF_PREC_TO_BITS drops that extra limb,
+   hence giving back the user's size in bits rounded up.  Notice that
+   converting prec->bits->prec gives an unchanged value.  */
+#define __GMPF_BITS_TO_PREC(n)						\
+  ((mp_size_t) ((__GMP_MAX (53, n) + 2 * GMP_NUMB_BITS - 1) / GMP_NUMB_BITS))
+#define __GMPF_PREC_TO_BITS(n) \
+  ((mp_bitcnt_t) (n) * GMP_NUMB_BITS - GMP_NUMB_BITS)
+
+__GMP_DECLSPEC extern mp_size_t __gmp_default_fp_limb_precision;
+
+/* Compute the number of base-b digits corresponding to nlimbs limbs, rounding
+   down.  */
+#define DIGITS_IN_BASE_PER_LIMB(res, nlimbs, b)				\
+  do {									\
+    mp_limb_t _ph, _dummy;						\
+    umul_ppmm (_ph, _dummy,						\
+	       mp_bases[b].logb2, GMP_NUMB_BITS * (mp_limb_t) (nlimbs));\
+    res = _ph;								\
+  } while (0)
+
+/* Compute the number of limbs corresponding to ndigits base-b digits, rounding
+   up.  */
+#define LIMBS_PER_DIGIT_IN_BASE(res, ndigits, b)			\
+  do {									\
+    mp_limb_t _ph, _dummy;						\
+    umul_ppmm (_ph, _dummy, mp_bases[b].log2b, (mp_limb_t) (ndigits));	\
+    res = 8 * _ph / GMP_NUMB_BITS + 2;					\
+  } while (0)
+
+
+/* Set n to the number of significant digits an mpf of the given _mp_prec
+   field, in the given base.  This is a rounded up value, designed to ensure
+   there's enough digits to reproduce all the guaranteed part of the value.
+
+   There are prec many limbs, but the high might be only "1" so forget it
+   and just count prec-1 limbs into chars.  +1 rounds that upwards, and a
+   further +1 is because the limbs usually won't fall on digit boundaries.
+
+   FIXME: If base is a power of 2 and the bits per digit divides
+   GMP_LIMB_BITS then the +2 is unnecessary.  This happens always for
+   base==2, and in base==16 with the current 32 or 64 bit limb sizes. */
+
+#define MPF_SIGNIFICANT_DIGITS(n, base, prec)				\
+  do {									\
+    size_t rawn;							\
+    ASSERT (base >= 2 && base < numberof (mp_bases));			\
+    DIGITS_IN_BASE_PER_LIMB (rawn, (prec) - 1, base);			\
+    n = rawn + 2;							\
+  } while (0)
+
+
+/* Decimal point string, from the current C locale.  Needs <langinfo.h> for
+   nl_langinfo and constants, preferably with _GNU_SOURCE defined to get
+   DECIMAL_POINT from glibc, and needs <locale.h> for localeconv, each under
+   their respective #if HAVE_FOO_H.
+
+   GLIBC recommends nl_langinfo because getting only one facet can be
+   faster, apparently. */
+
+/* DECIMAL_POINT seems to need _GNU_SOURCE defined to get it from glibc. */
+#if HAVE_NL_LANGINFO && defined (DECIMAL_POINT)
+#define GMP_DECIMAL_POINT  (nl_langinfo (DECIMAL_POINT))
+#endif
+/* RADIXCHAR is deprecated, still in unix98 or some such. */
+#if HAVE_NL_LANGINFO && defined (RADIXCHAR) && ! defined (GMP_DECIMAL_POINT)
+#define GMP_DECIMAL_POINT  (nl_langinfo (RADIXCHAR))
+#endif
+/* localeconv is slower since it returns all locale stuff */
+#if HAVE_LOCALECONV && ! defined (GMP_DECIMAL_POINT)
+#define GMP_DECIMAL_POINT  (localeconv()->decimal_point)
+#endif
+#if ! defined (GMP_DECIMAL_POINT)
+#define GMP_DECIMAL_POINT  (".")
+#endif
+
+
+#define DOPRNT_CONV_FIXED        1
+#define DOPRNT_CONV_SCIENTIFIC   2
+#define DOPRNT_CONV_GENERAL      3
+
+#define DOPRNT_JUSTIFY_NONE      0
+#define DOPRNT_JUSTIFY_LEFT      1
+#define DOPRNT_JUSTIFY_RIGHT     2
+#define DOPRNT_JUSTIFY_INTERNAL  3
+
+#define DOPRNT_SHOWBASE_YES      1
+#define DOPRNT_SHOWBASE_NO       2
+#define DOPRNT_SHOWBASE_NONZERO  3
+
+struct doprnt_params_t {
+  int         base;          /* negative for upper case */
+  int         conv;          /* choices above */
+  const char  *expfmt;       /* exponent format */
+  int         exptimes4;     /* exponent multiply by 4 */
+  char        fill;          /* character */
+  int         justify;       /* choices above */
+  int         prec;          /* prec field, or -1 for all digits */
+  int         showbase;      /* choices above */
+  int         showpoint;     /* if radix point always shown */
+  int         showtrailing;  /* if trailing zeros wanted */
+  char        sign;          /* '+', ' ', or '\0' */
+  int         width;         /* width field */
+};
+
+#if _GMP_H_HAVE_VA_LIST
+
+typedef int (*doprnt_format_t) (void *, const char *, va_list);
+typedef int (*doprnt_memory_t) (void *, const char *, size_t);
+typedef int (*doprnt_reps_t)   (void *, int, int);
+typedef int (*doprnt_final_t)  (void *);
+
+struct doprnt_funs_t {
+  doprnt_format_t  format;
+  doprnt_memory_t  memory;
+  doprnt_reps_t    reps;
+  doprnt_final_t   final;   /* NULL if not required */
+};
+
+extern const struct doprnt_funs_t  __gmp_fprintf_funs;
+extern const struct doprnt_funs_t  __gmp_sprintf_funs;
+extern const struct doprnt_funs_t  __gmp_snprintf_funs;
+extern const struct doprnt_funs_t  __gmp_obstack_printf_funs;
+extern const struct doprnt_funs_t  __gmp_ostream_funs;
+
+/* "buf" is a __gmp_allocate_func block of "alloc" many bytes.  The first
+   "size" of these have been written.  "alloc > size" is maintained, so
+   there's room to store a '\0' at the end.  "result" is where the
+   application wants the final block pointer.  */
+struct gmp_asprintf_t {
+  char    **result;
+  char    *buf;
+  size_t  size;
+  size_t  alloc;
+};
+
+#define GMP_ASPRINTF_T_INIT(d, output)					\
+  do {									\
+    (d).result = (output);						\
+    (d).alloc = 256;							\
+    (d).buf = (char *) (*__gmp_allocate_func) ((d).alloc);		\
+    (d).size = 0;							\
+  } while (0)
+
+/* If a realloc is necessary, use twice the size actually required, so as to
+   avoid repeated small reallocs.  */
+#define GMP_ASPRINTF_T_NEED(d, n)					\
+  do {									\
+    size_t  alloc, newsize, newalloc;					\
+    ASSERT ((d)->alloc >= (d)->size + 1);				\
+									\
+    alloc = (d)->alloc;							\
+    newsize = (d)->size + (n);						\
+    if (alloc <= newsize)						\
+      {									\
+	newalloc = 2*newsize;						\
+	(d)->alloc = newalloc;						\
+	(d)->buf = __GMP_REALLOCATE_FUNC_TYPE ((d)->buf,		\
+					       alloc, newalloc, char);	\
+      }									\
+  } while (0)
+
+__GMP_DECLSPEC int __gmp_asprintf_memory (struct gmp_asprintf_t *, const char *, size_t);
+__GMP_DECLSPEC int __gmp_asprintf_reps (struct gmp_asprintf_t *, int, int);
+__GMP_DECLSPEC int __gmp_asprintf_final (struct gmp_asprintf_t *);
+
+/* buf is where to write the next output, and size is how much space is left
+   there.  If the application passed size==0 then that's what we'll have
+   here, and nothing at all should be written.  */
+struct gmp_snprintf_t {
+  char    *buf;
+  size_t  size;
+};
+
+/* Add the bytes printed by the call to the total retval, or bail out on an
+   error.  */
+#define DOPRNT_ACCUMULATE(call)						\
+  do {									\
+    int  __ret;								\
+    __ret = call;							\
+    if (__ret == -1)							\
+      goto error;							\
+    retval += __ret;							\
+  } while (0)
+#define DOPRNT_ACCUMULATE_FUN(fun, params)				\
+  do {									\
+    ASSERT ((fun) != NULL);						\
+    DOPRNT_ACCUMULATE ((*(fun)) params);				\
+  } while (0)
+
+#define DOPRNT_FORMAT(fmt, ap)						\
+  DOPRNT_ACCUMULATE_FUN (funs->format, (data, fmt, ap))
+#define DOPRNT_MEMORY(ptr, len)						\
+  DOPRNT_ACCUMULATE_FUN (funs->memory, (data, ptr, len))
+#define DOPRNT_REPS(c, n)						\
+  DOPRNT_ACCUMULATE_FUN (funs->reps, (data, c, n))
+
+#define DOPRNT_STRING(str)      DOPRNT_MEMORY (str, strlen (str))
+
+#define DOPRNT_REPS_MAYBE(c, n)						\
+  do {									\
+    if ((n) != 0)							\
+      DOPRNT_REPS (c, n);						\
+  } while (0)
+#define DOPRNT_MEMORY_MAYBE(ptr, len)					\
+  do {									\
+    if ((len) != 0)							\
+      DOPRNT_MEMORY (ptr, len);						\
+  } while (0)
+
+__GMP_DECLSPEC int __gmp_doprnt (const struct doprnt_funs_t *, void *, const char *, va_list);
+__GMP_DECLSPEC int __gmp_doprnt_integer (const struct doprnt_funs_t *, void *, const struct doprnt_params_t *, const char *);
+
+#define __gmp_doprnt_mpf __gmp_doprnt_mpf2
+__GMP_DECLSPEC int __gmp_doprnt_mpf (const struct doprnt_funs_t *, void *, const struct doprnt_params_t *, const char *, mpf_srcptr);
+
+__GMP_DECLSPEC int __gmp_replacement_vsnprintf (char *, size_t, const char *, va_list);
+#endif /* _GMP_H_HAVE_VA_LIST */
+
+
+typedef int (*gmp_doscan_scan_t)  (void *, const char *, ...);
+typedef void *(*gmp_doscan_step_t) (void *, int);
+typedef int (*gmp_doscan_get_t)   (void *);
+typedef int (*gmp_doscan_unget_t) (int, void *);
+
+struct gmp_doscan_funs_t {
+  gmp_doscan_scan_t   scan;
+  gmp_doscan_step_t   step;
+  gmp_doscan_get_t    get;
+  gmp_doscan_unget_t  unget;
+};
+extern const struct gmp_doscan_funs_t  __gmp_fscanf_funs;
+extern const struct gmp_doscan_funs_t  __gmp_sscanf_funs;
+
+#if _GMP_H_HAVE_VA_LIST
+__GMP_DECLSPEC int __gmp_doscan (const struct gmp_doscan_funs_t *, void *, const char *, va_list);
+#endif
+
+
+/* For testing and debugging.  */
+#define MPZ_CHECK_FORMAT(z)						\
+  do {									\
+    ASSERT_ALWAYS (SIZ(z) == 0 || PTR(z)[ABSIZ(z) - 1] != 0);		\
+    ASSERT_ALWAYS (ALLOC(z) >= ABSIZ(z));				\
+    ASSERT_ALWAYS_MPN (PTR(z), ABSIZ(z));				\
+  } while (0)
+
+#define MPQ_CHECK_FORMAT(q)						\
+  do {									\
+    MPZ_CHECK_FORMAT (mpq_numref (q));					\
+    MPZ_CHECK_FORMAT (mpq_denref (q));					\
+    ASSERT_ALWAYS (SIZ(mpq_denref(q)) >= 1);				\
+									\
+    if (SIZ(mpq_numref(q)) == 0)					\
+      {									\
+	/* should have zero as 0/1 */					\
+	ASSERT_ALWAYS (SIZ(mpq_denref(q)) == 1				\
+		       && PTR(mpq_denref(q))[0] == 1);			\
+      }									\
+    else								\
+      {									\
+	/* should have no common factors */				\
+	mpz_t  g;							\
+	mpz_init (g);							\
+	mpz_gcd (g, mpq_numref(q), mpq_denref(q));			\
+	ASSERT_ALWAYS (mpz_cmp_ui (g, 1) == 0);				\
+	mpz_clear (g);							\
+      }									\
+  } while (0)
+
+#define MPF_CHECK_FORMAT(f)						\
+  do {									\
+    ASSERT_ALWAYS (PREC(f) >= __GMPF_BITS_TO_PREC(53));			\
+    ASSERT_ALWAYS (ABSIZ(f) <= PREC(f)+1);				\
+    if (SIZ(f) == 0)							\
+      ASSERT_ALWAYS (EXP(f) == 0);					\
+    if (SIZ(f) != 0)							\
+      ASSERT_ALWAYS (PTR(f)[ABSIZ(f) - 1] != 0);			\
+  } while (0)
+
+
+/* Enhancement: The "mod" and "gcd_1" functions below could have
+   __GMP_ATTRIBUTE_PURE, but currently (gcc 3.3) that's not supported on
+   function pointers, only actual functions.  It probably doesn't make much
+   difference to the gmp code, since hopefully we arrange calls so there's
+   no great need for the compiler to move things around.  */
+
+#if WANT_FAT_BINARY && (HAVE_HOST_CPU_FAMILY_x86 || HAVE_HOST_CPU_FAMILY_x86_64)
+/* NOTE: The function pointers in this struct are also in CPUVEC_FUNCS_LIST
+   in mpn/x86/x86-defs.m4 and mpn/x86_64/x86_64-defs.m4.  Be sure to update
+   those when changing here.  */
+struct cpuvec_t {
+  DECL_add_n           ((*add_n));
+  DECL_addlsh1_n       ((*addlsh1_n));
+  DECL_addlsh2_n       ((*addlsh2_n));
+  DECL_addmul_1        ((*addmul_1));
+  DECL_addmul_2        ((*addmul_2));
+  DECL_bdiv_dbm1c      ((*bdiv_dbm1c));
+  DECL_cnd_add_n       ((*cnd_add_n));
+  DECL_cnd_sub_n       ((*cnd_sub_n));
+  DECL_com             ((*com));
+  DECL_copyd           ((*copyd));
+  DECL_copyi           ((*copyi));
+  DECL_divexact_1      ((*divexact_1));
+  DECL_divrem_1        ((*divrem_1));
+  DECL_gcd_11          ((*gcd_11));
+  DECL_lshift          ((*lshift));
+  DECL_lshiftc         ((*lshiftc));
+  DECL_mod_1           ((*mod_1));
+  DECL_mod_1_1p        ((*mod_1_1p));
+  DECL_mod_1_1p_cps    ((*mod_1_1p_cps));
+  DECL_mod_1s_2p       ((*mod_1s_2p));
+  DECL_mod_1s_2p_cps   ((*mod_1s_2p_cps));
+  DECL_mod_1s_4p       ((*mod_1s_4p));
+  DECL_mod_1s_4p_cps   ((*mod_1s_4p_cps));
+  DECL_mod_34lsub1     ((*mod_34lsub1));
+  DECL_modexact_1c_odd ((*modexact_1c_odd));
+  DECL_mul_1           ((*mul_1));
+  DECL_mul_basecase    ((*mul_basecase));
+  DECL_mullo_basecase  ((*mullo_basecase));
+  DECL_preinv_divrem_1 ((*preinv_divrem_1));
+  DECL_preinv_mod_1    ((*preinv_mod_1));
+  DECL_redc_1          ((*redc_1));
+  DECL_redc_2          ((*redc_2));
+  DECL_rshift          ((*rshift));
+  DECL_sqr_basecase    ((*sqr_basecase));
+  DECL_sub_n           ((*sub_n));
+  DECL_sublsh1_n       ((*sublsh1_n));
+  DECL_submul_1        ((*submul_1));
+  mp_size_t            mul_toom22_threshold;
+  mp_size_t            mul_toom33_threshold;
+  mp_size_t            sqr_toom2_threshold;
+  mp_size_t            sqr_toom3_threshold;
+  mp_size_t            bmod_1_to_mod_1_threshold;
+};
+__GMP_DECLSPEC extern struct cpuvec_t __gmpn_cpuvec;
+__GMP_DECLSPEC extern int __gmpn_cpuvec_initialized;
+#endif /* x86 fat binary */
+
+__GMP_DECLSPEC void __gmpn_cpuvec_init (void);
+
+/* Get a threshold "field" from __gmpn_cpuvec, running __gmpn_cpuvec_init()
+   if that hasn't yet been done (to establish the right values).  */
+#define CPUVEC_THRESHOLD(field)						      \
+  ((LIKELY (__gmpn_cpuvec_initialized) ? 0 : (__gmpn_cpuvec_init (), 0)),     \
+   __gmpn_cpuvec.field)
+
+
+#if HAVE_NATIVE_mpn_add_nc
+#define mpn_add_nc __MPN(add_nc)
+__GMP_DECLSPEC mp_limb_t mpn_add_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+#else
+static inline
+mp_limb_t
+mpn_add_nc (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n, mp_limb_t ci)
+{
+  mp_limb_t co;
+  co = mpn_add_n (rp, up, vp, n);
+  co += mpn_add_1 (rp, rp, n, ci);
+  return co;
+}
+#endif
+
+#if HAVE_NATIVE_mpn_sub_nc
+#define mpn_sub_nc __MPN(sub_nc)
+__GMP_DECLSPEC mp_limb_t mpn_sub_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+#else
+static inline mp_limb_t
+mpn_sub_nc (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n, mp_limb_t ci)
+{
+  mp_limb_t co;
+  co = mpn_sub_n (rp, up, vp, n);
+  co += mpn_sub_1 (rp, rp, n, ci);
+  return co;
+}
+#endif
+
+#if TUNE_PROGRAM_BUILD
+/* Some extras wanted when recompiling some .c files for use by the tune
+   program.  Not part of a normal build.
+
+   It's necessary to keep these thresholds as #defines (just to an
+   identically named variable), since various defaults are established based
+   on #ifdef in the .c files.  For some this is not so (the defaults are
+   instead established above), but all are done this way for consistency. */
+
+#undef	MUL_TOOM22_THRESHOLD
+#define MUL_TOOM22_THRESHOLD		mul_toom22_threshold
+extern mp_size_t			mul_toom22_threshold;
+
+#undef	MUL_TOOM33_THRESHOLD
+#define MUL_TOOM33_THRESHOLD		mul_toom33_threshold
+extern mp_size_t			mul_toom33_threshold;
+
+#undef	MUL_TOOM44_THRESHOLD
+#define MUL_TOOM44_THRESHOLD		mul_toom44_threshold
+extern mp_size_t			mul_toom44_threshold;
+
+#undef	MUL_TOOM6H_THRESHOLD
+#define MUL_TOOM6H_THRESHOLD		mul_toom6h_threshold
+extern mp_size_t			mul_toom6h_threshold;
+
+#undef	MUL_TOOM8H_THRESHOLD
+#define MUL_TOOM8H_THRESHOLD		mul_toom8h_threshold
+extern mp_size_t			mul_toom8h_threshold;
+
+#undef	MUL_TOOM32_TO_TOOM43_THRESHOLD
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD	mul_toom32_to_toom43_threshold
+extern mp_size_t			mul_toom32_to_toom43_threshold;
+
+#undef	MUL_TOOM32_TO_TOOM53_THRESHOLD
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD	mul_toom32_to_toom53_threshold
+extern mp_size_t			mul_toom32_to_toom53_threshold;
+
+#undef	MUL_TOOM42_TO_TOOM53_THRESHOLD
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD	mul_toom42_to_toom53_threshold
+extern mp_size_t			mul_toom42_to_toom53_threshold;
+
+#undef	MUL_TOOM42_TO_TOOM63_THRESHOLD
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD	mul_toom42_to_toom63_threshold
+extern mp_size_t			mul_toom42_to_toom63_threshold;
+
+#undef  MUL_TOOM43_TO_TOOM54_THRESHOLD
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD	mul_toom43_to_toom54_threshold;
+extern mp_size_t			mul_toom43_to_toom54_threshold;
+
+#undef	MUL_FFT_THRESHOLD
+#define MUL_FFT_THRESHOLD		mul_fft_threshold
+extern mp_size_t			mul_fft_threshold;
+
+#undef	MUL_FFT_MODF_THRESHOLD
+#define MUL_FFT_MODF_THRESHOLD		mul_fft_modf_threshold
+extern mp_size_t			mul_fft_modf_threshold;
+
+#undef	MUL_FFT_TABLE
+#define MUL_FFT_TABLE			{ 0 }
+
+#undef	MUL_FFT_TABLE3
+#define MUL_FFT_TABLE3			{ {0,0} }
+
+/* A native mpn_sqr_basecase is not tuned and SQR_BASECASE_THRESHOLD should
+   remain as zero (always use it). */
+#if ! HAVE_NATIVE_mpn_sqr_basecase
+#undef	SQR_BASECASE_THRESHOLD
+#define SQR_BASECASE_THRESHOLD		sqr_basecase_threshold
+extern mp_size_t			sqr_basecase_threshold;
+#endif
+
+#if TUNE_PROGRAM_BUILD_SQR
+#undef	SQR_TOOM2_THRESHOLD
+#define SQR_TOOM2_THRESHOLD		SQR_TOOM2_MAX_GENERIC
+#else
+#undef	SQR_TOOM2_THRESHOLD
+#define SQR_TOOM2_THRESHOLD		sqr_toom2_threshold
+extern mp_size_t			sqr_toom2_threshold;
+#endif
+
+#undef	SQR_TOOM3_THRESHOLD
+#define SQR_TOOM3_THRESHOLD		sqr_toom3_threshold
+extern mp_size_t			sqr_toom3_threshold;
+
+#undef	SQR_TOOM4_THRESHOLD
+#define SQR_TOOM4_THRESHOLD		sqr_toom4_threshold
+extern mp_size_t			sqr_toom4_threshold;
+
+#undef	SQR_TOOM6_THRESHOLD
+#define SQR_TOOM6_THRESHOLD		sqr_toom6_threshold
+extern mp_size_t			sqr_toom6_threshold;
+
+#undef	SQR_TOOM8_THRESHOLD
+#define SQR_TOOM8_THRESHOLD		sqr_toom8_threshold
+extern mp_size_t			sqr_toom8_threshold;
+
+#undef  SQR_FFT_THRESHOLD
+#define SQR_FFT_THRESHOLD		sqr_fft_threshold
+extern mp_size_t			sqr_fft_threshold;
+
+#undef  SQR_FFT_MODF_THRESHOLD
+#define SQR_FFT_MODF_THRESHOLD		sqr_fft_modf_threshold
+extern mp_size_t			sqr_fft_modf_threshold;
+
+#undef	SQR_FFT_TABLE
+#define SQR_FFT_TABLE			{ 0 }
+
+#undef	SQR_FFT_TABLE3
+#define SQR_FFT_TABLE3			{ {0,0} }
+
+#undef	MULLO_BASECASE_THRESHOLD
+#define MULLO_BASECASE_THRESHOLD	mullo_basecase_threshold
+extern mp_size_t			mullo_basecase_threshold;
+
+#undef	MULLO_DC_THRESHOLD
+#define MULLO_DC_THRESHOLD		mullo_dc_threshold
+extern mp_size_t			mullo_dc_threshold;
+
+#undef	MULLO_MUL_N_THRESHOLD
+#define MULLO_MUL_N_THRESHOLD		mullo_mul_n_threshold
+extern mp_size_t			mullo_mul_n_threshold;
+
+#undef	SQRLO_BASECASE_THRESHOLD
+#define SQRLO_BASECASE_THRESHOLD	sqrlo_basecase_threshold
+extern mp_size_t			sqrlo_basecase_threshold;
+
+#undef	SQRLO_DC_THRESHOLD
+#define SQRLO_DC_THRESHOLD		sqrlo_dc_threshold
+extern mp_size_t			sqrlo_dc_threshold;
+
+#undef	SQRLO_SQR_THRESHOLD
+#define SQRLO_SQR_THRESHOLD		sqrlo_sqr_threshold
+extern mp_size_t			sqrlo_sqr_threshold;
+
+#undef	MULMID_TOOM42_THRESHOLD
+#define MULMID_TOOM42_THRESHOLD		mulmid_toom42_threshold
+extern mp_size_t			mulmid_toom42_threshold;
+
+#undef	DIV_QR_2_PI2_THRESHOLD
+#define DIV_QR_2_PI2_THRESHOLD		div_qr_2_pi2_threshold
+extern mp_size_t			div_qr_2_pi2_threshold;
+
+#undef	DC_DIV_QR_THRESHOLD
+#define DC_DIV_QR_THRESHOLD		dc_div_qr_threshold
+extern mp_size_t			dc_div_qr_threshold;
+
+#undef	DC_DIVAPPR_Q_THRESHOLD
+#define DC_DIVAPPR_Q_THRESHOLD		dc_divappr_q_threshold
+extern mp_size_t			dc_divappr_q_threshold;
+
+#undef	DC_BDIV_Q_THRESHOLD
+#define DC_BDIV_Q_THRESHOLD		dc_bdiv_q_threshold
+extern mp_size_t			dc_bdiv_q_threshold;
+
+#undef	DC_BDIV_QR_THRESHOLD
+#define DC_BDIV_QR_THRESHOLD		dc_bdiv_qr_threshold
+extern mp_size_t			dc_bdiv_qr_threshold;
+
+#undef	MU_DIV_QR_THRESHOLD
+#define MU_DIV_QR_THRESHOLD		mu_div_qr_threshold
+extern mp_size_t			mu_div_qr_threshold;
+
+#undef	MU_DIVAPPR_Q_THRESHOLD
+#define MU_DIVAPPR_Q_THRESHOLD		mu_divappr_q_threshold
+extern mp_size_t			mu_divappr_q_threshold;
+
+#undef	MUPI_DIV_QR_THRESHOLD
+#define MUPI_DIV_QR_THRESHOLD		mupi_div_qr_threshold
+extern mp_size_t			mupi_div_qr_threshold;
+
+#undef	MU_BDIV_QR_THRESHOLD
+#define MU_BDIV_QR_THRESHOLD		mu_bdiv_qr_threshold
+extern mp_size_t			mu_bdiv_qr_threshold;
+
+#undef	MU_BDIV_Q_THRESHOLD
+#define MU_BDIV_Q_THRESHOLD		mu_bdiv_q_threshold
+extern mp_size_t			mu_bdiv_q_threshold;
+
+#undef	INV_MULMOD_BNM1_THRESHOLD
+#define INV_MULMOD_BNM1_THRESHOLD	inv_mulmod_bnm1_threshold
+extern mp_size_t			inv_mulmod_bnm1_threshold;
+
+#undef	INV_NEWTON_THRESHOLD
+#define INV_NEWTON_THRESHOLD		inv_newton_threshold
+extern mp_size_t			inv_newton_threshold;
+
+#undef	INV_APPR_THRESHOLD
+#define INV_APPR_THRESHOLD		inv_appr_threshold
+extern mp_size_t			inv_appr_threshold;
+
+#undef	BINV_NEWTON_THRESHOLD
+#define BINV_NEWTON_THRESHOLD		binv_newton_threshold
+extern mp_size_t			binv_newton_threshold;
+
+#undef	REDC_1_TO_REDC_2_THRESHOLD
+#define REDC_1_TO_REDC_2_THRESHOLD	redc_1_to_redc_2_threshold
+extern mp_size_t			redc_1_to_redc_2_threshold;
+
+#undef	REDC_2_TO_REDC_N_THRESHOLD
+#define REDC_2_TO_REDC_N_THRESHOLD	redc_2_to_redc_n_threshold
+extern mp_size_t			redc_2_to_redc_n_threshold;
+
+#undef	REDC_1_TO_REDC_N_THRESHOLD
+#define REDC_1_TO_REDC_N_THRESHOLD	redc_1_to_redc_n_threshold
+extern mp_size_t			redc_1_to_redc_n_threshold;
+
+#undef	MATRIX22_STRASSEN_THRESHOLD
+#define MATRIX22_STRASSEN_THRESHOLD	matrix22_strassen_threshold
+extern mp_size_t			matrix22_strassen_threshold;
+
+typedef int hgcd2_func_t (mp_limb_t, mp_limb_t, mp_limb_t, mp_limb_t,
+			  struct hgcd_matrix1 *);
+extern hgcd2_func_t *hgcd2_func;
+
+#undef	HGCD_THRESHOLD
+#define HGCD_THRESHOLD			hgcd_threshold
+extern mp_size_t			hgcd_threshold;
+
+#undef	HGCD_APPR_THRESHOLD
+#define HGCD_APPR_THRESHOLD		hgcd_appr_threshold
+extern mp_size_t			hgcd_appr_threshold;
+
+#undef	HGCD_REDUCE_THRESHOLD
+#define HGCD_REDUCE_THRESHOLD		hgcd_reduce_threshold
+extern mp_size_t			hgcd_reduce_threshold;
+
+#undef	GCD_DC_THRESHOLD
+#define GCD_DC_THRESHOLD		gcd_dc_threshold
+extern mp_size_t			gcd_dc_threshold;
+
+#undef  GCDEXT_DC_THRESHOLD
+#define GCDEXT_DC_THRESHOLD		gcdext_dc_threshold
+extern mp_size_t			gcdext_dc_threshold;
+
+#undef  DIV_QR_1N_PI1_METHOD
+#define DIV_QR_1N_PI1_METHOD		div_qr_1n_pi1_method
+extern int				div_qr_1n_pi1_method;
+
+#undef  DIV_QR_1_NORM_THRESHOLD
+#define DIV_QR_1_NORM_THRESHOLD		div_qr_1_norm_threshold
+extern mp_size_t			div_qr_1_norm_threshold;
+
+#undef  DIV_QR_1_UNNORM_THRESHOLD
+#define DIV_QR_1_UNNORM_THRESHOLD	div_qr_1_unnorm_threshold
+extern mp_size_t			div_qr_1_unnorm_threshold;
+
+#undef  DIVREM_1_NORM_THRESHOLD
+#define DIVREM_1_NORM_THRESHOLD		divrem_1_norm_threshold
+extern mp_size_t			divrem_1_norm_threshold;
+
+#undef  DIVREM_1_UNNORM_THRESHOLD
+#define DIVREM_1_UNNORM_THRESHOLD	divrem_1_unnorm_threshold
+extern mp_size_t			divrem_1_unnorm_threshold;
+
+#undef	MOD_1_NORM_THRESHOLD
+#define MOD_1_NORM_THRESHOLD		mod_1_norm_threshold
+extern mp_size_t			mod_1_norm_threshold;
+
+#undef	MOD_1_UNNORM_THRESHOLD
+#define MOD_1_UNNORM_THRESHOLD		mod_1_unnorm_threshold
+extern mp_size_t			mod_1_unnorm_threshold;
+
+#undef  MOD_1_1P_METHOD
+#define MOD_1_1P_METHOD			mod_1_1p_method
+extern int				mod_1_1p_method;
+
+#undef	MOD_1N_TO_MOD_1_1_THRESHOLD
+#define MOD_1N_TO_MOD_1_1_THRESHOLD	mod_1n_to_mod_1_1_threshold
+extern mp_size_t			mod_1n_to_mod_1_1_threshold;
+
+#undef	MOD_1U_TO_MOD_1_1_THRESHOLD
+#define MOD_1U_TO_MOD_1_1_THRESHOLD	mod_1u_to_mod_1_1_threshold
+extern mp_size_t			mod_1u_to_mod_1_1_threshold;
+
+#undef	MOD_1_1_TO_MOD_1_2_THRESHOLD
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD	mod_1_1_to_mod_1_2_threshold
+extern mp_size_t			mod_1_1_to_mod_1_2_threshold;
+
+#undef	MOD_1_2_TO_MOD_1_4_THRESHOLD
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD	mod_1_2_to_mod_1_4_threshold
+extern mp_size_t			mod_1_2_to_mod_1_4_threshold;
+
+#undef	PREINV_MOD_1_TO_MOD_1_THRESHOLD
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD	preinv_mod_1_to_mod_1_threshold
+extern mp_size_t			preinv_mod_1_to_mod_1_threshold;
+
+#if ! UDIV_PREINV_ALWAYS
+#undef	DIVREM_2_THRESHOLD
+#define DIVREM_2_THRESHOLD		divrem_2_threshold
+extern mp_size_t			divrem_2_threshold;
+#endif
+
+#undef	MULMOD_BNM1_THRESHOLD
+#define MULMOD_BNM1_THRESHOLD		mulmod_bnm1_threshold
+extern mp_size_t			mulmod_bnm1_threshold;
+
+#undef	SQRMOD_BNM1_THRESHOLD
+#define SQRMOD_BNM1_THRESHOLD		sqrmod_bnm1_threshold
+extern mp_size_t			sqrmod_bnm1_threshold;
+
+#undef	GET_STR_DC_THRESHOLD
+#define GET_STR_DC_THRESHOLD		get_str_dc_threshold
+extern mp_size_t			get_str_dc_threshold;
+
+#undef  GET_STR_PRECOMPUTE_THRESHOLD
+#define GET_STR_PRECOMPUTE_THRESHOLD	get_str_precompute_threshold
+extern mp_size_t			get_str_precompute_threshold;
+
+#undef	SET_STR_DC_THRESHOLD
+#define SET_STR_DC_THRESHOLD		set_str_dc_threshold
+extern mp_size_t			set_str_dc_threshold;
+
+#undef  SET_STR_PRECOMPUTE_THRESHOLD
+#define SET_STR_PRECOMPUTE_THRESHOLD	set_str_precompute_threshold
+extern mp_size_t			set_str_precompute_threshold;
+
+#undef  FAC_ODD_THRESHOLD
+#define FAC_ODD_THRESHOLD		fac_odd_threshold
+extern  mp_size_t			fac_odd_threshold;
+
+#undef  FAC_DSC_THRESHOLD
+#define FAC_DSC_THRESHOLD		fac_dsc_threshold
+extern  mp_size_t			fac_dsc_threshold;
+
+#undef  FFT_TABLE_ATTRS
+#define FFT_TABLE_ATTRS
+extern mp_size_t  mpn_fft_table[2][MPN_FFT_TABLE_SIZE];
+#define FFT_TABLE3_SIZE 2000	/* generous space for tuning */
+extern struct fft_table_nk mpn_fft_table3[2][FFT_TABLE3_SIZE];
+
+/* Sizes the tune program tests up to, used in a couple of recompilations. */
+#undef MUL_TOOM22_THRESHOLD_LIMIT
+#undef MUL_TOOM33_THRESHOLD_LIMIT
+#undef MULLO_BASECASE_THRESHOLD_LIMIT
+#undef SQRLO_BASECASE_THRESHOLD_LIMIT
+#undef SQRLO_DC_THRESHOLD_LIMIT
+#undef SQR_TOOM3_THRESHOLD_LIMIT
+#define SQR_TOOM2_MAX_GENERIC           200
+#define MUL_TOOM22_THRESHOLD_LIMIT      700
+#define MUL_TOOM33_THRESHOLD_LIMIT      700
+#define SQR_TOOM3_THRESHOLD_LIMIT       400
+#define MUL_TOOM44_THRESHOLD_LIMIT     1000
+#define SQR_TOOM4_THRESHOLD_LIMIT      1000
+#define MUL_TOOM6H_THRESHOLD_LIMIT     1100
+#define SQR_TOOM6_THRESHOLD_LIMIT      1100
+#define MUL_TOOM8H_THRESHOLD_LIMIT     1200
+#define SQR_TOOM8_THRESHOLD_LIMIT      1200
+#define MULLO_BASECASE_THRESHOLD_LIMIT  200
+#define SQRLO_BASECASE_THRESHOLD_LIMIT  200
+#define SQRLO_DC_THRESHOLD_LIMIT        400
+#define GET_STR_THRESHOLD_LIMIT         150
+#define FAC_DSC_THRESHOLD_LIMIT        2048
+
+#endif /* TUNE_PROGRAM_BUILD */
+
+#if defined (__cplusplus)
+}
+#endif
+
+/* FIXME: Make these itch functions less conservative.  Also consider making
+   them dependent on just 'an', and compute the allocation directly from 'an'
+   instead of via n.  */
+
+/* toom22/toom2: Scratch need is 2*(an + k), k is the recursion depth.
+   k is ths smallest k such that
+     ceil(an/2^k) < MUL_TOOM22_THRESHOLD.
+   which implies that
+     k = bitsize of floor ((an-1)/(MUL_TOOM22_THRESHOLD-1))
+       = 1 + floor (log_2 (floor ((an-1)/(MUL_TOOM22_THRESHOLD-1))))
+*/
+#define mpn_toom22_mul_itch(an, bn) \
+  (2 * ((an) + GMP_NUMB_BITS))
+#define mpn_toom2_sqr_itch(an) \
+  (2 * ((an) + GMP_NUMB_BITS))
+
+/* toom33/toom3: Scratch need is 5an/2 + 10k, k is the recursion depth.
+   We use 3an + C, so that we can use a smaller constant.
+ */
+#define mpn_toom33_mul_itch(an, bn) \
+  (3 * (an) + GMP_NUMB_BITS)
+#define mpn_toom3_sqr_itch(an) \
+  (3 * (an) + GMP_NUMB_BITS)
+
+/* toom33/toom3: Scratch need is 8an/3 + 13k, k is the recursion depth.
+   We use 3an + C, so that we can use a smaller constant.
+ */
+#define mpn_toom44_mul_itch(an, bn) \
+  (3 * (an) + GMP_NUMB_BITS)
+#define mpn_toom4_sqr_itch(an) \
+  (3 * (an) + GMP_NUMB_BITS)
+
+#define mpn_toom6_sqr_itch(n)						\
+  (((n) - SQR_TOOM6_THRESHOLD)*2 +					\
+   MAX(SQR_TOOM6_THRESHOLD*2 + GMP_NUMB_BITS*6,				\
+       mpn_toom4_sqr_itch(SQR_TOOM6_THRESHOLD)))
+
+#define MUL_TOOM6H_MIN							\
+  ((MUL_TOOM6H_THRESHOLD > MUL_TOOM44_THRESHOLD) ?			\
+    MUL_TOOM6H_THRESHOLD : MUL_TOOM44_THRESHOLD)
+#define mpn_toom6_mul_n_itch(n)						\
+  (((n) - MUL_TOOM6H_MIN)*2 +						\
+   MAX(MUL_TOOM6H_MIN*2 + GMP_NUMB_BITS*6,				\
+       mpn_toom44_mul_itch(MUL_TOOM6H_MIN,MUL_TOOM6H_MIN)))
+
+static inline mp_size_t
+mpn_toom6h_mul_itch (mp_size_t an, mp_size_t bn) {
+  mp_size_t estimatedN;
+  estimatedN = (an + bn) / (size_t) 10 + 1;
+  return mpn_toom6_mul_n_itch (estimatedN * 6);
+}
+
+#define mpn_toom8_sqr_itch(n)						\
+  ((((n)*15)>>3) - ((SQR_TOOM8_THRESHOLD*15)>>3) +			\
+   MAX(((SQR_TOOM8_THRESHOLD*15)>>3) + GMP_NUMB_BITS*6,			\
+       mpn_toom6_sqr_itch(SQR_TOOM8_THRESHOLD)))
+
+#define MUL_TOOM8H_MIN							\
+  ((MUL_TOOM8H_THRESHOLD > MUL_TOOM6H_MIN) ?				\
+    MUL_TOOM8H_THRESHOLD : MUL_TOOM6H_MIN)
+#define mpn_toom8_mul_n_itch(n)						\
+  ((((n)*15)>>3) - ((MUL_TOOM8H_MIN*15)>>3) +				\
+   MAX(((MUL_TOOM8H_MIN*15)>>3) + GMP_NUMB_BITS*6,			\
+       mpn_toom6_mul_n_itch(MUL_TOOM8H_MIN)))
+
+static inline mp_size_t
+mpn_toom8h_mul_itch (mp_size_t an, mp_size_t bn) {
+  mp_size_t estimatedN;
+  estimatedN = (an + bn) / (size_t) 14 + 1;
+  return mpn_toom8_mul_n_itch (estimatedN * 8);
+}
+
+static inline mp_size_t
+mpn_toom32_mul_itch (mp_size_t an, mp_size_t bn)
+{
+  mp_size_t n = 1 + (2 * an >= 3 * bn ? (an - 1) / (size_t) 3 : (bn - 1) >> 1);
+  mp_size_t itch = 2 * n + 1;
+
+  return itch;
+}
+
+static inline mp_size_t
+mpn_toom42_mul_itch (mp_size_t an, mp_size_t bn)
+{
+  mp_size_t n = an >= 2 * bn ? (an + 3) >> 2 : (bn + 1) >> 1;
+  return 6 * n + 3;
+}
+
+static inline mp_size_t
+mpn_toom43_mul_itch (mp_size_t an, mp_size_t bn)
+{
+  mp_size_t n = 1 + (3 * an >= 4 * bn ? (an - 1) >> 2 : (bn - 1) / (size_t) 3);
+
+  return 6*n + 4;
+}
+
+static inline mp_size_t
+mpn_toom52_mul_itch (mp_size_t an, mp_size_t bn)
+{
+  mp_size_t n = 1 + (2 * an >= 5 * bn ? (an - 1) / (size_t) 5 : (bn - 1) >> 1);
+  return 6*n + 4;
+}
+
+static inline mp_size_t
+mpn_toom53_mul_itch (mp_size_t an, mp_size_t bn)
+{
+  mp_size_t n = 1 + (3 * an >= 5 * bn ? (an - 1) / (size_t) 5 : (bn - 1) / (size_t) 3);
+  return 10 * n + 10;
+}
+
+static inline mp_size_t
+mpn_toom62_mul_itch (mp_size_t an, mp_size_t bn)
+{
+  mp_size_t n = 1 + (an >= 3 * bn ? (an - 1) / (size_t) 6 : (bn - 1) >> 1);
+  return 10 * n + 10;
+}
+
+static inline mp_size_t
+mpn_toom63_mul_itch (mp_size_t an, mp_size_t bn)
+{
+  mp_size_t n = 1 + (an >= 2 * bn ? (an - 1) / (size_t) 6 : (bn - 1) / (size_t) 3);
+  return 9 * n + 3;
+}
+
+static inline mp_size_t
+mpn_toom54_mul_itch (mp_size_t an, mp_size_t bn)
+{
+  mp_size_t n = 1 + (4 * an >= 5 * bn ? (an - 1) / (size_t) 5 : (bn - 1) / (size_t) 4);
+  return 9 * n + 3;
+}
+
+/* let S(n) = space required for input size n,
+   then S(n) = 3 floor(n/2) + 1 + S(floor(n/2)).   */
+#define mpn_toom42_mulmid_itch(n) \
+  (3 * (n) + GMP_NUMB_BITS)
+
+#if 0
+#define mpn_fft_mul mpn_mul_fft_full
+#else
+#define mpn_fft_mul mpn_nussbaumer_mul
+#endif
+
+#ifdef __cplusplus
+
+/* A little helper for a null-terminated __gmp_allocate_func string.
+   The destructor ensures it's freed even if an exception is thrown.
+   The len field is needed by the destructor, and can be used by anyone else
+   to avoid a second strlen pass over the data.
+
+   Since our input is a C string, using strlen is correct.  Perhaps it'd be
+   more C++-ish style to use std::char_traits<char>::length, but char_traits
+   isn't available in gcc 2.95.4.  */
+
+class gmp_allocated_string {
+ public:
+  char *str;
+  size_t len;
+  gmp_allocated_string(char *arg)
+  {
+    str = arg;
+    len = std::strlen (str);
+  }
+  ~gmp_allocated_string()
+  {
+    (*__gmp_free_func) (str, len+1);
+  }
+};
+
+std::istream &__gmpz_operator_in_nowhite (std::istream &, mpz_ptr, char);
+int __gmp_istream_set_base (std::istream &, char &, bool &, bool &);
+void __gmp_istream_set_digits (std::string &, std::istream &, char &, bool &, int);
+void __gmp_doprnt_params_from_ios (struct doprnt_params_t *, std::ios &);
+std::ostream& __gmp_doprnt_integer_ostream (std::ostream &, struct doprnt_params_t *, char *);
+extern const struct doprnt_funs_t  __gmp_asprintf_funs_noformat;
+
+#endif /* __cplusplus */
+
+#endif /* __GMP_IMPL_H__ */
diff --git a/third_party/gmp/gmp.pc.in b/third_party/gmp/gmp.pc.in
new file mode 100644
index 0000000..bf1c799
--- /dev/null
+++ b/third_party/gmp/gmp.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+includedir=@includedir@
+libdir=@libdir@
+
+Name: @PACKAGE_NAME@
+Description: GNU Multiple Precision Arithmetic Library
+URL: https://gmplib.org
+Version: @PACKAGE_VERSION@
+Cflags: -I${includedir}
+Libs: -L${libdir} -lgmp
diff --git a/third_party/gmp/gmpxx.h b/third_party/gmp/gmpxx.h
new file mode 100644
index 0000000..0342116
--- /dev/null
+++ b/third_party/gmp/gmpxx.h
@@ -0,0 +1,3703 @@
+/* gmpxx.h -- C++ class wrapper for GMP types.  -*- C++ -*-
+
+Copyright 2001-2003, 2006, 2008, 2011-2015, 2018 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#ifndef __GMP_PLUSPLUS__
+#define __GMP_PLUSPLUS__
+
+#include <iosfwd>
+
+#include <cstring>  /* for strlen */
+#include <limits>  /* numeric_limits */
+#include <utility>
+#include <algorithm>  /* swap */
+#include <string>
+#include <stdexcept>
+#include <cfloat>
+#include <gmp.h>
+
+// wrapper for gcc's __builtin_constant_p
+// __builtin_constant_p has been in gcc since forever,
+// but g++-3.4 miscompiles it.
+#if __GMP_GNUC_PREREQ(4, 2)
+#define __GMPXX_CONSTANT(X) __builtin_constant_p(X)
+#else
+#define __GMPXX_CONSTANT(X) false
+#endif
+#define __GMPXX_CONSTANT_TRUE(X) (__GMPXX_CONSTANT(X) && (X))
+
+// Use C++11 features
+#ifndef __GMPXX_USE_CXX11
+#if __cplusplus >= 201103L
+#define __GMPXX_USE_CXX11 1
+#else
+#define __GMPXX_USE_CXX11 0
+#endif
+#endif
+
+#if __GMPXX_USE_CXX11
+#define __GMPXX_NOEXCEPT noexcept
+#include <type_traits> // for common_type
+#else
+#define __GMPXX_NOEXCEPT
+#endif
+
+// Max allocations for plain types when converted to GMP types
+#if GMP_NAIL_BITS != 0 && ! defined _LONG_LONG_LIMB
+#define __GMPZ_ULI_LIMBS 2
+#else
+#define __GMPZ_ULI_LIMBS 1
+#endif
+
+#define __GMPXX_BITS_TO_LIMBS(n)  (((n) + (GMP_NUMB_BITS - 1)) / GMP_NUMB_BITS)
+#define __GMPZ_DBL_LIMBS __GMPXX_BITS_TO_LIMBS(DBL_MAX_EXP)+1
+#define __GMPQ_NUM_DBL_LIMBS __GMPZ_DBL_LIMBS
+#define __GMPQ_DEN_DBL_LIMBS __GMPXX_BITS_TO_LIMBS(DBL_MANT_DIG+1-DBL_MIN_EXP)+1
+// The final +1s are a security margin. The current implementation of
+// mpq_set_d seems to need it for the denominator.
+
+inline void __mpz_set_ui_safe(mpz_ptr p, unsigned long l)
+{
+  p->_mp_size = (l != 0);
+  p->_mp_d[0] = l & GMP_NUMB_MASK;
+#if __GMPZ_ULI_LIMBS > 1
+  l >>= GMP_NUMB_BITS;
+  p->_mp_d[1] = l;
+  p->_mp_size += (l != 0);
+#endif
+}
+
+inline void __mpz_set_si_safe(mpz_ptr p, long l)
+{
+  if(l < 0)
+  {
+    __mpz_set_ui_safe(p, -static_cast<unsigned long>(l));
+    mpz_neg(p, p);
+  }
+  else
+    __mpz_set_ui_safe(p, l);
+    // Note: we know the high bit of l is 0 so we could do slightly better
+}
+
+// Fake temporary variables
+#define __GMPXX_TMPZ_UI							\
+  mpz_t temp;								\
+  mp_limb_t limbs[__GMPZ_ULI_LIMBS];					\
+  temp->_mp_d = limbs;							\
+  __mpz_set_ui_safe (temp, l)
+#define __GMPXX_TMPZ_SI							\
+  mpz_t temp;								\
+  mp_limb_t limbs[__GMPZ_ULI_LIMBS];					\
+  temp->_mp_d = limbs;							\
+  __mpz_set_si_safe (temp, l)
+#define __GMPXX_TMPZ_D							\
+  mpz_t temp;								\
+  mp_limb_t limbs[__GMPZ_DBL_LIMBS];					\
+  temp->_mp_d = limbs;							\
+  temp->_mp_alloc = __GMPZ_DBL_LIMBS;					\
+  mpz_set_d (temp, d)
+
+#define __GMPXX_TMPQ_UI							\
+  mpq_t temp;								\
+  mp_limb_t limbs[__GMPZ_ULI_LIMBS+1];					\
+  mpq_numref(temp)->_mp_d = limbs;					\
+  __mpz_set_ui_safe (mpq_numref(temp), l);				\
+  mpq_denref(temp)->_mp_d = limbs + __GMPZ_ULI_LIMBS;			\
+  mpq_denref(temp)->_mp_size = 1;					\
+  mpq_denref(temp)->_mp_d[0] = 1
+#define __GMPXX_TMPQ_SI							\
+  mpq_t temp;								\
+  mp_limb_t limbs[__GMPZ_ULI_LIMBS+1];					\
+  mpq_numref(temp)->_mp_d = limbs;					\
+  __mpz_set_si_safe (mpq_numref(temp), l);				\
+  mpq_denref(temp)->_mp_d = limbs + __GMPZ_ULI_LIMBS;			\
+  mpq_denref(temp)->_mp_size = 1;					\
+  mpq_denref(temp)->_mp_d[0] = 1
+#define __GMPXX_TMPQ_D							\
+  mpq_t temp;								\
+  mp_limb_t limbs[__GMPQ_NUM_DBL_LIMBS + __GMPQ_DEN_DBL_LIMBS];		\
+  mpq_numref(temp)->_mp_d = limbs;					\
+  mpq_numref(temp)->_mp_alloc = __GMPQ_NUM_DBL_LIMBS;			\
+  mpq_denref(temp)->_mp_d = limbs + __GMPQ_NUM_DBL_LIMBS;		\
+  mpq_denref(temp)->_mp_alloc = __GMPQ_DEN_DBL_LIMBS;			\
+  mpq_set_d (temp, d)
+
+inline unsigned long __gmpxx_abs_ui (signed long l)
+{
+  return l >= 0 ? static_cast<unsigned long>(l)
+	  : -static_cast<unsigned long>(l);
+}
+
+/**************** Function objects ****************/
+/* Any evaluation of a __gmp_expr ends up calling one of these functions
+   all intermediate functions being inline, the evaluation should optimize
+   to a direct call to the relevant function, thus yielding no overhead
+   over the C interface. */
+
+struct __gmp_unary_plus
+{
+  static void eval(mpz_ptr z, mpz_srcptr w) { mpz_set(z, w); }
+  static void eval(mpq_ptr q, mpq_srcptr r) { mpq_set(q, r); }
+  static void eval(mpf_ptr f, mpf_srcptr g) { mpf_set(f, g); }
+};
+
+struct __gmp_unary_minus
+{
+  static void eval(mpz_ptr z, mpz_srcptr w) { mpz_neg(z, w); }
+  static void eval(mpq_ptr q, mpq_srcptr r) { mpq_neg(q, r); }
+  static void eval(mpf_ptr f, mpf_srcptr g) { mpf_neg(f, g); }
+};
+
+struct __gmp_unary_com
+{
+  static void eval(mpz_ptr z, mpz_srcptr w) { mpz_com(z, w); }
+};
+
+struct __gmp_binary_plus
+{
+  static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v)
+  { mpz_add(z, w, v); }
+
+  static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l)
+  {
+    // Ideally, those checks should happen earlier so that the tree
+    // generated for a+0+b would just be sum(a,b).
+    if (__GMPXX_CONSTANT(l) && l == 0)
+    {
+      if (z != w) mpz_set(z, w);
+    }
+    else
+      mpz_add_ui(z, w, l);
+  }
+  static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w)
+  { eval(z, w, l); }
+  static void eval(mpz_ptr z, mpz_srcptr w, signed long int l)
+  {
+    if (l >= 0)
+      eval(z, w, static_cast<unsigned long>(l));
+    else
+      mpz_sub_ui(z, w, -static_cast<unsigned long>(l));
+  }
+  static void eval(mpz_ptr z, signed long int l, mpz_srcptr w)
+  { eval(z, w, l); }
+  static void eval(mpz_ptr z, mpz_srcptr w, double d)
+  {  __GMPXX_TMPZ_D;    mpz_add (z, w, temp); }
+  static void eval(mpz_ptr z, double d, mpz_srcptr w)
+  { eval(z, w, d); }
+
+  static void eval(mpq_ptr q, mpq_srcptr r, mpq_srcptr s)
+  { mpq_add(q, r, s); }
+
+  static void eval(mpq_ptr q, mpq_srcptr r, unsigned long int l)
+  {
+    if (__GMPXX_CONSTANT(l) && l == 0)
+    {
+      if (q != r) mpq_set(q, r);
+    }
+    else if (__GMPXX_CONSTANT(l) && l == 1)
+    {
+      mpz_add (mpq_numref(q), mpq_numref(r), mpq_denref(r));
+      if (q != r) mpz_set(mpq_denref(q), mpq_denref(r));
+    }
+    else
+    {
+      if (q == r)
+        mpz_addmul_ui(mpq_numref(q), mpq_denref(q), l);
+      else
+      {
+        mpz_mul_ui(mpq_numref(q), mpq_denref(r), l);
+        mpz_add(mpq_numref(q), mpq_numref(q), mpq_numref(r));
+        mpz_set(mpq_denref(q), mpq_denref(r));
+      }
+    }
+  }
+  static void eval(mpq_ptr q, unsigned long int l, mpq_srcptr r)
+  { eval(q, r, l); }
+  static inline void eval(mpq_ptr q, mpq_srcptr r, signed long int l);
+  // defined after __gmp_binary_minus
+  static void eval(mpq_ptr q, signed long int l, mpq_srcptr r)
+  { eval(q, r, l); }
+  static void eval(mpq_ptr q, mpq_srcptr r, double d)
+  {  __GMPXX_TMPQ_D;    mpq_add (q, r, temp); }
+  static void eval(mpq_ptr q, double d, mpq_srcptr r)
+  { eval(q, r, d); }
+
+  static void eval(mpq_ptr q, mpq_srcptr r, mpz_srcptr z)
+  {
+    if (q == r)
+      mpz_addmul(mpq_numref(q), mpq_denref(q), z);
+    else
+    {
+      mpz_mul(mpq_numref(q), mpq_denref(r), z);
+      mpz_add(mpq_numref(q), mpq_numref(q), mpq_numref(r));
+      mpz_set(mpq_denref(q), mpq_denref(r));
+    }
+  }
+  static void eval(mpq_ptr q, mpz_srcptr z, mpq_srcptr r)
+  { eval(q, r, z); }
+
+  static void eval(mpf_ptr f, mpf_srcptr g, mpf_srcptr h)
+  { mpf_add(f, g, h); }
+
+  static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l)
+  { mpf_add_ui(f, g, l); }
+  static void eval(mpf_ptr f, unsigned long int l, mpf_srcptr g)
+  { mpf_add_ui(f, g, l); }
+  static void eval(mpf_ptr f, mpf_srcptr g, signed long int l)
+  {
+    if (l >= 0)
+      mpf_add_ui(f, g, l);
+    else
+      mpf_sub_ui(f, g, -static_cast<unsigned long>(l));
+  }
+  static void eval(mpf_ptr f, signed long int l, mpf_srcptr g)
+  { eval(f, g, l); }
+  static void eval(mpf_ptr f, mpf_srcptr g, double d)
+  {
+    mpf_t temp;
+    mpf_init2(temp, 8*sizeof(double));
+    mpf_set_d(temp, d);
+    mpf_add(f, g, temp);
+    mpf_clear(temp);
+  }
+  static void eval(mpf_ptr f, double d, mpf_srcptr g)
+  { eval(f, g, d); }
+};
+
+struct __gmp_binary_minus
+{
+  static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v)
+  { mpz_sub(z, w, v); }
+
+  static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l)
+  {
+    if (__GMPXX_CONSTANT(l) && l == 0)
+    {
+      if (z != w) mpz_set(z, w);
+    }
+    else
+      mpz_sub_ui(z, w, l);
+  }
+  static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w)
+  {
+    if (__GMPXX_CONSTANT(l) && l == 0)
+    {
+      mpz_neg(z, w);
+    }
+    else
+      mpz_ui_sub(z, l, w);
+  }
+  static void eval(mpz_ptr z, mpz_srcptr w, signed long int l)
+  {
+    if (l >= 0)
+      eval(z, w, static_cast<unsigned long>(l));
+    else
+      mpz_add_ui(z, w, -static_cast<unsigned long>(l));
+  }
+  static void eval(mpz_ptr z, signed long int l, mpz_srcptr w)
+  {
+    if (l >= 0)
+      eval(z, static_cast<unsigned long>(l), w);
+    else
+      {
+        mpz_add_ui(z, w, -static_cast<unsigned long>(l));
+        mpz_neg(z, z);
+      }
+  }
+  static void eval(mpz_ptr z, mpz_srcptr w, double d)
+  {  __GMPXX_TMPZ_D;    mpz_sub (z, w, temp); }
+  static void eval(mpz_ptr z, double d, mpz_srcptr w)
+  {  __GMPXX_TMPZ_D;    mpz_sub (z, temp, w); }
+
+  static void eval(mpq_ptr q, mpq_srcptr r, mpq_srcptr s)
+  { mpq_sub(q, r, s); }
+
+  static void eval(mpq_ptr q, mpq_srcptr r, unsigned long int l)
+  {
+    if (__GMPXX_CONSTANT(l) && l == 0)
+    {
+      if (q != r) mpq_set(q, r);
+    }
+    else if (__GMPXX_CONSTANT(l) && l == 1)
+    {
+      mpz_sub (mpq_numref(q), mpq_numref(r), mpq_denref(r));
+      if (q != r) mpz_set(mpq_denref(q), mpq_denref(r));
+    }
+    else
+    {
+      if (q == r)
+        mpz_submul_ui(mpq_numref(q), mpq_denref(q), l);
+      else
+      {
+        mpz_mul_ui(mpq_numref(q), mpq_denref(r), l);
+        mpz_sub(mpq_numref(q), mpq_numref(r), mpq_numref(q));
+        mpz_set(mpq_denref(q), mpq_denref(r));
+      }
+    }
+  }
+  static void eval(mpq_ptr q, unsigned long int l, mpq_srcptr r)
+  { eval(q, r, l); mpq_neg(q, q); }
+  static void eval(mpq_ptr q, mpq_srcptr r, signed long int l)
+  {
+    if (l >= 0)
+      eval(q, r, static_cast<unsigned long>(l));
+    else
+      __gmp_binary_plus::eval(q, r, -static_cast<unsigned long>(l));
+  }
+  static void eval(mpq_ptr q, signed long int l, mpq_srcptr r)
+  { eval(q, r, l); mpq_neg(q, q); }
+  static void eval(mpq_ptr q, mpq_srcptr r, double d)
+  {  __GMPXX_TMPQ_D;    mpq_sub (q, r, temp); }
+  static void eval(mpq_ptr q, double d, mpq_srcptr r)
+  {  __GMPXX_TMPQ_D;    mpq_sub (q, temp, r); }
+
+  static void eval(mpq_ptr q, mpq_srcptr r, mpz_srcptr z)
+  {
+    if (q == r)
+      mpz_submul(mpq_numref(q), mpq_denref(q), z);
+    else
+    {
+      mpz_mul(mpq_numref(q), mpq_denref(r), z);
+      mpz_sub(mpq_numref(q), mpq_numref(r), mpq_numref(q));
+      mpz_set(mpq_denref(q), mpq_denref(r));
+    }
+  }
+  static void eval(mpq_ptr q, mpz_srcptr z, mpq_srcptr r)
+  { eval(q, r, z); mpq_neg(q, q); }
+
+  static void eval(mpf_ptr f, mpf_srcptr g, mpf_srcptr h)
+  { mpf_sub(f, g, h); }
+
+  static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l)
+  { mpf_sub_ui(f, g, l); }
+  static void eval(mpf_ptr f, unsigned long int l, mpf_srcptr g)
+  { mpf_ui_sub(f, l, g); }
+  static void eval(mpf_ptr f, mpf_srcptr g, signed long int l)
+  {
+    if (l >= 0)
+      mpf_sub_ui(f, g, l);
+    else
+      mpf_add_ui(f, g, -static_cast<unsigned long>(l));
+  }
+  static void eval(mpf_ptr f, signed long int l, mpf_srcptr g)
+  {
+    if (l >= 0)
+      mpf_sub_ui(f, g, l);
+    else
+      mpf_add_ui(f, g, -static_cast<unsigned long>(l));
+    mpf_neg(f, f);
+  }
+  static void eval(mpf_ptr f, mpf_srcptr g, double d)
+  {
+    mpf_t temp;
+    mpf_init2(temp, 8*sizeof(double));
+    mpf_set_d(temp, d);
+    mpf_sub(f, g, temp);
+    mpf_clear(temp);
+  }
+  static void eval(mpf_ptr f, double d, mpf_srcptr g)
+  {
+    mpf_t temp;
+    mpf_init2(temp, 8*sizeof(double));
+    mpf_set_d(temp, d);
+    mpf_sub(f, temp, g);
+    mpf_clear(temp);
+  }
+};
+
+// defined here so it can reference __gmp_binary_minus
+inline void
+__gmp_binary_plus::eval(mpq_ptr q, mpq_srcptr r, signed long int l)
+{
+  if (l >= 0)
+    eval(q, r, static_cast<unsigned long>(l));
+  else
+    __gmp_binary_minus::eval(q, r, -static_cast<unsigned long>(l));
+}
+
+struct __gmp_binary_lshift
+{
+  static void eval(mpz_ptr z, mpz_srcptr w, mp_bitcnt_t l)
+  {
+    if (__GMPXX_CONSTANT(l) && (l == 0))
+    {
+      if (z != w) mpz_set(z, w);
+    }
+    else
+      mpz_mul_2exp(z, w, l);
+  }
+  static void eval(mpq_ptr q, mpq_srcptr r, mp_bitcnt_t l)
+  {
+    if (__GMPXX_CONSTANT(l) && (l == 0))
+    {
+      if (q != r) mpq_set(q, r);
+    }
+    else
+      mpq_mul_2exp(q, r, l);
+  }
+  static void eval(mpf_ptr f, mpf_srcptr g, mp_bitcnt_t l)
+  { mpf_mul_2exp(f, g, l); }
+};
+
+struct __gmp_binary_rshift
+{
+  static void eval(mpz_ptr z, mpz_srcptr w, mp_bitcnt_t l)
+  {
+    if (__GMPXX_CONSTANT(l) && (l == 0))
+    {
+      if (z != w) mpz_set(z, w);
+    }
+    else
+      mpz_fdiv_q_2exp(z, w, l);
+  }
+  static void eval(mpq_ptr q, mpq_srcptr r, mp_bitcnt_t l)
+  {
+    if (__GMPXX_CONSTANT(l) && (l == 0))
+    {
+      if (q != r) mpq_set(q, r);
+    }
+    else
+      mpq_div_2exp(q, r, l);
+  }
+  static void eval(mpf_ptr f, mpf_srcptr g, mp_bitcnt_t l)
+  { mpf_div_2exp(f, g, l); }
+};
+
+struct __gmp_binary_multiplies
+{
+  static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v)
+  { mpz_mul(z, w, v); }
+
+  static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l)
+  {
+// gcc-3.3 doesn't have __builtin_ctzl. Don't bother optimizing for old gcc.
+#if __GMP_GNUC_PREREQ(3, 4)
+    if (__GMPXX_CONSTANT(l) && (l & (l-1)) == 0)
+    {
+      if (l == 0)
+      {
+        z->_mp_size = 0;
+      }
+      else
+      {
+        __gmp_binary_lshift::eval(z, w, __builtin_ctzl(l));
+      }
+    }
+    else
+#endif
+      mpz_mul_ui(z, w, l);
+  }
+  static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w)
+  { eval(z, w, l); }
+  static void eval(mpz_ptr z, mpz_srcptr w, signed long int l)
+  {
+    if (__GMPXX_CONSTANT_TRUE(l >= 0))
+      eval(z, w, static_cast<unsigned long>(l));
+    else if (__GMPXX_CONSTANT_TRUE(l <= 0))
+      {
+        eval(z, w, -static_cast<unsigned long>(l));
+	mpz_neg(z, z);
+      }
+    else
+      mpz_mul_si (z, w, l);
+  }
+  static void eval(mpz_ptr z, signed long int l, mpz_srcptr w)
+  { eval(z, w, l); }
+  static void eval(mpz_ptr z, mpz_srcptr w, double d)
+  {  __GMPXX_TMPZ_D;    mpz_mul (z, w, temp); }
+  static void eval(mpz_ptr z, double d, mpz_srcptr w)
+  { eval(z, w, d); }
+
+  static void eval(mpq_ptr q, mpq_srcptr r, mpq_srcptr s)
+  { mpq_mul(q, r, s); }
+
+  static void eval(mpq_ptr q, mpq_srcptr r, unsigned long int l)
+  {
+#if __GMP_GNUC_PREREQ(3, 4)
+    if (__GMPXX_CONSTANT(l) && (l & (l-1)) == 0)
+    {
+      if (l == 0)
+      {
+	mpq_set_ui(q, 0, 1);
+      }
+      else
+      {
+        __gmp_binary_lshift::eval(q, r, __builtin_ctzl(l));
+      }
+    }
+    else
+#endif
+    {
+      __GMPXX_TMPQ_UI;
+      mpq_mul (q, r, temp);
+    }
+  }
+  static void eval(mpq_ptr q, unsigned long int l, mpq_srcptr r)
+  { eval(q, r, l); }
+  static void eval(mpq_ptr q, mpq_srcptr r, signed long int l)
+  {
+    if (__GMPXX_CONSTANT_TRUE(l >= 0))
+      eval(q, r, static_cast<unsigned long>(l));
+    else if (__GMPXX_CONSTANT_TRUE(l <= 0))
+      {
+        eval(q, r, -static_cast<unsigned long>(l));
+	mpq_neg(q, q);
+      }
+    else
+      {
+	__GMPXX_TMPQ_SI;
+	mpq_mul (q, r, temp);
+      }
+  }
+  static void eval(mpq_ptr q, signed long int l, mpq_srcptr r)
+  { eval(q, r, l); }
+  static void eval(mpq_ptr q, mpq_srcptr r, double d)
+  {  __GMPXX_TMPQ_D;    mpq_mul (q, r, temp); }
+  static void eval(mpq_ptr q, double d, mpq_srcptr r)
+  { eval(q, r, d); }
+
+  static void eval(mpf_ptr f, mpf_srcptr g, mpf_srcptr h)
+  { mpf_mul(f, g, h); }
+
+  static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l)
+  { mpf_mul_ui(f, g, l); }
+  static void eval(mpf_ptr f, unsigned long int l, mpf_srcptr g)
+  { mpf_mul_ui(f, g, l); }
+  static void eval(mpf_ptr f, mpf_srcptr g, signed long int l)
+  {
+    if (l >= 0)
+      mpf_mul_ui(f, g, l);
+    else
+      {
+	mpf_mul_ui(f, g, -static_cast<unsigned long>(l));
+	mpf_neg(f, f);
+      }
+  }
+  static void eval(mpf_ptr f, signed long int l, mpf_srcptr g)
+  { eval(f, g, l); }
+  static void eval(mpf_ptr f, mpf_srcptr g, double d)
+  {
+    mpf_t temp;
+    mpf_init2(temp, 8*sizeof(double));
+    mpf_set_d(temp, d);
+    mpf_mul(f, g, temp);
+    mpf_clear(temp);
+  }
+  static void eval(mpf_ptr f, double d, mpf_srcptr g)
+  { eval(f, g, d); }
+};
+
+struct __gmp_binary_divides
+{
+  static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v)
+  { mpz_tdiv_q(z, w, v); }
+
+  static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l)
+  {
+#if __GMP_GNUC_PREREQ(3, 4)
+    // Don't optimize division by 0...
+    if (__GMPXX_CONSTANT(l) && (l & (l-1)) == 0 && l != 0)
+    {
+      if (l == 1)
+      {
+        if (z != w) mpz_set(z, w);
+      }
+      else
+        mpz_tdiv_q_2exp(z, w, __builtin_ctzl(l));
+        // warning: do not use rshift (fdiv)
+    }
+    else
+#endif
+      mpz_tdiv_q_ui(z, w, l);
+  }
+  static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w)
+  {
+    if (mpz_sgn(w) >= 0)
+      {
+	if (mpz_fits_ulong_p(w))
+	  mpz_set_ui(z, l / mpz_get_ui(w));
+	else
+	  mpz_set_ui(z, 0);
+      }
+    else
+      {
+	mpz_neg(z, w);
+	if (mpz_fits_ulong_p(z))
+	  {
+	    mpz_set_ui(z, l / mpz_get_ui(z));
+	    mpz_neg(z, z);
+	  }
+	else
+	  mpz_set_ui(z, 0);
+      }
+  }
+  static void eval(mpz_ptr z, mpz_srcptr w, signed long int l)
+  {
+    if (l >= 0)
+      eval(z, w, static_cast<unsigned long>(l));
+    else
+      {
+	eval(z, w, -static_cast<unsigned long>(l));
+	mpz_neg(z, z);
+      }
+  }
+  static void eval(mpz_ptr z, signed long int l, mpz_srcptr w)
+  {
+    if (mpz_fits_slong_p(w))
+      mpz_set_si(z, l / mpz_get_si(w));
+    else
+      {
+        /* if w is bigger than a long then the quotient must be zero, unless
+           l==LONG_MIN and w==-LONG_MIN in which case the quotient is -1 */
+        mpz_set_si (z, (mpz_cmpabs_ui (w, __gmpxx_abs_ui(l)) == 0 ? -1 : 0));
+      }
+  }
+  static void eval(mpz_ptr z, mpz_srcptr w, double d)
+  {  __GMPXX_TMPZ_D;    mpz_tdiv_q (z, w, temp); }
+  static void eval(mpz_ptr z, double d, mpz_srcptr w)
+  {  __GMPXX_TMPZ_D;    mpz_tdiv_q (z, temp, w); }
+
+  static void eval(mpq_ptr q, mpq_srcptr r, mpq_srcptr s)
+  { mpq_div(q, r, s); }
+
+  static void eval(mpq_ptr q, mpq_srcptr r, unsigned long int l)
+  {
+#if __GMP_GNUC_PREREQ(3, 4)
+    if (__GMPXX_CONSTANT(l) && (l & (l-1)) == 0 && l != 0)
+      __gmp_binary_rshift::eval(q, r, __builtin_ctzl(l));
+    else
+#endif
+    {
+      __GMPXX_TMPQ_UI;
+      mpq_div (q, r, temp);
+    }
+  }
+  static void eval(mpq_ptr q, unsigned long int l, mpq_srcptr r)
+  {
+    if (__GMPXX_CONSTANT_TRUE(l == 0))
+      mpq_set_ui(q, 0, 1);
+    else if (__GMPXX_CONSTANT_TRUE(l == 1))
+      mpq_inv(q, r);
+    else
+      {
+	__GMPXX_TMPQ_UI;
+	mpq_div (q, temp, r);
+      }
+  }
+  static void eval(mpq_ptr q, mpq_srcptr r, signed long int l)
+  {
+    if (__GMPXX_CONSTANT_TRUE(l >= 0))
+      eval(q, r, static_cast<unsigned long>(l));
+    else if (__GMPXX_CONSTANT_TRUE(l <= 0))
+      {
+        eval(q, r, -static_cast<unsigned long>(l));
+	mpq_neg(q, q);
+      }
+    else
+      {
+	__GMPXX_TMPQ_SI;
+	mpq_div (q, r, temp);
+      }
+  }
+  static void eval(mpq_ptr q, signed long int l, mpq_srcptr r)
+  {
+    if (__GMPXX_CONSTANT_TRUE(l == 0))
+      mpq_set_ui(q, 0, 1);
+    else if (__GMPXX_CONSTANT_TRUE(l == 1))
+      mpq_inv(q, r);
+    else if (__GMPXX_CONSTANT_TRUE(l == -1))
+      {
+	mpq_inv(q, r);
+	mpq_neg(q, q);
+      }
+    else
+      {
+	__GMPXX_TMPQ_SI;
+	mpq_div (q, temp, r);
+      }
+  }
+  static void eval(mpq_ptr q, mpq_srcptr r, double d)
+  {  __GMPXX_TMPQ_D;    mpq_div (q, r, temp); }
+  static void eval(mpq_ptr q, double d, mpq_srcptr r)
+  {  __GMPXX_TMPQ_D;    mpq_div (q, temp, r); }
+
+  static void eval(mpf_ptr f, mpf_srcptr g, mpf_srcptr h)
+  { mpf_div(f, g, h); }
+
+  static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l)
+  { mpf_div_ui(f, g, l); }
+  static void eval(mpf_ptr f, unsigned long int l, mpf_srcptr g)
+  { mpf_ui_div(f, l, g); }
+  static void eval(mpf_ptr f, mpf_srcptr g, signed long int l)
+  {
+    if (l >= 0)
+      mpf_div_ui(f, g, l);
+    else
+      {
+	mpf_div_ui(f, g, -static_cast<unsigned long>(l));
+	mpf_neg(f, f);
+      }
+  }
+  static void eval(mpf_ptr f, signed long int l, mpf_srcptr g)
+  {
+    if (l >= 0)
+      mpf_ui_div(f, l, g);
+    else
+      {
+	mpf_ui_div(f, -static_cast<unsigned long>(l), g);
+	mpf_neg(f, f);
+      }
+  }
+  static void eval(mpf_ptr f, mpf_srcptr g, double d)
+  {
+    mpf_t temp;
+    mpf_init2(temp, 8*sizeof(double));
+    mpf_set_d(temp, d);
+    mpf_div(f, g, temp);
+    mpf_clear(temp);
+  }
+  static void eval(mpf_ptr f, double d, mpf_srcptr g)
+  {
+    mpf_t temp;
+    mpf_init2(temp, 8*sizeof(double));
+    mpf_set_d(temp, d);
+    mpf_div(f, temp, g);
+    mpf_clear(temp);
+  }
+};
+
+struct __gmp_binary_modulus
+{
+  static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v)
+  { mpz_tdiv_r(z, w, v); }
+
+  static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l)
+  { mpz_tdiv_r_ui(z, w, l); }
+  static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w)
+  {
+    if (mpz_sgn(w) >= 0)
+      {
+	if (mpz_fits_ulong_p(w))
+	  mpz_set_ui(z, l % mpz_get_ui(w));
+	else
+	  mpz_set_ui(z, l);
+      }
+    else
+      {
+	mpz_neg(z, w);
+	if (mpz_fits_ulong_p(z))
+	  mpz_set_ui(z, l % mpz_get_ui(z));
+	else
+	  mpz_set_ui(z, l);
+      }
+  }
+  static void eval(mpz_ptr z, mpz_srcptr w, signed long int l)
+  {
+    mpz_tdiv_r_ui (z, w, __gmpxx_abs_ui(l));
+  }
+  static void eval(mpz_ptr z, signed long int l, mpz_srcptr w)
+  {
+    if (mpz_fits_slong_p(w))
+      mpz_set_si(z, l % mpz_get_si(w));
+    else
+      {
+        /* if w is bigger than a long then the remainder is l unchanged,
+           unless l==LONG_MIN and w==-LONG_MIN in which case it's 0 */
+        mpz_set_si (z, mpz_cmpabs_ui (w, __gmpxx_abs_ui(l)) == 0 ? 0 : l);
+      }
+  }
+  static void eval(mpz_ptr z, mpz_srcptr w, double d)
+  {  __GMPXX_TMPZ_D;    mpz_tdiv_r (z, w, temp); }
+  static void eval(mpz_ptr z, double d, mpz_srcptr w)
+  {  __GMPXX_TMPZ_D;    mpz_tdiv_r (z, temp, w); }
+};
+
+struct __gmp_binary_and
+{
+  static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v)
+  { mpz_and(z, w, v); }
+
+  static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l)
+  {  __GMPXX_TMPZ_UI;   mpz_and (z, w, temp);  }
+  static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w)
+  { eval(z, w, l);  }
+  static void eval(mpz_ptr z, mpz_srcptr w, signed long int l)
+  {  __GMPXX_TMPZ_SI;   mpz_and (z, w, temp);  }
+  static void eval(mpz_ptr z, signed long int l, mpz_srcptr w)
+  { eval(z, w, l);  }
+  static void eval(mpz_ptr z, mpz_srcptr w, double d)
+  {  __GMPXX_TMPZ_D;    mpz_and (z, w, temp); }
+  static void eval(mpz_ptr z, double d, mpz_srcptr w)
+  { eval(z, w, d);  }
+};
+
+struct __gmp_binary_ior
+{
+  static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v)
+  { mpz_ior(z, w, v); }
+  static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l)
+  {  __GMPXX_TMPZ_UI;   mpz_ior (z, w, temp);  }
+  static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w)
+  { eval(z, w, l);  }
+  static void eval(mpz_ptr z, mpz_srcptr w, signed long int l)
+  {  __GMPXX_TMPZ_SI;   mpz_ior (z, w, temp);  }
+  static void eval(mpz_ptr z, signed long int l, mpz_srcptr w)
+  { eval(z, w, l);  }
+  static void eval(mpz_ptr z, mpz_srcptr w, double d)
+  {  __GMPXX_TMPZ_D;    mpz_ior (z, w, temp); }
+  static void eval(mpz_ptr z, double d, mpz_srcptr w)
+  { eval(z, w, d);  }
+};
+
+struct __gmp_binary_xor
+{
+  static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v)
+  { mpz_xor(z, w, v); }
+  static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l)
+  {  __GMPXX_TMPZ_UI;   mpz_xor (z, w, temp);  }
+  static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w)
+  { eval(z, w, l);  }
+  static void eval(mpz_ptr z, mpz_srcptr w, signed long int l)
+  {  __GMPXX_TMPZ_SI;   mpz_xor (z, w, temp);  }
+  static void eval(mpz_ptr z, signed long int l, mpz_srcptr w)
+  { eval(z, w, l);  }
+  static void eval(mpz_ptr z, mpz_srcptr w, double d)
+  {  __GMPXX_TMPZ_D;    mpz_xor (z, w, temp); }
+  static void eval(mpz_ptr z, double d, mpz_srcptr w)
+  { eval(z, w, d);  }
+};
+
+struct __gmp_cmp_function
+{
+  static int eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w); }
+
+  static int eval(mpz_srcptr z, unsigned long int l)
+  { return mpz_cmp_ui(z, l); }
+  static int eval(unsigned long int l, mpz_srcptr z)
+  { return -mpz_cmp_ui(z, l); }
+  static int eval(mpz_srcptr z, signed long int l)
+  { return mpz_cmp_si(z, l); }
+  static int eval(signed long int l, mpz_srcptr z)
+  { return -mpz_cmp_si(z, l); }
+  static int eval(mpz_srcptr z, double d)
+  { return mpz_cmp_d(z, d); }
+  static int eval(double d, mpz_srcptr z)
+  { return -mpz_cmp_d(z, d); }
+
+  static int eval(mpq_srcptr q, mpq_srcptr r) { return mpq_cmp(q, r); }
+
+  static int eval(mpq_srcptr q, unsigned long int l)
+  { return mpq_cmp_ui(q, l, 1); }
+  static int eval(unsigned long int l, mpq_srcptr q)
+  { return -mpq_cmp_ui(q, l, 1); }
+  static int eval(mpq_srcptr q, signed long int l)
+  { return mpq_cmp_si(q, l, 1); }
+  static int eval(signed long int l, mpq_srcptr q)
+  { return -mpq_cmp_si(q, l, 1); }
+  static int eval(mpq_srcptr q, double d)
+  {  __GMPXX_TMPQ_D;    return mpq_cmp (q, temp); }
+  static int eval(double d, mpq_srcptr q)
+  {  __GMPXX_TMPQ_D;    return mpq_cmp (temp, q); }
+  static int eval(mpq_srcptr q, mpz_srcptr z)
+  { return mpq_cmp_z(q, z); }
+  static int eval(mpz_srcptr z, mpq_srcptr q)
+  { return -mpq_cmp_z(q, z); }
+
+  static int eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g); }
+
+  static int eval(mpf_srcptr f, unsigned long int l)
+  { return mpf_cmp_ui(f, l); }
+  static int eval(unsigned long int l, mpf_srcptr f)
+  { return -mpf_cmp_ui(f, l); }
+  static int eval(mpf_srcptr f, signed long int l)
+  { return mpf_cmp_si(f, l); }
+  static int eval(signed long int l, mpf_srcptr f)
+  { return -mpf_cmp_si(f, l); }
+  static int eval(mpf_srcptr f, double d)
+  { return mpf_cmp_d(f, d); }
+  static int eval(double d, mpf_srcptr f)
+  { return -mpf_cmp_d(f, d); }
+  static int eval(mpf_srcptr f, mpz_srcptr z)
+  { return mpf_cmp_z(f, z); }
+  static int eval(mpz_srcptr z, mpf_srcptr f)
+  { return -mpf_cmp_z(f, z); }
+  static int eval(mpf_srcptr f, mpq_srcptr q)
+  {
+    mpf_t qf;
+    mpf_init(qf); /* Should we use the precision of f?  */
+    mpf_set_q(qf, q);
+    int ret = eval(f, qf);
+    mpf_clear(qf);
+    return ret;
+  }
+  static int eval(mpq_srcptr q, mpf_srcptr f)
+  { return -eval(f, q); }
+};
+
+struct __gmp_binary_equal
+{
+  static bool eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w) == 0; }
+
+  static bool eval(mpz_srcptr z, unsigned long int l)
+  { return mpz_cmp_ui(z, l) == 0; }
+  static bool eval(unsigned long int l, mpz_srcptr z)
+  { return eval(z, l); }
+  static bool eval(mpz_srcptr z, signed long int l)
+  { return mpz_cmp_si(z, l) == 0; }
+  static bool eval(signed long int l, mpz_srcptr z)
+  { return eval(z, l); }
+  static bool eval(mpz_srcptr z, double d)
+  { return mpz_cmp_d(z, d) == 0; }
+  static bool eval(double d, mpz_srcptr z)
+  { return eval(z, d); }
+
+  static bool eval(mpq_srcptr q, mpq_srcptr r)
+  { return mpq_equal(q, r) != 0; }
+
+  static bool eval(mpq_srcptr q, unsigned long int l)
+  { return ((__GMPXX_CONSTANT(l) && l == 0) ||
+	    mpz_cmp_ui(mpq_denref(q), 1) == 0) &&
+      mpz_cmp_ui(mpq_numref(q), l) == 0; }
+  static bool eval(unsigned long int l, mpq_srcptr q)
+  { return eval(q, l); }
+  static bool eval(mpq_srcptr q, signed long int l)
+  { return ((__GMPXX_CONSTANT(l) && l == 0) ||
+	    mpz_cmp_ui(mpq_denref(q), 1) == 0) &&
+      mpz_cmp_si(mpq_numref(q), l) == 0; }
+  static bool eval(signed long int l, mpq_srcptr q)
+  { return eval(q, l); }
+  static bool eval(mpq_srcptr q, double d)
+  {  __GMPXX_TMPQ_D;    return mpq_equal (q, temp) != 0; }
+  static bool eval(double d, mpq_srcptr q)
+  { return eval(q, d); }
+  static bool eval(mpq_srcptr q, mpz_srcptr z)
+  { return mpz_cmp_ui(mpq_denref(q), 1) == 0 && mpz_cmp(mpq_numref(q), z) == 0; }
+  static bool eval(mpz_srcptr z, mpq_srcptr q)
+  { return eval(q, z); }
+
+  static bool eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g) == 0; }
+
+  static bool eval(mpf_srcptr f, unsigned long int l)
+  { return mpf_cmp_ui(f, l) == 0; }
+  static bool eval(unsigned long int l, mpf_srcptr f)
+  { return eval(f, l); }
+  static bool eval(mpf_srcptr f, signed long int l)
+  { return mpf_cmp_si(f, l) == 0; }
+  static bool eval(signed long int l, mpf_srcptr f)
+  { return eval(f, l); }
+  static bool eval(mpf_srcptr f, double d)
+  { return mpf_cmp_d(f, d) == 0; }
+  static bool eval(double d, mpf_srcptr f)
+  { return eval(f, d); }
+  static bool eval(mpf_srcptr f, mpz_srcptr z)
+  { return mpf_cmp_z(f, z) == 0; }
+  static bool eval(mpz_srcptr z, mpf_srcptr f)
+  { return eval(f, z); }
+  static bool eval(mpf_srcptr f, mpq_srcptr q)
+  { return __gmp_cmp_function::eval(f, q) == 0; }
+  static bool eval(mpq_srcptr q, mpf_srcptr f)
+  { return eval(f, q); }
+};
+
+struct __gmp_binary_less
+{
+  static bool eval(mpz_srcptr z, mpz_srcptr w) { return mpz_cmp(z, w) < 0; }
+
+  static bool eval(mpz_srcptr z, unsigned long int l)
+  { return mpz_cmp_ui(z, l) < 0; }
+  static bool eval(unsigned long int l, mpz_srcptr z)
+  { return mpz_cmp_ui(z, l) > 0; }
+  static bool eval(mpz_srcptr z, signed long int l)
+  { return mpz_cmp_si(z, l) < 0; }
+  static bool eval(signed long int l, mpz_srcptr z)
+  { return mpz_cmp_si(z, l) > 0; }
+  static bool eval(mpz_srcptr z, double d)
+  { return mpz_cmp_d(z, d) < 0; }
+  static bool eval(double d, mpz_srcptr z)
+  { return mpz_cmp_d(z, d) > 0; }
+
+  static bool eval(mpq_srcptr q, mpq_srcptr r) { return mpq_cmp(q, r) < 0; }
+
+  static bool eval(mpq_srcptr q, unsigned long int l)
+  { return mpq_cmp_ui(q, l, 1) < 0; }
+  static bool eval(unsigned long int l, mpq_srcptr q)
+  { return mpq_cmp_ui(q, l, 1) > 0; }
+  static bool eval(mpq_srcptr q, signed long int l)
+  { return mpq_cmp_si(q, l, 1) < 0; }
+  static bool eval(signed long int l, mpq_srcptr q)
+  { return mpq_cmp_si(q, l, 1) > 0; }
+  static bool eval(mpq_srcptr q, double d)
+  {  __GMPXX_TMPQ_D;    return mpq_cmp (q, temp) < 0; }
+  static bool eval(double d, mpq_srcptr q)
+  {  __GMPXX_TMPQ_D;    return mpq_cmp (temp, q) < 0; }
+  static bool eval(mpq_srcptr q, mpz_srcptr z)
+  { return mpq_cmp_z(q, z) < 0; }
+  static bool eval(mpz_srcptr z, mpq_srcptr q)
+  { return mpq_cmp_z(q, z) > 0; }
+
+  static bool eval(mpf_srcptr f, mpf_srcptr g) { return mpf_cmp(f, g) < 0; }
+
+  static bool eval(mpf_srcptr f, unsigned long int l)
+  { return mpf_cmp_ui(f, l) < 0; }
+  static bool eval(unsigned long int l, mpf_srcptr f)
+  { return mpf_cmp_ui(f, l) > 0; }
+  static bool eval(mpf_srcptr f, signed long int l)
+  { return mpf_cmp_si(f, l) < 0; }
+  static bool eval(signed long int l, mpf_srcptr f)
+  { return mpf_cmp_si(f, l) > 0; }
+  static bool eval(mpf_srcptr f, double d)
+  { return mpf_cmp_d(f, d) < 0; }
+  static bool eval(double d, mpf_srcptr f)
+  { return mpf_cmp_d(f, d) > 0; }
+  static bool eval(mpf_srcptr f, mpz_srcptr z)
+  { return mpf_cmp_z(f, z) < 0; }
+  static bool eval(mpz_srcptr z, mpf_srcptr f)
+  { return mpf_cmp_z(f, z) > 0; }
+  static bool eval(mpf_srcptr f, mpq_srcptr q)
+  { return __gmp_cmp_function::eval(f, q) < 0; }
+  static bool eval(mpq_srcptr q, mpf_srcptr f)
+  { return __gmp_cmp_function::eval(q, f) < 0; }
+};
+
+struct __gmp_binary_greater
+{
+  template <class T, class U>
+  static inline bool eval(T t, U u) { return __gmp_binary_less::eval(u, t); }
+};
+
+struct __gmp_unary_increment
+{
+  static void eval(mpz_ptr z) { mpz_add_ui(z, z, 1); }
+  static void eval(mpq_ptr q)
+  { mpz_add(mpq_numref(q), mpq_numref(q), mpq_denref(q)); }
+  static void eval(mpf_ptr f) { mpf_add_ui(f, f, 1); }
+};
+
+struct __gmp_unary_decrement
+{
+  static void eval(mpz_ptr z) { mpz_sub_ui(z, z, 1); }
+  static void eval(mpq_ptr q)
+  { mpz_sub(mpq_numref(q), mpq_numref(q), mpq_denref(q)); }
+  static void eval(mpf_ptr f) { mpf_sub_ui(f, f, 1); }
+};
+
+struct __gmp_abs_function
+{
+  static void eval(mpz_ptr z, mpz_srcptr w) { mpz_abs(z, w); }
+  static void eval(mpq_ptr q, mpq_srcptr r) { mpq_abs(q, r); }
+  static void eval(mpf_ptr f, mpf_srcptr g) { mpf_abs(f, g); }
+};
+
+struct __gmp_trunc_function
+{
+  static void eval(mpf_ptr f, mpf_srcptr g) { mpf_trunc(f, g); }
+};
+
+struct __gmp_floor_function
+{
+  static void eval(mpf_ptr f, mpf_srcptr g) { mpf_floor(f, g); }
+};
+
+struct __gmp_ceil_function
+{
+  static void eval(mpf_ptr f, mpf_srcptr g) { mpf_ceil(f, g); }
+};
+
+struct __gmp_sqrt_function
+{
+  static void eval(mpz_ptr z, mpz_srcptr w) { mpz_sqrt(z, w); }
+  static void eval(mpf_ptr f, mpf_srcptr g) { mpf_sqrt(f, g); }
+};
+
+struct __gmp_hypot_function
+{
+  static void eval(mpf_ptr f, mpf_srcptr g, mpf_srcptr h)
+  {
+    mpf_t temp;
+    mpf_init2(temp, mpf_get_prec(f));
+    mpf_mul(temp, g, g);
+    mpf_mul(f, h, h);
+    mpf_add(f, f, temp);
+    mpf_sqrt(f, f);
+    mpf_clear(temp);
+  }
+
+  static void eval(mpf_ptr f, mpf_srcptr g, unsigned long int l)
+  {
+    mpf_t temp;
+    mpf_init2(temp, mpf_get_prec(f));
+    mpf_mul(temp, g, g);
+    mpf_set_ui(f, l);
+    mpf_mul_ui(f, f, l);
+    mpf_add(f, f, temp);
+    mpf_clear(temp);
+    mpf_sqrt(f, f);
+  }
+  static void eval(mpf_ptr f, unsigned long int l, mpf_srcptr g)
+  { eval(f, g, l); }
+  static void eval(mpf_ptr f, mpf_srcptr g, signed long int l)
+  { eval(f, g, __gmpxx_abs_ui(l)); }
+  static void eval(mpf_ptr f, signed long int l, mpf_srcptr g)
+  { eval(f, g, l); }
+  static void eval(mpf_ptr f, mpf_srcptr g, double d)
+  {
+    mpf_t temp;
+    mpf_init2(temp, mpf_get_prec(f));
+    mpf_mul(temp, g, g);
+    mpf_set_d(f, d);
+    mpf_mul(f, f, f);
+    mpf_add(f, f, temp);
+    mpf_sqrt(f, f);
+    mpf_clear(temp);
+  }
+  static void eval(mpf_ptr f, double d, mpf_srcptr g)
+  { eval(f, g, d); }
+};
+
+struct __gmp_sgn_function
+{
+  static int eval(mpz_srcptr z) { return mpz_sgn(z); }
+  static int eval(mpq_srcptr q) { return mpq_sgn(q); }
+  static int eval(mpf_srcptr f) { return mpf_sgn(f); }
+};
+
+struct __gmp_gcd_function
+{
+  static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v)
+  { mpz_gcd(z, w, v); }
+  static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l)
+  { mpz_gcd_ui(z, w, l); }
+  static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w)
+  { eval(z, w, l); }
+  static void eval(mpz_ptr z, mpz_srcptr w, signed long int l)
+  { eval(z, w, __gmpxx_abs_ui(l)); }
+  static void eval(mpz_ptr z, signed long int l, mpz_srcptr w)
+  { eval(z, w, l); }
+  static void eval(mpz_ptr z, mpz_srcptr w, double d)
+  {  __GMPXX_TMPZ_D;    mpz_gcd (z, w, temp); }
+  static void eval(mpz_ptr z, double d, mpz_srcptr w)
+  { eval(z, w, d); }
+};
+
+struct __gmp_lcm_function
+{
+  static void eval(mpz_ptr z, mpz_srcptr w, mpz_srcptr v)
+  { mpz_lcm(z, w, v); }
+  static void eval(mpz_ptr z, mpz_srcptr w, unsigned long int l)
+  { mpz_lcm_ui(z, w, l); }
+  static void eval(mpz_ptr z, unsigned long int l, mpz_srcptr w)
+  { eval(z, w, l); }
+  static void eval(mpz_ptr z, mpz_srcptr w, signed long int l)
+  { eval(z, w, __gmpxx_abs_ui(l)); }
+  static void eval(mpz_ptr z, signed long int l, mpz_srcptr w)
+  { eval(z, w, l); }
+  static void eval(mpz_ptr z, mpz_srcptr w, double d)
+  {  __GMPXX_TMPZ_D;    mpz_lcm (z, w, temp); }
+  static void eval(mpz_ptr z, double d, mpz_srcptr w)
+  { eval(z, w, d); }
+};
+
+struct __gmp_rand_function
+{
+  static void eval(mpz_ptr z, gmp_randstate_t s, mp_bitcnt_t l)
+  { mpz_urandomb(z, s, l); }
+  static void eval(mpz_ptr z, gmp_randstate_t s, mpz_srcptr w)
+  { mpz_urandomm(z, s, w); }
+  static void eval(mpf_ptr f, gmp_randstate_t s, mp_bitcnt_t prec)
+  { mpf_urandomb(f, s, prec); }
+};
+
+struct __gmp_fac_function
+{
+  static void eval(mpz_ptr z, unsigned long l) { mpz_fac_ui(z, l); }
+  static void eval(mpz_ptr z, signed long l)
+  {
+    if (l < 0)
+      throw std::domain_error ("factorial(negative)");
+    eval(z, static_cast<unsigned long>(l));
+  }
+  static void eval(mpz_ptr z, mpz_srcptr w)
+  {
+    if (!mpz_fits_ulong_p(w))
+      {
+	if (mpz_sgn(w) < 0)
+	  throw std::domain_error ("factorial(negative)");
+	else
+	  throw std::bad_alloc(); // or std::overflow_error ("factorial")?
+      }
+    eval(z, mpz_get_ui(w));
+  }
+  static void eval(mpz_ptr z, double d)
+  {  __GMPXX_TMPZ_D;    eval (z, temp); }
+};
+
+struct __gmp_primorial_function
+{
+  static void eval(mpz_ptr z, unsigned long l) { mpz_primorial_ui(z, l); }
+  static void eval(mpz_ptr z, signed long l)
+  {
+    if (l < 0)
+      throw std::domain_error ("primorial(negative)");
+    eval(z, static_cast<unsigned long>(l));
+  }
+  static void eval(mpz_ptr z, mpz_srcptr w)
+  {
+    if (!mpz_fits_ulong_p(w))
+      {
+	if (mpz_sgn(w) < 0)
+	  throw std::domain_error ("primorial(negative)");
+	else
+	  throw std::bad_alloc(); // or std::overflow_error ("primorial")?
+      }
+    eval(z, mpz_get_ui(w));
+  }
+  static void eval(mpz_ptr z, double d)
+  {  __GMPXX_TMPZ_D;    eval (z, temp); }
+};
+
+struct __gmp_fib_function
+{
+  static void eval(mpz_ptr z, unsigned long l) { mpz_fib_ui(z, l); }
+  static void eval(mpz_ptr z, signed long l)
+  {
+    if (l < 0)
+      {
+	eval(z, -static_cast<unsigned long>(l));
+	if ((l & 1) == 0)
+	  mpz_neg(z, z);
+      }
+    else
+      eval(z, static_cast<unsigned long>(l));
+  }
+  static void eval(mpz_ptr z, mpz_srcptr w)
+  {
+    if (!mpz_fits_slong_p(w))
+      throw std::bad_alloc(); // or std::overflow_error ("fibonacci")?
+    eval(z, mpz_get_si(w));
+  }
+  static void eval(mpz_ptr z, double d)
+  {  __GMPXX_TMPZ_D;    eval (z, temp); }
+};
+
+
+/**************** Auxiliary classes ****************/
+
+/* this is much the same as gmp_allocated_string in gmp-impl.h
+   since gmp-impl.h is not publicly available, I redefine it here
+   I use a different name to avoid possible clashes */
+
+extern "C" {
+  typedef void (*__gmp_freefunc_t) (void *, size_t);
+}
+struct __gmp_alloc_cstring
+{
+  char *str;
+  __gmp_alloc_cstring(char *s) { str = s; }
+  ~__gmp_alloc_cstring()
+  {
+    __gmp_freefunc_t freefunc;
+    mp_get_memory_functions (NULL, NULL, &freefunc);
+    (*freefunc) (str, std::strlen(str)+1);
+  }
+};
+
+
+// general expression template class
+template <class T, class U>
+class __gmp_expr;
+
+
+// templates for resolving expression types
+template <class T>
+struct __gmp_resolve_ref
+{
+  typedef T ref_type;
+};
+
+template <class T, class U>
+struct __gmp_resolve_ref<__gmp_expr<T, U> >
+{
+  typedef const __gmp_expr<T, U> & ref_type;
+};
+
+
+template <class T, class U = T>
+struct __gmp_resolve_expr;
+
+template <>
+struct __gmp_resolve_expr<mpz_t>
+{
+  typedef mpz_t value_type;
+  typedef mpz_ptr ptr_type;
+  typedef mpz_srcptr srcptr_type;
+};
+
+template <>
+struct __gmp_resolve_expr<mpq_t>
+{
+  typedef mpq_t value_type;
+  typedef mpq_ptr ptr_type;
+  typedef mpq_srcptr srcptr_type;
+};
+
+template <>
+struct __gmp_resolve_expr<mpf_t>
+{
+  typedef mpf_t value_type;
+  typedef mpf_ptr ptr_type;
+  typedef mpf_srcptr srcptr_type;
+};
+
+template <>
+struct __gmp_resolve_expr<mpz_t, mpq_t>
+{
+  typedef mpq_t value_type;
+};
+
+template <>
+struct __gmp_resolve_expr<mpq_t, mpz_t>
+{
+  typedef mpq_t value_type;
+};
+
+template <>
+struct __gmp_resolve_expr<mpz_t, mpf_t>
+{
+  typedef mpf_t value_type;
+};
+
+template <>
+struct __gmp_resolve_expr<mpf_t, mpz_t>
+{
+  typedef mpf_t value_type;
+};
+
+template <>
+struct __gmp_resolve_expr<mpq_t, mpf_t>
+{
+  typedef mpf_t value_type;
+};
+
+template <>
+struct __gmp_resolve_expr<mpf_t, mpq_t>
+{
+  typedef mpf_t value_type;
+};
+
+#if __GMPXX_USE_CXX11
+namespace std {
+  template <class T, class U, class V, class W>
+  struct common_type <__gmp_expr<T, U>, __gmp_expr<V, W> >
+  {
+  private:
+    typedef typename __gmp_resolve_expr<T, V>::value_type X;
+  public:
+    typedef __gmp_expr<X, X> type;
+  };
+
+  template <class T, class U>
+  struct common_type <__gmp_expr<T, U> >
+  {
+    typedef __gmp_expr<T, T> type;
+  };
+
+#define __GMPXX_DECLARE_COMMON_TYPE(typ)	\
+  template <class T, class U>			\
+  struct common_type <__gmp_expr<T, U>, typ >	\
+  {						\
+    typedef __gmp_expr<T, T> type;		\
+  };						\
+						\
+  template <class T, class U>			\
+  struct common_type <typ, __gmp_expr<T, U> >	\
+  {						\
+    typedef __gmp_expr<T, T> type;		\
+  }
+
+  __GMPXX_DECLARE_COMMON_TYPE(signed char);
+  __GMPXX_DECLARE_COMMON_TYPE(unsigned char);
+  __GMPXX_DECLARE_COMMON_TYPE(signed int);
+  __GMPXX_DECLARE_COMMON_TYPE(unsigned int);
+  __GMPXX_DECLARE_COMMON_TYPE(signed short int);
+  __GMPXX_DECLARE_COMMON_TYPE(unsigned short int);
+  __GMPXX_DECLARE_COMMON_TYPE(signed long int);
+  __GMPXX_DECLARE_COMMON_TYPE(unsigned long int);
+  __GMPXX_DECLARE_COMMON_TYPE(float);
+  __GMPXX_DECLARE_COMMON_TYPE(double);
+#undef __GMPXX_DECLARE_COMMON_TYPE
+}
+#endif
+
+// classes for evaluating unary and binary expressions
+template <class T, class Op>
+struct __gmp_unary_expr
+{
+  typename __gmp_resolve_ref<T>::ref_type val;
+
+  __gmp_unary_expr(const T &v) : val(v) { }
+private:
+  __gmp_unary_expr();
+};
+
+template <class T, class U, class Op>
+struct __gmp_binary_expr
+{
+  typename __gmp_resolve_ref<T>::ref_type val1;
+  typename __gmp_resolve_ref<U>::ref_type val2;
+
+  __gmp_binary_expr(const T &v1, const U &v2) : val1(v1), val2(v2) { }
+private:
+  __gmp_binary_expr();
+};
+
+
+
+/**************** Macros for in-class declarations ****************/
+/* This is just repetitive code that is easier to maintain if it's written
+   only once */
+
+#define __GMPP_DECLARE_COMPOUND_OPERATOR(fun)                         \
+  template <class T, class U>                                         \
+  __gmp_expr<value_type, value_type> & fun(const __gmp_expr<T, U> &);
+
+#define __GMPN_DECLARE_COMPOUND_OPERATOR(fun) \
+  __gmp_expr & fun(signed char);              \
+  __gmp_expr & fun(unsigned char);            \
+  __gmp_expr & fun(signed int);               \
+  __gmp_expr & fun(unsigned int);             \
+  __gmp_expr & fun(signed short int);         \
+  __gmp_expr & fun(unsigned short int);       \
+  __gmp_expr & fun(signed long int);          \
+  __gmp_expr & fun(unsigned long int);        \
+  __gmp_expr & fun(float);                    \
+  __gmp_expr & fun(double);                   \
+  /* __gmp_expr & fun(long double); */
+
+#define __GMP_DECLARE_COMPOUND_OPERATOR(fun) \
+__GMPP_DECLARE_COMPOUND_OPERATOR(fun)        \
+__GMPN_DECLARE_COMPOUND_OPERATOR(fun)
+
+#define __GMP_DECLARE_COMPOUND_OPERATOR_UI(fun) \
+  __gmp_expr & fun(mp_bitcnt_t);
+
+#define __GMP_DECLARE_INCREMENT_OPERATOR(fun) \
+  inline __gmp_expr & fun();                  \
+  inline __gmp_expr fun(int);
+
+#define __GMPXX_DEFINE_ARITHMETIC_CONSTRUCTORS		\
+  __gmp_expr(signed char c) { init_si(c); }		\
+  __gmp_expr(unsigned char c) { init_ui(c); }		\
+  __gmp_expr(signed int i) { init_si(i); }		\
+  __gmp_expr(unsigned int i) { init_ui(i); }		\
+  __gmp_expr(signed short int s) { init_si(s); }	\
+  __gmp_expr(unsigned short int s) { init_ui(s); }	\
+  __gmp_expr(signed long int l) { init_si(l); }		\
+  __gmp_expr(unsigned long int l) { init_ui(l); }	\
+  __gmp_expr(float f) { init_d(f); }			\
+  __gmp_expr(double d) { init_d(d); }
+
+#define __GMPXX_DEFINE_ARITHMETIC_ASSIGNMENTS		\
+  __gmp_expr & operator=(signed char c) { assign_si(c); return *this; } \
+  __gmp_expr & operator=(unsigned char c) { assign_ui(c); return *this; } \
+  __gmp_expr & operator=(signed int i) { assign_si(i); return *this; } \
+  __gmp_expr & operator=(unsigned int i) { assign_ui(i); return *this; } \
+  __gmp_expr & operator=(signed short int s) { assign_si(s); return *this; } \
+  __gmp_expr & operator=(unsigned short int s) { assign_ui(s); return *this; } \
+  __gmp_expr & operator=(signed long int l) { assign_si(l); return *this; } \
+  __gmp_expr & operator=(unsigned long int l) { assign_ui(l); return *this; } \
+  __gmp_expr & operator=(float f) { assign_d(f); return *this; } \
+  __gmp_expr & operator=(double d) { assign_d(d); return *this; }
+
+#define __GMPP_DECLARE_UNARY_STATIC_MEMFUN(T, fun, eval_fun)                 \
+template <class U>                                                           \
+static __gmp_expr<T, __gmp_unary_expr<__gmp_expr<T, U>, eval_fun> >          \
+fun(const __gmp_expr<T, U> &expr);
+
+#define __GMPNN_DECLARE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, type, bigtype) \
+static inline __gmp_expr<T, __gmp_unary_expr<bigtype, eval_fun> >            \
+fun(type expr);
+
+#define __GMPNS_DECLARE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, type)  \
+__GMPNN_DECLARE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, type, signed long)
+#define __GMPNU_DECLARE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, type)  \
+__GMPNN_DECLARE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, type, unsigned long)
+#define __GMPND_DECLARE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, type)  \
+__GMPNN_DECLARE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, type, double)
+
+#define __GMPN_DECLARE_UNARY_STATIC_MEMFUN(T, fun, eval_fun)                 \
+__GMPNS_DECLARE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, signed char)           \
+__GMPNU_DECLARE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, unsigned char)         \
+__GMPNS_DECLARE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, signed int)            \
+__GMPNU_DECLARE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, unsigned int)          \
+__GMPNS_DECLARE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, signed short int)      \
+__GMPNU_DECLARE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, unsigned short int)    \
+__GMPNS_DECLARE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, signed long int)       \
+__GMPNU_DECLARE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, unsigned long int)     \
+__GMPND_DECLARE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, float)                 \
+__GMPND_DECLARE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, double)
+
+#define __GMP_DECLARE_UNARY_STATIC_MEMFUN(T, fun, eval_fun)                  \
+__GMPP_DECLARE_UNARY_STATIC_MEMFUN(T, fun, eval_fun)                         \
+__GMPN_DECLARE_UNARY_STATIC_MEMFUN(T, fun, eval_fun)
+
+/**************** mpz_class -- wrapper for mpz_t ****************/
+
+template <>
+class __gmp_expr<mpz_t, mpz_t>
+{
+private:
+  typedef mpz_t value_type;
+  value_type mp;
+
+  // Helper functions used for all arithmetic types
+  void assign_ui(unsigned long l)
+  {
+    if (__GMPXX_CONSTANT_TRUE(l == 0))
+      mp->_mp_size = 0;
+    else
+      mpz_set_ui(mp, l);
+  }
+  void assign_si(signed long l)
+  {
+    if (__GMPXX_CONSTANT_TRUE(l >= 0))
+      assign_ui(l);
+    else if (__GMPXX_CONSTANT_TRUE(l <= 0))
+      {
+	assign_ui(-static_cast<unsigned long>(l));
+	mpz_neg(mp, mp);
+      }
+    else
+      mpz_set_si(mp, l);
+  }
+  void assign_d (double d)
+  {
+    mpz_set_d (mp, d);
+  }
+
+  void init_ui(unsigned long l)
+  {
+    if (__GMPXX_CONSTANT_TRUE(l == 0))
+      mpz_init(mp);
+    else
+      mpz_init_set_ui(mp, l);
+  }
+  void init_si(signed long l)
+  {
+    if (__GMPXX_CONSTANT_TRUE(l >= 0))
+      init_ui(l);
+    else if (__GMPXX_CONSTANT_TRUE(l <= 0))
+      {
+	init_ui(-static_cast<unsigned long>(l));
+	mpz_neg(mp, mp);
+      }
+    else
+      mpz_init_set_si(mp, l);
+  }
+  void init_d (double d)
+  {
+    mpz_init_set_d (mp, d);
+  }
+
+public:
+  mp_bitcnt_t get_prec() const { return mpf_get_default_prec(); }
+
+  // constructors and destructor
+  __gmp_expr() __GMPXX_NOEXCEPT { mpz_init(mp); }
+
+  __gmp_expr(const __gmp_expr &z) { mpz_init_set(mp, z.mp); }
+#if __GMPXX_USE_CXX11
+  __gmp_expr(__gmp_expr &&z) noexcept
+  { *mp = *z.mp; mpz_init(z.mp); }
+#endif
+  template <class T>
+  __gmp_expr(const __gmp_expr<mpz_t, T> &expr)
+  { mpz_init(mp); __gmp_set_expr(mp, expr); }
+  template <class T, class U>
+  explicit __gmp_expr(const __gmp_expr<T, U> &expr)
+  { mpz_init(mp); __gmp_set_expr(mp, expr); }
+
+  __GMPXX_DEFINE_ARITHMETIC_CONSTRUCTORS
+
+  explicit __gmp_expr(const char *s, int base = 0)
+  {
+    if (mpz_init_set_str (mp, s, base) != 0)
+      {
+        mpz_clear (mp);
+        throw std::invalid_argument ("mpz_set_str");
+      }
+  }
+  explicit __gmp_expr(const std::string &s, int base = 0)
+  {
+    if (mpz_init_set_str(mp, s.c_str(), base) != 0)
+      {
+        mpz_clear (mp);
+        throw std::invalid_argument ("mpz_set_str");
+      }
+  }
+
+  explicit __gmp_expr(mpz_srcptr z) { mpz_init_set(mp, z); }
+
+  ~__gmp_expr() { mpz_clear(mp); }
+
+  void swap(__gmp_expr& z) __GMPXX_NOEXCEPT { std::swap(*mp, *z.mp); }
+
+  // assignment operators
+  __gmp_expr & operator=(const __gmp_expr &z)
+  { mpz_set(mp, z.mp); return *this; }
+#if __GMPXX_USE_CXX11
+  __gmp_expr & operator=(__gmp_expr &&z) noexcept
+  { swap(z); return *this; }
+#endif
+  template <class T, class U>
+  __gmp_expr<value_type, value_type> & operator=(const __gmp_expr<T, U> &expr)
+  { __gmp_set_expr(mp, expr); return *this; }
+
+  __GMPXX_DEFINE_ARITHMETIC_ASSIGNMENTS
+
+  __gmp_expr & operator=(const char *s)
+  {
+    if (mpz_set_str (mp, s, 0) != 0)
+      throw std::invalid_argument ("mpz_set_str");
+    return *this;
+  }
+  __gmp_expr & operator=(const std::string &s)
+  {
+    if (mpz_set_str(mp, s.c_str(), 0) != 0)
+      throw std::invalid_argument ("mpz_set_str");
+    return *this;
+  }
+
+  // string input/output functions
+  int set_str(const char *s, int base)
+  { return mpz_set_str(mp, s, base); }
+  int set_str(const std::string &s, int base)
+  { return mpz_set_str(mp, s.c_str(), base); }
+  std::string get_str(int base = 10) const
+  {
+    __gmp_alloc_cstring temp(mpz_get_str(0, base, mp));
+    return std::string(temp.str);
+  }
+
+  // conversion functions
+  mpz_srcptr __get_mp() const { return mp; }
+  mpz_ptr __get_mp() { return mp; }
+  mpz_srcptr get_mpz_t() const { return mp; }
+  mpz_ptr get_mpz_t() { return mp; }
+
+  signed long int get_si() const { return mpz_get_si(mp); }
+  unsigned long int get_ui() const { return mpz_get_ui(mp); }
+  double get_d() const { return mpz_get_d(mp); }
+
+  // bool fits_schar_p() const { return mpz_fits_schar_p(mp); }
+  // bool fits_uchar_p() const { return mpz_fits_uchar_p(mp); }
+  bool fits_sint_p() const { return mpz_fits_sint_p(mp); }
+  bool fits_uint_p() const { return mpz_fits_uint_p(mp); }
+  bool fits_sshort_p() const { return mpz_fits_sshort_p(mp); }
+  bool fits_ushort_p() const { return mpz_fits_ushort_p(mp); }
+  bool fits_slong_p() const { return mpz_fits_slong_p(mp); }
+  bool fits_ulong_p() const { return mpz_fits_ulong_p(mp); }
+  // bool fits_float_p() const { return mpz_fits_float_p(mp); }
+  // bool fits_double_p() const { return mpz_fits_double_p(mp); }
+  // bool fits_ldouble_p() const { return mpz_fits_ldouble_p(mp); }
+
+#if __GMPXX_USE_CXX11
+  explicit operator bool() const { return mp->_mp_size != 0; }
+#endif
+
+  // member operators
+  __GMP_DECLARE_COMPOUND_OPERATOR(operator+=)
+  __GMP_DECLARE_COMPOUND_OPERATOR(operator-=)
+  __GMP_DECLARE_COMPOUND_OPERATOR(operator*=)
+  __GMP_DECLARE_COMPOUND_OPERATOR(operator/=)
+  __GMP_DECLARE_COMPOUND_OPERATOR(operator%=)
+
+  __GMP_DECLARE_COMPOUND_OPERATOR(operator&=)
+  __GMP_DECLARE_COMPOUND_OPERATOR(operator|=)
+  __GMP_DECLARE_COMPOUND_OPERATOR(operator^=)
+
+  __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator<<=)
+  __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator>>=)
+
+  __GMP_DECLARE_INCREMENT_OPERATOR(operator++)
+  __GMP_DECLARE_INCREMENT_OPERATOR(operator--)
+
+  __GMP_DECLARE_UNARY_STATIC_MEMFUN(mpz_t, factorial, __gmp_fac_function)
+  __GMP_DECLARE_UNARY_STATIC_MEMFUN(mpz_t, primorial, __gmp_primorial_function)
+  __GMP_DECLARE_UNARY_STATIC_MEMFUN(mpz_t, fibonacci, __gmp_fib_function)
+};
+
+typedef __gmp_expr<mpz_t, mpz_t> mpz_class;
+
+
+/**************** mpq_class -- wrapper for mpq_t ****************/
+
+template <>
+class __gmp_expr<mpq_t, mpq_t>
+{
+private:
+  typedef mpq_t value_type;
+  value_type mp;
+
+  // Helper functions used for all arithmetic types
+  void assign_ui(unsigned long l) { mpq_set_ui(mp, l, 1); }
+  void assign_si(signed long l)
+  {
+    if (__GMPXX_CONSTANT_TRUE(l >= 0))
+      assign_ui(l);
+    else
+      mpq_set_si(mp, l, 1);
+  }
+  void assign_d (double d)        { mpq_set_d (mp, d); }
+
+  void init_ui(unsigned long l)	{ mpq_init(mp); get_num() = l; }
+  void init_si(signed long l)	{ mpq_init(mp); get_num() = l; }
+  void init_d (double d)	{ mpq_init(mp); assign_d (d); }
+
+public:
+  mp_bitcnt_t get_prec() const { return mpf_get_default_prec(); }
+  void canonicalize() { mpq_canonicalize(mp); }
+
+  // constructors and destructor
+  __gmp_expr() { mpq_init(mp); }
+
+  __gmp_expr(const __gmp_expr &q)
+  {
+    mpz_init_set(mpq_numref(mp), mpq_numref(q.mp));
+    mpz_init_set(mpq_denref(mp), mpq_denref(q.mp));
+  }
+#if __GMPXX_USE_CXX11
+  __gmp_expr(__gmp_expr &&q)
+  { *mp = *q.mp; mpq_init(q.mp); }
+#endif
+  template <class T>
+  __gmp_expr(const __gmp_expr<mpz_t, T> &expr)
+  { mpq_init(mp); __gmp_set_expr(mp, expr); }
+  template <class T>
+  __gmp_expr(const __gmp_expr<mpq_t, T> &expr)
+  { mpq_init(mp); __gmp_set_expr(mp, expr); }
+  template <class T, class U>
+  explicit __gmp_expr(const __gmp_expr<T, U> &expr)
+  { mpq_init(mp); __gmp_set_expr(mp, expr); }
+
+  __GMPXX_DEFINE_ARITHMETIC_CONSTRUCTORS
+
+  explicit __gmp_expr(const char *s, int base = 0)
+  {
+    mpq_init (mp);
+    // If s is the literal 0, we meant to call another constructor.
+    // If s just happens to evaluate to 0, we would crash, so whatever.
+    if (s == 0)
+      {
+	// Don't turn mpq_class(0,0) into 0
+	mpz_set_si(mpq_denref(mp), base);
+      }
+    else if (mpq_set_str(mp, s, base) != 0)
+      {
+        mpq_clear (mp);
+        throw std::invalid_argument ("mpq_set_str");
+      }
+  }
+  explicit __gmp_expr(const std::string &s, int base = 0)
+  {
+    mpq_init(mp);
+    if (mpq_set_str (mp, s.c_str(), base) != 0)
+      {
+        mpq_clear (mp);
+        throw std::invalid_argument ("mpq_set_str");
+      }
+  }
+  explicit __gmp_expr(mpq_srcptr q)
+  {
+    mpz_init_set(mpq_numref(mp), mpq_numref(q));
+    mpz_init_set(mpq_denref(mp), mpq_denref(q));
+  }
+
+  __gmp_expr(const mpz_class &num, const mpz_class &den)
+  {
+    mpz_init_set(mpq_numref(mp), num.get_mpz_t());
+    mpz_init_set(mpq_denref(mp), den.get_mpz_t());
+  }
+
+  ~__gmp_expr() { mpq_clear(mp); }
+
+  void swap(__gmp_expr& q) __GMPXX_NOEXCEPT { std::swap(*mp, *q.mp); }
+
+  // assignment operators
+  __gmp_expr & operator=(const __gmp_expr &q)
+  { mpq_set(mp, q.mp); return *this; }
+#if __GMPXX_USE_CXX11
+  __gmp_expr & operator=(__gmp_expr &&q) noexcept
+  { swap(q); return *this; }
+  __gmp_expr & operator=(mpz_class &&z) noexcept
+  { get_num() = std::move(z); get_den() = 1u; return *this; }
+#endif
+  template <class T, class U>
+  __gmp_expr<value_type, value_type> & operator=(const __gmp_expr<T, U> &expr)
+  { __gmp_set_expr(mp, expr); return *this; }
+
+  __GMPXX_DEFINE_ARITHMETIC_ASSIGNMENTS
+
+  __gmp_expr & operator=(const char *s)
+  {
+    if (mpq_set_str (mp, s, 0) != 0)
+      throw std::invalid_argument ("mpq_set_str");
+    return *this;
+  }
+  __gmp_expr & operator=(const std::string &s)
+  {
+    if (mpq_set_str(mp, s.c_str(), 0) != 0)
+      throw std::invalid_argument ("mpq_set_str");
+    return *this;
+  }
+
+  // string input/output functions
+  int set_str(const char *s, int base)
+  { return mpq_set_str(mp, s, base); }
+  int set_str(const std::string &s, int base)
+  { return mpq_set_str(mp, s.c_str(), base); }
+  std::string get_str(int base = 10) const
+  {
+    __gmp_alloc_cstring temp(mpq_get_str(0, base, mp));
+    return std::string(temp.str);
+  }
+
+  // conversion functions
+
+  // casting a reference to an mpz_t to mpz_class & is a dirty hack,
+  // but works because the internal representation of mpz_class is
+  // exactly an mpz_t
+  const mpz_class & get_num() const
+  { return reinterpret_cast<const mpz_class &>(*mpq_numref(mp)); }
+  mpz_class & get_num()
+  { return reinterpret_cast<mpz_class &>(*mpq_numref(mp)); }
+  const mpz_class & get_den() const
+  { return reinterpret_cast<const mpz_class &>(*mpq_denref(mp)); }
+  mpz_class & get_den()
+  { return reinterpret_cast<mpz_class &>(*mpq_denref(mp)); }
+
+  mpq_srcptr __get_mp() const { return mp; }
+  mpq_ptr __get_mp() { return mp; }
+  mpq_srcptr get_mpq_t() const { return mp; }
+  mpq_ptr get_mpq_t() { return mp; }
+
+  mpz_srcptr get_num_mpz_t() const { return mpq_numref(mp); }
+  mpz_ptr get_num_mpz_t() { return mpq_numref(mp); }
+  mpz_srcptr get_den_mpz_t() const { return mpq_denref(mp); }
+  mpz_ptr get_den_mpz_t() { return mpq_denref(mp); }
+
+  double get_d() const { return mpq_get_d(mp); }
+
+#if __GMPXX_USE_CXX11
+  explicit operator bool() const { return mpq_numref(mp)->_mp_size != 0; }
+#endif
+
+  // compound assignments
+  __GMP_DECLARE_COMPOUND_OPERATOR(operator+=)
+  __GMP_DECLARE_COMPOUND_OPERATOR(operator-=)
+  __GMP_DECLARE_COMPOUND_OPERATOR(operator*=)
+  __GMP_DECLARE_COMPOUND_OPERATOR(operator/=)
+
+  __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator<<=)
+  __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator>>=)
+
+  __GMP_DECLARE_INCREMENT_OPERATOR(operator++)
+  __GMP_DECLARE_INCREMENT_OPERATOR(operator--)
+};
+
+typedef __gmp_expr<mpq_t, mpq_t> mpq_class;
+
+
+/**************** mpf_class -- wrapper for mpf_t ****************/
+
+template <>
+class __gmp_expr<mpf_t, mpf_t>
+{
+private:
+  typedef mpf_t value_type;
+  value_type mp;
+
+  // Helper functions used for all arithmetic types
+  void assign_ui(unsigned long l) { mpf_set_ui(mp, l); }
+  void assign_si(signed long l)
+  {
+    if (__GMPXX_CONSTANT_TRUE(l >= 0))
+      assign_ui(l);
+    else
+      mpf_set_si(mp, l);
+  }
+  void assign_d (double d)        { mpf_set_d (mp, d); }
+
+  void init_ui(unsigned long l)
+  {
+    if (__GMPXX_CONSTANT_TRUE(l == 0))
+      mpf_init(mp);
+    else
+      mpf_init_set_ui(mp, l);
+  }
+  void init_si(signed long l)
+  {
+    if (__GMPXX_CONSTANT_TRUE(l >= 0))
+      init_ui(l);
+    else
+      mpf_init_set_si(mp, l);
+  }
+  void init_d (double d)	{ mpf_init_set_d (mp, d); }
+
+public:
+  mp_bitcnt_t get_prec() const { return mpf_get_prec(mp); }
+
+  void set_prec(mp_bitcnt_t prec) { mpf_set_prec(mp, prec); }
+  void set_prec_raw(mp_bitcnt_t prec) { mpf_set_prec_raw(mp, prec); }
+
+  // constructors and destructor
+  __gmp_expr() { mpf_init(mp); }
+
+  __gmp_expr(const __gmp_expr &f)
+  { mpf_init2(mp, f.get_prec()); mpf_set(mp, f.mp); }
+#if __GMPXX_USE_CXX11
+  __gmp_expr(__gmp_expr &&f)
+  { *mp = *f.mp; mpf_init2(f.mp, get_prec()); }
+#endif
+  __gmp_expr(const __gmp_expr &f, mp_bitcnt_t prec)
+  { mpf_init2(mp, prec); mpf_set(mp, f.mp); }
+  template <class T, class U>
+  __gmp_expr(const __gmp_expr<T, U> &expr)
+  { mpf_init2(mp, expr.get_prec()); __gmp_set_expr(mp, expr); }
+  template <class T, class U>
+  __gmp_expr(const __gmp_expr<T, U> &expr, mp_bitcnt_t prec)
+  { mpf_init2(mp, prec); __gmp_set_expr(mp, expr); }
+
+  __GMPXX_DEFINE_ARITHMETIC_CONSTRUCTORS
+
+  __gmp_expr(signed char c, mp_bitcnt_t prec)
+  { mpf_init2(mp, prec); mpf_set_si(mp, c); }
+  __gmp_expr(unsigned char c, mp_bitcnt_t prec)
+  { mpf_init2(mp, prec); mpf_set_ui(mp, c); }
+
+  __gmp_expr(signed int i, mp_bitcnt_t prec)
+  { mpf_init2(mp, prec); mpf_set_si(mp, i); }
+  __gmp_expr(unsigned int i, mp_bitcnt_t prec)
+  { mpf_init2(mp, prec); mpf_set_ui(mp, i); }
+
+  __gmp_expr(signed short int s, mp_bitcnt_t prec)
+  { mpf_init2(mp, prec); mpf_set_si(mp, s); }
+  __gmp_expr(unsigned short int s, mp_bitcnt_t prec)
+  { mpf_init2(mp, prec); mpf_set_ui(mp, s); }
+
+  __gmp_expr(signed long int l, mp_bitcnt_t prec)
+  { mpf_init2(mp, prec); mpf_set_si(mp, l); }
+  __gmp_expr(unsigned long int l, mp_bitcnt_t prec)
+  { mpf_init2(mp, prec); mpf_set_ui(mp, l); }
+
+  __gmp_expr(float f, mp_bitcnt_t prec)
+  { mpf_init2(mp, prec); mpf_set_d(mp, f); }
+  __gmp_expr(double d, mp_bitcnt_t prec)
+  { mpf_init2(mp, prec); mpf_set_d(mp, d); }
+  // __gmp_expr(long double ld) { mpf_init_set_d(mp, ld); }
+  // __gmp_expr(long double ld, mp_bitcnt_t prec)
+  // { mpf_init2(mp, prec); mpf_set_d(mp, ld); }
+
+  explicit __gmp_expr(const char *s)
+  {
+    if (mpf_init_set_str (mp, s, 0) != 0)
+      {
+        mpf_clear (mp);
+        throw std::invalid_argument ("mpf_set_str");
+      }
+  }
+  __gmp_expr(const char *s, mp_bitcnt_t prec, int base = 0)
+  {
+    mpf_init2(mp, prec);
+    if (mpf_set_str(mp, s, base) != 0)
+      {
+        mpf_clear (mp);
+        throw std::invalid_argument ("mpf_set_str");
+      }
+  }
+  explicit __gmp_expr(const std::string &s)
+  {
+    if (mpf_init_set_str(mp, s.c_str(), 0) != 0)
+      {
+        mpf_clear (mp);
+        throw std::invalid_argument ("mpf_set_str");
+      }
+  }
+  __gmp_expr(const std::string &s, mp_bitcnt_t prec, int base = 0)
+  {
+    mpf_init2(mp, prec);
+    if (mpf_set_str(mp, s.c_str(), base) != 0)
+      {
+        mpf_clear (mp);
+        throw std::invalid_argument ("mpf_set_str");
+      }
+  }
+
+  explicit __gmp_expr(mpf_srcptr f)
+  { mpf_init2(mp, mpf_get_prec(f)); mpf_set(mp, f); }
+  __gmp_expr(mpf_srcptr f, mp_bitcnt_t prec)
+  { mpf_init2(mp, prec); mpf_set(mp, f); }
+
+  ~__gmp_expr() { mpf_clear(mp); }
+
+  void swap(__gmp_expr& f) __GMPXX_NOEXCEPT { std::swap(*mp, *f.mp); }
+
+  // assignment operators
+  __gmp_expr & operator=(const __gmp_expr &f)
+  { mpf_set(mp, f.mp); return *this; }
+#if __GMPXX_USE_CXX11
+  __gmp_expr & operator=(__gmp_expr &&f) noexcept
+  { swap(f); return *this; }
+#endif
+  template <class T, class U>
+  __gmp_expr<value_type, value_type> & operator=(const __gmp_expr<T, U> &expr)
+  { __gmp_set_expr(mp, expr); return *this; }
+
+  __GMPXX_DEFINE_ARITHMETIC_ASSIGNMENTS
+
+  __gmp_expr & operator=(const char *s)
+  {
+    if (mpf_set_str (mp, s, 0) != 0)
+      throw std::invalid_argument ("mpf_set_str");
+    return *this;
+  }
+  __gmp_expr & operator=(const std::string &s)
+  {
+    if (mpf_set_str(mp, s.c_str(), 0) != 0)
+      throw std::invalid_argument ("mpf_set_str");
+    return *this;
+  }
+
+  // string input/output functions
+  int set_str(const char *s, int base)
+  { return mpf_set_str(mp, s, base); }
+  int set_str(const std::string &s, int base)
+  { return mpf_set_str(mp, s.c_str(), base); }
+  std::string get_str(mp_exp_t &expo, int base = 10, size_t size = 0) const
+  {
+    __gmp_alloc_cstring temp(mpf_get_str(0, &expo, base, size, mp));
+    return std::string(temp.str);
+  }
+
+  // conversion functions
+  mpf_srcptr __get_mp() const { return mp; }
+  mpf_ptr __get_mp() { return mp; }
+  mpf_srcptr get_mpf_t() const { return mp; }
+  mpf_ptr get_mpf_t() { return mp; }
+
+  signed long int get_si() const { return mpf_get_si(mp); }
+  unsigned long int get_ui() const { return mpf_get_ui(mp); }
+  double get_d() const { return mpf_get_d(mp); }
+
+  // bool fits_schar_p() const { return mpf_fits_schar_p(mp); }
+  // bool fits_uchar_p() const { return mpf_fits_uchar_p(mp); }
+  bool fits_sint_p() const { return mpf_fits_sint_p(mp); }
+  bool fits_uint_p() const { return mpf_fits_uint_p(mp); }
+  bool fits_sshort_p() const { return mpf_fits_sshort_p(mp); }
+  bool fits_ushort_p() const { return mpf_fits_ushort_p(mp); }
+  bool fits_slong_p() const { return mpf_fits_slong_p(mp); }
+  bool fits_ulong_p() const { return mpf_fits_ulong_p(mp); }
+  // bool fits_float_p() const { return mpf_fits_float_p(mp); }
+  // bool fits_double_p() const { return mpf_fits_double_p(mp); }
+  // bool fits_ldouble_p() const { return mpf_fits_ldouble_p(mp); }
+
+#if __GMPXX_USE_CXX11
+  explicit operator bool() const { return mpf_sgn(mp) != 0; }
+#endif
+
+  // compound assignments
+  __GMP_DECLARE_COMPOUND_OPERATOR(operator+=)
+  __GMP_DECLARE_COMPOUND_OPERATOR(operator-=)
+  __GMP_DECLARE_COMPOUND_OPERATOR(operator*=)
+  __GMP_DECLARE_COMPOUND_OPERATOR(operator/=)
+
+  __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator<<=)
+  __GMP_DECLARE_COMPOUND_OPERATOR_UI(operator>>=)
+
+  __GMP_DECLARE_INCREMENT_OPERATOR(operator++)
+  __GMP_DECLARE_INCREMENT_OPERATOR(operator--)
+};
+
+typedef __gmp_expr<mpf_t, mpf_t> mpf_class;
+
+
+
+/**************** User-defined literals ****************/
+
+#if __GMPXX_USE_CXX11
+inline mpz_class operator"" _mpz(const char* s)
+{
+  return mpz_class(s);
+}
+
+inline mpq_class operator"" _mpq(const char* s)
+{
+  mpq_class q;
+  q.get_num() = s;
+  return q;
+}
+
+inline mpf_class operator"" _mpf(const char* s)
+{
+  return mpf_class(s);
+}
+#endif
+
+/**************** I/O operators ****************/
+
+// these should (and will) be provided separately
+
+template <class T, class U>
+inline std::ostream & operator<<
+(std::ostream &o, const __gmp_expr<T, U> &expr)
+{
+  __gmp_expr<T, T> const& temp(expr);
+  return o << temp.__get_mp();
+}
+
+template <class T>
+inline std::istream & operator>>(std::istream &i, __gmp_expr<T, T> &expr)
+{
+  return i >> expr.__get_mp();
+}
+
+/*
+// you might want to uncomment this
+inline std::istream & operator>>(std::istream &i, mpq_class &q)
+{
+  i >> q.get_mpq_t();
+  q.canonicalize();
+  return i;
+}
+*/
+
+
+/**************** Functions for type conversion ****************/
+
+inline void __gmp_set_expr(mpz_ptr z, const mpz_class &w)
+{
+  mpz_set(z, w.get_mpz_t());
+}
+
+template <class T>
+inline void __gmp_set_expr(mpz_ptr z, const __gmp_expr<mpz_t, T> &expr)
+{
+  expr.eval(z);
+}
+
+template <class T>
+inline void __gmp_set_expr(mpz_ptr z, const __gmp_expr<mpq_t, T> &expr)
+{
+  mpq_class const& temp(expr);
+  mpz_set_q(z, temp.get_mpq_t());
+}
+
+template <class T>
+inline void __gmp_set_expr(mpz_ptr z, const __gmp_expr<mpf_t, T> &expr)
+{
+  mpf_class const& temp(expr);
+  mpz_set_f(z, temp.get_mpf_t());
+}
+
+inline void __gmp_set_expr(mpq_ptr q, const mpz_class &z)
+{
+  mpq_set_z(q, z.get_mpz_t());
+}
+
+template <class T>
+inline void __gmp_set_expr(mpq_ptr q, const __gmp_expr<mpz_t, T> &expr)
+{
+  __gmp_set_expr(mpq_numref(q), expr);
+  mpz_set_ui(mpq_denref(q), 1);
+}
+
+inline void __gmp_set_expr(mpq_ptr q, const mpq_class &r)
+{
+  mpq_set(q, r.get_mpq_t());
+}
+
+template <class T>
+inline void __gmp_set_expr(mpq_ptr q, const __gmp_expr<mpq_t, T> &expr)
+{
+  expr.eval(q);
+}
+
+template <class T>
+inline void __gmp_set_expr(mpq_ptr q, const __gmp_expr<mpf_t, T> &expr)
+{
+  mpf_class const& temp(expr);
+  mpq_set_f(q, temp.get_mpf_t());
+}
+
+template <class T>
+inline void __gmp_set_expr(mpf_ptr f, const __gmp_expr<mpz_t, T> &expr)
+{
+  mpz_class const& temp(expr);
+  mpf_set_z(f, temp.get_mpz_t());
+}
+
+template <class T>
+inline void __gmp_set_expr(mpf_ptr f, const __gmp_expr<mpq_t, T> &expr)
+{
+  mpq_class const& temp(expr);
+  mpf_set_q(f, temp.get_mpq_t());
+}
+
+inline void __gmp_set_expr(mpf_ptr f, const mpf_class &g)
+{
+  mpf_set(f, g.get_mpf_t());
+}
+
+template <class T>
+inline void __gmp_set_expr(mpf_ptr f, const __gmp_expr<mpf_t, T> &expr)
+{
+  expr.eval(f);
+}
+
+
+/* Temporary objects */
+
+template <class T>
+class __gmp_temp
+{
+  __gmp_expr<T, T> val;
+  public:
+  template<class U, class V>
+  __gmp_temp(U const& u, V) : val (u) {}
+  typename __gmp_resolve_expr<T>::srcptr_type
+  __get_mp() const { return val.__get_mp(); }
+};
+
+template <>
+class __gmp_temp <mpf_t>
+{
+  mpf_class val;
+  public:
+  template<class U>
+  __gmp_temp(U const& u, mpf_ptr res) : val (u, mpf_get_prec(res)) {}
+  mpf_srcptr __get_mp() const { return val.__get_mp(); }
+};
+
+/**************** Specializations of __gmp_expr ****************/
+/* The eval() method of __gmp_expr<T, U> evaluates the corresponding
+   expression and assigns the result to its argument, which is either an
+   mpz_t, mpq_t, or mpf_t as specified by the T argument.
+   Compound expressions are evaluated recursively (temporaries are created
+   to hold intermediate values), while for simple expressions the eval()
+   method of the appropriate function object (available as the Op argument
+   of either __gmp_unary_expr<T, Op> or __gmp_binary_expr<T, U, Op>) is
+   called. */
+
+
+/**************** Unary expressions ****************/
+/* cases:
+   - simple:   argument is mp*_class, that is, __gmp_expr<T, T>
+   - compound: argument is __gmp_expr<T, U> (with U not equal to T) */
+
+
+// simple expressions
+
+template <class T, class Op>
+class __gmp_expr<T, __gmp_unary_expr<__gmp_expr<T, T>, Op> >
+{
+private:
+  typedef __gmp_expr<T, T> val_type;
+
+  __gmp_unary_expr<val_type, Op> expr;
+public:
+  explicit __gmp_expr(const val_type &val) : expr(val) { }
+  void eval(typename __gmp_resolve_expr<T>::ptr_type p) const
+  { Op::eval(p, expr.val.__get_mp()); }
+  const val_type & get_val() const { return expr.val; }
+  mp_bitcnt_t get_prec() const { return expr.val.get_prec(); }
+};
+
+
+// simple expressions, U is a built-in numerical type
+
+template <class T, class U, class Op>
+class __gmp_expr<T, __gmp_unary_expr<U, Op> >
+{
+private:
+  typedef U val_type;
+
+  __gmp_unary_expr<val_type, Op> expr;
+public:
+  explicit __gmp_expr(const val_type &val) : expr(val) { }
+  void eval(typename __gmp_resolve_expr<T>::ptr_type p) const
+  { Op::eval(p, expr.val); }
+  const val_type & get_val() const { return expr.val; }
+  mp_bitcnt_t get_prec() const { return mpf_get_default_prec(); }
+};
+
+
+// compound expressions
+
+template <class T, class U, class Op>
+class __gmp_expr<T, __gmp_unary_expr<__gmp_expr<T, U>, Op> >
+{
+private:
+  typedef __gmp_expr<T, U> val_type;
+
+  __gmp_unary_expr<val_type, Op> expr;
+public:
+  explicit __gmp_expr(const val_type &val) : expr(val) { }
+  void eval(typename __gmp_resolve_expr<T>::ptr_type p) const
+  { expr.val.eval(p); Op::eval(p, p); }
+  const val_type & get_val() const { return expr.val; }
+  mp_bitcnt_t get_prec() const { return expr.val.get_prec(); }
+};
+
+
+/**************** Binary expressions ****************/
+/* simple:
+   - arguments are both mp*_class
+   - one argument is mp*_class, one is a built-in type
+   compound:
+   - one is mp*_class, one is __gmp_expr<T, U>
+   - one is __gmp_expr<T, U>, one is built-in
+   - both arguments are __gmp_expr<...> */
+
+
+// simple expressions
+
+template <class T, class Op>
+class __gmp_expr
+<T, __gmp_binary_expr<__gmp_expr<T, T>, __gmp_expr<T, T>, Op> >
+{
+private:
+  typedef __gmp_expr<T, T> val1_type;
+  typedef __gmp_expr<T, T> val2_type;
+
+  __gmp_binary_expr<val1_type, val2_type, Op> expr;
+public:
+  __gmp_expr(const val1_type &val1, const val2_type &val2)
+    : expr(val1, val2) { }
+  void eval(typename __gmp_resolve_expr<T>::ptr_type p) const
+  { Op::eval(p, expr.val1.__get_mp(), expr.val2.__get_mp()); }
+  const val1_type & get_val1() const { return expr.val1; }
+  const val2_type & get_val2() const { return expr.val2; }
+  mp_bitcnt_t get_prec() const
+  {
+    mp_bitcnt_t prec1 = expr.val1.get_prec(),
+      prec2 = expr.val2.get_prec();
+    return (prec1 > prec2) ? prec1 : prec2;
+  }
+};
+
+
+// simple expressions, U is a built-in numerical type
+
+template <class T, class U, class Op>
+class __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, T>, U, Op> >
+{
+private:
+  typedef __gmp_expr<T, T> val1_type;
+  typedef U val2_type;
+
+  __gmp_binary_expr<val1_type, val2_type, Op> expr;
+public:
+  __gmp_expr(const val1_type &val1, const val2_type &val2)
+    : expr(val1, val2) { }
+  void eval(typename __gmp_resolve_expr<T>::ptr_type p) const
+  { Op::eval(p, expr.val1.__get_mp(), expr.val2); }
+  const val1_type & get_val1() const { return expr.val1; }
+  const val2_type & get_val2() const { return expr.val2; }
+  mp_bitcnt_t get_prec() const { return expr.val1.get_prec(); }
+};
+
+template <class T, class U, class Op>
+class __gmp_expr<T, __gmp_binary_expr<U, __gmp_expr<T, T>, Op> >
+{
+private:
+  typedef U val1_type;
+  typedef __gmp_expr<T, T> val2_type;
+
+  __gmp_binary_expr<val1_type, val2_type, Op> expr;
+public:
+  __gmp_expr(const val1_type &val1, const val2_type &val2)
+    : expr(val1, val2) { }
+  void eval(typename __gmp_resolve_expr<T>::ptr_type p) const
+  { Op::eval(p, expr.val1, expr.val2.__get_mp()); }
+  const val1_type & get_val1() const { return expr.val1; }
+  const val2_type & get_val2() const { return expr.val2; }
+  mp_bitcnt_t get_prec() const { return expr.val2.get_prec(); }
+};
+
+
+// compound expressions, one argument is a subexpression
+
+template <class T, class U, class V, class Op>
+class __gmp_expr
+<T, __gmp_binary_expr<__gmp_expr<T, T>, __gmp_expr<U, V>, Op> >
+{
+private:
+  typedef __gmp_expr<T, T> val1_type;
+  typedef __gmp_expr<U, V> val2_type;
+
+  __gmp_binary_expr<val1_type, val2_type, Op> expr;
+public:
+  __gmp_expr(const val1_type &val1, const val2_type &val2)
+    : expr(val1, val2) { }
+  void eval(typename __gmp_resolve_expr<T>::ptr_type p) const
+  {
+    if(p != expr.val1.__get_mp())
+    {
+      __gmp_set_expr(p, expr.val2);
+      Op::eval(p, expr.val1.__get_mp(), p);
+    }
+    else
+    {
+      __gmp_temp<T> temp(expr.val2, p);
+      Op::eval(p, expr.val1.__get_mp(), temp.__get_mp());
+    }
+  }
+  const val1_type & get_val1() const { return expr.val1; }
+  const val2_type & get_val2() const { return expr.val2; }
+  mp_bitcnt_t get_prec() const
+  {
+    mp_bitcnt_t prec1 = expr.val1.get_prec(),
+      prec2 = expr.val2.get_prec();
+    return (prec1 > prec2) ? prec1 : prec2;
+  }
+};
+
+template <class T, class U, class V, class Op>
+class __gmp_expr
+<T, __gmp_binary_expr<__gmp_expr<U, V>, __gmp_expr<T, T>, Op> >
+{
+private:
+  typedef __gmp_expr<U, V> val1_type;
+  typedef __gmp_expr<T, T> val2_type;
+
+  __gmp_binary_expr<val1_type, val2_type, Op> expr;
+public:
+  __gmp_expr(const val1_type &val1, const val2_type &val2)
+    : expr(val1, val2) { }
+  void eval(typename __gmp_resolve_expr<T>::ptr_type p) const
+  {
+    if(p != expr.val2.__get_mp())
+    {
+      __gmp_set_expr(p, expr.val1);
+      Op::eval(p, p, expr.val2.__get_mp());
+    }
+    else
+    {
+      __gmp_temp<T> temp(expr.val1, p);
+      Op::eval(p, temp.__get_mp(), expr.val2.__get_mp());
+    }
+  }
+  const val1_type & get_val1() const { return expr.val1; }
+  const val2_type & get_val2() const { return expr.val2; }
+  mp_bitcnt_t get_prec() const
+  {
+    mp_bitcnt_t prec1 = expr.val1.get_prec(),
+      prec2 = expr.val2.get_prec();
+    return (prec1 > prec2) ? prec1 : prec2;
+  }
+};
+
+template <class T, class U, class Op>
+class __gmp_expr
+<T, __gmp_binary_expr<__gmp_expr<T, T>, __gmp_expr<T, U>, Op> >
+{
+private:
+  typedef __gmp_expr<T, T> val1_type;
+  typedef __gmp_expr<T, U> val2_type;
+
+  __gmp_binary_expr<val1_type, val2_type, Op> expr;
+public:
+  __gmp_expr(const val1_type &val1, const val2_type &val2)
+    : expr(val1, val2) { }
+  void eval(typename __gmp_resolve_expr<T>::ptr_type p) const
+  {
+    if(p != expr.val1.__get_mp())
+    {
+      __gmp_set_expr(p, expr.val2);
+      Op::eval(p, expr.val1.__get_mp(), p);
+    }
+    else
+    {
+      __gmp_temp<T> temp(expr.val2, p);
+      Op::eval(p, expr.val1.__get_mp(), temp.__get_mp());
+    }
+  }
+  const val1_type & get_val1() const { return expr.val1; }
+  const val2_type & get_val2() const { return expr.val2; }
+  mp_bitcnt_t get_prec() const
+  {
+    mp_bitcnt_t prec1 = expr.val1.get_prec(),
+      prec2 = expr.val2.get_prec();
+    return (prec1 > prec2) ? prec1 : prec2;
+  }
+};
+
+template <class T, class U, class Op>
+class __gmp_expr
+<T, __gmp_binary_expr<__gmp_expr<T, U>, __gmp_expr<T, T>, Op> >
+{
+private:
+  typedef __gmp_expr<T, U> val1_type;
+  typedef __gmp_expr<T, T> val2_type;
+
+  __gmp_binary_expr<val1_type, val2_type, Op> expr;
+public:
+  __gmp_expr(const val1_type &val1, const val2_type &val2)
+    : expr(val1, val2) { }
+  void eval(typename __gmp_resolve_expr<T>::ptr_type p) const
+  {
+    if(p != expr.val2.__get_mp())
+    {
+      __gmp_set_expr(p, expr.val1);
+      Op::eval(p, p, expr.val2.__get_mp());
+    }
+    else
+    {
+      __gmp_temp<T> temp(expr.val1, p);
+      Op::eval(p, temp.__get_mp(), expr.val2.__get_mp());
+    }
+  }
+  const val1_type & get_val1() const { return expr.val1; }
+  const val2_type & get_val2() const { return expr.val2; }
+  mp_bitcnt_t get_prec() const
+  {
+    mp_bitcnt_t prec1 = expr.val1.get_prec(),
+      prec2 = expr.val2.get_prec();
+    return (prec1 > prec2) ? prec1 : prec2;
+  }
+};
+
+
+// one argument is a subexpression, one is a built-in
+
+template <class T, class U, class V, class Op>
+class __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, U>, V, Op> >
+{
+private:
+  typedef __gmp_expr<T, U> val1_type;
+  typedef V val2_type;
+
+  __gmp_binary_expr<val1_type, val2_type, Op> expr;
+public:
+  __gmp_expr(const val1_type &val1, const val2_type &val2)
+    : expr(val1, val2) { }
+  void eval(typename __gmp_resolve_expr<T>::ptr_type p) const
+  {
+    expr.val1.eval(p);
+    Op::eval(p, p, expr.val2);
+  }
+  const val1_type & get_val1() const { return expr.val1; }
+  const val2_type & get_val2() const { return expr.val2; }
+  mp_bitcnt_t get_prec() const { return expr.val1.get_prec(); }
+};
+
+template <class T, class U, class V, class Op>
+class __gmp_expr<T, __gmp_binary_expr<U, __gmp_expr<T, V>, Op> >
+{
+private:
+  typedef U val1_type;
+  typedef __gmp_expr<T, V> val2_type;
+
+  __gmp_binary_expr<val1_type, val2_type, Op> expr;
+public:
+  __gmp_expr(const val1_type &val1, const val2_type &val2)
+    : expr(val1, val2) { }
+  void eval(typename __gmp_resolve_expr<T>::ptr_type p) const
+  {
+    expr.val2.eval(p);
+    Op::eval(p, expr.val1, p);
+  }
+  const val1_type & get_val1() const { return expr.val1; }
+  const val2_type & get_val2() const { return expr.val2; }
+  mp_bitcnt_t get_prec() const { return expr.val2.get_prec(); }
+};
+
+
+// both arguments are subexpressions
+
+template <class T, class U, class V, class W, class Op>
+class __gmp_expr
+<T, __gmp_binary_expr<__gmp_expr<T, U>, __gmp_expr<V, W>, Op> >
+{
+private:
+  typedef __gmp_expr<T, U> val1_type;
+  typedef __gmp_expr<V, W> val2_type;
+
+  __gmp_binary_expr<val1_type, val2_type, Op> expr;
+public:
+  __gmp_expr(const val1_type &val1, const val2_type &val2)
+    : expr(val1, val2) { }
+  void eval(typename __gmp_resolve_expr<T>::ptr_type p) const
+  {
+    __gmp_temp<T> temp2(expr.val2, p);
+    expr.val1.eval(p);
+    Op::eval(p, p, temp2.__get_mp());
+  }
+  const val1_type & get_val1() const { return expr.val1; }
+  const val2_type & get_val2() const { return expr.val2; }
+  mp_bitcnt_t get_prec() const
+  {
+    mp_bitcnt_t prec1 = expr.val1.get_prec(),
+      prec2 = expr.val2.get_prec();
+    return (prec1 > prec2) ? prec1 : prec2;
+  }
+};
+
+template <class T, class U, class V, class W, class Op>
+class __gmp_expr
+<T, __gmp_binary_expr<__gmp_expr<U, V>, __gmp_expr<T, W>, Op> >
+{
+private:
+  typedef __gmp_expr<U, V> val1_type;
+  typedef __gmp_expr<T, W> val2_type;
+
+  __gmp_binary_expr<val1_type, val2_type, Op> expr;
+public:
+  __gmp_expr(const val1_type &val1, const val2_type &val2)
+    : expr(val1, val2) { }
+  void eval(typename __gmp_resolve_expr<T>::ptr_type p) const
+  {
+    __gmp_temp<T> temp1(expr.val1, p);
+    expr.val2.eval(p);
+    Op::eval(p, temp1.__get_mp(), p);
+  }
+  const val1_type & get_val1() const { return expr.val1; }
+  const val2_type & get_val2() const { return expr.val2; }
+  mp_bitcnt_t get_prec() const
+  {
+    mp_bitcnt_t prec1 = expr.val1.get_prec(),
+      prec2 = expr.val2.get_prec();
+    return (prec1 > prec2) ? prec1 : prec2;
+  }
+};
+
+template <class T, class U, class V, class Op>
+class __gmp_expr
+<T, __gmp_binary_expr<__gmp_expr<T, U>, __gmp_expr<T, V>, Op> >
+{
+private:
+  typedef __gmp_expr<T, U> val1_type;
+  typedef __gmp_expr<T, V> val2_type;
+
+  __gmp_binary_expr<val1_type, val2_type, Op> expr;
+public:
+  __gmp_expr(const val1_type &val1, const val2_type &val2)
+    : expr(val1, val2) { }
+  void eval(typename __gmp_resolve_expr<T>::ptr_type p) const
+  {
+    __gmp_temp<T> temp2(expr.val2, p);
+    expr.val1.eval(p);
+    Op::eval(p, p, temp2.__get_mp());
+  }
+  const val1_type & get_val1() const { return expr.val1; }
+  const val2_type & get_val2() const { return expr.val2; }
+  mp_bitcnt_t get_prec() const
+  {
+    mp_bitcnt_t prec1 = expr.val1.get_prec(),
+      prec2 = expr.val2.get_prec();
+    return (prec1 > prec2) ? prec1 : prec2;
+  }
+};
+
+
+/**************** Special cases ****************/
+
+/* Some operations (i.e., add and subtract) with mixed mpz/mpq arguments
+   can be done directly without first converting the mpz to mpq.
+   Appropriate specializations of __gmp_expr are required. */
+
+
+#define __GMPZQ_DEFINE_EXPR(eval_fun)                                       \
+                                                                            \
+template <>                                                                 \
+class __gmp_expr<mpq_t, __gmp_binary_expr<mpz_class, mpq_class, eval_fun> > \
+{                                                                           \
+private:                                                                    \
+  typedef mpz_class val1_type;                                              \
+  typedef mpq_class val2_type;                                              \
+                                                                            \
+  __gmp_binary_expr<val1_type, val2_type, eval_fun> expr;                   \
+public:                                                                     \
+  __gmp_expr(const val1_type &val1, const val2_type &val2)                  \
+    : expr(val1, val2) { }                                                  \
+  void eval(mpq_ptr q) const                                                \
+  { eval_fun::eval(q, expr.val1.get_mpz_t(), expr.val2.get_mpq_t()); }      \
+  const val1_type & get_val1() const { return expr.val1; }                  \
+  const val2_type & get_val2() const { return expr.val2; }                  \
+  mp_bitcnt_t get_prec() const { return mpf_get_default_prec(); }           \
+};                                                                          \
+                                                                            \
+template <>                                                                 \
+class __gmp_expr<mpq_t, __gmp_binary_expr<mpq_class, mpz_class, eval_fun> > \
+{                                                                           \
+private:                                                                    \
+  typedef mpq_class val1_type;                                              \
+  typedef mpz_class val2_type;                                              \
+                                                                            \
+  __gmp_binary_expr<val1_type, val2_type, eval_fun> expr;                   \
+public:                                                                     \
+  __gmp_expr(const val1_type &val1, const val2_type &val2)                  \
+    : expr(val1, val2) { }                                                  \
+  void eval(mpq_ptr q) const                                                \
+  { eval_fun::eval(q, expr.val1.get_mpq_t(), expr.val2.get_mpz_t()); }      \
+  const val1_type & get_val1() const { return expr.val1; }                  \
+  const val2_type & get_val2() const { return expr.val2; }                  \
+  mp_bitcnt_t get_prec() const { return mpf_get_default_prec(); }           \
+};                                                                          \
+                                                                            \
+template <class T>                                                          \
+class __gmp_expr                                                            \
+<mpq_t, __gmp_binary_expr<mpz_class, __gmp_expr<mpq_t, T>, eval_fun> >      \
+{                                                                           \
+private:                                                                    \
+  typedef mpz_class val1_type;                                              \
+  typedef __gmp_expr<mpq_t, T> val2_type;                                   \
+                                                                            \
+  __gmp_binary_expr<val1_type, val2_type, eval_fun> expr;                   \
+public:                                                                     \
+  __gmp_expr(const val1_type &val1, const val2_type &val2)                  \
+    : expr(val1, val2) { }                                                  \
+  void eval(mpq_ptr q) const                                                \
+  {                                                                         \
+    mpq_class temp(expr.val2);                                              \
+    eval_fun::eval(q, expr.val1.get_mpz_t(), temp.get_mpq_t());             \
+  }                                                                         \
+  const val1_type & get_val1() const { return expr.val1; }                  \
+  const val2_type & get_val2() const { return expr.val2; }                  \
+  mp_bitcnt_t get_prec() const { return mpf_get_default_prec(); }           \
+};                                                                          \
+                                                                            \
+template <class T>                                                          \
+class __gmp_expr                                                            \
+<mpq_t, __gmp_binary_expr<mpq_class, __gmp_expr<mpz_t, T>, eval_fun> >      \
+{                                                                           \
+private:                                                                    \
+  typedef mpq_class val1_type;                                              \
+  typedef __gmp_expr<mpz_t, T> val2_type;                                   \
+                                                                            \
+  __gmp_binary_expr<val1_type, val2_type, eval_fun> expr;                   \
+public:                                                                     \
+  __gmp_expr(const val1_type &val1, const val2_type &val2)                  \
+    : expr(val1, val2) { }                                                  \
+  void eval(mpq_ptr q) const                                                \
+  {                                                                         \
+    mpz_class temp(expr.val2);                                              \
+    eval_fun::eval(q, expr.val1.get_mpq_t(), temp.get_mpz_t());             \
+  }                                                                         \
+  const val1_type & get_val1() const { return expr.val1; }                  \
+  const val2_type & get_val2() const { return expr.val2; }                  \
+  mp_bitcnt_t get_prec() const { return mpf_get_default_prec(); }           \
+};                                                                          \
+                                                                            \
+template <class T>                                                          \
+class __gmp_expr                                                            \
+<mpq_t, __gmp_binary_expr<__gmp_expr<mpz_t, T>, mpq_class, eval_fun> >      \
+{                                                                           \
+private:                                                                    \
+  typedef __gmp_expr<mpz_t, T> val1_type;                                   \
+  typedef mpq_class val2_type;                                              \
+                                                                            \
+  __gmp_binary_expr<val1_type, val2_type, eval_fun> expr;                   \
+public:                                                                     \
+  __gmp_expr(const val1_type &val1, const val2_type &val2)                  \
+    : expr(val1, val2) { }                                                  \
+  void eval(mpq_ptr q) const                                                \
+  {                                                                         \
+    mpz_class temp(expr.val1);                                              \
+    eval_fun::eval(q, temp.get_mpz_t(), expr.val2.get_mpq_t());             \
+  }                                                                         \
+  const val1_type & get_val1() const { return expr.val1; }                  \
+  const val2_type & get_val2() const { return expr.val2; }                  \
+  mp_bitcnt_t get_prec() const { return mpf_get_default_prec(); }           \
+};                                                                          \
+                                                                            \
+template <class T>                                                          \
+class __gmp_expr                                                            \
+<mpq_t, __gmp_binary_expr<__gmp_expr<mpq_t, T>, mpz_class, eval_fun> >      \
+{                                                                           \
+private:                                                                    \
+  typedef __gmp_expr<mpq_t, T> val1_type;                                   \
+  typedef mpz_class val2_type;                                              \
+                                                                            \
+  __gmp_binary_expr<val1_type, val2_type, eval_fun> expr;                   \
+public:                                                                     \
+  __gmp_expr(const val1_type &val1, const val2_type &val2)                  \
+    : expr(val1, val2) { }                                                  \
+  void eval(mpq_ptr q) const                                                \
+  {                                                                         \
+    mpq_class temp(expr.val1);                                              \
+    eval_fun::eval(q, temp.get_mpq_t(), expr.val2.get_mpz_t());             \
+  }                                                                         \
+  const val1_type & get_val1() const { return expr.val1; }                  \
+  const val2_type & get_val2() const { return expr.val2; }                  \
+  mp_bitcnt_t get_prec() const { return mpf_get_default_prec(); }           \
+};                                                                          \
+                                                                            \
+template <class T, class U>                                                 \
+class __gmp_expr<mpq_t, __gmp_binary_expr                                   \
+<__gmp_expr<mpz_t, T>, __gmp_expr<mpq_t, U>, eval_fun> >                    \
+{                                                                           \
+private:                                                                    \
+  typedef __gmp_expr<mpz_t, T> val1_type;                                   \
+  typedef __gmp_expr<mpq_t, U> val2_type;                                   \
+                                                                            \
+  __gmp_binary_expr<val1_type, val2_type, eval_fun> expr;                   \
+public:                                                                     \
+  __gmp_expr(const val1_type &val1, const val2_type &val2)                  \
+    : expr(val1, val2) { }                                                  \
+  void eval(mpq_ptr q) const                                                \
+  {                                                                         \
+    mpz_class temp1(expr.val1);                                             \
+    expr.val2.eval(q);                                                      \
+    eval_fun::eval(q, temp1.get_mpz_t(), q);                                \
+  }                                                                         \
+  const val1_type & get_val1() const { return expr.val1; }                  \
+  const val2_type & get_val2() const { return expr.val2; }                  \
+  mp_bitcnt_t get_prec() const { return mpf_get_default_prec(); }           \
+};                                                                          \
+                                                                            \
+template <class T, class U>                                                 \
+class __gmp_expr<mpq_t, __gmp_binary_expr                                   \
+<__gmp_expr<mpq_t, T>, __gmp_expr<mpz_t, U>, eval_fun> >                    \
+{                                                                           \
+private:                                                                    \
+  typedef __gmp_expr<mpq_t, T> val1_type;                                   \
+  typedef __gmp_expr<mpz_t, U> val2_type;                                   \
+                                                                            \
+  __gmp_binary_expr<val1_type, val2_type, eval_fun> expr;                   \
+public:                                                                     \
+  __gmp_expr(const val1_type &val1, const val2_type &val2)                  \
+    : expr(val1, val2) { }                                                  \
+  void eval(mpq_ptr q) const                                                \
+  {                                                                         \
+    mpz_class temp2(expr.val2);                                             \
+    expr.val1.eval(q);                                             \
+    eval_fun::eval(q, q, temp2.get_mpz_t());                \
+  }                                                                         \
+  const val1_type & get_val1() const { return expr.val1; }                  \
+  const val2_type & get_val2() const { return expr.val2; }                  \
+  mp_bitcnt_t get_prec() const { return mpf_get_default_prec(); }           \
+};
+
+
+__GMPZQ_DEFINE_EXPR(__gmp_binary_plus)
+__GMPZQ_DEFINE_EXPR(__gmp_binary_minus)
+
+
+
+/**************** Macros for defining functions ****************/
+/* Results of operators and functions are instances of __gmp_expr<T, U>.
+   T determines the numerical type of the expression: it can be either
+   mpz_t, mpq_t, or mpf_t.  When the arguments of a binary
+   expression have different numerical types, __gmp_resolve_expr is used
+   to determine the "larger" type.
+   U is either __gmp_unary_expr<V, Op> or __gmp_binary_expr<V, W, Op>,
+   where V and W are the arguments' types -- they can in turn be
+   expressions, thus allowing to build compound expressions to any
+   degree of complexity.
+   Op is a function object that must have an eval() method accepting
+   appropriate arguments.
+   Actual evaluation of a __gmp_expr<T, U> object is done when it gets
+   assigned to an mp*_class ("lazy" evaluation): this is done by calling
+   its eval() method. */
+
+
+// non-member unary operators and functions
+
+#define __GMP_DEFINE_UNARY_FUNCTION(fun, eval_fun)                           \
+                                                                             \
+template <class T, class U>                                                  \
+inline __gmp_expr<T, __gmp_unary_expr<__gmp_expr<T, U>, eval_fun> >          \
+fun(const __gmp_expr<T, U> &expr)                                            \
+{                                                                            \
+  return __gmp_expr<T, __gmp_unary_expr<__gmp_expr<T, U>, eval_fun> >(expr); \
+}
+
+// variant that only works for one of { mpz, mpq, mpf }
+
+#define __GMP_DEFINE_UNARY_FUNCTION_1(T, fun, eval_fun)                      \
+                                                                             \
+template <class U>                                                           \
+inline __gmp_expr<T, __gmp_unary_expr<__gmp_expr<T, U>, eval_fun> >          \
+fun(const __gmp_expr<T, U> &expr)                                            \
+{                                                                            \
+  return __gmp_expr<T, __gmp_unary_expr<__gmp_expr<T, U>, eval_fun> >(expr); \
+}
+
+#define __GMP_DEFINE_UNARY_TYPE_FUNCTION(type, fun, eval_fun) \
+                                                              \
+template <class T, class U>                                   \
+inline type fun(const __gmp_expr<T, U> &expr)                 \
+{                                                             \
+  __gmp_expr<T, T> const& temp(expr); \
+  return eval_fun::eval(temp.__get_mp());                     \
+}
+
+
+// non-member binary operators and functions
+
+#define __GMPP_DEFINE_BINARY_FUNCTION(fun, eval_fun)                   \
+                                                                       \
+template <class T, class U, class V, class W>                          \
+inline __gmp_expr<typename __gmp_resolve_expr<T, V>::value_type,       \
+__gmp_binary_expr<__gmp_expr<T, U>, __gmp_expr<V, W>, eval_fun> >      \
+fun(const __gmp_expr<T, U> &expr1, const __gmp_expr<V, W> &expr2)      \
+{                                                                      \
+  return __gmp_expr<typename __gmp_resolve_expr<T, V>::value_type,     \
+     __gmp_binary_expr<__gmp_expr<T, U>, __gmp_expr<V, W>, eval_fun> > \
+    (expr1, expr2);                                                    \
+}
+
+#define __GMPNN_DEFINE_BINARY_FUNCTION(fun, eval_fun, type, bigtype)       \
+                                                                           \
+template <class T, class U>                                                \
+inline __gmp_expr                                                          \
+<T, __gmp_binary_expr<__gmp_expr<T, U>, bigtype, eval_fun> >               \
+fun(const __gmp_expr<T, U> &expr, type t)                                  \
+{                                                                          \
+  return __gmp_expr                                                        \
+    <T, __gmp_binary_expr<__gmp_expr<T, U>, bigtype, eval_fun> >(expr, t); \
+}                                                                          \
+                                                                           \
+template <class T, class U>                                                \
+inline __gmp_expr                                                          \
+<T, __gmp_binary_expr<bigtype, __gmp_expr<T, U>, eval_fun> >               \
+fun(type t, const __gmp_expr<T, U> &expr)                                  \
+{                                                                          \
+  return __gmp_expr                                                        \
+    <T, __gmp_binary_expr<bigtype, __gmp_expr<T, U>, eval_fun> >(t, expr); \
+}
+
+#define __GMPNS_DEFINE_BINARY_FUNCTION(fun, eval_fun, type)          \
+__GMPNN_DEFINE_BINARY_FUNCTION(fun, eval_fun, type, signed long int)
+
+#define __GMPNU_DEFINE_BINARY_FUNCTION(fun, eval_fun, type)            \
+__GMPNN_DEFINE_BINARY_FUNCTION(fun, eval_fun, type, unsigned long int)
+
+#define __GMPND_DEFINE_BINARY_FUNCTION(fun, eval_fun, type) \
+__GMPNN_DEFINE_BINARY_FUNCTION(fun, eval_fun, type, double)
+
+#define __GMPNLD_DEFINE_BINARY_FUNCTION(fun, eval_fun, type)     \
+__GMPNN_DEFINE_BINARY_FUNCTION(fun, eval_fun, type, long double)
+
+#define __GMPN_DEFINE_BINARY_FUNCTION(fun, eval_fun)              \
+__GMPNS_DEFINE_BINARY_FUNCTION(fun, eval_fun, signed char)        \
+__GMPNU_DEFINE_BINARY_FUNCTION(fun, eval_fun, unsigned char)      \
+__GMPNS_DEFINE_BINARY_FUNCTION(fun, eval_fun, signed int)         \
+__GMPNU_DEFINE_BINARY_FUNCTION(fun, eval_fun, unsigned int)       \
+__GMPNS_DEFINE_BINARY_FUNCTION(fun, eval_fun, signed short int)   \
+__GMPNU_DEFINE_BINARY_FUNCTION(fun, eval_fun, unsigned short int) \
+__GMPNS_DEFINE_BINARY_FUNCTION(fun, eval_fun, signed long int)    \
+__GMPNU_DEFINE_BINARY_FUNCTION(fun, eval_fun, unsigned long int)  \
+__GMPND_DEFINE_BINARY_FUNCTION(fun, eval_fun, float)              \
+__GMPND_DEFINE_BINARY_FUNCTION(fun, eval_fun, double)             \
+/* __GMPNLD_DEFINE_BINARY_FUNCTION(fun, eval_fun, long double) */
+
+#define __GMP_DEFINE_BINARY_FUNCTION(fun, eval_fun) \
+__GMPP_DEFINE_BINARY_FUNCTION(fun, eval_fun)        \
+__GMPN_DEFINE_BINARY_FUNCTION(fun, eval_fun)
+
+// variant that only works for one of { mpz, mpq, mpf }
+
+#define __GMPP_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun)              \
+                                                                       \
+template <class U, class W>                                            \
+inline __gmp_expr<T,                                                   \
+__gmp_binary_expr<__gmp_expr<T, U>, __gmp_expr<T, W>, eval_fun> >      \
+fun(const __gmp_expr<T, U> &expr1, const __gmp_expr<T, W> &expr2)      \
+{                                                                      \
+  return __gmp_expr<T,                                                 \
+     __gmp_binary_expr<__gmp_expr<T, U>, __gmp_expr<T, W>, eval_fun> > \
+    (expr1, expr2);                                                    \
+}
+
+#define __GMPNN_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun, type, bigtype)  \
+                                                                           \
+template <class U>                                                         \
+inline __gmp_expr                                                          \
+<T, __gmp_binary_expr<__gmp_expr<T, U>, bigtype, eval_fun> >               \
+fun(const __gmp_expr<T, U> &expr, type t)                                  \
+{                                                                          \
+  return __gmp_expr                                                        \
+    <T, __gmp_binary_expr<__gmp_expr<T, U>, bigtype, eval_fun> >(expr, t); \
+}                                                                          \
+                                                                           \
+template <class U>                                                         \
+inline __gmp_expr                                                          \
+<T, __gmp_binary_expr<bigtype, __gmp_expr<T, U>, eval_fun> >               \
+fun(type t, const __gmp_expr<T, U> &expr)                                  \
+{                                                                          \
+  return __gmp_expr                                                        \
+    <T, __gmp_binary_expr<bigtype, __gmp_expr<T, U>, eval_fun> >(t, expr); \
+}
+
+#define __GMPNS_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun, type)          \
+__GMPNN_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun, type, signed long int)
+
+#define __GMPNU_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun, type)          \
+__GMPNN_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun, type, unsigned long int)
+
+#define __GMPND_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun, type) \
+__GMPNN_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun, type, double)
+
+#define __GMPNLD_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun, type)     \
+__GMPNN_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun, type, long double)
+
+#define __GMPN_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun)              \
+__GMPNS_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun, signed char)        \
+__GMPNU_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun, unsigned char)      \
+__GMPNS_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun, signed int)         \
+__GMPNU_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun, unsigned int)       \
+__GMPNS_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun, signed short int)   \
+__GMPNU_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun, unsigned short int) \
+__GMPNS_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun, signed long int)    \
+__GMPNU_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun, unsigned long int)  \
+__GMPND_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun, float)              \
+__GMPND_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun, double)             \
+/* __GMPNLD_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun, long double) */
+
+#define __GMP_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun) \
+__GMPP_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun)        \
+__GMPN_DEFINE_BINARY_FUNCTION_1(T, fun, eval_fun)
+
+
+#define __GMP_DEFINE_BINARY_FUNCTION_UI(fun, eval_fun)                 \
+                                                                       \
+template <class T, class U>                                            \
+inline __gmp_expr                                                      \
+<T, __gmp_binary_expr<__gmp_expr<T, U>, mp_bitcnt_t, eval_fun> > \
+fun(const __gmp_expr<T, U> &expr, mp_bitcnt_t l)                 \
+{                                                                      \
+  return __gmp_expr<T, __gmp_binary_expr                               \
+    <__gmp_expr<T, U>, mp_bitcnt_t, eval_fun> >(expr, l);        \
+}
+
+
+#define __GMPP_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun)         \
+                                                                        \
+template <class T, class U, class V, class W>                           \
+inline type fun(const __gmp_expr<T, U> &expr1,                          \
+		const __gmp_expr<V, W> &expr2)                          \
+{                                                                       \
+  __gmp_expr<T, T> const& temp1(expr1);                                 \
+  __gmp_expr<V, V> const& temp2(expr2);                                 \
+  return eval_fun::eval(temp1.__get_mp(), temp2.__get_mp());            \
+}
+
+#define __GMPNN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun,   \
+					    type2, bigtype)        \
+                                                                   \
+template <class T, class U>                                        \
+inline type fun(const __gmp_expr<T, U> &expr, type2 t)             \
+{                                                                  \
+  __gmp_expr<T, T> const& temp(expr);      \
+  return eval_fun::eval(temp.__get_mp(), static_cast<bigtype>(t)); \
+}                                                                  \
+                                                                   \
+template <class T, class U>                                        \
+inline type fun(type2 t, const __gmp_expr<T, U> &expr)             \
+{                                                                  \
+  __gmp_expr<T, T> const& temp(expr);      \
+  return eval_fun::eval(static_cast<bigtype>(t), temp.__get_mp()); \
+}
+
+#define __GMPNS_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2) \
+__GMPNN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun,                \
+				    type2, signed long int)
+
+#define __GMPNU_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2) \
+__GMPNN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun,                \
+				    type2, unsigned long int)
+
+#define __GMPND_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2) \
+__GMPNN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2, double)
+
+#define __GMPNLD_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2)     \
+__GMPNN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, type2, long double)
+
+#define __GMPN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun)              \
+__GMPNS_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, signed char)        \
+__GMPNU_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, unsigned char)      \
+__GMPNS_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, signed int)         \
+__GMPNU_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, unsigned int)       \
+__GMPNS_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, signed short int)   \
+__GMPNU_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, unsigned short int) \
+__GMPNS_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, signed long int)    \
+__GMPNU_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, unsigned long int)  \
+__GMPND_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, float)              \
+__GMPND_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, double)             \
+/* __GMPNLD_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun, long double) */
+
+#define __GMP_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun) \
+__GMPP_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun)        \
+__GMPN_DEFINE_BINARY_TYPE_FUNCTION(type, fun, eval_fun)
+
+
+// member operators
+
+#define __GMPP_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun)                 \
+                                                                             \
+template <class T, class U>                                                  \
+inline type##_class & type##_class::fun(const __gmp_expr<T, U> &expr)        \
+{                                                                            \
+  __gmp_set_expr(mp, __gmp_expr<type##_t, __gmp_binary_expr                  \
+		 <type##_class, __gmp_expr<T, U>, eval_fun> >(*this, expr)); \
+  return *this;                                                              \
+}
+
+#define __GMPNN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun,    \
+					 type2, bigtype)         \
+                                                                 \
+inline type##_class & type##_class::fun(type2 t)                 \
+{                                                                \
+  __gmp_set_expr(mp, __gmp_expr<type##_t, __gmp_binary_expr      \
+		 <type##_class, bigtype, eval_fun> >(*this, t)); \
+  return *this;                                                  \
+}
+
+#define __GMPNS_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2) \
+__GMPNN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun,                \
+				 type2, signed long int)
+
+#define __GMPNU_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2) \
+__GMPNN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun,                \
+				 type2, unsigned long int)
+
+#define __GMPND_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2) \
+__GMPNN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2, double)
+
+#define __GMPNLD_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2)     \
+__GMPNN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, type2, long double)
+
+#define __GMPN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun)              \
+__GMPNS_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, signed char)        \
+__GMPNU_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, unsigned char)      \
+__GMPNS_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, signed int)         \
+__GMPNU_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, unsigned int)       \
+__GMPNS_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, signed short int)   \
+__GMPNU_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, unsigned short int) \
+__GMPNS_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, signed long int)    \
+__GMPNU_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, unsigned long int)  \
+__GMPND_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, float)              \
+__GMPND_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, double)             \
+/* __GMPNLD_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun, long double) */
+
+#define __GMP_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun) \
+__GMPP_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun)        \
+__GMPN_DEFINE_COMPOUND_OPERATOR(type, fun, eval_fun)
+
+#define __GMPZ_DEFINE_COMPOUND_OPERATOR(fun, eval_fun) \
+__GMP_DEFINE_COMPOUND_OPERATOR(mpz, fun, eval_fun)
+
+#define __GMPQ_DEFINE_COMPOUND_OPERATOR(fun, eval_fun) \
+__GMP_DEFINE_COMPOUND_OPERATOR(mpq, fun, eval_fun)
+
+#define __GMPF_DEFINE_COMPOUND_OPERATOR(fun, eval_fun) \
+__GMP_DEFINE_COMPOUND_OPERATOR(mpf, fun, eval_fun)
+
+
+
+#define __GMP_DEFINE_COMPOUND_OPERATOR_UI(type, fun, eval_fun)  \
+                                                                \
+inline type##_class & type##_class::fun(mp_bitcnt_t l)    \
+{                                                               \
+  __gmp_set_expr(mp, __gmp_expr<type##_t, __gmp_binary_expr     \
+    <type##_class, mp_bitcnt_t, eval_fun> >(*this, l));   \
+  return *this;                                                 \
+}
+
+#define __GMPZ_DEFINE_COMPOUND_OPERATOR_UI(fun, eval_fun) \
+__GMP_DEFINE_COMPOUND_OPERATOR_UI(mpz, fun, eval_fun)
+
+#define __GMPQ_DEFINE_COMPOUND_OPERATOR_UI(fun, eval_fun) \
+__GMP_DEFINE_COMPOUND_OPERATOR_UI(mpq, fun, eval_fun)
+
+#define __GMPF_DEFINE_COMPOUND_OPERATOR_UI(fun, eval_fun) \
+__GMP_DEFINE_COMPOUND_OPERATOR_UI(mpf, fun, eval_fun)
+
+
+
+#define __GMP_DEFINE_INCREMENT_OPERATOR(type, fun, eval_fun) \
+                                                             \
+inline type##_class & type##_class::fun()                    \
+{                                                            \
+  eval_fun::eval(mp);                                        \
+  return *this;                                              \
+}                                                            \
+                                                             \
+inline type##_class type##_class::fun(int)                   \
+{                                                            \
+  type##_class temp(*this);                                  \
+  eval_fun::eval(mp);                                        \
+  return temp;                                               \
+}
+
+#define __GMPZ_DEFINE_INCREMENT_OPERATOR(fun, eval_fun) \
+__GMP_DEFINE_INCREMENT_OPERATOR(mpz, fun, eval_fun)
+
+#define __GMPQ_DEFINE_INCREMENT_OPERATOR(fun, eval_fun) \
+__GMP_DEFINE_INCREMENT_OPERATOR(mpq, fun, eval_fun)
+
+#define __GMPF_DEFINE_INCREMENT_OPERATOR(fun, eval_fun) \
+__GMP_DEFINE_INCREMENT_OPERATOR(mpf, fun, eval_fun)
+
+
+#define __GMPP_DEFINE_UNARY_STATIC_MEMFUN(T, fun, eval_fun)                  \
+template <class U>                                                           \
+__gmp_expr<T, __gmp_unary_expr<__gmp_expr<T, U>, eval_fun> >          \
+fun(const __gmp_expr<T, U> &expr)                                            \
+{                                                                            \
+  return __gmp_expr<T, __gmp_unary_expr<__gmp_expr<T, U>, eval_fun> >(expr); \
+}
+
+#define __GMPNN_DEFINE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, type, bigtype)  \
+inline __gmp_expr<T, __gmp_unary_expr<bigtype, eval_fun> >                   \
+fun(type expr)                                                               \
+{                                                                            \
+  return __gmp_expr<T, __gmp_unary_expr<bigtype, eval_fun> >(expr);          \
+}
+
+#define __GMPNS_DEFINE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, type)  \
+__GMPNN_DEFINE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, type, signed long)
+#define __GMPNU_DEFINE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, type)  \
+__GMPNN_DEFINE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, type, unsigned long)
+#define __GMPND_DEFINE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, type)  \
+__GMPNN_DEFINE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, type, double)
+
+#define __GMPN_DEFINE_UNARY_STATIC_MEMFUN(T, fun, eval_fun)                 \
+__GMPNS_DEFINE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, signed char)           \
+__GMPNU_DEFINE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, unsigned char)         \
+__GMPNS_DEFINE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, signed int)            \
+__GMPNU_DEFINE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, unsigned int)          \
+__GMPNS_DEFINE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, signed short int)      \
+__GMPNU_DEFINE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, unsigned short int)    \
+__GMPNS_DEFINE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, signed long int)       \
+__GMPNU_DEFINE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, unsigned long int)     \
+__GMPND_DEFINE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, float)                 \
+__GMPND_DEFINE_UNARY_STATIC_MEMFUN(T, fun, eval_fun, double)                \
+
+#define __GMP_DEFINE_UNARY_STATIC_MEMFUN(T, fun, eval_fun)                  \
+__GMPP_DEFINE_UNARY_STATIC_MEMFUN(T, fun, eval_fun)                         \
+__GMPN_DEFINE_UNARY_STATIC_MEMFUN(T, fun, eval_fun)                         \
+
+
+/**************** Arithmetic operators and functions ****************/
+
+// non-member operators and functions
+
+__GMP_DEFINE_UNARY_FUNCTION(operator+, __gmp_unary_plus)
+__GMP_DEFINE_UNARY_FUNCTION(operator-, __gmp_unary_minus)
+__GMP_DEFINE_UNARY_FUNCTION_1(mpz_t, operator~, __gmp_unary_com)
+
+__GMP_DEFINE_BINARY_FUNCTION(operator+, __gmp_binary_plus)
+__GMP_DEFINE_BINARY_FUNCTION(operator-, __gmp_binary_minus)
+__GMP_DEFINE_BINARY_FUNCTION(operator*, __gmp_binary_multiplies)
+__GMP_DEFINE_BINARY_FUNCTION(operator/, __gmp_binary_divides)
+__GMP_DEFINE_BINARY_FUNCTION_1(mpz_t, operator%, __gmp_binary_modulus)
+__GMP_DEFINE_BINARY_FUNCTION_1(mpz_t, operator&, __gmp_binary_and)
+__GMP_DEFINE_BINARY_FUNCTION_1(mpz_t, operator|, __gmp_binary_ior)
+__GMP_DEFINE_BINARY_FUNCTION_1(mpz_t, operator^, __gmp_binary_xor)
+
+__GMP_DEFINE_BINARY_FUNCTION_UI(operator<<, __gmp_binary_lshift)
+__GMP_DEFINE_BINARY_FUNCTION_UI(operator>>, __gmp_binary_rshift)
+
+__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator==, __gmp_binary_equal)
+__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator!=, ! __gmp_binary_equal)
+__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator<, __gmp_binary_less)
+__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator<=, ! __gmp_binary_greater)
+__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator>, __gmp_binary_greater)
+__GMP_DEFINE_BINARY_TYPE_FUNCTION(bool, operator>=, ! __gmp_binary_less)
+
+__GMP_DEFINE_UNARY_FUNCTION(abs, __gmp_abs_function)
+__GMP_DEFINE_UNARY_FUNCTION_1(mpf_t, trunc, __gmp_trunc_function)
+__GMP_DEFINE_UNARY_FUNCTION_1(mpf_t, floor, __gmp_floor_function)
+__GMP_DEFINE_UNARY_FUNCTION_1(mpf_t, ceil, __gmp_ceil_function)
+__GMP_DEFINE_UNARY_FUNCTION_1(mpf_t, sqrt, __gmp_sqrt_function)
+__GMP_DEFINE_UNARY_FUNCTION_1(mpz_t, sqrt, __gmp_sqrt_function)
+__GMP_DEFINE_UNARY_FUNCTION_1(mpz_t, factorial, __gmp_fac_function)
+__GMP_DEFINE_UNARY_FUNCTION_1(mpz_t, primorial, __gmp_primorial_function)
+__GMP_DEFINE_UNARY_FUNCTION_1(mpz_t, fibonacci, __gmp_fib_function)
+__GMP_DEFINE_BINARY_FUNCTION_1(mpf_t, hypot, __gmp_hypot_function)
+__GMP_DEFINE_BINARY_FUNCTION_1(mpz_t, gcd, __gmp_gcd_function)
+__GMP_DEFINE_BINARY_FUNCTION_1(mpz_t, lcm, __gmp_lcm_function)
+
+__GMP_DEFINE_UNARY_TYPE_FUNCTION(int, sgn, __gmp_sgn_function)
+__GMP_DEFINE_BINARY_TYPE_FUNCTION(int, cmp, __gmp_cmp_function)
+
+template <class T>
+void swap(__gmp_expr<T, T>& x, __gmp_expr<T, T>& y) __GMPXX_NOEXCEPT
+{ x.swap(y); }
+
+// member operators for mpz_class
+
+__GMPZ_DEFINE_COMPOUND_OPERATOR(operator+=, __gmp_binary_plus)
+__GMPZ_DEFINE_COMPOUND_OPERATOR(operator-=, __gmp_binary_minus)
+__GMPZ_DEFINE_COMPOUND_OPERATOR(operator*=, __gmp_binary_multiplies)
+__GMPZ_DEFINE_COMPOUND_OPERATOR(operator/=, __gmp_binary_divides)
+__GMPZ_DEFINE_COMPOUND_OPERATOR(operator%=, __gmp_binary_modulus)
+
+__GMPZ_DEFINE_COMPOUND_OPERATOR(operator&=, __gmp_binary_and)
+__GMPZ_DEFINE_COMPOUND_OPERATOR(operator|=, __gmp_binary_ior)
+__GMPZ_DEFINE_COMPOUND_OPERATOR(operator^=, __gmp_binary_xor)
+
+__GMPZ_DEFINE_COMPOUND_OPERATOR_UI(operator<<=, __gmp_binary_lshift)
+__GMPZ_DEFINE_COMPOUND_OPERATOR_UI(operator>>=, __gmp_binary_rshift)
+
+__GMPZ_DEFINE_INCREMENT_OPERATOR(operator++, __gmp_unary_increment)
+__GMPZ_DEFINE_INCREMENT_OPERATOR(operator--, __gmp_unary_decrement)
+
+__GMP_DEFINE_UNARY_STATIC_MEMFUN(mpz_t, mpz_class::factorial, __gmp_fac_function)
+__GMP_DEFINE_UNARY_STATIC_MEMFUN(mpz_t, mpz_class::primorial, __gmp_primorial_function)
+__GMP_DEFINE_UNARY_STATIC_MEMFUN(mpz_t, mpz_class::fibonacci, __gmp_fib_function)
+
+// member operators for mpq_class
+
+__GMPQ_DEFINE_COMPOUND_OPERATOR(operator+=, __gmp_binary_plus)
+__GMPQ_DEFINE_COMPOUND_OPERATOR(operator-=, __gmp_binary_minus)
+__GMPQ_DEFINE_COMPOUND_OPERATOR(operator*=, __gmp_binary_multiplies)
+__GMPQ_DEFINE_COMPOUND_OPERATOR(operator/=, __gmp_binary_divides)
+
+__GMPQ_DEFINE_COMPOUND_OPERATOR_UI(operator<<=, __gmp_binary_lshift)
+__GMPQ_DEFINE_COMPOUND_OPERATOR_UI(operator>>=, __gmp_binary_rshift)
+
+__GMPQ_DEFINE_INCREMENT_OPERATOR(operator++, __gmp_unary_increment)
+__GMPQ_DEFINE_INCREMENT_OPERATOR(operator--, __gmp_unary_decrement)
+
+// member operators for mpf_class
+
+__GMPF_DEFINE_COMPOUND_OPERATOR(operator+=, __gmp_binary_plus)
+__GMPF_DEFINE_COMPOUND_OPERATOR(operator-=, __gmp_binary_minus)
+__GMPF_DEFINE_COMPOUND_OPERATOR(operator*=, __gmp_binary_multiplies)
+__GMPF_DEFINE_COMPOUND_OPERATOR(operator/=, __gmp_binary_divides)
+
+__GMPF_DEFINE_COMPOUND_OPERATOR_UI(operator<<=, __gmp_binary_lshift)
+__GMPF_DEFINE_COMPOUND_OPERATOR_UI(operator>>=, __gmp_binary_rshift)
+
+__GMPF_DEFINE_INCREMENT_OPERATOR(operator++, __gmp_unary_increment)
+__GMPF_DEFINE_INCREMENT_OPERATOR(operator--, __gmp_unary_decrement)
+
+
+
+/**************** Class wrapper for gmp_randstate_t ****************/
+
+class __gmp_urandomb_value { };
+class __gmp_urandomm_value { };
+
+template <>
+class __gmp_expr<mpz_t, __gmp_urandomb_value>
+{
+private:
+  __gmp_randstate_struct *state;
+  mp_bitcnt_t bits;
+public:
+  __gmp_expr(gmp_randstate_t s, mp_bitcnt_t l) : state(s), bits(l) { }
+  void eval(mpz_ptr z) const { __gmp_rand_function::eval(z, state, bits); }
+  mp_bitcnt_t get_prec() const { return mpf_get_default_prec(); }
+};
+
+template <>
+class __gmp_expr<mpz_t, __gmp_urandomm_value>
+{
+private:
+  __gmp_randstate_struct *state;
+  mpz_class range;
+public:
+  __gmp_expr(gmp_randstate_t s, const mpz_class &z) : state(s), range(z) { }
+  void eval(mpz_ptr z) const
+  { __gmp_rand_function::eval(z, state, range.get_mpz_t()); }
+  mp_bitcnt_t get_prec() const { return mpf_get_default_prec(); }
+};
+
+template <>
+class __gmp_expr<mpf_t, __gmp_urandomb_value>
+{
+private:
+  __gmp_randstate_struct *state;
+  mp_bitcnt_t bits;
+public:
+  __gmp_expr(gmp_randstate_t s, mp_bitcnt_t l) : state(s), bits(l) { }
+  void eval(mpf_ptr f) const
+  {
+    __gmp_rand_function::eval(f, state,
+	(bits>0) ? bits : mpf_get_prec(f));
+  }
+  mp_bitcnt_t get_prec() const
+  {
+    if (bits == 0)
+      return mpf_get_default_prec();
+    else
+      return bits;
+  }
+};
+
+extern "C" {
+  typedef void __gmp_randinit_default_t (gmp_randstate_t);
+  typedef void __gmp_randinit_lc_2exp_t (gmp_randstate_t, mpz_srcptr, unsigned long int, mp_bitcnt_t);
+  typedef int __gmp_randinit_lc_2exp_size_t (gmp_randstate_t, mp_bitcnt_t);
+}
+
+class gmp_randclass
+{
+private:
+  gmp_randstate_t state;
+
+  // copy construction and assignment not allowed
+  gmp_randclass(const gmp_randclass &);
+  void operator=(const gmp_randclass &);
+public:
+  // constructors and destructor
+  gmp_randclass(gmp_randalg_t alg, unsigned long int size)
+  {
+    switch (alg)
+      {
+      case GMP_RAND_ALG_LC: // no other cases for now
+      default:
+	gmp_randinit(state, alg, size);
+	break;
+      }
+  }
+
+  // gmp_randinit_default
+  gmp_randclass(__gmp_randinit_default_t* f) { f(state); }
+
+  // gmp_randinit_lc_2exp
+  gmp_randclass(__gmp_randinit_lc_2exp_t* f,
+		mpz_class z, unsigned long int l1, mp_bitcnt_t l2)
+  { f(state, z.get_mpz_t(), l1, l2); }
+
+  // gmp_randinit_lc_2exp_size
+  gmp_randclass(__gmp_randinit_lc_2exp_size_t* f,
+		mp_bitcnt_t size)
+  {
+    if (f (state, size) == 0)
+      throw std::length_error ("gmp_randinit_lc_2exp_size");
+  }
+
+  ~gmp_randclass() { gmp_randclear(state); }
+
+  // initialize
+  void seed(); // choose a random seed some way (?)
+  void seed(unsigned long int s) { gmp_randseed_ui(state, s); }
+  void seed(const mpz_class &z) { gmp_randseed(state, z.get_mpz_t()); }
+
+  // get random number
+  __gmp_expr<mpz_t, __gmp_urandomb_value> get_z_bits(mp_bitcnt_t l)
+  { return __gmp_expr<mpz_t, __gmp_urandomb_value>(state, l); }
+  __gmp_expr<mpz_t, __gmp_urandomb_value> get_z_bits(const mpz_class &z)
+  { return get_z_bits(z.get_ui()); }
+  // FIXME: z.get_bitcnt_t() ?
+
+  __gmp_expr<mpz_t, __gmp_urandomm_value> get_z_range(const mpz_class &z)
+  { return __gmp_expr<mpz_t, __gmp_urandomm_value>(state, z); }
+
+  __gmp_expr<mpf_t, __gmp_urandomb_value> get_f(mp_bitcnt_t prec = 0)
+  { return __gmp_expr<mpf_t, __gmp_urandomb_value>(state, prec); }
+};
+
+
+/**************** Specialize std::numeric_limits ****************/
+
+namespace std {
+  template <> class numeric_limits<mpz_class>
+  {
+  public:
+    static const bool is_specialized = true;
+    static mpz_class min() { return mpz_class(); }
+    static mpz_class max() { return mpz_class(); }
+    static mpz_class lowest() { return mpz_class(); }
+    static const int digits = 0;
+    static const int digits10 = 0;
+    static const int max_digits10 = 0;
+    static const bool is_signed = true;
+    static const bool is_integer = true;
+    static const bool is_exact = true;
+    static const int radix = 2;
+    static mpz_class epsilon() { return mpz_class(); }
+    static mpz_class round_error() { return mpz_class(); }
+    static const int min_exponent = 0;
+    static const int min_exponent10 = 0;
+    static const int max_exponent = 0;
+    static const int max_exponent10 = 0;
+    static const bool has_infinity = false;
+    static const bool has_quiet_NaN = false;
+    static const bool has_signaling_NaN = false;
+    static const float_denorm_style has_denorm = denorm_absent;
+    static const bool has_denorm_loss = false;
+    static mpz_class infinity() { return mpz_class(); }
+    static mpz_class quiet_NaN() { return mpz_class(); }
+    static mpz_class signaling_NaN() { return mpz_class(); }
+    static mpz_class denorm_min() { return mpz_class(); }
+    static const bool is_iec559 = false;
+    static const bool is_bounded = false;
+    static const bool is_modulo = false;
+    static const bool traps = false;
+    static const bool tinyness_before = false;
+    static const float_round_style round_style = round_toward_zero;
+  };
+
+  template <> class numeric_limits<mpq_class>
+  {
+  public:
+    static const bool is_specialized = true;
+    static mpq_class min() { return mpq_class(); }
+    static mpq_class max() { return mpq_class(); }
+    static mpq_class lowest() { return mpq_class(); }
+    static const int digits = 0;
+    static const int digits10 = 0;
+    static const int max_digits10 = 0;
+    static const bool is_signed = true;
+    static const bool is_integer = false;
+    static const bool is_exact = true;
+    static const int radix = 2;
+    static mpq_class epsilon() { return mpq_class(); }
+    static mpq_class round_error() { return mpq_class(); }
+    static const int min_exponent = 0;
+    static const int min_exponent10 = 0;
+    static const int max_exponent = 0;
+    static const int max_exponent10 = 0;
+    static const bool has_infinity = false;
+    static const bool has_quiet_NaN = false;
+    static const bool has_signaling_NaN = false;
+    static const float_denorm_style has_denorm = denorm_absent;
+    static const bool has_denorm_loss = false;
+    static mpq_class infinity() { return mpq_class(); }
+    static mpq_class quiet_NaN() { return mpq_class(); }
+    static mpq_class signaling_NaN() { return mpq_class(); }
+    static mpq_class denorm_min() { return mpq_class(); }
+    static const bool is_iec559 = false;
+    static const bool is_bounded = false;
+    static const bool is_modulo = false;
+    static const bool traps = false;
+    static const bool tinyness_before = false;
+    static const float_round_style round_style = round_toward_zero;
+  };
+
+  template <> class numeric_limits<mpf_class>
+  {
+  public:
+    static const bool is_specialized = true;
+    static mpf_class min() { return mpf_class(); }
+    static mpf_class max() { return mpf_class(); }
+    static mpf_class lowest() { return mpf_class(); }
+    static const int digits = 0;
+    static const int digits10 = 0;
+    static const int max_digits10 = 0;
+    static const bool is_signed = true;
+    static const bool is_integer = false;
+    static const bool is_exact = false;
+    static const int radix = 2;
+    static mpf_class epsilon() { return mpf_class(); }
+    static mpf_class round_error() { return mpf_class(); }
+    static const int min_exponent = 0;
+    static const int min_exponent10 = 0;
+    static const int max_exponent = 0;
+    static const int max_exponent10 = 0;
+    static const bool has_infinity = false;
+    static const bool has_quiet_NaN = false;
+    static const bool has_signaling_NaN = false;
+    static const float_denorm_style has_denorm = denorm_absent;
+    static const bool has_denorm_loss = false;
+    static mpf_class infinity() { return mpf_class(); }
+    static mpf_class quiet_NaN() { return mpf_class(); }
+    static mpf_class signaling_NaN() { return mpf_class(); }
+    static mpf_class denorm_min() { return mpf_class(); }
+    static const bool is_iec559 = false;
+    static const bool is_bounded = false;
+    static const bool is_modulo = false;
+    static const bool traps = false;
+    static const bool tinyness_before = false;
+    static const float_round_style round_style = round_indeterminate;
+  };
+}
+
+
+/**************** #undef all private macros ****************/
+
+#undef __GMPP_DECLARE_COMPOUND_OPERATOR
+#undef __GMPN_DECLARE_COMPOUND_OPERATOR
+#undef __GMP_DECLARE_COMPOUND_OPERATOR
+#undef __GMP_DECLARE_COMPOUND_OPERATOR_UI
+#undef __GMP_DECLARE_INCREMENT_OPERATOR
+#undef __GMPXX_DEFINE_ARITHMETIC_CONSTRUCTORS
+#undef __GMPXX_DEFINE_ARITHMETIC_ASSIGNMENTS
+
+#undef __GMPZQ_DEFINE_EXPR
+
+#undef __GMP_DEFINE_UNARY_FUNCTION_1
+#undef __GMP_DEFINE_UNARY_FUNCTION
+#undef __GMP_DEFINE_UNARY_TYPE_FUNCTION
+
+#undef __GMPP_DEFINE_BINARY_FUNCTION
+#undef __GMPNN_DEFINE_BINARY_FUNCTION
+#undef __GMPNS_DEFINE_BINARY_FUNCTION
+#undef __GMPNU_DEFINE_BINARY_FUNCTION
+#undef __GMPND_DEFINE_BINARY_FUNCTION
+#undef __GMPNLD_DEFINE_BINARY_FUNCTION
+#undef __GMPN_DEFINE_BINARY_FUNCTION
+#undef __GMP_DEFINE_BINARY_FUNCTION
+
+#undef __GMP_DEFINE_BINARY_FUNCTION_UI
+
+#undef __GMPP_DEFINE_BINARY_TYPE_FUNCTION
+#undef __GMPNN_DEFINE_BINARY_TYPE_FUNCTION
+#undef __GMPNS_DEFINE_BINARY_TYPE_FUNCTION
+#undef __GMPNU_DEFINE_BINARY_TYPE_FUNCTION
+#undef __GMPND_DEFINE_BINARY_TYPE_FUNCTION
+#undef __GMPNLD_DEFINE_BINARY_TYPE_FUNCTION
+#undef __GMPN_DEFINE_BINARY_TYPE_FUNCTION
+#undef __GMP_DEFINE_BINARY_TYPE_FUNCTION
+
+#undef __GMPZ_DEFINE_COMPOUND_OPERATOR
+
+#undef __GMPP_DEFINE_COMPOUND_OPERATOR
+#undef __GMPNN_DEFINE_COMPOUND_OPERATOR
+#undef __GMPNS_DEFINE_COMPOUND_OPERATOR
+#undef __GMPNU_DEFINE_COMPOUND_OPERATOR
+#undef __GMPND_DEFINE_COMPOUND_OPERATOR
+#undef __GMPNLD_DEFINE_COMPOUND_OPERATOR
+#undef __GMPN_DEFINE_COMPOUND_OPERATOR
+#undef __GMP_DEFINE_COMPOUND_OPERATOR
+
+#undef __GMPQ_DEFINE_COMPOUND_OPERATOR
+#undef __GMPF_DEFINE_COMPOUND_OPERATOR
+
+#undef __GMP_DEFINE_COMPOUND_OPERATOR_UI
+#undef __GMPZ_DEFINE_COMPOUND_OPERATOR_UI
+#undef __GMPQ_DEFINE_COMPOUND_OPERATOR_UI
+#undef __GMPF_DEFINE_COMPOUND_OPERATOR_UI
+
+#undef __GMP_DEFINE_INCREMENT_OPERATOR
+#undef __GMPZ_DEFINE_INCREMENT_OPERATOR
+#undef __GMPQ_DEFINE_INCREMENT_OPERATOR
+#undef __GMPF_DEFINE_INCREMENT_OPERATOR
+
+#undef __GMPXX_CONSTANT_TRUE
+#undef __GMPXX_CONSTANT
+
+#endif /* __GMP_PLUSPLUS__ */
diff --git a/third_party/gmp/gmpxx.pc.in b/third_party/gmp/gmpxx.pc.in
new file mode 100644
index 0000000..181cc70
--- /dev/null
+++ b/third_party/gmp/gmpxx.pc.in
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+includedir=@includedir@
+libdir=@libdir@
+
+Name: @PACKAGE_NAME@ C++
+Description: GNU Multiple Precision Arithmetic Library (C++ bindings)
+URL: https://gmplib.org
+Version: @PACKAGE_VERSION@
+Requires: gmp
+Cflags: -I${includedir}
+Libs: -L${libdir} -lgmpxx
diff --git a/third_party/gmp/install-sh b/third_party/gmp/install-sh
new file mode 100755
index 0000000..0b0fdcb
--- /dev/null
+++ b/third_party/gmp/install-sh
@@ -0,0 +1,501 @@
+#!/bin/sh
+# install - install a program, script, or datafile
+
+scriptversion=2013-12-25.23; # UTC
+
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
+#
+#
+# FSF changes to this file are in the public domain.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# 'make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+
+tab='	'
+nl='
+'
+IFS=" $tab$nl"
+
+# Set DOITPROG to "echo" to test this script.
+
+doit=${DOITPROG-}
+doit_exec=${doit:-exec}
+
+# Put in absolute file names if you don't have them in your path;
+# or use environment vars.
+
+chgrpprog=${CHGRPPROG-chgrp}
+chmodprog=${CHMODPROG-chmod}
+chownprog=${CHOWNPROG-chown}
+cmpprog=${CMPPROG-cmp}
+cpprog=${CPPROG-cp}
+mkdirprog=${MKDIRPROG-mkdir}
+mvprog=${MVPROG-mv}
+rmprog=${RMPROG-rm}
+stripprog=${STRIPPROG-strip}
+
+posix_mkdir=
+
+# Desired mode of installed file.
+mode=0755
+
+chgrpcmd=
+chmodcmd=$chmodprog
+chowncmd=
+mvcmd=$mvprog
+rmcmd="$rmprog -f"
+stripcmd=
+
+src=
+dst=
+dir_arg=
+dst_arg=
+
+copy_on_change=false
+is_target_a_directory=possibly
+
+usage="\
+Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
+   or: $0 [OPTION]... SRCFILES... DIRECTORY
+   or: $0 [OPTION]... -t DIRECTORY SRCFILES...
+   or: $0 [OPTION]... -d DIRECTORIES...
+
+In the 1st form, copy SRCFILE to DSTFILE.
+In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
+In the 4th, create DIRECTORIES.
+
+Options:
+     --help     display this help and exit.
+     --version  display version info and exit.
+
+  -c            (ignored)
+  -C            install only if different (preserve the last data modification time)
+  -d            create directories instead of installing files.
+  -g GROUP      $chgrpprog installed files to GROUP.
+  -m MODE       $chmodprog installed files to MODE.
+  -o USER       $chownprog installed files to USER.
+  -s            $stripprog installed files.
+  -t DIRECTORY  install into DIRECTORY.
+  -T            report an error if DSTFILE is a directory.
+
+Environment variables override the default commands:
+  CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
+  RMPROG STRIPPROG
+"
+
+while test $# -ne 0; do
+  case $1 in
+    -c) ;;
+
+    -C) copy_on_change=true;;
+
+    -d) dir_arg=true;;
+
+    -g) chgrpcmd="$chgrpprog $2"
+        shift;;
+
+    --help) echo "$usage"; exit $?;;
+
+    -m) mode=$2
+        case $mode in
+          *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
+            echo "$0: invalid mode: $mode" >&2
+            exit 1;;
+        esac
+        shift;;
+
+    -o) chowncmd="$chownprog $2"
+        shift;;
+
+    -s) stripcmd=$stripprog;;
+
+    -t)
+        is_target_a_directory=always
+        dst_arg=$2
+        # Protect names problematic for 'test' and other utilities.
+        case $dst_arg in
+          -* | [=\(\)!]) dst_arg=./$dst_arg;;
+        esac
+        shift;;
+
+    -T) is_target_a_directory=never;;
+
+    --version) echo "$0 $scriptversion"; exit $?;;
+
+    --) shift
+        break;;
+
+    -*) echo "$0: invalid option: $1" >&2
+        exit 1;;
+
+    *)  break;;
+  esac
+  shift
+done
+
+# We allow the use of options -d and -T together, by making -d
+# take the precedence; this is for compatibility with GNU install.
+
+if test -n "$dir_arg"; then
+  if test -n "$dst_arg"; then
+    echo "$0: target directory not allowed when installing a directory." >&2
+    exit 1
+  fi
+fi
+
+if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
+  # When -d is used, all remaining arguments are directories to create.
+  # When -t is used, the destination is already specified.
+  # Otherwise, the last argument is the destination.  Remove it from $@.
+  for arg
+  do
+    if test -n "$dst_arg"; then
+      # $@ is not empty: it contains at least $arg.
+      set fnord "$@" "$dst_arg"
+      shift # fnord
+    fi
+    shift # arg
+    dst_arg=$arg
+    # Protect names problematic for 'test' and other utilities.
+    case $dst_arg in
+      -* | [=\(\)!]) dst_arg=./$dst_arg;;
+    esac
+  done
+fi
+
+if test $# -eq 0; then
+  if test -z "$dir_arg"; then
+    echo "$0: no input file specified." >&2
+    exit 1
+  fi
+  # It's OK to call 'install-sh -d' without argument.
+  # This can happen when creating conditional directories.
+  exit 0
+fi
+
+if test -z "$dir_arg"; then
+  if test $# -gt 1 || test "$is_target_a_directory" = always; then
+    if test ! -d "$dst_arg"; then
+      echo "$0: $dst_arg: Is not a directory." >&2
+      exit 1
+    fi
+  fi
+fi
+
+if test -z "$dir_arg"; then
+  do_exit='(exit $ret); exit $ret'
+  trap "ret=129; $do_exit" 1
+  trap "ret=130; $do_exit" 2
+  trap "ret=141; $do_exit" 13
+  trap "ret=143; $do_exit" 15
+
+  # Set umask so as not to create temps with too-generous modes.
+  # However, 'strip' requires both read and write access to temps.
+  case $mode in
+    # Optimize common cases.
+    *644) cp_umask=133;;
+    *755) cp_umask=22;;
+
+    *[0-7])
+      if test -z "$stripcmd"; then
+        u_plus_rw=
+      else
+        u_plus_rw='% 200'
+      fi
+      cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
+    *)
+      if test -z "$stripcmd"; then
+        u_plus_rw=
+      else
+        u_plus_rw=,u+rw
+      fi
+      cp_umask=$mode$u_plus_rw;;
+  esac
+fi
+
+for src
+do
+  # Protect names problematic for 'test' and other utilities.
+  case $src in
+    -* | [=\(\)!]) src=./$src;;
+  esac
+
+  if test -n "$dir_arg"; then
+    dst=$src
+    dstdir=$dst
+    test -d "$dstdir"
+    dstdir_status=$?
+  else
+
+    # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
+    # might cause directories to be created, which would be especially bad
+    # if $src (and thus $dsttmp) contains '*'.
+    if test ! -f "$src" && test ! -d "$src"; then
+      echo "$0: $src does not exist." >&2
+      exit 1
+    fi
+
+    if test -z "$dst_arg"; then
+      echo "$0: no destination specified." >&2
+      exit 1
+    fi
+    dst=$dst_arg
+
+    # If destination is a directory, append the input filename; won't work
+    # if double slashes aren't ignored.
+    if test -d "$dst"; then
+      if test "$is_target_a_directory" = never; then
+        echo "$0: $dst_arg: Is a directory" >&2
+        exit 1
+      fi
+      dstdir=$dst
+      dst=$dstdir/`basename "$src"`
+      dstdir_status=0
+    else
+      dstdir=`dirname "$dst"`
+      test -d "$dstdir"
+      dstdir_status=$?
+    fi
+  fi
+
+  obsolete_mkdir_used=false
+
+  if test $dstdir_status != 0; then
+    case $posix_mkdir in
+      '')
+        # Create intermediate dirs using mode 755 as modified by the umask.
+        # This is like FreeBSD 'install' as of 1997-10-28.
+        umask=`umask`
+        case $stripcmd.$umask in
+          # Optimize common cases.
+          *[2367][2367]) mkdir_umask=$umask;;
+          .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
+
+          *[0-7])
+            mkdir_umask=`expr $umask + 22 \
+              - $umask % 100 % 40 + $umask % 20 \
+              - $umask % 10 % 4 + $umask % 2
+            `;;
+          *) mkdir_umask=$umask,go-w;;
+        esac
+
+        # With -d, create the new directory with the user-specified mode.
+        # Otherwise, rely on $mkdir_umask.
+        if test -n "$dir_arg"; then
+          mkdir_mode=-m$mode
+        else
+          mkdir_mode=
+        fi
+
+        posix_mkdir=false
+        case $umask in
+          *[123567][0-7][0-7])
+            # POSIX mkdir -p sets u+wx bits regardless of umask, which
+            # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
+            ;;
+          *)
+            tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
+            trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
+
+            if (umask $mkdir_umask &&
+                exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
+            then
+              if test -z "$dir_arg" || {
+                   # Check for POSIX incompatibilities with -m.
+                   # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
+                   # other-writable bit of parent directory when it shouldn't.
+                   # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
+                   ls_ld_tmpdir=`ls -ld "$tmpdir"`
+                   case $ls_ld_tmpdir in
+                     d????-?r-*) different_mode=700;;
+                     d????-?--*) different_mode=755;;
+                     *) false;;
+                   esac &&
+                   $mkdirprog -m$different_mode -p -- "$tmpdir" && {
+                     ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
+                     test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
+                   }
+                 }
+              then posix_mkdir=:
+              fi
+              rmdir "$tmpdir/d" "$tmpdir"
+            else
+              # Remove any dirs left behind by ancient mkdir implementations.
+              rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
+            fi
+            trap '' 0;;
+        esac;;
+    esac
+
+    if
+      $posix_mkdir && (
+        umask $mkdir_umask &&
+        $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
+      )
+    then :
+    else
+
+      # The umask is ridiculous, or mkdir does not conform to POSIX,
+      # or it failed possibly due to a race condition.  Create the
+      # directory the slow way, step by step, checking for races as we go.
+
+      case $dstdir in
+        /*) prefix='/';;
+        [-=\(\)!]*) prefix='./';;
+        *)  prefix='';;
+      esac
+
+      oIFS=$IFS
+      IFS=/
+      set -f
+      set fnord $dstdir
+      shift
+      set +f
+      IFS=$oIFS
+
+      prefixes=
+
+      for d
+      do
+        test X"$d" = X && continue
+
+        prefix=$prefix$d
+        if test -d "$prefix"; then
+          prefixes=
+        else
+          if $posix_mkdir; then
+            (umask=$mkdir_umask &&
+             $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
+            # Don't fail if two instances are running concurrently.
+            test -d "$prefix" || exit 1
+          else
+            case $prefix in
+              *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
+              *) qprefix=$prefix;;
+            esac
+            prefixes="$prefixes '$qprefix'"
+          fi
+        fi
+        prefix=$prefix/
+      done
+
+      if test -n "$prefixes"; then
+        # Don't fail if two instances are running concurrently.
+        (umask $mkdir_umask &&
+         eval "\$doit_exec \$mkdirprog $prefixes") ||
+          test -d "$dstdir" || exit 1
+        obsolete_mkdir_used=true
+      fi
+    fi
+  fi
+
+  if test -n "$dir_arg"; then
+    { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
+    { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
+    { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
+      test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
+  else
+
+    # Make a couple of temp file names in the proper directory.
+    dsttmp=$dstdir/_inst.$$_
+    rmtmp=$dstdir/_rm.$$_
+
+    # Trap to clean up those temp files at exit.
+    trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
+
+    # Copy the file name to the temp name.
+    (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
+
+    # and set any options; do chmod last to preserve setuid bits.
+    #
+    # If any of these fail, we abort the whole thing.  If we want to
+    # ignore errors from any of these, just make sure not to ignore
+    # errors from the above "$doit $cpprog $src $dsttmp" command.
+    #
+    { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
+    { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
+    { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
+    { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
+
+    # If -C, don't bother to copy if it wouldn't change the file.
+    if $copy_on_change &&
+       old=`LC_ALL=C ls -dlL "$dst"     2>/dev/null` &&
+       new=`LC_ALL=C ls -dlL "$dsttmp"  2>/dev/null` &&
+       set -f &&
+       set X $old && old=:$2:$4:$5:$6 &&
+       set X $new && new=:$2:$4:$5:$6 &&
+       set +f &&
+       test "$old" = "$new" &&
+       $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
+    then
+      rm -f "$dsttmp"
+    else
+      # Rename the file to the real destination.
+      $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
+
+      # The rename failed, perhaps because mv can't rename something else
+      # to itself, or perhaps because mv is so ancient that it does not
+      # support -f.
+      {
+        # Now remove or move aside any old file at destination location.
+        # We try this two ways since rm can't unlink itself on some
+        # systems and the destination file might be busy for other
+        # reasons.  In this case, the final cleanup might fail but the new
+        # file should still install successfully.
+        {
+          test ! -f "$dst" ||
+          $doit $rmcmd -f "$dst" 2>/dev/null ||
+          { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
+            { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
+          } ||
+          { echo "$0: cannot unlink or rename $dst" >&2
+            (exit 1); exit 1
+          }
+        } &&
+
+        # Now rename the file to the real destination.
+        $doit $mvcmd "$dsttmp" "$dst"
+      }
+    fi || exit 1
+
+    trap '' 0
+  fi
+done
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/third_party/gmp/invalid.c b/third_party/gmp/invalid.c
new file mode 100644
index 0000000..e09eab2
--- /dev/null
+++ b/third_party/gmp/invalid.c
@@ -0,0 +1,82 @@
+/* __gmp_invalid_operation -- invalid floating point operation.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#include <signal.h>
+#include <stdlib.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>  /* for getpid */
+#endif
+
+#include "gmp-impl.h"
+
+
+/* Incidentally, kill is not available on mingw, but that's ok, it has raise
+   and we'll be using that.  */
+#if ! HAVE_RAISE
+#define raise(sig)   kill (getpid(), sig)
+#endif
+
+
+/* __gmp_invalid_operation is for an invalid floating point operation, like
+   mpz_set_d on a NaN or Inf.  It's done as a subroutine to minimize code in
+   places raising an exception.
+
+   feraiseexcept(FE_INVALID) is not used here, since unfortunately on most
+   systems it would require libm.
+
+   Alternatives:
+
+   It might be possible to check whether a hardware "invalid operation" trap
+   is enabled or not before raising a signal.  This would require all
+   callers to be prepared to continue with some bogus result.  Bogus returns
+   are bad, but presumably an application disabling the trap is prepared for
+   that.
+
+   On some systems (eg. BSD) the signal handler can find out the reason for
+   a SIGFPE (overflow, invalid, div-by-zero, etc).  Perhaps we could get
+   that into our raise too.
+
+   i386 GLIBC implements feraiseexcept(FE_INVALID) with an asm fdiv 0/0.
+   That would both respect the exceptions mask and give a reason code in a
+   BSD signal.  */
+
+void
+__gmp_invalid_operation (void)
+{
+  raise (SIGFPE);
+  abort ();
+}
diff --git a/third_party/gmp/longlong.h b/third_party/gmp/longlong.h
new file mode 100644
index 0000000..bc3fc81
--- /dev/null
+++ b/third_party/gmp/longlong.h
@@ -0,0 +1,2281 @@
+/* longlong.h -- definitions for mixed size 32/64 bit arithmetic.
+
+Copyright 1991-1994, 1996, 1997, 1999-2005, 2007-2009, 2011-2020 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+/* You have to define the following before including this file:
+
+   UWtype -- An unsigned type, default type for operations (typically a "word")
+   UHWtype -- An unsigned type, at least half the size of UWtype
+   UDWtype -- An unsigned type, at least twice as large a UWtype
+   W_TYPE_SIZE -- size in bits of UWtype
+
+   SItype, USItype -- Signed and unsigned 32 bit types
+   DItype, UDItype -- Signed and unsigned 64 bit types
+
+   On a 32 bit machine UWtype should typically be USItype;
+   on a 64 bit machine, UWtype should typically be UDItype.
+
+   Optionally, define:
+
+   LONGLONG_STANDALONE -- Avoid code that needs machine-dependent support files
+   NO_ASM -- Disable inline asm
+
+
+   CAUTION!  Using this version of longlong.h outside of GMP is not safe.  You
+   need to include gmp.h and gmp-impl.h, or certain things might not work as
+   expected.
+*/
+
+#define __BITS4 (W_TYPE_SIZE / 4)
+#define __ll_B ((UWtype) 1 << (W_TYPE_SIZE / 2))
+#define __ll_lowpart(t) ((UWtype) (t) & (__ll_B - 1))
+#define __ll_highpart(t) ((UWtype) (t) >> (W_TYPE_SIZE / 2))
+
+/* This is used to make sure no undesirable sharing between different libraries
+   that use this file takes place.  */
+#ifndef __MPN
+#define __MPN(x) __##x
+#endif
+
+/* Define auxiliary asm macros.
+
+   1) umul_ppmm(high_prod, low_prod, multiplier, multiplicand) multiplies two
+   UWtype integers MULTIPLIER and MULTIPLICAND, and generates a two UWtype
+   word product in HIGH_PROD and LOW_PROD.
+
+   2) __umulsidi3(a,b) multiplies two UWtype integers A and B, and returns a
+   UDWtype product.  This is just a variant of umul_ppmm.
+
+   3) udiv_qrnnd(quotient, remainder, high_numerator, low_numerator,
+   denominator) divides a UDWtype, composed by the UWtype integers
+   HIGH_NUMERATOR and LOW_NUMERATOR, by DENOMINATOR and places the quotient
+   in QUOTIENT and the remainder in REMAINDER.  HIGH_NUMERATOR must be less
+   than DENOMINATOR for correct operation.  If, in addition, the most
+   significant bit of DENOMINATOR must be 1, then the pre-processor symbol
+   UDIV_NEEDS_NORMALIZATION is defined to 1.
+
+   4) sdiv_qrnnd(quotient, remainder, high_numerator, low_numerator,
+   denominator).  Like udiv_qrnnd but the numbers are signed.  The quotient
+   is rounded towards 0.
+
+   5) count_leading_zeros(count, x) counts the number of zero-bits from the
+   msb to the first non-zero bit in the UWtype X.  This is the number of
+   steps X needs to be shifted left to set the msb.  Undefined for X == 0,
+   unless the symbol COUNT_LEADING_ZEROS_0 is defined to some value.
+
+   6) count_trailing_zeros(count, x) like count_leading_zeros, but counts
+   from the least significant end.
+
+   7) add_ssaaaa(high_sum, low_sum, high_addend_1, low_addend_1,
+   high_addend_2, low_addend_2) adds two UWtype integers, composed by
+   HIGH_ADDEND_1 and LOW_ADDEND_1, and HIGH_ADDEND_2 and LOW_ADDEND_2
+   respectively.  The result is placed in HIGH_SUM and LOW_SUM.  Overflow
+   (i.e. carry out) is not stored anywhere, and is lost.
+
+   8) sub_ddmmss(high_difference, low_difference, high_minuend, low_minuend,
+   high_subtrahend, low_subtrahend) subtracts two two-word UWtype integers,
+   composed by HIGH_MINUEND_1 and LOW_MINUEND_1, and HIGH_SUBTRAHEND_2 and
+   LOW_SUBTRAHEND_2 respectively.  The result is placed in HIGH_DIFFERENCE
+   and LOW_DIFFERENCE.  Overflow (i.e. carry out) is not stored anywhere,
+   and is lost.
+
+   If any of these macros are left undefined for a particular CPU,
+   C macros are used.
+
+
+   Notes:
+
+   For add_ssaaaa the two high and two low addends can both commute, but
+   unfortunately gcc only supports one "%" commutative in each asm block.
+   This has always been so but is only documented in recent versions
+   (eg. pre-release 3.3).  Having two or more "%"s can cause an internal
+   compiler error in certain rare circumstances.
+
+   Apparently it was only the last "%" that was ever actually respected, so
+   the code has been updated to leave just that.  Clearly there's a free
+   choice whether high or low should get it, if there's a reason to favour
+   one over the other.  Also obviously when the constraints on the two
+   operands are identical there's no benefit to the reloader in any "%" at
+   all.
+
+   */
+
+/* The CPUs come in alphabetical order below.
+
+   Please add support for more CPUs here, or improve the current support
+   for the CPUs below!  */
+
+
+/* count_leading_zeros_gcc_clz is count_leading_zeros implemented with gcc
+   3.4 __builtin_clzl or __builtin_clzll, according to our limb size.
+   Similarly count_trailing_zeros_gcc_ctz using __builtin_ctzl or
+   __builtin_ctzll.
+
+   These builtins are only used when we check what code comes out, on some
+   chips they're merely libgcc calls, where we will instead want an inline
+   in that case (either asm or generic C).
+
+   These builtins are better than an asm block of the same insn, since an
+   asm block doesn't give gcc any information about scheduling or resource
+   usage.  We keep an asm block for use on prior versions of gcc though.
+
+   For reference, __builtin_ffs existed in gcc prior to __builtin_clz, but
+   it's not used (for count_leading_zeros) because it generally gives extra
+   code to ensure the result is 0 when the input is 0, which we don't need
+   or want.  */
+
+#ifdef _LONG_LONG_LIMB
+#define count_leading_zeros_gcc_clz(count,x)	\
+  do {						\
+    ASSERT ((x) != 0);				\
+    (count) = __builtin_clzll (x);		\
+  } while (0)
+#else
+#define count_leading_zeros_gcc_clz(count,x)	\
+  do {						\
+    ASSERT ((x) != 0);				\
+    (count) = __builtin_clzl (x);		\
+  } while (0)
+#endif
+
+#ifdef _LONG_LONG_LIMB
+#define count_trailing_zeros_gcc_ctz(count,x)	\
+  do {						\
+    ASSERT ((x) != 0);				\
+    (count) = __builtin_ctzll (x);		\
+  } while (0)
+#else
+#define count_trailing_zeros_gcc_ctz(count,x)	\
+  do {						\
+    ASSERT ((x) != 0);				\
+    (count) = __builtin_ctzl (x);		\
+  } while (0)
+#endif
+
+
+/* FIXME: The macros using external routines like __MPN(count_leading_zeros)
+   don't need to be under !NO_ASM */
+#if ! defined (NO_ASM)
+
+#if defined (__alpha) && W_TYPE_SIZE == 64
+/* Most alpha-based machines, except Cray systems. */
+#if defined (__GNUC__)
+#if __GMP_GNUC_PREREQ (3,3)
+#define umul_ppmm(ph, pl, m0, m1) \
+  do {									\
+    UDItype __m0 = (m0), __m1 = (m1);					\
+    (ph) = __builtin_alpha_umulh (__m0, __m1);				\
+    (pl) = __m0 * __m1;							\
+  } while (0)
+#else
+#define umul_ppmm(ph, pl, m0, m1) \
+  do {									\
+    UDItype __m0 = (m0), __m1 = (m1);					\
+    __asm__ ("umulh %r1,%2,%0"						\
+	     : "=r" (ph)						\
+	     : "%rJ" (__m0), "rI" (__m1));				\
+    (pl) = __m0 * __m1;							\
+  } while (0)
+#endif
+#else /* ! __GNUC__ */
+#include <machine/builtins.h>
+#define umul_ppmm(ph, pl, m0, m1) \
+  do {									\
+    UDItype __m0 = (m0), __m1 = (m1);					\
+    (ph) = __UMULH (__m0, __m1);					\
+    (pl) = __m0 * __m1;							\
+  } while (0)
+#endif
+#ifndef LONGLONG_STANDALONE
+#define udiv_qrnnd(q, r, n1, n0, d) \
+  do { UWtype __di;							\
+    __di = __MPN(invert_limb) (d);					\
+    udiv_qrnnd_preinv (q, r, n1, n0, d, __di);				\
+  } while (0)
+#define UDIV_PREINV_ALWAYS  1
+#define UDIV_NEEDS_NORMALIZATION 1
+#endif /* LONGLONG_STANDALONE */
+
+/* clz_tab is required in all configurations, since mpn/alpha/cntlz.asm
+   always goes into libgmp.so, even when not actually used.  */
+#define COUNT_LEADING_ZEROS_NEED_CLZ_TAB
+
+#if defined (__GNUC__) && HAVE_HOST_CPU_alpha_CIX
+#define count_leading_zeros(COUNT,X) \
+  __asm__("ctlz %1,%0" : "=r"(COUNT) : "r"(X))
+#define count_trailing_zeros(COUNT,X) \
+  __asm__("cttz %1,%0" : "=r"(COUNT) : "r"(X))
+#endif /* clz/ctz using cix */
+
+#if ! defined (count_leading_zeros)				\
+  && defined (__GNUC__) && ! defined (LONGLONG_STANDALONE)
+/* ALPHA_CMPBGE_0 gives "cmpbge $31,src,dst", ie. test src bytes == 0.
+   "$31" is written explicitly in the asm, since an "r" constraint won't
+   select reg 31.  There seems no need to worry about "r31" syntax for cray,
+   since gcc itself (pre-release 3.4) emits just $31 in various places.	 */
+#define ALPHA_CMPBGE_0(dst, src)					\
+  do { asm ("cmpbge $31, %1, %0" : "=r" (dst) : "r" (src)); } while (0)
+/* Zero bytes are turned into bits with cmpbge, a __clz_tab lookup counts
+   them, locating the highest non-zero byte.  A second __clz_tab lookup
+   counts the leading zero bits in that byte, giving the result.  */
+#define count_leading_zeros(count, x)					\
+  do {									\
+    UWtype  __clz__b, __clz__c, __clz__x = (x);				\
+    ALPHA_CMPBGE_0 (__clz__b,  __clz__x);	    /* zero bytes */	\
+    __clz__b = __clz_tab [(__clz__b >> 1) ^ 0x7F];  /* 8 to 1 byte */	\
+    __clz__b = __clz__b * 8 - 7;		    /* 57 to 1 shift */ \
+    __clz__x >>= __clz__b;						\
+    __clz__c = __clz_tab [__clz__x];		    /* 8 to 1 bit */	\
+    __clz__b = 65 - __clz__b;						\
+    (count) = __clz__b - __clz__c;					\
+  } while (0)
+#define COUNT_LEADING_ZEROS_NEED_CLZ_TAB
+#endif /* clz using cmpbge */
+
+#if ! defined (count_leading_zeros) && ! defined (LONGLONG_STANDALONE)
+#if HAVE_ATTRIBUTE_CONST
+long __MPN(count_leading_zeros) (UDItype) __attribute__ ((const));
+#else
+long __MPN(count_leading_zeros) (UDItype);
+#endif
+#define count_leading_zeros(count, x) \
+  ((count) = __MPN(count_leading_zeros) (x))
+#endif /* clz using mpn */
+#endif /* __alpha */
+
+#if defined (__AVR) && W_TYPE_SIZE == 8
+#define umul_ppmm(ph, pl, m0, m1) \
+  do {									\
+    unsigned short __p = (unsigned short) (m0) * (m1);			\
+    (ph) = __p >> 8;							\
+    (pl) = __p;								\
+  } while (0)
+#endif /* AVR */
+
+#if defined (_CRAY) && W_TYPE_SIZE == 64
+#include <intrinsics.h>
+#define UDIV_PREINV_ALWAYS  1
+#define UDIV_NEEDS_NORMALIZATION 1
+long __MPN(count_leading_zeros) (UDItype);
+#define count_leading_zeros(count, x) \
+  ((count) = _leadz ((UWtype) (x)))
+#if defined (_CRAYIEEE)		/* I.e., Cray T90/ieee, T3D, and T3E */
+#define umul_ppmm(ph, pl, m0, m1) \
+  do {									\
+    UDItype __m0 = (m0), __m1 = (m1);					\
+    (ph) = _int_mult_upper (__m0, __m1);				\
+    (pl) = __m0 * __m1;							\
+  } while (0)
+#ifndef LONGLONG_STANDALONE
+#define udiv_qrnnd(q, r, n1, n0, d) \
+  do { UWtype __di;							\
+    __di = __MPN(invert_limb) (d);					\
+    udiv_qrnnd_preinv (q, r, n1, n0, d, __di);				\
+  } while (0)
+#endif /* LONGLONG_STANDALONE */
+#endif /* _CRAYIEEE */
+#endif /* _CRAY */
+
+#if defined (__ia64) && W_TYPE_SIZE == 64
+/* This form encourages gcc (pre-release 3.4 at least) to emit predicated
+   "sub r=r,r" and "sub r=r,r,1", giving a 2 cycle latency.  The generic
+   code using "al<bl" arithmetically comes out making an actual 0 or 1 in a
+   register, which takes an extra cycle.  */
+#define sub_ddmmss(sh, sl, ah, al, bh, bl)      \
+  do {						\
+    UWtype __x;					\
+    __x = (al) - (bl);				\
+    if ((al) < (bl))				\
+      (sh) = (ah) - (bh) - 1;			\
+    else					\
+      (sh) = (ah) - (bh);			\
+    (sl) = __x;					\
+  } while (0)
+#if defined (__GNUC__) && ! defined (__INTEL_COMPILER)
+/* Do both product parts in assembly, since that gives better code with
+   all gcc versions.  Some callers will just use the upper part, and in
+   that situation we waste an instruction, but not any cycles.  */
+#define umul_ppmm(ph, pl, m0, m1) \
+    __asm__ ("xma.hu %0 = %2, %3, f0\n\txma.l %1 = %2, %3, f0"		\
+	     : "=&f" (ph), "=f" (pl)					\
+	     : "f" (m0), "f" (m1))
+#define count_leading_zeros(count, x) \
+  do {									\
+    UWtype _x = (x), _y, _a, _c;					\
+    __asm__ ("mux1 %0 = %1, @rev" : "=r" (_y) : "r" (_x));		\
+    __asm__ ("czx1.l %0 = %1" : "=r" (_a) : "r" (-_y | _y));		\
+    _c = (_a - 1) << 3;							\
+    _x >>= _c;								\
+    if (_x >= 1 << 4)							\
+      _x >>= 4, _c += 4;						\
+    if (_x >= 1 << 2)							\
+      _x >>= 2, _c += 2;						\
+    _c += _x >> 1;							\
+    (count) =  W_TYPE_SIZE - 1 - _c;					\
+  } while (0)
+/* similar to what gcc does for __builtin_ffs, but 0 based rather than 1
+   based, and we don't need a special case for x==0 here */
+#define count_trailing_zeros(count, x)					\
+  do {									\
+    UWtype __ctz_x = (x);						\
+    __asm__ ("popcnt %0 = %1"						\
+	     : "=r" (count)						\
+	     : "r" ((__ctz_x-1) & ~__ctz_x));				\
+  } while (0)
+#endif
+#if defined (__INTEL_COMPILER)
+#include <ia64intrin.h>
+#define umul_ppmm(ph, pl, m0, m1)					\
+  do {									\
+    UWtype __m0 = (m0), __m1 = (m1);					\
+    ph = _m64_xmahu (__m0, __m1, 0);					\
+    pl = __m0 * __m1;							\
+  } while (0)
+#endif
+#ifndef LONGLONG_STANDALONE
+#define udiv_qrnnd(q, r, n1, n0, d) \
+  do { UWtype __di;							\
+    __di = __MPN(invert_limb) (d);					\
+    udiv_qrnnd_preinv (q, r, n1, n0, d, __di);				\
+  } while (0)
+#define UDIV_PREINV_ALWAYS  1
+#define UDIV_NEEDS_NORMALIZATION 1
+#endif
+#endif
+
+
+#if defined (__GNUC__)
+
+/* We sometimes need to clobber "cc" with gcc2, but that would not be
+   understood by gcc1.  Use cpp to avoid major code duplication.  */
+#if __GNUC__ < 2
+#define __CLOBBER_CC
+#define __AND_CLOBBER_CC
+#else /* __GNUC__ >= 2 */
+#define __CLOBBER_CC : "cc"
+#define __AND_CLOBBER_CC , "cc"
+#endif /* __GNUC__ < 2 */
+
+#if (defined (__a29k__) || defined (_AM29K)) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  __asm__ ("add %1,%4,%5\n\taddc %0,%2,%3"				\
+	   : "=r" (sh), "=&r" (sl)					\
+	   : "r" (ah), "rI" (bh), "%r" (al), "rI" (bl))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  __asm__ ("sub %1,%4,%5\n\tsubc %0,%2,%3"				\
+	   : "=r" (sh), "=&r" (sl)					\
+	   : "r" (ah), "rI" (bh), "r" (al), "rI" (bl))
+#define umul_ppmm(xh, xl, m0, m1) \
+  do {									\
+    USItype __m0 = (m0), __m1 = (m1);					\
+    __asm__ ("multiplu %0,%1,%2"					\
+	     : "=r" (xl)						\
+	     : "r" (__m0), "r" (__m1));					\
+    __asm__ ("multmu %0,%1,%2"						\
+	     : "=r" (xh)						\
+	     : "r" (__m0), "r" (__m1));					\
+  } while (0)
+#define udiv_qrnnd(q, r, n1, n0, d) \
+  __asm__ ("dividu %0,%3,%4"						\
+	   : "=r" (q), "=q" (r)						\
+	   : "1" (n1), "r" (n0), "r" (d))
+#define count_leading_zeros(count, x) \
+    __asm__ ("clz %0,%1"						\
+	     : "=r" (count)						\
+	     : "r" (x))
+#define COUNT_LEADING_ZEROS_0 32
+#endif /* __a29k__ */
+
+#if defined (__arc__)
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  __asm__ ("add.f\t%1, %4, %5\n\tadc\t%0, %2, %3"			\
+	   : "=r" (sh),							\
+	     "=&r" (sl)							\
+	   : "r"  ((USItype) (ah)),					\
+	     "rICal" ((USItype) (bh)),					\
+	     "%r" ((USItype) (al)),					\
+	     "rICal" ((USItype) (bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  __asm__ ("sub.f\t%1, %4, %5\n\tsbc\t%0, %2, %3"			\
+	   : "=r" (sh),							\
+	     "=&r" (sl)							\
+	   : "r" ((USItype) (ah)),					\
+	     "rICal" ((USItype) (bh)),					\
+	     "r" ((USItype) (al)),					\
+	     "rICal" ((USItype) (bl)))
+#endif
+
+#if defined (__arm__) && (defined (__thumb2__) || !defined (__thumb__)) \
+    && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  do {									\
+    if (__builtin_constant_p (bl) && -(USItype)(bl) < 0x100)		\
+      __asm__ ("subs\t%1, %4, %5\n\tadc\t%0, %2, %3"			\
+	   : "=r" (sh), "=&r" (sl)					\
+	       : "r" (ah), "rI" (bh),					\
+		 "%r" (al), "rI" (-(USItype)(bl)) __CLOBBER_CC);	\
+    else								\
+      __asm__ ("adds\t%1, %4, %5\n\tadc\t%0, %2, %3"			\
+	   : "=r" (sh), "=&r" (sl)					\
+	   : "r" (ah), "rI" (bh), "%r" (al), "rI" (bl) __CLOBBER_CC);	\
+  } while (0)
+/* FIXME: Extend the immediate range for the low word by using both ADDS and
+   SUBS, since they set carry in the same way.  Note: We need separate
+   definitions for thumb and non-thumb to to th absense of RSC under thumb.  */
+#if defined (__thumb__)
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  do {									\
+    if (__builtin_constant_p (ah) && __builtin_constant_p (bh)		\
+	&& (ah) == (bh))						\
+      __asm__ ("subs\t%1, %2, %3\n\tsbc\t%0, %0, %0"			\
+	       : "=r" (sh), "=r" (sl)					\
+	       : "r" (al), "rI" (bl) __CLOBBER_CC);			\
+    else if (__builtin_constant_p (al))					\
+      __asm__ ("rsbs\t%1, %5, %4\n\tsbc\t%0, %2, %3"			\
+	       : "=r" (sh), "=&r" (sl)					\
+	       : "r" (ah), "rI" (bh), "rI" (al), "r" (bl) __CLOBBER_CC); \
+    else if (__builtin_constant_p (bl))					\
+      __asm__ ("subs\t%1, %4, %5\n\tsbc\t%0, %2, %3"			\
+	       : "=r" (sh), "=&r" (sl)					\
+	       : "r" (ah), "rI" (bh), "r" (al), "rI" (bl) __CLOBBER_CC); \
+    else								\
+      __asm__ ("subs\t%1, %4, %5\n\tsbc\t%0, %2, %3"			\
+	       : "=r" (sh), "=&r" (sl)					\
+	       : "r" (ah), "rI" (bh), "r" (al), "rI" (bl) __CLOBBER_CC); \
+    } while (0)
+#else
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  do {									\
+    if (__builtin_constant_p (ah) && __builtin_constant_p (bh)		\
+	&& (ah) == (bh))						\
+      __asm__ ("subs\t%1, %2, %3\n\tsbc\t%0, %0, %0"			\
+	       : "=r" (sh), "=r" (sl)					\
+	       : "r" (al), "rI" (bl) __CLOBBER_CC);			\
+    else if (__builtin_constant_p (al))					\
+      {									\
+	if (__builtin_constant_p (ah))					\
+	  __asm__ ("rsbs\t%1, %5, %4\n\trsc\t%0, %3, %2"		\
+		   : "=r" (sh), "=&r" (sl)				\
+		   : "rI" (ah), "r" (bh), "rI" (al), "r" (bl) __CLOBBER_CC); \
+	else								\
+	  __asm__ ("rsbs\t%1, %5, %4\n\tsbc\t%0, %2, %3"		\
+		   : "=r" (sh), "=&r" (sl)				\
+		   : "r" (ah), "rI" (bh), "rI" (al), "r" (bl) __CLOBBER_CC); \
+      }									\
+    else if (__builtin_constant_p (ah))					\
+      {									\
+	if (__builtin_constant_p (bl))					\
+	  __asm__ ("subs\t%1, %4, %5\n\trsc\t%0, %3, %2"		\
+		   : "=r" (sh), "=&r" (sl)				\
+		   : "rI" (ah), "r" (bh), "r" (al), "rI" (bl) __CLOBBER_CC); \
+	else								\
+	  __asm__ ("rsbs\t%1, %5, %4\n\trsc\t%0, %3, %2"		\
+		   : "=r" (sh), "=&r" (sl)				\
+		   : "rI" (ah), "r" (bh), "rI" (al), "r" (bl) __CLOBBER_CC); \
+      }									\
+    else if (__builtin_constant_p (bl))					\
+      __asm__ ("subs\t%1, %4, %5\n\tsbc\t%0, %2, %3"			\
+	       : "=r" (sh), "=&r" (sl)					\
+	       : "r" (ah), "rI" (bh), "r" (al), "rI" (bl) __CLOBBER_CC); \
+    else /* only bh might be a constant */				\
+      __asm__ ("subs\t%1, %4, %5\n\tsbc\t%0, %2, %3"			\
+	       : "=r" (sh), "=&r" (sl)					\
+	       : "r" (ah), "rI" (bh), "r" (al), "rI" (bl) __CLOBBER_CC); \
+    } while (0)
+#endif
+#if defined (__ARM_ARCH_2__) || defined (__ARM_ARCH_2A__) \
+    || defined (__ARM_ARCH_3__)
+#define umul_ppmm(xh, xl, a, b)						\
+  do {									\
+    register USItype __t0, __t1, __t2;					\
+    __asm__ ("%@ Inlined umul_ppmm\n"					\
+	   "	mov	%2, %5, lsr #16\n"				\
+	   "	mov	%0, %6, lsr #16\n"				\
+	   "	bic	%3, %5, %2, lsl #16\n"				\
+	   "	bic	%4, %6, %0, lsl #16\n"				\
+	   "	mul	%1, %3, %4\n"					\
+	   "	mul	%4, %2, %4\n"					\
+	   "	mul	%3, %0, %3\n"					\
+	   "	mul	%0, %2, %0\n"					\
+	   "	adds	%3, %4, %3\n"					\
+	   "	addcs	%0, %0, #65536\n"				\
+	   "	adds	%1, %1, %3, lsl #16\n"				\
+	   "	adc	%0, %0, %3, lsr #16"				\
+	   : "=&r" ((USItype) (xh)), "=r" ((USItype) (xl)),		\
+	     "=&r" (__t0), "=&r" (__t1), "=r" (__t2)			\
+	   : "r" ((USItype) (a)), "r" ((USItype) (b)) __CLOBBER_CC);	\
+  } while (0)
+#ifndef LONGLONG_STANDALONE
+#define udiv_qrnnd(q, r, n1, n0, d) \
+  do { UWtype __r;							\
+    (q) = __MPN(udiv_qrnnd) (&__r, (n1), (n0), (d));			\
+    (r) = __r;								\
+  } while (0)
+extern UWtype __MPN(udiv_qrnnd) (UWtype *, UWtype, UWtype, UWtype);
+#endif /* LONGLONG_STANDALONE */
+#else /* ARMv4 or newer */
+#define umul_ppmm(xh, xl, a, b) \
+  __asm__ ("umull %0,%1,%2,%3" : "=&r" (xl), "=&r" (xh) : "r" (a), "r" (b))
+#define smul_ppmm(xh, xl, a, b) \
+  __asm__ ("smull %0,%1,%2,%3" : "=&r" (xl), "=&r" (xh) : "r" (a), "r" (b))
+#ifndef LONGLONG_STANDALONE
+#define udiv_qrnnd(q, r, n1, n0, d) \
+  do { UWtype __di;							\
+    __di = __MPN(invert_limb) (d);					\
+    udiv_qrnnd_preinv (q, r, n1, n0, d, __di);				\
+  } while (0)
+#define UDIV_PREINV_ALWAYS  1
+#define UDIV_NEEDS_NORMALIZATION 1
+#endif /* LONGLONG_STANDALONE */
+#endif /* defined(__ARM_ARCH_2__) ... */
+#define count_leading_zeros(count, x)  count_leading_zeros_gcc_clz(count, x)
+#define count_trailing_zeros(count, x)  count_trailing_zeros_gcc_ctz(count, x)
+#endif /* __arm__ */
+
+#if defined (__aarch64__) && W_TYPE_SIZE == 64
+/* FIXME: Extend the immediate range for the low word by using both
+   ADDS and SUBS, since they set carry in the same way.  */
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  do {									\
+    if (__builtin_constant_p (bl) && -(UDItype)(bl) < 0x1000)		\
+      __asm__ ("subs\t%1, %x4, %5\n\tadc\t%0, %x2, %x3"			\
+	       : "=r" (sh), "=&r" (sl)					\
+	       : "rZ" ((UDItype)(ah)), "rZ" ((UDItype)(bh)),		\
+		 "%r" ((UDItype)(al)), "rI" (-(UDItype)(bl)) __CLOBBER_CC);\
+    else								\
+      __asm__ ("adds\t%1, %x4, %5\n\tadc\t%0, %x2, %x3"			\
+	       : "=r" (sh), "=&r" (sl)					\
+	       : "rZ" ((UDItype)(ah)), "rZ" ((UDItype)(bh)),		\
+		 "%r" ((UDItype)(al)), "rI" ((UDItype)(bl)) __CLOBBER_CC);\
+  } while (0)
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  do {									\
+    if (__builtin_constant_p (bl) && -(UDItype)(bl) < 0x1000)		\
+      __asm__ ("adds\t%1, %x4, %5\n\tsbc\t%0, %x2, %x3"			\
+	       : "=r,r" (sh), "=&r,&r" (sl)				\
+	       : "rZ,rZ" ((UDItype)(ah)), "rZ,rZ" ((UDItype)(bh)),	\
+		 "r,Z"   ((UDItype)(al)), "rI,r" (-(UDItype)(bl)) __CLOBBER_CC);\
+    else								\
+      __asm__ ("subs\t%1, %x4, %5\n\tsbc\t%0, %x2, %x3"			\
+	       : "=r,r" (sh), "=&r,&r" (sl)				\
+	       : "rZ,rZ" ((UDItype)(ah)), "rZ,rZ" ((UDItype)(bh)),	\
+		 "r,Z"   ((UDItype)(al)), "rI,r"  ((UDItype)(bl)) __CLOBBER_CC);\
+  } while(0);
+#if __GMP_GNUC_PREREQ (4,9)
+#define umul_ppmm(w1, w0, u, v) \
+  do {									\
+    typedef unsigned int __ll_UTItype __attribute__((mode(TI)));	\
+    __ll_UTItype __ll = (__ll_UTItype)(u) * (v);			\
+    w1 = __ll >> 64;							\
+    w0 = __ll;								\
+  } while (0)
+#endif
+#if !defined (umul_ppmm)
+#define umul_ppmm(ph, pl, m0, m1) \
+  do {									\
+    UDItype __m0 = (m0), __m1 = (m1);					\
+    __asm__ ("umulh\t%0, %1, %2" : "=r" (ph) : "r" (__m0), "r" (__m1));	\
+    (pl) = __m0 * __m1;							\
+  } while (0)
+#endif
+#define count_leading_zeros(count, x)  count_leading_zeros_gcc_clz(count, x)
+#define count_trailing_zeros(count, x)  count_trailing_zeros_gcc_ctz(count, x)
+#endif /* __aarch64__ */
+
+#if defined (__clipper__) && W_TYPE_SIZE == 32
+#define umul_ppmm(w1, w0, u, v) \
+  ({union {UDItype __ll;						\
+	   struct {USItype __l, __h;} __i;				\
+	  } __x;							\
+  __asm__ ("mulwux %2,%0"						\
+	   : "=r" (__x.__ll)						\
+	   : "%0" ((USItype)(u)), "r" ((USItype)(v)));			\
+  (w1) = __x.__i.__h; (w0) = __x.__i.__l;})
+#define smul_ppmm(w1, w0, u, v) \
+  ({union {DItype __ll;							\
+	   struct {SItype __l, __h;} __i;				\
+	  } __x;							\
+  __asm__ ("mulwx %2,%0"						\
+	   : "=r" (__x.__ll)						\
+	   : "%0" ((SItype)(u)), "r" ((SItype)(v)));			\
+  (w1) = __x.__i.__h; (w0) = __x.__i.__l;})
+#define __umulsidi3(u, v) \
+  ({UDItype __w;							\
+    __asm__ ("mulwux %2,%0"						\
+	     : "=r" (__w) : "%0" ((USItype)(u)), "r" ((USItype)(v)));	\
+    __w; })
+#endif /* __clipper__ */
+
+/* Fujitsu vector computers.  */
+#if defined (__uxp__) && W_TYPE_SIZE == 32
+#define umul_ppmm(ph, pl, u, v) \
+  do {									\
+    union {UDItype __ll;						\
+	   struct {USItype __h, __l;} __i;				\
+	  } __x;							\
+    __asm__ ("mult.lu %1,%2,%0"	: "=r" (__x.__ll) : "%r" (u), "rK" (v));\
+    (ph) = __x.__i.__h;							\
+    (pl) = __x.__i.__l;							\
+  } while (0)
+#define smul_ppmm(ph, pl, u, v) \
+  do {									\
+    union {UDItype __ll;						\
+	   struct {USItype __h, __l;} __i;				\
+	  } __x;							\
+    __asm__ ("mult.l %1,%2,%0" : "=r" (__x.__ll) : "%r" (u), "rK" (v));	\
+    (ph) = __x.__i.__h;							\
+    (pl) = __x.__i.__l;							\
+  } while (0)
+#endif
+
+#if defined (__gmicro__) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  __asm__ ("add.w %5,%1\n\taddx %3,%0"					\
+	   : "=g" (sh), "=&g" (sl)					\
+	   : "0"  ((USItype)(ah)), "g" ((USItype)(bh)),			\
+	     "%1" ((USItype)(al)), "g" ((USItype)(bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  __asm__ ("sub.w %5,%1\n\tsubx %3,%0"					\
+	   : "=g" (sh), "=&g" (sl)					\
+	   : "0" ((USItype)(ah)), "g" ((USItype)(bh)),			\
+	     "1" ((USItype)(al)), "g" ((USItype)(bl)))
+#define umul_ppmm(ph, pl, m0, m1) \
+  __asm__ ("mulx %3,%0,%1"						\
+	   : "=g" (ph), "=r" (pl)					\
+	   : "%0" ((USItype)(m0)), "g" ((USItype)(m1)))
+#define udiv_qrnnd(q, r, nh, nl, d) \
+  __asm__ ("divx %4,%0,%1"						\
+	   : "=g" (q), "=r" (r)						\
+	   : "1" ((USItype)(nh)), "0" ((USItype)(nl)), "g" ((USItype)(d)))
+#define count_leading_zeros(count, x) \
+  __asm__ ("bsch/1 %1,%0"						\
+	   : "=g" (count) : "g" ((USItype)(x)), "0" ((USItype)0))
+#endif
+
+#if defined (__hppa) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  __asm__ ("add%I5 %5,%r4,%1\n\taddc %r2,%r3,%0"			\
+	   : "=r" (sh), "=&r" (sl)					\
+	   : "rM" (ah), "rM" (bh), "%rM" (al), "rI" (bl))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  __asm__ ("sub%I4 %4,%r5,%1\n\tsubb %r2,%r3,%0"			\
+	   : "=r" (sh), "=&r" (sl)					\
+	   : "rM" (ah), "rM" (bh), "rI" (al), "rM" (bl))
+#if defined (_PA_RISC1_1)
+#define umul_ppmm(wh, wl, u, v) \
+  do {									\
+    union {UDItype __ll;						\
+	   struct {USItype __h, __l;} __i;				\
+	  } __x;							\
+    __asm__ ("xmpyu %1,%2,%0" : "=*f" (__x.__ll) : "*f" (u), "*f" (v));	\
+    (wh) = __x.__i.__h;							\
+    (wl) = __x.__i.__l;							\
+  } while (0)
+#endif
+#define count_leading_zeros(count, x) \
+  do {									\
+    USItype __tmp;							\
+    __asm__ (								\
+       "ldi		1,%0\n"						\
+"	extru,=		%1,15,16,%%r0	; Bits 31..16 zero?\n"		\
+"	extru,tr	%1,15,16,%1	; No.  Shift down, skip add.\n"	\
+"	ldo		16(%0),%0	; Yes.  Perform add.\n"		\
+"	extru,=		%1,23,8,%%r0	; Bits 15..8 zero?\n"		\
+"	extru,tr	%1,23,8,%1	; No.  Shift down, skip add.\n"	\
+"	ldo		8(%0),%0	; Yes.  Perform add.\n"		\
+"	extru,=		%1,27,4,%%r0	; Bits 7..4 zero?\n"		\
+"	extru,tr	%1,27,4,%1	; No.  Shift down, skip add.\n"	\
+"	ldo		4(%0),%0	; Yes.  Perform add.\n"		\
+"	extru,=		%1,29,2,%%r0	; Bits 3..2 zero?\n"		\
+"	extru,tr	%1,29,2,%1	; No.  Shift down, skip add.\n"	\
+"	ldo		2(%0),%0	; Yes.  Perform add.\n"		\
+"	extru		%1,30,1,%1	; Extract bit 1.\n"		\
+"	sub		%0,%1,%0	; Subtract it.\n"		\
+	: "=r" (count), "=r" (__tmp) : "1" (x));			\
+  } while (0)
+#endif /* hppa */
+
+/* These macros are for ABI=2.0w.  In ABI=2.0n they can't be used, since GCC
+   (3.2) puts longlong into two adjacent 32-bit registers.  Presumably this
+   is just a case of no direct support for 2.0n but treating it like 1.0. */
+#if defined (__hppa) && W_TYPE_SIZE == 64 && ! defined (_LONG_LONG_LIMB)
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  __asm__ ("add%I5 %5,%r4,%1\n\tadd,dc %r2,%r3,%0"			\
+	   : "=r" (sh), "=&r" (sl)					\
+	   : "rM" (ah), "rM" (bh), "%rM" (al), "rI" (bl))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  __asm__ ("sub%I4 %4,%r5,%1\n\tsub,db %r2,%r3,%0"			\
+	   : "=r" (sh), "=&r" (sl)					\
+	   : "rM" (ah), "rM" (bh), "rI" (al), "rM" (bl))
+#endif /* hppa */
+
+#if (defined (__i370__) || defined (__s390__) || defined (__mvs__)) && W_TYPE_SIZE == 32
+#if defined (__zarch__) || defined (HAVE_HOST_CPU_s390_zarch)
+#define add_ssaaaa(sh, sl, ah, al, bh, bl)				\
+  do {									\
+/*  if (__builtin_constant_p (bl))					\
+      __asm__ ("alfi\t%1,%o5\n\talcr\t%0,%3"				\
+	       : "=r" (sh), "=&r" (sl)					\
+	       : "0"  (ah), "r" (bh), "%1" (al), "n" (bl) __CLOBBER_CC);\
+    else								\
+*/    __asm__ ("alr\t%1,%5\n\talcr\t%0,%3"				\
+	       : "=r" (sh), "=&r" (sl)					\
+	       : "0"  (ah), "r" (bh), "%1" (al), "r" (bl)__CLOBBER_CC);	\
+  } while (0)
+#define sub_ddmmss(sh, sl, ah, al, bh, bl)				\
+  do {									\
+/*  if (__builtin_constant_p (bl))					\
+      __asm__ ("slfi\t%1,%o5\n\tslbr\t%0,%3"				\
+	       : "=r" (sh), "=&r" (sl)					\
+	       : "0" (ah), "r" (bh), "1" (al), "n" (bl) __CLOBBER_CC);	\
+    else								\
+*/    __asm__ ("slr\t%1,%5\n\tslbr\t%0,%3"				\
+	       : "=r" (sh), "=&r" (sl)					\
+	       : "0" (ah), "r" (bh), "1" (al), "r" (bl) __CLOBBER_CC);	\
+  } while (0)
+#if __GMP_GNUC_PREREQ (4,5)
+#define umul_ppmm(xh, xl, m0, m1)					\
+  do {									\
+    union {UDItype __ll;						\
+	   struct {USItype __h, __l;} __i;				\
+	  } __x;							\
+    __x.__ll = (UDItype) (m0) * (UDItype) (m1);				\
+    (xh) = __x.__i.__h; (xl) = __x.__i.__l;				\
+  } while (0)
+#else
+#if 0
+/* FIXME: this fails if gcc knows about the 64-bit registers.  Use only
+   with a new enough processor pretending we have 32-bit registers.  */
+#define umul_ppmm(xh, xl, m0, m1)					\
+  do {									\
+    union {UDItype __ll;						\
+	   struct {USItype __h, __l;} __i;				\
+	  } __x;							\
+    __asm__ ("mlr\t%0,%2"						\
+	     : "=r" (__x.__ll)						\
+	     : "%0" (m0), "r" (m1));					\
+    (xh) = __x.__i.__h; (xl) = __x.__i.__l;				\
+  } while (0)
+#else
+#define umul_ppmm(xh, xl, m0, m1)					\
+  do {									\
+  /* When we have 64-bit regs and gcc is aware of that, we cannot simply use
+     DImode for the product, since that would be allocated to a single 64-bit
+     register, whereas mlr uses the low 32-bits of an even-odd register pair.
+  */									\
+    register USItype __r0 __asm__ ("0");				\
+    register USItype __r1 __asm__ ("1") = (m0);				\
+    __asm__ ("mlr\t%0,%3"						\
+	     : "=r" (__r0), "=r" (__r1)					\
+	     : "r" (__r1), "r" (m1));					\
+    (xh) = __r0; (xl) = __r1;						\
+  } while (0)
+#endif /* if 0 */
+#endif
+#if 0
+/* FIXME: this fails if gcc knows about the 64-bit registers.  Use only
+   with a new enough processor pretending we have 32-bit registers.  */
+#define udiv_qrnnd(q, r, n1, n0, d)					\
+  do {									\
+    union {UDItype __ll;						\
+	   struct {USItype __h, __l;} __i;				\
+	  } __x;							\
+    __x.__i.__h = n1; __x.__i.__l = n0;					\
+    __asm__ ("dlr\t%0,%2"						\
+	     : "=r" (__x.__ll)						\
+	     : "0" (__x.__ll), "r" (d));				\
+    (q) = __x.__i.__l; (r) = __x.__i.__h;				\
+  } while (0)
+#else
+#define udiv_qrnnd(q, r, n1, n0, d)					\
+  do {									\
+    register USItype __r0 __asm__ ("0") = (n1);				\
+    register USItype __r1 __asm__ ("1") = (n0);				\
+    __asm__ ("dlr\t%0,%4"						\
+	     : "=r" (__r0), "=r" (__r1)					\
+	     : "r" (__r0), "r" (__r1), "r" (d));			\
+    (q) = __r1; (r) = __r0;						\
+  } while (0)
+#endif /* if 0 */
+#else /* if __zarch__ */
+/* FIXME: this fails if gcc knows about the 64-bit registers.  */
+#define smul_ppmm(xh, xl, m0, m1)					\
+  do {									\
+    union {DItype __ll;							\
+	   struct {USItype __h, __l;} __i;				\
+	  } __x;							\
+    __asm__ ("mr\t%0,%2"						\
+	     : "=r" (__x.__ll)						\
+	     : "%0" (m0), "r" (m1));					\
+    (xh) = __x.__i.__h; (xl) = __x.__i.__l;				\
+  } while (0)
+/* FIXME: this fails if gcc knows about the 64-bit registers.  */
+#define sdiv_qrnnd(q, r, n1, n0, d)					\
+  do {									\
+    union {DItype __ll;							\
+	   struct {USItype __h, __l;} __i;				\
+	  } __x;							\
+    __x.__i.__h = n1; __x.__i.__l = n0;					\
+    __asm__ ("dr\t%0,%2"						\
+	     : "=r" (__x.__ll)						\
+	     : "0" (__x.__ll), "r" (d));				\
+    (q) = __x.__i.__l; (r) = __x.__i.__h;				\
+  } while (0)
+#endif /* if __zarch__ */
+#endif
+
+#if defined (__s390x__) && W_TYPE_SIZE == 64
+/* We need to cast operands with register constraints, otherwise their types
+   will be assumed to be SImode by gcc.  For these machines, such operations
+   will insert a value into the low 32 bits, and leave the high 32 bits with
+   garbage.  */
+#define add_ssaaaa(sh, sl, ah, al, bh, bl)				\
+  do {									\
+    __asm__ ("algr\t%1,%5\n\talcgr\t%0,%3"				\
+	       : "=r" (sh), "=&r" (sl)					\
+	       : "0"  ((UDItype)(ah)), "r" ((UDItype)(bh)),		\
+		 "%1" ((UDItype)(al)), "r" ((UDItype)(bl)) __CLOBBER_CC); \
+  } while (0)
+#define sub_ddmmss(sh, sl, ah, al, bh, bl)				\
+  do {									\
+    __asm__ ("slgr\t%1,%5\n\tslbgr\t%0,%3"				\
+	     : "=r" (sh), "=&r" (sl)					\
+	     : "0" ((UDItype)(ah)), "r" ((UDItype)(bh)),		\
+	       "1" ((UDItype)(al)), "r" ((UDItype)(bl)) __CLOBBER_CC);	\
+  } while (0)
+#define umul_ppmm(xh, xl, m0, m1)					\
+  do {									\
+    union {unsigned int __attribute__ ((mode(TI))) __ll;		\
+	   struct {UDItype __h, __l;} __i;				\
+	  } __x;							\
+    __asm__ ("mlgr\t%0,%2"						\
+	     : "=r" (__x.__ll)						\
+	     : "%0" ((UDItype)(m0)), "r" ((UDItype)(m1)));		\
+    (xh) = __x.__i.__h; (xl) = __x.__i.__l;				\
+  } while (0)
+#define udiv_qrnnd(q, r, n1, n0, d)					\
+  do {									\
+    union {unsigned int __attribute__ ((mode(TI))) __ll;		\
+	   struct {UDItype __h, __l;} __i;				\
+	  } __x;							\
+    __x.__i.__h = n1; __x.__i.__l = n0;					\
+    __asm__ ("dlgr\t%0,%2"						\
+	     : "=r" (__x.__ll)						\
+	     : "0" (__x.__ll), "r" ((UDItype)(d)));			\
+    (q) = __x.__i.__l; (r) = __x.__i.__h;				\
+  } while (0)
+#if 0 /* FIXME: Enable for z10 (?) */
+#define count_leading_zeros(cnt, x)					\
+  do {									\
+    union {unsigned int __attribute__ ((mode(TI))) __ll;		\
+	   struct {UDItype __h, __l;} __i;				\
+	  } __clr_cnt;							\
+    __asm__ ("flogr\t%0,%1"						\
+	     : "=r" (__clr_cnt.__ll)					\
+	     : "r" (x) __CLOBBER_CC);					\
+    (cnt) = __clr_cnt.__i.__h;						\
+  } while (0)
+#endif
+#endif
+
+/* On x86 and x86_64, every asm implicitly clobbers "flags" and "fpsr",
+   so we don't need __CLOBBER_CC.  */
+#if (defined (__i386__) || defined (__i486__)) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  __asm__ ("addl %5,%k1\n\tadcl %3,%k0"					\
+	   : "=r" (sh), "=&r" (sl)					\
+	   : "0"  ((USItype)(ah)), "g" ((USItype)(bh)),			\
+	     "%1" ((USItype)(al)), "g" ((USItype)(bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  __asm__ ("subl %5,%k1\n\tsbbl %3,%k0"					\
+	   : "=r" (sh), "=&r" (sl)					\
+	   : "0" ((USItype)(ah)), "g" ((USItype)(bh)),			\
+	     "1" ((USItype)(al)), "g" ((USItype)(bl)))
+#define umul_ppmm(w1, w0, u, v) \
+  __asm__ ("mull %3"							\
+	   : "=a" (w0), "=d" (w1)					\
+	   : "%0" ((USItype)(u)), "rm" ((USItype)(v)))
+#define udiv_qrnnd(q, r, n1, n0, dx) /* d renamed to dx avoiding "=d" */\
+  __asm__ ("divl %4"		     /* stringification in K&R C */	\
+	   : "=a" (q), "=d" (r)						\
+	   : "0" ((USItype)(n0)), "1" ((USItype)(n1)), "rm" ((USItype)(dx)))
+
+#if HAVE_HOST_CPU_i586 || HAVE_HOST_CPU_pentium || HAVE_HOST_CPU_pentiummmx
+/* Pentium bsrl takes between 10 and 72 cycles depending where the most
+   significant 1 bit is, hence the use of the following alternatives.  bsfl
+   is slow too, between 18 and 42 depending where the least significant 1
+   bit is, so let the generic count_trailing_zeros below make use of the
+   count_leading_zeros here too.  */
+
+#if HAVE_HOST_CPU_pentiummmx && ! defined (LONGLONG_STANDALONE)
+/* The following should be a fixed 14 or 15 cycles, but possibly plus an L1
+   cache miss reading from __clz_tab.  For P55 it's favoured over the float
+   below so as to avoid mixing MMX and x87, since the penalty for switching
+   between the two is about 100 cycles.
+
+   The asm block sets __shift to -3 if the high 24 bits are clear, -2 for
+   16, -1 for 8, or 0 otherwise.  This could be written equivalently as
+   follows, but as of gcc 2.95.2 it results in conditional jumps.
+
+       __shift = -(__n < 0x1000000);
+       __shift -= (__n < 0x10000);
+       __shift -= (__n < 0x100);
+
+   The middle two sbbl and cmpl's pair, and with luck something gcc
+   generates might pair with the first cmpl and the last sbbl.  The "32+1"
+   constant could be folded into __clz_tab[], but it doesn't seem worth
+   making a different table just for that.  */
+
+#define count_leading_zeros(c,n)					\
+  do {									\
+    USItype  __n = (n);							\
+    USItype  __shift;							\
+    __asm__ ("cmpl  $0x1000000, %1\n"					\
+	     "sbbl  %0, %0\n"						\
+	     "cmpl  $0x10000, %1\n"					\
+	     "sbbl  $0, %0\n"						\
+	     "cmpl  $0x100, %1\n"					\
+	     "sbbl  $0, %0\n"						\
+	     : "=&r" (__shift) : "r"  (__n));				\
+    __shift = __shift*8 + 24 + 1;					\
+    (c) = 32 + 1 - __shift - __clz_tab[__n >> __shift];			\
+  } while (0)
+#define COUNT_LEADING_ZEROS_NEED_CLZ_TAB
+#define COUNT_LEADING_ZEROS_0   31   /* n==0 indistinguishable from n==1 */
+
+#else /* ! pentiummmx || LONGLONG_STANDALONE */
+/* The following should be a fixed 14 cycles or so.  Some scheduling
+   opportunities should be available between the float load/store too.  This
+   sort of code is used in gcc 3 for __builtin_ffs (with "n&-n") and is
+   apparently suggested by the Intel optimizing manual (don't know exactly
+   where).  gcc 2.95 or up will be best for this, so the "double" is
+   correctly aligned on the stack.  */
+#define count_leading_zeros(c,n)					\
+  do {									\
+    union {								\
+      double    d;							\
+      unsigned  a[2];							\
+    } __u;								\
+    __u.d = (UWtype) (n);						\
+    (c) = 0x3FF + 31 - (__u.a[1] >> 20);				\
+  } while (0)
+#define COUNT_LEADING_ZEROS_0   (0x3FF + 31)
+#endif /* pentiummx */
+
+#else /* ! pentium */
+
+#if __GMP_GNUC_PREREQ (3,4)  /* using bsrl */
+#define count_leading_zeros(count,x)  count_leading_zeros_gcc_clz(count,x)
+#endif /* gcc clz */
+
+/* On P6, gcc prior to 3.0 generates a partial register stall for
+   __cbtmp^31, due to using "xorb $31" instead of "xorl $31", the former
+   being 1 code byte smaller.  "31-__cbtmp" is a workaround, probably at the
+   cost of one extra instruction.  Do this for "i386" too, since that means
+   generic x86.  */
+#if ! defined (count_leading_zeros) && __GNUC__ < 3			\
+  && (HAVE_HOST_CPU_i386						\
+      || HAVE_HOST_CPU_i686						\
+      || HAVE_HOST_CPU_pentiumpro					\
+      || HAVE_HOST_CPU_pentium2						\
+      || HAVE_HOST_CPU_pentium3)
+#define count_leading_zeros(count, x)					\
+  do {									\
+    USItype __cbtmp;							\
+    ASSERT ((x) != 0);							\
+    __asm__ ("bsrl %1,%0" : "=r" (__cbtmp) : "rm" ((USItype)(x)));	\
+    (count) = 31 - __cbtmp;						\
+  } while (0)
+#endif /* gcc<3 asm bsrl */
+
+#ifndef count_leading_zeros
+#define count_leading_zeros(count, x)					\
+  do {									\
+    USItype __cbtmp;							\
+    ASSERT ((x) != 0);							\
+    __asm__ ("bsrl %1,%0" : "=r" (__cbtmp) : "rm" ((USItype)(x)));	\
+    (count) = __cbtmp ^ 31;						\
+  } while (0)
+#endif /* asm bsrl */
+
+#if __GMP_GNUC_PREREQ (3,4)  /* using bsfl */
+#define count_trailing_zeros(count,x)  count_trailing_zeros_gcc_ctz(count,x)
+#endif /* gcc ctz */
+
+#ifndef count_trailing_zeros
+#define count_trailing_zeros(count, x)					\
+  do {									\
+    ASSERT ((x) != 0);							\
+    __asm__ ("bsfl %1,%k0" : "=r" (count) : "rm" ((USItype)(x)));	\
+  } while (0)
+#endif /* asm bsfl */
+
+#endif /* ! pentium */
+
+#endif /* 80x86 */
+
+#if defined (__amd64__) && W_TYPE_SIZE == 64
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  __asm__ ("addq %5,%q1\n\tadcq %3,%q0"					\
+	   : "=r" (sh), "=&r" (sl)					\
+	   : "0"  ((UDItype)(ah)), "rme" ((UDItype)(bh)),		\
+	     "%1" ((UDItype)(al)), "rme" ((UDItype)(bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  __asm__ ("subq %5,%q1\n\tsbbq %3,%q0"					\
+	   : "=r" (sh), "=&r" (sl)					\
+	   : "0" ((UDItype)(ah)), "rme" ((UDItype)(bh)),		\
+	     "1" ((UDItype)(al)), "rme" ((UDItype)(bl)))
+#if X86_ASM_MULX \
+   && (HAVE_HOST_CPU_haswell || HAVE_HOST_CPU_broadwell \
+       || HAVE_HOST_CPU_skylake || HAVE_HOST_CPU_bd4 || HAVE_HOST_CPU_zen)
+#define umul_ppmm(w1, w0, u, v) \
+  __asm__ ("mulx\t%3, %0, %1"						\
+	   : "=r" (w0), "=r" (w1)					\
+	   : "%d" ((UDItype)(u)), "rm" ((UDItype)(v)))
+#else
+#define umul_ppmm(w1, w0, u, v) \
+  __asm__ ("mulq\t%3"							\
+	   : "=a" (w0), "=d" (w1)					\
+	   : "%0" ((UDItype)(u)), "rm" ((UDItype)(v)))
+#endif
+#define udiv_qrnnd(q, r, n1, n0, dx) /* d renamed to dx avoiding "=d" */\
+  __asm__ ("divq %4"		     /* stringification in K&R C */	\
+	   : "=a" (q), "=d" (r)						\
+	   : "0" ((UDItype)(n0)), "1" ((UDItype)(n1)), "rm" ((UDItype)(dx)))
+
+#if HAVE_HOST_CPU_haswell || HAVE_HOST_CPU_broadwell || HAVE_HOST_CPU_skylake \
+  || HAVE_HOST_CPU_k10 || HAVE_HOST_CPU_bd1 || HAVE_HOST_CPU_bd2	\
+  || HAVE_HOST_CPU_bd3 || HAVE_HOST_CPU_bd4 || HAVE_HOST_CPU_zen	\
+  || HAVE_HOST_CPU_bobcat || HAVE_HOST_CPU_jaguar
+#define count_leading_zeros(count, x)					\
+  do {									\
+    /* This is lzcnt, spelled for older assemblers.  Destination and */	\
+    /* source must be a 64-bit registers, hence cast and %q.         */	\
+    __asm__ ("rep;bsr\t%1, %q0" : "=r" (count) : "rm" ((UDItype)(x)));	\
+  } while (0)
+#define COUNT_LEADING_ZEROS_0 64
+#else
+#define count_leading_zeros(count, x)					\
+  do {									\
+    UDItype __cbtmp;							\
+    ASSERT ((x) != 0);							\
+    __asm__ ("bsr\t%1,%0" : "=r" (__cbtmp) : "rm" ((UDItype)(x)));	\
+    (count) = __cbtmp ^ 63;						\
+  } while (0)
+#endif
+
+#if HAVE_HOST_CPU_bd2 || HAVE_HOST_CPU_bd3 || HAVE_HOST_CPU_bd4 \
+  || HAVE_HOST_CPU_zen || HAVE_HOST_CPU_jaguar
+#define count_trailing_zeros(count, x)					\
+  do {									\
+    /* This is tzcnt, spelled for older assemblers.  Destination and */	\
+    /* source must be a 64-bit registers, hence cast and %q.         */	\
+    __asm__ ("rep;bsf\t%1, %q0" : "=r" (count) : "rm" ((UDItype)(x)));	\
+  } while (0)
+#define COUNT_TRAILING_ZEROS_0 64
+#else
+#define count_trailing_zeros(count, x)					\
+  do {									\
+    ASSERT ((x) != 0);							\
+    __asm__ ("bsf\t%1, %q0" : "=r" (count) : "rm" ((UDItype)(x)));	\
+  } while (0)
+#endif
+#endif /* __amd64__ */
+
+#if defined (__i860__) && W_TYPE_SIZE == 32
+#define rshift_rhlc(r,h,l,c) \
+  __asm__ ("shr %3,r0,r0\;shrd %1,%2,%0"				\
+	   "=r" (r) : "r" (h), "r" (l), "rn" (c))
+#endif /* i860 */
+
+#if defined (__i960__) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  __asm__ ("cmpo 1,0\;addc %5,%4,%1\;addc %3,%2,%0"			\
+	   : "=r" (sh), "=&r" (sl)					\
+	   : "dI" (ah), "dI" (bh), "%dI" (al), "dI" (bl))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  __asm__ ("cmpo 0,0\;subc %5,%4,%1\;subc %3,%2,%0"			\
+	   : "=r" (sh), "=&r" (sl)					\
+	   : "dI" (ah), "dI" (bh), "dI" (al), "dI" (bl))
+#define umul_ppmm(w1, w0, u, v) \
+  ({union {UDItype __ll;						\
+	   struct {USItype __l, __h;} __i;				\
+	  } __x;							\
+  __asm__ ("emul %2,%1,%0"						\
+	   : "=d" (__x.__ll) : "%dI" (u), "dI" (v));			\
+  (w1) = __x.__i.__h; (w0) = __x.__i.__l;})
+#define __umulsidi3(u, v) \
+  ({UDItype __w;							\
+    __asm__ ("emul %2,%1,%0" : "=d" (__w) : "%dI" (u), "dI" (v));	\
+    __w; })
+#define udiv_qrnnd(q, r, nh, nl, d) \
+  do {									\
+    union {UDItype __ll;						\
+	   struct {USItype __l, __h;} __i;				\
+	  } __nn;							\
+    __nn.__i.__h = (nh); __nn.__i.__l = (nl);				\
+    __asm__ ("ediv %d,%n,%0"						\
+	   : "=d" (__rq.__ll) : "dI" (__nn.__ll), "dI" (d));		\
+    (r) = __rq.__i.__l; (q) = __rq.__i.__h;				\
+  } while (0)
+#define count_leading_zeros(count, x) \
+  do {									\
+    USItype __cbtmp;							\
+    __asm__ ("scanbit %1,%0" : "=r" (__cbtmp) : "r" (x));		\
+    (count) = __cbtmp ^ 31;						\
+  } while (0)
+#define COUNT_LEADING_ZEROS_0 (-32) /* sic */
+#if defined (__i960mx)		/* what is the proper symbol to test??? */
+#define rshift_rhlc(r,h,l,c) \
+  do {									\
+    union {UDItype __ll;						\
+	   struct {USItype __l, __h;} __i;				\
+	  } __nn;							\
+    __nn.__i.__h = (h); __nn.__i.__l = (l);				\
+    __asm__ ("shre %2,%1,%0" : "=d" (r) : "dI" (__nn.__ll), "dI" (c));	\
+  }
+#endif /* i960mx */
+#endif /* i960 */
+
+#if (defined (__mc68000__) || defined (__mc68020__) || defined(mc68020) \
+     || defined (__m68k__) || defined (__mc5200__) || defined (__mc5206e__) \
+     || defined (__mc5307__)) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  __asm__ ("add%.l %5,%1\n\taddx%.l %3,%0"				\
+	   : "=d" (sh), "=&d" (sl)					\
+	   : "0"  ((USItype)(ah)), "d" ((USItype)(bh)),			\
+	     "%1" ((USItype)(al)), "g" ((USItype)(bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  __asm__ ("sub%.l %5,%1\n\tsubx%.l %3,%0"				\
+	   : "=d" (sh), "=&d" (sl)					\
+	   : "0" ((USItype)(ah)), "d" ((USItype)(bh)),			\
+	     "1" ((USItype)(al)), "g" ((USItype)(bl)))
+/* The '020, '030, '040 and CPU32 have 32x32->64 and 64/32->32q-32r.  */
+#if defined (__mc68020__) || defined(mc68020) \
+     || defined (__mc68030__) || defined (mc68030) \
+     || defined (__mc68040__) || defined (mc68040) \
+     || defined (__mcpu32__) || defined (mcpu32) \
+     || defined (__NeXT__)
+#define umul_ppmm(w1, w0, u, v) \
+  __asm__ ("mulu%.l %3,%1:%0"						\
+	   : "=d" (w0), "=d" (w1)					\
+	   : "%0" ((USItype)(u)), "dmi" ((USItype)(v)))
+#define udiv_qrnnd(q, r, n1, n0, d) \
+  __asm__ ("divu%.l %4,%1:%0"						\
+	   : "=d" (q), "=d" (r)						\
+	   : "0" ((USItype)(n0)), "1" ((USItype)(n1)), "dmi" ((USItype)(d)))
+#define sdiv_qrnnd(q, r, n1, n0, d) \
+  __asm__ ("divs%.l %4,%1:%0"						\
+	   : "=d" (q), "=d" (r)						\
+	   : "0" ((USItype)(n0)), "1" ((USItype)(n1)), "dmi" ((USItype)(d)))
+#else /* for other 68k family members use 16x16->32 multiplication */
+#define umul_ppmm(xh, xl, a, b) \
+  do { USItype __umul_tmp1, __umul_tmp2;				\
+	__asm__ ("| Inlined umul_ppmm\n"				\
+"	move%.l	%5,%3\n"						\
+"	move%.l	%2,%0\n"						\
+"	move%.w	%3,%1\n"						\
+"	swap	%3\n"							\
+"	swap	%0\n"							\
+"	mulu%.w	%2,%1\n"						\
+"	mulu%.w	%3,%0\n"						\
+"	mulu%.w	%2,%3\n"						\
+"	swap	%2\n"							\
+"	mulu%.w	%5,%2\n"						\
+"	add%.l	%3,%2\n"						\
+"	jcc	1f\n"							\
+"	add%.l	%#0x10000,%0\n"						\
+"1:	move%.l	%2,%3\n"						\
+"	clr%.w	%2\n"							\
+"	swap	%2\n"							\
+"	swap	%3\n"							\
+"	clr%.w	%3\n"							\
+"	add%.l	%3,%1\n"						\
+"	addx%.l	%2,%0\n"						\
+"	| End inlined umul_ppmm"					\
+	      : "=&d" (xh), "=&d" (xl),					\
+		"=d" (__umul_tmp1), "=&d" (__umul_tmp2)			\
+	      : "%2" ((USItype)(a)), "d" ((USItype)(b)));		\
+  } while (0)
+#endif /* not mc68020 */
+/* The '020, '030, '040 and '060 have bitfield insns.
+   GCC 3.4 defines __mc68020__ when in CPU32 mode, check for __mcpu32__ to
+   exclude bfffo on that chip (bitfield insns not available).  */
+#if (defined (__mc68020__) || defined (mc68020)    \
+     || defined (__mc68030__) || defined (mc68030) \
+     || defined (__mc68040__) || defined (mc68040) \
+     || defined (__mc68060__) || defined (mc68060) \
+     || defined (__NeXT__))			   \
+  && ! defined (__mcpu32__)
+#define count_leading_zeros(count, x) \
+  __asm__ ("bfffo %1{%b2:%b2},%0"					\
+	   : "=d" (count)						\
+	   : "od" ((USItype) (x)), "n" (0))
+#define COUNT_LEADING_ZEROS_0 32
+#endif
+#endif /* mc68000 */
+
+#if defined (__m88000__) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  __asm__ ("addu.co %1,%r4,%r5\n\taddu.ci %0,%r2,%r3"			\
+	   : "=r" (sh), "=&r" (sl)					\
+	   : "rJ" (ah), "rJ" (bh), "%rJ" (al), "rJ" (bl))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  __asm__ ("subu.co %1,%r4,%r5\n\tsubu.ci %0,%r2,%r3"			\
+	   : "=r" (sh), "=&r" (sl)					\
+	   : "rJ" (ah), "rJ" (bh), "rJ" (al), "rJ" (bl))
+#define count_leading_zeros(count, x) \
+  do {									\
+    USItype __cbtmp;							\
+    __asm__ ("ff1 %0,%1" : "=r" (__cbtmp) : "r" (x));			\
+    (count) = __cbtmp ^ 31;						\
+  } while (0)
+#define COUNT_LEADING_ZEROS_0 63 /* sic */
+#if defined (__m88110__)
+#define umul_ppmm(wh, wl, u, v) \
+  do {									\
+    union {UDItype __ll;						\
+	   struct {USItype __h, __l;} __i;				\
+	  } __x;							\
+    __asm__ ("mulu.d %0,%1,%2" : "=r" (__x.__ll) : "r" (u), "r" (v));	\
+    (wh) = __x.__i.__h;							\
+    (wl) = __x.__i.__l;							\
+  } while (0)
+#define udiv_qrnnd(q, r, n1, n0, d) \
+  ({union {UDItype __ll;						\
+	   struct {USItype __h, __l;} __i;				\
+	  } __x, __q;							\
+  __x.__i.__h = (n1); __x.__i.__l = (n0);				\
+  __asm__ ("divu.d %0,%1,%2"						\
+	   : "=r" (__q.__ll) : "r" (__x.__ll), "r" (d));		\
+  (r) = (n0) - __q.__l * (d); (q) = __q.__l; })
+#endif /* __m88110__ */
+#endif /* __m88000__ */
+
+#if defined (__mips) && W_TYPE_SIZE == 32
+#if __GMP_GNUC_PREREQ (4,4)
+#define umul_ppmm(w1, w0, u, v) \
+  do {									\
+    UDItype __ll = (UDItype)(u) * (v);					\
+    w1 = __ll >> 32;							\
+    w0 = __ll;								\
+  } while (0)
+#endif
+#if !defined (umul_ppmm) && __GMP_GNUC_PREREQ (2,7) && !defined (__clang__)
+#define umul_ppmm(w1, w0, u, v) \
+  __asm__ ("multu %2,%3" : "=l" (w0), "=h" (w1) : "d" (u), "d" (v))
+#endif
+#if !defined (umul_ppmm)
+#define umul_ppmm(w1, w0, u, v) \
+  __asm__ ("multu %2,%3\n\tmflo %0\n\tmfhi %1"				\
+	   : "=d" (w0), "=d" (w1) : "d" (u), "d" (v))
+#endif
+#endif /* __mips */
+
+#if (defined (__mips) && __mips >= 3) && W_TYPE_SIZE == 64
+#if defined (_MIPS_ARCH_MIPS64R6)
+#define umul_ppmm(w1, w0, u, v) \
+  do {									\
+    UDItype __m0 = (u), __m1 = (v);					\
+    (w0) = __m0 * __m1;							\
+    __asm__ ("dmuhu\t%0, %1, %2" : "=d" (w1) : "d" (__m0), "d" (__m1));	\
+  } while (0)
+#endif
+#if !defined (umul_ppmm) && __GMP_GNUC_PREREQ (4,4)
+#define umul_ppmm(w1, w0, u, v) \
+  do {									\
+    typedef unsigned int __ll_UTItype __attribute__((mode(TI)));	\
+    __ll_UTItype __ll = (__ll_UTItype)(u) * (v);			\
+    w1 = __ll >> 64;							\
+    w0 = __ll;								\
+  } while (0)
+#endif
+#if !defined (umul_ppmm) && __GMP_GNUC_PREREQ (2,7) && !defined (__clang__)
+#define umul_ppmm(w1, w0, u, v) \
+  __asm__ ("dmultu %2,%3"						\
+	   : "=l" (w0), "=h" (w1)					\
+	   : "d" ((UDItype)(u)), "d" ((UDItype)(v)))
+#endif
+#if !defined (umul_ppmm)
+#define umul_ppmm(w1, w0, u, v) \
+  __asm__ ("dmultu %2,%3\n\tmflo %0\n\tmfhi %1"				\
+	   : "=d" (w0), "=d" (w1)					\
+	   : "d" ((UDItype)(u)), "d" ((UDItype)(v)))
+#endif
+#endif /* __mips */
+
+#if defined (__mmix__) && W_TYPE_SIZE == 64
+#define umul_ppmm(w1, w0, u, v) \
+  __asm__ ("MULU %0,%2,%3" : "=r" (w0), "=z" (w1) : "r" (u), "r" (v))
+#endif
+
+#if defined (__ns32000__) && W_TYPE_SIZE == 32
+#define umul_ppmm(w1, w0, u, v) \
+  ({union {UDItype __ll;						\
+	   struct {USItype __l, __h;} __i;				\
+	  } __x;							\
+  __asm__ ("meid %2,%0"							\
+	   : "=g" (__x.__ll)						\
+	   : "%0" ((USItype)(u)), "g" ((USItype)(v)));			\
+  (w1) = __x.__i.__h; (w0) = __x.__i.__l;})
+#define __umulsidi3(u, v) \
+  ({UDItype __w;							\
+    __asm__ ("meid %2,%0"						\
+	     : "=g" (__w)						\
+	     : "%0" ((USItype)(u)), "g" ((USItype)(v)));		\
+    __w; })
+#define udiv_qrnnd(q, r, n1, n0, d) \
+  ({union {UDItype __ll;						\
+	   struct {USItype __l, __h;} __i;				\
+	  } __x;							\
+  __x.__i.__h = (n1); __x.__i.__l = (n0);				\
+  __asm__ ("deid %2,%0"							\
+	   : "=g" (__x.__ll)						\
+	   : "0" (__x.__ll), "g" ((USItype)(d)));			\
+  (r) = __x.__i.__l; (q) = __x.__i.__h; })
+#define count_trailing_zeros(count,x) \
+  do {									\
+    __asm__ ("ffsd	%2,%0"						\
+	     : "=r" (count)						\
+	     : "0" ((USItype) 0), "r" ((USItype) (x)));			\
+  } while (0)
+#endif /* __ns32000__ */
+
+/* In the past we had a block of various #defines tested
+       _ARCH_PPC    - AIX
+       _ARCH_PWR    - AIX
+       __powerpc__  - gcc
+       __POWERPC__  - BEOS
+       __ppc__      - Darwin
+       PPC          - old gcc, GNU/Linux, SysV
+   The plain PPC test was not good for vxWorks, since PPC is defined on all
+   CPUs there (eg. m68k too), as a constant one is expected to compare
+   CPU_FAMILY against.
+
+   At any rate, this was pretty unattractive and a bit fragile.  The use of
+   HAVE_HOST_CPU_FAMILY is designed to cut through it all and be sure of
+   getting the desired effect.
+
+   ENHANCE-ME: We should test _IBMR2 here when we add assembly support for
+   the system vendor compilers.  (Is that vendor compilers with inline asm,
+   or what?)  */
+
+#if (HAVE_HOST_CPU_FAMILY_power || HAVE_HOST_CPU_FAMILY_powerpc)	\
+  && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  do {									\
+    if (__builtin_constant_p (bh) && (bh) == 0)				\
+      __asm__ ("add%I4c %1,%3,%4\n\taddze %0,%2"			\
+	       : "=r" (sh), "=&r" (sl) : "r" (ah), "%r" (al), "rI" (bl)	\
+		 __CLOBBER_CC);						\
+    else if (__builtin_constant_p (bh) && (bh) == ~(USItype) 0)		\
+      __asm__ ("add%I4c %1,%3,%4\n\taddme %0,%2"			\
+	       : "=r" (sh), "=&r" (sl) : "r" (ah), "%r" (al), "rI" (bl)	\
+		 __CLOBBER_CC);						\
+    else								\
+      __asm__ ("add%I5c %1,%4,%5\n\tadde %0,%2,%3"			\
+	       : "=r" (sh), "=&r" (sl)					\
+	       : "r" (ah), "r" (bh), "%r" (al), "rI" (bl)		\
+		 __CLOBBER_CC);						\
+  } while (0)
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  do {									\
+    if (__builtin_constant_p (ah) && (ah) == 0)				\
+      __asm__ ("subf%I3c %1,%4,%3\n\tsubfze %0,%2"			\
+	       : "=r" (sh), "=&r" (sl) : "r" (bh), "rI" (al), "r" (bl)	\
+		 __CLOBBER_CC);						\
+    else if (__builtin_constant_p (ah) && (ah) == ~(USItype) 0)		\
+      __asm__ ("subf%I3c %1,%4,%3\n\tsubfme %0,%2"			\
+	       : "=r" (sh), "=&r" (sl) : "r" (bh), "rI" (al), "r" (bl)	\
+		 __CLOBBER_CC);						\
+    else if (__builtin_constant_p (bh) && (bh) == 0)			\
+      __asm__ ("subf%I3c %1,%4,%3\n\taddme %0,%2"			\
+	       : "=r" (sh), "=&r" (sl) : "r" (ah), "rI" (al), "r" (bl)	\
+		 __CLOBBER_CC);						\
+    else if (__builtin_constant_p (bh) && (bh) == ~(USItype) 0)		\
+      __asm__ ("subf%I3c %1,%4,%3\n\taddze %0,%2"			\
+	       : "=r" (sh), "=&r" (sl) : "r" (ah), "rI" (al), "r" (bl)	\
+		 __CLOBBER_CC);						\
+    else								\
+      __asm__ ("subf%I4c %1,%5,%4\n\tsubfe %0,%3,%2"			\
+	       : "=r" (sh), "=&r" (sl)					\
+	       : "r" (ah), "r" (bh), "rI" (al), "r" (bl)		\
+		 __CLOBBER_CC);						\
+  } while (0)
+#define count_leading_zeros(count, x) \
+  __asm__ ("cntlzw %0,%1" : "=r" (count) : "r" (x))
+#define COUNT_LEADING_ZEROS_0 32
+#if HAVE_HOST_CPU_FAMILY_powerpc
+#if __GMP_GNUC_PREREQ (4,4)
+#define umul_ppmm(w1, w0, u, v) \
+  do {									\
+    UDItype __ll = (UDItype)(u) * (v);					\
+    w1 = __ll >> 32;							\
+    w0 = __ll;								\
+  } while (0)
+#endif
+#if !defined (umul_ppmm)
+#define umul_ppmm(ph, pl, m0, m1) \
+  do {									\
+    USItype __m0 = (m0), __m1 = (m1);					\
+    __asm__ ("mulhwu %0,%1,%2" : "=r" (ph) : "%r" (m0), "r" (m1));	\
+    (pl) = __m0 * __m1;							\
+  } while (0)
+#endif
+#define smul_ppmm(ph, pl, m0, m1) \
+  do {									\
+    SItype __m0 = (m0), __m1 = (m1);					\
+    __asm__ ("mulhw %0,%1,%2" : "=r" (ph) : "%r" (m0), "r" (m1));	\
+    (pl) = __m0 * __m1;							\
+  } while (0)
+#else
+#define smul_ppmm(xh, xl, m0, m1) \
+  __asm__ ("mul %0,%2,%3" : "=r" (xh), "=q" (xl) : "r" (m0), "r" (m1))
+#define sdiv_qrnnd(q, r, nh, nl, d) \
+  __asm__ ("div %0,%2,%4" : "=r" (q), "=q" (r) : "r" (nh), "1" (nl), "r" (d))
+#endif
+#endif /* 32-bit POWER architecture variants.  */
+
+/* We should test _IBMR2 here when we add assembly support for the system
+   vendor compilers.  */
+#if HAVE_HOST_CPU_FAMILY_powerpc && W_TYPE_SIZE == 64
+#if !defined (_LONG_LONG_LIMB)
+/* _LONG_LONG_LIMB is ABI=mode32 where adde operates on 32-bit values.  So
+   use adde etc only when not _LONG_LONG_LIMB.  */
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  do {									\
+    if (__builtin_constant_p (bh) && (bh) == 0)				\
+      __asm__ ("add%I4c %1,%3,%4\n\taddze %0,%2"			\
+	       : "=r" (sh), "=&r" (sl)					\
+	       : "r"  ((UDItype)(ah)),					\
+		 "%r" ((UDItype)(al)), "rI" ((UDItype)(bl))		\
+		 __CLOBBER_CC);						\
+    else if (__builtin_constant_p (bh) && (bh) == ~(UDItype) 0)		\
+      __asm__ ("add%I4c %1,%3,%4\n\taddme %0,%2"			\
+	       : "=r" (sh), "=&r" (sl)					\
+	       : "r"  ((UDItype)(ah)),					\
+		 "%r" ((UDItype)(al)), "rI" ((UDItype)(bl))		\
+		 __CLOBBER_CC);						\
+    else								\
+      __asm__ ("add%I5c %1,%4,%5\n\tadde %0,%2,%3"			\
+	       : "=r" (sh), "=&r" (sl)					\
+	       : "r"  ((UDItype)(ah)), "r"  ((UDItype)(bh)),		\
+		 "%r" ((UDItype)(al)), "rI" ((UDItype)(bl))		\
+		 __CLOBBER_CC);						\
+  } while (0)
+/* We use "*rI" for the constant operand here, since with just "I", gcc barfs.
+   This might seem strange, but gcc folds away the dead code late.  */
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  do {									\
+    if (__builtin_constant_p (bl) && bl > -0x8000 && bl <= 0x8000) {	\
+	if (__builtin_constant_p (ah) && (ah) == 0)			\
+	  __asm__ ("addic %1,%3,%4\n\tsubfze %0,%2"			\
+		   : "=r" (sh), "=&r" (sl)				\
+		   :                       "r" ((UDItype)(bh)),		\
+		     "rI" ((UDItype)(al)), "*rI" (-((UDItype)(bl)))	\
+		     __CLOBBER_CC);					\
+	else if (__builtin_constant_p (ah) && (ah) == ~(UDItype) 0)	\
+	  __asm__ ("addic %1,%3,%4\n\tsubfme %0,%2"			\
+		   : "=r" (sh), "=&r" (sl)				\
+		   :                       "r" ((UDItype)(bh)),		\
+		     "rI" ((UDItype)(al)), "*rI" (-((UDItype)(bl)))	\
+		     __CLOBBER_CC);					\
+	else if (__builtin_constant_p (bh) && (bh) == 0)		\
+	  __asm__ ("addic %1,%3,%4\n\taddme %0,%2"			\
+		   : "=r" (sh), "=&r" (sl)				\
+		   : "r"  ((UDItype)(ah)),				\
+		     "rI" ((UDItype)(al)), "*rI" (-((UDItype)(bl)))	\
+		     __CLOBBER_CC);					\
+	else if (__builtin_constant_p (bh) && (bh) == ~(UDItype) 0)	\
+	  __asm__ ("addic %1,%3,%4\n\taddze %0,%2"			\
+		   : "=r" (sh), "=&r" (sl)				\
+		   : "r"  ((UDItype)(ah)),				\
+		     "rI" ((UDItype)(al)), "*rI" (-((UDItype)(bl)))	\
+		     __CLOBBER_CC);					\
+	else								\
+	  __asm__ ("addic %1,%4,%5\n\tsubfe %0,%3,%2"			\
+		   : "=r" (sh), "=&r" (sl)				\
+		   : "r"  ((UDItype)(ah)), "r" ((UDItype)(bh)),		\
+		     "rI" ((UDItype)(al)), "*rI" (-((UDItype)(bl)))	\
+		     __CLOBBER_CC);					\
+    } else {								\
+	if (__builtin_constant_p (ah) && (ah) == 0)			\
+	  __asm__ ("subf%I3c %1,%4,%3\n\tsubfze %0,%2"			\
+		   : "=r" (sh), "=&r" (sl)				\
+		   :                       "r" ((UDItype)(bh)),		\
+		     "rI" ((UDItype)(al)), "r" ((UDItype)(bl))		\
+		     __CLOBBER_CC);					\
+	else if (__builtin_constant_p (ah) && (ah) == ~(UDItype) 0)	\
+	  __asm__ ("subf%I3c %1,%4,%3\n\tsubfme %0,%2"			\
+		   : "=r" (sh), "=&r" (sl)				\
+		   :                       "r" ((UDItype)(bh)),		\
+		     "rI" ((UDItype)(al)), "r" ((UDItype)(bl))		\
+		     __CLOBBER_CC);					\
+	else if (__builtin_constant_p (bh) && (bh) == 0)		\
+	  __asm__ ("subf%I3c %1,%4,%3\n\taddme %0,%2"			\
+		   : "=r" (sh), "=&r" (sl)				\
+		   : "r"  ((UDItype)(ah)),				\
+		     "rI" ((UDItype)(al)), "r" ((UDItype)(bl))		\
+		     __CLOBBER_CC);					\
+	else if (__builtin_constant_p (bh) && (bh) == ~(UDItype) 0)	\
+	  __asm__ ("subf%I3c %1,%4,%3\n\taddze %0,%2"			\
+		   : "=r" (sh), "=&r" (sl)				\
+		   : "r"  ((UDItype)(ah)),				\
+		     "rI" ((UDItype)(al)), "r" ((UDItype)(bl))		\
+		     __CLOBBER_CC);					\
+	else								\
+	  __asm__ ("subf%I4c %1,%5,%4\n\tsubfe %0,%3,%2"		\
+		   : "=r" (sh), "=&r" (sl)				\
+		   : "r"  ((UDItype)(ah)), "r" ((UDItype)(bh)),		\
+		     "rI" ((UDItype)(al)), "r" ((UDItype)(bl))		\
+		     __CLOBBER_CC);					\
+    }									\
+  } while (0)
+#endif /* ! _LONG_LONG_LIMB */
+#define count_leading_zeros(count, x) \
+  __asm__ ("cntlzd %0,%1" : "=r" (count) : "r" (x))
+#define COUNT_LEADING_ZEROS_0 64
+#if __GMP_GNUC_PREREQ (4,8)
+#define umul_ppmm(w1, w0, u, v) \
+  do {									\
+    typedef unsigned int __ll_UTItype __attribute__((mode(TI)));	\
+    __ll_UTItype __ll = (__ll_UTItype)(u) * (v);			\
+    w1 = __ll >> 64;							\
+    w0 = __ll;								\
+  } while (0)
+#endif
+#if !defined (umul_ppmm)
+#define umul_ppmm(ph, pl, m0, m1) \
+  do {									\
+    UDItype __m0 = (m0), __m1 = (m1);					\
+    __asm__ ("mulhdu %0,%1,%2" : "=r" (ph) : "%r" (__m0), "r" (__m1));	\
+    (pl) = __m0 * __m1;							\
+  } while (0)
+#endif
+#define smul_ppmm(ph, pl, m0, m1) \
+  do {									\
+    DItype __m0 = (m0), __m1 = (m1);					\
+    __asm__ ("mulhd %0,%1,%2" : "=r" (ph) : "%r" (__m0), "r" (__m1));	\
+    (pl) = __m0 * __m1;							\
+  } while (0)
+#endif /* 64-bit PowerPC.  */
+
+#if defined (__pyr__) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  __asm__ ("addw %5,%1\n\taddwc %3,%0"					\
+	   : "=r" (sh), "=&r" (sl)					\
+	   : "0"  ((USItype)(ah)), "g" ((USItype)(bh)),			\
+	     "%1" ((USItype)(al)), "g" ((USItype)(bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  __asm__ ("subw %5,%1\n\tsubwb %3,%0"					\
+	   : "=r" (sh), "=&r" (sl)					\
+	   : "0" ((USItype)(ah)), "g" ((USItype)(bh)),			\
+	     "1" ((USItype)(al)), "g" ((USItype)(bl)))
+/* This insn works on Pyramids with AP, XP, or MI CPUs, but not with SP.  */
+#define umul_ppmm(w1, w0, u, v) \
+  ({union {UDItype __ll;						\
+	   struct {USItype __h, __l;} __i;				\
+	  } __x;							\
+  __asm__ ("movw %1,%R0\n\tuemul %2,%0"					\
+	   : "=&r" (__x.__ll)						\
+	   : "g" ((USItype) (u)), "g" ((USItype)(v)));			\
+  (w1) = __x.__i.__h; (w0) = __x.__i.__l;})
+#endif /* __pyr__ */
+
+#if defined (__ibm032__) /* RT/ROMP */  && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  __asm__ ("a %1,%5\n\tae %0,%3"					\
+	   : "=r" (sh), "=&r" (sl)					\
+	   : "0"  ((USItype)(ah)), "r" ((USItype)(bh)),			\
+	     "%1" ((USItype)(al)), "r" ((USItype)(bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  __asm__ ("s %1,%5\n\tse %0,%3"					\
+	   : "=r" (sh), "=&r" (sl)					\
+	   : "0" ((USItype)(ah)), "r" ((USItype)(bh)),			\
+	     "1" ((USItype)(al)), "r" ((USItype)(bl)))
+#define smul_ppmm(ph, pl, m0, m1) \
+  __asm__ (								\
+       "s	r2,r2\n"						\
+"	mts r10,%2\n"							\
+"	m	r2,%3\n"						\
+"	m	r2,%3\n"						\
+"	m	r2,%3\n"						\
+"	m	r2,%3\n"						\
+"	m	r2,%3\n"						\
+"	m	r2,%3\n"						\
+"	m	r2,%3\n"						\
+"	m	r2,%3\n"						\
+"	m	r2,%3\n"						\
+"	m	r2,%3\n"						\
+"	m	r2,%3\n"						\
+"	m	r2,%3\n"						\
+"	m	r2,%3\n"						\
+"	m	r2,%3\n"						\
+"	m	r2,%3\n"						\
+"	m	r2,%3\n"						\
+"	cas	%0,r2,r0\n"						\
+"	mfs	r10,%1"							\
+	   : "=r" (ph), "=r" (pl)					\
+	   : "%r" ((USItype)(m0)), "r" ((USItype)(m1))			\
+	   : "r2")
+#define count_leading_zeros(count, x) \
+  do {									\
+    if ((x) >= 0x10000)							\
+      __asm__ ("clz	%0,%1"						\
+	       : "=r" (count) : "r" ((USItype)(x) >> 16));		\
+    else								\
+      {									\
+	__asm__ ("clz	%0,%1"						\
+		 : "=r" (count) : "r" ((USItype)(x)));			\
+	(count) += 16;							\
+      }									\
+  } while (0)
+#endif /* RT/ROMP */
+
+#if defined (__riscv64) && W_TYPE_SIZE == 64
+#define umul_ppmm(ph, pl, u, v) \
+  do {									\
+    UDItype __u = (u), __v = (v);					\
+    (pl) = __u * __v;							\
+    __asm__ ("mulhu\t%2, %1, %0" : "=r" (ph) : "%r" (__u), "r" (__v));	\
+  } while (0)
+#endif
+
+#if (defined (__SH2__) || defined (__SH3__) || defined (__SH4__)) && W_TYPE_SIZE == 32
+#define umul_ppmm(w1, w0, u, v) \
+  __asm__ ("dmulu.l %2,%3\n\tsts macl,%1\n\tsts mach,%0"		\
+	   : "=r" (w1), "=r" (w0) : "r" (u), "r" (v) : "macl", "mach")
+#endif
+
+#if defined (__sparc__) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  __asm__ ("addcc %r4,%5,%1\n\taddx %r2,%3,%0"				\
+	   : "=r" (sh), "=&r" (sl)					\
+	   : "rJ" (ah), "rI" (bh),"%rJ" (al), "rI" (bl)			\
+	   __CLOBBER_CC)
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  __asm__ ("subcc %r4,%5,%1\n\tsubx %r2,%3,%0"				\
+	   : "=r" (sh), "=&r" (sl)					\
+	   : "rJ" (ah), "rI" (bh), "rJ" (al), "rI" (bl)	\
+	   __CLOBBER_CC)
+/* FIXME: When gcc -mcpu=v9 is used on solaris, gcc/config/sol2-sld-64.h
+   doesn't define anything to indicate that to us, it only sets __sparcv8. */
+#if defined (__sparc_v9__) || defined (__sparcv9)
+/* Perhaps we should use floating-point operations here?  */
+#if 0
+/* Triggers a bug making mpz/tests/t-gcd.c fail.
+   Perhaps we simply need explicitly zero-extend the inputs?  */
+#define umul_ppmm(w1, w0, u, v) \
+  __asm__ ("mulx %2,%3,%%g1; srl %%g1,0,%1; srlx %%g1,32,%0" :		\
+	   "=r" (w1), "=r" (w0) : "r" (u), "r" (v) : "g1")
+#else
+/* Use v8 umul until above bug is fixed.  */
+#define umul_ppmm(w1, w0, u, v) \
+  __asm__ ("umul %2,%3,%1;rd %%y,%0" : "=r" (w1), "=r" (w0) : "r" (u), "r" (v))
+#endif
+/* Use a plain v8 divide for v9.  */
+#define udiv_qrnnd(q, r, n1, n0, d) \
+  do {									\
+    USItype __q;							\
+    __asm__ ("mov %1,%%y;nop;nop;nop;udiv %2,%3,%0"			\
+	     : "=r" (__q) : "r" (n1), "r" (n0), "r" (d));		\
+    (r) = (n0) - __q * (d);						\
+    (q) = __q;								\
+  } while (0)
+#else
+#if defined (__sparc_v8__)   /* gcc normal */				\
+  || defined (__sparcv8)     /* gcc solaris */				\
+  || HAVE_HOST_CPU_supersparc
+/* Don't match immediate range because, 1) it is not often useful,
+   2) the 'I' flag thinks of the range as a 13 bit signed interval,
+   while we want to match a 13 bit interval, sign extended to 32 bits,
+   but INTERPRETED AS UNSIGNED.  */
+#define umul_ppmm(w1, w0, u, v) \
+  __asm__ ("umul %2,%3,%1;rd %%y,%0" : "=r" (w1), "=r" (w0) : "r" (u), "r" (v))
+
+#if HAVE_HOST_CPU_supersparc
+#else
+/* Don't use this on SuperSPARC because its udiv only handles 53 bit
+   dividends and will trap to the kernel for the rest. */
+#define udiv_qrnnd(q, r, n1, n0, d) \
+  do {									\
+    USItype __q;							\
+    __asm__ ("mov %1,%%y;nop;nop;nop;udiv %2,%3,%0"			\
+	     : "=r" (__q) : "r" (n1), "r" (n0), "r" (d));		\
+    (r) = (n0) - __q * (d);						\
+    (q) = __q;								\
+  } while (0)
+#endif /* HAVE_HOST_CPU_supersparc */
+
+#else /* ! __sparc_v8__ */
+#if defined (__sparclite__)
+/* This has hardware multiply but not divide.  It also has two additional
+   instructions scan (ffs from high bit) and divscc.  */
+#define umul_ppmm(w1, w0, u, v) \
+  __asm__ ("umul %2,%3,%1;rd %%y,%0" : "=r" (w1), "=r" (w0) : "r" (u), "r" (v))
+#define udiv_qrnnd(q, r, n1, n0, d) \
+  __asm__ ("! Inlined udiv_qrnnd\n"					\
+"	wr	%%g0,%2,%%y	! Not a delayed write for sparclite\n"	\
+"	tst	%%g0\n"							\
+"	divscc	%3,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%%g1\n"						\
+"	divscc	%%g1,%4,%0\n"						\
+"	rd	%%y,%1\n"						\
+"	bl,a 1f\n"							\
+"	add	%1,%4,%1\n"						\
+"1:	! End of inline udiv_qrnnd"					\
+	   : "=r" (q), "=r" (r) : "r" (n1), "r" (n0), "rI" (d)		\
+	   : "%g1" __AND_CLOBBER_CC)
+#define count_leading_zeros(count, x) \
+  __asm__ ("scan %1,1,%0" : "=r" (count) : "r" (x))
+/* Early sparclites return 63 for an argument of 0, but they warn that future
+   implementations might change this.  Therefore, leave COUNT_LEADING_ZEROS_0
+   undefined.  */
+#endif /* __sparclite__ */
+#endif /* __sparc_v8__ */
+#endif /* __sparc_v9__ */
+/* Default to sparc v7 versions of umul_ppmm and udiv_qrnnd.  */
+#ifndef umul_ppmm
+#define umul_ppmm(w1, w0, u, v) \
+  __asm__ ("! Inlined umul_ppmm\n"					\
+"	wr	%%g0,%2,%%y	! SPARC has 0-3 delay insn after a wr\n" \
+"	sra	%3,31,%%g2	! Don't move this insn\n"		\
+"	and	%2,%%g2,%%g2	! Don't move this insn\n"		\
+"	andcc	%%g0,0,%%g1	! Don't move this insn\n"		\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,%3,%%g1\n"						\
+"	mulscc	%%g1,0,%%g1\n"						\
+"	add	%%g1,%%g2,%0\n"						\
+"	rd	%%y,%1"							\
+	   : "=r" (w1), "=r" (w0) : "%rI" (u), "r" (v)			\
+	   : "%g1", "%g2" __AND_CLOBBER_CC)
+#endif
+#ifndef udiv_qrnnd
+#ifndef LONGLONG_STANDALONE
+#define udiv_qrnnd(q, r, n1, n0, d) \
+  do { UWtype __r;							\
+    (q) = __MPN(udiv_qrnnd) (&__r, (n1), (n0), (d));			\
+    (r) = __r;								\
+  } while (0)
+extern UWtype __MPN(udiv_qrnnd) (UWtype *, UWtype, UWtype, UWtype);
+#endif /* LONGLONG_STANDALONE */
+#endif /* udiv_qrnnd */
+#endif /* __sparc__ */
+
+#if defined (__sparc__) && W_TYPE_SIZE == 64
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  __asm__ (								\
+       "addcc	%r4,%5,%1\n"						\
+      "	addccc	%r6,%7,%%g0\n"						\
+      "	addc	%r2,%3,%0"						\
+       : "=r" (sh), "=&r" (sl)						\
+       : "rJ"  ((UDItype)(ah)), "rI" ((UDItype)(bh)),			\
+	 "%rJ" ((UDItype)(al)), "rI" ((UDItype)(bl)),			\
+	 "%rJ" ((UDItype)(al) >> 32), "rI" ((UDItype)(bl) >> 32)	\
+	   __CLOBBER_CC)
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  __asm__ (								\
+       "subcc	%r4,%5,%1\n"						\
+      "	subccc	%r6,%7,%%g0\n"						\
+      "	subc	%r2,%3,%0"						\
+       : "=r" (sh), "=&r" (sl)						\
+       : "rJ" ((UDItype)(ah)), "rI" ((UDItype)(bh)),			\
+	 "rJ" ((UDItype)(al)), "rI" ((UDItype)(bl)),			\
+	 "rJ" ((UDItype)(al) >> 32), "rI" ((UDItype)(bl) >> 32)		\
+	   __CLOBBER_CC)
+#if __VIS__ >= 0x300
+#undef add_ssaaaa
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  __asm__ (								\
+       "addcc	%r4, %5, %1\n"						\
+      "	addxc	%r2, %r3, %0"						\
+	  : "=r" (sh), "=&r" (sl)					\
+       : "rJ"  ((UDItype)(ah)), "rJ" ((UDItype)(bh)),			\
+	 "%rJ" ((UDItype)(al)), "rI" ((UDItype)(bl)) __CLOBBER_CC)
+#define umul_ppmm(ph, pl, m0, m1) \
+  do {									\
+    UDItype __m0 = (m0), __m1 = (m1);					\
+    (pl) = __m0 * __m1;							\
+    __asm__ ("umulxhi\t%2, %1, %0"					\
+	     : "=r" (ph)						\
+	     : "%r" (__m0), "r" (__m1));				\
+  } while (0)
+#define count_leading_zeros(count, x) \
+  __asm__ ("lzd\t%1,%0" : "=r" (count) : "r" (x))
+/* Needed by count_leading_zeros_32 in sparc64.h.  */
+#define COUNT_LEADING_ZEROS_NEED_CLZ_TAB
+#endif
+#endif
+
+#if (defined (__vax) || defined (__vax__)) && W_TYPE_SIZE == 32
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  __asm__ ("addl2 %5,%1\n\tadwc %3,%0"					\
+	   : "=g" (sh), "=&g" (sl)					\
+	   : "0"  ((USItype)(ah)), "g" ((USItype)(bh)),			\
+	     "%1" ((USItype)(al)), "g" ((USItype)(bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  __asm__ ("subl2 %5,%1\n\tsbwc %3,%0"					\
+	   : "=g" (sh), "=&g" (sl)					\
+	   : "0" ((USItype)(ah)), "g" ((USItype)(bh)),			\
+	     "1" ((USItype)(al)), "g" ((USItype)(bl)))
+#define smul_ppmm(xh, xl, m0, m1) \
+  do {									\
+    union {UDItype __ll;						\
+	   struct {USItype __l, __h;} __i;				\
+	  } __x;							\
+    USItype __m0 = (m0), __m1 = (m1);					\
+    __asm__ ("emul %1,%2,$0,%0"						\
+	     : "=g" (__x.__ll) : "g" (__m0), "g" (__m1));		\
+    (xh) = __x.__i.__h; (xl) = __x.__i.__l;				\
+  } while (0)
+#define sdiv_qrnnd(q, r, n1, n0, d) \
+  do {									\
+    union {DItype __ll;							\
+	   struct {SItype __l, __h;} __i;				\
+	  } __x;							\
+    __x.__i.__h = n1; __x.__i.__l = n0;					\
+    __asm__ ("ediv %3,%2,%0,%1"						\
+	     : "=g" (q), "=g" (r) : "g" (__x.__ll), "g" (d));		\
+  } while (0)
+#if 0
+/* FIXME: This instruction appears to be unimplemented on some systems (vax
+   8800 maybe). */
+#define count_trailing_zeros(count,x)					\
+  do {									\
+    __asm__ ("ffs 0, 31, %1, %0"					\
+	     : "=g" (count)						\
+	     : "g" ((USItype) (x)));					\
+  } while (0)
+#endif
+#endif /* vax */
+
+#if defined (__z8000__) && W_TYPE_SIZE == 16
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  __asm__ ("add	%H1,%H5\n\tadc	%H0,%H3"				\
+	   : "=r" (sh), "=&r" (sl)					\
+	   : "0"  ((unsigned int)(ah)), "r" ((unsigned int)(bh)),	\
+	     "%1" ((unsigned int)(al)), "rQR" ((unsigned int)(bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  __asm__ ("sub	%H1,%H5\n\tsbc	%H0,%H3"				\
+	   : "=r" (sh), "=&r" (sl)					\
+	   : "0" ((unsigned int)(ah)), "r" ((unsigned int)(bh)),	\
+	     "1" ((unsigned int)(al)), "rQR" ((unsigned int)(bl)))
+#define umul_ppmm(xh, xl, m0, m1) \
+  do {									\
+    union {long int __ll;						\
+	   struct {unsigned int __h, __l;} __i;				\
+	  } __x;							\
+    unsigned int __m0 = (m0), __m1 = (m1);				\
+    __asm__ ("mult	%S0,%H3"					\
+	     : "=r" (__x.__i.__h), "=r" (__x.__i.__l)			\
+	     : "%1" (m0), "rQR" (m1));					\
+    (xh) = __x.__i.__h; (xl) = __x.__i.__l;				\
+    (xh) += ((((signed int) __m0 >> 15) & __m1)				\
+	     + (((signed int) __m1 >> 15) & __m0));			\
+  } while (0)
+#endif /* __z8000__ */
+
+#endif /* __GNUC__ */
+
+#endif /* NO_ASM */
+
+
+/* FIXME: "sidi" here is highly doubtful, should sometimes be "diti".  */
+#if !defined (umul_ppmm) && defined (__umulsidi3)
+#define umul_ppmm(ph, pl, m0, m1) \
+  do {									\
+    UDWtype __ll = __umulsidi3 (m0, m1);				\
+    ph = (UWtype) (__ll >> W_TYPE_SIZE);				\
+    pl = (UWtype) __ll;							\
+  } while (0)
+#endif
+
+#if !defined (__umulsidi3)
+#define __umulsidi3(u, v) \
+  ({UWtype __hi, __lo;							\
+    umul_ppmm (__hi, __lo, u, v);					\
+    ((UDWtype) __hi << W_TYPE_SIZE) | __lo; })
+#endif
+
+
+#if defined (__cplusplus)
+#define __longlong_h_C "C"
+#else
+#define __longlong_h_C
+#endif
+
+/* Use mpn_umul_ppmm or mpn_udiv_qrnnd functions, if they exist.  The "_r"
+   forms have "reversed" arguments, meaning the pointer is last, which
+   sometimes allows better parameter passing, in particular on 64-bit
+   hppa. */
+
+#define mpn_umul_ppmm  __MPN(umul_ppmm)
+extern __longlong_h_C UWtype mpn_umul_ppmm (UWtype *, UWtype, UWtype);
+
+#if ! defined (umul_ppmm) && HAVE_NATIVE_mpn_umul_ppmm  \
+  && ! defined (LONGLONG_STANDALONE)
+#define umul_ppmm(wh, wl, u, v)						\
+  do {									\
+    UWtype __umul_ppmm__p0;						\
+    (wh) = mpn_umul_ppmm (&__umul_ppmm__p0, (UWtype) (u), (UWtype) (v));\
+    (wl) = __umul_ppmm__p0;						\
+  } while (0)
+#endif
+
+#define mpn_umul_ppmm_r  __MPN(umul_ppmm_r)
+extern __longlong_h_C UWtype mpn_umul_ppmm_r (UWtype, UWtype, UWtype *);
+
+#if ! defined (umul_ppmm) && HAVE_NATIVE_mpn_umul_ppmm_r	\
+  && ! defined (LONGLONG_STANDALONE)
+#define umul_ppmm(wh, wl, u, v)						\
+  do {									\
+    UWtype __umul_p0;							\
+    (wh) = mpn_umul_ppmm_r ((UWtype) (u), (UWtype) (v), &__umul_p0);	\
+    (wl) = __umul_p0;							\
+  } while (0)
+#endif
+
+#define mpn_udiv_qrnnd  __MPN(udiv_qrnnd)
+extern __longlong_h_C UWtype mpn_udiv_qrnnd (UWtype *, UWtype, UWtype, UWtype);
+
+#if ! defined (udiv_qrnnd) && HAVE_NATIVE_mpn_udiv_qrnnd	\
+  && ! defined (LONGLONG_STANDALONE)
+#define udiv_qrnnd(q, r, n1, n0, d)					\
+  do {									\
+    UWtype __udiv_qrnnd_r;						\
+    (q) = mpn_udiv_qrnnd (&__udiv_qrnnd_r,				\
+			  (UWtype) (n1), (UWtype) (n0), (UWtype) d);	\
+    (r) = __udiv_qrnnd_r;						\
+  } while (0)
+#endif
+
+#define mpn_udiv_qrnnd_r  __MPN(udiv_qrnnd_r)
+extern __longlong_h_C UWtype mpn_udiv_qrnnd_r (UWtype, UWtype, UWtype, UWtype *);
+
+#if ! defined (udiv_qrnnd) && HAVE_NATIVE_mpn_udiv_qrnnd_r	\
+  && ! defined (LONGLONG_STANDALONE)
+#define udiv_qrnnd(q, r, n1, n0, d)					\
+  do {									\
+    UWtype __udiv_qrnnd_r;						\
+    (q) = mpn_udiv_qrnnd_r ((UWtype) (n1), (UWtype) (n0), (UWtype) d,	\
+			    &__udiv_qrnnd_r);				\
+    (r) = __udiv_qrnnd_r;						\
+  } while (0)
+#endif
+
+
+/* If this machine has no inline assembler, use C macros.  */
+
+#if !defined (add_ssaaaa)
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  do {									\
+    UWtype __x;								\
+    __x = (al) + (bl);							\
+    (sh) = (ah) + (bh) + (__x < (al));					\
+    (sl) = __x;								\
+  } while (0)
+#endif
+
+#if !defined (sub_ddmmss)
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  do {									\
+    UWtype __x;								\
+    __x = (al) - (bl);							\
+    (sh) = (ah) - (bh) - ((al) < (bl));					\
+    (sl) = __x;								\
+  } while (0)
+#endif
+
+/* If we lack umul_ppmm but have smul_ppmm, define umul_ppmm in terms of
+   smul_ppmm.  */
+#if !defined (umul_ppmm) && defined (smul_ppmm)
+#define umul_ppmm(w1, w0, u, v)						\
+  do {									\
+    UWtype __w1;							\
+    UWtype __xm0 = (u), __xm1 = (v);					\
+    smul_ppmm (__w1, w0, __xm0, __xm1);					\
+    (w1) = __w1 + (-(__xm0 >> (W_TYPE_SIZE - 1)) & __xm1)		\
+		+ (-(__xm1 >> (W_TYPE_SIZE - 1)) & __xm0);		\
+  } while (0)
+#endif
+
+/* If we still don't have umul_ppmm, define it using plain C.
+
+   For reference, when this code is used for squaring (ie. u and v identical
+   expressions), gcc recognises __x1 and __x2 are the same and generates 3
+   multiplies, not 4.  The subsequent additions could be optimized a bit,
+   but the only place GMP currently uses such a square is mpn_sqr_basecase,
+   and chips obliged to use this generic C umul will have plenty of worse
+   performance problems than a couple of extra instructions on the diagonal
+   of sqr_basecase.  */
+
+#if !defined (umul_ppmm)
+#define umul_ppmm(w1, w0, u, v)						\
+  do {									\
+    UWtype __x0, __x1, __x2, __x3;					\
+    UHWtype __ul, __vl, __uh, __vh;					\
+    UWtype __u = (u), __v = (v);					\
+									\
+    __ul = __ll_lowpart (__u);						\
+    __uh = __ll_highpart (__u);						\
+    __vl = __ll_lowpart (__v);						\
+    __vh = __ll_highpart (__v);						\
+									\
+    __x0 = (UWtype) __ul * __vl;					\
+    __x1 = (UWtype) __ul * __vh;					\
+    __x2 = (UWtype) __uh * __vl;					\
+    __x3 = (UWtype) __uh * __vh;					\
+									\
+    __x1 += __ll_highpart (__x0);/* this can't give carry */		\
+    __x1 += __x2;		/* but this indeed can */		\
+    if (__x1 < __x2)		/* did we get it? */			\
+      __x3 += __ll_B;		/* yes, add it in the proper pos. */	\
+									\
+    (w1) = __x3 + __ll_highpart (__x1);					\
+    (w0) = (__x1 << W_TYPE_SIZE/2) + __ll_lowpart (__x0);		\
+  } while (0)
+#endif
+
+/* If we don't have smul_ppmm, define it using umul_ppmm (which surely will
+   exist in one form or another.  */
+#if !defined (smul_ppmm)
+#define smul_ppmm(w1, w0, u, v)						\
+  do {									\
+    UWtype __w1;							\
+    UWtype __xm0 = (u), __xm1 = (v);					\
+    umul_ppmm (__w1, w0, __xm0, __xm1);					\
+    (w1) = __w1 - (-(__xm0 >> (W_TYPE_SIZE - 1)) & __xm1)		\
+		- (-(__xm1 >> (W_TYPE_SIZE - 1)) & __xm0);		\
+  } while (0)
+#endif
+
+/* Define this unconditionally, so it can be used for debugging.  */
+#define __udiv_qrnnd_c(q, r, n1, n0, d) \
+  do {									\
+    UWtype __d1, __d0, __q1, __q0, __r1, __r0, __m;			\
+									\
+    ASSERT ((d) != 0);							\
+    ASSERT ((n1) < (d));						\
+									\
+    __d1 = __ll_highpart (d);						\
+    __d0 = __ll_lowpart (d);						\
+									\
+    __q1 = (n1) / __d1;							\
+    __r1 = (n1) - __q1 * __d1;						\
+    __m = __q1 * __d0;							\
+    __r1 = __r1 * __ll_B | __ll_highpart (n0);				\
+    if (__r1 < __m)							\
+      {									\
+	__q1--, __r1 += (d);						\
+	if (__r1 >= (d)) /* i.e. we didn't get carry when adding to __r1 */\
+	  if (__r1 < __m)						\
+	    __q1--, __r1 += (d);					\
+      }									\
+    __r1 -= __m;							\
+									\
+    __q0 = __r1 / __d1;							\
+    __r0 = __r1  - __q0 * __d1;						\
+    __m = __q0 * __d0;							\
+    __r0 = __r0 * __ll_B | __ll_lowpart (n0);				\
+    if (__r0 < __m)							\
+      {									\
+	__q0--, __r0 += (d);						\
+	if (__r0 >= (d))						\
+	  if (__r0 < __m)						\
+	    __q0--, __r0 += (d);					\
+      }									\
+    __r0 -= __m;							\
+									\
+    (q) = __q1 * __ll_B | __q0;						\
+    (r) = __r0;								\
+  } while (0)
+
+/* If the processor has no udiv_qrnnd but sdiv_qrnnd, go through
+   __udiv_w_sdiv (defined in libgcc or elsewhere).  */
+#if !defined (udiv_qrnnd) && defined (sdiv_qrnnd) \
+  && ! defined (LONGLONG_STANDALONE)
+#define udiv_qrnnd(q, r, nh, nl, d) \
+  do {									\
+    UWtype __r;								\
+    (q) = __MPN(udiv_w_sdiv) (&__r, nh, nl, d);				\
+    (r) = __r;								\
+  } while (0)
+__GMP_DECLSPEC UWtype __MPN(udiv_w_sdiv) (UWtype *, UWtype, UWtype, UWtype);
+#endif
+
+/* If udiv_qrnnd was not defined for this processor, use __udiv_qrnnd_c.  */
+#if !defined (udiv_qrnnd)
+#define UDIV_NEEDS_NORMALIZATION 1
+#define udiv_qrnnd __udiv_qrnnd_c
+#endif
+
+#if !defined (count_leading_zeros)
+#define count_leading_zeros(count, x) \
+  do {									\
+    UWtype __xr = (x);							\
+    UWtype __a;								\
+									\
+    if (W_TYPE_SIZE == 32)						\
+      {									\
+	__a = __xr < ((UWtype) 1 << 2*__BITS4)				\
+	  ? (__xr < ((UWtype) 1 << __BITS4) ? 1 : __BITS4 + 1)		\
+	  : (__xr < ((UWtype) 1 << 3*__BITS4) ? 2*__BITS4 + 1		\
+	  : 3*__BITS4 + 1);						\
+      }									\
+    else								\
+      {									\
+	for (__a = W_TYPE_SIZE - 8; __a > 0; __a -= 8)			\
+	  if (((__xr >> __a) & 0xff) != 0)				\
+	    break;							\
+	++__a;								\
+      }									\
+									\
+    (count) = W_TYPE_SIZE + 1 - __a - __clz_tab[__xr >> __a];		\
+  } while (0)
+/* This version gives a well-defined value for zero. */
+#define COUNT_LEADING_ZEROS_0 (W_TYPE_SIZE - 1)
+#define COUNT_LEADING_ZEROS_NEED_CLZ_TAB
+#define COUNT_LEADING_ZEROS_SLOW
+#endif
+
+/* clz_tab needed by mpn/x86/pentium/mod_1.asm in a fat binary */
+#if HAVE_HOST_CPU_FAMILY_x86 && WANT_FAT_BINARY
+#define COUNT_LEADING_ZEROS_NEED_CLZ_TAB
+#endif
+
+#ifdef COUNT_LEADING_ZEROS_NEED_CLZ_TAB
+extern const unsigned char __GMP_DECLSPEC __clz_tab[129];
+#endif
+
+#if !defined (count_trailing_zeros)
+#if !defined (COUNT_LEADING_ZEROS_SLOW)
+/* Define count_trailing_zeros using an asm count_leading_zeros.  */
+#define count_trailing_zeros(count, x)					\
+  do {									\
+    UWtype __ctz_x = (x);						\
+    UWtype __ctz_c;							\
+    ASSERT (__ctz_x != 0);						\
+    count_leading_zeros (__ctz_c, __ctz_x & -__ctz_x);			\
+    (count) = W_TYPE_SIZE - 1 - __ctz_c;				\
+  } while (0)
+#else
+/* Define count_trailing_zeros in plain C, assuming small counts are common.
+   We use clz_tab without ado, since the C count_leading_zeros above will have
+   pulled it in.  */
+#define count_trailing_zeros(count, x)					\
+  do {									\
+    UWtype __ctz_x = (x);						\
+    int __ctz_c;							\
+									\
+    if (LIKELY ((__ctz_x & 0xff) != 0))					\
+      (count) = __clz_tab[__ctz_x & -__ctz_x] - 2;			\
+    else								\
+      {									\
+	for (__ctz_c = 8 - 2; __ctz_c < W_TYPE_SIZE - 2; __ctz_c += 8)	\
+	  {								\
+	    __ctz_x >>= 8;						\
+	    if (LIKELY ((__ctz_x & 0xff) != 0))				\
+	      break;							\
+	  }								\
+									\
+	(count) = __ctz_c + __clz_tab[__ctz_x & -__ctz_x];		\
+      }									\
+  } while (0)
+#endif
+#endif
+
+#ifndef UDIV_NEEDS_NORMALIZATION
+#define UDIV_NEEDS_NORMALIZATION 0
+#endif
+
+/* Whether udiv_qrnnd is actually implemented with udiv_qrnnd_preinv, and
+   that hence the latter should always be used.  */
+#ifndef UDIV_PREINV_ALWAYS
+#define UDIV_PREINV_ALWAYS 0
+#endif
diff --git a/third_party/gmp/ltmain.sh b/third_party/gmp/ltmain.sh
new file mode 100644
index 0000000..0f0a2da
--- /dev/null
+++ b/third_party/gmp/ltmain.sh
@@ -0,0 +1,11147 @@
+#! /bin/sh
+## DO NOT EDIT - This file generated from ./build-aux/ltmain.in
+##               by inline-source v2014-01-03.01
+
+# libtool (GNU libtool) 2.4.6
+# Provide generalized library-building support services.
+# Written by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+
+# Copyright (C) 1996-2015 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions.  There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# GNU Libtool is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+
+PROGRAM=libtool
+PACKAGE=libtool
+VERSION=2.4.6
+package_revision=2.4.6
+
+
+## ------ ##
+## Usage. ##
+## ------ ##
+
+# Run './libtool --help' for help with using this script from the
+# command line.
+
+
+## ------------------------------- ##
+## User overridable command paths. ##
+## ------------------------------- ##
+
+# After configure completes, it has a better idea of some of the
+# shell tools we need than the defaults used by the functions shared
+# with bootstrap, so set those here where they can still be over-
+# ridden by the user, but otherwise take precedence.
+
+: ${AUTOCONF="autoconf"}
+: ${AUTOMAKE="automake"}
+
+
+## -------------------------- ##
+## Source external libraries. ##
+## -------------------------- ##
+
+# Much of our low-level functionality needs to be sourced from external
+# libraries, which are installed to $pkgauxdir.
+
+# Set a version string for this script.
+scriptversion=2015-01-20.17; # UTC
+
+# General shell script boiler plate, and helper functions.
+# Written by Gary V. Vaughan, 2004
+
+# Copyright (C) 2004-2015 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions.  There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+
+# As a special exception to the GNU General Public License, if you distribute
+# this file as part of a program or library that is built using GNU Libtool,
+# you may include this file under the same distribution terms that you use
+# for the rest of that program.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNES FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Please report bugs or propose patches to gary@gnu.org.
+
+
+## ------ ##
+## Usage. ##
+## ------ ##
+
+# Evaluate this file near the top of your script to gain access to
+# the functions and variables defined here:
+#
+#   . `echo "$0" | ${SED-sed} 's|[^/]*$||'`/build-aux/funclib.sh
+#
+# If you need to override any of the default environment variable
+# settings, do that before evaluating this file.
+
+
+## -------------------- ##
+## Shell normalisation. ##
+## -------------------- ##
+
+# Some shells need a little help to be as Bourne compatible as possible.
+# Before doing anything else, make sure all that help has been provided!
+
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac
+fi
+
+# NLS nuisances: We save the old values in case they are required later.
+_G_user_locale=
+_G_safe_locale=
+for _G_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
+do
+  eval "if test set = \"\${$_G_var+set}\"; then
+          save_$_G_var=\$$_G_var
+          $_G_var=C
+	  export $_G_var
+	  _G_user_locale=\"$_G_var=\\\$save_\$_G_var; \$_G_user_locale\"
+	  _G_safe_locale=\"$_G_var=C; \$_G_safe_locale\"
+	fi"
+done
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Make sure IFS has a sensible default
+sp=' '
+nl='
+'
+IFS="$sp	$nl"
+
+# There are apparently some retarded systems that use ';' as a PATH separator!
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+
+
+## ------------------------- ##
+## Locate command utilities. ##
+## ------------------------- ##
+
+
+# func_executable_p FILE
+# ----------------------
+# Check that FILE is an executable regular file.
+func_executable_p ()
+{
+    test -f "$1" && test -x "$1"
+}
+
+
+# func_path_progs PROGS_LIST CHECK_FUNC [PATH]
+# --------------------------------------------
+# Search for either a program that responds to --version with output
+# containing "GNU", or else returned by CHECK_FUNC otherwise, by
+# trying all the directories in PATH with each of the elements of
+# PROGS_LIST.
+#
+# CHECK_FUNC should accept the path to a candidate program, and
+# set $func_check_prog_result if it truncates its output less than
+# $_G_path_prog_max characters.
+func_path_progs ()
+{
+    _G_progs_list=$1
+    _G_check_func=$2
+    _G_PATH=${3-"$PATH"}
+
+    _G_path_prog_max=0
+    _G_path_prog_found=false
+    _G_save_IFS=$IFS; IFS=${PATH_SEPARATOR-:}
+    for _G_dir in $_G_PATH; do
+      IFS=$_G_save_IFS
+      test -z "$_G_dir" && _G_dir=.
+      for _G_prog_name in $_G_progs_list; do
+        for _exeext in '' .EXE; do
+          _G_path_prog=$_G_dir/$_G_prog_name$_exeext
+          func_executable_p "$_G_path_prog" || continue
+          case `"$_G_path_prog" --version 2>&1` in
+            *GNU*) func_path_progs_result=$_G_path_prog _G_path_prog_found=: ;;
+            *)     $_G_check_func $_G_path_prog
+		   func_path_progs_result=$func_check_prog_result
+		   ;;
+          esac
+          $_G_path_prog_found && break 3
+        done
+      done
+    done
+    IFS=$_G_save_IFS
+    test -z "$func_path_progs_result" && {
+      echo "no acceptable sed could be found in \$PATH" >&2
+      exit 1
+    }
+}
+
+
+# We want to be able to use the functions in this file before configure
+# has figured out where the best binaries are kept, which means we have
+# to search for them ourselves - except when the results are already set
+# where we skip the searches.
+
+# Unless the user overrides by setting SED, search the path for either GNU
+# sed, or the sed that truncates its output the least.
+test -z "$SED" && {
+  _G_sed_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
+  for _G_i in 1 2 3 4 5 6 7; do
+    _G_sed_script=$_G_sed_script$nl$_G_sed_script
+  done
+  echo "$_G_sed_script" 2>/dev/null | sed 99q >conftest.sed
+  _G_sed_script=
+
+  func_check_prog_sed ()
+  {
+    _G_path_prog=$1
+
+    _G_count=0
+    printf 0123456789 >conftest.in
+    while :
+    do
+      cat conftest.in conftest.in >conftest.tmp
+      mv conftest.tmp conftest.in
+      cp conftest.in conftest.nl
+      echo '' >> conftest.nl
+      "$_G_path_prog" -f conftest.sed <conftest.nl >conftest.out 2>/dev/null || break
+      diff conftest.out conftest.nl >/dev/null 2>&1 || break
+      _G_count=`expr $_G_count + 1`
+      if test "$_G_count" -gt "$_G_path_prog_max"; then
+        # Best one so far, save it but keep looking for a better one
+        func_check_prog_result=$_G_path_prog
+        _G_path_prog_max=$_G_count
+      fi
+      # 10*(2^10) chars as input seems more than enough
+      test 10 -lt "$_G_count" && break
+    done
+    rm -f conftest.in conftest.tmp conftest.nl conftest.out
+  }
+
+  func_path_progs "sed gsed" func_check_prog_sed $PATH:/usr/xpg4/bin
+  rm -f conftest.sed
+  SED=$func_path_progs_result
+}
+
+
+# Unless the user overrides by setting GREP, search the path for either GNU
+# grep, or the grep that truncates its output the least.
+test -z "$GREP" && {
+  func_check_prog_grep ()
+  {
+    _G_path_prog=$1
+
+    _G_count=0
+    _G_path_prog_max=0
+    printf 0123456789 >conftest.in
+    while :
+    do
+      cat conftest.in conftest.in >conftest.tmp
+      mv conftest.tmp conftest.in
+      cp conftest.in conftest.nl
+      echo 'GREP' >> conftest.nl
+      "$_G_path_prog" -e 'GREP$' -e '-(cannot match)-' <conftest.nl >conftest.out 2>/dev/null || break
+      diff conftest.out conftest.nl >/dev/null 2>&1 || break
+      _G_count=`expr $_G_count + 1`
+      if test "$_G_count" -gt "$_G_path_prog_max"; then
+        # Best one so far, save it but keep looking for a better one
+        func_check_prog_result=$_G_path_prog
+        _G_path_prog_max=$_G_count
+      fi
+      # 10*(2^10) chars as input seems more than enough
+      test 10 -lt "$_G_count" && break
+    done
+    rm -f conftest.in conftest.tmp conftest.nl conftest.out
+  }
+
+  func_path_progs "grep ggrep" func_check_prog_grep $PATH:/usr/xpg4/bin
+  GREP=$func_path_progs_result
+}
+
+
+## ------------------------------- ##
+## User overridable command paths. ##
+## ------------------------------- ##
+
+# All uppercase variable names are used for environment variables.  These
+# variables can be overridden by the user before calling a script that
+# uses them if a suitable command of that name is not already available
+# in the command search PATH.
+
+: ${CP="cp -f"}
+: ${ECHO="printf %s\n"}
+: ${EGREP="$GREP -E"}
+: ${FGREP="$GREP -F"}
+: ${LN_S="ln -s"}
+: ${MAKE="make"}
+: ${MKDIR="mkdir"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+: ${SHELL="${CONFIG_SHELL-/bin/sh}"}
+
+
+## -------------------- ##
+## Useful sed snippets. ##
+## -------------------- ##
+
+sed_dirname='s|/[^/]*$||'
+sed_basename='s|^.*/||'
+
+# Sed substitution that helps us do robust quoting.  It backslashifies
+# metacharacters that are still active within double-quoted strings.
+sed_quote_subst='s|\([`"$\\]\)|\\\1|g'
+
+# Same as above, but do not quote variable references.
+sed_double_quote_subst='s/\(["`\\]\)/\\\1/g'
+
+# Sed substitution that turns a string into a regex matching for the
+# string literally.
+sed_make_literal_regex='s|[].[^$\\*\/]|\\&|g'
+
+# Sed substitution that converts a w32 file name or path
+# that contains forward slashes, into one that contains
+# (escaped) backslashes.  A very naive implementation.
+sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g'
+
+# Re-'\' parameter expansions in output of sed_double_quote_subst that
+# were '\'-ed in input to the same.  If an odd number of '\' preceded a
+# '$' in input to sed_double_quote_subst, that '$' was protected from
+# expansion.  Since each input '\' is now two '\'s, look for any number
+# of runs of four '\'s followed by two '\'s and then a '$'.  '\' that '$'.
+_G_bs='\\'
+_G_bs2='\\\\'
+_G_bs4='\\\\\\\\'
+_G_dollar='\$'
+sed_double_backslash="\
+  s/$_G_bs4/&\\
+/g
+  s/^$_G_bs2$_G_dollar/$_G_bs&/
+  s/\\([^$_G_bs]\\)$_G_bs2$_G_dollar/\\1$_G_bs2$_G_bs$_G_dollar/g
+  s/\n//g"
+
+
+## ----------------- ##
+## Global variables. ##
+## ----------------- ##
+
+# Except for the global variables explicitly listed below, the following
+# functions in the '^func_' namespace, and the '^require_' namespace
+# variables initialised in the 'Resource management' section, sourcing
+# this file will not pollute your global namespace with anything
+# else. There's no portable way to scope variables in Bourne shell
+# though, so actually running these functions will sometimes place
+# results into a variable named after the function, and often use
+# temporary variables in the '^_G_' namespace. If you are careful to
+# avoid using those namespaces casually in your sourcing script, things
+# should continue to work as you expect. And, of course, you can freely
+# overwrite any of the functions or variables defined here before
+# calling anything to customize them.
+
+EXIT_SUCCESS=0
+EXIT_FAILURE=1
+EXIT_MISMATCH=63  # $? = 63 is used to indicate version mismatch to missing.
+EXIT_SKIP=77	  # $? = 77 is used to indicate a skipped test to automake.
+
+# Allow overriding, eg assuming that you follow the convention of
+# putting '$debug_cmd' at the start of all your functions, you can get
+# bash to show function call trace with:
+#
+#    debug_cmd='eval echo "${FUNCNAME[0]} $*" >&2' bash your-script-name
+debug_cmd=${debug_cmd-":"}
+exit_cmd=:
+
+# By convention, finish your script with:
+#
+#    exit $exit_status
+#
+# so that you can set exit_status to non-zero if you want to indicate
+# something went wrong during execution without actually bailing out at
+# the point of failure.
+exit_status=$EXIT_SUCCESS
+
+# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh
+# is ksh but when the shell is invoked as "sh" and the current value of
+# the _XPG environment variable is not equal to 1 (one), the special
+# positional parameter $0, within a function call, is the name of the
+# function.
+progpath=$0
+
+# The name of this program.
+progname=`$ECHO "$progpath" |$SED "$sed_basename"`
+
+# Make sure we have an absolute progpath for reexecution:
+case $progpath in
+  [\\/]*|[A-Za-z]:\\*) ;;
+  *[\\/]*)
+     progdir=`$ECHO "$progpath" |$SED "$sed_dirname"`
+     progdir=`cd "$progdir" && pwd`
+     progpath=$progdir/$progname
+     ;;
+  *)
+     _G_IFS=$IFS
+     IFS=${PATH_SEPARATOR-:}
+     for progdir in $PATH; do
+       IFS=$_G_IFS
+       test -x "$progdir/$progname" && break
+     done
+     IFS=$_G_IFS
+     test -n "$progdir" || progdir=`pwd`
+     progpath=$progdir/$progname
+     ;;
+esac
+
+
+## ----------------- ##
+## Standard options. ##
+## ----------------- ##
+
+# The following options affect the operation of the functions defined
+# below, and should be set appropriately depending on run-time para-
+# meters passed on the command line.
+
+opt_dry_run=false
+opt_quiet=false
+opt_verbose=false
+
+# Categories 'all' and 'none' are always available.  Append any others
+# you will pass as the first argument to func_warning from your own
+# code.
+warning_categories=
+
+# By default, display warnings according to 'opt_warning_types'.  Set
+# 'warning_func'  to ':' to elide all warnings, or func_fatal_error to
+# treat the next displayed warning as a fatal error.
+warning_func=func_warn_and_continue
+
+# Set to 'all' to display all warnings, 'none' to suppress all
+# warnings, or a space delimited list of some subset of
+# 'warning_categories' to display only the listed warnings.
+opt_warning_types=all
+
+
+## -------------------- ##
+## Resource management. ##
+## -------------------- ##
+
+# This section contains definitions for functions that each ensure a
+# particular resource (a file, or a non-empty configuration variable for
+# example) is available, and if appropriate to extract default values
+# from pertinent package files. Call them using their associated
+# 'require_*' variable to ensure that they are executed, at most, once.
+#
+# It's entirely deliberate that calling these functions can set
+# variables that don't obey the namespace limitations obeyed by the rest
+# of this file, in order that that they be as useful as possible to
+# callers.
+
+
+# require_term_colors
+# -------------------
+# Allow display of bold text on terminals that support it.
+require_term_colors=func_require_term_colors
+func_require_term_colors ()
+{
+    $debug_cmd
+
+    test -t 1 && {
+      # COLORTERM and USE_ANSI_COLORS environment variables take
+      # precedence, because most terminfo databases neglect to describe
+      # whether color sequences are supported.
+      test -n "${COLORTERM+set}" && : ${USE_ANSI_COLORS="1"}
+
+      if test 1 = "$USE_ANSI_COLORS"; then
+        # Standard ANSI escape sequences
+        tc_reset=''
+        tc_bold='';   tc_standout=''
+        tc_red='';   tc_green=''
+        tc_blue='';  tc_cyan=''
+      else
+        # Otherwise trust the terminfo database after all.
+        test -n "`tput sgr0 2>/dev/null`" && {
+          tc_reset=`tput sgr0`
+          test -n "`tput bold 2>/dev/null`" && tc_bold=`tput bold`
+          tc_standout=$tc_bold
+          test -n "`tput smso 2>/dev/null`" && tc_standout=`tput smso`
+          test -n "`tput setaf 1 2>/dev/null`" && tc_red=`tput setaf 1`
+          test -n "`tput setaf 2 2>/dev/null`" && tc_green=`tput setaf 2`
+          test -n "`tput setaf 4 2>/dev/null`" && tc_blue=`tput setaf 4`
+          test -n "`tput setaf 5 2>/dev/null`" && tc_cyan=`tput setaf 5`
+        }
+      fi
+    }
+
+    require_term_colors=:
+}
+
+
+## ----------------- ##
+## Function library. ##
+## ----------------- ##
+
+# This section contains a variety of useful functions to call in your
+# scripts. Take note of the portable wrappers for features provided by
+# some modern shells, which will fall back to slower equivalents on
+# less featureful shells.
+
+
+# func_append VAR VALUE
+# ---------------------
+# Append VALUE onto the existing contents of VAR.
+
+  # We should try to minimise forks, especially on Windows where they are
+  # unreasonably slow, so skip the feature probes when bash or zsh are
+  # being used:
+  if test set = "${BASH_VERSION+set}${ZSH_VERSION+set}"; then
+    : ${_G_HAVE_ARITH_OP="yes"}
+    : ${_G_HAVE_XSI_OPS="yes"}
+    # The += operator was introduced in bash 3.1
+    case $BASH_VERSION in
+      [12].* | 3.0 | 3.0*) ;;
+      *)
+        : ${_G_HAVE_PLUSEQ_OP="yes"}
+        ;;
+    esac
+  fi
+
+  # _G_HAVE_PLUSEQ_OP
+  # Can be empty, in which case the shell is probed, "yes" if += is
+  # useable or anything else if it does not work.
+  test -z "$_G_HAVE_PLUSEQ_OP" \
+    && (eval 'x=a; x+=" b"; test "a b" = "$x"') 2>/dev/null \
+    && _G_HAVE_PLUSEQ_OP=yes
+
+if test yes = "$_G_HAVE_PLUSEQ_OP"
+then
+  # This is an XSI compatible shell, allowing a faster implementation...
+  eval 'func_append ()
+  {
+    $debug_cmd
+
+    eval "$1+=\$2"
+  }'
+else
+  # ...otherwise fall back to using expr, which is often a shell builtin.
+  func_append ()
+  {
+    $debug_cmd
+
+    eval "$1=\$$1\$2"
+  }
+fi
+
+
+# func_append_quoted VAR VALUE
+# ----------------------------
+# Quote VALUE and append to the end of shell variable VAR, separated
+# by a space.
+if test yes = "$_G_HAVE_PLUSEQ_OP"; then
+  eval 'func_append_quoted ()
+  {
+    $debug_cmd
+
+    func_quote_for_eval "$2"
+    eval "$1+=\\ \$func_quote_for_eval_result"
+  }'
+else
+  func_append_quoted ()
+  {
+    $debug_cmd
+
+    func_quote_for_eval "$2"
+    eval "$1=\$$1\\ \$func_quote_for_eval_result"
+  }
+fi
+
+
+# func_append_uniq VAR VALUE
+# --------------------------
+# Append unique VALUE onto the existing contents of VAR, assuming
+# entries are delimited by the first character of VALUE.  For example:
+#
+#   func_append_uniq options " --another-option option-argument"
+#
+# will only append to $options if " --another-option option-argument "
+# is not already present somewhere in $options already (note spaces at
+# each end implied by leading space in second argument).
+func_append_uniq ()
+{
+    $debug_cmd
+
+    eval _G_current_value='`$ECHO $'$1'`'
+    _G_delim=`expr "$2" : '\(.\)'`
+
+    case $_G_delim$_G_current_value$_G_delim in
+      *"$2$_G_delim"*) ;;
+      *) func_append "$@" ;;
+    esac
+}
+
+
+# func_arith TERM...
+# ------------------
+# Set func_arith_result to the result of evaluating TERMs.
+  test -z "$_G_HAVE_ARITH_OP" \
+    && (eval 'test 2 = $(( 1 + 1 ))') 2>/dev/null \
+    && _G_HAVE_ARITH_OP=yes
+
+if test yes = "$_G_HAVE_ARITH_OP"; then
+  eval 'func_arith ()
+  {
+    $debug_cmd
+
+    func_arith_result=$(( $* ))
+  }'
+else
+  func_arith ()
+  {
+    $debug_cmd
+
+    func_arith_result=`expr "$@"`
+  }
+fi
+
+
+# func_basename FILE
+# ------------------
+# Set func_basename_result to FILE with everything up to and including
+# the last / stripped.
+if test yes = "$_G_HAVE_XSI_OPS"; then
+  # If this shell supports suffix pattern removal, then use it to avoid
+  # forking. Hide the definitions single quotes in case the shell chokes
+  # on unsupported syntax...
+  _b='func_basename_result=${1##*/}'
+  _d='case $1 in
+        */*) func_dirname_result=${1%/*}$2 ;;
+        *  ) func_dirname_result=$3        ;;
+      esac'
+
+else
+  # ...otherwise fall back to using sed.
+  _b='func_basename_result=`$ECHO "$1" |$SED "$sed_basename"`'
+  _d='func_dirname_result=`$ECHO "$1"  |$SED "$sed_dirname"`
+      if test "X$func_dirname_result" = "X$1"; then
+        func_dirname_result=$3
+      else
+        func_append func_dirname_result "$2"
+      fi'
+fi
+
+eval 'func_basename ()
+{
+    $debug_cmd
+
+    '"$_b"'
+}'
+
+
+# func_dirname FILE APPEND NONDIR_REPLACEMENT
+# -------------------------------------------
+# Compute the dirname of FILE.  If nonempty, add APPEND to the result,
+# otherwise set result to NONDIR_REPLACEMENT.
+eval 'func_dirname ()
+{
+    $debug_cmd
+
+    '"$_d"'
+}'
+
+
+# func_dirname_and_basename FILE APPEND NONDIR_REPLACEMENT
+# --------------------------------------------------------
+# Perform func_basename and func_dirname in a single function
+# call:
+#   dirname:  Compute the dirname of FILE.  If nonempty,
+#             add APPEND to the result, otherwise set result
+#             to NONDIR_REPLACEMENT.
+#             value returned in "$func_dirname_result"
+#   basename: Compute filename of FILE.
+#             value retuned in "$func_basename_result"
+# For efficiency, we do not delegate to the functions above but instead
+# duplicate the functionality here.
+eval 'func_dirname_and_basename ()
+{
+    $debug_cmd
+
+    '"$_b"'
+    '"$_d"'
+}'
+
+
+# func_echo ARG...
+# ----------------
+# Echo program name prefixed message.
+func_echo ()
+{
+    $debug_cmd
+
+    _G_message=$*
+
+    func_echo_IFS=$IFS
+    IFS=$nl
+    for _G_line in $_G_message; do
+      IFS=$func_echo_IFS
+      $ECHO "$progname: $_G_line"
+    done
+    IFS=$func_echo_IFS
+}
+
+
+# func_echo_all ARG...
+# --------------------
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+    $ECHO "$*"
+}
+
+
+# func_echo_infix_1 INFIX ARG...
+# ------------------------------
+# Echo program name, followed by INFIX on the first line, with any
+# additional lines not showing INFIX.
+func_echo_infix_1 ()
+{
+    $debug_cmd
+
+    $require_term_colors
+
+    _G_infix=$1; shift
+    _G_indent=$_G_infix
+    _G_prefix="$progname: $_G_infix: "
+    _G_message=$*
+
+    # Strip color escape sequences before counting printable length
+    for _G_tc in "$tc_reset" "$tc_bold" "$tc_standout" "$tc_red" "$tc_green" "$tc_blue" "$tc_cyan"
+    do
+      test -n "$_G_tc" && {
+        _G_esc_tc=`$ECHO "$_G_tc" | $SED "$sed_make_literal_regex"`
+        _G_indent=`$ECHO "$_G_indent" | $SED "s|$_G_esc_tc||g"`
+      }
+    done
+    _G_indent="$progname: "`echo "$_G_indent" | $SED 's|.| |g'`"  " ## exclude from sc_prohibit_nested_quotes
+
+    func_echo_infix_1_IFS=$IFS
+    IFS=$nl
+    for _G_line in $_G_message; do
+      IFS=$func_echo_infix_1_IFS
+      $ECHO "$_G_prefix$tc_bold$_G_line$tc_reset" >&2
+      _G_prefix=$_G_indent
+    done
+    IFS=$func_echo_infix_1_IFS
+}
+
+
+# func_error ARG...
+# -----------------
+# Echo program name prefixed message to standard error.
+func_error ()
+{
+    $debug_cmd
+
+    $require_term_colors
+
+    func_echo_infix_1 "  $tc_standout${tc_red}error$tc_reset" "$*" >&2
+}
+
+
+# func_fatal_error ARG...
+# -----------------------
+# Echo program name prefixed message to standard error, and exit.
+func_fatal_error ()
+{
+    $debug_cmd
+
+    func_error "$*"
+    exit $EXIT_FAILURE
+}
+
+
+# func_grep EXPRESSION FILENAME
+# -----------------------------
+# Check whether EXPRESSION matches any line of FILENAME, without output.
+func_grep ()
+{
+    $debug_cmd
+
+    $GREP "$1" "$2" >/dev/null 2>&1
+}
+
+
+# func_len STRING
+# ---------------
+# Set func_len_result to the length of STRING. STRING may not
+# start with a hyphen.
+  test -z "$_G_HAVE_XSI_OPS" \
+    && (eval 'x=a/b/c;
+      test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \
+    && _G_HAVE_XSI_OPS=yes
+
+if test yes = "$_G_HAVE_XSI_OPS"; then
+  eval 'func_len ()
+  {
+    $debug_cmd
+
+    func_len_result=${#1}
+  }'
+else
+  func_len ()
+  {
+    $debug_cmd
+
+    func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len`
+  }
+fi
+
+
+# func_mkdir_p DIRECTORY-PATH
+# ---------------------------
+# Make sure the entire path to DIRECTORY-PATH is available.
+func_mkdir_p ()
+{
+    $debug_cmd
+
+    _G_directory_path=$1
+    _G_dir_list=
+
+    if test -n "$_G_directory_path" && test : != "$opt_dry_run"; then
+
+      # Protect directory names starting with '-'
+      case $_G_directory_path in
+        -*) _G_directory_path=./$_G_directory_path ;;
+      esac
+
+      # While some portion of DIR does not yet exist...
+      while test ! -d "$_G_directory_path"; do
+        # ...make a list in topmost first order.  Use a colon delimited
+	# list incase some portion of path contains whitespace.
+        _G_dir_list=$_G_directory_path:$_G_dir_list
+
+        # If the last portion added has no slash in it, the list is done
+        case $_G_directory_path in */*) ;; *) break ;; esac
+
+        # ...otherwise throw away the child directory and loop
+        _G_directory_path=`$ECHO "$_G_directory_path" | $SED -e "$sed_dirname"`
+      done
+      _G_dir_list=`$ECHO "$_G_dir_list" | $SED 's|:*$||'`
+
+      func_mkdir_p_IFS=$IFS; IFS=:
+      for _G_dir in $_G_dir_list; do
+	IFS=$func_mkdir_p_IFS
+        # mkdir can fail with a 'File exist' error if two processes
+        # try to create one of the directories concurrently.  Don't
+        # stop in that case!
+        $MKDIR "$_G_dir" 2>/dev/null || :
+      done
+      IFS=$func_mkdir_p_IFS
+
+      # Bail out if we (or some other process) failed to create a directory.
+      test -d "$_G_directory_path" || \
+        func_fatal_error "Failed to create '$1'"
+    fi
+}
+
+
+# func_mktempdir [BASENAME]
+# -------------------------
+# Make a temporary directory that won't clash with other running
+# libtool processes, and avoids race conditions if possible.  If
+# given, BASENAME is the basename for that directory.
+func_mktempdir ()
+{
+    $debug_cmd
+
+    _G_template=${TMPDIR-/tmp}/${1-$progname}
+
+    if test : = "$opt_dry_run"; then
+      # Return a directory name, but don't create it in dry-run mode
+      _G_tmpdir=$_G_template-$$
+    else
+
+      # If mktemp works, use that first and foremost
+      _G_tmpdir=`mktemp -d "$_G_template-XXXXXXXX" 2>/dev/null`
+
+      if test ! -d "$_G_tmpdir"; then
+        # Failing that, at least try and use $RANDOM to avoid a race
+        _G_tmpdir=$_G_template-${RANDOM-0}$$
+
+        func_mktempdir_umask=`umask`
+        umask 0077
+        $MKDIR "$_G_tmpdir"
+        umask $func_mktempdir_umask
+      fi
+
+      # If we're not in dry-run mode, bomb out on failure
+      test -d "$_G_tmpdir" || \
+        func_fatal_error "cannot create temporary directory '$_G_tmpdir'"
+    fi
+
+    $ECHO "$_G_tmpdir"
+}
+
+
+# func_normal_abspath PATH
+# ------------------------
+# Remove doubled-up and trailing slashes, "." path components,
+# and cancel out any ".." path components in PATH after making
+# it an absolute path.
+func_normal_abspath ()
+{
+    $debug_cmd
+
+    # These SED scripts presuppose an absolute path with a trailing slash.
+    _G_pathcar='s|^/\([^/]*\).*$|\1|'
+    _G_pathcdr='s|^/[^/]*||'
+    _G_removedotparts=':dotsl
+		s|/\./|/|g
+		t dotsl
+		s|/\.$|/|'
+    _G_collapseslashes='s|/\{1,\}|/|g'
+    _G_finalslash='s|/*$|/|'
+
+    # Start from root dir and reassemble the path.
+    func_normal_abspath_result=
+    func_normal_abspath_tpath=$1
+    func_normal_abspath_altnamespace=
+    case $func_normal_abspath_tpath in
+      "")
+        # Empty path, that just means $cwd.
+        func_stripname '' '/' "`pwd`"
+        func_normal_abspath_result=$func_stripname_result
+        return
+        ;;
+      # The next three entries are used to spot a run of precisely
+      # two leading slashes without using negated character classes;
+      # we take advantage of case's first-match behaviour.
+      ///*)
+        # Unusual form of absolute path, do nothing.
+        ;;
+      //*)
+        # Not necessarily an ordinary path; POSIX reserves leading '//'
+        # and for example Cygwin uses it to access remote file shares
+        # over CIFS/SMB, so we conserve a leading double slash if found.
+        func_normal_abspath_altnamespace=/
+        ;;
+      /*)
+        # Absolute path, do nothing.
+        ;;
+      *)
+        # Relative path, prepend $cwd.
+        func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath
+        ;;
+    esac
+
+    # Cancel out all the simple stuff to save iterations.  We also want
+    # the path to end with a slash for ease of parsing, so make sure
+    # there is one (and only one) here.
+    func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
+          -e "$_G_removedotparts" -e "$_G_collapseslashes" -e "$_G_finalslash"`
+    while :; do
+      # Processed it all yet?
+      if test / = "$func_normal_abspath_tpath"; then
+        # If we ascended to the root using ".." the result may be empty now.
+        if test -z "$func_normal_abspath_result"; then
+          func_normal_abspath_result=/
+        fi
+        break
+      fi
+      func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \
+          -e "$_G_pathcar"`
+      func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
+          -e "$_G_pathcdr"`
+      # Figure out what to do with it
+      case $func_normal_abspath_tcomponent in
+        "")
+          # Trailing empty path component, ignore it.
+          ;;
+        ..)
+          # Parent dir; strip last assembled component from result.
+          func_dirname "$func_normal_abspath_result"
+          func_normal_abspath_result=$func_dirname_result
+          ;;
+        *)
+          # Actual path component, append it.
+          func_append func_normal_abspath_result "/$func_normal_abspath_tcomponent"
+          ;;
+      esac
+    done
+    # Restore leading double-slash if one was found on entry.
+    func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result
+}
+
+
+# func_notquiet ARG...
+# --------------------
+# Echo program name prefixed message only when not in quiet mode.
+func_notquiet ()
+{
+    $debug_cmd
+
+    $opt_quiet || func_echo ${1+"$@"}
+
+    # A bug in bash halts the script if the last line of a function
+    # fails when set -e is in force, so we need another command to
+    # work around that:
+    :
+}
+
+
+# func_relative_path SRCDIR DSTDIR
+# --------------------------------
+# Set func_relative_path_result to the relative path from SRCDIR to DSTDIR.
+func_relative_path ()
+{
+    $debug_cmd
+
+    func_relative_path_result=
+    func_normal_abspath "$1"
+    func_relative_path_tlibdir=$func_normal_abspath_result
+    func_normal_abspath "$2"
+    func_relative_path_tbindir=$func_normal_abspath_result
+
+    # Ascend the tree starting from libdir
+    while :; do
+      # check if we have found a prefix of bindir
+      case $func_relative_path_tbindir in
+        $func_relative_path_tlibdir)
+          # found an exact match
+          func_relative_path_tcancelled=
+          break
+          ;;
+        $func_relative_path_tlibdir*)
+          # found a matching prefix
+          func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir"
+          func_relative_path_tcancelled=$func_stripname_result
+          if test -z "$func_relative_path_result"; then
+            func_relative_path_result=.
+          fi
+          break
+          ;;
+        *)
+          func_dirname $func_relative_path_tlibdir
+          func_relative_path_tlibdir=$func_dirname_result
+          if test -z "$func_relative_path_tlibdir"; then
+            # Have to descend all the way to the root!
+            func_relative_path_result=../$func_relative_path_result
+            func_relative_path_tcancelled=$func_relative_path_tbindir
+            break
+          fi
+          func_relative_path_result=../$func_relative_path_result
+          ;;
+      esac
+    done
+
+    # Now calculate path; take care to avoid doubling-up slashes.
+    func_stripname '' '/' "$func_relative_path_result"
+    func_relative_path_result=$func_stripname_result
+    func_stripname '/' '/' "$func_relative_path_tcancelled"
+    if test -n "$func_stripname_result"; then
+      func_append func_relative_path_result "/$func_stripname_result"
+    fi
+
+    # Normalisation. If bindir is libdir, return '.' else relative path.
+    if test -n "$func_relative_path_result"; then
+      func_stripname './' '' "$func_relative_path_result"
+      func_relative_path_result=$func_stripname_result
+    fi
+
+    test -n "$func_relative_path_result" || func_relative_path_result=.
+
+    :
+}
+
+
+# func_quote_for_eval ARG...
+# --------------------------
+# Aesthetically quote ARGs to be evaled later.
+# This function returns two values:
+#   i) func_quote_for_eval_result
+#      double-quoted, suitable for a subsequent eval
+#  ii) func_quote_for_eval_unquoted_result
+#      has all characters that are still active within double
+#      quotes backslashified.
+func_quote_for_eval ()
+{
+    $debug_cmd
+
+    func_quote_for_eval_unquoted_result=
+    func_quote_for_eval_result=
+    while test 0 -lt $#; do
+      case $1 in
+        *[\\\`\"\$]*)
+	  _G_unquoted_arg=`printf '%s\n' "$1" |$SED "$sed_quote_subst"` ;;
+        *)
+          _G_unquoted_arg=$1 ;;
+      esac
+      if test -n "$func_quote_for_eval_unquoted_result"; then
+	func_append func_quote_for_eval_unquoted_result " $_G_unquoted_arg"
+      else
+        func_append func_quote_for_eval_unquoted_result "$_G_unquoted_arg"
+      fi
+
+      case $_G_unquoted_arg in
+        # Double-quote args containing shell metacharacters to delay
+        # word splitting, command substitution and variable expansion
+        # for a subsequent eval.
+        # Many Bourne shells cannot handle close brackets correctly
+        # in scan sets, so we specify it separately.
+        *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+          _G_quoted_arg=\"$_G_unquoted_arg\"
+          ;;
+        *)
+          _G_quoted_arg=$_G_unquoted_arg
+	  ;;
+      esac
+
+      if test -n "$func_quote_for_eval_result"; then
+	func_append func_quote_for_eval_result " $_G_quoted_arg"
+      else
+        func_append func_quote_for_eval_result "$_G_quoted_arg"
+      fi
+      shift
+    done
+}
+
+
+# func_quote_for_expand ARG
+# -------------------------
+# Aesthetically quote ARG to be evaled later; same as above,
+# but do not quote variable references.
+func_quote_for_expand ()
+{
+    $debug_cmd
+
+    case $1 in
+      *[\\\`\"]*)
+	_G_arg=`$ECHO "$1" | $SED \
+	    -e "$sed_double_quote_subst" -e "$sed_double_backslash"` ;;
+      *)
+        _G_arg=$1 ;;
+    esac
+
+    case $_G_arg in
+      # Double-quote args containing shell metacharacters to delay
+      # word splitting and command substitution for a subsequent eval.
+      # Many Bourne shells cannot handle close brackets correctly
+      # in scan sets, so we specify it separately.
+      *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+        _G_arg=\"$_G_arg\"
+        ;;
+    esac
+
+    func_quote_for_expand_result=$_G_arg
+}
+
+
+# func_stripname PREFIX SUFFIX NAME
+# ---------------------------------
+# strip PREFIX and SUFFIX from NAME, and store in func_stripname_result.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+if test yes = "$_G_HAVE_XSI_OPS"; then
+  eval 'func_stripname ()
+  {
+    $debug_cmd
+
+    # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are
+    # positional parameters, so assign one to ordinary variable first.
+    func_stripname_result=$3
+    func_stripname_result=${func_stripname_result#"$1"}
+    func_stripname_result=${func_stripname_result%"$2"}
+  }'
+else
+  func_stripname ()
+  {
+    $debug_cmd
+
+    case $2 in
+      .*) func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%\\\\$2\$%%"`;;
+      *)  func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%$2\$%%"`;;
+    esac
+  }
+fi
+
+
+# func_show_eval CMD [FAIL_EXP]
+# -----------------------------
+# Unless opt_quiet is true, then output CMD.  Then, if opt_dryrun is
+# not true, evaluate CMD.  If the evaluation of CMD fails, and FAIL_EXP
+# is given, then evaluate it.
+func_show_eval ()
+{
+    $debug_cmd
+
+    _G_cmd=$1
+    _G_fail_exp=${2-':'}
+
+    func_quote_for_expand "$_G_cmd"
+    eval "func_notquiet $func_quote_for_expand_result"
+
+    $opt_dry_run || {
+      eval "$_G_cmd"
+      _G_status=$?
+      if test 0 -ne "$_G_status"; then
+	eval "(exit $_G_status); $_G_fail_exp"
+      fi
+    }
+}
+
+
+# func_show_eval_locale CMD [FAIL_EXP]
+# ------------------------------------
+# Unless opt_quiet is true, then output CMD.  Then, if opt_dryrun is
+# not true, evaluate CMD.  If the evaluation of CMD fails, and FAIL_EXP
+# is given, then evaluate it.  Use the saved locale for evaluation.
+func_show_eval_locale ()
+{
+    $debug_cmd
+
+    _G_cmd=$1
+    _G_fail_exp=${2-':'}
+
+    $opt_quiet || {
+      func_quote_for_expand "$_G_cmd"
+      eval "func_echo $func_quote_for_expand_result"
+    }
+
+    $opt_dry_run || {
+      eval "$_G_user_locale
+	    $_G_cmd"
+      _G_status=$?
+      eval "$_G_safe_locale"
+      if test 0 -ne "$_G_status"; then
+	eval "(exit $_G_status); $_G_fail_exp"
+      fi
+    }
+}
+
+
+# func_tr_sh
+# ----------
+# Turn $1 into a string suitable for a shell variable name.
+# Result is stored in $func_tr_sh_result.  All characters
+# not in the set a-zA-Z0-9_ are replaced with '_'. Further,
+# if $1 begins with a digit, a '_' is prepended as well.
+func_tr_sh ()
+{
+    $debug_cmd
+
+    case $1 in
+    [0-9]* | *[!a-zA-Z0-9_]*)
+      func_tr_sh_result=`$ECHO "$1" | $SED -e 's/^\([0-9]\)/_\1/' -e 's/[^a-zA-Z0-9_]/_/g'`
+      ;;
+    * )
+      func_tr_sh_result=$1
+      ;;
+    esac
+}
+
+
+# func_verbose ARG...
+# -------------------
+# Echo program name prefixed message in verbose mode only.
+func_verbose ()
+{
+    $debug_cmd
+
+    $opt_verbose && func_echo "$*"
+
+    :
+}
+
+
+# func_warn_and_continue ARG...
+# -----------------------------
+# Echo program name prefixed warning message to standard error.
+func_warn_and_continue ()
+{
+    $debug_cmd
+
+    $require_term_colors
+
+    func_echo_infix_1 "${tc_red}warning$tc_reset" "$*" >&2
+}
+
+
+# func_warning CATEGORY ARG...
+# ----------------------------
+# Echo program name prefixed warning message to standard error. Warning
+# messages can be filtered according to CATEGORY, where this function
+# elides messages where CATEGORY is not listed in the global variable
+# 'opt_warning_types'.
+func_warning ()
+{
+    $debug_cmd
+
+    # CATEGORY must be in the warning_categories list!
+    case " $warning_categories " in
+      *" $1 "*) ;;
+      *) func_internal_error "invalid warning category '$1'" ;;
+    esac
+
+    _G_category=$1
+    shift
+
+    case " $opt_warning_types " in
+      *" $_G_category "*) $warning_func ${1+"$@"} ;;
+    esac
+}
+
+
+# func_sort_ver VER1 VER2
+# -----------------------
+# 'sort -V' is not generally available.
+# Note this deviates from the version comparison in automake
+# in that it treats 1.5 < 1.5.0, and treats 1.4.4a < 1.4-p3a
+# but this should suffice as we won't be specifying old
+# version formats or redundant trailing .0 in bootstrap.conf.
+# If we did want full compatibility then we should probably
+# use m4_version_compare from autoconf.
+func_sort_ver ()
+{
+    $debug_cmd
+
+    printf '%s\n%s\n' "$1" "$2" \
+      | sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n -k 5,5n -k 6,6n -k 7,7n -k 8,8n -k 9,9n
+}
+
+# func_lt_ver PREV CURR
+# ---------------------
+# Return true if PREV and CURR are in the correct order according to
+# func_sort_ver, otherwise false.  Use it like this:
+#
+#  func_lt_ver "$prev_ver" "$proposed_ver" || func_fatal_error "..."
+func_lt_ver ()
+{
+    $debug_cmd
+
+    test "x$1" = x`func_sort_ver "$1" "$2" | $SED 1q`
+}
+
+
+# Local variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC"
+# time-stamp-time-zone: "UTC"
+# End:
+#! /bin/sh
+
+# Set a version string for this script.
+scriptversion=2014-01-07.03; # UTC
+
+# A portable, pluggable option parser for Bourne shell.
+# Written by Gary V. Vaughan, 2010
+
+# Copyright (C) 2010-2015 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions.  There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Please report bugs or propose patches to gary@gnu.org.
+
+
+## ------ ##
+## Usage. ##
+## ------ ##
+
+# This file is a library for parsing options in your shell scripts along
+# with assorted other useful supporting features that you can make use
+# of too.
+#
+# For the simplest scripts you might need only:
+#
+#   #!/bin/sh
+#   . relative/path/to/funclib.sh
+#   . relative/path/to/options-parser
+#   scriptversion=1.0
+#   func_options ${1+"$@"}
+#   eval set dummy "$func_options_result"; shift
+#   ...rest of your script...
+#
+# In order for the '--version' option to work, you will need to have a
+# suitably formatted comment like the one at the top of this file
+# starting with '# Written by ' and ending with '# warranty; '.
+#
+# For '-h' and '--help' to work, you will also need a one line
+# description of your script's purpose in a comment directly above the
+# '# Written by ' line, like the one at the top of this file.
+#
+# The default options also support '--debug', which will turn on shell
+# execution tracing (see the comment above debug_cmd below for another
+# use), and '--verbose' and the func_verbose function to allow your script
+# to display verbose messages only when your user has specified
+# '--verbose'.
+#
+# After sourcing this file, you can plug processing for additional
+# options by amending the variables from the 'Configuration' section
+# below, and following the instructions in the 'Option parsing'
+# section further down.
+
+## -------------- ##
+## Configuration. ##
+## -------------- ##
+
+# You should override these variables in your script after sourcing this
+# file so that they reflect the customisations you have added to the
+# option parser.
+
+# The usage line for option parsing errors and the start of '-h' and
+# '--help' output messages. You can embed shell variables for delayed
+# expansion at the time the message is displayed, but you will need to
+# quote other shell meta-characters carefully to prevent them being
+# expanded when the contents are evaled.
+usage='$progpath [OPTION]...'
+
+# Short help message in response to '-h' and '--help'.  Add to this or
+# override it after sourcing this library to reflect the full set of
+# options your script accepts.
+usage_message="\
+       --debug        enable verbose shell tracing
+   -W, --warnings=CATEGORY
+                      report the warnings falling in CATEGORY [all]
+   -v, --verbose      verbosely report processing
+       --version      print version information and exit
+   -h, --help         print short or long help message and exit
+"
+
+# Additional text appended to 'usage_message' in response to '--help'.
+long_help_message="
+Warning categories include:
+       'all'          show all warnings
+       'none'         turn off all the warnings
+       'error'        warnings are treated as fatal errors"
+
+# Help message printed before fatal option parsing errors.
+fatal_help="Try '\$progname --help' for more information."
+
+
+
+## ------------------------- ##
+## Hook function management. ##
+## ------------------------- ##
+
+# This section contains functions for adding, removing, and running hooks
+# to the main code.  A hook is just a named list of of function, that can
+# be run in order later on.
+
+# func_hookable FUNC_NAME
+# -----------------------
+# Declare that FUNC_NAME will run hooks added with
+# 'func_add_hook FUNC_NAME ...'.
+func_hookable ()
+{
+    $debug_cmd
+
+    func_append hookable_fns " $1"
+}
+
+
+# func_add_hook FUNC_NAME HOOK_FUNC
+# ---------------------------------
+# Request that FUNC_NAME call HOOK_FUNC before it returns.  FUNC_NAME must
+# first have been declared "hookable" by a call to 'func_hookable'.
+func_add_hook ()
+{
+    $debug_cmd
+
+    case " $hookable_fns " in
+      *" $1 "*) ;;
+      *) func_fatal_error "'$1' does not accept hook functions." ;;
+    esac
+
+    eval func_append ${1}_hooks '" $2"'
+}
+
+
+# func_remove_hook FUNC_NAME HOOK_FUNC
+# ------------------------------------
+# Remove HOOK_FUNC from the list of functions called by FUNC_NAME.
+func_remove_hook ()
+{
+    $debug_cmd
+
+    eval ${1}_hooks='`$ECHO "\$'$1'_hooks" |$SED "s| '$2'||"`'
+}
+
+
+# func_run_hooks FUNC_NAME [ARG]...
+# ---------------------------------
+# Run all hook functions registered to FUNC_NAME.
+# It is assumed that the list of hook functions contains nothing more
+# than a whitespace-delimited list of legal shell function names, and
+# no effort is wasted trying to catch shell meta-characters or preserve
+# whitespace.
+func_run_hooks ()
+{
+    $debug_cmd
+
+    case " $hookable_fns " in
+      *" $1 "*) ;;
+      *) func_fatal_error "'$1' does not support hook funcions.n" ;;
+    esac
+
+    eval _G_hook_fns=\$$1_hooks; shift
+
+    for _G_hook in $_G_hook_fns; do
+      eval $_G_hook '"$@"'
+
+      # store returned options list back into positional
+      # parameters for next 'cmd' execution.
+      eval _G_hook_result=\$${_G_hook}_result
+      eval set dummy "$_G_hook_result"; shift
+    done
+
+    func_quote_for_eval ${1+"$@"}
+    func_run_hooks_result=$func_quote_for_eval_result
+}
+
+
+
+## --------------- ##
+## Option parsing. ##
+## --------------- ##
+
+# In order to add your own option parsing hooks, you must accept the
+# full positional parameter list in your hook function, remove any
+# options that you action, and then pass back the remaining unprocessed
+# options in '<hooked_function_name>_result', escaped suitably for
+# 'eval'.  Like this:
+#
+#    my_options_prep ()
+#    {
+#        $debug_cmd
+#
+#        # Extend the existing usage message.
+#        usage_message=$usage_message'
+#      -s, --silent       don'\''t print informational messages
+#    '
+#
+#        func_quote_for_eval ${1+"$@"}
+#        my_options_prep_result=$func_quote_for_eval_result
+#    }
+#    func_add_hook func_options_prep my_options_prep
+#
+#
+#    my_silent_option ()
+#    {
+#        $debug_cmd
+#
+#        # Note that for efficiency, we parse as many options as we can
+#        # recognise in a loop before passing the remainder back to the
+#        # caller on the first unrecognised argument we encounter.
+#        while test $# -gt 0; do
+#          opt=$1; shift
+#          case $opt in
+#            --silent|-s) opt_silent=: ;;
+#            # Separate non-argument short options:
+#            -s*)         func_split_short_opt "$_G_opt"
+#                         set dummy "$func_split_short_opt_name" \
+#                             "-$func_split_short_opt_arg" ${1+"$@"}
+#                         shift
+#                         ;;
+#            *)            set dummy "$_G_opt" "$*"; shift; break ;;
+#          esac
+#        done
+#
+#        func_quote_for_eval ${1+"$@"}
+#        my_silent_option_result=$func_quote_for_eval_result
+#    }
+#    func_add_hook func_parse_options my_silent_option
+#
+#
+#    my_option_validation ()
+#    {
+#        $debug_cmd
+#
+#        $opt_silent && $opt_verbose && func_fatal_help "\
+#    '--silent' and '--verbose' options are mutually exclusive."
+#
+#        func_quote_for_eval ${1+"$@"}
+#        my_option_validation_result=$func_quote_for_eval_result
+#    }
+#    func_add_hook func_validate_options my_option_validation
+#
+# You'll alse need to manually amend $usage_message to reflect the extra
+# options you parse.  It's preferable to append if you can, so that
+# multiple option parsing hooks can be added safely.
+
+
+# func_options [ARG]...
+# ---------------------
+# All the functions called inside func_options are hookable. See the
+# individual implementations for details.
+func_hookable func_options
+func_options ()
+{
+    $debug_cmd
+
+    func_options_prep ${1+"$@"}
+    eval func_parse_options \
+        ${func_options_prep_result+"$func_options_prep_result"}
+    eval func_validate_options \
+        ${func_parse_options_result+"$func_parse_options_result"}
+
+    eval func_run_hooks func_options \
+        ${func_validate_options_result+"$func_validate_options_result"}
+
+    # save modified positional parameters for caller
+    func_options_result=$func_run_hooks_result
+}
+
+
+# func_options_prep [ARG]...
+# --------------------------
+# All initialisations required before starting the option parse loop.
+# Note that when calling hook functions, we pass through the list of
+# positional parameters.  If a hook function modifies that list, and
+# needs to propogate that back to rest of this script, then the complete
+# modified list must be put in 'func_run_hooks_result' before
+# returning.
+func_hookable func_options_prep
+func_options_prep ()
+{
+    $debug_cmd
+
+    # Option defaults:
+    opt_verbose=false
+    opt_warning_types=
+
+    func_run_hooks func_options_prep ${1+"$@"}
+
+    # save modified positional parameters for caller
+    func_options_prep_result=$func_run_hooks_result
+}
+
+
+# func_parse_options [ARG]...
+# ---------------------------
+# The main option parsing loop.
+func_hookable func_parse_options
+func_parse_options ()
+{
+    $debug_cmd
+
+    func_parse_options_result=
+
+    # this just eases exit handling
+    while test $# -gt 0; do
+      # Defer to hook functions for initial option parsing, so they
+      # get priority in the event of reusing an option name.
+      func_run_hooks func_parse_options ${1+"$@"}
+
+      # Adjust func_parse_options positional parameters to match
+      eval set dummy "$func_run_hooks_result"; shift
+
+      # Break out of the loop if we already parsed every option.
+      test $# -gt 0 || break
+
+      _G_opt=$1
+      shift
+      case $_G_opt in
+        --debug|-x)   debug_cmd='set -x'
+                      func_echo "enabling shell trace mode"
+                      $debug_cmd
+                      ;;
+
+        --no-warnings|--no-warning|--no-warn)
+                      set dummy --warnings none ${1+"$@"}
+                      shift
+		      ;;
+
+        --warnings|--warning|-W)
+                      test $# = 0 && func_missing_arg $_G_opt && break
+                      case " $warning_categories $1" in
+                        *" $1 "*)
+                          # trailing space prevents matching last $1 above
+                          func_append_uniq opt_warning_types " $1"
+                          ;;
+                        *all)
+                          opt_warning_types=$warning_categories
+                          ;;
+                        *none)
+                          opt_warning_types=none
+                          warning_func=:
+                          ;;
+                        *error)
+                          opt_warning_types=$warning_categories
+                          warning_func=func_fatal_error
+                          ;;
+                        *)
+                          func_fatal_error \
+                             "unsupported warning category: '$1'"
+                          ;;
+                      esac
+                      shift
+                      ;;
+
+        --verbose|-v) opt_verbose=: ;;
+        --version)    func_version ;;
+        -\?|-h)       func_usage ;;
+        --help)       func_help ;;
+
+	# Separate optargs to long options (plugins may need this):
+	--*=*)        func_split_equals "$_G_opt"
+	              set dummy "$func_split_equals_lhs" \
+                          "$func_split_equals_rhs" ${1+"$@"}
+                      shift
+                      ;;
+
+       # Separate optargs to short options:
+        -W*)
+                      func_split_short_opt "$_G_opt"
+                      set dummy "$func_split_short_opt_name" \
+                          "$func_split_short_opt_arg" ${1+"$@"}
+                      shift
+                      ;;
+
+        # Separate non-argument short options:
+        -\?*|-h*|-v*|-x*)
+                      func_split_short_opt "$_G_opt"
+                      set dummy "$func_split_short_opt_name" \
+                          "-$func_split_short_opt_arg" ${1+"$@"}
+                      shift
+                      ;;
+
+        --)           break ;;
+        -*)           func_fatal_help "unrecognised option: '$_G_opt'" ;;
+        *)            set dummy "$_G_opt" ${1+"$@"}; shift; break ;;
+      esac
+    done
+
+    # save modified positional parameters for caller
+    func_quote_for_eval ${1+"$@"}
+    func_parse_options_result=$func_quote_for_eval_result
+}
+
+
+# func_validate_options [ARG]...
+# ------------------------------
+# Perform any sanity checks on option settings and/or unconsumed
+# arguments.
+func_hookable func_validate_options
+func_validate_options ()
+{
+    $debug_cmd
+
+    # Display all warnings if -W was not given.
+    test -n "$opt_warning_types" || opt_warning_types=" $warning_categories"
+
+    func_run_hooks func_validate_options ${1+"$@"}
+
+    # Bail if the options were screwed!
+    $exit_cmd $EXIT_FAILURE
+
+    # save modified positional parameters for caller
+    func_validate_options_result=$func_run_hooks_result
+}
+
+
+
+## ----------------- ##
+## Helper functions. ##
+## ----------------- ##
+
+# This section contains the helper functions used by the rest of the
+# hookable option parser framework in ascii-betical order.
+
+
+# func_fatal_help ARG...
+# ----------------------
+# Echo program name prefixed message to standard error, followed by
+# a help hint, and exit.
+func_fatal_help ()
+{
+    $debug_cmd
+
+    eval \$ECHO \""Usage: $usage"\"
+    eval \$ECHO \""$fatal_help"\"
+    func_error ${1+"$@"}
+    exit $EXIT_FAILURE
+}
+
+
+# func_help
+# ---------
+# Echo long help message to standard output and exit.
+func_help ()
+{
+    $debug_cmd
+
+    func_usage_message
+    $ECHO "$long_help_message"
+    exit 0
+}
+
+
+# func_missing_arg ARGNAME
+# ------------------------
+# Echo program name prefixed message to standard error and set global
+# exit_cmd.
+func_missing_arg ()
+{
+    $debug_cmd
+
+    func_error "Missing argument for '$1'."
+    exit_cmd=exit
+}
+
+
+# func_split_equals STRING
+# ------------------------
+# Set func_split_equals_lhs and func_split_equals_rhs shell variables after
+# splitting STRING at the '=' sign.
+test -z "$_G_HAVE_XSI_OPS" \
+    && (eval 'x=a/b/c;
+      test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \
+    && _G_HAVE_XSI_OPS=yes
+
+if test yes = "$_G_HAVE_XSI_OPS"
+then
+  # This is an XSI compatible shell, allowing a faster implementation...
+  eval 'func_split_equals ()
+  {
+      $debug_cmd
+
+      func_split_equals_lhs=${1%%=*}
+      func_split_equals_rhs=${1#*=}
+      test "x$func_split_equals_lhs" = "x$1" \
+        && func_split_equals_rhs=
+  }'
+else
+  # ...otherwise fall back to using expr, which is often a shell builtin.
+  func_split_equals ()
+  {
+      $debug_cmd
+
+      func_split_equals_lhs=`expr "x$1" : 'x\([^=]*\)'`
+      func_split_equals_rhs=
+      test "x$func_split_equals_lhs" = "x$1" \
+        || func_split_equals_rhs=`expr "x$1" : 'x[^=]*=\(.*\)$'`
+  }
+fi #func_split_equals
+
+
+# func_split_short_opt SHORTOPT
+# -----------------------------
+# Set func_split_short_opt_name and func_split_short_opt_arg shell
+# variables after splitting SHORTOPT after the 2nd character.
+if test yes = "$_G_HAVE_XSI_OPS"
+then
+  # This is an XSI compatible shell, allowing a faster implementation...
+  eval 'func_split_short_opt ()
+  {
+      $debug_cmd
+
+      func_split_short_opt_arg=${1#??}
+      func_split_short_opt_name=${1%"$func_split_short_opt_arg"}
+  }'
+else
+  # ...otherwise fall back to using expr, which is often a shell builtin.
+  func_split_short_opt ()
+  {
+      $debug_cmd
+
+      func_split_short_opt_name=`expr "x$1" : 'x-\(.\)'`
+      func_split_short_opt_arg=`expr "x$1" : 'x-.\(.*\)$'`
+  }
+fi #func_split_short_opt
+
+
+# func_usage
+# ----------
+# Echo short help message to standard output and exit.
+func_usage ()
+{
+    $debug_cmd
+
+    func_usage_message
+    $ECHO "Run '$progname --help |${PAGER-more}' for full usage"
+    exit 0
+}
+
+
+# func_usage_message
+# ------------------
+# Echo short help message to standard output.
+func_usage_message ()
+{
+    $debug_cmd
+
+    eval \$ECHO \""Usage: $usage"\"
+    echo
+    $SED -n 's|^# ||
+        /^Written by/{
+          x;p;x
+        }
+	h
+	/^Written by/q' < "$progpath"
+    echo
+    eval \$ECHO \""$usage_message"\"
+}
+
+
+# func_version
+# ------------
+# Echo version message to standard output and exit.
+func_version ()
+{
+    $debug_cmd
+
+    printf '%s\n' "$progname $scriptversion"
+    $SED -n '
+        /(C)/!b go
+        :more
+        /\./!{
+          N
+          s|\n# | |
+          b more
+        }
+        :go
+        /^# Written by /,/# warranty; / {
+          s|^# ||
+          s|^# *$||
+          s|\((C)\)[ 0-9,-]*[ ,-]\([1-9][0-9]* \)|\1 \2|
+          p
+        }
+        /^# Written by / {
+          s|^# ||
+          p
+        }
+        /^warranty; /q' < "$progpath"
+
+    exit $?
+}
+
+
+# Local variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC"
+# time-stamp-time-zone: "UTC"
+# End:
+
+# Set a version string.
+scriptversion='(GNU libtool) 2.4.6'
+
+
+# func_echo ARG...
+# ----------------
+# Libtool also displays the current mode in messages, so override
+# funclib.sh func_echo with this custom definition.
+func_echo ()
+{
+    $debug_cmd
+
+    _G_message=$*
+
+    func_echo_IFS=$IFS
+    IFS=$nl
+    for _G_line in $_G_message; do
+      IFS=$func_echo_IFS
+      $ECHO "$progname${opt_mode+: $opt_mode}: $_G_line"
+    done
+    IFS=$func_echo_IFS
+}
+
+
+# func_warning ARG...
+# -------------------
+# Libtool warnings are not categorized, so override funclib.sh
+# func_warning with this simpler definition.
+func_warning ()
+{
+    $debug_cmd
+
+    $warning_func ${1+"$@"}
+}
+
+
+## ---------------- ##
+## Options parsing. ##
+## ---------------- ##
+
+# Hook in the functions to make sure our own options are parsed during
+# the option parsing loop.
+
+usage='$progpath [OPTION]... [MODE-ARG]...'
+
+# Short help message in response to '-h'.
+usage_message="Options:
+       --config             show all configuration variables
+       --debug              enable verbose shell tracing
+   -n, --dry-run            display commands without modifying any files
+       --features           display basic configuration information and exit
+       --mode=MODE          use operation mode MODE
+       --no-warnings        equivalent to '-Wnone'
+       --preserve-dup-deps  don't remove duplicate dependency libraries
+       --quiet, --silent    don't print informational messages
+       --tag=TAG            use configuration variables from tag TAG
+   -v, --verbose            print more informational messages than default
+       --version            print version information
+   -W, --warnings=CATEGORY  report the warnings falling in CATEGORY [all]
+   -h, --help, --help-all   print short, long, or detailed help message
+"
+
+# Additional text appended to 'usage_message' in response to '--help'.
+func_help ()
+{
+    $debug_cmd
+
+    func_usage_message
+    $ECHO "$long_help_message
+
+MODE must be one of the following:
+
+       clean           remove files from the build directory
+       compile         compile a source file into a libtool object
+       execute         automatically set library path, then run a program
+       finish          complete the installation of libtool libraries
+       install         install libraries or executables
+       link            create a library or an executable
+       uninstall       remove libraries from an installed directory
+
+MODE-ARGS vary depending on the MODE.  When passed as first option,
+'--mode=MODE' may be abbreviated as 'MODE' or a unique abbreviation of that.
+Try '$progname --help --mode=MODE' for a more detailed description of MODE.
+
+When reporting a bug, please describe a test case to reproduce it and
+include the following information:
+
+       host-triplet:   $host
+       shell:          $SHELL
+       compiler:       $LTCC
+       compiler flags: $LTCFLAGS
+       linker:         $LD (gnu? $with_gnu_ld)
+       version:        $progname (GNU libtool) 2.4.6
+       automake:       `($AUTOMAKE --version) 2>/dev/null |$SED 1q`
+       autoconf:       `($AUTOCONF --version) 2>/dev/null |$SED 1q`
+
+Report bugs to <bug-libtool@gnu.org>.
+GNU libtool home page: <http://www.gnu.org/software/libtool/>.
+General help using GNU software: <http://www.gnu.org/gethelp/>."
+    exit 0
+}
+
+
+# func_lo2o OBJECT-NAME
+# ---------------------
+# Transform OBJECT-NAME from a '.lo' suffix to the platform specific
+# object suffix.
+
+lo2o=s/\\.lo\$/.$objext/
+o2lo=s/\\.$objext\$/.lo/
+
+if test yes = "$_G_HAVE_XSI_OPS"; then
+  eval 'func_lo2o ()
+  {
+    case $1 in
+      *.lo) func_lo2o_result=${1%.lo}.$objext ;;
+      *   ) func_lo2o_result=$1               ;;
+    esac
+  }'
+
+  # func_xform LIBOBJ-OR-SOURCE
+  # ---------------------------
+  # Transform LIBOBJ-OR-SOURCE from a '.o' or '.c' (or otherwise)
+  # suffix to a '.lo' libtool-object suffix.
+  eval 'func_xform ()
+  {
+    func_xform_result=${1%.*}.lo
+  }'
+else
+  # ...otherwise fall back to using sed.
+  func_lo2o ()
+  {
+    func_lo2o_result=`$ECHO "$1" | $SED "$lo2o"`
+  }
+
+  func_xform ()
+  {
+    func_xform_result=`$ECHO "$1" | $SED 's|\.[^.]*$|.lo|'`
+  }
+fi
+
+
+# func_fatal_configuration ARG...
+# -------------------------------
+# Echo program name prefixed message to standard error, followed by
+# a configuration failure hint, and exit.
+func_fatal_configuration ()
+{
+    func__fatal_error ${1+"$@"} \
+      "See the $PACKAGE documentation for more information." \
+      "Fatal configuration error."
+}
+
+
+# func_config
+# -----------
+# Display the configuration for all the tags in this script.
+func_config ()
+{
+    re_begincf='^# ### BEGIN LIBTOOL'
+    re_endcf='^# ### END LIBTOOL'
+
+    # Default configuration.
+    $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath"
+
+    # Now print the configurations for the tags.
+    for tagname in $taglist; do
+      $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath"
+    done
+
+    exit $?
+}
+
+
+# func_features
+# -------------
+# Display the features supported by this script.
+func_features ()
+{
+    echo "host: $host"
+    if test yes = "$build_libtool_libs"; then
+      echo "enable shared libraries"
+    else
+      echo "disable shared libraries"
+    fi
+    if test yes = "$build_old_libs"; then
+      echo "enable static libraries"
+    else
+      echo "disable static libraries"
+    fi
+
+    exit $?
+}
+
+
+# func_enable_tag TAGNAME
+# -----------------------
+# Verify that TAGNAME is valid, and either flag an error and exit, or
+# enable the TAGNAME tag.  We also add TAGNAME to the global $taglist
+# variable here.
+func_enable_tag ()
+{
+    # Global variable:
+    tagname=$1
+
+    re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$"
+    re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$"
+    sed_extractcf=/$re_begincf/,/$re_endcf/p
+
+    # Validate tagname.
+    case $tagname in
+      *[!-_A-Za-z0-9,/]*)
+        func_fatal_error "invalid tag name: $tagname"
+        ;;
+    esac
+
+    # Don't test for the "default" C tag, as we know it's
+    # there but not specially marked.
+    case $tagname in
+        CC) ;;
+    *)
+        if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then
+	  taglist="$taglist $tagname"
+
+	  # Evaluate the configuration.  Be careful to quote the path
+	  # and the sed script, to avoid splitting on whitespace, but
+	  # also don't use non-portable quotes within backquotes within
+	  # quotes we have to do it in 2 steps:
+	  extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"`
+	  eval "$extractedcf"
+        else
+	  func_error "ignoring unknown tag $tagname"
+        fi
+        ;;
+    esac
+}
+
+
+# func_check_version_match
+# ------------------------
+# Ensure that we are using m4 macros, and libtool script from the same
+# release of libtool.
+func_check_version_match ()
+{
+    if test "$package_revision" != "$macro_revision"; then
+      if test "$VERSION" != "$macro_version"; then
+        if test -z "$macro_version"; then
+          cat >&2 <<_LT_EOF
+$progname: Version mismatch error.  This is $PACKAGE $VERSION, but the
+$progname: definition of this LT_INIT comes from an older release.
+$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION
+$progname: and run autoconf again.
+_LT_EOF
+        else
+          cat >&2 <<_LT_EOF
+$progname: Version mismatch error.  This is $PACKAGE $VERSION, but the
+$progname: definition of this LT_INIT comes from $PACKAGE $macro_version.
+$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION
+$progname: and run autoconf again.
+_LT_EOF
+        fi
+      else
+        cat >&2 <<_LT_EOF
+$progname: Version mismatch error.  This is $PACKAGE $VERSION, revision $package_revision,
+$progname: but the definition of this LT_INIT comes from revision $macro_revision.
+$progname: You should recreate aclocal.m4 with macros from revision $package_revision
+$progname: of $PACKAGE $VERSION and run autoconf again.
+_LT_EOF
+      fi
+
+      exit $EXIT_MISMATCH
+    fi
+}
+
+
+# libtool_options_prep [ARG]...
+# -----------------------------
+# Preparation for options parsed by libtool.
+libtool_options_prep ()
+{
+    $debug_mode
+
+    # Option defaults:
+    opt_config=false
+    opt_dlopen=
+    opt_dry_run=false
+    opt_help=false
+    opt_mode=
+    opt_preserve_dup_deps=false
+    opt_quiet=false
+
+    nonopt=
+    preserve_args=
+
+    # Shorthand for --mode=foo, only valid as the first argument
+    case $1 in
+    clean|clea|cle|cl)
+      shift; set dummy --mode clean ${1+"$@"}; shift
+      ;;
+    compile|compil|compi|comp|com|co|c)
+      shift; set dummy --mode compile ${1+"$@"}; shift
+      ;;
+    execute|execut|execu|exec|exe|ex|e)
+      shift; set dummy --mode execute ${1+"$@"}; shift
+      ;;
+    finish|finis|fini|fin|fi|f)
+      shift; set dummy --mode finish ${1+"$@"}; shift
+      ;;
+    install|instal|insta|inst|ins|in|i)
+      shift; set dummy --mode install ${1+"$@"}; shift
+      ;;
+    link|lin|li|l)
+      shift; set dummy --mode link ${1+"$@"}; shift
+      ;;
+    uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u)
+      shift; set dummy --mode uninstall ${1+"$@"}; shift
+      ;;
+    esac
+
+    # Pass back the list of options.
+    func_quote_for_eval ${1+"$@"}
+    libtool_options_prep_result=$func_quote_for_eval_result
+}
+func_add_hook func_options_prep libtool_options_prep
+
+
+# libtool_parse_options [ARG]...
+# ---------------------------------
+# Provide handling for libtool specific options.
+libtool_parse_options ()
+{
+    $debug_cmd
+
+    # Perform our own loop to consume as many options as possible in
+    # each iteration.
+    while test $# -gt 0; do
+      _G_opt=$1
+      shift
+      case $_G_opt in
+        --dry-run|--dryrun|-n)
+                        opt_dry_run=:
+                        ;;
+
+        --config)       func_config ;;
+
+        --dlopen|-dlopen)
+                        opt_dlopen="${opt_dlopen+$opt_dlopen
+}$1"
+                        shift
+                        ;;
+
+        --preserve-dup-deps)
+                        opt_preserve_dup_deps=: ;;
+
+        --features)     func_features ;;
+
+        --finish)       set dummy --mode finish ${1+"$@"}; shift ;;
+
+        --help)         opt_help=: ;;
+
+        --help-all)     opt_help=': help-all' ;;
+
+        --mode)         test $# = 0 && func_missing_arg $_G_opt && break
+                        opt_mode=$1
+                        case $1 in
+                          # Valid mode arguments:
+                          clean|compile|execute|finish|install|link|relink|uninstall) ;;
+
+                          # Catch anything else as an error
+                          *) func_error "invalid argument for $_G_opt"
+                             exit_cmd=exit
+                             break
+                             ;;
+                        esac
+                        shift
+                        ;;
+
+        --no-silent|--no-quiet)
+                        opt_quiet=false
+                        func_append preserve_args " $_G_opt"
+                        ;;
+
+        --no-warnings|--no-warning|--no-warn)
+                        opt_warning=false
+                        func_append preserve_args " $_G_opt"
+                        ;;
+
+        --no-verbose)
+                        opt_verbose=false
+                        func_append preserve_args " $_G_opt"
+                        ;;
+
+        --silent|--quiet)
+                        opt_quiet=:
+                        opt_verbose=false
+                        func_append preserve_args " $_G_opt"
+                        ;;
+
+        --tag)          test $# = 0 && func_missing_arg $_G_opt && break
+                        opt_tag=$1
+                        func_append preserve_args " $_G_opt $1"
+                        func_enable_tag "$1"
+                        shift
+                        ;;
+
+        --verbose|-v)   opt_quiet=false
+                        opt_verbose=:
+                        func_append preserve_args " $_G_opt"
+                        ;;
+
+	# An option not handled by this hook function:
+        *)		set dummy "$_G_opt" ${1+"$@"};	shift; break  ;;
+      esac
+    done
+
+
+    # save modified positional parameters for caller
+    func_quote_for_eval ${1+"$@"}
+    libtool_parse_options_result=$func_quote_for_eval_result
+}
+func_add_hook func_parse_options libtool_parse_options
+
+
+
+# libtool_validate_options [ARG]...
+# ---------------------------------
+# Perform any sanity checks on option settings and/or unconsumed
+# arguments.
+libtool_validate_options ()
+{
+    # save first non-option argument
+    if test 0 -lt $#; then
+      nonopt=$1
+      shift
+    fi
+
+    # preserve --debug
+    test : = "$debug_cmd" || func_append preserve_args " --debug"
+
+    case $host in
+      # Solaris2 added to fix http://debbugs.gnu.org/cgi/bugreport.cgi?bug=16452
+      # see also: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59788
+      *cygwin* | *mingw* | *pw32* | *cegcc* | *solaris2* | *os2*)
+        # don't eliminate duplications in $postdeps and $predeps
+        opt_duplicate_compiler_generated_deps=:
+        ;;
+      *)
+        opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps
+        ;;
+    esac
+
+    $opt_help || {
+      # Sanity checks first:
+      func_check_version_match
+
+      test yes != "$build_libtool_libs" \
+        && test yes != "$build_old_libs" \
+        && func_fatal_configuration "not configured to build any kind of library"
+
+      # Darwin sucks
+      eval std_shrext=\"$shrext_cmds\"
+
+      # Only execute mode is allowed to have -dlopen flags.
+      if test -n "$opt_dlopen" && test execute != "$opt_mode"; then
+        func_error "unrecognized option '-dlopen'"
+        $ECHO "$help" 1>&2
+        exit $EXIT_FAILURE
+      fi
+
+      # Change the help message to a mode-specific one.
+      generic_help=$help
+      help="Try '$progname --help --mode=$opt_mode' for more information."
+    }
+
+    # Pass back the unparsed argument list
+    func_quote_for_eval ${1+"$@"}
+    libtool_validate_options_result=$func_quote_for_eval_result
+}
+func_add_hook func_validate_options libtool_validate_options
+
+
+# Process options as early as possible so that --help and --version
+# can return quickly.
+func_options ${1+"$@"}
+eval set dummy "$func_options_result"; shift
+
+
+
+## ----------- ##
+##    Main.    ##
+## ----------- ##
+
+magic='%%%MAGIC variable%%%'
+magic_exe='%%%MAGIC EXE variable%%%'
+
+# Global variables.
+extracted_archives=
+extracted_serial=0
+
+# If this variable is set in any of the actions, the command in it
+# will be execed at the end.  This prevents here-documents from being
+# left over by shells.
+exec_cmd=
+
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+}
+
+# func_generated_by_libtool
+# True iff stdin has been generated by Libtool. This function is only
+# a basic sanity check; it will hardly flush out determined imposters.
+func_generated_by_libtool_p ()
+{
+  $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1
+}
+
+# func_lalib_p file
+# True iff FILE is a libtool '.la' library or '.lo' object file.
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_lalib_p ()
+{
+    test -f "$1" &&
+      $SED -e 4q "$1" 2>/dev/null | func_generated_by_libtool_p
+}
+
+# func_lalib_unsafe_p file
+# True iff FILE is a libtool '.la' library or '.lo' object file.
+# This function implements the same check as func_lalib_p without
+# resorting to external programs.  To this end, it redirects stdin and
+# closes it afterwards, without saving the original file descriptor.
+# As a safety measure, use it only where a negative result would be
+# fatal anyway.  Works if 'file' does not exist.
+func_lalib_unsafe_p ()
+{
+    lalib_p=no
+    if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then
+	for lalib_p_l in 1 2 3 4
+	do
+	    read lalib_p_line
+	    case $lalib_p_line in
+		\#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;;
+	    esac
+	done
+	exec 0<&5 5<&-
+    fi
+    test yes = "$lalib_p"
+}
+
+# func_ltwrapper_script_p file
+# True iff FILE is a libtool wrapper script
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_script_p ()
+{
+    test -f "$1" &&
+      $lt_truncate_bin < "$1" 2>/dev/null | func_generated_by_libtool_p
+}
+
+# func_ltwrapper_executable_p file
+# True iff FILE is a libtool wrapper executable
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_executable_p ()
+{
+    func_ltwrapper_exec_suffix=
+    case $1 in
+    *.exe) ;;
+    *) func_ltwrapper_exec_suffix=.exe ;;
+    esac
+    $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1
+}
+
+# func_ltwrapper_scriptname file
+# Assumes file is an ltwrapper_executable
+# uses $file to determine the appropriate filename for a
+# temporary ltwrapper_script.
+func_ltwrapper_scriptname ()
+{
+    func_dirname_and_basename "$1" "" "."
+    func_stripname '' '.exe' "$func_basename_result"
+    func_ltwrapper_scriptname_result=$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper
+}
+
+# func_ltwrapper_p file
+# True iff FILE is a libtool wrapper script or wrapper executable
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_p ()
+{
+    func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1"
+}
+
+
+# func_execute_cmds commands fail_cmd
+# Execute tilde-delimited COMMANDS.
+# If FAIL_CMD is given, eval that upon failure.
+# FAIL_CMD may read-access the current command in variable CMD!
+func_execute_cmds ()
+{
+    $debug_cmd
+
+    save_ifs=$IFS; IFS='~'
+    for cmd in $1; do
+      IFS=$sp$nl
+      eval cmd=\"$cmd\"
+      IFS=$save_ifs
+      func_show_eval "$cmd" "${2-:}"
+    done
+    IFS=$save_ifs
+}
+
+
+# func_source file
+# Source FILE, adding directory component if necessary.
+# Note that it is not necessary on cygwin/mingw to append a dot to
+# FILE even if both FILE and FILE.exe exist: automatic-append-.exe
+# behavior happens only for exec(3), not for open(2)!  Also, sourcing
+# 'FILE.' does not work on cygwin managed mounts.
+func_source ()
+{
+    $debug_cmd
+
+    case $1 in
+    */* | *\\*)	. "$1" ;;
+    *)		. "./$1" ;;
+    esac
+}
+
+
+# func_resolve_sysroot PATH
+# Replace a leading = in PATH with a sysroot.  Store the result into
+# func_resolve_sysroot_result
+func_resolve_sysroot ()
+{
+  func_resolve_sysroot_result=$1
+  case $func_resolve_sysroot_result in
+  =*)
+    func_stripname '=' '' "$func_resolve_sysroot_result"
+    func_resolve_sysroot_result=$lt_sysroot$func_stripname_result
+    ;;
+  esac
+}
+
+# func_replace_sysroot PATH
+# If PATH begins with the sysroot, replace it with = and
+# store the result into func_replace_sysroot_result.
+func_replace_sysroot ()
+{
+  case $lt_sysroot:$1 in
+  ?*:"$lt_sysroot"*)
+    func_stripname "$lt_sysroot" '' "$1"
+    func_replace_sysroot_result='='$func_stripname_result
+    ;;
+  *)
+    # Including no sysroot.
+    func_replace_sysroot_result=$1
+    ;;
+  esac
+}
+
+# func_infer_tag arg
+# Infer tagged configuration to use if any are available and
+# if one wasn't chosen via the "--tag" command line option.
+# Only attempt this if the compiler in the base compile
+# command doesn't match the default compiler.
+# arg is usually of the form 'gcc ...'
+func_infer_tag ()
+{
+    $debug_cmd
+
+    if test -n "$available_tags" && test -z "$tagname"; then
+      CC_quoted=
+      for arg in $CC; do
+	func_append_quoted CC_quoted "$arg"
+      done
+      CC_expanded=`func_echo_all $CC`
+      CC_quoted_expanded=`func_echo_all $CC_quoted`
+      case $@ in
+      # Blanks in the command may have been stripped by the calling shell,
+      # but not from the CC environment variable when configure was run.
+      " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \
+      " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;;
+      # Blanks at the start of $base_compile will cause this to fail
+      # if we don't check for them as well.
+      *)
+	for z in $available_tags; do
+	  if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then
+	    # Evaluate the configuration.
+	    eval "`$SED -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`"
+	    CC_quoted=
+	    for arg in $CC; do
+	      # Double-quote args containing other shell metacharacters.
+	      func_append_quoted CC_quoted "$arg"
+	    done
+	    CC_expanded=`func_echo_all $CC`
+	    CC_quoted_expanded=`func_echo_all $CC_quoted`
+	    case "$@ " in
+	    " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \
+	    " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*)
+	      # The compiler in the base compile command matches
+	      # the one in the tagged configuration.
+	      # Assume this is the tagged configuration we want.
+	      tagname=$z
+	      break
+	      ;;
+	    esac
+	  fi
+	done
+	# If $tagname still isn't set, then no tagged configuration
+	# was found and let the user know that the "--tag" command
+	# line option must be used.
+	if test -z "$tagname"; then
+	  func_echo "unable to infer tagged configuration"
+	  func_fatal_error "specify a tag with '--tag'"
+#	else
+#	  func_verbose "using $tagname tagged configuration"
+	fi
+	;;
+      esac
+    fi
+}
+
+
+
+# func_write_libtool_object output_name pic_name nonpic_name
+# Create a libtool object file (analogous to a ".la" file),
+# but don't create it if we're doing a dry run.
+func_write_libtool_object ()
+{
+    write_libobj=$1
+    if test yes = "$build_libtool_libs"; then
+      write_lobj=\'$2\'
+    else
+      write_lobj=none
+    fi
+
+    if test yes = "$build_old_libs"; then
+      write_oldobj=\'$3\'
+    else
+      write_oldobj=none
+    fi
+
+    $opt_dry_run || {
+      cat >${write_libobj}T <<EOF
+# $write_libobj - a libtool object file
+# Generated by $PROGRAM (GNU $PACKAGE) $VERSION
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+pic_object=$write_lobj
+
+# Name of the non-PIC object
+non_pic_object=$write_oldobj
+
+EOF
+      $MV "${write_libobj}T" "$write_libobj"
+    }
+}
+
+
+##################################################
+# FILE NAME AND PATH CONVERSION HELPER FUNCTIONS #
+##################################################
+
+# func_convert_core_file_wine_to_w32 ARG
+# Helper function used by file name conversion functions when $build is *nix,
+# and $host is mingw, cygwin, or some other w32 environment. Relies on a
+# correctly configured wine environment available, with the winepath program
+# in $build's $PATH.
+#
+# ARG is the $build file name to be converted to w32 format.
+# Result is available in $func_convert_core_file_wine_to_w32_result, and will
+# be empty on error (or when ARG is empty)
+func_convert_core_file_wine_to_w32 ()
+{
+  $debug_cmd
+
+  func_convert_core_file_wine_to_w32_result=$1
+  if test -n "$1"; then
+    # Unfortunately, winepath does not exit with a non-zero error code, so we
+    # are forced to check the contents of stdout. On the other hand, if the
+    # command is not found, the shell will set an exit code of 127 and print
+    # *an error message* to stdout. So we must check for both error code of
+    # zero AND non-empty stdout, which explains the odd construction:
+    func_convert_core_file_wine_to_w32_tmp=`winepath -w "$1" 2>/dev/null`
+    if test "$?" -eq 0 && test -n "$func_convert_core_file_wine_to_w32_tmp"; then
+      func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" |
+        $SED -e "$sed_naive_backslashify"`
+    else
+      func_convert_core_file_wine_to_w32_result=
+    fi
+  fi
+}
+# end: func_convert_core_file_wine_to_w32
+
+
+# func_convert_core_path_wine_to_w32 ARG
+# Helper function used by path conversion functions when $build is *nix, and
+# $host is mingw, cygwin, or some other w32 environment. Relies on a correctly
+# configured wine environment available, with the winepath program in $build's
+# $PATH. Assumes ARG has no leading or trailing path separator characters.
+#
+# ARG is path to be converted from $build format to win32.
+# Result is available in $func_convert_core_path_wine_to_w32_result.
+# Unconvertible file (directory) names in ARG are skipped; if no directory names
+# are convertible, then the result may be empty.
+func_convert_core_path_wine_to_w32 ()
+{
+  $debug_cmd
+
+  # unfortunately, winepath doesn't convert paths, only file names
+  func_convert_core_path_wine_to_w32_result=
+  if test -n "$1"; then
+    oldIFS=$IFS
+    IFS=:
+    for func_convert_core_path_wine_to_w32_f in $1; do
+      IFS=$oldIFS
+      func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f"
+      if test -n "$func_convert_core_file_wine_to_w32_result"; then
+        if test -z "$func_convert_core_path_wine_to_w32_result"; then
+          func_convert_core_path_wine_to_w32_result=$func_convert_core_file_wine_to_w32_result
+        else
+          func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result"
+        fi
+      fi
+    done
+    IFS=$oldIFS
+  fi
+}
+# end: func_convert_core_path_wine_to_w32
+
+
+# func_cygpath ARGS...
+# Wrapper around calling the cygpath program via LT_CYGPATH. This is used when
+# when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2)
+# $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or
+# (2), returns the Cygwin file name or path in func_cygpath_result (input
+# file name or path is assumed to be in w32 format, as previously converted
+# from $build's *nix or MSYS format). In case (3), returns the w32 file name
+# or path in func_cygpath_result (input file name or path is assumed to be in
+# Cygwin format). Returns an empty string on error.
+#
+# ARGS are passed to cygpath, with the last one being the file name or path to
+# be converted.
+#
+# Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH
+# environment variable; do not put it in $PATH.
+func_cygpath ()
+{
+  $debug_cmd
+
+  if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then
+    func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null`
+    if test "$?" -ne 0; then
+      # on failure, ensure result is empty
+      func_cygpath_result=
+    fi
+  else
+    func_cygpath_result=
+    func_error "LT_CYGPATH is empty or specifies non-existent file: '$LT_CYGPATH'"
+  fi
+}
+#end: func_cygpath
+
+
+# func_convert_core_msys_to_w32 ARG
+# Convert file name or path ARG from MSYS format to w32 format.  Return
+# result in func_convert_core_msys_to_w32_result.
+func_convert_core_msys_to_w32 ()
+{
+  $debug_cmd
+
+  # awkward: cmd appends spaces to result
+  func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null |
+    $SED -e 's/[ ]*$//' -e "$sed_naive_backslashify"`
+}
+#end: func_convert_core_msys_to_w32
+
+
+# func_convert_file_check ARG1 ARG2
+# Verify that ARG1 (a file name in $build format) was converted to $host
+# format in ARG2. Otherwise, emit an error message, but continue (resetting
+# func_to_host_file_result to ARG1).
+func_convert_file_check ()
+{
+  $debug_cmd
+
+  if test -z "$2" && test -n "$1"; then
+    func_error "Could not determine host file name corresponding to"
+    func_error "  '$1'"
+    func_error "Continuing, but uninstalled executables may not work."
+    # Fallback:
+    func_to_host_file_result=$1
+  fi
+}
+# end func_convert_file_check
+
+
+# func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH
+# Verify that FROM_PATH (a path in $build format) was converted to $host
+# format in TO_PATH. Otherwise, emit an error message, but continue, resetting
+# func_to_host_file_result to a simplistic fallback value (see below).
+func_convert_path_check ()
+{
+  $debug_cmd
+
+  if test -z "$4" && test -n "$3"; then
+    func_error "Could not determine the host path corresponding to"
+    func_error "  '$3'"
+    func_error "Continuing, but uninstalled executables may not work."
+    # Fallback.  This is a deliberately simplistic "conversion" and
+    # should not be "improved".  See libtool.info.
+    if test "x$1" != "x$2"; then
+      lt_replace_pathsep_chars="s|$1|$2|g"
+      func_to_host_path_result=`echo "$3" |
+        $SED -e "$lt_replace_pathsep_chars"`
+    else
+      func_to_host_path_result=$3
+    fi
+  fi
+}
+# end func_convert_path_check
+
+
+# func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG
+# Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT
+# and appending REPL if ORIG matches BACKPAT.
+func_convert_path_front_back_pathsep ()
+{
+  $debug_cmd
+
+  case $4 in
+  $1 ) func_to_host_path_result=$3$func_to_host_path_result
+    ;;
+  esac
+  case $4 in
+  $2 ) func_append func_to_host_path_result "$3"
+    ;;
+  esac
+}
+# end func_convert_path_front_back_pathsep
+
+
+##################################################
+# $build to $host FILE NAME CONVERSION FUNCTIONS #
+##################################################
+# invoked via '$to_host_file_cmd ARG'
+#
+# In each case, ARG is the path to be converted from $build to $host format.
+# Result will be available in $func_to_host_file_result.
+
+
+# func_to_host_file ARG
+# Converts the file name ARG from $build format to $host format. Return result
+# in func_to_host_file_result.
+func_to_host_file ()
+{
+  $debug_cmd
+
+  $to_host_file_cmd "$1"
+}
+# end func_to_host_file
+
+
+# func_to_tool_file ARG LAZY
+# converts the file name ARG from $build format to toolchain format. Return
+# result in func_to_tool_file_result.  If the conversion in use is listed
+# in (the comma separated) LAZY, no conversion takes place.
+func_to_tool_file ()
+{
+  $debug_cmd
+
+  case ,$2, in
+    *,"$to_tool_file_cmd",*)
+      func_to_tool_file_result=$1
+      ;;
+    *)
+      $to_tool_file_cmd "$1"
+      func_to_tool_file_result=$func_to_host_file_result
+      ;;
+  esac
+}
+# end func_to_tool_file
+
+
+# func_convert_file_noop ARG
+# Copy ARG to func_to_host_file_result.
+func_convert_file_noop ()
+{
+  func_to_host_file_result=$1
+}
+# end func_convert_file_noop
+
+
+# func_convert_file_msys_to_w32 ARG
+# Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic
+# conversion to w32 is not available inside the cwrapper.  Returns result in
+# func_to_host_file_result.
+func_convert_file_msys_to_w32 ()
+{
+  $debug_cmd
+
+  func_to_host_file_result=$1
+  if test -n "$1"; then
+    func_convert_core_msys_to_w32 "$1"
+    func_to_host_file_result=$func_convert_core_msys_to_w32_result
+  fi
+  func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_msys_to_w32
+
+
+# func_convert_file_cygwin_to_w32 ARG
+# Convert file name ARG from Cygwin to w32 format.  Returns result in
+# func_to_host_file_result.
+func_convert_file_cygwin_to_w32 ()
+{
+  $debug_cmd
+
+  func_to_host_file_result=$1
+  if test -n "$1"; then
+    # because $build is cygwin, we call "the" cygpath in $PATH; no need to use
+    # LT_CYGPATH in this case.
+    func_to_host_file_result=`cygpath -m "$1"`
+  fi
+  func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_cygwin_to_w32
+
+
+# func_convert_file_nix_to_w32 ARG
+# Convert file name ARG from *nix to w32 format.  Requires a wine environment
+# and a working winepath. Returns result in func_to_host_file_result.
+func_convert_file_nix_to_w32 ()
+{
+  $debug_cmd
+
+  func_to_host_file_result=$1
+  if test -n "$1"; then
+    func_convert_core_file_wine_to_w32 "$1"
+    func_to_host_file_result=$func_convert_core_file_wine_to_w32_result
+  fi
+  func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_nix_to_w32
+
+
+# func_convert_file_msys_to_cygwin ARG
+# Convert file name ARG from MSYS to Cygwin format.  Requires LT_CYGPATH set.
+# Returns result in func_to_host_file_result.
+func_convert_file_msys_to_cygwin ()
+{
+  $debug_cmd
+
+  func_to_host_file_result=$1
+  if test -n "$1"; then
+    func_convert_core_msys_to_w32 "$1"
+    func_cygpath -u "$func_convert_core_msys_to_w32_result"
+    func_to_host_file_result=$func_cygpath_result
+  fi
+  func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_msys_to_cygwin
+
+
+# func_convert_file_nix_to_cygwin ARG
+# Convert file name ARG from *nix to Cygwin format.  Requires Cygwin installed
+# in a wine environment, working winepath, and LT_CYGPATH set.  Returns result
+# in func_to_host_file_result.
+func_convert_file_nix_to_cygwin ()
+{
+  $debug_cmd
+
+  func_to_host_file_result=$1
+  if test -n "$1"; then
+    # convert from *nix to w32, then use cygpath to convert from w32 to cygwin.
+    func_convert_core_file_wine_to_w32 "$1"
+    func_cygpath -u "$func_convert_core_file_wine_to_w32_result"
+    func_to_host_file_result=$func_cygpath_result
+  fi
+  func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_nix_to_cygwin
+
+
+#############################################
+# $build to $host PATH CONVERSION FUNCTIONS #
+#############################################
+# invoked via '$to_host_path_cmd ARG'
+#
+# In each case, ARG is the path to be converted from $build to $host format.
+# The result will be available in $func_to_host_path_result.
+#
+# Path separators are also converted from $build format to $host format.  If
+# ARG begins or ends with a path separator character, it is preserved (but
+# converted to $host format) on output.
+#
+# All path conversion functions are named using the following convention:
+#   file name conversion function    : func_convert_file_X_to_Y ()
+#   path conversion function         : func_convert_path_X_to_Y ()
+# where, for any given $build/$host combination the 'X_to_Y' value is the
+# same.  If conversion functions are added for new $build/$host combinations,
+# the two new functions must follow this pattern, or func_init_to_host_path_cmd
+# will break.
+
+
+# func_init_to_host_path_cmd
+# Ensures that function "pointer" variable $to_host_path_cmd is set to the
+# appropriate value, based on the value of $to_host_file_cmd.
+to_host_path_cmd=
+func_init_to_host_path_cmd ()
+{
+  $debug_cmd
+
+  if test -z "$to_host_path_cmd"; then
+    func_stripname 'func_convert_file_' '' "$to_host_file_cmd"
+    to_host_path_cmd=func_convert_path_$func_stripname_result
+  fi
+}
+
+
+# func_to_host_path ARG
+# Converts the path ARG from $build format to $host format. Return result
+# in func_to_host_path_result.
+func_to_host_path ()
+{
+  $debug_cmd
+
+  func_init_to_host_path_cmd
+  $to_host_path_cmd "$1"
+}
+# end func_to_host_path
+
+
+# func_convert_path_noop ARG
+# Copy ARG to func_to_host_path_result.
+func_convert_path_noop ()
+{
+  func_to_host_path_result=$1
+}
+# end func_convert_path_noop
+
+
+# func_convert_path_msys_to_w32 ARG
+# Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic
+# conversion to w32 is not available inside the cwrapper.  Returns result in
+# func_to_host_path_result.
+func_convert_path_msys_to_w32 ()
+{
+  $debug_cmd
+
+  func_to_host_path_result=$1
+  if test -n "$1"; then
+    # Remove leading and trailing path separator characters from ARG.  MSYS
+    # behavior is inconsistent here; cygpath turns them into '.;' and ';.';
+    # and winepath ignores them completely.
+    func_stripname : : "$1"
+    func_to_host_path_tmp1=$func_stripname_result
+    func_convert_core_msys_to_w32 "$func_to_host_path_tmp1"
+    func_to_host_path_result=$func_convert_core_msys_to_w32_result
+    func_convert_path_check : ";" \
+      "$func_to_host_path_tmp1" "$func_to_host_path_result"
+    func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
+  fi
+}
+# end func_convert_path_msys_to_w32
+
+
+# func_convert_path_cygwin_to_w32 ARG
+# Convert path ARG from Cygwin to w32 format.  Returns result in
+# func_to_host_file_result.
+func_convert_path_cygwin_to_w32 ()
+{
+  $debug_cmd
+
+  func_to_host_path_result=$1
+  if test -n "$1"; then
+    # See func_convert_path_msys_to_w32:
+    func_stripname : : "$1"
+    func_to_host_path_tmp1=$func_stripname_result
+    func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"`
+    func_convert_path_check : ";" \
+      "$func_to_host_path_tmp1" "$func_to_host_path_result"
+    func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
+  fi
+}
+# end func_convert_path_cygwin_to_w32
+
+
+# func_convert_path_nix_to_w32 ARG
+# Convert path ARG from *nix to w32 format.  Requires a wine environment and
+# a working winepath.  Returns result in func_to_host_file_result.
+func_convert_path_nix_to_w32 ()
+{
+  $debug_cmd
+
+  func_to_host_path_result=$1
+  if test -n "$1"; then
+    # See func_convert_path_msys_to_w32:
+    func_stripname : : "$1"
+    func_to_host_path_tmp1=$func_stripname_result
+    func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1"
+    func_to_host_path_result=$func_convert_core_path_wine_to_w32_result
+    func_convert_path_check : ";" \
+      "$func_to_host_path_tmp1" "$func_to_host_path_result"
+    func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
+  fi
+}
+# end func_convert_path_nix_to_w32
+
+
+# func_convert_path_msys_to_cygwin ARG
+# Convert path ARG from MSYS to Cygwin format.  Requires LT_CYGPATH set.
+# Returns result in func_to_host_file_result.
+func_convert_path_msys_to_cygwin ()
+{
+  $debug_cmd
+
+  func_to_host_path_result=$1
+  if test -n "$1"; then
+    # See func_convert_path_msys_to_w32:
+    func_stripname : : "$1"
+    func_to_host_path_tmp1=$func_stripname_result
+    func_convert_core_msys_to_w32 "$func_to_host_path_tmp1"
+    func_cygpath -u -p "$func_convert_core_msys_to_w32_result"
+    func_to_host_path_result=$func_cygpath_result
+    func_convert_path_check : : \
+      "$func_to_host_path_tmp1" "$func_to_host_path_result"
+    func_convert_path_front_back_pathsep ":*" "*:" : "$1"
+  fi
+}
+# end func_convert_path_msys_to_cygwin
+
+
+# func_convert_path_nix_to_cygwin ARG
+# Convert path ARG from *nix to Cygwin format.  Requires Cygwin installed in a
+# a wine environment, working winepath, and LT_CYGPATH set.  Returns result in
+# func_to_host_file_result.
+func_convert_path_nix_to_cygwin ()
+{
+  $debug_cmd
+
+  func_to_host_path_result=$1
+  if test -n "$1"; then
+    # Remove leading and trailing path separator characters from
+    # ARG. msys behavior is inconsistent here, cygpath turns them
+    # into '.;' and ';.', and winepath ignores them completely.
+    func_stripname : : "$1"
+    func_to_host_path_tmp1=$func_stripname_result
+    func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1"
+    func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result"
+    func_to_host_path_result=$func_cygpath_result
+    func_convert_path_check : : \
+      "$func_to_host_path_tmp1" "$func_to_host_path_result"
+    func_convert_path_front_back_pathsep ":*" "*:" : "$1"
+  fi
+}
+# end func_convert_path_nix_to_cygwin
+
+
+# func_dll_def_p FILE
+# True iff FILE is a Windows DLL '.def' file.
+# Keep in sync with _LT_DLL_DEF_P in libtool.m4
+func_dll_def_p ()
+{
+  $debug_cmd
+
+  func_dll_def_p_tmp=`$SED -n \
+    -e 's/^[	 ]*//' \
+    -e '/^\(;.*\)*$/d' \
+    -e 's/^\(EXPORTS\|LIBRARY\)\([	 ].*\)*$/DEF/p' \
+    -e q \
+    "$1"`
+  test DEF = "$func_dll_def_p_tmp"
+}
+
+
+# func_mode_compile arg...
+func_mode_compile ()
+{
+    $debug_cmd
+
+    # Get the compilation command and the source file.
+    base_compile=
+    srcfile=$nonopt  #  always keep a non-empty value in "srcfile"
+    suppress_opt=yes
+    suppress_output=
+    arg_mode=normal
+    libobj=
+    later=
+    pie_flag=
+
+    for arg
+    do
+      case $arg_mode in
+      arg  )
+	# do not "continue".  Instead, add this to base_compile
+	lastarg=$arg
+	arg_mode=normal
+	;;
+
+      target )
+	libobj=$arg
+	arg_mode=normal
+	continue
+	;;
+
+      normal )
+	# Accept any command-line options.
+	case $arg in
+	-o)
+	  test -n "$libobj" && \
+	    func_fatal_error "you cannot specify '-o' more than once"
+	  arg_mode=target
+	  continue
+	  ;;
+
+	-pie | -fpie | -fPIE)
+          func_append pie_flag " $arg"
+	  continue
+	  ;;
+
+	-shared | -static | -prefer-pic | -prefer-non-pic)
+	  func_append later " $arg"
+	  continue
+	  ;;
+
+	-no-suppress)
+	  suppress_opt=no
+	  continue
+	  ;;
+
+	-Xcompiler)
+	  arg_mode=arg  #  the next one goes into the "base_compile" arg list
+	  continue      #  The current "srcfile" will either be retained or
+	  ;;            #  replaced later.  I would guess that would be a bug.
+
+	-Wc,*)
+	  func_stripname '-Wc,' '' "$arg"
+	  args=$func_stripname_result
+	  lastarg=
+	  save_ifs=$IFS; IFS=,
+	  for arg in $args; do
+	    IFS=$save_ifs
+	    func_append_quoted lastarg "$arg"
+	  done
+	  IFS=$save_ifs
+	  func_stripname ' ' '' "$lastarg"
+	  lastarg=$func_stripname_result
+
+	  # Add the arguments to base_compile.
+	  func_append base_compile " $lastarg"
+	  continue
+	  ;;
+
+	*)
+	  # Accept the current argument as the source file.
+	  # The previous "srcfile" becomes the current argument.
+	  #
+	  lastarg=$srcfile
+	  srcfile=$arg
+	  ;;
+	esac  #  case $arg
+	;;
+      esac    #  case $arg_mode
+
+      # Aesthetically quote the previous argument.
+      func_append_quoted base_compile "$lastarg"
+    done # for arg
+
+    case $arg_mode in
+    arg)
+      func_fatal_error "you must specify an argument for -Xcompile"
+      ;;
+    target)
+      func_fatal_error "you must specify a target with '-o'"
+      ;;
+    *)
+      # Get the name of the library object.
+      test -z "$libobj" && {
+	func_basename "$srcfile"
+	libobj=$func_basename_result
+      }
+      ;;
+    esac
+
+    # Recognize several different file suffixes.
+    # If the user specifies -o file.o, it is replaced with file.lo
+    case $libobj in
+    *.[cCFSifmso] | \
+    *.ada | *.adb | *.ads | *.asm | \
+    *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \
+    *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup)
+      func_xform "$libobj"
+      libobj=$func_xform_result
+      ;;
+    esac
+
+    case $libobj in
+    *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;;
+    *)
+      func_fatal_error "cannot determine name of library object from '$libobj'"
+      ;;
+    esac
+
+    func_infer_tag $base_compile
+
+    for arg in $later; do
+      case $arg in
+      -shared)
+	test yes = "$build_libtool_libs" \
+	  || func_fatal_configuration "cannot build a shared library"
+	build_old_libs=no
+	continue
+	;;
+
+      -static)
+	build_libtool_libs=no
+	build_old_libs=yes
+	continue
+	;;
+
+      -prefer-pic)
+	pic_mode=yes
+	continue
+	;;
+
+      -prefer-non-pic)
+	pic_mode=no
+	continue
+	;;
+      esac
+    done
+
+    func_quote_for_eval "$libobj"
+    test "X$libobj" != "X$func_quote_for_eval_result" \
+      && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"'	 &()|`$[]' \
+      && func_warning "libobj name '$libobj' may not contain shell special characters."
+    func_dirname_and_basename "$obj" "/" ""
+    objname=$func_basename_result
+    xdir=$func_dirname_result
+    lobj=$xdir$objdir/$objname
+
+    test -z "$base_compile" && \
+      func_fatal_help "you must specify a compilation command"
+
+    # Delete any leftover library objects.
+    if test yes = "$build_old_libs"; then
+      removelist="$obj $lobj $libobj ${libobj}T"
+    else
+      removelist="$lobj $libobj ${libobj}T"
+    fi
+
+    # On Cygwin there's no "real" PIC flag so we must build both object types
+    case $host_os in
+    cygwin* | mingw* | pw32* | os2* | cegcc*)
+      pic_mode=default
+      ;;
+    esac
+    if test no = "$pic_mode" && test pass_all != "$deplibs_check_method"; then
+      # non-PIC code in shared libraries is not supported
+      pic_mode=default
+    fi
+
+    # Calculate the filename of the output object if compiler does
+    # not support -o with -c
+    if test no = "$compiler_c_o"; then
+      output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.$objext
+      lockfile=$output_obj.lock
+    else
+      output_obj=
+      need_locks=no
+      lockfile=
+    fi
+
+    # Lock this critical section if it is needed
+    # We use this script file to make the link, it avoids creating a new file
+    if test yes = "$need_locks"; then
+      until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do
+	func_echo "Waiting for $lockfile to be removed"
+	sleep 2
+      done
+    elif test warn = "$need_locks"; then
+      if test -f "$lockfile"; then
+	$ECHO "\
+*** ERROR, $lockfile exists and contains:
+`cat $lockfile 2>/dev/null`
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support '-c' and '-o' together.  If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+	$opt_dry_run || $RM $removelist
+	exit $EXIT_FAILURE
+      fi
+      func_append removelist " $output_obj"
+      $ECHO "$srcfile" > "$lockfile"
+    fi
+
+    $opt_dry_run || $RM $removelist
+    func_append removelist " $lockfile"
+    trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15
+
+    func_to_tool_file "$srcfile" func_convert_file_msys_to_w32
+    srcfile=$func_to_tool_file_result
+    func_quote_for_eval "$srcfile"
+    qsrcfile=$func_quote_for_eval_result
+
+    # Only build a PIC object if we are building libtool libraries.
+    if test yes = "$build_libtool_libs"; then
+      # Without this assignment, base_compile gets emptied.
+      fbsd_hideous_sh_bug=$base_compile
+
+      if test no != "$pic_mode"; then
+	command="$base_compile $qsrcfile $pic_flag"
+      else
+	# Don't build PIC code
+	command="$base_compile $qsrcfile"
+      fi
+
+      func_mkdir_p "$xdir$objdir"
+
+      if test -z "$output_obj"; then
+	# Place PIC objects in $objdir
+	func_append command " -o $lobj"
+      fi
+
+      func_show_eval_locale "$command"	\
+          'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE'
+
+      if test warn = "$need_locks" &&
+	 test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+	$ECHO "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support '-c' and '-o' together.  If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+	$opt_dry_run || $RM $removelist
+	exit $EXIT_FAILURE
+      fi
+
+      # Just move the object if needed, then go on to compile the next one
+      if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then
+	func_show_eval '$MV "$output_obj" "$lobj"' \
+	  'error=$?; $opt_dry_run || $RM $removelist; exit $error'
+      fi
+
+      # Allow error messages only from the first compilation.
+      if test yes = "$suppress_opt"; then
+	suppress_output=' >/dev/null 2>&1'
+      fi
+    fi
+
+    # Only build a position-dependent object if we build old libraries.
+    if test yes = "$build_old_libs"; then
+      if test yes != "$pic_mode"; then
+	# Don't build PIC code
+	command="$base_compile $qsrcfile$pie_flag"
+      else
+	command="$base_compile $qsrcfile $pic_flag"
+      fi
+      if test yes = "$compiler_c_o"; then
+	func_append command " -o $obj"
+      fi
+
+      # Suppress compiler output if we already did a PIC compilation.
+      func_append command "$suppress_output"
+      func_show_eval_locale "$command" \
+        '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE'
+
+      if test warn = "$need_locks" &&
+	 test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+	$ECHO "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support '-c' and '-o' together.  If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+	$opt_dry_run || $RM $removelist
+	exit $EXIT_FAILURE
+      fi
+
+      # Just move the object if needed
+      if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then
+	func_show_eval '$MV "$output_obj" "$obj"' \
+	  'error=$?; $opt_dry_run || $RM $removelist; exit $error'
+      fi
+    fi
+
+    $opt_dry_run || {
+      func_write_libtool_object "$libobj" "$objdir/$objname" "$objname"
+
+      # Unlock the critical section if it was locked
+      if test no != "$need_locks"; then
+	removelist=$lockfile
+        $RM "$lockfile"
+      fi
+    }
+
+    exit $EXIT_SUCCESS
+}
+
+$opt_help || {
+  test compile = "$opt_mode" && func_mode_compile ${1+"$@"}
+}
+
+func_mode_help ()
+{
+    # We need to display help for each of the modes.
+    case $opt_mode in
+      "")
+        # Generic help is extracted from the usage comments
+        # at the start of this file.
+        func_help
+        ;;
+
+      clean)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE...
+
+Remove files from the build directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically '/bin/rm').  RM-OPTIONS are options (such as '-f') to be passed
+to RM.
+
+If FILE is a libtool library, object or program, all the files associated
+with it are deleted. Otherwise, only FILE itself is deleted using RM."
+        ;;
+
+      compile)
+      $ECHO \
+"Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE
+
+Compile a source file into a libtool library object.
+
+This mode accepts the following additional options:
+
+  -o OUTPUT-FILE    set the output file name to OUTPUT-FILE
+  -no-suppress      do not suppress compiler output for multiple passes
+  -prefer-pic       try to build PIC objects only
+  -prefer-non-pic   try to build non-PIC objects only
+  -shared           do not build a '.o' file suitable for static linking
+  -static           only build a '.o' file suitable for static linking
+  -Wc,FLAG          pass FLAG directly to the compiler
+
+COMPILE-COMMAND is a command to be used in creating a 'standard' object file
+from the given SOURCEFILE.
+
+The output file name is determined by removing the directory component from
+SOURCEFILE, then substituting the C source code suffix '.c' with the
+library object suffix, '.lo'."
+        ;;
+
+      execute)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]...
+
+Automatically set library path, then run a program.
+
+This mode accepts the following additional options:
+
+  -dlopen FILE      add the directory containing FILE to the library path
+
+This mode sets the library path environment variable according to '-dlopen'
+flags.
+
+If any of the ARGS are libtool executable wrappers, then they are translated
+into their corresponding uninstalled binary, and any of their required library
+directories are added to the library path.
+
+Then, COMMAND is executed, with ARGS as arguments."
+        ;;
+
+      finish)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=finish [LIBDIR]...
+
+Complete the installation of libtool libraries.
+
+Each LIBDIR is a directory that contains libtool libraries.
+
+The commands that this mode executes may require superuser privileges.  Use
+the '--dry-run' option if you just want to see what would be executed."
+        ;;
+
+      install)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND...
+
+Install executables or libraries.
+
+INSTALL-COMMAND is the installation command.  The first component should be
+either the 'install' or 'cp' program.
+
+The following components of INSTALL-COMMAND are treated specially:
+
+  -inst-prefix-dir PREFIX-DIR  Use PREFIX-DIR as a staging area for installation
+
+The rest of the components are interpreted as arguments to that command (only
+BSD-compatible install options are recognized)."
+        ;;
+
+      link)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=link LINK-COMMAND...
+
+Link object files or libraries together to form another library, or to
+create an executable program.
+
+LINK-COMMAND is a command using the C compiler that you would use to create
+a program from several object files.
+
+The following components of LINK-COMMAND are treated specially:
+
+  -all-static       do not do any dynamic linking at all
+  -avoid-version    do not add a version suffix if possible
+  -bindir BINDIR    specify path to binaries directory (for systems where
+                    libraries must be found in the PATH setting at runtime)
+  -dlopen FILE      '-dlpreopen' FILE if it cannot be dlopened at runtime
+  -dlpreopen FILE   link in FILE and add its symbols to lt_preloaded_symbols
+  -export-dynamic   allow symbols from OUTPUT-FILE to be resolved with dlsym(3)
+  -export-symbols SYMFILE
+                    try to export only the symbols listed in SYMFILE
+  -export-symbols-regex REGEX
+                    try to export only the symbols matching REGEX
+  -LLIBDIR          search LIBDIR for required installed libraries
+  -lNAME            OUTPUT-FILE requires the installed library libNAME
+  -module           build a library that can dlopened
+  -no-fast-install  disable the fast-install mode
+  -no-install       link a not-installable executable
+  -no-undefined     declare that a library does not refer to external symbols
+  -o OUTPUT-FILE    create OUTPUT-FILE from the specified objects
+  -objectlist FILE  use a list of object files found in FILE to specify objects
+  -os2dllname NAME  force a short DLL name on OS/2 (no effect on other OSes)
+  -precious-files-regex REGEX
+                    don't remove output files matching REGEX
+  -release RELEASE  specify package release information
+  -rpath LIBDIR     the created library will eventually be installed in LIBDIR
+  -R[ ]LIBDIR       add LIBDIR to the runtime path of programs and libraries
+  -shared           only do dynamic linking of libtool libraries
+  -shrext SUFFIX    override the standard shared library file extension
+  -static           do not do any dynamic linking of uninstalled libtool libraries
+  -static-libtool-libs
+                    do not do any dynamic linking of libtool libraries
+  -version-info CURRENT[:REVISION[:AGE]]
+                    specify library version info [each variable defaults to 0]
+  -weak LIBNAME     declare that the target provides the LIBNAME interface
+  -Wc,FLAG
+  -Xcompiler FLAG   pass linker-specific FLAG directly to the compiler
+  -Wl,FLAG
+  -Xlinker FLAG     pass linker-specific FLAG directly to the linker
+  -XCClinker FLAG   pass link-specific FLAG to the compiler driver (CC)
+
+All other options (arguments beginning with '-') are ignored.
+
+Every other argument is treated as a filename.  Files ending in '.la' are
+treated as uninstalled libtool libraries, other files are standard or library
+object files.
+
+If the OUTPUT-FILE ends in '.la', then a libtool library is created,
+only library objects ('.lo' files) may be specified, and '-rpath' is
+required, except when creating a convenience library.
+
+If OUTPUT-FILE ends in '.a' or '.lib', then a standard library is created
+using 'ar' and 'ranlib', or on Windows using 'lib'.
+
+If OUTPUT-FILE ends in '.lo' or '.$objext', then a reloadable object file
+is created, otherwise an executable program is created."
+        ;;
+
+      uninstall)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE...
+
+Remove libraries from an installation directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically '/bin/rm').  RM-OPTIONS are options (such as '-f') to be passed
+to RM.
+
+If FILE is a libtool library, all the files associated with it are deleted.
+Otherwise, only FILE itself is deleted using RM."
+        ;;
+
+      *)
+        func_fatal_help "invalid operation mode '$opt_mode'"
+        ;;
+    esac
+
+    echo
+    $ECHO "Try '$progname --help' for more information about other modes."
+}
+
+# Now that we've collected a possible --mode arg, show help if necessary
+if $opt_help; then
+  if test : = "$opt_help"; then
+    func_mode_help
+  else
+    {
+      func_help noexit
+      for opt_mode in compile link execute install finish uninstall clean; do
+	func_mode_help
+      done
+    } | $SED -n '1p; 2,$s/^Usage:/  or: /p'
+    {
+      func_help noexit
+      for opt_mode in compile link execute install finish uninstall clean; do
+	echo
+	func_mode_help
+      done
+    } |
+    $SED '1d
+      /^When reporting/,/^Report/{
+	H
+	d
+      }
+      $x
+      /information about other modes/d
+      /more detailed .*MODE/d
+      s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/'
+  fi
+  exit $?
+fi
+
+
+# func_mode_execute arg...
+func_mode_execute ()
+{
+    $debug_cmd
+
+    # The first argument is the command name.
+    cmd=$nonopt
+    test -z "$cmd" && \
+      func_fatal_help "you must specify a COMMAND"
+
+    # Handle -dlopen flags immediately.
+    for file in $opt_dlopen; do
+      test -f "$file" \
+	|| func_fatal_help "'$file' is not a file"
+
+      dir=
+      case $file in
+      *.la)
+	func_resolve_sysroot "$file"
+	file=$func_resolve_sysroot_result
+
+	# Check to see that this really is a libtool archive.
+	func_lalib_unsafe_p "$file" \
+	  || func_fatal_help "'$lib' is not a valid libtool archive"
+
+	# Read the libtool library.
+	dlname=
+	library_names=
+	func_source "$file"
+
+	# Skip this library if it cannot be dlopened.
+	if test -z "$dlname"; then
+	  # Warn if it was a shared library.
+	  test -n "$library_names" && \
+	    func_warning "'$file' was not linked with '-export-dynamic'"
+	  continue
+	fi
+
+	func_dirname "$file" "" "."
+	dir=$func_dirname_result
+
+	if test -f "$dir/$objdir/$dlname"; then
+	  func_append dir "/$objdir"
+	else
+	  if test ! -f "$dir/$dlname"; then
+	    func_fatal_error "cannot find '$dlname' in '$dir' or '$dir/$objdir'"
+	  fi
+	fi
+	;;
+
+      *.lo)
+	# Just add the directory containing the .lo file.
+	func_dirname "$file" "" "."
+	dir=$func_dirname_result
+	;;
+
+      *)
+	func_warning "'-dlopen' is ignored for non-libtool libraries and objects"
+	continue
+	;;
+      esac
+
+      # Get the absolute pathname.
+      absdir=`cd "$dir" && pwd`
+      test -n "$absdir" && dir=$absdir
+
+      # Now add the directory to shlibpath_var.
+      if eval "test -z \"\$$shlibpath_var\""; then
+	eval "$shlibpath_var=\"\$dir\""
+      else
+	eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\""
+      fi
+    done
+
+    # This variable tells wrapper scripts just to set shlibpath_var
+    # rather than running their programs.
+    libtool_execute_magic=$magic
+
+    # Check if any of the arguments is a wrapper script.
+    args=
+    for file
+    do
+      case $file in
+      -* | *.la | *.lo ) ;;
+      *)
+	# Do a test to see if this is really a libtool program.
+	if func_ltwrapper_script_p "$file"; then
+	  func_source "$file"
+	  # Transform arg to wrapped name.
+	  file=$progdir/$program
+	elif func_ltwrapper_executable_p "$file"; then
+	  func_ltwrapper_scriptname "$file"
+	  func_source "$func_ltwrapper_scriptname_result"
+	  # Transform arg to wrapped name.
+	  file=$progdir/$program
+	fi
+	;;
+      esac
+      # Quote arguments (to preserve shell metacharacters).
+      func_append_quoted args "$file"
+    done
+
+    if $opt_dry_run; then
+      # Display what would be done.
+      if test -n "$shlibpath_var"; then
+	eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\""
+	echo "export $shlibpath_var"
+      fi
+      $ECHO "$cmd$args"
+      exit $EXIT_SUCCESS
+    else
+      if test -n "$shlibpath_var"; then
+	# Export the shlibpath_var.
+	eval "export $shlibpath_var"
+      fi
+
+      # Restore saved environment variables
+      for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
+      do
+	eval "if test \"\${save_$lt_var+set}\" = set; then
+                $lt_var=\$save_$lt_var; export $lt_var
+	      else
+		$lt_unset $lt_var
+	      fi"
+      done
+
+      # Now prepare to actually exec the command.
+      exec_cmd=\$cmd$args
+    fi
+}
+
+test execute = "$opt_mode" && func_mode_execute ${1+"$@"}
+
+
+# func_mode_finish arg...
+func_mode_finish ()
+{
+    $debug_cmd
+
+    libs=
+    libdirs=
+    admincmds=
+
+    for opt in "$nonopt" ${1+"$@"}
+    do
+      if test -d "$opt"; then
+	func_append libdirs " $opt"
+
+      elif test -f "$opt"; then
+	if func_lalib_unsafe_p "$opt"; then
+	  func_append libs " $opt"
+	else
+	  func_warning "'$opt' is not a valid libtool archive"
+	fi
+
+      else
+	func_fatal_error "invalid argument '$opt'"
+      fi
+    done
+
+    if test -n "$libs"; then
+      if test -n "$lt_sysroot"; then
+        sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"`
+        sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;"
+      else
+        sysroot_cmd=
+      fi
+
+      # Remove sysroot references
+      if $opt_dry_run; then
+        for lib in $libs; do
+          echo "removing references to $lt_sysroot and '=' prefixes from $lib"
+        done
+      else
+        tmpdir=`func_mktempdir`
+        for lib in $libs; do
+	  $SED -e "$sysroot_cmd s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \
+	    > $tmpdir/tmp-la
+	  mv -f $tmpdir/tmp-la $lib
+	done
+        ${RM}r "$tmpdir"
+      fi
+    fi
+
+    if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
+      for libdir in $libdirs; do
+	if test -n "$finish_cmds"; then
+	  # Do each command in the finish commands.
+	  func_execute_cmds "$finish_cmds" 'admincmds="$admincmds
+'"$cmd"'"'
+	fi
+	if test -n "$finish_eval"; then
+	  # Do the single finish_eval.
+	  eval cmds=\"$finish_eval\"
+	  $opt_dry_run || eval "$cmds" || func_append admincmds "
+       $cmds"
+	fi
+      done
+    fi
+
+    # Exit here if they wanted silent mode.
+    $opt_quiet && exit $EXIT_SUCCESS
+
+    if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
+      echo "----------------------------------------------------------------------"
+      echo "Libraries have been installed in:"
+      for libdir in $libdirs; do
+	$ECHO "   $libdir"
+      done
+      echo
+      echo "If you ever happen to want to link against installed libraries"
+      echo "in a given directory, LIBDIR, you must either use libtool, and"
+      echo "specify the full pathname of the library, or use the '-LLIBDIR'"
+      echo "flag during linking and do at least one of the following:"
+      if test -n "$shlibpath_var"; then
+	echo "   - add LIBDIR to the '$shlibpath_var' environment variable"
+	echo "     during execution"
+      fi
+      if test -n "$runpath_var"; then
+	echo "   - add LIBDIR to the '$runpath_var' environment variable"
+	echo "     during linking"
+      fi
+      if test -n "$hardcode_libdir_flag_spec"; then
+	libdir=LIBDIR
+	eval flag=\"$hardcode_libdir_flag_spec\"
+
+	$ECHO "   - use the '$flag' linker flag"
+      fi
+      if test -n "$admincmds"; then
+	$ECHO "   - have your system administrator run these commands:$admincmds"
+      fi
+      if test -f /etc/ld.so.conf; then
+	echo "   - have your system administrator add LIBDIR to '/etc/ld.so.conf'"
+      fi
+      echo
+
+      echo "See any operating system documentation about shared libraries for"
+      case $host in
+	solaris2.[6789]|solaris2.1[0-9])
+	  echo "more information, such as the ld(1), crle(1) and ld.so(8) manual"
+	  echo "pages."
+	  ;;
+	*)
+	  echo "more information, such as the ld(1) and ld.so(8) manual pages."
+	  ;;
+      esac
+      echo "----------------------------------------------------------------------"
+    fi
+    exit $EXIT_SUCCESS
+}
+
+test finish = "$opt_mode" && func_mode_finish ${1+"$@"}
+
+
+# func_mode_install arg...
+func_mode_install ()
+{
+    $debug_cmd
+
+    # There may be an optional sh(1) argument at the beginning of
+    # install_prog (especially on Windows NT).
+    if test "$SHELL" = "$nonopt" || test /bin/sh = "$nonopt" ||
+       # Allow the use of GNU shtool's install command.
+       case $nonopt in *shtool*) :;; *) false;; esac
+    then
+      # Aesthetically quote it.
+      func_quote_for_eval "$nonopt"
+      install_prog="$func_quote_for_eval_result "
+      arg=$1
+      shift
+    else
+      install_prog=
+      arg=$nonopt
+    fi
+
+    # The real first argument should be the name of the installation program.
+    # Aesthetically quote it.
+    func_quote_for_eval "$arg"
+    func_append install_prog "$func_quote_for_eval_result"
+    install_shared_prog=$install_prog
+    case " $install_prog " in
+      *[\\\ /]cp\ *) install_cp=: ;;
+      *) install_cp=false ;;
+    esac
+
+    # We need to accept at least all the BSD install flags.
+    dest=
+    files=
+    opts=
+    prev=
+    install_type=
+    isdir=false
+    stripme=
+    no_mode=:
+    for arg
+    do
+      arg2=
+      if test -n "$dest"; then
+	func_append files " $dest"
+	dest=$arg
+	continue
+      fi
+
+      case $arg in
+      -d) isdir=: ;;
+      -f)
+	if $install_cp; then :; else
+	  prev=$arg
+	fi
+	;;
+      -g | -m | -o)
+	prev=$arg
+	;;
+      -s)
+	stripme=" -s"
+	continue
+	;;
+      -*)
+	;;
+      *)
+	# If the previous option needed an argument, then skip it.
+	if test -n "$prev"; then
+	  if test X-m = "X$prev" && test -n "$install_override_mode"; then
+	    arg2=$install_override_mode
+	    no_mode=false
+	  fi
+	  prev=
+	else
+	  dest=$arg
+	  continue
+	fi
+	;;
+      esac
+
+      # Aesthetically quote the argument.
+      func_quote_for_eval "$arg"
+      func_append install_prog " $func_quote_for_eval_result"
+      if test -n "$arg2"; then
+	func_quote_for_eval "$arg2"
+      fi
+      func_append install_shared_prog " $func_quote_for_eval_result"
+    done
+
+    test -z "$install_prog" && \
+      func_fatal_help "you must specify an install program"
+
+    test -n "$prev" && \
+      func_fatal_help "the '$prev' option requires an argument"
+
+    if test -n "$install_override_mode" && $no_mode; then
+      if $install_cp; then :; else
+	func_quote_for_eval "$install_override_mode"
+	func_append install_shared_prog " -m $func_quote_for_eval_result"
+      fi
+    fi
+
+    if test -z "$files"; then
+      if test -z "$dest"; then
+	func_fatal_help "no file or destination specified"
+      else
+	func_fatal_help "you must specify a destination"
+      fi
+    fi
+
+    # Strip any trailing slash from the destination.
+    func_stripname '' '/' "$dest"
+    dest=$func_stripname_result
+
+    # Check to see that the destination is a directory.
+    test -d "$dest" && isdir=:
+    if $isdir; then
+      destdir=$dest
+      destname=
+    else
+      func_dirname_and_basename "$dest" "" "."
+      destdir=$func_dirname_result
+      destname=$func_basename_result
+
+      # Not a directory, so check to see that there is only one file specified.
+      set dummy $files; shift
+      test "$#" -gt 1 && \
+	func_fatal_help "'$dest' is not a directory"
+    fi
+    case $destdir in
+    [\\/]* | [A-Za-z]:[\\/]*) ;;
+    *)
+      for file in $files; do
+	case $file in
+	*.lo) ;;
+	*)
+	  func_fatal_help "'$destdir' must be an absolute directory name"
+	  ;;
+	esac
+      done
+      ;;
+    esac
+
+    # This variable tells wrapper scripts just to set variables rather
+    # than running their programs.
+    libtool_install_magic=$magic
+
+    staticlibs=
+    future_libdirs=
+    current_libdirs=
+    for file in $files; do
+
+      # Do each installation.
+      case $file in
+      *.$libext)
+	# Do the static libraries later.
+	func_append staticlibs " $file"
+	;;
+
+      *.la)
+	func_resolve_sysroot "$file"
+	file=$func_resolve_sysroot_result
+
+	# Check to see that this really is a libtool archive.
+	func_lalib_unsafe_p "$file" \
+	  || func_fatal_help "'$file' is not a valid libtool archive"
+
+	library_names=
+	old_library=
+	relink_command=
+	func_source "$file"
+
+	# Add the libdir to current_libdirs if it is the destination.
+	if test "X$destdir" = "X$libdir"; then
+	  case "$current_libdirs " in
+	  *" $libdir "*) ;;
+	  *) func_append current_libdirs " $libdir" ;;
+	  esac
+	else
+	  # Note the libdir as a future libdir.
+	  case "$future_libdirs " in
+	  *" $libdir "*) ;;
+	  *) func_append future_libdirs " $libdir" ;;
+	  esac
+	fi
+
+	func_dirname "$file" "/" ""
+	dir=$func_dirname_result
+	func_append dir "$objdir"
+
+	if test -n "$relink_command"; then
+	  # Determine the prefix the user has applied to our future dir.
+	  inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"`
+
+	  # Don't allow the user to place us outside of our expected
+	  # location b/c this prevents finding dependent libraries that
+	  # are installed to the same prefix.
+	  # At present, this check doesn't affect windows .dll's that
+	  # are installed into $libdir/../bin (currently, that works fine)
+	  # but it's something to keep an eye on.
+	  test "$inst_prefix_dir" = "$destdir" && \
+	    func_fatal_error "error: cannot install '$file' to a directory not ending in $libdir"
+
+	  if test -n "$inst_prefix_dir"; then
+	    # Stick the inst_prefix_dir data into the link command.
+	    relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"`
+	  else
+	    relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"`
+	  fi
+
+	  func_warning "relinking '$file'"
+	  func_show_eval "$relink_command" \
+	    'func_fatal_error "error: relink '\''$file'\'' with the above command before installing it"'
+	fi
+
+	# See the names of the shared library.
+	set dummy $library_names; shift
+	if test -n "$1"; then
+	  realname=$1
+	  shift
+
+	  srcname=$realname
+	  test -n "$relink_command" && srcname=${realname}T
+
+	  # Install the shared library and build the symlinks.
+	  func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \
+	      'exit $?'
+	  tstripme=$stripme
+	  case $host_os in
+	  cygwin* | mingw* | pw32* | cegcc*)
+	    case $realname in
+	    *.dll.a)
+	      tstripme=
+	      ;;
+	    esac
+	    ;;
+	  os2*)
+	    case $realname in
+	    *_dll.a)
+	      tstripme=
+	      ;;
+	    esac
+	    ;;
+	  esac
+	  if test -n "$tstripme" && test -n "$striplib"; then
+	    func_show_eval "$striplib $destdir/$realname" 'exit $?'
+	  fi
+
+	  if test "$#" -gt 0; then
+	    # Delete the old symlinks, and create new ones.
+	    # Try 'ln -sf' first, because the 'ln' binary might depend on
+	    # the symlink we replace!  Solaris /bin/ln does not understand -f,
+	    # so we also need to try rm && ln -s.
+	    for linkname
+	    do
+	      test "$linkname" != "$realname" \
+		&& func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })"
+	    done
+	  fi
+
+	  # Do each command in the postinstall commands.
+	  lib=$destdir/$realname
+	  func_execute_cmds "$postinstall_cmds" 'exit $?'
+	fi
+
+	# Install the pseudo-library for information purposes.
+	func_basename "$file"
+	name=$func_basename_result
+	instname=$dir/${name}i
+	func_show_eval "$install_prog $instname $destdir/$name" 'exit $?'
+
+	# Maybe install the static library, too.
+	test -n "$old_library" && func_append staticlibs " $dir/$old_library"
+	;;
+
+      *.lo)
+	# Install (i.e. copy) a libtool object.
+
+	# Figure out destination file name, if it wasn't already specified.
+	if test -n "$destname"; then
+	  destfile=$destdir/$destname
+	else
+	  func_basename "$file"
+	  destfile=$func_basename_result
+	  destfile=$destdir/$destfile
+	fi
+
+	# Deduce the name of the destination old-style object file.
+	case $destfile in
+	*.lo)
+	  func_lo2o "$destfile"
+	  staticdest=$func_lo2o_result
+	  ;;
+	*.$objext)
+	  staticdest=$destfile
+	  destfile=
+	  ;;
+	*)
+	  func_fatal_help "cannot copy a libtool object to '$destfile'"
+	  ;;
+	esac
+
+	# Install the libtool object if requested.
+	test -n "$destfile" && \
+	  func_show_eval "$install_prog $file $destfile" 'exit $?'
+
+	# Install the old object if enabled.
+	if test yes = "$build_old_libs"; then
+	  # Deduce the name of the old-style object file.
+	  func_lo2o "$file"
+	  staticobj=$func_lo2o_result
+	  func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?'
+	fi
+	exit $EXIT_SUCCESS
+	;;
+
+      *)
+	# Figure out destination file name, if it wasn't already specified.
+	if test -n "$destname"; then
+	  destfile=$destdir/$destname
+	else
+	  func_basename "$file"
+	  destfile=$func_basename_result
+	  destfile=$destdir/$destfile
+	fi
+
+	# If the file is missing, and there is a .exe on the end, strip it
+	# because it is most likely a libtool script we actually want to
+	# install
+	stripped_ext=
+	case $file in
+	  *.exe)
+	    if test ! -f "$file"; then
+	      func_stripname '' '.exe' "$file"
+	      file=$func_stripname_result
+	      stripped_ext=.exe
+	    fi
+	    ;;
+	esac
+
+	# Do a test to see if this is really a libtool program.
+	case $host in
+	*cygwin* | *mingw*)
+	    if func_ltwrapper_executable_p "$file"; then
+	      func_ltwrapper_scriptname "$file"
+	      wrapper=$func_ltwrapper_scriptname_result
+	    else
+	      func_stripname '' '.exe' "$file"
+	      wrapper=$func_stripname_result
+	    fi
+	    ;;
+	*)
+	    wrapper=$file
+	    ;;
+	esac
+	if func_ltwrapper_script_p "$wrapper"; then
+	  notinst_deplibs=
+	  relink_command=
+
+	  func_source "$wrapper"
+
+	  # Check the variables that should have been set.
+	  test -z "$generated_by_libtool_version" && \
+	    func_fatal_error "invalid libtool wrapper script '$wrapper'"
+
+	  finalize=:
+	  for lib in $notinst_deplibs; do
+	    # Check to see that each library is installed.
+	    libdir=
+	    if test -f "$lib"; then
+	      func_source "$lib"
+	    fi
+	    libfile=$libdir/`$ECHO "$lib" | $SED 's%^.*/%%g'`
+	    if test -n "$libdir" && test ! -f "$libfile"; then
+	      func_warning "'$lib' has not been installed in '$libdir'"
+	      finalize=false
+	    fi
+	  done
+
+	  relink_command=
+	  func_source "$wrapper"
+
+	  outputname=
+	  if test no = "$fast_install" && test -n "$relink_command"; then
+	    $opt_dry_run || {
+	      if $finalize; then
+	        tmpdir=`func_mktempdir`
+		func_basename "$file$stripped_ext"
+		file=$func_basename_result
+	        outputname=$tmpdir/$file
+	        # Replace the output file specification.
+	        relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'`
+
+	        $opt_quiet || {
+	          func_quote_for_expand "$relink_command"
+		  eval "func_echo $func_quote_for_expand_result"
+	        }
+	        if eval "$relink_command"; then :
+	          else
+		  func_error "error: relink '$file' with the above command before installing it"
+		  $opt_dry_run || ${RM}r "$tmpdir"
+		  continue
+	        fi
+	        file=$outputname
+	      else
+	        func_warning "cannot relink '$file'"
+	      fi
+	    }
+	  else
+	    # Install the binary that we compiled earlier.
+	    file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"`
+	  fi
+	fi
+
+	# remove .exe since cygwin /usr/bin/install will append another
+	# one anyway
+	case $install_prog,$host in
+	*/usr/bin/install*,*cygwin*)
+	  case $file:$destfile in
+	  *.exe:*.exe)
+	    # this is ok
+	    ;;
+	  *.exe:*)
+	    destfile=$destfile.exe
+	    ;;
+	  *:*.exe)
+	    func_stripname '' '.exe' "$destfile"
+	    destfile=$func_stripname_result
+	    ;;
+	  esac
+	  ;;
+	esac
+	func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?'
+	$opt_dry_run || if test -n "$outputname"; then
+	  ${RM}r "$tmpdir"
+	fi
+	;;
+      esac
+    done
+
+    for file in $staticlibs; do
+      func_basename "$file"
+      name=$func_basename_result
+
+      # Set up the ranlib parameters.
+      oldlib=$destdir/$name
+      func_to_tool_file "$oldlib" func_convert_file_msys_to_w32
+      tool_oldlib=$func_to_tool_file_result
+
+      func_show_eval "$install_prog \$file \$oldlib" 'exit $?'
+
+      if test -n "$stripme" && test -n "$old_striplib"; then
+	func_show_eval "$old_striplib $tool_oldlib" 'exit $?'
+      fi
+
+      # Do each command in the postinstall commands.
+      func_execute_cmds "$old_postinstall_cmds" 'exit $?'
+    done
+
+    test -n "$future_libdirs" && \
+      func_warning "remember to run '$progname --finish$future_libdirs'"
+
+    if test -n "$current_libdirs"; then
+      # Maybe just do a dry run.
+      $opt_dry_run && current_libdirs=" -n$current_libdirs"
+      exec_cmd='$SHELL "$progpath" $preserve_args --finish$current_libdirs'
+    else
+      exit $EXIT_SUCCESS
+    fi
+}
+
+test install = "$opt_mode" && func_mode_install ${1+"$@"}
+
+
+# func_generate_dlsyms outputname originator pic_p
+# Extract symbols from dlprefiles and create ${outputname}S.o with
+# a dlpreopen symbol table.
+func_generate_dlsyms ()
+{
+    $debug_cmd
+
+    my_outputname=$1
+    my_originator=$2
+    my_pic_p=${3-false}
+    my_prefix=`$ECHO "$my_originator" | $SED 's%[^a-zA-Z0-9]%_%g'`
+    my_dlsyms=
+
+    if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then
+      if test -n "$NM" && test -n "$global_symbol_pipe"; then
+	my_dlsyms=${my_outputname}S.c
+      else
+	func_error "not configured to extract global symbols from dlpreopened files"
+      fi
+    fi
+
+    if test -n "$my_dlsyms"; then
+      case $my_dlsyms in
+      "") ;;
+      *.c)
+	# Discover the nlist of each of the dlfiles.
+	nlist=$output_objdir/$my_outputname.nm
+
+	func_show_eval "$RM $nlist ${nlist}S ${nlist}T"
+
+	# Parse the name list into a source file.
+	func_verbose "creating $output_objdir/$my_dlsyms"
+
+	$opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\
+/* $my_dlsyms - symbol resolution table for '$my_outputname' dlsym emulation. */
+/* Generated by $PROGRAM (GNU $PACKAGE) $VERSION */
+
+#ifdef __cplusplus
+extern \"C\" {
+#endif
+
+#if defined __GNUC__ && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4))
+#pragma GCC diagnostic ignored \"-Wstrict-prototypes\"
+#endif
+
+/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests.  */
+#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE
+/* DATA imports from DLLs on WIN32 can't be const, because runtime
+   relocations are performed -- see ld's documentation on pseudo-relocs.  */
+# define LT_DLSYM_CONST
+#elif defined __osf__
+/* This system does not cope well with relocations in const data.  */
+# define LT_DLSYM_CONST
+#else
+# define LT_DLSYM_CONST const
+#endif
+
+#define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0)
+
+/* External symbol declarations for the compiler. */\
+"
+
+	if test yes = "$dlself"; then
+	  func_verbose "generating symbol list for '$output'"
+
+	  $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist"
+
+	  # Add our own program objects to the symbol list.
+	  progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP`
+	  for progfile in $progfiles; do
+	    func_to_tool_file "$progfile" func_convert_file_msys_to_w32
+	    func_verbose "extracting global C symbols from '$func_to_tool_file_result'"
+	    $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'"
+	  done
+
+	  if test -n "$exclude_expsyms"; then
+	    $opt_dry_run || {
+	      eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T'
+	      eval '$MV "$nlist"T "$nlist"'
+	    }
+	  fi
+
+	  if test -n "$export_symbols_regex"; then
+	    $opt_dry_run || {
+	      eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T'
+	      eval '$MV "$nlist"T "$nlist"'
+	    }
+	  fi
+
+	  # Prepare the list of exported symbols
+	  if test -z "$export_symbols"; then
+	    export_symbols=$output_objdir/$outputname.exp
+	    $opt_dry_run || {
+	      $RM $export_symbols
+	      eval "$SED -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"'
+	      case $host in
+	      *cygwin* | *mingw* | *cegcc* )
+                eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
+                eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"'
+	        ;;
+	      esac
+	    }
+	  else
+	    $opt_dry_run || {
+	      eval "$SED -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"'
+	      eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T'
+	      eval '$MV "$nlist"T "$nlist"'
+	      case $host in
+	        *cygwin* | *mingw* | *cegcc* )
+	          eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
+	          eval 'cat "$nlist" >> "$output_objdir/$outputname.def"'
+	          ;;
+	      esac
+	    }
+	  fi
+	fi
+
+	for dlprefile in $dlprefiles; do
+	  func_verbose "extracting global C symbols from '$dlprefile'"
+	  func_basename "$dlprefile"
+	  name=$func_basename_result
+          case $host in
+	    *cygwin* | *mingw* | *cegcc* )
+	      # if an import library, we need to obtain dlname
+	      if func_win32_import_lib_p "$dlprefile"; then
+	        func_tr_sh "$dlprefile"
+	        eval "curr_lafile=\$libfile_$func_tr_sh_result"
+	        dlprefile_dlbasename=
+	        if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then
+	          # Use subshell, to avoid clobbering current variable values
+	          dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"`
+	          if test -n "$dlprefile_dlname"; then
+	            func_basename "$dlprefile_dlname"
+	            dlprefile_dlbasename=$func_basename_result
+	          else
+	            # no lafile. user explicitly requested -dlpreopen <import library>.
+	            $sharedlib_from_linklib_cmd "$dlprefile"
+	            dlprefile_dlbasename=$sharedlib_from_linklib_result
+	          fi
+	        fi
+	        $opt_dry_run || {
+	          if test -n "$dlprefile_dlbasename"; then
+	            eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"'
+	          else
+	            func_warning "Could not compute DLL name from $name"
+	            eval '$ECHO ": $name " >> "$nlist"'
+	          fi
+	          func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
+	          eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe |
+	            $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'"
+	        }
+	      else # not an import lib
+	        $opt_dry_run || {
+	          eval '$ECHO ": $name " >> "$nlist"'
+	          func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
+	          eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'"
+	        }
+	      fi
+	    ;;
+	    *)
+	      $opt_dry_run || {
+	        eval '$ECHO ": $name " >> "$nlist"'
+	        func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
+	        eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'"
+	      }
+	    ;;
+          esac
+	done
+
+	$opt_dry_run || {
+	  # Make sure we have at least an empty file.
+	  test -f "$nlist" || : > "$nlist"
+
+	  if test -n "$exclude_expsyms"; then
+	    $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T
+	    $MV "$nlist"T "$nlist"
+	  fi
+
+	  # Try sorting and uniquifying the output.
+	  if $GREP -v "^: " < "$nlist" |
+	      if sort -k 3 </dev/null >/dev/null 2>&1; then
+		sort -k 3
+	      else
+		sort +2
+	      fi |
+	      uniq > "$nlist"S; then
+	    :
+	  else
+	    $GREP -v "^: " < "$nlist" > "$nlist"S
+	  fi
+
+	  if test -f "$nlist"S; then
+	    eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"'
+	  else
+	    echo '/* NONE */' >> "$output_objdir/$my_dlsyms"
+	  fi
+
+	  func_show_eval '$RM "${nlist}I"'
+	  if test -n "$global_symbol_to_import"; then
+	    eval "$global_symbol_to_import"' < "$nlist"S > "$nlist"I'
+	  fi
+
+	  echo >> "$output_objdir/$my_dlsyms" "\
+
+/* The mapping between symbol names and symbols.  */
+typedef struct {
+  const char *name;
+  void *address;
+} lt_dlsymlist;
+extern LT_DLSYM_CONST lt_dlsymlist
+lt_${my_prefix}_LTX_preloaded_symbols[];\
+"
+
+	  if test -s "$nlist"I; then
+	    echo >> "$output_objdir/$my_dlsyms" "\
+static void lt_syminit(void)
+{
+  LT_DLSYM_CONST lt_dlsymlist *symbol = lt_${my_prefix}_LTX_preloaded_symbols;
+  for (; symbol->name; ++symbol)
+    {"
+	    $SED 's/.*/      if (STREQ (symbol->name, \"&\")) symbol->address = (void *) \&&;/' < "$nlist"I >> "$output_objdir/$my_dlsyms"
+	    echo >> "$output_objdir/$my_dlsyms" "\
+    }
+}"
+	  fi
+	  echo >> "$output_objdir/$my_dlsyms" "\
+LT_DLSYM_CONST lt_dlsymlist
+lt_${my_prefix}_LTX_preloaded_symbols[] =
+{ {\"$my_originator\", (void *) 0},"
+
+	  if test -s "$nlist"I; then
+	    echo >> "$output_objdir/$my_dlsyms" "\
+  {\"@INIT@\", (void *) &lt_syminit},"
+	  fi
+
+	  case $need_lib_prefix in
+	  no)
+	    eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms"
+	    ;;
+	  *)
+	    eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms"
+	    ;;
+	  esac
+	  echo >> "$output_objdir/$my_dlsyms" "\
+  {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+  return lt_${my_prefix}_LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif\
+"
+	} # !$opt_dry_run
+
+	pic_flag_for_symtable=
+	case "$compile_command " in
+	*" -static "*) ;;
+	*)
+	  case $host in
+	  # compiling the symbol table file with pic_flag works around
+	  # a FreeBSD bug that causes programs to crash when -lm is
+	  # linked before any other PIC object.  But we must not use
+	  # pic_flag when linking with -static.  The problem exists in
+	  # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1.
+	  *-*-freebsd2.*|*-*-freebsd3.0*|*-*-freebsdelf3.0*)
+	    pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;;
+	  *-*-hpux*)
+	    pic_flag_for_symtable=" $pic_flag"  ;;
+	  *)
+	    $my_pic_p && pic_flag_for_symtable=" $pic_flag"
+	    ;;
+	  esac
+	  ;;
+	esac
+	symtab_cflags=
+	for arg in $LTCFLAGS; do
+	  case $arg in
+	  -pie | -fpie | -fPIE) ;;
+	  *) func_append symtab_cflags " $arg" ;;
+	  esac
+	done
+
+	# Now compile the dynamic symbol file.
+	func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?'
+
+	# Clean up the generated files.
+	func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T" "${nlist}I"'
+
+	# Transform the symbol file into the correct name.
+	symfileobj=$output_objdir/${my_outputname}S.$objext
+	case $host in
+	*cygwin* | *mingw* | *cegcc* )
+	  if test -f "$output_objdir/$my_outputname.def"; then
+	    compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
+	    finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
+	  else
+	    compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+	    finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+	  fi
+	  ;;
+	*)
+	  compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+	  finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+	  ;;
+	esac
+	;;
+      *)
+	func_fatal_error "unknown suffix for '$my_dlsyms'"
+	;;
+      esac
+    else
+      # We keep going just in case the user didn't refer to
+      # lt_preloaded_symbols.  The linker will fail if global_symbol_pipe
+      # really was required.
+
+      # Nullify the symbol file.
+      compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"`
+      finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"`
+    fi
+}
+
+# func_cygming_gnu_implib_p ARG
+# This predicate returns with zero status (TRUE) if
+# ARG is a GNU/binutils-style import library. Returns
+# with nonzero status (FALSE) otherwise.
+func_cygming_gnu_implib_p ()
+{
+  $debug_cmd
+
+  func_to_tool_file "$1" func_convert_file_msys_to_w32
+  func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'`
+  test -n "$func_cygming_gnu_implib_tmp"
+}
+
+# func_cygming_ms_implib_p ARG
+# This predicate returns with zero status (TRUE) if
+# ARG is an MS-style import library. Returns
+# with nonzero status (FALSE) otherwise.
+func_cygming_ms_implib_p ()
+{
+  $debug_cmd
+
+  func_to_tool_file "$1" func_convert_file_msys_to_w32
+  func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'`
+  test -n "$func_cygming_ms_implib_tmp"
+}
+
+# func_win32_libid arg
+# return the library type of file 'arg'
+#
+# Need a lot of goo to handle *both* DLLs and import libs
+# Has to be a shell function in order to 'eat' the argument
+# that is supplied when $file_magic_command is called.
+# Despite the name, also deal with 64 bit binaries.
+func_win32_libid ()
+{
+  $debug_cmd
+
+  win32_libid_type=unknown
+  win32_fileres=`file -L $1 2>/dev/null`
+  case $win32_fileres in
+  *ar\ archive\ import\ library*) # definitely import
+    win32_libid_type="x86 archive import"
+    ;;
+  *ar\ archive*) # could be an import, or static
+    # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD.
+    if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null |
+       $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then
+      case $nm_interface in
+      "MS dumpbin")
+	if func_cygming_ms_implib_p "$1" ||
+	   func_cygming_gnu_implib_p "$1"
+	then
+	  win32_nmres=import
+	else
+	  win32_nmres=
+	fi
+	;;
+      *)
+	func_to_tool_file "$1" func_convert_file_msys_to_w32
+	win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" |
+	  $SED -n -e '
+	    1,100{
+		/ I /{
+		    s|.*|import|
+		    p
+		    q
+		}
+	    }'`
+	;;
+      esac
+      case $win32_nmres in
+      import*)  win32_libid_type="x86 archive import";;
+      *)        win32_libid_type="x86 archive static";;
+      esac
+    fi
+    ;;
+  *DLL*)
+    win32_libid_type="x86 DLL"
+    ;;
+  *executable*) # but shell scripts are "executable" too...
+    case $win32_fileres in
+    *MS\ Windows\ PE\ Intel*)
+      win32_libid_type="x86 DLL"
+      ;;
+    esac
+    ;;
+  esac
+  $ECHO "$win32_libid_type"
+}
+
+# func_cygming_dll_for_implib ARG
+#
+# Platform-specific function to extract the
+# name of the DLL associated with the specified
+# import library ARG.
+# Invoked by eval'ing the libtool variable
+#    $sharedlib_from_linklib_cmd
+# Result is available in the variable
+#    $sharedlib_from_linklib_result
+func_cygming_dll_for_implib ()
+{
+  $debug_cmd
+
+  sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"`
+}
+
+# func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs
+#
+# The is the core of a fallback implementation of a
+# platform-specific function to extract the name of the
+# DLL associated with the specified import library LIBNAME.
+#
+# SECTION_NAME is either .idata$6 or .idata$7, depending
+# on the platform and compiler that created the implib.
+#
+# Echos the name of the DLL associated with the
+# specified import library.
+func_cygming_dll_for_implib_fallback_core ()
+{
+  $debug_cmd
+
+  match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"`
+  $OBJDUMP -s --section "$1" "$2" 2>/dev/null |
+    $SED '/^Contents of section '"$match_literal"':/{
+      # Place marker at beginning of archive member dllname section
+      s/.*/====MARK====/
+      p
+      d
+    }
+    # These lines can sometimes be longer than 43 characters, but
+    # are always uninteresting
+    /:[	 ]*file format pe[i]\{,1\}-/d
+    /^In archive [^:]*:/d
+    # Ensure marker is printed
+    /^====MARK====/p
+    # Remove all lines with less than 43 characters
+    /^.\{43\}/!d
+    # From remaining lines, remove first 43 characters
+    s/^.\{43\}//' |
+    $SED -n '
+      # Join marker and all lines until next marker into a single line
+      /^====MARK====/ b para
+      H
+      $ b para
+      b
+      :para
+      x
+      s/\n//g
+      # Remove the marker
+      s/^====MARK====//
+      # Remove trailing dots and whitespace
+      s/[\. \t]*$//
+      # Print
+      /./p' |
+    # we now have a list, one entry per line, of the stringified
+    # contents of the appropriate section of all members of the
+    # archive that possess that section. Heuristic: eliminate
+    # all those that have a first or second character that is
+    # a '.' (that is, objdump's representation of an unprintable
+    # character.) This should work for all archives with less than
+    # 0x302f exports -- but will fail for DLLs whose name actually
+    # begins with a literal '.' or a single character followed by
+    # a '.'.
+    #
+    # Of those that remain, print the first one.
+    $SED -e '/^\./d;/^.\./d;q'
+}
+
+# func_cygming_dll_for_implib_fallback ARG
+# Platform-specific function to extract the
+# name of the DLL associated with the specified
+# import library ARG.
+#
+# This fallback implementation is for use when $DLLTOOL
+# does not support the --identify-strict option.
+# Invoked by eval'ing the libtool variable
+#    $sharedlib_from_linklib_cmd
+# Result is available in the variable
+#    $sharedlib_from_linklib_result
+func_cygming_dll_for_implib_fallback ()
+{
+  $debug_cmd
+
+  if func_cygming_gnu_implib_p "$1"; then
+    # binutils import library
+    sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"`
+  elif func_cygming_ms_implib_p "$1"; then
+    # ms-generated import library
+    sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"`
+  else
+    # unknown
+    sharedlib_from_linklib_result=
+  fi
+}
+
+
+# func_extract_an_archive dir oldlib
+func_extract_an_archive ()
+{
+    $debug_cmd
+
+    f_ex_an_ar_dir=$1; shift
+    f_ex_an_ar_oldlib=$1
+    if test yes = "$lock_old_archive_extraction"; then
+      lockfile=$f_ex_an_ar_oldlib.lock
+      until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do
+	func_echo "Waiting for $lockfile to be removed"
+	sleep 2
+      done
+    fi
+    func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \
+		   'stat=$?; rm -f "$lockfile"; exit $stat'
+    if test yes = "$lock_old_archive_extraction"; then
+      $opt_dry_run || rm -f "$lockfile"
+    fi
+    if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then
+     :
+    else
+      func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib"
+    fi
+}
+
+
+# func_extract_archives gentop oldlib ...
+func_extract_archives ()
+{
+    $debug_cmd
+
+    my_gentop=$1; shift
+    my_oldlibs=${1+"$@"}
+    my_oldobjs=
+    my_xlib=
+    my_xabs=
+    my_xdir=
+
+    for my_xlib in $my_oldlibs; do
+      # Extract the objects.
+      case $my_xlib in
+	[\\/]* | [A-Za-z]:[\\/]*) my_xabs=$my_xlib ;;
+	*) my_xabs=`pwd`"/$my_xlib" ;;
+      esac
+      func_basename "$my_xlib"
+      my_xlib=$func_basename_result
+      my_xlib_u=$my_xlib
+      while :; do
+        case " $extracted_archives " in
+	*" $my_xlib_u "*)
+	  func_arith $extracted_serial + 1
+	  extracted_serial=$func_arith_result
+	  my_xlib_u=lt$extracted_serial-$my_xlib ;;
+	*) break ;;
+	esac
+      done
+      extracted_archives="$extracted_archives $my_xlib_u"
+      my_xdir=$my_gentop/$my_xlib_u
+
+      func_mkdir_p "$my_xdir"
+
+      case $host in
+      *-darwin*)
+	func_verbose "Extracting $my_xabs"
+	# Do not bother doing anything if just a dry run
+	$opt_dry_run || {
+	  darwin_orig_dir=`pwd`
+	  cd $my_xdir || exit $?
+	  darwin_archive=$my_xabs
+	  darwin_curdir=`pwd`
+	  func_basename "$darwin_archive"
+	  darwin_base_archive=$func_basename_result
+	  darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true`
+	  if test -n "$darwin_arches"; then
+	    darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'`
+	    darwin_arch=
+	    func_verbose "$darwin_base_archive has multiple architectures $darwin_arches"
+	    for darwin_arch in  $darwin_arches; do
+	      func_mkdir_p "unfat-$$/$darwin_base_archive-$darwin_arch"
+	      $LIPO -thin $darwin_arch -output "unfat-$$/$darwin_base_archive-$darwin_arch/$darwin_base_archive" "$darwin_archive"
+	      cd "unfat-$$/$darwin_base_archive-$darwin_arch"
+	      func_extract_an_archive "`pwd`" "$darwin_base_archive"
+	      cd "$darwin_curdir"
+	      $RM "unfat-$$/$darwin_base_archive-$darwin_arch/$darwin_base_archive"
+	    done # $darwin_arches
+            ## Okay now we've a bunch of thin objects, gotta fatten them up :)
+	    darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$sed_basename" | sort -u`
+	    darwin_file=
+	    darwin_files=
+	    for darwin_file in $darwin_filelist; do
+	      darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP`
+	      $LIPO -create -output "$darwin_file" $darwin_files
+	    done # $darwin_filelist
+	    $RM -rf unfat-$$
+	    cd "$darwin_orig_dir"
+	  else
+	    cd $darwin_orig_dir
+	    func_extract_an_archive "$my_xdir" "$my_xabs"
+	  fi # $darwin_arches
+	} # !$opt_dry_run
+	;;
+      *)
+        func_extract_an_archive "$my_xdir" "$my_xabs"
+	;;
+      esac
+      my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP`
+    done
+
+    func_extract_archives_result=$my_oldobjs
+}
+
+
+# func_emit_wrapper [arg=no]
+#
+# Emit a libtool wrapper script on stdout.
+# Don't directly open a file because we may want to
+# incorporate the script contents within a cygwin/mingw
+# wrapper executable.  Must ONLY be called from within
+# func_mode_link because it depends on a number of variables
+# set therein.
+#
+# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR
+# variable will take.  If 'yes', then the emitted script
+# will assume that the directory where it is stored is
+# the $objdir directory.  This is a cygwin/mingw-specific
+# behavior.
+func_emit_wrapper ()
+{
+	func_emit_wrapper_arg1=${1-no}
+
+	$ECHO "\
+#! $SHELL
+
+# $output - temporary wrapper script for $objdir/$outputname
+# Generated by $PROGRAM (GNU $PACKAGE) $VERSION
+#
+# The $output program cannot be directly executed until all the libtool
+# libraries that it depends on are installed.
+#
+# This wrapper script should never be moved out of the build directory.
+# If it is, it will not operate correctly.
+
+# Sed substitution that helps us do robust quoting.  It backslashifies
+# metacharacters that are still active within double-quoted strings.
+sed_quote_subst='$sed_quote_subst'
+
+# Be Bourne compatible
+if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '\${1+\"\$@\"}'='\"\$@\"'
+  setopt NO_GLOB_SUBST
+else
+  case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+relink_command=\"$relink_command\"
+
+# This environment variable determines our operation mode.
+if test \"\$libtool_install_magic\" = \"$magic\"; then
+  # install mode needs the following variables:
+  generated_by_libtool_version='$macro_version'
+  notinst_deplibs='$notinst_deplibs'
+else
+  # When we are sourced in execute mode, \$file and \$ECHO are already set.
+  if test \"\$libtool_execute_magic\" != \"$magic\"; then
+    file=\"\$0\""
+
+    qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"`
+    $ECHO "\
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+\$1
+_LTECHO_EOF'
+}
+    ECHO=\"$qECHO\"
+  fi
+
+# Very basic option parsing. These options are (a) specific to
+# the libtool wrapper, (b) are identical between the wrapper
+# /script/ and the wrapper /executable/ that is used only on
+# windows platforms, and (c) all begin with the string "--lt-"
+# (application programs are unlikely to have options that match
+# this pattern).
+#
+# There are only two supported options: --lt-debug and
+# --lt-dump-script. There is, deliberately, no --lt-help.
+#
+# The first argument to this parsing function should be the
+# script's $0 value, followed by "$@".
+lt_option_debug=
+func_parse_lt_options ()
+{
+  lt_script_arg0=\$0
+  shift
+  for lt_opt
+  do
+    case \"\$lt_opt\" in
+    --lt-debug) lt_option_debug=1 ;;
+    --lt-dump-script)
+        lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\`
+        test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=.
+        lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\`
+        cat \"\$lt_dump_D/\$lt_dump_F\"
+        exit 0
+      ;;
+    --lt-*)
+        \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2
+        exit 1
+      ;;
+    esac
+  done
+
+  # Print the debug banner immediately:
+  if test -n \"\$lt_option_debug\"; then
+    echo \"$outputname:$output:\$LINENO: libtool wrapper (GNU $PACKAGE) $VERSION\" 1>&2
+  fi
+}
+
+# Used when --lt-debug. Prints its arguments to stdout
+# (redirection is the responsibility of the caller)
+func_lt_dump_args ()
+{
+  lt_dump_args_N=1;
+  for lt_arg
+  do
+    \$ECHO \"$outputname:$output:\$LINENO: newargv[\$lt_dump_args_N]: \$lt_arg\"
+    lt_dump_args_N=\`expr \$lt_dump_args_N + 1\`
+  done
+}
+
+# Core function for launching the target application
+func_exec_program_core ()
+{
+"
+  case $host in
+  # Backslashes separate directories on plain windows
+  *-*-mingw | *-*-os2* | *-cegcc*)
+    $ECHO "\
+      if test -n \"\$lt_option_debug\"; then
+        \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir\\\\\$program\" 1>&2
+        func_lt_dump_args \${1+\"\$@\"} 1>&2
+      fi
+      exec \"\$progdir\\\\\$program\" \${1+\"\$@\"}
+"
+    ;;
+
+  *)
+    $ECHO "\
+      if test -n \"\$lt_option_debug\"; then
+        \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir/\$program\" 1>&2
+        func_lt_dump_args \${1+\"\$@\"} 1>&2
+      fi
+      exec \"\$progdir/\$program\" \${1+\"\$@\"}
+"
+    ;;
+  esac
+  $ECHO "\
+      \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2
+      exit 1
+}
+
+# A function to encapsulate launching the target application
+# Strips options in the --lt-* namespace from \$@ and
+# launches target application with the remaining arguments.
+func_exec_program ()
+{
+  case \" \$* \" in
+  *\\ --lt-*)
+    for lt_wr_arg
+    do
+      case \$lt_wr_arg in
+      --lt-*) ;;
+      *) set x \"\$@\" \"\$lt_wr_arg\"; shift;;
+      esac
+      shift
+    done ;;
+  esac
+  func_exec_program_core \${1+\"\$@\"}
+}
+
+  # Parse options
+  func_parse_lt_options \"\$0\" \${1+\"\$@\"}
+
+  # Find the directory that this script lives in.
+  thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\`
+  test \"x\$thisdir\" = \"x\$file\" && thisdir=.
+
+  # Follow symbolic links until we get to the real thisdir.
+  file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\`
+  while test -n \"\$file\"; do
+    destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\`
+
+    # If there was a directory component, then change thisdir.
+    if test \"x\$destdir\" != \"x\$file\"; then
+      case \"\$destdir\" in
+      [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;;
+      *) thisdir=\"\$thisdir/\$destdir\" ;;
+      esac
+    fi
+
+    file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\`
+    file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\`
+  done
+
+  # Usually 'no', except on cygwin/mingw when embedded into
+  # the cwrapper.
+  WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1
+  if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then
+    # special case for '.'
+    if test \"\$thisdir\" = \".\"; then
+      thisdir=\`pwd\`
+    fi
+    # remove .libs from thisdir
+    case \"\$thisdir\" in
+    *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;;
+    $objdir )   thisdir=. ;;
+    esac
+  fi
+
+  # Try to get the absolute directory name.
+  absdir=\`cd \"\$thisdir\" && pwd\`
+  test -n \"\$absdir\" && thisdir=\"\$absdir\"
+"
+
+	if test yes = "$fast_install"; then
+	  $ECHO "\
+  program=lt-'$outputname'$exeext
+  progdir=\"\$thisdir/$objdir\"
+
+  if test ! -f \"\$progdir/\$program\" ||
+     { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | $SED 1q\`; \\
+       test \"X\$file\" != \"X\$progdir/\$program\"; }; then
+
+    file=\"\$\$-\$program\"
+
+    if test ! -d \"\$progdir\"; then
+      $MKDIR \"\$progdir\"
+    else
+      $RM \"\$progdir/\$file\"
+    fi"
+
+	  $ECHO "\
+
+    # relink executable if necessary
+    if test -n \"\$relink_command\"; then
+      if relink_command_output=\`eval \$relink_command 2>&1\`; then :
+      else
+	\$ECHO \"\$relink_command_output\" >&2
+	$RM \"\$progdir/\$file\"
+	exit 1
+      fi
+    fi
+
+    $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null ||
+    { $RM \"\$progdir/\$program\";
+      $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; }
+    $RM \"\$progdir/\$file\"
+  fi"
+	else
+	  $ECHO "\
+  program='$outputname'
+  progdir=\"\$thisdir/$objdir\"
+"
+	fi
+
+	$ECHO "\
+
+  if test -f \"\$progdir/\$program\"; then"
+
+	# fixup the dll searchpath if we need to.
+	#
+	# Fix the DLL searchpath if we need to.  Do this before prepending
+	# to shlibpath, because on Windows, both are PATH and uninstalled
+	# libraries must come first.
+	if test -n "$dllsearchpath"; then
+	  $ECHO "\
+    # Add the dll search path components to the executable PATH
+    PATH=$dllsearchpath:\$PATH
+"
+	fi
+
+	# Export our shlibpath_var if we have one.
+	if test yes = "$shlibpath_overrides_runpath" && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+	  $ECHO "\
+    # Add our own library path to $shlibpath_var
+    $shlibpath_var=\"$temp_rpath\$$shlibpath_var\"
+
+    # Some systems cannot cope with colon-terminated $shlibpath_var
+    # The second colon is a workaround for a bug in BeOS R4 sed
+    $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\`
+
+    export $shlibpath_var
+"
+	fi
+
+	$ECHO "\
+    if test \"\$libtool_execute_magic\" != \"$magic\"; then
+      # Run the actual program with our arguments.
+      func_exec_program \${1+\"\$@\"}
+    fi
+  else
+    # The program doesn't exist.
+    \$ECHO \"\$0: error: '\$progdir/\$program' does not exist\" 1>&2
+    \$ECHO \"This script is just a wrapper for \$program.\" 1>&2
+    \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2
+    exit 1
+  fi
+fi\
+"
+}
+
+
+# func_emit_cwrapperexe_src
+# emit the source code for a wrapper executable on stdout
+# Must ONLY be called from within func_mode_link because
+# it depends on a number of variable set therein.
+func_emit_cwrapperexe_src ()
+{
+	cat <<EOF
+
+/* $cwrappersource - temporary wrapper executable for $objdir/$outputname
+   Generated by $PROGRAM (GNU $PACKAGE) $VERSION
+
+   The $output program cannot be directly executed until all the libtool
+   libraries that it depends on are installed.
+
+   This wrapper executable should never be moved out of the build directory.
+   If it is, it will not operate correctly.
+*/
+EOF
+	    cat <<"EOF"
+#ifdef _MSC_VER
+# define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef _MSC_VER
+# include <direct.h>
+# include <process.h>
+# include <io.h>
+#else
+# include <unistd.h>
+# include <stdint.h>
+# ifdef __CYGWIN__
+#  include <io.h>
+# endif
+#endif
+#include <malloc.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0)
+
+/* declarations of non-ANSI functions */
+#if defined __MINGW32__
+# ifdef __STRICT_ANSI__
+int _putenv (const char *);
+# endif
+#elif defined __CYGWIN__
+# ifdef __STRICT_ANSI__
+char *realpath (const char *, char *);
+int putenv (char *);
+int setenv (const char *, const char *, int);
+# endif
+/* #elif defined other_platform || defined ... */
+#endif
+
+/* portability defines, excluding path handling macros */
+#if defined _MSC_VER
+# define setmode _setmode
+# define stat    _stat
+# define chmod   _chmod
+# define getcwd  _getcwd
+# define putenv  _putenv
+# define S_IXUSR _S_IEXEC
+#elif defined __MINGW32__
+# define setmode _setmode
+# define stat    _stat
+# define chmod   _chmod
+# define getcwd  _getcwd
+# define putenv  _putenv
+#elif defined __CYGWIN__
+# define HAVE_SETENV
+# define FOPEN_WB "wb"
+/* #elif defined other platforms ... */
+#endif
+
+#if defined PATH_MAX
+# define LT_PATHMAX PATH_MAX
+#elif defined MAXPATHLEN
+# define LT_PATHMAX MAXPATHLEN
+#else
+# define LT_PATHMAX 1024
+#endif
+
+#ifndef S_IXOTH
+# define S_IXOTH 0
+#endif
+#ifndef S_IXGRP
+# define S_IXGRP 0
+#endif
+
+/* path handling portability macros */
+#ifndef DIR_SEPARATOR
+# define DIR_SEPARATOR '/'
+# define PATH_SEPARATOR ':'
+#endif
+
+#if defined _WIN32 || defined __MSDOS__ || defined __DJGPP__ || \
+  defined __OS2__
+# define HAVE_DOS_BASED_FILE_SYSTEM
+# define FOPEN_WB "wb"
+# ifndef DIR_SEPARATOR_2
+#  define DIR_SEPARATOR_2 '\\'
+# endif
+# ifndef PATH_SEPARATOR_2
+#  define PATH_SEPARATOR_2 ';'
+# endif
+#endif
+
+#ifndef DIR_SEPARATOR_2
+# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR)
+#else /* DIR_SEPARATOR_2 */
+# define IS_DIR_SEPARATOR(ch) \
+	(((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2))
+#endif /* DIR_SEPARATOR_2 */
+
+#ifndef PATH_SEPARATOR_2
+# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR)
+#else /* PATH_SEPARATOR_2 */
+# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2)
+#endif /* PATH_SEPARATOR_2 */
+
+#ifndef FOPEN_WB
+# define FOPEN_WB "w"
+#endif
+#ifndef _O_BINARY
+# define _O_BINARY 0
+#endif
+
+#define XMALLOC(type, num)      ((type *) xmalloc ((num) * sizeof(type)))
+#define XFREE(stale) do { \
+  if (stale) { free (stale); stale = 0; } \
+} while (0)
+
+#if defined LT_DEBUGWRAPPER
+static int lt_debug = 1;
+#else
+static int lt_debug = 0;
+#endif
+
+const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */
+
+void *xmalloc (size_t num);
+char *xstrdup (const char *string);
+const char *base_name (const char *name);
+char *find_executable (const char *wrapper);
+char *chase_symlinks (const char *pathspec);
+int make_executable (const char *path);
+int check_executable (const char *path);
+char *strendzap (char *str, const char *pat);
+void lt_debugprintf (const char *file, int line, const char *fmt, ...);
+void lt_fatal (const char *file, int line, const char *message, ...);
+static const char *nonnull (const char *s);
+static const char *nonempty (const char *s);
+void lt_setenv (const char *name, const char *value);
+char *lt_extend_str (const char *orig_value, const char *add, int to_end);
+void lt_update_exe_path (const char *name, const char *value);
+void lt_update_lib_path (const char *name, const char *value);
+char **prepare_spawn (char **argv);
+void lt_dump_script (FILE *f);
+EOF
+
+	    cat <<EOF
+#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 5)
+# define externally_visible volatile
+#else
+# define externally_visible __attribute__((externally_visible)) volatile
+#endif
+externally_visible const char * MAGIC_EXE = "$magic_exe";
+const char * LIB_PATH_VARNAME = "$shlibpath_var";
+EOF
+
+	    if test yes = "$shlibpath_overrides_runpath" && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+              func_to_host_path "$temp_rpath"
+	      cat <<EOF
+const char * LIB_PATH_VALUE   = "$func_to_host_path_result";
+EOF
+	    else
+	      cat <<"EOF"
+const char * LIB_PATH_VALUE   = "";
+EOF
+	    fi
+
+	    if test -n "$dllsearchpath"; then
+              func_to_host_path "$dllsearchpath:"
+	      cat <<EOF
+const char * EXE_PATH_VARNAME = "PATH";
+const char * EXE_PATH_VALUE   = "$func_to_host_path_result";
+EOF
+	    else
+	      cat <<"EOF"
+const char * EXE_PATH_VARNAME = "";
+const char * EXE_PATH_VALUE   = "";
+EOF
+	    fi
+
+	    if test yes = "$fast_install"; then
+	      cat <<EOF
+const char * TARGET_PROGRAM_NAME = "lt-$outputname"; /* hopefully, no .exe */
+EOF
+	    else
+	      cat <<EOF
+const char * TARGET_PROGRAM_NAME = "$outputname"; /* hopefully, no .exe */
+EOF
+	    fi
+
+
+	    cat <<"EOF"
+
+#define LTWRAPPER_OPTION_PREFIX         "--lt-"
+
+static const char *ltwrapper_option_prefix = LTWRAPPER_OPTION_PREFIX;
+static const char *dumpscript_opt       = LTWRAPPER_OPTION_PREFIX "dump-script";
+static const char *debug_opt            = LTWRAPPER_OPTION_PREFIX "debug";
+
+int
+main (int argc, char *argv[])
+{
+  char **newargz;
+  int  newargc;
+  char *tmp_pathspec;
+  char *actual_cwrapper_path;
+  char *actual_cwrapper_name;
+  char *target_name;
+  char *lt_argv_zero;
+  int rval = 127;
+
+  int i;
+
+  program_name = (char *) xstrdup (base_name (argv[0]));
+  newargz = XMALLOC (char *, (size_t) argc + 1);
+
+  /* very simple arg parsing; don't want to rely on getopt
+   * also, copy all non cwrapper options to newargz, except
+   * argz[0], which is handled differently
+   */
+  newargc=0;
+  for (i = 1; i < argc; i++)
+    {
+      if (STREQ (argv[i], dumpscript_opt))
+	{
+EOF
+	    case $host in
+	      *mingw* | *cygwin* )
+		# make stdout use "unix" line endings
+		echo "          setmode(1,_O_BINARY);"
+		;;
+	      esac
+
+	    cat <<"EOF"
+	  lt_dump_script (stdout);
+	  return 0;
+	}
+      if (STREQ (argv[i], debug_opt))
+	{
+          lt_debug = 1;
+          continue;
+	}
+      if (STREQ (argv[i], ltwrapper_option_prefix))
+        {
+          /* however, if there is an option in the LTWRAPPER_OPTION_PREFIX
+             namespace, but it is not one of the ones we know about and
+             have already dealt with, above (inluding dump-script), then
+             report an error. Otherwise, targets might begin to believe
+             they are allowed to use options in the LTWRAPPER_OPTION_PREFIX
+             namespace. The first time any user complains about this, we'll
+             need to make LTWRAPPER_OPTION_PREFIX a configure-time option
+             or a configure.ac-settable value.
+           */
+          lt_fatal (__FILE__, __LINE__,
+		    "unrecognized %s option: '%s'",
+                    ltwrapper_option_prefix, argv[i]);
+        }
+      /* otherwise ... */
+      newargz[++newargc] = xstrdup (argv[i]);
+    }
+  newargz[++newargc] = NULL;
+
+EOF
+	    cat <<EOF
+  /* The GNU banner must be the first non-error debug message */
+  lt_debugprintf (__FILE__, __LINE__, "libtool wrapper (GNU $PACKAGE) $VERSION\n");
+EOF
+	    cat <<"EOF"
+  lt_debugprintf (__FILE__, __LINE__, "(main) argv[0]: %s\n", argv[0]);
+  lt_debugprintf (__FILE__, __LINE__, "(main) program_name: %s\n", program_name);
+
+  tmp_pathspec = find_executable (argv[0]);
+  if (tmp_pathspec == NULL)
+    lt_fatal (__FILE__, __LINE__, "couldn't find %s", argv[0]);
+  lt_debugprintf (__FILE__, __LINE__,
+                  "(main) found exe (before symlink chase) at: %s\n",
+		  tmp_pathspec);
+
+  actual_cwrapper_path = chase_symlinks (tmp_pathspec);
+  lt_debugprintf (__FILE__, __LINE__,
+                  "(main) found exe (after symlink chase) at: %s\n",
+		  actual_cwrapper_path);
+  XFREE (tmp_pathspec);
+
+  actual_cwrapper_name = xstrdup (base_name (actual_cwrapper_path));
+  strendzap (actual_cwrapper_path, actual_cwrapper_name);
+
+  /* wrapper name transforms */
+  strendzap (actual_cwrapper_name, ".exe");
+  tmp_pathspec = lt_extend_str (actual_cwrapper_name, ".exe", 1);
+  XFREE (actual_cwrapper_name);
+  actual_cwrapper_name = tmp_pathspec;
+  tmp_pathspec = 0;
+
+  /* target_name transforms -- use actual target program name; might have lt- prefix */
+  target_name = xstrdup (base_name (TARGET_PROGRAM_NAME));
+  strendzap (target_name, ".exe");
+  tmp_pathspec = lt_extend_str (target_name, ".exe", 1);
+  XFREE (target_name);
+  target_name = tmp_pathspec;
+  tmp_pathspec = 0;
+
+  lt_debugprintf (__FILE__, __LINE__,
+		  "(main) libtool target name: %s\n",
+		  target_name);
+EOF
+
+	    cat <<EOF
+  newargz[0] =
+    XMALLOC (char, (strlen (actual_cwrapper_path) +
+		    strlen ("$objdir") + 1 + strlen (actual_cwrapper_name) + 1));
+  strcpy (newargz[0], actual_cwrapper_path);
+  strcat (newargz[0], "$objdir");
+  strcat (newargz[0], "/");
+EOF
+
+	    cat <<"EOF"
+  /* stop here, and copy so we don't have to do this twice */
+  tmp_pathspec = xstrdup (newargz[0]);
+
+  /* do NOT want the lt- prefix here, so use actual_cwrapper_name */
+  strcat (newargz[0], actual_cwrapper_name);
+
+  /* DO want the lt- prefix here if it exists, so use target_name */
+  lt_argv_zero = lt_extend_str (tmp_pathspec, target_name, 1);
+  XFREE (tmp_pathspec);
+  tmp_pathspec = NULL;
+EOF
+
+	    case $host_os in
+	      mingw*)
+	    cat <<"EOF"
+  {
+    char* p;
+    while ((p = strchr (newargz[0], '\\')) != NULL)
+      {
+	*p = '/';
+      }
+    while ((p = strchr (lt_argv_zero, '\\')) != NULL)
+      {
+	*p = '/';
+      }
+  }
+EOF
+	    ;;
+	    esac
+
+	    cat <<"EOF"
+  XFREE (target_name);
+  XFREE (actual_cwrapper_path);
+  XFREE (actual_cwrapper_name);
+
+  lt_setenv ("BIN_SH", "xpg4"); /* for Tru64 */
+  lt_setenv ("DUALCASE", "1");  /* for MSK sh */
+  /* Update the DLL searchpath.  EXE_PATH_VALUE ($dllsearchpath) must
+     be prepended before (that is, appear after) LIB_PATH_VALUE ($temp_rpath)
+     because on Windows, both *_VARNAMEs are PATH but uninstalled
+     libraries must come first. */
+  lt_update_exe_path (EXE_PATH_VARNAME, EXE_PATH_VALUE);
+  lt_update_lib_path (LIB_PATH_VARNAME, LIB_PATH_VALUE);
+
+  lt_debugprintf (__FILE__, __LINE__, "(main) lt_argv_zero: %s\n",
+		  nonnull (lt_argv_zero));
+  for (i = 0; i < newargc; i++)
+    {
+      lt_debugprintf (__FILE__, __LINE__, "(main) newargz[%d]: %s\n",
+		      i, nonnull (newargz[i]));
+    }
+
+EOF
+
+	    case $host_os in
+	      mingw*)
+		cat <<"EOF"
+  /* execv doesn't actually work on mingw as expected on unix */
+  newargz = prepare_spawn (newargz);
+  rval = (int) _spawnv (_P_WAIT, lt_argv_zero, (const char * const *) newargz);
+  if (rval == -1)
+    {
+      /* failed to start process */
+      lt_debugprintf (__FILE__, __LINE__,
+		      "(main) failed to launch target \"%s\": %s\n",
+		      lt_argv_zero, nonnull (strerror (errno)));
+      return 127;
+    }
+  return rval;
+EOF
+		;;
+	      *)
+		cat <<"EOF"
+  execv (lt_argv_zero, newargz);
+  return rval; /* =127, but avoids unused variable warning */
+EOF
+		;;
+	    esac
+
+	    cat <<"EOF"
+}
+
+void *
+xmalloc (size_t num)
+{
+  void *p = (void *) malloc (num);
+  if (!p)
+    lt_fatal (__FILE__, __LINE__, "memory exhausted");
+
+  return p;
+}
+
+char *
+xstrdup (const char *string)
+{
+  return string ? strcpy ((char *) xmalloc (strlen (string) + 1),
+			  string) : NULL;
+}
+
+const char *
+base_name (const char *name)
+{
+  const char *base;
+
+#if defined HAVE_DOS_BASED_FILE_SYSTEM
+  /* Skip over the disk name in MSDOS pathnames. */
+  if (isalpha ((unsigned char) name[0]) && name[1] == ':')
+    name += 2;
+#endif
+
+  for (base = name; *name; name++)
+    if (IS_DIR_SEPARATOR (*name))
+      base = name + 1;
+  return base;
+}
+
+int
+check_executable (const char *path)
+{
+  struct stat st;
+
+  lt_debugprintf (__FILE__, __LINE__, "(check_executable): %s\n",
+                  nonempty (path));
+  if ((!path) || (!*path))
+    return 0;
+
+  if ((stat (path, &st) >= 0)
+      && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
+    return 1;
+  else
+    return 0;
+}
+
+int
+make_executable (const char *path)
+{
+  int rval = 0;
+  struct stat st;
+
+  lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n",
+                  nonempty (path));
+  if ((!path) || (!*path))
+    return 0;
+
+  if (stat (path, &st) >= 0)
+    {
+      rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR);
+    }
+  return rval;
+}
+
+/* Searches for the full path of the wrapper.  Returns
+   newly allocated full path name if found, NULL otherwise
+   Does not chase symlinks, even on platforms that support them.
+*/
+char *
+find_executable (const char *wrapper)
+{
+  int has_slash = 0;
+  const char *p;
+  const char *p_next;
+  /* static buffer for getcwd */
+  char tmp[LT_PATHMAX + 1];
+  size_t tmp_len;
+  char *concat_name;
+
+  lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n",
+                  nonempty (wrapper));
+
+  if ((wrapper == NULL) || (*wrapper == '\0'))
+    return NULL;
+
+  /* Absolute path? */
+#if defined HAVE_DOS_BASED_FILE_SYSTEM
+  if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':')
+    {
+      concat_name = xstrdup (wrapper);
+      if (check_executable (concat_name))
+	return concat_name;
+      XFREE (concat_name);
+    }
+  else
+    {
+#endif
+      if (IS_DIR_SEPARATOR (wrapper[0]))
+	{
+	  concat_name = xstrdup (wrapper);
+	  if (check_executable (concat_name))
+	    return concat_name;
+	  XFREE (concat_name);
+	}
+#if defined HAVE_DOS_BASED_FILE_SYSTEM
+    }
+#endif
+
+  for (p = wrapper; *p; p++)
+    if (*p == '/')
+      {
+	has_slash = 1;
+	break;
+      }
+  if (!has_slash)
+    {
+      /* no slashes; search PATH */
+      const char *path = getenv ("PATH");
+      if (path != NULL)
+	{
+	  for (p = path; *p; p = p_next)
+	    {
+	      const char *q;
+	      size_t p_len;
+	      for (q = p; *q; q++)
+		if (IS_PATH_SEPARATOR (*q))
+		  break;
+	      p_len = (size_t) (q - p);
+	      p_next = (*q == '\0' ? q : q + 1);
+	      if (p_len == 0)
+		{
+		  /* empty path: current directory */
+		  if (getcwd (tmp, LT_PATHMAX) == NULL)
+		    lt_fatal (__FILE__, __LINE__, "getcwd failed: %s",
+                              nonnull (strerror (errno)));
+		  tmp_len = strlen (tmp);
+		  concat_name =
+		    XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1);
+		  memcpy (concat_name, tmp, tmp_len);
+		  concat_name[tmp_len] = '/';
+		  strcpy (concat_name + tmp_len + 1, wrapper);
+		}
+	      else
+		{
+		  concat_name =
+		    XMALLOC (char, p_len + 1 + strlen (wrapper) + 1);
+		  memcpy (concat_name, p, p_len);
+		  concat_name[p_len] = '/';
+		  strcpy (concat_name + p_len + 1, wrapper);
+		}
+	      if (check_executable (concat_name))
+		return concat_name;
+	      XFREE (concat_name);
+	    }
+	}
+      /* not found in PATH; assume curdir */
+    }
+  /* Relative path | not found in path: prepend cwd */
+  if (getcwd (tmp, LT_PATHMAX) == NULL)
+    lt_fatal (__FILE__, __LINE__, "getcwd failed: %s",
+              nonnull (strerror (errno)));
+  tmp_len = strlen (tmp);
+  concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1);
+  memcpy (concat_name, tmp, tmp_len);
+  concat_name[tmp_len] = '/';
+  strcpy (concat_name + tmp_len + 1, wrapper);
+
+  if (check_executable (concat_name))
+    return concat_name;
+  XFREE (concat_name);
+  return NULL;
+}
+
+char *
+chase_symlinks (const char *pathspec)
+{
+#ifndef S_ISLNK
+  return xstrdup (pathspec);
+#else
+  char buf[LT_PATHMAX];
+  struct stat s;
+  char *tmp_pathspec = xstrdup (pathspec);
+  char *p;
+  int has_symlinks = 0;
+  while (strlen (tmp_pathspec) && !has_symlinks)
+    {
+      lt_debugprintf (__FILE__, __LINE__,
+		      "checking path component for symlinks: %s\n",
+		      tmp_pathspec);
+      if (lstat (tmp_pathspec, &s) == 0)
+	{
+	  if (S_ISLNK (s.st_mode) != 0)
+	    {
+	      has_symlinks = 1;
+	      break;
+	    }
+
+	  /* search backwards for last DIR_SEPARATOR */
+	  p = tmp_pathspec + strlen (tmp_pathspec) - 1;
+	  while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p)))
+	    p--;
+	  if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p)))
+	    {
+	      /* no more DIR_SEPARATORS left */
+	      break;
+	    }
+	  *p = '\0';
+	}
+      else
+	{
+	  lt_fatal (__FILE__, __LINE__,
+		    "error accessing file \"%s\": %s",
+		    tmp_pathspec, nonnull (strerror (errno)));
+	}
+    }
+  XFREE (tmp_pathspec);
+
+  if (!has_symlinks)
+    {
+      return xstrdup (pathspec);
+    }
+
+  tmp_pathspec = realpath (pathspec, buf);
+  if (tmp_pathspec == 0)
+    {
+      lt_fatal (__FILE__, __LINE__,
+		"could not follow symlinks for %s", pathspec);
+    }
+  return xstrdup (tmp_pathspec);
+#endif
+}
+
+char *
+strendzap (char *str, const char *pat)
+{
+  size_t len, patlen;
+
+  assert (str != NULL);
+  assert (pat != NULL);
+
+  len = strlen (str);
+  patlen = strlen (pat);
+
+  if (patlen <= len)
+    {
+      str += len - patlen;
+      if (STREQ (str, pat))
+	*str = '\0';
+    }
+  return str;
+}
+
+void
+lt_debugprintf (const char *file, int line, const char *fmt, ...)
+{
+  va_list args;
+  if (lt_debug)
+    {
+      (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line);
+      va_start (args, fmt);
+      (void) vfprintf (stderr, fmt, args);
+      va_end (args);
+    }
+}
+
+static void
+lt_error_core (int exit_status, const char *file,
+	       int line, const char *mode,
+	       const char *message, va_list ap)
+{
+  fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode);
+  vfprintf (stderr, message, ap);
+  fprintf (stderr, ".\n");
+
+  if (exit_status >= 0)
+    exit (exit_status);
+}
+
+void
+lt_fatal (const char *file, int line, const char *message, ...)
+{
+  va_list ap;
+  va_start (ap, message);
+  lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap);
+  va_end (ap);
+}
+
+static const char *
+nonnull (const char *s)
+{
+  return s ? s : "(null)";
+}
+
+static const char *
+nonempty (const char *s)
+{
+  return (s && !*s) ? "(empty)" : nonnull (s);
+}
+
+void
+lt_setenv (const char *name, const char *value)
+{
+  lt_debugprintf (__FILE__, __LINE__,
+		  "(lt_setenv) setting '%s' to '%s'\n",
+                  nonnull (name), nonnull (value));
+  {
+#ifdef HAVE_SETENV
+    /* always make a copy, for consistency with !HAVE_SETENV */
+    char *str = xstrdup (value);
+    setenv (name, str, 1);
+#else
+    size_t len = strlen (name) + 1 + strlen (value) + 1;
+    char *str = XMALLOC (char, len);
+    sprintf (str, "%s=%s", name, value);
+    if (putenv (str) != EXIT_SUCCESS)
+      {
+        XFREE (str);
+      }
+#endif
+  }
+}
+
+char *
+lt_extend_str (const char *orig_value, const char *add, int to_end)
+{
+  char *new_value;
+  if (orig_value && *orig_value)
+    {
+      size_t orig_value_len = strlen (orig_value);
+      size_t add_len = strlen (add);
+      new_value = XMALLOC (char, add_len + orig_value_len + 1);
+      if (to_end)
+        {
+          strcpy (new_value, orig_value);
+          strcpy (new_value + orig_value_len, add);
+        }
+      else
+        {
+          strcpy (new_value, add);
+          strcpy (new_value + add_len, orig_value);
+        }
+    }
+  else
+    {
+      new_value = xstrdup (add);
+    }
+  return new_value;
+}
+
+void
+lt_update_exe_path (const char *name, const char *value)
+{
+  lt_debugprintf (__FILE__, __LINE__,
+		  "(lt_update_exe_path) modifying '%s' by prepending '%s'\n",
+                  nonnull (name), nonnull (value));
+
+  if (name && *name && value && *value)
+    {
+      char *new_value = lt_extend_str (getenv (name), value, 0);
+      /* some systems can't cope with a ':'-terminated path #' */
+      size_t len = strlen (new_value);
+      while ((len > 0) && IS_PATH_SEPARATOR (new_value[len-1]))
+        {
+          new_value[--len] = '\0';
+        }
+      lt_setenv (name, new_value);
+      XFREE (new_value);
+    }
+}
+
+void
+lt_update_lib_path (const char *name, const char *value)
+{
+  lt_debugprintf (__FILE__, __LINE__,
+		  "(lt_update_lib_path) modifying '%s' by prepending '%s'\n",
+                  nonnull (name), nonnull (value));
+
+  if (name && *name && value && *value)
+    {
+      char *new_value = lt_extend_str (getenv (name), value, 0);
+      lt_setenv (name, new_value);
+      XFREE (new_value);
+    }
+}
+
+EOF
+	    case $host_os in
+	      mingw*)
+		cat <<"EOF"
+
+/* Prepares an argument vector before calling spawn().
+   Note that spawn() does not by itself call the command interpreter
+     (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") :
+      ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+         GetVersionEx(&v);
+         v.dwPlatformId == VER_PLATFORM_WIN32_NT;
+      }) ? "cmd.exe" : "command.com").
+   Instead it simply concatenates the arguments, separated by ' ', and calls
+   CreateProcess().  We must quote the arguments since Win32 CreateProcess()
+   interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a
+   special way:
+   - Space and tab are interpreted as delimiters. They are not treated as
+     delimiters if they are surrounded by double quotes: "...".
+   - Unescaped double quotes are removed from the input. Their only effect is
+     that within double quotes, space and tab are treated like normal
+     characters.
+   - Backslashes not followed by double quotes are not special.
+   - But 2*n+1 backslashes followed by a double quote become
+     n backslashes followed by a double quote (n >= 0):
+       \" -> "
+       \\\" -> \"
+       \\\\\" -> \\"
+ */
+#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+#define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+char **
+prepare_spawn (char **argv)
+{
+  size_t argc;
+  char **new_argv;
+  size_t i;
+
+  /* Count number of arguments.  */
+  for (argc = 0; argv[argc] != NULL; argc++)
+    ;
+
+  /* Allocate new argument vector.  */
+  new_argv = XMALLOC (char *, argc + 1);
+
+  /* Put quoted arguments into the new argument vector.  */
+  for (i = 0; i < argc; i++)
+    {
+      const char *string = argv[i];
+
+      if (string[0] == '\0')
+	new_argv[i] = xstrdup ("\"\"");
+      else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL)
+	{
+	  int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL);
+	  size_t length;
+	  unsigned int backslashes;
+	  const char *s;
+	  char *quoted_string;
+	  char *p;
+
+	  length = 0;
+	  backslashes = 0;
+	  if (quote_around)
+	    length++;
+	  for (s = string; *s != '\0'; s++)
+	    {
+	      char c = *s;
+	      if (c == '"')
+		length += backslashes + 1;
+	      length++;
+	      if (c == '\\')
+		backslashes++;
+	      else
+		backslashes = 0;
+	    }
+	  if (quote_around)
+	    length += backslashes + 1;
+
+	  quoted_string = XMALLOC (char, length + 1);
+
+	  p = quoted_string;
+	  backslashes = 0;
+	  if (quote_around)
+	    *p++ = '"';
+	  for (s = string; *s != '\0'; s++)
+	    {
+	      char c = *s;
+	      if (c == '"')
+		{
+		  unsigned int j;
+		  for (j = backslashes + 1; j > 0; j--)
+		    *p++ = '\\';
+		}
+	      *p++ = c;
+	      if (c == '\\')
+		backslashes++;
+	      else
+		backslashes = 0;
+	    }
+	  if (quote_around)
+	    {
+	      unsigned int j;
+	      for (j = backslashes; j > 0; j--)
+		*p++ = '\\';
+	      *p++ = '"';
+	    }
+	  *p = '\0';
+
+	  new_argv[i] = quoted_string;
+	}
+      else
+	new_argv[i] = (char *) string;
+    }
+  new_argv[argc] = NULL;
+
+  return new_argv;
+}
+EOF
+		;;
+	    esac
+
+            cat <<"EOF"
+void lt_dump_script (FILE* f)
+{
+EOF
+	    func_emit_wrapper yes |
+	      $SED -n -e '
+s/^\(.\{79\}\)\(..*\)/\1\
+\2/
+h
+s/\([\\"]\)/\\\1/g
+s/$/\\n/
+s/\([^\n]*\).*/  fputs ("\1", f);/p
+g
+D'
+            cat <<"EOF"
+}
+EOF
+}
+# end: func_emit_cwrapperexe_src
+
+# func_win32_import_lib_p ARG
+# True if ARG is an import lib, as indicated by $file_magic_cmd
+func_win32_import_lib_p ()
+{
+    $debug_cmd
+
+    case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in
+    *import*) : ;;
+    *) false ;;
+    esac
+}
+
+# func_suncc_cstd_abi
+# !!ONLY CALL THIS FOR SUN CC AFTER $compile_command IS FULLY EXPANDED!!
+# Several compiler flags select an ABI that is incompatible with the
+# Cstd library. Avoid specifying it if any are in CXXFLAGS.
+func_suncc_cstd_abi ()
+{
+    $debug_cmd
+
+    case " $compile_command " in
+    *" -compat=g "*|*\ -std=c++[0-9][0-9]\ *|*" -library=stdcxx4 "*|*" -library=stlport4 "*)
+      suncc_use_cstd_abi=no
+      ;;
+    *)
+      suncc_use_cstd_abi=yes
+      ;;
+    esac
+}
+
+# func_mode_link arg...
+func_mode_link ()
+{
+    $debug_cmd
+
+    case $host in
+    *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+      # It is impossible to link a dll without this setting, and
+      # we shouldn't force the makefile maintainer to figure out
+      # what system we are compiling for in order to pass an extra
+      # flag for every libtool invocation.
+      # allow_undefined=no
+
+      # FIXME: Unfortunately, there are problems with the above when trying
+      # to make a dll that has undefined symbols, in which case not
+      # even a static library is built.  For now, we need to specify
+      # -no-undefined on the libtool link line when we can be certain
+      # that all symbols are satisfied, otherwise we get a static library.
+      allow_undefined=yes
+      ;;
+    *)
+      allow_undefined=yes
+      ;;
+    esac
+    libtool_args=$nonopt
+    base_compile="$nonopt $@"
+    compile_command=$nonopt
+    finalize_command=$nonopt
+
+    compile_rpath=
+    finalize_rpath=
+    compile_shlibpath=
+    finalize_shlibpath=
+    convenience=
+    old_convenience=
+    deplibs=
+    old_deplibs=
+    compiler_flags=
+    linker_flags=
+    dllsearchpath=
+    lib_search_path=`pwd`
+    inst_prefix_dir=
+    new_inherited_linker_flags=
+
+    avoid_version=no
+    bindir=
+    dlfiles=
+    dlprefiles=
+    dlself=no
+    export_dynamic=no
+    export_symbols=
+    export_symbols_regex=
+    generated=
+    libobjs=
+    ltlibs=
+    module=no
+    no_install=no
+    objs=
+    os2dllname=
+    non_pic_objects=
+    precious_files_regex=
+    prefer_static_libs=no
+    preload=false
+    prev=
+    prevarg=
+    release=
+    rpath=
+    xrpath=
+    perm_rpath=
+    temp_rpath=
+    thread_safe=no
+    vinfo=
+    vinfo_number=no
+    weak_libs=
+    single_module=$wl-single_module
+    func_infer_tag $base_compile
+
+    # We need to know -static, to get the right output filenames.
+    for arg
+    do
+      case $arg in
+      -shared)
+	test yes != "$build_libtool_libs" \
+	  && func_fatal_configuration "cannot build a shared library"
+	build_old_libs=no
+	break
+	;;
+      -all-static | -static | -static-libtool-libs)
+	case $arg in
+	-all-static)
+	  if test yes = "$build_libtool_libs" && test -z "$link_static_flag"; then
+	    func_warning "complete static linking is impossible in this configuration"
+	  fi
+	  if test -n "$link_static_flag"; then
+	    dlopen_self=$dlopen_self_static
+	  fi
+	  prefer_static_libs=yes
+	  ;;
+	-static)
+	  if test -z "$pic_flag" && test -n "$link_static_flag"; then
+	    dlopen_self=$dlopen_self_static
+	  fi
+	  prefer_static_libs=built
+	  ;;
+	-static-libtool-libs)
+	  if test -z "$pic_flag" && test -n "$link_static_flag"; then
+	    dlopen_self=$dlopen_self_static
+	  fi
+	  prefer_static_libs=yes
+	  ;;
+	esac
+	build_libtool_libs=no
+	build_old_libs=yes
+	break
+	;;
+      esac
+    done
+
+    # See if our shared archives depend on static archives.
+    test -n "$old_archive_from_new_cmds" && build_old_libs=yes
+
+    # Go through the arguments, transforming them on the way.
+    while test "$#" -gt 0; do
+      arg=$1
+      shift
+      func_quote_for_eval "$arg"
+      qarg=$func_quote_for_eval_unquoted_result
+      func_append libtool_args " $func_quote_for_eval_result"
+
+      # If the previous option needs an argument, assign it.
+      if test -n "$prev"; then
+	case $prev in
+	output)
+	  func_append compile_command " @OUTPUT@"
+	  func_append finalize_command " @OUTPUT@"
+	  ;;
+	esac
+
+	case $prev in
+	bindir)
+	  bindir=$arg
+	  prev=
+	  continue
+	  ;;
+	dlfiles|dlprefiles)
+	  $preload || {
+	    # Add the symbol object into the linking commands.
+	    func_append compile_command " @SYMFILE@"
+	    func_append finalize_command " @SYMFILE@"
+	    preload=:
+	  }
+	  case $arg in
+	  *.la | *.lo) ;;  # We handle these cases below.
+	  force)
+	    if test no = "$dlself"; then
+	      dlself=needless
+	      export_dynamic=yes
+	    fi
+	    prev=
+	    continue
+	    ;;
+	  self)
+	    if test dlprefiles = "$prev"; then
+	      dlself=yes
+	    elif test dlfiles = "$prev" && test yes != "$dlopen_self"; then
+	      dlself=yes
+	    else
+	      dlself=needless
+	      export_dynamic=yes
+	    fi
+	    prev=
+	    continue
+	    ;;
+	  *)
+	    if test dlfiles = "$prev"; then
+	      func_append dlfiles " $arg"
+	    else
+	      func_append dlprefiles " $arg"
+	    fi
+	    prev=
+	    continue
+	    ;;
+	  esac
+	  ;;
+	expsyms)
+	  export_symbols=$arg
+	  test -f "$arg" \
+	    || func_fatal_error "symbol file '$arg' does not exist"
+	  prev=
+	  continue
+	  ;;
+	expsyms_regex)
+	  export_symbols_regex=$arg
+	  prev=
+	  continue
+	  ;;
+	framework)
+	  case $host in
+	    *-*-darwin*)
+	      case "$deplibs " in
+		*" $qarg.ltframework "*) ;;
+		*) func_append deplibs " $qarg.ltframework" # this is fixed later
+		   ;;
+	      esac
+	      ;;
+	  esac
+	  prev=
+	  continue
+	  ;;
+	inst_prefix)
+	  inst_prefix_dir=$arg
+	  prev=
+	  continue
+	  ;;
+	mllvm)
+	  # Clang does not use LLVM to link, so we can simply discard any
+	  # '-mllvm $arg' options when doing the link step.
+	  prev=
+	  continue
+	  ;;
+	objectlist)
+	  if test -f "$arg"; then
+	    save_arg=$arg
+	    moreargs=
+	    for fil in `cat "$save_arg"`
+	    do
+#	      func_append moreargs " $fil"
+	      arg=$fil
+	      # A libtool-controlled object.
+
+	      # Check to see that this really is a libtool object.
+	      if func_lalib_unsafe_p "$arg"; then
+		pic_object=
+		non_pic_object=
+
+		# Read the .lo file
+		func_source "$arg"
+
+		if test -z "$pic_object" ||
+		   test -z "$non_pic_object" ||
+		   test none = "$pic_object" &&
+		   test none = "$non_pic_object"; then
+		  func_fatal_error "cannot find name of object for '$arg'"
+		fi
+
+		# Extract subdirectory from the argument.
+		func_dirname "$arg" "/" ""
+		xdir=$func_dirname_result
+
+		if test none != "$pic_object"; then
+		  # Prepend the subdirectory the object is found in.
+		  pic_object=$xdir$pic_object
+
+		  if test dlfiles = "$prev"; then
+		    if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then
+		      func_append dlfiles " $pic_object"
+		      prev=
+		      continue
+		    else
+		      # If libtool objects are unsupported, then we need to preload.
+		      prev=dlprefiles
+		    fi
+		  fi
+
+		  # CHECK ME:  I think I busted this.  -Ossama
+		  if test dlprefiles = "$prev"; then
+		    # Preload the old-style object.
+		    func_append dlprefiles " $pic_object"
+		    prev=
+		  fi
+
+		  # A PIC object.
+		  func_append libobjs " $pic_object"
+		  arg=$pic_object
+		fi
+
+		# Non-PIC object.
+		if test none != "$non_pic_object"; then
+		  # Prepend the subdirectory the object is found in.
+		  non_pic_object=$xdir$non_pic_object
+
+		  # A standard non-PIC object
+		  func_append non_pic_objects " $non_pic_object"
+		  if test -z "$pic_object" || test none = "$pic_object"; then
+		    arg=$non_pic_object
+		  fi
+		else
+		  # If the PIC object exists, use it instead.
+		  # $xdir was prepended to $pic_object above.
+		  non_pic_object=$pic_object
+		  func_append non_pic_objects " $non_pic_object"
+		fi
+	      else
+		# Only an error if not doing a dry-run.
+		if $opt_dry_run; then
+		  # Extract subdirectory from the argument.
+		  func_dirname "$arg" "/" ""
+		  xdir=$func_dirname_result
+
+		  func_lo2o "$arg"
+		  pic_object=$xdir$objdir/$func_lo2o_result
+		  non_pic_object=$xdir$func_lo2o_result
+		  func_append libobjs " $pic_object"
+		  func_append non_pic_objects " $non_pic_object"
+	        else
+		  func_fatal_error "'$arg' is not a valid libtool object"
+		fi
+	      fi
+	    done
+	  else
+	    func_fatal_error "link input file '$arg' does not exist"
+	  fi
+	  arg=$save_arg
+	  prev=
+	  continue
+	  ;;
+	os2dllname)
+	  os2dllname=$arg
+	  prev=
+	  continue
+	  ;;
+	precious_regex)
+	  precious_files_regex=$arg
+	  prev=
+	  continue
+	  ;;
+	release)
+	  release=-$arg
+	  prev=
+	  continue
+	  ;;
+	rpath | xrpath)
+	  # We need an absolute path.
+	  case $arg in
+	  [\\/]* | [A-Za-z]:[\\/]*) ;;
+	  *)
+	    func_fatal_error "only absolute run-paths are allowed"
+	    ;;
+	  esac
+	  if test rpath = "$prev"; then
+	    case "$rpath " in
+	    *" $arg "*) ;;
+	    *) func_append rpath " $arg" ;;
+	    esac
+	  else
+	    case "$xrpath " in
+	    *" $arg "*) ;;
+	    *) func_append xrpath " $arg" ;;
+	    esac
+	  fi
+	  prev=
+	  continue
+	  ;;
+	shrext)
+	  shrext_cmds=$arg
+	  prev=
+	  continue
+	  ;;
+	weak)
+	  func_append weak_libs " $arg"
+	  prev=
+	  continue
+	  ;;
+	xcclinker)
+	  func_append linker_flags " $qarg"
+	  func_append compiler_flags " $qarg"
+	  prev=
+	  func_append compile_command " $qarg"
+	  func_append finalize_command " $qarg"
+	  continue
+	  ;;
+	xcompiler)
+	  func_append compiler_flags " $qarg"
+	  prev=
+	  func_append compile_command " $qarg"
+	  func_append finalize_command " $qarg"
+	  continue
+	  ;;
+	xlinker)
+	  func_append linker_flags " $qarg"
+	  func_append compiler_flags " $wl$qarg"
+	  prev=
+	  func_append compile_command " $wl$qarg"
+	  func_append finalize_command " $wl$qarg"
+	  continue
+	  ;;
+	*)
+	  eval "$prev=\"\$arg\""
+	  prev=
+	  continue
+	  ;;
+	esac
+      fi # test -n "$prev"
+
+      prevarg=$arg
+
+      case $arg in
+      -all-static)
+	if test -n "$link_static_flag"; then
+	  # See comment for -static flag below, for more details.
+	  func_append compile_command " $link_static_flag"
+	  func_append finalize_command " $link_static_flag"
+	fi
+	continue
+	;;
+
+      -allow-undefined)
+	# FIXME: remove this flag sometime in the future.
+	func_fatal_error "'-allow-undefined' must not be used because it is the default"
+	;;
+
+      -avoid-version)
+	avoid_version=yes
+	continue
+	;;
+
+      -bindir)
+	prev=bindir
+	continue
+	;;
+
+      -dlopen)
+	prev=dlfiles
+	continue
+	;;
+
+      -dlpreopen)
+	prev=dlprefiles
+	continue
+	;;
+
+      -export-dynamic)
+	export_dynamic=yes
+	continue
+	;;
+
+      -export-symbols | -export-symbols-regex)
+	if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
+	  func_fatal_error "more than one -exported-symbols argument is not allowed"
+	fi
+	if test X-export-symbols = "X$arg"; then
+	  prev=expsyms
+	else
+	  prev=expsyms_regex
+	fi
+	continue
+	;;
+
+      -framework)
+	prev=framework
+	continue
+	;;
+
+      -inst-prefix-dir)
+	prev=inst_prefix
+	continue
+	;;
+
+      # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:*
+      # so, if we see these flags be careful not to treat them like -L
+      -L[A-Z][A-Z]*:*)
+	case $with_gcc/$host in
+	no/*-*-irix* | /*-*-irix*)
+	  func_append compile_command " $arg"
+	  func_append finalize_command " $arg"
+	  ;;
+	esac
+	continue
+	;;
+
+      -L*)
+	func_stripname "-L" '' "$arg"
+	if test -z "$func_stripname_result"; then
+	  if test "$#" -gt 0; then
+	    func_fatal_error "require no space between '-L' and '$1'"
+	  else
+	    func_fatal_error "need path for '-L' option"
+	  fi
+	fi
+	func_resolve_sysroot "$func_stripname_result"
+	dir=$func_resolve_sysroot_result
+	# We need an absolute path.
+	case $dir in
+	[\\/]* | [A-Za-z]:[\\/]*) ;;
+	*)
+	  absdir=`cd "$dir" && pwd`
+	  test -z "$absdir" && \
+	    func_fatal_error "cannot determine absolute directory name of '$dir'"
+	  dir=$absdir
+	  ;;
+	esac
+	case "$deplibs " in
+	*" -L$dir "* | *" $arg "*)
+	  # Will only happen for absolute or sysroot arguments
+	  ;;
+	*)
+	  # Preserve sysroot, but never include relative directories
+	  case $dir in
+	    [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;;
+	    *) func_append deplibs " -L$dir" ;;
+	  esac
+	  func_append lib_search_path " $dir"
+	  ;;
+	esac
+	case $host in
+	*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+	  testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'`
+	  case :$dllsearchpath: in
+	  *":$dir:"*) ;;
+	  ::) dllsearchpath=$dir;;
+	  *) func_append dllsearchpath ":$dir";;
+	  esac
+	  case :$dllsearchpath: in
+	  *":$testbindir:"*) ;;
+	  ::) dllsearchpath=$testbindir;;
+	  *) func_append dllsearchpath ":$testbindir";;
+	  esac
+	  ;;
+	esac
+	continue
+	;;
+
+      -l*)
+	if test X-lc = "X$arg" || test X-lm = "X$arg"; then
+	  case $host in
+	  *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*)
+	    # These systems don't actually have a C or math library (as such)
+	    continue
+	    ;;
+	  *-*-os2*)
+	    # These systems don't actually have a C library (as such)
+	    test X-lc = "X$arg" && continue
+	    ;;
+	  *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*)
+	    # Do not include libc due to us having libc/libc_r.
+	    test X-lc = "X$arg" && continue
+	    ;;
+	  *-*-rhapsody* | *-*-darwin1.[012])
+	    # Rhapsody C and math libraries are in the System framework
+	    func_append deplibs " System.ltframework"
+	    continue
+	    ;;
+	  *-*-sco3.2v5* | *-*-sco5v6*)
+	    # Causes problems with __ctype
+	    test X-lc = "X$arg" && continue
+	    ;;
+	  *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
+	    # Compiler inserts libc in the correct place for threads to work
+	    test X-lc = "X$arg" && continue
+	    ;;
+	  esac
+	elif test X-lc_r = "X$arg"; then
+	 case $host in
+	 *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*)
+	   # Do not include libc_r directly, use -pthread flag.
+	   continue
+	   ;;
+	 esac
+	fi
+	func_append deplibs " $arg"
+	continue
+	;;
+
+      -mllvm)
+	prev=mllvm
+	continue
+	;;
+
+      -module)
+	module=yes
+	continue
+	;;
+
+      # Tru64 UNIX uses -model [arg] to determine the layout of C++
+      # classes, name mangling, and exception handling.
+      # Darwin uses the -arch flag to determine output architecture.
+      -model|-arch|-isysroot|--sysroot)
+	func_append compiler_flags " $arg"
+	func_append compile_command " $arg"
+	func_append finalize_command " $arg"
+	prev=xcompiler
+	continue
+	;;
+
+      -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \
+      |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*)
+	func_append compiler_flags " $arg"
+	func_append compile_command " $arg"
+	func_append finalize_command " $arg"
+	case "$new_inherited_linker_flags " in
+	    *" $arg "*) ;;
+	    * ) func_append new_inherited_linker_flags " $arg" ;;
+	esac
+	continue
+	;;
+
+      -multi_module)
+	single_module=$wl-multi_module
+	continue
+	;;
+
+      -no-fast-install)
+	fast_install=no
+	continue
+	;;
+
+      -no-install)
+	case $host in
+	*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*)
+	  # The PATH hackery in wrapper scripts is required on Windows
+	  # and Darwin in order for the loader to find any dlls it needs.
+	  func_warning "'-no-install' is ignored for $host"
+	  func_warning "assuming '-no-fast-install' instead"
+	  fast_install=no
+	  ;;
+	*) no_install=yes ;;
+	esac
+	continue
+	;;
+
+      -no-undefined)
+	allow_undefined=no
+	continue
+	;;
+
+      -objectlist)
+	prev=objectlist
+	continue
+	;;
+
+      -os2dllname)
+	prev=os2dllname
+	continue
+	;;
+
+      -o) prev=output ;;
+
+      -precious-files-regex)
+	prev=precious_regex
+	continue
+	;;
+
+      -release)
+	prev=release
+	continue
+	;;
+
+      -rpath)
+	prev=rpath
+	continue
+	;;
+
+      -R)
+	prev=xrpath
+	continue
+	;;
+
+      -R*)
+	func_stripname '-R' '' "$arg"
+	dir=$func_stripname_result
+	# We need an absolute path.
+	case $dir in
+	[\\/]* | [A-Za-z]:[\\/]*) ;;
+	=*)
+	  func_stripname '=' '' "$dir"
+	  dir=$lt_sysroot$func_stripname_result
+	  ;;
+	*)
+	  func_fatal_error "only absolute run-paths are allowed"
+	  ;;
+	esac
+	case "$xrpath " in
+	*" $dir "*) ;;
+	*) func_append xrpath " $dir" ;;
+	esac
+	continue
+	;;
+
+      -shared)
+	# The effects of -shared are defined in a previous loop.
+	continue
+	;;
+
+      -shrext)
+	prev=shrext
+	continue
+	;;
+
+      -static | -static-libtool-libs)
+	# The effects of -static are defined in a previous loop.
+	# We used to do the same as -all-static on platforms that
+	# didn't have a PIC flag, but the assumption that the effects
+	# would be equivalent was wrong.  It would break on at least
+	# Digital Unix and AIX.
+	continue
+	;;
+
+      -thread-safe)
+	thread_safe=yes
+	continue
+	;;
+
+      -version-info)
+	prev=vinfo
+	continue
+	;;
+
+      -version-number)
+	prev=vinfo
+	vinfo_number=yes
+	continue
+	;;
+
+      -weak)
+        prev=weak
+	continue
+	;;
+
+      -Wc,*)
+	func_stripname '-Wc,' '' "$arg"
+	args=$func_stripname_result
+	arg=
+	save_ifs=$IFS; IFS=,
+	for flag in $args; do
+	  IFS=$save_ifs
+          func_quote_for_eval "$flag"
+	  func_append arg " $func_quote_for_eval_result"
+	  func_append compiler_flags " $func_quote_for_eval_result"
+	done
+	IFS=$save_ifs
+	func_stripname ' ' '' "$arg"
+	arg=$func_stripname_result
+	;;
+
+      -Wl,*)
+	func_stripname '-Wl,' '' "$arg"
+	args=$func_stripname_result
+	arg=
+	save_ifs=$IFS; IFS=,
+	for flag in $args; do
+	  IFS=$save_ifs
+          func_quote_for_eval "$flag"
+	  func_append arg " $wl$func_quote_for_eval_result"
+	  func_append compiler_flags " $wl$func_quote_for_eval_result"
+	  func_append linker_flags " $func_quote_for_eval_result"
+	done
+	IFS=$save_ifs
+	func_stripname ' ' '' "$arg"
+	arg=$func_stripname_result
+	;;
+
+      -Xcompiler)
+	prev=xcompiler
+	continue
+	;;
+
+      -Xlinker)
+	prev=xlinker
+	continue
+	;;
+
+      -XCClinker)
+	prev=xcclinker
+	continue
+	;;
+
+      # -msg_* for osf cc
+      -msg_*)
+	func_quote_for_eval "$arg"
+	arg=$func_quote_for_eval_result
+	;;
+
+      # Flags to be passed through unchanged, with rationale:
+      # -64, -mips[0-9]      enable 64-bit mode for the SGI compiler
+      # -r[0-9][0-9]*        specify processor for the SGI compiler
+      # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler
+      # +DA*, +DD*           enable 64-bit mode for the HP compiler
+      # -q*                  compiler args for the IBM compiler
+      # -m*, -t[45]*, -txscale* architecture-specific flags for GCC
+      # -F/path              path to uninstalled frameworks, gcc on darwin
+      # -p, -pg, --coverage, -fprofile-*  profiling flags for GCC
+      # -fstack-protector*   stack protector flags for GCC
+      # @file                GCC response files
+      # -tp=*                Portland pgcc target processor selection
+      # --sysroot=*          for sysroot support
+      # -O*, -g*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization
+      # -stdlib=*            select c++ std lib with clang
+      -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+      -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \
+      -O*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-stdlib=*)
+        func_quote_for_eval "$arg"
+	arg=$func_quote_for_eval_result
+        func_append compile_command " $arg"
+        func_append finalize_command " $arg"
+        func_append compiler_flags " $arg"
+        continue
+        ;;
+
+      -Z*)
+        if test os2 = "`expr $host : '.*\(os2\)'`"; then
+          # OS/2 uses -Zxxx to specify OS/2-specific options
+	  compiler_flags="$compiler_flags $arg"
+	  func_append compile_command " $arg"
+	  func_append finalize_command " $arg"
+	  case $arg in
+	  -Zlinker | -Zstack)
+	    prev=xcompiler
+	    ;;
+	  esac
+	  continue
+        else
+	  # Otherwise treat like 'Some other compiler flag' below
+	  func_quote_for_eval "$arg"
+	  arg=$func_quote_for_eval_result
+        fi
+	;;
+
+      # Some other compiler flag.
+      -* | +*)
+        func_quote_for_eval "$arg"
+	arg=$func_quote_for_eval_result
+	;;
+
+      *.$objext)
+	# A standard object.
+	func_append objs " $arg"
+	;;
+
+      *.lo)
+	# A libtool-controlled object.
+
+	# Check to see that this really is a libtool object.
+	if func_lalib_unsafe_p "$arg"; then
+	  pic_object=
+	  non_pic_object=
+
+	  # Read the .lo file
+	  func_source "$arg"
+
+	  if test -z "$pic_object" ||
+	     test -z "$non_pic_object" ||
+	     test none = "$pic_object" &&
+	     test none = "$non_pic_object"; then
+	    func_fatal_error "cannot find name of object for '$arg'"
+	  fi
+
+	  # Extract subdirectory from the argument.
+	  func_dirname "$arg" "/" ""
+	  xdir=$func_dirname_result
+
+	  test none = "$pic_object" || {
+	    # Prepend the subdirectory the object is found in.
+	    pic_object=$xdir$pic_object
+
+	    if test dlfiles = "$prev"; then
+	      if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then
+		func_append dlfiles " $pic_object"
+		prev=
+		continue
+	      else
+		# If libtool objects are unsupported, then we need to preload.
+		prev=dlprefiles
+	      fi
+	    fi
+
+	    # CHECK ME:  I think I busted this.  -Ossama
+	    if test dlprefiles = "$prev"; then
+	      # Preload the old-style object.
+	      func_append dlprefiles " $pic_object"
+	      prev=
+	    fi
+
+	    # A PIC object.
+	    func_append libobjs " $pic_object"
+	    arg=$pic_object
+	  }
+
+	  # Non-PIC object.
+	  if test none != "$non_pic_object"; then
+	    # Prepend the subdirectory the object is found in.
+	    non_pic_object=$xdir$non_pic_object
+
+	    # A standard non-PIC object
+	    func_append non_pic_objects " $non_pic_object"
+	    if test -z "$pic_object" || test none = "$pic_object"; then
+	      arg=$non_pic_object
+	    fi
+	  else
+	    # If the PIC object exists, use it instead.
+	    # $xdir was prepended to $pic_object above.
+	    non_pic_object=$pic_object
+	    func_append non_pic_objects " $non_pic_object"
+	  fi
+	else
+	  # Only an error if not doing a dry-run.
+	  if $opt_dry_run; then
+	    # Extract subdirectory from the argument.
+	    func_dirname "$arg" "/" ""
+	    xdir=$func_dirname_result
+
+	    func_lo2o "$arg"
+	    pic_object=$xdir$objdir/$func_lo2o_result
+	    non_pic_object=$xdir$func_lo2o_result
+	    func_append libobjs " $pic_object"
+	    func_append non_pic_objects " $non_pic_object"
+	  else
+	    func_fatal_error "'$arg' is not a valid libtool object"
+	  fi
+	fi
+	;;
+
+      *.$libext)
+	# An archive.
+	func_append deplibs " $arg"
+	func_append old_deplibs " $arg"
+	continue
+	;;
+
+      *.la)
+	# A libtool-controlled library.
+
+	func_resolve_sysroot "$arg"
+	if test dlfiles = "$prev"; then
+	  # This library was specified with -dlopen.
+	  func_append dlfiles " $func_resolve_sysroot_result"
+	  prev=
+	elif test dlprefiles = "$prev"; then
+	  # The library was specified with -dlpreopen.
+	  func_append dlprefiles " $func_resolve_sysroot_result"
+	  prev=
+	else
+	  func_append deplibs " $func_resolve_sysroot_result"
+	fi
+	continue
+	;;
+
+      # Some other compiler argument.
+      *)
+	# Unknown arguments in both finalize_command and compile_command need
+	# to be aesthetically quoted because they are evaled later.
+	func_quote_for_eval "$arg"
+	arg=$func_quote_for_eval_result
+	;;
+      esac # arg
+
+      # Now actually substitute the argument into the commands.
+      if test -n "$arg"; then
+	func_append compile_command " $arg"
+	func_append finalize_command " $arg"
+      fi
+    done # argument parsing loop
+
+    test -n "$prev" && \
+      func_fatal_help "the '$prevarg' option requires an argument"
+
+    if test yes = "$export_dynamic" && test -n "$export_dynamic_flag_spec"; then
+      eval arg=\"$export_dynamic_flag_spec\"
+      func_append compile_command " $arg"
+      func_append finalize_command " $arg"
+    fi
+
+    oldlibs=
+    # calculate the name of the file, without its directory
+    func_basename "$output"
+    outputname=$func_basename_result
+    libobjs_save=$libobjs
+
+    if test -n "$shlibpath_var"; then
+      # get the directories listed in $shlibpath_var
+      eval shlib_search_path=\`\$ECHO \"\$$shlibpath_var\" \| \$SED \'s/:/ /g\'\`
+    else
+      shlib_search_path=
+    fi
+    eval sys_lib_search_path=\"$sys_lib_search_path_spec\"
+    eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\"
+
+    # Definition is injected by LT_CONFIG during libtool generation.
+    func_munge_path_list sys_lib_dlsearch_path "$LT_SYS_LIBRARY_PATH"
+
+    func_dirname "$output" "/" ""
+    output_objdir=$func_dirname_result$objdir
+    func_to_tool_file "$output_objdir/"
+    tool_output_objdir=$func_to_tool_file_result
+    # Create the object directory.
+    func_mkdir_p "$output_objdir"
+
+    # Determine the type of output
+    case $output in
+    "")
+      func_fatal_help "you must specify an output file"
+      ;;
+    *.$libext) linkmode=oldlib ;;
+    *.lo | *.$objext) linkmode=obj ;;
+    *.la) linkmode=lib ;;
+    *) linkmode=prog ;; # Anything else should be a program.
+    esac
+
+    specialdeplibs=
+
+    libs=
+    # Find all interdependent deplibs by searching for libraries
+    # that are linked more than once (e.g. -la -lb -la)
+    for deplib in $deplibs; do
+      if $opt_preserve_dup_deps; then
+	case "$libs " in
+	*" $deplib "*) func_append specialdeplibs " $deplib" ;;
+	esac
+      fi
+      func_append libs " $deplib"
+    done
+
+    if test lib = "$linkmode"; then
+      libs="$predeps $libs $compiler_lib_search_path $postdeps"
+
+      # Compute libraries that are listed more than once in $predeps
+      # $postdeps and mark them as special (i.e., whose duplicates are
+      # not to be eliminated).
+      pre_post_deps=
+      if $opt_duplicate_compiler_generated_deps; then
+	for pre_post_dep in $predeps $postdeps; do
+	  case "$pre_post_deps " in
+	  *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;;
+	  esac
+	  func_append pre_post_deps " $pre_post_dep"
+	done
+      fi
+      pre_post_deps=
+    fi
+
+    deplibs=
+    newdependency_libs=
+    newlib_search_path=
+    need_relink=no # whether we're linking any uninstalled libtool libraries
+    notinst_deplibs= # not-installed libtool libraries
+    notinst_path= # paths that contain not-installed libtool libraries
+
+    case $linkmode in
+    lib)
+	passes="conv dlpreopen link"
+	for file in $dlfiles $dlprefiles; do
+	  case $file in
+	  *.la) ;;
+	  *)
+	    func_fatal_help "libraries can '-dlopen' only libtool libraries: $file"
+	    ;;
+	  esac
+	done
+	;;
+    prog)
+	compile_deplibs=
+	finalize_deplibs=
+	alldeplibs=false
+	newdlfiles=
+	newdlprefiles=
+	passes="conv scan dlopen dlpreopen link"
+	;;
+    *)  passes="conv"
+	;;
+    esac
+
+    for pass in $passes; do
+      # The preopen pass in lib mode reverses $deplibs; put it back here
+      # so that -L comes before libs that need it for instance...
+      if test lib,link = "$linkmode,$pass"; then
+	## FIXME: Find the place where the list is rebuilt in the wrong
+	##        order, and fix it there properly
+        tmp_deplibs=
+	for deplib in $deplibs; do
+	  tmp_deplibs="$deplib $tmp_deplibs"
+	done
+	deplibs=$tmp_deplibs
+      fi
+
+      if test lib,link = "$linkmode,$pass" ||
+	 test prog,scan = "$linkmode,$pass"; then
+	libs=$deplibs
+	deplibs=
+      fi
+      if test prog = "$linkmode"; then
+	case $pass in
+	dlopen) libs=$dlfiles ;;
+	dlpreopen) libs=$dlprefiles ;;
+	link) libs="$deplibs %DEPLIBS% $dependency_libs" ;;
+	esac
+      fi
+      if test lib,dlpreopen = "$linkmode,$pass"; then
+	# Collect and forward deplibs of preopened libtool libs
+	for lib in $dlprefiles; do
+	  # Ignore non-libtool-libs
+	  dependency_libs=
+	  func_resolve_sysroot "$lib"
+	  case $lib in
+	  *.la)	func_source "$func_resolve_sysroot_result" ;;
+	  esac
+
+	  # Collect preopened libtool deplibs, except any this library
+	  # has declared as weak libs
+	  for deplib in $dependency_libs; do
+	    func_basename "$deplib"
+            deplib_base=$func_basename_result
+	    case " $weak_libs " in
+	    *" $deplib_base "*) ;;
+	    *) func_append deplibs " $deplib" ;;
+	    esac
+	  done
+	done
+	libs=$dlprefiles
+      fi
+      if test dlopen = "$pass"; then
+	# Collect dlpreopened libraries
+	save_deplibs=$deplibs
+	deplibs=
+      fi
+
+      for deplib in $libs; do
+	lib=
+	found=false
+	case $deplib in
+	-mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \
+        |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*)
+	  if test prog,link = "$linkmode,$pass"; then
+	    compile_deplibs="$deplib $compile_deplibs"
+	    finalize_deplibs="$deplib $finalize_deplibs"
+	  else
+	    func_append compiler_flags " $deplib"
+	    if test lib = "$linkmode"; then
+		case "$new_inherited_linker_flags " in
+		    *" $deplib "*) ;;
+		    * ) func_append new_inherited_linker_flags " $deplib" ;;
+		esac
+	    fi
+	  fi
+	  continue
+	  ;;
+	-l*)
+	  if test lib != "$linkmode" && test prog != "$linkmode"; then
+	    func_warning "'-l' is ignored for archives/objects"
+	    continue
+	  fi
+	  func_stripname '-l' '' "$deplib"
+	  name=$func_stripname_result
+	  if test lib = "$linkmode"; then
+	    searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path"
+	  else
+	    searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path"
+	  fi
+	  for searchdir in $searchdirs; do
+	    for search_ext in .la $std_shrext .so .a; do
+	      # Search the libtool library
+	      lib=$searchdir/lib$name$search_ext
+	      if test -f "$lib"; then
+		if test .la = "$search_ext"; then
+		  found=:
+		else
+		  found=false
+		fi
+		break 2
+	      fi
+	    done
+	  done
+	  if $found; then
+	    # deplib is a libtool library
+	    # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib,
+	    # We need to do some special things here, and not later.
+	    if test yes = "$allow_libtool_libs_with_static_runtimes"; then
+	      case " $predeps $postdeps " in
+	      *" $deplib "*)
+		if func_lalib_p "$lib"; then
+		  library_names=
+		  old_library=
+		  func_source "$lib"
+		  for l in $old_library $library_names; do
+		    ll=$l
+		  done
+		  if test "X$ll" = "X$old_library"; then # only static version available
+		    found=false
+		    func_dirname "$lib" "" "."
+		    ladir=$func_dirname_result
+		    lib=$ladir/$old_library
+		    if test prog,link = "$linkmode,$pass"; then
+		      compile_deplibs="$deplib $compile_deplibs"
+		      finalize_deplibs="$deplib $finalize_deplibs"
+		    else
+		      deplibs="$deplib $deplibs"
+		      test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs"
+		    fi
+		    continue
+		  fi
+		fi
+		;;
+	      *) ;;
+	      esac
+	    fi
+	  else
+	    # deplib doesn't seem to be a libtool library
+	    if test prog,link = "$linkmode,$pass"; then
+	      compile_deplibs="$deplib $compile_deplibs"
+	      finalize_deplibs="$deplib $finalize_deplibs"
+	    else
+	      deplibs="$deplib $deplibs"
+	      test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs"
+	    fi
+	    continue
+	  fi
+	  ;; # -l
+	*.ltframework)
+	  if test prog,link = "$linkmode,$pass"; then
+	    compile_deplibs="$deplib $compile_deplibs"
+	    finalize_deplibs="$deplib $finalize_deplibs"
+	  else
+	    deplibs="$deplib $deplibs"
+	    if test lib = "$linkmode"; then
+		case "$new_inherited_linker_flags " in
+		    *" $deplib "*) ;;
+		    * ) func_append new_inherited_linker_flags " $deplib" ;;
+		esac
+	    fi
+	  fi
+	  continue
+	  ;;
+	-L*)
+	  case $linkmode in
+	  lib)
+	    deplibs="$deplib $deplibs"
+	    test conv = "$pass" && continue
+	    newdependency_libs="$deplib $newdependency_libs"
+	    func_stripname '-L' '' "$deplib"
+	    func_resolve_sysroot "$func_stripname_result"
+	    func_append newlib_search_path " $func_resolve_sysroot_result"
+	    ;;
+	  prog)
+	    if test conv = "$pass"; then
+	      deplibs="$deplib $deplibs"
+	      continue
+	    fi
+	    if test scan = "$pass"; then
+	      deplibs="$deplib $deplibs"
+	    else
+	      compile_deplibs="$deplib $compile_deplibs"
+	      finalize_deplibs="$deplib $finalize_deplibs"
+	    fi
+	    func_stripname '-L' '' "$deplib"
+	    func_resolve_sysroot "$func_stripname_result"
+	    func_append newlib_search_path " $func_resolve_sysroot_result"
+	    ;;
+	  *)
+	    func_warning "'-L' is ignored for archives/objects"
+	    ;;
+	  esac # linkmode
+	  continue
+	  ;; # -L
+	-R*)
+	  if test link = "$pass"; then
+	    func_stripname '-R' '' "$deplib"
+	    func_resolve_sysroot "$func_stripname_result"
+	    dir=$func_resolve_sysroot_result
+	    # Make sure the xrpath contains only unique directories.
+	    case "$xrpath " in
+	    *" $dir "*) ;;
+	    *) func_append xrpath " $dir" ;;
+	    esac
+	  fi
+	  deplibs="$deplib $deplibs"
+	  continue
+	  ;;
+	*.la)
+	  func_resolve_sysroot "$deplib"
+	  lib=$func_resolve_sysroot_result
+	  ;;
+	*.$libext)
+	  if test conv = "$pass"; then
+	    deplibs="$deplib $deplibs"
+	    continue
+	  fi
+	  case $linkmode in
+	  lib)
+	    # Linking convenience modules into shared libraries is allowed,
+	    # but linking other static libraries is non-portable.
+	    case " $dlpreconveniencelibs " in
+	    *" $deplib "*) ;;
+	    *)
+	      valid_a_lib=false
+	      case $deplibs_check_method in
+		match_pattern*)
+		  set dummy $deplibs_check_method; shift
+		  match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+		  if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \
+		    | $EGREP "$match_pattern_regex" > /dev/null; then
+		    valid_a_lib=:
+		  fi
+		;;
+		pass_all)
+		  valid_a_lib=:
+		;;
+	      esac
+	      if $valid_a_lib; then
+		echo
+		$ECHO "*** Warning: Linking the shared library $output against the"
+		$ECHO "*** static library $deplib is not portable!"
+		deplibs="$deplib $deplibs"
+	      else
+		echo
+		$ECHO "*** Warning: Trying to link with static lib archive $deplib."
+		echo "*** I have the capability to make that library automatically link in when"
+		echo "*** you link to this library.  But I can only do this if you have a"
+		echo "*** shared version of the library, which you do not appear to have"
+		echo "*** because the file extensions .$libext of this argument makes me believe"
+		echo "*** that it is just a static archive that I should not use here."
+	      fi
+	      ;;
+	    esac
+	    continue
+	    ;;
+	  prog)
+	    if test link != "$pass"; then
+	      deplibs="$deplib $deplibs"
+	    else
+	      compile_deplibs="$deplib $compile_deplibs"
+	      finalize_deplibs="$deplib $finalize_deplibs"
+	    fi
+	    continue
+	    ;;
+	  esac # linkmode
+	  ;; # *.$libext
+	*.lo | *.$objext)
+	  if test conv = "$pass"; then
+	    deplibs="$deplib $deplibs"
+	  elif test prog = "$linkmode"; then
+	    if test dlpreopen = "$pass" || test yes != "$dlopen_support" || test no = "$build_libtool_libs"; then
+	      # If there is no dlopen support or we're linking statically,
+	      # we need to preload.
+	      func_append newdlprefiles " $deplib"
+	      compile_deplibs="$deplib $compile_deplibs"
+	      finalize_deplibs="$deplib $finalize_deplibs"
+	    else
+	      func_append newdlfiles " $deplib"
+	    fi
+	  fi
+	  continue
+	  ;;
+	%DEPLIBS%)
+	  alldeplibs=:
+	  continue
+	  ;;
+	esac # case $deplib
+
+	$found || test -f "$lib" \
+	  || func_fatal_error "cannot find the library '$lib' or unhandled argument '$deplib'"
+
+	# Check to see that this really is a libtool archive.
+	func_lalib_unsafe_p "$lib" \
+	  || func_fatal_error "'$lib' is not a valid libtool archive"
+
+	func_dirname "$lib" "" "."
+	ladir=$func_dirname_result
+
+	dlname=
+	dlopen=
+	dlpreopen=
+	libdir=
+	library_names=
+	old_library=
+	inherited_linker_flags=
+	# If the library was installed with an old release of libtool,
+	# it will not redefine variables installed, or shouldnotlink
+	installed=yes
+	shouldnotlink=no
+	avoidtemprpath=
+
+
+	# Read the .la file
+	func_source "$lib"
+
+	# Convert "-framework foo" to "foo.ltframework"
+	if test -n "$inherited_linker_flags"; then
+	  tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'`
+	  for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do
+	    case " $new_inherited_linker_flags " in
+	      *" $tmp_inherited_linker_flag "*) ;;
+	      *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";;
+	    esac
+	  done
+	fi
+	dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	if test lib,link = "$linkmode,$pass" ||
+	   test prog,scan = "$linkmode,$pass" ||
+	   { test prog != "$linkmode" && test lib != "$linkmode"; }; then
+	  test -n "$dlopen" && func_append dlfiles " $dlopen"
+	  test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen"
+	fi
+
+	if test conv = "$pass"; then
+	  # Only check for convenience libraries
+	  deplibs="$lib $deplibs"
+	  if test -z "$libdir"; then
+	    if test -z "$old_library"; then
+	      func_fatal_error "cannot find name of link library for '$lib'"
+	    fi
+	    # It is a libtool convenience library, so add in its objects.
+	    func_append convenience " $ladir/$objdir/$old_library"
+	    func_append old_convenience " $ladir/$objdir/$old_library"
+	  elif test prog != "$linkmode" && test lib != "$linkmode"; then
+	    func_fatal_error "'$lib' is not a convenience library"
+	  fi
+	  tmp_libs=
+	  for deplib in $dependency_libs; do
+	    deplibs="$deplib $deplibs"
+	    if $opt_preserve_dup_deps; then
+	      case "$tmp_libs " in
+	      *" $deplib "*) func_append specialdeplibs " $deplib" ;;
+	      esac
+	    fi
+	    func_append tmp_libs " $deplib"
+	  done
+	  continue
+	fi # $pass = conv
+
+
+	# Get the name of the library we link against.
+	linklib=
+	if test -n "$old_library" &&
+	   { test yes = "$prefer_static_libs" ||
+	     test built,no = "$prefer_static_libs,$installed"; }; then
+	  linklib=$old_library
+	else
+	  for l in $old_library $library_names; do
+	    linklib=$l
+	  done
+	fi
+	if test -z "$linklib"; then
+	  func_fatal_error "cannot find name of link library for '$lib'"
+	fi
+
+	# This library was specified with -dlopen.
+	if test dlopen = "$pass"; then
+	  test -z "$libdir" \
+	    && func_fatal_error "cannot -dlopen a convenience library: '$lib'"
+	  if test -z "$dlname" ||
+	     test yes != "$dlopen_support" ||
+	     test no = "$build_libtool_libs"
+	  then
+	    # If there is no dlname, no dlopen support or we're linking
+	    # statically, we need to preload.  We also need to preload any
+	    # dependent libraries so libltdl's deplib preloader doesn't
+	    # bomb out in the load deplibs phase.
+	    func_append dlprefiles " $lib $dependency_libs"
+	  else
+	    func_append newdlfiles " $lib"
+	  fi
+	  continue
+	fi # $pass = dlopen
+
+	# We need an absolute path.
+	case $ladir in
+	[\\/]* | [A-Za-z]:[\\/]*) abs_ladir=$ladir ;;
+	*)
+	  abs_ladir=`cd "$ladir" && pwd`
+	  if test -z "$abs_ladir"; then
+	    func_warning "cannot determine absolute directory name of '$ladir'"
+	    func_warning "passing it literally to the linker, although it might fail"
+	    abs_ladir=$ladir
+	  fi
+	  ;;
+	esac
+	func_basename "$lib"
+	laname=$func_basename_result
+
+	# Find the relevant object directory and library name.
+	if test yes = "$installed"; then
+	  if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+	    func_warning "library '$lib' was moved."
+	    dir=$ladir
+	    absdir=$abs_ladir
+	    libdir=$abs_ladir
+	  else
+	    dir=$lt_sysroot$libdir
+	    absdir=$lt_sysroot$libdir
+	  fi
+	  test yes = "$hardcode_automatic" && avoidtemprpath=yes
+	else
+	  if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+	    dir=$ladir
+	    absdir=$abs_ladir
+	    # Remove this search path later
+	    func_append notinst_path " $abs_ladir"
+	  else
+	    dir=$ladir/$objdir
+	    absdir=$abs_ladir/$objdir
+	    # Remove this search path later
+	    func_append notinst_path " $abs_ladir"
+	  fi
+	fi # $installed = yes
+	func_stripname 'lib' '.la' "$laname"
+	name=$func_stripname_result
+
+	# This library was specified with -dlpreopen.
+	if test dlpreopen = "$pass"; then
+	  if test -z "$libdir" && test prog = "$linkmode"; then
+	    func_fatal_error "only libraries may -dlpreopen a convenience library: '$lib'"
+	  fi
+	  case $host in
+	    # special handling for platforms with PE-DLLs.
+	    *cygwin* | *mingw* | *cegcc* )
+	      # Linker will automatically link against shared library if both
+	      # static and shared are present.  Therefore, ensure we extract
+	      # symbols from the import library if a shared library is present
+	      # (otherwise, the dlopen module name will be incorrect).  We do
+	      # this by putting the import library name into $newdlprefiles.
+	      # We recover the dlopen module name by 'saving' the la file
+	      # name in a special purpose variable, and (later) extracting the
+	      # dlname from the la file.
+	      if test -n "$dlname"; then
+	        func_tr_sh "$dir/$linklib"
+	        eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname"
+	        func_append newdlprefiles " $dir/$linklib"
+	      else
+	        func_append newdlprefiles " $dir/$old_library"
+	        # Keep a list of preopened convenience libraries to check
+	        # that they are being used correctly in the link pass.
+	        test -z "$libdir" && \
+	          func_append dlpreconveniencelibs " $dir/$old_library"
+	      fi
+	    ;;
+	    * )
+	      # Prefer using a static library (so that no silly _DYNAMIC symbols
+	      # are required to link).
+	      if test -n "$old_library"; then
+	        func_append newdlprefiles " $dir/$old_library"
+	        # Keep a list of preopened convenience libraries to check
+	        # that they are being used correctly in the link pass.
+	        test -z "$libdir" && \
+	          func_append dlpreconveniencelibs " $dir/$old_library"
+	      # Otherwise, use the dlname, so that lt_dlopen finds it.
+	      elif test -n "$dlname"; then
+	        func_append newdlprefiles " $dir/$dlname"
+	      else
+	        func_append newdlprefiles " $dir/$linklib"
+	      fi
+	    ;;
+	  esac
+	fi # $pass = dlpreopen
+
+	if test -z "$libdir"; then
+	  # Link the convenience library
+	  if test lib = "$linkmode"; then
+	    deplibs="$dir/$old_library $deplibs"
+	  elif test prog,link = "$linkmode,$pass"; then
+	    compile_deplibs="$dir/$old_library $compile_deplibs"
+	    finalize_deplibs="$dir/$old_library $finalize_deplibs"
+	  else
+	    deplibs="$lib $deplibs" # used for prog,scan pass
+	  fi
+	  continue
+	fi
+
+
+	if test prog = "$linkmode" && test link != "$pass"; then
+	  func_append newlib_search_path " $ladir"
+	  deplibs="$lib $deplibs"
+
+	  linkalldeplibs=false
+	  if test no != "$link_all_deplibs" || test -z "$library_names" ||
+	     test no = "$build_libtool_libs"; then
+	    linkalldeplibs=:
+	  fi
+
+	  tmp_libs=
+	  for deplib in $dependency_libs; do
+	    case $deplib in
+	    -L*) func_stripname '-L' '' "$deplib"
+	         func_resolve_sysroot "$func_stripname_result"
+	         func_append newlib_search_path " $func_resolve_sysroot_result"
+		 ;;
+	    esac
+	    # Need to link against all dependency_libs?
+	    if $linkalldeplibs; then
+	      deplibs="$deplib $deplibs"
+	    else
+	      # Need to hardcode shared library paths
+	      # or/and link against static libraries
+	      newdependency_libs="$deplib $newdependency_libs"
+	    fi
+	    if $opt_preserve_dup_deps; then
+	      case "$tmp_libs " in
+	      *" $deplib "*) func_append specialdeplibs " $deplib" ;;
+	      esac
+	    fi
+	    func_append tmp_libs " $deplib"
+	  done # for deplib
+	  continue
+	fi # $linkmode = prog...
+
+	if test prog,link = "$linkmode,$pass"; then
+	  if test -n "$library_names" &&
+	     { { test no = "$prefer_static_libs" ||
+	         test built,yes = "$prefer_static_libs,$installed"; } ||
+	       test -z "$old_library"; }; then
+	    # We need to hardcode the library path
+	    if test -n "$shlibpath_var" && test -z "$avoidtemprpath"; then
+	      # Make sure the rpath contains only unique directories.
+	      case $temp_rpath: in
+	      *"$absdir:"*) ;;
+	      *) func_append temp_rpath "$absdir:" ;;
+	      esac
+	    fi
+
+	    # Hardcode the library path.
+	    # Skip directories that are in the system default run-time
+	    # search path.
+	    case " $sys_lib_dlsearch_path " in
+	    *" $absdir "*) ;;
+	    *)
+	      case "$compile_rpath " in
+	      *" $absdir "*) ;;
+	      *) func_append compile_rpath " $absdir" ;;
+	      esac
+	      ;;
+	    esac
+	    case " $sys_lib_dlsearch_path " in
+	    *" $libdir "*) ;;
+	    *)
+	      case "$finalize_rpath " in
+	      *" $libdir "*) ;;
+	      *) func_append finalize_rpath " $libdir" ;;
+	      esac
+	      ;;
+	    esac
+	  fi # $linkmode,$pass = prog,link...
+
+	  if $alldeplibs &&
+	     { test pass_all = "$deplibs_check_method" ||
+	       { test yes = "$build_libtool_libs" &&
+		 test -n "$library_names"; }; }; then
+	    # We only need to search for static libraries
+	    continue
+	  fi
+	fi
+
+	link_static=no # Whether the deplib will be linked statically
+	use_static_libs=$prefer_static_libs
+	if test built = "$use_static_libs" && test yes = "$installed"; then
+	  use_static_libs=no
+	fi
+	if test -n "$library_names" &&
+	   { test no = "$use_static_libs" || test -z "$old_library"; }; then
+	  case $host in
+	  *cygwin* | *mingw* | *cegcc* | *os2*)
+	      # No point in relinking DLLs because paths are not encoded
+	      func_append notinst_deplibs " $lib"
+	      need_relink=no
+	    ;;
+	  *)
+	    if test no = "$installed"; then
+	      func_append notinst_deplibs " $lib"
+	      need_relink=yes
+	    fi
+	    ;;
+	  esac
+	  # This is a shared library
+
+	  # Warn about portability, can't link against -module's on some
+	  # systems (darwin).  Don't bleat about dlopened modules though!
+	  dlopenmodule=
+	  for dlpremoduletest in $dlprefiles; do
+	    if test "X$dlpremoduletest" = "X$lib"; then
+	      dlopenmodule=$dlpremoduletest
+	      break
+	    fi
+	  done
+	  if test -z "$dlopenmodule" && test yes = "$shouldnotlink" && test link = "$pass"; then
+	    echo
+	    if test prog = "$linkmode"; then
+	      $ECHO "*** Warning: Linking the executable $output against the loadable module"
+	    else
+	      $ECHO "*** Warning: Linking the shared library $output against the loadable module"
+	    fi
+	    $ECHO "*** $linklib is not portable!"
+	  fi
+	  if test lib = "$linkmode" &&
+	     test yes = "$hardcode_into_libs"; then
+	    # Hardcode the library path.
+	    # Skip directories that are in the system default run-time
+	    # search path.
+	    case " $sys_lib_dlsearch_path " in
+	    *" $absdir "*) ;;
+	    *)
+	      case "$compile_rpath " in
+	      *" $absdir "*) ;;
+	      *) func_append compile_rpath " $absdir" ;;
+	      esac
+	      ;;
+	    esac
+	    case " $sys_lib_dlsearch_path " in
+	    *" $libdir "*) ;;
+	    *)
+	      case "$finalize_rpath " in
+	      *" $libdir "*) ;;
+	      *) func_append finalize_rpath " $libdir" ;;
+	      esac
+	      ;;
+	    esac
+	  fi
+
+	  if test -n "$old_archive_from_expsyms_cmds"; then
+	    # figure out the soname
+	    set dummy $library_names
+	    shift
+	    realname=$1
+	    shift
+	    libname=`eval "\\$ECHO \"$libname_spec\""`
+	    # use dlname if we got it. it's perfectly good, no?
+	    if test -n "$dlname"; then
+	      soname=$dlname
+	    elif test -n "$soname_spec"; then
+	      # bleh windows
+	      case $host in
+	      *cygwin* | mingw* | *cegcc* | *os2*)
+	        func_arith $current - $age
+		major=$func_arith_result
+		versuffix=-$major
+		;;
+	      esac
+	      eval soname=\"$soname_spec\"
+	    else
+	      soname=$realname
+	    fi
+
+	    # Make a new name for the extract_expsyms_cmds to use
+	    soroot=$soname
+	    func_basename "$soroot"
+	    soname=$func_basename_result
+	    func_stripname 'lib' '.dll' "$soname"
+	    newlib=libimp-$func_stripname_result.a
+
+	    # If the library has no export list, then create one now
+	    if test -f "$output_objdir/$soname-def"; then :
+	    else
+	      func_verbose "extracting exported symbol list from '$soname'"
+	      func_execute_cmds "$extract_expsyms_cmds" 'exit $?'
+	    fi
+
+	    # Create $newlib
+	    if test -f "$output_objdir/$newlib"; then :; else
+	      func_verbose "generating import library for '$soname'"
+	      func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?'
+	    fi
+	    # make sure the library variables are pointing to the new library
+	    dir=$output_objdir
+	    linklib=$newlib
+	  fi # test -n "$old_archive_from_expsyms_cmds"
+
+	  if test prog = "$linkmode" || test relink != "$opt_mode"; then
+	    add_shlibpath=
+	    add_dir=
+	    add=
+	    lib_linked=yes
+	    case $hardcode_action in
+	    immediate | unsupported)
+	      if test no = "$hardcode_direct"; then
+		add=$dir/$linklib
+		case $host in
+		  *-*-sco3.2v5.0.[024]*) add_dir=-L$dir ;;
+		  *-*-sysv4*uw2*) add_dir=-L$dir ;;
+		  *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \
+		    *-*-unixware7*) add_dir=-L$dir ;;
+		  *-*-darwin* )
+		    # if the lib is a (non-dlopened) module then we cannot
+		    # link against it, someone is ignoring the earlier warnings
+		    if /usr/bin/file -L $add 2> /dev/null |
+			 $GREP ": [^:]* bundle" >/dev/null; then
+		      if test "X$dlopenmodule" != "X$lib"; then
+			$ECHO "*** Warning: lib $linklib is a module, not a shared library"
+			if test -z "$old_library"; then
+			  echo
+			  echo "*** And there doesn't seem to be a static archive available"
+			  echo "*** The link will probably fail, sorry"
+			else
+			  add=$dir/$old_library
+			fi
+		      elif test -n "$old_library"; then
+			add=$dir/$old_library
+		      fi
+		    fi
+		esac
+	      elif test no = "$hardcode_minus_L"; then
+		case $host in
+		*-*-sunos*) add_shlibpath=$dir ;;
+		esac
+		add_dir=-L$dir
+		add=-l$name
+	      elif test no = "$hardcode_shlibpath_var"; then
+		add_shlibpath=$dir
+		add=-l$name
+	      else
+		lib_linked=no
+	      fi
+	      ;;
+	    relink)
+	      if test yes = "$hardcode_direct" &&
+	         test no = "$hardcode_direct_absolute"; then
+		add=$dir/$linklib
+	      elif test yes = "$hardcode_minus_L"; then
+		add_dir=-L$absdir
+		# Try looking first in the location we're being installed to.
+		if test -n "$inst_prefix_dir"; then
+		  case $libdir in
+		    [\\/]*)
+		      func_append add_dir " -L$inst_prefix_dir$libdir"
+		      ;;
+		  esac
+		fi
+		add=-l$name
+	      elif test yes = "$hardcode_shlibpath_var"; then
+		add_shlibpath=$dir
+		add=-l$name
+	      else
+		lib_linked=no
+	      fi
+	      ;;
+	    *) lib_linked=no ;;
+	    esac
+
+	    if test yes != "$lib_linked"; then
+	      func_fatal_configuration "unsupported hardcode properties"
+	    fi
+
+	    if test -n "$add_shlibpath"; then
+	      case :$compile_shlibpath: in
+	      *":$add_shlibpath:"*) ;;
+	      *) func_append compile_shlibpath "$add_shlibpath:" ;;
+	      esac
+	    fi
+	    if test prog = "$linkmode"; then
+	      test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs"
+	      test -n "$add" && compile_deplibs="$add $compile_deplibs"
+	    else
+	      test -n "$add_dir" && deplibs="$add_dir $deplibs"
+	      test -n "$add" && deplibs="$add $deplibs"
+	      if test yes != "$hardcode_direct" &&
+		 test yes != "$hardcode_minus_L" &&
+		 test yes = "$hardcode_shlibpath_var"; then
+		case :$finalize_shlibpath: in
+		*":$libdir:"*) ;;
+		*) func_append finalize_shlibpath "$libdir:" ;;
+		esac
+	      fi
+	    fi
+	  fi
+
+	  if test prog = "$linkmode" || test relink = "$opt_mode"; then
+	    add_shlibpath=
+	    add_dir=
+	    add=
+	    # Finalize command for both is simple: just hardcode it.
+	    if test yes = "$hardcode_direct" &&
+	       test no = "$hardcode_direct_absolute"; then
+	      add=$libdir/$linklib
+	    elif test yes = "$hardcode_minus_L"; then
+	      add_dir=-L$libdir
+	      add=-l$name
+	    elif test yes = "$hardcode_shlibpath_var"; then
+	      case :$finalize_shlibpath: in
+	      *":$libdir:"*) ;;
+	      *) func_append finalize_shlibpath "$libdir:" ;;
+	      esac
+	      add=-l$name
+	    elif test yes = "$hardcode_automatic"; then
+	      if test -n "$inst_prefix_dir" &&
+		 test -f "$inst_prefix_dir$libdir/$linklib"; then
+		add=$inst_prefix_dir$libdir/$linklib
+	      else
+		add=$libdir/$linklib
+	      fi
+	    else
+	      # We cannot seem to hardcode it, guess we'll fake it.
+	      add_dir=-L$libdir
+	      # Try looking first in the location we're being installed to.
+	      if test -n "$inst_prefix_dir"; then
+		case $libdir in
+		  [\\/]*)
+		    func_append add_dir " -L$inst_prefix_dir$libdir"
+		    ;;
+		esac
+	      fi
+	      add=-l$name
+	    fi
+
+	    if test prog = "$linkmode"; then
+	      test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs"
+	      test -n "$add" && finalize_deplibs="$add $finalize_deplibs"
+	    else
+	      test -n "$add_dir" && deplibs="$add_dir $deplibs"
+	      test -n "$add" && deplibs="$add $deplibs"
+	    fi
+	  fi
+	elif test prog = "$linkmode"; then
+	  # Here we assume that one of hardcode_direct or hardcode_minus_L
+	  # is not unsupported.  This is valid on all known static and
+	  # shared platforms.
+	  if test unsupported != "$hardcode_direct"; then
+	    test -n "$old_library" && linklib=$old_library
+	    compile_deplibs="$dir/$linklib $compile_deplibs"
+	    finalize_deplibs="$dir/$linklib $finalize_deplibs"
+	  else
+	    compile_deplibs="-l$name -L$dir $compile_deplibs"
+	    finalize_deplibs="-l$name -L$dir $finalize_deplibs"
+	  fi
+	elif test yes = "$build_libtool_libs"; then
+	  # Not a shared library
+	  if test pass_all != "$deplibs_check_method"; then
+	    # We're trying link a shared library against a static one
+	    # but the system doesn't support it.
+
+	    # Just print a warning and add the library to dependency_libs so
+	    # that the program can be linked against the static library.
+	    echo
+	    $ECHO "*** Warning: This system cannot link to static lib archive $lib."
+	    echo "*** I have the capability to make that library automatically link in when"
+	    echo "*** you link to this library.  But I can only do this if you have a"
+	    echo "*** shared version of the library, which you do not appear to have."
+	    if test yes = "$module"; then
+	      echo "*** But as you try to build a module library, libtool will still create "
+	      echo "*** a static module, that should work as long as the dlopening application"
+	      echo "*** is linked with the -dlopen flag to resolve symbols at runtime."
+	      if test -z "$global_symbol_pipe"; then
+		echo
+		echo "*** However, this would only work if libtool was able to extract symbol"
+		echo "*** lists from a program, using 'nm' or equivalent, but libtool could"
+		echo "*** not find such a program.  So, this module is probably useless."
+		echo "*** 'nm' from GNU binutils and a full rebuild may help."
+	      fi
+	      if test no = "$build_old_libs"; then
+		build_libtool_libs=module
+		build_old_libs=yes
+	      else
+		build_libtool_libs=no
+	      fi
+	    fi
+	  else
+	    deplibs="$dir/$old_library $deplibs"
+	    link_static=yes
+	  fi
+	fi # link shared/static library?
+
+	if test lib = "$linkmode"; then
+	  if test -n "$dependency_libs" &&
+	     { test yes != "$hardcode_into_libs" ||
+	       test yes = "$build_old_libs" ||
+	       test yes = "$link_static"; }; then
+	    # Extract -R from dependency_libs
+	    temp_deplibs=
+	    for libdir in $dependency_libs; do
+	      case $libdir in
+	      -R*) func_stripname '-R' '' "$libdir"
+	           temp_xrpath=$func_stripname_result
+		   case " $xrpath " in
+		   *" $temp_xrpath "*) ;;
+		   *) func_append xrpath " $temp_xrpath";;
+		   esac;;
+	      *) func_append temp_deplibs " $libdir";;
+	      esac
+	    done
+	    dependency_libs=$temp_deplibs
+	  fi
+
+	  func_append newlib_search_path " $absdir"
+	  # Link against this library
+	  test no = "$link_static" && newdependency_libs="$abs_ladir/$laname $newdependency_libs"
+	  # ... and its dependency_libs
+	  tmp_libs=
+	  for deplib in $dependency_libs; do
+	    newdependency_libs="$deplib $newdependency_libs"
+	    case $deplib in
+              -L*) func_stripname '-L' '' "$deplib"
+                   func_resolve_sysroot "$func_stripname_result";;
+              *) func_resolve_sysroot "$deplib" ;;
+            esac
+	    if $opt_preserve_dup_deps; then
+	      case "$tmp_libs " in
+	      *" $func_resolve_sysroot_result "*)
+                func_append specialdeplibs " $func_resolve_sysroot_result" ;;
+	      esac
+	    fi
+	    func_append tmp_libs " $func_resolve_sysroot_result"
+	  done
+
+	  if test no != "$link_all_deplibs"; then
+	    # Add the search paths of all dependency libraries
+	    for deplib in $dependency_libs; do
+	      path=
+	      case $deplib in
+	      -L*) path=$deplib ;;
+	      *.la)
+	        func_resolve_sysroot "$deplib"
+	        deplib=$func_resolve_sysroot_result
+	        func_dirname "$deplib" "" "."
+		dir=$func_dirname_result
+		# We need an absolute path.
+		case $dir in
+		[\\/]* | [A-Za-z]:[\\/]*) absdir=$dir ;;
+		*)
+		  absdir=`cd "$dir" && pwd`
+		  if test -z "$absdir"; then
+		    func_warning "cannot determine absolute directory name of '$dir'"
+		    absdir=$dir
+		  fi
+		  ;;
+		esac
+		if $GREP "^installed=no" $deplib > /dev/null; then
+		case $host in
+		*-*-darwin*)
+		  depdepl=
+		  eval deplibrary_names=`$SED -n -e 's/^library_names=\(.*\)$/\1/p' $deplib`
+		  if test -n "$deplibrary_names"; then
+		    for tmp in $deplibrary_names; do
+		      depdepl=$tmp
+		    done
+		    if test -f "$absdir/$objdir/$depdepl"; then
+		      depdepl=$absdir/$objdir/$depdepl
+		      darwin_install_name=`$OTOOL -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'`
+                      if test -z "$darwin_install_name"; then
+                          darwin_install_name=`$OTOOL64 -L $depdepl  | awk '{if (NR == 2) {print $1;exit}}'`
+                      fi
+		      func_append compiler_flags " $wl-dylib_file $wl$darwin_install_name:$depdepl"
+		      func_append linker_flags " -dylib_file $darwin_install_name:$depdepl"
+		      path=
+		    fi
+		  fi
+		  ;;
+		*)
+		  path=-L$absdir/$objdir
+		  ;;
+		esac
+		else
+		  eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
+		  test -z "$libdir" && \
+		    func_fatal_error "'$deplib' is not a valid libtool archive"
+		  test "$absdir" != "$libdir" && \
+		    func_warning "'$deplib' seems to be moved"
+
+		  path=-L$absdir
+		fi
+		;;
+	      esac
+	      case " $deplibs " in
+	      *" $path "*) ;;
+	      *) deplibs="$path $deplibs" ;;
+	      esac
+	    done
+	  fi # link_all_deplibs != no
+	fi # linkmode = lib
+      done # for deplib in $libs
+      if test link = "$pass"; then
+	if test prog = "$linkmode"; then
+	  compile_deplibs="$new_inherited_linker_flags $compile_deplibs"
+	  finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs"
+	else
+	  compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	fi
+      fi
+      dependency_libs=$newdependency_libs
+      if test dlpreopen = "$pass"; then
+	# Link the dlpreopened libraries before other libraries
+	for deplib in $save_deplibs; do
+	  deplibs="$deplib $deplibs"
+	done
+      fi
+      if test dlopen != "$pass"; then
+	test conv = "$pass" || {
+	  # Make sure lib_search_path contains only unique directories.
+	  lib_search_path=
+	  for dir in $newlib_search_path; do
+	    case "$lib_search_path " in
+	    *" $dir "*) ;;
+	    *) func_append lib_search_path " $dir" ;;
+	    esac
+	  done
+	  newlib_search_path=
+	}
+
+	if test prog,link = "$linkmode,$pass"; then
+	  vars="compile_deplibs finalize_deplibs"
+	else
+	  vars=deplibs
+	fi
+	for var in $vars dependency_libs; do
+	  # Add libraries to $var in reverse order
+	  eval tmp_libs=\"\$$var\"
+	  new_libs=
+	  for deplib in $tmp_libs; do
+	    # FIXME: Pedantically, this is the right thing to do, so
+	    #        that some nasty dependency loop isn't accidentally
+	    #        broken:
+	    #new_libs="$deplib $new_libs"
+	    # Pragmatically, this seems to cause very few problems in
+	    # practice:
+	    case $deplib in
+	    -L*) new_libs="$deplib $new_libs" ;;
+	    -R*) ;;
+	    *)
+	      # And here is the reason: when a library appears more
+	      # than once as an explicit dependence of a library, or
+	      # is implicitly linked in more than once by the
+	      # compiler, it is considered special, and multiple
+	      # occurrences thereof are not removed.  Compare this
+	      # with having the same library being listed as a
+	      # dependency of multiple other libraries: in this case,
+	      # we know (pedantically, we assume) the library does not
+	      # need to be listed more than once, so we keep only the
+	      # last copy.  This is not always right, but it is rare
+	      # enough that we require users that really mean to play
+	      # such unportable linking tricks to link the library
+	      # using -Wl,-lname, so that libtool does not consider it
+	      # for duplicate removal.
+	      case " $specialdeplibs " in
+	      *" $deplib "*) new_libs="$deplib $new_libs" ;;
+	      *)
+		case " $new_libs " in
+		*" $deplib "*) ;;
+		*) new_libs="$deplib $new_libs" ;;
+		esac
+		;;
+	      esac
+	      ;;
+	    esac
+	  done
+	  tmp_libs=
+	  for deplib in $new_libs; do
+	    case $deplib in
+	    -L*)
+	      case " $tmp_libs " in
+	      *" $deplib "*) ;;
+	      *) func_append tmp_libs " $deplib" ;;
+	      esac
+	      ;;
+	    *) func_append tmp_libs " $deplib" ;;
+	    esac
+	  done
+	  eval $var=\"$tmp_libs\"
+	done # for var
+      fi
+
+      # Add Sun CC postdeps if required:
+      test CXX = "$tagname" && {
+        case $host_os in
+        linux*)
+          case `$CC -V 2>&1 | sed 5q` in
+          *Sun\ C*) # Sun C++ 5.9
+            func_suncc_cstd_abi
+
+            if test no != "$suncc_use_cstd_abi"; then
+              func_append postdeps ' -library=Cstd -library=Crun'
+            fi
+            ;;
+          esac
+          ;;
+
+        solaris*)
+          func_cc_basename "$CC"
+          case $func_cc_basename_result in
+          CC* | sunCC*)
+            func_suncc_cstd_abi
+
+            if test no != "$suncc_use_cstd_abi"; then
+              func_append postdeps ' -library=Cstd -library=Crun'
+            fi
+            ;;
+          esac
+          ;;
+        esac
+      }
+
+      # Last step: remove runtime libs from dependency_libs
+      # (they stay in deplibs)
+      tmp_libs=
+      for i in $dependency_libs; do
+	case " $predeps $postdeps $compiler_lib_search_path " in
+	*" $i "*)
+	  i=
+	  ;;
+	esac
+	if test -n "$i"; then
+	  func_append tmp_libs " $i"
+	fi
+      done
+      dependency_libs=$tmp_libs
+    done # for pass
+    if test prog = "$linkmode"; then
+      dlfiles=$newdlfiles
+    fi
+    if test prog = "$linkmode" || test lib = "$linkmode"; then
+      dlprefiles=$newdlprefiles
+    fi
+
+    case $linkmode in
+    oldlib)
+      if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then
+	func_warning "'-dlopen' is ignored for archives"
+      fi
+
+      case " $deplibs" in
+      *\ -l* | *\ -L*)
+	func_warning "'-l' and '-L' are ignored for archives" ;;
+      esac
+
+      test -n "$rpath" && \
+	func_warning "'-rpath' is ignored for archives"
+
+      test -n "$xrpath" && \
+	func_warning "'-R' is ignored for archives"
+
+      test -n "$vinfo" && \
+	func_warning "'-version-info/-version-number' is ignored for archives"
+
+      test -n "$release" && \
+	func_warning "'-release' is ignored for archives"
+
+      test -n "$export_symbols$export_symbols_regex" && \
+	func_warning "'-export-symbols' is ignored for archives"
+
+      # Now set the variables for building old libraries.
+      build_libtool_libs=no
+      oldlibs=$output
+      func_append objs "$old_deplibs"
+      ;;
+
+    lib)
+      # Make sure we only generate libraries of the form 'libNAME.la'.
+      case $outputname in
+      lib*)
+	func_stripname 'lib' '.la' "$outputname"
+	name=$func_stripname_result
+	eval shared_ext=\"$shrext_cmds\"
+	eval libname=\"$libname_spec\"
+	;;
+      *)
+	test no = "$module" \
+	  && func_fatal_help "libtool library '$output' must begin with 'lib'"
+
+	if test no != "$need_lib_prefix"; then
+	  # Add the "lib" prefix for modules if required
+	  func_stripname '' '.la' "$outputname"
+	  name=$func_stripname_result
+	  eval shared_ext=\"$shrext_cmds\"
+	  eval libname=\"$libname_spec\"
+	else
+	  func_stripname '' '.la' "$outputname"
+	  libname=$func_stripname_result
+	fi
+	;;
+      esac
+
+      if test -n "$objs"; then
+	if test pass_all != "$deplibs_check_method"; then
+	  func_fatal_error "cannot build libtool library '$output' from non-libtool objects on this host:$objs"
+	else
+	  echo
+	  $ECHO "*** Warning: Linking the shared library $output against the non-libtool"
+	  $ECHO "*** objects $objs is not portable!"
+	  func_append libobjs " $objs"
+	fi
+      fi
+
+      test no = "$dlself" \
+	|| func_warning "'-dlopen self' is ignored for libtool libraries"
+
+      set dummy $rpath
+      shift
+      test 1 -lt "$#" \
+	&& func_warning "ignoring multiple '-rpath's for a libtool library"
+
+      install_libdir=$1
+
+      oldlibs=
+      if test -z "$rpath"; then
+	if test yes = "$build_libtool_libs"; then
+	  # Building a libtool convenience library.
+	  # Some compilers have problems with a '.al' extension so
+	  # convenience libraries should have the same extension an
+	  # archive normally would.
+	  oldlibs="$output_objdir/$libname.$libext $oldlibs"
+	  build_libtool_libs=convenience
+	  build_old_libs=yes
+	fi
+
+	test -n "$vinfo" && \
+	  func_warning "'-version-info/-version-number' is ignored for convenience libraries"
+
+	test -n "$release" && \
+	  func_warning "'-release' is ignored for convenience libraries"
+      else
+
+	# Parse the version information argument.
+	save_ifs=$IFS; IFS=:
+	set dummy $vinfo 0 0 0
+	shift
+	IFS=$save_ifs
+
+	test -n "$7" && \
+	  func_fatal_help "too many parameters to '-version-info'"
+
+	# convert absolute version numbers to libtool ages
+	# this retains compatibility with .la files and attempts
+	# to make the code below a bit more comprehensible
+
+	case $vinfo_number in
+	yes)
+	  number_major=$1
+	  number_minor=$2
+	  number_revision=$3
+	  #
+	  # There are really only two kinds -- those that
+	  # use the current revision as the major version
+	  # and those that subtract age and use age as
+	  # a minor version.  But, then there is irix
+	  # that has an extra 1 added just for fun
+	  #
+	  case $version_type in
+	  # correct linux to gnu/linux during the next big refactor
+	  darwin|freebsd-elf|linux|osf|windows|none)
+	    func_arith $number_major + $number_minor
+	    current=$func_arith_result
+	    age=$number_minor
+	    revision=$number_revision
+	    ;;
+	  freebsd-aout|qnx|sunos)
+	    current=$number_major
+	    revision=$number_minor
+	    age=0
+	    ;;
+	  irix|nonstopux)
+	    func_arith $number_major + $number_minor
+	    current=$func_arith_result
+	    age=$number_minor
+	    revision=$number_minor
+	    lt_irix_increment=no
+	    ;;
+	  esac
+	  ;;
+	no)
+	  current=$1
+	  revision=$2
+	  age=$3
+	  ;;
+	esac
+
+	# Check that each of the things are valid numbers.
+	case $current in
+	0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+	*)
+	  func_error "CURRENT '$current' must be a nonnegative integer"
+	  func_fatal_error "'$vinfo' is not valid version information"
+	  ;;
+	esac
+
+	case $revision in
+	0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+	*)
+	  func_error "REVISION '$revision' must be a nonnegative integer"
+	  func_fatal_error "'$vinfo' is not valid version information"
+	  ;;
+	esac
+
+	case $age in
+	0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+	*)
+	  func_error "AGE '$age' must be a nonnegative integer"
+	  func_fatal_error "'$vinfo' is not valid version information"
+	  ;;
+	esac
+
+	if test "$age" -gt "$current"; then
+	  func_error "AGE '$age' is greater than the current interface number '$current'"
+	  func_fatal_error "'$vinfo' is not valid version information"
+	fi
+
+	# Calculate the version variables.
+	major=
+	versuffix=
+	verstring=
+	case $version_type in
+	none) ;;
+
+	darwin)
+	  # Like Linux, but with the current version available in
+	  # verstring for coding it into the library header
+	  func_arith $current - $age
+	  major=.$func_arith_result
+	  versuffix=$major.$age.$revision
+	  # Darwin ld doesn't like 0 for these options...
+	  func_arith $current + 1
+	  minor_current=$func_arith_result
+	  xlcverstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision"
+	  verstring="-compatibility_version $minor_current -current_version $minor_current.$revision"
+          # On Darwin other compilers
+          case $CC in
+              nagfor*)
+                  verstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision"
+                  ;;
+              *)
+                  verstring="-compatibility_version $minor_current -current_version $minor_current.$revision"
+                  ;;
+          esac
+	  ;;
+
+	freebsd-aout)
+	  major=.$current
+	  versuffix=.$current.$revision
+	  ;;
+
+	freebsd-elf)
+	  func_arith $current - $age
+	  major=.$func_arith_result
+	  versuffix=$major.$age.$revision
+	  ;;
+
+	irix | nonstopux)
+	  if test no = "$lt_irix_increment"; then
+	    func_arith $current - $age
+	  else
+	    func_arith $current - $age + 1
+	  fi
+	  major=$func_arith_result
+
+	  case $version_type in
+	    nonstopux) verstring_prefix=nonstopux ;;
+	    *)         verstring_prefix=sgi ;;
+	  esac
+	  verstring=$verstring_prefix$major.$revision
+
+	  # Add in all the interfaces that we are compatible with.
+	  loop=$revision
+	  while test 0 -ne "$loop"; do
+	    func_arith $revision - $loop
+	    iface=$func_arith_result
+	    func_arith $loop - 1
+	    loop=$func_arith_result
+	    verstring=$verstring_prefix$major.$iface:$verstring
+	  done
+
+	  # Before this point, $major must not contain '.'.
+	  major=.$major
+	  versuffix=$major.$revision
+	  ;;
+
+	linux) # correct to gnu/linux during the next big refactor
+	  func_arith $current - $age
+	  major=.$func_arith_result
+	  versuffix=$major.$age.$revision
+	  ;;
+
+	osf)
+	  func_arith $current - $age
+	  major=.$func_arith_result
+	  versuffix=.$current.$age.$revision
+	  verstring=$current.$age.$revision
+
+	  # Add in all the interfaces that we are compatible with.
+	  loop=$age
+	  while test 0 -ne "$loop"; do
+	    func_arith $current - $loop
+	    iface=$func_arith_result
+	    func_arith $loop - 1
+	    loop=$func_arith_result
+	    verstring=$verstring:$iface.0
+	  done
+
+	  # Make executables depend on our current version.
+	  func_append verstring ":$current.0"
+	  ;;
+
+	qnx)
+	  major=.$current
+	  versuffix=.$current
+	  ;;
+
+	sco)
+	  major=.$current
+	  versuffix=.$current
+	  ;;
+
+	sunos)
+	  major=.$current
+	  versuffix=.$current.$revision
+	  ;;
+
+	windows)
+	  # Use '-' rather than '.', since we only want one
+	  # extension on DOS 8.3 file systems.
+	  func_arith $current - $age
+	  major=$func_arith_result
+	  versuffix=-$major
+	  ;;
+
+	*)
+	  func_fatal_configuration "unknown library version type '$version_type'"
+	  ;;
+	esac
+
+	# Clear the version info if we defaulted, and they specified a release.
+	if test -z "$vinfo" && test -n "$release"; then
+	  major=
+	  case $version_type in
+	  darwin)
+	    # we can't check for "0.0" in archive_cmds due to quoting
+	    # problems, so we reset it completely
+	    verstring=
+	    ;;
+	  *)
+	    verstring=0.0
+	    ;;
+	  esac
+	  if test no = "$need_version"; then
+	    versuffix=
+	  else
+	    versuffix=.0.0
+	  fi
+	fi
+
+	# Remove version info from name if versioning should be avoided
+	if test yes,no = "$avoid_version,$need_version"; then
+	  major=
+	  versuffix=
+	  verstring=
+	fi
+
+	# Check to see if the archive will have undefined symbols.
+	if test yes = "$allow_undefined"; then
+	  if test unsupported = "$allow_undefined_flag"; then
+	    if test yes = "$build_old_libs"; then
+	      func_warning "undefined symbols not allowed in $host shared libraries; building static only"
+	      build_libtool_libs=no
+	    else
+	      func_fatal_error "can't build $host shared library unless -no-undefined is specified"
+	    fi
+	  fi
+	else
+	  # Don't allow undefined symbols.
+	  allow_undefined_flag=$no_undefined_flag
+	fi
+
+      fi
+
+      func_generate_dlsyms "$libname" "$libname" :
+      func_append libobjs " $symfileobj"
+      test " " = "$libobjs" && libobjs=
+
+      if test relink != "$opt_mode"; then
+	# Remove our outputs, but don't remove object files since they
+	# may have been created when compiling PIC objects.
+	removelist=
+	tempremovelist=`$ECHO "$output_objdir/*"`
+	for p in $tempremovelist; do
+	  case $p in
+	    *.$objext | *.gcno)
+	       ;;
+	    $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/$libname$release.*)
+	       if test -n "$precious_files_regex"; then
+		 if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1
+		 then
+		   continue
+		 fi
+	       fi
+	       func_append removelist " $p"
+	       ;;
+	    *) ;;
+	  esac
+	done
+	test -n "$removelist" && \
+	  func_show_eval "${RM}r \$removelist"
+      fi
+
+      # Now set the variables for building old libraries.
+      if test yes = "$build_old_libs" && test convenience != "$build_libtool_libs"; then
+	func_append oldlibs " $output_objdir/$libname.$libext"
+
+	# Transform .lo files to .o files.
+	oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.$libext$/d; $lo2o" | $NL2SP`
+      fi
+
+      # Eliminate all temporary directories.
+      #for path in $notinst_path; do
+      #	lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"`
+      #	deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"`
+      #	dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"`
+      #done
+
+      if test -n "$xrpath"; then
+	# If the user specified any rpath flags, then add them.
+	temp_xrpath=
+	for libdir in $xrpath; do
+	  func_replace_sysroot "$libdir"
+	  func_append temp_xrpath " -R$func_replace_sysroot_result"
+	  case "$finalize_rpath " in
+	  *" $libdir "*) ;;
+	  *) func_append finalize_rpath " $libdir" ;;
+	  esac
+	done
+	if test yes != "$hardcode_into_libs" || test yes = "$build_old_libs"; then
+	  dependency_libs="$temp_xrpath $dependency_libs"
+	fi
+      fi
+
+      # Make sure dlfiles contains only unique files that won't be dlpreopened
+      old_dlfiles=$dlfiles
+      dlfiles=
+      for lib in $old_dlfiles; do
+	case " $dlprefiles $dlfiles " in
+	*" $lib "*) ;;
+	*) func_append dlfiles " $lib" ;;
+	esac
+      done
+
+      # Make sure dlprefiles contains only unique files
+      old_dlprefiles=$dlprefiles
+      dlprefiles=
+      for lib in $old_dlprefiles; do
+	case "$dlprefiles " in
+	*" $lib "*) ;;
+	*) func_append dlprefiles " $lib" ;;
+	esac
+      done
+
+      if test yes = "$build_libtool_libs"; then
+	if test -n "$rpath"; then
+	  case $host in
+	  *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*)
+	    # these systems don't actually have a c library (as such)!
+	    ;;
+	  *-*-rhapsody* | *-*-darwin1.[012])
+	    # Rhapsody C library is in the System framework
+	    func_append deplibs " System.ltframework"
+	    ;;
+	  *-*-netbsd*)
+	    # Don't link with libc until the a.out ld.so is fixed.
+	    ;;
+	  *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+	    # Do not include libc due to us having libc/libc_r.
+	    ;;
+	  *-*-sco3.2v5* | *-*-sco5v6*)
+	    # Causes problems with __ctype
+	    ;;
+	  *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
+	    # Compiler inserts libc in the correct place for threads to work
+	    ;;
+	  *)
+	    # Add libc to deplibs on all other systems if necessary.
+	    if test yes = "$build_libtool_need_lc"; then
+	      func_append deplibs " -lc"
+	    fi
+	    ;;
+	  esac
+	fi
+
+	# Transform deplibs into only deplibs that can be linked in shared.
+	name_save=$name
+	libname_save=$libname
+	release_save=$release
+	versuffix_save=$versuffix
+	major_save=$major
+	# I'm not sure if I'm treating the release correctly.  I think
+	# release should show up in the -l (ie -lgmp5) so we don't want to
+	# add it in twice.  Is that correct?
+	release=
+	versuffix=
+	major=
+	newdeplibs=
+	droppeddeps=no
+	case $deplibs_check_method in
+	pass_all)
+	  # Don't check for shared/static.  Everything works.
+	  # This might be a little naive.  We might want to check
+	  # whether the library exists or not.  But this is on
+	  # osf3 & osf4 and I'm not really sure... Just
+	  # implementing what was already the behavior.
+	  newdeplibs=$deplibs
+	  ;;
+	test_compile)
+	  # This code stresses the "libraries are programs" paradigm to its
+	  # limits. Maybe even breaks it.  We compile a program, linking it
+	  # against the deplibs as a proxy for the library.  Then we can check
+	  # whether they linked in statically or dynamically with ldd.
+	  $opt_dry_run || $RM conftest.c
+	  cat > conftest.c <<EOF
+	  int main() { return 0; }
+EOF
+	  $opt_dry_run || $RM conftest
+	  if $LTCC $LTCFLAGS -o conftest conftest.c $deplibs; then
+	    ldd_output=`ldd conftest`
+	    for i in $deplibs; do
+	      case $i in
+	      -l*)
+		func_stripname -l '' "$i"
+		name=$func_stripname_result
+		if test yes = "$allow_libtool_libs_with_static_runtimes"; then
+		  case " $predeps $postdeps " in
+		  *" $i "*)
+		    func_append newdeplibs " $i"
+		    i=
+		    ;;
+		  esac
+		fi
+		if test -n "$i"; then
+		  libname=`eval "\\$ECHO \"$libname_spec\""`
+		  deplib_matches=`eval "\\$ECHO \"$library_names_spec\""`
+		  set dummy $deplib_matches; shift
+		  deplib_match=$1
+		  if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0; then
+		    func_append newdeplibs " $i"
+		  else
+		    droppeddeps=yes
+		    echo
+		    $ECHO "*** Warning: dynamic linker does not accept needed library $i."
+		    echo "*** I have the capability to make that library automatically link in when"
+		    echo "*** you link to this library.  But I can only do this if you have a"
+		    echo "*** shared version of the library, which I believe you do not have"
+		    echo "*** because a test_compile did reveal that the linker did not use it for"
+		    echo "*** its dynamic dependency list that programs get resolved with at runtime."
+		  fi
+		fi
+		;;
+	      *)
+		func_append newdeplibs " $i"
+		;;
+	      esac
+	    done
+	  else
+	    # Error occurred in the first compile.  Let's try to salvage
+	    # the situation: Compile a separate program for each library.
+	    for i in $deplibs; do
+	      case $i in
+	      -l*)
+		func_stripname -l '' "$i"
+		name=$func_stripname_result
+		$opt_dry_run || $RM conftest
+		if $LTCC $LTCFLAGS -o conftest conftest.c $i; then
+		  ldd_output=`ldd conftest`
+		  if test yes = "$allow_libtool_libs_with_static_runtimes"; then
+		    case " $predeps $postdeps " in
+		    *" $i "*)
+		      func_append newdeplibs " $i"
+		      i=
+		      ;;
+		    esac
+		  fi
+		  if test -n "$i"; then
+		    libname=`eval "\\$ECHO \"$libname_spec\""`
+		    deplib_matches=`eval "\\$ECHO \"$library_names_spec\""`
+		    set dummy $deplib_matches; shift
+		    deplib_match=$1
+		    if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0; then
+		      func_append newdeplibs " $i"
+		    else
+		      droppeddeps=yes
+		      echo
+		      $ECHO "*** Warning: dynamic linker does not accept needed library $i."
+		      echo "*** I have the capability to make that library automatically link in when"
+		      echo "*** you link to this library.  But I can only do this if you have a"
+		      echo "*** shared version of the library, which you do not appear to have"
+		      echo "*** because a test_compile did reveal that the linker did not use this one"
+		      echo "*** as a dynamic dependency that programs can get resolved with at runtime."
+		    fi
+		  fi
+		else
+		  droppeddeps=yes
+		  echo
+		  $ECHO "*** Warning!  Library $i is needed by this library but I was not able to"
+		  echo "*** make it link in!  You will probably need to install it or some"
+		  echo "*** library that it depends on before this library will be fully"
+		  echo "*** functional.  Installing it before continuing would be even better."
+		fi
+		;;
+	      *)
+		func_append newdeplibs " $i"
+		;;
+	      esac
+	    done
+	  fi
+	  ;;
+	file_magic*)
+	  set dummy $deplibs_check_method; shift
+	  file_magic_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+	  for a_deplib in $deplibs; do
+	    case $a_deplib in
+	    -l*)
+	      func_stripname -l '' "$a_deplib"
+	      name=$func_stripname_result
+	      if test yes = "$allow_libtool_libs_with_static_runtimes"; then
+		case " $predeps $postdeps " in
+		*" $a_deplib "*)
+		  func_append newdeplibs " $a_deplib"
+		  a_deplib=
+		  ;;
+		esac
+	      fi
+	      if test -n "$a_deplib"; then
+		libname=`eval "\\$ECHO \"$libname_spec\""`
+		if test -n "$file_magic_glob"; then
+		  libnameglob=`func_echo_all "$libname" | $SED -e $file_magic_glob`
+		else
+		  libnameglob=$libname
+		fi
+		test yes = "$want_nocaseglob" && nocaseglob=`shopt -p nocaseglob`
+		for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+		  if test yes = "$want_nocaseglob"; then
+		    shopt -s nocaseglob
+		    potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null`
+		    $nocaseglob
+		  else
+		    potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null`
+		  fi
+		  for potent_lib in $potential_libs; do
+		      # Follow soft links.
+		      if ls -lLd "$potent_lib" 2>/dev/null |
+			 $GREP " -> " >/dev/null; then
+			continue
+		      fi
+		      # The statement above tries to avoid entering an
+		      # endless loop below, in case of cyclic links.
+		      # We might still enter an endless loop, since a link
+		      # loop can be closed while we follow links,
+		      # but so what?
+		      potlib=$potent_lib
+		      while test -h "$potlib" 2>/dev/null; do
+			potliblink=`ls -ld $potlib | $SED 's/.* -> //'`
+			case $potliblink in
+			[\\/]* | [A-Za-z]:[\\/]*) potlib=$potliblink;;
+			*) potlib=`$ECHO "$potlib" | $SED 's|[^/]*$||'`"$potliblink";;
+			esac
+		      done
+		      if eval $file_magic_cmd \"\$potlib\" 2>/dev/null |
+			 $SED -e 10q |
+			 $EGREP "$file_magic_regex" > /dev/null; then
+			func_append newdeplibs " $a_deplib"
+			a_deplib=
+			break 2
+		      fi
+		  done
+		done
+	      fi
+	      if test -n "$a_deplib"; then
+		droppeddeps=yes
+		echo
+		$ECHO "*** Warning: linker path does not have real file for library $a_deplib."
+		echo "*** I have the capability to make that library automatically link in when"
+		echo "*** you link to this library.  But I can only do this if you have a"
+		echo "*** shared version of the library, which you do not appear to have"
+		echo "*** because I did check the linker path looking for a file starting"
+		if test -z "$potlib"; then
+		  $ECHO "*** with $libname but no candidates were found. (...for file magic test)"
+		else
+		  $ECHO "*** with $libname and none of the candidates passed a file format test"
+		  $ECHO "*** using a file magic. Last file checked: $potlib"
+		fi
+	      fi
+	      ;;
+	    *)
+	      # Add a -L argument.
+	      func_append newdeplibs " $a_deplib"
+	      ;;
+	    esac
+	  done # Gone through all deplibs.
+	  ;;
+	match_pattern*)
+	  set dummy $deplibs_check_method; shift
+	  match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+	  for a_deplib in $deplibs; do
+	    case $a_deplib in
+	    -l*)
+	      func_stripname -l '' "$a_deplib"
+	      name=$func_stripname_result
+	      if test yes = "$allow_libtool_libs_with_static_runtimes"; then
+		case " $predeps $postdeps " in
+		*" $a_deplib "*)
+		  func_append newdeplibs " $a_deplib"
+		  a_deplib=
+		  ;;
+		esac
+	      fi
+	      if test -n "$a_deplib"; then
+		libname=`eval "\\$ECHO \"$libname_spec\""`
+		for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+		  potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
+		  for potent_lib in $potential_libs; do
+		    potlib=$potent_lib # see symlink-check above in file_magic test
+		    if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \
+		       $EGREP "$match_pattern_regex" > /dev/null; then
+		      func_append newdeplibs " $a_deplib"
+		      a_deplib=
+		      break 2
+		    fi
+		  done
+		done
+	      fi
+	      if test -n "$a_deplib"; then
+		droppeddeps=yes
+		echo
+		$ECHO "*** Warning: linker path does not have real file for library $a_deplib."
+		echo "*** I have the capability to make that library automatically link in when"
+		echo "*** you link to this library.  But I can only do this if you have a"
+		echo "*** shared version of the library, which you do not appear to have"
+		echo "*** because I did check the linker path looking for a file starting"
+		if test -z "$potlib"; then
+		  $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)"
+		else
+		  $ECHO "*** with $libname and none of the candidates passed a file format test"
+		  $ECHO "*** using a regex pattern. Last file checked: $potlib"
+		fi
+	      fi
+	      ;;
+	    *)
+	      # Add a -L argument.
+	      func_append newdeplibs " $a_deplib"
+	      ;;
+	    esac
+	  done # Gone through all deplibs.
+	  ;;
+	none | unknown | *)
+	  newdeplibs=
+	  tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'`
+	  if test yes = "$allow_libtool_libs_with_static_runtimes"; then
+	    for i in $predeps $postdeps; do
+	      # can't use Xsed below, because $i might contain '/'
+	      tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s|$i||"`
+	    done
+	  fi
+	  case $tmp_deplibs in
+	  *[!\	\ ]*)
+	    echo
+	    if test none = "$deplibs_check_method"; then
+	      echo "*** Warning: inter-library dependencies are not supported in this platform."
+	    else
+	      echo "*** Warning: inter-library dependencies are not known to be supported."
+	    fi
+	    echo "*** All declared inter-library dependencies are being dropped."
+	    droppeddeps=yes
+	    ;;
+	  esac
+	  ;;
+	esac
+	versuffix=$versuffix_save
+	major=$major_save
+	release=$release_save
+	libname=$libname_save
+	name=$name_save
+
+	case $host in
+	*-*-rhapsody* | *-*-darwin1.[012])
+	  # On Rhapsody replace the C library with the System framework
+	  newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'`
+	  ;;
+	esac
+
+	if test yes = "$droppeddeps"; then
+	  if test yes = "$module"; then
+	    echo
+	    echo "*** Warning: libtool could not satisfy all declared inter-library"
+	    $ECHO "*** dependencies of module $libname.  Therefore, libtool will create"
+	    echo "*** a static module, that should work as long as the dlopening"
+	    echo "*** application is linked with the -dlopen flag."
+	    if test -z "$global_symbol_pipe"; then
+	      echo
+	      echo "*** However, this would only work if libtool was able to extract symbol"
+	      echo "*** lists from a program, using 'nm' or equivalent, but libtool could"
+	      echo "*** not find such a program.  So, this module is probably useless."
+	      echo "*** 'nm' from GNU binutils and a full rebuild may help."
+	    fi
+	    if test no = "$build_old_libs"; then
+	      oldlibs=$output_objdir/$libname.$libext
+	      build_libtool_libs=module
+	      build_old_libs=yes
+	    else
+	      build_libtool_libs=no
+	    fi
+	  else
+	    echo "*** The inter-library dependencies that have been dropped here will be"
+	    echo "*** automatically added whenever a program is linked with this library"
+	    echo "*** or is declared to -dlopen it."
+
+	    if test no = "$allow_undefined"; then
+	      echo
+	      echo "*** Since this library must not contain undefined symbols,"
+	      echo "*** because either the platform does not support them or"
+	      echo "*** it was explicitly requested with -no-undefined,"
+	      echo "*** libtool will only create a static version of it."
+	      if test no = "$build_old_libs"; then
+		oldlibs=$output_objdir/$libname.$libext
+		build_libtool_libs=module
+		build_old_libs=yes
+	      else
+		build_libtool_libs=no
+	      fi
+	    fi
+	  fi
+	fi
+	# Done checking deplibs!
+	deplibs=$newdeplibs
+      fi
+      # Time to change all our "foo.ltframework" stuff back to "-framework foo"
+      case $host in
+	*-*-darwin*)
+	  newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	  new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	  deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	  ;;
+      esac
+
+      # move library search paths that coincide with paths to not yet
+      # installed libraries to the beginning of the library search list
+      new_libs=
+      for path in $notinst_path; do
+	case " $new_libs " in
+	*" -L$path/$objdir "*) ;;
+	*)
+	  case " $deplibs " in
+	  *" -L$path/$objdir "*)
+	    func_append new_libs " -L$path/$objdir" ;;
+	  esac
+	  ;;
+	esac
+      done
+      for deplib in $deplibs; do
+	case $deplib in
+	-L*)
+	  case " $new_libs " in
+	  *" $deplib "*) ;;
+	  *) func_append new_libs " $deplib" ;;
+	  esac
+	  ;;
+	*) func_append new_libs " $deplib" ;;
+	esac
+      done
+      deplibs=$new_libs
+
+      # All the library-specific variables (install_libdir is set above).
+      library_names=
+      old_library=
+      dlname=
+
+      # Test again, we may have decided not to build it any more
+      if test yes = "$build_libtool_libs"; then
+	# Remove $wl instances when linking with ld.
+	# FIXME: should test the right _cmds variable.
+	case $archive_cmds in
+	  *\$LD\ *) wl= ;;
+        esac
+	if test yes = "$hardcode_into_libs"; then
+	  # Hardcode the library paths
+	  hardcode_libdirs=
+	  dep_rpath=
+	  rpath=$finalize_rpath
+	  test relink = "$opt_mode" || rpath=$compile_rpath$rpath
+	  for libdir in $rpath; do
+	    if test -n "$hardcode_libdir_flag_spec"; then
+	      if test -n "$hardcode_libdir_separator"; then
+		func_replace_sysroot "$libdir"
+		libdir=$func_replace_sysroot_result
+		if test -z "$hardcode_libdirs"; then
+		  hardcode_libdirs=$libdir
+		else
+		  # Just accumulate the unique libdirs.
+		  case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+		  *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+		    ;;
+		  *)
+		    func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
+		    ;;
+		  esac
+		fi
+	      else
+		eval flag=\"$hardcode_libdir_flag_spec\"
+		func_append dep_rpath " $flag"
+	      fi
+	    elif test -n "$runpath_var"; then
+	      case "$perm_rpath " in
+	      *" $libdir "*) ;;
+	      *) func_append perm_rpath " $libdir" ;;
+	      esac
+	    fi
+	  done
+	  # Substitute the hardcoded libdirs into the rpath.
+	  if test -n "$hardcode_libdir_separator" &&
+	     test -n "$hardcode_libdirs"; then
+	    libdir=$hardcode_libdirs
+	    eval "dep_rpath=\"$hardcode_libdir_flag_spec\""
+	  fi
+	  if test -n "$runpath_var" && test -n "$perm_rpath"; then
+	    # We should set the runpath_var.
+	    rpath=
+	    for dir in $perm_rpath; do
+	      func_append rpath "$dir:"
+	    done
+	    eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var"
+	  fi
+	  test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs"
+	fi
+
+	shlibpath=$finalize_shlibpath
+	test relink = "$opt_mode" || shlibpath=$compile_shlibpath$shlibpath
+	if test -n "$shlibpath"; then
+	  eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var"
+	fi
+
+	# Get the real and link names of the library.
+	eval shared_ext=\"$shrext_cmds\"
+	eval library_names=\"$library_names_spec\"
+	set dummy $library_names
+	shift
+	realname=$1
+	shift
+
+	if test -n "$soname_spec"; then
+	  eval soname=\"$soname_spec\"
+	else
+	  soname=$realname
+	fi
+	if test -z "$dlname"; then
+	  dlname=$soname
+	fi
+
+	lib=$output_objdir/$realname
+	linknames=
+	for link
+	do
+	  func_append linknames " $link"
+	done
+
+	# Use standard objects if they are pic
+	test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP`
+	test "X$libobjs" = "X " && libobjs=
+
+	delfiles=
+	if test -n "$export_symbols" && test -n "$include_expsyms"; then
+	  $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp"
+	  export_symbols=$output_objdir/$libname.uexp
+	  func_append delfiles " $export_symbols"
+	fi
+
+	orig_export_symbols=
+	case $host_os in
+	cygwin* | mingw* | cegcc*)
+	  if test -n "$export_symbols" && test -z "$export_symbols_regex"; then
+	    # exporting using user supplied symfile
+	    func_dll_def_p "$export_symbols" || {
+	      # and it's NOT already a .def file. Must figure out
+	      # which of the given symbols are data symbols and tag
+	      # them as such. So, trigger use of export_symbols_cmds.
+	      # export_symbols gets reassigned inside the "prepare
+	      # the list of exported symbols" if statement, so the
+	      # include_expsyms logic still works.
+	      orig_export_symbols=$export_symbols
+	      export_symbols=
+	      always_export_symbols=yes
+	    }
+	  fi
+	  ;;
+	esac
+
+	# Prepare the list of exported symbols
+	if test -z "$export_symbols"; then
+	  if test yes = "$always_export_symbols" || test -n "$export_symbols_regex"; then
+	    func_verbose "generating symbol list for '$libname.la'"
+	    export_symbols=$output_objdir/$libname.exp
+	    $opt_dry_run || $RM $export_symbols
+	    cmds=$export_symbols_cmds
+	    save_ifs=$IFS; IFS='~'
+	    for cmd1 in $cmds; do
+	      IFS=$save_ifs
+	      # Take the normal branch if the nm_file_list_spec branch
+	      # doesn't work or if tool conversion is not needed.
+	      case $nm_file_list_spec~$to_tool_file_cmd in
+		*~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*)
+		  try_normal_branch=yes
+		  eval cmd=\"$cmd1\"
+		  func_len " $cmd"
+		  len=$func_len_result
+		  ;;
+		*)
+		  try_normal_branch=no
+		  ;;
+	      esac
+	      if test yes = "$try_normal_branch" \
+		 && { test "$len" -lt "$max_cmd_len" \
+		      || test "$max_cmd_len" -le -1; }
+	      then
+		func_show_eval "$cmd" 'exit $?'
+		skipped_export=false
+	      elif test -n "$nm_file_list_spec"; then
+		func_basename "$output"
+		output_la=$func_basename_result
+		save_libobjs=$libobjs
+		save_output=$output
+		output=$output_objdir/$output_la.nm
+		func_to_tool_file "$output"
+		libobjs=$nm_file_list_spec$func_to_tool_file_result
+		func_append delfiles " $output"
+		func_verbose "creating $NM input file list: $output"
+		for obj in $save_libobjs; do
+		  func_to_tool_file "$obj"
+		  $ECHO "$func_to_tool_file_result"
+		done > "$output"
+		eval cmd=\"$cmd1\"
+		func_show_eval "$cmd" 'exit $?'
+		output=$save_output
+		libobjs=$save_libobjs
+		skipped_export=false
+	      else
+		# The command line is too long to execute in one step.
+		func_verbose "using reloadable object file for export list..."
+		skipped_export=:
+		# Break out early, otherwise skipped_export may be
+		# set to false by a later but shorter cmd.
+		break
+	      fi
+	    done
+	    IFS=$save_ifs
+	    if test -n "$export_symbols_regex" && test : != "$skipped_export"; then
+	      func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+	      func_show_eval '$MV "${export_symbols}T" "$export_symbols"'
+	    fi
+	  fi
+	fi
+
+	if test -n "$export_symbols" && test -n "$include_expsyms"; then
+	  tmp_export_symbols=$export_symbols
+	  test -n "$orig_export_symbols" && tmp_export_symbols=$orig_export_symbols
+	  $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"'
+	fi
+
+	if test : != "$skipped_export" && test -n "$orig_export_symbols"; then
+	  # The given exports_symbols file has to be filtered, so filter it.
+	  func_verbose "filter symbol list for '$libname.la' to tag DATA exports"
+	  # FIXME: $output_objdir/$libname.filter potentially contains lots of
+	  # 's' commands, which not all seds can handle. GNU sed should be fine
+	  # though. Also, the filter scales superlinearly with the number of
+	  # global variables. join(1) would be nice here, but unfortunately
+	  # isn't a blessed tool.
+	  $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter
+	  func_append delfiles " $export_symbols $output_objdir/$libname.filter"
+	  export_symbols=$output_objdir/$libname.def
+	  $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols
+	fi
+
+	tmp_deplibs=
+	for test_deplib in $deplibs; do
+	  case " $convenience " in
+	  *" $test_deplib "*) ;;
+	  *)
+	    func_append tmp_deplibs " $test_deplib"
+	    ;;
+	  esac
+	done
+	deplibs=$tmp_deplibs
+
+	if test -n "$convenience"; then
+	  if test -n "$whole_archive_flag_spec" &&
+	    test yes = "$compiler_needs_object" &&
+	    test -z "$libobjs"; then
+	    # extract the archives, so we have objects to list.
+	    # TODO: could optimize this to just extract one archive.
+	    whole_archive_flag_spec=
+	  fi
+	  if test -n "$whole_archive_flag_spec"; then
+	    save_libobjs=$libobjs
+	    eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+	    test "X$libobjs" = "X " && libobjs=
+	  else
+	    gentop=$output_objdir/${outputname}x
+	    func_append generated " $gentop"
+
+	    func_extract_archives $gentop $convenience
+	    func_append libobjs " $func_extract_archives_result"
+	    test "X$libobjs" = "X " && libobjs=
+	  fi
+	fi
+
+	if test yes = "$thread_safe" && test -n "$thread_safe_flag_spec"; then
+	  eval flag=\"$thread_safe_flag_spec\"
+	  func_append linker_flags " $flag"
+	fi
+
+	# Make a backup of the uninstalled library when relinking
+	if test relink = "$opt_mode"; then
+	  $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $?
+	fi
+
+	# Do each of the archive commands.
+	if test yes = "$module" && test -n "$module_cmds"; then
+	  if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+	    eval test_cmds=\"$module_expsym_cmds\"
+	    cmds=$module_expsym_cmds
+	  else
+	    eval test_cmds=\"$module_cmds\"
+	    cmds=$module_cmds
+	  fi
+	else
+	  if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+	    eval test_cmds=\"$archive_expsym_cmds\"
+	    cmds=$archive_expsym_cmds
+	  else
+	    eval test_cmds=\"$archive_cmds\"
+	    cmds=$archive_cmds
+	  fi
+	fi
+
+	if test : != "$skipped_export" &&
+	   func_len " $test_cmds" &&
+	   len=$func_len_result &&
+	   test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+	  :
+	else
+	  # The command line is too long to link in one step, link piecewise
+	  # or, if using GNU ld and skipped_export is not :, use a linker
+	  # script.
+
+	  # Save the value of $output and $libobjs because we want to
+	  # use them later.  If we have whole_archive_flag_spec, we
+	  # want to use save_libobjs as it was before
+	  # whole_archive_flag_spec was expanded, because we can't
+	  # assume the linker understands whole_archive_flag_spec.
+	  # This may have to be revisited, in case too many
+	  # convenience libraries get linked in and end up exceeding
+	  # the spec.
+	  if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then
+	    save_libobjs=$libobjs
+	  fi
+	  save_output=$output
+	  func_basename "$output"
+	  output_la=$func_basename_result
+
+	  # Clear the reloadable object creation command queue and
+	  # initialize k to one.
+	  test_cmds=
+	  concat_cmds=
+	  objlist=
+	  last_robj=
+	  k=1
+
+	  if test -n "$save_libobjs" && test : != "$skipped_export" && test yes = "$with_gnu_ld"; then
+	    output=$output_objdir/$output_la.lnkscript
+	    func_verbose "creating GNU ld script: $output"
+	    echo 'INPUT (' > $output
+	    for obj in $save_libobjs
+	    do
+	      func_to_tool_file "$obj"
+	      $ECHO "$func_to_tool_file_result" >> $output
+	    done
+	    echo ')' >> $output
+	    func_append delfiles " $output"
+	    func_to_tool_file "$output"
+	    output=$func_to_tool_file_result
+	  elif test -n "$save_libobjs" && test : != "$skipped_export" && test -n "$file_list_spec"; then
+	    output=$output_objdir/$output_la.lnk
+	    func_verbose "creating linker input file list: $output"
+	    : > $output
+	    set x $save_libobjs
+	    shift
+	    firstobj=
+	    if test yes = "$compiler_needs_object"; then
+	      firstobj="$1 "
+	      shift
+	    fi
+	    for obj
+	    do
+	      func_to_tool_file "$obj"
+	      $ECHO "$func_to_tool_file_result" >> $output
+	    done
+	    func_append delfiles " $output"
+	    func_to_tool_file "$output"
+	    output=$firstobj\"$file_list_spec$func_to_tool_file_result\"
+	  else
+	    if test -n "$save_libobjs"; then
+	      func_verbose "creating reloadable object files..."
+	      output=$output_objdir/$output_la-$k.$objext
+	      eval test_cmds=\"$reload_cmds\"
+	      func_len " $test_cmds"
+	      len0=$func_len_result
+	      len=$len0
+
+	      # Loop over the list of objects to be linked.
+	      for obj in $save_libobjs
+	      do
+		func_len " $obj"
+		func_arith $len + $func_len_result
+		len=$func_arith_result
+		if test -z "$objlist" ||
+		   test "$len" -lt "$max_cmd_len"; then
+		  func_append objlist " $obj"
+		else
+		  # The command $test_cmds is almost too long, add a
+		  # command to the queue.
+		  if test 1 -eq "$k"; then
+		    # The first file doesn't have a previous command to add.
+		    reload_objs=$objlist
+		    eval concat_cmds=\"$reload_cmds\"
+		  else
+		    # All subsequent reloadable object files will link in
+		    # the last one created.
+		    reload_objs="$objlist $last_robj"
+		    eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\"
+		  fi
+		  last_robj=$output_objdir/$output_la-$k.$objext
+		  func_arith $k + 1
+		  k=$func_arith_result
+		  output=$output_objdir/$output_la-$k.$objext
+		  objlist=" $obj"
+		  func_len " $last_robj"
+		  func_arith $len0 + $func_len_result
+		  len=$func_arith_result
+		fi
+	      done
+	      # Handle the remaining objects by creating one last
+	      # reloadable object file.  All subsequent reloadable object
+	      # files will link in the last one created.
+	      test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+	      reload_objs="$objlist $last_robj"
+	      eval concat_cmds=\"\$concat_cmds$reload_cmds\"
+	      if test -n "$last_robj"; then
+	        eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\"
+	      fi
+	      func_append delfiles " $output"
+
+	    else
+	      output=
+	    fi
+
+	    ${skipped_export-false} && {
+	      func_verbose "generating symbol list for '$libname.la'"
+	      export_symbols=$output_objdir/$libname.exp
+	      $opt_dry_run || $RM $export_symbols
+	      libobjs=$output
+	      # Append the command to create the export file.
+	      test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+	      eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\"
+	      if test -n "$last_robj"; then
+		eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\"
+	      fi
+	    }
+
+	    test -n "$save_libobjs" &&
+	      func_verbose "creating a temporary reloadable object file: $output"
+
+	    # Loop through the commands generated above and execute them.
+	    save_ifs=$IFS; IFS='~'
+	    for cmd in $concat_cmds; do
+	      IFS=$save_ifs
+	      $opt_quiet || {
+		  func_quote_for_expand "$cmd"
+		  eval "func_echo $func_quote_for_expand_result"
+	      }
+	      $opt_dry_run || eval "$cmd" || {
+		lt_exit=$?
+
+		# Restore the uninstalled library and exit
+		if test relink = "$opt_mode"; then
+		  ( cd "$output_objdir" && \
+		    $RM "${realname}T" && \
+		    $MV "${realname}U" "$realname" )
+		fi
+
+		exit $lt_exit
+	      }
+	    done
+	    IFS=$save_ifs
+
+	    if test -n "$export_symbols_regex" && ${skipped_export-false}; then
+	      func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+	      func_show_eval '$MV "${export_symbols}T" "$export_symbols"'
+	    fi
+	  fi
+
+          ${skipped_export-false} && {
+	    if test -n "$export_symbols" && test -n "$include_expsyms"; then
+	      tmp_export_symbols=$export_symbols
+	      test -n "$orig_export_symbols" && tmp_export_symbols=$orig_export_symbols
+	      $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"'
+	    fi
+
+	    if test -n "$orig_export_symbols"; then
+	      # The given exports_symbols file has to be filtered, so filter it.
+	      func_verbose "filter symbol list for '$libname.la' to tag DATA exports"
+	      # FIXME: $output_objdir/$libname.filter potentially contains lots of
+	      # 's' commands, which not all seds can handle. GNU sed should be fine
+	      # though. Also, the filter scales superlinearly with the number of
+	      # global variables. join(1) would be nice here, but unfortunately
+	      # isn't a blessed tool.
+	      $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter
+	      func_append delfiles " $export_symbols $output_objdir/$libname.filter"
+	      export_symbols=$output_objdir/$libname.def
+	      $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols
+	    fi
+	  }
+
+	  libobjs=$output
+	  # Restore the value of output.
+	  output=$save_output
+
+	  if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then
+	    eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+	    test "X$libobjs" = "X " && libobjs=
+	  fi
+	  # Expand the library linking commands again to reset the
+	  # value of $libobjs for piecewise linking.
+
+	  # Do each of the archive commands.
+	  if test yes = "$module" && test -n "$module_cmds"; then
+	    if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+	      cmds=$module_expsym_cmds
+	    else
+	      cmds=$module_cmds
+	    fi
+	  else
+	    if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+	      cmds=$archive_expsym_cmds
+	    else
+	      cmds=$archive_cmds
+	    fi
+	  fi
+	fi
+
+	if test -n "$delfiles"; then
+	  # Append the command to remove temporary files to $cmds.
+	  eval cmds=\"\$cmds~\$RM $delfiles\"
+	fi
+
+	# Add any objects from preloaded convenience libraries
+	if test -n "$dlprefiles"; then
+	  gentop=$output_objdir/${outputname}x
+	  func_append generated " $gentop"
+
+	  func_extract_archives $gentop $dlprefiles
+	  func_append libobjs " $func_extract_archives_result"
+	  test "X$libobjs" = "X " && libobjs=
+	fi
+
+	save_ifs=$IFS; IFS='~'
+	for cmd in $cmds; do
+	  IFS=$sp$nl
+	  eval cmd=\"$cmd\"
+	  IFS=$save_ifs
+	  $opt_quiet || {
+	    func_quote_for_expand "$cmd"
+	    eval "func_echo $func_quote_for_expand_result"
+	  }
+	  $opt_dry_run || eval "$cmd" || {
+	    lt_exit=$?
+
+	    # Restore the uninstalled library and exit
+	    if test relink = "$opt_mode"; then
+	      ( cd "$output_objdir" && \
+	        $RM "${realname}T" && \
+		$MV "${realname}U" "$realname" )
+	    fi
+
+	    exit $lt_exit
+	  }
+	done
+	IFS=$save_ifs
+
+	# Restore the uninstalled library and exit
+	if test relink = "$opt_mode"; then
+	  $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $?
+
+	  if test -n "$convenience"; then
+	    if test -z "$whole_archive_flag_spec"; then
+	      func_show_eval '${RM}r "$gentop"'
+	    fi
+	  fi
+
+	  exit $EXIT_SUCCESS
+	fi
+
+	# Create links to the real library.
+	for linkname in $linknames; do
+	  if test "$realname" != "$linkname"; then
+	    func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?'
+	  fi
+	done
+
+	# If -module or -export-dynamic was specified, set the dlname.
+	if test yes = "$module" || test yes = "$export_dynamic"; then
+	  # On all known operating systems, these are identical.
+	  dlname=$soname
+	fi
+      fi
+      ;;
+
+    obj)
+      if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then
+	func_warning "'-dlopen' is ignored for objects"
+      fi
+
+      case " $deplibs" in
+      *\ -l* | *\ -L*)
+	func_warning "'-l' and '-L' are ignored for objects" ;;
+      esac
+
+      test -n "$rpath" && \
+	func_warning "'-rpath' is ignored for objects"
+
+      test -n "$xrpath" && \
+	func_warning "'-R' is ignored for objects"
+
+      test -n "$vinfo" && \
+	func_warning "'-version-info' is ignored for objects"
+
+      test -n "$release" && \
+	func_warning "'-release' is ignored for objects"
+
+      case $output in
+      *.lo)
+	test -n "$objs$old_deplibs" && \
+	  func_fatal_error "cannot build library object '$output' from non-libtool objects"
+
+	libobj=$output
+	func_lo2o "$libobj"
+	obj=$func_lo2o_result
+	;;
+      *)
+	libobj=
+	obj=$output
+	;;
+      esac
+
+      # Delete the old objects.
+      $opt_dry_run || $RM $obj $libobj
+
+      # Objects from convenience libraries.  This assumes
+      # single-version convenience libraries.  Whenever we create
+      # different ones for PIC/non-PIC, this we'll have to duplicate
+      # the extraction.
+      reload_conv_objs=
+      gentop=
+      # if reload_cmds runs $LD directly, get rid of -Wl from
+      # whole_archive_flag_spec and hope we can get by with turning comma
+      # into space.
+      case $reload_cmds in
+        *\$LD[\ \$]*) wl= ;;
+      esac
+      if test -n "$convenience"; then
+	if test -n "$whole_archive_flag_spec"; then
+	  eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\"
+	  test -n "$wl" || tmp_whole_archive_flags=`$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'`
+	  reload_conv_objs=$reload_objs\ $tmp_whole_archive_flags
+	else
+	  gentop=$output_objdir/${obj}x
+	  func_append generated " $gentop"
+
+	  func_extract_archives $gentop $convenience
+	  reload_conv_objs="$reload_objs $func_extract_archives_result"
+	fi
+      fi
+
+      # If we're not building shared, we need to use non_pic_objs
+      test yes = "$build_libtool_libs" || libobjs=$non_pic_objects
+
+      # Create the old-style object.
+      reload_objs=$objs$old_deplibs' '`$ECHO "$libobjs" | $SP2NL | $SED "/\.$libext$/d; /\.lib$/d; $lo2o" | $NL2SP`' '$reload_conv_objs
+
+      output=$obj
+      func_execute_cmds "$reload_cmds" 'exit $?'
+
+      # Exit if we aren't doing a library object file.
+      if test -z "$libobj"; then
+	if test -n "$gentop"; then
+	  func_show_eval '${RM}r "$gentop"'
+	fi
+
+	exit $EXIT_SUCCESS
+      fi
+
+      test yes = "$build_libtool_libs" || {
+	if test -n "$gentop"; then
+	  func_show_eval '${RM}r "$gentop"'
+	fi
+
+	# Create an invalid libtool object if no PIC, so that we don't
+	# accidentally link it into a program.
+	# $show "echo timestamp > $libobj"
+	# $opt_dry_run || eval "echo timestamp > $libobj" || exit $?
+	exit $EXIT_SUCCESS
+      }
+
+      if test -n "$pic_flag" || test default != "$pic_mode"; then
+	# Only do commands if we really have different PIC objects.
+	reload_objs="$libobjs $reload_conv_objs"
+	output=$libobj
+	func_execute_cmds "$reload_cmds" 'exit $?'
+      fi
+
+      if test -n "$gentop"; then
+	func_show_eval '${RM}r "$gentop"'
+      fi
+
+      exit $EXIT_SUCCESS
+      ;;
+
+    prog)
+      case $host in
+	*cygwin*) func_stripname '' '.exe' "$output"
+	          output=$func_stripname_result.exe;;
+      esac
+      test -n "$vinfo" && \
+	func_warning "'-version-info' is ignored for programs"
+
+      test -n "$release" && \
+	func_warning "'-release' is ignored for programs"
+
+      $preload \
+	&& test unknown,unknown,unknown = "$dlopen_support,$dlopen_self,$dlopen_self_static" \
+	&& func_warning "'LT_INIT([dlopen])' not used. Assuming no dlopen support."
+
+      case $host in
+      *-*-rhapsody* | *-*-darwin1.[012])
+	# On Rhapsody replace the C library is the System framework
+	compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'`
+	finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'`
+	;;
+      esac
+
+      case $host in
+      *-*-darwin*)
+	# Don't allow lazy linking, it breaks C++ global constructors
+	# But is supposedly fixed on 10.4 or later (yay!).
+	if test CXX = "$tagname"; then
+	  case ${MACOSX_DEPLOYMENT_TARGET-10.0} in
+	    10.[0123])
+	      func_append compile_command " $wl-bind_at_load"
+	      func_append finalize_command " $wl-bind_at_load"
+	    ;;
+	  esac
+	fi
+	# Time to change all our "foo.ltframework" stuff back to "-framework foo"
+	compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	;;
+      esac
+
+
+      # move library search paths that coincide with paths to not yet
+      # installed libraries to the beginning of the library search list
+      new_libs=
+      for path in $notinst_path; do
+	case " $new_libs " in
+	*" -L$path/$objdir "*) ;;
+	*)
+	  case " $compile_deplibs " in
+	  *" -L$path/$objdir "*)
+	    func_append new_libs " -L$path/$objdir" ;;
+	  esac
+	  ;;
+	esac
+      done
+      for deplib in $compile_deplibs; do
+	case $deplib in
+	-L*)
+	  case " $new_libs " in
+	  *" $deplib "*) ;;
+	  *) func_append new_libs " $deplib" ;;
+	  esac
+	  ;;
+	*) func_append new_libs " $deplib" ;;
+	esac
+      done
+      compile_deplibs=$new_libs
+
+
+      func_append compile_command " $compile_deplibs"
+      func_append finalize_command " $finalize_deplibs"
+
+      if test -n "$rpath$xrpath"; then
+	# If the user specified any rpath flags, then add them.
+	for libdir in $rpath $xrpath; do
+	  # This is the magic to use -rpath.
+	  case "$finalize_rpath " in
+	  *" $libdir "*) ;;
+	  *) func_append finalize_rpath " $libdir" ;;
+	  esac
+	done
+      fi
+
+      # Now hardcode the library paths
+      rpath=
+      hardcode_libdirs=
+      for libdir in $compile_rpath $finalize_rpath; do
+	if test -n "$hardcode_libdir_flag_spec"; then
+	  if test -n "$hardcode_libdir_separator"; then
+	    if test -z "$hardcode_libdirs"; then
+	      hardcode_libdirs=$libdir
+	    else
+	      # Just accumulate the unique libdirs.
+	      case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+	      *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+		;;
+	      *)
+		func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
+		;;
+	      esac
+	    fi
+	  else
+	    eval flag=\"$hardcode_libdir_flag_spec\"
+	    func_append rpath " $flag"
+	  fi
+	elif test -n "$runpath_var"; then
+	  case "$perm_rpath " in
+	  *" $libdir "*) ;;
+	  *) func_append perm_rpath " $libdir" ;;
+	  esac
+	fi
+	case $host in
+	*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+	  testbindir=`$ECHO "$libdir" | $SED -e 's*/lib$*/bin*'`
+	  case :$dllsearchpath: in
+	  *":$libdir:"*) ;;
+	  ::) dllsearchpath=$libdir;;
+	  *) func_append dllsearchpath ":$libdir";;
+	  esac
+	  case :$dllsearchpath: in
+	  *":$testbindir:"*) ;;
+	  ::) dllsearchpath=$testbindir;;
+	  *) func_append dllsearchpath ":$testbindir";;
+	  esac
+	  ;;
+	esac
+      done
+      # Substitute the hardcoded libdirs into the rpath.
+      if test -n "$hardcode_libdir_separator" &&
+	 test -n "$hardcode_libdirs"; then
+	libdir=$hardcode_libdirs
+	eval rpath=\" $hardcode_libdir_flag_spec\"
+      fi
+      compile_rpath=$rpath
+
+      rpath=
+      hardcode_libdirs=
+      for libdir in $finalize_rpath; do
+	if test -n "$hardcode_libdir_flag_spec"; then
+	  if test -n "$hardcode_libdir_separator"; then
+	    if test -z "$hardcode_libdirs"; then
+	      hardcode_libdirs=$libdir
+	    else
+	      # Just accumulate the unique libdirs.
+	      case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+	      *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+		;;
+	      *)
+		func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
+		;;
+	      esac
+	    fi
+	  else
+	    eval flag=\"$hardcode_libdir_flag_spec\"
+	    func_append rpath " $flag"
+	  fi
+	elif test -n "$runpath_var"; then
+	  case "$finalize_perm_rpath " in
+	  *" $libdir "*) ;;
+	  *) func_append finalize_perm_rpath " $libdir" ;;
+	  esac
+	fi
+      done
+      # Substitute the hardcoded libdirs into the rpath.
+      if test -n "$hardcode_libdir_separator" &&
+	 test -n "$hardcode_libdirs"; then
+	libdir=$hardcode_libdirs
+	eval rpath=\" $hardcode_libdir_flag_spec\"
+      fi
+      finalize_rpath=$rpath
+
+      if test -n "$libobjs" && test yes = "$build_old_libs"; then
+	# Transform all the library objects into standard objects.
+	compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP`
+	finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP`
+      fi
+
+      func_generate_dlsyms "$outputname" "@PROGRAM@" false
+
+      # template prelinking step
+      if test -n "$prelink_cmds"; then
+	func_execute_cmds "$prelink_cmds" 'exit $?'
+      fi
+
+      wrappers_required=:
+      case $host in
+      *cegcc* | *mingw32ce*)
+        # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway.
+        wrappers_required=false
+        ;;
+      *cygwin* | *mingw* )
+        test yes = "$build_libtool_libs" || wrappers_required=false
+        ;;
+      *)
+        if test no = "$need_relink" || test yes != "$build_libtool_libs"; then
+          wrappers_required=false
+        fi
+        ;;
+      esac
+      $wrappers_required || {
+	# Replace the output file specification.
+	compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'`
+	link_command=$compile_command$compile_rpath
+
+	# We have no uninstalled library dependencies, so finalize right now.
+	exit_status=0
+	func_show_eval "$link_command" 'exit_status=$?'
+
+	if test -n "$postlink_cmds"; then
+	  func_to_tool_file "$output"
+	  postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
+	  func_execute_cmds "$postlink_cmds" 'exit $?'
+	fi
+
+	# Delete the generated files.
+	if test -f "$output_objdir/${outputname}S.$objext"; then
+	  func_show_eval '$RM "$output_objdir/${outputname}S.$objext"'
+	fi
+
+	exit $exit_status
+      }
+
+      if test -n "$compile_shlibpath$finalize_shlibpath"; then
+	compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command"
+      fi
+      if test -n "$finalize_shlibpath"; then
+	finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command"
+      fi
+
+      compile_var=
+      finalize_var=
+      if test -n "$runpath_var"; then
+	if test -n "$perm_rpath"; then
+	  # We should set the runpath_var.
+	  rpath=
+	  for dir in $perm_rpath; do
+	    func_append rpath "$dir:"
+	  done
+	  compile_var="$runpath_var=\"$rpath\$$runpath_var\" "
+	fi
+	if test -n "$finalize_perm_rpath"; then
+	  # We should set the runpath_var.
+	  rpath=
+	  for dir in $finalize_perm_rpath; do
+	    func_append rpath "$dir:"
+	  done
+	  finalize_var="$runpath_var=\"$rpath\$$runpath_var\" "
+	fi
+      fi
+
+      if test yes = "$no_install"; then
+	# We don't need to create a wrapper script.
+	link_command=$compile_var$compile_command$compile_rpath
+	# Replace the output file specification.
+	link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'`
+	# Delete the old output file.
+	$opt_dry_run || $RM $output
+	# Link the executable and exit
+	func_show_eval "$link_command" 'exit $?'
+
+	if test -n "$postlink_cmds"; then
+	  func_to_tool_file "$output"
+	  postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
+	  func_execute_cmds "$postlink_cmds" 'exit $?'
+	fi
+
+	exit $EXIT_SUCCESS
+      fi
+
+      case $hardcode_action,$fast_install in
+        relink,*)
+	  # Fast installation is not supported
+	  link_command=$compile_var$compile_command$compile_rpath
+	  relink_command=$finalize_var$finalize_command$finalize_rpath
+
+	  func_warning "this platform does not like uninstalled shared libraries"
+	  func_warning "'$output' will be relinked during installation"
+	  ;;
+        *,yes)
+	  link_command=$finalize_var$compile_command$finalize_rpath
+	  relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'`
+          ;;
+	*,no)
+	  link_command=$compile_var$compile_command$compile_rpath
+	  relink_command=$finalize_var$finalize_command$finalize_rpath
+          ;;
+	*,needless)
+	  link_command=$finalize_var$compile_command$finalize_rpath
+	  relink_command=
+          ;;
+      esac
+
+      # Replace the output file specification.
+      link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'`
+
+      # Delete the old output files.
+      $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname
+
+      func_show_eval "$link_command" 'exit $?'
+
+      if test -n "$postlink_cmds"; then
+	func_to_tool_file "$output_objdir/$outputname"
+	postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
+	func_execute_cmds "$postlink_cmds" 'exit $?'
+      fi
+
+      # Now create the wrapper script.
+      func_verbose "creating $output"
+
+      # Quote the relink command for shipping.
+      if test -n "$relink_command"; then
+	# Preserve any variables that may affect compiler behavior
+	for var in $variables_saved_for_relink; do
+	  if eval test -z \"\${$var+set}\"; then
+	    relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command"
+	  elif eval var_value=\$$var; test -z "$var_value"; then
+	    relink_command="$var=; export $var; $relink_command"
+	  else
+	    func_quote_for_eval "$var_value"
+	    relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
+	  fi
+	done
+	relink_command="(cd `pwd`; $relink_command)"
+	relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"`
+      fi
+
+      # Only actually do things if not in dry run mode.
+      $opt_dry_run || {
+	# win32 will think the script is a binary if it has
+	# a .exe suffix, so we strip it off here.
+	case $output in
+	  *.exe) func_stripname '' '.exe' "$output"
+	         output=$func_stripname_result ;;
+	esac
+	# test for cygwin because mv fails w/o .exe extensions
+	case $host in
+	  *cygwin*)
+	    exeext=.exe
+	    func_stripname '' '.exe' "$outputname"
+	    outputname=$func_stripname_result ;;
+	  *) exeext= ;;
+	esac
+	case $host in
+	  *cygwin* | *mingw* )
+	    func_dirname_and_basename "$output" "" "."
+	    output_name=$func_basename_result
+	    output_path=$func_dirname_result
+	    cwrappersource=$output_path/$objdir/lt-$output_name.c
+	    cwrapper=$output_path/$output_name.exe
+	    $RM $cwrappersource $cwrapper
+	    trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15
+
+	    func_emit_cwrapperexe_src > $cwrappersource
+
+	    # The wrapper executable is built using the $host compiler,
+	    # because it contains $host paths and files. If cross-
+	    # compiling, it, like the target executable, must be
+	    # executed on the $host or under an emulation environment.
+	    $opt_dry_run || {
+	      $LTCC $LTCFLAGS -o $cwrapper $cwrappersource
+	      $STRIP $cwrapper
+	    }
+
+	    # Now, create the wrapper script for func_source use:
+	    func_ltwrapper_scriptname $cwrapper
+	    $RM $func_ltwrapper_scriptname_result
+	    trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15
+	    $opt_dry_run || {
+	      # note: this script will not be executed, so do not chmod.
+	      if test "x$build" = "x$host"; then
+		$cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result
+	      else
+		func_emit_wrapper no > $func_ltwrapper_scriptname_result
+	      fi
+	    }
+	  ;;
+	  * )
+	    $RM $output
+	    trap "$RM $output; exit $EXIT_FAILURE" 1 2 15
+
+	    func_emit_wrapper no > $output
+	    chmod +x $output
+	  ;;
+	esac
+      }
+      exit $EXIT_SUCCESS
+      ;;
+    esac
+
+    # See if we need to build an old-fashioned archive.
+    for oldlib in $oldlibs; do
+
+      case $build_libtool_libs in
+        convenience)
+	  oldobjs="$libobjs_save $symfileobj"
+	  addlibs=$convenience
+	  build_libtool_libs=no
+	  ;;
+	module)
+	  oldobjs=$libobjs_save
+	  addlibs=$old_convenience
+	  build_libtool_libs=no
+          ;;
+	*)
+	  oldobjs="$old_deplibs $non_pic_objects"
+	  $preload && test -f "$symfileobj" \
+	    && func_append oldobjs " $symfileobj"
+	  addlibs=$old_convenience
+	  ;;
+      esac
+
+      if test -n "$addlibs"; then
+	gentop=$output_objdir/${outputname}x
+	func_append generated " $gentop"
+
+	func_extract_archives $gentop $addlibs
+	func_append oldobjs " $func_extract_archives_result"
+      fi
+
+      # Do each command in the archive commands.
+      if test -n "$old_archive_from_new_cmds" && test yes = "$build_libtool_libs"; then
+	cmds=$old_archive_from_new_cmds
+      else
+
+	# Add any objects from preloaded convenience libraries
+	if test -n "$dlprefiles"; then
+	  gentop=$output_objdir/${outputname}x
+	  func_append generated " $gentop"
+
+	  func_extract_archives $gentop $dlprefiles
+	  func_append oldobjs " $func_extract_archives_result"
+	fi
+
+	# POSIX demands no paths to be encoded in archives.  We have
+	# to avoid creating archives with duplicate basenames if we
+	# might have to extract them afterwards, e.g., when creating a
+	# static archive out of a convenience library, or when linking
+	# the entirety of a libtool archive into another (currently
+	# not supported by libtool).
+	if (for obj in $oldobjs
+	    do
+	      func_basename "$obj"
+	      $ECHO "$func_basename_result"
+	    done | sort | sort -uc >/dev/null 2>&1); then
+	  :
+	else
+	  echo "copying selected object files to avoid basename conflicts..."
+	  gentop=$output_objdir/${outputname}x
+	  func_append generated " $gentop"
+	  func_mkdir_p "$gentop"
+	  save_oldobjs=$oldobjs
+	  oldobjs=
+	  counter=1
+	  for obj in $save_oldobjs
+	  do
+	    func_basename "$obj"
+	    objbase=$func_basename_result
+	    case " $oldobjs " in
+	    " ") oldobjs=$obj ;;
+	    *[\ /]"$objbase "*)
+	      while :; do
+		# Make sure we don't pick an alternate name that also
+		# overlaps.
+		newobj=lt$counter-$objbase
+		func_arith $counter + 1
+		counter=$func_arith_result
+		case " $oldobjs " in
+		*[\ /]"$newobj "*) ;;
+		*) if test ! -f "$gentop/$newobj"; then break; fi ;;
+		esac
+	      done
+	      func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj"
+	      func_append oldobjs " $gentop/$newobj"
+	      ;;
+	    *) func_append oldobjs " $obj" ;;
+	    esac
+	  done
+	fi
+	func_to_tool_file "$oldlib" func_convert_file_msys_to_w32
+	tool_oldlib=$func_to_tool_file_result
+	eval cmds=\"$old_archive_cmds\"
+
+	func_len " $cmds"
+	len=$func_len_result
+	if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+	  cmds=$old_archive_cmds
+	elif test -n "$archiver_list_spec"; then
+	  func_verbose "using command file archive linking..."
+	  for obj in $oldobjs
+	  do
+	    func_to_tool_file "$obj"
+	    $ECHO "$func_to_tool_file_result"
+	  done > $output_objdir/$libname.libcmd
+	  func_to_tool_file "$output_objdir/$libname.libcmd"
+	  oldobjs=" $archiver_list_spec$func_to_tool_file_result"
+	  cmds=$old_archive_cmds
+	else
+	  # the command line is too long to link in one step, link in parts
+	  func_verbose "using piecewise archive linking..."
+	  save_RANLIB=$RANLIB
+	  RANLIB=:
+	  objlist=
+	  concat_cmds=
+	  save_oldobjs=$oldobjs
+	  oldobjs=
+	  # Is there a better way of finding the last object in the list?
+	  for obj in $save_oldobjs
+	  do
+	    last_oldobj=$obj
+	  done
+	  eval test_cmds=\"$old_archive_cmds\"
+	  func_len " $test_cmds"
+	  len0=$func_len_result
+	  len=$len0
+	  for obj in $save_oldobjs
+	  do
+	    func_len " $obj"
+	    func_arith $len + $func_len_result
+	    len=$func_arith_result
+	    func_append objlist " $obj"
+	    if test "$len" -lt "$max_cmd_len"; then
+	      :
+	    else
+	      # the above command should be used before it gets too long
+	      oldobjs=$objlist
+	      if test "$obj" = "$last_oldobj"; then
+		RANLIB=$save_RANLIB
+	      fi
+	      test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+	      eval concat_cmds=\"\$concat_cmds$old_archive_cmds\"
+	      objlist=
+	      len=$len0
+	    fi
+	  done
+	  RANLIB=$save_RANLIB
+	  oldobjs=$objlist
+	  if test -z "$oldobjs"; then
+	    eval cmds=\"\$concat_cmds\"
+	  else
+	    eval cmds=\"\$concat_cmds~\$old_archive_cmds\"
+	  fi
+	fi
+      fi
+      func_execute_cmds "$cmds" 'exit $?'
+    done
+
+    test -n "$generated" && \
+      func_show_eval "${RM}r$generated"
+
+    # Now create the libtool archive.
+    case $output in
+    *.la)
+      old_library=
+      test yes = "$build_old_libs" && old_library=$libname.$libext
+      func_verbose "creating $output"
+
+      # Preserve any variables that may affect compiler behavior
+      for var in $variables_saved_for_relink; do
+	if eval test -z \"\${$var+set}\"; then
+	  relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command"
+	elif eval var_value=\$$var; test -z "$var_value"; then
+	  relink_command="$var=; export $var; $relink_command"
+	else
+	  func_quote_for_eval "$var_value"
+	  relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
+	fi
+      done
+      # Quote the link command for shipping.
+      relink_command="(cd `pwd`; $SHELL \"$progpath\" $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)"
+      relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"`
+      if test yes = "$hardcode_automatic"; then
+	relink_command=
+      fi
+
+      # Only create the output if not a dry run.
+      $opt_dry_run || {
+	for installed in no yes; do
+	  if test yes = "$installed"; then
+	    if test -z "$install_libdir"; then
+	      break
+	    fi
+	    output=$output_objdir/${outputname}i
+	    # Replace all uninstalled libtool libraries with the installed ones
+	    newdependency_libs=
+	    for deplib in $dependency_libs; do
+	      case $deplib in
+	      *.la)
+		func_basename "$deplib"
+		name=$func_basename_result
+		func_resolve_sysroot "$deplib"
+		eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result`
+		test -z "$libdir" && \
+		  func_fatal_error "'$deplib' is not a valid libtool archive"
+		func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name"
+		;;
+	      -L*)
+		func_stripname -L '' "$deplib"
+		func_replace_sysroot "$func_stripname_result"
+		func_append newdependency_libs " -L$func_replace_sysroot_result"
+		;;
+	      -R*)
+		func_stripname -R '' "$deplib"
+		func_replace_sysroot "$func_stripname_result"
+		func_append newdependency_libs " -R$func_replace_sysroot_result"
+		;;
+	      *) func_append newdependency_libs " $deplib" ;;
+	      esac
+	    done
+	    dependency_libs=$newdependency_libs
+	    newdlfiles=
+
+	    for lib in $dlfiles; do
+	      case $lib in
+	      *.la)
+	        func_basename "$lib"
+		name=$func_basename_result
+		eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+		test -z "$libdir" && \
+		  func_fatal_error "'$lib' is not a valid libtool archive"
+		func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name"
+		;;
+	      *) func_append newdlfiles " $lib" ;;
+	      esac
+	    done
+	    dlfiles=$newdlfiles
+	    newdlprefiles=
+	    for lib in $dlprefiles; do
+	      case $lib in
+	      *.la)
+		# Only pass preopened files to the pseudo-archive (for
+		# eventual linking with the app. that links it) if we
+		# didn't already link the preopened objects directly into
+		# the library:
+		func_basename "$lib"
+		name=$func_basename_result
+		eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+		test -z "$libdir" && \
+		  func_fatal_error "'$lib' is not a valid libtool archive"
+		func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name"
+		;;
+	      esac
+	    done
+	    dlprefiles=$newdlprefiles
+	  else
+	    newdlfiles=
+	    for lib in $dlfiles; do
+	      case $lib in
+		[\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;;
+		*) abs=`pwd`"/$lib" ;;
+	      esac
+	      func_append newdlfiles " $abs"
+	    done
+	    dlfiles=$newdlfiles
+	    newdlprefiles=
+	    for lib in $dlprefiles; do
+	      case $lib in
+		[\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;;
+		*) abs=`pwd`"/$lib" ;;
+	      esac
+	      func_append newdlprefiles " $abs"
+	    done
+	    dlprefiles=$newdlprefiles
+	  fi
+	  $RM $output
+	  # place dlname in correct position for cygwin
+	  # In fact, it would be nice if we could use this code for all target
+	  # systems that can't hard-code library paths into their executables
+	  # and that have no shared library path variable independent of PATH,
+	  # but it turns out we can't easily determine that from inspecting
+	  # libtool variables, so we have to hard-code the OSs to which it
+	  # applies here; at the moment, that means platforms that use the PE
+	  # object format with DLL files.  See the long comment at the top of
+	  # tests/bindir.at for full details.
+	  tdlname=$dlname
+	  case $host,$output,$installed,$module,$dlname in
+	    *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll)
+	      # If a -bindir argument was supplied, place the dll there.
+	      if test -n "$bindir"; then
+		func_relative_path "$install_libdir" "$bindir"
+		tdlname=$func_relative_path_result/$dlname
+	      else
+		# Otherwise fall back on heuristic.
+		tdlname=../bin/$dlname
+	      fi
+	      ;;
+	  esac
+	  $ECHO > $output "\
+# $outputname - a libtool library file
+# Generated by $PROGRAM (GNU $PACKAGE) $VERSION
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# The name that we can dlopen(3).
+dlname='$tdlname'
+
+# Names of this library.
+library_names='$library_names'
+
+# The name of the static archive.
+old_library='$old_library'
+
+# Linker flags that cannot go in dependency_libs.
+inherited_linker_flags='$new_inherited_linker_flags'
+
+# Libraries that this one depends upon.
+dependency_libs='$dependency_libs'
+
+# Names of additional weak libraries provided by this library
+weak_library_names='$weak_libs'
+
+# Version information for $libname.
+current=$current
+age=$age
+revision=$revision
+
+# Is this an already installed library?
+installed=$installed
+
+# Should we warn about portability when linking against -modules?
+shouldnotlink=$module
+
+# Files to dlopen/dlpreopen
+dlopen='$dlfiles'
+dlpreopen='$dlprefiles'
+
+# Directory that this library needs to be installed in:
+libdir='$install_libdir'"
+	  if test no,yes = "$installed,$need_relink"; then
+	    $ECHO >> $output "\
+relink_command=\"$relink_command\""
+	  fi
+	done
+      }
+
+      # Do a symbolic link so that the libtool archive can be found in
+      # LD_LIBRARY_PATH before the program is installed.
+      func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?'
+      ;;
+    esac
+    exit $EXIT_SUCCESS
+}
+
+if test link = "$opt_mode" || test relink = "$opt_mode"; then
+  func_mode_link ${1+"$@"}
+fi
+
+
+# func_mode_uninstall arg...
+func_mode_uninstall ()
+{
+    $debug_cmd
+
+    RM=$nonopt
+    files=
+    rmforce=false
+    exit_status=0
+
+    # This variable tells wrapper scripts just to set variables rather
+    # than running their programs.
+    libtool_install_magic=$magic
+
+    for arg
+    do
+      case $arg in
+      -f) func_append RM " $arg"; rmforce=: ;;
+      -*) func_append RM " $arg" ;;
+      *) func_append files " $arg" ;;
+      esac
+    done
+
+    test -z "$RM" && \
+      func_fatal_help "you must specify an RM program"
+
+    rmdirs=
+
+    for file in $files; do
+      func_dirname "$file" "" "."
+      dir=$func_dirname_result
+      if test . = "$dir"; then
+	odir=$objdir
+      else
+	odir=$dir/$objdir
+      fi
+      func_basename "$file"
+      name=$func_basename_result
+      test uninstall = "$opt_mode" && odir=$dir
+
+      # Remember odir for removal later, being careful to avoid duplicates
+      if test clean = "$opt_mode"; then
+	case " $rmdirs " in
+	  *" $odir "*) ;;
+	  *) func_append rmdirs " $odir" ;;
+	esac
+      fi
+
+      # Don't error if the file doesn't exist and rm -f was used.
+      if { test -L "$file"; } >/dev/null 2>&1 ||
+	 { test -h "$file"; } >/dev/null 2>&1 ||
+	 test -f "$file"; then
+	:
+      elif test -d "$file"; then
+	exit_status=1
+	continue
+      elif $rmforce; then
+	continue
+      fi
+
+      rmfiles=$file
+
+      case $name in
+      *.la)
+	# Possibly a libtool archive, so verify it.
+	if func_lalib_p "$file"; then
+	  func_source $dir/$name
+
+	  # Delete the libtool libraries and symlinks.
+	  for n in $library_names; do
+	    func_append rmfiles " $odir/$n"
+	  done
+	  test -n "$old_library" && func_append rmfiles " $odir/$old_library"
+
+	  case $opt_mode in
+	  clean)
+	    case " $library_names " in
+	    *" $dlname "*) ;;
+	    *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;;
+	    esac
+	    test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i"
+	    ;;
+	  uninstall)
+	    if test -n "$library_names"; then
+	      # Do each command in the postuninstall commands.
+	      func_execute_cmds "$postuninstall_cmds" '$rmforce || exit_status=1'
+	    fi
+
+	    if test -n "$old_library"; then
+	      # Do each command in the old_postuninstall commands.
+	      func_execute_cmds "$old_postuninstall_cmds" '$rmforce || exit_status=1'
+	    fi
+	    # FIXME: should reinstall the best remaining shared library.
+	    ;;
+	  esac
+	fi
+	;;
+
+      *.lo)
+	# Possibly a libtool object, so verify it.
+	if func_lalib_p "$file"; then
+
+	  # Read the .lo file
+	  func_source $dir/$name
+
+	  # Add PIC object to the list of files to remove.
+	  if test -n "$pic_object" && test none != "$pic_object"; then
+	    func_append rmfiles " $dir/$pic_object"
+	  fi
+
+	  # Add non-PIC object to the list of files to remove.
+	  if test -n "$non_pic_object" && test none != "$non_pic_object"; then
+	    func_append rmfiles " $dir/$non_pic_object"
+	  fi
+	fi
+	;;
+
+      *)
+	if test clean = "$opt_mode"; then
+	  noexename=$name
+	  case $file in
+	  *.exe)
+	    func_stripname '' '.exe' "$file"
+	    file=$func_stripname_result
+	    func_stripname '' '.exe' "$name"
+	    noexename=$func_stripname_result
+	    # $file with .exe has already been added to rmfiles,
+	    # add $file without .exe
+	    func_append rmfiles " $file"
+	    ;;
+	  esac
+	  # Do a test to see if this is a libtool program.
+	  if func_ltwrapper_p "$file"; then
+	    if func_ltwrapper_executable_p "$file"; then
+	      func_ltwrapper_scriptname "$file"
+	      relink_command=
+	      func_source $func_ltwrapper_scriptname_result
+	      func_append rmfiles " $func_ltwrapper_scriptname_result"
+	    else
+	      relink_command=
+	      func_source $dir/$noexename
+	    fi
+
+	    # note $name still contains .exe if it was in $file originally
+	    # as does the version of $file that was added into $rmfiles
+	    func_append rmfiles " $odir/$name $odir/${name}S.$objext"
+	    if test yes = "$fast_install" && test -n "$relink_command"; then
+	      func_append rmfiles " $odir/lt-$name"
+	    fi
+	    if test "X$noexename" != "X$name"; then
+	      func_append rmfiles " $odir/lt-$noexename.c"
+	    fi
+	  fi
+	fi
+	;;
+      esac
+      func_show_eval "$RM $rmfiles" 'exit_status=1'
+    done
+
+    # Try to remove the $objdir's in the directories where we deleted files
+    for dir in $rmdirs; do
+      if test -d "$dir"; then
+	func_show_eval "rmdir $dir >/dev/null 2>&1"
+      fi
+    done
+
+    exit $exit_status
+}
+
+if test uninstall = "$opt_mode" || test clean = "$opt_mode"; then
+  func_mode_uninstall ${1+"$@"}
+fi
+
+test -z "$opt_mode" && {
+  help=$generic_help
+  func_fatal_help "you must specify a MODE"
+}
+
+test -z "$exec_cmd" && \
+  func_fatal_help "invalid operation mode '$opt_mode'"
+
+if test -n "$exec_cmd"; then
+  eval exec "$exec_cmd"
+  exit $EXIT_FAILURE
+fi
+
+exit $exit_status
+
+
+# The TAGs below are defined such that we never get into a situation
+# where we disable both kinds of libraries.  Given conflicting
+# choices, we go for a static library, that is the most portable,
+# since we can't tell whether shared libraries were disabled because
+# the user asked for that or because the platform doesn't support
+# them.  This is particularly important on AIX, because we don't
+# support having both static and shared libraries enabled at the same
+# time on that platform, so we default to a shared-only configuration.
+# If a disable-shared tag is given, we'll fallback to a static-only
+# configuration.  But we'll never go from static-only to shared-only.
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-shared
+build_libtool_libs=no
+build_old_libs=yes
+# ### END LIBTOOL TAG CONFIG: disable-shared
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-static
+build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac`
+# ### END LIBTOOL TAG CONFIG: disable-static
+
+# Local Variables:
+# mode:shell-script
+# sh-indentation:2
+# End:
diff --git a/third_party/gmp/memory.c b/third_party/gmp/memory.c
new file mode 100644
index 0000000..5e00191
--- /dev/null
+++ b/third_party/gmp/memory.c
@@ -0,0 +1,145 @@
+/* Memory allocation routines.
+
+Copyright 1991, 1993, 1994, 2000-2002, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h> /* for malloc, realloc, free */
+
+#include "gmp-impl.h"
+
+
+void * (*__gmp_allocate_func) (size_t) = __gmp_default_allocate;
+void * (*__gmp_reallocate_func) (void *, size_t, size_t) = __gmp_default_reallocate;
+void   (*__gmp_free_func) (void *, size_t) = __gmp_default_free;
+
+
+/* Default allocation functions.  In case of failure to allocate/reallocate
+   an error message is written to stderr and the program aborts.  */
+
+void *
+__gmp_default_allocate (size_t size)
+{
+  void *ret;
+#ifdef DEBUG
+  size_t req_size = size;
+  size += 2 * GMP_LIMB_BYTES;
+#endif
+  ret = malloc (size);
+  if (ret == 0)
+    {
+      fprintf (stderr, "GNU MP: Cannot allocate memory (size=%lu)\n", (long) size);
+      abort ();
+    }
+
+#ifdef DEBUG
+  {
+    mp_ptr p = ret;
+    p++;
+    p[-1] = (0xdeadbeef << 31) + 0xdeafdeed;
+    if (req_size % GMP_LIMB_BYTES == 0)
+      p[req_size / GMP_LIMB_BYTES] = ~((0xdeadbeef << 31) + 0xdeafdeed);
+    ret = p;
+  }
+#endif
+  return ret;
+}
+
+void *
+__gmp_default_reallocate (void *oldptr, size_t old_size, size_t new_size)
+{
+  void *ret;
+
+#ifdef DEBUG
+  size_t req_size = new_size;
+
+  if (old_size != 0)
+    {
+      mp_ptr p = oldptr;
+      if (p[-1] != (0xdeadbeef << 31) + 0xdeafdeed)
+	{
+	  fprintf (stderr, "gmp: (realloc) data clobbered before allocation block\n");
+	  abort ();
+	}
+      if (old_size % GMP_LIMB_BYTES == 0)
+	if (p[old_size / GMP_LIMB_BYTES] != ~((0xdeadbeef << 31) + 0xdeafdeed))
+	  {
+	    fprintf (stderr, "gmp: (realloc) data clobbered after allocation block\n");
+	    abort ();
+	  }
+      oldptr = p - 1;
+    }
+
+  new_size += 2 * GMP_LIMB_BYTES;
+#endif
+
+  ret = realloc (oldptr, new_size);
+  if (ret == 0)
+    {
+      fprintf (stderr, "GNU MP: Cannot reallocate memory (old_size=%lu new_size=%lu)\n", (long) old_size, (long) new_size);
+      abort ();
+    }
+
+#ifdef DEBUG
+  {
+    mp_ptr p = ret;
+    p++;
+    p[-1] = (0xdeadbeef << 31) + 0xdeafdeed;
+    if (req_size % GMP_LIMB_BYTES == 0)
+      p[req_size / GMP_LIMB_BYTES] = ~((0xdeadbeef << 31) + 0xdeafdeed);
+    ret = p;
+  }
+#endif
+  return ret;
+}
+
+void
+__gmp_default_free (void *blk_ptr, size_t blk_size)
+{
+#ifdef DEBUG
+  {
+    mp_ptr p = blk_ptr;
+    if (blk_size != 0)
+      {
+	if (p[-1] != (0xdeadbeef << 31) + 0xdeafdeed)
+	  {
+	    fprintf (stderr, "gmp: (free) data clobbered before allocation block\n");
+	    abort ();
+	  }
+	if (blk_size % GMP_LIMB_BYTES == 0)
+	  if (p[blk_size / GMP_LIMB_BYTES] != ~((0xdeadbeef << 31) + 0xdeafdeed))
+	    {
+	      fprintf (stderr, "gmp: (free) data clobbered after allocation block\n");
+	      abort ();
+	    }
+      }
+    blk_ptr = p - 1;
+  }
+#endif
+  free (blk_ptr);
+}
diff --git a/third_party/gmp/mini-gmp/README b/third_party/gmp/mini-gmp/README
new file mode 100644
index 0000000..b02b8da
--- /dev/null
+++ b/third_party/gmp/mini-gmp/README
@@ -0,0 +1,79 @@
+Copyright 2011-2013, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.
+
+
+This is "mini-gmp", a small implementation of a subset of GMP's mpn,
+mpz and mpq interfaces.
+
+It is intended for applications which need arithmetic on numbers
+larger than a machine word, but which don't need to handle very large
+numbers very efficiently. Those applications can include a copy of
+mini-gmp to get a GMP-compatible interface with small footprint. One
+can also arrange for optional linking with the real GMP library, using
+mini-gmp as a fallback when for some reason GMP is not available, or
+not desired as a dependency.
+
+The supported GMP subset of the mpn and mpz interfaces is declared in
+mini-gmp.h, and implemented in mini-gmp.c. The implemented
+functions are fully compatible with the corresponding GMP functions,
+as specified in the GMP manual, with a few exceptions:
+
+  mpz_export and mpz_import support only NAILS = 0.
+
+  The REALLOC_FUNC and FREE_FUNC registered with
+  mp_set_memory_functions does not get the correct size of the
+  allocated block in the corresponding argument. mini-gmp always
+  passes zero for these rarely used arguments.
+
+  When mpz_get_str allocates the block, it can be longer than needed.
+
+The performance target for mini-gmp is to be at most 10 times slower
+than the real GMP library, for numbers of size up to a few hundred
+bits. No asymptotically fast algorithms are included in mini-gmp, so
+it will be many orders of magnitude slower than GMP for very large
+numbers.
+
+The supported GMP subset of the mpq layer is declared in mini-mpq.h,
+and implemented in mini-mpq.c.
+
+You should never "install" mini-gmp. Applications can either just
+#include mini-gmp.c (but then, beware that it defines several macros
+and functions outside of the advertised interface), and if needed
+#include mini-mpq.c in a later line (order is important). Or compile
+mini-gmp.c and mini-mpq.c as separate compilation units, and use the
+declarations in mini-gmp.h and mini-mpq.h.
+
+The tests subdirectory contains a testsuite. To use it, you need GMP
+and GNU make. Just run make check in the tests directory. If the
+hard-coded compiler settings are not right, you have to either edit the
+Makefile or pass overriding values on the make command line (e.g.,
+make CC=cc check).
+
+The initial version of mini-gmp was put together by Niels Möller
+<nisse@lysator.liu.se>, with a fair amount of copy-and-paste from the
+GMP sources.
diff --git a/third_party/gmp/mini-gmp/mini-gmp.c b/third_party/gmp/mini-gmp/mini-gmp.c
new file mode 100644
index 0000000..78cd103
--- /dev/null
+++ b/third_party/gmp/mini-gmp/mini-gmp.c
@@ -0,0 +1,4571 @@
+/* mini-gmp, a minimalistic implementation of a GNU GMP subset.
+
+   Contributed to the GNU project by Niels Möller
+
+Copyright 1991-1997, 1999-2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+/* NOTE: All functions in this file which are not declared in
+   mini-gmp.h are internal, and are not intended to be compatible
+   neither with GMP nor with future versions of mini-gmp. */
+
+/* Much of the material copied from GMP files, including: gmp-impl.h,
+   longlong.h, mpn/generic/add_n.c, mpn/generic/addmul_1.c,
+   mpn/generic/lshift.c, mpn/generic/mul_1.c,
+   mpn/generic/mul_basecase.c, mpn/generic/rshift.c,
+   mpn/generic/sbpi1_div_qr.c, mpn/generic/sub_n.c,
+   mpn/generic/submul_1.c. */
+
+#include <assert.h>
+#include <ctype.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "mini-gmp.h"
+
+#if !defined(MINI_GMP_DONT_USE_FLOAT_H)
+#include <float.h>
+#endif
+
+
+/* Macros */
+#define GMP_LIMB_BITS (sizeof(mp_limb_t) * CHAR_BIT)
+
+#define GMP_LIMB_MAX ((mp_limb_t) ~ (mp_limb_t) 0)
+#define GMP_LIMB_HIGHBIT ((mp_limb_t) 1 << (GMP_LIMB_BITS - 1))
+
+#define GMP_HLIMB_BIT ((mp_limb_t) 1 << (GMP_LIMB_BITS / 2))
+#define GMP_LLIMB_MASK (GMP_HLIMB_BIT - 1)
+
+#define GMP_ULONG_BITS (sizeof(unsigned long) * CHAR_BIT)
+#define GMP_ULONG_HIGHBIT ((unsigned long) 1 << (GMP_ULONG_BITS - 1))
+
+#define GMP_ABS(x) ((x) >= 0 ? (x) : -(x))
+#define GMP_NEG_CAST(T,x) (-((T)((x) + 1) - 1))
+
+#define GMP_MIN(a, b) ((a) < (b) ? (a) : (b))
+#define GMP_MAX(a, b) ((a) > (b) ? (a) : (b))
+
+#define GMP_CMP(a,b) (((a) > (b)) - ((a) < (b)))
+
+#if defined(DBL_MANT_DIG) && FLT_RADIX == 2
+#define GMP_DBL_MANT_BITS DBL_MANT_DIG
+#else
+#define GMP_DBL_MANT_BITS (53)
+#endif
+
+/* Return non-zero if xp,xsize and yp,ysize overlap.
+   If xp+xsize<=yp there's no overlap, or if yp+ysize<=xp there's no
+   overlap.  If both these are false, there's an overlap. */
+#define GMP_MPN_OVERLAP_P(xp, xsize, yp, ysize)				\
+  ((xp) + (xsize) > (yp) && (yp) + (ysize) > (xp))
+
+#define gmp_assert_nocarry(x) do { \
+    mp_limb_t __cy = (x);	   \
+    assert (__cy == 0);		   \
+  } while (0)
+
+#define gmp_clz(count, x) do {						\
+    mp_limb_t __clz_x = (x);						\
+    unsigned __clz_c = 0;						\
+    int LOCAL_SHIFT_BITS = 8;						\
+    if (GMP_LIMB_BITS > LOCAL_SHIFT_BITS)				\
+      for (;								\
+	   (__clz_x & ((mp_limb_t) 0xff << (GMP_LIMB_BITS - 8))) == 0;	\
+	   __clz_c += 8)						\
+	{ __clz_x <<= LOCAL_SHIFT_BITS;	}				\
+    for (; (__clz_x & GMP_LIMB_HIGHBIT) == 0; __clz_c++)		\
+      __clz_x <<= 1;							\
+    (count) = __clz_c;							\
+  } while (0)
+
+#define gmp_ctz(count, x) do {						\
+    mp_limb_t __ctz_x = (x);						\
+    unsigned __ctz_c = 0;						\
+    gmp_clz (__ctz_c, __ctz_x & - __ctz_x);				\
+    (count) = GMP_LIMB_BITS - 1 - __ctz_c;				\
+  } while (0)
+
+#define gmp_add_ssaaaa(sh, sl, ah, al, bh, bl) \
+  do {									\
+    mp_limb_t __x;							\
+    __x = (al) + (bl);							\
+    (sh) = (ah) + (bh) + (__x < (al));					\
+    (sl) = __x;								\
+  } while (0)
+
+#define gmp_sub_ddmmss(sh, sl, ah, al, bh, bl) \
+  do {									\
+    mp_limb_t __x;							\
+    __x = (al) - (bl);							\
+    (sh) = (ah) - (bh) - ((al) < (bl));					\
+    (sl) = __x;								\
+  } while (0)
+
+#define gmp_umul_ppmm(w1, w0, u, v)					\
+  do {									\
+    int LOCAL_GMP_LIMB_BITS = GMP_LIMB_BITS;				\
+    if (sizeof(unsigned int) * CHAR_BIT >= 2 * GMP_LIMB_BITS)		\
+      {									\
+	unsigned int __ww = (unsigned int) (u) * (v);			\
+	w0 = (mp_limb_t) __ww;						\
+	w1 = (mp_limb_t) (__ww >> LOCAL_GMP_LIMB_BITS);			\
+      }									\
+    else if (GMP_ULONG_BITS >= 2 * GMP_LIMB_BITS)			\
+      {									\
+	unsigned long int __ww = (unsigned long int) (u) * (v);		\
+	w0 = (mp_limb_t) __ww;						\
+	w1 = (mp_limb_t) (__ww >> LOCAL_GMP_LIMB_BITS);			\
+      }									\
+    else {								\
+      mp_limb_t __x0, __x1, __x2, __x3;					\
+      unsigned __ul, __vl, __uh, __vh;					\
+      mp_limb_t __u = (u), __v = (v);					\
+									\
+      __ul = __u & GMP_LLIMB_MASK;					\
+      __uh = __u >> (GMP_LIMB_BITS / 2);				\
+      __vl = __v & GMP_LLIMB_MASK;					\
+      __vh = __v >> (GMP_LIMB_BITS / 2);				\
+									\
+      __x0 = (mp_limb_t) __ul * __vl;					\
+      __x1 = (mp_limb_t) __ul * __vh;					\
+      __x2 = (mp_limb_t) __uh * __vl;					\
+      __x3 = (mp_limb_t) __uh * __vh;					\
+									\
+      __x1 += __x0 >> (GMP_LIMB_BITS / 2);/* this can't give carry */	\
+      __x1 += __x2;		/* but this indeed can */		\
+      if (__x1 < __x2)		/* did we get it? */			\
+	__x3 += GMP_HLIMB_BIT;	/* yes, add it in the proper pos. */	\
+									\
+      (w1) = __x3 + (__x1 >> (GMP_LIMB_BITS / 2));			\
+      (w0) = (__x1 << (GMP_LIMB_BITS / 2)) + (__x0 & GMP_LLIMB_MASK);	\
+    }									\
+  } while (0)
+
+#define gmp_udiv_qrnnd_preinv(q, r, nh, nl, d, di)			\
+  do {									\
+    mp_limb_t _qh, _ql, _r, _mask;					\
+    gmp_umul_ppmm (_qh, _ql, (nh), (di));				\
+    gmp_add_ssaaaa (_qh, _ql, _qh, _ql, (nh) + 1, (nl));		\
+    _r = (nl) - _qh * (d);						\
+    _mask = -(mp_limb_t) (_r > _ql); /* both > and >= are OK */		\
+    _qh += _mask;							\
+    _r += _mask & (d);							\
+    if (_r >= (d))							\
+      {									\
+	_r -= (d);							\
+	_qh++;								\
+      }									\
+									\
+    (r) = _r;								\
+    (q) = _qh;								\
+  } while (0)
+
+#define gmp_udiv_qr_3by2(q, r1, r0, n2, n1, n0, d1, d0, dinv)		\
+  do {									\
+    mp_limb_t _q0, _t1, _t0, _mask;					\
+    gmp_umul_ppmm ((q), _q0, (n2), (dinv));				\
+    gmp_add_ssaaaa ((q), _q0, (q), _q0, (n2), (n1));			\
+									\
+    /* Compute the two most significant limbs of n - q'd */		\
+    (r1) = (n1) - (d1) * (q);						\
+    gmp_sub_ddmmss ((r1), (r0), (r1), (n0), (d1), (d0));		\
+    gmp_umul_ppmm (_t1, _t0, (d0), (q));				\
+    gmp_sub_ddmmss ((r1), (r0), (r1), (r0), _t1, _t0);			\
+    (q)++;								\
+									\
+    /* Conditionally adjust q and the remainders */			\
+    _mask = - (mp_limb_t) ((r1) >= _q0);				\
+    (q) += _mask;							\
+    gmp_add_ssaaaa ((r1), (r0), (r1), (r0), _mask & (d1), _mask & (d0)); \
+    if ((r1) >= (d1))							\
+      {									\
+	if ((r1) > (d1) || (r0) >= (d0))				\
+	  {								\
+	    (q)++;							\
+	    gmp_sub_ddmmss ((r1), (r0), (r1), (r0), (d1), (d0));	\
+	  }								\
+      }									\
+  } while (0)
+
+/* Swap macros. */
+#define MP_LIMB_T_SWAP(x, y)						\
+  do {									\
+    mp_limb_t __mp_limb_t_swap__tmp = (x);				\
+    (x) = (y);								\
+    (y) = __mp_limb_t_swap__tmp;					\
+  } while (0)
+#define MP_SIZE_T_SWAP(x, y)						\
+  do {									\
+    mp_size_t __mp_size_t_swap__tmp = (x);				\
+    (x) = (y);								\
+    (y) = __mp_size_t_swap__tmp;					\
+  } while (0)
+#define MP_BITCNT_T_SWAP(x,y)			\
+  do {						\
+    mp_bitcnt_t __mp_bitcnt_t_swap__tmp = (x);	\
+    (x) = (y);					\
+    (y) = __mp_bitcnt_t_swap__tmp;		\
+  } while (0)
+#define MP_PTR_SWAP(x, y)						\
+  do {									\
+    mp_ptr __mp_ptr_swap__tmp = (x);					\
+    (x) = (y);								\
+    (y) = __mp_ptr_swap__tmp;						\
+  } while (0)
+#define MP_SRCPTR_SWAP(x, y)						\
+  do {									\
+    mp_srcptr __mp_srcptr_swap__tmp = (x);				\
+    (x) = (y);								\
+    (y) = __mp_srcptr_swap__tmp;					\
+  } while (0)
+
+#define MPN_PTR_SWAP(xp,xs, yp,ys)					\
+  do {									\
+    MP_PTR_SWAP (xp, yp);						\
+    MP_SIZE_T_SWAP (xs, ys);						\
+  } while(0)
+#define MPN_SRCPTR_SWAP(xp,xs, yp,ys)					\
+  do {									\
+    MP_SRCPTR_SWAP (xp, yp);						\
+    MP_SIZE_T_SWAP (xs, ys);						\
+  } while(0)
+
+#define MPZ_PTR_SWAP(x, y)						\
+  do {									\
+    mpz_ptr __mpz_ptr_swap__tmp = (x);					\
+    (x) = (y);								\
+    (y) = __mpz_ptr_swap__tmp;						\
+  } while (0)
+#define MPZ_SRCPTR_SWAP(x, y)						\
+  do {									\
+    mpz_srcptr __mpz_srcptr_swap__tmp = (x);				\
+    (x) = (y);								\
+    (y) = __mpz_srcptr_swap__tmp;					\
+  } while (0)
+
+const int mp_bits_per_limb = GMP_LIMB_BITS;
+
+
+/* Memory allocation and other helper functions. */
+static void
+gmp_die (const char *msg)
+{
+  fprintf (stderr, "%s\n", msg);
+  abort();
+}
+
+static void *
+gmp_default_alloc (size_t size)
+{
+  void *p;
+
+  assert (size > 0);
+
+  p = malloc (size);
+  if (!p)
+    gmp_die("gmp_default_alloc: Virtual memory exhausted.");
+
+  return p;
+}
+
+static void *
+gmp_default_realloc (void *old, size_t unused_old_size, size_t new_size)
+{
+  void * p;
+
+  p = realloc (old, new_size);
+
+  if (!p)
+    gmp_die("gmp_default_realloc: Virtual memory exhausted.");
+
+  return p;
+}
+
+static void
+gmp_default_free (void *p, size_t unused_size)
+{
+  free (p);
+}
+
+static void * (*gmp_allocate_func) (size_t) = gmp_default_alloc;
+static void * (*gmp_reallocate_func) (void *, size_t, size_t) = gmp_default_realloc;
+static void (*gmp_free_func) (void *, size_t) = gmp_default_free;
+
+void
+mp_get_memory_functions (void *(**alloc_func) (size_t),
+			 void *(**realloc_func) (void *, size_t, size_t),
+			 void (**free_func) (void *, size_t))
+{
+  if (alloc_func)
+    *alloc_func = gmp_allocate_func;
+
+  if (realloc_func)
+    *realloc_func = gmp_reallocate_func;
+
+  if (free_func)
+    *free_func = gmp_free_func;
+}
+
+void
+mp_set_memory_functions (void *(*alloc_func) (size_t),
+			 void *(*realloc_func) (void *, size_t, size_t),
+			 void (*free_func) (void *, size_t))
+{
+  if (!alloc_func)
+    alloc_func = gmp_default_alloc;
+  if (!realloc_func)
+    realloc_func = gmp_default_realloc;
+  if (!free_func)
+    free_func = gmp_default_free;
+
+  gmp_allocate_func = alloc_func;
+  gmp_reallocate_func = realloc_func;
+  gmp_free_func = free_func;
+}
+
+#define gmp_xalloc(size) ((*gmp_allocate_func)((size)))
+#define gmp_free(p) ((*gmp_free_func) ((p), 0))
+
+static mp_ptr
+gmp_xalloc_limbs (mp_size_t size)
+{
+  return (mp_ptr) gmp_xalloc (size * sizeof (mp_limb_t));
+}
+
+static mp_ptr
+gmp_xrealloc_limbs (mp_ptr old, mp_size_t size)
+{
+  assert (size > 0);
+  return (mp_ptr) (*gmp_reallocate_func) (old, 0, size * sizeof (mp_limb_t));
+}
+
+
+/* MPN interface */
+
+void
+mpn_copyi (mp_ptr d, mp_srcptr s, mp_size_t n)
+{
+  mp_size_t i;
+  for (i = 0; i < n; i++)
+    d[i] = s[i];
+}
+
+void
+mpn_copyd (mp_ptr d, mp_srcptr s, mp_size_t n)
+{
+  while (--n >= 0)
+    d[n] = s[n];
+}
+
+int
+mpn_cmp (mp_srcptr ap, mp_srcptr bp, mp_size_t n)
+{
+  while (--n >= 0)
+    {
+      if (ap[n] != bp[n])
+	return ap[n] > bp[n] ? 1 : -1;
+    }
+  return 0;
+}
+
+static int
+mpn_cmp4 (mp_srcptr ap, mp_size_t an, mp_srcptr bp, mp_size_t bn)
+{
+  if (an != bn)
+    return an < bn ? -1 : 1;
+  else
+    return mpn_cmp (ap, bp, an);
+}
+
+static mp_size_t
+mpn_normalized_size (mp_srcptr xp, mp_size_t n)
+{
+  while (n > 0 && xp[n-1] == 0)
+    --n;
+  return n;
+}
+
+int
+mpn_zero_p(mp_srcptr rp, mp_size_t n)
+{
+  return mpn_normalized_size (rp, n) == 0;
+}
+
+void
+mpn_zero (mp_ptr rp, mp_size_t n)
+{
+  while (--n >= 0)
+    rp[n] = 0;
+}
+
+mp_limb_t
+mpn_add_1 (mp_ptr rp, mp_srcptr ap, mp_size_t n, mp_limb_t b)
+{
+  mp_size_t i;
+
+  assert (n > 0);
+  i = 0;
+  do
+    {
+      mp_limb_t r = ap[i] + b;
+      /* Carry out */
+      b = (r < b);
+      rp[i] = r;
+    }
+  while (++i < n);
+
+  return b;
+}
+
+mp_limb_t
+mpn_add_n (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n)
+{
+  mp_size_t i;
+  mp_limb_t cy;
+
+  for (i = 0, cy = 0; i < n; i++)
+    {
+      mp_limb_t a, b, r;
+      a = ap[i]; b = bp[i];
+      r = a + cy;
+      cy = (r < cy);
+      r += b;
+      cy += (r < b);
+      rp[i] = r;
+    }
+  return cy;
+}
+
+mp_limb_t
+mpn_add (mp_ptr rp, mp_srcptr ap, mp_size_t an, mp_srcptr bp, mp_size_t bn)
+{
+  mp_limb_t cy;
+
+  assert (an >= bn);
+
+  cy = mpn_add_n (rp, ap, bp, bn);
+  if (an > bn)
+    cy = mpn_add_1 (rp + bn, ap + bn, an - bn, cy);
+  return cy;
+}
+
+mp_limb_t
+mpn_sub_1 (mp_ptr rp, mp_srcptr ap, mp_size_t n, mp_limb_t b)
+{
+  mp_size_t i;
+
+  assert (n > 0);
+
+  i = 0;
+  do
+    {
+      mp_limb_t a = ap[i];
+      /* Carry out */
+      mp_limb_t cy = a < b;
+      rp[i] = a - b;
+      b = cy;
+    }
+  while (++i < n);
+
+  return b;
+}
+
+mp_limb_t
+mpn_sub_n (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n)
+{
+  mp_size_t i;
+  mp_limb_t cy;
+
+  for (i = 0, cy = 0; i < n; i++)
+    {
+      mp_limb_t a, b;
+      a = ap[i]; b = bp[i];
+      b += cy;
+      cy = (b < cy);
+      cy += (a < b);
+      rp[i] = a - b;
+    }
+  return cy;
+}
+
+mp_limb_t
+mpn_sub (mp_ptr rp, mp_srcptr ap, mp_size_t an, mp_srcptr bp, mp_size_t bn)
+{
+  mp_limb_t cy;
+
+  assert (an >= bn);
+
+  cy = mpn_sub_n (rp, ap, bp, bn);
+  if (an > bn)
+    cy = mpn_sub_1 (rp + bn, ap + bn, an - bn, cy);
+  return cy;
+}
+
+mp_limb_t
+mpn_mul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t vl)
+{
+  mp_limb_t ul, cl, hpl, lpl;
+
+  assert (n >= 1);
+
+  cl = 0;
+  do
+    {
+      ul = *up++;
+      gmp_umul_ppmm (hpl, lpl, ul, vl);
+
+      lpl += cl;
+      cl = (lpl < cl) + hpl;
+
+      *rp++ = lpl;
+    }
+  while (--n != 0);
+
+  return cl;
+}
+
+mp_limb_t
+mpn_addmul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t vl)
+{
+  mp_limb_t ul, cl, hpl, lpl, rl;
+
+  assert (n >= 1);
+
+  cl = 0;
+  do
+    {
+      ul = *up++;
+      gmp_umul_ppmm (hpl, lpl, ul, vl);
+
+      lpl += cl;
+      cl = (lpl < cl) + hpl;
+
+      rl = *rp;
+      lpl = rl + lpl;
+      cl += lpl < rl;
+      *rp++ = lpl;
+    }
+  while (--n != 0);
+
+  return cl;
+}
+
+mp_limb_t
+mpn_submul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t vl)
+{
+  mp_limb_t ul, cl, hpl, lpl, rl;
+
+  assert (n >= 1);
+
+  cl = 0;
+  do
+    {
+      ul = *up++;
+      gmp_umul_ppmm (hpl, lpl, ul, vl);
+
+      lpl += cl;
+      cl = (lpl < cl) + hpl;
+
+      rl = *rp;
+      lpl = rl - lpl;
+      cl += lpl > rl;
+      *rp++ = lpl;
+    }
+  while (--n != 0);
+
+  return cl;
+}
+
+mp_limb_t
+mpn_mul (mp_ptr rp, mp_srcptr up, mp_size_t un, mp_srcptr vp, mp_size_t vn)
+{
+  assert (un >= vn);
+  assert (vn >= 1);
+  assert (!GMP_MPN_OVERLAP_P(rp, un + vn, up, un));
+  assert (!GMP_MPN_OVERLAP_P(rp, un + vn, vp, vn));
+
+  /* We first multiply by the low order limb. This result can be
+     stored, not added, to rp. We also avoid a loop for zeroing this
+     way. */
+
+  rp[un] = mpn_mul_1 (rp, up, un, vp[0]);
+
+  /* Now accumulate the product of up[] and the next higher limb from
+     vp[]. */
+
+  while (--vn >= 1)
+    {
+      rp += 1, vp += 1;
+      rp[un] = mpn_addmul_1 (rp, up, un, vp[0]);
+    }
+  return rp[un];
+}
+
+void
+mpn_mul_n (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n)
+{
+  mpn_mul (rp, ap, n, bp, n);
+}
+
+void
+mpn_sqr (mp_ptr rp, mp_srcptr ap, mp_size_t n)
+{
+  mpn_mul (rp, ap, n, ap, n);
+}
+
+mp_limb_t
+mpn_lshift (mp_ptr rp, mp_srcptr up, mp_size_t n, unsigned int cnt)
+{
+  mp_limb_t high_limb, low_limb;
+  unsigned int tnc;
+  mp_limb_t retval;
+
+  assert (n >= 1);
+  assert (cnt >= 1);
+  assert (cnt < GMP_LIMB_BITS);
+
+  up += n;
+  rp += n;
+
+  tnc = GMP_LIMB_BITS - cnt;
+  low_limb = *--up;
+  retval = low_limb >> tnc;
+  high_limb = (low_limb << cnt);
+
+  while (--n != 0)
+    {
+      low_limb = *--up;
+      *--rp = high_limb | (low_limb >> tnc);
+      high_limb = (low_limb << cnt);
+    }
+  *--rp = high_limb;
+
+  return retval;
+}
+
+mp_limb_t
+mpn_rshift (mp_ptr rp, mp_srcptr up, mp_size_t n, unsigned int cnt)
+{
+  mp_limb_t high_limb, low_limb;
+  unsigned int tnc;
+  mp_limb_t retval;
+
+  assert (n >= 1);
+  assert (cnt >= 1);
+  assert (cnt < GMP_LIMB_BITS);
+
+  tnc = GMP_LIMB_BITS - cnt;
+  high_limb = *up++;
+  retval = (high_limb << tnc);
+  low_limb = high_limb >> cnt;
+
+  while (--n != 0)
+    {
+      high_limb = *up++;
+      *rp++ = low_limb | (high_limb << tnc);
+      low_limb = high_limb >> cnt;
+    }
+  *rp = low_limb;
+
+  return retval;
+}
+
+static mp_bitcnt_t
+mpn_common_scan (mp_limb_t limb, mp_size_t i, mp_srcptr up, mp_size_t un,
+		 mp_limb_t ux)
+{
+  unsigned cnt;
+
+  assert (ux == 0 || ux == GMP_LIMB_MAX);
+  assert (0 <= i && i <= un );
+
+  while (limb == 0)
+    {
+      i++;
+      if (i == un)
+	return (ux == 0 ? ~(mp_bitcnt_t) 0 : un * GMP_LIMB_BITS);
+      limb = ux ^ up[i];
+    }
+  gmp_ctz (cnt, limb);
+  return (mp_bitcnt_t) i * GMP_LIMB_BITS + cnt;
+}
+
+mp_bitcnt_t
+mpn_scan1 (mp_srcptr ptr, mp_bitcnt_t bit)
+{
+  mp_size_t i;
+  i = bit / GMP_LIMB_BITS;
+
+  return mpn_common_scan ( ptr[i] & (GMP_LIMB_MAX << (bit % GMP_LIMB_BITS)),
+			  i, ptr, i, 0);
+}
+
+mp_bitcnt_t
+mpn_scan0 (mp_srcptr ptr, mp_bitcnt_t bit)
+{
+  mp_size_t i;
+  i = bit / GMP_LIMB_BITS;
+
+  return mpn_common_scan (~ptr[i] & (GMP_LIMB_MAX << (bit % GMP_LIMB_BITS)),
+			  i, ptr, i, GMP_LIMB_MAX);
+}
+
+void
+mpn_com (mp_ptr rp, mp_srcptr up, mp_size_t n)
+{
+  while (--n >= 0)
+    *rp++ = ~ *up++;
+}
+
+mp_limb_t
+mpn_neg (mp_ptr rp, mp_srcptr up, mp_size_t n)
+{
+  while (*up == 0)
+    {
+      *rp = 0;
+      if (!--n)
+	return 0;
+      ++up; ++rp;
+    }
+  *rp = - *up;
+  mpn_com (++rp, ++up, --n);
+  return 1;
+}
+
+
+/* MPN division interface. */
+
+/* The 3/2 inverse is defined as
+
+     m = floor( (B^3-1) / (B u1 + u0)) - B
+*/
+mp_limb_t
+mpn_invert_3by2 (mp_limb_t u1, mp_limb_t u0)
+{
+  mp_limb_t r, m;
+
+  {
+    mp_limb_t p, ql;
+    unsigned ul, uh, qh;
+
+    /* For notation, let b denote the half-limb base, so that B = b^2.
+       Split u1 = b uh + ul. */
+    ul = u1 & GMP_LLIMB_MASK;
+    uh = u1 >> (GMP_LIMB_BITS / 2);
+
+    /* Approximation of the high half of quotient. Differs from the 2/1
+       inverse of the half limb uh, since we have already subtracted
+       u0. */
+    qh = (u1 ^ GMP_LIMB_MAX) / uh;
+
+    /* Adjust to get a half-limb 3/2 inverse, i.e., we want
+
+       qh' = floor( (b^3 - 1) / u) - b = floor ((b^3 - b u - 1) / u
+	   = floor( (b (~u) + b-1) / u),
+	   
+       and the remainder
+
+       r = b (~u) + b-1 - qh (b uh + ul)
+       = b (~u - qh uh) + b-1 - qh ul
+
+       Subtraction of qh ul may underflow, which implies adjustments.
+       But by normalization, 2 u >= B > qh ul, so we need to adjust by
+       at most 2.
+    */
+
+    r = ((~u1 - (mp_limb_t) qh * uh) << (GMP_LIMB_BITS / 2)) | GMP_LLIMB_MASK;
+
+    p = (mp_limb_t) qh * ul;
+    /* Adjustment steps taken from udiv_qrnnd_c */
+    if (r < p)
+      {
+	qh--;
+	r += u1;
+	if (r >= u1) /* i.e. we didn't get carry when adding to r */
+	  if (r < p)
+	    {
+	      qh--;
+	      r += u1;
+	    }
+      }
+    r -= p;
+
+    /* Low half of the quotient is
+
+       ql = floor ( (b r + b-1) / u1).
+
+       This is a 3/2 division (on half-limbs), for which qh is a
+       suitable inverse. */
+
+    p = (r >> (GMP_LIMB_BITS / 2)) * qh + r;
+    /* Unlike full-limb 3/2, we can add 1 without overflow. For this to
+       work, it is essential that ql is a full mp_limb_t. */
+    ql = (p >> (GMP_LIMB_BITS / 2)) + 1;
+
+    /* By the 3/2 trick, we don't need the high half limb. */
+    r = (r << (GMP_LIMB_BITS / 2)) + GMP_LLIMB_MASK - ql * u1;
+
+    if (r >= (GMP_LIMB_MAX & (p << (GMP_LIMB_BITS / 2))))
+      {
+	ql--;
+	r += u1;
+      }
+    m = ((mp_limb_t) qh << (GMP_LIMB_BITS / 2)) + ql;
+    if (r >= u1)
+      {
+	m++;
+	r -= u1;
+      }
+  }
+
+  /* Now m is the 2/1 inverse of u1. If u0 > 0, adjust it to become a
+     3/2 inverse. */
+  if (u0 > 0)
+    {
+      mp_limb_t th, tl;
+      r = ~r;
+      r += u0;
+      if (r < u0)
+	{
+	  m--;
+	  if (r >= u1)
+	    {
+	      m--;
+	      r -= u1;
+	    }
+	  r -= u1;
+	}
+      gmp_umul_ppmm (th, tl, u0, m);
+      r += th;
+      if (r < th)
+	{
+	  m--;
+	  m -= ((r > u1) | ((r == u1) & (tl > u0)));
+	}
+    }
+
+  return m;
+}
+
+struct gmp_div_inverse
+{
+  /* Normalization shift count. */
+  unsigned shift;
+  /* Normalized divisor (d0 unused for mpn_div_qr_1) */
+  mp_limb_t d1, d0;
+  /* Inverse, for 2/1 or 3/2. */
+  mp_limb_t di;
+};
+
+static void
+mpn_div_qr_1_invert (struct gmp_div_inverse *inv, mp_limb_t d)
+{
+  unsigned shift;
+
+  assert (d > 0);
+  gmp_clz (shift, d);
+  inv->shift = shift;
+  inv->d1 = d << shift;
+  inv->di = mpn_invert_limb (inv->d1);
+}
+
+static void
+mpn_div_qr_2_invert (struct gmp_div_inverse *inv,
+		     mp_limb_t d1, mp_limb_t d0)
+{
+  unsigned shift;
+
+  assert (d1 > 0);
+  gmp_clz (shift, d1);
+  inv->shift = shift;
+  if (shift > 0)
+    {
+      d1 = (d1 << shift) | (d0 >> (GMP_LIMB_BITS - shift));
+      d0 <<= shift;
+    }
+  inv->d1 = d1;
+  inv->d0 = d0;
+  inv->di = mpn_invert_3by2 (d1, d0);
+}
+
+static void
+mpn_div_qr_invert (struct gmp_div_inverse *inv,
+		   mp_srcptr dp, mp_size_t dn)
+{
+  assert (dn > 0);
+
+  if (dn == 1)
+    mpn_div_qr_1_invert (inv, dp[0]);
+  else if (dn == 2)
+    mpn_div_qr_2_invert (inv, dp[1], dp[0]);
+  else
+    {
+      unsigned shift;
+      mp_limb_t d1, d0;
+
+      d1 = dp[dn-1];
+      d0 = dp[dn-2];
+      assert (d1 > 0);
+      gmp_clz (shift, d1);
+      inv->shift = shift;
+      if (shift > 0)
+	{
+	  d1 = (d1 << shift) | (d0 >> (GMP_LIMB_BITS - shift));
+	  d0 = (d0 << shift) | (dp[dn-3] >> (GMP_LIMB_BITS - shift));
+	}
+      inv->d1 = d1;
+      inv->d0 = d0;
+      inv->di = mpn_invert_3by2 (d1, d0);
+    }
+}
+
+/* Not matching current public gmp interface, rather corresponding to
+   the sbpi1_div_* functions. */
+static mp_limb_t
+mpn_div_qr_1_preinv (mp_ptr qp, mp_srcptr np, mp_size_t nn,
+		     const struct gmp_div_inverse *inv)
+{
+  mp_limb_t d, di;
+  mp_limb_t r;
+  mp_ptr tp = NULL;
+
+  if (inv->shift > 0)
+    {
+      /* Shift, reusing qp area if possible. In-place shift if qp == np. */
+      tp = qp ? qp : gmp_xalloc_limbs (nn);
+      r = mpn_lshift (tp, np, nn, inv->shift);
+      np = tp;
+    }
+  else
+    r = 0;
+
+  d = inv->d1;
+  di = inv->di;
+  while (--nn >= 0)
+    {
+      mp_limb_t q;
+
+      gmp_udiv_qrnnd_preinv (q, r, r, np[nn], d, di);
+      if (qp)
+	qp[nn] = q;
+    }
+  if ((inv->shift > 0) && (tp != qp))
+    gmp_free (tp);
+
+  return r >> inv->shift;
+}
+
+static void
+mpn_div_qr_2_preinv (mp_ptr qp, mp_ptr np, mp_size_t nn,
+		     const struct gmp_div_inverse *inv)
+{
+  unsigned shift;
+  mp_size_t i;
+  mp_limb_t d1, d0, di, r1, r0;
+
+  assert (nn >= 2);
+  shift = inv->shift;
+  d1 = inv->d1;
+  d0 = inv->d0;
+  di = inv->di;
+
+  if (shift > 0)
+    r1 = mpn_lshift (np, np, nn, shift);
+  else
+    r1 = 0;
+
+  r0 = np[nn - 1];
+
+  i = nn - 2;
+  do
+    {
+      mp_limb_t n0, q;
+      n0 = np[i];
+      gmp_udiv_qr_3by2 (q, r1, r0, r1, r0, n0, d1, d0, di);
+
+      if (qp)
+	qp[i] = q;
+    }
+  while (--i >= 0);
+
+  if (shift > 0)
+    {
+      assert ((r0 & (GMP_LIMB_MAX >> (GMP_LIMB_BITS - shift))) == 0);
+      r0 = (r0 >> shift) | (r1 << (GMP_LIMB_BITS - shift));
+      r1 >>= shift;
+    }
+
+  np[1] = r1;
+  np[0] = r0;
+}
+
+static void
+mpn_div_qr_pi1 (mp_ptr qp,
+		mp_ptr np, mp_size_t nn, mp_limb_t n1,
+		mp_srcptr dp, mp_size_t dn,
+		mp_limb_t dinv)
+{
+  mp_size_t i;
+
+  mp_limb_t d1, d0;
+  mp_limb_t cy, cy1;
+  mp_limb_t q;
+
+  assert (dn > 2);
+  assert (nn >= dn);
+
+  d1 = dp[dn - 1];
+  d0 = dp[dn - 2];
+
+  assert ((d1 & GMP_LIMB_HIGHBIT) != 0);
+  /* Iteration variable is the index of the q limb.
+   *
+   * We divide <n1, np[dn-1+i], np[dn-2+i], np[dn-3+i],..., np[i]>
+   * by            <d1,          d0,        dp[dn-3],  ..., dp[0] >
+   */
+
+  i = nn - dn;
+  do
+    {
+      mp_limb_t n0 = np[dn-1+i];
+
+      if (n1 == d1 && n0 == d0)
+	{
+	  q = GMP_LIMB_MAX;
+	  mpn_submul_1 (np+i, dp, dn, q);
+	  n1 = np[dn-1+i];	/* update n1, last loop's value will now be invalid */
+	}
+      else
+	{
+	  gmp_udiv_qr_3by2 (q, n1, n0, n1, n0, np[dn-2+i], d1, d0, dinv);
+
+	  cy = mpn_submul_1 (np + i, dp, dn-2, q);
+
+	  cy1 = n0 < cy;
+	  n0 = n0 - cy;
+	  cy = n1 < cy1;
+	  n1 = n1 - cy1;
+	  np[dn-2+i] = n0;
+
+	  if (cy != 0)
+	    {
+	      n1 += d1 + mpn_add_n (np + i, np + i, dp, dn - 1);
+	      q--;
+	    }
+	}
+
+      if (qp)
+	qp[i] = q;
+    }
+  while (--i >= 0);
+
+  np[dn - 1] = n1;
+}
+
+static void
+mpn_div_qr_preinv (mp_ptr qp, mp_ptr np, mp_size_t nn,
+		   mp_srcptr dp, mp_size_t dn,
+		   const struct gmp_div_inverse *inv)
+{
+  assert (dn > 0);
+  assert (nn >= dn);
+
+  if (dn == 1)
+    np[0] = mpn_div_qr_1_preinv (qp, np, nn, inv);
+  else if (dn == 2)
+    mpn_div_qr_2_preinv (qp, np, nn, inv);
+  else
+    {
+      mp_limb_t nh;
+      unsigned shift;
+
+      assert (inv->d1 == dp[dn-1]);
+      assert (inv->d0 == dp[dn-2]);
+      assert ((inv->d1 & GMP_LIMB_HIGHBIT) != 0);
+
+      shift = inv->shift;
+      if (shift > 0)
+	nh = mpn_lshift (np, np, nn, shift);
+      else
+	nh = 0;
+
+      mpn_div_qr_pi1 (qp, np, nn, nh, dp, dn, inv->di);
+
+      if (shift > 0)
+	gmp_assert_nocarry (mpn_rshift (np, np, dn, shift));
+    }
+}
+
+static void
+mpn_div_qr (mp_ptr qp, mp_ptr np, mp_size_t nn, mp_srcptr dp, mp_size_t dn)
+{
+  struct gmp_div_inverse inv;
+  mp_ptr tp = NULL;
+
+  assert (dn > 0);
+  assert (nn >= dn);
+
+  mpn_div_qr_invert (&inv, dp, dn);
+  if (dn > 2 && inv.shift > 0)
+    {
+      tp = gmp_xalloc_limbs (dn);
+      gmp_assert_nocarry (mpn_lshift (tp, dp, dn, inv.shift));
+      dp = tp;
+    }
+  mpn_div_qr_preinv (qp, np, nn, dp, dn, &inv);
+  if (tp)
+    gmp_free (tp);
+}
+
+
+/* MPN base conversion. */
+static unsigned
+mpn_base_power_of_two_p (unsigned b)
+{
+  switch (b)
+    {
+    case 2: return 1;
+    case 4: return 2;
+    case 8: return 3;
+    case 16: return 4;
+    case 32: return 5;
+    case 64: return 6;
+    case 128: return 7;
+    case 256: return 8;
+    default: return 0;
+    }
+}
+
+struct mpn_base_info
+{
+  /* bb is the largest power of the base which fits in one limb, and
+     exp is the corresponding exponent. */
+  unsigned exp;
+  mp_limb_t bb;
+};
+
+static void
+mpn_get_base_info (struct mpn_base_info *info, mp_limb_t b)
+{
+  mp_limb_t m;
+  mp_limb_t p;
+  unsigned exp;
+
+  m = GMP_LIMB_MAX / b;
+  for (exp = 1, p = b; p <= m; exp++)
+    p *= b;
+
+  info->exp = exp;
+  info->bb = p;
+}
+
+static mp_bitcnt_t
+mpn_limb_size_in_base_2 (mp_limb_t u)
+{
+  unsigned shift;
+
+  assert (u > 0);
+  gmp_clz (shift, u);
+  return GMP_LIMB_BITS - shift;
+}
+
+static size_t
+mpn_get_str_bits (unsigned char *sp, unsigned bits, mp_srcptr up, mp_size_t un)
+{
+  unsigned char mask;
+  size_t sn, j;
+  mp_size_t i;
+  unsigned shift;
+
+  sn = ((un - 1) * GMP_LIMB_BITS + mpn_limb_size_in_base_2 (up[un-1])
+	+ bits - 1) / bits;
+
+  mask = (1U << bits) - 1;
+
+  for (i = 0, j = sn, shift = 0; j-- > 0;)
+    {
+      unsigned char digit = up[i] >> shift;
+
+      shift += bits;
+
+      if (shift >= GMP_LIMB_BITS && ++i < un)
+	{
+	  shift -= GMP_LIMB_BITS;
+	  digit |= up[i] << (bits - shift);
+	}
+      sp[j] = digit & mask;
+    }
+  return sn;
+}
+
+/* We generate digits from the least significant end, and reverse at
+   the end. */
+static size_t
+mpn_limb_get_str (unsigned char *sp, mp_limb_t w,
+		  const struct gmp_div_inverse *binv)
+{
+  mp_size_t i;
+  for (i = 0; w > 0; i++)
+    {
+      mp_limb_t h, l, r;
+
+      h = w >> (GMP_LIMB_BITS - binv->shift);
+      l = w << binv->shift;
+
+      gmp_udiv_qrnnd_preinv (w, r, h, l, binv->d1, binv->di);
+      assert ((r & (GMP_LIMB_MAX >> (GMP_LIMB_BITS - binv->shift))) == 0);
+      r >>= binv->shift;
+
+      sp[i] = r;
+    }
+  return i;
+}
+
+static size_t
+mpn_get_str_other (unsigned char *sp,
+		   int base, const struct mpn_base_info *info,
+		   mp_ptr up, mp_size_t un)
+{
+  struct gmp_div_inverse binv;
+  size_t sn;
+  size_t i;
+
+  mpn_div_qr_1_invert (&binv, base);
+
+  sn = 0;
+
+  if (un > 1)
+    {
+      struct gmp_div_inverse bbinv;
+      mpn_div_qr_1_invert (&bbinv, info->bb);
+
+      do
+	{
+	  mp_limb_t w;
+	  size_t done;
+	  w = mpn_div_qr_1_preinv (up, up, un, &bbinv);
+	  un -= (up[un-1] == 0);
+	  done = mpn_limb_get_str (sp + sn, w, &binv);
+
+	  for (sn += done; done < info->exp; done++)
+	    sp[sn++] = 0;
+	}
+      while (un > 1);
+    }
+  sn += mpn_limb_get_str (sp + sn, up[0], &binv);
+
+  /* Reverse order */
+  for (i = 0; 2*i + 1 < sn; i++)
+    {
+      unsigned char t = sp[i];
+      sp[i] = sp[sn - i - 1];
+      sp[sn - i - 1] = t;
+    }
+
+  return sn;
+}
+
+size_t
+mpn_get_str (unsigned char *sp, int base, mp_ptr up, mp_size_t un)
+{
+  unsigned bits;
+
+  assert (un > 0);
+  assert (up[un-1] > 0);
+
+  bits = mpn_base_power_of_two_p (base);
+  if (bits)
+    return mpn_get_str_bits (sp, bits, up, un);
+  else
+    {
+      struct mpn_base_info info;
+
+      mpn_get_base_info (&info, base);
+      return mpn_get_str_other (sp, base, &info, up, un);
+    }
+}
+
+static mp_size_t
+mpn_set_str_bits (mp_ptr rp, const unsigned char *sp, size_t sn,
+		  unsigned bits)
+{
+  mp_size_t rn;
+  size_t j;
+  unsigned shift;
+
+  for (j = sn, rn = 0, shift = 0; j-- > 0; )
+    {
+      if (shift == 0)
+	{
+	  rp[rn++] = sp[j];
+	  shift += bits;
+	}
+      else
+	{
+	  rp[rn-1] |= (mp_limb_t) sp[j] << shift;
+	  shift += bits;
+	  if (shift >= GMP_LIMB_BITS)
+	    {
+	      shift -= GMP_LIMB_BITS;
+	      if (shift > 0)
+		rp[rn++] = (mp_limb_t) sp[j] >> (bits - shift);
+	    }
+	}
+    }
+  rn = mpn_normalized_size (rp, rn);
+  return rn;
+}
+
+/* Result is usually normalized, except for all-zero input, in which
+   case a single zero limb is written at *RP, and 1 is returned. */
+static mp_size_t
+mpn_set_str_other (mp_ptr rp, const unsigned char *sp, size_t sn,
+		   mp_limb_t b, const struct mpn_base_info *info)
+{
+  mp_size_t rn;
+  mp_limb_t w;
+  unsigned k;
+  size_t j;
+
+  assert (sn > 0);
+
+  k = 1 + (sn - 1) % info->exp;
+
+  j = 0;
+  w = sp[j++];
+  while (--k != 0)
+    w = w * b + sp[j++];
+
+  rp[0] = w;
+
+  for (rn = 1; j < sn;)
+    {
+      mp_limb_t cy;
+
+      w = sp[j++];
+      for (k = 1; k < info->exp; k++)
+	w = w * b + sp[j++];
+
+      cy = mpn_mul_1 (rp, rp, rn, info->bb);
+      cy += mpn_add_1 (rp, rp, rn, w);
+      if (cy > 0)
+	rp[rn++] = cy;
+    }
+  assert (j == sn);
+
+  return rn;
+}
+
+mp_size_t
+mpn_set_str (mp_ptr rp, const unsigned char *sp, size_t sn, int base)
+{
+  unsigned bits;
+
+  if (sn == 0)
+    return 0;
+
+  bits = mpn_base_power_of_two_p (base);
+  if (bits)
+    return mpn_set_str_bits (rp, sp, sn, bits);
+  else
+    {
+      struct mpn_base_info info;
+
+      mpn_get_base_info (&info, base);
+      return mpn_set_str_other (rp, sp, sn, base, &info);
+    }
+}
+
+
+/* MPZ interface */
+void
+mpz_init (mpz_t r)
+{
+  static const mp_limb_t dummy_limb = GMP_LIMB_MAX & 0xc1a0;
+
+  r->_mp_alloc = 0;
+  r->_mp_size = 0;
+  r->_mp_d = (mp_ptr) &dummy_limb;
+}
+
+/* The utility of this function is a bit limited, since many functions
+   assigns the result variable using mpz_swap. */
+void
+mpz_init2 (mpz_t r, mp_bitcnt_t bits)
+{
+  mp_size_t rn;
+
+  bits -= (bits != 0);		/* Round down, except if 0 */
+  rn = 1 + bits / GMP_LIMB_BITS;
+
+  r->_mp_alloc = rn;
+  r->_mp_size = 0;
+  r->_mp_d = gmp_xalloc_limbs (rn);
+}
+
+void
+mpz_clear (mpz_t r)
+{
+  if (r->_mp_alloc)
+    gmp_free (r->_mp_d);
+}
+
+static mp_ptr
+mpz_realloc (mpz_t r, mp_size_t size)
+{
+  size = GMP_MAX (size, 1);
+
+  if (r->_mp_alloc)
+    r->_mp_d = gmp_xrealloc_limbs (r->_mp_d, size);
+  else
+    r->_mp_d = gmp_xalloc_limbs (size);
+  r->_mp_alloc = size;
+
+  if (GMP_ABS (r->_mp_size) > size)
+    r->_mp_size = 0;
+
+  return r->_mp_d;
+}
+
+/* Realloc for an mpz_t WHAT if it has less than NEEDED limbs.  */
+#define MPZ_REALLOC(z,n) ((n) > (z)->_mp_alloc			\
+			  ? mpz_realloc(z,n)			\
+			  : (z)->_mp_d)
+
+/* MPZ assignment and basic conversions. */
+void
+mpz_set_si (mpz_t r, signed long int x)
+{
+  if (x >= 0)
+    mpz_set_ui (r, x);
+  else /* (x < 0) */
+    if (GMP_LIMB_BITS < GMP_ULONG_BITS)
+      {
+	mpz_set_ui (r, GMP_NEG_CAST (unsigned long int, x));
+	mpz_neg (r, r);
+      }
+  else
+    {
+      r->_mp_size = -1;
+      MPZ_REALLOC (r, 1)[0] = GMP_NEG_CAST (unsigned long int, x);
+    }
+}
+
+void
+mpz_set_ui (mpz_t r, unsigned long int x)
+{
+  if (x > 0)
+    {
+      r->_mp_size = 1;
+      MPZ_REALLOC (r, 1)[0] = x;
+      if (GMP_LIMB_BITS < GMP_ULONG_BITS)
+	{
+	  int LOCAL_GMP_LIMB_BITS = GMP_LIMB_BITS;
+	  while (x >>= LOCAL_GMP_LIMB_BITS)
+	    {
+	      ++ r->_mp_size;
+	      MPZ_REALLOC (r, r->_mp_size)[r->_mp_size - 1] = x;
+	    }
+	}
+    }
+  else
+    r->_mp_size = 0;
+}
+
+void
+mpz_set (mpz_t r, const mpz_t x)
+{
+  /* Allow the NOP r == x */
+  if (r != x)
+    {
+      mp_size_t n;
+      mp_ptr rp;
+
+      n = GMP_ABS (x->_mp_size);
+      rp = MPZ_REALLOC (r, n);
+
+      mpn_copyi (rp, x->_mp_d, n);
+      r->_mp_size = x->_mp_size;
+    }
+}
+
+void
+mpz_init_set_si (mpz_t r, signed long int x)
+{
+  mpz_init (r);
+  mpz_set_si (r, x);
+}
+
+void
+mpz_init_set_ui (mpz_t r, unsigned long int x)
+{
+  mpz_init (r);
+  mpz_set_ui (r, x);
+}
+
+void
+mpz_init_set (mpz_t r, const mpz_t x)
+{
+  mpz_init (r);
+  mpz_set (r, x);
+}
+
+int
+mpz_fits_slong_p (const mpz_t u)
+{
+  return (LONG_MAX + LONG_MIN == 0 || mpz_cmp_ui (u, LONG_MAX) <= 0) &&
+    mpz_cmpabs_ui (u, GMP_NEG_CAST (unsigned long int, LONG_MIN)) <= 0;
+}
+
+static int
+mpn_absfits_ulong_p (mp_srcptr up, mp_size_t un)
+{
+  int ulongsize = GMP_ULONG_BITS / GMP_LIMB_BITS;
+  mp_limb_t ulongrem = 0;
+
+  if (GMP_ULONG_BITS % GMP_LIMB_BITS != 0)
+    ulongrem = (mp_limb_t) (ULONG_MAX >> GMP_LIMB_BITS * ulongsize) + 1;
+
+  return un <= ulongsize || (up[ulongsize] < ulongrem && un == ulongsize + 1);
+}
+
+int
+mpz_fits_ulong_p (const mpz_t u)
+{
+  mp_size_t us = u->_mp_size;
+
+  return us >= 0 && mpn_absfits_ulong_p (u->_mp_d, us);
+}
+
+long int
+mpz_get_si (const mpz_t u)
+{
+  unsigned long r = mpz_get_ui (u);
+  unsigned long c = -LONG_MAX - LONG_MIN;
+
+  if (u->_mp_size < 0)
+    /* This expression is necessary to properly handle -LONG_MIN */
+    return -(long) c - (long) ((r - c) & LONG_MAX);
+  else
+    return (long) (r & LONG_MAX);
+}
+
+unsigned long int
+mpz_get_ui (const mpz_t u)
+{
+  if (GMP_LIMB_BITS < GMP_ULONG_BITS)
+    {
+      int LOCAL_GMP_LIMB_BITS = GMP_LIMB_BITS;
+      unsigned long r = 0;
+      mp_size_t n = GMP_ABS (u->_mp_size);
+      n = GMP_MIN (n, 1 + (mp_size_t) (GMP_ULONG_BITS - 1) / GMP_LIMB_BITS);
+      while (--n >= 0)
+	r = (r << LOCAL_GMP_LIMB_BITS) + u->_mp_d[n];
+      return r;
+    }
+
+  return u->_mp_size == 0 ? 0 : u->_mp_d[0];
+}
+
+size_t
+mpz_size (const mpz_t u)
+{
+  return GMP_ABS (u->_mp_size);
+}
+
+mp_limb_t
+mpz_getlimbn (const mpz_t u, mp_size_t n)
+{
+  if (n >= 0 && n < GMP_ABS (u->_mp_size))
+    return u->_mp_d[n];
+  else
+    return 0;
+}
+
+void
+mpz_realloc2 (mpz_t x, mp_bitcnt_t n)
+{
+  mpz_realloc (x, 1 + (n - (n != 0)) / GMP_LIMB_BITS);
+}
+
+mp_srcptr
+mpz_limbs_read (mpz_srcptr x)
+{
+  return x->_mp_d;
+}
+
+mp_ptr
+mpz_limbs_modify (mpz_t x, mp_size_t n)
+{
+  assert (n > 0);
+  return MPZ_REALLOC (x, n);
+}
+
+mp_ptr
+mpz_limbs_write (mpz_t x, mp_size_t n)
+{
+  return mpz_limbs_modify (x, n);
+}
+
+void
+mpz_limbs_finish (mpz_t x, mp_size_t xs)
+{
+  mp_size_t xn;
+  xn = mpn_normalized_size (x->_mp_d, GMP_ABS (xs));
+  x->_mp_size = xs < 0 ? -xn : xn;
+}
+
+static mpz_srcptr
+mpz_roinit_normal_n (mpz_t x, mp_srcptr xp, mp_size_t xs)
+{
+  x->_mp_alloc = 0;
+  x->_mp_d = (mp_ptr) xp;
+  x->_mp_size = xs;
+  return x;
+}
+
+mpz_srcptr
+mpz_roinit_n (mpz_t x, mp_srcptr xp, mp_size_t xs)
+{
+  mpz_roinit_normal_n (x, xp, xs);
+  mpz_limbs_finish (x, xs);
+  return x;
+}
+
+
+/* Conversions and comparison to double. */
+void
+mpz_set_d (mpz_t r, double x)
+{
+  int sign;
+  mp_ptr rp;
+  mp_size_t rn, i;
+  double B;
+  double Bi;
+  mp_limb_t f;
+
+  /* x != x is true when x is a NaN, and x == x * 0.5 is true when x is
+     zero or infinity. */
+  if (x != x || x == x * 0.5)
+    {
+      r->_mp_size = 0;
+      return;
+    }
+
+  sign = x < 0.0 ;
+  if (sign)
+    x = - x;
+
+  if (x < 1.0)
+    {
+      r->_mp_size = 0;
+      return;
+    }
+  B = 4.0 * (double) (GMP_LIMB_HIGHBIT >> 1);
+  Bi = 1.0 / B;
+  for (rn = 1; x >= B; rn++)
+    x *= Bi;
+
+  rp = MPZ_REALLOC (r, rn);
+
+  f = (mp_limb_t) x;
+  x -= f;
+  assert (x < 1.0);
+  i = rn-1;
+  rp[i] = f;
+  while (--i >= 0)
+    {
+      x = B * x;
+      f = (mp_limb_t) x;
+      x -= f;
+      assert (x < 1.0);
+      rp[i] = f;
+    }
+
+  r->_mp_size = sign ? - rn : rn;
+}
+
+void
+mpz_init_set_d (mpz_t r, double x)
+{
+  mpz_init (r);
+  mpz_set_d (r, x);
+}
+
+double
+mpz_get_d (const mpz_t u)
+{
+  int m;
+  mp_limb_t l;
+  mp_size_t un;
+  double x;
+  double B = 4.0 * (double) (GMP_LIMB_HIGHBIT >> 1);
+
+  un = GMP_ABS (u->_mp_size);
+
+  if (un == 0)
+    return 0.0;
+
+  l = u->_mp_d[--un];
+  gmp_clz (m, l);
+  m = m + GMP_DBL_MANT_BITS - GMP_LIMB_BITS;
+  if (m < 0)
+    l &= GMP_LIMB_MAX << -m;
+
+  for (x = l; --un >= 0;)
+    {
+      x = B*x;
+      if (m > 0) {
+	l = u->_mp_d[un];
+	m -= GMP_LIMB_BITS;
+	if (m < 0)
+	  l &= GMP_LIMB_MAX << -m;
+	x += l;
+      }
+    }
+
+  if (u->_mp_size < 0)
+    x = -x;
+
+  return x;
+}
+
+int
+mpz_cmpabs_d (const mpz_t x, double d)
+{
+  mp_size_t xn;
+  double B, Bi;
+  mp_size_t i;
+
+  xn = x->_mp_size;
+  d = GMP_ABS (d);
+
+  if (xn != 0)
+    {
+      xn = GMP_ABS (xn);
+
+      B = 4.0 * (double) (GMP_LIMB_HIGHBIT >> 1);
+      Bi = 1.0 / B;
+
+      /* Scale d so it can be compared with the top limb. */
+      for (i = 1; i < xn; i++)
+	d *= Bi;
+
+      if (d >= B)
+	return -1;
+
+      /* Compare floor(d) to top limb, subtract and cancel when equal. */
+      for (i = xn; i-- > 0;)
+	{
+	  mp_limb_t f, xl;
+
+	  f = (mp_limb_t) d;
+	  xl = x->_mp_d[i];
+	  if (xl > f)
+	    return 1;
+	  else if (xl < f)
+	    return -1;
+	  d = B * (d - f);
+	}
+    }
+  return - (d > 0.0);
+}
+
+int
+mpz_cmp_d (const mpz_t x, double d)
+{
+  if (x->_mp_size < 0)
+    {
+      if (d >= 0.0)
+	return -1;
+      else
+	return -mpz_cmpabs_d (x, d);
+    }
+  else
+    {
+      if (d < 0.0)
+	return 1;
+      else
+	return mpz_cmpabs_d (x, d);
+    }
+}
+
+
+/* MPZ comparisons and the like. */
+int
+mpz_sgn (const mpz_t u)
+{
+  return GMP_CMP (u->_mp_size, 0);
+}
+
+int
+mpz_cmp_si (const mpz_t u, long v)
+{
+  mp_size_t usize = u->_mp_size;
+
+  if (v >= 0)
+    return mpz_cmp_ui (u, v);
+  else if (usize >= 0)
+    return 1;
+  else
+    return - mpz_cmpabs_ui (u, GMP_NEG_CAST (unsigned long int, v));
+}
+
+int
+mpz_cmp_ui (const mpz_t u, unsigned long v)
+{
+  mp_size_t usize = u->_mp_size;
+
+  if (usize < 0)
+    return -1;
+  else
+    return mpz_cmpabs_ui (u, v);
+}
+
+int
+mpz_cmp (const mpz_t a, const mpz_t b)
+{
+  mp_size_t asize = a->_mp_size;
+  mp_size_t bsize = b->_mp_size;
+
+  if (asize != bsize)
+    return (asize < bsize) ? -1 : 1;
+  else if (asize >= 0)
+    return mpn_cmp (a->_mp_d, b->_mp_d, asize);
+  else
+    return mpn_cmp (b->_mp_d, a->_mp_d, -asize);
+}
+
+int
+mpz_cmpabs_ui (const mpz_t u, unsigned long v)
+{
+  mp_size_t un = GMP_ABS (u->_mp_size);
+
+  if (! mpn_absfits_ulong_p (u->_mp_d, un))
+    return 1;
+  else
+    {
+      unsigned long uu = mpz_get_ui (u);
+      return GMP_CMP(uu, v);
+    }
+}
+
+int
+mpz_cmpabs (const mpz_t u, const mpz_t v)
+{
+  return mpn_cmp4 (u->_mp_d, GMP_ABS (u->_mp_size),
+		   v->_mp_d, GMP_ABS (v->_mp_size));
+}
+
+void
+mpz_abs (mpz_t r, const mpz_t u)
+{
+  mpz_set (r, u);
+  r->_mp_size = GMP_ABS (r->_mp_size);
+}
+
+void
+mpz_neg (mpz_t r, const mpz_t u)
+{
+  mpz_set (r, u);
+  r->_mp_size = -r->_mp_size;
+}
+
+void
+mpz_swap (mpz_t u, mpz_t v)
+{
+  MP_SIZE_T_SWAP (u->_mp_size, v->_mp_size);
+  MP_SIZE_T_SWAP (u->_mp_alloc, v->_mp_alloc);
+  MP_PTR_SWAP (u->_mp_d, v->_mp_d);
+}
+
+
+/* MPZ addition and subtraction */
+
+
+void
+mpz_add_ui (mpz_t r, const mpz_t a, unsigned long b)
+{
+  mpz_t bb;
+  mpz_init_set_ui (bb, b);
+  mpz_add (r, a, bb);
+  mpz_clear (bb);
+}
+
+void
+mpz_sub_ui (mpz_t r, const mpz_t a, unsigned long b)
+{
+  mpz_ui_sub (r, b, a);
+  mpz_neg (r, r);
+}
+
+void
+mpz_ui_sub (mpz_t r, unsigned long a, const mpz_t b)
+{
+  mpz_neg (r, b);
+  mpz_add_ui (r, r, a);
+}
+
+static mp_size_t
+mpz_abs_add (mpz_t r, const mpz_t a, const mpz_t b)
+{
+  mp_size_t an = GMP_ABS (a->_mp_size);
+  mp_size_t bn = GMP_ABS (b->_mp_size);
+  mp_ptr rp;
+  mp_limb_t cy;
+
+  if (an < bn)
+    {
+      MPZ_SRCPTR_SWAP (a, b);
+      MP_SIZE_T_SWAP (an, bn);
+    }
+
+  rp = MPZ_REALLOC (r, an + 1);
+  cy = mpn_add (rp, a->_mp_d, an, b->_mp_d, bn);
+
+  rp[an] = cy;
+
+  return an + cy;
+}
+
+static mp_size_t
+mpz_abs_sub (mpz_t r, const mpz_t a, const mpz_t b)
+{
+  mp_size_t an = GMP_ABS (a->_mp_size);
+  mp_size_t bn = GMP_ABS (b->_mp_size);
+  int cmp;
+  mp_ptr rp;
+
+  cmp = mpn_cmp4 (a->_mp_d, an, b->_mp_d, bn);
+  if (cmp > 0)
+    {
+      rp = MPZ_REALLOC (r, an);
+      gmp_assert_nocarry (mpn_sub (rp, a->_mp_d, an, b->_mp_d, bn));
+      return mpn_normalized_size (rp, an);
+    }
+  else if (cmp < 0)
+    {
+      rp = MPZ_REALLOC (r, bn);
+      gmp_assert_nocarry (mpn_sub (rp, b->_mp_d, bn, a->_mp_d, an));
+      return -mpn_normalized_size (rp, bn);
+    }
+  else
+    return 0;
+}
+
+void
+mpz_add (mpz_t r, const mpz_t a, const mpz_t b)
+{
+  mp_size_t rn;
+
+  if ( (a->_mp_size ^ b->_mp_size) >= 0)
+    rn = mpz_abs_add (r, a, b);
+  else
+    rn = mpz_abs_sub (r, a, b);
+
+  r->_mp_size = a->_mp_size >= 0 ? rn : - rn;
+}
+
+void
+mpz_sub (mpz_t r, const mpz_t a, const mpz_t b)
+{
+  mp_size_t rn;
+
+  if ( (a->_mp_size ^ b->_mp_size) >= 0)
+    rn = mpz_abs_sub (r, a, b);
+  else
+    rn = mpz_abs_add (r, a, b);
+
+  r->_mp_size = a->_mp_size >= 0 ? rn : - rn;
+}
+
+
+/* MPZ multiplication */
+void
+mpz_mul_si (mpz_t r, const mpz_t u, long int v)
+{
+  if (v < 0)
+    {
+      mpz_mul_ui (r, u, GMP_NEG_CAST (unsigned long int, v));
+      mpz_neg (r, r);
+    }
+  else
+    mpz_mul_ui (r, u, v);
+}
+
+void
+mpz_mul_ui (mpz_t r, const mpz_t u, unsigned long int v)
+{
+  mpz_t vv;
+  mpz_init_set_ui (vv, v);
+  mpz_mul (r, u, vv);
+  mpz_clear (vv);
+  return;
+}
+
+void
+mpz_mul (mpz_t r, const mpz_t u, const mpz_t v)
+{
+  int sign;
+  mp_size_t un, vn, rn;
+  mpz_t t;
+  mp_ptr tp;
+
+  un = u->_mp_size;
+  vn = v->_mp_size;
+
+  if (un == 0 || vn == 0)
+    {
+      r->_mp_size = 0;
+      return;
+    }
+
+  sign = (un ^ vn) < 0;
+
+  un = GMP_ABS (un);
+  vn = GMP_ABS (vn);
+
+  mpz_init2 (t, (un + vn) * GMP_LIMB_BITS);
+
+  tp = t->_mp_d;
+  if (un >= vn)
+    mpn_mul (tp, u->_mp_d, un, v->_mp_d, vn);
+  else
+    mpn_mul (tp, v->_mp_d, vn, u->_mp_d, un);
+
+  rn = un + vn;
+  rn -= tp[rn-1] == 0;
+
+  t->_mp_size = sign ? - rn : rn;
+  mpz_swap (r, t);
+  mpz_clear (t);
+}
+
+void
+mpz_mul_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t bits)
+{
+  mp_size_t un, rn;
+  mp_size_t limbs;
+  unsigned shift;
+  mp_ptr rp;
+
+  un = GMP_ABS (u->_mp_size);
+  if (un == 0)
+    {
+      r->_mp_size = 0;
+      return;
+    }
+
+  limbs = bits / GMP_LIMB_BITS;
+  shift = bits % GMP_LIMB_BITS;
+
+  rn = un + limbs + (shift > 0);
+  rp = MPZ_REALLOC (r, rn);
+  if (shift > 0)
+    {
+      mp_limb_t cy = mpn_lshift (rp + limbs, u->_mp_d, un, shift);
+      rp[rn-1] = cy;
+      rn -= (cy == 0);
+    }
+  else
+    mpn_copyd (rp + limbs, u->_mp_d, un);
+
+  mpn_zero (rp, limbs);
+
+  r->_mp_size = (u->_mp_size < 0) ? - rn : rn;
+}
+
+void
+mpz_addmul_ui (mpz_t r, const mpz_t u, unsigned long int v)
+{
+  mpz_t t;
+  mpz_init_set_ui (t, v);
+  mpz_mul (t, u, t);
+  mpz_add (r, r, t);
+  mpz_clear (t);
+}
+
+void
+mpz_submul_ui (mpz_t r, const mpz_t u, unsigned long int v)
+{
+  mpz_t t;
+  mpz_init_set_ui (t, v);
+  mpz_mul (t, u, t);
+  mpz_sub (r, r, t);
+  mpz_clear (t);
+}
+
+void
+mpz_addmul (mpz_t r, const mpz_t u, const mpz_t v)
+{
+  mpz_t t;
+  mpz_init (t);
+  mpz_mul (t, u, v);
+  mpz_add (r, r, t);
+  mpz_clear (t);
+}
+
+void
+mpz_submul (mpz_t r, const mpz_t u, const mpz_t v)
+{
+  mpz_t t;
+  mpz_init (t);
+  mpz_mul (t, u, v);
+  mpz_sub (r, r, t);
+  mpz_clear (t);
+}
+
+
+/* MPZ division */
+enum mpz_div_round_mode { GMP_DIV_FLOOR, GMP_DIV_CEIL, GMP_DIV_TRUNC };
+
+/* Allows q or r to be zero. Returns 1 iff remainder is non-zero. */
+static int
+mpz_div_qr (mpz_t q, mpz_t r,
+	    const mpz_t n, const mpz_t d, enum mpz_div_round_mode mode)
+{
+  mp_size_t ns, ds, nn, dn, qs;
+  ns = n->_mp_size;
+  ds = d->_mp_size;
+
+  if (ds == 0)
+    gmp_die("mpz_div_qr: Divide by zero.");
+
+  if (ns == 0)
+    {
+      if (q)
+	q->_mp_size = 0;
+      if (r)
+	r->_mp_size = 0;
+      return 0;
+    }
+
+  nn = GMP_ABS (ns);
+  dn = GMP_ABS (ds);
+
+  qs = ds ^ ns;
+
+  if (nn < dn)
+    {
+      if (mode == GMP_DIV_CEIL && qs >= 0)
+	{
+	  /* q = 1, r = n - d */
+	  if (r)
+	    mpz_sub (r, n, d);
+	  if (q)
+	    mpz_set_ui (q, 1);
+	}
+      else if (mode == GMP_DIV_FLOOR && qs < 0)
+	{
+	  /* q = -1, r = n + d */
+	  if (r)
+	    mpz_add (r, n, d);
+	  if (q)
+	    mpz_set_si (q, -1);
+	}
+      else
+	{
+	  /* q = 0, r = d */
+	  if (r)
+	    mpz_set (r, n);
+	  if (q)
+	    q->_mp_size = 0;
+	}
+      return 1;
+    }
+  else
+    {
+      mp_ptr np, qp;
+      mp_size_t qn, rn;
+      mpz_t tq, tr;
+
+      mpz_init_set (tr, n);
+      np = tr->_mp_d;
+
+      qn = nn - dn + 1;
+
+      if (q)
+	{
+	  mpz_init2 (tq, qn * GMP_LIMB_BITS);
+	  qp = tq->_mp_d;
+	}
+      else
+	qp = NULL;
+
+      mpn_div_qr (qp, np, nn, d->_mp_d, dn);
+
+      if (qp)
+	{
+	  qn -= (qp[qn-1] == 0);
+
+	  tq->_mp_size = qs < 0 ? -qn : qn;
+	}
+      rn = mpn_normalized_size (np, dn);
+      tr->_mp_size = ns < 0 ? - rn : rn;
+
+      if (mode == GMP_DIV_FLOOR && qs < 0 && rn != 0)
+	{
+	  if (q)
+	    mpz_sub_ui (tq, tq, 1);
+	  if (r)
+	    mpz_add (tr, tr, d);
+	}
+      else if (mode == GMP_DIV_CEIL && qs >= 0 && rn != 0)
+	{
+	  if (q)
+	    mpz_add_ui (tq, tq, 1);
+	  if (r)
+	    mpz_sub (tr, tr, d);
+	}
+
+      if (q)
+	{
+	  mpz_swap (tq, q);
+	  mpz_clear (tq);
+	}
+      if (r)
+	mpz_swap (tr, r);
+
+      mpz_clear (tr);
+
+      return rn != 0;
+    }
+}
+
+void
+mpz_cdiv_qr (mpz_t q, mpz_t r, const mpz_t n, const mpz_t d)
+{
+  mpz_div_qr (q, r, n, d, GMP_DIV_CEIL);
+}
+
+void
+mpz_fdiv_qr (mpz_t q, mpz_t r, const mpz_t n, const mpz_t d)
+{
+  mpz_div_qr (q, r, n, d, GMP_DIV_FLOOR);
+}
+
+void
+mpz_tdiv_qr (mpz_t q, mpz_t r, const mpz_t n, const mpz_t d)
+{
+  mpz_div_qr (q, r, n, d, GMP_DIV_TRUNC);
+}
+
+void
+mpz_cdiv_q (mpz_t q, const mpz_t n, const mpz_t d)
+{
+  mpz_div_qr (q, NULL, n, d, GMP_DIV_CEIL);
+}
+
+void
+mpz_fdiv_q (mpz_t q, const mpz_t n, const mpz_t d)
+{
+  mpz_div_qr (q, NULL, n, d, GMP_DIV_FLOOR);
+}
+
+void
+mpz_tdiv_q (mpz_t q, const mpz_t n, const mpz_t d)
+{
+  mpz_div_qr (q, NULL, n, d, GMP_DIV_TRUNC);
+}
+
+void
+mpz_cdiv_r (mpz_t r, const mpz_t n, const mpz_t d)
+{
+  mpz_div_qr (NULL, r, n, d, GMP_DIV_CEIL);
+}
+
+void
+mpz_fdiv_r (mpz_t r, const mpz_t n, const mpz_t d)
+{
+  mpz_div_qr (NULL, r, n, d, GMP_DIV_FLOOR);
+}
+
+void
+mpz_tdiv_r (mpz_t r, const mpz_t n, const mpz_t d)
+{
+  mpz_div_qr (NULL, r, n, d, GMP_DIV_TRUNC);
+}
+
+void
+mpz_mod (mpz_t r, const mpz_t n, const mpz_t d)
+{
+  mpz_div_qr (NULL, r, n, d, d->_mp_size >= 0 ? GMP_DIV_FLOOR : GMP_DIV_CEIL);
+}
+
+static void
+mpz_div_q_2exp (mpz_t q, const mpz_t u, mp_bitcnt_t bit_index,
+		enum mpz_div_round_mode mode)
+{
+  mp_size_t un, qn;
+  mp_size_t limb_cnt;
+  mp_ptr qp;
+  int adjust;
+
+  un = u->_mp_size;
+  if (un == 0)
+    {
+      q->_mp_size = 0;
+      return;
+    }
+  limb_cnt = bit_index / GMP_LIMB_BITS;
+  qn = GMP_ABS (un) - limb_cnt;
+  bit_index %= GMP_LIMB_BITS;
+
+  if (mode == ((un > 0) ? GMP_DIV_CEIL : GMP_DIV_FLOOR)) /* un != 0 here. */
+    /* Note: Below, the final indexing at limb_cnt is valid because at
+       that point we have qn > 0. */
+    adjust = (qn <= 0
+	      || !mpn_zero_p (u->_mp_d, limb_cnt)
+	      || (u->_mp_d[limb_cnt]
+		  & (((mp_limb_t) 1 << bit_index) - 1)));
+  else
+    adjust = 0;
+
+  if (qn <= 0)
+    qn = 0;
+  else
+    {
+      qp = MPZ_REALLOC (q, qn);
+
+      if (bit_index != 0)
+	{
+	  mpn_rshift (qp, u->_mp_d + limb_cnt, qn, bit_index);
+	  qn -= qp[qn - 1] == 0;
+	}
+      else
+	{
+	  mpn_copyi (qp, u->_mp_d + limb_cnt, qn);
+	}
+    }
+
+  q->_mp_size = qn;
+
+  if (adjust)
+    mpz_add_ui (q, q, 1);
+  if (un < 0)
+    mpz_neg (q, q);
+}
+
+static void
+mpz_div_r_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t bit_index,
+		enum mpz_div_round_mode mode)
+{
+  mp_size_t us, un, rn;
+  mp_ptr rp;
+  mp_limb_t mask;
+
+  us = u->_mp_size;
+  if (us == 0 || bit_index == 0)
+    {
+      r->_mp_size = 0;
+      return;
+    }
+  rn = (bit_index + GMP_LIMB_BITS - 1) / GMP_LIMB_BITS;
+  assert (rn > 0);
+
+  rp = MPZ_REALLOC (r, rn);
+  un = GMP_ABS (us);
+
+  mask = GMP_LIMB_MAX >> (rn * GMP_LIMB_BITS - bit_index);
+
+  if (rn > un)
+    {
+      /* Quotient (with truncation) is zero, and remainder is
+	 non-zero */
+      if (mode == ((us > 0) ? GMP_DIV_CEIL : GMP_DIV_FLOOR)) /* us != 0 here. */
+	{
+	  /* Have to negate and sign extend. */
+	  mp_size_t i;
+
+	  gmp_assert_nocarry (! mpn_neg (rp, u->_mp_d, un));
+	  for (i = un; i < rn - 1; i++)
+	    rp[i] = GMP_LIMB_MAX;
+
+	  rp[rn-1] = mask;
+	  us = -us;
+	}
+      else
+	{
+	  /* Just copy */
+	  if (r != u)
+	    mpn_copyi (rp, u->_mp_d, un);
+
+	  rn = un;
+	}
+    }
+  else
+    {
+      if (r != u)
+	mpn_copyi (rp, u->_mp_d, rn - 1);
+
+      rp[rn-1] = u->_mp_d[rn-1] & mask;
+
+      if (mode == ((us > 0) ? GMP_DIV_CEIL : GMP_DIV_FLOOR)) /* us != 0 here. */
+	{
+	  /* If r != 0, compute 2^{bit_count} - r. */
+	  mpn_neg (rp, rp, rn);
+
+	  rp[rn-1] &= mask;
+
+	  /* us is not used for anything else, so we can modify it
+	     here to indicate flipped sign. */
+	  us = -us;
+	}
+    }
+  rn = mpn_normalized_size (rp, rn);
+  r->_mp_size = us < 0 ? -rn : rn;
+}
+
+void
+mpz_cdiv_q_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt)
+{
+  mpz_div_q_2exp (r, u, cnt, GMP_DIV_CEIL);
+}
+
+void
+mpz_fdiv_q_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt)
+{
+  mpz_div_q_2exp (r, u, cnt, GMP_DIV_FLOOR);
+}
+
+void
+mpz_tdiv_q_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt)
+{
+  mpz_div_q_2exp (r, u, cnt, GMP_DIV_TRUNC);
+}
+
+void
+mpz_cdiv_r_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt)
+{
+  mpz_div_r_2exp (r, u, cnt, GMP_DIV_CEIL);
+}
+
+void
+mpz_fdiv_r_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt)
+{
+  mpz_div_r_2exp (r, u, cnt, GMP_DIV_FLOOR);
+}
+
+void
+mpz_tdiv_r_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt)
+{
+  mpz_div_r_2exp (r, u, cnt, GMP_DIV_TRUNC);
+}
+
+void
+mpz_divexact (mpz_t q, const mpz_t n, const mpz_t d)
+{
+  gmp_assert_nocarry (mpz_div_qr (q, NULL, n, d, GMP_DIV_TRUNC));
+}
+
+int
+mpz_divisible_p (const mpz_t n, const mpz_t d)
+{
+  return mpz_div_qr (NULL, NULL, n, d, GMP_DIV_TRUNC) == 0;
+}
+
+int
+mpz_congruent_p (const mpz_t a, const mpz_t b, const mpz_t m)
+{
+  mpz_t t;
+  int res;
+
+  /* a == b (mod 0) iff a == b */
+  if (mpz_sgn (m) == 0)
+    return (mpz_cmp (a, b) == 0);
+
+  mpz_init (t);
+  mpz_sub (t, a, b);
+  res = mpz_divisible_p (t, m);
+  mpz_clear (t);
+
+  return res;
+}
+
+static unsigned long
+mpz_div_qr_ui (mpz_t q, mpz_t r,
+	       const mpz_t n, unsigned long d, enum mpz_div_round_mode mode)
+{
+  unsigned long ret;
+  mpz_t rr, dd;
+
+  mpz_init (rr);
+  mpz_init_set_ui (dd, d);
+  mpz_div_qr (q, rr, n, dd, mode);
+  mpz_clear (dd);
+  ret = mpz_get_ui (rr);
+
+  if (r)
+    mpz_swap (r, rr);
+  mpz_clear (rr);
+
+  return ret;
+}
+
+unsigned long
+mpz_cdiv_qr_ui (mpz_t q, mpz_t r, const mpz_t n, unsigned long d)
+{
+  return mpz_div_qr_ui (q, r, n, d, GMP_DIV_CEIL);
+}
+
+unsigned long
+mpz_fdiv_qr_ui (mpz_t q, mpz_t r, const mpz_t n, unsigned long d)
+{
+  return mpz_div_qr_ui (q, r, n, d, GMP_DIV_FLOOR);
+}
+
+unsigned long
+mpz_tdiv_qr_ui (mpz_t q, mpz_t r, const mpz_t n, unsigned long d)
+{
+  return mpz_div_qr_ui (q, r, n, d, GMP_DIV_TRUNC);
+}
+
+unsigned long
+mpz_cdiv_q_ui (mpz_t q, const mpz_t n, unsigned long d)
+{
+  return mpz_div_qr_ui (q, NULL, n, d, GMP_DIV_CEIL);
+}
+
+unsigned long
+mpz_fdiv_q_ui (mpz_t q, const mpz_t n, unsigned long d)
+{
+  return mpz_div_qr_ui (q, NULL, n, d, GMP_DIV_FLOOR);
+}
+
+unsigned long
+mpz_tdiv_q_ui (mpz_t q, const mpz_t n, unsigned long d)
+{
+  return mpz_div_qr_ui (q, NULL, n, d, GMP_DIV_TRUNC);
+}
+
+unsigned long
+mpz_cdiv_r_ui (mpz_t r, const mpz_t n, unsigned long d)
+{
+  return mpz_div_qr_ui (NULL, r, n, d, GMP_DIV_CEIL);
+}
+unsigned long
+mpz_fdiv_r_ui (mpz_t r, const mpz_t n, unsigned long d)
+{
+  return mpz_div_qr_ui (NULL, r, n, d, GMP_DIV_FLOOR);
+}
+unsigned long
+mpz_tdiv_r_ui (mpz_t r, const mpz_t n, unsigned long d)
+{
+  return mpz_div_qr_ui (NULL, r, n, d, GMP_DIV_TRUNC);
+}
+
+unsigned long
+mpz_cdiv_ui (const mpz_t n, unsigned long d)
+{
+  return mpz_div_qr_ui (NULL, NULL, n, d, GMP_DIV_CEIL);
+}
+
+unsigned long
+mpz_fdiv_ui (const mpz_t n, unsigned long d)
+{
+  return mpz_div_qr_ui (NULL, NULL, n, d, GMP_DIV_FLOOR);
+}
+
+unsigned long
+mpz_tdiv_ui (const mpz_t n, unsigned long d)
+{
+  return mpz_div_qr_ui (NULL, NULL, n, d, GMP_DIV_TRUNC);
+}
+
+unsigned long
+mpz_mod_ui (mpz_t r, const mpz_t n, unsigned long d)
+{
+  return mpz_div_qr_ui (NULL, r, n, d, GMP_DIV_FLOOR);
+}
+
+void
+mpz_divexact_ui (mpz_t q, const mpz_t n, unsigned long d)
+{
+  gmp_assert_nocarry (mpz_div_qr_ui (q, NULL, n, d, GMP_DIV_TRUNC));
+}
+
+int
+mpz_divisible_ui_p (const mpz_t n, unsigned long d)
+{
+  return mpz_div_qr_ui (NULL, NULL, n, d, GMP_DIV_TRUNC) == 0;
+}
+
+
+/* GCD */
+static mp_limb_t
+mpn_gcd_11 (mp_limb_t u, mp_limb_t v)
+{
+  unsigned shift;
+
+  assert ( (u | v) > 0);
+
+  if (u == 0)
+    return v;
+  else if (v == 0)
+    return u;
+
+  gmp_ctz (shift, u | v);
+
+  u >>= shift;
+  v >>= shift;
+
+  if ( (u & 1) == 0)
+    MP_LIMB_T_SWAP (u, v);
+
+  while ( (v & 1) == 0)
+    v >>= 1;
+
+  while (u != v)
+    {
+      if (u > v)
+	{
+	  u -= v;
+	  do
+	    u >>= 1;
+	  while ( (u & 1) == 0);
+	}
+      else
+	{
+	  v -= u;
+	  do
+	    v >>= 1;
+	  while ( (v & 1) == 0);
+	}
+    }
+  return u << shift;
+}
+
+unsigned long
+mpz_gcd_ui (mpz_t g, const mpz_t u, unsigned long v)
+{
+  mpz_t t;
+  mpz_init_set_ui(t, v);
+  mpz_gcd (t, u, t);
+  if (v > 0)
+    v = mpz_get_ui (t);
+
+  if (g)
+    mpz_swap (t, g);
+
+  mpz_clear (t);
+
+  return v;
+}
+
+static mp_bitcnt_t
+mpz_make_odd (mpz_t r)
+{
+  mp_bitcnt_t shift;
+
+  assert (r->_mp_size > 0);
+  /* Count trailing zeros, equivalent to mpn_scan1, because we know that there is a 1 */
+  shift = mpn_common_scan (r->_mp_d[0], 0, r->_mp_d, 0, 0);
+  mpz_tdiv_q_2exp (r, r, shift);
+
+  return shift;
+}
+
+void
+mpz_gcd (mpz_t g, const mpz_t u, const mpz_t v)
+{
+  mpz_t tu, tv;
+  mp_bitcnt_t uz, vz, gz;
+
+  if (u->_mp_size == 0)
+    {
+      mpz_abs (g, v);
+      return;
+    }
+  if (v->_mp_size == 0)
+    {
+      mpz_abs (g, u);
+      return;
+    }
+
+  mpz_init (tu);
+  mpz_init (tv);
+
+  mpz_abs (tu, u);
+  uz = mpz_make_odd (tu);
+  mpz_abs (tv, v);
+  vz = mpz_make_odd (tv);
+  gz = GMP_MIN (uz, vz);
+
+  if (tu->_mp_size < tv->_mp_size)
+    mpz_swap (tu, tv);
+
+  mpz_tdiv_r (tu, tu, tv);
+  if (tu->_mp_size == 0)
+    {
+      mpz_swap (g, tv);
+    }
+  else
+    for (;;)
+      {
+	int c;
+
+	mpz_make_odd (tu);
+	c = mpz_cmp (tu, tv);
+	if (c == 0)
+	  {
+	    mpz_swap (g, tu);
+	    break;
+	  }
+	if (c < 0)
+	  mpz_swap (tu, tv);
+
+	if (tv->_mp_size == 1)
+	  {
+	    mp_limb_t vl = tv->_mp_d[0];
+	    mp_limb_t ul = mpz_tdiv_ui (tu, vl);
+	    mpz_set_ui (g, mpn_gcd_11 (ul, vl));
+	    break;
+	  }
+	mpz_sub (tu, tu, tv);
+      }
+  mpz_clear (tu);
+  mpz_clear (tv);
+  mpz_mul_2exp (g, g, gz);
+}
+
+void
+mpz_gcdext (mpz_t g, mpz_t s, mpz_t t, const mpz_t u, const mpz_t v)
+{
+  mpz_t tu, tv, s0, s1, t0, t1;
+  mp_bitcnt_t uz, vz, gz;
+  mp_bitcnt_t power;
+
+  if (u->_mp_size == 0)
+    {
+      /* g = 0 u + sgn(v) v */
+      signed long sign = mpz_sgn (v);
+      mpz_abs (g, v);
+      if (s)
+	s->_mp_size = 0;
+      if (t)
+	mpz_set_si (t, sign);
+      return;
+    }
+
+  if (v->_mp_size == 0)
+    {
+      /* g = sgn(u) u + 0 v */
+      signed long sign = mpz_sgn (u);
+      mpz_abs (g, u);
+      if (s)
+	mpz_set_si (s, sign);
+      if (t)
+	t->_mp_size = 0;
+      return;
+    }
+
+  mpz_init (tu);
+  mpz_init (tv);
+  mpz_init (s0);
+  mpz_init (s1);
+  mpz_init (t0);
+  mpz_init (t1);
+
+  mpz_abs (tu, u);
+  uz = mpz_make_odd (tu);
+  mpz_abs (tv, v);
+  vz = mpz_make_odd (tv);
+  gz = GMP_MIN (uz, vz);
+
+  uz -= gz;
+  vz -= gz;
+
+  /* Cofactors corresponding to odd gcd. gz handled later. */
+  if (tu->_mp_size < tv->_mp_size)
+    {
+      mpz_swap (tu, tv);
+      MPZ_SRCPTR_SWAP (u, v);
+      MPZ_PTR_SWAP (s, t);
+      MP_BITCNT_T_SWAP (uz, vz);
+    }
+
+  /* Maintain
+   *
+   * u = t0 tu + t1 tv
+   * v = s0 tu + s1 tv
+   *
+   * where u and v denote the inputs with common factors of two
+   * eliminated, and det (s0, t0; s1, t1) = 2^p. Then
+   *
+   * 2^p tu =  s1 u - t1 v
+   * 2^p tv = -s0 u + t0 v
+   */
+
+  /* After initial division, tu = q tv + tu', we have
+   *
+   * u = 2^uz (tu' + q tv)
+   * v = 2^vz tv
+   *
+   * or
+   *
+   * t0 = 2^uz, t1 = 2^uz q
+   * s0 = 0,    s1 = 2^vz
+   */
+
+  mpz_setbit (t0, uz);
+  mpz_tdiv_qr (t1, tu, tu, tv);
+  mpz_mul_2exp (t1, t1, uz);
+
+  mpz_setbit (s1, vz);
+  power = uz + vz;
+
+  if (tu->_mp_size > 0)
+    {
+      mp_bitcnt_t shift;
+      shift = mpz_make_odd (tu);
+      mpz_mul_2exp (t0, t0, shift);
+      mpz_mul_2exp (s0, s0, shift);
+      power += shift;
+
+      for (;;)
+	{
+	  int c;
+	  c = mpz_cmp (tu, tv);
+	  if (c == 0)
+	    break;
+
+	  if (c < 0)
+	    {
+	      /* tv = tv' + tu
+	       *
+	       * u = t0 tu + t1 (tv' + tu) = (t0 + t1) tu + t1 tv'
+	       * v = s0 tu + s1 (tv' + tu) = (s0 + s1) tu + s1 tv' */
+
+	      mpz_sub (tv, tv, tu);
+	      mpz_add (t0, t0, t1);
+	      mpz_add (s0, s0, s1);
+
+	      shift = mpz_make_odd (tv);
+	      mpz_mul_2exp (t1, t1, shift);
+	      mpz_mul_2exp (s1, s1, shift);
+	    }
+	  else
+	    {
+	      mpz_sub (tu, tu, tv);
+	      mpz_add (t1, t0, t1);
+	      mpz_add (s1, s0, s1);
+
+	      shift = mpz_make_odd (tu);
+	      mpz_mul_2exp (t0, t0, shift);
+	      mpz_mul_2exp (s0, s0, shift);
+	    }
+	  power += shift;
+	}
+    }
+
+  /* Now tv = odd part of gcd, and -s0 and t0 are corresponding
+     cofactors. */
+
+  mpz_mul_2exp (tv, tv, gz);
+  mpz_neg (s0, s0);
+
+  /* 2^p g = s0 u + t0 v. Eliminate one factor of two at a time. To
+     adjust cofactors, we need u / g and v / g */
+
+  mpz_divexact (s1, v, tv);
+  mpz_abs (s1, s1);
+  mpz_divexact (t1, u, tv);
+  mpz_abs (t1, t1);
+
+  while (power-- > 0)
+    {
+      /* s0 u + t0 v = (s0 - v/g) u - (t0 + u/g) v */
+      if (mpz_odd_p (s0) || mpz_odd_p (t0))
+	{
+	  mpz_sub (s0, s0, s1);
+	  mpz_add (t0, t0, t1);
+	}
+      assert (mpz_even_p (t0) && mpz_even_p (s0));
+      mpz_tdiv_q_2exp (s0, s0, 1);
+      mpz_tdiv_q_2exp (t0, t0, 1);
+    }
+
+  /* Arrange so that |s| < |u| / 2g */
+  mpz_add (s1, s0, s1);
+  if (mpz_cmpabs (s0, s1) > 0)
+    {
+      mpz_swap (s0, s1);
+      mpz_sub (t0, t0, t1);
+    }
+  if (u->_mp_size < 0)
+    mpz_neg (s0, s0);
+  if (v->_mp_size < 0)
+    mpz_neg (t0, t0);
+
+  mpz_swap (g, tv);
+  if (s)
+    mpz_swap (s, s0);
+  if (t)
+    mpz_swap (t, t0);
+
+  mpz_clear (tu);
+  mpz_clear (tv);
+  mpz_clear (s0);
+  mpz_clear (s1);
+  mpz_clear (t0);
+  mpz_clear (t1);
+}
+
+void
+mpz_lcm (mpz_t r, const mpz_t u, const mpz_t v)
+{
+  mpz_t g;
+
+  if (u->_mp_size == 0 || v->_mp_size == 0)
+    {
+      r->_mp_size = 0;
+      return;
+    }
+
+  mpz_init (g);
+
+  mpz_gcd (g, u, v);
+  mpz_divexact (g, u, g);
+  mpz_mul (r, g, v);
+
+  mpz_clear (g);
+  mpz_abs (r, r);
+}
+
+void
+mpz_lcm_ui (mpz_t r, const mpz_t u, unsigned long v)
+{
+  if (v == 0 || u->_mp_size == 0)
+    {
+      r->_mp_size = 0;
+      return;
+    }
+
+  v /= mpz_gcd_ui (NULL, u, v);
+  mpz_mul_ui (r, u, v);
+
+  mpz_abs (r, r);
+}
+
+int
+mpz_invert (mpz_t r, const mpz_t u, const mpz_t m)
+{
+  mpz_t g, tr;
+  int invertible;
+
+  if (u->_mp_size == 0 || mpz_cmpabs_ui (m, 1) <= 0)
+    return 0;
+
+  mpz_init (g);
+  mpz_init (tr);
+
+  mpz_gcdext (g, tr, NULL, u, m);
+  invertible = (mpz_cmp_ui (g, 1) == 0);
+
+  if (invertible)
+    {
+      if (tr->_mp_size < 0)
+	{
+	  if (m->_mp_size >= 0)
+	    mpz_add (tr, tr, m);
+	  else
+	    mpz_sub (tr, tr, m);
+	}
+      mpz_swap (r, tr);
+    }
+
+  mpz_clear (g);
+  mpz_clear (tr);
+  return invertible;
+}
+
+
+/* Higher level operations (sqrt, pow and root) */
+
+void
+mpz_pow_ui (mpz_t r, const mpz_t b, unsigned long e)
+{
+  unsigned long bit;
+  mpz_t tr;
+  mpz_init_set_ui (tr, 1);
+
+  bit = GMP_ULONG_HIGHBIT;
+  do
+    {
+      mpz_mul (tr, tr, tr);
+      if (e & bit)
+	mpz_mul (tr, tr, b);
+      bit >>= 1;
+    }
+  while (bit > 0);
+
+  mpz_swap (r, tr);
+  mpz_clear (tr);
+}
+
+void
+mpz_ui_pow_ui (mpz_t r, unsigned long blimb, unsigned long e)
+{
+  mpz_t b;
+
+  mpz_init_set_ui (b, blimb);
+  mpz_pow_ui (r, b, e);
+  mpz_clear (b);
+}
+
+void
+mpz_powm (mpz_t r, const mpz_t b, const mpz_t e, const mpz_t m)
+{
+  mpz_t tr;
+  mpz_t base;
+  mp_size_t en, mn;
+  mp_srcptr mp;
+  struct gmp_div_inverse minv;
+  unsigned shift;
+  mp_ptr tp = NULL;
+
+  en = GMP_ABS (e->_mp_size);
+  mn = GMP_ABS (m->_mp_size);
+  if (mn == 0)
+    gmp_die ("mpz_powm: Zero modulo.");
+
+  if (en == 0)
+    {
+      mpz_set_ui (r, 1);
+      return;
+    }
+
+  mp = m->_mp_d;
+  mpn_div_qr_invert (&minv, mp, mn);
+  shift = minv.shift;
+
+  if (shift > 0)
+    {
+      /* To avoid shifts, we do all our reductions, except the final
+	 one, using a *normalized* m. */
+      minv.shift = 0;
+
+      tp = gmp_xalloc_limbs (mn);
+      gmp_assert_nocarry (mpn_lshift (tp, mp, mn, shift));
+      mp = tp;
+    }
+
+  mpz_init (base);
+
+  if (e->_mp_size < 0)
+    {
+      if (!mpz_invert (base, b, m))
+	gmp_die ("mpz_powm: Negative exponent and non-invertible base.");
+    }
+  else
+    {
+      mp_size_t bn;
+      mpz_abs (base, b);
+
+      bn = base->_mp_size;
+      if (bn >= mn)
+	{
+	  mpn_div_qr_preinv (NULL, base->_mp_d, base->_mp_size, mp, mn, &minv);
+	  bn = mn;
+	}
+
+      /* We have reduced the absolute value. Now take care of the
+	 sign. Note that we get zero represented non-canonically as
+	 m. */
+      if (b->_mp_size < 0)
+	{
+	  mp_ptr bp = MPZ_REALLOC (base, mn);
+	  gmp_assert_nocarry (mpn_sub (bp, mp, mn, bp, bn));
+	  bn = mn;
+	}
+      base->_mp_size = mpn_normalized_size (base->_mp_d, bn);
+    }
+  mpz_init_set_ui (tr, 1);
+
+  while (--en >= 0)
+    {
+      mp_limb_t w = e->_mp_d[en];
+      mp_limb_t bit;
+
+      bit = GMP_LIMB_HIGHBIT;
+      do
+	{
+	  mpz_mul (tr, tr, tr);
+	  if (w & bit)
+	    mpz_mul (tr, tr, base);
+	  if (tr->_mp_size > mn)
+	    {
+	      mpn_div_qr_preinv (NULL, tr->_mp_d, tr->_mp_size, mp, mn, &minv);
+	      tr->_mp_size = mpn_normalized_size (tr->_mp_d, mn);
+	    }
+	  bit >>= 1;
+	}
+      while (bit > 0);
+    }
+
+  /* Final reduction */
+  if (tr->_mp_size >= mn)
+    {
+      minv.shift = shift;
+      mpn_div_qr_preinv (NULL, tr->_mp_d, tr->_mp_size, mp, mn, &minv);
+      tr->_mp_size = mpn_normalized_size (tr->_mp_d, mn);
+    }
+  if (tp)
+    gmp_free (tp);
+
+  mpz_swap (r, tr);
+  mpz_clear (tr);
+  mpz_clear (base);
+}
+
+void
+mpz_powm_ui (mpz_t r, const mpz_t b, unsigned long elimb, const mpz_t m)
+{
+  mpz_t e;
+
+  mpz_init_set_ui (e, elimb);
+  mpz_powm (r, b, e, m);
+  mpz_clear (e);
+}
+
+/* x=trunc(y^(1/z)), r=y-x^z */
+void
+mpz_rootrem (mpz_t x, mpz_t r, const mpz_t y, unsigned long z)
+{
+  int sgn;
+  mpz_t t, u;
+
+  sgn = y->_mp_size < 0;
+  if ((~z & sgn) != 0)
+    gmp_die ("mpz_rootrem: Negative argument, with even root.");
+  if (z == 0)
+    gmp_die ("mpz_rootrem: Zeroth root.");
+
+  if (mpz_cmpabs_ui (y, 1) <= 0) {
+    if (x)
+      mpz_set (x, y);
+    if (r)
+      r->_mp_size = 0;
+    return;
+  }
+
+  mpz_init (u);
+  mpz_init (t);
+  mpz_setbit (t, mpz_sizeinbase (y, 2) / z + 1);
+
+  if (z == 2) /* simplify sqrt loop: z-1 == 1 */
+    do {
+      mpz_swap (u, t);			/* u = x */
+      mpz_tdiv_q (t, y, u);		/* t = y/x */
+      mpz_add (t, t, u);		/* t = y/x + x */
+      mpz_tdiv_q_2exp (t, t, 1);	/* x'= (y/x + x)/2 */
+    } while (mpz_cmpabs (t, u) < 0);	/* |x'| < |x| */
+  else /* z != 2 */ {
+    mpz_t v;
+
+    mpz_init (v);
+    if (sgn)
+      mpz_neg (t, t);
+
+    do {
+      mpz_swap (u, t);			/* u = x */
+      mpz_pow_ui (t, u, z - 1);		/* t = x^(z-1) */
+      mpz_tdiv_q (t, y, t);		/* t = y/x^(z-1) */
+      mpz_mul_ui (v, u, z - 1);		/* v = x*(z-1) */
+      mpz_add (t, t, v);		/* t = y/x^(z-1) + x*(z-1) */
+      mpz_tdiv_q_ui (t, t, z);		/* x'=(y/x^(z-1) + x*(z-1))/z */
+    } while (mpz_cmpabs (t, u) < 0);	/* |x'| < |x| */
+
+    mpz_clear (v);
+  }
+
+  if (r) {
+    mpz_pow_ui (t, u, z);
+    mpz_sub (r, y, t);
+  }
+  if (x)
+    mpz_swap (x, u);
+  mpz_clear (u);
+  mpz_clear (t);
+}
+
+int
+mpz_root (mpz_t x, const mpz_t y, unsigned long z)
+{
+  int res;
+  mpz_t r;
+
+  mpz_init (r);
+  mpz_rootrem (x, r, y, z);
+  res = r->_mp_size == 0;
+  mpz_clear (r);
+
+  return res;
+}
+
+/* Compute s = floor(sqrt(u)) and r = u - s^2. Allows r == NULL */
+void
+mpz_sqrtrem (mpz_t s, mpz_t r, const mpz_t u)
+{
+  mpz_rootrem (s, r, u, 2);
+}
+
+void
+mpz_sqrt (mpz_t s, const mpz_t u)
+{
+  mpz_rootrem (s, NULL, u, 2);
+}
+
+int
+mpz_perfect_square_p (const mpz_t u)
+{
+  if (u->_mp_size <= 0)
+    return (u->_mp_size == 0);
+  else
+    return mpz_root (NULL, u, 2);
+}
+
+int
+mpn_perfect_square_p (mp_srcptr p, mp_size_t n)
+{
+  mpz_t t;
+
+  assert (n > 0);
+  assert (p [n-1] != 0);
+  return mpz_root (NULL, mpz_roinit_normal_n (t, p, n), 2);
+}
+
+mp_size_t
+mpn_sqrtrem (mp_ptr sp, mp_ptr rp, mp_srcptr p, mp_size_t n)
+{
+  mpz_t s, r, u;
+  mp_size_t res;
+
+  assert (n > 0);
+  assert (p [n-1] != 0);
+
+  mpz_init (r);
+  mpz_init (s);
+  mpz_rootrem (s, r, mpz_roinit_normal_n (u, p, n), 2);
+
+  assert (s->_mp_size == (n+1)/2);
+  mpn_copyd (sp, s->_mp_d, s->_mp_size);
+  mpz_clear (s);
+  res = r->_mp_size;
+  if (rp)
+    mpn_copyd (rp, r->_mp_d, res);
+  mpz_clear (r);
+  return res;
+}
+
+/* Combinatorics */
+
+void
+mpz_mfac_uiui (mpz_t x, unsigned long n, unsigned long m)
+{
+  mpz_set_ui (x, n + (n == 0));
+  if (m + 1 < 2) return;
+  while (n > m + 1)
+    mpz_mul_ui (x, x, n -= m);
+}
+
+void
+mpz_2fac_ui (mpz_t x, unsigned long n)
+{
+  mpz_mfac_uiui (x, n, 2);
+}
+
+void
+mpz_fac_ui (mpz_t x, unsigned long n)
+{
+  mpz_mfac_uiui (x, n, 1);
+}
+
+void
+mpz_bin_uiui (mpz_t r, unsigned long n, unsigned long k)
+{
+  mpz_t t;
+
+  mpz_set_ui (r, k <= n);
+
+  if (k > (n >> 1))
+    k = (k <= n) ? n - k : 0;
+
+  mpz_init (t);
+  mpz_fac_ui (t, k);
+
+  for (; k > 0; --k)
+    mpz_mul_ui (r, r, n--);
+
+  mpz_divexact (r, r, t);
+  mpz_clear (t);
+}
+
+
+/* Primality testing */
+
+/* Computes Kronecker (a/b) with odd b, a!=0 and GCD(a,b) = 1 */
+/* Adapted from JACOBI_BASE_METHOD==4 in mpn/generic/jacbase.c */
+static int
+gmp_jacobi_coprime (mp_limb_t a, mp_limb_t b)
+{
+  int c, bit = 0;
+
+  assert (b & 1);
+  assert (a != 0);
+  /* assert (mpn_gcd_11 (a, b) == 1); */
+
+  /* Below, we represent a and b shifted right so that the least
+     significant one bit is implicit. */
+  b >>= 1;
+
+  gmp_ctz(c, a);
+  a >>= 1;
+
+  do
+    {
+      a >>= c;
+      /* (2/b) = -1 if b = 3 or 5 mod 8 */
+      bit ^= c & (b ^ (b >> 1));
+      if (a < b)
+	{
+	  bit ^= a & b;
+	  a = b - a;
+	  b -= a;
+	}
+      else
+	{
+	  a -= b;
+	  assert (a != 0);
+	}
+
+      gmp_ctz(c, a);
+      ++c;
+    }
+  while (b > 0);
+
+  return bit & 1 ? -1 : 1;
+}
+
+static void
+gmp_lucas_step_k_2k (mpz_t V, mpz_t Qk, const mpz_t n)
+{
+  mpz_mod (Qk, Qk, n);
+  /* V_{2k} <- V_k ^ 2 - 2Q^k */
+  mpz_mul (V, V, V);
+  mpz_submul_ui (V, Qk, 2);
+  mpz_tdiv_r (V, V, n);
+  /* Q^{2k} = (Q^k)^2 */
+  mpz_mul (Qk, Qk, Qk);
+}
+
+/* Computes V_k, Q^k (mod n) for the Lucas' sequence */
+/* with P=1, Q=Q; k = (n>>b0)|1. */
+/* Requires an odd n > 4; b0 > 0; -2*Q must not overflow a long */
+/* Returns (U_k == 0) and sets V=V_k and Qk=Q^k. */
+static int
+gmp_lucas_mod (mpz_t V, mpz_t Qk, long Q,
+	       mp_bitcnt_t b0, const mpz_t n)
+{
+  mp_bitcnt_t bs;
+  mpz_t U;
+  int res;
+
+  assert (b0 > 0);
+  assert (Q <= - (LONG_MIN / 2));
+  assert (Q >= - (LONG_MAX / 2));
+  assert (mpz_cmp_ui (n, 4) > 0);
+  assert (mpz_odd_p (n));
+
+  mpz_init_set_ui (U, 1); /* U1 = 1 */
+  mpz_set_ui (V, 1); /* V1 = 1 */
+  mpz_set_si (Qk, Q);
+
+  for (bs = mpz_sizeinbase (n, 2) - 1; --bs >= b0;)
+    {
+      /* U_{2k} <- U_k * V_k */
+      mpz_mul (U, U, V);
+      /* V_{2k} <- V_k ^ 2 - 2Q^k */
+      /* Q^{2k} = (Q^k)^2 */
+      gmp_lucas_step_k_2k (V, Qk, n);
+
+      /* A step k->k+1 is performed if the bit in $n$ is 1	*/
+      /* mpz_tstbit(n,bs) or the the bit is 0 in $n$ but	*/
+      /* should be 1 in $n+1$ (bs == b0)			*/
+      if (b0 == bs || mpz_tstbit (n, bs))
+	{
+	  /* Q^{k+1} <- Q^k * Q */
+	  mpz_mul_si (Qk, Qk, Q);
+	  /* U_{k+1} <- (U_k + V_k) / 2 */
+	  mpz_swap (U, V); /* Keep in V the old value of U_k */
+	  mpz_add (U, U, V);
+	  /* We have to compute U/2, so we need an even value, */
+	  /* equivalent (mod n) */
+	  if (mpz_odd_p (U))
+	    mpz_add (U, U, n);
+	  mpz_tdiv_q_2exp (U, U, 1);
+	  /* V_{k+1} <-(D*U_k + V_k) / 2 =
+			U_{k+1} + (D-1)/2*U_k = U_{k+1} - 2Q*U_k */
+	  mpz_mul_si (V, V, -2*Q);
+	  mpz_add (V, U, V);
+	  mpz_tdiv_r (V, V, n);
+	}
+      mpz_tdiv_r (U, U, n);
+    }
+
+  res = U->_mp_size == 0;
+  mpz_clear (U);
+  return res;
+}
+
+/* Performs strong Lucas' test on x, with parameters suggested */
+/* for the BPSW test. Qk is only passed to recycle a variable. */
+/* Requires GCD (x,6) = 1.*/
+static int
+gmp_stronglucas (const mpz_t x, mpz_t Qk)
+{
+  mp_bitcnt_t b0;
+  mpz_t V, n;
+  mp_limb_t maxD, D; /* The absolute value is stored. */
+  long Q;
+  mp_limb_t tl;
+
+  /* Test on the absolute value. */
+  mpz_roinit_normal_n (n, x->_mp_d, GMP_ABS (x->_mp_size));
+
+  assert (mpz_odd_p (n));
+  /* assert (mpz_gcd_ui (NULL, n, 6) == 1); */
+  if (mpz_root (Qk, n, 2))
+    return 0; /* A square is composite. */
+
+  /* Check Ds up to square root (in case, n is prime)
+     or avoid overflows */
+  maxD = (Qk->_mp_size == 1) ? Qk->_mp_d [0] - 1 : GMP_LIMB_MAX;
+
+  D = 3;
+  /* Search a D such that (D/n) = -1 in the sequence 5,-7,9,-11,.. */
+  /* For those Ds we have (D/n) = (n/|D|) */
+  do
+    {
+      if (D >= maxD)
+	return 1 + (D != GMP_LIMB_MAX); /* (1 + ! ~ D) */
+      D += 2;
+      tl = mpz_tdiv_ui (n, D);
+      if (tl == 0)
+	return 0;
+    }
+  while (gmp_jacobi_coprime (tl, D) == 1);
+
+  mpz_init (V);
+
+  /* n-(D/n) = n+1 = d*2^{b0}, with d = (n>>b0) | 1 */
+  b0 = mpz_scan0 (n, 0);
+
+  /* D= P^2 - 4Q; P = 1; Q = (1-D)/4 */
+  Q = (D & 2) ? (long) (D >> 2) + 1 : -(long) (D >> 2);
+
+  if (! gmp_lucas_mod (V, Qk, Q, b0, n))	/* If Ud != 0 */
+    while (V->_mp_size != 0 && --b0 != 0)	/* while Vk != 0 */
+      /* V <- V ^ 2 - 2Q^k */
+      /* Q^{2k} = (Q^k)^2 */
+      gmp_lucas_step_k_2k (V, Qk, n);
+
+  mpz_clear (V);
+  return (b0 != 0);
+}
+
+static int
+gmp_millerrabin (const mpz_t n, const mpz_t nm1, mpz_t y,
+		 const mpz_t q, mp_bitcnt_t k)
+{
+  assert (k > 0);
+
+  /* Caller must initialize y to the base. */
+  mpz_powm (y, y, q, n);
+
+  if (mpz_cmp_ui (y, 1) == 0 || mpz_cmp (y, nm1) == 0)
+    return 1;
+
+  while (--k > 0)
+    {
+      mpz_powm_ui (y, y, 2, n);
+      if (mpz_cmp (y, nm1) == 0)
+	return 1;
+      /* y == 1 means that the previous y was a non-trivial square root
+	 of 1 (mod n). y == 0 means that n is a power of the base.
+	 In either case, n is not prime. */
+      if (mpz_cmp_ui (y, 1) <= 0)
+	return 0;
+    }
+  return 0;
+}
+
+/* This product is 0xc0cfd797, and fits in 32 bits. */
+#define GMP_PRIME_PRODUCT \
+  (3UL*5UL*7UL*11UL*13UL*17UL*19UL*23UL*29UL)
+
+/* Bit (p+1)/2 is set, for each odd prime <= 61 */
+#define GMP_PRIME_MASK 0xc96996dcUL
+
+int
+mpz_probab_prime_p (const mpz_t n, int reps)
+{
+  mpz_t nm1;
+  mpz_t q;
+  mpz_t y;
+  mp_bitcnt_t k;
+  int is_prime;
+  int j;
+
+  /* Note that we use the absolute value of n only, for compatibility
+     with the real GMP. */
+  if (mpz_even_p (n))
+    return (mpz_cmpabs_ui (n, 2) == 0) ? 2 : 0;
+
+  /* Above test excludes n == 0 */
+  assert (n->_mp_size != 0);
+
+  if (mpz_cmpabs_ui (n, 64) < 0)
+    return (GMP_PRIME_MASK >> (n->_mp_d[0] >> 1)) & 2;
+
+  if (mpz_gcd_ui (NULL, n, GMP_PRIME_PRODUCT) != 1)
+    return 0;
+
+  /* All prime factors are >= 31. */
+  if (mpz_cmpabs_ui (n, 31*31) < 0)
+    return 2;
+
+  mpz_init (nm1);
+  mpz_init (q);
+
+  /* Find q and k, where q is odd and n = 1 + 2**k * q.  */
+  mpz_abs (nm1, n);
+  nm1->_mp_d[0] -= 1;
+  k = mpz_scan1 (nm1, 0);
+  mpz_tdiv_q_2exp (q, nm1, k);
+
+  /* BPSW test */
+  mpz_init_set_ui (y, 2);
+  is_prime = gmp_millerrabin (n, nm1, y, q, k) && gmp_stronglucas (n, y);
+  reps -= 24; /* skip the first 24 repetitions */
+
+  /* Use Miller-Rabin, with a deterministic sequence of bases, a[j] =
+     j^2 + j + 41 using Euler's polynomial. We potentially stop early,
+     if a[j] >= n - 1. Since n >= 31*31, this can happen only if reps >
+     30 (a[30] == 971 > 31*31 == 961). */
+
+  for (j = 0; is_prime & (j < reps); j++)
+    {
+      mpz_set_ui (y, (unsigned long) j*j+j+41);
+      if (mpz_cmp (y, nm1) >= 0)
+	{
+	  /* Don't try any further bases. This "early" break does not affect
+	     the result for any reasonable reps value (<=5000 was tested) */
+	  assert (j >= 30);
+	  break;
+	}
+      is_prime = gmp_millerrabin (n, nm1, y, q, k);
+    }
+  mpz_clear (nm1);
+  mpz_clear (q);
+  mpz_clear (y);
+
+  return is_prime;
+}
+
+
+/* Logical operations and bit manipulation. */
+
+/* Numbers are treated as if represented in two's complement (and
+   infinitely sign extended). For a negative values we get the two's
+   complement from -x = ~x + 1, where ~ is bitwise complement.
+   Negation transforms
+
+     xxxx10...0
+
+   into
+
+     yyyy10...0
+
+   where yyyy is the bitwise complement of xxxx. So least significant
+   bits, up to and including the first one bit, are unchanged, and
+   the more significant bits are all complemented.
+
+   To change a bit from zero to one in a negative number, subtract the
+   corresponding power of two from the absolute value. This can never
+   underflow. To change a bit from one to zero, add the corresponding
+   power of two, and this might overflow. E.g., if x = -001111, the
+   two's complement is 110001. Clearing the least significant bit, we
+   get two's complement 110000, and -010000. */
+
+int
+mpz_tstbit (const mpz_t d, mp_bitcnt_t bit_index)
+{
+  mp_size_t limb_index;
+  unsigned shift;
+  mp_size_t ds;
+  mp_size_t dn;
+  mp_limb_t w;
+  int bit;
+
+  ds = d->_mp_size;
+  dn = GMP_ABS (ds);
+  limb_index = bit_index / GMP_LIMB_BITS;
+  if (limb_index >= dn)
+    return ds < 0;
+
+  shift = bit_index % GMP_LIMB_BITS;
+  w = d->_mp_d[limb_index];
+  bit = (w >> shift) & 1;
+
+  if (ds < 0)
+    {
+      /* d < 0. Check if any of the bits below is set: If so, our bit
+	 must be complemented. */
+      if (shift > 0 && (mp_limb_t) (w << (GMP_LIMB_BITS - shift)) > 0)
+	return bit ^ 1;
+      while (--limb_index >= 0)
+	if (d->_mp_d[limb_index] > 0)
+	  return bit ^ 1;
+    }
+  return bit;
+}
+
+static void
+mpz_abs_add_bit (mpz_t d, mp_bitcnt_t bit_index)
+{
+  mp_size_t dn, limb_index;
+  mp_limb_t bit;
+  mp_ptr dp;
+
+  dn = GMP_ABS (d->_mp_size);
+
+  limb_index = bit_index / GMP_LIMB_BITS;
+  bit = (mp_limb_t) 1 << (bit_index % GMP_LIMB_BITS);
+
+  if (limb_index >= dn)
+    {
+      mp_size_t i;
+      /* The bit should be set outside of the end of the number.
+	 We have to increase the size of the number. */
+      dp = MPZ_REALLOC (d, limb_index + 1);
+
+      dp[limb_index] = bit;
+      for (i = dn; i < limb_index; i++)
+	dp[i] = 0;
+      dn = limb_index + 1;
+    }
+  else
+    {
+      mp_limb_t cy;
+
+      dp = d->_mp_d;
+
+      cy = mpn_add_1 (dp + limb_index, dp + limb_index, dn - limb_index, bit);
+      if (cy > 0)
+	{
+	  dp = MPZ_REALLOC (d, dn + 1);
+	  dp[dn++] = cy;
+	}
+    }
+
+  d->_mp_size = (d->_mp_size < 0) ? - dn : dn;
+}
+
+static void
+mpz_abs_sub_bit (mpz_t d, mp_bitcnt_t bit_index)
+{
+  mp_size_t dn, limb_index;
+  mp_ptr dp;
+  mp_limb_t bit;
+
+  dn = GMP_ABS (d->_mp_size);
+  dp = d->_mp_d;
+
+  limb_index = bit_index / GMP_LIMB_BITS;
+  bit = (mp_limb_t) 1 << (bit_index % GMP_LIMB_BITS);
+
+  assert (limb_index < dn);
+
+  gmp_assert_nocarry (mpn_sub_1 (dp + limb_index, dp + limb_index,
+				 dn - limb_index, bit));
+  dn = mpn_normalized_size (dp, dn);
+  d->_mp_size = (d->_mp_size < 0) ? - dn : dn;
+}
+
+void
+mpz_setbit (mpz_t d, mp_bitcnt_t bit_index)
+{
+  if (!mpz_tstbit (d, bit_index))
+    {
+      if (d->_mp_size >= 0)
+	mpz_abs_add_bit (d, bit_index);
+      else
+	mpz_abs_sub_bit (d, bit_index);
+    }
+}
+
+void
+mpz_clrbit (mpz_t d, mp_bitcnt_t bit_index)
+{
+  if (mpz_tstbit (d, bit_index))
+    {
+      if (d->_mp_size >= 0)
+	mpz_abs_sub_bit (d, bit_index);
+      else
+	mpz_abs_add_bit (d, bit_index);
+    }
+}
+
+void
+mpz_combit (mpz_t d, mp_bitcnt_t bit_index)
+{
+  if (mpz_tstbit (d, bit_index) ^ (d->_mp_size < 0))
+    mpz_abs_sub_bit (d, bit_index);
+  else
+    mpz_abs_add_bit (d, bit_index);
+}
+
+void
+mpz_com (mpz_t r, const mpz_t u)
+{
+  mpz_add_ui (r, u, 1);
+  mpz_neg (r, r);
+}
+
+void
+mpz_and (mpz_t r, const mpz_t u, const mpz_t v)
+{
+  mp_size_t un, vn, rn, i;
+  mp_ptr up, vp, rp;
+
+  mp_limb_t ux, vx, rx;
+  mp_limb_t uc, vc, rc;
+  mp_limb_t ul, vl, rl;
+
+  un = GMP_ABS (u->_mp_size);
+  vn = GMP_ABS (v->_mp_size);
+  if (un < vn)
+    {
+      MPZ_SRCPTR_SWAP (u, v);
+      MP_SIZE_T_SWAP (un, vn);
+    }
+  if (vn == 0)
+    {
+      r->_mp_size = 0;
+      return;
+    }
+
+  uc = u->_mp_size < 0;
+  vc = v->_mp_size < 0;
+  rc = uc & vc;
+
+  ux = -uc;
+  vx = -vc;
+  rx = -rc;
+
+  /* If the smaller input is positive, higher limbs don't matter. */
+  rn = vx ? un : vn;
+
+  rp = MPZ_REALLOC (r, rn + (mp_size_t) rc);
+
+  up = u->_mp_d;
+  vp = v->_mp_d;
+
+  i = 0;
+  do
+    {
+      ul = (up[i] ^ ux) + uc;
+      uc = ul < uc;
+
+      vl = (vp[i] ^ vx) + vc;
+      vc = vl < vc;
+
+      rl = ( (ul & vl) ^ rx) + rc;
+      rc = rl < rc;
+      rp[i] = rl;
+    }
+  while (++i < vn);
+  assert (vc == 0);
+
+  for (; i < rn; i++)
+    {
+      ul = (up[i] ^ ux) + uc;
+      uc = ul < uc;
+
+      rl = ( (ul & vx) ^ rx) + rc;
+      rc = rl < rc;
+      rp[i] = rl;
+    }
+  if (rc)
+    rp[rn++] = rc;
+  else
+    rn = mpn_normalized_size (rp, rn);
+
+  r->_mp_size = rx ? -rn : rn;
+}
+
+void
+mpz_ior (mpz_t r, const mpz_t u, const mpz_t v)
+{
+  mp_size_t un, vn, rn, i;
+  mp_ptr up, vp, rp;
+
+  mp_limb_t ux, vx, rx;
+  mp_limb_t uc, vc, rc;
+  mp_limb_t ul, vl, rl;
+
+  un = GMP_ABS (u->_mp_size);
+  vn = GMP_ABS (v->_mp_size);
+  if (un < vn)
+    {
+      MPZ_SRCPTR_SWAP (u, v);
+      MP_SIZE_T_SWAP (un, vn);
+    }
+  if (vn == 0)
+    {
+      mpz_set (r, u);
+      return;
+    }
+
+  uc = u->_mp_size < 0;
+  vc = v->_mp_size < 0;
+  rc = uc | vc;
+
+  ux = -uc;
+  vx = -vc;
+  rx = -rc;
+
+  /* If the smaller input is negative, by sign extension higher limbs
+     don't matter. */
+  rn = vx ? vn : un;
+
+  rp = MPZ_REALLOC (r, rn + (mp_size_t) rc);
+
+  up = u->_mp_d;
+  vp = v->_mp_d;
+
+  i = 0;
+  do
+    {
+      ul = (up[i] ^ ux) + uc;
+      uc = ul < uc;
+
+      vl = (vp[i] ^ vx) + vc;
+      vc = vl < vc;
+
+      rl = ( (ul | vl) ^ rx) + rc;
+      rc = rl < rc;
+      rp[i] = rl;
+    }
+  while (++i < vn);
+  assert (vc == 0);
+
+  for (; i < rn; i++)
+    {
+      ul = (up[i] ^ ux) + uc;
+      uc = ul < uc;
+
+      rl = ( (ul | vx) ^ rx) + rc;
+      rc = rl < rc;
+      rp[i] = rl;
+    }
+  if (rc)
+    rp[rn++] = rc;
+  else
+    rn = mpn_normalized_size (rp, rn);
+
+  r->_mp_size = rx ? -rn : rn;
+}
+
+void
+mpz_xor (mpz_t r, const mpz_t u, const mpz_t v)
+{
+  mp_size_t un, vn, i;
+  mp_ptr up, vp, rp;
+
+  mp_limb_t ux, vx, rx;
+  mp_limb_t uc, vc, rc;
+  mp_limb_t ul, vl, rl;
+
+  un = GMP_ABS (u->_mp_size);
+  vn = GMP_ABS (v->_mp_size);
+  if (un < vn)
+    {
+      MPZ_SRCPTR_SWAP (u, v);
+      MP_SIZE_T_SWAP (un, vn);
+    }
+  if (vn == 0)
+    {
+      mpz_set (r, u);
+      return;
+    }
+
+  uc = u->_mp_size < 0;
+  vc = v->_mp_size < 0;
+  rc = uc ^ vc;
+
+  ux = -uc;
+  vx = -vc;
+  rx = -rc;
+
+  rp = MPZ_REALLOC (r, un + (mp_size_t) rc);
+
+  up = u->_mp_d;
+  vp = v->_mp_d;
+
+  i = 0;
+  do
+    {
+      ul = (up[i] ^ ux) + uc;
+      uc = ul < uc;
+
+      vl = (vp[i] ^ vx) + vc;
+      vc = vl < vc;
+
+      rl = (ul ^ vl ^ rx) + rc;
+      rc = rl < rc;
+      rp[i] = rl;
+    }
+  while (++i < vn);
+  assert (vc == 0);
+
+  for (; i < un; i++)
+    {
+      ul = (up[i] ^ ux) + uc;
+      uc = ul < uc;
+
+      rl = (ul ^ ux) + rc;
+      rc = rl < rc;
+      rp[i] = rl;
+    }
+  if (rc)
+    rp[un++] = rc;
+  else
+    un = mpn_normalized_size (rp, un);
+
+  r->_mp_size = rx ? -un : un;
+}
+
+static unsigned
+gmp_popcount_limb (mp_limb_t x)
+{
+  unsigned c;
+
+  /* Do 16 bits at a time, to avoid limb-sized constants. */
+  int LOCAL_SHIFT_BITS = 16;
+  for (c = 0; x > 0;)
+    {
+      unsigned w = x - ((x >> 1) & 0x5555);
+      w = ((w >> 2) & 0x3333) + (w & 0x3333);
+      w =  (w >> 4) + w;
+      w = ((w >> 8) & 0x000f) + (w & 0x000f);
+      c += w;
+      if (GMP_LIMB_BITS > LOCAL_SHIFT_BITS)
+	x >>= LOCAL_SHIFT_BITS;
+      else
+	x = 0;
+    }
+  return c;
+}
+
+mp_bitcnt_t
+mpn_popcount (mp_srcptr p, mp_size_t n)
+{
+  mp_size_t i;
+  mp_bitcnt_t c;
+
+  for (c = 0, i = 0; i < n; i++)
+    c += gmp_popcount_limb (p[i]);
+
+  return c;
+}
+
+mp_bitcnt_t
+mpz_popcount (const mpz_t u)
+{
+  mp_size_t un;
+
+  un = u->_mp_size;
+
+  if (un < 0)
+    return ~(mp_bitcnt_t) 0;
+
+  return mpn_popcount (u->_mp_d, un);
+}
+
+mp_bitcnt_t
+mpz_hamdist (const mpz_t u, const mpz_t v)
+{
+  mp_size_t un, vn, i;
+  mp_limb_t uc, vc, ul, vl, comp;
+  mp_srcptr up, vp;
+  mp_bitcnt_t c;
+
+  un = u->_mp_size;
+  vn = v->_mp_size;
+
+  if ( (un ^ vn) < 0)
+    return ~(mp_bitcnt_t) 0;
+
+  comp = - (uc = vc = (un < 0));
+  if (uc)
+    {
+      assert (vn < 0);
+      un = -un;
+      vn = -vn;
+    }
+
+  up = u->_mp_d;
+  vp = v->_mp_d;
+
+  if (un < vn)
+    MPN_SRCPTR_SWAP (up, un, vp, vn);
+
+  for (i = 0, c = 0; i < vn; i++)
+    {
+      ul = (up[i] ^ comp) + uc;
+      uc = ul < uc;
+
+      vl = (vp[i] ^ comp) + vc;
+      vc = vl < vc;
+
+      c += gmp_popcount_limb (ul ^ vl);
+    }
+  assert (vc == 0);
+
+  for (; i < un; i++)
+    {
+      ul = (up[i] ^ comp) + uc;
+      uc = ul < uc;
+
+      c += gmp_popcount_limb (ul ^ comp);
+    }
+
+  return c;
+}
+
+mp_bitcnt_t
+mpz_scan1 (const mpz_t u, mp_bitcnt_t starting_bit)
+{
+  mp_ptr up;
+  mp_size_t us, un, i;
+  mp_limb_t limb, ux;
+
+  us = u->_mp_size;
+  un = GMP_ABS (us);
+  i = starting_bit / GMP_LIMB_BITS;
+
+  /* Past the end there's no 1 bits for u>=0, or an immediate 1 bit
+     for u<0. Notice this test picks up any u==0 too. */
+  if (i >= un)
+    return (us >= 0 ? ~(mp_bitcnt_t) 0 : starting_bit);
+
+  up = u->_mp_d;
+  ux = 0;
+  limb = up[i];
+
+  if (starting_bit != 0)
+    {
+      if (us < 0)
+	{
+	  ux = mpn_zero_p (up, i);
+	  limb = ~ limb + ux;
+	  ux = - (mp_limb_t) (limb >= ux);
+	}
+
+      /* Mask to 0 all bits before starting_bit, thus ignoring them. */
+      limb &= GMP_LIMB_MAX << (starting_bit % GMP_LIMB_BITS);
+    }
+
+  return mpn_common_scan (limb, i, up, un, ux);
+}
+
+mp_bitcnt_t
+mpz_scan0 (const mpz_t u, mp_bitcnt_t starting_bit)
+{
+  mp_ptr up;
+  mp_size_t us, un, i;
+  mp_limb_t limb, ux;
+
+  us = u->_mp_size;
+  ux = - (mp_limb_t) (us >= 0);
+  un = GMP_ABS (us);
+  i = starting_bit / GMP_LIMB_BITS;
+
+  /* When past end, there's an immediate 0 bit for u>=0, or no 0 bits for
+     u<0.  Notice this test picks up all cases of u==0 too. */
+  if (i >= un)
+    return (ux ? starting_bit : ~(mp_bitcnt_t) 0);
+
+  up = u->_mp_d;
+  limb = up[i] ^ ux;
+
+  if (ux == 0)
+    limb -= mpn_zero_p (up, i); /* limb = ~(~limb + zero_p) */
+
+  /* Mask all bits before starting_bit, thus ignoring them. */
+  limb &= GMP_LIMB_MAX << (starting_bit % GMP_LIMB_BITS);
+
+  return mpn_common_scan (limb, i, up, un, ux);
+}
+
+
+/* MPZ base conversion. */
+
+size_t
+mpz_sizeinbase (const mpz_t u, int base)
+{
+  mp_size_t un;
+  mp_srcptr up;
+  mp_ptr tp;
+  mp_bitcnt_t bits;
+  struct gmp_div_inverse bi;
+  size_t ndigits;
+
+  assert (base >= 2);
+  assert (base <= 62);
+
+  un = GMP_ABS (u->_mp_size);
+  if (un == 0)
+    return 1;
+
+  up = u->_mp_d;
+
+  bits = (un - 1) * GMP_LIMB_BITS + mpn_limb_size_in_base_2 (up[un-1]);
+  switch (base)
+    {
+    case 2:
+      return bits;
+    case 4:
+      return (bits + 1) / 2;
+    case 8:
+      return (bits + 2) / 3;
+    case 16:
+      return (bits + 3) / 4;
+    case 32:
+      return (bits + 4) / 5;
+      /* FIXME: Do something more clever for the common case of base
+	 10. */
+    }
+
+  tp = gmp_xalloc_limbs (un);
+  mpn_copyi (tp, up, un);
+  mpn_div_qr_1_invert (&bi, base);
+
+  ndigits = 0;
+  do
+    {
+      ndigits++;
+      mpn_div_qr_1_preinv (tp, tp, un, &bi);
+      un -= (tp[un-1] == 0);
+    }
+  while (un > 0);
+
+  gmp_free (tp);
+  return ndigits;
+}
+
+char *
+mpz_get_str (char *sp, int base, const mpz_t u)
+{
+  unsigned bits;
+  const char *digits;
+  mp_size_t un;
+  size_t i, sn;
+
+  digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+  if (base > 1)
+    {
+      if (base <= 36)
+	digits = "0123456789abcdefghijklmnopqrstuvwxyz";
+      else if (base > 62)
+	return NULL;
+    }
+  else if (base >= -1)
+    base = 10;
+  else
+    {
+      base = -base;
+      if (base > 36)
+	return NULL;
+    }
+
+  sn = 1 + mpz_sizeinbase (u, base);
+  if (!sp)
+    sp = (char *) gmp_xalloc (1 + sn);
+
+  un = GMP_ABS (u->_mp_size);
+
+  if (un == 0)
+    {
+      sp[0] = '0';
+      sp[1] = '\0';
+      return sp;
+    }
+
+  i = 0;
+
+  if (u->_mp_size < 0)
+    sp[i++] = '-';
+
+  bits = mpn_base_power_of_two_p (base);
+
+  if (bits)
+    /* Not modified in this case. */
+    sn = i + mpn_get_str_bits ((unsigned char *) sp + i, bits, u->_mp_d, un);
+  else
+    {
+      struct mpn_base_info info;
+      mp_ptr tp;
+
+      mpn_get_base_info (&info, base);
+      tp = gmp_xalloc_limbs (un);
+      mpn_copyi (tp, u->_mp_d, un);
+
+      sn = i + mpn_get_str_other ((unsigned char *) sp + i, base, &info, tp, un);
+      gmp_free (tp);
+    }
+
+  for (; i < sn; i++)
+    sp[i] = digits[(unsigned char) sp[i]];
+
+  sp[sn] = '\0';
+  return sp;
+}
+
+int
+mpz_set_str (mpz_t r, const char *sp, int base)
+{
+  unsigned bits, value_of_a;
+  mp_size_t rn, alloc;
+  mp_ptr rp;
+  size_t dn;
+  int sign;
+  unsigned char *dp;
+
+  assert (base == 0 || (base >= 2 && base <= 62));
+
+  while (isspace( (unsigned char) *sp))
+    sp++;
+
+  sign = (*sp == '-');
+  sp += sign;
+
+  if (base == 0)
+    {
+      if (sp[0] == '0')
+	{
+	  if (sp[1] == 'x' || sp[1] == 'X')
+	    {
+	      base = 16;
+	      sp += 2;
+	    }
+	  else if (sp[1] == 'b' || sp[1] == 'B')
+	    {
+	      base = 2;
+	      sp += 2;
+	    }
+	  else
+	    base = 8;
+	}
+      else
+	base = 10;
+    }
+
+  if (!*sp)
+    {
+      r->_mp_size = 0;
+      return -1;
+    }
+  dp = (unsigned char *) gmp_xalloc (strlen (sp));
+
+  value_of_a = (base > 36) ? 36 : 10;
+  for (dn = 0; *sp; sp++)
+    {
+      unsigned digit;
+
+      if (isspace ((unsigned char) *sp))
+	continue;
+      else if (*sp >= '0' && *sp <= '9')
+	digit = *sp - '0';
+      else if (*sp >= 'a' && *sp <= 'z')
+	digit = *sp - 'a' + value_of_a;
+      else if (*sp >= 'A' && *sp <= 'Z')
+	digit = *sp - 'A' + 10;
+      else
+	digit = base; /* fail */
+
+      if (digit >= (unsigned) base)
+	{
+	  gmp_free (dp);
+	  r->_mp_size = 0;
+	  return -1;
+	}
+
+      dp[dn++] = digit;
+    }
+
+  if (!dn)
+    {
+      gmp_free (dp);
+      r->_mp_size = 0;
+      return -1;
+    }
+  bits = mpn_base_power_of_two_p (base);
+
+  if (bits > 0)
+    {
+      alloc = (dn * bits + GMP_LIMB_BITS - 1) / GMP_LIMB_BITS;
+      rp = MPZ_REALLOC (r, alloc);
+      rn = mpn_set_str_bits (rp, dp, dn, bits);
+    }
+  else
+    {
+      struct mpn_base_info info;
+      mpn_get_base_info (&info, base);
+      alloc = (dn + info.exp - 1) / info.exp;
+      rp = MPZ_REALLOC (r, alloc);
+      rn = mpn_set_str_other (rp, dp, dn, base, &info);
+      /* Normalization, needed for all-zero input. */
+      assert (rn > 0);
+      rn -= rp[rn-1] == 0;
+    }
+  assert (rn <= alloc);
+  gmp_free (dp);
+
+  r->_mp_size = sign ? - rn : rn;
+
+  return 0;
+}
+
+int
+mpz_init_set_str (mpz_t r, const char *sp, int base)
+{
+  mpz_init (r);
+  return mpz_set_str (r, sp, base);
+}
+
+size_t
+mpz_out_str (FILE *stream, int base, const mpz_t x)
+{
+  char *str;
+  size_t len;
+
+  str = mpz_get_str (NULL, base, x);
+  len = strlen (str);
+  len = fwrite (str, 1, len, stream);
+  gmp_free (str);
+  return len;
+}
+
+
+static int
+gmp_detect_endian (void)
+{
+  static const int i = 2;
+  const unsigned char *p = (const unsigned char *) &i;
+  return 1 - *p;
+}
+
+/* Import and export. Does not support nails. */
+void
+mpz_import (mpz_t r, size_t count, int order, size_t size, int endian,
+	    size_t nails, const void *src)
+{
+  const unsigned char *p;
+  ptrdiff_t word_step;
+  mp_ptr rp;
+  mp_size_t rn;
+
+  /* The current (partial) limb. */
+  mp_limb_t limb;
+  /* The number of bytes already copied to this limb (starting from
+     the low end). */
+  size_t bytes;
+  /* The index where the limb should be stored, when completed. */
+  mp_size_t i;
+
+  if (nails != 0)
+    gmp_die ("mpz_import: Nails not supported.");
+
+  assert (order == 1 || order == -1);
+  assert (endian >= -1 && endian <= 1);
+
+  if (endian == 0)
+    endian = gmp_detect_endian ();
+
+  p = (unsigned char *) src;
+
+  word_step = (order != endian) ? 2 * size : 0;
+
+  /* Process bytes from the least significant end, so point p at the
+     least significant word. */
+  if (order == 1)
+    {
+      p += size * (count - 1);
+      word_step = - word_step;
+    }
+
+  /* And at least significant byte of that word. */
+  if (endian == 1)
+    p += (size - 1);
+
+  rn = (size * count + sizeof(mp_limb_t) - 1) / sizeof(mp_limb_t);
+  rp = MPZ_REALLOC (r, rn);
+
+  for (limb = 0, bytes = 0, i = 0; count > 0; count--, p += word_step)
+    {
+      size_t j;
+      for (j = 0; j < size; j++, p -= (ptrdiff_t) endian)
+	{
+	  limb |= (mp_limb_t) *p << (bytes++ * CHAR_BIT);
+	  if (bytes == sizeof(mp_limb_t))
+	    {
+	      rp[i++] = limb;
+	      bytes = 0;
+	      limb = 0;
+	    }
+	}
+    }
+  assert (i + (bytes > 0) == rn);
+  if (limb != 0)
+    rp[i++] = limb;
+  else
+    i = mpn_normalized_size (rp, i);
+
+  r->_mp_size = i;
+}
+
+void *
+mpz_export (void *r, size_t *countp, int order, size_t size, int endian,
+	    size_t nails, const mpz_t u)
+{
+  size_t count;
+  mp_size_t un;
+
+  if (nails != 0)
+    gmp_die ("mpz_import: Nails not supported.");
+
+  assert (order == 1 || order == -1);
+  assert (endian >= -1 && endian <= 1);
+  assert (size > 0 || u->_mp_size == 0);
+
+  un = u->_mp_size;
+  count = 0;
+  if (un != 0)
+    {
+      size_t k;
+      unsigned char *p;
+      ptrdiff_t word_step;
+      /* The current (partial) limb. */
+      mp_limb_t limb;
+      /* The number of bytes left to to in this limb. */
+      size_t bytes;
+      /* The index where the limb was read. */
+      mp_size_t i;
+
+      un = GMP_ABS (un);
+
+      /* Count bytes in top limb. */
+      limb = u->_mp_d[un-1];
+      assert (limb != 0);
+
+      k = (GMP_LIMB_BITS <= CHAR_BIT);
+      if (!k)
+	{
+	  do {
+	    int LOCAL_CHAR_BIT = CHAR_BIT;
+	    k++; limb >>= LOCAL_CHAR_BIT;
+	  } while (limb != 0);
+	}
+      /* else limb = 0; */
+
+      count = (k + (un-1) * sizeof (mp_limb_t) + size - 1) / size;
+
+      if (!r)
+	r = gmp_xalloc (count * size);
+
+      if (endian == 0)
+	endian = gmp_detect_endian ();
+
+      p = (unsigned char *) r;
+
+      word_step = (order != endian) ? 2 * size : 0;
+
+      /* Process bytes from the least significant end, so point p at the
+	 least significant word. */
+      if (order == 1)
+	{
+	  p += size * (count - 1);
+	  word_step = - word_step;
+	}
+
+      /* And at least significant byte of that word. */
+      if (endian == 1)
+	p += (size - 1);
+
+      for (bytes = 0, i = 0, k = 0; k < count; k++, p += word_step)
+	{
+	  size_t j;
+	  for (j = 0; j < size; ++j, p -= (ptrdiff_t) endian)
+	    {
+	      if (sizeof (mp_limb_t) == 1)
+		{
+		  if (i < un)
+		    *p = u->_mp_d[i++];
+		  else
+		    *p = 0;
+		}
+	      else
+		{
+		  int LOCAL_CHAR_BIT = CHAR_BIT;
+		  if (bytes == 0)
+		    {
+		      if (i < un)
+			limb = u->_mp_d[i++];
+		      bytes = sizeof (mp_limb_t);
+		    }
+		  *p = limb;
+		  limb >>= LOCAL_CHAR_BIT;
+		  bytes--;
+		}
+	    }
+	}
+      assert (i == un);
+      assert (k == count);
+    }
+
+  if (countp)
+    *countp = count;
+
+  return r;
+}
diff --git a/third_party/gmp/mini-gmp/mini-gmp.h b/third_party/gmp/mini-gmp/mini-gmp.h
new file mode 100644
index 0000000..7cce3f7
--- /dev/null
+++ b/third_party/gmp/mini-gmp/mini-gmp.h
@@ -0,0 +1,304 @@
+/* mini-gmp, a minimalistic implementation of a GNU GMP subset.
+
+Copyright 2011-2015, 2017, 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+/* About mini-gmp: This is a minimal implementation of a subset of the
+   GMP interface. It is intended for inclusion into applications which
+   have modest bignums needs, as a fallback when the real GMP library
+   is not installed.
+
+   This file defines the public interface. */
+
+#ifndef __MINI_GMP_H__
+#define __MINI_GMP_H__
+
+/* For size_t */
+#include <stddef.h>
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+void mp_set_memory_functions (void *(*) (size_t),
+			      void *(*) (void *, size_t, size_t),
+			      void (*) (void *, size_t));
+
+void mp_get_memory_functions (void *(**) (size_t),
+			      void *(**) (void *, size_t, size_t),
+			      void (**) (void *, size_t));
+
+#ifndef MINI_GMP_LIMB_TYPE
+#define MINI_GMP_LIMB_TYPE long
+#endif
+
+typedef unsigned MINI_GMP_LIMB_TYPE mp_limb_t;
+typedef long mp_size_t;
+typedef unsigned long mp_bitcnt_t;
+
+typedef mp_limb_t *mp_ptr;
+typedef const mp_limb_t *mp_srcptr;
+
+typedef struct
+{
+  int _mp_alloc;		/* Number of *limbs* allocated and pointed
+				   to by the _mp_d field.  */
+  int _mp_size;			/* abs(_mp_size) is the number of limbs the
+				   last field points to.  If _mp_size is
+				   negative this is a negative number.  */
+  mp_limb_t *_mp_d;		/* Pointer to the limbs.  */
+} __mpz_struct;
+
+typedef __mpz_struct mpz_t[1];
+
+typedef __mpz_struct *mpz_ptr;
+typedef const __mpz_struct *mpz_srcptr;
+
+extern const int mp_bits_per_limb;
+
+void mpn_copyi (mp_ptr, mp_srcptr, mp_size_t);
+void mpn_copyd (mp_ptr, mp_srcptr, mp_size_t);
+void mpn_zero (mp_ptr, mp_size_t);
+
+int mpn_cmp (mp_srcptr, mp_srcptr, mp_size_t);
+int mpn_zero_p (mp_srcptr, mp_size_t);
+
+mp_limb_t mpn_add_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t mpn_add_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+mp_limb_t mpn_add (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+
+mp_limb_t mpn_sub_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t mpn_sub_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+mp_limb_t mpn_sub (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+
+mp_limb_t mpn_mul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t mpn_addmul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t mpn_submul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+mp_limb_t mpn_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+void mpn_mul_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+void mpn_sqr (mp_ptr, mp_srcptr, mp_size_t);
+int mpn_perfect_square_p (mp_srcptr, mp_size_t);
+mp_size_t mpn_sqrtrem (mp_ptr, mp_ptr, mp_srcptr, mp_size_t);
+
+mp_limb_t mpn_lshift (mp_ptr, mp_srcptr, mp_size_t, unsigned int);
+mp_limb_t mpn_rshift (mp_ptr, mp_srcptr, mp_size_t, unsigned int);
+
+mp_bitcnt_t mpn_scan0 (mp_srcptr, mp_bitcnt_t);
+mp_bitcnt_t mpn_scan1 (mp_srcptr, mp_bitcnt_t);
+
+void mpn_com (mp_ptr, mp_srcptr, mp_size_t);
+mp_limb_t mpn_neg (mp_ptr, mp_srcptr, mp_size_t);
+
+mp_bitcnt_t mpn_popcount (mp_srcptr, mp_size_t);
+
+mp_limb_t mpn_invert_3by2 (mp_limb_t, mp_limb_t);
+#define mpn_invert_limb(x) mpn_invert_3by2 ((x), 0)
+
+size_t mpn_get_str (unsigned char *, int, mp_ptr, mp_size_t);
+mp_size_t mpn_set_str (mp_ptr, const unsigned char *, size_t, int);
+
+void mpz_init (mpz_t);
+void mpz_init2 (mpz_t, mp_bitcnt_t);
+void mpz_clear (mpz_t);
+
+#define mpz_odd_p(z)   (((z)->_mp_size != 0) & (int) (z)->_mp_d[0])
+#define mpz_even_p(z)  (! mpz_odd_p (z))
+
+int mpz_sgn (const mpz_t);
+int mpz_cmp_si (const mpz_t, long);
+int mpz_cmp_ui (const mpz_t, unsigned long);
+int mpz_cmp (const mpz_t, const mpz_t);
+int mpz_cmpabs_ui (const mpz_t, unsigned long);
+int mpz_cmpabs (const mpz_t, const mpz_t);
+int mpz_cmp_d (const mpz_t, double);
+int mpz_cmpabs_d (const mpz_t, double);
+
+void mpz_abs (mpz_t, const mpz_t);
+void mpz_neg (mpz_t, const mpz_t);
+void mpz_swap (mpz_t, mpz_t);
+
+void mpz_add_ui (mpz_t, const mpz_t, unsigned long);
+void mpz_add (mpz_t, const mpz_t, const mpz_t);
+void mpz_sub_ui (mpz_t, const mpz_t, unsigned long);
+void mpz_ui_sub (mpz_t, unsigned long, const mpz_t);
+void mpz_sub (mpz_t, const mpz_t, const mpz_t);
+
+void mpz_mul_si (mpz_t, const mpz_t, long int);
+void mpz_mul_ui (mpz_t, const mpz_t, unsigned long int);
+void mpz_mul (mpz_t, const mpz_t, const mpz_t);
+void mpz_mul_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
+void mpz_addmul_ui (mpz_t, const mpz_t, unsigned long int);
+void mpz_addmul (mpz_t, const mpz_t, const mpz_t);
+void mpz_submul_ui (mpz_t, const mpz_t, unsigned long int);
+void mpz_submul (mpz_t, const mpz_t, const mpz_t);
+
+void mpz_cdiv_qr (mpz_t, mpz_t, const mpz_t, const mpz_t);
+void mpz_fdiv_qr (mpz_t, mpz_t, const mpz_t, const mpz_t);
+void mpz_tdiv_qr (mpz_t, mpz_t, const mpz_t, const mpz_t);
+void mpz_cdiv_q (mpz_t, const mpz_t, const mpz_t);
+void mpz_fdiv_q (mpz_t, const mpz_t, const mpz_t);
+void mpz_tdiv_q (mpz_t, const mpz_t, const mpz_t);
+void mpz_cdiv_r (mpz_t, const mpz_t, const mpz_t);
+void mpz_fdiv_r (mpz_t, const mpz_t, const mpz_t);
+void mpz_tdiv_r (mpz_t, const mpz_t, const mpz_t);
+
+void mpz_cdiv_q_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
+void mpz_fdiv_q_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
+void mpz_tdiv_q_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
+void mpz_cdiv_r_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
+void mpz_fdiv_r_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
+void mpz_tdiv_r_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
+
+void mpz_mod (mpz_t, const mpz_t, const mpz_t);
+
+void mpz_divexact (mpz_t, const mpz_t, const mpz_t);
+
+int mpz_divisible_p (const mpz_t, const mpz_t);
+int mpz_congruent_p (const mpz_t, const mpz_t, const mpz_t);
+
+unsigned long mpz_cdiv_qr_ui (mpz_t, mpz_t, const mpz_t, unsigned long);
+unsigned long mpz_fdiv_qr_ui (mpz_t, mpz_t, const mpz_t, unsigned long);
+unsigned long mpz_tdiv_qr_ui (mpz_t, mpz_t, const mpz_t, unsigned long);
+unsigned long mpz_cdiv_q_ui (mpz_t, const mpz_t, unsigned long);
+unsigned long mpz_fdiv_q_ui (mpz_t, const mpz_t, unsigned long);
+unsigned long mpz_tdiv_q_ui (mpz_t, const mpz_t, unsigned long);
+unsigned long mpz_cdiv_r_ui (mpz_t, const mpz_t, unsigned long);
+unsigned long mpz_fdiv_r_ui (mpz_t, const mpz_t, unsigned long);
+unsigned long mpz_tdiv_r_ui (mpz_t, const mpz_t, unsigned long);
+unsigned long mpz_cdiv_ui (const mpz_t, unsigned long);
+unsigned long mpz_fdiv_ui (const mpz_t, unsigned long);
+unsigned long mpz_tdiv_ui (const mpz_t, unsigned long);
+
+unsigned long mpz_mod_ui (mpz_t, const mpz_t, unsigned long);
+
+void mpz_divexact_ui (mpz_t, const mpz_t, unsigned long);
+
+int mpz_divisible_ui_p (const mpz_t, unsigned long);
+
+unsigned long mpz_gcd_ui (mpz_t, const mpz_t, unsigned long);
+void mpz_gcd (mpz_t, const mpz_t, const mpz_t);
+void mpz_gcdext (mpz_t, mpz_t, mpz_t, const mpz_t, const mpz_t);
+void mpz_lcm_ui (mpz_t, const mpz_t, unsigned long);
+void mpz_lcm (mpz_t, const mpz_t, const mpz_t);
+int mpz_invert (mpz_t, const mpz_t, const mpz_t);
+
+void mpz_sqrtrem (mpz_t, mpz_t, const mpz_t);
+void mpz_sqrt (mpz_t, const mpz_t);
+int mpz_perfect_square_p (const mpz_t);
+
+void mpz_pow_ui (mpz_t, const mpz_t, unsigned long);
+void mpz_ui_pow_ui (mpz_t, unsigned long, unsigned long);
+void mpz_powm (mpz_t, const mpz_t, const mpz_t, const mpz_t);
+void mpz_powm_ui (mpz_t, const mpz_t, unsigned long, const mpz_t);
+
+void mpz_rootrem (mpz_t, mpz_t, const mpz_t, unsigned long);
+int mpz_root (mpz_t, const mpz_t, unsigned long);
+
+void mpz_fac_ui (mpz_t, unsigned long);
+void mpz_2fac_ui (mpz_t, unsigned long);
+void mpz_mfac_uiui (mpz_t, unsigned long, unsigned long);
+void mpz_bin_uiui (mpz_t, unsigned long, unsigned long);
+
+int mpz_probab_prime_p (const mpz_t, int);
+
+int mpz_tstbit (const mpz_t, mp_bitcnt_t);
+void mpz_setbit (mpz_t, mp_bitcnt_t);
+void mpz_clrbit (mpz_t, mp_bitcnt_t);
+void mpz_combit (mpz_t, mp_bitcnt_t);
+
+void mpz_com (mpz_t, const mpz_t);
+void mpz_and (mpz_t, const mpz_t, const mpz_t);
+void mpz_ior (mpz_t, const mpz_t, const mpz_t);
+void mpz_xor (mpz_t, const mpz_t, const mpz_t);
+
+mp_bitcnt_t mpz_popcount (const mpz_t);
+mp_bitcnt_t mpz_hamdist (const mpz_t, const mpz_t);
+mp_bitcnt_t mpz_scan0 (const mpz_t, mp_bitcnt_t);
+mp_bitcnt_t mpz_scan1 (const mpz_t, mp_bitcnt_t);
+
+int mpz_fits_slong_p (const mpz_t);
+int mpz_fits_ulong_p (const mpz_t);
+long int mpz_get_si (const mpz_t);
+unsigned long int mpz_get_ui (const mpz_t);
+double mpz_get_d (const mpz_t);
+size_t mpz_size (const mpz_t);
+mp_limb_t mpz_getlimbn (const mpz_t, mp_size_t);
+
+void mpz_realloc2 (mpz_t, mp_bitcnt_t);
+mp_srcptr mpz_limbs_read (mpz_srcptr);
+mp_ptr mpz_limbs_modify (mpz_t, mp_size_t);
+mp_ptr mpz_limbs_write (mpz_t, mp_size_t);
+void mpz_limbs_finish (mpz_t, mp_size_t);
+mpz_srcptr mpz_roinit_n (mpz_t, mp_srcptr, mp_size_t);
+
+#define MPZ_ROINIT_N(xp, xs) {{0, (xs),(xp) }}
+
+void mpz_set_si (mpz_t, signed long int);
+void mpz_set_ui (mpz_t, unsigned long int);
+void mpz_set (mpz_t, const mpz_t);
+void mpz_set_d (mpz_t, double);
+
+void mpz_init_set_si (mpz_t, signed long int);
+void mpz_init_set_ui (mpz_t, unsigned long int);
+void mpz_init_set (mpz_t, const mpz_t);
+void mpz_init_set_d (mpz_t, double);
+
+size_t mpz_sizeinbase (const mpz_t, int);
+char *mpz_get_str (char *, int, const mpz_t);
+int mpz_set_str (mpz_t, const char *, int);
+int mpz_init_set_str (mpz_t, const char *, int);
+
+/* This long list taken from gmp.h. */
+/* For reference, "defined(EOF)" cannot be used here.  In g++ 2.95.4,
+   <iostream> defines EOF but not FILE.  */
+#if defined (FILE)                                              \
+  || defined (H_STDIO)                                          \
+  || defined (_H_STDIO)               /* AIX */                 \
+  || defined (_STDIO_H)               /* glibc, Sun, SCO */     \
+  || defined (_STDIO_H_)              /* BSD, OSF */            \
+  || defined (__STDIO_H)              /* Borland */             \
+  || defined (__STDIO_H__)            /* IRIX */                \
+  || defined (_STDIO_INCLUDED)        /* HPUX */                \
+  || defined (__dj_include_stdio_h_)  /* DJGPP */               \
+  || defined (_FILE_DEFINED)          /* Microsoft */           \
+  || defined (__STDIO__)              /* Apple MPW MrC */       \
+  || defined (_MSL_STDIO_H)           /* Metrowerks */          \
+  || defined (_STDIO_H_INCLUDED)      /* QNX4 */		\
+  || defined (_ISO_STDIO_ISO_H)       /* Sun C++ */		\
+  || defined (__STDIO_LOADED)         /* VMS */
+size_t mpz_out_str (FILE *, int, const mpz_t);
+#endif
+
+void mpz_import (mpz_t, size_t, int, size_t, int, size_t, const void *);
+void *mpz_export (void *, size_t *, int, size_t, int, size_t, const mpz_t);
+
+#if defined (__cplusplus)
+}
+#endif
+#endif /* __MINI_GMP_H__ */
diff --git a/third_party/gmp/mini-gmp/mini-mpq.c b/third_party/gmp/mini-gmp/mini-mpq.c
new file mode 100644
index 0000000..fd9b439
--- /dev/null
+++ b/third_party/gmp/mini-gmp/mini-mpq.c
@@ -0,0 +1,554 @@
+/* mini-mpq, a minimalistic implementation of a GNU GMP subset.
+
+   Contributed to the GNU project by Marco Bodrato
+
+   Acknowledgment: special thanks to Bradley Lucier for his comments
+   to the preliminary version of this code.
+
+Copyright 2018, 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <assert.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "mini-mpq.h"
+
+#ifndef GMP_LIMB_HIGHBIT
+/* Define macros and static functions already defined by mini-gmp.c */
+#define GMP_LIMB_BITS (sizeof(mp_limb_t) * CHAR_BIT)
+#define GMP_LIMB_HIGHBIT ((mp_limb_t) 1 << (GMP_LIMB_BITS - 1))
+#define GMP_NEG_CAST(T,x) (-((T)((x) + 1) - 1))
+#define GMP_MIN(a, b) ((a) < (b) ? (a) : (b))
+
+static mpz_srcptr
+mpz_roinit_normal_n (mpz_t x, mp_srcptr xp, mp_size_t xs)
+{
+  x->_mp_alloc = 0;
+  x->_mp_d = (mp_ptr) xp;
+  x->_mp_size = xs;
+  return x;
+}
+
+static void
+gmp_die (const char *msg)
+{
+  fprintf (stderr, "%s\n", msg);
+  abort();
+}
+#endif
+
+
+/* MPQ helper functions */
+static mpq_srcptr
+mpq_roinit_normal_nn (mpq_t x, mp_srcptr np, mp_size_t ns,
+		     mp_srcptr dp, mp_size_t ds)
+{
+  mpz_roinit_normal_n (mpq_numref(x), np, ns);
+  mpz_roinit_normal_n (mpq_denref(x), dp, ds);
+  return x;
+}
+
+static mpq_srcptr
+mpq_roinit_zz (mpq_t x, mpz_srcptr n, mpz_srcptr d)
+{
+  return mpq_roinit_normal_nn (x, n->_mp_d, n->_mp_size,
+			       d->_mp_d, d->_mp_size);
+}
+
+static void
+mpq_nan_init (mpq_t x)
+{
+  mpz_init (mpq_numref (x));
+  mpz_init (mpq_denref (x));
+}
+
+void
+mpq_init (mpq_t x)
+{
+  mpz_init (mpq_numref (x));
+  mpz_init_set_ui (mpq_denref (x), 1);
+}
+
+void
+mpq_clear (mpq_t x)
+{
+  mpz_clear (mpq_numref (x));
+  mpz_clear (mpq_denref (x));
+}
+
+static void
+mpq_canonical_sign (mpq_t r)
+{
+  int cmp = mpq_denref (r)->_mp_size;
+  if (cmp <= 0)
+    {
+      if (cmp == 0)
+	gmp_die("mpq: Fraction with zero denominator.");
+      mpz_neg (mpq_denref (r), mpq_denref (r));
+      mpz_neg (mpq_numref (r), mpq_numref (r));
+    }
+}
+
+static void
+mpq_helper_canonicalize (mpq_t r, const mpz_t num, const mpz_t den, mpz_t g)
+{
+  if (num->_mp_size == 0)
+    mpq_set_ui (r, 0, 1);
+  else
+    {
+      mpz_gcd (g, num, den);
+      mpz_tdiv_q (mpq_numref (r), num, g);
+      mpz_tdiv_q (mpq_denref (r), den, g);
+      mpq_canonical_sign (r);
+    }
+}
+
+void
+mpq_canonicalize (mpq_t r)
+{
+  mpz_t t;
+
+  mpz_init (t);
+  mpq_helper_canonicalize (r, mpq_numref (r), mpq_denref (r), t);
+  mpz_clear (t);
+}
+
+void
+mpq_swap (mpq_t a, mpq_t b)
+{
+  mpz_swap (mpq_numref (a), mpq_numref (b));
+  mpz_swap (mpq_denref (a), mpq_denref (b));
+}
+
+
+/* MPQ assignment and conversions. */
+void
+mpz_set_q (mpz_t r, const mpq_t q)
+{
+  mpz_tdiv_q (r, mpq_numref (q), mpq_denref (q));
+}
+
+void
+mpq_set (mpq_t r, const mpq_t q)
+{
+  mpz_set (mpq_numref (r), mpq_numref (q));
+  mpz_set (mpq_denref (r), mpq_denref (q));
+}
+
+void
+mpq_set_ui (mpq_t r, unsigned long n, unsigned long d)
+{
+  mpz_set_ui (mpq_numref (r), n);
+  mpz_set_ui (mpq_denref (r), d);
+}
+
+void
+mpq_set_si (mpq_t r, signed long n, unsigned long d)
+{
+  mpz_set_si (mpq_numref (r), n);
+  mpz_set_ui (mpq_denref (r), d);
+}
+
+void
+mpq_set_z (mpq_t r, const mpz_t n)
+{
+  mpz_set_ui (mpq_denref (r), 1);
+  mpz_set (mpq_numref (r), n);
+}
+
+void
+mpq_set_num (mpq_t r, const mpz_t z)
+{
+  mpz_set (mpq_numref (r), z);
+}
+
+void
+mpq_set_den (mpq_t r, const mpz_t z)
+{
+  mpz_set (mpq_denref (r), z);
+}
+
+void
+mpq_get_num (mpz_t r, const mpq_t q)
+{
+  mpz_set (r, mpq_numref (q));
+}
+
+void
+mpq_get_den (mpz_t r, const mpq_t q)
+{
+  mpz_set (r, mpq_denref (q));
+}
+
+
+/* MPQ comparisons and the like. */
+int
+mpq_cmp (const mpq_t a, const mpq_t b)
+{
+  mpz_t t1, t2;
+  int res;
+
+  mpz_init (t1);
+  mpz_init (t2);
+  mpz_mul (t1, mpq_numref (a), mpq_denref (b));
+  mpz_mul (t2, mpq_numref (b), mpq_denref (a));
+  res = mpz_cmp (t1, t2);
+  mpz_clear (t1);
+  mpz_clear (t2);
+
+  return res;
+}
+
+int
+mpq_cmp_z (const mpq_t a, const mpz_t b)
+{
+  mpz_t t;
+  int res;
+
+  mpz_init (t);
+  mpz_mul (t, b, mpq_denref (a));
+  res = mpz_cmp (mpq_numref (a), t);
+  mpz_clear (t);
+
+  return res;
+}
+
+int
+mpq_equal (const mpq_t a, const mpq_t b)
+{
+  return (mpz_cmp (mpq_numref (a), mpq_numref (b)) == 0) &&
+    (mpz_cmp (mpq_denref (a), mpq_denref (b)) == 0);
+}
+
+int
+mpq_cmp_ui (const mpq_t q, unsigned long n, unsigned long d)
+{
+  mpq_t t;
+  assert (d != 0);
+  if (ULONG_MAX <= GMP_LIMB_MAX) {
+    mp_limb_t nl = n, dl = d;
+    return mpq_cmp (q, mpq_roinit_normal_nn (t, &nl, n != 0, &dl, 1));
+  } else {
+    int ret;
+
+    mpq_init (t);
+    mpq_set_ui (t, n, d);
+    ret = mpq_cmp (q, t);
+    mpq_clear (t);
+
+    return ret;
+  }
+}
+
+int
+mpq_cmp_si (const mpq_t q, signed long n, unsigned long d)
+{
+  assert (d != 0);
+
+  if (n >= 0)
+    return mpq_cmp_ui (q, n, d);
+  else
+    {
+      mpq_t t;
+
+      if (ULONG_MAX <= GMP_LIMB_MAX)
+	{
+	  mp_limb_t nl = GMP_NEG_CAST (unsigned long, n), dl = d;
+	  return mpq_cmp (q, mpq_roinit_normal_nn (t, &nl, -1, &dl, 1));
+	}
+      else
+	{
+	  unsigned long l_n = GMP_NEG_CAST (unsigned long, n);
+
+	  mpq_roinit_normal_nn (t, mpq_numref (q)->_mp_d, - mpq_numref (q)->_mp_size,
+				mpq_denref (q)->_mp_d, mpq_denref (q)->_mp_size);
+	  return - mpq_cmp_ui (t, l_n, d);
+	}
+    }
+}
+
+int
+mpq_sgn (const mpq_t a)
+{
+  return mpz_sgn (mpq_numref (a));
+}
+
+
+/* MPQ arithmetic. */
+void
+mpq_abs (mpq_t r, const mpq_t q)
+{
+  mpz_abs (mpq_numref (r), mpq_numref (q));
+  mpz_set (mpq_denref (r), mpq_denref (q));
+}
+
+void
+mpq_neg (mpq_t r, const mpq_t q)
+{
+  mpz_neg (mpq_numref (r), mpq_numref (q));
+  mpz_set (mpq_denref (r), mpq_denref (q));
+}
+
+void
+mpq_add (mpq_t r, const mpq_t a, const mpq_t b)
+{
+  mpz_t t;
+
+  mpz_init (t);
+  mpz_gcd (t, mpq_denref (a), mpq_denref (b));
+  if (mpz_cmp_ui (t, 1) == 0)
+    {
+      mpz_mul (t, mpq_numref (a), mpq_denref (b));
+      mpz_addmul (t, mpq_numref (b), mpq_denref (a));
+      mpz_mul (mpq_denref (r), mpq_denref (a), mpq_denref (b));
+      mpz_swap (mpq_numref (r), t);
+    }
+  else
+    {
+      mpz_t x, y;
+      mpz_init (x);
+      mpz_init (y);
+
+      mpz_tdiv_q (x, mpq_denref (b), t);
+      mpz_tdiv_q (y, mpq_denref (a), t);
+      mpz_mul (x, mpq_numref (a), x);
+      mpz_addmul (x, mpq_numref (b), y);
+
+      mpz_gcd (t, x, t);
+      mpz_tdiv_q (mpq_numref (r), x, t);
+      mpz_tdiv_q (x, mpq_denref (b), t);
+      mpz_mul (mpq_denref (r), x, y);
+
+      mpz_clear (x);
+      mpz_clear (y);
+    }
+  mpz_clear (t);
+}
+
+void
+mpq_sub (mpq_t r, const mpq_t a, const mpq_t b)
+{
+  mpq_t t;
+
+  mpq_roinit_normal_nn (t, mpq_numref (b)->_mp_d, - mpq_numref (b)->_mp_size,
+			mpq_denref (b)->_mp_d, mpq_denref (b)->_mp_size);
+  mpq_add (r, a, t);
+}
+
+void
+mpq_div (mpq_t r, const mpq_t a, const mpq_t b)
+{
+  mpq_t t;
+  mpq_mul (r, a, mpq_roinit_zz (t, mpq_denref (b), mpq_numref (b)));
+}
+
+void
+mpq_mul (mpq_t r, const mpq_t a, const mpq_t b)
+{
+  mpq_t t;
+  mpq_nan_init (t);
+
+  if (a != b) {
+    mpz_t g;
+
+    mpz_init (g);
+    mpq_helper_canonicalize (t, mpq_numref (a), mpq_denref (b), g);
+    mpq_helper_canonicalize (r, mpq_numref (b), mpq_denref (a), g);
+    mpz_clear (g);
+
+    a = r;
+    b = t;
+  }
+
+  mpz_mul (mpq_numref (r), mpq_numref (a), mpq_numref (b));
+  mpz_mul (mpq_denref (r), mpq_denref (a), mpq_denref (b));
+  mpq_clear (t);
+}
+
+void
+mpq_div_2exp (mpq_t r, const mpq_t q, mp_bitcnt_t e)
+{
+  mp_bitcnt_t z = mpz_scan1 (mpq_numref (q), 0);
+  z = GMP_MIN (z, e);
+  mpz_mul_2exp (mpq_denref (r), mpq_denref (q), e - z);
+  mpz_tdiv_q_2exp (mpq_numref (r), mpq_numref (q), z);
+}
+
+void
+mpq_mul_2exp (mpq_t r, const mpq_t q, mp_bitcnt_t e)
+{
+  mp_bitcnt_t z = mpz_scan1 (mpq_denref (q), 0);
+  z = GMP_MIN (z, e);
+  mpz_mul_2exp (mpq_numref (r), mpq_numref (q), e - z);
+  mpz_tdiv_q_2exp (mpq_denref (r), mpq_denref (q), z);
+}
+
+void
+mpq_inv (mpq_t r, const mpq_t q)
+{
+  mpq_set (r, q);
+  mpz_swap (mpq_denref (r), mpq_numref (r));
+  mpq_canonical_sign (r);
+}
+
+
+/* MPQ to/from double. */
+void
+mpq_set_d (mpq_t r, double x)
+{
+  mpz_set_ui (mpq_denref (r), 1);
+
+  /* x != x is true when x is a NaN, and x == x * 0.5 is true when x is
+     zero or infinity. */
+  if (x == x * 0.5 || x != x)
+    mpq_numref (r)->_mp_size = 0;
+  else
+    {
+      double B;
+      mp_bitcnt_t e;
+
+      B = 4.0 * (double) (GMP_LIMB_HIGHBIT >> 1);
+      for (e = 0; x != x + 0.5; e += GMP_LIMB_BITS)
+	x *= B;
+
+      mpz_set_d (mpq_numref (r), x);
+      mpq_div_2exp (r, r, e);
+    }
+}
+
+double
+mpq_get_d (const mpq_t u)
+{
+  mp_bitcnt_t ne, de, ee;
+  mpz_t z;
+  double B, ret;
+
+  ne = mpz_sizeinbase (mpq_numref (u), 2);
+  de = mpz_sizeinbase (mpq_denref (u), 2);
+
+  ee = CHAR_BIT * sizeof (double);
+  if (de == 1 || ne > de + ee)
+    ee = 0;
+  else
+    ee = (ee + de - ne) / GMP_LIMB_BITS + 1;
+
+  mpz_init (z);
+  mpz_mul_2exp (z, mpq_numref (u), ee * GMP_LIMB_BITS);
+  mpz_tdiv_q (z, z, mpq_denref (u));
+  ret = mpz_get_d (z);
+  mpz_clear (z);
+
+  B = 4.0 * (double) (GMP_LIMB_HIGHBIT >> 1);
+  for (B = 1 / B; ee != 0; --ee)
+    ret *= B;
+
+  return ret;
+}
+
+
+/* MPQ and strings/streams. */
+char *
+mpq_get_str (char *sp, int base, const mpq_t q)
+{
+  char *res;
+  char *rden;
+  size_t len;
+
+  res = mpz_get_str (sp, base, mpq_numref (q));
+  if (res == NULL || mpz_cmp_ui (mpq_denref (q), 1) == 0)
+    return res;
+
+  len = strlen (res) + 1;
+  rden = sp ? sp + len : NULL;
+  rden = mpz_get_str (rden, base, mpq_denref (q));
+  assert (rden != NULL);
+
+  if (sp == NULL) {
+    void * (*gmp_reallocate_func) (void *, size_t, size_t);
+    void (*gmp_free_func) (void *, size_t);
+    size_t lden;
+
+    mp_get_memory_functions (NULL, &gmp_reallocate_func, &gmp_free_func);
+    lden = strlen (rden) + 1;
+    res = (char *) gmp_reallocate_func (res, 0, (lden + len) * sizeof (char));
+    memcpy (res + len, rden, lden);
+    gmp_free_func (rden, 0);
+  }
+
+  res [len - 1] = '/';
+  return res;
+}
+
+size_t
+mpq_out_str (FILE *stream, int base, const mpq_t x)
+{
+  char * str;
+  size_t len;
+  void (*gmp_free_func) (void *, size_t);
+
+  str = mpq_get_str (NULL, base, x);
+  len = strlen (str);
+  len = fwrite (str, 1, len, stream);
+  mp_get_memory_functions (NULL, NULL, &gmp_free_func);
+  gmp_free_func (str, 0);
+  return len;
+}
+
+int
+mpq_set_str (mpq_t r, const char *sp, int base)
+{
+  const char *slash;
+
+  slash = strchr (sp, '/');
+  if (slash == NULL) {
+    mpz_set_ui (mpq_denref(r), 1);
+    return mpz_set_str (mpq_numref(r), sp, base);
+  } else {
+    char *num;
+    size_t numlen;
+    int ret;
+    void * (*gmp_allocate_func) (size_t);
+    void (*gmp_free_func) (void *, size_t);
+
+    mp_get_memory_functions (&gmp_allocate_func, NULL, &gmp_free_func);
+    numlen = slash - sp;
+    num = (char *) gmp_allocate_func ((numlen + 1) * sizeof (char));
+    memcpy (num, sp, numlen);
+    num[numlen] = '\0';
+    ret = mpz_set_str (mpq_numref(r), num, base);
+    gmp_free_func (num, 0);
+
+    if (ret != 0)
+      return ret;
+
+    return mpz_set_str (mpq_denref(r), slash + 1, base);
+  }
+}
diff --git a/third_party/gmp/mini-gmp/mini-mpq.h b/third_party/gmp/mini-gmp/mini-mpq.h
new file mode 100644
index 0000000..8eabcec
--- /dev/null
+++ b/third_party/gmp/mini-gmp/mini-mpq.h
@@ -0,0 +1,114 @@
+/* mini-mpq, a minimalistic implementation of a GNU GMP subset.
+
+Copyright 2018, 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+/* Header */
+
+#ifndef __MINI_MPQ_H__
+#define __MINI_MPQ_H__
+
+#include "mini-gmp.h"
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+typedef struct
+{
+  __mpz_struct _mp_num;
+  __mpz_struct _mp_den;
+} __mpq_struct;
+
+typedef __mpq_struct mpq_t[1];
+
+typedef const __mpq_struct *mpq_srcptr;
+typedef __mpq_struct *mpq_ptr;
+
+#define mpq_numref(Q) (&((Q)->_mp_num))
+#define mpq_denref(Q) (&((Q)->_mp_den))
+
+void mpq_abs (mpq_t, const mpq_t);
+void mpq_add (mpq_t, const mpq_t, const mpq_t);
+void mpq_canonicalize (mpq_t);
+void mpq_clear (mpq_t);
+int mpq_cmp (const mpq_t, const mpq_t);
+int mpq_cmp_si (const mpq_t, signed long, unsigned long);
+int mpq_cmp_ui (const mpq_t, unsigned long, unsigned long);
+int mpq_cmp_z (const mpq_t, const mpz_t);
+void mpq_div (mpq_t, const mpq_t, const mpq_t);
+void mpq_div_2exp (mpq_t, const mpq_t, mp_bitcnt_t);
+int mpq_equal (const mpq_t, const mpq_t);
+double mpq_get_d (const mpq_t);
+void mpq_get_den (mpz_t, const mpq_t);
+void mpq_get_num (mpz_t, const mpq_t);
+char * mpq_get_str (char *, int, const mpq_t q);
+void mpq_init (mpq_t);
+void mpq_inv (mpq_t, const mpq_t);
+void mpq_mul (mpq_t, const mpq_t, const mpq_t);
+void mpq_mul_2exp (mpq_t, const mpq_t, mp_bitcnt_t);
+void mpq_neg (mpq_t, const mpq_t);
+void mpq_set (mpq_t, const mpq_t);
+void mpq_set_d (mpq_t, double);
+void mpq_set_den (mpq_t, const mpz_t);
+void mpq_set_num (mpq_t, const mpz_t);
+void mpq_set_si (mpq_t, signed long, unsigned long);
+int mpq_set_str (mpq_t, const char *, int);
+void mpq_set_ui (mpq_t, unsigned long, unsigned long);
+void mpq_set_z (mpq_t, const mpz_t);
+int mpq_sgn (const mpq_t);
+void mpq_sub (mpq_t, const mpq_t, const mpq_t);
+void mpq_swap (mpq_t, mpq_t);
+
+/* This long list taken from gmp.h. */
+/* For reference, "defined(EOF)" cannot be used here.  In g++ 2.95.4,
+   <iostream> defines EOF but not FILE.  */
+#if defined (FILE)                                              \
+  || defined (H_STDIO)                                          \
+  || defined (_H_STDIO)               /* AIX */                 \
+  || defined (_STDIO_H)               /* glibc, Sun, SCO */     \
+  || defined (_STDIO_H_)              /* BSD, OSF */            \
+  || defined (__STDIO_H)              /* Borland */             \
+  || defined (__STDIO_H__)            /* IRIX */                \
+  || defined (_STDIO_INCLUDED)        /* HPUX */                \
+  || defined (__dj_include_stdio_h_)  /* DJGPP */               \
+  || defined (_FILE_DEFINED)          /* Microsoft */           \
+  || defined (__STDIO__)              /* Apple MPW MrC */       \
+  || defined (_MSL_STDIO_H)           /* Metrowerks */          \
+  || defined (_STDIO_H_INCLUDED)      /* QNX4 */                \
+  || defined (_ISO_STDIO_ISO_H)       /* Sun C++ */             \
+  || defined (__STDIO_LOADED)         /* VMS */
+size_t mpq_out_str (FILE *, int, const mpq_t);
+#endif
+
+void mpz_set_q (mpz_t, const mpq_t);
+
+#if defined (__cplusplus)
+}
+#endif
+#endif /* __MINI_MPQ_H__ */
diff --git a/third_party/gmp/mini-gmp/tests/Makefile b/third_party/gmp/mini-gmp/tests/Makefile
new file mode 100644
index 0000000..7cc4485
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/Makefile
@@ -0,0 +1,65 @@
+# Note: Requires GNU make
+
+# Copyright 2011, 2012, 2014, 2016, 2018 Free Software Foundation, Inc.
+#
+# This file is part of the GNU MP Library test suite.
+#
+# The GNU MP Library test suite is free software; you can redistribute it
+# and/or modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 3 of the License,
+# or (at your option) any later version.
+#
+# The GNU MP Library test suite is distributed in the hope that it will be
+# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.
+
+srcdir=.
+MINI_GMP_DIR=..
+
+CC = gcc
+CFLAGS = -O -Wall -g
+CPPFLAGS =
+LDFLAGS =
+
+LIBS = -lgmp -lm -lmcheck
+
+CHECK_PROGRAMS = t-add t-sub t-mul t-invert t-div t-div_2exp \
+	t-double t-cmp_d t-gcd t-lcm t-import t-comb t-signed \
+	t-sqrt t-root t-powm t-logops t-bitops t-scan t-str \
+	t-reuse t-aorsmul t-limbs t-cong t-pprime_p t-lucm \
+	t-mpq_addsub t-mpq_muldiv t-mpq_muldiv_2exp t-mpq_str \
+	t-mpq_double
+# Default TESTS to all tests, allowing overriding TESTS for building tests
+# without running them.
+TESTS = $(CHECK_PROGRAMS)
+
+MISC_OBJS = hex-random.o mini-random.o testutils.o
+
+all:
+
+clean:
+	rm -f *.o $(CHECK_PROGRAMS)
+
+%: %.c
+.c:
+
+# Keep object files
+.PRECIOUS: %.o
+
+%.o: %.c $(MINI_GMP_DIR)/mini-gmp.h $(MINI_GMP_DIR)/mini-mpq.h hex-random.h mini-random.h
+	$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@
+
+testutils.o: $(MINI_GMP_DIR)/mini-gmp.c $(MINI_GMP_DIR)/mini-mpq.c
+
+%: %.o $(MISC_OBJS)
+	$(CC) $(CFLAGS) $(LDFLAGS) $^ $(LIBS) -o $@
+
+# Missing tests include:
+#   mpz_cmp_d, mpz_popcount, mpz_hamdist, mpz_ui_pow_ui
+
+check: $(CHECK_PROGRAMS)
+	$(srcdir)/run-tests $(TESTS)
diff --git a/third_party/gmp/mini-gmp/tests/hex-random.c b/third_party/gmp/mini-gmp/tests/hex-random.c
new file mode 100644
index 0000000..a5b405b
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/hex-random.c
@@ -0,0 +1,573 @@
+/*
+
+Copyright 2011, 2016, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <time.h>
+
+#ifdef __unix__
+# include <unistd.h>
+# include <sys/time.h>
+#endif
+
+#include "gmp.h"
+
+#include "hex-random.h"
+
+/* FIXME: gmp-impl.h included only for mpz_lucas_mod */
+/* #include "gmp-impl.h" */
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+#define mpz_lucas_mod  __gmpz_lucas_mod
+__GMP_DECLSPEC int mpz_lucas_mod (mpz_ptr, mpz_ptr, long, mp_bitcnt_t, mpz_srcptr, mpz_ptr, mpz_ptr);
+
+#if defined (__cplusplus)
+}
+#endif
+
+static gmp_randstate_t state;
+
+static void
+mkseed (mpz_t seed)
+{
+  FILE *f = fopen ("/dev/urandom", "rb");
+  if (f)
+    {
+      unsigned char buf[6];
+      size_t res;
+
+      setbuf (f, NULL);
+      res = fread (buf, sizeof(buf), 1, f);
+      fclose (f);
+
+      if (res == 1)
+	{
+	  mpz_import (seed, sizeof(buf), 1, 1, 0, 0, buf);
+	  return;
+	}
+    }
+
+#ifdef __unix__
+  {
+    struct timeval tv;
+    mpz_t usec;
+    mpz_init (usec);
+
+    gettimeofday (&tv, NULL);
+    mpz_set_ui (seed, tv.tv_sec);
+    mpz_set_ui (usec, tv.tv_usec);
+    /* usec fits in 20 bits, shift left to make it 48 bits. */
+    mpz_mul_2exp (usec, usec, 28);
+    mpz_xor (seed, seed, usec);
+
+    mpz_clear (usec);
+  }
+#else
+  mpz_set_ui (seed, time (NULL));
+#endif
+}
+
+void
+hex_random_init (void)
+{
+  mpz_t seed;
+  char *env_seed;
+
+  mpz_init (seed);
+
+  env_seed = getenv ("GMP_CHECK_RANDOMIZE");
+  if (env_seed && env_seed[0])
+    {
+      mpz_set_str (seed, env_seed, 0);
+      if (mpz_cmp_ui (seed, 0) != 0)
+	gmp_printf ("Re-seeding with GMP_CHECK_RANDOMIZE=%Zd\n", seed);
+      else
+	{
+	  mkseed (seed);
+	  gmp_printf ("Seed GMP_CHECK_RANDOMIZE=%Zd (include this in bug reports)\n", seed);
+	}
+      fflush (stdout);
+    }
+  else
+    mpz_set_ui (seed, 4711);
+
+  gmp_randinit_default (state);
+  gmp_randseed (state, seed);
+
+  mpz_clear (seed);
+}
+
+char *
+hex_urandomb (unsigned long bits)
+{
+  char *res;
+  mpz_t x;
+
+  mpz_init (x);
+  mpz_urandomb (x, state, bits);
+  gmp_asprintf (&res, "%Zx", x);
+  mpz_clear (x);
+  return res;
+}
+
+char *
+hex_rrandomb (unsigned long bits)
+{
+  char *res;
+  mpz_t x;
+
+  mpz_init (x);
+  mpz_rrandomb (x, state, bits);
+  gmp_asprintf (&res, "%Zx", x);
+  mpz_clear (x);
+  return res;
+}
+
+char *
+hex_rrandomb_export (void *dst, size_t *countp,
+		     int order, size_t size, int endian, unsigned long bits)
+{
+  char *res;
+  mpz_t x;
+  mpz_init (x);
+  mpz_rrandomb (x, state, bits);
+  gmp_asprintf (&res, "%Zx", x);
+  mpz_export (dst, countp, order, size, endian, 0, x);
+  mpz_clear (x);
+  return res;
+}
+
+void hex_random_op2 (enum hex_random_op op,  unsigned long maxbits,
+		     char **ap, char **rp)
+{
+  mpz_t a, r;
+  unsigned long abits;
+  unsigned signs;
+
+  mpz_init (a);
+  mpz_init (r);
+
+  abits = gmp_urandomb_ui (state, 32) % maxbits;
+
+  mpz_rrandomb (a, state, abits);
+
+  signs = gmp_urandomb_ui (state, 1);
+  if (signs & 1)
+    mpz_neg (a, a);
+
+  switch (op)
+    {
+    default:
+      abort ();
+    case OP_SQR:
+      mpz_mul (r, a, a);
+      break;
+    }
+
+  gmp_asprintf (ap, "%Zx", a);
+  gmp_asprintf (rp, "%Zx", r);
+
+  mpz_clear (a);
+  mpz_clear (r);
+}
+
+void
+hex_random_op3 (enum hex_random_op op,  unsigned long maxbits,
+		char **ap, char **bp, char **rp)
+{
+  mpz_t a, b, r;
+  unsigned long abits, bbits;
+  unsigned signs;
+
+  mpz_init (a);
+  mpz_init (b);
+  mpz_init (r);
+
+  abits = gmp_urandomb_ui (state, 32) % maxbits;
+  bbits = gmp_urandomb_ui (state, 32) % maxbits;
+
+  mpz_rrandomb (a, state, abits);
+  mpz_rrandomb (b, state, bbits);
+
+  signs = gmp_urandomb_ui (state, 3);
+  if (signs & 1)
+    mpz_neg (a, a);
+  if (signs & 2)
+    mpz_neg (b, b);
+
+  switch (op)
+    {
+    default:
+      abort ();
+    case OP_ADD:
+      mpz_add (r, a, b);
+      break;
+    case OP_SUB:
+      mpz_sub (r, a, b);
+      break;
+    case OP_MUL:
+      mpz_mul (r, a, b);
+      break;
+    case OP_GCD:
+      if (signs & 4)
+	{
+	  /* Produce a large gcd */
+	  unsigned long gbits = gmp_urandomb_ui (state, 32) % maxbits;
+	  mpz_rrandomb (r, state, gbits);
+	  mpz_mul (a, a, r);
+	  mpz_mul (b, b, r);
+	}
+      mpz_gcd (r, a, b);
+      break;
+    case OP_LCM:
+      if (signs & 4)
+	{
+	  /* Produce a large gcd */
+	  unsigned long gbits = gmp_urandomb_ui (state, 32) % maxbits;
+	  mpz_rrandomb (r, state, gbits);
+	  mpz_mul (a, a, r);
+	  mpz_mul (b, b, r);
+	}
+      mpz_lcm (r, a, b);
+      break;
+    case OP_AND:
+      mpz_and (r, a, b);
+      break;
+    case OP_IOR:
+      mpz_ior (r, a, b);
+      break;
+    case OP_XOR:
+      mpz_xor (r, a, b);
+      break;
+    }
+
+  gmp_asprintf (ap, "%Zx", a);
+  gmp_asprintf (bp, "%Zx", b);
+  gmp_asprintf (rp, "%Zx", r);
+
+  mpz_clear (a);
+  mpz_clear (b);
+  mpz_clear (r);
+}
+
+void
+hex_random_op4 (enum hex_random_op op, unsigned long maxbits,
+		char **ap, char **bp, char **cp, char **dp)
+{
+  mpz_t a, b, c, d;
+  unsigned long abits, bbits;
+  unsigned signs;
+
+  mpz_init (a);
+  mpz_init (b);
+  mpz_init (c);
+  mpz_init (d);
+
+  if (op == OP_POWM)
+    {
+      unsigned long cbits;
+      abits = gmp_urandomb_ui (state, 32) % maxbits;
+      bbits = 1 + gmp_urandomb_ui (state, 32) % maxbits;
+      cbits = 2 + gmp_urandomb_ui (state, 32) % maxbits;
+
+      mpz_rrandomb (a, state, abits);
+      mpz_rrandomb (b, state, bbits);
+      mpz_rrandomb (c, state, cbits);
+
+      signs = gmp_urandomb_ui (state, 3);
+      if (signs & 1)
+	mpz_neg (a, a);
+      if (signs & 2)
+	{
+	  mpz_t g;
+
+	  /* If we negate the exponent, must make sure that gcd(a, c) = 1 */
+	  if (mpz_sgn (a) == 0)
+	    mpz_set_ui (a, 1);
+	  else
+	    {
+	      mpz_init (g);
+
+	      for (;;)
+		{
+		  mpz_gcd (g, a, c);
+		  if (mpz_cmp_ui (g, 1) == 0)
+		    break;
+		  mpz_divexact (a, a, g);
+		}
+	      mpz_clear (g);
+	    }
+	  mpz_neg (b, b);
+	}
+      if (signs & 4)
+	mpz_neg (c, c);
+
+      mpz_powm (d, a, b, c);
+    }
+  else
+    {
+      unsigned long qbits;
+      bbits = 1 + gmp_urandomb_ui (state, 32) % maxbits;
+      qbits = gmp_urandomb_ui (state, 32) % maxbits;
+      abits = bbits + qbits;
+      if (abits > 30)
+	abits -= 30;
+      else
+	abits = 0;
+
+      mpz_rrandomb (a, state, abits);
+      mpz_rrandomb (b, state, bbits);
+
+      signs = gmp_urandomb_ui (state, 2);
+      if (signs & 1)
+	mpz_neg (a, a);
+      if (signs & 2)
+	mpz_neg (b, b);
+
+      switch (op)
+	{
+	default:
+	  abort ();
+	case OP_CDIV:
+	  mpz_cdiv_qr (c, d, a, b);
+	  break;
+	case OP_FDIV:
+	  mpz_fdiv_qr (c, d, a, b);
+	  break;
+	case OP_TDIV:
+	  mpz_tdiv_qr (c, d, a, b);
+	  break;
+	}
+    }
+  gmp_asprintf (ap, "%Zx", a);
+  gmp_asprintf (bp, "%Zx", b);
+  gmp_asprintf (cp, "%Zx", c);
+  gmp_asprintf (dp, "%Zx", d);
+
+  mpz_clear (a);
+  mpz_clear (b);
+  mpz_clear (c);
+  mpz_clear (d);
+}
+
+void
+hex_random_bit_op (enum hex_random_op op, unsigned long maxbits,
+		   char **ap, unsigned long *b, char **rp)
+{
+  mpz_t a, r;
+  unsigned long abits, bbits;
+  unsigned signs;
+
+  mpz_init (a);
+  mpz_init (r);
+
+  abits = gmp_urandomb_ui (state, 32) % maxbits;
+  bbits = gmp_urandomb_ui (state, 32) % (maxbits + 100);
+
+  mpz_rrandomb (a, state, abits);
+
+  signs = gmp_urandomb_ui (state, 1);
+  if (signs & 1)
+    mpz_neg (a, a);
+
+  switch (op)
+    {
+    default:
+      abort ();
+
+    case OP_SETBIT:
+      mpz_set (r, a);
+      mpz_setbit (r, bbits);
+      break;
+    case OP_CLRBIT:
+      mpz_set (r, a);
+      mpz_clrbit (r, bbits);
+      break;
+    case OP_COMBIT:
+      mpz_set (r, a);
+      mpz_combit (r, bbits);
+      break;
+    case OP_CDIV_Q_2:
+      mpz_cdiv_q_2exp (r, a, bbits);
+      break;
+    case OP_CDIV_R_2:
+      mpz_cdiv_r_2exp (r, a, bbits);
+      break;
+    case OP_FDIV_Q_2:
+      mpz_fdiv_q_2exp (r, a, bbits);
+      break;
+    case OP_FDIV_R_2:
+      mpz_fdiv_r_2exp (r, a, bbits);
+      break;
+    case OP_TDIV_Q_2:
+      mpz_tdiv_q_2exp (r, a, bbits);
+      break;
+    case OP_TDIV_R_2:
+      mpz_tdiv_r_2exp (r, a, bbits);
+      break;
+    }
+
+  gmp_asprintf (ap, "%Zx", a);
+  *b = bbits;
+  gmp_asprintf (rp, "%Zx", r);
+
+  mpz_clear (a);
+  mpz_clear (r);
+}
+
+void
+hex_random_scan_op (enum hex_random_op op, unsigned long maxbits,
+		    char **ap, unsigned long *b, unsigned long *r)
+{
+  mpz_t a;
+  unsigned long abits, bbits;
+  unsigned signs;
+
+  mpz_init (a);
+
+  abits = gmp_urandomb_ui (state, 32) % maxbits;
+  bbits = gmp_urandomb_ui (state, 32) % (maxbits + 100);
+
+  mpz_rrandomb (a, state, abits);
+
+  signs = gmp_urandomb_ui (state, 1);
+  if (signs & 1)
+    mpz_neg (a, a);
+
+  switch (op)
+    {
+    default:
+      abort ();
+
+    case OP_SCAN0:
+      *r = mpz_scan0 (a, bbits);
+      break;
+    case OP_SCAN1:
+      *r = mpz_scan1 (a, bbits);
+      break;
+    }
+  gmp_asprintf (ap, "%Zx", a);
+  *b = bbits;
+
+  mpz_clear (a);
+}
+
+void
+hex_random_str_op (unsigned long maxbits,
+		   int base, char **ap, char **rp)
+{
+  mpz_t a;
+  unsigned long abits;
+  unsigned signs;
+
+  mpz_init (a);
+
+  abits = gmp_urandomb_ui (state, 32) % maxbits;
+
+  mpz_rrandomb (a, state, abits);
+
+  signs = gmp_urandomb_ui (state, 2);
+  if (signs & 1)
+    mpz_neg (a, a);
+
+  *ap = mpz_get_str (NULL, 16, a);
+  *rp = mpz_get_str (NULL, base, a);
+
+  mpz_clear (a);
+}
+
+void hex_random_lucm_op (unsigned long maxbits,
+			 char **vp, char **qp, char **mp,
+			 long *Q, unsigned long *b0, int *res)
+{
+  mpz_t m, v, q, t1, t2;
+  unsigned long mbits;
+
+  mpz_init (m);
+  mpz_init (v);
+  mpz_init (q);
+  mpz_init (t1);
+  mpz_init (t2);
+
+  *Q = gmp_urandomb_ui (state, 14) + 1;
+
+  do
+    {
+      mbits = gmp_urandomb_ui (state, 32) % maxbits + 5;
+
+      mpz_rrandomb (m, state, mbits);
+      *b0 = gmp_urandomb_ui (state, 32) % (mbits - 3) + 2;
+      /* The GMP  implementation uses the exponent (m >> b0) + 1. */
+      /* mini-gmp implementation uses the exponent (m >> b0) | 1. */
+      /* They are the same (and are used) only when (m >> b0) is even */
+      mpz_clrbit (m, *b0);
+      /* mini-gmp implementation only works if the modulus is odd. */
+      mpz_setbit (m, 0);
+    }
+  while (mpz_gcd_ui (NULL, m, *Q) != 1);
+
+  if (*Q == 1 || gmp_urandomb_ui (state, 1))
+    *Q = - *Q;
+
+#if (__GNU_MP_VERSION == 6 && (__GNU_MP_VERSION_MINOR > 1 || __GNU_MP_VERSION_PATCHLEVEL > 9))
+  *res = mpz_lucas_mod (v, q, *Q, *b0, m, t1, t2);
+#else
+  *b0 = 0;
+#endif
+
+  gmp_asprintf (vp, "%Zx", v);
+  gmp_asprintf (qp, "%Zx", q);
+  gmp_asprintf (mp, "%Zx", m);
+
+  mpz_clear (m);
+  mpz_clear (v);
+  mpz_clear (q);
+  mpz_clear (t1);
+  mpz_clear (t2);
+}
+
+void
+hex_mpq_random_str_op (unsigned long maxbits,
+		       int base, char **ap, char **rp)
+{
+  mpq_t a;
+  unsigned long abits;
+  unsigned signs;
+
+  mpq_init (a);
+
+  abits = gmp_urandomb_ui (state, 32) % maxbits;
+
+  mpz_rrandomb (mpq_numref (a), state, abits);
+  mpz_rrandomb (mpq_denref (a), state, abits);
+  mpz_add_ui (mpq_denref (a), mpq_denref (a), 1);
+
+  mpq_canonicalize (a);
+  signs = gmp_urandomb_ui (state, 2);
+  if (signs & 1)
+    mpq_neg (a, a);
+
+  *ap = mpq_get_str (NULL, 16, a);
+  *rp = mpq_get_str (NULL, base, a);
+
+  mpq_clear (a);
+}
diff --git a/third_party/gmp/mini-gmp/tests/hex-random.h b/third_party/gmp/mini-gmp/tests/hex-random.h
new file mode 100644
index 0000000..da44347
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/hex-random.h
@@ -0,0 +1,55 @@
+/*
+
+Copyright 2011, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+enum hex_random_op
+  {
+    OP_ADD, OP_SUB, OP_MUL, OP_SQR,
+    OP_CDIV, OP_FDIV, OP_TDIV,
+    OP_CDIV_Q_2, OP_CDIV_R_2,
+    OP_FDIV_Q_2, OP_FDIV_R_2,
+    OP_TDIV_Q_2,  OP_TDIV_R_2,
+    OP_GCD, OP_LCM, OP_POWM, OP_AND, OP_IOR, OP_XOR,
+    OP_SETBIT, OP_CLRBIT, OP_COMBIT,
+    OP_SCAN0, OP_SCAN1,
+  };
+
+void hex_random_init (void);
+char *hex_urandomb (unsigned long bits);
+char *hex_rrandomb (unsigned long bits);
+char *hex_rrandomb_export (void *dst, size_t *countp,
+			   int order, size_t size, int endian,
+			   unsigned long bits);
+
+void hex_random_op2 (enum hex_random_op op,  unsigned long maxbits,
+		     char **ap, char **rp);
+void hex_random_op3 (enum hex_random_op op,  unsigned long maxbits,
+		     char **ap, char **bp, char **rp);
+void hex_random_op4 (enum hex_random_op op,  unsigned long maxbits,
+		     char **ap, char **bp, char **rp, char **qp);
+void hex_random_bit_op (enum hex_random_op op, unsigned long maxbits,
+			char **ap, unsigned long *b, char **rp);
+void hex_random_scan_op (enum hex_random_op op, unsigned long maxbits,
+			char **ap, unsigned long *b, unsigned long *r);
+void hex_random_str_op (unsigned long maxbits,
+			int base, char **ap, char **rp);
+void hex_random_lucm_op (unsigned long maxbits,
+			 char **vp, char **qp, char **mp,
+			 long *Q, unsigned long *b0, int *res);
+void hex_mpq_random_str_op (unsigned long maxbits,
+			    int base, char **ap, char **rp);
diff --git a/third_party/gmp/mini-gmp/tests/mini-random.c b/third_party/gmp/mini-gmp/tests/mini-random.c
new file mode 100644
index 0000000..7504af3
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/mini-random.c
@@ -0,0 +1,160 @@
+/*
+
+Copyright 2011, 2013, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "mini-random.h"
+
+static void
+set_str (mpz_t r, const char *s)
+{
+  if (mpz_set_str (r, s, 16) != 0)
+    {
+      fprintf (stderr, "mpz_set_str failed on input %s\n", s);
+      abort ();
+    }
+}
+
+void
+mini_urandomb (mpz_t r, unsigned long bits)
+{
+  char *s;
+  s = hex_urandomb (bits);
+  set_str (r, s);
+  free (s);
+}
+
+void
+mini_rrandomb (mpz_t r, unsigned long bits)
+{
+  char *s;
+  s = hex_rrandomb (bits);
+  set_str (r, s);
+  free (s);
+}
+
+void
+mini_rrandomb_export (mpz_t r, void *dst, size_t *countp,
+		      int order, size_t size, int endian, unsigned long bits)
+{
+  char *s;
+  s = hex_rrandomb_export (dst, countp, order, size, endian, bits);
+  set_str (r, s);
+  free (s);
+}
+
+void
+mini_random_op2 (enum hex_random_op op, unsigned long maxbits,
+		 mpz_t a, mpz_t r)
+{
+  char *ap;
+  char *rp;
+
+  hex_random_op2 (op, maxbits, &ap, &rp);
+  set_str (a, ap);
+  set_str (r, rp);
+
+  free (ap);
+  free (rp);
+}
+
+void
+mini_random_op3 (enum hex_random_op op, unsigned long maxbits,
+		 mpz_t a, mpz_t b, mpz_t r)
+{
+  char *ap;
+  char *bp;
+  char *rp;
+
+  hex_random_op3 (op, maxbits, &ap, &bp, &rp);
+  set_str (a, ap);
+  set_str (b, bp);
+  set_str (r, rp);
+
+  free (ap);
+  free (bp);
+  free (rp);
+}
+
+void
+mini_random_op4 (enum hex_random_op op, unsigned long maxbits,
+		 mpz_t a, mpz_t b, mpz_t c, mpz_t d)
+{
+  char *ap;
+  char *bp;
+  char *cp;
+  char *dp;
+
+  hex_random_op4 (op, maxbits, &ap, &bp, &cp, &dp);
+  set_str (a, ap);
+  set_str (b, bp);
+  set_str (c, cp);
+  set_str (d, dp);
+
+  free (ap);
+  free (bp);
+  free (cp);
+  free (dp);
+}
+
+void
+mini_random_bit_op (enum hex_random_op op, unsigned long maxbits,
+			 mpz_t a, mp_bitcnt_t *b, mpz_t r)
+{
+  char *ap;
+  char *rp;
+
+  hex_random_bit_op (op, maxbits, &ap, b, &rp);
+  set_str (a, ap);
+  set_str (r, rp);
+
+  free (ap);
+  free (rp);
+}
+
+void
+mini_random_scan_op (enum hex_random_op op, unsigned long maxbits,
+		     mpz_t a, mp_bitcnt_t *b, mp_bitcnt_t *r)
+{
+  char *ap;
+
+  hex_random_scan_op (op, maxbits, &ap, b, r);
+  set_str (a, ap);
+
+  free (ap);
+}
+
+void
+mini_random_lucm_op (unsigned long maxbits, mpz_t v, mpz_t q, mpz_t m,
+			  long *Q, unsigned long *b0, int *res)
+{
+  char *vp;
+  char *qp;
+  char *mp;
+
+  hex_random_lucm_op (maxbits, &vp, &qp, &mp, Q, b0, res);
+  set_str (v, vp);
+  set_str (q, qp);
+  set_str (m, mp);
+
+  free (vp);
+  free (qp);
+  free (mp);
+}
diff --git a/third_party/gmp/mini-gmp/tests/mini-random.h b/third_party/gmp/mini-gmp/tests/mini-random.h
new file mode 100644
index 0000000..2f54749
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/mini-random.h
@@ -0,0 +1,35 @@
+/*
+
+Copyright 2011, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "../mini-gmp.h"
+#include "hex-random.h"
+
+void mini_urandomb (mpz_t, unsigned long);
+void mini_rrandomb (mpz_t, unsigned long);
+void mini_rrandomb_export (mpz_t r, void *dst, size_t *countp,
+			   int order, size_t size, int endian,
+			   unsigned long bits);
+
+void mini_random_op2 (enum hex_random_op,  unsigned long, mpz_t, mpz_t);
+void mini_random_op3 (enum hex_random_op,  unsigned long, mpz_t, mpz_t, mpz_t);
+void mini_random_op4 (enum hex_random_op, unsigned long, mpz_t, mpz_t, mpz_t, mpz_t);
+void mini_random_scan_op (enum hex_random_op, unsigned long, mpz_t, mp_bitcnt_t *, mp_bitcnt_t *);
+void mini_random_bit_op (enum hex_random_op, unsigned long, mpz_t, mp_bitcnt_t *, mpz_t);
+void mini_random_lucm_op (unsigned long, mpz_t, mpz_t, mpz_t,
+			  long *, unsigned long *, int *);
diff --git a/third_party/gmp/mini-gmp/tests/run-tests b/third_party/gmp/mini-gmp/tests/run-tests
new file mode 100755
index 0000000..5d452d6
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/run-tests
@@ -0,0 +1,135 @@
+#! /bin/sh
+
+# Copyright (C) 2000-2002, 2004, 2005, 2011, 2012, 2016  Niels Möller
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+failed=0
+all=0
+
+debug='no'
+testflags=''
+
+if [ -z "$srcdir" ] ; then
+  srcdir=`pwd`
+fi
+
+export srcdir
+
+# When used in make rules, we sometimes get the filenames VPATH
+# expanded, but usually not.
+find_program () {
+    case "$1" in
+	*/*)
+	  echo "$1"
+	  ;;
+	*)
+	  if [ -x "$1" ] ; then
+	      echo "./$1"
+	  else
+	      echo "$srcdir/$1"
+	  fi
+	  ;;
+    esac
+}
+
+env_program () {
+  if [ -x "$1" ] ; then
+    if "$1"; then : ; else
+      echo FAIL: $1
+      exit 1
+    fi
+  fi
+}
+
+TEST_LD_LIBRARY_PATH="$LD_LIBRARY_PATH"
+TEST_DYLD_LIBRARY_PATH="$DYLD_LIBRARY_PATH"
+
+if [ "$TEST_LIBRARY_PATH" ] ; then
+  TEST_LD_LIBRARY_PATH="$TEST_LIBRARY_PATH:$TEST_LD_LIBRARY_PATH"
+  TEST_DYLD_LIBRARY_PATH="$TEST_LIBRARY_PATH:$TEST_DYLD_LIBRARY_PATH"
+fi
+
+test_program () {
+  testname=`basename "$1" .exe`
+  testname=`basename "$testname" -test`
+  if [ -z "$EMULATOR" ] || head -1 "$1" | grep '^#!' > /dev/null; then
+    LD_LIBRARY_PATH="$TEST_LD_LIBRARY_PATH" \
+    DYLD_LIBRARY_PATH="$TEST_DYLD_LIBRARY_PATH" \
+    "$1" $testflags
+  else
+    $EMULATOR "$1" $testflags
+  fi
+  case "$?" in
+      0)
+	echo PASS: $testname
+	all=`expr $all + 1`
+	;;
+      77)
+	echo SKIP: $testname
+      ;;
+      *)
+	echo FAIL: $testname
+	failed=`expr $failed + 1`
+	all=`expr $all + 1`
+	;;
+  esac
+}
+
+env_program `find_program setup-env`
+
+while test $# != 0
+do
+  case "$1" in
+  --debug)
+    debug=yes
+    ;;
+  -v)
+    testflags='-v'
+    ;;
+  -*)
+    echo >&2 'Unknown option `'"$1'"
+    exit 1
+    ;;
+  *)
+    break
+    ;;
+  esac
+  shift
+done
+
+# Comment out special handling for zero arguments to support separate
+# tests-build/tests-run.
+#if [ $# -eq 0 ] ; then
+#  for f in *-test; do test_program "./$f"; done
+#else
+  for f in "$@" ; do test_program `find_program "$f"`; done
+#fi
+
+if [ $failed -eq 0 ] ; then
+  banner="All $all tests passed"
+else
+  banner="$failed of $all tests failed"
+fi
+dashes=`echo "$banner" | sed s/./=/g`
+echo "$dashes"
+echo "$banner"
+echo "$dashes"
+
+if [ "x$debug" = xno ] ; then
+  env_program `find_program teardown-env`
+fi
+
+[ "$failed" -eq 0 ]
diff --git a/third_party/gmp/mini-gmp/tests/t-add.c b/third_party/gmp/mini-gmp/tests/t-add.c
new file mode 100644
index 0000000..0a093ef
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-add.c
@@ -0,0 +1,57 @@
+/*
+
+Copyright 2012, Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "testutils.h"
+
+#define MAXBITS 400
+#define COUNT 10000
+
+void
+testmain (int argc, char **argv)
+{
+  unsigned i;
+  mpz_t a, b, res, ref;
+
+  mpz_init (a);
+  mpz_init (b);
+  mpz_init (res);
+  mpz_init (ref);
+
+  for (i = 0; i < COUNT; i++)
+    {
+      mini_random_op3 (OP_ADD, MAXBITS, a, b, ref);
+      mpz_add (res, a, b);
+      if (mpz_cmp (res, ref))
+	{
+	  fprintf (stderr, "mpz_add failed:\n");
+	  dump ("a", a);
+	  dump ("b", b);
+	  dump ("r", res);
+	  dump ("ref", ref);
+	  abort ();
+	}
+    }
+  mpz_clear (a);
+  mpz_clear (b);
+  mpz_clear (res);
+  mpz_clear (ref);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-aorsmul.c b/third_party/gmp/mini-gmp/tests/t-aorsmul.c
new file mode 100644
index 0000000..eb275a8
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-aorsmul.c
@@ -0,0 +1,77 @@
+/*
+
+Copyright 2012, 2014, Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "testutils.h"
+
+#define MAXBITS 400
+#define COUNT 10000
+
+#define GMP_LIMB_BITS (sizeof(mp_limb_t) * CHAR_BIT)
+#define MAXLIMBS ((MAXBITS + GMP_LIMB_BITS - 1) / GMP_LIMB_BITS)
+
+void
+testmain (int argc, char **argv)
+{
+  unsigned i;
+  mpz_t a, b, res, ref;
+
+  mpz_init (a);
+  mpz_init (b);
+  mpz_init_set_ui (res, 5);
+  mpz_init (ref);
+
+  for (i = 0; i < COUNT; i++)
+    {
+      mini_random_op3 (OP_MUL, MAXBITS, a, b, ref);
+      if (i & 1) {
+	mpz_add (ref, ref, res);
+	if (mpz_fits_ulong_p (b))
+	  mpz_addmul_ui (res, a, mpz_get_ui (b));
+	else
+	  mpz_addmul (res, a, b);
+      } else {
+	mpz_sub (ref, res, ref);
+	if (mpz_fits_ulong_p (b))
+	  mpz_submul_ui (res, a, mpz_get_ui (b));
+	else
+	  mpz_submul (res, a, b);
+      }
+      if (mpz_cmp (res, ref))
+	{
+	  if (i & 1)
+	    fprintf (stderr, "mpz_addmul failed:\n");
+	  else
+	    fprintf (stderr, "mpz_submul failed:\n");
+	  dump ("a", a);
+	  dump ("b", b);
+	  dump ("r", res);
+	  dump ("ref", ref);
+	  abort ();
+	}
+    }
+  mpz_clear (a);
+  mpz_clear (b);
+  mpz_clear (res);
+  mpz_clear (ref);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-bitops.c b/third_party/gmp/mini-gmp/tests/t-bitops.c
new file mode 100644
index 0000000..27d87ca
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-bitops.c
@@ -0,0 +1,104 @@
+/*
+
+Copyright 2012, Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "testutils.h"
+
+#define MAXBITS 400
+#define COUNT 10000
+
+void
+testmain (int argc, char **argv)
+{
+  unsigned i;
+  mpz_t a, res, ref;
+  mp_bitcnt_t b;
+
+  mpz_init (a);
+  mpz_init (res);
+  mpz_init (ref);
+
+  for (i = 0; i < COUNT; i++)
+    {
+      mini_random_bit_op (OP_SETBIT, MAXBITS, a, &b, ref);
+      mpz_set (res, a);
+      mpz_setbit (res, b);
+      if (mpz_cmp (res, ref))
+	{
+	  fprintf (stderr, "mpz_setbit failed:\n");
+	  dump ("a", a);
+	  fprintf (stderr, "b: %lu\n", b);
+	  dump ("r", res);
+	  dump ("ref", ref);
+	  abort ();
+	}
+      if (!mpz_tstbit (res, b))
+	{
+	  fprintf (stderr, "mpz_tstbit failed (after mpz_setbit):\n");
+	  dump ("res", a);
+	  fprintf (stderr, "b: %lu\n", b);
+	  abort ();
+	}
+      mini_random_bit_op (OP_CLRBIT, MAXBITS, a, &b, ref);
+      mpz_set (res, a);
+      mpz_clrbit (res, b);
+      if (mpz_cmp (res, ref))
+	{
+	  fprintf (stderr, "mpz_clrbit failed:\n");
+	  dump ("a", a);
+	  fprintf (stderr, "b: %lu\n", b);
+	  dump ("r", res);
+	  dump ("ref", ref);
+	  abort ();
+	}
+      if (mpz_tstbit (res, b))
+	{
+	  fprintf (stderr, "mpz_tstbit failed (after mpz_clrbit):\n");
+	  dump ("res", a);
+	  fprintf (stderr, "b: %lu\n", b);
+	  abort ();
+	}
+      mini_random_bit_op (OP_COMBIT, MAXBITS, a, &b, ref);
+      mpz_set (res, a);
+      mpz_com (a, a);
+      mpz_combit (res, b);
+      if (mpz_cmp (res, ref))
+	{
+	  fprintf (stderr, "mpz_combit failed:\n");
+	  dump ("a", a);
+	  fprintf (stderr, "b: %lu\n", b);
+	  dump ("r", res);
+	  dump ("ref", ref);
+	  abort ();
+	}
+      if (mpz_tstbit (res, b) != mpz_tstbit (a, b))
+	{
+	  fprintf (stderr, "mpz_tstbit failed (after mpz_combit):\n");
+	  dump ("res", a);
+	  fprintf (stderr, "b: %lu\n", b);
+	  abort ();
+	}
+    }
+  mpz_clear (a);
+  mpz_clear (res);
+  mpz_clear (ref);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-cmp_d.c b/third_party/gmp/mini-gmp/tests/t-cmp_d.c
new file mode 100644
index 0000000..09ca810
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-cmp_d.c
@@ -0,0 +1,283 @@
+/* Test mpz_cmp_d and mpz_cmpabs_d.
+
+Copyright 2001-2003, 2005, 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <math.h>
+
+#include "testutils.h"
+
+/* FIXME: Not sure if the tests here are exhaustive.  Ought to try to get
+   each possible exit from mpz_cmp_d (and mpz_cmpabs_d) exercised.  */
+
+
+#define SGN(n)  ((n) > 0 ? 1 : (n) < 0 ? -1 : 0)
+
+
+void
+check_one (const char *name, mpz_srcptr x, double y, int cmp, int cmpabs)
+{
+  int   got;
+
+  got = mpz_cmp_d (x, y);
+  if (SGN(got) != cmp)
+    {
+      unsigned i;
+      printf    ("mpz_cmp_d wrong (from %s)\n", name);
+      printf    ("  got  %d\n", got);
+      printf    ("  want %d\n", cmp);
+    fail:
+      printf ("  x=");
+      mpz_out_str (stdout, 10, x);
+      printf    ("\n  y %g\n", y);
+      printf ("  x=0x");
+      mpz_out_str (stdout, -16, x);
+      printf    ("\n  y %g\n", y);
+      printf    ("  y");
+      for (i = 0; i < sizeof(y); i++)
+        printf (" %02X", (unsigned) ((unsigned char *) &y)[i]);
+      printf ("\n");
+      abort ();
+    }
+
+  got = mpz_cmpabs_d (x, y);
+  if (SGN(got) != cmpabs)
+    {
+      printf    ("mpz_cmpabs_d wrong\n");
+      printf    ("  got  %d\n", got);
+      printf    ("  want %d\n", cmpabs);
+      goto fail;
+    }
+}
+
+void
+check_data (void)
+{
+  static const struct {
+    const char  *x;
+    double      y;
+    int         cmp, cmpabs;
+
+  } data[] = {
+
+    {  "0",  0.0,  0,  0 },
+
+    {  "1",  0.0,  1,  1 },
+    { "-1",  0.0, -1,  1 },
+
+    {  "1",  0.5,  1,  1 },
+    { "-1", -0.5, -1,  1 },
+
+    {  "0",  1.0, -1, -1 },
+    {  "0", -1.0,  1, -1 },
+
+    {  "0x1000000000000000000000000000000000000000000000000", 1.0,  1, 1 },
+    { "-0x1000000000000000000000000000000000000000000000000", 1.0, -1, 1 },
+
+    {  "0",  1e100, -1, -1 },
+    {  "0", -1e100,  1, -1 },
+
+    {  "2",  1.5,   1,  1 },
+    {  "2", -1.5,   1,  1 },
+    { "-2",  1.5,  -1,  1 },
+    { "-2", -1.5,  -1,  1 },
+  };
+
+  mpz_t    x;
+  unsigned i;
+
+  mpz_init (x);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_set_str_or_abort (x, data[i].x, 0);
+      check_one ("check_data", x, data[i].y, data[i].cmp, data[i].cmpabs);
+    }
+
+  mpz_clear (x);
+}
+
+
+/* Equality of integers with up to 53 bits */
+void
+check_onebits (void)
+{
+  mpz_t   x, x2;
+  double  y;
+  int     i;
+
+  mpz_init_set_ui (x, 0L);
+  mpz_init (x2);
+
+  for (i = 0; i < 512; i++)
+    {
+      mpz_mul_2exp (x, x, 1);
+      mpz_add_ui (x, x, 1L);
+
+      y = mpz_get_d (x);
+      mpz_set_d (x2, y);
+
+      /* stop if any truncation is occurring */
+      if (mpz_cmp (x, x2) != 0)
+        break;
+
+      check_one ("check_onebits", x, y, 0, 0);
+      check_one ("check_onebits", x, -y, 1, 0);
+      mpz_neg (x, x);
+      check_one ("check_onebits", x, y, -1, 0);
+      check_one ("check_onebits", x, -y, 0, 0);
+      mpz_neg (x, x);
+    }
+
+  mpz_clear (x);
+  mpz_clear (x2);
+}
+
+
+/* With the mpz differing by 1, in a limb position possibly below the double */
+void
+check_low_z_one (void)
+{
+  mpz_t          x;
+  double         y;
+  unsigned long  i;
+
+  mpz_init (x);
+
+  /* FIXME: It'd be better to base this on the float format. */
+#if defined (__vax) || defined (__vax__)
+#define LIM 127			/* vax fp numbers have limited range */
+#else
+#define LIM 512
+#endif
+
+  for (i = 1; i < LIM; i++)
+    {
+      mpz_set_ui (x, 1L);
+      mpz_mul_2exp (x, x, i);
+      y = mpz_get_d (x);
+
+      check_one ("check_low_z_one", x, y,   0, 0);
+      check_one ("check_low_z_one", x, -y,  1, 0);
+      mpz_neg (x, x);
+      check_one ("check_low_z_one", x, y,  -1, 0);
+      check_one ("check_low_z_one", x, -y,  0, 0);
+      mpz_neg (x, x);
+
+      mpz_sub_ui (x, x, 1);
+
+      check_one ("check_low_z_one", x, y,  -1, -1);
+      check_one ("check_low_z_one", x, -y,  1, -1);
+      mpz_neg (x, x);
+      check_one ("check_low_z_one", x, y,  -1, -1);
+      check_one ("check_low_z_one", x, -y,  1, -1);
+      mpz_neg (x, x);
+
+      mpz_add_ui (x, x, 2);
+
+      check_one ("check_low_z_one", x, y,   1, 1);
+      check_one ("check_low_z_one", x, -y,  1, 1);
+      mpz_neg (x, x);
+      check_one ("check_low_z_one", x, y,  -1, 1);
+      check_one ("check_low_z_one", x, -y, -1, 1);
+      mpz_neg (x, x);
+    }
+
+  mpz_clear (x);
+}
+
+/* Comparing 1 and 1+2^-n.  "y" is volatile to make gcc store and fetch it,
+   which forces it to a 64-bit double, whereas on x86 it would otherwise
+   remain on the float stack as an 80-bit long double.  */
+void
+check_one_2exp (void)
+{
+  double           e;
+  mpz_t            x;
+  volatile double  y;
+  int              i;
+
+  mpz_init (x);
+
+  e = 1.0;
+  for (i = 0; i < 128; i++)
+    {
+      e /= 2.0;
+      y = 1.0 + e;
+      if (y == 1.0)
+        break;
+
+      mpz_set_ui (x, 1L);
+      check_one ("check_one_2exp", x,  y, -1, -1);
+      check_one ("check_one_2exp", x, -y,  1, -1);
+
+      mpz_set_si (x, -1L);
+      check_one ("check_one_2exp", x,  y, -1, -1);
+      check_one ("check_one_2exp", x, -y,  1, -1);
+    }
+
+  mpz_clear (x);
+}
+
+void
+check_infinity (void)
+{
+  mpz_t   x;
+  double  y = HUGE_VAL;
+  if (y != 2*y)
+    return;
+
+  mpz_init (x);
+
+  /* 0 cmp inf */
+  mpz_set_ui (x, 0L);
+  check_one ("check_infinity", x,  y, -1, -1);
+  check_one ("check_infinity", x, -y,  1, -1);
+
+  /* 123 cmp inf */
+  mpz_set_ui (x, 123L);
+  check_one ("check_infinity", x,  y, -1, -1);
+  check_one ("check_infinity", x, -y,  1, -1);
+
+  /* -123 cmp inf */
+  mpz_set_si (x, -123L);
+  check_one ("check_infinity", x,  y, -1, -1);
+  check_one ("check_infinity", x, -y,  1, -1);
+
+  /* 2^5000 cmp inf */
+  mpz_set_ui (x, 1L);
+  mpz_mul_2exp (x, x, 5000L);
+  check_one ("check_infinity", x,  y, -1, -1);
+  check_one ("check_infinity", x, -y,  1, -1);
+
+  /* -2^5000 cmp inf */
+  mpz_neg (x, x);
+  check_one ("check_infinity", x,  y, -1, -1);
+  check_one ("check_infinity", x, -y,  1, -1);
+
+  mpz_clear (x);
+}
+
+void
+testmain (int argc, char *argv[])
+{
+  check_data ();
+  check_onebits ();
+  check_low_z_one ();
+  check_one_2exp ();
+  check_infinity ();
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-comb.c b/third_party/gmp/mini-gmp/tests/t-comb.c
new file mode 100644
index 0000000..652bfcb
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-comb.c
@@ -0,0 +1,175 @@
+/* Exercise mpz_fac_ui and mpz_bin_uiui.
+
+Copyright 2000-2002, 2012, 2013, 2017-2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "testutils.h"
+
+/* Usage: t-fac_ui [x|num]
+
+   With no arguments testing goes up to the initial value of "limit" below.
+   With a number argument tests are carried that far, or with a literal "x"
+   tests are continued without limit (this being meant only for development
+   purposes).  */
+
+void
+try_mpz_bin_uiui (mpz_srcptr want, unsigned long n, unsigned long k)
+{
+  mpz_t  got;
+
+  mpz_init (got);
+  mpz_bin_uiui (got, n, k);
+  if (mpz_cmp (got, want) != 0)
+    {
+      printf ("mpz_bin_uiui wrong\n");
+      printf ("  n=%lu\n", n);
+      printf ("  k=%lu\n", k);
+      printf ("  got="); mpz_out_str (stdout, 10, got); printf ("\n");
+      printf ("  want="); mpz_out_str (stdout, 10, want); printf ("\n");
+      abort();
+    }
+  mpz_clear (got);
+}
+
+/* Test all bin(n,k) cases, with 0 <= k <= n + 1 <= count.  */
+void
+bin_smallexaustive (unsigned int count)
+{
+  mpz_t          want;
+  unsigned long  n, k;
+
+  mpz_init (want);
+
+  for (n = 0; n < count; n++)
+    {
+      mpz_set_ui (want, 1);
+      for (k = 0; k <= n; k++)
+	{
+	  try_mpz_bin_uiui (want, n, k);
+	  mpz_mul_ui (want, want, n - k);
+	  mpz_fdiv_q_ui (want, want, k + 1);
+	}
+      try_mpz_bin_uiui (want, n, k);
+    }
+
+  mpz_clear (want);
+}
+
+/* Test all fac(n) cases, with 0 <= n <= limit.  */
+void
+fac_smallexaustive (unsigned int limit)
+{
+  mpz_t          f, r;
+  unsigned long  n;
+  mpz_init_set_si (f, 1);  /* 0! = 1 */
+  mpz_init (r);
+
+  for (n = 0; n < limit; n++)
+    {
+      mpz_fac_ui (r, n);
+
+      if (mpz_cmp (f, r) != 0)
+        {
+          printf ("mpz_fac_ui(%lu) wrong\n", n);
+          printf ("  got  "); mpz_out_str (stdout, 10, r); printf("\n");
+          printf ("  want "); mpz_out_str (stdout, 10, f); printf("\n");
+          abort ();
+        }
+
+      mpz_mul_ui (f, f, n+1);  /* (n+1)! = n! * (n+1) */
+    }
+
+  mpz_clear (f);
+  mpz_clear (r);
+}
+
+void checkWilson (mpz_t f, unsigned long n)
+{
+  unsigned long m, a;
+
+  mpz_2fac_ui (f, 2 * n - 1);
+
+  a = mpz_fdiv_q_ui (f, f, n);
+  m = mpz_fdiv_ui (f, n);
+  if ((m != n - 1) || (a != 0))
+    {
+      printf ("mpz_2fac_ui(%lu) wrong\n", 2 * n - 1);
+      printf ("  Wilson's theorem not verified: got (%lu, %lu), expected (0, %lu).\n", a, m, n - 1);
+      abort ();
+    }
+
+  mpz_fac_ui (f, n - 1);
+  m = mpz_fdiv_ui (f, n);
+  if ( m != n - 1)
+    {
+      printf ("mpz_fac_ui(%lu) wrong\n", n - 1);
+      printf ("  Wilson's theorem not verified: got %lu, expected %lu.\n",m ,n - 1);
+      abort ();
+    }
+}
+
+void
+checkprimes (unsigned long p1, unsigned long p2, unsigned long p3)
+{
+  mpz_t          b, f;
+
+  if (p1 - 1 != p2 - 1 + p3 - 1)
+    {
+      printf ("checkprimes(%lu, %lu, %lu) wrong\n", p1, p2, p3);
+      printf (" %lu - 1 != %lu - 1 + %lu - 1 \n", p1, p2, p3);
+      abort ();
+    }
+
+  mpz_init (b);
+  mpz_init (f);
+
+  checkWilson (b, p1); /* b = (p1-1)! */
+  checkWilson (f, p2); /* f = (p2-1)! */
+  mpz_divexact (b, b, f);
+  checkWilson (f, p3); /* f = (p3-1)! */
+  mpz_divexact (b, b, f); /* b = (p1-1)!/((p2-1)!(p3-1)!) */
+  mpz_bin_uiui (f, p1 - 1, p2 - 1);
+  if (mpz_cmp (f, b) != 0)
+    {
+      printf ("checkprimes(%lu, %lu, %lu) wrong\n", p1, p2, p3);
+      printf ("  got  "); mpz_out_str (stdout, 10, b); printf("\n");
+      printf ("  want "); mpz_out_str (stdout, 10, f); printf("\n");
+      abort ();
+    }
+
+  mpz_clear (b);
+  mpz_clear (f);
+
+}
+
+void
+testmain (int argc, char *argv[])
+{
+  unsigned long  limit = 128;
+
+  if (argc > 1 && argv[1][0] == 'x')
+    limit = ~ limit;
+  else if (argc > 1)
+    limit = atoi (argv[1]);
+
+  checkprimes(1009, 733, 277);
+  fac_smallexaustive (limit);
+  bin_smallexaustive (limit);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-cong.c b/third_party/gmp/mini-gmp/tests/t-cong.c
new file mode 100644
index 0000000..92b6930
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-cong.c
@@ -0,0 +1,212 @@
+/* test mpz_congruent_p
+
+Copyright 2001, 2002, 2012, 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "testutils.h"
+
+#define MPZ_SRCPTR_SWAP(x, y)						\
+  do {									\
+    mpz_srcptr __mpz_srcptr_swap__tmp = (x);				\
+    (x) = (y);								\
+    (y) = __mpz_srcptr_swap__tmp;					\
+  } while (0)
+
+void
+check_one (mpz_srcptr a, mpz_srcptr c, mpz_srcptr d, int want)
+{
+  int   got;
+  int   swap;
+
+  for (swap = 0; swap <= 1; swap++)
+    {
+      got = (mpz_congruent_p (a, c, d) != 0);
+      if (want != got)
+	{
+	  printf ("mpz_congruent_p wrong\n");
+	  printf ("   expected %d got %d\n", want, got);
+	  dump ("	 a", a);
+	  dump ("	 c", c);
+	  dump ("	 d", d);
+	  abort ();
+	}
+
+#if 0
+      if (mpz_fits_ulong_p (c) && mpz_fits_ulong_p (d))
+	{
+	  unsigned long	 uc = mpz_get_ui (c);
+	  unsigned long	 ud = mpz_get_ui (d);
+	  got = (mpz_congruent_ui_p (a, uc, ud) != 0);
+	  if (want != got)
+	    {
+	      printf	("mpz_congruent_ui_p wrong\n");
+	      printf	("   expected %d got %d\n", want, got);
+	      dump ("   a", a);
+	      printf	("   c=%lu\n", uc);
+	      printf	("   d=%lu\n", ud);
+	      abort ();
+	    }
+	}
+#endif
+      MPZ_SRCPTR_SWAP (a, c);
+    }
+}
+
+
+void
+check_data (void)
+{
+  static const struct {
+    const char *a;
+    const char *c;
+    const char *d;
+    int        want;
+
+  } data[] = {
+
+    /* strict equality mod 0 */
+    { "0", "0", "0", 1 },
+    { "11", "11", "0", 1 },
+    { "3", "11", "0", 0 },
+
+    /* anything congruent mod 1 */
+    { "0", "0", "1", 1 },
+    { "1", "0", "1", 1 },
+    { "0", "1", "1", 1 },
+    { "123", "456", "1", 1 },
+    { "0x123456789123456789", "0x987654321987654321", "1", 1 },
+
+    /* csize==1, dsize==2 changing to 1 after stripping 2s */
+    { "0x3333333333333333",  "0x33333333",
+      "0x180000000", 1 },
+    { "0x33333333333333333333333333333333", "0x3333333333333333",
+      "0x18000000000000000", 1 },
+
+    /* another dsize==2 becoming 1, with opposite signs this time */
+    {  "0x444444441",
+      "-0x22222221F",
+       "0x333333330", 1 },
+    {  "0x44444444444444441",
+      "-0x2222222222222221F",
+       "0x33333333333333330", 1 },
+  };
+
+  mpz_t   a, c, d;
+  unsigned   i;
+
+  mpz_init (a);
+  mpz_init (c);
+  mpz_init (d);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_set_str_or_abort (a, data[i].a, 0);
+      mpz_set_str_or_abort (c, data[i].c, 0);
+      mpz_set_str_or_abort (d, data[i].d, 0);
+      check_one (a, c, d, data[i].want);
+    }
+
+  mpz_clear (a);
+  mpz_clear (c);
+  mpz_clear (d);
+}
+
+
+void
+check_random (int argc, char *argv[])
+{
+  mpz_t   a, c, d, ra, rc;
+  int     i;
+  int     want;
+  int     reps = 10000;
+  mpz_t bs;
+  unsigned long size_range, size;
+
+  if (argc >= 2)
+    reps = atoi (argv[1]);
+
+  mpz_init (bs);
+
+  mpz_init (a);
+  mpz_init (c);
+  mpz_init (d);
+  mpz_init (ra);
+  mpz_init (rc);
+
+  for (i = 0; i < reps; i++)
+    {
+      mini_urandomb (bs, 32);
+      size_range = mpz_get_ui (bs) % 13 + 1; /* 0..8192 bit operands */
+
+      mini_urandomb (bs, size_range);
+      size = mpz_get_ui (bs);
+      mini_rrandomb (a, size);
+
+      mini_urandomb (bs, 32);
+      size_range = mpz_get_ui (bs) % 13 + 1; /* 0..8192 bit operands */
+
+      mini_urandomb (bs, size_range);
+      size = mpz_get_ui (bs);
+      mini_rrandomb (c, size);
+
+      do
+	{
+	  mini_urandomb (bs, 32);
+	  size_range = mpz_get_ui (bs) % 13 + 1; /* 0..8192 bit operands */
+
+	  mini_urandomb (bs, size_range);
+	  size = mpz_get_ui (bs);
+	  mini_rrandomb (d, size);
+	}
+      while (mpz_sgn(d) == 0);
+
+      mini_urandomb (bs, 3);
+      if (mpz_tstbit (bs, 0))
+	mpz_neg (a, a);
+      if (mpz_tstbit (bs, 1))
+	mpz_neg (c, c);
+      if (mpz_tstbit (bs, 2))
+	mpz_neg (d, d);
+
+      mpz_fdiv_r (ra, a, d);
+      mpz_fdiv_r (rc, c, d);
+
+      want = (mpz_cmp (ra, rc) == 0);
+      check_one (a, c, d, want);
+
+      mpz_sub (ra, ra, rc);
+      mpz_sub (a, a, ra);
+      check_one (a, c, d, 1);
+
+    }
+
+  mpz_clear (bs);
+
+  mpz_clear (a);
+  mpz_clear (c);
+  mpz_clear (d);
+  mpz_clear (ra);
+  mpz_clear (rc);
+}
+
+
+void
+testmain (int argc, char *argv[])
+{
+  check_data ();
+  check_random (argc, argv);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-div.c b/third_party/gmp/mini-gmp/tests/t-div.c
new file mode 100644
index 0000000..be2f6b1
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-div.c
@@ -0,0 +1,258 @@
+/*
+
+Copyright 2012, 2013, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "testutils.h"
+
+#define MAXBITS 400
+#define COUNT 10000
+
+typedef void div_qr_func (mpz_t, mpz_t, const mpz_t, const mpz_t);
+typedef unsigned long div_qr_ui_func (mpz_t, mpz_t, const mpz_t, unsigned long);
+typedef void div_func (mpz_t, const mpz_t, const mpz_t);
+typedef unsigned long div_x_ui_func (mpz_t, const mpz_t, unsigned long);
+typedef unsigned long div_ui_func (const mpz_t, unsigned long);
+
+void
+testmain (int argc, char **argv)
+{
+  unsigned i;
+  mpz_t a, b, q, r, rq, rr;
+  int div_p;
+
+  mpz_init (a);
+  mpz_init (b);
+  mpz_init (r);
+  mpz_init (q);
+  mpz_init (rr);
+  mpz_init (rq);
+
+  for (i = 0; i < COUNT; i++)
+    {
+      unsigned j;
+      for (j = 0; j < 3; j++)
+	{
+	  static const enum hex_random_op ops[3] = { OP_CDIV, OP_FDIV, OP_TDIV };
+	  static const char name[3] = { 'c', 'f', 't'};
+	  static div_qr_func * const div_qr [3] =
+	    {
+	      mpz_cdiv_qr, mpz_fdiv_qr, mpz_tdiv_qr
+	    };
+	  static div_qr_ui_func * const div_qr_ui[3] =
+	    {
+	      mpz_cdiv_qr_ui, mpz_fdiv_qr_ui, mpz_tdiv_qr_ui
+	    };
+	  static div_func * const div_q [3] =
+	    {
+	      mpz_cdiv_q, mpz_fdiv_q, mpz_tdiv_q
+	    };
+	  static div_x_ui_func * const div_q_ui[3] =
+	    {
+	      mpz_cdiv_q_ui, mpz_fdiv_q_ui, mpz_tdiv_q_ui
+	    };
+	  static div_func * const div_r [3] =
+	    {
+	      mpz_cdiv_r, mpz_fdiv_r, mpz_tdiv_r
+	    };
+	  static div_x_ui_func * const div_r_ui[3] =
+	    {
+	      mpz_cdiv_r_ui, mpz_fdiv_r_ui, mpz_tdiv_r_ui
+	    };
+	  static div_ui_func * const div_ui[3] =
+	    {
+	      mpz_cdiv_ui, mpz_fdiv_ui, mpz_tdiv_ui
+	    };
+
+	  mini_random_op4 (ops[j], MAXBITS, a, b, rq, rr);
+	  div_qr[j] (q, r, a, b);
+	  if (mpz_cmp (r, rr) || mpz_cmp (q, rq))
+	    {
+	      fprintf (stderr, "mpz_%cdiv_qr failed:\n", name[j]);
+	      dump ("a", a);
+	      dump ("b", b);
+	      dump ("r   ", r);
+	      dump ("rref", rr);
+	      dump ("q   ", q);
+	      dump ("qref", rq);
+	      abort ();
+	    }
+	  mpz_set_si (q, -5);
+	  div_q[j] (q, a, b);
+	  if (mpz_cmp (q, rq))
+	    {
+	      fprintf (stderr, "mpz_%cdiv_q failed:\n", name[j]);
+	      dump ("a", a);
+	      dump ("b", b);
+	      dump ("q   ", q);
+	      dump ("qref", rq);
+	      abort ();
+	    }
+	  mpz_set_ui (r, ~5);
+	  div_r[j] (r, a, b);
+	  if (mpz_cmp (r, rr))
+	    {
+	      fprintf (stderr, "mpz_%cdiv_r failed:\n", name[j]);
+	      dump ("a", a);
+	      dump ("b", b);
+	      dump ("r   ", r);
+	      dump ("rref", rr);
+	      abort ();
+	    }
+
+	  if (j == 0)		/* do this once, not for all roundings */
+	    {
+	      div_p = mpz_divisible_p (a, b);
+	      if ((mpz_sgn (r) == 0) ^ (div_p != 0))
+		{
+		  fprintf (stderr, "mpz_divisible_p failed:\n");
+		  dump ("a", a);
+		  dump ("b", b);
+		  dump ("r   ", r);
+		  abort ();
+		}
+	    }
+
+	  mpz_set_si (r, -6);
+	  if (j == 0 && mpz_sgn (b) < 0)  /* ceil, negative divisor */
+	    {
+	      mpz_mod (r, a, b);
+	      if (mpz_cmp (r, rr))
+		{
+		  fprintf (stderr, "mpz_mod failed:\n");
+		  dump ("a", a);
+		  dump ("b", b);
+		  dump ("r   ", r);
+		  dump ("rref", rr);
+		  abort ();
+		}
+	    }
+
+	  if (j == 1 && mpz_sgn (b) > 0) /* floor, positive divisor */
+	    {
+	      mpz_mod (r, a, b);
+	      if (mpz_cmp (r, rr))
+		{
+		  fprintf (stderr, "mpz_mod failed:\n");
+		  dump ("a", a);
+		  dump ("b", b);
+		  dump ("r   ", r);
+		  dump ("rref", rr);
+		  abort ();
+		}
+	    }
+
+	  if (mpz_fits_ulong_p (b))
+	    {
+	      unsigned long rl;
+
+	      mpz_set_si (r, -7);
+	      mpz_set_ui (q, ~7);
+	      rl = div_qr_ui[j] (q, r, a, mpz_get_ui (b));
+	      if (rl != mpz_get_ui (rr)
+		  || mpz_cmp (r, rr) || mpz_cmp (q, rq))
+		{
+		  fprintf (stderr, "mpz_%cdiv_qr_ui failed:\n", name[j]);
+		  dump ("a", a);
+		  dump ("b", b);
+		  fprintf(stderr, "rl   = %lx\n", rl);
+		  dump ("r   ", r);
+		  dump ("rref", rr);
+		  dump ("q   ", q);
+		  dump ("qref", rq);
+		  abort ();
+		}
+
+	      mpz_set_si (q, 3);
+	      rl = div_q_ui[j] (q, a, mpz_get_ui (b));
+	      if (rl != mpz_get_ui (rr) || mpz_cmp (q, rq))
+		{
+		  fprintf (stderr, "mpz_%cdiv_q_ui failed:\n", name[j]);
+		  dump ("a", a);
+		  dump ("b", b);
+		  fprintf(stderr, "rl   = %lx\n", rl);
+		  dump ("rref", rr);
+		  dump ("q   ", q);
+		  dump ("qref", rq);
+		  abort ();
+		}
+
+	      mpz_set_ui (r, 7);
+	      rl = div_r_ui[j] (r, a, mpz_get_ui (b));
+	      if (rl != mpz_get_ui (rr) || mpz_cmp (r, rr))
+		{
+		  fprintf (stderr, "mpz_%cdiv_r_ui failed:\n", name[j]);
+		  dump ("a", a);
+		  dump ("b", b);
+		  fprintf(stderr, "rl   = %lx\n", rl);
+		  dump ("r   ", r);
+		  dump ("rref", rr);
+		  abort ();
+		}
+
+	      rl = div_ui[j] (a, mpz_get_ui (b));
+	      if (rl != mpz_get_ui (rr))
+		{
+		  fprintf (stderr, "mpz_%cdiv_ui failed:\n", name[j]);
+		  dump ("a", a);
+		  dump ("b", b);
+		  fprintf(stderr, "rl   = %lx\n", rl);
+		  dump ("rref", rr);
+		  abort ();
+		}
+
+	      if (j == 0)	/* do this once, not for all roundings */
+		{
+		  div_p = mpz_divisible_ui_p (a, mpz_get_ui (b));
+		  if ((mpz_sgn (r) == 0) ^ (div_p != 0))
+		    {
+		      fprintf (stderr, "mpz_divisible_ui_p failed:\n");
+		      dump ("a", a);
+		      dump ("b", b);
+		      dump ("r   ", r);
+		      abort ();
+		    }
+		}
+
+	      if (j == 1)	/* floor */
+		{
+		  mpz_set_si (r, -2);
+		  mpz_mod_ui (r, a, mpz_get_ui (b));
+		  if (mpz_cmp (r, rr))
+		    {
+		      fprintf (stderr, "mpz_mod failed:\n");
+		      dump ("a", a);
+		      dump ("b", b);
+		      dump ("r   ", r);
+		      dump ("rref", rr);
+		      abort ();
+		    }
+		}
+	    }
+	}
+    }
+  mpz_clear (a);
+  mpz_clear (b);
+  mpz_clear (r);
+  mpz_clear (q);
+  mpz_clear (rr);
+  mpz_clear (rq);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-div_2exp.c b/third_party/gmp/mini-gmp/tests/t-div_2exp.c
new file mode 100644
index 0000000..53d3f2b
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-div_2exp.c
@@ -0,0 +1,82 @@
+/*
+
+Copyright 2012, Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "testutils.h"
+
+#define MAXBITS 400
+#define COUNT 10000
+
+typedef void div_func (mpz_t, const mpz_t, mp_bitcnt_t);
+
+void
+testmain (int argc, char **argv)
+{
+  unsigned i;
+  mpz_t a, res, ref;
+  mp_bitcnt_t b;
+
+  mpz_init (a);
+  mpz_init (res);
+  mpz_init (ref);
+
+  for (i = 0; i < COUNT; i++)
+    {
+      unsigned j;
+      for (j = 0; j < 6; j++)
+	{
+	  static const enum hex_random_op ops[6] =
+	    {
+	      OP_CDIV_Q_2, OP_CDIV_R_2,
+	      OP_FDIV_Q_2, OP_FDIV_R_2,
+	      OP_TDIV_Q_2, OP_TDIV_R_2
+	    };
+	  static const char *name[6] =
+	    {
+	      "cdiv_q", "cdiv_r",
+	      "fdiv_q", "fdiv_r",
+	      "tdiv_q", "tdiv_r"
+	    };
+	  static div_func * const div [6] =
+	    {
+	      mpz_cdiv_q_2exp, mpz_cdiv_r_2exp,
+	      mpz_fdiv_q_2exp, mpz_fdiv_r_2exp,
+	      mpz_tdiv_q_2exp, mpz_tdiv_r_2exp
+	    };
+
+	  mini_random_bit_op (ops[j], MAXBITS, a, &b, ref);
+	  div[j] (res, a, b);
+	  if (mpz_cmp (ref, res))
+	    {
+	      fprintf (stderr, "mpz_%s_2exp failed:\n", name[j]);
+	      dump ("a", a);
+	      fprintf (stderr, "b: %lu\n", b);
+	      dump ("r", res);
+	      dump ("ref", ref);
+	      abort ();
+	    }
+	}
+    }
+  mpz_clear (a);
+  mpz_clear (res);
+  mpz_clear (ref);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-double.c b/third_party/gmp/mini-gmp/tests/t-double.c
new file mode 100644
index 0000000..9a1aa8f
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-double.c
@@ -0,0 +1,228 @@
+/*
+
+Copyright 2012, 2013, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <limits.h>
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <float.h>
+
+#include "testutils.h"
+
+#define GMP_LIMB_BITS (sizeof(mp_limb_t) * CHAR_BIT)
+
+mp_bitcnt_t
+mpz_mantissasizeinbits (const mpz_t z)
+{
+  return ! mpz_cmp_ui (z, 0) ? 0 :
+    mpz_sizeinbase (z, 2) - mpz_scan1 (z, 0);
+}
+
+#if defined(DBL_MANT_DIG) && FLT_RADIX == 2
+int
+mpz_get_d_exact_p (const mpz_t z)
+{
+  return mpz_mantissasizeinbits (z) <= DBL_MANT_DIG;
+}
+#define HAVE_EXACT_P 1
+#endif
+
+#define COUNT 10000
+
+void
+test_matissa (void)
+{
+  mpz_t x, y;
+  int i, c;
+
+  mpz_init (x);
+  mpz_init (y);
+
+  mini_urandomb (y, 4);
+  c = i = mpz_get_ui (y);
+
+  do {
+    double d;
+    int cmp;
+
+    mpz_setbit (x, c);
+    d = mpz_get_d (x);
+    mpz_set_d (y, d);
+    if (mpz_cmp_d (y, d) != 0)
+      {
+	fprintf (stderr, "mpz_cmp_d (y, d) failed:\n"
+		 "d = %.20g\n"
+		 "i = %i\n"
+		 "c = %i\n",
+		 d, i, c);
+	abort ();
+      }
+
+    cmp = mpz_cmp (x, y);
+
+#if defined(HAVE_EXACT_P)
+    if ((mpz_get_d_exact_p (x) != 0) != (cmp == 0))
+      {
+	fprintf (stderr, "Not all bits converted:\n"
+		 "d = %.20g\n"
+		 "i = %i\n"
+		 "c = %i\n",
+		 d, i, c);
+	abort ();
+      }
+#endif
+
+    if (cmp < 0)
+      {
+	fprintf (stderr, "mpz_get_d failed:\n"
+		 "d = %.20g\n"
+		 "i = %i\n"
+		 "c = %i\n",
+		 d, i, c);
+	abort ();
+      }
+    else if (cmp > 0)
+      {
+	if (mpz_cmp_d (x, d) <= 0)
+	  {
+	    fprintf (stderr, "mpz_cmp_d (x, d) failed:\n"
+		     "d = %.20g\n"
+		     "i = %i\n"
+		     "c = %i\n",
+		     d, i, c);
+	    abort ();
+	  }
+	break;
+      }
+    ++c;
+  } while (1);
+
+  mpz_clear (x);
+  mpz_clear (y);
+}
+
+static const struct
+{
+  double d;
+  const char *s;
+} values[] = {
+  { 0.0, "0" },
+  { 0.3, "0" },
+  { -0.3, "0" },
+  { M_PI, "3" },
+  { M_PI*1e15, "b29430a256d21" },
+  { -M_PI*1e15, "-b29430a256d21" },
+  /* 17 * 2^{200} =
+     27317946752402834684213355569799764242877450894307478200123392 */
+  {0.2731794675240283468421335556979976424288e62,
+    "1100000000000000000000000000000000000000000000000000" },
+  { 0.0, NULL }
+};
+
+void
+testmain (int argc, char **argv)
+{
+  unsigned i;
+  mpz_t x;
+
+  for (i = 0; values[i].s; i++)
+    {
+      char *s;
+      mpz_init_set_d (x, values[i].d);
+      s = mpz_get_str (NULL, 16, x);
+      if (strcmp (s, values[i].s) != 0)
+	{
+	  fprintf (stderr, "mpz_set_d failed:\n"
+		   "d = %.20g\n"
+		   "s = %s\n"
+		   "r = %s\n",
+		   values[i].d, s, values[i].s);
+	  abort ();
+	}
+      testfree (s);
+      mpz_clear (x);
+    }
+
+  mpz_init (x);
+
+  for (i = 0; i < COUNT; i++)
+    {
+      /* Use volatile, to avoid extended precision in floating point
+	 registers, e.g., on m68k and 80387. */
+      volatile double d, f;
+      unsigned long m;
+      int e;
+
+      mini_rrandomb (x, GMP_LIMB_BITS);
+      m = mpz_get_ui (x);
+      mini_urandomb (x, 8);
+      e = mpz_get_ui (x) - 100;
+
+      d = ldexp ((double) m, e);
+      mpz_set_d (x, d);
+      f = mpz_get_d (x);
+      if (f != floor (d))
+	{
+	  fprintf (stderr, "mpz_set_d/mpz_get_d failed:\n");
+	  goto dumperror;
+	}
+      if ((f == d) ? (mpz_cmp_d (x, d) != 0) : (mpz_cmp_d (x, d) >= 0))
+	{
+	  fprintf (stderr, "mpz_cmp_d (x, d) failed:\n");
+	  goto dumperror;
+	}
+      f = d + 1.0;
+      if (f > d && ! (mpz_cmp_d (x, f) < 0))
+	{
+	  fprintf (stderr, "mpz_cmp_d (x, f) failed:\n");
+	  goto dumperror;
+	}
+
+      d = - d;
+
+      mpz_set_d (x, d);
+      f = mpz_get_d (x);
+      if (f != ceil (d))
+	{
+	  fprintf (stderr, "mpz_set_d/mpz_get_d failed:\n");
+	dumperror:
+	  dump ("x", x);
+	  fprintf (stderr, "m = %lx, e = %i\n", m, e);
+	  fprintf (stderr, "d = %.15g\n", d);
+	  fprintf (stderr, "f = %.15g\n", f);
+	  fprintf (stderr, "f - d = %.5g\n", f - d);
+	  abort ();
+	}
+      if ((f == d) ? (mpz_cmp_d (x, d) != 0) : (mpz_cmp_d (x, d) <= 0))
+	{
+	  fprintf (stderr, "mpz_cmp_d (x, d) failed:\n");
+	  goto dumperror;
+	}
+      f = d - 1.0;
+      if (f < d && ! (mpz_cmp_d (x, f) > 0))
+	{
+	  fprintf (stderr, "mpz_cmp_d (x, f) failed:\n");
+	  goto dumperror;
+	}
+    }
+
+  mpz_clear (x);
+  test_matissa();
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-gcd.c b/third_party/gmp/mini-gmp/tests/t-gcd.c
new file mode 100644
index 0000000..64f90f4
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-gcd.c
@@ -0,0 +1,178 @@
+/*
+
+Copyright 2012, Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "testutils.h"
+
+#define MAXBITS 400
+#define COUNT 10000
+
+/* Called when g is supposed to be gcd(a,b), and g = s a + t b. */
+static int
+gcdext_valid_p (const mpz_t a, const mpz_t b,
+		const mpz_t g, const mpz_t s, const mpz_t t)
+{
+  mpz_t ta, tb, r;
+
+  /* It's not clear that gcd(0,0) is well defined, but we allow it and
+     require that gcd(0,0) = 0. */
+  if (mpz_sgn (g) < 0)
+    return 0;
+
+  if (mpz_sgn (a) == 0)
+    {
+      /* Must have g == abs (b). Any value for s is in some sense "correct",
+	 but it makes sense to require that s == 0, t = sgn (b)*/
+      return mpz_cmpabs (g, b) == 0
+	&& mpz_sgn (s) == 0 && mpz_cmp_si (t, mpz_sgn (b)) == 0;
+    }
+  else if (mpz_sgn (b) == 0)
+    {
+      /* Must have g == abs (a), s == sign (a), t = 0 */
+      return mpz_cmpabs (g, a) == 0
+	&& mpz_cmp_si (s, mpz_sgn (a)) == 0 && mpz_sgn (t) == 0;
+    }
+
+  if (mpz_sgn (g) <= 0)
+    return 0;
+
+  mpz_init (ta);
+  mpz_init (tb);
+  mpz_init (r);
+
+  mpz_mul (ta, s, a);
+  mpz_mul (tb, t, b);
+  mpz_add (ta, ta, tb);
+
+  if (mpz_cmp (ta, g) != 0)
+    {
+    fail:
+      mpz_clear (ta);
+      mpz_clear (tb);
+      mpz_clear (r);
+      return 0;
+    }
+  mpz_tdiv_qr (ta, r, a, g);
+  if (mpz_sgn (r) != 0)
+    goto fail;
+
+  mpz_tdiv_qr (tb, r, b, g);
+  if (mpz_sgn (r) != 0)
+    goto fail;
+
+  /* Require that 2 |s| < |b/g|, or |s| == 1. */
+  if (mpz_cmpabs_ui (s, 1) > 0)
+    {
+      mpz_mul_2exp (r, s, 1);
+      if (mpz_cmpabs (r, tb) > 0)
+	goto fail;
+    }
+
+  /* Require that 2 |t| < |a/g| or |t| == 1*/
+  if (mpz_cmpabs_ui (t, 1) > 0)
+    {
+      mpz_mul_2exp (r, t, 1);
+      if (mpz_cmpabs (r, ta) > 0)
+	return 0;
+    }
+
+  mpz_clear (ta);
+  mpz_clear (tb);
+  mpz_clear (r);
+
+  return 1;
+}
+
+void
+testmain (int argc, char **argv)
+{
+  unsigned i;
+  mpz_t a, b, g, s, t;
+
+  mpz_init (a);
+  mpz_init (b);
+  mpz_init (g);
+  mpz_init (s);
+  mpz_init (t);
+
+  for (i = 0; i < COUNT; i++)
+    {
+      mini_random_op3 (OP_GCD, MAXBITS, a, b, s);
+      mpz_gcd (g, a, b);
+      if (mpz_cmp (g, s))
+	{
+	  fprintf (stderr, "mpz_gcd failed:\n");
+	  dump ("a", a);
+	  dump ("b", b);
+	  dump ("r", g);
+	  dump ("ref", s);
+	  abort ();
+	}
+    }
+
+  for (i = 0; i < COUNT; i++)
+    {
+      unsigned flags;
+      mini_urandomb (a, 32);
+      flags = mpz_get_ui (a);
+      mini_rrandomb (a, MAXBITS);
+      mini_rrandomb (b, MAXBITS);
+
+      if (flags % 37 == 0)
+	mpz_mul (a, a, b);
+      if (flags % 37 == 1)
+	mpz_mul (b, a, b);
+
+      if (flags & 1)
+	mpz_neg (a, a);
+      if (flags & 2)
+	mpz_neg (b, b);
+
+      mpz_gcdext (g, s, t, a, b);
+      if (!gcdext_valid_p (a, b, g, s, t))
+	{
+	  fprintf (stderr, "mpz_gcdext failed:\n");
+	  dump ("a", a);
+	  dump ("b", b);
+	  dump ("g", g);
+	  dump ("s", s);
+	  dump ("t", t);
+	  abort ();
+	}
+
+      mpz_gcd (s, a, b);
+      if (mpz_cmp (g, s))
+	{
+	  fprintf (stderr, "mpz_gcd failed:\n");
+	  dump ("a", a);
+	  dump ("b", b);
+	  dump ("r", g);
+	  dump ("ref", s);
+	  abort ();
+	}
+    }
+  mpz_clear (a);
+  mpz_clear (b);
+  mpz_clear (g);
+  mpz_clear (s);
+  mpz_clear (t);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-import.c b/third_party/gmp/mini-gmp/tests/t-import.c
new file mode 100644
index 0000000..66c9d5e
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-import.c
@@ -0,0 +1,99 @@
+/*
+
+Copyright 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "testutils.h"
+
+#define MAX_WORDS 20
+#define MAX_WORD_SIZE 10
+
+static void
+dump_bytes (const char *label, const unsigned char *s, size_t n)
+{
+  size_t i;
+  fprintf (stderr, "%s:", label);
+  for (i = 0; i < n; i++)
+    {
+      if (i && (i % 16) == 0)
+	fprintf (stderr, "\n");
+      fprintf (stderr, " %02x", s[i]);
+    }
+  fprintf (stderr, "\n");
+}
+
+/* Tests both mpz_import and mpz_export. */
+void
+testmain (int argc, char **argv)
+{
+  unsigned char input[MAX_WORDS * MAX_WORD_SIZE];
+  unsigned char output[MAX_WORDS * MAX_WORD_SIZE + 2];
+  size_t count, in_count, out_count, size;
+  int endian, order;
+
+  mpz_t a, res;
+
+  mpz_init (a);
+  mpz_init (res);
+
+  for (size = 0; size <= MAX_WORD_SIZE; size++)
+    for (count = 0; count <= MAX_WORDS; count++)
+      for (endian = -1; endian <= 1; endian++)
+	for (order = -1; order <= 1; order += 2)
+	  {
+	    mini_rrandomb_export (a, input, &in_count,
+				  order, size, endian, size*count * 8);
+	    mpz_import (res, in_count, order, size, endian, 0, input);
+	    if (mpz_cmp (a, res))
+	      {
+		fprintf (stderr, "mpz_import failed:\n"
+			 "in_count %lu, out_count %lu, endian = %d, order = %d\n",
+			 (unsigned long) in_count, (unsigned long) out_count, endian, order);
+		dump ("a", a);
+		dump ("res", res);
+		abort ();
+	      }
+	    output[0] = 17;
+	    output[1+in_count*size] = 17;
+
+	    mpz_export (output+1, &out_count, order, size, endian, 0, a);
+	    if (out_count != in_count
+		|| memcmp (output+1, input, in_count * size)
+		|| output[0] != 17
+		|| output[1+in_count*size] != 17)
+	      {
+		fprintf (stderr, "mpz_export failed:\n"
+			 "in_count %lu, out_count %lu, endian = %d, order = %d\n",
+			 (unsigned long) in_count, (unsigned long) out_count, endian, order);
+		dump_bytes ("input", input, in_count * size);
+		dump_bytes ("output", output+1, out_count * size);
+		if (output[0] != 17)
+		  fprintf (stderr, "Overwrite at -1, value %02x\n", output[0]);
+		if (output[1+in_count*size] != 17)
+		  fprintf (stderr, "Overwrite at %lu, value %02x\n",
+			   (unsigned long) (in_count*size), output[1+in_count*size]);
+
+		abort ();
+	      }
+	  }
+  mpz_clear (a);
+  mpz_clear (res);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-invert.c b/third_party/gmp/mini-gmp/tests/t-invert.c
new file mode 100644
index 0000000..843002b
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-invert.c
@@ -0,0 +1,139 @@
+/*
+
+Copyright 2012, 2016 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <assert.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "testutils.h"
+
+#define GMP_LIMB_BITS (sizeof(mp_limb_t) * CHAR_BIT)
+
+#define COUNT 10000
+
+static void
+test_2by1(const mpz_t u)
+{
+  mpz_t m, p, t;
+
+  mpz_init (m);
+  mpz_init (p);
+  mpz_init (t);
+
+  assert (mpz_size (u) == 1);
+
+  mpz_set_ui (m, mpn_invert_limb (u->_mp_d[0]));
+  mpz_setbit (m, GMP_LIMB_BITS);
+
+  mpz_mul (p, m, u);
+
+  mpz_set_ui (t, 0);
+  mpz_setbit (t, 2* GMP_LIMB_BITS);
+  mpz_sub (t, t, p);
+
+  /* Should have 0 < B^2 - m u <= u */
+  if (mpz_sgn (t) <= 0 || mpz_cmp (t, u) > 0)
+    {
+      fprintf (stderr, "mpn_invert_limb failed:\n");
+      dump ("u", u);
+      dump ("m", m);
+      dump ("p", p);
+      dump ("t", t);
+      abort ();
+    }
+  mpz_clear (m);
+  mpz_clear (p);
+  mpz_clear (t);
+}
+
+static void
+test_3by2(const mpz_t u)
+{
+  mpz_t m, p, t;
+
+  mpz_init (m);
+  mpz_init (p);
+  mpz_init (t);
+
+  assert (mpz_size (u) == 2);
+
+  mpz_set_ui (m, mpn_invert_3by2 (u->_mp_d[1], u[0]._mp_d[0]));
+
+  mpz_setbit (m, GMP_LIMB_BITS);
+
+  mpz_mul (p, m, u);
+
+  mpz_set_ui (t, 0);
+  mpz_setbit (t, 3 * GMP_LIMB_BITS);
+  mpz_sub (t, t, p);
+
+  /* Should have 0 < B^3 - m u <= u */
+  if (mpz_sgn (t) <= 0 || mpz_cmp (t, u) > 0)
+    {
+      fprintf (stderr, "mpn_invert_3by2 failed:\n");
+      dump ("u", u);
+      dump ("m", m);
+      dump ("p", p);
+      dump ("t", t);
+      abort ();
+    }
+  mpz_clear (m);
+  mpz_clear (p);
+  mpz_clear (t);
+}
+
+void
+testmain (int argc, char **argv)
+{
+  unsigned i;
+  mpz_t u, m, p, t;
+
+  mpz_init (u);
+  mpz_init (m);
+  mpz_init (p);
+  mpz_init (t);
+
+  /* These values trigger 32-bit overflow of ql in mpn_invert_3by2. */
+  if (GMP_LIMB_BITS == 64)
+    {
+      mpz_set_str (u, "80007fff3ffe0000", 16);
+      test_2by1 (u);
+      mpz_set_str (u, "80007fff3ffe000000000000000003ff", 16);
+      test_3by2 (u);
+    }
+
+  for (i = 0; i < COUNT; i++)
+    {
+      mini_urandomb (u, GMP_LIMB_BITS);
+      mpz_setbit (u, GMP_LIMB_BITS -1);
+
+      test_2by1 (u);
+    }
+
+  for (i = 0; i < COUNT; i++)
+    {
+      mini_urandomb (u, 2*GMP_LIMB_BITS);
+      mpz_setbit (u, 2*GMP_LIMB_BITS -1);
+
+      test_3by2 (u);
+    }
+
+  mpz_clear (u);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-lcm.c b/third_party/gmp/mini-gmp/tests/t-lcm.c
new file mode 100644
index 0000000..f21a39a
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-lcm.c
@@ -0,0 +1,73 @@
+/*
+
+Copyright 2012, Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "testutils.h"
+
+#define MAXBITS 400
+#define COUNT 10000
+
+void
+testmain (int argc, char **argv)
+{
+  unsigned i;
+  mpz_t a, b, g, s;
+
+  mpz_init (a);
+  mpz_init (b);
+  mpz_init (g);
+  mpz_init (s);
+
+  for (i = 0; i < COUNT; i++)
+    {
+      mini_random_op3 (OP_LCM, MAXBITS, a, b, s);
+      mpz_lcm (g, a, b);
+      if (mpz_cmp (g, s))
+	{
+	  fprintf (stderr, "mpz_lcm failed:\n");
+	  dump ("a", a);
+	  dump ("b", b);
+	  dump ("r", g);
+	  dump ("ref", s);
+	  abort ();
+	}
+      if (mpz_fits_ulong_p (b))
+	{
+	  mpz_set_si (g, 0);
+	  mpz_lcm_ui (g, a, mpz_get_ui (b));
+	  if (mpz_cmp (g, s))
+	    {
+	      fprintf (stderr, "mpz_lcm_ui failed:\n");
+	      dump ("a", a);
+	      dump ("b", b);
+	      dump ("r", g);
+	      dump ("ref", s);
+	      abort ();
+	    }
+	}
+    }
+
+  mpz_clear (a);
+  mpz_clear (b);
+  mpz_clear (g);
+  mpz_clear (s);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-limbs.c b/third_party/gmp/mini-gmp/tests/t-limbs.c
new file mode 100644
index 0000000..f4e57dd
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-limbs.c
@@ -0,0 +1,111 @@
+/*
+
+Copyright 2012, 2014, 2016, Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <assert.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "testutils.h"
+
+#define MAXBITS 400
+#define COUNT 100
+
+void
+my_mpz_mul (mpz_t r, mpz_srcptr a,  mpz_srcptr b)
+{
+  mp_limb_t *tp;
+  mp_size_t tn, an, bn;
+
+  an = mpz_size (a);
+  bn = mpz_size (b);
+
+  assert (an > 0);
+  assert (bn > 0);
+
+  tn = an + bn;
+  tp = mpz_limbs_write (r, tn);
+  if (an > bn)
+    mpn_mul (tp, mpz_limbs_read (a), an, mpz_limbs_read (b), bn);
+  else
+    mpn_mul (tp, mpz_limbs_read (b), bn, mpz_limbs_read (a), an);
+
+  if (mpz_sgn (a) != mpz_sgn(b))
+    tn = - tn;
+
+  mpz_limbs_finish (r, tn);
+}
+
+void
+testmain (int argc, char **argv)
+{
+  unsigned i;
+  mpz_t a, b, res, ref;
+
+  mpz_init (a);
+  mpz_init (b);
+  mpz_init (res);
+  mpz_init (ref);
+
+  for (i = 0; i < COUNT; i++)
+    {
+      mini_random_op3 (OP_MUL, MAXBITS, a, b, ref);
+      if (mpz_sgn(ref) == 0)
+	/* my_mpz_mul requires a != 0, b != 0 */
+	continue;
+      my_mpz_mul (res, a, b);
+      if (mpz_cmp (res, ref))
+	{
+	  fprintf (stderr, "my_mpz_mul failed:\n");
+	  dump ("a", a);
+	  dump ("b", b);
+	  dump ("r", res);
+	  dump ("ref", ref);
+	  abort ();
+	}
+      /* The following test exploits a side-effect of my_mpz_mul: res
+	 points to a buffer with at least an+bn limbs, and the limbs
+	 above the result are zeroed. */
+      if (mpz_size (b) > 0 && mpz_getlimbn (res, mpz_size(a)) != mpz_limbs_read (res) [mpz_size(a)])
+	{
+	  fprintf (stderr, "getlimbn - limbs_read differ.\n");
+	  abort ();
+	}
+      if ((i % 4 == 0) && mpz_size (res) > 1)
+	{
+	  mpz_realloc2 (res, 1);
+	  if (mpz_cmp_ui (res, 0))
+	    {
+	      fprintf (stderr, "mpz_realloc2 did not clear res.\n");
+	      abort ();
+	    }
+	  mpz_limbs_finish (ref, 0);
+	  if (mpz_cmp_d (ref, 0))
+	    {
+	      fprintf (stderr, "mpz_limbs_finish did not clear res.\n");
+	      abort ();
+	    }
+	}
+    }
+  mpz_clear (a);
+  mpz_clear (b);
+  mpz_clear (res);
+  mpz_clear (ref);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-logops.c b/third_party/gmp/mini-gmp/tests/t-logops.c
new file mode 100644
index 0000000..b4e0239
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-logops.c
@@ -0,0 +1,112 @@
+/*
+
+Copyright 2012, 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "testutils.h"
+
+#define MAXBITS 400
+#define COUNT 10000
+
+void
+testlogops (int count)
+{
+  int i;
+  mpz_t a, b, res, ref;
+  mp_bitcnt_t c;
+
+  mpz_init (a);
+  mpz_init (b);
+  mpz_init (res);
+  mpz_init (ref);
+
+  for (i = 0; i < count; i++)
+    {
+      mini_random_op3 (OP_AND, MAXBITS, a, b, ref);
+      mpz_and (res, a, b);
+      if (mpz_cmp (res, ref))
+	{
+	  fprintf (stderr, "mpz_and failed:\n");
+	  dump ("a", a);
+	  dump ("b", b);
+	  dump ("r", res);
+	  dump ("ref", ref);
+	  abort ();
+	}
+
+      mini_random_op3 (OP_IOR, MAXBITS, a, b, ref);
+      mpz_ior (res, a, b);
+      if (mpz_cmp (res, ref))
+	{
+	  fprintf (stderr, "mpz_ior failed:\n");
+	  dump ("a", a);
+	  dump ("b", b);
+	  dump ("r", res);
+	  dump ("ref", ref);
+	  abort ();
+	}
+
+      mini_random_op3 (OP_XOR, MAXBITS, a, b, ref);
+      mpz_xor (res, a, b);
+      if (mpz_cmp (res, ref))
+	{
+	  fprintf (stderr, "mpz_xor failed:\n");
+	  dump ("a", a);
+	  dump ("b", b);
+	  dump ("r", res);
+	  dump ("ref", ref);
+	  abort ();
+	}
+
+      if (i % 8) {
+	c = 0;
+	mpz_mul_2exp (res, res, i % 8);
+      } else if (mpz_sgn (res) >= 0) {
+	c = mpz_odd_p (res) != 0;
+	mpz_tdiv_q_2exp (res, res, 1);
+      } else {
+	c = (~ (mp_bitcnt_t) 0) - 3;
+	mpz_set_ui (res, 11 << ((i >> 3)%4)); /* set 3 bits */
+      }
+
+      if (mpz_popcount (res) + c != mpz_hamdist (a, b))
+	{
+	  fprintf (stderr, "mpz_popcount(r) + %lu and mpz_hamdist(a,b) differ:\n", c);
+	  dump ("a", a);
+	  dump ("b", b);
+	  dump ("r", res);
+	  fprintf (stderr, "mpz_popcount(r) = %lu:\n", mpz_popcount (res));
+	  fprintf (stderr, "mpz_hamdist(a,b) = %lu:\n", mpz_hamdist (a, b));
+	  abort ();
+	}
+    }
+  mpz_clear (a);
+  mpz_clear (b);
+  mpz_clear (res);
+  mpz_clear (ref);
+}
+
+void
+testmain (int argc, char **argv)
+{
+  testhalves (COUNT*2/3, testlogops);
+  testlogops (COUNT/3);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-lucm.c b/third_party/gmp/mini-gmp/tests/t-lucm.c
new file mode 100644
index 0000000..22ad575
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-lucm.c
@@ -0,0 +1,98 @@
+/* Tests the (internal) function mpz_lucas_mod
+
+Copyright 2018, Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "testutils.h"
+
+#define MAXBITS 100
+#define COUNT 1000
+
+void
+testmain (int argc, char **argv)
+{
+  unsigned i;
+  mpz_t m, vr, qr, vm, qm, vt;
+  int resm, resr;
+  long Q;
+  unsigned long b0;
+
+  mpz_init (m);
+  mpz_init (vr);
+  mpz_init (qr);
+  mpz_init (vm);
+  mpz_init (qm);
+  mpz_init (vt);
+
+  for (i = 0; i < COUNT; i++)
+    {
+      mini_random_lucm_op (MAXBITS, vr, qr, m, &Q, &b0, &resr);
+      if (b0 == 0)
+	{
+	  fprintf (stderr, "lucas_mod: test disabled (%u tests done).\n", i);
+	  break;
+	}
+      resm = mpz_lucas_mod (vm, qm, Q, b0, m);
+
+      if (resr != resm)
+	{
+	  if (resm != 0 || mpz_cmp_ui (vm, 0) != 0)
+	    {
+	      fprintf (stderr, "mpz_lucas_mod wrong return value (%d != %d):\n", resr, resm);
+	      fprintf (stderr, "Q = %ld , b0 = %lu\n", Q, b0);
+	      dump ("m", m);
+	      dump ("vm", vm);
+	      dump ("qm", qm);
+	      abort ();
+	    }
+	}
+      else if (resm == 0)
+	{
+	  mpz_abs (vr, vr);
+	  mpz_sub (vt, m, vr);
+	  mpz_abs (vm, vm);
+	  mpz_mod (qm, qm, m);
+	  if (mpz_cmp_ui (qr, 0) < 0)
+	    mpz_add (qr, qr, m);
+	  if (mpz_cmp (qm, qr) != 0 ||
+	      (mpz_cmp (vm, vr) != 0 && mpz_cmp (vm, vt) != 0))
+	    {
+	      fprintf (stderr, "mpz_lucas_mod error:\n");
+	      fprintf (stderr, "Q = %ld , b0 = %lu\n", Q, b0);
+	      dump ("m", m);
+	      dump ("vm", vm);
+	      dump ("vr", vr);
+	      dump ("vt", vt);
+	      dump ("qm", qm);
+	      dump ("qr", qr);
+	      abort ();
+	    }
+
+	}
+    }
+  mpz_clear (m);
+  mpz_clear (vr);
+  mpz_clear (qr);
+  mpz_clear (vm);
+  mpz_clear (qm);
+  mpz_clear (vt);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-mpq_addsub.c b/third_party/gmp/mini-gmp/tests/t-mpq_addsub.c
new file mode 100644
index 0000000..de1461f
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-mpq_addsub.c
@@ -0,0 +1,204 @@
+/*
+
+Copyright 2012, 2013, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "testutils.h"
+#include "../mini-mpq.h"
+
+#define MAXBITS 300
+#define COUNT 10000
+
+static void
+_mpq_set_zz (mpq_t q, mpz_t n, mpz_t d)
+{
+  if (mpz_fits_ulong_p (d) && mpz_fits_slong_p (n))
+    {
+      mpq_set_si (q, mpz_get_si (n), mpz_get_ui (d));
+    }
+  else if (mpz_fits_ulong_p (d) && mpz_fits_ulong_p (n))
+    {
+      mpq_set_ui (q, mpz_get_ui (n), mpz_get_ui (d));
+    }
+  else
+    {
+      mpq_set_num (q, n);
+      mpq_set_den (q, d);
+    }
+  mpq_canonicalize (q);
+}
+
+void
+testcmpui ()
+{
+  unsigned d1, d2, n1, n2;
+  mpq_t q1, q2;
+
+  mpq_init (q1);
+  mpq_init (q2);
+
+  for (d1 = 1; d1 < 6; d1 += 2)
+    for (n1 = 1; n1 < 6; n1 *= 2)
+      {
+	mpq_set_ui (q1, n1, d1);
+	for (d2 = 1; d2 < 6; d2 += 2)
+	  for (n2 = 1; n2 < 6; n2 *= 2)
+	    {
+	      int fres = mpq_cmp_ui (q1, n2, d2);
+	      int ref = (d1*n2 < d2*n1) - (d1*n2 > d2*n1);
+
+	      mpq_set_ui (q2, n2, d2);
+
+	      if ((!ref) != mpq_equal (q1, q2))
+		{
+		  fprintf (stderr, "mpz_equal failed: %i / %i = %i / %i ? %i\n", n1, d1, n2, d2, ref);
+		  abort ();
+		}
+
+	      if (ref != fres)
+		{
+		  fprintf (stderr, "mpz_cmp_ui failed: %i / %i = %i / %i ? %i != %i\n", n1, d1, n2, d2, ref, fres);
+		  abort ();
+		}
+	    }
+      }
+
+  mpq_clear (q1);
+  mpq_clear (q2);
+}
+
+void
+testmain (int argc, char **argv)
+{
+  unsigned i;
+  mpz_t a, b, q, r, c;
+  mpq_t rr, ii, ff;
+  int tst;
+
+  testcmpui ();
+  mpz_init (a);
+  mpz_init (b);
+  mpz_init (r);
+  mpz_init (q);
+  mpz_init (c);
+  mpq_init (rr);
+  mpq_init (ff);
+  mpq_init (ii);
+
+  for (i = 0; i < COUNT; i++)
+    {
+      mini_random_op4 (OP_TDIV, MAXBITS, a, b, q, r);
+
+      _mpq_set_zz (rr, a, b);
+      _mpq_set_zz (ff, r, b);
+
+      mpq_set_z (ii, q);
+
+      mpz_set_q (c, rr);
+      if (mpz_cmp (c, q))
+	{
+	  fprintf (stderr, "mpz_set_q failed:\n");
+	  dump ("a", a);
+	  dump ("b", b);
+	  dump ("c", c);
+	  dump ("q", q);
+	  abort ();
+	}
+
+      if ((mpz_sgn (r) != 0) ^ (mpz_cmp_ui (mpq_denref (rr), 1) != 0))
+	{
+	  fprintf (stderr, "mpq_canonicalize failed:\n");
+	  dump ("a", a);
+	  dump ("b", b);
+	  dump ("r", r);
+	  dump ("D", mpq_denref (rr));
+	  abort ();
+	}
+
+      if (i & 1)
+	{
+	  if (mpz_fits_slong_p (q))
+	    tst = mpq_cmp_si (rr, mpz_get_si (q), 1);
+	  else if (mpz_fits_ulong_p (q))
+	    tst = mpq_cmp_ui (rr, mpz_get_ui (q), 1);
+	  else
+	    tst = mpq_cmp_z (rr, q);
+	  if (mpz_sgn (b) < 0)
+	    tst = - tst;
+	  if ((tst != mpz_sgn (r)) && ((tst < 0 && mpz_sgn (r) >= 0) || (tst > 0 && mpz_sgn (r) <= 0)))
+	    {
+	      fprintf (stderr, "mpq_cmp ii failed: %i %i\n", tst, mpz_sgn (r));
+	      dump ("a", a);
+	      dump ("b", b);
+	      dump ("r", r);
+	      dump ("q", q);
+	      abort ();
+	    }
+	}
+      else
+	{
+	  if (mpz_fits_ulong_p (b) && mpz_fits_slong_p (r))
+	    tst = mpq_cmp_si (rr, mpz_get_si (r), mpz_get_ui (b));
+	  else if (mpz_fits_ulong_p (b) && mpz_fits_ulong_p (r))
+	    tst = mpq_cmp_ui (rr, mpz_get_ui (r), mpz_get_ui (b));
+	  else
+	    tst = mpq_cmp (rr, ff);
+	  if ((tst != mpz_sgn (q)) && ((tst < 0 && mpz_sgn (q) >= 0) || (tst > 0 && mpz_sgn (q) <= 0)))
+	    {
+	      fprintf (stderr, "mpq_cmp ff failed: %i %i\n", tst, mpz_sgn (q));
+	      dump ("a", a);
+	      dump ("b", b);
+	      dump ("r", r);
+	      dump ("q", q);
+	      abort ();
+	    }
+	}
+
+      if (i & 1)
+	{
+	  mpq_sub (rr, rr, ff);
+	}
+      else
+	{
+	  mpq_neg (ff, ff);
+	  mpq_add (rr, ff, rr);
+	}
+
+      if (!mpq_equal (ii, rr))
+	{
+	  fprintf (stderr, "mpq_%s failed:\n", (i & 1) ? "sub" : "add");
+	  dump ("a", a);
+	  dump ("b", b);
+	  dump ("r", r);
+	  dump ("q", q);
+	  abort ();
+	}
+    }
+
+  mpz_clear (a);
+  mpz_clear (b);
+  mpz_clear (r);
+  mpz_clear (q);
+  mpz_clear (c);
+  mpq_clear (rr);
+  mpq_clear (ff);
+  mpq_clear (ii);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-mpq_double.c b/third_party/gmp/mini-gmp/tests/t-mpq_double.c
new file mode 100644
index 0000000..1bd6c92
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-mpq_double.c
@@ -0,0 +1,214 @@
+/* Test mpq_set_d.
+
+Copyright 2001-2003, 2005, 2013, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <math.h>
+#include <float.h>
+#include <limits.h>
+
+#include "testutils.h"
+#include "../mini-mpq.h"
+
+#define COUNT 2000
+
+mp_bitcnt_t
+mpz_mantissasizeinbits (const mpz_t z)
+{
+  return ! mpz_cmp_ui (z, 0) ? 0 :
+    mpz_sizeinbase (z, 2) - mpz_scan1 (z, 0);
+}
+
+int
+mpz_abspow2_p (const mpz_t z)
+{
+  return mpz_mantissasizeinbits (z) == 1;
+}
+
+mp_bitcnt_t
+mpq_mantissasizeinbits (const mpq_t q)
+{
+  if (! mpz_abspow2_p (mpq_denref (q)))
+    return ~ (mp_bitcnt_t) 0;
+
+  return mpz_mantissasizeinbits (mpq_numref (q));
+}
+
+#if defined(DBL_MANT_DIG) && FLT_RADIX == 2
+int
+mpz_get_d_exact_p (const mpz_t z)
+{
+  return mpz_mantissasizeinbits (z) <= DBL_MANT_DIG;
+}
+
+int
+mpq_get_d_exact_p (const mpq_t q)
+{
+  /* return mpq_mantissasizeinbits (q) <= DBL_MANT_DIG; */
+  return
+    (mpz_sizeinbase (mpq_denref (q), 2) -
+     mpz_scan1 (mpq_denref (q), 0) == 1) &&
+    (mpz_sizeinbase (mpq_numref (q), 2) -
+     mpz_scan1 (mpq_numref (q), 0) <= DBL_MANT_DIG);
+  /* mpz_sizeinbase (zero, 2) - mpz_scan1 (zero, 0) == 2 */
+}
+#define HAVE_EXACT_P 1
+#endif
+
+void
+check_random (void)
+{
+  unsigned i;
+  mpz_t x;
+  mpq_t y, z;
+
+  mpz_init (x);
+  mpq_init (y);
+  mpq_init (z);
+
+  for (i = 0; i < COUNT; i++)
+    {
+      /* Use volatile, to avoid extended precision in floating point
+	 registers, e.g., on m68k and 80387. */
+      volatile double d, f;
+      unsigned long m;
+      int e, c;
+
+      mini_rrandomb (x, CHAR_BIT * sizeof (unsigned long));
+      m = mpz_get_ui (x);
+      mini_urandomb (x, 8);
+      e = mpz_get_ui (x) - 128;
+
+      d = ldexp ((double) m, e);
+      mpq_set_d (y, d);
+      f = mpq_get_d (y);
+      if (f != d)
+	{
+	  fprintf (stderr, "mpq_set_d/mpq_get_d failed:\n");
+	  goto dumperror;
+	}
+
+      d = - d;
+      mpq_neg (y, y);
+
+      mpq_set_d (z, d);
+      f = mpq_get_d (z);
+      if (f != d || !mpq_equal (y, z))
+	{
+	  fprintf (stderr, "mpq_set_d/mpq_get_d failed:\n");
+	dumperror:
+	  dump ("ny", mpq_numref (y));
+	  dump ("dy", mpq_denref (y));
+	  fprintf (stderr, "m = %lx, e = %i\n", m, e);
+	  fprintf (stderr, "d = %.35g\n", d);
+	  fprintf (stderr, "f = %.35g\n", f);
+	  fprintf (stderr, "f - d = %.35g\n", f - d);
+	  abort ();
+	}
+
+      mini_rrandomb (x, CHAR_BIT * sizeof (unsigned long));
+      m = mpz_get_ui (x);
+      mini_urandomb (x, 8);
+      e = mpz_get_ui (x) - 128;
+
+      d = ldexp ((double) m, e);
+      mpq_set_d (y, d);
+
+      mpq_add (y, y, z);
+      mpq_set_d (z, mpq_get_d (y));
+      f = mpq_get_d (z);
+      c = mpq_cmp (y, z);
+
+#if defined(HAVE_EXACT_P)
+      if (mpq_get_d_exact_p (y) ? c != 0 : (f > 0 ? c <= 0 : c >= 0))
+#else
+      if (f > 0 ? c < 0 : c > 0)
+#endif
+	{
+	  fprintf (stderr, "mpq_get_d/mpq_set_d failed: %i %i\n", i, c);
+	  goto dumperror;
+	}
+    }
+
+  mpz_clear (x);
+  mpq_clear (y);
+  mpq_clear (z);
+}
+
+
+void
+check_data (void)
+{
+  static const struct {
+    double        y;
+    long int      n;
+    unsigned long d;
+  } data[] = {
+    {  0.0,  0, 1 },
+    {  1.0,  1, 1 },
+    { -1.0, -1, 1 },
+    { -1.5, -3, 2 },
+    {-1.25, -5, 4 },
+    {0.125,  1, 8 },
+
+    {24685,24685,1},
+    {-9876,-9876,1},
+    {463.5,  927,2},
+
+    {1234.5/8192,  2469, 16384 },
+    {-543.0/1024,  -543,  1024 },
+    {9876.5/ 512, 19753,  1024 },
+    {9753.0/ 128,  9753,   128 },
+    {-789.0/  32,  -789,    32 },
+    {4.580078125,  2345,   512 },
+  };
+
+  mpq_t    x, r;
+  unsigned i;
+  double d;
+
+  mpq_init (x);
+  mpq_init (r);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpq_set_d (x, data[i].y);
+      mpq_set_si (r, data[i].n, data[i].d);
+      mpq_canonicalize (r);
+      if (!mpq_equal (x, r))
+	{
+	  fprintf (stderr, "mpq_set_d failed: %li / %lu != %g\n", data[i].n, data[i].d, data[i].y);
+	  abort ();
+	}
+      d = mpq_get_d (r);
+      if (d != data[i].y)
+	{
+	  fprintf (stderr, "mpq_get_d failed: %li / %lu != %g\n", data[i].n, data[i].d, data[i].y);
+	  abort ();
+	}
+    }
+
+  mpq_clear (x);
+  mpq_clear (r);
+}
+
+void
+testmain (int argc, char *argv[])
+{
+  check_data ();
+  check_random ();
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-mpq_muldiv.c b/third_party/gmp/mini-gmp/tests/t-mpq_muldiv.c
new file mode 100644
index 0000000..8e7de8b
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-mpq_muldiv.c
@@ -0,0 +1,176 @@
+/*
+
+Copyright 2012, 2013, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "testutils.h"
+#include "../mini-mpq.h"
+
+#define MAXBITS 300
+#define COUNT 10000
+
+static void
+_mpq_set_zz (mpq_t q, mpz_t n, mpz_t d)
+{
+  if (mpz_fits_ulong_p (d) && mpz_fits_slong_p (n))
+    {
+      mpq_set_si (q, mpz_get_si (n), mpz_get_ui (d));
+    }
+  else if (mpz_fits_ulong_p (d) && mpz_fits_ulong_p (n))
+    {
+      mpq_set_ui (q, mpz_get_ui (n), mpz_get_ui (d));
+    }
+  else
+    {
+      mpq_set_num (q, n);
+      mpq_set_den (q, d);
+    }
+  mpq_canonicalize (q);
+}
+
+void
+testmain (int argc, char **argv)
+{
+  unsigned i;
+  mpz_t an, bn, rn, ad, bd, rd;
+  mpq_t aq, bq, refq, resq;
+
+  mpz_init (an);
+  mpz_init (bn);
+  mpz_init (rn);
+  mpz_init (ad);
+  mpz_init (bd);
+  mpz_init (rd);
+  mpq_init (aq);
+  mpq_init (bq);
+  mpq_init (refq);
+  mpq_init (resq);
+
+  for (i = 0; i < COUNT; i++)
+    {
+      mini_random_op3 (OP_MUL, MAXBITS, an, bn, rn);
+      do {
+	mini_random_op3 (OP_MUL, MAXBITS, ad, bd, rd);
+      } while (mpz_sgn (rd) == 0);
+
+      _mpq_set_zz (aq, an, ad);
+      _mpq_set_zz (bq, bn, bd);
+      _mpq_set_zz (refq, rn, rd);
+
+      mpq_mul (resq, aq, bq);
+      if (!mpq_equal (resq, refq))
+	{
+	  fprintf (stderr, "mpq_mul failed [%i]:\n", i);
+	  dump ("an", an);
+	  dump ("ad", ad);
+	  dump ("bn", bn);
+	  dump ("bd", bd);
+	  dump ("refn", rn);
+	  dump ("refd", rd);
+	  dump ("resn", mpq_numref (resq));
+	  dump ("resd", mpq_denref (resq));
+	  abort ();
+	}
+
+      if (mpq_sgn (refq) != 0)
+	{
+	  mpq_set_ui (resq, ~6, 8);
+	  mpq_inv (aq, aq);
+	  mpq_div (resq, aq, bq);
+	  mpq_inv (resq, resq);
+	  if (!mpq_equal (resq, refq))
+	    {
+	      fprintf (stderr, "mpq_div failed [%i]:\n", i);
+	      dump ("an", an);
+	      dump ("ad", ad);
+	      dump ("bn", bn);
+	      dump ("bd", bd);
+	      dump ("refn", rn);
+	      dump ("refd", rd);
+	      dump ("resn", mpq_numref (resq));
+	      dump ("resd", mpq_denref (resq));
+	      abort ();
+	    }
+
+	  mpq_swap (bq, aq);
+	  mpq_div (resq, aq, bq);
+	  if (!mpq_equal (resq, refq))
+	    {
+	      fprintf (stderr, "mpq_swap failed [%i]:\n", i);
+	      dump ("an", an);
+	      dump ("ad", ad);
+	      dump ("bn", bn);
+	      dump ("bd", bd);
+	      dump ("refn", rn);
+	      dump ("refd", rd);
+	      dump ("resn", mpq_numref (resq));
+	      dump ("resd", mpq_denref (resq));
+	      abort ();
+	    }
+	}
+
+      mpq_set (resq, aq);
+      mpq_neg (bq, aq);
+      mpq_abs (refq, aq);
+      if (mpq_equal (refq, resq))
+	mpq_add (resq, refq, bq);
+      else
+	mpq_add (resq, refq, resq);
+      mpq_set_ui (refq, 0, 1);
+      if (!mpq_equal (resq, refq))
+	{
+	  fprintf (stderr, "mpq_abs failed [%i]:\n", i);
+	      dump ("an", an);
+	      dump ("ad", ad);
+	      dump ("resn", mpq_numref (resq));
+	      dump ("resd", mpq_denref (resq));
+	      abort ();
+	}
+
+      mpq_mul (resq, aq, aq);
+      mpq_mul (refq, aq, bq); /* now bq = - aq */
+      mpq_neg (refq, refq);
+      if (!mpq_equal (resq, refq))
+	{
+	  fprintf (stderr, "mpq_mul(sqr) failed [%i]:\n", i);
+	  dump ("an", an);
+	  dump ("ad", ad);
+	  dump ("bn", bn);
+	  dump ("bd", bd);
+	  dump ("refn", rn);
+	  dump ("refd", rd);
+	  dump ("resn", mpq_numref (resq));
+	  dump ("resd", mpq_denref (resq));
+	  abort ();
+	}
+    }
+
+  mpz_clear (an);
+  mpz_clear (bn);
+  mpz_clear (rn);
+  mpz_clear (ad);
+  mpz_clear (bd);
+  mpz_clear (rd);
+  mpq_clear (aq);
+  mpq_clear (bq);
+  mpq_clear (refq);
+  mpq_clear (resq);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-mpq_muldiv_2exp.c b/third_party/gmp/mini-gmp/tests/t-mpq_muldiv_2exp.c
new file mode 100644
index 0000000..46b2c0c
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-mpq_muldiv_2exp.c
@@ -0,0 +1,138 @@
+/*
+
+Copyright 2012, 2013, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "testutils.h"
+#include "../mini-mpq.h"
+
+#define MAXBITS 300
+#define COUNT 10000
+
+static void
+_mpq_set_zz (mpq_t q, mpz_t n, mpz_t d)
+{
+  if (mpz_fits_ulong_p (d) && mpz_fits_slong_p (n))
+    {
+      mpq_set_si (q, mpz_get_si (n), mpz_get_ui (d));
+    }
+  else if (mpz_fits_ulong_p (d) && mpz_fits_ulong_p (n))
+    {
+      mpq_set_ui (q, mpz_get_ui (n), mpz_get_ui (d));
+    }
+  else
+    {
+      mpq_set_num (q, n);
+      mpq_set_den (q, d);
+    }
+  mpq_canonicalize (q);
+}
+
+void
+testmain (int argc, char **argv)
+{
+  unsigned i;
+  mpz_t a, b, t;
+  mpq_t aq, rq, tq;
+  mp_bitcnt_t e;
+  long int e2, t1, t2;
+
+  mpz_init (a);
+  mpz_init (b);
+  mpz_init (t);
+  mpq_init (aq);
+  mpq_init (rq);
+  mpq_init (tq);
+
+  for (i = 0; i < COUNT; i++)
+    {
+      do {
+	mini_random_bit_op (OP_COMBIT, MAXBITS, a, &e, b);
+      } while (mpz_sgn (a) == 0 || mpz_sgn (b) == 0);
+
+      _mpq_set_zz (aq, a, b);
+      e2 = mpz_scan1 (a, 0);
+      e2-= mpz_scan1 (b, 0);
+
+      mpq_mul_2exp (rq, aq, e);
+      t1 = mpz_scan1 (mpq_numref (rq), 0);
+      t2 = mpz_scan1 (mpq_denref (rq), 0);
+      mpq_neg (tq, rq);
+      mpq_div (tq, aq, tq);
+      mpq_get_den (t, tq);
+
+      if (e2 + e != t1 - t2 || (t2 != 0 && t1 != 0) || mpz_scan1 (t, 0) != e
+	  || mpz_sizeinbase (t, 2) - 1 != e || mpz_cmp_si (mpq_numref (tq), -1) != 0)
+	{
+	  fprintf (stderr, "mpq_mul_2exp failed: %lu\n", e);
+	  dump ("na", a);
+	  dump ("da", b);
+	  dump ("nr", mpq_numref (rq));
+	  dump ("dr", mpq_denref (rq));
+	  abort ();
+	}
+
+      mpq_div_2exp (rq, aq, e);
+      t1 = mpz_scan1 (mpq_numref (rq), 0);
+      t2 = mpz_scan1 (mpq_denref (rq), 0);
+      mpq_div (aq, aq, rq);
+      mpq_get_num (t, aq);
+
+      if (e2 != t1 - t2 + e || (t2 != 0 && t1 != 0) || mpz_scan1 (t, 0) != e
+	  || mpz_sizeinbase (t, 2) - 1 != e || mpz_cmp_ui (mpq_denref (aq), 1) != 0)
+	{
+	  fprintf (stderr, "mpq_div_2exp failed: %lu\n", e);
+	  fprintf (stderr, "%li %li %lu %zu\n", e2, t2, mpz_scan1 (t, 0), mpz_sizeinbase (t, 2));
+	  dump ("na", a);
+	  dump ("da", b);
+	  dump ("nr", mpq_numref (rq));
+	  dump ("dr", mpq_denref (rq));
+	  abort ();
+	}
+
+      mpq_set_ui (aq, 0, 1);
+      mpq_set_ui (rq, 6, 7);
+      mpq_set (tq, aq);
+      mpq_div_2exp (rq, aq, e);
+
+      if (!mpq_equal (tq, rq))
+	{
+	  fprintf (stderr, "mpq_div_2exp failed on zero: %lu\n", e);
+	  abort ();
+	}
+
+      mpq_set_ui (rq, 7, 6);
+      mpq_mul_2exp (rq, aq, e);
+
+      if (!mpq_equal (rq, tq))
+	{
+	  fprintf (stderr, "mpq_mul_2exp failed on zero: %lu\n", e);
+	  abort ();
+	}
+    }
+
+  mpz_clear (a);
+  mpz_clear (b);
+  mpz_clear (t);
+  mpq_clear (aq);
+  mpq_clear (rq);
+  mpq_clear (tq);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-mpq_str.c b/third_party/gmp/mini-gmp/tests/t-mpq_str.c
new file mode 100644
index 0000000..7c69153
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-mpq_str.c
@@ -0,0 +1,252 @@
+/*
+
+Copyright 2012-2014, 2016, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <assert.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "testutils.h"
+#include "../mini-mpq.h"
+
+#define MAXBITS 400
+#define COUNT 2000
+
+#define GMP_LIMB_BITS (sizeof(mp_limb_t) * CHAR_BIT)
+#define MAXLIMBS ((MAXBITS + GMP_LIMB_BITS - 1) / GMP_LIMB_BITS)
+
+static void
+test_small (void)
+{
+  struct {
+    const char *input;
+    const char *decimal;
+  } data[] = {
+    { "1832407/3", "1832407/3" },
+    { " 2763959/6", "2763959/6 " },
+    { "4 981 999 / 1 8", "4981999/18" },
+    { "10\t73981/30 ", "1073981/30" },
+    { "958 544 /1", "00958544/01" },
+    { "-0", "0000" },
+    { " -000  ", "0/ 1" },
+    { "0704436/011", "231710/9" },
+    /* Check the case of large number of leading zeros. */
+    { "0000000000000000000000000/1", "0/0000000000000000000000001" },
+    { "000000000000000704436/000011", "0000000000000000231710/00009" },
+    { " 012/ 02503517", "10/689999" },
+    { "0b 10/0 1312143", "2/365667" },
+    { "-03 274062/0x1", "-882738/1" },
+    { "012\t242", "005282" },
+    { "9/0b11010111110010001111", "9/883855" },
+    { "022/ 0b11001010010100001", "18/103585" },
+    { "-0b101010110011101111/0x12", "-175343/18" },
+    { "-05/0b 111 1111 0110 1110 0110", "-5/521958" },
+    { "0b 011 111 110 111 001 000 011/0b00110", "1044035/6" },
+    { " 0x53dfc", "343548" },
+    { "-0x00012/0x000fA019", "-18/1024025" },
+    { "0x 642d1", "410321" },
+    { "0x5 8067/0Xa", "360551/10" },
+    { "-0xd6Be6/3", "-879590/3" },
+    { "\t0B1110000100000000011", "460803" },
+    { "0B\t1111110010010100101", "517285" },
+    { "-0x 00 2d/0B1\t010111101101110100", "-45/359284" },
+    { "-0B101\t1001101111111001", "-367609" },
+    { "0B10001001010111110000/0xf", "562672/15" },
+    { "0Xe4B7e/1", "936830" },
+    { "0X1E4bf/0X1", "124095" },
+    { "-0Xfdb90/05", "-1039248/5" },
+    { "0b010/0X7fc47", "2/523335" },
+    { "15/0X8167c", "15/530044" },
+    /* Some invalid inputs */
+    { "", NULL },
+    { "0x", NULL },
+    { "0b", NULL },
+    { "0z", NULL },
+    { "-", NULL },
+    { "/0x ", NULL },
+    { "0|1", NULL },
+    { "/", NULL },
+    { "0ab", NULL },
+    { "10x0", NULL },
+    { "1/0xxab", NULL },
+    { "0/ab", NULL },
+    { "0/#", NULL },
+    { "$foo/1", NULL },
+    { NULL, NULL }
+  };
+  unsigned i;
+  mpq_t a, b;
+  mpq_init (a);
+  mpq_init (b);
+
+  for (i = 0; data[i].input; i++)
+    {
+      int res = mpq_set_str (a, data[i].input, 0);
+      if (data[i].decimal)
+	{
+	  if (res != 0)
+	    {
+	      fprintf (stderr, "mpq_set_str returned -1, input: %s\n",
+		       data[i].input);
+	      abort ();
+	    }
+	  if (mpq_set_str (b, data[i].decimal, 10) != 0)
+	    {
+	      fprintf (stderr, "mpq_set_str returned -1, decimal input: %s\n",
+		       data[i].input);
+	      abort ();
+	    }
+	  if (!mpq_equal (a, b))
+	    {
+	      fprintf (stderr, "mpq_set_str failed for input: %s\n",
+		       data[i].input);
+
+	      dump ("got_num", mpq_numref (a));
+	      dump ("got_den", mpq_denref (a));
+	      dump ("ref_num", mpq_numref (b));
+	      dump ("ref_den", mpq_denref (b));
+	      abort ();
+	    }
+	}
+      else if (res != -1)
+	{
+	  fprintf (stderr, "mpq_set_str returned %d, invalid input: %s\n",
+		   res, data[i].input);
+	  abort ();
+	}
+    }
+
+  mpq_clear (a);
+  mpq_clear (b);
+}
+
+void
+testmain (int argc, char **argv)
+{
+  unsigned i;
+  char *ap;
+  char *bp;
+  char *rp;
+  size_t rn, arn;
+
+  mpq_t a, b;
+
+  FILE *tmp;
+
+  test_small ();
+
+  mpq_init (a);
+  mpq_init (b);
+
+  tmp = tmpfile ();
+  if (!tmp)
+    fprintf (stderr,
+	     "Failed to create temporary file. Skipping mpq_out_str tests.\n");
+
+  for (i = 0; i < COUNT/60; i++)
+    {
+      int base;
+      for (base = 2; base <= 62; ++base)
+	{
+	  hex_mpq_random_str_op (MAXBITS, (i&1 || base > 36) ? base: -base, &ap, &rp);
+	  if (mpq_set_str (a, ap, 16) != 0)
+	    {
+	      fprintf (stderr, "mpq_set_str failed on input %s\n", ap);
+	      abort ();
+	    }
+
+	  rn = strlen (rp);
+	  arn = rn - (rp[0] == '-');
+
+	  bp = mpq_get_str (NULL, (i&1 || base > 36) ? base: -base, a);
+	  if (strcmp (bp, rp))
+	    {
+	      fprintf (stderr, "mpz_get_str failed:\n");
+	      dump ("a_num", mpq_numref (a));
+	      dump ("a_den", mpq_denref (a));
+	      fprintf (stderr, "b = %s\n", bp);
+	      fprintf (stderr, "  base = %d\n", base);
+	      fprintf (stderr, "r = %s\n", rp);
+	      abort ();
+	    }
+
+	  /* Just a few tests with file i/o. */
+	  if (tmp && i < 20)
+	    {
+	      size_t tn;
+	      rewind (tmp);
+	      tn = mpq_out_str (tmp, (i&1 || base > 36) ? base: -base, a);
+	      if (tn != rn)
+		{
+		  fprintf (stderr, "mpq_out_str, bad return value:\n");
+		  dump ("a_num", mpq_numref (a));
+		  dump ("a_den", mpq_denref (a));
+		  fprintf (stderr, "r = %s\n", rp);
+		  fprintf (stderr, "  base %d, correct size %u, got %u\n",
+			   base, (unsigned) rn, (unsigned)tn);
+		  abort ();
+		}
+	      rewind (tmp);
+	      memset (bp, 0, rn);
+	      tn = fread (bp, 1, rn, tmp);
+	      if (tn != rn)
+		{
+		  fprintf (stderr,
+			   "fread failed, expected %lu bytes, got only %lu.\n",
+			   (unsigned long) rn, (unsigned long) tn);
+		  abort ();
+		}
+
+	      if (memcmp (bp, rp, rn) != 0)
+		{
+		  fprintf (stderr, "mpq_out_str failed:\n");
+		  dump ("a_num", mpq_numref (a));
+		  dump ("a_den", mpq_denref (a));
+		  fprintf (stderr, "b = %s\n", bp);
+		  fprintf (stderr, "  base = %d\n", base);
+		  fprintf (stderr, "r = %s\n", rp);
+		  abort ();
+		}
+	    }
+
+	  mpq_set_str (b, rp, base);
+
+	  if (!mpq_equal (a, b))
+	    {
+	      fprintf (stderr, "mpq_set_str failed:\n");
+	      fprintf (stderr, "r = %s\n", rp);
+	      fprintf (stderr, "  base = %d\n", base);
+	      fprintf (stderr, "r = %s\n", ap);
+	      fprintf (stderr, "  base = 16\n");
+	      dump ("b_num", mpq_numref (b));
+	      dump ("b_den", mpq_denref (b));
+	      dump ("r_num", mpq_numref (a));
+	      dump ("r_den", mpq_denref (a));
+	      abort ();
+	    }
+
+	  free (ap);
+	  free (rp);
+	  testfree (bp);
+	}
+    }
+  mpq_clear (a);
+  mpq_clear (b);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-mul.c b/third_party/gmp/mini-gmp/tests/t-mul.c
new file mode 100644
index 0000000..57ec4ed
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-mul.c
@@ -0,0 +1,113 @@
+/*
+
+Copyright 2012, 2014, Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "testutils.h"
+
+#define MAXBITS 400
+#define COUNT 10000
+
+#define GMP_LIMB_BITS (sizeof(mp_limb_t) * CHAR_BIT)
+#define MAXLIMBS ((MAXBITS + GMP_LIMB_BITS - 1) / GMP_LIMB_BITS)
+
+void
+testmain (int argc, char **argv)
+{
+  unsigned i;
+  mpz_t a, b, res, res_ui, ref, tz;
+  mp_limb_t t[2*MAXLIMBS];
+  mp_size_t an;
+
+  mpz_init (a);
+  mpz_init (b);
+  mpz_init (res);
+  mpz_init (res_ui);
+  mpz_init (ref);
+
+  for (i = 0; i < COUNT; i++)
+    {
+      mini_random_op3 (OP_MUL, MAXBITS, a, b, ref);
+      mpz_mul (res, a, b);
+      if (mpz_cmp (res, ref))
+	{
+	  fprintf (stderr, "mpz_mul failed:\n");
+	  dump ("a", a);
+	  dump ("b", b);
+	  dump ("r", res);
+	  dump ("ref", ref);
+	  abort ();
+	}
+      if (mpz_size (a) == mpz_size (b))
+	{
+	  memset (t, 0x55, sizeof(t));
+	  an = mpz_size (a);
+	  if (an > 0)
+	    {
+	      mpn_mul_n (t, a->_mp_d, b->_mp_d, an);
+
+	      mpz_roinit_n (tz, t, 2*an);
+	      if (mpz_cmpabs (tz, ref))
+		{
+		  fprintf (stderr, "mpn_mul_n failed:\n");
+		  dump ("a", a);
+		  dump ("b", b);
+		  dump ("ref", ref);
+		  abort ();
+		}
+	    }
+	}
+      if (mpz_fits_slong_p (b)) {
+	mpz_mul_si (res_ui, a, mpz_get_si (b));
+	if (mpz_cmp (res_ui, ref))
+	  {
+	    fprintf (stderr, "mpz_mul_si failed:\n");
+	    dump ("a", a);
+	    dump ("b", b);
+	    dump ("r", res_ui);
+	    dump ("ref", ref);
+	    abort ();
+	  }
+      }
+      mini_random_op2 (OP_SQR, MAXBITS, a, ref);
+      an = mpz_size (a);
+      if (an > 0)
+	{
+	  memset (t, 0x33, sizeof(t));
+	  mpn_sqr (t, mpz_limbs_read (a), an);
+
+	  mpz_roinit_n (tz, t, 2*an);
+	  if (mpz_cmp (tz, ref))
+	    {
+	      fprintf (stderr, "mpn (squaring) failed:\n");
+	      dump ("a", a);
+	      dump ("ref", ref);
+	      abort ();
+	    }
+	}
+    }
+  mpz_clear (a);
+  mpz_clear (b);
+  mpz_clear (res);
+  mpz_clear (res_ui);
+  mpz_clear (ref);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-powm.c b/third_party/gmp/mini-gmp/tests/t-powm.c
new file mode 100644
index 0000000..d6c108d
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-powm.c
@@ -0,0 +1,61 @@
+/*
+
+Copyright 2012, Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "testutils.h"
+
+#define MAXBITS 400
+#define COUNT 1000
+
+void
+testmain (int argc, char **argv)
+{
+  unsigned i;
+  mpz_t b, e, m, res, ref;
+
+  mpz_init (b);
+  mpz_init (e);
+  mpz_init (m);
+  mpz_init (res);
+  mpz_init (ref);
+
+  for (i = 0; i < COUNT; i++)
+    {
+      mini_random_op4 (OP_POWM, MAXBITS, b, e, m, ref);
+      mpz_powm (res, b, e, m);
+      if (mpz_cmp (res, ref))
+	{
+	  fprintf (stderr, "mpz_powm failed:\n");
+	  dump ("b", b);
+	  dump ("e", e);
+	  dump ("m", m);
+	  dump ("r", res);
+	  dump ("ref", ref);
+	  abort ();
+	}
+    }
+  mpz_clear (b);
+  mpz_clear (e);
+  mpz_clear (m);
+  mpz_clear (res);
+  mpz_clear (ref);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-pprime_p.c b/third_party/gmp/mini-gmp/tests/t-pprime_p.c
new file mode 100644
index 0000000..6cf9b18
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-pprime_p.c
@@ -0,0 +1,183 @@
+/* test mpz_probab_prime_p
+
+Copyright 2001, 2002, 2004, 2011, 2012, 2014, 2016 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "testutils.h"
+
+static int
+isprime (unsigned long int t)
+{
+  unsigned long int q, r, d;
+
+  if (t < 32)
+    return (0xa08a28acUL >> t) & 1;
+  if ((t & 1) == 0)
+    return 0;
+
+  if (t % 3 == 0)
+    return 0;
+  if (t % 5 == 0)
+    return 0;
+  if (t % 7 == 0)
+    return 0;
+
+  for (d = 11;;)
+    {
+      q = t / d;
+      r = t - q * d;
+      if (q < d)
+	return 1;
+      if (r == 0)
+	break;
+      d += 2;
+      q = t / d;
+      r = t - q * d;
+      if (q < d)
+	return 1;
+      if (r == 0)
+	break;
+      d += 4;
+    }
+  return 0;
+}
+
+static void
+check_one (mpz_srcptr n, int want)
+{
+  int  got;
+
+  got = mpz_probab_prime_p (n, 25);
+
+  /* "definitely prime" is fine if we only wanted "probably prime" */
+  if (got == 2 && want == 1)
+    want = 2;
+
+  if (got != want)
+    {
+      printf ("mpz_probab_prime_p\n");
+      dump   ("  n    ", n);
+      printf ("  got =%d", got);
+      printf ("  want=%d\n", want);
+      abort ();
+    }
+}
+
+static void
+check_pn (mpz_ptr n, int want)
+{
+  check_one (n, want);
+  mpz_neg (n, n);
+  check_one (n, want);
+}
+
+static void
+check_small (void)
+{
+  mpz_t  n;
+  long   i;
+
+  mpz_init (n);
+
+  for (i = 0; i < 1700; i++)
+    {
+      mpz_set_si (n, i);
+      check_pn (n, isprime (i));
+    }
+
+  mpz_clear (n);
+}
+
+void
+check_composites (void)
+{
+  int i;
+  int reps = 1000;
+  mpz_t a, b, n, bs;
+  unsigned long size_range, size;
+
+  mpz_init (a);
+  mpz_init (b);
+  mpz_init (n);
+  mpz_init (bs);
+
+  for (i = 0; i < reps; i++)
+    {
+      mini_urandomb (bs, 16);
+      size_range = mpz_get_ui (bs) % 10 + 1; /* 0..1024 bit operands */
+
+      mini_urandomb (bs, size_range);
+      size = mpz_get_ui (bs);
+      mini_rrandomb (a, size);
+
+      mini_urandomb (bs, size_range);
+      size = mpz_get_ui (bs);
+      mini_rrandomb (b, size);
+
+      /* Exclude trivial factors */
+      if (mpz_cmp_ui (a, 1) == 0)
+	mpz_set_ui (a, 2);
+      if (mpz_cmp_ui (b, 1) == 0)
+	mpz_set_ui (b, 2);
+
+      mpz_mul (n, a, b);
+
+      check_pn (n, 0);
+    }
+  mpz_clear (a);
+  mpz_clear (b);
+  mpz_clear (n);
+  mpz_clear (bs);
+}
+
+static void
+check_primes (void)
+{
+  static const char * const primes[] = {
+    "2", "17", "65537",
+    /* diffie-hellman-group1-sha1, also "Well known group 2" in RFC
+       2412, 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 } */
+    "0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
+    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
+    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381"
+    "FFFFFFFFFFFFFFFF",
+    NULL
+  };
+
+  mpz_t n;
+  int i;
+
+  mpz_init (n);
+
+  for (i = 0; primes[i]; i++)
+    {
+      mpz_set_str_or_abort (n, primes[i], 0);
+      check_one (n, 1);
+    }
+  mpz_clear (n);
+}
+
+void
+testmain (int argc, char *argv[])
+{
+  check_small ();
+  check_composites ();
+  check_primes ();
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-reuse.c b/third_party/gmp/mini-gmp/tests/t-reuse.c
new file mode 100644
index 0000000..5ac9e11
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-reuse.c
@@ -0,0 +1,663 @@
+/* Test that routines allow reusing a source variable as destination.
+
+Copyright 1996, 1999-2002, 2009, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "testutils.h"
+
+#define COUNT 100
+
+void dump3 (const char *, mpz_t, mpz_t, mpz_t);
+void mpz_check_format (const mpz_t);
+
+typedef void (*dss_func) (mpz_t, const mpz_t, const mpz_t);
+typedef void (*dsi_func) (mpz_t, const mpz_t, unsigned long int);
+typedef unsigned long int (*dsi_div_func) (mpz_t, const mpz_t, unsigned long int);
+typedef unsigned long int (*ddsi_div_func) (mpz_t, mpz_t, const mpz_t, unsigned long int);
+typedef void (*ddss_div_func) (mpz_t, mpz_t, const mpz_t, const mpz_t);
+typedef void (*ds_func) (mpz_t, const mpz_t);
+
+
+void
+mpz_xinvert (mpz_t r, const mpz_t a, const mpz_t b)
+{
+  int res;
+  res = mpz_invert (r, a, b);
+  if (res == 0)
+    mpz_set_ui (r, 0);
+}
+
+dss_func dss_funcs[] =
+{
+  mpz_add, mpz_sub, mpz_mul,
+  mpz_cdiv_q, mpz_cdiv_r, mpz_fdiv_q, mpz_fdiv_r, mpz_tdiv_q, mpz_tdiv_r,
+  mpz_xinvert,
+  mpz_gcd, mpz_lcm, mpz_and, mpz_ior, mpz_xor
+};
+const char *dss_func_names[] =
+{
+  "mpz_add", "mpz_sub", "mpz_mul",
+  "mpz_cdiv_q", "mpz_cdiv_r", "mpz_fdiv_q", "mpz_fdiv_r", "mpz_tdiv_q", "mpz_tdiv_r",
+  "mpz_xinvert",
+  "mpz_gcd", "mpz_lcm", "mpz_and", "mpz_ior", "mpz_xor"
+};
+char dss_func_division[] = {0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0};
+
+dsi_func dsi_funcs[] =
+{
+  /* Don't change order here without changing the code in main(). */
+  mpz_add_ui, mpz_mul_ui, mpz_sub_ui,
+  mpz_fdiv_q_2exp, mpz_fdiv_r_2exp,
+  mpz_cdiv_q_2exp, mpz_cdiv_r_2exp,
+  mpz_tdiv_q_2exp, mpz_tdiv_r_2exp,
+  mpz_mul_2exp,
+  mpz_pow_ui
+};
+const char *dsi_func_names[] =
+{
+  "mpz_add_ui", "mpz_mul_ui", "mpz_sub_ui",
+  "mpz_fdiv_q_2exp", "mpz_fdiv_r_2exp",
+  "mpz_cdiv_q_2exp", "mpz_cdiv_r_2exp",
+  "mpz_tdiv_q_2exp", "mpz_tdiv_r_2exp",
+  "mpz_mul_2exp",
+  "mpz_pow_ui"
+};
+
+dsi_div_func dsi_div_funcs[] =
+{
+  mpz_cdiv_q_ui, mpz_cdiv_r_ui,
+  mpz_fdiv_q_ui, mpz_fdiv_r_ui,
+  mpz_tdiv_q_ui, mpz_tdiv_r_ui
+};
+const char *dsi_div_func_names[] =
+{
+  "mpz_cdiv_q_ui", "mpz_cdiv_r_ui",
+  "mpz_fdiv_q_ui", "mpz_fdiv_r_ui",
+  "mpz_tdiv_q_ui", "mpz_tdiv_r_ui"
+};
+
+ddsi_div_func ddsi_div_funcs[] =
+{
+  mpz_cdiv_qr_ui,
+  mpz_fdiv_qr_ui,
+  mpz_tdiv_qr_ui
+};
+const char *ddsi_div_func_names[] =
+{
+  "mpz_cdiv_qr_ui",
+  "mpz_fdiv_qr_ui",
+  "mpz_tdiv_qr_ui"
+};
+
+ddss_div_func ddss_div_funcs[] =
+{
+  mpz_cdiv_qr,
+  mpz_fdiv_qr,
+  mpz_tdiv_qr
+};
+const char *ddss_div_func_names[] =
+{
+  "mpz_cdiv_qr",
+  "mpz_fdiv_qr",
+  "mpz_tdiv_qr"
+};
+
+ds_func ds_funcs[] =
+{
+  mpz_abs, mpz_com, mpz_neg, mpz_sqrt
+};
+const char *ds_func_names[] =
+{
+  "mpz_abs", "mpz_com", "mpz_neg", "mpz_sqrt"
+};
+
+
+#define FAIL(class,indx,op1,op2,op3) \
+  do {									\
+  class##_funcs[indx] = 0;						\
+  dump3 (class##_func_names[indx], op1, op2, op3);			\
+  failures++;								\
+  } while (0)
+#define FAIL2(fname,op1,op2,op3) \
+  do {									\
+  dump3 (#fname, op1, op2, op3);						\
+  failures++;								\
+  } while (0)
+
+void
+testmain (int argc, char **argv)
+{
+  unsigned i;
+  int pass, reps = COUNT;
+  mpz_t in1, in2, in3;
+  unsigned long int in2i;
+  mp_size_t size;
+  mpz_t res1, res2, res3;
+  mpz_t ref1, ref2, ref3;
+  mpz_t t;
+  unsigned long int r1, r2;
+  long failures = 0;
+  mpz_t bs;
+  unsigned long bsi, size_range;
+
+  mpz_init (bs);
+
+  mpz_init (in1);
+  mpz_init (in2);
+  mpz_init (in3);
+  mpz_init (ref1);
+  mpz_init (ref2);
+  mpz_init (ref3);
+  mpz_init (res1);
+  mpz_init (res2);
+  mpz_init (res3);
+  mpz_init (t);
+
+  for (pass = 1; pass <= reps; pass++)
+    {
+      mini_urandomb (bs, 32);
+      size_range = mpz_get_ui (bs) % 12 + 2;
+
+      mini_urandomb (bs, size_range);
+      size = mpz_get_ui (bs);
+      mini_rrandomb (in1, size);
+
+      mini_urandomb (bs, size_range);
+      size = mpz_get_ui (bs);
+      mini_rrandomb (in2, size);
+
+      mini_urandomb (bs, size_range);
+      size = mpz_get_ui (bs);
+      mini_rrandomb (in3, size);
+
+      mini_urandomb (bs, 3);
+      bsi = mpz_get_ui (bs);
+      if ((bsi & 1) != 0)
+	mpz_neg (in1, in1);
+      if ((bsi & 2) != 0)
+	mpz_neg (in2, in2);
+      if ((bsi & 4) != 0)
+	mpz_neg (in3, in3);
+
+      for (i = 0; i < sizeof (dss_funcs) / sizeof (dss_func); i++)
+	{
+	  if (dss_funcs[i] == 0)
+	    continue;
+	  if (dss_func_division[i] && mpz_sgn (in2) == 0)
+	    continue;
+
+	  (dss_funcs[i]) (ref1, in1, in2);
+	  mpz_check_format (ref1);
+
+	  mpz_set (res1, in1);
+	  (dss_funcs[i]) (res1, res1, in2);
+	  mpz_check_format (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL (dss, i, in1, in2, NULL);
+
+	  mpz_set (res1, in2);
+	  (dss_funcs[i]) (res1, in1, res1);
+	  mpz_check_format (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL (dss, i, in1, in2, NULL);
+	}
+
+      for (i = 0; i < sizeof (ddss_div_funcs) / sizeof (ddss_div_func); i++)
+	{
+	  if (ddss_div_funcs[i] == 0)
+	    continue;
+	  if (mpz_sgn (in2) == 0)
+	    continue;
+
+	  (ddss_div_funcs[i]) (ref1, ref2, in1, in2);
+	  mpz_check_format (ref1);
+	  mpz_check_format (ref2);
+
+	  mpz_set (res1, in1);
+	  (ddss_div_funcs[i]) (res1, res2, res1, in2);
+	  mpz_check_format (res1);
+	  mpz_check_format (res2);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0)
+	    FAIL (ddss_div, i, in1, in2, NULL);
+
+	  mpz_set (res2, in1);
+	  (ddss_div_funcs[i]) (res1, res2, res2, in2);
+	  mpz_check_format (res1);
+	  mpz_check_format (res2);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0)
+	    FAIL (ddss_div, i, in1, in2, NULL);
+
+	  mpz_set (res1, in2);
+	  (ddss_div_funcs[i]) (res1, res2, in1, res1);
+	  mpz_check_format (res1);
+	  mpz_check_format (res2);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0)
+	    FAIL (ddss_div, i, in1, in2, NULL);
+
+	  mpz_set (res2, in2);
+	  (ddss_div_funcs[i]) (res1, res2, in1, res2);
+	  mpz_check_format (res1);
+	  mpz_check_format (res2);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0)
+	    FAIL (ddss_div, i, in1, in2, NULL);
+	}
+
+      for (i = 0; i < sizeof (ds_funcs) / sizeof (ds_func); i++)
+	{
+	  if (ds_funcs[i] == 0)
+	    continue;
+	  if (strcmp (ds_func_names[i], "mpz_sqrt") == 0
+	      && mpz_sgn (in1) < 0)
+	    continue;
+
+	  (ds_funcs[i]) (ref1, in1);
+	  mpz_check_format (ref1);
+
+	  mpz_set (res1, in1);
+	  (ds_funcs[i]) (res1, res1);
+	  mpz_check_format (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL (ds, i, in1, in2, NULL);
+	}
+
+      in2i = mpz_get_ui (in2);
+
+      for (i = 0; i < sizeof (dsi_funcs) / sizeof (dsi_func); i++)
+	{
+	  if (dsi_funcs[i] == 0)
+	    continue;
+	  if (strcmp (dsi_func_names[i], "mpz_fdiv_q_2exp") == 0)
+	    /* Limit exponent to something reasonable for the division
+	       functions.  Without this, we'd  normally shift things off
+	       the end and just generate the trivial values 1, 0, -1.  */
+	    in2i %= 0x1000;
+	  if (strcmp (dsi_func_names[i], "mpz_mul_2exp") == 0)
+	    /* Limit exponent more for mpz_mul_2exp to save time.  */
+	    in2i %= 0x100;
+	  if (strcmp (dsi_func_names[i], "mpz_pow_ui") == 0)
+	    /* Limit exponent yet more for mpz_pow_ui to save time.  */
+	    in2i %= 0x10;
+
+	  (dsi_funcs[i]) (ref1, in1, in2i);
+	  mpz_check_format (ref1);
+
+	  mpz_set (res1, in1);
+	  (dsi_funcs[i]) (res1, res1, in2i);
+	  mpz_check_format (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL (dsi, i, in1, in2, NULL);
+	}
+
+      if (in2i != 0)	  /* Don't divide by 0.  */
+	{
+	  for (i = 0; i < sizeof (dsi_div_funcs) / sizeof (dsi_div_funcs); i++)
+	    {
+	      r1 = (dsi_div_funcs[i]) (ref1, in1, in2i);
+	      mpz_check_format (ref1);
+
+	      mpz_set (res1, in1);
+	      r2 = (dsi_div_funcs[i]) (res1, res1, in2i);
+	      mpz_check_format (res1);
+	      if (mpz_cmp (ref1, res1) != 0 || r1 != r2)
+		FAIL (dsi_div, i, in1, in2, NULL);
+	    }
+
+	  for (i = 0; i < sizeof (ddsi_div_funcs) / sizeof (ddsi_div_funcs); i++)
+	    {
+	      r1 = (ddsi_div_funcs[i]) (ref1, ref2, in1, in2i);
+	      mpz_check_format (ref1);
+
+	      mpz_set (res1, in1);
+	      r2 = (ddsi_div_funcs[i]) (res1, res2, res1, in2i);
+	      mpz_check_format (res1);
+	      if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0 || r1 != r2)
+		FAIL (ddsi_div, i, in1, in2, NULL);
+
+	      mpz_set (res2, in1);
+	      (ddsi_div_funcs[i]) (res1, res2, res2, in2i);
+	      mpz_check_format (res1);
+	      if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0 || r1 != r2)
+		FAIL (ddsi_div, i, in1, in2, NULL);
+	    }
+	}
+
+      if (mpz_sgn (in1) >= 0)
+	{
+	  mpz_sqrtrem (ref1, ref2, in1);
+	  mpz_check_format (ref1);
+	  mpz_check_format (ref2);
+
+	  mpz_set (res1, in1);
+	  mpz_sqrtrem (res1, res2, res1);
+	  mpz_check_format (res1);
+	  mpz_check_format (res2);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0)
+	    FAIL2 (mpz_sqrtrem, in1, NULL, NULL);
+
+	  mpz_set (res2, in1);
+	  mpz_sqrtrem (res1, res2, res2);
+	  mpz_check_format (res1);
+	  mpz_check_format (res2);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0)
+	    FAIL2 (mpz_sqrtrem, in1, NULL, NULL);
+	}
+
+      if (mpz_sgn (in1) >= 0)
+	{
+	  mpz_root (ref1, in1, in2i % 0x1000 + 1);
+	  mpz_check_format (ref1);
+
+	  mpz_set (res1, in1);
+	  mpz_root (res1, res1, in2i % 0x1000 + 1);
+	  mpz_check_format (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL2 (mpz_root, in1, in2, NULL);
+	}
+
+      if (mpz_sgn (in1) >= 0)
+	{
+	  mpz_rootrem (ref1, ref2, in1, in2i % 0x1000 + 1);
+	  mpz_check_format (ref1);
+	  mpz_check_format (ref2);
+
+	  mpz_set (res1, in1);
+	  mpz_rootrem (res1, res2, res1, in2i % 0x1000 + 1);
+	  mpz_check_format (res1);
+	  mpz_check_format (res2);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0)
+	    FAIL2 (mpz_rootrem, in1, in2, NULL);
+
+	  mpz_set (res2, in1);
+	  mpz_rootrem (res1, res2, res2, in2i % 0x1000 + 1);
+	  mpz_check_format (res1);
+	  mpz_check_format (res2);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0)
+	    FAIL2 (mpz_rootrem, in1, in2, NULL);
+	}
+
+      if (pass < reps / 2)	/* run fewer tests since gcdext lots of time */
+	{
+	  mpz_gcdext (ref1, ref2, ref3, in1, in2);
+	  mpz_check_format (ref1);
+	  mpz_check_format (ref2);
+	  mpz_check_format (ref3);
+
+	  mpz_set (res1, in1);
+	  mpz_gcdext (res1, res2, res3, res1, in2);
+	  mpz_check_format (res1);
+	  mpz_check_format (res2);
+	  mpz_check_format (res3);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0
+	      || mpz_cmp (ref3, res3) != 0)
+	    FAIL2 (mpz_gcdext, in1, in2, NULL);
+
+	  mpz_set (res2, in1);
+	  mpz_gcdext (res1, res2, res3, res2, in2);
+	  mpz_check_format (res1);
+	  mpz_check_format (res2);
+	  mpz_check_format (res3);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0
+	      || mpz_cmp (ref3, res3) != 0)
+	    FAIL2 (mpz_gcdext, in1, in2, NULL);
+
+	  mpz_set (res3, in1);
+	  mpz_gcdext (res1, res2, res3, res3, in2);
+	  mpz_check_format (res1);
+	  mpz_check_format (res2);
+	  mpz_check_format (res3);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0
+	      || mpz_cmp (ref3, res3) != 0)
+	    FAIL2 (mpz_gcdext, in1, in2, NULL);
+
+	  mpz_set (res1, in2);
+	  mpz_gcdext (res1, res2, res3, in1, res1);
+	  mpz_check_format (res1);
+	  mpz_check_format (res2);
+	  mpz_check_format (res3);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0
+	      || mpz_cmp (ref3, res3) != 0)
+	    FAIL2 (mpz_gcdext, in1, in2, NULL);
+
+	  mpz_set (res2, in2);
+	  mpz_gcdext (res1, res2, res3, in1, res2);
+	  mpz_check_format (res1);
+	  mpz_check_format (res2);
+	  mpz_check_format (res3);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0
+	      || mpz_cmp (ref3, res3) != 0)
+	    FAIL2 (mpz_gcdext, in1, in2, NULL);
+
+	  mpz_set (res3, in2);
+	  mpz_gcdext (res1, res2, res3, in1, res3);
+	  mpz_check_format (res1);
+	  mpz_check_format (res2);
+	  mpz_check_format (res3);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0
+	      || mpz_cmp (ref3, res3) != 0)
+	    FAIL2 (mpz_gcdext, in1, in2, NULL);
+
+	  mpz_set (res1, in1);
+	  mpz_gcdext (res1, res2, NULL, res1, in2);
+	  mpz_check_format (res1);
+	  mpz_check_format (res2);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0
+	      || mpz_cmp (ref3, res3) != 0)
+	    FAIL2 (mpz_gcdext, in1, in2, NULL);
+
+	  mpz_set (res2, in1);
+	  mpz_gcdext (res1, res2, NULL, res2, in2);
+	  mpz_check_format (res1);
+	  mpz_check_format (res2);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0
+	      || mpz_cmp (ref3, res3) != 0)
+	    FAIL2 (mpz_gcdext, in1, in2, NULL);
+
+	  mpz_set (res1, in2);
+	  mpz_gcdext (res1, res2, NULL, in1, res1);
+	  mpz_check_format (res1);
+	  mpz_check_format (res2);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0
+	      || mpz_cmp (ref3, res3) != 0)
+	    FAIL2 (mpz_gcdext, in1, in2, NULL);
+
+	  mpz_set (res2, in2);
+	  mpz_gcdext (res1, res2, NULL, in1, res2);
+	  mpz_check_format (res1);
+	  mpz_check_format (res2);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0
+	      || mpz_cmp (ref3, res3) != 0)
+	    FAIL2 (mpz_gcdext, in1, in2, NULL);
+	}
+
+      /* Don't run mpz_powm for huge exponents or when undefined.  */
+      if (mpz_sizeinbase (in2, 2) < 250 && mpz_sgn (in3) != 0
+	  && (mpz_sgn (in2) >= 0 || mpz_invert (t, in1, in3)))
+	{
+	  mpz_powm (ref1, in1, in2, in3);
+	  mpz_check_format (ref1);
+
+	  mpz_set (res1, in1);
+	  mpz_powm (res1, res1, in2, in3);
+	  mpz_check_format (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL2 (mpz_powm, in1, in2, in3);
+
+	  mpz_set (res1, in2);
+	  mpz_powm (res1, in1, res1, in3);
+	  mpz_check_format (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL2 (mpz_powm, in1, in2, in3);
+
+	  mpz_set (res1, in3);
+	  mpz_powm (res1, in1, in2, res1);
+	  mpz_check_format (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL2 (mpz_powm, in1, in2, in3);
+	}
+
+      /* Don't run mpz_powm_ui when undefined.  */
+      if (mpz_sgn (in3) != 0)
+	{
+	  mpz_powm_ui (ref1, in1, in2i, in3);
+	  mpz_check_format (ref1);
+
+	  mpz_set (res1, in1);
+	  mpz_powm_ui (res1, res1, in2i, in3);
+	  mpz_check_format (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL2 (mpz_powm_ui, in1, in2, in3);
+
+	  mpz_set (res1, in3);
+	  mpz_powm_ui (res1, in1, in2i, res1);
+	  mpz_check_format (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL2 (mpz_powm_ui, in1, in2, in3);
+	}
+
+      {
+	r1 = mpz_gcd_ui (ref1, in1, in2i);
+	mpz_check_format (ref1);
+
+	mpz_set (res1, in1);
+	r2 = mpz_gcd_ui (res1, res1, in2i);
+	mpz_check_format (res1);
+	if (mpz_cmp (ref1, res1) != 0)
+	  FAIL2 (mpz_gcd_ui, in1, in2, NULL);
+      }
+#if 0
+      if (mpz_cmp_ui (in2, 1L) > 0 && mpz_sgn (in1) != 0)
+	{
+	  /* Test mpz_remove */
+	  mpz_remove (ref1, in1, in2);
+	  mpz_check_format (ref1);
+
+	  mpz_set (res1, in1);
+	  mpz_remove (res1, res1, in2);
+	  mpz_check_format (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL2 (mpz_remove, in1, in2, NULL);
+
+	  mpz_set (res1, in2);
+	  mpz_remove (res1, in1, res1);
+	  mpz_check_format (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL2 (mpz_remove, in1, in2, NULL);
+	}
+#endif
+      if (mpz_sgn (in2) != 0)
+	{
+	  /* Test mpz_divexact */
+	  mpz_mul (t, in1, in2);
+	  mpz_divexact (ref1, t, in2);
+	  mpz_check_format (ref1);
+
+	  mpz_set (res1, t);
+	  mpz_divexact (res1, res1, in2);
+	  mpz_check_format (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL2 (mpz_divexact, t, in2, NULL);
+
+	  mpz_set (res1, in2);
+	  mpz_divexact (res1, t, res1);
+	  mpz_check_format (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL2 (mpz_divexact, t, in2, NULL);
+	}
+
+#if 0
+      if (mpz_sgn (in2) > 0)
+	{
+	  /* Test mpz_divexact_gcd, same as mpz_divexact */
+	  mpz_mul (t, in1, in2);
+	  mpz_divexact_gcd (ref1, t, in2);
+	  mpz_check_format (ref1);
+
+	  mpz_set (res1, t);
+	  mpz_divexact_gcd (res1, res1, in2);
+	  mpz_check_format (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL2 (mpz_divexact_gcd, t, in2, NULL);
+
+	  mpz_set (res1, in2);
+	  mpz_divexact_gcd (res1, t, res1);
+	  mpz_check_format (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL2 (mpz_divexact_gcd, t, in2, NULL);
+	}
+#endif
+    }
+
+  if (failures != 0)
+    {
+      fprintf (stderr, "mpz/reuse: %ld error%s\n", failures, "s" + (failures == 1));
+      exit (1);
+    }
+
+  mpz_clear (bs);
+  mpz_clear (in1);
+  mpz_clear (in2);
+  mpz_clear (in3);
+  mpz_clear (ref1);
+  mpz_clear (ref2);
+  mpz_clear (ref3);
+  mpz_clear (res1);
+  mpz_clear (res2);
+  mpz_clear (res3);
+  mpz_clear (t);
+}
+
+void
+dump3 (const char *name, mpz_t in1, mpz_t in2, mpz_t in3)
+{
+  printf ("failure in %s (", name);
+  mpz_out_str (stdout, -16, in1);
+  if (in2 != NULL)
+    {
+      printf (" ");
+      mpz_out_str (stdout, -16, in2);
+    }
+  if (in3 != NULL)
+    {
+      printf (" ");
+      mpz_out_str (stdout, -16, in3);
+    }
+  printf (")\n");
+}
+
+void
+mpz_check_format (const mpz_t x)
+{
+  mp_size_t n = x ->_mp_size;
+  if (n < 0)
+    n = - n;
+
+  if (n > x->_mp_alloc)
+    {
+      fprintf (stderr, "mpz_t size exceeds allocation!\n");
+      abort ();
+    }
+
+  if (n > 0 && x->_mp_d[n-1] == 0)
+    {
+      fprintf (stderr, "Unnormalized mpz_t!\n");
+      abort ();
+    }
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-root.c b/third_party/gmp/mini-gmp/tests/t-root.c
new file mode 100644
index 0000000..1f46c43
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-root.c
@@ -0,0 +1,95 @@
+/*
+
+Copyright 2012, 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "testutils.h"
+
+#define MAXBITS 400
+#define COUNT 10000
+
+/* Called when s is supposed to be floor(root(u,z)), and r = u - s^z */
+static int
+rootrem_valid_p (const mpz_t u, const mpz_t s, const mpz_t r, unsigned long z)
+{
+  mpz_t t;
+
+  mpz_init (t);
+  if (mpz_fits_ulong_p (s))
+    mpz_ui_pow_ui (t, mpz_get_ui (s), z);
+  else
+    mpz_pow_ui (t, s, z);
+  mpz_sub (t, u, t);
+  if ((mpz_sgn (t) != mpz_sgn(u) && mpz_sgn (t) != 0) || mpz_cmp (t, r) != 0)
+    {
+      mpz_clear (t);
+      return 0;
+    }
+  if (mpz_sgn (s) > 0)
+    mpz_add_ui (t, s, 1);
+  else
+    mpz_sub_ui (t, s, 1);
+  mpz_pow_ui (t, t, z);
+  if (mpz_cmpabs (t, u) <= 0)
+    {
+      mpz_clear (t);
+      return 0;
+    }
+
+  mpz_clear (t);
+  return 1;
+}
+
+void
+testmain (int argc, char **argv)
+{
+  unsigned i;
+  unsigned long e;
+  mpz_t u, s, r, bs;
+
+  mpz_init (u);
+  mpz_init (s);
+  mpz_init (r);
+  mpz_init (bs);
+
+  for (i = 0; i < COUNT; i++)
+    {
+      mini_rrandomb (u, MAXBITS);
+      mini_rrandomb (bs, 12);
+      e = mpz_getlimbn (bs, 0) % mpz_sizeinbase (u, 2) + 1;
+      if ((e & 1) && (mpz_getlimbn (bs, 0) & (1L<<10)))
+	mpz_neg (u, u);
+      mpz_rootrem (s, r, u, e);
+
+      if (!rootrem_valid_p (u, s, r, e))
+	{
+	  fprintf (stderr, "mpz_rootrem(%lu-th) failed:\n", e);
+	  dump ("u", u);
+	  dump ("root", s);
+	  dump ("rem", r);
+	  abort ();
+	}
+    }
+  mpz_clear (bs);
+  mpz_clear (u);
+  mpz_clear (s);
+  mpz_clear (r);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-scan.c b/third_party/gmp/mini-gmp/tests/t-scan.c
new file mode 100644
index 0000000..39b1f35
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-scan.c
@@ -0,0 +1,90 @@
+/*
+
+Copyright 2012, Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "testutils.h"
+
+#define MAXBITS 400
+#define COUNT 10000
+
+void
+testmain (int argc, char **argv)
+{
+  unsigned i;
+  mpz_t a;
+  mp_bitcnt_t b, res, ref;
+
+  mpz_init (a);
+
+  for (i = 0; i < COUNT; i++)
+    {
+      mini_random_scan_op (OP_SCAN0, MAXBITS, a, &b, &ref);
+      res = mpz_scan0 (a, b);
+      if (res != ref)
+	{
+	  fprintf (stderr, "mpz_scan0 failed:\n");
+	  dump ("a", a);
+	  fprintf (stderr, "b: %lu\n", b);
+	  fprintf (stderr, "r: %lu\n", res);
+	  fprintf (stderr, "ref: %lu\n", ref);
+	  abort ();
+	}
+      if (mpz_sgn (a) > 0 && ref < mpz_sizeinbase (a, 2))
+	{
+	  res = mpn_scan0 (a->_mp_d, b);
+	  if (res != ref)
+	    {
+	      fprintf (stderr, "mpn_scan0 failed:\n");
+	      dump ("a", a);
+	      fprintf (stderr, "b: %lu\n", b);
+	      fprintf (stderr, "r: %lu\n", res);
+	      fprintf (stderr, "ref: %lu\n", ref);
+	      abort ();
+	    }
+	}
+      mini_random_scan_op (OP_SCAN1, MAXBITS, a, &b, &ref);
+      res = mpz_scan1 (a, b);
+      if (res != ref)
+	{
+	  fprintf (stderr, "mpz_scan1 failed:\n");
+	  dump ("a", a);
+	  fprintf (stderr, "b: %lu\n", b);
+	  fprintf (stderr, "r: %lu\n", res);
+	  fprintf (stderr, "ref: %lu\n", ref);
+	  abort ();
+	}
+      if (mpz_sgn (a) > 0 && ref != ~ (mp_bitcnt_t) 0)
+	{
+	  res = mpn_scan1 (a->_mp_d, b);
+	  if (res != ref)
+	    {
+	      fprintf (stderr, "mpn_scan1 failed:\n");
+	      dump ("a", a);
+	      fprintf (stderr, "b: %lu\n", b);
+	      fprintf (stderr, "r: %lu\n", res);
+	      fprintf (stderr, "ref: %lu\n", ref);
+	      abort ();
+	    }
+	}
+    }
+  mpz_clear (a);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-signed.c b/third_party/gmp/mini-gmp/tests/t-signed.c
new file mode 100644
index 0000000..e183944
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-signed.c
@@ -0,0 +1,205 @@
+/* Exercise some mpz_..._si functions.
+
+Copyright 2013, 2016 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "testutils.h"
+
+/* Always called with sz fitting in a signed long, and si is the
+   corresponding value. */
+int
+check_si (const mpz_t sz, long si)
+{
+  mpz_t t;
+
+  /* Checks on sz/si */
+  if ((mpz_cmp_si (sz, si)) != 0)
+    {
+      printf ("mpz_cmp_si (sz, %ld) != 0.\n", si);
+      return 0;
+    }
+  if (mpz_get_si (sz) != si)
+    {
+      printf ("mpz_get_si (sz) != %ld.\n", si);
+      return 0;
+    }
+
+  mpz_init_set_si (t, si);
+
+  if (mpz_cmp (t, sz) != 0)
+    {
+      printf ("mpz_init_set_si (%ld) failed.\n", si);
+      printf (" got="); mpz_out_str (stdout, 10, t); printf ("\n");
+      return 0;
+    }
+
+  mpz_clear (t);
+  return 1;
+}
+
+/* Called with mpz_cmp (sz, oz) == c. If sz fits in a signed long,
+   si is the coresponding value, and similarly for oz and oi. */
+void
+check_si_cmp (const mpz_t sz, const mpz_t oz, long si, long oi, int c)
+{
+  if (mpz_cmp (sz, oz) != c)
+    {
+      printf ("mpz_cmp (sz, oz) != %i.\n", c);
+      goto fail;
+    }
+
+  if (mpz_fits_slong_p (sz))
+    {
+      if (!check_si (sz, si))
+	goto fail;
+      if (mpz_cmp_si (oz, si) != -c)
+	{
+	  printf ("mpz_cmp_si (oz, %ld) != %i.\n", si, -c);
+	  goto fail;
+	}
+    }
+  else
+    {
+      if (mpz_cmp_si (sz, si) != c)
+	{
+	  printf ("mpz_cmp_si (sz, %ld) != %i.\n", si, c);
+	  goto fail;
+	}
+      if (mpz_cmp_si (sz, -c) != c)
+	{
+	  printf ("mpz_cmp_si (sz, %i) != %i.\n", -c, c);
+	  goto fail;
+	}
+    }
+  if (mpz_fits_slong_p (oz))
+    {
+      if (!check_si (oz, oi))
+	goto fail;
+      if (mpz_cmp_si (sz, oi) != c)
+	{
+	  printf ("mpz_cmp_si (sz, %ld) != %i.\n", oi, c);
+	  goto fail;
+	}
+    }
+  return;
+
+ fail:
+  printf (" sz="); mpz_out_str (stdout, 10, sz); printf ("\n");
+  printf (" si=%ld\n", si);
+  printf (" oz="); mpz_out_str (stdout, 10, oz); printf ("\n");
+  printf (" oi=%ld\n", si);
+  abort ();
+}
+
+void
+try_op_si (int c)
+{
+  long  si, oi;
+  mpz_t sz, oz;
+  unsigned overflow_count;
+
+  si = c;
+  mpz_init_set_si (sz, si);
+
+  oi = si;
+  mpz_init_set (oz, sz);
+
+  /* To get a few tests with operands straddling the border, don't
+     stop at the very first operand exceeding a signed long. */
+  for (overflow_count = 0; overflow_count < 10; )
+    {
+      /* c * 2^k */
+      mpz_mul_2exp (sz, sz, 1);
+      if (mpz_fits_slong_p (sz))
+	si *= 2;
+      else
+	overflow_count++;
+
+      check_si_cmp (sz, oz, si, oi, c);
+
+      /* c * (2^k + 1) */
+      if (c == -1)
+	mpz_sub_ui (oz, sz, 1);
+      else
+	mpz_add_ui (oz, sz, 1);
+      if (mpz_fits_slong_p (oz))
+	oi = si + c;
+      else
+	overflow_count++;
+      check_si_cmp (oz, sz, oi, si, c);
+
+      /* c * (2^K - 1) */
+      mpz_mul_si (oz, sz, 2*c);
+      if (c == -1)
+	mpz_ui_sub (oz, 1, oz); /* oz = sz * 2 + 1 */
+      else
+	mpz_sub_ui (oz, oz, 1); /* oz = sz * 2 - 1 */
+      if (mpz_fits_slong_p (oz))
+	oi = (si - c) * 2 + c;
+      else
+	overflow_count++;
+
+      check_si_cmp (oz, sz, oi, si, c);
+    };
+
+  mpz_clear (sz);
+  mpz_clear (oz);
+}
+
+void
+try_fits_slong_p (void)
+{
+  mpz_t x;
+  mpz_init_set_si (x, LONG_MAX);
+  if (!mpz_fits_slong_p (x))
+    {
+      printf ("mpz_fits_slong_p (LONG_MAX) false!\n");
+      abort ();
+    }
+  mpz_add_ui (x, x, 1);
+  if (mpz_fits_slong_p (x))
+    {
+      printf ("mpz_fits_slong_p (LONG_MAX + 1) true!\n");
+      abort ();
+    }
+  mpz_set_si (x, LONG_MIN);
+  if (!mpz_fits_slong_p (x))
+    {
+      printf ("mpz_fits_slong_p (LONG_MIN) false!\n");
+      abort ();
+    }
+  mpz_sub_ui (x, x, 1);
+  if (mpz_fits_slong_p (x))
+    {
+      printf ("mpz_fits_slong_p (LONG_MIN - 1) true!\n");
+      abort ();
+    }
+
+  mpz_clear (x);
+}
+
+void
+testmain (int argc, char *argv[])
+{
+  try_fits_slong_p ();
+  try_op_si (-1);
+  try_op_si (1);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-sqrt.c b/third_party/gmp/mini-gmp/tests/t-sqrt.c
new file mode 100644
index 0000000..dd4c83a
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-sqrt.c
@@ -0,0 +1,181 @@
+/*
+
+Copyright 2012, 2014, Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "testutils.h"
+
+#define MAXBITS 400
+#define COUNT 9000
+
+/* Called when s is supposed to be floor(sqrt(u)), and r = u - s^2 */
+static int
+sqrtrem_valid_p (const mpz_t u, const mpz_t s, const mpz_t r)
+{
+  mpz_t t;
+
+  mpz_init (t);
+  mpz_mul (t, s, s);
+  mpz_sub (t, u, t);
+  if (mpz_sgn (t) < 0 || mpz_cmp (t, r) != 0)
+    {
+      mpz_clear (t);
+      return 0;
+    }
+  mpz_add_ui (t, s, 1);
+  mpz_mul (t, t, t);
+  if (mpz_cmp (t, u) <= 0)
+    {
+      mpz_clear (t);
+      return 0;
+    }
+
+  mpz_clear (t);
+  return 1;
+}
+
+void
+mpz_mpn_sqrtrem (mpz_t s, mpz_t r, const mpz_t u)
+{
+  mp_limb_t *sp, *rp;
+  mp_size_t un, sn, ret;
+
+  un = mpz_size (u);
+
+  mpz_xor (s, s, u);
+  sn = (un + 1) / 2;
+  sp = mpz_limbs_write (s, sn + 1);
+  sp [sn] = 11;
+
+  if (un & 1)
+    rp = NULL; /* Exploits the fact that r already is correct. */
+  else {
+    mpz_add (r, u, s);
+    rp = mpz_limbs_write (r, un + 1);
+    rp [un] = 19;
+  }
+
+  ret = mpn_sqrtrem (sp, rp, mpz_limbs_read (u), un);
+
+  if (sp [sn] != 11)
+    {
+      fprintf (stderr, "mpn_sqrtrem buffer overrun on sp.\n");
+      abort ();
+    }
+  if (un & 1) {
+    if ((ret != 0) != (mpz_size (r) != 0)) {
+      fprintf (stderr, "mpn_sqrtrem wrong return value with NULL.\n");
+      abort ();
+    }
+  } else {
+    mpz_limbs_finish (r, ret);
+    if ((size_t) ret != mpz_size (r)) {
+      fprintf (stderr, "mpn_sqrtrem wrong return value.\n");
+      abort ();
+    }
+    if (rp [un] != 19)
+      {
+	fprintf (stderr, "mpn_sqrtrem buffer overrun on rp.\n");
+	abort ();
+      }
+  }
+
+  mpz_limbs_finish (s, (un + 1) / 2);
+}
+
+void
+testmain (int argc, char **argv)
+{
+  unsigned i;
+  mpz_t u, s, r;
+
+  mpz_init (s);
+  mpz_init (r);
+
+  mpz_init_set_si (u, -1);
+  if (mpz_perfect_square_p (u))
+    {
+      fprintf (stderr, "mpz_perfect_square_p failed on -1.\n");
+      abort ();
+    }
+
+  if (!mpz_perfect_square_p (s))
+    {
+      fprintf (stderr, "mpz_perfect_square_p failed on 0.\n");
+      abort ();
+    }
+
+  for (i = 0; i < COUNT; i++)
+    {
+      mini_rrandomb (u, MAXBITS - (i & 0xFF));
+      mpz_sqrtrem (s, r, u);
+
+      if (!sqrtrem_valid_p (u, s, r))
+	{
+	  fprintf (stderr, "mpz_sqrtrem failed:\n");
+	  dump ("u", u);
+	  dump ("sqrt", s);
+	  dump ("rem", r);
+	  abort ();
+	}
+
+      mpz_mpn_sqrtrem (s, r, u);
+
+      if (!sqrtrem_valid_p (u, s, r))
+	{
+	  fprintf (stderr, "mpn_sqrtrem failed:\n");
+	  dump ("u", u);
+	  dump ("sqrt", s);
+	  dump ("rem", r);
+	  abort ();
+	}
+
+      if (mpz_sgn (r) == 0) {
+	mpz_neg (u, u);
+	mpz_sub_ui (u, u, 1);
+      }
+
+      if ((mpz_sgn (u) <= 0 || (i & 1)) ?
+	  mpz_perfect_square_p (u) :
+	  mpn_perfect_square_p (mpz_limbs_read (u), mpz_size (u)))
+	{
+	  fprintf (stderr, "mp%s_perfect_square_p failed on non square:\n",
+		   (mpz_sgn (u) <= 0 || (i & 1)) ? "z" : "n");
+	  dump ("u", u);
+	  abort ();
+	}
+
+      mpz_mul (u, s, s);
+      if (!((mpz_sgn (u) <= 0 || (i & 1)) ?
+	    mpz_perfect_square_p (u) :
+	    mpn_perfect_square_p (mpz_limbs_read (u), mpz_size (u))))
+	{
+	  fprintf (stderr, "mp%s_perfect_square_p failed on square:\n",
+		   (mpz_sgn (u) <= 0 || (i & 1)) ? "z" : "n");
+	  dump ("u", u);
+	  abort ();
+	}
+
+    }
+  mpz_clear (u);
+  mpz_clear (s);
+  mpz_clear (r);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-str.c b/third_party/gmp/mini-gmp/tests/t-str.c
new file mode 100644
index 0000000..1e78676
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-str.c
@@ -0,0 +1,319 @@
+/*
+
+Copyright 2012-2014, 2016 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <assert.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "testutils.h"
+
+#define MAXBITS 400
+#define COUNT 2000
+
+#define GMP_LIMB_BITS (sizeof(mp_limb_t) * CHAR_BIT)
+#define MAXLIMBS ((MAXBITS + GMP_LIMB_BITS - 1) / GMP_LIMB_BITS)
+
+static void
+test_small (void)
+{
+  struct {
+    const char *input;
+    const char *decimal;
+  } data[] = {
+    { "183407", "183407" },
+    { " 763959", "763959 " },
+    { "9 81999", "981999" },
+    { "10\t7398 ", "107398" },
+    { "-9585 44", "-00958544" },
+    { "-0", "0000" },
+    { " -000  ", "0" },
+    { "0704436", "231710" },
+    /* Check the case of large number of leading zeros. */
+    { "0000000000000000000000000", "0000000000000000000000000" },
+    { "000000000000000000000000704436", "000000000000000000000000231710" },
+    { " 02503517", "689999" },
+    { "0 1312143", "365667" },
+    { "-03 274062", "-882738" },
+    { "012\t242", "005282" },
+    { "0b11010111110010001111", "883855" },
+    { " 0b11001010010100001", "103585" },
+    { "-0b101010110011101111", "-175343" },
+    { "0b 1111111011011100110", "521958" },
+    { "0b1 1111110111001000011", "1044035" },
+    { " 0x53dfc", "343548" },
+    { "0xfA019", "1024025" },
+    { "0x 642d1", "410321" },
+    { "0x5 8067", "360551" },
+    { "-0xd6Be6", "-879590" },
+    { "\t0B1110000100000000011", "460803" },
+    { "0B\t1111110010010100101", "517285" },
+    { "0B1\t010111101101110100", "359284" },
+    { "-0B101\t1001101111111001", "-367609" },
+    { "0B10001001010111110000", "562672" },
+    { "0Xe4B7e", "936830" },
+    { "0X1E4bf", "124095" },
+    { "-0Xfdb90", "-1039248" },
+    { "0X7fc47", "523335" },
+    { "0X8167c", "530044" },
+    /* Some invalid inputs */
+    { "", NULL },
+    { "0x", NULL },
+    { "0b", NULL },
+    { "0z", NULL },
+    { "-", NULL },
+    { "-0x ", NULL },
+    { "0|1", NULL },
+    { "4+4", NULL },
+    { "0ab", NULL },
+    { "10x0", NULL },
+    { "0xxab", NULL },
+    { "ab", NULL },
+    { "0%#", NULL },
+    { "$foo", NULL },
+    { NULL, NULL }
+  };
+  unsigned i;
+  mpz_t a, b;
+  mpz_init (b);
+
+  for (i = 0; data[i].input; i++)
+    {
+      int res = mpz_init_set_str (a, data[i].input, 0);
+      if (data[i].decimal)
+	{
+	  if (res != 0)
+	    {
+	      fprintf (stderr, "mpz_set_str returned -1, input: %s\n",
+		       data[i].input);
+	      abort ();
+	    }
+	  if (mpz_set_str (b, data[i].decimal, 10) != 0)
+	    {
+	      fprintf (stderr, "mpz_set_str returned -1, decimal input: %s\n",
+		       data[i].input);
+	      abort ();
+	    }
+	  if (mpz_cmp (a, b) != 0)
+	    {
+	      fprintf (stderr, "mpz_set_str failed for input: %s\n",
+		       data[i].input);
+
+	      dump ("got", a);
+	      dump ("ref", b);
+	      abort ();
+	    }
+	}
+      else if (res != -1)
+	{
+	  fprintf (stderr, "mpz_set_str returned %d, invalid input: %s\n",
+		   res, data[i].input);
+	  abort ();
+	}
+      mpz_clear (a);
+    }
+
+  mpz_clear (b);
+}
+
+void
+testmain (int argc, char **argv)
+{
+  unsigned i;
+  char *ap;
+  char *bp;
+  char *rp;
+  size_t bn, rn, arn;
+
+  mpz_t a, b;
+
+  FILE *tmp;
+
+  test_small ();
+
+  mpz_init (a);
+  mpz_init (b);
+
+  tmp = tmpfile ();
+  if (!tmp)
+    fprintf (stderr,
+	     "Failed to create temporary file. Skipping mpz_out_str tests.\n");
+
+  for (i = 0; i < COUNT; i++)
+    {
+      int base;
+      for (base = 0; base <= 62; base += 1 + (base == 0))
+	{
+	  hex_random_str_op (MAXBITS, (i&1 || base > 36) ? base: -base, &ap, &rp);
+	  if (mpz_set_str (a, ap, 16) != 0)
+	    {
+	      fprintf (stderr, "mpz_set_str failed on input %s\n", ap);
+	      abort ();
+	    }
+
+	  rn = strlen (rp);
+	  arn = rn - (rp[0] == '-');
+
+	  bn = mpz_sizeinbase (a, base ? base : 10);
+	  if (bn < arn || bn > (arn + 1))
+	    {
+	      fprintf (stderr, "mpz_sizeinbase failed:\n");
+	      dump ("a", a);
+	      fprintf (stderr, "r = %s\n", rp);
+	      fprintf (stderr, "  base %d, correct size %u, got %u\n",
+		       base, (unsigned) arn, (unsigned)bn);
+	      abort ();
+	    }
+	  bp = mpz_get_str (NULL, (i&1 || base > 36) ? base: -base, a);
+	  if (strcmp (bp, rp))
+	    {
+	      fprintf (stderr, "mpz_get_str failed:\n");
+	      dump ("a", a);
+	      fprintf (stderr, "b = %s\n", bp);
+	      fprintf (stderr, "  base = %d\n", base);
+	      fprintf (stderr, "r = %s\n", rp);
+	      abort ();
+	    }
+
+	  /* Just a few tests with file i/o. */
+	  if (tmp && i < 20)
+	    {
+	      size_t tn;
+	      rewind (tmp);
+	      tn = mpz_out_str (tmp, (i&1 || base > 36) ? base: -base, a);
+	      if (tn != rn)
+		{
+		  fprintf (stderr, "mpz_out_str, bad return value:\n");
+		  dump ("a", a);
+		  fprintf (stderr, "r = %s\n", rp);
+		  fprintf (stderr, "  base %d, correct size %u, got %u\n",
+			   base, (unsigned) rn, (unsigned)tn);
+		  abort ();
+		}
+	      rewind (tmp);
+	      memset (bp, 0, rn);
+	      tn = fread (bp, 1, rn, tmp);
+	      if (tn != rn)
+		{
+		  fprintf (stderr,
+			   "fread failed, expected %lu bytes, got only %lu.\n",
+			   (unsigned long) rn, (unsigned long) tn);
+		  abort ();
+		}
+
+	      if (memcmp (bp, rp, rn) != 0)
+		{
+		  fprintf (stderr, "mpz_out_str failed:\n");
+		  dump ("a", a);
+		  fprintf (stderr, "b = %s\n", bp);
+		  fprintf (stderr, "  base = %d\n", base);
+		  fprintf (stderr, "r = %s\n", rp);
+		  abort ();
+		}
+	    }
+
+	  mpz_set_str (b, rp, base);
+
+	  if (mpz_cmp (a, b))
+	    {
+	      fprintf (stderr, "mpz_set_str failed:\n");
+	      fprintf (stderr, "r = %s\n", rp);
+	      fprintf (stderr, "  base = %d\n", base);
+	      fprintf (stderr, "r = %s\n", ap);
+	      fprintf (stderr, "  base = 16\n");
+	      dump ("b", b);
+	      dump ("r", a);
+	      abort ();
+	    }
+
+	  /* Test mpn interface */
+	  if (base && mpz_sgn (a))
+	    {
+	      size_t i;
+	      const char *absr;
+	      mp_limb_t t[MAXLIMBS];
+	      size_t tn = mpz_size (a);
+
+	      assert (tn <= MAXLIMBS);
+	      mpn_copyi (t, a->_mp_d, tn);
+
+	      bn = mpn_get_str ((unsigned char *) bp, base, t, tn);
+	      if (bn != arn)
+		{
+		  fprintf (stderr, "mpn_get_str failed:\n");
+		  fprintf (stderr, "returned length: %lu (bad)\n", (unsigned long) bn);
+		  fprintf (stderr, "expected: %lu\n", (unsigned long) arn);
+		  fprintf (stderr, "  base = %d\n", base);
+		  fprintf (stderr, "r = %s\n", ap);
+		  fprintf (stderr, "  base = 16\n");
+		  dump ("b", b);
+		  dump ("r", a);
+		  abort ();
+		}
+	      absr = rp + (rp[0] == '-');
+
+	      for (i = 0; i < bn; i++)
+		{
+		  unsigned char digit = absr[i];
+		  char value;
+		  if (digit >= '0' && digit <= '9')
+		    value = digit - '0';
+		  else if (digit >= 'a' && digit <= 'z')
+		    value = digit - 'a' + ((base > 36) ? 36 : 10);
+		  else if (digit >= 'A' && digit <= 'Z')
+		    value = digit - 'A' + 10;
+		  else
+		    {
+		      fprintf (stderr, "Internal error in test.\n");
+		      abort();
+		    }
+		  if (bp[i] != value)
+		    {
+		      fprintf (stderr, "mpn_get_str failed:\n");
+		      fprintf (stderr, "digit %lu: %d (bad)\n", (unsigned long) i, bp[i]);
+		      fprintf (stderr, "expected: %d\n", value);
+		      fprintf (stderr, "  base = %d\n", base);
+		      fprintf (stderr, "r = %s\n", ap);
+		      fprintf (stderr, "  base = 16\n");
+		      dump ("b", b);
+		      dump ("r", a);
+		      abort ();
+		    }
+		}
+	      tn = mpn_set_str (t, (unsigned char *) bp, bn, base);
+	      if (tn != mpz_size (a) || mpn_cmp (t, a->_mp_d, tn))
+		{
+		  fprintf (stderr, "mpn_set_str failed:\n");
+		  fprintf (stderr, "r = %s\n", rp);
+		  fprintf (stderr, "  base = %d\n", base);
+		  fprintf (stderr, "r = %s\n", ap);
+		  fprintf (stderr, "  base = 16\n");
+		  dump ("r", a);
+		  abort ();
+		}
+	    }
+	  free (ap);
+	  free (rp);
+	  testfree (bp);
+	}
+    }
+  mpz_clear (a);
+  mpz_clear (b);
+}
diff --git a/third_party/gmp/mini-gmp/tests/t-sub.c b/third_party/gmp/mini-gmp/tests/t-sub.c
new file mode 100644
index 0000000..e230fda
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/t-sub.c
@@ -0,0 +1,71 @@
+/*
+
+Copyright 2012, 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "testutils.h"
+
+#define MAXBITS 400
+#define COUNT 10000
+
+void
+testmain (int argc, char **argv)
+{
+  unsigned i;
+  mpz_t a, b, res, res_ui, ref;
+
+  mpz_init (a);
+  mpz_init (b);
+  mpz_init (res);
+  mpz_init (res_ui);
+  mpz_init (ref);
+
+  for (i = 0; i < COUNT; i++)
+    {
+      mini_random_op3 (OP_SUB, MAXBITS, a, b, ref);
+      mpz_sub (res, a, b);
+      if (mpz_cmp (res, ref))
+	{
+	  fprintf (stderr, "mpz_sub failed:\n");
+	  dump ("a", a);
+	  dump ("b", b);
+	  dump ("r", res);
+	  dump ("ref", ref);
+	  abort ();
+	}
+      if (mpz_fits_ulong_p (a)) {
+	mpz_ui_sub (res_ui, mpz_get_ui (a), b);
+	if (mpz_cmp (res_ui, ref))
+	  {
+	    fprintf (stderr, "mpz_ui_sub failed:\n");
+	    dump ("a", a);
+	    dump ("b", b);
+	    dump ("r", res_ui);
+	    dump ("ref", ref);
+	    abort ();
+	  }
+      }
+    }
+  mpz_clear (a);
+  mpz_clear (b);
+  mpz_clear (res);
+  mpz_clear (res_ui);
+  mpz_clear (ref);
+}
diff --git a/third_party/gmp/mini-gmp/tests/testutils.c b/third_party/gmp/mini-gmp/tests/testutils.c
new file mode 100644
index 0000000..b131a9e
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/testutils.c
@@ -0,0 +1,181 @@
+/*
+
+Copyright 2013-2015, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "testutils.h"
+
+/* Include it here, so we we could tweak, e.g., how MPZ_REALLOC
+   works. */
+#include "../mini-gmp.c"
+#include "../mini-mpq.c"
+
+static size_t total_alloc = 0;
+
+/* Custom memory allocation to track memory usage, and add a small red
+   zone.
+
+   About alignment: In general, getting a block from malloc, and
+   incrementing it by sizeof(size_t), like we do here, might give a
+   pointer which is not properly aligned for all types. But the
+   largest type we allocate space for is unsigned long (mp_limb_t),
+   which shouldn't have stricter alignment requirements than
+   size_t. */
+
+static unsigned char block_end[8] =
+  { 0x7c, 0x37, 0xd6, 0x12, 0xa8, 0x6c, 0x01, 0xd1 };
+
+static void *
+block_init (size_t *block, size_t size)
+{
+  char *p;
+  *block++ = size;
+
+  p = (char *) block;
+  memcpy (p + size, block_end, sizeof(block_end));
+
+  total_alloc += size;
+  return p;
+}
+
+/* Check small redzone, return pointer to malloced block. */
+static size_t *
+block_check  (void *p)
+{
+  size_t *block = (size_t *) p - 1;
+  size_t size = block[0];
+
+  if (memcmp ((char *)p + size, block_end, sizeof(block_end)) != 0)
+    {
+      fprintf (stderr, "red zone overwritten.\n");
+      abort ();
+    }
+  total_alloc -= size;
+  return block;
+}
+
+static void *
+tu_alloc (size_t size)
+{
+  size_t *block = (size_t *) malloc (sizeof(size_t) + size + sizeof(block_end));
+  if (!block)
+    {
+      fprintf (stderr, "Virtual memory exhausted.\n");
+      abort ();
+    }
+
+  return block_init (block, size);
+}
+
+static void *
+tu_realloc (void *p, size_t old_size, size_t new_size)
+{
+  size_t *block = block_check (p);
+  block = (size_t *) realloc (block, sizeof(size_t) + new_size + sizeof(block_end));
+  if (!block)
+    {
+      fprintf (stderr, "Virtual memory exhausted.\n");
+      abort ();
+    }
+
+  return block_init (block, new_size);
+}
+
+static void
+tu_free (void *p, size_t old_size)
+{
+  free (block_check (p));
+}
+
+/* Free memory allocated via mini-gmp allocation function. */
+void
+testfree (void *p)
+{
+  void (*freefunc) (void *, size_t);
+  mp_get_memory_functions (NULL, NULL, &freefunc);
+
+  freefunc (p, 0);
+}
+
+int
+main (int argc, char **argv)
+{
+  hex_random_init ();
+
+  mp_set_memory_functions (tu_alloc, tu_realloc, tu_free);
+
+  /* Currently, t-comb seems to be the only program accepting any
+     arguments. It might make sense to parse common arguments here. */
+  testmain (argc, argv);
+
+  if (total_alloc != 0)
+    {
+      fprintf (stderr, "Memory leaked: %lu bytes.\n",
+	       (unsigned long) total_alloc);
+      abort ();
+    }
+  return 0;
+}
+
+void
+testhalves (int count, void (*tested_fun) (int))
+{
+  void (*freefunc) (void *, size_t);
+  void *(*reallocfunc) (void *, size_t, size_t);
+  void *(*allocfunc) (size_t);
+  size_t initial_alloc;
+
+  mp_get_memory_functions (&allocfunc, &reallocfunc, &freefunc);
+  initial_alloc = total_alloc;
+  (*tested_fun) (count / 2);
+  if (initial_alloc != total_alloc)
+    {
+      fprintf (stderr, "First half, memory leaked: %lu bytes.\n",
+	       (unsigned long) total_alloc - initial_alloc);
+      abort ();
+    }
+  mp_set_memory_functions (NULL, NULL, NULL);
+  (*tested_fun) (count / 2);
+  mp_set_memory_functions (allocfunc, reallocfunc, freefunc);
+}
+
+void
+dump (const char *label, const mpz_t x)
+{
+  char *buf = mpz_get_str (NULL, 16, x);
+  fprintf (stderr, "%s: %s\n", label, buf);
+  testfree (buf);
+}
+
+void
+mpz_set_str_or_abort (mpz_ptr z, const char *str, int base)
+{
+  if (mpz_set_str (z, str, base) != 0)
+    {
+      fprintf (stderr, "ERROR: mpz_set_str failed\n");
+      fprintf (stderr, "   str  = \"%s\"\n", str);
+      fprintf (stderr, "   base = %d\n", base);
+      abort();
+    }
+}
+
+int
+mpz_lucas_mod (mpz_t V, mpz_t Qk, long Q,
+	       mp_bitcnt_t b0, const mpz_t n)
+{
+  return gmp_lucas_mod (V, Qk, Q, b0, n);
+}
diff --git a/third_party/gmp/mini-gmp/tests/testutils.h b/third_party/gmp/mini-gmp/tests/testutils.h
new file mode 100644
index 0000000..e565ac3
--- /dev/null
+++ b/third_party/gmp/mini-gmp/tests/testutils.h
@@ -0,0 +1,42 @@
+/*
+
+Copyright 2013, 2014, 2018, Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "mini-random.h"
+
+#define numberof(x)  (sizeof (x) / sizeof ((x)[0]))
+
+void testmain (int argc, char **argv);
+
+void testhalves (int count, void (*tested_fun) (int));
+
+void testfree (void *p);
+
+void
+dump (const char *label, const mpz_t x);
+
+void
+mpz_set_str_or_abort (mpz_ptr z, const char *str, int base);
+
+/* Prototype for wrappers to internal functions to be tested. */
+int
+mpz_lucas_mod (mpz_t V, mpz_t Qk, long Q,
+	       mp_bitcnt_t b0, const mpz_t n);
diff --git a/third_party/gmp/missing b/third_party/gmp/missing
new file mode 100755
index 0000000..f62bbae
--- /dev/null
+++ b/third_party/gmp/missing
@@ -0,0 +1,215 @@
+#! /bin/sh
+# Common wrapper for a few potentially missing GNU programs.
+
+scriptversion=2013-10-28.13; # UTC
+
+# Copyright (C) 1996-2014 Free Software Foundation, Inc.
+# Originally written by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+if test $# -eq 0; then
+  echo 1>&2 "Try '$0 --help' for more information"
+  exit 1
+fi
+
+case $1 in
+
+  --is-lightweight)
+    # Used by our autoconf macros to check whether the available missing
+    # script is modern enough.
+    exit 0
+    ;;
+
+  --run)
+    # Back-compat with the calling convention used by older automake.
+    shift
+    ;;
+
+  -h|--h|--he|--hel|--help)
+    echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due
+to PROGRAM being missing or too old.
+
+Options:
+  -h, --help      display this help and exit
+  -v, --version   output version information and exit
+
+Supported PROGRAM values:
+  aclocal   autoconf  autoheader   autom4te  automake  makeinfo
+  bison     yacc      flex         lex       help2man
+
+Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and
+'g' are ignored when checking the name.
+
+Send bug reports to <bug-automake@gnu.org>."
+    exit $?
+    ;;
+
+  -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+    echo "missing $scriptversion (GNU Automake)"
+    exit $?
+    ;;
+
+  -*)
+    echo 1>&2 "$0: unknown '$1' option"
+    echo 1>&2 "Try '$0 --help' for more information"
+    exit 1
+    ;;
+
+esac
+
+# Run the given program, remember its exit status.
+"$@"; st=$?
+
+# If it succeeded, we are done.
+test $st -eq 0 && exit 0
+
+# Also exit now if we it failed (or wasn't found), and '--version' was
+# passed; such an option is passed most likely to detect whether the
+# program is present and works.
+case $2 in --version|--help) exit $st;; esac
+
+# Exit code 63 means version mismatch.  This often happens when the user
+# tries to use an ancient version of a tool on a file that requires a
+# minimum version.
+if test $st -eq 63; then
+  msg="probably too old"
+elif test $st -eq 127; then
+  # Program was missing.
+  msg="missing on your system"
+else
+  # Program was found and executed, but failed.  Give up.
+  exit $st
+fi
+
+perl_URL=http://www.perl.org/
+flex_URL=http://flex.sourceforge.net/
+gnu_software_URL=http://www.gnu.org/software
+
+program_details ()
+{
+  case $1 in
+    aclocal|automake)
+      echo "The '$1' program is part of the GNU Automake package:"
+      echo "<$gnu_software_URL/automake>"
+      echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:"
+      echo "<$gnu_software_URL/autoconf>"
+      echo "<$gnu_software_URL/m4/>"
+      echo "<$perl_URL>"
+      ;;
+    autoconf|autom4te|autoheader)
+      echo "The '$1' program is part of the GNU Autoconf package:"
+      echo "<$gnu_software_URL/autoconf/>"
+      echo "It also requires GNU m4 and Perl in order to run:"
+      echo "<$gnu_software_URL/m4/>"
+      echo "<$perl_URL>"
+      ;;
+  esac
+}
+
+give_advice ()
+{
+  # Normalize program name to check for.
+  normalized_program=`echo "$1" | sed '
+    s/^gnu-//; t
+    s/^gnu//; t
+    s/^g//; t'`
+
+  printf '%s\n' "'$1' is $msg."
+
+  configure_deps="'configure.ac' or m4 files included by 'configure.ac'"
+  case $normalized_program in
+    autoconf*)
+      echo "You should only need it if you modified 'configure.ac',"
+      echo "or m4 files included by it."
+      program_details 'autoconf'
+      ;;
+    autoheader*)
+      echo "You should only need it if you modified 'acconfig.h' or"
+      echo "$configure_deps."
+      program_details 'autoheader'
+      ;;
+    automake*)
+      echo "You should only need it if you modified 'Makefile.am' or"
+      echo "$configure_deps."
+      program_details 'automake'
+      ;;
+    aclocal*)
+      echo "You should only need it if you modified 'acinclude.m4' or"
+      echo "$configure_deps."
+      program_details 'aclocal'
+      ;;
+   autom4te*)
+      echo "You might have modified some maintainer files that require"
+      echo "the 'autom4te' program to be rebuilt."
+      program_details 'autom4te'
+      ;;
+    bison*|yacc*)
+      echo "You should only need it if you modified a '.y' file."
+      echo "You may want to install the GNU Bison package:"
+      echo "<$gnu_software_URL/bison/>"
+      ;;
+    lex*|flex*)
+      echo "You should only need it if you modified a '.l' file."
+      echo "You may want to install the Fast Lexical Analyzer package:"
+      echo "<$flex_URL>"
+      ;;
+    help2man*)
+      echo "You should only need it if you modified a dependency" \
+           "of a man page."
+      echo "You may want to install the GNU Help2man package:"
+      echo "<$gnu_software_URL/help2man/>"
+    ;;
+    makeinfo*)
+      echo "You should only need it if you modified a '.texi' file, or"
+      echo "any other file indirectly affecting the aspect of the manual."
+      echo "You might want to install the Texinfo package:"
+      echo "<$gnu_software_URL/texinfo/>"
+      echo "The spurious makeinfo call might also be the consequence of"
+      echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might"
+      echo "want to install GNU make:"
+      echo "<$gnu_software_URL/make/>"
+      ;;
+    *)
+      echo "You might have modified some files without having the proper"
+      echo "tools for further handling them.  Check the 'README' file, it"
+      echo "often tells you about the needed prerequisites for installing"
+      echo "this package.  You may also peek at any GNU archive site, in"
+      echo "case some other package contains this missing '$1' program."
+      ;;
+  esac
+}
+
+give_advice "$1" | sed -e '1s/^/WARNING: /' \
+                       -e '2,$s/^/         /' >&2
+
+# Propagate the correct exit status (expected to be 127 for a program
+# not found, 63 for a program that failed due to version mismatch).
+exit $st
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/third_party/gmp/mp_bpl.c b/third_party/gmp/mp_bpl.c
new file mode 100644
index 0000000..a13fb15
--- /dev/null
+++ b/third_party/gmp/mp_bpl.c
@@ -0,0 +1,34 @@
+/*
+Copyright 1996 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+const int mp_bits_per_limb = GMP_LIMB_BITS;
+const int __gmp_0 = 0;
+int __gmp_junk;
diff --git a/third_party/gmp/mp_clz_tab.c b/third_party/gmp/mp_clz_tab.c
new file mode 100644
index 0000000..fc7cb0b
--- /dev/null
+++ b/third_party/gmp/mp_clz_tab.c
@@ -0,0 +1,48 @@
+/* __clz_tab -- support for longlong.h
+
+   THE CONTENTS OF THIS FILE ARE FOR INTERNAL USE AND MAY CHANGE
+   INCOMPATIBLY OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 1991, 1993, 1994, 1996, 1997, 2000, 2001 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#ifdef COUNT_LEADING_ZEROS_NEED_CLZ_TAB
+const
+unsigned char __clz_tab[129] =
+{
+  1,2,3,3,4,4,4,4,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
+  7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+  8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+  8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
+  9
+};
+#endif
diff --git a/third_party/gmp/mp_dv_tab.c b/third_party/gmp/mp_dv_tab.c
new file mode 100644
index 0000000..cd09d5d
--- /dev/null
+++ b/third_party/gmp/mp_dv_tab.c
@@ -0,0 +1,77 @@
+/* __gmp_digit_value_tab -- support for mp*_set_str
+
+   THE CONTENTS OF THIS FILE ARE FOR INTERNAL USE AND MAY CHANGE
+   INCOMPATIBLY OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2003, 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/* Table to be indexed by character, to get its numerical value.  Assumes ASCII
+   character set.
+
+   First part of table supports common usages, where 'A' and 'a' have the same
+   value; this supports bases 2..36
+
+   At offset 208, values for bases 37..62 start.  Here, 'A' has the value 10
+   (in decimal) and 'a' has the value 36.  */
+
+#define X 0xff
+const unsigned char __gmp_digit_value_tab[] =
+{
+  X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
+  X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
+  X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
+  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, X, X, X, X, X, X,
+  X,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,X, X, X, X, X,
+  X,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,X, X, X, X, X,
+  X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
+  X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
+  X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
+  X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
+  X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
+  X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
+  X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
+  X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
+  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, X, X, X, X, X, X,
+  X,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,X, X, X, X, X,
+  X,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,X, X, X, X, X,
+  X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
+  X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
+  X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
+  X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
+  X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
+  X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
+  X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,
+  X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X
+};
diff --git a/third_party/gmp/mp_get_fns.c b/third_party/gmp/mp_get_fns.c
new file mode 100644
index 0000000..70ed96d
--- /dev/null
+++ b/third_party/gmp/mp_get_fns.c
@@ -0,0 +1,47 @@
+/* mp_get_memory_functions -- Get the allocate, reallocate, and free functions.
+
+Copyright 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>  /* for NULL */
+#include "gmp-impl.h"
+
+void
+mp_get_memory_functions (void *(**alloc_func) (size_t),
+			 void *(**realloc_func) (void *, size_t, size_t),
+			 void (**free_func) (void *, size_t)) __GMP_NOTHROW
+{
+  if (alloc_func != NULL)
+    *alloc_func = __gmp_allocate_func;
+
+  if (realloc_func != NULL)
+    *realloc_func = __gmp_reallocate_func;
+
+  if (free_func != NULL)
+    *free_func = __gmp_free_func;
+}
diff --git a/third_party/gmp/mp_minv_tab.c b/third_party/gmp/mp_minv_tab.c
new file mode 100644
index 0000000..833d4c1
--- /dev/null
+++ b/third_party/gmp/mp_minv_tab.c
@@ -0,0 +1,58 @@
+/* A table of data supporting binvert_limb().
+
+   THE CONTENTS OF THIS FILE ARE FOR INTERNAL USE AND MAY CHANGE
+   INCOMPATIBLY OR DISAPPEAR IN A FUTURE GNU MP RELEASE.  */
+
+/*
+Copyright 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* binvert_limb_table[i] is the multiplicative inverse of 2*i+1 mod 256,
+   ie. (binvert_limb_table[i] * (2*i+1)) % 256 == 1 */
+
+const unsigned char  binvert_limb_table[128] = {
+  0x01, 0xAB, 0xCD, 0xB7, 0x39, 0xA3, 0xC5, 0xEF,
+  0xF1, 0x1B, 0x3D, 0xA7, 0x29, 0x13, 0x35, 0xDF,
+  0xE1, 0x8B, 0xAD, 0x97, 0x19, 0x83, 0xA5, 0xCF,
+  0xD1, 0xFB, 0x1D, 0x87, 0x09, 0xF3, 0x15, 0xBF,
+  0xC1, 0x6B, 0x8D, 0x77, 0xF9, 0x63, 0x85, 0xAF,
+  0xB1, 0xDB, 0xFD, 0x67, 0xE9, 0xD3, 0xF5, 0x9F,
+  0xA1, 0x4B, 0x6D, 0x57, 0xD9, 0x43, 0x65, 0x8F,
+  0x91, 0xBB, 0xDD, 0x47, 0xC9, 0xB3, 0xD5, 0x7F,
+  0x81, 0x2B, 0x4D, 0x37, 0xB9, 0x23, 0x45, 0x6F,
+  0x71, 0x9B, 0xBD, 0x27, 0xA9, 0x93, 0xB5, 0x5F,
+  0x61, 0x0B, 0x2D, 0x17, 0x99, 0x03, 0x25, 0x4F,
+  0x51, 0x7B, 0x9D, 0x07, 0x89, 0x73, 0x95, 0x3F,
+  0x41, 0xEB, 0x0D, 0xF7, 0x79, 0xE3, 0x05, 0x2F,
+  0x31, 0x5B, 0x7D, 0xE7, 0x69, 0x53, 0x75, 0x1F,
+  0x21, 0xCB, 0xED, 0xD7, 0x59, 0xC3, 0xE5, 0x0F,
+  0x11, 0x3B, 0x5D, 0xC7, 0x49, 0x33, 0x55, 0xFF
+};
diff --git a/third_party/gmp/mp_set_fns.c b/third_party/gmp/mp_set_fns.c
new file mode 100644
index 0000000..b7bcd5b
--- /dev/null
+++ b/third_party/gmp/mp_set_fns.c
@@ -0,0 +1,49 @@
+/* mp_set_memory_functions -- Set the allocate, reallocate, and free functions
+   for use by the mp package.
+
+Copyright 1991, 1993, 1994, 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mp_set_memory_functions (void *(*alloc_func) (size_t),
+			 void *(*realloc_func) (void *, size_t, size_t),
+			 void (*free_func) (void *, size_t)) __GMP_NOTHROW
+{
+  if (alloc_func == 0)
+    alloc_func = __gmp_default_allocate;
+  if (realloc_func == 0)
+    realloc_func = __gmp_default_reallocate;
+  if (free_func == 0)
+    free_func = __gmp_default_free;
+
+  __gmp_allocate_func = alloc_func;
+  __gmp_reallocate_func = realloc_func;
+  __gmp_free_func = free_func;
+}
diff --git a/third_party/gmp/mpf/Makefile.am b/third_party/gmp/mpf/Makefile.am
new file mode 100644
index 0000000..ff7e48f
--- /dev/null
+++ b/third_party/gmp/mpf/Makefile.am
@@ -0,0 +1,47 @@
+## Process this file with automake to generate Makefile.in
+
+# Copyright 1996, 1998-2002 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+
+AM_CPPFLAGS = -D__GMP_WITHIN_GMP -I$(top_srcdir)
+
+noinst_LTLIBRARIES = libmpf.la
+libmpf_la_SOURCES = \
+  init.c init2.c inits.c set.c set_ui.c set_si.c set_str.c set_d.c set_z.c \
+  set_q.c iset.c iset_ui.c iset_si.c iset_str.c iset_d.c clear.c clears.c \
+  get_str.c dump.c size.c eq.c reldiff.c sqrt.c random2.c inp_str.c out_str.c \
+  add.c add_ui.c sub.c sub_ui.c ui_sub.c mul.c mul_ui.c div.c div_ui.c \
+  cmp.c cmp_d.c cmp_z.c cmp_si.c cmp_ui.c mul_2exp.c div_2exp.c abs.c neg.c get_d.c \
+  get_d_2exp.c set_dfl_prec.c set_prc.c set_prc_raw.c get_dfl_prec.c get_prc.c \
+  ui_div.c sqrt_ui.c \
+  pow_ui.c urandomb.c swap.c get_si.c get_ui.c int_p.c \
+  ceilfloor.c trunc.c \
+  fits_sint.c fits_slong.c fits_sshort.c \
+  fits_uint.c fits_ulong.c fits_ushort.c \
+  fits_s.h fits_u.h
diff --git a/third_party/gmp/mpf/Makefile.in b/third_party/gmp/mpf/Makefile.in
new file mode 100644
index 0000000..8acf389
--- /dev/null
+++ b/third_party/gmp/mpf/Makefile.in
@@ -0,0 +1,662 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Copyright 1996, 1998-2002 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = mpf
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libmpf_la_LIBADD =
+am_libmpf_la_OBJECTS = init.lo init2.lo inits.lo set.lo set_ui.lo \
+	set_si.lo set_str.lo set_d.lo set_z.lo set_q.lo iset.lo \
+	iset_ui.lo iset_si.lo iset_str.lo iset_d.lo clear.lo clears.lo \
+	get_str.lo dump.lo size.lo eq.lo reldiff.lo sqrt.lo random2.lo \
+	inp_str.lo out_str.lo add.lo add_ui.lo sub.lo sub_ui.lo \
+	ui_sub.lo mul.lo mul_ui.lo div.lo div_ui.lo cmp.lo cmp_d.lo \
+	cmp_z.lo cmp_si.lo cmp_ui.lo mul_2exp.lo div_2exp.lo abs.lo \
+	neg.lo get_d.lo get_d_2exp.lo set_dfl_prec.lo set_prc.lo \
+	set_prc_raw.lo get_dfl_prec.lo get_prc.lo ui_div.lo sqrt_ui.lo \
+	pow_ui.lo urandomb.lo swap.lo get_si.lo get_ui.lo int_p.lo \
+	ceilfloor.lo trunc.lo fits_sint.lo fits_slong.lo \
+	fits_sshort.lo fits_uint.lo fits_ulong.lo fits_ushort.lo
+libmpf_la_OBJECTS = $(am_libmpf_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp =
+am__depfiles_maybe =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+SOURCES = $(libmpf_la_SOURCES)
+DIST_SOURCES = $(libmpf_la_SOURCES)
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ABI = @ABI@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+ASMFLAGS = @ASMFLAGS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CALLING_CONVENTIONS_OBJS = @CALLING_CONVENTIONS_OBJS@
+CC = @CC@
+CCAS = @CCAS@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPP_FOR_BUILD = @CPP_FOR_BUILD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFN_LONG_LONG_LIMB = @DEFN_LONG_LONG_LIMB@
+DEFS = @DEFS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@
+FGREP = @FGREP@
+GMP_LDFLAGS = @GMP_LDFLAGS@
+GMP_LIMB_BITS = @GMP_LIMB_BITS@
+GMP_NAIL_BITS = @GMP_NAIL_BITS@
+GREP = @GREP@
+HAVE_CLOCK_01 = @HAVE_CLOCK_01@
+HAVE_CPUTIME_01 = @HAVE_CPUTIME_01@
+HAVE_GETRUSAGE_01 = @HAVE_GETRUSAGE_01@
+HAVE_GETTIMEOFDAY_01 = @HAVE_GETTIMEOFDAY_01@
+HAVE_HOST_CPU_FAMILY_power = @HAVE_HOST_CPU_FAMILY_power@
+HAVE_HOST_CPU_FAMILY_powerpc = @HAVE_HOST_CPU_FAMILY_powerpc@
+HAVE_SIGACTION_01 = @HAVE_SIGACTION_01@
+HAVE_SIGALTSTACK_01 = @HAVE_SIGALTSTACK_01@
+HAVE_SIGSTACK_01 = @HAVE_SIGSTACK_01@
+HAVE_STACK_T_01 = @HAVE_STACK_T_01@
+HAVE_SYS_RESOURCE_H_01 = @HAVE_SYS_RESOURCE_H_01@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCURSES = @LIBCURSES@
+LIBGMPXX_LDFLAGS = @LIBGMPXX_LDFLAGS@
+LIBGMP_DLL = @LIBGMP_DLL@
+LIBGMP_LDFLAGS = @LIBGMP_LDFLAGS@
+LIBM = @LIBM@
+LIBM_FOR_BUILD = @LIBM_FOR_BUILD@
+LIBOBJS = @LIBOBJS@
+LIBREADLINE = @LIBREADLINE@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+M4 = @M4@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPEED_CYCLECOUNTER_OBJ = @SPEED_CYCLECOUNTER_OBJ@
+STRIP = @STRIP@
+TAL_OBJECT = @TAL_OBJECT@
+TUNE_LIBS = @TUNE_LIBS@
+TUNE_SQR_OBJ = @TUNE_SQR_OBJ@
+U_FOR_BUILD = @U_FOR_BUILD@
+VERSION = @VERSION@
+WITH_READLINE_01 = @WITH_READLINE_01@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__leading_dot = @am__leading_dot@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gmp_srclinks = @gmp_srclinks@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+mpn_objects = @mpn_objects@
+mpn_objs_in_libgmp = @mpn_objs_in_libgmp@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_CPPFLAGS = -D__GMP_WITHIN_GMP -I$(top_srcdir)
+noinst_LTLIBRARIES = libmpf.la
+libmpf_la_SOURCES = \
+  init.c init2.c inits.c set.c set_ui.c set_si.c set_str.c set_d.c set_z.c \
+  set_q.c iset.c iset_ui.c iset_si.c iset_str.c iset_d.c clear.c clears.c \
+  get_str.c dump.c size.c eq.c reldiff.c sqrt.c random2.c inp_str.c out_str.c \
+  add.c add_ui.c sub.c sub_ui.c ui_sub.c mul.c mul_ui.c div.c div_ui.c \
+  cmp.c cmp_d.c cmp_z.c cmp_si.c cmp_ui.c mul_2exp.c div_2exp.c abs.c neg.c get_d.c \
+  get_d_2exp.c set_dfl_prec.c set_prc.c set_prc_raw.c get_dfl_prec.c get_prc.c \
+  ui_div.c sqrt_ui.c \
+  pow_ui.c urandomb.c swap.c get_si.c get_ui.c int_p.c \
+  ceilfloor.c trunc.c \
+  fits_sint.c fits_slong.c fits_sshort.c \
+  fits_uint.c fits_ulong.c fits_ushort.c \
+  fits_s.h fits_u.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu --ignore-deps mpf/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu --ignore-deps mpf/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+	@list='$(noinst_LTLIBRARIES)'; \
+	locs=`for p in $$list; do echo $$p; done | \
+	      sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+	      sort -u`; \
+	test -z "$$locs" || { \
+	  echo rm -f $${locs}; \
+	  rm -f $${locs}; \
+	}
+
+libmpf.la: $(libmpf_la_OBJECTS) $(libmpf_la_DEPENDENCIES) $(EXTRA_libmpf_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(LINK)  $(libmpf_la_OBJECTS) $(libmpf_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+.c.o:
+	$(AM_V_CC)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+	$(AM_V_CC)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+	$(AM_V_CC)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+	clean-libtool clean-noinstLTLIBRARIES cscopelist-am ctags \
+	ctags-am distclean distclean-compile distclean-generic \
+	distclean-libtool distclean-tags distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-dvi install-dvi-am install-exec \
+	install-exec-am install-html install-html-am install-info \
+	install-info-am install-man install-pdf install-pdf-am \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/third_party/gmp/mpf/abs.c b/third_party/gmp/mpf/abs.c
new file mode 100644
index 0000000..1642a46
--- /dev/null
+++ b/third_party/gmp/mpf/abs.c
@@ -0,0 +1,58 @@
+/* mpf_abs -- Compute the absolute value of a float.
+
+Copyright 1993-1995, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpf_abs (mpf_ptr r, mpf_srcptr u)
+{
+  mp_size_t size;
+
+  size = ABS (u->_mp_size);
+  if (r != u)
+    {
+      mp_size_t prec;
+      mp_ptr rp, up;
+
+      prec = r->_mp_prec + 1;	/* lie not to lose precision in assignment */
+      rp = r->_mp_d;
+      up = u->_mp_d;
+
+      if (size > prec)
+	{
+	  up += size - prec;
+	  size = prec;
+	}
+
+      MPN_COPY (rp, up, size);
+      r->_mp_exp = u->_mp_exp;
+    }
+  r->_mp_size = size;
+}
diff --git a/third_party/gmp/mpf/add.c b/third_party/gmp/mpf/add.c
new file mode 100644
index 0000000..77a9e47
--- /dev/null
+++ b/third_party/gmp/mpf/add.c
@@ -0,0 +1,183 @@
+/* mpf_add -- Add two floats.
+
+Copyright 1993, 1994, 1996, 2000, 2001, 2005 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpf_add (mpf_ptr r, mpf_srcptr u, mpf_srcptr v)
+{
+  mp_srcptr up, vp;
+  mp_ptr rp, tp;
+  mp_size_t usize, vsize, rsize;
+  mp_size_t prec;
+  mp_exp_t uexp;
+  mp_size_t ediff;
+  mp_limb_t cy;
+  int negate;
+  TMP_DECL;
+
+  usize = u->_mp_size;
+  vsize = v->_mp_size;
+
+  /* Handle special cases that don't work in generic code below.  */
+  if (usize == 0)
+    {
+    set_r_v_maybe:
+      if (r != v)
+        mpf_set (r, v);
+      return;
+    }
+  if (vsize == 0)
+    {
+      v = u;
+      goto set_r_v_maybe;
+    }
+
+  /* If signs of U and V are different, perform subtraction.  */
+  if ((usize ^ vsize) < 0)
+    {
+      __mpf_struct v_negated;
+      v_negated._mp_size = -vsize;
+      v_negated._mp_exp = v->_mp_exp;
+      v_negated._mp_d = v->_mp_d;
+      mpf_sub (r, u, &v_negated);
+      return;
+    }
+
+  TMP_MARK;
+
+  /* Signs are now known to be the same.  */
+  negate = usize < 0;
+
+  /* Make U be the operand with the largest exponent.  */
+  if (u->_mp_exp < v->_mp_exp)
+    {
+      mpf_srcptr t;
+      t = u; u = v; v = t;
+      usize = u->_mp_size;
+      vsize = v->_mp_size;
+    }
+
+  usize = ABS (usize);
+  vsize = ABS (vsize);
+  up = u->_mp_d;
+  vp = v->_mp_d;
+  rp = r->_mp_d;
+  prec = r->_mp_prec;
+  uexp = u->_mp_exp;
+  ediff = u->_mp_exp - v->_mp_exp;
+
+  /* If U extends beyond PREC, ignore the part that does.  */
+  if (usize > prec)
+    {
+      up += usize - prec;
+      usize = prec;
+    }
+
+  /* If V extends beyond PREC, ignore the part that does.
+     Note that this may make vsize negative.  */
+  if (vsize + ediff > prec)
+    {
+      vp += vsize + ediff - prec;
+      vsize = prec - ediff;
+    }
+
+#if 0
+  /* Locate the least significant non-zero limb in (the needed parts
+     of) U and V, to simplify the code below.  */
+  while (up[0] == 0)
+    up++, usize--;
+  while (vp[0] == 0)
+    vp++, vsize--;
+#endif
+
+  /* Allocate temp space for the result.  Allocate
+     just vsize + ediff later???  */
+  tp = TMP_ALLOC_LIMBS (prec);
+
+  if (ediff >= prec)
+    {
+      /* V completely cancelled.  */
+      if (rp != up)
+	MPN_COPY_INCR (rp, up, usize);
+      rsize = usize;
+    }
+  else
+    {
+      /* uuuu     |  uuuu     |  uuuu     |  uuuu     |  uuuu    */
+      /* vvvvvvv  |  vv       |    vvvvv  |    v      |       vv */
+
+      if (usize > ediff)
+	{
+	  /* U and V partially overlaps.  */
+	  if (vsize + ediff <= usize)
+	    {
+	      /* uuuu     */
+	      /*   v      */
+	      mp_size_t size;
+	      size = usize - ediff - vsize;
+	      MPN_COPY (tp, up, size);
+	      cy = mpn_add (tp + size, up + size, usize - size, vp, vsize);
+	      rsize = usize;
+	    }
+	  else
+	    {
+	      /* uuuu     */
+	      /*   vvvvv  */
+	      mp_size_t size;
+	      size = vsize + ediff - usize;
+	      MPN_COPY (tp, vp, size);
+	      cy = mpn_add (tp + size, up, usize, vp + size, usize - ediff);
+	      rsize = vsize + ediff;
+	    }
+	}
+      else
+	{
+	  /* uuuu     */
+	  /*      vv  */
+	  mp_size_t size;
+	  size = vsize + ediff - usize;
+	  MPN_COPY (tp, vp, vsize);
+	  MPN_ZERO (tp + vsize, ediff - usize);
+	  MPN_COPY (tp + size, up, usize);
+	  cy = 0;
+	  rsize = size + usize;
+	}
+
+      MPN_COPY (rp, tp, rsize);
+      rp[rsize] = cy;
+      rsize += cy;
+      uexp += cy;
+    }
+
+  r->_mp_size = negate ? -rsize : rsize;
+  r->_mp_exp = uexp;
+  TMP_FREE;
+}
diff --git a/third_party/gmp/mpf/add_ui.c b/third_party/gmp/mpf/add_ui.c
new file mode 100644
index 0000000..1e2a94b
--- /dev/null
+++ b/third_party/gmp/mpf/add_ui.c
@@ -0,0 +1,152 @@
+/* mpf_add_ui -- Add a float and an unsigned integer.
+
+Copyright 1993, 1994, 1996, 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpf_add_ui (mpf_ptr sum, mpf_srcptr u, unsigned long int v)
+{
+  mp_srcptr up = u->_mp_d;
+  mp_ptr sump = sum->_mp_d;
+  mp_size_t usize, sumsize;
+  mp_size_t prec = sum->_mp_prec;
+  mp_exp_t uexp = u->_mp_exp;
+
+  usize = u->_mp_size;
+  if (usize <= 0)
+    {
+      if (usize == 0)
+	{
+	  mpf_set_ui (sum, v);
+	  return;
+	}
+      else
+	{
+	  __mpf_struct u_negated;
+	  u_negated._mp_size = -usize;
+	  u_negated._mp_exp = u->_mp_exp;
+	  u_negated._mp_d = u->_mp_d;
+	  mpf_sub_ui (sum, &u_negated, v);
+	  sum->_mp_size = -(sum->_mp_size);
+	  return;
+	}
+    }
+
+  if (v == 0)
+    {
+    sum_is_u:
+      if (u != sum)
+	{
+	  sumsize = MIN (usize, prec + 1);
+	  MPN_COPY (sum->_mp_d, up + usize - sumsize, sumsize);
+	  sum->_mp_size = sumsize;
+	  sum->_mp_exp = u->_mp_exp;
+	}
+      return;
+    }
+
+  if (uexp > 0)
+    {
+      /* U >= 1.  */
+      if (uexp > prec)
+	{
+	  /* U >> V, V is not part of final result.  */
+	  goto sum_is_u;
+	}
+      else
+	{
+	  /* U's "limb point" is somewhere between the first limb
+	     and the PREC:th limb.
+	     Both U and V are part of the final result.  */
+	  if (uexp > usize)
+	    {
+	      /*   uuuuuu0000. */
+	      /* +          v. */
+	      /* We begin with moving U to the top of SUM, to handle
+		 samevar(U,SUM).  */
+	      MPN_COPY_DECR (sump + uexp - usize, up, usize);
+	      sump[0] = v;
+	      MPN_ZERO (sump + 1, uexp - usize - 1);
+#if 0 /* What is this??? */
+	      if (sum == u)
+		MPN_COPY (sum->_mp_d, sump, uexp);
+#endif
+	      sum->_mp_size = uexp;
+	      sum->_mp_exp = uexp;
+	    }
+	  else
+	    {
+	      /*   uuuuuu.uuuu */
+	      /* +      v.     */
+	      mp_limb_t cy_limb;
+	      if (usize > prec)
+		{
+		  /* Ignore excess limbs in U.  */
+		  up += usize - prec;
+		  usize -= usize - prec; /* Eq. usize = prec */
+		}
+	      if (sump != up)
+		MPN_COPY_INCR (sump, up, usize - uexp);
+	      cy_limb = mpn_add_1 (sump + usize - uexp, up + usize - uexp,
+				   uexp, (mp_limb_t) v);
+	      sump[usize] = cy_limb;
+	      sum->_mp_size = usize + cy_limb;
+	      sum->_mp_exp = uexp + cy_limb;
+	    }
+	}
+    }
+  else
+    {
+      /* U < 1, so V > U for sure.  */
+      /* v.         */
+      /*  .0000uuuu */
+      if ((-uexp) >= prec)
+	{
+	  sump[0] = v;
+	  sum->_mp_size = 1;
+	  sum->_mp_exp = 1;
+	}
+      else
+	{
+	  if (usize + (-uexp) + 1 > prec)
+	    {
+	      /* Ignore excess limbs in U.  */
+	      up += usize + (-uexp) + 1 - prec;
+	      usize -= usize + (-uexp) + 1 - prec;
+	    }
+	  if (sump != up)
+	    MPN_COPY_INCR (sump, up, usize);
+	  MPN_ZERO (sump + usize, -uexp);
+	  sump[usize + (-uexp)] = v;
+	  sum->_mp_size = usize + (-uexp) + 1;
+	  sum->_mp_exp = 1;
+	}
+    }
+}
diff --git a/third_party/gmp/mpf/ceilfloor.c b/third_party/gmp/mpf/ceilfloor.c
new file mode 100644
index 0000000..9bb6638
--- /dev/null
+++ b/third_party/gmp/mpf/ceilfloor.c
@@ -0,0 +1,125 @@
+/* mpf_ceil, mpf_floor -- round an mpf to an integer.
+
+Copyright 2001, 2004, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* dir==1 for ceil, dir==-1 for floor
+
+   Notice the use of prec+1 ensures mpf_ceil and mpf_floor are equivalent to
+   mpf_set if u is already an integer.  */
+
+static void __gmpf_ceil_or_floor (REGPARM_2_1 (mpf_ptr, mpf_srcptr, int)) REGPARM_ATTR (1);
+#define mpf_ceil_or_floor(r,u,dir)  __gmpf_ceil_or_floor (REGPARM_2_1 (r, u, dir))
+
+REGPARM_ATTR (1) static void
+mpf_ceil_or_floor (mpf_ptr r, mpf_srcptr u, int dir)
+{
+  mp_ptr     rp, up, p;
+  mp_size_t  size, asize, prec;
+  mp_exp_t   exp;
+
+  size = SIZ(u);
+  if (size == 0)
+    {
+    zero:
+      SIZ(r) = 0;
+      EXP(r) = 0;
+      return;
+    }
+
+  rp = PTR(r);
+  exp = EXP(u);
+  if (exp <= 0)
+    {
+      /* u is only a fraction */
+      if ((size ^ dir) < 0)
+        goto zero;
+      rp[0] = 1;
+      EXP(r) = 1;
+      SIZ(r) = dir;
+      return;
+    }
+  EXP(r) = exp;
+
+  up = PTR(u);
+  asize = ABS (size);
+  up += asize;
+
+  /* skip fraction part of u */
+  asize = MIN (asize, exp);
+
+  /* don't lose precision in the copy */
+  prec = PREC (r) + 1;
+
+  /* skip excess over target precision */
+  asize = MIN (asize, prec);
+
+  up -= asize;
+
+  if ((size ^ dir) >= 0)
+    {
+      /* rounding direction matches sign, must increment if ignored part is
+         non-zero */
+      for (p = PTR(u); p != up; p++)
+        {
+          if (*p != 0)
+            {
+              if (mpn_add_1 (rp, up, asize, CNST_LIMB(1)))
+                {
+                  /* was all 0xFF..FFs, which have become zeros, giving just
+                     a carry */
+                  rp[0] = 1;
+                  asize = 1;
+                  EXP(r)++;
+                }
+              SIZ(r) = (size >= 0 ? asize : -asize);
+              return;
+            }
+        }
+    }
+
+  SIZ(r) = (size >= 0 ? asize : -asize);
+  if (rp != up)
+    MPN_COPY_INCR (rp, up, asize);
+}
+
+
+void
+mpf_ceil (mpf_ptr r, mpf_srcptr u)
+{
+  mpf_ceil_or_floor (r, u, 1);
+}
+
+void
+mpf_floor (mpf_ptr r, mpf_srcptr u)
+{
+  mpf_ceil_or_floor (r, u, -1);
+}
diff --git a/third_party/gmp/mpf/clear.c b/third_party/gmp/mpf/clear.c
new file mode 100644
index 0000000..0939e03
--- /dev/null
+++ b/third_party/gmp/mpf/clear.c
@@ -0,0 +1,38 @@
+/* mpf_clear -- de-allocate the space occupied by the dynamic digit space of
+   an integer.
+
+Copyright 1993-1995, 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpf_clear (mpf_ptr x)
+{
+  __GMP_FREE_FUNC_LIMBS (PTR(x), PREC(x) + 1);
+}
diff --git a/third_party/gmp/mpf/clears.c b/third_party/gmp/mpf/clears.c
new file mode 100644
index 0000000..115fa19
--- /dev/null
+++ b/third_party/gmp/mpf/clears.c
@@ -0,0 +1,49 @@
+/* mpf_clears() -- Clear multiple mpf_t variables.
+
+Copyright 2009, 2014, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+#include "gmp-impl.h"
+
+void
+mpf_clears (mpf_ptr x, ...)
+{
+  va_list  ap;
+
+  va_start (ap, x);
+
+  do
+    {
+      __GMP_FREE_FUNC_LIMBS (PTR(x), PREC(x) + 1);
+      x = va_arg (ap, mpf_ptr);
+    }
+  while (x != NULL);
+
+  va_end (ap);
+}
diff --git a/third_party/gmp/mpf/cmp.c b/third_party/gmp/mpf/cmp.c
new file mode 100644
index 0000000..3518b51
--- /dev/null
+++ b/third_party/gmp/mpf/cmp.c
@@ -0,0 +1,113 @@
+/* mpf_cmp -- Compare two floats.
+
+Copyright 1993, 1994, 1996, 2001, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+int
+mpf_cmp (mpf_srcptr u, mpf_srcptr v) __GMP_NOTHROW
+{
+  mp_srcptr up, vp;
+  mp_size_t usize, vsize;
+  mp_exp_t uexp, vexp;
+  int cmp;
+  int usign;
+
+  usize = SIZ(u);
+  vsize = SIZ(v);
+  usign = usize >= 0 ? 1 : -1;
+
+  /* 1. Are the signs different?  */
+  if ((usize ^ vsize) >= 0)
+    {
+      /* U and V are both non-negative or both negative.  */
+      if (usize == 0)
+	/* vsize >= 0 */
+	return -(vsize != 0);
+      if (vsize == 0)
+	/* usize >= 0 */
+	return usize != 0;
+      /* Fall out.  */
+    }
+  else
+    {
+      /* Either U or V is negative, but not both.  */
+      return usign;
+    }
+
+  /* U and V have the same sign and are both non-zero.  */
+
+  uexp = EXP(u);
+  vexp = EXP(v);
+
+  /* 2. Are the exponents different?  */
+  if (uexp > vexp)
+    return usign;
+  if (uexp < vexp)
+    return -usign;
+
+  usize = ABS (usize);
+  vsize = ABS (vsize);
+
+  up = PTR (u);
+  vp = PTR (v);
+
+#define STRICT_MPF_NORMALIZATION 0
+#if ! STRICT_MPF_NORMALIZATION
+  /* Ignore zeroes at the low end of U and V.  */
+  do {
+    mp_limb_t tl;
+    tl = up[0];
+    MPN_STRIP_LOW_ZEROS_NOT_ZERO (up, usize, tl);
+    tl = vp[0];
+    MPN_STRIP_LOW_ZEROS_NOT_ZERO (vp, vsize, tl);
+  } while (0);
+#endif
+
+  if (usize > vsize)
+    {
+      cmp = mpn_cmp (up + usize - vsize, vp, vsize);
+      /* if (cmp == 0) */
+      /*	return usign; */
+      ++cmp;
+    }
+  else if (vsize > usize)
+    {
+      cmp = mpn_cmp (up, vp + vsize - usize, usize);
+      /* if (cmp == 0) */
+      /*	return -usign; */
+    }
+  else
+    {
+      cmp = mpn_cmp (up, vp, usize);
+      if (cmp == 0)
+	return 0;
+    }
+  return cmp > 0 ? usign : -usign;
+}
diff --git a/third_party/gmp/mpf/cmp_d.c b/third_party/gmp/mpf/cmp_d.c
new file mode 100644
index 0000000..3fa099b
--- /dev/null
+++ b/third_party/gmp/mpf/cmp_d.c
@@ -0,0 +1,59 @@
+/* mpf_cmp_d -- compare mpf and double.
+
+Copyright 2001, 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#if HAVE_FLOAT_H
+#include <float.h>  /* for DBL_MAX */
+#endif
+
+#include "gmp-impl.h"
+
+int
+mpf_cmp_d (mpf_srcptr f, double d)
+{
+  mp_limb_t  darray[LIMBS_PER_DOUBLE];
+  mpf_t      df;
+
+  /* d=NaN has no sensible return value, so raise an exception.
+     d=Inf or -Inf is always bigger than z.  */
+  DOUBLE_NAN_INF_ACTION (d,
+                         __gmp_invalid_operation (),
+                         return (d < 0.0 ? 1 : -1));
+
+  if (d == 0.0)
+    return SIZ(f);
+
+  PTR(df) = darray;
+  SIZ(df) = (d >= 0.0 ? LIMBS_PER_DOUBLE : -LIMBS_PER_DOUBLE);
+  EXP(df) = __gmp_extract_double (darray, ABS(d));
+
+  return mpf_cmp (f, df);
+}
diff --git a/third_party/gmp/mpf/cmp_si.c b/third_party/gmp/mpf/cmp_si.c
new file mode 100644
index 0000000..d8d9880
--- /dev/null
+++ b/third_party/gmp/mpf/cmp_si.c
@@ -0,0 +1,109 @@
+/* mpf_cmp_si -- Compare a float with a signed integer.
+
+Copyright 1993-1995, 1999-2002, 2004, 2012, 2015 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+int
+mpf_cmp_si (mpf_srcptr u, long int vval) __GMP_NOTHROW
+{
+  mp_srcptr up;
+  mp_size_t usize;
+  mp_exp_t uexp;
+  mp_limb_t ulimb;
+  int usign;
+  unsigned long abs_vval;
+
+  usize = SIZ (u);
+
+  /* 1. Are the signs different?  */
+  if ((usize < 0) == (vval < 0)) /* don't use xor, type size may differ */
+    {
+      /* U and V are both non-negative or both negative.  */
+      if (usize == 0)
+	/* vval >= 0 */
+	return -(vval != 0);
+      if (vval == 0)
+	/* usize >= 0 */
+	return usize != 0;
+      /* Fall out.  */
+    }
+  else
+    {
+      /* Either U or V is negative, but not both.  */
+      return usize >= 0 ? 1 : -1;
+    }
+
+  /* U and V have the same sign and are both non-zero.  */
+
+  /* 2. Are the exponents different (V's exponent == 1)?  */
+  uexp = EXP (u);
+  usign = usize >= 0 ? 1 : -1;
+  usize = ABS (usize);
+  abs_vval = ABS_CAST (unsigned long, vval);
+
+#if GMP_NAIL_BITS != 0
+  if (uexp != 1 + (abs_vval > GMP_NUMB_MAX))
+    return (uexp < 1 + (abs_vval > GMP_NUMB_MAX)) ? -usign : usign;
+#else
+  if (uexp != 1)
+    return (uexp < 1) ? -usign : usign;
+#endif
+
+  up = PTR (u);
+
+  ASSERT (usize > 0);
+  ulimb = up[--usize];
+#if GMP_NAIL_BITS != 0
+  if (uexp == 2)
+    {
+      if ((ulimb >> GMP_NAIL_BITS) != 0)
+	return usign;
+      ulimb = (ulimb << GMP_NUMB_BITS);
+      if (usize != 0) ulimb |= up[--usize];
+    }
+#endif
+
+  /* 3. Compare the most significant mantissa limb with V.  */
+  if (ulimb != abs_vval)
+    return (ulimb < abs_vval) ? -usign : usign;
+
+  /* Ignore zeroes at the low end of U.  */
+  for (; *up == 0; ++up)
+    --usize;
+
+  /* 4. Now, if the number of limbs are different, we have a difference
+     since we have made sure the trailing limbs are not zero.  */
+  if (usize > 0)
+    return usign;
+
+  /* Wow, we got zero even if we tried hard to avoid it.  */
+  return 0;
+}
diff --git a/third_party/gmp/mpf/cmp_ui.c b/third_party/gmp/mpf/cmp_ui.c
new file mode 100644
index 0000000..a9a6036
--- /dev/null
+++ b/third_party/gmp/mpf/cmp_ui.c
@@ -0,0 +1,87 @@
+/* mpf_cmp_ui -- Compare a float with an unsigned integer.
+
+Copyright 1993-1995, 1999, 2001, 2002, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+int
+mpf_cmp_ui (mpf_srcptr u, unsigned long int vval) __GMP_NOTHROW
+{
+  mp_srcptr up;
+  mp_size_t usize;
+  mp_exp_t uexp;
+  mp_limb_t ulimb;
+
+  usize = SIZ (u);
+
+  /* 1. Is U negative?  */
+  if (usize < 0)
+    return -1;
+  /* We rely on usize being non-negative in the code that follows.  */
+
+  if (vval == 0)
+    return usize != 0;
+
+  /* 2. Are the exponents different (V's exponent == 1)?  */
+  uexp = EXP (u);
+
+#if GMP_NAIL_BITS != 0
+  if (uexp != 1 + (vval > GMP_NUMB_MAX))
+    return (uexp < 1 + (vval > GMP_NUMB_MAX)) ? -1 : 1;
+#else
+  if (uexp != 1)
+    return (uexp < 1) ? -1 : 1;
+#endif
+
+  up = PTR (u);
+
+  ASSERT (usize > 0);
+  ulimb = up[--usize];
+#if GMP_NAIL_BITS != 0
+  if (uexp == 2)
+    {
+      if ((ulimb >> GMP_NAIL_BITS) != 0)
+	return 1;
+      ulimb = (ulimb << GMP_NUMB_BITS);
+      if (usize != 0) ulimb |= up[--usize];
+    }
+#endif
+
+  /* 3. Compare the most significant mantissa limb with V.  */
+  if (ulimb != vval)
+    return (ulimb < vval) ? -1 : 1;
+
+  /* Ignore zeroes at the low end of U.  */
+  for (; *up == 0; ++up)
+    --usize;
+
+  /* 4. Now, if the number of limbs are different, we have a difference
+     since we have made sure the trailing limbs are not zero.  */
+  return (usize > 0);
+}
diff --git a/third_party/gmp/mpf/cmp_z.c b/third_party/gmp/mpf/cmp_z.c
new file mode 100644
index 0000000..279980f
--- /dev/null
+++ b/third_party/gmp/mpf/cmp_z.c
@@ -0,0 +1,45 @@
+/* mpf_cmp_z -- Compare a float with an integer.
+
+Copyright 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+int
+mpf_cmp_z (mpf_srcptr u, mpz_srcptr v) __GMP_NOTHROW
+{
+  mpf_t vf;
+  mp_size_t size;
+
+  SIZ (vf) = size = SIZ (v);
+  EXP (vf) = size = ABS (size);
+  /* PREC (vf) = size; */
+  PTR (vf) = PTR (v);
+
+  return mpf_cmp (u, vf);
+}
diff --git a/third_party/gmp/mpf/div.c b/third_party/gmp/mpf/div.c
new file mode 100644
index 0000000..d13af75
--- /dev/null
+++ b/third_party/gmp/mpf/div.c
@@ -0,0 +1,137 @@
+/* mpf_div -- Divide two floats.
+
+Copyright 1993, 1994, 1996, 2000-2002, 2004, 2005, 2010, 2012 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* Not done:
+
+   No attempt is made to identify an overlap u==v.  The result will be
+   correct (1.0), but a full actual division is done whereas of course
+   x/x==1 needs no work.  Such a call is not a sensible thing to make, and
+   it's left to an application to notice and optimize if it might arise
+   somehow through pointer aliasing or whatever.
+
+   Enhancements:
+
+   The high quotient limb is non-zero when high{up,vsize} >= {vp,vsize}.  We
+   could make that comparison and use qsize==prec instead of qsize==prec+1,
+   to save one limb in the division.
+
+   If r==u but the size is enough bigger than prec that there won't be an
+   overlap between quotient and dividend in mpn_div_q, then we can avoid
+   copying up,usize.  This would only arise from a prec reduced with
+   mpf_set_prec_raw and will be pretty unusual, but might be worthwhile if
+   it could be worked into the copy_u decision cleanly.  */
+
+void
+mpf_div (mpf_ptr r, mpf_srcptr u, mpf_srcptr v)
+{
+  mp_srcptr up, vp;
+  mp_ptr rp, tp, new_vp;
+  mp_size_t usize, vsize, rsize, prospective_rsize, tsize, zeros;
+  mp_size_t sign_quotient, prec, high_zero, chop;
+  mp_exp_t rexp;
+  int copy_u;
+  TMP_DECL;
+
+  usize = SIZ(u);
+  vsize = SIZ(v);
+
+  if (UNLIKELY (vsize == 0))
+    DIVIDE_BY_ZERO;
+
+  if (usize == 0)
+    {
+      SIZ(r) = 0;
+      EXP(r) = 0;
+      return;
+    }
+
+  sign_quotient = usize ^ vsize;
+  usize = ABS (usize);
+  vsize = ABS (vsize);
+  prec = PREC(r);
+
+  TMP_MARK;
+  rexp = EXP(u) - EXP(v) + 1;
+
+  rp = PTR(r);
+  up = PTR(u);
+  vp = PTR(v);
+
+  prospective_rsize = usize - vsize + 1; /* quot from using given u,v sizes */
+  rsize = prec + 1;			 /* desired quot */
+
+  zeros = rsize - prospective_rsize;	 /* padding u to give rsize */
+  copy_u = (zeros > 0 || rp == up);	 /* copy u if overlap or padding */
+
+  chop = MAX (-zeros, 0);		 /* negative zeros means shorten u */
+  up += chop;
+  usize -= chop;
+  zeros += chop;			 /* now zeros >= 0 */
+
+  tsize = usize + zeros;		 /* size for possible copy of u */
+
+  /* copy and possibly extend u if necessary */
+  if (copy_u)
+    {
+      tp = TMP_ALLOC_LIMBS (tsize + 1);	/* +1 for mpn_div_q's scratch needs */
+      MPN_ZERO (tp, zeros);
+      MPN_COPY (tp+zeros, up, usize);
+      up = tp;
+      usize = tsize;
+    }
+  else
+    {
+      tp = TMP_ALLOC_LIMBS (usize + 1);
+    }
+
+  /* ensure divisor doesn't overlap quotient */
+  if (rp == vp)
+    {
+      new_vp = TMP_ALLOC_LIMBS (vsize);
+      MPN_COPY (new_vp, vp, vsize);
+      vp = new_vp;
+    }
+
+  ASSERT (usize-vsize+1 == rsize);
+  mpn_div_q (rp, up, usize, vp, vsize, tp);
+
+  /* strip possible zero high limb */
+  high_zero = (rp[rsize-1] == 0);
+  rsize -= high_zero;
+  rexp -= high_zero;
+
+  SIZ(r) = sign_quotient >= 0 ? rsize : -rsize;
+  EXP(r) = rexp;
+  TMP_FREE;
+}
diff --git a/third_party/gmp/mpf/div_2exp.c b/third_party/gmp/mpf/div_2exp.c
new file mode 100644
index 0000000..ad552c1
--- /dev/null
+++ b/third_party/gmp/mpf/div_2exp.c
@@ -0,0 +1,138 @@
+/* mpf_div_2exp -- Divide a float by 2^n.
+
+Copyright 1993, 1994, 1996, 2000-2002, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* Multiples of GMP_NUMB_BITS in exp simply mean an amount subtracted from
+   EXP(u) to set EXP(r).  The remainder exp%GMP_NUMB_BITS is then a right
+   shift for the limb data.
+
+   If exp%GMP_NUMB_BITS == 0 then there's no shifting, we effectively just
+   do an mpz_set with changed EXP(r).  Like mpz_set we take prec+1 limbs in
+   this case.  Although just prec would suffice, it's nice to have
+   mpf_div_2exp with exp==0 come out the same as mpz_set.
+
+   When shifting we take up to prec many limbs from the input.  Our shift is
+   cy = mpn_rshift (PTR(r)+1, PTR(u)+k, ...), where k is the number of low
+   limbs dropped from u, and the carry out is stored to PTR(r)[0].  We don't
+   try to work extra bits from PTR(u)[k-1] (when k>=1 makes it available)
+   into that low carry limb.  Just prec limbs (with the high non-zero) from
+   the input is enough bits for the application requested precision, no need
+   to do extra work.
+
+   If r==u the shift will have overlapping operands.  When k>=1 (ie. when
+   usize > prec), the overlap is in the style supported by rshift (ie. dst
+   <= src).
+
+   But when r==u and k==0 (ie. usize <= prec), we would have an invalid
+   overlap (mpn_rshift (rp+1, rp, ...)).  In this case we must instead use
+   mpn_lshift (PTR(r), PTR(u), size, NUMB-shift).  An lshift by NUMB-shift
+   bits gives identical data of course, it's just its overlap restrictions
+   which differ.
+
+   In both shift cases, the resulting data is abs_usize+1 limbs.  "adj" is
+   used to add +1 to that size if the high is non-zero (it may of course
+   have become zero by the shifting).  EXP(u) is the exponent just above
+   those abs_usize+1 limbs, so it gets -1+adj, which means -1 if the high is
+   zero, or no change if the high is non-zero.
+
+   Enhancements:
+
+   The way mpn_lshift is used means successive mpf_div_2exp calls on the
+   same operand will accumulate low zero limbs, until prec+1 limbs is
+   reached.  This is wasteful for subsequent operations.  When abs_usize <=
+   prec, we should test the low exp%GMP_NUMB_BITS many bits of PTR(u)[0],
+   ie. those which would be shifted out by an mpn_rshift.  If they're zero
+   then use that mpn_rshift.  */
+
+void
+mpf_div_2exp (mpf_ptr r, mpf_srcptr u, mp_bitcnt_t exp)
+{
+  mp_srcptr up;
+  mp_ptr rp = r->_mp_d;
+  mp_size_t usize;
+  mp_size_t abs_usize;
+  mp_size_t prec = r->_mp_prec;
+  mp_exp_t uexp = u->_mp_exp;
+
+  usize = u->_mp_size;
+
+  if (UNLIKELY (usize == 0))
+    {
+      r->_mp_size = 0;
+      r->_mp_exp = 0;
+      return;
+    }
+
+  abs_usize = ABS (usize);
+  up = u->_mp_d;
+
+  if (exp % GMP_NUMB_BITS == 0)
+    {
+      prec++;			/* retain more precision here as we don't need
+				   to account for carry-out here */
+      if (abs_usize > prec)
+	{
+	  up += abs_usize - prec;
+	  abs_usize = prec;
+	}
+      if (rp != up)
+	MPN_COPY_INCR (rp, up, abs_usize);
+      r->_mp_exp = uexp - exp / GMP_NUMB_BITS;
+    }
+  else
+    {
+      mp_limb_t cy_limb;
+      mp_size_t adj;
+      if (abs_usize > prec)
+	{
+	  up += abs_usize - prec;
+	  abs_usize = prec;
+	  /* Use mpn_rshift since mpn_lshift operates downwards, and we
+	     therefore would clobber part of U before using that part, in case
+	     R is the same variable as U.  */
+	  cy_limb = mpn_rshift (rp + 1, up, abs_usize, exp % GMP_NUMB_BITS);
+	  rp[0] = cy_limb;
+	  adj = rp[abs_usize] != 0;
+	}
+      else
+	{
+	  cy_limb = mpn_lshift (rp, up, abs_usize,
+				GMP_NUMB_BITS - exp % GMP_NUMB_BITS);
+	  rp[abs_usize] = cy_limb;
+	  adj = cy_limb != 0;
+	}
+
+      abs_usize += adj;
+      r->_mp_exp = uexp - exp / GMP_NUMB_BITS - 1 + adj;
+    }
+  r->_mp_size = usize >= 0 ? abs_usize : -abs_usize;
+}
diff --git a/third_party/gmp/mpf/div_ui.c b/third_party/gmp/mpf/div_ui.c
new file mode 100644
index 0000000..e1b0112
--- /dev/null
+++ b/third_party/gmp/mpf/div_ui.c
@@ -0,0 +1,110 @@
+/* mpf_div_ui -- Divide a float with an unsigned integer.
+
+Copyright 1993, 1994, 1996, 2000-2002, 2004, 2005, 2012 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+void
+mpf_div_ui (mpf_ptr r, mpf_srcptr u, unsigned long int v)
+{
+  mp_srcptr up;
+  mp_ptr rp, tp, rtp;
+  mp_size_t usize;
+  mp_size_t rsize, tsize;
+  mp_size_t sign_quotient;
+  mp_size_t prec;
+  mp_limb_t q_limb;
+  mp_exp_t rexp;
+  TMP_DECL;
+
+#if BITS_PER_ULONG > GMP_NUMB_BITS  /* avoid warnings about shift amount */
+  if (v > GMP_NUMB_MAX)
+    {
+      mpf_t vf;
+      mp_limb_t vl[2];
+      SIZ(vf) = 2;
+      EXP(vf) = 2;
+      PTR(vf) = vl;
+      vl[0] = v & GMP_NUMB_MASK;
+      vl[1] = v >> GMP_NUMB_BITS;
+      mpf_div (r, u, vf);
+      return;
+    }
+#endif
+
+  if (UNLIKELY (v == 0))
+    DIVIDE_BY_ZERO;
+
+  usize = u->_mp_size;
+
+  if (usize == 0)
+    {
+      r->_mp_size = 0;
+      r->_mp_exp = 0;
+      return;
+    }
+
+  sign_quotient = usize;
+  usize = ABS (usize);
+  prec = r->_mp_prec;
+
+  TMP_MARK;
+
+  rp = r->_mp_d;
+  up = u->_mp_d;
+
+  tsize = 1 + prec;
+  tp = TMP_ALLOC_LIMBS (tsize + 1);
+
+  if (usize > tsize)
+    {
+      up += usize - tsize;
+      usize = tsize;
+      rtp = tp;
+    }
+  else
+    {
+      MPN_ZERO (tp, tsize - usize);
+      rtp = tp + (tsize - usize);
+    }
+
+  /* Move the dividend to the remainder.  */
+  MPN_COPY (rtp, up, usize);
+
+  mpn_divmod_1 (rp, tp, tsize, (mp_limb_t) v);
+  q_limb = rp[tsize - 1];
+
+  rsize = tsize - (q_limb == 0);
+  rexp = u->_mp_exp - (q_limb == 0);
+  r->_mp_size = sign_quotient >= 0 ? rsize : -rsize;
+  r->_mp_exp = rexp;
+  TMP_FREE;
+}
diff --git a/third_party/gmp/mpf/dump.c b/third_party/gmp/mpf/dump.c
new file mode 100644
index 0000000..cd37dab
--- /dev/null
+++ b/third_party/gmp/mpf/dump.c
@@ -0,0 +1,52 @@
+/* mpf_dump -- Dump a float to stdout.
+
+   THIS IS AN INTERNAL FUNCTION WITH A MUTABLE INTERFACE.  IT IS NOT SAFE TO
+   CALL THIS FUNCTION DIRECTLY.  IN FACT, IT IS ALMOST GUARANTEED THAT THIS
+   FUNCTION WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+
+Copyright 1993-1995, 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <string.h> /* for strlen */
+#include "gmp-impl.h"
+
+void
+mpf_dump (mpf_srcptr u)
+{
+  mp_exp_t exp;
+  char *str;
+
+  str = mpf_get_str (0, &exp, 10, 0, u);
+  if (str[0] == '-')
+    printf ("-0.%se%ld\n", str + 1, exp);
+  else
+    printf ("0.%se%ld\n", str, exp);
+  (*__gmp_free_func) (str, strlen (str) + 1);
+}
diff --git a/third_party/gmp/mpf/eq.c b/third_party/gmp/mpf/eq.c
new file mode 100644
index 0000000..cddb9d5
--- /dev/null
+++ b/third_party/gmp/mpf/eq.c
@@ -0,0 +1,149 @@
+/* mpf_eq -- Compare two floats up to a specified bit #.
+
+Copyright 1993, 1995, 1996, 2001, 2002, 2008, 2009, 2012 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+int
+mpf_eq (mpf_srcptr u, mpf_srcptr v, mp_bitcnt_t n_bits)
+{
+  mp_srcptr up, vp, p;
+  mp_size_t usize, vsize, minsize, maxsize, n_limbs, i, size;
+  mp_exp_t uexp, vexp;
+  mp_limb_t diff;
+  int cnt;
+
+  uexp = u->_mp_exp;
+  vexp = v->_mp_exp;
+
+  usize = u->_mp_size;
+  vsize = v->_mp_size;
+
+  /* 1. Are the signs different?  */
+  if ((usize ^ vsize) >= 0)
+    {
+      /* U and V are both non-negative or both negative.  */
+      if (usize == 0)
+	return vsize == 0;
+      if (vsize == 0)
+	return 0;
+
+      /* Fall out.  */
+    }
+  else
+    {
+      /* Either U or V is negative, but not both.  */
+      return 0;
+    }
+
+  /* U and V have the same sign and are both non-zero.  */
+
+  /* 2. Are the exponents different?  */
+  if (uexp != vexp)
+    return 0;
+
+  usize = ABS (usize);
+  vsize = ABS (vsize);
+
+  up = u->_mp_d;
+  vp = v->_mp_d;
+
+  up += usize;			/* point just above most significant limb */
+  vp += vsize;			/* point just above most significant limb */
+
+  count_leading_zeros (cnt, up[-1]);
+  if ((vp[-1] >> (GMP_LIMB_BITS - 1 - cnt)) != 1)
+    return 0;			/* msb positions different */
+
+  n_bits += cnt - GMP_NAIL_BITS;
+  n_limbs = (n_bits + GMP_NUMB_BITS - 1) / GMP_NUMB_BITS;
+
+  usize = MIN (usize, n_limbs);
+  vsize = MIN (vsize, n_limbs);
+
+#if 0
+  /* Ignore zeros at the low end of U and V.  */
+  while (up[0] == 0)
+    up++, usize--;
+  while (vp[0] == 0)
+    vp++, vsize--;
+#endif
+
+  minsize = MIN (usize, vsize);
+  maxsize = usize + vsize - minsize;
+
+  up -= minsize;		/* point at most significant common limb */
+  vp -= minsize;		/* point at most significant common limb */
+
+  /* Compare the most significant part which has explicit limbs for U and V. */
+  for (i = minsize - 1; i > 0; i--)
+    {
+      if (up[i] != vp[i])
+	return 0;
+    }
+
+  n_bits -= (maxsize - 1) * GMP_NUMB_BITS;
+
+  size = maxsize - minsize;
+  if (size != 0)
+    {
+      if (up[0] != vp[0])
+	return 0;
+
+      /* Now either U or V has its limbs consumed, i.e, continues with an
+	 infinite number of implicit zero limbs.  Check that the other operand
+	 has just zeros in the corresponding, relevant part.  */
+
+      if (usize > vsize)
+	p = up - size;
+      else
+	p = vp - size;
+
+      for (i = size - 1; i > 0; i--)
+	{
+	  if (p[i] != 0)
+	    return 0;
+	}
+
+      diff = p[0];
+    }
+  else
+    {
+      /* Both U or V has its limbs consumed.  */
+
+      diff = up[0] ^ vp[0];
+    }
+
+  if (n_bits < GMP_NUMB_BITS)
+    diff >>= GMP_NUMB_BITS - n_bits;
+
+  return diff == 0;
+}
diff --git a/third_party/gmp/mpf/fits_s.h b/third_party/gmp/mpf/fits_s.h
new file mode 100644
index 0000000..80e74be
--- /dev/null
+++ b/third_party/gmp/mpf/fits_s.h
@@ -0,0 +1,71 @@
+/* mpf_fits_s*_p -- test whether an mpf fits a C signed type.
+
+Copyright 2001, 2002, 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* Notice this is equivalent to mpz_set_f + mpz_fits_s*_p.  */
+
+int
+FUNCTION (mpf_srcptr f) __GMP_NOTHROW
+{
+  mp_size_t  fs, fn;
+  mp_srcptr  fp;
+  mp_exp_t   exp;
+  mp_limb_t  fl;
+
+  exp = EXP(f);
+  if (exp < 1)
+    return 1;  /* -1 < f < 1 truncates to zero, so fits */
+
+  fs = SIZ (f);
+  fp = PTR(f);
+  fn = ABS (fs);
+
+  if (exp == 1)
+    {
+      fl = fp[fn-1];
+    }
+#if GMP_NAIL_BITS != 0
+  else if (exp == 2 && MAXIMUM > GMP_NUMB_MAX)
+    {
+      fl = fp[fn-1];
+      if ((fl >> GMP_NAIL_BITS) != 0)
+	return 0;
+      fl = (fl << GMP_NUMB_BITS);
+      if (fn >= 2)
+        fl |= fp[fn-2];
+    }
+#endif
+  else
+    return 0;
+
+  return fl <= (fs >= 0 ? (mp_limb_t) MAXIMUM : NEG_CAST (mp_limb_t, MINIMUM));
+}
diff --git a/third_party/gmp/mpf/fits_sint.c b/third_party/gmp/mpf/fits_sint.c
new file mode 100644
index 0000000..26ace07
--- /dev/null
+++ b/third_party/gmp/mpf/fits_sint.c
@@ -0,0 +1,36 @@
+/* mpf_fits_sint_p -- test whether an mpf fits an int.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#define FUNCTION   mpf_fits_sint_p
+#define MAXIMUM    INT_MAX
+#define MINIMUM    INT_MIN
+
+#include "fits_s.h"
diff --git a/third_party/gmp/mpf/fits_slong.c b/third_party/gmp/mpf/fits_slong.c
new file mode 100644
index 0000000..25db68c
--- /dev/null
+++ b/third_party/gmp/mpf/fits_slong.c
@@ -0,0 +1,36 @@
+/* mpf_fits_slong_p -- test whether an mpf fits a long.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#define FUNCTION   mpf_fits_slong_p
+#define MAXIMUM    LONG_MAX
+#define MINIMUM    LONG_MIN
+
+#include "fits_s.h"
diff --git a/third_party/gmp/mpf/fits_sshort.c b/third_party/gmp/mpf/fits_sshort.c
new file mode 100644
index 0000000..3bfc5a4
--- /dev/null
+++ b/third_party/gmp/mpf/fits_sshort.c
@@ -0,0 +1,36 @@
+/* mpf_fits_sshort_p -- test whether an mpf fits a short.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#define FUNCTION   mpf_fits_sshort_p
+#define MAXIMUM    SHRT_MAX
+#define MINIMUM    SHRT_MIN
+
+#include "fits_s.h"
diff --git a/third_party/gmp/mpf/fits_u.h b/third_party/gmp/mpf/fits_u.h
new file mode 100644
index 0000000..bd7ca78
--- /dev/null
+++ b/third_party/gmp/mpf/fits_u.h
@@ -0,0 +1,73 @@
+/* mpf_fits_u*_p -- test whether an mpf fits a C unsigned type.
+
+Copyright 2001, 2002, 2013, 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* Notice this is equivalent to mpz_set_f + mpz_fits_u*_p.  */
+
+int
+FUNCTION (mpf_srcptr f) __GMP_NOTHROW
+{
+  mp_size_t  fn;
+  mp_srcptr  fp;
+  mp_exp_t   exp;
+  mp_limb_t  fl;
+
+  exp = EXP(f);
+  if (exp < 1)
+    return 1;  /* -1 < f < 1 truncates to zero, so fits */
+
+  fn = SIZ(f);
+  if (fn < 0) /* zero catched by exp == 0 */
+    return 0; /* negatives don't fit */
+
+  fp = PTR(f);
+
+  if (exp == 1)
+    {
+      fl = fp[fn-1];
+    }
+#if GMP_NAIL_BITS != 0
+  else if (exp == 2 && MAXIMUM > GMP_NUMB_MAX)
+    {
+      fl = fp[fn-1];
+      if ((fl >> GMP_NAIL_BITS) != 0)
+	return 0;
+      fl = (fl << GMP_NUMB_BITS);
+      if (fn >= 2)
+        fl |= fp[fn-2];
+    }
+#endif
+  else
+    return 0;
+
+  return fl <= MAXIMUM;
+}
diff --git a/third_party/gmp/mpf/fits_uint.c b/third_party/gmp/mpf/fits_uint.c
new file mode 100644
index 0000000..4b107b0
--- /dev/null
+++ b/third_party/gmp/mpf/fits_uint.c
@@ -0,0 +1,35 @@
+/* mpf_fits_uint_p -- test whether an mpf fits an unsigned int.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#define FUNCTION  mpf_fits_uint_p
+#define MAXIMUM   UINT_MAX
+
+#include "fits_u.h"
diff --git a/third_party/gmp/mpf/fits_ulong.c b/third_party/gmp/mpf/fits_ulong.c
new file mode 100644
index 0000000..1db688c
--- /dev/null
+++ b/third_party/gmp/mpf/fits_ulong.c
@@ -0,0 +1,35 @@
+/* mpf_fits_ulong_p -- test whether an mpf fits an unsigned long.
+
+Copyright 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#define FUNCTION  mpf_fits_ulong_p
+#define MAXIMUM   ULONG_MAX
+
+#include "fits_u.h"
diff --git a/third_party/gmp/mpf/fits_ushort.c b/third_party/gmp/mpf/fits_ushort.c
new file mode 100644
index 0000000..76a3fd9
--- /dev/null
+++ b/third_party/gmp/mpf/fits_ushort.c
@@ -0,0 +1,35 @@
+/* mpf_fits_ushort_p -- test whether an mpf fits an unsigned short.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#define FUNCTION  mpf_fits_ushort_p
+#define MAXIMUM   USHRT_MAX
+
+#include "fits_u.h"
diff --git a/third_party/gmp/mpf/get_d.c b/third_party/gmp/mpf/get_d.c
new file mode 100644
index 0000000..34826fb
--- /dev/null
+++ b/third_party/gmp/mpf/get_d.c
@@ -0,0 +1,46 @@
+/* double mpf_get_d (mpf_t src) -- return SRC truncated to a double.
+
+Copyright 1996, 2001-2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+double
+mpf_get_d (mpf_srcptr src)
+{
+  mp_size_t  size, abs_size;
+  long       exp;
+
+  size = SIZ (src);
+  if (UNLIKELY (size == 0))
+    return 0.0;
+
+  abs_size = ABS (size);
+  exp = (EXP (src) - abs_size) * GMP_NUMB_BITS;
+  return mpn_get_d (PTR (src), abs_size, size, exp);
+}
diff --git a/third_party/gmp/mpf/get_d_2exp.c b/third_party/gmp/mpf/get_d_2exp.c
new file mode 100644
index 0000000..440a753
--- /dev/null
+++ b/third_party/gmp/mpf/get_d_2exp.c
@@ -0,0 +1,56 @@
+/* double mpf_get_d_2exp (signed long int *exp, mpf_t src).
+
+Copyright 2001-2004, 2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+double
+mpf_get_d_2exp (signed long int *expptr, mpf_srcptr src)
+{
+  mp_size_t size, abs_size;
+  mp_srcptr ptr;
+  int cnt;
+
+  size = SIZ(src);
+  if (UNLIKELY (size == 0))
+    {
+      *expptr = 0;
+      return 0.0;
+    }
+
+  ptr = PTR(src);
+  abs_size = ABS (size);
+  count_leading_zeros (cnt, ptr[abs_size - 1]);
+  cnt -= GMP_NAIL_BITS;
+
+  *expptr = EXP(src) * GMP_NUMB_BITS - cnt;
+  return mpn_get_d (ptr, abs_size, size, -(abs_size * GMP_NUMB_BITS - cnt));
+}
diff --git a/third_party/gmp/mpf/get_dfl_prec.c b/third_party/gmp/mpf/get_dfl_prec.c
new file mode 100644
index 0000000..13fc514
--- /dev/null
+++ b/third_party/gmp/mpf/get_dfl_prec.c
@@ -0,0 +1,38 @@
+/* mpf_get_default_prec -- return default precision in bits.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+mp_bitcnt_t
+mpf_get_default_prec (void) __GMP_NOTHROW
+{
+  return __GMPF_PREC_TO_BITS (__gmp_default_fp_limb_precision);
+}
diff --git a/third_party/gmp/mpf/get_prc.c b/third_party/gmp/mpf/get_prc.c
new file mode 100644
index 0000000..8dee99e
--- /dev/null
+++ b/third_party/gmp/mpf/get_prc.c
@@ -0,0 +1,37 @@
+/* mpf_get_prec(x) -- Return the precision in bits of x.
+
+Copyright 1996, 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+mp_bitcnt_t
+mpf_get_prec (mpf_srcptr x) __GMP_NOTHROW
+{
+  return __GMPF_PREC_TO_BITS (x->_mp_prec);
+}
diff --git a/third_party/gmp/mpf/get_si.c b/third_party/gmp/mpf/get_si.c
new file mode 100644
index 0000000..6ac4d44
--- /dev/null
+++ b/third_party/gmp/mpf/get_si.c
@@ -0,0 +1,86 @@
+/* mpf_get_si -- mpf to long conversion
+
+Copyright 2001, 2002, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* Any fraction bits are truncated, meaning simply discarded.
+
+   For values bigger than a long, the low bits are returned, like
+   mpz_get_si, but this isn't documented.
+
+   Notice this is equivalent to mpz_set_f + mpz_get_si.
+
+
+   Implementation:
+
+   fl is established in basically the same way as for mpf_get_ui, see that
+   code for explanations of the conditions.
+
+   However unlike mpf_get_ui we need an explicit return 0 for exp<=0.  When
+   f is a negative fraction (ie. size<0 and exp<=0) we can't let fl==0 go
+   through to the zany final "~ ((fl - 1) & LONG_MAX)", that would give
+   -0x80000000 instead of the desired 0.  */
+
+long
+mpf_get_si (mpf_srcptr f) __GMP_NOTHROW
+{
+  mp_exp_t exp;
+  mp_size_t size, abs_size;
+  mp_srcptr fp;
+  mp_limb_t fl;
+
+  exp = EXP (f);
+  size = SIZ (f);
+  fp = PTR (f);
+
+  /* fraction alone truncates to zero
+     this also covers zero, since we have exp==0 for zero */
+  if (exp <= 0)
+    return 0L;
+
+  /* there are some limbs above the radix point */
+
+  fl = 0;
+  abs_size = ABS (size);
+  if (abs_size >= exp)
+    fl = fp[abs_size-exp];
+
+#if BITS_PER_ULONG > GMP_NUMB_BITS
+  if (exp > 1 && abs_size+1 >= exp)
+    fl |= fp[abs_size - exp + 1] << GMP_NUMB_BITS;
+#endif
+
+  if (size > 0)
+    return fl & LONG_MAX;
+  else
+    /* this form necessary to correctly handle -0x80..00 */
+    return -1 - (long) ((fl - 1) & LONG_MAX);
+}
diff --git a/third_party/gmp/mpf/get_str.c b/third_party/gmp/mpf/get_str.c
new file mode 100644
index 0000000..946c4ae
--- /dev/null
+++ b/third_party/gmp/mpf/get_str.c
@@ -0,0 +1,320 @@
+/* mpf_get_str (digit_ptr, exp, base, n_digits, a) -- Convert the floating
+   point number A to a base BASE number and store N_DIGITS raw digits at
+   DIGIT_PTR, and the base BASE exponent in the word pointed to by EXP.  For
+   example, the number 3.1416 would be returned as "31416" in DIGIT_PTR and
+   1 in EXP.
+
+Copyright 1993-1997, 2000-2003, 2005, 2006, 2011, 2015, 2017 Free
+Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdlib.h>		/* for NULL */
+#include "gmp-impl.h"
+#include "longlong.h"		/* for count_leading_zeros */
+
+/* Could use some more work.
+
+   1. Allocation is excessive.  Try to combine areas.  Perhaps use result
+      string area for temp limb space?
+   2. We generate up to two limbs of extra digits.  This is because we don't
+      check the exact number of bits in the input operand, and from that
+      compute an accurate exponent (variable e in the code).  It would be
+      cleaner and probably somewhat faster to change this.
+*/
+
+/* Compute base^exp and return the most significant prec limbs in rp[].
+   Put the count of omitted low limbs in *ign.
+   Return the actual size (which might be less than prec).
+   Allocation of rp[] and the temporary tp[] should be 2*prec+2 limbs.  */
+static mp_size_t
+mpn_pow_1_highpart (mp_ptr rp, mp_size_t *ignp,
+		    mp_limb_t base, unsigned long exp,
+		    mp_size_t prec, mp_ptr tp)
+{
+  mp_size_t ign;		/* counts number of ignored low limbs in r */
+  mp_size_t off;		/* keeps track of offset where value starts */
+  mp_ptr passed_rp = rp;
+  mp_size_t rn;
+  int cnt;
+  int i;
+
+  if (exp == 0)
+    {
+      rp[0] = 1;
+      *ignp = 0;
+      return 1;
+    }
+
+  rp[0] = base;
+  rn = 1;
+  off = 0;
+  ign = 0;
+  count_leading_zeros (cnt, exp);
+  for (i = GMP_LIMB_BITS - cnt - 2; i >= 0; i--)
+    {
+      mpn_sqr (tp, rp + off, rn);
+      rn = 2 * rn;
+      rn -= tp[rn - 1] == 0;
+      ign <<= 1;
+
+      off = 0;
+      if (rn > prec)
+	{
+	  ign += rn - prec;
+	  off = rn - prec;
+	  rn = prec;
+	}
+      MP_PTR_SWAP (rp, tp);
+
+      if (((exp >> i) & 1) != 0)
+	{
+	  mp_limb_t cy;
+	  cy = mpn_mul_1 (rp, rp + off, rn, base);
+	  rp[rn] = cy;
+	  rn += cy != 0;
+	  off = 0;
+	}
+    }
+
+  if (rn > prec)
+    {
+      ASSERT (rn == prec + 1);
+
+      ign += rn - prec;
+      rp += rn - prec;
+      rn = prec;
+    }
+
+  /* With somewhat less than 50% probability, we can skip this copy.  */
+  if (passed_rp != rp + off)
+    MPN_COPY_INCR (passed_rp, rp + off, rn);
+  *ignp = ign;
+  return rn;
+}
+
+char *
+mpf_get_str (char *dbuf, mp_exp_t *exp, int base, size_t n_digits, mpf_srcptr u)
+{
+  mp_exp_t ue;
+  mp_size_t n_limbs_needed;
+  size_t max_digits;
+  mp_ptr up, pp, tp;
+  mp_size_t un, pn, tn;
+  unsigned char *tstr;
+  mp_exp_t exp_in_base;
+  size_t n_digits_computed;
+  mp_size_t i;
+  const char *num_to_text;
+  size_t alloc_size = 0;
+  char *dp;
+  TMP_DECL;
+
+  up = PTR(u);
+  un = ABSIZ(u);
+  ue = EXP(u);
+
+  num_to_text = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+  if (base > 1)
+    {
+      if (base <= 36)
+	num_to_text = "0123456789abcdefghijklmnopqrstuvwxyz";
+      else if (UNLIKELY (base > 62))
+	    return NULL;
+    }
+  else if (base > -2)
+    {
+      base = 10;
+    }
+  else
+    {
+      base = -base;
+      if (UNLIKELY (base > 36))
+	return NULL;
+    }
+
+  MPF_SIGNIFICANT_DIGITS (max_digits, base, PREC(u));
+  if (n_digits == 0 || n_digits > max_digits)
+    n_digits = max_digits;
+
+  if (dbuf == 0)
+    {
+      /* We didn't get a string from the user.  Allocate one (and return
+	 a pointer to it) with space for `-' and terminating null.  */
+      alloc_size = n_digits + 2;
+      dbuf = __GMP_ALLOCATE_FUNC_TYPE (n_digits + 2, char);
+    }
+
+  if (un == 0)
+    {
+      *exp = 0;
+      *dbuf = 0;
+      n_digits = 0;
+      goto done;
+    }
+
+  TMP_MARK;
+
+  /* Allocate temporary digit space.  We can't put digits directly in the user
+     area, since we generate more digits than requested.  (We allocate
+     2 * GMP_LIMB_BITS extra bytes because of the digit block nature of the
+     conversion.)  */
+  tstr = (unsigned char *) TMP_ALLOC (n_digits + 2 * GMP_LIMB_BITS + 3);
+
+  LIMBS_PER_DIGIT_IN_BASE (n_limbs_needed, n_digits, base);
+
+  if (un > n_limbs_needed)
+    {
+      up += un - n_limbs_needed;
+      un = n_limbs_needed;
+    }
+
+  TMP_ALLOC_LIMBS_2 (pp, 2 * n_limbs_needed + 4,
+		     tp, 2 * n_limbs_needed + 4);
+
+  if (ue <= n_limbs_needed)
+    {
+      /* We need to multiply number by base^n to get an n_digits integer part.  */
+      mp_size_t n_more_limbs_needed, ign, off;
+      unsigned long e;
+
+      n_more_limbs_needed = n_limbs_needed - ue;
+      DIGITS_IN_BASE_PER_LIMB (e, n_more_limbs_needed, base);
+
+      pn = mpn_pow_1_highpart (pp, &ign, (mp_limb_t) base, e, n_limbs_needed + 1, tp);
+      if (un > pn)
+	mpn_mul (tp, up, un, pp, pn);	/* FIXME: mpn_mul_highpart */
+      else
+	mpn_mul (tp, pp, pn, up, un);	/* FIXME: mpn_mul_highpart */
+      tn = un + pn;
+      tn -= tp[tn - 1] == 0;
+      off = un - ue - ign;
+      if (off < 0)
+	{
+	  MPN_COPY_DECR (tp - off, tp, tn);
+	  MPN_ZERO (tp, -off);
+	  tn -= off;
+	  off = 0;
+	}
+      n_digits_computed = mpn_get_str (tstr, base, tp + off, tn - off);
+
+      exp_in_base = n_digits_computed - e;
+    }
+  else
+    {
+      /* We need to divide number by base^n to get an n_digits integer part.  */
+      mp_size_t n_less_limbs_needed, ign, off, xn;
+      unsigned long e;
+      mp_ptr dummyp, xp;
+
+      n_less_limbs_needed = ue - n_limbs_needed;
+      DIGITS_IN_BASE_PER_LIMB (e, n_less_limbs_needed, base);
+
+      pn = mpn_pow_1_highpart (pp, &ign, (mp_limb_t) base, e, n_limbs_needed + 1, tp);
+
+      xn = n_limbs_needed + (n_less_limbs_needed-ign);
+      xp = TMP_ALLOC_LIMBS (xn);
+      off = xn - un;
+      MPN_ZERO (xp, off);
+      MPN_COPY (xp + off, up, un);
+
+      dummyp = TMP_ALLOC_LIMBS (pn);
+      mpn_tdiv_qr (tp, dummyp, (mp_size_t) 0, xp, xn, pp, pn);
+      tn = xn - pn + 1;
+      tn -= tp[tn - 1] == 0;
+      n_digits_computed = mpn_get_str (tstr, base, tp, tn);
+
+      exp_in_base = n_digits_computed + e;
+    }
+
+  /* We should normally have computed too many digits.  Round the result
+     at the point indicated by n_digits.  */
+  if (n_digits_computed > n_digits)
+    {
+      size_t i;
+      /* Round the result.  */
+      if (tstr[n_digits] * 2 >= base)
+	{
+	  n_digits_computed = n_digits;
+	  for (i = n_digits - 1;; i--)
+	    {
+	      unsigned int x;
+	      x = ++(tstr[i]);
+	      if (x != base)
+		break;
+	      n_digits_computed--;
+	      if (i == 0)
+		{
+		  /* We had something like `bbbbbbb...bd', where 2*d >= base
+		     and `b' denotes digit with significance base - 1.
+		     This rounds up to `1', increasing the exponent.  */
+		  tstr[0] = 1;
+		  n_digits_computed = 1;
+		  exp_in_base++;
+		  break;
+		}
+	    }
+	}
+    }
+
+  /* We might have fewer digits than requested as a result of rounding above,
+     (i.e. 0.999999 => 1.0) or because we have a number that simply doesn't
+     need many digits in this base (e.g., 0.125 in base 10).  */
+  if (n_digits > n_digits_computed)
+    n_digits = n_digits_computed;
+
+  /* Remove trailing 0.  There can be many zeros.  */
+  while (n_digits != 0 && tstr[n_digits - 1] == 0)
+    n_digits--;
+
+  dp = dbuf + (SIZ(u) < 0);
+
+  /* Translate to ASCII and copy to result string.  */
+  for (i = 0; i < n_digits; i++)
+    dp[i] = num_to_text[tstr[i]];
+  dp[n_digits] = 0;
+
+  *exp = exp_in_base;
+
+  if (SIZ(u) < 0)
+    {
+      dbuf[0] = '-';
+      n_digits++;
+    }
+
+  TMP_FREE;
+
+ done:
+  /* If the string was alloced then resize it down to the actual space
+     required.  */
+  if (alloc_size != 0)
+    {
+      __GMP_REALLOCATE_FUNC_MAYBE_TYPE (dbuf, alloc_size, n_digits + 1, char);
+    }
+
+  return dbuf;
+}
diff --git a/third_party/gmp/mpf/get_ui.c b/third_party/gmp/mpf/get_ui.c
new file mode 100644
index 0000000..e7b9333
--- /dev/null
+++ b/third_party/gmp/mpf/get_ui.c
@@ -0,0 +1,101 @@
+/* mpf_get_ui -- mpf to ulong conversion
+
+Copyright 2001, 2002, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* Any fraction bits are truncated, meaning simply discarded.
+
+   For values bigger than a ulong, the low bits are returned (the low
+   absolute value bits actually), like mpz_get_ui, but this isn't
+   documented.
+
+   Notice this is equivalent to mpz_set_f + mpz_get_ui.
+
+
+   Implementation:
+
+   The limb just above the radix point for us to extract is ptr[size-exp].
+
+   We need to check that the size-exp index falls in our available data
+   range, 0 to size-1 inclusive.  We test this without risk of an overflow
+   involving exp by requiring size>=exp (giving size-exp >= 0) and exp>0
+   (giving size-exp <= size-1).
+
+   Notice if size==0 there's no fetch, since of course size>=exp and exp>0
+   can only be true if size>0.  So there's no special handling for size==0,
+   it comes out as 0 the same as any other time we have no data at our
+   target index.
+
+   For nails, the second limb above the radix point is also required, this
+   is ptr[size-exp+1].
+
+   Again we need to check that size-exp+1 falls in our data range, 0 to
+   size-1 inclusive.  We test without risk of overflow by requiring
+   size+1>=exp (giving size-exp+1 >= 0) and exp>1 (giving size-exp+1 <=
+   size-1).
+
+   And again if size==0 these second fetch conditions are not satisfied
+   either since size+1>=exp and exp>1 are only true if size>0.
+
+   The code is arranged with exp>0 wrapping the exp>1 test since exp>1 is
+   mis-compiled by alpha gcc prior to version 3.4.  It re-writes it as
+   exp-1>0, which is incorrect when exp==MP_EXP_T_MIN.  By having exp>0
+   tested first we ensure MP_EXP_T_MIN doesn't reach exp>1.  */
+
+unsigned long
+mpf_get_ui (mpf_srcptr f) __GMP_NOTHROW
+{
+  mp_size_t size;
+  mp_exp_t exp;
+  mp_srcptr fp;
+  mp_limb_t fl;
+
+  exp = EXP (f);
+  size = SIZ (f);
+  fp = PTR (f);
+
+  fl = 0;
+  if (exp > 0)
+    {
+      /* there are some limbs above the radix point */
+
+      size = ABS (size);
+      if (size >= exp)
+        fl = fp[size-exp];
+
+#if BITS_PER_ULONG > GMP_NUMB_BITS
+      if (exp > 1 && size+1 >= exp)
+        fl += (fp[size-exp+1] << GMP_NUMB_BITS);
+#endif
+    }
+
+  return (unsigned long) fl;
+}
diff --git a/third_party/gmp/mpf/init.c b/third_party/gmp/mpf/init.c
new file mode 100644
index 0000000..26ab262
--- /dev/null
+++ b/third_party/gmp/mpf/init.c
@@ -0,0 +1,41 @@
+/* mpf_init() -- Make a new multiple precision number with value 0.
+
+Copyright 1993-1995, 2000, 2001, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpf_init (mpf_ptr r)
+{
+  mp_size_t prec = __gmp_default_fp_limb_precision;
+  r->_mp_size = 0;
+  r->_mp_exp = 0;
+  r->_mp_prec = prec;
+  r->_mp_d = __GMP_ALLOCATE_FUNC_LIMBS (prec + 1);
+}
diff --git a/third_party/gmp/mpf/init2.c b/third_party/gmp/mpf/init2.c
new file mode 100644
index 0000000..b90a08a
--- /dev/null
+++ b/third_party/gmp/mpf/init2.c
@@ -0,0 +1,43 @@
+/* mpf_init2() -- Make a new multiple precision number with value 0.
+
+Copyright 1993-1995, 2000, 2001, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpf_init2 (mpf_ptr r, mp_bitcnt_t prec_in_bits)
+{
+  mp_size_t prec;
+
+  prec = __GMPF_BITS_TO_PREC (prec_in_bits);
+  r->_mp_size = 0;
+  r->_mp_exp = 0;
+  r->_mp_prec = prec;
+  r->_mp_d = __GMP_ALLOCATE_FUNC_LIMBS (prec + 1);
+}
diff --git a/third_party/gmp/mpf/inits.c b/third_party/gmp/mpf/inits.c
new file mode 100644
index 0000000..b6d054f
--- /dev/null
+++ b/third_party/gmp/mpf/inits.c
@@ -0,0 +1,49 @@
+/* mpf_inits() -- Initialize multiple mpf_t variables and set them to 0.
+
+Copyright 2009, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+#include "gmp-impl.h"
+
+void
+mpf_inits (mpf_ptr x, ...)
+{
+  va_list  ap;
+
+  va_start (ap, x);
+
+  do
+    {
+      mpf_init (x);
+      x = va_arg (ap, mpf_ptr);
+    }
+  while (x != NULL);
+
+  va_end (ap);
+}
diff --git a/third_party/gmp/mpf/inp_str.c b/third_party/gmp/mpf/inp_str.c
new file mode 100644
index 0000000..c661a79
--- /dev/null
+++ b/third_party/gmp/mpf/inp_str.c
@@ -0,0 +1,92 @@
+/* mpf_inp_str(dest_float, stream, base) -- Input a number in base
+   BASE from stdio stream STREAM and store the result in DEST_FLOAT.
+
+Copyright 1996, 2000-2002, 2005 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <ctype.h>
+#include "gmp-impl.h"
+
+size_t
+mpf_inp_str (mpf_ptr rop, FILE *stream, int base)
+{
+  char *str;
+  size_t alloc_size, str_size;
+  int c;
+  int res;
+  size_t nread;
+
+  if (stream == 0)
+    stream = stdin;
+
+  alloc_size = 100;
+  str = __GMP_ALLOCATE_FUNC_TYPE (alloc_size, char);
+  str_size = 0;
+  nread = 0;
+
+  /* Skip whitespace.  */
+  do
+    {
+      c = getc (stream);
+      nread++;
+    }
+  while (isspace (c));
+
+  for (;;)
+    {
+      if (str_size >= alloc_size)
+	{
+	  size_t old_alloc_size = alloc_size;
+	  alloc_size = alloc_size * 3 / 2;
+	  str = __GMP_REALLOCATE_FUNC_TYPE (str, old_alloc_size, alloc_size, char);
+	}
+      if (c == EOF || isspace (c))
+	break;
+      str[str_size++] = c;
+      c = getc (stream);
+    }
+  ungetc (c, stream);
+  nread--;
+
+  if (str_size >= alloc_size)
+    {
+      size_t old_alloc_size = alloc_size;
+      alloc_size = alloc_size * 3 / 2;
+      str = __GMP_REALLOCATE_FUNC_TYPE (str, old_alloc_size, alloc_size, char);
+    }
+  str[str_size] = 0;
+
+  res = mpf_set_str (rop, str, base);
+  (*__gmp_free_func) (str, alloc_size);
+
+  if (res == -1)
+    return 0;			/* error */
+
+  return str_size + nread;
+}
diff --git a/third_party/gmp/mpf/int_p.c b/third_party/gmp/mpf/int_p.c
new file mode 100644
index 0000000..024cfb5
--- /dev/null
+++ b/third_party/gmp/mpf/int_p.c
@@ -0,0 +1,55 @@
+/* mpf_integer_p -- test whether an mpf is an integer */
+
+/*
+Copyright 2001, 2002, 2014-2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+int
+mpf_integer_p (mpf_srcptr f) __GMP_NOTHROW
+{
+  mp_srcptr fp;
+  mp_exp_t exp;
+  mp_size_t size;
+
+  size = SIZ (f);
+  exp = EXP (f);
+  if (exp <= 0)
+    return (size == 0);  /* zero is an integer,
+			    others have only fraction limbs */
+  size = ABS (size);
+
+  /* Ignore zeroes at the low end of F.  */
+  for (fp = PTR (f); *fp == 0; ++fp)
+    --size;
+
+  /* no fraction limbs */
+  return size <= exp;
+}
diff --git a/third_party/gmp/mpf/iset.c b/third_party/gmp/mpf/iset.c
new file mode 100644
index 0000000..07f9006
--- /dev/null
+++ b/third_party/gmp/mpf/iset.c
@@ -0,0 +1,61 @@
+/* mpf_init_set -- Initialize a float and assign it from another float.
+
+Copyright 1993-1995, 2000, 2001, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpf_init_set (mpf_ptr r, mpf_srcptr s)
+{
+  mp_ptr rp, sp;
+  mp_size_t ssize, size;
+  mp_size_t prec;
+
+  prec = __gmp_default_fp_limb_precision;
+  r->_mp_d = __GMP_ALLOCATE_FUNC_LIMBS (prec + 1);
+  r->_mp_prec = prec;
+
+  prec++;		/* lie not to lose precision in assignment */
+  ssize = s->_mp_size;
+  size = ABS (ssize);
+
+  rp = r->_mp_d;
+  sp = s->_mp_d;
+
+  if (size > prec)
+    {
+      sp += size - prec;
+      size = prec;
+    }
+
+  r->_mp_exp = s->_mp_exp;
+  r->_mp_size = ssize >= 0 ? size : -size;
+
+  MPN_COPY (rp, sp, size);
+}
diff --git a/third_party/gmp/mpf/iset_d.c b/third_party/gmp/mpf/iset_d.c
new file mode 100644
index 0000000..2f36240
--- /dev/null
+++ b/third_party/gmp/mpf/iset_d.c
@@ -0,0 +1,41 @@
+/* mpf_init_set_d -- Initialize a float and assign it from a double.
+
+Copyright 1993-1995, 2000, 2001, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpf_init_set_d (mpf_ptr r, double val)
+{
+  mp_size_t prec = __gmp_default_fp_limb_precision;
+  r->_mp_prec = prec;
+  r->_mp_d = __GMP_ALLOCATE_FUNC_LIMBS (prec + 1);
+
+  mpf_set_d (r, val);
+}
diff --git a/third_party/gmp/mpf/iset_si.c b/third_party/gmp/mpf/iset_si.c
new file mode 100644
index 0000000..65abb9a
--- /dev/null
+++ b/third_party/gmp/mpf/iset_si.c
@@ -0,0 +1,57 @@
+/* mpf_init_set_si() -- Initialize a float and assign it from a signed int.
+
+Copyright 1993-1995, 2000, 2001, 2003, 2004, 2012 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpf_init_set_si (mpf_ptr r, long int val)
+{
+  mp_size_t prec = __gmp_default_fp_limb_precision;
+  mp_size_t size;
+  mp_limb_t vl;
+
+  r->_mp_prec = prec;
+  r->_mp_d = __GMP_ALLOCATE_FUNC_LIMBS (prec + 1);
+
+  vl = (mp_limb_t) ABS_CAST (unsigned long int, val);
+
+  r->_mp_d[0] = vl & GMP_NUMB_MASK;
+  size = vl != 0;
+
+#if BITS_PER_ULONG > GMP_NUMB_BITS
+  vl >>= GMP_NUMB_BITS;
+  r->_mp_d[1] = vl;
+  size += (vl != 0);
+#endif
+
+  r->_mp_exp = size;
+  r->_mp_size = val >= 0 ? size : -size;
+}
diff --git a/third_party/gmp/mpf/iset_str.c b/third_party/gmp/mpf/iset_str.c
new file mode 100644
index 0000000..10acda9
--- /dev/null
+++ b/third_party/gmp/mpf/iset_str.c
@@ -0,0 +1,43 @@
+/* mpf_init_set_str -- Initialize a float and assign it from a string.
+
+Copyright 1995, 1996, 2000, 2001, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+int
+mpf_init_set_str (mpf_ptr r, const char *s, int base)
+{
+  mp_size_t prec = __gmp_default_fp_limb_precision;
+  r->_mp_size = 0;
+  r->_mp_exp = 0;
+  r->_mp_prec = prec;
+  r->_mp_d = __GMP_ALLOCATE_FUNC_LIMBS (prec + 1);
+
+  return mpf_set_str (r, s, base);
+}
diff --git a/third_party/gmp/mpf/iset_ui.c b/third_party/gmp/mpf/iset_ui.c
new file mode 100644
index 0000000..2c426bf
--- /dev/null
+++ b/third_party/gmp/mpf/iset_ui.c
@@ -0,0 +1,52 @@
+/* mpf_init_set_ui() -- Initialize a float and assign it from an unsigned int.
+
+Copyright 1993-1995, 2000, 2001, 2003, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpf_init_set_ui (mpf_ptr r, unsigned long int val)
+{
+  mp_size_t prec = __gmp_default_fp_limb_precision;
+  mp_size_t size;
+
+  r->_mp_prec = prec;
+  r->_mp_d = __GMP_ALLOCATE_FUNC_LIMBS (prec + 1);
+  r->_mp_d[0] = val & GMP_NUMB_MASK;
+  size = (val != 0);
+
+#if BITS_PER_ULONG > GMP_NUMB_BITS
+  val >>= GMP_NUMB_BITS;
+  r->_mp_d[1] = val;
+  size += (val != 0);
+#endif
+
+  r->_mp_size = size;
+  r->_mp_exp = size;
+}
diff --git a/third_party/gmp/mpf/mul.c b/third_party/gmp/mpf/mul.c
new file mode 100644
index 0000000..3099461
--- /dev/null
+++ b/third_party/gmp/mpf/mul.c
@@ -0,0 +1,134 @@
+/* mpf_mul -- Multiply two floats.
+
+Copyright 1993, 1994, 1996, 2001, 2005, 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpf_mul (mpf_ptr r, mpf_srcptr u, mpf_srcptr v)
+{
+  mp_size_t sign_product;
+  mp_size_t prec = r->_mp_prec;
+  mp_size_t rsize;
+  mp_limb_t cy_limb;
+  mp_ptr rp, tp;
+  mp_size_t adj;
+  TMP_DECL;
+
+  if (u == v)
+    {
+      mp_srcptr up;
+      mp_size_t usize;
+
+      usize = u->_mp_size;
+      sign_product = 0;
+
+      usize = ABS (usize);
+
+      up = u->_mp_d;
+      if (usize > prec)
+	{
+	  up += usize - prec;
+	  usize = prec;
+	}
+
+      if (usize == 0)
+	{
+	  r->_mp_size = 0;
+	  r->_mp_exp = 0;		/* ??? */
+	  return;
+	}
+      else
+	{
+	  TMP_MARK;
+	  rsize = 2 * usize;
+	  tp = TMP_ALLOC_LIMBS (rsize);
+
+	  mpn_sqr (tp, up, usize);
+	  cy_limb = tp[rsize - 1];
+	}
+    }
+  else
+    {
+      mp_srcptr up, vp;
+      mp_size_t usize, vsize;
+
+      usize = u->_mp_size;
+      vsize = v->_mp_size;
+      sign_product = usize ^ vsize;
+
+      usize = ABS (usize);
+      vsize = ABS (vsize);
+
+      up = u->_mp_d;
+      vp = v->_mp_d;
+      if (usize > prec)
+	{
+	  up += usize - prec;
+	  usize = prec;
+	}
+      if (vsize > prec)
+	{
+	  vp += vsize - prec;
+	  vsize = prec;
+	}
+
+      if (usize == 0 || vsize == 0)
+	{
+	  r->_mp_size = 0;
+	  r->_mp_exp = 0;
+	  return;
+	}
+      else
+	{
+	  TMP_MARK;
+	  rsize = usize + vsize;
+	  tp = TMP_ALLOC_LIMBS (rsize);
+	  cy_limb = (usize >= vsize
+		     ? mpn_mul (tp, up, usize, vp, vsize)
+		     : mpn_mul (tp, vp, vsize, up, usize));
+
+	}
+    }
+
+  adj = cy_limb == 0;
+  rsize -= adj;
+  prec++;
+  if (rsize > prec)
+    {
+      tp += rsize - prec;
+      rsize = prec;
+    }
+  rp = r->_mp_d;
+  MPN_COPY (rp, tp, rsize);
+  r->_mp_exp = u->_mp_exp + v->_mp_exp - adj;
+  r->_mp_size = sign_product >= 0 ? rsize : -rsize;
+
+  TMP_FREE;
+}
diff --git a/third_party/gmp/mpf/mul_2exp.c b/third_party/gmp/mpf/mul_2exp.c
new file mode 100644
index 0000000..5de7363
--- /dev/null
+++ b/third_party/gmp/mpf/mul_2exp.c
@@ -0,0 +1,132 @@
+/* mpf_mul_2exp -- Multiply a float by 2^n.
+
+Copyright 1993, 1994, 1996, 2000-2002, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* Multiples of GMP_NUMB_BITS in exp simply mean an amount added to EXP(u)
+   to set EXP(r).  The remainder exp%GMP_NUMB_BITS is then a left shift for
+   the limb data.
+
+   If exp%GMP_NUMB_BITS == 0 then there's no shifting, we effectively just
+   do an mpz_set with changed EXP(r).  Like mpz_set we take prec+1 limbs in
+   this case.  Although just prec would suffice, it's nice to have
+   mpf_mul_2exp with exp==0 come out the same as mpz_set.
+
+   When shifting we take up to prec many limbs from the input.  Our shift is
+   cy = mpn_lshift (PTR(r), PTR(u)+k, size, ...), where k is the number of
+   low limbs dropped from u, and the carry out is stored to PTR(r)[size].
+
+   It may be noted that the low limb PTR(r)[0] doesn't incorporate bits from
+   PTR(u)[k-1] (when k>=1 makes that limb available).  Taking just prec
+   limbs from the input (with the high non-zero) is enough bits for the
+   application requested precision, there's no need for extra work.
+
+   If r==u the shift will have overlapping operands.  When k==0 (ie. when
+   usize <= prec), the overlap is supported by lshift (ie. dst == src).
+
+   But when r==u and k>=1 (ie. usize > prec), we would have an invalid
+   overlap (ie. mpn_lshift (rp, rp+k, ...)).  In this case we must instead
+   use mpn_rshift (PTR(r)+1, PTR(u)+k, size, NUMB-shift) with the carry out
+   stored to PTR(r)[0].  An rshift by NUMB-shift bits like this gives
+   identical data, it's just its overlap restrictions which differ.
+
+   Enhancements:
+
+   The way mpn_lshift is used means successive mpf_mul_2exp calls on the
+   same operand will accumulate low zero limbs, until prec+1 limbs is
+   reached.  This is wasteful for subsequent operations.  When abs_usize <=
+   prec, we should test the low exp%GMP_NUMB_BITS many bits of PTR(u)[0],
+   ie. those which would be shifted out by an mpn_rshift.  If they're zero
+   then use that mpn_rshift.  */
+
+void
+mpf_mul_2exp (mpf_ptr r, mpf_srcptr u, mp_bitcnt_t exp)
+{
+  mp_srcptr up;
+  mp_ptr rp = r->_mp_d;
+  mp_size_t usize;
+  mp_size_t abs_usize;
+  mp_size_t prec = r->_mp_prec;
+  mp_exp_t uexp = u->_mp_exp;
+
+  usize = u->_mp_size;
+
+  if (UNLIKELY (usize == 0))
+    {
+      r->_mp_size = 0;
+      r->_mp_exp = 0;
+      return;
+    }
+
+  abs_usize = ABS (usize);
+  up = u->_mp_d;
+
+  if (exp % GMP_NUMB_BITS == 0)
+    {
+      prec++;			/* retain more precision here as we don't need
+				   to account for carry-out here */
+      if (abs_usize > prec)
+	{
+	  up += abs_usize - prec;
+	  abs_usize = prec;
+	}
+      if (rp != up)
+	MPN_COPY_INCR (rp, up, abs_usize);
+      r->_mp_exp = uexp + exp / GMP_NUMB_BITS;
+    }
+  else
+    {
+      mp_limb_t cy_limb;
+      mp_size_t adj;
+      if (abs_usize > prec)
+	{
+	  up += abs_usize - prec;
+	  abs_usize = prec;
+	  /* Use mpn_rshift since mpn_lshift operates downwards, and we
+	     therefore would clobber part of U before using that part, in case
+	     R is the same variable as U.  */
+	  cy_limb = mpn_rshift (rp + 1, up, abs_usize,
+				GMP_NUMB_BITS - exp % GMP_NUMB_BITS);
+	  rp[0] = cy_limb;
+	  adj = rp[abs_usize] != 0;
+	}
+      else
+	{
+	  cy_limb = mpn_lshift (rp, up, abs_usize, exp % GMP_NUMB_BITS);
+	  rp[abs_usize] = cy_limb;
+	  adj = cy_limb != 0;
+	}
+
+      abs_usize += adj;
+      r->_mp_exp = uexp + exp / GMP_NUMB_BITS + adj;
+    }
+  r->_mp_size = usize >= 0 ? abs_usize : -abs_usize;
+}
diff --git a/third_party/gmp/mpf/mul_ui.c b/third_party/gmp/mpf/mul_ui.c
new file mode 100644
index 0000000..30da6ae
--- /dev/null
+++ b/third_party/gmp/mpf/mul_ui.c
@@ -0,0 +1,181 @@
+/* mpf_mul_ui -- Multiply a float and an unsigned integer.
+
+Copyright 1993, 1994, 1996, 2001, 2003, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* The core operation is a multiply of PREC(r) limbs from u by v, producing
+   either PREC(r) or PREC(r)+1 result limbs.  If u is shorter than PREC(r),
+   then we take only as much as it has.  If u is longer we incorporate a
+   carry from the lower limbs.
+
+   If u has just 1 extra limb, then the carry to add is high(up[0]*v).  That
+   is of course what mpn_mul_1 would do if it was called with PREC(r)+1
+   limbs of input.
+
+   If u has more than 1 extra limb, then there can be a further carry bit
+   out of lower uncalculated limbs (the way the low of one product adds to
+   the high of the product below it).  This is of course what an mpn_mul_1
+   would do if it was called with the full u operand.  But we instead work
+   downwards explicitly, until a carry occurs or until a value other than
+   GMP_NUMB_MAX occurs (that being the only value a carry bit can propagate
+   across).
+
+   The carry determination normally requires two umul_ppmm's, only rarely
+   will GMP_NUMB_MAX occur and require further products.
+
+   The carry limb is conveniently added into the mul_1 using mpn_mul_1c when
+   that function exists, otherwise a subsequent mpn_add_1 is needed.
+
+   Clearly when mpn_mul_1c is used the carry must be calculated first.  But
+   this is also the case when add_1 is used, since if r==u and ABSIZ(r) >
+   PREC(r) then the mpn_mul_1 overwrites the low part of the input.
+
+   A reuse r==u with size > prec can occur from a size PREC(r)+1 in the
+   usual way, or it can occur from an mpf_set_prec_raw leaving a bigger
+   sized value.  In both cases we can end up calling mpn_mul_1 with
+   overlapping src and dst regions, but this will be with dst < src and such
+   an overlap is permitted.
+
+   Not done:
+
+   No attempt is made to determine in advance whether the result will be
+   PREC(r) or PREC(r)+1 limbs.  If it's going to be PREC(r)+1 then we could
+   take one less limb from u and generate just PREC(r), that of course
+   satisfying application requested precision.  But any test counting bits
+   or forming the high product would almost certainly take longer than the
+   incremental cost of an extra limb in mpn_mul_1.
+
+   Enhancements:
+
+   Repeated mpf_mul_ui's with an even v will accumulate low zero bits on the
+   result, leaving low zero limbs after a while, which it might be nice to
+   strip to save work in subsequent operations.  Calculating the low limb
+   explicitly would let us direct mpn_mul_1 to put the balance at rp when
+   the low is zero (instead of normally rp+1).  But it's not clear whether
+   this would be worthwhile.  Explicit code for the low limb will probably
+   be slower than having it done in mpn_mul_1, so we need to consider how
+   often a zero will be stripped and how much that's likely to save
+   later.  */
+
+void
+mpf_mul_ui (mpf_ptr r, mpf_srcptr u, unsigned long int v)
+{
+  mp_srcptr up;
+  mp_size_t usize;
+  mp_size_t size;
+  mp_size_t prec, excess;
+  mp_limb_t cy_limb, vl, cbit, cin;
+  mp_ptr rp;
+
+  usize = u->_mp_size;
+  if (UNLIKELY (v == 0) || UNLIKELY (usize == 0))
+    {
+      r->_mp_size = 0;
+      r->_mp_exp = 0;
+      return;
+    }
+
+#if BITS_PER_ULONG > GMP_NUMB_BITS  /* avoid warnings about shift amount */
+  if (v > GMP_NUMB_MAX)
+    {
+      mpf_t     vf;
+      mp_limb_t vp[2];
+      vp[0] = v & GMP_NUMB_MASK;
+      vp[1] = v >> GMP_NUMB_BITS;
+      PTR(vf) = vp;
+      SIZ(vf) = 2;
+      ASSERT_CODE (PREC(vf) = 2);
+      EXP(vf) = 2;
+      mpf_mul (r, u, vf);
+      return;
+    }
+#endif
+
+  size = ABS (usize);
+  prec = r->_mp_prec;
+  up = u->_mp_d;
+  vl = v;
+  excess = size - prec;
+  cin = 0;
+
+  if (excess > 0)
+    {
+      /* up is bigger than desired rp, shorten it to prec limbs and
+         determine a carry-in */
+
+      mp_limb_t  vl_shifted = vl << GMP_NAIL_BITS;
+      mp_limb_t  hi, lo, next_lo, sum;
+      mp_size_t  i;
+
+      /* high limb of top product */
+      i = excess - 1;
+      umul_ppmm (cin, lo, up[i], vl_shifted);
+
+      /* and carry bit out of products below that, if any */
+      for (;;)
+        {
+          i--;
+          if (i < 0)
+            break;
+
+          umul_ppmm (hi, next_lo, up[i], vl_shifted);
+          lo >>= GMP_NAIL_BITS;
+          ADDC_LIMB (cbit, sum, hi, lo);
+          cin += cbit;
+          lo = next_lo;
+
+          /* Continue only if the sum is GMP_NUMB_MAX.  GMP_NUMB_MAX is the
+             only value a carry from below can propagate across.  If we've
+             just seen the carry out (ie. cbit!=0) then sum!=GMP_NUMB_MAX,
+             so this test stops us for that case too.  */
+          if (LIKELY (sum != GMP_NUMB_MAX))
+            break;
+        }
+
+      up += excess;
+      size = prec;
+    }
+
+  rp = r->_mp_d;
+#if HAVE_NATIVE_mpn_mul_1c
+  cy_limb = mpn_mul_1c (rp, up, size, vl, cin);
+#else
+  cy_limb = mpn_mul_1 (rp, up, size, vl);
+  __GMPN_ADD_1 (cbit, rp, rp, size, cin);
+  cy_limb += cbit;
+#endif
+  rp[size] = cy_limb;
+  cy_limb = cy_limb != 0;
+  r->_mp_exp = u->_mp_exp + cy_limb;
+  size += cy_limb;
+  r->_mp_size = usize >= 0 ? size : -size;
+}
diff --git a/third_party/gmp/mpf/neg.c b/third_party/gmp/mpf/neg.c
new file mode 100644
index 0000000..d294815
--- /dev/null
+++ b/third_party/gmp/mpf/neg.c
@@ -0,0 +1,61 @@
+/* mpf_neg -- Negate a float.
+
+Copyright 1993-1995, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpf_neg (mpf_ptr r, mpf_srcptr u)
+{
+  mp_size_t size;
+
+  size = -u->_mp_size;
+  if (r != u)
+    {
+      mp_size_t prec;
+      mp_size_t asize;
+      mp_ptr rp, up;
+
+      prec = r->_mp_prec + 1;	/* lie not to lose precision in assignment */
+      asize = ABS (size);
+      rp = r->_mp_d;
+      up = u->_mp_d;
+
+      if (asize > prec)
+	{
+	  up += asize - prec;
+	  asize = prec;
+	}
+
+      MPN_COPY (rp, up, asize);
+      r->_mp_exp = u->_mp_exp;
+      size = size >= 0 ? asize : -asize;
+    }
+  r->_mp_size = size;
+}
diff --git a/third_party/gmp/mpf/out_str.c b/third_party/gmp/mpf/out_str.c
new file mode 100644
index 0000000..1802d0f
--- /dev/null
+++ b/third_party/gmp/mpf/out_str.c
@@ -0,0 +1,116 @@
+/* mpf_out_str (stream, base, n_digits, op) -- Print N_DIGITS digits from
+   the float OP to STREAM in base BASE.  Return the number of characters
+   written, or 0 if an error occurred.
+
+Copyright 1996, 1997, 2001, 2002, 2005, 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define _GNU_SOURCE    /* for DECIMAL_POINT in langinfo.h */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#if HAVE_LANGINFO_H
+#include <langinfo.h>  /* for nl_langinfo */
+#endif
+
+#if HAVE_LOCALE_H
+#include <locale.h>    /* for localeconv */
+#endif
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+size_t
+mpf_out_str (FILE *stream, int base, size_t n_digits, mpf_srcptr op)
+{
+  char *str;
+  mp_exp_t exp;
+  size_t written;
+  TMP_DECL;
+
+  TMP_MARK;
+
+  if (base == 0)
+    base = 10;
+  if (n_digits == 0)
+    MPF_SIGNIFICANT_DIGITS (n_digits, base, op->_mp_prec);
+
+  if (stream == 0)
+    stream = stdout;
+
+  /* Consider these changes:
+     * Don't allocate memory here for huge n_digits; pass NULL to mpf_get_str.
+     * Make mpf_get_str allocate extra space when passed NULL, to avoid
+       allocating two huge string buffers.
+     * Implement more/other allocation reductions tricks.  */
+
+  str = (char *) TMP_ALLOC (n_digits + 2); /* extra for minus sign and \0 */
+
+  mpf_get_str (str, &exp, base, n_digits, op);
+  n_digits = strlen (str);
+
+  written = 0;
+
+  /* Write sign */
+  if (str[0] == '-')
+    {
+      str++;
+      fputc ('-', stream);
+      written = 1;
+      n_digits--;
+    }
+
+  {
+    const char  *point = GMP_DECIMAL_POINT;
+    size_t      pointlen = strlen (point);
+    putc ('0', stream);
+    fwrite (point, 1, pointlen, stream);
+    written += pointlen + 1;
+  }
+
+  /* Write mantissa */
+  {
+    size_t fwret;
+    fwret = fwrite (str, 1, n_digits, stream);
+    written += fwret;
+  }
+
+  /* Write exponent */
+  {
+    int fpret;
+    fpret = fprintf (stream, (base <= 10 ? "e%ld" : "@%ld"), exp);
+    written += fpret;
+  }
+
+  TMP_FREE;
+  return ferror (stream) ? 0 : written;
+}
diff --git a/third_party/gmp/mpf/pow_ui.c b/third_party/gmp/mpf/pow_ui.c
new file mode 100644
index 0000000..8d54dc0
--- /dev/null
+++ b/third_party/gmp/mpf/pow_ui.c
@@ -0,0 +1,83 @@
+/* mpf_pow_ui -- Compute b^e.
+
+Copyright 1998, 1999, 2001, 2012, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/* This uses a plain right-to-left square-and-multiply algorithm.
+
+   FIXME: When popcount(e) is not too small, it would probably speed things up
+   to use a k-ary sliding window algorithm.  */
+
+void
+mpf_pow_ui (mpf_ptr r, mpf_srcptr b, unsigned long int e)
+{
+  mpf_t t;
+  int cnt;
+
+  if (e <= 1)
+    {
+      if (e == 0)
+	mpf_set_ui (r, 1);
+      else
+	mpf_set (r, b);
+      return;
+    }
+
+  count_leading_zeros (cnt, (mp_limb_t) e);
+  cnt = GMP_LIMB_BITS - 1 - cnt;
+
+  /* Increase computation precision as a function of the exponent.  Adding
+     log2(popcount(e) + log2(e)) bits should be sufficient, but we add log2(e),
+     i.e. much more.  With mpf's rounding of precision to whole limbs, this
+     will be excessive only when limbs are artificially small.  */
+  mpf_init2 (t, mpf_get_prec (r) + cnt);
+
+  mpf_set (t, b);		/* consume most significant bit */
+  while (--cnt > 0)
+    {
+      mpf_mul (t, t, t);
+      if ((e >> cnt) & 1)
+	mpf_mul (t, t, b);
+    }
+
+  /* Do the last iteration specially in order to save a copy operation.  */
+  if (e & 1)
+    {
+      mpf_mul (t, t, t);
+      mpf_mul (r, t, b);
+    }
+  else
+    {
+      mpf_mul (r, t, t);
+    }
+
+  mpf_clear (t);
+}
diff --git a/third_party/gmp/mpf/random2.c b/third_party/gmp/mpf/random2.c
new file mode 100644
index 0000000..2e0163c
--- /dev/null
+++ b/third_party/gmp/mpf/random2.c
@@ -0,0 +1,66 @@
+/* mpf_random2 -- Generate a positive random mpf_t of specified size, with
+   long runs of consecutive ones and zeros in the binary representation.
+   Intended for testing of other MP routines.
+
+Copyright 1995, 1996, 2001-2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+void
+mpf_random2 (mpf_ptr x, mp_size_t xs, mp_exp_t exp)
+{
+  mp_size_t xn;
+  mp_size_t prec;
+  mp_limb_t elimb;
+
+  xn = ABS (xs);
+  prec = PREC(x);
+
+  if (xn == 0)
+    {
+      EXP(x) = 0;
+      SIZ(x) = 0;
+      return;
+    }
+
+  if (xn > prec + 1)
+    xn = prec + 1;
+
+  /* General random mantissa.  */
+  mpn_random2 (PTR(x), xn);
+
+  /* Generate random exponent.  */
+  _gmp_rand (&elimb, RANDS, GMP_NUMB_BITS);
+  exp = ABS (exp);
+  exp = elimb % (2 * exp + 1) - exp;
+
+  EXP(x) = exp;
+  SIZ(x) = xs < 0 ? -xn : xn;
+}
diff --git a/third_party/gmp/mpf/reldiff.c b/third_party/gmp/mpf/reldiff.c
new file mode 100644
index 0000000..81f05dd
--- /dev/null
+++ b/third_party/gmp/mpf/reldiff.c
@@ -0,0 +1,64 @@
+/* mpf_reldiff -- Generate the relative difference of two floats.
+
+Copyright 1996, 2001, 2004, 2005 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* The precision we use for d = x-y is based on what mpf_div will want from
+   the dividend.  It calls mpn_div_q to produce a quotient of rprec+1 limbs.
+   So rprec+1 == dsize - xsize + 1, hence dprec = rprec+xsize.  */
+
+void
+mpf_reldiff (mpf_t rdiff, mpf_srcptr x, mpf_srcptr y)
+{
+  if (UNLIKELY (SIZ(x) == 0))
+    {
+      mpf_set_ui (rdiff, (unsigned long int) (mpf_sgn (y) != 0));
+    }
+  else
+    {
+      mp_size_t dprec;
+      mpf_t d;
+      TMP_DECL;
+
+      TMP_MARK;
+      dprec = PREC(rdiff) + ABSIZ(x);
+      ASSERT (PREC(rdiff)+1 == dprec - ABSIZ(x) + 1);
+
+      PREC(d) = dprec;
+      PTR(d) = TMP_ALLOC_LIMBS (dprec + 1);
+
+      mpf_sub (d, x, y);
+      SIZ(d) = ABSIZ(d);
+      mpf_div (rdiff, d, x);
+
+      TMP_FREE;
+    }
+}
diff --git a/third_party/gmp/mpf/set.c b/third_party/gmp/mpf/set.c
new file mode 100644
index 0000000..382fe86
--- /dev/null
+++ b/third_party/gmp/mpf/set.c
@@ -0,0 +1,55 @@
+/* mpf_set -- Assign a float from another float.
+
+Copyright 1993-1995, 2001, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpf_set (mpf_ptr r, mpf_srcptr u)
+{
+  mp_ptr rp, up;
+  mp_size_t size, asize;
+  mp_size_t prec;
+
+  prec = r->_mp_prec + 1;		/* lie not to lose precision in assignment */
+  size = u->_mp_size;
+  asize = ABS (size);
+  rp = r->_mp_d;
+  up = u->_mp_d;
+
+  if (asize > prec)
+    {
+      up += asize - prec;
+      asize = prec;
+    }
+
+  r->_mp_exp = u->_mp_exp;
+  r->_mp_size = size >= 0 ? asize : -asize;
+  MPN_COPY_INCR (rp, up, asize);
+}
diff --git a/third_party/gmp/mpf/set_d.c b/third_party/gmp/mpf/set_d.c
new file mode 100644
index 0000000..0442f2f
--- /dev/null
+++ b/third_party/gmp/mpf/set_d.c
@@ -0,0 +1,59 @@
+/* mpf_set_d -- Assign a float from a double.
+
+Copyright 1993-1996, 2001, 2003, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#if HAVE_FLOAT_H
+#include <float.h>  /* for DBL_MAX */
+#endif
+
+#include "gmp-impl.h"
+
+void
+mpf_set_d (mpf_ptr r, double d)
+{
+  int negative;
+
+  DOUBLE_NAN_INF_ACTION (d,
+                         __gmp_invalid_operation (),
+                         __gmp_invalid_operation ());
+
+  if (UNLIKELY (d == 0))
+    {
+      SIZ(r) = 0;
+      EXP(r) = 0;
+      return;
+    }
+  negative = d < 0;
+  d = ABS (d);
+
+  SIZ(r) = negative ? -LIMBS_PER_DOUBLE : LIMBS_PER_DOUBLE;
+  EXP(r) = __gmp_extract_double (PTR(r), d);
+}
diff --git a/third_party/gmp/mpf/set_dfl_prec.c b/third_party/gmp/mpf/set_dfl_prec.c
new file mode 100644
index 0000000..9be71c0
--- /dev/null
+++ b/third_party/gmp/mpf/set_dfl_prec.c
@@ -0,0 +1,39 @@
+/* mpf_set_default_prec --
+
+Copyright 1993-1995, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+mp_size_t __gmp_default_fp_limb_precision = __GMPF_BITS_TO_PREC (53);
+
+void
+mpf_set_default_prec (mp_bitcnt_t prec_in_bits) __GMP_NOTHROW
+{
+  __gmp_default_fp_limb_precision = __GMPF_BITS_TO_PREC (prec_in_bits);
+}
diff --git a/third_party/gmp/mpf/set_prc.c b/third_party/gmp/mpf/set_prc.c
new file mode 100644
index 0000000..40c3f0e
--- /dev/null
+++ b/third_party/gmp/mpf/set_prc.c
@@ -0,0 +1,68 @@
+/* mpf_set_prec(x) -- Change the precision of x.
+
+Copyright 1993-1995, 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* A full new_prec+1 limbs are always retained, even though just new_prec
+   would satisfy the requested precision.  If size==new_prec+1 then
+   certainly new_prec+1 should be kept since no copying is needed in that
+   case.  If just new_prec was kept for size>new_prec+1 it'd be a bit
+   inconsistent.  */
+
+void
+mpf_set_prec (mpf_ptr x, mp_bitcnt_t new_prec_in_bits)
+{
+  mp_size_t  old_prec, new_prec, new_prec_plus1;
+  mp_size_t  size, sign;
+  mp_ptr     xp;
+
+  new_prec = __GMPF_BITS_TO_PREC (new_prec_in_bits);
+  old_prec = PREC(x);
+
+  /* do nothing if already the right precision */
+  if (new_prec == old_prec)
+    return;
+
+  PREC(x) = new_prec;
+  new_prec_plus1 = new_prec + 1;
+
+  /* retain most significant limbs */
+  sign = SIZ(x);
+  size = ABS (sign);
+  xp = PTR(x);
+  if (size > new_prec_plus1)
+    {
+      SIZ(x) = (sign >= 0 ? new_prec_plus1 : -new_prec_plus1);
+      MPN_COPY_INCR (xp, xp + size - new_prec_plus1, new_prec_plus1);
+    }
+
+  PTR(x) = __GMP_REALLOCATE_FUNC_LIMBS (xp, old_prec+1, new_prec_plus1);
+}
diff --git a/third_party/gmp/mpf/set_prc_raw.c b/third_party/gmp/mpf/set_prc_raw.c
new file mode 100644
index 0000000..e5c52cc
--- /dev/null
+++ b/third_party/gmp/mpf/set_prc_raw.c
@@ -0,0 +1,39 @@
+/* mpf_set_prec_raw(x,bits) -- Change the precision of x without changing
+   allocation.  For proper operation, the original precision need to be reset
+   sooner or later.
+
+Copyright 1996, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpf_set_prec_raw (mpf_ptr x, mp_bitcnt_t prec_in_bits) __GMP_NOTHROW
+{
+  x->_mp_prec = __GMPF_BITS_TO_PREC (prec_in_bits);
+}
diff --git a/third_party/gmp/mpf/set_q.c b/third_party/gmp/mpf/set_q.c
new file mode 100644
index 0000000..b0b7fe3
--- /dev/null
+++ b/third_party/gmp/mpf/set_q.c
@@ -0,0 +1,118 @@
+/* mpf_set_q (mpf_t rop, mpq_t op) -- Convert the rational op to the float rop.
+
+Copyright 1996, 1999, 2001, 2002, 2004, 2005, 2016 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* As usual the aim is to produce PREC(r) limbs, with the high non-zero.  The
+   basic mpn_div_q produces a quotient of nsize-dsize+1 limbs, with either the
+   high or second highest limb non-zero.  We arrange for nsize-dsize+1 to equal
+   prec+1, hence giving either prec or prec+1 result limbs at PTR(r).
+
+   nsize-dsize+1 == prec+1 is achieved by adjusting num(q), either dropping low
+   limbs if it's too big, or padding with low zeros if it's too small.  The
+   full given den(q) is always used.
+
+   We cannot truncate den(q), because even when it's much bigger than prec the
+   last limbs can still influence the final quotient.  Often they don't, but we
+   leave optimization of that to mpn_div_q.
+
+   Enhancements:
+
+   The high quotient limb is non-zero when high{np,dsize} > {dp,dsize}.  We
+   could make that comparison and use qsize==prec instead of qsize==prec+1,
+   to save one limb in the division.  */
+
+void
+mpf_set_q (mpf_t r, mpq_srcptr q)
+{
+  mp_srcptr np, dp;
+  mp_size_t prec, nsize, dsize, qsize, prospective_qsize, tsize, zeros;
+  mp_size_t sign_quotient, high_zero;
+  mp_ptr qp, tp;
+  mp_exp_t exp;
+  TMP_DECL;
+
+  ASSERT (SIZ(&q->_mp_den) > 0);  /* canonical q */
+
+  nsize = SIZ (&q->_mp_num);
+  dsize = SIZ (&q->_mp_den);
+
+  if (UNLIKELY (nsize == 0))
+    {
+      SIZ (r) = 0;
+      EXP (r) = 0;
+      return;
+    }
+
+  TMP_MARK;
+
+  prec = PREC (r);
+  qp = PTR (r);
+
+  sign_quotient = nsize;
+  nsize = ABS (nsize);
+  np = PTR (&q->_mp_num);
+  dp = PTR (&q->_mp_den);
+
+  prospective_qsize = nsize - dsize + 1;  /* q from using given n,d sizes */
+  exp = prospective_qsize;                /* ie. number of integer limbs */
+  qsize = prec + 1;                       /* desired q */
+
+  zeros = qsize - prospective_qsize;      /* n zeros to get desired qsize */
+  tsize = nsize + zeros;                  /* size of intermediate numerator */
+  tp = TMP_ALLOC_LIMBS (tsize + 1);       /* +1 for mpn_div_q's scratch */
+
+  if (zeros > 0)
+    {
+      /* pad n with zeros into temporary space */
+      MPN_ZERO (tp, zeros);
+      MPN_COPY (tp+zeros, np, nsize);
+      np = tp;                            /* mpn_div_q allows this overlap */
+    }
+  else
+    {
+      /* shorten n to get desired qsize */
+      np -= zeros;
+    }
+
+  ASSERT (tsize-dsize+1 == qsize);
+  mpn_div_q (qp, np, tsize, dp, dsize, tp);
+
+  /* strip possible zero high limb */
+  high_zero = (qp[qsize-1] == 0);
+  qsize -= high_zero;
+  exp -= high_zero;
+
+  EXP (r) = exp;
+  SIZ (r) = sign_quotient >= 0 ? qsize : -qsize;
+
+  TMP_FREE;
+}
diff --git a/third_party/gmp/mpf/set_si.c b/third_party/gmp/mpf/set_si.c
new file mode 100644
index 0000000..23f713d
--- /dev/null
+++ b/third_party/gmp/mpf/set_si.c
@@ -0,0 +1,52 @@
+/* mpf_set_si() -- Assign a float from a signed int.
+
+Copyright 1993-1995, 2000-2002, 2004, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpf_set_si (mpf_ptr dest, long val)
+{
+  mp_size_t size;
+  mp_limb_t vl;
+
+  vl = (mp_limb_t) ABS_CAST (unsigned long int, val);
+
+  dest->_mp_d[0] = vl & GMP_NUMB_MASK;
+  size = vl != 0;
+
+#if BITS_PER_ULONG > GMP_NUMB_BITS
+  vl >>= GMP_NUMB_BITS;
+  dest->_mp_d[1] = vl;
+  size += (vl != 0);
+#endif
+
+  dest->_mp_exp = size;
+  dest->_mp_size = val >= 0 ? size : -size;
+}
diff --git a/third_party/gmp/mpf/set_str.c b/third_party/gmp/mpf/set_str.c
new file mode 100644
index 0000000..c7bfe0b
--- /dev/null
+++ b/third_party/gmp/mpf/set_str.c
@@ -0,0 +1,412 @@
+/* mpf_set_str (dest, string, base) -- Convert the string STRING
+   in base BASE to a float in dest.  If BASE is zero, the leading characters
+   of STRING is used to figure out the base.
+
+Copyright 1993-1997, 2000-2003, 2005, 2007, 2008, 2011, 2013, 2019 Free
+Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+/*
+  This still needs work, as suggested by some FIXME comments.
+  1. Don't depend on superfluous mantissa digits.
+  2. Allocate temp space more cleverly.
+  3. Use mpn_div_q instead of mpn_lshift+mpn_divrem.
+*/
+
+#define _GNU_SOURCE    /* for DECIMAL_POINT in langinfo.h */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#if HAVE_LANGINFO_H
+#include <langinfo.h>  /* for nl_langinfo */
+#endif
+
+#if HAVE_LOCALE_H
+#include <locale.h>    /* for localeconv */
+#endif
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+#define digit_value_tab __gmp_digit_value_tab
+
+/* Compute base^exp and return the most significant prec limbs in rp[].
+   Put the count of omitted low limbs in *ign.
+   Return the actual size (which might be less than prec).  */
+static mp_size_t
+mpn_pow_1_highpart (mp_ptr rp, mp_size_t *ignp,
+		    mp_limb_t base, mp_exp_t exp,
+		    mp_size_t prec, mp_ptr tp)
+{
+  mp_size_t ign;		/* counts number of ignored low limbs in r */
+  mp_size_t off;		/* keeps track of offset where value starts */
+  mp_ptr passed_rp = rp;
+  mp_size_t rn;
+  int cnt;
+  int i;
+
+  rp[0] = base;
+  rn = 1;
+  off = 0;
+  ign = 0;
+  count_leading_zeros (cnt, exp);
+  for (i = GMP_LIMB_BITS - cnt - 2; i >= 0; i--)
+    {
+      mpn_sqr (tp, rp + off, rn);
+      rn = 2 * rn;
+      rn -= tp[rn - 1] == 0;
+      ign <<= 1;
+
+      off = 0;
+      if (rn > prec)
+	{
+	  ign += rn - prec;
+	  off = rn - prec;
+	  rn = prec;
+	}
+      MP_PTR_SWAP (rp, tp);
+
+      if (((exp >> i) & 1) != 0)
+	{
+	  mp_limb_t cy;
+	  cy = mpn_mul_1 (rp, rp + off, rn, base);
+	  rp[rn] = cy;
+	  rn += cy != 0;
+	  off = 0;
+	}
+    }
+
+  if (rn > prec)
+    {
+      ign += rn - prec;
+      rp += rn - prec;
+      rn = prec;
+    }
+
+  MPN_COPY_INCR (passed_rp, rp + off, rn);
+  *ignp = ign;
+  return rn;
+}
+
+int
+mpf_set_str (mpf_ptr x, const char *str, int base)
+{
+  size_t str_size;
+  char *s, *begs;
+  size_t i, j;
+  int c;
+  int negative;
+  char *dotpos;
+  const char *expptr;
+  int exp_base;
+  const char  *point = GMP_DECIMAL_POINT;
+  size_t      pointlen = strlen (point);
+  const unsigned char *digit_value;
+  int incr;
+  size_t n_zeros_skipped;
+
+  TMP_DECL;
+
+  c = (unsigned char) *str;
+
+  /* Skip whitespace.  */
+  while (isspace (c))
+    c = (unsigned char) *++str;
+
+  negative = 0;
+  if (c == '-')
+    {
+      negative = 1;
+      c = (unsigned char) *++str;
+    }
+
+  /* Default base to decimal.  */
+  if (base == 0)
+    base = 10;
+
+  exp_base = base;
+
+  if (base < 0)
+    {
+      exp_base = 10;
+      base = -base;
+    }
+
+  digit_value = digit_value_tab;
+  if (base > 36)
+    {
+      /* For bases > 36, use the collating sequence
+	 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.  */
+      digit_value += 208;
+      if (base > 62)
+	return -1;		/* too large base */
+    }
+
+  /* Require at least one digit, possibly after an initial decimal point.  */
+  if (digit_value[c] >= base)
+    {
+      /* not a digit, must be a decimal point */
+      for (i = 0; i < pointlen; i++)
+	if (str[i] != point[i])
+	  return -1;
+      if (digit_value[(unsigned char) str[pointlen]] >= base)
+	return -1;
+    }
+
+  /* Locate exponent part of the input.  Look from the right of the string,
+     since the exponent is usually a lot shorter than the mantissa.  */
+  expptr = NULL;
+  str_size = strlen (str);
+  for (i = str_size - 1; i > 0; i--)
+    {
+      c = (unsigned char) str[i];
+      if (c == '@' || (base <= 10 && (c == 'e' || c == 'E')))
+	{
+	  expptr = str + i + 1;
+	  str_size = i;
+	  break;
+	}
+    }
+
+  TMP_MARK;
+  s = begs = (char *) TMP_ALLOC (str_size + 1);
+
+  incr = 0;
+  n_zeros_skipped = 0;
+  dotpos = NULL;
+
+  /* Loop through mantissa, converting it from ASCII to raw byte values.  */
+  for (i = 0; i < str_size; i++)
+    {
+      c = (unsigned char) *str;
+      if (!isspace (c))
+	{
+	  int dig;
+
+	  for (j = 0; j < pointlen; j++)
+	    if (str[j] != point[j])
+	      goto not_point;
+	  if (1)
+	    {
+	      if (dotpos != 0)
+		{
+		  /* already saw a decimal point, another is invalid */
+		  TMP_FREE;
+		  return -1;
+		}
+	      dotpos = s;
+	      str += pointlen - 1;
+	      i += pointlen - 1;
+	    }
+	  else
+	    {
+	    not_point:
+	      dig = digit_value[c];
+	      if (dig >= base)
+		{
+		  TMP_FREE;
+		  return -1;
+		}
+	      *s = dig;
+	      incr |= dig != 0;
+	      s += incr;	/* Increment after first non-0 digit seen. */
+	      if (dotpos != NULL)
+		/* Count skipped zeros between radix point and first non-0
+		   digit. */
+		n_zeros_skipped += 1 - incr;
+	    }
+	}
+      c = (unsigned char) *++str;
+    }
+
+  str_size = s - begs;
+
+  {
+    long exp_in_base;
+    mp_size_t ra, ma, rn, mn;
+    int cnt;
+    mp_ptr mp, tp, rp;
+    mp_exp_t exp_in_limbs;
+    mp_size_t prec = PREC(x) + 1;
+    int divflag;
+    mp_size_t madj, radj;
+
+#if 0
+    size_t n_chars_needed;
+
+    /* This needs careful testing.  Leave disabled for now.  */
+    /* Just consider the relevant leading digits of the mantissa.  */
+    LIMBS_PER_DIGIT_IN_BASE (n_chars_needed, prec, base);
+    if (str_size > n_chars_needed)
+      str_size = n_chars_needed;
+#endif
+
+    if (str_size == 0)
+      {
+	SIZ(x) = 0;
+	EXP(x) = 0;
+	TMP_FREE;
+	return 0;
+      }
+
+    LIMBS_PER_DIGIT_IN_BASE (ma, str_size, base);
+    mp = TMP_ALLOC_LIMBS (ma);
+    mn = mpn_set_str (mp, (unsigned char *) begs, str_size, base);
+
+    madj = 0;
+    /* Ignore excess limbs in MP,MSIZE.  */
+    if (mn > prec)
+      {
+	madj = mn - prec;
+	mp += mn - prec;
+	mn = prec;
+      }
+
+    if (expptr != 0)
+      {
+	/* Scan and convert the exponent, in base exp_base.  */
+	long dig, minus, plusminus;
+	c = (unsigned char) *expptr;
+	minus = -(long) (c == '-');
+	plusminus = minus | -(long) (c == '+');
+	expptr -= plusminus;			/* conditional increment */
+	c = (unsigned char) *expptr++;
+	dig = digit_value[c];
+	if (dig >= exp_base)
+	  {
+	    TMP_FREE;
+	    return -1;
+	  }
+	exp_in_base = dig;
+	c = (unsigned char) *expptr++;
+	dig = digit_value[c];
+	while (dig < exp_base)
+	  {
+	    exp_in_base = exp_in_base * exp_base;
+	    exp_in_base += dig;
+	    c = (unsigned char) *expptr++;
+	    dig = digit_value[c];
+	  }
+	exp_in_base = (exp_in_base ^ minus) - minus; /* conditional negation */
+      }
+    else
+      exp_in_base = 0;
+    if (dotpos != 0)
+      exp_in_base -= s - dotpos + n_zeros_skipped;
+    divflag = exp_in_base < 0;
+    exp_in_base = ABS (exp_in_base);
+
+    if (exp_in_base == 0)
+      {
+	MPN_COPY (PTR(x), mp, mn);
+	SIZ(x) = negative ? -mn : mn;
+	EXP(x) = mn + madj;
+	TMP_FREE;
+	return 0;
+      }
+
+    ra = 2 * (prec + 1);
+    TMP_ALLOC_LIMBS_2 (rp, ra, tp, ra);
+    rn = mpn_pow_1_highpart (rp, &radj, (mp_limb_t) base, exp_in_base, prec, tp);
+
+    if (divflag)
+      {
+#if 0
+	/* FIXME: Should use mpn_div_q here.  */
+	...
+	mpn_div_q (tp, mp, mn, rp, rn, scratch);
+	...
+#else
+	mp_ptr qp;
+	mp_limb_t qlimb;
+	if (mn < rn)
+	  {
+	    /* Pad out MP,MSIZE for current divrem semantics.  */
+	    mp_ptr tmp = TMP_ALLOC_LIMBS (rn + 1);
+	    MPN_ZERO (tmp, rn - mn);
+	    MPN_COPY (tmp + rn - mn, mp, mn);
+	    mp = tmp;
+	    madj -= rn - mn;
+	    mn = rn;
+	  }
+	if ((rp[rn - 1] & GMP_NUMB_HIGHBIT) == 0)
+	  {
+	    mp_limb_t cy;
+	    count_leading_zeros (cnt, rp[rn - 1]);
+	    cnt -= GMP_NAIL_BITS;
+	    mpn_lshift (rp, rp, rn, cnt);
+	    cy = mpn_lshift (mp, mp, mn, cnt);
+	    if (cy)
+	      mp[mn++] = cy;
+	  }
+
+	qp = TMP_ALLOC_LIMBS (prec + 1);
+	qlimb = mpn_divrem (qp, prec - (mn - rn), mp, mn, rp, rn);
+	tp = qp;
+	exp_in_limbs = qlimb + (mn - rn) + (madj - radj);
+	rn = prec;
+	if (qlimb != 0)
+	  {
+	    tp[prec] = qlimb;
+	    /* Skip the least significant limb not to overrun the destination
+	       variable.  */
+	    tp++;
+	  }
+#endif
+      }
+    else
+      {
+	tp = TMP_ALLOC_LIMBS (rn + mn);
+	if (rn > mn)
+	  mpn_mul (tp, rp, rn, mp, mn);
+	else
+	  mpn_mul (tp, mp, mn, rp, rn);
+	rn += mn;
+	rn -= tp[rn - 1] == 0;
+	exp_in_limbs = rn + madj + radj;
+
+	if (rn > prec)
+	  {
+	    tp += rn - prec;
+	    rn = prec;
+	    exp_in_limbs += 0;
+	  }
+      }
+
+    MPN_COPY (PTR(x), tp, rn);
+    SIZ(x) = negative ? -rn : rn;
+    EXP(x) = exp_in_limbs;
+    TMP_FREE;
+    return 0;
+  }
+}
diff --git a/third_party/gmp/mpf/set_ui.c b/third_party/gmp/mpf/set_ui.c
new file mode 100644
index 0000000..bd4ba26
--- /dev/null
+++ b/third_party/gmp/mpf/set_ui.c
@@ -0,0 +1,48 @@
+/* mpf_set_ui() -- Assign a float from an unsigned int.
+
+Copyright 1993-1995, 2001, 2002, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpf_set_ui (mpf_ptr f, unsigned long val)
+{
+  mp_size_t size;
+
+  f->_mp_d[0] = val & GMP_NUMB_MASK;
+  size = val != 0;
+
+#if BITS_PER_ULONG > GMP_NUMB_BITS
+  val >>= GMP_NUMB_BITS;
+  f->_mp_d[1] = val;
+  size += (val != 0);
+#endif
+
+  f->_mp_exp = f->_mp_size = size;
+}
diff --git a/third_party/gmp/mpf/set_z.c b/third_party/gmp/mpf/set_z.c
new file mode 100644
index 0000000..f762633
--- /dev/null
+++ b/third_party/gmp/mpf/set_z.c
@@ -0,0 +1,56 @@
+/* mpf_set_z -- Assign a float from an integer.
+
+Copyright 1996, 2001, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpf_set_z (mpf_ptr r, mpz_srcptr u)
+{
+  mp_ptr rp, up;
+  mp_size_t size, asize;
+  mp_size_t prec;
+
+  prec = PREC (r) + 1;
+  size = SIZ (u);
+  asize = ABS (size);
+  rp = PTR (r);
+  up = PTR (u);
+
+  EXP (r) = asize;
+
+  if (asize > prec)
+    {
+      up += asize - prec;
+      asize = prec;
+    }
+
+  SIZ (r) = size >= 0 ? asize : -asize;
+  MPN_COPY (rp, up, asize);
+}
diff --git a/third_party/gmp/mpf/size.c b/third_party/gmp/mpf/size.c
new file mode 100644
index 0000000..f7a9dbd
--- /dev/null
+++ b/third_party/gmp/mpf/size.c
@@ -0,0 +1,38 @@
+/* mpf_size(x) -- return the number of limbs currently used by the
+   value of the float X.
+
+Copyright 1993-1995, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+size_t
+mpf_size (mpf_srcptr f) __GMP_NOTHROW
+{
+  return __GMP_ABS (f->_mp_size);
+}
diff --git a/third_party/gmp/mpf/sqrt.c b/third_party/gmp/mpf/sqrt.c
new file mode 100644
index 0000000..ffb7c10
--- /dev/null
+++ b/third_party/gmp/mpf/sqrt.c
@@ -0,0 +1,112 @@
+/* mpf_sqrt -- Compute the square root of a float.
+
+Copyright 1993, 1994, 1996, 2000, 2001, 2004, 2005, 2012 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h> /* for NULL */
+#include "gmp-impl.h"
+
+
+/* As usual, the aim is to produce PREC(r) limbs of result, with the high
+   limb non-zero.  This is accomplished by applying mpn_sqrtrem to either
+   2*prec or 2*prec-1 limbs, both such sizes resulting in prec limbs.
+
+   The choice between 2*prec or 2*prec-1 limbs is based on the input
+   exponent.  With b=2^GMP_NUMB_BITS the limb base then we can think of
+   effectively taking out a factor b^(2k), for suitable k, to get to an
+   integer input of the desired size ready for mpn_sqrtrem.  It must be an
+   even power taken out, ie. an even number of limbs, so the square root
+   gives factor b^k and the radix point is still on a limb boundary.  So if
+   EXP(r) is even we'll get an even number of input limbs 2*prec, or if
+   EXP(r) is odd we get an odd number 2*prec-1.
+
+   Further limbs below the 2*prec or 2*prec-1 used don't affect the result
+   and are simply truncated.  This can be seen by considering an integer x,
+   with s=floor(sqrt(x)).  s is the unique integer satisfying s^2 <= x <
+   (s+1)^2.  Notice that adding a fraction part to x (ie. some further bits)
+   doesn't change the inequality, s remains the unique solution.  Working
+   suitable factors of 2 into this argument lets it apply to an intended
+   precision at any position for any x, not just the integer binary point.
+
+   If the input is smaller than 2*prec or 2*prec-1, then we just pad with
+   zeros, that of course being our usual interpretation of short inputs.
+   The effect is to extend the root beyond the size of the input (for
+   instance into fractional limbs if u is an integer).  */
+
+void
+mpf_sqrt (mpf_ptr r, mpf_srcptr u)
+{
+  mp_size_t usize;
+  mp_ptr up, tp;
+  mp_size_t prec, tsize;
+  mp_exp_t uexp, expodd;
+  TMP_DECL;
+
+  usize = u->_mp_size;
+  if (UNLIKELY (usize <= 0))
+    {
+      if (usize < 0)
+        SQRT_OF_NEGATIVE;
+      r->_mp_size = 0;
+      r->_mp_exp = 0;
+      return;
+    }
+
+  TMP_MARK;
+
+  uexp = u->_mp_exp;
+  prec = r->_mp_prec;
+  up = u->_mp_d;
+
+  expodd = (uexp & 1);
+  tsize = 2 * prec - expodd;
+  r->_mp_size = prec;
+  r->_mp_exp = (uexp + expodd) / 2;    /* ceil(uexp/2) */
+
+  /* root size is ceil(tsize/2), this will be our desired "prec" limbs */
+  ASSERT ((tsize + 1) / 2 == prec);
+
+  tp = TMP_ALLOC_LIMBS (tsize);
+
+  if (usize > tsize)
+    {
+      up += usize - tsize;
+      usize = tsize;
+      MPN_COPY (tp, up, tsize);
+    }
+  else
+    {
+      MPN_ZERO (tp, tsize - usize);
+      MPN_COPY (tp + (tsize - usize), up, usize);
+    }
+
+  mpn_sqrtrem (r->_mp_d, NULL, tp, tsize);
+
+  TMP_FREE;
+}
diff --git a/third_party/gmp/mpf/sqrt_ui.c b/third_party/gmp/mpf/sqrt_ui.c
new file mode 100644
index 0000000..9f91f99
--- /dev/null
+++ b/third_party/gmp/mpf/sqrt_ui.c
@@ -0,0 +1,108 @@
+/* mpf_sqrt_ui -- Compute the square root of an unsigned integer.
+
+Copyright 1993, 1994, 1996, 2000, 2001, 2004, 2005, 2015 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h> /* for NULL */
+#include "gmp-impl.h"
+
+
+/* As usual the aim is to produce PREC(r) limbs of result with the high limb
+   non-zero.  That high limb will end up floor(sqrt(u)), and limbs below are
+   produced by padding the input with zeros, two for each desired result
+   limb, being 2*(prec-1) for a total 2*prec-1 limbs passed to mpn_sqrtrem.
+   The way mpn_sqrtrem calculates floor(sqrt(x)) ensures the root is correct
+   to the intended accuracy, ie. truncated to prec limbs.
+
+   With nails, u might be two limbs, in which case a total 2*prec limbs is
+   passed to mpn_sqrtrem (still giving a prec limb result).  If uhigh is
+   zero we adjust back to 2*prec-1, since mpn_sqrtrem requires the high
+   non-zero.  2*prec limbs are always allocated, even when uhigh is zero, so
+   the store of uhigh can be done without a conditional.
+
+   u==0 is a special case so the rest of the code can assume the result is
+   non-zero (ie. will have a non-zero high limb on the result).
+
+   Not done:
+
+   No attempt is made to identify perfect squares.  It's considered this can
+   be left to an application if it might occur with any frequency.  As it
+   stands, mpn_sqrtrem does its normal amount of work on a perfect square
+   followed by zero limbs, though of course only an mpn_sqrtrem1 would be
+   actually needed.  We also end up leaving our mpf result with lots of low
+   trailing zeros, slowing down subsequent operations.
+
+   We're not aware of any optimizations that can be made using the fact the
+   input has lots of trailing zeros (apart from the perfect square
+   case).  */
+
+
+/* 1 if we (might) need two limbs for u */
+#define U2   (GMP_NUMB_BITS < BITS_PER_ULONG)
+
+void
+mpf_sqrt_ui (mpf_ptr r, unsigned long int u)
+{
+  mp_size_t rsize, zeros;
+  mp_ptr tp;
+  mp_size_t prec;
+  TMP_DECL;
+
+  if (UNLIKELY (u <= 1))
+    {
+      SIZ (r) = EXP (r) = u;
+      *PTR (r) = u;
+      return;
+    }
+
+  TMP_MARK;
+
+  prec = PREC (r);
+  zeros = 2 * prec - 2;
+  rsize = zeros + 1 + U2;
+
+  tp = TMP_ALLOC_LIMBS (rsize);
+
+  MPN_ZERO (tp, zeros);
+  tp[zeros] = u & GMP_NUMB_MASK;
+
+#if U2
+  {
+    mp_limb_t uhigh = u >> GMP_NUMB_BITS;
+    tp[zeros + 1] = uhigh;
+    rsize -= (uhigh == 0);
+  }
+#endif
+
+  mpn_sqrtrem (PTR (r), NULL, tp, rsize);
+
+  SIZ (r) = prec;
+  EXP (r) = 1;
+  TMP_FREE;
+}
diff --git a/third_party/gmp/mpf/sub.c b/third_party/gmp/mpf/sub.c
new file mode 100644
index 0000000..56f26f6
--- /dev/null
+++ b/third_party/gmp/mpf/sub.c
@@ -0,0 +1,395 @@
+/* mpf_sub -- Subtract two floats.
+
+Copyright 1993-1996, 1999-2002, 2004, 2005, 2011, 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpf_sub (mpf_ptr r, mpf_srcptr u, mpf_srcptr v)
+{
+  mp_srcptr up, vp;
+  mp_ptr rp, tp;
+  mp_size_t usize, vsize, rsize;
+  mp_size_t prec;
+  mp_exp_t exp;
+  mp_size_t ediff;
+  int negate;
+  TMP_DECL;
+
+  usize = SIZ (u);
+  vsize = SIZ (v);
+
+  /* Handle special cases that don't work in generic code below.  */
+  if (usize == 0)
+    {
+      mpf_neg (r, v);
+      return;
+    }
+  if (vsize == 0)
+    {
+      if (r != u)
+        mpf_set (r, u);
+      return;
+    }
+
+  /* If signs of U and V are different, perform addition.  */
+  if ((usize ^ vsize) < 0)
+    {
+      __mpf_struct v_negated;
+      v_negated._mp_size = -vsize;
+      v_negated._mp_exp = EXP (v);
+      v_negated._mp_d = PTR (v);
+      mpf_add (r, u, &v_negated);
+      return;
+    }
+
+  TMP_MARK;
+
+  /* Signs are now known to be the same.  */
+  negate = usize < 0;
+
+  /* Make U be the operand with the largest exponent.  */
+  if (EXP (u) < EXP (v))
+    {
+      mpf_srcptr t;
+      t = u; u = v; v = t;
+      negate ^= 1;
+      usize = SIZ (u);
+      vsize = SIZ (v);
+    }
+
+  usize = ABS (usize);
+  vsize = ABS (vsize);
+  up = PTR (u);
+  vp = PTR (v);
+  rp = PTR (r);
+  prec = PREC (r) + 1;
+  exp = EXP (u);
+  ediff = exp - EXP (v);
+
+  /* If ediff is 0 or 1, we might have a situation where the operands are
+     extremely close.  We need to scan the operands from the most significant
+     end ignore the initial parts that are equal.  */
+  if (ediff <= 1)
+    {
+      if (ediff == 0)
+	{
+	  /* Skip leading limbs in U and V that are equal.  */
+	      /* This loop normally exits immediately.  Optimize for that.  */
+	      while (up[usize - 1] == vp[vsize - 1])
+		{
+		  usize--;
+		  vsize--;
+		  exp--;
+
+		  if (usize == 0)
+		    {
+                      /* u cancels high limbs of v, result is rest of v */
+		      negate ^= 1;
+                    cancellation:
+                      /* strip high zeros before truncating to prec */
+                      while (vsize != 0 && vp[vsize - 1] == 0)
+                        {
+                          vsize--;
+                          exp--;
+                        }
+		      if (vsize > prec)
+			{
+			  vp += vsize - prec;
+			  vsize = prec;
+			}
+                      MPN_COPY_INCR (rp, vp, vsize);
+                      rsize = vsize;
+                      goto done;
+		    }
+		  if (vsize == 0)
+		    {
+                      vp = up;
+                      vsize = usize;
+                      goto cancellation;
+		    }
+		}
+
+	  if (up[usize - 1] < vp[vsize - 1])
+	    {
+	      /* For simplicity, swap U and V.  Note that since the loop above
+		 wouldn't have exited unless up[usize - 1] and vp[vsize - 1]
+		 were non-equal, this if-statement catches all cases where U
+		 is smaller than V.  */
+	      MPN_SRCPTR_SWAP (up,usize, vp,vsize);
+	      negate ^= 1;
+	      /* negating ediff not necessary since it is 0.  */
+	    }
+
+	  /* Check for
+	     x+1 00000000 ...
+	      x  ffffffff ... */
+	  if (up[usize - 1] != vp[vsize - 1] + 1)
+	    goto general_case;
+	  usize--;
+	  vsize--;
+	  exp--;
+	}
+      else /* ediff == 1 */
+	{
+	  /* Check for
+	     1 00000000 ...
+	     0 ffffffff ... */
+
+	  if (up[usize - 1] != 1 || vp[vsize - 1] != GMP_NUMB_MAX
+	      || (usize >= 2 && up[usize - 2] != 0))
+	    goto general_case;
+
+	  usize--;
+	  exp--;
+	}
+
+      /* Skip sequences of 00000000/ffffffff */
+      while (vsize != 0 && usize != 0 && up[usize - 1] == 0
+	     && vp[vsize - 1] == GMP_NUMB_MAX)
+	{
+	  usize--;
+	  vsize--;
+	  exp--;
+	}
+
+      if (usize == 0)
+	{
+	  while (vsize != 0 && vp[vsize - 1] == GMP_NUMB_MAX)
+	    {
+	      vsize--;
+	      exp--;
+	    }
+	}
+      else if (usize > prec - 1)
+	{
+	  up += usize - (prec - 1);
+	  usize = prec - 1;
+	}
+      if (vsize > prec - 1)
+	{
+	  vp += vsize - (prec - 1);
+	  vsize = prec - 1;
+	}
+
+      tp = TMP_ALLOC_LIMBS (prec);
+      {
+	mp_limb_t cy_limb;
+	if (vsize == 0)
+	  {
+	    MPN_COPY (tp, up, usize);
+	    tp[usize] = 1;
+	    rsize = usize + 1;
+	    exp++;
+	    goto normalized;
+	  }
+	if (usize == 0)
+	  {
+	    cy_limb = mpn_neg (tp, vp, vsize);
+	    rsize = vsize;
+	  }
+	else if (usize >= vsize)
+	  {
+	    /* uuuu     */
+	    /* vv       */
+	    mp_size_t size;
+	    size = usize - vsize;
+	    MPN_COPY (tp, up, size);
+	    cy_limb = mpn_sub_n (tp + size, up + size, vp, vsize);
+	    rsize = usize;
+	  }
+	else /* (usize < vsize) */
+	  {
+	    /* uuuu     */
+	    /* vvvvvvv  */
+	    mp_size_t size;
+	    size = vsize - usize;
+	    cy_limb = mpn_neg (tp, vp, size);
+	    cy_limb = mpn_sub_nc (tp + size, up, vp + size, usize, cy_limb);
+	    rsize = vsize;
+	  }
+	if (cy_limb == 0)
+	  {
+	    tp[rsize] = 1;
+	    rsize++;
+	    exp++;
+	    goto normalized;
+	  }
+	goto normalize;
+      }
+    }
+
+general_case:
+  /* If U extends beyond PREC, ignore the part that does.  */
+  if (usize > prec)
+    {
+      up += usize - prec;
+      usize = prec;
+    }
+
+  /* If V extends beyond PREC, ignore the part that does.
+     Note that this may make vsize negative.  */
+  if (vsize + ediff > prec)
+    {
+      vp += vsize + ediff - prec;
+      vsize = prec - ediff;
+    }
+
+  if (ediff >= prec)
+    {
+      /* V completely cancelled.  */
+      if (rp != up)
+	MPN_COPY (rp, up, usize);
+      rsize = usize;
+    }
+  else
+    {
+      /* Allocate temp space for the result.  Allocate
+	 just vsize + ediff later???  */
+      tp = TMP_ALLOC_LIMBS (prec);
+
+      /* Locate the least significant non-zero limb in (the needed
+	 parts of) U and V, to simplify the code below.  */
+      for (;;)
+	{
+	  if (vsize == 0)
+	    {
+	      MPN_COPY (rp, up, usize);
+	      rsize = usize;
+	      goto done;
+	    }
+	  if (vp[0] != 0)
+	    break;
+	  vp++, vsize--;
+	}
+      for (;;)
+	{
+	  if (usize == 0)
+	    {
+	      MPN_COPY (rp, vp, vsize);
+	      rsize = vsize;
+	      negate ^= 1;
+	      goto done;
+	    }
+	  if (up[0] != 0)
+	    break;
+	  up++, usize--;
+	}
+
+      /* uuuu     |  uuuu     |  uuuu     |  uuuu     |  uuuu    */
+      /* vvvvvvv  |  vv       |    vvvvv  |    v      |       vv */
+
+      if (usize > ediff)
+	{
+	  /* U and V partially overlaps.  */
+	  if (ediff == 0)
+	    {
+	      /* Have to compare the leading limbs of u and v
+		 to determine whether to compute u - v or v - u.  */
+	      if (usize >= vsize)
+		{
+		  /* uuuu     */
+		  /* vv       */
+		  mp_size_t size;
+		  size = usize - vsize;
+		  MPN_COPY (tp, up, size);
+		  mpn_sub_n (tp + size, up + size, vp, vsize);
+		  rsize = usize;
+		}
+	      else /* (usize < vsize) */
+		{
+		  /* uuuu     */
+		  /* vvvvvvv  */
+		  mp_size_t size;
+		  size = vsize - usize;
+		  ASSERT_CARRY (mpn_neg (tp, vp, size));
+		  mpn_sub_nc (tp + size, up, vp + size, usize, CNST_LIMB (1));
+		  rsize = vsize;
+		}
+	    }
+	  else
+	    {
+	      if (vsize + ediff <= usize)
+		{
+		  /* uuuu     */
+		  /*   v      */
+		  mp_size_t size;
+		  size = usize - ediff - vsize;
+		  MPN_COPY (tp, up, size);
+		  mpn_sub (tp + size, up + size, usize - size, vp, vsize);
+		  rsize = usize;
+		}
+	      else
+		{
+		  /* uuuu     */
+		  /*   vvvvv  */
+		  mp_size_t size;
+		  rsize = vsize + ediff;
+		  size = rsize - usize;
+		  ASSERT_CARRY (mpn_neg (tp, vp, size));
+		  mpn_sub (tp + size, up, usize, vp + size, usize - ediff);
+		  /* Should we use sub_nc then sub_1? */
+		  MPN_DECR_U (tp + size, usize, CNST_LIMB (1));
+		}
+	    }
+	}
+      else
+	{
+	  /* uuuu     */
+	  /*      vv  */
+	  mp_size_t size, i;
+	  size = vsize + ediff - usize;
+	  ASSERT_CARRY (mpn_neg (tp, vp, vsize));
+	  for (i = vsize; i < size; i++)
+	    tp[i] = GMP_NUMB_MAX;
+	  mpn_sub_1 (tp + size, up, usize, (mp_limb_t) 1);
+	  rsize = size + usize;
+	}
+
+    normalize:
+      /* Full normalize.  Optimize later.  */
+      while (rsize != 0 && tp[rsize - 1] == 0)
+	{
+	  rsize--;
+	  exp--;
+	}
+    normalized:
+      MPN_COPY (rp, tp, rsize);
+    }
+
+ done:
+  TMP_FREE;
+  if (rsize == 0) {
+    SIZ (r) = 0;
+    EXP (r) = 0;
+  } else {
+    SIZ (r) = negate ? -rsize : rsize;
+    EXP (r) = exp;
+  }
+}
diff --git a/third_party/gmp/mpf/sub_ui.c b/third_party/gmp/mpf/sub_ui.c
new file mode 100644
index 0000000..a23d2a8
--- /dev/null
+++ b/third_party/gmp/mpf/sub_ui.c
@@ -0,0 +1,50 @@
+/* mpf_sub_ui -- Subtract an unsigned integer from a float.
+
+Copyright 1993, 1994, 1996, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpf_sub_ui (mpf_ptr sum, mpf_srcptr u, unsigned long int v)
+{
+  __mpf_struct vv;
+  mp_limb_t vl;
+
+  if (v == 0)
+    {
+      mpf_set (sum, u);
+      return;
+    }
+
+  vl = v;
+  vv._mp_size = 1;
+  vv._mp_d = &vl;
+  vv._mp_exp = 1;
+  mpf_sub (sum, u, &vv);
+}
diff --git a/third_party/gmp/mpf/swap.c b/third_party/gmp/mpf/swap.c
new file mode 100644
index 0000000..80b2e9b
--- /dev/null
+++ b/third_party/gmp/mpf/swap.c
@@ -0,0 +1,56 @@
+/* mpf_swap (U, V) -- Swap U and V.
+
+Copyright 1997, 1998, 2000, 2001, 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpf_swap (mpf_ptr u, mpf_ptr v) __GMP_NOTHROW
+{
+  mp_ptr tptr;
+  mp_size_t tprec;
+  mp_size_t tsiz;
+  mp_exp_t  texp;
+
+  tprec = PREC(u);
+  PREC(u) = PREC(v);
+  PREC(v) = tprec;
+
+  tsiz = SIZ(u);
+  SIZ(u) = SIZ(v);
+  SIZ(v) = tsiz;
+
+  texp = EXP(u);
+  EXP(u) = EXP(v);
+  EXP(v) = texp;
+
+  tptr = PTR(u);
+  PTR(u) = PTR(v);
+  PTR(v) = tptr;
+}
diff --git a/third_party/gmp/mpf/trunc.c b/third_party/gmp/mpf/trunc.c
new file mode 100644
index 0000000..e9af4a7
--- /dev/null
+++ b/third_party/gmp/mpf/trunc.c
@@ -0,0 +1,74 @@
+/* mpf_trunc -- truncate an mpf to an integer.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* Notice the use of prec+1 ensures mpf_trunc is equivalent to mpf_set if u
+   is already an integer.  */
+
+void
+mpf_trunc (mpf_ptr r, mpf_srcptr u)
+{
+  mp_ptr     rp;
+  mp_srcptr  up;
+  mp_size_t  size, asize, prec;
+  mp_exp_t   exp;
+
+  exp = EXP(u);
+  size = SIZ(u);
+  if (size == 0 || exp <= 0)
+    {
+      /* u is only a fraction */
+      SIZ(r) = 0;
+      EXP(r) = 0;
+      return;
+    }
+
+  up = PTR(u);
+  EXP(r) = exp;
+  asize = ABS (size);
+  up += asize;
+
+  /* skip fraction part of u */
+  asize = MIN (asize, exp);
+
+  /* don't lose precision in the copy */
+  prec = PREC(r) + 1;
+
+  /* skip excess over target precision */
+  asize = MIN (asize, prec);
+
+  up -= asize;
+  rp = PTR(r);
+  SIZ(r) = (size >= 0 ? asize : -asize);
+  if (rp != up)
+    MPN_COPY_INCR (rp, up, asize);
+}
diff --git a/third_party/gmp/mpf/ui_div.c b/third_party/gmp/mpf/ui_div.c
new file mode 100644
index 0000000..d228bd4
--- /dev/null
+++ b/third_party/gmp/mpf/ui_div.c
@@ -0,0 +1,127 @@
+/* mpf_ui_div -- Divide an unsigned integer with a float.
+
+Copyright 1993-1996, 2000-2002, 2004, 2005, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>  /* for NULL */
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+void
+mpf_ui_div (mpf_ptr r, unsigned long int u, mpf_srcptr v)
+{
+  mp_srcptr vp;
+  mp_ptr rp, tp, remp, new_vp;
+  mp_size_t vsize;
+  mp_size_t rsize, prospective_rsize, zeros, tsize, high_zero;
+  mp_size_t sign_quotient;
+  mp_size_t prec;
+  mp_exp_t rexp;
+  TMP_DECL;
+
+  vsize = v->_mp_size;
+  sign_quotient = vsize;
+
+  if (UNLIKELY (vsize == 0))
+    DIVIDE_BY_ZERO;
+
+  if (UNLIKELY (u == 0))
+    {
+      r->_mp_size = 0;
+      r->_mp_exp = 0;
+      return;
+    }
+
+  vsize = ABS (vsize);
+  prec = r->_mp_prec;
+
+  TMP_MARK;
+  rexp = 1 - v->_mp_exp + 1;
+
+  rp = r->_mp_d;
+  vp = v->_mp_d;
+
+  prospective_rsize = 1 - vsize + 1;    /* quot from using given u,v sizes */
+  rsize = prec + 1;                     /* desired quot size */
+
+  zeros = rsize - prospective_rsize;    /* padding u to give rsize */
+  tsize = 1 + zeros;                    /* u with zeros */
+
+  if (WANT_TMP_DEBUG)
+    {
+      /* separate alloc blocks, for malloc debugging */
+      remp = TMP_ALLOC_LIMBS (vsize);
+      tp = TMP_ALLOC_LIMBS (tsize);
+      new_vp = NULL;
+      if (rp == vp)
+        new_vp = TMP_ALLOC_LIMBS (vsize);
+    }
+  else
+    {
+      /* one alloc with calculated size, for efficiency */
+      mp_size_t size = vsize + tsize + (rp == vp ? vsize : 0);
+      remp = TMP_ALLOC_LIMBS (size);
+      tp = remp + vsize;
+      new_vp = tp + tsize;
+    }
+
+  /* ensure divisor doesn't overlap quotient */
+  if (rp == vp)
+    {
+      MPN_COPY (new_vp, vp, vsize);
+      vp = new_vp;
+    }
+
+  MPN_ZERO (tp, tsize-1);
+
+  tp[tsize - 1] = u & GMP_NUMB_MASK;
+#if BITS_PER_ULONG > GMP_NUMB_BITS
+  if (u > GMP_NUMB_MAX)
+    {
+      /* tsize-vsize+1 == rsize, so tsize >= rsize.  rsize == prec+1 >= 2,
+         so tsize >= 2, hence there's room for 2-limb u with nails */
+      ASSERT (tsize >= 2);
+      tp[tsize - 1] = u >> GMP_NUMB_BITS;
+      tp[tsize - 2] = u & GMP_NUMB_MASK;
+      rexp++;
+    }
+#endif
+
+  ASSERT (tsize-vsize+1 == rsize);
+  mpn_tdiv_qr (rp, remp, (mp_size_t) 0, tp, tsize, vp, vsize);
+
+  /* strip possible zero high limb */
+  high_zero = (rp[rsize-1] == 0);
+  rsize -= high_zero;
+  rexp -= high_zero;
+
+  r->_mp_size = sign_quotient >= 0 ? rsize : -rsize;
+  r->_mp_exp = rexp;
+  TMP_FREE;
+}
diff --git a/third_party/gmp/mpf/ui_sub.c b/third_party/gmp/mpf/ui_sub.c
new file mode 100644
index 0000000..58da56b
--- /dev/null
+++ b/third_party/gmp/mpf/ui_sub.c
@@ -0,0 +1,281 @@
+/* mpf_ui_sub -- Subtract a float from an unsigned long int.
+
+Copyright 1993-1996, 2001, 2002, 2005, 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpf_ui_sub (mpf_ptr r, unsigned long int u, mpf_srcptr v)
+{
+#if 1
+  __mpf_struct uu;
+  mp_limb_t ul;
+
+  if (u == 0)
+    {
+      mpf_neg (r, v);
+      return;
+    }
+
+  ul = u;
+  uu._mp_size = 1;
+  uu._mp_d = &ul;
+  uu._mp_exp = 1;
+  mpf_sub (r, &uu, v);
+
+#else
+  mp_srcptr up, vp;
+  mp_ptr rp, tp;
+  mp_size_t usize, vsize, rsize;
+  mp_size_t prec;
+  mp_exp_t uexp;
+  mp_size_t ediff;
+  int negate;
+  mp_limb_t ulimb;
+  TMP_DECL;
+
+  vsize = v->_mp_size;
+
+  /* Handle special cases that don't work in generic code below.  */
+  if (u == 0)
+    {
+      mpf_neg (r, v);
+      return;
+    }
+  if (vsize == 0)
+    {
+      mpf_set_ui (r, u);
+      return;
+    }
+
+  /* If signs of U and V are different, perform addition.  */
+  if (vsize < 0)
+    {
+      __mpf_struct v_negated;
+      v_negated._mp_size = -vsize;
+      v_negated._mp_exp = v->_mp_exp;
+      v_negated._mp_d = v->_mp_d;
+      mpf_add_ui (r, &v_negated, u);
+      return;
+    }
+
+  /* Signs are now known to be the same.  */
+  ASSERT (vsize > 0);
+  ulimb = u;
+  /* Make U be the operand with the largest exponent.  */
+  negate = 1 < v->_mp_exp;
+  prec = r->_mp_prec + negate;
+  rp = r->_mp_d;
+  if (negate)
+    {
+      usize = vsize;
+      vsize = 1;
+      up = v->_mp_d;
+      vp = &ulimb;
+      uexp = v->_mp_exp;
+      ediff = uexp - 1;
+
+      /* If U extends beyond PREC, ignore the part that does.  */
+      if (usize > prec)
+	{
+	  up += usize - prec;
+	  usize = prec;
+	}
+      ASSERT (ediff > 0);
+    }
+  else
+    {
+      vp = v->_mp_d;
+      ediff = 1 - v->_mp_exp;
+  /* Ignore leading limbs in U and V that are equal.  Doing
+     this helps increase the precision of the result.  */
+      if (ediff == 0 && ulimb == vp[vsize - 1])
+	{
+	  usize = 0;
+	  vsize--;
+	  uexp = 0;
+	  /* Note that V might now have leading zero limbs.
+	     In that case we have to adjust uexp.  */
+	  for (;;)
+	    {
+	      if (vsize == 0) {
+		rsize = 0;
+		uexp = 0;
+		goto done;
+	      }
+	      if ( vp[vsize - 1] != 0)
+		break;
+	      vsize--, uexp--;
+	    }
+	}
+      else
+	{
+	  usize = 1;
+	  uexp = 1;
+	  up = &ulimb;
+	}
+      ASSERT (usize <= prec);
+    }
+
+  if (ediff >= prec)
+    {
+      /* V completely cancelled.  */
+      if (rp != up)
+	MPN_COPY (rp, up, usize);
+      rsize = usize;
+    }
+  else
+    {
+  /* If V extends beyond PREC, ignore the part that does.
+     Note that this can make vsize neither zero nor negative.  */
+  if (vsize + ediff > prec)
+    {
+      vp += vsize + ediff - prec;
+      vsize = prec - ediff;
+    }
+
+      /* Locate the least significant non-zero limb in (the needed
+	 parts of) U and V, to simplify the code below.  */
+      ASSERT (vsize > 0);
+      for (;;)
+	{
+	  if (vp[0] != 0)
+	    break;
+	  vp++, vsize--;
+	  if (vsize == 0)
+	    {
+	      MPN_COPY (rp, up, usize);
+	      rsize = usize;
+	      goto done;
+	    }
+	}
+      for (;;)
+	{
+	  if (usize == 0)
+	    {
+	      MPN_COPY (rp, vp, vsize);
+	      rsize = vsize;
+	      negate ^= 1;
+	      goto done;
+	    }
+	  if (up[0] != 0)
+	    break;
+	  up++, usize--;
+	}
+
+      ASSERT (usize > 0 && vsize > 0);
+      TMP_MARK;
+
+      tp = TMP_ALLOC_LIMBS (prec);
+
+      /* uuuu     |  uuuu     |  uuuu     |  uuuu     |  uuuu    */
+      /* vvvvvvv  |  vv       |    vvvvv  |    v      |       vv */
+
+      if (usize > ediff)
+	{
+	  /* U and V partially overlaps.  */
+	  if (ediff == 0)
+	    {
+	      ASSERT (usize == 1 && vsize >= 1 && ulimb == *up); /* usize is 1>ediff, vsize >= 1 */
+	      if (1 < vsize)
+		{
+		  /* u        */
+		  /* vvvvvvv  */
+		  rsize = vsize;
+		  vsize -= 1;
+		  /* mpn_cmp (up, vp + vsize - usize, usize) > 0 */
+		  if (ulimb > vp[vsize])
+		    {
+		      tp[vsize] = ulimb - vp[vsize] - 1;
+		      ASSERT_CARRY (mpn_neg (tp, vp, vsize));
+		    }
+		  else
+		    {
+		      /* vvvvvvv  */  /* Swap U and V. */
+		      /* u        */
+		      MPN_COPY (tp, vp, vsize);
+		      tp[vsize] = vp[vsize] - ulimb;
+		      negate = 1;
+		    }
+		}
+	      else /* vsize == usize == 1 */
+		{
+		  /* u     */
+		  /* v     */
+		  rsize = 1;
+		  negate = ulimb < vp[0];
+		  tp[0] = negate ? vp[0] - ulimb: ulimb - vp[0];
+		}
+	    }
+	  else
+	    {
+	      ASSERT (vsize + ediff <= usize);
+	      ASSERT (vsize == 1 && usize >= 2 && ulimb == *vp);
+		{
+		  /* uuuu     */
+		  /*   v      */
+		  mp_size_t size;
+		  size = usize - ediff - 1;
+		  MPN_COPY (tp, up, size);
+		  ASSERT_NOCARRY (mpn_sub_1 (tp + size, up + size, usize - size, ulimb));
+		  rsize = usize;
+		}
+		/* Other cases are not possible */
+		/* uuuu     */
+		/*   vvvvv  */
+	    }
+	}
+      else
+	{
+	  /* uuuu     */
+	  /*      vv  */
+	  mp_size_t size, i;
+	  ASSERT_CARRY (mpn_neg (tp, vp, vsize));
+	  rsize = vsize + ediff;
+	  size = rsize - usize;
+	  for (i = vsize; i < size; i++)
+	    tp[i] = GMP_NUMB_MAX;
+	  ASSERT_NOCARRY (mpn_sub_1 (tp + size, up, usize, CNST_LIMB (1)));
+	}
+
+      /* Full normalize.  Optimize later.  */
+      while (rsize != 0 && tp[rsize - 1] == 0)
+	{
+	  rsize--;
+	  uexp--;
+	}
+      MPN_COPY (rp, tp, rsize);
+      TMP_FREE;
+    }
+
+ done:
+  r->_mp_size = negate ? -rsize : rsize;
+  r->_mp_exp = uexp;
+#endif
+}
diff --git a/third_party/gmp/mpf/urandomb.c b/third_party/gmp/mpf/urandomb.c
new file mode 100644
index 0000000..ebe85ab
--- /dev/null
+++ b/third_party/gmp/mpf/urandomb.c
@@ -0,0 +1,68 @@
+/* mpf_urandomb (rop, state, nbits) -- Generate a uniform pseudorandom
+   real number between 0 (inclusive) and 1 (exclusive) of size NBITS,
+   using STATE as the random state previously initialized by a call to
+   gmp_randinit().
+
+Copyright 1999-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpf_urandomb (mpf_t rop, gmp_randstate_t rstate, mp_bitcnt_t nbits)
+{
+  mp_ptr rp;
+  mp_size_t nlimbs;
+  mp_exp_t exp;
+  mp_size_t prec;
+
+  rp = PTR (rop);
+  nlimbs = BITS_TO_LIMBS (nbits);
+  prec = PREC (rop);
+
+  if (nlimbs > prec + 1 || nlimbs == 0)
+    {
+      nlimbs = prec + 1;
+      nbits = nlimbs * GMP_NUMB_BITS;
+    }
+
+  _gmp_rand (rp, rstate, nbits);
+
+  /* If nbits isn't a multiple of GMP_NUMB_BITS, shift up.  */
+  if (nbits % GMP_NUMB_BITS != 0)
+    mpn_lshift (rp, rp, nlimbs, GMP_NUMB_BITS - nbits % GMP_NUMB_BITS);
+
+  exp = 0;
+  while (nlimbs != 0 && rp[nlimbs - 1] == 0)
+    {
+      nlimbs--;
+      exp--;
+    }
+  EXP (rop) = exp;
+  SIZ (rop) = nlimbs;
+}
diff --git a/third_party/gmp/mpn.bzl b/third_party/gmp/mpn.bzl
new file mode 100644
index 0000000..d498070
--- /dev/null
+++ b/third_party/gmp/mpn.bzl
@@ -0,0 +1,201 @@
+alternatives = {
+    "add_n": ["aors_n"],
+    "sub_n": ["aors_n"],
+    "add_err1_n": ["aors_err1_n"],
+    "sub_err1_n": ["aors_err1_n"],
+    "add_err2_n": ["aors_err2_n"],
+    "sub_err2_n": ["aors_err2_n"],
+    "add_err3_n": ["aors_err3_n"],
+    "sub_err3_n": ["aors_err3_n"],
+    "cnd_add_n": ["cnd_aors_n"],
+    "cnd_sub_n": ["cnd_aors_n"],
+    "sec_add_1": ["sec_aors_1"],
+    "sec_sub_1": ["sec_aors_1"],
+    "addmul_1": ["aorsmul_1"],
+    "submul_1": ["aorsmul_1"],
+    "mul_2": ["aormul_2"],
+    "addmul_2": ["aormul_2"],
+    "mul_3": ["aormul_3"],
+    "addmul_3": ["aormul_3"],
+    "mul_4": ["aormul_4"],
+    "addmul_4": ["aormul_4"],
+    "popcount": ["popham"],
+    "hamdist": ["popham"],
+    "and_n": ["logops_n"],
+    "andn_n": ["logops_n"],
+    "nand_n": ["logops_n"],
+    "ior_n": ["logops_n"],
+    "iorn_n": ["logops_n"],
+    "nior_n": ["logops_n"],
+    "xor_n": ["logops_n"],
+    "xnor_n": ["logops_n"],
+    "lshift": ["lorrshift"],
+    "rshift": ["lorrshift"],
+    "addlsh1_n": ["aorslsh1_n", "aorrlsh1_n", "aorsorrlsh1_n"],
+    "sublsh1_n": ["aorslsh1_n", "sorrlsh1_n", "aorsorrlsh1_n"],
+    "rsblsh1_n": ["aorrlsh1_n", "sorrlsh1_n", "aorsorrlsh1_n"],
+    "addlsh2_n": ["aorslsh2_n", "aorrlsh2_n", "aorsorrlsh2_n"],
+    "sublsh2_n": ["aorslsh2_n", "sorrlsh2_n", "aorsorrlsh2_n"],
+    "rsblsh2_n": ["aorrlsh2_n", "sorrlsh2_n", "aorsorrlsh2_n"],
+    "addlsh_n": ["aorslsh_n", "aorrlsh_n", "aorsorrlsh_n"],
+    "sublsh_n": ["aorslsh_n", "sorrlsh_n", "aorsorrlsh_n"],
+    "rsblsh_n": ["aorrlsh_n", "sorrlsh_n", "aorsorrlsh_n"],
+    "rsh1add_n": ["rsh1aors_n"],
+    "rsh1sub_n": ["rsh1aors_n"],
+    "sec_div_qr": ["sec_div"],
+    "sec_div_r": ["sec_div"],
+    "sec_pi1_div_qr": ["sec_pi1_div"],
+    "sec_pi1_div_r": ["sec_pi1_div"],
+}
+
+def current_directory():
+    return native.package_name()
+
+def mpn_cc_library(
+        name,
+        srcs,
+        hdrs = [],
+        copts = [],
+        deps = [],
+        target_compatible_with = None):
+    native.cc_library(
+        name = name,
+        srcs = srcs,
+        hdrs = hdrs,
+        copts = copts + [
+            "-DHAVE_CONFIG_H",
+            "-I" + current_directory() + "/mpn",
+            "-I" + current_directory(),
+            "-I$(GENDIR)/" + current_directory(),
+            "-D__GMP_WITHIN_GMP",
+            "-DOPERATION_" + name,
+        ],
+        deps = deps,
+        target_compatible_with = target_compatible_with,
+    )
+
+def _m4_mpn_function_impl(ctx):
+    if len(ctx.files.files) == 0:
+        out = ctx.actions.declare_file("mpn/" + ctx.attr.operation + ".c")
+        ctx.actions.write(out, "")
+        return DefaultInfo(files = depset([out]))
+
+    if ctx.files.files[0].extension == "c":
+        out = ctx.actions.declare_file("mpn/" + ctx.attr.operation + ".c")
+        ctx.actions.run_shell(
+            inputs = [ctx.files.files[0]],
+            outputs = [out],
+            progress_message = "Generating " + out.short_path,
+            command = "(echo '#define OPERATION_" + ctx.attr.operation + " 1'; cat " + ctx.files.files[0].path + ") > " + out.path,
+        )
+        return DefaultInfo(files = depset([out]))
+
+    out = ctx.actions.declare_file("mpn/" + ctx.attr.operation + ".s")
+
+    ruledir = ctx.label.workspace_root + "/" + ctx.label.package
+    ctx.actions.run_shell(
+        inputs = [ctx.files.files[0]] + ctx.files.deps,
+        outputs = [out],
+        progress_message = "Generating " + out.short_path,
+        tools = [ctx.executable._m4] + ctx.attr._m4_lib.files.to_list(),
+        command = " && ".join([
+            "ROOT=$(pwd)",
+            "cd ./" + ruledir + "/mpn",
+            "echo '#define OPERATION_" + ctx.attr.operation + " 1' > ${ROOT}/" + out.path,
+            "LD_LIBRARY_PATH=${ROOT}/external/m4_v1.4.18/usr/lib/x86_64-linux-gnu/ ${ROOT}/" + ctx.executable._m4.path + " -I ${ROOT}/" + ctx.var["GENDIR"] + "/" + ruledir + "/mpn" +
+            " -DHAVE_CONFIG_H -D__GMP_WITHIN_GMP -DOPERATION_" + ctx.attr.operation +
+            " -DPIC ${ROOT}/" + ctx.files.files[0].path + " >> ${ROOT}/" + out.path,
+        ]),
+    )
+
+    return DefaultInfo(files = depset([out]))
+
+_m4_mpn_function = rule(
+    attrs = {
+        "files": attr.label_list(
+            allow_files = True,
+        ),
+        "deps": attr.label_list(
+            mandatory = True,
+            allow_files = True,
+        ),
+        "operation": attr.string(
+            mandatory = True,
+        ),
+        "_m4": attr.label(
+            default = "@m4_v1.4.18//:bin",
+            cfg = "host",
+            executable = True,
+        ),
+        "_m4_lib": attr.label(
+            default = "@m4_v1.4.18//:lib",
+            cfg = "host",
+        ),
+    },
+    implementation = _m4_mpn_function_impl,
+)
+
+def mparam_path(architecture_paths):
+    result = dict()
+    for key in architecture_paths:
+        value = architecture_paths[key]
+        globs = []
+        for p in value:
+            globs += native.glob([
+                "mpn/" + p + "/gmp-mparam.h",
+            ])
+        result[key] = [globs[0]]
+
+    return select(result)
+
+def architecture_includes(architecture_paths):
+    result = dict()
+    for key in architecture_paths:
+        result[key] = ["-I" + current_directory() + "/mpn/" + p for p in architecture_paths[key]]
+    return select(result)
+
+def file_from_architecture(architecture_paths, f):
+    result = dict()
+    for key in architecture_paths:
+        result[key] = ["config/" + architecture_paths[key][0] + "/" + f]
+    return select(result)
+
+def config_include_from_architecture(architecture_paths):
+    result = dict()
+    for key in architecture_paths:
+        result[key] = ["-I" + current_directory() + "/config/" + architecture_paths[key][0] + "/"]
+    return select(result)
+
+def _file_globs(path, use_asm):
+    if use_asm:
+        return native.glob([
+            path + ".asm",
+            path + ".c",
+        ])
+    else:
+        return native.glob([
+            path + ".c",
+        ])
+
+def mpn_m4_cc_library(name, architecture_paths, target_compatible_with = None):
+    # Search architecture_paths in order from 0 to N.
+    # From there, search starting with the main name, then start looking at the alternatives.
+    # And then look for .c or .asm
+    architecture_globs = dict()
+    for key in architecture_paths:
+        value = architecture_paths[key]
+        globs = []
+        for p in value:
+            globs += _file_globs("mpn/" + p + "/" + name, "msan" not in key)
+            if name in alternatives:
+                for alternative in alternatives[name]:
+                    globs += _file_globs("mpn/" + p + "/" + alternative, "msan" not in key)
+        architecture_globs[key] = globs
+
+    _m4_mpn_function(
+        name = name,
+        operation = name,
+        files = select(architecture_globs),
+        deps = native.glob(["**/*.m4", "**/*.asm"]) + ["config.m4"],
+        target_compatible_with = target_compatible_with,
+    )
diff --git a/third_party/gmp/mpn/Makeasm.am b/third_party/gmp/mpn/Makeasm.am
new file mode 100644
index 0000000..5d7306c
--- /dev/null
+++ b/third_party/gmp/mpn/Makeasm.am
@@ -0,0 +1,118 @@
+## Automake asm file rules.
+
+# Copyright 1996, 1998-2002 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+
+# COMPILE minus CC.
+#
+COMPILE_FLAGS = $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) $(ASMFLAGS)
+
+# Flags used for preprocessing (in ansi2knr rules).
+#
+PREPROCESS_FLAGS = $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS)
+
+
+# Recent versions of automake (1.5 and up for instance) append automake
+# generated suffixes to this $(SUFFIXES) list.  This is essential for us,
+# since .c must come after .s, .S and .asm.  If .c is before .s, for
+# instance, then in the mpn directory "make" will see add_n.c mentioned in
+# an explicit rule (the ansi2knr stuff) and decide it must have add_n.c,
+# even if add_n.c doesn't exist but add_n.s does.  See GNU make
+# documentation "(make)Implicit Rule Search", part 5c.
+#
+# On IRIX 6 native make this doesn't work properly though.  Somehow .c
+# remains ahead of .s, perhaps because .c.s is a builtin rule.  .asm works
+# fine though, and mpn/mips3 uses this.
+#
+SUFFIXES = .s .S .asm
+
+
+# .s assembler, no preprocessing.
+#
+.s.o:
+	$(CCAS) $(COMPILE_FLAGS) `test -f '$<' || echo '$(srcdir)/'`$<
+.s.obj:
+	$(CCAS) $(COMPILE_FLAGS) `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi`
+.s.lo:
+	$(LIBTOOL) --mode=compile --tag=CC $(CCAS) $(COMPILE_FLAGS) `test -f '$<' || echo '$(srcdir)/'`$<
+
+
+# can be overridden during development, eg. "make RM_TMP=: mul_1.lo"
+RM_TMP = rm -f
+
+
+# .S assembler, preprocessed with cpp.
+#
+# It's necessary to run $(CPP) separately, since it seems not all compilers
+# recognise .S files, in particular "cc" on HP-UX 10 and 11 doesn't (and
+# will silently do nothing if given a .S).
+#
+# For .lo we need a helper script, as described below for .asm.lo.
+#
+.S.o:
+	$(CPP) $(PREPROCESS_FLAGS) `test -f '$<' || echo '$(srcdir)/'`$< | grep -v '^#' >tmp-$*.s
+	$(CCAS) $(COMPILE_FLAGS) tmp-$*.s -o $@
+	$(RM_TMP) tmp-$*.s
+.S.obj:
+	$(CPP) $(PREPROCESS_FLAGS) `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi` | grep -v '^#' >tmp-$*.s
+	$(CCAS) $(COMPILE_FLAGS) tmp-$*.s -o $@
+	$(RM_TMP) tmp-$*.s
+.S.lo:
+	$(LIBTOOL) --mode=compile --tag=CC $(top_srcdir)/mpn/cpp-ccas --cpp="$(CPP) $(PREPROCESS_FLAGS)" $(CCAS) $(COMPILE_FLAGS) `test -f '$<' || echo '$(srcdir)/'`$<
+
+
+# .asm assembler, preprocessed with m4.
+#
+# .o and .obj are non-PIC and just need m4 followed by a compile.
+#
+# .lo is a bit tricky.  Libtool (as of version 1.5) has foo.lo as a little
+# text file, and .libs/foo.o and foo.o as the PIC and non-PIC objects,
+# respectively.  It'd be asking for lots of trouble to try to create foo.lo
+# ourselves, so instead arrange to invoke libtool like a --mode=compile, but
+# with a special m4-ccas script which first m4 preprocesses, then compiles.
+# --tag=CC is necessary since foo.asm is otherwise unknown to libtool.
+#
+# Libtool adds -DPIC when building a shared object and the .asm files look
+# for that.  But it should be noted that the other PIC flags are on occasion
+# important too, in particular FreeBSD 2.2.8 gas 1.92.3 requires -k before
+# it accepts PIC constructs like @GOT, and gcc adds that flag only under
+# -fPIC.  (Later versions of gas are happy to accept PIC stuff any time.)
+#
+.asm.o:
+	$(M4) -DOPERATION_$* `test -f '$<' || echo '$(srcdir)/'`$< >tmp-$*.s
+	$(CCAS) $(COMPILE_FLAGS) tmp-$*.s -o $@
+	$(RM_TMP) tmp-$*.s
+.asm.obj:
+	$(M4) -DOPERATION_$* `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi` >tmp-$*.s
+	$(CCAS) $(COMPILE_FLAGS) tmp-$*.s -o $@
+	$(RM_TMP) tmp-$*.s
+.asm.lo:
+	$(LIBTOOL) --mode=compile --tag=CC $(top_srcdir)/mpn/m4-ccas --m4="$(M4)" $(CCAS) $(COMPILE_FLAGS) `test -f '$<' || echo '$(srcdir)/'`$<
diff --git a/third_party/gmp/mpn/Makefile.am b/third_party/gmp/mpn/Makefile.am
new file mode 100644
index 0000000..3ab4006
--- /dev/null
+++ b/third_party/gmp/mpn/Makefile.am
@@ -0,0 +1,59 @@
+## Process this file with automake to generate Makefile.in
+
+# Copyright 1996, 1998-2002, 2005, 2011, 2013 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+
+AM_CPPFLAGS = -D__GMP_WITHIN_GMP -I$(top_srcdir) \
+  -DOPERATION_`echo $* | sed 's/_$$//'`
+
+OFILES = @mpn_objects@
+
+noinst_LTLIBRARIES = libmpn.la
+nodist_libmpn_la_SOURCES = fib_table.c mp_bases.c
+libmpn_la_LIBADD = $(OFILES)
+libmpn_la_DEPENDENCIES = $(OFILES)
+
+TARG_DIST = alpha arm arm64 cray generic ia64 lisp m68k m88k \
+  minithres mips32 mips64 pa32 pa64 power powerpc32 powerpc64 \
+  riscv s390_32 s390_64 sh sparc32 sparc64 thumb vax x86 x86_64
+
+EXTRA_DIST = asm-defs.m4 cpp-ccas m4-ccas $(TARG_DIST)
+
+
+# These are BUILT_SOURCES at the top-level, so normally they're built before
+# recursing into this directory.
+#
+fib_table.c:
+	cd ..; $(MAKE) $(AM_MAKEFLAGS) mpn/fib_table.c
+mp_bases.c:
+	cd ..; $(MAKE) $(AM_MAKEFLAGS) mpn/mp_bases.c
+perfsqr.h:
+	cd ..; $(MAKE) $(AM_MAKEFLAGS) mpn/perfsqr.h
+
+include Makeasm.am
diff --git a/third_party/gmp/mpn/Makefile.in b/third_party/gmp/mpn/Makefile.in
new file mode 100644
index 0000000..6593969
--- /dev/null
+++ b/third_party/gmp/mpn/Makefile.in
@@ -0,0 +1,772 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Copyright 1996, 1998-2002, 2005, 2011, 2013 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+# Copyright 1996, 1998-2002 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = mpn
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+nodist_libmpn_la_OBJECTS = fib_table.lo mp_bases.lo
+libmpn_la_OBJECTS = $(nodist_libmpn_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp =
+am__depfiles_maybe =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+SOURCES = $(nodist_libmpn_la_SOURCES)
+DIST_SOURCES =
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makeasm.am $(srcdir)/Makefile.in README
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ABI = @ABI@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+ASMFLAGS = @ASMFLAGS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CALLING_CONVENTIONS_OBJS = @CALLING_CONVENTIONS_OBJS@
+CC = @CC@
+CCAS = @CCAS@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPP_FOR_BUILD = @CPP_FOR_BUILD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFN_LONG_LONG_LIMB = @DEFN_LONG_LONG_LIMB@
+DEFS = @DEFS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@
+FGREP = @FGREP@
+GMP_LDFLAGS = @GMP_LDFLAGS@
+GMP_LIMB_BITS = @GMP_LIMB_BITS@
+GMP_NAIL_BITS = @GMP_NAIL_BITS@
+GREP = @GREP@
+HAVE_CLOCK_01 = @HAVE_CLOCK_01@
+HAVE_CPUTIME_01 = @HAVE_CPUTIME_01@
+HAVE_GETRUSAGE_01 = @HAVE_GETRUSAGE_01@
+HAVE_GETTIMEOFDAY_01 = @HAVE_GETTIMEOFDAY_01@
+HAVE_HOST_CPU_FAMILY_power = @HAVE_HOST_CPU_FAMILY_power@
+HAVE_HOST_CPU_FAMILY_powerpc = @HAVE_HOST_CPU_FAMILY_powerpc@
+HAVE_SIGACTION_01 = @HAVE_SIGACTION_01@
+HAVE_SIGALTSTACK_01 = @HAVE_SIGALTSTACK_01@
+HAVE_SIGSTACK_01 = @HAVE_SIGSTACK_01@
+HAVE_STACK_T_01 = @HAVE_STACK_T_01@
+HAVE_SYS_RESOURCE_H_01 = @HAVE_SYS_RESOURCE_H_01@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCURSES = @LIBCURSES@
+LIBGMPXX_LDFLAGS = @LIBGMPXX_LDFLAGS@
+LIBGMP_DLL = @LIBGMP_DLL@
+LIBGMP_LDFLAGS = @LIBGMP_LDFLAGS@
+LIBM = @LIBM@
+LIBM_FOR_BUILD = @LIBM_FOR_BUILD@
+LIBOBJS = @LIBOBJS@
+LIBREADLINE = @LIBREADLINE@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+M4 = @M4@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPEED_CYCLECOUNTER_OBJ = @SPEED_CYCLECOUNTER_OBJ@
+STRIP = @STRIP@
+TAL_OBJECT = @TAL_OBJECT@
+TUNE_LIBS = @TUNE_LIBS@
+TUNE_SQR_OBJ = @TUNE_SQR_OBJ@
+U_FOR_BUILD = @U_FOR_BUILD@
+VERSION = @VERSION@
+WITH_READLINE_01 = @WITH_READLINE_01@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__leading_dot = @am__leading_dot@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gmp_srclinks = @gmp_srclinks@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+mpn_objects = @mpn_objects@
+mpn_objs_in_libgmp = @mpn_objs_in_libgmp@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_CPPFLAGS = -D__GMP_WITHIN_GMP -I$(top_srcdir) \
+  -DOPERATION_`echo $* | sed 's/_$$//'`
+
+OFILES = @mpn_objects@
+noinst_LTLIBRARIES = libmpn.la
+nodist_libmpn_la_SOURCES = fib_table.c mp_bases.c
+libmpn_la_LIBADD = $(OFILES)
+libmpn_la_DEPENDENCIES = $(OFILES)
+TARG_DIST = alpha arm arm64 cray generic ia64 lisp m68k m88k \
+  minithres mips32 mips64 pa32 pa64 power powerpc32 powerpc64 \
+  riscv s390_32 s390_64 sh sparc32 sparc64 thumb vax x86 x86_64
+
+EXTRA_DIST = asm-defs.m4 cpp-ccas m4-ccas $(TARG_DIST)
+
+# COMPILE minus CC.
+#
+COMPILE_FLAGS = $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) $(ASMFLAGS)
+
+
+# Flags used for preprocessing (in ansi2knr rules).
+#
+PREPROCESS_FLAGS = $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS)
+
+
+# Recent versions of automake (1.5 and up for instance) append automake
+# generated suffixes to this $(SUFFIXES) list.  This is essential for us,
+# since .c must come after .s, .S and .asm.  If .c is before .s, for
+# instance, then in the mpn directory "make" will see add_n.c mentioned in
+# an explicit rule (the ansi2knr stuff) and decide it must have add_n.c,
+# even if add_n.c doesn't exist but add_n.s does.  See GNU make
+# documentation "(make)Implicit Rule Search", part 5c.
+#
+# On IRIX 6 native make this doesn't work properly though.  Somehow .c
+# remains ahead of .s, perhaps because .c.s is a builtin rule.  .asm works
+# fine though, and mpn/mips3 uses this.
+#
+SUFFIXES = .s .S .asm
+
+# can be overridden during development, eg. "make RM_TMP=: mul_1.lo"
+RM_TMP = rm -f
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .s .S .asm .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/Makeasm.am $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu --ignore-deps mpn/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu --ignore-deps mpn/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+$(srcdir)/Makeasm.am $(am__empty):
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+	@list='$(noinst_LTLIBRARIES)'; \
+	locs=`for p in $$list; do echo $$p; done | \
+	      sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+	      sort -u`; \
+	test -z "$$locs" || { \
+	  echo rm -f $${locs}; \
+	  rm -f $${locs}; \
+	}
+
+libmpn.la: $(libmpn_la_OBJECTS) $(libmpn_la_DEPENDENCIES) $(EXTRA_libmpn_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(LINK)  $(libmpn_la_OBJECTS) $(libmpn_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+.c.o:
+	$(AM_V_CC)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+	$(AM_V_CC)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+	$(AM_V_CC)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+	clean-libtool clean-noinstLTLIBRARIES cscopelist-am ctags \
+	ctags-am distclean distclean-compile distclean-generic \
+	distclean-libtool distclean-tags distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-dvi install-dvi-am install-exec \
+	install-exec-am install-html install-html-am install-info \
+	install-info-am install-man install-pdf install-pdf-am \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# These are BUILT_SOURCES at the top-level, so normally they're built before
+# recursing into this directory.
+#
+fib_table.c:
+	cd ..; $(MAKE) $(AM_MAKEFLAGS) mpn/fib_table.c
+mp_bases.c:
+	cd ..; $(MAKE) $(AM_MAKEFLAGS) mpn/mp_bases.c
+perfsqr.h:
+	cd ..; $(MAKE) $(AM_MAKEFLAGS) mpn/perfsqr.h
+
+# .s assembler, no preprocessing.
+#
+.s.o:
+	$(CCAS) $(COMPILE_FLAGS) `test -f '$<' || echo '$(srcdir)/'`$<
+.s.obj:
+	$(CCAS) $(COMPILE_FLAGS) `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi`
+.s.lo:
+	$(LIBTOOL) --mode=compile --tag=CC $(CCAS) $(COMPILE_FLAGS) `test -f '$<' || echo '$(srcdir)/'`$<
+
+# .S assembler, preprocessed with cpp.
+#
+# It's necessary to run $(CPP) separately, since it seems not all compilers
+# recognise .S files, in particular "cc" on HP-UX 10 and 11 doesn't (and
+# will silently do nothing if given a .S).
+#
+# For .lo we need a helper script, as described below for .asm.lo.
+#
+.S.o:
+	$(CPP) $(PREPROCESS_FLAGS) `test -f '$<' || echo '$(srcdir)/'`$< | grep -v '^#' >tmp-$*.s
+	$(CCAS) $(COMPILE_FLAGS) tmp-$*.s -o $@
+	$(RM_TMP) tmp-$*.s
+.S.obj:
+	$(CPP) $(PREPROCESS_FLAGS) `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi` | grep -v '^#' >tmp-$*.s
+	$(CCAS) $(COMPILE_FLAGS) tmp-$*.s -o $@
+	$(RM_TMP) tmp-$*.s
+.S.lo:
+	$(LIBTOOL) --mode=compile --tag=CC $(top_srcdir)/mpn/cpp-ccas --cpp="$(CPP) $(PREPROCESS_FLAGS)" $(CCAS) $(COMPILE_FLAGS) `test -f '$<' || echo '$(srcdir)/'`$<
+
+# .asm assembler, preprocessed with m4.
+#
+# .o and .obj are non-PIC and just need m4 followed by a compile.
+#
+# .lo is a bit tricky.  Libtool (as of version 1.5) has foo.lo as a little
+# text file, and .libs/foo.o and foo.o as the PIC and non-PIC objects,
+# respectively.  It'd be asking for lots of trouble to try to create foo.lo
+# ourselves, so instead arrange to invoke libtool like a --mode=compile, but
+# with a special m4-ccas script which first m4 preprocesses, then compiles.
+# --tag=CC is necessary since foo.asm is otherwise unknown to libtool.
+#
+# Libtool adds -DPIC when building a shared object and the .asm files look
+# for that.  But it should be noted that the other PIC flags are on occasion
+# important too, in particular FreeBSD 2.2.8 gas 1.92.3 requires -k before
+# it accepts PIC constructs like @GOT, and gcc adds that flag only under
+# -fPIC.  (Later versions of gas are happy to accept PIC stuff any time.)
+#
+.asm.o:
+	$(M4) -DOPERATION_$* `test -f '$<' || echo '$(srcdir)/'`$< >tmp-$*.s
+	$(CCAS) $(COMPILE_FLAGS) tmp-$*.s -o $@
+	$(RM_TMP) tmp-$*.s
+.asm.obj:
+	$(M4) -DOPERATION_$* `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi` >tmp-$*.s
+	$(CCAS) $(COMPILE_FLAGS) tmp-$*.s -o $@
+	$(RM_TMP) tmp-$*.s
+.asm.lo:
+	$(LIBTOOL) --mode=compile --tag=CC $(top_srcdir)/mpn/m4-ccas --m4="$(M4)" $(CCAS) $(COMPILE_FLAGS) `test -f '$<' || echo '$(srcdir)/'`$<
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/third_party/gmp/mpn/README b/third_party/gmp/mpn/README
new file mode 100644
index 0000000..bc046be
--- /dev/null
+++ b/third_party/gmp/mpn/README
@@ -0,0 +1,44 @@
+Copyright 1996, 1999 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.
+
+
+
+
+This directory contains all code for the mpn layer of GMP.
+
+Most subdirectories contain machine-dependent code, written in assembly or C.
+The `generic' subdirectory contains default code, used when there is no
+machine-dependent replacement for a particular machine.
+
+There is one subdirectory for each ISA family.  Note that e.g., 32-bit SPARC
+and 64-bit SPARC are very different ISA's, and thus cannot share any code.
+
+A particular compile will only use code from one subdirectory, and the
+`generic' subdirectory.  The ISA-specific subdirectories contain hierachies of
+directories for various architecture variants and implementations; the
+top-most level contains code that runs correctly on all variants.
diff --git a/third_party/gmp/mpn/alpha/README b/third_party/gmp/mpn/alpha/README
new file mode 100644
index 0000000..09c2f04
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/README
@@ -0,0 +1,208 @@
+Copyright 1996, 1997, 1999-2005 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.
+
+
+
+
+
+This directory contains mpn functions optimized for DEC Alpha processors.
+
+ALPHA ASSEMBLY RULES AND REGULATIONS
+
+The `.prologue N' pseudo op marks the end of instruction that needs special
+handling by unwinding.  It also says whether $27 is really needed for computing
+the gp.  The `.mask M' pseudo op says which registers are saved on the stack,
+and at what offset in the frame.
+
+Cray T3 code is very very different...
+
+"$6" / "$f6" etc is the usual syntax for registers, but on Unicos instead "r6"
+/ "f6" is required.  We use the "r6" / "f6" forms, and have m4 defines expand
+them to "$6" or "$f6" where necessary.
+
+"0x" introduces a hex constant in gas and DEC as, but on Unicos "^X" is
+required.  The X() macro accommodates this difference.
+
+"cvttqc" is required by DEC as, "cvttq/c" is required by Unicos, and gas will
+accept either.  We use cvttqc and have an m4 define expand to cvttq/c where
+necessary.
+
+"not" as an alias for "ornot r31, ..." is available in gas and DEC as, but not
+the Unicos assembler.  The full "ornot" must be used.
+
+"unop" is not available in Unicos.  We make an m4 define to the usual "ldq_u
+r31,0(r30)", and in fact use that define on all systems since it comes out the
+same.
+
+"!literal!123" etc explicit relocations as per Tru64 4.0 are apparently not
+available in older alpha assemblers (including gas prior to 2.12), according to
+the GCC manual, so the assembler macro forms must be used (eg. ldgp).
+
+
+
+RELEVANT OPTIMIZATION ISSUES
+
+EV4
+
+1. This chip has very limited store bandwidth.  The on-chip L1 cache is write-
+   through, and a cache line is transferred from the store buffer to the off-
+   chip L2 in as much 15 cycles on most systems.  This delay hurts mpn_add_n,
+   mpn_sub_n, mpn_lshift, and mpn_rshift.
+
+2. Pairing is possible between memory instructions and integer arithmetic
+   instructions.
+
+3. mulq and umulh are documented to have a latency of 23 cycles, but 2 of these
+   cycles are pipelined.  Thus, multiply instructions can be issued at a rate
+   of one each 21st cycle.
+
+EV5
+
+1. The memory bandwidth of this chip is good, both for loads and stores.  The
+   L1 cache can handle two loads or one store per cycle, but two cycles after a
+   store, no ld can issue.
+
+2. mulq has a latency of 12 cycles and an issue rate of 1 each 8th cycle.
+   umulh has a latency of 14 cycles and an issue rate of 1 each 10th cycle.
+   (Note that published documentation gets these numbers slightly wrong.)
+
+3. mpn_add_n.  With 4-fold unrolling, we need 37 instructions, whereof 12
+   are memory operations.  This will take at least
+	ceil(37/2) [dual issue] + 1 [taken branch] = 19 cycles
+   We have 12 memory cycles, plus 4 after-store conflict cycles, or 16 data
+   cache cycles, which should be completely hidden in the 19 issue cycles.
+   The computation is inherently serial, with these dependencies:
+
+	       ldq  ldq
+		 \  /\
+	  (or)   addq |
+	   |\   /   \ |
+	   | addq  cmpult
+	    \  |     |
+	     cmpult  |
+		 \  /
+		  or
+
+   I.e., 3 operations are needed between carry-in and carry-out, making 12
+   cycles the absolute minimum for the 4 limbs.  We could replace the `or' with
+   a cmoveq/cmovne, which could issue one cycle earlier that the `or', but that
+   might waste a cycle on EV4.  The total depth remain unaffected, since cmov
+   has a latency of 2 cycles.
+
+     addq
+     /   \
+   addq  cmpult
+     |      \
+   cmpult -> cmovne
+
+  Montgomery has a slightly different way of computing carry that requires one
+  less instruction, but has depth 4 (instead of the current 3).  Since the code
+  is currently instruction issue bound, Montgomery's idea should save us 1/2
+  cycle per limb, or bring us down to a total of 17 cycles or 4.25 cycles/limb.
+  Unfortunately, this method will not be good for the EV6.
+
+4. addmul_1 and friends: We previously had a scheme for splitting the single-
+   limb operand in 21-bits chunks and the multi-limb operand in 32-bit chunks,
+   and then use FP operations for every 2nd multiply, and integer operations
+   for every 2nd multiply.
+
+   But it seems much better to split the single-limb operand in 16-bit chunks,
+   since we save many integer shifts and adds that way.  See powerpc64/README
+   for some more details.
+
+EV6
+
+Here we have a really parallel pipeline, capable of issuing up to 4 integer
+instructions per cycle.  In actual practice, it is never possible to sustain
+more than 3.5 integer insns/cycle due to rename register shortage.  One integer
+multiply instruction can issue each cycle.  To get optimal speed, we need to
+pretend we are vectorizing the code, i.e., minimize the depth of recurrences.
+
+There are two dependencies to watch out for.  1) Address arithmetic
+dependencies, and 2) carry propagation dependencies.
+
+We can avoid serializing due to address arithmetic by unrolling loops, so that
+addresses don't depend heavily on an index variable.  Avoiding serializing
+because of carry propagation is trickier; the ultimate performance of the code
+will be determined of the number of latency cycles it takes from accepting
+carry-in to a vector point until we can generate carry-out.
+
+Most integer instructions can execute in either the L0, U0, L1, or U1
+pipelines.  Shifts only execute in U0 and U1, and multiply only in U1.
+
+CMOV instructions split into two internal instructions, CMOV1 and CMOV2.  CMOV
+split the mapping process (see pg 2-26 in cmpwrgd.pdf), suggesting the CMOV
+should always be placed as the last instruction of an aligned 4 instruction
+block, or perhaps simply avoided.
+
+Perhaps the most important issue is the latency between the L0/U0 and L1/U1
+clusters; a result obtained on either cluster has an extra cycle of latency for
+consumers in the opposite cluster.  Because of the dynamic nature of the
+implementation, it is hard to predict where an instruction will execute.
+
+
+
+REFERENCES
+
+"Alpha Architecture Handbook", version 4, Compaq, October 1998, order number
+EC-QD2KC-TE.
+
+"Alpha 21164 Microprocessor Hardware Reference Manual", Compaq, December 1998,
+order number EC-QP99C-TE.
+
+"Alpha 21264/EV67 Microprocessor Hardware Reference Manual", revision 1.4,
+Compaq, September 2000, order number DS-0028B-TE.
+
+"Compiler Writer's Guide for the Alpha 21264", Compaq, June 1999, order number
+EC-RJ66A-TE.
+
+All of the above are available online from
+
+  http://ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html
+  ftp://ftp.compaq.com/pub/products/alphaCPUdocs
+
+"Tru64 Unix Assembly Language Programmer's Guide", Compaq, March 1996, part
+number AA-PS31D-TE.
+
+"Digital UNIX Calling Standard for Alpha Systems", Digital Equipment Corp,
+March 1996, part number AA-PY8AC-TE.
+
+The above are available online,
+
+  http://h30097.www3.hp.com/docs/pub_page/V40F_DOCS.HTM
+
+(Dunno what h30097 means in this URL, but if it moves try searching for "tru64
+online documentation" from the main www.hp.com page.)
+
+
+
+----------------
+Local variables:
+mode: text
+fill-column: 79
+End:
diff --git a/third_party/gmp/mpn/alpha/add_n.asm b/third_party/gmp/mpn/alpha/add_n.asm
new file mode 100644
index 0000000..bc572a5
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/add_n.asm
@@ -0,0 +1,164 @@
+dnl  Alpha mpn_add_n -- Add two limb vectors of the same length > 0 and
+dnl  store sum in a third limb vector.
+
+dnl  Copyright 1995, 1999, 2000, 2005, 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C      cycles/limb
+C EV4:     ?
+C EV5:     4.75
+C EV6:     3
+
+dnl  INPUT PARAMETERS
+dnl  res_ptr	r16
+dnl  s1_ptr	r17
+dnl  s2_ptr	r18
+dnl  size	r19
+
+ASM_START()
+PROLOGUE(mpn_add_nc)
+	bis	r20,r31,r25
+	br	L(com)
+EPILOGUE()
+PROLOGUE(mpn_add_n)
+	bis	r31,r31,r25		C clear cy
+L(com):	subq	r19,4,r19		C decr loop cnt
+	blt	r19,$Lend2		C if less than 4 limbs, goto 2nd loop
+C Start software pipeline for 1st loop
+	ldq	r0,0(r18)
+	ldq	r4,0(r17)
+	ldq	r1,8(r18)
+	ldq	r5,8(r17)
+	addq	r17,32,r17		C update s1_ptr
+	addq	r0,r4,r28		C 1st main add
+	ldq	r2,16(r18)
+	addq	r25,r28,r20		C 1st carry add
+	ldq	r3,24(r18)
+	cmpult	r28,r4,r8		C compute cy from last add
+	ldq	r6,-16(r17)
+	cmpult	r20,r28,r25		C compute cy from last add
+	ldq	r7,-8(r17)
+	bis	r8,r25,r25		C combine cy from the two adds
+	subq	r19,4,r19		C decr loop cnt
+	addq	r1,r5,r28		C 2nd main add
+	addq	r18,32,r18		C update s2_ptr
+	addq	r28,r25,r21		C 2nd carry add
+	cmpult	r28,r5,r8		C compute cy from last add
+	blt	r19,$Lend1		C if less than 4 limbs remain, jump
+C 1st loop handles groups of 4 limbs in a software pipeline
+	ALIGN(16)
+$Loop:	cmpult	r21,r28,r25		C compute cy from last add
+	ldq	r0,0(r18)
+	bis	r8,r25,r25		C combine cy from the two adds
+	ldq	r1,8(r18)
+	addq	r2,r6,r28		C 3rd main add
+	ldq	r4,0(r17)
+	addq	r28,r25,r22		C 3rd carry add
+	ldq	r5,8(r17)
+	cmpult	r28,r6,r8		C compute cy from last add
+	cmpult	r22,r28,r25		C compute cy from last add
+	stq	r20,0(r16)
+	bis	r8,r25,r25		C combine cy from the two adds
+	stq	r21,8(r16)
+	addq	r3,r7,r28		C 4th main add
+	addq	r28,r25,r23		C 4th carry add
+	cmpult	r28,r7,r8		C compute cy from last add
+	cmpult	r23,r28,r25		C compute cy from last add
+		addq	r17,32,r17		C update s1_ptr
+	bis	r8,r25,r25		C combine cy from the two adds
+		addq	r16,32,r16		C update res_ptr
+	addq	r0,r4,r28		C 1st main add
+	ldq	r2,16(r18)
+	addq	r25,r28,r20		C 1st carry add
+	ldq	r3,24(r18)
+	cmpult	r28,r4,r8		C compute cy from last add
+	ldq	r6,-16(r17)
+	cmpult	r20,r28,r25		C compute cy from last add
+	ldq	r7,-8(r17)
+	bis	r8,r25,r25		C combine cy from the two adds
+	subq	r19,4,r19		C decr loop cnt
+	stq	r22,-16(r16)
+	addq	r1,r5,r28		C 2nd main add
+	stq	r23,-8(r16)
+	addq	r25,r28,r21		C 2nd carry add
+		addq	r18,32,r18		C update s2_ptr
+	cmpult	r28,r5,r8		C compute cy from last add
+	bge	r19,$Loop
+C Finish software pipeline for 1st loop
+$Lend1:	cmpult	r21,r28,r25		C compute cy from last add
+	bis	r8,r25,r25		C combine cy from the two adds
+	addq	r2,r6,r28		C 3rd main add
+	addq	r28,r25,r22		C 3rd carry add
+	cmpult	r28,r6,r8		C compute cy from last add
+	cmpult	r22,r28,r25		C compute cy from last add
+	stq	r20,0(r16)
+	bis	r8,r25,r25		C combine cy from the two adds
+	stq	r21,8(r16)
+	addq	r3,r7,r28		C 4th main add
+	addq	r28,r25,r23		C 4th carry add
+	cmpult	r28,r7,r8		C compute cy from last add
+	cmpult	r23,r28,r25		C compute cy from last add
+	bis	r8,r25,r25		C combine cy from the two adds
+	addq	r16,32,r16		C update res_ptr
+	stq	r22,-16(r16)
+	stq	r23,-8(r16)
+$Lend2:	addq	r19,4,r19		C restore loop cnt
+	beq	r19,$Lret
+C Start software pipeline for 2nd loop
+	ldq	r0,0(r18)
+	ldq	r4,0(r17)
+	subq	r19,1,r19
+	beq	r19,$Lend0
+C 2nd loop handles remaining 1-3 limbs
+	ALIGN(16)
+$Loop0:	addq	r0,r4,r28		C main add
+	ldq	r0,8(r18)
+	cmpult	r28,r4,r8		C compute cy from last add
+	ldq	r4,8(r17)
+	addq	r28,r25,r20		C carry add
+	addq	r18,8,r18
+	addq	r17,8,r17
+	stq	r20,0(r16)
+	cmpult	r20,r28,r25		C compute cy from last add
+	subq	r19,1,r19		C decr loop cnt
+	bis	r8,r25,r25		C combine cy from the two adds
+	addq	r16,8,r16
+	bne	r19,$Loop0
+$Lend0:	addq	r0,r4,r28		C main add
+	addq	r28,r25,r20		C carry add
+	cmpult	r28,r4,r8		C compute cy from last add
+	cmpult	r20,r28,r25		C compute cy from last add
+	stq	r20,0(r16)
+	bis	r8,r25,r25		C combine cy from the two adds
+
+$Lret:	bis	r25,r31,r0		C return cy
+	ret	r31,(r26),1
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/alpha/addmul_1.asm b/third_party/gmp/mpn/alpha/addmul_1.asm
new file mode 100644
index 0000000..c4e6834
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/addmul_1.asm
@@ -0,0 +1,99 @@
+dnl Alpha mpn_addmul_1 -- Multiply a limb vector with a limb and add the
+dnl result to a second limb vector.
+
+dnl  Copyright 1992, 1994, 1995, 2000, 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C      cycles/limb
+C EV4:     42
+C EV5:     18
+C EV6:      7
+
+C  INPUT PARAMETERS
+C  rp	r16
+C  up	r17
+C  n	r18
+C  vl	r19
+
+
+ASM_START()
+PROLOGUE(mpn_addmul_1)
+	ldq	r2,0(r17)	C r2 = s1_limb
+	addq	r17,8,r17	C s1_ptr++
+	subq	r18,1,r18	C size--
+	mulq	r2,r19,r3	C r3 = prod_low
+	ldq	r5,0(r16)	C r5 = *res_ptr
+	umulh	r2,r19,r0	C r0 = prod_high
+	beq	r18,$Lend1	C jump if size was == 1
+	ldq	r2,0(r17)	C r2 = s1_limb
+	addq	r17,8,r17	C s1_ptr++
+	subq	r18,1,r18	C size--
+	addq	r5,r3,r3
+	cmpult	r3,r5,r4
+	stq	r3,0(r16)
+	addq	r16,8,r16	C res_ptr++
+	beq	r18,$Lend2	C jump if size was == 2
+
+	ALIGN(8)
+$Loop:	mulq	r2,r19,r3	C r3 = prod_low
+	ldq	r5,0(r16)	C r5 = *res_ptr
+	addq	r4,r0,r0	C cy_limb = cy_limb + 'cy'
+	subq	r18,1,r18	C size--
+	umulh	r2,r19,r4	C r4 = cy_limb
+	ldq	r2,0(r17)	C r2 = s1_limb
+	addq	r17,8,r17	C s1_ptr++
+	addq	r3,r0,r3	C r3 = cy_limb + prod_low
+	cmpult	r3,r0,r0	C r0 = carry from (cy_limb + prod_low)
+	addq	r5,r3,r3
+	cmpult	r3,r5,r5
+	stq	r3,0(r16)
+	addq	r16,8,r16	C res_ptr++
+	addq	r5,r0,r0	C combine carries
+	bne	r18,$Loop
+
+$Lend2:	mulq	r2,r19,r3	C r3 = prod_low
+	ldq	r5,0(r16)	C r5 = *res_ptr
+	addq	r4,r0,r0	C cy_limb = cy_limb + 'cy'
+	umulh	r2,r19,r4	C r4 = cy_limb
+	addq	r3,r0,r3	C r3 = cy_limb + prod_low
+	cmpult	r3,r0,r0	C r0 = carry from (cy_limb + prod_low)
+	addq	r5,r3,r3
+	cmpult	r3,r5,r5
+	stq	r3,0(r16)
+	addq	r5,r0,r0	C combine carries
+	addq	r4,r0,r0	C cy_limb = prod_high + cy
+	ret	r31,(r26),1
+$Lend1:	addq	r5,r3,r3
+	cmpult	r3,r5,r5
+	stq	r3,0(r16)
+	addq	r0,r5,r0
+	ret	r31,(r26),1
+EPILOGUE(mpn_addmul_1)
+ASM_END()
diff --git a/third_party/gmp/mpn/alpha/alpha-defs.m4 b/third_party/gmp/mpn/alpha/alpha-defs.m4
new file mode 100644
index 0000000..af34c92
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/alpha-defs.m4
@@ -0,0 +1,107 @@
+divert(-1)
+
+dnl  m4 macros for Alpha assembler.
+
+dnl  Copyright 2003, 2004 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+dnl  Usage: ASSERT([reg] [,code])
+dnl
+dnl  Require that the given reg is non-zero after executing the test code.
+dnl  For example,
+dnl
+dnl         ASSERT(r8,
+dnl         `       cmpult r16, r17, r8')
+dnl
+dnl  If the register argument is empty then nothing is tested, the code is
+dnl  just executed.  This can be used for setups required by later ASSERTs.
+dnl  If the code argument is omitted then the register is just tested, with
+dnl  no special setup code.
+
+define(ASSERT,
+m4_assert_numargs_range(1,2)
+m4_assert_defined(`WANT_ASSERT')
+`ifelse(WANT_ASSERT,1,
+`ifelse(`$2',,,`$2')
+ifelse(`$1',,,
+`	bne	$1, L(ASSERTok`'ASSERT_label_counter)
+	.long	0	C halt
+L(ASSERTok`'ASSERT_label_counter):
+define(`ASSERT_label_counter',eval(ASSERT_label_counter+1))
+')
+')')
+define(`ASSERT_label_counter',1)
+
+
+dnl  Usage: bigend(`code')
+dnl
+dnl  Emit the given code only for a big-endian system, like Unicos.  This
+dnl  can be used for instance for extra stuff needed by extwl.
+
+define(bigend,
+m4_assert_numargs(1)
+`ifdef(`HAVE_LIMB_BIG_ENDIAN',`$1',
+`ifdef(`HAVE_LIMB_LITTLE_ENDIAN',`',
+`m4_error(`Cannot assemble, unknown limb endianness')')')')
+
+
+dnl  Usage: bwx_available_p
+dnl
+dnl  Evaluate to 1 if the BWX byte memory instructions are available, or to
+dnl  0 if not.
+dnl
+dnl  Listing the chips which do have BWX means anything we haven't looked at
+dnl  will use safe non-BWX code.  The only targets without BWX currently are
+dnl  plain alpha (ie. ev4) and alphaev5.
+
+define(bwx_available_p,
+m4_assert_numargs(-1)
+`m4_ifdef_anyof_p(
+	`HAVE_HOST_CPU_alphaev56',
+	`HAVE_HOST_CPU_alphapca56',
+	`HAVE_HOST_CPU_alphapca57',
+	`HAVE_HOST_CPU_alphaev6',
+	`HAVE_HOST_CPU_alphaev67',
+	`HAVE_HOST_CPU_alphaev68',
+	`HAVE_HOST_CPU_alphaev69',
+	`HAVE_HOST_CPU_alphaev7',
+	`HAVE_HOST_CPU_alphaev79')')
+
+
+dnl  Usage: unop
+dnl
+dnl  The Cray Unicos assembler lacks unop, so give the equivalent ldq_u
+dnl  explicitly.
+
+define(unop,
+m4_assert_numargs(-1)
+`ldq_u	r31, 0(r30)')
+
+
+divert
diff --git a/third_party/gmp/mpn/alpha/aorslsh1_n.asm b/third_party/gmp/mpn/alpha/aorslsh1_n.asm
new file mode 100644
index 0000000..9525e66
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/aorslsh1_n.asm
@@ -0,0 +1,164 @@
+dnl  Alpha mpn_addlsh1_n/mpn_sublsh1_n -- rp[] = up[] +- (vp[] << 1).
+
+dnl  Copyright 2003, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C      cycles/limb
+C EV4:     ?
+C EV5:     6.25
+C EV6:     4.5
+
+define(`rp',`r16')
+define(`up',`r17')
+define(`vp',`r18')
+define(`n', `r19')
+
+define(`u0', `r8')
+define(`u1', `r1')
+define(`v0', `r4')
+define(`v1', `r5')
+
+define(`cy0', `r0')
+define(`cy1', `r20')
+define(`cy', `r22')
+define(`rr', `r24')
+define(`ps', `r25')
+define(`sl', `r28')
+
+ifdef(`OPERATION_addlsh1_n',`
+  define(ADDSUB,       addq)
+  define(CARRY,       `cmpult $1,$2,$3')
+  define(func, mpn_addlsh1_n)
+')
+ifdef(`OPERATION_sublsh1_n',`
+  define(ADDSUB,       subq)
+  define(CARRY,       `cmpult $2,$1,$3')
+  define(func, mpn_sublsh1_n)
+')
+
+MULFUNC_PROLOGUE(mpn_addlsh1_n mpn_sublsh1_n)
+
+ASM_START()
+PROLOGUE(func)
+	and	n, 2, cy0
+	blbs	n, L(bx1)
+L(bx0):	ldq	v1, 0(vp)
+	ldq	u1, 0(up)
+	nop
+	bne	cy0, L(b10)
+
+L(b00):	lda	vp, 48(vp)
+	lda	up, -16(up)
+	lda	rp, -8(rp)
+	br	r31, L(lo0)
+
+L(b10):	lda	vp, 32(vp)
+	lda	rp, 8(rp)
+	lda	cy0, 0(r31)
+	br	r31, L(lo2)
+
+L(bx1):	ldq	v0, 0(vp)
+	ldq	u0, 0(up)
+	lda	cy1, 0(r31)
+	beq	cy0, L(b01)
+
+L(b11):	lda	vp, 40(vp)
+	lda	up, -24(up)
+	lda	rp, 16(rp)
+	br	r31, L(lo3)
+
+L(b01):	lda	n, -4(n)
+	ble	n, L(end)
+	lda	vp, 24(vp)
+	lda	up, -8(up)
+
+	ALIGN(16)
+L(top):	addq	v0, v0, sl	C left shift vlimb
+	ldq	v1, -16(vp)
+	ADDSUB	u0, sl, ps	C ulimb + (vlimb << 1)
+	cmplt	v0, r31, cy0	C carry out #1
+	ldq	u1, 16(up)
+	ADDSUB	ps, cy1, rr	C consume carry from previous operation
+	CARRY(	ps, u0, cy)	C carry out #2
+	stq	rr, 0(rp)
+	addq	cy, cy0, cy0	C combine carry out #1 and #2
+	CARRY(	rr, ps, cy)	C carry out #3
+	addq	cy, cy0, cy0	C final carry out
+	lda	vp, 32(vp)	C bookkeeping
+L(lo0):	addq	v1, v1, sl
+	ldq	v0, -40(vp)
+	ADDSUB	u1, sl, ps
+	cmplt	v1, r31, cy1
+	ldq	u0, 24(up)
+	ADDSUB	ps, cy0, rr
+	CARRY(	ps, u1, cy)
+	stq	rr, 8(rp)
+	addq	cy, cy1, cy1
+	CARRY(	rr, ps, cy)
+	addq	cy, cy1, cy1
+	lda	rp, 32(rp)	C bookkeeping
+L(lo3):	addq	v0, v0, sl
+	ldq	v1, -32(vp)
+	ADDSUB	u0, sl, ps
+	cmplt	v0, r31, cy0
+	ldq	u1, 32(up)
+	ADDSUB	ps, cy1, rr
+	CARRY(	ps, u0, cy)
+	stq	rr, -16(rp)
+	addq	cy, cy0, cy0
+	CARRY(	rr, ps, cy)
+	addq	cy, cy0, cy0
+	lda	up, 32(up)	C bookkeeping
+L(lo2):	addq	v1, v1, sl
+	ldq	v0, -24(vp)
+	ADDSUB	u1, sl, ps
+	cmplt	v1, r31, cy1
+	ldq	u0, 8(up)
+	ADDSUB	ps, cy0, rr
+	CARRY(	ps, u1, cy)
+	stq	rr, -8(rp)
+	addq	cy, cy1, cy1
+	CARRY(	rr, ps, cy)
+	addq	cy, cy1, cy1
+	lda	n, -4(n)	C bookkeeping
+	bgt	n, L(top)
+
+L(end):	addq	v0, v0, sl
+	ADDSUB	u0, sl, ps
+	ADDSUB	ps, cy1, rr
+	cmplt	v0, r31, cy0
+	CARRY(	ps, u0, cy)
+	stq	rr, 0(rp)
+	addq	cy, cy0, cy0
+	CARRY(	rr, ps, cy)
+	addq	cy, cy0, r0
+	ret	r31,(r26),1
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/alpha/aorslsh2_n.asm b/third_party/gmp/mpn/alpha/aorslsh2_n.asm
new file mode 100644
index 0000000..bdee1d6
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/aorslsh2_n.asm
@@ -0,0 +1,167 @@
+dnl  Alpha mpn_addlsh2_n/mpn_sublsh2_n -- rp[] = up[] +- (vp[] << 2).
+
+dnl  Copyright 2003, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C      cycles/limb
+C EV4:     ?
+C EV5:     6
+C EV6:     3.75
+
+C TODO
+C  * Tune to reach 3.5 c/l on ev6 and 5.75 c/l on ev5.
+
+define(`rp',`r16')
+define(`up',`r17')
+define(`vp',`r18')
+define(`n', `r19')
+
+define(`u0', `r8')
+define(`u1', `r1')
+define(`v0', `r4')
+define(`v1', `r5')
+
+define(`cy0', `r0')
+define(`cy1', `r20')
+define(`cy', `r22')
+define(`rr', `r24')
+define(`ps', `r25')
+define(`sl', `r28')
+
+ifdef(`OPERATION_addlsh2_n',`
+  define(ADDSUB,       addq)
+  define(CARRY,       `cmpult $1,$2,$3')
+  define(func, mpn_addlsh2_n)
+')
+ifdef(`OPERATION_sublsh2_n',`
+  define(ADDSUB,       subq)
+  define(CARRY,       `cmpult $2,$1,$3')
+  define(func, mpn_sublsh2_n)
+')
+
+MULFUNC_PROLOGUE(mpn_addlsh2_n mpn_sublsh2_n)
+
+ASM_START()
+PROLOGUE(func)
+	and	n, 2, cy0
+	blbs	n, L(bx1)
+L(bx0):	ldq	v1, 0(vp)
+	ldq	u1, 0(up)
+	bis	r31, r31, r2
+	bne	cy0, L(b10)
+
+L(b00):	lda	vp, 48(vp)
+	lda	up, -16(up)
+	lda	rp, -8(rp)
+	s4addq	v1, r31, sl
+	br	r31, L(lo0)
+
+L(b10):	lda	vp, 32(vp)
+	lda	rp, 8(rp)
+	lda	cy0, 0(r31)
+	br	r31, L(lo2)
+
+L(bx1):	ldq	v0, 0(vp)
+	ldq	u0, 0(up)
+	lda	cy1, 0(r31)
+	bis	r31, r31, r3
+	nop
+	beq	cy0, L(b01)
+
+L(b11):	lda	vp, 40(vp)
+	lda	up, -24(up)
+	lda	rp, 16(rp)
+	br	r31, L(lo3)
+
+L(b01):	lda	n, -4(n)
+	ble	n, L(end)
+	lda	vp, 24(vp)
+	lda	up, -8(up)
+
+	ALIGN(16)
+L(top):	s4addq	v0, r3, sl	C combined vlimb
+	ldq	v1, -16(vp)
+	ADDSUB	u0, sl, ps	C ulimb + (vlimb << 1)
+	ldq	u1, 16(up)
+	srl	v0, 62, r2	C high v bits
+	ADDSUB	ps, cy1, rr	C consume carry from previous operation
+	CARRY(	ps, u0, cy0)	C carry out #2
+	stq	rr, 0(rp)
+	CARRY(	rr, ps, cy)	C carry out #3
+	lda	vp, 32(vp)	C bookkeeping
+	addq	cy, cy0, cy0	C final carry out
+	s4addq	v1, r2, sl
+L(lo0):	ldq	v0, -40(vp)
+	ADDSUB	u1, sl, ps
+	ldq	u0, 24(up)
+	srl	v1, 62, r3
+	ADDSUB	ps, cy0, rr
+	CARRY(	ps, u1, cy1)
+	stq	rr, 8(rp)
+	CARRY(	rr, ps, cy)
+	lda	rp, 32(rp)	C bookkeeping
+	addq	cy, cy1, cy1
+L(lo3):	s4addq	v0, r3, sl
+	ldq	v1, -32(vp)
+	ADDSUB	u0, sl, ps
+	ldq	u1, 32(up)
+	srl	v0, 62, r2
+	ADDSUB	ps, cy1, rr
+	CARRY(	ps, u0, cy0)
+	stq	rr, -16(rp)
+	CARRY(	rr, ps, cy)
+	lda	up, 32(up)	C bookkeeping
+	addq	cy, cy0, cy0
+L(lo2):	s4addq	v1, r2, sl
+	ldq	v0, -24(vp)
+	ADDSUB	u1, sl, ps
+	ldq	u0, 8(up)
+	srl	v1, 62, r3
+	ADDSUB	ps, cy0, rr
+	CARRY(	ps, u1, cy1)
+	stq	rr, -8(rp)
+	CARRY(	rr, ps, cy)
+	lda	n, -4(n)	C bookkeeping
+	addq	cy, cy1, cy1
+	bgt	n, L(top)
+
+L(end):	s4addq	v0, r3, sl
+	ADDSUB	u0, sl, ps
+	srl	v0, 62, r2
+	ADDSUB	ps, cy1, rr
+	CARRY(	ps, u0, cy0)
+	stq	rr, 0(rp)
+	CARRY(	rr, ps, cy)
+	addq	cy, cy0, cy0
+	addq	cy0, r2, r0
+
+	ret	r31,(r26),1
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/alpha/bdiv_dbm1c.asm b/third_party/gmp/mpn/alpha/bdiv_dbm1c.asm
new file mode 100644
index 0000000..472966c
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/bdiv_dbm1c.asm
@@ -0,0 +1,282 @@
+dnl  Alpha mpn_bdiv_dbm1c.
+
+dnl  Copyright 2008 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C      cycles/limb
+C EV4:     42
+C EV5:     18
+C EV6:      3
+
+C TODO
+C  * Try less unrolling, 2-way should give the same performance.
+C  * Optimize feed-in and wind-down code, for speed, and perhaps further for
+C    code size.
+C  * This runs optimally given the algorithm, r8 is on a 3 operation recurrency
+C    path.  We have not tried very hard to find a better algorithm.  Perhaps
+C    it would be a good task for the GNU superoptimizer.
+
+C INPUT PARAMETERS
+define(`rp', `r16')
+define(`up', `r17')
+define(`n',  `r18')
+define(`bd', `r19')
+define(`cy', `r19')
+
+
+ASM_START()
+PROLOGUE(mpn_bdiv_dbm1c)
+	mov	r20, r8
+
+	ldq	r24, 0(r17)
+	and	r18, 3, r28
+	lda	r18, -4(r18)
+	beq	r28, L(b0)
+	cmpeq	r28, 1, r21
+	bne	r21, L(b1)
+	cmpeq	r28, 2, r21
+	bne	r21, L(b2)
+
+
+L(b3):	ldq	r2, 8(r17)
+	ldq	r3, 16(r17)
+	bgt	r18, L(gt3)
+
+	mulq	r24, r19, r5	C U1
+	umulh	r24, r19, r21	C U1
+	mulq	r2, r19, r6	C U1
+	umulh	r2, r19, r22	C U1
+	mulq	r3, r19, r7	C U1
+	umulh	r3, r19, r23	C U1
+	lda	r16, -32(r16)
+	br	L(cj3)
+
+L(gt3):	ldq	r0, 24(r17)
+	mulq	r24, r19, r5	C U1
+	umulh	r24, r19, r21	C U1
+	ldq	r1, 32(r17)
+	mulq	r2, r19, r6	C U1
+	umulh	r2, r19, r22	C U1
+	ldq	r2, 40(r17)
+	mulq	r3, r19, r7	C U1
+	umulh	r3, r19, r23	C U1
+	ldq	r3, 48(r17)
+	lda	r18, -4(r18)
+	lda	r17, 56(r17)
+	mulq	r0, r19, r4	C U1
+	bgt	r18, L(L3)
+
+	br	L(cj7)
+
+
+L(b2):	ldq	r3, 8(r17)
+	bgt	r18, L(gt2)
+
+	mulq	r24, r19, r6	C U1
+	umulh	r24, r19, r22	C U1
+	mulq	r3, r19, r7	C U1
+	umulh	r3, r19, r23	C U1
+	lda	r16, -40(r16)
+	br	L(cj2)
+
+L(gt2):	ldq	r0, 16(r17)
+	ldq	r1, 24(r17)
+	mulq	r24, r19, r6	C U1
+	umulh	r24, r19, r22	C U1
+	ldq	r2, 32(r17)
+	mulq	r3, r19, r7	C U1
+	umulh	r3, r19, r23	C U1
+	ldq	r3, 40(r17)
+	lda	r18, -4(r18)
+	lda	r17, 48(r17)
+	mulq	r0, r19, r4	C U1
+	umulh	r0, r19, r20	C U1
+	lda	r16, -8(r16)
+	bgt	r18, L(gt6)
+
+	mulq	r1, r19, r5	C U1
+	br	L(cj6)
+
+L(gt6):	ldq	r0, 0(r17)
+	mulq	r1, r19, r5	C U1
+	br	L(L2)
+
+
+L(b1):	bgt	r18, L(gt1)
+
+	mulq	r24, r19, r7	C U1
+	umulh	r24, r19, r23	C U1
+	lda	r16, -48(r16)
+	br	L(cj1)
+
+L(gt1):	ldq	r0, 8(r17)
+	ldq	r1, 16(r17)
+	ldq	r2, 24(r17)
+	mulq	r24, r19, r7	C U1
+	umulh	r24, r19, r23	C U1
+	ldq	r3, 32(r17)
+	lda	r18, -4(r18)
+	lda	r17, 40(r17)
+	mulq	r0, r19, r4	C U1
+	umulh	r0, r19, r20	C U1
+	lda	r16, -16(r16)
+	bgt	r18, L(gt5)
+
+	mulq	r1, r19, r5	C U1
+	umulh	r1, r19, r21	C U1
+	mulq	r2, r19, r6	C U1
+	br	L(cj5)
+
+L(gt5):	ldq	r0, 0(r17)
+	mulq	r1, r19, r5	C U1
+	umulh	r1, r19, r21	C U1
+	ldq	r1, 8(r17)
+	mulq	r2, r19, r6	C U1
+	br	L(L1)
+
+
+L(b0):	ldq	r1, 8(r17)
+	ldq	r2, 16(r17)
+	ldq	r3, 24(r17)
+	lda	r17, 32(r17)
+	lda	r16, -24(r16)
+	mulq	r24, r19, r4	C U1
+	umulh	r24, r19, r20	C U1
+	bgt	r18, L(gt4)
+
+	mulq	r1, r19, r5	C U1
+	umulh	r1, r19, r21	C U1
+	mulq	r2, r19, r6	C U1
+	umulh	r2, r19, r22	C U1
+	mulq	r3, r19, r7	C U1
+	br	L(cj4)
+
+L(gt4):	ldq	r0, 0(r17)
+	mulq	r1, r19, r5	C U1
+	umulh	r1, r19, r21	C U1
+	ldq	r1, 8(r17)
+	mulq	r2, r19, r6	C U1
+	umulh	r2, r19, r22	C U1
+	ldq	r2, 16(r17)
+	mulq	r3, r19, r7	C U1
+	br	L(L0)
+
+C *** MAIN LOOP START ***
+	ALIGN(16)
+L(top):	mulq	r0, r19, r4	C U1
+	subq	r8, r28, r8
+L(L3):	umulh	r0, r19, r20	C U1
+	cmpult	r8, r5, r28
+	ldq	r0, 0(r17)
+	subq	r8, r5, r8
+	addq	r21, r28, r28
+	stq	r8, 0(r16)
+
+	mulq	r1, r19, r5	C U1
+	subq	r8, r28, r8
+L(L2):	umulh	r1, r19, r21	C U1
+	cmpult	r8, r6, r28
+	ldq	r1, 8(r17)
+	subq	r8, r6, r8
+	addq	r22, r28, r28
+	stq	r8, 8(r16)
+
+	mulq	r2, r19, r6	C U1
+	subq	r8, r28, r8
+L(L1):	umulh	r2, r19, r22	C U1
+	cmpult	r8, r7, r28
+	ldq	r2, 16(r17)
+	subq	r8, r7, r8
+	addq	r23, r28, r28
+	stq	r8, 16(r16)
+
+	mulq	r3, r19, r7	C U1
+	subq	r8, r28, r8
+L(L0):	umulh	r3, r19, r23	C U1
+	cmpult	r8, r4, r28
+	ldq	r3, 24(r17)
+	subq	r8, r4, r8
+	addq	r20, r28, r28
+	stq	r8, 24(r16)
+
+	lda	r18, -4(r18)
+	lda	r17, 32(r17)
+	lda	r16, 32(r16)
+	bgt	r18, L(top)
+C *** MAIN LOOP END ***
+
+	mulq	r0, r19, r4	C U1
+	subq	r8, r28, r8
+L(cj7):	umulh	r0, r19, r20	C U1
+	cmpult	r8, r5, r28
+	subq	r8, r5, r8
+	addq	r21, r28, r28
+	stq	r8, 0(r16)
+	mulq	r1, r19, r5	C U1
+	subq	r8, r28, r8
+L(cj6):	umulh	r1, r19, r21	C U1
+	cmpult	r8, r6, r28
+	subq	r8, r6, r8
+	addq	r22, r28, r28
+	stq	r8, 8(r16)
+	mulq	r2, r19, r6	C U1
+	subq	r8, r28, r8
+L(cj5):	umulh	r2, r19, r22	C U1
+	cmpult	r8, r7, r28
+	subq	r8, r7, r8
+	addq	r23, r28, r28
+	stq	r8, 16(r16)
+	mulq	r3, r19, r7	C U1
+	subq	r8, r28, r8
+L(cj4):	umulh	r3, r19, r23	C U1
+	cmpult	r8, r4, r28
+	subq	r8, r4, r8
+	addq	r20, r28, r28
+	stq	r8, 24(r16)
+	subq	r8, r28, r8
+L(cj3):	cmpult	r8, r5, r28
+	subq	r8, r5, r8
+	addq	r21, r28, r28
+	stq	r8, 32(r16)
+	subq	r8, r28, r8
+L(cj2):	cmpult	r8, r6, r28
+	subq	r8, r6, r8
+	addq	r22, r28, r28
+	stq	r8, 40(r16)
+	subq	r8, r28, r8
+L(cj1):	cmpult	r8, r7, r28
+	subq	r8, r7, r8
+	addq	r23, r28, r28
+	stq	r8, 48(r16)
+	subq	r8, r28, r0
+	ret	r31, (r26), 1
+
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/alpha/cntlz.asm b/third_party/gmp/mpn/alpha/cntlz.asm
new file mode 100644
index 0000000..25af19b
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/cntlz.asm
@@ -0,0 +1,55 @@
+dnl  Alpha auxiliary for longlong.h's count_leading_zeros
+
+dnl  Copyright 1997, 2000, 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+ASM_START()
+EXTERN(__clz_tab)
+PROLOGUE(mpn_count_leading_zeros,gp)
+	cmpbge	r31,  r16, r1
+	LEA(r3,__clz_tab)
+	sra	r1,   1,   r1
+	xor	r1,   127, r1
+	srl	r16,  1,   r16
+	addq	r1,   r3,  r1
+	ldq_u	r0,   0(r1)
+	lda	r2,   64
+	extbl	r0,   r1,   r0
+	s8subl	r0,   8,    r0
+	srl	r16,  r0,   r16
+	addq	r16,  r3,   r16
+	ldq_u	r1,   0(r16)
+	extbl	r1,   r16,  r1
+	subq	r2,   r1,   r2
+	subq	r2,   r0,   r0
+	ret	r31,  (r26),1
+EPILOGUE(mpn_count_leading_zeros)
+ASM_END()
diff --git a/third_party/gmp/mpn/alpha/com.asm b/third_party/gmp/mpn/alpha/com.asm
new file mode 100644
index 0000000..f084ab5
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/com.asm
@@ -0,0 +1,176 @@
+dnl  Alpha mpn_com -- mpn one's complement.
+
+dnl  Copyright 2003 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C      cycles/limb
+C EV4:    4.75
+C EV5:    2.0
+C EV6:    1.5
+
+
+C mp_limb_t mpn_com (mp_ptr dst, mp_srcptr src, mp_size_t size);
+C
+C For ev5 the main loop is 7 cycles plus 1 taken branch bubble, for a total
+C 2.0 c/l.  In general, a pattern like this unrolled to N limbs per loop
+C will be 1.5+2/N c/l.
+C
+C 2 cycles of loop control are unavoidable, for pointer updates and the
+C taken branch bubble, but also since ldq cannot issue two cycles after stq
+C (and with a run of stqs that means neither of two cycles at the end of the
+C loop.
+C
+C The fbeq is forced into the second cycle of the loop using unops, since
+C the first time through it must wait for the cvtqt result.  Once that
+C result is ready (a 1 cycle stall) then both the branch and following loads
+C can issue together.
+C
+C The main loop handles an odd count of limbs, being two limbs loaded before
+C each size test, plus one pipelined around from the previous iteration (or
+C setup in the entry sequence).
+C
+C An even number of limbs is handled by an explicit dst[0]=~src[0] in the
+C entry sequence, and an increment of the pointers.  For an odd size there's
+C no increment and the first store in the loop (r24) is a repeat of dst[0].
+C
+C Note that the load for r24 after the possible pointer increment is done
+C before the explicit store to dst[0], in case src==dst.
+
+
+ASM_START()
+
+FLOAT64(L(dat), 2.0)
+
+	ALIGN(16)
+
+PROLOGUE(mpn_com,gp)
+
+	C r16	dst
+	C r17	src
+	C r18	size
+
+	lda	r30, -16(r30)		C temporary stack space
+	lda	r7, -3(r18)		C size - 3
+
+	ldq	r20, 0(r17)		C src[0]
+	srl	r7, 1, r6		C (size-3)/2
+
+	stq	r6, 8(r30)		C (size-3)/2
+	and	r7, 1, r5		C 1 if size even
+
+	LEA(	r8, L(dat))
+	s8addq	r5, r17, r17		C skip src[0] if even
+
+	ornot	r31, r20, r20		C ~src[0]
+	unop
+
+	ldt	f0, 8(r30)		C (size-3)/2
+	ldq	r24, 0(r17)		C src[0 or 1]
+
+	stq	r20, 0(r16)		C dst[0]
+	s8addq	r5, r16, r19		C skip dst[0] if even
+
+	ldt	f1, 0(r8)		C data 2.0
+	lda	r30, 16(r30)		C restore stack
+	unop
+	cvtqt	f0, f0			C (size-3)/2 as float
+
+	ornot	r31, r24, r24
+	blt	r7, L(done_1)		C if size<=2
+	unop
+	unop
+
+
+	C 16-byte alignment here
+L(top):
+	C r17	src, incrementing
+	C r19	dst, incrementing
+	C r24	dst[i] result, ready to store
+	C f0	(size-3)/2, decrementing
+	C f1	2.0
+
+	ldq	r20, 8(r17)		C src[i+1]
+	ldq	r21, 16(r17)		C src[i+2]
+	unop
+	unop
+
+	fbeq	f0, L(done_2)
+	unop
+	ldq	r22, 24(r17)		C src[i+3]
+	ldq	r23, 32(r17)		C src[i+4]
+
+	stq	r24, 0(r19)		C dst[i]
+	ornot	r31, r20, r20
+	subt	f0, f1, f0		C count -= 2
+	unop
+
+	stq	r20, 8(r19)		C dst[i+1]
+	ornot	r31, r21, r21
+	unop
+	unop
+
+	stq	r21, 16(r19)		C dst[i+2]
+	ornot	r31, r22, r22
+
+	stq	r22, 24(r19)		C dst[i+3]
+	ornot	r31, r23, r24
+
+	lda	r17, 32(r17)		C src += 4
+	lda	r19, 32(r19)		C dst += 4
+	unop
+	fbge	f0, L(top)
+
+
+L(done_1):
+	C r19	&dst[size-1]
+	C r24	result for dst[size-1]
+
+	stq	r24, 0(r19)		C dst[size-1]
+	ret	r31, (r26), 1
+
+
+L(done_2):
+	C r19	&dst[size-3]
+	C r20	src[size-2]
+	C r21	src[size-1]
+	C r24	result for dst[size-3]
+
+	stq	r24, 0(r19)		C dst[size-3]
+	ornot	r31, r20, r20
+
+	stq	r20, 8(r19)		C dst[size-2]
+	ornot	r31, r21, r21
+
+	stq	r21, 16(r19)		C dst[size-1]
+	ret	r31, (r26), 1
+
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/alpha/copyd.asm b/third_party/gmp/mpn/alpha/copyd.asm
new file mode 100644
index 0000000..b41b536
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/copyd.asm
@@ -0,0 +1,88 @@
+dnl  Alpha mpn_copyd -- copy, decrementing.
+
+dnl  Copyright 2002, 2003 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C      cycles/limb
+C EV4:     4
+C EV5:     1.75
+C EV6:     1
+
+C INPUT PARAMETERS
+C rp	r16
+C up	r17
+C n	r18
+
+
+ASM_START()
+PROLOGUE(mpn_copyd)
+	s8addq	r18,r16,r16		C E0
+	s8addq	r18,r17,r17		C E1
+	lda	r18,-8(r18)		C E0
+	blt	r18,$Lend		C E1
+$Loop:	ldq	r0,-8(r17)		C E0
+	ldq	r1,-16(r17)		C E1
+	ldq	r2,-24(r17)		C E0
+	ldq	r3,-32(r17)		C E1
+	ldq	r4,-40(r17)		C E0
+	ldq	r5,-48(r17)		C E1
+	ldq	r6,-56(r17)		C E0
+	ldq	r7,-64(r17)		C E1
+	stq	r0,-8(r16)		C E0
+	lda	r17,-64(r17)		C E1
+	stq	r1,-16(r16)		C E0
+	bis	r31, r31, r31		C E1
+	stq	r2,-24(r16)		C E0
+	lda	r18,-8(r18)		C E1
+	stq	r3,-32(r16)		C E0
+	bis	r31, r31, r31		C E1
+	stq	r4,-40(r16)		C E0
+	bis	r31, r31, r31		C E1
+	stq	r5,-48(r16)		C E0
+	bis	r31, r31, r31		C E1
+	stq	r6,-56(r16)		C E0
+	bis	r31, r31, r31		C E1
+	stq	r7,-64(r16)		C E0
+	lda	r16,-64(r16)		C E1
+	bge	r18,$Loop		C E1
+$Lend:	lda	r18,7(r18)		C E0
+	blt	r18,$Lret		C E1
+	ldq	r0,-8(r17)		C E0
+	beq	r18,$Lend0		C E1
+$Loop0:	stq	r0,-8(r16)		C E0
+	lda	r16,-8(r16)		C E1
+	ldq	r0,-16(r17)		C E0
+	lda	r18,-1(r18)		C E1
+	lda	r17,-8(r17)		C E0
+	bgt	r18,$Loop0		C E1
+$Lend0:	stq	r0,-8(r16)		C E0
+$Lret:	ret	r31,(r26),1		C E1
+EPILOGUE(mpn_copyd)
+ASM_END()
diff --git a/third_party/gmp/mpn/alpha/copyi.asm b/third_party/gmp/mpn/alpha/copyi.asm
new file mode 100644
index 0000000..f7e2ad6
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/copyi.asm
@@ -0,0 +1,86 @@
+dnl  Alpha mpn_copyi -- copy, incrementing.
+
+dnl  Copyright 2002, 2003 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C      cycles/limb
+C EV4:     4
+C EV5:     1.75
+C EV6:     1
+
+C INPUT PARAMETERS
+C rp	r16
+C up	r17
+C n	r18
+
+
+ASM_START()
+PROLOGUE(mpn_copyi)
+	lda	r18,-8(r18)		C E0
+	blt	r18,$Lend		C E1
+$Loop:	ldq	r0,0(r17)		C E0
+	ldq	r1,8(r17)		C E1
+	ldq	r2,16(r17)		C E0
+	ldq	r3,24(r17)		C E1
+	ldq	r4,32(r17)		C E0
+	ldq	r5,40(r17)		C E1
+	ldq	r6,48(r17)		C E0
+	ldq	r7,56(r17)		C E1
+	stq	r0,0(r16)		C E0
+	lda	r17,64(r17)		C E1
+	stq	r1,8(r16)		C E0
+	bis	r31, r31, r31		C E1
+	stq	r2,16(r16)		C E0
+	lda	r18,-8(r18)		C E1
+	stq	r3,24(r16)		C E0
+	bis	r31, r31, r31		C E1
+	stq	r4,32(r16)		C E0
+	bis	r31, r31, r31		C E1
+	stq	r5,40(r16)		C E0
+	bis	r31, r31, r31		C E1
+	stq	r6,48(r16)		C E0
+	bis	r31, r31, r31		C E1
+	stq	r7,56(r16)		C E0
+	lda	r16,64(r16)		C E1
+	bge	r18,$Loop		C E1
+$Lend:	lda	r18,7(r18)		C E0
+	blt	r18,$Lret		C E1
+	ldq	r0,0(r17)		C E0
+	beq	r18,$Lend0		C E1
+$Loop0:	stq	r0,0(r16)		C E0
+	lda	r16,8(r16)		C E1
+	ldq	r0,8(r17)		C E0
+	lda	r18,-1(r18)		C E1
+	lda	r17,8(r17)		C E0
+	bgt	r18,$Loop0		C E1
+$Lend0:	stq	r0,0(r16)		C E0
+$Lret:	ret	r31,(r26),1		C E1
+EPILOGUE(mpn_copyi)
+ASM_END()
diff --git a/third_party/gmp/mpn/alpha/default.m4 b/third_party/gmp/mpn/alpha/default.m4
new file mode 100644
index 0000000..8fe7c4e
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/default.m4
@@ -0,0 +1,127 @@
+divert(-1)
+
+dnl  m4 macros for alpha assembler (everywhere except unicos).
+
+
+dnl  Copyright 2000, 2002-2004, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+dnl  Usage: ASM_START()
+define(`ASM_START',
+m4_assert_numargs(0)
+`	.set noreorder
+	.set noat')
+
+dnl  Usage: X(value)
+define(`X',
+m4_assert_numargs(1)
+`0x$1')
+
+dnl  Usage: FLOAT64(label,value)
+define(`FLOAT64',
+m4_assert_numargs(2)
+`	.align	3
+$1:	.t_floating $2')
+
+
+dnl  Called: PROLOGUE_cpu(GSYM_PREFIX`'foo[,gp|noalign])
+dnl          EPILOGUE_cpu(GSYM_PREFIX`'foo)
+
+define(`PROLOGUE_cpu',
+m4_assert_numargs_range(1,2)
+`ifelse(`$2',gp,,
+`ifelse(`$2',noalign,,
+`ifelse(`$2',,,`m4_error(`Unrecognised PROLOGUE parameter
+')')')')dnl
+	.text
+ifelse(`$2',noalign,,`	ALIGN(16)')
+	.globl	$1
+	.ent	$1
+$1:
+	.frame r30,0,r26,0
+ifelse(`$2',gp,`	ldgp	r29, 0(r27)
+`$'$1..ng:')
+	.prologue ifelse(`$2',gp,1,0)')
+
+define(`EPILOGUE_cpu',
+m4_assert_numargs(1)
+`	.end	$1')
+
+
+dnl  Usage: LDGP(dst,src)
+dnl
+dnl  Emit an "ldgp dst,src", but only if the system uses a GOT.
+
+define(LDGP,
+m4_assert_numargs(2)
+`ldgp	`$1', `$2'')
+
+
+dnl  Usage: EXTERN(variable_name)
+define(`EXTERN',
+m4_assert_numargs(1)
+)
+
+dnl  Usage: r0 ... r31
+dnl         f0 ... f31
+dnl
+dnl  Map register names r0 to $0, and f0 to $f0, etc.
+dnl  This is needed on all systems but Unicos
+dnl
+dnl  defreg() is used to protect the $ in $0 (otherwise it would represent a
+dnl  macro argument).  Double quoting is used to protect the f0 in $f0
+dnl  (otherwise it would be an infinite recursion).
+
+forloop(i,0,31,`defreg(`r'i,$i)')
+forloop(i,0,31,`deflit(`f'i,``$f''i)')
+
+
+dnl  Usage: DATASTART(name,align)  or  DATASTART(name)
+dnl         DATAEND()
+
+define(`DATASTART',
+m4_assert_numargs_range(1,2)
+`	RODATA
+	ALIGN(ifelse($#,1,2,$2))
+$1:')
+define(`DATAEND',
+m4_assert_numargs(0)
+)
+
+dnl  Load a symbolic address into a register
+define(`LEA',
+m4_assert_numargs(2)
+`lda	$1, $2')
+
+dnl  Usage: ASM_END()
+define(`ASM_END',
+m4_assert_numargs(0)
+)
+
+divert
diff --git a/third_party/gmp/mpn/alpha/dive_1.c b/third_party/gmp/mpn/alpha/dive_1.c
new file mode 100644
index 0000000..349d581
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/dive_1.c
@@ -0,0 +1,114 @@
+/* Alpha mpn_divexact_1 -- mpn by limb exact division.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2000-2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/*      cycles/limb
+   EV4:    47.0
+   EV5:    30.0
+   EV6:    15.0
+*/
+
+
+/* The dependent chain is as follows (the same as modexact), and this is
+   what the code runs as.
+
+       ev4    ev5   ev6
+        1      1     1    sub    y = x - h
+       23     13     7    mulq   q = y * inverse
+       23     15     7    umulh  h = high (q * d)
+       --     --    --
+       47     30    15
+
+   The time to load src[i+1] and establish x hides under the umulh latency.  */
+
+void
+mpn_divexact_1 (mp_ptr dst, mp_srcptr src, mp_size_t size, mp_limb_t divisor)
+{
+  mp_limb_t  inverse, lshift_mask, s, sr, s_next, c, h, x, y, q, dummy;
+  unsigned   rshift, lshift;
+
+  ASSERT (size >= 1);
+  ASSERT (divisor != 0);
+  ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, size));
+  ASSERT_MPN (src, size);
+  ASSERT_LIMB (divisor);
+
+  s_next = *src++;   /* src[0] */
+
+  rshift = 0;
+  lshift_mask = 0;
+  if ((divisor & 1) == 0)
+    {
+      count_trailing_zeros (rshift, divisor);
+      lshift_mask = MP_LIMB_T_MAX;
+      divisor >>= rshift;
+    }
+
+  binvert_limb (inverse, divisor);
+  lshift = 64 - rshift;
+
+  c = 0;
+  h = 0;
+  sr = s_next >> rshift;
+
+  size--;
+  if (LIKELY (size != 0))
+    {
+      do
+        {
+          s_next = *src++;      /* src[i+1] */
+          s = sr | ((s_next << lshift) & lshift_mask);
+          x = s - c;
+          c = s < c;
+          sr = s_next >> rshift;
+
+          y = x - h;
+          c += (x < h);
+          q = y * inverse;
+          *dst++ = q;
+          umul_ppmm (h, dummy, q, divisor);
+
+          size--;
+        }
+      while (size != 0);
+    }
+
+  x = sr - c;
+  y = x - h;
+  q = y * inverse;
+  *dst = q;         /* dst[size-1] */
+}
diff --git a/third_party/gmp/mpn/alpha/divrem_2.asm b/third_party/gmp/mpn/alpha/divrem_2.asm
new file mode 100644
index 0000000..046b246
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/divrem_2.asm
@@ -0,0 +1,177 @@
+dnl  Alpha mpn_divrem_2 -- Divide an mpn number by a normalized 2-limb number.
+
+dnl  Copyright 2007, 2008, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		norm	frac
+C ev4
+C ev5		70	70
+C ev6		29	29
+
+C TODO
+C  * Perhaps inline mpn_invert_limb, that would allow us to not save/restore
+C    any registers (thus save ~10 cycles per call).
+C  * Use negated d1 and/or d0 to speed carry propagation.  Might save a cycle
+C    or two.
+C  * Check cluster delays (for ev6).  We very likely could save some cycles.
+C  * Use branch-free code for computing di.
+C  * CAVEAT: We rely on r19 not being clobbered by mpn_invert_limb call.
+
+C INPUT PARAMETERS
+define(`qp',		`r16')
+define(`fn',		`r17')
+define(`up_param',	`r18')
+define(`un_param',	`r19')
+define(`dp',		`r20')
+
+ASM_START()
+PROLOGUE(mpn_divrem_2,gp)
+	lda	r30, -80(r30)
+	stq	r26, 0(r30)
+	stq	r9, 8(r30)
+	stq	r10, 16(r30)
+	stq	r11, 24(r30)
+	stq	r12, 32(r30)
+	stq	r13, 40(r30)
+C	stq	r14, 48(r30)
+	stq	r15, 56(r30)
+	.prologue	1
+	stq	r16, 64(r30)
+	bis	r31, r17, r15
+	s8addq	r19, r18, r13
+	lda	r13, -24(r13)
+	ldq	r12, 8(r20)
+	ldq	r10, 0(r20)
+	ldq	r11, 16(r13)
+	ldq	r9, 8(r13)
+
+	bis	r31, r31, r3		C most_significant_q_limb = 0
+	cmpult	r11, r12, r1
+	bne	r1, L(L8)
+	cmpule	r11, r12, r1
+	cmpult	r9, r10, r2
+	and	r1, r2, r1
+	bne	r1, L(L8)
+	subq	r11, r12, r11
+	subq	r11, r2, r11
+	subq	r9, r10, r9
+	lda	r3, 1(r31)		C most_significant_q_limb = 1
+L(L8):	stq	r3, 72(r30)
+
+	addq	r15, r19, r19
+	lda	r19, -3(r19)
+	blt	r19, L(L10)
+	bis	r31, r12, r16
+	jsr	r26, mpn_invert_limb
+	LDGP(	r29, 0(r26))
+	mulq	r0, r12, r4		C t0 = LO(di * d1)
+	umulh	r0, r10, r2		C s1 = HI(di * d0)
+	addq	r4, r10, r4		C t0 += d0
+	cmpule	r10, r4, r7		C (t0 < d0)
+	addq	r4, r2, r4		C t0 += s1
+	cmpult	r4, r2, r1
+	subq	r1, r7, r7		C t1 (-1, 0, or 1)
+	blt	r7, L(L42)
+L(L22):
+	lda	r0, -1(r0)		C di--
+	cmpult	r4, r12, r1		C cy for: t0 -= d1 (below)
+	subq	r7, r1, r7		C t1 -= cy
+	subq	r4, r12, r4		C t0 -= d1
+	bge	r7, L(L22)
+L(L42):
+	ldq	r16, 64(r30)
+	s8addq	r19, r16, r16
+	ALIGN(16)
+L(loop):
+	mulq	r11, r0, r5		C q0 (early)
+	umulh	r11, r0, r6		C q  (early)
+	addq	r5, r9, r8		C q0 += n1
+	addq	r6, r11, r6		C q  += n2
+	cmpult	r8, r5, r1		C cy for: q0 += n1
+	addq	r6, r1, r6		C q  += cy
+	unop
+	mulq	r12, r6, r1		C LO(d1 * q)
+	umulh	r10, r6, r7		C t1 = HI(d0 * q)
+	subq	r9, r1, r9		C n1 -= LO(d1 * q)
+	mulq	r10, r6, r4		C t0 = LO(d0 * q)
+	unop
+	cmple	r15, r19, r5		C condition and n0...
+	beq	r5, L(L31)
+	ldq	r5, 0(r13)
+	lda	r13, -8(r13)
+L(L31):	subq	r9, r12, r9		C n1 -= d1
+	cmpult	r5, r10, r1		C
+	subq	r9, r1, r9		C
+	subq	r5, r10, r5		C n0 -= d0
+	subq	r9, r7, r9		C n1 -= t0
+	cmpult	r5, r4, r1		C
+	subq	r9, r1, r2		C
+	subq	r5, r4, r5		C n0 -= t1
+	cmpult	r2, r8, r1		C (n1 < q0)
+	addq	r6, r1, r6		C q += cond
+	lda	r1, -1(r1)		C -(n1 >= q0)
+	and	r1, r10, r4		C
+	addq	r5, r4, r9		C n0 += mask & d0
+	and	r1, r12, r1		C
+	cmpult	r9, r5, r11		C cy for: n0 += mask & d0
+	addq	r2, r1, r1		C n1 += mask & d1
+	addq	r1, r11, r11		C n1 += cy
+	cmpult	r11, r12, r1		C
+	beq	r1, L(fix)		C
+L(bck):	stq	r6, 0(r16)
+	lda	r16, -8(r16)
+	lda	r19, -1(r19)
+	bge	r19, L(loop)
+
+L(L10):	stq	r9, 8(r13)
+	stq	r11, 16(r13)
+	ldq	r0, 72(r30)
+	ldq	r26, 0(r30)
+	ldq	r9, 8(r30)
+	ldq	r10, 16(r30)
+	ldq	r11, 24(r30)
+	ldq	r12, 32(r30)
+	ldq	r13, 40(r30)
+C	ldq	r14, 48(r30)
+	ldq	r15, 56(r30)
+	lda	r30, 80(r30)
+	ret	r31, (r26), 1
+
+L(fix):	cmpule	r11, r12, r1
+	cmpult	r9, r10, r2
+	and	r1, r2, r1
+	bne	r1, L(bck)
+	subq	r11, r12, r11
+	subq	r11, r2, r11
+	subq	r9, r10, r9
+	lda	r6, 1(r6)
+	br	L(bck)
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/alpha/ev5/diveby3.asm b/third_party/gmp/mpn/alpha/ev5/diveby3.asm
new file mode 100644
index 0000000..3758188
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/ev5/diveby3.asm
@@ -0,0 +1,332 @@
+dnl  Alpha mpn_divexact_by3c -- mpn division by 3, expecting no remainder.
+
+dnl  Copyright 2004, 2005, 2009 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C      cycles/limb
+C EV4:    22
+C EV5:    11.5
+C EV6:     6.3		Note that mpn_bdiv_dbm1c is faster
+
+C TODO
+C  * Remove the unops, they benefit just ev6, which no longer uses this file.
+C  * Try prefetch for destination, using lds.
+C  * Improve feed-in code, by moving initial mulq earlier; make initial load
+C    to u0/u0 to save some copying.
+C  * Combine u0 and u2, u1 and u3.
+
+C INPUT PARAMETERS
+define(`rp',	`r16')
+define(`up',	`r17')
+define(`n',	`r18')
+define(`cy',	`r19')
+
+ASM_START()
+
+DATASTART(L(LC),8)
+	.quad	0xAAAAAAAAAAAAAAAB
+	.quad	0x5555555555555555
+	.quad	0xAAAAAAAAAAAAAAAA
+DATAEND()
+
+define(`xAAAAAAAAAAAAAAAB',	`r20')
+define(`x5555555555555555',	`r21')
+define(`xAAAAAAAAAAAAAAAA',	`r22')
+define(`u0',	`r0')	define(`u1',	`r1')
+define(`u2',	`r2')	define(`u3',	`r3')
+define(`l0',	`r25')	define(`x',	`r8')
+define(`q0',	`r4')	define(`q1',	`r5')
+define(`p6',	`r6')	define(`p7',	`r7')
+define(`t0',	`r23')	define(`t1',	`r24')
+define(`cymask',`r28')
+
+
+PROLOGUE(mpn_divexact_by3c,gp)
+
+	ldq	r28, 0(up)			C load first limb early
+
+C Put magic constants in registers
+	lda	r0, L(LC)
+	ldq	xAAAAAAAAAAAAAAAB, 0(r0)
+	ldq	x5555555555555555, 8(r0)
+	ldq	xAAAAAAAAAAAAAAAA, 16(r0)
+
+C Compute initial l0 value
+	cmpeq	cy, 1, p6
+	cmpeq	cy, 2, p7
+	negq	p6, p6
+	and	p6, x5555555555555555, l0
+	cmovne	p7, xAAAAAAAAAAAAAAAA, l0
+
+C Feed-in depending on (n mod 4)
+	and	n, 3, r8
+	lda	n, -3(n)
+	cmpeq	r8, 1, r4
+	cmpeq	r8, 2, r5
+	bne	r4, $Lb01
+	bne	r5, $Lb10
+	beq	r8, $Lb00
+
+$Lb11:	ldq	u3, 8(up)
+	lda	up, -24(up)
+	lda	rp, -24(rp)
+	mulq	r28, xAAAAAAAAAAAAAAAB, q0
+	mov	r28, u2
+	br	r31, $L11
+
+$Lb00:	ldq	u2, 8(up)
+	lda	up, -16(up)
+	lda	rp, -16(rp)
+	mulq	r28, xAAAAAAAAAAAAAAAB, q1
+	mov	r28, u1
+	br	r31, $L00
+
+$Lb01:	lda	rp, -8(rp)
+	mulq	r28, xAAAAAAAAAAAAAAAB, q0
+	mov	r28, u0
+	blt	n, $Lcj1
+	ldq	u1, 8(up)
+	lda	up, -8(up)
+	br	r31, $L01
+
+$Lb10:	ldq	u0, 8(up)
+	mulq	r28, xAAAAAAAAAAAAAAAB, q1
+	mov	r28, u3
+	blt	n, $Lend
+
+	ALIGN(16)
+$Ltop:
+C 0
+	cmpult	u3, cy, cy			C L0
+	mulq	u0, xAAAAAAAAAAAAAAAB, q0	C U1
+	ldq	u1, 16(up)			C L1
+	addq	q1, l0, x			C U0
+C 1
+	negq	cy, cymask			C L0
+	unop					C U1
+	unop					C L1
+	cmpult	x5555555555555555, x, p6	C U0
+C 2
+	cmpult	xAAAAAAAAAAAAAAAA, x, p7	C U1
+	unop
+	unop
+	negq	p6, t0				C L0
+C 3
+	negq	p7, t1				C L0
+	and	cymask, x5555555555555555, l0	C U1
+	addq	p6, cy, cy
+	and	t0, x5555555555555555, t0
+C 4
+	and	t1, x5555555555555555, t1
+	addq	p7, cy, cy
+	unop
+	addq	t0, l0, l0
+C 5
+	addq	t1, l0, l0
+	unop
+	stq	x, 0(rp)			C L1
+	unop
+$L01:
+C 0
+	cmpult	u0, cy, cy			C L0
+	mulq	u1, xAAAAAAAAAAAAAAAB, q1	C U1
+	ldq	u2, 24(up)			C L1
+	addq	q0, l0, x			C U0
+C 1
+	negq	cy, cymask			C L0
+	unop					C U1
+	unop					C L1
+	cmpult	x5555555555555555, x, p6	C U0
+C 2
+	cmpult	xAAAAAAAAAAAAAAAA, x, p7	C U1
+	unop
+	unop
+	negq	p6, t0				C L0
+C 3
+	negq	p7, t1				C L0
+	and	cymask, x5555555555555555, l0	C U1
+	addq	p6, cy, cy
+	and	t0, x5555555555555555, t0
+C 4
+	and	t1, x5555555555555555, t1
+	addq	p7, cy, cy
+	unop
+	addq	t0, l0, l0
+C 5
+	addq	t1, l0, l0
+	unop
+	stq	x, 8(rp)			C L1
+	unop
+$L00:
+C 0
+	cmpult	u1, cy, cy			C L0
+	mulq	u2, xAAAAAAAAAAAAAAAB, q0	C U1
+	ldq	u3, 32(up)			C L1
+	addq	q1, l0, x			C U0
+C 1
+	negq	cy, cymask			C L0
+	unop					C U1
+	unop					C L1
+	cmpult	x5555555555555555, x, p6	C U0
+C 2
+	cmpult	xAAAAAAAAAAAAAAAA, x, p7	C U1
+	unop
+	unop
+	negq	p6, t0				C L0
+C 3
+	negq	p7, t1				C L0
+	and	cymask, x5555555555555555, l0	C U1
+	addq	p6, cy, cy
+	and	t0, x5555555555555555, t0
+C 4
+	and	t1, x5555555555555555, t1
+	addq	p7, cy, cy
+	unop
+	addq	t0, l0, l0
+C 5
+	addq	t1, l0, l0
+	unop
+	stq	x, 16(rp)			C L1
+	unop
+$L11:
+C 0
+	cmpult	u2, cy, cy			C L0
+	mulq	u3, xAAAAAAAAAAAAAAAB, q1	C U1
+	ldq	u0, 40(up)			C L1
+	addq	q0, l0, x			C U0
+C 1
+	negq	cy, cymask			C L0
+	unop					C U1
+	unop					C L1
+	cmpult	x5555555555555555, x, p6	C U0
+C 2
+	cmpult	xAAAAAAAAAAAAAAAA, x, p7	C U1
+	lda	n, -4(n)			C L1 bookkeeping
+	unop
+	negq	p6, t0				C L0
+C 3
+	negq	p7, t1				C L0
+	and	cymask, x5555555555555555, l0	C U1
+	addq	p6, cy, cy
+	and	t0, x5555555555555555, t0
+C 4
+	and	t1, x5555555555555555, t1
+	addq	p7, cy, cy
+	unop
+	addq	t0, l0, l0
+C 5
+	addq	t1, l0, l0
+	unop
+	stq	x, 24(rp)			C L1
+	lda	up, 32(up)
+C
+	ldl	r31, 256(up)			C prefetch
+	unop
+	lda	rp, 32(rp)
+	bge	n, $Ltop			C U1
+C *** MAIN LOOP END ***
+$Lend:
+
+	cmpult	u3, cy, cy			C L0
+	mulq	u0, xAAAAAAAAAAAAAAAB, q0	C U1
+	unop
+	addq	q1, l0, x			C U0
+C 1
+	negq	cy, cymask			C L0
+	unop					C U1
+	unop					C L1
+	cmpult	x5555555555555555, x, p6	C U0
+C 2
+	cmpult	xAAAAAAAAAAAAAAAA, x, p7	C U1
+	unop
+	unop
+	negq	p6, t0				C L0
+C 3
+	negq	p7, t1				C L0
+	and	cymask, x5555555555555555, l0	C U1
+	addq	p6, cy, cy
+	and	t0, x5555555555555555, t0
+C 4
+	and	t1, x5555555555555555, t1
+	addq	p7, cy, cy
+	unop
+	addq	t0, l0, l0
+C 5
+	addq	t1, l0, l0
+	unop
+	stq	x, 0(rp)			C L1
+	unop
+$Lcj1:
+	cmpult	u0, cy, cy			C L0
+	addq	q0, l0, x			C U0
+	cmpult	x5555555555555555, x, p6	C U0
+	cmpult	xAAAAAAAAAAAAAAAA, x, p7	C U1
+	addq	p6, cy, cy
+	addq	p7, cy, r0
+	stq	x, 8(rp)			C L1
+
+	ret	r31,(r26),1
+EPILOGUE()
+ASM_END()
+
+C This is useful for playing with various schedules.
+C Expand as: one(0)one(1)one(2)one(3)
+define(`one',`
+C 0
+	cmpult	`$'eval(($1+3)%4), cy, cy		C L0
+	mulq	`$'$1, xAAAAAAAAAAAAAAAB, `$'eval(4+$1%2) C U1
+	ldq	`$'eval(($1+1)%4), eval($1*8+16)(up)	C L1
+	addq	`$'eval(4+($1+1)%2), l0, x		C U0
+C 1
+	negq	cy, cymask				C L0
+	unop						C U1
+	unop						C L1
+	cmpult	x5555555555555555, x, p6		C U0
+C 2
+	cmpult	xAAAAAAAAAAAAAAAA, x, p7		C U1
+	unop
+	unop
+	negq	p6, t0					C L0
+C 3
+	negq	p7, t1					C L0
+	and	cymask, x5555555555555555, l0		C U1
+	addq	p6, cy, cy
+	and	t0, x5555555555555555, t0
+C 4
+	and	t1, x5555555555555555, t1
+	addq	p7, cy, cy
+	unop
+	addq	t0, l0, l0
+C 5
+	addq	t1, l0, l0
+	unop
+	stq	x, eval($1*8)(rp)			C L1
+	unop
+')
diff --git a/third_party/gmp/mpn/alpha/ev5/gmp-mparam.h b/third_party/gmp/mpn/alpha/ev5/gmp-mparam.h
new file mode 100644
index 0000000..1575a28
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/ev5/gmp-mparam.h
@@ -0,0 +1,191 @@
+/* Alpha EV5 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991-2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+/* 600 MHz 21164A */
+/* FFT tuning limit = 5000000 */
+/* Generated by tuneup.c, 2017-02-02, gcc 4.9 */
+
+#define DIVREM_1_NORM_THRESHOLD              0  /* preinv always */
+#define DIVREM_1_UNNORM_THRESHOLD            0  /* always */
+#define MOD_1_1P_METHOD                      2
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD         10
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          7
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        22
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD         0  /* never mpn_mod_1s_2p */
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     20
+#define USE_PREINV_DIVREM_1                  1  /* preinv always */
+#define DIV_QR_1N_PI1_METHOD                 1
+#define DIV_QR_1_NORM_THRESHOLD          MP_SIZE_T_MAX  /* never */
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always */
+#define BMOD_1_TO_MOD_1_THRESHOLD           69
+
+#define DIV_1_VS_MUL_1_PERCENT             181
+
+#define MUL_TOOM22_THRESHOLD                16
+#define MUL_TOOM33_THRESHOLD                50
+#define MUL_TOOM44_THRESHOLD               118
+#define MUL_TOOM6H_THRESHOLD               173
+#define MUL_TOOM8H_THRESHOLD               236
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      49
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD      84
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD      81
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD      53
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD      70
+
+#define SQR_BASECASE_THRESHOLD               0  /* always */
+#define SQR_TOOM2_THRESHOLD                 22
+#define SQR_TOOM3_THRESHOLD                 69
+#define SQR_TOOM4_THRESHOLD                178
+#define SQR_TOOM6_THRESHOLD                189
+#define SQR_TOOM8_THRESHOLD                357
+
+#define MULMID_TOOM42_THRESHOLD             18
+
+#define MULMOD_BNM1_THRESHOLD                9
+#define SQRMOD_BNM1_THRESHOLD               12
+
+#define MUL_FFT_MODF_THRESHOLD             284  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    284, 5}, {     11, 6}, {      6, 5}, {     13, 6}, \
+    {      7, 5}, {     15, 6}, {     13, 7}, {      7, 6}, \
+    {     15, 7}, {      8, 6}, {     17, 7}, {     13, 8}, \
+    {      7, 7}, {     17, 8}, {      9, 7}, {     20, 8}, \
+    {     11, 7}, {     23, 8}, {     13, 9}, {      7, 8}, \
+    {     19, 9}, {     11, 8}, {     25,10}, {      7, 9}, \
+    {     15, 8}, {     33, 9}, {     19, 8}, {     39, 9}, \
+    {     23, 8}, {     47,10}, {     15, 9}, {     39,10}, \
+    {     23, 9}, {     47,11}, {     15,10}, {     31, 9}, \
+    {     67,10}, {     39, 9}, {     79,10}, {     47, 9}, \
+    {     95,10}, {     55,11}, {     31,10}, {     63, 8}, \
+    {    255, 7}, {    511,10}, {     71, 9}, {    143, 8}, \
+    {    287, 7}, {    575, 9}, {    159, 8}, {    319,11}, \
+    {     47,12}, {     31,11}, {     63, 9}, {    255, 8}, \
+    {    511,10}, {    143, 9}, {    287,11}, {     79,10}, \
+    {    159, 9}, {    319,10}, {    175, 9}, {    351, 8}, \
+    {    703,10}, {    191, 9}, {    383,10}, {    207, 9}, \
+    {    415,12}, {     63,10}, {    255,11}, {    143,10}, \
+    {    287, 9}, {    575,11}, {    159,10}, {    319, 9}, \
+    {    639,11}, {    175,12}, {     95,11}, {    191,10}, \
+    {    383,11}, {    207,10}, {    415,11}, {    223,13}, \
+    {     63,11}, {    287,10}, {    575,12}, {    159,11}, \
+    {    319,10}, {    639,11}, {    351,12}, {    191,11}, \
+    {    415,12}, {    223,11}, {    447,10}, {    895,11}, \
+    {    479,12}, {    287,11}, {    575,12}, {    351,13}, \
+    {    191,12}, {    479,13}, {    255,12}, {    575,13}, \
+    {    319,12}, {    703,13}, {    383,12}, {    831,13}, \
+    {    447,14}, {    255,13}, {   8192,14}, {  16384,15}, \
+    {  32768,16}, {  65536,17}, { 131072,18}, { 262144,19}, \
+    { 524288,20}, {1048576,21}, {2097152,22}, {4194304,23}, \
+    {8388608,24} }
+#define MUL_FFT_TABLE3_SIZE 121
+#define MUL_FFT_THRESHOLD                 4224
+
+#define SQR_FFT_MODF_THRESHOLD             240  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    240, 5}, {     13, 6}, {      7, 5}, {     15, 6}, \
+    {     14, 5}, {     29, 7}, {      9, 6}, {     19, 7}, \
+    {     13, 6}, {     27, 8}, {      7, 7}, {     21, 8}, \
+    {     11, 7}, {     29, 8}, {     19, 9}, {     11, 8}, \
+    {     27,10}, {      7, 9}, {     15, 8}, {     33, 9}, \
+    {     19, 8}, {     39, 9}, {     23, 8}, {     47,10}, \
+    {     15, 9}, {     39,10}, {     23, 9}, {     47,11}, \
+    {     15,10}, {     31, 9}, {     67,10}, {     39, 9}, \
+    {     79,10}, {     47,11}, {     31,10}, {     63, 9}, \
+    {    127, 8}, {    255,10}, {     71, 9}, {    143, 8}, \
+    {    287,10}, {     79,11}, {     47,12}, {     31,11}, \
+    {     63,10}, {    127, 9}, {    255,10}, {    143, 9}, \
+    {    287,11}, {     79,10}, {    159, 9}, {    319,10}, \
+    {    175,11}, {     95,10}, {    191, 9}, {    383,10}, \
+    {    207, 9}, {    415,11}, {    111,10}, {    223,12}, \
+    {     63,11}, {    175,12}, {     95,11}, {    207,13}, \
+    {     63,12}, {    127,11}, {    287,12}, {    159,11}, \
+    {    351,12}, {    191,11}, {    415,12}, {    223,11}, \
+    {    447,13}, {    127,12}, {    351,13}, {    191,12}, \
+    {    383,11}, {    767,12}, {    415,11}, {    831,12}, \
+    {    447,14}, {    127,13}, {    255,12}, {    511,11}, \
+    {   1087,12}, {    575,13}, {    319,12}, {    703,13}, \
+    {    383,12}, {    831,13}, {    447,14}, {    255,13}, \
+    {    511,12}, {   1023,13}, {   8192,14}, {  16384,15}, \
+    {  32768,16}, {  65536,17}, { 131072,18}, { 262144,19}, \
+    { 524288,20}, {1048576,21}, {2097152,22}, {4194304,23}, \
+    {8388608,24} }
+#define SQR_FFT_TABLE3_SIZE 105
+#define SQR_FFT_THRESHOLD                 3968
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  50
+#define MULLO_MUL_N_THRESHOLD             5558
+#define SQRLO_BASECASE_THRESHOLD             0  /* always */
+#define SQRLO_DC_THRESHOLD                  78
+#define SQRLO_SQR_THRESHOLD               3597
+
+#define DC_DIV_QR_THRESHOLD                 47
+#define DC_DIVAPPR_Q_THRESHOLD             167
+#define DC_BDIV_QR_THRESHOLD                47
+#define DC_BDIV_Q_THRESHOLD                110
+
+#define INV_MULMOD_BNM1_THRESHOLD           30
+#define INV_NEWTON_THRESHOLD               181
+#define INV_APPR_THRESHOLD                 173
+
+#define BINV_NEWTON_THRESHOLD              182
+#define REDC_1_TO_REDC_N_THRESHOLD          47
+
+#define MU_DIV_QR_THRESHOLD                979
+#define MU_DIVAPPR_Q_THRESHOLD            1142
+#define MUPI_DIV_QR_THRESHOLD               90
+#define MU_BDIV_QR_THRESHOLD               748
+#define MU_BDIV_Q_THRESHOLD                979
+
+#define POWM_SEC_TABLE  1,16,90,386,2177
+
+#define GET_STR_DC_THRESHOLD                14
+#define GET_STR_PRECOMPUTE_THRESHOLD        26
+#define SET_STR_DC_THRESHOLD               363
+#define SET_STR_PRECOMPUTE_THRESHOLD      1201
+
+#define FAC_DSC_THRESHOLD                  342
+#define FAC_ODD_THRESHOLD                    0  /* always */
+
+#define MATRIX22_STRASSEN_THRESHOLD         13
+#define HGCD_THRESHOLD                     105
+#define HGCD_APPR_THRESHOLD                108
+#define HGCD_REDUCE_THRESHOLD             1679
+#define GCD_DC_THRESHOLD                   238
+#define GCDEXT_DC_THRESHOLD                199
+#define JACOBI_BASE_METHOD                   2
diff --git a/third_party/gmp/mpn/alpha/ev6/add_n.asm b/third_party/gmp/mpn/alpha/ev6/add_n.asm
new file mode 100644
index 0000000..9261f31
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/ev6/add_n.asm
@@ -0,0 +1,283 @@
+dnl  Alpha ev6 mpn_add_n -- Add two limb vectors of the same length > 0 and
+dnl  store sum in a third limb vector.
+
+dnl  Copyright 2000, 2003, 2005 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C      cycles/limb
+C EV4:     ?
+C EV5:     5.4
+C EV6:     2.125
+
+C  INPUT PARAMETERS
+C  rp	r16
+C  up	r17
+C  vp	r18
+C  n	r19
+C  cy	r20   (for mpn_add_nc)
+
+C TODO
+C   Finish cleaning up cy registers r22, r23 (make them use cy0/cy1)
+C   Use multi-pronged feed-in.
+C   Perform additional micro-tuning
+
+C  This code was written in cooperation with ev6 pipeline expert Steve Root.
+
+C  Pair loads and stores where possible
+C  Store pairs oct-aligned where possible (didn't need it here)
+C  Stores are delayed every third cycle
+C  Loads and stores are delayed by fills
+C  U stays still, put code there where possible (note alternation of U1 and U0)
+C  L moves because of loads and stores
+C  Note dampers in L to limit damage
+
+C  This odd-looking optimization expects that were having random bits in our
+C  data, so that a pure zero result is unlikely. so we penalize the unlikely
+C  case to help the common case.
+
+define(`u0', `r0')  define(`u1', `r3')
+define(`v0', `r1')  define(`v1', `r4')
+
+define(`cy0', `r20')  define(`cy1', `r21')
+
+MULFUNC_PROLOGUE(mpn_add_n mpn_add_nc)
+
+ASM_START()
+PROLOGUE(mpn_add_nc)
+	br	r31,	$entry
+EPILOGUE()
+PROLOGUE(mpn_add_n)
+	bis	r31,	r31,	cy0	C clear carry in
+$entry:	cmpult	r19,	5,	r22	C L1 move counter
+	ldq	u1,	0(r17)		C L0 get next ones
+	ldq	v1,	0(r18)		C L1
+	bne	r22,	$Lsmall
+
+	ldq	u0,	8(r17)		C L0 get next ones
+	ldq	v0,	8(r18)		C L1
+	addq	u1,	v1,	r5	C U0 add two data
+
+	cmpult	r5,	v1,	r23	C U0 did it carry
+	ldq	u1,	16(r17)		C L0 get next ones
+	ldq	v1,	16(r18)		C L1
+
+	addq	u0,	v0,	r8	C U1 add two data
+	addq	r5,	cy0,	r5	C U0 carry in
+
+	cmpult	r8,	v0,	r22	C U1 did it carry
+	beq	r5,	$fix5f		C U0 fix exact zero
+$ret5f:	ldq	u0,	24(r17)		C L0 get next ones
+	ldq	v0,	24(r18)		C L1
+
+	addq	r8,	r23,	r8	C U1 carry from last
+	addq	u1,	v1,	r7	C U0 add two data
+
+	beq	r8,	$fix6f		C U1 fix exact zero
+$ret6f:	cmpult	r7,	v1,	r23	C U0 did it carry
+	ldq	u1,	32(r17)		C L0 get next ones
+	ldq	v1,	32(r18)		C L1
+
+	lda	r17,	40(r17)		C L0 move pointer
+	lda	r18,	40(r18)		C L1 move pointer
+
+	lda	r16,	-8(r16)
+	lda	r19,	-13(r19)	C L1 move counter
+	blt	r19,	$Lend		C U1 loop control
+
+
+C Main loop.  8-way unrolled.
+	ALIGN(16)
+$Loop:	addq	u0,	v0,	r2	C U1 add two data
+	addq	r7,	r22,	r7	C U0 add in carry
+	stq	r5,	8(r16)		C L0 put an answer
+	stq	r8,	16(r16)		C L1 pair
+
+	cmpult	r2,	v0,	cy1	C U1 did it carry
+	beq	r7,	$fix7		C U0 fix exact 0
+$ret7:	ldq	u0,	0(r17)		C L0 get next ones
+	ldq	v0,	0(r18)		C L1
+
+	bis	r31,	r31,	r31	C L  damp out
+	addq	r2,	r23,	r2	C U1 carry from last
+	bis	r31,	r31,	r31	C L  moves in L !
+	addq	u1,	v1,	r5	C U0 add two data
+
+	beq	r2,	$fix0		C U1 fix exact zero
+$ret0:	cmpult	r5,	v1,	cy0	C U0 did it carry
+	ldq	u1,	8(r17)		C L0 get next ones
+	ldq	v1,	8(r18)		C L1
+
+	addq	u0,	v0,	r8	C U1 add two data
+	addq	r5,	cy1,	r5	C U0 carry from last
+	stq	r7,	24(r16)		C L0 store pair
+	stq	r2,	32(r16)		C L1
+
+	cmpult	r8,	v0,	r22	C U1 did it carry
+	beq	r5,	$fix1		C U0 fix exact zero
+$ret1:	ldq	u0,	16(r17)		C L0 get next ones
+	ldq	v0,	16(r18)		C L1
+
+	lda	r16,	64(r16)		C L0 move pointer
+	addq	r8,	cy0,	r8	C U1 carry from last
+	lda	r19,	-8(r19)		C L1 move counter
+	addq	u1,	v1,	r7	C U0 add two data
+
+	beq	r8,	$fix2		C U1 fix exact zero
+$ret2:	cmpult	r7,	v1,	r23	C U0 did it carry
+	ldq	u1,	24(r17)		C L0 get next ones
+	ldq	v1,	24(r18)		C L1
+
+	addq	u0,	v0,	r2	C U1 add two data
+	addq	r7,	r22,	r7	C U0 add in carry
+	stq	r5,	-24(r16)	C L0 put an answer
+	stq	r8,	-16(r16)	C L1 pair
+
+	cmpult	r2,	v0,	cy1	C U1 did it carry
+	beq	r7,	$fix3		C U0 fix exact 0
+$ret3:	ldq	u0,	32(r17)		C L0 get next ones
+	ldq	v0,	32(r18)		C L1
+
+	bis	r31,	r31,	r31	C L  damp out
+	addq	r2,	r23,	r2	C U1 carry from last
+	bis	r31,	r31,	r31	C L  moves in L !
+	addq	u1,	v1,	r5	C U0 add two data
+
+	beq	r2,	$fix4		C U1 fix exact zero
+$ret4:	cmpult	r5,	v1,	cy0	C U0 did it carry
+	ldq	u1,	40(r17)		C L0 get next ones
+	ldq	v1,	40(r18)		C L1
+
+	addq	u0,	v0,	r8	C U1 add two data
+	addq	r5,	cy1,	r5	C U0 carry from last
+	stq	r7,	-8(r16)		C L0 store pair
+	stq	r2,	0(r16)		C L1
+
+	cmpult	r8,	v0,	r22	C U1 did it carry
+	beq	r5,	$fix5		C U0 fix exact zero
+$ret5:	ldq	u0,	48(r17)		C L0 get next ones
+	ldq	v0,	48(r18)		C L1
+
+	ldl	r31, 256(r17)		C L0 prefetch
+	addq	r8,	cy0,	r8	C U1 carry from last
+	ldl	r31, 256(r18)		C L1 prefetch
+	addq	u1,	v1,	r7	C U0 add two data
+
+	beq	r8,	$fix6		C U1 fix exact zero
+$ret6:	cmpult	r7,	v1,	r23	C U0 did it carry
+	ldq	u1,	56(r17)		C L0 get next ones
+	ldq	v1,	56(r18)		C L1
+
+	lda	r17,	64(r17)		C L0 move pointer
+	bis	r31,	r31,	r31	C U
+	lda	r18,	64(r18)		C L1 move pointer
+	bge	r19,	$Loop		C U1 loop control
+C ==== main loop end
+
+$Lend:	addq	u0,	v0,	r2	C U1 add two data
+	addq	r7,	r22,	r7	C U0 add in carry
+	stq	r5,	8(r16)		C L0 put an answer
+	stq	r8,	16(r16)		C L1 pair
+	cmpult	r2,	v0,	cy1	C U1 did it carry
+	beq	r7,	$fix7c		C U0 fix exact 0
+$ret7c:	addq	r2,	r23,	r2	C U1 carry from last
+	addq	u1,	v1,	r5	C U0 add two data
+	beq	r2,	$fix0c		C U1 fix exact zero
+$ret0c:	cmpult	r5,	v1,	cy0	C U0 did it carry
+	addq	r5,	cy1,	r5	C U0 carry from last
+	stq	r7,	24(r16)		C L0 store pair
+	stq	r2,	32(r16)		C L1
+	beq	r5,	$fix1c		C U0 fix exact zero
+$ret1c:	stq	r5,	40(r16)		C L0 put an answer
+	lda	r16,	48(r16)		C L0 move pointer
+
+	lda	r19,	8(r19)
+	beq	r19,	$Lret
+
+	ldq	u1,	0(r17)
+	ldq	v1,	0(r18)
+$Lsmall:
+	lda	r19,	-1(r19)
+	beq	r19,	$Lend0
+
+	ALIGN(8)
+$Loop0:	addq	u1,	v1,	r2	C main add
+	cmpult	r2,	v1,	r8	C compute cy from last add
+	ldq	u1,	8(r17)
+	ldq	v1,	8(r18)
+	addq	r2,	cy0,	r5	C carry add
+	lda	r17,	8(r17)
+	lda	r18,	8(r18)
+	stq	r5,	0(r16)
+	cmpult	r5,	r2,	cy0	C compute cy from last add
+	lda	r19,	-1(r19)		C decr loop cnt
+	bis	r8,	cy0,	cy0	C combine cy from the two adds
+	lda	r16,	8(r16)
+	bne	r19,	$Loop0
+$Lend0:	addq	u1,	v1,	r2	C main add
+	addq	r2,	cy0,	r5	C carry add
+	cmpult	r2,	v1,	r8	C compute cy from last add
+	cmpult	r5,	r2,	cy0	C compute cy from last add
+	stq	r5,	0(r16)
+	bis	r8,	cy0,	r0	C combine cy from the two adds
+	ret	r31,(r26),1
+
+	ALIGN(8)
+$Lret:	lda	r0,	0(cy0)		C copy carry into return register
+	ret	r31,(r26),1
+
+$fix5f:	bis	r23,	cy0,	r23	C bring forward carry
+	br	r31,	$ret5f
+$fix6f:	bis	r22,	r23,	r22	C bring forward carry
+	br	r31,	$ret6f
+$fix0:	bis	cy1,	r23,	cy1	C bring forward carry
+	br	r31,	$ret0
+$fix1:	bis	cy0,	cy1,	cy0	C bring forward carry
+	br	r31,	$ret1
+$fix2:	bis	r22,	cy0,	r22	C bring forward carry
+	br	r31,	$ret2
+$fix3:	bis	r23,	r22,	r23	C bring forward carry
+	br	r31,	$ret3
+$fix4:	bis	cy1,	r23,	cy1	C bring forward carry
+	br	r31,	$ret4
+$fix5:	bis	cy1,	cy0,	cy0	C bring forward carry
+	br	r31,	$ret5
+$fix6:	bis	r22,	cy0,	r22	C bring forward carry
+	br	r31,	$ret6
+$fix7:	bis	r23,	r22,	r23	C bring forward carry
+	br	r31,	$ret7
+$fix0c:	bis	cy1,	r23,	cy1	C bring forward carry
+	br	r31,	$ret0c
+$fix1c:	bis	cy0,	cy1,	cy0	C bring forward carry
+	br	r31,	$ret1c
+$fix7c:	bis	r23,	r22,	r23	C bring forward carry
+	br	r31,	$ret7c
+
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/alpha/ev6/aorslsh1_n.asm b/third_party/gmp/mpn/alpha/ev6/aorslsh1_n.asm
new file mode 100644
index 0000000..cb966ce
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/ev6/aorslsh1_n.asm
@@ -0,0 +1,172 @@
+dnl  Alpha mpn_addlsh1_n/mpn_sublsh1_n -- rp[] = up[] +- (vp[] << 1).
+
+dnl  Copyright 2003, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C      cycles/limb
+C EV4:     ?
+C EV5:     7
+C EV6:     4
+
+C TODO
+C  * Tune to reach 3.75 c/l on ev6.
+
+define(`rp',`r16')
+define(`up',`r17')
+define(`vp',`r18')
+define(`n', `r19')
+
+define(`u0', `r8')
+define(`u1', `r1')
+define(`v0', `r4')
+define(`v1', `r5')
+
+define(`cy0', `r0')
+define(`cy1', `r20')
+define(`cy', `r22')
+define(`rr', `r24')
+define(`ps', `r25')
+define(`sl', `r28')
+
+ifdef(`OPERATION_addlsh1_n',`
+  define(ADDSUB,       addq)
+  define(CARRY,       `cmpult $1,$2,$3')
+  define(func, mpn_addlsh1_n)
+')
+ifdef(`OPERATION_sublsh1_n',`
+  define(ADDSUB,       subq)
+  define(CARRY,       `cmpult $2,$1,$3')
+  define(func, mpn_sublsh1_n)
+')
+
+MULFUNC_PROLOGUE(mpn_addlsh1_n mpn_sublsh1_n)
+
+ASM_START()
+PROLOGUE(func)
+	and	n, 2, cy0
+	blbs	n, L(bx1)
+L(bx0):	ldq	v1, 0(vp)
+	ldq	u1, 0(up)
+	lda	r2, 0(r31)
+	bne	cy0, L(b10)
+
+L(b00):	lda	vp, 48(vp)
+	lda	up, -16(up)
+	lda	rp, -8(rp)
+	lda	cy0, 0(r31)
+	br	r31, L(lo0)
+
+L(b10):	lda	vp, 32(vp)
+	lda	rp, 8(rp)
+	lda	cy0, 0(r31)
+	br	r31, L(lo2)
+
+L(bx1):	ldq	v0, 0(vp)
+	ldq	u0, 0(up)
+	lda	r3, 0(r31)
+	beq	cy0, L(b01)
+
+L(b11):	lda	vp, 40(vp)
+	lda	up, -24(up)
+	lda	rp, 16(rp)
+	lda	cy1, 0(r31)
+	br	r31, L(lo3)
+
+L(b01):	lda	n, -4(n)
+	lda	cy1, 0(r31)
+	ble	n, L(end)
+	lda	vp, 24(vp)
+	lda	up, -8(up)
+
+	ALIGN(16)
+L(top):	addq	v0, v0, r6
+	ldq	v1, -16(vp)
+	addq	r6, r3, sl	C combined vlimb
+	ldq	u1, 16(up)
+	ADDSUB	u0, sl, ps	C ulimb + (vlimb << 1)
+	cmplt	v0, r31, r2	C high v bits
+	ADDSUB	ps, cy1, rr	C consume carry from previous operation
+	CARRY(	ps, u0, cy0)	C carry out #2
+	stq	rr, 0(rp)
+	CARRY(	rr, ps, cy)	C carry out #3
+	lda	vp, 32(vp)	C bookkeeping
+	addq	cy, cy0, cy0	C final carry out
+L(lo0):	addq	v1, v1, r7
+	ldq	v0, -40(vp)
+	addq	r7, r2, sl
+	ldq	u0, 24(up)
+	ADDSUB	u1, sl, ps
+	cmplt	v1, r31, r3
+	ADDSUB	ps, cy0, rr
+	CARRY(	ps, u1, cy1)
+	stq	rr, 8(rp)
+	CARRY(	rr, ps, cy)
+	lda	rp, 32(rp)	C bookkeeping
+	addq	cy, cy1, cy1
+L(lo3):	addq	v0, v0, r6
+	ldq	v1, -32(vp)
+	addq	r6, r3, sl
+	ldq	u1, 32(up)
+	ADDSUB	u0, sl, ps
+	cmplt	v0, r31, r2
+	ADDSUB	ps, cy1, rr
+	CARRY(	ps, u0, cy0)
+	stq	rr, -16(rp)
+	CARRY(	rr, ps, cy)
+	lda	up, 32(up)	C bookkeeping
+	addq	cy, cy0, cy0
+L(lo2):	addq	v1, v1, r7
+	ldq	v0, -24(vp)
+	addq	r7, r2, sl
+	ldq	u0, 8(up)
+	ADDSUB	u1, sl, ps
+	cmplt	v1, r31, r3
+	ADDSUB	ps, cy0, rr
+	CARRY(	ps, u1, cy1)
+	stq	rr, -8(rp)
+	CARRY(	rr, ps, cy)
+	lda	n, -4(n)	C bookkeeping
+	addq	cy, cy1, cy1
+	bgt	n, L(top)
+
+L(end):	addq	v0, v0, r6
+	addq	r6, r3, sl
+	ADDSUB	u0, sl, ps
+	cmplt	v0, r31, r2
+	ADDSUB	ps, cy1, rr
+	CARRY(	ps, u0, cy0)
+	stq	rr, 0(rp)
+	CARRY(	rr, ps, cy)
+	addq	cy, cy0, cy0
+	addq	cy0, r2, r0
+
+	ret	r31,(r26),1
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/alpha/ev6/aorsmul_1.asm b/third_party/gmp/mpn/alpha/ev6/aorsmul_1.asm
new file mode 100644
index 0000000..0e68e6e
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/ev6/aorsmul_1.asm
@@ -0,0 +1,398 @@
+dnl  Alpha ev6 mpn_addmul_1 and mpn_submul_1.
+
+dnl  Copyright 2000, 2003-2005, 2008 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C      cycles/limb
+C EV4:    42
+C EV5:    18
+C EV6:     3.5
+
+C  INPUT PARAMETERS
+define(`rp',	`r16')
+define(`up',	`r17')
+define(`n',	`r18')
+define(`v0',	`r19')
+
+dnl  This code was written in cooperation with ev6 pipeline expert Steve Root.
+
+dnl  The stores can issue a cycle late so we have paired no-op's to 'catch'
+dnl  them, so that further disturbance to the schedule is damped.
+
+dnl  We couldn't pair the loads, because the entangled schedule of the carry's
+dnl  has to happen on one side {0} of the machine.
+
+dnl  This is a great schedule for the d_cache, a poor schedule for the b_cache.
+dnl  The lockup on U0 means that any stall can't be recovered from.  Consider a
+dnl  ldq in L1, say that load gets stalled because it collides with a fill from
+dnl  the b_cache.  On the next cycle, this load gets priority.  If first looks
+dnl  at L0, and goes there.  The instruction we intended for L0 gets to look at
+dnl  L1, which is NOT where we want it.  It either stalls 1, because it can't
+dnl  go in L0, or goes there, and causes a further instruction to stall.
+
+dnl  So for b_cache, we're likely going to want to put one or more cycles back
+dnl  into the code! And, of course, put in lds prefetch for the rp[] operand.
+dnl  At a place where we have an mt followed by a bookkeeping, put the
+dnl  bookkeeping in upper, and the prefetch into lower.
+
+dnl  Note, the ldq's and stq's are at the end of the quadpacks.  Note, we'd
+dnl  like not to have an ldq or an stq to preceded a conditional branch in a
+dnl  quadpack.  The conditional branch moves the retire pointer one cycle
+dnl  later.
+
+ifdef(`OPERATION_addmul_1',`
+    define(`ADDSUB',	`addq')
+    define(`CMPCY',	`cmpult	$2,$1')
+    define(`func',	`mpn_addmul_1')
+')
+ifdef(`OPERATION_submul_1',`
+    define(`ADDSUB',	`subq')
+    define(`CMPCY',	`cmpult	$1,$2')
+    define(`func',	`mpn_submul_1')
+')
+
+MULFUNC_PROLOGUE(mpn_addmul_1 mpn_submul_1)
+
+ASM_START()
+PROLOGUE(func)
+	ldq	r3,	0(up)		C
+	and	r18,	7,	r20	C
+	lda	r18,	-9(r18)		C
+	cmpeq	r20,	1,	r21	C
+	beq	r21,	$L1		C
+
+$1mod8:	ldq	r5,	0(rp)		C
+	mulq	v0,	r3,	r7	C
+	umulh	v0,	r3,	r8	C
+	ADDSUB	r5,	r7,	r23	C
+	CMPCY(	r5,	r23),	r20	C
+	addq	r8,	r20,	r0	C
+	stq	r23,	0(rp)		C
+	bge	r18,	$ent1		C
+	ret	r31,	(r26),	1	C
+
+$L1:	lda	r8,	0(r31)		C zero carry reg
+	lda	r24,	0(r31)		C zero carry reg
+	cmpeq	r20,	2,	r21	C
+	bne	r21,	$2mod8		C
+	cmpeq	r20,	3,	r21	C
+	bne	r21,	$3mod8		C
+	cmpeq	r20,	4,	r21	C
+	bne	r21,	$4mod8		C
+	cmpeq	r20,	5,	r21	C
+	bne	r21,	$5mod8		C
+	cmpeq	r20,	6,	r21	C
+	bne	r21,	$6mod8		C
+	cmpeq	r20,	7,	r21	C
+	beq	r21,	$0mod8		C
+
+$7mod8:	ldq	r5,	0(rp)		C
+	lda	up,	8(up)		C
+	mulq	v0,	r3,	r7	C
+	umulh	v0,	r3,	r24	C
+	ADDSUB	r5,	r7,	r23	C
+	CMPCY(	r5,	r23),	r20	C
+	addq	r24,	r20,	r24	C
+	stq	r23,	0(rp)		C
+	lda	rp,	8(rp)		C
+	ldq	r3,	0(up)		C
+$6mod8:	ldq	r1,	8(up)		C
+	mulq	v0,	r3,	r25	C
+	umulh	v0,	r3,	r3	C
+	mulq	v0,	r1,	r28	C
+	ldq	r0,	16(up)		C
+	ldq	r4,	0(rp)		C
+	umulh	v0,	r1,	r8	C
+	ldq	r1,	24(up)		C
+	lda	up,	48(up)		C L1 bookkeeping
+	mulq	v0,	r0,	r2	C
+	ldq	r5,	8(rp)		C
+	lda	rp,	-32(rp)		C L1 bookkeeping
+	umulh	v0,	r0,	r6	C
+	ADDSUB	r4,	r25,	r25	C lo + acc
+	mulq	v0,	r1,	r7	C
+	br	r31,	$ent6		C
+
+$ent1:	lda	up,	8(up)		C
+	lda	rp,	8(rp)		C
+	lda	r8,	0(r0)		C
+	ldq	r3,	0(up)		C
+$0mod8:	ldq	r1,	8(up)		C
+	mulq	v0,	r3,	r2	C
+	umulh	v0,	r3,	r6	C
+	mulq	v0,	r1,	r7	C
+	ldq	r0,	16(up)		C
+	ldq	r4,	0(rp)		C
+	umulh	v0,	r1,	r24	C
+	ldq	r1,	24(up)		C
+	mulq	v0,	r0,	r25	C
+	ldq	r5,	8(rp)		C
+	umulh	v0,	r0,	r3	C
+	ADDSUB	r4,	r2,	r2	C lo + acc
+	mulq	v0,	r1,	r28	C
+	lda	rp,	-16(rp)		C
+	br	r31,	$ent0		C
+
+$3mod8:	ldq	r5,	0(rp)		C
+	lda	up,	8(up)		C
+	mulq	v0,	r3,	r7	C
+	umulh	v0,	r3,	r8	C
+	ADDSUB	r5,	r7,	r23	C
+	CMPCY(	r5,	r23),	r20	C
+	addq	r8,	r20,	r24	C
+	stq	r23,	0(rp)		C
+	lda	rp,	8(rp)		C
+	ldq	r3,	0(up)		C
+$2mod8:	ldq	r1,	8(up)		C
+	mulq	v0,	r3,	r25	C
+	umulh	v0,	r3,	r3	C
+	mulq	v0,	r1,	r28	C
+	ble	r18,	$n23		C
+	ldq	r0,	16(up)		C
+	ldq	r4,	0(rp)		C
+	umulh	v0,	r1,	r8	C
+	ldq	r1,	24(up)		C
+	lda	up,	16(up)		C L1 bookkeeping
+	mulq	v0,	r0,	r2	C
+	ldq	r5,	8(rp)		C
+	lda	rp,	0(rp)		C L1 bookkeeping
+	umulh	v0,	r0,	r6	C
+	ADDSUB	r4,	r25,	r25	C lo + acc
+	mulq	v0,	r1,	r7	C
+	br	r31,	$ent2		C
+
+$5mod8:	ldq	r5,	0(rp)		C
+	lda	up,	8(up)		C
+	mulq	v0,	r3,	r7	C
+	umulh	v0,	r3,	r24	C
+	ADDSUB	r5,	r7,	r23	C
+	CMPCY(	r5,	r23),	r20	C
+	addq	r24,	r20,	r8	C
+	stq	r23,	0(rp)		C
+	lda	rp,	8(rp)		C
+	ldq	r3,	0(up)		C
+$4mod8:	ldq	r1,	8(up)		C
+	mulq	v0,	r3,	r2	C
+	umulh	v0,	r3,	r6	C
+	mulq	v0,	r1,	r7	C
+	ldq	r0,	16(up)		C
+	ldq	r4,	0(rp)		C
+	umulh	v0,	r1,	r24	C
+	ldq	r1,	24(up)		C
+	lda	up,	32(up)		C L1 bookkeeping
+	mulq	v0,	r0,	r25	C
+	ldq	r5,	8(rp)		C
+	lda	rp,	16(rp)		C L1 bookkeeping
+	umulh	v0,	r0,	r3	C
+	ADDSUB	r4,	r2,	r2	C lo + acc
+	mulq	v0,	r1,	r28	C
+	CMPCY(	r4,	r2),	r20	C L0 lo add => carry
+	ADDSUB	r2,	r8,	r22	C U0 hi add => answer
+	ble	r18,	$Lend		C
+	ALIGN(16)
+$Loop:
+	bis	r31,	r31,	r31	C U1 mt
+	CMPCY(	r2,	r22),	r21	C L0 hi add => carry
+	addq	r6,	r20,	r6	C U0 hi mul + carry
+	ldq	r0,	0(up)		C
+
+	bis	r31,	r31,	r31	C U1 mt
+	ADDSUB	r5,	r7,	r7	C L0 lo + acc
+	addq	r6,	r21,	r6	C U0 hi mul + carry
+	ldq	r4,	0(rp)		C L1
+
+	umulh	v0,	r1,	r8	C U1
+	CMPCY(	r5,	r7),	r20	C L0 lo add => carry
+	ADDSUB	r7,	r6,	r23	C U0 hi add => answer
+	ldq	r1,	8(up)		C L1
+
+	mulq	v0,	r0,	r2	C U1
+	CMPCY(	r7,	r23),	r21	C L0 hi add => carry
+	addq	r24,	r20,	r24	C U0 hi mul + carry
+	ldq	r5,	8(rp)		C L1
+
+	umulh	v0,	r0,	r6	C U1
+	ADDSUB	r4,	r25,	r25	C U0 lo + acc
+	stq	r22,	-16(rp)		C L0
+	stq	r23,	-8(rp)		C L1
+
+	bis	r31,	r31,	r31	C L0 st slosh
+	mulq	v0,	r1,	r7	C U1
+	bis	r31,	r31,	r31	C L1 st slosh
+	addq	r24,	r21,	r24	C U0 hi mul + carry
+$ent2:
+	CMPCY(	r4,	r25),	r20	C L0 lo add => carry
+	bis	r31,	r31,	r31	C U1 mt
+	lda	r18,	-8(r18)		C L1 bookkeeping
+	ADDSUB	r25,	r24,	r22	C U0 hi add => answer
+
+	bis	r31,	r31,	r31	C U1 mt
+	CMPCY(	r25,	r22),	r21	C L0 hi add => carry
+	addq	r3,	r20,	r3	C U0 hi mul + carry
+	ldq	r0,	16(up)		C L1
+
+	bis	r31,	r31,	r31	C U1 mt
+	ADDSUB	r5,	r28,	r28	C L0 lo + acc
+	addq	r3,	r21,	r3	C U0 hi mul + carry
+	ldq	r4,	16(rp)		C L1
+
+	umulh	v0,	r1,	r24	C U1
+	CMPCY(	r5,	r28),	r20	C L0 lo add => carry
+	ADDSUB	r28,	r3,	r23	C U0 hi add => answer
+	ldq	r1,	24(up)		C L1
+
+	mulq	v0,	r0,	r25	C U1
+	CMPCY(	r28,	r23),	r21	C L0 hi add => carry
+	addq	r8,	r20,	r8	C U0 hi mul + carry
+	ldq	r5,	24(rp)		C L1
+
+	umulh	v0,	r0,	r3	C U1
+	ADDSUB	r4,	r2,	r2	C U0 lo + acc
+	stq	r22,	0(rp)		C L0
+	stq	r23,	8(rp)		C L1
+
+	bis	r31,	r31,	r31	C L0 st slosh
+	mulq	v0,	r1,	r28	C U1
+	bis	r31,	r31,	r31	C L1 st slosh
+	addq	r8,	r21,	r8	C U0 hi mul + carry
+$ent0:
+	CMPCY(	r4,	r2),	r20	C L0 lo add => carry
+	bis	r31,	r31,	r31	C U1 mt
+	lda	up,	64(up)		C L1 bookkeeping
+	ADDSUB	r2,	r8,	r22	C U0 hi add => answer
+
+	bis	r31,	r31,	r31	C U1 mt
+	CMPCY(	r2,	r22),	r21	C L0 hi add => carry
+	addq	r6,	r20,	r6	C U0 hi mul + carry
+	ldq	r0,	-32(up)		C L1
+
+	bis	r31,	r31,	r31	C U1 mt
+	ADDSUB	r5,	r7,	r7	C L0 lo + acc
+	addq	r6,	r21,	r6	C U0 hi mul + carry
+	ldq	r4,	32(rp)		C L1
+
+	umulh	v0,	r1,	r8	C U1
+	CMPCY(	r5,	r7),	r20	C L0 lo add => carry
+	ADDSUB	r7,	r6,	r23	C U0 hi add => answer
+	ldq	r1,	-24(up)		C L1
+
+	mulq	v0,	r0,	r2	C U1
+	CMPCY(	r7,	r23),	r21	C L0 hi add => carry
+	addq	r24,	r20,	r24	C U0 hi mul + carry
+	ldq	r5,	40(rp)		C L1
+
+	umulh	v0,	r0,	r6	C U1
+	ADDSUB	r4,	r25,	r25	C U0 lo + acc
+	stq	r22,	16(rp)		C L0
+	stq	r23,	24(rp)		C L1
+
+	bis	r31,	r31,	r31	C L0 st slosh
+	mulq	v0,	r1,	r7	C U1
+	bis	r31,	r31,	r31	C L1 st slosh
+	addq	r24,	r21,	r24	C U0 hi mul + carry
+$ent6:
+	CMPCY(	r4,	r25),	r20	C L0 lo add => carry
+	bis	r31,	r31,	r31	C U1 mt
+	lda	rp,	64(rp)		C L1 bookkeeping
+	ADDSUB	r25,	r24,	r22	C U0 hi add => answer
+
+	bis	r31,	r31,	r31	C U1 mt
+	CMPCY(	r25,	r22),	r21	C L0 hi add => carry
+	addq	r3,	r20,	r3	C U0 hi mul + carry
+	ldq	r0,	-16(up)		C L1
+
+	bis	r31,	r31,	r31	C U1 mt
+	ADDSUB	r5,	r28,	r28	C L0 lo + acc
+	addq	r3,	r21,	r3	C U0 hi mul + carry
+	ldq	r4,	-16(rp)		C L1
+
+	umulh	v0,	r1,	r24	C U1
+	CMPCY(	r5,	r28),	r20	C L0 lo add => carry
+	ADDSUB	r28,	r3,	r23	C U0 hi add => answer
+	ldq	r1,	-8(up)		C L1
+
+	mulq	v0,	r0,	r25	C U1
+	CMPCY(	r28,	r23),	r21	C L0 hi add => carry
+	addq	r8,	r20,	r8	C U0 hi mul + carry
+	ldq	r5,	-8(rp)		C L1
+
+	umulh	v0,	r0,	r3	C U1
+	ADDSUB	r4,	r2,	r2	C U0 lo + acc
+	stq	r22,	-32(rp)		C L0
+	stq	r23,	-24(rp)		C L1
+
+	bis	r31,	r31,	r31	C L0 st slosh
+	mulq	v0,	r1,	r28	C U1
+	bis	r31,	r31,	r31	C L1 st slosh
+	addq	r8,	r21,	r8	C U0 hi mul + carry
+
+	CMPCY(	r4,	r2),	r20	C L0 lo add => carry
+	ADDSUB	r2,	r8,	r22	C U0 hi add => answer
+	ldl	r31,	256(up)		C prefetch up[]
+	bgt	r18,	$Loop		C U1 bookkeeping
+
+$Lend:	CMPCY(	r2,	r22),	r21	C
+	addq	r6,	r20,	r6	C
+	ADDSUB	r5,	r7,	r7	C
+	addq	r6,	r21,	r6	C
+	ldq	r4,	0(rp)		C
+	umulh	v0,	r1,	r8	C
+	CMPCY(	r5,	r7),	r20	C
+	ADDSUB	r7,	r6,	r23	C
+	CMPCY(r7,	r23),	r21	C
+	addq	r24,	r20,	r24	C
+	ldq	r5,	8(rp)		C
+	ADDSUB	r4,	r25,	r25	C
+	stq	r22,	-16(rp)		C
+	stq	r23,	-8(rp)		C
+	addq	r24,	r21,	r24	C
+	br	L(x)
+
+	ALIGN(16)
+$n23:	ldq	r4,	0(rp)		C
+	ldq	r5,	8(rp)		C
+	umulh	v0,	r1,	r8	C
+	ADDSUB	r4,	r25,	r25	C
+L(x):	CMPCY(	r4,	r25),	r20	C
+	ADDSUB	r25,	r24,	r22	C
+	CMPCY(	r25,	r22),	r21	C
+	addq	r3,	r20,	r3	C
+	ADDSUB	r5,	r28,	r28	C
+	addq	r3,	r21,	r3	C
+	CMPCY(	r5,	r28),	r20	C
+	ADDSUB	r28,	r3,	r23	C
+	CMPCY(	r28,	r23),	r21	C
+	addq	r8,	r20,	r8	C
+	stq	r22,	0(rp)		C
+	stq	r23,	8(rp)		C
+	addq	r8,	r21,	r0	C
+	ret	r31,	(r26),	1	C
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/alpha/ev6/gmp-mparam.h b/third_party/gmp/mpn/alpha/ev6/gmp-mparam.h
new file mode 100644
index 0000000..e51d6b0
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/ev6/gmp-mparam.h
@@ -0,0 +1,209 @@
+/* gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 1999-2002, 2004, 2005, 2008-2010, 2014 Free
+Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+#define DIVEXACT_BY3_METHOD 0	/* override ../diveby3.asm */
+
+/* 500 MHz 21164 (agnesi.math.su.se) */
+/* FFT tuning limit = 20000000 */
+/* Generated by tuneup.c, 2014-03-14, gcc 3.3 */
+
+#define DIVREM_1_NORM_THRESHOLD              0  /* preinv always */
+#define DIVREM_1_UNNORM_THRESHOLD            0  /* always */
+#define MOD_1_1P_METHOD                      2
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          4
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          2
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        10
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        21
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD      7
+#define USE_PREINV_DIVREM_1                  1  /* preinv always */
+#define DIV_QR_1N_PI1_METHOD                 2
+#define DIV_QR_1_NORM_THRESHOLD              5
+#define DIV_QR_1_UNNORM_THRESHOLD            1
+#define DIV_QR_2_PI2_THRESHOLD               8
+#define DIVEXACT_1_THRESHOLD                 0  /* always */
+#define BMOD_1_TO_MOD_1_THRESHOLD           20
+
+#define MUL_TOOM22_THRESHOLD                32
+#define MUL_TOOM33_THRESHOLD               117
+#define MUL_TOOM44_THRESHOLD               124
+#define MUL_TOOM6H_THRESHOLD               230
+#define MUL_TOOM8H_THRESHOLD               357
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      97
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     107
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD      88
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     105
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     136
+
+#define SQR_BASECASE_THRESHOLD               0  /* always */
+#define SQR_TOOM2_THRESHOLD                 59
+#define SQR_TOOM3_THRESHOLD                123
+#define SQR_TOOM4_THRESHOLD                163
+#define SQR_TOOM6_THRESHOLD                333
+#define SQR_TOOM8_THRESHOLD                  0  /* always */
+
+#define MULMID_TOOM42_THRESHOLD             52
+
+#define MULMOD_BNM1_THRESHOLD               19
+#define SQRMOD_BNM1_THRESHOLD                5
+
+#define MUL_FFT_MODF_THRESHOLD             468  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    468, 5}, {     19, 6}, {     10, 5}, {     21, 6}, \
+    {     11, 5}, {     23, 6}, {     19, 7}, {     10, 6}, \
+    {     24, 7}, {     13, 6}, {     27, 7}, {     14, 6}, \
+    {     29, 7}, {     17, 6}, {     35, 7}, {     29, 8}, \
+    {     15, 7}, {     32, 8}, {     17, 7}, {     35, 8}, \
+    {     19, 7}, {     39, 8}, {     29, 9}, {     15, 8}, \
+    {     35, 9}, {     19, 8}, {     41, 9}, {     23, 8}, \
+    {     51, 9}, {     27, 8}, {     55, 9}, {     35, 8}, \
+    {     71, 9}, {     39,10}, {     23, 9}, {     55,10}, \
+    {     31, 9}, {     67,10}, {     39, 9}, {     79,10}, \
+    {     47, 9}, {     95,10}, {     55,11}, {     31,10}, \
+    {     79,11}, {     47,10}, {    103,12}, {     31,11}, \
+    {     63,10}, {    135,11}, {     79,10}, {    167,11}, \
+    {     95,10}, {    199,11}, {    111,12}, {     63,11}, \
+    {    143,10}, {    287, 9}, {    575,11}, {    159,10}, \
+    {    319,12}, {     95,11}, {    191,10}, {    383,11}, \
+    {    207,13}, {     63,12}, {    127,11}, {    255,10}, \
+    {    511,11}, {    271,10}, {    543,11}, {    287,10}, \
+    {    575,12}, {    159,11}, {    319,10}, {    639,11}, \
+    {    335,10}, {    671,11}, {    351,10}, {    703,12}, \
+    {    191,11}, {    383,10}, {    767,11}, {    415,12}, \
+    {    223,11}, {    447,13}, {    127,12}, {    255,11}, \
+    {    543,12}, {    287,11}, {    575,10}, {   1151,11}, \
+    {    607,12}, {    319,11}, {    671,12}, {    351,11}, \
+    {    703,13}, {    191,12}, {    383,11}, {    767,12}, \
+    {    415,11}, {    831,12}, {    447,14}, {    127,13}, \
+    {    255,12}, {    575,11}, {   1151,12}, {    607,13}, \
+    {    319,12}, {    735,13}, {    383,12}, {    767,11}, \
+    {   1535,12}, {    831,13}, {    447,12}, {    959,14}, \
+    {    255,13}, {    511,12}, {   1087,13}, {    575,12}, \
+    {   1215,13}, {    639,12}, {   1343,13}, {    703,12}, \
+    {   1407,14}, {    383,13}, {    767,12}, {   1535,13}, \
+    {    831,12}, {   1663,13}, {    959,15}, {    255,14}, \
+    {    511,13}, {   1215,14}, {    639,13}, {   1407,14}, \
+    {    767,13}, {   1663,14}, {    895,13}, {   1855,15}, \
+    {    511,14}, {  16384,15}, {  32768,16}, {  65536,17}, \
+    { 131072,18}, { 262144,19}, { 524288,20}, {1048576,21}, \
+    {2097152,22}, {4194304,23}, {8388608,24} }
+#define MUL_FFT_TABLE3_SIZE 151
+#define MUL_FFT_THRESHOLD                 5760
+
+#define SQR_FFT_MODF_THRESHOLD             412  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    412, 5}, {     19, 6}, {     10, 5}, {     21, 6}, \
+    {     11, 5}, {     23, 6}, {     12, 5}, {     25, 6}, \
+    {     27, 7}, {     14, 6}, {     29, 7}, {     28, 8}, \
+    {     15, 7}, {     31, 8}, {     17, 7}, {     36, 8}, \
+    {     19, 7}, {     39, 8}, {     29, 9}, {     15, 8}, \
+    {     35, 9}, {     19, 8}, {     41, 9}, {     23, 8}, \
+    {     49, 9}, {     27,10}, {     15, 9}, {     39,10}, \
+    {     23, 9}, {     51,11}, {     15,10}, {     31, 9}, \
+    {     67,10}, {     39, 9}, {     79,10}, {     47, 9}, \
+    {     95,10}, {     55,11}, {     31,10}, {     79,11}, \
+    {     47,10}, {     95,12}, {     31,11}, {     63,10}, \
+    {    127, 9}, {    255,11}, {     79,10}, {    159, 9}, \
+    {    319,10}, {    167,11}, {     95,10}, {    191, 9}, \
+    {    383,11}, {    111,12}, {     63,11}, {    127,10}, \
+    {    271,11}, {    143,10}, {    287, 9}, {    575,10}, \
+    {    303,11}, {    159,10}, {    319,12}, {     95,11}, \
+    {    191,10}, {    383,11}, {    207,13}, {     63,12}, \
+    {    127,11}, {    255,10}, {    511,11}, {    271,10}, \
+    {    543,11}, {    287,10}, {    575,11}, {    303,12}, \
+    {    159,11}, {    319,10}, {    639,11}, {    335,10}, \
+    {    671,11}, {    351,10}, {    703,11}, {    367,12}, \
+    {    191,11}, {    383,10}, {    767,11}, {    415,12}, \
+    {    223,11}, {    447,13}, {    127,12}, {    255,11}, \
+    {    543,12}, {    287,11}, {    575,10}, {   1151,11}, \
+    {    607,12}, {    319,11}, {    639,10}, {   1279,11}, \
+    {    671,12}, {    351,11}, {    703,13}, {    191,12}, \
+    {    383,11}, {    767,12}, {    415,11}, {    831,12}, \
+    {    447,11}, {    895,12}, {    479,14}, {    127,13}, \
+    {    255,12}, {    575,11}, {   1151,12}, {    607,13}, \
+    {    319,12}, {    703,11}, {   1407,12}, {    735,13}, \
+    {    383,12}, {    831,13}, {    447,12}, {    959,14}, \
+    {    255,13}, {    511,12}, {   1087,13}, {    575,12}, \
+    {   1151,13}, {    639,12}, {   1279,13}, {    703,12}, \
+    {   1407,14}, {    383,13}, {    767,12}, {   1535,13}, \
+    {    831,12}, {   1663,13}, {    959,15}, {    255,14}, \
+    {    511,13}, {   1215,14}, {    639,13}, {   1407,14}, \
+    {    767,13}, {   1663,14}, {    895,13}, {   1791,15}, \
+    {    511,14}, {  16384,15}, {  32768,16}, {  65536,17}, \
+    { 131072,18}, { 262144,19}, { 524288,20}, {1048576,21}, \
+    {2097152,22}, {4194304,23}, {8388608,24} }
+#define SQR_FFT_TABLE3_SIZE 159
+#define SQR_FFT_THRESHOLD                 5056
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                 100
+#define MULLO_MUL_N_THRESHOLD            11355
+
+#define DC_DIV_QR_THRESHOLD                124
+#define DC_DIVAPPR_Q_THRESHOLD             438
+#define DC_BDIV_QR_THRESHOLD               153
+#define DC_BDIV_Q_THRESHOLD                318
+
+#define INV_MULMOD_BNM1_THRESHOLD           62
+#define INV_NEWTON_THRESHOLD               384
+#define INV_APPR_THRESHOLD                 402
+
+#define BINV_NEWTON_THRESHOLD              381
+#define REDC_1_TO_REDC_N_THRESHOLD         110
+
+#define MU_DIV_QR_THRESHOLD               1752
+#define MU_DIVAPPR_Q_THRESHOLD            1895
+#define MUPI_DIV_QR_THRESHOLD              174
+#define MU_BDIV_QR_THRESHOLD              1387
+#define MU_BDIV_Q_THRESHOLD               1787
+
+#define POWM_SEC_TABLE  1,13,66,82,579
+
+#define MATRIX22_STRASSEN_THRESHOLD         15
+#define HGCD_THRESHOLD                     318
+#define HGCD_APPR_THRESHOLD                363
+#define HGCD_REDUCE_THRESHOLD             2384
+#define GCD_DC_THRESHOLD                  2504
+#define GCDEXT_DC_THRESHOLD                671
+#define JACOBI_BASE_METHOD                   3
+
+#define GET_STR_DC_THRESHOLD                14
+#define GET_STR_PRECOMPUTE_THRESHOLD        25
+#define SET_STR_DC_THRESHOLD              3754
+#define SET_STR_PRECOMPUTE_THRESHOLD      8097
+
+#define FAC_DSC_THRESHOLD                  951
+#define FAC_ODD_THRESHOLD                   24
diff --git a/third_party/gmp/mpn/alpha/ev6/mod_1_4.asm b/third_party/gmp/mpn/alpha/ev6/mod_1_4.asm
new file mode 100644
index 0000000..82c42ae
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/ev6/mod_1_4.asm
@@ -0,0 +1,336 @@
+dnl Alpha mpn_mod_1s_4p
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2009, 2010 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C TODO:
+C  * Optimise.  2.75 c/l should be possible.
+C  * Write a proper mpn_mod_1s_4p_cps.  The code below was compiler generated.
+C  * Optimise feed-in code, starting the sw pipeline in switch code.
+C  * Shorten software pipeline.  The mul instructions are scheduled too far
+C    from their users.  Fixing this will allow us to use fewer registers.
+C  * If we cannot reduce register usage, write perhaps small-n basecase.
+C  * Does this work for PIC?
+
+C      cycles/limb
+C EV4:     ?
+C EV5:    23
+C EV6:     3
+
+define(`ap',     `r16')
+define(`n',      `r17')
+define(`pl',     `r24')
+define(`ph',     `r25')
+define(`rl',     `r6')
+define(`rh',     `r7')
+define(`B1modb', `r1')
+define(`B2modb', `r2')
+define(`B3modb', `r3')
+define(`B4modb', `r4')
+define(`B5modb', `r5')
+
+ASM_START()
+PROLOGUE(mpn_mod_1s_4p)
+	lda	r30, -64(r30)
+	stq	r9, 8(r30)
+	ldq	B1modb, 16(r19)
+	stq	r10, 16(r30)
+	ldq	B2modb, 24(r19)
+	stq	r11, 24(r30)
+	ldq	B3modb, 32(r19)
+	stq	r12, 32(r30)
+	ldq	B4modb, 40(r19)
+	stq	r13, 40(r30)
+	ldq	B5modb, 48(r19)
+	s8addq	n, ap, ap		C point ap at vector end
+
+	and	n, 3, r0
+	lda	n, -4(n)
+	beq	r0, L(b0)
+	lda	r6, -2(r0)
+	blt	r6, L(b1)
+	beq	r6, L(b2)
+
+L(b3):	ldq	r21, -16(ap)
+	ldq	r22, -8(ap)
+	ldq	r20, -24(ap)
+	mulq	r21, B1modb, r8
+	umulh	r21, B1modb, r12
+	mulq	r22, B2modb, r9
+	umulh	r22, B2modb, r13
+	addq	r8, r20, pl
+	cmpult	pl, r8, r0
+	addq	r0, r12, ph
+	addq	r9, pl, rl
+	cmpult	rl, r9, r0
+	addq	r13, ph, ph
+	addq	r0, ph, rh
+	lda	ap, -56(ap)
+	br	L(com)
+
+L(b0):	ldq	r21, -24(ap)
+	ldq	r22, -16(ap)
+	ldq	r23, -8(ap)
+	ldq	r20, -32(ap)
+	mulq	r21, B1modb, r8
+	umulh	r21, B1modb, r12
+	mulq	r22, B2modb, r9
+	umulh	r22, B2modb, r13
+	mulq	r23, B3modb, r10
+	umulh	r23, B3modb, r27
+	addq	r8, r20, pl
+	cmpult	pl, r8, r0
+	addq	r0, r12, ph
+	addq	r9, pl, pl
+	cmpult	pl, r9, r0
+	addq	r13, ph, ph
+	addq	r0, ph, ph
+	addq	r10, pl, rl
+	cmpult	rl, r10, r0
+	addq	r27, ph, ph
+	addq	r0, ph, rh
+	lda	ap, -64(ap)
+	br	L(com)
+
+L(b1):	bis	r31, r31, rh
+	ldq	rl, -8(ap)
+	lda	ap, -40(ap)
+	br	L(com)
+
+L(b2):	ldq	rh, -8(ap)
+	ldq	rl, -16(ap)
+	lda	ap, -48(ap)
+
+L(com):	ble	n, L(ed3)
+	ldq	r21, 8(ap)
+	ldq	r22, 16(ap)
+	ldq	r23, 24(ap)
+	ldq	r20, 0(ap)
+	lda	n, -4(n)
+	lda	ap, -32(ap)
+	mulq	r21, B1modb, r8
+	umulh	r21, B1modb, r12
+	mulq	r22, B2modb, r9
+	umulh	r22, B2modb, r13
+	mulq	r23, B3modb, r10
+	umulh	r23, B3modb, r27
+	mulq	rl, B4modb, r11
+	umulh	rl, B4modb, r28
+	ble	n, L(ed2)
+
+	ALIGN(16)
+L(top):	ldq	r21, 8(ap)
+	mulq	rh, B5modb, rl
+	addq	r8, r20, pl
+	ldq	r22, 16(ap)
+	cmpult	pl, r8, r0
+	umulh	rh, B5modb, rh
+	ldq	r23, 24(ap)
+	addq	r0, r12, ph
+	addq	r9, pl, pl
+	mulq	r21, B1modb, r8
+	cmpult	pl, r9, r0
+	addq	r13, ph, ph
+	umulh	r21, B1modb, r12
+	lda	ap, -32(ap)
+	addq	r0, ph, ph
+	addq	r10, pl, pl
+	mulq	r22, B2modb, r9
+	cmpult	pl, r10, r0
+	addq	r27, ph, ph
+	addq	r11, pl, pl
+	umulh	r22, B2modb, r13
+	addq	r0, ph, ph
+	cmpult	pl, r11, r0
+	addq	r28, ph, ph
+	mulq	r23, B3modb, r10
+	ldq	r20, 32(ap)
+	addq	pl, rl, rl
+	umulh	r23, B3modb, r27
+	addq	r0, ph, ph
+	cmpult	rl, pl, r0
+	mulq	rl, B4modb, r11
+	addq	ph, rh, rh
+	umulh	rl, B4modb, r28
+	addq	r0, rh, rh
+	lda	n, -4(n)
+	bgt	n, L(top)
+
+L(ed2):	mulq	rh, B5modb, rl
+	addq	r8, r20, pl
+	umulh	rh, B5modb, rh
+	cmpult	pl, r8, r0
+	addq	r0, r12, ph
+	addq	r9, pl, pl
+	cmpult	pl, r9, r0
+	addq	r13, ph, ph
+	addq	r0, ph, ph
+	addq	r10, pl, pl
+	cmpult	pl, r10, r0
+	addq	r27, ph, ph
+	addq	r11, pl, pl
+	addq	r0, ph, ph
+	cmpult	pl, r11, r0
+	addq	r28, ph, ph
+	addq	pl, rl, rl
+	addq	r0, ph, ph
+	cmpult	rl, pl, r0
+	addq	ph, rh, rh
+	addq	r0, rh, rh
+
+L(ed3):	mulq	rh, B1modb, r8
+	umulh	rh, B1modb, rh
+	addq	r8, rl, rl
+	cmpult	rl, r8, r0
+	addq	r0, rh, rh
+
+	ldq	r24, 8(r19)		C cnt
+	sll	rh, r24, rh
+	subq	r31, r24, r25
+	srl	rl, r25, r2
+	sll	rl, r24, rl
+	or	r2, rh, rh
+
+	ldq	r23, 0(r19)		C bi
+	mulq	rh, r23, r8
+	umulh	rh, r23, r9
+	addq	rh, 1, r7
+	addq	r8, rl, r8		C ql
+	cmpult	r8, rl, r0
+	addq	r9, r7, r9
+	addq	r0, r9, r9		C qh
+	mulq	r9, r18, r21		C qh * b
+	subq	rl, r21, rl
+	cmpult	r8, rl, r0		C rl > ql
+	negq	r0, r0
+	and	r0, r18, r0
+	addq	rl, r0, rl
+	cmpule	r18, rl, r0		C rl >= b
+	negq	r0, r0
+	and	r0, r18, r0
+	subq	rl, r0, rl
+
+	srl	rl, r24, r0
+
+	ldq	r9, 8(r30)
+	ldq	r10, 16(r30)
+	ldq	r11, 24(r30)
+	ldq	r12, 32(r30)
+	ldq	r13, 40(r30)
+	lda	r30, 64(r30)
+	ret	r31, (r26), 1
+EPILOGUE()
+
+PROLOGUE(mpn_mod_1s_4p_cps,gp)
+	lda	r30, -32(r30)
+	stq	r26, 0(r30)
+	stq	r9, 8(r30)
+	stq	r10, 16(r30)
+	stq	r11, 24(r30)
+	mov	r16, r11
+	LEA(	r4, __clz_tab)
+	lda	r10, 65(r31)
+	cmpbge	r31, r17, r1
+	srl	r1, 1, r1
+	xor	r1, 127, r1
+	addq	r1, r4, r1
+	ldq_u	r2, 0(r1)
+	extbl	r2, r1, r2
+	s8subq	r2, 7, r2
+	srl	r17, r2, r3
+	subq	r10, r2, r10
+	addq	r3, r4, r3
+	ldq_u	r1, 0(r3)
+	extbl	r1, r3, r1
+	subq	r10, r1, r10
+	sll	r17, r10, r9
+	mov	r9, r16
+	jsr	r26, mpn_invert_limb
+	LDGP(	r29, 0(r26))
+	subq	r31, r10, r2
+	lda	r1, 1(r31)
+	sll	r1, r10, r1
+	subq	r31, r9, r3
+	srl	r0, r2, r2
+	ldq	r26, 0(r30)
+	bis	r2, r1, r2
+	stq	r0, 0(r11)
+	stq	r10, 8(r11)
+	mulq	r2, r3, r2
+	srl	r2, r10, r3
+	umulh	r2, r0, r1
+	stq	r3, 16(r11)
+	mulq	r2, r0, r3
+	ornot	r31, r1, r1
+	subq	r1, r2, r1
+	mulq	r1, r9, r1
+	addq	r1, r9, r2
+	cmpule	r1, r3, r3
+	cmoveq	r3, r2, r1
+	srl	r1, r10, r3
+	umulh	r1, r0, r2
+	stq	r3, 24(r11)
+	mulq	r1, r0, r3
+	ornot	r31, r2, r2
+	subq	r2, r1, r2
+	mulq	r2, r9, r2
+	addq	r2, r9, r1
+	cmpule	r2, r3, r3
+	cmoveq	r3, r1, r2
+	srl	r2, r10, r1
+	umulh	r2, r0, r3
+	stq	r1, 32(r11)
+	mulq	r2, r0, r1
+	ornot	r31, r3, r3
+	subq	r3, r2, r3
+	mulq	r3, r9, r3
+	addq	r3, r9, r2
+	cmpule	r3, r1, r1
+	cmoveq	r1, r2, r3
+	srl	r3, r10, r2
+	umulh	r3, r0, r1
+	stq	r2, 40(r11)
+	mulq	r3, r0, r0
+	ornot	r31, r1, r1
+	subq	r1, r3, r1
+	mulq	r1, r9, r1
+	addq	r1, r9, r9
+	cmpule	r1, r0, r0
+	cmoveq	r0, r9, r1
+	ldq	r9, 8(r30)
+	srl	r1, r10, r1
+	ldq	r10, 16(r30)
+	stq	r1, 48(r11)
+	ldq	r11, 24(r30)
+	lda	r30, 32(r30)
+	ret	r31, (r26), 1
+EPILOGUE()
diff --git a/third_party/gmp/mpn/alpha/ev6/mul_1.asm b/third_party/gmp/mpn/alpha/ev6/mul_1.asm
new file mode 100644
index 0000000..8ee19cd
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/ev6/mul_1.asm
@@ -0,0 +1,496 @@
+dnl  Alpha ev6 mpn_mul_1 -- Multiply a limb vector with a limb and store the
+dnl  result in a second limb vector.
+
+dnl  Copyright 2000, 2001, 2005 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C res_ptr	r16
+C s1_ptr	r17
+C size		r18
+C s2_limb	r19
+
+C This code runs at 2.25 cycles/limb on EV6.
+
+C This code was written in close cooperation with ev6 pipeline expert
+C Steve Root.  Any errors are tege's fault, though.
+
+C Code structure:
+
+C  code for n < 8
+C  code for n > 8	code for (n mod 8)
+C			code for (n div 8)	feed-in code
+C						8-way unrolled loop
+C						wind-down code
+
+C Some notes about unrolled loop:
+C
+C   r1-r8     multiplies and workup
+C   r21-r28   multiplies and workup
+C   r9-r12    loads
+C   r0       -1
+C   r20,r29,r13-r15  scramble
+C
+C   We're doing 7 of the 8 carry propagations with a br fixup code and 1 with a
+C   put-the-carry-into-hi.  The idea is that these branches are very rarely
+C   taken, and since a non-taken branch consumes no resources, that is better
+C   than an addq.
+C
+C   Software pipeline: a load in cycle #09, feeds a mul in cycle #16, feeds an
+C   add NEXT cycle #09 which feeds a store in NEXT cycle #02
+
+C The code could use some further work:
+C   1. Speed up really small multiplies.  The default alpha/mul_1.asm code is
+C      faster than this for size < 3.
+C   2. Improve feed-in code, perhaps with the equivalent of switch(n%8) unless
+C      that is too costly.
+C   3. Consider using 4-way unrolling, even if that runs slower.
+C   4. Reduce register usage.  In particular, try to avoid using r29.
+
+ASM_START()
+PROLOGUE(mpn_mul_1)
+	cmpult	r18,	8,	r1
+	beq	r1,	$Large
+$Lsmall:
+	ldq	r2,0(r17)	C r2 = s1_limb
+	lda	r18,-1(r18)	C size--
+	mulq	r2,r19,r3	C r3 = prod_low
+	bic	r31,r31,r4	C clear cy_limb
+	umulh	r2,r19,r0	C r0 = prod_high
+	beq	r18,$Le1a	C jump if size was == 1
+	ldq	r2,8(r17)	C r2 = s1_limb
+	lda	r18,-1(r18)	C size--
+	stq	r3,0(r16)
+	beq	r18,$Le2a	C jump if size was == 2
+	ALIGN(8)
+$Lopa:	mulq	r2,r19,r3	C r3 = prod_low
+	addq	r4,r0,r0	C cy_limb = cy_limb + 'cy'
+	lda	r18,-1(r18)	C size--
+	umulh	r2,r19,r4	C r4 = cy_limb
+	ldq	r2,16(r17)	C r2 = s1_limb
+	lda	r17,8(r17)	C s1_ptr++
+	addq	r3,r0,r3	C r3 = cy_limb + prod_low
+	stq	r3,8(r16)
+	cmpult	r3,r0,r0	C r0 = carry from (cy_limb + prod_low)
+	lda	r16,8(r16)	C res_ptr++
+	bne	r18,$Lopa
+
+$Le2a:	mulq	r2,r19,r3	C r3 = prod_low
+	addq	r4,r0,r0	C cy_limb = cy_limb + 'cy'
+	umulh	r2,r19,r4	C r4 = cy_limb
+	addq	r3,r0,r3	C r3 = cy_limb + prod_low
+	cmpult	r3,r0,r0	C r0 = carry from (cy_limb + prod_low)
+	stq	r3,8(r16)
+	addq	r4,r0,r0	C cy_limb = prod_high + cy
+	ret	r31,(r26),1
+$Le1a:	stq	r3,0(r16)
+	ret	r31,(r26),1
+
+$Large:
+	lda	r30,	-224(r30)
+	stq	r26,	0(r30)
+	stq	r9,	8(r30)
+	stq	r10,	16(r30)
+	stq	r11,	24(r30)
+	stq	r12,	32(r30)
+	stq	r13,	40(r30)
+	stq	r14,	48(r30)
+	stq	r15,	56(r30)
+	stq	r29,	64(r30)
+
+	and	r18,	7,	r20	C count for the first loop, 0-7
+	srl	r18,	3,	r18	C count for unrolled loop
+	bis	r31,	r31,	r21
+	beq	r20,	$L_8_or_more	C skip first loop
+
+$L_9_or_more:
+	ldq	r2,0(r17)	C r2 = s1_limb
+	lda	r17,8(r17)	C s1_ptr++
+	lda	r20,-1(r20)	C size--
+	mulq	r2,r19,r3	C r3 = prod_low
+	umulh	r2,r19,r21	C r21 = prod_high
+	beq	r20,$Le1b	C jump if size was == 1
+	bis	r31, r31, r0	C FIXME: shouldn't need this
+	ldq	r2,0(r17)	C r2 = s1_limb
+	lda	r17,8(r17)	C s1_ptr++
+	lda	r20,-1(r20)	C size--
+	stq	r3,0(r16)
+	lda	r16,8(r16)	C res_ptr++
+	beq	r20,$Le2b	C jump if size was == 2
+	ALIGN(8)
+$Lopb:	mulq	r2,r19,r3	C r3 = prod_low
+	addq	r21,r0,r0	C cy_limb = cy_limb + 'cy'
+	lda	r20,-1(r20)	C size--
+	umulh	r2,r19,r21	C r21 = prod_high
+	ldq	r2,0(r17)	C r2 = s1_limb
+	lda	r17,8(r17)	C s1_ptr++
+	addq	r3,r0,r3	C r3 = cy_limb + prod_low
+	stq	r3,0(r16)
+	cmpult	r3,r0,r0	C r0 = carry from (cy_limb + prod_low)
+	lda	r16,8(r16)	C res_ptr++
+	bne	r20,$Lopb
+
+$Le2b:	mulq	r2,r19,r3	C r3 = prod_low
+	addq	r21,r0,r0	C cy_limb = cy_limb + 'cy'
+	umulh	r2,r19,r21	C r21 = prod_high
+	addq	r3,r0,r3	C r3 = cy_limb + prod_low
+	cmpult	r3,r0,r0	C r0 = carry from (cy_limb + prod_low)
+	stq	r3,0(r16)
+	lda	r16,8(r16)	C res_ptr++
+	addq	r21,r0,r21	C cy_limb = prod_high + cy
+	br	r31,	$L_8_or_more
+$Le1b:	stq	r3,0(r16)
+	lda	r16,8(r16)	C res_ptr++
+
+$L_8_or_more:
+	lda	r0,	-1(r31)		C put -1 in r0, for tricky loop control
+	lda	r17,	-32(r17)	C L1 bookkeeping
+	lda	r18,	-1(r18)		C decrement count
+
+	ldq	r9,	32(r17)		C L1
+	ldq	r10,	40(r17)		C L1
+	mulq	r9,	r19,	r22	C U1 #07
+	ldq	r11,	48(r17)		C L1
+	umulh	r9,	r19,	r23	C U1 #08
+	ldq	r12,	56(r17)		C L1
+	mulq	r10,	r19,	r24	C U1 #09
+	ldq	r9,	64(r17)		C L1
+
+	lda	r17,	64(r17)		C L1 bookkeeping
+
+	umulh	r10,	r19,	r25	C U1 #11
+	mulq	r11,	r19,	r26	C U1 #12
+	umulh	r11,	r19,	r27	C U1 #13
+	mulq	r12,	r19,	r28	C U1 #14
+	ldq	r10,	8(r17)		C L1
+	umulh	r12,	r19,	r1	C U1 #15
+	ldq	r11,	16(r17)		C L1
+	mulq	r9,	r19,	r2	C U1 #16
+	ldq	r12,	24(r17)		C L1
+	umulh	r9,	r19,	r3	C U1 #17
+	addq	r21,	r22,	r13	C L1 mov
+	mulq	r10,	r19,	r4	C U1 #18
+	addq	r23,	r24,	r22	C L0 sum 2 mul's
+	cmpult	r13,	r21,	r14	C L1 carry from sum
+	bgt	r18,	$L_16_or_more
+
+	cmpult	r22,	r24,	r24	C U0 carry from sum
+	umulh	r10,	r19,	r5	C U1 #02
+	addq	r25,	r26,	r23	C U0 sum 2 mul's
+	mulq	r11,	r19,	r6	C U1 #03
+	cmpult	r23,	r26,	r25	C U0 carry from sum
+	umulh	r11,	r19,	r7	C U1 #04
+	addq	r27,	r28,	r28	C U0 sum 2 mul's
+	mulq	r12,	r19,	r8	C U1 #05
+	cmpult	r28,	r27,	r15	C L0 carry from sum
+	lda	r16,	32(r16)		C L1 bookkeeping
+	addq	r13,	r31,	r13	C U0 start carry cascade
+	umulh	r12,	r19,	r21	C U1 #06
+	br	r31,	$ret0c
+
+$L_16_or_more:
+C ---------------------------------------------------------------
+	subq	r18,1,r18
+	cmpult	r22,	r24,	r24	C U0 carry from sum
+	ldq	r9,	32(r17)		C L1
+
+	umulh	r10,	r19,	r5	C U1 #02
+	addq	r25,	r26,	r23	C U0 sum 2 mul's
+	mulq	r11,	r19,	r6	C U1 #03
+	cmpult	r23,	r26,	r25	C U0 carry from sum
+	umulh	r11,	r19,	r7	C U1 #04
+	addq	r27,	r28,	r28	C U0 sum 2 mul's
+	mulq	r12,	r19,	r8	C U1 #05
+	cmpult	r28,	r27,	r15	C L0 carry from sum
+	lda	r16,	32(r16)		C L1 bookkeeping
+	addq	r13,	r31,	r13	C U0 start carry cascade
+
+	umulh	r12,	r19,	r21	C U1 #06
+C	beq	r13,	$fix0w		C U0
+$ret0w:	addq	r22,	r14,	r26	C L0
+	ldq	r10,	40(r17)		C L1
+
+	mulq	r9,	r19,	r22	C U1 #07
+	beq	r26,	$fix1w		C U0
+$ret1w:	addq	r23,	r24,	r27	C L0
+	ldq	r11,	48(r17)		C L1
+
+	umulh	r9,	r19,	r23	C U1 #08
+	beq	r27,	$fix2w		C U0
+$ret2w:	addq	r28,	r25,	r28	C L0
+	ldq	r12,	56(r17)		C L1
+
+	mulq	r10,	r19,	r24	C U1 #09
+	beq	r28,	$fix3w		C U0
+$ret3w:	addq	r1,	r2,	r20	C L0 sum 2 mul's
+	ldq	r9,	64(r17)		C L1
+
+	addq	r3,	r4,	r2	C L0 #10 2 mul's
+	lda	r17,	64(r17)		C L1 bookkeeping
+	cmpult	r20,	r1,	r29	C U0 carry from sum
+
+	umulh	r10,	r19,	r25	C U1 #11
+	cmpult	r2,	r4,	r4	C U0 carry from sum
+	stq	r13,	-32(r16)	C L0
+	stq	r26,	-24(r16)	C L1
+
+	mulq	r11,	r19,	r26	C U1 #12
+	addq	r5,	r6,	r14	C U0 sum 2 mul's
+	stq	r27,	-16(r16)	C L0
+	stq	r28,	-8(r16)		C L1
+
+	umulh	r11,	r19,	r27	C U1 #13
+	cmpult	r14,	r6,	r3	C U0 carry from sum
+C could do cross-jumping here:
+C	bra	$L_middle_of_unrolled_loop
+	mulq	r12,	r19,	r28	C U1 #14
+	addq	r7,	r3,	r5	C L0 eat carry
+	addq	r20,	r15,	r20	C U0 carry cascade
+	ldq	r10,	8(r17)		C L1
+
+	umulh	r12,	r19,	r1	C U1 #15
+	beq	r20,	$fix4		C U0
+$ret4w:	addq	r2,	r29,	r6	C L0
+	ldq	r11,	16(r17)		C L1
+
+	mulq	r9,	r19,	r2	C U1 #16
+	beq	r6,	$fix5		C U0
+$ret5w:	addq	r14,	r4,	r7	C L0
+	ldq	r12,	24(r17)		C L1
+
+	umulh	r9,	r19,	r3	C U1 #17
+	beq	r7,	$fix6		C U0
+$ret6w:	addq	r5,	r8,	r8	C L0 sum 2
+	addq	r21,	r22,	r13	C L1 sum 2 mul's
+
+	mulq	r10,	r19,	r4	C U1 #18
+	addq	r23,	r24,	r22	C L0 sum 2 mul's
+	cmpult	r13,	r21,	r14	C L1 carry from sum
+	ble	r18,	$Lend		C U0
+C ---------------------------------------------------------------
+	ALIGN(16)
+$Loop:
+	umulh	r0,	r18,	r18	C U1 #01 decrement r18!
+	cmpult	r8,	r5,	r29	C L0 carry from last bunch
+	cmpult	r22,	r24,	r24	C U0 carry from sum
+	ldq	r9,	32(r17)		C L1
+
+	umulh	r10,	r19,	r5	C U1 #02
+	addq	r25,	r26,	r23	C U0 sum 2 mul's
+	stq	r20,	0(r16)		C L0
+	stq	r6,	8(r16)		C L1
+
+	mulq	r11,	r19,	r6	C U1 #03
+	cmpult	r23,	r26,	r25	C U0 carry from sum
+	stq	r7,	16(r16)		C L0
+	stq	r8,	24(r16)		C L1
+
+	umulh	r11,	r19,	r7	C U1 #04
+	bis	r31,	r31,	r31	C L0 st slosh
+	bis	r31,	r31,	r31	C L1 st slosh
+	addq	r27,	r28,	r28	C U0 sum 2 mul's
+
+	mulq	r12,	r19,	r8	C U1 #05
+	cmpult	r28,	r27,	r15	C L0 carry from sum
+	lda	r16,	64(r16)		C L1 bookkeeping
+	addq	r13,	r29,	r13	C U0 start carry cascade
+
+	umulh	r12,	r19,	r21	C U1 #06
+	beq	r13,	$fix0		C U0
+$ret0:	addq	r22,	r14,	r26	C L0
+	ldq	r10,	40(r17)		C L1
+
+	mulq	r9,	r19,	r22	C U1 #07
+	beq	r26,	$fix1		C U0
+$ret1:	addq	r23,	r24,	r27	C L0
+	ldq	r11,	48(r17)		C L1
+
+	umulh	r9,	r19,	r23	C U1 #08
+	beq	r27,	$fix2		C U0
+$ret2:	addq	r28,	r25,	r28	C L0
+	ldq	r12,	56(r17)		C L1
+
+	mulq	r10,	r19,	r24	C U1 #09
+	beq	r28,	$fix3		C U0
+$ret3:	addq	r1,	r2,	r20	C L0 sum 2 mul's
+	ldq	r9,	64(r17)		C L1
+
+	addq	r3,	r4,	r2	C L0 #10 2 mul's
+	bis	r31,	r31,	r31	C U1 mul hole
+	lda	r17,	64(r17)		C L1 bookkeeping
+	cmpult	r20,	r1,	r29	C U0 carry from sum
+
+	umulh	r10,	r19,	r25	C U1 #11
+	cmpult	r2,	r4,	r4	C U0 carry from sum
+	stq	r13,	-32(r16)	C L0
+	stq	r26,	-24(r16)	C L1
+
+	mulq	r11,	r19,	r26	C U1 #12
+	addq	r5,	r6,	r14	C U0 sum 2 mul's
+	stq	r27,	-16(r16)	C L0
+	stq	r28,	-8(r16)		C L1
+
+	umulh	r11,	r19,	r27	C U1 #13
+	bis	r31,	r31,	r31	C L0 st slosh
+	bis	r31,	r31,	r31	C L1 st slosh
+	cmpult	r14,	r6,	r3	C U0 carry from sum
+$L_middle_of_unrolled_loop:
+	mulq	r12,	r19,	r28	C U1 #14
+	addq	r7,	r3,	r5	C L0 eat carry
+	addq	r20,	r15,	r20	C U0 carry cascade
+	ldq	r10,	8(r17)		C L1
+
+	umulh	r12,	r19,	r1	C U1 #15
+	beq	r20,	$fix4		C U0
+$ret4:	addq	r2,	r29,	r6	C L0
+	ldq	r11,	16(r17)		C L1
+
+	mulq	r9,	r19,	r2	C U1 #16
+	beq	r6,	$fix5		C U0
+$ret5:	addq	r14,	r4,	r7	C L0
+	ldq	r12,	24(r17)		C L1
+
+	umulh	r9,	r19,	r3	C U1 #17
+	beq	r7,	$fix6		C U0
+$ret6:	addq	r5,	r8,	r8	C L0 sum 2
+	addq	r21,	r22,	r13	C L1 sum 2 mul's
+
+	mulq	r10,	r19,	r4	C U1 #18
+	addq	r23,	r24,	r22	C L0 sum 2 mul's
+	cmpult	r13,	r21,	r14	C L1 carry from sum
+	bgt	r18,	$Loop		C U0
+C ---------------------------------------------------------------
+$Lend:
+	cmpult	r8,	r5,	r29	C L0 carry from last bunch
+	cmpult	r22,	r24,	r24	C U0 carry from sum
+
+	umulh	r10,	r19,	r5	C U1 #02
+	addq	r25,	r26,	r23	C U0 sum 2 mul's
+	stq	r20,	0(r16)		C L0
+	stq	r6,	8(r16)		C L1
+
+	mulq	r11,	r19,	r6	C U1 #03
+	cmpult	r23,	r26,	r25	C U0 carry from sum
+	stq	r7,	16(r16)		C L0
+	stq	r8,	24(r16)		C L1
+
+	umulh	r11,	r19,	r7	C U1 #04
+	addq	r27,	r28,	r28	C U0 sum 2 mul's
+
+	mulq	r12,	r19,	r8	C U1 #05
+	cmpult	r28,	r27,	r15	C L0 carry from sum
+	lda	r16,	64(r16)		C L1 bookkeeping
+	addq	r13,	r29,	r13	C U0 start carry cascade
+
+	umulh	r12,	r19,	r21	C U1 #06
+	beq	r13,	$fix0c		C U0
+$ret0c:	addq	r22,	r14,	r26	C L0
+	beq	r26,	$fix1c		C U0
+$ret1c:	addq	r23,	r24,	r27	C L0
+	beq	r27,	$fix2c		C U0
+$ret2c:	addq	r28,	r25,	r28	C L0
+	beq	r28,	$fix3c		C U0
+$ret3c:	addq	r1,	r2,	r20	C L0 sum 2 mul's
+	addq	r3,	r4,	r2	C L0 #10 2 mul's
+	lda	r17,	64(r17)		C L1 bookkeeping
+	cmpult	r20,	r1,	r29	C U0 carry from sum
+	cmpult	r2,	r4,	r4	C U0 carry from sum
+	stq	r13,	-32(r16)	C L0
+	stq	r26,	-24(r16)	C L1
+	addq	r5,	r6,	r14	C U0 sum 2 mul's
+	stq	r27,	-16(r16)	C L0
+	stq	r28,	-8(r16)		C L1
+	cmpult	r14,	r6,	r3	C U0 carry from sum
+	addq	r7,	r3,	r5	C L0 eat carry
+	addq	r20,	r15,	r20	C U0 carry cascade
+	beq	r20,	$fix4c		C U0
+$ret4c:	addq	r2,	r29,	r6	C L0
+	beq	r6,	$fix5c		C U0
+$ret5c:	addq	r14,	r4,	r7	C L0
+	beq	r7,	$fix6c		C U0
+$ret6c:	addq	r5,	r8,	r8	C L0 sum 2
+	cmpult	r8,	r5,	r29	C L0 carry from last bunch
+	stq	r20,	0(r16)		C L0
+	stq	r6,	8(r16)		C L1
+	stq	r7,	16(r16)		C L0
+	stq	r8,	24(r16)		C L1
+	addq	r29,	r21,	r0
+
+	ldq	r26,	0(r30)
+	ldq	r9,	8(r30)
+	ldq	r10,	16(r30)
+	ldq	r11,	24(r30)
+	ldq	r12,	32(r30)
+	ldq	r13,	40(r30)
+	ldq	r14,	48(r30)
+	ldq	r15,	56(r30)
+	ldq	r29,	64(r30)
+	lda	r30,	224(r30)
+	ret	r31,	(r26),	1
+
+C $fix0w:	bis	r14,	r29,	r14	C join carries
+C	br	r31,	$ret0w
+$fix1w:	bis	r24,	r14,	r24	C join carries
+	br	r31,	$ret1w
+$fix2w:	bis	r25,	r24,	r25	C join carries
+	br	r31,	$ret2w
+$fix3w:	bis	r15,	r25,	r15	C join carries
+	br	r31,	$ret3w
+$fix0:	bis	r14,	r29,	r14	C join carries
+	br	r31,	$ret0
+$fix1:	bis	r24,	r14,	r24	C join carries
+	br	r31,	$ret1
+$fix2:	bis	r25,	r24,	r25	C join carries
+	br	r31,	$ret2
+$fix3:	bis	r15,	r25,	r15	C join carries
+	br	r31,	$ret3
+$fix4:	bis	r29,	r15,	r29	C join carries
+	br	r31,	$ret4
+$fix5:	bis	r4,	r29,	r4	C join carries
+	br	r31,	$ret5
+$fix6:	addq	r5,	r4,	r5	C can't carry twice!
+	br	r31,	$ret6
+$fix0c:	bis	r14,	r29,	r14	C join carries
+	br	r31,	$ret0c
+$fix1c:	bis	r24,	r14,	r24	C join carries
+	br	r31,	$ret1c
+$fix2c:	bis	r25,	r24,	r25	C join carries
+	br	r31,	$ret2c
+$fix3c:	bis	r15,	r25,	r15	C join carries
+	br	r31,	$ret3c
+$fix4c:	bis	r29,	r15,	r29	C join carries
+	br	r31,	$ret4c
+$fix5c:	bis	r4,	r29,	r4	C join carries
+	br	r31,	$ret5c
+$fix6c:	addq	r5,	r4,	r5	C can't carry twice!
+	br	r31,	$ret6c
+
+EPILOGUE(mpn_mul_1)
+ASM_END()
diff --git a/third_party/gmp/mpn/alpha/ev6/nails/README b/third_party/gmp/mpn/alpha/ev6/nails/README
new file mode 100644
index 0000000..b214ac5
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/ev6/nails/README
@@ -0,0 +1,65 @@
+Copyright 2002, 2005 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.
+
+
+
+
+
+This directory contains assembly code for nails-enabled 21264.  The code is not
+very well optimized.
+
+For addmul_N, as N grows larger, we could make multiple loads together, then do
+about 3.3 i/c.  10 cycles after the last load, we can increase to 4 i/c.  This
+would surely allow addmul_4 to run at 2 c/l, but the same should be possible
+also for addmul_3 and perhaps even addmul_2.
+
+
+		current		fair		best
+Routine		c/l  unroll	c/l  unroll	c/l  i/c
+mul_1		3.25		2.75		2.75 3.273
+addmul_1	4.0	4	3.5	4 14	3.25 3.385
+addmul_2	4.0	1	2.5	2 10	2.25 3.333
+addmul_3	3.0	1	2.33	2 14	2    3.333
+addmul_4	2.5	1	2.125	2 17	2    3.135
+
+addmul_5			2	1 10
+addmul_6			2	1 12
+addmul_7			2	1 14
+
+(The "best" column doesn't account for bookkeeping instructions and
+thereby assumes infinite unrolling.)
+
+Basecase usages:
+
+1	 addmul_1
+2	 addmul_2
+3	 addmul_3
+4	 addmul_4
+5	 addmul_3 + addmul_2	2.3998
+6	 addmul_4 + addmul_2
+7	 addmul_4 + addmul_3
diff --git a/third_party/gmp/mpn/alpha/ev6/nails/addmul_1.asm b/third_party/gmp/mpn/alpha/ev6/nails/addmul_1.asm
new file mode 100644
index 0000000..711d4e6
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/ev6/nails/addmul_1.asm
@@ -0,0 +1,396 @@
+dnl  Alpha ev6 nails mpn_addmul_1.
+
+dnl  Copyright 2002, 2005, 2006 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C      cycles/limb
+C EV4:    42
+C EV5:    18
+C EV6:     4
+
+C TODO
+C  * Reroll loop for 3.75 c/l with current 4-way unrolling.
+C  * The loop is overscheduled wrt loads and wrt multiplies, in particular
+C    umulh.
+C  * Use FP loop count and multiple exit points, that would simplify feed-in lp0
+C    and would work since the loop structure is really regular.
+
+C  INPUT PARAMETERS
+define(`rp',`r16')
+define(`up',`r17')
+define(`n', `r18')
+define(`vl0',`r19')
+
+define(`numb_mask',`r6')
+
+define(`m0a',`r0')
+define(`m0b',`r1')
+define(`m1a',`r2')
+define(`m1b',`r3')
+define(`m2a',`r20')
+define(`m2b',`r21')
+define(`m3a',`r22')
+define(`m3b',`r23')
+
+define(`acc0',`r25')
+define(`acc1',`r27')
+
+define(`ul0',`r4')
+define(`ul1',`r5')
+define(`ul2',`r4')
+define(`ul3',`r5')
+
+define(`rl0',`r24')
+define(`rl1',`r24')
+define(`rl2',`r24')
+define(`rl3',`r24')
+
+define(`t0',`r7')
+define(`t1',`r8')
+
+define(`NAIL_BITS',`GMP_NAIL_BITS')
+define(`NUMB_BITS',`GMP_NUMB_BITS')
+
+dnl  This declaration is munged by configure
+NAILS_SUPPORT(2-63)
+
+ASM_START()
+PROLOGUE(mpn_addmul_1)
+	sll	vl0, NAIL_BITS, vl0
+	lda	numb_mask, -1(r31)
+	srl	numb_mask, NAIL_BITS, numb_mask
+
+	and	n,	3,	r25
+	cmpeq	r25,	1,	r21
+	bne	r21,	L(1m4)
+	cmpeq	r25,	2,	r21
+	bne	r21,	L(2m4)
+	beq	r25,	L(0m4)
+
+L(3m4):	ldq	ul3,	0(up)
+	lda	n,	-4(n)
+	ldq	ul0,	8(up)
+	mulq	vl0,	ul3,	m3a
+	umulh	vl0,	ul3,	m3b
+	ldq	ul1,	16(up)
+	lda	up,	24(up)
+	lda	rp,	-8(rp)
+	mulq	vl0,	ul0,	m0a
+	umulh	vl0,	ul0,	m0b
+	bge	n,	L(ge3)
+
+	mulq	vl0,	ul1,	m1a
+	umulh	vl0,	ul1,	m1b
+	ldq	rl3,	8(rp)
+	srl	m3a,NAIL_BITS,	t0
+	addq	t0,	r31,	acc1
+	addq	rl3,	acc1,	acc1
+	ldq	rl0,	16(rp)
+	srl	m0a,NAIL_BITS,	t0
+	addq	t0,	m3b,	acc0
+	srl	acc1,NUMB_BITS,	t1
+	br	r31,	L(ta3)
+
+L(ge3):	ldq	ul2,	0(up)
+	mulq	vl0,	ul1,	m1a
+	umulh	vl0,	ul1,	m1b
+	ldq	rl3,	8(rp)
+	srl	m3a,NAIL_BITS,	t0
+	ldq	ul3,	8(up)
+	lda	n,	-4(n)
+	mulq	vl0,	ul2,	m2a
+	addq	t0,	r31,	acc1
+	umulh	vl0,	ul2,	m2b
+	addq	rl3,	acc1,	acc1
+	ldq	rl0,	16(rp)
+	srl	m0a,NAIL_BITS,	t0
+	ldq	ul0,	16(up)
+	mulq	vl0,	ul3,	m3a
+	addq	t0,	m3b,	acc0
+	srl	acc1,NUMB_BITS,	t1
+	br	r31,	L(el3)
+
+L(0m4):	lda	n,	-8(n)
+	ldq	ul2,	0(up)
+	ldq	ul3,	8(up)
+	mulq	vl0,	ul2,	m2a
+	umulh	vl0,	ul2,	m2b
+	ldq	ul0,	16(up)
+	mulq	vl0,	ul3,	m3a
+	umulh	vl0,	ul3,	m3b
+	ldq	ul1,	24(up)
+	lda	up,	32(up)
+	mulq	vl0,	ul0,	m0a
+	umulh	vl0,	ul0,	m0b
+	bge	n,	L(ge4)
+
+	ldq	rl2,	0(rp)
+	srl	m2a,NAIL_BITS,	t0
+	mulq	vl0,	ul1,	m1a
+	addq	t0,	r31,	acc0
+	umulh	vl0,	ul1,	m1b
+	addq	rl2,	acc0,	acc0
+	ldq	rl3,	8(rp)
+	srl	m3a,NAIL_BITS,	t0
+	addq	t0,	m2b,	acc1
+	srl	acc0,NUMB_BITS,	t1
+	br	r31,	L(ta4)
+
+L(ge4):	ldq	rl2,	0(rp)
+	srl	m2a,NAIL_BITS,	t0
+	ldq	ul2,	0(up)
+	mulq	vl0,	ul1,	m1a
+	addq	t0,	r31,	acc0
+	umulh	vl0,	ul1,	m1b
+	addq	rl2,	acc0,	acc0
+	ldq	rl3,	8(rp)
+	srl	m3a,NAIL_BITS,	t0
+	ldq	ul3,	8(up)
+	lda	n,	-4(n)
+	mulq	vl0,	ul2,	m2a
+	addq	t0,	m2b,	acc1
+	srl	acc0,NUMB_BITS,	t1
+	br	r31,	L(el0)
+
+L(2m4):	lda	n,	-4(n)
+	ldq	ul0,	0(up)
+	ldq	ul1,	8(up)
+	lda	up,	16(up)
+	lda	rp,	-16(rp)
+	mulq	vl0,	ul0,	m0a
+	umulh	vl0,	ul0,	m0b
+	bge	n,	L(ge2)
+
+	mulq	vl0,	ul1,	m1a
+	umulh	vl0,	ul1,	m1b
+	ldq	rl0,	16(rp)
+	srl	m0a,NAIL_BITS,	t0
+	addq	t0,	r31,	acc0
+	addq	rl0,	acc0,	acc0
+	ldq	rl1,	24(rp)
+	srl	m1a,NAIL_BITS,	t0
+	addq	t0,	m0b,	acc1
+	srl	acc0,NUMB_BITS,	t1
+	br	r31,	L(ta2)
+
+L(ge2):	ldq	ul2,	0(up)
+	mulq	vl0,	ul1,	m1a
+	umulh	vl0,	ul1,	m1b
+	ldq	ul3,	8(up)
+	lda	n,	-4(n)
+	mulq	vl0,	ul2,	m2a
+	umulh	vl0,	ul2,	m2b
+	ldq	rl0,	16(rp)
+	srl	m0a,NAIL_BITS,	t0
+	ldq	ul0,	16(up)
+	mulq	vl0,	ul3,	m3a
+	addq	t0,	r31,	acc0
+	umulh	vl0,	ul3,	m3b
+	addq	rl0,	acc0,	acc0
+	ldq	rl1,	24(rp)
+	srl	m1a,NAIL_BITS,	t0
+	ldq	ul1,	24(up)
+	lda	up,	32(up)
+	lda	rp,	32(rp)
+	mulq	vl0,	ul0,	m0a
+	addq	t0,	m0b,	acc1
+	srl	acc0,NUMB_BITS,	t1
+	bge	n,	L(el2)
+
+	br	r31,	L(ta6)
+
+L(1m4):	lda	n,	-4(n)
+	ldq	ul1,	0(up)
+	lda	up,	8(up)
+	lda	rp,	-24(rp)
+	bge	n,	L(ge1)
+
+	mulq	vl0,	ul1,	m1a
+	umulh	vl0,	ul1,	m1b
+	ldq	rl1,	24(rp)
+	srl	m1a,NAIL_BITS,	t0
+	addq	rl1,	t0,	acc1
+	and	acc1,numb_mask,	r28
+	srl	acc1,NUMB_BITS,	t1
+	stq	r28,	24(rp)
+	addq	t1,	m1b,	r0
+	ret	r31,	(r26),	1
+
+L(ge1):	ldq	ul2,	0(up)
+	mulq	vl0,	ul1,	m1a
+	umulh	vl0,	ul1,	m1b
+	ldq	ul3,	8(up)
+	lda	n,	-4(n)
+	mulq	vl0,	ul2,	m2a
+	umulh	vl0,	ul2,	m2b
+	ldq	ul0,	16(up)
+	mulq	vl0,	ul3,	m3a
+	umulh	vl0,	ul3,	m3b
+	ldq	rl1,	24(rp)
+	srl	m1a,NAIL_BITS,	t0
+	ldq	ul1,	24(up)
+	lda	up,	32(up)
+	lda	rp,	32(rp)
+	mulq	vl0,	ul0,	m0a
+	addq	t0,	r31,	acc1
+	umulh	vl0,	ul0,	m0b
+	addq	rl1,	acc1,	acc1
+	ldq	rl2,	0(rp)
+	srl	m2a,NAIL_BITS,	t0
+	mulq	vl0,	ul1,	m1a
+	addq	t0,	m1b,	acc0
+	srl	acc1,NUMB_BITS,	t1
+	blt	n,	L(ta5)
+
+L(ge5):	ldq	ul2,	0(up)
+	br	r31,	L(el1)
+
+	ALIGN(16)
+L(top):	mulq	vl0,	ul0,	m0a		C U1
+	addq	t0,	m0b,	acc1		C L0
+	srl	acc0,NUMB_BITS,	t1		C U0
+	stq	r28,	-24(rp)			C L1
+C
+L(el2):	umulh	vl0,	ul0,	m0b		C U1
+	and	acc0,numb_mask,	r28		C L0
+	addq	rl1,	acc1,	acc1		C U0
+	ldq	rl2,	0(rp)			C L1
+C
+	unop					C U1
+	addq	t1,	acc1,	acc1		C L0
+	srl	m2a,NAIL_BITS,	t0		C U0
+	ldq	ul2,	0(up)			C L1
+C
+	mulq	vl0,	ul1,	m1a		C U1
+	addq	t0,	m1b,	acc0		C L0
+	srl	acc1,NUMB_BITS,	t1		C U0
+	stq	r28,	-16(rp)			C L1
+C
+L(el1):	umulh	vl0,	ul1,	m1b		C U1
+	and	acc1,numb_mask,	r28		C L0
+	addq	rl2,	acc0,	acc0		C U0
+	ldq	rl3,	8(rp)			C L1
+C
+	lda	n,	-4(n)			C L1
+	addq	t1,	acc0,	acc0		C L0
+	srl	m3a,NAIL_BITS,	t0		C U0
+	ldq	ul3,	8(up)			C L1
+C
+	mulq	vl0,	ul2,	m2a		C U1
+	addq	t0,	m2b,	acc1		C L0
+	srl	acc0,NUMB_BITS,	t1		C U0
+	stq	r28,	-8(rp)			C L1
+C
+L(el0):	umulh	vl0,	ul2,	m2b		C U1
+	and	acc0,numb_mask,	r28		C L0
+	addq	rl3,	acc1,	acc1		C U0
+	ldq	rl0,	16(rp)			C L1
+C
+	unop					C U1
+	addq	t1,	acc1,	acc1		C L0
+	srl	m0a,NAIL_BITS,	t0		C U0
+	ldq	ul0,	16(up)			C L1
+C
+	mulq	vl0,	ul3,	m3a		C U1
+	addq	t0,	m3b,	acc0		C L0
+	srl	acc1,NUMB_BITS,	t1		C U0
+	stq	r28,	0(rp)			C L1
+C
+L(el3):	umulh	vl0,	ul3,	m3b		C U1
+	and	acc1,numb_mask,	r28		C L0
+	addq	rl0,	acc0,	acc0		C U0
+	ldq	rl1,	24(rp)			C L1
+C
+	unop					C U1
+	addq	t1,	acc0,	acc0		C L0
+	srl	m1a,NAIL_BITS,	t0		C U0
+	ldq	ul1,	24(up)			C L1
+C
+	lda	up,	32(up)			C L0
+	unop					C U1
+	lda	rp,	32(rp)			C L1
+	bge	n,	L(top)			C U0
+
+L(end):	mulq	vl0,	ul0,	m0a
+	addq	t0,	m0b,	acc1
+	srl	acc0,NUMB_BITS,	t1
+	stq	r28,	-24(rp)
+L(ta6):	umulh	vl0,	ul0,	m0b
+	and	acc0,numb_mask,	r28
+	addq	rl1,	acc1,	acc1
+	ldq	rl2,	0(rp)
+	addq	t1,	acc1,	acc1
+	srl	m2a,NAIL_BITS,	t0
+	mulq	vl0,	ul1,	m1a
+	addq	t0,	m1b,	acc0
+	srl	acc1,NUMB_BITS,	t1
+	stq	r28,	-16(rp)
+L(ta5):	umulh	vl0,	ul1,	m1b
+	and	acc1,numb_mask,	r28
+	addq	rl2,	acc0,	acc0
+	ldq	rl3,	8(rp)
+	addq	t1,	acc0,	acc0
+	srl	m3a,NAIL_BITS,	t0
+	addq	t0,	m2b,	acc1
+	srl	acc0,NUMB_BITS,	t1
+	stq	r28,	-8(rp)
+	unop
+	ALIGN(16)
+L(ta4):	and	acc0,numb_mask,	r28
+	addq	rl3,	acc1,	acc1
+	ldq	rl0,	16(rp)
+	addq	t1,	acc1,	acc1
+	srl	m0a,NAIL_BITS,	t0
+	addq	t0,	m3b,	acc0
+	srl	acc1,NUMB_BITS,	t1
+	stq	r28,	0(rp)
+	unop
+	ALIGN(16)
+L(ta3):	and	acc1,numb_mask,	r28
+	addq	rl0,	acc0,	acc0
+	ldq	rl1,	24(rp)
+	addq	t1,	acc0,	acc0
+	srl	m1a,NAIL_BITS,	t0
+	addq	t0,	m0b,	acc1
+	srl	acc0,NUMB_BITS,	t1
+	stq	r28,	8(rp)
+	unop
+	ALIGN(16)
+L(ta2):	and	acc0,numb_mask,	r28
+	addq	rl1,	acc1,	acc1
+	addq	t1,	acc1,	acc1
+	srl	acc1,NUMB_BITS,	t1
+	stq	r28,	16(rp)
+	and	acc1,numb_mask,	r28
+	addq	t1,	m1b,	r0
+	stq	r28,	24(rp)
+	ret	r31,	(r26),	1
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/alpha/ev6/nails/addmul_2.asm b/third_party/gmp/mpn/alpha/ev6/nails/addmul_2.asm
new file mode 100644
index 0000000..6ff6b3a
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/ev6/nails/addmul_2.asm
@@ -0,0 +1,146 @@
+dnl  Alpha ev6 nails mpn_addmul_2.
+
+dnl  Copyright 2002, 2005, 2006 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C Runs at 4.0 cycles/limb.
+
+C We could either go for 2-way unrolling over 11 cycles, or 2.75 c/l,
+C or 4-way unrolling over 20 cycles, for 2.5 c/l.
+
+
+C  INPUT PARAMETERS
+define(`rp',`r16')
+define(`up',`r17')
+define(`n',`r18')
+define(`vp',`r19')
+
+C  Useful register aliases
+define(`numb_mask',`r24')
+define(`ulimb',`r25')
+define(`rlimb',`r27')
+
+define(`m0a',`r0')
+define(`m0b',`r1')
+define(`m1a',`r2')
+define(`m1b',`r3')
+
+define(`acc0',`r4')
+define(`acc1',`r5')
+
+define(`v0',`r6')
+define(`v1',`r7')
+
+C Used for temps: r8 r19 r28
+
+define(`NAIL_BITS',`GMP_NAIL_BITS')
+define(`NUMB_BITS',`GMP_NUMB_BITS')
+
+C  This declaration is munged by configure
+NAILS_SUPPORT(3-63)
+
+ASM_START()
+PROLOGUE(mpn_addmul_2)
+	lda	numb_mask,-1(r31)
+	srl	numb_mask,NAIL_BITS,numb_mask
+
+	ldq	v0,	0(vp)
+	ldq	v1,	8(vp)
+
+	bis	r31,	r31,	acc0		C	zero acc0
+	sll	v0,NAIL_BITS,	v0
+	bis	r31,	r31,	acc1		C	zero acc1
+	sll	v1,NAIL_BITS,	v1
+	bis	r31,	r31,	r19
+
+	ldq	ulimb,	0(up)
+	lda	up,	8(up)
+	mulq	v0,	ulimb,	m0a		C U1
+	umulh	v0,	ulimb,	m0b		C U1
+	mulq	v1,	ulimb,	m1a		C U1
+	umulh	v1,	ulimb,	m1b		C U1
+	lda	n,	-1(n)
+	beq	n,	L(end)			C U0
+
+	ALIGN(16)
+L(top):	bis	r31,	r31,	r31		C U1	nop
+	addq	r19,	acc0,	acc0		C U0	propagate nail
+	ldq	rlimb,	0(rp)			C L0
+	ldq	ulimb,	0(up)			C L1
+
+	lda	rp,	8(rp)			C L1
+	srl	m0a,NAIL_BITS,	r8		C U0
+	lda	up,	8(up)			C L0
+	mulq	v0,	ulimb,	m0a		C U1
+
+	addq	r8,	acc0,	r19		C U0
+	addq	m0b,	acc1,	acc0		C L1
+	umulh	v0,	ulimb,	m0b		C U1
+	bis	r31,	r31,	r31		C L0	nop
+
+	addq	rlimb,	r19,	r19		C L1	FINAL PROD-SUM
+	srl	m1a,NAIL_BITS,	r8		C U0
+	lda	n,	-1(n)			C L0
+	mulq	v1,	ulimb,	m1a		C U1
+
+	addq	r8,	acc0,	acc0		C U0
+	bis	r31,	m1b,	acc1		C L1
+	umulh	v1,	ulimb,	m1b		C U1
+	and	r19,numb_mask,	r28		C L0	extract numb part
+
+	unop
+	srl	r19,NUMB_BITS,	r19		C U1	extract nail part
+	stq	r28,	-8(rp)			C L1
+	bne	n,	L(top)			C U0
+
+L(end):	ldq	rlimb,	0(rp)
+	addq	r19,	acc0,	acc0		C	propagate nail
+	lda	rp,	8(rp)
+	srl	m0a,NAIL_BITS,	r8		C U0
+	addq	r8,	acc0,	r19
+	addq	m0b,	acc1,	acc0
+	addq	rlimb,	r19,	r19
+	srl	m1a,NAIL_BITS,	r8		C U0
+	addq	r8,	acc0,	acc0
+	bis	r31,	m1b,	acc1
+	and	r19,numb_mask,	r28		C extract limb
+
+	srl	r19,NUMB_BITS,	r19		C extract nail
+	stq	r28,	-8(rp)
+
+	addq	r19,	acc0,	acc0		C propagate nail
+	and	acc0,numb_mask,	r28
+	stq	r28,	0(rp)
+	srl	acc0,NUMB_BITS,	r19
+	addq	r19,	acc1,	r0
+
+	ret	r31,	(r26),	1
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/alpha/ev6/nails/addmul_3.asm b/third_party/gmp/mpn/alpha/ev6/nails/addmul_3.asm
new file mode 100644
index 0000000..a1ffb68
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/ev6/nails/addmul_3.asm
@@ -0,0 +1,169 @@
+dnl  Alpha ev6 nails mpn_addmul_3.
+
+dnl  Copyright 2002, 2006 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C Runs at 3.0 cycles/limb.
+
+C With 2-way unrolling, we could probably reach 2.25 c/l (3.33 i/c).
+
+
+C  INPUT PARAMETERS
+define(`rp',`r16')
+define(`up',`r17')
+define(`n',`r18')
+define(`vp',`r19')
+
+C  Useful register aliases
+define(`numb_mask',`r24')
+define(`ulimb',`r25')
+define(`rlimb',`r27')
+
+define(`m0a',`r0')
+define(`m0b',`r1')
+define(`m1a',`r2')
+define(`m1b',`r3')
+define(`m2a',`r20')
+define(`m2b',`r21')
+
+define(`acc0',`r4')
+define(`acc1',`r5')
+define(`acc2',`r22')
+
+define(`v0',`r6')
+define(`v1',`r7')
+define(`v2',`r23')
+
+C Used for temps: r8 r19 r28
+
+define(`NAIL_BITS',`GMP_NAIL_BITS')
+define(`NUMB_BITS',`GMP_NUMB_BITS')
+
+C  This declaration is munged by configure
+NAILS_SUPPORT(3-63)
+
+ASM_START()
+PROLOGUE(mpn_addmul_3)
+	lda	numb_mask,-1(r31)
+	srl	numb_mask,NAIL_BITS,numb_mask
+
+	ldq	v0,	0(vp)
+	ldq	v1,	8(vp)
+	ldq	v2,	16(vp)
+
+	bis	r31,	r31,	acc0		C	zero acc0
+	sll	v0,NAIL_BITS,	v0
+	bis	r31,	r31,	acc1		C	zero acc1
+	sll	v1,NAIL_BITS,	v1
+	bis	r31,	r31,	acc2		C	zero acc2
+	sll	v2,NAIL_BITS,	v2
+	bis	r31,	r31,	r19
+
+	ldq	ulimb,	0(up)
+	lda	up,	8(up)
+	mulq	v0,	ulimb,	m0a		C U1
+	umulh	v0,	ulimb,	m0b		C U1
+	mulq	v1,	ulimb,	m1a		C U1
+	umulh	v1,	ulimb,	m1b		C U1
+	lda	n,	-1(n)
+	mulq	v2,	ulimb,	m2a		C U1
+	umulh	v2,	ulimb,	m2b		C U1
+	beq	n,	L(end)			C U0
+
+	ALIGN(16)
+L(top):	ldq	rlimb,	0(rp)			C L1
+	ldq	ulimb,	0(up)			C L0
+	bis	r31,	r31,	r31		C U0	nop
+	addq	r19,	acc0,	acc0		C U1	propagate nail
+
+	lda	rp,	8(rp)			C L1
+	srl	m0a,NAIL_BITS,	r8		C U0
+	lda	up,	8(up)			C L0
+	mulq	v0,	ulimb,	m0a		C U1
+
+	addq	r8,	acc0,	r19		C U0
+	addq	m0b,	acc1,	acc0		C L1
+	umulh	v0,	ulimb,	m0b		C U1
+	bis	r31,	r31,	r31		C L0	nop
+
+	addq	rlimb,	r19,	r19		C L1
+	srl	m1a,NAIL_BITS,	r8		C U0
+	bis	r31,	r31,	r31		C L0	nop
+	mulq	v1,	ulimb,	m1a		C U1
+
+	addq	r8,	acc0,	acc0		C U0
+	addq	m1b,	acc2,	acc1		C L1
+	umulh	v1,	ulimb,	m1b		C U1
+	and	r19,numb_mask,	r28		C L0	extract numb part
+
+	bis	r31,	r31,	r31		C L1	nop
+	srl	m2a,NAIL_BITS,	r8		C U0
+	lda	n,	-1(n)			C L0
+	mulq	v2,	ulimb,	m2a		C U1
+
+	addq	r8,	acc1,	acc1		C L0
+	bis	r31,	m2b,	acc2		C L1
+	umulh	v2,	ulimb,	m2b		C U1
+	srl	r19,NUMB_BITS,	r19		C U0	extract nail part
+
+	stq	r28,	-8(rp)			C L
+	bne	n,	L(top)			C U0
+
+L(end):	ldq	rlimb,	0(rp)
+	addq	r19,	acc0,	acc0		C	propagate nail
+	lda	rp,	8(rp)
+	srl	m0a,NAIL_BITS,	r8		C U0
+	addq	r8,	acc0,	r19
+	addq	m0b,	acc1,	acc0
+	addq	rlimb,	r19,	r19
+	srl	m1a,NAIL_BITS,	r8		C U0
+	addq	r8,	acc0,	acc0
+	addq	m1b,	acc2,	acc1
+	and	r19,numb_mask,	r28		C extract limb
+	srl	m2a,NAIL_BITS,	r8		C U0
+	addq	r8,	acc1,	acc1
+	bis	r31,	m2b,	acc2
+	srl	r19,NUMB_BITS,	r19		C extract nail
+	stq	r28,	-8(rp)
+
+	addq	r19,	acc0,	acc0		C propagate nail
+	and	acc0,numb_mask,	r28
+	stq	r28,	0(rp)
+	srl	acc0,NUMB_BITS,	r19
+	addq	r19,	acc1,	acc1
+
+	and	acc1,numb_mask,	r28
+	stq	r28,	8(rp)
+	srl	acc1,NUMB_BITS,	r19
+	addq	r19,	acc2,	m0a
+
+	ret	r31,	(r26),	1
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/alpha/ev6/nails/addmul_4.asm b/third_party/gmp/mpn/alpha/ev6/nails/addmul_4.asm
new file mode 100644
index 0000000..77e02a4
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/ev6/nails/addmul_4.asm
@@ -0,0 +1,210 @@
+dnl  Alpha ev6 nails mpn_addmul_4.
+
+dnl  Copyright 2002, 2005, 2006 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C Runs at 2.5 cycles/limb.
+
+C We should go for 2-way unrolling over 17 cycles, for 2.125 c/l corresponding
+C to 3.24 insn/cycle.
+
+
+C  INPUT PARAMETERS
+define(`rp',`r16')
+define(`up',`r17')
+define(`n',`r18')
+define(`vp',`r19')
+
+C  Useful register aliases
+define(`numb_mask',`r24')
+define(`ulimb',`r25')
+define(`rlimb',`r27')
+
+define(`m0a',`r0')
+define(`m0b',`r1')
+define(`m1a',`r2')
+define(`m1b',`r3')
+define(`m2a',`r20')
+define(`m2b',`r21')
+define(`m3a',`r12')
+define(`m3b',`r13')
+
+define(`acc0',`r4')
+define(`acc1',`r5')
+define(`acc2',`r22')
+define(`acc3',`r14')
+
+define(`v0',`r6')
+define(`v1',`r7')
+define(`v2',`r23')
+define(`v3',`r15')
+
+C Used for temps: r8 r19 r28
+
+define(`NAIL_BITS',`GMP_NAIL_BITS')
+define(`NUMB_BITS',`GMP_NUMB_BITS')
+
+C  This declaration is munged by configure
+NAILS_SUPPORT(4-63)
+
+ASM_START()
+PROLOGUE(mpn_addmul_4)
+	lda	r30,	-240(r30)
+	stq	r12,	32(r30)
+	stq	r13,	40(r30)
+	stq	r14,	48(r30)
+	stq	r15,	56(r30)
+
+	lda	numb_mask,-1(r31)
+	srl	numb_mask,NAIL_BITS,numb_mask
+
+	ldq	v0,	0(vp)
+	ldq	v1,	8(vp)
+	ldq	v2,	16(vp)
+	ldq	v3,	24(vp)
+
+	bis	r31,	r31,	acc0		C	zero acc0
+	sll	v0,NAIL_BITS,	v0
+	bis	r31,	r31,	acc1		C	zero acc1
+	sll	v1,NAIL_BITS,	v1
+	bis	r31,	r31,	acc2		C	zero acc2
+	sll	v2,NAIL_BITS,	v2
+	bis	r31,	r31,	acc3		C	zero acc3
+	sll	v3,NAIL_BITS,	v3
+	bis	r31,	r31,	r19
+
+	ldq	ulimb,	0(up)
+	lda	up,	8(up)
+	mulq	v0,	ulimb,	m0a		C U1
+	umulh	v0,	ulimb,	m0b		C U1
+	mulq	v1,	ulimb,	m1a		C U1
+	umulh	v1,	ulimb,	m1b		C U1
+	lda	n,	-1(n)
+	mulq	v2,	ulimb,	m2a		C U1
+	umulh	v2,	ulimb,	m2b		C U1
+	mulq	v3,	ulimb,	m3a		C U1
+	umulh	v3,	ulimb,	m3b		C U1
+	beq	n,	L(end)			C U0
+
+	ALIGN(16)
+L(top):	bis	r31,	r31,	r31		C U1	nop
+	ldq	rlimb,	0(rp)			C L0
+	ldq	ulimb,	0(up)			C L1
+	addq	r19,	acc0,	acc0		C U0	propagate nail
+
+	bis	r31,	r31,	r31		C L0	nop
+	bis	r31,	r31,	r31		C U1	nop
+	bis	r31,	r31,	r31		C L1	nop
+	bis	r31,	r31,	r31		C U0	nop
+
+	lda	rp,	8(rp)			C L0
+	srl	m0a,NAIL_BITS,	r8		C U0
+	lda	up,	8(up)			C L1
+	mulq	v0,	ulimb,	m0a		C U1
+
+	addq	r8,	acc0,	r19		C U0
+	addq	m0b,	acc1,	acc0		C L0
+	umulh	v0,	ulimb,	m0b		C U1
+	bis	r31,	r31,	r31		C L1	nop
+
+	addq	rlimb,	r19,	r19		C L0
+	srl	m1a,NAIL_BITS,	r8		C U0
+	bis	r31,	r31,	r31		C L1	nop
+	mulq	v1,	ulimb,	m1a		C U1
+
+	addq	r8,	acc0,	acc0		C U0
+	addq	m1b,	acc2,	acc1		C L0
+	umulh	v1,	ulimb,	m1b		C U1
+	and	r19,numb_mask,	r28		C L1	extract numb part
+
+	bis	r31,	r31,	r31		C L0	nop
+	srl	m2a,NAIL_BITS,	r8		C U0
+	lda	n,	-1(n)			C L1
+	mulq	v2,	ulimb,	m2a		C U1
+
+	addq	r8,	acc1,	acc1		C L1
+	addq	m2b,	acc3,	acc2		C L0
+	umulh	v2,	ulimb,	m2b		C U1
+	srl	r19,NUMB_BITS,	r19		C U0	extract nail part
+
+	bis	r31,	r31,	r31		C L0	nop
+	srl	m3a,NAIL_BITS,	r8		C U0
+	stq	r28,	-8(rp)			C L1
+	mulq	v3,	ulimb,	m3a		C U1
+
+	addq	r8,	acc2,	acc2		C L0
+	bis	r31,	m3b,	acc3		C L1
+	umulh	v3,	ulimb,	m3b		C U1
+	bne	n,	L(top)			C U0
+
+L(end):	ldq	rlimb,	0(rp)
+	addq	r19,	acc0,	acc0		C	propagate nail
+	lda	rp,	8(rp)			C FIXME: DELETE
+	srl	m0a,NAIL_BITS,	r8		C U0
+	addq	r8,	acc0,	r19
+	addq	m0b,	acc1,	acc0
+	addq	rlimb,	r19,	r19
+	srl	m1a,NAIL_BITS,	r8		C U0
+	addq	r8,	acc0,	acc0
+	addq	m1b,	acc2,	acc1
+	and	r19,numb_mask,	r28		C extract limb
+	srl	m2a,NAIL_BITS,	r8		C U0
+	addq	r8,	acc1,	acc1
+	addq	m2b,	acc3,	acc2
+	srl	r19,NUMB_BITS,	r19		C extract nail
+	srl	m3a,NAIL_BITS,	r8		C U0
+	stq	r28,	-8(rp)
+	addq	r8,	acc2,	acc2
+	bis	r31,	m3b,	acc3
+
+	addq	r19,	acc0,	acc0		C propagate nail
+	and	acc0,numb_mask,	r28
+	stq	r28,	0(rp)
+	srl	acc0,NUMB_BITS,	r19
+	addq	r19,	acc1,	acc1
+
+	and	acc1,numb_mask,	r28
+	stq	r28,	8(rp)
+	srl	acc1,NUMB_BITS,	r19
+	addq	r19,	acc2,	acc2
+
+	and	acc2,numb_mask,	r28
+	stq	r28,	16(rp)
+	srl	acc2,NUMB_BITS,	r19
+	addq	r19,	acc3,	r0
+
+	ldq	r12,	32(r30)
+	ldq	r13,	40(r30)
+	ldq	r14,	48(r30)
+	ldq	r15,	56(r30)
+	lda	r30,	240(r30)
+	ret	r31,	(r26),	1
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/alpha/ev6/nails/aors_n.asm b/third_party/gmp/mpn/alpha/ev6/nails/aors_n.asm
new file mode 100644
index 0000000..f658677
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/ev6/nails/aors_n.asm
@@ -0,0 +1,233 @@
+dnl  Alpha ev6 nails mpn_add_n and mpn_sub_n.
+
+dnl  Copyright 2002, 2006 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+dnl  Runs at 2.5 cycles/limb.  It would be possible to reach 2.0 cycles/limb
+dnl  with 8-way unrolling.
+
+include(`../config.m4')
+
+dnl  INPUT PARAMETERS
+define(`rp',`r16')
+define(`up',`r17')
+define(`vp',`r18')
+define(`n',`r19')
+
+define(`rl0',`r0')
+define(`rl1',`r1')
+define(`rl2',`r2')
+define(`rl3',`r3')
+
+define(`ul0',`r4')
+define(`ul1',`r5')
+define(`ul2',`r6')
+define(`ul3',`r7')
+
+define(`vl0',`r22')
+define(`vl1',`r23')
+define(`vl2',`r24')
+define(`vl3',`r25')
+
+define(`numb_mask',`r21')
+
+define(`NAIL_BITS',`GMP_NAIL_BITS')
+define(`CYSH',`GMP_NUMB_BITS')
+
+dnl  This declaration is munged by configure
+NAILS_SUPPORT(1-63)
+
+ifdef(`OPERATION_add_n', `
+	define(`OP',        addq)
+	define(`CYSH',`GMP_NUMB_BITS')
+	define(`func',  mpn_add_n)')
+ifdef(`OPERATION_sub_n', `
+	define(`OP',        subq)
+	define(`CYSH',63)
+	define(`func',  mpn_sub_n)')
+
+MULFUNC_PROLOGUE(mpn_add_n mpn_sub_n)
+
+ASM_START()
+PROLOGUE(func)
+	lda	numb_mask, -1(r31)
+	srl	numb_mask, NAIL_BITS, numb_mask
+	bis	r31,	r31,	r20
+
+	and	n,	3,	r25
+	lda	n,	-4(n)
+	beq	r25,	L(ge4)
+
+L(lp0):	ldq	ul0,	0(up)
+	lda	up,	8(up)
+	ldq	vl0,	0(vp)
+	lda	vp,	8(vp)
+	lda	rp,	8(rp)
+	lda	r25,	-1(r25)
+	OP	ul0,	vl0,	rl0
+	OP	rl0,	r20,	rl0
+	and	rl0, numb_mask,	r28
+	stq	r28,	-8(rp)
+	srl	rl0,	CYSH,	r20
+	bne	r25,	L(lp0)
+
+	blt	n,	L(ret)
+
+L(ge4):	ldq	ul0,	0(up)
+	ldq	vl0,	0(vp)
+	ldq	ul1,	8(up)
+	ldq	vl1,	8(vp)
+	ldq	ul2,	16(up)
+	ldq	vl2,	16(vp)
+	ldq	ul3,	24(up)
+	ldq	vl3,	24(vp)
+	lda	up,	32(up)
+	lda	vp,	32(vp)
+	lda	n,	-4(n)
+	bge	n,	L(ge8)
+
+	OP	ul0,	vl0,	rl0	C		main-add 0
+	OP	rl0,	r20,	rl0	C		cy-add 0
+	OP	ul1,	vl1,	rl1	C		main-add 1
+	srl	rl0,	CYSH,	r20	C		gen cy 0
+	OP	rl1,	r20,	rl1	C		cy-add 1
+	and	rl0,numb_mask,	r27
+	br	r31,	L(cj0)
+
+L(ge8):	OP	ul0,	vl0,	rl0	C		main-add 0
+	ldq	ul0,	0(up)
+	ldq	vl0,	0(vp)
+	OP	rl0,	r20,	rl0	C		cy-add 0
+	OP	ul1,	vl1,	rl1	C		main-add 1
+	srl	rl0,	CYSH,	r20	C		gen cy 0
+	ldq	ul1,	8(up)
+	ldq	vl1,	8(vp)
+	OP	rl1,	r20,	rl1	C		cy-add 1
+	and	rl0,numb_mask,	r27
+	OP	ul2,	vl2,	rl2	C		main-add 2
+	srl	rl1,	CYSH,	r20	C		gen cy 1
+	ldq	ul2,	16(up)
+	ldq	vl2,	16(vp)
+	OP	rl2,	r20,	rl2	C		cy-add 2
+	and	rl1,numb_mask,	r28
+	stq	r27,	0(rp)
+	OP	ul3,	vl3,	rl3	C		main-add 3
+	srl	rl2,	CYSH,	r20	C		gen cy 2
+	ldq	ul3,	24(up)
+	ldq	vl3,	24(vp)
+	OP	rl3,	r20,	rl3	C		cy-add 3
+	and	rl2,numb_mask,	r27
+	stq	r28,	8(rp)
+	lda	rp,	32(rp)
+	lda	up,	32(up)
+	lda	vp,	32(vp)
+	lda	n,	-4(n)
+	blt	n,	L(end)
+
+	ALIGN(32)
+L(top):	OP	ul0,	vl0,	rl0	C		main-add 0
+	srl	rl3,	CYSH,	r20	C		gen cy 3
+	ldq	ul0,	0(up)
+	ldq	vl0,	0(vp)
+
+	OP	rl0,	r20,	rl0	C		cy-add 0
+	and	rl3,numb_mask,	r28
+	stq	r27,	-16(rp)
+	bis	r31,	r31,	r31
+
+	OP	ul1,	vl1,	rl1	C		main-add 1
+	srl	rl0,	CYSH,	r20	C		gen cy 0
+	ldq	ul1,	8(up)
+	ldq	vl1,	8(vp)
+
+	OP	rl1,	r20,	rl1	C		cy-add 1
+	and	rl0,numb_mask,	r27
+	stq	r28,	-8(rp)
+	bis	r31,	r31,	r31
+
+	OP	ul2,	vl2,	rl2	C		main-add 2
+	srl	rl1,	CYSH,	r20	C		gen cy 1
+	ldq	ul2,	16(up)
+	ldq	vl2,	16(vp)
+
+	OP	rl2,	r20,	rl2	C		cy-add 2
+	and	rl1,numb_mask,	r28
+	stq	r27,	0(rp)
+	bis	r31,	r31,	r31
+
+	OP	ul3,	vl3,	rl3	C		main-add 3
+	srl	rl2,	CYSH,	r20	C		gen cy 2
+	ldq	ul3,	24(up)
+	ldq	vl3,	24(vp)
+
+	OP	rl3,	r20,	rl3	C		cy-add 3
+	and	rl2,numb_mask,	r27
+	stq	r28,	8(rp)
+	bis	r31,	r31,	r31
+
+	bis	r31,	r31,	r31
+	lda	n,	-4(n)
+	lda	up,	32(up)
+	lda	vp,	32(vp)
+
+	bis	r31,	r31,	r31
+	bis	r31,	r31,	r31
+	lda	rp,	32(rp)
+	bge	n,	L(top)
+
+L(end):	OP	ul0,	vl0,	rl0	C		main-add 0
+	srl	rl3,	CYSH,	r20	C		gen cy 3
+	OP	rl0,	r20,	rl0	C		cy-add 0
+	and	rl3,numb_mask,	r28
+	stq	r27,	-16(rp)
+	OP	ul1,	vl1,	rl1	C		main-add 1
+	srl	rl0,	CYSH,	r20	C		gen cy 0
+	OP	rl1,	r20,	rl1	C		cy-add 1
+	and	rl0,numb_mask,	r27
+	stq	r28,	-8(rp)
+L(cj0):	OP	ul2,	vl2,	rl2	C		main-add 2
+	srl	rl1,	CYSH,	r20	C		gen cy 1
+	OP	rl2,	r20,	rl2	C		cy-add 2
+	and	rl1,numb_mask,	r28
+	stq	r27,	0(rp)
+	OP	ul3,	vl3,	rl3	C		main-add 3
+	srl	rl2,	CYSH,	r20	C		gen cy 2
+	OP	rl3,	r20,	rl3	C		cy-add 3
+	and	rl2,numb_mask,	r27
+	stq	r28,	8(rp)
+
+	srl	rl3,	CYSH,	r20	C		gen cy 3
+	and	rl3,numb_mask,	r28
+	stq	r27,	16(rp)
+	stq	r28,	24(rp)
+
+L(ret):	and	r20,	1,	r0
+	ret	r31,	(r26),	1
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/alpha/ev6/nails/gmp-mparam.h b/third_party/gmp/mpn/alpha/ev6/nails/gmp-mparam.h
new file mode 100644
index 0000000..7949fe8
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/ev6/nails/gmp-mparam.h
@@ -0,0 +1,72 @@
+/* gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 1999-2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+/* Generated by tuneup.c, 2004-02-07, gcc 3.3 */
+
+#define MUL_TOOM22_THRESHOLD             40
+#define MUL_TOOM33_THRESHOLD            236
+
+#define SQR_BASECASE_THRESHOLD            7  /* karatsuba */
+#define SQR_TOOM2_THRESHOLD               0  /* never sqr_basecase */
+#define SQR_TOOM3_THRESHOLD             120
+
+#define DIV_SB_PREINV_THRESHOLD       MP_SIZE_T_MAX  /* no preinv with nails */
+#define DIV_DC_THRESHOLD                 48
+#define POWM_THRESHOLD                  113
+
+#define HGCD_THRESHOLD                   78
+#define GCD_ACCEL_THRESHOLD               3
+#define GCD_DC_THRESHOLD                392
+#define JACOBI_BASE_METHOD                1
+
+#define DIVREM_1_NORM_THRESHOLD       MP_SIZE_T_MAX  /* no preinv with nails */
+#define DIVREM_1_UNNORM_THRESHOLD     MP_SIZE_T_MAX  /* no preinv with nails */
+#define MOD_1_NORM_THRESHOLD          MP_SIZE_T_MAX  /* no preinv with nails */
+#define MOD_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* no preinv with nails */
+#define USE_PREINV_DIVREM_1               0  /* no preinv with nails */
+#define USE_PREINV_MOD_1                  0  /* no preinv with nails */
+#define DIVREM_2_THRESHOLD            MP_SIZE_T_MAX  /* no preinv with nails */
+#define DIVEXACT_1_THRESHOLD              0  /* always */
+#define MODEXACT_1_ODD_THRESHOLD          0  /* always */
+
+#define GET_STR_DC_THRESHOLD             15
+#define GET_STR_PRECOMPUTE_THRESHOLD     24
+#define SET_STR_THRESHOLD              6336
+
+#define MUL_FFT_TABLE  { 688, 1440, 3648, 6400, 25600, 0 }
+#define MUL_FFT_MODF_THRESHOLD          488
+#define MUL_FFT_THRESHOLD              3712
+
+#define SQR_FFT_TABLE  { 432, 864, 3136, 6400, 25600, 0 }
+#define SQR_FFT_MODF_THRESHOLD          480
+#define SQR_FFT_THRESHOLD              2976
diff --git a/third_party/gmp/mpn/alpha/ev6/nails/mul_1.asm b/third_party/gmp/mpn/alpha/ev6/nails/mul_1.asm
new file mode 100644
index 0000000..da2ee3d
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/ev6/nails/mul_1.asm
@@ -0,0 +1,364 @@
+dnl  Alpha ev6 nails mpn_mul_1.
+
+dnl  Copyright 2002, 2005, 2006 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C      cycles/limb
+C EV4:    42
+C EV5:    18
+C EV6:     3.25
+
+C TODO
+C  * Reroll loop for 3.0 c/l with current 4-way unrolling.
+C  * The loop is overscheduled wrt loads and wrt multiplies, in particular
+C    umulh.
+C  * Use FP loop count and multiple exit points, that would simplify feed-in lp0
+C    and would work since the loop structure is really regular.
+
+C  INPUT PARAMETERS
+define(`rp',`r16')
+define(`up',`r17')
+define(`n', `r18')
+define(`vl0',`r19')
+
+define(`numb_mask',`r6')
+
+define(`m0a',`r0')
+define(`m0b',`r1')
+define(`m1a',`r2')
+define(`m1b',`r3')
+define(`m2a',`r20')
+define(`m2b',`r21')
+define(`m3a',`r22')
+define(`m3b',`r23')
+
+define(`acc0',`r25')
+define(`acc1',`r27')
+
+define(`ul0',`r4')
+define(`ul1',`r5')
+define(`ul2',`r4')
+define(`ul3',`r5')
+
+define(`rl0',`r24')
+define(`rl1',`r24')
+define(`rl2',`r24')
+define(`rl3',`r24')
+
+define(`t0',`r7')
+define(`t1',`r8')
+
+define(`NAIL_BITS',`GMP_NAIL_BITS')
+define(`NUMB_BITS',`GMP_NUMB_BITS')
+
+dnl  This declaration is munged by configure
+NAILS_SUPPORT(1-63)
+
+ASM_START()
+PROLOGUE(mpn_mul_1)
+	sll	vl0, NAIL_BITS, vl0
+	lda	numb_mask, -1(r31)
+	srl	numb_mask, NAIL_BITS, numb_mask
+
+	and	n,	3,	r25
+	cmpeq	r25,	1,	r21
+	bne	r21,	L(1m4)
+	cmpeq	r25,	2,	r21
+	bne	r21,	L(2m4)
+	beq	r25,	L(0m4)
+
+L(3m4):	ldq	ul3,	0(up)
+	lda	n,	-4(n)
+	ldq	ul0,	8(up)
+	mulq	vl0,	ul3,	m3a
+	umulh	vl0,	ul3,	m3b
+	ldq	ul1,	16(up)
+	lda	up,	24(up)
+	lda	rp,	-8(rp)
+	mulq	vl0,	ul0,	m0a
+	umulh	vl0,	ul0,	m0b
+	bge	n,	L(ge3)
+
+	mulq	vl0,	ul1,	m1a
+	umulh	vl0,	ul1,	m1b
+	srl	m3a,NAIL_BITS,	t0
+	addq	t0,	r31,	acc1
+	srl	m0a,NAIL_BITS,	t0
+	addq	t0,	m3b,	acc0
+	srl	acc1,NUMB_BITS,	t1
+	br	r31,	L(ta3)
+
+L(ge3):	ldq	ul2,	0(up)
+	mulq	vl0,	ul1,	m1a
+	umulh	vl0,	ul1,	m1b
+	srl	m3a,NAIL_BITS,	t0
+	ldq	ul3,	8(up)
+	lda	n,	-4(n)
+	mulq	vl0,	ul2,	m2a
+	addq	t0,	r31,	acc1
+	umulh	vl0,	ul2,	m2b
+	srl	m0a,NAIL_BITS,	t0
+	ldq	ul0,	16(up)
+	mulq	vl0,	ul3,	m3a
+	addq	t0,	m3b,	acc0
+	srl	acc1,NUMB_BITS,	t1
+	br	r31,	L(el3)
+
+L(0m4):	lda	n,	-8(n)
+	ldq	ul2,	0(up)
+	ldq	ul3,	8(up)
+	mulq	vl0,	ul2,	m2a
+	umulh	vl0,	ul2,	m2b
+	ldq	ul0,	16(up)
+	mulq	vl0,	ul3,	m3a
+	umulh	vl0,	ul3,	m3b
+	ldq	ul1,	24(up)
+	lda	up,	32(up)
+	mulq	vl0,	ul0,	m0a
+	umulh	vl0,	ul0,	m0b
+	bge	n,	L(ge4)
+
+	srl	m2a,NAIL_BITS,	t0
+	mulq	vl0,	ul1,	m1a
+	addq	t0,	r31,	acc0
+	umulh	vl0,	ul1,	m1b
+	srl	m3a,NAIL_BITS,	t0
+	addq	t0,	m2b,	acc1
+	srl	acc0,NUMB_BITS,	t1
+	br	r31,	L(ta4)
+
+L(ge4):	srl	m2a,NAIL_BITS,	t0
+	ldq	ul2,	0(up)
+	mulq	vl0,	ul1,	m1a
+	addq	t0,	r31,	acc0
+	umulh	vl0,	ul1,	m1b
+	srl	m3a,NAIL_BITS,	t0
+	ldq	ul3,	8(up)
+	lda	n,	-4(n)
+	mulq	vl0,	ul2,	m2a
+	addq	t0,	m2b,	acc1
+	srl	acc0,NUMB_BITS,	t1
+	br	r31,	L(el0)
+
+L(2m4):	lda	n,	-4(n)
+	ldq	ul0,	0(up)
+	ldq	ul1,	8(up)
+	lda	up,	16(up)
+	lda	rp,	-16(rp)
+	mulq	vl0,	ul0,	m0a
+	umulh	vl0,	ul0,	m0b
+	bge	n,	L(ge2)
+
+	mulq	vl0,	ul1,	m1a
+	umulh	vl0,	ul1,	m1b
+	srl	m0a,NAIL_BITS,	t0
+	addq	t0,	r31,	acc0
+	srl	m1a,NAIL_BITS,	t0
+	addq	t0,	m0b,	acc1
+	srl	acc0,NUMB_BITS,	t1
+	br	r31,	L(ta2)
+
+L(ge2):	ldq	ul2,	0(up)
+	mulq	vl0,	ul1,	m1a
+	umulh	vl0,	ul1,	m1b
+	ldq	ul3,	8(up)
+	lda	n,	-4(n)
+	mulq	vl0,	ul2,	m2a
+	umulh	vl0,	ul2,	m2b
+	srl	m0a,NAIL_BITS,	t0
+	ldq	ul0,	16(up)
+	mulq	vl0,	ul3,	m3a
+	addq	t0,	r31,	acc0
+	umulh	vl0,	ul3,	m3b
+	srl	m1a,NAIL_BITS,	t0
+	ldq	ul1,	24(up)
+	lda	up,	32(up)
+	lda	rp,	32(rp)
+	mulq	vl0,	ul0,	m0a
+	addq	t0,	m0b,	acc1
+	srl	acc0,NUMB_BITS,	t1
+	bge	n,	L(el2)
+
+	br	r31,	L(ta6)
+
+L(1m4):	lda	n,	-4(n)
+	ldq	ul1,	0(up)
+	lda	up,	8(up)
+	lda	rp,	-24(rp)
+	bge	n,	L(ge1)
+
+	mulq	vl0,	ul1,	m1a
+	umulh	vl0,	ul1,	m1b
+	srl	m1a,NAIL_BITS,	t0
+	addq	t0,	r31,	acc1
+	and	acc1,numb_mask,	r28
+	srl	acc1,NUMB_BITS,	t1
+	stq	r28,	24(rp)
+	addq	t1,	m1b,	r0
+	ret	r31,	(r26),	1
+
+L(ge1):	ldq	ul2,	0(up)
+	mulq	vl0,	ul1,	m1a
+	umulh	vl0,	ul1,	m1b
+	ldq	ul3,	8(up)
+	lda	n,	-4(n)
+	mulq	vl0,	ul2,	m2a
+	umulh	vl0,	ul2,	m2b
+	ldq	ul0,	16(up)
+	mulq	vl0,	ul3,	m3a
+	umulh	vl0,	ul3,	m3b
+	srl	m1a,NAIL_BITS,	t0
+	ldq	ul1,	24(up)
+	lda	up,	32(up)
+	lda	rp,	32(rp)
+	mulq	vl0,	ul0,	m0a
+	addq	t0,	r31,	acc1
+	umulh	vl0,	ul0,	m0b
+	srl	m2a,NAIL_BITS,	t0
+	mulq	vl0,	ul1,	m1a
+	addq	t0,	m1b,	acc0
+	srl	acc1,NUMB_BITS,	t1
+	blt	n,	L(ta5)
+
+L(ge5):	ldq	ul2,	0(up)
+	br	r31,	L(el1)
+
+	ALIGN(16)
+L(top):	mulq	vl0,	ul0,	m0a		C U1
+	addq	t0,	m0b,	acc1		C L0
+	srl	acc0,NUMB_BITS,	t1		C U0
+	stq	r28,	-24(rp)			C L1
+C
+L(el2):	umulh	vl0,	ul0,	m0b		C U1
+	and	acc0,numb_mask,	r28		C L0
+	unop					C U0
+	unop					C L1
+C
+	unop					C U1
+	addq	t1,	acc1,	acc1		C L0
+	srl	m2a,NAIL_BITS,	t0		C U0
+	ldq	ul2,	0(up)			C L1
+C
+	mulq	vl0,	ul1,	m1a		C U1
+	addq	t0,	m1b,	acc0		C L0
+	srl	acc1,NUMB_BITS,	t1		C U0
+	stq	r28,	-16(rp)			C L1
+C
+L(el1):	umulh	vl0,	ul1,	m1b		C U1
+	and	acc1,numb_mask,	r28		C L0
+	unop					C U0
+	lda	n,	-4(n)			C L1
+C
+	unop					C U1
+	addq	t1,	acc0,	acc0		C L0
+	srl	m3a,NAIL_BITS,	t0		C U0
+	ldq	ul3,	8(up)			C L1
+C
+	mulq	vl0,	ul2,	m2a		C U1
+	addq	t0,	m2b,	acc1		C L0
+	srl	acc0,NUMB_BITS,	t1		C U0
+	stq	r28,	-8(rp)			C L1
+C
+L(el0):	umulh	vl0,	ul2,	m2b		C U1
+	and	acc0,numb_mask,	r28		C L0
+	unop					C U0
+	unop					C L1
+C
+	unop					C U1
+	addq	t1,	acc1,	acc1		C L0
+	srl	m0a,NAIL_BITS,	t0		C U0
+	ldq	ul0,	16(up)			C L1
+C
+	mulq	vl0,	ul3,	m3a		C U1
+	addq	t0,	m3b,	acc0		C L0
+	srl	acc1,NUMB_BITS,	t1		C U0
+	stq	r28,	0(rp)			C L1
+C
+L(el3):	umulh	vl0,	ul3,	m3b		C U1
+	and	acc1,numb_mask,	r28		C L0
+	unop					C U0
+	unop					C L1
+C
+	unop					C U1
+	addq	t1,	acc0,	acc0		C L0
+	srl	m1a,NAIL_BITS,	t0		C U0
+	ldq	ul1,	24(up)			C L1
+C
+	lda	up,	32(up)			C L0
+	unop					C U1
+	lda	rp,	32(rp)			C L1
+	bge	n,	L(top)			C U0
+
+L(end):	mulq	vl0,	ul0,	m0a
+	addq	t0,	m0b,	acc1
+	srl	acc0,NUMB_BITS,	t1
+	stq	r28,	-24(rp)
+L(ta6):	umulh	vl0,	ul0,	m0b
+	and	acc0,numb_mask,	r28
+	addq	t1,	acc1,	acc1
+	srl	m2a,NAIL_BITS,	t0
+	mulq	vl0,	ul1,	m1a
+	addq	t0,	m1b,	acc0
+	srl	acc1,NUMB_BITS,	t1
+	stq	r28,	-16(rp)
+L(ta5):	umulh	vl0,	ul1,	m1b
+	and	acc1,numb_mask,	r28
+	addq	t1,	acc0,	acc0
+	srl	m3a,NAIL_BITS,	t0
+	addq	t0,	m2b,	acc1
+	srl	acc0,NUMB_BITS,	t1
+	stq	r28,	-8(rp)
+	ALIGN(16)
+L(ta4):	and	acc0,numb_mask,	r28
+	addq	t1,	acc1,	acc1
+	srl	m0a,NAIL_BITS,	t0
+	addq	t0,	m3b,	acc0
+	srl	acc1,NUMB_BITS,	t1
+	stq	r28,	0(rp)
+	unop
+	ALIGN(16)
+L(ta3):	and	acc1,numb_mask,	r28
+	addq	t1,	acc0,	acc0
+	srl	m1a,NAIL_BITS,	t0
+	addq	t0,	m0b,	acc1
+	srl	acc0,NUMB_BITS,	t1
+	stq	r28,	8(rp)
+	unop
+	ALIGN(16)
+L(ta2):	and	acc0,numb_mask,	r28
+	addq	t1,	acc1,	acc1
+	srl	acc1,NUMB_BITS,	t1
+	stq	r28,	16(rp)
+	and	acc1,numb_mask,	r28
+	addq	t1,	m1b,	r0
+	stq	r28,	24(rp)
+	ret	r31,	(r26),	1
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/alpha/ev6/nails/submul_1.asm b/third_party/gmp/mpn/alpha/ev6/nails/submul_1.asm
new file mode 100644
index 0000000..f473a59
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/ev6/nails/submul_1.asm
@@ -0,0 +1,396 @@
+dnl  Alpha ev6 nails mpn_submul_1.
+
+dnl  Copyright 2002, 2005, 2006 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C      cycles/limb
+C EV4:    42
+C EV5:    18
+C EV6:     4
+
+C TODO
+C  * Reroll loop for 3.75 c/l with current 4-way unrolling.
+C  * The loop is overscheduled wrt loads and wrt multiplies, in particular
+C    umulh.
+C  * Use FP loop count and multiple exit points, that would simplify feed-in lp0
+C    and would work since the loop structure is really regular.
+
+C  INPUT PARAMETERS
+define(`rp',`r16')
+define(`up',`r17')
+define(`n', `r18')
+define(`vl0',`r19')
+
+define(`numb_mask',`r6')
+
+define(`m0a',`r0')
+define(`m0b',`r1')
+define(`m1a',`r2')
+define(`m1b',`r3')
+define(`m2a',`r20')
+define(`m2b',`r21')
+define(`m3a',`r22')
+define(`m3b',`r23')
+
+define(`acc0',`r25')
+define(`acc1',`r27')
+
+define(`ul0',`r4')
+define(`ul1',`r5')
+define(`ul2',`r4')
+define(`ul3',`r5')
+
+define(`rl0',`r24')
+define(`rl1',`r24')
+define(`rl2',`r24')
+define(`rl3',`r24')
+
+define(`t0',`r7')
+define(`t1',`r8')
+
+define(`NAIL_BITS',`GMP_NAIL_BITS')
+define(`NUMB_BITS',`GMP_NUMB_BITS')
+
+dnl  This declaration is munged by configure
+NAILS_SUPPORT(2-63)
+
+ASM_START()
+PROLOGUE(mpn_submul_1)
+	sll	vl0, NAIL_BITS, vl0
+	lda	numb_mask, -1(r31)
+	srl	numb_mask, NAIL_BITS, numb_mask
+
+	and	n,	3,	r25
+	cmpeq	r25,	1,	r21
+	bne	r21,	L(1m4)
+	cmpeq	r25,	2,	r21
+	bne	r21,	L(2m4)
+	beq	r25,	L(0m4)
+
+L(3m4):	ldq	ul3,	0(up)
+	lda	n,	-4(n)
+	ldq	ul0,	8(up)
+	mulq	vl0,	ul3,	m3a
+	umulh	vl0,	ul3,	m3b
+	ldq	ul1,	16(up)
+	lda	up,	24(up)
+	lda	rp,	-8(rp)
+	mulq	vl0,	ul0,	m0a
+	umulh	vl0,	ul0,	m0b
+	bge	n,	L(ge3)
+
+	mulq	vl0,	ul1,	m1a
+	umulh	vl0,	ul1,	m1b
+	ldq	rl3,	8(rp)
+	srl	m3a,NAIL_BITS,	t0
+	addq	t0,	r31,	acc1
+	subq	rl3,	acc1,	acc1
+	ldq	rl0,	16(rp)
+	srl	m0a,NAIL_BITS,	t0
+	addq	t0,	m3b,	acc0
+	sra	acc1,NUMB_BITS,	t1
+	br	r31,	L(ta3)
+
+L(ge3):	ldq	ul2,	0(up)
+	mulq	vl0,	ul1,	m1a
+	umulh	vl0,	ul1,	m1b
+	ldq	rl3,	8(rp)
+	srl	m3a,NAIL_BITS,	t0
+	ldq	ul3,	8(up)
+	lda	n,	-4(n)
+	mulq	vl0,	ul2,	m2a
+	addq	t0,	r31,	acc1
+	umulh	vl0,	ul2,	m2b
+	subq	rl3,	acc1,	acc1
+	ldq	rl0,	16(rp)
+	srl	m0a,NAIL_BITS,	t0
+	ldq	ul0,	16(up)
+	mulq	vl0,	ul3,	m3a
+	addq	t0,	m3b,	acc0
+	sra	acc1,NUMB_BITS,	t1
+	br	r31,	L(el3)
+
+L(0m4):	lda	n,	-8(n)
+	ldq	ul2,	0(up)
+	ldq	ul3,	8(up)
+	mulq	vl0,	ul2,	m2a
+	umulh	vl0,	ul2,	m2b
+	ldq	ul0,	16(up)
+	mulq	vl0,	ul3,	m3a
+	umulh	vl0,	ul3,	m3b
+	ldq	ul1,	24(up)
+	lda	up,	32(up)
+	mulq	vl0,	ul0,	m0a
+	umulh	vl0,	ul0,	m0b
+	bge	n,	L(ge4)
+
+	ldq	rl2,	0(rp)
+	srl	m2a,NAIL_BITS,	t0
+	mulq	vl0,	ul1,	m1a
+	addq	t0,	r31,	acc0
+	umulh	vl0,	ul1,	m1b
+	subq	rl2,	acc0,	acc0
+	ldq	rl3,	8(rp)
+	srl	m3a,NAIL_BITS,	t0
+	addq	t0,	m2b,	acc1
+	sra	acc0,NUMB_BITS,	t1
+	br	r31,	L(ta4)
+
+L(ge4):	ldq	rl2,	0(rp)
+	srl	m2a,NAIL_BITS,	t0
+	ldq	ul2,	0(up)
+	mulq	vl0,	ul1,	m1a
+	addq	t0,	r31,	acc0
+	umulh	vl0,	ul1,	m1b
+	subq	rl2,	acc0,	acc0
+	ldq	rl3,	8(rp)
+	srl	m3a,NAIL_BITS,	t0
+	ldq	ul3,	8(up)
+	lda	n,	-4(n)
+	mulq	vl0,	ul2,	m2a
+	addq	t0,	m2b,	acc1
+	sra	acc0,NUMB_BITS,	t1
+	br	r31,	L(el0)
+
+L(2m4):	lda	n,	-4(n)
+	ldq	ul0,	0(up)
+	ldq	ul1,	8(up)
+	lda	up,	16(up)
+	lda	rp,	-16(rp)
+	mulq	vl0,	ul0,	m0a
+	umulh	vl0,	ul0,	m0b
+	bge	n,	L(ge2)
+
+	mulq	vl0,	ul1,	m1a
+	umulh	vl0,	ul1,	m1b
+	ldq	rl0,	16(rp)
+	srl	m0a,NAIL_BITS,	t0
+	addq	t0,	r31,	acc0
+	subq	rl0,	acc0,	acc0
+	ldq	rl1,	24(rp)
+	srl	m1a,NAIL_BITS,	t0
+	addq	t0,	m0b,	acc1
+	sra	acc0,NUMB_BITS,	t1
+	br	r31,	L(ta2)
+
+L(ge2):	ldq	ul2,	0(up)
+	mulq	vl0,	ul1,	m1a
+	umulh	vl0,	ul1,	m1b
+	ldq	ul3,	8(up)
+	lda	n,	-4(n)
+	mulq	vl0,	ul2,	m2a
+	umulh	vl0,	ul2,	m2b
+	ldq	rl0,	16(rp)
+	srl	m0a,NAIL_BITS,	t0
+	ldq	ul0,	16(up)
+	mulq	vl0,	ul3,	m3a
+	addq	t0,	r31,	acc0
+	umulh	vl0,	ul3,	m3b
+	subq	rl0,	acc0,	acc0
+	ldq	rl1,	24(rp)
+	srl	m1a,NAIL_BITS,	t0
+	ldq	ul1,	24(up)
+	lda	up,	32(up)
+	lda	rp,	32(rp)
+	mulq	vl0,	ul0,	m0a
+	addq	t0,	m0b,	acc1
+	sra	acc0,NUMB_BITS,	t1
+	bge	n,	L(el2)
+
+	br	r31,	L(ta6)
+
+L(1m4):	lda	n,	-4(n)
+	ldq	ul1,	0(up)
+	lda	up,	8(up)
+	lda	rp,	-24(rp)
+	bge	n,	L(ge1)
+
+	mulq	vl0,	ul1,	m1a
+	umulh	vl0,	ul1,	m1b
+	ldq	rl1,	24(rp)
+	srl	m1a,NAIL_BITS,	t0
+	subq	rl1,	t0,	acc1
+	and	acc1,numb_mask,	r28
+	sra	acc1,NUMB_BITS,	t1
+	stq	r28,	24(rp)
+	subq	m1b,	t1,	r0
+	ret	r31,	(r26),	1
+
+L(ge1):	ldq	ul2,	0(up)
+	mulq	vl0,	ul1,	m1a
+	umulh	vl0,	ul1,	m1b
+	ldq	ul3,	8(up)
+	lda	n,	-4(n)
+	mulq	vl0,	ul2,	m2a
+	umulh	vl0,	ul2,	m2b
+	ldq	ul0,	16(up)
+	mulq	vl0,	ul3,	m3a
+	umulh	vl0,	ul3,	m3b
+	ldq	rl1,	24(rp)
+	srl	m1a,NAIL_BITS,	t0
+	ldq	ul1,	24(up)
+	lda	up,	32(up)
+	lda	rp,	32(rp)
+	mulq	vl0,	ul0,	m0a
+	addq	t0,	r31,	acc1
+	umulh	vl0,	ul0,	m0b
+	subq	rl1,	acc1,	acc1
+	ldq	rl2,	0(rp)
+	srl	m2a,NAIL_BITS,	t0
+	mulq	vl0,	ul1,	m1a
+	addq	t0,	m1b,	acc0
+	sra	acc1,NUMB_BITS,	t1
+	blt	n,	L(ta5)
+
+L(ge5):	ldq	ul2,	0(up)
+	br	r31,	L(el1)
+
+	ALIGN(16)
+L(top):	mulq	vl0,	ul0,	m0a		C U1
+	addq	t0,	m0b,	acc1		C L0
+	sra	acc0,NUMB_BITS,	t1		C U0
+	stq	r28,	-24(rp)			C L1
+C
+L(el2):	umulh	vl0,	ul0,	m0b		C U1
+	and	acc0,numb_mask,	r28		C L0
+	subq	rl1,	acc1,	acc1		C U0
+	ldq	rl2,	0(rp)			C L1
+C
+	unop					C U1
+	addq	t1,	acc1,	acc1		C L0
+	srl	m2a,NAIL_BITS,	t0		C U0
+	ldq	ul2,	0(up)			C L1
+C
+	mulq	vl0,	ul1,	m1a		C U1
+	addq	t0,	m1b,	acc0		C L0
+	sra	acc1,NUMB_BITS,	t1		C U0
+	stq	r28,	-16(rp)			C L1
+C
+L(el1):	umulh	vl0,	ul1,	m1b		C U1
+	and	acc1,numb_mask,	r28		C L0
+	subq	rl2,	acc0,	acc0		C U0
+	ldq	rl3,	8(rp)			C L1
+C
+	lda	n,	-4(n)			C L1
+	addq	t1,	acc0,	acc0		C L0
+	srl	m3a,NAIL_BITS,	t0		C U0
+	ldq	ul3,	8(up)			C L1
+C
+	mulq	vl0,	ul2,	m2a		C U1
+	addq	t0,	m2b,	acc1		C L0
+	sra	acc0,NUMB_BITS,	t1		C U0
+	stq	r28,	-8(rp)			C L1
+C
+L(el0):	umulh	vl0,	ul2,	m2b		C U1
+	and	acc0,numb_mask,	r28		C L0
+	subq	rl3,	acc1,	acc1		C U0
+	ldq	rl0,	16(rp)			C L1
+C
+	unop					C U1
+	addq	t1,	acc1,	acc1		C L0
+	srl	m0a,NAIL_BITS,	t0		C U0
+	ldq	ul0,	16(up)			C L1
+C
+	mulq	vl0,	ul3,	m3a		C U1
+	addq	t0,	m3b,	acc0		C L0
+	sra	acc1,NUMB_BITS,	t1		C U0
+	stq	r28,	0(rp)			C L1
+C
+L(el3):	umulh	vl0,	ul3,	m3b		C U1
+	and	acc1,numb_mask,	r28		C L0
+	subq	rl0,	acc0,	acc0		C U0
+	ldq	rl1,	24(rp)			C L1
+C
+	unop					C U1
+	addq	t1,	acc0,	acc0		C L0
+	srl	m1a,NAIL_BITS,	t0		C U0
+	ldq	ul1,	24(up)			C L1
+C
+	lda	up,	32(up)			C L0
+	unop					C U1
+	lda	rp,	32(rp)			C L1
+	bge	n,	L(top)			C U0
+
+L(end):	mulq	vl0,	ul0,	m0a
+	addq	t0,	m0b,	acc1
+	sra	acc0,NUMB_BITS,	t1
+	stq	r28,	-24(rp)
+L(ta6):	umulh	vl0,	ul0,	m0b
+	and	acc0,numb_mask,	r28
+	subq	rl1,	acc1,	acc1
+	ldq	rl2,	0(rp)
+	addq	t1,	acc1,	acc1
+	srl	m2a,NAIL_BITS,	t0
+	mulq	vl0,	ul1,	m1a
+	addq	t0,	m1b,	acc0
+	sra	acc1,NUMB_BITS,	t1
+	stq	r28,	-16(rp)
+L(ta5):	umulh	vl0,	ul1,	m1b
+	and	acc1,numb_mask,	r28
+	subq	rl2,	acc0,	acc0
+	ldq	rl3,	8(rp)
+	addq	t1,	acc0,	acc0
+	srl	m3a,NAIL_BITS,	t0
+	addq	t0,	m2b,	acc1
+	sra	acc0,NUMB_BITS,	t1
+	stq	r28,	-8(rp)
+	unop
+	ALIGN(16)
+L(ta4):	and	acc0,numb_mask,	r28
+	subq	rl3,	acc1,	acc1
+	ldq	rl0,	16(rp)
+	addq	t1,	acc1,	acc1
+	srl	m0a,NAIL_BITS,	t0
+	addq	t0,	m3b,	acc0
+	sra	acc1,NUMB_BITS,	t1
+	stq	r28,	0(rp)
+	unop
+	ALIGN(16)
+L(ta3):	and	acc1,numb_mask,	r28
+	subq	rl0,	acc0,	acc0
+	ldq	rl1,	24(rp)
+	addq	t1,	acc0,	acc0
+	srl	m1a,NAIL_BITS,	t0
+	addq	t0,	m0b,	acc1
+	sra	acc0,NUMB_BITS,	t1
+	stq	r28,	8(rp)
+	unop
+	ALIGN(16)
+L(ta2):	and	acc0,numb_mask,	r28
+	subq	rl1,	acc1,	acc1
+	addq	t1,	acc1,	acc1
+	sra	acc1,NUMB_BITS,	t1
+	stq	r28,	16(rp)
+	and	acc1,numb_mask,	r28
+	subq	m1b,	t1,	r0
+	stq	r28,	24(rp)
+	ret	r31,	(r26),	1
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/alpha/ev6/slot.pl b/third_party/gmp/mpn/alpha/ev6/slot.pl
new file mode 100755
index 0000000..a4c8a36
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/ev6/slot.pl
@@ -0,0 +1,318 @@
+#!/usr/bin/perl -w
+
+# Copyright 2000, 2001, 2003-2005, 2011 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+
+# Usage: slot.pl [filename.o]...
+#
+# Run "objdump" to produce a disassembly of the given object file(s) and
+# annotate the output with "U" or "L" slotting which Alpha EV6 will use.
+#
+# When an instruction is E (ie. either U or L), an "eU" or "eL" is shown, as
+# a reminder that it wasn't a fixed requirement that gave the U or L, but
+# the octaword slotting rules.
+#
+# If an instruction is not recognised, that octaword does not get any U/L
+# shown, only lower-case "u", "l" or "e" for the instructions which are
+# known.  Add any unknown instructions to %optable below.
+
+
+use strict;
+
+# The U or L which various instructions demand, or E if either.
+#
+my %optable =
+  (
+   'addq'   => 'E',
+   'and'    => 'E',
+   'andnot' => 'E',
+   'beq'    => 'U',
+   'bge'    => 'U',
+   'bgt'    => 'U',
+   'bic'    => 'E',
+   'bis'    => 'E',
+   'blt'    => 'U',
+   'bne'    => 'U',
+   'br'     => 'L',
+   'clr'    => 'E',
+   'cmpule' => 'E',
+   'cmpult' => 'E',
+   'cmpeq'  => 'E',
+   'cmoveq' => 'E',
+   'cmovne' => 'E',
+   'ctpop'  => 'U',
+   'ctlz'   => 'U',
+   'cttz'   => 'U',
+   'extbl'  => 'U',
+   'extlh'  => 'U',
+   'extll'  => 'U',
+   'extqh'  => 'U',
+   'extql'  => 'U',
+   'extwh'  => 'U',
+   'extwl'  => 'U',
+   'jsr'    => 'L',
+   'lda'    => 'E',
+   'ldah'   => 'E',
+   'ldbu'   => 'L',
+   'ldl'    => 'L',
+   'ldq'    => 'L',
+   'ldt'    => 'L',
+   'ret'    => 'L',
+   'mov'    => 'E',
+   'mull'   => 'U',
+   'mulq'   => 'U',
+   'negq'   => 'E',
+   'nop'    => 'E',
+   'not'    => 'E',
+   's8addq' => 'E',
+   's8subq' => 'E',
+   # 'sextb'  => ?
+   # 'sextl'  => ?
+   'sll'    => 'U',
+   'srl'    => 'U',
+   'stq'    => 'L',
+   'subq'   => 'E',
+   'umulh'  => 'U',
+   'unop'   => 'E',
+   'xor'    => 'E',
+  );
+
+# Slottings used for a given pattern of U/L/E in an octaword.  This is as
+# per the "Ebox Slotting" section of the EV6 hardware reference manual.
+#
+my %slottable =
+  (
+   'EEEE' => 'ULUL',
+   'EEEL' => 'ULUL',
+   'EEEU' => 'ULLU',
+   'EELE' => 'ULLU',
+   'EELL' => 'UULL',
+   'EELU' => 'ULLU',
+   'EEUE' => 'ULUL',
+   'EEUL' => 'ULUL',
+   'EEUU' => 'LLUU',
+   'ELEE' => 'ULUL',
+   'ELEL' => 'ULUL',
+   'ELEU' => 'ULLU',
+   'ELLE' => 'ULLU',
+   'ELLL' => 'ULLL',
+   'ELLU' => 'ULLU',
+   'ELUE' => 'ULUL',
+   'ELUL' => 'ULUL',
+
+   'LLLL' => 'LLLL',
+   'LLLU' => 'LLLU',
+   'LLUE' => 'LLUU',
+   'LLUL' => 'LLUL',
+   'LLUU' => 'LLUU',
+   'LUEE' => 'LULU',
+   'LUEL' => 'LUUL',
+   'LUEU' => 'LULU',
+   'LULE' => 'LULU',
+   'LULL' => 'LULL',
+   'LULU' => 'LULU',
+   'LUUE' => 'LUUL',
+   'LUUL' => 'LUUL',
+   'LUUU' => 'LUUU',
+   'UEEE' => 'ULUL',
+   'UEEL' => 'ULUL',
+   'UEEU' => 'ULLU',
+
+   'ELUU' => 'LLUU',
+   'EUEE' => 'LULU',
+   'EUEL' => 'LUUL',
+   'EUEU' => 'LULU',
+   'EULE' => 'LULU',
+   'EULL' => 'UULL',
+   'EULU' => 'LULU',
+   'EUUE' => 'LUUL',
+   'EUUL' => 'LUUL',
+   'EUUU' => 'LUUU',
+   'LEEE' => 'LULU',
+   'LEEL' => 'LUUL',
+   'LEEU' => 'LULU',
+   'LELE' => 'LULU',
+   'LELL' => 'LULL',
+   'LELU' => 'LULU',
+   'LEUE' => 'LUUL',
+   'LEUL' => 'LUUL',
+   'LEUU' => 'LLUU',
+   'LLEE' => 'LLUU',
+   'LLEL' => 'LLUL',
+   'LLEU' => 'LLUU',
+   'LLLE' => 'LLLU',
+
+   'UELE' => 'ULLU',
+   'UELL' => 'UULL',
+   'UELU' => 'ULLU',
+   'UEUE' => 'ULUL',
+   'UEUL' => 'ULUL',
+   'UEUU' => 'ULUU',
+   'ULEE' => 'ULUL',
+   'ULEL' => 'ULUL',
+   'ULEU' => 'ULLU',
+   'ULLE' => 'ULLU',
+   'ULLL' => 'ULLL',
+   'ULLU' => 'ULLU',
+   'ULUE' => 'ULUL',
+   'ULUL' => 'ULUL',
+   'ULUU' => 'ULUU',
+   'UUEE' => 'UULL',
+   'UUEL' => 'UULL',
+   'UUEU' => 'UULU',
+   'UULE' => 'UULL',
+   'UULL' => 'UULL',
+   'UULU' => 'UULU',
+   'UUUE' => 'UUUL',
+   'UUUL' => 'UUUL',
+   'UUUU' => 'UUUU',
+  );
+
+# Check all combinations of U/L/E are present in %slottable.
+sub coverage {
+  foreach my $a ('U', 'L', 'E') {
+    foreach my $b ('U', 'L', 'E') {
+      foreach my $c ('U', 'L', 'E') {
+        foreach my $d ('U', 'L', 'E') {
+          my $x = $a . $b . $c . $d;
+          if (! defined $slottable{$x}) {
+            print "slottable missing: $x\n"
+          }
+        }
+      }
+    }
+  }
+}
+
+# Certain consistency checks for %slottable.
+sub check {
+  foreach my $x (keys %slottable) {
+    my $a = substr($x,0,1);
+    my $b = substr($x,1,1);
+    my $c = substr($x,2,1);
+    my $d = substr($x,3,1);
+    my $es = ($a eq 'E') + ($b eq 'E') + ($c eq 'E') + ($d eq 'E');
+    my $ls = ($a eq 'L') + ($b eq 'L') + ($c eq 'L') + ($d eq 'L');
+    my $us = ($a eq 'U') + ($b eq 'U') + ($c eq 'U') + ($d eq 'U');
+
+    my $got = $slottable{$x};
+    my $want = $x;
+
+    if ($es == 0) {
+
+    } elsif ($es == 1) {
+      # when only one E, it's mapped to whichever of U or L is otherwise
+      # used the least
+      if ($ls > $us) {
+        $want =~ s/E/U/;
+      } else {
+        $want =~ s/E/L/;
+      }
+    } elsif ($es == 2) {
+      # when two E's and two U, then the E's map to L; vice versa for two E
+      # and two L
+      if ($ls == 2) {
+        $want =~ s/E/U/g;
+      } elsif ($us == 2) {
+        $want =~ s/E/L/g;
+      } else {
+        next;
+      }
+    } elsif ($es == 3) {
+      next;
+
+    } else { # $es == 4
+      next;
+    }
+
+    if ($want ne $got) {
+      print "slottable $x want $want got $got\n";
+    }
+  }
+}
+
+sub disassemble {
+  my ($file) = @_;
+
+  open (IN, "objdump -Srfh $file |") || die "Cannot open pipe from objdump\n";
+
+  my (%pre, %post, %type);
+  while (<IN>) {
+    my $line = $_ . "";
+
+    if ($line =~ /(^[ \t]*[0-9a-f]*([0-9a-f]):[ \t]*[0-9a-f][0-9a-f] [0-9a-f][0-9a-f] [0-9a-f][0-9a-f] [0-9a-f][0-9a-f] )\t(([a-z0-9]+).*)/) {
+      my ($this_pre, $addr, $this_post, $opcode) = ($1, $2, $3, $4);
+
+      my $this_type = $optable{$opcode};
+      if (! defined ($this_type)) { $this_type = ' '; }
+
+      $pre{$addr} = $this_pre;
+      $post{$addr} = $this_post;
+      $type{$addr} = $this_type;
+
+      if ($addr eq 'c') {
+        my %slot = ('0'=>' ', '4'=>' ', '8'=>' ', 'c'=>' ');
+
+        my $str = $type{'c'} . $type{'8'} . $type{'4'} . $type{'0'};
+        $str = $slottable{$str};
+        if (defined $str) {
+          $slot{'c'} = substr($str,0,1);
+          $slot{'8'} = substr($str,1,1);
+          $slot{'4'} = substr($str,2,1);
+          $slot{'0'} = substr($str,3,1);
+        }
+
+        foreach my $i ('0', '4', '8', 'c') {
+          if ($slot{$i} eq $type{$i}) { $type{$i} = ' '; }
+          print $pre{$i}, ' ', lc($type{$i}),$slot{$i}, '  ', $post{$i}, "\n";
+        }
+
+        %pre = ();
+        %type = ();
+        %post = ();
+      }
+    }
+  }
+
+  close IN || die "Error from objdump (or objdump not available)\n";
+}
+
+coverage();
+check();
+
+my @files;
+if ($#ARGV >= 0) {
+  @files = @ARGV;
+} else {
+  die
+}
+
+foreach (@files)  {
+    disassemble($_);
+}
diff --git a/third_party/gmp/mpn/alpha/ev6/sub_n.asm b/third_party/gmp/mpn/alpha/ev6/sub_n.asm
new file mode 100644
index 0000000..a35ba40
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/ev6/sub_n.asm
@@ -0,0 +1,283 @@
+dnl  Alpha ev6 mpn_sub_n -- Subtract two limb vectors of the same length > 0
+dnl  and store difference in a third limb vector.
+
+dnl  Copyright 2000, 2003, 2005 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C      cycles/limb
+C EV4:     ?
+C EV5:     5.4
+C EV6:     2.125
+
+C  INPUT PARAMETERS
+C  rp	r16
+C  up	r17
+C  vp	r18
+C  n	r19
+C  cy	r20   (for mpn_add_nc)
+
+C TODO
+C   Finish cleaning up cy registers r22, r23 (make them use cy0/cy1)
+C   Use multi-pronged feed-in.
+C   Perform additional micro-tuning
+
+C  This code was written in cooperation with ev6 pipeline expert Steve Root.
+
+C  Pair loads and stores where possible
+C  Store pairs oct-aligned where possible (didn't need it here)
+C  Stores are delayed every third cycle
+C  Loads and stores are delayed by fills
+C  U stays still, put code there where possible (note alternation of U1 and U0)
+C  L moves because of loads and stores
+C  Note dampers in L to limit damage
+
+C  This odd-looking optimization expects that were having random bits in our
+C  data, so that a pure zero result is unlikely. so we penalize the unlikely
+C  case to help the common case.
+
+define(`u0', `r0')  define(`u1', `r3')
+define(`v0', `r1')  define(`v1', `r4')
+
+define(`cy0', `r20')  define(`cy1', `r21')
+
+MULFUNC_PROLOGUE(mpn_sub_n mpn_sub_nc)
+
+ASM_START()
+PROLOGUE(mpn_sub_nc)
+	br	r31,	$entry
+EPILOGUE()
+PROLOGUE(mpn_sub_n)
+	bis	r31,	r31,	cy0	C clear carry in
+$entry:	cmpult	r19,	5,	r22	C L1 move counter
+	ldq	u1,	0(r17)		C L0 get next ones
+	ldq	v1,	0(r18)		C L1
+	bne	r22,	$Lsmall
+
+	ldq	u0,	8(r17)		C L0 get next ones
+	ldq	v0,	8(r18)		C L1
+	subq	u1,	v1,	r5	C U0 sub two data
+
+	cmpult	u1,	v1,	r23	C U0 did it borrow
+	ldq	u1,	16(r17)		C L0 get next ones
+	ldq	v1,	16(r18)		C L1
+
+	subq	u0,	v0,	r8	C U1 sub two data
+	subq	r5,	cy0,	r24	C U0 borrow in
+
+	cmpult	u0,	v0,	r22	C U1 did it borrow
+	beq	r5,	$fix5f		C U0 fix exact zero
+$ret5f:	ldq	u0,	24(r17)		C L0 get next ones
+	ldq	v0,	24(r18)		C L1
+
+	subq	r8,	r23,	r25	C U1 borrow from last
+	subq	u1,	v1,	r7	C U0 sub two data
+
+	beq	r8,	$fix6f		C U1 fix exact zero
+$ret6f:	cmpult	u1,	v1,	r23	C U0 did it borrow
+	ldq	u1,	32(r17)		C L0 get next ones
+	ldq	v1,	32(r18)		C L1
+
+	lda	r17,	40(r17)		C L0 move pointer
+	lda	r18,	40(r18)		C L1 move pointer
+
+	lda	r16,	-8(r16)
+	lda	r19,	-13(r19)	C L1 move counter
+	blt	r19,	$Lend		C U1 loop control
+
+
+C Main loop.  8-way unrolled.
+	ALIGN(16)
+$Loop:	subq	u0,	v0,	r2	C U1 sub two data
+	stq	r24,	8(r16)		C L0 put an answer
+	subq	r7,	r22,	r24	C U0 borrow from last
+	stq	r25,	16(r16)		C L1 pair
+
+	cmpult	u0,	v0,	cy1	C U1 did it borrow
+	beq	r7,	$fix7		C U0 fix exact 0
+$ret7:	ldq	u0,	0(r17)		C L0 get next ones
+	ldq	v0,	0(r18)		C L1
+
+	bis	r31,	r31,	r31	C L  damp out
+	subq	r2,	r23,	r25	C U1 borrow from last
+	bis	r31,	r31,	r31	C L  moves in L !
+	subq	u1,	v1,	r5	C U0 sub two data
+
+	beq	r2,	$fix0		C U1 fix exact zero
+$ret0:	cmpult	u1,	v1,	cy0	C U0 did it borrow
+	ldq	u1,	8(r17)		C L0 get next ones
+	ldq	v1,	8(r18)		C L1
+
+	subq	u0,	v0,	r8	C U1 sub two data
+	stq	r24,	24(r16)		C L0 store pair
+	subq	r5,	cy1,	r24	C U0 borrow from last
+	stq	r25,	32(r16)		C L1
+
+	cmpult	u0,	v0,	r22	C U1 did it borrow
+	beq	r5,	$fix1		C U0 fix exact zero
+$ret1:	ldq	u0,	16(r17)		C L0 get next ones
+	ldq	v0,	16(r18)		C L1
+
+	lda	r16,	64(r16)		C L0 move pointer
+	subq	r8,	cy0,	r25	C U1 borrow from last
+	lda	r19,	-8(r19)		C L1 move counter
+	subq	u1,	v1,	r7	C U0 sub two data
+
+	beq	r8,	$fix2		C U1 fix exact zero
+$ret2:	cmpult	u1,	v1,	r23	C U0 did it borrow
+	ldq	u1,	24(r17)		C L0 get next ones
+	ldq	v1,	24(r18)		C L1
+
+	subq	u0,	v0,	r2	C U1 sub two data
+	stq	r24,	-24(r16)	C L0 put an answer
+	subq	r7,	r22,	r24	C U0 borrow from last
+	stq	r25,	-16(r16)	C L1 pair
+
+	cmpult	u0,	v0,	cy1	C U1 did it borrow
+	beq	r7,	$fix3		C U0 fix exact 0
+$ret3:	ldq	u0,	32(r17)		C L0 get next ones
+	ldq	v0,	32(r18)		C L1
+
+	bis	r31,	r31,	r31	C L  damp out
+	subq	r2,	r23,	r25	C U1 borrow from last
+	bis	r31,	r31,	r31	C L  moves in L !
+	subq	u1,	v1,	r5	C U0 sub two data
+
+	beq	r2,	$fix4		C U1 fix exact zero
+$ret4:	cmpult	u1,	v1,	cy0	C U0 did it borrow
+	ldq	u1,	40(r17)		C L0 get next ones
+	ldq	v1,	40(r18)		C L1
+
+	subq	u0,	v0,	r8	C U1 sub two data
+	stq	r24,	-8(r16)		C L0 store pair
+	subq	r5,	cy1,	r24	C U0 borrow from last
+	stq	r25,	0(r16)		C L1
+
+	cmpult	u0,	v0,	r22	C U1 did it borrow
+	beq	r5,	$fix5		C U0 fix exact zero
+$ret5:	ldq	u0,	48(r17)		C L0 get next ones
+	ldq	v0,	48(r18)		C L1
+
+	ldl	r31, 256(r17)		C L0 prefetch
+	subq	r8,	cy0,	r25	C U1 borrow from last
+	ldl	r31, 256(r18)		C L1 prefetch
+	subq	u1,	v1,	r7	C U0 sub two data
+
+	beq	r8,	$fix6		C U1 fix exact zero
+$ret6:	cmpult	u1,	v1,	r23	C U0 did it borrow
+	ldq	u1,	56(r17)		C L0 get next ones
+	ldq	v1,	56(r18)		C L1
+
+	lda	r17,	64(r17)		C L0 move pointer
+	bis	r31,	r31,	r31	C U
+	lda	r18,	64(r18)		C L1 move pointer
+	bge	r19,	$Loop		C U1 loop control
+C ==== main loop end
+
+$Lend:	subq	u0,	v0,	r2	C U1 sub two data
+	stq	r24,	8(r16)		C L0 put an answer
+	subq	r7,	r22,	r24	C U0 borrow from last
+	stq	r25,	16(r16)		C L1 pair
+	cmpult	u0,	v0,	cy1	C U1 did it borrow
+	beq	r7,	$fix7c		C U0 fix exact 0
+$ret7c:	subq	r2,	r23,	r25	C U1 borrow from last
+	subq	u1,	v1,	r5	C U0 sub two data
+	beq	r2,	$fix0c		C U1 fix exact zero
+$ret0c:	cmpult	u1,	v1,	cy0	C U0 did it borrow
+	stq	r24,	24(r16)		C L0 store pair
+	subq	r5,	cy1,	r24	C U0 borrow from last
+	stq	r25,	32(r16)		C L1
+	beq	r5,	$fix1c		C U0 fix exact zero
+$ret1c:	stq	r24,	40(r16)		C L0 put an answer
+	lda	r16,	48(r16)		C L0 move pointer
+
+	lda	r19,	8(r19)
+	beq	r19,	$Lret
+
+	ldq	u1,	0(r17)
+	ldq	v1,	0(r18)
+$Lsmall:
+	lda	r19,	-1(r19)
+	beq	r19,	$Lend0
+
+	ALIGN(8)
+$Loop0:	subq	u1,	v1,	r2	C main sub
+	cmpult	u1,	v1,	r8	C compute bw from last sub
+	ldq	u1,	8(r17)
+	ldq	v1,	8(r18)
+	subq	r2,	cy0,	r5	C borrow sub
+	lda	r17,	8(r17)
+	lda	r18,	8(r18)
+	stq	r5,	0(r16)
+	cmpult	r2,	cy0,	cy0	C compute bw from last sub
+	lda	r19,	-1(r19)		C decr loop cnt
+	bis	r8,	cy0,	cy0	C combine bw from the two subs
+	lda	r16,	8(r16)
+	bne	r19,	$Loop0
+$Lend0:	subq	u1,	v1,	r2	C main sub
+	subq	r2,	cy0,	r5	C borrow sub
+	cmpult	u1,	v1,	r8	C compute bw from last sub
+	cmpult	r2,	cy0,	cy0	C compute bw from last sub
+	stq	r5,	0(r16)
+	bis	r8,	cy0,	r0	C combine bw from the two subs
+	ret	r31,(r26),1
+
+	ALIGN(8)
+$Lret:	lda	r0,	0(cy0)		C copy borrow into return register
+	ret	r31,(r26),1
+
+$fix5f:	bis	r23,	cy0,	r23	C bring forward borrow
+	br	r31,	$ret5f
+$fix6f:	bis	r22,	r23,	r22	C bring forward borrow
+	br	r31,	$ret6f
+$fix0:	bis	cy1,	r23,	cy1	C bring forward borrow
+	br	r31,	$ret0
+$fix1:	bis	cy0,	cy1,	cy0	C bring forward borrow
+	br	r31,	$ret1
+$fix2:	bis	r22,	cy0,	r22	C bring forward borrow
+	br	r31,	$ret2
+$fix3:	bis	r23,	r22,	r23	C bring forward borrow
+	br	r31,	$ret3
+$fix4:	bis	cy1,	r23,	cy1	C bring forward borrow
+	br	r31,	$ret4
+$fix5:	bis	cy1,	cy0,	cy0	C bring forward borrow
+	br	r31,	$ret5
+$fix6:	bis	r22,	cy0,	r22	C bring forward borrow
+	br	r31,	$ret6
+$fix7:	bis	r23,	r22,	r23	C bring forward borrow
+	br	r31,	$ret7
+$fix0c:	bis	cy1,	r23,	cy1	C bring forward borrow
+	br	r31,	$ret0c
+$fix1c:	bis	cy0,	cy1,	cy0	C bring forward borrow
+	br	r31,	$ret1c
+$fix7c:	bis	r23,	r22,	r23	C bring forward borrow
+	br	r31,	$ret7c
+
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/alpha/ev67/gcd_11.asm b/third_party/gmp/mpn/alpha/ev67/gcd_11.asm
new file mode 100644
index 0000000..03c234b
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/ev67/gcd_11.asm
@@ -0,0 +1,79 @@
+dnl  Alpha ev67 mpn_gcd_11 -- Nx1 greatest common divisor.
+
+dnl  Copyright 2003, 2004 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C ev67: 3.4 cycles/bitpair for 1x1 part
+
+
+C mp_limb_t mpn_gcd_1 (mp_srcptr xp, mp_size_t xsize, mp_limb_t y);
+C
+C In the 1x1 part, the algorithm is to change x,y to abs(x-y),min(x,y) and
+C strip trailing zeros from abs(x-y) to maintain x and y both odd.
+C
+C The trailing zeros are calculated from just x-y, since in twos-complement
+C there's the same number of trailing zeros on d or -d.  This means the cttz
+C runs in parallel with abs(x-y).
+C
+C The loop takes 5 cycles, and at 0.68 iterations per bit for two N-bit
+C operands with this algorithm gives the measured 3.4 c/l.
+C
+C The slottings shown are for SVR4 style systems, Unicos differs in the
+C initial gp setup and the LEA.
+
+
+ASM_START()
+PROLOGUE(mpn_gcd_11)
+	mov	r16, r0
+	mov	r17, r1
+
+	ALIGN(16)
+L(top):	subq	r0, r1, r7		C l0  d = x - y
+	cmpult	r0, r1, r16		C u0  test x >= y
+
+	subq	r1, r0, r4		C l0  new_x = y - x
+	cttz	r7, r8			C U0  d twos
+
+	cmoveq	r16, r7, r4		C l0  new_x = d if x>=y
+	cmovne	r16, r0, r1		C u0  y = x if x<y
+	unop				C l   \ force cmoveq into l0
+	unop				C u   /
+
+	C				C cmoveq2 L0, cmovne2 U0
+
+	srl	r4, r8, r0		C U0  x = new_x >> twos
+	bne	r7, L(top)		C U1  stop when d==0
+
+
+L(end):	mov	r1, r0			C U0  return y << common_twos
+	ret	r31, (r26), 1		C L0
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/alpha/ev67/hamdist.asm b/third_party/gmp/mpn/alpha/ev67/hamdist.asm
new file mode 100644
index 0000000..4b13e9f
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/ev67/hamdist.asm
@@ -0,0 +1,111 @@
+dnl  Alpha ev67 mpn_hamdist -- mpn hamming distance.
+
+dnl  Copyright 2003, 2005 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C ev67: 2.5 cycles/limb
+
+
+C unsigned long mpn_hamdist (mp_srcptr xp, mp_srcptr yp, mp_size_t size);
+C
+C The hope was for 2.0 c/l here, but that isn't achieved.  We're limited by
+C renaming register shortage.  Since we need 5 instructions per limb, further
+C unrolling could approach 1.5 c/l.
+C
+C The main loop processes two limbs from each operand on each iteration.  An
+C odd size is handled by processing xp[0]^yp[0] at the start.  If the size
+C is even that result is discarded, and is repeated by the main loop.
+C
+
+ASM_START()
+PROLOGUE(mpn_hamdist)
+
+	C r16	xp
+	C r17	yp
+	C r18	size
+
+	ldq	r1, 0(r16)		C L0  xp[0]
+	ldq	r2, 0(r17)		C L1  yp[0]
+	and	r18, 1, r8		C U1  1 if size odd
+	srl	r18, 1, r18		C U0  size, limb pairs
+
+	clr	r0			C L0  initial total
+	s8addq	r8, r17, r17		C U1  yp++ if size odd
+	s8addq	r8, r16, r16		C L1  xp++ if size odd
+	clr	r6			C U0  dummy initial xor 1
+
+	xor	r1, r2, r5		C L   initial xor 0
+	beq	r18, L(one)		C U   if size==1
+
+	cmoveq	r8, r31, r5		C L   discard first limb if size even
+	unop				C U
+
+
+	ALIGN(16)
+L(top):
+	C r0	total accumulating
+	C r7	xor 0
+	C r8	xor 1
+	C r16	xp, incrementing
+	C r17	yp, incrementing
+	C r18	size, limb pairs, decrementing
+
+	ldq	r1, 0(r16)		C L
+	ldq	r2, 0(r17)		C L
+	ctpop	r5, r7			C U0
+	lda	r16, 16(r16)		C U
+
+	ldq	r3, -8(r16)		C L
+	ldq	r4, 8(r17)		C L
+	ctpop	r6, r8			C U0
+	lda	r17, 16(r17)		C U
+
+	ldl	r31, 256(r16)		C L	prefetch
+	ldl	r31, 256(r17)		C L	prefetch
+	xor	r1, r2, r5		C U
+	lda	r18, -1(r18)		C U
+
+	xor	r3, r4, r6		C U
+	addq	r0, r7, r0		C L
+	addq	r0, r8, r0		C L
+	bne	r18, L(top)		C U
+
+
+	ctpop	r6, r8			C U0
+	addq	r0, r8, r0		C L
+L(one):
+	ctpop	r5, r7			C U0
+	addq	r0, r7, r0		C L
+
+	ret	r31, (r26), 1		C L0
+
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/alpha/ev67/popcount.asm b/third_party/gmp/mpn/alpha/ev67/popcount.asm
new file mode 100644
index 0000000..049c1cd
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/ev67/popcount.asm
@@ -0,0 +1,101 @@
+dnl  Alpha ev67 mpn_popcount -- mpn bit population count.
+
+dnl  Copyright 2003, 2005 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C ev67: 1.5 cycles/limb
+
+
+C unsigned long mpn_popcount (mp_srcptr src, mp_size_t size);
+C
+C This schedule seems necessary for the full 1.5 c/l, the IQ can't quite hide
+C all latencies, the addq's must be deferred to the next iteration.
+C
+C Since we need just 3 instructions per limb, further unrolling could approach
+C 1.0 c/l.
+C
+C The main loop processes two limbs at a time.  An odd size is handled by
+C processing src[0] at the start.  If the size is even that result is
+C discarded, and src[0] is repeated by the main loop.
+C
+
+ASM_START()
+PROLOGUE(mpn_popcount)
+
+	C r16	src
+	C r17	size
+
+	ldq	r0, 0(r16)		C L0  src[0]
+	and	r17, 1, r8		C U1  1 if size odd
+	srl	r17, 1, r17		C U0  size, limb pairs
+
+	s8addq	r8, r16, r16		C L1  src++ if size odd
+	ctpop	r0, r0			C U0
+	beq	r17, L(one)		C U1  if size==1
+
+	cmoveq	r8, r31, r0		C L   discard first limb if size even
+	clr	r3			C L
+
+	clr	r4			C L
+	unop				C U
+	unop				C L
+	unop				C U
+
+
+	ALIGN(16)
+L(top):
+	C r0	total accumulating
+	C r3	pop 0
+	C r4	pop 1
+	C r16	src, incrementing
+	C r17	size, decrementing
+
+	ldq	r1, 0(r16)		C L
+	ldq	r2, 8(r16)		C L
+	lda	r16, 16(r16)		C U
+	lda	r17, -1(r17)		C U
+
+	addq	r0, r3, r0		C L
+	addq	r0, r4, r0		C L
+	ctpop	r1, r3			C U0
+	ctpop	r2, r4			C U0
+
+	ldl	r31, 512(r16)		C L	prefetch
+	bne	r17, L(top)		C U
+
+
+	addq	r0, r3, r0		C L
+	addq	r0, r4, r0		C U
+L(one):
+	ret	r31, (r26), 1		C L0
+
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/alpha/gmp-mparam.h b/third_party/gmp/mpn/alpha/gmp-mparam.h
new file mode 100644
index 0000000..b850bd2
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/gmp-mparam.h
@@ -0,0 +1,86 @@
+/* Alpha EV4 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 1999-2002, 2004, 2005, 2009 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+
+/* 175MHz 21064 */
+
+/* Generated by tuneup.c, 2009-01-15, gcc 3.2 */
+
+#define MUL_TOOM22_THRESHOLD             12
+#define MUL_TOOM33_THRESHOLD             69
+#define MUL_TOOM44_THRESHOLD             88
+
+#define SQR_BASECASE_THRESHOLD            4
+#define SQR_TOOM2_THRESHOLD              20
+#define SQR_TOOM3_THRESHOLD              62
+#define SQR_TOOM4_THRESHOLD             155
+
+#define MULLO_BASECASE_THRESHOLD          0  /* always */
+#define MULLO_DC_THRESHOLD               40
+#define MULLO_MUL_N_THRESHOLD           202
+
+#define DIV_SB_PREINV_THRESHOLD           0  /* preinv always */
+#define DIV_DC_THRESHOLD                 38
+#define POWM_THRESHOLD                   60
+
+#define MATRIX22_STRASSEN_THRESHOLD      17
+#define HGCD_THRESHOLD                   80
+#define GCD_DC_THRESHOLD                237
+#define GCDEXT_DC_THRESHOLD             198
+#define JACOBI_BASE_METHOD                2
+
+#define DIVREM_1_NORM_THRESHOLD           0  /* preinv always */
+#define DIVREM_1_UNNORM_THRESHOLD         0  /* always */
+#define MOD_1_NORM_THRESHOLD              0  /* always */
+#define MOD_1_UNNORM_THRESHOLD            0  /* always */
+#define MOD_1_1_THRESHOLD                 2
+#define MOD_1_2_THRESHOLD                 9
+#define MOD_1_4_THRESHOLD                20
+#define USE_PREINV_DIVREM_1               1  /* preinv always */
+#define USE_PREINV_MOD_1                  1  /* preinv always */
+#define DIVEXACT_1_THRESHOLD              0  /* always */
+#define MODEXACT_1_ODD_THRESHOLD          0  /* always */
+
+#define GET_STR_DC_THRESHOLD             20
+#define GET_STR_PRECOMPUTE_THRESHOLD     37
+#define SET_STR_DC_THRESHOLD            746
+#define SET_STR_PRECOMPUTE_THRESHOLD   1332
+
+#define MUL_FFT_TABLE  { 240, 480, 1344, 2304, 5120, 20480, 49152, 0 }
+#define MUL_FFT_MODF_THRESHOLD          232
+#define MUL_FFT_THRESHOLD              1664
+
+#define SQR_FFT_TABLE  { 240, 480, 1216, 2304, 5120, 12288, 49152, 0 }
+#define SQR_FFT_MODF_THRESHOLD          232
+#define SQR_FFT_THRESHOLD              1408
diff --git a/third_party/gmp/mpn/alpha/invert_limb.asm b/third_party/gmp/mpn/alpha/invert_limb.asm
new file mode 100644
index 0000000..afc010f
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/invert_limb.asm
@@ -0,0 +1,95 @@
+dnl  Alpha mpn_invert_limb -- Invert a normalized limb.
+
+dnl  Copyright 1996, 2000-2003, 2007, 2011, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C      cycles/limb
+C EV4:     ?
+C EV5:   137/140  (with BWX/without BWX)
+C EV6:    71/72   (with BWX/without BWX)
+
+C This was compiler generated, with minimal manual edits.  Surely several
+C cycles could be cut with some thought.
+
+ASM_START()
+PROLOGUE(mpn_invert_limb,gp)
+	LEA(	r2, approx_tab)
+	srl	r16, 54, r1
+	srl	r16, 24, r4
+	and	r16, 1, r5
+	bic	r1, 1, r7
+	lda	r4, 1(r4)
+	srl	r16, 1, r3
+	addq	r7, r2, r1
+ifelse(bwx_available_p,1,`
+	ldwu	r0, -512(r1)
+',`
+	ldq_u	r0, -512(r1)
+	extwl	r0, r7, r0
+')
+	addq	r3, r5, r3
+	mull	r0, r0, r1
+	sll	r0, 11, r0
+	mulq	r1, r4, r1
+	srl	r1, 40, r1
+	subq	r0, r1, r0
+	lda	r0, -1(r0)
+	mulq	r0, r0, r2
+	sll	r0, 60, r1
+	sll	r0, 13, r0
+	mulq	r2, r4, r2
+	subq	r1, r2, r1
+	srl	r1, 47, r1
+	addq	r0, r1, r0
+	mulq	r0, r3, r3
+	srl	r0, 1, r1
+	cmoveq	r5, 0, r1
+	subq	r1, r3, r1
+	umulh	r1, r0, r3
+	sll	r0, 31, r0
+	srl	r3, 1, r1
+	addq	r0, r1, r0
+	mulq	r0, r16, r2
+	umulh	r0, r16, r3
+	addq	r2, r16, r1
+	addq	r3, r16, r16
+	cmpult	r1, r2, r1
+	addq	r16, r1, r3
+	subq	r0, r3, r0
+	ret	r31, (r26), 1
+EPILOGUE()
+DATASTART(approx_tab,8)
+forloop(i,256,512-1,dnl
+`	.word	eval(0x7fd00/i)
+')dnl
+	SIZE(approx_tab, 512)
+	TYPE(approx_tab, object)
+DATAEND()
+ASM_END()
diff --git a/third_party/gmp/mpn/alpha/lshift.asm b/third_party/gmp/mpn/alpha/lshift.asm
new file mode 100644
index 0000000..c62a856
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/lshift.asm
@@ -0,0 +1,182 @@
+dnl  Alpha mpn_lshift -- Shift a number left.
+
+dnl  Copyright 1994, 1995, 2000, 2003, 2009 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C      cycles/limb
+C EV4:     ?
+C EV5:     3.25
+C EV6:     1.75
+
+C  INPUT PARAMETERS
+C  rp	r16
+C  up	r17
+C  n	r18
+C  cnt	r19
+
+
+ASM_START()
+PROLOGUE(mpn_lshift)
+	s8addq	r18,r17,r17	C make r17 point at end of s1
+	ldq	r4,-8(r17)	C load first limb
+	subq	r31,r19,r20
+	s8addq	r18,r16,r16	C make r16 point at end of RES
+	subq	r18,1,r18
+	and	r18,4-1,r28	C number of limbs in first loop
+	srl	r4,r20,r0	C compute function result
+
+	beq	r28,L(L0)
+	subq	r18,r28,r18
+
+	ALIGN(8)
+L(top0):
+	ldq	r3,-16(r17)
+	subq	r16,8,r16
+	sll	r4,r19,r5
+	subq	r17,8,r17
+	subq	r28,1,r28
+	srl	r3,r20,r6
+	bis	r3,r3,r4
+	bis	r5,r6,r8
+	stq	r8,0(r16)
+	bne	r28,L(top0)
+
+L(L0):	sll	r4,r19,r24
+	beq	r18,L(end)
+C warm up phase 1
+	ldq	r1,-16(r17)
+	subq	r18,4,r18
+	ldq	r2,-24(r17)
+	ldq	r3,-32(r17)
+	ldq	r4,-40(r17)
+C warm up phase 2
+	srl	r1,r20,r7
+	sll	r1,r19,r21
+	srl	r2,r20,r8
+	beq	r18,L(end1)
+	ldq	r1,-48(r17)
+	sll	r2,r19,r22
+	ldq	r2,-56(r17)
+	srl	r3,r20,r5
+	bis	r7,r24,r7
+	sll	r3,r19,r23
+	bis	r8,r21,r8
+	srl	r4,r20,r6
+	ldq	r3,-64(r17)
+	sll	r4,r19,r24
+	ldq	r4,-72(r17)
+	subq	r18,4,r18
+	beq	r18,L(end2)
+	ALIGN(16)
+C main loop
+L(top):	stq	r7,-8(r16)
+	bis	r5,r22,r5
+	stq	r8,-16(r16)
+	bis	r6,r23,r6
+
+	srl	r1,r20,r7
+	subq	r18,4,r18
+	sll	r1,r19,r21
+	unop	C ldq	r31,-96(r17)
+
+	srl	r2,r20,r8
+	ldq	r1,-80(r17)
+	sll	r2,r19,r22
+	ldq	r2,-88(r17)
+
+	stq	r5,-24(r16)
+	bis	r7,r24,r7
+	stq	r6,-32(r16)
+	bis	r8,r21,r8
+
+	srl	r3,r20,r5
+	unop	C ldq	r31,-96(r17)
+	sll	r3,r19,r23
+	subq	r16,32,r16
+
+	srl	r4,r20,r6
+	ldq	r3,-96(r17)
+	sll	r4,r19,r24
+	ldq	r4,-104(r17)
+
+	subq	r17,32,r17
+	bne	r18,L(top)
+C cool down phase 2/1
+L(end2):
+	stq	r7,-8(r16)
+	bis	r5,r22,r5
+	stq	r8,-16(r16)
+	bis	r6,r23,r6
+	srl	r1,r20,r7
+	sll	r1,r19,r21
+	srl	r2,r20,r8
+	sll	r2,r19,r22
+	stq	r5,-24(r16)
+	bis	r7,r24,r7
+	stq	r6,-32(r16)
+	bis	r8,r21,r8
+	srl	r3,r20,r5
+	sll	r3,r19,r23
+	srl	r4,r20,r6
+	sll	r4,r19,r24
+C cool down phase 2/2
+	stq	r7,-40(r16)
+	bis	r5,r22,r5
+	stq	r8,-48(r16)
+	bis	r6,r23,r6
+	stq	r5,-56(r16)
+	stq	r6,-64(r16)
+C cool down phase 2/3
+	stq	r24,-72(r16)
+	ret	r31,(r26),1
+
+C cool down phase 1/1
+L(end1):
+	sll	r2,r19,r22
+	srl	r3,r20,r5
+	bis	r7,r24,r7
+	sll	r3,r19,r23
+	bis	r8,r21,r8
+	srl	r4,r20,r6
+	sll	r4,r19,r24
+C cool down phase 1/2
+	stq	r7,-8(r16)
+	bis	r5,r22,r5
+	stq	r8,-16(r16)
+	bis	r6,r23,r6
+	stq	r5,-24(r16)
+	stq	r6,-32(r16)
+	stq	r24,-40(r16)
+	ret	r31,(r26),1
+
+L(end):	stq	r24,-8(r16)
+	ret	r31,(r26),1
+EPILOGUE(mpn_lshift)
+ASM_END()
diff --git a/third_party/gmp/mpn/alpha/mod_34lsub1.asm b/third_party/gmp/mpn/alpha/mod_34lsub1.asm
new file mode 100644
index 0000000..1b03b63
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/mod_34lsub1.asm
@@ -0,0 +1,164 @@
+dnl Alpha mpn_mod_34lsub1.
+
+dnl  Copyright 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C      cycles/limb
+C EV4:     4 (?)
+C EV5:     2.67
+C EV6:     1.67
+
+
+dnl  INPUT PARAMETERS
+dnl  up		r16
+dnl  n		r17
+
+define(`l0',`r18')
+define(`l1',`r19')
+define(`l2',`r20')
+define(`a0',`r21')
+define(`a1',`r22')
+define(`a2',`r23')
+define(`c0',`r24')
+define(`c1',`r5')
+define(`c2',`r6')
+
+ASM_START()
+PROLOGUE(mpn_mod_34lsub1)
+	bis	r31, r31, c0
+	bis	r31, r31, c1
+	bis	r31, r31, c2
+
+	lda	r17, -3(r17)
+	bge	r17, $L_3_or_more
+	bis	r31, r31, a0
+	bis	r31, r31, a1
+	bis	r31, r31, a2
+	br	r31, $L_012
+
+$L_3_or_more:
+	ldq	a0, 0(r16)
+	ldq	a1, 8(r16)
+	ldq	a2, 16(r16)
+	lda	r16, 24(r16)
+	lda	r17, -3(r17)
+	blt	r17, $L_012
+
+$L_6_or_more:
+	ldq	l0, 0(r16)
+	ldq	l1, 8(r16)
+	ldq	l2, 16(r16)
+	addq	l0, a0, a0
+
+	lda	r16, 24(r16)
+	lda	r17, -3(r17)
+	blt	r17, $L_end
+
+	ALIGN(16)
+C Main loop
+$L_9_or_more:
+$Loop:	cmpult	a0, l0, r0
+	ldq	l0, 0(r16)
+	addq	r0, c0, c0
+	addq	l1, a1, a1
+	cmpult	a1, l1, r0
+	ldq	l1, 8(r16)
+	addq	r0, c1, c1
+	addq	l2, a2, a2
+	cmpult	a2, l2, r0
+	ldq	l2, 16(r16)
+	addq	r0, c2, c2
+	addq	l0, a0, a0
+	lda	r16, 24(r16)
+	lda	r17, -3(r17)
+	bge	r17, $Loop
+
+$L_end:	cmpult	a0, l0, r0
+	addq	r0, c0, c0
+	addq	l1, a1, a1
+	cmpult	a1, l1, r0
+	addq	r0, c1, c1
+	addq	l2, a2, a2
+	cmpult	a2, l2, r0
+	addq	r0, c2, c2
+
+C Handle the last (n mod 3) limbs
+$L_012:	lda	r17, 2(r17)
+	blt	r17, $L_0
+	ldq	l0, 0(r16)
+	addq	l0, a0, a0
+	cmpult	a0, l0, r0
+	addq	r0, c0, c0
+	beq	r17, $L_0
+	ldq	l1, 8(r16)
+	addq	l1, a1, a1
+	cmpult	a1, l1, r0
+	addq	r0, c1, c1
+
+C Align and sum our 3 main accumulators and 3 carry accumulators
+$L_0:	srl	a0, 48, r2
+	srl	a1, 32, r4
+ifdef(`HAVE_LIMB_LITTLE_ENDIAN',
+`	insll	a1, 2, r1',		C (a1 & 0xffffffff) << 16
+`	zapnot	a1, 15, r25
+	sll	r25, 16, r1')
+	zapnot	a0, 63, r0		C a0 & 0xffffffffffff
+	srl	a2, 16, a1
+ifdef(`HAVE_LIMB_LITTLE_ENDIAN',
+`	inswl	a2, 4, r3',		C (a2 & 0xffff) << 32
+`	zapnot	a2, 3, r25
+	sll	r25, 32, r3')
+	addq	r1, r4, r1
+	addq	r0, r2, r0
+	srl	c0, 32, a2
+ifdef(`HAVE_LIMB_LITTLE_ENDIAN',
+`	insll	c0, 2, r4',		C (c0 & 0xffffffff) << 16
+`	zapnot	c0, 15, r25
+	sll	r25, 16, r4')
+	addq	r0, r1, r0
+	addq	r3, a1, r3
+	addq	r0, r3, r0
+	srl	c1, 16, c0
+ifdef(`HAVE_LIMB_LITTLE_ENDIAN',
+`	inswl	c1, 4, r2',		C (c1 & 0xffff) << 32
+`	zapnot	c1, 3, r25
+	sll	r25, 32, r2')
+	addq	r4, a2, r4
+C	srl	c2, 48, r3		C This will be 0 in practise
+	zapnot	c2, 63, r1		C r1 = c2 & 0xffffffffffff
+	addq	r0, r4, r0
+	addq	r2, c0, r2
+	addq	r0, r2, r0
+C	addq	r1, r3, r1
+	addq	r0, r1, r0
+
+	ret	r31, (r26), 1
+EPILOGUE(mpn_mod_34lsub1)
+ASM_END()
diff --git a/third_party/gmp/mpn/alpha/mode1o.asm b/third_party/gmp/mpn/alpha/mode1o.asm
new file mode 100644
index 0000000..96dccc7
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/mode1o.asm
@@ -0,0 +1,209 @@
+dnl  Alpha mpn_modexact_1c_odd -- mpn exact remainder
+
+dnl  Copyright 2003, 2004 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C      cycles/limb
+C EV4:    47
+C EV5:    30
+C EV6:    15
+
+
+C mp_limb_t mpn_modexact_1c_odd (mp_srcptr src, mp_size_t size, mp_limb_t d,
+C                                mp_limb_t c)
+C
+C This code follows the "alternate" code in mpn/generic/mode1o.c,
+C eliminating cbit+climb from the dependent chain.  This leaves,
+C
+C        ev4   ev5   ev6
+C         1     3     1    subq   y = x - h
+C        23    13     7    mulq   q = y * inverse
+C        23    14     7    umulh  h = high (q * d)
+C        --    --    --
+C        47    30    15
+C
+C In each case, the load latency, loop control, and extra carry bit handling
+C hide under the multiply latencies.  Those latencies are long enough that
+C we don't need to worry about alignment or pairing to squeeze out
+C performance.
+C
+C For the first limb, some of the loop code is broken out and scheduled back
+C since it can be done earlier.
+C
+C   - The first ldq src[0] is near the start of the routine, for maximum
+C     time from memory.
+C
+C   - The subq y=x-climb can be done without waiting for the inverse.
+C
+C   - The mulq y*inverse is replicated after the final subq for the inverse,
+C     instead of branching to the mulq in the main loop.  On ev4 a branch
+C     there would cost cycles, but we can hide them under the mulq latency.
+C
+C For the last limb, high<divisor is tested and if that's true a subtract
+C and addback is done, as per the main mpn/generic/mode1o.c code.  This is a
+C data-dependent branch, but we're waiting for umulh so any penalty should
+C hide there.  The multiplies saved would be worth the cost anyway.
+C
+C Enhancements:
+C
+C For size==1, a plain division (done bitwise say) might be faster than
+C calculating an inverse, the latter taking about 130 cycles on ev4 or 70 on
+C ev5.  A call to gcc __remqu might be a possibility.
+
+ASM_START()
+PROLOGUE(mpn_modexact_1c_odd,gp)
+
+	C r16	src
+	C r17	size
+	C r18	d
+	C r19	c
+
+	LEA(r0, binvert_limb_table)
+	srl	r18, 1, r20		C d >> 1
+
+	and	r20, 127, r20		C idx = d>>1 & 0x7F
+
+	addq	r0, r20, r21		C table + idx
+
+ifelse(bwx_available_p,1,
+`	ldbu	r20, 0(r21)		C table[idx], inverse 8 bits
+',`
+	ldq_u	r20, 0(r21)		C table[idx] qword
+	extbl	r20, r21, r20		C table[idx], inverse 8 bits
+')
+
+	mull	r20, r20, r7		C i*i
+	addq	r20, r20, r20		C 2*i
+
+	ldq	r2, 0(r16)		C x = s = src[0]
+	lda	r17, -1(r17)		C size--
+	clr	r0			C initial cbit=0
+
+	mull	r7, r18, r7		C i*i*d
+
+	subq	r20, r7, r20		C 2*i-i*i*d, inverse 16 bits
+
+	mull	r20, r20, r7		C i*i
+	addq	r20, r20, r20		C 2*i
+
+	mull	r7, r18, r7		C i*i*d
+
+	subq	r20, r7, r20		C 2*i-i*i*d, inverse 32 bits
+
+	mulq	r20, r20, r7		C i*i
+	addq	r20, r20, r20		C 2*i
+
+	mulq	r7, r18, r7		C i*i*d
+	subq	r2, r19, r3		C y = x - climb
+
+	subq	r20, r7, r20		C inv = 2*i-i*i*d, inverse 64 bits
+
+ASSERT(r7, C should have d*inv==1 mod 2^64
+`	mulq	r18, r20, r7
+	cmpeq	r7, 1, r7')
+
+	mulq	r3, r20, r4		C first q = y * inv
+
+	beq	r17, L(one)		C if size==1
+	br	L(entry)
+
+
+L(top):
+	C r0	cbit
+	C r16	src, incrementing
+	C r17	size, decrementing
+	C r18	d
+	C r19	climb
+	C r20	inv
+
+	ldq	r1, 0(r16)		C s = src[i]
+	subq	r1, r0, r2		C x = s - cbit
+	cmpult	r1, r0, r0		C new cbit = s < cbit
+
+	subq	r2, r19, r3		C y = x - climb
+
+	mulq	r3, r20, r4		C q = y * inv
+L(entry):
+	cmpult	r2, r19, r5		C cbit2 = x < climb
+	addq	r5, r0, r0		C cbit += cbit2
+	lda	r16, 8(r16)		C src++
+	lda	r17, -1(r17)		C size--
+
+	umulh	r4, r18, r19		C climb = q * d
+	bne	r17, L(top)		C while 2 or more limbs left
+
+
+
+	C r0	cbit
+	C r18	d
+	C r19	climb
+	C r20	inv
+
+	ldq	r1, 0(r16)		C s = src[size-1] high limb
+
+	cmpult	r1, r18, r2		C test high<divisor
+	bne	r2, L(skip)		C skip if so
+
+	C can't skip a division, repeat loop code
+
+	subq	r1, r0, r2		C x = s - cbit
+	cmpult	r1, r0, r0		C new cbit = s < cbit
+
+	subq	r2, r19, r3		C y = x - climb
+
+	mulq	r3, r20, r4		C q = y * inv
+L(one):
+	cmpult	r2, r19, r5		C cbit2 = x < climb
+	addq	r5, r0, r0		C cbit += cbit2
+
+	umulh	r4, r18, r19		C climb = q * d
+
+	addq	r19, r0, r0		C return climb + cbit
+	ret	r31, (r26), 1
+
+
+	ALIGN(8)
+L(skip):
+	C with high<divisor, the final step can be just (cbit+climb)-s and
+	C an addback of d if that underflows
+
+	addq	r19, r0, r19		C c = climb + cbit
+
+	subq	r19, r1, r2		C c - s
+	cmpult	r19, r1, r3		C c < s
+
+	addq	r2, r18, r0		C return c-s + divisor
+
+	cmoveq	r3, r2, r0		C return c-s if no underflow
+	ret	r31, (r26), 1
+
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/alpha/mul_1.asm b/third_party/gmp/mpn/alpha/mul_1.asm
new file mode 100644
index 0000000..a7cdbcf
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/mul_1.asm
@@ -0,0 +1,102 @@
+dnl  Alpha mpn_mul_1 -- Multiply a limb vector with a limb and store
+dnl  the result in a second limb vector.
+
+dnl  Copyright 1992, 1994, 1995, 2000, 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C      cycles/limb
+C EV4:     42
+C EV5:     18
+C EV6:      7
+
+C  INPUT PARAMETERS
+C  rp	r16
+C  up	r17
+C  n	r18
+C  vl	r19
+C  cl	r20
+
+
+ASM_START()
+PROLOGUE(mpn_mul_1c)
+	ldq	r2,0(r17)	C r2 = s1_limb
+	lda	r18,-1(r18)	C size--
+	mulq	r2,r19,r3	C r3 = prod_low
+	umulh	r2,r19,r4	C r4 = prod_high
+	beq	r18,$Le1c	C jump if size was == 1
+	ldq	r2,8(r17)	C r2 = s1_limb
+	lda	r18,-1(r18)	C size--
+	addq	r3,r20,r3	C r3 = cy_limb + cl
+	stq	r3,0(r16)
+	cmpult	r3,r20,r0	C r0 = carry from (cy_limb + cl)
+	bne	r18,$Loop	C jump if size was == 2
+	br	r31,$Le2
+$Le1c:	addq	r3,r20,r3	C r3 = cy_limb + cl
+	cmpult	r3,r20,r0	C r0 = carry from (cy_limb + cl)
+$Le1:	stq	r3,0(r16)
+	addq	r4,r0,r0
+	ret	r31,(r26),1
+EPILOGUE(mpn_mul_1c)
+
+PROLOGUE(mpn_mul_1)
+	ldq	r2,0(r17)	C r2 = s1_limb
+	lda	r18,-1(r18)	C size--
+	mulq	r2,r19,r3	C r3 = prod_low
+	bic	r31,r31,r0	C clear cy_limb
+	umulh	r2,r19,r4	C r4 = prod_high
+	beq	r18,$Le1	C jump if size was == 1
+	ldq	r2,8(r17)	C r2 = s1_limb
+	lda	r18,-1(r18)	C size--
+	stq	r3,0(r16)
+	beq	r18,$Le2	C jump if size was == 2
+
+	ALIGN(8)
+$Loop:	mulq	r2,r19,r3	C r3 = prod_low
+	addq	r4,r0,r0	C cy_limb = cy_limb + 'cy'
+	lda	r18,-1(r18)	C size--
+	umulh	r2,r19,r4	C r4 = prod_high
+	ldq	r2,16(r17)	C r2 = s1_limb
+	lda	r17,8(r17)	C s1_ptr++
+	addq	r3,r0,r3	C r3 = cy_limb + prod_low
+	stq	r3,8(r16)
+	cmpult	r3,r0,r0	C r0 = carry from (cy_limb + prod_low)
+	lda	r16,8(r16)	C res_ptr++
+	bne	r18,$Loop
+
+$Le2:	mulq	r2,r19,r3	C r3 = prod_low
+	addq	r4,r0,r0	C cy_limb = cy_limb + 'cy'
+	umulh	r2,r19,r4	C r4 = prod_high
+	addq	r3,r0,r3	C r3 = cy_limb + prod_low
+	cmpult	r3,r0,r0	C r0 = carry from (cy_limb + prod_low)
+	stq	r3,8(r16)
+	addq	r4,r0,r0	C cy_limb = prod_high + cy
+	ret	r31,(r26),1
+EPILOGUE(mpn_mul_1)
+ASM_END()
diff --git a/third_party/gmp/mpn/alpha/rshift.asm b/third_party/gmp/mpn/alpha/rshift.asm
new file mode 100644
index 0000000..6e1e214
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/rshift.asm
@@ -0,0 +1,180 @@
+dnl  Alpha mpn_rshift -- Shift a number right.
+
+dnl  Copyright 1994, 1995, 2000, 2009 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C      cycles/limb
+C EV4:     ?
+C EV5:     3.25
+C EV6:     1.75
+
+C  INPUT PARAMETERS
+C  rp	r16
+C  up	r17
+C  n	r18
+C  cnt	r19
+
+
+ASM_START()
+PROLOGUE(mpn_rshift)
+	ldq	r4,0(r17)	C load first limb
+	subq	r31,r19,r20
+	subq	r18,1,r18
+	and	r18,4-1,r28	C number of limbs in first loop
+	sll	r4,r20,r0	C compute function result
+
+	beq	r28,L(L0)
+	subq	r18,r28,r18
+
+	ALIGN(8)
+L(top0):
+	ldq	r3,8(r17)
+	addq	r16,8,r16
+	srl	r4,r19,r5
+	addq	r17,8,r17
+	subq	r28,1,r28
+	sll	r3,r20,r6
+	bis	r3,r3,r4
+	bis	r5,r6,r8
+	stq	r8,-8(r16)
+	bne	r28,L(top0)
+
+L(L0):	srl	r4,r19,r24
+	beq	r18,L(end)
+C warm up phase 1
+	ldq	r1,8(r17)
+	subq	r18,4,r18
+	ldq	r2,16(r17)
+	ldq	r3,24(r17)
+	ldq	r4,32(r17)
+C warm up phase 2
+	sll	r1,r20,r7
+	srl	r1,r19,r21
+	sll	r2,r20,r8
+	beq	r18,L(end1)
+	ldq	r1,40(r17)
+	srl	r2,r19,r22
+	ldq	r2,48(r17)
+	sll	r3,r20,r5
+	bis	r7,r24,r7
+	srl	r3,r19,r23
+	bis	r8,r21,r8
+	sll	r4,r20,r6
+	ldq	r3,56(r17)
+	srl	r4,r19,r24
+	ldq	r4,64(r17)
+	subq	r18,4,r18
+	beq	r18,L(end2)
+	ALIGN(16)
+C main loop
+L(top):	stq	r7,0(r16)
+	bis	r5,r22,r5
+	stq	r8,8(r16)
+	bis	r6,r23,r6
+
+	sll	r1,r20,r7
+	subq	r18,4,r18
+	srl	r1,r19,r21
+	unop	C ldq	r31,-96(r17)
+
+	sll	r2,r20,r8
+	ldq	r1,72(r17)
+	srl	r2,r19,r22
+	ldq	r2,80(r17)
+
+	stq	r5,16(r16)
+	bis	r7,r24,r7
+	stq	r6,24(r16)
+	bis	r8,r21,r8
+
+	sll	r3,r20,r5
+	unop	C ldq	r31,-96(r17)
+	srl	r3,r19,r23
+	addq	r16,32,r16
+
+	sll	r4,r20,r6
+	ldq	r3,88(r17)
+	srl	r4,r19,r24
+	ldq	r4,96(r17)
+
+	addq	r17,32,r17
+	bne	r18,L(top)
+C cool down phase 2/1
+L(end2):
+	stq	r7,0(r16)
+	bis	r5,r22,r5
+	stq	r8,8(r16)
+	bis	r6,r23,r6
+	sll	r1,r20,r7
+	srl	r1,r19,r21
+	sll	r2,r20,r8
+	srl	r2,r19,r22
+	stq	r5,16(r16)
+	bis	r7,r24,r7
+	stq	r6,24(r16)
+	bis	r8,r21,r8
+	sll	r3,r20,r5
+	srl	r3,r19,r23
+	sll	r4,r20,r6
+	srl	r4,r19,r24
+C cool down phase 2/2
+	stq	r7,32(r16)
+	bis	r5,r22,r5
+	stq	r8,40(r16)
+	bis	r6,r23,r6
+	stq	r5,48(r16)
+	stq	r6,56(r16)
+C cool down phase 2/3
+	stq	r24,64(r16)
+	ret	r31,(r26),1
+
+C cool down phase 1/1
+L(end1):
+	srl	r2,r19,r22
+	sll	r3,r20,r5
+	bis	r7,r24,r7
+	srl	r3,r19,r23
+	bis	r8,r21,r8
+	sll	r4,r20,r6
+	srl	r4,r19,r24
+C cool down phase 1/2
+	stq	r7,0(r16)
+	bis	r5,r22,r5
+	stq	r8,8(r16)
+	bis	r6,r23,r6
+	stq	r5,16(r16)
+	stq	r6,24(r16)
+	stq	r24,32(r16)
+	ret	r31,(r26),1
+
+L(end):	stq	r24,0(r16)
+	ret	r31,(r26),1
+EPILOGUE(mpn_rshift)
+ASM_END()
diff --git a/third_party/gmp/mpn/alpha/sec_tabselect.asm b/third_party/gmp/mpn/alpha/sec_tabselect.asm
new file mode 100644
index 0000000..679b169
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/sec_tabselect.asm
@@ -0,0 +1,137 @@
+dnl  Alpha mpn_sec_tabselect.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C      cycles/limb
+C EV4:      ?
+C EV5:      2.25
+C EV6:      1.64
+
+define(`rp',     `r16')
+define(`tp',     `r17')
+define(`n',      `r18')
+define(`nents',  `r19')
+define(`which',  `r20')
+
+define(`i',      `r21')
+define(`j',      `r22')
+define(`stride', `r23')
+define(`mask',   `r24')
+define(`k',      `r25')
+
+
+ASM_START()
+PROLOGUE(mpn_sec_tabselect)
+	subq	n, 4, j			C outer loop induction variable
+
+	blt	j, L(outer_end)
+L(outer_top):
+	mov	tp, r8
+	lda	r0, 0(r31)
+	lda	r1, 0(r31)
+	lda	r2, 0(r31)
+	lda	r3, 0(r31)
+	subq	j, 4, j			C outer loop induction variable
+	subq	nents, which, k
+	mov	nents, i
+
+	ALIGN(16)
+L(top):	ldq	r4, 0(tp)
+	ldq	r5, 8(tp)
+	cmpeq	k, i, mask
+	subq	i, 1, i
+	subq	r31, mask, mask
+	ldq	r6, 16(tp)
+	ldq	r7, 24(tp)
+	and	r4, mask, r4
+	and	r5, mask, r5
+	or	r0, r4, r0
+	or	r1, r5, r1
+	and	r6, mask, r6
+	and	r7, mask, r7
+	or	r2, r6, r2
+	or	r3, r7, r3
+	s8addq	n, tp, tp
+	bne	i, L(top)
+
+	stq	r0, 0(rp)
+	stq	r1, 8(rp)
+	stq	r2, 16(rp)
+	stq	r3, 24(rp)
+	addq	r8, 32, tp
+	addq	rp, 32, rp
+	bge	j, L(outer_top)
+L(outer_end):
+
+	and	n, 2, r0
+	beq	r0, L(b0x)
+L(b1x):	mov	tp, r8
+	lda	r0, 0(r31)
+	lda	r1, 0(r31)
+	subq	nents, which, k
+	mov	nents, i
+	ALIGN(16)
+L(tp2):	ldq	r4, 0(tp)
+	ldq	r5, 8(tp)
+	cmpeq	k, i, mask
+	subq	i, 1, i
+	subq	r31, mask, mask
+	and	r4, mask, r4
+	and	r5, mask, r5
+	or	r0, r4, r0
+	or	r1, r5, r1
+	s8addq	n, tp, tp
+	bne	i, L(tp2)
+	stq	r0, 0(rp)
+	stq	r1, 8(rp)
+	addq	r8, 16, tp
+	addq	rp, 16, rp
+
+L(b0x):	and	n, 1, r0
+	beq	r0, L(b00)
+L(b01):	lda	r0, 0(r31)
+	subq	nents, which, k
+	mov	nents, i
+	ALIGN(16)
+L(tp1):	ldq	r4, 0(tp)
+	cmpeq	k, i, mask
+	subq	i, 1, i
+	subq	r31, mask, mask
+	and	r4, mask, r4
+	or	r0, r4, r0
+	s8addq	n, tp, tp
+	bne	i, L(tp1)
+	stq	r0, 0(rp)
+
+L(b00):	ret	r31, (r26), 1
+EPILOGUE()
diff --git a/third_party/gmp/mpn/alpha/sqr_diag_addlsh1.asm b/third_party/gmp/mpn/alpha/sqr_diag_addlsh1.asm
new file mode 100644
index 0000000..ee219ef
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/sqr_diag_addlsh1.asm
@@ -0,0 +1,93 @@
+dnl  Alpha mpn_sqr_diag_addlsh1.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C      cycles/limb
+C EV4:      ?
+C EV5:     10.2
+C EV6:      4.5
+
+C Ideally, one-way code could run at 9 c/l (limited by mulq+umulh) on ev5 and
+C about 3.75 c/l on ev6.  Two-way code could run at about 3.25 c/l on ev6.
+
+C Algorithm: We allow ourselves to propagate carry to a product high word
+C without worrying for carry out, since (B-1)^2 = B^2-2B+1 has a high word of
+C B-2, i.e, will not spill.  We propagate carry similarly to a product low word
+C since the problem value B-1 is a quadratic non-residue mod B, but our
+C products are squares.
+
+define(`rp',	`r16')
+define(`tp',	`r17')
+define(`up',	`r18')
+define(`n',	`r19')
+
+ASM_START()
+PROLOGUE(mpn_sqr_diag_addlsh1)
+	ldq	r0, 0(up)
+	bis	r31, r31, r21
+	bis	r31, r31, r3
+	mulq	r0, r0, r7
+	stq	r7, 0(rp)
+	umulh	r0, r0, r6
+	lda	n, -1(n)
+
+	ALIGN(16)
+L(top):	ldq	r0, 8(up)
+	lda	up, 8(up)
+	ldq	r8, 0(tp)
+	ldq	r20, 8(tp)
+	mulq	r0, r0, r7
+	lda	tp, 16(tp)
+	sll	r8, 1, r23
+	srl	r8, 63, r22
+	or	r21, r23, r23
+	sll	r20, 1, r24
+	addq	r3, r6, r6		C cannot carry per comment above
+	or	r22, r24, r24
+	addq	r23, r6, r21
+	umulh	r0, r0, r6
+	cmpult	r21, r23, r1
+	addq	r1, r7, r7		C cannot carry per comment above
+	stq	r21, 8(rp)
+	addq	r24, r7, r22
+	stq	r22, 16(rp)
+	lda	n, -1(n)
+	cmpult	r22, r7, r3
+	srl	r20, 63, r21
+	lda	rp, 16(rp)
+	bne	n, L(top)
+
+	addq	r3, r6, r6		C cannot carry per comment above
+	addq	r21, r6, r21
+	stq	r21, 8(rp)
+	ret	r31, (r26), 1
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/alpha/sub_n.asm b/third_party/gmp/mpn/alpha/sub_n.asm
new file mode 100644
index 0000000..1bb7226
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/sub_n.asm
@@ -0,0 +1,164 @@
+dnl  Alpha mpn_sub_n -- Subtract two limb vectors of the same length > 0
+dnl  and store difference in a third limb vector.
+
+dnl  Copyright 1995, 1999, 2000, 2005, 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C      cycles/limb
+C EV4:     ?
+C EV5:     4.75
+C EV6:     3
+
+dnl  INPUT PARAMETERS
+dnl  res_ptr	r16
+dnl  s1_ptr	r17
+dnl  s2_ptr	r18
+dnl  size	r19
+
+ASM_START()
+PROLOGUE(mpn_sub_nc)
+	bis	r31,r20,r25
+	br	L(com)
+EPILOGUE()
+PROLOGUE(mpn_sub_n)
+	bis	r31,r31,r25		C clear cy
+L(com):	subq	r19,4,r19		C decr loop cnt
+	blt	r19,$Lend2		C if less than 4 limbs, goto 2nd loop
+C Start software pipeline for 1st loop
+	ldq	r0,0(r18)
+	ldq	r4,0(r17)
+	ldq	r1,8(r18)
+	ldq	r5,8(r17)
+	addq	r17,32,r17		C update s1_ptr
+	subq	r4,r0,r28		C 1st main subtract
+	ldq	r2,16(r18)
+	subq	r28,r25,r20		C 1st carry subtract
+	ldq	r3,24(r18)
+	cmpult	r4,r0,r8		C compute cy from last subtract
+	ldq	r6,-16(r17)
+	cmpult	r28,r25,r25		C compute cy from last subtract
+	ldq	r7,-8(r17)
+	bis	r8,r25,r25		C combine cy from the two subtracts
+	subq	r19,4,r19		C decr loop cnt
+	subq	r5,r1,r28		C 2nd main subtract
+	addq	r18,32,r18		C update s2_ptr
+	subq	r28,r25,r21		C 2nd carry subtract
+	cmpult	r5,r1,r8		C compute cy from last subtract
+	blt	r19,$Lend1		C if less than 4 limbs remain, jump
+C 1st loop handles groups of 4 limbs in a software pipeline
+	ALIGN(16)
+$Loop:	cmpult	r28,r25,r25		C compute cy from last subtract
+	ldq	r0,0(r18)
+	bis	r8,r25,r25		C combine cy from the two subtracts
+	ldq	r1,8(r18)
+	subq	r6,r2,r28		C 3rd main subtract
+	ldq	r4,0(r17)
+	subq	r28,r25,r22		C 3rd carry subtract
+	ldq	r5,8(r17)
+	cmpult	r6,r2,r8		C compute cy from last subtract
+	cmpult	r28,r25,r25		C compute cy from last subtract
+	stq	r20,0(r16)
+	bis	r8,r25,r25		C combine cy from the two subtracts
+	stq	r21,8(r16)
+	subq	r7,r3,r28		C 4th main subtract
+	subq	r28,r25,r23		C 4th carry subtract
+	cmpult	r7,r3,r8		C compute cy from last subtract
+	cmpult	r28,r25,r25		C compute cy from last subtract
+		addq	r17,32,r17		C update s1_ptr
+	bis	r8,r25,r25		C combine cy from the two subtracts
+		addq	r16,32,r16		C update res_ptr
+	subq	r4,r0,r28		C 1st main subtract
+	ldq	r2,16(r18)
+	subq	r28,r25,r20		C 1st carry subtract
+	ldq	r3,24(r18)
+	cmpult	r4,r0,r8		C compute cy from last subtract
+	ldq	r6,-16(r17)
+	cmpult	r28,r25,r25		C compute cy from last subtract
+	ldq	r7,-8(r17)
+	bis	r8,r25,r25		C combine cy from the two subtracts
+	subq	r19,4,r19		C decr loop cnt
+	stq	r22,-16(r16)
+	subq	r5,r1,r28		C 2nd main subtract
+	stq	r23,-8(r16)
+	subq	r28,r25,r21		C 2nd carry subtract
+		addq	r18,32,r18		C update s2_ptr
+	cmpult	r5,r1,r8		C compute cy from last subtract
+	bge	r19,$Loop
+C Finish software pipeline for 1st loop
+$Lend1:	cmpult	r28,r25,r25		C compute cy from last subtract
+	bis	r8,r25,r25		C combine cy from the two subtracts
+	subq	r6,r2,r28		C cy add
+	subq	r28,r25,r22		C 3rd main subtract
+	cmpult	r6,r2,r8		C compute cy from last subtract
+	cmpult	r28,r25,r25		C compute cy from last subtract
+	stq	r20,0(r16)
+	bis	r8,r25,r25		C combine cy from the two subtracts
+	stq	r21,8(r16)
+	subq	r7,r3,r28		C cy add
+	subq	r28,r25,r23		C 4th main subtract
+	cmpult	r7,r3,r8		C compute cy from last subtract
+	cmpult	r28,r25,r25		C compute cy from last subtract
+	bis	r8,r25,r25		C combine cy from the two subtracts
+	addq	r16,32,r16		C update res_ptr
+	stq	r22,-16(r16)
+	stq	r23,-8(r16)
+$Lend2:	addq	r19,4,r19		C restore loop cnt
+	beq	r19,$Lret
+C Start software pipeline for 2nd loop
+	ldq	r0,0(r18)
+	ldq	r4,0(r17)
+	subq	r19,1,r19
+	beq	r19,$Lend0
+C 2nd loop handles remaining 1-3 limbs
+	ALIGN(16)
+$Loop0:	subq	r4,r0,r28		C main subtract
+	cmpult	r4,r0,r8		C compute cy from last subtract
+	ldq	r0,8(r18)
+	ldq	r4,8(r17)
+	subq	r28,r25,r20		C carry subtract
+	addq	r18,8,r18
+	addq	r17,8,r17
+	stq	r20,0(r16)
+	cmpult	r28,r25,r25		C compute cy from last subtract
+	subq	r19,1,r19		C decr loop cnt
+	bis	r8,r25,r25		C combine cy from the two subtracts
+	addq	r16,8,r16
+	bne	r19,$Loop0
+$Lend0:	subq	r4,r0,r28		C main subtract
+	subq	r28,r25,r20		C carry subtract
+	cmpult	r4,r0,r8		C compute cy from last subtract
+	cmpult	r28,r25,r25		C compute cy from last subtract
+	stq	r20,0(r16)
+	bis	r8,r25,r25		C combine cy from the two subtracts
+
+$Lret:	bis	r25,r31,r0		C return cy
+	ret	r31,(r26),1
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/alpha/submul_1.asm b/third_party/gmp/mpn/alpha/submul_1.asm
new file mode 100644
index 0000000..2b63b52
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/submul_1.asm
@@ -0,0 +1,99 @@
+dnl  Alpha mpn_submul_1 -- Multiply a limb vector with a limb and subtract
+dnl  the result from a second limb vector.
+
+dnl  Copyright 1992, 1994, 1995, 2000, 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C      cycles/limb
+C EV4:     42
+C EV5:     18
+C EV6:      7
+
+C  INPUT PARAMETERS
+C  rp	r16
+C  up	r17
+C  n	r18
+C  limb	r19
+
+
+ASM_START()
+PROLOGUE(mpn_submul_1)
+	ldq	r2,0(r17)	C r2 = s1_limb
+	addq	r17,8,r17	C s1_ptr++
+	subq	r18,1,r18	C size--
+	mulq	r2,r19,r3	C r3 = prod_low
+	ldq	r5,0(r16)	C r5 = *res_ptr
+	umulh	r2,r19,r0	C r0 = prod_high
+	beq	r18,$Lend1	C jump if size was == 1
+	ldq	r2,0(r17)	C r2 = s1_limb
+	addq	r17,8,r17	C s1_ptr++
+	subq	r18,1,r18	C size--
+	subq	r5,r3,r3
+	cmpult	r5,r3,r4
+	stq	r3,0(r16)
+	addq	r16,8,r16	C res_ptr++
+	beq	r18,$Lend2	C jump if size was == 2
+
+	ALIGN(8)
+$Loop:	mulq	r2,r19,r3	C r3 = prod_low
+	ldq	r5,0(r16)	C r5 = *res_ptr
+	addq	r4,r0,r0	C cy_limb = cy_limb + 'cy'
+	subq	r18,1,r18	C size--
+	umulh	r2,r19,r4	C r4 = cy_limb
+	ldq	r2,0(r17)	C r2 = s1_limb
+	addq	r17,8,r17	C s1_ptr++
+	addq	r3,r0,r3	C r3 = cy_limb + prod_low
+	cmpult	r3,r0,r0	C r0 = carry from (cy_limb + prod_low)
+	subq	r5,r3,r3
+	cmpult	r5,r3,r5
+	stq	r3,0(r16)
+	addq	r16,8,r16	C res_ptr++
+	addq	r5,r0,r0	C combine carries
+	bne	r18,$Loop
+
+$Lend2:	mulq	r2,r19,r3	C r3 = prod_low
+	ldq	r5,0(r16)	C r5 = *res_ptr
+	addq	r4,r0,r0	C cy_limb = cy_limb + 'cy'
+	umulh	r2,r19,r4	C r4 = cy_limb
+	addq	r3,r0,r3	C r3 = cy_limb + prod_low
+	cmpult	r3,r0,r0	C r0 = carry from (cy_limb + prod_low)
+	subq	r5,r3,r3
+	cmpult	r5,r3,r5
+	stq	r3,0(r16)
+	addq	r5,r0,r0	C combine carries
+	addq	r4,r0,r0	C cy_limb = prod_high + cy
+	ret	r31,(r26),1
+$Lend1:	subq	r5,r3,r3
+	cmpult	r5,r3,r5
+	stq	r3,0(r16)
+	addq	r0,r5,r0
+	ret	r31,(r26),1
+EPILOGUE(mpn_submul_1)
+ASM_END()
diff --git a/third_party/gmp/mpn/alpha/umul.asm b/third_party/gmp/mpn/alpha/umul.asm
new file mode 100644
index 0000000..039081e
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/umul.asm
@@ -0,0 +1,44 @@
+dnl  mpn_umul_ppmm -- 1x1->2 limb multiplication
+
+dnl  Copyright 1999, 2000, 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C mp_limb_t mpn_umul_ppmm (mp_limb_t *lowptr, mp_limb_t m1, mp_limb_t m2);
+C
+
+ASM_START()
+PROLOGUE(mpn_umul_ppmm)
+	mulq	r17, r18, r1
+	umulh	r17, r18, r0
+	stq	r1, 0(r16)
+	ret	r31, (r26), 1
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/alpha/unicos.m4 b/third_party/gmp/mpn/alpha/unicos.m4
new file mode 100644
index 0000000..e05cf5c
--- /dev/null
+++ b/third_party/gmp/mpn/alpha/unicos.m4
@@ -0,0 +1,131 @@
+divert(-1)
+
+dnl  m4 macros for alpha assembler on unicos.
+
+
+dnl  Copyright 2000, 2002-2004, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+dnl  Note that none of the standard GMP_ASM_ autoconf tests are done for
+dnl  unicos, so none of the config.m4 results can be used here.
+
+dnl  No underscores on unicos
+define(`GSYM_PREFIX')
+
+define(`ASM_START',
+m4_assert_numargs(0)
+`	.ident	dummy')
+
+define(`X',
+m4_assert_numargs(1)
+`^X$1')
+
+define(`FLOAT64',
+m4_assert_numargs(2)
+`	.psect	$1@crud,data
+$1:	.t_floating $2
+	.endp')
+
+dnl  Called: PROLOGUE_cpu(GSYM_PREFIX`'foo[,gp|noalign])
+dnl          EPILOGUE_cpu(GSYM_PREFIX`'foo)
+
+define(`PROLOGUE_cpu',
+m4_assert_numargs_range(1,2)
+`ifelse(`$2',gp,,
+`ifelse(`$2',noalign,,
+`ifelse(`$2',,,`m4_error(`Unrecognised PROLOGUE parameter
+')')')')dnl
+	.stack	192		; What does this mean?  Only Cray knows.
+	.psect	$1@code,code,cache
+$1::')
+
+define(`EPILOGUE_cpu',
+m4_assert_numargs(1)
+`	.endp')
+
+
+dnl  Usage: LDGP(dst,src)
+dnl
+dnl  Emit an "ldgp dst,src", but only on systems using a GOT (which unicos
+dnl  doesn't).
+
+define(LDGP,
+m4_assert_numargs(2)
+)
+
+
+dnl  Usage: EXTERN(variable_name)
+define(`EXTERN',
+m4_assert_numargs(1)
+`	.extern	$1')
+
+define(`DATASTART',
+m4_assert_numargs_range(1,2)
+`	.psect	$1@crud,data
+	ALIGN(ifelse($#,1,2,$2))
+$1:')
+
+define(`DATAEND',
+m4_assert_numargs(0)
+`	.endp')
+
+define(`ASM_END',
+m4_assert_numargs(0)
+`	.end')
+
+define(`cvttqc',
+m4_assert_numargs(-1)
+`cvttq/c')
+
+dnl  Load a symbolic address into a register
+define(`LEA',
+m4_assert_numargs(2)
+	`laum	$1,  $2(r31)
+	sll	$1,  32,   $1
+	lalm	$1,  $2($1)
+	lal	$1,  $2($1)')
+
+
+dnl  Usage: ALIGN(bytes)
+dnl
+dnl  Unicos assembler .align emits zeros, even in code segments, so disable
+dnl  aligning.
+dnl
+dnl  GCC uses a macro emiting nops until the desired alignment is reached
+dnl  (see unicosmk_file_start in alpha.c).  Could do something like that if
+dnl  we cared.  The maximum desired alignment must be established at the
+dnl  start of the section though, since of course emitting nops only
+dnl  advances relative to the section beginning.
+
+define(`ALIGN',
+m4_assert_numargs(1)
+)
+
+
+divert
diff --git a/third_party/gmp/mpn/arm/README b/third_party/gmp/mpn/arm/README
new file mode 100644
index 0000000..53c7214
--- /dev/null
+++ b/third_party/gmp/mpn/arm/README
@@ -0,0 +1,35 @@
+Copyright 2002, 2012, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.
+
+
+
+
+
+This directory contains mpn functions for ARM processors.  It has been
+optimised mainly for Cortex-A9 and Cortex-A15, but the code in the top-level
+directory should run on all ARM processors at architecture level v4 or later.
diff --git a/third_party/gmp/mpn/arm/aors_n.asm b/third_party/gmp/mpn/arm/aors_n.asm
new file mode 100644
index 0000000..fdad9f7
--- /dev/null
+++ b/third_party/gmp/mpn/arm/aors_n.asm
@@ -0,0 +1,112 @@
+dnl  ARM mpn_add_n and mpn_sub_n
+
+dnl  Contributed to the GNU project by Robert Harley.
+
+dnl  Copyright 1997, 2000, 2001, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C StrongARM	 ?
+C XScale	 ?
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 2.5	slightly fluctuating
+C Cortex-A15	 2.25
+
+define(`rp', `r0')
+define(`up', `r1')
+define(`vp', `r2')
+define(`n',  `r3')
+
+ifdef(`OPERATION_add_n', `
+  define(`ADDSUB',	adds)
+  define(`ADDSUBC',	adcs)
+  define(`CLRCY',	`cmn	r0, #0')
+  define(`SETCY',	`cmp	$1, #1')
+  define(`RETVAL',	`adc	r0, n, #0')
+  define(`func',	mpn_add_n)
+  define(`func_nc',	mpn_add_nc)')
+ifdef(`OPERATION_sub_n', `
+  define(`ADDSUB',	subs)
+  define(`ADDSUBC',	sbcs)
+  define(`CLRCY',	`cmp	r0, r0')
+  define(`SETCY',	`rsbs	$1, $1, #0')
+  define(`RETVAL',	`sbc	r0, r0, r0
+			and	r0, r0, #1')
+  define(`func',	mpn_sub_n)
+  define(`func_nc',	mpn_sub_nc)')
+
+MULFUNC_PROLOGUE(mpn_add_n mpn_add_nc mpn_sub_n mpn_sub_nc)
+
+ASM_START()
+PROLOGUE(func_nc)
+	ldr	r12, [sp, #0]
+	stmfd	sp!, { r8, r9, lr }
+	SETCY(	r12)
+	b	L(ent)
+EPILOGUE()
+PROLOGUE(func)
+	stmfd	sp!, { r8, r9, lr }
+	CLRCY(	r12)
+L(ent):	tst	n, #1
+	beq	L(skip1)
+	ldr	r12, [up], #4
+	ldr	lr, [vp], #4
+	ADDSUBC	r12, r12, lr
+	str	r12, [rp], #4
+L(skip1):
+	tst	n, #2
+	beq	L(skip2)
+	ldmia	up!, { r8, r9 }
+	ldmia	vp!, { r12, lr }
+	ADDSUBC	r8, r8, r12
+	ADDSUBC	r9, r9, lr
+	stmia	rp!, { r8, r9 }
+L(skip2):
+	bics	n, n, #3
+	beq	L(rtn)
+	stmfd	sp!, { r4, r5, r6, r7 }
+
+L(top):	ldmia	up!, { r4, r5, r6, r7 }
+	ldmia	vp!, { r8, r9, r12, lr }
+	ADDSUBC	r4, r4, r8
+	sub	n, n, #4
+	ADDSUBC	r5, r5, r9
+	ADDSUBC	r6, r6, r12
+	ADDSUBC	r7, r7, lr
+	stmia	rp!, { r4, r5, r6, r7 }
+	teq	n, #0
+	bne	L(top)
+
+	ldmfd	sp!, { r4, r5, r6, r7 }
+
+L(rtn):	RETVAL
+	ldmfd	sp!, { r8, r9, pc }
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/aorslsh1_n.asm b/third_party/gmp/mpn/arm/aorslsh1_n.asm
new file mode 100644
index 0000000..889e654
--- /dev/null
+++ b/third_party/gmp/mpn/arm/aorslsh1_n.asm
@@ -0,0 +1,167 @@
+dnl  ARM mpn_addlsh1_n and mpn_sublsh1_n
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	      addlsh1_n       sublsh1_n
+C	     cycles/limb     cycles/limb
+C StrongARM	 ?		 ?
+C XScale	 ?		 ?
+C Cortex-A7	 ?		 ?
+C Cortex-A8	 ?		 ?
+C Cortex-A9	 3.12		 3.7
+C Cortex-A15	 ?		 ?
+
+C TODO
+C  * The addlsh1_n code runs well, but is only barely faster than mpn_addmul_1.
+C    The sublsh1_n code could surely be tweaked, its REVCY slows down things
+C    very much.  If two insns are really needed, it might help to separate them
+C    for better micro-parallelism.
+
+define(`rp', `r0')
+define(`up', `r1')
+define(`vp', `r2')
+define(`n',  `r3')
+
+ifdef(`OPERATION_addlsh1_n', `
+  define(`ADDSUB',	adds)
+  define(`ADDSUBC',	adcs)
+  define(`SETCY',	`cmp	$1, #1')
+  define(`RETVAL',	`adc	r0, $1, #2')
+  define(`SAVECY',	`sbc	$1, $2, #0')
+  define(`RESTCY',	`cmn	$1, #1')
+  define(`REVCY',	`')
+  define(`INICYR',	`mov	$1, #0')
+  define(`r10r11',	`r11')
+  define(`func',	mpn_addlsh1_n)
+  define(`func_nc',	mpn_addlsh1_nc)')
+ifdef(`OPERATION_sublsh1_n', `
+  define(`ADDSUB',	subs)
+  define(`ADDSUBC',	sbcs)
+  define(`SETCY',	`rsbs	$1, $1, #0')
+  define(`RETVAL',	`adc	r0, $1, #1')
+  define(`SAVECY',	`sbc	$1, $1, $1')
+  define(`RESTCY',	`cmn	$1, #1')
+  define(`REVCY',	`sbc	$1, $1, $1
+			cmn	$1, #1')
+  define(`INICYR',	`mvn	$1, #0')
+  define(`r10r11',	`r10')
+  define(`func',	mpn_sublsh1_n)
+  define(`func_nc',	mpn_sublsh1_nc)')
+
+MULFUNC_PROLOGUE(mpn_addlsh1_n mpn_sublsh1_n)
+
+ASM_START()
+PROLOGUE(func)
+	push	{r4-r10r11, r14}
+
+ifdef(`OPERATION_addlsh1_n', `
+	mvn	r11, #0
+')
+	INICYR(	r14)
+	subs	n, n, #3
+	blt	L(le2)			C carry clear on branch path
+
+	cmn	r0, #0			C clear carry
+	ldmia	vp!, {r8, r9, r10}
+	b	L(mid)
+
+L(top):	RESTCY(	r14)
+	ADDSUBC	r4, r4, r8
+	ADDSUBC	r5, r5, r9
+	ADDSUBC	r6, r6, r10
+	ldmia	vp!, {r8, r9, r10}
+	stmia	rp!, {r4, r5, r6}
+	REVCY(r14)
+	adcs	r8, r8, r8
+	adcs	r9, r9, r9
+	adcs	r10, r10, r10
+	ldmia	up!, {r4, r5, r6}
+	SAVECY(	r14, r11)
+	subs	n, n, #3
+	blt	L(exi)
+	RESTCY(	r12)
+	ADDSUBC	r4, r4, r8
+	ADDSUBC	r5, r5, r9
+	ADDSUBC	r6, r6, r10
+	ldmia	vp!, {r8, r9, r10}
+	stmia	rp!, {r4, r5, r6}
+	REVCY(r12)
+L(mid):	adcs	r8, r8, r8
+	adcs	r9, r9, r9
+	adcs	r10, r10, r10
+	ldmia	up!, {r4, r5, r6}
+	SAVECY(	r12, r11)
+	subs	n, n, #3
+	bge	L(top)
+
+	mov	r7, r12			C swap alternating...
+	mov	r12, r14		C ...carry-save...
+	mov	r14, r7			C ...registers
+
+L(exi):	RESTCY(	r12)
+	ADDSUBC	r4, r4, r8
+	ADDSUBC	r5, r5, r9
+	ADDSUBC	r6, r6, r10
+	stmia	rp!, {r4, r5, r6}
+
+	REVCY(r12)
+L(le2):	tst	n, #1			C n = {-1,-2,-3} map to [2], [1], [0]
+	beq	L(e1)
+
+L(e02):	tst	n, #2
+	beq	L(rt0)
+	ldm	vp, {r8, r9}
+	adcs	r8, r8, r8
+	adcs	r9, r9, r9
+	ldm	up, {r4, r5}
+	SAVECY(	r12, r11)
+	RESTCY(	r14)
+	ADDSUBC	r4, r4, r8
+	ADDSUBC	r5, r5, r9
+	stm	rp, {r4, r5}
+	b	L(rt1)
+
+L(e1):	ldr	r8, [vp]
+	adcs	r8, r8, r8
+	ldr	r4, [up]
+	SAVECY(	r12, r11)
+	RESTCY(	r14)
+	ADDSUBC	r4, r4, r8
+	str	r4, [rp]
+
+L(rt1):	mov	r14, r12
+	REVCY(r12)
+L(rt0):	RETVAL(	r14)
+	pop	{r4-r10r11, r14}
+	return	r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/aorsmul_1.asm b/third_party/gmp/mpn/arm/aorsmul_1.asm
new file mode 100644
index 0000000..b02fbb3
--- /dev/null
+++ b/third_party/gmp/mpn/arm/aorsmul_1.asm
@@ -0,0 +1,135 @@
+dnl  ARM mpn_addmul_1 and mpn_submul_1.
+
+dnl  Copyright 1998, 2000, 2001, 2003, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C StrongARM:     ?
+C XScale	 ?
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 5.25
+C Cortex-A15	 4
+
+define(`rp', `r0')
+define(`up', `r1')
+define(`n',  `r2')
+define(`vl', `r3')
+define(`rl', `r12')
+define(`ul', `r6')
+define(`r',  `lr')
+
+ifdef(`OPERATION_addmul_1', `
+  define(`ADDSUB',	adds)
+  define(`ADDSUBC',	adcs)
+  define(`CLRRCY',	`mov	$1, #0
+			adds	r0, r0, #0')
+  define(`RETVAL',	`adc	r0, r4, #0')
+  define(`func',	mpn_addmul_1)')
+ifdef(`OPERATION_submul_1', `
+  define(`ADDSUB',	subs)
+  define(`ADDSUBC',	sbcs)
+  define(`CLRRCY',	`subs	$1, r0, r0')
+  define(`RETVAL',	`sbc	r0, r0, r0
+			sub	r0, $1, r0')
+  define(`func',	mpn_submul_1)')
+
+MULFUNC_PROLOGUE(mpn_addmul_1 mpn_submul_1)
+
+ASM_START()
+PROLOGUE(func)
+	stmfd	sp!, { r4-r6, lr }
+	CLRRCY(	r4)
+	tst	n, #1
+	beq	L(skip1)
+	ldr	ul, [up], #4
+	ldr	rl, [rp, #0]
+	umull	r5, r4, ul, vl
+	ADDSUB	r, rl, r5
+	str	r, [rp], #4
+L(skip1):
+	tst	n, #2
+	beq	L(skip2)
+	ldr	ul, [up], #4
+	ldr	rl, [rp, #0]
+	mov	r5, #0
+	umlal	r4, r5, ul, vl
+	ldr	ul, [up], #4
+	ADDSUBC	r, rl, r4
+	ldr	rl, [rp, #4]
+	mov	r4, #0
+	umlal	r5, r4, ul, vl
+	str	r, [rp], #4
+	ADDSUBC	r, rl, r5
+	str	r, [rp], #4
+L(skip2):
+	bics	n, n, #3
+	beq	L(rtn)
+
+	ldr	ul, [up], #4
+	ldr	rl, [rp, #0]
+	mov	r5, #0
+	umlal	r4, r5, ul, vl
+	b	L(in)
+
+L(top):	ldr	ul, [up], #4
+	ADDSUBC	r, rl, r5
+	ldr	rl, [rp, #4]
+	mov	r5, #0
+	umlal	r4, r5, ul, vl
+	str	r, [rp], #4
+L(in):	ldr	ul, [up], #4
+	ADDSUBC	r, rl, r4
+	ldr	rl, [rp, #4]
+	mov	r4, #0
+	umlal	r5, r4, ul, vl
+	str	r, [rp], #4
+	ldr	ul, [up], #4
+	ADDSUBC	r, rl, r5
+	ldr	rl, [rp, #4]
+	mov	r5, #0
+	umlal	r4, r5, ul, vl
+	str	r, [rp], #4
+	ldr	ul, [up], #4
+	ADDSUBC	r, rl, r4
+	ldr	rl, [rp, #4]
+	mov	r4, #0
+	umlal	r5, r4, ul, vl
+	sub	n, n, #4
+	tst	n, n
+	str	r, [rp], #4
+	bne	L(top)
+
+	ADDSUBC	r, rl, r5
+	str	r, [rp]
+
+L(rtn):	RETVAL(	r4)
+	ldmfd	sp!, { r4-r6, pc }
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/arm-defs.m4 b/third_party/gmp/mpn/arm/arm-defs.m4
new file mode 100644
index 0000000..4b4fa0b
--- /dev/null
+++ b/third_party/gmp/mpn/arm/arm-defs.m4
@@ -0,0 +1,100 @@
+divert(-1)
+
+dnl  m4 macros for ARM assembler.
+
+dnl  Copyright 2001, 2012-2016, 2018-2019 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+dnl  Standard commenting is with @, the default m4 # is for constants and we
+dnl  don't want to disable macro expansions in or after them.
+
+changecom(@&*$)
+
+define(`ASM_START',
+m4_assert_numargs_range(0,1)
+`ifelse($1,`neon',`.fpu	neon',
+        $1,,`',
+        1,1,`m4_error(`$0 got invalid argument $1')')')
+
+dnl  APCS register names.
+
+deflit(a1,r0)
+deflit(a2,r1)
+deflit(a3,r2)
+deflit(a4,r3)
+dnl deflit(v1,r4)
+dnl deflit(v2,r5)
+dnl deflit(v3,r6)
+dnl deflit(v4,r7)
+dnl deflit(v5,r8)
+dnl deflit(v6,r9)
+deflit(sb,r9)
+dnl deflit(v7,r10)
+deflit(sl,r10)
+deflit(fp,r11)
+deflit(ip,r12)
+dnl deflit(sp,r13)
+deflit(lr,r14)
+deflit(pc,r15)
+
+
+define(`lea_list', `')
+define(`lea_num',0)
+
+dnl  LEA(reg,gmp_symbol)
+dnl
+dnl  Load the address of gmp_symbol into a register.  The gmp_symbol must be
+dnl  either local or protected/hidden, since we assume it has a fixed distance
+dnl  from the point of use.
+
+define(`LEA',`dnl
+ldr	$1, L(ptr`'lea_num)
+ifdef(`PIC',dnl
+`dnl
+L(bas`'lea_num):dnl
+	add	$1, $1, pc`'dnl
+	m4append(`lea_list',`
+L(ptr'lea_num`):	.word	GSYM_PREFIX`'$2-L(bas'lea_num`)-8')
+	define(`lea_num', eval(lea_num+1))dnl
+',`dnl
+	m4append(`lea_list',`
+L(ptr'lea_num`):	.word	GSYM_PREFIX`'$2')
+	define(`lea_num', eval(lea_num+1))dnl
+')dnl
+')
+
+define(`return',`ifdef(`NOTHUMB',`mov	pc, ',`bx')')
+
+
+define(`EPILOGUE_cpu',
+`lea_list
+	SIZE(`$1',.-`$1')'
+`define(`lea_list', `')')
+
+divert
diff --git a/third_party/gmp/mpn/arm/bdiv_dbm1c.asm b/third_party/gmp/mpn/arm/bdiv_dbm1c.asm
new file mode 100644
index 0000000..b919dc4
--- /dev/null
+++ b/third_party/gmp/mpn/arm/bdiv_dbm1c.asm
@@ -0,0 +1,113 @@
+dnl  ARM mpn_bdiv_dbm1c.
+
+dnl  Copyright 2008, 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C StrongARM	 ?
+C XScale	 ?
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 4.25
+C Cortex-A15	 2.5
+
+C TODO
+C  * Try using umlal or umaal.
+C  * Try using ldm/stm.
+
+define(`qp',	  `r0')
+define(`up',	  `r1')
+define(`n',	  `r2')
+define(`bd',	  `r3')
+define(`cy',	  `sp,#0')
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_bdiv_dbm1c)
+	push	{r4, r5, r6, r7, r8}
+	ldr	r4, [up], #4
+	ldr	r5, [sp, #20]
+	ands	r12, n, #3
+	beq	L(fi0)
+	cmp	r12, #2
+	bcc	L(fi1)
+	beq	L(fi2)
+
+L(fi3):	umull	r8, r12, r4, bd
+	ldr	r4, [up], #4
+	b	L(lo3)
+
+L(fi0):	umull	r6, r7, r4, bd
+	ldr	r4, [up], #4
+	b	L(lo0)
+
+L(fi1):	subs	n, n, #1
+	umull	r8, r12, r4, bd
+	bls	L(wd1)
+	ldr	r4, [up], #4
+	b	L(lo1)
+
+L(fi2):	umull	r6, r7, r4, bd
+	ldr	r4, [up], #4
+	b	L(lo2)
+
+L(top):	ldr	r4, [up], #4
+	subs	r5, r5, r6
+	str	r5, [qp], #4
+	sbc	r5, r5, r7
+L(lo1):	umull	r6, r7, r4, bd
+	ldr	r4, [up], #4
+	subs	r5, r5, r8
+	str	r5, [qp], #4
+	sbc	r5, r5, r12
+L(lo0):	umull	r8, r12, r4, bd
+	ldr	r4, [up], #4
+	subs	r5, r5, r6
+	str	r5, [qp], #4
+	sbc	r5, r5, r7
+L(lo3):	umull	r6, r7, r4, bd
+	ldr	r4, [up], #4
+	subs	r5, r5, r8
+	str	r5, [qp], #4
+	sbc	r5, r5, r12
+L(lo2):	subs	n, n, #4
+	umull	r8, r12, r4, bd
+	bhi	L(top)
+
+L(wd2):	subs	r5, r5, r6
+	str	r5, [qp], #4
+	sbc	r5, r5, r7
+L(wd1):	subs	r5, r5, r8
+	str	r5, [qp]
+	sbc	r0, r5, r12
+	pop	{r4, r5, r6, r7, r8}
+	return	lr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/bdiv_q_1.asm b/third_party/gmp/mpn/arm/bdiv_q_1.asm
new file mode 100644
index 0000000..ae395d1
--- /dev/null
+++ b/third_party/gmp/mpn/arm/bdiv_q_1.asm
@@ -0,0 +1,162 @@
+dnl  ARM v4 mpn_bdiv_q_1, mpn_pi1_bdiv_q_1 -- Hensel division by 1-limb divisor.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2012, 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C               cycles/limb
+C               norm   unorm
+C 1176		13	18
+C Cortex-A5	 8	12
+C Cortex-A7	10.5	18
+C Cortex-A8	14	15
+C Cortex-A9	10	12		not measured since latest edits
+C Cortex-A15	 9	 9
+C Cortex-A53	14	20
+
+C Architecture requirements:
+C v5	-
+C v5t	-
+C v5te	-
+C v6	-
+C v6t2	-
+C v7a	-
+
+define(`rp',  `r0')
+define(`up',  `r1')
+define(`n',   `r2')
+define(`d',   `r3')
+define(`di_arg',  `sp[0]')		C	just mpn_pi1_bdiv_q_1
+define(`cnt_arg', `sp[4]')		C	just mpn_pi1_bdiv_q_1
+
+define(`cy',  `r7')
+define(`cnt', `r6')
+define(`tnc', `r8')
+
+ASM_START()
+PROLOGUE(mpn_bdiv_q_1)
+	tst	d, #1
+	push	{r6-r11}
+	mov	cnt, #0
+	bne	L(inv)
+
+C count trailing zeros
+	movs	r10, d, lsl #16
+	moveq	d, d, lsr #16
+	moveq	cnt, #16
+	tst	d, #0xff
+	moveq	d, d, lsr #8
+	addeq	cnt, cnt, #8
+	LEA(	r10, ctz_tab)
+	and	r11, d, #0xff
+	ldrb	r10, [r10, r11]
+	mov	d, d, lsr r10
+	add	cnt, cnt, r10
+
+C binvert limb
+L(inv):	LEA(	r10, binvert_limb_table)
+	and	r12, d, #254
+	ldrb	r10, [r10, r12, lsr #1]
+	mul	r12, r10, r10
+	mul	r12, d, r12
+	rsb	r12, r12, r10, lsl #1
+	mul	r10, r12, r12
+	mul	r10, d, r10
+	rsb	r10, r10, r12, lsl #1	C r10 = inverse
+	b	L(pi1)
+EPILOGUE()
+
+PROLOGUE(mpn_pi1_bdiv_q_1)
+	push	{r6-r11}
+
+	ldr	cnt, [sp, #28]
+	ldr	r10, [sp, #24]
+
+L(pi1):	ldr	r11, [up], #4		C up[0]
+	cmp	cnt, #0
+	mov	cy, #0
+	bne	L(unorm)
+
+L(norm):
+	subs	n, n, #1		C set carry as side-effect
+	beq	L(edn)
+
+	ALIGN(16)
+L(tpn):	sbcs	cy, r11, cy
+	ldr	r11, [up], #4
+	sub	n, n, #1
+	mul	r9, r10, cy
+	tst	n, n
+	umull	r12, cy, d, r9
+	str	r9, [rp], #4
+	bne	L(tpn)
+
+L(edn):	sbc	cy, r11, cy
+	mul	r9, r10, cy
+	str	r9, [rp]
+	pop	{r6-r11}
+	return	r14
+
+L(unorm):
+	rsb	tnc, cnt, #32
+	mov	r11, r11, lsr cnt
+	subs	n, n, #1		C set carry as side-effect
+	beq	L(edu)
+
+	ALIGN(16)
+L(tpu):	ldr	r12, [up], #4
+	orr	r9, r11, r12, lsl tnc
+	mov	r11, r12, lsr cnt
+	sbcs	cy, r9, cy		C critical path ->cy->cy->
+	sub	n, n, #1
+	mul	r9, r10, cy		C critical path ->cy->r9->
+	tst	n, n
+	umull	r12, cy, d, r9		C critical path ->r9->cy->
+	str	r9, [rp], #4
+	bne	L(tpu)
+
+L(edu):	sbc	cy, r11, cy
+	mul	r9, r10, cy
+	str	r9, [rp]
+	pop	{r6-r11}
+	return	r14
+EPILOGUE()
+
+	RODATA
+ctz_tab:
+	.byte	8,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+	.byte	5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+	.byte	6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+	.byte	5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+	.byte	7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+	.byte	5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+	.byte	6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+	.byte	5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
diff --git a/third_party/gmp/mpn/arm/cnd_aors_n.asm b/third_party/gmp/mpn/arm/cnd_aors_n.asm
new file mode 100644
index 0000000..0479f0d
--- /dev/null
+++ b/third_party/gmp/mpn/arm/cnd_aors_n.asm
@@ -0,0 +1,134 @@
+dnl  ARM mpn_cnd_add_n, mpn_cnd_sub_n
+
+dnl  Copyright 2012, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C StrongARM	 ?
+C XScale	 ?
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 3
+C Cortex-A15	 2.5
+
+define(`cnd',	`r0')
+define(`rp',	`r1')
+define(`up',	`r2')
+define(`vp',	`r3')
+
+define(`n',	`r12')
+
+
+ifdef(`OPERATION_cnd_add_n', `
+	define(`ADDSUB',      adds)
+	define(`ADDSUBC',      adcs)
+	define(`INITCY',      `cmn	r0, #0')
+	define(`RETVAL',      `adc	r0, n, #0')
+	define(func,	      mpn_cnd_add_n)')
+ifdef(`OPERATION_cnd_sub_n', `
+	define(`ADDSUB',      subs)
+	define(`ADDSUBC',      sbcs)
+	define(`INITCY',      `cmp	r0, #0')
+	define(`RETVAL',      `adc	r0, n, #0
+			      rsb	r0, r0, #1')
+	define(func,	      mpn_cnd_sub_n)')
+
+MULFUNC_PROLOGUE(mpn_cnd_add_n mpn_cnd_sub_n)
+
+ASM_START()
+PROLOGUE(func)
+	push	{r4-r11}
+	ldr	n, [sp, #32]
+
+	cmp	cnd, #1
+	sbc	cnd, cnd, cnd		C conditionally set to 0xffffffff
+
+	INITCY				C really only needed for n = 0 (mod 4)
+
+	ands	r4, n, #3
+	beq	L(top)
+	cmp	r4, #2
+	bcc	L(b1)
+	beq	L(b2)
+
+L(b3):	ldm	vp!, {r4,r5,r6}
+	ldm	up!, {r8,r9,r10}
+	bic	r4, r4, cnd
+	bic	r5, r5, cnd
+	bic	r6, r6, cnd
+	ADDSUB	r8, r8, r4
+	ADDSUBC	r9, r9, r5
+	ADDSUBC	r10, r10, r6
+	stm	rp!, {r8,r9,r10}
+	sub	n, n, #3
+	teq	n, #0
+	bne	L(top)
+	b	L(end)
+
+L(b2):	ldm	vp!, {r4,r5}
+	ldm	up!, {r8,r9}
+	bic	r4, r4, cnd
+	bic	r5, r5, cnd
+	ADDSUB	r8, r8, r4
+	ADDSUBC	r9, r9, r5
+	stm	rp!, {r8,r9}
+	sub	n, n, #2
+	teq	n, #0
+	bne	L(top)
+	b	L(end)
+
+L(b1):	ldr	r4, [vp], #4
+	ldr	r8, [up], #4
+	bic	r4, r4, cnd
+	ADDSUB	r8, r8, r4
+	str	r8, [rp], #4
+	sub	n, n, #1
+	teq	n, #0
+	beq	L(end)
+
+L(top):	ldm	vp!, {r4,r5,r6,r7}
+	ldm	up!, {r8,r9,r10,r11}
+	bic	r4, r4, cnd
+	bic	r5, r5, cnd
+	bic	r6, r6, cnd
+	bic	r7, r7, cnd
+	ADDSUBC	r8, r8, r4
+	ADDSUBC	r9, r9, r5
+	ADDSUBC	r10, r10, r6
+	ADDSUBC	r11, r11, r7
+	sub	n, n, #4
+	stm	rp!, {r8,r9,r10,r11}
+	teq	n, #0
+	bne	L(top)
+
+L(end):	RETVAL
+	pop	{r4-r11}
+	return	r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/com.asm b/third_party/gmp/mpn/arm/com.asm
new file mode 100644
index 0000000..850b10a
--- /dev/null
+++ b/third_party/gmp/mpn/arm/com.asm
@@ -0,0 +1,75 @@
+dnl  ARM mpn_com.
+
+dnl  Copyright 2003, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C StrongARM	 ?
+C XScale	 ?
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 2.0
+C Cortex-A15	 1.75
+
+define(`rp', `r0')
+define(`up', `r1')
+define(`n',  `r2')
+
+ASM_START()
+PROLOGUE(mpn_com)
+	tst	n, #1
+	beq	L(skip1)
+	ldr	r3, [up], #4
+	mvn	r3, r3
+	str	r3, [rp], #4
+L(skip1):
+	tst	n, #2
+	beq	L(skip2)
+	ldmia	up!, { r3, r12 }		C load 2 limbs
+	mvn	r3, r3
+	mvn	r12, r12
+	stmia	rp!, { r3, r12 }		C store 2 limbs
+L(skip2):
+	bics	n, n, #3
+	beq	L(rtn)
+	stmfd	sp!, { r7, r8, r9 }		C save regs on stack
+
+L(top):	ldmia	up!, { r3, r8, r9, r12 }	C load 4 limbs
+	subs	n, n, #4
+	mvn	r3, r3
+	mvn	r8, r8
+	mvn	r9, r9
+	mvn	r12, r12
+	stmia	rp!, { r3, r8, r9, r12 }	C store 4 limbs
+	bne	L(top)
+
+	ldmfd	sp!, { r7, r8, r9 }		C restore regs from stack
+L(rtn):	return	lr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/copyd.asm b/third_party/gmp/mpn/arm/copyd.asm
new file mode 100644
index 0000000..bcad98d
--- /dev/null
+++ b/third_party/gmp/mpn/arm/copyd.asm
@@ -0,0 +1,84 @@
+dnl  ARM mpn_copyd.
+
+dnl  Contributed to the GNU project by Robert Harley and Torbjörn Granlund.
+
+dnl  Copyright 2003, 2012, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C StrongARM	 ?
+C XScale	 ?
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 1.25-1.5
+C Cortex-A15	 1.25
+
+C TODO
+C  * Consider wider unrolling.  Analogous 8-way code runs 10% faster on both A9
+C    and A15.  But it probably slows things down for 8 <= n < a few dozen.
+
+define(`rp', `r0')
+define(`up', `r1')
+define(`n',  `r2')
+
+ASM_START()
+PROLOGUE(mpn_copyd)
+	mov	r12, n, lsl #2
+	sub	r12, r12, #4
+	add	rp, rp, r12
+	add	up, up, r12
+
+	tst	n, #1
+	beq	L(skip1)
+	ldr	r3, [up], #-4
+	str	r3, [rp], #-4
+L(skip1):
+	tst	n, #2
+	beq	L(skip2)
+	ldmda	up!, { r3,r12 }
+	stmda	rp!, { r3,r12 }
+L(skip2):
+	bics	n, n, #3
+	beq	L(rtn)
+
+	push	{ r4-r5 }
+	subs	n, n, #4
+	ldmda	up!, { r3,r4,r5,r12 }
+	beq	L(end)
+
+L(top):	subs	n, n, #4
+	stmda	rp!, { r3,r4,r5,r12 }
+	ldmda	up!, { r3,r4,r5,r12 }
+	bne	L(top)
+
+L(end):	stmda	rp, { r3,r4,r5,r12 }
+	pop	{ r4-r5 }
+L(rtn):	return	lr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/copyi.asm b/third_party/gmp/mpn/arm/copyi.asm
new file mode 100644
index 0000000..421930f
--- /dev/null
+++ b/third_party/gmp/mpn/arm/copyi.asm
@@ -0,0 +1,79 @@
+dnl  ARM mpn_copyi.
+
+dnl  Contributed to the GNU project by Robert Harley and Torbjörn Granlund.
+
+dnl  Copyright 2003, 2012, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C StrongARM	 ?
+C XScale	 ?
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 1.25-1.5
+C Cortex-A15	 1.25
+
+C TODO
+C  * Consider wider unrolling.  Analogous 8-way code runs 10% faster on both A9
+C    and A15.  But it probably slows things down for 8 <= n < a few dozen.
+
+define(`rp', `r0')
+define(`up', `r1')
+define(`n',  `r2')
+
+ASM_START()
+PROLOGUE(mpn_copyi)
+	tst	n, #1
+	beq	L(skip1)
+	ldr	r3, [up], #4
+	str	r3, [rp], #4
+L(skip1):
+	tst	n, #2
+	beq	L(skip2)
+	ldmia	up!, { r3,r12 }
+	stmia	rp!, { r3,r12 }
+L(skip2):
+	bics	n, n, #3
+	beq	L(rtn)
+
+	push	{ r4-r5 }
+	subs	n, n, #4
+	ldmia	up!, { r3,r4,r5,r12 }
+	beq	L(end)
+
+L(top):	subs	n, n, #4
+	stmia	rp!, { r3,r4,r5,r12 }
+	ldmia	up!, { r3,r4,r5,r12 }
+	bne	L(top)
+
+L(end):	stm	rp, { r3,r4,r5,r12 }
+	pop	{ r4-r5 }
+L(rtn):	return	lr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/dive_1.asm b/third_party/gmp/mpn/arm/dive_1.asm
new file mode 100644
index 0000000..8bffb0c
--- /dev/null
+++ b/third_party/gmp/mpn/arm/dive_1.asm
@@ -0,0 +1,151 @@
+dnl  ARM v4 mpn_divexact_1.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C               cycles/limb       cycles/limb
+C               norm    unorm    modexact_1c_odd
+C StrongARM	 ?
+C XScale	 ?
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	10	12
+C Cortex-A15	 9	 9
+
+C Architecture requirements:
+C v5	-
+C v5t	-
+C v5te	-
+C v6	-
+C v6t2	-
+C v7a	-
+
+define(`rp', `r0')
+define(`up', `r1')
+define(`n',  `r2')
+define(`d',  `r3')
+
+define(`cy', `r7')
+define(`cnt', `r6')
+define(`tnc', `r8')
+
+ASM_START()
+PROLOGUE(mpn_divexact_1)
+	tst	d, #1
+	push	{r4-r9}
+	mov	cnt, #0
+	bne	L(inv)
+
+C count trailing zeros
+	movs	r4, d, lsl #16
+	moveq	d, d, lsr #16
+	moveq	cnt, #16
+	tst	d, #0xff
+	moveq	d, d, lsr #8
+	addeq	cnt, cnt, #8
+	LEA(	r4, ctz_tab)
+	and	r5, d, #0xff
+	ldrb	r4, [r4, r5]
+	mov	d, d, lsr r4
+	add	cnt, cnt, r4
+
+C binvert limb
+L(inv):	LEA(	r4, binvert_limb_table)
+	and	r12, d, #254
+	ldrb	r4, [r4, r12, lsr #1]
+	mul	r12, r4, r4
+	mul	r12, d, r12
+	rsb	r12, r12, r4, lsl #1
+	mul	r4, r12, r12
+	mul	r4, d, r4
+	rsb	r4, r4, r12, lsl #1	C r4 = inverse
+
+	tst	cnt, cnt
+	ldr	r5, [up], #4		C up[0]
+	mov	cy, #0
+	bne	L(unnorm)
+
+L(norm):
+	subs	n, n, #1		C set carry as side-effect
+	beq	L(edn)
+
+	ALIGN(16)
+L(tpn):	sbcs	cy, r5, cy
+	ldr	r5, [up], #4
+	sub	n, n, #1
+	mul	r9, r4, cy
+	tst	n, n
+	umull	r12, cy, d, r9
+	str	r9, [rp], #4
+	bne	L(tpn)
+
+L(edn):	sbc	cy, r5, cy
+	mul	r9, r4, cy
+	str	r9, [rp]
+	pop	{r4-r9}
+	return	r14
+
+L(unnorm):
+	rsb	tnc, cnt, #32
+	mov	r5, r5, lsr cnt
+	subs	n, n, #1		C set carry as side-effect
+	beq	L(edu)
+
+	ALIGN(16)
+L(tpu):	ldr	r12, [up], #4
+	orr	r9, r5, r12, lsl tnc
+	mov	r5, r12, lsr cnt
+	sbcs	cy, r9, cy		C critical path ->cy->cy->
+	sub	n, n, #1
+	mul	r9, r4, cy		C critical path ->cy->r9->
+	tst	n, n
+	umull	r12, cy, d, r9		C critical path ->r9->cy->
+	str	r9, [rp], #4
+	bne	L(tpu)
+
+L(edu):	sbc	cy, r5, cy
+	mul	r9, r4, cy
+	str	r9, [rp]
+	pop	{r4-r9}
+	return	r14
+EPILOGUE()
+
+	RODATA
+ctz_tab:
+	.byte	8,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+	.byte	5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+	.byte	6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+	.byte	5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+	.byte	7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+	.byte	5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+	.byte	6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+	.byte	5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
diff --git a/third_party/gmp/mpn/arm/gmp-mparam.h b/third_party/gmp/mpn/arm/gmp-mparam.h
new file mode 100644
index 0000000..87eec3a
--- /dev/null
+++ b/third_party/gmp/mpn/arm/gmp-mparam.h
@@ -0,0 +1,127 @@
+/* gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 1999-2003, 2009, 2010 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+/* 1193MHz ARM (gcc55.fsffrance.org) */
+
+#define DIVREM_1_NORM_THRESHOLD              0  /* preinv always */
+#define DIVREM_1_UNNORM_THRESHOLD            0  /* always */
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD         56
+#define MOD_1U_TO_MOD_1_1_THRESHOLD         11
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD         0  /* never mpn_mod_1_1p */
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD     MP_SIZE_T_MAX
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     71
+#define USE_PREINV_DIVREM_1                  1  /* preinv always */
+#define DIVREM_2_THRESHOLD                   0  /* preinv always */
+#define DIVEXACT_1_THRESHOLD                 0  /* always */
+#define BMOD_1_TO_MOD_1_THRESHOLD           41
+
+#define MUL_TOOM22_THRESHOLD                36
+#define MUL_TOOM33_THRESHOLD               125
+#define MUL_TOOM44_THRESHOLD               193
+#define MUL_TOOM6H_THRESHOLD               303
+#define MUL_TOOM8H_THRESHOLD               418
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD     125
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     176
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     114
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     129
+
+#define SQR_BASECASE_THRESHOLD              12
+#define SQR_TOOM2_THRESHOLD                 78
+#define SQR_TOOM3_THRESHOLD                137
+#define SQR_TOOM4_THRESHOLD                212
+#define SQR_TOOM6_THRESHOLD                306
+#define SQR_TOOM8_THRESHOLD                422
+
+#define MULMOD_BNM1_THRESHOLD               20
+#define SQRMOD_BNM1_THRESHOLD               26
+
+#define MUL_FFT_MODF_THRESHOLD             436  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    436, 5}, {     27, 6}, {     28, 7}, {     15, 6}, \
+    {     32, 7}, {     17, 6}, {     35, 7}, {     19, 6}, \
+    {     39, 7}, {     29, 8}, {     15, 7}, {     35, 8}, \
+    {     19, 7}, {     41, 8}, {     23, 7}, {     49, 8}, \
+    {     27, 9}, {     15, 8}, {     31, 7}, {     63, 8}, \
+    {    256, 9}, {    512,10}, {   1024,11}, {   2048,12}, \
+    {   4096,13}, {   8192,14}, {  16384,15}, {  32768,16} }
+#define MUL_FFT_TABLE3_SIZE 28
+#define MUL_FFT_THRESHOLD                 5760
+
+#define SQR_FFT_MODF_THRESHOLD             404  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    404, 5}, {     13, 4}, {     27, 5}, {     27, 6}, \
+    {     28, 7}, {     15, 6}, {     32, 7}, {     17, 6}, \
+    {     35, 7}, {     29, 8}, {     15, 7}, {     35, 8}, \
+    {     19, 7}, {     41, 8}, {     23, 7}, {     47, 8}, \
+    {     27, 9}, {     15, 8}, {     39, 9}, {    512,10}, \
+    {   1024,11}, {   2048,12}, {   4096,13}, {   8192,14}, \
+    {  16384,15}, {  32768,16} }
+#define SQR_FFT_TABLE3_SIZE 26
+#define SQR_FFT_THRESHOLD                 3776
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                 137
+#define MULLO_MUL_N_THRESHOLD            11479
+
+#define DC_DIV_QR_THRESHOLD                150
+#define DC_DIVAPPR_Q_THRESHOLD             494
+#define DC_BDIV_QR_THRESHOLD               148
+#define DC_BDIV_Q_THRESHOLD                345
+
+#define INV_MULMOD_BNM1_THRESHOLD           70
+#define INV_NEWTON_THRESHOLD               474
+#define INV_APPR_THRESHOLD                 478
+
+#define BINV_NEWTON_THRESHOLD              542
+#define REDC_1_TO_REDC_N_THRESHOLD         117
+
+#define MU_DIV_QR_THRESHOLD               2089
+#define MU_DIVAPPR_Q_THRESHOLD            2172
+#define MUPI_DIV_QR_THRESHOLD              225
+#define MU_BDIV_QR_THRESHOLD              1528
+#define MU_BDIV_Q_THRESHOLD               2089
+
+#define MATRIX22_STRASSEN_THRESHOLD         16
+#define HGCD_THRESHOLD                     197
+#define GCD_DC_THRESHOLD                   902
+#define GCDEXT_DC_THRESHOLD                650
+#define JACOBI_BASE_METHOD                   2
+
+#define GET_STR_DC_THRESHOLD                20
+#define GET_STR_PRECOMPUTE_THRESHOLD        39
+#define SET_STR_DC_THRESHOLD              1045
+#define SET_STR_PRECOMPUTE_THRESHOLD      2147
diff --git a/third_party/gmp/mpn/arm/invert_limb.asm b/third_party/gmp/mpn/arm/invert_limb.asm
new file mode 100644
index 0000000..af7502d
--- /dev/null
+++ b/third_party/gmp/mpn/arm/invert_limb.asm
@@ -0,0 +1,93 @@
+dnl  ARM mpn_invert_limb -- Invert a normalized limb.
+
+dnl  Copyright 2001, 2009, 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ASM_START()
+PROLOGUE(mpn_invert_limb)
+	LEA(	r2, approx_tab-512)
+	mov	r3, r0, lsr #23
+	mov	r3, r3, asl #1
+	ldrh	r3, [r3, r2]
+	mov	r1, r3, asl #17
+	mul	r12, r3, r3
+	umull	r3, r2, r12, r0
+	sub	r1, r1, r2, asl #1
+	umull	r3, r2, r1, r1
+	umull	r12, r3, r0, r3
+	umull	r2, r12, r0, r2
+	adds	r2, r2, r3
+	adc	r12, r12, #0
+	rsb	r1, r12, r1
+	mvn	r2, r2, lsr #30
+	add	r2, r2, r1, asl #2
+	umull	r12, r3, r0, r2
+	adds	r1, r12, r0
+	adc	r3, r3, r0
+	rsb	r0, r3, r2
+	return	lr
+EPILOGUE()
+
+	RODATA
+	ALIGN(2)
+approx_tab:
+	.short    0xffc0,0xfec0,0xfdc0,0xfcc0,0xfbc0,0xfac0,0xfa00,0xf900
+	.short    0xf800,0xf700,0xf640,0xf540,0xf440,0xf380,0xf280,0xf180
+	.short    0xf0c0,0xefc0,0xef00,0xee00,0xed40,0xec40,0xeb80,0xeac0
+	.short    0xe9c0,0xe900,0xe840,0xe740,0xe680,0xe5c0,0xe500,0xe400
+	.short    0xe340,0xe280,0xe1c0,0xe100,0xe040,0xdf80,0xdec0,0xde00
+	.short    0xdd40,0xdc80,0xdbc0,0xdb00,0xda40,0xd980,0xd8c0,0xd800
+	.short    0xd740,0xd680,0xd600,0xd540,0xd480,0xd3c0,0xd340,0xd280
+	.short    0xd1c0,0xd140,0xd080,0xcfc0,0xcf40,0xce80,0xcdc0,0xcd40
+	.short    0xcc80,0xcc00,0xcb40,0xcac0,0xca00,0xc980,0xc8c0,0xc840
+	.short    0xc780,0xc700,0xc640,0xc5c0,0xc540,0xc480,0xc400,0xc380
+	.short    0xc2c0,0xc240,0xc1c0,0xc100,0xc080,0xc000,0xbf80,0xbec0
+	.short    0xbe40,0xbdc0,0xbd40,0xbc80,0xbc00,0xbb80,0xbb00,0xba80
+	.short    0xba00,0xb980,0xb900,0xb840,0xb7c0,0xb740,0xb6c0,0xb640
+	.short    0xb5c0,0xb540,0xb4c0,0xb440,0xb3c0,0xb340,0xb2c0,0xb240
+	.short    0xb1c0,0xb140,0xb0c0,0xb080,0xb000,0xaf80,0xaf00,0xae80
+	.short    0xae00,0xad80,0xad40,0xacc0,0xac40,0xabc0,0xab40,0xaac0
+	.short    0xaa80,0xaa00,0xa980,0xa900,0xa8c0,0xa840,0xa7c0,0xa740
+	.short    0xa700,0xa680,0xa600,0xa5c0,0xa540,0xa4c0,0xa480,0xa400
+	.short    0xa380,0xa340,0xa2c0,0xa240,0xa200,0xa180,0xa140,0xa0c0
+	.short    0xa080,0xa000,0x9f80,0x9f40,0x9ec0,0x9e80,0x9e00,0x9dc0
+	.short    0x9d40,0x9d00,0x9c80,0x9c40,0x9bc0,0x9b80,0x9b00,0x9ac0
+	.short    0x9a40,0x9a00,0x9980,0x9940,0x98c0,0x9880,0x9840,0x97c0
+	.short    0x9780,0x9700,0x96c0,0x9680,0x9600,0x95c0,0x9580,0x9500
+	.short    0x94c0,0x9440,0x9400,0x93c0,0x9340,0x9300,0x92c0,0x9240
+	.short    0x9200,0x91c0,0x9180,0x9100,0x90c0,0x9080,0x9000,0x8fc0
+	.short    0x8f80,0x8f40,0x8ec0,0x8e80,0x8e40,0x8e00,0x8d80,0x8d40
+	.short    0x8d00,0x8cc0,0x8c80,0x8c00,0x8bc0,0x8b80,0x8b40,0x8b00
+	.short    0x8a80,0x8a40,0x8a00,0x89c0,0x8980,0x8940,0x88c0,0x8880
+	.short    0x8840,0x8800,0x87c0,0x8780,0x8740,0x8700,0x8680,0x8640
+	.short    0x8600,0x85c0,0x8580,0x8540,0x8500,0x84c0,0x8480,0x8440
+	.short    0x8400,0x8380,0x8340,0x8300,0x82c0,0x8280,0x8240,0x8200
+	.short    0x81c0,0x8180,0x8140,0x8100,0x80c0,0x8080,0x8040,0x8000
+ASM_END()
diff --git a/third_party/gmp/mpn/arm/logops_n.asm b/third_party/gmp/mpn/arm/logops_n.asm
new file mode 100644
index 0000000..7e04165
--- /dev/null
+++ b/third_party/gmp/mpn/arm/logops_n.asm
@@ -0,0 +1,139 @@
+dnl  ARM mpn_and_n, mpn_andn_n. mpn_nand_n, etc.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 1997, 2000, 2001, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C            cycles/limb             cycles/limb
+C          and andn ior xor         nand iorn nior xnor
+C StrongARM	 ?			 ?
+C XScale	 ?			 ?
+C Cortex-A7	 ?			 ?
+C Cortex-A8	 ?			 ?
+C Cortex-A9	2.5-2.72		2.75-3
+C Cortex-A15	2.25			2.75
+
+C TODO
+C  * It seems that 2.25 c/l and 2.75 c/l is possible for A9.
+C  * Debug popping issue, see comment below.
+
+define(`rp', `r0')
+define(`up', `r1')
+define(`vp', `r2')
+define(`n',  `r3')
+
+define(`POSTOP')
+
+ifdef(`OPERATION_and_n',`
+  define(`func',    `mpn_and_n')
+  define(`LOGOP',   `and	$1, $2, $3')')
+ifdef(`OPERATION_andn_n',`
+  define(`func',    `mpn_andn_n')
+  define(`LOGOP',   `bic	$1, $2, $3')')
+ifdef(`OPERATION_nand_n',`
+  define(`func',    `mpn_nand_n')
+  define(`POSTOP',  `mvn	$1, $1')
+  define(`LOGOP',   `and	$1, $2, $3')')
+ifdef(`OPERATION_ior_n',`
+  define(`func',    `mpn_ior_n')
+  define(`LOGOP',   `orr	$1, $2, $3')')
+ifdef(`OPERATION_iorn_n',`
+  define(`func',    `mpn_iorn_n')
+  define(`POSTOP',  `mvn	$1, $1')
+  define(`LOGOP',   `bic	$1, $3, $2')')
+ifdef(`OPERATION_nior_n',`
+  define(`func',    `mpn_nior_n')
+  define(`POSTOP',  `mvn	$1, $1')
+  define(`LOGOP',   `orr	$1, $2, $3')')
+ifdef(`OPERATION_xor_n',`
+  define(`func',    `mpn_xor_n')
+  define(`LOGOP',   `eor	$1, $2, $3')')
+ifdef(`OPERATION_xnor_n',`
+  define(`func',    `mpn_xnor_n')
+  define(`POSTOP',  `mvn	$1, $1')
+  define(`LOGOP',   `eor	$1, $2, $3')')
+
+MULFUNC_PROLOGUE(mpn_and_n mpn_andn_n mpn_nand_n mpn_ior_n mpn_iorn_n mpn_nior_n mpn_xor_n mpn_xnor_n)
+
+ASM_START()
+PROLOGUE(func)
+	push	{ r8, r9, r10 }
+	tst	n, #1
+	beq	L(skip1)
+	ldr	r10, [vp], #4
+	ldr	r12, [up], #4
+	LOGOP(	r12, r12, r10)
+	POSTOP(	r12)
+	str	r12, [rp], #4
+L(skip1):
+	tst	n, #2
+	beq	L(skip2)
+	ldmia	vp!, { r10, r12 }
+	ldmia	up!, { r8, r9 }
+	LOGOP(	r8, r8, r10)
+	LOGOP(	r9, r9, r12)
+	POSTOP(	r8)
+	POSTOP(	r9)
+	stmia	rp!, { r8, r9 }
+L(skip2):
+	bics	n, n, #3
+	beq	L(rtn)
+	push	{ r4, r5, r6, r7 }
+
+	ldmia	vp!, { r8, r9, r10, r12 }
+	b	L(mid)
+
+L(top):	ldmia	vp!, { r8, r9, r10, r12 }
+	POSTOP(	r4)
+	POSTOP(	r5)
+	POSTOP(	r6)
+	POSTOP(	r7)
+	stmia	rp!, { r4, r5, r6, r7 }
+L(mid):	sub	n, n, #4
+	ldmia	up!, { r4, r5, r6, r7 }
+	teq	n, #0
+	LOGOP(	r4, r4, r8)
+	LOGOP(	r5, r5, r9)
+	LOGOP(	r6, r6, r10)
+	LOGOP(	r7, r7, r12)
+	bne	L(top)
+
+	POSTOP(	r4)
+	POSTOP(	r5)
+	POSTOP(	r6)
+	POSTOP(	r7)
+	stmia	rp!, { r4, r5, r6, r7 }
+
+	pop	{ r4, r5, r6, r7 }	C popping r8-r10 here strangely fails
+
+L(rtn):	pop	{ r8, r9, r10 }
+	return	r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/lshift.asm b/third_party/gmp/mpn/arm/lshift.asm
new file mode 100644
index 0000000..1d5ce0a
--- /dev/null
+++ b/third_party/gmp/mpn/arm/lshift.asm
@@ -0,0 +1,88 @@
+dnl  ARM mpn_lshift.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C StrongARM	 ?
+C XScale	 ?
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 3.5
+C Cortex-A15	 ?
+
+define(`rp',  `r0')
+define(`up',  `r1')
+define(`n',   `r2')
+define(`cnt', `r3')
+define(`tnc', `r12')
+
+ASM_START()
+PROLOGUE(mpn_lshift)
+	add	up, up, n, lsl #2
+	push	{r4, r6, r7, r8}
+	ldr	r4, [up, #-4]!
+	add	rp, rp, n, lsl #2
+	rsb	tnc, cnt, #32
+
+	mov	r7, r4, lsl cnt
+	tst	n, #1
+	beq	L(evn)			C n even
+
+L(odd):	subs	n, n, #2
+	bcc	L(1)			C n = 1
+	ldr	r8, [up, #-4]!
+	b	L(mid)
+
+L(evn):	ldr	r6, [up, #-4]!
+	subs	n, n, #2
+	beq	L(end)
+
+L(top):	ldr	r8, [up, #-4]!
+	orr	r7, r7, r6, lsr tnc
+	str	r7, [rp, #-4]!
+	mov	r7, r6, lsl cnt
+L(mid):	ldr	r6, [up, #-4]!
+	orr	r7, r7, r8, lsr tnc
+	str	r7, [rp, #-4]!
+	mov	r7, r8, lsl cnt
+	subs	n, n, #2
+	bgt	L(top)
+
+L(end):	orr	r7, r7, r6, lsr tnc
+	str	r7, [rp, #-4]!
+	mov	r7, r6, lsl cnt
+L(1):	str	r7, [rp, #-4]
+	mov	r0, r4, lsr tnc
+	pop	{r4, r6, r7, r8}
+	return	r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/lshiftc.asm b/third_party/gmp/mpn/arm/lshiftc.asm
new file mode 100644
index 0000000..e5b52df
--- /dev/null
+++ b/third_party/gmp/mpn/arm/lshiftc.asm
@@ -0,0 +1,95 @@
+dnl  ARM mpn_lshiftc.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C StrongARM	 ?
+C XScale	 ?
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 4.0
+C Cortex-A15	 ?
+
+define(`rp',  `r0')
+define(`up',  `r1')
+define(`n',   `r2')
+define(`cnt', `r3')
+define(`tnc', `r12')
+
+ASM_START()
+PROLOGUE(mpn_lshiftc)
+	add	up, up, n, lsl #2
+	push	{r4, r6, r7, r8}
+	ldr	r4, [up, #-4]!
+	add	rp, rp, n, lsl #2
+	rsb	tnc, cnt, #32
+	mvn	r6, r4
+
+	mov	r7, r6, lsl cnt
+	tst	n, #1
+	beq	L(evn)			C n even
+
+L(odd):	subs	n, n, #2
+	bcc	L(1)			C n = 1
+	ldr	r8, [up, #-4]!
+	mvn	r8, r8
+	b	L(mid)
+
+L(evn):	ldr	r6, [up, #-4]!
+	mvn	r6, r6
+	subs	n, n, #2
+	beq	L(end)
+
+L(top):	ldr	r8, [up, #-4]!
+	orr	r7, r7, r6, lsr tnc
+	str	r7, [rp, #-4]!
+	mvn	r8, r8
+	mov	r7, r6, lsl cnt
+L(mid):	ldr	r6, [up, #-4]!
+	orr	r7, r7, r8, lsr tnc
+	str	r7, [rp, #-4]!
+	mvn	r6, r6
+	mov	r7, r8, lsl cnt
+	subs	n, n, #2
+	bgt	L(top)
+
+L(end):	orr	r7, r7, r6, lsr tnc
+	str	r7, [rp, #-4]!
+	mov	r7, r6, lsl cnt
+L(1):	mvn	r6, #0
+	orr	r7, r7, r6, lsr tnc
+	str	r7, [rp, #-4]
+	mov	r0, r4, lsr tnc
+	pop	{r4, r6, r7, r8}
+	return	r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/mod_34lsub1.asm b/third_party/gmp/mpn/arm/mod_34lsub1.asm
new file mode 100644
index 0000000..596cd3c
--- /dev/null
+++ b/third_party/gmp/mpn/arm/mod_34lsub1.asm
@@ -0,0 +1,124 @@
+dnl  ARM mpn_mod_34lsub1 -- remainder modulo 2^24-1.
+
+dnl  Copyright 2012, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C StrongARM	 ?
+C XScale	 ?
+C Cortex-A5	 2.67
+C Cortex-A7	 2.35
+C Cortex-A8	 2.0
+C Cortex-A9	 1.33
+C Cortex-A15	 1.33
+C Cortex-A17	 3.34
+C Cortex-A53	 2.0
+
+define(`ap',	r0)
+define(`n',	r1)
+
+C mp_limb_t mpn_mod_34lsub1 (mp_srcptr up, mp_size_t n)
+
+C TODO
+C  * Write cleverer summation code.
+C  * Consider loading 6 64-bit aligned registers at a time, to approach 1 c/l.
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_mod_34lsub1)
+	push	{ r4, r5, r6, r7 }
+
+	subs	n, n, #3
+	mov	r7, #0
+	blt	L(le2)			C n <= 2
+
+	ldmia	ap!, { r2, r3, r12 }
+	subs	n, n, #3
+	blt	L(sum)			C n <= 5
+	cmn	r0, #0			C clear carry
+	sub	n, n, #3
+	b	L(mid)
+
+L(top):	adcs	r2, r2, r4
+	adcs	r3, r3, r5
+	adcs	r12, r12, r6
+L(mid):	ldmia	ap!, { r4, r5, r6 }
+	tst	n, n
+	sub	n, n, #3
+	bpl	L(top)
+
+	add	n, n, #3
+
+	adcs	r2, r2, r4
+	adcs	r3, r3, r5
+	adcs	r12, r12, r6
+	movcs	r7, #1			C r7 <= 1
+
+L(sum):	cmn	n, #2
+	movlo	r4, #0
+	ldrhs	r4, [ap], #4
+	movls	r5, #0
+	ldrhi	r5, [ap], #4
+
+	adds	r2, r2, r4
+	adcs	r3, r3, r5
+	adcs	r12, r12, #0
+	adc	r7, r7, #0		C r7 <= 2
+
+L(sum2):
+	bic	r0, r2, #0xff000000
+	add	r0, r0, r2, lsr #24
+	add	r0, r0, r7
+
+	mov	r7, r3, lsl #8
+	bic	r1, r7, #0xff000000
+	add	r0, r0, r1
+	add	r0, r0, r3, lsr #16
+
+	mov	r7, r12, lsl #16
+	bic	r1, r7, #0xff000000
+	add	r0, r0, r1
+	add	r0, r0, r12, lsr #8
+
+	pop	{ r4, r5, r6, r7 }
+	return	lr
+
+L(le2):	cmn	n, #1
+	bne	L(1)
+	ldmia	ap!, { r2, r3 }
+	mov	r12, #0
+	b	L(sum2)
+L(1):	ldr	r2, [ap]
+	bic	r0, r2, #0xff000000
+	add	r0, r0, r2, lsr #24
+	pop	{ r4, r5, r6, r7 }
+	return	lr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/mode1o.asm b/third_party/gmp/mpn/arm/mode1o.asm
new file mode 100644
index 0000000..63a7f36
--- /dev/null
+++ b/third_party/gmp/mpn/arm/mode1o.asm
@@ -0,0 +1,92 @@
+dnl  ARM mpn_modexact_1c_odd
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C StrongARM	 ?
+C XScale	 ?
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	10
+C Cortex-A15	 9
+
+C Architecture requirements:
+C v5	-
+C v5t	-
+C v5te	-
+C v6	-
+C v6t2	-
+C v7a	-
+
+define(`up', `r0')
+define(`n',  `r1')
+define(`d',  `r2')
+define(`cy', `r3')
+
+	.protected	binvert_limb_table
+ASM_START()
+PROLOGUE(mpn_modexact_1c_odd)
+	stmfd	sp!, {r4, r5}
+
+	LEA(	r4, binvert_limb_table)
+
+	ldr	r5, [up], #4		C up[0]
+
+	and	r12, d, #254
+	ldrb	r4, [r4, r12, lsr #1]
+	mul	r12, r4, r4
+	mul	r12, d, r12
+	rsb	r12, r12, r4, asl #1
+	mul	r4, r12, r12
+	mul	r4, d, r4
+	rsb	r4, r4, r12, asl #1	C r4 = inverse
+
+	subs	n, n, #1		C set carry as side-effect
+	beq	L(end)
+
+L(top):	sbcs	cy, r5, cy
+	ldr	r5, [up], #4
+	sub	n, n, #1
+	mul	r12, r4, cy
+	tst	n, n
+	umull	r12, cy, d, r12
+	bne	L(top)
+
+L(end):	sbcs	cy, r5, cy
+	mul	r12, r4, cy
+	umull	r12, r0, d, r12
+	addcc	r0, r0, #1
+
+	ldmfd	sp!, {r4, r5}
+	return	r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/mul_1.asm b/third_party/gmp/mpn/arm/mul_1.asm
new file mode 100644
index 0000000..f7bc1bc
--- /dev/null
+++ b/third_party/gmp/mpn/arm/mul_1.asm
@@ -0,0 +1,94 @@
+dnl  ARM mpn_mul_1 -- Multiply a limb vector with a limb and store the result
+dnl  in a second limb vector.
+dnl  Contributed by Robert Harley.
+
+dnl  Copyright 1998, 2000, 2001, 2003, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C StrongARM	6-8
+C XScale	 ?
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 4.75
+C Cortex-A15	 ?
+
+C We should rewrite this along the lines of addmul_1.asm.  That should save a
+C cycle on StrongARM, and several cycles on XScale.
+
+define(`rp',`r0')
+define(`up',`r1')
+define(`n',`r2')
+define(`vl',`r3')
+
+
+ASM_START()
+PROLOGUE(mpn_mul_1)
+	stmfd	sp!, { r8, r9, lr }
+	ands	r12, n, #1
+	beq	L(skip1)
+	ldr	lr, [up], #4
+	umull	r9, r12, lr, vl
+	str	r9, [rp], #4
+L(skip1):
+	tst	n, #2
+	beq	L(skip2)
+	mov	r8, r12
+	ldmia	up!, { r12, lr }
+	mov	r9, #0
+	umlal	r8, r9, r12, vl
+	mov	r12, #0
+	umlal	r9, r12, lr, vl
+	stmia	rp!, { r8, r9 }
+L(skip2):
+	bics	n, n, #3
+	beq	L(rtn)
+	stmfd	sp!, { r6, r7 }
+
+L(top):	mov	r6, r12
+	ldmia	up!, { r8, r9, r12, lr }
+	ldr	r7, [rp, #12]			C cache allocate
+	mov	r7, #0
+	umlal	r6, r7, r8, vl
+	mov	r8, #0
+	umlal	r7, r8, r9, vl
+	mov	r9, #0
+	umlal	r8, r9, r12, vl
+	mov	r12, #0
+	umlal	r9, r12, lr, vl
+	subs	n, n, #4
+	stmia	rp!, { r6, r7, r8, r9 }
+	bne	L(top)
+
+	ldmfd	sp!, { r6, r7 }
+
+L(rtn):	mov	r0, r12
+	ldmfd	sp!, { r8, r9, pc }
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/neon/README b/third_party/gmp/mpn/arm/neon/README
new file mode 100644
index 0000000..79e3b48
--- /dev/null
+++ b/third_party/gmp/mpn/arm/neon/README
@@ -0,0 +1,2 @@
+This directory contains Neon code which runs and is efficient on all
+ARM CPUs which support Neon.
diff --git a/third_party/gmp/mpn/arm/neon/hamdist.asm b/third_party/gmp/mpn/arm/neon/hamdist.asm
new file mode 100644
index 0000000..2320896
--- /dev/null
+++ b/third_party/gmp/mpn/arm/neon/hamdist.asm
@@ -0,0 +1,194 @@
+dnl  ARM Neon mpn_hamdist -- mpn bit hamming distance.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C StrongARM:	 -
+C XScale	 -
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 1.89
+C Cortex-A15	 0.95
+
+C TODO
+C  * Explore using vldr and vldm.  Does it help on A9?  (These loads do
+C    64-bits-at-a-time, which will mess up in big-endian mode.  Except not for
+C    popcount. Except perhaps also for popcount for the edge loads.)
+C  * Arrange to align the pointer, if that helps performance.  Use the same
+C    read-and-mask trick we use on PCs, for simplicity and performance.  (Sorry
+C    valgrind!)
+C  * Explore if explicit align directives, e.g., "[ptr:128]" help.
+C  * See rth's gmp-devel 2013-02/03 messages about final summation tricks.
+
+C INPUT PARAMETERS
+define(`ap', r0)
+define(`bp', r1)
+define(`n',  r2)
+
+C We sum into 16 16-bit counters in q8,q9, but at the end we sum them and end
+C up with 8 16-bit counters.  Therefore, we can sum to 8(2^16-1) bits, or
+C (8*2^16-1)/32 = 0x3fff limbs.  We use a chunksize close to that, but which
+C can be represented as a 8-bit ARM constant.
+C
+define(`chunksize',0x3f80)
+
+ASM_START()
+PROLOGUE(mpn_hamdist)
+
+	cmp	n, #chunksize
+	bhi	L(gt16k)
+
+L(lt16k):
+	vmov.i64   q8, #0		C clear summation register
+	vmov.i64   q9, #0		C clear summation register
+
+	tst	   n, #1
+	beq	   L(xxx0)
+	vmov.i64   d0, #0
+	vmov.i64   d20, #0
+	sub	   n, n, #1
+	vld1.32   {d0[0]}, [ap]!	C load 1 limb
+	vld1.32   {d20[0]}, [bp]!	C load 1 limb
+	veor	   d0, d0, d20
+	vcnt.8	   d24, d0
+	vpadal.u8  d16, d24		C d16/q8 = 0; could just splat
+
+L(xxx0):tst	   n, #2
+	beq	   L(xx00)
+	sub	   n, n, #2
+	vld1.32    {d0}, [ap]!		C load 2 limbs
+	vld1.32    {d20}, [bp]!		C load 2 limbs
+	veor	   d0, d0, d20
+	vcnt.8	   d24, d0
+	vpadal.u8  d16, d24
+
+L(xx00):tst	   n, #4
+	beq	   L(x000)
+	sub	   n, n, #4
+	vld1.32    {q0}, [ap]!		C load 4 limbs
+	vld1.32    {q10}, [bp]!		C load 4 limbs
+	veor	   q0, q0, q10
+	vcnt.8	   q12, q0
+	vpadal.u8  q8, q12
+
+L(x000):tst	   n, #8
+	beq	   L(0000)
+
+	subs	   n, n, #8
+	vld1.32    {q0,q1}, [ap]!	C load 8 limbs
+	vld1.32    {q10,q11}, [bp]!	C load 8 limbs
+	bls	   L(sum)
+
+L(gt8):	vld1.32    {q2,q3}, [ap]!	C load 8 limbs
+	vld1.32    {q14,q15}, [bp]!	C load 8 limbs
+	veor	   q0, q0, q10
+	veor	   q1, q1, q11
+	sub	   n, n, #8
+	vcnt.8	   q12, q0
+	vcnt.8	   q13, q1
+	b	   L(mid)
+
+L(0000):subs	   n, n, #16
+	blo	   L(e0)
+
+	vld1.32    {q2,q3}, [ap]!	C load 8 limbs
+	vld1.32    {q0,q1}, [ap]!	C load 8 limbs
+	vld1.32    {q14,q15}, [bp]!	C load 8 limbs
+	vld1.32    {q10,q11}, [bp]!	C load 8 limbs
+	veor	   q2, q2, q14
+	veor	   q3, q3, q15
+	vcnt.8	   q12, q2
+	vcnt.8	   q13, q3
+	subs	   n, n, #16
+	blo	   L(end)
+
+L(top):	vld1.32    {q2,q3}, [ap]!	C load 8 limbs
+	vld1.32    {q14,q15}, [bp]!	C load 8 limbs
+	veor	   q0, q0, q10
+	veor	   q1, q1, q11
+	vpadal.u8  q8, q12
+	vcnt.8	   q12, q0
+	vpadal.u8  q9, q13
+	vcnt.8	   q13, q1
+L(mid):	vld1.32    {q0,q1}, [ap]!	C load 8 limbs
+	vld1.32    {q10,q11}, [bp]!	C load 8 limbs
+	veor	   q2, q2, q14
+	veor	   q3, q3, q15
+	subs	   n, n, #16
+	vpadal.u8  q8, q12
+	vcnt.8	   q12, q2
+	vpadal.u8  q9, q13
+	vcnt.8	   q13, q3
+	bhs	   L(top)
+
+L(end):	vpadal.u8  q8, q12
+	vpadal.u8  q9, q13
+L(sum):	veor	   q0, q0, q10
+	veor	   q1, q1, q11
+	vcnt.8	   q12, q0
+	vcnt.8	   q13, q1
+	vpadal.u8  q8, q12
+	vpadal.u8  q9, q13
+	vadd.i16   q8, q8, q9
+					C we have 8 16-bit counts
+L(e0):	vpaddl.u16 q8, q8		C we have 4 32-bit counts
+	vpaddl.u32 q8, q8		C we have 2 64-bit counts
+	vmov.32    r0, d16[0]
+	vmov.32    r1, d17[0]
+	add	   r0, r0, r1
+	bx	lr
+
+C Code for large count.  Splits operand and calls above code.
+define(`ap2', r5)
+define(`bp2', r6)
+L(gt16k):
+	push	{r4,r5,r6,r14}
+	mov	ap2, ap
+	mov	bp2, bp
+	mov	r3, n			C full count
+	mov	r4, #0			C total sum
+
+1:	mov	n, #chunksize		C count for this invocation
+	bl	L(lt16k)		C could jump deep inside code
+	add	ap2, ap2, #chunksize*4	C point at next chunk
+	add	bp2, bp2, #chunksize*4	C point at next chunk
+	add	r4, r4, r0
+	mov	ap, ap2			C put chunk pointer in place for call
+	mov	bp, bp2			C put chunk pointer in place for call
+	sub	r3, r3, #chunksize
+	cmp	r3, #chunksize
+	bhi	1b
+
+	mov	n, r3			C count for final invocation
+	bl	L(lt16k)
+	add	r0, r4, r0
+	pop	{r4,r5,r6,pc}
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/neon/lorrshift.asm b/third_party/gmp/mpn/arm/neon/lorrshift.asm
new file mode 100644
index 0000000..7ebc780
--- /dev/null
+++ b/third_party/gmp/mpn/arm/neon/lorrshift.asm
@@ -0,0 +1,279 @@
+dnl  ARM Neon mpn_lshift and mpn_rshift.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb     cycles/limb     cycles/limb      good
+C              aligned	      unaligned	      best seen	     for cpu?
+C StrongARM	 -		 -
+C XScale	 -		 -
+C Cortex-A7	 ?		 ?
+C Cortex-A8	 ?		 ?
+C Cortex-A9	 3		 3				Y
+C Cortex-A15	 1.5		 1.5				Y
+
+
+C We read 64 bits at a time at 32-bit aligned addresses, and except for the
+C first and last store, we write using 64-bit aligned addresses.  All shifting
+C is done on 64-bit words in 'extension' registers.
+C
+C It should be possible to read also using 64-bit alignment, by manipulating
+C the shift count for unaligned operands.  Not done, since it does not seem to
+C matter for A9 or A15.
+C
+C This will not work in big-endian mode.
+
+C TODO
+C  * Try using 128-bit operations.  Note that Neon lacks pure 128-bit shifts,
+C    which might make it tricky.
+C  * Clean up and simplify.
+C  * Consider sharing most of the code for lshift and rshift, since the feed-in
+C    code, the loop, and most of the wind-down code are identical.
+C  * Replace the basecase code with code using 'extension' registers.
+C  * Optimise.  It is not clear that this loop insn permutation is optimal for
+C    either A9 or A15.
+
+C INPUT PARAMETERS
+define(`rp',  `r0')
+define(`ap',  `r1')
+define(`n',   `r2')
+define(`cnt', `r3')
+
+ifdef(`OPERATION_lshift',`
+	define(`IFLSH', `$1')
+	define(`IFRSH', `')
+	define(`X',`0')
+	define(`Y',`1')
+	define(`func',`mpn_lshift')
+')
+ifdef(`OPERATION_rshift',`
+	define(`IFLSH', `')
+	define(`IFRSH', `$1')
+	define(`X',`1')
+	define(`Y',`0')
+	define(`func',`mpn_rshift')
+')
+
+MULFUNC_PROLOGUE(mpn_lshift mpn_rshift)
+
+ASM_START(neon)
+	TEXT
+	ALIGN(64)
+PROLOGUE(func)
+IFLSH(`	mov	r12, n, lsl #2	')
+IFLSH(`	add	rp, rp, r12	')
+IFLSH(`	add	ap, ap, r12	')
+
+	cmp	n, #4			C SIMD code n limit
+	ble	L(base)
+
+ifdef(`OPERATION_lshift',`
+	vdup.32	d6, r3			C left shift count is positive
+	sub	r3, r3, #64		C right shift count is negative
+	vdup.32	d7, r3
+	mov	r12, #-8')		C lshift pointer update offset
+ifdef(`OPERATION_rshift',`
+	rsb	r3, r3, #0		C right shift count is negative
+	vdup.32	d6, r3
+	add	r3, r3, #64		C left shift count is positive
+	vdup.32	d7, r3
+	mov	r12, #8')		C rshift pointer update offset
+
+IFLSH(`	sub	ap, ap, #8	')
+	vld1.32	{d19}, [ap], r12	C load initial 2 limbs
+	vshl.u64 d18, d19, d7		C retval
+
+	tst	rp, #4			C is rp 64-bit aligned already?
+	beq	L(rp_aligned)		C yes, skip
+IFLSH(`	add	ap, ap, #4	')	C move back ap pointer
+IFRSH(`	sub	ap, ap, #4	')	C move back ap pointer
+	vshl.u64 d4, d19, d6
+	sub	n, n, #1		C first limb handled
+IFLSH(`	sub	 rp, rp, #4	')
+	vst1.32	 {d4[Y]}, [rp]IFRSH(!)	C store first limb, rp gets aligned
+	vld1.32	 {d19}, [ap], r12	C load ap[1] and ap[2]
+
+L(rp_aligned):
+IFLSH(`	sub	rp, rp, #8	')
+	subs	n, n, #6
+	blt	L(two_or_three_more)
+	tst	n, #2
+	beq	L(2)
+
+L(1):	vld1.32	 {d17}, [ap], r12
+	vshl.u64 d5, d19, d6
+	vld1.32	 {d16}, [ap], r12
+	vshl.u64 d0, d17, d7
+	vshl.u64 d4, d17, d6
+	sub	n, n, #2
+	b	 L(mid)
+
+L(2):	vld1.32	 {d16}, [ap], r12
+	vshl.u64 d4, d19, d6
+	vld1.32	 {d17}, [ap], r12
+	vshl.u64 d1, d16, d7
+	vshl.u64 d5, d16, d6
+	subs	n, n, #4
+	blt	L(end)
+
+L(top):	vld1.32	 {d16}, [ap], r12
+	vorr	 d2, d4, d1
+	vshl.u64 d0, d17, d7
+	vshl.u64 d4, d17, d6
+	vst1.32	 {d2}, [rp:64], r12
+L(mid):	vld1.32	 {d17}, [ap], r12
+	vorr	 d3, d5, d0
+	vshl.u64 d1, d16, d7
+	vshl.u64 d5, d16, d6
+	vst1.32	 {d3}, [rp:64], r12
+	subs	n, n, #4
+	bge	L(top)
+
+L(end):	tst	 n, #1
+	beq	 L(evn)
+
+	vorr	 d2, d4, d1
+	vst1.32	 {d2}, [rp:64], r12
+	b	 L(cj1)
+
+L(evn):	vorr	 d2, d4, d1
+	vshl.u64 d0, d17, d7
+	vshl.u64 d16, d17, d6
+	vst1.32	 {d2}, [rp:64], r12
+	vorr	 d2, d5, d0
+	b	 L(cj2)
+
+C Load last 2 - 3 limbs, store last 4 - 5 limbs
+L(two_or_three_more):
+	tst	n, #1
+	beq	L(l2)
+
+L(l3):	vshl.u64 d5, d19, d6
+	vld1.32	 {d17}, [ap], r12
+L(cj1):	veor	 d16, d16, d16
+IFLSH(`	add	 ap, ap, #4	')
+	vld1.32	 {d16[Y]}, [ap], r12
+	vshl.u64 d0, d17, d7
+	vshl.u64 d4, d17, d6
+	vorr	 d3, d5, d0
+	vshl.u64 d1, d16, d7
+	vshl.u64 d5, d16, d6
+	vst1.32	 {d3}, [rp:64], r12
+	vorr	 d2, d4, d1
+	vst1.32	 {d2}, [rp:64], r12
+IFLSH(`	add	 rp, rp, #4	')
+	vst1.32	 {d5[Y]}, [rp]
+	vmov.32	 r0, d18[X]
+	bx	lr
+
+L(l2):	vld1.32	 {d16}, [ap], r12
+	vshl.u64 d4, d19, d6
+	vshl.u64 d1, d16, d7
+	vshl.u64 d16, d16, d6
+	vorr	 d2, d4, d1
+L(cj2):	vst1.32	 {d2}, [rp:64], r12
+	vst1.32	 {d16}, [rp]
+	vmov.32	 r0, d18[X]
+	bx	lr
+
+
+define(`tnc', `r12')
+L(base):
+	push	{r4, r6, r7, r8}
+ifdef(`OPERATION_lshift',`
+	ldr	r4, [ap, #-4]!
+	rsb	tnc, cnt, #32
+
+	mov	r7, r4, lsl cnt
+	tst	n, #1
+	beq	L(ev)			C n even
+
+L(od):	subs	n, n, #2
+	bcc	L(ed1)			C n = 1
+	ldr	r8, [ap, #-4]!
+	b	L(md)			C n = 3
+
+L(ev):	ldr	r6, [ap, #-4]!
+	subs	n, n, #2
+	beq	L(ed)			C n = 3
+					C n = 4
+L(tp):	ldr	r8, [ap, #-4]!
+	orr	r7, r7, r6, lsr tnc
+	str	r7, [rp, #-4]!
+	mov	r7, r6, lsl cnt
+L(md):	ldr	r6, [ap, #-4]!
+	orr	r7, r7, r8, lsr tnc
+	str	r7, [rp, #-4]!
+	mov	r7, r8, lsl cnt
+
+L(ed):	orr	r7, r7, r6, lsr tnc
+	str	r7, [rp, #-4]!
+	mov	r7, r6, lsl cnt
+L(ed1):	str	r7, [rp, #-4]
+	mov	r0, r4, lsr tnc
+')
+ifdef(`OPERATION_rshift',`
+	ldr	r4, [ap]
+	rsb	tnc, cnt, #32
+
+	mov	r7, r4, lsr cnt
+	tst	n, #1
+	beq	L(ev)			C n even
+
+L(od):	subs	n, n, #2
+	bcc	L(ed1)			C n = 1
+	ldr	r8, [ap, #4]!
+	b	L(md)			C n = 3
+
+L(ev):	ldr	r6, [ap, #4]!
+	subs	n, n, #2
+	beq	L(ed)			C n = 2
+					C n = 4
+
+L(tp):	ldr	r8, [ap, #4]!
+	orr	r7, r7, r6, lsl tnc
+	str	r7, [rp], #4
+	mov	r7, r6, lsr cnt
+L(md):	ldr	r6, [ap, #4]!
+	orr	r7, r7, r8, lsl tnc
+	str	r7, [rp], #4
+	mov	r7, r8, lsr cnt
+
+L(ed):	orr	r7, r7, r6, lsl tnc
+	str	r7, [rp], #4
+	mov	r7, r6, lsr cnt
+L(ed1):	str	r7, [rp], #4
+	mov	r0, r4, lsl tnc
+')
+	pop	{r4, r6, r7, r8}
+	bx	r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/neon/lshiftc.asm b/third_party/gmp/mpn/arm/neon/lshiftc.asm
new file mode 100644
index 0000000..f1bf0de
--- /dev/null
+++ b/third_party/gmp/mpn/arm/neon/lshiftc.asm
@@ -0,0 +1,242 @@
+dnl  ARM Neon mpn_lshiftc.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb     cycles/limb     cycles/limb      good
+C              aligned	      unaligned	      best seen	     for cpu?
+C StrongARM	 -		 -
+C XScale	 -		 -
+C Cortex-A7	 ?		 ?
+C Cortex-A8	 ?		 ?
+C Cortex-A9	 3.5		 3.5				Y
+C Cortex-A15	 1.75		 1.75				Y
+
+
+C We read 64 bits at a time at 32-bit aligned addresses, and except for the
+C first and last store, we write using 64-bit aligned addresses.  All shifting
+C is done on 64-bit words in 'extension' registers.
+C
+C It should be possible to read also using 64-bit alignment, by manipulating
+C the shift count for unaligned operands.  Not done, since it does not seem to
+C matter for A9 or A15.
+C
+C This will not work in big-endian mode.
+
+C TODO
+C  * Try using 128-bit operations.  Note that Neon lacks pure 128-bit shifts,
+C    which might make it tricky.
+C  * Clean up and simplify.
+C  * Consider sharing most of the code for lshift and rshift, since the feed-in
+C    code, the loop, and most of the wind-down code are identical.
+C  * Replace the basecase code with code using 'extension' registers.
+C  * Optimise.  It is not clear that this loop insn permutation is optimal for
+C    either A9 or A15.
+
+C INPUT PARAMETERS
+define(`rp',  `r0')
+define(`ap',  `r1')
+define(`n',   `r2')
+define(`cnt', `r3')
+
+ASM_START(neon)
+	TEXT
+	ALIGN(64)
+PROLOGUE(mpn_lshiftc)
+	mov	r12, n, lsl #2
+	add	rp, rp, r12
+	add	ap, ap, r12
+
+	cmp	n, #4			C SIMD code n limit
+	ble	L(base)
+
+	vdup.32	d6, r3			C left shift count is positive
+	sub	r3, r3, #64		C right shift count is negative
+	vdup.32	d7, r3
+	mov	r12, #-8		C lshift pointer update offset
+
+	sub	ap, ap, #8
+	vld1.32	{d19}, [ap], r12	C load initial 2 limbs
+	vshl.u64 d18, d19, d7		C retval
+
+	tst	rp, #4			C is rp 64-bit aligned already?
+	beq	L(rp_aligned)		C yes, skip
+	vmvn	 d19, d19
+	add	ap, ap, #4		C move back ap pointer
+	vshl.u64 d4, d19, d6
+	sub	n, n, #1		C first limb handled
+	sub	 rp, rp, #4
+	vst1.32	 {d4[1]}, [rp]		C store first limb, rp gets aligned
+	vld1.32	 {d19}, [ap], r12	C load ap[1] and ap[2]
+
+L(rp_aligned):
+	sub	rp, rp, #8
+	subs	n, n, #6
+	vmvn	 d19, d19
+	blt	L(two_or_three_more)
+	tst	n, #2
+	beq	L(2)
+
+L(1):	vld1.32	 {d17}, [ap], r12
+	vshl.u64 d5, d19, d6
+	vmvn	 d17, d17
+	vld1.32	 {d16}, [ap], r12
+	vshl.u64 d0, d17, d7
+	vshl.u64 d4, d17, d6
+	sub	n, n, #2
+	b	 L(mid)
+
+L(2):	vld1.32	 {d16}, [ap], r12
+	vshl.u64 d4, d19, d6
+	vmvn	 d16, d16
+	vld1.32	 {d17}, [ap], r12
+	vshl.u64 d1, d16, d7
+	vshl.u64 d5, d16, d6
+	subs	n, n, #4
+	blt	L(end)
+
+L(top):	vmvn	 d17, d17
+	vld1.32	 {d16}, [ap], r12
+	vorr	 d2, d4, d1
+	vshl.u64 d0, d17, d7
+	vshl.u64 d4, d17, d6
+	vst1.32	 {d2}, [rp:64], r12
+L(mid):	vmvn	 d16, d16
+	vld1.32	 {d17}, [ap], r12
+	vorr	 d3, d5, d0
+	vshl.u64 d1, d16, d7
+	vshl.u64 d5, d16, d6
+	vst1.32	 {d3}, [rp:64], r12
+	subs	n, n, #4
+	bge	L(top)
+
+L(end):	tst	 n, #1
+	beq	 L(evn)
+
+	vorr	 d2, d4, d1
+	vst1.32	 {d2}, [rp:64], r12
+	b	 L(cj1)
+
+L(evn):	vmvn	 d17, d17
+	vorr	 d2, d4, d1
+	vshl.u64 d0, d17, d7
+	vshl.u64 d4, d17, d6
+	vst1.32	 {d2}, [rp:64], r12
+	vmov.u8	 d17, #255
+	vorr	 d2, d5, d0
+	vshl.u64 d0, d17, d7
+	vorr	 d3, d4, d0
+	b	 L(cj2)
+
+C Load last 2 - 3 limbs, store last 4 - 5 limbs
+L(two_or_three_more):
+	tst	n, #1
+	beq	L(l2)
+
+L(l3):	vshl.u64 d5, d19, d6
+	vld1.32	 {d17}, [ap], r12
+L(cj1):	vmov.u8	 d16, #0
+	add	 ap, ap, #4
+	vmvn	 d17, d17
+	vld1.32	 {d16[1]}, [ap], r12
+	vshl.u64 d0, d17, d7
+	vshl.u64 d4, d17, d6
+	vmvn	 d16, d16
+	vorr	 d3, d5, d0
+	vshl.u64 d1, d16, d7
+	vshl.u64 d5, d16, d6
+	vst1.32	 {d3}, [rp:64], r12
+	vorr	 d2, d4, d1
+	vst1.32	 {d2}, [rp:64], r12
+	add	 rp, rp, #4
+	vst1.32	 {d5[1]}, [rp]
+	vmov.32	 r0, d18[0]
+	bx	lr
+
+L(l2):	vld1.32	 {d16}, [ap], r12
+	vshl.u64 d4, d19, d6
+	vmvn	 d16, d16
+	vshl.u64 d1, d16, d7
+	vshl.u64 d5, d16, d6
+	vmov.u8	 d17, #255
+	vorr	 d2, d4, d1
+	vshl.u64 d0, d17, d7
+	vorr	 d3, d5, d0
+L(cj2):	vst1.32	 {d2}, [rp:64], r12
+	vst1.32	 {d3}, [rp]
+	vmov.32	 r0, d18[0]
+	bx	lr
+
+
+define(`tnc', `r12')
+L(base):
+	push	{r4, r6, r7, r8}
+	ldr	r4, [ap, #-4]!
+	rsb	tnc, cnt, #32
+	mvn	r6, r4
+
+	mov	r7, r6, lsl cnt
+	tst	n, #1
+	beq	L(ev)			C n even
+
+L(od):	subs	n, n, #2
+	bcc	L(ed1)			C n = 1
+	ldr	r8, [ap, #-4]!
+	mvn	r8, r8
+	b	L(md)			C n = 3
+
+L(ev):	ldr	r6, [ap, #-4]!
+	mvn	r6, r6
+	subs	n, n, #2
+	beq	L(ed)			C n = 3
+					C n = 4
+L(tp):	ldr	r8, [ap, #-4]!
+	orr	r7, r7, r6, lsr tnc
+	str	r7, [rp, #-4]!
+	mvn	r8, r8
+	mov	r7, r6, lsl cnt
+L(md):	ldr	r6, [ap, #-4]!
+	orr	r7, r7, r8, lsr tnc
+	str	r7, [rp, #-4]!
+	mvn	r6, r6
+	mov	r7, r8, lsl cnt
+
+L(ed):	orr	r7, r7, r6, lsr tnc
+	str	r7, [rp, #-4]!
+	mov	r7, r6, lsl cnt
+L(ed1):	mvn	r6, #0
+	orr	r7, r7, r6, lsr tnc
+	str	r7, [rp, #-4]
+	mov	r0, r4, lsr tnc
+	pop	{r4, r6, r7, r8}
+	bx	r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/neon/popcount.asm b/third_party/gmp/mpn/arm/neon/popcount.asm
new file mode 100644
index 0000000..2f8f9af
--- /dev/null
+++ b/third_party/gmp/mpn/arm/neon/popcount.asm
@@ -0,0 +1,166 @@
+dnl  ARM Neon mpn_popcount -- mpn bit population count.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C StrongARM:	 -
+C XScale	 -
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 1.125
+C Cortex-A15	 0.56
+
+C TODO
+C  * Explore using vldr and vldm.  Does it help on A9?  (These loads do
+C    64-bits-at-a-time, which will mess up in big-endian mode.  Except not for
+C    popcount. Except perhaps also for popcount for the edge loads.)
+C  * Arrange to align the pointer, if that helps performance.  Use the same
+C    read-and-mask trick we use on PCs, for simplicity and performance.  (Sorry
+C    valgrind!)
+C  * Explore if explicit align directives, e.g., "[ptr:128]" help.
+C  * See rth's gmp-devel 2013-02/03 messages about final summation tricks.
+
+C INPUT PARAMETERS
+define(`ap', r0)
+define(`n',  r1)
+
+C We sum into 16 16-bit counters in q8,q9, but at the end we sum them and end
+C up with 8 16-bit counters.  Therefore, we can sum to 8(2^16-1) bits, or
+C (8*2^16-1)/32 = 0x3fff limbs.  We use a chunksize close to that, but which
+C can be represented as a 8-bit ARM constant.
+C
+define(`chunksize',0x3f80)
+
+ASM_START()
+PROLOGUE(mpn_popcount)
+
+	cmp	n, #chunksize
+	bhi	L(gt16k)
+
+L(lt16k):
+	vmov.i64   q8, #0		C clear summation register
+	vmov.i64   q9, #0		C clear summation register
+
+	tst	   n, #1
+	beq	   L(xxx0)
+	vmov.i64   d0, #0
+	sub	   n, n, #1
+	vld1.32   {d0[0]}, [ap]!	C load 1 limb
+	vcnt.8	   d24, d0
+	vpadal.u8  d16, d24		C d16/q8 = 0; could just splat
+
+L(xxx0):tst	   n, #2
+	beq	   L(xx00)
+	sub	   n, n, #2
+	vld1.32    {d0}, [ap]!		C load 2 limbs
+	vcnt.8	   d24, d0
+	vpadal.u8  d16, d24
+
+L(xx00):tst	   n, #4
+	beq	   L(x000)
+	sub	   n, n, #4
+	vld1.32    {q0}, [ap]!		C load 4 limbs
+	vcnt.8	   q12, q0
+	vpadal.u8  q8, q12
+
+L(x000):tst	   n, #8
+	beq	   L(0000)
+
+	subs	   n, n, #8
+	vld1.32    {q0,q1}, [ap]!	C load 8 limbs
+	bls	   L(sum)
+
+L(gt8):	vld1.32    {q2,q3}, [ap]!	C load 8 limbs
+	sub	   n, n, #8
+	vcnt.8	   q12, q0
+	vcnt.8	   q13, q1
+	b	   L(mid)
+
+L(0000):subs	   n, n, #16
+	blo	   L(e0)
+
+	vld1.32    {q2,q3}, [ap]!	C load 8 limbs
+	vld1.32    {q0,q1}, [ap]!	C load 8 limbs
+	vcnt.8	   q12, q2
+	vcnt.8	   q13, q3
+	subs	   n, n, #16
+	blo	   L(end)
+
+L(top):	vld1.32    {q2,q3}, [ap]!	C load 8 limbs
+	vpadal.u8  q8, q12
+	vcnt.8	   q12, q0
+	vpadal.u8  q9, q13
+	vcnt.8	   q13, q1
+L(mid):	vld1.32    {q0,q1}, [ap]!	C load 8 limbs
+	subs	   n, n, #16
+	vpadal.u8  q8, q12
+	vcnt.8	   q12, q2
+	vpadal.u8  q9, q13
+	vcnt.8	   q13, q3
+	bhs	   L(top)
+
+L(end):	vpadal.u8  q8, q12
+	vpadal.u8  q9, q13
+L(sum):	vcnt.8	   q12, q0
+	vcnt.8	   q13, q1
+	vpadal.u8  q8, q12
+	vpadal.u8  q9, q13
+	vadd.i16   q8, q8, q9
+					C we have 8 16-bit counts
+L(e0):	vpaddl.u16 q8, q8		C we have 4 32-bit counts
+	vpaddl.u32 q8, q8		C we have 2 64-bit counts
+	vmov.32    r0, d16[0]
+	vmov.32    r1, d17[0]
+	add	   r0, r0, r1
+	bx	lr
+
+C Code for large count.  Splits operand and calls above code.
+define(`ap2', r2)			C caller-saves reg not used above
+L(gt16k):
+	push	{r4,r14}
+	mov	ap2, ap
+	mov	r3, n			C full count
+	mov	r4, #0			C total sum
+
+1:	mov	n, #chunksize		C count for this invocation
+	bl	L(lt16k)		C could jump deep inside code
+	add	ap2, ap2, #chunksize*4	C point at next chunk
+	add	r4, r4, r0
+	mov	ap, ap2			C put chunk pointer in place for call
+	sub	r3, r3, #chunksize
+	cmp	r3, #chunksize
+	bhi	1b
+
+	mov	n, r3			C count for final invocation
+	bl	L(lt16k)
+	add	r0, r4, r0
+	pop	{r4,pc}
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/neon/sec_tabselect.asm b/third_party/gmp/mpn/arm/neon/sec_tabselect.asm
new file mode 100644
index 0000000..69fceb0
--- /dev/null
+++ b/third_party/gmp/mpn/arm/neon/sec_tabselect.asm
@@ -0,0 +1,140 @@
+dnl  ARM Neon mpn_sec_tabselect.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C	     cycles/limb
+C StrongARM	 -
+C XScale	 -
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 1.15
+C Cortex-A15	 0.65
+
+define(`rp',     `r0')
+define(`tp',     `r1')
+define(`n',      `r2')
+define(`nents',  `r3')
+C define(`which',  on stack)
+
+define(`i',      `r4')
+define(`j',      `r5')
+
+define(`maskq',  `q10')
+define(`maskd',  `d20')
+
+ASM_START()
+PROLOGUE(mpn_sec_tabselect)
+	push	{r4-r5}
+
+	add	  r4, sp, #8
+	vld1.32	  {d30[], d31[]}, [r4]	C 4 `which' copies
+	vmov.i32  q14, #1		C 4 copies of 1
+
+	subs	j, n, #8
+	bmi	L(outer_end)
+
+L(outer_top):
+	mov	  i, nents
+	mov	  r12, tp		C preserve tp
+	veor	  q13, q13, q13		C 4 counter copies
+	veor	  q2, q2, q2
+	veor	  q3, q3, q3
+	ALIGN(16)
+L(top):	vceq.i32  maskq, q13, q15	C compare idx copies to `which' copies
+	vld1.32	  {q0,q1}, [tp]
+	vadd.i32  q13, q13, q14
+	vbit	  q2, q0, maskq
+	vbit	  q3, q1, maskq
+	add	  tp, tp, n, lsl #2
+	subs	  i, i, #1
+	bne	  L(top)
+	vst1.32	  {q2,q3}, [rp]!
+	add	  tp, r12, #32		C restore tp, point to next slice
+	subs	  j, j, #8
+	bpl	  L(outer_top)
+L(outer_end):
+
+	tst	  n, #4
+	beq	  L(b0xx)
+L(b1xx):mov	  i, nents
+	mov	  r12, tp
+	veor	  q13, q13, q13
+	veor	  q2, q2, q2
+	ALIGN(16)
+L(tp4):	vceq.i32  maskq, q13, q15
+	vld1.32	  {q0}, [tp]
+	vadd.i32  q13, q13, q14
+	vbit	  q2, q0, maskq
+	add	  tp, tp, n, lsl #2
+	subs	  i, i, #1
+	bne	  L(tp4)
+	vst1.32	  {q2}, [rp]!
+	add	  tp, r12, #16
+
+L(b0xx):tst	  n, #2
+	beq	  L(b00x)
+L(b01x):mov	  i, nents
+	mov	  r12, tp
+	veor	  d26, d26, d26
+	veor	  d4, d4, d4
+	ALIGN(16)
+L(tp2):	vceq.i32  maskd, d26, d30
+	vld1.32	  {d0}, [tp]
+	vadd.i32  d26, d26, d28
+	vbit	  d4, d0, maskd
+	add	  tp, tp, n, lsl #2
+	subs	  i, i, #1
+	bne	  L(tp2)
+	vst1.32	  {d4}, [rp]!
+	add	  tp, r12, #8
+
+L(b00x):tst	  n, #1
+	beq	  L(b000)
+L(b001):mov	  i, nents
+	mov	  r12, tp
+	veor	  d26, d26, d26
+	veor	  d4, d4, d4
+	ALIGN(16)
+L(tp1):	vceq.i32  maskd, d26, d30
+	vld1.32	  {d0[0]}, [tp]
+	vadd.i32  d26, d26, d28
+	vbit	  d4, d0, maskd
+	add	  tp, tp, n, lsl #2
+	subs	  i, i, #1
+	bne	  L(tp1)
+	vst1.32	  {d4[0]}, [rp]
+
+L(b000):pop	{r4-r5}
+	bx	r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/rsh1aors_n.asm b/third_party/gmp/mpn/arm/rsh1aors_n.asm
new file mode 100644
index 0000000..f2e3006
--- /dev/null
+++ b/third_party/gmp/mpn/arm/rsh1aors_n.asm
@@ -0,0 +1,124 @@
+dnl  ARM mpn_rsh1add_n and mpn_rsh1sub_n.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C StrongARM	 ?
+C XScale	 ?
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	3.64-3.7
+C Cortex-A15	 2.5
+
+C TODO
+C  * Not optimised.
+
+define(`rp', `r0')
+define(`up', `r1')
+define(`vp', `r2')
+define(`n',  `r3')
+
+ifdef(`OPERATION_rsh1add_n', `
+  define(`ADDSUB',	adds)
+  define(`ADDSUBC',	adcs)
+  define(`RSTCY',	`cmn	$1, $1')
+  define(`func',	mpn_rsh1add_n)
+  define(`func_nc',	mpn_rsh1add_nc)')
+ifdef(`OPERATION_rsh1sub_n', `
+  define(`ADDSUB',	subs)
+  define(`ADDSUBC',	sbcs)
+  define(`RSTCY',
+	`mvn	$2, #0x80000000
+	cmp	$2, $1')
+  define(`func',	mpn_rsh1sub_n)
+  define(`func_nc',	mpn_rsh1sub_nc)')
+
+MULFUNC_PROLOGUE(mpn_rsh1add_n mpn_rsh1sub_n)
+
+ASM_START()
+PROLOGUE(func)
+	push	{r4-r11}
+	ldr	r4, [up], #4
+	ldr	r8, [vp], #4
+	ADDSUB	r4, r4, r8
+	movs	r12, r7, rrx
+	and	r11, r4, #1	C return value
+	subs	n, n, #4
+	blo	L(end)
+
+L(top):	ldmia	up!, {r5,r6,r7}
+	ldmia	vp!, {r8,r9,r10}
+	cmn	r12, r12
+	ADDSUBC	r5, r5, r8
+	ADDSUBC	r6, r6, r9
+	ADDSUBC	r7, r7, r10
+	movs	r12, r7, rrx
+	movs	r6, r6, rrx
+	movs	r5, r5, rrx
+	movs	r4, r4, rrx
+	subs	n, n, #3
+	stmia	rp!, {r4,r5,r6}
+	mov	r4, r7
+	bhs	L(top)
+
+L(end):	cmn	n, #2
+	bls	L(e2)
+	ldm	up, {r5,r6}
+	ldm	vp, {r8,r9}
+	cmn	r12, r12
+	ADDSUBC	r5, r5, r8
+	ADDSUBC	r6, r6, r9
+	movs	r12, r6, rrx
+	movs	r5, r5, rrx
+	movs	r4, r4, rrx
+	stmia	rp!, {r4,r5}
+	mov	r4, r6
+	b	L(e1)
+
+L(e2):	bne	L(e1)
+	ldr	r5, [up, #0]
+	ldr	r8, [vp, #0]
+	cmn	r12, r12
+	ADDSUBC	r5, r5, r8
+	movs	r12, r5, rrx
+	movs	r4, r4, rrx
+	str	r4, [rp], #4
+	mov	r4, r5
+
+L(e1):	RSTCY(	r12, r1)
+	mov	r4, r4, rrx
+	str	r4, [rp, #0]
+	mov	r0, r11
+	pop	{r4-r11}
+	return	r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/rshift.asm b/third_party/gmp/mpn/arm/rshift.asm
new file mode 100644
index 0000000..9ddbc2e
--- /dev/null
+++ b/third_party/gmp/mpn/arm/rshift.asm
@@ -0,0 +1,86 @@
+dnl  ARM mpn_rshift.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 1997, 2000, 2001, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C StrongARM	 ?
+C XScale	 ?
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 3.5
+C Cortex-A15	 ?
+
+define(`rp',  `r0')
+define(`up',  `r1')
+define(`n',   `r2')
+define(`cnt', `r3')
+define(`tnc', `r12')
+
+ASM_START()
+PROLOGUE(mpn_rshift)
+	push	{r4, r6, r7, r8}
+	ldr	r4, [up]
+	rsb	tnc, cnt, #32
+
+	mov	r7, r4, lsr cnt
+	tst	n, #1
+	beq	L(evn)			C n even
+
+L(odd):	subs	n, n, #2
+	bcc	L(1)			C n = 1
+	ldr	r8, [up, #4]!
+	b	L(mid)
+
+L(evn):	ldr	r6, [up, #4]!
+	subs	n, n, #2
+	beq	L(end)
+
+L(top):	ldr	r8, [up, #4]!
+	orr	r7, r7, r6, lsl tnc
+	str	r7, [rp], #4
+	mov	r7, r6, lsr cnt
+L(mid):	ldr	r6, [up, #4]!
+	orr	r7, r7, r8, lsl tnc
+	str	r7, [rp], #4
+	mov	r7, r8, lsr cnt
+	subs	n, n, #2
+	bgt	L(top)
+
+L(end):	orr	r7, r7, r6, lsl tnc
+	str	r7, [rp], #4
+	mov	r7, r6, lsr cnt
+L(1):	str	r7, [rp]
+	mov	r0, r4, lsl tnc
+	pop	{r4, r6, r7, r8}
+	return	r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/sec_tabselect.asm b/third_party/gmp/mpn/arm/sec_tabselect.asm
new file mode 100644
index 0000000..76a412b
--- /dev/null
+++ b/third_party/gmp/mpn/arm/sec_tabselect.asm
@@ -0,0 +1,131 @@
+dnl  ARM mpn_sec_tabselect
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C StrongARM	 ?
+C XScale	 ?
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 2.33
+C Cortex-A15	 2.2
+
+C TODO
+C  * Consider using special code for small nents, either swapping the inner and
+C    outer loops, or providing a few completely unrolling the inner loops.
+
+define(`rp',    `r0')
+define(`tp',    `r1')
+define(`n',     `r2')
+define(`nents', `r3')
+C      which  on stack
+
+define(`i',     `r11')
+define(`j',     `r12')
+define(`c',     `r14')
+define(`mask',  `r7')
+
+ASM_START()
+PROLOGUE(mpn_sec_tabselect)
+	push	{r4-r11, r14}
+
+	subs	j, n, #3
+	bmi	L(outer_end)
+L(outer_top):
+	ldr	c, [sp, #36]
+	mov	i, nents
+	push	{tp}
+
+	mov	r8, #0
+	mov	r9, #0
+	mov	r10, #0
+
+L(top):	subs	c, c, #1
+	ldm	tp, {r4,r5,r6}
+	sbc	mask, mask, mask
+	subs	i, i, #1
+	add	tp, tp, n, lsl #2
+	and	r4, r4, mask
+	and	r5, r5, mask
+	and	r6, r6, mask
+	orr	r8, r8, r4
+	orr	r9, r9, r5
+	orr	r10, r10, r6
+	bge	L(top)
+
+	stmia	rp!, {r8,r9,r10}
+	pop	{tp}
+	add	tp, tp, #12
+	subs	j, j, #3
+	bpl	L(outer_top)
+L(outer_end):
+
+	cmp	j, #-1
+	bne	L(n2)
+
+	ldr	c, [sp, #36]
+	mov	i, nents
+	mov	r8, #0
+	mov	r9, #0
+L(tp2):	subs	c, c, #1
+	sbc	mask, mask, mask
+	ldm	tp, {r4,r5}
+	subs	i, i, #1
+	add	tp, tp, n, lsl #2
+	and	r4, r4, mask
+	and	r5, r5, mask
+	orr	r8, r8, r4
+	orr	r9, r9, r5
+	bge	L(tp2)
+	stmia	rp, {r8,r9}
+	pop	{r4-r11, r14}
+	return	lr
+
+L(n2):	cmp	j, #-2
+	bne	L(n1)
+
+	ldr	c, [sp, #36]
+	mov	i, nents
+	mov	r8, #0
+L(tp1):	subs	c, c, #1
+	sbc	mask, mask, mask
+	ldr	r4, [tp]
+	subs	i, i, #1
+	add	tp, tp, n, lsl #2
+	and	r4, r4, mask
+	orr	r8, r8, r4
+	bge	L(tp1)
+	str	r8, [rp]
+L(n1):	pop	{r4-r11, r14}
+	return	lr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/udiv.asm b/third_party/gmp/mpn/arm/udiv.asm
new file mode 100644
index 0000000..7c04789
--- /dev/null
+++ b/third_party/gmp/mpn/arm/udiv.asm
@@ -0,0 +1,104 @@
+dnl  ARM mpn_udiv_qrnnd -- divide a two limb dividend and a one limb divisor.
+dnl  Return quotient and store remainder through a supplied pointer.
+
+dnl  Copyright 2001, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+define(`rem_ptr',`r0')
+define(`n1',`r1')
+define(`n0',`r2')
+define(`d',`r3')
+
+C divstep -- develop one quotient bit.  Dividend in $1$2, divisor in $3.
+C Quotient bit is shifted into $2.
+define(`divstep',
+       `adcs	$2, $2, $2
+	adc	$1, $1, $1
+	cmp	$1, $3
+	subcs	$1, $1, $3')
+
+ASM_START()
+PROLOGUE(mpn_udiv_qrnnd)
+	mov	r12, #8			C loop counter for both loops below
+	cmp	d, #0x80000000		C check divisor msb and clear carry
+	bcs	L(_large_divisor)
+
+L(oop):	divstep(n1,n0,d)
+	divstep(n1,n0,d)
+	divstep(n1,n0,d)
+	divstep(n1,n0,d)
+	sub	r12, r12, #1
+	teq	r12, #0
+	bne	L(oop)
+
+	str	n1, [rem_ptr]		C store remainder
+	adc	r0, n0, n0		C quotient: add last carry from divstep
+	return	lr
+
+L(_large_divisor):
+	stmfd	sp!, { r8, lr }
+
+	and	r8, n0, #1		C save lsb of dividend
+	mov	lr, n1, lsl #31
+	orrs	n0, lr, n0, lsr #1	C n0 = lo(n1n0 >> 1)
+	mov	n1, n1, lsr #1		C n1 = hi(n1n0 >> 1)
+
+	and	lr, d, #1		C save lsb of divisor
+	movs	d, d, lsr #1		C d = floor(orig_d / 2)
+	adc	d, d, #0		C d = ceil(orig_d / 2)
+
+L(oop2):
+	divstep(n1,n0,d)
+	divstep(n1,n0,d)
+	divstep(n1,n0,d)
+	divstep(n1,n0,d)
+	sub	r12, r12, #1
+	teq	r12, #0
+	bne	L(oop2)
+
+	adc	n0, n0, n0		C shift and add last carry from divstep
+	add	n1, r8, n1, lsl #1	C shift in omitted dividend lsb
+	tst	lr, lr			C test saved divisor lsb
+	beq	L(_even_divisor)
+
+	rsb	d, lr, d, lsl #1	C restore orig d value
+	adds	n1, n1, n0		C fix remainder for omitted divisor lsb
+	addcs	n0, n0, #1		C adjust quotient if rem. fix carried
+	subcs	n1, n1, d		C adjust remainder accordingly
+	cmp	n1, d			C remainder >= divisor?
+	subcs	n1, n1, d		C adjust remainder
+	addcs	n0, n0, #1		C adjust quotient
+
+L(_even_divisor):
+	str	n1, [rem_ptr]		C store remainder
+	mov	r0, n0			C quotient
+	ldmfd	sp!, { r8, pc }
+EPILOGUE(mpn_udiv_qrnnd)
diff --git a/third_party/gmp/mpn/arm/v5/gcd_11.asm b/third_party/gmp/mpn/arm/v5/gcd_11.asm
new file mode 100644
index 0000000..3c2b48f
--- /dev/null
+++ b/third_party/gmp/mpn/arm/v5/gcd_11.asm
@@ -0,0 +1,70 @@
+dnl  ARM v5 mpn_gcd_11.
+
+dnl  Based on the K7 gcd_1.asm, by Kevin Ryde.  Rehacked for ARM by Torbjörn
+dnl  Granlund.
+
+dnl  Copyright 2000-2002, 2005, 2009, 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/bit (approx)
+C StrongARM	 -
+C XScale	 ?
+C Cortex-A5	 6.45	obsolete
+C Cortex-A7	 6.41	obsolete
+C Cortex-A8	 5.0	obsolete
+C Cortex-A9	 5.9	obsolete
+C Cortex-A15	 4.40	obsolete
+C Cortex-A17	 5.68	obsolete
+C Cortex-A53	 4.37	obsolete
+C Numbers measured with: speed -CD -s8-32 -t24 mpn_gcd_1
+
+define(`u0',    `r0')
+define(`v0',    `r1')
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_gcd_11)
+	subs	r3, u0, v0	C			0
+	beq	L(end)		C
+
+	ALIGN(16)
+L(top):	sub	r2, v0, u0	C			0,5
+	and	r12, r2, r3	C			1
+	clz	r12, r12	C			2
+	rsb	r12, r12, #31	C			3
+	rsbcc	r3, r3, #0	C v = abs(u-v), even	1
+	movcs	u0, v0		C u = min(u,v)		1
+	lsr	v0, r3, r12	C			4
+	subs	r3, u0, v0	C			5
+	bne	L(top)		C
+
+L(end):	bx	lr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/v5/mod_1_1.asm b/third_party/gmp/mpn/arm/v5/mod_1_1.asm
new file mode 100644
index 0000000..3cf0cd7
--- /dev/null
+++ b/third_party/gmp/mpn/arm/v5/mod_1_1.asm
@@ -0,0 +1,129 @@
+dnl  ARM mpn_mod_1_1p
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C StrongARM	 -
+C XScale	 ?
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 7
+C Cortex-A15	 6
+
+define(`ap', `r0')
+define(`n',  `r1')
+define(`d',  `r2')
+define(`cps',`r3')
+
+ASM_START()
+PROLOGUE(mpn_mod_1_1p)
+	push	{r4-r10}
+	add	r0, r0, r1, asl #2
+	ldr	r5, [r0, #-4]!
+	ldr	r12, [r0, #-4]!
+	subs	r1, r1, #2
+	ble	L(4)
+	ldr	r8, [r3, #12]
+	mov	r4, r12
+	mov	r10, r5
+	umull	r7, r5, r10, r8
+	sub	r1, r1, #1
+	b	L(mid)
+
+L(top):	adds	r12, r6, r7
+	adcs	r10, r4, r5
+	sub	r1, r1, #1
+	mov	r6, #0
+	movcs	r6, r8
+	umull	r7, r5, r10, r8
+	adds	r4, r12, r6
+	subcs	r4, r4, r2
+L(mid):	ldr	r6, [r0, #-4]!
+	teq	r1, #0
+	bne	L(top)
+
+	adds	r12, r6, r7
+	adcs	r5, r4, r5
+	subcs	r5, r5, r2
+L(4):	ldr	r1, [r3, #4]
+	cmp	r1, #0
+	beq	L(7)
+	ldr	r4, [r3, #8]
+	umull	r0, r6, r5, r4
+	adds	r12, r0, r12
+	addcs	r6, r6, #1
+	rsb	r0, r1, #32
+	mov	r0, r12, lsr r0
+	orr	r5, r0, r6, asl r1
+	mov	r12, r12, asl r1
+	b	L(8)
+L(7):	cmp	r5, r2
+	subcs	r5, r5, r2
+L(8):	ldr	r0, [r3, #0]
+	umull	r4, r3, r5, r0
+	add	r5, r5, #1
+	adds	r0, r4, r12
+	adc	r5, r3, r5
+	mul	r5, r2, r5
+	sub	r12, r12, r5
+	cmp	r12, r0
+	addhi	r12, r12, r2
+	cmp	r2, r12
+	subls	r12, r12, r2
+	mov	r0, r12, lsr r1
+	pop	{r4-r10}
+	bx	r14
+EPILOGUE()
+
+PROLOGUE(mpn_mod_1_1p_cps)
+	stmfd	sp!, {r4, r5, r6, r14}
+	mov	r5, r0
+	clz	r4, r1
+	mov	r0, r1, asl r4
+	rsb	r6, r0, #0
+	bl	mpn_invert_limb
+	str	r0, [r5, #0]
+	str	r4, [r5, #4]
+	cmp	r4, #0
+	beq	L(2)
+	rsb	r1, r4, #32
+	mov	r3, #1
+	mov	r3, r3, asl r4
+	orr	r3, r3, r0, lsr r1
+	mul	r3, r6, r3
+	mov	r4, r3, lsr r4
+	str	r4, [r5, #8]
+L(2):	mul	r0, r6, r0
+	str	r0, [r5, #12]
+	ldmfd	sp!, {r4, r5, r6, pc}
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/v5/mod_1_2.asm b/third_party/gmp/mpn/arm/v5/mod_1_2.asm
new file mode 100644
index 0000000..aa26ecb
--- /dev/null
+++ b/third_party/gmp/mpn/arm/v5/mod_1_2.asm
@@ -0,0 +1,156 @@
+dnl  ARM mpn_mod_1s_2p
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C StrongARM	 -
+C XScale	 ?
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 4.25
+C Cortex-A15	 3
+
+define(`ap', `r0')
+define(`n',  `r1')
+define(`d',  `r2')
+define(`cps',`r3')
+
+ASM_START()
+PROLOGUE(mpn_mod_1s_2p)
+	push	{r4-r10}
+	tst	n, #1
+	add	r7, r3, #8
+	ldmia	r7, {r7, r8, r12}	C load B1, B2, B3
+	add	ap, ap, n, lsl #2	C put ap at operand end
+	beq	L(evn)
+
+L(odd):	subs	n, n, #1
+	beq	L(1)
+	ldmdb	ap!, {r4,r6,r9}
+	mov	r10, #0
+	umlal	r4, r10, r6, r7
+	umlal	r4, r10, r9, r8
+	b	L(com)
+
+L(evn):	ldmdb	ap!, {r4,r10}
+L(com):	subs	n, n, #2
+	ble	L(end)
+	ldmdb	ap!, {r5,r6}
+	b	L(mid)
+
+L(top):	mov	r9, #0
+	umlal	r5, r9, r6, r7		C B1
+	umlal	r5, r9, r4, r8		C B2
+	ldmdb	ap!, {r4,r6}
+	umlal	r5, r9, r10, r12	C B3
+	ble	L(xit)
+	mov	r10, #0
+	umlal	r4, r10, r6, r7		C B1
+	umlal	r4, r10, r5, r8		C B2
+	ldmdb	ap!, {r5,r6}
+	umlal	r4, r10, r9, r12	C B3
+L(mid):	subs	n, n, #4
+	bge	L(top)
+
+	mov	r9, #0
+	umlal	r5, r9, r6, r7		C B1
+	umlal	r5, r9, r4, r8		C B2
+	umlal	r5, r9, r10, r12	C B3
+	mov	r4, r5
+
+L(end):	movge	   r9, r10		C executed iff coming via xit
+	ldr	r6, [r3, #4]		C cps[1] = cnt
+	mov	r5, #0
+	umlal	r4, r5, r9, r7
+	mov	r7, r5, lsl r6
+L(x):	rsb	r1, r6, #32
+	orr	r8, r7, r4, lsr r1
+	mov	r9, r4, lsl r6
+	ldr	r5, [r3, #0]
+	add	r0, r8, #1
+	umull	r12, r1, r8, r5
+	adds	r4, r12, r9
+	adc	r1, r1, r0
+	mul	r5, r2, r1
+	sub	r9, r9, r5
+	cmp	r9, r4
+	addhi	r9, r9, r2
+	cmp	r2, r9
+	subls	r9, r9, r2
+	mov	r0, r9, lsr r6
+	pop	{r4-r10}
+	bx	r14
+
+L(xit):	mov	r10, #0
+	umlal	r4, r10, r6, r7		C B1
+	umlal	r4, r10, r5, r8		C B2
+	umlal	r4, r10, r9, r12	C B3
+	b	L(end)
+
+L(1):	ldr	r6, [r3, #4]		C cps[1] = cnt
+	ldr	r4, [ap, #-4]		C ap[0]
+	mov	r7, #0
+	b	L(x)
+EPILOGUE()
+
+PROLOGUE(mpn_mod_1s_2p_cps)
+	push	{r4-r8, r14}
+	clz	r4, r1
+	mov	r5, r1, lsl r4		C b <<= cnt
+	mov	r6, r0			C r6 = cps
+	mov	r0, r5
+	bl	mpn_invert_limb
+	rsb	r3, r4, #32
+	mov	r3, r0, lsr r3
+	mov	r2, #1
+	orr	r3, r3, r2, lsl r4
+	rsb	r1, r5, #0
+	mul	r2, r1, r3
+	umull	r3, r12, r2, r0
+	add	r12, r2, r12
+	mvn	r12, r12
+	mul	r1, r5, r12
+	cmp	r1, r3
+	addhi	r1, r1, r5
+	umull	r12, r7, r1, r0
+	add	r7, r1, r7
+	mvn	r7, r7
+	mul	r3, r5, r7
+	cmp	r3, r12
+	addhi	r3, r3, r5
+	mov	r5, r2, lsr r4
+	mov	r7, r1, lsr r4
+	mov	r8, r3, lsr r4
+	stmia	r6, {r0,r4,r5,r7,r8}	C fill cps
+	pop	{r4-r8, pc}
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/v6/addmul_1.asm b/third_party/gmp/mpn/arm/v6/addmul_1.asm
new file mode 100644
index 0000000..a38af58
--- /dev/null
+++ b/third_party/gmp/mpn/arm/v6/addmul_1.asm
@@ -0,0 +1,112 @@
+dnl  ARM mpn_addmul_1.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C StrongARM:	 -
+C XScale	 -
+C ARM11		 6.4
+C Cortex-A7	 5.25
+C Cortex-A8	 7
+C Cortex-A9	 3.25
+C Cortex-A15	 4
+
+C TODO
+C  * Micro-optimise feed-in code.
+C  * Optimise for n=1,2 by delaying register saving.
+C  * Try using ldm/stm.
+
+define(`rp',`r0')
+define(`up',`r1')
+define(`n', `r2')
+define(`v0',`r3')
+
+ASM_START()
+PROLOGUE(mpn_addmul_1)
+	stmfd	sp!, { r4, r5, r6, r7 }
+
+	ands	r6, n, #3
+	mov	r12, #0
+	beq	L(fi0)
+	cmp	r6, #2
+	bcc	L(fi1)
+	beq	L(fi2)
+
+L(fi3):	ldr	r4, [up], #4
+	ldr	r6, [rp, #0]
+	ldr	r5, [up], #4
+	b	L(lo3)
+
+L(fi0):	ldr	r5, [up], #4
+	ldr	r7, [rp], #4
+	ldr	r4, [up], #4
+	b	L(lo0)
+
+L(fi1):	ldr	r4, [up], #4
+	ldr	r6, [rp], #8
+	subs	n, n, #1
+	beq	L(1)
+	ldr	r5, [up], #4
+	b	L(lo1)
+
+L(fi2):	ldr	r5, [up], #4
+	ldr	r7, [rp], #12
+	ldr	r4, [up], #4
+	b	L(lo2)
+
+	ALIGN(16)
+L(top):	ldr	r6, [rp, #-8]
+	ldr	r5, [up], #4
+	str	r7, [rp, #-12]
+L(lo1):	umaal	r6, r12, r4, v0
+	ldr	r7, [rp, #-4]
+	ldr	r4, [up], #4
+	str	r6, [rp, #-8]
+L(lo0):	umaal	r7, r12, r5, v0
+	ldr	r6, [rp, #0]
+	ldr	r5, [up], #4
+	str	r7, [rp, #-4]
+L(lo3):	umaal	r6, r12, r4, v0
+	ldr	r7, [rp, #4]
+	ldr	r4, [up], #4
+	str	r6, [rp], #16
+L(lo2):	umaal	r7, r12, r5, v0
+	subs	n, n, #4
+	bhi	L(top)
+
+	ldr	r6, [rp, #-8]
+	str	r7, [rp, #-12]
+L(1):	umaal	r6, r12, r4, v0
+	str	r6, [rp, #-8]
+	mov	r0, r12
+	ldmfd	sp!, { r4, r5, r6, r7 }
+	bx	lr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/v6/addmul_2.asm b/third_party/gmp/mpn/arm/v6/addmul_2.asm
new file mode 100644
index 0000000..69d0b8f
--- /dev/null
+++ b/third_party/gmp/mpn/arm/v6/addmul_2.asm
@@ -0,0 +1,125 @@
+dnl  ARM mpn_addmul_2.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2012, 2013, 2015 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C StrongARM:	 -
+C XScale	 -
+C ARM11		 4.68
+C Cortex-A5	 3.63
+C Cortex-A7	 3.65
+C Cortex-A8	 4.0
+C Cortex-A9	 2.25
+C Cortex-A15	 2.5
+C Cortex-A17	 2.13
+C Cortex-A53	 3.5
+
+define(`rp',`r0')
+define(`up',`r1')
+define(`n', `r2')
+define(`vp',`r3')
+
+define(`v0',`r6')
+define(`v1',`r7')
+define(`u0',`r3')
+define(`u1',`r9')
+
+define(`cya',`r8')
+define(`cyb',`r12')
+
+
+ASM_START()
+PROLOGUE(mpn_addmul_2)
+	push	{ r4-r9 }
+
+	ldrd	v0, v1, [vp, #0]
+	mov	cya, #0
+	mov	cyb, #0
+
+	tst	n, #1
+	beq	L(evn)
+
+L(odd):	ldr	u1, [up, #0]
+	ldr	r4, [rp, #0]
+	tst	n, #2
+	beq	L(fi1)
+L(fi3):	sub	up, up, #8
+	sub	rp, rp, #8
+	b	L(lo3)
+L(fi1):	sub	n, n, #1
+	b	L(top)
+
+L(evn):	ldr	u0, [up, #0]
+	ldr	r5, [rp, #0]
+	tst	n, #2
+	bne	L(fi2)
+L(fi0):	sub	up, up, #4
+	sub	rp, rp, #4
+	b	L(lo0)
+L(fi2):	sub	up, up, #12
+	sub	rp, rp, #12
+	b	L(lo2)
+
+	ALIGN(16)
+L(top):	ldr	r5, [rp, #4]
+	umaal	r4, cya, u1, v0
+	ldr	u0, [up, #4]
+	umaal	r5, cyb, u1, v1
+	str	r4, [rp, #0]
+L(lo0):	ldr	r4, [rp, #8]
+	umaal	r5, cya, u0, v0
+	ldr	u1, [up, #8]
+	umaal	r4, cyb, u0, v1
+	str	r5, [rp, #4]
+L(lo3):	ldr	r5, [rp, #12]
+	umaal	r4, cya, u1, v0
+	ldr	u0, [up, #12]
+	umaal	r5, cyb, u1, v1
+	str	r4, [rp, #8]
+L(lo2):	ldr	r4, [rp, #16]!
+	umaal	r5, cya, u0, v0
+	ldr	u1, [up, #16]!
+	umaal	r4, cyb, u0, v1
+	str	r5, [rp, #-4]
+	subs	n, n, #4
+	bhi	L(top)
+
+L(end):	umaal	r4, cya, u1, v0
+	umaal	cya, cyb, u1, v1
+	str	r4, [rp, #0]
+	str	cya, [rp, #4]
+	mov	r0, cyb
+
+	pop	{ r4-r9 }
+	bx	r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/v6/addmul_3.asm b/third_party/gmp/mpn/arm/v6/addmul_3.asm
new file mode 100644
index 0000000..d1490cd
--- /dev/null
+++ b/third_party/gmp/mpn/arm/v6/addmul_3.asm
@@ -0,0 +1,191 @@
+dnl  ARM mpn_addmul_3.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C StrongARM:	 -
+C XScale	 -
+C ARM11		 4.33
+C Cortex-A5	 3.28
+C Cortex-A7	 3.25
+C Cortex-A8	 3.17
+C Cortex-A9	 2.125
+C Cortex-A15	 2
+C Cortex-A17	 2.11
+C Cortex-A53	 4.18
+
+C TODO
+C  * Use a fast path for n <= KARATSUBA_MUL_THRESHOLD using a jump table,
+C    avoiding the current multiply.
+C  * Start the first multiply or multiplies early.
+
+define(`rp',`r0')
+define(`up',`r1')
+define(`n', `r2')
+define(`vp',`r3')
+
+define(`v0',`r4')  define(`v1',`r5')  define(`v2',`r6')
+define(`u0',`r3')  define(`u1',`r14')
+define(`w0',`r7')  define(`w1',`r8')  define(`w2',`r9')
+define(`cy0',`r10')  define(`cy1',`r11') define(`cy2',`r12')
+
+
+ASM_START()
+PROLOGUE(mpn_addmul_3)
+	push	{ r4-r11, r14 }
+
+	ldr	w0, =0xaaaaaaab		C 3^{-1} mod 2^32
+	ldm	vp, { v0,v1,v2 }
+	mov	cy0, #0
+	mov	cy1, #0
+	mov	cy2, #0
+
+C Tricky n mod 6
+	mul	w0, w0, n		C n * 3^{-1} mod 2^32
+	and	w0, w0, #0xc0000001	C pseudo-CRT mod 3,2
+	sub	n, n, #3
+ifdef(`PIC',`
+	add	pc, pc, w0, ror $28
+	nop
+	b	L(b0)
+	b	L(b2)
+	b	L(b4)
+	.word	0xe7f000f0	C udf
+	b	L(b3)
+	b	L(b5)
+	b	L(b1)
+',`
+	ldr	pc, [pc, w0, ror $28]
+	nop
+	.word	L(b0), L(b2), L(b4), 0, L(b3), L(b5), L(b1)
+')
+
+L(b5):	add	up, up, #-8
+	ldr	w1, [rp, #0]
+	ldr	w2, [rp, #4]
+	ldr	u1, [up, #8]
+	b	L(lo5)
+
+L(b4):	add	rp, rp, #-4
+	add	up, up, #-12
+	ldr	w2, [rp, #4]
+	ldr	w0, [rp, #8]
+	ldr	u0, [up, #12]
+	b	L(lo4)
+
+L(b3):	add	rp, rp, #-8
+	add	up, up, #-16
+	ldr	w0, [rp, #8]
+	ldr	w1, [rp, #12]
+	ldr	u1, [up, #16]
+	b	L(lo3)
+
+L(b1):	add	rp, rp, #8
+	ldr	w2, [rp, #-8]
+	ldr	w0, [rp, #-4]
+	ldr	u1, [up, #0]
+	b	L(lo1)
+
+L(b0):	add	rp, rp, #4
+	add	up, up, #-4
+	ldr	w0, [rp, #-4]
+	ldr	w1, [rp, #0]
+	ldr	u0, [up, #4]
+	b	L(lo0)
+
+L(b2):	add	rp, rp, #12
+	add	up, up, #4
+	ldr	w1, [rp, #-12]
+	ldr	w2, [rp, #-8]
+	ldr	u0, [up, #-4]
+
+	ALIGN(16)
+L(top):	ldr	w0, [rp, #-4]
+	umaal	w1, cy0, u0, v0
+	ldr	u1, [up, #0]
+	umaal	w2, cy1, u0, v1
+	str	w1, [rp, #-12]
+	umaal	w0, cy2, u0, v2
+L(lo1):	ldr	w1, [rp, #0]
+	umaal	w2, cy0, u1, v0
+	ldr	u0, [up, #4]
+	umaal	w0, cy1, u1, v1
+	str	w2, [rp, #-8]
+	umaal	w1, cy2, u1, v2
+L(lo0):	ldr	w2, [rp, #4]
+	umaal	w0, cy0, u0, v0
+	ldr	u1, [up, #8]
+	umaal	w1, cy1, u0, v1
+	str	w0, [rp, #-4]
+	umaal	w2, cy2, u0, v2
+L(lo5):	ldr	w0, [rp, #8]
+	umaal	w1, cy0, u1, v0
+	ldr	u0, [up, #12]
+	umaal	w2, cy1, u1, v1
+	str	w1, [rp, #0]
+	umaal	w0, cy2, u1, v2
+L(lo4):	ldr	w1, [rp, #12]
+	umaal	w2, cy0, u0, v0
+	ldr	u1, [up, #16]
+	umaal	w0, cy1, u0, v1
+	str	w2, [rp, #4]
+	umaal	w1, cy2, u0, v2
+L(lo3):	ldr	w2, [rp, #16]
+	umaal	w0, cy0, u1, v0
+	ldr	u0, [up, #20]
+	umaal	w1, cy1, u1, v1
+	str	w0, [rp, #8]
+	umaal	w2, cy2, u1, v2
+L(lo2):	subs	n, n, #6
+	add	up, up, #24
+	add	rp, rp, #24
+	bge	L(top)
+
+L(end):	umaal	w1, cy0, u0, v0
+	ldr	u1, [up, #0]
+	umaal	w2, cy1, u0, v1
+	str	w1, [rp, #-12]
+	mov	w0, #0
+	umaal	w0, cy2, u0, v2
+	umaal	w2, cy0, u1, v0
+	umaal	w0, cy1, u1, v1
+	str	w2, [rp, #-8]
+	umaal	cy1, cy2, u1, v2
+	adds	w0, w0, cy0
+	str	w0, [rp, #-4]
+	adcs	w1, cy1, #0
+	str	w1, [rp, #0]
+	adc	r0, cy2, #0
+
+	pop	{ r4-r11, pc }
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/v6/dive_1.asm b/third_party/gmp/mpn/arm/v6/dive_1.asm
new file mode 100644
index 0000000..92de814
--- /dev/null
+++ b/third_party/gmp/mpn/arm/v6/dive_1.asm
@@ -0,0 +1,149 @@
+dnl  ARM v6 mpn_divexact_1
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2012, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C               cycles/limb       cycles/limb
+C               norm    unorm    modexact_1c_odd
+C StrongARM	 -	 -
+C XScale	 -	 -
+C Cortex-A7	 ?	 ?
+C Cortex-A8	 ?	 ?
+C Cortex-A9	 9	10		 9
+C Cortex-A15	 7	 7		 7
+
+C Architecture requirements:
+C v5	-
+C v5t	clz
+C v5te	-
+C v6	umaal
+C v6t2	-
+C v7a	-
+
+define(`rp', `r0')
+define(`up', `r1')
+define(`n',  `r2')
+define(`d',  `r3')
+
+define(`cy',  `r7')
+define(`cnt', `r6')
+define(`tnc', `r10')
+
+ASM_START()
+PROLOGUE(mpn_divexact_1)
+	push	{r4,r5,r6,r7,r8,r9}
+
+	tst	d, #1
+
+	rsb	r4, d, #0
+	and	r4, r4, d
+	clz	r4, r4
+	rsb	cnt, r4, #31		C count_trailing_zeros
+	mov	d, d, lsr cnt
+
+C binvert limb
+	LEA(	r4, binvert_limb_table)
+	and	r12, d, #254
+	ldrb	r4, [r4, r12, lsr #1]
+	mul	r12, r4, r4
+	mul	r12, d, r12
+	rsb	r12, r12, r4, lsl #1
+	mul	r4, r12, r12
+	mul	r4, d, r4
+	rsb	r4, r4, r12, lsl #1	C r4 = inverse
+
+	ldr	r5, [up], #4		C up[0]
+	mov	cy, #0
+	rsb	r8, r4, #0		C r8 = -inverse
+	beq	L(unnorm)
+
+L(norm):
+	subs	n, n, #1
+	mul	r5, r5, r4
+	beq	L(end)
+
+	ALIGN(16)
+L(top):	ldr	r9, [up], #4
+	mov	r12, #0
+	str	r5, [rp], #4
+	umaal	r12, cy, r5, d
+	mul	r5, r9, r4
+	mla	r5, cy, r8, r5
+	subs	n, n, #1
+	bne	L(top)
+
+L(end):	str	r5, [rp]
+	pop	{r4,r5,r6,r7,r8,r9}
+	bx	r14
+
+L(unnorm):
+	push	{r10,r11}
+	rsb	tnc, cnt, #32
+	mov	r11, r5, lsr cnt
+	subs	n, n, #1
+	beq	L(edx)
+
+	ldr	r12, [up], #4
+	orr	r9, r11, r12, lsl tnc
+	mov	r11, r12, lsr cnt
+	mul	r5, r9, r4
+	subs	n, n, #1
+	beq	L(edu)
+
+	ALIGN(16)
+L(tpu):	ldr	r12, [up], #4
+	orr	r9, r11, r12, lsl tnc
+	mov	r11, r12, lsr cnt
+	mov	r12, #0
+	str	r5, [rp], #4
+	umaal	r12, cy, r5, d
+	mul	r5, r9, r4
+	mla	r5, cy, r8, r5
+	subs	n, n, #1
+	bne	L(tpu)
+
+L(edu):	str	r5, [rp], #4
+	mov	r12, #0
+	umaal	r12, cy, r5, d
+	mul	r5, r11, r4
+	mla	r5, cy, r8, r5
+	str	r5, [rp]
+	pop	{r10,r11}
+	pop	{r4,r5,r6,r7,r8,r9}
+	bx	r14
+
+L(edx):	mul	r5, r11, r4
+	str	r5, [rp]
+	pop	{r10,r11}
+	pop	{r4,r5,r6,r7,r8,r9}
+	bx	r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/v6/gmp-mparam.h b/third_party/gmp/mpn/arm/v6/gmp-mparam.h
new file mode 100644
index 0000000..35a7c55
--- /dev/null
+++ b/third_party/gmp/mpn/arm/v6/gmp-mparam.h
@@ -0,0 +1,187 @@
+/* gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+/* 700 MHz ARM11 (raspberry pi) */
+/* FFT tuning limit = 8,088,775 */
+/* Generated by tuneup.c, 2019-10-23, gcc 8.3 */
+
+#define DIVREM_1_NORM_THRESHOLD              0  /* preinv always */
+#define DIVREM_1_UNNORM_THRESHOLD            0  /* always */
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          7
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          6
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD         0  /* never mpn_mod_1_1p */
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD     MP_SIZE_T_MAX
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     19
+#define USE_PREINV_DIVREM_1                  1  /* preinv always */
+#define DIV_QR_1N_PI1_METHOD                 1  /* 71.61% faster than 2 */
+#define DIV_QR_1_NORM_THRESHOLD          MP_SIZE_T_MAX  /* never */
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           38
+
+#define DIV_1_VS_MUL_1_PERCENT             251
+
+#define MUL_TOOM22_THRESHOLD                38
+#define MUL_TOOM33_THRESHOLD               134
+#define MUL_TOOM44_THRESHOLD               512
+#define MUL_TOOM6H_THRESHOLD                 0  /* always */
+#define MUL_TOOM8H_THRESHOLD               620
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD     209
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     625
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     209
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     211
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     300
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 55
+#define SQR_TOOM3_THRESHOLD                200
+#define SQR_TOOM4_THRESHOLD                470
+#define SQR_TOOM6_THRESHOLD                614
+#define SQR_TOOM8_THRESHOLD                882
+
+#define MULMID_TOOM42_THRESHOLD             62
+
+#define MULMOD_BNM1_THRESHOLD               23
+#define SQRMOD_BNM1_THRESHOLD               26
+
+#define MUL_FFT_MODF_THRESHOLD             565  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    565, 5}, {     25, 6}, {     13, 5}, {     27, 6}, \
+    {     15, 5}, {     31, 6}, {     28, 7}, {     15, 6}, \
+    {     33, 7}, {     17, 6}, {     35, 7}, {     19, 6}, \
+    {     39, 7}, {     21, 6}, {     43, 7}, {     23, 6}, \
+    {     47, 7}, {     27, 8}, {     15, 7}, {     35, 8}, \
+    {     19, 7}, {     43, 8}, {     23, 7}, {     51, 8}, \
+    {     27, 7}, {     55, 8}, {     31, 7}, {     63, 8}, \
+    {     43, 9}, {     23, 8}, {     55, 9}, {     31, 8}, \
+    {     71, 9}, {     39, 8}, {     83, 9}, {     47, 8}, \
+    {     99, 9}, {     55,10}, {     31, 9}, {     79,10}, \
+    {     47, 9}, {    103,11}, {     31,10}, {     63, 9}, \
+    {    135,10}, {     79, 9}, {    159,10}, {     95, 9}, \
+    {    191,10}, {    111,11}, {     63,10}, {    159,11}, \
+    {     95,10}, {    207,12}, {     63,11}, {    127,10}, \
+    {    255, 9}, {    511,10}, {    271,11}, {    159,10}, \
+    {    351,11}, {    191,10}, {    399,11}, {    223,12}, \
+    {    127,11}, {    255,10}, {    511,11}, {    287,10}, \
+    {    607,11}, {    319,10}, {    639,11}, {    351,12}, \
+    {    191,11}, {    415,13}, {    127,12}, {    255,11}, \
+    {    575,12}, {    319,11}, {    671,12}, {    383,11}, \
+    {    799,12}, {    447,13}, {    255,12}, {    511,11}, \
+    {   1023,12}, {    703,13}, {    383,12}, {    895,14}, \
+    {    255,13}, {    511,12}, {   1151,13}, {    639,12}, \
+    {   1343,13}, {    767,12}, {   1599,13}, {    895,14}, \
+    {  16384,15}, {  32768,16} }
+#define MUL_FFT_TABLE3_SIZE 98
+#define MUL_FFT_THRESHOLD                 5760
+
+#define SQR_FFT_MODF_THRESHOLD             530  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    530, 5}, {     25, 6}, {     13, 5}, {     27, 6}, \
+    {     28, 7}, {     15, 6}, {     33, 7}, {     17, 6}, \
+    {     35, 7}, {     19, 6}, {     39, 7}, {     21, 6}, \
+    {     43, 7}, {     23, 6}, {     47, 7}, {     29, 8}, \
+    {     15, 7}, {     35, 8}, {     19, 7}, {     43, 8}, \
+    {     23, 7}, {     49, 8}, {     27, 7}, {     55, 8}, \
+    {     31, 7}, {     63, 8}, {     43, 9}, {     23, 8}, \
+    {     55, 9}, {     31, 8}, {     71, 9}, {     39, 8}, \
+    {     83, 9}, {     47, 8}, {     95, 9}, {     55,10}, \
+    {     31, 9}, {     79,10}, {     47, 9}, {    103,11}, \
+    {     31,10}, {     63, 9}, {    135,10}, {     79, 9}, \
+    {    167,10}, {     95, 9}, {    191,10}, {    111,11}, \
+    {     63,10}, {    143, 9}, {    287,10}, {    159,11}, \
+    {     95,10}, {    191, 9}, {    383,12}, {     63,11}, \
+    {    127,10}, {    255, 9}, {    511,10}, {    271, 9}, \
+    {    543,10}, {    287,11}, {    159,10}, {    351,11}, \
+    {    191,10}, {    415,11}, {    223,12}, {    127,11}, \
+    {    255,10}, {    543,11}, {    287,10}, {    607,11}, \
+    {    319,10}, {    639,11}, {    351,12}, {    191,11}, \
+    {    383,10}, {    767,11}, {    415,13}, {    127,12}, \
+    {    255,11}, {    607,12}, {    319,11}, {    703,12}, \
+    {    383,11}, {    799,12}, {    447,11}, {    895,13}, \
+    {    255,12}, {    511,11}, {   1023,12}, {    703,13}, \
+    {    383,12}, {    895,14}, {    255,13}, {    511,12}, \
+    {   1151,13}, {    639,12}, {   1343,13}, {    767,12}, \
+    {   1599,13}, {    895,14}, {  16384,15}, {  32768,16} }
+#define SQR_FFT_TABLE3_SIZE 104
+#define SQR_FFT_THRESHOLD                 4416
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  51
+#define MULLO_MUL_N_THRESHOLD            11278
+#define SQRLO_BASECASE_THRESHOLD            10
+#define SQRLO_DC_THRESHOLD                  55
+#define SQRLO_SQR_THRESHOLD               8648
+
+#define DC_DIV_QR_THRESHOLD                 36
+#define DC_DIVAPPR_Q_THRESHOLD             146
+#define DC_BDIV_QR_THRESHOLD                46
+#define DC_BDIV_Q_THRESHOLD                160
+
+#define INV_MULMOD_BNM1_THRESHOLD           74
+#define INV_NEWTON_THRESHOLD               145
+#define INV_APPR_THRESHOLD                 147
+
+#define BINV_NEWTON_THRESHOLD              372
+#define REDC_1_TO_REDC_2_THRESHOLD           6
+#define REDC_2_TO_REDC_N_THRESHOLD         140
+
+#define MU_DIV_QR_THRESHOLD               2801
+#define MU_DIVAPPR_Q_THRESHOLD            2801
+#define MUPI_DIV_QR_THRESHOLD               79
+#define MU_BDIV_QR_THRESHOLD              2541
+#define MU_BDIV_Q_THRESHOLD               2764
+
+#define POWM_SEC_TABLE  3,20,139,734
+
+#define GET_STR_DC_THRESHOLD                27
+#define GET_STR_PRECOMPUTE_THRESHOLD        45
+#define SET_STR_DC_THRESHOLD               342
+#define SET_STR_PRECOMPUTE_THRESHOLD      1290
+
+#define FAC_DSC_THRESHOLD                  390
+#define FAC_ODD_THRESHOLD                  438
+
+#define MATRIX22_STRASSEN_THRESHOLD         25
+#define HGCD2_DIV1_METHOD                    5  /* 1.32% faster than 3 */
+#define HGCD_THRESHOLD                      82
+#define HGCD_APPR_THRESHOLD                 81
+#define HGCD_REDUCE_THRESHOLD             4633
+#define GCD_DC_THRESHOLD                   345
+#define GCDEXT_DC_THRESHOLD                268
+#define JACOBI_BASE_METHOD                   1  /* 3.30% faster than 2 */
+
+/* Tuneup completed successfully, took 45018 seconds */
diff --git a/third_party/gmp/mpn/arm/v6/mode1o.asm b/third_party/gmp/mpn/arm/v6/mode1o.asm
new file mode 100644
index 0000000..a2f77a6
--- /dev/null
+++ b/third_party/gmp/mpn/arm/v6/mode1o.asm
@@ -0,0 +1,95 @@
+dnl  ARM v6 mpn_modexact_1c_odd
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C StrongARM	 -
+C XScale	 -
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 9
+C Cortex-A15	 7
+
+C Architecture requirements:
+C v5	-
+C v5t	-
+C v5te	smulbb
+C v6	umaal
+C v6t2	-
+C v7a	-
+
+define(`up', `r0')
+define(`n',  `r1')
+define(`d',  `r2')
+define(`cy', `r3')
+
+	.protected	binvert_limb_table
+ASM_START()
+PROLOGUE(mpn_modexact_1c_odd)
+	stmfd	sp!, {r4, r5, r6, r7}
+
+	LEA(	r4, binvert_limb_table)
+
+	ldr	r6, [up], #4		C up[0]
+
+	and	r12, d, #254
+	ldrb	r4, [r4, r12, lsr #1]
+	smulbb	r12, r4, r4
+	mul	r12, d, r12
+	rsb	r12, r12, r4, asl #1
+	mul	r4, r12, r12
+	mul	r4, d, r4
+	rsb	r4, r4, r12, asl #1	C r4 = inverse
+
+	subs	n, n, #1
+	sub	r6, r6, cy
+	mul	r6, r6, r4
+	beq	L(end)
+
+	rsb	r5, r4, #0		C r5 = -inverse
+
+L(top):	ldr	r7, [up], #4
+	mov	r12, #0
+	umaal	r12, cy, r6, d
+	mul	r6, r7, r4
+	mla	r6, cy, r5, r6
+	subs	n, n, #1
+	bne	L(top)
+
+L(end):	mov	r12, #0
+	umaal	r12, cy, r6, d
+	mov	r0, cy
+
+	ldmfd	sp!, {r4, r5, r6, r7}
+	bx	r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/v6/mul_1.asm b/third_party/gmp/mpn/arm/v6/mul_1.asm
new file mode 100644
index 0000000..3c6ef99
--- /dev/null
+++ b/third_party/gmp/mpn/arm/v6/mul_1.asm
@@ -0,0 +1,115 @@
+dnl  ARM mpn_mul_1.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C StrongARM:	 -
+C XScale	 -
+C ARM11		 6.4
+C Cortex-A7	 5.25
+C Cortex-A8	 7
+C Cortex-A9	 3.25
+C Cortex-A15	 4
+
+C TODO
+C  * Micro-optimise feed-in code.
+C  * Optimise for n=1,2 by delaying register saving.
+C  * Try using ldm/stm.
+
+define(`rp',`r0')
+define(`up',`r1')
+define(`n', `r2')
+define(`v0',`r3')
+
+ASM_START()
+PROLOGUE(mpn_mul_1)
+	stmfd	sp!, { r4, r5, r6, r7 }
+
+	ands	r6, n, #3
+	mov	r12, #0
+	beq	L(fi0)
+	cmp	r6, #2
+	bcc	L(fi1)
+	beq	L(fi2)
+
+L(fi3):	ldr	r4, [up], #4
+	mov	r6, #0
+	ldr	r5, [up], #4
+	b	L(lo3)
+
+L(fi0):	ldr	r5, [up], #4
+	add	rp, rp, #4
+	mov	r7, #0
+	ldr	r4, [up], #4
+	b	L(lo0)
+
+L(fi1):	ldr	r4, [up], #4
+	mov	r6, #0
+	add	rp, rp, #8
+	subs	n, n, #1
+	beq	L(1)
+	ldr	r5, [up], #4
+	b	L(lo1)
+
+L(fi2):	ldr	r5, [up], #4
+	add	rp, rp, #12
+	mov	r7, #0
+	ldr	r4, [up], #4
+	b	L(lo2)
+
+	ALIGN(16)
+L(top):	mov	r6, #0
+	ldr	r5, [up], #4
+	str	r7, [rp, #-12]
+L(lo1):	umaal	r6, r12, r4, v0
+	mov	r7, #0
+	ldr	r4, [up], #4
+	str	r6, [rp, #-8]
+L(lo0):	umaal	r7, r12, r5, v0
+	mov	r6, #0
+	ldr	r5, [up], #4
+	str	r7, [rp, #-4]
+L(lo3):	umaal	r6, r12, r4, v0
+	mov	r7, #0
+	ldr	r4, [up], #4
+	str	r6, [rp], #16
+L(lo2):	umaal	r7, r12, r5, v0
+	subs	n, n, #4
+	bhi	L(top)
+
+	mov	r6, #0
+	str	r7, [rp, #-12]
+L(1):	umaal	r6, r12, r4, v0
+	str	r6, [rp, #-8]
+	mov	r0, r12
+	ldmfd	sp!, { r4, r5, r6, r7 }
+	bx	lr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/v6/mul_2.asm b/third_party/gmp/mpn/arm/v6/mul_2.asm
new file mode 100644
index 0000000..edd27f3
--- /dev/null
+++ b/third_party/gmp/mpn/arm/v6/mul_2.asm
@@ -0,0 +1,135 @@
+dnl  ARM mpn_mul_2.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C StrongARM:	 -
+C XScale	 -
+C ARM11		 5.25
+C Cortex-A5	 3.63
+C Cortex-A7	 3.15
+C Cortex-A8	 5.0
+C Cortex-A9	 2.25
+C Cortex-A15	 2.5
+C Cortex-A17	 2.13
+C Cortex-A53	 3.5
+
+C TODO
+C  * This is a trivial edit of the addmul_2 code.  Check for simplifications,
+C    and possible speedups to 2.0 c/l.
+
+define(`rp',`r0')
+define(`up',`r1')
+define(`n', `r2')
+define(`vp',`r3')
+
+define(`v0',`r6')
+define(`v1',`r7')
+define(`u0',`r3')
+define(`u1',`r9')
+
+define(`cya',`r8')
+define(`cyb',`r12')
+
+
+ASM_START()
+PROLOGUE(mpn_mul_2)
+	push	{ r4, r5, r6, r7, r8, r9 }
+
+	ldm	vp, { v0, v1 }
+	mov	cya, #0
+	mov	cyb, #0
+
+	tst	n, #1
+	beq	L(evn)
+L(odd):	mov	r5, #0
+	ldr	u0, [up, #0]
+	mov	r4, #0
+	tst	n, #2
+	beq	L(fi1)
+L(fi3):	sub	up, up, #12
+	sub	rp, rp, #16
+	b	L(lo3)
+L(fi1):	sub	n, n, #1
+	sub	up, up, #4
+	sub	rp, rp, #8
+	b	L(lo1)
+L(evn):	mov	r4, #0
+	ldr	u1, [up, #0]
+	mov	r5, #0
+	tst	n, #2
+	bne	L(fi2)
+L(fi0):	sub	up, up, #8
+	sub	rp, rp, #12
+	b	L(lo0)
+L(fi2):	subs	n, n, #2
+	sub	rp, rp, #4
+	bls	L(end)
+
+	ALIGN(16)
+L(top):	ldr	u0, [up, #4]
+	umaal	r4, cya, u1, v0
+	str	r4, [rp, #4]
+	mov	r4, #0
+	umaal	r5, cyb, u1, v1
+L(lo1):	ldr	u1, [up, #8]
+	umaal	r5, cya, u0, v0
+	str	r5, [rp, #8]
+	mov	r5, #0
+	umaal	r4, cyb, u0, v1
+L(lo0):	ldr	u0, [up, #12]
+	umaal	r4, cya, u1, v0
+	str	r4, [rp, #12]
+	mov	r4, #0
+	umaal	r5, cyb, u1, v1
+L(lo3):	ldr	u1, [up, #16]!
+	umaal	r5, cya, u0, v0
+	str	r5, [rp, #16]!
+	mov	r5, #0
+	umaal	r4, cyb, u0, v1
+	subs	n, n, #4
+	bhi	L(top)
+
+L(end):	umaal	r4, cya, u1, v0
+	ldr	u0, [up, #4]
+	umaal	r5, cyb, u1, v1
+	str	r4, [rp, #4]
+	umaal	r5, cya, u0, v0
+	umaal	cya, cyb, u0, v1
+	str	r5, [rp, #8]
+	str	cya, [rp, #12]
+	mov	r0, cyb
+
+	pop	{ r4, r5, r6, r7, r8, r9 }
+	bx	r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/v6/popham.asm b/third_party/gmp/mpn/arm/v6/popham.asm
new file mode 100644
index 0000000..c254368
--- /dev/null
+++ b/third_party/gmp/mpn/arm/v6/popham.asm
@@ -0,0 +1,139 @@
+dnl  ARM mpn_popcount and mpn_hamdist.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		     popcount	      hamdist
+C		    cycles/limb	    cycles/limb
+C StrongARM		 -
+C XScale		 -
+C Cortex-A7		 ?
+C Cortex-A8		 ?
+C Cortex-A9		 8.94		 9.47
+C Cortex-A15		 5.67		 6.44
+
+C Architecture requirements:
+C v5	-
+C v5t	-
+C v5te	ldrd strd
+C v6	usada8
+C v6t2	-
+C v7a	-
+
+ifdef(`OPERATION_popcount',`
+  define(`func',`mpn_popcount')
+  define(`ap',		`r0')
+  define(`n',		`r1')
+  define(`a0',		`r2')
+  define(`a1',		`r3')
+  define(`s',		`r5')
+  define(`b_01010101',	`r6')
+  define(`b_00110011',	`r7')
+  define(`b_00001111',	`r8')
+  define(`zero',	`r9')
+  define(`POPC',	`$1')
+  define(`HAMD',	`dnl')
+')
+ifdef(`OPERATION_hamdist',`
+  define(`func',`mpn_hamdist')
+  define(`ap',		`r0')
+  define(`bp',		`r1')
+  define(`n',		`r2')
+  define(`a0',		`r6')
+  define(`a1',		`r7')
+  define(`b0',		`r4')
+  define(`b1',		`r5')
+  define(`s',		`r11')
+  define(`b_01010101',	`r8')
+  define(`b_00110011',	`r9')
+  define(`b_00001111',	`r10')
+  define(`zero',	`r3')
+  define(`POPC',	`dnl')
+  define(`HAMD',	`$1')
+')
+
+MULFUNC_PROLOGUE(mpn_popcount mpn_hamdist)
+
+ASM_START()
+PROLOGUE(func)
+POPC(`	push	{ r4-r9 }	')
+HAMD(`	push	{ r4-r11 }	')
+
+	ldr	b_01010101, =0x55555555
+	mov	r12, #0
+	ldr	b_00110011, =0x33333333
+	mov	zero, #0
+	ldr	b_00001111, =0x0f0f0f0f
+
+	tst	n, #1
+	beq	L(evn)
+
+L(odd):	ldr	a1, [ap], #4		C 1 x 32 1-bit accumulators, 0-1
+HAMD(`	ldr	b1, [bp], #4	')	C 1 x 32 1-bit accumulators, 0-1
+HAMD(`	eor	a1, a1, b1	')
+	and	r4, b_01010101, a1, lsr #1
+	sub	a1, a1, r4
+	and	r4, a1, b_00110011
+	bic	r5, a1, b_00110011
+	add	r5, r4, r5, lsr #2	C 8 4-bit accumulators, 0-4
+	subs	n, n, #1
+	b	L(mid)
+
+L(evn):	mov	s, #0
+
+L(top):	ldrd	a0, a1, [ap], #8	C 2 x 32 1-bit accumulators, 0-1
+HAMD(`	ldrd	b0, b1, [bp], #8')
+HAMD(`	eor	a0, a0, b0	')
+HAMD(`	eor	a1, a1, b1	')
+	subs	n, n, #2
+	usada8	r12, s, zero, r12
+	and	r4, b_01010101, a0, lsr #1
+	sub	a0, a0, r4
+	and	r4, b_01010101, a1, lsr #1
+	sub	a1, a1, r4
+	and	r4, a0, b_00110011
+	bic	r5, a0, b_00110011
+	add	a0, r4, r5, lsr #2	C 8 4-bit accumulators, 0-4
+	and	r4, a1, b_00110011
+	bic	r5, a1, b_00110011
+	add	a1, r4, r5, lsr #2	C 8 4-bit accumulators, 0-4
+	add	r5, a0, a1		C 8 4-bit accumulators, 0-8
+L(mid):	and	r4, r5, b_00001111
+	bic	r5, r5, b_00001111
+	add	s, r4, r5, lsr #4	C 4 8-bit accumulators
+	bne	L(top)
+
+	usada8	r0, s, zero, r12
+POPC(`	pop	{ r4-r9 }	')
+HAMD(`	pop	{ r4-r11 }	')
+	bx	r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/v6/sqr_basecase.asm b/third_party/gmp/mpn/arm/v6/sqr_basecase.asm
new file mode 100644
index 0000000..0fc4f13
--- /dev/null
+++ b/third_party/gmp/mpn/arm/v6/sqr_basecase.asm
@@ -0,0 +1,544 @@
+dnl  ARM v6 mpn_sqr_basecase.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2012, 2013, 2015 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C Code structure:
+C
+C
+C        m_2(0m4)        m_2(2m4)        m_2(1m4)        m_2(3m4)
+C           |               |               |               |
+C           |               |               |               |
+C           |               |               |               |
+C          \|/             \|/             \|/             \|/
+C              ____________                   ____________
+C             /            \                 /            \
+C            \|/            \               \|/            \
+C         am_2(3m4)       am_2(1m4)       am_2(0m4)       am_2(2m4)
+C            \            /|\                \            /|\
+C             \____________/                  \____________/
+C                       \                        /
+C                        \                      /
+C                         \                    /
+C                         cor3             cor2
+C                            \              /
+C                             \            /
+C                            sqr_diag_addlsh1
+
+C TODO
+C  * Align more labels.
+C  * Further tweak counter and updates in outer loops.  (This could save
+C    perhaps 5n cycles).
+C  * Avoid sub-with-lsl in outer loops.  We could keep n up-shifted, then
+C    initialise loop counter i with a right shift.
+C  * Try to use fewer register.  Perhaps coalesce r9 branch target and n_saved.
+C    (This could save 2-3 cycles for n > 4.)
+C  * Optimise sqr_diag_addlsh1 loop.  The current code uses old-style carry
+C    propagation.
+C  * Stop loops earlier suppressing writes of upper-most rp[] values.
+C  * The addmul_2 loops here runs well on all cores, but mul_2 runs poorly
+C    particularly on Cortex-A8.
+
+
+define(`rp',      r0)
+define(`up',      r1)
+define(`n',       r2)
+
+define(`v0',      r3)
+define(`v1',      r6)
+define(`i',       r8)
+define(`n_saved', r14)
+define(`cya',     r11)
+define(`cyb',     r12)
+define(`u0',      r7)
+define(`u1',      r9)
+
+ASM_START()
+PROLOGUE(mpn_sqr_basecase)
+	and	r12, n, #3
+	cmp	n, #4
+	addgt	r12, r12, #4
+	add	pc, pc, r12, lsl #2
+	nop
+	b	L(4)
+	b	L(1)
+	b	L(2)
+	b	L(3)
+	b	L(0m4)
+	b	L(1m4)
+	b	L(2m4)
+	b	L(3m4)
+
+
+L(1m4):	push	{r4-r11, r14}
+	mov	n_saved, n
+	sub	i, n, #4
+	sub	n, n, #2
+	add	r10, pc, #L(am2_2m4)-.-8
+	ldm	up, {v0,v1,u0}
+	sub	up, up, #4
+	mov	cyb, #0
+	mov	r5, #0
+	umull	r4, cya, v1, v0
+	str	r4, [rp], #-12
+	mov	r4, #0
+	b	L(ko0)
+
+L(3m4):	push	{r4-r11, r14}
+	mov	n_saved, n
+	sub	i, n, #4
+	sub	n, n, #2
+	add	r10, pc, #L(am2_0m4)-.-8
+	ldm	up, {v0,v1,u0}
+	add	up, up, #4
+	mov	cyb, #0
+	mov	r5, #0
+	umull	r4, cya, v1, v0
+	str	r4, [rp], #-4
+	mov	r4, #0
+	b	L(ko2)
+
+L(2m4):	push	{r4-r11, r14}
+	mov	n_saved, n
+	sub	i, n, #4
+	sub	n, n, #2
+	add	r10, pc, #L(am2_3m4)-.-8
+	ldm	up, {v0,v1,u1}
+	mov	cyb, #0
+	mov	r4, #0
+	umull	r5, cya, v1, v0
+	str	r5, [rp], #-8
+	mov	r5, #0
+	b	L(ko1)
+
+L(0m4):	push	{r4-r11, r14}
+	mov	n_saved, n
+	sub	i, n, #4
+	sub	n, n, #2
+	add	r10, pc, #L(am2_1m4)-.-8
+	ldm	up, {v0,v1,u1}
+	mov	cyb, #0
+	mov	r4, #0
+	add	up, up, #8
+	umull	r5, cya, v1, v0
+	str	r5, [rp, #0]
+	mov	r5, #0
+
+L(top):	ldr	u0, [up, #4]
+	umaal	r4, cya, u1, v0
+	str	r4, [rp, #4]
+	mov	r4, #0
+	umaal	r5, cyb, u1, v1
+L(ko2):	ldr	u1, [up, #8]
+	umaal	r5, cya, u0, v0
+	str	r5, [rp, #8]
+	mov	r5, #0
+	umaal	r4, cyb, u0, v1
+L(ko1):	ldr	u0, [up, #12]
+	umaal	r4, cya, u1, v0
+	str	r4, [rp, #12]
+	mov	r4, #0
+	umaal	r5, cyb, u1, v1
+L(ko0):	ldr	u1, [up, #16]!
+	umaal	r5, cya, u0, v0
+	str	r5, [rp, #16]!
+	mov	r5, #0
+	umaal	r4, cyb, u0, v1
+	subs	i, i, #4
+	bhi	L(top)
+
+	umaal	r4, cya, u1, v0
+	ldr	u0, [up, #4]
+	umaal	r5, cyb, u1, v1
+	str	r4, [rp, #4]
+	umaal	r5, cya, u0, v0
+	umaal	cya, cyb, u0, v1
+	str	r5, [rp, #8]
+	str	cya, [rp, #12]
+	str	cyb, [rp, #16]
+
+	add	up, up, #4
+	sub	n, n, #1
+	add	rp, rp, #8
+	bx	r10
+
+L(evnloop):
+	subs	i, n, #6
+	sub	n, n, #2
+	blt	L(cor2)
+	ldm	up, {v0,v1,u1}
+	add	up, up, #8
+	mov	cya, #0
+	mov	cyb, #0
+	ldr	r4, [rp, #-4]
+	umaal	r4, cya, v1, v0
+	str	r4, [rp, #-4]
+	ldr	r4, [rp, #0]
+
+	ALIGN(16)
+L(ua2):	ldr	r5, [rp, #4]
+	umaal	r4, cya, u1, v0
+	ldr	u0, [up, #4]
+	umaal	r5, cyb, u1, v1
+	str	r4, [rp, #0]
+	ldr	r4, [rp, #8]
+	umaal	r5, cya, u0, v0
+	ldr	u1, [up, #8]
+	umaal	r4, cyb, u0, v1
+	str	r5, [rp, #4]
+	ldr	r5, [rp, #12]
+	umaal	r4, cya, u1, v0
+	ldr	u0, [up, #12]
+	umaal	r5, cyb, u1, v1
+	str	r4, [rp, #8]
+	ldr	r4, [rp, #16]!
+	umaal	r5, cya, u0, v0
+	ldr	u1, [up, #16]!
+	umaal	r4, cyb, u0, v1
+	str	r5, [rp, #-4]
+	subs	i, i, #4
+	bhs	L(ua2)
+
+	umaal	r4, cya, u1, v0
+	umaal	cya, cyb, u1, v1
+	str	r4, [rp, #0]
+	str	cya, [rp, #4]
+	str	cyb, [rp, #8]
+L(am2_0m4):
+	sub	rp, rp, n, lsl #2
+	sub	up, up, n, lsl #2
+	add	rp, rp, #8
+
+	sub	i, n, #4
+	sub	n, n, #2
+	ldm	up, {v0,v1,u1}
+	mov	cya, #0
+	mov	cyb, #0
+	ldr	r4, [rp, #4]
+	umaal	r4, cya, v1, v0
+	str	r4, [rp, #4]
+	ldr	r4, [rp, #8]
+	b	L(lo0)
+
+	ALIGN(16)
+L(ua0):	ldr	r5, [rp, #4]
+	umaal	r4, cya, u1, v0
+	ldr	u0, [up, #4]
+	umaal	r5, cyb, u1, v1
+	str	r4, [rp, #0]
+	ldr	r4, [rp, #8]
+	umaal	r5, cya, u0, v0
+	ldr	u1, [up, #8]
+	umaal	r4, cyb, u0, v1
+	str	r5, [rp, #4]
+L(lo0):	ldr	r5, [rp, #12]
+	umaal	r4, cya, u1, v0
+	ldr	u0, [up, #12]
+	umaal	r5, cyb, u1, v1
+	str	r4, [rp, #8]
+	ldr	r4, [rp, #16]!
+	umaal	r5, cya, u0, v0
+	ldr	u1, [up, #16]!
+	umaal	r4, cyb, u0, v1
+	str	r5, [rp, #-4]
+	subs	i, i, #4
+	bhs	L(ua0)
+
+	umaal	r4, cya, u1, v0
+	umaal	cya, cyb, u1, v1
+	str	r4, [rp, #0]
+	str	cya, [rp, #4]
+	str	cyb, [rp, #8]
+L(am2_2m4):
+	sub	rp, rp, n, lsl #2
+	sub	up, up, n, lsl #2
+	add	rp, rp, #16
+	b	L(evnloop)
+
+
+L(oddloop):
+	sub	i, n, #5
+	sub	n, n, #2
+	ldm	up, {v0,v1,u0}
+	mov	cya, #0
+	mov	cyb, #0
+	ldr	r5, [rp, #0]
+	umaal	r5, cya, v1, v0
+	str	r5, [rp, #0]
+	ldr	r5, [rp, #4]
+	add	up, up, #4
+	b	L(lo1)
+
+	ALIGN(16)
+L(ua1):	ldr	r5, [rp, #4]
+	umaal	r4, cya, u1, v0
+	ldr	u0, [up, #4]
+	umaal	r5, cyb, u1, v1
+	str	r4, [rp, #0]
+L(lo1):	ldr	r4, [rp, #8]
+	umaal	r5, cya, u0, v0
+	ldr	u1, [up, #8]
+	umaal	r4, cyb, u0, v1
+	str	r5, [rp, #4]
+	ldr	r5, [rp, #12]
+	umaal	r4, cya, u1, v0
+	ldr	u0, [up, #12]
+	umaal	r5, cyb, u1, v1
+	str	r4, [rp, #8]
+	ldr	r4, [rp, #16]!
+	umaal	r5, cya, u0, v0
+	ldr	u1, [up, #16]!
+	umaal	r4, cyb, u0, v1
+	str	r5, [rp, #-4]
+	subs	i, i, #4
+	bhs	L(ua1)
+
+	umaal	r4, cya, u1, v0
+	umaal	cya, cyb, u1, v1
+	str	r4, [rp, #0]
+	str	cya, [rp, #4]
+	str	cyb, [rp, #8]
+L(am2_3m4):
+	sub	rp, rp, n, lsl #2
+	sub	up, up, n, lsl #2
+	add	rp, rp, #4
+
+	subs	i, n, #3
+	beq	L(cor3)
+	sub	n, n, #2
+	ldm	up, {v0,v1,u0}
+	mov	cya, #0
+	mov	cyb, #0
+	ldr	r5, [rp, #8]
+	sub	up, up, #4
+	umaal	r5, cya, v1, v0
+	str	r5, [rp, #8]
+	ldr	r5, [rp, #12]
+	b	L(lo3)
+
+	ALIGN(16)
+L(ua3):	ldr	r5, [rp, #4]
+	umaal	r4, cya, u1, v0
+	ldr	u0, [up, #4]
+	umaal	r5, cyb, u1, v1
+	str	r4, [rp, #0]
+	ldr	r4, [rp, #8]
+	umaal	r5, cya, u0, v0
+	ldr	u1, [up, #8]
+	umaal	r4, cyb, u0, v1
+	str	r5, [rp, #4]
+	ldr	r5, [rp, #12]
+	umaal	r4, cya, u1, v0
+	ldr	u0, [up, #12]
+	umaal	r5, cyb, u1, v1
+	str	r4, [rp, #8]
+L(lo3):	ldr	r4, [rp, #16]!
+	umaal	r5, cya, u0, v0
+	ldr	u1, [up, #16]!
+	umaal	r4, cyb, u0, v1
+	str	r5, [rp, #-4]
+	subs	i, i, #4
+	bhs	L(ua3)
+
+	umaal	r4, cya, u1, v0
+	umaal	cya, cyb, u1, v1
+	str	r4, [rp, #0]
+	str	cya, [rp, #4]
+	str	cyb, [rp, #8]
+L(am2_1m4):
+	sub	rp, rp, n, lsl #2
+	sub	up, up, n, lsl #2
+	add	rp, rp, #12
+	b	L(oddloop)
+
+
+L(cor3):ldm	up, {v0,v1,u0}
+	ldr	r5, [rp, #8]
+	mov	cya, #0
+	mov	cyb, #0
+	umaal	r5, cya, v1, v0
+	str	r5, [rp, #8]
+	ldr	r5, [rp, #12]
+	ldr	r4, [rp, #16]
+	umaal	r5, cya, u0, v0
+	ldr	u1, [up, #12]
+	umaal	r4, cyb, u0, v1
+	str	r5, [rp, #12]
+	umaal	r4, cya, u1, v0
+	umaal	cya, cyb, u1, v1
+	str	r4, [rp, #16]
+	str	cya, [rp, #20]
+	str	cyb, [rp, #24]
+	add	up, up, #16
+	mov	cya, cyb
+	adds	rp, rp, #36		C clear cy
+	mov	cyb, #0
+	umaal	cya, cyb, u1, u0
+	b	L(sqr_diag_addlsh1)
+
+L(cor2):
+	ldm	up!, {v0,v1,u0}
+	mov	r4, cya
+	mov	r5, cyb
+	mov	cya, #0
+	umaal	r4, cya, v1, v0
+	mov	cyb, #0
+	umaal	r5, cya, u0, v0
+	strd	r4, r5, [rp, #-4]
+	umaal	cya, cyb, u0, v1
+	add	rp, rp, #16
+C	b	L(sqr_diag_addlsh1)
+
+
+define(`w0',  r6)
+define(`w1',  r7)
+define(`w2',  r8)
+define(`rbx', r9)
+
+L(sqr_diag_addlsh1):
+	str	cya, [rp, #-12]
+	str	cyb, [rp, #-8]
+	sub	n, n_saved, #1
+	sub	up, up, n_saved, lsl #2
+	sub	rp, rp, n_saved, lsl #3
+	ldr	r3, [up], #4
+	umull	w1, r5, r3, r3
+	mov	w2, #0
+	mov	r10, #0
+C	cmn	r0, #0			C clear cy (already clear)
+	b	L(lm)
+
+L(tsd):	adds	w0, w0, rbx
+	adcs	w1, w1, r4
+	str	w0, [rp, #0]
+L(lm):	ldr	w0, [rp, #4]
+	str	w1, [rp, #4]
+	ldr	w1, [rp, #8]!
+	add	rbx, r5, w2
+	adcs	w0, w0, w0
+	ldr	r3, [up], #4
+	adcs	w1, w1, w1
+	adc	w2, r10, r10
+	umull	r4, r5, r3, r3
+	subs	n, n, #1
+	bne	L(tsd)
+
+	adds	w0, w0, rbx
+	adcs	w1, w1, r4
+	adc	w2, r5, w2
+	stm	rp, {w0,w1,w2}
+
+	pop	{r4-r11, pc}
+
+
+C Straight line code for n <= 4
+
+L(1):	ldr	r3, [up, #0]
+	umull	r1, r2, r3, r3
+	stm	rp, {r1,r2}
+	bx	r14
+
+L(2):	push	{r4-r5}
+	ldm	up, {r5,r12}
+	umull	r1, r2, r5, r5
+	umull	r3, r4, r12, r12
+	umull	r5, r12, r5, r12
+	adds	r5, r5, r5
+	adcs	r12, r12, r12
+	adc	r4, r4, #0
+	adds	r2, r2, r5
+	adcs	r3, r3, r12
+	adc	r4, r4, #0
+	stm	rp, {r1,r2,r3,r4}
+	pop	{r4-r5}
+	bx	r14
+
+L(3):	push	{r4-r11}
+	ldm	up, {r7,r8,r9}
+	umull	r1, r2, r7, r7
+	umull	r3, r4, r8, r8
+	umull	r5, r6, r9, r9
+	umull	r10, r11, r7, r8
+	mov	r12, #0
+	umlal	r11, r12, r7, r9
+	mov	r7, #0
+	umlal	r12, r7, r8, r9
+	adds	r10, r10, r10
+	adcs	r11, r11, r11
+	adcs	r12, r12, r12
+	adcs	r7, r7, r7
+	adc	r6, r6, #0
+	adds	r2, r2, r10
+	adcs	r3, r3, r11
+	adcs	r4, r4, r12
+	adcs	r5, r5, r7
+	adc	r6, r6, #0
+	stm	rp, {r1,r2,r3,r4,r5,r6}
+	pop	{r4-r11}
+	bx	r14
+
+L(4):	push	{r4-r11, r14}
+	ldm	up, {r9,r10,r11,r12}
+	umull	r1, r2, r9, r9
+	umull	r3, r4, r10, r10
+	umull	r5, r6, r11, r11
+	umull	r7, r8, r12, r12
+	stm	rp, {r1,r2,r3,r4,r5,r6,r7}
+	umull	r1, r2, r9, r10
+	mov	r3, #0
+	umlal	r2, r3, r9, r11
+	mov	r4, #0
+	umlal	r3, r4, r9, r12
+	mov	r5, #0
+	umlal	r3, r5, r10, r11
+	umaal	r4, r5, r10, r12
+	mov	r6, #0
+	umlal	r5, r6, r11, r12
+	adds	r1, r1, r1
+	adcs	r2, r2, r2
+	adcs	r3, r3, r3
+	adcs	r4, r4, r4
+	adcs	r5, r5, r5
+	adcs	r6, r6, r6
+	add	rp, rp, #4
+	adc	r7, r8, #0
+	ldm	rp, {r8,r9,r10,r11,r12,r14}
+	adds	r1, r1, r8
+	adcs	r2, r2, r9
+	adcs	r3, r3, r10
+	adcs	r4, r4, r11
+	adcs	r5, r5, r12
+	adcs	r6, r6, r14
+	adc	r7, r7, #0
+	stm	rp, {r1,r2,r3,r4,r5,r6,r7}
+	pop	{r4-r11, pc}
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/v6/submul_1.asm b/third_party/gmp/mpn/arm/v6/submul_1.asm
new file mode 100644
index 0000000..8a21733
--- /dev/null
+++ b/third_party/gmp/mpn/arm/v6/submul_1.asm
@@ -0,0 +1,125 @@
+dnl  ARM mpn_submul_1.
+
+dnl  Copyright 2012, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C StrongARM:	 -
+C XScale	 -
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 3.75
+C Cortex-A15	 4.0
+
+C This loop complements U on the fly,
+C   U' = B^n - 1 - U
+C and then uses that
+C   R - U*v = R + U'*v + v - B^n v
+
+C TODO
+C  * Micro-optimise feed-in code.
+C  * Optimise for n=1,2 by delaying register saving.
+C  * Try using ldm/stm.
+
+define(`rp',`r0')
+define(`up',`r1')
+define(`n', `r2')
+define(`v0',`r3')
+
+ASM_START()
+PROLOGUE(mpn_submul_1)
+	stmfd	sp!, { r4, r5, r6, r7 }
+
+	ands	r6, n, #3
+	mov	r12, v0
+	beq	L(fi0)
+	cmp	r6, #2
+	bcc	L(fi1)
+	beq	L(fi2)
+
+L(fi3):	ldr	r4, [up], #12
+	mvn	r4, r4
+	ldr	r6, [rp, #0]
+	ldr	r5, [up, #-8]
+	b	L(lo3)
+
+L(fi0):	ldr	r5, [up], #16
+	mvn	r5, r5
+	ldr	r7, [rp], #4
+	ldr	r4, [up, #-12]
+	b	L(lo0)
+
+L(fi1):	ldr	r4, [up], #4
+	mvn	r4, r4
+	ldr	r6, [rp], #8
+	subs	n, n, #1
+	beq	L(1)
+	ldr	r5, [up]
+	b	L(lo1)
+
+L(fi2):	ldr	r5, [up], #8
+	mvn	r5, r5
+	ldr	r7, [rp], #12
+	ldr	r4, [up, #-4]
+	b	L(lo2)
+
+	ALIGN(16)
+L(top):	ldr	r6, [rp, #-8]
+	ldr	r5, [up]
+	str	r7, [rp, #-12]
+L(lo1):	umaal	r6, r12, r4, v0
+	add	up, up, #16
+	mvn	r5, r5
+	ldr	r7, [rp, #-4]
+	ldr	r4, [up, #-12]
+	str	r6, [rp, #-8]
+L(lo0):	umaal	r7, r12, r5, v0
+	mvn	r4, r4
+	ldr	r6, [rp, #0]
+	ldr	r5, [up, #-8]
+	str	r7, [rp, #-4]
+L(lo3):	umaal	r6, r12, r4, v0
+	mvn	r5, r5
+	ldr	r7, [rp, #4]
+	ldr	r4, [up, #-4]
+	str	r6, [rp], #16
+L(lo2):	umaal	r7, r12, r5, v0
+	mvn	r4, r4
+	subs	n, n, #4
+	bhi	L(top)
+
+	ldr	r6, [rp, #-8]
+	str	r7, [rp, #-12]
+L(1):	umaal	r6, r12, r4, v0
+	str	r6, [rp, #-8]
+	sub	r0, v0, r12
+	ldmfd	sp!, { r4, r5, r6, r7 }
+	bx	lr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/v6t2/divrem_1.asm b/third_party/gmp/mpn/arm/v6t2/divrem_1.asm
new file mode 100644
index 0000000..be24615
--- /dev/null
+++ b/third_party/gmp/mpn/arm/v6t2/divrem_1.asm
@@ -0,0 +1,212 @@
+dnl  ARM v6t2 mpn_divrem_1 and mpn_preinv_divrem_1.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		norm	unorm	frac
+C StrongARM	 -	 -	 -
+C XScale	 -	 -	 -
+C Cortex-A7	 ?	 ?	 ?
+C Cortex-A8	 ?	 ?	 ?
+C Cortex-A9	13	14	13
+C Cortex-A15	11.4	11.8	11.1
+
+C TODO
+C  * Optimise inner-loops better, they could likely run a cycle or two faster.
+C  * Decrease register usage, streamline non-loop code.
+
+define(`qp_arg',  `r0')
+define(`fn',      `r1')
+define(`up_arg',  `r2')
+define(`n_arg',   `r3')
+define(`d_arg',   `0')
+define(`dinv_arg',`4')
+define(`cnt_arg', `8')
+
+define(`n',       `r9')
+define(`qp',      `r5')
+define(`up',      `r6')
+define(`cnt',     `r7')
+define(`tnc',     `r10')
+define(`dinv',    `r0')
+define(`d',       `r4')
+
+ASM_START()
+PROLOGUE(mpn_preinv_divrem_1)
+	stmfd	sp!, {r4, r5, r6, r7, r8, r9, r10, r11, lr}
+	ldr	d,    [sp, #9*4+d_arg]
+	ldr	cnt,  [sp, #9*4+cnt_arg]
+	str	r1, [sp, #9*4+d_arg]	C reuse d stack slot for fn
+	sub	n, r3, #1
+	add	r3, r1, n
+	cmp	d, #0
+	add	qp, qp_arg, r3, lsl #2	C put qp at Q[] end
+	add	up, up_arg, n, lsl #2	C put up at U[] end
+	ldr	dinv, [sp, #9*4+dinv_arg]
+	blt	L(nent)
+	b	L(uent)
+EPILOGUE()
+
+PROLOGUE(mpn_divrem_1)
+	stmfd	sp!, {r4, r5, r6, r7, r8, r9, r10, r11, lr}
+	sub	n, r3, #1
+	ldr	d, [sp, #9*4+d_arg]	C d
+	str	r1, [sp, #9*4+d_arg]	C reuse d stack slot for fn
+	add	r3, r1, n
+	cmp	d, #0
+	add	qp, qp_arg, r3, lsl #2	C put qp at Q[] end
+	add	up, up_arg, n, lsl #2	C put up at U[] end
+	blt	L(normalised)
+
+L(unnorm):
+	clz	cnt, d
+	mov	r0, d, lsl cnt		C pass d << cnt
+	bl	mpn_invert_limb
+L(uent):
+	mov	d, d, lsl cnt		C d <<= cnt
+	cmp	n, #0
+	mov	r1, #0			C r
+	blt	L(frac)
+
+	ldr	r11, [up, #0]
+
+	rsb	tnc, cnt, #32
+	mov	r1, r11, lsr tnc
+	mov	r11, r11, lsl cnt
+	beq	L(uend)
+
+	ldr	r3, [up, #-4]!
+	orr	r2, r11, r3, lsr tnc
+	b	L(mid)
+
+L(utop):
+	mls	r1, d, r8, r11
+	mov	r11, r3, lsl cnt
+	ldr	r3, [up, #-4]!
+	cmp	r1, r2
+	addhi	r1, r1, d
+	subhi	r8, r8, #1
+	orr	r2, r11, r3, lsr tnc
+	cmp	r1, d
+	bcs	L(ufx)
+L(uok):	str	r8, [qp], #-4
+L(mid):	add	r8, r1, #1
+	mov	r11, r2
+	umlal	r2, r8, r1, dinv
+	subs	n, n, #1
+	bne	L(utop)
+
+	mls	r1, d, r8, r11
+	mov	r11, r3, lsl cnt
+	cmp	r1, r2
+	addhi	r1, r1, d
+	subhi	r8, r8, #1
+	cmp	r1, d
+	rsbcs	r1, d, r1
+	addcs	r8, r8, #1
+	str	r8, [qp], #-4
+
+L(uend):add	r8, r1, #1
+	mov	r2, r11
+	umlal	r2, r8, r1, dinv
+	mls	r1, d, r8, r11
+	cmp	r1, r2
+	addhi	r1, r1, d
+	subhi	r8, r8, #1
+	cmp	r1, d
+	rsbcs	r1, d, r1
+	addcs	r8, r8, #1
+	str	r8, [qp], #-4
+L(frac):
+	ldr	r2, [sp, #9*4+d_arg]	C fn
+	cmp	r2, #0
+	beq	L(fend)
+
+L(ftop):mov	r6, #0
+	add	r3, r1, #1
+	umlal	r6, r3, r1, dinv
+	mov	r8, #0
+	mls	r1, d, r3, r8
+	cmp	r1, r6
+	addhi	r1, r1, d
+	subhi	r3, r3, #1
+	subs	r2, r2, #1
+	str	r3, [qp], #-4
+	bne	L(ftop)
+
+L(fend):mov	r11, r1, lsr cnt
+L(rtn):	mov	r0, r11
+	ldmfd	sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc}
+
+L(normalised):
+	mov	r0, d
+	bl	mpn_invert_limb
+L(nent):
+	cmp	n, #0
+	mov	r11, #0			C r
+	blt	L(nend)
+
+	ldr	r11, [up, #0]
+	cmp	r11, d
+	movlo	r2, #0			C hi q limb
+	movhs	r2, #1			C hi q limb
+	subhs	r11, r11, d
+
+	str	r2, [qp], #-4
+	cmp	n, #0
+	beq	L(nend)
+
+L(ntop):ldr	r1, [up, #-4]!
+	add	r12, r11, #1
+	umlal	r1, r12, r11, dinv
+	ldr	r3, [up, #0]
+	mls	r11, d, r12, r3
+	cmp	r11, r1
+	addhi	r11, r11, d
+	subhi	r12, r12, #1
+	cmp	d, r11
+	bls	L(nfx)
+L(nok):	str	r12, [qp], #-4
+	subs	n, n, #1
+	bne	L(ntop)
+
+L(nend):mov	r1, r11			C r
+	mov	cnt, #0			C shift cnt
+	b	L(frac)
+
+L(nfx):	add	r12, r12, #1
+	rsb	r11, d, r11
+	b	L(nok)
+L(ufx):	rsb	r1, d, r1
+	add	r8, r8, #1
+	b	L(uok)
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/v6t2/gcd_11.asm b/third_party/gmp/mpn/arm/v6t2/gcd_11.asm
new file mode 100644
index 0000000..8a38351
--- /dev/null
+++ b/third_party/gmp/mpn/arm/v6t2/gcd_11.asm
@@ -0,0 +1,65 @@
+dnl  ARM v6t2 mpn_gcd_11.
+
+dnl  Copyright 2000-2002, 2005, 2009, 2011, 2012, 2019 Free Software Foundation,
+dnl  Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/bit (approx)
+C StrongARM	 -
+C XScale	 -
+C Cortex-A5	 5.2
+C Cortex-A7	 5.04
+C Cortex-A8	 3.59
+C Cortex-A9	 9.5
+C Cortex-A15	 3.2
+C Cortex-A17	 5.25
+C Cortex-A53	 3.57
+
+define(`u0',    `r0')
+define(`v0',    `r1')
+
+ASM_START()
+	TEXT
+	ALIGN(64)
+PROLOGUE(mpn_gcd_11)
+	subs	r3, u0, v0	C			0
+	beq	L(end)		C
+
+	ALIGN(16)
+L(top):	rbit	r12, r3		C			1,5
+	clz	r12, r12	C			2
+	rsbcc	r3, r3, #0	C v = abs(u-v), even	1
+	movcs	u0, v0		C u = min(u,v)		1
+	lsr	v0, r3, r12	C			3
+	subs	r3, u0, v0	C			4
+	bne	L(top)		C
+
+L(end):	bx	lr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/v6t2/gcd_22.asm b/third_party/gmp/mpn/arm/v6t2/gcd_22.asm
new file mode 100644
index 0000000..3b23808
--- /dev/null
+++ b/third_party/gmp/mpn/arm/v6t2/gcd_22.asm
@@ -0,0 +1,113 @@
+dnl  ARM v6t2 mpn_gcd_22.
+
+dnl  Copyright 2019 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C	     cycles/bit (approx)
+C StrongARM	 -
+C XScale	 -
+C Cortex-A5	10.1
+C Cortex-A7	 9.1
+C Cortex-A8	 6.3
+C Cortex-A9	 ?
+C Cortex-A12	 7.7
+C Cortex-A15	 5.7
+C Cortex-A17	 ?
+C Cortex-A53	 7.0
+
+
+define(`gp',    `r0')
+
+define(`u1',    `r1')
+define(`u0',    `r2')
+define(`v1',    `r3')
+define(`v0',    `r4')
+
+define(`t0',    `r5')
+define(`t1',    `r6')
+define(`cnt',   `r7')
+
+ASM_START()
+PROLOGUE(mpn_gcd_22)
+	push	{ r4-r7 }
+
+	ldr	v0, [sp,#16]		C
+
+L(top):	subs	t0, u0, v0		C 0 7
+	beq	L(lowz)
+	sbcs	t1, u1, v1		C 1 8
+
+	rbit	cnt, t0			C 1
+
+	negcc	t0, t0
+	mvncc	t1, t1
+L(bck):	movcc	v0, u0
+	movcc	v1, u1
+
+	clz	cnt, cnt		C 2
+	rsb	r12, cnt, #32		C 3
+
+	lsr	u0, t0, cnt		C 3
+	lsl	r12, t1, r12		C 4
+	lsr	u1, t1, cnt		C 3
+	orr	u0, u0, r12		C 5
+
+	orrs	r12, u1, v1
+	bne	L(top)
+
+
+	str	r12, [gp,#4]		C high result limb <= 0
+
+	mov	r6, gp
+	mov	r0, u0			C pass 1st argument
+	mov	r1, v0			C pass 2nd argument
+	mov	r7, r14			C preserve link register
+	bl	mpn_gcd_11
+	str	r0, [r6,#0]
+	mov	r14, r7
+	pop	{ r4-r7 }
+	bx	r14
+
+L(lowz):C We come here when v0 - u0 = 0
+	C 1. If v1 - u1 = 0, then gcd is u = v.
+	C 2. Else compute gcd_21({v1,v0}, |u1-v1|)
+	subs	t0, u1, v1
+	beq	L(end)
+	mov	t1, #0
+	rbit	cnt, t0			C 1
+	negcc	t0, t0
+	b	L(bck)
+
+L(end):	str	v0, [gp,#0]
+	str	v1, [gp,#4]
+	pop	{ r4-r7 }
+	bx	r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/v7a/cora15/addmul_1.asm b/third_party/gmp/mpn/arm/v7a/cora15/addmul_1.asm
new file mode 100644
index 0000000..c2277b3
--- /dev/null
+++ b/third_party/gmp/mpn/arm/v7a/cora15/addmul_1.asm
@@ -0,0 +1,145 @@
+dnl  ARM mpn_addmul_1 optimised for A15.
+
+dnl  Copyright 2012, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb		best
+C StrongARM:     -
+C XScale	 ?
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 6			3.25
+C Cortex-A15	 2			this
+
+C This code uses umlal for adding in the rp[] data, keeping the recurrency path
+C separate from any multiply instructions.  It performs well on A15, at umlal's
+C bandwidth.
+C
+C An A9 variant should perhaps stick to 3-way unrolling, and use ldm and stm
+C for all loads and stores.  Alternatively, it could do 2-way or 4-way, but
+C then alignment aware code will be necessary (adding O(1) bookkeeping
+C overhead).
+C
+C We don't use r12 due to ldrd and strd limitations.
+
+C Architecture requirements:
+C v5	-
+C v5t	-
+C v5te	ldrd strd
+C v6	-
+C v6t2	-
+C v7a	-
+
+define(`rp', `r0')
+define(`up', `r1')
+define(`n',  `r2')
+define(`v0', `r3')
+
+define(`w0', `r10') define(`w1', `r11')
+define(`u0', `r8')  define(`u1', `r9')
+
+ASM_START()
+PROLOGUE(mpn_addmul_1)
+	push	{ r4-r11 }
+
+	ands	r6, n, #3
+	sub	n, n, #3
+	beq	L(b00)
+	cmp	r6, #2
+	bcc	L(b01)
+	beq	L(b10)
+
+L(b11):	mov	r6, #0
+	cmn	r13, #0			C carry clear
+	ldr	u1, [up], #-4
+	ldr	w1, [rp], #-4
+	mov	r7, #0
+	b	L(mid)
+
+L(b00):	ldrd	u0, u1, [up]
+	ldrd	w0, w1, [rp]
+	mov	r6, #0
+	umlal	w0, r6, u0, v0
+	cmn	r13, #0			C carry clear
+	mov	r7, #0
+	str	w0, [rp]
+	b	L(mid)
+
+L(b10):	ldrd	u0, u1, [up], #8
+	ldrd	w0, w1, [rp]
+	mov	r4, #0
+	umlal	w0, r4, u0, v0
+	cmn	r13, #0			C carry clear
+	mov	r5, #0
+	str	w0, [rp], #8
+	umlal	w1, r5, u1, v0
+	tst	n, n
+	bmi	L(end)
+	b	L(top)
+
+L(b01):	mov	r4, #0
+	ldr	u1, [up], #4
+	ldr	w1, [rp], #4
+	mov	r5, #0
+	umlal	w1, r5, u1, v0
+	tst	n, n
+	bmi	L(end)
+
+	ALIGN(16)
+L(top):	ldrd	u0, u1, [up, #0]
+	adcs	r4, r4, w1
+	ldrd	w0, w1, [rp, #0]
+	mov	r6, #0
+	umlal	w0, r6, u0, v0		C 1 2
+	adcs	r5, r5, w0
+	mov	r7, #0
+	strd	r4, r5, [rp, #-4]
+L(mid):	umlal	w1, r7, u1, v0		C 2 3
+	ldrd	u0, u1, [up, #8]
+	adcs	r6, r6, w1
+	ldrd	w0, w1, [rp, #8]
+	mov	r4, #0
+	umlal	w0, r4, u0, v0		C 3 4
+	adcs	r7, r7, w0
+	mov	r5, #0
+	strd	r6, r7, [rp, #4]
+	umlal	w1, r5, u1, v0		C 0 1
+	sub	n, n, #4
+	add	up, up, #16
+	add	rp, rp, #16
+	tst	n, n
+	bpl	L(top)
+
+L(end):	adcs	r4, r4, w1
+	str	r4, [rp, #-4]
+	adc	r0, r5, #0
+	pop	{ r4-r11 }
+	bx	r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/v7a/cora15/aors_n.asm b/third_party/gmp/mpn/arm/v7a/cora15/aors_n.asm
new file mode 100644
index 0000000..dc3f839
--- /dev/null
+++ b/third_party/gmp/mpn/arm/v7a/cora15/aors_n.asm
@@ -0,0 +1,162 @@
+dnl  ARM mpn_add_n/mpn_sub_n optimised for A15.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb		best
+C StrongARM:     -
+C XScale	 ?
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 3.55			2.5
+C Cortex-A15	 1.27			this
+
+C This was a major improvement compared to the code we had before, but it might
+C not be the best 8-way code possible.  We've tried some permutations of auto-
+C increments and separate pointer updates, but they all ran at the same speed
+C on A15.
+
+C Architecture requirements:
+C v5	-
+C v5t	-
+C v5te	ldrd strd
+C v6	-
+C v6t2	-
+C v7a	-
+
+define(`rp', `r0')
+define(`up', `r1')
+define(`vp', `r2')
+define(`n',  `r3')
+
+ifdef(`OPERATION_add_n', `
+  define(`ADDSUBC',	adcs)
+  define(`IFADD',	`$1')
+  define(`SETCY',	`cmp	$1, #1')
+  define(`RETVAL',	`adc	r0, n, #0')
+  define(`RETVAL2',	`adc	r0, n, #1')
+  define(`func',	mpn_add_n)
+  define(`func_nc',	mpn_add_nc)')
+ifdef(`OPERATION_sub_n', `
+  define(`ADDSUBC',	sbcs)
+  define(`IFADD',	`')
+  define(`SETCY',	`rsbs	$1, $1, #0')
+  define(`RETVAL',	`sbc	r0, r0, r0
+			and	r0, r0, #1')
+  define(`RETVAL2',	`RETVAL')
+  define(`func',	mpn_sub_n)
+  define(`func_nc',	mpn_sub_nc)')
+
+MULFUNC_PROLOGUE(mpn_add_n mpn_add_nc mpn_sub_n mpn_sub_nc)
+
+ASM_START()
+PROLOGUE(func_nc)
+	ldr	r12, [sp]
+	b	L(ent)
+EPILOGUE()
+PROLOGUE(func)
+	mov	r12, #0
+L(ent):	push	{ r4-r9 }
+
+	ands	r6, n, #3
+	mov	n, n, lsr #2
+	beq	L(b00)
+	cmp	r6, #2
+	bcc	L(b01)
+	beq	L(b10)
+
+L(b11):	ldr	r5, [up], #4
+	ldr	r7, [vp], #4
+	SETCY(	r12)
+	ADDSUBC	r9, r5, r7
+	ldrd	r4, r5, [up, #0]
+	ldrd	r6, r7, [vp, #0]
+	str	r9, [rp], #-4
+	b	L(lo)
+
+L(b00):	ldrd	r4, r5, [up], #-8
+	ldrd	r6, r7, [vp], #-8
+	SETCY(	r12)
+	sub	rp, rp, #16
+	b	L(mid)
+
+L(b01):	ldr	r5, [up], #-4
+	ldr	r7, [vp], #-4
+	SETCY(	r12)
+	ADDSUBC	r9, r5, r7
+	str	r9, [rp], #-12
+	tst	n, n
+	beq	L(wd1)
+L(gt1):	ldrd	r4, r5, [up, #8]
+	ldrd	r6, r7, [vp, #8]
+	b	L(mid)
+
+L(b10):	ldrd	r4, r5, [up]
+	ldrd	r6, r7, [vp]
+	SETCY(	r12)
+	sub	rp, rp, #8
+	b	L(lo)
+
+	ALIGN(16)
+L(top):	ldrd	r4, r5, [up, #8]
+	ldrd	r6, r7, [vp, #8]
+	strd	r8, r9, [rp, #8]
+L(mid):	ADDSUBC	r8, r4, r6
+	ADDSUBC	r9, r5, r7
+	ldrd	r4, r5, [up, #16]
+	ldrd	r6, r7, [vp, #16]
+	strd	r8, r9, [rp, #16]
+	ADDSUBC	r8, r4, r6
+	ADDSUBC	r9, r5, r7
+	sub	n, n, #2
+	tst	n, n
+	bmi	L(dne)
+	ldrd	r4, r5, [up, #24]
+	ldrd	r6, r7, [vp, #24]
+	strd	r8, r9, [rp, #24]
+	ADDSUBC	r8, r4, r6
+	ADDSUBC	r9, r5, r7
+	ldrd	r4, r5, [up, #32]!
+	ldrd	r6, r7, [vp, #32]!
+	strd	r8, r9, [rp, #32]!
+L(lo):	ADDSUBC	r8, r4, r6
+	ADDSUBC	r9, r5, r7
+	tst	n, n
+	bne	L(top)
+
+L(end):	strd	r8, r9, [rp, #8]
+L(wd1):	RETVAL
+	pop	{ r4-r9 }
+	bx	r14
+L(dne):	strd	r8, r9, [rp, #24]
+	RETVAL2
+	pop	{ r4-r9 }
+	bx	r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/v7a/cora15/bdiv_q_1.asm b/third_party/gmp/mpn/arm/v7a/cora15/bdiv_q_1.asm
new file mode 100644
index 0000000..245b371
--- /dev/null
+++ b/third_party/gmp/mpn/arm/v7a/cora15/bdiv_q_1.asm
@@ -0,0 +1,36 @@
+dnl  ARM mpn_bdiv_q_1, mpn_pi1_bdiv_q_1 -- Hensel division by 1-limb divisor.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2012, 2013, 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+MULFUNC_PROLOGUE(mpn_bdiv_q_1 mpn_pi1_bdiv_q_1)
+include_mpn(`arm/v7a/cora8/bdiv_q_1.asm')
diff --git a/third_party/gmp/mpn/arm/v7a/cora15/cnd_aors_n.asm b/third_party/gmp/mpn/arm/v7a/cora15/cnd_aors_n.asm
new file mode 100644
index 0000000..b9e5cd3
--- /dev/null
+++ b/third_party/gmp/mpn/arm/v7a/cora15/cnd_aors_n.asm
@@ -0,0 +1,158 @@
+dnl  ARM mpn_cnd_add_n/mpn_cnd_sub_n optimised for A15.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb		best
+C StrongARM:     -
+C XScale	 ?
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 3.75			 3
+C Cortex-A15	 1.78			this
+
+C This code does not run as well as one could have hoped, since 1.5 c/l seems
+C realistic for this insn mix.
+
+C Architecture requirements:
+C v5	-
+C v5t	-
+C v5te	ldrd strd
+C v6	-
+C v6t2	-
+C v7a	-
+
+define(`cnd',`r0')
+define(`rp', `r1')
+define(`up', `r2')
+define(`vp', `r3')
+define(`n',  `r12')
+
+ifdef(`OPERATION_cnd_add_n', `
+  define(`ADDSUB',	adds)
+  define(`ADDSUBC',	adcs)
+  define(`IFADD',	`$1')
+  define(`INITCY',      `cmn	r0, #0')
+  define(`RETVAL',	`adc	r0, n, #0')
+  define(`RETVAL2',	`adc	r0, n, #1')
+  define(`func',	mpn_cnd_add_n)
+  define(`func_nc',	mpn_add_nc)')
+ifdef(`OPERATION_cnd_sub_n', `
+  define(`ADDSUB',	subs)
+  define(`ADDSUBC',	sbcs)
+  define(`IFADD',	`')
+  define(`INITCY',      `cmp	r0, #0')
+  define(`RETVAL',	`sbc	r0, r0, r0
+			and	r0, r0, #1')
+  define(`RETVAL2',	`RETVAL')
+  define(`func',	mpn_cnd_sub_n)
+  define(`func_nc',	mpn_sub_nc)')
+
+MULFUNC_PROLOGUE(mpn_cnd_add_n mpn_cnd_sub_n)
+
+ASM_START()
+PROLOGUE(func)
+	ldr	n, [sp]
+	push	{ r4-r9 }
+
+	cmp	cnd, #1
+	sbc	cnd, cnd, cnd		C conditionally set to 0xffffffff
+
+	ands	r6, n, #3
+	mov	n, n, lsr #2
+	beq	L(b00)
+	cmp	r6, #2
+	bcc	L(b01)
+	beq	L(b10)
+
+L(b11):	ldr	r5, [up], #4
+	ldr	r7, [vp], #4
+	bic	r7, r7, cnd
+	ADDSUB	r9, r5, r7
+	ldrd	r4, r5, [up, #0]
+	ldrd	r6, r7, [vp, #0]
+	bic	r6, r6, cnd
+	bic	r7, r7, cnd
+	str	r9, [rp], #-4
+	b	L(lo)
+
+L(b00):	ldrd	r4, r5, [up], #-8
+	ldrd	r6, r7, [vp], #-8
+	bic	r6, r6, cnd
+	bic	r7, r7, cnd
+	INITCY
+	sub	rp, rp, #16
+	b	L(mid)
+
+L(b01):	ldr	r5, [up], #-4
+	ldr	r7, [vp], #-4
+	bic	r7, r7, cnd
+	ADDSUB	r9, r5, r7
+	str	r9, [rp], #-12
+	tst	n, n
+	beq	L(wd1)
+L(gt1):	ldrd	r4, r5, [up, #8]
+	ldrd	r6, r7, [vp, #8]
+	bic	r6, r6, cnd
+	bic	r7, r7, cnd
+	b	L(mid)
+
+L(b10):	ldrd	r4, r5, [up]
+	ldrd	r6, r7, [vp]
+	bic	r6, r6, cnd
+	bic	r7, r7, cnd
+	INITCY
+	sub	rp, rp, #8
+	b	L(lo)
+
+	ALIGN(16)
+L(top):	ldrd	r6, r7, [vp, #8]
+	ldrd	r4, r5, [up, #8]
+	bic	r6, r6, cnd
+	bic	r7, r7, cnd
+	strd	r8, r9, [rp, #8]
+L(mid):	ADDSUBC	r8, r4, r6
+	ADDSUBC	r9, r5, r7
+	ldrd	r6, r7, [vp, #16]!
+	ldrd	r4, r5, [up, #16]!
+	bic	r6, r6, cnd
+	bic	r7, r7, cnd
+	sub	n, n, #1
+	strd	r8, r9, [rp, #16]!
+L(lo):	ADDSUBC	r8, r4, r6
+	ADDSUBC	r9, r5, r7
+	tst	n, n
+	bne	L(top)
+
+L(end):	strd	r8, r9, [rp, #8]
+L(wd1):	RETVAL
+	pop	{ r4-r9 }
+	bx	r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/v7a/cora15/com.asm b/third_party/gmp/mpn/arm/v7a/cora15/com.asm
new file mode 100644
index 0000000..a258afe
--- /dev/null
+++ b/third_party/gmp/mpn/arm/v7a/cora15/com.asm
@@ -0,0 +1,180 @@
+dnl  ARM mpn_com optimised for A15.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C            cycles/limb
+C StrongARM	 ?
+C XScale	 ?
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	2.5
+C Cortex-A15	1.0
+
+C This is great A15 core register code, but it is a bit large.
+C We use FEEDIN_VARIANT 1 to save some space, but use 8-way unrolling.
+
+C Architecture requirements:
+C v5	-
+C v5t	-
+C v5te	ldrd strd
+C v6	-
+C v6t2	-
+C v7a	-
+
+define(`FEEDIN_VARIANT', 1)	C alternatives: 0 1 2
+define(`UNROLL', 4x2)		C alternatives: 4 4x2
+
+define(`rp', `r0')
+define(`up', `r1')
+define(`n',  `r2')
+
+ASM_START()
+PROLOGUE(mpn_com)
+	push	{ r4-r5,r8-r9 }
+
+ifelse(FEEDIN_VARIANT,0,`
+	ands	r12, n, #3
+	mov	n, n, lsr #2
+	beq	L(b00a)
+	tst	r12, #1
+	beq	L(bx0)
+	ldr	r5, [up], #4
+	mvn	r9, r5
+	str	r9, [rp], #4
+	tst	r12, #2
+	beq	L(b00)
+L(bx0):	ldrd	r4, r5, [up, #0]
+	sub	rp, rp, #8
+	b	L(lo)
+L(b00):	tst	n, n
+	beq	L(wd1)
+L(b00a):ldrd	r4, r5, [up], #-8
+	sub	rp, rp, #16
+	b	L(mid)
+')
+ifelse(FEEDIN_VARIANT,1,`
+	and	r12, n, #3
+	mov	n, n, lsr #2
+	tst	r12, #1
+	beq	L(bx0)
+	ldr	r5, [up], #4
+	mvn	r9, r5
+	str	r9, [rp], #4
+L(bx0):	tst	r12, #2
+	beq	L(b00)
+	ldrd	r4, r5, [up, #0]
+	sub	rp, rp, #8
+	b	L(lo)
+L(b00):	tst	n, n
+	beq	L(wd1)
+	ldrd	r4, r5, [up], #-8
+	sub	rp, rp, #16
+	b	L(mid)
+')
+ifelse(FEEDIN_VARIANT,2,`
+	ands	r12, n, #3
+	mov	n, n, lsr #2
+	beq	L(b00)
+	cmp	r12, #2
+	bcc	L(b01)
+	beq	L(b10)
+
+L(b11):	ldr	r5, [up], #4
+	mvn	r9, r5
+	ldrd	r4, r5, [up, #0]
+	str	r9, [rp], #-4
+	b	L(lo)
+
+L(b00):	ldrd	r4, r5, [up], #-8
+	sub	rp, rp, #16
+	b	L(mid)
+
+L(b01):	ldr	r5, [up], #-4
+	mvn	r9, r5
+	str	r9, [rp], #-12
+	tst	n, n
+	beq	L(wd1)
+L(gt1):	ldrd	r4, r5, [up, #8]
+	b	L(mid)
+
+L(b10):	ldrd	r4, r5, [up]
+	sub	rp, rp, #8
+	b	L(lo)
+')
+	ALIGN(16)
+ifelse(UNROLL,4,`
+L(top):	ldrd	r4, r5, [up, #8]
+	strd	r8, r9, [rp, #8]
+L(mid):	mvn	r8, r4
+	mvn	r9, r5
+	ldrd	r4, r5, [up, #16]!
+	strd	r8, r9, [rp, #16]!
+	sub	n, n, #1
+L(lo):	mvn	r8, r4
+	mvn	r9, r5
+	tst	n, n
+	bne	L(top)
+')
+ifelse(UNROLL,4x2,`
+L(top):	ldrd	r4, r5, [up, #8]
+	strd	r8, r9, [rp, #8]
+L(mid):	mvn	r8, r4
+	mvn	r9, r5
+	ldrd	r4, r5, [up, #16]
+	strd	r8, r9, [rp, #16]
+	mvn	r8, r4
+	mvn	r9, r5
+	sub	n, n, #2
+	tst	n, n
+	bmi	L(dne)
+	ldrd	r4, r5, [up, #24]
+	strd	r8, r9, [rp, #24]
+	mvn	r8, r4
+	mvn	r9, r5
+	ldrd	r4, r5, [up, #32]!
+	strd	r8, r9, [rp, #32]!
+L(lo):	mvn	r8, r4
+	mvn	r9, r5
+	tst	n, n
+	bne	L(top)
+')
+
+L(end):	strd	r8, r9, [rp, #8]
+L(wd1):	pop	{ r4-r5,r8-r9 }
+	bx	r14
+ifelse(UNROLL,4x2,`
+L(dne):	strd	r8, r9, [rp, #24]
+	pop	{ r4-r5,r8-r9 }
+	bx	r14
+')
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/v7a/cora15/gmp-mparam.h b/third_party/gmp/mpn/arm/v7a/cora15/gmp-mparam.h
new file mode 100644
index 0000000..409cbbb
--- /dev/null
+++ b/third_party/gmp/mpn/arm/v7a/cora15/gmp-mparam.h
@@ -0,0 +1,212 @@
+/* gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+/* 2000 MHz Cortex-A15 with Neon (in spite of file position) */
+/* FFT tuning limit = 50,736,668 */
+/* Generated by tuneup.c, 2019-10-22, gcc 5.4 */
+
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          3
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          2
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        10
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD     MP_SIZE_T_MAX
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD      8
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1N_PI1_METHOD                 1  /* 49.14% faster than 2 */
+#define DIV_QR_1_NORM_THRESHOLD          MP_SIZE_T_MAX  /* never */
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           17
+
+#define DIV_1_VS_MUL_1_PERCENT             267
+
+#define MUL_TOOM22_THRESHOLD                28
+#define MUL_TOOM33_THRESHOLD               114
+#define MUL_TOOM44_THRESHOLD               178
+#define MUL_TOOM6H_THRESHOLD               238
+#define MUL_TOOM8H_THRESHOLD               597
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD     113
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     115
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     115
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     115
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     154
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 38
+#define SQR_TOOM3_THRESHOLD                126
+#define SQR_TOOM4_THRESHOLD                336
+#define SQR_TOOM6_THRESHOLD                446
+#define SQR_TOOM8_THRESHOLD                650
+
+#define MULMID_TOOM42_THRESHOLD             52
+
+#define MULMOD_BNM1_THRESHOLD               23
+#define SQRMOD_BNM1_THRESHOLD               17
+
+#define MUL_FFT_MODF_THRESHOLD             575  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    575, 5}, {     25, 6}, {     13, 5}, {     27, 6}, \
+    {     27, 7}, {     15, 6}, {     31, 7}, {     19, 6}, \
+    {     39, 7}, {     25, 6}, {     51, 7}, {     27, 8}, \
+    {     15, 7}, {     33, 8}, {     19, 7}, {     41, 8}, \
+    {     23, 7}, {     51, 8}, {     27, 9}, {     15, 8}, \
+    {     31, 7}, {     63, 8}, {     39, 9}, {     23, 8}, \
+    {     55,10}, {     15, 9}, {     31, 8}, {     67, 9}, \
+    {     39, 8}, {     79, 9}, {     47, 8}, {     95, 9}, \
+    {     55,10}, {     31, 9}, {     71, 8}, {    143, 9}, \
+    {     87,10}, {     47, 9}, {    111,11}, {     31,10}, \
+    {     63, 9}, {    143,10}, {     79, 9}, {    159,10}, \
+    {     95,11}, {     63,10}, {    143, 9}, {    287,10}, \
+    {    159,11}, {     95,10}, {    191,12}, {     63,11}, \
+    {    127,10}, {    255, 9}, {    511,10}, {    271, 9}, \
+    {    543,10}, {    287,11}, {    159,10}, {    335, 9}, \
+    {    671,10}, {    367, 9}, {    735,11}, {    191,10}, \
+    {    383, 9}, {    799,10}, {    415,11}, {    223,12}, \
+    {    127,10}, {    543,11}, {    287,10}, {    575,11}, \
+    {    319,10}, {    639,11}, {    351,10}, {    703,12}, \
+    {    191,11}, {    383,10}, {    767,11}, {    415,10}, \
+    {    831,11}, {    447,13}, {    127,12}, {    255,11}, \
+    {    543,10}, {   1087,11}, {    575,12}, {    319,11}, \
+    {    671,10}, {   1343,11}, {    735,12}, {    383,11}, \
+    {    831,12}, {    447,11}, {    959,13}, {    255,12}, \
+    {    511,11}, {   1087,12}, {    575,11}, {   1151,12}, \
+    {    639,11}, {   1343,12}, {    703,13}, {    383,12}, \
+    {    767,11}, {   1599,12}, {    895,14}, {    255,13}, \
+    {    511,12}, {   1087,13}, {    639,12}, {   1407,13}, \
+    {    767,12}, {   1599,13}, {    895,14}, {    511,13}, \
+    {   1023,12}, {   2111,13}, {   1151,12}, {   2431,13}, \
+    {   1279,12}, {   2559,13}, {   1407,14}, {    767,13}, \
+    {   1535,12}, {   3135,13}, {   1663,15}, {    511,14}, \
+    {   1023,13}, {   2303,14}, {   1279,13}, {   2559,12}, \
+    {   5119,13}, {   2687,14}, {   1535,13}, {   3071,12}, \
+    {   6143,13}, {   3199,12}, {   6399,14}, {   1791,15}, \
+    {   1023,14}, {   2047,13}, {   4095,14}, {   2303,13}, \
+    {   4607,12}, {   9215,13}, {   4863,12}, {   9727,14}, \
+    {   2559,13}, {   5119,15}, {   1535,14}, {   3071,13}, \
+    {   8192,14}, {  16384,15}, {  32768,16} }
+#define MUL_FFT_TABLE3_SIZE 155
+#define MUL_FFT_THRESHOLD                 5760
+
+#define SQR_FFT_MODF_THRESHOLD             525  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    525, 5}, {     25, 6}, {     27, 7}, {     15, 6}, \
+    {     31, 7}, {     17, 6}, {     35, 7}, {     19, 6}, \
+    {     39, 7}, {     25, 6}, {     51, 7}, {     27, 8}, \
+    {     15, 7}, {     33, 8}, {     19, 7}, {     41, 8}, \
+    {     23, 7}, {     51, 8}, {     27, 7}, {     55, 9}, \
+    {     15, 8}, {     31, 7}, {     63, 8}, {     39, 9}, \
+    {     23, 8}, {     51,10}, {     15, 9}, {     31, 8}, \
+    {     67, 9}, {     39, 8}, {     79, 9}, {     47, 8}, \
+    {     99, 9}, {     55,10}, {     31, 9}, {     79,10}, \
+    {     47, 9}, {     95,11}, {     31,10}, {     63, 9}, \
+    {    135,10}, {     95,11}, {     63,10}, {    143, 9}, \
+    {    287, 8}, {    575, 9}, {    303,10}, {    159,11}, \
+    {     95,10}, {    191, 9}, {    383,12}, {     63,11}, \
+    {    127,10}, {    255, 9}, {    511,10}, {    271, 9}, \
+    {    543,10}, {    287,11}, {    159,10}, {    319, 9}, \
+    {    639,10}, {    335, 9}, {    671,10}, {    351,11}, \
+    {    191,10}, {    399, 9}, {    799,10}, {    415, 9}, \
+    {    831,11}, {    223,10}, {    447,12}, {    127,10}, \
+    {    543,11}, {    287,10}, {    575,11}, {    319,10}, \
+    {    639,11}, {    351,10}, {    703,12}, {    191,11}, \
+    {    383,10}, {    799,11}, {    415,10}, {    831,11}, \
+    {    447,13}, {    127,11}, {    543,10}, {   1087,11}, \
+    {    607,12}, {    319,11}, {    735,12}, {    383,11}, \
+    {    831,12}, {    447,11}, {    959,12}, {    511,11}, \
+    {   1023,12}, {    575,11}, {   1151,12}, {    639,11}, \
+    {   1279,12}, {    703,13}, {    383,12}, {    767,11}, \
+    {   1535,12}, {    831,11}, {   1663,12}, {    895,14}, \
+    {    255,13}, {    511,12}, {   1087,13}, {    639,12}, \
+    {   1343,13}, {    767,12}, {   1599,13}, {    895,14}, \
+    {    511,13}, {   1023,12}, {   2111,13}, {   1151,12}, \
+    {   2303,13}, {   1279,14}, {    767,13}, {   1535,12}, \
+    {   3135,13}, {   1663,15}, {    511,14}, {   1023,13}, \
+    {   2047,12}, {   4095,13}, {   2303,14}, {   1279,13}, \
+    {   2559,12}, {   5119,14}, {   1535,13}, {   3071,12}, \
+    {   6143,13}, {   3199,12}, {   6399,14}, {   1791,15}, \
+    {   1023,14}, {   2047,13}, {   4095,14}, {   2303,13}, \
+    {   4607,12}, {   9215,13}, {   4863,12}, {   9727,14}, \
+    {   2559,15}, {   1535,14}, {   3071,13}, {   8192,14}, \
+    {  16384,15}, {  32768,16} }
+#define SQR_FFT_TABLE3_SIZE 154
+#define SQR_FFT_THRESHOLD                 5312
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  38
+#define MULLO_MUL_N_THRESHOLD            10950
+#define SQRLO_BASECASE_THRESHOLD            10
+#define SQRLO_DC_THRESHOLD                  35
+#define SQRLO_SQR_THRESHOLD              10323
+
+#define DC_DIV_QR_THRESHOLD                 57
+#define DC_DIVAPPR_Q_THRESHOLD             254
+#define DC_BDIV_QR_THRESHOLD                48
+#define DC_BDIV_Q_THRESHOLD                286
+
+#define INV_MULMOD_BNM1_THRESHOLD           55
+#define INV_NEWTON_THRESHOLD               252
+#define INV_APPR_THRESHOLD                 252
+
+#define BINV_NEWTON_THRESHOLD              372
+#define REDC_1_TO_REDC_2_THRESHOLD          61
+#define REDC_2_TO_REDC_N_THRESHOLD           0  /* always */
+
+#define MU_DIV_QR_THRESHOLD               1858
+#define MU_DIVAPPR_Q_THRESHOLD            1787
+#define MUPI_DIV_QR_THRESHOLD              122
+#define MU_BDIV_QR_THRESHOLD              1528
+#define MU_BDIV_Q_THRESHOLD               1836
+
+#define POWM_SEC_TABLE  1,14,200,480,1532
+
+#define GET_STR_DC_THRESHOLD                16
+#define GET_STR_PRECOMPUTE_THRESHOLD        33
+#define SET_STR_DC_THRESHOLD               104
+#define SET_STR_PRECOMPUTE_THRESHOLD      1120
+
+#define FAC_DSC_THRESHOLD                  164
+#define FAC_ODD_THRESHOLD                   27
+
+#define MATRIX22_STRASSEN_THRESHOLD         19
+#define HGCD2_DIV1_METHOD                    1  /* 3.70% faster than 3 */
+#define HGCD_THRESHOLD                     137
+#define HGCD_APPR_THRESHOLD                157
+#define HGCD_REDUCE_THRESHOLD             3389
+#define GCD_DC_THRESHOLD                   610
+#define GCDEXT_DC_THRESHOLD                443
+#define JACOBI_BASE_METHOD                   4  /* 12.66% faster than 1 */
+
+/* Tuneup completed successfully, took 69757 seconds */
diff --git a/third_party/gmp/mpn/arm/v7a/cora15/logops_n.asm b/third_party/gmp/mpn/arm/v7a/cora15/logops_n.asm
new file mode 100644
index 0000000..0602614
--- /dev/null
+++ b/third_party/gmp/mpn/arm/v7a/cora15/logops_n.asm
@@ -0,0 +1,253 @@
+dnl  ARM mpn_and_n, mpn_andn_n. mpn_nand_n, etc, optimised for A15.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C            cycles/limb             cycles/limb
+C          and andn ior xor         nand iorn nior xnor
+C StrongARM	 ?			 ?
+C XScale	 ?			 ?
+C Cortex-A7	 ?			 ?
+C Cortex-A8	 ?			 ?
+C Cortex-A9	3.5			3.56
+C Cortex-A15	1.27			1.64
+
+C This is great A15 core register code, but it is a bit large.
+C We use FEEDIN_VARIANT 1 to save some space, but use 8-way unrolling.
+
+C Architecture requirements:
+C v5	-
+C v5t	-
+C v5te	ldrd strd
+C v6	-
+C v6t2	-
+C v7a	-
+
+define(`FEEDIN_VARIANT', 1)	C alternatives: 0 1 2
+define(`UNROLL', 4x2)		C alternatives: 4 4x2
+
+define(`rp', `r0')
+define(`up', `r1')
+define(`vp', `r2')
+define(`n',  `r3')
+
+define(`POSTOP')
+
+ifdef(`OPERATION_and_n',`
+  define(`func',    `mpn_and_n')
+  define(`LOGOP',   `and	$1, $2, $3')')
+ifdef(`OPERATION_andn_n',`
+  define(`func',    `mpn_andn_n')
+  define(`LOGOP',   `bic	$1, $2, $3')')
+ifdef(`OPERATION_nand_n',`
+  define(`func',    `mpn_nand_n')
+  define(`POSTOP',  `mvn	$1, $1')
+  define(`LOGOP',   `and	$1, $2, $3')')
+ifdef(`OPERATION_ior_n',`
+  define(`func',    `mpn_ior_n')
+  define(`LOGOP',   `orr	$1, $2, $3')')
+ifdef(`OPERATION_iorn_n',`
+  define(`func',    `mpn_iorn_n')
+  define(`POSTOP',  `mvn	$1, $1')
+  define(`LOGOP',   `bic	$1, $3, $2')')
+ifdef(`OPERATION_nior_n',`
+  define(`func',    `mpn_nior_n')
+  define(`POSTOP',  `mvn	$1, $1')
+  define(`LOGOP',   `orr	$1, $2, $3')')
+ifdef(`OPERATION_xor_n',`
+  define(`func',    `mpn_xor_n')
+  define(`LOGOP',   `eor	$1, $2, $3')')
+ifdef(`OPERATION_xnor_n',`
+  define(`func',    `mpn_xnor_n')
+  define(`POSTOP',  `mvn	$1, $1')
+  define(`LOGOP',   `eor	$1, $2, $3')')
+
+MULFUNC_PROLOGUE(mpn_and_n mpn_andn_n mpn_nand_n mpn_ior_n mpn_iorn_n mpn_nior_n mpn_xor_n mpn_xnor_n)
+
+ASM_START()
+PROLOGUE(func)
+	push	{ r4-r9 }
+
+ifelse(FEEDIN_VARIANT,0,`
+	ands	r6, n, #3
+	mov	n, n, lsr #2
+	beq	L(b00a)
+	tst	r6, #1
+	beq	L(bx0)
+	ldr	r5, [up], #4
+	ldr	r7, [vp], #4
+	LOGOP(	r9, r5, r7)
+	POSTOP(	r9)
+	str	r9, [rp], #4
+	tst	r6, #2
+	beq	L(b00)
+L(bx0):	ldrd	r4, r5, [up, #0]
+	ldrd	r6, r7, [vp, #0]
+	sub	rp, rp, #8
+	b	L(lo)
+L(b00):	tst	n, n
+	beq	L(wd1)
+L(b00a):ldrd	r4, r5, [up], #-8
+	ldrd	r6, r7, [vp], #-8
+	sub	rp, rp, #16
+	b	L(mid)
+')
+ifelse(FEEDIN_VARIANT,1,`
+	and	r6, n, #3
+	mov	n, n, lsr #2
+	tst	r6, #1
+	beq	L(bx0)
+	ldr	r5, [up], #4
+	ldr	r7, [vp], #4
+	LOGOP(	r9, r5, r7)
+	POSTOP(	r9)
+	str	r9, [rp], #4
+L(bx0):	tst	r6, #2
+	beq	L(b00)
+	ldrd	r4, r5, [up, #0]
+	ldrd	r6, r7, [vp, #0]
+	sub	rp, rp, #8
+	b	L(lo)
+L(b00):	tst	n, n
+	beq	L(wd1)
+	ldrd	r4, r5, [up], #-8
+	ldrd	r6, r7, [vp], #-8
+	sub	rp, rp, #16
+	b	L(mid)
+')
+ifelse(FEEDIN_VARIANT,2,`
+	ands	r6, n, #3
+	mov	n, n, lsr #2
+	beq	L(b00)
+	cmp	r6, #2
+	bcc	L(b01)
+	beq	L(b10)
+
+L(b11):	ldr	r5, [up], #4
+	ldr	r7, [vp], #4
+	LOGOP(	r9, r5, r7)
+	ldrd	r4, r5, [up, #0]
+	ldrd	r6, r7, [vp, #0]
+	POSTOP(	r9)
+	str	r9, [rp], #-4
+	b	L(lo)
+
+L(b00):	ldrd	r4, r5, [up], #-8
+	ldrd	r6, r7, [vp], #-8
+	sub	rp, rp, #16
+	b	L(mid)
+
+L(b01):	ldr	r5, [up], #-4
+	ldr	r7, [vp], #-4
+	LOGOP(	r9, r5, r7)
+	POSTOP(	r9)
+	str	r9, [rp], #-12
+	tst	n, n
+	beq	L(wd1)
+L(gt1):	ldrd	r4, r5, [up, #8]
+	ldrd	r6, r7, [vp, #8]
+	b	L(mid)
+
+L(b10):	ldrd	r4, r5, [up]
+	ldrd	r6, r7, [vp]
+	sub	rp, rp, #8
+	b	L(lo)
+')
+	ALIGN(16)
+ifelse(UNROLL,4,`
+L(top):	ldrd	r4, r5, [up, #8]
+	ldrd	r6, r7, [vp, #8]
+	POSTOP(	r8)
+	POSTOP(	r9)
+	strd	r8, r9, [rp, #8]
+L(mid):	LOGOP(	r8, r4, r6)
+	LOGOP(	r9, r5, r7)
+	ldrd	r4, r5, [up, #16]!
+	ldrd	r6, r7, [vp, #16]!
+	POSTOP(	r8)
+	POSTOP(	r9)
+	strd	r8, r9, [rp, #16]!
+	sub	n, n, #1
+L(lo):	LOGOP(	r8, r4, r6)
+	LOGOP(	r9, r5, r7)
+	tst	n, n
+	bne	L(top)
+')
+ifelse(UNROLL,4x2,`
+L(top):	ldrd	r4, r5, [up, #8]
+	ldrd	r6, r7, [vp, #8]
+	POSTOP(	r8)
+	POSTOP(	r9)
+	strd	r8, r9, [rp, #8]
+L(mid):	LOGOP(	r8, r4, r6)
+	LOGOP(	r9, r5, r7)
+	ldrd	r4, r5, [up, #16]
+	ldrd	r6, r7, [vp, #16]
+	POSTOP(	r8)
+	POSTOP(	r9)
+	strd	r8, r9, [rp, #16]
+	LOGOP(	r8, r4, r6)
+	LOGOP(	r9, r5, r7)
+	sub	n, n, #2
+	tst	n, n
+	bmi	L(dne)
+	ldrd	r4, r5, [up, #24]
+	ldrd	r6, r7, [vp, #24]
+	POSTOP(	r8)
+	POSTOP(	r9)
+	strd	r8, r9, [rp, #24]
+	LOGOP(	r8, r4, r6)
+	LOGOP(	r9, r5, r7)
+	ldrd	r4, r5, [up, #32]!
+	ldrd	r6, r7, [vp, #32]!
+	POSTOP(	r8)
+	POSTOP(	r9)
+	strd	r8, r9, [rp, #32]!
+L(lo):	LOGOP(	r8, r4, r6)
+	LOGOP(	r9, r5, r7)
+	tst	n, n
+	bne	L(top)
+')
+
+L(end):	POSTOP(	r8)
+	POSTOP(	r9)
+	strd	r8, r9, [rp, #8]
+L(wd1):	pop	{ r4-r9 }
+	bx	r14
+ifelse(UNROLL,4x2,`
+L(dne):	POSTOP(	r8)
+	POSTOP(	r9)
+	strd	r8, r9, [rp, #24]
+	pop	{ r4-r9 }
+	bx	r14
+')
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/v7a/cora15/mul_1.asm b/third_party/gmp/mpn/arm/v7a/cora15/mul_1.asm
new file mode 100644
index 0000000..766ba5c
--- /dev/null
+++ b/third_party/gmp/mpn/arm/v7a/cora15/mul_1.asm
@@ -0,0 +1,104 @@
+dnl  ARM mpn_mul_1 optimised for A15.
+
+dnl  Copyright 2012, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb		best
+C StrongARM:	 -
+C XScale	 ?
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 5.25			3.25
+C Cortex-A15	 2.25			this
+
+
+C This runs well on A15 but very poorly on A9.  By scheduling loads and adds
+C it is possible to get good A9 performance as well, but at the cost of using
+C many more (callee-saves) registers.
+
+C This is armv5 code, optimized for the armv7a cpu A15.  Its location in the
+C GMP file structure might be misleading.
+
+
+define(`rp', `r0')
+define(`up', `r1')
+define(`n',  `r2')
+define(`v0', `r3')
+
+ASM_START()
+PROLOGUE(mpn_mul_1c)
+	ldr	r12, [sp]
+	b	L(ent)
+EPILOGUE()
+PROLOGUE(mpn_mul_1)
+	mov	r12, #0
+L(ent):	push	{r4-r7}
+
+	ldr	r6, [up], #4
+	tst	n, #1
+	beq	L(bx0)
+
+L(bx1):	umull	r4, r7, r6, v0
+	adds	r4, r4, r12
+	tst	n, #2
+	beq	L(lo1)
+	b	L(lo3)
+
+L(bx0):	umull	r4, r5, r6, v0
+	adds	r4, r4, r12
+	tst	n, #2
+	beq	L(lo0)
+	b	L(lo2)
+
+L(top):	ldr	r6, [up], #4
+	str	r4, [rp], #4
+	umull	r4, r5, r6, v0
+	adds	r4, r4, r7
+L(lo0):	ldr	r6, [up], #4
+	str	r4, [rp], #4
+	umull	r4, r7, r6, v0
+	adcs	r4, r4, r5
+L(lo3):	ldr	r6, [up], #4
+	str	r4, [rp], #4
+	umull	r4, r5, r6, v0
+	adcs	r4, r4, r7
+L(lo2):	ldr	r6, [up], #4
+	str	r4, [rp], #4
+	umull	r4, r7, r6, v0
+	adcs	r4, r4, r5
+L(lo1):	adc	r7, r7, #0
+	subs	n, n, #4
+	bgt	L(top)
+
+	str	r4, [rp]
+	mov	r0, r7
+	pop	{r4-r7}
+	bx	lr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/v7a/cora15/neon/aorsorrlsh1_n.asm b/third_party/gmp/mpn/arm/v7a/cora15/neon/aorsorrlsh1_n.asm
new file mode 100644
index 0000000..d8cfe3f
--- /dev/null
+++ b/third_party/gmp/mpn/arm/v7a/cora15/neon/aorsorrlsh1_n.asm
@@ -0,0 +1,43 @@
+dnl  ARM mpn_addlshC_n, mpn_sublshC_n, mpn_rsblshC_n
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+define(LSH,		1)
+
+ifdef(`OPERATION_addlsh1_n',`define(`DO_add')')
+ifdef(`OPERATION_sublsh1_n',`define(`DO_sub')')
+ifdef(`OPERATION_rsblsh1_n',`define(`DO_rsb')')
+
+MULFUNC_PROLOGUE(mpn_addlsh1_n mpn_sublsh1_n mpn_rsblsh1_n)
+
+include_mpn(`arm/v7a/cora15/neon/aorsorrlshC_n.asm')
diff --git a/third_party/gmp/mpn/arm/v7a/cora15/neon/aorsorrlsh2_n.asm b/third_party/gmp/mpn/arm/v7a/cora15/neon/aorsorrlsh2_n.asm
new file mode 100644
index 0000000..b48204d
--- /dev/null
+++ b/third_party/gmp/mpn/arm/v7a/cora15/neon/aorsorrlsh2_n.asm
@@ -0,0 +1,43 @@
+dnl  ARM mpn_addlshC_n, mpn_sublshC_n, mpn_rsblshC_n
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+define(LSH,		2)
+
+ifdef(`OPERATION_addlsh2_n',`define(`DO_add')')
+ifdef(`OPERATION_sublsh2_n',`define(`DO_sub')')
+ifdef(`OPERATION_rsblsh2_n',`define(`DO_rsb')')
+
+MULFUNC_PROLOGUE(mpn_addlsh2_n mpn_sublsh2_n mpn_rsblsh2_n)
+
+include_mpn(`arm/v7a/cora15/neon/aorsorrlshC_n.asm')
diff --git a/third_party/gmp/mpn/arm/v7a/cora15/neon/aorsorrlshC_n.asm b/third_party/gmp/mpn/arm/v7a/cora15/neon/aorsorrlshC_n.asm
new file mode 100644
index 0000000..51f93c1
--- /dev/null
+++ b/third_party/gmp/mpn/arm/v7a/cora15/neon/aorsorrlshC_n.asm
@@ -0,0 +1,144 @@
+dnl  ARM mpn_addlshC_n, mpn_sublshC_n, mpn_rsblshC_n
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+C	     cycles/limb
+C StrongARM	 -
+C XScale	 -
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 5.25
+C Cortex-A15	 2.25
+
+C TODO
+C  * Consider using 4-way feed-in code.
+C  * This is ad-hoc scheduled, perhaps unnecessarily so for A15, and perhaps
+C    insufficiently for A7 and A8.
+
+define(`rp', `r0')
+define(`up', `r1')
+define(`vp', `r2')
+define(`n',  `r3')
+
+ifdef(`DO_add', `
+  define(`ADCSBCS',	`adcs	$1, $2, $3')
+  define(`CLRCY',	`cmn	r13, #1')
+  define(`RETVAL',	`adc	r0, $1, #0')
+  define(`func',	mpn_addlsh`'LSH`'_n)')
+ifdef(`DO_sub', `
+  define(`ADCSBCS',	`sbcs	$1, $2, $3')
+  define(`CLRCY',	`cmp	r13, #0')
+  define(`RETVAL',	`sbc	$2, $2, $2
+			cmn	$2, #1
+			adc	r0, $1, #0')
+  define(`func',	mpn_sublsh`'LSH`'_n)')
+ifdef(`DO_rsb', `
+  define(`ADCSBCS',	`sbcs	$1, $3, $2')
+  define(`CLRCY',	`cmp	r13, #0')
+  define(`RETVAL',	`sbc	r0, $1, #0')
+  define(`func',	mpn_rsblsh`'LSH`'_n)')
+
+
+ASM_START()
+PROLOGUE(func)
+	push	 {r4-r10}
+	vmov.i8	 d0, #0			C could feed carry through here
+	CLRCY
+	tst	n, #1
+	beq	L(bb0)
+
+L(bb1):	vld1.32	 {d3[0]}, [vp]!
+	vsli.u32 d0, d3, #LSH
+	ldr	 r12, [up], #4
+	vmov.32	 r5, d0[0]
+	vshr.u32 d0, d3, #32-LSH
+	ADCSBCS( r12, r12, r5)
+	str	 r12, [rp], #4
+	bics	 n, n, #1
+	beq	 L(rtn)
+
+L(bb0):	tst	n, #2
+	beq	L(b00)
+
+L(b10):	vld1.32	 {d3}, [vp]!
+	vsli.u64 d0, d3, #LSH
+	ldmia	 up!, {r10,r12}
+	vmov	 r4, r5, d0
+	vshr.u64 d0, d3, #64-LSH
+	ADCSBCS( r10, r10, r4)
+	ADCSBCS( r12, r12, r5)
+	stmia	 rp!, {r10,r12}
+	bics	 n, n, #2
+	beq	 L(rtn)
+
+L(b00):	vld1.32	 {d2}, [vp]!
+	vsli.u64 d0, d2, #LSH
+	vshr.u64 d1, d2, #64-LSH
+	vld1.32	 {d3}, [vp]!
+	vsli.u64 d1, d3, #LSH
+	vmov	 r6, r7, d0
+	vshr.u64 d0, d3, #64-LSH
+	sub	 n, n, #4
+	tst	 n, n
+	beq	 L(end)
+
+	ALIGN(16)
+L(top):	ldmia	 up!, {r8,r9,r10,r12}
+	vld1.32	 {d2}, [vp]!
+	vsli.u64 d0, d2, #LSH
+	vmov	 r4, r5, d1
+	vshr.u64 d1, d2, #64-LSH
+	ADCSBCS( r8, r8, r6)
+	ADCSBCS( r9, r9, r7)
+	vld1.32	 {d3}, [vp]!
+	vsli.u64 d1, d3, #LSH
+	vmov	 r6, r7, d0
+	vshr.u64 d0, d3, #64-LSH
+	ADCSBCS( r10, r10, r4)
+	ADCSBCS( r12, r12, r5)
+	stmia	 rp!, {r8,r9,r10,r12}
+	sub	 n, n, #4
+	tst	 n, n
+	bne	 L(top)
+
+L(end):	ldmia	 up!, {r8,r9,r10,r12}
+	vmov	 r4, r5, d1
+	ADCSBCS( r8, r8, r6)
+	ADCSBCS( r9, r9, r7)
+	ADCSBCS( r10, r10, r4)
+	ADCSBCS( r12, r12, r5)
+	stmia	 rp!, {r8,r9,r10,r12}
+L(rtn):	vmov.32	 r0, d0[0]
+	RETVAL(	 r0, r1)
+	pop	 {r4-r10}
+	bx	 r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/v7a/cora15/neon/com.asm b/third_party/gmp/mpn/arm/v7a/cora15/neon/com.asm
new file mode 100644
index 0000000..9e7a629
--- /dev/null
+++ b/third_party/gmp/mpn/arm/v7a/cora15/neon/com.asm
@@ -0,0 +1,97 @@
+dnl  ARM Neon mpn_com optimised for A15.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C            cycles/limb
+C StrongARM	 ?
+C XScale	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 2.1
+C Cortex-A15	 0.65
+
+define(`rp', `r0')
+define(`up', `r1')
+define(`n',  `r2')
+
+ASM_START()
+PROLOGUE(mpn_com)
+	cmp		n, #7
+	ble		L(bc)
+
+C Perform a few initial operation until rp is 128-bit aligned
+	tst		rp, #4
+	beq		L(al1)
+	vld1.32		{d0[0]}, [up]!
+	sub		n, n, #1
+	vmvn		d0, d0
+	vst1.32		{d0[0]}, [rp]!
+L(al1):	tst		rp, #8
+	beq		L(al2)
+	vld1.32		{d0}, [up]!
+	sub		n, n, #2
+	vmvn		d0, d0
+	vst1.32		{d0}, [rp:64]!
+L(al2):	vld1.32		{q2}, [up]!
+	subs		n, n, #12
+	blt		L(end)
+
+	ALIGN(16)
+L(top):	vld1.32		{q0}, [up]!
+	vmvn		q2, q2
+	subs		n, n, #8
+	vst1.32		{q2}, [rp:128]!
+	vld1.32		{q2}, [up]!
+	vmvn		q0, q0
+	vst1.32		{q0}, [rp:128]!
+	bge	L(top)
+
+L(end):	vmvn		q2, q2
+	vst1.32		{q2}, [rp:128]!
+
+C Handle last 0-7 limbs.  Note that rp is aligned after loop, but not when we
+C arrive here via L(bc)
+L(bc):	tst		n, #4
+	beq		L(tl1)
+	vld1.32		{q0}, [up]!
+	vmvn		q0, q0
+	vst1.32		{q0}, [rp]!
+L(tl1):	tst		n, #2
+	beq		L(tl2)
+	vld1.32		{d0}, [up]!
+	vmvn		d0, d0
+	vst1.32		{d0}, [rp]!
+L(tl2):	tst		n, #1
+	beq		L(tl3)
+	vld1.32		{d0[0]}, [up]
+	vmvn		d0, d0
+	vst1.32		{d0[0]}, [rp]
+L(tl3):	bx		lr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/v7a/cora15/neon/copyd.asm b/third_party/gmp/mpn/arm/v7a/cora15/neon/copyd.asm
new file mode 100644
index 0000000..98fe535
--- /dev/null
+++ b/third_party/gmp/mpn/arm/v7a/cora15/neon/copyd.asm
@@ -0,0 +1,110 @@
+dnl  ARM Neon mpn_copyd optimised for A15.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C StrongARM	 -
+C XScale	 -
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 1.75		slower than core register code
+C Cortex-A15	 0.52
+
+define(`rp', `r0')
+define(`up', `r1')
+define(`n',  `r2')
+
+ASM_START()
+PROLOGUE(mpn_copyd)
+	add	rp, rp, n, lsl #2
+	add	up, up, n, lsl #2
+
+	cmp	n, #7
+	ble	L(bc)
+
+C Copy until rp is 128-bit aligned
+	tst	rp, #4
+	beq	L(al1)
+	sub	up, up, #4
+	vld1.32	{d22[0]}, [up]
+	sub	n, n, #1
+	sub	rp, rp, #4
+	vst1.32	{d22[0]}, [rp]
+L(al1):	tst	rp, #8
+	beq	L(al2)
+	sub	up, up, #8
+	vld1.32	{d22}, [up]
+	sub	n, n, #2
+	sub	rp, rp, #8
+	vst1.32	{d22}, [rp:64]
+L(al2):	sub	up, up, #16
+	vld1.32	{d26-d27}, [up]
+	subs	n, n, #12
+	sub	rp, rp, #16			C offset rp for loop
+	blt	L(end)
+
+	sub	up, up, #16			C offset up for loop
+	mov	r12, #-16
+
+	ALIGN(16)
+L(top):	vld1.32	{d22-d23}, [up], r12
+	vst1.32	{d26-d27}, [rp:128], r12
+	vld1.32	{d26-d27}, [up], r12
+	vst1.32	{d22-d23}, [rp:128], r12
+	subs	n, n, #8
+	bge	L(top)
+
+	add	up, up, #16			C undo up offset
+						C rp offset undoing folded
+L(end):	vst1.32	{d26-d27}, [rp:128]
+
+C Copy last 0-7 limbs.  Note that rp is aligned after loop, but not when we
+C arrive here via L(bc)
+L(bc):	tst	n, #4
+	beq	L(tl1)
+	sub	up, up, #16
+	vld1.32	{d22-d23}, [up]
+	sub	rp, rp, #16
+	vst1.32	{d22-d23}, [rp]
+L(tl1):	tst	n, #2
+	beq	L(tl2)
+	sub	up, up, #8
+	vld1.32	{d22}, [up]
+	sub	rp, rp, #8
+	vst1.32	{d22}, [rp]
+L(tl2):	tst	n, #1
+	beq	L(tl3)
+	sub	up, up, #4
+	vld1.32	{d22[0]}, [up]
+	sub	rp, rp, #4
+	vst1.32	{d22[0]}, [rp]
+L(tl3):	bx	lr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/v7a/cora15/neon/copyi.asm b/third_party/gmp/mpn/arm/v7a/cora15/neon/copyi.asm
new file mode 100644
index 0000000..2e05afe
--- /dev/null
+++ b/third_party/gmp/mpn/arm/v7a/cora15/neon/copyi.asm
@@ -0,0 +1,90 @@
+dnl  ARM Neon mpn_copyi optimised for A15.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C StrongARM	 -
+C XScale	 -
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 1.75		slower than core register code
+C Cortex-A15	 0.52
+
+define(`rp', `r0')
+define(`up', `r1')
+define(`n',  `r2')
+
+ASM_START()
+PROLOGUE(mpn_copyi)
+	cmp	n, #7
+	ble	L(bc)
+
+C Copy until rp is 128-bit aligned
+	tst	rp, #4
+	beq	L(al1)
+	vld1.32	{d22[0]}, [up]!
+	sub	n, n, #1
+	vst1.32	{d22[0]}, [rp]!
+L(al1):	tst	rp, #8
+	beq	L(al2)
+	vld1.32	{d22}, [up]!
+	sub	n, n, #2
+	vst1.32	{d22}, [rp:64]!
+L(al2):	vld1.32	{d26-d27}, [up]!
+	subs	n, n, #12
+	blt	L(end)
+
+	ALIGN(16)
+L(top):	vld1.32	{d22-d23}, [up]!
+	vst1.32	{d26-d27}, [rp:128]!
+	vld1.32	{d26-d27}, [up]!
+	vst1.32	{d22-d23}, [rp:128]!
+	subs	n, n, #8
+	bge	L(top)
+
+L(end):	vst1.32	{d26-d27}, [rp:128]!
+
+C Copy last 0-7 limbs.  Note that rp is aligned after loop, but not when we
+C arrive here via L(bc)
+L(bc):	tst	n, #4
+	beq	L(tl1)
+	vld1.32	{d22-d23}, [up]!
+	vst1.32	{d22-d23}, [rp]!
+L(tl1):	tst	n, #2
+	beq	L(tl2)
+	vld1.32	{d22}, [up]!
+	vst1.32	{d22}, [rp]!
+L(tl2):	tst	n, #1
+	beq	L(tl3)
+	vld1.32	{d22[0]}, [up]
+	vst1.32	{d22[0]}, [rp]
+L(tl3):	bx	lr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/v7a/cora15/neon/rsh1aors_n.asm b/third_party/gmp/mpn/arm/v7a/cora15/neon/rsh1aors_n.asm
new file mode 100644
index 0000000..2c11d6d
--- /dev/null
+++ b/third_party/gmp/mpn/arm/v7a/cora15/neon/rsh1aors_n.asm
@@ -0,0 +1,177 @@
+dnl  ARM Neon mpn_rsh1add_n, mpn_rsh1sub_n.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C StrongARM	 -
+C XScale	 -
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	4-5
+C Cortex-A15	 2.5
+
+C TODO
+C  * Try to make this smaller, its size (384 bytes) is excessive.
+C  * Try to reach 2.25 c/l on A15, to match the addlsh_1 family.
+C  * This is ad-hoc scheduled, perhaps unnecessarily so for A15, and perhaps
+C    insufficiently for A7 and A8.
+
+define(`rp', `r0')
+define(`up', `r1')
+define(`vp', `r2')
+define(`n',  `r3')
+
+ifdef(`OPERATION_rsh1add_n', `
+  define(`ADDSUBS',	`adds	$1, $2, $3')
+  define(`ADCSBCS',	`adcs	$1, $2, $3')
+  define(`IFADD',	`$1')
+  define(`IFSUB',	`')
+  define(`func',	mpn_rsh1add_n)')
+ifdef(`OPERATION_rsh1sub_n', `
+  define(`ADDSUBS',	`subs	$1, $2, $3')
+  define(`ADCSBCS',	`sbcs	$1, $2, $3')
+  define(`IFADD',	`')
+  define(`IFSUB',	`$1')
+  define(`func',	mpn_rsh1sub_n)')
+
+MULFUNC_PROLOGUE(mpn_rsh1add_n mpn_rsh1sub_n)
+
+ASM_START()
+PROLOGUE(func)
+	push	 {r4-r10}
+
+	ands	r4, n, #3
+	beq	L(b00)
+	cmp	r4, #2
+	blo	L(b01)
+	beq	L(b10)
+
+L(b11):	ldmia	 up!, {r9,r10,r12}
+	ldmia	 vp!, {r5,r6,r7}
+	ADDSUBS( r9, r9, r5)
+	vmov	 d4, r9, r9
+	ADCSBCS( r10, r10, r6)
+	ADCSBCS( r12, r12, r7)
+	vshr.u64 d3, d4, #1
+	vmov	 d1, r10, r12
+	vsli.u64 d3, d1, #31
+	vshr.u64 d2, d1, #1
+	vst1.32	 d3[0], [rp]!
+	bics	 n, n, #3
+	beq	 L(wd2)
+L(gt3):	ldmia	 up!, {r8,r9,r10,r12}
+	ldmia	 vp!, {r4,r5,r6,r7}
+	b	 L(mi0)
+
+L(b10):	ldmia	 up!, {r10,r12}
+	ldmia	 vp!, {r6,r7}
+	ADDSUBS( r10, r10, r6)
+	ADCSBCS( r12, r12, r7)
+	vmov	 d4, r10, r12
+	bics	 n, n, #2
+	vshr.u64 d2, d4, #1
+	beq	 L(wd2)
+L(gt2):	ldmia	 up!, {r8,r9,r10,r12}
+	ldmia	 vp!, {r4,r5,r6,r7}
+	b	 L(mi0)
+
+L(b01):	ldr	 r12, [up], #4
+	ldr	 r7, [vp], #4
+	ADDSUBS( r12, r12, r7)
+	vmov	 d4, r12, r12
+	bics	 n, n, #1
+	bne	 L(gt1)
+	mov	 r5, r12, lsr #1
+IFADD(`	adc	 r1, n, #0')
+IFSUB(`	adc	 r1, n, #1')
+	bfi	 r5, r1, #31, #1
+	str	 r5, [rp]
+	and	 r0, r12, #1
+	pop	 {r4-r10}
+	bx	 r14
+L(gt1):	ldmia	 up!, {r8,r9,r10,r12}
+	ldmia	 vp!, {r4,r5,r6,r7}
+	vshr.u64 d2, d4, #1
+	ADCSBCS( r8, r8, r4)
+	ADCSBCS( r9, r9, r5)
+	vmov	 d0, r8, r9
+	ADCSBCS( r10, r10, r6)
+	ADCSBCS( r12, r12, r7)
+	vsli.u64 d2, d0, #31
+	vshr.u64 d3, d0, #1
+	vst1.32	 d2[0], [rp]!
+	b	 L(mi1)
+
+L(b00):	ldmia	 up!, {r8,r9,r10,r12}
+	ldmia	 vp!, {r4,r5,r6,r7}
+	ADDSUBS( r8, r8, r4)
+	ADCSBCS( r9, r9, r5)
+	vmov	 d4, r8, r9
+	ADCSBCS( r10, r10, r6)
+	ADCSBCS( r12, r12, r7)
+	vshr.u64 d3, d4, #1
+	b	 L(mi1)
+
+	ALIGN(16)
+L(top):	ldmia	 up!, {r8,r9,r10,r12}
+	ldmia	 vp!, {r4,r5,r6,r7}
+	vsli.u64 d3, d1, #63
+	vshr.u64 d2, d1, #1
+	vst1.32	 d3, [rp]!
+L(mi0):	ADCSBCS( r8, r8, r4)
+	ADCSBCS( r9, r9, r5)
+	vmov	 d0, r8, r9
+	ADCSBCS( r10, r10, r6)
+	ADCSBCS( r12, r12, r7)
+	vsli.u64 d2, d0, #63
+	vshr.u64 d3, d0, #1
+	vst1.32	 d2, [rp]!
+L(mi1):	vmov	 d1, r10, r12
+	sub	 n, n, #4
+	tst	 n, n
+	bne	 L(top)
+
+L(end):	vsli.u64 d3, d1, #63
+	vshr.u64 d2, d1, #1
+	vst1.32	 d3, [rp]!
+L(wd2):	vmov	 r4, r5, d2
+IFADD(`	adc	 r1, n, #0')
+IFSUB(`	adc	 r1, n, #1')
+	bfi	 r5, r1, #31, #1
+	stm	 rp, {r4,r5}
+
+L(rtn):	vmov.32	 r0, d4[0]
+	and	 r0, r0, #1
+	pop	 {r4-r10}
+	bx	 r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/v7a/cora15/submul_1.asm b/third_party/gmp/mpn/arm/v7a/cora15/submul_1.asm
new file mode 100644
index 0000000..ed7bfe8
--- /dev/null
+++ b/third_party/gmp/mpn/arm/v7a/cora15/submul_1.asm
@@ -0,0 +1,159 @@
+dnl  ARM mpn_submul_1 optimised for A15.
+
+dnl  Copyright 2012, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb		best
+C StrongARM:     -
+C XScale	 ?
+C Cortex-A7	 ?
+C Cortex-A8	 ?
+C Cortex-A9	 5.75			3.75
+C Cortex-A15	 2.32			this
+
+C This code uses umlal and umaal for adding in the rp[] data, keeping the
+C recurrency path separate from any multiply instructions.  It performs well on
+C A15, but not quite at the multiply bandwidth like the corresponding addmul_1
+C code.
+C
+C We don't use r12 due to ldrd and strd limitations.
+C
+C This loop complements U on the fly,
+C   U' = B^n - 1 - U
+C and then uses that
+C   R - U*v = R + U'*v + v - B^n v
+
+C Architecture requirements:
+C v5	-
+C v5t	-
+C v5te	ldrd strd
+C v6	umaal
+C v6t2	-
+C v7a	-
+
+define(`rp', `r0')
+define(`up', `r1')
+define(`n',  `r2')
+define(`v0', `r3')
+
+define(`w0', `r10') define(`w1', `r11')
+define(`u0', `r8')  define(`u1', `r9')
+
+ASM_START()
+PROLOGUE(mpn_submul_1)
+	sub	sp, sp, #32
+	strd	r10, r11, [sp, #24]
+	strd	r8, r9, [sp, #16]
+	strd	r6, r7, [sp, #8]
+	strd	r4, r5, [sp, #0]
+C	push	{ r4-r11 }
+
+	ands	r6, n, #3
+	sub	n, n, #3
+	beq	L(b00)
+	cmp	r6, #2
+	bcc	L(b01)
+	beq	L(b10)
+
+L(b11):	mov	r6, #0
+	ldr	u1, [up], #-4
+	ldr	w1, [rp], #-16
+	mvn	u1, u1
+	adds	r7, v0, #0
+	b	L(mid)
+
+L(b00):	ldrd	u0, u1, [up]
+	ldrd	w0, w1, [rp], #-12
+	mvn	u0, u0
+	mvn	u1, u1
+	mov	r6, v0
+	umaal	w0, r6, u0, v0
+	cmn	r13, #0			C carry clear
+	mov	r7, #0
+	str	w0, [rp, #12]
+	b	L(mid)
+
+L(b10):	ldrd	u0, u1, [up], #8
+	ldrd	w0, w1, [rp]
+	mvn	u0, u0
+	mvn	u1, u1
+	mov	r4, v0
+	umaal	w0, r4, u0, v0
+	mov	r5, #0
+	str	w0, [rp], #-4
+	umlal	w1, r5, u1, v0
+	adds	n, n, #0
+	bmi	L(end)
+	b	L(top)
+
+L(b01):	ldr	u1, [up], #4
+	ldr	w1, [rp], #-8
+	mvn	u1, u1
+	mov	r5, v0
+	mov	r4, #0
+	umaal	w1, r5, u1, v0
+	tst	n, n
+	bmi	L(end)
+
+C	ALIGN(16)
+L(top):	ldrd	u0, u1, [up, #0]
+	adcs	r4, r4, w1
+	mvn	u0, u0
+	ldrd	w0, w1, [rp, #12]
+	mvn	u1, u1
+	mov	r6, #0
+	umlal	w0, r6, u0, v0		C 1 2
+	adcs	r5, r5, w0
+	mov	r7, #0
+	strd	r4, r5, [rp, #8]
+L(mid):	umaal	w1, r7, u1, v0		C 2 3
+	ldrd	u0, u1, [up, #8]
+	add	up, up, #16
+	adcs	r6, r6, w1
+	mvn	u0, u0
+	ldrd	w0, w1, [rp, #20]
+	mvn	u1, u1
+	mov	r4, #0
+	umlal	w0, r4, u0, v0		C 3 4
+	adcs	r7, r7, w0
+	mov	r5, #0
+	strd	r6, r7, [rp, #16]!
+	sub	n, n, #4
+	umlal	w1, r5, u1, v0		C 0 1
+	tst	n, n
+	bpl	L(top)
+
+L(end):	adcs	r4, r4, w1
+	str	r4, [rp, #8]
+	adc	r0, r5, #0
+	sub	r0, v0, r0
+	pop	{ r4-r11 }
+	bx	r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/v7a/cora17/addmul_1.asm b/third_party/gmp/mpn/arm/v7a/cora17/addmul_1.asm
new file mode 100644
index 0000000..c11ed47
--- /dev/null
+++ b/third_party/gmp/mpn/arm/v7a/cora17/addmul_1.asm
@@ -0,0 +1,34 @@
+dnl  ARM mpn_addmul_1
+
+dnl  Copyright 2018 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+MULFUNC_PROLOGUE(mpn_addmul_1)
+include_mpn(`arm/v6/addmul_1.asm')
diff --git a/third_party/gmp/mpn/arm/v7a/cora17/gmp-mparam.h b/third_party/gmp/mpn/arm/v7a/cora17/gmp-mparam.h
new file mode 100644
index 0000000..143d4bc
--- /dev/null
+++ b/third_party/gmp/mpn/arm/v7a/cora17/gmp-mparam.h
@@ -0,0 +1,233 @@
+/* gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+/* 1800 MHz Cortex-A17 with Neon (in spite of file position) */
+/* FFT tuning limit = 51243975 */
+/* Generated by tuneup.c, 2019-10-29, gcc 6.3 */
+
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          5
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          3
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD         8
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD     MP_SIZE_T_MAX
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     12
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1N_PI1_METHOD                 1  /* 54.08% faster than 2 */
+#define DIV_QR_1_NORM_THRESHOLD          MP_SIZE_T_MAX  /* never */
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           45
+
+#define DIV_1_VS_MUL_1_PERCENT             248
+
+#define MUL_TOOM22_THRESHOLD                38
+#define MUL_TOOM33_THRESHOLD               132
+#define MUL_TOOM44_THRESHOLD               200
+#define MUL_TOOM6H_THRESHOLD               303
+#define MUL_TOOM8H_THRESHOLD               478
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD     137
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     179
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     132
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     145
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     191
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 62
+#define SQR_TOOM3_THRESHOLD                189
+#define SQR_TOOM4_THRESHOLD                354
+#define SQR_TOOM6_THRESHOLD                426
+#define SQR_TOOM8_THRESHOLD                608
+
+#define MULMID_TOOM42_THRESHOLD             62
+
+#define MULMOD_BNM1_THRESHOLD               21
+#define SQRMOD_BNM1_THRESHOLD               29
+
+#define MUL_FFT_MODF_THRESHOLD             595  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    595, 5}, {     29, 6}, {     15, 5}, {     31, 6}, \
+    {     16, 5}, {     33, 6}, {     29, 7}, {     15, 6}, \
+    {     33, 7}, {     17, 6}, {     36, 7}, {     19, 6}, \
+    {     39, 7}, {     29, 8}, {     15, 7}, {     35, 8}, \
+    {     19, 7}, {     41, 8}, {     23, 7}, {     49, 8}, \
+    {     27, 7}, {     55, 9}, {     15, 8}, {     31, 7}, \
+    {     63, 8}, {     43, 9}, {     23, 8}, {     55, 9}, \
+    {     31, 8}, {     63, 9}, {     39, 8}, {     83, 9}, \
+    {     47, 8}, {     95, 9}, {     55,10}, {     31, 9}, \
+    {     79,10}, {     47, 9}, {    103,11}, {     31,10}, \
+    {     63, 9}, {    135,10}, {     79, 9}, {    159,10}, \
+    {     95, 9}, {    191,10}, {    111,11}, {     63,10}, \
+    {    143, 8}, {    575,10}, {    159,11}, {     95,10}, \
+    {    191, 9}, {    383, 8}, {    767, 9}, {    399, 8}, \
+    {    799,12}, {     63,11}, {    127,10}, {    255, 9}, \
+    {    511, 8}, {   1023, 9}, {    543, 8}, {   1087, 9}, \
+    {    575,10}, {    303,11}, {    159,10}, {    319, 9}, \
+    {    639,10}, {    335, 9}, {    671,10}, {    351, 9}, \
+    {    703,10}, {    367, 9}, {    735,11}, {    191,10}, \
+    {    383, 9}, {    767,10}, {    399, 9}, {    799,10}, \
+    {    415, 9}, {    831,10}, {    431, 9}, {    863,11}, \
+    {    223,10}, {    447,12}, {    127,10}, {    511, 9}, \
+    {   1023,10}, {    543, 9}, {   1087,10}, {    607, 9}, \
+    {   1215,11}, {    319,10}, {    671, 9}, {   1343,11}, \
+    {    351,10}, {    735,12}, {    191,11}, {    383,10}, \
+    {    799,11}, {    415,10}, {    863,11}, {    447,10}, \
+    {    895,13}, {    127,11}, {    511,10}, {   1023,11}, \
+    {    543,10}, {   1087,11}, {    607,10}, {   1215,12}, \
+    {    319,11}, {    671,10}, {   1343,11}, {    735,10}, \
+    {   1471,12}, {    383,11}, {    799,10}, {   1599,11}, \
+    {    863,10}, {   1727,12}, {    447,11}, {    991,10}, \
+    {   1983,12}, {    511,11}, {   1087,12}, {    575,11}, \
+    {   1215,10}, {   2431,12}, {    639,11}, {   1343,12}, \
+    {    703,11}, {   1471,13}, {    383,12}, {    767,11}, \
+    {   1599,12}, {    831,11}, {   1727,12}, {    959,11}, \
+    {   1983,13}, {    511,12}, {   1087,11}, {   2239,12}, \
+    {   1215,11}, {   2431,13}, {    639,12}, {   1471,11}, \
+    {   2943,13}, {    767,12}, {   1727,13}, {    895,12}, \
+    {   1983,14}, {    511,13}, {   1023,12}, {   2239,13}, \
+    {   1151,12}, {   2495,13}, {   1279,12}, {   2623,13}, \
+    {   1407,12}, {   2943,14}, {    767,13}, {   1535,12}, \
+    {   3135,13}, {   1663,12}, {   3455,13}, {   1919,12}, \
+    {   3839,15}, {    511,14}, {   1023,13}, {   2175,12}, \
+    {   4479,13}, {   2431,14}, {   1279,13}, {   2943,12}, \
+    {   5887,14}, {   1535,13}, {   3455,14}, {   1791,13}, \
+    {   3967,15}, {   1023,14}, {   2047,13}, {   4479,14}, \
+    {   2303,13}, {   4991,12}, {   9983,14}, {   2559,13}, \
+    {   5247,14}, {   2815,13}, {   5887,15}, {   1535,14}, \
+    {  16384,15}, {  32768,16} }
+#define MUL_FFT_TABLE3_SIZE 194
+#define MUL_FFT_THRESHOLD                 6784
+
+#define SQR_FFT_MODF_THRESHOLD             500  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    500, 5}, {     29, 6}, {     15, 5}, {     31, 6}, \
+    {     16, 5}, {     33, 6}, {     29, 7}, {     15, 6}, \
+    {     32, 7}, {     17, 6}, {     36, 7}, {     19, 6}, \
+    {     39, 7}, {     29, 8}, {     15, 7}, {     35, 8}, \
+    {     19, 7}, {     41, 8}, {     23, 7}, {     49, 8}, \
+    {     27, 9}, {     15, 8}, {     31, 7}, {     63, 8}, \
+    {     43, 9}, {     23, 8}, {     55,10}, {     15, 9}, \
+    {     31, 8}, {     67, 9}, {     39, 8}, {     79, 9}, \
+    {     47, 8}, {     95, 9}, {     55,10}, {     31, 9}, \
+    {     79,10}, {     47, 9}, {     95,11}, {     31,10}, \
+    {     63, 9}, {    135,10}, {     79, 9}, {    159,10}, \
+    {     95, 9}, {    191,10}, {    111,11}, {     63,10}, \
+    {    127, 9}, {    255,10}, {    143, 9}, {    287,10}, \
+    {    159, 9}, {    319,11}, {     95,10}, {    191, 9}, \
+    {    383, 8}, {    767, 9}, {    399,12}, {     63,11}, \
+    {    127,10}, {    255, 9}, {    511,10}, {    271, 9}, \
+    {    543,10}, {    287, 9}, {    575,10}, {    303,11}, \
+    {    159,10}, {    319, 9}, {    639,10}, {    335, 9}, \
+    {    671,10}, {    351, 9}, {    703,10}, {    367, 9}, \
+    {    735,11}, {    191,10}, {    383, 9}, {    767,10}, \
+    {    399, 9}, {    799,10}, {    415, 9}, {    831,10}, \
+    {    431, 9}, {    863,10}, {    447,12}, {    127,11}, \
+    {    255,10}, {    511, 9}, {   1023,10}, {    543, 9}, \
+    {   1087,11}, {    287,10}, {    607, 9}, {   1215,11}, \
+    {    319,10}, {    671,11}, {    351,10}, {    735,12}, \
+    {    191,11}, {    383,10}, {    799,11}, {    415,10}, \
+    {    863,11}, {    447,10}, {    895,13}, {    127,12}, \
+    {    255,11}, {    511,10}, {   1023,11}, {    543,10}, \
+    {   1087,11}, {    607,10}, {   1215,12}, {    319,11}, \
+    {    671,10}, {   1343,11}, {    735,10}, {   1471,12}, \
+    {    383,11}, {    799,10}, {   1599,11}, {    863,12}, \
+    {    447,11}, {    959,10}, {   1919,11}, {    991,13}, \
+    {    255,12}, {    511,11}, {   1087,12}, {    575,11}, \
+    {   1215,10}, {   2431,12}, {    639,11}, {   1343,12}, \
+    {    703,11}, {   1471,13}, {    383,12}, {    767,11}, \
+    {   1599,12}, {    831,11}, {   1727,12}, {    959,11}, \
+    {   1919,14}, {    255,13}, {    511,12}, {   1087,11}, \
+    {   2239,12}, {   1215,11}, {   2431,13}, {    639,12}, \
+    {   1471,11}, {   2943,13}, {    767,12}, {   1727,13}, \
+    {    895,12}, {   1983,14}, {    511,13}, {   1023,12}, \
+    {   2239,13}, {   1151,12}, {   2495,13}, {   1279,12}, \
+    {   2623,13}, {   1407,12}, {   2943,14}, {    767,13}, \
+    {   1535,12}, {   3071,13}, {   1663,12}, {   3455,13}, \
+    {   1919,12}, {   3839,15}, {    511,14}, {   1023,13}, \
+    {   2175,12}, {   4479,13}, {   2431,14}, {   1279,13}, \
+    {   2943,12}, {   5887,14}, {   1535,13}, {   3455,14}, \
+    {   1791,13}, {   3967,15}, {   1023,14}, {   2047,13}, \
+    {   4479,14}, {   2303,13}, {   4991,12}, {   9983,14}, \
+    {   2559,13}, {   5119,14}, {   2815,13}, {   5887,15}, \
+    {   1535,14}, {  16384,15}, {  32768,16} }
+#define SQR_FFT_TABLE3_SIZE 199
+#define SQR_FFT_THRESHOLD                 4736
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  27
+#define MULLO_MUL_N_THRESHOLD            13463
+#define SQRLO_BASECASE_THRESHOLD             0  /* always */
+#define SQRLO_DC_THRESHOLD                  26
+#define SQRLO_SQR_THRESHOLD               8907
+
+#define DC_DIV_QR_THRESHOLD                 38
+#define DC_DIVAPPR_Q_THRESHOLD             103
+#define DC_BDIV_QR_THRESHOLD                44
+#define DC_BDIV_Q_THRESHOLD                 98
+
+#define INV_MULMOD_BNM1_THRESHOLD           78
+#define INV_NEWTON_THRESHOLD               165
+#define INV_APPR_THRESHOLD                 115
+
+#define BINV_NEWTON_THRESHOLD              296
+#define REDC_1_TO_REDC_2_THRESHOLD           2
+#define REDC_2_TO_REDC_N_THRESHOLD         147
+
+#define MU_DIV_QR_THRESHOLD               2089
+#define MU_DIVAPPR_Q_THRESHOLD            2089
+#define MUPI_DIV_QR_THRESHOLD               70
+#define MU_BDIV_QR_THRESHOLD              1718
+#define MU_BDIV_Q_THRESHOLD               2089
+
+#define POWM_SEC_TABLE  7,19,107,480,1486
+
+#define GET_STR_DC_THRESHOLD                14
+#define GET_STR_PRECOMPUTE_THRESHOLD        29
+#define SET_STR_DC_THRESHOLD               126
+#define SET_STR_PRECOMPUTE_THRESHOLD       541
+
+#define FAC_DSC_THRESHOLD                  132
+#define FAC_ODD_THRESHOLD                   29
+
+#define MATRIX22_STRASSEN_THRESHOLD         30
+#define HGCD2_DIV1_METHOD                    1  /* 6.55% faster than 3 */
+#define HGCD_THRESHOLD                      54
+#define HGCD_APPR_THRESHOLD                 52
+#define HGCD_REDUCE_THRESHOLD             3524
+#define GCD_DC_THRESHOLD                   303
+#define GCDEXT_DC_THRESHOLD                225
+#define JACOBI_BASE_METHOD                   4  /* 9.73% faster than 1 */
+
+/* Tuneup completed successfully, took 111418 seconds */
diff --git a/third_party/gmp/mpn/arm/v7a/cora17/mod_34lsub1.asm b/third_party/gmp/mpn/arm/v7a/cora17/mod_34lsub1.asm
new file mode 100644
index 0000000..39e5a15
--- /dev/null
+++ b/third_party/gmp/mpn/arm/v7a/cora17/mod_34lsub1.asm
@@ -0,0 +1,121 @@
+dnl  ARM mpn_mod_34lsub1 -- remainder modulo 2^24-1.
+
+dnl  Copyright 2012, 2013, 2018 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C StrongARM	 ?
+C XScale	 ?
+C Cortex-A5	 2.67
+C Cortex-A7	 2.37
+C Cortex-A8	 2.34
+C Cortex-A9	 ?
+C Cortex-A15	 1.39
+C Cortex-A17	 1.60
+C Cortex-A53	 2.51
+
+define(`ap',	r0)
+define(`n',	r1)
+
+C mp_limb_t mpn_mod_34lsub1 (mp_srcptr up, mp_size_t n)
+
+C TODO
+C  * Write cleverer summation code.
+C  * Consider loading 6 64-bit aligned registers at a time, to approach 1 c/l.
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_mod_34lsub1)
+	push	{ r4, r5, r6, r7 }
+
+	subs	n, n, #3
+	mov	r7, #0
+	blt	L(le2)			C n <= 2
+
+	ldmia	ap!, { r2, r3, r12 }
+	subs	n, n, #3
+	blt	L(sum)			C n <= 5
+	mov	r7, #0
+	b	L(mid)
+
+L(top):	adds	r2, r2, r4
+	adcs	r3, r3, r5
+	adcs	r12, r12, r6
+	adc	r7, r7, #0
+L(mid):	ldmia	ap!, { r4, r5, r6 }
+	subs	n, n, #3
+	bpl	L(top)
+
+	adds	r2, r2, r4
+	adcs	r3, r3, r5
+	adcs	r12, r12, r6
+	adc	r7, r7, #0		C r7 <= 1
+
+L(sum):	cmn	n, #2
+	movlo	r4, #0
+	ldrhs	r4, [ap], #4
+	movls	r5, #0
+	ldrhi	r5, [ap], #4
+
+	adds	r2, r2, r4
+	adcs	r3, r3, r5
+	adcs	r12, r12, #0
+	adc	r7, r7, #0		C r7 <= 2
+
+L(sum2):
+	bic	r0, r2, #0xff000000
+	add	r0, r0, r2, lsr #24
+	add	r0, r0, r7
+
+	mov	r7, r3, lsl #8
+	bic	r2, r7, #0xff000000
+	add	r0, r0, r2
+	add	r0, r0, r3, lsr #16
+
+	mov	r2, r12, lsl #16
+	bic	r1, r2, #0xff000000
+	add	r0, r0, r1
+	add	r0, r0, r12, lsr #8
+
+	pop	{ r4, r5, r6, r7 }
+	return	lr
+
+L(le2):	cmn	n, #1
+	bne	L(1)
+	ldmia	ap!, { r2, r3 }
+	mov	r12, #0
+	b	L(sum2)
+L(1):	ldr	r2, [ap]
+	bic	r0, r2, #0xff000000
+	add	r0, r0, r2, lsr #24
+	pop	{ r4, r5, r6, r7 }
+	return	lr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/v7a/cora17/mul_1.asm b/third_party/gmp/mpn/arm/v7a/cora17/mul_1.asm
new file mode 100644
index 0000000..d9b6042
--- /dev/null
+++ b/third_party/gmp/mpn/arm/v7a/cora17/mul_1.asm
@@ -0,0 +1,34 @@
+dnl  ARM mpn_mul_1
+
+dnl  Copyright 2018 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+MULFUNC_PROLOGUE(mpn_mul_1)
+include_mpn(`arm/v6/mul_1.asm')
diff --git a/third_party/gmp/mpn/arm/v7a/cora17/submul_1.asm b/third_party/gmp/mpn/arm/v7a/cora17/submul_1.asm
new file mode 100644
index 0000000..f3e8139
--- /dev/null
+++ b/third_party/gmp/mpn/arm/v7a/cora17/submul_1.asm
@@ -0,0 +1,34 @@
+dnl  ARM mpn_submul_1
+
+dnl  Copyright 2018 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+MULFUNC_PROLOGUE(mpn_submul_1)
+include_mpn(`arm/v6/submul_1.asm')
diff --git a/third_party/gmp/mpn/arm/v7a/cora5/gmp-mparam.h b/third_party/gmp/mpn/arm/v7a/cora5/gmp-mparam.h
new file mode 100644
index 0000000..e3564e0
--- /dev/null
+++ b/third_party/gmp/mpn/arm/v7a/cora5/gmp-mparam.h
@@ -0,0 +1,205 @@
+/* gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+/* 1500 MHz Cortex-A5 (odroid c1) */
+/* FFT tuning limit = 18,235,562 */
+/* Generated by tuneup.c, 2019-10-22, gcc 4.9 */
+
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          7
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          7
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD         8
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD     MP_SIZE_T_MAX
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     23
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1N_PI1_METHOD                 1  /* 132.79% faster than 2 */
+#define DIV_QR_1_NORM_THRESHOLD          MP_SIZE_T_MAX  /* never */
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           52
+
+#define DIV_1_VS_MUL_1_PERCENT             213
+
+#define MUL_TOOM22_THRESHOLD                48
+#define MUL_TOOM33_THRESHOLD               143
+#define MUL_TOOM44_THRESHOLD               262
+#define MUL_TOOM6H_THRESHOLD               414
+#define MUL_TOOM8H_THRESHOLD               527
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD     153
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     168
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     152
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     180
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     226
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 66
+#define SQR_TOOM3_THRESHOLD                149
+#define SQR_TOOM4_THRESHOLD                348
+#define SQR_TOOM6_THRESHOLD                517
+#define SQR_TOOM8_THRESHOLD                608
+
+#define MULMID_TOOM42_THRESHOLD             70
+
+#define MULMOD_BNM1_THRESHOLD               26
+#define SQRMOD_BNM1_THRESHOLD               28
+
+#define MUL_FFT_MODF_THRESHOLD             660  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    660, 5}, {     29, 6}, {     15, 5}, {     33, 6}, \
+    {     17, 5}, {     35, 6}, {     29, 7}, {     15, 6}, \
+    {     37, 7}, {     19, 6}, {     40, 7}, {     21, 6}, \
+    {     43, 7}, {     37, 8}, {     19, 7}, {     43, 8}, \
+    {     23, 7}, {     51, 8}, {     27, 7}, {     55, 8}, \
+    {     31, 7}, {     63, 8}, {     43, 9}, {     23, 8}, \
+    {     55, 9}, {     31, 8}, {     71, 9}, {     39, 8}, \
+    {     83, 9}, {     47, 8}, {     99, 9}, {     55,10}, \
+    {     31, 9}, {     63, 8}, {    127, 9}, {     79,10}, \
+    {     47, 9}, {    103,11}, {     31,10}, {     63, 9}, \
+    {    135,10}, {     79, 9}, {    167,10}, {     95, 9}, \
+    {    191,10}, {    111,11}, {     63,10}, {    159,11}, \
+    {     95,10}, {    191, 9}, {    383,12}, {     63,11}, \
+    {    127,10}, {    255, 9}, {    511,10}, {    271,11}, \
+    {    159,10}, {    319, 9}, {    639,10}, {    335, 9}, \
+    {    671,11}, {    191,10}, {    383, 9}, {    767,10}, \
+    {    399, 9}, {    799,10}, {    415,11}, {    223,12}, \
+    {    127,11}, {    255,10}, {    511, 9}, {   1023,10}, \
+    {    543,11}, {    287,10}, {    607,11}, {    319,10}, \
+    {    671,11}, {    351,12}, {    191,11}, {    383,10}, \
+    {    799,11}, {    415,10}, {    831,13}, {    127,12}, \
+    {    255,11}, {    511,10}, {   1023,11}, {    543,10}, \
+    {   1087,11}, {    575,10}, {   1151,11}, {    607,12}, \
+    {    319,11}, {    703,12}, {    383,11}, {    831,12}, \
+    {    447,11}, {    895,13}, {    255,12}, {    511,11}, \
+    {   1087,12}, {    575,11}, {   1183,12}, {    639,11}, \
+    {   1279,12}, {    703,13}, {    383,12}, {    767,11}, \
+    {   1535,12}, {    895,14}, {    255,13}, {    511,12}, \
+    {   1151,13}, {    639,12}, {   1407,13}, {    767,12}, \
+    {   1599,13}, {    895,12}, {   1791,14}, {    511,13}, \
+    {   1023,12}, {   2111,13}, {   1151,12}, {   2367,13}, \
+    {   1279,12}, {   2559,13}, {   1407,14}, {    767,13}, \
+    {   1535,12}, {   3071,13}, {   1663,12}, {   3327,13}, \
+    {   1791,15}, {    511,14}, {   1023,13}, {   2175,12}, \
+    {   4351,13}, {   8192,14}, {  16384,15}, {  32768,16} }
+#define MUL_FFT_TABLE3_SIZE 140
+#define MUL_FFT_THRESHOLD                 7552
+
+#define SQR_FFT_MODF_THRESHOLD             590  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    590, 5}, {     33, 6}, {     17, 5}, {     35, 6}, \
+    {     36, 7}, {     19, 6}, {     40, 7}, {     21, 6}, \
+    {     43, 7}, {     23, 6}, {     47, 7}, {     37, 8}, \
+    {     19, 7}, {     43, 8}, {     23, 7}, {     49, 8}, \
+    {     27, 7}, {     55, 8}, {     31, 7}, {     63, 8}, \
+    {     43, 9}, {     23, 8}, {     55, 9}, {     31, 8}, \
+    {     67, 9}, {     39, 8}, {     83, 9}, {     47, 8}, \
+    {     95, 9}, {     55,10}, {     31, 9}, {     79,10}, \
+    {     47, 9}, {    103,11}, {     31,10}, {     63, 9}, \
+    {    135,10}, {     79, 9}, {    167,10}, {     95, 9}, \
+    {    191,10}, {    111,11}, {     63,10}, {    159,11}, \
+    {     95,10}, {    191, 9}, {    383,12}, {     63,11}, \
+    {    127,10}, {    255, 9}, {    511,10}, {    271, 9}, \
+    {    543,11}, {    159,10}, {    319, 9}, {    639,10}, \
+    {    335, 9}, {    671,10}, {    351,11}, {    191,10}, \
+    {    383, 9}, {    767,10}, {    415,12}, {    127,11}, \
+    {    255,10}, {    511, 9}, {   1023,10}, {    543, 9}, \
+    {   1087,11}, {    287,10}, {    575, 9}, {   1151,10}, \
+    {    607,11}, {    319,10}, {    671,11}, {    351,12}, \
+    {    191,11}, {    383,10}, {    799,11}, {    415,10}, \
+    {    831,13}, {    127,12}, {    255,11}, {    511,10}, \
+    {   1023,11}, {    543,10}, {   1087,11}, {    575,10}, \
+    {   1151,11}, {    607,12}, {    319,11}, {    735,12}, \
+    {    383,11}, {    831,12}, {    447,11}, {    927,13}, \
+    {    255,12}, {    511,11}, {   1087,12}, {    575,11}, \
+    {   1151,12}, {    639,11}, {   1279,12}, {    703,13}, \
+    {    383,12}, {    767,11}, {   1535,12}, {    831,11}, \
+    {   1663,12}, {    895,11}, {   1791,12}, {    959,14}, \
+    {    255,13}, {    511,12}, {   1023,11}, {   2047,12}, \
+    {   1151,13}, {    639,12}, {   1407,13}, {    767,12}, \
+    {   1599,13}, {    895,12}, {   1791,14}, {    511,13}, \
+    {   1023,12}, {   2111,13}, {   1151,12}, {   2367,13}, \
+    {   1279,12}, {   2559,13}, {   1407,14}, {    767,13}, \
+    {   1535,12}, {   3071,13}, {   1663,12}, {   3327,13}, \
+    {   1791,15}, {    511,14}, {   1023,13}, {   2175,12}, \
+    {   4351,13}, {   8192,14}, {  16384,15}, {  32768,16} }
+#define SQR_FFT_TABLE3_SIZE 144
+#define SQR_FFT_THRESHOLD                 5760
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  39
+#define MULLO_MUL_N_THRESHOLD            14709
+#define SQRLO_BASECASE_THRESHOLD             8
+#define SQRLO_DC_THRESHOLD                  33
+#define SQRLO_SQR_THRESHOLD              11278
+
+#define DC_DIV_QR_THRESHOLD                 36
+#define DC_DIVAPPR_Q_THRESHOLD             116
+#define DC_BDIV_QR_THRESHOLD                48
+#define DC_BDIV_Q_THRESHOLD                140
+
+#define INV_MULMOD_BNM1_THRESHOLD           95
+#define INV_NEWTON_THRESHOLD               181
+#define INV_APPR_THRESHOLD                 125
+
+#define BINV_NEWTON_THRESHOLD              327
+#define REDC_1_TO_REDC_2_THRESHOLD           0  /* always */
+#define REDC_2_TO_REDC_N_THRESHOLD         152
+
+#define MU_DIV_QR_THRESHOLD               2350
+#define MU_DIVAPPR_Q_THRESHOLD            2130
+#define MUPI_DIV_QR_THRESHOLD               98
+#define MU_BDIV_QR_THRESHOLD              1970
+#define MU_BDIV_Q_THRESHOLD               2172
+
+#define POWM_SEC_TABLE  6,37,108,624,2351
+
+#define GET_STR_DC_THRESHOLD                28
+#define GET_STR_PRECOMPUTE_THRESHOLD        44
+#define SET_STR_DC_THRESHOLD               309
+#define SET_STR_PRECOMPUTE_THRESHOLD       762
+
+#define FAC_DSC_THRESHOLD                  236
+#define FAC_ODD_THRESHOLD                   29
+
+#define MATRIX22_STRASSEN_THRESHOLD         25
+#define HGCD2_DIV1_METHOD                    5  /* 2.92% faster than 3 */
+#define HGCD_THRESHOLD                      70
+#define HGCD_APPR_THRESHOLD                 59
+#define HGCD_REDUCE_THRESHOLD             4120
+#define GCD_DC_THRESHOLD                   229
+#define GCDEXT_DC_THRESHOLD                233
+#define JACOBI_BASE_METHOD                   1  /* 17.07% faster than 4 */
+
+/* Tuneup completed successfully, took 47845 seconds */
diff --git a/third_party/gmp/mpn/arm/v7a/cora7/gmp-mparam.h b/third_party/gmp/mpn/arm/v7a/cora7/gmp-mparam.h
new file mode 100644
index 0000000..78de045
--- /dev/null
+++ b/third_party/gmp/mpn/arm/v7a/cora7/gmp-mparam.h
@@ -0,0 +1,202 @@
+/* gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+/* 900 MHz Cortex-A7 (raspberry pi2) */
+/* FFT tuning limit = 21,559,921 */
+/* Generated by tuneup.c, 2019-10-22, gcc 8.3 */
+
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          7
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          8
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD         0  /* never mpn_mod_1_1p */
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD     MP_SIZE_T_MAX
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     18
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1N_PI1_METHOD                 1  /* 64.16% faster than 2 */
+#define DIV_QR_1_NORM_THRESHOLD          MP_SIZE_T_MAX  /* never */
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           48
+
+#define DIV_1_VS_MUL_1_PERCENT             216
+
+#define MUL_TOOM22_THRESHOLD                39
+#define MUL_TOOM33_THRESHOLD               129
+#define MUL_TOOM44_THRESHOLD               196
+#define MUL_TOOM6H_THRESHOLD               327
+#define MUL_TOOM8H_THRESHOLD               478
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD     129
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     183
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     132
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     144
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     190
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 52
+#define SQR_TOOM3_THRESHOLD                162
+#define SQR_TOOM4_THRESHOLD                268
+#define SQR_TOOM6_THRESHOLD                399
+#define SQR_TOOM8_THRESHOLD                547
+
+#define MULMID_TOOM42_THRESHOLD             50
+
+#define MULMOD_BNM1_THRESHOLD               21
+#define SQRMOD_BNM1_THRESHOLD               25
+
+#define MUL_FFT_MODF_THRESHOLD             636  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    636, 5}, {     28, 6}, {     15, 5}, {     31, 6}, \
+    {     29, 7}, {     15, 6}, {     33, 7}, {     17, 6}, \
+    {     35, 7}, {     19, 6}, {     39, 7}, {     29, 8}, \
+    {     15, 7}, {     35, 8}, {     19, 7}, {     43, 8}, \
+    {     23, 7}, {     49, 8}, {     27, 7}, {     55, 8}, \
+    {     31, 7}, {     63, 8}, {     43, 9}, {     23, 8}, \
+    {     55, 9}, {     31, 8}, {     67, 9}, {     39, 8}, \
+    {     83, 9}, {     47, 8}, {     95, 9}, {     55,10}, \
+    {     31, 9}, {     79,10}, {     47, 9}, {    103,11}, \
+    {     31,10}, {     63, 9}, {    135,10}, {     79, 9}, \
+    {    159,10}, {     95, 9}, {    191,10}, {    111,11}, \
+    {     63,10}, {    159,11}, {     95,10}, {    191,12}, \
+    {     63,11}, {    127,10}, {    255, 9}, {    511,10}, \
+    {    271, 9}, {    543,11}, {    159,10}, {    319, 9}, \
+    {    639,10}, {    335, 9}, {    671,10}, {    351,11}, \
+    {    191,10}, {    383, 9}, {    767,10}, {    399, 9}, \
+    {    799,10}, {    415,11}, {    223,12}, {    127,11}, \
+    {    255,10}, {    511, 9}, {   1023,10}, {    543,11}, \
+    {    287,10}, {    607,11}, {    319,10}, {    671,11}, \
+    {    351,12}, {    191,11}, {    383,10}, {    799,11}, \
+    {    415,10}, {    831,13}, {    127,12}, {    255,11}, \
+    {    511,10}, {   1023,11}, {    543,10}, {   1087,11}, \
+    {    607,12}, {    319,11}, {    735,12}, {    383,11}, \
+    {    863,12}, {    447,11}, {    959,13}, {    255,12}, \
+    {    511,11}, {   1087,12}, {    575,11}, {   1215,12}, \
+    {    639,11}, {   1279,12}, {    703,13}, {    383,12}, \
+    {    767,11}, {   1599,12}, {    959,14}, {    255,13}, \
+    {    511,12}, {   1215,13}, {    639,12}, {   1471,13}, \
+    {    767,12}, {   1663,13}, {    895,12}, {   1855,14}, \
+    {    511,13}, {   1023,12}, {   2111,13}, {   1151,12}, \
+    {   2431,13}, {   1407,14}, {    767,13}, {   1663,12}, \
+    {   3327,13}, {   1791,15}, {    511,14}, {   1023,13}, \
+    {   2431,14}, {   1279,13}, {   8192,14}, {  16384,15}, \
+    {  32768,16} }
+#define MUL_FFT_TABLE3_SIZE 133
+#define MUL_FFT_THRESHOLD                 6784
+
+#define SQR_FFT_MODF_THRESHOLD             535  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    535, 5}, {     25, 6}, {     13, 5}, {     28, 6}, \
+    {     15, 5}, {     31, 6}, {     29, 7}, {     15, 6}, \
+    {     33, 7}, {     17, 6}, {     36, 7}, {     19, 6}, \
+    {     39, 7}, {     29, 8}, {     15, 7}, {     37, 8}, \
+    {     19, 7}, {     43, 8}, {     23, 7}, {     49, 8}, \
+    {     27, 7}, {     55, 8}, {     31, 7}, {     63, 8}, \
+    {     43, 9}, {     23, 8}, {     55, 9}, {     31, 8}, \
+    {     67, 9}, {     39, 8}, {     79, 9}, {     47, 8}, \
+    {     95, 9}, {     55,10}, {     31, 9}, {     79,10}, \
+    {     47, 9}, {    103,11}, {     31,10}, {     63, 9}, \
+    {    135,10}, {     79, 9}, {    159,10}, {     95, 9}, \
+    {    191,10}, {    111,11}, {     63,10}, {    143, 9}, \
+    {    287,10}, {    159,11}, {     95,10}, {    191,12}, \
+    {     63,11}, {    127,10}, {    255, 9}, {    511,10}, \
+    {    271, 9}, {    543,10}, {    287,11}, {    159,10}, \
+    {    319, 9}, {    639,10}, {    335, 9}, {    671,10}, \
+    {    351,11}, {    191,10}, {    383, 9}, {    767,10}, \
+    {    399, 9}, {    799,10}, {    415, 9}, {    831,11}, \
+    {    223,12}, {    127,10}, {    543,11}, {    287,10}, \
+    {    607,11}, {    319,10}, {    671,11}, {    351,10}, \
+    {    703,12}, {    191,11}, {    383,10}, {    799,11}, \
+    {    415,10}, {    831,13}, {    127,11}, {    511,10}, \
+    {   1023,11}, {    543,10}, {   1087,11}, {    607,12}, \
+    {    319,11}, {    735,12}, {    383,11}, {    863,12}, \
+    {    447,11}, {    991,12}, {    511,11}, {   1087,12}, \
+    {    575,11}, {   1215,12}, {    639,11}, {   1279,12}, \
+    {    703,13}, {    383,12}, {    767,11}, {   1535,12}, \
+    {    831,11}, {   1663,12}, {    959,13}, {    511,12}, \
+    {   1215,13}, {    639,12}, {   1471,13}, {    767,12}, \
+    {   1663,13}, {    895,12}, {   1855,14}, {    511,13}, \
+    {   1023,12}, {   2111,13}, {   1151,12}, {   2431,13}, \
+    {   1407,14}, {    767,13}, {   1791,15}, {    511,14}, \
+    {   1023,13}, {   2431,14}, {   1279,13}, {   8192,14}, \
+    {  16384,15}, {  32768,16} }
+#define SQR_FFT_TABLE3_SIZE 134
+#define SQR_FFT_THRESHOLD                 4736
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  27
+#define MULLO_MUL_N_THRESHOLD            13463
+#define SQRLO_BASECASE_THRESHOLD             5
+#define SQRLO_DC_THRESHOLD                  31
+#define SQRLO_SQR_THRESHOLD               9449
+
+#define DC_DIV_QR_THRESHOLD                 28
+#define DC_DIVAPPR_Q_THRESHOLD              90
+#define DC_BDIV_QR_THRESHOLD                32
+#define DC_BDIV_Q_THRESHOLD                110
+
+#define INV_MULMOD_BNM1_THRESHOLD           78
+#define INV_NEWTON_THRESHOLD               134
+#define INV_APPR_THRESHOLD                  98
+
+#define BINV_NEWTON_THRESHOLD              278
+#define REDC_1_TO_REDC_2_THRESHOLD           4
+#define REDC_2_TO_REDC_N_THRESHOLD         123
+
+#define MU_DIV_QR_THRESHOLD               1718
+#define MU_DIVAPPR_Q_THRESHOLD            1685
+#define MUPI_DIV_QR_THRESHOLD               62
+#define MU_BDIV_QR_THRESHOLD              1528
+#define MU_BDIV_Q_THRESHOLD               1718
+
+#define POWM_SEC_TABLE  1,22,95,563,1955
+
+#define GET_STR_DC_THRESHOLD                28
+#define GET_STR_PRECOMPUTE_THRESHOLD        51
+#define SET_STR_DC_THRESHOLD               182
+#define SET_STR_PRECOMPUTE_THRESHOLD       638
+
+#define FAC_DSC_THRESHOLD                  153
+#define FAC_ODD_THRESHOLD                   56
+
+#define MATRIX22_STRASSEN_THRESHOLD         25
+#define HGCD2_DIV1_METHOD                    1  /* 5.04% faster than 3 */
+#define HGCD_THRESHOLD                      55
+#define HGCD_APPR_THRESHOLD                 50
+#define HGCD_REDUCE_THRESHOLD             3389
+#define GCD_DC_THRESHOLD                   153
+#define GCDEXT_DC_THRESHOLD                180
+#define JACOBI_BASE_METHOD                   1  /* 30.60% faster than 4 */
+
+/* Tuneup completed successfully, took 75202 seconds */
diff --git a/third_party/gmp/mpn/arm/v7a/cora8/bdiv_q_1.asm b/third_party/gmp/mpn/arm/v7a/cora8/bdiv_q_1.asm
new file mode 100644
index 0000000..e74b260
--- /dev/null
+++ b/third_party/gmp/mpn/arm/v7a/cora8/bdiv_q_1.asm
@@ -0,0 +1,158 @@
+dnl  ARM v6 mpn_bdiv_q_1, mpn_pi1_bdiv_q_1 -- Hensel division by 1-limb divisor.
+dnl  This is v6 code but it runs well on just the v7a Cortex-A8, A9, and A15.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2012, 2013, 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C               cycles/limb
+C               norm   unorm
+C 1176		 -	 -
+C Cortex-A5	 9	13
+C Cortex-A7	12	18
+C Cortex-A8	13	14
+C Cortex-A9	 9	10		not measured since latest edits
+C Cortex-A15	 7	 7
+C Cortex-A53	16	24
+
+C Architecture requirements:
+C v5	-
+C v5t	clz
+C v5te	-
+C v6	umaal
+C v6t2	-
+C v7a	-
+
+define(`rp',  `r0')
+define(`up',  `r1')
+define(`n',   `r2')
+define(`d',   `r3')
+define(`di_arg',  `sp[0]')		C	just mpn_pi1_bdiv_q_1
+define(`cnt_arg', `sp[4]')		C	just mpn_pi1_bdiv_q_1
+
+define(`cy',  `r7')
+define(`cnt', `r6')
+define(`tnc', `r4')
+
+ASM_START()
+PROLOGUE(mpn_bdiv_q_1)
+	push	{r6-r11}
+
+	rsb	r10, d, #0
+	and	r10, r10, d
+	clz	r10, r10
+	rsbs	cnt, r10, #31		C count_trailing_zeros
+	mov	d, d, lsr cnt
+
+C binvert limb
+	LEA(	r10, binvert_limb_table)
+	and	r12, d, #254
+	ldrb	r10, [r10, r12, lsr #1]
+	mul	r12, r10, r10
+	mul	r12, d, r12
+	rsb	r12, r12, r10, lsl #1
+	mul	r10, r12, r12
+	mul	r10, d, r10
+	rsb	r10, r10, r12, lsl #1	C r10 = inverse
+	b	L(pi1)
+EPILOGUE()
+
+PROLOGUE(mpn_pi1_bdiv_q_1)
+	push	{r6-r11}
+
+	ldr	cnt, [sp, #28]
+	ldr	r10, [sp, #24]
+	cmp	cnt, #0
+
+L(pi1):	ldr	r11, [up], #4		C up[0]
+	mov	cy, #0
+	rsb	r8, r10, #0		C r8 = -inverse
+	bne	L(unorm)
+
+L(norm):
+	subs	n, n, #1
+	mul	r11, r11, r10
+	beq	L(edn)
+
+	ALIGN(16)
+L(tpn):	ldr	r9, [up], #4
+	mov	r12, #0
+	str	r11, [rp], #4
+	umaal	r12, cy, r11, d
+	mul	r11, r9, r10
+	mla	r11, cy, r8, r11
+	subs	n, n, #1
+	bne	L(tpn)
+
+L(edn):	str	r11, [rp]
+	pop	{r6-r11}
+	bx	r14
+
+L(unorm):
+	push	{r4-r5}
+	rsb	tnc, cnt, #32
+	mov	r5, r11, lsr cnt
+	subs	n, n, #1
+	beq	L(ed1)
+
+	ldr	r12, [up], #4
+	orr	r9, r5, r12, lsl tnc
+	mov	r5, r12, lsr cnt
+	mul	r11, r9, r10
+	subs	n, n, #1
+	beq	L(edu)
+
+	ALIGN(16)
+L(tpu):	ldr	r12, [up], #4
+	orr	r9, r5, r12, lsl tnc
+	mov	r5, r12, lsr cnt
+	mov	r12, #0
+	str	r11, [rp], #4
+	umaal	r12, cy, r11, d
+	mul	r11, r9, r10
+	mla	r11, cy, r8, r11
+	subs	n, n, #1
+	bne	L(tpu)
+
+L(edu):	str	r11, [rp], #4
+	mov	r12, #0
+	umaal	r12, cy, r11, d
+	mul	r11, r5, r10
+	mla	r11, cy, r8, r11
+	str	r11, [rp]
+	pop	{r4-r11}
+	bx	r14
+
+L(ed1):	mul	r11, r5, r10
+	str	r11, [rp]
+	pop	{r4-r11}
+	bx	r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm/v7a/cora8/gmp-mparam.h b/third_party/gmp/mpn/arm/v7a/cora8/gmp-mparam.h
new file mode 100644
index 0000000..5864841
--- /dev/null
+++ b/third_party/gmp/mpn/arm/v7a/cora8/gmp-mparam.h
@@ -0,0 +1,207 @@
+/* gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+/* 1000 MHz Cortex-A8 (beaglebone black) */
+/* FFT tuning limit = 9,464,348 */
+/* Generated by tuneup.c, 2019-10-23, gcc 6.3 */
+
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          5
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          5
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD     MP_SIZE_T_MAX
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD         0  /* never mpn_mod_1s_2p */
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     12
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1N_PI1_METHOD                 1  /* 50.65% faster than 2 */
+#define DIV_QR_1_NORM_THRESHOLD          MP_SIZE_T_MAX  /* never */
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           31
+
+#define DIV_1_VS_MUL_1_PERCENT             192
+
+#define MUL_TOOM22_THRESHOLD                39
+#define MUL_TOOM33_THRESHOLD               129
+#define MUL_TOOM44_THRESHOLD               226
+#define MUL_TOOM6H_THRESHOLD               366
+#define MUL_TOOM8H_THRESHOLD               620
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD     141
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     183
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     154
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     160
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     193
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 46
+#define SQR_TOOM3_THRESHOLD                145
+#define SQR_TOOM4_THRESHOLD                375
+#define SQR_TOOM6_THRESHOLD                  0  /* always */
+#define SQR_TOOM8_THRESHOLD                547
+
+#define MULMID_TOOM42_THRESHOLD             38
+
+#define MULMOD_BNM1_THRESHOLD               22
+#define SQRMOD_BNM1_THRESHOLD               23
+
+#define MUL_FFT_MODF_THRESHOLD             476  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    476, 5}, {     28, 6}, {     15, 5}, {     31, 6}, \
+    {     28, 7}, {     15, 6}, {     33, 7}, {     19, 6}, \
+    {     39, 7}, {     27, 8}, {     15, 7}, {     35, 8}, \
+    {     19, 7}, {     43, 8}, {     23, 7}, {     51, 8}, \
+    {     27, 7}, {     55, 8}, {     31, 7}, {     63, 8}, \
+    {     43, 9}, {     23, 8}, {     55, 9}, {     31, 8}, \
+    {     71, 9}, {     39, 8}, {     83, 9}, {     47, 8}, \
+    {     99, 9}, {     55,10}, {     31, 9}, {     87,10}, \
+    {     47, 9}, {    103,11}, {     31,10}, {     63, 9}, \
+    {    135,10}, {     79, 9}, {    167,10}, {     95, 9}, \
+    {    199,10}, {    111,11}, {     63,10}, {    127, 9}, \
+    {    255,10}, {    143, 9}, {    287, 8}, {    575,10}, \
+    {    159, 9}, {    319,11}, {     95,10}, {    191, 9}, \
+    {    383, 8}, {    767, 9}, {    399,10}, {    207,12}, \
+    {     63,11}, {    127,10}, {    255, 9}, {    511,10}, \
+    {    271, 9}, {    543,10}, {    287, 9}, {    575,11}, \
+    {    159,10}, {    319, 9}, {    639,10}, {    335, 9}, \
+    {    671,10}, {    351, 9}, {    703,10}, {    367,11}, \
+    {    191,10}, {    399, 9}, {    799,10}, {    415,11}, \
+    {    223,12}, {    127,11}, {    255,10}, {    543,11}, \
+    {    287,10}, {    607, 9}, {   1215,11}, {    319,10}, \
+    {    671,11}, {    351,10}, {    703,12}, {    191,11}, \
+    {    383,10}, {    799,11}, {    415,10}, {    863,11}, \
+    {    447,13}, {    127,12}, {    255,11}, {    543,10}, \
+    {   1087,11}, {    607,12}, {    319,11}, {    671,10}, \
+    {   1343,11}, {    735,12}, {    383,11}, {    799,10}, \
+    {   1599,11}, {    863,12}, {    447,11}, {    959,13}, \
+    {    255,12}, {    511,11}, {   1087,12}, {    575,11}, \
+    {   1215,12}, {    639,11}, {   1343,12}, {    703,13}, \
+    {    383,12}, {    767,11}, {   1599,12}, {    831,11}, \
+    {   1663,12}, {    959,14}, {    255,13}, {    511,12}, \
+    {   1215,13}, {    639,12}, {   1407,13}, {    767,12}, \
+    {   1663,13}, {    895,12}, {   1791,14}, {    511,13}, \
+    {   1023,12}, {   2111,13}, {   1151,12}, {   4096,13}, \
+    {   8192,14}, {  16384,15}, {  32768,16} }
+#define MUL_FFT_TABLE3_SIZE 139
+#define MUL_FFT_THRESHOLD                 6784
+
+#define SQR_FFT_MODF_THRESHOLD             436  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    436, 5}, {     25, 6}, {     13, 5}, {     27, 6}, \
+    {     28, 7}, {     15, 6}, {     32, 7}, {     17, 6}, \
+    {     35, 7}, {     19, 6}, {     39, 7}, {     29, 8}, \
+    {     15, 7}, {     35, 8}, {     19, 7}, {     41, 8}, \
+    {     23, 7}, {     49, 8}, {     27, 9}, {     15, 8}, \
+    {     43, 9}, {     23, 8}, {     55,10}, {     15, 9}, \
+    {     31, 8}, {     67, 9}, {     39, 8}, {     79, 9}, \
+    {     47, 8}, {     95, 9}, {     55,10}, {     31, 9}, \
+    {     79,10}, {     47, 9}, {    103,11}, {     31,10}, \
+    {     63, 9}, {    135,10}, {     79, 9}, {    159, 8}, \
+    {    319, 9}, {    167,10}, {     95, 9}, {    191,10}, \
+    {    111,11}, {     63,10}, {    127, 9}, {    255, 8}, \
+    {    511, 9}, {    271,10}, {    143, 9}, {    287, 8}, \
+    {    575, 9}, {    303,10}, {    159, 9}, {    319,11}, \
+    {     95,10}, {    191, 9}, {    383, 8}, {    767, 9}, \
+    {    399,12}, {     63,11}, {    127,10}, {    255, 9}, \
+    {    511,10}, {    271, 9}, {    543,10}, {    287, 9}, \
+    {    575,10}, {    303,11}, {    159,10}, {    319, 9}, \
+    {    639,10}, {    335, 9}, {    671,10}, {    351, 9}, \
+    {    703,10}, {    367,11}, {    191,10}, {    383, 9}, \
+    {    767,10}, {    399, 9}, {    799,10}, {    415, 9}, \
+    {    831,11}, {    223,10}, {    447,12}, {    127,11}, \
+    {    255,10}, {    511, 9}, {   1023,10}, {    543,11}, \
+    {    287,10}, {    607,11}, {    319,10}, {    671,11}, \
+    {    351,10}, {    735,12}, {    191,11}, {    383,10}, \
+    {    799,11}, {    415,10}, {    863,11}, {    447,10}, \
+    {    895,13}, {    127,12}, {    255,11}, {    511,10}, \
+    {   1023,11}, {    543,10}, {   1087,11}, {    607,12}, \
+    {    319,11}, {    671,10}, {   1343,11}, {    735,12}, \
+    {    383,11}, {    863,12}, {    447,11}, {    959,13}, \
+    {    255,12}, {    511,11}, {   1087,12}, {    575,11}, \
+    {   1215,12}, {    639,11}, {   1343,12}, {    703,11}, \
+    {   1407,13}, {    383,12}, {    767,11}, {   1599,12}, \
+    {    831,11}, {   1663,12}, {    959,14}, {    255,13}, \
+    {    511,12}, {   1215,13}, {    639,12}, {   1471,13}, \
+    {    767,12}, {   1663,13}, {    895,12}, {   1855,14}, \
+    {    511,13}, {   1023,12}, {   2111,13}, {   1151,12}, \
+    {   4096,13}, {   8192,14}, {  16384,15}, {  32768,16} }
+#define SQR_FFT_TABLE3_SIZE 152
+#define SQR_FFT_THRESHOLD                 3712
+
+#define MULLO_BASECASE_THRESHOLD            21
+#define MULLO_DC_THRESHOLD                   0  /* never mpn_mullo_basecase */
+#define MULLO_MUL_N_THRESHOLD            13463
+#define SQRLO_BASECASE_THRESHOLD             9
+#define SQRLO_DC_THRESHOLD                  17
+#define SQRLO_SQR_THRESHOLD               7246
+
+#define DC_DIV_QR_THRESHOLD                 27
+#define DC_DIVAPPR_Q_THRESHOLD              74
+#define DC_BDIV_QR_THRESHOLD                21
+#define DC_BDIV_Q_THRESHOLD                 64
+
+#define INV_MULMOD_BNM1_THRESHOLD           78
+#define INV_NEWTON_THRESHOLD                31
+#define INV_APPR_THRESHOLD                  37
+
+#define BINV_NEWTON_THRESHOLD              167
+#define REDC_1_TO_REDC_2_THRESHOLD           4
+#define REDC_2_TO_REDC_N_THRESHOLD         198
+
+#define MU_DIV_QR_THRESHOLD               1858
+#define MU_DIVAPPR_Q_THRESHOLD            1685
+#define MUPI_DIV_QR_THRESHOLD               43
+#define MU_BDIV_QR_THRESHOLD              1589
+#define MU_BDIV_Q_THRESHOLD               1685
+
+#define POWM_SEC_TABLE  1,13,96,487,1378
+
+#define GET_STR_DC_THRESHOLD                18
+#define GET_STR_PRECOMPUTE_THRESHOLD        36
+#define SET_STR_DC_THRESHOLD               145
+#define SET_STR_PRECOMPUTE_THRESHOLD       505
+
+#define FAC_DSC_THRESHOLD                  137
+#define FAC_ODD_THRESHOLD                   29
+
+#define MATRIX22_STRASSEN_THRESHOLD         24
+#define HGCD2_DIV1_METHOD                    5  /* 4.29% faster than 4 */
+#define HGCD_THRESHOLD                      39
+#define HGCD_APPR_THRESHOLD                 50
+#define HGCD_REDUCE_THRESHOLD             3524
+#define GCD_DC_THRESHOLD                   116
+#define GCDEXT_DC_THRESHOLD                124
+#define JACOBI_BASE_METHOD                   4  /* 5.89% faster than 1 */
+
+/* Tuneup completed successfully, took 48230 seconds */
diff --git a/third_party/gmp/mpn/arm/v7a/cora9/bdiv_q_1.asm b/third_party/gmp/mpn/arm/v7a/cora9/bdiv_q_1.asm
new file mode 100644
index 0000000..245b371
--- /dev/null
+++ b/third_party/gmp/mpn/arm/v7a/cora9/bdiv_q_1.asm
@@ -0,0 +1,36 @@
+dnl  ARM mpn_bdiv_q_1, mpn_pi1_bdiv_q_1 -- Hensel division by 1-limb divisor.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2012, 2013, 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+MULFUNC_PROLOGUE(mpn_bdiv_q_1 mpn_pi1_bdiv_q_1)
+include_mpn(`arm/v7a/cora8/bdiv_q_1.asm')
diff --git a/third_party/gmp/mpn/arm/v7a/cora9/gmp-mparam.h b/third_party/gmp/mpn/arm/v7a/cora9/gmp-mparam.h
new file mode 100644
index 0000000..5c54012
--- /dev/null
+++ b/third_party/gmp/mpn/arm/v7a/cora9/gmp-mparam.h
@@ -0,0 +1,211 @@
+/* gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 1999-2003, 2009, 2010, 2012-2015 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+/* 1000 MHz Cortex-A9 */
+/* FFT tuning limit = 25 M */
+/* Generated by tuneup.c, 2014-03-12, gcc 4.6 */
+
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          5
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          4
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD         8
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD     MP_SIZE_T_MAX
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     12
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1N_PI1_METHOD                 1
+#define DIV_QR_1_NORM_THRESHOLD              5
+#define DIV_QR_1_UNNORM_THRESHOLD            1
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           20
+
+#define DIV_1_VS_MUL_1_PERCENT             190
+
+#define MUL_TOOM22_THRESHOLD                45
+#define MUL_TOOM33_THRESHOLD               129
+#define MUL_TOOM44_THRESHOLD               387
+#define MUL_TOOM6H_THRESHOLD               537
+#define MUL_TOOM8H_THRESHOLD               774
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD     141
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     237
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     141
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     258
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     211
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 64
+#define SQR_TOOM3_THRESHOLD                189
+#define SQR_TOOM4_THRESHOLD                517
+#define SQR_TOOM6_THRESHOLD                656
+#define SQR_TOOM8_THRESHOLD                  0  /* always */
+
+#define MULMID_TOOM42_THRESHOLD             62
+
+#define MULMOD_BNM1_THRESHOLD               23
+#define SQRMOD_BNM1_THRESHOLD               28
+
+#define MUL_FFT_MODF_THRESHOLD             630  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    630, 5}, {     29, 6}, {     15, 5}, {     33, 6}, \
+    {     17, 5}, {     35, 6}, {     36, 7}, {     19, 6}, \
+    {     40, 7}, {     21, 6}, {     43, 7}, {     23, 6}, \
+    {     47, 7}, {     25, 6}, {     51, 7}, {     27, 6}, \
+    {     55, 7}, {     29, 8}, {     15, 7}, {     37, 8}, \
+    {     19, 7}, {     43, 8}, {     23, 7}, {     51, 8}, \
+    {     27, 7}, {     57, 9}, {     15, 8}, {     31, 7}, \
+    {     65, 8}, {     35, 7}, {     71, 8}, {     43, 9}, \
+    {     23, 8}, {     55, 9}, {     31, 8}, {     71, 9}, \
+    {     39, 8}, {     83, 9}, {     47, 8}, {     99, 9}, \
+    {     55,10}, {     31, 9}, {     79,10}, {     47, 9}, \
+    {    103,11}, {     31,10}, {     63, 9}, {    135,10}, \
+    {     79, 9}, {    167,10}, {     95, 9}, {    191,10}, \
+    {    111,11}, {     63,10}, {    159,11}, {     95,10}, \
+    {    191, 9}, {    383,12}, {     63,11}, {    127,10}, \
+    {    255, 9}, {    511,10}, {    271, 9}, {    543,11}, \
+    {    159,10}, {    319, 9}, {    639,10}, {    335, 9}, \
+    {    671,11}, {    191,10}, {    383, 9}, {    767,10}, \
+    {    399, 9}, {    799,10}, {    415,11}, {    223,12}, \
+    {    127,11}, {    255,10}, {    511, 9}, {   1023,10}, \
+    {    543,11}, {    287,10}, {    607,11}, {    319,10}, \
+    {    671,11}, {    351,12}, {    191,11}, {    383,10}, \
+    {    799,11}, {    415,10}, {    831,13}, {    127,12}, \
+    {    255,11}, {    511,10}, {   1023,11}, {    543,10}, \
+    {   1087,11}, {    607,12}, {    319,11}, {    735,12}, \
+    {    383,11}, {    831,12}, {    447,11}, {    927,13}, \
+    {    255,12}, {    511,11}, {   1087,12}, {    575,11}, \
+    {   1215,12}, {    639,11}, {   1343,12}, {    703,13}, \
+    {    383,12}, {    767,11}, {   1535,12}, {    831,11}, \
+    {   1663,12}, {    895,14}, {    255,13}, {    511,12}, \
+    {   1023,11}, {   2047,12}, {   1151,13}, {    639,12}, \
+    {   1407,13}, {    767,12}, {   1663,13}, {    895,12}, \
+    {   1791,14}, {    511,13}, {   1023,12}, {   2111,13}, \
+    {   1151,12}, {   2431,13}, {   1279,12}, {   2559,13}, \
+    {   1407,14}, {    767,13}, {   1535,12}, {   3071,13}, \
+    {   1663,12}, {   3455,13}, {   1791,15}, {    511,14}, \
+    {   1023,13}, {   2047,12}, {   4095,13}, {   2175,12}, \
+    {   4479,13}, {   2431,14}, {   1279,13}, {   2559,12}, \
+    {   5119,13}, {   2815,12}, {   5631,14}, {  16384,15}, \
+    {  32768,16} }
+#define MUL_FFT_TABLE3_SIZE 157
+#define MUL_FFT_THRESHOLD                 6784
+
+#define SQR_FFT_MODF_THRESHOLD             565  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    565, 5}, {     19, 4}, {     40, 5}, {     21, 4}, \
+    {     43, 5}, {     28, 6}, {     15, 5}, {     35, 6}, \
+    {     29, 7}, {     15, 6}, {     37, 7}, {     19, 6}, \
+    {     39, 7}, {     21, 6}, {     43, 7}, {     23, 6}, \
+    {     47, 7}, {     29, 8}, {     15, 7}, {     37, 8}, \
+    {     19, 7}, {     43, 8}, {     23, 7}, {     51, 8}, \
+    {     27, 7}, {     55, 9}, {     15, 8}, {     31, 7}, \
+    {     65, 8}, {     35, 7}, {     71, 8}, {     43, 9}, \
+    {     23, 8}, {     55,10}, {     15, 9}, {     31, 8}, \
+    {     71, 9}, {     39, 8}, {     83, 9}, {     47, 8}, \
+    {     95, 9}, {     55,10}, {     31, 9}, {     79,10}, \
+    {     47, 9}, {    103,11}, {     31,10}, {     63, 9}, \
+    {    135,10}, {     79, 9}, {    159,10}, {     95, 9}, \
+    {    191,10}, {    111,11}, {     63,10}, {    159,11}, \
+    {     95,10}, {    191, 9}, {    383,12}, {     63,11}, \
+    {    127,10}, {    255, 9}, {    511, 8}, {   1023, 9}, \
+    {    527,10}, {    271, 9}, {    543,10}, {    287,11}, \
+    {    159, 9}, {    639,10}, {    335, 9}, {    671,10}, \
+    {    351,11}, {    191,10}, {    383, 9}, {    767,10}, \
+    {    399, 9}, {    799,10}, {    415,11}, {    223,12}, \
+    {    127,11}, {    255,10}, {    511, 9}, {   1023,10}, \
+    {    543,11}, {    287,10}, {    671,11}, {    351,12}, \
+    {    191,11}, {    383,10}, {    799,11}, {    415,10}, \
+    {    831,13}, {    127,12}, {    255,11}, {    511,10}, \
+    {   1023,11}, {    543,10}, {   1087,11}, {    735,12}, \
+    {    383,11}, {    831,12}, {    447,11}, {    927,13}, \
+    {    255,12}, {    511,11}, {   1087,12}, {    575,11}, \
+    {   1151,12}, {    639,11}, {   1343,12}, {    703,13}, \
+    {    383,12}, {    767,11}, {   1535,12}, {    831,11}, \
+    {   1663,12}, {    959,13}, {    511,12}, {   1023,11}, \
+    {   2047,12}, {   1151,13}, {    639,12}, {   1407,13}, \
+    {    767,12}, {   1599,13}, {    895,12}, {   1791,14}, \
+    {    511,13}, {   1023,12}, {   2111,13}, {   1151,12}, \
+    {   2431,13}, {   1279,12}, {   2559,13}, {   1407,14}, \
+    {    767,13}, {   1535,12}, {   3071,13}, {   1663,12}, \
+    {   3455,13}, {   1791,15}, {    511,14}, {   1023,13}, \
+    {   2047,12}, {   4095,13}, {   2175,12}, {   4479,13}, \
+    {   2303,14}, {   1279,13}, {   2559,12}, {   5119,13}, \
+    {   2815,14}, {  16384,15}, {  32768,16} }
+#define SQR_FFT_TABLE3_SIZE 155
+#define SQR_FFT_THRESHOLD                 5568
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  37
+#define MULLO_MUL_N_THRESHOLD            13463
+#define SQRLO_BASECASE_THRESHOLD            12
+#define SQRLO_DC_THRESHOLD                  22
+#define SQRLO_SQR_THRESHOLD              10950
+
+#define DC_DIV_QR_THRESHOLD                 32
+#define DC_DIVAPPR_Q_THRESHOLD              99
+#define DC_BDIV_QR_THRESHOLD                43
+#define DC_BDIV_Q_THRESHOLD                102
+
+#define INV_MULMOD_BNM1_THRESHOLD           88
+#define INV_NEWTON_THRESHOLD               141
+#define INV_APPR_THRESHOLD                 111
+
+#define BINV_NEWTON_THRESHOLD              312
+#define REDC_1_TO_REDC_2_THRESHOLD           6
+#define REDC_2_TO_REDC_N_THRESHOLD         140
+
+#define MU_DIV_QR_THRESHOLD               2492
+#define MU_DIVAPPR_Q_THRESHOLD            2130
+#define MUPI_DIV_QR_THRESHOLD               55
+#define MU_BDIV_QR_THRESHOLD              2130
+#define MU_BDIV_Q_THRESHOLD               2172
+
+#define POWM_SEC_TABLE  40,53,56,71,1985
+
+#define GET_STR_DC_THRESHOLD                16
+#define GET_STR_PRECOMPUTE_THRESHOLD        33
+#define SET_STR_DC_THRESHOLD               172
+#define SET_STR_PRECOMPUTE_THRESHOLD       671
+
+#define FAC_DSC_THRESHOLD                  309
+#define FAC_ODD_THRESHOLD                   29
+
+#define MATRIX22_STRASSEN_THRESHOLD         24
+#define HGCD_THRESHOLD                      61
+#define HGCD_APPR_THRESHOLD                 50
+#define HGCD_REDUCE_THRESHOLD             4120
+#define GCD_DC_THRESHOLD                   408
+#define GCDEXT_DC_THRESHOLD                303
+#define JACOBI_BASE_METHOD                   4
diff --git a/third_party/gmp/mpn/arm64/aors_n.asm b/third_party/gmp/mpn/arm64/aors_n.asm
new file mode 100644
index 0000000..b1f3bb9
--- /dev/null
+++ b/third_party/gmp/mpn/arm64/aors_n.asm
@@ -0,0 +1,125 @@
+dnl  ARM64 mpn_add_n and mpn_sub_n
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013, 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C Cortex-A53	2.75-3.25
+C Cortex-A57	 1.5
+C X-Gene	 2.0
+
+changecom(blah)
+
+define(`rp', `x0')
+define(`up', `x1')
+define(`vp', `x2')
+define(`n',  `x3')
+
+ifdef(`OPERATION_add_n', `
+  define(`ADDSUBC',	adcs)
+  define(`CLRCY',	`cmn	xzr, xzr')
+  define(`SETCY',	`cmp	$1, #1')
+  define(`RETVAL',	`cset	x0, cs')
+  define(`func_n',	mpn_add_n)
+  define(`func_nc',	mpn_add_nc)')
+ifdef(`OPERATION_sub_n', `
+  define(`ADDSUBC',	sbcs)
+  define(`CLRCY',	`cmp	xzr, xzr')
+  define(`SETCY',	`cmp	xzr, $1')
+  define(`RETVAL',	`cset	x0, cc')
+  define(`func_n',	mpn_sub_n)
+  define(`func_nc',	mpn_sub_nc)')
+
+MULFUNC_PROLOGUE(mpn_add_n mpn_add_nc mpn_sub_n mpn_sub_nc)
+
+ASM_START()
+PROLOGUE(func_nc)
+	SETCY(	x4)
+	b	L(ent)
+EPILOGUE()
+PROLOGUE(func_n)
+	CLRCY
+L(ent):	lsr	x18, n, #2
+	tbz	n, #0, L(bx0)
+
+L(bx1):	ldr	x7, [up]
+	ldr	x11, [vp]
+	ADDSUBC	x13, x7, x11
+	str	x13, [rp],#8
+	tbnz	n, #1, L(b11)
+
+L(b01):	cbz	x18, L(ret)
+	ldp	x4, x5, [up,#8]
+	ldp	x8, x9, [vp,#8]
+	sub	up, up, #8
+	sub	vp, vp, #8
+	b	L(mid)
+
+L(b11):	ldp	x6, x7, [up,#8]
+	ldp	x10, x11, [vp,#8]
+	add	up, up, #8
+	add	vp, vp, #8
+	cbz	x18, L(end)
+	b	L(top)
+
+L(bx0):	tbnz	n, #1, L(b10)
+
+L(b00):	ldp	x4, x5, [up]
+	ldp	x8, x9, [vp]
+	sub	up, up, #16
+	sub	vp, vp, #16
+	b	L(mid)
+
+L(b10):	ldp	x6, x7, [up]
+	ldp	x10, x11, [vp]
+	cbz	x18, L(end)
+
+	ALIGN(16)
+L(top):	ldp	x4, x5, [up,#16]
+	ldp	x8, x9, [vp,#16]
+	ADDSUBC	x12, x6, x10
+	ADDSUBC	x13, x7, x11
+	stp	x12, x13, [rp],#16
+L(mid):	ldp	x6, x7, [up,#32]!
+	ldp	x10, x11, [vp,#32]!
+	ADDSUBC	x12, x4, x8
+	ADDSUBC	x13, x5, x9
+	stp	x12, x13, [rp],#16
+	sub	x18, x18, #1
+	cbnz	x18, L(top)
+
+L(end):	ADDSUBC	x12, x6, x10
+	ADDSUBC	x13, x7, x11
+	stp	x12, x13, [rp]
+L(ret):	RETVAL
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm64/aorsmul_1.asm b/third_party/gmp/mpn/arm64/aorsmul_1.asm
new file mode 100644
index 0000000..fd3c36e
--- /dev/null
+++ b/third_party/gmp/mpn/arm64/aorsmul_1.asm
@@ -0,0 +1,140 @@
+dnl  ARM64 mpn_addmul_1 and mpn_submul_1
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013, 2015, 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C Cortex-A53	9.3-9.8
+C Cortex-A57	 7.0
+C X-Gene	 5.0
+
+C NOTES
+C  * It is possible to keep the carry chain alive between the addition blocks
+C    and thus avoid csinc, but only for addmul_1.  Since that saves no time
+C    on the tested pipelines, we keep addmul_1 and submul_1 similar.
+C  * We could separate feed-in into 4 blocks, one for each residue (mod 4).
+C    That is likely to save a few cycles.
+
+changecom(blah)
+
+define(`rp', `x0')
+define(`up', `x1')
+define(`n',  `x2')
+define(`v0', `x3')
+
+ifdef(`OPERATION_addmul_1', `
+  define(`ADDSUB',	adds)
+  define(`ADDSUBC',	adcs)
+  define(`COND',	`cc')
+  define(`func',	mpn_addmul_1)')
+ifdef(`OPERATION_submul_1', `
+  define(`ADDSUB',	subs)
+  define(`ADDSUBC',	sbcs)
+  define(`COND',	`cs')
+  define(`func',	mpn_submul_1)')
+
+MULFUNC_PROLOGUE(mpn_addmul_1 mpn_submul_1)
+
+PROLOGUE(func)
+	adds	x15, xzr, xzr
+
+	tbz	n, #0, L(1)
+
+	ldr	x4, [up],#8
+	mul	x8, x4, v0
+	umulh	x12, x4, v0
+	ldr	x4, [rp]
+	ADDSUB	x8, x4, x8
+	csinc	x15, x12, x12, COND
+	str	x8, [rp],#8
+
+L(1):	tbz	n, #1, L(2)
+
+	ldp	x4, x5, [up],#16
+	mul	x8, x4, v0
+	umulh	x12, x4, v0
+	mul	x9, x5, v0
+	umulh	x13, x5, v0
+	adds	x8, x8, x15
+	adcs	x9, x9, x12
+	ldp	x4, x5, [rp]
+	adc	x15, x13, xzr
+	ADDSUB	x8, x4, x8
+	ADDSUBC	x9, x5, x9
+	csinc	x15, x15, x15, COND
+	stp	x8, x9, [rp],#16
+
+L(2):	lsr	n, n, #2
+	cbz	n, L(le3)
+	ldp	x4, x5, [up],#32
+	ldp	x6, x7, [up,#-16]
+	b	L(mid)
+L(le3):	mov	x0, x15
+	ret
+
+	ALIGN(16)
+L(top):	ldp	x4, x5, [up],#32
+	ldp	x6, x7, [up,#-16]
+	ADDSUB	x8, x16, x8
+	ADDSUBC	x9, x17, x9
+	stp	x8, x9, [rp],#32
+	ADDSUBC	x10, x12, x10
+	ADDSUBC	x11, x13, x11
+	stp	x10, x11, [rp,#-16]
+	csinc	x15, x15, x15, COND
+L(mid):	sub	n, n, #1
+	mul	x8, x4, v0
+	umulh	x12, x4, v0
+	mul	x9, x5, v0
+	umulh	x13, x5, v0
+	adds	x8, x8, x15
+	mul	x10, x6, v0
+	umulh	x14, x6, v0
+	adcs	x9, x9, x12
+	mul	x11, x7, v0
+	umulh	x15, x7, v0
+	adcs	x10, x10, x13
+	ldp	x16, x17, [rp]
+	adcs	x11, x11, x14
+	ldp	x12, x13, [rp,#16]
+	adc	x15, x15, xzr
+	cbnz	n, L(top)
+
+	ADDSUB	x8, x16, x8
+	ADDSUBC	x9, x17, x9
+	ADDSUBC	x10, x12, x10
+	ADDSUBC	x11, x13, x11
+	stp	x8, x9, [rp]
+	stp	x10, x11, [rp,#16]
+	csinc	x0, x15, x15, COND
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm64/aorsorrlsh1_n.asm b/third_party/gmp/mpn/arm64/aorsorrlsh1_n.asm
new file mode 100644
index 0000000..c617a67
--- /dev/null
+++ b/third_party/gmp/mpn/arm64/aorsorrlsh1_n.asm
@@ -0,0 +1,43 @@
+dnl  ARM64 mpn_addlsh1_n, mpn_sublsh1_n, mpn_rsblsh1_n.
+
+dnl  Copyright 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+define(LSH,		1)
+define(RSH,		63)
+
+ifdef(`OPERATION_addlsh1_n',`define(`DO_add')')
+ifdef(`OPERATION_sublsh1_n',`define(`DO_sub')')
+ifdef(`OPERATION_rsblsh1_n',`define(`DO_rsb')')
+
+MULFUNC_PROLOGUE(mpn_addlsh1_n mpn_sublsh1_n mpn_rsblsh1_n)
+
+include_mpn(`arm64/aorsorrlshC_n.asm')
diff --git a/third_party/gmp/mpn/arm64/aorsorrlsh2_n.asm b/third_party/gmp/mpn/arm64/aorsorrlsh2_n.asm
new file mode 100644
index 0000000..852d117
--- /dev/null
+++ b/third_party/gmp/mpn/arm64/aorsorrlsh2_n.asm
@@ -0,0 +1,43 @@
+dnl  ARM64 mpn_addlsh2_n, mpn_sublsh2_n, mpn_rsblsh2_n.
+
+dnl  Copyright 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+define(LSH,		2)
+define(RSH,		62)
+
+ifdef(`OPERATION_addlsh2_n',`define(`DO_add')')
+ifdef(`OPERATION_sublsh2_n',`define(`DO_sub')')
+ifdef(`OPERATION_rsblsh2_n',`define(`DO_rsb')')
+
+MULFUNC_PROLOGUE(mpn_addlsh2_n mpn_sublsh2_n mpn_rsblsh2_n)
+
+include_mpn(`arm64/aorsorrlshC_n.asm')
diff --git a/third_party/gmp/mpn/arm64/aorsorrlshC_n.asm b/third_party/gmp/mpn/arm64/aorsorrlshC_n.asm
new file mode 100644
index 0000000..168caad
--- /dev/null
+++ b/third_party/gmp/mpn/arm64/aorsorrlshC_n.asm
@@ -0,0 +1,139 @@
+dnl  ARM64 mpn_addlshC_n, mpn_sublshC_n, mpn_rsblshC_n.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C Cortex-A53	3.25-3.75
+C Cortex-A57	 2.18
+C X-Gene	 2.5
+
+changecom(blah)
+
+define(`rp', `x0')
+define(`up', `x1')
+define(`vp', `x2')
+define(`n',  `x3')
+
+ifdef(`DO_add', `
+  define(`ADDSUB',	`adds	$1, $2, $3')
+  define(`ADDSUBC',	`adcs	$1, $2, $3')
+  define(`CLRRCY',	`adds	$1, xzr, xzr')
+  define(`RETVAL',	`adc	x0, $1, xzr')
+  define(`func_n',	mpn_addlsh`'LSH`'_n)')
+ifdef(`DO_sub', `
+  define(`ADDSUB',	`subs	$1, $3, $2')
+  define(`ADDSUBC',	`sbcs	$1, $3, $2')
+  define(`CLRRCY',	`subs	$1, xzr, xzr')
+  define(`RETVAL',	`cinc	x0, $1, cc')
+  define(`func_n',	mpn_sublsh`'LSH`'_n)')
+ifdef(`DO_rsb', `
+  define(`ADDSUB',	`subs	$1, $2, $3')
+  define(`ADDSUBC',	`sbcs	$1, $2, $3')
+  define(`CLRRCY',	`subs	$1, xzr, xzr')
+  define(`RETVAL',	`sbc	x0, $1, xzr')
+  define(`func_n',	mpn_rsblsh`'LSH`'_n)')
+
+ASM_START()
+PROLOGUE(func_n)
+	lsr	x18, n, #2
+	tbz	n, #0, L(bx0)
+
+L(bx1):	ldr	x5, [up]
+	tbnz	n, #1, L(b11)
+
+L(b01):	ldr	x11, [vp]
+	cbz	x18, L(1)
+	ldp	x8, x9, [vp,#8]
+	lsl	x13, x11, #LSH
+	ADDSUB(	x15, x13, x5)
+	str	x15, [rp],#8
+	sub	up, up, #24
+	sub	vp, vp, #8
+	b	L(mid)
+
+L(1):	lsl	x13, x11, #LSH
+	ADDSUB(	x15, x13, x5)
+	str	x15, [rp]
+	lsr	x0, x11, RSH
+	RETVAL(	 x0, x1)
+	ret
+
+L(b11):	ldr	x9, [vp]
+	ldp	x10, x11, [vp,#8]!
+	lsl	x13, x9, #LSH
+	ADDSUB(	x17, x13, x5)
+	str	x17, [rp],#8
+	sub	up, up, #8
+	cbz	x18, L(end)
+	b	L(top)
+
+L(bx0):	tbnz	n, #1, L(b10)
+
+L(b00):	CLRRCY(	x11)
+	ldp	x8, x9, [vp],#-16
+	sub	up, up, #32
+	b	L(mid)
+
+L(b10):	CLRRCY(	x9)
+	ldp	x10, x11, [vp]
+	sub	up, up, #16
+	cbz	x18, L(end)
+
+	ALIGN(16)
+L(top):	ldp	x4, x5, [up,#16]
+	extr	x12, x10, x9, #RSH
+	ldp	x8, x9, [vp,#16]
+	extr	x13, x11, x10, #RSH
+	ADDSUBC(x14, x12, x4)
+	ADDSUBC(x15, x13, x5)
+	stp	x14, x15, [rp],#16
+L(mid):	ldp	x4, x5, [up,#32]!
+	extr	x12, x8, x11, #RSH
+	ldp	x10, x11, [vp,#32]!
+	extr	x13, x9, x8, #RSH
+	ADDSUBC(x16, x12, x4)
+	ADDSUBC(x17, x13, x5)
+	stp	x16, x17, [rp],#16
+	sub	x18, x18, #1
+	cbnz	x18, L(top)
+
+L(end):	ldp	x4, x5, [up,#16]
+	extr	x12, x10, x9, #RSH
+	extr	x13, x11, x10, #RSH
+	ADDSUBC(x14, x12, x4)
+	ADDSUBC(x15, x13, x5)
+	stp	x14, x15, [rp]
+	lsr	x0, x11, RSH
+	RETVAL(	 x0, x1)
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm64/bdiv_dbm1c.asm b/third_party/gmp/mpn/arm64/bdiv_dbm1c.asm
new file mode 100644
index 0000000..78984b4
--- /dev/null
+++ b/third_party/gmp/mpn/arm64/bdiv_dbm1c.asm
@@ -0,0 +1,111 @@
+dnl  ARM64 mpn_bdiv_dbm1c.
+
+dnl  Copyright 2008, 2011, 2012, 2014 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C Cortex-A53	 8
+C Cortex-A57	 7
+C X-Gene	 4.25
+
+define(`qp',	  `x0')
+define(`up',	  `x1')
+define(`n',	  `x2')
+define(`bd',	  `x3')
+define(`cy',	  `x4')
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_bdiv_dbm1c)
+	ldr	x5, [up], #8
+	ands	x6, n, #3
+	b.eq	L(fi0)
+	cmp	x6, #2
+	b.cc	L(fi1)
+	b.eq	L(fi2)
+
+L(fi3):	mul	x12, x5, bd
+	umulh	x13, x5, bd
+	ldr	x5, [up], #8
+	b	L(lo3)
+
+L(fi0):	mul	x10, x5, bd
+	umulh	x11, x5, bd
+	ldr	x5, [up], #8
+	b	L(lo0)
+
+L(fi1):	subs	n, n, #1
+	mul	x12, x5, bd
+	umulh	x13, x5, bd
+	b.ls	L(wd1)
+	ldr	x5, [up], #8
+	b	L(lo1)
+
+L(fi2):	mul	x10, x5, bd
+	umulh	x11, x5, bd
+	ldr	x5, [up], #8
+	b	L(lo2)
+
+L(top):	ldr	x5, [up], #8
+	subs	x4, x4, x10
+	str	x4, [qp], #8
+	sbc	x4, x4, x11
+L(lo1):	mul	x10, x5, bd
+	umulh	x11, x5, bd
+	ldr	x5, [up], #8
+	subs	x4, x4, x12
+	str	x4, [qp], #8
+	sbc	x4, x4, x13
+L(lo0):	mul	x12, x5, bd
+	umulh	x13, x5, bd
+	ldr	x5, [up], #8
+	subs	x4, x4, x10
+	str	x4, [qp], #8
+	sbc	x4, x4, x11
+L(lo3):	mul	x10, x5, bd
+	umulh	x11, x5, bd
+	ldr	x5, [up], #8
+	subs	x4, x4, x12
+	str	x4, [qp], #8
+	sbc	x4, x4, x13
+L(lo2):	subs	n, n, #4
+	mul	x12, x5, bd
+	umulh	x13, x5, bd
+	b.hi	L(top)
+
+L(wd2):	subs	x4, x4, x10
+	str	x4, [qp], #8
+	sbc	x4, x4, x11
+L(wd1):	subs	x4, x4, x12
+	str	x4, [qp]
+	sbc	x0, x4, x13
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm64/bdiv_q_1.asm b/third_party/gmp/mpn/arm64/bdiv_q_1.asm
new file mode 100644
index 0000000..2e189b8
--- /dev/null
+++ b/third_party/gmp/mpn/arm64/bdiv_q_1.asm
@@ -0,0 +1,128 @@
+dnl  ARM64 mpn_bdiv_q_1, mpn_pi1_bdiv_q_1 -- Hensel division by 1-limb divisor.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2012, 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C               cycles/limb
+C               norm   unorm
+C Cortex-A53	12	15
+C Cortex-A57	12	12
+C Cortex-A72
+C Cortex-A73
+C X-Gene	11	11
+
+C TODO
+C  * Scheduling of umulh later in the unorm loop brings A53 time to 12 c/l.
+C    Unfortunately, that requires software pipelining.
+
+define(`rp',  `x0')
+define(`up',  `x1')
+define(`n',   `x2')
+define(`d',   `x3')
+define(`di',  `x4')		C	just mpn_pi1_bdiv_q_1
+define(`cnt', `x5')		C	just mpn_pi1_bdiv_q_1
+
+define(`cy',  `r7')
+define(`tnc', `x8')
+
+ASM_START()
+PROLOGUE(mpn_bdiv_q_1)
+
+	rbit	x6, d
+	clz	cnt, x6
+	lsr	d, d, cnt
+
+ifdef(`PIC',`
+	adrp	x7, :got:__gmp_binvert_limb_table
+	ubfx	x6, d, 1, 7
+	ldr	x7, [x7, #:got_lo12:__gmp_binvert_limb_table]
+',`
+	adrp	x7, __gmp_binvert_limb_table
+	ubfx	x6, d, 1, 7
+	add	x7, x7, :lo12:__gmp_binvert_limb_table
+')
+	ldrb	w6, [x7, x6]
+	ubfiz	x7, x6, 1, 8
+	umull	x6, w6, w6
+	msub	x6, x6, d, x7
+	lsl	x7, x6, 1
+	mul	x6, x6, x6
+	msub	x6, x6, d, x7
+	lsl	x7, x6, 1
+	mul	x6, x6, x6
+	msub	di, x6, d, x7
+
+	b	mpn_pi1_bdiv_q_1
+EPILOGUE()
+
+PROLOGUE(mpn_pi1_bdiv_q_1)
+	sub	n, n, #1
+	subs	x6, x6, x6		C clear r6 and C flag
+	ldr	x9, [up],#8
+	cbz	cnt, L(norm)
+
+L(unorm):
+	lsr	x12, x9, cnt
+	cbz	n, L(eu1)
+	sub	tnc, xzr, cnt
+
+L(tpu):	ldr	x9, [up],#8
+	lsl	x7, x9, tnc
+	orr	x7, x7, x12
+	sbcs	x6, x7, x6
+	mul	x7, x6, di
+	str	x7, [rp],#8
+	lsr	x12, x9, cnt
+	umulh	x6, x7, d
+	sub	n, n, #1
+	cbnz	n, L(tpu)
+
+L(eu1):	sbcs	x6, x12, x6
+	mul	x6, x6, di
+	str	x6, [rp]
+	ret
+
+L(norm):
+	mul	x5, x9, di
+	str	x5, [rp],#8
+	cbz	n, L(en1)
+
+L(tpn):	ldr	x9, [up],#8
+	umulh	x5, x5, d
+	sbcs	x5, x9, x5
+	mul	x5, x5, di
+	str	x5, [rp],#8
+	sub	n, n, #1
+	cbnz	n, L(tpn)
+
+L(en1):	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm64/cnd_aors_n.asm b/third_party/gmp/mpn/arm64/cnd_aors_n.asm
new file mode 100644
index 0000000..39e6cd3
--- /dev/null
+++ b/third_party/gmp/mpn/arm64/cnd_aors_n.asm
@@ -0,0 +1,129 @@
+dnl  ARM64 mpn_cnd_add_n, mpn_cnd_sub_n
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2012, 2013, 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C Cortex-A53	3.87-4.37
+C Cortex-A57	 1.75
+C X-Gene	 2.0
+
+changecom(blah)
+
+define(`cnd',	`x0')
+define(`rp',	`x1')
+define(`up',	`x2')
+define(`vp',	`x3')
+define(`n',	`x4')
+
+ifdef(`OPERATION_cnd_add_n', `
+  define(`ADDSUBC',	adcs)
+  define(`CLRCY',	`cmn	xzr, xzr')
+  define(`RETVAL',	`cset	x0, cs')
+  define(`func',	mpn_cnd_add_n)')
+ifdef(`OPERATION_cnd_sub_n', `
+  define(`ADDSUBC',	sbcs)
+  define(`CLRCY',	`cmp	xzr, xzr')
+  define(`RETVAL',	`cset	x0, cc')
+  define(`func',	mpn_cnd_sub_n)')
+
+MULFUNC_PROLOGUE(mpn_cnd_add_n mpn_cnd_sub_n)
+
+ASM_START()
+PROLOGUE(func)
+	cmp	cnd, #1
+	sbc	cnd, cnd, cnd
+
+	CLRCY
+
+	lsr	x18, n, #2
+	tbz	n, #0, L(bx0)
+
+L(bx1):	ldr	x13, [vp]
+	ldr	x11, [up]
+	bic	x7, x13, cnd
+	ADDSUBC	x9, x11, x7
+	str	x9, [rp]
+	tbnz	n, #1, L(b11)
+
+L(b01):	cbz	x18, L(rt)
+	ldp	x12, x13, [vp,#8]
+	ldp	x10, x11, [up,#8]
+	sub	up, up, #8
+	sub	vp, vp, #8
+	sub	rp, rp, #24
+	b	L(mid)
+
+L(b11):	ldp	x12, x13, [vp,#8]!
+	ldp	x10, x11, [up,#8]!
+	sub	rp, rp, #8
+	cbz	x18, L(end)
+	b	L(top)
+
+L(bx0):	ldp	x12, x13, [vp]
+	ldp	x10, x11, [up]
+	tbnz	n, #1, L(b10)
+
+L(b00):	sub	up, up, #16
+	sub	vp, vp, #16
+	sub	rp, rp, #32
+	b	L(mid)
+
+L(b10):	sub	rp, rp, #16
+	cbz	x18, L(end)
+
+	ALIGN(16)
+L(top):	bic	x6, x12, cnd
+	bic	x7, x13, cnd
+	ldp	x12, x13, [vp,#16]
+	ADDSUBC	x8, x10, x6
+	ADDSUBC	x9, x11, x7
+	ldp	x10, x11, [up,#16]
+	stp	x8, x9, [rp,#16]
+L(mid):	bic	x6, x12, cnd
+	bic	x7, x13, cnd
+	ldp	x12, x13, [vp,#32]!
+	ADDSUBC	x8, x10, x6
+	ADDSUBC	x9, x11, x7
+	ldp	x10, x11, [up,#32]!
+	stp	x8, x9, [rp,#32]!
+	sub	x18, x18, #1
+	cbnz	x18, L(top)
+
+L(end):	bic	x6, x12, cnd
+	bic	x7, x13, cnd
+	ADDSUBC	x8, x10, x6
+	ADDSUBC	x9, x11, x7
+	stp	x8, x9, [rp,#16]
+L(rt):	RETVAL
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm64/com.asm b/third_party/gmp/mpn/arm64/com.asm
new file mode 100644
index 0000000..63ad249
--- /dev/null
+++ b/third_party/gmp/mpn/arm64/com.asm
@@ -0,0 +1,84 @@
+dnl  ARM64 mpn_com.
+
+dnl  Copyright 2013, 2014 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C Cortex-A53	 2.25
+C Cortex-A57	 1.25
+C X-Gene	 1.75
+
+changecom(blah)
+
+define(`rp', `x0')
+define(`up', `x1')
+define(`n',  `x2')
+
+ASM_START()
+PROLOGUE(mpn_com)
+	cmp	n, #3
+	b.le	L(bc)
+
+C Copy until rp is 128-bit aligned
+	tbz	rp, #3, L(al2)
+	ld1	{v22.1d}, [up], #8
+	sub	n, n, #1
+	mvn	v22.8b, v22.8b
+	st1	{v22.1d}, [rp], #8
+
+L(al2):	ld1	{v26.2d}, [up], #16
+	subs	n, n, #6
+	b.lt	L(end)
+
+	ALIGN(16)
+L(top):	ld1	{v22.2d}, [up], #16
+	mvn	v26.16b, v26.16b
+	st1	{v26.2d}, [rp], #16
+	ld1	{v26.2d}, [up], #16
+	mvn	v22.16b, v22.16b
+	st1	{v22.2d}, [rp], #16
+	subs	n, n, #4
+	b.ge	L(top)
+
+L(end):	mvn	v26.16b, v26.16b
+	st1	{v26.2d}, [rp], #16
+
+C Copy last 0-3 limbs.  Note that rp is aligned after loop, but not when we
+C arrive here via L(bc)
+L(bc):	tbz	n, #1, L(tl1)
+	ld1	{v22.2d}, [up], #16
+	mvn	v22.16b, v22.16b
+	st1	{v22.2d}, [rp], #16
+L(tl1):	tbz	n, #0, L(tl2)
+	ld1	{v22.1d}, [up]
+	mvn	v22.8b, v22.8b
+	st1	{v22.1d}, [rp]
+L(tl2):	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm64/copyd.asm b/third_party/gmp/mpn/arm64/copyd.asm
new file mode 100644
index 0000000..c8001a3
--- /dev/null
+++ b/third_party/gmp/mpn/arm64/copyd.asm
@@ -0,0 +1,93 @@
+dnl  ARM64 mpn_copyd.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C Cortex-A53	 ?
+C Cortex-A57	 ?
+
+changecom(blah)
+
+define(`rp', `x0')
+define(`up', `x1')
+define(`n',  `x2')
+
+ASM_START()
+PROLOGUE(mpn_copyd)
+	add	rp, rp, n, lsl #3
+	add	up, up, n, lsl #3
+
+	cmp	n, #3
+	b.le	L(bc)
+
+C Copy until rp is 128-bit aligned
+	tbz	rp, #3, L(al2)
+	sub	up, up, #8
+	ld1	{v22.1d}, [up]
+	sub	n, n, #1
+	sub	rp, rp, #8
+	st1	{v22.1d}, [rp]
+
+L(al2):	sub	up, up, #16
+	ld1	{v26.2d}, [up]
+	sub	n, n, #6
+	sub	rp, rp, #16			C offset rp for loop
+	tbnz	n, #63, L(end)
+
+	sub	up, up, #16			C offset up for loop
+	mov	x12, #-16
+
+	ALIGN(16)
+L(top):	ld1	{v22.2d}, [up], x12
+	st1	{v26.2d}, [rp], x12
+	ld1	{v26.2d}, [up], x12
+	st1	{v22.2d}, [rp], x12
+	sub	n, n, #4
+	tbz	n, #63, L(top)
+
+	add	up, up, #16			C undo up offset
+
+L(end):	st1	{v26.2d}, [rp]
+
+C Copy last 0-3 limbs.  Note that rp is aligned after loop, but not when we
+C arrive here via L(bc)
+L(bc):	tbz	n, #1, L(tl1)
+	sub	up, up, #16
+	ld1	{v22.2d}, [up]
+	sub	rp, rp, #16
+	st1	{v22.2d}, [rp]
+L(tl1):	tbz	n, #0, L(tl2)
+	sub	up, up, #8
+	ld1	{v22.1d}, [up]
+	sub	rp, rp, #8
+	st1	{v22.1d}, [rp]
+L(tl2):	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm64/copyi.asm b/third_party/gmp/mpn/arm64/copyi.asm
new file mode 100644
index 0000000..cfb90c7
--- /dev/null
+++ b/third_party/gmp/mpn/arm64/copyi.asm
@@ -0,0 +1,78 @@
+dnl  ARM64 mpn_copyi.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C Cortex-A53	 2
+C Cortex-A57	 1
+C X-Gene	 1.25
+
+changecom(blah)
+
+define(`rp', `x0')
+define(`up', `x1')
+define(`n',  `x2')
+
+ASM_START()
+PROLOGUE(mpn_copyi)
+	cmp	n, #3
+	b.le	L(bc)
+
+C Copy until rp is 128-bit aligned
+	tbz	rp, #3, L(al2)
+	ld1	{v22.1d}, [up], #8
+	sub	n, n, #1
+	st1	{v22.1d}, [rp], #8
+
+L(al2):	ld1	{v26.2d}, [up], #16
+	sub	n, n, #6
+	tbnz	n, #63, L(end)
+
+	ALIGN(16)
+L(top):	ld1	{v22.2d}, [up], #16
+	st1	{v26.2d}, [rp], #16
+	ld1	{v26.2d}, [up], #16
+	st1	{v22.2d}, [rp], #16
+	sub	n, n, #4
+	tbz	n, #63, L(top)
+
+L(end):	st1	{v26.2d}, [rp], #16
+
+C Copy last 0-3 limbs.  Note that rp is aligned after loop, but not when we
+C arrive here via L(bc)
+L(bc):	tbz	n, #1, L(tl1)
+	ld1	{v22.2d}, [up], #16
+	st1	{v22.2d}, [rp], #16
+L(tl1):	tbz	n, #0, L(tl2)
+	ld1	{v22.1d}, [up]
+	st1	{v22.1d}, [rp]
+L(tl2):	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm64/cora53/cnd_aors_n.asm b/third_party/gmp/mpn/arm64/cora53/cnd_aors_n.asm
new file mode 100644
index 0000000..1b227da
--- /dev/null
+++ b/third_party/gmp/mpn/arm64/cora53/cnd_aors_n.asm
@@ -0,0 +1,99 @@
+dnl  ARM64 mpn_cnd_add_n, mpn_cnd_sub_n
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2012, 2013, 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C Cortex-A53	3.5-4
+C Cortex-A57	 2.25
+C X-Gene	 3.5
+
+changecom(blah)
+
+define(`cnd',	`x0')
+define(`rp',	`x1')
+define(`up',	`x2')
+define(`vp',	`x3')
+define(`n',	`x4')
+
+ifdef(`OPERATION_cnd_add_n', `
+  define(`ADDSUBC',	adcs)
+  define(`CLRCY',	`cmn	xzr, xzr')
+  define(`RETVAL',	`cset	x0, cs')
+  define(`func',	mpn_cnd_add_n)')
+ifdef(`OPERATION_cnd_sub_n', `
+  define(`ADDSUBC',	sbcs)
+  define(`CLRCY',	`cmp	xzr, xzr')
+  define(`RETVAL',	`cset	x0, cc')
+  define(`func',	mpn_cnd_sub_n)')
+
+MULFUNC_PROLOGUE(mpn_cnd_add_n mpn_cnd_sub_n)
+
+ASM_START()
+PROLOGUE(func)
+	cmp	cnd, #1
+	sbc	cnd, cnd, cnd
+
+	CLRCY				C really only needed for n = 0 (mod 4)
+
+	tbz	n, #0, L(1)
+	ldr	x10, [up], #8
+	ldr	x12, [vp], #8
+	bic	x6, x12, cnd
+	ADDSUBC	x8, x10, x6
+	sub	n, n, #1
+	str	x8, [rp], #8
+	cbz	n, L(rt)
+
+L(1):	ldp	x10, x11, [up], #16
+	ldp	x12, x13, [vp], #16
+	sub	n, n, #2
+	cbz	n, L(end)
+
+L(top):	bic	x6, x12, cnd
+	bic	x7, x13, cnd
+	ldp	x12, x13, [vp], #16
+	ADDSUBC	x8, x10, x6
+	ADDSUBC	x9, x11, x7
+	ldp	x10, x11, [up], #16
+	sub	n, n, #2
+	stp	x8, x9, [rp], #16
+	cbnz	n, L(top)
+
+L(end):	bic	x6, x12, cnd
+	bic	x7, x13, cnd
+	ADDSUBC	x8, x10, x6
+	ADDSUBC	x9, x11, x7
+	stp	x8, x9, [rp]
+L(rt):	RETVAL
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm64/cora53/gmp-mparam.h b/third_party/gmp/mpn/arm64/cora53/gmp-mparam.h
new file mode 100644
index 0000000..f4e258d
--- /dev/null
+++ b/third_party/gmp/mpn/arm64/cora53/gmp-mparam.h
@@ -0,0 +1,242 @@
+/* gmp-mparam.h -- Compiler/machine parameter header file for a53.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+/* 1536 MHz Cortex-A53 */
+/* FFT tuning limit = 21,583,800 */
+/* Generated by tuneup.c, 2019-10-22, gcc 5.4 */
+
+#define DIVREM_1_NORM_THRESHOLD              3
+#define DIVREM_1_UNNORM_THRESHOLD            4
+#define MOD_1_1P_METHOD                      2  /* 4.84% faster than 1 */
+#define MOD_1_NORM_THRESHOLD                 3
+#define MOD_1_UNNORM_THRESHOLD               4
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          7
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          7
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        12
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        18
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     22
+#define USE_PREINV_DIVREM_1                  1
+#define DIV_QR_1N_PI1_METHOD                 1  /* 39.05% faster than 2 */
+#define DIV_QR_1_NORM_THRESHOLD             21
+#define DIV_QR_1_UNNORM_THRESHOLD           21
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always */
+#define BMOD_1_TO_MOD_1_THRESHOLD           38
+
+#define DIV_1_VS_MUL_1_PERCENT             161
+
+#define MUL_TOOM22_THRESHOLD                14
+#define MUL_TOOM33_THRESHOLD                49
+#define MUL_TOOM44_THRESHOLD                73
+#define MUL_TOOM6H_THRESHOLD               173
+#define MUL_TOOM8H_THRESHOLD               236
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      81
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD      77
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD      81
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD      88
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD      65
+
+#define SQR_BASECASE_THRESHOLD               0  /* always */
+#define SQR_TOOM2_THRESHOLD                 18
+#define SQR_TOOM3_THRESHOLD                 68
+#define SQR_TOOM4_THRESHOLD                183
+#define SQR_TOOM6_THRESHOLD                230
+#define SQR_TOOM8_THRESHOLD                357
+
+#define MULMID_TOOM42_THRESHOLD             23
+
+#define MULMOD_BNM1_THRESHOLD                9
+#define SQRMOD_BNM1_THRESHOLD               11
+
+#define MUL_FFT_MODF_THRESHOLD             316  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    316, 5}, {     13, 6}, {      7, 5}, {     15, 6}, \
+    {     13, 7}, {      7, 6}, {     15, 7}, {      8, 6}, \
+    {     17, 7}, {      9, 6}, {     19, 7}, {     17, 8}, \
+    {      9, 7}, {     20, 8}, {     11, 7}, {     23, 8}, \
+    {     13, 9}, {      7, 8}, {     19, 9}, {     11, 8}, \
+    {     27, 9}, {     15, 8}, {     33, 9}, {     19, 8}, \
+    {     41, 9}, {     23, 8}, {     49, 9}, {     27,10}, \
+    {     15, 9}, {     39,10}, {     23, 9}, {     51,11}, \
+    {     15,10}, {     31, 9}, {     71,10}, {     39, 9}, \
+    {     83,10}, {     47, 9}, {     99,10}, {     55,11}, \
+    {     31,10}, {     63, 8}, {    255,10}, {     71, 8}, \
+    {    287,10}, {     79, 9}, {    159, 8}, {    319,10}, \
+    {     87,11}, {     47,10}, {     95, 9}, {    191, 8}, \
+    {    383,10}, {    103, 9}, {    207, 8}, {    415,10}, \
+    {    111, 9}, {    223,12}, {     31,11}, {     63, 9}, \
+    {    255, 8}, {    511,10}, {    135, 9}, {    287, 8}, \
+    {    575,11}, {     79,10}, {    159, 9}, {    319, 8}, \
+    {    639,10}, {    175, 9}, {    351, 8}, {    703,11}, \
+    {     95,10}, {    191, 9}, {    383, 8}, {    767,10}, \
+    {    207, 9}, {    415, 8}, {    831,10}, {    223, 9}, \
+    {    447,12}, {     63,10}, {    255, 9}, {    511, 8}, \
+    {   1023, 9}, {    543,10}, {    287, 9}, {    575, 8}, \
+    {   1151,11}, {    159,10}, {    319, 9}, {    639,11}, \
+    {    175,10}, {    351, 9}, {    703, 8}, {   1407,12}, \
+    {     95,11}, {    191,10}, {    383, 9}, {    767,11}, \
+    {    207,10}, {    415, 9}, {    831,11}, {    223,10}, \
+    {    447,13}, {     63,11}, {    255,10}, {    543,11}, \
+    {    287,10}, {    575, 9}, {   1151,12}, {    159,11}, \
+    {    319,10}, {    639,11}, {    351,10}, {    703, 9}, \
+    {   1407, 8}, {   2815,12}, {    191,11}, {    383,10}, \
+    {    767,11}, {    415,10}, {    831,12}, {    223,11}, \
+    {    447,10}, {    895,11}, {    479,10}, {    959, 9}, \
+    {   1919,12}, {    255,11}, {    511,10}, {   1023,11}, \
+    {    543,10}, {   1087,12}, {    287,11}, {    575,10}, \
+    {   1151,12}, {    319,11}, {    639,12}, {    351,11}, \
+    {    703,10}, {   1407, 9}, {   2815,13}, {    191,12}, \
+    {    383,11}, {    767,12}, {    415,11}, {    831,10}, \
+    {   1663,12}, {    447,11}, {    895,10}, {   1791,12}, \
+    {    479,11}, {    959,13}, {    255,12}, {    511,11}, \
+    {   1023,12}, {    543,11}, {   1087,12}, {    575,11}, \
+    {   1151,13}, {    319,12}, {    703,11}, {   1407,10}, \
+    {   2815,13}, {    383,12}, {    831,11}, {   1663,13}, \
+    {    447,12}, {    895,11}, {   1791,12}, {    959,11}, \
+    {   1919,14}, {    255,13}, {    511,12}, {   1087,13}, \
+    {    575,12}, {   1151,13}, {    703,12}, {   1407,11}, \
+    {   2815,14}, {    383,13}, {    831,12}, {   1663,13}, \
+    {    895,12}, {   1791,13}, {    959,12}, {   1919,15}, \
+    {    255,14}, {    511,13}, {   1087,12}, {   2175,13}, \
+    {   1215,14}, {    639,13}, {   1407,12}, {   2815,14}, \
+    {    767,13}, {   1663,14}, {    895,13}, {   1919,12}, \
+    {   3839,15}, {    511,14}, {   1023,13}, {   2175,14}, \
+    {   1151,13}, {   2431,12}, {   4863,14}, {  16384,15}, \
+    {  32768,16}, {  65536,17}, { 131072,18}, { 262144,19}, \
+    { 524288,20}, {1048576,21}, {2097152,22}, {4194304,23}, \
+    {8388608,24} }
+#define MUL_FFT_TABLE3_SIZE 217
+#define MUL_FFT_THRESHOLD                 3200
+
+#define SQR_FFT_MODF_THRESHOLD             276  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    276, 5}, {     13, 6}, {      7, 5}, {     15, 6}, \
+    {     17, 7}, {     17, 8}, {      9, 7}, {     20, 8}, \
+    {     11, 7}, {     23, 8}, {     13, 9}, {      7, 8}, \
+    {     15, 7}, {     31, 8}, {     19, 9}, {     11, 8}, \
+    {     27, 9}, {     15, 8}, {     33, 9}, {     19, 8}, \
+    {     39, 9}, {     23, 8}, {     47, 9}, {     27,10}, \
+    {     15, 9}, {     39,10}, {     23, 9}, {     47,11}, \
+    {     15,10}, {     31, 9}, {     67,10}, {     39, 9}, \
+    {     79,10}, {     47, 9}, {     95, 8}, {    191,10}, \
+    {     55,11}, {     31,10}, {     63, 8}, {    255,10}, \
+    {     71, 9}, {    143, 8}, {    287,10}, {     79, 9}, \
+    {    159,11}, {     47,10}, {     95, 9}, {    191, 8}, \
+    {    383, 7}, {    767,10}, {    103,12}, {     31,11}, \
+    {     63, 9}, {    255, 8}, {    511, 7}, {   1023,10}, \
+    {    143, 9}, {    287,11}, {     79,10}, {    159, 9}, \
+    {    319, 8}, {    639,10}, {    175, 9}, {    351, 8}, \
+    {    703,11}, {     95,10}, {    191, 9}, {    383, 8}, \
+    {    767,10}, {    207, 9}, {    415, 8}, {    831,10}, \
+    {    223, 9}, {    447,12}, {     63,10}, {    255, 9}, \
+    {    511, 8}, {   1023,11}, {    143,10}, {    287, 9}, \
+    {    575, 8}, {   1151,11}, {    159,10}, {    319, 9}, \
+    {    639,11}, {    175,10}, {    351, 9}, {    703,12}, \
+    {     95,11}, {    191,10}, {    383, 9}, {    767,11}, \
+    {    207,10}, {    415, 9}, {    831,11}, {    223,10}, \
+    {    447,13}, {     63,11}, {    255,10}, {    511, 9}, \
+    {   1023,11}, {    287,10}, {    575, 9}, {   1151,12}, \
+    {    159,11}, {    319,10}, {    639,11}, {    351,10}, \
+    {    703, 9}, {   1407,12}, {    191,11}, {    383,10}, \
+    {    767,11}, {    415,10}, {    831,12}, {    223,11}, \
+    {    447,10}, {    895,11}, {    479,10}, {    959,12}, \
+    {    255,11}, {    511,10}, {   1023,12}, {    287,11}, \
+    {    575,10}, {   1151,12}, {    319,11}, {    639,12}, \
+    {    351,11}, {    703,10}, {   1407,13}, {    191,12}, \
+    {    383,11}, {    767,12}, {    415,11}, {    831,10}, \
+    {   1663,12}, {    447,11}, {    895,12}, {    479,11}, \
+    {    959,10}, {   1919,13}, {    255,12}, {    511,11}, \
+    {   1023,12}, {    543,11}, {   1087,12}, {    575,11}, \
+    {   1151,13}, {    319,12}, {    703,11}, {   1407,10}, \
+    {   2815,13}, {    383,12}, {    831,11}, {   1663,13}, \
+    {    447,12}, {    895,11}, {   1791,12}, {    959,14}, \
+    {    255,13}, {    511,12}, {   1087,13}, {    575,12}, \
+    {   1151,13}, {    703,12}, {   1407,11}, {   2815,14}, \
+    {    383,13}, {    831,12}, {   1663,13}, {    895,12}, \
+    {   1791,13}, {    959,12}, {   1919,15}, {    255,14}, \
+    {    511,13}, {   1087,12}, {   2175,13}, {   1151,14}, \
+    {    639,13}, {   1407,12}, {   2815,14}, {    767,13}, \
+    {   1663,14}, {    895,13}, {   1919,12}, {   3839,15}, \
+    {    511,14}, {   1023,13}, {   2175,14}, {   1151,13}, \
+    {   2431,12}, {   4863,14}, {  16384,15}, {  32768,16}, \
+    {  65536,17}, { 131072,18}, { 262144,19}, { 524288,20}, \
+    {1048576,21}, {2097152,22}, {4194304,23}, {8388608,24} }
+#define SQR_FFT_TABLE3_SIZE 204
+#define SQR_FFT_THRESHOLD                 2688
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  38
+#define MULLO_MUL_N_THRESHOLD             6253
+#define SQRLO_BASECASE_THRESHOLD             4
+#define SQRLO_DC_THRESHOLD                  67
+#define SQRLO_SQR_THRESHOLD               5240
+
+#define DC_DIV_QR_THRESHOLD                 43
+#define DC_DIVAPPR_Q_THRESHOLD             155
+#define DC_BDIV_QR_THRESHOLD                39
+#define DC_BDIV_Q_THRESHOLD                 89
+
+#define INV_MULMOD_BNM1_THRESHOLD           34
+#define INV_NEWTON_THRESHOLD               163
+#define INV_APPR_THRESHOLD                 161
+
+#define BINV_NEWTON_THRESHOLD              196
+#define REDC_1_TO_REDC_N_THRESHOLD          43
+
+#define MU_DIV_QR_THRESHOLD                998
+#define MU_DIVAPPR_Q_THRESHOLD             998
+#define MUPI_DIV_QR_THRESHOLD               91
+#define MU_BDIV_QR_THRESHOLD               807
+#define MU_BDIV_Q_THRESHOLD                924
+
+#define POWM_SEC_TABLE  6,30,125,579,1730
+
+#define GET_STR_DC_THRESHOLD                15
+#define GET_STR_PRECOMPUTE_THRESHOLD        30
+#define SET_STR_DC_THRESHOLD               802
+#define SET_STR_PRECOMPUTE_THRESHOLD      1815
+
+#define FAC_DSC_THRESHOLD                  258
+#define FAC_ODD_THRESHOLD                   24
+
+#define MATRIX22_STRASSEN_THRESHOLD         10
+#define HGCD2_DIV1_METHOD                    1  /* 7.05% faster than 3 */
+#define HGCD_THRESHOLD                     107
+#define HGCD_APPR_THRESHOLD                112
+#define HGCD_REDUCE_THRESHOLD             1679
+#define GCD_DC_THRESHOLD                   324
+#define GCDEXT_DC_THRESHOLD                242
+#define JACOBI_BASE_METHOD                   4  /* 22.41% faster than 1 */
+
+/* Tuneup completed successfully, took 66624 seconds */
diff --git a/third_party/gmp/mpn/arm64/cora57/gmp-mparam.h b/third_party/gmp/mpn/arm64/cora57/gmp-mparam.h
new file mode 100644
index 0000000..0d38621
--- /dev/null
+++ b/third_party/gmp/mpn/arm64/cora57/gmp-mparam.h
@@ -0,0 +1,187 @@
+/* gmp-mparam.h -- Compiler/machine parameter header file for a57, a72-a75.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+/* 1800 MHz Cortex-A72 */
+/* FFT tuning limit = 0.5 M */
+/* Generated by tuneup.c, 2019-10-02, gcc 7.4 */
+
+#define DIVREM_1_NORM_THRESHOLD              3
+#define DIVREM_1_UNNORM_THRESHOLD            4
+#define MOD_1_1P_METHOD                      1  /* 2.21% faster than 2 */
+#define MOD_1_NORM_THRESHOLD                 3
+#define MOD_1_UNNORM_THRESHOLD               4
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          6
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          4
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD         8
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        42
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     15
+#define USE_PREINV_DIVREM_1                  1
+#define DIV_QR_1N_PI1_METHOD                 1  /* 34.95% faster than 2 */
+#define DIV_QR_1_NORM_THRESHOLD              5
+#define DIV_QR_1_UNNORM_THRESHOLD            5
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always */
+#define BMOD_1_TO_MOD_1_THRESHOLD           33
+
+#define DIV_1_VS_MUL_1_PERCENT             168
+
+#define MUL_TOOM22_THRESHOLD                10
+#define MUL_TOOM33_THRESHOLD                41
+#define MUL_TOOM44_THRESHOLD                99
+#define MUL_TOOM6H_THRESHOLD               142
+#define MUL_TOOM8H_THRESHOLD               199
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      65
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD      69
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD      63
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD      66
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD      55
+
+#define SQR_BASECASE_THRESHOLD               0  /* always */
+#define SQR_TOOM2_THRESHOLD                 18
+#define SQR_TOOM3_THRESHOLD                 65
+#define SQR_TOOM4_THRESHOLD                166
+#define SQR_TOOM6_THRESHOLD                222
+#define SQR_TOOM8_THRESHOLD                309
+
+#define MULMID_TOOM42_THRESHOLD             22
+
+#define MULMOD_BNM1_THRESHOLD                7
+#define SQRMOD_BNM1_THRESHOLD               12
+
+#define MUL_FFT_MODF_THRESHOLD             276  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    276, 5}, {     13, 6}, {      7, 5}, {     15, 6}, \
+    {     13, 7}, {      7, 6}, {     15, 7}, {      8, 6}, \
+    {     17, 7}, {      9, 6}, {     19, 7}, {     13, 8}, \
+    {      7, 7}, {     17, 8}, {      9, 7}, {     20, 8}, \
+    {     11, 7}, {     23, 8}, {     13, 9}, {      7, 8}, \
+    {     21, 9}, {     11, 8}, {     25,10}, {      7, 9}, \
+    {     15, 8}, {     33, 9}, {     19, 8}, {     39, 9}, \
+    {     23, 8}, {     49, 9}, {     27,10}, {     15, 9}, \
+    {     39,10}, {     23, 9}, {     51,11}, {     15,10}, \
+    {     31, 9}, {     67,10}, {     39, 9}, {     79,10}, \
+    {     47, 9}, {     99,10}, {     55,11}, {     31,10}, \
+    {     63, 8}, {    255,10}, {     71, 9}, {    143, 8}, \
+    {    287,10}, {     79, 9}, {    159, 8}, {    319,11}, \
+    {     47,10}, {     95, 9}, {    191,10}, {    103,12}, \
+    {     31,11}, {     63, 9}, {    255, 8}, {    511,10}, \
+    {    143, 8}, {    575,11}, {     79,10}, {    159, 9}, \
+    {    319,10}, {    175, 9}, {    351, 8}, {    703,11}, \
+    {     95,10}, {    191, 9}, {    383,10}, {    207, 9}, \
+    {    415,10}, {    223, 9}, {    447, 8}, {    895,12}, \
+    {     63,10}, {    255, 9}, {    511, 8}, {   1023, 9}, \
+    {    543,11}, {    143,10}, {    287, 9}, {    575, 8}, \
+    {   1151,10}, {    319, 9}, {    639,11}, {    175,10}, \
+    {    351, 9}, {    703,12}, {     95,10}, {    383, 9}, \
+    {    767,11}, {    207, 9}, {    831,11}, {    223,10}, \
+    {    447, 9}, {    895,13}, {   8192,14}, {  16384,15}, \
+    {  32768,16}, {  65536,17}, { 131072,18}, { 262144,19}, \
+    { 524288,20}, {1048576,21}, {2097152,22}, {4194304,23}, \
+    {8388608,24} }
+#define MUL_FFT_TABLE3_SIZE 109
+#define MUL_FFT_THRESHOLD                 3200
+
+#define SQR_FFT_MODF_THRESHOLD             244  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    244, 5}, {     13, 6}, {      7, 5}, {     15, 6}, \
+    {      8, 5}, {     17, 6}, {     17, 7}, {      9, 6}, \
+    {     19, 7}, {     17, 8}, {      9, 7}, {     20, 8}, \
+    {     11, 7}, {     23, 8}, {     13, 9}, {      7, 8}, \
+    {     19, 9}, {     11, 8}, {     25,10}, {      7, 9}, \
+    {     15, 8}, {     33, 9}, {     19, 8}, {     39, 9}, \
+    {     27,10}, {     15, 9}, {     39,10}, {     23, 9}, \
+    {     47,11}, {     15,10}, {     31, 9}, {     67,10}, \
+    {     39, 9}, {     79,10}, {     47, 9}, {     99,10}, \
+    {     55,11}, {     31,10}, {     63, 9}, {    127, 8}, \
+    {    255,10}, {     71, 8}, {    287, 7}, {    575, 9}, \
+    {    159, 8}, {    319,11}, {     47,10}, {     95, 9}, \
+    {    191, 8}, {    383,12}, {     31,11}, {     63,10}, \
+    {    127, 9}, {    255,10}, {    143, 9}, {    287, 8}, \
+    {    575,11}, {     79,10}, {    159, 9}, {    319, 8}, \
+    {    639, 9}, {    351,10}, {    191, 9}, {    383,10}, \
+    {    207, 9}, {    415,10}, {    239,12}, {     63,10}, \
+    {    255, 9}, {    511,10}, {    271,11}, {    143,10}, \
+    {    287, 9}, {    575,11}, {    159,10}, {    319, 9}, \
+    {    639,10}, {    351, 9}, {    703,11}, {    191,10}, \
+    {    383, 9}, {    767,11}, {    207,10}, {    415, 9}, \
+    {    831,11}, {    223,13}, {   8192,14}, {  16384,15}, \
+    {  32768,16}, {  65536,17}, { 131072,18}, { 262144,19}, \
+    { 524288,20}, {1048576,21}, {2097152,22}, {4194304,23}, \
+    {8388608,24} }
+#define SQR_FFT_TABLE3_SIZE 97
+#define SQR_FFT_THRESHOLD                 2496
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  39
+#define MULLO_MUL_N_THRESHOLD             6253
+#define SQRLO_BASECASE_THRESHOLD             4
+#define SQRLO_DC_THRESHOLD                  56
+#define SQRLO_SQR_THRESHOLD               4940
+
+#define DC_DIV_QR_THRESHOLD                 41
+#define DC_DIVAPPR_Q_THRESHOLD             136
+#define DC_BDIV_QR_THRESHOLD                39
+#define DC_BDIV_Q_THRESHOLD                 89
+
+#define INV_MULMOD_BNM1_THRESHOLD           22
+#define INV_NEWTON_THRESHOLD               154
+#define INV_APPR_THRESHOLD                 141
+
+#define BINV_NEWTON_THRESHOLD              182
+#define REDC_1_TO_REDC_N_THRESHOLD          39
+
+#define MU_DIV_QR_THRESHOLD                979
+#define MU_DIVAPPR_Q_THRESHOLD            1078
+#define MUPI_DIV_QR_THRESHOLD               75
+#define MU_BDIV_QR_THRESHOLD               872
+#define MU_BDIV_Q_THRESHOLD                942
+
+#define POWM_SEC_TABLE  1,19,117,539,1730
+
+#define GET_STR_DC_THRESHOLD                10
+#define GET_STR_PRECOMPUTE_THRESHOLD        21
+#define SET_STR_DC_THRESHOLD               572
+#define SET_STR_PRECOMPUTE_THRESHOLD      1036
+
+#define FAC_DSC_THRESHOLD                  142
+#define FAC_ODD_THRESHOLD                   23
+
+#define MATRIX22_STRASSEN_THRESHOLD         11
+#define HGCD2_DIV1_METHOD                    1  /* 8.83% faster than 3 */
+#define HGCD_THRESHOLD                      80
+#define HGCD_APPR_THRESHOLD                 70
+#define HGCD_REDUCE_THRESHOLD             1962
+#define GCD_DC_THRESHOLD                   273
+#define GCDEXT_DC_THRESHOLD                198
+#define JACOBI_BASE_METHOD                   1  /* 7.49% faster than 4 */
diff --git a/third_party/gmp/mpn/arm64/cora72/gmp-mparam.h b/third_party/gmp/mpn/arm64/cora72/gmp-mparam.h
new file mode 100644
index 0000000..fc66fd3
--- /dev/null
+++ b/third_party/gmp/mpn/arm64/cora72/gmp-mparam.h
@@ -0,0 +1,242 @@
+/* gmp-mparam.h -- Compiler/machine parameter header file for a72.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+/* 1800 MHz Cortex-A72 */
+/* FFT tuning limit = 50,811,960 */
+/* Generated by tuneup.c, 2019-10-22, gcc 7.3 */
+
+#define DIVREM_1_NORM_THRESHOLD              3
+#define DIVREM_1_UNNORM_THRESHOLD            3
+#define MOD_1_1P_METHOD                      2  /* 12.09% faster than 1 */
+#define MOD_1_NORM_THRESHOLD                 3
+#define MOD_1_UNNORM_THRESHOLD               3
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          8
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          5
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD         0  /* never mpn_mod_1_1p */
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        26
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     15
+#define USE_PREINV_DIVREM_1                  1
+#define DIV_QR_1N_PI1_METHOD                 1  /* 13.42% faster than 2 */
+#define DIV_QR_1_NORM_THRESHOLD              4
+#define DIV_QR_1_UNNORM_THRESHOLD            4
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always */
+#define BMOD_1_TO_MOD_1_THRESHOLD           38
+
+#define DIV_1_VS_MUL_1_PERCENT             168
+
+#define MUL_TOOM22_THRESHOLD                 8
+#define MUL_TOOM33_THRESHOLD                57
+#define MUL_TOOM44_THRESHOLD               153
+#define MUL_TOOM6H_THRESHOLD               222
+#define MUL_TOOM8H_THRESHOLD               333
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      57
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     108
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     104
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD      56
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD      82
+
+#define SQR_BASECASE_THRESHOLD               0  /* always */
+#define SQR_TOOM2_THRESHOLD                 16
+#define SQR_TOOM3_THRESHOLD                 73
+#define SQR_TOOM4_THRESHOLD                154
+#define SQR_TOOM6_THRESHOLD                206
+#define SQR_TOOM8_THRESHOLD                333
+
+#define MULMID_TOOM42_THRESHOLD             18
+
+#define MULMOD_BNM1_THRESHOLD                8
+#define SQRMOD_BNM1_THRESHOLD               10
+
+#define MUL_FFT_MODF_THRESHOLD             268  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    268, 5}, {     11, 6}, {      6, 5}, {     13, 6}, \
+    {     15, 7}, {     13, 8}, {      7, 7}, {     16, 8}, \
+    {      9, 7}, {     19, 8}, {     11, 7}, {     23, 8}, \
+    {     13, 9}, {      7, 8}, {     15, 7}, {     31, 8}, \
+    {     19, 9}, {     11, 8}, {     27,10}, {      7, 9}, \
+    {     15, 8}, {     33, 9}, {     19, 8}, {     39, 9}, \
+    {     27,10}, {     15, 9}, {     39,10}, {     23, 9}, \
+    {     51,11}, {     15,10}, {     31, 9}, {     71,10}, \
+    {     39, 9}, {     79, 8}, {    159, 7}, {    319, 9}, \
+    {     83,10}, {     47, 9}, {     95, 7}, {    383, 9}, \
+    {     99,10}, {     55,11}, {     31,10}, {     63, 8}, \
+    {    255, 7}, {    511, 9}, {    131,10}, {     71, 9}, \
+    {    143, 8}, {    287, 7}, {    575, 6}, {   1151,10}, \
+    {     79, 8}, {    319, 7}, {    639,10}, {     87, 8}, \
+    {    351,11}, {     47,10}, {     95, 8}, {    383, 7}, \
+    {    767,10}, {    103, 8}, {    415, 7}, {    831, 6}, \
+    {   1663, 9}, {    223, 8}, {    447,12}, {     31,11}, \
+    {     63, 9}, {    255, 8}, {    511, 7}, {   1023, 9}, \
+    {    287, 8}, {    575, 7}, {   1151, 6}, {   2303, 7}, \
+    {   1215,11}, {     79, 9}, {    319, 8}, {    639, 7}, \
+    {   1279, 9}, {    351, 8}, {    703, 7}, {   1407, 6}, \
+    {   2815, 9}, {    383, 8}, {    831, 7}, {   1663, 9}, \
+    {    447, 8}, {    895, 7}, {   1791, 6}, {   3583, 8}, \
+    {    959, 6}, {   3839, 5}, {   7679, 9}, {    511, 8}, \
+    {   1023, 7}, {   2175, 9}, {    575, 8}, {   1151, 7}, \
+    {   2303, 8}, {   1215,10}, {    351, 9}, {    703, 7}, \
+    {   3071, 8}, {   1663, 9}, {    895, 8}, {   1791, 7}, \
+    {   3583, 8}, {   1919, 6}, {   7679, 7}, {   3967, 9}, \
+    {   1023,10}, {    575, 9}, {   1151, 8}, {   2559,10}, \
+    {    703, 8}, {   2815, 9}, {   1471, 7}, {   5887,10}, \
+    {    767,11}, {    415, 9}, {   1791, 8}, {   3583,11}, \
+    {    479,10}, {    959, 8}, {   3967,11}, {    511, 9}, \
+    {   2175,10}, {   1151, 8}, {   4607, 9}, {   2815,10}, \
+    {   1471, 9}, {   2943,11}, {    767,10}, {   1535,11}, \
+    {    831,10}, {   1791,11}, {    959,10}, {   1919, 9}, \
+    {   3839, 8}, {   7679,10}, {   1983,12}, {    511,10}, \
+    {   2047,11}, {   1215,12}, {    639,11}, {   1407,10}, \
+    {   2815,11}, {   1471,12}, {    767,11}, {   1663,12}, \
+    {    895,11}, {   1791,12}, {    959,11}, {   1919,10}, \
+    {   3839,14}, {    255,13}, {    511,12}, {   1023,11}, \
+    {   2047,12}, {   1215,13}, {    639,12}, {   1279,13}, \
+    {    703,12}, {   1407,11}, {   2815,13}, {    767,12}, \
+    {   1535,13}, {    831,12}, {   1663,13}, {    895,12}, \
+    {   1791,11}, {   3583,13}, {    959,12}, {   1919,11}, \
+    {   3839,14}, {    511,13}, {   1023,12}, {   2047,13}, \
+    {   1215,12}, {   2431,14}, {    639,13}, {   1407,12}, \
+    {   2815,13}, {   1471,12}, {   2943,14}, {    767,13}, \
+    {   1535,12}, {   3071,13}, {   1791,12}, {   3583,13}, \
+    {   1919,14}, {   1023,13}, {   2175,14}, {   1151,13}, \
+    {   2431,14}, {   1279,13}, {   2559,15}, {    767,14}, \
+    {   1791,13}, {   3839,15}, {   1023,14}, {   2431,13}, \
+    {   4863,15}, {   1279,14}, {   2943,15}, {   1535,14}, \
+    {  16384,15}, {  32768,16}, {  65536,17}, { 131072,18}, \
+    { 262144,19}, { 524288,20}, {1048576,21}, {2097152,22}, \
+    {4194304,23}, {8388608,24} }
+#define MUL_FFT_TABLE3_SIZE 218
+#define MUL_FFT_THRESHOLD                 2688
+
+#define SQR_FFT_MODF_THRESHOLD             236  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    236, 5}, {     13, 6}, {      7, 5}, {     15, 6}, \
+    {     15, 7}, {      8, 6}, {     17, 7}, {     13, 8}, \
+    {      7, 7}, {     17, 8}, {      9, 7}, {     20, 8}, \
+    {     11, 7}, {     23, 8}, {     13, 9}, {      7, 8}, \
+    {     19, 9}, {     11, 8}, {     25,10}, {      7, 9}, \
+    {     15, 8}, {     33, 9}, {     19, 8}, {     39, 9}, \
+    {     27,10}, {     15, 9}, {     39,10}, {     23, 9}, \
+    {     47,11}, {     15,10}, {     31, 9}, {     67,10}, \
+    {     39, 9}, {     79, 8}, {    159,10}, {     47, 9}, \
+    {     95, 8}, {    191, 7}, {    383,10}, {     55,11}, \
+    {     31,10}, {     63, 9}, {    127, 8}, {    255, 7}, \
+    {    511,10}, {     71, 9}, {    143, 8}, {    287, 7}, \
+    {    575,10}, {     79, 8}, {    319, 7}, {    639,11}, \
+    {     47,10}, {     95, 8}, {    383, 7}, {    767, 8}, \
+    {    415,12}, {     31,11}, {     63,10}, {    127, 9}, \
+    {    255, 8}, {    543, 9}, {    287, 8}, {    575, 7}, \
+    {   1151, 9}, {    319, 8}, {    639, 9}, {    351, 8}, \
+    {    703, 7}, {   1407, 6}, {   2815,10}, {    191, 9}, \
+    {    383, 8}, {    767, 9}, {    415, 8}, {    831, 7}, \
+    {   1663,10}, {    223, 9}, {    447, 8}, {    895, 7}, \
+    {   1791, 9}, {    479, 8}, {    959,12}, {     63,11}, \
+    {    127, 9}, {    543, 8}, {   1087,10}, {    287, 9}, \
+    {    575, 8}, {   1151,10}, {    319, 9}, {    639,10}, \
+    {    351, 9}, {    703, 8}, {   1407, 7}, {   2815, 8}, \
+    {   1471, 5}, {  11775, 9}, {    767, 8}, {   1535,10}, \
+    {    415, 9}, {    895, 8}, {   1919, 6}, {   7679, 7}, \
+    {   3967,11}, {    255,10}, {    543, 9}, {   1087, 8}, \
+    {   2175,10}, {    575, 9}, {   1151, 8}, {   2431,10}, \
+    {    639, 9}, {   1279,10}, {    703, 9}, {   1407, 8}, \
+    {   2943,11}, {    383,10}, {    767,11}, {    447,10}, \
+    {    895,11}, {    479,10}, {    959, 9}, {   1919, 8}, \
+    {   3839,10}, {   1023, 9}, {   2175,10}, {   1215, 9}, \
+    {   2431,11}, {    703, 9}, {   2815,10}, {   1471,11}, \
+    {    767,10}, {   1663,11}, {    895,10}, {   1791,11}, \
+    {    959, 9}, {   3839,12}, {    511,11}, {   1087,10}, \
+    {   2175,11}, {   1215,10}, {   2431,12}, {    639,11}, \
+    {   1279,12}, {    703,11}, {   1471,12}, {    767,11}, \
+    {   1663,12}, {    895,11}, {   1919,10}, {   3839,13}, \
+    {    511,12}, {   1087,11}, {   2175,12}, {   1215,11}, \
+    {   2431,13}, {    639,12}, {   1279,13}, {    703,12}, \
+    {   1407,13}, {    767,12}, {   1535,13}, {    831,12}, \
+    {   1791,13}, {   1151,12}, {   2303,13}, {   1215,14}, \
+    {    639,12}, {   2559,13}, {   1407,14}, {    767,12}, \
+    {   3071,14}, {    895,13}, {   1919,12}, {   3839,14}, \
+    {   1023,13}, {   2175,14}, {   1151,12}, {   4607,14}, \
+    {   1279,13}, {   2559,14}, {   1407,13}, {   2943,15}, \
+    {    767,14}, {   1663,13}, {   3583,14}, {   1919,15}, \
+    {   1023,14}, {   2047,13}, {   4095,14}, {   2943,15}, \
+    {   1535,14}, {  16384,15}, {  32768,16}, {  65536,17}, \
+    { 131072,18}, { 262144,19}, { 524288,20}, {1048576,21}, \
+    {2097152,22}, {4194304,23}, {8388608,24} }
+#define SQR_FFT_TABLE3_SIZE 203
+#define SQR_FFT_THRESHOLD                 2176
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  33
+#define MULLO_MUL_N_THRESHOLD             5240
+#define SQRLO_BASECASE_THRESHOLD             6
+#define SQRLO_DC_THRESHOLD                  45
+#define SQRLO_SQR_THRESHOLD               4265
+
+#define DC_DIV_QR_THRESHOLD                 38
+#define DC_DIVAPPR_Q_THRESHOLD             108
+#define DC_BDIV_QR_THRESHOLD                36
+#define DC_BDIV_Q_THRESHOLD                 71
+
+#define INV_MULMOD_BNM1_THRESHOLD           14
+#define INV_NEWTON_THRESHOLD               132
+#define INV_APPR_THRESHOLD                 124
+
+#define BINV_NEWTON_THRESHOLD              199
+#define REDC_1_TO_REDC_N_THRESHOLD          34
+
+#define MU_DIV_QR_THRESHOLD                979
+#define MU_DIVAPPR_Q_THRESHOLD             979
+#define MUPI_DIV_QR_THRESHOLD               61
+#define MU_BDIV_QR_THRESHOLD               734
+#define MU_BDIV_Q_THRESHOLD                942
+
+#define POWM_SEC_TABLE  6,30,110,579,1730
+
+#define GET_STR_DC_THRESHOLD                12
+#define GET_STR_PRECOMPUTE_THRESHOLD        19
+#define SET_STR_DC_THRESHOLD               458
+#define SET_STR_PRECOMPUTE_THRESHOLD       875
+
+#define FAC_DSC_THRESHOLD                  153
+#define FAC_ODD_THRESHOLD                   24
+
+#define MATRIX22_STRASSEN_THRESHOLD         15
+#define HGCD2_DIV1_METHOD                    1  /* 8.41% faster than 3 */
+#define HGCD_THRESHOLD                      81
+#define HGCD_APPR_THRESHOLD                 80
+#define HGCD_REDUCE_THRESHOLD             1494
+#define GCD_DC_THRESHOLD                   268
+#define GCDEXT_DC_THRESHOLD                189
+#define JACOBI_BASE_METHOD                   1  /* 10.80% faster than 4 */
+
+/* Tuneup completed successfully, took 96906 seconds */
diff --git a/third_party/gmp/mpn/arm64/cora73/gmp-mparam.h b/third_party/gmp/mpn/arm64/cora73/gmp-mparam.h
new file mode 100644
index 0000000..7fc7f4e
--- /dev/null
+++ b/third_party/gmp/mpn/arm64/cora73/gmp-mparam.h
@@ -0,0 +1,225 @@
+/* gmp-mparam.h -- Compiler/machine parameter header file for a73.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+/* 1800 MHz Cortex-A72 */
+/* FFT tuning limit = 48,820,337 */
+/* Generated by tuneup.c, 2019-10-22, gcc 7.4 */
+
+#define DIVREM_1_NORM_THRESHOLD              3
+#define DIVREM_1_UNNORM_THRESHOLD            3
+#define MOD_1_1P_METHOD                      1  /* 2.28% faster than 2 */
+#define MOD_1_NORM_THRESHOLD                 3
+#define MOD_1_UNNORM_THRESHOLD               4
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          8
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          5
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD         8
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        44
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     16
+#define USE_PREINV_DIVREM_1                  1
+#define DIV_QR_1N_PI1_METHOD                 1  /* 35.13% faster than 2 */
+#define DIV_QR_1_NORM_THRESHOLD              5
+#define DIV_QR_1_UNNORM_THRESHOLD            5
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always */
+#define BMOD_1_TO_MOD_1_THRESHOLD           33
+
+#define DIV_1_VS_MUL_1_PERCENT             168
+
+#define MUL_TOOM22_THRESHOLD                10
+#define MUL_TOOM33_THRESHOLD                57
+#define MUL_TOOM44_THRESHOLD                89
+#define MUL_TOOM6H_THRESHOLD               141
+#define MUL_TOOM8H_THRESHOLD               199
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      61
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD      69
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD      65
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD      66
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD      58
+
+#define SQR_BASECASE_THRESHOLD               0  /* always */
+#define SQR_TOOM2_THRESHOLD                 18
+#define SQR_TOOM3_THRESHOLD                 62
+#define SQR_TOOM4_THRESHOLD                166
+#define SQR_TOOM6_THRESHOLD                222
+#define SQR_TOOM8_THRESHOLD                309
+
+#define MULMID_TOOM42_THRESHOLD             22
+
+#define MULMOD_BNM1_THRESHOLD                8
+#define SQRMOD_BNM1_THRESHOLD               11
+
+#define MUL_FFT_MODF_THRESHOLD             276  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    276, 5}, {     13, 6}, {      7, 5}, {     15, 6}, \
+    {     15, 7}, {      8, 6}, {     17, 7}, {      9, 6}, \
+    {     19, 7}, {     13, 8}, {      7, 7}, {     17, 8}, \
+    {      9, 7}, {     19, 8}, {     11, 7}, {     23, 8}, \
+    {     13, 9}, {      7, 8}, {     19, 9}, {     11, 8}, \
+    {     27,10}, {      7, 9}, {     15, 8}, {     33, 9}, \
+    {     19, 8}, {     39, 9}, {     23, 8}, {     47, 9}, \
+    {     27,10}, {     15, 9}, {     43,10}, {     23, 9}, \
+    {     51,11}, {     15,10}, {     31, 9}, {     67,10}, \
+    {     39, 9}, {     83,10}, {     47, 9}, {     99,10}, \
+    {     55,11}, {     31,10}, {     63, 9}, {    127, 8}, \
+    {    255, 9}, {    131,10}, {     71, 9}, {    143, 8}, \
+    {    287,10}, {     79, 9}, {    159, 8}, {    319,11}, \
+    {     47, 9}, {    191, 8}, {    383, 7}, {    767, 8}, \
+    {    415,12}, {     31,11}, {     63, 9}, {    255, 8}, \
+    {    511,10}, {    143, 9}, {    287, 8}, {    575,11}, \
+    {     79,10}, {    159, 9}, {    319,10}, {    175, 9}, \
+    {    351, 8}, {    703,11}, {     95,10}, {    191, 9}, \
+    {    383, 8}, {    767,10}, {    207, 9}, {    415,10}, \
+    {    223, 9}, {    447,12}, {     63,10}, {    255, 9}, \
+    {    511, 8}, {   1023, 9}, {    543,11}, {    143, 9}, \
+    {    575,10}, {    319, 9}, {    639,10}, {    351, 9}, \
+    {    703,12}, {     95,11}, {    191,10}, {    383,11}, \
+    {    207,10}, {    415,11}, {    223,10}, {    447, 9}, \
+    {    895,13}, {     63,11}, {    255,10}, {    511,11}, \
+    {    287,10}, {    575,12}, {    159,11}, {    319,10}, \
+    {    639,11}, {    351,10}, {    703, 9}, {   1407,12}, \
+    {    191,11}, {    383,10}, {    767,11}, {    415,12}, \
+    {    223,11}, {    447,10}, {    895,11}, {    479,10}, \
+    {    959,12}, {    255,11}, {    543,10}, {   1087,11}, \
+    {    575,12}, {    319,11}, {    639,12}, {    351,11}, \
+    {    703,13}, {    191,12}, {    383,11}, {    767,12}, \
+    {    415,11}, {    831,12}, {    447,11}, {    895,12}, \
+    {    479,13}, {    255,12}, {    511,11}, {   1023,12}, \
+    {    575,13}, {    319,12}, {    703,13}, {    383,12}, \
+    {    831,13}, {    447,12}, {    959,14}, {    255,13}, \
+    {    511,12}, {   1023,13}, {    575,12}, {   1151,13}, \
+    {    703,12}, {   1407,14}, {    383,13}, {    831,12}, \
+    {   1663,13}, {    959,15}, {    255,14}, {    511,13}, \
+    {   1151,14}, {    639,13}, {   1407,14}, {    767,13}, \
+    {   1663,14}, {    895,13}, {   1791,15}, {    511,14}, \
+    {   1023,13}, {   2047,14}, {   1151,13}, {   2431,14}, \
+    {   1407,15}, {    767,14}, {   1791,16}, {    511,15}, \
+    {   1023,14}, {   2431,15}, {   1279,14}, {   2815,15}, \
+    {  32768,16}, {  65536,17}, { 131072,18}, { 262144,19}, \
+    { 524288,20}, {1048576,21}, {2097152,22}, {4194304,23}, \
+    {8388608,24} }
+#define MUL_FFT_TABLE3_SIZE 185
+#define MUL_FFT_THRESHOLD                 3200
+
+#define SQR_FFT_MODF_THRESHOLD             244  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    244, 5}, {     13, 6}, {      7, 5}, {     15, 6}, \
+    {     17, 7}, {      9, 6}, {     19, 7}, {     17, 8}, \
+    {      9, 7}, {     20, 8}, {     11, 7}, {     23, 8}, \
+    {     13, 9}, {      7, 8}, {     19, 9}, {     11, 8}, \
+    {     25,10}, {      7, 9}, {     15, 8}, {     31, 9}, \
+    {     19, 8}, {     39, 9}, {     23, 8}, {     47,10}, \
+    {     15, 9}, {     39,10}, {     23, 9}, {     47,11}, \
+    {     15,10}, {     31, 9}, {     63,10}, {     39, 9}, \
+    {     79,10}, {     47, 9}, {     95,10}, {     55,11}, \
+    {     31,10}, {     63, 8}, {    255,10}, {     71, 9}, \
+    {    143, 8}, {    287,10}, {     79, 9}, {    159, 8}, \
+    {    319,11}, {     47,10}, {     95, 9}, {    191, 8}, \
+    {    383,12}, {     31,11}, {     63,10}, {    127, 9}, \
+    {    287, 8}, {    575,11}, {     79,10}, {    159, 9}, \
+    {    319, 8}, {    639,10}, {    175, 9}, {    351, 8}, \
+    {    703,11}, {     95, 9}, {    383, 8}, {    767,10}, \
+    {    207, 9}, {    415,10}, {    223, 8}, {    895,10}, \
+    {    239,12}, {     63,11}, {    127,10}, {    255, 9}, \
+    {    511,10}, {    287, 9}, {    575,11}, {    159,10}, \
+    {    319, 9}, {    639,11}, {    175,10}, {    351, 9}, \
+    {    703,11}, {    191,10}, {    383,11}, {    207,10}, \
+    {    415,11}, {    223,10}, {    479,11}, {    255,10}, \
+    {    511,11}, {    287,10}, {    575,12}, {    159,11}, \
+    {    351,12}, {    191,11}, {    383,10}, {    767,12}, \
+    {    223,11}, {    447,10}, {    895,11}, {    479,13}, \
+    {    127,12}, {    255,11}, {    511,12}, {    287,10}, \
+    {   1151,12}, {    319,11}, {    639,12}, {    351,11}, \
+    {    703,13}, {    191,12}, {    383,11}, {    767,12}, \
+    {    415,11}, {    831,12}, {    447,11}, {    895,12}, \
+    {    479,11}, {    959,12}, {    511,11}, {   1023,12}, \
+    {    575,11}, {   1151,13}, {    319,12}, {    639,11}, \
+    {   1279,13}, {    383,12}, {    831,13}, {    447,12}, \
+    {    895,14}, {    255,13}, {    511,12}, {   1023,13}, \
+    {    703,14}, {    383,13}, {    831,12}, {   1663,13}, \
+    {    895,15}, {    255,14}, {    511,13}, {   1151,14}, \
+    {    639,13}, {   1407,14}, {    767,13}, {   1535,14}, \
+    {    895,15}, {    511,14}, {   1151,13}, {   2431,14}, \
+    {   1407,15}, {    767,14}, {   1791,16}, {    511,15}, \
+    {   1023,14}, {   2431,15}, {   1279,14}, {   2815,15}, \
+    {  32768,16}, {  65536,17}, { 131072,18}, { 262144,19}, \
+    { 524288,20}, {1048576,21}, {2097152,22}, {4194304,23}, \
+    {8388608,24} }
+#define SQR_FFT_TABLE3_SIZE 165
+#define SQR_FFT_THRESHOLD                 2496
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  39
+#define MULLO_MUL_N_THRESHOLD             6253
+#define SQRLO_BASECASE_THRESHOLD             4
+#define SQRLO_DC_THRESHOLD                  56
+#define SQRLO_SQR_THRESHOLD               4940
+
+#define DC_DIV_QR_THRESHOLD                 36
+#define DC_DIVAPPR_Q_THRESHOLD             136
+#define DC_BDIV_QR_THRESHOLD                35
+#define DC_BDIV_Q_THRESHOLD                 88
+
+#define INV_MULMOD_BNM1_THRESHOLD           30
+#define INV_NEWTON_THRESHOLD               149
+#define INV_APPR_THRESHOLD                 139
+
+#define BINV_NEWTON_THRESHOLD              166
+#define REDC_1_TO_REDC_N_THRESHOLD          38
+
+#define MU_DIV_QR_THRESHOLD               1120
+#define MU_DIVAPPR_Q_THRESHOLD            1078
+#define MUPI_DIV_QR_THRESHOLD               68
+#define MU_BDIV_QR_THRESHOLD               889
+#define MU_BDIV_Q_THRESHOLD                942
+
+#define POWM_SEC_TABLE  4,22,102,473,1730
+
+#define GET_STR_DC_THRESHOLD                11
+#define GET_STR_PRECOMPUTE_THRESHOLD        22
+#define SET_STR_DC_THRESHOLD               381
+#define SET_STR_PRECOMPUTE_THRESHOLD      1042
+
+#define FAC_DSC_THRESHOLD                  140
+#define FAC_ODD_THRESHOLD                   23
+
+#define MATRIX22_STRASSEN_THRESHOLD         11
+#define HGCD2_DIV1_METHOD                    1  /* 7.84% faster than 3 */
+#define HGCD_THRESHOLD                      80
+#define HGCD_APPR_THRESHOLD                 80
+#define HGCD_REDUCE_THRESHOLD             1679
+#define GCD_DC_THRESHOLD                   273
+#define GCDEXT_DC_THRESHOLD                201
+#define JACOBI_BASE_METHOD                   1  /* 1.03% faster than 4 */
+
+/* Tuneup completed successfully, took 64972 seconds */
diff --git a/third_party/gmp/mpn/arm64/gcd_11.asm b/third_party/gmp/mpn/arm64/gcd_11.asm
new file mode 100644
index 0000000..d8cc3e2
--- /dev/null
+++ b/third_party/gmp/mpn/arm64/gcd_11.asm
@@ -0,0 +1,70 @@
+dnl  ARM v8a mpn_gcd_11.
+
+dnl  Based on the K7 gcd_1.asm, by Kevin Ryde.  Rehacked for ARM by Torbjorn
+dnl  Granlund.
+
+dnl  Copyright 2000-2002, 2005, 2009, 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+changecom(blah)
+
+C	     cycles/bit (approx)
+C Cortex-A35	 ?
+C Cortex-A53	 ?
+C Cortex-A55	 ?
+C Cortex-A57	 ?
+C Cortex-A72	 ?
+C Cortex-A73	 ?
+C Cortex-A75	 ?
+C Cortex-A76	 ?
+C Cortex-A77	 ?
+C Numbers measured with: speed -CD -s16-64 -t48 mpn_gcd_1
+
+define(`u0',    `x0')
+define(`v0',    `x1')
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_gcd_11)
+	subs	x3, u0, v0		C			0
+	b.eq	L(end)			C
+
+	ALIGN(16)
+L(top):	rbit	x12, x3			C			1,5
+	clz	x12, x12		C			2
+	csneg	x3, x3, x3, cs		C v = abs(u-v), even	1
+	csel	u0, v0, u0, cs		C u = min(u,v)		1
+	lsr	v0, x3, x12		C			3
+	subs	x3, u0, v0		C			4
+	b.ne	L(top)			C
+
+L(end):	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm64/gcd_22.asm b/third_party/gmp/mpn/arm64/gcd_22.asm
new file mode 100644
index 0000000..5367fea
--- /dev/null
+++ b/third_party/gmp/mpn/arm64/gcd_22.asm
@@ -0,0 +1,112 @@
+dnl  ARM v8a mpn_gcd_22.
+
+dnl  Copyright 2019 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+changecom(blah)
+
+C	     cycles/bit (approx)
+C Cortex-A35	 ?
+C Cortex-A53	 7.26
+C Cortex-A55	 ?
+C Cortex-A57	 ?
+C Cortex-A72	 5.72
+C Cortex-A73	 6.43
+C Cortex-A75	 ?
+C Cortex-A76	 ?
+C Cortex-A77	 ?
+
+
+define(`u1',    `x0')
+define(`u0',    `x1')
+define(`v1',    `x2')
+define(`v0',    `x3')
+
+define(`t0',    `x5')
+define(`t1',    `x6')
+define(`cnt',   `x7')
+define(`tnc',   `x8')
+
+ASM_START()
+PROLOGUE(mpn_gcd_22)
+
+	ALIGN(16)
+L(top):	subs	t0, u0, v0		C 0 6
+	cbz	t0, L(lowz)
+	sbcs	t1, u1, v1		C 1 7
+
+	rbit	cnt, t0			C 1
+
+	cneg	t0, t0, cc		C 2
+	cinv	t1, t1, cc		C 2 u = |u - v|
+L(bck):	csel	v0, v0, u0, cs		C 2
+	csel	v1, v1, u1, cs		C 2 v = min(u,v)
+
+	clz	cnt, cnt		C 2
+	sub	tnc, xzr, cnt		C 3
+
+	lsr	u0, t0, cnt		C 3
+	lsl	x14, t1, tnc		C 4
+	lsr	u1, t1, cnt		C 3
+	orr	u0, u0, x14		C 5
+
+	orr	x11, u1, v1
+	cbnz	x11, L(top)
+
+
+	subs	x4, u0, v0		C			0
+	b.eq	L(end1)			C
+
+	ALIGN(16)
+L(top1):rbit	x12, x4			C			1,5
+	clz	x12, x12		C			2
+	csneg	x4, x4, x4, cs		C v = abs(u-v), even	1
+	csel	u0, v0, u0, cs		C u = min(u,v)		1
+	lsr	v0, x4, x12		C			3
+	subs	x4, u0, v0		C			4
+	b.ne	L(top1)			C
+L(end1):mov	x0, u0
+	mov	x1, #0
+	ret
+
+L(lowz):C We come here when v0 - u0 = 0
+	C 1. If v1 - u1 = 0, then gcd is u = v.
+	C 2. Else compute gcd_21({v1,v0}, |u1-v1|)
+	subs	t0, u1, v1
+	b.eq	L(end)
+	mov	t1, #0
+	rbit	cnt, t0			C 1
+	cneg	t0, t0, cc		C 2
+	b	L(bck)			C FIXME: make conditional
+
+L(end):	mov	x0, v0
+	mov	x1, v1
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm64/gmp-mparam.h b/third_party/gmp/mpn/arm64/gmp-mparam.h
new file mode 100644
index 0000000..7c0c193
--- /dev/null
+++ b/third_party/gmp/mpn/arm64/gmp-mparam.h
@@ -0,0 +1,192 @@
+/* gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+/* 1536 MHz Cortex-A53 */
+/* FFT tuning limit = 0.5 M */
+/* Generated by tuneup.c, 2019-09-29, gcc 5.4 */
+
+#define DIVREM_1_NORM_THRESHOLD              3
+#define DIVREM_1_UNNORM_THRESHOLD            4
+#define MOD_1_1P_METHOD                      2  /* 2.08% faster than 1 */
+#define MOD_1_NORM_THRESHOLD                 3
+#define MOD_1_UNNORM_THRESHOLD               4
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          8
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          6
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        10
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        20
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     21
+#define USE_PREINV_DIVREM_1                  1
+#define DIV_QR_1N_PI1_METHOD                 1  /* 38.26% faster than 2 */
+#define DIV_QR_1_NORM_THRESHOLD             13
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always */
+#define BMOD_1_TO_MOD_1_THRESHOLD           40
+
+#define DIV_1_VS_MUL_1_PERCENT             159
+
+#define MUL_TOOM22_THRESHOLD                14
+#define MUL_TOOM33_THRESHOLD                49
+#define MUL_TOOM44_THRESHOLD                82
+#define MUL_TOOM6H_THRESHOLD               173
+#define MUL_TOOM8H_THRESHOLD               236
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      81
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD      76
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD      81
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD      80
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD      74
+
+#define SQR_BASECASE_THRESHOLD               0  /* always */
+#define SQR_TOOM2_THRESHOLD                 18
+#define SQR_TOOM3_THRESHOLD                 67
+#define SQR_TOOM4_THRESHOLD                166
+#define SQR_TOOM6_THRESHOLD                222
+#define SQR_TOOM8_THRESHOLD                333
+
+#define MULMID_TOOM42_THRESHOLD             20
+
+#define MULMOD_BNM1_THRESHOLD               10
+#define SQRMOD_BNM1_THRESHOLD               11
+
+#define MUL_FFT_MODF_THRESHOLD             316  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    316, 5}, {     13, 6}, {      7, 5}, {     15, 6}, \
+    {     13, 7}, {      7, 6}, {     15, 7}, {      8, 6}, \
+    {     17, 7}, {      9, 6}, {     19, 7}, {     17, 8}, \
+    {      9, 7}, {     20, 8}, {     11, 7}, {     23, 8}, \
+    {     13, 9}, {      7, 8}, {     19, 9}, {     11, 8}, \
+    {     27, 9}, {     15, 8}, {     33, 9}, {     19, 8}, \
+    {     41, 9}, {     23, 8}, {     49, 9}, {     27,10}, \
+    {     15, 9}, {     39,10}, {     23, 9}, {     51,11}, \
+    {     15,10}, {     31, 9}, {     71,10}, {     39, 9}, \
+    {     83,10}, {     47, 9}, {     99,10}, {     55,11}, \
+    {     31,10}, {     63, 9}, {    127, 8}, {    255, 9}, \
+    {    131,10}, {     71, 8}, {    287,10}, {     79, 9}, \
+    {    159, 8}, {    319,10}, {     87,11}, {     47,10}, \
+    {     95, 9}, {    191, 8}, {    383,10}, {    103, 9}, \
+    {    207, 8}, {    415,10}, {    111, 9}, {    223,12}, \
+    {     31,11}, {     63, 9}, {    255, 8}, {    511,10}, \
+    {    135, 9}, {    287, 8}, {    575,11}, {     79,10}, \
+    {    159, 9}, {    319, 8}, {    639,10}, {    175, 9}, \
+    {    351, 8}, {    703,11}, {     95,10}, {    191, 9}, \
+    {    383, 8}, {    767,10}, {    207, 9}, {    415,11}, \
+    {    111,10}, {    223, 9}, {    447,12}, {     63,10}, \
+    {    255, 9}, {    511, 8}, {   1023, 9}, {    543,10}, \
+    {    287, 9}, {    575, 8}, {   1151,11}, {    159,10}, \
+    {    319, 9}, {    639,11}, {    175,10}, {    351, 9}, \
+    {    703, 8}, {   1407,12}, {     95,11}, {    191,10}, \
+    {    383, 9}, {    767,11}, {    207,10}, {    415, 9}, \
+    {    831,11}, {    223,10}, {    447,13}, {   8192,14}, \
+    {  16384,15}, {  32768,16}, {  65536,17}, { 131072,18}, \
+    { 262144,19}, { 524288,20}, {1048576,21}, {2097152,22}, \
+    {4194304,23}, {8388608,24} }
+#define MUL_FFT_TABLE3_SIZE 118
+#define MUL_FFT_THRESHOLD                 3200
+
+#define SQR_FFT_MODF_THRESHOLD             272  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    272, 5}, {     13, 6}, {      7, 5}, {     15, 6}, \
+    {      8, 5}, {     17, 6}, {     17, 7}, {     17, 8}, \
+    {      9, 7}, {     19, 8}, {     11, 7}, {     23, 8}, \
+    {     13, 9}, {      7, 8}, {     15, 7}, {     31, 8}, \
+    {     19, 9}, {     11, 8}, {     27, 9}, {     15, 8}, \
+    {     33, 9}, {     19, 8}, {     39, 9}, {     23, 8}, \
+    {     47, 9}, {     27,10}, {     15, 9}, {     39,10}, \
+    {     23, 9}, {     47,11}, {     15,10}, {     31, 9}, \
+    {     67,10}, {     39, 9}, {     79,10}, {     47, 9}, \
+    {     95, 8}, {    191,10}, {     55,11}, {     31,10}, \
+    {     63, 8}, {    255,10}, {     71, 9}, {    143, 8}, \
+    {    287,10}, {     79, 9}, {    159,11}, {     47,10}, \
+    {     95, 9}, {    191, 8}, {    383, 7}, {    767,10}, \
+    {    103, 9}, {    207,12}, {     31,11}, {     63, 9}, \
+    {    255, 8}, {    511, 7}, {   1023, 9}, {    271,10}, \
+    {    143, 9}, {    287,11}, {     79,10}, {    159, 9}, \
+    {    319, 8}, {    639,10}, {    175, 9}, {    351, 8}, \
+    {    703,11}, {     95,10}, {    191, 9}, {    383, 8}, \
+    {    767,10}, {    207, 9}, {    415, 8}, {    831,10}, \
+    {    223,12}, {     63,10}, {    255, 9}, {    511, 8}, \
+    {   1023,10}, {    271,11}, {    143,10}, {    287, 9}, \
+    {    575, 8}, {   1151,11}, {    159,10}, {    319, 9}, \
+    {    639,11}, {    175,10}, {    351, 9}, {    703,12}, \
+    {     95,11}, {    191,10}, {    383, 9}, {    767,11}, \
+    {    207,10}, {    415, 9}, {    831,11}, {    223,10}, \
+    {    447,13}, {   8192,14}, {  16384,15}, {  32768,16}, \
+    {  65536,17}, { 131072,18}, { 262144,19}, { 524288,20}, \
+    {1048576,21}, {2097152,22}, {4194304,23}, {8388608,24} }
+#define SQR_FFT_TABLE3_SIZE 112
+#define SQR_FFT_THRESHOLD                 2688
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  38
+#define MULLO_MUL_N_THRESHOLD             6253
+#define SQRLO_BASECASE_THRESHOLD             4
+#define SQRLO_DC_THRESHOLD                  67
+#define SQRLO_SQR_THRESHOLD               5240
+
+#define DC_DIV_QR_THRESHOLD                 42
+#define DC_DIVAPPR_Q_THRESHOLD             152
+#define DC_BDIV_QR_THRESHOLD                39
+#define DC_BDIV_Q_THRESHOLD                 93
+
+#define INV_MULMOD_BNM1_THRESHOLD           37
+#define INV_NEWTON_THRESHOLD               163
+#define INV_APPR_THRESHOLD                 162
+
+#define BINV_NEWTON_THRESHOLD              194
+#define REDC_1_TO_REDC_N_THRESHOLD          43
+
+#define MU_DIV_QR_THRESHOLD                998
+#define MU_DIVAPPR_Q_THRESHOLD             998
+#define MUPI_DIV_QR_THRESHOLD               98
+#define MU_BDIV_QR_THRESHOLD               807
+#define MU_BDIV_Q_THRESHOLD                924
+
+#define POWM_SEC_TABLE  6,30,194,579,1730
+
+#define GET_STR_DC_THRESHOLD                15
+#define GET_STR_PRECOMPUTE_THRESHOLD        29
+#define SET_STR_DC_THRESHOLD               788
+#define SET_STR_PRECOMPUTE_THRESHOLD      1816
+
+#define FAC_DSC_THRESHOLD                  236
+#define FAC_ODD_THRESHOLD                   24
+
+#define MATRIX22_STRASSEN_THRESHOLD         10
+#define HGCD2_DIV1_METHOD                    1  /* 7.05% faster than 3 */
+#define HGCD_THRESHOLD                     101
+#define HGCD_APPR_THRESHOLD                104
+#define HGCD_REDUCE_THRESHOLD             1679
+#define GCD_DC_THRESHOLD                   330
+#define GCDEXT_DC_THRESHOLD                242
+#define JACOBI_BASE_METHOD                   4  /* 20.00% faster than 1 */
diff --git a/third_party/gmp/mpn/arm64/hamdist.asm b/third_party/gmp/mpn/arm64/hamdist.asm
new file mode 100644
index 0000000..c72ca55
--- /dev/null
+++ b/third_party/gmp/mpn/arm64/hamdist.asm
@@ -0,0 +1,181 @@
+dnl  ARM64 Neon mpn_hamdist -- mpn bit hamming distance.
+
+dnl  Copyright 2013, 2014 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C Cortex-A53	 4.5
+C Cortex-A57	 1.9
+C X-Gene	 4.36
+
+C TODO
+C  * Consider greater unrolling.
+C  * Arrange to align the pointer, if that helps performance.  Use the same
+C    read-and-mask trick we use on PCs, for simplicity and performance.  (Sorry
+C    valgrind!)
+C  * Explore if explicit align directives, e.g., "[ptr:128]" help.
+C  * See rth's gmp-devel 2013-02/03 messages about final summation tricks.
+
+changecom(blah)
+
+C INPUT PARAMETERS
+define(`ap', x0)
+define(`bp', x1)
+define(`n',  x2)
+
+C We sum into 16 16-bit counters in v4,v5, but at the end we sum them and end
+C up with 8 16-bit counters.  Therefore, we can sum to 8(2^16-1) bits, or
+C (8*2^16-1)/64 = 0x1fff limbs.  We use a chunksize close to that, but which
+C  allows the huge count code to jump deep into the code (at L(chu)).
+
+define(`maxsize',  0x1fff)
+define(`chunksize',0x1ff0)
+
+ASM_START()
+PROLOGUE(mpn_hamdist)
+
+	mov	x11, #maxsize
+	cmp	n, x11
+	b.hi	L(gt8k)
+
+L(lt8k):
+	movi	v4.16b, #0			C clear summation register
+	movi	v5.16b, #0			C clear summation register
+
+	tbz	n, #0, L(xx0)
+	sub	n, n, #1
+	ld1	{v0.1d}, [ap], #8		C load 1 limb
+	ld1	{v16.1d}, [bp], #8		C load 1 limb
+	eor	v0.16b, v0.16b, v16.16b
+	cnt	v6.16b, v0.16b
+	uadalp	v4.8h,  v6.16b			C could also splat
+
+L(xx0):	tbz	n, #1, L(x00)
+	sub	n, n, #2
+	ld1	{v0.2d}, [ap], #16		C load 2 limbs
+	ld1	{v16.2d}, [bp], #16		C load 2 limbs
+	eor	v0.16b, v0.16b, v16.16b
+	cnt	v6.16b, v0.16b
+	uadalp	v4.8h,  v6.16b
+
+L(x00):	tbz	n, #2, L(000)
+	subs	n, n, #4
+	ld1	{v0.2d,v1.2d}, [ap], #32	C load 4 limbs
+	ld1	{v16.2d,v17.2d}, [bp], #32	C load 4 limbs
+	b.ls	L(sum)
+
+L(gt4):	ld1	{v2.2d,v3.2d}, [ap], #32	C load 4 limbs
+	ld1	{v18.2d,v19.2d}, [bp], #32	C load 4 limbs
+	eor	v0.16b, v0.16b, v16.16b
+	eor	v1.16b, v1.16b, v17.16b
+	sub	n, n, #4
+	cnt	v6.16b, v0.16b
+	cnt	v7.16b, v1.16b
+	b	L(mid)
+
+L(000):	subs	n, n, #8
+	b.lo	L(e0)
+
+L(chu):	ld1	{v2.2d,v3.2d}, [ap], #32	C load 4 limbs
+	ld1	{v0.2d,v1.2d}, [ap], #32	C load 4 limbs
+	ld1	{v18.2d,v19.2d}, [bp], #32	C load 4 limbs
+	ld1	{v16.2d,v17.2d}, [bp], #32	C load 4 limbs
+	eor	v2.16b, v2.16b, v18.16b
+	eor	v3.16b, v3.16b, v19.16b
+	cnt	v6.16b, v2.16b
+	cnt	v7.16b, v3.16b
+	subs	n, n, #8
+	b.lo	L(end)
+
+L(top):	ld1	{v2.2d,v3.2d}, [ap], #32	C load 4 limbs
+	ld1	{v18.2d,v19.2d}, [bp], #32	C load 4 limbs
+	eor	v0.16b, v0.16b, v16.16b
+	eor	v1.16b, v1.16b, v17.16b
+	uadalp	v4.8h,  v6.16b
+	cnt	v6.16b, v0.16b
+	uadalp	v5.8h,  v7.16b
+	cnt	v7.16b, v1.16b
+L(mid):	ld1	{v0.2d,v1.2d}, [ap], #32	C load 4 limbs
+	ld1	{v16.2d,v17.2d}, [bp], #32	C load 4 limbs
+	eor	v2.16b, v2.16b, v18.16b
+	eor	v3.16b, v3.16b, v19.16b
+	subs	n, n, #8
+	uadalp	v4.8h,  v6.16b
+	cnt	v6.16b, v2.16b
+	uadalp	v5.8h,  v7.16b
+	cnt	v7.16b, v3.16b
+	b.hs	L(top)
+
+L(end):	uadalp	v4.8h,  v6.16b
+	uadalp	v5.8h,  v7.16b
+L(sum):	eor	v0.16b, v0.16b, v16.16b
+	eor	v1.16b, v1.16b, v17.16b
+	cnt	v6.16b, v0.16b
+	cnt	v7.16b, v1.16b
+	uadalp	v4.8h,  v6.16b
+	uadalp	v5.8h,  v7.16b
+	add	v4.8h, v4.8h, v5.8h
+					C we have 8 16-bit counts
+L(e0):	uaddlp	v4.4s,  v4.8h		C we have 4 32-bit counts
+	uaddlp	v4.2d,  v4.4s		C we have 2 64-bit counts
+	mov	x0, v4.d[0]
+	mov	x1, v4.d[1]
+	add	x0, x0, x1
+	ret
+
+C Code for count > maxsize.  Splits operand and calls above code.
+define(`ap2', x5)			C caller-saves reg not used above
+define(`bp2', x6)			C caller-saves reg not used above
+L(gt8k):
+	mov	x8, x30
+	mov	x7, n			C full count (caller-saves reg not used above)
+	mov	x4, #0			C total sum  (caller-saves reg not used above)
+	mov	x9, #chunksize*8	C caller-saves reg not used above
+	mov	x10, #chunksize		C caller-saves reg not used above
+
+1:	add	ap2, ap, x9		C point at subsequent block
+	add	bp2, bp, x9		C point at subsequent block
+	mov	n, #chunksize-8		C count for this invocation, adjusted for entry pt
+	movi	v4.16b, #0		C clear chunk summation register
+	movi	v5.16b, #0		C clear chunk summation register
+	bl	L(chu)			C jump deep inside code
+	add	x4, x4, x0
+	mov	ap, ap2			C put chunk pointer in place for calls
+	mov	bp, bp2			C put chunk pointer in place for calls
+	sub	x7, x7, x10
+	cmp	x7, x11
+	b.hi	1b
+
+	mov	n, x7			C count for final invocation
+	bl	L(lt8k)
+	add	x0, x4, x0
+	mov	x30, x8
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm64/invert_limb.asm b/third_party/gmp/mpn/arm64/invert_limb.asm
new file mode 100644
index 0000000..a94b0e9
--- /dev/null
+++ b/third_party/gmp/mpn/arm64/invert_limb.asm
@@ -0,0 +1,83 @@
+dnl  ARM64 mpn_invert_limb -- Invert a normalized limb.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C            cycles/limb
+C Cortex-A53     ?
+C Cortex-A57     ?
+
+C Compiler generated, mildly edited.  Could surely be further optimised.
+
+ASM_START()
+PROLOGUE(mpn_invert_limb)
+	lsr	x2, x0, #54
+	adrp	x1, approx_tab
+	and	x2, x2, #0x1fe
+	add	x1, x1, :lo12:approx_tab
+	ldrh	w3, [x1,x2]
+	lsr	x4, x0, #24
+	add	x4, x4, #1
+	ubfiz	x2, x3, #11, #16
+	umull	x3, w3, w3
+	mul	x3, x3, x4
+	sub	x2, x2, #1
+	sub	x2, x2, x3, lsr #40
+	lsl	x3, x2, #60
+	mul	x1, x2, x2
+	msub	x1, x1, x4, x3
+	lsl	x2, x2, #13
+	add	x1, x2, x1, lsr #47
+	and	x2, x0, #1
+	neg	x3, x2
+	and	x3, x3, x1, lsr #1
+	add	x2, x2, x0, lsr #1
+	msub	x2, x1, x2, x3
+	umulh	x2, x2, x1
+	lsl	x1, x1, #31
+	add	x1, x1, x2, lsr #1
+	mul	x3, x1, x0
+	umulh	x2, x1, x0
+	adds	x4, x3, x0
+	adc	x0, x2, x0
+	sub	x0, x1, x0
+	ret
+EPILOGUE()
+
+	RODATA
+	ALIGN(2)
+	TYPE(   approx_tab, object)
+	SIZE(   approx_tab, 512)
+approx_tab:
+forloop(i,256,512-1,dnl
+`	.hword	eval(0x7fd00/i)
+')dnl
diff --git a/third_party/gmp/mpn/arm64/logops_n.asm b/third_party/gmp/mpn/arm64/logops_n.asm
new file mode 100644
index 0000000..ccaec9c
--- /dev/null
+++ b/third_party/gmp/mpn/arm64/logops_n.asm
@@ -0,0 +1,139 @@
+dnl  ARM64 mpn_and_n, mpn_andn_n. mpn_nand_n, etc.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb     cycles/limb
+C	      nand,nior	      all other
+C Cortex-A53	3.25-3.5	2.75-3
+C Cortex-A57	 2.0		 1.5
+C X-Gene	 2.14		 2.0
+
+changecom(blah)
+
+define(`rp', `x0')
+define(`up', `x1')
+define(`vp', `x2')
+define(`n',  `x3')
+
+define(`POSTOP', `dnl')
+
+ifdef(`OPERATION_and_n',`
+  define(`func',    `mpn_and_n')
+  define(`LOGOP',   `and	$1, $2, $3')')
+ifdef(`OPERATION_andn_n',`
+  define(`func',    `mpn_andn_n')
+  define(`LOGOP',   `bic	$1, $2, $3')')
+ifdef(`OPERATION_nand_n',`
+  define(`func',    `mpn_nand_n')
+  define(`POSTOP',  `mvn	$1, $1')
+  define(`LOGOP',   `and	$1, $2, $3')')
+ifdef(`OPERATION_ior_n',`
+  define(`func',    `mpn_ior_n')
+  define(`LOGOP',   `orr	$1, $2, $3')')
+ifdef(`OPERATION_iorn_n',`
+  define(`func',    `mpn_iorn_n')
+  define(`LOGOP',   `orn	$1, $2, $3')')
+ifdef(`OPERATION_nior_n',`
+  define(`func',    `mpn_nior_n')
+  define(`POSTOP',  `mvn	$1, $1')
+  define(`LOGOP',   `orr	$1, $2, $3')')
+ifdef(`OPERATION_xor_n',`
+  define(`func',    `mpn_xor_n')
+  define(`LOGOP',   `eor	$1, $2, $3')')
+ifdef(`OPERATION_xnor_n',`
+  define(`func',    `mpn_xnor_n')
+  define(`LOGOP',   `eon	$1, $2, $3')')
+
+MULFUNC_PROLOGUE(mpn_and_n mpn_andn_n mpn_nand_n mpn_ior_n mpn_iorn_n mpn_nior_n mpn_xor_n mpn_xnor_n)
+
+ASM_START()
+PROLOGUE(func)
+	lsr	x18, n, #2
+	tbz	n, #0, L(bx0)
+
+L(bx1):	ldr	x7, [up]
+	ldr	x11, [vp]
+	LOGOP(	x15, x7, x11)
+	POSTOP(	x15)
+	str	x15, [rp],#8
+	tbnz	n, #1, L(b11)
+
+L(b01):	cbz	x18, L(ret)
+	ldp	x4, x5, [up,#8]
+	ldp	x8, x9, [vp,#8]
+	sub	up, up, #8
+	sub	vp, vp, #8
+	b	L(mid)
+
+L(b11):	ldp	x6, x7, [up,#8]
+	ldp	x10, x11, [vp,#8]
+	add	up, up, #8
+	add	vp, vp, #8
+	cbz	x18, L(end)
+	b	L(top)
+
+L(bx0):	tbnz	n, #1, L(b10)
+
+L(b00):	ldp	x4, x5, [up],#-16
+	ldp	x8, x9, [vp],#-16
+	b	L(mid)
+
+L(b10):	ldp	x6, x7, [up]
+	ldp	x10, x11, [vp]
+	cbz	x18, L(end)
+
+	ALIGN(16)
+L(top):	ldp	x4, x5, [up,#16]
+	ldp	x8, x9, [vp,#16]
+	LOGOP(	x12, x6, x10)
+	LOGOP(	x13, x7, x11)
+	POSTOP(	x12)
+	POSTOP(	x13)
+	stp	x12, x13, [rp],#16
+L(mid):	ldp	x6, x7, [up,#32]!
+	ldp	x10, x11, [vp,#32]!
+	LOGOP(	x12, x4, x8)
+	LOGOP(	x13, x5, x9)
+	POSTOP(	x12)
+	POSTOP(	x13)
+	stp	x12, x13, [rp],#16
+	sub	x18, x18, #1
+	cbnz	x18, L(top)
+
+L(end):	LOGOP(	x12, x6, x10)
+	LOGOP(	x13, x7, x11)
+	POSTOP(	x12)
+	POSTOP(	x13)
+	stp	x12, x13, [rp]
+L(ret):	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm64/lshift.asm b/third_party/gmp/mpn/arm64/lshift.asm
new file mode 100644
index 0000000..472b7ec
--- /dev/null
+++ b/third_party/gmp/mpn/arm64/lshift.asm
@@ -0,0 +1,127 @@
+dnl  ARM64 mpn_lshift.
+
+dnl  Copyright 2013, 2014, 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of the GNU Lesser General Public License as published
+dnl  by the Free Software Foundation; either version 3 of the License, or (at
+dnl  your option) any later version.
+
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+dnl  License for more details.
+
+dnl  You should have received a copy of the GNU Lesser General Public License
+dnl  along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb   assumed optimal c/l
+C Cortex-A53	3.5-4.0		 3.25
+C Cortex-A57	 2.0		 2.0
+C X-Gene	 2.67		 2.5
+
+C TODO
+C  * The feed-in code used 1 ldr for odd sized and 2 ldr for even sizes.  These
+C    numbers should be 1 and 0, respectively.  The str in wind-down should also
+C    go.
+C  * Using extr and with 63 separate loops we might reach 1.25 c/l on A57.
+C  * A53's speed depends on alignment, tune/speed -w1 gives 3.5, -w0 gives 4.0.
+
+changecom(blah)
+
+define(`rp_arg', `x0')
+define(`up',     `x1')
+define(`n',      `x2')
+define(`cnt',    `x3')
+
+define(`rp',     `x16')
+
+define(`tnc',`x8')
+
+define(`PSHIFT', lsl)
+define(`NSHIFT', lsr)
+
+ASM_START()
+PROLOGUE(mpn_lshift)
+	add	rp, rp_arg, n, lsl #3
+	add	up, up, n, lsl #3
+	sub	tnc, xzr, cnt
+	lsr	x18, n, #2
+	tbz	n, #0, L(bx0)
+
+L(bx1):	ldr	x4, [up,#-8]
+	tbnz	n, #1, L(b11)
+
+L(b01):	NSHIFT	x0, x4, tnc
+	PSHIFT	x2, x4, cnt
+	cbnz	x18, L(gt1)
+	str	x2, [rp,#-8]
+	ret
+L(gt1):	ldp	x4, x5, [up,#-24]
+	sub	up, up, #8
+	add	rp, rp, #16
+	b	L(lo2)
+
+L(b11):	NSHIFT	x0, x4, tnc
+	PSHIFT	x2, x4, cnt
+	ldp	x6, x7, [up,#-24]!
+	b	L(lo3)
+
+L(bx0):	ldp	x4, x5, [up,#-16]
+	tbz	n, #1, L(b00)
+
+L(b10):	NSHIFT	x0, x5, tnc
+	PSHIFT	x13, x5, cnt
+	NSHIFT	x10, x4, tnc
+	PSHIFT	x2, x4, cnt
+	cbnz	x18, L(gt2)
+	orr	x10, x10, x13
+	stp	x2, x10, [rp,#-16]
+	ret
+L(gt2):	ldp	x4, x5, [up,#-32]
+	orr	x10, x10, x13
+	str	x10, [rp,#-8]
+	sub	up, up, #16
+	add	rp, rp, #8
+	b	L(lo2)
+
+L(b00):	NSHIFT	x0, x5, tnc
+	PSHIFT	x13, x5, cnt
+	NSHIFT	x10, x4, tnc
+	PSHIFT	x2, x4, cnt
+	ldp	x6, x7, [up,#-32]!
+	orr	x10, x10, x13
+	str	x10, [rp,#-8]!
+	b	L(lo0)
+
+	ALIGN(16)
+L(top):	ldp	x4, x5, [up,#-16]
+	orr	x10, x10, x13
+	orr	x11, x12, x2
+	stp	x10, x11, [rp,#-16]
+	PSHIFT	x2, x6, cnt
+L(lo2):	NSHIFT	x10, x4, tnc
+	PSHIFT	x13, x5, cnt
+	NSHIFT	x12, x5, tnc
+	ldp	x6, x7, [up,#-32]!
+	orr	x10, x10, x13
+	orr	x11, x12, x2
+	stp	x10, x11, [rp,#-32]!
+	PSHIFT	x2, x4, cnt
+L(lo0):	sub	x18, x18, #1
+L(lo3):	NSHIFT	x10, x6, tnc
+	PSHIFT	x13, x7, cnt
+	NSHIFT	x12, x7, tnc
+	cbnz	x18, L(top)
+
+L(end):	orr	x10, x10, x13
+	orr	x11, x12, x2
+	PSHIFT	x2, x6, cnt
+	stp	x10, x11, [rp,#-16]
+	str	x2, [rp,#-24]
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm64/lshiftc.asm b/third_party/gmp/mpn/arm64/lshiftc.asm
new file mode 100644
index 0000000..dd4c4ce
--- /dev/null
+++ b/third_party/gmp/mpn/arm64/lshiftc.asm
@@ -0,0 +1,130 @@
+dnl  ARM64 mpn_lshiftc.
+
+dnl  Copyright 2013, 2014, 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of the GNU Lesser General Public License as published
+dnl  by the Free Software Foundation; either version 3 of the License, or (at
+dnl  your option) any later version.
+
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+dnl  License for more details.
+
+dnl  You should have received a copy of the GNU Lesser General Public License
+dnl  along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb   assumed optimal c/l
+C Cortex-A53	3.5-4.0		 3.25
+C Cortex-A57	 2.0		 2.0
+C X-Gene	 2.67		 2.5
+
+C TODO
+C  * The feed-in code used 1 ldr for odd sized and 2 ldr for even sizes.  These
+C    numbers should be 1 and 0, respectively.  The str in wind-down should also
+C    go.
+C  * Using extr and with 63 separate loops we might reach 1.5 c/l on A57.
+C  * A53's speed depends on alignment, tune/speed -w1 gives 3.5, -w0 gives 4.0.
+
+changecom(blah)
+
+define(`rp_arg', `x0')
+define(`up',     `x1')
+define(`n',      `x2')
+define(`cnt',    `x3')
+
+define(`rp',     `x16')
+
+define(`tnc',`x8')
+
+define(`PSHIFT', lsl)
+define(`NSHIFT', lsr)
+
+ASM_START()
+PROLOGUE(mpn_lshiftc)
+	add	rp, rp_arg, n, lsl #3
+	add	up, up, n, lsl #3
+	sub	tnc, xzr, cnt
+	lsr	x18, n, #2
+	tbz	n, #0, L(bx0)
+
+L(bx1):	ldr	x4, [up,#-8]
+	tbnz	n, #1, L(b11)
+
+L(b01):	NSHIFT	x0, x4, tnc
+	PSHIFT	x2, x4, cnt
+	cbnz	x18, L(gt1)
+	mvn	x2, x2
+	str	x2, [rp,#-8]
+	ret
+L(gt1):	ldp	x4, x5, [up,#-24]
+	sub	up, up, #8
+	add	rp, rp, #16
+	b	L(lo2)
+
+L(b11):	NSHIFT	x0, x4, tnc
+	PSHIFT	x2, x4, cnt
+	ldp	x6, x7, [up,#-24]!
+	b	L(lo3)
+
+L(bx0):	ldp	x4, x5, [up,#-16]
+	tbz	n, #1, L(b00)
+
+L(b10):	NSHIFT	x0, x5, tnc
+	PSHIFT	x13, x5, cnt
+	NSHIFT	x10, x4, tnc
+	PSHIFT	x2, x4, cnt
+	cbnz	x18, L(gt2)
+	eon	x10, x10, x13
+	mvn	x2, x2
+	stp	x2, x10, [rp,#-16]
+	ret
+L(gt2):	ldp	x4, x5, [up,#-32]
+	eon	x10, x10, x13
+	str	x10, [rp,#-8]
+	sub	up, up, #16
+	add	rp, rp, #8
+	b	L(lo2)
+
+L(b00):	NSHIFT	x0, x5, tnc
+	PSHIFT	x13, x5, cnt
+	NSHIFT	x10, x4, tnc
+	PSHIFT	x2, x4, cnt
+	ldp	x6, x7, [up,#-32]!
+	eon	x10, x10, x13
+	str	x10, [rp,#-8]!
+	b	L(lo0)
+
+	ALIGN(16)
+L(top):	ldp	x4, x5, [up,#-16]
+	eon	x10, x10, x13
+	eon	x11, x12, x2
+	stp	x10, x11, [rp,#-16]
+	PSHIFT	x2, x6, cnt
+L(lo2):	NSHIFT	x10, x4, tnc
+	PSHIFT	x13, x5, cnt
+	NSHIFT	x12, x5, tnc
+	ldp	x6, x7, [up,#-32]!
+	eon	x10, x10, x13
+	eon	x11, x12, x2
+	stp	x10, x11, [rp,#-32]!
+	PSHIFT	x2, x4, cnt
+L(lo0):	sub	x18, x18, #1
+L(lo3):	NSHIFT	x10, x6, tnc
+	PSHIFT	x13, x7, cnt
+	NSHIFT	x12, x7, tnc
+	cbnz	x18, L(top)
+
+L(end):	eon	x10, x10, x13
+	eon	x11, x12, x2
+	PSHIFT	x2, x6, cnt
+	stp	x10, x11, [rp,#-16]
+	mvn	x2, x2
+	str	x2, [rp,#-24]
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm64/mod_34lsub1.asm b/third_party/gmp/mpn/arm64/mod_34lsub1.asm
new file mode 100644
index 0000000..7945fe7
--- /dev/null
+++ b/third_party/gmp/mpn/arm64/mod_34lsub1.asm
@@ -0,0 +1,124 @@
+dnl  ARM64 mpn_mod_34lsub1 -- remainder modulo 2^48-1.
+
+dnl  Copyright 2012-2014 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C Cortex-A53	 2
+C Cortex-A57	 1
+C X-Gene	 1.45
+
+define(`ap',	x0)
+define(`n',	x1)
+
+changecom(blah)
+
+C mp_limb_t mpn_mod_34lsub1 (mp_srcptr up, mp_size_t n)
+
+C TODO
+C  * An alternative inner loop which could run at 0.722 c/l on A57:
+C	adds	x8, x8, x2
+C	adcs	x9, x9, x3
+C	ldp	x2, x3, [ap, #-32]
+C	adcs	x10, x10, x4
+C	adc	x12, x12, xzr
+C	adds	x8, x8, x5
+C	ldp	x4, x5, [ap, #-16]
+C	sub	n, n, #6
+C	adcs	x9, x9, x6
+C	adcs	x10, x10, x7
+C	ldp	x6, x7, [ap], #48
+C	adc	x12, x12, xzr
+C	tbz	n, #63, L(top)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_mod_34lsub1)
+	subs	n, n, #3
+	mov	x8, #0
+	b.lt	L(le2)			C n <= 2
+
+	ldp	x2, x3, [ap, #0]
+	ldr	x4, [ap, #16]
+	add	ap, ap, #24
+	subs	n, n, #3
+	b.lt	L(sum)			C n <= 5
+	cmn	x0, #0			C clear carry
+
+L(top):	ldp	x5, x6, [ap, #0]
+	ldr	x7, [ap, #16]
+	add	ap, ap, #24
+	sub	n, n, #3
+	adcs	x2, x2, x5
+	adcs	x3, x3, x6
+	adcs	x4, x4, x7
+	tbz	n, #63, L(top)
+
+	adc	x8, xzr, xzr		C x8 <= 1
+
+L(sum):	cmn	n, #2
+	mov	x5, #0
+	b.lo	1f
+	ldr	x5, [ap], #8
+1:	mov	x6, #0
+	b.ls	1f
+	ldr	x6, [ap], #8
+1:	adds	x2, x2, x5
+	adcs	x3, x3, x6
+	adcs	x4, x4, xzr
+	adc	x8, x8, xzr		C x8 <= 2
+
+L(sum2):
+	and	x0, x2, #0xffffffffffff
+	add	x0, x0, x2, lsr #48
+	add	x0, x0, x8
+
+	lsl	x8, x3, #16
+	and	x1, x8, #0xffffffffffff
+	add	x0, x0, x1
+	add	x0, x0, x3, lsr #32
+
+	lsl	x8, x4, #32
+	and	x1, x8, #0xffffffffffff
+	add	x0, x0, x1
+	add	x0, x0, x4, lsr #16
+	ret
+
+L(le2):	cmn	n, #1
+	b.ne	L(1)
+	ldp	x2, x3, [ap]
+	mov	x4, #0
+	b	L(sum2)
+L(1):	ldr	x2, [ap]
+	and	x0, x2, #0xffffffffffff
+	add	x0, x0, x2, lsr #48
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm64/mul_1.asm b/third_party/gmp/mpn/arm64/mul_1.asm
new file mode 100644
index 0000000..d1d3394
--- /dev/null
+++ b/third_party/gmp/mpn/arm64/mul_1.asm
@@ -0,0 +1,127 @@
+dnl  ARM64 mpn_mul_1
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013, 2015, 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C Cortex-A53	7.5-8
+C Cortex-A57	 7
+C Cortex-A72
+C X-Gene	 4
+
+C TODO
+C  * Start first multiply earlier.
+
+changecom(blah)
+
+define(`rp', `x0')
+define(`up', `x1')
+define(`n',  `x2')
+define(`v0', `x3')
+
+
+PROLOGUE(mpn_mul_1c)
+	adds	xzr, xzr, xzr		C clear cy flag
+	b	L(com)
+EPILOGUE()
+
+PROLOGUE(mpn_mul_1)
+	adds	x4, xzr, xzr		C clear register and cy flag
+L(com):	lsr	x18, n, #2
+	tbnz	n, #0, L(bx1)
+
+L(bx0):	mov	x11, x4
+	tbz	n, #1, L(b00)
+
+L(b10):	ldp	x4, x5, [up]
+	mul	x8, x4, v0
+	umulh	x10, x4, v0
+	cbz	x18, L(2)
+	ldp	x6, x7, [up,#16]!
+	mul	x9, x5, v0
+	b	L(mid)-8
+
+L(2):	mul	x9, x5, v0
+	b	L(2e)
+
+L(bx1):	ldr	x7, [up],#8
+	mul	x9, x7, v0
+	umulh	x11, x7, v0
+	adds	x9, x9, x4
+	str	x9, [rp],#8
+	tbnz	n, #1, L(b10)
+
+L(b01):	cbz	x18, L(1)
+
+L(b00):	ldp	x6, x7, [up]
+	mul	x8, x6, v0
+	umulh	x10, x6, v0
+	ldp	x4, x5, [up,#16]
+	mul	x9, x7, v0
+	adcs	x12, x8, x11
+	umulh	x11, x7, v0
+	add	rp, rp, #16
+	sub	x18, x18, #1
+	cbz	x18, L(end)
+
+	ALIGN(16)
+L(top):	mul	x8, x4, v0
+	ldp	x6, x7, [up,#32]!
+	adcs	x13, x9, x10
+	umulh	x10, x4, v0
+	mul	x9, x5, v0
+	stp	x12, x13, [rp,#-16]
+	adcs	x12, x8, x11
+	umulh	x11, x5, v0
+L(mid):	mul	x8, x6, v0
+	ldp	x4, x5, [up,#16]
+	adcs	x13, x9, x10
+	umulh	x10, x6, v0
+	mul	x9, x7, v0
+	stp	x12, x13, [rp],#32
+	adcs	x12, x8, x11
+	umulh	x11, x7, v0
+	sub	x18, x18, #1
+	cbnz	x18, L(top)
+
+L(end):	mul	x8, x4, v0
+	adcs	x13, x9, x10
+	umulh	x10, x4, v0
+	mul	x9, x5, v0
+	stp	x12, x13, [rp,#-16]
+L(2e):	adcs	x12, x8, x11
+	umulh	x11, x5, v0
+	adcs	x13, x9, x10
+	stp	x12, x13, [rp]
+L(1):	adc	x0, x11, xzr
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm64/popcount.asm b/third_party/gmp/mpn/arm64/popcount.asm
new file mode 100644
index 0000000..74de3fc
--- /dev/null
+++ b/third_party/gmp/mpn/arm64/popcount.asm
@@ -0,0 +1,157 @@
+dnl  ARM64 Neon mpn_popcount -- mpn bit population count.
+
+dnl  Copyright 2013, 2014 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C Cortex-A53	 2.5
+C Cortex-A57	 1.14
+C X-Gene	 3
+
+C TODO
+C  * Consider greater unrolling.
+C  * Arrange to align the pointer, if that helps performance.  Use the same
+C    read-and-mask trick we use on PCs, for simplicity and performance.  (Sorry
+C    valgrind!)
+C  * Explore if explicit align directives, e.g., "[ptr:128]" help.
+C  * See rth's gmp-devel 2013-02/03 messages about final summation tricks.
+
+changecom(blah)
+
+C INPUT PARAMETERS
+define(`ap', x0)
+define(`n',  x1)
+
+C We sum into 16 16-bit counters in v4,v5, but at the end we sum them and end
+C up with 8 16-bit counters.  Therefore, we can sum to 8(2^16-1) bits, or
+C (8*2^16-1)/64 = 0x1fff limbs.  We use a chunksize close to that, but which
+C  allows the huge count code to jump deep into the code (at L(chu)).
+
+define(`maxsize',  0x1fff)
+define(`chunksize',0x1ff0)
+
+ASM_START()
+PROLOGUE(mpn_popcount)
+
+	mov	x11, #maxsize
+	cmp	n, x11
+	b.hi	L(gt8k)
+
+L(lt8k):
+	movi	v4.16b, #0			C clear summation register
+	movi	v5.16b, #0			C clear summation register
+
+	tbz	n, #0, L(xx0)
+	sub	n, n, #1
+	ld1	{v0.1d}, [ap], #8		C load 1 limb
+	cnt	v6.16b, v0.16b
+	uadalp	v4.8h,  v6.16b			C could also splat
+
+L(xx0):	tbz	n, #1, L(x00)
+	sub	n, n, #2
+	ld1	{v0.2d}, [ap], #16		C load 2 limbs
+	cnt	v6.16b, v0.16b
+	uadalp	v4.8h,  v6.16b
+
+L(x00):	tbz	n, #2, L(000)
+	subs	n, n, #4
+	ld1	{v0.2d,v1.2d}, [ap], #32	C load 4 limbs
+	b.ls	L(sum)
+
+L(gt4):	ld1	{v2.2d,v3.2d}, [ap], #32	C load 4 limbs
+	sub	n, n, #4
+	cnt	v6.16b, v0.16b
+	cnt	v7.16b, v1.16b
+	b	L(mid)
+
+L(000):	subs	n, n, #8
+	b.lo	L(e0)
+
+L(chu):	ld1	{v2.2d,v3.2d}, [ap], #32	C load 4 limbs
+	ld1	{v0.2d,v1.2d}, [ap], #32	C load 4 limbs
+	cnt	v6.16b, v2.16b
+	cnt	v7.16b, v3.16b
+	subs	n, n, #8
+	b.lo	L(end)
+
+L(top):	ld1	{v2.2d,v3.2d}, [ap], #32	C load 4 limbs
+	uadalp	v4.8h,  v6.16b
+	cnt	v6.16b, v0.16b
+	uadalp	v5.8h,  v7.16b
+	cnt	v7.16b, v1.16b
+L(mid):	ld1	{v0.2d,v1.2d}, [ap], #32	C load 4 limbs
+	subs	n, n, #8
+	uadalp	v4.8h,  v6.16b
+	cnt	v6.16b, v2.16b
+	uadalp	v5.8h,  v7.16b
+	cnt	v7.16b, v3.16b
+	b.hs	L(top)
+
+L(end):	uadalp	v4.8h,  v6.16b
+	uadalp	v5.8h,  v7.16b
+L(sum):	cnt	v6.16b, v0.16b
+	cnt	v7.16b, v1.16b
+	uadalp	v4.8h,  v6.16b
+	uadalp	v5.8h,  v7.16b
+	add	v4.8h, v4.8h, v5.8h
+					C we have 8 16-bit counts
+L(e0):	uaddlp	v4.4s,  v4.8h		C we have 4 32-bit counts
+	uaddlp	v4.2d,  v4.4s		C we have 2 64-bit counts
+	mov	x0, v4.d[0]
+	mov	x1, v4.d[1]
+	add	x0, x0, x1
+	ret
+
+C Code for count > maxsize.  Splits operand and calls above code.
+define(`ap2', x5)			C caller-saves reg not used above
+L(gt8k):
+	mov	x8, x30
+	mov	x7, n			C full count (caller-saves reg not used above)
+	mov	x4, #0			C total sum  (caller-saves reg not used above)
+	mov	x9, #chunksize*8	C caller-saves reg not used above
+	mov	x10, #chunksize		C caller-saves reg not used above
+
+1:	add	ap2, ap, x9		C point at subsequent block
+	mov	n, #chunksize-8		C count for this invocation, adjusted for entry pt
+	movi	v4.16b, #0		C clear chunk summation register
+	movi	v5.16b, #0		C clear chunk summation register
+	bl	L(chu)			C jump deep inside code
+	add	x4, x4, x0
+	mov	ap, ap2			C put chunk pointer in place for calls
+	sub	x7, x7, x10
+	cmp	x7, x11
+	b.hi	1b
+
+	mov	n, x7			C count for final invocation
+	bl	L(lt8k)
+	add	x0, x4, x0
+	mov	x30, x8
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm64/rsh1aors_n.asm b/third_party/gmp/mpn/arm64/rsh1aors_n.asm
new file mode 100644
index 0000000..e0b760b
--- /dev/null
+++ b/third_party/gmp/mpn/arm64/rsh1aors_n.asm
@@ -0,0 +1,168 @@
+dnl  ARM64 mpn_rsh1add_n and mpn_rsh1sub_n.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb   assumed optimal c/l
+C Cortex-A53	3.25-3.75	 3.0 steady
+C Cortex-A57	 2.15		 1.75
+C X-Gene	 2.75		 2.5
+
+changecom(blah)
+
+define(`rp', `x0')
+define(`up', `x1')
+define(`vp', `x2')
+define(`n',  `x3')
+
+ifdef(`OPERATION_rsh1add_n', `
+  define(`ADDSUB',	adds)
+  define(`ADDSUBC',	adcs)
+  define(`COND',	`cs')
+  define(`func_n',	mpn_rsh1add_n)')
+ifdef(`OPERATION_rsh1sub_n', `
+  define(`ADDSUB',	subs)
+  define(`ADDSUBC',	sbcs)
+  define(`COND',	`cc')
+  define(`func_n',	mpn_rsh1sub_n)')
+
+MULFUNC_PROLOGUE(mpn_rsh1add_n mpn_rsh1sub_n)
+
+ASM_START()
+PROLOGUE(func_n)
+	lsr	x18, n, #2
+
+	tbz	n, #0, L(bx0)
+
+L(bx1):	ldr	x5, [up],#8
+	ldr	x9, [vp],#8
+	tbnz	n, #1, L(b11)
+
+L(b01):	ADDSUB	x13, x5, x9
+	and	x10, x13, #1
+	cbz	x18, L(1)
+	ldp	x4, x5, [up],#48
+	ldp	x8, x9, [vp],#48
+	ADDSUBC	x14, x4, x8
+	ADDSUBC	x15, x5, x9
+	ldp	x4, x5, [up,#-32]
+	ldp	x8, x9, [vp,#-32]
+	extr	x17, x14, x13, #1
+	ADDSUBC	x12, x4, x8
+	ADDSUBC	x13, x5, x9
+	str	x17, [rp], #24
+	sub	x18, x18, #1
+	cbz	x18, L(end)
+	b	L(top)
+
+L(1):	cset	x14, COND
+	extr	x17, x14, x13, #1
+	str	x17, [rp]
+	mov	x0, x10
+	ret
+
+L(b11):	ADDSUB	x15, x5, x9
+	and	x10, x15, #1
+
+	ldp	x4, x5, [up],#32
+	ldp	x8, x9, [vp],#32
+	ADDSUBC	x12, x4, x8
+	ADDSUBC	x13, x5, x9
+	cbz	x18, L(3)
+	ldp	x4, x5, [up,#-16]
+	ldp	x8, x9, [vp,#-16]
+	extr	x17, x12, x15, #1
+	ADDSUBC	x14, x4, x8
+	ADDSUBC	x15, x5, x9
+	str	x17, [rp], #8
+	b	L(mid)
+
+L(3):	extr	x17, x12, x15, #1
+	str	x17, [rp], #8
+	b	L(2)
+
+L(bx0):	tbz	n, #1, L(b00)
+
+L(b10):	ldp	x4, x5, [up],#32
+	ldp	x8, x9, [vp],#32
+	ADDSUB	x12, x4, x8
+	ADDSUBC	x13, x5, x9
+	and	x10, x12, #1
+	cbz	x18, L(2)
+	ldp	x4, x5, [up,#-16]
+	ldp	x8, x9, [vp,#-16]
+	ADDSUBC	x14, x4, x8
+	ADDSUBC	x15, x5, x9
+	b	L(mid)
+
+L(b00):	ldp	x4, x5, [up],#48
+	ldp	x8, x9, [vp],#48
+	ADDSUB	x14, x4, x8
+	ADDSUBC	x15, x5, x9
+	and	x10, x14, #1
+	ldp	x4, x5, [up,#-32]
+	ldp	x8, x9, [vp,#-32]
+	ADDSUBC	x12, x4, x8
+	ADDSUBC	x13, x5, x9
+	add	rp, rp, #16
+	sub	x18, x18, #1
+	cbz	x18, L(end)
+
+	ALIGN(16)
+L(top):	ldp	x4, x5, [up,#-16]
+	ldp	x8, x9, [vp,#-16]
+	extr	x16, x15, x14, #1
+	extr	x17, x12, x15, #1
+	ADDSUBC	x14, x4, x8
+	ADDSUBC	x15, x5, x9
+	stp	x16, x17, [rp,#-16]
+L(mid):	ldp	x4, x5, [up],#32
+	ldp	x8, x9, [vp],#32
+	extr	x16, x13, x12, #1
+	extr	x17, x14, x13, #1
+	ADDSUBC	x12, x4, x8
+	ADDSUBC	x13, x5, x9
+	stp	x16, x17, [rp],#32
+	sub	x18, x18, #1
+	cbnz	x18, L(top)
+
+L(end):	extr	x16, x15, x14, #1
+	extr	x17, x12, x15, #1
+	stp	x16, x17, [rp,#-16]
+L(2):	cset	x14, COND
+	extr	x16, x13, x12, #1
+	extr	x17, x14, x13, #1
+	stp	x16, x17, [rp]
+
+L(ret):	mov	x0, x10
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm64/rshift.asm b/third_party/gmp/mpn/arm64/rshift.asm
new file mode 100644
index 0000000..78ae960
--- /dev/null
+++ b/third_party/gmp/mpn/arm64/rshift.asm
@@ -0,0 +1,125 @@
+dnl  ARM64 mpn_rshift.
+
+dnl  Copyright 2013, 2014, 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of the GNU Lesser General Public License as published
+dnl  by the Free Software Foundation; either version 3 of the License, or (at
+dnl  your option) any later version.
+
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+dnl  License for more details.
+
+dnl  You should have received a copy of the GNU Lesser General Public License
+dnl  along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb   assumed optimal c/l
+C Cortex-A53	3.5-4.0		 3.25
+C Cortex-A57	 2.0		 2.0
+C X-Gene	 2.67		 2.5
+
+C TODO
+C  * The feed-in code used 1 ldr for odd sized and 2 ldr for even sizes.  These
+C    numbers should be 1 and 0, respectively.  The str in wind-down should also
+C    go.
+C  * Using extr and with 63 separate loops we might reach 1.25 c/l on A57.
+C  * A53's speed depends on alignment, but not as simply as for lshift/lshiftc.
+
+changecom(blah)
+
+define(`rp_arg', `x0')
+define(`up',     `x1')
+define(`n',      `x2')
+define(`cnt',    `x3')
+
+define(`rp',     `x16')
+
+define(`tnc',`x8')
+
+define(`PSHIFT', lsr)
+define(`NSHIFT', lsl)
+
+ASM_START()
+PROLOGUE(mpn_rshift)
+	mov	rp, rp_arg
+	sub	tnc, xzr, cnt
+	lsr	x18, n, #2
+	tbz	n, #0, L(bx0)
+
+L(bx1):	ldr	x5, [up]
+	tbnz	n, #1, L(b11)
+
+L(b01):	NSHIFT	x0, x5, tnc
+	PSHIFT	x2, x5, cnt
+	cbnz	x18, L(gt1)
+	str	x2, [rp]
+	ret
+L(gt1):	ldp	x4, x5, [up,#8]
+	sub	up, up, #8
+	sub	rp, rp, #32
+	b	L(lo2)
+
+L(b11):	NSHIFT	x0, x5, tnc
+	PSHIFT	x2, x5, cnt
+	ldp	x6, x7, [up,#8]!
+	sub	rp, rp, #16
+	b	L(lo3)
+
+L(bx0):	ldp	x4, x5, [up]
+	tbz	n, #1, L(b00)
+
+L(b10):	NSHIFT	x0, x4, tnc
+	PSHIFT	x13, x4, cnt
+	NSHIFT	x10, x5, tnc
+	PSHIFT	x2, x5, cnt
+	cbnz	x18, L(gt2)
+	orr	x10, x10, x13
+	stp	x10, x2, [rp]
+	ret
+L(gt2):	ldp	x4, x5, [up,#16]
+	orr	x10, x10, x13
+	str	x10, [rp],#-24
+	b	L(lo2)
+
+L(b00):	NSHIFT	x0, x4, tnc
+	PSHIFT	x13, x4, cnt
+	NSHIFT	x10, x5, tnc
+	PSHIFT	x2, x5, cnt
+	ldp	x6, x7, [up,#16]!
+	orr	x10, x10, x13
+	str	x10, [rp],#-8
+	b	L(lo0)
+
+	ALIGN(16)
+L(top):	ldp	x4, x5, [up,#16]
+	orr	x10, x10, x13
+	orr	x11, x12, x2
+	stp	x11, x10, [rp,#16]
+	PSHIFT	x2, x7, cnt
+L(lo2):	NSHIFT	x10, x5, tnc
+	NSHIFT	x12, x4, tnc
+	PSHIFT	x13, x4, cnt
+	ldp	x6, x7, [up,#32]!
+	orr	x10, x10, x13
+	orr	x11, x12, x2
+	stp	x11, x10, [rp,#32]!
+	PSHIFT	x2, x5, cnt
+L(lo0):	sub	x18, x18, #1
+L(lo3):	NSHIFT	x10, x7, tnc
+	NSHIFT	x12, x6, tnc
+	PSHIFT	x13, x6, cnt
+	cbnz	x18, L(top)
+
+L(end):	orr	x10, x10, x13
+	orr	x11, x12, x2
+	PSHIFT	x2, x7, cnt
+	stp	x11, x10, [rp,#16]
+	str	x2, [rp,#32]
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm64/sec_tabselect.asm b/third_party/gmp/mpn/arm64/sec_tabselect.asm
new file mode 100644
index 0000000..18a268a
--- /dev/null
+++ b/third_party/gmp/mpn/arm64/sec_tabselect.asm
@@ -0,0 +1,122 @@
+dnl  ARM64 Neon mpn_sec_tabselect.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2011-2014 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C	     cycles/limb
+C Cortex-A53	 2.25
+C Cortex-A57	 1.33
+C X-Gene	 2
+
+C void
+C mpn_sec_tabselect (mp_ptr rp, mp_srcptr *tab,
+C		     mp_size_t n, mp_size_t nents, mp_size_t which)
+
+changecom(blah)
+
+define(`rp',     `x0')
+define(`tp',     `x1')
+define(`n',      `x2')
+define(`nents',  `x3')
+define(`which',  `x4')
+
+define(`i',      `x5')
+define(`j',      `x6')
+
+define(`maskq',  `v4')
+
+ASM_START()
+PROLOGUE(mpn_sec_tabselect)
+	dup	v7.2d, x4			C 2 `which' copies
+
+	mov	x10, #1
+	dup	v6.2d, x10			C 2 copies of 1
+
+	subs	j, n, #4
+	b.mi	L(outer_end)
+
+L(outer_top):
+	mov	i, nents
+	mov	x12, tp				C preserve tp
+	movi	v5.16b, #0			C zero 2 counter copies
+	movi	v2.16b, #0
+	movi	v3.16b, #0
+	ALIGN(16)
+L(tp4):	cmeq	maskq.2d, v5.2d, v7.2d		C compare idx copies to `which' copies
+	ld1	{v0.2d,v1.2d}, [tp]
+	add	v5.2d, v5.2d, v6.2d
+	bit	v2.16b, v0.16b, maskq.16b
+	bit	v3.16b, v1.16b, maskq.16b
+	add	tp, tp, n, lsl #3
+	sub	i, i, #1
+	cbnz	i, L(tp4)
+	st1	{v2.2d,v3.2d}, [rp], #32
+	add	tp, x12, #32			C restore tp, point to next slice
+	subs	j, j, #4
+	b.pl	L(outer_top)
+L(outer_end):
+
+	tbz	n, #1, L(b0x)
+	mov	i, nents
+	mov	x12, tp
+	movi	v5.16b, #0			C zero 2 counter copies
+	movi	v2.16b, #0
+	ALIGN(16)
+L(tp2):	cmeq	maskq.2d, v5.2d, v7.2d
+	ld1	{v0.2d}, [tp]
+	add	v5.2d, v5.2d, v6.2d
+	bit	v2.16b, v0.16b, maskq.16b
+	add	tp, tp, n, lsl #3
+	sub	i, i, #1
+	cbnz	i, L(tp2)
+	st1	{v2.2d}, [rp], #16
+	add	tp, x12, #16
+
+L(b0x):	tbz	n, #0, L(b00)
+	mov	i, nents
+	mov	x12, tp
+	movi	v5.16b, #0			C zero 2 counter copies
+	movi	v2.16b, #0
+	ALIGN(16)
+L(tp1):	cmeq	maskq.2d, v5.2d, v7.2d
+	ld1	{v0.1d}, [tp]
+	add	v5.2d, v5.2d, v6.2d		C FIXME size should be `1d'
+	bit	v2.8b, v0.8b, maskq.8b
+	add	tp, tp, n, lsl #3
+	sub	i, i, #1
+	cbnz	i, L(tp1)
+	st1	{v2.1d}, [rp], #8
+	add	tp, x12, #8
+
+L(b00):	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm64/sqr_diag_addlsh1.asm b/third_party/gmp/mpn/arm64/sqr_diag_addlsh1.asm
new file mode 100644
index 0000000..55b5ac7
--- /dev/null
+++ b/third_party/gmp/mpn/arm64/sqr_diag_addlsh1.asm
@@ -0,0 +1,102 @@
+dnl  ARM64 mpn_sqr_diag_addlsh1.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2016, 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C Cortex-A53	 5.65
+C Cortex-A57	 3.5
+C X-Gene	 3.38
+
+changecom(blah)
+
+define(`rp', `x0')
+define(`tp', `x1')
+define(`up', `x2')
+define(`n',  `x3')
+
+ASM_START()
+PROLOGUE(mpn_sqr_diag_addlsh1)
+	ldr	x15, [up],#8
+	lsr	x18, n, #1
+	tbz	n, #0, L(bx0)
+
+L(bx1):	adds	x7, xzr, xzr
+	mul	x12, x15, x15
+	ldr	x16, [up],#8
+	ldp	x4, x5, [tp],#16
+	umulh	x11, x15, x15
+	b	L(mid)
+
+L(bx0):	adds	x5, xzr, xzr
+	mul	x12, x15, x15
+	ldr	x17, [up],#16
+	ldp	x6, x7, [tp],#32
+	umulh	x11, x15, x15
+	sub	x18, x18, #1
+	cbz	x18, L(end)
+
+	ALIGN(16)
+L(top):	extr	x9, x6, x5, #63
+	mul	x10, x17, x17
+	ldr	x16, [up,#-8]
+	adcs	x13, x9, x11
+	ldp	x4, x5, [tp,#-16]
+	umulh	x11, x17, x17
+	extr	x8, x7, x6, #63
+	stp	x12, x13, [rp],#16
+	adcs	x12, x8, x10
+L(mid):	extr	x9, x4, x7, #63
+	mul	x10, x16, x16
+	ldr	x17, [up],#16
+	adcs	x13, x9, x11
+	ldp	x6, x7, [tp],#32
+	umulh	x11, x16, x16
+	extr	x8, x5, x4, #63
+	stp	x12, x13, [rp],#16
+	adcs	x12, x8, x10
+	sub	x18, x18, #1
+	cbnz	x18, L(top)
+
+L(end):	extr	x9, x6, x5, #63
+	mul	x10, x17, x17
+	adcs	x13, x9, x11
+	umulh	x11, x17, x17
+	extr	x8, x7, x6, #63
+	stp	x12, x13, [rp]
+	adcs	x12, x8, x10
+	extr	x9, xzr, x7, #63
+	adcs	x13, x9, x11
+	stp	x12, x13, [rp,#16]
+
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/arm64/xgene1/gmp-mparam.h b/third_party/gmp/mpn/arm64/xgene1/gmp-mparam.h
new file mode 100644
index 0000000..7cc3cb3
--- /dev/null
+++ b/third_party/gmp/mpn/arm64/xgene1/gmp-mparam.h
@@ -0,0 +1,181 @@
+/* gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+/* 2400 MHz AppliedMicro X-Gene */
+/* FFT tuning limit = 0.5 M */
+/* Generated by tuneup.c, 2019-09-28, gcc 4.8 */
+
+#define DIVREM_1_NORM_THRESHOLD              0  /* always */
+#define DIVREM_1_UNNORM_THRESHOLD            0  /* always */
+#define MOD_1_1P_METHOD                      1  /* 2.00% faster than 2 */
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          7
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          5
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD         0  /* never mpn_mod_1_1p */
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        22
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     13
+#define USE_PREINV_DIVREM_1                  1
+#define DIV_QR_1N_PI1_METHOD                 1  /* 37.38% faster than 2 */
+#define DIV_QR_1_NORM_THRESHOLD              1
+#define DIV_QR_1_UNNORM_THRESHOLD            1
+#define DIV_QR_2_PI2_THRESHOLD              14
+#define DIVEXACT_1_THRESHOLD                 0  /* always */
+#define BMOD_1_TO_MOD_1_THRESHOLD           27
+
+#define DIV_1_VS_MUL_1_PERCENT             249
+
+#define MUL_TOOM22_THRESHOLD                18
+#define MUL_TOOM33_THRESHOLD                61
+#define MUL_TOOM44_THRESHOLD               112
+#define MUL_TOOM6H_THRESHOLD               242
+#define MUL_TOOM8H_THRESHOLD               321
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      73
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD      99
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     109
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD      72
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     106
+
+#define SQR_BASECASE_THRESHOLD               0  /* always */
+#define SQR_TOOM2_THRESHOLD                 28
+#define SQR_TOOM3_THRESHOLD                 81
+#define SQR_TOOM4_THRESHOLD                154
+#define SQR_TOOM6_THRESHOLD                214
+#define SQR_TOOM8_THRESHOLD                284
+
+#define MULMID_TOOM42_THRESHOLD             46
+
+#define MULMOD_BNM1_THRESHOLD               11
+#define SQRMOD_BNM1_THRESHOLD               13
+
+#define MUL_FFT_MODF_THRESHOLD             412  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    412, 5}, {     15, 6}, {      8, 5}, {     17, 6}, \
+    {     19, 7}, {     12, 6}, {     25, 7}, {     17, 8}, \
+    {      9, 7}, {     20, 8}, {     11, 7}, {     25, 8}, \
+    {     13, 7}, {     27, 8}, {     15, 7}, {     31, 8}, \
+    {     17, 7}, {     35, 8}, {     21, 9}, {     11, 8}, \
+    {     27, 9}, {     15, 8}, {     35, 9}, {     19, 8}, \
+    {     41, 9}, {     23, 8}, {     49, 9}, {     27,10}, \
+    {     15, 9}, {     31, 8}, {     63, 9}, {     39,10}, \
+    {     23, 9}, {     55,11}, {     15,10}, {     31, 9}, \
+    {     71,10}, {     39, 9}, {     83,10}, {     47, 9}, \
+    {     99,10}, {     55,11}, {     31,10}, {     63, 9}, \
+    {    127,10}, {     71, 9}, {    143,10}, {     79,11}, \
+    {     47,10}, {    103,12}, {     31,11}, {     63,10}, \
+    {    127, 9}, {    255,10}, {    135, 9}, {    271,10}, \
+    {    143,11}, {     79, 9}, {    319,10}, {    167, 9}, \
+    {    351,11}, {     95, 9}, {    383, 8}, {    767,10}, \
+    {    207, 9}, {    415,11}, {    111,12}, {     63,11}, \
+    {    127,10}, {    255, 9}, {    511,10}, {    271, 9}, \
+    {    543,11}, {    143,10}, {    287, 9}, {    575,10}, \
+    {    319, 9}, {    639,10}, {    351,12}, {     95,10}, \
+    {    383, 9}, {    767,11}, {    207,10}, {    415, 9}, \
+    {    831,11}, {    223,10}, {    447,13}, {   8192,14}, \
+    {  16384,15}, {  32768,16}, {  65536,17}, { 131072,18}, \
+    { 262144,19}, { 524288,20}, {1048576,21}, {2097152,22}, \
+    {4194304,23}, {8388608,24} }
+#define MUL_FFT_TABLE3_SIZE 98
+#define MUL_FFT_THRESHOLD                 4736
+
+#define SQR_FFT_MODF_THRESHOLD             340  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    340, 5}, {     17, 6}, {      9, 5}, {     19, 6}, \
+    {     19, 7}, {     10, 6}, {     21, 7}, {     11, 6}, \
+    {     23, 7}, {     21, 8}, {     11, 7}, {     24, 8}, \
+    {     15, 7}, {     31, 8}, {     21, 9}, {     11, 8}, \
+    {     27, 9}, {     15, 8}, {     33, 9}, {     19, 8}, \
+    {     39, 9}, {     23, 8}, {     47, 9}, {     27,10}, \
+    {     15, 9}, {     31, 8}, {     63, 9}, {     39,10}, \
+    {     23, 9}, {     51,11}, {     15,10}, {     31, 9}, \
+    {     67,10}, {     39, 9}, {     79,10}, {     47, 9}, \
+    {     95,10}, {     55,11}, {     31,10}, {     79,11}, \
+    {     47,10}, {     95, 9}, {    191,12}, {     31,11}, \
+    {     63,10}, {    127, 9}, {    255, 8}, {    511,10}, \
+    {    135, 9}, {    271,11}, {     79, 9}, {    319, 8}, \
+    {    639,10}, {    175,11}, {     95,10}, {    191, 9}, \
+    {    383,10}, {    207,12}, {     63,11}, {    127,10}, \
+    {    255, 9}, {    511,10}, {    271, 9}, {    543,10}, \
+    {    287, 9}, {    575,10}, {    319, 9}, {    639,11}, \
+    {    175,10}, {    351,12}, {     95,11}, {    191,10}, \
+    {    383, 9}, {    767,11}, {    207,10}, {    415,13}, \
+    {   8192,14}, {  16384,15}, {  32768,16}, {  65536,17}, \
+    { 131072,18}, { 262144,19}, { 524288,20}, {1048576,21}, \
+    {2097152,22}, {4194304,23}, {8388608,24} }
+#define SQR_FFT_TABLE3_SIZE 87
+#define SQR_FFT_THRESHOLD                 3264
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  45
+#define MULLO_MUL_N_THRESHOLD             8648
+#define SQRLO_BASECASE_THRESHOLD             0  /* always */
+#define SQRLO_DC_THRESHOLD                 108
+#define SQRLO_SQR_THRESHOLD               6461
+
+#define DC_DIV_QR_THRESHOLD                 64
+#define DC_DIVAPPR_Q_THRESHOLD             222
+#define DC_BDIV_QR_THRESHOLD                63
+#define DC_BDIV_Q_THRESHOLD                132
+
+#define INV_MULMOD_BNM1_THRESHOLD           38
+#define INV_NEWTON_THRESHOLD               242
+#define INV_APPR_THRESHOLD                 222
+
+#define BINV_NEWTON_THRESHOLD              254
+#define REDC_1_TO_REDC_N_THRESHOLD          66
+
+#define MU_DIV_QR_THRESHOLD               1234
+#define MU_DIVAPPR_Q_THRESHOLD            1234
+#define MUPI_DIV_QR_THRESHOLD              122
+#define MU_BDIV_QR_THRESHOLD              1210
+#define MU_BDIV_Q_THRESHOLD               1234
+
+#define POWM_SEC_TABLE  3,23,194,712,2499
+
+#define GET_STR_DC_THRESHOLD                11
+#define GET_STR_PRECOMPUTE_THRESHOLD        22
+#define SET_STR_DC_THRESHOLD               381
+#define SET_STR_PRECOMPUTE_THRESHOLD      2503
+
+#define FAC_DSC_THRESHOLD                  216
+#define FAC_ODD_THRESHOLD                   26
+
+#define MATRIX22_STRASSEN_THRESHOLD         14
+#define HGCD2_DIV1_METHOD                    5  /* 2.01% faster than 3 */
+#define HGCD_THRESHOLD                     122
+#define HGCD_APPR_THRESHOLD                171
+#define HGCD_REDUCE_THRESHOLD             2479
+#define GCD_DC_THRESHOLD                   541
+#define GCDEXT_DC_THRESHOLD                386
+#define JACOBI_BASE_METHOD                   4  /* 7.46% faster than 1 */
diff --git a/third_party/gmp/mpn/asm-defs.m4 b/third_party/gmp/mpn/asm-defs.m4
new file mode 100644
index 0000000..7b7e53e
--- /dev/null
+++ b/third_party/gmp/mpn/asm-defs.m4
@@ -0,0 +1,1766 @@
+divert(-1)
+dnl
+dnl  m4 macros for gmp assembly code, shared by all CPUs.
+
+dnl  Copyright 1999-2006, 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+dnl  These macros are designed for use with any m4 and have been used on
+dnl  GNU, FreeBSD, NetBSD, OpenBSD and SysV.
+dnl
+dnl  GNU m4 and OpenBSD 2.7 m4 will give filenames and line numbers in error
+dnl  messages.
+dnl
+dnl
+dnl  Macros:
+dnl
+dnl  Most new m4 specific macros have an "m4_" prefix to emphasise they're
+dnl  m4 expansions.  But new defining things like deflit() and defreg() are
+dnl  named like the builtin define(), and forloop() is named following the
+dnl  GNU m4 example on which it's based.
+dnl
+dnl  GNU m4 with the -P option uses "m4_" as a prefix for builtins, but that
+dnl  option isn't going to be used, so there's no conflict or confusion.
+dnl
+dnl
+dnl  Comments in output:
+dnl
+dnl  The m4 comment delimiters are left at # and \n, the normal assembler
+dnl  commenting for most CPUs.  m4 passes comment text through without
+dnl  expanding macros in it, which is generally a good thing since it stops
+dnl  unexpected expansions and possible resultant errors.
+dnl
+dnl  But note that when a quoted string is being read, a # isn't special, so
+dnl  apostrophes in comments in quoted strings must be avoided or they'll be
+dnl  interpreted as a closing quote mark.  But when the quoted text is
+dnl  re-read # will still act like a normal comment, suppressing macro
+dnl  expansion.
+dnl
+dnl  For example,
+dnl
+dnl          # apostrophes in comments that're outside quotes are ok
+dnl          # and using macro names like PROLOGUE is ok too
+dnl          ...
+dnl          ifdef(`PIC',`
+dnl                  # but apostrophes aren't ok inside quotes
+dnl                  #                     ^--wrong
+dnl                  ...
+dnl                  # though macro names like PROLOGUE are still ok
+dnl                  ...
+dnl          ')
+dnl
+dnl  If macro expansion in a comment is wanted, use `#' in the .asm (ie. a
+dnl  quoted hash symbol), which will turn into # in the .s but get
+dnl  expansions done on that line.  This can make the .s more readable to
+dnl  humans, but it won't make a blind bit of difference to the assembler.
+dnl
+dnl  All the above applies, mutatis mutandis, when changecom() is used to
+dnl  select @ ! ; or whatever other commenting.
+dnl
+dnl
+dnl  Variations in m4 affecting gmp:
+dnl
+dnl  $# - When a macro is called as "foo" with no brackets, BSD m4 sets $#
+dnl       to 1, whereas GNU or SysV m4 set it to 0.  In all cases though
+dnl       "foo()" sets $# to 1.  This is worked around in various places.
+dnl
+dnl  len() - When "len()" is given an empty argument, BSD m4 evaluates to
+dnl       nothing, whereas GNU, SysV, and the new OpenBSD, evaluate to 0.
+dnl       See m4_length() below which works around this.
+dnl
+dnl  translit() - GNU m4 accepts character ranges like A-Z, and the new
+dnl       OpenBSD m4 does under option -g, but basic BSD and SysV don't.
+dnl
+dnl  popdef() - in BSD and SysV m4 popdef() takes multiple arguments and
+dnl       pops each, but GNU m4 only takes one argument.
+dnl
+dnl  push back - BSD m4 has some limits on the amount of text that can be
+dnl       pushed back.  The limit is reasonably big and so long as macros
+dnl       don't gratuitously duplicate big arguments it isn't a problem.
+dnl       Normally an error message is given, but sometimes it just hangs.
+dnl
+dnl  eval() &,|,^ - GNU and SysV m4 have bitwise operators &,|,^ available,
+dnl       but BSD m4 doesn't (contrary to what the man page suggests) and
+dnl       instead ^ is exponentiation.
+dnl
+dnl  eval() ?: - The C ternary operator "?:" is available in BSD m4, but not
+dnl       in SysV or GNU m4 (as of GNU m4 1.4 and betas of 1.5).
+dnl
+dnl  eval() -2^31 - BSD m4 has a bug where an eval() resulting in -2^31
+dnl       (ie. -2147483648) gives "-(".  Using -2147483648 within an
+dnl       expression is ok, it just can't be a final result.  "-(" will of
+dnl       course upset parsing, with all sorts of strange effects.
+dnl
+dnl  eval() <<,>> - SysV m4 doesn't support shift operators in eval() (on
+dnl       Solaris 7 /usr/xpg4/m4 has them but /usr/ccs/m4 doesn't).  See
+dnl       m4_lshift() and m4_rshift() below for workarounds.
+dnl
+dnl  ifdef() - OSF 4.0 m4 considers a macro defined to a zero value `0' or
+dnl       `00' etc as not defined.  See m4_ifdef below for a workaround.
+dnl
+dnl  m4wrap() sequence - in BSD m4, m4wrap() replaces any previous m4wrap()
+dnl       string, in SysV m4 it appends to it, and in GNU m4 it prepends.
+dnl       See m4wrap_prepend() below which brings uniformity to this.
+dnl
+dnl  m4wrap() 0xFF - old versions of BSD m4 store EOF in a C "char" under an
+dnl       m4wrap() and on systems where char is unsigned by default a
+dnl       spurious 0xFF is output.  This has been observed on recent Cray
+dnl       Unicos Alpha, Apple MacOS X, and HPUX 11 systems.  An autoconf
+dnl       test is used to check for this, see the m4wrap handling below.  It
+dnl       might work to end the m4wrap string with a dnl to consume the
+dnl       0xFF, but that probably induces the offending m4's to read from an
+dnl       already closed "FILE *", which could be bad on a glibc style
+dnl       stdio.
+dnl
+dnl  __file__,__line__ - GNU m4 and OpenBSD 2.7 m4 provide these, and
+dnl       they're used here to make error messages more informative.  GNU m4
+dnl       gives an unhelpful "NONE 0" in an m4wrap(), but that's worked
+dnl       around.
+dnl
+dnl  __file__ quoting - OpenBSD m4, unlike GNU m4, doesn't quote the
+dnl       filename in __file__, so care should be taken that no macro has
+dnl       the same name as a file, or an unwanted expansion will occur when
+dnl       printing an error or warning.
+dnl
+dnl  changecom() - BSD m4 changecom doesn't quite work like the man page
+dnl       suggests, in particular "changecom" or "changecom()" doesn't
+dnl       disable the comment feature, and multi-character comment sequences
+dnl       don't seem to work.  If the default `#' and newline aren't
+dnl       suitable it's necessary to change it to something else,
+dnl       eg. changecom(;).
+dnl
+dnl  OpenBSD 2.6 m4 - in this m4, eval() rejects decimal constants containing
+dnl       an 8 or 9, making it pretty much unusable.  The bug is confined to
+dnl       version 2.6 (it's not in 2.5, and was fixed in 2.7).
+dnl
+dnl  SunOS /usr/bin/m4 - this m4 lacks a number of desired features,
+dnl       including $# and $@, defn(), m4exit(), m4wrap(), pushdef(),
+dnl       popdef().  /usr/5bin/m4 is a SysV style m4 which should always be
+dnl       available, and "configure" will reject /usr/bin/m4 in favour of
+dnl       /usr/5bin/m4 (if necessary).
+dnl
+dnl       The sparc code actually has modest m4 requirements currently and
+dnl       could manage with /usr/bin/m4, but there's no reason to put our
+dnl       macros through contortions when /usr/5bin/m4 is available or GNU
+dnl       m4 can be installed.
+
+
+ifdef(`__ASM_DEFS_M4_INCLUDED__',
+`m4_error(`asm-defs.m4 already included, dont include it twice
+')m4exit(1)')
+define(`__ASM_DEFS_M4_INCLUDED__')
+
+
+dnl  Detect and give a message about the unsuitable OpenBSD 2.6 m4.
+
+ifelse(eval(89),89,,
+`errprint(
+`This m4 doesnt accept 8 and/or 9 in constants in eval(), making it unusable.
+This is probably OpenBSD 2.6 m4 (September 1999).  Upgrade to OpenBSD 2.7,
+or get a bug fix from the CVS (expr.c rev 1.9), or get GNU m4.  Dont forget
+to configure with M4=/wherever/m4 if you install one of these in a directory
+not in $PATH.
+')m4exit(1)')
+
+
+dnl  Detect and give a message about the unsuitable SunOS /usr/bin/m4.
+dnl
+dnl  Unfortunately this test doesn't work when m4 is run in the normal way
+dnl  from mpn/Makefile with "m4 -DOPERATION_foo foo.asm", since the bad m4
+dnl  takes "-" in "-D..." to mean read stdin, so it will look like it just
+dnl  hangs.  But running "m4 asm-defs.m4" to try it out will work.
+dnl
+dnl  We'd like to abort immediately on finding a problem, but unfortunately
+dnl  the bad m4 doesn't have an m4exit(), nor does an invalid eval() kill
+dnl  it.  Unexpanded $#'s in some m4_assert_numargs() later on will comment
+dnl  out some closing parentheses and kill it with "m4: arg stack overflow".
+
+define(m4_dollarhash_works_test,``$#'')
+ifelse(m4_dollarhash_works_test(x),1,,
+`errprint(
+`This m4 doesnt support $# and cant be used for GMP asm processing.
+If this is on SunOS, ./configure should choose /usr/5bin/m4 if you have that
+or can get it, otherwise install GNU m4.  Dont forget to configure with
+M4=/wherever/m4 if you install in a directory not in $PATH.
+')')
+undefine(`m4_dollarhash_works_test')
+
+
+dnl  --------------------------------------------------------------------------
+dnl  Basic error handling things.
+
+
+dnl  Usage: m4_dollarhash_1_if_noparen_p
+dnl
+dnl  Expand to 1 if a call "foo" gives $# set to 1 (as opposed to 0 like GNU
+dnl  and SysV m4 give).
+
+define(m4_dollarhash_1_if_noparen_test,`$#')
+define(m4_dollarhash_1_if_noparen_p,
+eval(m4_dollarhash_1_if_noparen_test==1))
+undefine(`m4_dollarhash_1_if_noparen_test')
+
+
+dnl  Usage: m4wrap_prepend(string)
+dnl
+dnl  Prepend the given string to what will be expanded under m4wrap at the
+dnl  end of input.
+dnl
+dnl  This macro exists to work around variations in m4wrap() behaviour in
+dnl  the various m4s (notes at the start of this file).  Don't use m4wrap()
+dnl  directly since it will interfere with this scheme.
+
+define(m4wrap_prepend,
+m4_assert_numargs(1)
+`define(`m4wrap_string',`$1'defn(`m4wrap_string'))')
+
+define(m4wrap_string,`')
+
+define(m4wrap_works_p,
+`ifelse(M4WRAP_SPURIOUS,yes,0,1)')
+
+ifelse(m4wrap_works_p,1,
+`m4wrap(`m4wrap_string')')
+
+
+dnl  Usage: m4_file_and_line
+dnl
+dnl  Expand to the current file and line number, if the GNU m4 extensions
+dnl  __file__ and __line__ are available.
+dnl
+dnl  In GNU m4 1.4 at the end of input when m4wrap text is expanded,
+dnl  __file__ is NONE and __line__ is 0, which is not a helpful thing to
+dnl  print.  If m4_file_seen() has been called to note the last file seen,
+dnl  then that file at a big line number is used, otherwise "end of input"
+dnl  is used (although "end of input" won't parse as an error message).
+
+define(m4_file_and_line,
+`ifdef(`__file__',
+`ifelse(__file__`'__line__,`NONE0',
+`ifdef(`m4_file_seen_last',`m4_file_seen_last: 999999: ',`end of input: ')',
+`__file__: __line__: ')')')
+
+
+dnl  Usage: m4_errprint_commas(arg,...)
+dnl
+dnl  The same as errprint(), but commas are printed between arguments
+dnl  instead of spaces.
+
+define(m4_errprint_commas,
+`errprint(`$1')dnl
+ifelse(eval($#>1),1,`errprint(`,')m4_errprint_commas(shift($@))')')
+
+
+dnl  Usage: m4_error(args...)
+dnl         m4_warning(args...)
+dnl
+dnl  Print an error message, using m4_errprint_commas, prefixed with the
+dnl  current filename and line number (if available).  m4_error sets up to
+dnl  give an error exit at the end of processing, m4_warning just prints.
+dnl  These macros are the recommended way to print errors.
+dnl
+dnl  The arguments here should be quoted in the usual way to prevent them
+dnl  being expanded when the macro call is read.  (m4_error takes care not
+dnl  to do any further expansion.)
+dnl
+dnl  For example,
+dnl
+dnl         m4_error(`some error message
+dnl         ')
+dnl
+dnl  which prints
+dnl
+dnl         foo.asm:123: some error message
+dnl
+dnl  or if __file__ and __line__ aren't available
+dnl
+dnl         some error message
+dnl
+dnl  The "file:line:" format is a basic style, used by gcc and GNU m4, so
+dnl  emacs and other editors will recognise it in their normal error message
+dnl  parsing.
+
+define(m4_warning,
+`m4_errprint_commas(m4_file_and_line`'$@)')
+
+define(m4_error,
+`define(`m4_error_occurred',1)m4_warning($@)dnl
+ifelse(m4wrap_works_p,0,`m4exit(1)')')
+
+define(`m4_error_occurred',0)
+
+dnl  This m4wrap_prepend() is first, so it'll be executed last.
+m4wrap_prepend(
+`ifelse(m4_error_occurred,1,
+`m4_error(`Errors occurred during m4 processing
+')m4exit(1)')')
+
+
+dnl  Usage: m4_assert_numargs(num)
+dnl
+dnl  Put this unquoted on a line on its own at the start of a macro
+dnl  definition to add some code to check that num many arguments get passed
+dnl  to the macro.  For example,
+dnl
+dnl         define(foo,
+dnl         m4_assert_numargs(2)
+dnl         `something `$1' and `$2' blah blah')
+dnl
+dnl  Then a call like foo(one,two,three) will provoke an error like
+dnl
+dnl         file:10: foo expected 2 arguments, got 3 arguments
+dnl
+dnl  Here are some calls and how many arguments they're interpreted as passing.
+dnl
+dnl         foo(abc,def)  2
+dnl         foo(xyz)      1
+dnl         foo()         0
+dnl         foo          -1
+dnl
+dnl  The -1 for no parentheses at all means a macro that's meant to be used
+dnl  that way can be checked with m4_assert_numargs(-1).  For example,
+dnl
+dnl         define(SPECIAL_SUFFIX,
+dnl         m4_assert_numargs(-1)
+dnl         `ifdef(`FOO',`_foo',`_bar')')
+dnl
+dnl  But as an alternative see also deflit() below where parenthesized
+dnl  expressions following a macro are passed through to the output.
+dnl
+dnl  Note that in BSD m4 there's no way to differentiate calls "foo" and
+dnl  "foo()", so in BSD m4 the distinction between the two isn't enforced.
+dnl  (In GNU and SysV m4 it can be checked, and is.)
+
+
+dnl  m4_assert_numargs is able to check its own arguments by calling
+dnl  assert_numargs_internal directly.
+dnl
+dnl  m4_doublequote($`'0) expands to ``$0'', whereas ``$`'0'' would expand
+dnl  to `$`'0' and do the wrong thing, and likewise for $1.  The same is
+dnl  done in other assert macros.
+dnl
+dnl  $`#' leaves $# in the new macro being defined, and stops # being
+dnl  interpreted as a comment character.
+dnl
+dnl  `dnl ' means an explicit dnl isn't necessary when m4_assert_numargs is
+dnl  used.  The space means that if there is a dnl it'll still work.
+
+dnl  Usage: m4_doublequote(x) expands to ``x''
+define(m4_doublequote,
+`m4_assert_numargs_internal(`$0',1,$#,len(`$1'))``$1''')
+
+define(m4_assert_numargs,
+`m4_assert_numargs_internal(`$0',1,$#,len(`$1'))dnl
+`m4_assert_numargs_internal'(m4_doublequote($`'0),$1,$`#',`len'(m4_doublequote($`'1)))`dnl '')
+
+dnl  Called: m4_assert_numargs_internal(`macroname',wantargs,$#,len(`$1'))
+define(m4_assert_numargs_internal,
+`m4_assert_numargs_internal_check(`$1',`$2',m4_numargs_count(`$3',`$4'))')
+
+dnl  Called: m4_assert_numargs_internal_check(`macroname',wantargs,gotargs)
+dnl
+dnl  If m4_dollarhash_1_if_noparen_p (BSD m4) then gotargs can be 0 when it
+dnl  should be -1.  If wantargs is -1 but gotargs is 0 and the two can't be
+dnl  distinguished then it's allowed to pass.
+dnl
+define(m4_assert_numargs_internal_check,
+`ifelse(eval($2 == $3
+             || ($2==-1 && $3==0 && m4_dollarhash_1_if_noparen_p)),0,
+`m4_error(`$1 expected 'm4_Narguments(`$2')`, got 'm4_Narguments(`$3')
+)')')
+
+dnl  Called: m4_numargs_count($#,len(`$1'))
+dnl  If $#==0 then -1 args, if $#==1 but len(`$1')==0 then 0 args, otherwise
+dnl  $# args.
+define(m4_numargs_count,
+`ifelse($1,0, -1,
+`ifelse(eval($1==1 && $2-0==0),1, 0, $1)')')
+
+dnl  Usage: m4_Narguments(N)
+dnl  "$1 argument" or "$1 arguments" with the plural according to $1.
+define(m4_Narguments,
+`$1 argument`'ifelse(`$1',1,,s)')
+
+
+dnl  --------------------------------------------------------------------------
+dnl  Additional error checking things.
+
+
+dnl  Usage: m4_file_seen()
+dnl
+dnl  Record __file__ for the benefit of m4_file_and_line in m4wrap text.
+dnl
+dnl  The basic __file__ macro comes out quoted in GNU m4, like `foo.asm',
+dnl  and m4_file_seen_last is defined like that too.
+dnl
+dnl  This is used by PROLOGUE, since that's normally in the main .asm file,
+dnl  and in particular it sets up m4wrap error checks for missing EPILOGUE.
+
+define(m4_file_seen,
+m4_assert_numargs(0)
+`ifelse(__file__,`NONE',,
+`define(`m4_file_seen_last',m4_doublequote(__file__))')')
+
+
+dnl  Usage: m4_assert_onearg()
+dnl
+dnl  Put this, unquoted, at the start of a macro definition to add some code
+dnl  to check that one argument is passed to the macro, but with that
+dnl  argument allowed to be empty.  For example,
+dnl
+dnl          define(foo,
+dnl          m4_assert_onearg()
+dnl          `blah blah $1 blah blah')
+dnl
+dnl  Calls "foo(xyz)" or "foo()" are accepted.  A call "foo(xyz,abc)" fails.
+dnl  A call "foo" fails too, but BSD m4 can't detect this case (GNU and SysV
+dnl  m4 can).
+
+define(m4_assert_onearg,
+m4_assert_numargs(0)
+`m4_assert_onearg_internal'(m4_doublequote($`'0),$`#')`dnl ')
+
+dnl  Called: m4_assert_onearg(`macroname',$#)
+define(m4_assert_onearg_internal,
+`ifelse($2,1,,
+`m4_error(`$1 expected 1 argument, got 'm4_Narguments(`$2')
+)')')
+
+
+dnl  Usage: m4_assert_numargs_range(low,high)
+dnl
+dnl  Put this, unquoted, at the start of a macro definition to add some code
+dnl  to check that between low and high many arguments get passed to the
+dnl  macro.  For example,
+dnl
+dnl         define(foo,
+dnl         m4_assert_numargs_range(3,5)
+dnl         `mandatory $1 $2 $3 optional $4 $5 end')
+dnl
+dnl  See m4_assert_numargs() for more info.
+
+define(m4_assert_numargs_range,
+m4_assert_numargs(2)
+``m4_assert_numargs_range_internal'(m4_doublequote($`'0),$1,$2,$`#',`len'(m4_doublequote($`'1)))`dnl '')
+
+dnl  Called: m4_assert_numargs_range_internal(`name',low,high,$#,len(`$1'))
+define(m4_assert_numargs_range_internal,
+m4_assert_numargs(5)
+`m4_assert_numargs_range_check(`$1',`$2',`$3',m4_numargs_count(`$4',`$5'))')
+
+dnl  Called: m4_assert_numargs_range_check(`name',low,high,gotargs)
+dnl
+dnl  If m4_dollarhash_1_if_noparen_p (BSD m4) then gotargs can be 0 when it
+dnl  should be -1.  To ensure a `high' of -1 works, a fudge is applied to
+dnl  gotargs if it's 0 and the 0 and -1 cases can't be distinguished.
+dnl
+define(m4_assert_numargs_range_check,
+m4_assert_numargs(4)
+`ifelse(eval($2 <= $4 &&
+             ($4 - ($4==0 && m4_dollarhash_1_if_noparen_p) <= $3)),0,
+`m4_error(`$1 expected $2 to $3 arguments, got 'm4_Narguments(`$4')
+)')')
+
+
+dnl  Usage: m4_assert_defined(symbol)
+dnl
+dnl  Put this unquoted on a line of its own at the start of a macro
+dnl  definition to add some code to check that the given symbol is defined
+dnl  when the macro is used.  For example,
+dnl
+dnl          define(foo,
+dnl          m4_assert_defined(`FOO_PREFIX')
+dnl          `FOO_PREFIX whatever')
+dnl
+dnl  This is a convenient way to check that the user or ./configure or
+dnl  whatever has defined the things needed by a macro, as opposed to
+dnl  silently generating garbage.
+
+define(m4_assert_defined,
+m4_assert_numargs(1)
+``m4_assert_defined_internal'(m4_doublequote($`'0),``$1'')`dnl '')
+
+dnl  Called: m4_assert_defined_internal(`macroname',`define_required')
+define(m4_assert_defined_internal,
+m4_assert_numargs(2)
+`m4_ifdef(`$2',,
+`m4_error(`$1 needs $2 defined
+')')')
+
+
+dnl  Usage: m4_not_for_expansion(`SYMBOL')
+dnl         define_not_for_expansion(`SYMBOL')
+dnl
+dnl  m4_not_for_expansion turns SYMBOL, if defined, into something which
+dnl  will give an error if expanded.  For example,
+dnl
+dnl         m4_not_for_expansion(`PIC')
+dnl
+dnl  define_not_for_expansion is the same, but always makes a definition.
+dnl
+dnl  These are for symbols that should be tested with ifdef(`FOO',...)
+dnl  rather than be expanded as such.  They guard against accidentally
+dnl  omitting the quotes, as in ifdef(FOO,...).  Note though that they only
+dnl  catches this when FOO is defined, so be sure to test code both with and
+dnl  without each definition.
+
+define(m4_not_for_expansion,
+m4_assert_numargs(1)
+`ifdef(`$1',`define_not_for_expansion(`$1')')')
+
+define(define_not_for_expansion,
+m4_assert_numargs(1)
+`ifelse(defn(`$1'),,,
+`m4_error(``$1' has a non-empty value, maybe it shouldnt be munged with m4_not_for_expansion()
+')')dnl
+define(`$1',`m4_not_for_expansion_internal(`$1')')')
+
+define(m4_not_for_expansion_internal,
+`m4_error(``$1' is not meant to be expanded, perhaps you mean `ifdef(`$1',...)'
+')')
+
+
+dnl  --------------------------------------------------------------------------
+dnl  Various generic m4 things.
+
+
+dnl  Usage: m4_unquote(macro)
+dnl
+dnl  Allow the argument text to be re-evaluated.  This is useful for "token
+dnl  pasting" like m4_unquote(foo`'bar).
+
+define(m4_unquote,
+m4_assert_onearg()
+`$1')
+
+
+dnl  Usage: m4_ifdef(name,yes[,no])
+dnl
+dnl  Expand to the yes argument if name is defined, or to the no argument if
+dnl  not.
+dnl
+dnl  This is the same as the builtin "ifdef", but avoids an OSF 4.0 m4 bug
+dnl  in which a macro with a zero value `0' or `00' etc is considered not
+dnl  defined.
+dnl
+dnl  There's no particular need to use this everywhere, only if there might
+dnl  be a zero value.
+
+define(m4_ifdef,
+m4_assert_numargs_range(2,3)
+`ifelse(eval(ifdef(`$1',1,0)+m4_length(defn(`$1'))),0,
+`$3',`$2')')
+
+
+dnl  Usage: m4_ifdef_anyof_p(`symbol',...)
+dnl
+dnl  Expand to 1 if any of the symbols in the argument list are defined, or
+dnl  to 0 if not.
+
+define(m4_ifdef_anyof_p,
+`ifelse(eval($#<=1 && m4_length(`$1')==0),1, 0,
+`ifdef(`$1', 1,
+`m4_ifdef_anyof_p(shift($@))')')')
+
+
+dnl  Usage: m4_length(string)
+dnl
+dnl  Determine the length of a string.  This is the same as len(), but
+dnl  always expands to a number, working around the BSD len() which
+dnl  evaluates to nothing given an empty argument.
+
+define(m4_length,
+m4_assert_onearg()
+`eval(len(`$1')-0)')
+
+
+dnl  Usage: m4_stringequal_p(x,y)
+dnl
+dnl  Expand to 1 or 0 according as strings x and y are equal or not.
+
+define(m4_stringequal_p,
+`ifelse(`$1',`$2',1,0)')
+
+
+dnl  Usage: m4_incr_or_decr(n,last)
+dnl
+dnl  Do an incr(n) or decr(n), whichever is in the direction of "last".
+dnl  Both n and last must be numbers of course.
+
+define(m4_incr_or_decr,
+m4_assert_numargs(2)
+`ifelse(eval($1<$2),1,incr($1),decr($1))')
+
+
+dnl  Usage: forloop(i, first, last, statement)
+dnl
+dnl  Based on GNU m4 examples/forloop.m4, but extended.
+dnl
+dnl  statement is expanded repeatedly, with i successively defined as
+dnl
+dnl         first, first+1, ..., last-1, last
+dnl
+dnl  Or if first > last, then it's
+dnl
+dnl         first, first-1, ..., last+1, last
+dnl
+dnl  If first == last, then one expansion is done.
+dnl
+dnl  A pushdef/popdef of i is done to preserve any previous definition (or
+dnl  lack of definition).  first and last are eval()ed and so can be
+dnl  expressions.
+dnl
+dnl  forloop_first is defined to 1 on the first iteration, 0 on the rest.
+dnl  forloop_last is defined to 1 on the last iteration, 0 on the others.
+dnl  Nested forloops are allowed, in which case forloop_first and
+dnl  forloop_last apply to the innermost loop that's open.
+dnl
+dnl  A simple example,
+dnl
+dnl         forloop(i, 1, 2*2+1, `dnl
+dnl         iteration number i ... ifelse(forloop_first,1,FIRST)
+dnl         ')
+
+
+dnl  "i" and "statement" are carefully quoted, but "first" and "last" are
+dnl  just plain numbers once eval()ed.
+
+define(`forloop',
+m4_assert_numargs(4)
+`pushdef(`$1',eval(`$2'))dnl
+pushdef(`forloop_first',1)dnl
+pushdef(`forloop_last',0)dnl
+forloop_internal(`$1',eval(`$3'),`$4')`'dnl
+popdef(`forloop_first')dnl
+popdef(`forloop_last')dnl
+popdef(`$1')')
+
+dnl  Called: forloop_internal(`var',last,statement)
+define(`forloop_internal',
+m4_assert_numargs(3)
+`ifelse($1,$2,
+`define(`forloop_last',1)$3',
+`$3`'dnl
+define(`forloop_first',0)dnl
+define(`$1',m4_incr_or_decr($1,$2))dnl
+forloop_internal(`$1',$2,`$3')')')
+
+
+dnl  Usage: foreach(var,body, item1,item2,...,itemN)
+dnl
+dnl  For each "item" argument, define "var" to that value and expand "body".
+dnl  For example,
+dnl
+dnl         foreach(i, `something i
+dnl         ', one, two)
+dnl  gives
+dnl         something one
+dnl         something two
+dnl
+dnl  Any previous definition of "var", or lack thereof, is saved and
+dnl  restored.  Empty "item"s are not allowed.
+
+define(foreach,
+m4_assert_numargs_range(2,1000)
+`ifelse(`$3',,,
+`pushdef(`$1',`$3')$2`'popdef(`$1')dnl
+foreach(`$1',`$2',shift(shift(shift($@))))')')
+
+
+dnl  Usage: m4_toupper(x)
+dnl         m4_tolower(x)
+dnl
+dnl  Convert the argument string to upper or lower case, respectively.
+dnl  Only one argument accepted.
+dnl
+dnl  BSD m4 doesn't take ranges like a-z in translit(), so the full alphabet
+dnl  is written out.
+
+define(m4_alphabet_lower, `abcdefghijklmnopqrstuvwxyz')
+define(m4_alphabet_upper, `ABCDEFGHIJKLMNOPQRSTUVWXYZ')
+
+define(m4_toupper,
+m4_assert_onearg()
+`translit(`$1', m4_alphabet_lower, m4_alphabet_upper)')
+
+define(m4_tolower,
+m4_assert_onearg()
+`translit(`$1', m4_alphabet_upper, m4_alphabet_lower)')
+
+
+dnl  Usage: m4_empty_if_zero(x)
+dnl
+dnl  Evaluate to x, or to nothing if x is 0.  x is eval()ed and so can be an
+dnl  expression.
+dnl
+dnl  This is useful for x86 addressing mode displacements since forms like
+dnl  (%ebx) are one byte shorter than 0(%ebx).  A macro `foo' for use as
+dnl  foo(%ebx) could be defined with the following so it'll be empty if the
+dnl  expression comes out zero.
+dnl
+dnl	   deflit(`foo', `m4_empty_if_zero(a+b*4-c)')
+dnl
+dnl  Naturally this shouldn't be done if, say, a computed jump depends on
+dnl  the code being a particular size.
+
+define(m4_empty_if_zero,
+m4_assert_onearg()
+`ifelse(eval($1),0,,eval($1))')
+
+
+dnl  Usage: m4_log2(x)
+dnl
+dnl  Calculate a logarithm to base 2.
+dnl  x must be an integral power of 2, between 2**0 and 2**30.
+dnl  x is eval()ed, so it can be an expression.
+dnl  An error results if x is invalid.
+dnl
+dnl  2**31 isn't supported, because an unsigned 2147483648 is out of range
+dnl  of a 32-bit signed int.  Also, the bug in BSD m4 where an eval()
+dnl  resulting in 2147483648 (or -2147483648 as the case may be) gives `-('
+dnl  means tests like eval(1<<31==(x)) would be necessary, but that then
+dnl  gives an unattractive explosion of eval() error messages if x isn't
+dnl  numeric.
+
+define(m4_log2,
+m4_assert_numargs(1)
+`m4_log2_internal(0,1,eval(`$1'))')
+
+dnl  Called: m4_log2_internal(n,2**n,target)
+define(m4_log2_internal,
+m4_assert_numargs(3)
+`ifelse($2,$3,$1,
+`ifelse($1,30,
+`m4_error(`m4_log2() argument too big or not a power of two: $3
+')',
+`m4_log2_internal(incr($1),eval(2*$2),$3)')')')
+
+
+dnl  Usage:  m4_div2_towards_zero
+dnl
+dnl  m4 division is probably whatever a C signed division is, and C doesn't
+dnl  specify what rounding gets used on negatives, so this expression forces
+dnl  a rounding towards zero.
+
+define(m4_div2_towards_zero,
+m4_assert_numargs(1)
+`eval((($1) + ((($1)<0) & ($1))) / 2)')
+
+
+dnl  Usage: m4_lshift(n,count)
+dnl         m4_rshift(n,count)
+dnl
+dnl  Calculate n shifted left or right by count many bits.  Both n and count
+dnl  are eval()ed and so can be expressions.
+dnl
+dnl  Negative counts are allowed and mean a shift in the opposite direction.
+dnl  Negative n is allowed and right shifts will be arithmetic (meaning
+dnl  divide by 2**count, rounding towards zero, also meaning the sign bit is
+dnl  duplicated).
+dnl
+dnl  Use these macros instead of << and >> in eval() since the basic ccs
+dnl  SysV m4 doesn't have those operators.
+
+define(m4_rshift,
+m4_assert_numargs(2)
+`m4_lshift(`$1',-(`$2'))')
+
+define(m4_lshift,
+m4_assert_numargs(2)
+`m4_lshift_internal(eval(`$1'),eval(`$2'))')
+
+define(m4_lshift_internal,
+m4_assert_numargs(2)
+`ifelse(eval($2-0==0),1,$1,
+`ifelse(eval($2>0),1,
+`m4_lshift_internal(eval($1*2),decr($2))',
+`m4_lshift_internal(m4_div2_towards_zero($1),incr($2))')')')
+
+
+dnl  Usage: m4_popcount(n)
+dnl
+dnl  Expand to the number 1 bits in n.
+
+define(m4_popcount,
+m4_assert_numargs(1)
+`m4_popcount_internal(0,eval(`$1'))')
+
+dnl  Called: m4_popcount_internal(count,rem)
+define(m4_popcount_internal,
+m4_assert_numargs(2)
+`ifelse($2,0,$1,
+`m4_popcount_internal(eval($1+($2%2)),eval($2/2))')')
+
+
+dnl  Usage: m4_count_trailing_zeros(N)
+dnl
+dnl  Determine the number of trailing zero bits on N.  N is eval()ed and so
+dnl  can be an expression.  If N is zero an error is generated.
+
+define(m4_count_trailing_zeros,
+m4_assert_numargs(1)
+`m4_count_trailing_zeros_internal(eval(`$1'),0)')
+
+dnl  Called: m4_count_trailing_zeros_internal(val,count)
+define(m4_count_trailing_zeros_internal,
+m4_assert_numargs(2)
+`ifelse($1,0,
+`m4_error(`m4_count_trailing_zeros() given a zero value')',
+`ifelse(eval(($1)%2),1,`$2',
+`m4_count_trailing_zeros_internal(eval($1/2),incr($2))')')')
+
+
+dnl  Usage: deflit(name,value)
+dnl
+dnl  Like define(), but "name" expands like a literal, rather than taking
+dnl  arguments.  For example "name(%eax)" expands to "value(%eax)".
+dnl
+dnl  Limitations:
+dnl
+dnl  $ characters in the value part must have quotes to stop them looking
+dnl  like macro parameters.  For example, deflit(reg,`123+$`'4+567').  See
+dnl  defreg() below for handling simple register definitions like $7 etc.
+dnl
+dnl  "name()" is turned into "name", unfortunately.  In GNU and SysV m4 an
+dnl  error is generated when this happens, but in BSD m4 it will happen
+dnl  silently.  The problem is that in BSD m4 $# is 1 in both "name" or
+dnl  "name()", so there's no way to differentiate them.  Because we want
+dnl  plain "name" to turn into plain "value", we end up with "name()"
+dnl  turning into plain "value" too.
+dnl
+dnl  "name(foo)" will lose any whitespace after commas in "foo", for example
+dnl  "disp(%eax, %ecx)" would become "128(%eax,%ecx)".
+dnl
+dnl  These parentheses oddities shouldn't matter in assembler text, but if
+dnl  they do the suggested workaround is to write "name ()" or "name (foo)"
+dnl  to stop the parentheses looking like a macro argument list.  If a space
+dnl  isn't acceptable in the output, then write "name`'()" or "name`'(foo)".
+dnl  The `' is stripped when read, but again stops the parentheses looking
+dnl  like parameters.
+
+dnl  Quoting for deflit_emptyargcheck is similar to m4_assert_numargs.  The
+dnl  stuff in the ifelse gives a $#, $1 and $@ evaluated in the new macro
+dnl  created, not in deflit.
+define(deflit,
+m4_assert_numargs(2)
+`define(`$1',
+`deflit_emptyargcheck'(``$1'',$`#',m4_doublequote($`'1))`dnl
+$2`'dnl
+ifelse(eval($'`#>1 || m4_length('m4_doublequote($`'1)`)!=0),1,($'`@))')')
+
+dnl  Called: deflit_emptyargcheck(macroname,$#,`$1')
+define(deflit_emptyargcheck,
+`ifelse(eval($2==1 && !m4_dollarhash_1_if_noparen_p && m4_length(`$3')==0),1,
+`m4_error(`dont use a deflit as $1() because it loses the brackets (see deflit in asm-defs.m4 for more information)
+')')')
+
+
+dnl  Usage: m4_assert(`expr')
+dnl
+dnl  Test a compile-time requirement with an m4 expression.  The expression
+dnl  should be quoted, and will be eval()ed and expected to be non-zero.
+dnl  For example,
+dnl
+dnl         m4_assert(`FOO*2+6 < 14')
+
+define(m4_assert,
+m4_assert_numargs(1)
+`ifelse(eval($1),1,,
+`m4_error(`assertion failed: $1
+')')')
+
+
+dnl  Usage: m4_repeat(count,text)
+dnl
+dnl  Expand to the given repetitions of the given text.  A zero count is
+dnl  allowed, and expands to nothing.
+
+define(m4_repeat,
+m4_assert_numargs(2)
+`m4_repeat_internal(eval($1),`$2')')
+
+define(m4_repeat_internal,
+m4_assert_numargs(2)
+`ifelse(`$1',0,,
+`forloop(m4_repeat_internal_counter,1,$1,``$2'')')')
+
+
+dnl  Usage: m4_hex_lowmask(bits)
+dnl
+dnl  Generate a hex constant which is a low mask of the given number of
+dnl  bits.  For example m4_hex_lowmask(10) would give 0x3ff.
+
+define(m4_hex_lowmask,
+m4_assert_numargs(1)
+`m4_cpu_hex_constant(m4_hex_lowmask_internal1(eval(`$1')))')
+
+dnl  Called: m4_hex_lowmask_internal1(bits)
+define(m4_hex_lowmask_internal1,
+m4_assert_numargs(1)
+`ifelse($1,0,`0',
+`m4_hex_lowmask_internal2(eval(($1)%4),eval(($1)/4))')')
+
+dnl  Called: m4_hex_lowmask_internal(remainder,digits)
+define(m4_hex_lowmask_internal2,
+m4_assert_numargs(2)
+`ifelse($1,1,`1',
+`ifelse($1,2,`3',
+`ifelse($1,3,`7')')')dnl
+m4_repeat($2,`f')')
+
+
+dnl  --------------------------------------------------------------------------
+dnl  The following m4_list functions take a list as multiple arguments.
+dnl  Arguments are evaluated multiple times, there's no attempt at strict
+dnl  quoting.  Empty list elements are not allowed, since an empty final
+dnl  argument is ignored.  These restrictions don't affect the current uses,
+dnl  and make the implementation easier.
+
+
+dnl  Usage: m4_list_quote(list,...)
+dnl
+dnl  Produce a list with quoted commas, so it can be a single argument
+dnl  string.  For instance m4_list_quote(a,b,c) gives
+dnl
+dnl         a`,'b`,'c`,'
+dnl
+dnl  This can be used to put a list in a define,
+dnl
+dnl         define(foolist, m4_list_quote(a,b,c))
+dnl
+dnl  Which can then be used for instance as
+dnl
+dnl         m4_list_find(target, foolist)
+
+define(m4_list_quote,
+`ifelse(`$1',,,
+`$1`,'m4_list_quote(shift($@))')')
+
+
+dnl  Usage: m4_list_find(key,list,...)
+dnl
+dnl  Evaluate to 1 or 0 according to whether key is in the list elements.
+
+define(m4_list_find,
+m4_assert_numargs_range(1,1000)
+`ifelse(`$2',,0,
+`ifelse(`$1',`$2',1,
+`m4_list_find(`$1',shift(shift($@)))')')')
+
+
+dnl  Usage: m4_list_remove(key,list,...)
+dnl
+dnl  Evaluate to the given list with `key' removed (if present).
+
+define(m4_list_remove,
+m4_assert_numargs_range(1,1000)
+`ifelse(`$2',,,
+`ifelse(`$1',`$2',,`$2,')dnl
+m4_list_remove(`$1',shift(shift($@)))')')
+
+
+dnl  Usage: m4_list_first(list,...)
+dnl
+dnl  Evaluate to the first element of the list (if any).
+
+define(m4_list_first,`$1')
+
+
+dnl  Usage: m4_list_count(list,...)
+dnl
+dnl  Evaluate to the number of elements in the list.  This can't just use $#
+dnl  because the last element might be empty.
+
+define(m4_list_count,
+`m4_list_count_internal(0,$@)')
+
+dnl  Called: m4_list_internal(count,list,...)
+define(m4_list_count_internal,
+m4_assert_numargs_range(1,1000)
+`ifelse(`$2',,$1,
+`m4_list_count_internal(eval($1+1),shift(shift($@)))')')
+
+
+dnl  --------------------------------------------------------------------------
+dnl  Various assembler things, not specific to any particular CPU.
+dnl
+
+
+dnl  Usage: include_mpn(`filename')
+dnl
+dnl  Like include(), but adds a path to the mpn source directory.  For
+dnl  example,
+dnl
+dnl         include_mpn(`sparc64/addmul_1h.asm')
+
+define(include_mpn,
+m4_assert_numargs(1)
+m4_assert_defined(`CONFIG_TOP_SRCDIR')
+`include(CONFIG_TOP_SRCDIR`/mpn/$1')')
+
+
+dnl  Usage: C comment ...
+dnl
+dnl  This works like a FORTRAN-style comment character.  It can be used for
+dnl  comments to the right of assembly instructions, where just dnl would
+dnl  remove the newline and concatenate adjacent lines.
+dnl
+dnl  C and/or dnl are useful when an assembler doesn't support comments, or
+dnl  where different assemblers for a particular CPU need different styles.
+dnl  The intermediate ".s" files will end up with no comments, just code.
+dnl
+dnl  Using C is not intended to cause offence to anyone who doesn't like
+dnl  FORTRAN; but if that happens it's an unexpected bonus.
+dnl
+dnl  During development, if comments are wanted in the .s files to help see
+dnl  what's expanding where, C can be redefined with something like
+dnl
+dnl         define(`C',`#')
+
+define(C, `
+dnl')
+
+
+dnl  Normally PIC is defined (or not) by libtool, but it doesn't set it on
+dnl  systems which are always PIC.  PIC_ALWAYS established in config.m4
+dnl  identifies these for us.
+
+ifelse(`PIC_ALWAYS',`yes',`define(`PIC')')
+
+
+dnl  Various possible defines passed from the Makefile that are to be tested
+dnl  with ifdef() rather than be expanded.
+
+m4_not_for_expansion(`PIC')
+m4_not_for_expansion(`DLL_EXPORT')
+
+dnl  aors_n
+m4_not_for_expansion(`OPERATION_add_n')
+m4_not_for_expansion(`OPERATION_sub_n')
+
+dnl  aors_err1_n
+m4_not_for_expansion(`OPERATION_add_err1_n')
+m4_not_for_expansion(`OPERATION_sub_err1_n')
+
+dnl  aors_err2_n
+m4_not_for_expansion(`OPERATION_add_err2_n')
+m4_not_for_expansion(`OPERATION_sub_err2_n')
+
+dnl  aors_err3_n
+m4_not_for_expansion(`OPERATION_add_err3_n')
+m4_not_for_expansion(`OPERATION_sub_err3_n')
+
+dnl  aorsmul_1
+m4_not_for_expansion(`OPERATION_addmul_1')
+m4_not_for_expansion(`OPERATION_submul_1')
+
+dnl  logops_n
+m4_not_for_expansion(`OPERATION_and_n')
+m4_not_for_expansion(`OPERATION_andn_n')
+m4_not_for_expansion(`OPERATION_nand_n')
+m4_not_for_expansion(`OPERATION_ior_n')
+m4_not_for_expansion(`OPERATION_iorn_n')
+m4_not_for_expansion(`OPERATION_nior_n')
+m4_not_for_expansion(`OPERATION_xor_n')
+m4_not_for_expansion(`OPERATION_xnor_n')
+
+dnl  popham
+m4_not_for_expansion(`OPERATION_popcount')
+m4_not_for_expansion(`OPERATION_hamdist')
+
+dnl  lorrshift
+m4_not_for_expansion(`OPERATION_lshift')
+m4_not_for_expansion(`OPERATION_rshift')
+
+dnl  aorslsh1_n
+m4_not_for_expansion(`OPERATION_addlsh1_n')
+m4_not_for_expansion(`OPERATION_sublsh1_n')
+m4_not_for_expansion(`OPERATION_rsblsh1_n')
+
+dnl  aorslsh2_n
+m4_not_for_expansion(`OPERATION_addlsh2_n')
+m4_not_for_expansion(`OPERATION_sublsh2_n')
+m4_not_for_expansion(`OPERATION_rsblsh2_n')
+
+dnl  rsh1aors_n
+m4_not_for_expansion(`OPERATION_rsh1add_n')
+m4_not_for_expansion(`OPERATION_rsh1sub_n')
+
+
+dnl  Usage: m4_config_gmp_mparam(`symbol')
+dnl
+dnl  Check that `symbol' is defined.  If it isn't, issue an error and
+dnl  terminate immediately.  The error message explains that the symbol
+dnl  should be in config.m4, copied from gmp-mparam.h.
+dnl
+dnl  Termination is immediate since missing say SQR_TOOM2_THRESHOLD can
+dnl  lead to infinite loops and endless error messages.
+
+define(m4_config_gmp_mparam,
+m4_assert_numargs(1)
+`ifdef(`$1',,
+`m4_error(`$1 is not defined.
+	"configure" should have extracted this from gmp-mparam.h and put it
+	in config.m4 (or in <cpu>_<file>.asm for a fat binary), but somehow
+        this has failed.
+')m4exit(1)')')
+
+
+dnl  Usage: defreg(name,reg)
+dnl
+dnl  Give a name to a $ style register.  For example,
+dnl
+dnl         defreg(foo,$12)
+dnl
+dnl  defreg() inserts an extra pair of quotes after the $ so that it's not
+dnl  interpreted as an m4 macro parameter, ie. foo is actually $`'12.  m4
+dnl  strips those quotes when foo is expanded.
+dnl
+dnl  deflit() is used to make the new definition, so it will expand
+dnl  literally even if followed by parentheses ie. foo(99) will become
+dnl  $12(99).  (But there's nowhere that would be used is there?)
+dnl
+dnl  When making further definitions from existing defreg() macros, remember
+dnl  to use defreg() again to protect the $ in the new definitions too.  For
+dnl  example,
+dnl
+dnl         defreg(a0,$4)
+dnl         defreg(a1,$5)
+dnl         ...
+dnl
+dnl         defreg(PARAM_DST,a0)
+dnl
+dnl  This is only because a0 is expanding at the time the PARAM_DST
+dnl  definition is made, leaving a literal $4 that must be re-quoted.  On
+dnl  the other hand in something like the following ra is only expanded when
+dnl  ret is used and its $`'31 protection will have its desired effect at
+dnl  that time.
+dnl
+dnl         defreg(ra,$31)
+dnl         ...
+dnl         define(ret,`j ra')
+dnl
+dnl  Note that only $n forms are meant to be used here, and something like
+dnl  128($30) doesn't get protected and will come out wrong.
+
+define(defreg,
+m4_assert_numargs(2)
+`deflit(`$1',
+substr(`$2',0,1)``''substr(`$2',1))')
+
+
+dnl  Usage: m4_instruction_wrapper()
+dnl
+dnl  Put this, unquoted, on a line on its own, at the start of a macro
+dnl  that's a wrapper around an assembler instruction.  It adds code to give
+dnl  a descriptive error message if the macro is invoked without arguments.
+dnl
+dnl  For example, suppose jmp needs to be wrapped,
+dnl
+dnl         define(jmp,
+dnl         m4_instruction_wrapper()
+dnl         m4_assert_numargs(1)
+dnl                 `.byte 0x42
+dnl                 .long  $1
+dnl                 nop')
+dnl
+dnl  The point of m4_instruction_wrapper is to get a better error message
+dnl  than m4_assert_numargs would give if jmp is accidentally used as plain
+dnl  "jmp foo" instead of the intended "jmp( foo)".  "jmp()" with no
+dnl  argument also provokes the error message.
+dnl
+dnl  m4_instruction_wrapper should only be used with wrapped instructions
+dnl  that take arguments, since obviously something meant to be used as say
+dnl  plain "ret" doesn't want to give an error when used that way.
+
+define(m4_instruction_wrapper,
+m4_assert_numargs(0)
+``m4_instruction_wrapper_internal'(m4_doublequote($`'0),dnl
+ifdef(`__file__',`m4_doublequote(__file__)',``the m4 sources''),dnl
+$`#',m4_doublequote($`'1))`dnl'')
+
+dnl  Called: m4_instruction_wrapper_internal($0,`filename',$#,$1)
+define(m4_instruction_wrapper_internal,
+`ifelse(eval($3<=1 && m4_length(`$4')==0),1,
+`m4_error(`$1 is a macro replacing that instruction and needs arguments, see $2 for details
+')')')
+
+
+dnl  Usage: m4_cpu_hex_constant(string)
+dnl
+dnl  Expand to the string prefixed by a suitable `0x' hex marker.  This
+dnl  should be redefined as necessary for CPUs with different conventions.
+
+define(m4_cpu_hex_constant,
+m4_assert_numargs(1)
+`0x`$1'')
+
+
+dnl  Usage: UNROLL_LOG2, UNROLL_MASK, UNROLL_BYTES
+dnl         CHUNK_LOG2, CHUNK_MASK, CHUNK_BYTES
+dnl
+dnl  When code supports a variable amount of loop unrolling, the convention
+dnl  is to define UNROLL_COUNT to the number of limbs processed per loop.
+dnl  When testing code this can be varied to see how much the loop overhead
+dnl  is costing.  For example,
+dnl
+dnl         deflit(UNROLL_COUNT, 32)
+dnl
+dnl  If the forloop() generating the unrolled loop has a pattern processing
+dnl  more than one limb, the convention is to express this with CHUNK_COUNT.
+dnl  For example,
+dnl
+dnl         deflit(CHUNK_COUNT, 2)
+dnl
+dnl  The LOG2, MASK and BYTES definitions below are derived from these COUNT
+dnl  definitions.  If COUNT is redefined, the LOG2, MASK and BYTES follow
+dnl  the new definition automatically.
+dnl
+dnl  LOG2 is the log base 2 of COUNT.  MASK is COUNT-1, which can be used as
+dnl  a bit mask.  BYTES is GMP_LIMB_BYTES*COUNT, the number of bytes
+dnl  processed in each unrolled loop.
+dnl
+dnl  GMP_LIMB_BYTES is defined in a CPU specific m4 include file.  It
+dnl  exists only so the BYTES definitions here can be common to all CPUs.
+dnl  In the actual code for a given CPU, an explicit 4 or 8 may as well be
+dnl  used because the code is only for a particular CPU, it doesn't need to
+dnl  be general.
+dnl
+dnl  Note that none of these macros do anything except give conventional
+dnl  names to commonly used things.  You still have to write your own
+dnl  expressions for a forloop() and the resulting address displacements.
+dnl  Something like the following would be typical for 4 bytes per limb.
+dnl
+dnl         forloop(`i',0,UNROLL_COUNT-1,`
+dnl                 deflit(`disp',eval(i*4))
+dnl                 ...
+dnl         ')
+dnl
+dnl  Or when using CHUNK_COUNT,
+dnl
+dnl         forloop(`i',0,UNROLL_COUNT/CHUNK_COUNT-1,`
+dnl                 deflit(`disp0',eval(i*CHUNK_COUNT*4))
+dnl                 deflit(`disp1',eval(disp0+4))
+dnl                 ...
+dnl         ')
+dnl
+dnl  Clearly `i' can be run starting from 1, or from high to low or whatever
+dnl  best suits.
+
+deflit(UNROLL_LOG2,
+m4_assert_defined(`UNROLL_COUNT')
+`m4_log2(UNROLL_COUNT)')
+
+deflit(UNROLL_MASK,
+m4_assert_defined(`UNROLL_COUNT')
+`eval(UNROLL_COUNT-1)')
+
+deflit(UNROLL_BYTES,
+m4_assert_defined(`UNROLL_COUNT')
+m4_assert_defined(`GMP_LIMB_BYTES')
+`eval(UNROLL_COUNT * GMP_LIMB_BYTES)')
+
+deflit(CHUNK_LOG2,
+m4_assert_defined(`CHUNK_COUNT')
+`m4_log2(CHUNK_COUNT)')
+
+deflit(CHUNK_MASK,
+m4_assert_defined(`CHUNK_COUNT')
+`eval(CHUNK_COUNT-1)')
+
+deflit(CHUNK_BYTES,
+m4_assert_defined(`CHUNK_COUNT')
+m4_assert_defined(`GMP_LIMB_BYTES')
+`eval(CHUNK_COUNT * GMP_LIMB_BYTES)')
+
+
+dnl  Usage: MPN(name)
+dnl
+dnl  Add MPN_PREFIX to a name.
+dnl  MPN_PREFIX defaults to "__gmpn_" if not defined.
+dnl
+dnl  m4_unquote is used in MPN so that when it expands to say __gmpn_foo,
+dnl  that identifier will be subject to further macro expansion.  This is
+dnl  used by some of the fat binary support for renaming symbols.
+
+ifdef(`MPN_PREFIX',,
+`define(`MPN_PREFIX',`__gmpn_')')
+
+define(MPN,
+m4_assert_numargs(1)
+`m4_unquote(MPN_PREFIX`'$1)')
+
+
+dnl  Usage: mpn_add_n, etc
+dnl
+dnl  Convenience definitions using MPN(), like the #defines in gmp.h.  Each
+dnl  function that might be implemented in assembler is here.
+
+define(define_mpn,
+m4_assert_numargs(1)
+`deflit(`mpn_$1',`MPN(`$1')')')
+
+define_mpn(add)
+define_mpn(add_1)
+define_mpn(add_err1_n)
+define_mpn(add_err2_n)
+define_mpn(add_err3_n)
+define_mpn(add_n)
+define_mpn(add_nc)
+define_mpn(addlsh1_n)
+define_mpn(addlsh1_nc)
+define_mpn(addlsh2_n)
+define_mpn(addlsh2_nc)
+define_mpn(addlsh_n)
+define_mpn(addlsh_nc)
+define_mpn(addlsh1_n_ip1)
+define_mpn(addlsh1_nc_ip1)
+define_mpn(addlsh2_n_ip1)
+define_mpn(addlsh2_nc_ip1)
+define_mpn(addlsh_n_ip1)
+define_mpn(addlsh_nc_ip1)
+define_mpn(addlsh1_n_ip2)
+define_mpn(addlsh1_nc_ip2)
+define_mpn(addlsh2_n_ip2)
+define_mpn(addlsh2_nc_ip2)
+define_mpn(addlsh_n_ip2)
+define_mpn(addlsh_nc_ip2)
+define_mpn(addmul_1)
+define_mpn(addmul_1c)
+define_mpn(addmul_2)
+define_mpn(addmul_3)
+define_mpn(addmul_4)
+define_mpn(addmul_5)
+define_mpn(addmul_6)
+define_mpn(addmul_7)
+define_mpn(addmul_8)
+define_mpn(addmul_2s)
+define_mpn(add_n_sub_n)
+define_mpn(add_n_sub_nc)
+define_mpn(addaddmul_1msb0)
+define_mpn(and_n)
+define_mpn(andn_n)
+define_mpn(bdiv_q_1)
+define_mpn(pi1_bdiv_q_1)
+define_mpn(bdiv_dbm1c)
+define_mpn(cmp)
+define_mpn(cnd_add_n)
+define_mpn(cnd_sub_n)
+define_mpn(com)
+define_mpn(copyd)
+define_mpn(copyi)
+define_mpn(count_leading_zeros)
+define_mpn(count_trailing_zeros)
+define_mpn(div_qr_1n_pi1)
+define_mpn(div_qr_2)
+define_mpn(div_qr_2n_pi1)
+define_mpn(div_qr_2u_pi1)
+define_mpn(div_qr_2n_pi2)
+define_mpn(div_qr_2u_pi2)
+define_mpn(divexact_1)
+define_mpn(divexact_by3c)
+define_mpn(divrem)
+define_mpn(divrem_1)
+define_mpn(divrem_1c)
+define_mpn(divrem_2)
+define_mpn(divrem_classic)
+define_mpn(divrem_newton)
+define_mpn(dump)
+define_mpn(gcd)
+define_mpn(gcd_1)
+define_mpn(gcd_11)
+define_mpn(gcd_22)
+define_mpn(gcdext)
+define_mpn(get_str)
+define_mpn(hamdist)
+define_mpn(invert_limb)
+define_mpn(invert_limb_table)
+define_mpn(ior_n)
+define_mpn(iorn_n)
+define_mpn(lshift)
+define_mpn(lshiftc)
+define_mpn(mod_1_1p)
+define_mpn(mod_1_1p_cps)
+define_mpn(mod_1s_2p)
+define_mpn(mod_1s_2p_cps)
+define_mpn(mod_1s_3p)
+define_mpn(mod_1s_3p_cps)
+define_mpn(mod_1s_4p)
+define_mpn(mod_1s_4p_cps)
+define_mpn(mod_1)
+define_mpn(mod_1c)
+define_mpn(mod_34lsub1)
+define_mpn(modexact_1_odd)
+define_mpn(modexact_1c_odd)
+define_mpn(mul)
+define_mpn(mul_1)
+define_mpn(mul_1c)
+define_mpn(mul_2)
+define_mpn(mul_3)
+define_mpn(mul_4)
+define_mpn(mul_5)
+define_mpn(mul_6)
+define_mpn(mul_basecase)
+define_mpn(mul_n)
+define_mpn(mullo_basecase)
+define_mpn(mulmid_basecase)
+define_mpn(perfect_square_p)
+define_mpn(popcount)
+define_mpn(preinv_divrem_1)
+define_mpn(preinv_mod_1)
+define_mpn(nand_n)
+define_mpn(neg)
+define_mpn(nior_n)
+define_mpn(powm)
+define_mpn(powlo)
+define_mpn(random)
+define_mpn(random2)
+define_mpn(redc_1)
+define_mpn(redc_2)
+define_mpn(rsblsh1_n)
+define_mpn(rsblsh1_nc)
+define_mpn(rsblsh2_n)
+define_mpn(rsblsh2_nc)
+define_mpn(rsblsh_n)
+define_mpn(rsblsh_nc)
+define_mpn(rsh1add_n)
+define_mpn(rsh1add_nc)
+define_mpn(rsh1sub_n)
+define_mpn(rsh1sub_nc)
+define_mpn(rshift)
+define_mpn(rshiftc)
+define_mpn(sbpi1_bdiv_q)
+define_mpn(sbpi1_bdiv_qr)
+define_mpn(sbpi1_bdiv_r)
+define_mpn(scan0)
+define_mpn(scan1)
+define_mpn(set_str)
+define_mpn(sqr_basecase)
+define_mpn(sqr_diagonal)
+define_mpn(sqr_diag_addlsh1)
+define_mpn(sub_n)
+define_mpn(sublsh1_n)
+define_mpn(sublsh1_nc)
+define_mpn(sublsh1_n_ip1)
+define_mpn(sublsh1_nc_ip1)
+define_mpn(sublsh2_n)
+define_mpn(sublsh2_nc)
+define_mpn(sublsh2_n_ip1)
+define_mpn(sublsh2_nc_ip1)
+define_mpn(sublsh_n)
+define_mpn(sublsh_nc)
+define_mpn(sublsh_n_ip1)
+define_mpn(sublsh_nc_ip1)
+define_mpn(sqrtrem)
+define_mpn(sub)
+define_mpn(sub_1)
+define_mpn(sub_err1_n)
+define_mpn(sub_err2_n)
+define_mpn(sub_err3_n)
+define_mpn(sub_n)
+define_mpn(sub_nc)
+define_mpn(submul_1)
+define_mpn(submul_1c)
+define_mpn(sec_tabselect)
+define_mpn(umul_ppmm)
+define_mpn(umul_ppmm_r)
+define_mpn(udiv_qrnnd)
+define_mpn(udiv_qrnnd_r)
+define_mpn(xnor_n)
+define_mpn(xor_n)
+
+
+dnl  Defines for C global arrays and variables, with names matching what's
+dnl  used in the C code.
+dnl
+dnl  Notice that GSYM_PREFIX is included, unlike with the function defines
+dnl  above.  Also, "deflit" is used so that something like __clz_tab(%ebx)
+dnl  comes out as __gmpn_clz_tab(%ebx), for the benefit of CPUs with that
+dnl  style assembler syntax.
+
+deflit(__clz_tab,
+m4_assert_defined(`GSYM_PREFIX')
+`GSYM_PREFIX`'MPN(`clz_tab')')
+
+deflit(binvert_limb_table,
+m4_assert_defined(`GSYM_PREFIX')
+`GSYM_PREFIX`'__gmp_binvert_limb_table')
+
+
+dnl  Usage: ASM_START()
+dnl
+dnl  Emit any directives needed once at the start of an assembler file, like
+dnl  ".set noreorder" or whatever.  The default for this is nothing, but
+dnl  it's redefined by CPU specific m4 files.
+
+define(ASM_START)
+
+
+dnl  Usage: ASM_END()
+dnl
+dnl  Emit any directives needed once at the end of an assembler file.  The
+dnl  default for this is nothing, but it's redefined by CPU specific m4 files.
+
+define(ASM_END)
+
+
+dnl  Usage: PROLOGUE(foo[,param])
+dnl         EPILOGUE(foo)
+dnl
+dnl  Emit directives to start or end a function.  GSYM_PREFIX is added by
+dnl  these macros if necessary, so the given "foo" is what the function will
+dnl  be called in C.
+dnl
+dnl  The second parameter to PROLOGUE is used only for some CPUs and should
+dnl  be omitted if not required.
+dnl
+dnl  Nested or overlapping PROLOGUE/EPILOGUE pairs are allowed, if that
+dnl  makes sense for the system.  The name given to EPILOGUE must be a
+dnl  currently open PROLOGUE.
+dnl
+dnl  If only one PROLOGUE is open then the name can be omitted from
+dnl  EPILOGUE.  This is encouraged, since it means the name only has to
+dnl  appear in one place, not two.
+dnl
+dnl  The given name "foo" is not fully quoted here, it will be macro
+dnl  expanded more than once.  This is the way the m4_list macros work, and
+dnl  it also helps the tune/many.pl program do a renaming like
+dnl  -D__gmpn_add_n=mpn_add_n_foo when GSYM_PREFIX is not empty.
+
+define(PROLOGUE,
+m4_assert_numargs_range(1,2)
+`m4_file_seen()dnl
+define(`PROLOGUE_list',m4_list_quote($1,PROLOGUE_list))dnl
+ifelse(`$2',,
+`PROLOGUE_cpu(GSYM_PREFIX`'$1)',
+`PROLOGUE_cpu(GSYM_PREFIX`'$1,`$2')')')
+
+define(EPILOGUE,
+m4_assert_numargs_range(0,1)
+`ifelse(`$1',,
+`ifelse(m4_list_count(PROLOGUE_list),0,
+`m4_error(`no open functions for EPILOGUE
+')',
+`ifelse(m4_list_count(PROLOGUE_list),1,
+`EPILOGUE_internal(PROLOGUE_current_function)',
+`m4_error(`more than one open function for EPILOGUE
+')')')',
+`EPILOGUE_internal(`$1')')')
+
+define(EPILOGUE_internal,
+m4_assert_numargs(1)
+m4_assert_defined(`EPILOGUE_cpu')
+`ifelse(m4_list_find($1,PROLOGUE_list),0,
+`m4_error(`EPILOGUE without PROLOGUE: $1
+')')dnl
+define(`PROLOGUE_list',m4_list_quote(m4_list_remove($1,PROLOGUE_list)))dnl
+EPILOGUE_cpu(GSYM_PREFIX`$1')')
+
+dnl  Currently open PROLOGUEs, as a comma-separated list.
+define(PROLOGUE_list)
+
+
+dnl  Called: PROLOGUE_check(list,...)
+dnl  Check there's no remaining open PROLOGUEs at the end of input.
+define(PROLOGUE_check,
+`ifelse($1,,,
+`m4_error(`no EPILOGUE for: $1
+')dnl
+PROLOGUE_check(shift($@))')')
+
+m4wrap_prepend(`PROLOGUE_check(PROLOGUE_list)')
+
+
+dnl  Usage: PROLOGUE_current_function
+dnl
+dnl  This macro expands to the current PROLOGUE/EPILOGUE function, or the
+dnl  most recent PROLOGUE if such pairs are nested or overlapped.
+
+define(PROLOGUE_current_function,
+m4_assert_numargs(-1)
+`m4_list_first(PROLOGUE_list)')
+
+
+dnl  Usage: PROLOGUE_cpu(GSYM_PREFIX`'foo[,param])
+dnl         EPILOGUE_cpu(GSYM_PREFIX`'foo)
+dnl
+dnl  These macros hold the CPU-specific parts of PROLOGUE and EPILOGUE.
+dnl  Both are called with the function name, with GSYM_PREFIX already
+dnl  prepended.
+dnl
+dnl  The definitions here are something typical and sensible, but CPU or
+dnl  system specific m4 files should redefine them as necessary.  The
+dnl  optional extra parameter to PROLOGUE_cpu is not expected and not
+dnl  accepted here.
+
+define(PROLOGUE_cpu,
+m4_assert_numargs(1)
+`	TEXT
+	ALIGN(8)
+	GLOBL	`$1' GLOBL_ATTR
+	TYPE(`$1',`function')
+`$1'LABEL_SUFFIX')
+
+define(EPILOGUE_cpu,
+`	SIZE(`$1',.-`$1')')
+
+
+dnl  Usage: L(name)
+dnl
+dnl  Generate a local label with the given name.  This is simply a
+dnl  convenient way to add LSYM_PREFIX.
+dnl
+dnl  LSYM_PREFIX might be L$, so defn() must be used to quote it or the L
+dnl  will expand again as the L macro, making an infinite recursion.
+
+define(`L',
+m4_assert_numargs(1)
+`defn(`LSYM_PREFIX')$1')
+
+
+dnl  Usage: LDEF(name)
+dnl
+dnl  Generate a directive to define a local label.
+dnl
+dnl  On systems with a fixed syntax for defining labels there's no need to
+dnl  use this macro, it's only meant for systems where the syntax varies,
+dnl  like hppa which is "L(foo):" with gas, but just "L(foo)" in column 0
+dnl  with the system `as'.
+dnl
+dnl  The extra `' after LABEL_SUFFIX avoids any chance of a following
+dnl  "(...)"  being interpreted as an argument list.  Not that it'd be
+dnl  sensible to write anything like that after an LDEF(), but just in case.
+
+define(LDEF,
+m4_assert_numargs(1)
+m4_assert_defined(`LABEL_SUFFIX')
+`L(`$1')`'LABEL_SUFFIX`'')
+
+
+dnl  Usage: INT32(label,value)
+dnl         INT64(label,first,second)
+
+define(`INT32',
+m4_assert_defined(`W32')
+`	ALIGN(4)
+LDEF(`$1')
+	W32	$2')
+
+define(`INT64',
+m4_assert_defined(`W32')
+`	ALIGN(8)
+LDEF(`$1')
+	W32	$2
+	W32	$3')
+
+
+dnl  Usage: ALIGN(bytes)
+dnl
+dnl  Emit a ".align" directive.  The alignment is specified in bytes, and
+dnl  will normally need to be a power of 2.  The actual ".align" generated
+dnl  is either bytes or logarithmic according to what ./configure finds the
+dnl  assembler needs.
+dnl
+dnl  If ALIGN_FILL_0x90 is defined and equal to "yes", then ", 0x90" is
+dnl  appended.  This is for x86, see mpn/x86/README.
+
+define(ALIGN,
+m4_assert_numargs(1)
+m4_assert_defined(`ALIGN_LOGARITHMIC')
+`.align	ifelse(ALIGN_LOGARITHMIC,yes,`m4_log2($1)',`eval($1)')dnl
+ifelse(ALIGN_FILL_0x90,yes,`, 0x90')')
+
+
+dnl  Usage: MULFUNC_PROLOGUE(function function...)
+dnl
+dnl  A dummy macro which is grepped for by ./configure to know what
+dnl  functions a multi-function file is providing.  Use this if there aren't
+dnl  explicit PROLOGUE()s for each possible function.
+dnl
+dnl  Multiple MULFUNC_PROLOGUEs can be used, or just one with the function
+dnl  names separated by spaces.
+
+define(`MULFUNC_PROLOGUE',
+m4_assert_numargs(1)
+)
+
+
+dnl  Usage: NAILS_SUPPORT(spec spec ...)
+dnl
+dnl  A dummy macro which is grepped for by ./configure to know what nails
+dnl  are supported in an asm file.
+dnl
+dnl  Ranges can be given, or just individual values.  Multiple values or
+dnl  ranges can be given, separated by spaces.  Multiple NAILS_SUPPORT
+dnl  declarations work too.  Some examples,
+dnl
+dnl         NAILS_SUPPORT(1-20)
+dnl         NAILS_SUPPORT(1 6 9-12)
+dnl         NAILS_SUPPORT(1-10 16-20)
+
+define(NAILS_SUPPORT,
+m4_assert_numargs(1)
+)
+
+
+dnl  Usage: ABI_SUPPORT(abi)
+dnl
+dnl  A dummy macro which is grepped for by ./configure to know what ABIs
+dnl  are supported in an asm file.
+dnl
+dnl  If multiple non-standard ABIs are supported, several ABI_SUPPORT
+dnl  declarations should be used:
+dnl
+dnl         ABI_SUPPORT(FOOABI)
+dnl         ABI_SUPPORT(BARABI)
+
+define(ABI_SUPPORT,
+m4_assert_numargs(1)
+)
+
+
+dnl  Usage: GMP_NUMB_MASK
+dnl
+dnl  A bit mask for the number part of a limb.  Eg. with 6 bit nails in a
+dnl  32 bit limb, GMP_NUMB_MASK would be 0x3ffffff.
+
+define(GMP_NUMB_MASK,
+m4_assert_numargs(-1)
+m4_assert_defined(`GMP_NUMB_BITS')
+`m4_hex_lowmask(GMP_NUMB_BITS)')
+
+
+dnl  Usage: m4append(`variable',`value-to-append')
+
+define(`m4append',
+`define(`$1',  defn(`$1')`$2')
+'
+)
+
+divert`'dnl
diff --git a/third_party/gmp/mpn/cpp-ccas b/third_party/gmp/mpn/cpp-ccas
new file mode 100755
index 0000000..25f7cdc
--- /dev/null
+++ b/third_party/gmp/mpn/cpp-ccas
@@ -0,0 +1,118 @@
+#!/bin/sh
+#
+# A helper script for Makeasm.am .S.lo rule.
+
+# Copyright 2001 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+
+# Usage: cpp-cc --cpp=CPP CC ... file.S ...
+#
+# Process file.S with the given CPP command plus any -D options in the
+# rest of the arguments, then assemble with the given CC plus all
+# arguments.
+#
+# The CPP command must be in a single --cpp= argument, and will be
+# split on whitespace.  It should include -I options required.
+#
+# When CC is invoked, file.S is replaced with a temporary .s file
+# which is the CPP output.
+#
+# Any lines starting with "#" are removed from the CPP output, usually
+# these will be #line and #file markers from CPP, but they might also
+# be comments from the .S.
+#
+# To allow parallel builds, the temp file name is based on the .S file
+# name, which will be the output object filename for all uses we put
+# this script to.
+
+CPP=
+CPPDEFS=
+CC=
+S=
+SEEN_O=no
+
+for i in "$@"; do
+  case $i in
+    --cpp=*)
+      CPP=`echo "$i" | sed 's/^--cpp=//'`
+      ;;
+    -D*)
+      CPPDEFS="$CPPDEFS $i"
+      CC="$CC $i"
+      ;;
+    *.S)
+      if test -n "$S"; then
+        echo "Only one .S file permitted"
+        exit 1
+      fi
+      BASENAME=`echo "$i" | sed -e 's/\.S$//' -e 's/^.*[\\/:]//'`
+      S=$i
+      TMP_I=tmp-$BASENAME.i
+      TMP_S=tmp-$BASENAME.s
+      CC="$CC $TMP_S"
+      ;;
+    -o)
+      SEEN_O=yes
+      CC="$CC $i"
+      ;;
+    *)
+      CC="$CC $i"
+      ;;
+  esac
+done
+
+if test -z "$CPP"; then
+  echo "No --cpp specified"
+  exit 1
+fi
+
+if test -z "$S"; then
+  echo "No .S specified"
+  exit 1
+fi
+
+# Libtool adds it's own -o when sending output to .libs/foo.o, but not
+# when just wanting foo.o in the current directory.  We need an
+# explicit -o in both cases since we're assembling tmp-foo.s.
+#
+if test $SEEN_O = no; then
+  CC="$CC -o $BASENAME.o"
+fi
+
+echo "$CPP $CPPDEFS $S >$TMP_I"
+$CPP $CPPDEFS $S >$TMP_I || exit
+
+echo "grep -v '^#' $TMP_I >$TMP_S"
+grep -v '^#' $TMP_I >$TMP_S
+
+echo "$CC"
+$CC || exit
+
+# Comment this out to preserve .s intermediates
+rm -f $TMP
diff --git a/third_party/gmp/mpn/cray/README b/third_party/gmp/mpn/cray/README
new file mode 100644
index 0000000..3a347d2
--- /dev/null
+++ b/third_party/gmp/mpn/cray/README
@@ -0,0 +1,121 @@
+Copyright 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.
+
+
+
+
+
+
+The code in this directory works for Cray vector systems such as C90,
+J90, T90 (both the CFP variant and the IEEE variant) and SV1.  (For
+the T3E and T3D systems, see the `alpha' subdirectory at the same
+level as the directory containing this file.)
+
+The cfp subdirectory is for systems utilizing the traditional Cray
+floating-point format, and the ieee subdirectory is for the newer
+systems that use the IEEE floating-point format.
+
+There are several issues that reduces speed on Cray systems.  For
+systems with cfp floating point, the main obstacle is the forming of
+128-bit products.  For IEEE systems, adding, and in particular
+computing carry is the main issue.  There are no vectorizing
+unsigned-less-than instructions, and the sequence that implement that
+operation is very long.
+
+Shifting is the only operation that is simple to make fast.  All Cray
+systems have a bitblt instructions (Vi Vj,Vj<Ak and Vi Vj,Vj>Ak) that
+should be really useful.
+
+For best speed for cfp systems, we need a mul_basecase, since that
+reduces the need for carry propagation to a minimum.  Depending on the
+size (vn) of the smaller of the two operands (V), we should split U and V
+in different chunk sizes:
+
+U split in 2 32-bit parts
+V split according to the table:
+parts			4	5	6	7	8
+bits/part		16	13	11	10	8
+max allowed vn		1	8	32	64	256
+number of multiplies	8	10	12	14	16
+peak cycles/limb	4	5	6	7	8
+
+U split in 3 22-bit parts
+V split according to the table:
+parts			3	4	5
+bits/part		22	16	13
+max allowed vn		16	1024	8192
+number of multiplies	9	12	15
+peak cycles/limb	4.5	6	7.5
+
+U split in 4 16-bit parts
+V split according to the table:
+parts			4
+bits/part		16
+max allowed vn		65536
+number of multiplies	16
+peak cycles/limb	8
+
+(A T90 CPU can accumulate two products per cycle.)
+
+IDEA:
+* Rewrite mpn_add_n:
+    short cy[n + 1];
+    #pragma _CRI ivdep
+      for (i = 0; i < n; i++)
+	{ s = up[i] + vp[i];
+	  rp[i] = s;
+	  cy[i + 1] = s < up[i]; }
+      more_carries = 0;
+    #pragma _CRI ivdep
+      for (i = 1; i < n; i++)
+	{ s = rp[i] + cy[i];
+	  rp[i] = s;
+	  more_carries += s < cy[i]; }
+      cys = 0;
+      if (more_carries)
+	{
+	  cys = rp[1] < cy[1];
+	  for (i = 2; i < n; i++)
+	    { rp[i] += cys;
+	      cys = rp[i] < cys; }
+	}
+      return cys + cy[n];
+
+* Write mpn_add3_n for adding three operands.  First add operands 1
+  and 2, and generate cy[].  Then add operand 3 to the partial result,
+  and accumulate carry into cy[].  Finally propagate carry just like
+  in the new mpn_add_n.
+
+IDEA:
+
+Store fewer bits, perhaps 62, per limb.  That brings mpn_add_n time
+down to 2.5 cycles/limb and mpn_addmul_1 times to 4 cycles/limb.  By
+storing even fewer bits per limb, perhaps 56, it would be possible to
+write a mul_mul_basecase that would run at effectively 1 cycle/limb.
+(Use VM here to better handle the romb-shaped multiply area, perhaps
+rounding operand sizes up to the next power of 2.)
diff --git a/third_party/gmp/mpn/cray/add_n.c b/third_party/gmp/mpn/cray/add_n.c
new file mode 100644
index 0000000..af49159
--- /dev/null
+++ b/third_party/gmp/mpn/cray/add_n.c
@@ -0,0 +1,90 @@
+/* Cray PVP mpn_add_n -- add two limb vectors and store their sum in a third
+   limb vector.
+
+Copyright 1996, 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+/* This code runs at 4 cycles/limb.  It may be possible to bring it down
+   to 3 cycles/limb.  */
+
+#include "gmp-impl.h"
+
+mp_limb_t
+mpn_add_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n)
+{
+  mp_limb_t cy[n];
+  mp_limb_t a, b, r, s0, c0, c1;
+  mp_size_t i;
+  int more_carries;
+
+  /* Main add loop.  Generate a raw output sum in rp[] and a carry vector
+     in cy[].  */
+#pragma _CRI ivdep
+  for (i = 0; i < n; i++)
+    {
+      a = up[i];
+      b = vp[i];
+      s0 = a + b;
+      rp[i] = s0;
+      c0 = ((a & b) | ((a | b) & ~s0)) >> 63;
+      cy[i] = c0;
+    }
+  /* Carry add loop.  Add the carry vector cy[] to the raw sum rp[] and
+     store the new sum back to rp[0].  If this generates further carry, set
+     more_carries.  */
+  more_carries = 0;
+#pragma _CRI ivdep
+  for (i = 1; i < n; i++)
+    {
+      r = rp[i];
+      c0 = cy[i - 1];
+      s0 = r + c0;
+      rp[i] = s0;
+      c0 = (r & ~s0) >> 63;
+      more_carries += c0;
+    }
+  /* If that second loop generated carry, handle that in scalar loop.  */
+  if (more_carries)
+    {
+      mp_limb_t cyrec = 0;
+      /* Look for places where rp[k] is zero and cy[k-1] is non-zero.
+	 These are where we got a recurrency carry.  */
+      for (i = 1; i < n; i++)
+	{
+	  r = rp[i];
+	  c0 = (r == 0 && cy[i - 1] != 0);
+	  s0 = r + cyrec;
+	  rp[i] = s0;
+	  c1 = (r & ~s0) >> 63;
+	  cyrec = c0 | c1;
+	}
+      return cyrec | cy[n - 1];
+    }
+
+  return cy[n - 1];
+}
diff --git a/third_party/gmp/mpn/cray/cfp/addmul_1.c b/third_party/gmp/mpn/cray/cfp/addmul_1.c
new file mode 100644
index 0000000..9c7f383
--- /dev/null
+++ b/third_party/gmp/mpn/cray/cfp/addmul_1.c
@@ -0,0 +1,48 @@
+/* mpn_addmul_1 for Cray PVP.
+
+Copyright 1996, 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+mp_limb_t
+mpn_addmul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t limb)
+{
+  mp_limb_t p0[n], p1[n], tp[n];
+  mp_limb_t cy_limb;
+
+  GMPN_MULWW (p1, p0, up, &n, &limb);
+  cy_limb = mpn_add_n (tp, rp, p0, n);
+  rp[0] = tp[0];
+  if (n != 1)
+    cy_limb += mpn_add_n (rp + 1, tp + 1, p1, n - 1);
+  cy_limb += p1[n - 1];
+
+  return cy_limb;
+}
diff --git a/third_party/gmp/mpn/cray/cfp/mul_1.c b/third_party/gmp/mpn/cray/cfp/mul_1.c
new file mode 100644
index 0000000..33a6a05
--- /dev/null
+++ b/third_party/gmp/mpn/cray/cfp/mul_1.c
@@ -0,0 +1,47 @@
+/* mpn_mul_1 for Cray PVP.
+
+Copyright 1996, 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+mp_limb_t
+mpn_mul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t limb)
+{
+  mp_limb_t p0[n], p1[n];
+  mp_limb_t cy_limb;
+
+  GMPN_MULWW (p1, p0, up, &n, &limb);
+  rp[0] = p0[0];
+  cy_limb = p1[n - 1];
+  if (n != 1)
+    cy_limb += mpn_add_n (rp + 1, p0 + 1, p1, n - 1);
+
+  return cy_limb;
+}
diff --git a/third_party/gmp/mpn/cray/cfp/mulwwc90.s b/third_party/gmp/mpn/cray/cfp/mulwwc90.s
new file mode 100644
index 0000000..71d2285
--- /dev/null
+++ b/third_party/gmp/mpn/cray/cfp/mulwwc90.s
@@ -0,0 +1,254 @@
+*    Helper for mpn_mul_1, mpn_addmul_1, and mpn_submul_1 for Cray PVP.
+
+*    Copyright 1996, 2000 Free Software Foundation, Inc.
+*    This file is generated from mulww.f in this same directory.
+
+*  This file is part of the GNU MP Library.
+*
+*  The GNU MP Library is free software; you can redistribute it and/or modify
+*  it under the terms of either:
+*
+*    * the GNU Lesser General Public License as published by the Free
+*      Software Foundation; either version 3 of the License, or (at your
+*      option) any later version.
+*
+*  or
+*
+*    * the GNU General Public License as published by the Free Software
+*      Foundation; either version 2 of the License, or (at your option) any
+*      later version.
+*
+*  or both in parallel, as here.
+*
+*  The GNU MP Library is distributed in the hope that it will be useful, but
+*  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+*  for more details.
+*
+*  You should have received copies of the GNU General Public License and the
+*  GNU Lesser General Public License along with the GNU MP Library.  If not,
+*  see https://www.gnu.org/licenses/.
+
+            IDENT           GMPN_MULWW
+**********************************************
+*      Assemble with Cal Version 2.0         *
+*                                            *
+* Generated by CFT77   6.0.4.19              *
+*           on 06/27/00 at 04:34:13          *
+*                                            *
+**********************************************
+* ALLOW UNDERSCORES IN IDENTIFIERS
+            EDIT            OFF
+            FORMAT          NEW
+@DATA       SECTION         DATA,CM
+@DATA       =               W.*
+            CON             O'0000000000040000000000
+            CON             O'0435152404713723252514
+            CON             O'0535270000000000000000
+            CON             O'0000000000000001200012
+            VWD             32/0,32/P.GMPN_MULWW
+            CON             O'0014003000000000001416
+            CON             O'0000000000000000000011
+            CON             O'0000000000000000000215
+            BSSZ            1
+@CODE       SECTION         CODE
+@CODE       =               P.*
+L3          =               P.*
+            A0              A6
+            A5              6
+            B03,A5          0,A0
+            A0              A1+A2
+            A5              1
+            0,A0            T00,A5
+            B02             A2
+            B66             A3
+            B01             A6
+            A7              P.L4
+            B00             A7
+            A6              @DATA
+            J               $STKOFEN
+GMPN_MULWW  =               P.*
+            A0              @DATA+3
+            B77             A0
+            A1              13
+            A0              B66
+            A2              B66
+            A4              B67
+            0,A0            B77,A1
+            A7              782
+            A3              A2+A7
+            A0              A4-A3
+            JAM             L3
+            A0              A6
+            A5              6
+            B03,A5          0,A0
+            A0              A1+A2
+            A5              1
+            0,A0            T00,A5
+            B02             A2
+            B66             A3
+            B01             A6
+L4          =               P.*
+            A7              B07
+            S7              0,A7
+            A6              B10
+            S6              0,A6
+            S5              1
+            S4              <22
+            S7              S7-S5
+            S5              #S7
+            T00             S6
+            S6              S6>22
+            S7              T00
+            S7              S7>44
+            S3              T00
+            S3              S3&S4
+            S6              S6&S4
+            S7              S7&S4
+            S3              S3<24
+            S6              S6<24
+            S7              S7<24
+            S0              S5
+            S4              S5
+            S1              S6
+            S2              S3
+            S3              S7
+            JSP             L5
+L6          =               P.*
+            S7              -S4
+            A2              S7
+            VL              A2
+            A3              B06
+            A5              B05
+            A4              B04
+            A1              VL
+            A2              S4
+L7          =               P.*
+            A0              A3
+            VL              A1
+            V7              ,A0,1
+            B11             A5
+            A7              22
+            B12             A4
+            V6              V7>A7
+            B13             A3
+            S7              <22
+            A3              B02
+            V5              S7&V6
+            A6              24
+            V4              V5<A6
+            V3              S1*FV4
+            V2              S7&V7
+            V1              V2<A6
+            V0              S3*FV1
+            V6              V0+V3
+            A5              44
+            V5              V7>A5
+            V2              S1*FV1
+            V3              S7&V5
+            A0              14
+            B77             A0
+            A4              B77
+            A0              A4+A3
+            ,A0,1           V2
+            V0              V3<A6
+            V7              S2*FV1
+            A4              142
+            A0              A4+A3
+            ,A0,1           V7
+            V5              V7>A7
+            V2              S2*FV0
+            V3              V6+V2
+            S7              <20
+            V1              S7&V3
+            A4              270
+            A0              A4+A3
+            ,A0,1           V0
+            A4              14
+            A0              A4+A3
+            V7              ,A0,1
+            V6              V1<A7
+            V2              S2*FV4
+            V0              V7+V2
+            S7              <42
+            V1              S7&V0
+            A4              398
+            A0              A4+A3
+            ,A0,1           V0
+            V7              S3*FV4
+            V2              V5+V1
+            V0              V3<A5
+            A5              526
+            A0              A5+A3
+            ,A0,1           V0
+            A5              270
+            A0              A5+A3
+            V4              ,A0,1
+            V5              V2+V6
+            A5              20
+            V1              V3>A5
+            V0              S1*FV4
+            A5              654
+            A0              A5+A3
+            ,A0,1           V1
+            V6              V7+V0
+            A5              2
+            V2              V6<A5
+            V3              S3*FV4
+            A5              142
+            A0              A5+A3
+            V1              ,A0,1
+            A5              526
+            A0              A5+A3
+            V7              ,A0,1
+            V0              V1+V7
+            V6              V3<A6
+            V4              V6+V2
+            A6              42
+            V7              V5>A6
+            A5              654
+            CPW
+            A0              A5+A3
+            V1              ,A0,1
+            A5              398
+            A0              A5+A3
+            V3              ,A0,1
+            V6              V4+V1
+            V2              V3>A6
+            V5              V6+V2
+            A6              B12
+            V4              V3<A7
+            A7              B13
+            A3              A7+A1
+            A7              B11
+            A5              A7+A1
+            A4              A6+A1
+            A7              A2+A1
+            A0              A2+A1
+            A2              128
+            B13             A0
+            V1              V0+V4
+            A0              B11
+            ,A0,1           V1
+            V6              V5+V7
+            A0              A6
+            ,A0,1           V6
+            A0              B13
+            A1              A2
+            A2              A7
+            JAN             L7
+L8          =               P.*
+L5          =               P.*
+            S1              0
+            A0              B02
+            A2              B02
+            A1              13
+            B66             A0
+            B77,A1          0,A0
+            A0              A2+A1
+            A1              1
+            T00,A1          0,A0
+            J               B00
+            EXT             $STKOFEN:p
+            ENTRY           GMPN_MULWW
+            END
diff --git a/third_party/gmp/mpn/cray/cfp/mulwwj90.s b/third_party/gmp/mpn/cray/cfp/mulwwj90.s
new file mode 100644
index 0000000..1c2c7cd
--- /dev/null
+++ b/third_party/gmp/mpn/cray/cfp/mulwwj90.s
@@ -0,0 +1,253 @@
+*    Helper for mpn_mul_1, mpn_addmul_1, and mpn_submul_1 for Cray PVP.
+
+*    Copyright 1996, 2000 Free Software Foundation, Inc.
+*    This file is generated from mulww.f in this same directory.
+
+*  This file is part of the GNU MP Library.
+*
+*  The GNU MP Library is free software; you can redistribute it and/or modify
+*  it under the terms of either:
+*
+*    * the GNU Lesser General Public License as published by the Free
+*      Software Foundation; either version 3 of the License, or (at your
+*      option) any later version.
+*
+*  or
+*
+*    * the GNU General Public License as published by the Free Software
+*      Foundation; either version 2 of the License, or (at your option) any
+*      later version.
+*
+*  or both in parallel, as here.
+*
+*  The GNU MP Library is distributed in the hope that it will be useful, but
+*  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+*  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+*  for more details.
+*
+*  You should have received copies of the GNU General Public License and the
+*  GNU Lesser General Public License along with the GNU MP Library.  If not,
+*  see https://www.gnu.org/licenses/.
+
+            IDENT           GMPN_MULWW
+**********************************************
+*      Assemble with Cal Version 2.0         *
+*                                            *
+* Generated by CFT77   6.0.4.19              *
+*           on 06/27/00 at 04:34:13          *
+*                                            *
+**********************************************
+* ALLOW UNDERSCORES IN IDENTIFIERS
+            EDIT            OFF
+            FORMAT          NEW
+@DATA       SECTION         DATA,CM
+@DATA       =               W.*
+            CON             O'0000000000040000000000
+            CON             O'0435152404713723252514
+            CON             O'0535270000000000000000
+            CON             O'0000000000000001200012
+            VWD             32/0,32/P.GMPN_MULWW
+            CON             O'0014003000000000001416
+            CON             O'0000000000000000000011
+            CON             O'0000000000000000000215
+            BSSZ            1
+@CODE       SECTION         CODE
+@CODE       =               P.*
+L3          =               P.*
+            A0              A6
+            A5              6
+            B03,A5          0,A0
+            A0              A1+A2
+            A5              1
+            0,A0            T00,A5
+            B02             A2
+            B66             A3
+            B01             A6
+            A7              P.L4
+            B00             A7
+            A6              @DATA
+            J               $STKOFEN
+GMPN_MULWW  =               P.*
+            A0              @DATA+3
+            B77             A0
+            A1              13
+            A0              B66
+            A2              B66
+            A4              B67
+            0,A0            B77,A1
+            A7              782
+            A3              A2+A7
+            A0              A4-A3
+            JAM             L3
+            A0              A6
+            A5              6
+            B03,A5          0,A0
+            A0              A1+A2
+            A5              1
+            0,A0            T00,A5
+            B02             A2
+            B66             A3
+            B01             A6
+L4          =               P.*
+            A7              B07
+            S7              0,A7
+            A6              B10
+            S6              0,A6
+            S5              1
+            S4              <22
+            S7              S7-S5
+            S5              #S7
+            T00             S6
+            S6              S6>22
+            S7              T00
+            S7              S7>44
+            S3              T00
+            S3              S3&S4
+            S6              S6&S4
+            S7              S7&S4
+            S3              S3<24
+            S6              S6<24
+            S7              S7<24
+            S0              S5
+            S4              S5
+            S1              S6
+            S2              S3
+            S3              S7
+            JSP             L5
+L6          =               P.*
+            S7              -S4
+            A2              S7
+            VL              A2
+            A3              B06
+            A5              B05
+            A4              B04
+            A1              VL
+            A2              S4
+L7          =               P.*
+            A0              A3
+            VL              A1
+            V7              ,A0,1
+            B11             A5
+            A7              22
+            B12             A4
+            V6              V7>A7
+            B13             A3
+            S7              <22
+            A3              B02
+            V5              S7&V6
+            A6              24
+            V4              V5<A6
+            V3              S1*FV4
+            V2              S7&V7
+            V1              V2<A6
+            V0              S3*FV1
+            V6              V0+V3
+            A5              44
+            V5              V7>A5
+            V2              S1*FV1
+            V3              S7&V5
+            A0              14
+            B77             A0
+            A4              B77
+            A0              A4+A3
+            ,A0,1           V2
+            V0              V3<A6
+            V7              S2*FV1
+            A4              142
+            A0              A4+A3
+            ,A0,1           V7
+            V5              V7>A7
+            V2              S2*FV0
+            V3              V6+V2
+            S7              <20
+            V1              S7&V3
+            A4              270
+            A0              A4+A3
+            ,A0,1           V0
+            A4              14
+            A0              A4+A3
+            V7              ,A0,1
+            V6              V1<A7
+            V2              S2*FV4
+            V0              V7+V2
+            S7              <42
+            V1              S7&V0
+            A4              398
+            A0              A4+A3
+            ,A0,1           V0
+            V7              S3*FV4
+            V2              V5+V1
+            V0              V3<A5
+            A5              526
+            A0              A5+A3
+            ,A0,1           V0
+            A5              270
+            A0              A5+A3
+            V4              ,A0,1
+            V5              V2+V6
+            A5              20
+            V1              V3>A5
+            V0              S1*FV4
+            A5              654
+            A0              A5+A3
+            ,A0,1           V1
+            V6              V7+V0
+            A5              2
+            V2              V6<A5
+            V3              S3*FV4
+            A5              142
+            A0              A5+A3
+            V1              ,A0,1
+            A5              526
+            A0              A5+A3
+            V7              ,A0,1
+            V0              V1+V7
+            V6              V3<A6
+            V4              V6+V2
+            A6              42
+            V7              V5>A6
+            A5              654
+            A0              A5+A3
+            V1              ,A0,1
+            A5              398
+            A0              A5+A3
+            V3              ,A0,1
+            V6              V4+V1
+            V2              V3>A6
+            V5              V6+V2
+            A6              B12
+            V4              V3<A7
+            A7              B13
+            A3              A7+A1
+            A7              B11
+            A5              A7+A1
+            A4              A6+A1
+            A7              A2+A1
+            A0              A2+A1
+            A2              64
+            B13             A0
+            V1              V0+V4
+            A0              B11
+            ,A0,1           V1
+            V6              V5+V7
+            A0              A6
+            ,A0,1           V6
+            A0              B13
+            A1              A2
+            A2              A7
+            JAN             L7
+L8          =               P.*
+L5          =               P.*
+            S1              0
+            A0              B02
+            A2              B02
+            A1              13
+            B66             A0
+            B77,A1          0,A0
+            A0              A2+A1
+            A1              1
+            T00,A1          0,A0
+            J               B00
+            EXT             $STKOFEN:p
+            ENTRY           GMPN_MULWW
+            END
diff --git a/third_party/gmp/mpn/cray/cfp/submul_1.c b/third_party/gmp/mpn/cray/cfp/submul_1.c
new file mode 100644
index 0000000..622c275
--- /dev/null
+++ b/third_party/gmp/mpn/cray/cfp/submul_1.c
@@ -0,0 +1,48 @@
+/* mpn_submul_1 for Cray PVP.
+
+Copyright 1996, 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+mp_limb_t
+mpn_submul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t limb)
+{
+  mp_limb_t p0[n], p1[n], tp[n];
+  mp_limb_t cy_limb;
+
+  GMPN_MULWW (p1, p0, up, &n, &limb);
+  cy_limb = mpn_sub_n (tp, rp, p0, n);
+  rp[0] = tp[0];
+  if (n != 1)
+    cy_limb += mpn_sub_n (rp + 1, tp + 1, p1, n - 1);
+  cy_limb += p1[n - 1];
+
+  return cy_limb;
+}
diff --git a/third_party/gmp/mpn/cray/gmp-mparam.h b/third_party/gmp/mpn/cray/gmp-mparam.h
new file mode 100644
index 0000000..1baed1e
--- /dev/null
+++ b/third_party/gmp/mpn/cray/gmp-mparam.h
@@ -0,0 +1,74 @@
+/* Cray T90 CFP gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 1996, 2000-2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+/* T90 Unicos 10.0.X in CFP mode */
+
+/* Generated by tuneup.c, 2004-02-07, system compiler */
+
+#define MUL_TOOM22_THRESHOLD             71
+#define MUL_TOOM33_THRESHOLD            131
+
+#define SQR_BASECASE_THRESHOLD           32
+#define SQR_TOOM2_THRESHOLD             199
+#define SQR_TOOM3_THRESHOLD             363
+
+#define DIV_SB_PREINV_THRESHOLD           0  /* (preinv always) */
+#define DIV_DC_THRESHOLD                996
+#define POWM_THRESHOLD                  601
+
+#define HGCD_THRESHOLD                  964
+#define GCD_ACCEL_THRESHOLD               3
+#define GCD_DC_THRESHOLD               2874
+#define JACOBI_BASE_METHOD                2
+
+#define DIVREM_1_NORM_THRESHOLD           0  /* preinv always */
+#define DIVREM_1_UNNORM_THRESHOLD         0  /* always */
+#define MOD_1_NORM_THRESHOLD              0  /* always */
+#define MOD_1_UNNORM_THRESHOLD            0  /* always */
+#define USE_PREINV_DIVREM_1               1  /* preinv always */
+#define USE_PREINV_MOD_1                  1  /* preinv always */
+#define DIVREM_2_THRESHOLD                0  /* preinv always */
+#define DIVEXACT_1_THRESHOLD              0  /* always */
+#define MODEXACT_1_ODD_THRESHOLD          0  /* always */
+
+#define GET_STR_DC_THRESHOLD             26
+#define GET_STR_PRECOMPUTE_THRESHOLD     42
+#define SET_STR_THRESHOLD            145756
+
+#define MUL_FFT_TABLE  { 272, 544, 1088, 2304, 5120, 12288, 49152, 0 }
+#define MUL_FFT_MODF_THRESHOLD          200
+#define MUL_FFT_THRESHOLD              1664
+
+#define SQR_FFT_TABLE  { 1008, 2080, 3904, 7936, 17408, 45056, 0 }
+#define SQR_FFT_MODF_THRESHOLD          600
+#define SQR_FFT_THRESHOLD              2976
diff --git a/third_party/gmp/mpn/cray/hamdist.c b/third_party/gmp/mpn/cray/hamdist.c
new file mode 100644
index 0000000..e7f177a
--- /dev/null
+++ b/third_party/gmp/mpn/cray/hamdist.c
@@ -0,0 +1,42 @@
+/* Cray mpn_hamdist -- hamming distance count.
+
+Copyright 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <intrinsics.h>
+#include "gmp-impl.h"
+
+unsigned long int
+mpn_hamdist (mp_srcptr p1, mp_srcptr p2, mp_size_t n)
+{
+  unsigned long int result = 0;
+  mp_size_t i;
+  for (i = 0; i < n; i++)
+    result += _popcnt (p1[i] ^ p2[i]);
+  return result;
+}
diff --git a/third_party/gmp/mpn/cray/ieee/addmul_1.c b/third_party/gmp/mpn/cray/ieee/addmul_1.c
new file mode 100644
index 0000000..ce7dfbb
--- /dev/null
+++ b/third_party/gmp/mpn/cray/ieee/addmul_1.c
@@ -0,0 +1,111 @@
+/* Cray PVP/IEEE mpn_addmul_1 -- multiply a limb vector with a limb and add the
+   result to a second limb vector.
+
+Copyright 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+/* This code runs at just under 9 cycles/limb on a T90.  That is not perfect,
+   mainly due to vector register shortage in the main loop.  Assembly code
+   should bring it down to perhaps 7 cycles/limb.  */
+
+#include <intrinsics.h>
+#include "gmp-impl.h"
+
+mp_limb_t
+mpn_addmul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t vl)
+{
+  mp_limb_t cy[n];
+  mp_limb_t a, b, r, s0, s1, c0, c1;
+  mp_size_t i;
+  int more_carries;
+
+  if (up == rp)
+    {
+      /* The algorithm used below cannot handle overlap.  Handle it here by
+	 making a temporary copy of the source vector, then call ourselves.  */
+      mp_limb_t xp[n];
+      MPN_COPY (xp, up, n);
+      return mpn_addmul_1 (rp, xp, n, vl);
+    }
+
+  a = up[0] * vl;
+  r = rp[0];
+  s0 = a + r;
+  rp[0] = s0;
+  c0 = ((a & r) | ((a | r) & ~s0)) >> 63;
+  cy[0] = c0;
+
+  /* Main multiply loop.  Generate a raw accumulated output product in rp[]
+     and a carry vector in cy[].  */
+#pragma _CRI ivdep
+  for (i = 1; i < n; i++)
+    {
+      a = up[i] * vl;
+      b = _int_mult_upper (up[i - 1], vl);
+      s0 = a + b;
+      c0 = ((a & b) | ((a | b) & ~s0)) >> 63;
+      r = rp[i];
+      s1 = s0 + r;
+      rp[i] = s1;
+      c1 = ((s0 & r) | ((s0 | r) & ~s1)) >> 63;
+      cy[i] = c0 + c1;
+    }
+  /* Carry add loop.  Add the carry vector cy[] to the raw result rp[] and
+     store the new result back to rp[].  */
+  more_carries = 0;
+#pragma _CRI ivdep
+  for (i = 1; i < n; i++)
+    {
+      r = rp[i];
+      c0 = cy[i - 1];
+      s0 = r + c0;
+      rp[i] = s0;
+      c0 = (r & ~s0) >> 63;
+      more_carries += c0;
+    }
+  /* If that second loop generated carry, handle that in scalar loop.  */
+  if (more_carries)
+    {
+      mp_limb_t cyrec = 0;
+      /* Look for places where rp[k] == 0 and cy[k-1] == 1 or
+	 rp[k] == 1 and cy[k-1] == 2.
+	 These are where we got a recurrency carry.  */
+      for (i = 1; i < n; i++)
+	{
+	  r = rp[i];
+	  c0 = r < cy[i - 1];
+	  s0 = r + cyrec;
+	  rp[i] = s0;
+	  c1 = (r & ~s0) >> 63;
+	  cyrec = c0 | c1;
+	}
+      return _int_mult_upper (up[n - 1], vl) + cyrec + cy[n - 1];
+    }
+
+  return _int_mult_upper (up[n - 1], vl) + cy[n - 1];
+}
diff --git a/third_party/gmp/mpn/cray/ieee/gmp-mparam.h b/third_party/gmp/mpn/cray/ieee/gmp-mparam.h
new file mode 100644
index 0000000..1fdc286
--- /dev/null
+++ b/third_party/gmp/mpn/cray/ieee/gmp-mparam.h
@@ -0,0 +1,73 @@
+/* Cray T90 IEEE gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 1996, 2000-2002, 2004 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+/* Generated by tuneup.c, 2004-02-07, system compiler */
+
+#define MUL_TOOM22_THRESHOLD            130
+#define MUL_TOOM33_THRESHOLD            260
+
+#define SQR_BASECASE_THRESHOLD            9  /* karatsuba */
+#define SQR_TOOM2_THRESHOLD               0  /* never sqr_basecase */
+#define SQR_TOOM3_THRESHOLD              34
+
+#define DIV_SB_PREINV_THRESHOLD           0  /* preinv always */
+#define DIV_DC_THRESHOLD                390
+#define POWM_THRESHOLD                  656
+
+#define HGCD_THRESHOLD                  964
+#define GCD_ACCEL_THRESHOLD               3
+#define GCD_DC_THRESHOLD                964
+#define JACOBI_BASE_METHOD                2
+
+#define DIVREM_1_NORM_THRESHOLD           0  /* preinv always */
+#define DIVREM_1_UNNORM_THRESHOLD         0  /* always */
+#define MOD_1_NORM_THRESHOLD              0  /* always */
+#define MOD_1_UNNORM_THRESHOLD            0  /* always */
+#define USE_PREINV_DIVREM_1               1  /* preinv always */
+#define USE_PREINV_MOD_1                  1  /* preinv always */
+#define DIVREM_2_THRESHOLD                0  /* preinv always */
+#define DIVEXACT_1_THRESHOLD              0  /* always */
+#define MODEXACT_1_ODD_THRESHOLD          0  /* always */
+
+#define GET_STR_DC_THRESHOLD             45
+#define GET_STR_PRECOMPUTE_THRESHOLD     77
+#define SET_STR_THRESHOLD            145756
+
+#define MUL_FFT_TABLE  { 1104, 2208, 4416, 8960, 19456, 45056, 0 }
+#define MUL_FFT_MODF_THRESHOLD         1168
+#define MUL_FFT_THRESHOLD              6528
+
+#define SQR_FFT_TABLE  { 368, 736, 1600, 2816, 7168, 12288, 0 }
+#define SQR_FFT_MODF_THRESHOLD          296
+#define SQR_FFT_THRESHOLD              1312
diff --git a/third_party/gmp/mpn/cray/ieee/invert_limb.c b/third_party/gmp/mpn/cray/ieee/invert_limb.c
new file mode 100644
index 0000000..774a27b
--- /dev/null
+++ b/third_party/gmp/mpn/cray/ieee/invert_limb.c
@@ -0,0 +1,127 @@
+/* mpn_invert_limb -- Invert a normalized limb.
+
+Copyright 1991, 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/*
+  This is needed to make configure define HAVE_NATIVE_mpn_invert_limb:
+  PROLOGUE(mpn_invert_limb)
+*/
+
+static const unsigned short int approx_tab[0x100] =
+{
+  /* 0x400, */
+  0x3ff,
+         0x3fc, 0x3f8, 0x3f4, 0x3f0, 0x3ec, 0x3e8, 0x3e4,
+  0x3e0, 0x3dd, 0x3d9, 0x3d5, 0x3d2, 0x3ce, 0x3ca, 0x3c7,
+  0x3c3, 0x3c0, 0x3bc, 0x3b9, 0x3b5, 0x3b2, 0x3ae, 0x3ab,
+  0x3a8, 0x3a4, 0x3a1, 0x39e, 0x39b, 0x397, 0x394, 0x391,
+  0x38e, 0x38b, 0x387, 0x384, 0x381, 0x37e, 0x37b, 0x378,
+  0x375, 0x372, 0x36f, 0x36c, 0x369, 0x366, 0x364, 0x361,
+  0x35e, 0x35b, 0x358, 0x355, 0x353, 0x350, 0x34d, 0x34a,
+  0x348, 0x345, 0x342, 0x340, 0x33d, 0x33a, 0x338, 0x335,
+  0x333, 0x330, 0x32e, 0x32b, 0x329, 0x326, 0x324, 0x321,
+  0x31f, 0x31c, 0x31a, 0x317, 0x315, 0x313, 0x310, 0x30e,
+  0x30c, 0x309, 0x307, 0x305, 0x303, 0x300, 0x2fe, 0x2fc,
+  0x2fa, 0x2f7, 0x2f5, 0x2f3, 0x2f1, 0x2ef, 0x2ec, 0x2ea,
+  0x2e8, 0x2e6, 0x2e4, 0x2e2, 0x2e0, 0x2de, 0x2dc, 0x2da,
+  0x2d8, 0x2d6, 0x2d4, 0x2d2, 0x2d0, 0x2ce, 0x2cc, 0x2ca,
+  0x2c8, 0x2c6, 0x2c4, 0x2c2, 0x2c0, 0x2be, 0x2bc, 0x2bb,
+  0x2b9, 0x2b7, 0x2b5, 0x2b3, 0x2b1, 0x2b0, 0x2ae, 0x2ac,
+  0x2aa, 0x2a8, 0x2a7, 0x2a5, 0x2a3, 0x2a1, 0x2a0, 0x29e,
+  0x29c, 0x29b, 0x299, 0x297, 0x295, 0x294, 0x292, 0x291,
+  0x28f, 0x28d, 0x28c, 0x28a, 0x288, 0x287, 0x285, 0x284,
+  0x282, 0x280, 0x27f, 0x27d, 0x27c, 0x27a, 0x279, 0x277,
+  0x276, 0x274, 0x273, 0x271, 0x270, 0x26e, 0x26d, 0x26b,
+  0x26a, 0x268, 0x267, 0x265, 0x264, 0x263, 0x261, 0x260,
+  0x25e, 0x25d, 0x25c, 0x25a, 0x259, 0x257, 0x256, 0x255,
+  0x253, 0x252, 0x251, 0x24f, 0x24e, 0x24d, 0x24b, 0x24a,
+  0x249, 0x247, 0x246, 0x245, 0x243, 0x242, 0x241, 0x240,
+  0x23e, 0x23d, 0x23c, 0x23b, 0x239, 0x238, 0x237, 0x236,
+  0x234, 0x233, 0x232, 0x231, 0x230, 0x22e, 0x22d, 0x22c,
+  0x22b, 0x22a, 0x229, 0x227, 0x226, 0x225, 0x224, 0x223,
+  0x222, 0x220, 0x21f, 0x21e, 0x21d, 0x21c, 0x21b, 0x21a,
+  0x219, 0x218, 0x216, 0x215, 0x214, 0x213, 0x212, 0x211,
+  0x210, 0x20f, 0x20e, 0x20d, 0x20c, 0x20b, 0x20a, 0x209,
+  0x208, 0x207, 0x206, 0x205, 0x204, 0x203, 0x202, 0x201,
+};
+
+/* iteration: z = 2z-(z**2)d */
+
+mp_limb_t
+mpn_invert_limb (mp_limb_t d)
+{
+  mp_limb_t z, z2l, z2h, tl, th;
+  mp_limb_t xh, xl;
+  mp_limb_t zh, zl;
+
+#if GMP_LIMB_BITS == 32
+  z = approx_tab[(d >> 23) - 0x100] << 6;	/* z < 2^16 */
+
+  z2l = z * z;					/* z2l < 2^32 */
+  umul_ppmm (th, tl, z2l, d);
+  z = (z << 17) - (th << 1);
+#endif
+#if GMP_LIMB_BITS == 64
+  z = approx_tab[(d >> 55) - 0x100] << 6;	/* z < 2^16 */
+
+  z2l = z * z;					/* z2l < 2^32 */
+  th = z2l * (d >> 32);				/* th < 2^64 */
+  z = (z << 17) - (th >> 31);			/* z < 2^32 */
+
+  z2l = z * z;
+  umul_ppmm (th, tl, z2l, d);
+  z = (z << 33) - (th << 1);
+#endif
+
+  umul_ppmm (z2h, z2l, z, z);
+  umul_ppmm (th, tl, z2h, d);
+  umul_ppmm (xh, xl, z2l, d);
+  tl += xh;
+  th += tl < xh;
+  th = (th << 2) | (tl >> GMP_LIMB_BITS - 2);
+  tl = tl << 2;
+  sub_ddmmss (zh, zl, z << 2, 0, th, tl);
+
+  umul_ppmm (xh, xl, d, zh);
+  xh += d;		/* add_ssaaaa (xh, xl, xh, xl, d, 0); */
+  if (~xh != 0)
+    {
+      add_ssaaaa (xh, xl, xh, xl, 0, d);
+      zh++;
+    }
+
+  add_ssaaaa (xh, xl, xh, xl, 0, d);
+  if (xh != 0)
+    zh++;
+
+  return zh;
+}
diff --git a/third_party/gmp/mpn/cray/ieee/mul_1.c b/third_party/gmp/mpn/cray/ieee/mul_1.c
new file mode 100644
index 0000000..40139fb
--- /dev/null
+++ b/third_party/gmp/mpn/cray/ieee/mul_1.c
@@ -0,0 +1,103 @@
+/* Cray PVP/IEEE mpn_mul_1 -- multiply a limb vector with a limb and store the
+   result in a second limb vector.
+
+Copyright 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+/* This code runs at 5 cycles/limb on a T90.  That would probably
+   be hard to improve upon, even with assembly code.  */
+
+#include <intrinsics.h>
+#include "gmp-impl.h"
+
+mp_limb_t
+mpn_mul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t vl)
+{
+  mp_limb_t cy[n];
+  mp_limb_t a, b, r, s0, s1, c0, c1;
+  mp_size_t i;
+  int more_carries;
+
+  if (up == rp)
+    {
+      /* The algorithm used below cannot handle overlap.  Handle it here by
+	 making a temporary copy of the source vector, then call ourselves.  */
+      mp_limb_t xp[n];
+      MPN_COPY (xp, up, n);
+      return mpn_mul_1 (rp, xp, n, vl);
+    }
+
+  a = up[0] * vl;
+  rp[0] = a;
+  cy[0] = 0;
+
+  /* Main multiply loop.  Generate a raw accumulated output product in rp[]
+     and a carry vector in cy[].  */
+#pragma _CRI ivdep
+  for (i = 1; i < n; i++)
+    {
+      a = up[i] * vl;
+      b = _int_mult_upper (up[i - 1], vl);
+      s0 = a + b;
+      c0 = ((a & b) | ((a | b) & ~s0)) >> 63;
+      rp[i] = s0;
+      cy[i] = c0;
+    }
+  /* Carry add loop.  Add the carry vector cy[] to the raw sum rp[] and
+     store the new sum back to rp[0].  */
+  more_carries = 0;
+#pragma _CRI ivdep
+  for (i = 2; i < n; i++)
+    {
+      r = rp[i];
+      c0 = cy[i - 1];
+      s0 = r + c0;
+      rp[i] = s0;
+      c0 = (r & ~s0) >> 63;
+      more_carries += c0;
+    }
+  /* If that second loop generated carry, handle that in scalar loop.  */
+  if (more_carries)
+    {
+      mp_limb_t cyrec = 0;
+      /* Look for places where rp[k] is zero and cy[k-1] is non-zero.
+	 These are where we got a recurrency carry.  */
+      for (i = 2; i < n; i++)
+	{
+	  r = rp[i];
+	  c0 = (r == 0 && cy[i - 1] != 0);
+	  s0 = r + cyrec;
+	  rp[i] = s0;
+	  c1 = (r & ~s0) >> 63;
+	  cyrec = c0 | c1;
+	}
+      return _int_mult_upper (up[n - 1], vl) + cyrec + cy[n - 1];
+    }
+
+  return _int_mult_upper (up[n - 1], vl) + cy[n - 1];
+}
diff --git a/third_party/gmp/mpn/cray/ieee/mul_basecase.c b/third_party/gmp/mpn/cray/ieee/mul_basecase.c
new file mode 100644
index 0000000..72628f7
--- /dev/null
+++ b/third_party/gmp/mpn/cray/ieee/mul_basecase.c
@@ -0,0 +1,107 @@
+/* Cray PVP/IEEE mpn_mul_basecase.
+
+Copyright 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+/* The most critical loop of this code runs at about 5 cycles/limb on a T90.
+   That is not perfect, mainly due to vector register shortage.  */
+
+#include <intrinsics.h>
+#include "gmp-impl.h"
+
+void
+mpn_mul_basecase (mp_ptr rp,
+		  mp_srcptr up, mp_size_t un,
+		  mp_srcptr vp, mp_size_t vn)
+{
+  mp_limb_t cy[un + vn];
+  mp_limb_t vl;
+  mp_limb_t a, b, r, s0, s1, c0, c1;
+  mp_size_t i, j;
+  int more_carries;
+
+  for (i = 0; i < un + vn; i++)
+    {
+      rp[i] = 0;
+      cy[i] = 0;
+    }
+
+#pragma _CRI novector
+  for (j = 0; j < vn; j++)
+    {
+      vl = vp[j];
+
+      a = up[0] * vl;
+      r = rp[j];
+      s0 = a + r;
+      rp[j] = s0;
+      c0 = ((a & r) | ((a | r) & ~s0)) >> 63;
+      cy[j] += c0;
+
+#pragma _CRI ivdep
+      for (i = 1; i < un; i++)
+	{
+	  a = up[i] * vl;
+	  b = _int_mult_upper (up[i - 1], vl);
+	  s0 = a + b;
+	  c0 = ((a & b) | ((a | b) & ~s0)) >> 63;
+	  r = rp[j + i];
+	  s1 = s0 + r;
+	  rp[j + i] = s1;
+	  c1 = ((s0 & r) | ((s0 | r) & ~s1)) >> 63;
+	  cy[j + i] += c0 + c1;
+	}
+      rp[j + un] = _int_mult_upper (up[un - 1], vl);
+    }
+
+  more_carries = 0;
+#pragma _CRI ivdep
+  for (i = 1; i < un + vn; i++)
+    {
+      r = rp[i];
+      c0 = cy[i - 1];
+      s0 = r + c0;
+      rp[i] = s0;
+      c0 = (r & ~s0) >> 63;
+      more_carries += c0;
+    }
+  /* If that second loop generated carry, handle that in scalar loop.  */
+  if (more_carries)
+    {
+      mp_limb_t cyrec = 0;
+      for (i = 1; i < un + vn; i++)
+	{
+	  r = rp[i];
+	  c0 = (r < cy[i - 1]);
+	  s0 = r + cyrec;
+	  rp[i] = s0;
+	  c1 = (r & ~s0) >> 63;
+	  cyrec = c0 | c1;
+	}
+    }
+}
diff --git a/third_party/gmp/mpn/cray/ieee/sqr_basecase.c b/third_party/gmp/mpn/cray/ieee/sqr_basecase.c
new file mode 100644
index 0000000..5bd4e56
--- /dev/null
+++ b/third_party/gmp/mpn/cray/ieee/sqr_basecase.c
@@ -0,0 +1,105 @@
+/* Cray PVP/IEEE mpn_sqr_basecase.
+
+Copyright 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+/* This is just mpn_mul_basecase with trivial modifications.  */
+
+#include <intrinsics.h>
+#include "gmp-impl.h"
+
+void
+mpn_sqr_basecase (mp_ptr rp,
+		  mp_srcptr up, mp_size_t un)
+{
+  mp_limb_t cy[un + un];
+  mp_limb_t ul;
+  mp_limb_t a, b, r, s0, s1, c0, c1;
+  mp_size_t i, j;
+  int more_carries;
+
+  for (i = 0; i < un + un; i++)
+    {
+      rp[i] = 0;
+      cy[i] = 0;
+    }
+
+#pragma _CRI novector
+  for (j = 0; j < un; j++)
+    {
+      ul = up[j];
+
+      a = up[0] * ul;
+      r = rp[j];
+      s0 = a + r;
+      rp[j] = s0;
+      c0 = ((a & r) | ((a | r) & ~s0)) >> 63;
+      cy[j] += c0;
+
+#pragma _CRI ivdep
+      for (i = 1; i < un; i++)
+	{
+	  a = up[i] * ul;
+	  b = _int_mult_upper (up[i - 1], ul);
+	  s0 = a + b;
+	  c0 = ((a & b) | ((a | b) & ~s0)) >> 63;
+	  r = rp[j + i];
+	  s1 = s0 + r;
+	  rp[j + i] = s1;
+	  c1 = ((s0 & r) | ((s0 | r) & ~s1)) >> 63;
+	  cy[j + i] += c0 + c1;
+	}
+      rp[j + un] = _int_mult_upper (up[un - 1], ul);
+    }
+
+  more_carries = 0;
+#pragma _CRI ivdep
+  for (i = 1; i < un + un; i++)
+    {
+      r = rp[i];
+      c0 = cy[i - 1];
+      s0 = r + c0;
+      rp[i] = s0;
+      c0 = (r & ~s0) >> 63;
+      more_carries += c0;
+    }
+  /* If that second loop generated carry, handle that in scalar loop.  */
+  if (more_carries)
+    {
+      mp_limb_t cyrec = 0;
+      for (i = 1; i < un + un; i++)
+	{
+	  r = rp[i];
+	  c0 = (r < cy[i - 1]);
+	  s0 = r + cyrec;
+	  rp[i] = s0;
+	  c1 = (r & ~s0) >> 63;
+	  cyrec = c0 | c1;
+	}
+    }
+}
diff --git a/third_party/gmp/mpn/cray/ieee/submul_1.c b/third_party/gmp/mpn/cray/ieee/submul_1.c
new file mode 100644
index 0000000..2b3ca21
--- /dev/null
+++ b/third_party/gmp/mpn/cray/ieee/submul_1.c
@@ -0,0 +1,111 @@
+/* Cray PVP/IEEE mpn_submul_1 -- multiply a limb vector with a limb and
+   subtract the result from a second limb vector.
+
+Copyright 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+/* This code runs at just under 9 cycles/limb on a T90.  That is not perfect,
+   mainly due to vector register shortage in the main loop.  Assembly code
+   should bring it down to perhaps 7 cycles/limb.  */
+
+#include <intrinsics.h>
+#include "gmp-impl.h"
+
+mp_limb_t
+mpn_submul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t vl)
+{
+  mp_limb_t cy[n];
+  mp_limb_t a, b, r, s0, s1, c0, c1;
+  mp_size_t i;
+  int more_carries;
+
+  if (up == rp)
+    {
+      /* The algorithm used below cannot handle overlap.  Handle it here by
+	 making a temporary copy of the source vector, then call ourselves.  */
+      mp_limb_t xp[n];
+      MPN_COPY (xp, up, n);
+      return mpn_submul_1 (rp, xp, n, vl);
+    }
+
+  a = up[0] * vl;
+  r = rp[0];
+  s0 = r - a;
+  rp[0] = s0;
+  c1 = ((s0 & a) | ((s0 | a) & ~r)) >> 63;
+  cy[0] = c1;
+
+  /* Main multiply loop.  Generate a raw accumulated output product in rp[]
+     and a carry vector in cy[].  */
+#pragma _CRI ivdep
+  for (i = 1; i < n; i++)
+    {
+      a = up[i] * vl;
+      b = _int_mult_upper (up[i - 1], vl);
+      s0 = a + b;
+      c0 = ((a & b) | ((a | b) & ~s0)) >> 63;
+      r = rp[i];
+      s1 = r - s0;
+      rp[i] = s1;
+      c1 = ((s1 & s0) | ((s1 | s0) & ~r)) >> 63;
+      cy[i] = c0 + c1;
+    }
+  /* Carry subtract loop.  Subtract the carry vector cy[] from the raw result
+     rp[] and store the new result back to rp[].  */
+  more_carries = 0;
+#pragma _CRI ivdep
+  for (i = 1; i < n; i++)
+    {
+      r = rp[i];
+      c0 = cy[i - 1];
+      s0 = r - c0;
+      rp[i] = s0;
+      c0 = (s0 & ~r) >> 63;
+      more_carries += c0;
+    }
+  /* If that second loop generated carry, handle that in scalar loop.  */
+  if (more_carries)
+    {
+      mp_limb_t cyrec = 0;
+      /* Look for places where rp[k] == ~0 and cy[k-1] == 1 or
+	 rp[k] == ~1 and cy[k-1] == 2.
+	 These are where we got a recurrency carry.  */
+      for (i = 1; i < n; i++)
+	{
+	  r = rp[i];
+	  c0 = ~r < cy[i - 1];
+	  s0 = r - cyrec;
+	  rp[i] = s0;
+	  c1 = (s0 & ~r) >> 63;
+	  cyrec = c0 | c1;
+	}
+      return _int_mult_upper (up[n - 1], vl) + cyrec + cy[n - 1];
+    }
+
+  return _int_mult_upper (up[n - 1], vl) + cy[n - 1];
+}
diff --git a/third_party/gmp/mpn/cray/lshift.c b/third_party/gmp/mpn/cray/lshift.c
new file mode 100644
index 0000000..8534e93
--- /dev/null
+++ b/third_party/gmp/mpn/cray/lshift.c
@@ -0,0 +1,58 @@
+/* mpn_lshift -- Shift left low level for Cray vector processors.
+
+Copyright (C) 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <intrinsics.h>
+#include "gmp-impl.h"
+
+mp_limb_t
+mpn_lshift (mp_ptr wp, mp_srcptr up, mp_size_t n, unsigned int cnt)
+{
+  unsigned sh_1, sh_2;
+  mp_size_t i;
+  mp_limb_t retval;
+
+  sh_1 = cnt;
+  sh_2 = GMP_LIMB_BITS - sh_1;
+  retval = up[n - 1] >> sh_2;
+
+#pragma _CRI ivdep
+  for (i = n - 1; i > 0; i--)
+    {
+#if 1
+      wp[i] = (up[i] << sh_1) | (up[i - 1] >> sh_2);
+#else
+      /* This is the recommended way, but at least on SV1 it is slower.  */
+      wp[i] = _dshiftl (up[i], up[i - 1], sh_1);
+#endif
+    }
+
+  wp[0] = up[0] << sh_1;
+  return retval;
+}
diff --git a/third_party/gmp/mpn/cray/mulww.f b/third_party/gmp/mpn/cray/mulww.f
new file mode 100644
index 0000000..6885dfc
--- /dev/null
+++ b/third_party/gmp/mpn/cray/mulww.f
@@ -0,0 +1,63 @@
+c    Helper for mpn_mul_1, mpn_addmul_1, and mpn_submul_1 for Cray PVP.
+
+c    Copyright 1996, 2000 Free Software Foundation, Inc.
+
+c    This file is part of the GNU MP Library.
+c
+c    The GNU MP Library is free software; you can redistribute it and/or modify
+c    it under the terms of either:
+c
+c      * the GNU Lesser General Public License as published by the Free
+c        Software Foundation; either version 3 of the License, or (at your
+c        option) any later version.
+c
+c    or
+c
+c      * the GNU General Public License as published by the Free Software
+c        Foundation; either version 2 of the License, or (at your option) any
+c        later version.
+c
+c    or both in parallel, as here.
+c
+c    The GNU MP Library is distributed in the hope that it will be useful, but
+c    WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+c    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+c    for more details.
+c
+c    You should have received copies of the GNU General Public License and the
+c    GNU Lesser General Public License along with the GNU MP Library.  If not,
+c    see https://www.gnu.org/licenses/.
+
+c    p1[] = hi(a[]*s); the upper limbs of each product
+c    p0[] = low(a[]*s); the corresponding lower limbs
+c    n is number of limbs in the vectors
+
+      subroutine gmpn_mulww(p1,p0,a,n,s)
+      integer*8 p1(0:*),p0(0:*),a(0:*),s
+      integer n
+
+      integer*8 a0,a1,a2,s0,s1,s2,c
+      integer*8 ai,t0,t1,t2,t3,t4
+
+      s0 = shiftl(and(s,4194303),24)
+      s1 = shiftl(and(shiftr(s,22),4194303),24)
+      s2 = shiftl(and(shiftr(s,44),4194303),24)
+
+      do i = 0,n-1
+         ai = a(i)
+         a0 = shiftl(and(ai,4194303),24)
+         a1 = shiftl(and(shiftr(ai,22),4194303),24)
+         a2 = shiftl(and(shiftr(ai,44),4194303),24)
+
+         t0 = i24mult(a0,s0)
+         t1 = i24mult(a0,s1)+i24mult(a1,s0)
+         t2 = i24mult(a0,s2)+i24mult(a1,s1)+i24mult(a2,s0)
+         t3 = i24mult(a1,s2)+i24mult(a2,s1)
+         t4 = i24mult(a2,s2)
+
+         p0(i)=shiftl(t2,44)+shiftl(t1,22)+t0
+         c=shiftr(shiftr(t0,22)+and(t1,4398046511103)+
+     $        shiftl(and(t2,1048575),22),42)
+         p1(i)=shiftl(t4,24)+shiftl(t3,2)+shiftr(t2,20)+shiftr(t1,42)+c
+      end do
+      end
diff --git a/third_party/gmp/mpn/cray/popcount.c b/third_party/gmp/mpn/cray/popcount.c
new file mode 100644
index 0000000..a79211f
--- /dev/null
+++ b/third_party/gmp/mpn/cray/popcount.c
@@ -0,0 +1,42 @@
+/* Cray mpn_popcount -- population count.
+
+Copyright 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <intrinsics.h>
+#include "gmp-impl.h"
+
+unsigned long int
+mpn_popcount (mp_srcptr p, mp_size_t n)
+{
+  unsigned long int result = 0;
+  mp_size_t i;
+  for (i = 0; i < n; i++)
+    result += _popcnt (p[i]);
+  return result;
+}
diff --git a/third_party/gmp/mpn/cray/rshift.c b/third_party/gmp/mpn/cray/rshift.c
new file mode 100644
index 0000000..9c4aa22
--- /dev/null
+++ b/third_party/gmp/mpn/cray/rshift.c
@@ -0,0 +1,58 @@
+/* mpn_rshift -- Shift right low level for Cray vector processors.
+
+Copyright (C) 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <intrinsics.h>
+#include "gmp-impl.h"
+
+mp_limb_t
+mpn_rshift (mp_ptr wp, mp_srcptr up, mp_size_t n, unsigned int cnt)
+{
+  unsigned sh_1, sh_2;
+  mp_size_t i;
+  mp_limb_t retval;
+
+  sh_1 = cnt;
+  sh_2 = GMP_LIMB_BITS - sh_1;
+  retval = up[0] << sh_2;
+
+#pragma _CRI ivdep
+  for (i = 0; i < n - 1; i++)
+    {
+#if 1
+      wp[i] = (up[i] >> sh_1) | (up[i + 1] << sh_2);
+#else
+      /* This is the recommended way, but at least on SV1 it is slower.  */
+      wp[i] = _dshiftr (up[i + 1], up[i], sh_1);
+#endif
+    }
+
+  wp[n - 1] = up[n - 1] >> sh_1;
+  return retval;
+}
diff --git a/third_party/gmp/mpn/cray/sub_n.c b/third_party/gmp/mpn/cray/sub_n.c
new file mode 100644
index 0000000..f518764
--- /dev/null
+++ b/third_party/gmp/mpn/cray/sub_n.c
@@ -0,0 +1,90 @@
+/* Cray PVP mpn_sub_n -- subtract two limb vectors and store their difference
+   in a third limb vector.
+
+Copyright 1996, 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+/* This code runs at 4 cycles/limb.  It may be possible to bring it down
+   to 3 cycles/limb.  */
+
+#include "gmp-impl.h"
+
+mp_limb_t
+mpn_sub_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n)
+{
+  mp_limb_t cy[n];
+  mp_limb_t a, b, r, s0, c0, c1;
+  mp_size_t i;
+  int more_carries;
+
+  /* Main subtract loop.  Generate a raw output difference in rp[] and a
+     borrow vector in cy[].  */
+#pragma _CRI ivdep
+  for (i = 0; i < n; i++)
+    {
+      a = up[i];
+      b = vp[i];
+      s0 = a - b;		/* a = s0 + b */
+      rp[i] = s0;
+      c0 = ((s0 & b) | ((s0 | b) & ~a)) >> 63;
+      cy[i] = c0;
+    }
+  /* Borrow subtract loop.  Subtract the borrow vector cy[] from the raw
+     difference rp[] and store the new difference back to rp[0].  If this
+     generates further borrow, set more_carries.  */
+  more_carries = 0;
+#pragma _CRI ivdep
+  for (i = 1; i < n; i++)
+    {
+      r = rp[i];
+      c0 = cy[i - 1];
+      s0 = r - c0;		/* r = s0 + c0 */
+      rp[i] = s0;
+      c0 = (s0 & ~r) >> 63;
+      more_carries += c0;
+    }
+  /* If that second loop generated borrow, handle that in scalar loop.  */
+  if (more_carries)
+    {
+      mp_limb_t cyrec = 0;
+      /* Look for places where rp[k] contains just ones and cy[k-1] is
+	 non-zero.  These are where we got a recurrency borrow.  */
+      for (i = 1; i < n; i++)
+	{
+	  r = rp[i];
+	  c0 = (~r == 0 && cy[i - 1] != 0);
+	  s0 = r - cyrec;
+	  rp[i] = s0;
+	  c1 = (s0 & ~r) >> 63;
+	  cyrec = c0 | c1;
+	}
+      return cyrec | cy[n - 1];
+    }
+
+  return cy[n - 1];
+}
diff --git a/third_party/gmp/mpn/generic/add.c b/third_party/gmp/mpn/generic/add.c
new file mode 100644
index 0000000..4a6e3ba
--- /dev/null
+++ b/third_party/gmp/mpn/generic/add.c
@@ -0,0 +1,33 @@
+/* mpn_add - add mpn to mpn.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define __GMP_FORCE_mpn_add 1
+
+#include "gmp-impl.h"
diff --git a/third_party/gmp/mpn/generic/add_1.c b/third_party/gmp/mpn/generic/add_1.c
new file mode 100644
index 0000000..1745aed
--- /dev/null
+++ b/third_party/gmp/mpn/generic/add_1.c
@@ -0,0 +1,33 @@
+/* mpn_add_1 - add limb to mpn.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define __GMP_FORCE_mpn_add_1 1
+
+#include "gmp-impl.h"
diff --git a/third_party/gmp/mpn/generic/add_err1_n.c b/third_party/gmp/mpn/generic/add_err1_n.c
new file mode 100644
index 0000000..b247f19
--- /dev/null
+++ b/third_party/gmp/mpn/generic/add_err1_n.c
@@ -0,0 +1,100 @@
+/* mpn_add_err1_n -- add_n with one error term
+
+   Contributed by David Harvey.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/*
+  Computes:
+
+  (1) {rp,n} := {up,n} + {vp,n} (just like mpn_add_n) with incoming carry cy,
+  return value is carry out.
+
+  (2) Let c[i+1] = carry from i-th limb addition (c[0] = cy).
+  Computes c[1]*yp[n-1] + ... + c[n]*yp[0], stores two-limb result at ep.
+
+  Requires n >= 1.
+
+  None of the outputs may overlap each other or any of the inputs, except
+  that {rp,n} may be equal to {up,n} or {vp,n}.
+*/
+mp_limb_t
+mpn_add_err1_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp,
+		mp_ptr ep, mp_srcptr yp,
+                mp_size_t n, mp_limb_t cy)
+{
+  mp_limb_t el, eh, ul, vl, yl, zl, rl, sl, cy1, cy2;
+
+  ASSERT (n >= 1);
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, up, n));
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, vp, n));
+  ASSERT (! MPN_OVERLAP_P (rp, n, yp, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 2, up, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 2, vp, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 2, yp, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 2, rp, n));
+
+  yp += n - 1;
+  el = eh = 0;
+
+  do
+    {
+      yl = *yp--;
+      ul = *up++;
+      vl = *vp++;
+
+      /* ordinary add_n */
+      ADDC_LIMB (cy1, sl, ul, vl);
+      ADDC_LIMB (cy2, rl, sl, cy);
+      cy = cy1 | cy2;
+      *rp++ = rl;
+
+      /* update (eh:el) */
+      zl = (-cy) & yl;
+      el += zl;
+      eh += el < zl;
+    }
+  while (--n);
+
+#if GMP_NAIL_BITS != 0
+  eh = (eh << GMP_NAIL_BITS) + (el >> GMP_NUMB_BITS);
+  el &= GMP_NUMB_MASK;
+#endif
+
+  ep[0] = el;
+  ep[1] = eh;
+
+  return cy;
+}
diff --git a/third_party/gmp/mpn/generic/add_err2_n.c b/third_party/gmp/mpn/generic/add_err2_n.c
new file mode 100644
index 0000000..d584d6d
--- /dev/null
+++ b/third_party/gmp/mpn/generic/add_err2_n.c
@@ -0,0 +1,116 @@
+/* mpn_add_err2_n -- add_n with two error terms
+
+   Contributed by David Harvey.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/*
+  Computes:
+
+  (1) {rp,n} := {up,n} + {vp,n} (just like mpn_add_n) with incoming carry cy,
+  return value is carry out.
+
+  (2) Let c[i+1] = carry from i-th limb addition (c[0] = cy).
+  Computes c[1]*yp1[n-1] + ... + c[n]*yp1[0],
+           c[1]*yp2[n-1] + ... + c[n]*yp2[0],
+  stores two-limb results at {ep,2} and {ep+2,2} respectively.
+
+  Requires n >= 1.
+
+  None of the outputs may overlap each other or any of the inputs, except
+  that {rp,n} may be equal to {up,n} or {vp,n}.
+*/
+mp_limb_t
+mpn_add_err2_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp,
+                mp_ptr ep, mp_srcptr yp1, mp_srcptr yp2,
+                mp_size_t n, mp_limb_t cy)
+{
+  mp_limb_t el1, eh1, el2, eh2, ul, vl, yl1, yl2, zl1, zl2, rl, sl, cy1, cy2;
+
+  ASSERT (n >= 1);
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, up, n));
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, vp, n));
+  ASSERT (! MPN_OVERLAP_P (rp, n, yp1, n));
+  ASSERT (! MPN_OVERLAP_P (rp, n, yp2, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 4, up, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 4, vp, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 4, yp1, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 4, yp2, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 4, rp, n));
+
+  yp1 += n - 1;
+  yp2 += n - 1;
+  el1 = eh1 = 0;
+  el2 = eh2 = 0;
+
+  do
+    {
+      yl1 = *yp1--;
+      yl2 = *yp2--;
+      ul = *up++;
+      vl = *vp++;
+
+      /* ordinary add_n */
+      ADDC_LIMB (cy1, sl, ul, vl);
+      ADDC_LIMB (cy2, rl, sl, cy);
+      cy = cy1 | cy2;
+      *rp++ = rl;
+
+      /* update (eh1:el1) */
+      zl1 = (-cy) & yl1;
+      el1 += zl1;
+      eh1 += el1 < zl1;
+
+      /* update (eh2:el2) */
+      zl2 = (-cy) & yl2;
+      el2 += zl2;
+      eh2 += el2 < zl2;
+    }
+  while (--n);
+
+#if GMP_NAIL_BITS != 0
+  eh1 = (eh1 << GMP_NAIL_BITS) + (el1 >> GMP_NUMB_BITS);
+  el1 &= GMP_NUMB_MASK;
+  eh2 = (eh2 << GMP_NAIL_BITS) + (el2 >> GMP_NUMB_BITS);
+  el2 &= GMP_NUMB_MASK;
+#endif
+
+  ep[0] = el1;
+  ep[1] = eh1;
+  ep[2] = el2;
+  ep[3] = eh2;
+
+  return cy;
+}
diff --git a/third_party/gmp/mpn/generic/add_err3_n.c b/third_party/gmp/mpn/generic/add_err3_n.c
new file mode 100644
index 0000000..a6ed4dc
--- /dev/null
+++ b/third_party/gmp/mpn/generic/add_err3_n.c
@@ -0,0 +1,131 @@
+/* mpn_add_err3_n -- add_n with three error terms
+
+   Contributed by David Harvey.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/*
+  Computes:
+
+  (1) {rp,n} := {up,n} + {vp,n} (just like mpn_add_n) with incoming carry cy,
+  return value is carry out.
+
+  (2) Let c[i+1] = carry from i-th limb addition (c[0] = cy).
+  Computes c[1]*yp1[n-1] + ... + c[n]*yp1[0],
+           c[1]*yp2[n-1] + ... + c[n]*yp2[0],
+           c[1]*yp3[n-1] + ... + c[n]*yp3[0],
+  stores two-limb results at {ep,2}, {ep+2,2} and {ep+4,2} respectively.
+
+  Requires n >= 1.
+
+  None of the outputs may overlap each other or any of the inputs, except
+  that {rp,n} may be equal to {up,n} or {vp,n}.
+*/
+mp_limb_t
+mpn_add_err3_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp,
+                mp_ptr ep, mp_srcptr yp1, mp_srcptr yp2, mp_srcptr yp3,
+                mp_size_t n, mp_limb_t cy)
+{
+  mp_limb_t el1, eh1, el2, eh2, el3, eh3, ul, vl, yl1, yl2, yl3, zl1, zl2, zl3, rl, sl, cy1, cy2;
+
+  ASSERT (n >= 1);
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, up, n));
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, vp, n));
+  ASSERT (! MPN_OVERLAP_P (rp, n, yp1, n));
+  ASSERT (! MPN_OVERLAP_P (rp, n, yp2, n));
+  ASSERT (! MPN_OVERLAP_P (rp, n, yp3, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 6, up, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 6, vp, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 6, yp1, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 6, yp2, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 6, yp3, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 6, rp, n));
+
+  yp1 += n - 1;
+  yp2 += n - 1;
+  yp3 += n - 1;
+  el1 = eh1 = 0;
+  el2 = eh2 = 0;
+  el3 = eh3 = 0;
+
+  do
+    {
+      yl1 = *yp1--;
+      yl2 = *yp2--;
+      yl3 = *yp3--;
+      ul = *up++;
+      vl = *vp++;
+
+      /* ordinary add_n */
+      ADDC_LIMB (cy1, sl, ul, vl);
+      ADDC_LIMB (cy2, rl, sl, cy);
+      cy = cy1 | cy2;
+      *rp++ = rl;
+
+      /* update (eh1:el1) */
+      zl1 = (-cy) & yl1;
+      el1 += zl1;
+      eh1 += el1 < zl1;
+
+      /* update (eh2:el2) */
+      zl2 = (-cy) & yl2;
+      el2 += zl2;
+      eh2 += el2 < zl2;
+
+      /* update (eh3:el3) */
+      zl3 = (-cy) & yl3;
+      el3 += zl3;
+      eh3 += el3 < zl3;
+    }
+  while (--n);
+
+#if GMP_NAIL_BITS != 0
+  eh1 = (eh1 << GMP_NAIL_BITS) + (el1 >> GMP_NUMB_BITS);
+  el1 &= GMP_NUMB_MASK;
+  eh2 = (eh2 << GMP_NAIL_BITS) + (el2 >> GMP_NUMB_BITS);
+  el2 &= GMP_NUMB_MASK;
+  eh3 = (eh3 << GMP_NAIL_BITS) + (el3 >> GMP_NUMB_BITS);
+  el3 &= GMP_NUMB_MASK;
+#endif
+
+  ep[0] = el1;
+  ep[1] = eh1;
+  ep[2] = el2;
+  ep[3] = eh2;
+  ep[4] = el3;
+  ep[5] = eh3;
+
+  return cy;
+}
diff --git a/third_party/gmp/mpn/generic/add_n.c b/third_party/gmp/mpn/generic/add_n.c
new file mode 100644
index 0000000..f62ac87
--- /dev/null
+++ b/third_party/gmp/mpn/generic/add_n.c
@@ -0,0 +1,89 @@
+/* mpn_add_n -- Add equal length limb vectors.
+
+Copyright 1992-1994, 1996, 2000, 2002, 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+#if GMP_NAIL_BITS == 0
+
+mp_limb_t
+mpn_add_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n)
+{
+  mp_limb_t ul, vl, sl, rl, cy, cy1, cy2;
+
+  ASSERT (n >= 1);
+  ASSERT (MPN_SAME_OR_INCR_P (rp, up, n));
+  ASSERT (MPN_SAME_OR_INCR_P (rp, vp, n));
+
+  cy = 0;
+  do
+    {
+      ul = *up++;
+      vl = *vp++;
+      sl = ul + vl;
+      cy1 = sl < ul;
+      rl = sl + cy;
+      cy2 = rl < sl;
+      cy = cy1 | cy2;
+      *rp++ = rl;
+    }
+  while (--n != 0);
+
+  return cy;
+}
+
+#endif
+
+#if GMP_NAIL_BITS >= 1
+
+mp_limb_t
+mpn_add_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n)
+{
+  mp_limb_t ul, vl, rl, cy;
+
+  ASSERT (n >= 1);
+  ASSERT (MPN_SAME_OR_INCR_P (rp, up, n));
+  ASSERT (MPN_SAME_OR_INCR_P (rp, vp, n));
+
+  cy = 0;
+  do
+    {
+      ul = *up++;
+      vl = *vp++;
+      rl = ul + vl + cy;
+      cy = rl >> GMP_NUMB_BITS;
+      *rp++ = rl & GMP_NUMB_MASK;
+    }
+  while (--n != 0);
+
+  return cy;
+}
+
+#endif
diff --git a/third_party/gmp/mpn/generic/add_n_sub_n.c b/third_party/gmp/mpn/generic/add_n_sub_n.c
new file mode 100644
index 0000000..1e72b5d
--- /dev/null
+++ b/third_party/gmp/mpn/generic/add_n_sub_n.c
@@ -0,0 +1,172 @@
+/* mpn_add_n_sub_n -- Add and Subtract two limb vectors of equal, non-zero length.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 1999-2001, 2006 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#ifndef L1_CACHE_SIZE
+#define L1_CACHE_SIZE 8192	/* only 68040 has less than this */
+#endif
+
+#define PART_SIZE (L1_CACHE_SIZE / GMP_LIMB_BYTES / 6)
+
+
+/* mpn_add_n_sub_n.
+   r1[] = s1[] + s2[]
+   r2[] = s1[] - s2[]
+   All operands have n limbs.
+   In-place operations allowed.  */
+mp_limb_t
+mpn_add_n_sub_n (mp_ptr r1p, mp_ptr r2p, mp_srcptr s1p, mp_srcptr s2p, mp_size_t n)
+{
+  mp_limb_t acyn, acyo;		/* carry for add */
+  mp_limb_t scyn, scyo;		/* carry for subtract */
+  mp_size_t off;		/* offset in operands */
+  mp_size_t this_n;		/* size of current chunk */
+
+  /* We alternatingly add and subtract in chunks that fit into the (L1)
+     cache.  Since the chunks are several hundred limbs, the function call
+     overhead is insignificant, but we get much better locality.  */
+
+  /* We have three variant of the inner loop, the proper loop is chosen
+     depending on whether r1 or r2 are the same operand as s1 or s2.  */
+
+  if (r1p != s1p && r1p != s2p)
+    {
+      /* r1 is not identical to either input operand.  We can therefore write
+	 to r1 directly, without using temporary storage.  */
+      acyo = 0;
+      scyo = 0;
+      for (off = 0; off < n; off += PART_SIZE)
+	{
+	  this_n = MIN (n - off, PART_SIZE);
+#if HAVE_NATIVE_mpn_add_nc
+	  acyo = mpn_add_nc (r1p + off, s1p + off, s2p + off, this_n, acyo);
+#else
+	  acyn = mpn_add_n (r1p + off, s1p + off, s2p + off, this_n);
+	  acyo = acyn + mpn_add_1 (r1p + off, r1p + off, this_n, acyo);
+#endif
+#if HAVE_NATIVE_mpn_sub_nc
+	  scyo = mpn_sub_nc (r2p + off, s1p + off, s2p + off, this_n, scyo);
+#else
+	  scyn = mpn_sub_n (r2p + off, s1p + off, s2p + off, this_n);
+	  scyo = scyn + mpn_sub_1 (r2p + off, r2p + off, this_n, scyo);
+#endif
+	}
+    }
+  else if (r2p != s1p && r2p != s2p)
+    {
+      /* r2 is not identical to either input operand.  We can therefore write
+	 to r2 directly, without using temporary storage.  */
+      acyo = 0;
+      scyo = 0;
+      for (off = 0; off < n; off += PART_SIZE)
+	{
+	  this_n = MIN (n - off, PART_SIZE);
+#if HAVE_NATIVE_mpn_sub_nc
+	  scyo = mpn_sub_nc (r2p + off, s1p + off, s2p + off, this_n, scyo);
+#else
+	  scyn = mpn_sub_n (r2p + off, s1p + off, s2p + off, this_n);
+	  scyo = scyn + mpn_sub_1 (r2p + off, r2p + off, this_n, scyo);
+#endif
+#if HAVE_NATIVE_mpn_add_nc
+	  acyo = mpn_add_nc (r1p + off, s1p + off, s2p + off, this_n, acyo);
+#else
+	  acyn = mpn_add_n (r1p + off, s1p + off, s2p + off, this_n);
+	  acyo = acyn + mpn_add_1 (r1p + off, r1p + off, this_n, acyo);
+#endif
+	}
+    }
+  else
+    {
+      /* r1 and r2 are identical to s1 and s2 (r1==s1 and r2==s2 or vice versa)
+	 Need temporary storage.  */
+      mp_limb_t tp[PART_SIZE];
+      acyo = 0;
+      scyo = 0;
+      for (off = 0; off < n; off += PART_SIZE)
+	{
+	  this_n = MIN (n - off, PART_SIZE);
+#if HAVE_NATIVE_mpn_add_nc
+	  acyo = mpn_add_nc (tp, s1p + off, s2p + off, this_n, acyo);
+#else
+	  acyn = mpn_add_n (tp, s1p + off, s2p + off, this_n);
+	  acyo = acyn + mpn_add_1 (tp, tp, this_n, acyo);
+#endif
+#if HAVE_NATIVE_mpn_sub_nc
+	  scyo = mpn_sub_nc (r2p + off, s1p + off, s2p + off, this_n, scyo);
+#else
+	  scyn = mpn_sub_n (r2p + off, s1p + off, s2p + off, this_n);
+	  scyo = scyn + mpn_sub_1 (r2p + off, r2p + off, this_n, scyo);
+#endif
+	  MPN_COPY (r1p + off, tp, this_n);
+	}
+    }
+
+  return 2 * acyo + scyo;
+}
+
+#ifdef MAIN
+#include <stdlib.h>
+#include <stdio.h>
+#include "timing.h"
+
+long cputime ();
+
+int
+main (int argc, char **argv)
+{
+  mp_ptr r1p, r2p, s1p, s2p;
+  double t;
+  mp_size_t n;
+
+  n = strtol (argv[1], 0, 0);
+
+  r1p = malloc (n * GMP_LIMB_BYTES);
+  r2p = malloc (n * GMP_LIMB_BYTES);
+  s1p = malloc (n * GMP_LIMB_BYTES);
+  s2p = malloc (n * GMP_LIMB_BYTES);
+  TIME (t,(mpn_add_n(r1p,s1p,s2p,n),mpn_sub_n(r1p,s1p,s2p,n)));
+  printf ("              separate add and sub: %.3f\n", t);
+  TIME (t,mpn_add_n_sub_n(r1p,r2p,s1p,s2p,n));
+  printf ("combined addsub separate variables: %.3f\n", t);
+  TIME (t,mpn_add_n_sub_n(r1p,r2p,r1p,s2p,n));
+  printf ("        combined addsub r1 overlap: %.3f\n", t);
+  TIME (t,mpn_add_n_sub_n(r1p,r2p,r1p,s2p,n));
+  printf ("        combined addsub r2 overlap: %.3f\n", t);
+  TIME (t,mpn_add_n_sub_n(r1p,r2p,r1p,r2p,n));
+  printf ("          combined addsub in-place: %.3f\n", t);
+
+  return 0;
+}
+#endif
diff --git a/third_party/gmp/mpn/generic/addmul_1.c b/third_party/gmp/mpn/generic/addmul_1.c
new file mode 100644
index 0000000..6140e8e
--- /dev/null
+++ b/third_party/gmp/mpn/generic/addmul_1.c
@@ -0,0 +1,145 @@
+/* mpn_addmul_1 -- multiply the N long limb vector pointed to by UP by VL,
+   add the N least significant limbs of the product to the limb vector
+   pointed to by RP.  Return the most significant limb of the product,
+   adjusted for carry-out from the addition.
+
+Copyright 1992-1994, 1996, 2000, 2002, 2004, 2016 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+#if GMP_NAIL_BITS == 0
+
+mp_limb_t
+mpn_addmul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t v0)
+{
+  mp_limb_t u0, crec, c, p1, p0, r0;
+
+  ASSERT (n >= 1);
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, up, n));
+
+  crec = 0;
+  do
+    {
+      u0 = *up++;
+      umul_ppmm (p1, p0, u0, v0);
+
+      r0 = *rp;
+
+      p0 = r0 + p0;
+      c = r0 > p0;
+
+      p1 = p1 + c;
+
+      r0 = p0 + crec;		/* cycle 0, 3, ... */
+      c = p0 > r0;		/* cycle 1, 4, ... */
+
+      crec = p1 + c;		/* cycle 2, 5, ... */
+
+      *rp++ = r0;
+    }
+  while (--n != 0);
+
+  return crec;
+}
+
+#endif
+
+#if GMP_NAIL_BITS == 1
+
+mp_limb_t
+mpn_addmul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t v0)
+{
+  mp_limb_t shifted_v0, u0, r0, p0, p1, prev_p1, crec, xl, c1, c2, c3;
+
+  ASSERT (n >= 1);
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, up, n));
+  ASSERT_MPN (rp, n);
+  ASSERT_MPN (up, n);
+  ASSERT_LIMB (v0);
+
+  shifted_v0 = v0 << GMP_NAIL_BITS;
+  crec = 0;
+  prev_p1 = 0;
+  do
+    {
+      u0 = *up++;
+      r0 = *rp;
+      umul_ppmm (p1, p0, u0, shifted_v0);
+      p0 >>= GMP_NAIL_BITS;
+      ADDC_LIMB (c1, xl, prev_p1, p0);
+      ADDC_LIMB (c2, xl, xl, r0);
+      ADDC_LIMB (c3, xl, xl, crec);
+      crec = c1 + c2 + c3;
+      *rp++ = xl;
+      prev_p1 = p1;
+    }
+  while (--n != 0);
+
+  return prev_p1 + crec;
+}
+
+#endif
+
+#if GMP_NAIL_BITS >= 2
+
+mp_limb_t
+mpn_addmul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t v0)
+{
+  mp_limb_t shifted_v0, u0, r0, p0, p1, prev_p1, xw, crec, xl;
+
+  ASSERT (n >= 1);
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, up, n));
+  ASSERT_MPN (rp, n);
+  ASSERT_MPN (up, n);
+  ASSERT_LIMB (v0);
+
+  shifted_v0 = v0 << GMP_NAIL_BITS;
+  crec = 0;
+  prev_p1 = 0;
+  do
+    {
+      u0 = *up++;
+      r0 = *rp;
+      umul_ppmm (p1, p0, u0, shifted_v0);
+      p0 >>= GMP_NAIL_BITS;
+      xw = prev_p1 + p0 + r0 + crec;
+      crec = xw >> GMP_NUMB_BITS;
+      xl = xw & GMP_NUMB_MASK;
+      *rp++ = xl;
+      prev_p1 = p1;
+    }
+  while (--n != 0);
+
+  return prev_p1 + crec;
+}
+
+#endif
diff --git a/third_party/gmp/mpn/generic/bdiv_dbm1c.c b/third_party/gmp/mpn/generic/bdiv_dbm1c.c
new file mode 100644
index 0000000..543bb6e
--- /dev/null
+++ b/third_party/gmp/mpn/generic/bdiv_dbm1c.c
@@ -0,0 +1,58 @@
+/* mpn_bdiv_dbm1c -- divide an mpn number by a divisor of B-1, where B is the
+   limb base.  The dbm1c moniker means "Divisor of B Minus 1 with Carry".
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2008, 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+mp_limb_t
+mpn_bdiv_dbm1c (mp_ptr qp, mp_srcptr ap, mp_size_t n, mp_limb_t bd, mp_limb_t h)
+{
+  mp_limb_t a, p0, p1, cy;
+  mp_size_t i;
+
+  for (i = 0; i < n; i++)
+    {
+      a = ap[i];
+      umul_ppmm (p1, p0, a, bd << GMP_NAIL_BITS);
+      p0 >>= GMP_NAIL_BITS;
+      cy = h < p0;
+      h = (h - p0) & GMP_NUMB_MASK;
+      qp[i] = h;
+      h = h - p1 - cy;
+    }
+
+  return h;
+}
diff --git a/third_party/gmp/mpn/generic/bdiv_q.c b/third_party/gmp/mpn/generic/bdiv_q.c
new file mode 100644
index 0000000..52aa473
--- /dev/null
+++ b/third_party/gmp/mpn/generic/bdiv_q.c
@@ -0,0 +1,76 @@
+/* mpn_bdiv_q -- Hensel division with precomputed inverse, returning quotient.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright 2006, 2007, 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* Computes Q = N / D mod B^n. */
+
+void
+mpn_bdiv_q (mp_ptr qp,
+	    mp_srcptr np, mp_size_t nn,
+	    mp_srcptr dp, mp_size_t dn,
+	    mp_ptr tp)
+{
+  mp_limb_t di;
+
+  if (BELOW_THRESHOLD (dn, DC_BDIV_Q_THRESHOLD))
+    {
+      MPN_COPY (tp, np, nn);
+      binvert_limb (di, dp[0]);  di = -di;
+      mpn_sbpi1_bdiv_q (qp, tp, nn, dp, dn, di);
+    }
+  else if (BELOW_THRESHOLD (dn, MU_BDIV_Q_THRESHOLD))
+    {
+      MPN_COPY (tp, np, nn);
+      binvert_limb (di, dp[0]);  di = -di;
+      mpn_dcpi1_bdiv_q (qp, tp, nn, dp, dn, di);
+    }
+  else
+    {
+      mpn_mu_bdiv_q (qp, np, nn, dp, dn, tp);
+    }
+  return;
+}
+
+mp_size_t
+mpn_bdiv_q_itch (mp_size_t nn, mp_size_t dn)
+{
+  if (BELOW_THRESHOLD (dn, MU_BDIV_Q_THRESHOLD))
+    return nn;
+  else
+    return mpn_mu_bdiv_q_itch (nn, dn);
+}
diff --git a/third_party/gmp/mpn/generic/bdiv_q_1.c b/third_party/gmp/mpn/generic/bdiv_q_1.c
new file mode 100644
index 0000000..6beb9a0
--- /dev/null
+++ b/third_party/gmp/mpn/generic/bdiv_q_1.c
@@ -0,0 +1,121 @@
+/* mpn_bdiv_q_1, mpn_pi1_bdiv_q_1 -- schoolbook Hensel division by 1-limb
+   divisor, returning quotient only.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2000-2003, 2005, 2009, 2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+mp_limb_t
+mpn_pi1_bdiv_q_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t d,
+		  mp_limb_t di, int shift)
+{
+  mp_size_t  i;
+  mp_limb_t  c, h, l, u, u_next, dummy;
+
+  ASSERT (n >= 1);
+  ASSERT (d != 0);
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, up, n));
+  ASSERT_MPN (up, n);
+  ASSERT_LIMB (d);
+
+  d <<= GMP_NAIL_BITS;
+
+  if (shift != 0)
+    {
+      c = 0;
+
+      u = up[0];
+      rp--;
+      for (i = 1; i < n; i++)
+	{
+	  u_next = up[i];
+	  u = ((u >> shift) | (u_next << (GMP_NUMB_BITS-shift))) & GMP_NUMB_MASK;
+
+	  SUBC_LIMB (c, l, u, c);
+
+	  l = (l * di) & GMP_NUMB_MASK;
+	  rp[i] = l;
+
+	  umul_ppmm (h, dummy, l, d);
+	  c += h;
+	  u = u_next;
+	}
+
+      u = u >> shift;
+      SUBC_LIMB (c, l, u, c);
+
+      l = (l * di) & GMP_NUMB_MASK;
+      rp[n] = l;
+    }
+  else
+    {
+      u = up[0];
+      l = (u * di) & GMP_NUMB_MASK;
+      rp[0] = l;
+      c = 0;
+
+      for (i = 1; i < n; i++)
+	{
+	  umul_ppmm (h, dummy, l, d);
+	  c += h;
+
+	  u = up[i];
+	  SUBC_LIMB (c, l, u, c);
+
+	  l = (l * di) & GMP_NUMB_MASK;
+	  rp[i] = l;
+	}
+    }
+
+  return c;
+}
+
+mp_limb_t
+mpn_bdiv_q_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t d)
+{
+  mp_limb_t di;
+  int shift;
+
+  ASSERT (n >= 1);
+  ASSERT (d != 0);
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, up, n));
+  ASSERT_MPN (up, n);
+  ASSERT_LIMB (d);
+
+  count_trailing_zeros (shift, d);
+  d >>= shift;
+
+  binvert_limb (di, d);
+  return mpn_pi1_bdiv_q_1 (rp, up, n, d, di, shift);
+}
diff --git a/third_party/gmp/mpn/generic/bdiv_qr.c b/third_party/gmp/mpn/generic/bdiv_qr.c
new file mode 100644
index 0000000..a4f0f39
--- /dev/null
+++ b/third_party/gmp/mpn/generic/bdiv_qr.c
@@ -0,0 +1,84 @@
+/* mpn_bdiv_qr -- Hensel division with precomputed inverse, returning quotient
+   and remainder.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright 2006, 2007, 2009, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* Computes Q = N / D mod B^n,
+	    R = N - QD.  */
+
+mp_limb_t
+mpn_bdiv_qr (mp_ptr qp, mp_ptr rp,
+	     mp_srcptr np, mp_size_t nn,
+	     mp_srcptr dp, mp_size_t dn,
+	     mp_ptr tp)
+{
+  mp_limb_t di;
+  mp_limb_t rh;
+
+  ASSERT (nn > dn);
+  if (BELOW_THRESHOLD (dn, DC_BDIV_QR_THRESHOLD) ||
+      BELOW_THRESHOLD (nn - dn, DC_BDIV_QR_THRESHOLD))
+    {
+      MPN_COPY (tp, np, nn);
+      binvert_limb (di, dp[0]);  di = -di;
+      rh = mpn_sbpi1_bdiv_qr (qp, tp, nn, dp, dn, di);
+      MPN_COPY (rp, tp + nn - dn, dn);
+    }
+  else if (BELOW_THRESHOLD (dn, MU_BDIV_QR_THRESHOLD))
+    {
+      MPN_COPY (tp, np, nn);
+      binvert_limb (di, dp[0]);  di = -di;
+      rh = mpn_dcpi1_bdiv_qr (qp, tp, nn, dp, dn, di);
+      MPN_COPY (rp, tp + nn - dn, dn);
+    }
+  else
+    {
+      rh = mpn_mu_bdiv_qr (qp, rp, np, nn, dp, dn, tp);
+    }
+
+  return rh;
+}
+
+mp_size_t
+mpn_bdiv_qr_itch (mp_size_t nn, mp_size_t dn)
+{
+  if (BELOW_THRESHOLD (dn, MU_BDIV_QR_THRESHOLD))
+    return nn;
+  else
+    return  mpn_mu_bdiv_qr_itch (nn, dn);
+}
diff --git a/third_party/gmp/mpn/generic/binvert.c b/third_party/gmp/mpn/generic/binvert.c
new file mode 100644
index 0000000..6c24ab7
--- /dev/null
+++ b/third_party/gmp/mpn/generic/binvert.c
@@ -0,0 +1,103 @@
+/* Compute {up,n}^(-1) mod B^n.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright (C) 2004-2007, 2009, 2012, 2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/*
+  r[k+1] = r[k] - r[k] * (u*r[k] - 1)
+  r[k+1] = r[k] + r[k] - r[k]*(u*r[k])
+*/
+
+#if TUNE_PROGRAM_BUILD
+#define NPOWS \
+ ((sizeof(mp_size_t) > 6 ? 48 : 8*sizeof(mp_size_t)))
+#else
+#define NPOWS \
+ ((sizeof(mp_size_t) > 6 ? 48 : 8*sizeof(mp_size_t)) - LOG2C (BINV_NEWTON_THRESHOLD))
+#endif
+
+mp_size_t
+mpn_binvert_itch (mp_size_t n)
+{
+  mp_size_t itch_local = mpn_mulmod_bnm1_next_size (n);
+  mp_size_t itch_out = mpn_mulmod_bnm1_itch (itch_local, n, (n + 1) >> 1);
+  return itch_local + itch_out;
+}
+
+void
+mpn_binvert (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_ptr scratch)
+{
+  mp_ptr xp;
+  mp_size_t rn, newrn;
+  mp_size_t sizes[NPOWS], *sizp;
+  mp_limb_t di;
+
+  /* Compute the computation precisions from highest to lowest, leaving the
+     base case size in 'rn'.  */
+  sizp = sizes;
+  for (rn = n; ABOVE_THRESHOLD (rn, BINV_NEWTON_THRESHOLD); rn = (rn + 1) >> 1)
+    *sizp++ = rn;
+
+  xp = scratch;
+
+  /* Compute a base value of rn limbs.  */
+  MPN_ZERO (xp, rn);
+  xp[0] = 1;
+  binvert_limb (di, up[0]);
+  if (BELOW_THRESHOLD (rn, DC_BDIV_Q_THRESHOLD))
+    mpn_sbpi1_bdiv_q (rp, xp, rn, up, rn, -di);
+  else
+    mpn_dcpi1_bdiv_q (rp, xp, rn, up, rn, -di);
+
+  mpn_neg (rp, rp, rn);
+
+  /* Use Newton iterations to get the desired precision.  */
+  for (; rn < n; rn = newrn)
+    {
+      mp_size_t m;
+      newrn = *--sizp;
+
+      /* X <- UR. */
+      m = mpn_mulmod_bnm1_next_size (newrn);
+      mpn_mulmod_bnm1 (xp, m, up, newrn, rp, rn, xp + m);
+      mpn_sub_1 (xp + m, xp, rn - (m - newrn), 1);
+
+      /* R = R(X/B^rn) */
+      mpn_mullo_n (rp + rn, rp, xp + rn, newrn - rn);
+      mpn_neg (rp + rn, rp + rn, newrn - rn);
+    }
+}
diff --git a/third_party/gmp/mpn/generic/broot.c b/third_party/gmp/mpn/generic/broot.c
new file mode 100644
index 0000000..02fe75a
--- /dev/null
+++ b/third_party/gmp/mpn/generic/broot.c
@@ -0,0 +1,195 @@
+/* mpn_broot -- Compute hensel sqrt
+
+   Contributed to the GNU project by Niels Möller
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/* Computes a^e (mod B). Uses right-to-left binary algorithm, since
+   typical use will have e small. */
+static mp_limb_t
+powlimb (mp_limb_t a, mp_limb_t e)
+{
+  mp_limb_t r = 1;
+  mp_limb_t s = a;
+
+  for (r = 1, s = a; e > 0; e >>= 1, s *= s)
+    if (e & 1)
+      r *= s;
+
+  return r;
+}
+
+/* Computes a^{1/k - 1} (mod B^n). Both a and k must be odd.
+
+   Iterates
+
+     r' <-- r - r * (a^{k-1} r^k - 1) / n
+
+   If
+
+     a^{k-1} r^k = 1 (mod 2^m),
+
+   then
+
+     a^{k-1} r'^k = 1 (mod 2^{2m}),
+
+   Compute the update term as
+
+     r' = r - (a^{k-1} r^{k+1} - r) / k
+
+   where we still have cancellation of low limbs.
+
+ */
+void
+mpn_broot_invm1 (mp_ptr rp, mp_srcptr ap, mp_size_t n, mp_limb_t k)
+{
+  mp_size_t sizes[GMP_LIMB_BITS * 2];
+  mp_ptr akm1, tp, rnp, ep;
+  mp_limb_t a0, r0, km1, kp1h, kinv;
+  mp_size_t rn;
+  unsigned i;
+
+  TMP_DECL;
+
+  ASSERT (n > 0);
+  ASSERT (ap[0] & 1);
+  ASSERT (k & 1);
+  ASSERT (k >= 3);
+
+  TMP_MARK;
+
+  akm1 = TMP_ALLOC_LIMBS (4*n);
+  tp = akm1 + n;
+
+  km1 = k-1;
+  /* FIXME: Could arrange the iteration so we don't need to compute
+     this up front, computing a^{k-1} * r^k as (a r)^{k-1} * r. Note
+     that we can use wraparound also for a*r, since the low half is
+     unchanged from the previous iteration. Or possibly mulmid. Also,
+     a r = a^{1/k}, so we get that value too, for free? */
+  mpn_powlo (akm1, ap, &km1, 1, n, tp); /* 3 n scratch space */
+
+  a0 = ap[0];
+  binvert_limb (kinv, k);
+
+  /* 4 bits: a^{1/k - 1} (mod 16):
+
+	a % 8
+	1 3 5 7
+   k%4 +-------
+     1 |1 1 1 1
+     3 |1 9 9 1
+  */
+  r0 = 1 + (((k << 2) & ((a0 << 1) ^ (a0 << 2))) & 8);
+  r0 = kinv * r0 * (k+1 - akm1[0] * powlimb (r0, k & 0x7f)); /* 8 bits */
+  r0 = kinv * r0 * (k+1 - akm1[0] * powlimb (r0, k & 0x7fff)); /* 16 bits */
+  r0 = kinv * r0 * (k+1 - akm1[0] * powlimb (r0, k)); /* 32 bits */
+#if GMP_NUMB_BITS > 32
+  {
+    unsigned prec = 32;
+    do
+      {
+	r0 = kinv * r0 * (k+1 - akm1[0] * powlimb (r0, k));
+	prec *= 2;
+      }
+    while (prec < GMP_NUMB_BITS);
+  }
+#endif
+
+  rp[0] = r0;
+  if (n == 1)
+    {
+      TMP_FREE;
+      return;
+    }
+
+  /* For odd k, (k+1)/2 = k/2+1, and the latter avoids overflow. */
+  kp1h = k/2 + 1;
+
+  /* FIXME: Special case for two limb iteration. */
+  rnp = TMP_ALLOC_LIMBS (2*n + 1);
+  ep = rnp + n;
+
+  /* FIXME: Possible to this on the fly with some bit fiddling. */
+  for (i = 0; n > 1; n = (n + 1)/2)
+    sizes[i++] = n;
+
+  rn = 1;
+
+  while (i-- > 0)
+    {
+      /* Compute x^{k+1}. */
+      mpn_sqr (ep, rp, rn); /* For odd n, writes n+1 limbs in the
+			       final iteration. */
+      mpn_powlo (rnp, ep, &kp1h, 1, sizes[i], tp);
+
+      /* Multiply by a^{k-1}. Can use wraparound; low part equals r. */
+
+      mpn_mullo_n (ep, rnp, akm1, sizes[i]);
+      ASSERT (mpn_cmp (ep, rp, rn) == 0);
+
+      ASSERT (sizes[i] <= 2*rn);
+      mpn_pi1_bdiv_q_1 (rp + rn, ep + rn, sizes[i] - rn, k, kinv, 0);
+      mpn_neg (rp + rn, rp + rn, sizes[i] - rn);
+      rn = sizes[i];
+    }
+  TMP_FREE;
+}
+
+/* Computes a^{1/k} (mod B^n). Both a and k must be odd. */
+void
+mpn_broot (mp_ptr rp, mp_srcptr ap, mp_size_t n, mp_limb_t k)
+{
+  mp_ptr tp;
+  TMP_DECL;
+
+  ASSERT (n > 0);
+  ASSERT (ap[0] & 1);
+  ASSERT (k & 1);
+
+  if (k == 1)
+    {
+      MPN_COPY (rp, ap, n);
+      return;
+    }
+
+  TMP_MARK;
+  tp = TMP_ALLOC_LIMBS (n);
+
+  mpn_broot_invm1 (tp, ap, n, k);
+  mpn_mullo_n (rp, tp, ap, n);
+
+  TMP_FREE;
+}
diff --git a/third_party/gmp/mpn/generic/brootinv.c b/third_party/gmp/mpn/generic/brootinv.c
new file mode 100644
index 0000000..e91b597
--- /dev/null
+++ b/third_party/gmp/mpn/generic/brootinv.c
@@ -0,0 +1,159 @@
+/* mpn_brootinv, compute r such that r^k * y = 1 (mod 2^b).
+
+   Contributed to the GNU project by Martin Boij (as part of perfpow.c).
+
+Copyright 2009, 2010, 2012, 2013, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/* Computes a^2e (mod B). Uses right-to-left binary algorithm, since
+   typical use will have e small. */
+static mp_limb_t
+powsquaredlimb (mp_limb_t a, mp_limb_t e)
+{
+  mp_limb_t r;
+
+  r = 1;
+  /* if (LIKELY (e != 0)) */
+  do {
+    a *= a;
+    if (e & 1)
+      r *= a;
+    e >>= 1;
+  } while (e != 0);
+
+  return r;
+}
+
+/* Compute r such that r^k * y = 1 (mod B^n).
+
+   Iterates
+     r' <-- k^{-1} ((k+1) r - r^{k+1} y) (mod 2^b)
+   using Hensel lifting, each time doubling the number of known bits in r.
+
+   Works just for odd k.  Else the Hensel lifting degenerates.
+
+   FIXME:
+
+     (1) Make it work for k == GMP_LIMB_MAX (k+1 below overflows).
+
+     (2) Rewrite iteration as
+	   r' <-- r - k^{-1} r (r^k y - 1)
+	 and take advantage of the zero low part of r^k y - 1.
+
+     (3) Use wrap-around trick.
+
+     (4) Use a small table to get starting value.
+
+   Scratch need: bn + (((bn + 1) >> 1) + 1) + scratch for mpn_powlo
+   Currently mpn_powlo requires 3*bn
+   so that 5*bn is surely enough, where bn = ceil (bnb / GMP_NUMB_BITS).
+*/
+
+void
+mpn_brootinv (mp_ptr rp, mp_srcptr yp, mp_size_t bn, mp_limb_t k, mp_ptr tp)
+{
+  mp_ptr tp2, tp3;
+  mp_limb_t kinv, k2, r0, y0;
+  mp_size_t order[GMP_LIMB_BITS + 1];
+  int d;
+
+  ASSERT (bn > 0);
+  ASSERT ((k & 1) != 0);
+
+  tp2 = tp + bn;
+  tp3 = tp + bn + ((bn + 3) >> 1);
+  k2 = (k >> 1) + 1; /* (k + 1) / 2 , but avoid k+1 overflow */
+
+  binvert_limb (kinv, k);
+
+  /* 4-bit initial approximation:
+
+   y%16 | 1  3  5  7  9 11 13 15,
+    k%4 +-------------------------+k2%2
+     1  | 1 11 13  7  9  3  5 15  |  1
+     3  | 1  3  5  7  9 11 13 15  |  0
+
+  */
+  y0 = yp[0];
+
+  r0 = y0 ^ (((y0 << 1) ^ (y0 << 2)) & (k2 << 3) & 8);			/* 4 bits */
+  r0 = kinv * (k2 * r0 * 2 - y0 * powsquaredlimb(r0, k2 & 0x3f));	/* 8 bits */
+  r0 = kinv * (k2 * r0 * 2 - y0 * powsquaredlimb(r0, k2 & 0x3fff));	/* 16 bits */
+#if GMP_NUMB_BITS > 16
+  {
+    unsigned prec = 16;
+    do
+      {
+	r0 = kinv * (k2 * r0 * 2 - y0 * powsquaredlimb(r0, k2));
+	prec *= 2;
+      }
+    while (prec < GMP_NUMB_BITS);
+  }
+#endif
+
+  rp[0] = r0;
+  if (bn == 1)
+    return;
+
+  d = 0;
+  for (; bn != 2; bn = (bn + 1) >> 1)
+    order[d++] = bn;
+
+  order[d] = 2;
+  bn = 1;
+
+  do
+    {
+      mpn_sqr (tp, rp, bn); /* Result may overlap tp2 */
+      tp2[bn] = mpn_mul_1 (tp2, rp, bn, k2 << 1);
+
+      bn = order[d];
+
+      mpn_powlo (rp, tp, &k2, 1, bn, tp3);
+      mpn_mullo_n (tp, yp, rp, bn);
+
+      /* mpn_sub (tp, tp2, ((bn + 1) >> 1) + 1, tp, bn); */
+      /* The function above is not handled, ((bn + 1) >> 1) + 1 <= bn*/
+      {
+	mp_size_t pbn = (bn + 3) >> 1; /* Size of tp2 */
+	int borrow;
+	borrow = mpn_sub_n (tp, tp2, tp, pbn) != 0;
+	if (bn > pbn) /* 3 < bn */
+	  {
+	    if (borrow)
+	      mpn_com (tp + pbn, tp + pbn, bn - pbn);
+	    else
+	      mpn_neg (tp + pbn, tp + pbn, bn - pbn);
+	  }
+      }
+      mpn_pi1_bdiv_q_1 (rp, tp, bn, k, kinv, 0);
+    }
+  while (--d >= 0);
+}
diff --git a/third_party/gmp/mpn/generic/bsqrt.c b/third_party/gmp/mpn/generic/bsqrt.c
new file mode 100644
index 0000000..27184f0
--- /dev/null
+++ b/third_party/gmp/mpn/generic/bsqrt.c
@@ -0,0 +1,47 @@
+/* mpn_bsqrt, a^{1/2} (mod 2^n).
+
+Copyright 2009, 2010, 2012, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+void
+mpn_bsqrt (mp_ptr rp, mp_srcptr ap, mp_bitcnt_t nb, mp_ptr tp)
+{
+  mp_ptr sp;
+  mp_size_t n;
+
+  ASSERT (nb > 0);
+
+  n = nb / GMP_NUMB_BITS;
+  sp = tp + n;
+
+  mpn_bsqrtinv (tp, ap, nb, sp);
+  mpn_mullo_n (rp, tp, ap, n);
+}
diff --git a/third_party/gmp/mpn/generic/bsqrtinv.c b/third_party/gmp/mpn/generic/bsqrtinv.c
new file mode 100644
index 0000000..c286773
--- /dev/null
+++ b/third_party/gmp/mpn/generic/bsqrtinv.c
@@ -0,0 +1,103 @@
+/* mpn_bsqrtinv, compute r such that r^2 * y = 1 (mod 2^{b+1}).
+
+   Contributed to the GNU project by Martin Boij (as part of perfpow.c).
+
+Copyright 2009, 2010, 2012, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/* Compute r such that r^2 * y = 1 (mod 2^{b+1}).
+   Return non-zero if such an integer r exists.
+
+   Iterates
+     r' <-- (3r - r^3 y) / 2
+   using Hensel lifting.  Since we divide by two, the Hensel lifting is
+   somewhat degenerates.  Therefore, we lift from 2^b to 2^{b+1}-1.
+
+   FIXME:
+     (1) Simplify to do precision book-keeping in limbs rather than bits.
+
+     (2) Rewrite iteration as
+	   r' <-- r - r (r^2 y - 1) / 2
+	 and take advantage of zero low part of r^2 y - 1.
+
+     (3) Use wrap-around trick.
+
+     (4) Use a small table to get starting value.
+*/
+int
+mpn_bsqrtinv (mp_ptr rp, mp_srcptr yp, mp_bitcnt_t bnb, mp_ptr tp)
+{
+  mp_ptr tp2;
+  mp_size_t bn, order[GMP_LIMB_BITS + 1];
+  int i, d;
+
+  ASSERT (bnb > 0);
+
+  bn = 1 + bnb / GMP_LIMB_BITS;
+
+  tp2 = tp + bn;
+
+  rp[0] = 1;
+  if (bnb == 1)
+    {
+      if ((yp[0] & 3) != 1)
+	return 0;
+    }
+  else
+    {
+      if ((yp[0] & 7) != 1)
+	return 0;
+
+      d = 0;
+      for (; bnb != 2; bnb = (bnb + 2) >> 1)
+	order[d++] = bnb;
+
+      for (i = d - 1; i >= 0; i--)
+	{
+	  bnb = order[i];
+	  bn = 1 + bnb / GMP_LIMB_BITS;
+
+	  mpn_sqrlo (tp, rp, bn);
+	  mpn_mullo_n (tp2, rp, tp, bn); /* tp2 <- rp ^ 3 */
+
+	  mpn_mul_1 (tp, rp, bn, 3);
+
+	  mpn_mullo_n (rp, yp, tp2, bn);
+
+#if HAVE_NATIVE_mpn_rsh1sub_n
+	  mpn_rsh1sub_n (rp, tp, rp, bn);
+#else
+	  mpn_sub_n (tp2, tp, rp, bn);
+	  mpn_rshift (rp, tp2, bn, 1);
+#endif
+	}
+    }
+  return 1;
+}
diff --git a/third_party/gmp/mpn/generic/cmp.c b/third_party/gmp/mpn/generic/cmp.c
new file mode 100644
index 0000000..940314b
--- /dev/null
+++ b/third_party/gmp/mpn/generic/cmp.c
@@ -0,0 +1,33 @@
+/* mpn_cmp -- Compare two low-level natural-number integers.
+
+Copyright 1991, 1993, 1994, 1996, 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define __GMP_FORCE_mpn_cmp 1
+
+#include "gmp-impl.h"
diff --git a/third_party/gmp/mpn/generic/cnd_add_n.c b/third_party/gmp/mpn/generic/cnd_add_n.c
new file mode 100644
index 0000000..e6b1373
--- /dev/null
+++ b/third_party/gmp/mpn/generic/cnd_add_n.c
@@ -0,0 +1,69 @@
+/* mpn_cnd_add_n -- Compute R = U + V if CND != 0 or R = U if CND == 0.
+   Both cases should take the same time and perform the exact same memory
+   accesses, since this function is intended to be used where side-channel
+   attack resilience is relevant.
+
+Copyright 1992-1994, 1996, 2000, 2002, 2008, 2009, 2011, 2013 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+mp_limb_t
+mpn_cnd_add_n (mp_limb_t cnd, mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n)
+{
+  mp_limb_t ul, vl, sl, rl, cy, cy1, cy2, mask;
+
+  ASSERT (n >= 1);
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, up, n));
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, vp, n));
+
+  mask = -(mp_limb_t) (cnd != 0);
+  cy = 0;
+  do
+    {
+      ul = *up++;
+      vl = *vp++ & mask;
+#if GMP_NAIL_BITS == 0
+      sl = ul + vl;
+      cy1 = sl < ul;
+      rl = sl + cy;
+      cy2 = rl < sl;
+      cy = cy1 | cy2;
+      *rp++ = rl;
+#else
+      rl = ul + vl;
+      rl += cy;
+      cy = rl >> GMP_NUMB_BITS;
+      *rp++ = rl & GMP_NUMB_MASK;
+#endif
+    }
+  while (--n != 0);
+
+  return cy;
+}
diff --git a/third_party/gmp/mpn/generic/cnd_sub_n.c b/third_party/gmp/mpn/generic/cnd_sub_n.c
new file mode 100644
index 0000000..d04ad8a
--- /dev/null
+++ b/third_party/gmp/mpn/generic/cnd_sub_n.c
@@ -0,0 +1,69 @@
+/* mpn_cnd_sub_n -- Compute R = U - V if CND != 0 or R = U if CND == 0.
+   Both cases should take the same time and perform the exact same memory
+   accesses, since this function is intended to be used where side-channel
+   attack resilience is relevant.
+
+Copyright 1992-1994, 1996, 2000, 2002, 2008, 2009, 2011, 2013 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+mp_limb_t
+mpn_cnd_sub_n (mp_limb_t cnd, mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n)
+{
+  mp_limb_t ul, vl, sl, rl, cy, cy1, cy2, mask;
+
+  ASSERT (n >= 1);
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, up, n));
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, vp, n));
+
+  mask = -(mp_limb_t) (cnd != 0);
+  cy = 0;
+  do
+    {
+      ul = *up++;
+      vl = *vp++ & mask;
+#if GMP_NAIL_BITS == 0
+      sl = ul - vl;
+      cy1 = sl > ul;
+      rl = sl - cy;
+      cy2 = rl > sl;
+      cy = cy1 | cy2;
+      *rp++ = rl;
+#else
+      rl = ul - vl;
+      rl -= cy;
+      cy = rl >> (GMP_LIMB_BITS - 1);
+      *rp++ = rl & GMP_NUMB_MASK;
+#endif
+    }
+  while (--n != 0);
+
+  return cy;
+}
diff --git a/third_party/gmp/mpn/generic/cnd_swap.c b/third_party/gmp/mpn/generic/cnd_swap.c
new file mode 100644
index 0000000..83d856d
--- /dev/null
+++ b/third_party/gmp/mpn/generic/cnd_swap.c
@@ -0,0 +1,50 @@
+/* mpn_cnd_swap
+
+   Contributed to the GNU project by Niels Möller
+
+Copyright 2013, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpn_cnd_swap (mp_limb_t cnd, volatile mp_limb_t *ap, volatile mp_limb_t *bp,
+	      mp_size_t n)
+{
+  volatile mp_limb_t mask = - (mp_limb_t) (cnd != 0);
+  mp_size_t i;
+  for (i = 0; i < n; i++)
+    {
+      mp_limb_t a, b, t;
+      a = ap[i];
+      b = bp[i];
+      t = (a ^ b) & mask;
+      ap[i] = a ^ t;
+      bp[i] = b ^ t;
+    }
+}
diff --git a/third_party/gmp/mpn/generic/com.c b/third_party/gmp/mpn/generic/com.c
new file mode 100644
index 0000000..4de5824
--- /dev/null
+++ b/third_party/gmp/mpn/generic/com.c
@@ -0,0 +1,44 @@
+/* mpn_com - complement an mpn.
+
+Copyright 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#undef mpn_com
+#define mpn_com __MPN(com)
+
+void
+mpn_com (mp_ptr rp, mp_srcptr up, mp_size_t n)
+{
+  mp_limb_t ul;
+  do {
+      ul = *up++;
+      *rp++ = ~ul & GMP_NUMB_MASK;
+  } while (--n != 0);
+}
diff --git a/third_party/gmp/mpn/generic/comb_tables.c b/third_party/gmp/mpn/generic/comb_tables.c
new file mode 100644
index 0000000..dedb77b
--- /dev/null
+++ b/third_party/gmp/mpn/generic/comb_tables.c
@@ -0,0 +1,47 @@
+/* Const tables shared among combinatoric functions.
+
+   THE CONTENTS OF THIS FILE ARE FOR INTERNAL USE AND ARE ALMOST CERTAIN TO
+   BE SUBJECT TO INCOMPATIBLE CHANGES IN FUTURE GNU MP RELEASES.
+
+Copyright 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/* Entry i contains (i!/2^t) where t is chosen such that the parenthesis
+   is an odd integer. */
+const mp_limb_t __gmp_oddfac_table[] = { ONE_LIMB_ODD_FACTORIAL_TABLE, ONE_LIMB_ODD_FACTORIAL_EXTTABLE };
+
+/* Entry i contains ((2i+1)!!/2^t) where t is chosen such that the parenthesis
+   is an odd integer. */
+const mp_limb_t __gmp_odd2fac_table[] = { ONE_LIMB_ODD_DOUBLEFACTORIAL_TABLE };
+
+/* Entry i contains 2i-popc(2i). */
+const unsigned char __gmp_fac2cnt_table[] = { TABLE_2N_MINUS_POPC_2N };
+
+const mp_limb_t __gmp_limbroots_table[] = { NTH_ROOT_NUMB_MASK_TABLE };
diff --git a/third_party/gmp/mpn/generic/compute_powtab.c b/third_party/gmp/mpn/generic/compute_powtab.c
new file mode 100644
index 0000000..f4fbc64
--- /dev/null
+++ b/third_party/gmp/mpn/generic/compute_powtab.c
@@ -0,0 +1,373 @@
+/* mpn_compute_powtab.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 1991-2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+/*
+  CAVEATS:
+  * The exptab and powtab vectors are in opposite orders.  Probably OK.
+  * Consider getting rid of exptab, doing bit ops on the un argument instead.
+  * Consider rounding greatest power slightly upwards to save adjustments.
+  * In powtab_decide, consider computing cost from just the 2-3 largest
+    operands, since smaller operand contribute little.  This makes most sense
+    if exptab is suppressed.
+*/
+
+#include "gmp-impl.h"
+
+#ifndef DIV_1_VS_MUL_1_PERCENT
+#define DIV_1_VS_MUL_1_PERCENT 150
+#endif
+
+#define SET_powers_t(dest, ptr, size, dib, b, sh)	\
+  do {							\
+    dest.p = ptr;					\
+    dest.n = size;					\
+    dest.digits_in_base = dib;				\
+    dest.base = b;					\
+    dest.shift = sh;					\
+  } while (0)
+
+#if DIV_1_VS_MUL_1_PERCENT > 120
+#define HAVE_mpn_compute_powtab_mul 1
+static void
+mpn_compute_powtab_mul (powers_t *powtab, mp_ptr powtab_mem, mp_size_t un,
+			int base, const size_t *exptab, size_t n_pows)
+{
+  mp_size_t n;
+  mp_ptr p, t;
+  mp_limb_t cy;
+  long start_idx;
+  int c;
+
+  mp_limb_t big_base = mp_bases[base].big_base;
+  int chars_per_limb = mp_bases[base].chars_per_limb;
+
+  mp_ptr powtab_mem_ptr = powtab_mem;
+
+  size_t digits_in_base = chars_per_limb;
+
+  powers_t *pt = powtab;
+
+  p = powtab_mem_ptr;
+  powtab_mem_ptr += 1;
+  p[0] = big_base;
+
+  SET_powers_t (pt[0], p, 1, digits_in_base, base, 0);
+  pt++;
+
+  t = powtab_mem_ptr;
+  powtab_mem_ptr += 2;
+  t[1] = mpn_mul_1 (t, p, 1, big_base);
+  n = 2;
+
+  digits_in_base *= 2;
+
+  c = t[0] == 0;
+  t += c;
+  n -= c;
+  mp_size_t shift = c;
+
+  SET_powers_t (pt[0], t, n, digits_in_base, base, shift);
+  p = t;
+  pt++;
+
+  if (exptab[0] == ((size_t) chars_per_limb << n_pows))
+    {
+      start_idx = n_pows - 2;
+    }
+  else
+    {
+      if (((digits_in_base + chars_per_limb) << (n_pows-2)) <= exptab[0])
+	{
+	  /* 3, sometimes adjusted to 4.  */
+	  t = powtab_mem_ptr;
+	  powtab_mem_ptr += 4;
+	  t[n] = cy = mpn_mul_1 (t, p, n, big_base);
+	  n += cy != 0;;
+
+	  digits_in_base += chars_per_limb;
+
+	  c  = t[0] == 0;
+	  t += c;
+	  n -= c;
+	  shift += c;
+	}
+      else
+	{
+	  /* 2 copy, will always become 3 with back-multiplication.  */
+	  t = powtab_mem_ptr;
+	  powtab_mem_ptr += 3;
+	  t[0] = p[0];
+	  t[1] = p[1];
+	}
+
+      SET_powers_t (pt[0], t, n, digits_in_base, base, shift);
+      p = t;
+      pt++;
+      start_idx = n_pows - 3;
+    }
+
+  for (long pi = start_idx; pi >= 0; pi--)
+    {
+      t = powtab_mem_ptr;
+      powtab_mem_ptr += 2 * n + 2;
+
+      ASSERT (powtab_mem_ptr < powtab_mem + mpn_str_powtab_alloc (un));
+
+      mpn_sqr (t, p, n);
+
+      digits_in_base *= 2;
+      n *= 2;
+      n -= t[n - 1] == 0;
+      shift *= 2;
+
+      c = t[0] == 0;
+      t += c;
+      n -= c;
+      shift += c;
+
+      /* Adjust new value if it is too small as input to the next squaring.  */
+      if (((digits_in_base + chars_per_limb) << pi) <= exptab[0])
+	{
+	  t[n] = cy = mpn_mul_1 (t, t, n, big_base);
+	  n += cy != 0;
+
+	  digits_in_base += chars_per_limb;
+
+	  c  = t[0] == 0;
+	  t += c;
+	  n -= c;
+	  shift += c;
+	}
+
+      SET_powers_t (pt[0], t, n, digits_in_base, base, shift);
+
+      /* Adjust previous value if it is not at its target power.  */
+      if (pt[-1].digits_in_base < exptab[pi + 1])
+	{
+	  mp_size_t n = pt[-1].n;
+	  mp_ptr p = pt[-1].p;
+	  p[n] = cy = mpn_mul_1 (p, p, n, big_base);
+	  n += cy != 0;
+
+	  ASSERT (pt[-1].digits_in_base + chars_per_limb == exptab[pi + 1]);
+	  pt[-1].digits_in_base = exptab[pi + 1];
+
+	  c = p[0] == 0;
+	  pt[-1].p = p + c;
+	  pt[-1].n = n - c;
+	  pt[-1].shift += c;
+	}
+
+      p = t;
+      pt++;
+    }
+}
+#endif
+
+#if DIV_1_VS_MUL_1_PERCENT < 275
+#define HAVE_mpn_compute_powtab_div 1
+static void
+mpn_compute_powtab_div (powers_t *powtab, mp_ptr powtab_mem, mp_size_t un,
+			int base, const size_t *exptab, size_t n_pows)
+{
+  mp_ptr p, t;
+
+  mp_limb_t big_base = mp_bases[base].big_base;
+  int chars_per_limb = mp_bases[base].chars_per_limb;
+
+  mp_ptr powtab_mem_ptr = powtab_mem;
+
+  size_t digits_in_base = chars_per_limb;
+
+  powers_t *pt = powtab;
+
+  p = powtab_mem_ptr;
+  powtab_mem_ptr += 1;
+  p[0] = big_base;
+
+  SET_powers_t (pt[0], p, 1, digits_in_base, base, 0);
+  pt++;
+
+  mp_size_t n = 1;
+  mp_size_t shift = 0;
+  for (long pi = n_pows - 1; pi >= 0; pi--)
+    {
+      t = powtab_mem_ptr;
+      powtab_mem_ptr += 2 * n;
+
+      ASSERT (powtab_mem_ptr < powtab_mem + mpn_str_powtab_alloc (un));
+
+      mpn_sqr (t, p, n);
+      n = 2 * n - 1; n += t[n] != 0;
+      digits_in_base *= 2;
+
+      if (digits_in_base != exptab[pi])	/* if ((((un - 1) >> pi) & 2) == 0) */
+	{
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1 || ! HAVE_NATIVE_mpn_divexact_1
+	  if (__GMP_LIKELY (base == 10))
+	    mpn_pi1_bdiv_q_1 (t, t, n, big_base >> MP_BASES_BIG_BASE_CTZ_10,
+			      MP_BASES_BIG_BASE_BINVERTED_10,
+			      MP_BASES_BIG_BASE_CTZ_10);
+	  else
+#endif
+	    /* FIXME: We could use _pi1 here if we add big_base_binverted and
+	       big_base_ctz fields to struct bases.  That would add about 2 KiB
+	       to mp_bases.c.
+	       FIXME: Use mpn_bdiv_q_1 here when mpn_divexact_1 is converted to
+	       mpn_bdiv_q_1 for more machines. */
+	    mpn_divexact_1 (t, t, n, big_base);
+
+	  n -= t[n - 1] == 0;
+	  digits_in_base -= chars_per_limb;
+	}
+
+      shift *= 2;
+      /* Strip low zero limbs, but be careful to keep the result divisible by
+	 big_base.  */
+      while (t[0] == 0 && (t[1] & ((big_base & -big_base) - 1)) == 0)
+	{
+	  t++;
+	  n--;
+	  shift++;
+	}
+      p = t;
+
+      SET_powers_t (pt[0], p, n, digits_in_base, base, shift);
+      pt++;
+    }
+
+  /* Strip any remaining low zero limbs.  */
+  pt -= n_pows + 1;
+  for (long pi = n_pows; pi >= 0; pi--)
+    {
+      mp_ptr t = pt[pi].p;
+      mp_size_t shift = pt[pi].shift;
+      mp_size_t n = pt[pi].n;
+      int c;
+      c = t[0] == 0;
+      t += c;
+      n -= c;
+      shift += c;
+      pt[pi].p = t;
+      pt[pi].shift = shift;
+      pt[pi].n = n;
+    }
+}
+#endif
+
+static long
+powtab_decide (size_t *exptab, size_t un, int base)
+{
+  int chars_per_limb = mp_bases[base].chars_per_limb;
+  long n_pows = 0;
+  for (size_t pn = (un + 1) >> 1; pn != 1; pn = (pn + 1) >> 1)
+    {
+      exptab[n_pows] = pn * chars_per_limb;
+      n_pows++;
+    }
+  exptab[n_pows] = chars_per_limb;
+
+#if HAVE_mpn_compute_powtab_mul && HAVE_mpn_compute_powtab_div
+  size_t pn = un - 1;
+  size_t xn = (un + 1) >> 1;
+  unsigned mcost = 1;
+  unsigned dcost = 1;
+  for (long i = n_pows - 2; i >= 0; i--)
+    {
+      size_t pow = (pn >> (i + 1)) + 1;
+
+      if (pow & 1)
+	dcost += pow;
+
+      if (xn != (pow << i))
+	{
+	  if (pow > 2 && (pow & 1) == 0)
+	    mcost += 2 * pow;
+	  else
+	    mcost += pow;
+	}
+      else
+	{
+	  if (pow & 1)
+	    mcost += pow;
+	}
+    }
+
+  dcost = dcost * DIV_1_VS_MUL_1_PERCENT / 100;
+
+  if (mcost <= dcost)
+    return n_pows;
+  else
+    return -n_pows;
+#elif HAVE_mpn_compute_powtab_mul
+  return n_pows;
+#elif HAVE_mpn_compute_powtab_div
+  return -n_pows;
+#else
+#error "no powtab function available"
+#endif
+}
+
+size_t
+mpn_compute_powtab (powers_t *powtab, mp_ptr powtab_mem, mp_size_t un, int base)
+{
+  size_t exptab[GMP_LIMB_BITS];
+
+  long n_pows = powtab_decide (exptab, un, base);
+
+#if HAVE_mpn_compute_powtab_mul && HAVE_mpn_compute_powtab_div
+  if (n_pows >= 0)
+    {
+      mpn_compute_powtab_mul (powtab, powtab_mem, un, base, exptab, n_pows);
+      return n_pows;
+    }
+  else
+    {
+      mpn_compute_powtab_div (powtab, powtab_mem, un, base, exptab, -n_pows);
+      return -n_pows;
+    }
+#elif HAVE_mpn_compute_powtab_mul
+  ASSERT (n_pows > 0);
+  mpn_compute_powtab_mul (powtab, powtab_mem, un, base, exptab, n_pows);
+  return n_pows;
+#elif HAVE_mpn_compute_powtab_div
+  ASSERT (n_pows < 0);
+  mpn_compute_powtab_div (powtab, powtab_mem, un, base, exptab, -n_pows);
+  return -n_pows;
+#else
+#error "no powtab function available"
+#endif
+}
diff --git a/third_party/gmp/mpn/generic/copyd.c b/third_party/gmp/mpn/generic/copyd.c
new file mode 100644
index 0000000..7def007
--- /dev/null
+++ b/third_party/gmp/mpn/generic/copyd.c
@@ -0,0 +1,40 @@
+/* mpn_copyd
+
+Copyright 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpn_copyd (mp_ptr rp, mp_srcptr up, mp_size_t n)
+{
+  mp_size_t i;
+
+  for (i = n - 1; i >= 0; i--)
+    rp[i] = up[i];
+}
diff --git a/third_party/gmp/mpn/generic/copyi.c b/third_party/gmp/mpn/generic/copyi.c
new file mode 100644
index 0000000..736e0b5
--- /dev/null
+++ b/third_party/gmp/mpn/generic/copyi.c
@@ -0,0 +1,42 @@
+/* mpn_copyi
+
+Copyright 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpn_copyi (mp_ptr rp, mp_srcptr up, mp_size_t n)
+{
+  mp_size_t i;
+
+  up += n;
+  rp += n;
+  for (i = -n; i != 0; i++)
+    rp[i] = up[i];
+}
diff --git a/third_party/gmp/mpn/generic/dcpi1_bdiv_q.c b/third_party/gmp/mpn/generic/dcpi1_bdiv_q.c
new file mode 100644
index 0000000..1a4bd2a
--- /dev/null
+++ b/third_party/gmp/mpn/generic/dcpi1_bdiv_q.c
@@ -0,0 +1,159 @@
+/* mpn_dcpi1_bdiv_q -- divide-and-conquer Hensel division with precomputed
+   inverse, returning quotient.
+
+   Contributed to the GNU project by Niels Möller and Torbjorn Granlund.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright 2006, 2007, 2009-2011, 2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+static mp_size_t
+mpn_dcpi1_bdiv_q_n_itch (mp_size_t n)
+{
+  /* NOTE: Depends on mullo_n and mpn_dcpi1_bdiv_qr_n interface */
+  return n;
+}
+
+/* Computes Q = - N / D mod B^n, destroys N.
+
+   N = {np,n}
+   D = {dp,n}
+*/
+
+static void
+mpn_dcpi1_bdiv_q_n (mp_ptr qp,
+		    mp_ptr np, mp_srcptr dp, mp_size_t n,
+		    mp_limb_t dinv, mp_ptr tp)
+{
+  while (ABOVE_THRESHOLD (n, DC_BDIV_Q_THRESHOLD))
+    {
+      mp_size_t lo, hi;
+      mp_limb_t cy;
+
+      lo = n >> 1;			/* floor(n/2) */
+      hi = n - lo;			/* ceil(n/2) */
+
+      cy = mpn_dcpi1_bdiv_qr_n (qp, np, dp, lo, dinv, tp);
+
+      mpn_mullo_n (tp, qp, dp + hi, lo);
+      mpn_add_n (np + hi, np + hi, tp, lo);
+
+      if (lo < hi)
+	{
+	  cy += mpn_addmul_1 (np + lo, qp, lo, dp[lo]);
+	  np[n - 1] += cy;
+	}
+      qp += lo;
+      np += lo;
+      n -= lo;
+    }
+  mpn_sbpi1_bdiv_q (qp, np, n, dp, n, dinv);
+}
+
+/* Computes Q = - N / D mod B^nn, destroys N.
+
+   N = {np,nn}
+   D = {dp,dn}
+*/
+
+void
+mpn_dcpi1_bdiv_q (mp_ptr qp,
+		  mp_ptr np, mp_size_t nn,
+		  mp_srcptr dp, mp_size_t dn,
+		  mp_limb_t dinv)
+{
+  mp_size_t qn;
+  mp_limb_t cy;
+  mp_ptr tp;
+  TMP_DECL;
+
+  TMP_MARK;
+
+  ASSERT (dn >= 2);
+  ASSERT (nn - dn >= 0);
+  ASSERT (dp[0] & 1);
+
+  tp = TMP_SALLOC_LIMBS (dn);
+
+  qn = nn;
+
+  if (qn > dn)
+    {
+      /* Reduce qn mod dn in a super-efficient manner.  */
+      do
+	qn -= dn;
+      while (qn > dn);
+
+      /* Perform the typically smaller block first.  */
+      if (BELOW_THRESHOLD (qn, DC_BDIV_QR_THRESHOLD))
+	cy = mpn_sbpi1_bdiv_qr (qp, np, 2 * qn, dp, qn, dinv);
+      else
+	cy = mpn_dcpi1_bdiv_qr_n (qp, np, dp, qn, dinv, tp);
+
+      if (qn != dn)
+	{
+	  if (qn > dn - qn)
+	    mpn_mul (tp, qp, qn, dp + qn, dn - qn);
+	  else
+	    mpn_mul (tp, dp + qn, dn - qn, qp, qn);
+	  mpn_incr_u (tp + qn, cy);
+
+	  mpn_add (np + qn, np + qn, nn - qn, tp, dn);
+	  cy = 0;
+	}
+
+      np += qn;
+      qp += qn;
+
+      qn = nn - qn;
+      while (qn > dn)
+	{
+	  mpn_add_1 (np + dn, np + dn, qn - dn, cy);
+	  cy = mpn_dcpi1_bdiv_qr_n (qp, np, dp, dn, dinv, tp);
+	  qp += dn;
+	  np += dn;
+	  qn -= dn;
+	}
+      mpn_dcpi1_bdiv_q_n (qp, np, dp, dn, dinv, tp);
+    }
+  else
+    {
+      if (BELOW_THRESHOLD (qn, DC_BDIV_Q_THRESHOLD))
+	mpn_sbpi1_bdiv_q (qp, np, qn, dp, qn, dinv);
+      else
+	mpn_dcpi1_bdiv_q_n (qp, np, dp, qn, dinv, tp);
+    }
+
+  TMP_FREE;
+}
diff --git a/third_party/gmp/mpn/generic/dcpi1_bdiv_qr.c b/third_party/gmp/mpn/generic/dcpi1_bdiv_qr.c
new file mode 100644
index 0000000..11da44f
--- /dev/null
+++ b/third_party/gmp/mpn/generic/dcpi1_bdiv_qr.c
@@ -0,0 +1,176 @@
+/* mpn_dcpi1_bdiv_qr -- divide-and-conquer Hensel division with precomputed
+   inverse, returning quotient and remainder.
+
+   Contributed to the GNU project by Niels Möller and Torbjorn Granlund.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright 2006, 2007, 2009, 2010, 2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* Computes Hensel binary division of {np, 2*n} by {dp, n}.
+
+   Output:
+
+      q = -n * d^{-1} mod 2^{qn * GMP_NUMB_BITS},
+
+      r = (n + q * d) * 2^{-qn * GMP_NUMB_BITS}
+
+   Stores q at qp. Stores the n least significant limbs of r at the high half
+   of np, and returns the carry from the addition n + q*d.
+
+   d must be odd. dinv is (-d)^-1 mod 2^GMP_NUMB_BITS. */
+
+mp_size_t
+mpn_dcpi1_bdiv_qr_n_itch (mp_size_t n)
+{
+  return n;
+}
+
+mp_limb_t
+mpn_dcpi1_bdiv_qr_n (mp_ptr qp, mp_ptr np, mp_srcptr dp, mp_size_t n,
+		     mp_limb_t dinv, mp_ptr tp)
+{
+  mp_size_t lo, hi;
+  mp_limb_t cy;
+  mp_limb_t rh;
+
+  lo = n >> 1;			/* floor(n/2) */
+  hi = n - lo;			/* ceil(n/2) */
+
+  if (BELOW_THRESHOLD (lo, DC_BDIV_QR_THRESHOLD))
+    cy = mpn_sbpi1_bdiv_qr (qp, np, 2 * lo, dp, lo, dinv);
+  else
+    cy = mpn_dcpi1_bdiv_qr_n (qp, np, dp, lo, dinv, tp);
+
+  mpn_mul (tp, dp + lo, hi, qp, lo);
+
+  mpn_incr_u (tp + lo, cy);
+  rh = mpn_add (np + lo, np + lo, n + hi, tp, n);
+
+  if (BELOW_THRESHOLD (hi, DC_BDIV_QR_THRESHOLD))
+    cy = mpn_sbpi1_bdiv_qr (qp + lo, np + lo, 2 * hi, dp, hi, dinv);
+  else
+    cy = mpn_dcpi1_bdiv_qr_n (qp + lo, np + lo, dp, hi, dinv, tp);
+
+  mpn_mul (tp, qp + lo, hi, dp + hi, lo);
+
+  mpn_incr_u (tp + hi, cy);
+  rh += mpn_add_n (np + n, np + n, tp, n);
+
+  return rh;
+}
+
+mp_limb_t
+mpn_dcpi1_bdiv_qr (mp_ptr qp, mp_ptr np, mp_size_t nn,
+		   mp_srcptr dp, mp_size_t dn, mp_limb_t dinv)
+{
+  mp_size_t qn;
+  mp_limb_t rr, cy;
+  mp_ptr tp;
+  TMP_DECL;
+
+  TMP_MARK;
+
+  ASSERT (dn >= 2);		/* to adhere to mpn_sbpi1_div_qr's limits */
+  ASSERT (nn - dn >= 1);	/* to adhere to mpn_sbpi1_div_qr's limits */
+  ASSERT (dp[0] & 1);
+
+  tp = TMP_SALLOC_LIMBS (dn);
+
+  qn = nn - dn;
+
+  if (qn > dn)
+    {
+      /* Reduce qn mod dn without division, optimizing small operations.  */
+      do
+	qn -= dn;
+      while (qn > dn);
+
+      /* Perform the typically smaller block first.  */
+      if (BELOW_THRESHOLD (qn, DC_BDIV_QR_THRESHOLD))
+	cy = mpn_sbpi1_bdiv_qr (qp, np, 2 * qn, dp, qn, dinv);
+      else
+	cy = mpn_dcpi1_bdiv_qr_n (qp, np, dp, qn, dinv, tp);
+
+      rr = 0;
+      if (qn != dn)
+	{
+	  if (qn > dn - qn)
+	    mpn_mul (tp, qp, qn, dp + qn, dn - qn);
+	  else
+	    mpn_mul (tp, dp + qn, dn - qn, qp, qn);
+	  mpn_incr_u (tp + qn, cy);
+
+	  rr = mpn_add (np + qn, np + qn, nn - qn, tp, dn);
+	  cy = 0;
+	}
+
+      np += qn;
+      qp += qn;
+
+      qn = nn - dn - qn;
+      do
+	{
+	  rr += mpn_add_1 (np + dn, np + dn, qn, cy);
+	  cy = mpn_dcpi1_bdiv_qr_n (qp, np, dp, dn, dinv, tp);
+	  qp += dn;
+	  np += dn;
+	  qn -= dn;
+	}
+      while (qn > 0);
+      TMP_FREE;
+      return rr + cy;
+    }
+
+  if (BELOW_THRESHOLD (qn, DC_BDIV_QR_THRESHOLD))
+    cy = mpn_sbpi1_bdiv_qr (qp, np, 2 * qn, dp, qn, dinv);
+  else
+    cy = mpn_dcpi1_bdiv_qr_n (qp, np, dp, qn, dinv, tp);
+
+  rr = 0;
+  if (qn != dn)
+    {
+      if (qn > dn - qn)
+	mpn_mul (tp, qp, qn, dp + qn, dn - qn);
+      else
+	mpn_mul (tp, dp + qn, dn - qn, qp, qn);
+      mpn_incr_u (tp + qn, cy);
+
+      rr = mpn_add (np + qn, np + qn, nn - qn, tp, dn);
+      cy = 0;
+    }
+
+  TMP_FREE;
+  return rr + cy;
+}
diff --git a/third_party/gmp/mpn/generic/dcpi1_div_q.c b/third_party/gmp/mpn/generic/dcpi1_div_q.c
new file mode 100644
index 0000000..1905c98
--- /dev/null
+++ b/third_party/gmp/mpn/generic/dcpi1_div_q.c
@@ -0,0 +1,86 @@
+/* mpn_dc_div_q -- divide-and-conquer division, returning exact quotient
+   only.
+
+   Contributed to the GNU project by Torbjorn Granlund and Marco Bodrato.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright 2006, 2007, 2009, 2010 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+mp_limb_t
+mpn_dcpi1_div_q (mp_ptr qp, mp_ptr np, mp_size_t nn,
+		 mp_srcptr dp, mp_size_t dn, gmp_pi1_t *dinv)
+{
+  mp_ptr tp, wp;
+  mp_limb_t qh;
+  mp_size_t qn;
+  TMP_DECL;
+
+  TMP_MARK;
+
+  ASSERT (dn >= 6);
+  ASSERT (nn - dn >= 3);
+  ASSERT (dp[dn-1] & GMP_NUMB_HIGHBIT);
+
+  tp = TMP_ALLOC_LIMBS (nn + 1);
+  MPN_COPY (tp + 1, np, nn);
+  tp[0] = 0;
+
+  qn = nn - dn;
+  wp = TMP_ALLOC_LIMBS (qn + 1);
+
+  qh = mpn_dcpi1_divappr_q (wp, tp, nn + 1, dp, dn, dinv);
+
+  if (wp[0] == 0)
+    {
+      mp_limb_t cy;
+
+      if (qn > dn)
+	mpn_mul (tp, wp + 1, qn, dp, dn);
+      else
+	mpn_mul (tp, dp, dn, wp + 1, qn);
+
+      cy = (qh != 0) ? mpn_add_n (tp + qn, tp + qn, dp, dn) : 0;
+
+      if (cy || mpn_cmp (tp, np, nn) > 0) /* At most is wrong by one, no cycle. */
+	qh -= mpn_sub_1 (qp, wp + 1, qn, 1);
+      else /* Same as below */
+	MPN_COPY (qp, wp + 1, qn);
+    }
+  else
+    MPN_COPY (qp, wp + 1, qn);
+
+  TMP_FREE;
+  return qh;
+}
diff --git a/third_party/gmp/mpn/generic/dcpi1_div_qr.c b/third_party/gmp/mpn/generic/dcpi1_div_qr.c
new file mode 100644
index 0000000..d7a65f8
--- /dev/null
+++ b/third_party/gmp/mpn/generic/dcpi1_div_qr.c
@@ -0,0 +1,248 @@
+/* mpn_dcpi1_div_qr_n -- recursive divide-and-conquer division for arbitrary
+   size operands.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright 2006, 2007, 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+mp_limb_t
+mpn_dcpi1_div_qr_n (mp_ptr qp, mp_ptr np, mp_srcptr dp, mp_size_t n,
+		    gmp_pi1_t *dinv, mp_ptr tp)
+{
+  mp_size_t lo, hi;
+  mp_limb_t cy, qh, ql;
+
+  lo = n >> 1;			/* floor(n/2) */
+  hi = n - lo;			/* ceil(n/2) */
+
+  if (BELOW_THRESHOLD (hi, DC_DIV_QR_THRESHOLD))
+    qh = mpn_sbpi1_div_qr (qp + lo, np + 2 * lo, 2 * hi, dp + lo, hi, dinv->inv32);
+  else
+    qh = mpn_dcpi1_div_qr_n (qp + lo, np + 2 * lo, dp + lo, hi, dinv, tp);
+
+  mpn_mul (tp, qp + lo, hi, dp, lo);
+
+  cy = mpn_sub_n (np + lo, np + lo, tp, n);
+  if (qh != 0)
+    cy += mpn_sub_n (np + n, np + n, dp, lo);
+
+  while (cy != 0)
+    {
+      qh -= mpn_sub_1 (qp + lo, qp + lo, hi, 1);
+      cy -= mpn_add_n (np + lo, np + lo, dp, n);
+    }
+
+  if (BELOW_THRESHOLD (lo, DC_DIV_QR_THRESHOLD))
+    ql = mpn_sbpi1_div_qr (qp, np + hi, 2 * lo, dp + hi, lo, dinv->inv32);
+  else
+    ql = mpn_dcpi1_div_qr_n (qp, np + hi, dp + hi, lo, dinv, tp);
+
+  mpn_mul (tp, dp, hi, qp, lo);
+
+  cy = mpn_sub_n (np, np, tp, n);
+  if (ql != 0)
+    cy += mpn_sub_n (np + lo, np + lo, dp, hi);
+
+  while (cy != 0)
+    {
+      mpn_sub_1 (qp, qp, lo, 1);
+      cy -= mpn_add_n (np, np, dp, n);
+    }
+
+  return qh;
+}
+
+mp_limb_t
+mpn_dcpi1_div_qr (mp_ptr qp,
+		  mp_ptr np, mp_size_t nn,
+		  mp_srcptr dp, mp_size_t dn,
+		  gmp_pi1_t *dinv)
+{
+  mp_size_t qn;
+  mp_limb_t qh, cy;
+  mp_ptr tp;
+  TMP_DECL;
+
+  TMP_MARK;
+
+  ASSERT (dn >= 6);		/* to adhere to mpn_sbpi1_div_qr's limits */
+  ASSERT (nn - dn >= 3);	/* to adhere to mpn_sbpi1_div_qr's limits */
+  ASSERT (dp[dn-1] & GMP_NUMB_HIGHBIT);
+
+  tp = TMP_ALLOC_LIMBS (dn);
+
+  qn = nn - dn;
+  qp += qn;
+  np += nn;
+  dp += dn;
+
+  if (qn > dn)
+    {
+      /* Reduce qn mod dn without division, optimizing small operations.  */
+      do
+	qn -= dn;
+      while (qn > dn);
+
+      qp -= qn;			/* point at low limb of next quotient block */
+      np -= qn;			/* point in the middle of partial remainder */
+
+      /* Perform the typically smaller block first.  */
+      if (qn == 1)
+	{
+	  mp_limb_t q, n2, n1, n0, d1, d0;
+
+	  /* Handle qh up front, for simplicity. */
+	  qh = mpn_cmp (np - dn + 1, dp - dn, dn) >= 0;
+	  if (qh)
+	    ASSERT_NOCARRY (mpn_sub_n (np - dn + 1, np - dn + 1, dp - dn, dn));
+
+	  /* A single iteration of schoolbook: One 3/2 division,
+	     followed by the bignum update and adjustment. */
+	  n2 = np[0];
+	  n1 = np[-1];
+	  n0 = np[-2];
+	  d1 = dp[-1];
+	  d0 = dp[-2];
+
+	  ASSERT (n2 < d1 || (n2 == d1 && n1 <= d0));
+
+	  if (UNLIKELY (n2 == d1) && n1 == d0)
+	    {
+	      q = GMP_NUMB_MASK;
+	      cy = mpn_submul_1 (np - dn, dp - dn, dn, q);
+	      ASSERT (cy == n2);
+	    }
+	  else
+	    {
+	      udiv_qr_3by2 (q, n1, n0, n2, n1, n0, d1, d0, dinv->inv32);
+
+	      if (dn > 2)
+		{
+		  mp_limb_t cy, cy1;
+		  cy = mpn_submul_1 (np - dn, dp - dn, dn - 2, q);
+
+		  cy1 = n0 < cy;
+		  n0 = (n0 - cy) & GMP_NUMB_MASK;
+		  cy = n1 < cy1;
+		  n1 = (n1 - cy1) & GMP_NUMB_MASK;
+		  np[-2] = n0;
+
+		  if (UNLIKELY (cy != 0))
+		    {
+		      n1 += d1 + mpn_add_n (np - dn, np - dn, dp - dn, dn - 1);
+		      qh -= (q == 0);
+		      q = (q - 1) & GMP_NUMB_MASK;
+		    }
+		}
+	      else
+		np[-2] = n0;
+
+	      np[-1] = n1;
+	    }
+	  qp[0] = q;
+	}
+      else
+	{
+	  /* Do a 2qn / qn division */
+	  if (qn == 2)
+	    qh = mpn_divrem_2 (qp, 0L, np - 2, 4, dp - 2); /* FIXME: obsolete function. Use 5/3 division? */
+	  else if (BELOW_THRESHOLD (qn, DC_DIV_QR_THRESHOLD))
+	    qh = mpn_sbpi1_div_qr (qp, np - qn, 2 * qn, dp - qn, qn, dinv->inv32);
+	  else
+	    qh = mpn_dcpi1_div_qr_n (qp, np - qn, dp - qn, qn, dinv, tp);
+
+	  if (qn != dn)
+	    {
+	      if (qn > dn - qn)
+		mpn_mul (tp, qp, qn, dp - dn, dn - qn);
+	      else
+		mpn_mul (tp, dp - dn, dn - qn, qp, qn);
+
+	      cy = mpn_sub_n (np - dn, np - dn, tp, dn);
+	      if (qh != 0)
+		cy += mpn_sub_n (np - dn + qn, np - dn + qn, dp - dn, dn - qn);
+
+	      while (cy != 0)
+		{
+		  qh -= mpn_sub_1 (qp, qp, qn, 1);
+		  cy -= mpn_add_n (np - dn, np - dn, dp - dn, dn);
+		}
+	    }
+	}
+
+      qn = nn - dn - qn;
+      do
+	{
+	  qp -= dn;
+	  np -= dn;
+	  mpn_dcpi1_div_qr_n (qp, np - dn, dp - dn, dn, dinv, tp);
+	  qn -= dn;
+	}
+      while (qn > 0);
+    }
+  else
+    {
+      qp -= qn;			/* point at low limb of next quotient block */
+      np -= qn;			/* point in the middle of partial remainder */
+
+      if (BELOW_THRESHOLD (qn, DC_DIV_QR_THRESHOLD))
+	qh = mpn_sbpi1_div_qr (qp, np - qn, 2 * qn, dp - qn, qn, dinv->inv32);
+      else
+	qh = mpn_dcpi1_div_qr_n (qp, np - qn, dp - qn, qn, dinv, tp);
+
+      if (qn != dn)
+	{
+	  if (qn > dn - qn)
+	    mpn_mul (tp, qp, qn, dp - dn, dn - qn);
+	  else
+	    mpn_mul (tp, dp - dn, dn - qn, qp, qn);
+
+	  cy = mpn_sub_n (np - dn, np - dn, tp, dn);
+	  if (qh != 0)
+	    cy += mpn_sub_n (np - dn + qn, np - dn + qn, dp - dn, dn - qn);
+
+	  while (cy != 0)
+	    {
+	      qh -= mpn_sub_1 (qp, qp, qn, 1);
+	      cy -= mpn_add_n (np - dn, np - dn, dp - dn, dn);
+	    }
+	}
+    }
+
+  TMP_FREE;
+  return qh;
+}
diff --git a/third_party/gmp/mpn/generic/dcpi1_divappr_q.c b/third_party/gmp/mpn/generic/dcpi1_divappr_q.c
new file mode 100644
index 0000000..0abe04e
--- /dev/null
+++ b/third_party/gmp/mpn/generic/dcpi1_divappr_q.c
@@ -0,0 +1,256 @@
+/* mpn_dcpi1_divappr_q -- divide-and-conquer division, returning approximate
+   quotient.  The quotient returned is either correct, or one too large.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright 2006, 2007, 2009, 2010 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+static mp_limb_t
+mpn_dcpi1_divappr_q_n (mp_ptr qp, mp_ptr np, mp_srcptr dp, mp_size_t n,
+		       gmp_pi1_t *dinv, mp_ptr tp)
+{
+  mp_size_t lo, hi;
+  mp_limb_t cy, qh, ql;
+
+  lo = n >> 1;			/* floor(n/2) */
+  hi = n - lo;			/* ceil(n/2) */
+
+  if (BELOW_THRESHOLD (hi, DC_DIV_QR_THRESHOLD))
+    qh = mpn_sbpi1_div_qr (qp + lo, np + 2 * lo, 2 * hi, dp + lo, hi, dinv->inv32);
+  else
+    qh = mpn_dcpi1_div_qr_n (qp + lo, np + 2 * lo, dp + lo, hi, dinv, tp);
+
+  mpn_mul (tp, qp + lo, hi, dp, lo);
+
+  cy = mpn_sub_n (np + lo, np + lo, tp, n);
+  if (qh != 0)
+    cy += mpn_sub_n (np + n, np + n, dp, lo);
+
+  while (cy != 0)
+    {
+      qh -= mpn_sub_1 (qp + lo, qp + lo, hi, 1);
+      cy -= mpn_add_n (np + lo, np + lo, dp, n);
+    }
+
+  if (BELOW_THRESHOLD (lo, DC_DIVAPPR_Q_THRESHOLD))
+    ql = mpn_sbpi1_divappr_q (qp, np + hi, 2 * lo, dp + hi, lo, dinv->inv32);
+  else
+    ql = mpn_dcpi1_divappr_q_n (qp, np + hi, dp + hi, lo, dinv, tp);
+
+  if (UNLIKELY (ql != 0))
+    {
+      mp_size_t i;
+      for (i = 0; i < lo; i++)
+	qp[i] = GMP_NUMB_MASK;
+    }
+
+  return qh;
+}
+
+mp_limb_t
+mpn_dcpi1_divappr_q (mp_ptr qp, mp_ptr np, mp_size_t nn,
+		     mp_srcptr dp, mp_size_t dn, gmp_pi1_t *dinv)
+{
+  mp_size_t qn;
+  mp_limb_t qh, cy, qsave;
+  mp_ptr tp;
+  TMP_DECL;
+
+  TMP_MARK;
+
+  ASSERT (dn >= 6);
+  ASSERT (nn > dn);
+  ASSERT (dp[dn-1] & GMP_NUMB_HIGHBIT);
+
+  qn = nn - dn;
+  qp += qn;
+  np += nn;
+  dp += dn;
+
+  if (qn >= dn)
+    {
+      qn++;			/* pretend we'll need an extra limb */
+      /* Reduce qn mod dn without division, optimizing small operations.  */
+      do
+	qn -= dn;
+      while (qn > dn);
+
+      qp -= qn;			/* point at low limb of next quotient block */
+      np -= qn;			/* point in the middle of partial remainder */
+
+      tp = TMP_SALLOC_LIMBS (dn);
+
+      /* Perform the typically smaller block first.  */
+      if (qn == 1)
+	{
+	  mp_limb_t q, n2, n1, n0, d1, d0;
+
+	  /* Handle qh up front, for simplicity. */
+	  qh = mpn_cmp (np - dn + 1, dp - dn, dn) >= 0;
+	  if (qh)
+	    ASSERT_NOCARRY (mpn_sub_n (np - dn + 1, np - dn + 1, dp - dn, dn));
+
+	  /* A single iteration of schoolbook: One 3/2 division,
+	     followed by the bignum update and adjustment. */
+	  n2 = np[0];
+	  n1 = np[-1];
+	  n0 = np[-2];
+	  d1 = dp[-1];
+	  d0 = dp[-2];
+
+	  ASSERT (n2 < d1 || (n2 == d1 && n1 <= d0));
+
+	  if (UNLIKELY (n2 == d1) && n1 == d0)
+	    {
+	      q = GMP_NUMB_MASK;
+	      cy = mpn_submul_1 (np - dn, dp - dn, dn, q);
+	      ASSERT (cy == n2);
+	    }
+	  else
+	    {
+	      udiv_qr_3by2 (q, n1, n0, n2, n1, n0, d1, d0, dinv->inv32);
+
+	      if (dn > 2)
+		{
+		  mp_limb_t cy, cy1;
+		  cy = mpn_submul_1 (np - dn, dp - dn, dn - 2, q);
+
+		  cy1 = n0 < cy;
+		  n0 = (n0 - cy) & GMP_NUMB_MASK;
+		  cy = n1 < cy1;
+		  n1 = (n1 - cy1) & GMP_NUMB_MASK;
+		  np[-2] = n0;
+
+		  if (UNLIKELY (cy != 0))
+		    {
+		      n1 += d1 + mpn_add_n (np - dn, np - dn, dp - dn, dn - 1);
+		      qh -= (q == 0);
+		      q = (q - 1) & GMP_NUMB_MASK;
+		    }
+		}
+	      else
+		np[-2] = n0;
+
+	      np[-1] = n1;
+	    }
+	  qp[0] = q;
+	}
+      else
+	{
+	  if (qn == 2)
+	    qh = mpn_divrem_2 (qp, 0L, np - 2, 4, dp - 2);
+	  else if (BELOW_THRESHOLD (qn, DC_DIV_QR_THRESHOLD))
+	    qh = mpn_sbpi1_div_qr (qp, np - qn, 2 * qn, dp - qn, qn, dinv->inv32);
+	  else
+	    qh = mpn_dcpi1_div_qr_n (qp, np - qn, dp - qn, qn, dinv, tp);
+
+	  if (qn != dn)
+	    {
+	      if (qn > dn - qn)
+		mpn_mul (tp, qp, qn, dp - dn, dn - qn);
+	      else
+		mpn_mul (tp, dp - dn, dn - qn, qp, qn);
+
+	      cy = mpn_sub_n (np - dn, np - dn, tp, dn);
+	      if (qh != 0)
+		cy += mpn_sub_n (np - dn + qn, np - dn + qn, dp - dn, dn - qn);
+
+	      while (cy != 0)
+		{
+		  qh -= mpn_sub_1 (qp, qp, qn, 1);
+		  cy -= mpn_add_n (np - dn, np - dn, dp - dn, dn);
+		}
+	    }
+	}
+      qn = nn - dn - qn + 1;
+      while (qn > dn)
+	{
+	  qp -= dn;
+	  np -= dn;
+	  mpn_dcpi1_div_qr_n (qp, np - dn, dp - dn, dn, dinv, tp);
+	  qn -= dn;
+	}
+
+      /* Since we pretended we'd need an extra quotient limb before, we now
+	 have made sure the code above left just dn-1=qn quotient limbs to
+	 develop.  Develop that plus a guard limb. */
+      qn--;
+      qp -= qn;
+      np -= dn;
+      qsave = qp[qn];
+      mpn_dcpi1_divappr_q_n (qp, np - dn, dp - dn, dn, dinv, tp);
+      MPN_COPY_INCR (qp, qp + 1, qn);
+      qp[qn] = qsave;
+    }
+  else    /* (qn < dn) */
+    {
+      mp_ptr q2p;
+#if 0				/* not possible since we demand nn > dn */
+      if (qn == 0)
+	{
+	  qh = mpn_cmp (np - dn, dp - dn, dn) >= 0;
+	  if (qh)
+	    mpn_sub_n (np - dn, np - dn, dp - dn, dn);
+	  TMP_FREE;
+	  return qh;
+	}
+#endif
+
+      qp -= qn;			/* point at low limb of next quotient block */
+      np -= qn;			/* point in the middle of partial remainder */
+
+      q2p = TMP_SALLOC_LIMBS (qn + 1);
+      /* Should we at all check DC_DIVAPPR_Q_THRESHOLD here, or reply on
+	 callers not to be silly?  */
+      if (BELOW_THRESHOLD (qn, DC_DIVAPPR_Q_THRESHOLD))
+	{
+	  qh = mpn_sbpi1_divappr_q (q2p, np - qn - 2, 2 * (qn + 1),
+				    dp - (qn + 1), qn + 1, dinv->inv32);
+	}
+      else
+	{
+	  /* It is tempting to use qp for recursive scratch and put quotient in
+	     tp, but the recursive scratch needs one limb too many.  */
+	  tp = TMP_SALLOC_LIMBS (qn + 1);
+	  qh = mpn_dcpi1_divappr_q_n (q2p, np - qn - 2, dp - (qn + 1), qn + 1, dinv, tp);
+	}
+      MPN_COPY (qp, q2p + 1, qn);
+    }
+
+  TMP_FREE;
+  return qh;
+}
diff --git a/third_party/gmp/mpn/generic/div_q.c b/third_party/gmp/mpn/generic/div_q.c
new file mode 100644
index 0000000..18c4ecf
--- /dev/null
+++ b/third_party/gmp/mpn/generic/div_q.c
@@ -0,0 +1,313 @@
+/* mpn_div_q -- division for arbitrary size operands.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright 2009, 2010, 2015, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* Compute Q = N/D with truncation.
+     N = {np,nn}
+     D = {dp,dn}
+     Q = {qp,nn-dn+1}
+     T = {scratch,nn+1} is scratch space
+   N and D are both untouched by the computation.
+   N and T may overlap; pass the same space if N is irrelevant after the call,
+   but note that tp needs an extra limb.
+
+   Operand requirements:
+     N >= D > 0
+     dp[dn-1] != 0
+     No overlap between the N, D, and Q areas.
+
+   This division function does not clobber its input operands, since it is
+   intended to support average-O(qn) division, and for that to be effective, it
+   cannot put requirements on callers to copy a O(nn) operand.
+
+   If a caller does not care about the value of {np,nn+1} after calling this
+   function, it should pass np also for the scratch argument.  This function
+   will then save some time and space by avoiding allocation and copying.
+   (FIXME: Is this a good design?  We only really save any copying for
+   already-normalised divisors, which should be rare.  It also prevents us from
+   reasonably asking for all scratch space we need.)
+
+   We write nn-dn+1 limbs for the quotient, but return void.  Why not return
+   the most significant quotient limb?  Look at the 4 main code blocks below
+   (consisting of an outer if-else where each arm contains an if-else). It is
+   tricky for the first code block, since the mpn_*_div_q calls will typically
+   generate all nn-dn+1 and return 0 or 1.  I don't see how to fix that unless
+   we generate the most significant quotient limb here, before calling
+   mpn_*_div_q, or put the quotient in a temporary area.  Since this is a
+   critical division case (the SB sub-case in particular) copying is not a good
+   idea.
+
+   It might make sense to split the if-else parts of the (qn + FUDGE
+   >= dn) blocks into separate functions, since we could promise quite
+   different things to callers in these two cases.  The 'then' case
+   benefits from np=scratch, and it could perhaps even tolerate qp=np,
+   saving some headache for many callers.
+
+   FIXME: Scratch allocation leaves a lot to be desired.  E.g., for the MU size
+   operands, we do not reuse the huge scratch for adjustments.  This can be a
+   serious waste of memory for the largest operands.
+*/
+
+/* FUDGE determines when to try getting an approximate quotient from the upper
+   parts of the dividend and divisor, then adjust.  N.B. FUDGE must be >= 2
+   for the code to be correct.  */
+#define FUDGE 5			/* FIXME: tune this */
+
+#define DC_DIV_Q_THRESHOLD      DC_DIVAPPR_Q_THRESHOLD
+#define MU_DIV_Q_THRESHOLD      MU_DIVAPPR_Q_THRESHOLD
+#define MUPI_DIV_Q_THRESHOLD  MUPI_DIVAPPR_Q_THRESHOLD
+#ifndef MUPI_DIVAPPR_Q_THRESHOLD
+#define MUPI_DIVAPPR_Q_THRESHOLD  MUPI_DIV_QR_THRESHOLD
+#endif
+
+void
+mpn_div_q (mp_ptr qp,
+	   mp_srcptr np, mp_size_t nn,
+	   mp_srcptr dp, mp_size_t dn, mp_ptr scratch)
+{
+  mp_ptr new_dp, new_np, tp, rp;
+  mp_limb_t cy, dh, qh;
+  mp_size_t new_nn, qn;
+  gmp_pi1_t dinv;
+  int cnt;
+  TMP_DECL;
+  TMP_MARK;
+
+  ASSERT (nn >= dn);
+  ASSERT (dn > 0);
+  ASSERT (dp[dn - 1] != 0);
+  ASSERT (! MPN_OVERLAP_P (qp, nn - dn + 1, np, nn));
+  ASSERT (! MPN_OVERLAP_P (qp, nn - dn + 1, dp, dn));
+  ASSERT (MPN_SAME_OR_SEPARATE_P (np, scratch, nn));
+
+  ASSERT_ALWAYS (FUDGE >= 2);
+
+  dh = dp[dn - 1];
+  if (dn == 1)
+    {
+      mpn_divrem_1 (qp, 0L, np, nn, dh);
+      return;
+    }
+
+  qn = nn - dn + 1;		/* Quotient size, high limb might be zero */
+
+  if (qn + FUDGE >= dn)
+    {
+      /* |________________________|
+                          |_______|  */
+      new_np = scratch;
+
+      if (LIKELY ((dh & GMP_NUMB_HIGHBIT) == 0))
+	{
+	  count_leading_zeros (cnt, dh);
+
+	  cy = mpn_lshift (new_np, np, nn, cnt);
+	  new_np[nn] = cy;
+	  new_nn = nn + (cy != 0);
+
+	  new_dp = TMP_ALLOC_LIMBS (dn);
+	  mpn_lshift (new_dp, dp, dn, cnt);
+
+	  if (dn == 2)
+	    {
+	      qh = mpn_divrem_2 (qp, 0L, new_np, new_nn, new_dp);
+	    }
+	  else if (BELOW_THRESHOLD (dn, DC_DIV_Q_THRESHOLD) ||
+		   BELOW_THRESHOLD (new_nn - dn, DC_DIV_Q_THRESHOLD))
+	    {
+	      invert_pi1 (dinv, new_dp[dn - 1], new_dp[dn - 2]);
+	      qh = mpn_sbpi1_div_q (qp, new_np, new_nn, new_dp, dn, dinv.inv32);
+	    }
+	  else if (BELOW_THRESHOLD (dn, MUPI_DIV_Q_THRESHOLD) ||   /* fast condition */
+		   BELOW_THRESHOLD (nn, 2 * MU_DIV_Q_THRESHOLD) || /* fast condition */
+		   (double) (2 * (MU_DIV_Q_THRESHOLD - MUPI_DIV_Q_THRESHOLD)) * dn /* slow... */
+		   + (double) MUPI_DIV_Q_THRESHOLD * nn > (double) dn * nn)   /* ...condition */
+	    {
+	      invert_pi1 (dinv, new_dp[dn - 1], new_dp[dn - 2]);
+	      qh = mpn_dcpi1_div_q (qp, new_np, new_nn, new_dp, dn, &dinv);
+	    }
+	  else
+	    {
+	      mp_size_t itch = mpn_mu_div_q_itch (new_nn, dn, 0);
+	      mp_ptr scratch = TMP_ALLOC_LIMBS (itch);
+	      qh = mpn_mu_div_q (qp, new_np, new_nn, new_dp, dn, scratch);
+	    }
+	  if (cy == 0)
+	    qp[qn - 1] = qh;
+	  else
+	    ASSERT (qh == 0);
+	}
+      else  /* divisor is already normalised */
+	{
+	  if (new_np != np)
+	    MPN_COPY (new_np, np, nn);
+
+	  if (dn == 2)
+	    {
+	      qh = mpn_divrem_2 (qp, 0L, new_np, nn, dp);
+	    }
+	  else if (BELOW_THRESHOLD (dn, DC_DIV_Q_THRESHOLD) ||
+		   BELOW_THRESHOLD (nn - dn, DC_DIV_Q_THRESHOLD))
+	    {
+	      invert_pi1 (dinv, dh, dp[dn - 2]);
+	      qh = mpn_sbpi1_div_q (qp, new_np, nn, dp, dn, dinv.inv32);
+	    }
+	  else if (BELOW_THRESHOLD (dn, MUPI_DIV_Q_THRESHOLD) ||   /* fast condition */
+		   BELOW_THRESHOLD (nn, 2 * MU_DIV_Q_THRESHOLD) || /* fast condition */
+		   (double) (2 * (MU_DIV_Q_THRESHOLD - MUPI_DIV_Q_THRESHOLD)) * dn /* slow... */
+		   + (double) MUPI_DIV_Q_THRESHOLD * nn > (double) dn * nn)   /* ...condition */
+	    {
+	      invert_pi1 (dinv, dh, dp[dn - 2]);
+	      qh = mpn_dcpi1_div_q (qp, new_np, nn, dp, dn, &dinv);
+	    }
+	  else
+	    {
+	      mp_size_t itch = mpn_mu_div_q_itch (nn, dn, 0);
+	      mp_ptr scratch = TMP_ALLOC_LIMBS (itch);
+	      qh = mpn_mu_div_q (qp, np, nn, dp, dn, scratch);
+	    }
+	  qp[nn - dn] = qh;
+	}
+    }
+  else
+    {
+      /* |________________________|
+                |_________________|  */
+      tp = TMP_ALLOC_LIMBS (qn + 1);
+
+      new_np = scratch;
+      new_nn = 2 * qn + 1;
+      if (new_np == np)
+	/* We need {np,nn} to remain untouched until the final adjustment, so
+	   we need to allocate separate space for new_np.  */
+	new_np = TMP_ALLOC_LIMBS (new_nn + 1);
+
+
+      if (LIKELY ((dh & GMP_NUMB_HIGHBIT) == 0))
+	{
+	  count_leading_zeros (cnt, dh);
+
+	  cy = mpn_lshift (new_np, np + nn - new_nn, new_nn, cnt);
+	  new_np[new_nn] = cy;
+
+	  new_nn += (cy != 0);
+
+	  new_dp = TMP_ALLOC_LIMBS (qn + 1);
+	  mpn_lshift (new_dp, dp + dn - (qn + 1), qn + 1, cnt);
+	  new_dp[0] |= dp[dn - (qn + 1) - 1] >> (GMP_NUMB_BITS - cnt);
+
+	  if (qn + 1 == 2)
+	    {
+	      qh = mpn_divrem_2 (tp, 0L, new_np, new_nn, new_dp);
+	    }
+	  else if (BELOW_THRESHOLD (qn, DC_DIVAPPR_Q_THRESHOLD - 1))
+	    {
+	      invert_pi1 (dinv, new_dp[qn], new_dp[qn - 1]);
+	      qh = mpn_sbpi1_divappr_q (tp, new_np, new_nn, new_dp, qn + 1, dinv.inv32);
+	    }
+	  else if (BELOW_THRESHOLD (qn, MU_DIVAPPR_Q_THRESHOLD - 1))
+	    {
+	      invert_pi1 (dinv, new_dp[qn], new_dp[qn - 1]);
+	      qh = mpn_dcpi1_divappr_q (tp, new_np, new_nn, new_dp, qn + 1, &dinv);
+	    }
+	  else
+	    {
+	      mp_size_t itch = mpn_mu_divappr_q_itch (new_nn, qn + 1, 0);
+	      mp_ptr scratch = TMP_ALLOC_LIMBS (itch);
+	      qh = mpn_mu_divappr_q (tp, new_np, new_nn, new_dp, qn + 1, scratch);
+	    }
+	  if (cy == 0)
+	    tp[qn] = qh;
+	  else if (UNLIKELY (qh != 0))
+	    {
+	      /* This happens only when the quotient is close to B^n and
+		 mpn_*_divappr_q returned B^n.  */
+	      mp_size_t i, n;
+	      n = new_nn - (qn + 1);
+	      for (i = 0; i < n; i++)
+		tp[i] = GMP_NUMB_MAX;
+	      qh = 0;		/* currently ignored */
+	    }
+	}
+      else  /* divisor is already normalised */
+	{
+	  MPN_COPY (new_np, np + nn - new_nn, new_nn); /* pointless if MU will be used */
+
+	  new_dp = (mp_ptr) dp + dn - (qn + 1);
+
+	  if (qn == 2 - 1)
+	    {
+	      qh = mpn_divrem_2 (tp, 0L, new_np, new_nn, new_dp);
+	    }
+	  else if (BELOW_THRESHOLD (qn, DC_DIVAPPR_Q_THRESHOLD - 1))
+	    {
+	      invert_pi1 (dinv, dh, new_dp[qn - 1]);
+	      qh = mpn_sbpi1_divappr_q (tp, new_np, new_nn, new_dp, qn + 1, dinv.inv32);
+	    }
+	  else if (BELOW_THRESHOLD (qn, MU_DIVAPPR_Q_THRESHOLD - 1))
+	    {
+	      invert_pi1 (dinv, dh, new_dp[qn - 1]);
+	      qh = mpn_dcpi1_divappr_q (tp, new_np, new_nn, new_dp, qn + 1, &dinv);
+	    }
+	  else
+	    {
+	      mp_size_t itch = mpn_mu_divappr_q_itch (new_nn, qn + 1, 0);
+	      mp_ptr scratch = TMP_ALLOC_LIMBS (itch);
+	      qh = mpn_mu_divappr_q (tp, new_np, new_nn, new_dp, qn + 1, scratch);
+	    }
+	  tp[qn] = qh;
+	}
+
+      MPN_COPY (qp, tp + 1, qn);
+      if (tp[0] <= 4)
+        {
+	  mp_size_t rn;
+
+          rp = TMP_ALLOC_LIMBS (dn + qn);
+          mpn_mul (rp, dp, dn, tp + 1, qn);
+	  rn = dn + qn;
+	  rn -= rp[rn - 1] == 0;
+
+          if (rn > nn || mpn_cmp (np, rp, nn) < 0)
+            MPN_DECR_U (qp, qn, 1);
+        }
+    }
+
+  TMP_FREE;
+}
diff --git a/third_party/gmp/mpn/generic/div_qr_1.c b/third_party/gmp/mpn/generic/div_qr_1.c
new file mode 100644
index 0000000..8f80d37
--- /dev/null
+++ b/third_party/gmp/mpn/generic/div_qr_1.c
@@ -0,0 +1,125 @@
+/* mpn_div_qr_1 -- mpn by limb division.
+
+   Contributed to the GNU project by Niels Möller and Torbjörn Granlund
+
+Copyright 1991, 1993, 1994, 1996, 1998-2000, 2002, 2003, 2013 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#ifndef DIV_QR_1_NORM_THRESHOLD
+#define DIV_QR_1_NORM_THRESHOLD 3
+#endif
+#ifndef DIV_QR_1_UNNORM_THRESHOLD
+#define DIV_QR_1_UNNORM_THRESHOLD 3
+#endif
+
+#if GMP_NAIL_BITS > 0
+#error Nail bits not supported
+#endif
+
+/* Divides {up, n} by d. Writes the n-1 low quotient limbs at {qp,
+ * n-1}, and the high quotient limb at *qh. Returns remainder. */
+mp_limb_t
+mpn_div_qr_1 (mp_ptr qp, mp_limb_t *qh, mp_srcptr up, mp_size_t n,
+	      mp_limb_t d)
+{
+  unsigned cnt;
+  mp_limb_t uh;
+
+  ASSERT (n > 0);
+  ASSERT (d > 0);
+
+  if (d & GMP_NUMB_HIGHBIT)
+    {
+      /* Normalized case */
+      mp_limb_t dinv, q;
+
+      uh = up[--n];
+
+      q = (uh >= d);
+      *qh = q;
+      uh -= (-q) & d;
+
+      if (BELOW_THRESHOLD (n, DIV_QR_1_NORM_THRESHOLD))
+	{
+	  cnt = 0;
+	plain:
+	  while (n > 0)
+	    {
+	      mp_limb_t ul = up[--n];
+	      udiv_qrnnd (qp[n], uh, uh, ul, d);
+	    }
+	  return uh >> cnt;
+	}
+      invert_limb (dinv, d);
+      return mpn_div_qr_1n_pi1 (qp, up, n, uh, d, dinv);
+    }
+  else
+    {
+      /* Unnormalized case */
+      mp_limb_t dinv, ul;
+
+      if (! UDIV_NEEDS_NORMALIZATION
+	  && BELOW_THRESHOLD (n, DIV_QR_1_UNNORM_THRESHOLD))
+	{
+	  uh = up[--n];
+	  udiv_qrnnd (*qh, uh, CNST_LIMB(0), uh, d);
+	  cnt = 0;
+	  goto plain;
+	}
+
+      count_leading_zeros (cnt, d);
+      d <<= cnt;
+
+#if HAVE_NATIVE_mpn_div_qr_1u_pi1
+      /* FIXME: Call loop doing on-the-fly normalization */
+#endif
+
+      /* Shift up front, use qp area for shifted copy. A bit messy,
+	 since we have only n-1 limbs available, and shift the high
+	 limb manually. */
+      uh = up[--n];
+      ul = (uh << cnt) | mpn_lshift (qp, up, n, cnt);
+      uh >>= (GMP_LIMB_BITS - cnt);
+
+      if (UDIV_NEEDS_NORMALIZATION
+	  && BELOW_THRESHOLD (n, DIV_QR_1_UNNORM_THRESHOLD))
+	{
+	  udiv_qrnnd (*qh, uh, uh, ul, d);
+	  up = qp;
+	  goto plain;
+	}
+      invert_limb (dinv, d);
+
+      udiv_qrnnd_preinv (*qh, uh, uh, ul, d, dinv);
+      return mpn_div_qr_1n_pi1 (qp, qp, n, uh, d, dinv) >> cnt;
+    }
+}
diff --git a/third_party/gmp/mpn/generic/div_qr_1n_pi1.c b/third_party/gmp/mpn/generic/div_qr_1n_pi1.c
new file mode 100644
index 0000000..5c32810
--- /dev/null
+++ b/third_party/gmp/mpn/generic/div_qr_1n_pi1.c
@@ -0,0 +1,277 @@
+/* mpn_div_qr_1n_pi1
+
+   Contributed to the GNU project by Niels Möller
+
+   THIS FILE CONTAINS INTERNAL FUNCTIONS WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+
+Copyright 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#if GMP_NAIL_BITS > 0
+#error Nail bits not supported
+#endif
+
+#ifndef DIV_QR_1N_METHOD
+#define DIV_QR_1N_METHOD 2
+#endif
+
+/* FIXME: Duplicated in mod_1_1.c. Move to gmp-impl.h */
+
+#if defined (__GNUC__) && ! defined (NO_ASM)
+
+#if HAVE_HOST_CPU_FAMILY_x86 && W_TYPE_SIZE == 32
+#define add_mssaaaa(m, s1, s0, a1, a0, b1, b0)				\
+  __asm__ (  "add	%6, %k2\n\t"					\
+	     "adc	%4, %k1\n\t"					\
+	     "sbb	%k0, %k0"					\
+	   : "=r" (m), "=r" (s1), "=&r" (s0)				\
+	   : "1"  ((USItype)(a1)), "g" ((USItype)(b1)),			\
+	     "%2" ((USItype)(a0)), "g" ((USItype)(b0)))
+#endif
+
+#if HAVE_HOST_CPU_FAMILY_x86_64 && W_TYPE_SIZE == 64
+#define add_mssaaaa(m, s1, s0, a1, a0, b1, b0)				\
+  __asm__ (  "add	%6, %q2\n\t"					\
+	     "adc	%4, %q1\n\t"					\
+	     "sbb	%q0, %q0"					\
+	   : "=r" (m), "=r" (s1), "=&r" (s0)				\
+	   : "1"  ((UDItype)(a1)), "rme" ((UDItype)(b1)),		\
+	     "%2" ((UDItype)(a0)), "rme" ((UDItype)(b0)))
+#endif
+
+#if defined (__sparc__) && W_TYPE_SIZE == 32
+#define add_mssaaaa(m, sh, sl, ah, al, bh, bl)				\
+  __asm__ (  "addcc	%r5, %6, %2\n\t"				\
+	     "addxcc	%r3, %4, %1\n\t"				\
+	     "subx	%%g0, %%g0, %0"					\
+	   : "=r" (m), "=r" (sh), "=&r" (sl)				\
+	   : "rJ" (ah), "rI" (bh), "%rJ" (al), "rI" (bl)		\
+	 __CLOBBER_CC)
+#endif
+
+#if defined (__sparc__) && W_TYPE_SIZE == 64
+#define add_mssaaaa(m, sh, sl, ah, al, bh, bl)				\
+  __asm__ (  "addcc	%r5, %6, %2\n\t"				\
+	     "addccc	%r7, %8, %%g0\n\t"				\
+	     "addccc	%r3, %4, %1\n\t"				\
+	     "clr	%0\n\t"						\
+	     "movcs	%%xcc, -1, %0"					\
+	   : "=r" (m), "=r" (sh), "=&r" (sl)				\
+	   : "rJ" (ah), "rI" (bh), "%rJ" (al), "rI" (bl),		\
+	     "rJ" ((al) >> 32), "rI" ((bl) >> 32)			\
+	 __CLOBBER_CC)
+#if __VIS__ >= 0x300
+#undef add_mssaaaa
+#define add_mssaaaa(m, sh, sl, ah, al, bh, bl)				\
+  __asm__ (  "addcc	%r5, %6, %2\n\t"				\
+	     "addxccc	%r3, %4, %1\n\t"				\
+	     "clr	%0\n\t"						\
+	     "movcs	%%xcc, -1, %0"					\
+	   : "=r" (m), "=r" (sh), "=&r" (sl)				\
+	   : "rJ" (ah), "rI" (bh), "%rJ" (al), "rI" (bl)		\
+	 __CLOBBER_CC)
+#endif
+#endif
+
+#if HAVE_HOST_CPU_FAMILY_powerpc && !defined (_LONG_LONG_LIMB)
+/* This works fine for 32-bit and 64-bit limbs, except for 64-bit limbs with a
+   processor running in 32-bit mode, since the carry flag then gets the 32-bit
+   carry.  */
+#define add_mssaaaa(m, s1, s0, a1, a0, b1, b0)				\
+  __asm__ (  "add%I6c	%2, %5, %6\n\t"					\
+	     "adde	%1, %3, %4\n\t"					\
+	     "subfe	%0, %0, %0\n\t"					\
+	     "nor	%0, %0, %0"					\
+	   : "=r" (m), "=r" (s1), "=&r" (s0)				\
+	   : "r"  (a1), "r" (b1), "%r" (a0), "rI" (b0)			\
+	   __CLOBBER_CC)
+#endif
+
+#if defined (__s390x__) && W_TYPE_SIZE == 64
+#define add_mssaaaa(m, s1, s0, a1, a0, b1, b0)				\
+  __asm__ (  "algr	%2, %6\n\t"					\
+	     "alcgr	%1, %4\n\t"					\
+	     "lghi	%0, 0\n\t"					\
+	     "alcgr	%0, %0\n\t"					\
+	     "lcgr	%0, %0"						\
+	   : "=r" (m), "=r" (s1), "=&r" (s0)				\
+	   : "1"  ((UDItype)(a1)), "r" ((UDItype)(b1)),			\
+	     "%2" ((UDItype)(a0)), "r" ((UDItype)(b0)) __CLOBBER_CC)
+#endif
+
+#if defined (__arm__) && !defined (__thumb__) && W_TYPE_SIZE == 32
+#define add_mssaaaa(m, sh, sl, ah, al, bh, bl)				\
+  __asm__ (  "adds	%2, %5, %6\n\t"					\
+	     "adcs	%1, %3, %4\n\t"					\
+	     "movcc	%0, #0\n\t"					\
+	     "movcs	%0, #-1"					\
+	   : "=r" (m), "=r" (sh), "=&r" (sl)				\
+	   : "r" (ah), "rI" (bh), "%r" (al), "rI" (bl) __CLOBBER_CC)
+#endif
+#endif /* defined (__GNUC__) */
+
+#ifndef add_mssaaaa
+#define add_mssaaaa(m, s1, s0, a1, a0, b1, b0)				\
+  do {									\
+    UWtype __s0, __s1, __c0, __c1;					\
+    __s0 = (a0) + (b0);							\
+    __s1 = (a1) + (b1);							\
+    __c0 = __s0 < (a0);							\
+    __c1 = __s1 < (a1);							\
+    (s0) = __s0;							\
+    __s1 = __s1 + __c0;							\
+    (s1) = __s1;							\
+    (m) = - (__c1 + (__s1 < __c0));					\
+  } while (0)
+#endif
+
+#if DIV_QR_1N_METHOD == 1
+
+/* Divides (uh B^n + {up, n}) by d, storing the quotient at {qp, n}.
+   Requires that uh < d. */
+mp_limb_t
+mpn_div_qr_1n_pi1 (mp_ptr qp, mp_srcptr up, mp_size_t n, mp_limb_t uh,
+		   mp_limb_t d, mp_limb_t dinv)
+{
+  ASSERT (n > 0);
+  ASSERT (uh < d);
+  ASSERT (d & GMP_NUMB_HIGHBIT);
+  ASSERT (MPN_SAME_OR_SEPARATE_P (qp, up, n));
+
+  do
+    {
+      mp_limb_t q, ul;
+
+      ul = up[--n];
+      udiv_qrnnd_preinv (q, uh, uh, ul, d, dinv);
+      qp[n] = q;
+    }
+  while (n > 0);
+
+  return uh;
+}
+
+#elif DIV_QR_1N_METHOD == 2
+
+mp_limb_t
+mpn_div_qr_1n_pi1 (mp_ptr qp, mp_srcptr up, mp_size_t n, mp_limb_t u1,
+		   mp_limb_t d, mp_limb_t dinv)
+{
+  mp_limb_t B2;
+  mp_limb_t u0, u2;
+  mp_limb_t q0, q1;
+  mp_limb_t p0, p1;
+  mp_limb_t t;
+  mp_size_t j;
+
+  ASSERT (d & GMP_LIMB_HIGHBIT);
+  ASSERT (n > 0);
+  ASSERT (u1 < d);
+
+  if (n == 1)
+    {
+      udiv_qrnnd_preinv (qp[0], u1, u1, up[0], d, dinv);
+      return u1;
+    }
+
+  /* FIXME: Could be precomputed */
+  B2 = -d*dinv;
+
+  umul_ppmm (q1, q0, dinv, u1);
+  umul_ppmm (p1, p0, B2, u1);
+  q1 += u1;
+  ASSERT (q1 >= u1);
+  u0 = up[n-1];	/* Early read, to allow qp == up. */
+  qp[n-1] = q1;
+
+  add_mssaaaa (u2, u1, u0, u0, up[n-2], p1, p0);
+
+  /* FIXME: Keep q1 in a variable between iterations, to reduce number
+     of memory accesses. */
+  for (j = n-2; j-- > 0; )
+    {
+      mp_limb_t q2, cy;
+
+      /* Additions for the q update:
+       *	+-------+
+       *        |u1 * v |
+       *        +---+---+
+       *        | u1|
+       *    +---+---+
+       *    | 1 | v |  (conditional on u2)
+       *    +---+---+
+       *        | 1 |  (conditional on u0 + u2 B2 carry)
+       *        +---+
+       * +      | q0|
+       *   -+---+---+---+
+       *    | q2| q1| q0|
+       *    +---+---+---+
+      */
+      umul_ppmm (p1, t, u1, dinv);
+      add_ssaaaa (q2, q1, -u2, u2 & dinv, CNST_LIMB(0), u1);
+      add_ssaaaa (q2, q1, q2, q1, CNST_LIMB(0), p1);
+      add_ssaaaa (q2, q1, q2, q1, CNST_LIMB(0), q0);
+      q0 = t;
+
+      umul_ppmm (p1, p0, u1, B2);
+      ADDC_LIMB (cy, u0, u0, u2 & B2);
+      u0 -= (-cy) & d;
+
+      /* Final q update */
+      add_ssaaaa (q2, q1, q2, q1, CNST_LIMB(0), cy);
+      qp[j+1] = q1;
+      MPN_INCR_U (qp+j+2, n-j-2, q2);
+
+      add_mssaaaa (u2, u1, u0, u0, up[j], p1, p0);
+    }
+
+  q1 = (u2 > 0);
+  u1 -= (-q1) & d;
+
+  t = (u1 >= d);
+  q1 += t;
+  u1 -= (-t) & d;
+
+  udiv_qrnnd_preinv (t, u0, u1, u0, d, dinv);
+  add_ssaaaa (q1, q0, q1, q0, CNST_LIMB(0), t);
+
+  MPN_INCR_U (qp+1, n-1, q1);
+
+  qp[0] = q0;
+  return u0;
+}
+
+#else
+#error Unknown DIV_QR_1N_METHOD
+#endif
diff --git a/third_party/gmp/mpn/generic/div_qr_1n_pi2.c b/third_party/gmp/mpn/generic/div_qr_1n_pi2.c
new file mode 100644
index 0000000..d8834ea
--- /dev/null
+++ b/third_party/gmp/mpn/generic/div_qr_1n_pi2.c
@@ -0,0 +1,203 @@
+/* mpn_div_qr_1n_pi2.
+
+   THIS FILE CONTAINS AN INTERNAL FUNCTION WITH A MUTABLE INTERFACE.  IT IS
+   ONLY SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2013, 2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+/* ISSUES:
+
+   * Can we really use the high pi2 inverse limb for udiv_qrnnd_preinv?
+
+   * Are there any problems with generating n quotient limbs in the q area?  It
+     surely simplifies things.
+
+   * Not yet adequately tested.
+*/
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/* Define some longlong.h-style macros, but for wider operations.
+   * add_sssaaaa is like longlong.h's add_ssaaaa but propagating carry-out into
+     an additional sum operand.
+*/
+#if defined (__GNUC__)  && ! defined (__INTEL_COMPILER) && ! defined (NO_ASM)
+
+#if HAVE_HOST_CPU_FAMILY_x86 && W_TYPE_SIZE == 32
+#define add_sssaaaa(s2, s1, s0, a1, a0, b1, b0)				\
+  __asm__ ("add\t%7, %k2\n\tadc\t%5, %k1\n\tadc\t$0, %k0"		\
+	   : "=r" (s2), "=&r" (s1), "=&r" (s0)				\
+	   : "0"  ((USItype)(s2)),					\
+	     "1"  ((USItype)(a1)), "g" ((USItype)(b1)),			\
+	     "%2" ((USItype)(a0)), "g" ((USItype)(b0)))
+#endif
+
+#if defined (__amd64__) && W_TYPE_SIZE == 64
+#define add_sssaaaa(s2, s1, s0, a1, a0, b1, b0)				\
+  __asm__ ("add\t%7, %q2\n\tadc\t%5, %q1\n\tadc\t$0, %q0"		\
+	   : "=r" (s2), "=&r" (s1), "=&r" (s0)				\
+	   : "0"  ((UDItype)(s2)),					\
+	     "1"  ((UDItype)(a1)), "rme" ((UDItype)(b1)),		\
+	     "%2" ((UDItype)(a0)), "rme" ((UDItype)(b0)))
+#endif
+
+#if defined (__aarch64__) && W_TYPE_SIZE == 64
+#define add_sssaaaa(s2, s1, s0, a1, a0, b1, b0)				\
+  __asm__ ("adds\t%2, %x6, %7\n\tadcs\t%1, %x4, %x5\n\tadc\t%0, %3, xzr"\
+	   : "=r" (s2), "=&r" (s1), "=&r" (s0)				\
+	   : "rZ" (s2), "%rZ"  (a1), "rZ" (b1), "%rZ" (a0), "rI" (b0)	\
+	     __CLOBBER_CC)
+#endif
+
+#if HAVE_HOST_CPU_FAMILY_powerpc && !defined (_LONG_LONG_LIMB)
+/* This works fine for 32-bit and 64-bit limbs, except for 64-bit limbs with a
+   processor running in 32-bit mode, since the carry flag then gets the 32-bit
+   carry.  */
+#define add_sssaaaa(s2, s1, s0, a1, a0, b1, b0)				\
+  __asm__ ("add%I7c\t%2,%6,%7\n\tadde\t%1,%4,%5\n\taddze\t%0,%3"	\
+	   : "=r" (s2), "=&r" (s1), "=&r" (s0)				\
+	   : "r"  (s2), "r"  (a1), "r" (b1), "%r" (a0), "rI" (b0)	\
+	     __CLOBBER_CC)
+#endif
+
+#endif /* __GNUC__ */
+
+#ifndef add_sssaaaa
+#define add_sssaaaa(s2, s1, s0, a1, a0, b1, b0)				\
+  do {									\
+    UWtype __s0, __s1, __c0, __c1;					\
+    __s0 = (a0) + (b0);							\
+    __s1 = (a1) + (b1);							\
+    __c0 = __s0 < (a0);							\
+    __c1 = __s1 < (a1);							\
+    (s0) = __s0;							\
+    __s1 = __s1 + __c0;							\
+    (s1) = __s1;							\
+    (s2) += __c1 + (__s1 < __c0);					\
+  } while (0)
+#endif
+
+struct precomp_div_1_pi2
+{
+  mp_limb_t dip[2];
+  mp_limb_t d;
+  int norm_cnt;
+};
+
+mp_limb_t
+mpn_div_qr_1n_pi2 (mp_ptr qp,
+		   mp_srcptr up, mp_size_t un,
+		   struct precomp_div_1_pi2 *pd)
+{
+  mp_limb_t most_significant_q_limb;
+  mp_size_t i;
+  mp_limb_t r, u2, u1, u0;
+  mp_limb_t d0, di1, di0;
+  mp_limb_t q3a, q2a, q2b, q1b, q2c, q1c, q1d, q0d;
+  mp_limb_t cnd;
+
+  ASSERT (un >= 2);
+  ASSERT ((pd->d & GMP_NUMB_HIGHBIT) != 0);
+  ASSERT (! MPN_OVERLAP_P (qp, un-2, up, un) || qp+2 >= up);
+  ASSERT_MPN (up, un);
+
+#define q3 q3a
+#define q2 q2b
+#define q1 q1b
+
+  up += un - 3;
+  r = up[2];
+  d0 = pd->d;
+
+  most_significant_q_limb = (r >= d0);
+  r -= d0 & -most_significant_q_limb;
+
+  qp += un - 3;
+  qp[2] = most_significant_q_limb;
+
+  di1 = pd->dip[1];
+  di0 = pd->dip[0];
+
+  for (i = un - 3; i >= 0; i -= 2)
+    {
+      u2 = r;
+      u1 = up[1];
+      u0 = up[0];
+
+      /* Dividend in {r,u1,u0} */
+
+      umul_ppmm (q1d,q0d, u1, di0);
+      umul_ppmm (q2b,q1b, u1, di1);
+      q2b++;				/* cannot spill */
+      add_sssaaaa (r,q2b,q1b, q2b,q1b, u1,u0);
+
+      umul_ppmm (q2c,q1c, u2,  di0);
+      add_sssaaaa (r,q2b,q1b, q2b,q1b, q2c,q1c);
+      umul_ppmm (q3a,q2a, u2, di1);
+
+      add_sssaaaa (r,q2b,q1b, q2b,q1b, q2a,q1d);
+
+      q3 += r;
+
+      r = u0 - q2 * d0;
+
+      cnd = (r >= q1);
+      r += d0 & -cnd;
+      sub_ddmmss (q3,q2,  q3,q2,  0,cnd);
+
+      if (UNLIKELY (r >= d0))
+	{
+	  r -= d0;
+	  add_ssaaaa (q3,q2,  q3,q2,  0,1);
+	}
+
+      qp[0] = q2;
+      qp[1] = q3;
+
+      up -= 2;
+      qp -= 2;
+    }
+
+  if ((un & 1) == 0)
+    {
+      u2 = r;
+      u1 = up[1];
+
+      udiv_qrnnd_preinv (q3, r, u2, u1, d0, di1);
+      qp[1] = q3;
+    }
+
+  return r;
+
+#undef q3
+#undef q2
+#undef q1
+}
diff --git a/third_party/gmp/mpn/generic/div_qr_1u_pi2.c b/third_party/gmp/mpn/generic/div_qr_1u_pi2.c
new file mode 100644
index 0000000..047662f
--- /dev/null
+++ b/third_party/gmp/mpn/generic/div_qr_1u_pi2.c
@@ -0,0 +1,235 @@
+/* mpn_div_qr_1u_pi2.
+
+   THIS FILE CONTAINS AN INTERNAL FUNCTION WITH A MUTABLE INTERFACE.  IT IS
+   ONLY SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2013, 2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+/* ISSUES:
+
+   * Can we really use the high pi2 inverse limb for udiv_qrnnd_preinv?
+
+   * Are there any problems with generating n quotient limbs in the q area?  It
+     surely simplifies things.
+
+   * Not yet adequately tested.
+*/
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/* Define some longlong.h-style macros, but for wider operations.
+   * add_sssaaaa is like longlong.h's add_ssaaaa but propagating carry-out into
+     an additional sum operand.
+*/
+#if defined (__GNUC__)  && ! defined (__INTEL_COMPILER) && ! defined (NO_ASM)
+
+#if HAVE_HOST_CPU_FAMILY_x86 && W_TYPE_SIZE == 32
+#define add_sssaaaa(s2, s1, s0, a1, a0, b1, b0)				\
+  __asm__ ("add\t%7, %k2\n\tadc\t%5, %k1\n\tadc\t$0, %k0"		\
+	   : "=r" (s2), "=&r" (s1), "=&r" (s0)				\
+	   : "0"  ((USItype)(s2)),					\
+	     "1"  ((USItype)(a1)), "g" ((USItype)(b1)),			\
+	     "%2" ((USItype)(a0)), "g" ((USItype)(b0)))
+#endif
+
+#if defined (__amd64__) && W_TYPE_SIZE == 64
+#define add_sssaaaa(s2, s1, s0, a1, a0, b1, b0)				\
+  __asm__ ("add\t%7, %q2\n\tadc\t%5, %q1\n\tadc\t$0, %q0"		\
+	   : "=r" (s2), "=&r" (s1), "=&r" (s0)				\
+	   : "0"  ((UDItype)(s2)),					\
+	     "1"  ((UDItype)(a1)), "rme" ((UDItype)(b1)),		\
+	     "%2" ((UDItype)(a0)), "rme" ((UDItype)(b0)))
+#endif
+
+#if defined (__aarch64__) && W_TYPE_SIZE == 64
+#define add_sssaaaa(s2, s1, s0, a1, a0, b1, b0)				\
+  __asm__ ("adds\t%2, %x6, %7\n\tadcs\t%1, %x4, %x5\n\tadc\t%0, %3, xzr"\
+	   : "=r" (s2), "=&r" (s1), "=&r" (s0)				\
+	   : "rZ" (s2), "%rZ"  (a1), "rZ" (b1), "%rZ" (a0), "rI" (b0) __CLOBBER_CC)
+#endif
+
+#if HAVE_HOST_CPU_FAMILY_powerpc && !defined (_LONG_LONG_LIMB)
+/* This works fine for 32-bit and 64-bit limbs, except for 64-bit limbs with a
+   processor running in 32-bit mode, since the carry flag then gets the 32-bit
+   carry.  */
+#define add_sssaaaa(s2, s1, s0, a1, a0, b1, b0)				\
+  __asm__ ("add%I7c\t%2,%6,%7\n\tadde\t%1,%4,%5\n\taddze\t%0,%3"	\
+	   : "=r" (s2), "=&r" (s1), "=&r" (s0)				\
+	   : "r"  (s2), "r"  (a1), "r" (b1), "%r" (a0), "rI" (b0)	\
+	     __CLOBBER_CC)
+#endif
+
+#endif /* __GNUC__ */
+
+#ifndef add_sssaaaa
+#define add_sssaaaa(s2, s1, s0, a1, a0, b1, b0)				\
+  do {									\
+    UWtype __s0, __s1, __c0, __c1;					\
+    __s0 = (a0) + (b0);							\
+    __s1 = (a1) + (b1);							\
+    __c0 = __s0 < (a0);							\
+    __c1 = __s1 < (a1);							\
+    (s0) = __s0;							\
+    __s1 = __s1 + __c0;							\
+    (s1) = __s1;							\
+    (s2) += __c1 + (__s1 < __c0);					\
+  } while (0)
+#endif
+
+struct precomp_div_1_pi2
+{
+  mp_limb_t dip[2];
+  mp_limb_t d;
+  int norm_cnt;
+};
+
+mp_limb_t
+mpn_div_qr_1u_pi2 (mp_ptr qp,
+		   mp_srcptr up, mp_size_t un,
+		   struct precomp_div_1_pi2 *pd)
+{
+  mp_size_t i;
+  mp_limb_t r, u2, u1, u0;
+  mp_limb_t d0, di1, di0;
+  mp_limb_t q3a, q2a, q2b, q1b, q2c, q1c, q1d, q0d;
+  mp_limb_t cnd;
+  int cnt;
+
+  ASSERT (un >= 2);
+  ASSERT ((pd->d & GMP_NUMB_HIGHBIT) == 0);
+  ASSERT (! MPN_OVERLAP_P (qp, un-2, up, un) || qp+2 >= up);
+  ASSERT_MPN (up, un);
+
+#define q3 q3a
+#define q2 q2b
+#define q1 q1b
+
+  up += un - 3;
+  cnt = pd->norm_cnt;
+  r = up[2] >> (GMP_NUMB_BITS - cnt);
+  d0 = pd->d << cnt;
+
+  qp += un - 2;
+
+  di1 = pd->dip[1];
+  di0 = pd->dip[0];
+
+  for (i = un - 3; i >= 0; i -= 2)
+    {
+      u2 = r;
+      u1 = (up[2] << cnt) | (up[1] >> (GMP_NUMB_BITS - cnt));
+      u0 = (up[1] << cnt) | (up[0] >> (GMP_NUMB_BITS - cnt));
+
+      /* Dividend in {r,u1,u0} */
+
+      umul_ppmm (q1d,q0d, u1, di0);
+      umul_ppmm (q2b,q1b, u1, di1);
+      q2b++;				/* cannot spill */
+      add_sssaaaa (r,q2b,q1b, q2b,q1b, u1,u0);
+
+      umul_ppmm (q2c,q1c, u2,  di0);
+      add_sssaaaa (r,q2b,q1b, q2b,q1b, q2c,q1c);
+      umul_ppmm (q3a,q2a, u2, di1);
+
+      add_sssaaaa (r,q2b,q1b, q2b,q1b, q2a,q1d);
+
+      q3 += r;
+
+      r = u0 - q2 * d0;
+
+      cnd = (r >= q1);
+      r += d0 & -cnd;
+      sub_ddmmss (q3,q2,  q3,q2,  0,cnd);
+
+      if (UNLIKELY (r >= d0))
+	{
+	  r -= d0;
+	  add_ssaaaa (q3,q2,  q3,q2,  0,1);
+	}
+
+      qp[0] = q2;
+      qp[1] = q3;
+
+      up -= 2;
+      qp -= 2;
+    }
+
+  if ((un & 1) != 0)
+    {
+      u2 = r;
+      u1 = (up[2] << cnt);
+
+      udiv_qrnnd_preinv (q3, r, u2, u1, d0, di1);
+      qp[1] = q3;
+    }
+  else
+    {
+      u2 = r;
+      u1 = (up[2] << cnt) | (up[1] >> (GMP_NUMB_BITS - cnt));
+      u0 = (up[1] << cnt);
+
+      /* Dividend in {r,u1,u0} */
+
+      umul_ppmm (q1d,q0d, u1, di0);
+      umul_ppmm (q2b,q1b, u1, di1);
+      q2b++;				/* cannot spill */
+      add_sssaaaa (r,q2b,q1b, q2b,q1b, u1,u0);
+
+      umul_ppmm (q2c,q1c, u2,  di0);
+      add_sssaaaa (r,q2b,q1b, q2b,q1b, q2c,q1c);
+      umul_ppmm (q3a,q2a, u2, di1);
+
+      add_sssaaaa (r,q2b,q1b, q2b,q1b, q2a,q1d);
+
+      q3 += r;
+
+      r = u0 - q2 * d0;
+
+      cnd = (r >= q1);
+      r += d0 & -cnd;
+      sub_ddmmss (q3,q2,  q3,q2,  0,cnd);
+
+      if (UNLIKELY (r >= d0))
+	{
+	  r -= d0;
+	  add_ssaaaa (q3,q2,  q3,q2,  0,1);
+	}
+
+      qp[0] = q2;
+      qp[1] = q3;
+    }
+
+  return r >> cnt;
+
+#undef q3
+#undef q2
+#undef q1
+}
diff --git a/third_party/gmp/mpn/generic/div_qr_2.c b/third_party/gmp/mpn/generic/div_qr_2.c
new file mode 100644
index 0000000..f7add44
--- /dev/null
+++ b/third_party/gmp/mpn/generic/div_qr_2.c
@@ -0,0 +1,314 @@
+/* mpn_div_qr_2 -- Divide natural numbers, producing both remainder and
+   quotient.  The divisor is two limbs.
+
+   Contributed to the GNU project by Torbjorn Granlund and Niels Möller
+
+   THIS FILE CONTAINS INTERNAL FUNCTIONS WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+
+Copyright 1993-1996, 1999-2002, 2011, 2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#ifndef DIV_QR_2_PI2_THRESHOLD
+/* Disabled unless explicitly tuned. */
+#define DIV_QR_2_PI2_THRESHOLD MP_LIMB_T_MAX
+#endif
+
+#ifndef SANITY_CHECK
+#define SANITY_CHECK 0
+#endif
+
+/* Define some longlong.h-style macros, but for wider operations.
+   * add_sssaaaa is like longlong.h's add_ssaaaa but propagating carry-out into
+     an additional sum operand.
+   * add_csaac accepts two addends and a carry in, and generates a sum and a
+     carry out.  A little like a "full adder".
+*/
+#if defined (__GNUC__)  && ! defined (__INTEL_COMPILER) && ! defined (NO_ASM)
+
+#if HAVE_HOST_CPU_FAMILY_x86 && W_TYPE_SIZE == 32
+#define add_sssaaaa(s2, s1, s0, a1, a0, b1, b0)				\
+  __asm__ ("add\t%7, %k2\n\tadc\t%5, %k1\n\tadc\t$0, %k0"		\
+	   : "=r" (s2), "=&r" (s1), "=&r" (s0)				\
+	   : "0"  ((USItype)(s2)),					\
+	     "1"  ((USItype)(a1)), "g" ((USItype)(b1)),			\
+	     "%2" ((USItype)(a0)), "g" ((USItype)(b0)))
+#endif
+
+#if defined (__amd64__) && W_TYPE_SIZE == 64
+#define add_sssaaaa(s2, s1, s0, a1, a0, b1, b0)				\
+  __asm__ ("add\t%7, %q2\n\tadc\t%5, %q1\n\tadc\t$0, %q0"		\
+	   : "=r" (s2), "=&r" (s1), "=&r" (s0)				\
+	   : "0"  ((UDItype)(s2)),					\
+	     "1"  ((UDItype)(a1)), "rme" ((UDItype)(b1)),		\
+	     "%2" ((UDItype)(a0)), "rme" ((UDItype)(b0)))
+#endif
+
+#if defined (__aarch64__) && W_TYPE_SIZE == 64
+#define add_sssaaaa(s2, s1, s0, a1, a0, b1, b0)				\
+  __asm__ ("adds\t%2, %x6, %7\n\tadcs\t%1, %x4, %x5\n\tadc\t%0, %3, xzr"\
+	   : "=r" (s2), "=&r" (s1), "=&r" (s0)				\
+	   : "rZ" (s2), "%rZ"  (a1), "rZ" (b1), "%rZ" (a0), "rI" (b0)	\
+	     __CLOBBER_CC)
+#endif
+
+#if HAVE_HOST_CPU_FAMILY_powerpc && !defined (_LONG_LONG_LIMB)
+/* This works fine for 32-bit and 64-bit limbs, except for 64-bit limbs with a
+   processor running in 32-bit mode, since the carry flag then gets the 32-bit
+   carry.  */
+#define add_sssaaaa(s2, s1, s0, a1, a0, b1, b0)				\
+  __asm__ ("add%I7c\t%2,%6,%7\n\tadde\t%1,%4,%5\n\taddze\t%0,%3"	\
+	   : "=r" (s2), "=&r" (s1), "=&r" (s0)				\
+	   : "r"  (s2), "r"  (a1), "r" (b1), "%r" (a0), "rI" (b0)	\
+	     __CLOBBER_CC)
+#endif
+
+#endif /* __GNUC__ */
+
+#ifndef add_sssaaaa
+#define add_sssaaaa(s2, s1, s0, a1, a0, b1, b0)				\
+  do {									\
+    UWtype __s0, __s1, __c0, __c1;					\
+    __s0 = (a0) + (b0);							\
+    __s1 = (a1) + (b1);							\
+    __c0 = __s0 < (a0);							\
+    __c1 = __s1 < (a1);							\
+    (s0) = __s0;							\
+    __s1 = __s1 + __c0;							\
+    (s1) = __s1;							\
+    (s2) += __c1 + (__s1 < __c0);					\
+  } while (0)
+#endif
+
+/* Typically used with r1, r0 same as n3, n2. Other types of overlap
+   between inputs and outputs are not supported. */
+#define udiv_qr_4by2(q1,q0, r1,r0, n3,n2,n1,n0, d1,d0, di1,di0)		\
+  do {									\
+    mp_limb_t _q3, _q2a, _q2, _q1, _q2c, _q1c, _q1d, _q0;		\
+    mp_limb_t _t1, _t0;							\
+    mp_limb_t _mask;							\
+									\
+    /* [q3,q2,q1,q0] = [n3,n2]*[di1,di0] + [n3,n2,n1,n0] + [0,1,0,0] */	\
+    umul_ppmm (_q2,_q1, n2, di1);					\
+    umul_ppmm (_q3,_q2a, n3, di1);					\
+    ++_q2;	/* _q2 cannot overflow */				\
+    add_ssaaaa (_q3,_q2, _q3,_q2, n3,_q2a);				\
+    umul_ppmm (_q2c,_q1c, n3, di0);					\
+    add_sssaaaa (_q3,_q2,_q1, _q2,_q1, n2,_q1c);			\
+    umul_ppmm (_q1d,_q0, n2, di0);					\
+    add_sssaaaa (_q2c,_q1,_q0, _q1,_q0, n1,n0); /* _q2c cannot overflow */ \
+    add_sssaaaa (_q3,_q2,_q1, _q2,_q1, _q2c,_q1d);			\
+									\
+    umul_ppmm (_t1,_t0, _q2, d0);					\
+    _t1 += _q2 * d1 + _q3 * d0;						\
+									\
+    sub_ddmmss (r1, r0, n1, n0, _t1, _t0);				\
+									\
+    _mask = -(mp_limb_t) ((r1 >= _q1) & ((r1 > _q1) | (r0 >= _q0)));  /* (r1,r0) >= (q1,q0) */  \
+    add_ssaaaa (r1, r0, r1, r0, d1 & _mask, d0 & _mask);		\
+    sub_ddmmss (_q3, _q2, _q3, _q2, CNST_LIMB(0), -_mask);		\
+									\
+    if (UNLIKELY (r1 >= d1))						\
+      {									\
+	if (r1 > d1 || r0 >= d0)					\
+	  {								\
+	    sub_ddmmss (r1, r0, r1, r0, d1, d0);			\
+	    add_ssaaaa (_q3, _q2, _q3, _q2, CNST_LIMB(0), CNST_LIMB(1));\
+	  }								\
+      }									\
+    (q1) = _q3;								\
+    (q0) = _q2;								\
+  } while (0)
+
+static void
+invert_4by2 (mp_ptr di, mp_limb_t d1, mp_limb_t d0)
+{
+  mp_limb_t v1, v0, p1, t1, t0, p0, mask;
+  invert_limb (v1, d1);
+  p1 = d1 * v1;
+  /* <1, v1> * d1 = <B-1, p1> */
+  p1 += d0;
+  if (p1 < d0)
+    {
+      v1--;
+      mask = -(mp_limb_t) (p1 >= d1);
+      p1 -= d1;
+      v1 += mask;
+      p1 -= mask & d1;
+    }
+  /* <1, v1> * d1 + d0 = <B-1, p1> */
+  umul_ppmm (t1, p0, d0, v1);
+  p1 += t1;
+  if (p1 < t1)
+    {
+      if (UNLIKELY (p1 >= d1))
+	{
+	  if (p1 > d1 || p0 >= d0)
+	    {
+	      sub_ddmmss (p1, p0, p1, p0, d1, d0);
+	      v1--;
+	    }
+	}
+      sub_ddmmss (p1, p0, p1, p0, d1, d0);
+      v1--;
+    }
+  /* Now v1 is the 3/2 inverse, <1, v1> * <d1, d0> = <B-1, p1, p0>,
+   * with <p1, p0> + <d1, d0> >= B^2.
+   *
+   * The 4/2 inverse is (B^4 - 1) / <d1, d0> = <1, v1, v0>. The
+   * partial remainder after <1, v1> is
+   *
+   * B^4 - 1 - B <1, v1> <d1, d0> = <B-1, B-1, B-1, B-1> - <B-1, p1, p0, 0>
+   *                              = <~p1, ~p0, B-1>
+   */
+  udiv_qr_3by2 (v0, t1, t0, ~p1, ~p0, MP_LIMB_T_MAX, d1, d0, v1);
+  di[0] = v0;
+  di[1] = v1;
+
+#if SANITY_CHECK
+  {
+    mp_limb_t tp[4];
+    mp_limb_t dp[2];
+    dp[0] = d0;
+    dp[1] = d1;
+    mpn_mul_n (tp, dp, di, 2);
+    ASSERT_ALWAYS (mpn_add_n (tp+2, tp+2, dp, 2) == 0);
+    ASSERT_ALWAYS (tp[2] == MP_LIMB_T_MAX);
+    ASSERT_ALWAYS (tp[3] == MP_LIMB_T_MAX);
+    ASSERT_ALWAYS (mpn_add_n (tp, tp, dp, 2) == 1);
+  }
+#endif
+}
+
+static mp_limb_t
+mpn_div_qr_2n_pi2 (mp_ptr qp, mp_ptr rp, mp_srcptr np, mp_size_t nn,
+		   mp_limb_t d1, mp_limb_t d0, mp_limb_t di1, mp_limb_t di0)
+{
+  mp_limb_t qh;
+  mp_size_t i;
+  mp_limb_t r1, r0;
+
+  ASSERT (nn >= 2);
+  ASSERT (d1 & GMP_NUMB_HIGHBIT);
+
+  r1 = np[nn-1];
+  r0 = np[nn-2];
+
+  qh = 0;
+  if (r1 >= d1 && (r1 > d1 || r0 >= d0))
+    {
+#if GMP_NAIL_BITS == 0
+      sub_ddmmss (r1, r0, r1, r0, d1, d0);
+#else
+      r0 = r0 - d0;
+      r1 = r1 - d1 - (r0 >> GMP_LIMB_BITS - 1);
+      r0 &= GMP_NUMB_MASK;
+#endif
+      qh = 1;
+    }
+
+  for (i = nn - 2; i >= 2; i -= 2)
+    {
+      mp_limb_t n1, n0, q1, q0;
+      n1 = np[i-1];
+      n0 = np[i-2];
+      udiv_qr_4by2 (q1, q0, r1, r0, r1, r0, n1, n0, d1, d0, di1, di0);
+      qp[i-1] = q1;
+      qp[i-2] = q0;
+    }
+
+  if (i > 0)
+    {
+      mp_limb_t q;
+      udiv_qr_3by2 (q, r1, r0, r1, r0, np[0], d1, d0, di1);
+      qp[0] = q;
+    }
+  rp[1] = r1;
+  rp[0] = r0;
+
+  return qh;
+}
+
+
+/* Divide num {np,nn} by den {dp,2} and write the nn-2 least
+   significant quotient limbs at qp and the 2 long remainder at np.
+   Return the most significant limb of the quotient.
+
+   Preconditions:
+   1. qp must either not overlap with the other operands at all, or
+      qp >= np + 2 must hold true.  (This means that it's possible to put
+      the quotient in the high part of {np,nn}, right above the remainder.)
+   2. nn >= 2.  */
+
+mp_limb_t
+mpn_div_qr_2 (mp_ptr qp, mp_ptr rp, mp_srcptr np, mp_size_t nn,
+	      mp_srcptr dp)
+{
+  mp_limb_t d1;
+  mp_limb_t d0;
+  gmp_pi1_t dinv;
+
+  ASSERT (nn >= 2);
+  ASSERT (! MPN_OVERLAP_P (qp, nn-2, np, nn) || qp >= np + 2);
+  ASSERT_MPN (np, nn);
+  ASSERT_MPN (dp, 2);
+
+  d1 = dp[1]; d0 = dp[0];
+
+  ASSERT (d1 > 0);
+
+  if (UNLIKELY (d1 & GMP_NUMB_HIGHBIT))
+    {
+      if (BELOW_THRESHOLD (nn, DIV_QR_2_PI2_THRESHOLD))
+	{
+	  gmp_pi1_t dinv;
+	  invert_pi1 (dinv, d1, d0);
+	  return mpn_div_qr_2n_pi1 (qp, rp, np, nn, d1, d0, dinv.inv32);
+	}
+      else
+	{
+	  mp_limb_t di[2];
+	  invert_4by2 (di, d1, d0);
+	  return mpn_div_qr_2n_pi2 (qp, rp, np, nn, d1, d0, di[1], di[0]);
+	}
+    }
+  else
+    {
+      int shift;
+      count_leading_zeros (shift, d1);
+      d1 = (d1 << shift) | (d0 >> (GMP_LIMB_BITS - shift));
+      d0 <<= shift;
+      invert_pi1 (dinv, d1, d0);
+      return mpn_div_qr_2u_pi1 (qp, rp, np, nn, d1, d0, shift, dinv.inv32);
+    }
+}
diff --git a/third_party/gmp/mpn/generic/div_qr_2n_pi1.c b/third_party/gmp/mpn/generic/div_qr_2n_pi1.c
new file mode 100644
index 0000000..131a811
--- /dev/null
+++ b/third_party/gmp/mpn/generic/div_qr_2n_pi1.c
@@ -0,0 +1,84 @@
+/* mpn_div_qr_2n_pi1
+
+   Contributed to the GNU project by Torbjorn Granlund and Niels Möller
+
+   THIS FILE CONTAINS INTERNAL FUNCTIONS WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+
+Copyright 1993-1996, 1999-2002, 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* 3/2 loop, for normalized divisor */
+mp_limb_t
+mpn_div_qr_2n_pi1 (mp_ptr qp, mp_ptr rp, mp_srcptr np, mp_size_t nn,
+		   mp_limb_t d1, mp_limb_t d0, mp_limb_t di)
+{
+  mp_limb_t qh;
+  mp_size_t i;
+  mp_limb_t r1, r0;
+
+  ASSERT (nn >= 2);
+  ASSERT (d1 & GMP_NUMB_HIGHBIT);
+
+  np += nn - 2;
+  r1 = np[1];
+  r0 = np[0];
+
+  qh = 0;
+  if (r1 >= d1 && (r1 > d1 || r0 >= d0))
+    {
+#if GMP_NAIL_BITS == 0
+      sub_ddmmss (r1, r0, r1, r0, d1, d0);
+#else
+      r0 = r0 - d0;
+      r1 = r1 - d1 - (r0 >> GMP_LIMB_BITS - 1);
+      r0 &= GMP_NUMB_MASK;
+#endif
+      qh = 1;
+    }
+
+  for (i = nn - 2 - 1; i >= 0; i--)
+    {
+      mp_limb_t n0, q;
+      n0 = np[-1];
+      udiv_qr_3by2 (q, r1, r0, r1, r0, n0, d1, d0, di);
+      np--;
+      qp[i] = q;
+    }
+
+  rp[1] = r1;
+  rp[0] = r0;
+
+  return qh;
+}
diff --git a/third_party/gmp/mpn/generic/div_qr_2u_pi1.c b/third_party/gmp/mpn/generic/div_qr_2u_pi1.c
new file mode 100644
index 0000000..70e617b
--- /dev/null
+++ b/third_party/gmp/mpn/generic/div_qr_2u_pi1.c
@@ -0,0 +1,76 @@
+/* mpn_div_qr_2u_pi1
+
+   Contributed to the GNU project by Niels Möller
+
+   THIS FILE CONTAINS INTERNAL FUNCTIONS WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+
+Copyright 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* 3/2 loop, for unnormalized divisor. Caller must pass shifted d1 and
+   d0, while {np,nn} is shifted on the fly. */
+mp_limb_t
+mpn_div_qr_2u_pi1 (mp_ptr qp, mp_ptr rp, mp_srcptr np, mp_size_t nn,
+		   mp_limb_t d1, mp_limb_t d0, int shift, mp_limb_t di)
+{
+  mp_limb_t qh;
+  mp_limb_t r2, r1, r0;
+  mp_size_t i;
+
+  ASSERT (nn >= 2);
+  ASSERT (d1 & GMP_NUMB_HIGHBIT);
+  ASSERT (shift > 0);
+
+  r2 = np[nn-1] >> (GMP_LIMB_BITS - shift);
+  r1 = (np[nn-1] << shift) | (np[nn-2] >> (GMP_LIMB_BITS - shift));
+  r0 = np[nn-2] << shift;
+
+  udiv_qr_3by2 (qh, r2, r1, r2, r1, r0, d1, d0, di);
+
+  for (i = nn - 2 - 1; i >= 0; i--)
+    {
+      mp_limb_t q;
+      r0 = np[i];
+      r1 |= r0 >> (GMP_LIMB_BITS - shift);
+      r0 <<= shift;
+      udiv_qr_3by2 (q, r2, r1, r2, r1, r0, d1, d0, di);
+      qp[i] = q;
+    }
+
+  rp[0] = (r1 >> shift) | (r2 << (GMP_LIMB_BITS - shift));
+  rp[1] = r2 >> shift;
+
+  return qh;
+}
diff --git a/third_party/gmp/mpn/generic/dive_1.c b/third_party/gmp/mpn/generic/dive_1.c
new file mode 100644
index 0000000..056f5b9
--- /dev/null
+++ b/third_party/gmp/mpn/generic/dive_1.c
@@ -0,0 +1,146 @@
+/* mpn_divexact_1 -- mpn by limb exact division.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2000-2003, 2005, 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+
+/* Divide a={src,size} by d=divisor and store the quotient in q={dst,size}.
+   q will only be correct if d divides a exactly.
+
+   A separate loop is used for shift==0 because n<<GMP_LIMB_BITS doesn't
+   give zero on all CPUs (for instance it doesn't on the x86s).  This
+   separate loop might run faster too, helping odd divisors.
+
+   Possibilities:
+
+   mpn_divexact_1c could be created, accepting and returning c.  This would
+   let a long calculation be done piece by piece.  Currently there's no
+   particular need for that, and not returning c means that a final umul can
+   be skipped.
+
+   Another use for returning c would be letting the caller know whether the
+   division was in fact exact.  It would work just to return the carry bit
+   "c=(l>s)" and let the caller do a final umul if interested.
+
+   When the divisor is even, the factors of two could be handled with a
+   separate mpn_rshift, instead of shifting on the fly.  That might be
+   faster on some CPUs and would mean just the shift==0 style loop would be
+   needed.
+
+   If n<<GMP_LIMB_BITS gives zero on a particular CPU then the separate
+   shift==0 loop is unnecessary, and could be eliminated if there's no great
+   speed difference.
+
+   It's not clear whether "/" is the best way to handle size==1.  Alpha gcc
+   2.95 for instance has a poor "/" and might prefer the modular method.
+   Perhaps a tuned parameter should control this.
+
+   If src[size-1] < divisor then dst[size-1] will be zero, and one divide
+   step could be skipped.  A test at last step for s<divisor (or ls in the
+   even case) might be a good way to do that.  But if this code is often
+   used with small divisors then it might not be worth bothering  */
+
+void
+mpn_divexact_1 (mp_ptr dst, mp_srcptr src, mp_size_t size, mp_limb_t divisor)
+{
+  mp_size_t  i;
+  mp_limb_t  c, h, l, ls, s, s_next, inverse, dummy;
+  unsigned   shift;
+
+  ASSERT (size >= 1);
+  ASSERT (divisor != 0);
+  ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, size));
+  ASSERT_MPN (src, size);
+  ASSERT_LIMB (divisor);
+
+  if ((divisor & 1) == 0)
+    {
+      count_trailing_zeros (shift, divisor);
+      divisor >>= shift;
+    }
+  else
+    shift = 0;
+
+  binvert_limb (inverse, divisor);
+  divisor <<= GMP_NAIL_BITS;
+
+  if (shift != 0)
+    {
+      c = 0;
+
+      s = src[0];
+
+      for (i = 1; i < size; i++)
+	{
+	  s_next = src[i];
+	  ls = ((s >> shift) | (s_next << (GMP_NUMB_BITS-shift))) & GMP_NUMB_MASK;
+	  s = s_next;
+
+	  SUBC_LIMB (c, l, ls, c);
+
+	  l = (l * inverse) & GMP_NUMB_MASK;
+	  dst[i - 1] = l;
+
+	  umul_ppmm (h, dummy, l, divisor);
+	  c += h;
+	}
+
+      ls = s >> shift;
+      l = ls - c;
+      l = (l * inverse) & GMP_NUMB_MASK;
+      dst[size - 1] = l;
+    }
+  else
+    {
+      s = src[0];
+
+      l = (s * inverse) & GMP_NUMB_MASK;
+      dst[0] = l;
+      c = 0;
+
+      for (i = 1; i < size; i++)
+	{
+	  umul_ppmm (h, dummy, l, divisor);
+	  c += h;
+
+	  s = src[i];
+	  SUBC_LIMB (c, l, s, c);
+
+	  l = (l * inverse) & GMP_NUMB_MASK;
+	  dst[i] = l;
+	}
+    }
+}
diff --git a/third_party/gmp/mpn/generic/diveby3.c b/third_party/gmp/mpn/generic/diveby3.c
new file mode 100644
index 0000000..7dee0bc
--- /dev/null
+++ b/third_party/gmp/mpn/generic/diveby3.c
@@ -0,0 +1,173 @@
+/* mpn_divexact_by3c -- mpn exact division by 3.
+
+Copyright 2000-2003, 2008 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#if DIVEXACT_BY3_METHOD == 0
+
+mp_limb_t
+mpn_divexact_by3c (mp_ptr rp, mp_srcptr up, mp_size_t un, mp_limb_t c)
+{
+  mp_limb_t r;
+  r = mpn_bdiv_dbm1c (rp, up, un, GMP_NUMB_MASK / 3, GMP_NUMB_MASK / 3 * c);
+
+  /* Possible bdiv_dbm1 return values are C * (GMP_NUMB_MASK / 3), 0 <= C < 3.
+     We want to return C.  We compute the remainder mod 4 and notice that the
+     inverse of (2^(2k)-1)/3 mod 4 is 1.  */
+  return r & 3;
+}
+
+#endif
+
+#if DIVEXACT_BY3_METHOD == 1
+
+/* The algorithm here is basically the same as mpn_divexact_1, as described
+   in the manual.  Namely at each step q = (src[i]-c)*inverse, and new c =
+   borrow(src[i]-c) + high(divisor*q).  But because the divisor is just 3,
+   high(divisor*q) can be determined with two comparisons instead of a
+   multiply.
+
+   The "c += ..."s add the high limb of 3*l to c.  That high limb will be 0,
+   1 or 2.  Doing two separate "+="s seems to give better code on gcc (as of
+   2.95.2 at least).
+
+   It will be noted that the new c is formed by adding three values each 0
+   or 1.  But the total is only 0, 1 or 2.  When the subtraction src[i]-c
+   causes a borrow, that leaves a limb value of either 0xFF...FF or
+   0xFF...FE.  The multiply by MODLIMB_INVERSE_3 gives 0x55...55 or
+   0xAA...AA respectively, and in those cases high(3*q) is only 0 or 1
+   respectively, hence a total of no more than 2.
+
+   Alternatives:
+
+   This implementation has each multiply on the dependent chain, due to
+   "l=s-c".  See below for alternative code which avoids that.  */
+
+mp_limb_t
+mpn_divexact_by3c (mp_ptr restrict rp, mp_srcptr restrict up, mp_size_t un, mp_limb_t c)
+{
+  mp_limb_t  l, q, s;
+  mp_size_t  i;
+
+  ASSERT (un >= 1);
+  ASSERT (c == 0 || c == 1 || c == 2);
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, up, un));
+
+  i = 0;
+  do
+    {
+      s = up[i];
+      SUBC_LIMB (c, l, s, c);
+
+      q = (l * MODLIMB_INVERSE_3) & GMP_NUMB_MASK;
+      rp[i] = q;
+
+      c += (q >= GMP_NUMB_CEIL_MAX_DIV3);
+      c += (q >= GMP_NUMB_CEIL_2MAX_DIV3);
+    }
+  while (++i < un);
+
+  ASSERT (c == 0 || c == 1 || c == 2);
+  return c;
+}
+
+
+#endif
+
+#if DIVEXACT_BY3_METHOD == 2
+
+/* The following alternative code re-arranges the quotient calculation from
+   (src[i]-c)*inverse to instead
+
+       q = src[i]*inverse - c*inverse
+
+   thereby allowing src[i]*inverse to be scheduled back as far as desired,
+   making full use of multiplier throughput and leaving just some carry
+   handing on the dependent chain.
+
+   The carry handling consists of determining the c for the next iteration.
+   This is the same as described above, namely look for any borrow from
+   src[i]-c, and at the high of 3*q.
+
+   high(3*q) is done with two comparisons as above (in c2 and c3).  The
+   borrow from src[i]-c is incorporated into those by noting that if there's
+   a carry then then we have src[i]-c == 0xFF..FF or 0xFF..FE, in turn
+   giving q = 0x55..55 or 0xAA..AA.  Adding 1 to either of those q values is
+   enough to make high(3*q) come out 1 bigger, as required.
+
+   l = -c*inverse is calculated at the same time as c, since for most chips
+   it can be more conveniently derived from separate c1/c2/c3 values than
+   from a combined c equal to 0, 1 or 2.
+
+   The net effect is that with good pipelining this loop should be able to
+   run at perhaps 4 cycles/limb, depending on available execute resources
+   etc.
+
+   Usage:
+
+   This code is not used by default, since we really can't rely on the
+   compiler generating a good software pipeline, nor on such an approach
+   even being worthwhile on all CPUs.
+
+   Itanium is one chip where this algorithm helps though, see
+   mpn/ia64/diveby3.asm.  */
+
+mp_limb_t
+mpn_divexact_by3c (mp_ptr restrict rp, mp_srcptr restrict up, mp_size_t un, mp_limb_t cy)
+{
+  mp_limb_t  s, sm, cl, q, qx, c2, c3;
+  mp_size_t  i;
+
+  ASSERT (un >= 1);
+  ASSERT (cy == 0 || cy == 1 || cy == 2);
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, up, un));
+
+  cl = cy == 0 ? 0 : cy == 1 ? -MODLIMB_INVERSE_3 : -2*MODLIMB_INVERSE_3;
+
+  for (i = 0; i < un; i++)
+    {
+      s = up[i];
+      sm = (s * MODLIMB_INVERSE_3) & GMP_NUMB_MASK;
+
+      q = (cl + sm) & GMP_NUMB_MASK;
+      rp[i] = q;
+      qx = q + (s < cy);
+
+      c2 = qx >= GMP_NUMB_CEIL_MAX_DIV3;
+      c3 = qx >= GMP_NUMB_CEIL_2MAX_DIV3 ;
+
+      cy = c2 + c3;
+      cl = (-c2 & -MODLIMB_INVERSE_3) + (-c3 & -MODLIMB_INVERSE_3);
+    }
+
+  return cy;
+}
+
+#endif
diff --git a/third_party/gmp/mpn/generic/divexact.c b/third_party/gmp/mpn/generic/divexact.c
new file mode 100644
index 0000000..ec417df
--- /dev/null
+++ b/third_party/gmp/mpn/generic/divexact.c
@@ -0,0 +1,296 @@
+/* mpn_divexact(qp,np,nn,dp,dn,tp) -- Divide N = {np,nn} by D = {dp,dn} storing
+   the result in Q = {qp,nn-dn+1} expecting no remainder.  Overlap allowed
+   between Q and N; all other overlap disallowed.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright 2006, 2007, 2009, 2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#if 1
+void
+mpn_divexact (mp_ptr qp,
+	      mp_srcptr np, mp_size_t nn,
+	      mp_srcptr dp, mp_size_t dn)
+{
+  unsigned shift;
+  mp_size_t qn;
+  mp_ptr tp;
+  TMP_DECL;
+
+  ASSERT (dn > 0);
+  ASSERT (nn >= dn);
+  ASSERT (dp[dn-1] > 0);
+
+  while (dp[0] == 0)
+    {
+      ASSERT (np[0] == 0);
+      dp++;
+      np++;
+      dn--;
+      nn--;
+    }
+
+  if (dn == 1)
+    {
+      MPN_DIVREM_OR_DIVEXACT_1 (qp, np, nn, dp[0]);
+      return;
+    }
+
+  TMP_MARK;
+
+  qn = nn + 1 - dn;
+  count_trailing_zeros (shift, dp[0]);
+
+  if (shift > 0)
+    {
+      mp_ptr wp;
+      mp_size_t ss;
+      ss = (dn > qn) ? qn + 1 : dn;
+
+      tp = TMP_ALLOC_LIMBS (ss);
+      mpn_rshift (tp, dp, ss, shift);
+      dp = tp;
+
+      /* Since we have excluded dn == 1, we have nn > qn, and we need
+	 to shift one limb beyond qn. */
+      wp = TMP_ALLOC_LIMBS (qn + 1);
+      mpn_rshift (wp, np, qn + 1, shift);
+      np = wp;
+    }
+
+  if (dn > qn)
+    dn = qn;
+
+  tp = TMP_ALLOC_LIMBS (mpn_bdiv_q_itch (qn, dn));
+  mpn_bdiv_q (qp, np, qn, dp, dn, tp);
+  TMP_FREE;
+
+  /* Since bdiv_q computes -N/D (mod B^{qn}), we must negate now. */
+  mpn_neg (qp, qp, qn);
+}
+
+#else
+
+/* We use the Jebelean's bidirectional exact division algorithm.  This is
+   somewhat naively implemented, with equal quotient parts done by 2-adic
+   division and truncating division.  Since 2-adic division is faster, it
+   should be used for a larger chunk.
+
+   This code is horrendously ugly, in all sorts of ways.
+
+   * It was hacked without much care or thought, but with a testing program.
+   * It handles scratch space frivolously, and furthermore the itch function
+     is broken.
+   * Doesn't provide any measures to deal with mu_divappr_q's +3 error.  We
+     have yet to provoke an error due to this, though.
+   * Algorithm selection leaves a lot to be desired.  In particular, the choice
+     between DC and MU isn't a point, but we treat it like one.
+   * It makes the msb part 1 or 2 limbs larger than the lsb part, in spite of
+     that the latter is faster.  We should at least reverse this, but perhaps
+     we should make the lsb part considerably larger.  (How do we tune this?)
+*/
+
+mp_size_t
+mpn_divexact_itch (mp_size_t nn, mp_size_t dn)
+{
+  return nn + dn;		/* FIXME this is not right */
+}
+
+void
+mpn_divexact (mp_ptr qp,
+	      mp_srcptr np, mp_size_t nn,
+	      mp_srcptr dp, mp_size_t dn,
+	      mp_ptr scratch)
+{
+  mp_size_t qn;
+  mp_size_t nn0, qn0;
+  mp_size_t nn1, qn1;
+  mp_ptr tp;
+  mp_limb_t qml;
+  mp_limb_t qh;
+  int cnt;
+  mp_ptr xdp;
+  mp_limb_t di;
+  mp_limb_t cy;
+  gmp_pi1_t dinv;
+  TMP_DECL;
+
+  TMP_MARK;
+
+  qn = nn - dn + 1;
+
+  /* For small divisors, and small quotients, don't use Jebelean's algorithm. */
+  if (dn < DIVEXACT_JEB_THRESHOLD || qn < DIVEXACT_JEB_THRESHOLD)
+    {
+      tp = scratch;
+      MPN_COPY (tp, np, qn);
+      binvert_limb (di, dp[0]);  di = -di;
+      dn = MIN (dn, qn);
+      mpn_sbpi1_bdiv_q (qp, tp, qn, dp, dn, di);
+      TMP_FREE;
+      return;
+    }
+
+  qn0 = ((nn - dn) >> 1) + 1;	/* low quotient size */
+
+  /* If quotient is much larger than the divisor, the bidirectional algorithm
+     does not work as currently implemented.  Fall back to plain bdiv.  */
+  if (qn0 > dn)
+    {
+      if (BELOW_THRESHOLD (dn, DC_BDIV_Q_THRESHOLD))
+	{
+	  tp = scratch;
+	  MPN_COPY (tp, np, qn);
+	  binvert_limb (di, dp[0]);  di = -di;
+	  dn = MIN (dn, qn);
+	  mpn_sbpi1_bdiv_q (qp, tp, qn, dp, dn, di);
+	}
+      else if (BELOW_THRESHOLD (dn, MU_BDIV_Q_THRESHOLD))
+	{
+	  tp = scratch;
+	  MPN_COPY (tp, np, qn);
+	  binvert_limb (di, dp[0]);  di = -di;
+	  mpn_dcpi1_bdiv_q (qp, tp, qn, dp, dn, di);
+	}
+      else
+	{
+	  mpn_mu_bdiv_q (qp, np, qn, dp, dn, scratch);
+	}
+      TMP_FREE;
+      return;
+    }
+
+  nn0 = qn0 + qn0;
+
+  nn1 = nn0 - 1 + ((nn-dn) & 1);
+  qn1 = qn0;
+  if (LIKELY (qn0 != dn))
+    {
+      nn1 = nn1 + 1;
+      qn1 = qn1 + 1;
+      if (UNLIKELY (dp[dn - 1] == 1 && qn1 != dn))
+	{
+	  /* If the leading divisor limb == 1, i.e. has just one bit, we have
+	     to include an extra limb in order to get the needed overlap.  */
+	  /* FIXME: Now with the mu_divappr_q function, we should really need
+	     more overlap. That indicates one of two things: (1) The test code
+	     is not good. (2) We actually overlap too much by default.  */
+	  nn1 = nn1 + 1;
+	  qn1 = qn1 + 1;
+	}
+    }
+
+  tp = TMP_ALLOC_LIMBS (nn1 + 1);
+
+  count_leading_zeros (cnt, dp[dn - 1]);
+
+  /* Normalize divisor, store into tmp area.  */
+  if (cnt != 0)
+    {
+      xdp = TMP_ALLOC_LIMBS (qn1);
+      mpn_lshift (xdp, dp + dn - qn1, qn1, cnt);
+    }
+  else
+    {
+      xdp = (mp_ptr) dp + dn - qn1;
+    }
+
+  /* Shift dividend according to the divisor normalization.  */
+  /* FIXME: We compute too much here for XX_divappr_q, but these functions'
+     interfaces want a pointer to the imaginative least significant limb, not
+     to the least significant *used* limb.  Of course, we could leave nn1-qn1
+     rubbish limbs in the low part, to save some time.  */
+  if (cnt != 0)
+    {
+      cy = mpn_lshift (tp, np + nn - nn1, nn1, cnt);
+      if (cy != 0)
+	{
+	  tp[nn1] = cy;
+	  nn1++;
+	}
+    }
+  else
+    {
+      /* FIXME: This copy is not needed for mpn_mu_divappr_q, except when the
+	 mpn_sub_n right before is executed.  */
+      MPN_COPY (tp, np + nn - nn1, nn1);
+    }
+
+  invert_pi1 (dinv, xdp[qn1 - 1], xdp[qn1 - 2]);
+  if (BELOW_THRESHOLD (qn1, DC_DIVAPPR_Q_THRESHOLD))
+    {
+      qp[qn0 - 1 + nn1 - qn1] = mpn_sbpi1_divappr_q (qp + qn0 - 1, tp, nn1, xdp, qn1, dinv.inv32);
+    }
+  else if (BELOW_THRESHOLD (qn1, MU_DIVAPPR_Q_THRESHOLD))
+    {
+      qp[qn0 - 1 + nn1 - qn1] = mpn_dcpi1_divappr_q (qp + qn0 - 1, tp, nn1, xdp, qn1, &dinv);
+    }
+  else
+    {
+      /* FIXME: mpn_mu_divappr_q doesn't handle qh != 0.  Work around it with a
+	 conditional subtraction here.  */
+      qh = mpn_cmp (tp + nn1 - qn1, xdp, qn1) >= 0;
+      if (qh)
+	mpn_sub_n (tp + nn1 - qn1, tp + nn1 - qn1, xdp, qn1);
+      mpn_mu_divappr_q (qp + qn0 - 1, tp, nn1, xdp, qn1, scratch);
+      qp[qn0 - 1 + nn1 - qn1] = qh;
+    }
+  qml = qp[qn0 - 1];
+
+  binvert_limb (di, dp[0]);  di = -di;
+
+  if (BELOW_THRESHOLD (qn0, DC_BDIV_Q_THRESHOLD))
+    {
+      MPN_COPY (tp, np, qn0);
+      mpn_sbpi1_bdiv_q (qp, tp, qn0, dp, qn0, di);
+    }
+  else if (BELOW_THRESHOLD (qn0, MU_BDIV_Q_THRESHOLD))
+    {
+      MPN_COPY (tp, np, qn0);
+      mpn_dcpi1_bdiv_q (qp, tp, qn0, dp, qn0, di);
+    }
+  else
+    {
+      mpn_mu_bdiv_q (qp, np, qn0, dp, qn0, scratch);
+    }
+
+  if (qml < qp[qn0 - 1])
+    mpn_decr_u (qp + qn0, 1);
+
+  TMP_FREE;
+}
+#endif
diff --git a/third_party/gmp/mpn/generic/divis.c b/third_party/gmp/mpn/generic/divis.c
new file mode 100644
index 0000000..f989ddb
--- /dev/null
+++ b/third_party/gmp/mpn/generic/divis.c
@@ -0,0 +1,194 @@
+/* mpn_divisible_p -- mpn by mpn divisibility test
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2001, 2002, 2005, 2009, 2014, 2017, 2018 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* Determine whether A={ap,an} is divisible by D={dp,dn}.  Must have both
+   operands normalized, meaning high limbs non-zero, except that an==0 is
+   allowed.
+
+   There usually won't be many low zero bits on D, but the checks for this
+   are fast and might pick up a few operand combinations, in particular they
+   might reduce D to fit the single-limb mod_1/modexact_1 code.
+
+   Future:
+
+   Getting the remainder limb by limb would make an early exit possible on
+   finding a non-zero.  This would probably have to be bdivmod style so
+   there's no addback, but it would need a multi-precision inverse and so
+   might be slower than the plain method (on small sizes at least).
+
+   When D must be normalized (shifted to low bit set), it's possible to
+   suppress the bit-shifting of A down, as long as it's already been checked
+   that A has at least as many trailing zero bits as D.  */
+
+int
+mpn_divisible_p (mp_srcptr ap, mp_size_t an,
+		 mp_srcptr dp, mp_size_t dn)
+{
+  mp_limb_t  alow, dlow, dmask;
+  mp_ptr     qp, rp, tp;
+  mp_limb_t di;
+  unsigned  twos;
+  int c;
+  TMP_DECL;
+
+  ASSERT (an >= 0);
+  ASSERT (an == 0 || ap[an-1] != 0);
+  ASSERT (dn >= 1);
+  ASSERT (dp[dn-1] != 0);
+  ASSERT_MPN (ap, an);
+  ASSERT_MPN (dp, dn);
+
+  /* When a<d only a==0 is divisible.
+     Notice this test covers all cases of an==0. */
+  if (an < dn)
+    return (an == 0);
+
+  /* Strip low zero limbs from d, requiring a==0 on those. */
+  for (;;)
+    {
+      alow = *ap;
+      dlow = *dp;
+
+      if (dlow != 0)
+	break;
+
+      if (alow != 0)
+	return 0;  /* a has fewer low zero limbs than d, so not divisible */
+
+      /* a!=0 and d!=0 so won't get to n==0 */
+      an--; ASSERT (an >= 1);
+      dn--; ASSERT (dn >= 1);
+      ap++;
+      dp++;
+    }
+
+  /* a must have at least as many low zero bits as d */
+  dmask = LOW_ZEROS_MASK (dlow);
+  if ((alow & dmask) != 0)
+    return 0;
+
+  if (dn == 1)
+    {
+      if (ABOVE_THRESHOLD (an, BMOD_1_TO_MOD_1_THRESHOLD))
+	return mpn_mod_1 (ap, an, dlow) == 0;
+
+      count_trailing_zeros (twos, dlow);
+      dlow >>= twos;
+      return mpn_modexact_1_odd (ap, an, dlow) == 0;
+    }
+
+  count_trailing_zeros (twos, dlow);
+  if (dn == 2)
+    {
+      mp_limb_t  dsecond = dp[1];
+      if (dsecond <= dmask)
+	{
+	  dlow = (dlow >> twos) | (dsecond << (GMP_NUMB_BITS-twos));
+	  ASSERT_LIMB (dlow);
+	  return MPN_MOD_OR_MODEXACT_1_ODD (ap, an, dlow) == 0;
+	}
+    }
+
+  /* Should we compute Q = A * D^(-1) mod B^k,
+                       R = A - Q * D  mod B^k
+     here, for some small values of k?  Then check if R = 0 (mod B^k).  */
+
+  /* We could also compute A' = A mod T and D' = D mod P, for some
+     P = 3 * 5 * 7 * 11 ..., and then check if any prime factor from P
+     dividing D' also divides A'.  */
+
+  TMP_MARK;
+
+  TMP_ALLOC_LIMBS_2 (rp, an + 1,
+		     qp, an - dn + 1); /* FIXME: Could we avoid this? */
+
+  if (twos != 0)
+    {
+      tp = TMP_ALLOC_LIMBS (dn);
+      ASSERT_NOCARRY (mpn_rshift (tp, dp, dn, twos));
+      dp = tp;
+
+      ASSERT_NOCARRY (mpn_rshift (rp, ap, an, twos));
+    }
+  else
+    {
+      MPN_COPY (rp, ap, an);
+    }
+  if (rp[an - 1] >= dp[dn - 1])
+    {
+      rp[an] = 0;
+      an++;
+    }
+  else if (an == dn)
+    {
+      TMP_FREE;
+      return 0;
+    }
+
+  ASSERT (an > dn);		/* requirement of functions below */
+
+  if (BELOW_THRESHOLD (dn, DC_BDIV_QR_THRESHOLD) ||
+      BELOW_THRESHOLD (an - dn, DC_BDIV_QR_THRESHOLD))
+    {
+      binvert_limb (di, dp[0]);
+      mpn_sbpi1_bdiv_qr (qp, rp, an, dp, dn, -di);
+      rp += an - dn;
+    }
+  else if (BELOW_THRESHOLD (dn, MU_BDIV_QR_THRESHOLD))
+    {
+      binvert_limb (di, dp[0]);
+      mpn_dcpi1_bdiv_qr (qp, rp, an, dp, dn, -di);
+      rp += an - dn;
+    }
+  else
+    {
+      tp = TMP_ALLOC_LIMBS (mpn_mu_bdiv_qr_itch (an, dn));
+      mpn_mu_bdiv_qr (qp, rp, rp, an, dp, dn, tp);
+    }
+
+  /* In general, bdiv may return either R = 0 or R = D when D divides
+     A. But R = 0 can happen only when A = 0, which we already have
+     excluded. Furthermore, R == D (mod B^{dn}) implies no carry, so
+     we don't need to check the carry returned from bdiv. */
+
+  MPN_CMP (c, rp, dp, dn);
+
+  TMP_FREE;
+  return c == 0;
+}
diff --git a/third_party/gmp/mpn/generic/divrem.c b/third_party/gmp/mpn/generic/divrem.c
new file mode 100644
index 0000000..1da84a8
--- /dev/null
+++ b/third_party/gmp/mpn/generic/divrem.c
@@ -0,0 +1,103 @@
+/* mpn_divrem -- Divide natural numbers, producing both remainder and
+   quotient.  This is now just a middle layer calling mpn_tdiv_qr.
+
+Copyright 1993-1997, 1999-2002, 2005, 2016 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+mp_limb_t
+mpn_divrem (mp_ptr qp, mp_size_t qxn,
+	    mp_ptr np, mp_size_t nn,
+	    mp_srcptr dp, mp_size_t dn)
+{
+  ASSERT (qxn >= 0);
+  ASSERT (nn >= dn);
+  ASSERT (dn >= 1);
+  ASSERT (dp[dn-1] & GMP_NUMB_HIGHBIT);
+  ASSERT (! MPN_OVERLAP_P (np, nn, dp, dn));
+  ASSERT (! MPN_OVERLAP_P (qp, nn-dn+qxn, np, nn) || qp==np+dn+qxn);
+  ASSERT (! MPN_OVERLAP_P (qp, nn-dn+qxn, dp, dn));
+  ASSERT_MPN (np, nn);
+  ASSERT_MPN (dp, dn);
+
+  if (dn == 1)
+    {
+      mp_limb_t ret;
+      mp_ptr q2p;
+      mp_size_t qn;
+      TMP_DECL;
+
+      TMP_MARK;
+      q2p = TMP_ALLOC_LIMBS (nn + qxn);
+
+      np[0] = mpn_divrem_1 (q2p, qxn, np, nn, dp[0]);
+      qn = nn + qxn - 1;
+      MPN_COPY (qp, q2p, qn);
+      ret = q2p[qn];
+
+      TMP_FREE;
+      return ret;
+    }
+  else if (dn == 2)
+    {
+      return mpn_divrem_2 (qp, qxn, np, nn, dp);
+    }
+  else
+    {
+      mp_ptr q2p;
+      mp_limb_t qhl;
+      mp_size_t qn;
+      TMP_DECL;
+
+      TMP_MARK;
+      if (UNLIKELY (qxn != 0))
+	{
+	  mp_ptr n2p;
+	  TMP_ALLOC_LIMBS_2 (n2p, nn + qxn,
+			     q2p, nn - dn + qxn + 1);
+	  MPN_ZERO (n2p, qxn);
+	  MPN_COPY (n2p + qxn, np, nn);
+	  mpn_tdiv_qr (q2p, np, 0L, n2p, nn + qxn, dp, dn);
+	  qn = nn - dn + qxn;
+	  MPN_COPY (qp, q2p, qn);
+	  qhl = q2p[qn];
+	}
+      else
+	{
+	  q2p = TMP_ALLOC_LIMBS (nn - dn + 1);
+	  mpn_tdiv_qr (q2p, np, 0L, np, nn, dp, dn);
+	  qn = nn - dn;
+	  MPN_COPY (qp, q2p, qn);
+	  qhl = q2p[qn];
+	}
+      TMP_FREE;
+      return qhl;
+    }
+}
diff --git a/third_party/gmp/mpn/generic/divrem_1.c b/third_party/gmp/mpn/generic/divrem_1.c
new file mode 100644
index 0000000..c13aa79
--- /dev/null
+++ b/third_party/gmp/mpn/generic/divrem_1.c
@@ -0,0 +1,254 @@
+/* mpn_divrem_1 -- mpn by limb division.
+
+Copyright 1991, 1993, 1994, 1996, 1998-2000, 2002, 2003 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* The size where udiv_qrnnd_preinv should be used rather than udiv_qrnnd,
+   meaning the quotient size where that should happen, the quotient size
+   being how many udiv divisions will be done.
+
+   The default is to use preinv always, CPUs where this doesn't suit have
+   tuned thresholds.  Note in particular that preinv should certainly be
+   used if that's the only division available (USE_PREINV_ALWAYS).  */
+
+#ifndef DIVREM_1_NORM_THRESHOLD
+#define DIVREM_1_NORM_THRESHOLD  0
+#endif
+#ifndef DIVREM_1_UNNORM_THRESHOLD
+#define DIVREM_1_UNNORM_THRESHOLD  0
+#endif
+
+
+
+/* If the cpu only has multiply-by-inverse division (eg. alpha), then NORM
+   and UNNORM thresholds are 0 and only the inversion code is included.
+
+   If multiply-by-inverse is never viable, then NORM and UNNORM thresholds
+   will be MP_SIZE_T_MAX and only the plain division code is included.
+
+   Otherwise mul-by-inverse is better than plain division above some
+   threshold, and best results are obtained by having code for both present.
+
+   The main reason for separating the norm and unnorm cases is that not all
+   CPUs give zero for "n0 >> GMP_LIMB_BITS" which would arise in the unnorm
+   code used on an already normalized divisor.
+
+   If UDIV_NEEDS_NORMALIZATION is false then plain division uses the same
+   non-shifting code for both the norm and unnorm cases, though with
+   different criteria for skipping a division, and with different thresholds
+   of course.  And in fact if inversion is never viable, then that simple
+   non-shifting division would be all that's left.
+
+   The NORM and UNNORM thresholds might not differ much, but if there's
+   going to be separate code for norm and unnorm then it makes sense to have
+   separate thresholds.  One thing that's possible is that the
+   mul-by-inverse might be better only for normalized divisors, due to that
+   case not needing variable bit shifts.
+
+   Notice that the thresholds are tested after the decision to possibly skip
+   one divide step, so they're based on the actual number of divisions done.
+
+   For the unnorm case, it would be possible to call mpn_lshift to adjust
+   the dividend all in one go (into the quotient space say), rather than
+   limb-by-limb in the loop.  This might help if mpn_lshift is a lot faster
+   than what the compiler can generate for EXTRACT.  But this is left to CPU
+   specific implementations to consider, especially since EXTRACT isn't on
+   the dependent chain.  */
+
+mp_limb_t
+mpn_divrem_1 (mp_ptr qp, mp_size_t qxn,
+	      mp_srcptr up, mp_size_t un, mp_limb_t d)
+{
+  mp_size_t  n;
+  mp_size_t  i;
+  mp_limb_t  n1, n0;
+  mp_limb_t  r = 0;
+
+  ASSERT (qxn >= 0);
+  ASSERT (un >= 0);
+  ASSERT (d != 0);
+  /* FIXME: What's the correct overlap rule when qxn!=0? */
+  ASSERT (MPN_SAME_OR_SEPARATE_P (qp+qxn, up, un));
+
+  n = un + qxn;
+  if (n == 0)
+    return 0;
+
+  d <<= GMP_NAIL_BITS;
+
+  qp += (n - 1);   /* Make qp point at most significant quotient limb */
+
+  if ((d & GMP_LIMB_HIGHBIT) != 0)
+    {
+      if (un != 0)
+	{
+	  /* High quotient limb is 0 or 1, skip a divide step. */
+	  mp_limb_t q;
+	  r = up[un - 1] << GMP_NAIL_BITS;
+	  q = (r >= d);
+	  *qp-- = q;
+	  r -= (d & -q);
+	  r >>= GMP_NAIL_BITS;
+	  n--;
+	  un--;
+	}
+
+      if (BELOW_THRESHOLD (n, DIVREM_1_NORM_THRESHOLD))
+	{
+	plain:
+	  for (i = un - 1; i >= 0; i--)
+	    {
+	      n0 = up[i] << GMP_NAIL_BITS;
+	      udiv_qrnnd (*qp, r, r, n0, d);
+	      r >>= GMP_NAIL_BITS;
+	      qp--;
+	    }
+	  for (i = qxn - 1; i >= 0; i--)
+	    {
+	      udiv_qrnnd (*qp, r, r, CNST_LIMB(0), d);
+	      r >>= GMP_NAIL_BITS;
+	      qp--;
+	    }
+	  return r;
+	}
+      else
+	{
+	  /* Multiply-by-inverse, divisor already normalized. */
+	  mp_limb_t dinv;
+	  invert_limb (dinv, d);
+
+	  for (i = un - 1; i >= 0; i--)
+	    {
+	      n0 = up[i] << GMP_NAIL_BITS;
+	      udiv_qrnnd_preinv (*qp, r, r, n0, d, dinv);
+	      r >>= GMP_NAIL_BITS;
+	      qp--;
+	    }
+	  for (i = qxn - 1; i >= 0; i--)
+	    {
+	      udiv_qrnnd_preinv (*qp, r, r, CNST_LIMB(0), d, dinv);
+	      r >>= GMP_NAIL_BITS;
+	      qp--;
+	    }
+	  return r;
+	}
+    }
+  else
+    {
+      /* Most significant bit of divisor == 0.  */
+      int cnt;
+
+      /* Skip a division if high < divisor (high quotient 0).  Testing here
+	 before normalizing will still skip as often as possible.  */
+      if (un != 0)
+	{
+	  n1 = up[un - 1] << GMP_NAIL_BITS;
+	  if (n1 < d)
+	    {
+	      r = n1 >> GMP_NAIL_BITS;
+	      *qp-- = 0;
+	      n--;
+	      if (n == 0)
+		return r;
+	      un--;
+	    }
+	}
+
+      if (! UDIV_NEEDS_NORMALIZATION
+	  && BELOW_THRESHOLD (n, DIVREM_1_UNNORM_THRESHOLD))
+	goto plain;
+
+      count_leading_zeros (cnt, d);
+      d <<= cnt;
+      r <<= cnt;
+
+      if (UDIV_NEEDS_NORMALIZATION
+	  && BELOW_THRESHOLD (n, DIVREM_1_UNNORM_THRESHOLD))
+	{
+	  mp_limb_t nshift;
+	  if (un != 0)
+	    {
+	      n1 = up[un - 1] << GMP_NAIL_BITS;
+	      r |= (n1 >> (GMP_LIMB_BITS - cnt));
+	      for (i = un - 2; i >= 0; i--)
+		{
+		  n0 = up[i] << GMP_NAIL_BITS;
+		  nshift = (n1 << cnt) | (n0 >> (GMP_NUMB_BITS - cnt));
+		  udiv_qrnnd (*qp, r, r, nshift, d);
+		  r >>= GMP_NAIL_BITS;
+		  qp--;
+		  n1 = n0;
+		}
+	      udiv_qrnnd (*qp, r, r, n1 << cnt, d);
+	      r >>= GMP_NAIL_BITS;
+	      qp--;
+	    }
+	  for (i = qxn - 1; i >= 0; i--)
+	    {
+	      udiv_qrnnd (*qp, r, r, CNST_LIMB(0), d);
+	      r >>= GMP_NAIL_BITS;
+	      qp--;
+	    }
+	  return r >> cnt;
+	}
+      else
+	{
+	  mp_limb_t  dinv, nshift;
+	  invert_limb (dinv, d);
+	  if (un != 0)
+	    {
+	      n1 = up[un - 1] << GMP_NAIL_BITS;
+	      r |= (n1 >> (GMP_LIMB_BITS - cnt));
+	      for (i = un - 2; i >= 0; i--)
+		{
+		  n0 = up[i] << GMP_NAIL_BITS;
+		  nshift = (n1 << cnt) | (n0 >> (GMP_NUMB_BITS - cnt));
+		  udiv_qrnnd_preinv (*qp, r, r, nshift, d, dinv);
+		  r >>= GMP_NAIL_BITS;
+		  qp--;
+		  n1 = n0;
+		}
+	      udiv_qrnnd_preinv (*qp, r, r, n1 << cnt, d, dinv);
+	      r >>= GMP_NAIL_BITS;
+	      qp--;
+	    }
+	  for (i = qxn - 1; i >= 0; i--)
+	    {
+	      udiv_qrnnd_preinv (*qp, r, r, CNST_LIMB(0), d, dinv);
+	      r >>= GMP_NAIL_BITS;
+	      qp--;
+	    }
+	  return r >> cnt;
+	}
+    }
+}
diff --git a/third_party/gmp/mpn/generic/divrem_2.c b/third_party/gmp/mpn/generic/divrem_2.c
new file mode 100644
index 0000000..217f2f6
--- /dev/null
+++ b/third_party/gmp/mpn/generic/divrem_2.c
@@ -0,0 +1,118 @@
+/* mpn_divrem_2 -- Divide natural numbers, producing both remainder and
+   quotient.  The divisor is two limbs.
+
+   THIS FILE CONTAINS INTERNAL FUNCTIONS WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+
+Copyright 1993-1996, 1999-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* Divide num {np,nn} by den {dp,2} and write the nn-2 least significant
+   quotient limbs at qp and the 2 long remainder at np.  If qxn is non-zero,
+   generate that many fraction bits and append them after the other quotient
+   limbs.  Return the most significant limb of the quotient, this is always 0
+   or 1.
+
+   Preconditions:
+   1. The most significant bit of the divisor must be set.
+   2. qp must either not overlap with the input operands at all, or
+      qp >= np + 2 must hold true.  (This means that it's possible to put
+      the quotient in the high part of {np,nn}, right above the remainder.
+   3. nn >= 2, even if qxn is non-zero.  */
+
+mp_limb_t
+mpn_divrem_2 (mp_ptr qp, mp_size_t qxn,
+	      mp_ptr np, mp_size_t nn,
+	      mp_srcptr dp)
+{
+  mp_limb_t most_significant_q_limb;
+  mp_size_t i;
+  mp_limb_t r1, r0, d1, d0;
+  gmp_pi1_t di;
+
+  ASSERT (nn >= 2);
+  ASSERT (qxn >= 0);
+  ASSERT (dp[1] & GMP_NUMB_HIGHBIT);
+  ASSERT (! MPN_OVERLAP_P (qp, nn-2+qxn, np, nn) || qp >= np+2);
+  ASSERT_MPN (np, nn);
+  ASSERT_MPN (dp, 2);
+
+  np += nn - 2;
+  d1 = dp[1];
+  d0 = dp[0];
+  r1 = np[1];
+  r0 = np[0];
+
+  most_significant_q_limb = 0;
+  if (r1 >= d1 && (r1 > d1 || r0 >= d0))
+    {
+#if GMP_NAIL_BITS == 0
+      sub_ddmmss (r1, r0, r1, r0, d1, d0);
+#else
+      r0 = r0 - d0;
+      r1 = r1 - d1 - (r0 >> GMP_LIMB_BITS - 1);
+      r0 &= GMP_NUMB_MASK;
+#endif
+      most_significant_q_limb = 1;
+    }
+
+  invert_pi1 (di, d1, d0);
+
+  qp += qxn;
+
+  for (i = nn - 2 - 1; i >= 0; i--)
+    {
+      mp_limb_t n0, q;
+      n0 = np[-1];
+      udiv_qr_3by2 (q, r1, r0, r1, r0, n0, d1, d0, di.inv32);
+      np--;
+      qp[i] = q;
+    }
+
+  if (UNLIKELY (qxn != 0))
+    {
+      qp -= qxn;
+      for (i = qxn - 1; i >= 0; i--)
+	{
+	  mp_limb_t q;
+	  udiv_qr_3by2 (q, r1, r0, r1, r0, CNST_LIMB(0), d1, d0, di.inv32);
+	  qp[i] = q;
+	}
+    }
+
+  np[1] = r1;
+  np[0] = r0;
+
+  return most_significant_q_limb;
+}
diff --git a/third_party/gmp/mpn/generic/dump.c b/third_party/gmp/mpn/generic/dump.c
new file mode 100644
index 0000000..9a4ddf4
--- /dev/null
+++ b/third_party/gmp/mpn/generic/dump.c
@@ -0,0 +1,99 @@
+/* THIS IS AN INTERNAL FUNCTION WITH A MUTABLE INTERFACE.  IT IS NOT SAFE TO
+   CALL THIS FUNCTION DIRECTLY.  IN FACT, IT IS ALMOST GUARANTEED THAT THIS
+   FUNCTION WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+
+Copyright 1996, 2000-2002, 2005 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp-impl.h"
+
+#if GMP_NUMB_BITS % 4 == 0
+void
+mpn_dump (mp_srcptr ptr, mp_size_t n)
+{
+  MPN_NORMALIZE (ptr, n);
+
+  if (n == 0)
+    printf ("0\n");
+  else
+    {
+      n--;
+#if _LONG_LONG_LIMB
+      if ((ptr[n] >> GMP_LIMB_BITS / 2) != 0)
+	{
+	  printf ("%lX", (unsigned long) (ptr[n] >> GMP_LIMB_BITS / 2));
+	  printf ("%0*lX", (GMP_LIMB_BITS / 2 / 4), (unsigned long) ptr[n]);
+	}
+      else
+#endif
+	printf ("%lX", (unsigned long) ptr[n]);
+
+      while (n)
+	{
+	  n--;
+#if _LONG_LONG_LIMB
+	  printf ("%0*lX", (GMP_NUMB_BITS - GMP_LIMB_BITS / 2) / 4,
+		  (unsigned long) (ptr[n] >> GMP_LIMB_BITS / 2));
+	  printf ("%0*lX", GMP_LIMB_BITS / 2 / 4, (unsigned long) ptr[n]);
+#else
+	  printf ("%0*lX", GMP_NUMB_BITS / 4, (unsigned long) ptr[n]);
+#endif
+	}
+      printf ("\n");
+    }
+}
+
+#else
+
+static void
+mpn_recdump (mp_ptr p, mp_size_t n)
+{
+  mp_limb_t lo;
+  if (n != 0)
+    {
+      lo = p[0] & 0xf;
+      mpn_rshift (p, p, n, 4);
+      mpn_recdump (p, n);
+      printf ("%lX", lo);
+    }
+}
+
+void
+mpn_dump (mp_srcptr p, mp_size_t n)
+{
+  mp_ptr tp;
+  TMP_DECL;
+  TMP_MARK;
+  tp = TMP_ALLOC_LIMBS (n);
+  MPN_COPY (tp, p, n);
+  TMP_FREE;
+}
+
+#endif
diff --git a/third_party/gmp/mpn/generic/fib2_ui.c b/third_party/gmp/mpn/generic/fib2_ui.c
new file mode 100644
index 0000000..0b81571
--- /dev/null
+++ b/third_party/gmp/mpn/generic/fib2_ui.c
@@ -0,0 +1,174 @@
+/* mpn_fib2_ui -- calculate Fibonacci numbers.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2001, 2002, 2005, 2009, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp-impl.h"
+
+/* change this to "#define TRACE(x) x" for diagnostics */
+#define TRACE(x)
+
+
+/* Store F[n] at fp and F[n-1] at f1p.  fp and f1p should have room for
+   MPN_FIB2_SIZE(n) limbs.
+
+   The return value is the actual number of limbs stored, this will be at
+   least 1.  fp[size-1] will be non-zero, except when n==0, in which case
+   fp[0] is 0 and f1p[0] is 1.  f1p[size-1] can be zero, since F[n-1]<F[n]
+   (for n>0).
+
+   Notes: F[2k+1] = 4*F[k]^2 - F[k-1]^2 + 2*(-1)^k.
+
+   In F[2k+1] with k even, +2 is applied to 4*F[k]^2 just by ORing into the
+   low limb.
+
+   In F[2k+1] with k odd, -2 is applied to F[k-1]^2 just by ORing into the
+   low limb.
+*/
+
+mp_size_t
+mpn_fib2_ui (mp_ptr fp, mp_ptr f1p, unsigned long int n)
+{
+  mp_size_t      size;
+  unsigned long  nfirst, mask;
+
+  TRACE (printf ("mpn_fib2_ui n=%lu\n", n));
+
+  ASSERT (! MPN_OVERLAP_P (fp, MPN_FIB2_SIZE(n), f1p, MPN_FIB2_SIZE(n)));
+
+  /* Take a starting pair from the table. */
+  mask = 1;
+  for (nfirst = n; nfirst > FIB_TABLE_LIMIT; nfirst /= 2)
+    mask <<= 1;
+  TRACE (printf ("nfirst=%lu mask=0x%lX\n", nfirst, mask));
+
+  f1p[0] = FIB_TABLE ((int) nfirst - 1);
+  fp[0]  = FIB_TABLE (nfirst);
+  size = 1;
+
+  /* Skip to the end if the table lookup gives the final answer. */
+  if (mask != 1)
+    {
+      mp_size_t  alloc;
+      mp_ptr        xp;
+      TMP_DECL;
+
+      TMP_MARK;
+      alloc = MPN_FIB2_SIZE (n);
+      xp = TMP_ALLOC_LIMBS (alloc);
+
+      do
+	{
+	  /* Here fp==F[k] and f1p==F[k-1], with k being the bits of n from
+	     n&mask upwards.
+
+	     The next bit of n is n&(mask>>1) and we'll double to the pair
+	     fp==F[2k],f1p==F[2k-1] or fp==F[2k+1],f1p==F[2k], according as
+	     that bit is 0 or 1 respectively.  */
+
+	  TRACE (printf ("k=%lu mask=0x%lX size=%ld alloc=%ld\n",
+			 n >> refmpn_count_trailing_zeros(mask),
+			 mask, size, alloc);
+		 mpn_trace ("fp ", fp, size);
+		 mpn_trace ("f1p", f1p, size));
+
+	  /* fp normalized, f1p at most one high zero */
+	  ASSERT (fp[size-1] != 0);
+	  ASSERT (f1p[size-1] != 0 || f1p[size-2] != 0);
+
+	  /* f1p[size-1] might be zero, but this occurs rarely, so it's not
+	     worth bothering checking for it */
+	  ASSERT (alloc >= 2*size);
+	  mpn_sqr (xp, fp,  size);
+	  mpn_sqr (fp, f1p, size);
+	  size *= 2;
+
+	  /* Shrink if possible.  Since fp was normalized there'll be at
+	     most one high zero on xp (and if there is then there's one on
+	     yp too).  */
+	  ASSERT (xp[size-1] != 0 || fp[size-1] == 0);
+	  size -= (xp[size-1] == 0);
+	  ASSERT (xp[size-1] != 0);  /* only one xp high zero */
+
+	  /* Calculate F[2k-1] = F[k]^2 + F[k-1]^2. */
+	  f1p[size] = mpn_add_n (f1p, xp, fp, size);
+
+	  /* Calculate F[2k+1] = 4*F[k]^2 - F[k-1]^2 + 2*(-1)^k.
+	     n&mask is the low bit of our implied k.  */
+
+	  ASSERT ((fp[0] & 2) == 0);
+	  /* fp is F[k-1]^2 == 0 or 1 mod 4, like all squares. */
+	  fp[0] |= (n & mask ? 2 : 0);			/* possible -2 */
+#if HAVE_NATIVE_mpn_rsblsh2_n
+	  fp[size] = mpn_rsblsh2_n (fp, fp, xp, size);
+	  MPN_INCR_U(fp, size + 1, (n & mask ? 0 : 2));	/* possible +2 */
+#else
+	  {
+	    mp_limb_t  c;
+
+	    c = mpn_lshift (xp, xp, size, 2);
+	    xp[0] |= (n & mask ? 0 : 2);	/* possible +2 */
+	    c -= mpn_sub_n (fp, xp, fp, size);
+	    fp[size] = c;
+	  }
+#endif
+	  ASSERT (alloc >= size+1);
+	  size += (fp[size] != 0);
+
+	  /* now n&mask is the new bit of n being considered */
+	  mask >>= 1;
+
+	  /* Calculate F[2k] = F[2k+1] - F[2k-1], replacing the unwanted one of
+	     F[2k+1] and F[2k-1].  */
+	  if (n & mask)
+	    ASSERT_NOCARRY (mpn_sub_n (f1p, fp, f1p, size));
+	  else {
+	    ASSERT_NOCARRY (mpn_sub_n ( fp, fp, f1p, size));
+
+	    /* Can have a high zero after replacing F[2k+1] with F[2k].
+	       f1p will have a high zero if fp does. */
+	    ASSERT (fp[size-1] != 0 || f1p[size-1] == 0);
+	    size -= (fp[size-1] == 0);
+	  }
+	}
+      while (mask != 1);
+
+      TMP_FREE;
+    }
+
+  TRACE (printf ("done size=%ld\n", size);
+	 mpn_trace ("fp ", fp, size);
+	 mpn_trace ("f1p", f1p, size));
+
+  return size;
+}
diff --git a/third_party/gmp/mpn/generic/fib2m.c b/third_party/gmp/mpn/generic/fib2m.c
new file mode 100644
index 0000000..89d2b86
--- /dev/null
+++ b/third_party/gmp/mpn/generic/fib2m.c
@@ -0,0 +1,252 @@
+/* mpn_fib2m -- calculate Fibonacci numbers, modulo m.
+
+Contributed to the GNU project by Marco Bodrato, based on the previous
+fib2_ui.c file.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2001, 2002, 2005, 2009, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* Stores |{ap,n}-{bp,n}| in {rp,n},
+   returns the sign of {ap,n}-{bp,n}. */
+static int
+abs_sub_n (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n)
+{
+  mp_limb_t  x, y;
+  while (--n >= 0)
+    {
+      x = ap[n];
+      y = bp[n];
+      if (x != y)
+        {
+          ++n;
+          if (x > y)
+            {
+              ASSERT_NOCARRY (mpn_sub_n (rp, ap, bp, n));
+              return 1;
+            }
+          else
+            {
+              ASSERT_NOCARRY (mpn_sub_n (rp, bp, ap, n));
+              return -1;
+            }
+        }
+      rp[n] = 0;
+    }
+  return 0;
+}
+
+/* Store F[n] at fp and F[n-1] at f1p.  Both are computed modulo m.
+   fp and f1p should have room for mn*2+1 limbs.
+
+   The sign of one or both the values may be flipped (n-F, instead of F),
+   the return value is 0 (zero) if the signs are coherent (both positive
+   or both negative) and 1 (one) otherwise.
+
+   Notes:
+
+   In F[2k+1] with k even, +2 is applied to 4*F[k]^2 just by ORing into the
+   low limb.
+
+   In F[2k+1] with k odd, -2 is applied to F[k-1]^2 just by ORing into the
+   low limb.
+
+   TODO: Should {tp, 2 * mn} be passed as a scratch pointer?
+   Should the call to mpn_fib2_ui() obtain (up to) 2*mn limbs?
+*/
+
+int
+mpn_fib2m (mp_ptr fp, mp_ptr f1p, mp_srcptr np, mp_size_t nn, mp_srcptr mp, mp_size_t mn)
+{
+  unsigned long	nfirst;
+  mp_limb_t	nh;
+  mp_bitcnt_t	nbi;
+  mp_size_t	sn, fn;
+  int		fcnt, ncnt;
+
+  ASSERT (! MPN_OVERLAP_P (fp, MAX(2*mn+1,5), f1p, MAX(2*mn+1,5)));
+  ASSERT (nn > 0 && np[nn - 1] != 0);
+
+  /* Estimate the maximal n such that fibonacci(n) fits in mn limbs. */
+#if GMP_NUMB_BITS % 16 == 0
+  if (UNLIKELY (ULONG_MAX / (23 * (GMP_NUMB_BITS / 16)) <= mn))
+    nfirst = ULONG_MAX;
+  else
+    nfirst = mn * (23 * (GMP_NUMB_BITS / 16));
+#else
+  {
+    mp_bitcnt_t	mbi;
+    mbi = (mp_bitcnt_t) mn * GMP_NUMB_BITS;
+
+    if (UNLIKELY (ULONG_MAX / 23 < mbi))
+      {
+	if (UNLIKELY (ULONG_MAX / 23 * 16 <= mbi))
+	  nfirst = ULONG_MAX;
+	else
+	  nfirst = mbi / 16 * 23;
+      }
+    else
+      nfirst = mbi * 23 / 16;
+  }
+#endif
+
+  sn = nn - 1;
+  nh = np[sn];
+  count_leading_zeros (ncnt, nh);
+  count_leading_zeros (fcnt, nfirst);
+
+  if (fcnt >= ncnt)
+    {
+      ncnt = fcnt - ncnt;
+      nh >>= ncnt;
+    }
+  else if (sn > 0)
+    {
+      ncnt -= fcnt;
+      nh <<= ncnt;
+      ncnt = GMP_NUMB_BITS - ncnt;
+      --sn;
+      nh |= np[sn] >> ncnt;
+    }
+  else
+    ncnt = 0;
+
+  nbi = sn * GMP_NUMB_BITS + ncnt;
+  if (nh > nfirst)
+    {
+      nh >>= 1;
+      ++nbi;
+    }
+
+  ASSERT (nh <= nfirst);
+  /* Take a starting pair from mpn_fib2_ui. */
+  fn = mpn_fib2_ui (fp, f1p, nh);
+  MPN_ZERO (fp + fn, mn - fn);
+  MPN_ZERO (f1p + fn, mn - fn);
+
+  if (nbi == 0)
+    {
+      if (fn == mn)
+	{
+	  mp_limb_t qp[2];
+	  mpn_tdiv_qr (qp, fp, 0, fp, fn, mp, mn);
+	  mpn_tdiv_qr (qp, f1p, 0, f1p, fn, mp, mn);
+	}
+
+      return 0;
+    }
+  else
+    {
+      mp_ptr	tp;
+      unsigned	pb = nh & 1;
+      int	neg;
+      TMP_DECL;
+
+      TMP_MARK;
+
+      tp = TMP_ALLOC_LIMBS (2 * mn + (mn < 2));
+
+      do
+	{
+	  mp_ptr	rp;
+	  /* Here fp==F[k] and f1p==F[k-1], with k being the bits of n from
+	     nbi upwards.
+
+	     Based on the next bit of n, we'll double to the pair
+	     fp==F[2k],f1p==F[2k-1] or fp==F[2k+1],f1p==F[2k], according as
+	     that bit is 0 or 1 respectively.  */
+
+	  mpn_sqr (tp, fp,  mn);
+	  mpn_sqr (fp, f1p, mn);
+
+	  /* Calculate F[2k-1] = F[k]^2 + F[k-1]^2. */
+	  f1p[2 * mn] = mpn_add_n (f1p, tp, fp, 2 * mn);
+
+	  /* Calculate F[2k+1] = 4*F[k]^2 - F[k-1]^2 + 2*(-1)^k.
+	     pb is the low bit of our implied k.  */
+
+	  /* fp is F[k-1]^2 == 0 or 1 mod 4, like all squares. */
+	  ASSERT ((fp[0] & 2) == 0);
+	  ASSERT (pb == (pb & 1));
+	  ASSERT ((fp[0] + (pb ? 2 : 0)) == (fp[0] | (pb << 1)));
+	  fp[0] |= pb << 1;		/* possible -2 */
+#if HAVE_NATIVE_mpn_rsblsh2_n
+	  fp[2 * mn] = 1 + mpn_rsblsh2_n (fp, fp, tp, 2 * mn);
+	  MPN_INCR_U(fp, 2 * mn + 1, (1 ^ pb) << 1);	/* possible +2 */
+	  fp[2 * mn] = (fp[2 * mn] - 1) & GMP_NUMB_MAX;
+#else
+	  {
+	    mp_limb_t  c;
+
+	    c = mpn_lshift (tp, tp, 2 * mn, 2);
+	    tp[0] |= (1 ^ pb) << 1;	/* possible +2 */
+	    c -= mpn_sub_n (fp, tp, fp, 2 * mn);
+	    fp[2 * mn] = c & GMP_NUMB_MAX;
+	  }
+#endif
+	  neg = fp[2 * mn] == GMP_NUMB_MAX;
+
+	  /* Calculate F[2k-1] = F[k]^2 + F[k-1]^2 */
+	  /* Calculate F[2k+1] = 4*F[k]^2 - F[k-1]^2 + 2*(-1)^k */
+
+	  /* Calculate F[2k] = F[2k+1] - F[2k-1], replacing the unwanted one of
+	     F[2k+1] and F[2k-1].  */
+	  --nbi;
+	  pb = (np [nbi / GMP_NUMB_BITS] >> (nbi % GMP_NUMB_BITS)) & 1;
+	  rp = pb ? f1p : fp;
+	  if (neg)
+	    {
+	      /* Calculate -(F[2k+1] - F[2k-1]) */
+	      rp[2 * mn] = f1p[2 * mn] + 1 - mpn_sub_n (rp, f1p, fp, 2 * mn);
+	      neg = ! pb;
+	      if (pb) /* fp not overwritten, negate it. */
+		fp [2 * mn] = 1 ^ mpn_neg (fp, fp, 2 * mn);
+	    }
+	  else
+	    {
+	      neg = abs_sub_n (rp, fp, f1p, 2 * mn + 1) < 0;
+	    }
+
+	  mpn_tdiv_qr (tp, fp, 0, fp, 2 * mn + 1, mp, mn);
+	  mpn_tdiv_qr (tp, f1p, 0, f1p, 2 * mn + 1, mp, mn);
+	}
+      while (nbi != 0);
+
+      TMP_FREE;
+
+      return neg;
+    }
+}
diff --git a/third_party/gmp/mpn/generic/gcd.c b/third_party/gmp/mpn/generic/gcd.c
new file mode 100644
index 0000000..3f92cbf
--- /dev/null
+++ b/third_party/gmp/mpn/generic/gcd.c
@@ -0,0 +1,266 @@
+/* mpn/gcd.c: mpn_gcd for gcd of two odd integers.
+
+Copyright 1991, 1993-1998, 2000-2005, 2008, 2010, 2012, 2019 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/* Uses the HGCD operation described in
+
+     N. Möller, On Schönhage's algorithm and subquadratic integer gcd
+     computation, Math. Comp. 77 (2008), 589-607.
+
+  to reduce inputs until they are of size below GCD_DC_THRESHOLD, and
+  then uses Lehmer's algorithm.
+*/
+
+/* Some reasonable choices are n / 2 (same as in hgcd), and p = (n +
+ * 2)/3, which gives a balanced multiplication in
+ * mpn_hgcd_matrix_adjust. However, p = 2 n/3 gives slightly better
+ * performance. The matrix-vector multiplication is then
+ * 4:1-unbalanced, with matrix elements of size n/6, and vector
+ * elements of size p = 2n/3. */
+
+/* From analysis of the theoretical running time, it appears that when
+ * multiplication takes time O(n^alpha), p should be chosen so that
+ * the ratio of the time for the mpn_hgcd call, and the time for the
+ * multiplication in mpn_hgcd_matrix_adjust, is roughly 1/(alpha -
+ * 1). */
+#ifdef TUNE_GCD_P
+#define P_TABLE_SIZE 10000
+mp_size_t p_table[P_TABLE_SIZE];
+#define CHOOSE_P(n) ( (n) < P_TABLE_SIZE ? p_table[n] : 2*(n)/3)
+#else
+#define CHOOSE_P(n) (2*(n) / 3)
+#endif
+
+struct gcd_ctx
+{
+  mp_ptr gp;
+  mp_size_t gn;
+};
+
+static void
+gcd_hook (void *p, mp_srcptr gp, mp_size_t gn,
+	  mp_srcptr qp, mp_size_t qn, int d)
+{
+  struct gcd_ctx *ctx = (struct gcd_ctx *) p;
+  MPN_COPY (ctx->gp, gp, gn);
+  ctx->gn = gn;
+}
+
+mp_size_t
+mpn_gcd (mp_ptr gp, mp_ptr up, mp_size_t usize, mp_ptr vp, mp_size_t n)
+{
+  mp_size_t talloc;
+  mp_size_t scratch;
+  mp_size_t matrix_scratch;
+
+  struct gcd_ctx ctx;
+  mp_ptr tp;
+  TMP_DECL;
+
+  ASSERT (usize >= n);
+  ASSERT (n > 0);
+  ASSERT (vp[n-1] > 0);
+
+  /* FIXME: Check for small sizes first, before setting up temporary
+     storage etc. */
+  talloc = MPN_GCD_SUBDIV_STEP_ITCH(n);
+
+  /* For initial division */
+  scratch = usize - n + 1;
+  if (scratch > talloc)
+    talloc = scratch;
+
+#if TUNE_GCD_P
+  if (CHOOSE_P (n) > 0)
+#else
+  if (ABOVE_THRESHOLD (n, GCD_DC_THRESHOLD))
+#endif
+    {
+      mp_size_t hgcd_scratch;
+      mp_size_t update_scratch;
+      mp_size_t p = CHOOSE_P (n);
+      mp_size_t scratch;
+#if TUNE_GCD_P
+      /* Worst case, since we don't guarantee that n - CHOOSE_P(n)
+	 is increasing */
+      matrix_scratch = MPN_HGCD_MATRIX_INIT_ITCH (n);
+      hgcd_scratch = mpn_hgcd_itch (n);
+      update_scratch = 2*(n - 1);
+#else
+      matrix_scratch = MPN_HGCD_MATRIX_INIT_ITCH (n - p);
+      hgcd_scratch = mpn_hgcd_itch (n - p);
+      update_scratch = p + n - 1;
+#endif
+      scratch = matrix_scratch + MAX(hgcd_scratch, update_scratch);
+      if (scratch > talloc)
+	talloc = scratch;
+    }
+
+  TMP_MARK;
+  tp = TMP_ALLOC_LIMBS(talloc);
+
+  if (usize > n)
+    {
+      mpn_tdiv_qr (tp, up, 0, up, usize, vp, n);
+
+      if (mpn_zero_p (up, n))
+	{
+	  MPN_COPY (gp, vp, n);
+	  ctx.gn = n;
+	  goto done;
+	}
+    }
+
+  ctx.gp = gp;
+
+#if TUNE_GCD_P
+  while (CHOOSE_P (n) > 0)
+#else
+  while (ABOVE_THRESHOLD (n, GCD_DC_THRESHOLD))
+#endif
+    {
+      struct hgcd_matrix M;
+      mp_size_t p = CHOOSE_P (n);
+      mp_size_t matrix_scratch = MPN_HGCD_MATRIX_INIT_ITCH (n - p);
+      mp_size_t nn;
+      mpn_hgcd_matrix_init (&M, n - p, tp);
+      nn = mpn_hgcd (up + p, vp + p, n - p, &M, tp + matrix_scratch);
+      if (nn > 0)
+	{
+	  ASSERT (M.n <= (n - p - 1)/2);
+	  ASSERT (M.n + p <= (p + n - 1) / 2);
+	  /* Temporary storage 2 (p + M->n) <= p + n - 1. */
+	  n = mpn_hgcd_matrix_adjust (&M, p + nn, up, vp, p, tp + matrix_scratch);
+	}
+      else
+	{
+	  /* Temporary storage n */
+	  n = mpn_gcd_subdiv_step (up, vp, n, 0, gcd_hook, &ctx, tp);
+	  if (n == 0)
+	    goto done;
+	}
+    }
+
+  while (n > 2)
+    {
+      struct hgcd_matrix1 M;
+      mp_limb_t uh, ul, vh, vl;
+      mp_limb_t mask;
+
+      mask = up[n-1] | vp[n-1];
+      ASSERT (mask > 0);
+
+      if (mask & GMP_NUMB_HIGHBIT)
+	{
+	  uh = up[n-1]; ul = up[n-2];
+	  vh = vp[n-1]; vl = vp[n-2];
+	}
+      else
+	{
+	  int shift;
+
+	  count_leading_zeros (shift, mask);
+	  uh = MPN_EXTRACT_NUMB (shift, up[n-1], up[n-2]);
+	  ul = MPN_EXTRACT_NUMB (shift, up[n-2], up[n-3]);
+	  vh = MPN_EXTRACT_NUMB (shift, vp[n-1], vp[n-2]);
+	  vl = MPN_EXTRACT_NUMB (shift, vp[n-2], vp[n-3]);
+	}
+
+      /* Try an mpn_hgcd2 step */
+      if (mpn_hgcd2 (uh, ul, vh, vl, &M))
+	{
+	  n = mpn_matrix22_mul1_inverse_vector (&M, tp, up, vp, n);
+	  MP_PTR_SWAP (up, tp);
+	}
+      else
+	{
+	  /* mpn_hgcd2 has failed. Then either one of a or b is very
+	     small, or the difference is very small. Perform one
+	     subtraction followed by one division. */
+
+	  /* Temporary storage n */
+	  n = mpn_gcd_subdiv_step (up, vp, n, 0, &gcd_hook, &ctx, tp);
+	  if (n == 0)
+	    goto done;
+	}
+    }
+
+  ASSERT(up[n-1] | vp[n-1]);
+
+  /* Due to the calling convention for mpn_gcd, at most one can be even. */
+  if ((up[0] & 1) == 0)
+    MP_PTR_SWAP (up, vp);
+  ASSERT ((up[0] & 1) != 0);
+
+  {
+    mp_limb_t u0, u1, v0, v1;
+    mp_double_limb_t g;
+
+    u0 = up[0];
+    v0 = vp[0];
+
+    if (n == 1)
+      {
+	int cnt;
+	count_trailing_zeros (cnt, v0);
+	*gp = mpn_gcd_11 (u0, v0 >> cnt);
+	ctx.gn = 1;
+	goto done;
+      }
+
+    v1 = vp[1];
+    if (UNLIKELY (v0 == 0))
+      {
+	v0 = v1;
+	v1 = 0;
+	/* FIXME: We could invoke a mpn_gcd_21 here, just like mpn_gcd_22 could
+	   when this situation occurs internally.  */
+      }
+    if ((v0 & 1) == 0)
+      {
+	int cnt;
+	count_trailing_zeros (cnt, v0);
+	v0 = ((v1 << (GMP_NUMB_BITS - cnt)) & GMP_NUMB_MASK) | (v0 >> cnt);
+	v1 >>= cnt;
+      }
+
+    u1 = up[1];
+    g = mpn_gcd_22 (u1, u0, v1, v0);
+    gp[0] = g.d0;
+    gp[1] = g.d1;
+    ctx.gn = 1 + (g.d1 > 0);
+  }
+done:
+  TMP_FREE;
+  return ctx.gn;
+}
diff --git a/third_party/gmp/mpn/generic/gcd_1.c b/third_party/gmp/mpn/generic/gcd_1.c
new file mode 100644
index 0000000..22b1422
--- /dev/null
+++ b/third_party/gmp/mpn/generic/gcd_1.c
@@ -0,0 +1,103 @@
+/* mpn_gcd_1 -- mpn and limb greatest common divisor.
+
+Copyright 1994, 1996, 2000, 2001, 2009, 2012, 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/* Does not work for U == 0 or V == 0.  It would be tough to make it work for
+   V == 0 since gcd(x,0) = x, and U does not generally fit in an mp_limb_t.
+
+   The threshold for doing u%v when size==1 will vary by CPU according to
+   the speed of a division and the code generated for the main loop.  Any
+   tuning for this is left to a CPU specific implementation.  */
+
+mp_limb_t
+mpn_gcd_1 (mp_srcptr up, mp_size_t size, mp_limb_t vlimb)
+{
+  mp_limb_t      ulimb;
+  unsigned long  zero_bits, u_low_zero_bits;
+  int c;
+
+  ASSERT (size >= 1);
+  ASSERT (vlimb != 0);
+  ASSERT_MPN_NONZERO_P (up, size);
+
+  ulimb = up[0];
+
+  /* Need vlimb odd for modexact, want it odd to get common zeros. */
+  count_trailing_zeros (zero_bits, vlimb);
+  vlimb >>= zero_bits;
+
+  if (size > 1)
+    {
+      /* Must get common zeros before the mod reduction.  If ulimb==0 then
+	 vlimb already gives the common zeros.  */
+      if (ulimb != 0)
+	{
+	  count_trailing_zeros (u_low_zero_bits, ulimb);
+	  zero_bits = MIN (zero_bits, u_low_zero_bits);
+	}
+
+      ulimb = MPN_MOD_OR_MODEXACT_1_ODD (up, size, vlimb);
+      if (ulimb == 0)
+	goto done;
+
+      count_trailing_zeros (c, ulimb);
+      ulimb >>= c;
+    }
+  else
+    {
+      /* size==1, so up[0]!=0 */
+      count_trailing_zeros (u_low_zero_bits, ulimb);
+      ulimb >>= u_low_zero_bits;
+      zero_bits = MIN (zero_bits, u_low_zero_bits);
+
+      /* make u bigger */
+      if (vlimb > ulimb)
+	MP_LIMB_T_SWAP (ulimb, vlimb);
+
+      /* if u is much bigger than v, reduce using a division rather than
+	 chipping away at it bit-by-bit */
+      if ((ulimb >> 16) > vlimb)
+	{
+	  ulimb %= vlimb;
+	  if (ulimb == 0)
+	    goto done;
+
+	  count_trailing_zeros (c, ulimb);
+	  ulimb >>= c;
+	}
+    }
+
+  vlimb = mpn_gcd_11 (ulimb, vlimb);
+
+ done:
+  return vlimb << zero_bits;
+}
diff --git a/third_party/gmp/mpn/generic/gcd_11.c b/third_party/gmp/mpn/generic/gcd_11.c
new file mode 100644
index 0000000..214e45c
--- /dev/null
+++ b/third_party/gmp/mpn/generic/gcd_11.c
@@ -0,0 +1,74 @@
+/* mpn_gcd_11 -- limb greatest common divisor.
+
+Copyright 1994, 1996, 2000, 2001, 2009, 2012, 2019 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+mp_limb_t
+mpn_gcd_11 (mp_limb_t u, mp_limb_t v)
+{
+  ASSERT (u & v & 1);
+
+  /* In this loop, we represent the odd numbers ulimb and vlimb
+     without the redundant least significant one bit. This reduction
+     in size by one bit ensures that the high bit of t, below, is set
+     if and only if vlimb > ulimb. */
+
+  u >>= 1;
+  v >>= 1;
+
+  while (u != v)
+    {
+      mp_limb_t t;
+      mp_limb_t vgtu;
+      int c;
+
+      t = u - v;
+      vgtu = LIMB_HIGHBIT_TO_MASK (t);
+
+      /* v <-- min (u, v) */
+      v += (vgtu & t);
+
+      /* u <-- |u - v| */
+      u = (t ^ vgtu) - vgtu;
+
+      count_trailing_zeros (c, t);
+      /* We have c <= GMP_LIMB_BITS - 2 here, so that
+
+	   ulimb >>= (c + 1);
+
+	 would be safe. But unlike the addition c + 1, a separate
+	 shift by 1 is independent of c, and can be executed in
+	 parallel with count_trailing_zeros. */
+      u = (u >> 1) >> c;
+    }
+  return (u << 1) + 1;
+}
diff --git a/third_party/gmp/mpn/generic/gcd_22.c b/third_party/gmp/mpn/generic/gcd_22.c
new file mode 100644
index 0000000..d97f096
--- /dev/null
+++ b/third_party/gmp/mpn/generic/gcd_22.c
@@ -0,0 +1,131 @@
+/* mpn_gcd_22 -- double limb greatest common divisor.
+
+Copyright 1994, 1996, 2000, 2001, 2009, 2012, 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#if GMP_NAIL_BITS > 0
+#error Nails not supported.
+#endif
+
+mp_double_limb_t
+mpn_gcd_22 (mp_limb_t u1, mp_limb_t u0, mp_limb_t v1, mp_limb_t v0)
+{
+  mp_double_limb_t g;
+  ASSERT (u0 & v0 & 1);
+
+  /* Implicit least significant bit */
+  u0 = (u0 >> 1) | (u1 << (GMP_LIMB_BITS - 1));
+  u1 >>= 1;
+
+  v0 = (v0 >> 1) | (v1 << (GMP_LIMB_BITS - 1));
+  v1 >>= 1;
+
+  while (u1 || v1) /* u1 == 0 can happen at most twice per call */
+    {
+      mp_limb_t vgtu, t1, t0;
+      sub_ddmmss (t1, t0, u1, u0, v1, v0);
+      vgtu = LIMB_HIGHBIT_TO_MASK(t1);
+
+      if (UNLIKELY (t0 == 0))
+	{
+	  if (t1 == 0)
+	    {
+	      g.d1 = (u1 << 1) | (u0 >> (GMP_LIMB_BITS - 1));
+	      g.d0 = (u0 << 1) | 1;
+	      return g;
+	    }
+	  int c;
+	  count_trailing_zeros (c, t1);
+
+	  /* v1 = min (u1, v1) */
+	  v1 += (vgtu & t1);
+	  /* u0 = |u1 - v1| */
+	  u0 = (t1 ^ vgtu) - vgtu;
+	  ASSERT (c < GMP_LIMB_BITS - 1);
+	  u0 >>= c + 1;
+	  u1 = 0;
+	}
+      else
+	{
+	  int c;
+	  count_trailing_zeros (c, t0);
+	  c++;
+	  /* V <-- min (U, V).
+
+	     Assembly version should use cmov. Another alternative,
+	     avoiding carry propagation, would be
+
+	     v0 += vgtu & t0; v1 += vtgu & (u1 - v1);
+	  */
+	  add_ssaaaa (v1, v0, v1, v0, vgtu & t1, vgtu & t0);
+	  /* U  <--  |U - V|
+	     No carry handling needed in this conditional negation,
+	     since t0 != 0. */
+	  u0 = (t0 ^ vgtu) - vgtu;
+	  u1 = t1 ^ vgtu;
+	  if (UNLIKELY (c == GMP_LIMB_BITS))
+	    {
+	      u0 = u1;
+	      u1 = 0;
+	    }
+	  else
+	    {
+	      u0 = (u0 >> c) | (u1 << (GMP_LIMB_BITS - c));
+	      u1 >>= c;
+	    }
+	}
+    }
+  while ((v0 | u0) & GMP_LIMB_HIGHBIT)
+    { /* At most two iterations */
+      mp_limb_t vgtu, t0;
+      int c;
+      sub_ddmmss (vgtu, t0, 0, u0, 0, v0);
+      if (UNLIKELY (t0 == 0))
+	{
+	  g.d1 = u0 >> (GMP_LIMB_BITS - 1);
+	  g.d0 = (u0 << 1) | 1;
+	  return g;
+	}
+
+      /* v <-- min (u, v) */
+      v0 += (vgtu & t0);
+
+      /* u <-- |u - v| */
+      u0 = (t0 ^ vgtu) - vgtu;
+
+      count_trailing_zeros (c, t0);
+      u0 = (u0 >> 1) >> c;
+    }
+
+  g.d0 = mpn_gcd_11 ((u0 << 1) + 1, (v0 << 1) + 1);
+  g.d1 = 0;
+  return g;
+}
diff --git a/third_party/gmp/mpn/generic/gcd_subdiv_step.c b/third_party/gmp/mpn/generic/gcd_subdiv_step.c
new file mode 100644
index 0000000..9c3b88d
--- /dev/null
+++ b/third_party/gmp/mpn/generic/gcd_subdiv_step.c
@@ -0,0 +1,204 @@
+/* gcd_subdiv_step.c.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2003-2005, 2008, 2010, 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdlib.h>		/* for NULL */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/* Used when mpn_hgcd or mpn_hgcd2 has failed. Then either one of a or
+   b is small, or the difference is small. Perform one subtraction
+   followed by one division. The normal case is to compute the reduced
+   a and b, and return the new size.
+
+   If s == 0 (used for gcd and gcdext), returns zero if the gcd is
+   found.
+
+   If s > 0, don't reduce to size <= s, and return zero if no
+   reduction is possible (if either a, b or |a-b| is of size <= s). */
+
+/* The hook function is called as
+
+     hook(ctx, gp, gn, qp, qn, d)
+
+   in the following cases:
+
+   + If A = B at the start, G is the gcd, Q is NULL, d = -1.
+
+   + If one input is zero at the start, G is the gcd, Q is NULL,
+     d = 0 if A = G and d = 1 if B = G.
+
+   Otherwise, if d = 0 we have just subtracted a multiple of A from B,
+   and if d = 1 we have subtracted a multiple of B from A.
+
+   + If A = B after subtraction, G is the gcd, Q is NULL.
+
+   + If we get a zero remainder after division, G is the gcd, Q is the
+     quotient.
+
+   + Otherwise, G is NULL, Q is the quotient (often 1).
+
+ */
+
+mp_size_t
+mpn_gcd_subdiv_step (mp_ptr ap, mp_ptr bp, mp_size_t n, mp_size_t s,
+		     gcd_subdiv_step_hook *hook, void *ctx,
+		     mp_ptr tp)
+{
+  static const mp_limb_t one = CNST_LIMB(1);
+  mp_size_t an, bn, qn;
+
+  int swapped;
+
+  ASSERT (n > 0);
+  ASSERT (ap[n-1] > 0 || bp[n-1] > 0);
+
+  an = bn = n;
+  MPN_NORMALIZE (ap, an);
+  MPN_NORMALIZE (bp, bn);
+
+  swapped = 0;
+
+  /* Arrange so that a < b, subtract b -= a, and maintain
+     normalization. */
+  if (an == bn)
+    {
+      int c;
+      MPN_CMP (c, ap, bp, an);
+      if (UNLIKELY (c == 0))
+	{
+	  /* For gcdext, return the smallest of the two cofactors, so
+	     pass d = -1. */
+	  if (s == 0)
+	    hook (ctx, ap, an, NULL, 0, -1);
+	  return 0;
+	}
+      else if (c > 0)
+	{
+	  MP_PTR_SWAP (ap, bp);
+	  swapped ^= 1;
+	}
+    }
+  else
+    {
+      if (an > bn)
+	{
+	  MPN_PTR_SWAP (ap, an, bp, bn);
+	  swapped ^= 1;
+	}
+    }
+  if (an <= s)
+    {
+      if (s == 0)
+	hook (ctx, bp, bn, NULL, 0, swapped ^ 1);
+      return 0;
+    }
+
+  ASSERT_NOCARRY (mpn_sub (bp, bp, bn, ap, an));
+  MPN_NORMALIZE (bp, bn);
+  ASSERT (bn > 0);
+
+  if (bn <= s)
+    {
+      /* Undo subtraction. */
+      mp_limb_t cy = mpn_add (bp, ap, an, bp, bn);
+      if (cy > 0)
+	bp[an] = cy;
+      return 0;
+    }
+
+  /* Arrange so that a < b */
+  if (an == bn)
+    {
+      int c;
+      MPN_CMP (c, ap, bp, an);
+      if (UNLIKELY (c == 0))
+	{
+	  if (s > 0)
+	    /* Just record subtraction and return */
+	    hook (ctx, NULL, 0, &one, 1, swapped);
+	  else
+	    /* Found gcd. */
+	    hook (ctx, bp, bn, NULL, 0, swapped);
+	  return 0;
+	}
+
+      hook (ctx, NULL, 0, &one, 1, swapped);
+
+      if (c > 0)
+	{
+	  MP_PTR_SWAP (ap, bp);
+	  swapped ^= 1;
+	}
+    }
+  else
+    {
+      hook (ctx, NULL, 0, &one, 1, swapped);
+
+      if (an > bn)
+	{
+	  MPN_PTR_SWAP (ap, an, bp, bn);
+	  swapped ^= 1;
+	}
+    }
+
+  mpn_tdiv_qr (tp, bp, 0, bp, bn, ap, an);
+  qn = bn - an + 1;
+  bn = an;
+  MPN_NORMALIZE (bp, bn);
+
+  if (UNLIKELY (bn <= s))
+    {
+      if (s == 0)
+	{
+	  hook (ctx, ap, an, tp, qn, swapped);
+	  return 0;
+	}
+
+      /* Quotient is one too large, so decrement it and add back A. */
+      if (bn > 0)
+	{
+	  mp_limb_t cy = mpn_add (bp, ap, an, bp, bn);
+	  if (cy)
+	    bp[an++] = cy;
+	}
+      else
+	MPN_COPY (bp, ap, an);
+
+      MPN_DECR_U (tp, qn, 1);
+    }
+
+  hook (ctx, NULL, 0, tp, qn, swapped);
+  return an;
+}
diff --git a/third_party/gmp/mpn/generic/gcdext.c b/third_party/gmp/mpn/generic/gcdext.c
new file mode 100644
index 0000000..5501480
--- /dev/null
+++ b/third_party/gmp/mpn/generic/gcdext.c
@@ -0,0 +1,557 @@
+/* mpn_gcdext -- Extended Greatest Common Divisor.
+
+Copyright 1996, 1998, 2000-2005, 2008, 2009, 2012 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/* Computes (r;b) = (a; b) M. Result is of size n + M->n +/- 1, and
+   the size is returned (if inputs are non-normalized, result may be
+   non-normalized too). Temporary space needed is M->n + n.
+ */
+static size_t
+hgcd_mul_matrix_vector (struct hgcd_matrix *M,
+			mp_ptr rp, mp_srcptr ap, mp_ptr bp, mp_size_t n, mp_ptr tp)
+{
+  mp_limb_t ah, bh;
+
+  /* Compute (r,b) <-- (u00 a + u10 b, u01 a + u11 b) as
+
+     t  = u00 * a
+     r  = u10 * b
+     r += t;
+
+     t  = u11 * b
+     b  = u01 * a
+     b += t;
+  */
+
+  if (M->n >= n)
+    {
+      mpn_mul (tp, M->p[0][0], M->n, ap, n);
+      mpn_mul (rp, M->p[1][0], M->n, bp, n);
+    }
+  else
+    {
+      mpn_mul (tp, ap, n, M->p[0][0], M->n);
+      mpn_mul (rp, bp, n, M->p[1][0], M->n);
+    }
+
+  ah = mpn_add_n (rp, rp, tp, n + M->n);
+
+  if (M->n >= n)
+    {
+      mpn_mul (tp, M->p[1][1], M->n, bp, n);
+      mpn_mul (bp, M->p[0][1], M->n, ap, n);
+    }
+  else
+    {
+      mpn_mul (tp, bp, n, M->p[1][1], M->n);
+      mpn_mul (bp, ap, n, M->p[0][1], M->n);
+    }
+  bh = mpn_add_n (bp, bp, tp, n + M->n);
+
+  n += M->n;
+  if ( (ah | bh) > 0)
+    {
+      rp[n] = ah;
+      bp[n] = bh;
+      n++;
+    }
+  else
+    {
+      /* Normalize */
+      while ( (rp[n-1] | bp[n-1]) == 0)
+	n--;
+    }
+
+  return n;
+}
+
+#define COMPUTE_V_ITCH(n) (2*(n))
+
+/* Computes |v| = |(g - u a)| / b, where u may be positive or
+   negative, and v is of the opposite sign. max(a, b) is of size n, u and
+   v at most size n, and v must have space for n+1 limbs. */
+static mp_size_t
+compute_v (mp_ptr vp,
+	   mp_srcptr ap, mp_srcptr bp, mp_size_t n,
+	   mp_srcptr gp, mp_size_t gn,
+	   mp_srcptr up, mp_size_t usize,
+	   mp_ptr tp)
+{
+  mp_size_t size;
+  mp_size_t an;
+  mp_size_t bn;
+  mp_size_t vn;
+
+  ASSERT (n > 0);
+  ASSERT (gn > 0);
+  ASSERT (usize != 0);
+
+  size = ABS (usize);
+  ASSERT (size <= n);
+  ASSERT (up[size-1] > 0);
+
+  an = n;
+  MPN_NORMALIZE (ap, an);
+  ASSERT (gn <= an);
+
+  if (an >= size)
+    mpn_mul (tp, ap, an, up, size);
+  else
+    mpn_mul (tp, up, size, ap, an);
+
+  size += an;
+
+  if (usize > 0)
+    {
+      /* |v| = -v = (u a - g) / b */
+
+      ASSERT_NOCARRY (mpn_sub (tp, tp, size, gp, gn));
+      MPN_NORMALIZE (tp, size);
+      if (size == 0)
+	return 0;
+    }
+  else
+    { /* |v| = v = (g - u a) / b = (g + |u| a) / b. Since g <= a,
+	 (g + |u| a) always fits in (|usize| + an) limbs. */
+
+      ASSERT_NOCARRY (mpn_add (tp, tp, size, gp, gn));
+      size -= (tp[size - 1] == 0);
+    }
+
+  /* Now divide t / b. There must be no remainder */
+  bn = n;
+  MPN_NORMALIZE (bp, bn);
+  ASSERT (size >= bn);
+
+  vn = size + 1 - bn;
+  ASSERT (vn <= n + 1);
+
+  mpn_divexact (vp, tp, size, bp, bn);
+  vn -= (vp[vn-1] == 0);
+
+  return vn;
+}
+
+/* Temporary storage:
+
+   Initial division: Quotient of at most an - n + 1 <= an limbs.
+
+   Storage for u0 and u1: 2(n+1).
+
+   Storage for hgcd matrix M, with input ceil(n/2): 5 * ceil(n/4)
+
+   Storage for hgcd, input (n + 1)/2: 9 n/4 plus some.
+
+   When hgcd succeeds: 1 + floor(3n/2) for adjusting a and b, and 2(n+1) for the cofactors.
+
+   When hgcd fails: 2n + 1 for mpn_gcdext_subdiv_step, which is less.
+
+   For the lehmer call after the loop, Let T denote
+   GCDEXT_DC_THRESHOLD. For the gcdext_lehmer call, we need T each for
+   u, a and b, and 4T+3 scratch space. Next, for compute_v, we need T
+   for u, T+1 for v and 2T scratch space. In all, 7T + 3 is
+   sufficient for both operations.
+
+*/
+
+/* Optimal choice of p seems difficult. In each iteration the division
+ * of work between hgcd and the updates of u0 and u1 depends on the
+ * current size of the u. It may be desirable to use a different
+ * choice of p in each iteration. Also the input size seems to matter;
+ * choosing p = n / 3 in the first iteration seems to improve
+ * performance slightly for input size just above the threshold, but
+ * degrade performance for larger inputs. */
+#define CHOOSE_P_1(n) ((n) / 2)
+#define CHOOSE_P_2(n) ((n) / 3)
+
+mp_size_t
+mpn_gcdext (mp_ptr gp, mp_ptr up, mp_size_t *usizep,
+	    mp_ptr ap, mp_size_t an, mp_ptr bp, mp_size_t n)
+{
+  mp_size_t talloc;
+  mp_size_t scratch;
+  mp_size_t matrix_scratch;
+  mp_size_t ualloc = n + 1;
+
+  struct gcdext_ctx ctx;
+  mp_size_t un;
+  mp_ptr u0;
+  mp_ptr u1;
+
+  mp_ptr tp;
+
+  TMP_DECL;
+
+  ASSERT (an >= n);
+  ASSERT (n > 0);
+  ASSERT (bp[n-1] > 0);
+
+  TMP_MARK;
+
+  /* FIXME: Check for small sizes first, before setting up temporary
+     storage etc. */
+  talloc = MPN_GCDEXT_LEHMER_N_ITCH(n);
+
+  /* For initial division */
+  scratch = an - n + 1;
+  if (scratch > talloc)
+    talloc = scratch;
+
+  if (ABOVE_THRESHOLD (n, GCDEXT_DC_THRESHOLD))
+    {
+      /* For hgcd loop. */
+      mp_size_t hgcd_scratch;
+      mp_size_t update_scratch;
+      mp_size_t p1 = CHOOSE_P_1 (n);
+      mp_size_t p2 = CHOOSE_P_2 (n);
+      mp_size_t min_p = MIN(p1, p2);
+      mp_size_t max_p = MAX(p1, p2);
+      matrix_scratch = MPN_HGCD_MATRIX_INIT_ITCH (n - min_p);
+      hgcd_scratch = mpn_hgcd_itch (n - min_p);
+      update_scratch = max_p + n - 1;
+
+      scratch = matrix_scratch + MAX(hgcd_scratch, update_scratch);
+      if (scratch > talloc)
+	talloc = scratch;
+
+      /* Final mpn_gcdext_lehmer_n call. Need space for u and for
+	 copies of a and b. */
+      scratch = MPN_GCDEXT_LEHMER_N_ITCH (GCDEXT_DC_THRESHOLD)
+	+ 3*GCDEXT_DC_THRESHOLD;
+
+      if (scratch > talloc)
+	talloc = scratch;
+
+      /* Cofactors u0 and u1 */
+      talloc += 2*(n+1);
+    }
+
+  tp = TMP_ALLOC_LIMBS(talloc);
+
+  if (an > n)
+    {
+      mpn_tdiv_qr (tp, ap, 0, ap, an, bp, n);
+
+      if (mpn_zero_p (ap, n))
+	{
+	  MPN_COPY (gp, bp, n);
+	  *usizep = 0;
+	  TMP_FREE;
+	  return n;
+	}
+    }
+
+  if (BELOW_THRESHOLD (n, GCDEXT_DC_THRESHOLD))
+    {
+      mp_size_t gn = mpn_gcdext_lehmer_n(gp, up, usizep, ap, bp, n, tp);
+
+      TMP_FREE;
+      return gn;
+    }
+
+  MPN_ZERO (tp, 2*ualloc);
+  u0 = tp; tp += ualloc;
+  u1 = tp; tp += ualloc;
+
+  ctx.gp = gp;
+  ctx.up = up;
+  ctx.usize = usizep;
+
+  {
+    /* For the first hgcd call, there are no u updates, and it makes
+       some sense to use a different choice for p. */
+
+    /* FIXME: We could trim use of temporary storage, since u0 and u1
+       are not used yet. For the hgcd call, we could swap in the u0
+       and u1 pointers for the relevant matrix elements. */
+
+    struct hgcd_matrix M;
+    mp_size_t p = CHOOSE_P_1 (n);
+    mp_size_t nn;
+
+    mpn_hgcd_matrix_init (&M, n - p, tp);
+    nn = mpn_hgcd (ap + p, bp + p, n - p, &M, tp + matrix_scratch);
+    if (nn > 0)
+      {
+	ASSERT (M.n <= (n - p - 1)/2);
+	ASSERT (M.n + p <= (p + n - 1) / 2);
+
+	/* Temporary storage 2 (p + M->n) <= p + n - 1 */
+	n = mpn_hgcd_matrix_adjust (&M, p + nn, ap, bp, p, tp + matrix_scratch);
+
+	MPN_COPY (u0, M.p[1][0], M.n);
+	MPN_COPY (u1, M.p[1][1], M.n);
+	un = M.n;
+	while ( (u0[un-1] | u1[un-1] ) == 0)
+	  un--;
+      }
+    else
+      {
+	/* mpn_hgcd has failed. Then either one of a or b is very
+	   small, or the difference is very small. Perform one
+	   subtraction followed by one division. */
+	u1[0] = 1;
+
+	ctx.u0 = u0;
+	ctx.u1 = u1;
+	ctx.tp = tp + n; /* ualloc */
+	ctx.un = 1;
+
+	/* Temporary storage n */
+	n = mpn_gcd_subdiv_step (ap, bp, n, 0, mpn_gcdext_hook, &ctx, tp);
+	if (n == 0)
+	  {
+	    TMP_FREE;
+	    return ctx.gn;
+	  }
+
+	un = ctx.un;
+	ASSERT (un < ualloc);
+      }
+  }
+
+  while (ABOVE_THRESHOLD (n, GCDEXT_DC_THRESHOLD))
+    {
+      struct hgcd_matrix M;
+      mp_size_t p = CHOOSE_P_2 (n);
+      mp_size_t nn;
+
+      mpn_hgcd_matrix_init (&M, n - p, tp);
+      nn = mpn_hgcd (ap + p, bp + p, n - p, &M, tp + matrix_scratch);
+      if (nn > 0)
+	{
+	  mp_ptr t0;
+
+	  t0 = tp + matrix_scratch;
+	  ASSERT (M.n <= (n - p - 1)/2);
+	  ASSERT (M.n + p <= (p + n - 1) / 2);
+
+	  /* Temporary storage 2 (p + M->n) <= p + n - 1 */
+	  n = mpn_hgcd_matrix_adjust (&M, p + nn, ap, bp, p, t0);
+
+	  /* By the same analysis as for mpn_hgcd_matrix_mul */
+	  ASSERT (M.n + un <= ualloc);
+
+	  /* FIXME: This copying could be avoided by some swapping of
+	   * pointers. May need more temporary storage, though. */
+	  MPN_COPY (t0, u0, un);
+
+	  /* Temporary storage ualloc */
+	  un = hgcd_mul_matrix_vector (&M, u0, t0, u1, un, t0 + un);
+
+	  ASSERT (un < ualloc);
+	  ASSERT ( (u0[un-1] | u1[un-1]) > 0);
+	}
+      else
+	{
+	  /* mpn_hgcd has failed. Then either one of a or b is very
+	     small, or the difference is very small. Perform one
+	     subtraction followed by one division. */
+	  ctx.u0 = u0;
+	  ctx.u1 = u1;
+	  ctx.tp = tp + n; /* ualloc */
+	  ctx.un = un;
+
+	  /* Temporary storage n */
+	  n = mpn_gcd_subdiv_step (ap, bp, n, 0, mpn_gcdext_hook, &ctx, tp);
+	  if (n == 0)
+	    {
+	      TMP_FREE;
+	      return ctx.gn;
+	    }
+
+	  un = ctx.un;
+	  ASSERT (un < ualloc);
+	}
+    }
+  /* We have A = ... a + ... b
+	     B =  u0 a +  u1 b
+
+	     a = u1  A + ... B
+	     b = -u0 A + ... B
+
+     with bounds
+
+       |u0|, |u1| <= B / min(a, b)
+
+     We always have u1 > 0, and u0 == 0 is possible only if u1 == 1,
+     in which case the only reduction done so far is a = A - k B for
+     some k.
+
+     Compute g = u a + v b = (u u1 - v u0) A + (...) B
+     Here, u, v are bounded by
+
+       |u| <= b,
+       |v| <= a
+  */
+
+  ASSERT ( (ap[n-1] | bp[n-1]) > 0);
+
+  if (UNLIKELY (mpn_cmp (ap, bp, n) == 0))
+    {
+      /* Must return the smallest cofactor, +u1 or -u0 */
+      int c;
+
+      MPN_COPY (gp, ap, n);
+
+      MPN_CMP (c, u0, u1, un);
+      /* c == 0 can happen only when A = (2k+1) G, B = 2 G. And in
+	 this case we choose the cofactor + 1, corresponding to G = A
+	 - k B, rather than -1, corresponding to G = - A + (k+1) B. */
+      ASSERT (c != 0 || (un == 1 && u0[0] == 1 && u1[0] == 1));
+      if (c < 0)
+	{
+	  MPN_NORMALIZE (u0, un);
+	  MPN_COPY (up, u0, un);
+	  *usizep = -un;
+	}
+      else
+	{
+	  MPN_NORMALIZE_NOT_ZERO (u1, un);
+	  MPN_COPY (up, u1, un);
+	  *usizep = un;
+	}
+
+      TMP_FREE;
+      return n;
+    }
+  else if (UNLIKELY (u0[0] == 0) && un == 1)
+    {
+      mp_size_t gn;
+      ASSERT (u1[0] == 1);
+
+      /* g = u a + v b = (u u1 - v u0) A + (...) B = u A + (...) B */
+      gn = mpn_gcdext_lehmer_n (gp, up, usizep, ap, bp, n, tp);
+
+      TMP_FREE;
+      return gn;
+    }
+  else
+    {
+      mp_size_t u0n;
+      mp_size_t u1n;
+      mp_size_t lehmer_un;
+      mp_size_t lehmer_vn;
+      mp_size_t gn;
+
+      mp_ptr lehmer_up;
+      mp_ptr lehmer_vp;
+      int negate;
+
+      lehmer_up = tp; tp += n;
+
+      /* Call mpn_gcdext_lehmer_n with copies of a and b. */
+      MPN_COPY (tp, ap, n);
+      MPN_COPY (tp + n, bp, n);
+      gn = mpn_gcdext_lehmer_n (gp, lehmer_up, &lehmer_un, tp, tp + n, n, tp + 2*n);
+
+      u0n = un;
+      MPN_NORMALIZE (u0, u0n);
+      ASSERT (u0n > 0);
+
+      if (lehmer_un == 0)
+	{
+	  /* u == 0  ==>  v = g / b == 1  ==> g = - u0 A + (...) B */
+	  MPN_COPY (up, u0, u0n);
+	  *usizep = -u0n;
+
+	  TMP_FREE;
+	  return gn;
+	}
+
+      lehmer_vp = tp;
+      /* Compute v = (g - u a) / b */
+      lehmer_vn = compute_v (lehmer_vp,
+			     ap, bp, n, gp, gn, lehmer_up, lehmer_un, tp + n + 1);
+
+      if (lehmer_un > 0)
+	negate = 0;
+      else
+	{
+	  lehmer_un = -lehmer_un;
+	  negate = 1;
+	}
+
+      u1n = un;
+      MPN_NORMALIZE (u1, u1n);
+      ASSERT (u1n > 0);
+
+      ASSERT (lehmer_un + u1n <= ualloc);
+      ASSERT (lehmer_vn + u0n <= ualloc);
+
+      /* We may still have v == 0 */
+
+      /* Compute u u0 */
+      if (lehmer_un <= u1n)
+	/* Should be the common case */
+	mpn_mul (up, u1, u1n, lehmer_up, lehmer_un);
+      else
+	mpn_mul (up, lehmer_up, lehmer_un, u1, u1n);
+
+      un = u1n + lehmer_un;
+      un -= (up[un - 1] == 0);
+
+      if (lehmer_vn > 0)
+	{
+	  mp_limb_t cy;
+
+	  /* Overwrites old u1 value */
+	  if (lehmer_vn <= u0n)
+	    /* Should be the common case */
+	    mpn_mul (u1, u0, u0n, lehmer_vp, lehmer_vn);
+	  else
+	    mpn_mul (u1, lehmer_vp, lehmer_vn, u0, u0n);
+
+	  u1n = u0n + lehmer_vn;
+	  u1n -= (u1[u1n - 1] == 0);
+
+	  if (u1n <= un)
+	    {
+	      cy = mpn_add (up, up, un, u1, u1n);
+	    }
+	  else
+	    {
+	      cy = mpn_add (up, u1, u1n, up, un);
+	      un = u1n;
+	    }
+	  up[un] = cy;
+	  un += (cy != 0);
+
+	  ASSERT (un < ualloc);
+	}
+      *usizep = negate ? -un : un;
+
+      TMP_FREE;
+      return gn;
+    }
+}
diff --git a/third_party/gmp/mpn/generic/gcdext_1.c b/third_party/gmp/mpn/generic/gcdext_1.c
new file mode 100644
index 0000000..b221a92
--- /dev/null
+++ b/third_party/gmp/mpn/generic/gcdext_1.c
@@ -0,0 +1,275 @@
+/* mpn_gcdext -- Extended Greatest Common Divisor.
+
+Copyright 1996, 1998, 2000-2005, 2008, 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#ifndef GCDEXT_1_USE_BINARY
+#define GCDEXT_1_USE_BINARY 0
+#endif
+
+#ifndef GCDEXT_1_BINARY_METHOD
+#define GCDEXT_1_BINARY_METHOD 2
+#endif
+
+#if GCDEXT_1_USE_BINARY
+
+mp_limb_t
+mpn_gcdext_1 (mp_limb_signed_t *sp, mp_limb_signed_t *tp,
+	      mp_limb_t u, mp_limb_t v)
+{
+  /* Maintain
+
+     U = t1 u + t0 v
+     V = s1 u + s0 v
+
+     where U, V are the inputs (without any shared power of two),
+     and the matrix has determinant ± 2^{shift}.
+  */
+  mp_limb_t s0 = 1;
+  mp_limb_t t0 = 0;
+  mp_limb_t s1 = 0;
+  mp_limb_t t1 = 1;
+  mp_limb_t ug;
+  mp_limb_t vg;
+  mp_limb_t ugh;
+  mp_limb_t vgh;
+  unsigned zero_bits;
+  unsigned shift;
+  unsigned i;
+#if GCDEXT_1_BINARY_METHOD == 2
+  mp_limb_t det_sign;
+#endif
+
+  ASSERT (u > 0);
+  ASSERT (v > 0);
+
+  count_trailing_zeros (zero_bits, u | v);
+  u >>= zero_bits;
+  v >>= zero_bits;
+
+  if ((u & 1) == 0)
+    {
+      count_trailing_zeros (shift, u);
+      u >>= shift;
+      t1 <<= shift;
+    }
+  else if ((v & 1) == 0)
+    {
+      count_trailing_zeros (shift, v);
+      v >>= shift;
+      s0 <<= shift;
+    }
+  else
+    shift = 0;
+
+#if GCDEXT_1_BINARY_METHOD == 1
+  while (u != v)
+    {
+      unsigned count;
+      if (u > v)
+	{
+	  u -= v;
+
+	  count_trailing_zeros (count, u);
+	  u >>= count;
+
+	  t0 += t1; t1 <<= count;
+	  s0 += s1; s1 <<= count;
+	}
+      else
+	{
+	  v -= u;
+
+	  count_trailing_zeros (count, v);
+	  v >>= count;
+
+	  t1 += t0; t0 <<= count;
+	  s1 += s0; s0 <<= count;
+	}
+      shift += count;
+    }
+#else
+# if GCDEXT_1_BINARY_METHOD == 2
+  u >>= 1;
+  v >>= 1;
+
+  det_sign = 0;
+
+  while (u != v)
+    {
+      unsigned count;
+      mp_limb_t d =  u - v;
+      mp_limb_t vgtu = LIMB_HIGHBIT_TO_MASK (d);
+      mp_limb_t sx;
+      mp_limb_t tx;
+
+      /* When v <= u (vgtu == 0), the updates are:
+
+	   (u; v)   <-- ( (u - v) >> count; v)    (det = +(1<<count) for corr. M factor)
+	   (t1, t0) <-- (t1 << count, t0 + t1)
+
+	 and when v > 0, the updates are
+
+	   (u; v)   <-- ( (v - u) >> count; u)    (det = -(1<<count))
+	   (t1, t0) <-- (t0 << count, t0 + t1)
+
+	 and similarly for s1, s0
+      */
+
+      /* v <-- min (u, v) */
+      v += (vgtu & d);
+
+      /* u <-- |u - v| */
+      u = (d ^ vgtu) - vgtu;
+
+      /* Number of trailing zeros is the same no matter if we look at
+       * d or u, but using d gives more parallelism. */
+      count_trailing_zeros (count, d);
+
+      det_sign ^= vgtu;
+
+      tx = vgtu & (t0 - t1);
+      sx = vgtu & (s0 - s1);
+      t0 += t1;
+      s0 += s1;
+      t1 += tx;
+      s1 += sx;
+
+      count++;
+      u >>= count;
+      t1 <<= count;
+      s1 <<= count;
+      shift += count;
+    }
+  u = (u << 1) + 1;
+# else /* GCDEXT_1_BINARY_METHOD == 2 */
+#  error Unknown GCDEXT_1_BINARY_METHOD
+# endif
+#endif
+
+  /* Now u = v = g = gcd (u,v). Compute U/g and V/g */
+  ug = t0 + t1;
+  vg = s0 + s1;
+
+  ugh = ug/2 + (ug & 1);
+  vgh = vg/2 + (vg & 1);
+
+  /* Now 2^{shift} g = s0 U - t0 V. Get rid of the power of two, using
+     s0 U - t0 V = (s0 + V/g) U - (t0 + U/g) V. */
+  for (i = 0; i < shift; i++)
+    {
+      mp_limb_t mask = - ( (s0 | t0) & 1);
+
+      s0 /= 2;
+      t0 /= 2;
+      s0 += mask & vgh;
+      t0 += mask & ugh;
+    }
+
+  ASSERT_ALWAYS (s0 <= vg);
+  ASSERT_ALWAYS (t0 <= ug);
+
+  if (s0 > vg - s0)
+    {
+      s0 -= vg;
+      t0 -= ug;
+    }
+#if GCDEXT_1_BINARY_METHOD == 2
+  /* Conditional negation. */
+  s0 = (s0 ^ det_sign) - det_sign;
+  t0 = (t0 ^ det_sign) - det_sign;
+#endif
+  *sp = s0;
+  *tp = -t0;
+
+  return u << zero_bits;
+}
+
+#else /* !GCDEXT_1_USE_BINARY */
+
+
+/* FIXME: Takes two single-word limbs. It could be extended to a
+ * function that accepts a bignum for the first input, and only
+ * returns the first co-factor. */
+
+mp_limb_t
+mpn_gcdext_1 (mp_limb_signed_t *up, mp_limb_signed_t *vp,
+	      mp_limb_t a, mp_limb_t b)
+{
+  /* Maintain
+
+     a =  u0 A + v0 B
+     b =  u1 A + v1 B
+
+     where A, B are the original inputs.
+  */
+  mp_limb_signed_t u0 = 1;
+  mp_limb_signed_t v0 = 0;
+  mp_limb_signed_t u1 = 0;
+  mp_limb_signed_t v1 = 1;
+
+  ASSERT (a > 0);
+  ASSERT (b > 0);
+
+  if (a < b)
+    goto divide_by_b;
+
+  for (;;)
+    {
+      mp_limb_t q;
+
+      q = a / b;
+      a -= q * b;
+
+      if (a == 0)
+	{
+	  *up = u1;
+	  *vp = v1;
+	  return b;
+	}
+      u0 -= q * u1;
+      v0 -= q * v1;
+
+    divide_by_b:
+      q = b / a;
+      b -= q * a;
+
+      if (b == 0)
+	{
+	  *up = u0;
+	  *vp = v0;
+	  return a;
+	}
+      u1 -= q * u0;
+      v1 -= q * v0;
+    }
+}
+#endif /* !GCDEXT_1_USE_BINARY */
diff --git a/third_party/gmp/mpn/generic/gcdext_lehmer.c b/third_party/gmp/mpn/generic/gcdext_lehmer.c
new file mode 100644
index 0000000..ea4e86d
--- /dev/null
+++ b/third_party/gmp/mpn/generic/gcdext_lehmer.c
@@ -0,0 +1,336 @@
+/* mpn_gcdext -- Extended Greatest Common Divisor.
+
+Copyright 1996, 1998, 2000-2005, 2008, 2009, 2012 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/* Here, d is the index of the cofactor to update. FIXME: Could use qn
+   = 0 for the common case q = 1. */
+void
+mpn_gcdext_hook (void *p, mp_srcptr gp, mp_size_t gn,
+		 mp_srcptr qp, mp_size_t qn, int d)
+{
+  struct gcdext_ctx *ctx = (struct gcdext_ctx *) p;
+  mp_size_t un = ctx->un;
+
+  if (gp)
+    {
+      mp_srcptr up;
+
+      ASSERT (gn > 0);
+      ASSERT (gp[gn-1] > 0);
+
+      MPN_COPY (ctx->gp, gp, gn);
+      ctx->gn = gn;
+
+      if (d < 0)
+	{
+	  int c;
+
+	  /* Must return the smallest cofactor, +u1 or -u0 */
+	  MPN_CMP (c, ctx->u0, ctx->u1, un);
+	  ASSERT (c != 0 || (un == 1 && ctx->u0[0] == 1 && ctx->u1[0] == 1));
+
+	  d = c < 0;
+	}
+
+      up = d ? ctx->u0 : ctx->u1;
+
+      MPN_NORMALIZE (up, un);
+      MPN_COPY (ctx->up, up, un);
+
+      *ctx->usize = d ? -un : un;
+    }
+  else
+    {
+      mp_limb_t cy;
+      mp_ptr u0 = ctx->u0;
+      mp_ptr u1 = ctx->u1;
+
+      ASSERT (d >= 0);
+
+      if (d)
+	MP_PTR_SWAP (u0, u1);
+
+      qn -= (qp[qn-1] == 0);
+
+      /* Update u0 += q  * u1 */
+      if (qn == 1)
+	{
+	  mp_limb_t q = qp[0];
+
+	  if (q == 1)
+	    /* A common case. */
+	    cy = mpn_add_n (u0, u0, u1, un);
+	  else
+	    cy = mpn_addmul_1 (u0, u1, un, q);
+	}
+      else
+	{
+	  mp_size_t u1n;
+	  mp_ptr tp;
+
+	  u1n = un;
+	  MPN_NORMALIZE (u1, u1n);
+
+	  if (u1n == 0)
+	    return;
+
+	  /* Should always have u1n == un here, and u1 >= u0. The
+	     reason is that we alternate adding u0 to u1 and u1 to u0
+	     (corresponding to subtractions a - b and b - a), and we
+	     can get a large quotient only just after a switch, which
+	     means that we'll add (a multiple of) the larger u to the
+	     smaller. */
+
+	  tp = ctx->tp;
+
+	  if (qn > u1n)
+	    mpn_mul (tp, qp, qn, u1, u1n);
+	  else
+	    mpn_mul (tp, u1, u1n, qp, qn);
+
+	  u1n += qn;
+	  u1n -= tp[u1n-1] == 0;
+
+	  if (u1n >= un)
+	    {
+	      cy = mpn_add (u0, tp, u1n, u0, un);
+	      un = u1n;
+	    }
+	  else
+	    /* Note: Unlikely case, maybe never happens? */
+	    cy = mpn_add (u0, u0, un, tp, u1n);
+
+	}
+      u0[un] = cy;
+      ctx->un = un + (cy > 0);
+    }
+}
+
+/* Temporary storage: 3*(n+1) for u. If hgcd2 succeeds, we need n for
+   the matrix-vector multiplication adjusting a, b. If hgcd fails, we
+   need at most n for the quotient and n+1 for the u update (reusing
+   the extra u). In all, 4n + 3. */
+
+mp_size_t
+mpn_gcdext_lehmer_n (mp_ptr gp, mp_ptr up, mp_size_t *usize,
+		     mp_ptr ap, mp_ptr bp, mp_size_t n,
+		     mp_ptr tp)
+{
+  mp_size_t ualloc = n + 1;
+
+  /* Keeps track of the second row of the reduction matrix
+   *
+   *   M = (v0, v1 ; u0, u1)
+   *
+   * which correspond to the first column of the inverse
+   *
+   *   M^{-1} = (u1, -v1; -u0, v0)
+   *
+   * This implies that
+   *
+   *   a =  u1 A (mod B)
+   *   b = -u0 A (mod B)
+   *
+   * where A, B denotes the input values.
+   */
+
+  struct gcdext_ctx ctx;
+  mp_size_t un;
+  mp_ptr u0;
+  mp_ptr u1;
+  mp_ptr u2;
+
+  MPN_ZERO (tp, 3*ualloc);
+  u0 = tp; tp += ualloc;
+  u1 = tp; tp += ualloc;
+  u2 = tp; tp += ualloc;
+
+  u1[0] = 1; un = 1;
+
+  ctx.gp = gp;
+  ctx.up = up;
+  ctx.usize = usize;
+
+  /* FIXME: Handle n == 2 differently, after the loop? */
+  while (n >= 2)
+    {
+      struct hgcd_matrix1 M;
+      mp_limb_t ah, al, bh, bl;
+      mp_limb_t mask;
+
+      mask = ap[n-1] | bp[n-1];
+      ASSERT (mask > 0);
+
+      if (mask & GMP_NUMB_HIGHBIT)
+	{
+	  ah = ap[n-1]; al = ap[n-2];
+	  bh = bp[n-1]; bl = bp[n-2];
+	}
+      else if (n == 2)
+	{
+	  /* We use the full inputs without truncation, so we can
+	     safely shift left. */
+	  int shift;
+
+	  count_leading_zeros (shift, mask);
+	  ah = MPN_EXTRACT_NUMB (shift, ap[1], ap[0]);
+	  al = ap[0] << shift;
+	  bh = MPN_EXTRACT_NUMB (shift, bp[1], bp[0]);
+	  bl = bp[0] << shift;
+	}
+      else
+	{
+	  int shift;
+
+	  count_leading_zeros (shift, mask);
+	  ah = MPN_EXTRACT_NUMB (shift, ap[n-1], ap[n-2]);
+	  al = MPN_EXTRACT_NUMB (shift, ap[n-2], ap[n-3]);
+	  bh = MPN_EXTRACT_NUMB (shift, bp[n-1], bp[n-2]);
+	  bl = MPN_EXTRACT_NUMB (shift, bp[n-2], bp[n-3]);
+	}
+
+      /* Try an mpn_nhgcd2 step */
+      if (mpn_hgcd2 (ah, al, bh, bl, &M))
+	{
+	  n = mpn_matrix22_mul1_inverse_vector (&M, tp, ap, bp, n);
+	  MP_PTR_SWAP (ap, tp);
+	  un = mpn_hgcd_mul_matrix1_vector(&M, u2, u0, u1, un);
+	  MP_PTR_SWAP (u0, u2);
+	}
+      else
+	{
+	  /* mpn_hgcd2 has failed. Then either one of a or b is very
+	     small, or the difference is very small. Perform one
+	     subtraction followed by one division. */
+	  ctx.u0 = u0;
+	  ctx.u1 = u1;
+	  ctx.tp = u2;
+	  ctx.un = un;
+
+	  /* Temporary storage n for the quotient and ualloc for the
+	     new cofactor. */
+	  n = mpn_gcd_subdiv_step (ap, bp, n, 0, mpn_gcdext_hook, &ctx, tp);
+	  if (n == 0)
+	    return ctx.gn;
+
+	  un = ctx.un;
+	}
+    }
+  ASSERT_ALWAYS (ap[0] > 0);
+  ASSERT_ALWAYS (bp[0] > 0);
+
+  if (ap[0] == bp[0])
+    {
+      int c;
+
+      /* Which cofactor to return now? Candidates are +u1 and -u0,
+	 depending on which of a and b was most recently reduced,
+	 which we don't keep track of. So compare and get the smallest
+	 one. */
+
+      gp[0] = ap[0];
+
+      MPN_CMP (c, u0, u1, un);
+      ASSERT (c != 0 || (un == 1 && u0[0] == 1 && u1[0] == 1));
+      if (c < 0)
+	{
+	  MPN_NORMALIZE (u0, un);
+	  MPN_COPY (up, u0, un);
+	  *usize = -un;
+	}
+      else
+	{
+	  MPN_NORMALIZE_NOT_ZERO (u1, un);
+	  MPN_COPY (up, u1, un);
+	  *usize = un;
+	}
+      return 1;
+    }
+  else
+    {
+      mp_limb_t uh, vh;
+      mp_limb_signed_t u;
+      mp_limb_signed_t v;
+      int negate;
+
+      gp[0] = mpn_gcdext_1 (&u, &v, ap[0], bp[0]);
+
+      /* Set up = u u1 - v u0. Keep track of size, un grows by one or
+	 two limbs. */
+
+      if (u == 0)
+	{
+	  ASSERT (v == 1);
+	  MPN_NORMALIZE (u0, un);
+	  MPN_COPY (up, u0, un);
+	  *usize = -un;
+	  return 1;
+	}
+      else if (v == 0)
+	{
+	  ASSERT (u == 1);
+	  MPN_NORMALIZE (u1, un);
+	  MPN_COPY (up, u1, un);
+	  *usize = un;
+	  return 1;
+	}
+      else if (u > 0)
+	{
+	  negate = 0;
+	  ASSERT (v < 0);
+	  v = -v;
+	}
+      else
+	{
+	  negate = 1;
+	  ASSERT (v > 0);
+	  u = -u;
+	}
+
+      uh = mpn_mul_1 (up, u1, un, u);
+      vh = mpn_addmul_1 (up, u0, un, v);
+
+      if ( (uh | vh) > 0)
+	{
+	  uh += vh;
+	  up[un++] = uh;
+	  if (uh < vh)
+	    up[un++] = 1;
+	}
+
+      MPN_NORMALIZE_NOT_ZERO (up, un);
+
+      *usize = negate ? -un : un;
+      return 1;
+    }
+}
diff --git a/third_party/gmp/mpn/generic/get_d.c b/third_party/gmp/mpn/generic/get_d.c
new file mode 100644
index 0000000..9784f21
--- /dev/null
+++ b/third_party/gmp/mpn/generic/get_d.c
@@ -0,0 +1,438 @@
+/* mpn_get_d -- limbs to double conversion.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2003, 2004, 2007, 2009, 2010, 2012, 2018 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#if HAVE_FLOAT_H
+#include <float.h>  /* for DBL_MANT_DIG and FLT_RADIX */
+#endif
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#ifndef _GMP_IEEE_FLOATS
+#define _GMP_IEEE_FLOATS 0
+#endif
+
+/* To force use of the generic C code for testing, put
+   "#define _GMP_IEEE_FLOATS 0" at this point.  */
+
+
+/* In alpha gcc prior to 3.4, signed DI comparisons involving constants are
+   rearranged from "x < n" to "x+(-n) < 0", which is of course hopelessly
+   wrong if that addition overflows.
+
+   The workaround here avoids this bug by ensuring n is not a literal constant.
+   Note that this is alpha specific.  The offending transformation is/was in
+   alpha.c alpha_emit_conditional_branch() under "We want to use cmpcc/bcc".
+
+   Bizarrely, this happens also with Cray cc on alphaev5-cray-unicosmk2.0.6.X,
+   and has the same solution.  Don't know why or how.  */
+
+#if HAVE_HOST_CPU_FAMILY_alpha				\
+  && ((defined (__GNUC__) && ! __GMP_GNUC_PREREQ(3,4))	\
+      || defined (_CRAY))
+static volatile const long CONST_1024 = 1024;
+static volatile const long CONST_NEG_1023 = -1023;
+static volatile const long CONST_NEG_1022_SUB_53 = -1022 - 53;
+#else
+#define CONST_1024	      (1024)
+#define CONST_NEG_1023	      (-1023)
+#define CONST_NEG_1022_SUB_53 (-1022 - 53)
+#endif
+
+
+/* Return the value {ptr,size}*2^exp, and negative if sign<0.  Must have
+   size>=1, and a non-zero high limb ptr[size-1].
+
+   When we know the fp format, the result is truncated towards zero.  This is
+   consistent with other gmp conversions, like mpz_set_f or mpz_set_q, and is
+   easy to implement and test.
+
+   When we do not know the format, such truncation seems much harder.  One
+   would need to defeat any rounding mode, including round-up.
+
+   It's felt that GMP is not primarily concerned with hardware floats, and
+   really isn't enhanced by getting involved with hardware rounding modes
+   (which could even be some weird unknown style), so something unambiguous and
+   straightforward is best.
+
+
+   The IEEE code below is the usual case, it knows either a 32-bit or 64-bit
+   limb and is done with shifts and masks.  The 64-bit case in particular
+   should come out nice and compact.
+
+   The generic code used to work one bit at a time, which was not only slow,
+   but implicitly relied upon denorms for intermediates, since the lowest bits'
+   weight of a perfectly valid fp number underflows in non-denorm.  Therefore,
+   the generic code now works limb-per-limb, initially creating a number x such
+   that 1 <= x <= BASE.  (BASE is reached only as result of rounding.)  Then
+   x's exponent is scaled with explicit code (not ldexp to avoid libm
+   dependency).  It is a tap-dance to avoid underflow or overflow, beware!
+
+
+   Traps:
+
+   Hardware traps for overflow to infinity, underflow to zero, or unsupported
+   denorms may or may not be taken.  The IEEE code works bitwise and so
+   probably won't trigger them, the generic code works by float operations and
+   so probably will.  This difference might be thought less than ideal, but
+   again its felt straightforward code is better than trying to get intimate
+   with hardware exceptions (of perhaps unknown nature).
+
+
+   Not done:
+
+   mpz_get_d in the past handled size==1 with a cast limb->double.  This might
+   still be worthwhile there (for up to the mantissa many bits), but for
+   mpn_get_d here, the cost of applying "exp" to the resulting exponent would
+   probably use up any benefit a cast may have over bit twiddling.  Also, if
+   the exponent is pushed into denorm range then bit twiddling is the only
+   option, to ensure the desired truncation is obtained.
+
+
+   Other:
+
+   For reference, note that HPPA 8000, 8200, 8500 and 8600 trap FCNV,UDW,DBL
+   to the kernel for values >= 2^63.  This makes it slow, and worse the kernel
+   Linux (what versions?) apparently uses untested code in its trap handling
+   routines, and gets the sign wrong.  We don't use such a limb-to-double
+   cast, neither in the IEEE or generic code.  */
+
+
+
+#undef FORMAT_RECOGNIZED
+
+double
+mpn_get_d (mp_srcptr up, mp_size_t size, mp_size_t sign, long exp)
+{
+  int lshift, nbits;
+  mp_limb_t x, mhi, mlo;
+
+  ASSERT (size >= 0);
+  ASSERT_MPN (up, size);
+  ASSERT (size == 0 || up[size-1] != 0);
+
+  if (size == 0)
+    return 0.0;
+
+  /* Adjust exp to a radix point just above {up,size}, guarding against
+     overflow.  After this exp can of course be reduced to anywhere within
+     the {up,size} region without underflow.  */
+  if (UNLIKELY ((unsigned long) (GMP_NUMB_BITS * size)
+		> ((unsigned long) LONG_MAX - exp)))
+    {
+#if _GMP_IEEE_FLOATS
+      goto ieee_infinity;
+#endif
+
+      /* generic */
+      exp = LONG_MAX;
+    }
+  else
+    {
+      exp += GMP_NUMB_BITS * size;
+    }
+
+#if _GMP_IEEE_FLOATS
+    {
+      union ieee_double_extract u;
+
+      up += size;
+
+#if GMP_LIMB_BITS == 64
+      mlo = up[-1];
+      count_leading_zeros (lshift, mlo);
+
+      exp -= (lshift - GMP_NAIL_BITS) + 1;
+      mlo <<= lshift;
+
+      nbits = GMP_LIMB_BITS - lshift;
+
+      if (nbits < 53 && size > 1)
+	{
+	  x = up[-2];
+	  x <<= GMP_NAIL_BITS;
+	  x >>= nbits;
+	  mlo |= x;
+	  nbits += GMP_NUMB_BITS;
+
+	  if (LIMBS_PER_DOUBLE >= 3 && nbits < 53 && size > 2)
+	    {
+	      x = up[-3];
+	      x <<= GMP_NAIL_BITS;
+	      x >>= nbits;
+	      mlo |= x;
+	      nbits += GMP_NUMB_BITS;
+	    }
+	}
+      mhi = mlo >> (32 + 11);
+      mlo = mlo >> 11;		/* later implicitly truncated to 32 bits */
+#endif
+#if GMP_LIMB_BITS == 32
+      x = *--up;
+      count_leading_zeros (lshift, x);
+
+      exp -= (lshift - GMP_NAIL_BITS) + 1;
+      x <<= lshift;
+      mhi = x >> 11;
+
+      if (lshift < 11)		/* FIXME: never true if NUMB < 20 bits */
+	{
+	  /* All 20 bits in mhi */
+	  mlo = x << 21;
+	  /* >= 1 bit in mlo */
+	  nbits = GMP_LIMB_BITS - lshift - 21;
+	}
+      else
+	{
+	  if (size > 1)
+	    {
+	      nbits = GMP_LIMB_BITS - lshift;
+
+	      x = *--up, size--;
+	      x <<= GMP_NAIL_BITS;
+	      mhi |= x >> nbits >> 11;
+
+	      mlo = x << GMP_LIMB_BITS - nbits - 11;
+	      nbits = nbits + 11 - GMP_NAIL_BITS;
+	    }
+	  else
+	    {
+	      mlo = 0;
+	      goto done;
+	    }
+	}
+
+      /* Now all needed bits in mhi have been accumulated.  Add bits to mlo.  */
+
+      if (LIMBS_PER_DOUBLE >= 2 && nbits < 32 && size > 1)
+	{
+	  x = up[-1];
+	  x <<= GMP_NAIL_BITS;
+	  x >>= nbits;
+	  mlo |= x;
+	  nbits += GMP_NUMB_BITS;
+
+	  if (LIMBS_PER_DOUBLE >= 3 && nbits < 32 && size > 2)
+	    {
+	      x = up[-2];
+	      x <<= GMP_NAIL_BITS;
+	      x >>= nbits;
+	      mlo |= x;
+	      nbits += GMP_NUMB_BITS;
+
+	      if (LIMBS_PER_DOUBLE >= 4 && nbits < 32 && size > 3)
+		{
+		  x = up[-3];
+		  x <<= GMP_NAIL_BITS;
+		  x >>= nbits;
+		  mlo |= x;
+		  nbits += GMP_NUMB_BITS;
+		}
+	    }
+	}
+
+    done:;
+
+#endif
+      if (UNLIKELY (exp >= CONST_1024))
+	{
+	  /* overflow, return infinity */
+	ieee_infinity:
+	  mhi = 0;
+	  mlo = 0;
+	  exp = 1024;
+	}
+      else if (UNLIKELY (exp <= CONST_NEG_1023))
+	{
+	  int rshift;
+
+	  if (LIKELY (exp <= CONST_NEG_1022_SUB_53))
+	    return 0.0;	 /* denorm underflows to zero */
+
+	  rshift = -1022 - exp;
+	  ASSERT (rshift > 0 && rshift < 53);
+#if GMP_LIMB_BITS > 53
+	  mlo >>= rshift;
+	  mhi = mlo >> 32;
+#else
+	  if (rshift >= 32)
+	    {
+	      mlo = mhi;
+	      mhi = 0;
+	      rshift -= 32;
+	    }
+	  lshift = GMP_LIMB_BITS - rshift;
+	  mlo = (mlo >> rshift) | (rshift == 0 ? 0 : mhi << lshift);
+	  mhi >>= rshift;
+#endif
+	  exp = -1023;
+	}
+      u.s.manh = mhi;
+      u.s.manl = mlo;
+      u.s.exp = exp + 1023;
+      u.s.sig = (sign < 0);
+      return u.d;
+    }
+#define FORMAT_RECOGNIZED 1
+#endif
+
+#if HAVE_DOUBLE_VAX_D
+    {
+      union double_extract u;
+
+      up += size;
+
+      mhi = up[-1];
+
+      count_leading_zeros (lshift, mhi);
+      exp -= lshift;
+      mhi <<= lshift;
+
+      mlo = 0;
+      if (size > 1)
+	{
+	  mlo = up[-2];
+	  if (lshift != 0)
+	    mhi += mlo >> (GMP_LIMB_BITS - lshift);
+	  mlo <<= lshift;
+
+	  if (size > 2 && lshift > 8)
+	    {
+	      x = up[-3];
+	      mlo += x >> (GMP_LIMB_BITS - lshift);
+	    }
+	}
+
+      if (UNLIKELY (exp >= 128))
+	{
+	  /* overflow, return maximum number */
+	  mhi = 0xffffffff;
+	  mlo = 0xffffffff;
+	  exp = 127;
+	}
+      else if (UNLIKELY (exp < -128))
+	{
+	  return 0.0;	 /* underflows to zero */
+	}
+
+      u.s.man3 = mhi >> 24;	/* drop msb, since implicit */
+      u.s.man2 = mhi >> 8;
+      u.s.man1 = (mhi << 8) + (mlo >> 24);
+      u.s.man0 = mlo >> 8;
+      u.s.exp = exp + 128;
+      u.s.sig = sign < 0;
+      return u.d;
+    }
+#define FORMAT_RECOGNIZED 1
+#endif
+
+#if ! FORMAT_RECOGNIZED
+
+#if !defined(GMP_DBL_MANT_BITS)
+#if defined(DBL_MANT_DIG) && FLT_RADIX == 2
+#define GMP_DBL_MANT_BITS DBL_MANT_DIG
+#else
+/* FIXME: Chose a smarter default value. */
+#define GMP_DBL_MANT_BITS (16 * sizeof (double))
+#endif
+#endif
+
+    { /* Non-IEEE or strange limb size, generically convert
+	 GMP_DBL_MANT_BITS bits. */
+      mp_limb_t l;
+      int m;
+      mp_size_t i;
+      double d, weight;
+      unsigned long uexp;
+
+      /* First generate an fp number disregarding exp, instead keeping things
+	 within the numb base factor from 1, which should prevent overflow and
+	 underflow even for the most exponent limited fp formats.  */
+      i = size - 1;
+      l = up[i];
+      count_leading_zeros (m, l);
+      m = m + GMP_DBL_MANT_BITS - GMP_LIMB_BITS;
+      if (m < 0)
+	l &= GMP_NUMB_MAX << -m;
+      d = l;
+      for (weight = 1/MP_BASE_AS_DOUBLE; m > 0 && --i >= 0;)
+	{
+	  l = up[i];
+	  m -= GMP_NUMB_BITS;
+	  if (m < 0)
+	    l &= GMP_NUMB_MAX << -m;
+	  d += l * weight;
+	  weight /= MP_BASE_AS_DOUBLE;
+	  if (weight == 0)
+	    break;
+	}
+
+      /* Now apply exp.  */
+      exp -= GMP_NUMB_BITS;
+      if (exp > 0)
+	{
+	  weight = 2.0;
+	  uexp = exp;
+	}
+      else
+	{
+	  weight = 0.5;
+	  uexp = NEG_CAST (unsigned long, exp);
+	}
+#if 1
+      /* Square-and-multiply exponentiation.  */
+      if (uexp & 1)
+	d *= weight;
+      while (uexp >>= 1)
+	{
+	  weight *= weight;
+	  if (uexp & 1)
+	    d *= weight;
+	}
+#else
+      /* Plain exponentiation.  */
+      while (uexp > 0)
+	{
+	  d *= weight;
+	  uexp--;
+	}
+#endif
+
+      return sign >= 0 ? d : -d;
+    }
+#endif
+}
diff --git a/third_party/gmp/mpn/generic/get_str.c b/third_party/gmp/mpn/generic/get_str.c
new file mode 100644
index 0000000..19cc581
--- /dev/null
+++ b/third_party/gmp/mpn/generic/get_str.c
@@ -0,0 +1,451 @@
+/* mpn_get_str -- Convert {UP,USIZE} to a base BASE string in STR.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+   THE FUNCTIONS IN THIS FILE, EXCEPT mpn_get_str, ARE INTERNAL WITH MUTABLE
+   INTERFACES.  IT IS ONLY SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.
+   IN FACT, IT IS ALMOST GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A
+   FUTURE GNU MP RELEASE.
+
+Copyright 1991-2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/* Conversion of U {up,un} to a string in base b.  Internally, we convert to
+   base B = b^m, the largest power of b that fits a limb.  Basic algorithms:
+
+  A) Divide U repeatedly by B, generating a quotient and remainder, until the
+     quotient becomes zero.  The remainders hold the converted digits.  Digits
+     come out from right to left.  (Used in mpn_bc_get_str.)
+
+  B) Divide U by b^g, for g such that 1/b <= U/b^g < 1, generating a fraction.
+     Then develop digits by multiplying the fraction repeatedly by b.  Digits
+     come out from left to right.  (Currently not used herein, except for in
+     code for converting single limbs to individual digits.)
+
+  C) Compute B^1, B^2, B^4, ..., B^s, for s such that B^s is just above
+     sqrt(U).  Then divide U by B^s, generating quotient and remainder.
+     Recursively convert the quotient, then the remainder, using the
+     precomputed powers.  Digits come out from left to right.  (Used in
+     mpn_dc_get_str.)
+
+  When using algorithm C, algorithm B might be suitable for basecase code,
+  since the required b^g power will be readily accessible.
+
+  Optimization ideas:
+  1. The recursive function of (C) could use less temporary memory.  The powtab
+     allocation could be trimmed with some computation, and the tmp area could
+     be reduced, or perhaps eliminated if up is reused for both quotient and
+     remainder (it is currently used just for remainder).
+  2. Store the powers of (C) in normalized form, with the normalization count.
+     Quotients will usually need to be left-shifted before each divide, and
+     remainders will either need to be left-shifted of right-shifted.
+  3. In the code for developing digits from a single limb, we could avoid using
+     a full umul_ppmm except for the first (or first few) digits, provided base
+     is even.  Subsequent digits can be developed using plain multiplication.
+     (This saves on register-starved machines (read x86) and on all machines
+     that generate the upper product half using a separate instruction (alpha,
+     powerpc, IA-64) or lacks such support altogether (sparc64, hppa64).
+  4. Separate mpn_dc_get_str basecase code from code for small conversions. The
+     former code will have the exact right power readily available in the
+     powtab parameter for dividing the current number into a fraction.  Convert
+     that using algorithm B.
+  5. Completely avoid division.  Compute the inverses of the powers now in
+     powtab instead of the actual powers.
+  6. Decrease powtab allocation for even bases.  E.g. for base 10 we could save
+     about 30% (1-log(5)/log(10)).
+
+  Basic structure of (C):
+    mpn_get_str:
+      if POW2_P (n)
+	...
+      else
+	if (un < GET_STR_PRECOMPUTE_THRESHOLD)
+	  mpn_bx_get_str (str, base, up, un);
+	else
+	  precompute_power_tables
+	  mpn_dc_get_str
+
+    mpn_dc_get_str:
+	mpn_tdiv_qr
+	if (qn < GET_STR_DC_THRESHOLD)
+	  mpn_bc_get_str
+	else
+	  mpn_dc_get_str
+	if (rn < GET_STR_DC_THRESHOLD)
+	  mpn_bc_get_str
+	else
+	  mpn_dc_get_str
+
+
+  The reason for the two threshold values is the cost of
+  precompute_power_tables.  GET_STR_PRECOMPUTE_THRESHOLD will be
+  considerably larger than GET_STR_DC_THRESHOLD.  */
+
+
+/* The x86s and m68020 have a quotient and remainder "div" instruction and
+   gcc recognises an adjacent "/" and "%" can be combined using that.
+   Elsewhere "/" and "%" are either separate instructions, or separate
+   libgcc calls (which unfortunately gcc as of version 3.0 doesn't combine).
+   A multiply and subtract should be faster than a "%" in those cases.  */
+#if HAVE_HOST_CPU_FAMILY_x86            \
+  || HAVE_HOST_CPU_m68020               \
+  || HAVE_HOST_CPU_m68030               \
+  || HAVE_HOST_CPU_m68040               \
+  || HAVE_HOST_CPU_m68060               \
+  || HAVE_HOST_CPU_m68360 /* CPU32 */
+#define udiv_qrnd_unnorm(q,r,n,d)       \
+  do {                                  \
+    mp_limb_t  __q = (n) / (d);         \
+    mp_limb_t  __r = (n) % (d);         \
+    (q) = __q;                          \
+    (r) = __r;                          \
+  } while (0)
+#else
+#define udiv_qrnd_unnorm(q,r,n,d)       \
+  do {                                  \
+    mp_limb_t  __q = (n) / (d);         \
+    mp_limb_t  __r = (n) - __q*(d);     \
+    (q) = __q;                          \
+    (r) = __r;                          \
+  } while (0)
+#endif
+
+
+/* Convert {up,un} to a string in base base, and put the result in str.
+   Generate len characters, possibly padding with zeros to the left.  If len is
+   zero, generate as many characters as required.  Return a pointer immediately
+   after the last digit of the result string.  Complexity is O(un^2); intended
+   for small conversions.  */
+static unsigned char *
+mpn_bc_get_str (unsigned char *str, size_t len,
+		mp_ptr up, mp_size_t un, int base)
+{
+  mp_limb_t rl, ul;
+  unsigned char *s;
+  size_t l;
+  /* Allocate memory for largest possible string, given that we only get here
+     for operands with un < GET_STR_PRECOMPUTE_THRESHOLD and that the smallest
+     base is 3.  7/11 is an approximation to 1/log2(3).  */
+#if TUNE_PROGRAM_BUILD
+#define BUF_ALLOC (GET_STR_THRESHOLD_LIMIT * GMP_LIMB_BITS * 7 / 11)
+#else
+#define BUF_ALLOC (GET_STR_PRECOMPUTE_THRESHOLD * GMP_LIMB_BITS * 7 / 11)
+#endif
+  unsigned char buf[BUF_ALLOC];
+#if TUNE_PROGRAM_BUILD
+  mp_limb_t rp[GET_STR_THRESHOLD_LIMIT];
+#else
+  mp_limb_t rp[GET_STR_PRECOMPUTE_THRESHOLD];
+#endif
+
+  if (base == 10)
+    {
+      /* Special case code for base==10 so that the compiler has a chance to
+	 optimize things.  */
+
+      MPN_COPY (rp + 1, up, un);
+
+      s = buf + BUF_ALLOC;
+      while (un > 1)
+	{
+	  int i;
+	  mp_limb_t frac, digit;
+	  MPN_DIVREM_OR_PREINV_DIVREM_1 (rp, (mp_size_t) 1, rp + 1, un,
+					 MP_BASES_BIG_BASE_10,
+					 MP_BASES_BIG_BASE_INVERTED_10,
+					 MP_BASES_NORMALIZATION_STEPS_10);
+	  un -= rp[un] == 0;
+	  frac = (rp[0] + 1) << GMP_NAIL_BITS;
+	  s -= MP_BASES_CHARS_PER_LIMB_10;
+#if HAVE_HOST_CPU_FAMILY_x86
+	  /* The code below turns out to be a bit slower for x86 using gcc.
+	     Use plain code.  */
+	  i = MP_BASES_CHARS_PER_LIMB_10;
+	  do
+	    {
+	      umul_ppmm (digit, frac, frac, 10);
+	      *s++ = digit;
+	    }
+	  while (--i);
+#else
+	  /* Use the fact that 10 in binary is 1010, with the lowest bit 0.
+	     After a few umul_ppmm, we will have accumulated enough low zeros
+	     to use a plain multiply.  */
+	  if (MP_BASES_NORMALIZATION_STEPS_10 == 0)
+	    {
+	      umul_ppmm (digit, frac, frac, 10);
+	      *s++ = digit;
+	    }
+	  if (MP_BASES_NORMALIZATION_STEPS_10 <= 1)
+	    {
+	      umul_ppmm (digit, frac, frac, 10);
+	      *s++ = digit;
+	    }
+	  if (MP_BASES_NORMALIZATION_STEPS_10 <= 2)
+	    {
+	      umul_ppmm (digit, frac, frac, 10);
+	      *s++ = digit;
+	    }
+	  if (MP_BASES_NORMALIZATION_STEPS_10 <= 3)
+	    {
+	      umul_ppmm (digit, frac, frac, 10);
+	      *s++ = digit;
+	    }
+	  i = (MP_BASES_CHARS_PER_LIMB_10 - ((MP_BASES_NORMALIZATION_STEPS_10 < 4)
+					     ? (4-MP_BASES_NORMALIZATION_STEPS_10)
+					     : 0));
+	  frac = (frac + 0xf) >> 4;
+	  do
+	    {
+	      frac *= 10;
+	      digit = frac >> (GMP_LIMB_BITS - 4);
+	      *s++ = digit;
+	      frac &= (~(mp_limb_t) 0) >> 4;
+	    }
+	  while (--i);
+#endif
+	  s -= MP_BASES_CHARS_PER_LIMB_10;
+	}
+
+      ul = rp[1];
+      while (ul != 0)
+	{
+	  udiv_qrnd_unnorm (ul, rl, ul, 10);
+	  *--s = rl;
+	}
+    }
+  else /* not base 10 */
+    {
+      unsigned chars_per_limb;
+      mp_limb_t big_base, big_base_inverted;
+      unsigned normalization_steps;
+
+      chars_per_limb = mp_bases[base].chars_per_limb;
+      big_base = mp_bases[base].big_base;
+      big_base_inverted = mp_bases[base].big_base_inverted;
+      count_leading_zeros (normalization_steps, big_base);
+
+      MPN_COPY (rp + 1, up, un);
+
+      s = buf + BUF_ALLOC;
+      while (un > 1)
+	{
+	  int i;
+	  mp_limb_t frac;
+	  MPN_DIVREM_OR_PREINV_DIVREM_1 (rp, (mp_size_t) 1, rp + 1, un,
+					 big_base, big_base_inverted,
+					 normalization_steps);
+	  un -= rp[un] == 0;
+	  frac = (rp[0] + 1) << GMP_NAIL_BITS;
+	  s -= chars_per_limb;
+	  i = chars_per_limb;
+	  do
+	    {
+	      mp_limb_t digit;
+	      umul_ppmm (digit, frac, frac, base);
+	      *s++ = digit;
+	    }
+	  while (--i);
+	  s -= chars_per_limb;
+	}
+
+      ul = rp[1];
+      while (ul != 0)
+	{
+	  udiv_qrnd_unnorm (ul, rl, ul, base);
+	  *--s = rl;
+	}
+    }
+
+  l = buf + BUF_ALLOC - s;
+  while (l < len)
+    {
+      *str++ = 0;
+      len--;
+    }
+  while (l != 0)
+    {
+      *str++ = *s++;
+      l--;
+    }
+  return str;
+}
+
+
+/* Convert {UP,UN} to a string with a base as represented in POWTAB, and put
+   the string in STR.  Generate LEN characters, possibly padding with zeros to
+   the left.  If LEN is zero, generate as many characters as required.
+   Return a pointer immediately after the last digit of the result string.
+   This uses divide-and-conquer and is intended for large conversions.  */
+static unsigned char *
+mpn_dc_get_str (unsigned char *str, size_t len,
+		mp_ptr up, mp_size_t un,
+		const powers_t *powtab, mp_ptr tmp)
+{
+  if (BELOW_THRESHOLD (un, GET_STR_DC_THRESHOLD))
+    {
+      if (un != 0)
+	str = mpn_bc_get_str (str, len, up, un, powtab->base);
+      else
+	{
+	  while (len != 0)
+	    {
+	      *str++ = 0;
+	      len--;
+	    }
+	}
+    }
+  else
+    {
+      mp_ptr pwp, qp, rp;
+      mp_size_t pwn, qn;
+      mp_size_t sn;
+
+      pwp = powtab->p;
+      pwn = powtab->n;
+      sn = powtab->shift;
+
+      if (un < pwn + sn || (un == pwn + sn && mpn_cmp (up + sn, pwp, un - sn) < 0))
+	{
+	  str = mpn_dc_get_str (str, len, up, un, powtab - 1, tmp);
+	}
+      else
+	{
+	  qp = tmp;		/* (un - pwn + 1) limbs for qp */
+	  rp = up;		/* pwn limbs for rp; overwrite up area */
+
+	  mpn_tdiv_qr (qp, rp + sn, 0L, up + sn, un - sn, pwp, pwn);
+	  qn = un - sn - pwn; qn += qp[qn] != 0;		/* quotient size */
+
+	  ASSERT (qn < pwn + sn || (qn == pwn + sn && mpn_cmp (qp + sn, pwp, pwn) < 0));
+
+	  if (len != 0)
+	    len = len - powtab->digits_in_base;
+
+	  str = mpn_dc_get_str (str, len, qp, qn, powtab - 1, tmp + qn);
+	  str = mpn_dc_get_str (str, powtab->digits_in_base, rp, pwn + sn, powtab - 1, tmp);
+	}
+    }
+  return str;
+}
+
+/* There are no leading zeros on the digits generated at str, but that's not
+   currently a documented feature.  The current mpz_out_str and mpz_get_str
+   rely on it.  */
+
+size_t
+mpn_get_str (unsigned char *str, int base, mp_ptr up, mp_size_t un)
+{
+  mp_ptr powtab_mem;
+  powers_t powtab[GMP_LIMB_BITS];
+  int pi;
+  size_t out_len;
+  mp_ptr tmp;
+  TMP_DECL;
+
+  /* Special case zero, as the code below doesn't handle it.  */
+  if (un == 0)
+    {
+      str[0] = 0;
+      return 1;
+    }
+
+  if (POW2_P (base))
+    {
+      /* The base is a power of 2.  Convert from most significant end.  */
+      mp_limb_t n1, n0;
+      int bits_per_digit = mp_bases[base].big_base;
+      int cnt;
+      int bit_pos;
+      mp_size_t i;
+      unsigned char *s = str;
+      mp_bitcnt_t bits;
+
+      n1 = up[un - 1];
+      count_leading_zeros (cnt, n1);
+
+      /* BIT_POS should be R when input ends in least significant nibble,
+	 R + bits_per_digit * n when input ends in nth least significant
+	 nibble. */
+
+      bits = (mp_bitcnt_t) GMP_NUMB_BITS * un - cnt + GMP_NAIL_BITS;
+      cnt = bits % bits_per_digit;
+      if (cnt != 0)
+	bits += bits_per_digit - cnt;
+      bit_pos = bits - (mp_bitcnt_t) (un - 1) * GMP_NUMB_BITS;
+
+      /* Fast loop for bit output.  */
+      i = un - 1;
+      for (;;)
+	{
+	  bit_pos -= bits_per_digit;
+	  while (bit_pos >= 0)
+	    {
+	      *s++ = (n1 >> bit_pos) & ((1 << bits_per_digit) - 1);
+	      bit_pos -= bits_per_digit;
+	    }
+	  i--;
+	  if (i < 0)
+	    break;
+	  n0 = (n1 << -bit_pos) & ((1 << bits_per_digit) - 1);
+	  n1 = up[i];
+	  bit_pos += GMP_NUMB_BITS;
+	  *s++ = n0 | (n1 >> bit_pos);
+	}
+
+      return s - str;
+    }
+
+  /* General case.  The base is not a power of 2.  */
+
+  if (BELOW_THRESHOLD (un, GET_STR_PRECOMPUTE_THRESHOLD))
+    return mpn_bc_get_str (str, (size_t) 0, up, un, base) - str;
+
+  TMP_MARK;
+
+  /* Allocate one large block for the powers of big_base.  */
+  powtab_mem = TMP_BALLOC_LIMBS (mpn_str_powtab_alloc (un));
+
+  /* Compute a table of powers, were the largest power is >= sqrt(U).  */
+  size_t ndig;
+  mp_size_t xn;
+  DIGITS_IN_BASE_PER_LIMB (ndig, un, base);
+  xn = 1 + ndig / mp_bases[base].chars_per_limb; /* FIXME: scalar integer division */
+
+  pi = 1 + mpn_compute_powtab (powtab, powtab_mem, xn, base);
+
+  /* Using our precomputed powers, now in powtab[], convert our number.  */
+  tmp = TMP_BALLOC_LIMBS (mpn_dc_get_str_itch (un));
+  out_len = mpn_dc_get_str (str, 0, up, un, powtab + (pi - 1), tmp) - str;
+  TMP_FREE;
+
+  return out_len;
+}
diff --git a/third_party/gmp/mpn/generic/gmp-mparam.h b/third_party/gmp/mpn/generic/gmp-mparam.h
new file mode 100644
index 0000000..7dc057a
--- /dev/null
+++ b/third_party/gmp/mpn/generic/gmp-mparam.h
@@ -0,0 +1,33 @@
+/* Generic C gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+/* Values for GMP_LIMB_BITS etc will be determined by ./configure and put
+   in config.h. */
diff --git a/third_party/gmp/mpn/generic/hgcd.c b/third_party/gmp/mpn/generic/hgcd.c
new file mode 100644
index 0000000..e3e9c66
--- /dev/null
+++ b/third_party/gmp/mpn/generic/hgcd.c
@@ -0,0 +1,182 @@
+/* hgcd.c.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2003-2005, 2008, 2011, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* Size analysis for hgcd:
+
+   For the recursive calls, we have n1 <= ceil(n / 2). Then the
+   storage need is determined by the storage for the recursive call
+   computing M1, and hgcd_matrix_adjust and hgcd_matrix_mul calls that use M1
+   (after this, the storage needed for M1 can be recycled).
+
+   Let S(r) denote the required storage. For M1 we need 4 * (ceil(n1/2) + 1)
+   = 4 * (ceil(n/4) + 1), for the hgcd_matrix_adjust call, we need n + 2,
+   and for the hgcd_matrix_mul, we may need 3 ceil(n/2) + 8. In total,
+   4 * ceil(n/4) + 3 ceil(n/2) + 12 <= 10 ceil(n/4) + 12.
+
+   For the recursive call, we need S(n1) = S(ceil(n/2)).
+
+   S(n) <= 10*ceil(n/4) + 12 + S(ceil(n/2))
+	<= 10*(ceil(n/4) + ... + ceil(n/2^(1+k))) + 12k + S(ceil(n/2^k))
+	<= 10*(2 ceil(n/4) + k) + 12k + S(ceil(n/2^k))
+	<= 20 ceil(n/4) + 22k + S(ceil(n/2^k))
+*/
+
+mp_size_t
+mpn_hgcd_itch (mp_size_t n)
+{
+  unsigned k;
+  int count;
+  mp_size_t nscaled;
+
+  if (BELOW_THRESHOLD (n, HGCD_THRESHOLD))
+    return n;
+
+  /* Get the recursion depth. */
+  nscaled = (n - 1) / (HGCD_THRESHOLD - 1);
+  count_leading_zeros (count, nscaled);
+  k = GMP_LIMB_BITS - count;
+
+  return 20 * ((n+3) / 4) + 22 * k + HGCD_THRESHOLD;
+}
+
+/* Reduces a,b until |a-b| fits in n/2 + 1 limbs. Constructs matrix M
+   with elements of size at most (n+1)/2 - 1. Returns new size of a,
+   b, or zero if no reduction is possible. */
+
+mp_size_t
+mpn_hgcd (mp_ptr ap, mp_ptr bp, mp_size_t n,
+	  struct hgcd_matrix *M, mp_ptr tp)
+{
+  mp_size_t s = n/2 + 1;
+
+  mp_size_t nn;
+  int success = 0;
+
+  if (n <= s)
+    /* Happens when n <= 2, a fairly uninteresting case but exercised
+       by the random inputs of the testsuite. */
+    return 0;
+
+  ASSERT ((ap[n-1] | bp[n-1]) > 0);
+
+  ASSERT ((n+1)/2 - 1 < M->alloc);
+
+  if (ABOVE_THRESHOLD (n, HGCD_THRESHOLD))
+    {
+      mp_size_t n2 = (3*n)/4 + 1;
+      mp_size_t p = n/2;
+
+      nn = mpn_hgcd_reduce (M, ap, bp, n, p, tp);
+      if (nn)
+	{
+	  n = nn;
+	  success = 1;
+	}
+
+      /* NOTE: It appears this loop never runs more than once (at
+	 least when not recursing to hgcd_appr). */
+      while (n > n2)
+	{
+	  /* Needs n + 1 storage */
+	  nn = mpn_hgcd_step (n, ap, bp, s, M, tp);
+	  if (!nn)
+	    return success ? n : 0;
+
+	  n = nn;
+	  success = 1;
+	}
+
+      if (n > s + 2)
+	{
+	  struct hgcd_matrix M1;
+	  mp_size_t scratch;
+
+	  p = 2*s - n + 1;
+	  scratch = MPN_HGCD_MATRIX_INIT_ITCH (n-p);
+
+	  mpn_hgcd_matrix_init(&M1, n - p, tp);
+
+	  /* FIXME: Should use hgcd_reduce, but that may require more
+	     scratch space, which requires review. */
+
+	  nn = mpn_hgcd (ap + p, bp + p, n - p, &M1, tp + scratch);
+	  if (nn > 0)
+	    {
+	      /* We always have max(M) > 2^{-(GMP_NUMB_BITS + 1)} max(M1) */
+	      ASSERT (M->n + 2 >= M1.n);
+
+	      /* Furthermore, assume M ends with a quotient (1, q; 0, 1),
+		 then either q or q + 1 is a correct quotient, and M1 will
+		 start with either (1, 0; 1, 1) or (2, 1; 1, 1). This
+		 rules out the case that the size of M * M1 is much
+		 smaller than the expected M->n + M1->n. */
+
+	      ASSERT (M->n + M1.n < M->alloc);
+
+	      /* Needs 2 (p + M->n) <= 2 (2*s - n2 + 1 + n2 - s - 1)
+		 = 2*s <= 2*(floor(n/2) + 1) <= n + 2. */
+	      n = mpn_hgcd_matrix_adjust (&M1, p + nn, ap, bp, p, tp + scratch);
+
+	      /* We need a bound for of M->n + M1.n. Let n be the original
+		 input size. Then
+
+		 ceil(n/2) - 1 >= size of product >= M.n + M1.n - 2
+
+		 and it follows that
+
+		 M.n + M1.n <= ceil(n/2) + 1
+
+		 Then 3*(M.n + M1.n) + 5 <= 3 * ceil(n/2) + 8 is the
+		 amount of needed scratch space. */
+	      mpn_hgcd_matrix_mul (M, &M1, tp + scratch);
+	      success = 1;
+	    }
+	}
+    }
+
+  for (;;)
+    {
+      /* Needs s+3 < n */
+      nn = mpn_hgcd_step (n, ap, bp, s, M, tp);
+      if (!nn)
+	return success ? n : 0;
+
+      n = nn;
+      success = 1;
+    }
+}
diff --git a/third_party/gmp/mpn/generic/hgcd2.c b/third_party/gmp/mpn/generic/hgcd2.c
new file mode 100644
index 0000000..3fa4012
--- /dev/null
+++ b/third_party/gmp/mpn/generic/hgcd2.c
@@ -0,0 +1,734 @@
+/* hgcd2.c
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 1996, 1998, 2000-2004, 2008, 2012, 2019 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#ifndef HGCD2_DIV1_METHOD
+#define HGCD2_DIV1_METHOD 3
+#endif
+
+#ifndef HGCD2_DIV2_METHOD
+#define HGCD2_DIV2_METHOD 2
+#endif
+
+#if GMP_NAIL_BITS != 0
+#error Nails not implemented
+#endif
+
+#if HAVE_NATIVE_mpn_div_11
+
+#define div1 mpn_div_11
+/* Single-limb division optimized for small quotients.
+   Returned value holds d0 = r, d1 = q. */
+mp_double_limb_t div1 (mp_limb_t, mp_limb_t);
+
+#elif HGCD2_DIV1_METHOD == 1
+
+static inline mp_double_limb_t
+div1 (mp_limb_t n0, mp_limb_t d0)
+{
+  mp_double_limb_t res;
+  res.d1 = n0 / d0;
+  res.d0 = n0 - res.d1 * d0;
+
+  return res;
+}
+
+#elif HGCD2_DIV1_METHOD == 2
+
+static mp_double_limb_t
+div1 (mp_limb_t n0, mp_limb_t d0)
+{
+  mp_double_limb_t res;
+  int ncnt, dcnt, cnt;
+  mp_limb_t q;
+  mp_limb_t mask;
+
+  ASSERT (n0 >= d0);
+
+  count_leading_zeros (ncnt, n0);
+  count_leading_zeros (dcnt, d0);
+  cnt = dcnt - ncnt;
+
+  d0 <<= cnt;
+
+  q = -(mp_limb_t) (n0 >= d0);
+  n0 -= d0 & q;
+  d0 >>= 1;
+  q = -q;
+
+  while (--cnt >= 0)
+    {
+      mask = -(mp_limb_t) (n0 >= d0);
+      n0 -= d0 & mask;
+      d0 >>= 1;
+      q = (q << 1) - mask;
+    }
+
+  res.d0 = n0;
+  res.d1 = q;
+  return res;
+}
+
+#elif HGCD2_DIV1_METHOD == 3
+
+static inline mp_double_limb_t
+div1 (mp_limb_t n0, mp_limb_t d0)
+{
+  mp_double_limb_t res;
+  if (UNLIKELY ((d0 >> (GMP_LIMB_BITS - 3)) != 0)
+      || UNLIKELY (n0 >= (d0 << 3)))
+    {
+      res.d1 = n0 / d0;
+      res.d0 = n0 - res.d1 * d0;
+    }
+  else
+    {
+      mp_limb_t q, mask;
+
+      d0 <<= 2;
+
+      mask = -(mp_limb_t) (n0 >= d0);
+      n0 -= d0 & mask;
+      q = 4 & mask;
+
+      d0 >>= 1;
+      mask = -(mp_limb_t) (n0 >= d0);
+      n0 -= d0 & mask;
+      q += 2 & mask;
+
+      d0 >>= 1;
+      mask = -(mp_limb_t) (n0 >= d0);
+      n0 -= d0 & mask;
+      q -= mask;
+
+      res.d0 = n0;
+      res.d1 = q;
+    }
+  return res;
+}
+
+#elif HGCD2_DIV1_METHOD == 4
+
+/* Table quotients.  We extract the NBITS most significant bits of the
+   numerator limb, and the corresponding bits from the divisor limb, and use
+   these to form an index into the table.  This method is probably only useful
+   for short pipelines with slow multiplication.
+
+   Possible improvements:
+
+   * Perhaps extract the highest NBITS of the divisor instead of the same bits
+     as from the numerator.  That would require another count_leading_zeros,
+     and a post-multiply shift of the quotient.
+
+   * Compress tables?  Their values are tiny, and there are lots of zero
+     entries (which are never used).
+
+   * Round the table entries more cleverly?
+*/
+
+#ifndef NBITS
+#define NBITS 5
+#endif
+
+#if NBITS == 5
+/* This needs full division about 13.2% of the time. */
+static const unsigned char tab[512] = {
+17, 9, 5,4,3,2,2,2,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+18, 9, 6,4,3,2,2,2,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+19,10, 6,4,3,3,2,2,2,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,
+20,10, 6,5,3,3,2,2,2,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,
+21,11, 7,5,4,3,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,
+22,11, 7,5,4,3,3,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,
+23,12, 7,5,4,3,3,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,
+24,12, 8,6,4,3,3,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,
+25,13, 8,6,5,4,3,3,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,
+26,13, 8,6,5,4,3,3,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,
+27,14, 9,6,5,4,3,3,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,
+28,14, 9,7,5,4,3,3,3,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,
+29,15,10,7,5,4,4,3,3,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,
+30,15,10,7,6,5,4,3,3,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,
+31,16,10,7,6,5,4,3,3,3,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
+32,16,11,8,6,5,4,3,3,3,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
+};
+#elif NBITS == 6
+/* This needs full division about 9.8% of the time. */
+static const unsigned char tab[2048] = {
+33,17,11, 8, 6, 5,4,4,3,3,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 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,0,0,0,0,0,
+34,17,11, 8, 6, 5,4,4,3,3,3,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1, 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,0,0,0,0,
+35,18,12, 9, 7, 5,5,4,3,3,3,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1, 1, 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,0,0,0,
+36,18,12, 9, 7, 6,5,4,3,3,3,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1, 1, 1, 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,0,0,
+37,19,13, 9, 7, 6,5,4,4,3,3,3,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1, 1, 1, 1, 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,0,
+38,19,13, 9, 7, 6,5,4,4,3,3,3,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1, 1, 1, 1, 1, 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,
+39,20,13,10, 7, 6,5,4,4,3,3,3,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1, 1, 1, 1, 1, 1,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,
+40,20,14,10, 8, 6,5,5,4,3,3,3,3,2,2,2,2,2,2,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+41,21,14,10, 8, 6,5,5,4,4,3,3,3,2,2,2,2,2,2,2,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+42,21,14,10, 8, 7,6,5,4,4,3,3,3,2,2,2,2,2,2,2,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+43,22,15,11, 8, 7,6,5,4,4,3,3,3,3,2,2,2,2,2,2,2,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+44,22,15,11, 9, 7,6,5,4,4,3,3,3,3,2,2,2,2,2,2,2,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+45,23,15,11, 9, 7,6,5,5,4,4,3,3,3,2,2,2,2,2,2,2,2,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+46,23,16,11, 9, 7,6,5,5,4,4,3,3,3,3,2,2,2,2,2,2,2,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+47,24,16,12, 9, 7,6,5,5,4,4,3,3,3,3,2,2,2,2,2,2,2,2,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+48,24,16,12, 9, 8,6,6,5,4,4,3,3,3,3,2,2,2,2,2,2,2,2,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,0,0,0,0,0,0,0,0,0,0,0,0,0,
+49,25,17,12,10, 8,7,6,5,4,4,4,3,3,3,3,2,2,2,2,2,2,2,2,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,0,0,0,0,0,0,0,0,0,0,0,0,
+50,25,17,13,10, 8,7,6,5,5,4,4,3,3,3,3,2,2,2,2,2,2,2,2,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,0,0,0,0,0,0,0,0,0,0,0,
+51,26,18,13,10, 8,7,6,5,5,4,4,3,3,3,3,2,2,2,2,2,2,2,2,2,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,0,0,0,0,0,0,0,0,0,0,
+52,26,18,13,10, 8,7,6,5,5,4,4,3,3,3,3,3,2,2,2,2,2,2,2,2,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,0,0,0,0,0,0,0,0,0,
+53,27,18,13,10, 9,7,6,5,5,4,4,4,3,3,3,3,2,2,2,2,2,2,2,2,2,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,0,0,0,0,0,0,0,0,
+54,27,19,14,11, 9,7,6,6,5,4,4,4,3,3,3,3,2,2,2,2,2,2,2,2,2,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,0,0,0,0,0,0,0,0,0,0,
+55,28,19,14,11, 9,7,6,6,5,5,4,4,3,3,3,3,3,2,2,2,2,2,2,2,2,2,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,0,0,0,0,0,0,0,0,0,
+56,28,19,14,11, 9,8,7,6,5,5,4,4,3,3,3,3,3,2,2,2,2,2,2,2,2,2,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,0,0,0,0,0,0,0,0,
+57,29,20,14,11, 9,8,7,6,5,5,4,4,4,3,3,3,3,2,2,2,2,2,2,2,2,2,2,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,0,0,0,0,0,0,0,
+58,29,20,15,11, 9,8,7,6,5,5,4,4,4,3,3,3,3,3,2,2,2,2,2,2,2,2,2,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,0,0,0,0,0,0,
+59,30,20,15,12,10,8,7,6,5,5,4,4,4,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,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,0,0,0,0,0,
+60,30,21,15,12,10,8,7,6,6,5,5,4,4,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,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,0,0,0,0,
+61,31,21,15,12,10,8,7,6,6,5,5,4,4,4,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,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,0,0,0,
+62,31,22,16,12,10,9,7,6,6,5,5,4,4,4,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,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,0,0,
+63,32,22,16,13,10,9,7,7,6,5,5,4,4,4,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,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,0,
+64,32,22,16,13,10,9,8,7,6,5,5,4,4,4,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,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
+};
+#else
+#error No table for provided NBITS
+#endif
+
+static const unsigned char *tabp = tab - (1 << (NBITS - 1) << NBITS);
+
+static inline mp_double_limb_t
+div1 (mp_limb_t n0, mp_limb_t d0)
+{
+  int ncnt;
+  size_t nbi, dbi;
+  mp_limb_t q0;
+  mp_limb_t r0;
+  mp_limb_t mask;
+  mp_double_limb_t res;
+
+  ASSERT (n0 >= d0);		/* Actually only msb position is critical. */
+
+  count_leading_zeros (ncnt, n0);
+  nbi = n0 << ncnt >> (GMP_LIMB_BITS - NBITS);
+  dbi = d0 << ncnt >> (GMP_LIMB_BITS - NBITS);
+
+  q0 = tabp[(nbi << NBITS) + dbi];
+  r0 = n0 - q0 * d0;
+  mask = -(mp_limb_t) (r0 >= d0);
+  q0 -= mask;
+  r0 -= d0 & mask;
+
+  if (UNLIKELY (r0 >= d0))
+    {
+      q0 = n0 / d0;
+      r0 = n0 - q0 * d0;
+    }
+
+  res.d1 = q0;
+  res.d0 = r0;
+  return res;
+}
+
+#elif HGCD2_DIV1_METHOD == 5
+
+/* Table inverses of divisors.  We don't bother with suppressing the msb from
+   the tables.  We index with the NBITS most significant divisor bits,
+   including the always-set highest bit, but use addressing trickery via tabp
+   to suppress it.
+
+   Possible improvements:
+
+   * Do first multiply using 32-bit operations on 64-bit computers.  At least
+     on most Arm64 cores, that uses 3 times less resources.  It also saves on
+     many x86-64 processors.
+*/
+
+#ifndef NBITS
+#define NBITS 7
+#endif
+
+#if NBITS == 5
+/* This needs full division about 1.63% of the time. */
+static const unsigned char tab[16] = {
+ 63, 59, 55, 52, 50, 47, 45, 43, 41, 39, 38, 36, 35, 34, 33, 32
+};
+static const unsigned char *tabp = tab - (1 << (NBITS - 1));
+#elif NBITS == 6
+/* This needs full division about 0.93% of the time. */
+static const unsigned char tab[32] = {
+127,123,119,116,112,109,106,104,101, 98, 96, 94, 92, 90, 88, 86,
+ 84, 82, 80, 79, 77, 76, 74, 73, 72, 70, 69, 68, 67, 66, 65, 64
+};
+static const unsigned char *tabp = tab - (1 << (NBITS - 1));
+#elif NBITS == 7
+/* This needs full division about 0.49% of the time. */
+static const unsigned char tab[64] = {
+255,251,247,243,239,236,233,229,226,223,220,217,214,211,209,206,
+203,201,198,196,194,191,189,187,185,183,181,179,177,175,173,171,
+169,167,166,164,162,161,159,158,156,155,153,152,150,149,147,146,
+145,143,142,141,140,139,137,136,135,134,133,132,131,130,129,128
+};
+static const unsigned char *tabp = tab - (1 << (NBITS - 1));
+#elif NBITS == 8
+/* This needs full division about 0.26% of the time. */
+static const unsigned short tab[128] = {
+511,507,503,499,495,491,488,484,480,477,473,470,467,463,460,457,
+454,450,447,444,441,438,435,433,430,427,424,421,419,416,413,411,
+408,406,403,401,398,396,393,391,389,386,384,382,380,377,375,373,
+371,369,367,365,363,361,359,357,355,353,351,349,347,345,343,342,
+340,338,336,335,333,331,329,328,326,325,323,321,320,318,317,315,
+314,312,311,309,308,306,305,303,302,301,299,298,296,295,294,292,
+291,290,288,287,286,285,283,282,281,280,279,277,276,275,274,273,
+272,270,269,268,267,266,265,264,263,262,261,260,259,258,257,256
+};
+static const unsigned short *tabp = tab - (1 << (NBITS - 1));
+#else
+#error No table for provided NBITS
+#endif
+
+static inline mp_double_limb_t
+div1 (mp_limb_t n0, mp_limb_t d0)
+{
+  int ncnt, dcnt;
+  size_t dbi;
+  mp_limb_t inv;
+  mp_limb_t q0;
+  mp_limb_t r0;
+  mp_limb_t mask;
+  mp_double_limb_t res;
+
+  count_leading_zeros (ncnt, n0);
+  count_leading_zeros (dcnt, d0);
+
+  dbi = d0 << dcnt >> (GMP_LIMB_BITS - NBITS);
+  inv = tabp[dbi];
+  q0 = ((n0 << ncnt) >> (NBITS + 1)) * inv >> (GMP_LIMB_BITS - 1 + ncnt - dcnt);
+  r0 = n0 - q0 * d0;
+  mask = -(mp_limb_t) (r0 >= d0);
+  q0 -= mask;
+  r0 -= d0 & mask;
+
+  if (UNLIKELY (r0 >= d0))
+    {
+      q0 = n0 / d0;
+      r0 = n0 - q0 * d0;
+    }
+
+  res.d1 = q0;
+  res.d0 = r0;
+  return res;
+}
+
+#else
+#error Unknown HGCD2_DIV1_METHOD
+#endif
+
+#if HAVE_NATIVE_mpn_div_22
+
+#define div2 mpn_div_22
+/* Two-limb division optimized for small quotients.  */
+mp_limb_t div2 (mp_ptr, mp_limb_t, mp_limb_t, mp_limb_t, mp_limb_t);
+
+#elif HGCD2_DIV2_METHOD == 1
+
+static mp_limb_t
+div2 (mp_ptr rp,
+      mp_limb_t n1, mp_limb_t n0,
+      mp_limb_t d1, mp_limb_t d0)
+{
+  mp_double_limb_t rq = div1 (n1, d1);
+  if (UNLIKELY (rq.d1 > d1))
+    {
+      mp_limb_t n2, q, t1, t0;
+      int c;
+
+      /* Normalize */
+      count_leading_zeros (c, d1);
+      ASSERT (c > 0);
+
+      n2 = n1 >> (GMP_LIMB_BITS - c);
+      n1 = (n1 << c) | (n0 >> (GMP_LIMB_BITS - c));
+      n0 <<= c;
+      d1 = (d1 << c) | (d0 >> (GMP_LIMB_BITS - c));
+      d0 <<= c;
+
+      udiv_qrnnd (q, n1, n2, n1, d1);
+      umul_ppmm (t1, t0, q, d0);
+      if (t1 > n1 || (t1 == n1 && t0 > n0))
+	{
+	  ASSERT (q > 0);
+	  q--;
+	  sub_ddmmss (t1, t0, t1, t0, d1, d0);
+	}
+      sub_ddmmss (n1, n0, n1, n0, t1, t0);
+
+      /* Undo normalization */
+      rp[0] = (n0 >> c) | (n1 << (GMP_LIMB_BITS - c));
+      rp[1] = n1 >> c;
+
+      return q;
+    }
+  else
+    {
+      mp_limb_t q, t1, t0;
+      n1 = rq.d0;
+      q = rq.d1;
+      umul_ppmm (t1, t0, q, d0);
+      if (UNLIKELY (t1 >= n1) && (t1 > n1 || t0 > n0))
+	{
+	  ASSERT (q > 0);
+	  q--;
+	  sub_ddmmss (t1, t0, t1, t0, d1, d0);
+	}
+      sub_ddmmss (rp[1], rp[0], n1, n0, t1, t0);
+      return q;
+    }
+}
+
+#elif HGCD2_DIV2_METHOD == 2
+
+/* Bit-wise div2. Relies on fast count_leading_zeros. */
+static mp_limb_t
+div2 (mp_ptr rp,
+      mp_limb_t n1, mp_limb_t n0,
+      mp_limb_t d1, mp_limb_t d0)
+{
+  mp_limb_t q = 0;
+  int ncnt;
+  int dcnt;
+
+  count_leading_zeros (ncnt, n1);
+  count_leading_zeros (dcnt, d1);
+  dcnt -= ncnt;
+
+  d1 = (d1 << dcnt) + (d0 >> 1 >> (GMP_LIMB_BITS - 1 - dcnt));
+  d0 <<= dcnt;
+
+  do
+    {
+      mp_limb_t mask;
+      q <<= 1;
+      if (UNLIKELY (n1 == d1))
+	mask = -(n0 >= d0);
+      else
+	mask = -(n1 > d1);
+
+      q -= mask;
+
+      sub_ddmmss (n1, n0, n1, n0, mask & d1, mask & d0);
+
+      d0 = (d1 << (GMP_LIMB_BITS - 1)) | (d0 >> 1);
+      d1 = d1 >> 1;
+    }
+  while (dcnt--);
+
+  rp[0] = n0;
+  rp[1] = n1;
+
+  return q;
+}
+#else
+#error Unknown HGCD2_DIV2_METHOD
+#endif
+
+/* Reduces a,b until |a-b| (almost) fits in one limb + 1 bit. Constructs
+   matrix M. Returns 1 if we make progress, i.e. can perform at least
+   one subtraction. Otherwise returns zero. */
+
+/* FIXME: Possible optimizations:
+
+   The div2 function starts with checking the most significant bit of
+   the numerator. We can maintained normalized operands here, call
+   hgcd with normalized operands only, which should make the code
+   simpler and possibly faster.
+
+   Experiment with table lookups on the most significant bits.
+
+   This function is also a candidate for assembler implementation.
+*/
+int
+mpn_hgcd2 (mp_limb_t ah, mp_limb_t al, mp_limb_t bh, mp_limb_t bl,
+	   struct hgcd_matrix1 *M)
+{
+  mp_limb_t u00, u01, u10, u11;
+
+  if (ah < 2 || bh < 2)
+    return 0;
+
+  if (ah > bh || (ah == bh && al > bl))
+    {
+      sub_ddmmss (ah, al, ah, al, bh, bl);
+      if (ah < 2)
+	return 0;
+
+      u00 = u01 = u11 = 1;
+      u10 = 0;
+    }
+  else
+    {
+      sub_ddmmss (bh, bl, bh, bl, ah, al);
+      if (bh < 2)
+	return 0;
+
+      u00 = u10 = u11 = 1;
+      u01 = 0;
+    }
+
+  if (ah < bh)
+    goto subtract_a;
+
+  for (;;)
+    {
+      ASSERT (ah >= bh);
+      if (ah == bh)
+	goto done;
+
+      if (ah < (CNST_LIMB(1) << (GMP_LIMB_BITS / 2)))
+	{
+	  ah = (ah << (GMP_LIMB_BITS / 2) ) + (al >> (GMP_LIMB_BITS / 2));
+	  bh = (bh << (GMP_LIMB_BITS / 2) ) + (bl >> (GMP_LIMB_BITS / 2));
+
+	  break;
+	}
+
+      /* Subtract a -= q b, and multiply M from the right by (1 q ; 0
+	 1), affecting the second column of M. */
+      ASSERT (ah > bh);
+      sub_ddmmss (ah, al, ah, al, bh, bl);
+
+      if (ah < 2)
+	goto done;
+
+      if (ah <= bh)
+	{
+	  /* Use q = 1 */
+	  u01 += u00;
+	  u11 += u10;
+	}
+      else
+	{
+	  mp_limb_t r[2];
+	  mp_limb_t q = div2 (r, ah, al, bh, bl);
+	  al = r[0]; ah = r[1];
+	  if (ah < 2)
+	    {
+	      /* A is too small, but q is correct. */
+	      u01 += q * u00;
+	      u11 += q * u10;
+	      goto done;
+	    }
+	  q++;
+	  u01 += q * u00;
+	  u11 += q * u10;
+	}
+    subtract_a:
+      ASSERT (bh >= ah);
+      if (ah == bh)
+	goto done;
+
+      if (bh < (CNST_LIMB(1) << (GMP_LIMB_BITS / 2)))
+	{
+	  ah = (ah << (GMP_LIMB_BITS / 2) ) + (al >> (GMP_LIMB_BITS / 2));
+	  bh = (bh << (GMP_LIMB_BITS / 2) ) + (bl >> (GMP_LIMB_BITS / 2));
+
+	  goto subtract_a1;
+	}
+
+      /* Subtract b -= q a, and multiply M from the right by (1 0 ; q
+	 1), affecting the first column of M. */
+      sub_ddmmss (bh, bl, bh, bl, ah, al);
+
+      if (bh < 2)
+	goto done;
+
+      if (bh <= ah)
+	{
+	  /* Use q = 1 */
+	  u00 += u01;
+	  u10 += u11;
+	}
+      else
+	{
+	  mp_limb_t r[2];
+	  mp_limb_t q = div2 (r, bh, bl, ah, al);
+	  bl = r[0]; bh = r[1];
+	  if (bh < 2)
+	    {
+	      /* B is too small, but q is correct. */
+	      u00 += q * u01;
+	      u10 += q * u11;
+	      goto done;
+	    }
+	  q++;
+	  u00 += q * u01;
+	  u10 += q * u11;
+	}
+    }
+
+  /* NOTE: Since we discard the least significant half limb, we don't get a
+     truly maximal M (corresponding to |a - b| < 2^{GMP_LIMB_BITS +1}). */
+  /* Single precision loop */
+  for (;;)
+    {
+      ASSERT (ah >= bh);
+
+      ah -= bh;
+      if (ah < (CNST_LIMB (1) << (GMP_LIMB_BITS / 2 + 1)))
+	break;
+
+      if (ah <= bh)
+	{
+	  /* Use q = 1 */
+	  u01 += u00;
+	  u11 += u10;
+	}
+      else
+	{
+	  mp_double_limb_t rq = div1 (ah, bh);
+	  mp_limb_t q = rq.d1;
+	  ah = rq.d0;
+
+	  if (ah < (CNST_LIMB(1) << (GMP_LIMB_BITS / 2 + 1)))
+	    {
+	      /* A is too small, but q is correct. */
+	      u01 += q * u00;
+	      u11 += q * u10;
+	      break;
+	    }
+	  q++;
+	  u01 += q * u00;
+	  u11 += q * u10;
+	}
+    subtract_a1:
+      ASSERT (bh >= ah);
+
+      bh -= ah;
+      if (bh < (CNST_LIMB (1) << (GMP_LIMB_BITS / 2 + 1)))
+	break;
+
+      if (bh <= ah)
+	{
+	  /* Use q = 1 */
+	  u00 += u01;
+	  u10 += u11;
+	}
+      else
+	{
+	  mp_double_limb_t rq = div1 (bh, ah);
+	  mp_limb_t q = rq.d1;
+	  bh = rq.d0;
+
+	  if (bh < (CNST_LIMB(1) << (GMP_LIMB_BITS / 2 + 1)))
+	    {
+	      /* B is too small, but q is correct. */
+	      u00 += q * u01;
+	      u10 += q * u11;
+	      break;
+	    }
+	  q++;
+	  u00 += q * u01;
+	  u10 += q * u11;
+	}
+    }
+
+ done:
+  M->u[0][0] = u00; M->u[0][1] = u01;
+  M->u[1][0] = u10; M->u[1][1] = u11;
+
+  return 1;
+}
+
+/* Sets (r;b) = (a;b) M, with M = (u00, u01; u10, u11). Vector must
+ * have space for n + 1 limbs. Uses three buffers to avoid a copy*/
+mp_size_t
+mpn_hgcd_mul_matrix1_vector (const struct hgcd_matrix1 *M,
+			     mp_ptr rp, mp_srcptr ap, mp_ptr bp, mp_size_t n)
+{
+  mp_limb_t ah, bh;
+
+  /* Compute (r,b) <-- (u00 a + u10 b, u01 a + u11 b) as
+
+     r  = u00 * a
+     r += u10 * b
+     b *= u11
+     b += u01 * a
+  */
+
+#if HAVE_NATIVE_mpn_addaddmul_1msb0
+  ah = mpn_addaddmul_1msb0 (rp, ap, bp, n, M->u[0][0], M->u[1][0]);
+  bh = mpn_addaddmul_1msb0 (bp, bp, ap, n, M->u[1][1], M->u[0][1]);
+#else
+  ah =     mpn_mul_1 (rp, ap, n, M->u[0][0]);
+  ah += mpn_addmul_1 (rp, bp, n, M->u[1][0]);
+
+  bh =     mpn_mul_1 (bp, bp, n, M->u[1][1]);
+  bh += mpn_addmul_1 (bp, ap, n, M->u[0][1]);
+#endif
+  rp[n] = ah;
+  bp[n] = bh;
+
+  n += (ah | bh) > 0;
+  return n;
+}
diff --git a/third_party/gmp/mpn/generic/hgcd2_jacobi.c b/third_party/gmp/mpn/generic/hgcd2_jacobi.c
new file mode 100644
index 0000000..98e079b
--- /dev/null
+++ b/third_party/gmp/mpn/generic/hgcd2_jacobi.c
@@ -0,0 +1,365 @@
+/* hgcd2_jacobi.c
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 1996, 1998, 2000-2004, 2008, 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#if GMP_NAIL_BITS > 0
+#error Nails not supported.
+#endif
+
+/* FIXME: Duplicated in hgcd2.c. Should move to gmp-impl.h, and
+   possibly be renamed. */
+static inline mp_limb_t
+div1 (mp_ptr rp,
+      mp_limb_t n0,
+      mp_limb_t d0)
+{
+  mp_limb_t q = 0;
+
+  if ((mp_limb_signed_t) n0 < 0)
+    {
+      int cnt;
+      for (cnt = 1; (mp_limb_signed_t) d0 >= 0; cnt++)
+	{
+	  d0 = d0 << 1;
+	}
+
+      q = 0;
+      while (cnt)
+	{
+	  q <<= 1;
+	  if (n0 >= d0)
+	    {
+	      n0 = n0 - d0;
+	      q |= 1;
+	    }
+	  d0 = d0 >> 1;
+	  cnt--;
+	}
+    }
+  else
+    {
+      int cnt;
+      for (cnt = 0; n0 >= d0; cnt++)
+	{
+	  d0 = d0 << 1;
+	}
+
+      q = 0;
+      while (cnt)
+	{
+	  d0 = d0 >> 1;
+	  q <<= 1;
+	  if (n0 >= d0)
+	    {
+	      n0 = n0 - d0;
+	      q |= 1;
+	    }
+	  cnt--;
+	}
+    }
+  *rp = n0;
+  return q;
+}
+
+/* Two-limb division optimized for small quotients.  */
+static inline mp_limb_t
+div2 (mp_ptr rp,
+      mp_limb_t nh, mp_limb_t nl,
+      mp_limb_t dh, mp_limb_t dl)
+{
+  mp_limb_t q = 0;
+
+  if ((mp_limb_signed_t) nh < 0)
+    {
+      int cnt;
+      for (cnt = 1; (mp_limb_signed_t) dh >= 0; cnt++)
+	{
+	  dh = (dh << 1) | (dl >> (GMP_LIMB_BITS - 1));
+	  dl = dl << 1;
+	}
+
+      while (cnt)
+	{
+	  q <<= 1;
+	  if (nh > dh || (nh == dh && nl >= dl))
+	    {
+	      sub_ddmmss (nh, nl, nh, nl, dh, dl);
+	      q |= 1;
+	    }
+	  dl = (dh << (GMP_LIMB_BITS - 1)) | (dl >> 1);
+	  dh = dh >> 1;
+	  cnt--;
+	}
+    }
+  else
+    {
+      int cnt;
+      for (cnt = 0; nh > dh || (nh == dh && nl >= dl); cnt++)
+	{
+	  dh = (dh << 1) | (dl >> (GMP_LIMB_BITS - 1));
+	  dl = dl << 1;
+	}
+
+      while (cnt)
+	{
+	  dl = (dh << (GMP_LIMB_BITS - 1)) | (dl >> 1);
+	  dh = dh >> 1;
+	  q <<= 1;
+	  if (nh > dh || (nh == dh && nl >= dl))
+	    {
+	      sub_ddmmss (nh, nl, nh, nl, dh, dl);
+	      q |= 1;
+	    }
+	  cnt--;
+	}
+    }
+
+  rp[0] = nl;
+  rp[1] = nh;
+
+  return q;
+}
+
+int
+mpn_hgcd2_jacobi (mp_limb_t ah, mp_limb_t al, mp_limb_t bh, mp_limb_t bl,
+		  struct hgcd_matrix1 *M, unsigned *bitsp)
+{
+  mp_limb_t u00, u01, u10, u11;
+  unsigned bits = *bitsp;
+
+  if (ah < 2 || bh < 2)
+    return 0;
+
+  if (ah > bh || (ah == bh && al > bl))
+    {
+      sub_ddmmss (ah, al, ah, al, bh, bl);
+      if (ah < 2)
+	return 0;
+
+      u00 = u01 = u11 = 1;
+      u10 = 0;
+      bits = mpn_jacobi_update (bits, 1, 1);
+    }
+  else
+    {
+      sub_ddmmss (bh, bl, bh, bl, ah, al);
+      if (bh < 2)
+	return 0;
+
+      u00 = u10 = u11 = 1;
+      u01 = 0;
+      bits = mpn_jacobi_update (bits, 0, 1);
+    }
+
+  if (ah < bh)
+    goto subtract_a;
+
+  for (;;)
+    {
+      ASSERT (ah >= bh);
+      if (ah == bh)
+	goto done;
+
+      if (ah < (CNST_LIMB(1) << (GMP_LIMB_BITS / 2)))
+	{
+	  ah = (ah << (GMP_LIMB_BITS / 2) ) + (al >> (GMP_LIMB_BITS / 2));
+	  bh = (bh << (GMP_LIMB_BITS / 2) ) + (bl >> (GMP_LIMB_BITS / 2));
+
+	  break;
+	}
+
+      /* Subtract a -= q b, and multiply M from the right by (1 q ; 0
+	 1), affecting the second column of M. */
+      ASSERT (ah > bh);
+      sub_ddmmss (ah, al, ah, al, bh, bl);
+
+      if (ah < 2)
+	goto done;
+
+      if (ah <= bh)
+	{
+	  /* Use q = 1 */
+	  u01 += u00;
+	  u11 += u10;
+	  bits = mpn_jacobi_update (bits, 1, 1);
+	}
+      else
+	{
+	  mp_limb_t r[2];
+	  mp_limb_t q = div2 (r, ah, al, bh, bl);
+	  al = r[0]; ah = r[1];
+	  if (ah < 2)
+	    {
+	      /* A is too small, but q is correct. */
+	      u01 += q * u00;
+	      u11 += q * u10;
+	      bits = mpn_jacobi_update (bits, 1, q & 3);
+	      goto done;
+	    }
+	  q++;
+	  u01 += q * u00;
+	  u11 += q * u10;
+	  bits = mpn_jacobi_update (bits, 1, q & 3);
+	}
+    subtract_a:
+      ASSERT (bh >= ah);
+      if (ah == bh)
+	goto done;
+
+      if (bh < (CNST_LIMB(1) << (GMP_LIMB_BITS / 2)))
+	{
+	  ah = (ah << (GMP_LIMB_BITS / 2) ) + (al >> (GMP_LIMB_BITS / 2));
+	  bh = (bh << (GMP_LIMB_BITS / 2) ) + (bl >> (GMP_LIMB_BITS / 2));
+
+	  goto subtract_a1;
+	}
+
+      /* Subtract b -= q a, and multiply M from the right by (1 0 ; q
+	 1), affecting the first column of M. */
+      sub_ddmmss (bh, bl, bh, bl, ah, al);
+
+      if (bh < 2)
+	goto done;
+
+      if (bh <= ah)
+	{
+	  /* Use q = 1 */
+	  u00 += u01;
+	  u10 += u11;
+	  bits = mpn_jacobi_update (bits, 0, 1);
+	}
+      else
+	{
+	  mp_limb_t r[2];
+	  mp_limb_t q = div2 (r, bh, bl, ah, al);
+	  bl = r[0]; bh = r[1];
+	  if (bh < 2)
+	    {
+	      /* B is too small, but q is correct. */
+	      u00 += q * u01;
+	      u10 += q * u11;
+	      bits = mpn_jacobi_update (bits, 0, q & 3);
+	      goto done;
+	    }
+	  q++;
+	  u00 += q * u01;
+	  u10 += q * u11;
+	  bits = mpn_jacobi_update (bits, 0, q & 3);
+	}
+    }
+
+  /* NOTE: Since we discard the least significant half limb, we don't
+     get a truly maximal M (corresponding to |a - b| <
+     2^{GMP_LIMB_BITS +1}). */
+  /* Single precision loop */
+  for (;;)
+    {
+      ASSERT (ah >= bh);
+      if (ah == bh)
+	break;
+
+      ah -= bh;
+      if (ah < (CNST_LIMB (1) << (GMP_LIMB_BITS / 2 + 1)))
+	break;
+
+      if (ah <= bh)
+	{
+	  /* Use q = 1 */
+	  u01 += u00;
+	  u11 += u10;
+	  bits = mpn_jacobi_update (bits, 1, 1);
+	}
+      else
+	{
+	  mp_limb_t r;
+	  mp_limb_t q = div1 (&r, ah, bh);
+	  ah = r;
+	  if (ah < (CNST_LIMB(1) << (GMP_LIMB_BITS / 2 + 1)))
+	    {
+	      /* A is too small, but q is correct. */
+	      u01 += q * u00;
+	      u11 += q * u10;
+	      bits = mpn_jacobi_update (bits, 1, q & 3);
+	      break;
+	    }
+	  q++;
+	  u01 += q * u00;
+	  u11 += q * u10;
+	  bits = mpn_jacobi_update (bits, 1, q & 3);
+	}
+    subtract_a1:
+      ASSERT (bh >= ah);
+      if (ah == bh)
+	break;
+
+      bh -= ah;
+      if (bh < (CNST_LIMB (1) << (GMP_LIMB_BITS / 2 + 1)))
+	break;
+
+      if (bh <= ah)
+	{
+	  /* Use q = 1 */
+	  u00 += u01;
+	  u10 += u11;
+	  bits = mpn_jacobi_update (bits, 0, 1);
+	}
+      else
+	{
+	  mp_limb_t r;
+	  mp_limb_t q = div1 (&r, bh, ah);
+	  bh = r;
+	  if (bh < (CNST_LIMB(1) << (GMP_LIMB_BITS / 2 + 1)))
+	    {
+	      /* B is too small, but q is correct. */
+	      u00 += q * u01;
+	      u10 += q * u11;
+	      bits = mpn_jacobi_update (bits, 0, q & 3);
+	      break;
+	    }
+	  q++;
+	  u00 += q * u01;
+	  u10 += q * u11;
+	  bits = mpn_jacobi_update (bits, 0, q & 3);
+	}
+    }
+
+ done:
+  M->u[0][0] = u00; M->u[0][1] = u01;
+  M->u[1][0] = u10; M->u[1][1] = u11;
+  *bitsp = bits;
+
+  return 1;
+}
diff --git a/third_party/gmp/mpn/generic/hgcd_appr.c b/third_party/gmp/mpn/generic/hgcd_appr.c
new file mode 100644
index 0000000..bb01738
--- /dev/null
+++ b/third_party/gmp/mpn/generic/hgcd_appr.c
@@ -0,0 +1,267 @@
+/* hgcd_appr.c.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2011, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/* Identical to mpn_hgcd_itch. FIXME: Do we really need to add
+   HGCD_THRESHOLD at the end? */
+mp_size_t
+mpn_hgcd_appr_itch (mp_size_t n)
+{
+  if (BELOW_THRESHOLD (n, HGCD_APPR_THRESHOLD))
+    return n;
+  else
+    {
+      unsigned k;
+      int count;
+      mp_size_t nscaled;
+
+      /* Get the recursion depth. */
+      nscaled = (n - 1) / (HGCD_APPR_THRESHOLD - 1);
+      count_leading_zeros (count, nscaled);
+      k = GMP_LIMB_BITS - count;
+
+      return 20 * ((n+3) / 4) + 22 * k + HGCD_THRESHOLD;
+    }
+}
+
+/* Destroys inputs. */
+int
+mpn_hgcd_appr (mp_ptr ap, mp_ptr bp, mp_size_t n,
+	       struct hgcd_matrix *M, mp_ptr tp)
+{
+  mp_size_t s;
+  int success = 0;
+
+  ASSERT (n > 0);
+
+  ASSERT ((ap[n-1] | bp[n-1]) != 0);
+
+  if (n <= 2)
+    /* Implies s = n. A fairly uninteresting case but exercised by the
+       random inputs of the testsuite. */
+    return 0;
+
+  ASSERT ((n+1)/2 - 1 < M->alloc);
+
+  /* We aim for reduction of to GMP_NUMB_BITS * s bits. But each time
+     we discard some of the least significant limbs, we must keep one
+     additional bit to account for the truncation error. We maintain
+     the GMP_NUMB_BITS * s - extra_bits as the current target size. */
+
+  s = n/2 + 1;
+  if (BELOW_THRESHOLD (n, HGCD_APPR_THRESHOLD))
+    {
+      unsigned extra_bits = 0;
+
+      while (n > 2)
+	{
+	  mp_size_t nn;
+
+	  ASSERT (n > s);
+	  ASSERT (n <= 2*s);
+
+	  nn = mpn_hgcd_step (n, ap, bp, s, M, tp);
+	  if (!nn)
+	    break;
+
+	  n = nn;
+	  success = 1;
+
+	  /* We can truncate and discard the lower p bits whenever nbits <=
+	     2*sbits - p. To account for the truncation error, we must
+	     adjust
+
+	     sbits <-- sbits + 1 - p,
+
+	     rather than just sbits <-- sbits - p. This adjustment makes
+	     the produced matrix slightly smaller than it could be. */
+
+	  if (GMP_NUMB_BITS * (n + 1) + 2 * extra_bits <= 2*GMP_NUMB_BITS * s)
+	    {
+	      mp_size_t p = (GMP_NUMB_BITS * (2*s - n) - 2*extra_bits) / GMP_NUMB_BITS;
+
+	      if (extra_bits == 0)
+		{
+		  /* We cross a limb boundary and bump s. We can't do that
+		     if the result is that it makes makes min(U, V)
+		     smaller than 2^{GMP_NUMB_BITS} s. */
+		  if (s + 1 == n
+		      || mpn_zero_p (ap + s + 1, n - s - 1)
+		      || mpn_zero_p (bp + s + 1, n - s - 1))
+		    continue;
+
+		  extra_bits = GMP_NUMB_BITS - 1;
+		  s++;
+		}
+	      else
+		{
+		  extra_bits--;
+		}
+
+	      /* Drop the p least significant limbs */
+	      ap += p; bp += p; n -= p; s -= p;
+	    }
+	}
+
+      ASSERT (s > 0);
+
+      if (extra_bits > 0)
+	{
+	  /* We can get here only of we have dropped at least one of the least
+	     significant bits, so we can decrement ap and bp. We can then shift
+	     left extra bits using mpn_rshift. */
+	  /* NOTE: In the unlikely case that n is large, it would be preferable
+	     to do an initial subdiv step to reduce the size before shifting,
+	     but that would mean duplicating mpn_gcd_subdiv_step with a bit
+	     count rather than a limb count. */
+	  ap--; bp--;
+	  ap[0] = mpn_rshift (ap+1, ap+1, n, GMP_NUMB_BITS - extra_bits);
+	  bp[0] = mpn_rshift (bp+1, bp+1, n, GMP_NUMB_BITS - extra_bits);
+	  n += (ap[n] | bp[n]) > 0;
+
+	  ASSERT (success);
+
+	  while (n > 2)
+	    {
+	      mp_size_t nn;
+
+	      ASSERT (n > s);
+	      ASSERT (n <= 2*s);
+
+	      nn = mpn_hgcd_step (n, ap, bp, s, M, tp);
+
+	      if (!nn)
+		return 1;
+
+	      n = nn;
+	    }
+	}
+
+      if (n == 2)
+	{
+	  struct hgcd_matrix1 M1;
+	  ASSERT (s == 1);
+
+	  if (mpn_hgcd2 (ap[1], ap[0], bp[1], bp[0], &M1))
+	    {
+	      /* Multiply M <- M * M1 */
+	      mpn_hgcd_matrix_mul_1 (M, &M1, tp);
+	      success = 1;
+	    }
+	}
+      return success;
+    }
+  else
+    {
+      mp_size_t n2 = (3*n)/4 + 1;
+      mp_size_t p = n/2;
+      mp_size_t nn;
+
+      nn = mpn_hgcd_reduce (M, ap, bp, n, p, tp);
+      if (nn)
+	{
+	  n = nn;
+	  /* FIXME: Discard some of the low limbs immediately? */
+	  success = 1;
+	}
+
+      while (n > n2)
+	{
+	  mp_size_t nn;
+
+	  /* Needs n + 1 storage */
+	  nn = mpn_hgcd_step (n, ap, bp, s, M, tp);
+	  if (!nn)
+	    return success;
+
+	  n = nn;
+	  success = 1;
+	}
+      if (n > s + 2)
+	{
+	  struct hgcd_matrix M1;
+	  mp_size_t scratch;
+
+	  p = 2*s - n + 1;
+	  scratch = MPN_HGCD_MATRIX_INIT_ITCH (n-p);
+
+	  mpn_hgcd_matrix_init(&M1, n - p, tp);
+	  if (mpn_hgcd_appr (ap + p, bp + p, n - p, &M1, tp + scratch))
+	    {
+	      /* We always have max(M) > 2^{-(GMP_NUMB_BITS + 1)} max(M1) */
+	      ASSERT (M->n + 2 >= M1.n);
+
+	      /* Furthermore, assume M ends with a quotient (1, q; 0, 1),
+		 then either q or q + 1 is a correct quotient, and M1 will
+		 start with either (1, 0; 1, 1) or (2, 1; 1, 1). This
+		 rules out the case that the size of M * M1 is much
+		 smaller than the expected M->n + M1->n. */
+
+	      ASSERT (M->n + M1.n < M->alloc);
+
+	      /* We need a bound for of M->n + M1.n. Let n be the original
+		 input size. Then
+
+		 ceil(n/2) - 1 >= size of product >= M.n + M1.n - 2
+
+		 and it follows that
+
+		 M.n + M1.n <= ceil(n/2) + 1
+
+		 Then 3*(M.n + M1.n) + 5 <= 3 * ceil(n/2) + 8 is the
+		 amount of needed scratch space. */
+	      mpn_hgcd_matrix_mul (M, &M1, tp + scratch);
+	      return 1;
+	    }
+	}
+
+      for(;;)
+	{
+	  mp_size_t nn;
+
+	  ASSERT (n > s);
+	  ASSERT (n <= 2*s);
+
+	  nn = mpn_hgcd_step (n, ap, bp, s, M, tp);
+
+	  if (!nn)
+	    return success;
+
+	  n = nn;
+	  success = 1;
+	}
+    }
+}
diff --git a/third_party/gmp/mpn/generic/hgcd_jacobi.c b/third_party/gmp/mpn/generic/hgcd_jacobi.c
new file mode 100644
index 0000000..24014ce
--- /dev/null
+++ b/third_party/gmp/mpn/generic/hgcd_jacobi.c
@@ -0,0 +1,243 @@
+/* hgcd_jacobi.c.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2003-2005, 2008, 2011, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/* This file is almost a copy of hgcd.c, with some added calls to
+   mpn_jacobi_update */
+
+struct hgcd_jacobi_ctx
+{
+  struct hgcd_matrix *M;
+  unsigned *bitsp;
+};
+
+static void
+hgcd_jacobi_hook (void *p, mp_srcptr gp, mp_size_t gn,
+		  mp_srcptr qp, mp_size_t qn, int d)
+{
+  ASSERT (!gp);
+  ASSERT (d >= 0);
+
+  MPN_NORMALIZE (qp, qn);
+  if (qn > 0)
+    {
+      struct hgcd_jacobi_ctx *ctx = (struct hgcd_jacobi_ctx *) p;
+      /* NOTES: This is a bit ugly. A tp area is passed to
+	 gcd_subdiv_step, which stores q at the start of that area. We
+	 now use the rest. */
+      mp_ptr tp = (mp_ptr) qp + qn;
+
+      mpn_hgcd_matrix_update_q (ctx->M, qp, qn, d, tp);
+      *ctx->bitsp = mpn_jacobi_update (*ctx->bitsp, d, qp[0] & 3);
+    }
+}
+
+/* Perform a few steps, using some of mpn_hgcd2, subtraction and
+   division. Reduces the size by almost one limb or more, but never
+   below the given size s. Return new size for a and b, or 0 if no
+   more steps are possible.
+
+   If hgcd2 succeeds, needs temporary space for hgcd_matrix_mul_1, M->n
+   limbs, and hgcd_mul_matrix1_inverse_vector, n limbs. If hgcd2
+   fails, needs space for the quotient, qn <= n - s + 1 limbs, for and
+   hgcd_matrix_update_q, qn + (size of the appropriate column of M) <=
+   resulting size of M.
+
+   If N is the input size to the calling hgcd, then s = floor(N/2) +
+   1, M->n < N, qn + matrix size <= n - s + 1 + n - s = 2 (n - s) + 1
+   < N, so N is sufficient.
+*/
+
+static mp_size_t
+hgcd_jacobi_step (mp_size_t n, mp_ptr ap, mp_ptr bp, mp_size_t s,
+		  struct hgcd_matrix *M, unsigned *bitsp, mp_ptr tp)
+{
+  struct hgcd_matrix1 M1;
+  mp_limb_t mask;
+  mp_limb_t ah, al, bh, bl;
+
+  ASSERT (n > s);
+
+  mask = ap[n-1] | bp[n-1];
+  ASSERT (mask > 0);
+
+  if (n == s + 1)
+    {
+      if (mask < 4)
+	goto subtract;
+
+      ah = ap[n-1]; al = ap[n-2];
+      bh = bp[n-1]; bl = bp[n-2];
+    }
+  else if (mask & GMP_NUMB_HIGHBIT)
+    {
+      ah = ap[n-1]; al = ap[n-2];
+      bh = bp[n-1]; bl = bp[n-2];
+    }
+  else
+    {
+      int shift;
+
+      count_leading_zeros (shift, mask);
+      ah = MPN_EXTRACT_NUMB (shift, ap[n-1], ap[n-2]);
+      al = MPN_EXTRACT_NUMB (shift, ap[n-2], ap[n-3]);
+      bh = MPN_EXTRACT_NUMB (shift, bp[n-1], bp[n-2]);
+      bl = MPN_EXTRACT_NUMB (shift, bp[n-2], bp[n-3]);
+    }
+
+  /* Try an mpn_hgcd2 step */
+  if (mpn_hgcd2_jacobi (ah, al, bh, bl, &M1, bitsp))
+    {
+      /* Multiply M <- M * M1 */
+      mpn_hgcd_matrix_mul_1 (M, &M1, tp);
+
+      /* Can't swap inputs, so we need to copy. */
+      MPN_COPY (tp, ap, n);
+      /* Multiply M1^{-1} (a;b) */
+      return mpn_matrix22_mul1_inverse_vector (&M1, ap, tp, bp, n);
+    }
+
+ subtract:
+  {
+    struct hgcd_jacobi_ctx ctx;
+    ctx.M = M;
+    ctx.bitsp = bitsp;
+
+    return mpn_gcd_subdiv_step (ap, bp, n, s, hgcd_jacobi_hook, &ctx, tp);
+  }
+}
+
+/* Reduces a,b until |a-b| fits in n/2 + 1 limbs. Constructs matrix M
+   with elements of size at most (n+1)/2 - 1. Returns new size of a,
+   b, or zero if no reduction is possible. */
+
+/* Same scratch requirements as for mpn_hgcd. */
+mp_size_t
+mpn_hgcd_jacobi (mp_ptr ap, mp_ptr bp, mp_size_t n,
+		 struct hgcd_matrix *M, unsigned *bitsp, mp_ptr tp)
+{
+  mp_size_t s = n/2 + 1;
+
+  mp_size_t nn;
+  int success = 0;
+
+  if (n <= s)
+    /* Happens when n <= 2, a fairly uninteresting case but exercised
+       by the random inputs of the testsuite. */
+    return 0;
+
+  ASSERT ((ap[n-1] | bp[n-1]) > 0);
+
+  ASSERT ((n+1)/2 - 1 < M->alloc);
+
+  if (ABOVE_THRESHOLD (n, HGCD_THRESHOLD))
+    {
+      mp_size_t n2 = (3*n)/4 + 1;
+      mp_size_t p = n/2;
+
+      nn = mpn_hgcd_jacobi (ap + p, bp + p, n - p, M, bitsp, tp);
+      if (nn > 0)
+	{
+	  /* Needs 2*(p + M->n) <= 2*(floor(n/2) + ceil(n/2) - 1)
+	     = 2 (n - 1) */
+	  n = mpn_hgcd_matrix_adjust (M, p + nn, ap, bp, p, tp);
+	  success = 1;
+	}
+      while (n > n2)
+	{
+	  /* Needs n + 1 storage */
+	  nn = hgcd_jacobi_step (n, ap, bp, s, M, bitsp, tp);
+	  if (!nn)
+	    return success ? n : 0;
+	  n = nn;
+	  success = 1;
+	}
+
+      if (n > s + 2)
+	{
+	  struct hgcd_matrix M1;
+	  mp_size_t scratch;
+
+	  p = 2*s - n + 1;
+	  scratch = MPN_HGCD_MATRIX_INIT_ITCH (n-p);
+
+	  mpn_hgcd_matrix_init(&M1, n - p, tp);
+	  nn = mpn_hgcd_jacobi (ap + p, bp + p, n - p, &M1, bitsp, tp + scratch);
+	  if (nn > 0)
+	    {
+	      /* We always have max(M) > 2^{-(GMP_NUMB_BITS + 1)} max(M1) */
+	      ASSERT (M->n + 2 >= M1.n);
+
+	      /* Furthermore, assume M ends with a quotient (1, q; 0, 1),
+		 then either q or q + 1 is a correct quotient, and M1 will
+		 start with either (1, 0; 1, 1) or (2, 1; 1, 1). This
+		 rules out the case that the size of M * M1 is much
+		 smaller than the expected M->n + M1->n. */
+
+	      ASSERT (M->n + M1.n < M->alloc);
+
+	      /* Needs 2 (p + M->n) <= 2 (2*s - n2 + 1 + n2 - s - 1)
+		 = 2*s <= 2*(floor(n/2) + 1) <= n + 2. */
+	      n = mpn_hgcd_matrix_adjust (&M1, p + nn, ap, bp, p, tp + scratch);
+
+	      /* We need a bound for of M->n + M1.n. Let n be the original
+		 input size. Then
+
+		 ceil(n/2) - 1 >= size of product >= M.n + M1.n - 2
+
+		 and it follows that
+
+		 M.n + M1.n <= ceil(n/2) + 1
+
+		 Then 3*(M.n + M1.n) + 5 <= 3 * ceil(n/2) + 8 is the
+		 amount of needed scratch space. */
+	      mpn_hgcd_matrix_mul (M, &M1, tp + scratch);
+	      success = 1;
+	    }
+	}
+    }
+
+  for (;;)
+    {
+      /* Needs s+3 < n */
+      nn = hgcd_jacobi_step (n, ap, bp, s, M, bitsp, tp);
+      if (!nn)
+	return success ? n : 0;
+
+      n = nn;
+      success = 1;
+    }
+}
diff --git a/third_party/gmp/mpn/generic/hgcd_matrix.c b/third_party/gmp/mpn/generic/hgcd_matrix.c
new file mode 100644
index 0000000..54c795d
--- /dev/null
+++ b/third_party/gmp/mpn/generic/hgcd_matrix.c
@@ -0,0 +1,265 @@
+/* hgcd_matrix.c.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2003-2005, 2008, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/* For input of size n, matrix elements are of size at most ceil(n/2)
+   - 1, but we need two limbs extra. */
+void
+mpn_hgcd_matrix_init (struct hgcd_matrix *M, mp_size_t n, mp_ptr p)
+{
+  mp_size_t s = (n+1)/2 + 1;
+  M->alloc = s;
+  M->n = 1;
+  MPN_ZERO (p, 4 * s);
+  M->p[0][0] = p;
+  M->p[0][1] = p + s;
+  M->p[1][0] = p + 2 * s;
+  M->p[1][1] = p + 3 * s;
+
+  M->p[0][0][0] = M->p[1][1][0] = 1;
+}
+
+/* Update column COL, adding in Q * column (1-COL). Temporary storage:
+ * qn + n <= M->alloc, where n is the size of the largest element in
+ * column 1 - COL. */
+void
+mpn_hgcd_matrix_update_q (struct hgcd_matrix *M, mp_srcptr qp, mp_size_t qn,
+			  unsigned col, mp_ptr tp)
+{
+  ASSERT (col < 2);
+
+  if (qn == 1)
+    {
+      mp_limb_t q = qp[0];
+      mp_limb_t c0, c1;
+
+      c0 = mpn_addmul_1 (M->p[0][col], M->p[0][1-col], M->n, q);
+      c1 = mpn_addmul_1 (M->p[1][col], M->p[1][1-col], M->n, q);
+
+      M->p[0][col][M->n] = c0;
+      M->p[1][col][M->n] = c1;
+
+      M->n += (c0 | c1) != 0;
+    }
+  else
+    {
+      unsigned row;
+
+      /* Carries for the unlikely case that we get both high words
+	 from the multiplication and carries from the addition. */
+      mp_limb_t c[2];
+      mp_size_t n;
+
+      /* The matrix will not necessarily grow in size by qn, so we
+	 need normalization in order not to overflow M. */
+
+      for (n = M->n; n + qn > M->n; n--)
+	{
+	  ASSERT (n > 0);
+	  if (M->p[0][1-col][n-1] > 0 || M->p[1][1-col][n-1] > 0)
+	    break;
+	}
+
+      ASSERT (qn + n <= M->alloc);
+
+      for (row = 0; row < 2; row++)
+	{
+	  if (qn <= n)
+	    mpn_mul (tp, M->p[row][1-col], n, qp, qn);
+	  else
+	    mpn_mul (tp, qp, qn, M->p[row][1-col], n);
+
+	  ASSERT (n + qn >= M->n);
+	  c[row] = mpn_add (M->p[row][col], tp, n + qn, M->p[row][col], M->n);
+	}
+
+      n += qn;
+
+      if (c[0] | c[1])
+	{
+	  M->p[0][col][n] = c[0];
+	  M->p[1][col][n] = c[1];
+	  n++;
+	}
+      else
+	{
+	  n -= (M->p[0][col][n-1] | M->p[1][col][n-1]) == 0;
+	  ASSERT (n >= M->n);
+	}
+      M->n = n;
+    }
+
+  ASSERT (M->n < M->alloc);
+}
+
+/* Multiply M by M1 from the right. Since the M1 elements fit in
+   GMP_NUMB_BITS - 1 bits, M grows by at most one limb. Needs
+   temporary space M->n */
+void
+mpn_hgcd_matrix_mul_1 (struct hgcd_matrix *M, const struct hgcd_matrix1 *M1,
+		       mp_ptr tp)
+{
+  mp_size_t n0, n1;
+
+  /* Could avoid copy by some swapping of pointers. */
+  MPN_COPY (tp, M->p[0][0], M->n);
+  n0 = mpn_hgcd_mul_matrix1_vector (M1, M->p[0][0], tp, M->p[0][1], M->n);
+  MPN_COPY (tp, M->p[1][0], M->n);
+  n1 = mpn_hgcd_mul_matrix1_vector (M1, M->p[1][0], tp, M->p[1][1], M->n);
+
+  /* Depends on zero initialization */
+  M->n = MAX(n0, n1);
+  ASSERT (M->n < M->alloc);
+}
+
+/* Multiply M by M1 from the right. Needs 3*(M->n + M1->n) + 5 limbs
+   of temporary storage (see mpn_matrix22_mul_itch). */
+void
+mpn_hgcd_matrix_mul (struct hgcd_matrix *M, const struct hgcd_matrix *M1,
+		     mp_ptr tp)
+{
+  mp_size_t n;
+
+  /* About the new size of M:s elements. Since M1's diagonal elements
+     are > 0, no element can decrease. The new elements are of size
+     M->n + M1->n, one limb more or less. The computation of the
+     matrix product produces elements of size M->n + M1->n + 1. But
+     the true size, after normalization, may be three limbs smaller.
+
+     The reason that the product has normalized size >= M->n + M1->n -
+     2 is subtle. It depends on the fact that M and M1 can be factored
+     as products of (1,1; 0,1) and (1,0; 1,1), and that we can't have
+     M ending with a large power and M1 starting with a large power of
+     the same matrix. */
+
+  /* FIXME: Strassen multiplication gives only a small speedup. In FFT
+     multiplication range, this function could be sped up quite a lot
+     using invariance. */
+  ASSERT (M->n + M1->n < M->alloc);
+
+  ASSERT ((M->p[0][0][M->n-1] | M->p[0][1][M->n-1]
+	   | M->p[1][0][M->n-1] | M->p[1][1][M->n-1]) > 0);
+
+  ASSERT ((M1->p[0][0][M1->n-1] | M1->p[0][1][M1->n-1]
+	   | M1->p[1][0][M1->n-1] | M1->p[1][1][M1->n-1]) > 0);
+
+  mpn_matrix22_mul (M->p[0][0], M->p[0][1],
+		    M->p[1][0], M->p[1][1], M->n,
+		    M1->p[0][0], M1->p[0][1],
+		    M1->p[1][0], M1->p[1][1], M1->n, tp);
+
+  /* Index of last potentially non-zero limb, size is one greater. */
+  n = M->n + M1->n;
+
+  n -= ((M->p[0][0][n] | M->p[0][1][n] | M->p[1][0][n] | M->p[1][1][n]) == 0);
+  n -= ((M->p[0][0][n] | M->p[0][1][n] | M->p[1][0][n] | M->p[1][1][n]) == 0);
+  n -= ((M->p[0][0][n] | M->p[0][1][n] | M->p[1][0][n] | M->p[1][1][n]) == 0);
+
+  ASSERT ((M->p[0][0][n] | M->p[0][1][n] | M->p[1][0][n] | M->p[1][1][n]) > 0);
+
+  M->n = n + 1;
+}
+
+/* Multiplies the least significant p limbs of (a;b) by M^-1.
+   Temporary space needed: 2 * (p + M->n)*/
+mp_size_t
+mpn_hgcd_matrix_adjust (const struct hgcd_matrix *M,
+			mp_size_t n, mp_ptr ap, mp_ptr bp,
+			mp_size_t p, mp_ptr tp)
+{
+  /* M^-1 (a;b) = (r11, -r01; -r10, r00) (a ; b)
+     = (r11 a - r01 b; - r10 a + r00 b */
+
+  mp_ptr t0 = tp;
+  mp_ptr t1 = tp + p + M->n;
+  mp_limb_t ah, bh;
+  mp_limb_t cy;
+
+  ASSERT (p + M->n  < n);
+
+  /* First compute the two values depending on a, before overwriting a */
+
+  if (M->n >= p)
+    {
+      mpn_mul (t0, M->p[1][1], M->n, ap, p);
+      mpn_mul (t1, M->p[1][0], M->n, ap, p);
+    }
+  else
+    {
+      mpn_mul (t0, ap, p, M->p[1][1], M->n);
+      mpn_mul (t1, ap, p, M->p[1][0], M->n);
+    }
+
+  /* Update a */
+  MPN_COPY (ap, t0, p);
+  ah = mpn_add (ap + p, ap + p, n - p, t0 + p, M->n);
+
+  if (M->n >= p)
+    mpn_mul (t0, M->p[0][1], M->n, bp, p);
+  else
+    mpn_mul (t0, bp, p, M->p[0][1], M->n);
+
+  cy = mpn_sub (ap, ap, n, t0, p + M->n);
+  ASSERT (cy <= ah);
+  ah -= cy;
+
+  /* Update b */
+  if (M->n >= p)
+    mpn_mul (t0, M->p[0][0], M->n, bp, p);
+  else
+    mpn_mul (t0, bp, p, M->p[0][0], M->n);
+
+  MPN_COPY (bp, t0, p);
+  bh = mpn_add (bp + p, bp + p, n - p, t0 + p, M->n);
+  cy = mpn_sub (bp, bp, n, t1, p + M->n);
+  ASSERT (cy <= bh);
+  bh -= cy;
+
+  if (ah > 0 || bh > 0)
+    {
+      ap[n] = ah;
+      bp[n] = bh;
+      n++;
+    }
+  else
+    {
+      /* The subtraction can reduce the size by at most one limb. */
+      if (ap[n-1] == 0 && bp[n-1] == 0)
+	n--;
+    }
+  ASSERT (ap[n-1] > 0 || bp[n-1] > 0);
+  return n;
+}
diff --git a/third_party/gmp/mpn/generic/hgcd_reduce.c b/third_party/gmp/mpn/generic/hgcd_reduce.c
new file mode 100644
index 0000000..3aee77d
--- /dev/null
+++ b/third_party/gmp/mpn/generic/hgcd_reduce.c
@@ -0,0 +1,242 @@
+/* hgcd_reduce.c.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2011, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/* Computes R -= A * B. Result must be non-negative. Normalized down
+   to size an, and resulting size is returned. */
+static mp_size_t
+submul (mp_ptr rp, mp_size_t rn,
+	mp_srcptr ap, mp_size_t an, mp_srcptr bp, mp_size_t bn)
+{
+  mp_ptr tp;
+  TMP_DECL;
+
+  ASSERT (bn > 0);
+  ASSERT (an >= bn);
+  ASSERT (rn >= an);
+  ASSERT (an + bn <= rn + 1);
+
+  TMP_MARK;
+  tp = TMP_ALLOC_LIMBS (an + bn);
+
+  mpn_mul (tp, ap, an, bp, bn);
+  ASSERT ((an + bn <= rn) || (tp[rn] == 0));
+  ASSERT_NOCARRY (mpn_sub (rp, rp, rn, tp, an + bn - (an + bn > rn)));
+  TMP_FREE;
+
+  while (rn > an && (rp[rn-1] == 0))
+    rn--;
+
+  return rn;
+}
+
+/* Computes (a, b)  <--  M^{-1} (a; b) */
+/* FIXME:
+    x Take scratch parameter, and figure out scratch need.
+
+    x Use some fallback for small M->n?
+*/
+static mp_size_t
+hgcd_matrix_apply (const struct hgcd_matrix *M,
+		   mp_ptr ap, mp_ptr bp,
+		   mp_size_t n)
+{
+  mp_size_t an, bn, un, vn, nn;
+  mp_size_t mn[2][2];
+  mp_size_t modn;
+  mp_ptr tp, sp, scratch;
+  mp_limb_t cy;
+  unsigned i, j;
+
+  TMP_DECL;
+
+  ASSERT ( (ap[n-1] | bp[n-1]) > 0);
+
+  an = n;
+  MPN_NORMALIZE (ap, an);
+  bn = n;
+  MPN_NORMALIZE (bp, bn);
+
+  for (i = 0; i < 2; i++)
+    for (j = 0; j < 2; j++)
+      {
+	mp_size_t k;
+	k = M->n;
+	MPN_NORMALIZE (M->p[i][j], k);
+	mn[i][j] = k;
+      }
+
+  ASSERT (mn[0][0] > 0);
+  ASSERT (mn[1][1] > 0);
+  ASSERT ( (mn[0][1] | mn[1][0]) > 0);
+
+  TMP_MARK;
+
+  if (mn[0][1] == 0)
+    {
+      /* A unchanged, M = (1, 0; q, 1) */
+      ASSERT (mn[0][0] == 1);
+      ASSERT (M->p[0][0][0] == 1);
+      ASSERT (mn[1][1] == 1);
+      ASSERT (M->p[1][1][0] == 1);
+
+      /* Put B <-- B - q A */
+      nn = submul (bp, bn, ap, an, M->p[1][0], mn[1][0]);
+    }
+  else if (mn[1][0] == 0)
+    {
+      /* B unchanged, M = (1, q; 0, 1) */
+      ASSERT (mn[0][0] == 1);
+      ASSERT (M->p[0][0][0] == 1);
+      ASSERT (mn[1][1] == 1);
+      ASSERT (M->p[1][1][0] == 1);
+
+      /* Put A  <-- A - q * B */
+      nn = submul (ap, an, bp, bn, M->p[0][1], mn[0][1]);
+    }
+  else
+    {
+      /* A = m00 a + m01 b  ==> a <= A / m00, b <= A / m01.
+	 B = m10 a + m11 b  ==> a <= B / m10, b <= B / m11. */
+      un = MIN (an - mn[0][0], bn - mn[1][0]) + 1;
+      vn = MIN (an - mn[0][1], bn - mn[1][1]) + 1;
+
+      nn = MAX (un, vn);
+      /* In the range of interest, mulmod_bnm1 should always beat mullo. */
+      modn = mpn_mulmod_bnm1_next_size (nn + 1);
+
+      TMP_ALLOC_LIMBS_3 (tp, modn,
+			 sp, modn,
+			 scratch, mpn_mulmod_bnm1_itch (modn, modn, M->n));
+
+      ASSERT (n <= 2*modn);
+
+      if (n > modn)
+	{
+	  cy = mpn_add (ap, ap, modn, ap + modn, n - modn);
+	  MPN_INCR_U (ap, modn, cy);
+
+	  cy = mpn_add (bp, bp, modn, bp + modn, n - modn);
+	  MPN_INCR_U (bp, modn, cy);
+
+	  n = modn;
+	}
+
+      mpn_mulmod_bnm1 (tp, modn, ap, n, M->p[1][1], mn[1][1], scratch);
+      mpn_mulmod_bnm1 (sp, modn, bp, n, M->p[0][1], mn[0][1], scratch);
+
+      /* FIXME: Handle the small n case in some better way. */
+      if (n + mn[1][1] < modn)
+	MPN_ZERO (tp + n + mn[1][1], modn - n - mn[1][1]);
+      if (n + mn[0][1] < modn)
+	MPN_ZERO (sp + n + mn[0][1], modn - n - mn[0][1]);
+
+      cy = mpn_sub_n (tp, tp, sp, modn);
+      MPN_DECR_U (tp, modn, cy);
+
+      ASSERT (mpn_zero_p (tp + nn, modn - nn));
+
+      mpn_mulmod_bnm1 (sp, modn, ap, n, M->p[1][0], mn[1][0], scratch);
+      MPN_COPY (ap, tp, nn);
+      mpn_mulmod_bnm1 (tp, modn, bp, n, M->p[0][0], mn[0][0], scratch);
+
+      if (n + mn[1][0] < modn)
+	MPN_ZERO (sp + n + mn[1][0], modn - n - mn[1][0]);
+      if (n + mn[0][0] < modn)
+	MPN_ZERO (tp + n + mn[0][0], modn - n - mn[0][0]);
+
+      cy = mpn_sub_n (tp, tp, sp, modn);
+      MPN_DECR_U (tp, modn, cy);
+
+      ASSERT (mpn_zero_p (tp + nn, modn - nn));
+      MPN_COPY (bp, tp, nn);
+
+      while ( (ap[nn-1] | bp[nn-1]) == 0)
+	{
+	  nn--;
+	  ASSERT (nn > 0);
+	}
+    }
+  TMP_FREE;
+
+  return nn;
+}
+
+mp_size_t
+mpn_hgcd_reduce_itch (mp_size_t n, mp_size_t p)
+{
+  mp_size_t itch;
+  if (BELOW_THRESHOLD (n, HGCD_REDUCE_THRESHOLD))
+    {
+      itch = mpn_hgcd_itch (n-p);
+
+      /* For arbitrary p, the storage for _adjust is 2*(p + M->n) = 2 *
+	 (p + ceil((n-p)/2) - 1 <= n + p - 1 */
+      if (itch < n + p - 1)
+	itch = n + p - 1;
+    }
+  else
+    {
+      itch = 2*(n-p) + mpn_hgcd_itch (n-p);
+      /* Currently, hgcd_matrix_apply allocates its own storage. */
+    }
+  return itch;
+}
+
+/* FIXME: Document storage need. */
+mp_size_t
+mpn_hgcd_reduce (struct hgcd_matrix *M,
+		 mp_ptr ap, mp_ptr bp, mp_size_t n, mp_size_t p,
+		 mp_ptr tp)
+{
+  mp_size_t nn;
+  if (BELOW_THRESHOLD (n, HGCD_REDUCE_THRESHOLD))
+    {
+      nn = mpn_hgcd (ap + p, bp + p, n - p, M, tp);
+      if (nn > 0)
+	/* Needs 2*(p + M->n) <= 2*(floor(n/2) + ceil(n/2) - 1)
+	   = 2 (n - 1) */
+	return mpn_hgcd_matrix_adjust (M, p + nn, ap, bp, p, tp);
+    }
+  else
+    {
+      MPN_COPY (tp, ap + p, n - p);
+      MPN_COPY (tp + n - p, bp + p, n - p);
+      if (mpn_hgcd_appr (tp, tp + n - p, n - p, M, tp + 2*(n-p)))
+	return hgcd_matrix_apply (M, ap, bp, n);
+    }
+  return 0;
+}
diff --git a/third_party/gmp/mpn/generic/hgcd_step.c b/third_party/gmp/mpn/generic/hgcd_step.c
new file mode 100644
index 0000000..a978a88
--- /dev/null
+++ b/third_party/gmp/mpn/generic/hgcd_step.c
@@ -0,0 +1,127 @@
+/* hgcd_step.c.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2003-2005, 2008, 2011, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+static void
+hgcd_hook (void *p, mp_srcptr gp, mp_size_t gn,
+	   mp_srcptr qp, mp_size_t qn, int d)
+{
+  ASSERT (!gp);
+  ASSERT (d >= 0);
+  ASSERT (d <= 1);
+
+  MPN_NORMALIZE (qp, qn);
+  if (qn > 0)
+    {
+      struct hgcd_matrix *M = (struct hgcd_matrix *) p;
+      /* NOTES: This is a bit ugly. A tp area is passed to
+	 gcd_subdiv_step, which stores q at the start of that area. We
+	 now use the rest. */
+      mp_ptr tp = (mp_ptr) qp + qn;
+      mpn_hgcd_matrix_update_q (M, qp, qn, d, tp);
+    }
+}
+
+/* Perform a few steps, using some of mpn_hgcd2, subtraction and
+   division. Reduces the size by almost one limb or more, but never
+   below the given size s. Return new size for a and b, or 0 if no
+   more steps are possible.
+
+   If hgcd2 succeeds, needs temporary space for hgcd_matrix_mul_1, M->n
+   limbs, and hgcd_mul_matrix1_inverse_vector, n limbs. If hgcd2
+   fails, needs space for the quotient, qn <= n - s limbs, for and
+   hgcd_matrix_update_q, qn + (size of the appropriate column of M) <=
+   (resulting size of M) + 1.
+
+   If N is the input size to the calling hgcd, then s = floor(N/2) +
+   1, M->n < N, qn + product size <= n - s + n - s + 1 = 2 (n - s) + 1
+   <= N.
+*/
+
+mp_size_t
+mpn_hgcd_step (mp_size_t n, mp_ptr ap, mp_ptr bp, mp_size_t s,
+	       struct hgcd_matrix *M, mp_ptr tp)
+{
+  struct hgcd_matrix1 M1;
+  mp_limb_t mask;
+  mp_limb_t ah, al, bh, bl;
+
+  ASSERT (n > s);
+
+  mask = ap[n-1] | bp[n-1];
+  ASSERT (mask > 0);
+
+  if (n == s + 1)
+    {
+      if (mask < 4)
+	goto subtract;
+
+      ah = ap[n-1]; al = ap[n-2];
+      bh = bp[n-1]; bl = bp[n-2];
+    }
+  else if (mask & GMP_NUMB_HIGHBIT)
+    {
+      ah = ap[n-1]; al = ap[n-2];
+      bh = bp[n-1]; bl = bp[n-2];
+    }
+  else
+    {
+      int shift;
+
+      count_leading_zeros (shift, mask);
+      ah = MPN_EXTRACT_NUMB (shift, ap[n-1], ap[n-2]);
+      al = MPN_EXTRACT_NUMB (shift, ap[n-2], ap[n-3]);
+      bh = MPN_EXTRACT_NUMB (shift, bp[n-1], bp[n-2]);
+      bl = MPN_EXTRACT_NUMB (shift, bp[n-2], bp[n-3]);
+    }
+
+  /* Try an mpn_hgcd2 step */
+  if (mpn_hgcd2 (ah, al, bh, bl, &M1))
+    {
+      /* Multiply M <- M * M1 */
+      mpn_hgcd_matrix_mul_1 (M, &M1, tp);
+
+      /* Can't swap inputs, so we need to copy. */
+      MPN_COPY (tp, ap, n);
+      /* Multiply M1^{-1} (a;b) */
+      return mpn_matrix22_mul1_inverse_vector (&M1, ap, tp, bp, n);
+    }
+
+ subtract:
+
+  return mpn_gcd_subdiv_step (ap, bp, n, s, hgcd_hook, M, tp);
+}
diff --git a/third_party/gmp/mpn/generic/invert.c b/third_party/gmp/mpn/generic/invert.c
new file mode 100644
index 0000000..157ff2b
--- /dev/null
+++ b/third_party/gmp/mpn/generic/invert.c
@@ -0,0 +1,86 @@
+/* invert.c -- Compute floor((B^{2n}-1)/U) - B^n.
+
+   Contributed to the GNU project by Marco Bodrato.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright (C) 2007, 2009, 2010, 2012, 2014-2016 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+void
+mpn_invert (mp_ptr ip, mp_srcptr dp, mp_size_t n, mp_ptr scratch)
+{
+  ASSERT (n > 0);
+  ASSERT (dp[n-1] & GMP_NUMB_HIGHBIT);
+  ASSERT (! MPN_OVERLAP_P (ip, n, dp, n));
+  ASSERT (! MPN_OVERLAP_P (ip, n, scratch, mpn_invertappr_itch(n)));
+  ASSERT (! MPN_OVERLAP_P (dp, n, scratch, mpn_invertappr_itch(n)));
+
+  if (n == 1)
+    invert_limb (*ip, *dp);
+  else if (BELOW_THRESHOLD (n, INV_APPR_THRESHOLD))
+    {
+	/* Maximum scratch needed by this branch: 2*n */
+	mp_ptr xp;
+
+	xp = scratch;				/* 2 * n limbs */
+	/* n > 1 here */
+	MPN_FILL (xp, n, GMP_NUMB_MAX);
+	mpn_com (xp + n, dp, n);
+	if (n == 2) {
+	  mpn_divrem_2 (ip, 0, xp, 4, dp);
+	} else {
+	  gmp_pi1_t inv;
+	  invert_pi1 (inv, dp[n-1], dp[n-2]);
+	  /* FIXME: should we use dcpi1_div_q, for big sizes? */
+	  mpn_sbpi1_div_q (ip, xp, 2 * n, dp, n, inv.inv32);
+	}
+    }
+  else { /* Use approximated inverse; correct the result if needed. */
+      mp_limb_t e; /* The possible error in the approximate inverse */
+
+      ASSERT ( mpn_invert_itch (n) >= mpn_invertappr_itch (n) );
+      e = mpn_ni_invertappr (ip, dp, n, scratch);
+
+      if (UNLIKELY (e)) { /* Assume the error can only be "0" (no error) or "1". */
+	/* Code to detect and correct the "off by one" approximation. */
+	mpn_mul_n (scratch, ip, dp, n);
+	e = mpn_add_n (scratch, scratch, dp, n); /* FIXME: we only need e.*/
+	if (LIKELY(e)) /* The high part can not give a carry by itself. */
+	  e = mpn_add_nc (scratch + n, scratch + n, dp, n, e); /* FIXME:e */
+	/* If the value was wrong (no carry), correct it (increment). */
+	e ^= CNST_LIMB (1);
+	MPN_INCR_U (ip, n, e);
+      }
+  }
+}
diff --git a/third_party/gmp/mpn/generic/invertappr.c b/third_party/gmp/mpn/generic/invertappr.c
new file mode 100644
index 0000000..3be5596
--- /dev/null
+++ b/third_party/gmp/mpn/generic/invertappr.c
@@ -0,0 +1,300 @@
+/* mpn_invertappr and helper functions.  Compute I such that
+   floor((B^{2n}-1)/U - 1 <= I + B^n <= floor((B^{2n}-1)/U.
+
+   Contributed to the GNU project by Marco Bodrato.
+
+   The algorithm used here was inspired by ApproximateReciprocal from "Modern
+   Computer Arithmetic", by Richard P. Brent and Paul Zimmermann.  Special
+   thanks to Paul Zimmermann for his very valuable suggestions on all the
+   theoretical aspects during the work on this code.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright (C) 2007, 2009, 2010, 2012, 2015, 2016 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/* FIXME: The iterative version splits the operand in two slightly unbalanced
+   parts, the use of log_2 (or counting the bits) underestimate the maximum
+   number of iterations.  */
+
+#if TUNE_PROGRAM_BUILD
+#define NPOWS \
+ ((sizeof(mp_size_t) > 6 ? 48 : 8*sizeof(mp_size_t)))
+#define MAYBE_dcpi1_divappr   1
+#else
+#define NPOWS \
+ ((sizeof(mp_size_t) > 6 ? 48 : 8*sizeof(mp_size_t)) - LOG2C (INV_NEWTON_THRESHOLD))
+#define MAYBE_dcpi1_divappr \
+  (INV_NEWTON_THRESHOLD < DC_DIVAPPR_Q_THRESHOLD)
+#if (INV_NEWTON_THRESHOLD > INV_MULMOD_BNM1_THRESHOLD) && \
+    (INV_APPR_THRESHOLD > INV_MULMOD_BNM1_THRESHOLD)
+#undef  INV_MULMOD_BNM1_THRESHOLD
+#define INV_MULMOD_BNM1_THRESHOLD 0 /* always when Newton */
+#endif
+#endif
+
+/* All the three functions mpn{,_bc,_ni}_invertappr (ip, dp, n, scratch), take
+   the strictly normalised value {dp,n} (i.e., most significant bit must be set)
+   as an input, and compute {ip,n}: the approximate reciprocal of {dp,n}.
+
+   Let e = mpn*_invertappr (ip, dp, n, scratch) be the returned value; the
+   following conditions are satisfied by the output:
+     0 <= e <= 1;
+     {dp,n}*(B^n+{ip,n}) < B^{2n} <= {dp,n}*(B^n+{ip,n}+1+e) .
+   I.e. e=0 means that the result {ip,n} equals the one given by mpn_invert.
+	e=1 means that the result _may_ be one less than expected.
+
+   The _bc version returns e=1 most of the time.
+   The _ni version should return e=0 most of the time; only about 1% of
+   possible random input should give e=1.
+
+   When the strict result is needed, i.e., e=0 in the relation above:
+     {dp,n}*(B^n+{ip,n}) < B^{2n} <= {dp,n}*(B^n+{ip,n}+1) ;
+   the function mpn_invert (ip, dp, n, scratch) should be used instead.  */
+
+/* Maximum scratch needed by this branch (at xp): 2*n */
+static mp_limb_t
+mpn_bc_invertappr (mp_ptr ip, mp_srcptr dp, mp_size_t n, mp_ptr xp)
+{
+  ASSERT (n > 0);
+  ASSERT (dp[n-1] & GMP_NUMB_HIGHBIT);
+  ASSERT (! MPN_OVERLAP_P (ip, n, dp, n));
+  ASSERT (! MPN_OVERLAP_P (ip, n, xp, mpn_invertappr_itch(n)));
+  ASSERT (! MPN_OVERLAP_P (dp, n, xp, mpn_invertappr_itch(n)));
+
+  /* Compute a base value of r limbs. */
+  if (n == 1)
+    invert_limb (*ip, *dp);
+  else {
+    /* n > 1 here */
+    MPN_FILL (xp, n, GMP_NUMB_MAX);
+    mpn_com (xp + n, dp, n);
+
+    /* Now xp contains B^2n - {dp,n}*B^n - 1 */
+
+    /* FIXME: if mpn_*pi1_divappr_q handles n==2, use it! */
+    if (n == 2) {
+      mpn_divrem_2 (ip, 0, xp, 4, dp);
+    } else {
+      gmp_pi1_t inv;
+      invert_pi1 (inv, dp[n-1], dp[n-2]);
+      if (! MAYBE_dcpi1_divappr
+	  || BELOW_THRESHOLD (n, DC_DIVAPPR_Q_THRESHOLD))
+	mpn_sbpi1_divappr_q (ip, xp, 2 * n, dp, n, inv.inv32);
+      else
+	mpn_dcpi1_divappr_q (ip, xp, 2 * n, dp, n, &inv);
+      MPN_DECR_U(ip, n, CNST_LIMB (1));
+      return 1;
+    }
+  }
+  return 0;
+}
+
+/* mpn_ni_invertappr: computes the approximate reciprocal using Newton's
+   iterations (at least one).
+
+   Inspired by Algorithm "ApproximateReciprocal", published in "Modern Computer
+   Arithmetic" by Richard P. Brent and Paul Zimmermann, algorithm 3.5, page 121
+   in version 0.4 of the book.
+
+   Some adaptations were introduced, to allow product mod B^m-1 and return the
+   value e.
+
+   We introduced a correction in such a way that "the value of
+   B^{n+h}-T computed at step 8 cannot exceed B^n-1" (the book reads
+   "2B^n-1").
+
+   Maximum scratch needed by this branch <= 2*n, but have to fit 3*rn
+   in the scratch, i.e. 3*rn <= 2*n: we require n>4.
+
+   We use a wrapped product modulo B^m-1.  NOTE: is there any normalisation
+   problem for the [0] class?  It shouldn't: we compute 2*|A*X_h - B^{n+h}| <
+   B^m-1.  We may get [0] if and only if we get AX_h = B^{n+h}.  This can
+   happen only if A=B^{n}/2, but this implies X_h = B^{h}*2-1 i.e., AX_h =
+   B^{n+h} - A, then we get into the "negative" branch, where X_h is not
+   incremented (because A < B^n).
+
+   FIXME: the scratch for mulmod_bnm1 does not currently fit in the scratch, it
+   is allocated apart.
+ */
+
+mp_limb_t
+mpn_ni_invertappr (mp_ptr ip, mp_srcptr dp, mp_size_t n, mp_ptr scratch)
+{
+  mp_limb_t cy;
+  mp_size_t rn, mn;
+  mp_size_t sizes[NPOWS], *sizp;
+  mp_ptr tp;
+  TMP_DECL;
+#define xp scratch
+
+  ASSERT (n > 4);
+  ASSERT (dp[n-1] & GMP_NUMB_HIGHBIT);
+  ASSERT (! MPN_OVERLAP_P (ip, n, dp, n));
+  ASSERT (! MPN_OVERLAP_P (ip, n, scratch, mpn_invertappr_itch(n)));
+  ASSERT (! MPN_OVERLAP_P (dp, n, scratch, mpn_invertappr_itch(n)));
+
+  /* Compute the computation precisions from highest to lowest, leaving the
+     base case size in 'rn'.  */
+  sizp = sizes;
+  rn = n;
+  do {
+    *sizp = rn;
+    rn = (rn >> 1) + 1;
+    ++sizp;
+  } while (ABOVE_THRESHOLD (rn, INV_NEWTON_THRESHOLD));
+
+  /* We search the inverse of 0.{dp,n}, we compute it as 1.{ip,n} */
+  dp += n;
+  ip += n;
+
+  /* Compute a base value of rn limbs. */
+  mpn_bc_invertappr (ip - rn, dp - rn, rn, scratch);
+
+  TMP_MARK;
+
+  if (ABOVE_THRESHOLD (n, INV_MULMOD_BNM1_THRESHOLD))
+    {
+      mn = mpn_mulmod_bnm1_next_size (n + 1);
+      tp = TMP_ALLOC_LIMBS (mpn_mulmod_bnm1_itch (mn, n, (n >> 1) + 1));
+    }
+  /* Use Newton's iterations to get the desired precision.*/
+
+  while (1) {
+    n = *--sizp;
+    /*
+      v    n  v
+      +----+--+
+      ^ rn ^
+    */
+
+    /* Compute i_jd . */
+    if (BELOW_THRESHOLD (n, INV_MULMOD_BNM1_THRESHOLD)
+	|| ((mn = mpn_mulmod_bnm1_next_size (n + 1)) > (n + rn))) {
+      /* FIXME: We do only need {xp,n+1}*/
+      mpn_mul (xp, dp - n, n, ip - rn, rn);
+      mpn_add_n (xp + rn, xp + rn, dp - n, n - rn + 1);
+      cy = CNST_LIMB(1); /* Remember we truncated, Mod B^(n+1) */
+      /* We computed (truncated) {xp,n+1} <- 1.{ip,rn} * 0.{dp,n} */
+    } else { /* Use B^mn-1 wraparound */
+      mpn_mulmod_bnm1 (xp, mn, dp - n, n, ip - rn, rn, tp);
+      /* We computed {xp,mn} <- {ip,rn} * {dp,n} mod (B^mn-1) */
+      /* We know that 2*|ip*dp + dp*B^rn - B^{rn+n}| < B^mn-1 */
+      /* Add dp*B^rn mod (B^mn-1) */
+      ASSERT (n >= mn - rn);
+      cy = mpn_add_n (xp + rn, xp + rn, dp - n, mn - rn);
+      cy = mpn_add_nc (xp, xp, dp - (n - (mn - rn)), n - (mn - rn), cy);
+      /* Subtract B^{rn+n}, maybe only compensate the carry*/
+      xp[mn] = CNST_LIMB (1); /* set a limit for DECR_U */
+      MPN_DECR_U (xp + rn + n - mn, 2 * mn + 1 - rn - n, CNST_LIMB (1) - cy);
+      MPN_DECR_U (xp, mn, CNST_LIMB (1) - xp[mn]); /* if DECR_U eroded xp[mn] */
+      cy = CNST_LIMB(0); /* Remember we are working Mod B^mn-1 */
+    }
+
+    if (xp[n] < CNST_LIMB (2)) { /* "positive" residue class */
+      cy = xp[n]; /* 0 <= cy <= 1 here. */
+#if HAVE_NATIVE_mpn_sublsh1_n
+      if (cy++) {
+	if (mpn_cmp (xp, dp - n, n) > 0) {
+	  mp_limb_t chk;
+	  chk = mpn_sublsh1_n (xp, xp, dp - n, n);
+	  ASSERT (chk == xp[n]);
+	  ++ cy;
+	} else
+	  ASSERT_CARRY (mpn_sub_n (xp, xp, dp - n, n));
+      }
+#else /* no mpn_sublsh1_n*/
+      if (cy++ && !mpn_sub_n (xp, xp, dp - n, n)) {
+	ASSERT_CARRY (mpn_sub_n (xp, xp, dp - n, n));
+	++cy;
+      }
+#endif
+      /* 1 <= cy <= 3 here. */
+#if HAVE_NATIVE_mpn_rsblsh1_n
+      if (mpn_cmp (xp, dp - n, n) > 0) {
+	ASSERT_NOCARRY (mpn_rsblsh1_n (xp + n, xp, dp - n, n));
+	++cy;
+      } else
+	ASSERT_NOCARRY (mpn_sub_nc (xp + 2 * n - rn, dp - rn, xp + n - rn, rn, mpn_cmp (xp, dp - n, n - rn) > 0));
+#else /* no mpn_rsblsh1_n*/
+      if (mpn_cmp (xp, dp - n, n) > 0) {
+	ASSERT_NOCARRY (mpn_sub_n (xp, xp, dp - n, n));
+	++cy;
+      }
+      ASSERT_NOCARRY (mpn_sub_nc (xp + 2 * n - rn, dp - rn, xp + n - rn, rn, mpn_cmp (xp, dp - n, n - rn) > 0));
+#endif
+      MPN_DECR_U(ip - rn, rn, cy); /* 1 <= cy <= 4 here. */
+    } else { /* "negative" residue class */
+      ASSERT (xp[n] >= GMP_NUMB_MAX - CNST_LIMB(1));
+      MPN_DECR_U(xp, n + 1, cy);
+      if (xp[n] != GMP_NUMB_MAX) {
+	MPN_INCR_U(ip - rn, rn, CNST_LIMB (1));
+	ASSERT_CARRY (mpn_add_n (xp, xp, dp - n, n));
+      }
+      mpn_com (xp + 2 * n - rn, xp + n - rn, rn);
+    }
+
+    /* Compute x_ju_j. FIXME:We need {xp+rn,rn}, mulhi? */
+    mpn_mul_n (xp, xp + 2 * n - rn, ip - rn, rn);
+    cy = mpn_add_n (xp + rn, xp + rn, xp + 2 * n - rn, 2 * rn - n);
+    cy = mpn_add_nc (ip - n, xp + 3 * rn - n, xp + n + rn, n - rn, cy);
+    MPN_INCR_U (ip - rn, rn, cy);
+    if (sizp == sizes) { /* Get out of the cycle */
+      /* Check for possible carry propagation from below. */
+      cy = xp[3 * rn - n - 1] > GMP_NUMB_MAX - CNST_LIMB (7); /* Be conservative. */
+      /*    cy = mpn_add_1 (xp + rn, xp + rn, 2*rn - n, 4); */
+      break;
+    }
+    rn = n;
+  }
+  TMP_FREE;
+
+  return cy;
+#undef xp
+}
+
+mp_limb_t
+mpn_invertappr (mp_ptr ip, mp_srcptr dp, mp_size_t n, mp_ptr scratch)
+{
+  ASSERT (n > 0);
+  ASSERT (dp[n-1] & GMP_NUMB_HIGHBIT);
+  ASSERT (! MPN_OVERLAP_P (ip, n, dp, n));
+  ASSERT (! MPN_OVERLAP_P (ip, n, scratch, mpn_invertappr_itch(n)));
+  ASSERT (! MPN_OVERLAP_P (dp, n, scratch, mpn_invertappr_itch(n)));
+
+  if (BELOW_THRESHOLD (n, INV_NEWTON_THRESHOLD))
+    return mpn_bc_invertappr (ip, dp, n, scratch);
+  else
+    return mpn_ni_invertappr (ip, dp, n, scratch);
+}
diff --git a/third_party/gmp/mpn/generic/jacbase.c b/third_party/gmp/mpn/generic/jacbase.c
new file mode 100644
index 0000000..735ad7a
--- /dev/null
+++ b/third_party/gmp/mpn/generic/jacbase.c
@@ -0,0 +1,242 @@
+/* mpn_jacobi_base -- limb/limb Jacobi symbol with restricted arguments.
+
+   THIS INTERFACE IS PRELIMINARY AND MIGHT DISAPPEAR OR BE SUBJECT TO
+   INCOMPATIBLE CHANGES IN A FUTURE RELEASE OF GMP.
+
+Copyright 1999-2002, 2010 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* Use the simple loop by default.  The generic count_trailing_zeros is not
+   very fast, and the extra trickery of method 3 has proven to be less use
+   than might have been though.  */
+#ifndef JACOBI_BASE_METHOD
+#define JACOBI_BASE_METHOD  2
+#endif
+
+
+/* Use count_trailing_zeros.  */
+#if JACOBI_BASE_METHOD == 1
+#define PROCESS_TWOS_ANY                                \
+  {                                                     \
+    mp_limb_t  twos;                                    \
+    count_trailing_zeros (twos, a);                     \
+    result_bit1 ^= JACOBI_TWOS_U_BIT1 (twos, b);        \
+    a >>= twos;                                         \
+  }
+#define PROCESS_TWOS_EVEN  PROCESS_TWOS_ANY
+#endif
+
+/* Use a simple loop.  A disadvantage of this is that there's a branch on a
+   50/50 chance of a 0 or 1 low bit.  */
+#if JACOBI_BASE_METHOD == 2
+#define PROCESS_TWOS_EVEN               \
+  {                                     \
+    int  two;                           \
+    two = JACOBI_TWO_U_BIT1 (b);        \
+    do                                  \
+      {                                 \
+	a >>= 1;                        \
+	result_bit1 ^= two;             \
+	ASSERT (a != 0);                \
+      }                                 \
+    while ((a & 1) == 0);               \
+  }
+#define PROCESS_TWOS_ANY        \
+  if ((a & 1) == 0)             \
+    PROCESS_TWOS_EVEN;
+#endif
+
+/* Process one bit arithmetically, then a simple loop.  This cuts the loop
+   condition down to a 25/75 chance, which should branch predict better.
+   The CPU will need a reasonable variable left shift.  */
+#if JACOBI_BASE_METHOD == 3
+#define PROCESS_TWOS_EVEN               \
+  {                                     \
+    int  two, mask, shift;              \
+					\
+    two = JACOBI_TWO_U_BIT1 (b);        \
+    mask = (~a & 2);                    \
+    a >>= 1;                            \
+					\
+    shift = (~a & 1);                   \
+    a >>= shift;                        \
+    result_bit1 ^= two ^ (two & mask);  \
+					\
+    while ((a & 1) == 0)                \
+      {                                 \
+	a >>= 1;                        \
+	result_bit1 ^= two;             \
+	ASSERT (a != 0);                \
+      }                                 \
+  }
+#define PROCESS_TWOS_ANY                \
+  {                                     \
+    int  two, mask, shift;              \
+					\
+    two = JACOBI_TWO_U_BIT1 (b);        \
+    shift = (~a & 1);                   \
+    a >>= shift;                        \
+					\
+    mask = shift << 1;                  \
+    result_bit1 ^= (two & mask);        \
+					\
+    while ((a & 1) == 0)                \
+      {                                 \
+	a >>= 1;                        \
+	result_bit1 ^= two;             \
+	ASSERT (a != 0);                \
+      }                                 \
+  }
+#endif
+
+#if JACOBI_BASE_METHOD < 4
+/* Calculate the value of the Jacobi symbol (a/b) of two mp_limb_t's, but
+   with a restricted range of inputs accepted, namely b>1, b odd.
+
+   The initial result_bit1 is taken as a parameter for the convenience of
+   mpz_kronecker_ui() et al.  The sign changes both here and in those
+   routines accumulate nicely in bit 1, see the JACOBI macros.
+
+   The return value here is the normal +1, 0, or -1.  Note that +1 and -1
+   have bit 1 in the "BIT1" sense, which could be useful if the caller is
+   accumulating it into some extended calculation.
+
+   Duplicating the loop body to avoid the MP_LIMB_T_SWAP(a,b) would be
+   possible, but a couple of tests suggest it's not a significant speedup,
+   and may even be a slowdown, so what's here is good enough for now. */
+
+int
+mpn_jacobi_base (mp_limb_t a, mp_limb_t b, int result_bit1)
+{
+  ASSERT (b & 1);  /* b odd */
+  ASSERT (b != 1);
+
+  if (a == 0)
+    return 0;
+
+  PROCESS_TWOS_ANY;
+  if (a == 1)
+    goto done;
+
+  if (a >= b)
+    goto a_gt_b;
+
+  for (;;)
+    {
+      result_bit1 ^= JACOBI_RECIP_UU_BIT1 (a, b);
+      MP_LIMB_T_SWAP (a, b);
+
+    a_gt_b:
+      do
+	{
+	  /* working on (a/b), a,b odd, a>=b */
+	  ASSERT (a & 1);
+	  ASSERT (b & 1);
+	  ASSERT (a >= b);
+
+	  if ((a -= b) == 0)
+	    return 0;
+
+	  PROCESS_TWOS_EVEN;
+	  if (a == 1)
+	    goto done;
+	}
+      while (a >= b);
+    }
+
+ done:
+  return JACOBI_BIT1_TO_PN (result_bit1);
+}
+#endif
+
+#if JACOBI_BASE_METHOD == 4
+/* Computes (a/b) for odd b > 1 and any a. The initial bit is taken as a
+ * parameter. We have no need for the convention that the sign is in
+ * bit 1, internally we use bit 0. */
+
+/* FIXME: Could try table-based count_trailing_zeros. */
+int
+mpn_jacobi_base (mp_limb_t a, mp_limb_t b, int bit)
+{
+  int c;
+
+  ASSERT (b & 1);
+  ASSERT (b > 1);
+
+  if (a == 0)
+    /* This is the only line which depends on b > 1 */
+    return 0;
+
+  bit >>= 1;
+
+  /* Below, we represent a and b shifted right so that the least
+     significant one bit is implicit. */
+
+  b >>= 1;
+
+  count_trailing_zeros (c, a);
+  bit ^= c & (b ^ (b >> 1));
+
+  /* We may have c==GMP_LIMB_BITS-1, so we can't use a>>c+1. */
+  a >>= c;
+  a >>= 1;
+
+  do
+    {
+      mp_limb_t t = a - b;
+      mp_limb_t bgta = LIMB_HIGHBIT_TO_MASK (t);
+
+      if (t == 0)
+	return 0;
+
+      /* If b > a, invoke reciprocity */
+      bit ^= (bgta & a & b);
+
+      /* b <-- min (a, b) */
+      b += (bgta & t);
+
+      /* a <-- |a - b| */
+      a = (t ^ bgta) - bgta;
+
+      /* Number of trailing zeros is the same no matter if we look at
+       * t or a, but using t gives more parallelism. */
+      count_trailing_zeros (c, t);
+      c ++;
+      /* (2/b) = -1 if b = 3 or 5 mod 8 */
+      bit ^= c & (b ^ (b >> 1));
+      a >>= c;
+    }
+  while (b > 0);
+
+  return 1-2*(bit & 1);
+}
+#endif /* JACOBI_BASE_METHOD == 4 */
diff --git a/third_party/gmp/mpn/generic/jacobi.c b/third_party/gmp/mpn/generic/jacobi.c
new file mode 100644
index 0000000..d98b126
--- /dev/null
+++ b/third_party/gmp/mpn/generic/jacobi.c
@@ -0,0 +1,294 @@
+/* jacobi.c
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 1996, 1998, 2000-2004, 2008, 2010, 2011 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#ifndef JACOBI_DC_THRESHOLD
+#define JACOBI_DC_THRESHOLD GCD_DC_THRESHOLD
+#endif
+
+/* Schönhage's rules:
+ *
+ * Assume r0 = r1 q1 + r2, with r0 odd, and r1 = q2 r2 + r3
+ *
+ * If r1 is odd, then
+ *
+ *   (r1 | r0) = s(r1, r0) (r0 | r1) = s(r1, r0) (r2, r1)
+ *
+ * where s(x,y) = (-1)^{(x-1)(y-1)/4} = (-1)^[x = y = 3 (mod 4)].
+ *
+ * If r1 is even, r2 must be odd. We have
+ *
+ *   (r1 | r0) = (r1 - r0 | r0) = (-1)^(r0-1)/2 (r0 - r1 | r0)
+ *             = (-1)^(r0-1)/2 s(r0, r0 - r1) (r0 | r0 - r1)
+ *             = (-1)^(r0-1)/2 s(r0, r0 - r1) (r1 | r0 - r1)
+ *
+ * Now, if r1 = 0 (mod 4), then the sign factor is +1, and repeating
+ * q1 times gives
+ *
+ *   (r1 | r0) = (r1 | r2) = (r3 | r2)
+ *
+ * On the other hand, if r1 = 2 (mod 4), the sign factor is
+ * (-1)^{(r0-1)/2}, and repeating q1 times gives the exponent
+ *
+ *   (r0-1)/2 + (r0-r1-1)/2 + ... + (r0 - (q1-1) r1)/2
+ *   = q1 (r0-1)/2 + q1 (q1-1)/2
+ *
+ * and we can summarize the even case as
+ *
+ *   (r1 | r0) = t(r1, r0, q1) (r3 | r2)
+ *
+ * where t(x,y,q) = (-1)^{[x = 2 (mod 4)] (q(y-1)/2 + y(q-1)/2)}
+ *
+ * What about termination? The remainder sequence ends with (0|1) = 1
+ * (or (0 | r) = 0 if r != 1). What are the possible cases? If r1 is
+ * odd, r2 may be zero. If r1 is even, then r2 = r0 - q1 r1 is odd and
+ * hence non-zero. We may have r3 = r1 - q2 r2 = 0.
+ *
+ * Examples: (11|15) = - (15|11) = - (4|11)
+ *            (4|11) =    (4| 3) =   (1| 3)
+ *            (1| 3) = (3|1) = (0|1) = 1
+ *
+ *             (2|7) = (2|1) = (0|1) = 1
+ *
+ * Detail:     (2|7) = (2-7|7) = (-1|7)(5|7) = -(7|5) = -(2|5)
+ *             (2|5) = (2-5|5) = (-1|5)(3|5) =  (5|3) =  (2|3)
+ *             (2|3) = (2-3|3) = (-1|3)(1|3) = -(3|1) = -(2|1)
+ *
+ */
+
+/* In principle, the state consists of four variables: e (one bit), a,
+   b (two bits each), d (one bit). Collected factors are (-1)^e. a and
+   b are the least significant bits of the current remainders. d
+   (denominator) is 0 if we're currently subtracting multiplies of a
+   from b, and 1 if we're subtracting b from a.
+
+   e is stored in the least significant bit, while a, b and d are
+   coded as only 13 distinct values in bits 1-4, according to the
+   following table. For rows not mentioning d, the value is either
+   implied, or it doesn't matter. */
+
+#if WANT_ASSERT
+static const struct
+{
+  unsigned char a;
+  unsigned char b;
+} decode_table[13] = {
+  /*  0 */ { 0, 1 },
+  /*  1 */ { 0, 3 },
+  /*  2 */ { 1, 1 },
+  /*  3 */ { 1, 3 },
+  /*  4 */ { 2, 1 },
+  /*  5 */ { 2, 3 },
+  /*  6 */ { 3, 1 },
+  /*  7 */ { 3, 3 }, /* d = 1 */
+  /*  8 */ { 1, 0 },
+  /*  9 */ { 1, 2 },
+  /* 10 */ { 3, 0 },
+  /* 11 */ { 3, 2 },
+  /* 12 */ { 3, 3 }, /* d = 0 */
+};
+#define JACOBI_A(bits) (decode_table[(bits)>>1].a)
+#define JACOBI_B(bits) (decode_table[(bits)>>1].b)
+#endif /* WANT_ASSERT */
+
+const unsigned char jacobi_table[208] = {
+#include "jacobitab.h"
+};
+
+#define BITS_FAIL 31
+
+static void
+jacobi_hook (void *p, mp_srcptr gp, mp_size_t gn,
+	     mp_srcptr qp, mp_size_t qn, int d)
+{
+  unsigned *bitsp = (unsigned *) p;
+
+  if (gp)
+    {
+      ASSERT (gn > 0);
+      if (gn != 1 || gp[0] != 1)
+	{
+	  *bitsp = BITS_FAIL;
+	  return;
+	}
+    }
+
+  if (qp)
+    {
+      ASSERT (qn > 0);
+      ASSERT (d >= 0);
+      *bitsp = mpn_jacobi_update (*bitsp, d, qp[0] & 3);
+    }
+}
+
+#define CHOOSE_P(n) (2*(n) / 3)
+
+int
+mpn_jacobi_n (mp_ptr ap, mp_ptr bp, mp_size_t n, unsigned bits)
+{
+  mp_size_t scratch;
+  mp_size_t matrix_scratch;
+  mp_ptr tp;
+
+  TMP_DECL;
+
+  ASSERT (n > 0);
+  ASSERT ( (ap[n-1] | bp[n-1]) > 0);
+  ASSERT ( (bp[0] | ap[0]) & 1);
+
+  /* FIXME: Check for small sizes first, before setting up temporary
+     storage etc. */
+  scratch = MPN_GCD_SUBDIV_STEP_ITCH(n);
+
+  if (ABOVE_THRESHOLD (n, JACOBI_DC_THRESHOLD))
+    {
+      mp_size_t hgcd_scratch;
+      mp_size_t update_scratch;
+      mp_size_t p = CHOOSE_P (n);
+      mp_size_t dc_scratch;
+
+      matrix_scratch = MPN_HGCD_MATRIX_INIT_ITCH (n - p);
+      hgcd_scratch = mpn_hgcd_itch (n - p);
+      update_scratch = p + n - 1;
+
+      dc_scratch = matrix_scratch + MAX(hgcd_scratch, update_scratch);
+      if (dc_scratch > scratch)
+	scratch = dc_scratch;
+    }
+
+  TMP_MARK;
+  tp = TMP_ALLOC_LIMBS(scratch);
+
+  while (ABOVE_THRESHOLD (n, JACOBI_DC_THRESHOLD))
+    {
+      struct hgcd_matrix M;
+      mp_size_t p = 2*n/3;
+      mp_size_t matrix_scratch = MPN_HGCD_MATRIX_INIT_ITCH (n - p);
+      mp_size_t nn;
+      mpn_hgcd_matrix_init (&M, n - p, tp);
+
+      nn = mpn_hgcd_jacobi (ap + p, bp + p, n - p, &M, &bits,
+			    tp + matrix_scratch);
+      if (nn > 0)
+	{
+	  ASSERT (M.n <= (n - p - 1)/2);
+	  ASSERT (M.n + p <= (p + n - 1) / 2);
+	  /* Temporary storage 2 (p + M->n) <= p + n - 1. */
+	  n = mpn_hgcd_matrix_adjust (&M, p + nn, ap, bp, p, tp + matrix_scratch);
+	}
+      else
+	{
+	  /* Temporary storage n */
+	  n = mpn_gcd_subdiv_step (ap, bp, n, 0, jacobi_hook, &bits, tp);
+	  if (!n)
+	    {
+	      TMP_FREE;
+	      return bits == BITS_FAIL ? 0 : mpn_jacobi_finish (bits);
+	    }
+	}
+    }
+
+  while (n > 2)
+    {
+      struct hgcd_matrix1 M;
+      mp_limb_t ah, al, bh, bl;
+      mp_limb_t mask;
+
+      mask = ap[n-1] | bp[n-1];
+      ASSERT (mask > 0);
+
+      if (mask & GMP_NUMB_HIGHBIT)
+	{
+	  ah = ap[n-1]; al = ap[n-2];
+	  bh = bp[n-1]; bl = bp[n-2];
+	}
+      else
+	{
+	  int shift;
+
+	  count_leading_zeros (shift, mask);
+	  ah = MPN_EXTRACT_NUMB (shift, ap[n-1], ap[n-2]);
+	  al = MPN_EXTRACT_NUMB (shift, ap[n-2], ap[n-3]);
+	  bh = MPN_EXTRACT_NUMB (shift, bp[n-1], bp[n-2]);
+	  bl = MPN_EXTRACT_NUMB (shift, bp[n-2], bp[n-3]);
+	}
+
+      /* Try an mpn_nhgcd2 step */
+      if (mpn_hgcd2_jacobi (ah, al, bh, bl, &M, &bits))
+	{
+	  n = mpn_matrix22_mul1_inverse_vector (&M, tp, ap, bp, n);
+	  MP_PTR_SWAP (ap, tp);
+	}
+      else
+	{
+	  /* mpn_hgcd2 has failed. Then either one of a or b is very
+	     small, or the difference is very small. Perform one
+	     subtraction followed by one division. */
+	  n = mpn_gcd_subdiv_step (ap, bp, n, 0, &jacobi_hook, &bits, tp);
+	  if (!n)
+	    {
+	      TMP_FREE;
+	      return bits == BITS_FAIL ? 0 : mpn_jacobi_finish (bits);
+	    }
+	}
+    }
+
+  if (bits >= 16)
+    MP_PTR_SWAP (ap, bp);
+
+  ASSERT (bp[0] & 1);
+
+  if (n == 1)
+    {
+      mp_limb_t al, bl;
+      al = ap[0];
+      bl = bp[0];
+
+      TMP_FREE;
+      if (bl == 1)
+	return 1 - 2*(bits & 1);
+      else
+	return mpn_jacobi_base (al, bl, bits << 1);
+    }
+
+  else
+    {
+      int res = mpn_jacobi_2 (ap, bp, bits & 1);
+      TMP_FREE;
+      return res;
+    }
+}
diff --git a/third_party/gmp/mpn/generic/jacobi_2.c b/third_party/gmp/mpn/generic/jacobi_2.c
new file mode 100644
index 0000000..028b8a4
--- /dev/null
+++ b/third_party/gmp/mpn/generic/jacobi_2.c
@@ -0,0 +1,351 @@
+/* jacobi_2.c
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 1996, 1998, 2000-2004, 2008, 2010 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#ifndef JACOBI_2_METHOD
+#define JACOBI_2_METHOD 2
+#endif
+
+/* Computes (a / b) where b is odd, and a and b are otherwise arbitrary
+   two-limb numbers. */
+#if JACOBI_2_METHOD == 1
+int
+mpn_jacobi_2 (mp_srcptr ap, mp_srcptr bp, unsigned bit)
+{
+  mp_limb_t ah, al, bh, bl;
+  int c;
+
+  al = ap[0];
+  ah = ap[1];
+  bl = bp[0];
+  bh = bp[1];
+
+  ASSERT (bl & 1);
+
+  bl = ((bh << (GMP_NUMB_BITS - 1)) & GMP_NUMB_MASK) | (bl >> 1);
+  bh >>= 1;
+
+  if ( (bh | bl) == 0)
+    return 1 - 2*(bit & 1);
+
+  if ( (ah | al) == 0)
+    return 0;
+
+  if (al == 0)
+    {
+      al = ah;
+      ah = 0;
+      bit ^= GMP_NUMB_BITS & (bl ^ (bl >> 1));
+    }
+  count_trailing_zeros (c, al);
+  bit ^= c & (bl ^ (bl >> 1));
+
+  c++;
+  if (UNLIKELY (c == GMP_NUMB_BITS))
+    {
+      al = ah;
+      ah = 0;
+    }
+  else
+    {
+      al = ((ah << (GMP_NUMB_BITS - c)) & GMP_NUMB_MASK) | (al >> c);
+      ah >>= c;
+    }
+  while ( (ah | bh) > 0)
+    {
+      mp_limb_t th, tl;
+      mp_limb_t bgta;
+
+      sub_ddmmss (th, tl, ah, al, bh, bl);
+      if ( (tl | th) == 0)
+	return 0;
+
+      bgta = LIMB_HIGHBIT_TO_MASK (th);
+
+      /* If b > a, invoke reciprocity */
+      bit ^= (bgta & al & bl);
+
+      /* b <-- min (a, b) */
+      add_ssaaaa (bh, bl, bh, bl, th & bgta, tl & bgta);
+
+      if ( (bh | bl) == 0)
+	return 1 - 2*(bit & 1);
+
+      /* a <-- |a - b| */
+      al = (bgta ^ tl) - bgta;
+      ah = (bgta ^ th);
+
+      if (UNLIKELY (al == 0))
+	{
+	  /* If b > a, al == 0 implies that we have a carry to
+	     propagate. */
+	  al = ah - bgta;
+	  ah = 0;
+	  bit ^= GMP_NUMB_BITS & (bl ^ (bl >> 1));
+	}
+      count_trailing_zeros (c, al);
+      c++;
+      bit ^= c & (bl ^ (bl >> 1));
+
+      if (UNLIKELY (c == GMP_NUMB_BITS))
+	{
+	  al = ah;
+	  ah = 0;
+	}
+      else
+	{
+	  al = ((ah << (GMP_NUMB_BITS - c)) & GMP_NUMB_MASK) | (al >> c);
+	  ah >>= c;
+	}
+    }
+
+  ASSERT (bl > 0);
+
+  while ( (al | bl) & GMP_LIMB_HIGHBIT)
+    {
+      /* Need an extra comparison to get the mask. */
+      mp_limb_t t = al - bl;
+      mp_limb_t bgta = - (bl > al);
+
+      if (t == 0)
+	return 0;
+
+      /* If b > a, invoke reciprocity */
+      bit ^= (bgta & al & bl);
+
+      /* b <-- min (a, b) */
+      bl += (bgta & t);
+
+      /* a <-- |a - b| */
+      al = (t ^ bgta) - bgta;
+
+      /* Number of trailing zeros is the same no matter if we look at
+       * t or a, but using t gives more parallelism. */
+      count_trailing_zeros (c, t);
+      c ++;
+      /* (2/b) = -1 if b = 3 or 5 mod 8 */
+      bit ^= c & (bl ^ (bl >> 1));
+
+      if (UNLIKELY (c == GMP_NUMB_BITS))
+	return 1 - 2*(bit & 1);
+
+      al >>= c;
+    }
+
+  /* Here we have a little impedance mismatch. Better to inline it? */
+  return mpn_jacobi_base (2*al+1, 2*bl+1, bit << 1);
+}
+#elif JACOBI_2_METHOD == 2
+int
+mpn_jacobi_2 (mp_srcptr ap, mp_srcptr bp, unsigned bit)
+{
+  mp_limb_t ah, al, bh, bl;
+  int c;
+
+  al = ap[0];
+  ah = ap[1];
+  bl = bp[0];
+  bh = bp[1];
+
+  ASSERT (bl & 1);
+
+  /* Use bit 1. */
+  bit <<= 1;
+
+  if (bh == 0 && bl == 1)
+    /* (a|1) = 1 */
+    return 1 - (bit & 2);
+
+  if (al == 0)
+    {
+      if (ah == 0)
+	/* (0|b) = 0, b > 1 */
+	return 0;
+
+      count_trailing_zeros (c, ah);
+      bit ^= ((GMP_NUMB_BITS + c) << 1) & (bl ^ (bl >> 1));
+
+      al = bl;
+      bl = ah >> c;
+
+      if (bl == 1)
+	/* (1|b) = 1 */
+	return 1 - (bit & 2);
+
+      ah = bh;
+
+      bit ^= al & bl;
+
+      goto b_reduced;
+    }
+  if ( (al & 1) == 0)
+    {
+      count_trailing_zeros (c, al);
+
+      al = ((ah << (GMP_NUMB_BITS - c)) & GMP_NUMB_MASK) | (al >> c);
+      ah >>= c;
+      bit ^= (c << 1) & (bl ^ (bl >> 1));
+    }
+  if (ah == 0)
+    {
+      if (bh > 0)
+	{
+	  bit ^= al & bl;
+	  MP_LIMB_T_SWAP (al, bl);
+	  ah = bh;
+	  goto b_reduced;
+	}
+      goto ab_reduced;
+    }
+
+  while (bh > 0)
+    {
+      /* Compute (a|b) */
+      while (ah > bh)
+	{
+	  sub_ddmmss (ah, al, ah, al, bh, bl);
+	  if (al == 0)
+	    {
+	      count_trailing_zeros (c, ah);
+	      bit ^= ((GMP_NUMB_BITS + c) << 1) & (bl ^ (bl >> 1));
+
+	      al = bl;
+	      bl = ah >> c;
+	      ah = bh;
+
+	      bit ^= al & bl;
+	      goto b_reduced;
+	    }
+	  count_trailing_zeros (c, al);
+	  bit ^= (c << 1) & (bl ^ (bl >> 1));
+	  al = ((ah << (GMP_NUMB_BITS - c)) & GMP_NUMB_MASK) | (al >> c);
+	  ah >>= c;
+	}
+      if (ah == bh)
+	goto cancel_hi;
+
+      if (ah == 0)
+	{
+	  bit ^= al & bl;
+	  MP_LIMB_T_SWAP (al, bl);
+	  ah = bh;
+	  break;
+	}
+
+      bit ^= al & bl;
+
+      /* Compute (b|a) */
+      while (bh > ah)
+	{
+	  sub_ddmmss (bh, bl, bh, bl, ah, al);
+	  if (bl == 0)
+	    {
+	      count_trailing_zeros (c, bh);
+	      bit ^= ((GMP_NUMB_BITS + c) << 1) & (al ^ (al >> 1));
+
+	      bl = bh >> c;
+	      bit ^= al & bl;
+	      goto b_reduced;
+	    }
+	  count_trailing_zeros (c, bl);
+	  bit ^= (c << 1) & (al ^ (al >> 1));
+	  bl = ((bh << (GMP_NUMB_BITS - c)) & GMP_NUMB_MASK) | (bl >> c);
+	  bh >>= c;
+	}
+      bit ^= al & bl;
+
+      /* Compute (a|b) */
+      if (ah == bh)
+	{
+	cancel_hi:
+	  if (al < bl)
+	    {
+	      MP_LIMB_T_SWAP (al, bl);
+	      bit ^= al & bl;
+	    }
+	  al -= bl;
+	  if (al == 0)
+	    return 0;
+
+	  count_trailing_zeros (c, al);
+	  bit ^= (c << 1) & (bl ^ (bl >> 1));
+	  al >>= c;
+
+	  if (al == 1)
+	    return 1 - (bit & 2);
+
+	  MP_LIMB_T_SWAP (al, bl);
+	  bit ^= al & bl;
+	  break;
+	}
+    }
+
+ b_reduced:
+  /* Compute (a|b), with b a single limb. */
+  ASSERT (bl & 1);
+
+  if (bl == 1)
+    /* (a|1) = 1 */
+    return 1 - (bit & 2);
+
+  while (ah > 0)
+    {
+      ah -= (al < bl);
+      al -= bl;
+      if (al == 0)
+	{
+	  if (ah == 0)
+	    return 0;
+	  count_trailing_zeros (c, ah);
+	  bit ^= ((GMP_NUMB_BITS + c) << 1) & (bl ^ (bl >> 1));
+	  al = ah >> c;
+	  goto ab_reduced;
+	}
+      count_trailing_zeros (c, al);
+
+      al = ((ah << (GMP_NUMB_BITS - c)) & GMP_NUMB_MASK) | (al >> c);
+      ah >>= c;
+      bit ^= (c << 1) & (bl ^ (bl >> 1));
+    }
+ ab_reduced:
+  ASSERT (bl & 1);
+  ASSERT (bl > 1);
+
+  return mpn_jacobi_base (al, bl, bit);
+}
+#else
+#error Unsupported value for JACOBI_2_METHOD
+#endif
diff --git a/third_party/gmp/mpn/generic/logops_n.c b/third_party/gmp/mpn/generic/logops_n.c
new file mode 100644
index 0000000..3adba2c
--- /dev/null
+++ b/third_party/gmp/mpn/generic/logops_n.c
@@ -0,0 +1,77 @@
+/* mpn_and_n, mpn_ior_n, etc -- mpn logical operations.
+
+Copyright 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#ifdef OPERATION_and_n
+#define func __MPN(and_n)
+#define call mpn_and_n
+#endif
+
+#ifdef OPERATION_andn_n
+#define func __MPN(andn_n)
+#define call mpn_andn_n
+#endif
+
+#ifdef OPERATION_nand_n
+#define func __MPN(nand_n)
+#define call mpn_nand_n
+#endif
+
+#ifdef OPERATION_ior_n
+#define func __MPN(ior_n)
+#define call mpn_ior_n
+#endif
+
+#ifdef OPERATION_iorn_n
+#define func __MPN(iorn_n)
+#define call mpn_iorn_n
+#endif
+
+#ifdef OPERATION_nior_n
+#define func __MPN(nior_n)
+#define call mpn_nior_n
+#endif
+
+#ifdef OPERATION_xor_n
+#define func __MPN(xor_n)
+#define call mpn_xor_n
+#endif
+
+#ifdef OPERATION_xnor_n
+#define func __MPN(xnor_n)
+#define call mpn_xnor_n
+#endif
+
+void
+func (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n)
+{
+  call (rp, up, vp, n);
+}
diff --git a/third_party/gmp/mpn/generic/lshift.c b/third_party/gmp/mpn/generic/lshift.c
new file mode 100644
index 0000000..7e1fdef
--- /dev/null
+++ b/third_party/gmp/mpn/generic/lshift.c
@@ -0,0 +1,72 @@
+/* mpn_lshift -- Shift left low level.
+
+Copyright 1991, 1993, 1994, 1996, 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/* Shift U (pointed to by up and n limbs long) cnt bits to the left
+   and store the n least significant limbs of the result at rp.
+   Return the bits shifted out from the most significant limb.
+
+   Argument constraints:
+   1. 0 < cnt < GMP_NUMB_BITS.
+   2. If the result is to be written over the input, rp must be >= up.
+*/
+
+mp_limb_t
+mpn_lshift (mp_ptr rp, mp_srcptr up, mp_size_t n, unsigned int cnt)
+{
+  mp_limb_t high_limb, low_limb;
+  unsigned int tnc;
+  mp_size_t i;
+  mp_limb_t retval;
+
+  ASSERT (n >= 1);
+  ASSERT (cnt >= 1);
+  ASSERT (cnt < GMP_NUMB_BITS);
+  ASSERT (MPN_SAME_OR_DECR_P (rp, up, n));
+
+  up += n;
+  rp += n;
+
+  tnc = GMP_NUMB_BITS - cnt;
+  low_limb = *--up;
+  retval = low_limb >> tnc;
+  high_limb = (low_limb << cnt) & GMP_NUMB_MASK;
+
+  for (i = n - 1; i != 0; i--)
+    {
+      low_limb = *--up;
+      *--rp = high_limb | (low_limb >> tnc);
+      high_limb = (low_limb << cnt) & GMP_NUMB_MASK;
+    }
+  *--rp = high_limb;
+
+  return retval;
+}
diff --git a/third_party/gmp/mpn/generic/lshiftc.c b/third_party/gmp/mpn/generic/lshiftc.c
new file mode 100644
index 0000000..a583602
--- /dev/null
+++ b/third_party/gmp/mpn/generic/lshiftc.c
@@ -0,0 +1,73 @@
+/* mpn_lshiftc -- Shift left low level with complement.
+
+Copyright 1991, 1993, 1994, 1996, 2000-2002, 2009 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/* Shift U (pointed to by up and n limbs long) cnt bits to the left
+   and store the n least significant limbs of the result at rp.
+   Return the bits shifted out from the most significant limb.
+
+   Argument constraints:
+   1. 0 < cnt < GMP_NUMB_BITS.
+   2. If the result is to be written over the input, rp must be >= up.
+*/
+
+mp_limb_t
+mpn_lshiftc (mp_ptr rp, mp_srcptr up, mp_size_t n, unsigned int cnt)
+{
+  mp_limb_t high_limb, low_limb;
+  unsigned int tnc;
+  mp_size_t i;
+  mp_limb_t retval;
+
+  ASSERT (n >= 1);
+  ASSERT (cnt >= 1);
+  ASSERT (cnt < GMP_NUMB_BITS);
+  ASSERT (MPN_SAME_OR_DECR_P (rp, up, n));
+
+  up += n;
+  rp += n;
+
+  tnc = GMP_NUMB_BITS - cnt;
+  low_limb = *--up;
+  retval = low_limb >> tnc;
+  high_limb = (low_limb << cnt);
+
+  for (i = n - 1; i != 0; i--)
+    {
+      low_limb = *--up;
+      *--rp = (~(high_limb | (low_limb >> tnc))) & GMP_NUMB_MASK;
+      high_limb = low_limb << cnt;
+    }
+  *--rp = (~high_limb) & GMP_NUMB_MASK;
+
+  return retval;
+}
diff --git a/third_party/gmp/mpn/generic/matrix22_mul.c b/third_party/gmp/mpn/generic/matrix22_mul.c
new file mode 100644
index 0000000..6a1299a
--- /dev/null
+++ b/third_party/gmp/mpn/generic/matrix22_mul.c
@@ -0,0 +1,321 @@
+/* matrix22_mul.c.
+
+   Contributed by Niels Möller and Marco Bodrato.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2003-2005, 2008, 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#define MUL(rp, ap, an, bp, bn) do {		\
+  if (an >= bn)					\
+    mpn_mul (rp, ap, an, bp, bn);		\
+  else						\
+    mpn_mul (rp, bp, bn, ap, an);		\
+} while (0)
+
+/* Inputs are unsigned. */
+static int
+abs_sub_n (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n)
+{
+  int c;
+  MPN_CMP (c, ap, bp, n);
+  if (c >= 0)
+    {
+      mpn_sub_n (rp, ap, bp, n);
+      return 0;
+    }
+  else
+    {
+      mpn_sub_n (rp, bp, ap, n);
+      return 1;
+    }
+}
+
+static int
+add_signed_n (mp_ptr rp,
+	      mp_srcptr ap, int as, mp_srcptr bp, int bs, mp_size_t n)
+{
+  if (as != bs)
+    return as ^ abs_sub_n (rp, ap, bp, n);
+  else
+    {
+      ASSERT_NOCARRY (mpn_add_n (rp, ap, bp, n));
+      return as;
+    }
+}
+
+mp_size_t
+mpn_matrix22_mul_itch (mp_size_t rn, mp_size_t mn)
+{
+  if (BELOW_THRESHOLD (rn, MATRIX22_STRASSEN_THRESHOLD)
+      || BELOW_THRESHOLD (mn, MATRIX22_STRASSEN_THRESHOLD))
+    return 3*rn + 2*mn;
+  else
+    return 3*(rn + mn) + 5;
+}
+
+/* Algorithm:
+
+    / s0 \   /  1  0  0  0 \ / r0 \
+    | s1 |   |  0  1  0  1 | | r1 |
+    | s2 |   |  0  0 -1  1 | | r2 |
+    | s3 | = |  0  1 -1  1 | \ r3 /
+    | s4 |   | -1  1 -1  1 |
+    | s5 |   |  0  1  0  0 |
+    \ s6 /   \  0  0  1  0 /
+
+    / t0 \   /  1  0  0  0 \ / m0 \
+    | t1 |   |  0  1  0  1 | | m1 |
+    | t2 |   |  0  0 -1  1 | | m2 |
+    | t3 | = |  0  1 -1  1 | \ m3 /
+    | t4 |   | -1  1 -1  1 |
+    | t5 |   |  0  1  0  0 |
+    \ t6 /   \  0  0  1  0 /
+
+  Note: the two matrices above are the same, but s_i and t_i are used
+  in the same product, only for i<4, see "A Strassen-like Matrix
+  Multiplication suited for squaring and higher power computation" by
+  M. Bodrato, in Proceedings of ISSAC 2010.
+
+    / r0 \   / 1 0  0  0  0  1  0 \ / s0*t0 \
+    | r1 | = | 0 0 -1  1 -1  1  0 | | s1*t1 |
+    | r2 |   | 0 1  0 -1  0 -1 -1 | | s2*t2 |
+    \ r3 /   \ 0 1  1 -1  0 -1  0 / | s3*t3 |
+				    | s4*t5 |
+				    | s5*t6 |
+				    \ s6*t4 /
+
+  The scheduling uses two temporaries U0 and U1 to store products, and
+  two, S0 and T0, to store combinations of entries of the two
+  operands.
+*/
+
+/* Computes R = R * M. Elements are numbers R = (r0, r1; r2, r3).
+ *
+ * Resulting elements are of size up to rn + mn + 1.
+ *
+ * Temporary storage: 3 rn + 3 mn + 5. */
+static void
+mpn_matrix22_mul_strassen (mp_ptr r0, mp_ptr r1, mp_ptr r2, mp_ptr r3, mp_size_t rn,
+			   mp_srcptr m0, mp_srcptr m1, mp_srcptr m2, mp_srcptr m3, mp_size_t mn,
+			   mp_ptr tp)
+{
+  mp_ptr s0, t0, u0, u1;
+  int r1s, r3s, s0s, t0s, u1s;
+  s0 = tp; tp += rn + 1;
+  t0 = tp; tp += mn + 1;
+  u0 = tp; tp += rn + mn + 1;
+  u1 = tp; /* rn + mn + 2 */
+
+  MUL (u0, r1, rn, m2, mn);		/* u5 = s5 * t6 */
+  r3s = abs_sub_n (r3, r3, r2, rn);	/* r3 - r2 */
+  if (r3s)
+    {
+      r1s = abs_sub_n (r1, r1, r3, rn);
+      r1[rn] = 0;
+    }
+  else
+    {
+      r1[rn] = mpn_add_n (r1, r1, r3, rn);
+      r1s = 0;				/* r1 - r2 + r3  */
+    }
+  if (r1s)
+    {
+      s0[rn] = mpn_add_n (s0, r1, r0, rn);
+      s0s = 0;
+    }
+  else if (r1[rn] != 0)
+    {
+      s0[rn] = r1[rn] - mpn_sub_n (s0, r1, r0, rn);
+      s0s = 1;				/* s4 = -r0 + r1 - r2 + r3 */
+					/* Reverse sign! */
+    }
+  else
+    {
+      s0s = abs_sub_n (s0, r0, r1, rn);
+      s0[rn] = 0;
+    }
+  MUL (u1, r0, rn, m0, mn);		/* u0 = s0 * t0 */
+  r0[rn+mn] = mpn_add_n (r0, u0, u1, rn + mn);
+  ASSERT (r0[rn+mn] < 2);		/* u0 + u5 */
+
+  t0s = abs_sub_n (t0, m3, m2, mn);
+  u1s = r3s^t0s^1;			/* Reverse sign! */
+  MUL (u1, r3, rn, t0, mn);		/* u2 = s2 * t2 */
+  u1[rn+mn] = 0;
+  if (t0s)
+    {
+      t0s = abs_sub_n (t0, m1, t0, mn);
+      t0[mn] = 0;
+    }
+  else
+    {
+      t0[mn] = mpn_add_n (t0, t0, m1, mn);
+    }
+
+  /* FIXME: Could be simplified if we had space for rn + mn + 2 limbs
+     at r3. I'd expect that for matrices of random size, the high
+     words t0[mn] and r1[rn] are non-zero with a pretty small
+     probability. If that can be confirmed this should be done as an
+     unconditional rn x (mn+1) followed by an if (UNLIKELY (r1[rn]))
+     add_n. */
+  if (t0[mn] != 0)
+    {
+      MUL (r3, r1, rn, t0, mn + 1);	/* u3 = s3 * t3 */
+      ASSERT (r1[rn] < 2);
+      if (r1[rn] != 0)
+	mpn_add_n (r3 + rn, r3 + rn, t0, mn + 1);
+    }
+  else
+    {
+      MUL (r3, r1, rn + 1, t0, mn);
+    }
+
+  ASSERT (r3[rn+mn] < 4);
+
+  u0[rn+mn] = 0;
+  if (r1s^t0s)
+    {
+      r3s = abs_sub_n (r3, u0, r3, rn + mn + 1);
+    }
+  else
+    {
+      ASSERT_NOCARRY (mpn_add_n (r3, r3, u0, rn + mn + 1));
+      r3s = 0;				/* u3 + u5 */
+    }
+
+  if (t0s)
+    {
+      t0[mn] = mpn_add_n (t0, t0, m0, mn);
+    }
+  else if (t0[mn] != 0)
+    {
+      t0[mn] -= mpn_sub_n (t0, t0, m0, mn);
+    }
+  else
+    {
+      t0s = abs_sub_n (t0, t0, m0, mn);
+    }
+  MUL (u0, r2, rn, t0, mn + 1);		/* u6 = s6 * t4 */
+  ASSERT (u0[rn+mn] < 2);
+  if (r1s)
+    {
+      ASSERT_NOCARRY (mpn_sub_n (r1, r2, r1, rn));
+    }
+  else
+    {
+      r1[rn] += mpn_add_n (r1, r1, r2, rn);
+    }
+  rn++;
+  t0s = add_signed_n (r2, r3, r3s, u0, t0s, rn + mn);
+					/* u3 + u5 + u6 */
+  ASSERT (r2[rn+mn-1] < 4);
+  r3s = add_signed_n (r3, r3, r3s, u1, u1s, rn + mn);
+					/* -u2 + u3 + u5  */
+  ASSERT (r3[rn+mn-1] < 3);
+  MUL (u0, s0, rn, m1, mn);		/* u4 = s4 * t5 */
+  ASSERT (u0[rn+mn-1] < 2);
+  t0[mn] = mpn_add_n (t0, m3, m1, mn);
+  MUL (u1, r1, rn, t0, mn + 1);		/* u1 = s1 * t1 */
+  mn += rn;
+  ASSERT (u1[mn-1] < 4);
+  ASSERT (u1[mn] == 0);
+  ASSERT_NOCARRY (add_signed_n (r1, r3, r3s, u0, s0s, mn));
+					/* -u2 + u3 - u4 + u5  */
+  ASSERT (r1[mn-1] < 2);
+  if (r3s)
+    {
+      ASSERT_NOCARRY (mpn_add_n (r3, u1, r3, mn));
+    }
+  else
+    {
+      ASSERT_NOCARRY (mpn_sub_n (r3, u1, r3, mn));
+					/* u1 + u2 - u3 - u5  */
+    }
+  ASSERT (r3[mn-1] < 2);
+  if (t0s)
+    {
+      ASSERT_NOCARRY (mpn_add_n (r2, u1, r2, mn));
+    }
+  else
+    {
+      ASSERT_NOCARRY (mpn_sub_n (r2, u1, r2, mn));
+					/* u1 - u3 - u5 - u6  */
+    }
+  ASSERT (r2[mn-1] < 2);
+}
+
+void
+mpn_matrix22_mul (mp_ptr r0, mp_ptr r1, mp_ptr r2, mp_ptr r3, mp_size_t rn,
+		  mp_srcptr m0, mp_srcptr m1, mp_srcptr m2, mp_srcptr m3, mp_size_t mn,
+		  mp_ptr tp)
+{
+  if (BELOW_THRESHOLD (rn, MATRIX22_STRASSEN_THRESHOLD)
+      || BELOW_THRESHOLD (mn, MATRIX22_STRASSEN_THRESHOLD))
+    {
+      mp_ptr p0, p1;
+      unsigned i;
+
+      /* Temporary storage: 3 rn + 2 mn */
+      p0 = tp + rn;
+      p1 = p0 + rn + mn;
+
+      for (i = 0; i < 2; i++)
+	{
+	  MPN_COPY (tp, r0, rn);
+
+	  if (rn >= mn)
+	    {
+	      mpn_mul (p0, r0, rn, m0, mn);
+	      mpn_mul (p1, r1, rn, m3, mn);
+	      mpn_mul (r0, r1, rn, m2, mn);
+	      mpn_mul (r1, tp, rn, m1, mn);
+	    }
+	  else
+	    {
+	      mpn_mul (p0, m0, mn, r0, rn);
+	      mpn_mul (p1, m3, mn, r1, rn);
+	      mpn_mul (r0, m2, mn, r1, rn);
+	      mpn_mul (r1, m1, mn, tp, rn);
+	    }
+	  r0[rn+mn] = mpn_add_n (r0, r0, p0, rn + mn);
+	  r1[rn+mn] = mpn_add_n (r1, r1, p1, rn + mn);
+
+	  r0 = r2; r1 = r3;
+	}
+    }
+  else
+    mpn_matrix22_mul_strassen (r0, r1, r2, r3, rn,
+			       m0, m1, m2, m3, mn, tp);
+}
diff --git a/third_party/gmp/mpn/generic/matrix22_mul1_inverse_vector.c b/third_party/gmp/mpn/generic/matrix22_mul1_inverse_vector.c
new file mode 100644
index 0000000..68d50b7
--- /dev/null
+++ b/third_party/gmp/mpn/generic/matrix22_mul1_inverse_vector.c
@@ -0,0 +1,64 @@
+/* matrix22_mul1_inverse_vector.c
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2008, 2010 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/* Sets (r;b) = M^{-1}(a;b), with M^{-1} = (u11, -u01; -u10, u00) from
+   the left. Uses three buffers, to avoid a copy. */
+mp_size_t
+mpn_matrix22_mul1_inverse_vector (const struct hgcd_matrix1 *M,
+				  mp_ptr rp, mp_srcptr ap, mp_ptr bp, mp_size_t n)
+{
+  mp_limb_t h0, h1;
+
+  /* Compute (r;b) <-- (u11 a - u01 b; -u10 a + u00 b) as
+
+     r  = u11 * a
+     r -= u01 * b
+     b *= u00
+     b -= u10 * a
+  */
+
+  h0 =    mpn_mul_1 (rp, ap, n, M->u[1][1]);
+  h1 = mpn_submul_1 (rp, bp, n, M->u[0][1]);
+  ASSERT (h0 == h1);
+
+  h0 =    mpn_mul_1 (bp, bp, n, M->u[0][0]);
+  h1 = mpn_submul_1 (bp, ap, n, M->u[1][0]);
+  ASSERT (h0 == h1);
+
+  n -= (rp[n-1] | bp[n-1]) == 0;
+  return n;
+}
diff --git a/third_party/gmp/mpn/generic/mod_1.c b/third_party/gmp/mpn/generic/mod_1.c
new file mode 100644
index 0000000..8e415df
--- /dev/null
+++ b/third_party/gmp/mpn/generic/mod_1.c
@@ -0,0 +1,280 @@
+/* mpn_mod_1(dividend_ptr, dividend_size, divisor_limb) --
+   Divide (DIVIDEND_PTR,,DIVIDEND_SIZE) by DIVISOR_LIMB.
+   Return the single-limb remainder.
+   There are no constraints on the value of the divisor.
+
+Copyright 1991, 1993, 1994, 1999, 2000, 2002, 2007-2009, 2012 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* The size where udiv_qrnnd_preinv should be used rather than udiv_qrnnd,
+   meaning the quotient size where that should happen, the quotient size
+   being how many udiv divisions will be done.
+
+   The default is to use preinv always, CPUs where this doesn't suit have
+   tuned thresholds.  Note in particular that preinv should certainly be
+   used if that's the only division available (USE_PREINV_ALWAYS).  */
+
+#ifndef MOD_1_NORM_THRESHOLD
+#define MOD_1_NORM_THRESHOLD  0
+#endif
+
+#ifndef MOD_1_UNNORM_THRESHOLD
+#define MOD_1_UNNORM_THRESHOLD  0
+#endif
+
+#ifndef MOD_1U_TO_MOD_1_1_THRESHOLD
+#define MOD_1U_TO_MOD_1_1_THRESHOLD  MP_SIZE_T_MAX /* default is not to use mpn_mod_1s */
+#endif
+
+#ifndef MOD_1N_TO_MOD_1_1_THRESHOLD
+#define MOD_1N_TO_MOD_1_1_THRESHOLD  MP_SIZE_T_MAX /* default is not to use mpn_mod_1s */
+#endif
+
+#ifndef MOD_1_1_TO_MOD_1_2_THRESHOLD
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD  10
+#endif
+
+#ifndef MOD_1_2_TO_MOD_1_4_THRESHOLD
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD  20
+#endif
+
+#if TUNE_PROGRAM_BUILD && !HAVE_NATIVE_mpn_mod_1_1p
+/* Duplicates declarations in tune/speed.h */
+mp_limb_t mpn_mod_1_1p_1 (mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t [4]);
+mp_limb_t mpn_mod_1_1p_2 (mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t [4]);
+
+void mpn_mod_1_1p_cps_1 (mp_limb_t [4], mp_limb_t);
+void mpn_mod_1_1p_cps_2 (mp_limb_t [4], mp_limb_t);
+
+#undef mpn_mod_1_1p
+#define mpn_mod_1_1p(ap, n, b, pre)			     \
+  (mod_1_1p_method == 1 ? mpn_mod_1_1p_1 (ap, n, b, pre)     \
+   : (mod_1_1p_method == 2 ? mpn_mod_1_1p_2 (ap, n, b, pre)  \
+      : __gmpn_mod_1_1p (ap, n, b, pre)))
+
+#undef mpn_mod_1_1p_cps
+#define mpn_mod_1_1p_cps(pre, b)				\
+  (mod_1_1p_method == 1 ? mpn_mod_1_1p_cps_1 (pre, b)		\
+   : (mod_1_1p_method == 2 ? mpn_mod_1_1p_cps_2 (pre, b)	\
+      : __gmpn_mod_1_1p_cps (pre, b)))
+#endif /* TUNE_PROGRAM_BUILD && !HAVE_NATIVE_mpn_mod_1_1p */
+
+
+/* The comments in mpn/generic/divrem_1.c apply here too.
+
+   As noted in the algorithms section of the manual, the shifts in the loop
+   for the unnorm case can be avoided by calculating r = a%(d*2^n), followed
+   by a final (r*2^n)%(d*2^n).  In fact if it happens that a%(d*2^n) can
+   skip a division where (a*2^n)%(d*2^n) can't then there's the same number
+   of divide steps, though how often that happens depends on the assumed
+   distributions of dividend and divisor.  In any case this idea is left to
+   CPU specific implementations to consider.  */
+
+static mp_limb_t
+mpn_mod_1_unnorm (mp_srcptr up, mp_size_t un, mp_limb_t d)
+{
+  mp_size_t  i;
+  mp_limb_t  n1, n0, r;
+  mp_limb_t  dummy;
+  int cnt;
+
+  ASSERT (un > 0);
+  ASSERT (d != 0);
+
+  d <<= GMP_NAIL_BITS;
+
+  /* Skip a division if high < divisor.  Having the test here before
+     normalizing will still skip as often as possible.  */
+  r = up[un - 1] << GMP_NAIL_BITS;
+  if (r < d)
+    {
+      r >>= GMP_NAIL_BITS;
+      un--;
+      if (un == 0)
+	return r;
+    }
+  else
+    r = 0;
+
+  /* If udiv_qrnnd doesn't need a normalized divisor, can use the simple
+     code above. */
+  if (! UDIV_NEEDS_NORMALIZATION
+      && BELOW_THRESHOLD (un, MOD_1_UNNORM_THRESHOLD))
+    {
+      for (i = un - 1; i >= 0; i--)
+	{
+	  n0 = up[i] << GMP_NAIL_BITS;
+	  udiv_qrnnd (dummy, r, r, n0, d);
+	  r >>= GMP_NAIL_BITS;
+	}
+      return r;
+    }
+
+  count_leading_zeros (cnt, d);
+  d <<= cnt;
+
+  n1 = up[un - 1] << GMP_NAIL_BITS;
+  r = (r << cnt) | (n1 >> (GMP_LIMB_BITS - cnt));
+
+  if (UDIV_NEEDS_NORMALIZATION
+      && BELOW_THRESHOLD (un, MOD_1_UNNORM_THRESHOLD))
+    {
+      mp_limb_t nshift;
+      for (i = un - 2; i >= 0; i--)
+	{
+	  n0 = up[i] << GMP_NAIL_BITS;
+	  nshift = (n1 << cnt) | (n0 >> (GMP_NUMB_BITS - cnt));
+	  udiv_qrnnd (dummy, r, r, nshift, d);
+	  r >>= GMP_NAIL_BITS;
+	  n1 = n0;
+	}
+      udiv_qrnnd (dummy, r, r, n1 << cnt, d);
+      r >>= GMP_NAIL_BITS;
+      return r >> cnt;
+    }
+  else
+    {
+      mp_limb_t inv, nshift;
+      invert_limb (inv, d);
+
+      for (i = un - 2; i >= 0; i--)
+	{
+	  n0 = up[i] << GMP_NAIL_BITS;
+	  nshift = (n1 << cnt) | (n0 >> (GMP_NUMB_BITS - cnt));
+	  udiv_rnnd_preinv (r, r, nshift, d, inv);
+	  r >>= GMP_NAIL_BITS;
+	  n1 = n0;
+	}
+      udiv_rnnd_preinv (r, r, n1 << cnt, d, inv);
+      r >>= GMP_NAIL_BITS;
+      return r >> cnt;
+    }
+}
+
+static mp_limb_t
+mpn_mod_1_norm (mp_srcptr up, mp_size_t un, mp_limb_t d)
+{
+  mp_size_t  i;
+  mp_limb_t  n0, r;
+  mp_limb_t  dummy;
+
+  ASSERT (un > 0);
+
+  d <<= GMP_NAIL_BITS;
+
+  ASSERT (d & GMP_LIMB_HIGHBIT);
+
+  /* High limb is initial remainder, possibly with one subtract of
+     d to get r<d.  */
+  r = up[un - 1] << GMP_NAIL_BITS;
+  if (r >= d)
+    r -= d;
+  r >>= GMP_NAIL_BITS;
+  un--;
+  if (un == 0)
+    return r;
+
+  if (BELOW_THRESHOLD (un, MOD_1_NORM_THRESHOLD))
+    {
+      for (i = un - 1; i >= 0; i--)
+	{
+	  n0 = up[i] << GMP_NAIL_BITS;
+	  udiv_qrnnd (dummy, r, r, n0, d);
+	  r >>= GMP_NAIL_BITS;
+	}
+      return r;
+    }
+  else
+    {
+      mp_limb_t  inv;
+      invert_limb (inv, d);
+      for (i = un - 1; i >= 0; i--)
+	{
+	  n0 = up[i] << GMP_NAIL_BITS;
+	  udiv_rnnd_preinv (r, r, n0, d, inv);
+	  r >>= GMP_NAIL_BITS;
+	}
+      return r;
+    }
+}
+
+mp_limb_t
+mpn_mod_1 (mp_srcptr ap, mp_size_t n, mp_limb_t b)
+{
+  ASSERT (n >= 0);
+  ASSERT (b != 0);
+
+  /* Should this be handled at all?  Rely on callers?  Note un==0 is currently
+     required by mpz/fdiv_r_ui.c and possibly other places.  */
+  if (n == 0)
+    return 0;
+
+  if (UNLIKELY ((b & GMP_NUMB_HIGHBIT) != 0))
+    {
+      if (BELOW_THRESHOLD (n, MOD_1N_TO_MOD_1_1_THRESHOLD))
+	{
+	  return mpn_mod_1_norm (ap, n, b);
+	}
+      else
+	{
+	  mp_limb_t pre[4];
+	  mpn_mod_1_1p_cps (pre, b);
+	  return mpn_mod_1_1p (ap, n, b, pre);
+	}
+    }
+  else
+    {
+      if (BELOW_THRESHOLD (n, MOD_1U_TO_MOD_1_1_THRESHOLD))
+	{
+	  return mpn_mod_1_unnorm (ap, n, b);
+	}
+      else if (BELOW_THRESHOLD (n, MOD_1_1_TO_MOD_1_2_THRESHOLD))
+	{
+	  mp_limb_t pre[4];
+	  mpn_mod_1_1p_cps (pre, b);
+	  return mpn_mod_1_1p (ap, n, b << pre[1], pre);
+	}
+      else if (BELOW_THRESHOLD (n, MOD_1_2_TO_MOD_1_4_THRESHOLD) || UNLIKELY (b > GMP_NUMB_MASK / 4))
+	{
+	  mp_limb_t pre[5];
+	  mpn_mod_1s_2p_cps (pre, b);
+	  return mpn_mod_1s_2p (ap, n, b << pre[1], pre);
+	}
+      else
+	{
+	  mp_limb_t pre[7];
+	  mpn_mod_1s_4p_cps (pre, b);
+	  return mpn_mod_1s_4p (ap, n, b << pre[1], pre);
+	}
+    }
+}
diff --git a/third_party/gmp/mpn/generic/mod_1_1.c b/third_party/gmp/mpn/generic/mod_1_1.c
new file mode 100644
index 0000000..f6342d6
--- /dev/null
+++ b/third_party/gmp/mpn/generic/mod_1_1.c
@@ -0,0 +1,332 @@
+/* mpn_mod_1_1p (ap, n, b, cps)
+   Divide (ap,,n) by b.  Return the single-limb remainder.
+
+   Contributed to the GNU project by Torbjorn Granlund and Niels Möller.
+   Based on a suggestion by Peter L. Montgomery.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2008-2011, 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#ifndef MOD_1_1P_METHOD
+# define MOD_1_1P_METHOD 1    /* need to make sure this is 2 for asm testing */
+#endif
+
+/* Define some longlong.h-style macros, but for wider operations.
+ * add_mssaaaa is like longlong.h's add_ssaaaa, but also generates
+ * carry out, in the form of a mask. */
+
+#if defined (__GNUC__) && ! defined (NO_ASM)
+
+#if HAVE_HOST_CPU_FAMILY_x86 && W_TYPE_SIZE == 32
+#define add_mssaaaa(m, s1, s0, a1, a0, b1, b0)				\
+  __asm__ (  "add	%6, %k2\n\t"					\
+	     "adc	%4, %k1\n\t"					\
+	     "sbb	%k0, %k0"					\
+	   : "=r" (m), "=r" (s1), "=&r" (s0)				\
+	   : "1"  ((USItype)(a1)), "g" ((USItype)(b1)),			\
+	     "%2" ((USItype)(a0)), "g" ((USItype)(b0)))
+#endif
+
+#if HAVE_HOST_CPU_FAMILY_x86_64 && W_TYPE_SIZE == 64
+#define add_mssaaaa(m, s1, s0, a1, a0, b1, b0)				\
+  __asm__ (  "add	%6, %q2\n\t"					\
+	     "adc	%4, %q1\n\t"					\
+	     "sbb	%q0, %q0"					\
+	   : "=r" (m), "=r" (s1), "=&r" (s0)				\
+	   : "1"  ((UDItype)(a1)), "rme" ((UDItype)(b1)),		\
+	     "%2" ((UDItype)(a0)), "rme" ((UDItype)(b0)))
+#endif
+
+#if defined (__sparc__) && W_TYPE_SIZE == 32
+#define add_mssaaaa(m, sh, sl, ah, al, bh, bl)				\
+  __asm__ (  "addcc	%r5, %6, %2\n\t"				\
+	     "addxcc	%r3, %4, %1\n\t"				\
+	     "subx	%%g0, %%g0, %0"					\
+	   : "=r" (m), "=r" (sh), "=&r" (sl)				\
+	   : "rJ" (ah), "rI" (bh), "%rJ" (al), "rI" (bl)		\
+	 __CLOBBER_CC)
+#endif
+
+#if defined (__sparc__) && W_TYPE_SIZE == 64
+#define add_mssaaaa(m, sh, sl, ah, al, bh, bl)				\
+  __asm__ (  "addcc	%r5, %6, %2\n\t"				\
+	     "addccc	%r7, %8, %%g0\n\t"				\
+	     "addccc	%r3, %4, %1\n\t"				\
+	     "clr	%0\n\t"						\
+	     "movcs	%%xcc, -1, %0"					\
+	   : "=r" (m), "=r" (sh), "=&r" (sl)				\
+	   : "rJ" (ah), "rI" (bh), "%rJ" (al), "rI" (bl),		\
+	     "rJ" ((al) >> 32), "rI" ((bl) >> 32)			\
+	 __CLOBBER_CC)
+#if __VIS__ >= 0x300
+#undef add_mssaaaa
+#define add_mssaaaa(m, sh, sl, ah, al, bh, bl)				\
+  __asm__ (  "addcc	%r5, %6, %2\n\t"				\
+	     "addxccc	%r3, %4, %1\n\t"				\
+	     "clr	%0\n\t"						\
+	     "movcs	%%xcc, -1, %0"					\
+	   : "=r" (m), "=r" (sh), "=&r" (sl)				\
+	   : "rJ" (ah), "rI" (bh), "%rJ" (al), "rI" (bl)		\
+	 __CLOBBER_CC)
+#endif
+#endif
+
+#if HAVE_HOST_CPU_FAMILY_powerpc && !defined (_LONG_LONG_LIMB)
+/* This works fine for 32-bit and 64-bit limbs, except for 64-bit limbs with a
+   processor running in 32-bit mode, since the carry flag then gets the 32-bit
+   carry.  */
+#define add_mssaaaa(m, s1, s0, a1, a0, b1, b0)				\
+  __asm__ (  "add%I6c	%2, %5, %6\n\t"					\
+	     "adde	%1, %3, %4\n\t"					\
+	     "subfe	%0, %0, %0\n\t"					\
+	     "nor	%0, %0, %0"					\
+	   : "=r" (m), "=r" (s1), "=&r" (s0)				\
+	   : "r"  (a1), "r" (b1), "%r" (a0), "rI" (b0)			\
+	     __CLOBBER_CC)
+#endif
+
+#if defined (__s390x__) && W_TYPE_SIZE == 64
+#define add_mssaaaa(m, s1, s0, a1, a0, b1, b0)				\
+  __asm__ (  "algr	%2, %6\n\t"					\
+	     "alcgr	%1, %4\n\t"					\
+	     "lghi	%0, 0\n\t"					\
+	     "alcgr	%0, %0\n\t"					\
+	     "lcgr	%0, %0"						\
+	   : "=r" (m), "=r" (s1), "=&r" (s0)				\
+	   : "1"  ((UDItype)(a1)), "r" ((UDItype)(b1)),			\
+	     "%2" ((UDItype)(a0)), "r" ((UDItype)(b0)) __CLOBBER_CC)
+#endif
+
+#if defined (__arm__) && !defined (__thumb__) && W_TYPE_SIZE == 32
+#define add_mssaaaa(m, sh, sl, ah, al, bh, bl)				\
+  __asm__ (  "adds	%2, %5, %6\n\t"					\
+	     "adcs	%1, %3, %4\n\t"					\
+	     "movcc	%0, #0\n\t"					\
+	     "movcs	%0, #-1"					\
+	   : "=r" (m), "=r" (sh), "=&r" (sl)				\
+	   : "r" (ah), "rI" (bh), "%r" (al), "rI" (bl) __CLOBBER_CC)
+#endif
+#endif /* defined (__GNUC__) */
+
+#ifndef add_mssaaaa
+#define add_mssaaaa(m, s1, s0, a1, a0, b1, b0)				\
+  do {									\
+    UWtype __s0, __s1, __c0, __c1;					\
+    __s0 = (a0) + (b0);							\
+    __s1 = (a1) + (b1);							\
+    __c0 = __s0 < (a0);							\
+    __c1 = __s1 < (a1);							\
+    (s0) = __s0;							\
+    __s1 = __s1 + __c0;							\
+    (s1) = __s1;							\
+    (m) = - (__c1 + (__s1 < __c0));					\
+  } while (0)
+#endif
+
+#if MOD_1_1P_METHOD == 1
+void
+mpn_mod_1_1p_cps (mp_limb_t cps[4], mp_limb_t b)
+{
+  mp_limb_t bi;
+  mp_limb_t B1modb, B2modb;
+  int cnt;
+
+  count_leading_zeros (cnt, b);
+
+  b <<= cnt;
+  invert_limb (bi, b);
+
+  cps[0] = bi;
+  cps[1] = cnt;
+
+  B1modb = -b;
+  if (LIKELY (cnt != 0))
+    B1modb *= ((bi >> (GMP_LIMB_BITS-cnt)) | (CNST_LIMB(1) << cnt));
+  ASSERT (B1modb <= b);		/* NB: not fully reduced mod b */
+  cps[2] = B1modb >> cnt;
+
+  /* In the normalized case, this can be simplified to
+   *
+   *   B2modb = - b * bi;
+   *   ASSERT (B2modb <= b);    // NB: equality iff b = B/2
+   */
+  udiv_rnnd_preinv (B2modb, B1modb, CNST_LIMB(0), b, bi);
+  cps[3] = B2modb >> cnt;
+}
+
+mp_limb_t
+mpn_mod_1_1p (mp_srcptr ap, mp_size_t n, mp_limb_t b, const mp_limb_t bmodb[4])
+{
+  mp_limb_t rh, rl, bi, ph, pl, r;
+  mp_limb_t B1modb, B2modb;
+  mp_size_t i;
+  int cnt;
+  mp_limb_t mask;
+
+  ASSERT (n >= 2);		/* fix tuneup.c if this is changed */
+
+  B1modb = bmodb[2];
+  B2modb = bmodb[3];
+
+  rl = ap[n - 1];
+  umul_ppmm (ph, pl, rl, B1modb);
+  add_ssaaaa (rh, rl, ph, pl, CNST_LIMB(0), ap[n - 2]);
+
+  for (i = n - 3; i >= 0; i -= 1)
+    {
+      /* rr = ap[i]				< B
+	    + LO(rr)  * (B mod b)		<= (B-1)(b-1)
+	    + HI(rr)  * (B^2 mod b)		<= (B-1)(b-1)
+      */
+      umul_ppmm (ph, pl, rl, B1modb);
+      add_ssaaaa (ph, pl, ph, pl, CNST_LIMB(0), ap[i]);
+
+      umul_ppmm (rh, rl, rh, B2modb);
+      add_ssaaaa (rh, rl, rh, rl, ph, pl);
+    }
+
+  cnt = bmodb[1];
+  bi = bmodb[0];
+
+  if (LIKELY (cnt != 0))
+    rh = (rh << cnt) | (rl >> (GMP_LIMB_BITS - cnt));
+
+  mask = -(mp_limb_t) (rh >= b);
+  rh -= mask & b;
+
+  udiv_rnnd_preinv (r, rh, rl << cnt, b, bi);
+
+  return r >> cnt;
+}
+#endif /* MOD_1_1P_METHOD == 1 */
+
+#if MOD_1_1P_METHOD == 2
+void
+mpn_mod_1_1p_cps (mp_limb_t cps[4], mp_limb_t b)
+{
+  mp_limb_t bi;
+  mp_limb_t B2modb;
+  int cnt;
+
+  count_leading_zeros (cnt, b);
+
+  b <<= cnt;
+  invert_limb (bi, b);
+
+  cps[0] = bi;
+  cps[1] = cnt;
+
+  if (LIKELY (cnt != 0))
+    {
+      mp_limb_t B1modb = -b;
+      B1modb *= ((bi >> (GMP_LIMB_BITS-cnt)) | (CNST_LIMB(1) << cnt));
+      ASSERT (B1modb <= b);		/* NB: not fully reduced mod b */
+      cps[2] = B1modb >> cnt;
+    }
+  B2modb = - b * bi;
+  ASSERT (B2modb <= b);    // NB: equality iff b = B/2
+  cps[3] = B2modb;
+}
+
+mp_limb_t
+mpn_mod_1_1p (mp_srcptr ap, mp_size_t n, mp_limb_t b, const mp_limb_t bmodb[4])
+{
+  int cnt;
+  mp_limb_t bi, B1modb;
+  mp_limb_t r0, r1;
+  mp_limb_t r;
+
+  ASSERT (n >= 2);		/* fix tuneup.c if this is changed */
+
+  r0 = ap[n-2];
+  r1 = ap[n-1];
+
+  if (n > 2)
+    {
+      mp_limb_t B2modb, B2mb;
+      mp_limb_t p0, p1;
+      mp_limb_t r2;
+      mp_size_t j;
+
+      B2modb = bmodb[3];
+      B2mb = B2modb - b;
+
+      umul_ppmm (p1, p0, r1, B2modb);
+      add_mssaaaa (r2, r1, r0, r0, ap[n-3], p1, p0);
+
+      for (j = n-4; j >= 0; j--)
+	{
+	  mp_limb_t cy;
+	  /* mp_limb_t t = r0 + B2mb; */
+	  umul_ppmm (p1, p0, r1, B2modb);
+
+	  ADDC_LIMB (cy, r0, r0, r2 & B2modb);
+	  /* Alternative, for cmov: if (cy) r0 = t; */
+	  r0 -= (-cy) & b;
+	  add_mssaaaa (r2, r1, r0, r0, ap[j], p1, p0);
+	}
+
+      r1 -= (r2 & b);
+    }
+
+  cnt = bmodb[1];
+
+  if (LIKELY (cnt != 0))
+    {
+      mp_limb_t t;
+      mp_limb_t B1modb = bmodb[2];
+
+      umul_ppmm (r1, t, r1, B1modb);
+      r0 += t;
+      r1 += (r0 < t);
+
+      /* Normalize */
+      r1 = (r1 << cnt) | (r0 >> (GMP_LIMB_BITS - cnt));
+      r0 <<= cnt;
+
+      /* NOTE: Might get r1 == b here, but udiv_rnnd_preinv allows that. */
+    }
+  else
+    {
+      mp_limb_t mask = -(mp_limb_t) (r1 >= b);
+      r1 -= mask & b;
+    }
+
+  bi = bmodb[0];
+
+  udiv_rnnd_preinv (r, r1, r0, b, bi);
+  return r >> cnt;
+}
+#endif /* MOD_1_1P_METHOD == 2 */
diff --git a/third_party/gmp/mpn/generic/mod_1_2.c b/third_party/gmp/mpn/generic/mod_1_2.c
new file mode 100644
index 0000000..b00d19e
--- /dev/null
+++ b/third_party/gmp/mpn/generic/mod_1_2.c
@@ -0,0 +1,148 @@
+/* mpn_mod_1s_2p (ap, n, b, cps)
+   Divide (ap,,n) by b.  Return the single-limb remainder.
+   Requires that b < B / 2.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+   Based on a suggestion by Peter L. Montgomery.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2008-2010 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+void
+mpn_mod_1s_2p_cps (mp_limb_t cps[5], mp_limb_t b)
+{
+  mp_limb_t bi;
+  mp_limb_t B1modb, B2modb, B3modb;
+  int cnt;
+
+  ASSERT (b <= (~(mp_limb_t) 0) / 2);
+
+  count_leading_zeros (cnt, b);
+
+  b <<= cnt;
+  invert_limb (bi, b);
+
+  cps[0] = bi;
+  cps[1] = cnt;
+
+  B1modb = -b * ((bi >> (GMP_LIMB_BITS-cnt)) | (CNST_LIMB(1) << cnt));
+  ASSERT (B1modb <= b);		/* NB: not fully reduced mod b */
+  cps[2] = B1modb >> cnt;
+
+  udiv_rnnd_preinv (B2modb, B1modb, CNST_LIMB(0), b, bi);
+  cps[3] = B2modb >> cnt;
+
+  udiv_rnnd_preinv (B3modb, B2modb, CNST_LIMB(0), b, bi);
+  cps[4] = B3modb >> cnt;
+
+#if WANT_ASSERT
+  {
+    int i;
+    b = cps[2];
+    for (i = 3; i <= 4; i++)
+      {
+	b += cps[i];
+	ASSERT (b >= cps[i]);
+      }
+  }
+#endif
+}
+
+mp_limb_t
+mpn_mod_1s_2p (mp_srcptr ap, mp_size_t n, mp_limb_t b, const mp_limb_t cps[5])
+{
+  mp_limb_t rh, rl, bi, ph, pl, ch, cl, r;
+  mp_limb_t B1modb, B2modb, B3modb;
+  mp_size_t i;
+  int cnt;
+
+  ASSERT (n >= 1);
+
+  B1modb = cps[2];
+  B2modb = cps[3];
+  B3modb = cps[4];
+
+  if ((n & 1) != 0)
+    {
+      if (n == 1)
+	{
+	  rl = ap[n - 1];
+	  bi = cps[0];
+	  cnt = cps[1];
+	  udiv_rnnd_preinv (r, rl >> (GMP_LIMB_BITS - cnt),
+			     rl << cnt, b, bi);
+	  return r >> cnt;
+	}
+
+      umul_ppmm (ph, pl, ap[n - 2], B1modb);
+      add_ssaaaa (ph, pl, ph, pl, CNST_LIMB(0), ap[n - 3]);
+      umul_ppmm (rh, rl, ap[n - 1], B2modb);
+      add_ssaaaa (rh, rl, rh, rl, ph, pl);
+      n--;
+    }
+  else
+    {
+      rh = ap[n - 1];
+      rl = ap[n - 2];
+    }
+
+  for (i = n - 4; i >= 0; i -= 2)
+    {
+      /* rr = ap[i]				< B
+	    + ap[i+1] * (B mod b)		<= (B-1)(b-1)
+	    + LO(rr)  * (B^2 mod b)		<= (B-1)(b-1)
+	    + HI(rr)  * (B^3 mod b)		<= (B-1)(b-1)
+      */
+      umul_ppmm (ph, pl, ap[i + 1], B1modb);
+      add_ssaaaa (ph, pl, ph, pl, CNST_LIMB(0), ap[i + 0]);
+
+      umul_ppmm (ch, cl, rl, B2modb);
+      add_ssaaaa (ph, pl, ph, pl, ch, cl);
+
+      umul_ppmm (rh, rl, rh, B3modb);
+      add_ssaaaa (rh, rl, rh, rl, ph, pl);
+    }
+
+  umul_ppmm (rh, cl, rh, B1modb);
+  add_ssaaaa (rh, rl, rh, rl, CNST_LIMB(0), cl);
+
+  cnt = cps[1];
+  bi = cps[0];
+
+  r = (rh << cnt) | (rl >> (GMP_LIMB_BITS - cnt));
+  udiv_rnnd_preinv (r, r, rl << cnt, b, bi);
+
+  return r >> cnt;
+}
diff --git a/third_party/gmp/mpn/generic/mod_1_3.c b/third_party/gmp/mpn/generic/mod_1_3.c
new file mode 100644
index 0000000..4d4be5d
--- /dev/null
+++ b/third_party/gmp/mpn/generic/mod_1_3.c
@@ -0,0 +1,156 @@
+/* mpn_mod_1s_3p (ap, n, b, cps)
+   Divide (ap,,n) by b.  Return the single-limb remainder.
+   Requires that b < B / 3.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+   Based on a suggestion by Peter L. Montgomery.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2008-2010, 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+void
+mpn_mod_1s_3p_cps (mp_limb_t cps[6], mp_limb_t b)
+{
+  mp_limb_t bi;
+  mp_limb_t B1modb, B2modb, B3modb, B4modb;
+  int cnt;
+
+  ASSERT (b <= (~(mp_limb_t) 0) / 3);
+
+  count_leading_zeros (cnt, b);
+
+  b <<= cnt;
+  invert_limb (bi, b);
+
+  cps[0] = bi;
+  cps[1] = cnt;
+
+  B1modb = -b * ((bi >> (GMP_LIMB_BITS-cnt)) | (CNST_LIMB(1) << cnt));
+  ASSERT (B1modb <= b);		/* NB: not fully reduced mod b */
+  cps[2] = B1modb >> cnt;
+
+  udiv_rnnd_preinv (B2modb, B1modb, CNST_LIMB(0), b, bi);
+  cps[3] = B2modb >> cnt;
+
+  udiv_rnnd_preinv (B3modb, B2modb, CNST_LIMB(0), b, bi);
+  cps[4] = B3modb >> cnt;
+
+  udiv_rnnd_preinv (B4modb, B3modb, CNST_LIMB(0), b, bi);
+  cps[5] = B4modb >> cnt;
+
+#if WANT_ASSERT
+  {
+    int i;
+    b = cps[2];
+    for (i = 3; i <= 5; i++)
+      {
+	b += cps[i];
+	ASSERT (b >= cps[i]);
+      }
+  }
+#endif
+}
+
+mp_limb_t
+mpn_mod_1s_3p (mp_srcptr ap, mp_size_t n, mp_limb_t b, const mp_limb_t cps[6])
+{
+  mp_limb_t rh, rl, bi, ph, pl, ch, cl, r;
+  mp_limb_t B1modb, B2modb, B3modb, B4modb;
+  mp_size_t i;
+  int cnt;
+
+  ASSERT (n >= 1);
+
+  B1modb = cps[2];
+  B2modb = cps[3];
+  B3modb = cps[4];
+  B4modb = cps[5];
+
+  /* We compute n mod 3 in a tricky way, which works except for when n is so
+     close to the maximum size that we don't need to support it.  The final
+     cast to int is a workaround for HP cc.  */
+  switch ((int) ((mp_limb_t) n * MODLIMB_INVERSE_3 >> (GMP_NUMB_BITS - 2)))
+    {
+    case 0:
+      umul_ppmm (ph, pl, ap[n - 2], B1modb);
+      add_ssaaaa (ph, pl, ph, pl, CNST_LIMB(0), ap[n - 3]);
+      umul_ppmm (rh, rl, ap[n - 1], B2modb);
+      add_ssaaaa (rh, rl, rh, rl, ph, pl);
+      n -= 3;
+      break;
+    case 2:	/* n mod 3 = 1 */
+      rh = 0;
+      rl = ap[n - 1];
+      n -= 1;
+      break;
+    case 1:	/* n mod 3 = 2 */
+      rh = ap[n - 1];
+      rl = ap[n - 2];
+      n -= 2;
+      break;
+    }
+
+  for (i = n - 3; i >= 0; i -= 3)
+    {
+      /* rr = ap[i]				< B
+	    + ap[i+1] * (B mod b)		<= (B-1)(b-1)
+	    + ap[i+2] * (B^2 mod b)		<= (B-1)(b-1)
+	    + LO(rr)  * (B^3 mod b)		<= (B-1)(b-1)
+	    + HI(rr)  * (B^4 mod b)		<= (B-1)(b-1)
+      */
+      umul_ppmm (ph, pl, ap[i + 1], B1modb);
+      add_ssaaaa (ph, pl, ph, pl, CNST_LIMB(0), ap[i + 0]);
+
+      umul_ppmm (ch, cl, ap[i + 2], B2modb);
+      add_ssaaaa (ph, pl, ph, pl, ch, cl);
+
+      umul_ppmm (ch, cl, rl, B3modb);
+      add_ssaaaa (ph, pl, ph, pl, ch, cl);
+
+      umul_ppmm (rh, rl, rh, B4modb);
+      add_ssaaaa (rh, rl, rh, rl, ph, pl);
+    }
+
+  umul_ppmm (rh, cl, rh, B1modb);
+  add_ssaaaa (rh, rl, rh, rl, CNST_LIMB(0), cl);
+
+  cnt = cps[1];
+  bi = cps[0];
+
+  r = (rh << cnt) | (rl >> (GMP_LIMB_BITS - cnt));
+  udiv_rnnd_preinv (r, r, rl << cnt, b, bi);
+
+  return r >> cnt;
+}
diff --git a/third_party/gmp/mpn/generic/mod_1_4.c b/third_party/gmp/mpn/generic/mod_1_4.c
new file mode 100644
index 0000000..80b42ba
--- /dev/null
+++ b/third_party/gmp/mpn/generic/mod_1_4.c
@@ -0,0 +1,170 @@
+/* mpn_mod_1s_4p (ap, n, b, cps)
+   Divide (ap,,n) by b.  Return the single-limb remainder.
+   Requires that b < B / 4.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+   Based on a suggestion by Peter L. Montgomery.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2008-2010 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+void
+mpn_mod_1s_4p_cps (mp_limb_t cps[7], mp_limb_t b)
+{
+  mp_limb_t bi;
+  mp_limb_t B1modb, B2modb, B3modb, B4modb, B5modb;
+  int cnt;
+
+  ASSERT (b <= (~(mp_limb_t) 0) / 4);
+
+  count_leading_zeros (cnt, b);
+
+  b <<= cnt;
+  invert_limb (bi, b);
+
+  cps[0] = bi;
+  cps[1] = cnt;
+
+  B1modb = -b * ((bi >> (GMP_LIMB_BITS-cnt)) | (CNST_LIMB(1) << cnt));
+  ASSERT (B1modb <= b);		/* NB: not fully reduced mod b */
+  cps[2] = B1modb >> cnt;
+
+  udiv_rnnd_preinv (B2modb, B1modb, CNST_LIMB(0), b, bi);
+  cps[3] = B2modb >> cnt;
+
+  udiv_rnnd_preinv (B3modb, B2modb, CNST_LIMB(0), b, bi);
+  cps[4] = B3modb >> cnt;
+
+  udiv_rnnd_preinv (B4modb, B3modb, CNST_LIMB(0), b, bi);
+  cps[5] = B4modb >> cnt;
+
+  udiv_rnnd_preinv (B5modb, B4modb, CNST_LIMB(0), b, bi);
+  cps[6] = B5modb >> cnt;
+
+#if WANT_ASSERT
+  {
+    int i;
+    b = cps[2];
+    for (i = 3; i <= 6; i++)
+      {
+	b += cps[i];
+	ASSERT (b >= cps[i]);
+      }
+  }
+#endif
+}
+
+mp_limb_t
+mpn_mod_1s_4p (mp_srcptr ap, mp_size_t n, mp_limb_t b, const mp_limb_t cps[7])
+{
+  mp_limb_t rh, rl, bi, ph, pl, ch, cl, r;
+  mp_limb_t B1modb, B2modb, B3modb, B4modb, B5modb;
+  mp_size_t i;
+  int cnt;
+
+  ASSERT (n >= 1);
+
+  B1modb = cps[2];
+  B2modb = cps[3];
+  B3modb = cps[4];
+  B4modb = cps[5];
+  B5modb = cps[6];
+
+  switch (n & 3)
+    {
+    case 0:
+      umul_ppmm (ph, pl, ap[n - 3], B1modb);
+      add_ssaaaa (ph, pl, ph, pl, CNST_LIMB(0), ap[n - 4]);
+      umul_ppmm (ch, cl, ap[n - 2], B2modb);
+      add_ssaaaa (ph, pl, ph, pl, ch, cl);
+      umul_ppmm (rh, rl, ap[n - 1], B3modb);
+      add_ssaaaa (rh, rl, rh, rl, ph, pl);
+      n -= 4;
+      break;
+    case 1:
+      rh = 0;
+      rl = ap[n - 1];
+      n -= 1;
+      break;
+    case 2:
+      rh = ap[n - 1];
+      rl = ap[n - 2];
+      n -= 2;
+      break;
+    case 3:
+      umul_ppmm (ph, pl, ap[n - 2], B1modb);
+      add_ssaaaa (ph, pl, ph, pl, CNST_LIMB(0), ap[n - 3]);
+      umul_ppmm (rh, rl, ap[n - 1], B2modb);
+      add_ssaaaa (rh, rl, rh, rl, ph, pl);
+      n -= 3;
+      break;
+    }
+
+  for (i = n - 4; i >= 0; i -= 4)
+    {
+      /* rr = ap[i]				< B
+	    + ap[i+1] * (B mod b)		<= (B-1)(b-1)
+	    + ap[i+2] * (B^2 mod b)		<= (B-1)(b-1)
+	    + ap[i+3] * (B^3 mod b)		<= (B-1)(b-1)
+	    + LO(rr)  * (B^4 mod b)		<= (B-1)(b-1)
+	    + HI(rr)  * (B^5 mod b)		<= (B-1)(b-1)
+      */
+      umul_ppmm (ph, pl, ap[i + 1], B1modb);
+      add_ssaaaa (ph, pl, ph, pl, CNST_LIMB(0), ap[i + 0]);
+
+      umul_ppmm (ch, cl, ap[i + 2], B2modb);
+      add_ssaaaa (ph, pl, ph, pl, ch, cl);
+
+      umul_ppmm (ch, cl, ap[i + 3], B3modb);
+      add_ssaaaa (ph, pl, ph, pl, ch, cl);
+
+      umul_ppmm (ch, cl, rl, B4modb);
+      add_ssaaaa (ph, pl, ph, pl, ch, cl);
+
+      umul_ppmm (rh, rl, rh, B5modb);
+      add_ssaaaa (rh, rl, rh, rl, ph, pl);
+    }
+
+  umul_ppmm (rh, cl, rh, B1modb);
+  add_ssaaaa (rh, rl, rh, rl, CNST_LIMB(0), cl);
+
+  cnt = cps[1];
+  bi = cps[0];
+
+  r = (rh << cnt) | (rl >> (GMP_LIMB_BITS - cnt));
+  udiv_rnnd_preinv (r, r, rl << cnt, b, bi);
+
+  return r >> cnt;
+}
diff --git a/third_party/gmp/mpn/generic/mod_34lsub1.c b/third_party/gmp/mpn/generic/mod_34lsub1.c
new file mode 100644
index 0000000..af9c6c6
--- /dev/null
+++ b/third_party/gmp/mpn/generic/mod_34lsub1.c
@@ -0,0 +1,128 @@
+/* mpn_mod_34lsub1 -- remainder modulo 2^(GMP_NUMB_BITS*3/4)-1.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+
+/* Calculate a remainder from {p,n} divided by 2^(GMP_NUMB_BITS*3/4)-1.
+   The remainder is not fully reduced, it's any limb value congruent to
+   {p,n} modulo that divisor.
+
+   This implementation is only correct when GMP_NUMB_BITS is a multiple of
+   4.
+
+   FIXME: If GMP_NAIL_BITS is some silly big value during development then
+   it's possible the carry accumulators c0,c1,c2 could overflow.
+
+   General notes:
+
+   The basic idea is to use a set of N accumulators (N=3 in this case) to
+   effectively get a remainder mod 2^(GMP_NUMB_BITS*N)-1 followed at the end
+   by a reduction to GMP_NUMB_BITS*N/M bits (M=4 in this case) for a
+   remainder mod 2^(GMP_NUMB_BITS*N/M)-1.  N and M are chosen to give a good
+   set of small prime factors in 2^(GMP_NUMB_BITS*N/M)-1.
+
+   N=3 M=4 suits GMP_NUMB_BITS==32 and GMP_NUMB_BITS==64 quite well, giving
+   a few more primes than a single accumulator N=1 does, and for no extra
+   cost (assuming the processor has a decent number of registers).
+
+   For strange nailified values of GMP_NUMB_BITS the idea would be to look
+   for what N and M give good primes.  With GMP_NUMB_BITS not a power of 2
+   the choices for M may be opened up a bit.  But such things are probably
+   best done in separate code, not grafted on here.  */
+
+#if GMP_NUMB_BITS % 4 == 0
+
+#define B1  (GMP_NUMB_BITS / 4)
+#define B2  (B1 * 2)
+#define B3  (B1 * 3)
+
+#define M1  ((CNST_LIMB(1) << B1) - 1)
+#define M2  ((CNST_LIMB(1) << B2) - 1)
+#define M3  ((CNST_LIMB(1) << B3) - 1)
+
+#define LOW0(n)      ((n) & M3)
+#define HIGH0(n)     ((n) >> B3)
+
+#define LOW1(n)      (((n) & M2) << B1)
+#define HIGH1(n)     ((n) >> B2)
+
+#define LOW2(n)      (((n) & M1) << B2)
+#define HIGH2(n)     ((n) >> B1)
+
+#define PARTS0(n)    (LOW0(n) + HIGH0(n))
+#define PARTS1(n)    (LOW1(n) + HIGH1(n))
+#define PARTS2(n)    (LOW2(n) + HIGH2(n))
+
+#define ADD(c,a,val)                    \
+  do {                                  \
+    mp_limb_t  new_c;                   \
+    ADDC_LIMB (new_c, a, a, val);       \
+    (c) += new_c;                       \
+  } while (0)
+
+mp_limb_t
+mpn_mod_34lsub1 (mp_srcptr p, mp_size_t n)
+{
+  mp_limb_t  c0, c1, c2;
+  mp_limb_t  a0, a1, a2;
+
+  ASSERT (n >= 1);
+  ASSERT (n/3 < GMP_NUMB_MAX);
+
+  a0 = a1 = a2 = 0;
+  c0 = c1 = c2 = 0;
+
+  while ((n -= 3) >= 0)
+    {
+      ADD (c0, a0, p[0]);
+      ADD (c1, a1, p[1]);
+      ADD (c2, a2, p[2]);
+      p += 3;
+    }
+
+  if (n != -3)
+    {
+      ADD (c0, a0, p[0]);
+      if (n != -2)
+	ADD (c1, a1, p[1]);
+    }
+
+  return
+    PARTS0 (a0) + PARTS1 (a1) + PARTS2 (a2)
+    + PARTS1 (c0) + PARTS2 (c1) + PARTS0 (c2);
+}
+
+#endif
diff --git a/third_party/gmp/mpn/generic/mode1o.c b/third_party/gmp/mpn/generic/mode1o.c
new file mode 100644
index 0000000..9ba0ae1
--- /dev/null
+++ b/third_party/gmp/mpn/generic/mode1o.c
@@ -0,0 +1,235 @@
+/* mpn_modexact_1c_odd -- mpn by limb exact division style remainder.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2000-2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* Calculate an r satisfying
+
+           r*B^k + a - c == q*d
+
+   where B=2^GMP_LIMB_BITS, a is {src,size}, k is either size or size-1
+   (the caller won't know which), and q is the quotient (discarded).  d must
+   be odd, c can be any limb value.
+
+   If c<d then r will be in the range 0<=r<d, or if c>=d then 0<=r<=d.
+
+   This slightly strange function suits the initial Nx1 reduction for GCDs
+   or Jacobi symbols since the factors of 2 in B^k can be ignored, leaving
+   -r == a mod d (by passing c=0).  For a GCD the factor of -1 on r can be
+   ignored, or for the Jacobi symbol it can be accounted for.  The function
+   also suits divisibility and congruence testing since if r=0 (or r=d) is
+   obtained then a==c mod d.
+
+
+   r is a bit like the remainder returned by mpn_divexact_by3c, and is the
+   sort of remainder mpn_divexact_1 might return.  Like mpn_divexact_by3c, r
+   represents a borrow, since effectively quotient limbs are chosen so that
+   subtracting that multiple of d from src at each step will produce a zero
+   limb.
+
+   A long calculation can be done piece by piece from low to high by passing
+   the return value from one part as the carry parameter to the next part.
+   The effective final k becomes anything between size and size-n, if n
+   pieces are used.
+
+
+   A similar sort of routine could be constructed based on adding multiples
+   of d at each limb, much like redc in mpz_powm does.  Subtracting however
+   has a small advantage that when subtracting to cancel out l there's never
+   a borrow into h, whereas using an addition would put a carry into h
+   depending whether l==0 or l!=0.
+
+
+   In terms of efficiency, this function is similar to a mul-by-inverse
+   mpn_mod_1.  Both are essentially two multiplies and are best suited to
+   CPUs with low latency multipliers (in comparison to a divide instruction
+   at least.)  But modexact has a few less supplementary operations, only
+   needs low part and high part multiplies, and has fewer working quantities
+   (helping CPUs with few registers).
+
+
+   In the main loop it will be noted that the new carry (call it r) is the
+   sum of the high product h and any borrow from l=s-c.  If c<d then we will
+   have r<d too, for the following reasons.  Let q=l*inverse be the quotient
+   limb, so that q*d = B*h + l, where B=2^GMP_NUMB_BITS.  Now if h=d-1 then
+
+       l = q*d - B*(d-1) <= (B-1)*d - B*(d-1) = B-d
+
+   But if l=s-c produces a borrow when c<d, then l>=B-d+1 and hence will
+   never have h=d-1 and so r=h+borrow <= d-1.
+
+   When c>=d, on the other hand, h=d-1 can certainly occur together with a
+   borrow, thereby giving only r<=d, as per the function definition above.
+
+   As a design decision it's left to the caller to check for r=d if it might
+   be passing c>=d.  Several applications have c<d initially so the extra
+   test is often unnecessary, for example the GCDs or a plain divisibility
+   d|a test will pass c=0.
+
+
+   The special case for size==1 is so that it can be assumed c<=d in the
+   high<=divisor test at the end.  c<=d is only guaranteed after at least
+   one iteration of the main loop.  There's also a decent chance one % is
+   faster than a binvert_limb, though that will depend on the processor.
+
+   A CPU specific implementation might want to omit the size==1 code or the
+   high<divisor test.  mpn/x86/k6/mode1o.asm for instance finds neither
+   useful.  */
+
+
+mp_limb_t
+mpn_modexact_1c_odd (mp_srcptr src, mp_size_t size, mp_limb_t d,
+                     mp_limb_t orig_c)
+{
+  mp_limb_t  s, h, l, inverse, dummy, dmul, ret;
+  mp_limb_t  c = orig_c;
+  mp_size_t  i;
+
+  ASSERT (size >= 1);
+  ASSERT (d & 1);
+  ASSERT_MPN (src, size);
+  ASSERT_LIMB (d);
+  ASSERT_LIMB (c);
+
+  if (size == 1)
+    {
+      s = src[0];
+      if (s > c)
+	{
+	  l = s-c;
+	  h = l % d;
+	  if (h != 0)
+	    h = d - h;
+	}
+      else
+	{
+	  l = c-s;
+	  h = l % d;
+	}
+      return h;
+    }
+
+
+  binvert_limb (inverse, d);
+  dmul = d << GMP_NAIL_BITS;
+
+  i = 0;
+  do
+    {
+      s = src[i];
+      SUBC_LIMB (c, l, s, c);
+      l = (l * inverse) & GMP_NUMB_MASK;
+      umul_ppmm (h, dummy, l, dmul);
+      c += h;
+    }
+  while (++i < size-1);
+
+
+  s = src[i];
+  if (s <= d)
+    {
+      /* With high<=d the final step can be a subtract and addback.  If c==0
+	 then the addback will restore to l>=0.  If c==d then will get l==d
+	 if s==0, but that's ok per the function definition.  */
+
+      l = c - s;
+      if (c < s)
+	l += d;
+
+      ret = l;
+    }
+  else
+    {
+      /* Can't skip a divide, just do the loop code once more. */
+
+      SUBC_LIMB (c, l, s, c);
+      l = (l * inverse) & GMP_NUMB_MASK;
+      umul_ppmm (h, dummy, l, dmul);
+      c += h;
+      ret = c;
+    }
+
+  ASSERT (orig_c < d ? ret < d : ret <= d);
+  return ret;
+}
+
+
+
+#if 0
+
+/* The following is an alternate form that might shave one cycle on a
+   superscalar processor since it takes c+=h off the dependent chain,
+   leaving just a low product, high product, and a subtract.
+
+   This is for CPU specific implementations to consider.  A special case for
+   high<divisor and/or size==1 can be added if desired.
+
+   Notice that c is only ever 0 or 1, since if s-c produces a borrow then
+   x=0xFF..FF and x-h cannot produce a borrow.  The c=(x>s) could become
+   c=(x==0xFF..FF) too, if that helped.  */
+
+mp_limb_t
+mpn_modexact_1c_odd (mp_srcptr src, mp_size_t size, mp_limb_t d, mp_limb_t h)
+{
+  mp_limb_t  s, x, y, inverse, dummy, dmul, c1, c2;
+  mp_limb_t  c = 0;
+  mp_size_t  i;
+
+  ASSERT (size >= 1);
+  ASSERT (d & 1);
+
+  binvert_limb (inverse, d);
+  dmul = d << GMP_NAIL_BITS;
+
+  for (i = 0; i < size; i++)
+    {
+      ASSERT (c==0 || c==1);
+
+      s = src[i];
+      SUBC_LIMB (c1, x, s, c);
+
+      SUBC_LIMB (c2, y, x, h);
+      c = c1 + c2;
+
+      y = (y * inverse) & GMP_NUMB_MASK;
+      umul_ppmm (h, dummy, y, dmul);
+    }
+
+  h += c;
+  return h;
+}
+
+#endif
diff --git a/third_party/gmp/mpn/generic/mu_bdiv_q.c b/third_party/gmp/mpn/generic/mu_bdiv_q.c
new file mode 100644
index 0000000..0ef3bd8
--- /dev/null
+++ b/third_party/gmp/mpn/generic/mu_bdiv_q.c
@@ -0,0 +1,281 @@
+/* mpn_mu_bdiv_q(qp,np,nn,dp,dn,tp) -- Compute {np,nn} / {dp,dn} mod B^nn.
+   storing the result in {qp,nn}.  Overlap allowed between Q and N; all other
+   overlap disallowed.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright 2005-2007, 2009, 2010, 2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+/*
+   The idea of the algorithm used herein is to compute a smaller inverted value
+   than used in the standard Barrett algorithm, and thus save time in the
+   Newton iterations, and pay just a small price when using the inverted value
+   for developing quotient bits.  This algorithm was presented at ICMS 2006.
+*/
+
+#include "gmp-impl.h"
+
+
+/* N = {np,nn}
+   D = {dp,dn}
+
+   Requirements: N >= D
+		 D >= 1
+		 D odd
+		 dn >= 2
+		 nn >= 2
+		 scratch space as determined by mpn_mu_bdiv_q_itch(nn,dn).
+
+   Write quotient to Q = {qp,nn}.
+
+   FIXME: When iterating, perhaps do the small step before loop, not after.
+   FIXME: Try to avoid the scalar divisions when computing inverse size.
+   FIXME: Trim allocation for (qn > dn) case, 3*dn might be possible.  In
+	  particular, when dn==in, tp and rp could use the same space.
+   FIXME: Trim final quotient calculation to qn limbs of precision.
+*/
+static void
+mpn_mu_bdiv_q_old (mp_ptr qp,
+	       mp_srcptr np, mp_size_t nn,
+	       mp_srcptr dp, mp_size_t dn,
+	       mp_ptr scratch)
+{
+  mp_size_t qn;
+  mp_size_t in;
+  int cy, c0;
+  mp_size_t tn, wn;
+
+  qn = nn;
+
+  ASSERT (dn >= 2);
+  ASSERT (qn >= 2);
+
+  if (qn > dn)
+    {
+      mp_size_t b;
+
+      /* |_______________________|   dividend
+			|________|   divisor  */
+
+#define ip           scratch			/* in */
+#define rp           (scratch + in)		/* dn or rest >= binvert_itch(in) */
+#define tp           (scratch + in + dn)	/* dn+in or next_size(dn) */
+#define scratch_out  (scratch + in + dn + tn)	/* mulmod_bnm1_itch(next_size(dn)) */
+
+      /* Compute an inverse size that is a nice partition of the quotient.  */
+      b = (qn - 1) / dn + 1;	/* ceil(qn/dn), number of blocks */
+      in = (qn - 1) / b + 1;	/* ceil(qn/b) = ceil(qn / ceil(qn/dn)) */
+
+      /* Some notes on allocation:
+
+	 When in = dn, R dies when mpn_mullo returns, if in < dn the low in
+	 limbs of R dies at that point.  We could save memory by letting T live
+	 just under R, and let the upper part of T expand into R. These changes
+	 should reduce itch to perhaps 3dn.
+       */
+
+      mpn_binvert (ip, dp, in, rp);
+
+      cy = 0;
+
+      MPN_COPY (rp, np, dn);
+      np += dn;
+      mpn_mullo_n (qp, rp, ip, in);
+      qn -= in;
+
+      while (qn > in)
+	{
+	  if (BELOW_THRESHOLD (in, MUL_TO_MULMOD_BNM1_FOR_2NXN_THRESHOLD))
+	    mpn_mul (tp, dp, dn, qp, in);	/* mulhi, need tp[dn+in-1...in] */
+	  else
+	    {
+	      tn = mpn_mulmod_bnm1_next_size (dn);
+	      mpn_mulmod_bnm1 (tp, tn, dp, dn, qp, in, scratch_out);
+	      wn = dn + in - tn;		/* number of wrapped limbs */
+	      if (wn > 0)
+		{
+		  c0 = mpn_sub_n (tp + tn, tp, rp, wn);
+		  mpn_decr_u (tp + wn, c0);
+		}
+	    }
+
+	  qp += in;
+	  if (dn != in)
+	    {
+	      /* Subtract tp[dn-1...in] from partial remainder.  */
+	      cy += mpn_sub_n (rp, rp + in, tp + in, dn - in);
+	      if (cy == 2)
+		{
+		  mpn_incr_u (tp + dn, 1);
+		  cy = 1;
+		}
+	    }
+	  /* Subtract tp[dn+in-1...dn] from dividend.  */
+	  cy = mpn_sub_nc (rp + dn - in, np, tp + dn, in, cy);
+	  np += in;
+	  mpn_mullo_n (qp, rp, ip, in);
+	  qn -= in;
+	}
+
+      /* Generate last qn limbs.
+	 FIXME: It should be possible to limit precision here, since qn is
+	 typically somewhat smaller than dn.  No big gains expected.  */
+
+      if (BELOW_THRESHOLD (in, MUL_TO_MULMOD_BNM1_FOR_2NXN_THRESHOLD))
+	mpn_mul (tp, dp, dn, qp, in);		/* mulhi, need tp[qn+in-1...in] */
+      else
+	{
+	  tn = mpn_mulmod_bnm1_next_size (dn);
+	  mpn_mulmod_bnm1 (tp, tn, dp, dn, qp, in, scratch_out);
+	  wn = dn + in - tn;			/* number of wrapped limbs */
+	  if (wn > 0)
+	    {
+	      c0 = mpn_sub_n (tp + tn, tp, rp, wn);
+	      mpn_decr_u (tp + wn, c0);
+	    }
+	}
+
+      qp += in;
+      if (dn != in)
+	{
+	  cy += mpn_sub_n (rp, rp + in, tp + in, dn - in);
+	  if (cy == 2)
+	    {
+	      mpn_incr_u (tp + dn, 1);
+	      cy = 1;
+	    }
+	}
+
+      mpn_sub_nc (rp + dn - in, np, tp + dn, qn - (dn - in), cy);
+      mpn_mullo_n (qp, rp, ip, qn);
+
+#undef ip
+#undef rp
+#undef tp
+#undef scratch_out
+   }
+  else
+    {
+      /* |_______________________|   dividend
+		|________________|   divisor  */
+
+#define ip           scratch		/* in */
+#define tp           (scratch + in)	/* qn+in or next_size(qn) or rest >= binvert_itch(in) */
+#define scratch_out  (scratch + in + tn)/* mulmod_bnm1_itch(next_size(qn)) */
+
+      /* Compute half-sized inverse.  */
+      in = qn - (qn >> 1);
+
+      mpn_binvert (ip, dp, in, tp);
+
+      mpn_mullo_n (qp, np, ip, in);		/* low `in' quotient limbs */
+
+      if (BELOW_THRESHOLD (in, MUL_TO_MULMOD_BNM1_FOR_2NXN_THRESHOLD))
+	mpn_mul (tp, dp, qn, qp, in);		/* mulhigh */
+      else
+	{
+	  tn = mpn_mulmod_bnm1_next_size (qn);
+	  mpn_mulmod_bnm1 (tp, tn, dp, qn, qp, in, scratch_out);
+	  wn = qn + in - tn;			/* number of wrapped limbs */
+	  if (wn > 0)
+	    {
+	      c0 = mpn_cmp (tp, np, wn) < 0;
+	      mpn_decr_u (tp + wn, c0);
+	    }
+	}
+
+      mpn_sub_n (tp, np + in, tp + in, qn - in);
+      mpn_mullo_n (qp + in, tp, ip, qn - in);	/* high qn-in quotient limbs */
+
+#undef ip
+#undef tp
+#undef scratch_out
+    }
+}
+
+void
+mpn_mu_bdiv_q (mp_ptr qp,
+	       mp_srcptr np, mp_size_t nn,
+	       mp_srcptr dp, mp_size_t dn,
+	       mp_ptr scratch)
+{
+  mpn_mu_bdiv_q_old (qp, np, nn, dp, dn, scratch);
+  mpn_neg (qp, qp, nn);
+}
+
+mp_size_t
+mpn_mu_bdiv_q_itch (mp_size_t nn, mp_size_t dn)
+{
+  mp_size_t qn, in, tn, itch_binvert, itch_out, itches;
+  mp_size_t b;
+
+  ASSERT_ALWAYS (DC_BDIV_Q_THRESHOLD < MU_BDIV_Q_THRESHOLD);
+
+  qn = nn;
+
+  if (qn > dn)
+    {
+      b = (qn - 1) / dn + 1;	/* ceil(qn/dn), number of blocks */
+      in = (qn - 1) / b + 1;	/* ceil(qn/b) = ceil(qn / ceil(qn/dn)) */
+      if (BELOW_THRESHOLD (in, MUL_TO_MULMOD_BNM1_FOR_2NXN_THRESHOLD))
+	{
+	  tn = dn + in;
+	  itch_out = 0;
+	}
+      else
+	{
+	  tn = mpn_mulmod_bnm1_next_size (dn);
+	  itch_out = mpn_mulmod_bnm1_itch (tn, dn, in);
+	}
+      itches = dn + tn + itch_out;
+    }
+  else
+    {
+      in = qn - (qn >> 1);
+      if (BELOW_THRESHOLD (in, MUL_TO_MULMOD_BNM1_FOR_2NXN_THRESHOLD))
+	{
+	  tn = qn + in;
+	  itch_out = 0;
+	}
+      else
+	{
+	  tn = mpn_mulmod_bnm1_next_size (qn);
+	  itch_out = mpn_mulmod_bnm1_itch (tn, qn, in);
+	}
+      itches = tn + itch_out;
+    }
+
+  itch_binvert = mpn_binvert_itch (in);
+  return in + MAX (itches, itch_binvert);
+}
diff --git a/third_party/gmp/mpn/generic/mu_bdiv_qr.c b/third_party/gmp/mpn/generic/mu_bdiv_qr.c
new file mode 100644
index 0000000..540ad73
--- /dev/null
+++ b/third_party/gmp/mpn/generic/mu_bdiv_qr.c
@@ -0,0 +1,312 @@
+/* mpn_mu_bdiv_qr(qp,rp,np,nn,dp,dn,tp) -- Compute {np,nn} / {dp,dn} mod B^qn,
+   where qn = nn-dn, storing the result in {qp,qn}.  Overlap allowed between Q
+   and N; all other overlap disallowed.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright 2005-2007, 2009, 2010, 2012, 2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+/*
+   The idea of the algorithm used herein is to compute a smaller inverted value
+   than used in the standard Barrett algorithm, and thus save time in the
+   Newton iterations, and pay just a small price when using the inverted value
+   for developing quotient bits.  This algorithm was presented at ICMS 2006.
+*/
+
+#include "gmp-impl.h"
+
+
+/* N = {np,nn}
+   D = {dp,dn}
+
+   Requirements: N >= D
+		 D >= 1
+		 D odd
+		 dn >= 2
+		 nn >= 2
+		 scratch space as determined by mpn_mu_bdiv_qr_itch(nn,dn).
+
+   Write quotient to Q = {qp,nn-dn}.
+
+   FIXME: When iterating, perhaps do the small step before loop, not after.
+   FIXME: Try to avoid the scalar divisions when computing inverse size.
+   FIXME: Trim allocation for (qn > dn) case, 3*dn might be possible.  In
+	  particular, when dn==in, tp and rp could use the same space.
+*/
+static mp_limb_t
+mpn_mu_bdiv_qr_old (mp_ptr qp,
+		    mp_ptr rp,
+		    mp_srcptr np, mp_size_t nn,
+		    mp_srcptr dp, mp_size_t dn,
+		    mp_ptr scratch)
+{
+  mp_size_t qn;
+  mp_size_t in;
+  mp_limb_t cy, c0;
+  mp_size_t tn, wn;
+
+  qn = nn - dn;
+
+  ASSERT (dn >= 2);
+  ASSERT (qn >= 2);
+
+  if (qn > dn)
+    {
+      mp_size_t b;
+
+      /* |_______________________|   dividend
+			|________|   divisor  */
+
+#define ip           scratch		/* in */
+#define tp           (scratch + in)	/* dn+in or next_size(dn) or rest >= binvert_itch(in) */
+#define scratch_out  (scratch + in + tn)/* mulmod_bnm1_itch(next_size(dn)) */
+
+      /* Compute an inverse size that is a nice partition of the quotient.  */
+      b = (qn - 1) / dn + 1;	/* ceil(qn/dn), number of blocks */
+      in = (qn - 1) / b + 1;	/* ceil(qn/b) = ceil(qn / ceil(qn/dn)) */
+
+      /* Some notes on allocation:
+
+	 When in = dn, R dies when mpn_mullo returns, if in < dn the low in
+	 limbs of R dies at that point.  We could save memory by letting T live
+	 just under R, and let the upper part of T expand into R. These changes
+	 should reduce itch to perhaps 3dn.
+       */
+
+      mpn_binvert (ip, dp, in, tp);
+
+      MPN_COPY (rp, np, dn);
+      np += dn;
+      cy = 0;
+
+      while (qn > in)
+	{
+	  mpn_mullo_n (qp, rp, ip, in);
+
+	  if (BELOW_THRESHOLD (in, MUL_TO_MULMOD_BNM1_FOR_2NXN_THRESHOLD))
+	    mpn_mul (tp, dp, dn, qp, in);	/* mulhi, need tp[dn+in-1...in] */
+	  else
+	    {
+	      tn = mpn_mulmod_bnm1_next_size (dn);
+	      mpn_mulmod_bnm1 (tp, tn, dp, dn, qp, in, scratch_out);
+	      wn = dn + in - tn;		/* number of wrapped limbs */
+	      if (wn > 0)
+		{
+		  c0 = mpn_sub_n (tp + tn, tp, rp, wn);
+		  mpn_decr_u (tp + wn, c0);
+		}
+	    }
+
+	  qp += in;
+	  qn -= in;
+
+	  if (dn != in)
+	    {
+	      /* Subtract tp[dn-1...in] from partial remainder.  */
+	      cy += mpn_sub_n (rp, rp + in, tp + in, dn - in);
+	      if (cy == 2)
+		{
+		  mpn_incr_u (tp + dn, 1);
+		  cy = 1;
+		}
+	    }
+	  /* Subtract tp[dn+in-1...dn] from dividend.  */
+	  cy = mpn_sub_nc (rp + dn - in, np, tp + dn, in, cy);
+	  np += in;
+	}
+
+      /* Generate last qn limbs.  */
+      mpn_mullo_n (qp, rp, ip, qn);
+
+      if (BELOW_THRESHOLD (qn, MUL_TO_MULMOD_BNM1_FOR_2NXN_THRESHOLD))
+	mpn_mul (tp, dp, dn, qp, qn);		/* mulhi, need tp[qn+in-1...in] */
+      else
+	{
+	  tn = mpn_mulmod_bnm1_next_size (dn);
+	  mpn_mulmod_bnm1 (tp, tn, dp, dn, qp, qn, scratch_out);
+	  wn = dn + qn - tn;			/* number of wrapped limbs */
+	  if (wn > 0)
+	    {
+	      c0 = mpn_sub_n (tp + tn, tp, rp, wn);
+	      mpn_decr_u (tp + wn, c0);
+	    }
+	}
+
+      if (dn != qn)
+	{
+	  cy += mpn_sub_n (rp, rp + qn, tp + qn, dn - qn);
+	  if (cy == 2)
+	    {
+	      mpn_incr_u (tp + dn, 1);
+	      cy = 1;
+	    }
+	}
+      return mpn_sub_nc (rp + dn - qn, np, tp + dn, qn, cy);
+
+#undef ip
+#undef tp
+#undef scratch_out
+    }
+  else
+    {
+      /* |_______________________|   dividend
+		|________________|   divisor  */
+
+#define ip           scratch		/* in */
+#define tp           (scratch + in)	/* dn+in or next_size(dn) or rest >= binvert_itch(in) */
+#define scratch_out  (scratch + in + tn)/* mulmod_bnm1_itch(next_size(dn)) */
+
+      /* Compute half-sized inverse.  */
+      in = qn - (qn >> 1);
+
+      mpn_binvert (ip, dp, in, tp);
+
+      mpn_mullo_n (qp, np, ip, in);		/* low `in' quotient limbs */
+
+      if (BELOW_THRESHOLD (in, MUL_TO_MULMOD_BNM1_FOR_2NXN_THRESHOLD))
+	mpn_mul (tp, dp, dn, qp, in);		/* mulhigh */
+      else
+	{
+	  tn = mpn_mulmod_bnm1_next_size (dn);
+	  mpn_mulmod_bnm1 (tp, tn, dp, dn, qp, in, scratch_out);
+	  wn = dn + in - tn;			/* number of wrapped limbs */
+	  if (wn > 0)
+	    {
+	      c0 = mpn_sub_n (tp + tn, tp, np, wn);
+	      mpn_decr_u (tp + wn, c0);
+	    }
+	}
+
+      qp += in;
+      qn -= in;
+
+      cy = mpn_sub_n (rp, np + in, tp + in, dn);
+      mpn_mullo_n (qp, rp, ip, qn);		/* high qn quotient limbs */
+
+      if (BELOW_THRESHOLD (qn, MUL_TO_MULMOD_BNM1_FOR_2NXN_THRESHOLD))
+	mpn_mul (tp, dp, dn, qp, qn);		/* mulhigh */
+      else
+	{
+	  tn = mpn_mulmod_bnm1_next_size (dn);
+	  mpn_mulmod_bnm1 (tp, tn, dp, dn, qp, qn, scratch_out);
+	  wn = dn + qn - tn;			/* number of wrapped limbs */
+	  if (wn > 0)
+	    {
+	      c0 = mpn_sub_n (tp + tn, tp, rp, wn);
+	      mpn_decr_u (tp + wn, c0);
+	    }
+	}
+
+      cy += mpn_sub_n (rp, rp + qn, tp + qn, dn - qn);
+      if (cy == 2)
+	{
+	  mpn_incr_u (tp + dn, 1);
+	  cy = 1;
+	}
+      return mpn_sub_nc (rp + dn - qn, np + dn + in, tp + dn, qn, cy);
+
+#undef ip
+#undef tp
+#undef scratch_out
+    }
+}
+
+mp_limb_t
+mpn_mu_bdiv_qr (mp_ptr qp,
+		mp_ptr rp,
+		mp_srcptr np, mp_size_t nn,
+		mp_srcptr dp, mp_size_t dn,
+		mp_ptr scratch)
+{
+  mp_limb_t cy = mpn_mu_bdiv_qr_old (qp, rp, np, nn, dp, dn, scratch);
+
+  /* R' B^{qn} = U - Q' D
+   *
+   * Q = B^{qn} - Q' (assuming Q' != 0)
+   *
+   * R B^{qn} = U + Q D = U + B^{qn} D - Q' D
+   *          = B^{qn} D + R'
+   */
+
+  if (UNLIKELY (!mpn_neg (qp, qp, nn - dn)))
+    {
+      /* Zero quotient. */
+      ASSERT (cy == 0);
+      return 0;
+    }
+  else
+    {
+      mp_limb_t cy2 = mpn_add_n (rp, rp, dp, dn);
+      ASSERT (cy2 >= cy);
+
+      return cy2 - cy;
+    }
+}
+
+
+mp_size_t
+mpn_mu_bdiv_qr_itch (mp_size_t nn, mp_size_t dn)
+{
+  mp_size_t qn, in, tn, itch_binvert, itch_out, itches;
+  mp_size_t b;
+
+  ASSERT_ALWAYS (DC_BDIV_Q_THRESHOLD < MU_BDIV_Q_THRESHOLD);
+
+  qn = nn - dn;
+
+  if (qn > dn)
+    {
+      b = (qn - 1) / dn + 1;	/* ceil(qn/dn), number of blocks */
+      in = (qn - 1) / b + 1;	/* ceil(qn/b) = ceil(qn / ceil(qn/dn)) */
+    }
+  else
+    {
+      in = qn - (qn >> 1);
+    }
+
+  if (BELOW_THRESHOLD (in, MUL_TO_MULMOD_BNM1_FOR_2NXN_THRESHOLD))
+    {
+      tn = dn + in;
+      itch_out = 0;
+    }
+  else
+    {
+      tn = mpn_mulmod_bnm1_next_size (dn);
+      itch_out = mpn_mulmod_bnm1_itch (tn, dn, in);
+    }
+
+  itch_binvert = mpn_binvert_itch (in);
+  itches = tn + itch_out;
+  return in + MAX (itches, itch_binvert);
+}
diff --git a/third_party/gmp/mpn/generic/mu_div_q.c b/third_party/gmp/mpn/generic/mu_div_q.c
new file mode 100644
index 0000000..44cfb40
--- /dev/null
+++ b/third_party/gmp/mpn/generic/mu_div_q.c
@@ -0,0 +1,184 @@
+/* mpn_mu_div_q.
+
+   Contributed to the GNU project by Torbjorn Granlund and Marco Bodrato.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright 2005-2007, 2009, 2010, 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+/*
+   The idea of the algorithm used herein is to compute a smaller inverted value
+   than used in the standard Barrett algorithm, and thus save time in the
+   Newton iterations, and pay just a small price when using the inverted value
+   for developing quotient bits.  This algorithm was presented at ICMS 2006.
+*/
+
+/*
+  Things to work on:
+
+  1. This is a rudimentary implementation of mpn_mu_div_q.  The algorithm is
+     probably close to optimal, except when mpn_mu_divappr_q fails.
+
+  2. We used to fall back to mpn_mu_div_qr when we detect a possible
+     mpn_mu_divappr_q rounding problem, now we multiply and compare.
+     Unfortunately, since mpn_mu_divappr_q does not return the partial
+     remainder, this also doesn't become optimal.  A mpn_mu_divappr_qr could
+     solve that.
+
+  3. The allocations done here should be made from the scratch area, which
+     then would need to be amended.
+*/
+
+#include <stdlib.h>		/* for NULL */
+#include "gmp-impl.h"
+
+
+mp_limb_t
+mpn_mu_div_q (mp_ptr qp,
+	      mp_srcptr np, mp_size_t nn,
+	      mp_srcptr dp, mp_size_t dn,
+	      mp_ptr scratch)
+{
+  mp_ptr tp, rp;
+  mp_size_t qn;
+  mp_limb_t cy, qh;
+  TMP_DECL;
+
+  TMP_MARK;
+
+  qn = nn - dn;
+
+  tp = TMP_BALLOC_LIMBS (qn + 1);
+
+  if (qn >= dn)			/* nn >= 2*dn + 1 */
+    {
+       /* |_______________________|   dividend
+			 |________|   divisor  */
+
+      rp = TMP_BALLOC_LIMBS (nn + 1);
+      MPN_COPY (rp + 1, np, nn);
+      rp[0] = 0;
+
+      qh = mpn_cmp (rp + 1 + nn - dn, dp, dn) >= 0;
+      if (qh != 0)
+	mpn_sub_n (rp + 1 + nn - dn, rp + 1 + nn - dn, dp, dn);
+
+      cy = mpn_mu_divappr_q (tp, rp, nn + 1, dp, dn, scratch);
+
+      if (UNLIKELY (cy != 0))
+	{
+	  /* Since the partial remainder fed to mpn_preinv_mu_divappr_q was
+	     canonically reduced, replace the returned value of B^(qn-dn)+eps
+	     by the largest possible value.  */
+	  mp_size_t i;
+	  for (i = 0; i < qn + 1; i++)
+	    tp[i] = GMP_NUMB_MAX;
+	}
+
+      /* The max error of mpn_mu_divappr_q is +4.  If the low quotient limb is
+	 smaller than the max error, we cannot trust the quotient.  */
+      if (tp[0] > 4)
+	{
+	  MPN_COPY (qp, tp + 1, qn);
+	}
+      else
+	{
+	  mp_limb_t cy;
+	  mp_ptr pp;
+
+	  pp = rp;
+	  mpn_mul (pp, tp + 1, qn, dp, dn);
+
+	  cy = (qh != 0) ? mpn_add_n (pp + qn, pp + qn, dp, dn) : 0;
+
+	  if (cy || mpn_cmp (pp, np, nn) > 0) /* At most is wrong by one, no cycle. */
+	    qh -= mpn_sub_1 (qp, tp + 1, qn, 1);
+	  else /* Same as above */
+	    MPN_COPY (qp, tp + 1, qn);
+	}
+    }
+  else
+    {
+       /* |_______________________|   dividend
+		 |________________|   divisor  */
+
+      /* FIXME: When nn = 2dn-1, qn becomes dn-1, and the numerator size passed
+	 here becomes 2dn, i.e., more than nn.  This shouldn't hurt, since only
+	 the most significant dn-1 limbs will actually be read, but it is not
+	 pretty.  */
+
+      qh = mpn_mu_divappr_q (tp, np + nn - (2 * qn + 2), 2 * qn + 2,
+			     dp + dn - (qn + 1), qn + 1, scratch);
+
+      /* The max error of mpn_mu_divappr_q is +4, but we get an additional
+         error from the divisor truncation.  */
+      if (tp[0] > 6)
+	{
+	  MPN_COPY (qp, tp + 1, qn);
+	}
+      else
+	{
+	  mp_limb_t cy;
+
+	  /* FIXME: a shorter product should be enough; we may use already
+	     allocated space... */
+	  rp = TMP_BALLOC_LIMBS (nn);
+	  mpn_mul (rp, dp, dn, tp + 1, qn);
+
+	  cy = (qh != 0) ? mpn_add_n (rp + qn, rp + qn, dp, dn) : 0;
+
+	  if (cy || mpn_cmp (rp, np, nn) > 0) /* At most is wrong by one, no cycle. */
+	    qh -= mpn_sub_1 (qp, tp + 1, qn, 1);
+	  else /* Same as above */
+	    MPN_COPY (qp, tp + 1, qn);
+	}
+    }
+
+  TMP_FREE;
+  return qh;
+}
+
+mp_size_t
+mpn_mu_div_q_itch (mp_size_t nn, mp_size_t dn, int mua_k)
+{
+  mp_size_t qn;
+
+  qn = nn - dn;
+  if (qn >= dn)
+    {
+      return mpn_mu_divappr_q_itch (nn + 1, dn, mua_k);
+    }
+  else
+    {
+      return mpn_mu_divappr_q_itch (2 * qn + 2, qn + 1, mua_k);
+    }
+}
diff --git a/third_party/gmp/mpn/generic/mu_div_qr.c b/third_party/gmp/mpn/generic/mu_div_qr.c
new file mode 100644
index 0000000..8b9c702
--- /dev/null
+++ b/third_party/gmp/mpn/generic/mu_div_qr.c
@@ -0,0 +1,417 @@
+/* mpn_mu_div_qr, mpn_preinv_mu_div_qr.
+
+   Compute Q = floor(N / D) and R = N-QD.  N is nn limbs and D is dn limbs and
+   must be normalized, and Q must be nn-dn limbs.  The requirement that Q is
+   nn-dn limbs (and not nn-dn+1 limbs) was put in place in order to allow us to
+   let N be unmodified during the operation.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright 2005-2007, 2009, 2010 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+/*
+   The idea of the algorithm used herein is to compute a smaller inverted value
+   than used in the standard Barrett algorithm, and thus save time in the
+   Newton iterations, and pay just a small price when using the inverted value
+   for developing quotient bits.  This algorithm was presented at ICMS 2006.
+*/
+
+/* CAUTION: This code and the code in mu_divappr_q.c should be edited in sync.
+
+ Things to work on:
+
+  * This isn't optimal when the quotient isn't needed, as it might take a lot
+    of space.  The computation is always needed, though, so there is no time to
+    save with special code.
+
+  * The itch/scratch scheme isn't perhaps such a good idea as it once seemed,
+    demonstrated by the fact that the mpn_invertappr function's scratch needs
+    mean that we need to keep a large allocation long after it is needed.
+    Things are worse as mpn_mul_fft does not accept any scratch parameter,
+    which means we'll have a large memory hole while in mpn_mul_fft.  In
+    general, a peak scratch need in the beginning of a function isn't
+    well-handled by the itch/scratch scheme.
+*/
+
+#ifdef STAT
+#undef STAT
+#define STAT(x) x
+#else
+#define STAT(x)
+#endif
+
+#include <stdlib.h>		/* for NULL */
+#include "gmp-impl.h"
+
+
+/* FIXME: The MU_DIV_QR_SKEW_THRESHOLD was not analysed properly.  It gives a
+   speedup according to old measurements, but does the decision mechanism
+   really make sense?  It seem like the quotient between dn and qn might be
+   what we really should be checking.  */
+#ifndef MU_DIV_QR_SKEW_THRESHOLD
+#define MU_DIV_QR_SKEW_THRESHOLD 100
+#endif
+
+#ifdef CHECK				/* FIXME: Enable in minithres */
+#undef  MU_DIV_QR_SKEW_THRESHOLD
+#define MU_DIV_QR_SKEW_THRESHOLD 1
+#endif
+
+
+static mp_limb_t mpn_mu_div_qr2 (mp_ptr, mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+static mp_size_t mpn_mu_div_qr_choose_in (mp_size_t, mp_size_t, int);
+
+
+mp_limb_t
+mpn_mu_div_qr (mp_ptr qp,
+	       mp_ptr rp,
+	       mp_srcptr np,
+	       mp_size_t nn,
+	       mp_srcptr dp,
+	       mp_size_t dn,
+	       mp_ptr scratch)
+{
+  mp_size_t qn;
+  mp_limb_t cy, qh;
+
+  qn = nn - dn;
+  if (qn + MU_DIV_QR_SKEW_THRESHOLD < dn)
+    {
+      /* |______________|_ign_first__|   dividend			  nn
+		|_______|_ign_first__|   divisor			  dn
+
+		|______|	     quotient (prel)			  qn
+
+		 |___________________|   quotient * ignored-divisor-part  dn-1
+      */
+
+      /* Compute a preliminary quotient and a partial remainder by dividing the
+	 most significant limbs of each operand.  */
+      qh = mpn_mu_div_qr2 (qp, rp + nn - (2 * qn + 1),
+			   np + nn - (2 * qn + 1), 2 * qn + 1,
+			   dp + dn - (qn + 1), qn + 1,
+			   scratch);
+
+      /* Multiply the quotient by the divisor limbs ignored above.  */
+      if (dn - (qn + 1) > qn)
+	mpn_mul (scratch, dp, dn - (qn + 1), qp, qn);  /* prod is dn-1 limbs */
+      else
+	mpn_mul (scratch, qp, qn, dp, dn - (qn + 1));  /* prod is dn-1 limbs */
+
+      if (qh)
+	cy = mpn_add_n (scratch + qn, scratch + qn, dp, dn - (qn + 1));
+      else
+	cy = 0;
+      scratch[dn - 1] = cy;
+
+      cy = mpn_sub_n (rp, np, scratch, nn - (2 * qn + 1));
+      cy = mpn_sub_nc (rp + nn - (2 * qn + 1),
+		       rp + nn - (2 * qn + 1),
+		       scratch + nn - (2 * qn + 1),
+		       qn + 1, cy);
+      if (cy)
+	{
+	  qh -= mpn_sub_1 (qp, qp, qn, 1);
+	  mpn_add_n (rp, rp, dp, dn);
+	}
+    }
+  else
+    {
+      qh = mpn_mu_div_qr2 (qp, rp, np, nn, dp, dn, scratch);
+    }
+
+  return qh;
+}
+
+static mp_limb_t
+mpn_mu_div_qr2 (mp_ptr qp,
+		mp_ptr rp,
+		mp_srcptr np,
+		mp_size_t nn,
+		mp_srcptr dp,
+		mp_size_t dn,
+		mp_ptr scratch)
+{
+  mp_size_t qn, in;
+  mp_limb_t cy, qh;
+  mp_ptr ip, tp;
+
+  ASSERT (dn > 1);
+
+  qn = nn - dn;
+
+  /* Compute the inverse size.  */
+  in = mpn_mu_div_qr_choose_in (qn, dn, 0);
+  ASSERT (in <= dn);
+
+#if 1
+  /* This alternative inverse computation method gets slightly more accurate
+     results.  FIXMEs: (1) Temp allocation needs not analysed (2) itch function
+     not adapted (3) mpn_invertappr scratch needs not met.  */
+  ip = scratch;
+  tp = scratch + in + 1;
+
+  /* compute an approximate inverse on (in+1) limbs */
+  if (dn == in)
+    {
+      MPN_COPY (tp + 1, dp, in);
+      tp[0] = 1;
+      mpn_invertappr (ip, tp, in + 1, tp + in + 1);
+      MPN_COPY_INCR (ip, ip + 1, in);
+    }
+  else
+    {
+      cy = mpn_add_1 (tp, dp + dn - (in + 1), in + 1, 1);
+      if (UNLIKELY (cy != 0))
+	MPN_ZERO (ip, in);
+      else
+	{
+	  mpn_invertappr (ip, tp, in + 1, tp + in + 1);
+	  MPN_COPY_INCR (ip, ip + 1, in);
+	}
+    }
+#else
+  /* This older inverse computation method gets slightly worse results than the
+     one above.  */
+  ip = scratch;
+  tp = scratch + in;
+
+  /* Compute inverse of D to in+1 limbs, then round to 'in' limbs.  Ideally the
+     inversion function should do this automatically.  */
+  if (dn == in)
+    {
+      tp[in + 1] = 0;
+      MPN_COPY (tp + in + 2, dp, in);
+      mpn_invertappr (tp, tp + in + 1, in + 1, NULL);
+    }
+  else
+    {
+      mpn_invertappr (tp, dp + dn - (in + 1), in + 1, NULL);
+    }
+  cy = mpn_sub_1 (tp, tp, in + 1, GMP_NUMB_HIGHBIT);
+  if (UNLIKELY (cy != 0))
+    MPN_ZERO (tp + 1, in);
+  MPN_COPY (ip, tp + 1, in);
+#endif
+
+  qh = mpn_preinv_mu_div_qr (qp, rp, np, nn, dp, dn, ip, in, scratch + in);
+
+  return qh;
+}
+
+mp_limb_t
+mpn_preinv_mu_div_qr (mp_ptr qp,
+		      mp_ptr rp,
+		      mp_srcptr np,
+		      mp_size_t nn,
+		      mp_srcptr dp,
+		      mp_size_t dn,
+		      mp_srcptr ip,
+		      mp_size_t in,
+		      mp_ptr scratch)
+{
+  mp_size_t qn;
+  mp_limb_t cy, cx, qh;
+  mp_limb_t r;
+  mp_size_t tn, wn;
+
+#define tp           scratch
+#define scratch_out  (scratch + tn)
+
+  qn = nn - dn;
+
+  np += qn;
+  qp += qn;
+
+  qh = mpn_cmp (np, dp, dn) >= 0;
+  if (qh != 0)
+    mpn_sub_n (rp, np, dp, dn);
+  else
+    MPN_COPY_INCR (rp, np, dn);
+
+  /* if (qn == 0) */			/* The while below handles this case */
+  /*   return qh; */			/* Degenerate use.  Should we allow this? */
+
+  while (qn > 0)
+    {
+      if (qn < in)
+	{
+	  ip += in - qn;
+	  in = qn;
+	}
+      np -= in;
+      qp -= in;
+
+      /* Compute the next block of quotient limbs by multiplying the inverse I
+	 by the upper part of the partial remainder R.  */
+      mpn_mul_n (tp, rp + dn - in, ip, in);		/* mulhi  */
+      cy = mpn_add_n (qp, tp + in, rp + dn - in, in);	/* I's msb implicit */
+      ASSERT_ALWAYS (cy == 0);
+
+      qn -= in;
+
+      /* Compute the product of the quotient block and the divisor D, to be
+	 subtracted from the partial remainder combined with new limbs from the
+	 dividend N.  We only really need the low dn+1 limbs.  */
+
+      if (BELOW_THRESHOLD (in, MUL_TO_MULMOD_BNM1_FOR_2NXN_THRESHOLD))
+	mpn_mul (tp, dp, dn, qp, in);		/* dn+in limbs, high 'in' cancels */
+      else
+	{
+	  tn = mpn_mulmod_bnm1_next_size (dn + 1);
+	  mpn_mulmod_bnm1 (tp, tn, dp, dn, qp, in, scratch_out);
+	  wn = dn + in - tn;			/* number of wrapped limbs */
+	  if (wn > 0)
+	    {
+	      cy = mpn_sub_n (tp, tp, rp + dn - wn, wn);
+	      cy = mpn_sub_1 (tp + wn, tp + wn, tn - wn, cy);
+	      cx = mpn_cmp (rp + dn - in, tp + dn, tn - dn) < 0;
+	      ASSERT_ALWAYS (cx >= cy);
+	      mpn_incr_u (tp, cx - cy);
+	    }
+	}
+
+      r = rp[dn - in] - tp[dn];
+
+      /* Subtract the product from the partial remainder combined with new
+	 limbs from the dividend N, generating a new partial remainder R.  */
+      if (dn != in)
+	{
+	  cy = mpn_sub_n (tp, np, tp, in);	/* get next 'in' limbs from N */
+	  cy = mpn_sub_nc (tp + in, rp, tp + in, dn - in, cy);
+	  MPN_COPY (rp, tp, dn);		/* FIXME: try to avoid this */
+	}
+      else
+	{
+	  cy = mpn_sub_n (rp, np, tp, in);	/* get next 'in' limbs from N */
+	}
+
+      STAT (int i; int err = 0;
+	    static int errarr[5]; static int err_rec; static int tot);
+
+      /* Check the remainder R and adjust the quotient as needed.  */
+      r -= cy;
+      while (r != 0)
+	{
+	  /* We loop 0 times with about 69% probability, 1 time with about 31%
+	     probability, 2 times with about 0.6% probability, if inverse is
+	     computed as recommended.  */
+	  mpn_incr_u (qp, 1);
+	  cy = mpn_sub_n (rp, rp, dp, dn);
+	  r -= cy;
+	  STAT (err++);
+	}
+      if (mpn_cmp (rp, dp, dn) >= 0)
+	{
+	  /* This is executed with about 76% probability.  */
+	  mpn_incr_u (qp, 1);
+	  cy = mpn_sub_n (rp, rp, dp, dn);
+	  STAT (err++);
+	}
+
+      STAT (
+	    tot++;
+	    errarr[err]++;
+	    if (err > err_rec)
+	      err_rec = err;
+	    if (tot % 0x10000 == 0)
+	      {
+		for (i = 0; i <= err_rec; i++)
+		  printf ("  %d(%.1f%%)", errarr[i], 100.0*errarr[i]/tot);
+		printf ("\n");
+	      }
+	    );
+    }
+
+  return qh;
+}
+
+/* In case k=0 (automatic choice), we distinguish 3 cases:
+   (a) dn < qn:         in = ceil(qn / ceil(qn/dn))
+   (b) dn/3 < qn <= dn: in = ceil(qn / 2)
+   (c) qn < dn/3:       in = qn
+   In all cases we have in <= dn.
+ */
+static mp_size_t
+mpn_mu_div_qr_choose_in (mp_size_t qn, mp_size_t dn, int k)
+{
+  mp_size_t in;
+
+  if (k == 0)
+    {
+      mp_size_t b;
+      if (qn > dn)
+	{
+	  /* Compute an inverse size that is a nice partition of the quotient.  */
+	  b = (qn - 1) / dn + 1;	/* ceil(qn/dn), number of blocks */
+	  in = (qn - 1) / b + 1;	/* ceil(qn/b) = ceil(qn / ceil(qn/dn)) */
+	}
+      else if (3 * qn > dn)
+	{
+	  in = (qn - 1) / 2 + 1;	/* b = 2 */
+	}
+      else
+	{
+	  in = (qn - 1) / 1 + 1;	/* b = 1 */
+	}
+    }
+  else
+    {
+      mp_size_t xn;
+      xn = MIN (dn, qn);
+      in = (xn - 1) / k + 1;
+    }
+
+  return in;
+}
+
+mp_size_t
+mpn_mu_div_qr_itch (mp_size_t nn, mp_size_t dn, int mua_k)
+{
+  mp_size_t in = mpn_mu_div_qr_choose_in (nn - dn, dn, mua_k);
+  mp_size_t itch_preinv = mpn_preinv_mu_div_qr_itch (nn, dn, in);
+  mp_size_t itch_invapp = mpn_invertappr_itch (in + 1) + in + 2; /* 3in + 4 */
+
+  ASSERT (itch_preinv >= itch_invapp);
+  return in + MAX (itch_invapp, itch_preinv);
+}
+
+mp_size_t
+mpn_preinv_mu_div_qr_itch (mp_size_t nn, mp_size_t dn, mp_size_t in)
+{
+  mp_size_t itch_local = mpn_mulmod_bnm1_next_size (dn + 1);
+  mp_size_t itch_out = mpn_mulmod_bnm1_itch (itch_local, dn, in);
+
+  return itch_local + itch_out;
+}
diff --git a/third_party/gmp/mpn/generic/mu_divappr_q.c b/third_party/gmp/mpn/generic/mu_divappr_q.c
new file mode 100644
index 0000000..c022b4f
--- /dev/null
+++ b/third_party/gmp/mpn/generic/mu_divappr_q.c
@@ -0,0 +1,368 @@
+/* mpn_mu_divappr_q, mpn_preinv_mu_divappr_q.
+
+   Compute Q = floor(N / D) + e.  N is nn limbs, D is dn limbs and must be
+   normalized, and Q must be nn-dn limbs, 0 <= e <= 4.  The requirement that Q
+   is nn-dn limbs (and not nn-dn+1 limbs) was put in place in order to allow us
+   to let N be unmodified during the operation.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright 2005-2007, 2009, 2010 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+/*
+   The idea of the algorithm used herein is to compute a smaller inverted value
+   than used in the standard Barrett algorithm, and thus save time in the
+   Newton iterations, and pay just a small price when using the inverted value
+   for developing quotient bits.  This algorithm was presented at ICMS 2006.
+*/
+
+/* CAUTION: This code and the code in mu_div_qr.c should be edited in sync.
+
+ Things to work on:
+
+  * The itch/scratch scheme isn't perhaps such a good idea as it once seemed,
+    demonstrated by the fact that the mpn_invertappr function's scratch needs
+    mean that we need to keep a large allocation long after it is needed.
+    Things are worse as mpn_mul_fft does not accept any scratch parameter,
+    which means we'll have a large memory hole while in mpn_mul_fft.  In
+    general, a peak scratch need in the beginning of a function isn't
+    well-handled by the itch/scratch scheme.
+*/
+
+#ifdef STAT
+#undef STAT
+#define STAT(x) x
+#else
+#define STAT(x)
+#endif
+
+#include <stdlib.h>		/* for NULL */
+#include "gmp-impl.h"
+
+static mp_limb_t mpn_preinv_mu_divappr_q (mp_ptr, mp_srcptr, mp_size_t,
+			 mp_srcptr, mp_size_t, mp_srcptr, mp_size_t, mp_ptr);
+static mp_size_t mpn_mu_divappr_q_choose_in (mp_size_t, mp_size_t, int);
+
+mp_limb_t
+mpn_mu_divappr_q (mp_ptr qp,
+		  mp_srcptr np,
+		  mp_size_t nn,
+		  mp_srcptr dp,
+		  mp_size_t dn,
+		  mp_ptr scratch)
+{
+  mp_size_t qn, in;
+  mp_limb_t cy, qh;
+  mp_ptr ip, tp;
+
+  ASSERT (dn > 1);
+
+  qn = nn - dn;
+
+  /* If Q is smaller than D, truncate operands. */
+  if (qn + 1 < dn)
+    {
+      np += dn - (qn + 1);
+      nn -= dn - (qn + 1);
+      dp += dn - (qn + 1);
+      dn = qn + 1;
+    }
+
+  /* Compute the inverse size.  */
+  in = mpn_mu_divappr_q_choose_in (qn, dn, 0);
+  ASSERT (in <= dn);
+
+#if 1
+  /* This alternative inverse computation method gets slightly more accurate
+     results.  FIXMEs: (1) Temp allocation needs not analysed (2) itch function
+     not adapted (3) mpn_invertappr scratch needs not met.  */
+  ip = scratch;
+  tp = scratch + in + 1;
+
+  /* compute an approximate inverse on (in+1) limbs */
+  if (dn == in)
+    {
+      MPN_COPY (tp + 1, dp, in);
+      tp[0] = 1;
+      mpn_invertappr (ip, tp, in + 1, tp + in + 1);
+      MPN_COPY_INCR (ip, ip + 1, in);
+    }
+  else
+    {
+      cy = mpn_add_1 (tp, dp + dn - (in + 1), in + 1, 1);
+      if (UNLIKELY (cy != 0))
+	MPN_ZERO (ip, in);
+      else
+	{
+	  mpn_invertappr (ip, tp, in + 1, tp + in + 1);
+	  MPN_COPY_INCR (ip, ip + 1, in);
+	}
+    }
+#else
+  /* This older inverse computation method gets slightly worse results than the
+     one above.  */
+  ip = scratch;
+  tp = scratch + in;
+
+  /* Compute inverse of D to in+1 limbs, then round to 'in' limbs.  Ideally the
+     inversion function should do this automatically.  */
+  if (dn == in)
+    {
+      tp[in + 1] = 0;
+      MPN_COPY (tp + in + 2, dp, in);
+      mpn_invertappr (tp, tp + in + 1, in + 1, NULL);
+    }
+  else
+    {
+      mpn_invertappr (tp, dp + dn - (in + 1), in + 1, NULL);
+    }
+  cy = mpn_sub_1 (tp, tp, in + 1, GMP_NUMB_HIGHBIT);
+  if (UNLIKELY (cy != 0))
+    MPN_ZERO (tp + 1, in);
+  MPN_COPY (ip, tp + 1, in);
+#endif
+
+  qh = mpn_preinv_mu_divappr_q (qp, np, nn, dp, dn, ip, in, scratch + in);
+
+  return qh;
+}
+
+static mp_limb_t
+mpn_preinv_mu_divappr_q (mp_ptr qp,
+			 mp_srcptr np,
+			 mp_size_t nn,
+			 mp_srcptr dp,
+			 mp_size_t dn,
+			 mp_srcptr ip,
+			 mp_size_t in,
+			 mp_ptr scratch)
+{
+  mp_size_t qn;
+  mp_limb_t cy, cx, qh;
+  mp_limb_t r;
+  mp_size_t tn, wn;
+
+#define rp           scratch
+#define tp           (scratch + dn)
+#define scratch_out  (scratch + dn + tn)
+
+  qn = nn - dn;
+
+  np += qn;
+  qp += qn;
+
+  qh = mpn_cmp (np, dp, dn) >= 0;
+  if (qh != 0)
+    mpn_sub_n (rp, np, dp, dn);
+  else
+    MPN_COPY (rp, np, dn);
+
+  if (qn == 0)
+    return qh;			/* Degenerate use.  Should we allow this? */
+
+  while (qn > 0)
+    {
+      if (qn < in)
+	{
+	  ip += in - qn;
+	  in = qn;
+	}
+      np -= in;
+      qp -= in;
+
+      /* Compute the next block of quotient limbs by multiplying the inverse I
+	 by the upper part of the partial remainder R.  */
+      mpn_mul_n (tp, rp + dn - in, ip, in);		/* mulhi  */
+      cy = mpn_add_n (qp, tp + in, rp + dn - in, in);	/* I's msb implicit */
+      ASSERT_ALWAYS (cy == 0);
+
+      qn -= in;
+      if (qn == 0)
+	break;
+
+      /* Compute the product of the quotient block and the divisor D, to be
+	 subtracted from the partial remainder combined with new limbs from the
+	 dividend N.  We only really need the low dn limbs.  */
+
+      if (BELOW_THRESHOLD (in, MUL_TO_MULMOD_BNM1_FOR_2NXN_THRESHOLD))
+	mpn_mul (tp, dp, dn, qp, in);		/* dn+in limbs, high 'in' cancels */
+      else
+	{
+	  tn = mpn_mulmod_bnm1_next_size (dn + 1);
+	  mpn_mulmod_bnm1 (tp, tn, dp, dn, qp, in, scratch_out);
+	  wn = dn + in - tn;			/* number of wrapped limbs */
+	  if (wn > 0)
+	    {
+	      cy = mpn_sub_n (tp, tp, rp + dn - wn, wn);
+	      cy = mpn_sub_1 (tp + wn, tp + wn, tn - wn, cy);
+	      cx = mpn_cmp (rp + dn - in, tp + dn, tn - dn) < 0;
+	      ASSERT_ALWAYS (cx >= cy);
+	      mpn_incr_u (tp, cx - cy);
+	    }
+	}
+
+      r = rp[dn - in] - tp[dn];
+
+      /* Subtract the product from the partial remainder combined with new
+	 limbs from the dividend N, generating a new partial remainder R.  */
+      if (dn != in)
+	{
+	  cy = mpn_sub_n (tp, np, tp, in);	/* get next 'in' limbs from N */
+	  cy = mpn_sub_nc (tp + in, rp, tp + in, dn - in, cy);
+	  MPN_COPY (rp, tp, dn);		/* FIXME: try to avoid this */
+	}
+      else
+	{
+	  cy = mpn_sub_n (rp, np, tp, in);	/* get next 'in' limbs from N */
+	}
+
+      STAT (int i; int err = 0;
+	    static int errarr[5]; static int err_rec; static int tot);
+
+      /* Check the remainder R and adjust the quotient as needed.  */
+      r -= cy;
+      while (r != 0)
+	{
+	  /* We loop 0 times with about 69% probability, 1 time with about 31%
+	     probability, 2 times with about 0.6% probability, if inverse is
+	     computed as recommended.  */
+	  mpn_incr_u (qp, 1);
+	  cy = mpn_sub_n (rp, rp, dp, dn);
+	  r -= cy;
+	  STAT (err++);
+	}
+      if (mpn_cmp (rp, dp, dn) >= 0)
+	{
+	  /* This is executed with about 76% probability.  */
+	  mpn_incr_u (qp, 1);
+	  cy = mpn_sub_n (rp, rp, dp, dn);
+	  STAT (err++);
+	}
+
+      STAT (
+	    tot++;
+	    errarr[err]++;
+	    if (err > err_rec)
+	      err_rec = err;
+	    if (tot % 0x10000 == 0)
+	      {
+		for (i = 0; i <= err_rec; i++)
+		  printf ("  %d(%.1f%%)", errarr[i], 100.0*errarr[i]/tot);
+		printf ("\n");
+	      }
+	    );
+    }
+
+  /* FIXME: We should perhaps be somewhat more elegant in our rounding of the
+     quotient.  For now, just make sure the returned quotient is >= the real
+     quotient; add 3 with saturating arithmetic.  */
+  qn = nn - dn;
+  cy += mpn_add_1 (qp, qp, qn, 3);
+  if (cy != 0)
+    {
+      if (qh != 0)
+	{
+	  /* Return a quotient of just 1-bits, with qh set.  */
+	  mp_size_t i;
+	  for (i = 0; i < qn; i++)
+	    qp[i] = GMP_NUMB_MAX;
+	}
+      else
+	{
+	  /* Propagate carry into qh.  */
+	  qh = 1;
+	}
+    }
+
+  return qh;
+}
+
+/* In case k=0 (automatic choice), we distinguish 3 cases:
+   (a) dn < qn:         in = ceil(qn / ceil(qn/dn))
+   (b) dn/3 < qn <= dn: in = ceil(qn / 2)
+   (c) qn < dn/3:       in = qn
+   In all cases we have in <= dn.
+ */
+static mp_size_t
+mpn_mu_divappr_q_choose_in (mp_size_t qn, mp_size_t dn, int k)
+{
+  mp_size_t in;
+
+  if (k == 0)
+    {
+      mp_size_t b;
+      if (qn > dn)
+	{
+	  /* Compute an inverse size that is a nice partition of the quotient.  */
+	  b = (qn - 1) / dn + 1;	/* ceil(qn/dn), number of blocks */
+	  in = (qn - 1) / b + 1;	/* ceil(qn/b) = ceil(qn / ceil(qn/dn)) */
+	}
+      else if (3 * qn > dn)
+	{
+	  in = (qn - 1) / 2 + 1;	/* b = 2 */
+	}
+      else
+	{
+	  in = (qn - 1) / 1 + 1;	/* b = 1 */
+	}
+    }
+  else
+    {
+      mp_size_t xn;
+      xn = MIN (dn, qn);
+      in = (xn - 1) / k + 1;
+    }
+
+  return in;
+}
+
+mp_size_t
+mpn_mu_divappr_q_itch (mp_size_t nn, mp_size_t dn, int mua_k)
+{
+  mp_size_t qn, in, itch_local, itch_out, itch_invapp;
+
+  qn = nn - dn;
+  if (qn + 1 < dn)
+    {
+      dn = qn + 1;
+    }
+  in = mpn_mu_divappr_q_choose_in (qn, dn, mua_k);
+
+  itch_local = mpn_mulmod_bnm1_next_size (dn + 1);
+  itch_out = mpn_mulmod_bnm1_itch (itch_local, dn, in);
+  itch_invapp = mpn_invertappr_itch (in + 1) + in + 2; /* 3in + 4 */
+
+  ASSERT (dn + itch_local + itch_out >= itch_invapp);
+  return in + MAX (dn + itch_local + itch_out, itch_invapp);
+}
diff --git a/third_party/gmp/mpn/generic/mul.c b/third_party/gmp/mpn/generic/mul.c
new file mode 100644
index 0000000..37444e9
--- /dev/null
+++ b/third_party/gmp/mpn/generic/mul.c
@@ -0,0 +1,441 @@
+/* mpn_mul -- Multiply two natural numbers.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+Copyright 1991, 1993, 1994, 1996, 1997, 1999-2003, 2005-2007, 2009, 2010, 2012,
+2014, 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+#ifndef MUL_BASECASE_MAX_UN
+#define MUL_BASECASE_MAX_UN 500
+#endif
+
+/* Areas where the different toom algorithms can be called (extracted
+   from the t-toom*.c files, and ignoring small constant offsets):
+
+   1/6  1/5 1/4 4/13 1/3 3/8 2/5 5/11 1/2 3/5 2/3 3/4 4/5   1 vn/un
+                                        4/7              6/7
+				       6/11
+                                       |--------------------| toom22 (small)
+                                                           || toom22 (large)
+                                                       |xxxx| toom22 called
+                      |-------------------------------------| toom32
+                                         |xxxxxxxxxxxxxxxx| | toom32 called
+                                               |------------| toom33
+                                                          |x| toom33 called
+             |---------------------------------|            | toom42
+	              |xxxxxxxxxxxxxxxxxxxxxxxx|            | toom42 called
+                                       |--------------------| toom43
+                                               |xxxxxxxxxx|   toom43 called
+         |-----------------------------|                      toom52 (unused)
+                                                   |--------| toom44
+						   |xxxxxxxx| toom44 called
+                              |--------------------|        | toom53
+                                        |xxxxxx|              toom53 called
+    |-------------------------|                               toom62 (unused)
+                                           |----------------| toom54 (unused)
+                      |--------------------|                  toom63
+	                      |xxxxxxxxx|                   | toom63 called
+                          |---------------------------------| toom6h
+						   |xxxxxxxx| toom6h called
+                                  |-------------------------| toom8h (32 bit)
+                 |------------------------------------------| toom8h (64 bit)
+						   |xxxxxxxx| toom8h called
+*/
+
+#define TOOM33_OK(an,bn) (6 + 2 * an < 3 * bn)
+#define TOOM44_OK(an,bn) (12 + 3 * an < 4 * bn)
+
+/* Multiply the natural numbers u (pointed to by UP, with UN limbs) and v
+   (pointed to by VP, with VN limbs), and store the result at PRODP.  The
+   result is UN + VN limbs.  Return the most significant limb of the result.
+
+   NOTE: The space pointed to by PRODP is overwritten before finished with U
+   and V, so overlap is an error.
+
+   Argument constraints:
+   1. UN >= VN.
+   2. PRODP != UP and PRODP != VP, i.e. the destination must be distinct from
+      the multiplier and the multiplicand.  */
+
+/*
+  * The cutoff lines in the toomX2 and toomX3 code are now exactly between the
+    ideal lines of the surrounding algorithms.  Is that optimal?
+
+  * The toomX3 code now uses a structure similar to the one of toomX2, except
+    that it loops longer in the unbalanced case.  The result is that the
+    remaining area might have un < vn.  Should we fix the toomX2 code in a
+    similar way?
+
+  * The toomX3 code is used for the largest non-FFT unbalanced operands.  It
+    therefore calls mpn_mul recursively for certain cases.
+
+  * Allocate static temp space using THRESHOLD variables (except for toom44
+    when !WANT_FFT).  That way, we can typically have no TMP_ALLOC at all.
+
+  * We sort ToomX2 algorithms together, assuming the toom22, toom32, toom42
+    have the same vn threshold.  This is not true, we should actually use
+    mul_basecase for slightly larger operands for toom32 than for toom22, and
+    even larger for toom42.
+
+  * That problem is even more prevalent for toomX3.  We therefore use special
+    THRESHOLD variables there.
+*/
+
+mp_limb_t
+mpn_mul (mp_ptr prodp,
+	 mp_srcptr up, mp_size_t un,
+	 mp_srcptr vp, mp_size_t vn)
+{
+  ASSERT (un >= vn);
+  ASSERT (vn >= 1);
+  ASSERT (! MPN_OVERLAP_P (prodp, un+vn, up, un));
+  ASSERT (! MPN_OVERLAP_P (prodp, un+vn, vp, vn));
+
+  if (BELOW_THRESHOLD (un, MUL_TOOM22_THRESHOLD))
+    {
+      /* When un (and thus vn) is below the toom22 range, do mul_basecase.
+	 Test un and not vn here not to thwart the un >> vn code below.
+	 This special case is not necessary, but cuts the overhead for the
+	 smallest operands. */
+      mpn_mul_basecase (prodp, up, un, vp, vn);
+    }
+  else if (un == vn)
+    {
+      mpn_mul_n (prodp, up, vp, un);
+    }
+  else if (vn < MUL_TOOM22_THRESHOLD)
+    { /* plain schoolbook multiplication */
+
+      /* Unless un is very large, or else if have an applicable mpn_mul_N,
+	 perform basecase multiply directly.  */
+      if (un <= MUL_BASECASE_MAX_UN
+#if HAVE_NATIVE_mpn_mul_2
+	  || vn <= 2
+#else
+	  || vn == 1
+#endif
+	  )
+	mpn_mul_basecase (prodp, up, un, vp, vn);
+      else
+	{
+	  /* We have un >> MUL_BASECASE_MAX_UN > vn.  For better memory
+	     locality, split up[] into MUL_BASECASE_MAX_UN pieces and multiply
+	     these pieces with the vp[] operand.  After each such partial
+	     multiplication (but the last) we copy the most significant vn
+	     limbs into a temporary buffer since that part would otherwise be
+	     overwritten by the next multiplication.  After the next
+	     multiplication, we add it back.  This illustrates the situation:
+
+                                                    -->vn<--
+                                                      |  |<------- un ------->|
+                                                         _____________________|
+                                                        X                    /|
+                                                      /XX__________________/  |
+                                    _____________________                     |
+                                   X                    /                     |
+                                 /XX__________________/                       |
+               _____________________                                          |
+              /                    /                                          |
+            /____________________/                                            |
+	    ==================================================================
+
+	    The parts marked with X are the parts whose sums are copied into
+	    the temporary buffer.  */
+
+	  mp_limb_t tp[MUL_TOOM22_THRESHOLD_LIMIT];
+	  mp_limb_t cy;
+	  ASSERT (MUL_TOOM22_THRESHOLD <= MUL_TOOM22_THRESHOLD_LIMIT);
+
+	  mpn_mul_basecase (prodp, up, MUL_BASECASE_MAX_UN, vp, vn);
+	  prodp += MUL_BASECASE_MAX_UN;
+	  MPN_COPY (tp, prodp, vn);		/* preserve high triangle */
+	  up += MUL_BASECASE_MAX_UN;
+	  un -= MUL_BASECASE_MAX_UN;
+	  while (un > MUL_BASECASE_MAX_UN)
+	    {
+	      mpn_mul_basecase (prodp, up, MUL_BASECASE_MAX_UN, vp, vn);
+	      cy = mpn_add_n (prodp, prodp, tp, vn); /* add back preserved triangle */
+	      mpn_incr_u (prodp + vn, cy);
+	      prodp += MUL_BASECASE_MAX_UN;
+	      MPN_COPY (tp, prodp, vn);		/* preserve high triangle */
+	      up += MUL_BASECASE_MAX_UN;
+	      un -= MUL_BASECASE_MAX_UN;
+	    }
+	  if (un > vn)
+	    {
+	      mpn_mul_basecase (prodp, up, un, vp, vn);
+	    }
+	  else
+	    {
+	      ASSERT (un > 0);
+	      mpn_mul_basecase (prodp, vp, vn, up, un);
+	    }
+	  cy = mpn_add_n (prodp, prodp, tp, vn); /* add back preserved triangle */
+	  mpn_incr_u (prodp + vn, cy);
+	}
+    }
+  else if (BELOW_THRESHOLD (vn, MUL_TOOM33_THRESHOLD))
+    {
+      /* Use ToomX2 variants */
+      mp_ptr scratch;
+      TMP_SDECL; TMP_SMARK;
+
+#define ITCH_TOOMX2 (9 * vn / 2 + GMP_NUMB_BITS * 2)
+      scratch = TMP_SALLOC_LIMBS (ITCH_TOOMX2);
+      ASSERT (mpn_toom22_mul_itch ((5*vn-1)/4, vn) <= ITCH_TOOMX2); /* 5vn/2+ */
+      ASSERT (mpn_toom32_mul_itch ((7*vn-1)/4, vn) <= ITCH_TOOMX2); /* 7vn/6+ */
+      ASSERT (mpn_toom42_mul_itch (3 * vn - 1, vn) <= ITCH_TOOMX2); /* 9vn/2+ */
+#undef ITCH_TOOMX2
+
+      /* FIXME: This condition (repeated in the loop below) leaves from a vn*vn
+	 square to a (3vn-1)*vn rectangle.  Leaving such a rectangle is hardly
+	 wise; we would get better balance by slightly moving the bound.  We
+	 will sometimes end up with un < vn, like in the X3 arm below.  */
+      if (un >= 3 * vn)
+	{
+	  mp_limb_t cy;
+	  mp_ptr ws;
+
+	  /* The maximum ws usage is for the mpn_mul result.  */
+	  ws = TMP_SALLOC_LIMBS (4 * vn);
+
+	  mpn_toom42_mul (prodp, up, 2 * vn, vp, vn, scratch);
+	  un -= 2 * vn;
+	  up += 2 * vn;
+	  prodp += 2 * vn;
+
+	  while (un >= 3 * vn)
+	    {
+	      mpn_toom42_mul (ws, up, 2 * vn, vp, vn, scratch);
+	      un -= 2 * vn;
+	      up += 2 * vn;
+	      cy = mpn_add_n (prodp, prodp, ws, vn);
+	      MPN_COPY (prodp + vn, ws + vn, 2 * vn);
+	      mpn_incr_u (prodp + vn, cy);
+	      prodp += 2 * vn;
+	    }
+
+	  /* vn <= un < 3vn */
+
+	  if (4 * un < 5 * vn)
+	    mpn_toom22_mul (ws, up, un, vp, vn, scratch);
+	  else if (4 * un < 7 * vn)
+	    mpn_toom32_mul (ws, up, un, vp, vn, scratch);
+	  else
+	    mpn_toom42_mul (ws, up, un, vp, vn, scratch);
+
+	  cy = mpn_add_n (prodp, prodp, ws, vn);
+	  MPN_COPY (prodp + vn, ws + vn, un);
+	  mpn_incr_u (prodp + vn, cy);
+	}
+      else
+	{
+	  if (4 * un < 5 * vn)
+	    mpn_toom22_mul (prodp, up, un, vp, vn, scratch);
+	  else if (4 * un < 7 * vn)
+	    mpn_toom32_mul (prodp, up, un, vp, vn, scratch);
+	  else
+	    mpn_toom42_mul (prodp, up, un, vp, vn, scratch);
+	}
+      TMP_SFREE;
+    }
+  else if (BELOW_THRESHOLD ((un + vn) >> 1, MUL_FFT_THRESHOLD) ||
+	   BELOW_THRESHOLD (3 * vn, MUL_FFT_THRESHOLD))
+    {
+      /* Handle the largest operands that are not in the FFT range.  The 2nd
+	 condition makes very unbalanced operands avoid the FFT code (except
+	 perhaps as coefficient products of the Toom code.  */
+
+      if (BELOW_THRESHOLD (vn, MUL_TOOM44_THRESHOLD) || !TOOM44_OK (un, vn))
+	{
+	  /* Use ToomX3 variants */
+	  mp_ptr scratch;
+	  TMP_DECL; TMP_MARK;
+
+#define ITCH_TOOMX3 (4 * vn + GMP_NUMB_BITS)
+	  scratch = TMP_ALLOC_LIMBS (ITCH_TOOMX3);
+	  ASSERT (mpn_toom33_mul_itch ((7*vn-1)/6, vn) <= ITCH_TOOMX3); /* 7vn/2+ */
+	  ASSERT (mpn_toom43_mul_itch ((3*vn-1)/2, vn) <= ITCH_TOOMX3); /* 9vn/4+ */
+	  ASSERT (mpn_toom32_mul_itch ((7*vn-1)/4, vn) <= ITCH_TOOMX3); /* 7vn/6+ */
+	  ASSERT (mpn_toom53_mul_itch ((11*vn-1)/6, vn) <= ITCH_TOOMX3); /* 11vn/3+ */
+	  ASSERT (mpn_toom42_mul_itch ((5*vn-1)/2, vn) <= ITCH_TOOMX3); /* 15vn/4+ */
+	  ASSERT (mpn_toom63_mul_itch ((5*vn-1)/2, vn) <= ITCH_TOOMX3); /* 15vn/4+ */
+#undef ITCH_TOOMX3
+
+	  if (2 * un >= 5 * vn)
+	    {
+	      mp_limb_t cy;
+	      mp_ptr ws;
+
+	      /* The maximum ws usage is for the mpn_mul result.  */
+	      ws = TMP_ALLOC_LIMBS (7 * vn >> 1);
+
+	      if (BELOW_THRESHOLD (vn, MUL_TOOM42_TO_TOOM63_THRESHOLD))
+		mpn_toom42_mul (prodp, up, 2 * vn, vp, vn, scratch);
+	      else
+		mpn_toom63_mul (prodp, up, 2 * vn, vp, vn, scratch);
+	      un -= 2 * vn;
+	      up += 2 * vn;
+	      prodp += 2 * vn;
+
+	      while (2 * un >= 5 * vn)	/* un >= 2.5vn */
+		{
+		  if (BELOW_THRESHOLD (vn, MUL_TOOM42_TO_TOOM63_THRESHOLD))
+		    mpn_toom42_mul (ws, up, 2 * vn, vp, vn, scratch);
+		  else
+		    mpn_toom63_mul (ws, up, 2 * vn, vp, vn, scratch);
+		  un -= 2 * vn;
+		  up += 2 * vn;
+		  cy = mpn_add_n (prodp, prodp, ws, vn);
+		  MPN_COPY (prodp + vn, ws + vn, 2 * vn);
+		  mpn_incr_u (prodp + vn, cy);
+		  prodp += 2 * vn;
+		}
+
+	      /* vn / 2 <= un < 2.5vn */
+
+	      if (un < vn)
+		mpn_mul (ws, vp, vn, up, un);
+	      else
+		mpn_mul (ws, up, un, vp, vn);
+
+	      cy = mpn_add_n (prodp, prodp, ws, vn);
+	      MPN_COPY (prodp + vn, ws + vn, un);
+	      mpn_incr_u (prodp + vn, cy);
+	    }
+	  else
+	    {
+	      if (6 * un < 7 * vn)
+		mpn_toom33_mul (prodp, up, un, vp, vn, scratch);
+	      else if (2 * un < 3 * vn)
+		{
+		  if (BELOW_THRESHOLD (vn, MUL_TOOM32_TO_TOOM43_THRESHOLD))
+		    mpn_toom32_mul (prodp, up, un, vp, vn, scratch);
+		  else
+		    mpn_toom43_mul (prodp, up, un, vp, vn, scratch);
+		}
+	      else if (6 * un < 11 * vn)
+		{
+		  if (4 * un < 7 * vn)
+		    {
+		      if (BELOW_THRESHOLD (vn, MUL_TOOM32_TO_TOOM53_THRESHOLD))
+			mpn_toom32_mul (prodp, up, un, vp, vn, scratch);
+		      else
+			mpn_toom53_mul (prodp, up, un, vp, vn, scratch);
+		    }
+		  else
+		    {
+		      if (BELOW_THRESHOLD (vn, MUL_TOOM42_TO_TOOM53_THRESHOLD))
+			mpn_toom42_mul (prodp, up, un, vp, vn, scratch);
+		      else
+			mpn_toom53_mul (prodp, up, un, vp, vn, scratch);
+		    }
+		}
+	      else
+		{
+		  if (BELOW_THRESHOLD (vn, MUL_TOOM42_TO_TOOM63_THRESHOLD))
+		    mpn_toom42_mul (prodp, up, un, vp, vn, scratch);
+		  else
+		    mpn_toom63_mul (prodp, up, un, vp, vn, scratch);
+		}
+	    }
+	  TMP_FREE;
+	}
+      else
+	{
+	  mp_ptr scratch;
+	  TMP_DECL; TMP_MARK;
+
+	  if (BELOW_THRESHOLD (vn, MUL_TOOM6H_THRESHOLD))
+	    {
+	      scratch = TMP_SALLOC_LIMBS (mpn_toom44_mul_itch (un, vn));
+	      mpn_toom44_mul (prodp, up, un, vp, vn, scratch);
+	    }
+	  else if (BELOW_THRESHOLD (vn, MUL_TOOM8H_THRESHOLD))
+	    {
+	      scratch = TMP_SALLOC_LIMBS (mpn_toom6h_mul_itch (un, vn));
+	      mpn_toom6h_mul (prodp, up, un, vp, vn, scratch);
+	    }
+	  else
+	    {
+	      scratch = TMP_ALLOC_LIMBS (mpn_toom8h_mul_itch (un, vn));
+	      mpn_toom8h_mul (prodp, up, un, vp, vn, scratch);
+	    }
+	  TMP_FREE;
+	}
+    }
+  else
+    {
+      if (un >= 8 * vn)
+	{
+	  mp_limb_t cy;
+	  mp_ptr ws;
+	  TMP_DECL; TMP_MARK;
+
+	  /* The maximum ws usage is for the mpn_mul result.  */
+	  ws = TMP_BALLOC_LIMBS (9 * vn >> 1);
+
+	  mpn_fft_mul (prodp, up, 3 * vn, vp, vn);
+	  un -= 3 * vn;
+	  up += 3 * vn;
+	  prodp += 3 * vn;
+
+	  while (2 * un >= 7 * vn)	/* un >= 3.5vn  */
+	    {
+	      mpn_fft_mul (ws, up, 3 * vn, vp, vn);
+	      un -= 3 * vn;
+	      up += 3 * vn;
+	      cy = mpn_add_n (prodp, prodp, ws, vn);
+	      MPN_COPY (prodp + vn, ws + vn, 3 * vn);
+	      mpn_incr_u (prodp + vn, cy);
+	      prodp += 3 * vn;
+	    }
+
+	  /* vn / 2 <= un < 3.5vn */
+
+	  if (un < vn)
+	    mpn_mul (ws, vp, vn, up, un);
+	  else
+	    mpn_mul (ws, up, un, vp, vn);
+
+	  cy = mpn_add_n (prodp, prodp, ws, vn);
+	  MPN_COPY (prodp + vn, ws + vn, un);
+	  mpn_incr_u (prodp + vn, cy);
+
+	  TMP_FREE;
+	}
+      else
+	mpn_fft_mul (prodp, up, un, vp, vn);
+    }
+
+  return prodp[un + vn - 1];	/* historic */
+}
diff --git a/third_party/gmp/mpn/generic/mul_1.c b/third_party/gmp/mpn/generic/mul_1.c
new file mode 100644
index 0000000..52d46da
--- /dev/null
+++ b/third_party/gmp/mpn/generic/mul_1.c
@@ -0,0 +1,96 @@
+/* mpn_mul_1 -- Multiply a limb vector with a single limb and store the
+   product in a second limb vector.
+
+Copyright 1991-1994, 1996, 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+#if GMP_NAIL_BITS == 0
+
+mp_limb_t
+mpn_mul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t vl)
+{
+  mp_limb_t ul, cl, hpl, lpl;
+
+  ASSERT (n >= 1);
+  ASSERT (MPN_SAME_OR_INCR_P (rp, up, n));
+
+  cl = 0;
+  do
+    {
+      ul = *up++;
+      umul_ppmm (hpl, lpl, ul, vl);
+
+      lpl += cl;
+      cl = (lpl < cl) + hpl;
+
+      *rp++ = lpl;
+    }
+  while (--n != 0);
+
+  return cl;
+}
+
+#endif
+
+#if GMP_NAIL_BITS >= 1
+
+mp_limb_t
+mpn_mul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t vl)
+{
+  mp_limb_t shifted_vl, ul, lpl, hpl, prev_hpl, xw, cl, xl;
+
+  ASSERT (n >= 1);
+  ASSERT (MPN_SAME_OR_INCR_P (rp, up, n));
+  ASSERT_MPN (up, n);
+  ASSERT_LIMB (vl);
+
+  shifted_vl = vl << GMP_NAIL_BITS;
+  cl = 0;
+  prev_hpl = 0;
+  do
+    {
+      ul = *up++;
+
+      umul_ppmm (hpl, lpl, ul, shifted_vl);
+      lpl >>= GMP_NAIL_BITS;
+      xw = prev_hpl + lpl + cl;
+      cl = xw >> GMP_NUMB_BITS;
+      xl = xw & GMP_NUMB_MASK;
+      *rp++ = xl;
+      prev_hpl = hpl;
+    }
+  while (--n != 0);
+
+  return prev_hpl + cl;
+}
+
+#endif
diff --git a/third_party/gmp/mpn/generic/mul_basecase.c b/third_party/gmp/mpn/generic/mul_basecase.c
new file mode 100644
index 0000000..2487fba
--- /dev/null
+++ b/third_party/gmp/mpn/generic/mul_basecase.c
@@ -0,0 +1,165 @@
+/* mpn_mul_basecase -- Internal routine to multiply two natural numbers
+   of length m and n.
+
+   THIS IS AN INTERNAL FUNCTION WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH THIS FUNCTION THROUGH DOCUMENTED INTERFACES.
+
+Copyright 1991-1994, 1996, 1997, 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* Multiply {up,usize} by {vp,vsize} and write the result to
+   {prodp,usize+vsize}.  Must have usize>=vsize.
+
+   Note that prodp gets usize+vsize limbs stored, even if the actual result
+   only needs usize+vsize-1.
+
+   There's no good reason to call here with vsize>=MUL_TOOM22_THRESHOLD.
+   Currently this is allowed, but it might not be in the future.
+
+   This is the most critical code for multiplication.  All multiplies rely
+   on this, both small and huge.  Small ones arrive here immediately, huge
+   ones arrive here as this is the base case for Karatsuba's recursive
+   algorithm.  */
+
+void
+mpn_mul_basecase (mp_ptr rp,
+		  mp_srcptr up, mp_size_t un,
+		  mp_srcptr vp, mp_size_t vn)
+{
+  ASSERT (un >= vn);
+  ASSERT (vn >= 1);
+  ASSERT (! MPN_OVERLAP_P (rp, un+vn, up, un));
+  ASSERT (! MPN_OVERLAP_P (rp, un+vn, vp, vn));
+
+  /* We first multiply by the low order limb (or depending on optional function
+     availability, limbs).  This result can be stored, not added, to rp.  We
+     also avoid a loop for zeroing this way.  */
+
+#if HAVE_NATIVE_mpn_mul_2
+  if (vn >= 2)
+    {
+      rp[un + 1] = mpn_mul_2 (rp, up, un, vp);
+      rp += 2, vp += 2, vn -= 2;
+    }
+  else
+    {
+      rp[un] = mpn_mul_1 (rp, up, un, vp[0]);
+      return;
+    }
+#else
+  rp[un] = mpn_mul_1 (rp, up, un, vp[0]);
+  rp += 1, vp += 1, vn -= 1;
+#endif
+
+  /* Now accumulate the product of up[] and the next higher limb (or depending
+     on optional function availability, limbs) from vp[].  */
+
+#define MAX_LEFT MP_SIZE_T_MAX	/* Used to simplify loops into if statements */
+
+
+#if HAVE_NATIVE_mpn_addmul_6
+  while (vn >= 6)
+    {
+      rp[un + 6 - 1] = mpn_addmul_6 (rp, up, un, vp);
+      if (MAX_LEFT == 6)
+	return;
+      rp += 6, vp += 6, vn -= 6;
+      if (MAX_LEFT < 2 * 6)
+	break;
+    }
+#undef MAX_LEFT
+#define MAX_LEFT (6 - 1)
+#endif
+
+#if HAVE_NATIVE_mpn_addmul_5
+  while (vn >= 5)
+    {
+      rp[un + 5 - 1] = mpn_addmul_5 (rp, up, un, vp);
+      if (MAX_LEFT == 5)
+	return;
+      rp += 5, vp += 5, vn -= 5;
+      if (MAX_LEFT < 2 * 5)
+	break;
+    }
+#undef MAX_LEFT
+#define MAX_LEFT (5 - 1)
+#endif
+
+#if HAVE_NATIVE_mpn_addmul_4
+  while (vn >= 4)
+    {
+      rp[un + 4 - 1] = mpn_addmul_4 (rp, up, un, vp);
+      if (MAX_LEFT == 4)
+	return;
+      rp += 4, vp += 4, vn -= 4;
+      if (MAX_LEFT < 2 * 4)
+	break;
+    }
+#undef MAX_LEFT
+#define MAX_LEFT (4 - 1)
+#endif
+
+#if HAVE_NATIVE_mpn_addmul_3
+  while (vn >= 3)
+    {
+      rp[un + 3 - 1] = mpn_addmul_3 (rp, up, un, vp);
+      if (MAX_LEFT == 3)
+	return;
+      rp += 3, vp += 3, vn -= 3;
+      if (MAX_LEFT < 2 * 3)
+	break;
+    }
+#undef MAX_LEFT
+#define MAX_LEFT (3 - 1)
+#endif
+
+#if HAVE_NATIVE_mpn_addmul_2
+  while (vn >= 2)
+    {
+      rp[un + 2 - 1] = mpn_addmul_2 (rp, up, un, vp);
+      if (MAX_LEFT == 2)
+	return;
+      rp += 2, vp += 2, vn -= 2;
+      if (MAX_LEFT < 2 * 2)
+	break;
+    }
+#undef MAX_LEFT
+#define MAX_LEFT (2 - 1)
+#endif
+
+  while (vn >= 1)
+    {
+      rp[un] = mpn_addmul_1 (rp, up, un, vp[0]);
+      if (MAX_LEFT == 1)
+	return;
+      rp += 1, vp += 1, vn -= 1;
+    }
+}
diff --git a/third_party/gmp/mpn/generic/mul_fft.c b/third_party/gmp/mpn/generic/mul_fft.c
new file mode 100644
index 0000000..df8ee63
--- /dev/null
+++ b/third_party/gmp/mpn/generic/mul_fft.c
@@ -0,0 +1,1041 @@
+/* Schoenhage's fast multiplication modulo 2^N+1.
+
+   Contributed by Paul Zimmermann.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 1998-2010, 2012, 2013, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+/* References:
+
+   Schnelle Multiplikation grosser Zahlen, by Arnold Schoenhage and Volker
+   Strassen, Computing 7, p. 281-292, 1971.
+
+   Asymptotically fast algorithms for the numerical multiplication and division
+   of polynomials with complex coefficients, by Arnold Schoenhage, Computer
+   Algebra, EUROCAM'82, LNCS 144, p. 3-15, 1982.
+
+   Tapes versus Pointers, a study in implementing fast algorithms, by Arnold
+   Schoenhage, Bulletin of the EATCS, 30, p. 23-32, 1986.
+
+   TODO:
+
+   Implement some of the tricks published at ISSAC'2007 by Gaudry, Kruppa, and
+   Zimmermann.
+
+   It might be possible to avoid a small number of MPN_COPYs by using a
+   rotating temporary or two.
+
+   Cleanup and simplify the code!
+*/
+
+#ifdef TRACE
+#undef TRACE
+#define TRACE(x) x
+#include <stdio.h>
+#else
+#define TRACE(x)
+#endif
+
+#include "gmp-impl.h"
+
+#ifdef WANT_ADDSUB
+#include "generic/add_n_sub_n.c"
+#define HAVE_NATIVE_mpn_add_n_sub_n 1
+#endif
+
+static mp_limb_t mpn_mul_fft_internal (mp_ptr, mp_size_t, int, mp_ptr *,
+				       mp_ptr *, mp_ptr, mp_ptr, mp_size_t,
+				       mp_size_t, mp_size_t, int **, mp_ptr, int);
+static void mpn_mul_fft_decompose (mp_ptr, mp_ptr *, mp_size_t, mp_size_t, mp_srcptr,
+				   mp_size_t, mp_size_t, mp_size_t, mp_ptr);
+
+
+/* Find the best k to use for a mod 2^(m*GMP_NUMB_BITS)+1 FFT for m >= n.
+   We have sqr=0 if for a multiply, sqr=1 for a square.
+   There are three generations of this code; we keep the old ones as long as
+   some gmp-mparam.h is not updated.  */
+
+
+/*****************************************************************************/
+
+#if TUNE_PROGRAM_BUILD || (defined (MUL_FFT_TABLE3) && defined (SQR_FFT_TABLE3))
+
+#ifndef FFT_TABLE3_SIZE		/* When tuning this is defined in gmp-impl.h */
+#if defined (MUL_FFT_TABLE3_SIZE) && defined (SQR_FFT_TABLE3_SIZE)
+#if MUL_FFT_TABLE3_SIZE > SQR_FFT_TABLE3_SIZE
+#define FFT_TABLE3_SIZE MUL_FFT_TABLE3_SIZE
+#else
+#define FFT_TABLE3_SIZE SQR_FFT_TABLE3_SIZE
+#endif
+#endif
+#endif
+
+#ifndef FFT_TABLE3_SIZE
+#define FFT_TABLE3_SIZE 200
+#endif
+
+FFT_TABLE_ATTRS struct fft_table_nk mpn_fft_table3[2][FFT_TABLE3_SIZE] =
+{
+  MUL_FFT_TABLE3,
+  SQR_FFT_TABLE3
+};
+
+int
+mpn_fft_best_k (mp_size_t n, int sqr)
+{
+  const struct fft_table_nk *fft_tab, *tab;
+  mp_size_t tab_n, thres;
+  int last_k;
+
+  fft_tab = mpn_fft_table3[sqr];
+  last_k = fft_tab->k;
+  for (tab = fft_tab + 1; ; tab++)
+    {
+      tab_n = tab->n;
+      thres = tab_n << last_k;
+      if (n <= thres)
+	break;
+      last_k = tab->k;
+    }
+  return last_k;
+}
+
+#define MPN_FFT_BEST_READY 1
+#endif
+
+/*****************************************************************************/
+
+#if ! defined (MPN_FFT_BEST_READY)
+FFT_TABLE_ATTRS mp_size_t mpn_fft_table[2][MPN_FFT_TABLE_SIZE] =
+{
+  MUL_FFT_TABLE,
+  SQR_FFT_TABLE
+};
+
+int
+mpn_fft_best_k (mp_size_t n, int sqr)
+{
+  int i;
+
+  for (i = 0; mpn_fft_table[sqr][i] != 0; i++)
+    if (n < mpn_fft_table[sqr][i])
+      return i + FFT_FIRST_K;
+
+  /* treat 4*last as one further entry */
+  if (i == 0 || n < 4 * mpn_fft_table[sqr][i - 1])
+    return i + FFT_FIRST_K;
+  else
+    return i + FFT_FIRST_K + 1;
+}
+#endif
+
+/*****************************************************************************/
+
+
+/* Returns smallest possible number of limbs >= pl for a fft of size 2^k,
+   i.e. smallest multiple of 2^k >= pl.
+
+   Don't declare static: needed by tuneup.
+*/
+
+mp_size_t
+mpn_fft_next_size (mp_size_t pl, int k)
+{
+  pl = 1 + ((pl - 1) >> k); /* ceil (pl/2^k) */
+  return pl << k;
+}
+
+
+/* Initialize l[i][j] with bitrev(j) */
+static void
+mpn_fft_initl (int **l, int k)
+{
+  int i, j, K;
+  int *li;
+
+  l[0][0] = 0;
+  for (i = 1, K = 1; i <= k; i++, K *= 2)
+    {
+      li = l[i];
+      for (j = 0; j < K; j++)
+	{
+	  li[j] = 2 * l[i - 1][j];
+	  li[K + j] = 1 + li[j];
+	}
+    }
+}
+
+
+/* r <- a*2^d mod 2^(n*GMP_NUMB_BITS)+1 with a = {a, n+1}
+   Assumes a is semi-normalized, i.e. a[n] <= 1.
+   r and a must have n+1 limbs, and not overlap.
+*/
+static void
+mpn_fft_mul_2exp_modF (mp_ptr r, mp_srcptr a, mp_bitcnt_t d, mp_size_t n)
+{
+  unsigned int sh;
+  mp_size_t m;
+  mp_limb_t cc, rd;
+
+  sh = d % GMP_NUMB_BITS;
+  m = d / GMP_NUMB_BITS;
+
+  if (m >= n)			/* negate */
+    {
+      /* r[0..m-1]  <-- lshift(a[n-m]..a[n-1], sh)
+	 r[m..n-1]  <-- -lshift(a[0]..a[n-m-1],  sh) */
+
+      m -= n;
+      if (sh != 0)
+	{
+	  /* no out shift below since a[n] <= 1 */
+	  mpn_lshift (r, a + n - m, m + 1, sh);
+	  rd = r[m];
+	  cc = mpn_lshiftc (r + m, a, n - m, sh);
+	}
+      else
+	{
+	  MPN_COPY (r, a + n - m, m);
+	  rd = a[n];
+	  mpn_com (r + m, a, n - m);
+	  cc = 0;
+	}
+
+      /* add cc to r[0], and add rd to r[m] */
+
+      /* now add 1 in r[m], subtract 1 in r[n], i.e. add 1 in r[0] */
+
+      r[n] = 0;
+      /* cc < 2^sh <= 2^(GMP_NUMB_BITS-1) thus no overflow here */
+      cc++;
+      mpn_incr_u (r, cc);
+
+      rd++;
+      /* rd might overflow when sh=GMP_NUMB_BITS-1 */
+      cc = (rd == 0) ? 1 : rd;
+      r = r + m + (rd == 0);
+      mpn_incr_u (r, cc);
+    }
+  else
+    {
+      /* r[0..m-1]  <-- -lshift(a[n-m]..a[n-1], sh)
+	 r[m..n-1]  <-- lshift(a[0]..a[n-m-1],  sh)  */
+      if (sh != 0)
+	{
+	  /* no out bits below since a[n] <= 1 */
+	  mpn_lshiftc (r, a + n - m, m + 1, sh);
+	  rd = ~r[m];
+	  /* {r, m+1} = {a+n-m, m+1} << sh */
+	  cc = mpn_lshift (r + m, a, n - m, sh); /* {r+m, n-m} = {a, n-m}<<sh */
+	}
+      else
+	{
+	  /* r[m] is not used below, but we save a test for m=0 */
+	  mpn_com (r, a + n - m, m + 1);
+	  rd = a[n];
+	  MPN_COPY (r + m, a, n - m);
+	  cc = 0;
+	}
+
+      /* now complement {r, m}, subtract cc from r[0], subtract rd from r[m] */
+
+      /* if m=0 we just have r[0]=a[n] << sh */
+      if (m != 0)
+	{
+	  /* now add 1 in r[0], subtract 1 in r[m] */
+	  if (cc-- == 0) /* then add 1 to r[0] */
+	    cc = mpn_add_1 (r, r, n, CNST_LIMB(1));
+	  cc = mpn_sub_1 (r, r, m, cc) + 1;
+	  /* add 1 to cc instead of rd since rd might overflow */
+	}
+
+      /* now subtract cc and rd from r[m..n] */
+
+      r[n] = -mpn_sub_1 (r + m, r + m, n - m, cc);
+      r[n] -= mpn_sub_1 (r + m, r + m, n - m, rd);
+      if (r[n] & GMP_LIMB_HIGHBIT)
+	r[n] = mpn_add_1 (r, r, n, CNST_LIMB(1));
+    }
+}
+
+#if HAVE_NATIVE_mpn_add_n_sub_n
+static inline void
+mpn_fft_add_sub_modF (mp_ptr A0, mp_ptr Ai, mp_srcptr tp, mp_size_t n)
+{
+  mp_limb_t cyas, c, x;
+
+  cyas = mpn_add_n_sub_n (A0, Ai, A0, tp, n);
+
+  c = A0[n] - tp[n] - (cyas & 1);
+  x = (-c) & -((c & GMP_LIMB_HIGHBIT) != 0);
+  Ai[n] = x + c;
+  MPN_INCR_U (Ai, n + 1, x);
+
+  c = A0[n] + tp[n] + (cyas >> 1);
+  x = (c - 1) & -(c != 0);
+  A0[n] = c - x;
+  MPN_DECR_U (A0, n + 1, x);
+}
+
+#else /* ! HAVE_NATIVE_mpn_add_n_sub_n  */
+
+/* r <- a+b mod 2^(n*GMP_NUMB_BITS)+1.
+   Assumes a and b are semi-normalized.
+*/
+static inline void
+mpn_fft_add_modF (mp_ptr r, mp_srcptr a, mp_srcptr b, mp_size_t n)
+{
+  mp_limb_t c, x;
+
+  c = a[n] + b[n] + mpn_add_n (r, a, b, n);
+  /* 0 <= c <= 3 */
+
+#if 1
+  /* GCC 4.1 outsmarts most expressions here, and generates a 50% branch.  The
+     result is slower code, of course.  But the following outsmarts GCC.  */
+  x = (c - 1) & -(c != 0);
+  r[n] = c - x;
+  MPN_DECR_U (r, n + 1, x);
+#endif
+#if 0
+  if (c > 1)
+    {
+      r[n] = 1;                       /* r[n] - c = 1 */
+      MPN_DECR_U (r, n + 1, c - 1);
+    }
+  else
+    {
+      r[n] = c;
+    }
+#endif
+}
+
+/* r <- a-b mod 2^(n*GMP_NUMB_BITS)+1.
+   Assumes a and b are semi-normalized.
+*/
+static inline void
+mpn_fft_sub_modF (mp_ptr r, mp_srcptr a, mp_srcptr b, mp_size_t n)
+{
+  mp_limb_t c, x;
+
+  c = a[n] - b[n] - mpn_sub_n (r, a, b, n);
+  /* -2 <= c <= 1 */
+
+#if 1
+  /* GCC 4.1 outsmarts most expressions here, and generates a 50% branch.  The
+     result is slower code, of course.  But the following outsmarts GCC.  */
+  x = (-c) & -((c & GMP_LIMB_HIGHBIT) != 0);
+  r[n] = x + c;
+  MPN_INCR_U (r, n + 1, x);
+#endif
+#if 0
+  if ((c & GMP_LIMB_HIGHBIT) != 0)
+    {
+      r[n] = 0;
+      MPN_INCR_U (r, n + 1, -c);
+    }
+  else
+    {
+      r[n] = c;
+    }
+#endif
+}
+#endif /* HAVE_NATIVE_mpn_add_n_sub_n */
+
+/* input: A[0] ... A[inc*(K-1)] are residues mod 2^N+1 where
+	  N=n*GMP_NUMB_BITS, and 2^omega is a primitive root mod 2^N+1
+   output: A[inc*l[k][i]] <- \sum (2^omega)^(ij) A[inc*j] mod 2^N+1 */
+
+static void
+mpn_fft_fft (mp_ptr *Ap, mp_size_t K, int **ll,
+	     mp_size_t omega, mp_size_t n, mp_size_t inc, mp_ptr tp)
+{
+  if (K == 2)
+    {
+      mp_limb_t cy;
+#if HAVE_NATIVE_mpn_add_n_sub_n
+      cy = mpn_add_n_sub_n (Ap[0], Ap[inc], Ap[0], Ap[inc], n + 1) & 1;
+#else
+      MPN_COPY (tp, Ap[0], n + 1);
+      mpn_add_n (Ap[0], Ap[0], Ap[inc], n + 1);
+      cy = mpn_sub_n (Ap[inc], tp, Ap[inc], n + 1);
+#endif
+      if (Ap[0][n] > 1) /* can be 2 or 3 */
+	Ap[0][n] = 1 - mpn_sub_1 (Ap[0], Ap[0], n, Ap[0][n] - 1);
+      if (cy) /* Ap[inc][n] can be -1 or -2 */
+	Ap[inc][n] = mpn_add_1 (Ap[inc], Ap[inc], n, ~Ap[inc][n] + 1);
+    }
+  else
+    {
+      mp_size_t j, K2 = K >> 1;
+      int *lk = *ll;
+
+      mpn_fft_fft (Ap,     K2, ll-1, 2 * omega, n, inc * 2, tp);
+      mpn_fft_fft (Ap+inc, K2, ll-1, 2 * omega, n, inc * 2, tp);
+      /* A[2*j*inc]   <- A[2*j*inc] + omega^l[k][2*j*inc] A[(2j+1)inc]
+	 A[(2j+1)inc] <- A[2*j*inc] + omega^l[k][(2j+1)inc] A[(2j+1)inc] */
+      for (j = 0; j < K2; j++, lk += 2, Ap += 2 * inc)
+	{
+	  /* Ap[inc] <- Ap[0] + Ap[inc] * 2^(lk[1] * omega)
+	     Ap[0]   <- Ap[0] + Ap[inc] * 2^(lk[0] * omega) */
+	  mpn_fft_mul_2exp_modF (tp, Ap[inc], lk[0] * omega, n);
+#if HAVE_NATIVE_mpn_add_n_sub_n
+	  mpn_fft_add_sub_modF (Ap[0], Ap[inc], tp, n);
+#else
+	  mpn_fft_sub_modF (Ap[inc], Ap[0], tp, n);
+	  mpn_fft_add_modF (Ap[0],   Ap[0], tp, n);
+#endif
+	}
+    }
+}
+
+/* input: A[0] ... A[inc*(K-1)] are residues mod 2^N+1 where
+	  N=n*GMP_NUMB_BITS, and 2^omega is a primitive root mod 2^N+1
+   output: A[inc*l[k][i]] <- \sum (2^omega)^(ij) A[inc*j] mod 2^N+1
+   tp must have space for 2*(n+1) limbs.
+*/
+
+
+/* Given ap[0..n] with ap[n]<=1, reduce it modulo 2^(n*GMP_NUMB_BITS)+1,
+   by subtracting that modulus if necessary.
+
+   If ap[0..n] is exactly 2^(n*GMP_NUMB_BITS) then mpn_sub_1 produces a
+   borrow and the limbs must be zeroed out again.  This will occur very
+   infrequently.  */
+
+static inline void
+mpn_fft_normalize (mp_ptr ap, mp_size_t n)
+{
+  if (ap[n] != 0)
+    {
+      MPN_DECR_U (ap, n + 1, CNST_LIMB(1));
+      if (ap[n] == 0)
+	{
+	  /* This happens with very low probability; we have yet to trigger it,
+	     and thereby make sure this code is correct.  */
+	  MPN_ZERO (ap, n);
+	  ap[n] = 1;
+	}
+      else
+	ap[n] = 0;
+    }
+}
+
+/* a[i] <- a[i]*b[i] mod 2^(n*GMP_NUMB_BITS)+1 for 0 <= i < K */
+static void
+mpn_fft_mul_modF_K (mp_ptr *ap, mp_ptr *bp, mp_size_t n, mp_size_t K)
+{
+  int i;
+  int sqr = (ap == bp);
+  TMP_DECL;
+
+  TMP_MARK;
+
+  if (n >= (sqr ? SQR_FFT_MODF_THRESHOLD : MUL_FFT_MODF_THRESHOLD))
+    {
+      mp_size_t K2, nprime2, Nprime2, M2, maxLK, l, Mp2;
+      int k;
+      int **fft_l, *tmp;
+      mp_ptr *Ap, *Bp, A, B, T;
+
+      k = mpn_fft_best_k (n, sqr);
+      K2 = (mp_size_t) 1 << k;
+      ASSERT_ALWAYS((n & (K2 - 1)) == 0);
+      maxLK = (K2 > GMP_NUMB_BITS) ? K2 : GMP_NUMB_BITS;
+      M2 = n * GMP_NUMB_BITS >> k;
+      l = n >> k;
+      Nprime2 = ((2 * M2 + k + 2 + maxLK) / maxLK) * maxLK;
+      /* Nprime2 = ceil((2*M2+k+3)/maxLK)*maxLK*/
+      nprime2 = Nprime2 / GMP_NUMB_BITS;
+
+      /* we should ensure that nprime2 is a multiple of the next K */
+      if (nprime2 >= (sqr ? SQR_FFT_MODF_THRESHOLD : MUL_FFT_MODF_THRESHOLD))
+	{
+	  mp_size_t K3;
+	  for (;;)
+	    {
+	      K3 = (mp_size_t) 1 << mpn_fft_best_k (nprime2, sqr);
+	      if ((nprime2 & (K3 - 1)) == 0)
+		break;
+	      nprime2 = (nprime2 + K3 - 1) & -K3;
+	      Nprime2 = nprime2 * GMP_LIMB_BITS;
+	      /* warning: since nprime2 changed, K3 may change too! */
+	    }
+	}
+      ASSERT_ALWAYS(nprime2 < n); /* otherwise we'll loop */
+
+      Mp2 = Nprime2 >> k;
+
+      Ap = TMP_BALLOC_MP_PTRS (K2);
+      Bp = TMP_BALLOC_MP_PTRS (K2);
+      A = TMP_BALLOC_LIMBS (2 * (nprime2 + 1) << k);
+      T = TMP_BALLOC_LIMBS (2 * (nprime2 + 1));
+      B = A + ((nprime2 + 1) << k);
+      fft_l = TMP_BALLOC_TYPE (k + 1, int *);
+      tmp = TMP_BALLOC_TYPE ((size_t) 2 << k, int);
+      for (i = 0; i <= k; i++)
+	{
+	  fft_l[i] = tmp;
+	  tmp += (mp_size_t) 1 << i;
+	}
+
+      mpn_fft_initl (fft_l, k);
+
+      TRACE (printf ("recurse: %ldx%ld limbs -> %ld times %ldx%ld (%1.2f)\n", n,
+		    n, K2, nprime2, nprime2, 2.0*(double)n/nprime2/K2));
+      for (i = 0; i < K; i++, ap++, bp++)
+	{
+	  mp_limb_t cy;
+	  mpn_fft_normalize (*ap, n);
+	  if (!sqr)
+	    mpn_fft_normalize (*bp, n);
+
+	  mpn_mul_fft_decompose (A, Ap, K2, nprime2, *ap, (l << k) + 1, l, Mp2, T);
+	  if (!sqr)
+	    mpn_mul_fft_decompose (B, Bp, K2, nprime2, *bp, (l << k) + 1, l, Mp2, T);
+
+	  cy = mpn_mul_fft_internal (*ap, n, k, Ap, Bp, A, B, nprime2,
+				     l, Mp2, fft_l, T, sqr);
+	  (*ap)[n] = cy;
+	}
+    }
+  else
+    {
+      mp_ptr a, b, tp, tpn;
+      mp_limb_t cc;
+      mp_size_t n2 = 2 * n;
+      tp = TMP_BALLOC_LIMBS (n2);
+      tpn = tp + n;
+      TRACE (printf ("  mpn_mul_n %ld of %ld limbs\n", K, n));
+      for (i = 0; i < K; i++)
+	{
+	  a = *ap++;
+	  b = *bp++;
+	  if (sqr)
+	    mpn_sqr (tp, a, n);
+	  else
+	    mpn_mul_n (tp, b, a, n);
+	  if (a[n] != 0)
+	    cc = mpn_add_n (tpn, tpn, b, n);
+	  else
+	    cc = 0;
+	  if (b[n] != 0)
+	    cc += mpn_add_n (tpn, tpn, a, n) + a[n];
+	  if (cc != 0)
+	    {
+	      /* FIXME: use MPN_INCR_U here, since carry is not expected.  */
+	      cc = mpn_add_1 (tp, tp, n2, cc);
+	      ASSERT (cc == 0);
+	    }
+	  a[n] = mpn_sub_n (a, tp, tpn, n) && mpn_add_1 (a, a, n, CNST_LIMB(1));
+	}
+    }
+  TMP_FREE;
+}
+
+
+/* input: A^[l[k][0]] A^[l[k][1]] ... A^[l[k][K-1]]
+   output: K*A[0] K*A[K-1] ... K*A[1].
+   Assumes the Ap[] are pseudo-normalized, i.e. 0 <= Ap[][n] <= 1.
+   This condition is also fulfilled at exit.
+*/
+static void
+mpn_fft_fftinv (mp_ptr *Ap, mp_size_t K, mp_size_t omega, mp_size_t n, mp_ptr tp)
+{
+  if (K == 2)
+    {
+      mp_limb_t cy;
+#if HAVE_NATIVE_mpn_add_n_sub_n
+      cy = mpn_add_n_sub_n (Ap[0], Ap[1], Ap[0], Ap[1], n + 1) & 1;
+#else
+      MPN_COPY (tp, Ap[0], n + 1);
+      mpn_add_n (Ap[0], Ap[0], Ap[1], n + 1);
+      cy = mpn_sub_n (Ap[1], tp, Ap[1], n + 1);
+#endif
+      if (Ap[0][n] > 1) /* can be 2 or 3 */
+	Ap[0][n] = 1 - mpn_sub_1 (Ap[0], Ap[0], n, Ap[0][n] - 1);
+      if (cy) /* Ap[1][n] can be -1 or -2 */
+	Ap[1][n] = mpn_add_1 (Ap[1], Ap[1], n, ~Ap[1][n] + 1);
+    }
+  else
+    {
+      mp_size_t j, K2 = K >> 1;
+
+      mpn_fft_fftinv (Ap,      K2, 2 * omega, n, tp);
+      mpn_fft_fftinv (Ap + K2, K2, 2 * omega, n, tp);
+      /* A[j]     <- A[j] + omega^j A[j+K/2]
+	 A[j+K/2] <- A[j] + omega^(j+K/2) A[j+K/2] */
+      for (j = 0; j < K2; j++, Ap++)
+	{
+	  /* Ap[K2] <- Ap[0] + Ap[K2] * 2^((j + K2) * omega)
+	     Ap[0]  <- Ap[0] + Ap[K2] * 2^(j * omega) */
+	  mpn_fft_mul_2exp_modF (tp, Ap[K2], j * omega, n);
+#if HAVE_NATIVE_mpn_add_n_sub_n
+	  mpn_fft_add_sub_modF (Ap[0], Ap[K2], tp, n);
+#else
+	  mpn_fft_sub_modF (Ap[K2], Ap[0], tp, n);
+	  mpn_fft_add_modF (Ap[0],  Ap[0], tp, n);
+#endif
+	}
+    }
+}
+
+
+/* R <- A/2^k mod 2^(n*GMP_NUMB_BITS)+1 */
+static void
+mpn_fft_div_2exp_modF (mp_ptr r, mp_srcptr a, mp_bitcnt_t k, mp_size_t n)
+{
+  mp_bitcnt_t i;
+
+  ASSERT (r != a);
+  i = (mp_bitcnt_t) 2 * n * GMP_NUMB_BITS - k;
+  mpn_fft_mul_2exp_modF (r, a, i, n);
+  /* 1/2^k = 2^(2nL-k) mod 2^(n*GMP_NUMB_BITS)+1 */
+  /* normalize so that R < 2^(n*GMP_NUMB_BITS)+1 */
+  mpn_fft_normalize (r, n);
+}
+
+
+/* {rp,n} <- {ap,an} mod 2^(n*GMP_NUMB_BITS)+1, n <= an <= 3*n.
+   Returns carry out, i.e. 1 iff {ap,an} = -1 mod 2^(n*GMP_NUMB_BITS)+1,
+   then {rp,n}=0.
+*/
+static mp_size_t
+mpn_fft_norm_modF (mp_ptr rp, mp_size_t n, mp_ptr ap, mp_size_t an)
+{
+  mp_size_t l, m, rpn;
+  mp_limb_t cc;
+
+  ASSERT ((n <= an) && (an <= 3 * n));
+  m = an - 2 * n;
+  if (m > 0)
+    {
+      l = n;
+      /* add {ap, m} and {ap+2n, m} in {rp, m} */
+      cc = mpn_add_n (rp, ap, ap + 2 * n, m);
+      /* copy {ap+m, n-m} to {rp+m, n-m} */
+      rpn = mpn_add_1 (rp + m, ap + m, n - m, cc);
+    }
+  else
+    {
+      l = an - n; /* l <= n */
+      MPN_COPY (rp, ap, n);
+      rpn = 0;
+    }
+
+  /* remains to subtract {ap+n, l} from {rp, n+1} */
+  cc = mpn_sub_n (rp, rp, ap + n, l);
+  rpn -= mpn_sub_1 (rp + l, rp + l, n - l, cc);
+  if (rpn < 0) /* necessarily rpn = -1 */
+    rpn = mpn_add_1 (rp, rp, n, CNST_LIMB(1));
+  return rpn;
+}
+
+/* store in A[0..nprime] the first M bits from {n, nl},
+   in A[nprime+1..] the following M bits, ...
+   Assumes M is a multiple of GMP_NUMB_BITS (M = l * GMP_NUMB_BITS).
+   T must have space for at least (nprime + 1) limbs.
+   We must have nl <= 2*K*l.
+*/
+static void
+mpn_mul_fft_decompose (mp_ptr A, mp_ptr *Ap, mp_size_t K, mp_size_t nprime,
+		       mp_srcptr n, mp_size_t nl, mp_size_t l, mp_size_t Mp,
+		       mp_ptr T)
+{
+  mp_size_t i, j;
+  mp_ptr tmp;
+  mp_size_t Kl = K * l;
+  TMP_DECL;
+  TMP_MARK;
+
+  if (nl > Kl) /* normalize {n, nl} mod 2^(Kl*GMP_NUMB_BITS)+1 */
+    {
+      mp_size_t dif = nl - Kl;
+      mp_limb_signed_t cy;
+
+      tmp = TMP_BALLOC_LIMBS(Kl + 1);
+
+      if (dif > Kl)
+	{
+	  int subp = 0;
+
+	  cy = mpn_sub_n (tmp, n, n + Kl, Kl);
+	  n += 2 * Kl;
+	  dif -= Kl;
+
+	  /* now dif > 0 */
+	  while (dif > Kl)
+	    {
+	      if (subp)
+		cy += mpn_sub_n (tmp, tmp, n, Kl);
+	      else
+		cy -= mpn_add_n (tmp, tmp, n, Kl);
+	      subp ^= 1;
+	      n += Kl;
+	      dif -= Kl;
+	    }
+	  /* now dif <= Kl */
+	  if (subp)
+	    cy += mpn_sub (tmp, tmp, Kl, n, dif);
+	  else
+	    cy -= mpn_add (tmp, tmp, Kl, n, dif);
+	  if (cy >= 0)
+	    cy = mpn_add_1 (tmp, tmp, Kl, cy);
+	  else
+	    cy = mpn_sub_1 (tmp, tmp, Kl, -cy);
+	}
+      else /* dif <= Kl, i.e. nl <= 2 * Kl */
+	{
+	  cy = mpn_sub (tmp, n, Kl, n + Kl, dif);
+	  cy = mpn_add_1 (tmp, tmp, Kl, cy);
+	}
+      tmp[Kl] = cy;
+      nl = Kl + 1;
+      n = tmp;
+    }
+  for (i = 0; i < K; i++)
+    {
+      Ap[i] = A;
+      /* store the next M bits of n into A[0..nprime] */
+      if (nl > 0) /* nl is the number of remaining limbs */
+	{
+	  j = (l <= nl && i < K - 1) ? l : nl; /* store j next limbs */
+	  nl -= j;
+	  MPN_COPY (T, n, j);
+	  MPN_ZERO (T + j, nprime + 1 - j);
+	  n += l;
+	  mpn_fft_mul_2exp_modF (A, T, i * Mp, nprime);
+	}
+      else
+	MPN_ZERO (A, nprime + 1);
+      A += nprime + 1;
+    }
+  ASSERT_ALWAYS (nl == 0);
+  TMP_FREE;
+}
+
+/* op <- n*m mod 2^N+1 with fft of size 2^k where N=pl*GMP_NUMB_BITS
+   op is pl limbs, its high bit is returned.
+   One must have pl = mpn_fft_next_size (pl, k).
+   T must have space for 2 * (nprime + 1) limbs.
+*/
+
+static mp_limb_t
+mpn_mul_fft_internal (mp_ptr op, mp_size_t pl, int k,
+		      mp_ptr *Ap, mp_ptr *Bp, mp_ptr A, mp_ptr B,
+		      mp_size_t nprime, mp_size_t l, mp_size_t Mp,
+		      int **fft_l, mp_ptr T, int sqr)
+{
+  mp_size_t K, i, pla, lo, sh, j;
+  mp_ptr p;
+  mp_limb_t cc;
+
+  K = (mp_size_t) 1 << k;
+
+  /* direct fft's */
+  mpn_fft_fft (Ap, K, fft_l + k, 2 * Mp, nprime, 1, T);
+  if (!sqr)
+    mpn_fft_fft (Bp, K, fft_l + k, 2 * Mp, nprime, 1, T);
+
+  /* term to term multiplications */
+  mpn_fft_mul_modF_K (Ap, sqr ? Ap : Bp, nprime, K);
+
+  /* inverse fft's */
+  mpn_fft_fftinv (Ap, K, 2 * Mp, nprime, T);
+
+  /* division of terms after inverse fft */
+  Bp[0] = T + nprime + 1;
+  mpn_fft_div_2exp_modF (Bp[0], Ap[0], k, nprime);
+  for (i = 1; i < K; i++)
+    {
+      Bp[i] = Ap[i - 1];
+      mpn_fft_div_2exp_modF (Bp[i], Ap[i], k + (K - i) * Mp, nprime);
+    }
+
+  /* addition of terms in result p */
+  MPN_ZERO (T, nprime + 1);
+  pla = l * (K - 1) + nprime + 1; /* number of required limbs for p */
+  p = B; /* B has K*(n' + 1) limbs, which is >= pla, i.e. enough */
+  MPN_ZERO (p, pla);
+  cc = 0; /* will accumulate the (signed) carry at p[pla] */
+  for (i = K - 1, lo = l * i + nprime,sh = l * i; i >= 0; i--,lo -= l,sh -= l)
+    {
+      mp_ptr n = p + sh;
+
+      j = (K - i) & (K - 1);
+
+      if (mpn_add_n (n, n, Bp[j], nprime + 1))
+	cc += mpn_add_1 (n + nprime + 1, n + nprime + 1,
+			  pla - sh - nprime - 1, CNST_LIMB(1));
+      T[2 * l] = i + 1; /* T = (i + 1)*2^(2*M) */
+      if (mpn_cmp (Bp[j], T, nprime + 1) > 0)
+	{ /* subtract 2^N'+1 */
+	  cc -= mpn_sub_1 (n, n, pla - sh, CNST_LIMB(1));
+	  cc -= mpn_sub_1 (p + lo, p + lo, pla - lo, CNST_LIMB(1));
+	}
+    }
+  if (cc == -CNST_LIMB(1))
+    {
+      if ((cc = mpn_add_1 (p + pla - pl, p + pla - pl, pl, CNST_LIMB(1))))
+	{
+	  /* p[pla-pl]...p[pla-1] are all zero */
+	  mpn_sub_1 (p + pla - pl - 1, p + pla - pl - 1, pl + 1, CNST_LIMB(1));
+	  mpn_sub_1 (p + pla - 1, p + pla - 1, 1, CNST_LIMB(1));
+	}
+    }
+  else if (cc == 1)
+    {
+      if (pla >= 2 * pl)
+	{
+	  while ((cc = mpn_add_1 (p + pla - 2 * pl, p + pla - 2 * pl, 2 * pl, cc)))
+	    ;
+	}
+      else
+	{
+	  cc = mpn_sub_1 (p + pla - pl, p + pla - pl, pl, cc);
+	  ASSERT (cc == 0);
+	}
+    }
+  else
+    ASSERT (cc == 0);
+
+  /* here p < 2^(2M) [K 2^(M(K-1)) + (K-1) 2^(M(K-2)) + ... ]
+     < K 2^(2M) [2^(M(K-1)) + 2^(M(K-2)) + ... ]
+     < K 2^(2M) 2^(M(K-1))*2 = 2^(M*K+M+k+1) */
+  return mpn_fft_norm_modF (op, pl, p, pla);
+}
+
+/* return the lcm of a and 2^k */
+static mp_bitcnt_t
+mpn_mul_fft_lcm (mp_bitcnt_t a, int k)
+{
+  mp_bitcnt_t l = k;
+
+  while (a % 2 == 0 && k > 0)
+    {
+      a >>= 1;
+      k --;
+    }
+  return a << l;
+}
+
+
+mp_limb_t
+mpn_mul_fft (mp_ptr op, mp_size_t pl,
+	     mp_srcptr n, mp_size_t nl,
+	     mp_srcptr m, mp_size_t ml,
+	     int k)
+{
+  int i;
+  mp_size_t K, maxLK;
+  mp_size_t N, Nprime, nprime, M, Mp, l;
+  mp_ptr *Ap, *Bp, A, T, B;
+  int **fft_l, *tmp;
+  int sqr = (n == m && nl == ml);
+  mp_limb_t h;
+  TMP_DECL;
+
+  TRACE (printf ("\nmpn_mul_fft pl=%ld nl=%ld ml=%ld k=%d\n", pl, nl, ml, k));
+  ASSERT_ALWAYS (mpn_fft_next_size (pl, k) == pl);
+
+  TMP_MARK;
+  N = pl * GMP_NUMB_BITS;
+  fft_l = TMP_BALLOC_TYPE (k + 1, int *);
+  tmp = TMP_BALLOC_TYPE ((size_t) 2 << k, int);
+  for (i = 0; i <= k; i++)
+    {
+      fft_l[i] = tmp;
+      tmp += (mp_size_t) 1 << i;
+    }
+
+  mpn_fft_initl (fft_l, k);
+  K = (mp_size_t) 1 << k;
+  M = N >> k;	/* N = 2^k M */
+  l = 1 + (M - 1) / GMP_NUMB_BITS;
+  maxLK = mpn_mul_fft_lcm (GMP_NUMB_BITS, k); /* lcm (GMP_NUMB_BITS, 2^k) */
+
+  Nprime = (1 + (2 * M + k + 2) / maxLK) * maxLK;
+  /* Nprime = ceil((2*M+k+3)/maxLK)*maxLK; */
+  nprime = Nprime / GMP_NUMB_BITS;
+  TRACE (printf ("N=%ld K=%ld, M=%ld, l=%ld, maxLK=%ld, Np=%ld, np=%ld\n",
+		 N, K, M, l, maxLK, Nprime, nprime));
+  /* we should ensure that recursively, nprime is a multiple of the next K */
+  if (nprime >= (sqr ? SQR_FFT_MODF_THRESHOLD : MUL_FFT_MODF_THRESHOLD))
+    {
+      mp_size_t K2;
+      for (;;)
+	{
+	  K2 = (mp_size_t) 1 << mpn_fft_best_k (nprime, sqr);
+	  if ((nprime & (K2 - 1)) == 0)
+	    break;
+	  nprime = (nprime + K2 - 1) & -K2;
+	  Nprime = nprime * GMP_LIMB_BITS;
+	  /* warning: since nprime changed, K2 may change too! */
+	}
+      TRACE (printf ("new maxLK=%ld, Np=%ld, np=%ld\n", maxLK, Nprime, nprime));
+    }
+  ASSERT_ALWAYS (nprime < pl); /* otherwise we'll loop */
+
+  T = TMP_BALLOC_LIMBS (2 * (nprime + 1));
+  Mp = Nprime >> k;
+
+  TRACE (printf ("%ldx%ld limbs -> %ld times %ldx%ld limbs (%1.2f)\n",
+		pl, pl, K, nprime, nprime, 2.0 * (double) N / Nprime / K);
+	 printf ("   temp space %ld\n", 2 * K * (nprime + 1)));
+
+  A = TMP_BALLOC_LIMBS (K * (nprime + 1));
+  Ap = TMP_BALLOC_MP_PTRS (K);
+  mpn_mul_fft_decompose (A, Ap, K, nprime, n, nl, l, Mp, T);
+  if (sqr)
+    {
+      mp_size_t pla;
+      pla = l * (K - 1) + nprime + 1; /* number of required limbs for p */
+      B = TMP_BALLOC_LIMBS (pla);
+      Bp = TMP_BALLOC_MP_PTRS (K);
+    }
+  else
+    {
+      B = TMP_BALLOC_LIMBS (K * (nprime + 1));
+      Bp = TMP_BALLOC_MP_PTRS (K);
+      mpn_mul_fft_decompose (B, Bp, K, nprime, m, ml, l, Mp, T);
+    }
+  h = mpn_mul_fft_internal (op, pl, k, Ap, Bp, A, B, nprime, l, Mp, fft_l, T, sqr);
+
+  TMP_FREE;
+  return h;
+}
+
+#if WANT_OLD_FFT_FULL
+/* multiply {n, nl} by {m, ml}, and put the result in {op, nl+ml} */
+void
+mpn_mul_fft_full (mp_ptr op,
+		  mp_srcptr n, mp_size_t nl,
+		  mp_srcptr m, mp_size_t ml)
+{
+  mp_ptr pad_op;
+  mp_size_t pl, pl2, pl3, l;
+  mp_size_t cc, c2, oldcc;
+  int k2, k3;
+  int sqr = (n == m && nl == ml);
+
+  pl = nl + ml; /* total number of limbs of the result */
+
+  /* perform a fft mod 2^(2N)+1 and one mod 2^(3N)+1.
+     We must have pl3 = 3/2 * pl2, with pl2 a multiple of 2^k2, and
+     pl3 a multiple of 2^k3. Since k3 >= k2, both are multiples of 2^k2,
+     and pl2 must be an even multiple of 2^k2. Thus (pl2,pl3) =
+     (2*j*2^k2,3*j*2^k2), which works for 3*j <= pl/2^k2 <= 5*j.
+     We need that consecutive intervals overlap, i.e. 5*j >= 3*(j+1),
+     which requires j>=2. Thus this scheme requires pl >= 6 * 2^FFT_FIRST_K. */
+
+  /*  ASSERT_ALWAYS(pl >= 6 * (1 << FFT_FIRST_K)); */
+
+  pl2 = (2 * pl - 1) / 5; /* ceil (2pl/5) - 1 */
+  do
+    {
+      pl2++;
+      k2 = mpn_fft_best_k (pl2, sqr); /* best fft size for pl2 limbs */
+      pl2 = mpn_fft_next_size (pl2, k2);
+      pl3 = 3 * pl2 / 2; /* since k>=FFT_FIRST_K=4, pl2 is a multiple of 2^4,
+			    thus pl2 / 2 is exact */
+      k3 = mpn_fft_best_k (pl3, sqr);
+    }
+  while (mpn_fft_next_size (pl3, k3) != pl3);
+
+  TRACE (printf ("mpn_mul_fft_full nl=%ld ml=%ld -> pl2=%ld pl3=%ld k=%d\n",
+		 nl, ml, pl2, pl3, k2));
+
+  ASSERT_ALWAYS(pl3 <= pl);
+  cc = mpn_mul_fft (op, pl3, n, nl, m, ml, k3);     /* mu */
+  ASSERT(cc == 0);
+  pad_op = __GMP_ALLOCATE_FUNC_LIMBS (pl2);
+  cc = mpn_mul_fft (pad_op, pl2, n, nl, m, ml, k2); /* lambda */
+  cc = -cc + mpn_sub_n (pad_op, pad_op, op, pl2);    /* lambda - low(mu) */
+  /* 0 <= cc <= 1 */
+  ASSERT(0 <= cc && cc <= 1);
+  l = pl3 - pl2; /* l = pl2 / 2 since pl3 = 3/2 * pl2 */
+  c2 = mpn_add_n (pad_op, pad_op, op + pl2, l);
+  cc = mpn_add_1 (pad_op + l, pad_op + l, l, (mp_limb_t) c2) - cc;
+  ASSERT(-1 <= cc && cc <= 1);
+  if (cc < 0)
+    cc = mpn_add_1 (pad_op, pad_op, pl2, (mp_limb_t) -cc);
+  ASSERT(0 <= cc && cc <= 1);
+  /* now lambda-mu = {pad_op, pl2} - cc mod 2^(pl2*GMP_NUMB_BITS)+1 */
+  oldcc = cc;
+#if HAVE_NATIVE_mpn_add_n_sub_n
+  c2 = mpn_add_n_sub_n (pad_op + l, pad_op, pad_op, pad_op + l, l);
+  cc += c2 >> 1; /* carry out from high <- low + high */
+  c2 = c2 & 1; /* borrow out from low <- low - high */
+#else
+  {
+    mp_ptr tmp;
+    TMP_DECL;
+
+    TMP_MARK;
+    tmp = TMP_BALLOC_LIMBS (l);
+    MPN_COPY (tmp, pad_op, l);
+    c2 = mpn_sub_n (pad_op,      pad_op, pad_op + l, l);
+    cc += mpn_add_n (pad_op + l, tmp,    pad_op + l, l);
+    TMP_FREE;
+  }
+#endif
+  c2 += oldcc;
+  /* first normalize {pad_op, pl2} before dividing by 2: c2 is the borrow
+     at pad_op + l, cc is the carry at pad_op + pl2 */
+  /* 0 <= cc <= 2 */
+  cc -= mpn_sub_1 (pad_op + l, pad_op + l, l, (mp_limb_t) c2);
+  /* -1 <= cc <= 2 */
+  if (cc > 0)
+    cc = -mpn_sub_1 (pad_op, pad_op, pl2, (mp_limb_t) cc);
+  /* now -1 <= cc <= 0 */
+  if (cc < 0)
+    cc = mpn_add_1 (pad_op, pad_op, pl2, (mp_limb_t) -cc);
+  /* now {pad_op, pl2} is normalized, with 0 <= cc <= 1 */
+  if (pad_op[0] & 1) /* if odd, add 2^(pl2*GMP_NUMB_BITS)+1 */
+    cc += 1 + mpn_add_1 (pad_op, pad_op, pl2, CNST_LIMB(1));
+  /* now 0 <= cc <= 2, but cc=2 cannot occur since it would give a carry
+     out below */
+  mpn_rshift (pad_op, pad_op, pl2, 1); /* divide by two */
+  if (cc) /* then cc=1 */
+    pad_op [pl2 - 1] |= (mp_limb_t) 1 << (GMP_NUMB_BITS - 1);
+  /* now {pad_op,pl2}-cc = (lambda-mu)/(1-2^(l*GMP_NUMB_BITS))
+     mod 2^(pl2*GMP_NUMB_BITS) + 1 */
+  c2 = mpn_add_n (op, op, pad_op, pl2); /* no need to add cc (is 0) */
+  /* since pl2+pl3 >= pl, necessary the extra limbs (including cc) are zero */
+  MPN_COPY (op + pl3, pad_op, pl - pl3);
+  ASSERT_MPN_ZERO_P (pad_op + pl - pl3, pl2 + pl3 - pl);
+  __GMP_FREE_FUNC_LIMBS (pad_op, pl2);
+  /* since the final result has at most pl limbs, no carry out below */
+  mpn_add_1 (op + pl2, op + pl2, pl - pl2, (mp_limb_t) c2);
+}
+#endif
diff --git a/third_party/gmp/mpn/generic/mul_n.c b/third_party/gmp/mpn/generic/mul_n.c
new file mode 100644
index 0000000..36bd923
--- /dev/null
+++ b/third_party/gmp/mpn/generic/mul_n.c
@@ -0,0 +1,96 @@
+/* mpn_mul_n -- multiply natural numbers.
+
+Copyright 1991, 1993, 1994, 1996-2003, 2005, 2008, 2009 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+void
+mpn_mul_n (mp_ptr p, mp_srcptr a, mp_srcptr b, mp_size_t n)
+{
+  ASSERT (n >= 1);
+  ASSERT (! MPN_OVERLAP_P (p, 2 * n, a, n));
+  ASSERT (! MPN_OVERLAP_P (p, 2 * n, b, n));
+
+  if (BELOW_THRESHOLD (n, MUL_TOOM22_THRESHOLD))
+    {
+      mpn_mul_basecase (p, a, n, b, n);
+    }
+  else if (BELOW_THRESHOLD (n, MUL_TOOM33_THRESHOLD))
+    {
+      /* Allocate workspace of fixed size on stack: fast! */
+      mp_limb_t ws[mpn_toom22_mul_itch (MUL_TOOM33_THRESHOLD_LIMIT-1,
+					MUL_TOOM33_THRESHOLD_LIMIT-1)];
+      ASSERT (MUL_TOOM33_THRESHOLD <= MUL_TOOM33_THRESHOLD_LIMIT);
+      mpn_toom22_mul (p, a, n, b, n, ws);
+    }
+  else if (BELOW_THRESHOLD (n, MUL_TOOM44_THRESHOLD))
+    {
+      mp_ptr ws;
+      TMP_SDECL;
+      TMP_SMARK;
+      ws = TMP_SALLOC_LIMBS (mpn_toom33_mul_itch (n, n));
+      mpn_toom33_mul (p, a, n, b, n, ws);
+      TMP_SFREE;
+    }
+  else if (BELOW_THRESHOLD (n, MUL_TOOM6H_THRESHOLD))
+    {
+      mp_ptr ws;
+      TMP_SDECL;
+      TMP_SMARK;
+      ws = TMP_SALLOC_LIMBS (mpn_toom44_mul_itch (n, n));
+      mpn_toom44_mul (p, a, n, b, n, ws);
+      TMP_SFREE;
+    }
+  else if (BELOW_THRESHOLD (n, MUL_TOOM8H_THRESHOLD))
+    {
+      mp_ptr ws;
+      TMP_SDECL;
+      TMP_SMARK;
+      ws = TMP_SALLOC_LIMBS (mpn_toom6_mul_n_itch (n));
+      mpn_toom6h_mul (p, a, n, b, n, ws);
+      TMP_SFREE;
+    }
+  else if (BELOW_THRESHOLD (n, MUL_FFT_THRESHOLD))
+    {
+      mp_ptr ws;
+      TMP_DECL;
+      TMP_MARK;
+      ws = TMP_ALLOC_LIMBS (mpn_toom8_mul_n_itch (n));
+      mpn_toom8h_mul (p, a, n, b, n, ws);
+      TMP_FREE;
+    }
+  else
+    {
+      /* The current FFT code allocates its own space.  That should probably
+	 change.  */
+      mpn_fft_mul (p, a, n, b, n);
+    }
+}
diff --git a/third_party/gmp/mpn/generic/mullo_basecase.c b/third_party/gmp/mpn/generic/mullo_basecase.c
new file mode 100644
index 0000000..9a4cd3d
--- /dev/null
+++ b/third_party/gmp/mpn/generic/mullo_basecase.c
@@ -0,0 +1,90 @@
+/* mpn_mullo_basecase -- Internal routine to multiply two natural
+   numbers of length n and return the low part.
+
+   THIS IS AN INTERNAL FUNCTION WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH THIS FUNCTION THROUGH DOCUMENTED INTERFACES.
+
+
+Copyright (C) 2000, 2002, 2004, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/* FIXME: Should optionally use mpn_mul_2/mpn_addmul_2.  */
+
+#ifndef MULLO_VARIANT
+#define MULLO_VARIANT 2
+#endif
+
+
+#if MULLO_VARIANT == 1
+void
+mpn_mullo_basecase (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n)
+{
+  mp_size_t i;
+
+  mpn_mul_1 (rp, up, n, vp[0]);
+
+  for (i = n - 1; i > 0; i--)
+    {
+      vp++;
+      rp++;
+      mpn_addmul_1 (rp, up, i, vp[0]);
+    }
+}
+#endif
+
+
+#if MULLO_VARIANT == 2
+void
+mpn_mullo_basecase (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n)
+{
+  mp_limb_t h;
+
+  h = up[0] * vp[n - 1];
+
+  if (n != 1)
+    {
+      mp_size_t i;
+      mp_limb_t v0;
+
+      v0 = *vp++;
+      h += up[n - 1] * v0 + mpn_mul_1 (rp, up, n - 1, v0);
+      rp++;
+
+      for (i = n - 2; i > 0; i--)
+	{
+	  v0 = *vp++;
+	  h += up[i] * v0 + mpn_addmul_1 (rp, up, i, v0);
+	  rp++;
+	}
+    }
+
+  rp[0] = h;
+}
+#endif
diff --git a/third_party/gmp/mpn/generic/mullo_n.c b/third_party/gmp/mpn/generic/mullo_n.c
new file mode 100644
index 0000000..6f4e7ae
--- /dev/null
+++ b/third_party/gmp/mpn/generic/mullo_n.c
@@ -0,0 +1,243 @@
+/* mpn_mullo_n -- multiply two n-limb numbers and return the low n limbs
+   of their products.
+
+   Contributed to the GNU project by Torbjorn Granlund and Marco Bodrato.
+
+   THIS IS (FOR NOW) AN INTERNAL FUNCTION.  IT IS ONLY SAFE TO REACH THIS
+   FUNCTION THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST GUARANTEED
+   THAT IT'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2004, 2005, 2009, 2010, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+#if TUNE_PROGRAM_BUILD || WANT_FAT_BINARY
+#define MAYBE_range_basecase 1
+#define MAYBE_range_toom22   1
+#else
+#define MAYBE_range_basecase                                           \
+  ((MULLO_DC_THRESHOLD == 0 ? MULLO_BASECASE_THRESHOLD : MULLO_DC_THRESHOLD) < MUL_TOOM22_THRESHOLD*36/(36-11))
+#define MAYBE_range_toom22                                             \
+  ((MULLO_DC_THRESHOLD == 0 ? MULLO_BASECASE_THRESHOLD : MULLO_DC_THRESHOLD) < MUL_TOOM33_THRESHOLD*36/(36-11) )
+#endif
+
+/*  THINK: The DC strategy uses different constants in different Toom's
+	 ranges. Something smoother?
+*/
+
+/*
+  Compute the least significant half of the product {xy,n}*{yp,n}, or
+  formally {rp,n} = {xy,n}*{yp,n} Mod (B^n).
+
+  Above the given threshold, the Divide and Conquer strategy is used.
+  The operands are split in two, and a full product plus two mullo
+  are used to obtain the final result. The more natural strategy is to
+  split in two halves, but this is far from optimal when a
+  sub-quadratic multiplication is used.
+
+  Mulders suggests an unbalanced split in favour of the full product,
+  split n = n1 + n2, where an = n1 <= n2 = (1-a)n; i.e. 0 < a <= 1/2.
+
+  To compute the value of a, we assume that the cost of mullo for a
+  given size ML(n) is a fraction of the cost of a full product with
+  same size M(n), and the cost M(n)=n^e for some exponent 1 < e <= 2;
+  then we can write:
+
+  ML(n) = 2*ML(an) + M((1-a)n) => k*M(n) = 2*k*M(n)*a^e + M(n)*(1-a)^e
+
+  Given a value for e, want to minimise the value of k, i.e. the
+  function k=(1-a)^e/(1-2*a^e).
+
+  With e=2, the exponent for schoolbook multiplication, the minimum is
+  given by the values a=1-a=1/2.
+
+  With e=log(3)/log(2), the exponent for Karatsuba (aka toom22),
+  Mulders compute (1-a) = 0.694... and we approximate a with 11/36.
+
+  Other possible approximations follow:
+  e=log(5)/log(3) [Toom-3] -> a ~= 9/40
+  e=log(7)/log(4) [Toom-4] -> a ~= 7/39
+  e=log(11)/log(6) [Toom-6] -> a ~= 1/8
+  e=log(15)/log(8) [Toom-8] -> a ~= 1/10
+
+  The values above where obtained with the following trivial commands
+  in the gp-pari shell:
+
+fun(e,a)=(1-a)^e/(1-2*a^e)
+mul(a,b,c)={local(m,x,p);if(b-c<1/10000,(b+c)/2,m=1;x=b;forstep(p=c,b,(b-c)/8,if(fun(a,p)<m,m=fun(a,p);x=p));mul(a,(b+x)/2,(c+x)/2))}
+contfracpnqn(contfrac(mul(log(2*2-1)/log(2),1/2,0),5))
+contfracpnqn(contfrac(mul(log(3*2-1)/log(3),1/2,0),5))
+contfracpnqn(contfrac(mul(log(4*2-1)/log(4),1/2,0),5))
+contfracpnqn(contfrac(mul(log(6*2-1)/log(6),1/2,0),3))
+contfracpnqn(contfrac(mul(log(8*2-1)/log(8),1/2,0),3))
+
+  ,
+  |\
+  | \
+  +----,
+  |    |
+  |    |
+  |    |\
+  |    | \
+  +----+--`
+  ^ n2 ^n1^
+
+  For an actual implementation, the assumption that M(n)=n^e is
+  incorrect, as a consequence also the assumption that ML(n)=k*M(n)
+  with a constant k is wrong.
+
+  But theory suggest us two things:
+  - the best the multiplication product is (lower e), the more k
+    approaches 1, and a approaches 0.
+
+  - A value for a smaller than optimal is probably less bad than a
+    bigger one: e.g. let e=log(3)/log(2), a=0.3058_ the optimal
+    value, and k(a)=0.808_ the mul/mullo speed ratio. We get
+    k(a+1/6)=0.929_ but k(a-1/6)=0.865_.
+*/
+
+static mp_size_t
+mpn_mullo_n_itch (mp_size_t n)
+{
+  return 2*n;
+}
+
+/*
+    mpn_dc_mullo_n requires a scratch space of 2*n limbs at tp.
+    It accepts tp == rp.
+*/
+static void
+mpn_dc_mullo_n (mp_ptr rp, mp_srcptr xp, mp_srcptr yp, mp_size_t n, mp_ptr tp)
+{
+  mp_size_t n2, n1;
+  ASSERT (n >= 2);
+  ASSERT (! MPN_OVERLAP_P (rp, n, xp, n));
+  ASSERT (! MPN_OVERLAP_P (rp, n, yp, n));
+  ASSERT (MPN_SAME_OR_SEPARATE2_P(rp, n, tp, 2*n));
+
+  /* Divide-and-conquer */
+
+  /* We need fractional approximation of the value 0 < a <= 1/2
+     giving the minimum in the function k=(1-a)^e/(1-2*a^e).
+  */
+  if (MAYBE_range_basecase && BELOW_THRESHOLD (n, MUL_TOOM22_THRESHOLD*36/(36-11)))
+    n1 = n >> 1;
+  else if (MAYBE_range_toom22 && BELOW_THRESHOLD (n, MUL_TOOM33_THRESHOLD*36/(36-11)))
+    n1 = n * 11 / (size_t) 36;	/* n1 ~= n*(1-.694...) */
+  else if (BELOW_THRESHOLD (n, MUL_TOOM44_THRESHOLD*40/(40-9)))
+    n1 = n * 9 / (size_t) 40;	/* n1 ~= n*(1-.775...) */
+  else if (BELOW_THRESHOLD (n, MUL_TOOM8H_THRESHOLD*10/9))
+    n1 = n * 7 / (size_t) 39;	/* n1 ~= n*(1-.821...) */
+  /* n1 = n * 4 / (size_t) 31;	// n1 ~= n*(1-.871...) [TOOM66] */
+  else
+    n1 = n / (size_t) 10;		/* n1 ~= n*(1-.899...) [TOOM88] */
+
+  n2 = n - n1;
+
+  /* Split as x = x1 2^(n2 GMP_NUMB_BITS) + x0,
+	      y = y1 2^(n2 GMP_NUMB_BITS) + y0 */
+
+  /* x0 * y0 */
+  mpn_mul_n (tp, xp, yp, n2);
+  MPN_COPY (rp, tp, n2);
+
+  /* x1 * y0 * 2^(n2 GMP_NUMB_BITS) */
+  if (BELOW_THRESHOLD (n1, MULLO_BASECASE_THRESHOLD))
+    mpn_mul_basecase (tp + n, xp + n2, n1, yp, n1);
+  else if (BELOW_THRESHOLD (n1, MULLO_DC_THRESHOLD))
+    mpn_mullo_basecase (tp + n, xp + n2, yp, n1);
+  else
+    mpn_dc_mullo_n (tp + n, xp + n2, yp, n1, tp + n);
+  mpn_add_n (rp + n2, tp + n2, tp + n, n1);
+
+  /* x0 * y1 * 2^(n2 GMP_NUMB_BITS) */
+  if (BELOW_THRESHOLD (n1, MULLO_BASECASE_THRESHOLD))
+    mpn_mul_basecase (tp + n, xp, n1, yp + n2, n1);
+  else if (BELOW_THRESHOLD (n1, MULLO_DC_THRESHOLD))
+    mpn_mullo_basecase (tp + n, xp, yp + n2, n1);
+  else
+    mpn_dc_mullo_n (tp + n, xp, yp + n2, n1, tp + n);
+  mpn_add_n (rp + n2, rp + n2, tp + n, n1);
+}
+
+/* Avoid zero allocations when MULLO_BASECASE_THRESHOLD is 0.  */
+#define MUL_BASECASE_ALLOC \
+ (MULLO_BASECASE_THRESHOLD_LIMIT == 0 ? 1 : 2*MULLO_BASECASE_THRESHOLD_LIMIT)
+
+/* FIXME: This function should accept a temporary area; dc_mullow_n
+   accepts a pointer tp, and handle the case tp == rp, do the same here.
+   Maybe recombine the two functions.
+   THINK: If mpn_mul_basecase is always faster than mpn_mullo_basecase
+	  (typically thanks to mpn_addmul_2) should we unconditionally use
+	  mpn_mul_n?
+*/
+
+void
+mpn_mullo_n (mp_ptr rp, mp_srcptr xp, mp_srcptr yp, mp_size_t n)
+{
+  ASSERT (n >= 1);
+  ASSERT (! MPN_OVERLAP_P (rp, n, xp, n));
+  ASSERT (! MPN_OVERLAP_P (rp, n, yp, n));
+
+  if (BELOW_THRESHOLD (n, MULLO_BASECASE_THRESHOLD))
+    {
+      /* Allocate workspace of fixed size on stack: fast! */
+      mp_limb_t tp[MUL_BASECASE_ALLOC];
+      mpn_mul_basecase (tp, xp, n, yp, n);
+      MPN_COPY (rp, tp, n);
+    }
+  else if (BELOW_THRESHOLD (n, MULLO_DC_THRESHOLD))
+    {
+      mpn_mullo_basecase (rp, xp, yp, n);
+    }
+  else
+    {
+      mp_ptr tp;
+      TMP_DECL;
+      TMP_MARK;
+      tp = TMP_ALLOC_LIMBS (mpn_mullo_n_itch (n));
+      if (BELOW_THRESHOLD (n, MULLO_MUL_N_THRESHOLD))
+	{
+	  mpn_dc_mullo_n (rp, xp, yp, n, tp);
+	}
+      else
+	{
+	  /* For really large operands, use plain mpn_mul_n but throw away upper n
+	     limbs of result.  */
+#if !TUNE_PROGRAM_BUILD && (MULLO_MUL_N_THRESHOLD > MUL_FFT_THRESHOLD)
+	  mpn_fft_mul (tp, xp, n, yp, n);
+#else
+	  mpn_mul_n (tp, xp, yp, n);
+#endif
+	  MPN_COPY (rp, tp, n);
+	}
+      TMP_FREE;
+    }
+}
diff --git a/third_party/gmp/mpn/generic/mulmid.c b/third_party/gmp/mpn/generic/mulmid.c
new file mode 100644
index 0000000..f35c5fb
--- /dev/null
+++ b/third_party/gmp/mpn/generic/mulmid.c
@@ -0,0 +1,255 @@
+/* mpn_mulmid -- middle product
+
+   Contributed by David Harvey.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+
+#define CHUNK (200 + MULMID_TOOM42_THRESHOLD)
+
+
+void
+mpn_mulmid (mp_ptr rp,
+            mp_srcptr ap, mp_size_t an,
+            mp_srcptr bp, mp_size_t bn)
+{
+  mp_size_t rn, k;
+  mp_ptr scratch, temp;
+
+  ASSERT (an >= bn);
+  ASSERT (bn >= 1);
+  ASSERT (! MPN_OVERLAP_P (rp, an - bn + 3, ap, an));
+  ASSERT (! MPN_OVERLAP_P (rp, an - bn + 3, bp, bn));
+
+  if (bn < MULMID_TOOM42_THRESHOLD)
+    {
+      /* region not tall enough to make toom42 worthwhile for any portion */
+
+      if (an < CHUNK)
+	{
+	  /* region not too wide either, just call basecase directly */
+	  mpn_mulmid_basecase (rp, ap, an, bp, bn);
+	  return;
+	}
+
+      /* Region quite wide. For better locality, use basecase on chunks:
+
+	 AAABBBCC..
+	 .AAABBBCC.
+	 ..AAABBBCC
+      */
+
+      k = CHUNK - bn + 1;    /* number of diagonals per chunk */
+
+      /* first chunk (marked A in the above diagram) */
+      mpn_mulmid_basecase (rp, ap, CHUNK, bp, bn);
+
+      /* remaining chunks (B, C, etc) */
+      an -= k;
+
+      while (an >= CHUNK)
+	{
+	  mp_limb_t t0, t1, cy;
+	  ap += k, rp += k;
+	  t0 = rp[0], t1 = rp[1];
+	  mpn_mulmid_basecase (rp, ap, CHUNK, bp, bn);
+	  ADDC_LIMB (cy, rp[0], rp[0], t0);    /* add back saved limbs */
+	  MPN_INCR_U (rp + 1, k + 1, t1 + cy);
+	  an -= k;
+	}
+
+      if (an >= bn)
+	{
+	  /* last remaining chunk */
+	  mp_limb_t t0, t1, cy;
+	  ap += k, rp += k;
+	  t0 = rp[0], t1 = rp[1];
+	  mpn_mulmid_basecase (rp, ap, an, bp, bn);
+	  ADDC_LIMB (cy, rp[0], rp[0], t0);
+	  MPN_INCR_U (rp + 1, an - bn + 2, t1 + cy);
+	}
+
+      return;
+    }
+
+  /* region is tall enough for toom42 */
+
+  rn = an - bn + 1;
+
+  if (rn < MULMID_TOOM42_THRESHOLD)
+    {
+      /* region not wide enough to make toom42 worthwhile for any portion */
+
+      TMP_DECL;
+
+      if (bn < CHUNK)
+	{
+	  /* region not too tall either, just call basecase directly */
+	  mpn_mulmid_basecase (rp, ap, an, bp, bn);
+	  return;
+	}
+
+      /* Region quite tall. For better locality, use basecase on chunks:
+
+	 AAAAA....
+	 .AAAAA...
+	 ..BBBBB..
+	 ...BBBBB.
+	 ....CCCCC
+      */
+
+      TMP_MARK;
+
+      temp = TMP_ALLOC_LIMBS (rn + 2);
+
+      /* first chunk (marked A in the above diagram) */
+      bp += bn - CHUNK, an -= bn - CHUNK;
+      mpn_mulmid_basecase (rp, ap, an, bp, CHUNK);
+
+      /* remaining chunks (B, C, etc) */
+      bn -= CHUNK;
+
+      while (bn >= CHUNK)
+	{
+	  ap += CHUNK, bp -= CHUNK;
+	  mpn_mulmid_basecase (temp, ap, an, bp, CHUNK);
+	  mpn_add_n (rp, rp, temp, rn + 2);
+	  bn -= CHUNK;
+	}
+
+      if (bn)
+	{
+	  /* last remaining chunk */
+	  ap += CHUNK, bp -= bn;
+	  mpn_mulmid_basecase (temp, ap, rn + bn - 1, bp, bn);
+	  mpn_add_n (rp, rp, temp, rn + 2);
+	}
+
+      TMP_FREE;
+      return;
+    }
+
+  /* we're definitely going to use toom42 somewhere */
+
+  if (bn > rn)
+    {
+      /* slice region into chunks, use toom42 on all chunks except possibly
+	 the last:
+
+         AA....
+         .AA...
+         ..BB..
+         ...BB.
+         ....CC
+      */
+
+      TMP_DECL;
+      TMP_MARK;
+
+      temp = TMP_ALLOC_LIMBS (rn + 2 + mpn_toom42_mulmid_itch (rn));
+      scratch = temp + rn + 2;
+
+      /* first chunk (marked A in the above diagram) */
+      bp += bn - rn;
+      mpn_toom42_mulmid (rp, ap, bp, rn, scratch);
+
+      /* remaining chunks (B, C, etc) */
+      bn -= rn;
+
+      while (bn >= rn)
+        {
+          ap += rn, bp -= rn;
+	  mpn_toom42_mulmid (temp, ap, bp, rn, scratch);
+          mpn_add_n (rp, rp, temp, rn + 2);
+          bn -= rn;
+        }
+
+      if (bn)
+        {
+          /* last remaining chunk */
+          ap += rn, bp -= bn;
+	  mpn_mulmid (temp, ap, rn + bn - 1, bp, bn);
+          mpn_add_n (rp, rp, temp, rn + 2);
+        }
+
+      TMP_FREE;
+    }
+  else
+    {
+      /* slice region into chunks, use toom42 on all chunks except possibly
+	 the last:
+
+         AAABBBCC..
+         .AAABBBCC.
+         ..AAABBBCC
+      */
+
+      TMP_DECL;
+      TMP_MARK;
+
+      scratch = TMP_ALLOC_LIMBS (mpn_toom42_mulmid_itch (bn));
+
+      /* first chunk (marked A in the above diagram) */
+      mpn_toom42_mulmid (rp, ap, bp, bn, scratch);
+
+      /* remaining chunks (B, C, etc) */
+      rn -= bn;
+
+      while (rn >= bn)
+        {
+	  mp_limb_t t0, t1, cy;
+          ap += bn, rp += bn;
+          t0 = rp[0], t1 = rp[1];
+          mpn_toom42_mulmid (rp, ap, bp, bn, scratch);
+	  ADDC_LIMB (cy, rp[0], rp[0], t0);     /* add back saved limbs */
+	  MPN_INCR_U (rp + 1, bn + 1, t1 + cy);
+	  rn -= bn;
+        }
+
+      TMP_FREE;
+
+      if (rn)
+        {
+          /* last remaining chunk */
+	  mp_limb_t t0, t1, cy;
+          ap += bn, rp += bn;
+          t0 = rp[0], t1 = rp[1];
+          mpn_mulmid (rp, ap, rn + bn - 1, bp, bn);
+	  ADDC_LIMB (cy, rp[0], rp[0], t0);
+	  MPN_INCR_U (rp + 1, rn + 1, t1 + cy);
+        }
+    }
+}
diff --git a/third_party/gmp/mpn/generic/mulmid_basecase.c b/third_party/gmp/mpn/generic/mulmid_basecase.c
new file mode 100644
index 0000000..d5434ea
--- /dev/null
+++ b/third_party/gmp/mpn/generic/mulmid_basecase.c
@@ -0,0 +1,82 @@
+/* mpn_mulmid_basecase -- classical middle product algorithm
+
+   Contributed by David Harvey.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/* Middle product of {up,un} and {vp,vn}, write result to {rp,un-vn+3}.
+   Must have un >= vn >= 1.
+
+   Neither input buffer may overlap with the output buffer. */
+
+void
+mpn_mulmid_basecase (mp_ptr rp,
+                     mp_srcptr up, mp_size_t un,
+                     mp_srcptr vp, mp_size_t vn)
+{
+  mp_limb_t lo, hi;  /* last two limbs of output */
+  mp_limb_t cy;
+
+  ASSERT (un >= vn);
+  ASSERT (vn >= 1);
+  ASSERT (! MPN_OVERLAP_P (rp, un - vn + 3, up, un));
+  ASSERT (! MPN_OVERLAP_P (rp, un - vn + 3, vp, vn));
+
+  up += vn - 1;
+  un -= vn - 1;
+
+  /* multiply by first limb, store result */
+  lo = mpn_mul_1 (rp, up, un, vp[0]);
+  hi = 0;
+
+  /* accumulate remaining rows */
+  for (vn--; vn; vn--)
+    {
+      up--, vp++;
+      cy = mpn_addmul_1 (rp, up, un, vp[0]);
+      add_ssaaaa (hi, lo, hi, lo, CNST_LIMB(0), cy);
+    }
+
+  /* store final limbs */
+#if GMP_NAIL_BITS != 0
+  hi = (hi << GMP_NAIL_BITS) + (lo >> GMP_NUMB_BITS);
+  lo &= GMP_NUMB_MASK;
+#endif
+
+  rp[un] = lo;
+  rp[un + 1] = hi;
+}
diff --git a/third_party/gmp/mpn/generic/mulmid_n.c b/third_party/gmp/mpn/generic/mulmid_n.c
new file mode 100644
index 0000000..ac7e8f1
--- /dev/null
+++ b/third_party/gmp/mpn/generic/mulmid_n.c
@@ -0,0 +1,61 @@
+/* mpn_mulmid_n -- balanced middle product
+
+   Contributed by David Harvey.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+
+void
+mpn_mulmid_n (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n)
+{
+  ASSERT (n >= 1);
+  ASSERT (! MPN_OVERLAP_P (rp, n + 2, ap, 2*n - 1));
+  ASSERT (! MPN_OVERLAP_P (rp, n + 2, bp, n));
+
+  if (n < MULMID_TOOM42_THRESHOLD)
+    {
+      mpn_mulmid_basecase (rp, ap, 2*n - 1, bp, n);
+    }
+  else
+    {
+      mp_ptr scratch;
+      TMP_DECL;
+      TMP_MARK;
+      scratch = TMP_ALLOC_LIMBS (mpn_toom42_mulmid_itch (n));
+      mpn_toom42_mulmid (rp, ap, bp, n, scratch);
+      TMP_FREE;
+    }
+}
diff --git a/third_party/gmp/mpn/generic/mulmod_bnm1.c b/third_party/gmp/mpn/generic/mulmod_bnm1.c
new file mode 100644
index 0000000..769bdbc
--- /dev/null
+++ b/third_party/gmp/mpn/generic/mulmod_bnm1.c
@@ -0,0 +1,354 @@
+/* mulmod_bnm1.c -- multiplication mod B^n-1.
+
+   Contributed to the GNU project by Niels Möller, Torbjorn Granlund and
+   Marco Bodrato.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009, 2010, 2012, 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/* Inputs are {ap,rn} and {bp,rn}; output is {rp,rn}, computation is
+   mod B^rn - 1, and values are semi-normalised; zero is represented
+   as either 0 or B^n - 1.  Needs a scratch of 2rn limbs at tp.
+   tp==rp is allowed. */
+void
+mpn_bc_mulmod_bnm1 (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t rn,
+		    mp_ptr tp)
+{
+  mp_limb_t cy;
+
+  ASSERT (0 < rn);
+
+  mpn_mul_n (tp, ap, bp, rn);
+  cy = mpn_add_n (rp, tp, tp + rn, rn);
+  /* If cy == 1, then the value of rp is at most B^rn - 2, so there can
+   * be no overflow when adding in the carry. */
+  MPN_INCR_U (rp, rn, cy);
+}
+
+
+/* Inputs are {ap,rn+1} and {bp,rn+1}; output is {rp,rn+1}, in
+   semi-normalised representation, computation is mod B^rn + 1. Needs
+   a scratch area of 2rn + 2 limbs at tp; tp == rp is allowed.
+   Output is normalised. */
+static void
+mpn_bc_mulmod_bnp1 (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t rn,
+		    mp_ptr tp)
+{
+  mp_limb_t cy;
+
+  ASSERT (0 < rn);
+
+  mpn_mul_n (tp, ap, bp, rn + 1);
+  ASSERT (tp[2*rn+1] == 0);
+  ASSERT (tp[2*rn] < GMP_NUMB_MAX);
+  cy = tp[2*rn] + mpn_sub_n (rp, tp, tp+rn, rn);
+  rp[rn] = 0;
+  MPN_INCR_U (rp, rn+1, cy);
+}
+
+
+/* Computes {rp,MIN(rn,an+bn)} <- {ap,an}*{bp,bn} Mod(B^rn-1)
+ *
+ * The result is expected to be ZERO if and only if one of the operand
+ * already is. Otherwise the class [0] Mod(B^rn-1) is represented by
+ * B^rn-1. This should not be a problem if mulmod_bnm1 is used to
+ * combine results and obtain a natural number when one knows in
+ * advance that the final value is less than (B^rn-1).
+ * Moreover it should not be a problem if mulmod_bnm1 is used to
+ * compute the full product with an+bn <= rn, because this condition
+ * implies (B^an-1)(B^bn-1) < (B^rn-1) .
+ *
+ * Requires 0 < bn <= an <= rn and an + bn > rn/2
+ * Scratch need: rn + (need for recursive call OR rn + 4). This gives
+ *
+ * S(n) <= rn + MAX (rn + 4, S(n/2)) <= 2rn + 4
+ */
+void
+mpn_mulmod_bnm1 (mp_ptr rp, mp_size_t rn, mp_srcptr ap, mp_size_t an, mp_srcptr bp, mp_size_t bn, mp_ptr tp)
+{
+  ASSERT (0 < bn);
+  ASSERT (bn <= an);
+  ASSERT (an <= rn);
+
+  if ((rn & 1) != 0 || BELOW_THRESHOLD (rn, MULMOD_BNM1_THRESHOLD))
+    {
+      if (UNLIKELY (bn < rn))
+	{
+	  if (UNLIKELY (an + bn <= rn))
+	    {
+	      mpn_mul (rp, ap, an, bp, bn);
+	    }
+	  else
+	    {
+	      mp_limb_t cy;
+	      mpn_mul (tp, ap, an, bp, bn);
+	      cy = mpn_add (rp, tp, rn, tp + rn, an + bn - rn);
+	      MPN_INCR_U (rp, rn, cy);
+	    }
+	}
+      else
+	mpn_bc_mulmod_bnm1 (rp, ap, bp, rn, tp);
+    }
+  else
+    {
+      mp_size_t n;
+      mp_limb_t cy;
+      mp_limb_t hi;
+
+      n = rn >> 1;
+
+      /* We need at least an + bn >= n, to be able to fit one of the
+	 recursive products at rp. Requiring strict inequality makes
+	 the code slightly simpler. If desired, we could avoid this
+	 restriction by initially halving rn as long as rn is even and
+	 an + bn <= rn/2. */
+
+      ASSERT (an + bn > n);
+
+      /* Compute xm = a*b mod (B^n - 1), xp = a*b mod (B^n + 1)
+	 and crt together as
+
+	 x = -xp * B^n + (B^n + 1) * [ (xp + xm)/2 mod (B^n-1)]
+      */
+
+#define a0 ap
+#define a1 (ap + n)
+#define b0 bp
+#define b1 (bp + n)
+
+#define xp  tp	/* 2n + 2 */
+      /* am1  maybe in {xp, n} */
+      /* bm1  maybe in {xp + n, n} */
+#define sp1 (tp + 2*n + 2)
+      /* ap1  maybe in {sp1, n + 1} */
+      /* bp1  maybe in {sp1 + n + 1, n + 1} */
+
+      {
+	mp_srcptr am1, bm1;
+	mp_size_t anm, bnm;
+	mp_ptr so;
+
+	bm1 = b0;
+	bnm = bn;
+	if (LIKELY (an > n))
+	  {
+	    am1 = xp;
+	    cy = mpn_add (xp, a0, n, a1, an - n);
+	    MPN_INCR_U (xp, n, cy);
+	    anm = n;
+	    so = xp + n;
+	    if (LIKELY (bn > n))
+	      {
+		bm1 = so;
+		cy = mpn_add (so, b0, n, b1, bn - n);
+		MPN_INCR_U (so, n, cy);
+		bnm = n;
+		so += n;
+	      }
+	  }
+	else
+	  {
+	    so = xp;
+	    am1 = a0;
+	    anm = an;
+	  }
+
+	mpn_mulmod_bnm1 (rp, n, am1, anm, bm1, bnm, so);
+      }
+
+      {
+	int       k;
+	mp_srcptr ap1, bp1;
+	mp_size_t anp, bnp;
+
+	bp1 = b0;
+	bnp = bn;
+	if (LIKELY (an > n)) {
+	  ap1 = sp1;
+	  cy = mpn_sub (sp1, a0, n, a1, an - n);
+	  sp1[n] = 0;
+	  MPN_INCR_U (sp1, n + 1, cy);
+	  anp = n + ap1[n];
+	  if (LIKELY (bn > n)) {
+	    bp1 = sp1 + n + 1;
+	    cy = mpn_sub (sp1 + n + 1, b0, n, b1, bn - n);
+	    sp1[2*n+1] = 0;
+	    MPN_INCR_U (sp1 + n + 1, n + 1, cy);
+	    bnp = n + bp1[n];
+	  }
+	} else {
+	  ap1 = a0;
+	  anp = an;
+	}
+
+	if (BELOW_THRESHOLD (n, MUL_FFT_MODF_THRESHOLD))
+	  k=0;
+	else
+	  {
+	    int mask;
+	    k = mpn_fft_best_k (n, 0);
+	    mask = (1<<k) - 1;
+	    while (n & mask) {k--; mask >>=1;};
+	  }
+	if (k >= FFT_FIRST_K)
+	  xp[n] = mpn_mul_fft (xp, n, ap1, anp, bp1, bnp, k);
+	else if (UNLIKELY (bp1 == b0))
+	  {
+	    ASSERT (anp + bnp <= 2*n+1);
+	    ASSERT (anp + bnp > n);
+	    ASSERT (anp >= bnp);
+	    mpn_mul (xp, ap1, anp, bp1, bnp);
+	    anp = anp + bnp - n;
+	    ASSERT (anp <= n || xp[2*n]==0);
+	    anp-= anp > n;
+	    cy = mpn_sub (xp, xp, n, xp + n, anp);
+	    xp[n] = 0;
+	    MPN_INCR_U (xp, n+1, cy);
+	  }
+	else
+	  mpn_bc_mulmod_bnp1 (xp, ap1, bp1, n, xp);
+      }
+
+      /* Here the CRT recomposition begins.
+
+	 xm <- (xp + xm)/2 = (xp + xm)B^n/2 mod (B^n-1)
+	 Division by 2 is a bitwise rotation.
+
+	 Assumes xp normalised mod (B^n+1).
+
+	 The residue class [0] is represented by [B^n-1]; except when
+	 both input are ZERO.
+      */
+
+#if HAVE_NATIVE_mpn_rsh1add_n || HAVE_NATIVE_mpn_rsh1add_nc
+#if HAVE_NATIVE_mpn_rsh1add_nc
+      cy = mpn_rsh1add_nc(rp, rp, xp, n, xp[n]); /* B^n = 1 */
+      hi = cy << (GMP_NUMB_BITS - 1);
+      cy = 0;
+      /* next update of rp[n-1] will set cy = 1 only if rp[n-1]+=hi
+	 overflows, i.e. a further increment will not overflow again. */
+#else /* ! _nc */
+      cy = xp[n] + mpn_rsh1add_n(rp, rp, xp, n); /* B^n = 1 */
+      hi = (cy<<(GMP_NUMB_BITS-1))&GMP_NUMB_MASK; /* (cy&1) << ... */
+      cy >>= 1;
+      /* cy = 1 only if xp[n] = 1 i.e. {xp,n} = ZERO, this implies that
+	 the rsh1add was a simple rshift: the top bit is 0. cy=1 => hi=0. */
+#endif
+#if GMP_NAIL_BITS == 0
+      add_ssaaaa(cy, rp[n-1], cy, rp[n-1], 0, hi);
+#else
+      cy += (hi & rp[n-1]) >> (GMP_NUMB_BITS-1);
+      rp[n-1] ^= hi;
+#endif
+#else /* ! HAVE_NATIVE_mpn_rsh1add_n */
+#if HAVE_NATIVE_mpn_add_nc
+      cy = mpn_add_nc(rp, rp, xp, n, xp[n]);
+#else /* ! _nc */
+      cy = xp[n] + mpn_add_n(rp, rp, xp, n); /* xp[n] == 1 implies {xp,n} == ZERO */
+#endif
+      cy += (rp[0]&1);
+      mpn_rshift(rp, rp, n, 1);
+      ASSERT (cy <= 2);
+      hi = (cy<<(GMP_NUMB_BITS-1))&GMP_NUMB_MASK; /* (cy&1) << ... */
+      cy >>= 1;
+      /* We can have cy != 0 only if hi = 0... */
+      ASSERT ((rp[n-1] & GMP_NUMB_HIGHBIT) == 0);
+      rp[n-1] |= hi;
+      /* ... rp[n-1] + cy can not overflow, the following INCR is correct. */
+#endif
+      ASSERT (cy <= 1);
+      /* Next increment can not overflow, read the previous comments about cy. */
+      ASSERT ((cy == 0) || ((rp[n-1] & GMP_NUMB_HIGHBIT) == 0));
+      MPN_INCR_U(rp, n, cy);
+
+      /* Compute the highest half:
+	 ([(xp + xm)/2 mod (B^n-1)] - xp ) * B^n
+       */
+      if (UNLIKELY (an + bn < rn))
+	{
+	  /* Note that in this case, the only way the result can equal
+	     zero mod B^{rn} - 1 is if one of the inputs is zero, and
+	     then the output of both the recursive calls and this CRT
+	     reconstruction is zero, not B^{rn} - 1. Which is good,
+	     since the latter representation doesn't fit in the output
+	     area.*/
+	  cy = mpn_sub_n (rp + n, rp, xp, an + bn - n);
+
+	  /* FIXME: This subtraction of the high parts is not really
+	     necessary, we do it to get the carry out, and for sanity
+	     checking. */
+	  cy = xp[n] + mpn_sub_nc (xp + an + bn - n, rp + an + bn - n,
+				   xp + an + bn - n, rn - (an + bn), cy);
+	  ASSERT (an + bn == rn - 1 ||
+		  mpn_zero_p (xp + an + bn - n + 1, rn - 1 - (an + bn)));
+	  cy = mpn_sub_1 (rp, rp, an + bn, cy);
+	  ASSERT (cy == (xp + an + bn - n)[0]);
+	}
+      else
+	{
+	  cy = xp[n] + mpn_sub_n (rp + n, rp, xp, n);
+	  /* cy = 1 only if {xp,n+1} is not ZERO, i.e. {rp,n} is not ZERO.
+	     DECR will affect _at most_ the lowest n limbs. */
+	  MPN_DECR_U (rp, 2*n, cy);
+	}
+#undef a0
+#undef a1
+#undef b0
+#undef b1
+#undef xp
+#undef sp1
+    }
+}
+
+mp_size_t
+mpn_mulmod_bnm1_next_size (mp_size_t n)
+{
+  mp_size_t nh;
+
+  if (BELOW_THRESHOLD (n,     MULMOD_BNM1_THRESHOLD))
+    return n;
+  if (BELOW_THRESHOLD (n, 4 * (MULMOD_BNM1_THRESHOLD - 1) + 1))
+    return (n + (2-1)) & (-2);
+  if (BELOW_THRESHOLD (n, 8 * (MULMOD_BNM1_THRESHOLD - 1) + 1))
+    return (n + (4-1)) & (-4);
+
+  nh = (n + 1) >> 1;
+
+  if (BELOW_THRESHOLD (nh, MUL_FFT_MODF_THRESHOLD))
+    return (n + (8-1)) & (-8);
+
+  return 2 * mpn_fft_next_size (nh, mpn_fft_best_k (nh, 0));
+}
diff --git a/third_party/gmp/mpn/generic/neg.c b/third_party/gmp/mpn/generic/neg.c
new file mode 100644
index 0000000..bec2a32
--- /dev/null
+++ b/third_party/gmp/mpn/generic/neg.c
@@ -0,0 +1,33 @@
+/* mpn_neg - negate an mpn.
+
+Copyright 2001, 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define __GMP_FORCE_mpn_neg 1
+
+#include "gmp-impl.h"
diff --git a/third_party/gmp/mpn/generic/nussbaumer_mul.c b/third_party/gmp/mpn/generic/nussbaumer_mul.c
new file mode 100644
index 0000000..3e0cf27
--- /dev/null
+++ b/third_party/gmp/mpn/generic/nussbaumer_mul.c
@@ -0,0 +1,70 @@
+/* mpn_nussbaumer_mul -- Multiply {ap,an} and {bp,bn} using
+   Nussbaumer's negacyclic convolution.
+
+   Contributed to the GNU project by Marco Bodrato.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+/* Multiply {ap,an} by {bp,bn}, and put the result in {pp, an+bn} */
+void
+mpn_nussbaumer_mul (mp_ptr pp,
+		    mp_srcptr ap, mp_size_t an,
+		    mp_srcptr bp, mp_size_t bn)
+{
+  mp_size_t rn;
+  mp_ptr tp;
+  TMP_DECL;
+
+  ASSERT (an >= bn);
+  ASSERT (bn > 0);
+
+  TMP_MARK;
+
+  if ((ap == bp) && (an == bn))
+    {
+      rn = mpn_sqrmod_bnm1_next_size (2*an);
+      tp = TMP_ALLOC_LIMBS (mpn_sqrmod_bnm1_itch (rn, an));
+      mpn_sqrmod_bnm1 (pp, rn, ap, an, tp);
+    }
+  else
+    {
+      rn = mpn_mulmod_bnm1_next_size (an + bn);
+      tp = TMP_ALLOC_LIMBS (mpn_mulmod_bnm1_itch (rn, an, bn));
+      mpn_mulmod_bnm1 (pp, rn, ap, an, bp, bn, tp);
+    }
+
+  TMP_FREE;
+}
diff --git a/third_party/gmp/mpn/generic/perfpow.c b/third_party/gmp/mpn/generic/perfpow.c
new file mode 100644
index 0000000..9d46477
--- /dev/null
+++ b/third_party/gmp/mpn/generic/perfpow.c
@@ -0,0 +1,342 @@
+/* mpn_perfect_power_p -- mpn perfect power detection.
+
+   Contributed to the GNU project by Martin Boij.
+
+Copyright 2009, 2010, 2012, 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#define SMALL 20
+#define MEDIUM 100
+
+/* Return non-zero if {np,nn} == {xp,xn} ^ k.
+   Algorithm:
+       For s = 1, 2, 4, ..., s_max, compute the s least significant limbs of
+       {xp,xn}^k. Stop if they don't match the s least significant limbs of
+       {np,nn}.
+
+   FIXME: Low xn limbs can be expected to always match, if computed as a mod
+   B^{xn} root. So instead of using mpn_powlo, compute an approximation of the
+   most significant (normalized) limb of {xp,xn} ^ k (and an error bound), and
+   compare to {np, nn}. Or use an even cruder approximation based on fix-point
+   base 2 logarithm.  */
+static int
+pow_equals (mp_srcptr np, mp_size_t n,
+	    mp_srcptr xp,mp_size_t xn,
+	    mp_limb_t k, mp_bitcnt_t f,
+	    mp_ptr tp)
+{
+  mp_bitcnt_t y, z;
+  mp_size_t bn;
+  mp_limb_t h, l;
+
+  ASSERT (n > 1 || (n == 1 && np[0] > 1));
+  ASSERT (np[n - 1] > 0);
+  ASSERT (xn > 0);
+
+  if (xn == 1 && xp[0] == 1)
+    return 0;
+
+  z = 1 + (n >> 1);
+  for (bn = 1; bn < z; bn <<= 1)
+    {
+      mpn_powlo (tp, xp, &k, 1, bn, tp + bn);
+      if (mpn_cmp (tp, np, bn) != 0)
+	return 0;
+    }
+
+  /* Final check. Estimate the size of {xp,xn}^k before computing the power
+     with full precision.  Optimization: It might pay off to make a more
+     accurate estimation of the logarithm of {xp,xn}, rather than using the
+     index of the MSB.  */
+
+  MPN_SIZEINBASE_2EXP(y, xp, xn, 1);
+  y -= 1;  /* msb_index (xp, xn) */
+
+  umul_ppmm (h, l, k, y);
+  h -= l == 0;  --l;	/* two-limb decrement */
+
+  z = f - 1; /* msb_index (np, n) */
+  if (h == 0 && l <= z)
+    {
+      mp_limb_t *tp2;
+      mp_size_t i;
+      int ans;
+      mp_limb_t size;
+      TMP_DECL;
+
+      size = l + k;
+      ASSERT_ALWAYS (size >= k);
+
+      TMP_MARK;
+      y = 2 + size / GMP_LIMB_BITS;
+      tp2 = TMP_ALLOC_LIMBS (y);
+
+      i = mpn_pow_1 (tp, xp, xn, k, tp2);
+      if (i == n && mpn_cmp (tp, np, n) == 0)
+	ans = 1;
+      else
+	ans = 0;
+      TMP_FREE;
+      return ans;
+    }
+
+  return 0;
+}
+
+
+/* Return non-zero if N = {np,n} is a kth power.
+   I = {ip,n} = N^(-1) mod B^n.  */
+static int
+is_kth_power (mp_ptr rp, mp_srcptr np,
+	      mp_limb_t k, mp_srcptr ip,
+	      mp_size_t n, mp_bitcnt_t f,
+	      mp_ptr tp)
+{
+  mp_bitcnt_t b;
+  mp_size_t rn, xn;
+
+  ASSERT (n > 0);
+  ASSERT ((k & 1) != 0 || k == 2);
+  ASSERT ((np[0] & 1) != 0);
+
+  if (k == 2)
+    {
+      b = (f + 1) >> 1;
+      rn = 1 + b / GMP_LIMB_BITS;
+      if (mpn_bsqrtinv (rp, ip, b, tp) != 0)
+	{
+	  rp[rn - 1] &= (CNST_LIMB(1) << (b % GMP_LIMB_BITS)) - 1;
+	  xn = rn;
+	  MPN_NORMALIZE (rp, xn);
+	  if (pow_equals (np, n, rp, xn, k, f, tp) != 0)
+	    return 1;
+
+	  /* Check if (2^b - r)^2 == n */
+	  mpn_neg (rp, rp, rn);
+	  rp[rn - 1] &= (CNST_LIMB(1) << (b % GMP_LIMB_BITS)) - 1;
+	  MPN_NORMALIZE (rp, rn);
+	  if (pow_equals (np, n, rp, rn, k, f, tp) != 0)
+	    return 1;
+	}
+    }
+  else
+    {
+      b = 1 + (f - 1) / k;
+      rn = 1 + (b - 1) / GMP_LIMB_BITS;
+      mpn_brootinv (rp, ip, rn, k, tp);
+      if ((b % GMP_LIMB_BITS) != 0)
+	rp[rn - 1] &= (CNST_LIMB(1) << (b % GMP_LIMB_BITS)) - 1;
+      MPN_NORMALIZE (rp, rn);
+      if (pow_equals (np, n, rp, rn, k, f, tp) != 0)
+	return 1;
+    }
+  MPN_ZERO (rp, rn); /* Untrash rp */
+  return 0;
+}
+
+static int
+perfpow (mp_srcptr np, mp_size_t n,
+	 mp_limb_t ub, mp_limb_t g,
+	 mp_bitcnt_t f, int neg)
+{
+  mp_ptr ip, tp, rp;
+  mp_limb_t k;
+  int ans;
+  mp_bitcnt_t b;
+  gmp_primesieve_t ps;
+  TMP_DECL;
+
+  ASSERT (n > 0);
+  ASSERT ((np[0] & 1) != 0);
+  ASSERT (ub > 0);
+
+  TMP_MARK;
+  gmp_init_primesieve (&ps);
+  b = (f + 3) >> 1;
+
+  TMP_ALLOC_LIMBS_3 (ip, n, rp, n, tp, 5 * n);
+
+  MPN_ZERO (rp, n);
+
+  /* FIXME: It seems the inverse in ninv is needed only to get non-inverted
+     roots. I.e., is_kth_power computes n^{1/2} as (n^{-1})^{-1/2} and
+     similarly for nth roots. It should be more efficient to compute n^{1/2} as
+     n * n^{-1/2}, with a mullo instead of a binvert. And we can do something
+     similar for kth roots if we switch to an iteration converging to n^{1/k -
+     1}, and we can then eliminate this binvert call. */
+  mpn_binvert (ip, np, 1 + (b - 1) / GMP_LIMB_BITS, tp);
+  if (b % GMP_LIMB_BITS)
+    ip[(b - 1) / GMP_LIMB_BITS] &= (CNST_LIMB(1) << (b % GMP_LIMB_BITS)) - 1;
+
+  if (neg)
+    gmp_nextprime (&ps);
+
+  ans = 0;
+  if (g > 0)
+    {
+      ub = MIN (ub, g + 1);
+      while ((k = gmp_nextprime (&ps)) < ub)
+	{
+	  if ((g % k) == 0)
+	    {
+	      if (is_kth_power (rp, np, k, ip, n, f, tp) != 0)
+		{
+		  ans = 1;
+		  goto ret;
+		}
+	    }
+	}
+    }
+  else
+    {
+      while ((k = gmp_nextprime (&ps)) < ub)
+	{
+	  if (is_kth_power (rp, np, k, ip, n, f, tp) != 0)
+	    {
+	      ans = 1;
+	      goto ret;
+	    }
+	}
+    }
+ ret:
+  TMP_FREE;
+  return ans;
+}
+
+static const unsigned short nrtrial[] = { 100, 500, 1000 };
+
+/* Table of (log_{p_i} 2) values, where p_i is the (nrtrial[i] + 1)'th prime
+   number.  */
+static const double logs[] =
+  { 0.1099457228193620, 0.0847016403115322, 0.0772048195144415 };
+
+int
+mpn_perfect_power_p (mp_srcptr np, mp_size_t n)
+{
+  mp_limb_t *nc, factor, g;
+  mp_limb_t exp, d;
+  mp_bitcnt_t twos, count;
+  int ans, where, neg, trial;
+  TMP_DECL;
+
+  neg = n < 0;
+  if (neg)
+    {
+      n = -n;
+    }
+
+  if (n == 0 || (n == 1 && np[0] == 1)) /* Valgrind doesn't like
+					   (n <= (np[0] == 1)) */
+    return 1;
+
+  TMP_MARK;
+
+  count = 0;
+
+  twos = mpn_scan1 (np, 0);
+  if (twos != 0)
+    {
+      mp_size_t s;
+      if (twos == 1)
+	{
+	  return 0;
+	}
+      s = twos / GMP_LIMB_BITS;
+      if (s + 1 == n && POW2_P (np[s]))
+	{
+	  return ! (neg && POW2_P (twos));
+	}
+      count = twos % GMP_LIMB_BITS;
+      n -= s;
+      np += s;
+      if (count > 0)
+	{
+	  nc = TMP_ALLOC_LIMBS (n);
+	  mpn_rshift (nc, np, n, count);
+	  n -= (nc[n - 1] == 0);
+	  np = nc;
+	}
+    }
+  g = twos;
+
+  trial = (n > SMALL) + (n > MEDIUM);
+
+  where = 0;
+  factor = mpn_trialdiv (np, n, nrtrial[trial], &where);
+
+  if (factor != 0)
+    {
+      if (count == 0) /* We did not allocate nc yet. */
+	{
+	  nc = TMP_ALLOC_LIMBS (n);
+	}
+
+      /* Remove factors found by trialdiv.  Optimization: If remove
+	 define _itch, we can allocate its scratch just once */
+
+      do
+	{
+	  binvert_limb (d, factor);
+
+	  /* After the first round we always have nc == np */
+	  exp = mpn_remove (nc, &n, np, n, &d, 1, ~(mp_bitcnt_t)0);
+
+	  if (g == 0)
+	    g = exp;
+	  else
+	    g = mpn_gcd_1 (&g, 1, exp);
+
+	  if (g == 1)
+	    {
+	      ans = 0;
+	      goto ret;
+	    }
+
+	  if ((n == 1) & (nc[0] == 1))
+	    {
+	      ans = ! (neg && POW2_P (g));
+	      goto ret;
+	    }
+
+	  np = nc;
+	  factor = mpn_trialdiv (np, n, nrtrial[trial], &where);
+	}
+      while (factor != 0);
+    }
+
+  MPN_SIZEINBASE_2EXP(count, np, n, 1);   /* log (np) + 1 */
+  d = (mp_limb_t) (count * logs[trial] + 1e-9) + 1;
+  ans = perfpow (np, n, d, g, count, neg);
+
+ ret:
+  TMP_FREE;
+  return ans;
+}
diff --git a/third_party/gmp/mpn/generic/perfsqr.c b/third_party/gmp/mpn/generic/perfsqr.c
new file mode 100644
index 0000000..38a1a91
--- /dev/null
+++ b/third_party/gmp/mpn/generic/perfsqr.c
@@ -0,0 +1,239 @@
+/* mpn_perfect_square_p(u,usize) -- Return non-zero if U is a perfect square,
+   zero otherwise.
+
+Copyright 1991, 1993, 1994, 1996, 1997, 2000-2002, 2005, 2012 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h> /* for NULL */
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#include "perfsqr.h"
+
+
+/* change this to "#define TRACE(x) x" for diagnostics */
+#define TRACE(x)
+
+
+
+/* PERFSQR_MOD_* detects non-squares using residue tests.
+
+   A macro PERFSQR_MOD_TEST is setup by gen-psqr.c in perfsqr.h.  It takes
+   {up,usize} modulo a selected modulus to get a remainder r.  For 32-bit or
+   64-bit limbs this modulus will be 2^24-1 or 2^48-1 using PERFSQR_MOD_34,
+   or for other limb or nail sizes a PERFSQR_PP is chosen and PERFSQR_MOD_PP
+   used.  PERFSQR_PP_NORM and PERFSQR_PP_INVERTED are pre-calculated in this
+   case too.
+
+   PERFSQR_MOD_TEST then makes various calls to PERFSQR_MOD_1 or
+   PERFSQR_MOD_2 with divisors d which are factors of the modulus, and table
+   data indicating residues and non-residues modulo those divisors.  The
+   table data is in 1 or 2 limbs worth of bits respectively, per the size of
+   each d.
+
+   A "modexact" style remainder is taken to reduce r modulo d.
+   PERFSQR_MOD_IDX implements this, producing an index "idx" for use with
+   the table data.  Notice there's just one multiplication by a constant
+   "inv", for each d.
+
+   The modexact doesn't produce a true r%d remainder, instead idx satisfies
+   "-(idx<<PERFSQR_MOD_BITS) == r mod d".  Because d is odd, this factor
+   -2^PERFSQR_MOD_BITS is a one-to-one mapping between r and idx, and is
+   accounted for by having the table data suitably permuted.
+
+   The remainder r fits within PERFSQR_MOD_BITS which is less than a limb.
+   In fact the GMP_LIMB_BITS - PERFSQR_MOD_BITS spare bits are enough to fit
+   each divisor d meaning the modexact multiply can take place entirely
+   within one limb, giving the compiler the chance to optimize it, in a way
+   that say umul_ppmm would not give.
+
+   There's no need for the divisors d to be prime, in fact gen-psqr.c makes
+   a deliberate effort to combine factors so as to reduce the number of
+   separate tests done on r.  But such combining is limited to d <=
+   2*GMP_LIMB_BITS so that the table data fits in at most 2 limbs.
+
+   Alternatives:
+
+   It'd be possible to use bigger divisors d, and more than 2 limbs of table
+   data, but this doesn't look like it would be of much help to the prime
+   factors in the usual moduli 2^24-1 or 2^48-1.
+
+   The moduli 2^24-1 or 2^48-1 are nothing particularly special, they're
+   just easy to calculate (see mpn_mod_34lsub1) and have a nice set of prime
+   factors.  2^32-1 and 2^64-1 would be equally easy to calculate, but have
+   fewer prime factors.
+
+   The nails case usually ends up using mpn_mod_1, which is a lot slower
+   than mpn_mod_34lsub1.  Perhaps other such special moduli could be found
+   for the nails case.  Two-term things like 2^30-2^15-1 might be
+   candidates.  Or at worst some on-the-fly de-nailing would allow the plain
+   2^24-1 to be used.  Currently nails are too preliminary to be worried
+   about.
+
+*/
+
+#define PERFSQR_MOD_MASK       ((CNST_LIMB(1) << PERFSQR_MOD_BITS) - 1)
+
+#define MOD34_BITS  (GMP_NUMB_BITS / 4 * 3)
+#define MOD34_MASK  ((CNST_LIMB(1) << MOD34_BITS) - 1)
+
+#define PERFSQR_MOD_34(r, up, usize)				\
+  do {								\
+    (r) = mpn_mod_34lsub1 (up, usize);				\
+    (r) = ((r) & MOD34_MASK) + ((r) >> MOD34_BITS);		\
+  } while (0)
+
+/* FIXME: The %= here isn't good, and might destroy any savings from keeping
+   the PERFSQR_MOD_IDX stuff within a limb (rather than needing umul_ppmm).
+   Maybe a new sort of mpn_preinv_mod_1 could accept an unnormalized divisor
+   and a shift count, like mpn_preinv_divrem_1.  But mod_34lsub1 is our
+   normal case, so lets not worry too much about mod_1.  */
+#define PERFSQR_MOD_PP(r, up, usize)					\
+  do {									\
+    if (BELOW_THRESHOLD (usize, PREINV_MOD_1_TO_MOD_1_THRESHOLD))	\
+      {									\
+	(r) = mpn_preinv_mod_1 (up, usize, PERFSQR_PP_NORM,		\
+				PERFSQR_PP_INVERTED);			\
+	(r) %= PERFSQR_PP;						\
+      }									\
+    else								\
+      {									\
+	(r) = mpn_mod_1 (up, usize, PERFSQR_PP);			\
+      }									\
+  } while (0)
+
+#define PERFSQR_MOD_IDX(idx, r, d, inv)				\
+  do {								\
+    mp_limb_t  q;						\
+    ASSERT ((r) <= PERFSQR_MOD_MASK);				\
+    ASSERT ((((inv) * (d)) & PERFSQR_MOD_MASK) == 1);		\
+    ASSERT (MP_LIMB_T_MAX / (d) >= PERFSQR_MOD_MASK);		\
+								\
+    q = ((r) * (inv)) & PERFSQR_MOD_MASK;			\
+    ASSERT (r == ((q * (d)) & PERFSQR_MOD_MASK));		\
+    (idx) = (q * (d)) >> PERFSQR_MOD_BITS;			\
+  } while (0)
+
+#define PERFSQR_MOD_1(r, d, inv, mask)				\
+  do {								\
+    unsigned   idx;						\
+    ASSERT ((d) <= GMP_LIMB_BITS);				\
+    PERFSQR_MOD_IDX(idx, r, d, inv);				\
+    TRACE (printf ("  PERFSQR_MOD_1 d=%u r=%lu idx=%u\n",	\
+		   d, r%d, idx));				\
+    if ((((mask) >> idx) & 1) == 0)				\
+      {								\
+	TRACE (printf ("  non-square\n"));			\
+	return 0;						\
+      }								\
+  } while (0)
+
+/* The expression "(int) idx - GMP_LIMB_BITS < 0" lets the compiler use the
+   sign bit from "idx-GMP_LIMB_BITS", which might help avoid a branch.  */
+#define PERFSQR_MOD_2(r, d, inv, mhi, mlo)			\
+  do {								\
+    mp_limb_t  m;						\
+    unsigned   idx;						\
+    ASSERT ((d) <= 2*GMP_LIMB_BITS);				\
+								\
+    PERFSQR_MOD_IDX (idx, r, d, inv);				\
+    TRACE (printf ("  PERFSQR_MOD_2 d=%u r=%lu idx=%u\n",	\
+		   d, r%d, idx));				\
+    m = ((int) idx - GMP_LIMB_BITS < 0 ? (mlo) : (mhi));	\
+    idx %= GMP_LIMB_BITS;					\
+    if (((m >> idx) & 1) == 0)					\
+      {								\
+	TRACE (printf ("  non-square\n"));			\
+	return 0;						\
+      }								\
+  } while (0)
+
+
+int
+mpn_perfect_square_p (mp_srcptr up, mp_size_t usize)
+{
+  ASSERT (usize >= 1);
+
+  TRACE (gmp_printf ("mpn_perfect_square_p %Nd\n", up, usize));
+
+  /* The first test excludes 212/256 (82.8%) of the perfect square candidates
+     in O(1) time.  */
+  {
+    unsigned  idx = up[0] % 0x100;
+    if (((sq_res_0x100[idx / GMP_LIMB_BITS]
+	  >> (idx % GMP_LIMB_BITS)) & 1) == 0)
+      return 0;
+  }
+
+#if 0
+  /* Check that we have even multiplicity of 2, and then check that the rest is
+     a possible perfect square.  Leave disabled until we can determine this
+     really is an improvement.  It it is, it could completely replace the
+     simple probe above, since this should throw out more non-squares, but at
+     the expense of somewhat more cycles.  */
+  {
+    mp_limb_t lo;
+    int cnt;
+    lo = up[0];
+    while (lo == 0)
+      up++, lo = up[0], usize--;
+    count_trailing_zeros (cnt, lo);
+    if ((cnt & 1) != 0)
+      return 0;			/* return of not even multiplicity of 2 */
+    lo >>= cnt;			/* shift down to align lowest non-zero bit */
+    lo >>= 1;			/* shift away lowest non-zero bit */
+    if ((lo & 3) != 0)
+      return 0;
+  }
+#endif
+
+
+  /* The second test uses mpn_mod_34lsub1 or mpn_mod_1 to detect non-squares
+     according to their residues modulo small primes (or powers of
+     primes).  See perfsqr.h.  */
+  PERFSQR_MOD_TEST (up, usize);
+
+
+  /* For the third and last test, we finally compute the square root,
+     to make sure we've really got a perfect square.  */
+  {
+    mp_ptr root_ptr;
+    int res;
+    TMP_DECL;
+
+    TMP_MARK;
+    root_ptr = TMP_ALLOC_LIMBS ((usize + 1) / 2);
+
+    /* Iff mpn_sqrtrem returns zero, the square is perfect.  */
+    res = ! mpn_sqrtrem (root_ptr, NULL, up, usize);
+    TMP_FREE;
+
+    return res;
+  }
+}
diff --git a/third_party/gmp/mpn/generic/popham.c b/third_party/gmp/mpn/generic/popham.c
new file mode 100644
index 0000000..87974d7
--- /dev/null
+++ b/third_party/gmp/mpn/generic/popham.c
@@ -0,0 +1,125 @@
+/* mpn_popcount, mpn_hamdist -- mpn bit population count/hamming distance.
+
+Copyright 1994, 1996, 2000-2002, 2005, 2011, 2012 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#if OPERATION_popcount
+#define FNAME mpn_popcount
+#define POPHAM(u,v) u
+#endif
+
+#if OPERATION_hamdist
+#define FNAME mpn_hamdist
+#define POPHAM(u,v) u ^ v
+#endif
+
+mp_bitcnt_t
+FNAME (mp_srcptr up,
+#if OPERATION_hamdist
+       mp_srcptr vp,
+#endif
+       mp_size_t n) __GMP_NOTHROW
+{
+  mp_bitcnt_t result = 0;
+  mp_limb_t p0, p1, p2, p3, x, p01, p23;
+  mp_size_t i;
+
+  ASSERT (n >= 1);		/* Actually, this code handles any n, but some
+				   assembly implementations do not.  */
+
+  for (i = n >> 2; i != 0; i--)
+    {
+      p0 = POPHAM (up[0], vp[0]);
+      p0 -= (p0 >> 1) & MP_LIMB_T_MAX/3;				/* 2 0-2 */
+      p0 = ((p0 >> 2) & MP_LIMB_T_MAX/5) + (p0 & MP_LIMB_T_MAX/5);	/* 4 0-4 */
+
+      p1 = POPHAM (up[1], vp[1]);
+      p1 -= (p1 >> 1) & MP_LIMB_T_MAX/3;				/* 2 0-2 */
+      p1 = ((p1 >> 2) & MP_LIMB_T_MAX/5) + (p1 & MP_LIMB_T_MAX/5);	/* 4 0-4 */
+
+      p01 = p0 + p1;							/* 8 0-8 */
+      p01 = ((p01 >> 4) & MP_LIMB_T_MAX/17) + (p01 & MP_LIMB_T_MAX/17);	/* 8 0-16 */
+
+      p2 = POPHAM (up[2], vp[2]);
+      p2 -= (p2 >> 1) & MP_LIMB_T_MAX/3;				/* 2 0-2 */
+      p2 = ((p2 >> 2) & MP_LIMB_T_MAX/5) + (p2 & MP_LIMB_T_MAX/5);	/* 4 0-4 */
+
+      p3 = POPHAM (up[3], vp[3]);
+      p3 -= (p3 >> 1) & MP_LIMB_T_MAX/3;				/* 2 0-2 */
+      p3 = ((p3 >> 2) & MP_LIMB_T_MAX/5) + (p3 & MP_LIMB_T_MAX/5);	/* 4 0-4 */
+
+      p23 = p2 + p3;							/* 8 0-8 */
+      p23 = ((p23 >> 4) & MP_LIMB_T_MAX/17) + (p23 & MP_LIMB_T_MAX/17);	/* 8 0-16 */
+
+      x = p01 + p23;							/* 8 0-32 */
+      x = (x >> 8) + x;							/* 8 0-64 */
+      x = (x >> 16) + x;						/* 8 0-128 */
+#if GMP_LIMB_BITS > 32
+      x = ((x >> 32) & 0xff) + (x & 0xff);				/* 8 0-256 */
+      result += x;
+#else
+      result += x & 0xff;
+#endif
+      up += 4;
+#if OPERATION_hamdist
+      vp += 4;
+#endif
+    }
+
+  n &= 3;
+  if (n != 0)
+    {
+      x = 0;
+      do
+	{
+	  p0 = POPHAM (up[0], vp[0]);
+	  p0 -= (p0 >> 1) & MP_LIMB_T_MAX/3;				/* 2 0-2 */
+	  p0 = ((p0 >> 2) & MP_LIMB_T_MAX/5) + (p0 & MP_LIMB_T_MAX/5);	/* 4 0-4 */
+	  p0 = ((p0 >> 4) + p0) & MP_LIMB_T_MAX/17;			/* 8 0-8 */
+
+	  x += p0;
+	  up += 1;
+#if OPERATION_hamdist
+	  vp += 1;
+#endif
+	}
+      while (--n);
+
+      x = (x >> 8) + x;
+      x = (x >> 16) + x;
+#if GMP_LIMB_BITS > 32
+      x = (x >> 32) + x;
+#endif
+      result += x & 0xff;
+    }
+
+  return result;
+}
diff --git a/third_party/gmp/mpn/generic/pow_1.c b/third_party/gmp/mpn/generic/pow_1.c
new file mode 100644
index 0000000..de11cd2
--- /dev/null
+++ b/third_party/gmp/mpn/generic/pow_1.c
@@ -0,0 +1,135 @@
+/* mpn_pow_1 -- Compute powers R = U^exp.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2002, 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+mp_size_t
+mpn_pow_1 (mp_ptr rp, mp_srcptr bp, mp_size_t bn, mp_limb_t exp, mp_ptr tp)
+{
+  mp_limb_t x;
+  int cnt, i;
+  mp_size_t rn;
+  int par;
+
+  ASSERT (bn >= 1);
+  /* FIXME: Add operand overlap criteria */
+
+  if (exp <= 1)
+    {
+      if (exp == 0)
+	{
+	  rp[0] = 1;
+	  return 1;
+	}
+      else
+	{
+	  MPN_COPY (rp, bp, bn);
+	  return bn;
+	}
+    }
+
+  /* Count number of bits in exp, and compute where to put initial square in
+     order to magically get results in the entry rp.  Use simple code,
+     optimized for small exp.  For large exp, the bignum operations will take
+     so much time that the slowness of this code will be negligible.  */
+  par = 0;
+  cnt = GMP_LIMB_BITS;
+  x = exp;
+  do
+    {
+      par ^= x;
+      cnt--;
+      x >>= 1;
+    } while (x != 0);
+  exp <<= cnt;
+
+  if (bn == 1)
+    {
+      mp_limb_t rl, rh, bl = bp[0];
+
+      if ((cnt & 1) != 0)
+	MP_PTR_SWAP (rp, tp);
+
+      umul_ppmm (rh, rl, bl, bl << GMP_NAIL_BITS);
+      rp[0] = rl >> GMP_NAIL_BITS;
+      rp[1] = rh;
+      rn = 1 + (rh != 0);
+
+      for (i = GMP_LIMB_BITS - cnt - 1;;)
+	{
+	  exp <<= 1;
+	  if ((exp & GMP_LIMB_HIGHBIT) != 0)
+	    {
+	      rp[rn] = rh = mpn_mul_1 (rp, rp, rn, bl);
+	      rn += rh != 0;
+	    }
+
+	  if (--i == 0)
+	    break;
+
+	  mpn_sqr (tp, rp, rn);
+	  rn = 2 * rn; rn -= tp[rn - 1] == 0;
+	  MP_PTR_SWAP (rp, tp);
+	}
+    }
+  else
+    {
+      if (((par ^ cnt) & 1) == 0)
+	MP_PTR_SWAP (rp, tp);
+
+      mpn_sqr (rp, bp, bn);
+      rn = 2 * bn; rn -= rp[rn - 1] == 0;
+
+      for (i = GMP_LIMB_BITS - cnt - 1;;)
+	{
+	  exp <<= 1;
+	  if ((exp & GMP_LIMB_HIGHBIT) != 0)
+	    {
+	      rn = rn + bn - (mpn_mul (tp, rp, rn, bp, bn) == 0);
+	      MP_PTR_SWAP (rp, tp);
+	    }
+
+	  if (--i == 0)
+	    break;
+
+	  mpn_sqr (tp, rp, rn);
+	  rn = 2 * rn; rn -= tp[rn - 1] == 0;
+	  MP_PTR_SWAP (rp, tp);
+	}
+    }
+
+  return rn;
+}
diff --git a/third_party/gmp/mpn/generic/powlo.c b/third_party/gmp/mpn/generic/powlo.c
new file mode 100644
index 0000000..3b26bca
--- /dev/null
+++ b/third_party/gmp/mpn/generic/powlo.c
@@ -0,0 +1,188 @@
+/* mpn_powlo -- Compute R = U^E mod B^n, where B is the limb base.
+
+Copyright 2007-2009, 2012, 2015, 2016, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+#define getbit(p,bi) \
+  ((p[(bi - 1) / GMP_LIMB_BITS] >> (bi - 1) % GMP_LIMB_BITS) & 1)
+
+static inline mp_limb_t
+getbits (const mp_limb_t *p, mp_bitcnt_t bi, unsigned nbits)
+{
+  unsigned nbits_in_r;
+  mp_limb_t r;
+  mp_size_t i;
+
+  if (bi < nbits)
+    {
+      return p[0] & (((mp_limb_t) 1 << bi) - 1);
+    }
+  else
+    {
+      bi -= nbits;			/* bit index of low bit to extract */
+      i = bi / GMP_NUMB_BITS;		/* word index of low bit to extract */
+      bi %= GMP_NUMB_BITS;		/* bit index in low word */
+      r = p[i] >> bi;			/* extract (low) bits */
+      nbits_in_r = GMP_NUMB_BITS - bi;	/* number of bits now in r */
+      if (nbits_in_r < nbits)		/* did we get enough bits? */
+	r += p[i + 1] << nbits_in_r;	/* prepend bits from higher word */
+      return r & (((mp_limb_t ) 1 << nbits) - 1);
+    }
+}
+
+static inline unsigned
+win_size (mp_bitcnt_t eb)
+{
+  unsigned k;
+  static mp_bitcnt_t x[] = {7,25,81,241,673,1793,4609,11521,28161,~(mp_bitcnt_t)0};
+  ASSERT (eb > 1);
+  for (k = 0; eb > x[k++];)
+    ;
+  return k;
+}
+
+/* rp[n-1..0] = bp[n-1..0] ^ ep[en-1..0] mod B^n, B is the limb base.
+   Requires that ep[en-1] is non-zero.
+   Uses scratch space tp[3n-1..0], i.e., 3n words.  */
+/* We only use n words in the scratch space, we should pass tp + n to
+   mullo/sqrlo as a temporary area, it is needed. */
+void
+mpn_powlo (mp_ptr rp, mp_srcptr bp,
+	   mp_srcptr ep, mp_size_t en,
+	   mp_size_t n, mp_ptr tp)
+{
+  unsigned cnt;
+  mp_bitcnt_t ebi;
+  unsigned windowsize, this_windowsize;
+  mp_limb_t expbits;
+  mp_limb_t *pp;
+  long i;
+  int flipflop;
+  TMP_DECL;
+
+  ASSERT (en > 1 || (en == 1 && ep[0] > 1));
+
+  TMP_MARK;
+
+  MPN_SIZEINBASE_2EXP(ebi, ep, en, 1);
+
+  windowsize = win_size (ebi);
+  if (windowsize > 1)
+    {
+      mp_limb_t *this_pp, *last_pp;
+      ASSERT (windowsize < ebi);
+
+      pp = TMP_ALLOC_LIMBS ((n << (windowsize - 1)));
+
+      this_pp = pp;
+
+      MPN_COPY (this_pp, bp, n);
+
+      /* Store b^2 in tp.  */
+      mpn_sqrlo (tp, bp, n);
+
+      /* Precompute odd powers of b and put them in the temporary area at pp.  */
+      i = (1 << (windowsize - 1)) - 1;
+      do
+	{
+	  last_pp = this_pp;
+	  this_pp += n;
+	  mpn_mullo_n (this_pp, last_pp, tp, n);
+	} while (--i != 0);
+
+      expbits = getbits (ep, ebi, windowsize);
+
+      /* THINK: Should we initialise the case expbits % 4 == 0 with a mullo? */
+      count_trailing_zeros (cnt, expbits);
+      ebi -= windowsize;
+      ebi += cnt;
+      expbits >>= cnt;
+
+      MPN_COPY (rp, pp + n * (expbits >> 1), n);
+    }
+  else
+    {
+      pp = tp + n;
+      MPN_COPY (pp, bp, n);
+      MPN_COPY (rp, bp, n);
+      --ebi;
+    }
+
+  flipflop = 0;
+
+  do
+    {
+      while (getbit (ep, ebi) == 0)
+	{
+	  mpn_sqrlo (tp, rp, n);
+	  MP_PTR_SWAP (rp, tp);
+	  flipflop = ! flipflop;
+	  if (--ebi == 0)
+	    goto done;
+	}
+
+      /* The next bit of the exponent is 1.  Now extract the largest block of
+	 bits <= windowsize, and such that the least significant bit is 1.  */
+
+      expbits = getbits (ep, ebi, windowsize);
+      this_windowsize = MIN (windowsize, ebi);
+      ebi -= this_windowsize;
+
+      count_trailing_zeros (cnt, expbits);
+      this_windowsize -= cnt;
+      ebi += cnt;
+      expbits >>= cnt;
+
+      while (this_windowsize > 1)
+	{
+	  mpn_sqrlo (tp, rp, n);
+	  mpn_sqrlo (rp, tp, n);
+	  this_windowsize -= 2;
+	}
+
+      if (this_windowsize != 0)
+	mpn_sqrlo (tp, rp, n);
+      else
+	{
+	  MP_PTR_SWAP (rp, tp);
+	  flipflop = ! flipflop;
+	}
+
+      mpn_mullo_n (rp, tp, pp + n * (expbits >> 1), n);
+    } while (ebi != 0);
+
+ done:
+  if (flipflop)
+    MPN_COPY (tp, rp, n);
+  TMP_FREE;
+}
diff --git a/third_party/gmp/mpn/generic/powm.c b/third_party/gmp/mpn/generic/powm.c
new file mode 100644
index 0000000..2828103
--- /dev/null
+++ b/third_party/gmp/mpn/generic/powm.c
@@ -0,0 +1,635 @@
+/* mpn_powm -- Compute R = U^E mod M.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2007-2012, 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+/*
+  BASIC ALGORITHM, Compute U^E mod M, where M < B^n is odd.
+
+  1. W <- U
+
+  2. T <- (B^n * U) mod M                Convert to REDC form
+
+  3. Compute table U^1, U^3, U^5... of E-dependent size
+
+  4. While there are more bits in E
+       W <- power left-to-right base-k
+
+
+  TODO:
+
+   * Make getbits a macro, thereby allowing it to update the index operand.
+     That will simplify the code using getbits.  (Perhaps make getbits' sibling
+     getbit then have similar form, for symmetry.)
+
+   * Write an itch function.  Or perhaps get rid of tp parameter since the huge
+     pp area is allocated locally anyway?
+
+   * Choose window size without looping.  (Superoptimize or think(tm).)
+
+   * Handle small bases with initial, reduction-free exponentiation.
+
+   * Call new division functions, not mpn_tdiv_qr.
+
+   * Consider special code for one-limb M.
+
+   * How should we handle the redc1/redc2/redc_n choice?
+     - redc1:  T(binvert_1limb)  + e * (n)   * (T(mullo-1x1) + n*T(addmul_1))
+     - redc2:  T(binvert_2limbs) + e * (n/2) * (T(mullo-2x2) + n*T(addmul_2))
+     - redc_n: T(binvert_nlimbs) + e * (T(mullo-nxn) + T(M(n)))
+     This disregards the addmul_N constant term, but we could think of
+     that as part of the respective mullo.
+
+   * When U (the base) is small, we should start the exponentiation with plain
+     operations, then convert that partial result to REDC form.
+
+   * When U is just one limb, should it be handled without the k-ary tricks?
+     We could keep a factor of B^n in W, but use U' = BU as base.  After
+     multiplying by this (pseudo two-limb) number, we need to multiply by 1/B
+     mod M.
+*/
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#undef MPN_REDC_0
+#define MPN_REDC_0(rp, up, mp, invm)					\
+  do {									\
+    mp_limb_t p1, r0, u0, _dummy;					\
+    u0 = *(up);								\
+    umul_ppmm (p1, _dummy, *(mp), (u0 * (invm)) & GMP_NUMB_MASK);	\
+    ASSERT (((u0 + _dummy) & GMP_NUMB_MASK) == 0);			\
+    p1 += (u0 != 0);							\
+    r0 = (up)[1] + p1;							\
+    if (p1 > r0)							\
+      r0 -= *(mp);							\
+    *(rp) = r0;								\
+  } while (0)
+
+#undef MPN_REDC_1
+#if HAVE_NATIVE_mpn_sbpi1_bdiv_r
+#define MPN_REDC_1(rp, up, mp, n, invm)					\
+  do {									\
+    mp_limb_t cy;							\
+    cy = mpn_sbpi1_bdiv_r (up, 2 * n, mp, n, invm);			\
+    if (cy != 0)							\
+      mpn_sub_n (rp, up + n, mp, n);					\
+    else								\
+      MPN_COPY (rp, up + n, n);						\
+  } while (0)
+#else
+#define MPN_REDC_1(rp, up, mp, n, invm)					\
+  do {									\
+    mp_limb_t cy;							\
+    cy = mpn_redc_1 (rp, up, mp, n, invm);				\
+    if (cy != 0)							\
+      mpn_sub_n (rp, rp, mp, n);					\
+  } while (0)
+#endif
+
+#undef MPN_REDC_2
+#define MPN_REDC_2(rp, up, mp, n, mip)					\
+  do {									\
+    mp_limb_t cy;							\
+    cy = mpn_redc_2 (rp, up, mp, n, mip);				\
+    if (cy != 0)							\
+      mpn_sub_n (rp, rp, mp, n);					\
+  } while (0)
+
+#if HAVE_NATIVE_mpn_addmul_2 || HAVE_NATIVE_mpn_redc_2
+#define WANT_REDC_2 1
+#endif
+
+#define getbit(p,bi) \
+  ((p[(bi - 1) / GMP_LIMB_BITS] >> (bi - 1) % GMP_LIMB_BITS) & 1)
+
+static inline mp_limb_t
+getbits (const mp_limb_t *p, mp_bitcnt_t bi, int nbits)
+{
+  int nbits_in_r;
+  mp_limb_t r;
+  mp_size_t i;
+
+  if (bi < nbits)
+    {
+      return p[0] & (((mp_limb_t) 1 << bi) - 1);
+    }
+  else
+    {
+      bi -= nbits;			/* bit index of low bit to extract */
+      i = bi / GMP_NUMB_BITS;		/* word index of low bit to extract */
+      bi %= GMP_NUMB_BITS;		/* bit index in low word */
+      r = p[i] >> bi;			/* extract (low) bits */
+      nbits_in_r = GMP_NUMB_BITS - bi;	/* number of bits now in r */
+      if (nbits_in_r < nbits)		/* did we get enough bits? */
+	r += p[i + 1] << nbits_in_r;	/* prepend bits from higher word */
+      return r & (((mp_limb_t) 1 << nbits) - 1);
+    }
+}
+
+static inline int
+win_size (mp_bitcnt_t eb)
+{
+  int k;
+  static mp_bitcnt_t x[] = {0,7,25,81,241,673,1793,4609,11521,28161,~(mp_bitcnt_t)0};
+  for (k = 1; eb > x[k]; k++)
+    ;
+  return k;
+}
+
+/* Convert U to REDC form, U_r = B^n * U mod M */
+static void
+redcify (mp_ptr rp, mp_srcptr up, mp_size_t un, mp_srcptr mp, mp_size_t n)
+{
+  mp_ptr tp, qp;
+  TMP_DECL;
+  TMP_MARK;
+
+  TMP_ALLOC_LIMBS_2 (tp, un + n, qp, un + 1);
+
+  MPN_ZERO (tp, n);
+  MPN_COPY (tp + n, up, un);
+  mpn_tdiv_qr (qp, rp, 0L, tp, un + n, mp, n);
+  TMP_FREE;
+}
+
+/* rp[n-1..0] = bp[bn-1..0] ^ ep[en-1..0] mod mp[n-1..0]
+   Requires that mp[n-1..0] is odd.
+   Requires that ep[en-1..0] is > 1.
+   Uses scratch space at tp of MAX(mpn_binvert_itch(n),2n) limbs.  */
+void
+mpn_powm (mp_ptr rp, mp_srcptr bp, mp_size_t bn,
+	  mp_srcptr ep, mp_size_t en,
+	  mp_srcptr mp, mp_size_t n, mp_ptr tp)
+{
+  mp_limb_t ip[2], *mip;
+  int cnt;
+  mp_bitcnt_t ebi;
+  int windowsize, this_windowsize;
+  mp_limb_t expbits;
+  mp_ptr pp, this_pp;
+  long i;
+  TMP_DECL;
+
+  ASSERT (en > 1 || (en == 1 && ep[0] > 1));
+  ASSERT (n >= 1 && ((mp[0] & 1) != 0));
+
+  TMP_MARK;
+
+  MPN_SIZEINBASE_2EXP(ebi, ep, en, 1);
+
+#if 0
+  if (bn < n)
+    {
+      /* Do the first few exponent bits without mod reductions,
+	 until the result is greater than the mod argument.  */
+      for (;;)
+	{
+	  mpn_sqr (tp, this_pp, tn);
+	  tn = tn * 2 - 1,  tn += tp[tn] != 0;
+	  if (getbit (ep, ebi) != 0)
+	    mpn_mul (..., tp, tn, bp, bn);
+	  ebi--;
+	}
+    }
+#endif
+
+  windowsize = win_size (ebi);
+
+#if WANT_REDC_2
+  if (BELOW_THRESHOLD (n, REDC_1_TO_REDC_2_THRESHOLD))
+    {
+      mip = ip;
+      binvert_limb (mip[0], mp[0]);
+      mip[0] = -mip[0];
+    }
+  else if (BELOW_THRESHOLD (n, REDC_2_TO_REDC_N_THRESHOLD))
+    {
+      mip = ip;
+      mpn_binvert (mip, mp, 2, tp);
+      mip[0] = -mip[0]; mip[1] = ~mip[1];
+    }
+#else
+  if (BELOW_THRESHOLD (n, REDC_1_TO_REDC_N_THRESHOLD))
+    {
+      mip = ip;
+      binvert_limb (mip[0], mp[0]);
+      mip[0] = -mip[0];
+    }
+#endif
+  else
+    {
+      mip = TMP_ALLOC_LIMBS (n);
+      mpn_binvert (mip, mp, n, tp);
+    }
+
+  pp = TMP_ALLOC_LIMBS (n << (windowsize - 1));
+
+  this_pp = pp;
+  redcify (this_pp, bp, bn, mp, n);
+
+  /* Store b^2 at rp.  */
+  mpn_sqr (tp, this_pp, n);
+#if 0
+  if (n == 1) {
+    MPN_REDC_0 (rp, tp, mp, mip[0]);
+  } else
+#endif
+#if WANT_REDC_2
+  if (BELOW_THRESHOLD (n, REDC_1_TO_REDC_2_THRESHOLD))
+    MPN_REDC_1 (rp, tp, mp, n, mip[0]);
+  else if (BELOW_THRESHOLD (n, REDC_2_TO_REDC_N_THRESHOLD))
+    MPN_REDC_2 (rp, tp, mp, n, mip);
+#else
+  if (BELOW_THRESHOLD (n, REDC_1_TO_REDC_N_THRESHOLD))
+    MPN_REDC_1 (rp, tp, mp, n, mip[0]);
+#endif
+  else
+    mpn_redc_n (rp, tp, mp, n, mip);
+
+  /* Precompute odd powers of b and put them in the temporary area at pp.  */
+  for (i = (1 << (windowsize - 1)) - 1; i > 0; i--)
+#if 1
+    if (n == 1) {
+      umul_ppmm((tp)[1], *(tp), *(this_pp), *(rp));
+      ++this_pp ;
+      MPN_REDC_0 (this_pp, tp, mp, mip[0]);
+    } else
+#endif
+    {
+      mpn_mul_n (tp, this_pp, rp, n);
+      this_pp += n;
+#if WANT_REDC_2
+      if (BELOW_THRESHOLD (n, REDC_1_TO_REDC_2_THRESHOLD))
+	MPN_REDC_1 (this_pp, tp, mp, n, mip[0]);
+      else if (BELOW_THRESHOLD (n, REDC_2_TO_REDC_N_THRESHOLD))
+	MPN_REDC_2 (this_pp, tp, mp, n, mip);
+#else
+      if (BELOW_THRESHOLD (n, REDC_1_TO_REDC_N_THRESHOLD))
+	MPN_REDC_1 (this_pp, tp, mp, n, mip[0]);
+#endif
+      else
+	mpn_redc_n (this_pp, tp, mp, n, mip);
+    }
+
+  expbits = getbits (ep, ebi, windowsize);
+  if (ebi < windowsize)
+    ebi = 0;
+  else
+    ebi -= windowsize;
+
+  count_trailing_zeros (cnt, expbits);
+  ebi += cnt;
+  expbits >>= cnt;
+
+  MPN_COPY (rp, pp + n * (expbits >> 1), n);
+
+#define INNERLOOP							\
+  while (ebi != 0)							\
+    {									\
+      while (getbit (ep, ebi) == 0)					\
+	{								\
+	  MPN_SQR (tp, rp, n);						\
+	  MPN_REDUCE (rp, tp, mp, n, mip);				\
+	  if (--ebi == 0)						\
+	    goto done;							\
+	}								\
+									\
+      /* The next bit of the exponent is 1.  Now extract the largest	\
+	 block of bits <= windowsize, and such that the least		\
+	 significant bit is 1.  */					\
+									\
+      expbits = getbits (ep, ebi, windowsize);				\
+      this_windowsize = windowsize;					\
+      if (ebi < windowsize)						\
+	{								\
+	  this_windowsize -= windowsize - ebi;				\
+	  ebi = 0;							\
+	}								\
+      else								\
+        ebi -= windowsize;						\
+									\
+      count_trailing_zeros (cnt, expbits);				\
+      this_windowsize -= cnt;						\
+      ebi += cnt;							\
+      expbits >>= cnt;							\
+									\
+      do								\
+	{								\
+	  MPN_SQR (tp, rp, n);						\
+	  MPN_REDUCE (rp, tp, mp, n, mip);				\
+	}								\
+      while (--this_windowsize != 0);					\
+									\
+      MPN_MUL_N (tp, rp, pp + n * (expbits >> 1), n);			\
+      MPN_REDUCE (rp, tp, mp, n, mip);					\
+    }
+
+
+  if (n == 1)
+    {
+#undef MPN_MUL_N
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_MUL_N(r,a,b,n)		umul_ppmm((r)[1], *(r), *(a), *(b))
+#define MPN_SQR(r,a,n)			umul_ppmm((r)[1], *(r), *(a), *(a))
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_0(rp, tp, mp, mip[0])
+      INNERLOOP;
+    }
+  else
+#if WANT_REDC_2
+  if (REDC_1_TO_REDC_2_THRESHOLD < MUL_TOOM22_THRESHOLD)
+    {
+      if (BELOW_THRESHOLD (n, REDC_1_TO_REDC_2_THRESHOLD))
+	{
+	  if (REDC_1_TO_REDC_2_THRESHOLD < SQR_BASECASE_THRESHOLD
+	      || BELOW_THRESHOLD (n, SQR_BASECASE_THRESHOLD))
+	    {
+#undef MPN_MUL_N
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_MUL_N(r,a,b,n)		mpn_mul_basecase (r,a,n,b,n)
+#define MPN_SQR(r,a,n)			mpn_mul_basecase (r,a,n,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_1 (rp, tp, mp, n, mip[0])
+	      INNERLOOP;
+	    }
+	  else
+	    {
+#undef MPN_MUL_N
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_MUL_N(r,a,b,n)		mpn_mul_basecase (r,a,n,b,n)
+#define MPN_SQR(r,a,n)			mpn_sqr_basecase (r,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_1 (rp, tp, mp, n, mip[0])
+	      INNERLOOP;
+	    }
+	}
+      else if (BELOW_THRESHOLD (n, MUL_TOOM22_THRESHOLD))
+	{
+	  if (MUL_TOOM22_THRESHOLD < SQR_BASECASE_THRESHOLD
+	      || BELOW_THRESHOLD (n, SQR_BASECASE_THRESHOLD))
+	    {
+#undef MPN_MUL_N
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_MUL_N(r,a,b,n)		mpn_mul_basecase (r,a,n,b,n)
+#define MPN_SQR(r,a,n)			mpn_mul_basecase (r,a,n,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_2 (rp, tp, mp, n, mip)
+	      INNERLOOP;
+	    }
+	  else
+	    {
+#undef MPN_MUL_N
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_MUL_N(r,a,b,n)		mpn_mul_basecase (r,a,n,b,n)
+#define MPN_SQR(r,a,n)			mpn_sqr_basecase (r,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_2 (rp, tp, mp, n, mip)
+	      INNERLOOP;
+	    }
+	}
+      else if (BELOW_THRESHOLD (n, REDC_2_TO_REDC_N_THRESHOLD))
+	{
+#undef MPN_MUL_N
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_MUL_N(r,a,b,n)		mpn_mul_n (r,a,b,n)
+#define MPN_SQR(r,a,n)			mpn_sqr (r,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_2 (rp, tp, mp, n, mip)
+	  INNERLOOP;
+	}
+      else
+	{
+#undef MPN_MUL_N
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_MUL_N(r,a,b,n)		mpn_mul_n (r,a,b,n)
+#define MPN_SQR(r,a,n)			mpn_sqr (r,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	mpn_redc_n (rp, tp, mp, n, mip)
+	  INNERLOOP;
+	}
+    }
+  else
+    {
+      if (BELOW_THRESHOLD (n, MUL_TOOM22_THRESHOLD))
+	{
+	  if (MUL_TOOM22_THRESHOLD < SQR_BASECASE_THRESHOLD
+	      || BELOW_THRESHOLD (n, SQR_BASECASE_THRESHOLD))
+	    {
+#undef MPN_MUL_N
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_MUL_N(r,a,b,n)		mpn_mul_basecase (r,a,n,b,n)
+#define MPN_SQR(r,a,n)			mpn_mul_basecase (r,a,n,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_1 (rp, tp, mp, n, mip[0])
+	      INNERLOOP;
+	    }
+	  else
+	    {
+#undef MPN_MUL_N
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_MUL_N(r,a,b,n)		mpn_mul_basecase (r,a,n,b,n)
+#define MPN_SQR(r,a,n)			mpn_sqr_basecase (r,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_1 (rp, tp, mp, n, mip[0])
+	      INNERLOOP;
+	    }
+	}
+      else if (BELOW_THRESHOLD (n, REDC_1_TO_REDC_2_THRESHOLD))
+	{
+#undef MPN_MUL_N
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_MUL_N(r,a,b,n)		mpn_mul_n (r,a,b,n)
+#define MPN_SQR(r,a,n)			mpn_sqr (r,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_1 (rp, tp, mp, n, mip[0])
+	  INNERLOOP;
+	}
+      else if (BELOW_THRESHOLD (n, REDC_2_TO_REDC_N_THRESHOLD))
+	{
+#undef MPN_MUL_N
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_MUL_N(r,a,b,n)		mpn_mul_n (r,a,b,n)
+#define MPN_SQR(r,a,n)			mpn_sqr (r,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_2 (rp, tp, mp, n, mip)
+	  INNERLOOP;
+	}
+      else
+	{
+#undef MPN_MUL_N
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_MUL_N(r,a,b,n)		mpn_mul_n (r,a,b,n)
+#define MPN_SQR(r,a,n)			mpn_sqr (r,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	mpn_redc_n (rp, tp, mp, n, mip)
+	  INNERLOOP;
+	}
+    }
+
+#else  /* WANT_REDC_2 */
+
+  if (REDC_1_TO_REDC_N_THRESHOLD < MUL_TOOM22_THRESHOLD)
+    {
+      if (BELOW_THRESHOLD (n, REDC_1_TO_REDC_N_THRESHOLD))
+	{
+	  if (REDC_1_TO_REDC_N_THRESHOLD < SQR_BASECASE_THRESHOLD
+	      || BELOW_THRESHOLD (n, SQR_BASECASE_THRESHOLD))
+	    {
+#undef MPN_MUL_N
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_MUL_N(r,a,b,n)		mpn_mul_basecase (r,a,n,b,n)
+#define MPN_SQR(r,a,n)			mpn_mul_basecase (r,a,n,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_1 (rp, tp, mp, n, mip[0])
+	      INNERLOOP;
+	    }
+	  else
+	    {
+#undef MPN_MUL_N
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_MUL_N(r,a,b,n)		mpn_mul_basecase (r,a,n,b,n)
+#define MPN_SQR(r,a,n)			mpn_sqr_basecase (r,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_1 (rp, tp, mp, n, mip[0])
+	      INNERLOOP;
+	    }
+	}
+      else if (BELOW_THRESHOLD (n, MUL_TOOM22_THRESHOLD))
+	{
+	  if (MUL_TOOM22_THRESHOLD < SQR_BASECASE_THRESHOLD
+	      || BELOW_THRESHOLD (n, SQR_BASECASE_THRESHOLD))
+	    {
+#undef MPN_MUL_N
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_MUL_N(r,a,b,n)		mpn_mul_basecase (r,a,n,b,n)
+#define MPN_SQR(r,a,n)			mpn_mul_basecase (r,a,n,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	mpn_redc_n (rp, tp, mp, n, mip)
+	      INNERLOOP;
+	    }
+	  else
+	    {
+#undef MPN_MUL_N
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_MUL_N(r,a,b,n)		mpn_mul_basecase (r,a,n,b,n)
+#define MPN_SQR(r,a,n)			mpn_sqr_basecase (r,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	mpn_redc_n (rp, tp, mp, n, mip)
+	      INNERLOOP;
+	    }
+	}
+      else
+	{
+#undef MPN_MUL_N
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_MUL_N(r,a,b,n)		mpn_mul_n (r,a,b,n)
+#define MPN_SQR(r,a,n)			mpn_sqr (r,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	mpn_redc_n (rp, tp, mp, n, mip)
+	  INNERLOOP;
+	}
+    }
+  else
+    {
+      if (BELOW_THRESHOLD (n, MUL_TOOM22_THRESHOLD))
+	{
+	  if (MUL_TOOM22_THRESHOLD < SQR_BASECASE_THRESHOLD
+	      || BELOW_THRESHOLD (n, SQR_BASECASE_THRESHOLD))
+	    {
+#undef MPN_MUL_N
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_MUL_N(r,a,b,n)		mpn_mul_basecase (r,a,n,b,n)
+#define MPN_SQR(r,a,n)			mpn_mul_basecase (r,a,n,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_1 (rp, tp, mp, n, mip[0])
+	      INNERLOOP;
+	    }
+	  else
+	    {
+#undef MPN_MUL_N
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_MUL_N(r,a,b,n)		mpn_mul_basecase (r,a,n,b,n)
+#define MPN_SQR(r,a,n)			mpn_sqr_basecase (r,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_1 (rp, tp, mp, n, mip[0])
+	      INNERLOOP;
+	    }
+	}
+      else if (BELOW_THRESHOLD (n, REDC_1_TO_REDC_N_THRESHOLD))
+	{
+#undef MPN_MUL_N
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_MUL_N(r,a,b,n)		mpn_mul_n (r,a,b,n)
+#define MPN_SQR(r,a,n)			mpn_sqr (r,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_1 (rp, tp, mp, n, mip[0])
+	  INNERLOOP;
+	}
+      else
+	{
+#undef MPN_MUL_N
+#undef MPN_SQR
+#undef MPN_REDUCE
+#define MPN_MUL_N(r,a,b,n)		mpn_mul_n (r,a,b,n)
+#define MPN_SQR(r,a,n)			mpn_sqr (r,a,n)
+#define MPN_REDUCE(rp,tp,mp,n,mip)	mpn_redc_n (rp, tp, mp, n, mip)
+	  INNERLOOP;
+	}
+    }
+#endif  /* WANT_REDC_2 */
+
+ done:
+
+  MPN_COPY (tp, rp, n);
+  MPN_ZERO (tp + n, n);
+
+#if WANT_REDC_2
+  if (BELOW_THRESHOLD (n, REDC_1_TO_REDC_2_THRESHOLD))
+    MPN_REDC_1 (rp, tp, mp, n, mip[0]);
+  else if (BELOW_THRESHOLD (n, REDC_2_TO_REDC_N_THRESHOLD))
+    MPN_REDC_2 (rp, tp, mp, n, mip);
+#else
+  if (BELOW_THRESHOLD (n, REDC_1_TO_REDC_N_THRESHOLD))
+    MPN_REDC_1 (rp, tp, mp, n, mip[0]);
+#endif
+  else
+    mpn_redc_n (rp, tp, mp, n, mip);
+
+  if (mpn_cmp (rp, mp, n) >= 0)
+    mpn_sub_n (rp, rp, mp, n);
+
+  TMP_FREE;
+}
diff --git a/third_party/gmp/mpn/generic/pre_divrem_1.c b/third_party/gmp/mpn/generic/pre_divrem_1.c
new file mode 100644
index 0000000..3b29d77
--- /dev/null
+++ b/third_party/gmp/mpn/generic/pre_divrem_1.c
@@ -0,0 +1,145 @@
+/* mpn_preinv_divrem_1 -- mpn by limb division with pre-inverted divisor.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2000-2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* Don't bloat a shared library with unused code. */
+#if USE_PREINV_DIVREM_1
+
+/* Same test here for skipping one divide step as in mpn_divrem_1.
+
+   The main reason for a separate shift==0 case is that not all CPUs give
+   zero for "n0 >> GMP_LIMB_BITS" which would arise in the general case
+   code used on shift==0.  shift==0 is also reasonably common in mp_bases
+   big_base, for instance base==10 on a 64-bit limb.
+
+   Under shift!=0 it would be possible to call mpn_lshift to adjust the
+   dividend all in one go (into the quotient space say), rather than
+   limb-by-limb in the loop.  This might help if mpn_lshift is a lot faster
+   than what the compiler can generate for EXTRACT.  But this is left to CPU
+   specific implementations to consider, especially since EXTRACT isn't on
+   the dependent chain.
+
+   If size==0 then the result is simply xsize limbs of zeros, but nothing
+   special is done for that, since it wouldn't be a usual call, and
+   certainly never arises from mpn_get_str which is our main caller.  */
+
+mp_limb_t
+mpn_preinv_divrem_1 (mp_ptr qp, mp_size_t xsize,
+		     mp_srcptr ap, mp_size_t size, mp_limb_t d_unnorm,
+		     mp_limb_t dinv, int shift)
+{
+  mp_limb_t  ahigh, qhigh, r;
+  mp_size_t  i;
+  mp_limb_t  n1, n0;
+  mp_limb_t  d;
+
+  ASSERT (xsize >= 0);
+  ASSERT (size >= 1);
+  ASSERT (d_unnorm != 0);
+#if WANT_ASSERT
+  {
+    int        want_shift;
+    mp_limb_t  want_dinv;
+    count_leading_zeros (want_shift, d_unnorm);
+    ASSERT (shift == want_shift);
+    invert_limb (want_dinv, d_unnorm << shift);
+    ASSERT (dinv == want_dinv);
+  }
+#endif
+  /* FIXME: What's the correct overlap rule when xsize!=0? */
+  ASSERT (MPN_SAME_OR_SEPARATE_P (qp+xsize, ap, size));
+
+  ahigh = ap[size-1];
+  d = d_unnorm << shift;
+  qp += (size + xsize - 1);   /* dest high limb */
+
+  if (shift == 0)
+    {
+      /* High quotient limb is 0 or 1, and skip a divide step. */
+      r = ahigh;
+      qhigh = (r >= d);
+      r = (qhigh ? r-d : r);
+      *qp-- = qhigh;
+      size--;
+
+      for (i = size-1; i >= 0; i--)
+	{
+	  n0 = ap[i];
+	  udiv_qrnnd_preinv (*qp, r, r, n0, d, dinv);
+	  qp--;
+	}
+    }
+  else
+    {
+      r = 0;
+      if (ahigh < d_unnorm)
+	{
+	  r = ahigh << shift;
+	  *qp-- = 0;
+	  size--;
+	  if (size == 0)
+	    goto done_integer;
+	}
+
+      n1 = ap[size-1];
+      r |= n1 >> (GMP_LIMB_BITS - shift);
+
+      for (i = size-2; i >= 0; i--)
+	{
+	  ASSERT (r < d);
+	  n0 = ap[i];
+	  udiv_qrnnd_preinv (*qp, r, r,
+			     ((n1 << shift) | (n0 >> (GMP_LIMB_BITS - shift))),
+			     d, dinv);
+	  qp--;
+	  n1 = n0;
+	}
+      udiv_qrnnd_preinv (*qp, r, r, n1 << shift, d, dinv);
+      qp--;
+    }
+
+ done_integer:
+  for (i = 0; i < xsize; i++)
+    {
+      udiv_qrnnd_preinv (*qp, r, r, CNST_LIMB(0), d, dinv);
+      qp--;
+    }
+
+  return r >> shift;
+}
+
+#endif /* USE_PREINV_DIVREM_1 */
diff --git a/third_party/gmp/mpn/generic/pre_mod_1.c b/third_party/gmp/mpn/generic/pre_mod_1.c
new file mode 100644
index 0000000..78ae308
--- /dev/null
+++ b/third_party/gmp/mpn/generic/pre_mod_1.c
@@ -0,0 +1,61 @@
+/* mpn_preinv_mod_1 (up, un, d, dinv) -- Divide (UP,,UN) by the normalized D.
+   DINV should be 2^(2*GMP_LIMB_BITS) / D - 2^GMP_LIMB_BITS.
+   Return the single-limb remainder.
+
+Copyright 1991, 1993, 1994, 2000-2002, 2004, 2005 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* This function used to be documented, but is now considered obsolete.  It
+   continues to exist for binary compatibility, even when not required
+   internally.  */
+
+mp_limb_t
+mpn_preinv_mod_1 (mp_srcptr up, mp_size_t un, mp_limb_t d, mp_limb_t dinv)
+{
+  mp_size_t i;
+  mp_limb_t n0, r;
+
+  ASSERT (un >= 1);
+  ASSERT (d & GMP_LIMB_HIGHBIT);
+
+  r = up[un - 1];
+  if (r >= d)
+    r -= d;
+
+  for (i = un - 2; i >= 0; i--)
+    {
+      n0 = up[i];
+      udiv_rnnd_preinv (r, r, n0, d, dinv);
+    }
+  return r;
+}
diff --git a/third_party/gmp/mpn/generic/random.c b/third_party/gmp/mpn/generic/random.c
new file mode 100644
index 0000000..485f9eb
--- /dev/null
+++ b/third_party/gmp/mpn/generic/random.c
@@ -0,0 +1,50 @@
+/* mpn_random -- Generate random numbers.
+
+Copyright 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpn_random (mp_ptr ptr, mp_size_t size)
+{
+  gmp_randstate_ptr  rands;
+
+  /* FIXME: Is size==0 supposed to be allowed? */
+  ASSERT (size >= 0);
+
+  if (size == 0)
+    return;
+
+  rands = RANDS;
+  _gmp_rand (ptr, rands, size * GMP_NUMB_BITS);
+
+  /* Make sure the most significant limb is non-zero.  */
+  while (ptr[size-1] == 0)
+    _gmp_rand (&ptr[size-1], rands, GMP_NUMB_BITS);
+}
diff --git a/third_party/gmp/mpn/generic/random2.c b/third_party/gmp/mpn/generic/random2.c
new file mode 100644
index 0000000..1eede67
--- /dev/null
+++ b/third_party/gmp/mpn/generic/random2.c
@@ -0,0 +1,105 @@
+/* mpn_random2 -- Generate random numbers with relatively long strings
+   of ones and zeroes.  Suitable for border testing.
+
+Copyright 1992-1994, 1996, 2000-2002, 2004, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+static void gmp_rrandomb (mp_ptr, gmp_randstate_t, mp_bitcnt_t);
+
+/* Ask _gmp_rand for 32 bits per call unless that's more than a limb can hold.
+   Thus, we get the same random number sequence in the common cases.
+   FIXME: We should always generate the same random number sequence!  */
+#if GMP_NUMB_BITS < 32
+#define BITS_PER_RANDCALL GMP_NUMB_BITS
+#else
+#define BITS_PER_RANDCALL 32
+#endif
+
+void
+mpn_random2 (mp_ptr rp, mp_size_t n)
+{
+  gmp_randstate_ptr rstate = RANDS;
+  int bit_pos;			/* bit number of least significant bit where
+				   next bit field to be inserted */
+  mp_limb_t ran, ranm;		/* buffer for random bits */
+
+  /* FIXME: Is n==0 supposed to be allowed? */
+  ASSERT (n >= 0);
+
+  _gmp_rand (&ranm, rstate, BITS_PER_RANDCALL);
+  ran = ranm;
+
+  /* Start off at a random bit position in the most significant limb.  */
+  bit_pos = ran % GMP_NUMB_BITS;
+
+  gmp_rrandomb (rp, rstate, n * GMP_NUMB_BITS - bit_pos);
+}
+
+static void
+gmp_rrandomb (mp_ptr rp, gmp_randstate_t rstate, mp_bitcnt_t nbits)
+{
+  mp_bitcnt_t bi;
+  mp_limb_t ranm;		/* buffer for random bits */
+  unsigned cap_chunksize, chunksize;
+  mp_size_t i;
+
+  /* Set entire result to 111..1  */
+  i = BITS_TO_LIMBS (nbits) - 1;
+  rp[i] = GMP_NUMB_MAX >> (GMP_NUMB_BITS - (nbits % GMP_NUMB_BITS)) % GMP_NUMB_BITS;
+  for (i = i - 1; i >= 0; i--)
+    rp[i] = GMP_NUMB_MAX;
+
+  _gmp_rand (&ranm, rstate, BITS_PER_RANDCALL);
+  cap_chunksize = nbits / (ranm % 4 + 1);
+  cap_chunksize += cap_chunksize == 0; /* make it at least 1 */
+
+  bi = nbits;
+
+  for (;;)
+    {
+      _gmp_rand (&ranm, rstate, BITS_PER_RANDCALL);
+      chunksize = 1 + ranm % cap_chunksize;
+      bi = (bi < chunksize) ? 0 : bi - chunksize;
+
+      if (bi == 0)
+	break;			/* low chunk is ...1 */
+
+      rp[bi / GMP_NUMB_BITS] ^= CNST_LIMB (1) << bi % GMP_NUMB_BITS;
+
+      _gmp_rand (&ranm, rstate, BITS_PER_RANDCALL);
+      chunksize = 1 + ranm % cap_chunksize;
+      bi = (bi < chunksize) ? 0 : bi - chunksize;
+
+      mpn_incr_u (rp + bi / GMP_NUMB_BITS, CNST_LIMB (1) << bi % GMP_NUMB_BITS);
+
+      if (bi == 0)
+	break;			/* low chunk is ...0 */
+    }
+}
diff --git a/third_party/gmp/mpn/generic/redc_1.c b/third_party/gmp/mpn/generic/redc_1.c
new file mode 100644
index 0000000..eab128f
--- /dev/null
+++ b/third_party/gmp/mpn/generic/redc_1.c
@@ -0,0 +1,56 @@
+/* mpn_redc_1.  Set rp[] <- up[]/R^n mod mp[].  Clobber up[].
+   mp[] is n limbs; up[] is 2n limbs.
+
+   THIS IS AN INTERNAL FUNCTION WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH THIS FUNCTION THROUGH DOCUMENTED INTERFACES.
+
+Copyright (C) 2000-2002, 2004, 2008, 2009, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+mp_limb_t
+mpn_redc_1 (mp_ptr rp, mp_ptr up, mp_srcptr mp, mp_size_t n, mp_limb_t invm)
+{
+  mp_size_t j;
+  mp_limb_t cy;
+
+  ASSERT (n > 0);
+  ASSERT_MPN (up, 2*n);
+
+  for (j = n - 1; j >= 0; j--)
+    {
+      cy = mpn_addmul_1 (up, mp, n, (up[0] * invm) & GMP_NUMB_MASK);
+      ASSERT (up[0] == 0);
+      up[0] = cy;
+      up++;
+    }
+
+  cy = mpn_add_n (rp, up, up - n, n);
+  return cy;
+}
diff --git a/third_party/gmp/mpn/generic/redc_2.c b/third_party/gmp/mpn/generic/redc_2.c
new file mode 100644
index 0000000..8d15589
--- /dev/null
+++ b/third_party/gmp/mpn/generic/redc_2.c
@@ -0,0 +1,110 @@
+/* mpn_redc_2.  Set rp[] <- up[]/R^n mod mp[].  Clobber up[].
+   mp[] is n limbs; up[] is 2n limbs.
+
+   THIS IS AN INTERNAL FUNCTION WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH THIS FUNCTION THROUGH DOCUMENTED INTERFACES.
+
+Copyright (C) 2000-2002, 2004, 2008, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+#if GMP_NAIL_BITS != 0
+you lose
+#endif
+
+/* For testing purposes, define our own mpn_addmul_2 if there is none already
+   available.  */
+#ifndef HAVE_NATIVE_mpn_addmul_2
+#undef mpn_addmul_2
+static mp_limb_t
+mpn_addmul_2 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_srcptr vp)
+{
+  rp[n] = mpn_addmul_1 (rp, up, n, vp[0]);
+  return mpn_addmul_1 (rp + 1, up, n, vp[1]);
+}
+#endif
+
+#if defined (__GNUC__) && ! defined (NO_ASM) \
+  && defined (__ia64) && W_TYPE_SIZE == 64
+#define umul2low(ph, pl, uh, ul, vh, vl) \
+  do {									\
+    mp_limb_t _ph, _pl;							\
+    __asm__ ("xma.hu %0 = %3, %5, f0\n\t"				\
+	     "xma.l %1 = %3, %5, f0\n\t"				\
+	     ";;\n\t"							\
+	     "xma.l %0 = %3, %4, %0\n\t"				\
+	     ";;\n\t"							\
+	     "xma.l %0 = %2, %5, %0"					\
+	     : "=&f" (ph), "=&f" (pl)					\
+	     : "f" (uh), "f" (ul), "f" (vh), "f" (vl));			\
+  } while (0)
+#endif
+
+#ifndef umul2low
+#define umul2low(ph, pl, uh, ul, vh, vl) \
+  do {									\
+    mp_limb_t _ph, _pl;							\
+    umul_ppmm (_ph, _pl, ul, vl);					\
+    (ph) = _ph + (ul) * (vh) + (uh) * (vl);				\
+    (pl) = _pl;								\
+  } while (0)
+#endif
+
+mp_limb_t
+mpn_redc_2 (mp_ptr rp, mp_ptr up, mp_srcptr mp, mp_size_t n, mp_srcptr mip)
+{
+  mp_limb_t q[2];
+  mp_size_t j;
+  mp_limb_t upn;
+  mp_limb_t cy;
+
+  ASSERT (n > 0);
+  ASSERT_MPN (up, 2*n);
+
+  if ((n & 1) != 0)
+    {
+      up[0] = mpn_addmul_1 (up, mp, n, (up[0] * mip[0]) & GMP_NUMB_MASK);
+      up++;
+    }
+
+  for (j = n - 2; j >= 0; j -= 2)
+    {
+      umul2low (q[1], q[0], mip[1], mip[0], up[1], up[0]);
+      upn = up[n];		/* mpn_addmul_2 overwrites this */
+      up[1] = mpn_addmul_2 (up, mp, n, q);
+      up[0] = up[n];
+      up[n] = upn;
+      up += 2;
+    }
+
+  cy = mpn_add_n (rp, up, up - n, n);
+  return cy;
+}
diff --git a/third_party/gmp/mpn/generic/redc_n.c b/third_party/gmp/mpn/generic/redc_n.c
new file mode 100644
index 0000000..0c94b7c
--- /dev/null
+++ b/third_party/gmp/mpn/generic/redc_n.c
@@ -0,0 +1,80 @@
+/* mpn_redc_n.  Set rp[] <- up[]/R^n mod mp[].  Clobber up[].
+   mp[] is n limbs; up[] is 2n limbs, the inverse ip[] is n limbs.
+
+   THIS IS AN INTERNAL FUNCTION WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH THIS FUNCTION THROUGH DOCUMENTED INTERFACES.
+
+Copyright 2009, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/*
+  TODO
+
+  * We assume mpn_mulmod_bnm1 is always faster than plain mpn_mul_n (or a
+    future mpn_mulhi) for the range we will be called.  Follow up that
+    assumption.
+
+  * Decrease scratch usage.
+
+  * Consider removing the residue canonicalisation.
+*/
+
+void
+mpn_redc_n (mp_ptr rp, mp_ptr up, mp_srcptr mp, mp_size_t n, mp_srcptr ip)
+{
+  mp_ptr xp, yp, scratch;
+  mp_limb_t cy;
+  mp_size_t rn;
+  TMP_DECL;
+  TMP_MARK;
+
+  ASSERT (n > 8);
+
+  rn = mpn_mulmod_bnm1_next_size (n);
+
+  scratch = TMP_ALLOC_LIMBS (n + rn + mpn_mulmod_bnm1_itch (rn, n, n));
+
+  xp = scratch;
+  mpn_mullo_n (xp, up, ip, n);
+
+  yp = scratch + n;
+  mpn_mulmod_bnm1 (yp, rn, xp, n, mp, n, scratch + n + rn);
+
+  ASSERT_ALWAYS (2 * n > rn);				/* could handle this */
+
+  cy = mpn_sub_n (yp + rn, yp, up, 2*n - rn);		/* undo wrap around */
+  MPN_DECR_U (yp + 2*n - rn, rn, cy);
+
+  cy = mpn_sub_n (rp, up + n, yp + n, n);
+  if (cy != 0)
+    mpn_add_n (rp, rp, mp, n);
+
+  TMP_FREE;
+}
diff --git a/third_party/gmp/mpn/generic/remove.c b/third_party/gmp/mpn/generic/remove.c
new file mode 100644
index 0000000..cbb0742
--- /dev/null
+++ b/third_party/gmp/mpn/generic/remove.c
@@ -0,0 +1,182 @@
+/* mpn_remove -- divide out all multiples of odd mpn number from another mpn
+   number.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright 2009, 2012-2014, 2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#if GMP_LIMB_BITS > 50
+#define LOG 50
+#else
+#define LOG GMP_LIMB_BITS
+#endif
+
+
+/* Input: U = {up,un}, V = {vp,vn} must be odd, cap
+   Ouput  W = {wp,*wn} allocation need is exactly *wn
+
+   Set W = U / V^k, where k is the largest integer <= cap such that the
+   division yields an integer.
+
+   FIXME: We currently allow any operand overlap.  This is quite non mpn-ish
+   and might be changed, since it cost significant temporary space.
+   * If we require W to have space for un + 1 limbs, we could save qp or qp2
+     (but we will still need to copy things into wp 50% of the time).
+   * If we allow ourselves to clobber U, we could save the other of qp and qp2,
+     and the initial COPY (but also here we would need un + 1 limbs).
+*/
+
+/* FIXME: We need to wrap mpn_bdiv_qr due to the itch interface.  This need
+   indicates a flaw in the current itch mechanism: Which operands not greater
+   than un,un will incur the worst itch?  We need a parallel foo_maxitch set
+   of functions.  */
+static void
+mpn_bdiv_qr_wrap (mp_ptr qp, mp_ptr rp,
+		  mp_srcptr np, mp_size_t nn,
+		  mp_srcptr dp, mp_size_t dn)
+{
+  mp_ptr scratch_out;
+  TMP_DECL;
+
+  TMP_MARK;
+  scratch_out = TMP_ALLOC_LIMBS (mpn_bdiv_qr_itch (nn, dn));
+  mpn_bdiv_qr (qp, rp, np, nn, dp, dn, scratch_out);
+
+  TMP_FREE;
+}
+
+mp_bitcnt_t
+mpn_remove (mp_ptr wp, mp_size_t *wn,
+	    mp_srcptr up, mp_size_t un, mp_srcptr vp, mp_size_t vn,
+	    mp_bitcnt_t cap)
+{
+  mp_srcptr pwpsp[LOG];
+  mp_size_t pwpsn[LOG];
+  mp_size_t npowers;
+  mp_ptr tp, qp, np, qp2;
+  mp_srcptr pp;
+  mp_size_t pn, nn, qn, i;
+  mp_bitcnt_t pwr;
+  TMP_DECL;
+
+  ASSERT (un > 0);
+  ASSERT (vn > 0);
+  ASSERT (vp[0] % 2 != 0);	/* 2-adic division wants odd numbers */
+  ASSERT (vn > 1 || vp[0] > 1);	/* else we would loop indefinitely */
+
+  TMP_MARK;
+
+  TMP_ALLOC_LIMBS_3 (qp, un + 1,	/* quotient, alternating */
+		     qp2, un + 1,	/* quotient, alternating */
+		     tp, (un + 1 + vn) / 2); /* remainder */
+  pp = vp;
+  pn = vn;
+
+  MPN_COPY (qp, up, un);
+  qn = un;
+
+  npowers = 0;
+  while (qn >= pn)
+    {
+      qp[qn] = 0;
+      mpn_bdiv_qr_wrap (qp2, tp, qp, qn + 1, pp, pn);
+      if (!mpn_zero_p (tp, pn))
+	{
+	  if (mpn_cmp (tp, pp, pn) != 0)
+	    break;		/* could not divide by V^npowers */
+	}
+
+      MP_PTR_SWAP (qp, qp2);
+      qn = qn - pn;
+      mpn_neg (qp, qp, qn+1);
+
+      qn += qp[qn] != 0;
+
+      pwpsp[npowers] = pp;
+      pwpsn[npowers] = pn;
+      ++npowers;
+
+      if (((mp_bitcnt_t) 2 << npowers) - 1 > cap)
+	break;
+
+      nn = 2 * pn - 1;		/* next power will be at least this large */
+      if (nn > qn)
+	break;			/* next power would be overlarge */
+
+      if (npowers == 1)		/* Alloc once, but only if it's needed */
+	np = TMP_ALLOC_LIMBS (qn + LOG);	/* powers of V */
+      else
+	np += pn;
+
+      mpn_sqr (np, pp, pn);
+      pn = nn + (np[nn] != 0);
+      pp = np;
+    }
+
+  pwr = ((mp_bitcnt_t) 1 << npowers) - 1;
+
+  for (i = npowers; --i >= 0;)
+    {
+      pn = pwpsn[i];
+      if (qn < pn)
+	continue;
+
+      if (pwr + ((mp_bitcnt_t) 1 << i) > cap)
+	continue;		/* V^i would bring us past cap */
+
+      qp[qn] = 0;
+      mpn_bdiv_qr_wrap (qp2, tp, qp, qn + 1, pwpsp[i], pn);
+      if (!mpn_zero_p (tp, pn))
+	{
+	  if (mpn_cmp (tp, pwpsp[i], pn) != 0)
+	    continue;		/* could not divide by V^i */
+	}
+
+      MP_PTR_SWAP (qp, qp2);
+      qn = qn - pn;
+      mpn_neg (qp, qp, qn+1);
+
+      qn += qp[qn] != 0;
+
+      pwr += (mp_bitcnt_t) 1 << i;
+    }
+
+  MPN_COPY (wp, qp, qn);
+  *wn = qn;
+
+  TMP_FREE;
+
+  return pwr;
+}
diff --git a/third_party/gmp/mpn/generic/rootrem.c b/third_party/gmp/mpn/generic/rootrem.c
new file mode 100644
index 0000000..a79099e
--- /dev/null
+++ b/third_party/gmp/mpn/generic/rootrem.c
@@ -0,0 +1,515 @@
+/* mpn_rootrem(rootp,remp,ap,an,nth) -- Compute the nth root of {ap,an}, and
+   store the truncated integer part at rootp and the remainder at remp.
+
+   Contributed by Paul Zimmermann (algorithm) and
+   Paul Zimmermann and Torbjorn Granlund (implementation).
+   Marco Bodrato wrote logbased_root to seed the loop.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL, AND HAVE MUTABLE INTERFACES.  IT'S
+   ONLY SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT'S ALMOST
+   GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2002, 2005, 2009-2012, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+/* FIXME:
+     This implementation is not optimal when remp == NULL, since the complexity
+     is M(n), whereas it should be M(n/k) on average.
+*/
+
+#include <stdio.h>		/* for NULL */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+static mp_size_t mpn_rootrem_internal (mp_ptr, mp_ptr, mp_srcptr, mp_size_t,
+				       mp_limb_t, int);
+
+#define MPN_RSHIFT(rp,up,un,cnt) \
+  do {									\
+    if ((cnt) != 0)							\
+      mpn_rshift (rp, up, un, cnt);					\
+    else								\
+      {									\
+	MPN_COPY_INCR (rp, up, un);					\
+      }									\
+  } while (0)
+
+#define MPN_LSHIFT(cy,rp,up,un,cnt) \
+  do {									\
+    if ((cnt) != 0)							\
+      cy = mpn_lshift (rp, up, un, cnt);				\
+    else								\
+      {									\
+	MPN_COPY_DECR (rp, up, un);					\
+	cy = 0;								\
+      }									\
+  } while (0)
+
+
+/* Put in {rootp, ceil(un/k)} the kth root of {up, un}, rounded toward zero.
+   If remp <> NULL, put in {remp, un} the remainder.
+   Return the size (in limbs) of the remainder if remp <> NULL,
+	  or a non-zero value iff the remainder is non-zero when remp = NULL.
+   Assumes:
+   (a) up[un-1] is not zero
+   (b) rootp has at least space for ceil(un/k) limbs
+   (c) remp has at least space for un limbs (in case remp <> NULL)
+   (d) the operands do not overlap.
+
+   The auxiliary memory usage is 3*un+2 if remp = NULL,
+   and 2*un+2 if remp <> NULL.  FIXME: This is an incorrect comment.
+*/
+mp_size_t
+mpn_rootrem (mp_ptr rootp, mp_ptr remp,
+	     mp_srcptr up, mp_size_t un, mp_limb_t k)
+{
+  ASSERT (un > 0);
+  ASSERT (up[un - 1] != 0);
+  ASSERT (k > 1);
+
+  if (UNLIKELY (k == 2))
+    return mpn_sqrtrem (rootp, remp, up, un);
+  /* (un-1)/k > 2 <=> un > 3k <=> (un + 2)/3 > k */
+  if (remp == NULL && (un + 2) / 3 > k)
+    /* Pad {up,un} with k zero limbs.  This will produce an approximate root
+       with one more limb, allowing us to compute the exact integral result. */
+    {
+      mp_ptr sp, wp;
+      mp_size_t rn, sn, wn;
+      TMP_DECL;
+      TMP_MARK;
+      wn = un + k;
+      sn = (un - 1) / k + 2; /* ceil(un/k) + 1 */
+      TMP_ALLOC_LIMBS_2 (wp, wn, /* will contain the padded input */
+			 sp, sn); /* approximate root of padded input */
+      MPN_COPY (wp + k, up, un);
+      MPN_FILL (wp, k, 0);
+      rn = mpn_rootrem_internal (sp, NULL, wp, wn, k, 1);
+      /* The approximate root S = {sp,sn} is either the correct root of
+	 {sp,sn}, or 1 too large.  Thus unless the least significant limb of
+	 S is 0 or 1, we can deduce the root of {up,un} is S truncated by one
+	 limb.  (In case sp[0]=1, we can deduce the root, but not decide
+	 whether it is exact or not.) */
+      MPN_COPY (rootp, sp + 1, sn - 1);
+      TMP_FREE;
+      return rn;
+    }
+  else
+    {
+      return mpn_rootrem_internal (rootp, remp, up, un, k, 0);
+    }
+}
+
+#define LOGROOT_USED_BITS 8
+#define LOGROOT_NEEDS_TWO_CORRECTIONS 1
+#define LOGROOT_RETURNED_BITS (LOGROOT_USED_BITS + LOGROOT_NEEDS_TWO_CORRECTIONS)
+/* Puts in *rootp some bits of the k^nt root of the number
+   2^bitn * 1.op ; where op represents the "fractional" bits.
+
+   The returned value is the number of bits of the root minus one;
+   i.e. an approximation of the root will be
+   (*rootp) * 2^(retval-LOGROOT_RETURNED_BITS+1).
+
+   Currently, only LOGROOT_USED_BITS bits of op are used (the implicit
+   one is not counted).
+ */
+static unsigned
+logbased_root (mp_ptr rootp, mp_limb_t op, mp_bitcnt_t bitn, mp_limb_t k)
+{
+  /* vlog=vector(256,i,floor((log(256+i)/log(2)-8)*256)-(i>255)) */
+  static const
+  unsigned char vlog[] = {1,   2,   4,   5,   7,   8,   9,  11,  12,  14,  15,  16,  18,  19,  21,  22,
+			 23,  25,  26,  27,  29,  30,  31,  33,  34,  35,  37,  38,  39,  40,  42,  43,
+			 44,  46,  47,  48,  49,  51,  52,  53,  54,  56,  57,  58,  59,  61,  62,  63,
+			 64,  65,  67,  68,  69,  70,  71,  73,  74,  75,  76,  77,  78,  80,  81,  82,
+			 83,  84,  85,  87,  88,  89,  90,  91,  92,  93,  94,  96,  97,  98,  99, 100,
+			101, 102, 103, 104, 105, 106, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117,
+			118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 131, 132, 133, 134,
+			135, 136, 137, 138, 139, 140, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
+			150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 162, 163, 164,
+			165, 166, 167, 168, 169, 170, 171, 172, 173, 173, 174, 175, 176, 177, 178, 179,
+			180, 181, 181, 182, 183, 184, 185, 186, 187, 188, 188, 189, 190, 191, 192, 193,
+			194, 194, 195, 196, 197, 198, 199, 200, 200, 201, 202, 203, 204, 205, 205, 206,
+			207, 208, 209, 209, 210, 211, 212, 213, 214, 214, 215, 216, 217, 218, 218, 219,
+			220, 221, 222, 222, 223, 224, 225, 225, 226, 227, 228, 229, 229, 230, 231, 232,
+			232, 233, 234, 235, 235, 236, 237, 238, 239, 239, 240, 241, 242, 242, 243, 244,
+			245, 245, 246, 247, 247, 248, 249, 250, 250, 251, 252, 253, 253, 254, 255, 255};
+
+  /* vexp=vector(256,i,floor(2^(8+i/256)-256)-(i>255)) */
+  static const
+  unsigned char vexp[] = {0,   1,   2,   2,   3,   4,   4,   5,   6,   7,   7,   8,   9,   9,  10,  11,
+			 12,  12,  13,  14,  14,  15,  16,  17,  17,  18,  19,  20,  20,  21,  22,  23,
+			 23,  24,  25,  26,  26,  27,  28,  29,  30,  30,  31,  32,  33,  33,  34,  35,
+			 36,  37,  37,  38,  39,  40,  41,  41,  42,  43,  44,  45,  45,  46,  47,  48,
+			 49,  50,  50,  51,  52,  53,  54,  55,  55,  56,  57,  58,  59,  60,  61,  61,
+			 62,  63,  64,  65,  66,  67,  67,  68,  69,  70,  71,  72,  73,  74,  75,  75,
+			 76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  86,  87,  88,  89,  90,
+			 91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103, 104, 105, 106,
+			107, 108, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 119, 120, 121, 122,
+			123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138,
+			139, 140, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 154, 155, 156,
+			157, 158, 159, 160, 161, 163, 164, 165, 166, 167, 168, 169, 171, 172, 173, 174,
+			175, 176, 178, 179, 180, 181, 182, 183, 185, 186, 187, 188, 189, 191, 192, 193,
+			194, 196, 197, 198, 199, 200, 202, 203, 204, 205, 207, 208, 209, 210, 212, 213,
+			214, 216, 217, 218, 219, 221, 222, 223, 225, 226, 227, 229, 230, 231, 232, 234,
+			235, 236, 238, 239, 240, 242, 243, 245, 246, 247, 249, 250, 251, 253, 254, 255};
+  mp_bitcnt_t retval;
+
+  if (UNLIKELY (bitn > (~ (mp_bitcnt_t) 0) >> LOGROOT_USED_BITS))
+    {
+      /* In the unlikely case, we use two divisions and a modulo. */
+      retval = bitn / k;
+      bitn %= k;
+      bitn = (bitn << LOGROOT_USED_BITS |
+	      vlog[op >> (GMP_NUMB_BITS - LOGROOT_USED_BITS)]) / k;
+    }
+  else
+    {
+      bitn = (bitn << LOGROOT_USED_BITS |
+	      vlog[op >> (GMP_NUMB_BITS - LOGROOT_USED_BITS)]) / k;
+      retval = bitn >> LOGROOT_USED_BITS;
+      bitn &= (CNST_LIMB (1) << LOGROOT_USED_BITS) - 1;
+    }
+  ASSERT(bitn < CNST_LIMB (1) << LOGROOT_USED_BITS);
+  *rootp = CNST_LIMB(1) << (LOGROOT_USED_BITS - ! LOGROOT_NEEDS_TWO_CORRECTIONS)
+    | vexp[bitn] >> ! LOGROOT_NEEDS_TWO_CORRECTIONS;
+  return retval;
+}
+
+/* if approx is non-zero, does not compute the final remainder */
+static mp_size_t
+mpn_rootrem_internal (mp_ptr rootp, mp_ptr remp, mp_srcptr up, mp_size_t un,
+		      mp_limb_t k, int approx)
+{
+  mp_ptr qp, rp, sp, wp, scratch;
+  mp_size_t qn, rn, sn, wn, nl, bn;
+  mp_limb_t save, save2, cy, uh;
+  mp_bitcnt_t unb; /* number of significant bits of {up,un} */
+  mp_bitcnt_t xnb; /* number of significant bits of the result */
+  mp_bitcnt_t b, kk;
+  mp_bitcnt_t sizes[GMP_NUMB_BITS + 1];
+  int ni;
+  int perf_pow;
+  unsigned ulz, snb, c, logk;
+  TMP_DECL;
+
+  /* MPN_SIZEINBASE_2EXP(unb, up, un, 1); --unb; */
+  uh = up[un - 1];
+  count_leading_zeros (ulz, uh);
+  ulz = ulz - GMP_NAIL_BITS + 1; /* Ignore the first 1. */
+  unb = (mp_bitcnt_t) un * GMP_NUMB_BITS - ulz;
+  /* unb is the (truncated) logarithm of the input U in base 2*/
+
+  if (unb < k) /* root is 1 */
+    {
+      rootp[0] = 1;
+      if (remp == NULL)
+	un -= (*up == CNST_LIMB (1)); /* Non-zero iif {up,un} > 1 */
+      else
+	{
+	  mpn_sub_1 (remp, up, un, CNST_LIMB (1));
+	  un -= (remp [un - 1] == 0);	/* There should be at most one zero limb,
+				   if we demand u to be normalized  */
+	}
+      return un;
+    }
+  /* if (unb - k < k/2 + k/16) // root is 2 */
+
+  if (ulz == GMP_NUMB_BITS)
+    uh = up[un - 2];
+  else
+    uh = (uh << ulz & GMP_NUMB_MASK) | up[un - 1 - (un != 1)] >> (GMP_NUMB_BITS - ulz);
+  ASSERT (un != 1 || up[un - 1 - (un != 1)] >> (GMP_NUMB_BITS - ulz) == 1);
+
+  xnb = logbased_root (rootp, uh, unb, k);
+  snb = LOGROOT_RETURNED_BITS - 1;
+  /* xnb+1 is the number of bits of the root R */
+  /* snb+1 is the number of bits of the current approximation S */
+
+  kk = k * xnb;		/* number of truncated bits in the input */
+
+  /* FIXME: Should we skip the next two loops when xnb <= snb ? */
+  for (uh = (k - 1) / 2, logk = 3; (uh >>= 1) != 0; ++logk )
+    ;
+  /* logk = ceil(log(k)/log(2)) + 1 */
+
+  /* xnb is the number of remaining bits to determine in the kth root */
+  for (ni = 0; (sizes[ni] = xnb) > snb; ++ni)
+    {
+      /* invariant: here we want xnb+1 total bits for the kth root */
+
+      /* if c is the new value of xnb, this means that we'll go from a
+	 root of c+1 bits (say s') to a root of xnb+1 bits.
+	 It is proved in the book "Modern Computer Arithmetic" by Brent
+	 and Zimmermann, Chapter 1, that
+	 if s' >= k*beta, then at most one correction is necessary.
+	 Here beta = 2^(xnb-c), and s' >= 2^c, thus it suffices that
+	 c >= ceil((xnb + log2(k))/2). */
+      if (xnb > logk)
+	xnb = (xnb + logk) / 2;
+      else
+	--xnb;	/* add just one bit at a time */
+    }
+
+  *rootp >>= snb - xnb;
+  kk -= xnb;
+
+  ASSERT_ALWAYS (ni < GMP_NUMB_BITS + 1);
+  /* We have sizes[0] = b > sizes[1] > ... > sizes[ni] = 0 with
+     sizes[i] <= 2 * sizes[i+1].
+     Newton iteration will first compute sizes[ni-1] extra bits,
+     then sizes[ni-2], ..., then sizes[0] = b. */
+
+  TMP_MARK;
+  /* qp and wp need enough space to store S'^k where S' is an approximate
+     root. Since S' can be as large as S+2, the worst case is when S=2 and
+     S'=4. But then since we know the number of bits of S in advance, S'
+     can only be 3 at most. Similarly for S=4, then S' can be 6 at most.
+     So the worst case is S'/S=3/2, thus S'^k <= (3/2)^k * S^k. Since S^k
+     fits in un limbs, the number of extra limbs needed is bounded by
+     ceil(k*log2(3/2)/GMP_NUMB_BITS). */
+  /* THINK: with the use of logbased_root, maybe the constant is
+     258/256 instead of 3/2 ? log2(258/256) < 1/89 < 1/64 */
+#define EXTRA 2 + (mp_size_t) (0.585 * (double) k / (double) GMP_NUMB_BITS)
+  TMP_ALLOC_LIMBS_3 (scratch, un + 1, /* used by mpn_div_q */
+		     qp, un + EXTRA,  /* will contain quotient and remainder
+					 of R/(k*S^(k-1)), and S^k */
+		     wp, un + EXTRA); /* will contain S^(k-1), k*S^(k-1),
+					 and temporary for mpn_pow_1 */
+
+  if (remp == NULL)
+    rp = scratch;	/* will contain the remainder */
+  else
+    rp = remp;
+  sp = rootp;
+
+  sn = 1;		/* Initial approximation has one limb */
+
+  for (b = xnb; ni != 0; --ni)
+    {
+      /* 1: loop invariant:
+	 {sp, sn} is the current approximation of the root, which has
+		  exactly 1 + sizes[ni] bits.
+	 {rp, rn} is the current remainder
+	 {wp, wn} = {sp, sn}^(k-1)
+	 kk = number of truncated bits of the input
+      */
+
+      /* Since each iteration treats b bits from the root and thus k*b bits
+	 from the input, and we already considered b bits from the input,
+	 we now have to take another (k-1)*b bits from the input. */
+      kk -= (k - 1) * b; /* remaining input bits */
+      /* {rp, rn} = floor({up, un} / 2^kk) */
+      rn = un - kk / GMP_NUMB_BITS;
+      MPN_RSHIFT (rp, up + kk / GMP_NUMB_BITS, rn, kk % GMP_NUMB_BITS);
+      rn -= rp[rn - 1] == 0;
+
+      /* 9: current buffers: {sp,sn}, {rp,rn} */
+
+      for (c = 0;; c++)
+	{
+	  /* Compute S^k in {qp,qn}. */
+	  /* W <- S^(k-1) for the next iteration,
+	     and S^k = W * S. */
+	  wn = mpn_pow_1 (wp, sp, sn, k - 1, qp);
+	  mpn_mul (qp, wp, wn, sp, sn);
+	  qn = wn + sn;
+	  qn -= qp[qn - 1] == 0;
+
+	  perf_pow = 1;
+	  /* if S^k > floor(U/2^kk), the root approximation was too large */
+	  if (qn > rn || (qn == rn && (perf_pow=mpn_cmp (qp, rp, rn)) > 0))
+	    MPN_DECR_U (sp, sn, 1);
+	  else
+	    break;
+	}
+
+      /* 10: current buffers: {sp,sn}, {rp,rn}, {qp,qn}, {wp,wn} */
+
+      /* sometimes two corrections are needed with logbased_root*/
+      ASSERT (c <= 1 + LOGROOT_NEEDS_TWO_CORRECTIONS);
+      ASSERT_ALWAYS (rn >= qn);
+
+      b = sizes[ni - 1] - sizes[ni]; /* number of bits to compute in the
+				      next iteration */
+      bn = b / GMP_NUMB_BITS; /* lowest limb from high part of rp[], after shift */
+
+      kk = kk - b;
+      /* nl is the number of limbs in U which contain bits [kk,kk+b-1] */
+      nl = 1 + (kk + b - 1) / GMP_NUMB_BITS - (kk / GMP_NUMB_BITS);
+      /* nl  = 1 + floor((kk + b - 1) / GMP_NUMB_BITS)
+		 - floor(kk / GMP_NUMB_BITS)
+	     <= 1 + (kk + b - 1) / GMP_NUMB_BITS
+		  - (kk - GMP_NUMB_BITS + 1) / GMP_NUMB_BITS
+	     = 2 + (b - 2) / GMP_NUMB_BITS
+	 thus since nl is an integer:
+	 nl <= 2 + floor(b/GMP_NUMB_BITS) <= 2 + bn. */
+
+      /* 11: current buffers: {sp,sn}, {rp,rn}, {wp,wn} */
+
+      /* R = R - Q = floor(U/2^kk) - S^k */
+      if (perf_pow != 0)
+	{
+	  mpn_sub (rp, rp, rn, qp, qn);
+	  MPN_NORMALIZE_NOT_ZERO (rp, rn);
+
+	  /* first multiply the remainder by 2^b */
+	  MPN_LSHIFT (cy, rp + bn, rp, rn, b % GMP_NUMB_BITS);
+	  rn = rn + bn;
+	  if (cy != 0)
+	    {
+	      rp[rn] = cy;
+	      rn++;
+	    }
+
+	  save = rp[bn];
+	  /* we have to save rp[bn] up to rp[nl-1], i.e. 1 or 2 limbs */
+	  if (nl - 1 > bn)
+	    save2 = rp[bn + 1];
+	}
+      else
+	{
+	  rn = bn;
+	  save2 = save = 0;
+	}
+      /* 2: current buffers: {sp,sn}, {rp,rn}, {wp,wn} */
+
+      /* Now insert bits [kk,kk+b-1] from the input U */
+      MPN_RSHIFT (rp, up + kk / GMP_NUMB_BITS, nl, kk % GMP_NUMB_BITS);
+      /* set to zero high bits of rp[bn] */
+      rp[bn] &= (CNST_LIMB (1) << (b % GMP_NUMB_BITS)) - 1;
+      /* restore corresponding bits */
+      rp[bn] |= save;
+      if (nl - 1 > bn)
+	rp[bn + 1] = save2; /* the low b bits go in rp[0..bn] only, since
+			       they start by bit 0 in rp[0], so they use
+			       at most ceil(b/GMP_NUMB_BITS) limbs */
+      /* FIXME: Should we normalise {rp,rn} here ?*/
+
+      /* 3: current buffers: {sp,sn}, {rp,rn}, {wp,wn} */
+
+      /* compute {wp, wn} = k * {sp, sn}^(k-1) */
+      cy = mpn_mul_1 (wp, wp, wn, k);
+      wp[wn] = cy;
+      wn += cy != 0;
+
+      /* 6: current buffers: {sp,sn}, {qp,qn} */
+
+      /* multiply the root approximation by 2^b */
+      MPN_LSHIFT (cy, sp + b / GMP_NUMB_BITS, sp, sn, b % GMP_NUMB_BITS);
+      sn = sn + b / GMP_NUMB_BITS;
+      if (cy != 0)
+	{
+	  sp[sn] = cy;
+	  sn++;
+	}
+
+      save = sp[b / GMP_NUMB_BITS];
+
+      /* Number of limbs used by b bits, when least significant bit is
+	 aligned to least limb */
+      bn = (b - 1) / GMP_NUMB_BITS + 1;
+
+      /* 4: current buffers: {sp,sn}, {rp,rn}, {wp,wn} */
+
+      /* now divide {rp, rn} by {wp, wn} to get the low part of the root */
+      if (UNLIKELY (rn < wn))
+	{
+	  MPN_FILL (sp, bn, 0);
+	}
+      else
+	{
+	  qn = rn - wn; /* expected quotient size */
+	  if (qn <= bn) { /* Divide only if result is not too big. */
+	    mpn_div_q (qp, rp, rn, wp, wn, scratch);
+	    qn += qp[qn] != 0;
+	  }
+
+      /* 5: current buffers: {sp,sn}, {qp,qn}.
+	 Note: {rp,rn} is not needed any more since we'll compute it from
+	 scratch at the end of the loop.
+       */
+
+      /* the quotient should be smaller than 2^b, since the previous
+	 approximation was correctly rounded toward zero */
+	  if (qn > bn || (qn == bn && (b % GMP_NUMB_BITS != 0) &&
+			  qp[qn - 1] >= (CNST_LIMB (1) << (b % GMP_NUMB_BITS))))
+	    {
+	      for (qn = 1; qn < bn; ++qn)
+		sp[qn - 1] = GMP_NUMB_MAX;
+	      sp[qn - 1] = GMP_NUMB_MAX >> (GMP_NUMB_BITS - 1 - ((b - 1) % GMP_NUMB_BITS));
+	    }
+	  else
+	    {
+      /* 7: current buffers: {sp,sn}, {qp,qn} */
+
+      /* Combine sB and q to form sB + q.  */
+	      MPN_COPY (sp, qp, qn);
+	      MPN_ZERO (sp + qn, bn - qn);
+	    }
+	}
+      sp[b / GMP_NUMB_BITS] |= save;
+
+      /* 8: current buffer: {sp,sn} */
+
+    }
+
+  /* otherwise we have rn > 0, thus the return value is ok */
+  if (!approx || sp[0] <= CNST_LIMB (1))
+    {
+      for (c = 0;; c++)
+	{
+	  /* Compute S^k in {qp,qn}. */
+	  /* Last iteration: we don't need W anymore. */
+	  /* mpn_pow_1 requires that both qp and wp have enough
+	     space to store the result {sp,sn}^k + 1 limb */
+	  qn = mpn_pow_1 (qp, sp, sn, k, wp);
+
+	  perf_pow = 1;
+	  if (qn > un || (qn == un && (perf_pow=mpn_cmp (qp, up, un)) > 0))
+	    MPN_DECR_U (sp, sn, 1);
+	  else
+	    break;
+	};
+
+      /* sometimes two corrections are needed with logbased_root*/
+      ASSERT (c <= 1 + LOGROOT_NEEDS_TWO_CORRECTIONS);
+
+      rn = perf_pow != 0;
+      if (rn != 0 && remp != NULL)
+	{
+	  mpn_sub (remp, up, un, qp, qn);
+	  rn = un;
+	  MPN_NORMALIZE_NOT_ZERO (remp, rn);
+	}
+    }
+
+  TMP_FREE;
+  return rn;
+}
diff --git a/third_party/gmp/mpn/generic/rshift.c b/third_party/gmp/mpn/generic/rshift.c
new file mode 100644
index 0000000..15d427d
--- /dev/null
+++ b/third_party/gmp/mpn/generic/rshift.c
@@ -0,0 +1,69 @@
+/* mpn_rshift -- Shift right low level.
+
+Copyright 1991, 1993, 1994, 1996, 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/* Shift U (pointed to by up and N limbs long) cnt bits to the right
+   and store the n least significant limbs of the result at rp.
+   The bits shifted out to the right are returned.
+
+   Argument constraints:
+   1. 0 < cnt < GMP_NUMB_BITS.
+   2. If the result is to be written over the input, rp must be <= up.
+*/
+
+mp_limb_t
+mpn_rshift (mp_ptr rp, mp_srcptr up, mp_size_t n, unsigned int cnt)
+{
+  mp_limb_t high_limb, low_limb;
+  unsigned int tnc;
+  mp_size_t i;
+  mp_limb_t retval;
+
+  ASSERT (n >= 1);
+  ASSERT (cnt >= 1);
+  ASSERT (cnt < GMP_NUMB_BITS);
+  ASSERT (MPN_SAME_OR_INCR_P (rp, up, n));
+
+  tnc = GMP_NUMB_BITS - cnt;
+  high_limb = *up++;
+  retval = (high_limb << tnc) & GMP_NUMB_MASK;
+  low_limb = high_limb >> cnt;
+
+  for (i = n - 1; i != 0; i--)
+    {
+      high_limb = *up++;
+      *rp++ = low_limb | ((high_limb << tnc) & GMP_NUMB_MASK);
+      low_limb = high_limb >> cnt;
+    }
+  *rp = low_limb;
+
+  return retval;
+}
diff --git a/third_party/gmp/mpn/generic/sbpi1_bdiv_q.c b/third_party/gmp/mpn/generic/sbpi1_bdiv_q.c
new file mode 100644
index 0000000..850e593
--- /dev/null
+++ b/third_party/gmp/mpn/generic/sbpi1_bdiv_q.c
@@ -0,0 +1,96 @@
+/* mpn_sbpi1_bdiv_q -- schoolbook Hensel division with precomputed inverse,
+   returning quotient only.
+
+   Contributed to the GNU project by Niels Möller and Torbjörn Granlund.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL FUNCTIONS WITH MUTABLE INTERFACES.
+   IT IS ONLY SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS
+   ALMOST GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright 2005, 2006, 2009, 2011, 2012, 2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/* Computes Q = - U / D mod B^un, destroys U.
+
+   D must be odd. dinv is (-D)^-1 mod B.
+
+*/
+
+void
+mpn_sbpi1_bdiv_q (mp_ptr qp,
+		  mp_ptr up, mp_size_t un,
+		  mp_srcptr dp, mp_size_t dn,
+		  mp_limb_t dinv)
+{
+  mp_size_t i;
+  mp_limb_t q;
+
+  ASSERT (dn > 0);
+  ASSERT (un >= dn);
+  ASSERT ((dp[0] & 1) != 0);
+  ASSERT (-(dp[0] * dinv) == 1);
+  ASSERT (up == qp || !MPN_OVERLAP_P (up, un, qp, un - dn));
+
+  if (un > dn)
+    {
+      mp_limb_t cy, hi;
+      for (i = un - dn - 1, cy = 0; i > 0; i--)
+	{
+	  q = dinv * up[0];
+	  hi = mpn_addmul_1 (up, dp, dn, q);
+
+	  ASSERT (up[0] == 0);
+	  *qp++ = q;
+	  hi += cy;
+	  cy = hi < cy;
+	  hi += up[dn];
+	  cy += hi < up[dn];
+	  up[dn] = hi;
+	  up++;
+	}
+      q = dinv * up[0];
+      hi = cy + mpn_addmul_1 (up, dp, dn, q);
+      ASSERT (up[0] == 0);
+      *qp++ = q;
+      up[dn] += hi;
+      up++;
+    }
+  for (i = dn; i > 1; i--)
+    {
+      mp_limb_t q = dinv * up[0];
+      mpn_addmul_1 (up, dp, i, q);
+      ASSERT (up[0] == 0);
+      *qp++ = q;
+      up++;
+    }
+
+  /* Final limb */
+  *qp = dinv * up[0];
+}
diff --git a/third_party/gmp/mpn/generic/sbpi1_bdiv_qr.c b/third_party/gmp/mpn/generic/sbpi1_bdiv_qr.c
new file mode 100644
index 0000000..6146c45
--- /dev/null
+++ b/third_party/gmp/mpn/generic/sbpi1_bdiv_qr.c
@@ -0,0 +1,82 @@
+/* mpn_sbpi1_bdiv_qr -- schoolbook Hensel division with precomputed inverse,
+   returning quotient and remainder.
+
+   Contributed to the GNU project by Niels Möller and Torbjörn Granlund.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL FUNCTIONS WITH MUTABLE INTERFACES.
+   IT IS ONLY SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS
+   ALMOST GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright 2006, 2009, 2011, 2012, 2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* Computes a binary quotient of size qn = un - dn.
+   Output:
+
+      Q = -U * D^{-1} mod B^qn,
+
+      R = (U + Q * D) * B^(-qn)
+
+   Stores the dn least significant limbs of R at {up + un - dn, dn},
+   and returns the carry from the addition N + Q*D.
+
+   D must be odd. dinv is (-D)^-1 mod B. */
+
+mp_limb_t
+mpn_sbpi1_bdiv_qr (mp_ptr qp,
+		   mp_ptr up, mp_size_t un,
+		   mp_srcptr dp, mp_size_t dn, mp_limb_t dinv)
+{
+  mp_size_t i;
+  mp_limb_t cy;
+
+  ASSERT (dn > 0);
+  ASSERT (un > dn);
+  ASSERT ((dp[0] & 1) != 0);
+  ASSERT (-(dp[0] * dinv) == 1);
+  ASSERT (up == qp || !MPN_OVERLAP_P (up, un, qp, un - dn));
+
+  for (i = un - dn, cy = 0; i != 0; i--)
+    {
+      mp_limb_t q = dinv * up[0];
+      mp_limb_t hi = mpn_addmul_1 (up, dp, dn, q);
+      *qp++ = q;
+
+      hi += cy;
+      cy = hi < cy;
+      hi += up[dn];
+      cy += hi < up[dn];
+      up[dn] = hi;
+      up++;
+    }
+
+  return cy;
+}
diff --git a/third_party/gmp/mpn/generic/sbpi1_bdiv_r.c b/third_party/gmp/mpn/generic/sbpi1_bdiv_r.c
new file mode 100644
index 0000000..a609951
--- /dev/null
+++ b/third_party/gmp/mpn/generic/sbpi1_bdiv_r.c
@@ -0,0 +1,79 @@
+/* mpn_sbpi1_bdiv_r -- schoolbook Hensel division with precomputed inverse,
+   returning remainder.
+
+   Contributed to the GNU project by Niels Möller and Torbjörn Granlund.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL FUNCTIONS WITH MUTABLE INTERFACES.
+   IT IS ONLY SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS
+   ALMOST GUARANTEED THAT THEY'LL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright 2006, 2009, 2011, 2012, 2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* Computes a binary quotient of size qn = un - dn.
+   Output:
+
+      Q = -U * D^{-1} mod B^qn,
+
+      R = (U + Q * D) * B^(-qn)
+
+   Stores the dn least significant limbs of R at {up + un - dn, dn},
+   and returns the carry from the addition N + Q*D.
+
+   D must be odd. dinv is (-D)^-1 mod B. */
+
+mp_limb_t
+mpn_sbpi1_bdiv_r (mp_ptr up, mp_size_t un,
+		  mp_srcptr dp, mp_size_t dn, mp_limb_t dinv)
+{
+  mp_size_t i;
+  mp_limb_t cy;
+
+  ASSERT (dn > 0);
+  ASSERT (un > dn);
+  ASSERT ((dp[0] & 1) != 0);
+  ASSERT (-(dp[0] * dinv) == 1);
+
+  for (i = un - dn, cy = 0; i != 0; i--)
+    {
+      mp_limb_t q = dinv * up[0];
+      mp_limb_t hi = mpn_addmul_1 (up, dp, dn, q);
+
+      hi += cy;
+      cy = hi < cy;
+      hi += up[dn];
+      cy += hi < up[dn];
+      up[dn] = hi;
+      up++;
+    }
+
+  return cy;
+}
diff --git a/third_party/gmp/mpn/generic/sbpi1_div_q.c b/third_party/gmp/mpn/generic/sbpi1_div_q.c
new file mode 100644
index 0000000..a9975eb
--- /dev/null
+++ b/third_party/gmp/mpn/generic/sbpi1_div_q.c
@@ -0,0 +1,302 @@
+/* mpn_sbpi1_div_q -- Schoolbook division using the Möller-Granlund 3/2
+   division algorithm.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright 2007, 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+mp_limb_t
+mpn_sbpi1_div_q (mp_ptr qp,
+		 mp_ptr np, mp_size_t nn,
+		 mp_srcptr dp, mp_size_t dn,
+		 mp_limb_t dinv)
+{
+  mp_limb_t qh;
+  mp_size_t qn, i;
+  mp_limb_t n1, n0;
+  mp_limb_t d1, d0;
+  mp_limb_t cy, cy1;
+  mp_limb_t q;
+  mp_limb_t flag;
+
+  mp_size_t dn_orig = dn;
+  mp_srcptr dp_orig = dp;
+  mp_ptr np_orig = np;
+
+  ASSERT (dn > 2);
+  ASSERT (nn >= dn);
+  ASSERT ((dp[dn-1] & GMP_NUMB_HIGHBIT) != 0);
+
+  np += nn;
+
+  qn = nn - dn;
+  if (qn + 1 < dn)
+    {
+      dp += dn - (qn + 1);
+      dn = qn + 1;
+    }
+
+  qh = mpn_cmp (np - dn, dp, dn) >= 0;
+  if (qh != 0)
+    mpn_sub_n (np - dn, np - dn, dp, dn);
+
+  qp += qn;
+
+  dn -= 2;			/* offset dn by 2 for main division loops,
+				   saving two iterations in mpn_submul_1.  */
+  d1 = dp[dn + 1];
+  d0 = dp[dn + 0];
+
+  np -= 2;
+
+  n1 = np[1];
+
+  for (i = qn - (dn + 2); i >= 0; i--)
+    {
+      np--;
+      if (UNLIKELY (n1 == d1) && np[1] == d0)
+	{
+	  q = GMP_NUMB_MASK;
+	  mpn_submul_1 (np - dn, dp, dn + 2, q);
+	  n1 = np[1];		/* update n1, last loop's value will now be invalid */
+	}
+      else
+	{
+	  udiv_qr_3by2 (q, n1, n0, n1, np[1], np[0], d1, d0, dinv);
+
+	  cy = mpn_submul_1 (np - dn, dp, dn, q);
+
+	  cy1 = n0 < cy;
+	  n0 = (n0 - cy) & GMP_NUMB_MASK;
+	  cy = n1 < cy1;
+	  n1 -= cy1;
+	  np[0] = n0;
+
+	  if (UNLIKELY (cy != 0))
+	    {
+	      n1 += d1 + mpn_add_n (np - dn, np - dn, dp, dn + 1);
+	      q--;
+	    }
+	}
+
+      *--qp = q;
+    }
+
+  flag = ~CNST_LIMB(0);
+
+  if (dn >= 0)
+    {
+      for (i = dn; i > 0; i--)
+	{
+	  np--;
+	  if (UNLIKELY (n1 >= (d1 & flag)))
+	    {
+	      q = GMP_NUMB_MASK;
+	      cy = mpn_submul_1 (np - dn, dp, dn + 2, q);
+
+	      if (UNLIKELY (n1 != cy))
+		{
+		  if (n1 < (cy & flag))
+		    {
+		      q--;
+		      mpn_add_n (np - dn, np - dn, dp, dn + 2);
+		    }
+		  else
+		    flag = 0;
+		}
+	      n1 = np[1];
+	    }
+	  else
+	    {
+	      udiv_qr_3by2 (q, n1, n0, n1, np[1], np[0], d1, d0, dinv);
+
+	      cy = mpn_submul_1 (np - dn, dp, dn, q);
+
+	      cy1 = n0 < cy;
+	      n0 = (n0 - cy) & GMP_NUMB_MASK;
+	      cy = n1 < cy1;
+	      n1 -= cy1;
+	      np[0] = n0;
+
+	      if (UNLIKELY (cy != 0))
+		{
+		  n1 += d1 + mpn_add_n (np - dn, np - dn, dp, dn + 1);
+		  q--;
+		}
+	    }
+
+	  *--qp = q;
+
+	  /* Truncate operands.  */
+	  dn--;
+	  dp++;
+	}
+
+      np--;
+      if (UNLIKELY (n1 >= (d1 & flag)))
+	{
+	  q = GMP_NUMB_MASK;
+	  cy = mpn_submul_1 (np, dp, 2, q);
+
+	  if (UNLIKELY (n1 != cy))
+	    {
+	      if (n1 < (cy & flag))
+		{
+		  q--;
+		  add_ssaaaa (np[1], np[0], np[1], np[0], dp[1], dp[0]);
+		}
+	      else
+		flag = 0;
+	    }
+	  n1 = np[1];
+	}
+      else
+	{
+	  udiv_qr_3by2 (q, n1, n0, n1, np[1], np[0], d1, d0, dinv);
+
+	  np[0] = n0;
+	  np[1] = n1;
+	}
+
+      *--qp = q;
+    }
+  ASSERT_ALWAYS (np[1] == n1);
+  np += 2;
+
+
+  dn = dn_orig;
+  if (UNLIKELY (n1 < (dn & flag)))
+    {
+      mp_limb_t q, x;
+
+      /* The quotient may be too large if the remainder is small.  Recompute
+	 for above ignored operand parts, until the remainder spills.
+
+	 FIXME: The quality of this code isn't the same as the code above.
+	 1. We don't compute things in an optimal order, high-to-low, in order
+	    to terminate as quickly as possible.
+	 2. We mess with pointers and sizes, adding and subtracting and
+	    adjusting to get things right.  It surely could be streamlined.
+	 3. The only termination criteria are that we determine that the
+	    quotient needs to be adjusted, or that we have recomputed
+	    everything.  We should stop when the remainder is so large
+	    that no additional subtracting could make it spill.
+	 4. If nothing else, we should not do two loops of submul_1 over the
+	    data, instead handle both the triangularization and chopping at
+	    once.  */
+
+      x = n1;
+
+      if (dn > 2)
+	{
+	  /* Compensate for triangularization.  */
+	  mp_limb_t y;
+
+	  dp = dp_orig;
+	  if (qn + 1 < dn)
+	    {
+	      dp += dn - (qn + 1);
+	      dn = qn + 1;
+	    }
+
+	  y = np[-2];
+
+	  for (i = dn - 3; i >= 0; i--)
+	    {
+	      q = qp[i];
+	      cy = mpn_submul_1 (np - (dn - i), dp, dn - i - 2, q);
+
+	      if (y < cy)
+		{
+		  if (x == 0)
+		    {
+		      cy = mpn_sub_1 (qp, qp, qn, 1);
+		      ASSERT_ALWAYS (cy == 0);
+		      return qh - cy;
+		    }
+		  x--;
+		}
+	      y -= cy;
+	    }
+	  np[-2] = y;
+	}
+
+      dn = dn_orig;
+      if (qn + 1 < dn)
+	{
+	  /* Compensate for ignored dividend and divisor tails.  */
+
+	  dp = dp_orig;
+	  np = np_orig;
+
+	  if (qh != 0)
+	    {
+	      cy = mpn_sub_n (np + qn, np + qn, dp, dn - (qn + 1));
+	      if (cy != 0)
+		{
+		  if (x == 0)
+		    {
+		      if (qn != 0)
+			cy = mpn_sub_1 (qp, qp, qn, 1);
+		      return qh - cy;
+		    }
+		  x--;
+		}
+	    }
+
+	  if (qn == 0)
+	    return qh;
+
+	  for (i = dn - qn - 2; i >= 0; i--)
+	    {
+	      cy = mpn_submul_1 (np + i, qp, qn, dp[i]);
+	      cy = mpn_sub_1 (np + qn + i, np + qn + i, dn - qn - i - 1, cy);
+	      if (cy != 0)
+		{
+		  if (x == 0)
+		    {
+		      cy = mpn_sub_1 (qp, qp, qn, 1);
+		      return qh;
+		    }
+		  x--;
+		}
+	    }
+	}
+    }
+
+  return qh;
+}
diff --git a/third_party/gmp/mpn/generic/sbpi1_div_qr.c b/third_party/gmp/mpn/generic/sbpi1_div_qr.c
new file mode 100644
index 0000000..7330a77
--- /dev/null
+++ b/third_party/gmp/mpn/generic/sbpi1_div_qr.c
@@ -0,0 +1,109 @@
+/* mpn_sbpi1_div_qr -- Schoolbook division using the Möller-Granlund 3/2
+   division algorithm.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright 2007, 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+mp_limb_t
+mpn_sbpi1_div_qr (mp_ptr qp,
+		  mp_ptr np, mp_size_t nn,
+		  mp_srcptr dp, mp_size_t dn,
+		  mp_limb_t dinv)
+{
+  mp_limb_t qh;
+  mp_size_t i;
+  mp_limb_t n1, n0;
+  mp_limb_t d1, d0;
+  mp_limb_t cy, cy1;
+  mp_limb_t q;
+
+  ASSERT (dn > 2);
+  ASSERT (nn >= dn);
+  ASSERT ((dp[dn-1] & GMP_NUMB_HIGHBIT) != 0);
+
+  np += nn;
+
+  qh = mpn_cmp (np - dn, dp, dn) >= 0;
+  if (qh != 0)
+    mpn_sub_n (np - dn, np - dn, dp, dn);
+
+  qp += nn - dn;
+
+  dn -= 2;			/* offset dn by 2 for main division loops,
+				   saving two iterations in mpn_submul_1.  */
+  d1 = dp[dn + 1];
+  d0 = dp[dn + 0];
+
+  np -= 2;
+
+  n1 = np[1];
+
+  for (i = nn - (dn + 2); i > 0; i--)
+    {
+      np--;
+      if (UNLIKELY (n1 == d1) && np[1] == d0)
+	{
+	  q = GMP_NUMB_MASK;
+	  mpn_submul_1 (np - dn, dp, dn + 2, q);
+	  n1 = np[1];		/* update n1, last loop's value will now be invalid */
+	}
+      else
+	{
+	  udiv_qr_3by2 (q, n1, n0, n1, np[1], np[0], d1, d0, dinv);
+
+	  cy = mpn_submul_1 (np - dn, dp, dn, q);
+
+	  cy1 = n0 < cy;
+	  n0 = (n0 - cy) & GMP_NUMB_MASK;
+	  cy = n1 < cy1;
+	  n1 = (n1 - cy1) & GMP_NUMB_MASK;
+	  np[0] = n0;
+
+	  if (UNLIKELY (cy != 0))
+	    {
+	      n1 += d1 + mpn_add_n (np - dn, np - dn, dp, dn + 1);
+	      q--;
+	    }
+	}
+
+      *--qp = q;
+    }
+  np[1] = n1;
+
+  return qh;
+}
diff --git a/third_party/gmp/mpn/generic/sbpi1_divappr_q.c b/third_party/gmp/mpn/generic/sbpi1_divappr_q.c
new file mode 100644
index 0000000..ef7ca26
--- /dev/null
+++ b/third_party/gmp/mpn/generic/sbpi1_divappr_q.c
@@ -0,0 +1,198 @@
+/* mpn_sbpi1_divappr_q -- Schoolbook division using the Möller-Granlund 3/2
+   division algorithm, returning approximate quotient.  The quotient returned
+   is either correct, or one too large.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GMP RELEASE.
+
+Copyright 2007, 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+mp_limb_t
+mpn_sbpi1_divappr_q (mp_ptr qp,
+		     mp_ptr np, mp_size_t nn,
+		     mp_srcptr dp, mp_size_t dn,
+		     mp_limb_t dinv)
+{
+  mp_limb_t qh;
+  mp_size_t qn, i;
+  mp_limb_t n1, n0;
+  mp_limb_t d1, d0;
+  mp_limb_t cy, cy1;
+  mp_limb_t q;
+  mp_limb_t flag;
+
+  ASSERT (dn > 2);
+  ASSERT (nn >= dn);
+  ASSERT ((dp[dn-1] & GMP_NUMB_HIGHBIT) != 0);
+
+  np += nn;
+
+  qn = nn - dn;
+  if (qn + 1 < dn)
+    {
+      dp += dn - (qn + 1);
+      dn = qn + 1;
+    }
+
+  qh = mpn_cmp (np - dn, dp, dn) >= 0;
+  if (qh != 0)
+    mpn_sub_n (np - dn, np - dn, dp, dn);
+
+  qp += qn;
+
+  dn -= 2;			/* offset dn by 2 for main division loops,
+				   saving two iterations in mpn_submul_1.  */
+  d1 = dp[dn + 1];
+  d0 = dp[dn + 0];
+
+  np -= 2;
+
+  n1 = np[1];
+
+  for (i = qn - (dn + 2); i >= 0; i--)
+    {
+      np--;
+      if (UNLIKELY (n1 == d1) && np[1] == d0)
+	{
+	  q = GMP_NUMB_MASK;
+	  mpn_submul_1 (np - dn, dp, dn + 2, q);
+	  n1 = np[1];		/* update n1, last loop's value will now be invalid */
+	}
+      else
+	{
+	  udiv_qr_3by2 (q, n1, n0, n1, np[1], np[0], d1, d0, dinv);
+
+	  cy = mpn_submul_1 (np - dn, dp, dn, q);
+
+	  cy1 = n0 < cy;
+	  n0 = (n0 - cy) & GMP_NUMB_MASK;
+	  cy = n1 < cy1;
+	  n1 -= cy1;
+	  np[0] = n0;
+
+	  if (UNLIKELY (cy != 0))
+	    {
+	      n1 += d1 + mpn_add_n (np - dn, np - dn, dp, dn + 1);
+	      q--;
+	    }
+	}
+
+      *--qp = q;
+    }
+
+  flag = ~CNST_LIMB(0);
+
+  if (dn >= 0)
+    {
+      for (i = dn; i > 0; i--)
+	{
+	  np--;
+	  if (UNLIKELY (n1 >= (d1 & flag)))
+	    {
+	      q = GMP_NUMB_MASK;
+	      cy = mpn_submul_1 (np - dn, dp, dn + 2, q);
+
+	      if (UNLIKELY (n1 != cy))
+		{
+		  if (n1 < (cy & flag))
+		    {
+		      q--;
+		      mpn_add_n (np - dn, np - dn, dp, dn + 2);
+		    }
+		  else
+		    flag = 0;
+		}
+	      n1 = np[1];
+	    }
+	  else
+	    {
+	      udiv_qr_3by2 (q, n1, n0, n1, np[1], np[0], d1, d0, dinv);
+
+	      cy = mpn_submul_1 (np - dn, dp, dn, q);
+
+	      cy1 = n0 < cy;
+	      n0 = (n0 - cy) & GMP_NUMB_MASK;
+	      cy = n1 < cy1;
+	      n1 -= cy1;
+	      np[0] = n0;
+
+	      if (UNLIKELY (cy != 0))
+		{
+		  n1 += d1 + mpn_add_n (np - dn, np - dn, dp, dn + 1);
+		  q--;
+		}
+	    }
+
+	  *--qp = q;
+
+	  /* Truncate operands.  */
+	  dn--;
+	  dp++;
+	}
+
+      np--;
+      if (UNLIKELY (n1 >= (d1 & flag)))
+	{
+	  q = GMP_NUMB_MASK;
+	  cy = mpn_submul_1 (np, dp, 2, q);
+
+	  if (UNLIKELY (n1 != cy))
+	    {
+	      if (n1 < (cy & flag))
+		{
+		  q--;
+		  add_ssaaaa (np[1], np[0], np[1], np[0], dp[1], dp[0]);
+		}
+	      else
+		flag = 0;
+	    }
+	  n1 = np[1];
+	}
+      else
+	{
+	  udiv_qr_3by2 (q, n1, n0, n1, np[1], np[0], d1, d0, dinv);
+
+	  np[1] = n1;
+	  np[0] = n0;
+	}
+
+      *--qp = q;
+    }
+
+  ASSERT_ALWAYS (np[1] == n1);
+
+  return qh;
+}
diff --git a/third_party/gmp/mpn/generic/scan0.c b/third_party/gmp/mpn/generic/scan0.c
new file mode 100644
index 0000000..d71832e
--- /dev/null
+++ b/third_party/gmp/mpn/generic/scan0.c
@@ -0,0 +1,59 @@
+/* mpn_scan0 -- Scan from a given bit position for the next clear bit.
+
+Copyright 1994, 1996, 2001, 2002, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/* Argument constraints:
+   1. U must sooner or later have a limb with a clear bit.
+ */
+
+mp_bitcnt_t
+mpn_scan0 (mp_srcptr up, mp_bitcnt_t starting_bit)
+{
+  mp_size_t starting_word;
+  mp_limb_t alimb;
+  int cnt;
+  mp_srcptr p;
+
+  /* Start at the word implied by STARTING_BIT.  */
+  starting_word = starting_bit / GMP_NUMB_BITS;
+  p = up + starting_word;
+  alimb = *p++ ^ GMP_NUMB_MASK;
+
+  /* Mask off any bits before STARTING_BIT in the first limb.  */
+  alimb &= - (mp_limb_t) 1 << (starting_bit % GMP_NUMB_BITS);
+
+  while (alimb == 0)
+    alimb = *p++ ^ GMP_NUMB_MASK;
+
+  count_trailing_zeros (cnt, alimb);
+  return (p - up - 1) * GMP_NUMB_BITS + cnt;
+}
diff --git a/third_party/gmp/mpn/generic/scan1.c b/third_party/gmp/mpn/generic/scan1.c
new file mode 100644
index 0000000..09e8060
--- /dev/null
+++ b/third_party/gmp/mpn/generic/scan1.c
@@ -0,0 +1,59 @@
+/* mpn_scan1 -- Scan from a given bit position for the next set bit.
+
+Copyright 1994, 1996, 2001, 2002, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/* Argument constraints:
+   1. U must sooner or later have a limb != 0.
+ */
+
+mp_bitcnt_t
+mpn_scan1 (mp_srcptr up, mp_bitcnt_t starting_bit)
+{
+  mp_size_t starting_word;
+  mp_limb_t alimb;
+  int cnt;
+  mp_srcptr p;
+
+  /* Start at the word implied by STARTING_BIT.  */
+  starting_word = starting_bit / GMP_NUMB_BITS;
+  p = up + starting_word;
+  alimb = *p++;
+
+  /* Mask off any bits before STARTING_BIT in the first limb.  */
+  alimb &= - (mp_limb_t) 1 << (starting_bit % GMP_NUMB_BITS);
+
+  while (alimb == 0)
+    alimb = *p++;
+
+  count_trailing_zeros (cnt, alimb);
+  return (p - up - 1) * GMP_NUMB_BITS + cnt;
+}
diff --git a/third_party/gmp/mpn/generic/sec_aors_1.c b/third_party/gmp/mpn/generic/sec_aors_1.c
new file mode 100644
index 0000000..6480fa1
--- /dev/null
+++ b/third_party/gmp/mpn/generic/sec_aors_1.c
@@ -0,0 +1,59 @@
+/* mpn_sec_add_1, mpn_sec_sub_1
+
+   Contributed to the GNU project by Niels Möller
+
+Copyright 2013, 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#if OPERATION_sec_add_1
+#define FNAME mpn_sec_add_1
+#define FNAME_itch mpn_sec_add_1_itch
+#define OP_N mpn_add_n
+#endif
+#if OPERATION_sec_sub_1
+#define FNAME mpn_sec_sub_1
+#define FNAME_itch mpn_sec_sub_1_itch
+#define OP_N mpn_sub_n
+#endif
+
+/* It's annoying to that we need scratch space */
+mp_size_t
+FNAME_itch (mp_size_t n)
+{
+  return n;
+}
+
+mp_limb_t
+FNAME (mp_ptr rp, mp_srcptr ap, mp_size_t n, mp_limb_t b, mp_ptr scratch)
+{
+  scratch[0] = b;
+  MPN_ZERO (scratch + 1, n-1);
+  return OP_N (rp, ap, scratch, n);
+}
diff --git a/third_party/gmp/mpn/generic/sec_div.c b/third_party/gmp/mpn/generic/sec_div.c
new file mode 100644
index 0000000..1f08649
--- /dev/null
+++ b/third_party/gmp/mpn/generic/sec_div.c
@@ -0,0 +1,131 @@
+/* mpn_sec_div_qr, mpn_sec_div_r -- Compute Q = floor(U / V), U = U mod V.
+   Side-channel silent under the assumption that the used instructions are
+   side-channel silent.
+
+   Contributed to the GNU project by Torbjörn Granlund.
+
+Copyright 2011-2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#if OPERATION_sec_div_qr
+#define FNAME mpn_sec_div_qr
+#define FNAME_itch mpn_sec_div_qr_itch
+#define Q(q) q,
+#define RETTYPE mp_limb_t
+#endif
+#if OPERATION_sec_div_r
+#define FNAME mpn_sec_div_r
+#define FNAME_itch mpn_sec_div_r_itch
+#define Q(q)
+#define RETTYPE void
+#endif
+
+mp_size_t
+FNAME_itch (mp_size_t nn, mp_size_t dn)
+{
+#if OPERATION_sec_div_qr
+/* Needs (nn + dn + 1) + mpn_sec_pi1_div_qr's needs of (2nn' - dn + 1) for a
+   total of 3nn + 4 limbs at tp.  Note that mpn_sec_pi1_div_qr's nn is one
+   greater than ours, therefore +4 and not just +2.  */
+  return 3 * nn + 4;
+#endif
+#if OPERATION_sec_div_r
+/* Needs (nn + dn + 1) + mpn_sec_pi1_div_r's needs of (dn + 1) for a total of
+   nn + 2dn + 2 limbs at tp.  */
+  return nn + 2 * dn + 2;
+#endif
+}
+
+RETTYPE
+FNAME (Q(mp_ptr qp)
+       mp_ptr np, mp_size_t nn,
+       mp_srcptr dp, mp_size_t dn,
+       mp_ptr tp)
+{
+  mp_limb_t d1, d0;
+  unsigned int cnt;
+  mp_limb_t inv32;
+
+  ASSERT (dn >= 1);
+  ASSERT (nn >= dn);
+  ASSERT (dp[dn - 1] != 0);
+
+  d1 = dp[dn - 1];
+  count_leading_zeros (cnt, d1);
+
+  if (cnt != 0)
+    {
+      mp_limb_t qh, cy;
+      mp_ptr np2, dp2;
+      dp2 = tp;					/* dn limbs */
+      mpn_lshift (dp2, dp, dn, cnt);
+
+      np2 = tp + dn;				/* (nn + 1) limbs */
+      cy = mpn_lshift (np2, np, nn, cnt);
+      np2[nn++] = cy;
+
+      d0 = dp2[dn - 1];
+      d0 += (~d0 != 0);
+      invert_limb (inv32, d0);
+
+      /* We add nn + dn to tp here, not nn + 1 + dn, as expected.  This is
+	 since nn here will have been incremented.  */
+#if OPERATION_sec_div_qr
+      qh = mpn_sec_pi1_div_qr (np2 + dn, np2, nn, dp2, dn, inv32, tp + nn + dn);
+      ASSERT (qh == 0);		/* FIXME: this indicates inefficiency! */
+      MPN_COPY (qp, np2 + dn, nn - dn - 1);
+      qh = np2[nn - 1];
+#else
+      mpn_sec_pi1_div_r (np2, nn, dp2, dn, inv32, tp + nn + dn);
+#endif
+
+      mpn_rshift (np, np2, dn, cnt);
+
+#if OPERATION_sec_div_qr
+      return qh;
+#endif
+    }
+  else
+    {
+      /* FIXME: Consider copying np => np2 here, adding a 0-limb at the top.
+	 That would simplify the underlying pi1 function, since then it could
+	 assume nn > dn.  */
+      d0 = dp[dn - 1];
+      d0 += (~d0 != 0);
+      invert_limb (inv32, d0);
+
+#if OPERATION_sec_div_qr
+      return mpn_sec_pi1_div_qr (qp, np, nn, dp, dn, inv32, tp);
+#else
+      mpn_sec_pi1_div_r (np, nn, dp, dn, inv32, tp);
+#endif
+    }
+}
diff --git a/third_party/gmp/mpn/generic/sec_invert.c b/third_party/gmp/mpn/generic/sec_invert.c
new file mode 100644
index 0000000..07665d1
--- /dev/null
+++ b/third_party/gmp/mpn/generic/sec_invert.c
@@ -0,0 +1,177 @@
+/* mpn_sec_invert
+
+   Contributed to the GNU project by Niels Möller
+
+Copyright 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#if 0
+/* Currently unused. Should be resurrected once mpn_cnd_neg is
+   advertised. */
+static mp_size_t
+mpn_cnd_neg_itch (mp_size_t n)
+{
+  return n;
+}
+#endif
+
+/* FIXME: Ought to return carry */
+static void
+mpn_cnd_neg (int cnd, mp_limb_t *rp, const mp_limb_t *ap, mp_size_t n,
+	     mp_ptr scratch)
+{
+  mpn_lshift (scratch, ap, n, 1);
+  mpn_cnd_sub_n (cnd, rp, ap, scratch, n);
+}
+
+static int
+mpn_sec_eq_ui (mp_srcptr ap, mp_size_t n, mp_limb_t b)
+{
+  mp_limb_t d;
+  ASSERT (n > 0);
+
+  d = ap[0] ^ b;
+
+  while (--n > 0)
+    d |= ap[n];
+
+  return d == 0;
+}
+
+mp_size_t
+mpn_sec_invert_itch (mp_size_t n)
+{
+  return 4*n;
+}
+
+/* Compute V <-- A^{-1} (mod M), in data-independent time. M must be
+   odd. Returns 1 on success, and 0 on failure (i.e., if gcd (A, m) !=
+   1). Inputs and outputs of size n, and no overlap allowed. The {ap,
+   n} area is destroyed. For arbitrary inputs, bit_size should be
+   2*n*GMP_NUMB_BITS, but if A or M are known to be smaller, e.g., if
+   M = 2^521 - 1 and A < M, bit_size can be any bound on the sum of
+   the bit sizes of A and M. */
+int
+mpn_sec_invert (mp_ptr vp, mp_ptr ap, mp_srcptr mp,
+		mp_size_t n, mp_bitcnt_t bit_size,
+		mp_ptr scratch)
+{
+  ASSERT (n > 0);
+  ASSERT (bit_size > 0);
+  ASSERT (mp[0] & 1);
+  ASSERT (! MPN_OVERLAP_P (ap, n, vp, n));
+#define bp (scratch + n)
+#define up (scratch + 2*n)
+#define m1hp (scratch + 3*n)
+
+  /* Maintain
+
+       a = u * orig_a (mod m)
+       b = v * orig_a (mod m)
+
+     and b odd at all times. Initially,
+
+       a = a_orig, u = 1
+       b = m,      v = 0
+     */
+
+
+  up[0] = 1;
+  mpn_zero (up+1, n - 1);
+  mpn_copyi (bp, mp, n);
+  mpn_zero (vp, n);
+
+  ASSERT_CARRY (mpn_rshift (m1hp, mp, n, 1));
+  ASSERT_NOCARRY (mpn_sec_add_1 (m1hp, m1hp, n, 1, scratch));
+
+  while (bit_size-- > 0)
+    {
+      mp_limb_t odd, swap, cy;
+
+      /* Always maintain b odd. The logic of the iteration is as
+	 follows. For a, b:
+
+	   odd = a & 1
+	   a -= odd * b
+	   if (underflow from a-b)
+	     {
+	       b += a, assigns old a
+	       a = B^n-a
+	     }
+
+	   a /= 2
+
+	 For u, v:
+
+	   if (underflow from a - b)
+	     swap u, v
+	   u -= odd * v
+	   if (underflow from u - v)
+	     u += m
+
+	   u /= 2
+	   if (a one bit was shifted out)
+	     u += (m+1)/2
+
+	 As long as a > 0, the quantity
+
+	   (bitsize of a) + (bitsize of b)
+
+	 is reduced by at least one bit per iteration, hence after (bit_size of
+	 orig_a) + (bit_size of m) - 1 iterations we surely have a = 0. Then b
+	 = gcd(orig_a, m) and if b = 1 then also v = orig_a^{-1} (mod m).
+      */
+
+      ASSERT (bp[0] & 1);
+      odd = ap[0] & 1;
+
+      swap = mpn_cnd_sub_n (odd, ap, ap, bp, n);
+      mpn_cnd_add_n (swap, bp, bp, ap, n);
+      mpn_cnd_neg (swap, ap, ap, n, scratch);
+
+      mpn_cnd_swap (swap, up, vp, n);
+      cy = mpn_cnd_sub_n (odd, up, up, vp, n);
+      cy -= mpn_cnd_add_n (cy, up, up, mp, n);
+      ASSERT (cy == 0);
+
+      cy = mpn_rshift (ap, ap, n, 1);
+      ASSERT (cy == 0);
+      cy = mpn_rshift (up, up, n, 1);
+      cy = mpn_cnd_add_n (cy, up, up, m1hp, n);
+      ASSERT (cy == 0);
+    }
+  /* Should be all zeros, but check only extreme limbs */
+  ASSERT ( (ap[0] | ap[n-1]) == 0);
+  /* Check if indeed gcd == 1. */
+  return mpn_sec_eq_ui (bp, n, 1);
+#undef bp
+#undef up
+#undef m1hp
+}
diff --git a/third_party/gmp/mpn/generic/sec_mul.c b/third_party/gmp/mpn/generic/sec_mul.c
new file mode 100644
index 0000000..4bbfa61
--- /dev/null
+++ b/third_party/gmp/mpn/generic/sec_mul.c
@@ -0,0 +1,48 @@
+/* mpn_sec_mul.
+
+   Contributed to the GNU project by Torbjörn Granlund.
+
+Copyright 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpn_sec_mul (mp_ptr rp,
+	     mp_srcptr ap, mp_size_t an,
+	     mp_srcptr bp, mp_size_t bn,
+	     mp_ptr tp)
+{
+  mpn_mul_basecase (rp, ap, an, bp, bn);
+}
+
+mp_size_t
+mpn_sec_mul_itch (mp_size_t an, mp_size_t bn)
+{
+  return 0;
+}
diff --git a/third_party/gmp/mpn/generic/sec_pi1_div.c b/third_party/gmp/mpn/generic/sec_pi1_div.c
new file mode 100644
index 0000000..29d01e7
--- /dev/null
+++ b/third_party/gmp/mpn/generic/sec_pi1_div.c
@@ -0,0 +1,172 @@
+/* mpn_sec_pi1_div_qr, mpn_sec_pi1_div_r -- Compute Q = floor(U / V), U = U
+   mod V.  Side-channel silent under the assumption that the used instructions
+   are side-channel silent.
+
+   Contributed to the GNU project by Torbjörn Granlund.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2011-2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/* This side-channel silent division algorithm reduces the partial remainder by
+   GMP_NUMB_BITS/2 bits at a time, compared to GMP_NUMB_BITS for the main
+   division algorithm.  We actually do not insist on reducing by exactly
+   GMP_NUMB_BITS/2, but may leave a partial remainder that is D*B^i to 3D*B^i
+   too large (B is the limb base, D is the divisor, and i is the induction
+   variable); the subsequent step will handle the extra partial remainder bits.
+
+   With that partial remainder reduction, each step generates a quotient "half
+   limb".  The outer loop generates two quotient half limbs, an upper (q1h) and
+   a lower (q0h) which are stored sparsely in separate limb arrays.  These
+   arrays are added at the end; using separate arrays avoids data-dependent
+   carry propagation which could else pose a side-channel leakage problem.
+
+   The quotient half limbs may be between -3 to 0 from the accurate value
+   ("accurate" being the one which corresponds to a reduction to a principal
+   partial remainder).  Too small quotient half limbs correspond to too large
+   remainders, which we reduce later, as described above.
+
+   In order to keep quotients from getting too big, corresponding to a negative
+   partial remainder, we use an inverse which is slightly smaller than usually.
+*/
+
+#if OPERATION_sec_pi1_div_qr
+/* Needs (dn + 1) + (nn - dn) + (nn - dn) = 2nn - dn + 1 limbs at tp. */
+#define FNAME mpn_sec_pi1_div_qr
+#define Q(q) q,
+#define RETTYPE mp_limb_t
+#endif
+#if OPERATION_sec_pi1_div_r
+/* Needs (dn + 1) limbs at tp.  */
+#define FNAME mpn_sec_pi1_div_r
+#define Q(q)
+#define RETTYPE void
+#endif
+
+RETTYPE
+FNAME (Q(mp_ptr qp)
+       mp_ptr np, mp_size_t nn,
+       mp_srcptr dp, mp_size_t dn,
+       mp_limb_t dinv,
+       mp_ptr tp)
+{
+  mp_limb_t nh, cy, q1h, q0h, dummy, cnd;
+  mp_size_t i;
+  mp_ptr hp;
+#if OPERATION_sec_pi1_div_qr
+  mp_limb_t qh;
+  mp_ptr qlp, qhp;
+#endif
+
+  ASSERT (dn >= 1);
+  ASSERT (nn >= dn);
+  ASSERT ((dp[dn - 1] & GMP_NUMB_HIGHBIT) != 0);
+
+  if (nn == dn)
+    {
+      cy = mpn_sub_n (np, np, dp, dn);
+      mpn_cnd_add_n (cy, np, np, dp, dn);
+#if OPERATION_sec_pi1_div_qr
+      return 1 - cy;
+#else
+      return;
+#endif
+    }
+
+  /* Create a divisor copy shifted half a limb.  */
+  hp = tp;					/* (dn + 1) limbs */
+  hp[dn] = mpn_lshift (hp, dp, dn, GMP_NUMB_BITS / 2);
+
+#if OPERATION_sec_pi1_div_qr
+  qlp = tp + (dn + 1);				/* (nn - dn) limbs */
+  qhp = tp + (nn + 1);				/* (nn - dn) limbs */
+#endif
+
+  np += nn - dn;
+  nh = 0;
+
+  for (i = nn - dn - 1; i >= 0; i--)
+    {
+      np--;
+
+      nh = (nh << GMP_NUMB_BITS/2) + (np[dn] >> GMP_NUMB_BITS/2);
+      umul_ppmm (q1h, dummy, nh, dinv);
+      q1h += nh;
+#if OPERATION_sec_pi1_div_qr
+      qhp[i] = q1h;
+#endif
+      mpn_submul_1 (np, hp, dn + 1, q1h);
+
+      nh = np[dn];
+      umul_ppmm (q0h, dummy, nh, dinv);
+      q0h += nh;
+#if OPERATION_sec_pi1_div_qr
+      qlp[i] = q0h;
+#endif
+      nh -= mpn_submul_1 (np, dp, dn, q0h);
+    }
+
+  /* 1st adjustment depends on extra high remainder limb.  */
+  cnd = nh != 0;				/* FIXME: cmp-to-int */
+#if OPERATION_sec_pi1_div_qr
+  qlp[0] += cnd;
+#endif
+  nh -= mpn_cnd_sub_n (cnd, np, np, dp, dn);
+
+  /* 2nd adjustment depends on remainder/divisor comparison as well as whether
+     extra remainder limb was nullified by previous subtract.  */
+  cy = mpn_sub_n (np, np, dp, dn);
+  cy = cy - nh;
+#if OPERATION_sec_pi1_div_qr
+  qlp[0] += 1 - cy;
+#endif
+  mpn_cnd_add_n (cy, np, np, dp, dn);
+
+  /* 3rd adjustment depends on remainder/divisor comparison.  */
+  cy = mpn_sub_n (np, np, dp, dn);
+#if OPERATION_sec_pi1_div_qr
+  qlp[0] += 1 - cy;
+#endif
+  mpn_cnd_add_n (cy, np, np, dp, dn);
+
+#if OPERATION_sec_pi1_div_qr
+  /* Combine quotient halves into final quotient.  */
+  qh = mpn_lshift (qhp, qhp, nn - dn, GMP_NUMB_BITS/2);
+  qh += mpn_add_n (qp, qhp, qlp, nn - dn);
+
+  return qh;
+#else
+  return;
+#endif
+}
diff --git a/third_party/gmp/mpn/generic/sec_powm.c b/third_party/gmp/mpn/generic/sec_powm.c
new file mode 100644
index 0000000..3a78c66
--- /dev/null
+++ b/third_party/gmp/mpn/generic/sec_powm.c
@@ -0,0 +1,383 @@
+/* mpn_sec_powm -- Compute R = U^E mod M.  Secure variant, side-channel silent
+   under the assumption that the multiply instruction is side channel silent.
+
+   Contributed to the GNU project by Torbjörn Granlund.
+
+Copyright 2007-2009, 2011-2014, 2018-2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+/*
+  BASIC ALGORITHM, Compute U^E mod M, where M < B^n is odd.
+
+  1. T <- (B^n * U) mod M; convert to REDC form
+
+  2. Compute table U^0, U^1, U^2... of floor(log(E))-dependent size
+
+  3. While there are more bits in E
+       W <- power left-to-right base-k
+
+  The article "Defeating modexp side-channel attacks with data-independent
+  execution traces", https://gmplib.org/~tege/modexp-silent.pdf, has details.
+
+
+  TODO:
+
+   * Make getbits a macro, thereby allowing it to update the index operand.
+     That will simplify the code using getbits.  (Perhaps make getbits' sibling
+     getbit then have similar form, for symmetry.)
+
+   * Choose window size without looping.  (Superoptimize or think(tm).)
+
+   * REDC_1_TO_REDC_2_THRESHOLD might actually represent the cutoff between
+     redc_1 and redc_n.  On such systems, we will switch to redc_2 causing
+     slowdown.
+*/
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#undef MPN_REDC_1_SEC
+#if HAVE_NATIVE_mpn_sbpi1_bdiv_r
+#define MPN_REDC_1_SEC(rp, up, mp, n, invm)				\
+  do {									\
+    mp_limb_t cy;							\
+    cy = mpn_sbpi1_bdiv_r (up, 2 * n, mp, n, invm);			\
+    mpn_cnd_sub_n (cy, rp, up + n, mp, n);				\
+  } while (0)
+#else
+#define MPN_REDC_1_SEC(rp, up, mp, n, invm)				\
+  do {									\
+    mp_limb_t cy;							\
+    cy = mpn_redc_1 (rp, up, mp, n, invm);				\
+    mpn_cnd_sub_n (cy, rp, rp, mp, n);					\
+  } while (0)
+#endif
+
+#if HAVE_NATIVE_mpn_addmul_2 || HAVE_NATIVE_mpn_redc_2
+#undef MPN_REDC_2_SEC
+#define MPN_REDC_2_SEC(rp, up, mp, n, mip)				\
+  do {									\
+    mp_limb_t cy;							\
+    cy = mpn_redc_2 (rp, up, mp, n, mip);				\
+    mpn_cnd_sub_n (cy, rp, rp, mp, n);					\
+  } while (0)
+#else
+#define MPN_REDC_2_SEC(rp, up, mp, n, mip) /* empty */
+#undef REDC_1_TO_REDC_2_THRESHOLD
+#define REDC_1_TO_REDC_2_THRESHOLD MP_SIZE_T_MAX
+#endif
+
+/* Define our own mpn squaring function.  We do this since we cannot use a
+   native mpn_sqr_basecase over TUNE_SQR_TOOM2_MAX, or a non-native one over
+   SQR_TOOM2_THRESHOLD.  This is so because of fixed size stack allocations
+   made inside mpn_sqr_basecase.  */
+
+#if ! HAVE_NATIVE_mpn_sqr_basecase
+/* The limit of the generic code is SQR_TOOM2_THRESHOLD.  */
+#define SQR_BASECASE_LIM  SQR_TOOM2_THRESHOLD
+#endif
+
+#if HAVE_NATIVE_mpn_sqr_basecase
+#ifdef TUNE_SQR_TOOM2_MAX
+/* We slightly abuse TUNE_SQR_TOOM2_MAX here.  If it is set for an assembly
+   mpn_sqr_basecase, it comes from SQR_TOOM2_THRESHOLD_MAX in the assembly
+   file.  An assembly mpn_sqr_basecase that does not define it should allow
+   any size.  */
+#define SQR_BASECASE_LIM  SQR_TOOM2_THRESHOLD
+#endif
+#endif
+
+#ifdef WANT_FAT_BINARY
+/* For fat builds, we use SQR_TOOM2_THRESHOLD which will expand to a read from
+   __gmpn_cpuvec.  Perhaps any possible sqr_basecase.asm allow any size, and we
+   limit the use unnecessarily.  We cannot tell, so play it safe.  FIXME.  */
+#define SQR_BASECASE_LIM  SQR_TOOM2_THRESHOLD
+#endif
+
+#ifndef SQR_BASECASE_LIM
+/* If SQR_BASECASE_LIM is now not defined, use mpn_sqr_basecase for any operand
+   size.  */
+#define SQR_BASECASE_LIM  MP_SIZE_T_MAX
+#endif
+
+#define mpn_local_sqr(rp,up,n)						\
+  do {									\
+    if (ABOVE_THRESHOLD (n, SQR_BASECASE_THRESHOLD)			\
+	&& BELOW_THRESHOLD (n, SQR_BASECASE_LIM))			\
+      mpn_sqr_basecase (rp, up, n);					\
+    else								\
+      mpn_mul_basecase(rp, up, n, up, n);				\
+  } while (0)
+
+#define getbit(p,bi) \
+  ((p[(bi - 1) / GMP_NUMB_BITS] >> (bi - 1) % GMP_NUMB_BITS) & 1)
+
+/* FIXME: Maybe some things would get simpler if all callers ensure
+   that bi >= nbits. As far as I understand, with the current code bi
+   < nbits can happen only for the final iteration. */
+static inline mp_limb_t
+getbits (const mp_limb_t *p, mp_bitcnt_t bi, int nbits)
+{
+  int nbits_in_r;
+  mp_limb_t r;
+  mp_size_t i;
+
+  if (bi < nbits)
+    {
+      return p[0] & (((mp_limb_t) 1 << bi) - 1);
+    }
+  else
+    {
+      bi -= nbits;			/* bit index of low bit to extract */
+      i = bi / GMP_NUMB_BITS;		/* word index of low bit to extract */
+      bi %= GMP_NUMB_BITS;		/* bit index in low word */
+      r = p[i] >> bi;			/* extract (low) bits */
+      nbits_in_r = GMP_NUMB_BITS - bi;	/* number of bits now in r */
+      if (nbits_in_r < nbits)		/* did we get enough bits? */
+	r += p[i + 1] << nbits_in_r;	/* prepend bits from higher word */
+      return r & (((mp_limb_t ) 1 << nbits) - 1);
+    }
+}
+
+#ifndef POWM_SEC_TABLE
+#if GMP_NUMB_BITS < 50
+#define POWM_SEC_TABLE  2,33,96,780,2741
+#else
+#define POWM_SEC_TABLE  2,130,524,2578
+#endif
+#endif
+
+#if TUNE_PROGRAM_BUILD
+extern int win_size (mp_bitcnt_t);
+#else
+static inline int
+win_size (mp_bitcnt_t enb)
+{
+  int k;
+  /* Find k, such that x[k-1] < enb <= x[k].
+
+     We require that x[k] >= k, then it follows that enb > x[k-1] >=
+     k-1, which implies k <= enb.
+  */
+  static const mp_bitcnt_t x[] = {0,POWM_SEC_TABLE,~(mp_bitcnt_t)0};
+  for (k = 1; enb > x[k]; k++)
+    ;
+  ASSERT (k <= enb);
+  return k;
+}
+#endif
+
+/* Convert U to REDC form, U_r = B^n * U mod M.
+   Uses scratch space at tp of size 2un + n + 1.  */
+static void
+redcify (mp_ptr rp, mp_srcptr up, mp_size_t un, mp_srcptr mp, mp_size_t n, mp_ptr tp)
+{
+  MPN_ZERO (tp, n);
+  MPN_COPY (tp + n, up, un);
+
+  mpn_sec_div_r (tp, un + n, mp, n, tp + un + n);
+  MPN_COPY (rp, tp, n);
+}
+
+/* {rp, n} <-- {bp, bn} ^ {ep, en} mod {mp, n},
+   where en = ceil (enb / GMP_NUMB_BITS)
+   Requires that {mp, n} is odd (and hence also mp[0] odd).
+   Uses scratch space at tp as defined by mpn_sec_powm_itch.  */
+void
+mpn_sec_powm (mp_ptr rp, mp_srcptr bp, mp_size_t bn,
+	      mp_srcptr ep, mp_bitcnt_t enb,
+	      mp_srcptr mp, mp_size_t n, mp_ptr tp)
+{
+  mp_limb_t ip[2], *mip;
+  int windowsize, this_windowsize;
+  mp_limb_t expbits;
+  mp_ptr pp, this_pp, ps;
+  long i;
+  int cnd;
+
+  ASSERT (enb > 0);
+  ASSERT (n > 0);
+  /* The code works for bn = 0, but the defined scratch space is 2 limbs
+     greater than we supply, when converting 1 to redc form .  */
+  ASSERT (bn > 0);
+  ASSERT ((mp[0] & 1) != 0);
+
+  windowsize = win_size (enb);
+
+  if (BELOW_THRESHOLD (n, REDC_1_TO_REDC_2_THRESHOLD))
+    {
+      mip = ip;
+      binvert_limb (mip[0], mp[0]);
+      mip[0] = -mip[0];
+    }
+  else
+    {
+      mip = ip;
+      mpn_binvert (mip, mp, 2, tp);
+      mip[0] = -mip[0]; mip[1] = ~mip[1];
+    }
+
+  pp = tp;
+  tp += (n << windowsize);	/* put tp after power table */
+
+  /* Compute pp[0] table entry */
+  /* scratch: |   n   | 1 |   n+2    |  */
+  /*          | pp[0] | 1 | redcify  |  */
+  this_pp = pp;
+  this_pp[n] = 1;
+  redcify (this_pp, this_pp + n, 1, mp, n, this_pp + n + 1);
+  this_pp += n;
+
+  /* Compute pp[1] table entry.  To avoid excessive scratch usage in the
+     degenerate situation where B >> M, we let redcify use scratch space which
+     will later be used by the pp table (element 2 and up).  */
+  /* scratch: |   n   |   n   |  bn + n + 1  |  */
+  /*          | pp[0] | pp[1] |   redcify    |  */
+  redcify (this_pp, bp, bn, mp, n, this_pp + n);
+
+  /* Precompute powers of b and put them in the temporary area at pp.  */
+  /* scratch: |   n   |   n   | ...  |                    |   2n      |  */
+  /*          | pp[0] | pp[1] | ...  | pp[2^windowsize-1] |  product  |  */
+  ps = pp + n;		/* initially B^1 */
+  if (BELOW_THRESHOLD (n, REDC_1_TO_REDC_2_THRESHOLD))
+    {
+      for (i = (1 << windowsize) - 2; i > 0; i -= 2)
+	{
+	  mpn_local_sqr (tp, ps, n);
+	  ps += n;
+	  this_pp += n;
+	  MPN_REDC_1_SEC (this_pp, tp, mp, n, mip[0]);
+
+	  mpn_mul_basecase (tp, this_pp, n, pp + n, n);
+	  this_pp += n;
+	  MPN_REDC_1_SEC (this_pp, tp, mp, n, mip[0]);
+	}
+    }
+  else
+    {
+      for (i = (1 << windowsize) - 2; i > 0; i -= 2)
+	{
+	  mpn_local_sqr (tp, ps, n);
+	  ps += n;
+	  this_pp += n;
+	  MPN_REDC_2_SEC (this_pp, tp, mp, n, mip);
+
+	  mpn_mul_basecase (tp, this_pp, n, pp + n, n);
+	  this_pp += n;
+	  MPN_REDC_2_SEC (this_pp, tp, mp, n, mip);
+	}
+    }
+
+  expbits = getbits (ep, enb, windowsize);
+  ASSERT_ALWAYS (enb >= windowsize);
+  enb -= windowsize;
+
+  mpn_sec_tabselect (rp, pp, n, 1 << windowsize, expbits);
+
+  /* Main exponentiation loop.  */
+  /* scratch: |   n   |   n   | ...  |                    |     3n-4n     |  */
+  /*          | pp[0] | pp[1] | ...  | pp[2^windowsize-1] |  loop scratch |  */
+
+#define INNERLOOP							\
+  while (enb != 0)							\
+    {									\
+      expbits = getbits (ep, enb, windowsize);				\
+      this_windowsize = windowsize;					\
+      if (enb < windowsize)						\
+	{								\
+	  this_windowsize -= windowsize - enb;				\
+	  enb = 0;							\
+	}								\
+      else								\
+	enb -= windowsize;						\
+									\
+      do								\
+	{								\
+	  mpn_local_sqr (tp, rp, n);					\
+	  MPN_REDUCE (rp, tp, mp, n, mip);				\
+	  this_windowsize--;						\
+	}								\
+      while (this_windowsize != 0);					\
+									\
+      mpn_sec_tabselect (tp + 2*n, pp, n, 1 << windowsize, expbits);	\
+      mpn_mul_basecase (tp, rp, n, tp + 2*n, n);			\
+									\
+      MPN_REDUCE (rp, tp, mp, n, mip);					\
+    }
+
+  if (BELOW_THRESHOLD (n, REDC_1_TO_REDC_2_THRESHOLD))
+    {
+#undef MPN_REDUCE
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_1_SEC (rp, tp, mp, n, mip[0])
+      INNERLOOP;
+    }
+  else
+    {
+#undef MPN_REDUCE
+#define MPN_REDUCE(rp,tp,mp,n,mip)	MPN_REDC_2_SEC (rp, tp, mp, n, mip)
+      INNERLOOP;
+    }
+
+  MPN_COPY (tp, rp, n);
+  MPN_ZERO (tp + n, n);
+
+  if (BELOW_THRESHOLD (n, REDC_1_TO_REDC_2_THRESHOLD))
+    MPN_REDC_1_SEC (rp, tp, mp, n, mip[0]);
+  else
+    MPN_REDC_2_SEC (rp, tp, mp, n, mip);
+
+  cnd = mpn_sub_n (tp, rp, mp, n);	/* we need just retval */
+  mpn_cnd_sub_n (!cnd, rp, rp, mp, n);
+}
+
+mp_size_t
+mpn_sec_powm_itch (mp_size_t bn, mp_bitcnt_t enb, mp_size_t n)
+{
+  int windowsize;
+  mp_size_t redcify_itch, itch;
+
+  /* FIXME: no more _local/_basecase difference. */
+  /* The top scratch usage will either be when reducing B in the 2nd redcify
+     call, or more typically n*2^windowsize + 3n or 4n, in the main loop.  (It
+     is 3n or 4n depending on if we use mpn_local_sqr or a native
+     mpn_sqr_basecase.  We assume 4n always for now.) */
+
+  windowsize = win_size (enb);
+
+  /* The 2n term is due to pp[0] and pp[1] at the time of the 2nd redcify call,
+     the (bn + n) term is due to redcify's own usage, and the rest is due to
+     mpn_sec_div_r's usage when called from redcify.  */
+  redcify_itch = (2 * n) + (bn + n) + ((bn + n) + 2 * n + 2);
+
+  /* The n * 2^windowsize term is due to the power table, the 4n term is due to
+     scratch needs of squaring/multiplication in the exponentiation loop.  */
+  itch = (n << windowsize) + (4 * n);
+
+  return MAX (itch, redcify_itch);
+}
diff --git a/third_party/gmp/mpn/generic/sec_sqr.c b/third_party/gmp/mpn/generic/sec_sqr.c
new file mode 100644
index 0000000..83fc7d9
--- /dev/null
+++ b/third_party/gmp/mpn/generic/sec_sqr.c
@@ -0,0 +1,76 @@
+/* mpn_sec_sqr.
+
+   Contributed to the GNU project by Torbjörn Granlund.
+
+Copyright 2013, 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#if ! HAVE_NATIVE_mpn_sqr_basecase
+/* The limit of the generic code is SQR_TOOM2_THRESHOLD.  */
+#define SQR_BASECASE_LIM  SQR_TOOM2_THRESHOLD
+#endif
+
+#if HAVE_NATIVE_mpn_sqr_basecase
+#ifdef TUNE_SQR_TOOM2_MAX
+/* We slightly abuse TUNE_SQR_TOOM2_MAX here.  If it is set for an assembly
+   mpn_sqr_basecase, it comes from SQR_TOOM2_THRESHOLD_MAX in the assembly
+   file.  An assembly mpn_sqr_basecase that does not define it should allow
+   any size.  */
+#define SQR_BASECASE_LIM  SQR_TOOM2_THRESHOLD
+#endif
+#endif
+
+#ifdef WANT_FAT_BINARY
+/* For fat builds, we use SQR_TOOM2_THRESHOLD which will expand to a read from
+   __gmpn_cpuvec.  Perhaps any possible sqr_basecase.asm allow any size, and we
+   limit the use unnecessarily.  We cannot tell, so play it safe.  FIXME.  */
+#define SQR_BASECASE_LIM  SQR_TOOM2_THRESHOLD
+#endif
+
+void
+mpn_sec_sqr (mp_ptr rp,
+	     mp_srcptr ap, mp_size_t an,
+	     mp_ptr tp)
+{
+#ifndef SQR_BASECASE_LIM
+/* If SQR_BASECASE_LIM is now not defined, use mpn_sqr_basecase for any operand
+   size.  */
+  mpn_sqr_basecase (rp, ap, an);
+#else
+/* Else use mpn_mul_basecase.  */
+  mpn_mul_basecase (rp, ap, an, ap, an);
+#endif
+}
+
+mp_size_t
+mpn_sec_sqr_itch (mp_size_t an)
+{
+  return 0;
+}
diff --git a/third_party/gmp/mpn/generic/sec_tabselect.c b/third_party/gmp/mpn/generic/sec_tabselect.c
new file mode 100644
index 0000000..5767e27
--- /dev/null
+++ b/third_party/gmp/mpn/generic/sec_tabselect.c
@@ -0,0 +1,54 @@
+/* mpn_sec_tabselect.
+
+Copyright 2007-2009, 2011, 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* Select entry `which' from table `tab', which has nents entries, each `n'
+   limbs.  Store the selected entry at rp.  Reads entire table to avoid
+   side-channel information leaks.  O(n*nents).  */
+void
+mpn_sec_tabselect (volatile mp_limb_t *rp, volatile const mp_limb_t *tab,
+		   mp_size_t n, mp_size_t nents, mp_size_t which)
+{
+  mp_size_t k, i;
+  mp_limb_t mask;
+  volatile const mp_limb_t *tp;
+
+  for (k = 0; k < nents; k++)
+    {
+      mask = -(mp_limb_t) (which == k);
+      tp = tab + n * k;
+      for (i = 0; i < n; i++)
+	{
+	  rp[i] = (rp[i] & ~mask) | (tp[i] & mask);
+	}
+    }
+}
diff --git a/third_party/gmp/mpn/generic/set_str.c b/third_party/gmp/mpn/generic/set_str.c
new file mode 100644
index 0000000..2bd584c
--- /dev/null
+++ b/third_party/gmp/mpn/generic/set_str.c
@@ -0,0 +1,290 @@
+/* mpn_set_str (mp_ptr res_ptr, const char *str, size_t str_len, int base) --
+   Convert a STR_LEN long base BASE byte string pointed to by STR to a limb
+   vector pointed to by RES_PTR.  Return the number of limbs in RES_PTR.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+   THE FUNCTIONS IN THIS FILE, EXCEPT mpn_set_str, ARE INTERNAL WITH MUTABLE
+   INTERFACES.  IT IS ONLY SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.
+   IN FACT, IT IS ALMOST GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A
+   FUTURE GNU MP RELEASE.
+
+Copyright 1991-2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+/* TODO:
+
+      Perhaps do not compute the highest power?
+      Instead, multiply twice by the 2nd highest power:
+
+	       _______
+	      |_______|  hp
+	      |_______|  pow
+       _______________
+      |_______________|  final result
+
+
+	       _______
+	      |_______|  hp
+		  |___|  pow[-1]
+	   ___________
+	  |___________|  intermediate result
+		  |___|  pow[-1]
+       _______________
+      |_______________|  final result
+
+      Generalizing that idea, perhaps we should make powtab contain successive
+      cubes, not squares.
+*/
+
+#include "gmp-impl.h"
+
+mp_size_t
+mpn_set_str (mp_ptr rp, const unsigned char *str, size_t str_len, int base)
+{
+  if (POW2_P (base))
+    {
+      /* The base is a power of 2.  Read the input string from least to most
+	 significant character/digit.  */
+
+      const unsigned char *s;
+      int next_bitpos;
+      mp_limb_t res_digit;
+      mp_size_t size;
+      int bits_per_indigit = mp_bases[base].big_base;
+
+      size = 0;
+      res_digit = 0;
+      next_bitpos = 0;
+
+      for (s = str + str_len - 1; s >= str; s--)
+	{
+	  int inp_digit = *s;
+
+	  res_digit |= ((mp_limb_t) inp_digit << next_bitpos) & GMP_NUMB_MASK;
+	  next_bitpos += bits_per_indigit;
+	  if (next_bitpos >= GMP_NUMB_BITS)
+	    {
+	      rp[size++] = res_digit;
+	      next_bitpos -= GMP_NUMB_BITS;
+	      res_digit = inp_digit >> (bits_per_indigit - next_bitpos);
+	    }
+	}
+
+      if (res_digit != 0)
+	rp[size++] = res_digit;
+      return size;
+    }
+
+  if (BELOW_THRESHOLD (str_len, SET_STR_PRECOMPUTE_THRESHOLD))
+    return mpn_bc_set_str (rp, str, str_len, base);
+  else
+    {
+      mp_ptr powtab_mem, tp;
+      powers_t powtab[GMP_LIMB_BITS];
+      int chars_per_limb;
+      mp_size_t size;
+      mp_size_t un;
+      TMP_DECL;
+
+      TMP_MARK;
+
+      chars_per_limb = mp_bases[base].chars_per_limb;
+
+      un = str_len / chars_per_limb + 1; /* FIXME: scalar integer division */
+
+      /* Allocate one large block for the powers of big_base.  */
+      powtab_mem = TMP_BALLOC_LIMBS (mpn_str_powtab_alloc (un));
+
+      size_t n_pows = mpn_compute_powtab (powtab, powtab_mem, un, base);
+      powers_t *pt = powtab + n_pows;
+
+      tp = TMP_BALLOC_LIMBS (mpn_dc_set_str_itch (un));
+      size = mpn_dc_set_str (rp, str, str_len, pt, tp);
+
+      TMP_FREE;
+      return size;
+    }
+}
+
+mp_size_t
+mpn_dc_set_str (mp_ptr rp, const unsigned char *str, size_t str_len,
+		const powers_t *powtab, mp_ptr tp)
+{
+  size_t len_lo, len_hi;
+  mp_limb_t cy;
+  mp_size_t ln, hn, n, sn;
+
+  len_lo = powtab->digits_in_base;
+
+  if (str_len <= len_lo)
+    {
+      if (BELOW_THRESHOLD (str_len, SET_STR_DC_THRESHOLD))
+	return mpn_bc_set_str (rp, str, str_len, powtab->base);
+      else
+	return mpn_dc_set_str (rp, str, str_len, powtab - 1, tp);
+    }
+
+  len_hi = str_len - len_lo;
+  ASSERT (len_lo >= len_hi);
+
+  if (BELOW_THRESHOLD (len_hi, SET_STR_DC_THRESHOLD))
+    hn = mpn_bc_set_str (tp, str, len_hi, powtab->base);
+  else
+    hn = mpn_dc_set_str (tp, str, len_hi, powtab - 1, rp);
+
+  sn = powtab->shift;
+
+  if (hn == 0)
+    {
+      /* Zero +1 limb here, to avoid reading an allocated but uninitialised
+	 limb in mpn_incr_u below.  */
+      MPN_ZERO (rp, powtab->n + sn + 1);
+    }
+  else
+    {
+      if (powtab->n > hn)
+	mpn_mul (rp + sn, powtab->p, powtab->n, tp, hn);
+      else
+	mpn_mul (rp + sn, tp, hn, powtab->p, powtab->n);
+      MPN_ZERO (rp, sn);
+    }
+
+  str = str + str_len - len_lo;
+  if (BELOW_THRESHOLD (len_lo, SET_STR_DC_THRESHOLD))
+    ln = mpn_bc_set_str (tp, str, len_lo, powtab->base);
+  else
+    ln = mpn_dc_set_str (tp, str, len_lo, powtab - 1, tp + powtab->n + sn + 1);
+
+  if (ln != 0)
+    {
+      cy = mpn_add_n (rp, rp, tp, ln);
+      mpn_incr_u (rp + ln, cy);
+    }
+  n = hn + powtab->n + sn;
+  return n - (rp[n - 1] == 0);
+}
+
+mp_size_t
+mpn_bc_set_str (mp_ptr rp, const unsigned char *str, size_t str_len, int base)
+{
+  mp_size_t size;
+  size_t i;
+  long j;
+  mp_limb_t cy_limb;
+
+  mp_limb_t big_base;
+  int chars_per_limb;
+  mp_limb_t res_digit;
+
+  ASSERT (base >= 2);
+  ASSERT (base < numberof (mp_bases));
+  ASSERT (str_len >= 1);
+
+  big_base = mp_bases[base].big_base;
+  chars_per_limb = mp_bases[base].chars_per_limb;
+
+  size = 0;
+  for (i = chars_per_limb; i < str_len; i += chars_per_limb)
+    {
+      res_digit = *str++;
+      if (base == 10)
+	{ /* This is a common case.
+	     Help the compiler to avoid multiplication.  */
+	  for (j = MP_BASES_CHARS_PER_LIMB_10 - 1; j != 0; j--)
+	    res_digit = res_digit * 10 + *str++;
+	}
+      else
+	{
+	  for (j = chars_per_limb - 1; j != 0; j--)
+	    res_digit = res_digit * base + *str++;
+	}
+
+      if (size == 0)
+	{
+	  if (res_digit != 0)
+	    {
+	      rp[0] = res_digit;
+	      size = 1;
+	    }
+	}
+      else
+	{
+#if HAVE_NATIVE_mpn_mul_1c
+	  cy_limb = mpn_mul_1c (rp, rp, size, big_base, res_digit);
+#else
+	  cy_limb = mpn_mul_1 (rp, rp, size, big_base);
+	  cy_limb += mpn_add_1 (rp, rp, size, res_digit);
+#endif
+	  if (cy_limb != 0)
+	    rp[size++] = cy_limb;
+	}
+    }
+
+  big_base = base;
+  res_digit = *str++;
+  if (base == 10)
+    { /* This is a common case.
+	 Help the compiler to avoid multiplication.  */
+      for (j = str_len - (i - MP_BASES_CHARS_PER_LIMB_10) - 1; j > 0; j--)
+	{
+	  res_digit = res_digit * 10 + *str++;
+	  big_base *= 10;
+	}
+    }
+  else
+    {
+      for (j = str_len - (i - chars_per_limb) - 1; j > 0; j--)
+	{
+	  res_digit = res_digit * base + *str++;
+	  big_base *= base;
+	}
+    }
+
+  if (size == 0)
+    {
+      if (res_digit != 0)
+	{
+	  rp[0] = res_digit;
+	  size = 1;
+	}
+    }
+  else
+    {
+#if HAVE_NATIVE_mpn_mul_1c
+      cy_limb = mpn_mul_1c (rp, rp, size, big_base, res_digit);
+#else
+      cy_limb = mpn_mul_1 (rp, rp, size, big_base);
+      cy_limb += mpn_add_1 (rp, rp, size, res_digit);
+#endif
+      if (cy_limb != 0)
+	rp[size++] = cy_limb;
+    }
+  return size;
+}
diff --git a/third_party/gmp/mpn/generic/sizeinbase.c b/third_party/gmp/mpn/generic/sizeinbase.c
new file mode 100644
index 0000000..faee947
--- /dev/null
+++ b/third_party/gmp/mpn/generic/sizeinbase.c
@@ -0,0 +1,49 @@
+/* mpn_sizeinbase -- approximation to chars required for an mpn.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 1991, 1993-1995, 2001, 2002, 2011, 2012 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* Same as mpz_sizeinbase, meaning exact for power-of-2 bases, and either
+   exact or 1 too big for other bases.  */
+
+size_t
+mpn_sizeinbase (mp_srcptr xp, mp_size_t xsize, int base)
+{
+  size_t  result;
+  MPN_SIZEINBASE (result, xp, xsize, base);
+  return result;
+}
diff --git a/third_party/gmp/mpn/generic/sqr.c b/third_party/gmp/mpn/generic/sqr.c
new file mode 100644
index 0000000..74fbff0
--- /dev/null
+++ b/third_party/gmp/mpn/generic/sqr.c
@@ -0,0 +1,98 @@
+/* mpn_sqr -- square natural numbers.
+
+Copyright 1991, 1993, 1994, 1996-2003, 2005, 2008, 2009 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+void
+mpn_sqr (mp_ptr p, mp_srcptr a, mp_size_t n)
+{
+  ASSERT (n >= 1);
+  ASSERT (! MPN_OVERLAP_P (p, 2 * n, a, n));
+
+  if (BELOW_THRESHOLD (n, SQR_BASECASE_THRESHOLD))
+    { /* mul_basecase is faster than sqr_basecase on small sizes sometimes */
+      mpn_mul_basecase (p, a, n, a, n);
+    }
+  else if (BELOW_THRESHOLD (n, SQR_TOOM2_THRESHOLD))
+    {
+      mpn_sqr_basecase (p, a, n);
+    }
+  else if (BELOW_THRESHOLD (n, SQR_TOOM3_THRESHOLD))
+    {
+      /* Allocate workspace of fixed size on stack: fast! */
+      mp_limb_t ws[mpn_toom2_sqr_itch (SQR_TOOM3_THRESHOLD_LIMIT-1)];
+      ASSERT (SQR_TOOM3_THRESHOLD <= SQR_TOOM3_THRESHOLD_LIMIT);
+      mpn_toom2_sqr (p, a, n, ws);
+    }
+  else if (BELOW_THRESHOLD (n, SQR_TOOM4_THRESHOLD))
+    {
+      mp_ptr ws;
+      TMP_SDECL;
+      TMP_SMARK;
+      ws = TMP_SALLOC_LIMBS (mpn_toom3_sqr_itch (n));
+      mpn_toom3_sqr (p, a, n, ws);
+      TMP_SFREE;
+    }
+  else if (BELOW_THRESHOLD (n, SQR_TOOM6_THRESHOLD))
+    {
+      mp_ptr ws;
+      TMP_SDECL;
+      TMP_SMARK;
+      ws = TMP_SALLOC_LIMBS (mpn_toom4_sqr_itch (n));
+      mpn_toom4_sqr (p, a, n, ws);
+      TMP_SFREE;
+    }
+  else if (BELOW_THRESHOLD (n, SQR_TOOM8_THRESHOLD))
+    {
+      mp_ptr ws;
+      TMP_SDECL;
+      TMP_SMARK;
+      ws = TMP_SALLOC_LIMBS (mpn_toom6_sqr_itch (n));
+      mpn_toom6_sqr (p, a, n, ws);
+      TMP_SFREE;
+    }
+  else if (BELOW_THRESHOLD (n, SQR_FFT_THRESHOLD))
+    {
+      mp_ptr ws;
+      TMP_DECL;
+      TMP_MARK;
+      ws = TMP_ALLOC_LIMBS (mpn_toom8_sqr_itch (n));
+      mpn_toom8_sqr (p, a, n, ws);
+      TMP_FREE;
+    }
+  else
+    {
+      /* The current FFT code allocates its own space.  That should probably
+	 change.  */
+      mpn_fft_mul (p, a, n, a, n);
+    }
+}
diff --git a/third_party/gmp/mpn/generic/sqr_basecase.c b/third_party/gmp/mpn/generic/sqr_basecase.c
new file mode 100644
index 0000000..2645bad
--- /dev/null
+++ b/third_party/gmp/mpn/generic/sqr_basecase.c
@@ -0,0 +1,361 @@
+/* mpn_sqr_basecase -- Internal routine to square a natural number
+   of length n.
+
+   THIS IS AN INTERNAL FUNCTION WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH THIS FUNCTION THROUGH DOCUMENTED INTERFACES.
+
+
+Copyright 1991-1994, 1996, 1997, 2000-2005, 2008, 2010, 2011, 2017 Free
+Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+#if HAVE_NATIVE_mpn_sqr_diagonal
+#define MPN_SQR_DIAGONAL(rp, up, n)					\
+  mpn_sqr_diagonal (rp, up, n)
+#else
+#define MPN_SQR_DIAGONAL(rp, up, n)					\
+  do {									\
+    mp_size_t _i;							\
+    for (_i = 0; _i < (n); _i++)					\
+      {									\
+	mp_limb_t ul, lpl;						\
+	ul = (up)[_i];							\
+	umul_ppmm ((rp)[2 * _i + 1], lpl, ul, ul << GMP_NAIL_BITS);	\
+	(rp)[2 * _i] = lpl >> GMP_NAIL_BITS;				\
+      }									\
+  } while (0)
+#endif
+
+#if HAVE_NATIVE_mpn_sqr_diag_addlsh1
+#define MPN_SQR_DIAG_ADDLSH1(rp, tp, up, n)				\
+  mpn_sqr_diag_addlsh1 (rp, tp, up, n)
+#else
+#if HAVE_NATIVE_mpn_addlsh1_n
+#define MPN_SQR_DIAG_ADDLSH1(rp, tp, up, n)				\
+  do {									\
+    mp_limb_t cy;							\
+    MPN_SQR_DIAGONAL (rp, up, n);					\
+    cy = mpn_addlsh1_n (rp + 1, rp + 1, tp, 2 * n - 2);			\
+    rp[2 * n - 1] += cy;						\
+  } while (0)
+#else
+#define MPN_SQR_DIAG_ADDLSH1(rp, tp, up, n)				\
+  do {									\
+    mp_limb_t cy;							\
+    MPN_SQR_DIAGONAL (rp, up, n);					\
+    cy = mpn_lshift (tp, tp, 2 * n - 2, 1);				\
+    cy += mpn_add_n (rp + 1, rp + 1, tp, 2 * n - 2);			\
+    rp[2 * n - 1] += cy;						\
+  } while (0)
+#endif
+#endif
+
+
+#undef READY_WITH_mpn_sqr_basecase
+
+
+#if ! defined (READY_WITH_mpn_sqr_basecase) && HAVE_NATIVE_mpn_addmul_2s
+void
+mpn_sqr_basecase (mp_ptr rp, mp_srcptr up, mp_size_t n)
+{
+  mp_size_t i;
+  mp_limb_t tarr[2 * SQR_TOOM2_THRESHOLD];
+  mp_ptr tp = tarr;
+  mp_limb_t cy;
+
+  /* must fit 2*n limbs in tarr */
+  ASSERT (n <= SQR_TOOM2_THRESHOLD);
+
+  if ((n & 1) != 0)
+    {
+      if (n == 1)
+	{
+	  mp_limb_t ul, lpl;
+	  ul = up[0];
+	  umul_ppmm (rp[1], lpl, ul, ul << GMP_NAIL_BITS);
+	  rp[0] = lpl >> GMP_NAIL_BITS;
+	  return;
+	}
+
+      MPN_ZERO (tp, n);
+
+      for (i = 0; i <= n - 2; i += 2)
+	{
+	  cy = mpn_addmul_2s (tp + 2 * i, up + i + 1, n - (i + 1), up + i);
+	  tp[n + i] = cy;
+	}
+    }
+  else
+    {
+      if (n == 2)
+	{
+#if HAVE_NATIVE_mpn_mul_2
+	  rp[3] = mpn_mul_2 (rp, up, 2, up);
+#else
+	  rp[0] = 0;
+	  rp[1] = 0;
+	  rp[3] = mpn_addmul_2 (rp, up, 2, up);
+#endif
+	  return;
+	}
+
+      MPN_ZERO (tp, n);
+
+      for (i = 0; i <= n - 4; i += 2)
+	{
+	  cy = mpn_addmul_2s (tp + 2 * i, up + i + 1, n - (i + 1), up + i);
+	  tp[n + i] = cy;
+	}
+      cy = mpn_addmul_1 (tp + 2 * n - 4, up + n - 1, 1, up[n - 2]);
+      tp[2 * n - 3] = cy;
+    }
+
+  MPN_SQR_DIAG_ADDLSH1 (rp, tp, up, n);
+}
+#define READY_WITH_mpn_sqr_basecase
+#endif
+
+
+#if ! defined (READY_WITH_mpn_sqr_basecase) && HAVE_NATIVE_mpn_addmul_2
+
+/* mpn_sqr_basecase using plain mpn_addmul_2.
+
+   This is tricky, since we have to let mpn_addmul_2 make some undesirable
+   multiplies, u[k]*u[k], that we would like to let mpn_sqr_diagonal handle.
+   This forces us to conditionally add or subtract the mpn_sqr_diagonal
+   results.  Examples of the product we form:
+
+   n = 4              n = 5		n = 6
+   u1u0 * u3u2u1      u1u0 * u4u3u2u1	u1u0 * u5u4u3u2u1
+   u2 * u3	      u3u2 * u4u3	u3u2 * u5u4u3
+					u4 * u5
+   add: u0 u2 u3      add: u0 u2 u4	add: u0 u2 u4 u5
+   sub: u1	      sub: u1 u3	sub: u1 u3
+*/
+
+void
+mpn_sqr_basecase (mp_ptr rp, mp_srcptr up, mp_size_t n)
+{
+  mp_size_t i;
+  mp_limb_t tarr[2 * SQR_TOOM2_THRESHOLD];
+  mp_ptr tp = tarr;
+  mp_limb_t cy;
+
+  /* must fit 2*n limbs in tarr */
+  ASSERT (n <= SQR_TOOM2_THRESHOLD);
+
+  if ((n & 1) != 0)
+    {
+      mp_limb_t x0, x1;
+
+      if (n == 1)
+	{
+	  mp_limb_t ul, lpl;
+	  ul = up[0];
+	  umul_ppmm (rp[1], lpl, ul, ul << GMP_NAIL_BITS);
+	  rp[0] = lpl >> GMP_NAIL_BITS;
+	  return;
+	}
+
+      /* The code below doesn't like unnormalized operands.  Since such
+	 operands are unusual, handle them with a dumb recursion.  */
+      if (up[n - 1] == 0)
+	{
+	  rp[2 * n - 2] = 0;
+	  rp[2 * n - 1] = 0;
+	  mpn_sqr_basecase (rp, up, n - 1);
+	  return;
+	}
+
+      MPN_ZERO (tp, n);
+
+      for (i = 0; i <= n - 2; i += 2)
+	{
+	  cy = mpn_addmul_2 (tp + 2 * i, up + i + 1, n - (i + 1), up + i);
+	  tp[n + i] = cy;
+	}
+
+      MPN_SQR_DIAGONAL (rp, up, n);
+
+      for (i = 2;; i += 4)
+	{
+	  x0 = rp[i + 0];
+	  rp[i + 0] = (-x0) & GMP_NUMB_MASK;
+	  x1 = rp[i + 1];
+	  rp[i + 1] = (-x1 - (x0 != 0)) & GMP_NUMB_MASK;
+	  __GMPN_SUB_1 (cy, rp + i + 2, rp + i + 2, 2, (x1 | x0) != 0);
+	  if (i + 4 >= 2 * n)
+	    break;
+	  mpn_incr_u (rp + i + 4, cy);
+	}
+    }
+  else
+    {
+      mp_limb_t x0, x1;
+
+      if (n == 2)
+	{
+#if HAVE_NATIVE_mpn_mul_2
+	  rp[3] = mpn_mul_2 (rp, up, 2, up);
+#else
+	  rp[0] = 0;
+	  rp[1] = 0;
+	  rp[3] = mpn_addmul_2 (rp, up, 2, up);
+#endif
+	  return;
+	}
+
+      /* The code below doesn't like unnormalized operands.  Since such
+	 operands are unusual, handle them with a dumb recursion.  */
+      if (up[n - 1] == 0)
+	{
+	  rp[2 * n - 2] = 0;
+	  rp[2 * n - 1] = 0;
+	  mpn_sqr_basecase (rp, up, n - 1);
+	  return;
+	}
+
+      MPN_ZERO (tp, n);
+
+      for (i = 0; i <= n - 4; i += 2)
+	{
+	  cy = mpn_addmul_2 (tp + 2 * i, up + i + 1, n - (i + 1), up + i);
+	  tp[n + i] = cy;
+	}
+      cy = mpn_addmul_1 (tp + 2 * n - 4, up + n - 1, 1, up[n - 2]);
+      tp[2 * n - 3] = cy;
+
+      MPN_SQR_DIAGONAL (rp, up, n);
+
+      for (i = 2;; i += 4)
+	{
+	  x0 = rp[i + 0];
+	  rp[i + 0] = (-x0) & GMP_NUMB_MASK;
+	  x1 = rp[i + 1];
+	  rp[i + 1] = (-x1 - (x0 != 0)) & GMP_NUMB_MASK;
+	  if (i + 6 >= 2 * n)
+	    break;
+	  __GMPN_SUB_1 (cy, rp + i + 2, rp + i + 2, 2, (x1 | x0) != 0);
+	  mpn_incr_u (rp + i + 4, cy);
+	}
+      mpn_decr_u (rp + i + 2, (x1 | x0) != 0);
+    }
+
+#if HAVE_NATIVE_mpn_addlsh1_n
+  cy = mpn_addlsh1_n (rp + 1, rp + 1, tp, 2 * n - 2);
+#else
+  cy = mpn_lshift (tp, tp, 2 * n - 2, 1);
+  cy += mpn_add_n (rp + 1, rp + 1, tp, 2 * n - 2);
+#endif
+  rp[2 * n - 1] += cy;
+}
+#define READY_WITH_mpn_sqr_basecase
+#endif
+
+
+#if ! defined (READY_WITH_mpn_sqr_basecase) && HAVE_NATIVE_mpn_sqr_diag_addlsh1
+
+/* mpn_sqr_basecase using mpn_addmul_1 and mpn_sqr_diag_addlsh1, avoiding stack
+   allocation.  */
+void
+mpn_sqr_basecase (mp_ptr rp, mp_srcptr up, mp_size_t n)
+{
+  if (n == 1)
+    {
+      mp_limb_t ul, lpl;
+      ul = up[0];
+      umul_ppmm (rp[1], lpl, ul, ul << GMP_NAIL_BITS);
+      rp[0] = lpl >> GMP_NAIL_BITS;
+    }
+  else
+    {
+      mp_size_t i;
+      mp_ptr xp;
+
+      rp += 1;
+      rp[n - 1] = mpn_mul_1 (rp, up + 1, n - 1, up[0]);
+      for (i = n - 2; i != 0; i--)
+	{
+	  up += 1;
+	  rp += 2;
+	  rp[i] = mpn_addmul_1 (rp, up + 1, i, up[0]);
+	}
+
+      xp = rp - 2 * n + 3;
+      mpn_sqr_diag_addlsh1 (xp, xp + 1, up - n + 2, n);
+    }
+}
+#define READY_WITH_mpn_sqr_basecase
+#endif
+
+
+#if ! defined (READY_WITH_mpn_sqr_basecase)
+
+/* Default mpn_sqr_basecase using mpn_addmul_1.  */
+void
+mpn_sqr_basecase (mp_ptr rp, mp_srcptr up, mp_size_t n)
+{
+  mp_size_t i;
+
+  ASSERT (n >= 1);
+  ASSERT (! MPN_OVERLAP_P (rp, 2*n, up, n));
+
+  if (n == 1)
+    {
+      mp_limb_t ul, lpl;
+      ul = up[0];
+      umul_ppmm (rp[1], lpl, ul, ul << GMP_NAIL_BITS);
+      rp[0] = lpl >> GMP_NAIL_BITS;
+    }
+  else
+    {
+      mp_limb_t tarr[2 * SQR_TOOM2_THRESHOLD];
+      mp_ptr tp = tarr;
+      mp_limb_t cy;
+
+      /* must fit 2*n limbs in tarr */
+      ASSERT (n <= SQR_TOOM2_THRESHOLD);
+
+      cy = mpn_mul_1 (tp, up + 1, n - 1, up[0]);
+      tp[n - 1] = cy;
+      for (i = 2; i < n; i++)
+	{
+	  mp_limb_t cy;
+	  cy = mpn_addmul_1 (tp + 2 * i - 2, up + i, n - i, up[i - 1]);
+	  tp[n + i - 2] = cy;
+	}
+
+      MPN_SQR_DIAG_ADDLSH1 (rp, tp, up, n);
+    }
+}
+#define READY_WITH_mpn_sqr_basecase
+#endif
diff --git a/third_party/gmp/mpn/generic/sqrlo.c b/third_party/gmp/mpn/generic/sqrlo.c
new file mode 100644
index 0000000..71530b6
--- /dev/null
+++ b/third_party/gmp/mpn/generic/sqrlo.c
@@ -0,0 +1,239 @@
+/* mpn_sqrlo -- squares an n-limb number and returns the low n limbs
+   of the result.
+
+   Contributed to the GNU project by Torbjorn Granlund and Marco Bodrato.
+
+   THIS IS (FOR NOW) AN INTERNAL FUNCTION.  IT IS ONLY SAFE TO REACH THIS
+   FUNCTION THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST GUARANTEED
+   THAT IT'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2004, 2005, 2009, 2010, 2012, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#if TUNE_PROGRAM_BUILD || WANT_FAT_BINARY
+#define MAYBE_range_basecase 1
+#define MAYBE_range_toom22   1
+#else
+#define MAYBE_range_basecase                                           \
+  ((SQRLO_DC_THRESHOLD == 0 ? SQRLO_BASECASE_THRESHOLD : SQRLO_DC_THRESHOLD) < SQR_TOOM2_THRESHOLD*36/(36-11))
+#define MAYBE_range_toom22                                             \
+  ((SQRLO_DC_THRESHOLD == 0 ? SQRLO_BASECASE_THRESHOLD : SQRLO_DC_THRESHOLD) < SQR_TOOM3_THRESHOLD*36/(36-11) )
+#endif
+
+/*  THINK: The DC strategy uses different constants in different Toom's
+	 ranges. Something smoother?
+*/
+
+/*
+  Compute the least significant half of the product {xy,n}*{yp,n}, or
+  formally {rp,n} = {xy,n}*{yp,n} Mod (B^n).
+
+  Above the given threshold, the Divide and Conquer strategy is used.
+  The operand is split in two, and a full square plus a mullo
+  is used to obtain the final result. The more natural strategy is to
+  split in two halves, but this is far from optimal when a
+  sub-quadratic multiplication is used.
+
+  Mulders suggests an unbalanced split in favour of the full product,
+  split n = n1 + n2, where an = n1 <= n2 = (1-a)n; i.e. 0 < a <= 1/2.
+
+  To compute the value of a, we assume that the cost of mullo for a
+  given size ML(n) is a fraction of the cost of a full product with
+  same size M(n), and the cost M(n)=n^e for some exponent 1 < e <= 2;
+  then we can write:
+
+  ML(n) = 2*ML(an) + M((1-a)n) => k*M(n) = 2*k*M(n)*a^e + M(n)*(1-a)^e
+
+  Given a value for e, want to minimise the value of k, i.e. the
+  function k=(1-a)^e/(1-2*a^e).
+
+  With e=2, the exponent for schoolbook multiplication, the minimum is
+  given by the values a=1-a=1/2.
+
+  With e=log(3)/log(2), the exponent for Karatsuba (aka toom22),
+  Mulders compute (1-a) = 0.694... and we approximate a with 11/36.
+
+  Other possible approximations follow:
+  e=log(5)/log(3) [Toom-3] -> a ~= 9/40
+  e=log(7)/log(4) [Toom-4] -> a ~= 7/39
+  e=log(11)/log(6) [Toom-6] -> a ~= 1/8
+  e=log(15)/log(8) [Toom-8] -> a ~= 1/10
+
+  The values above where obtained with the following trivial commands
+  in the gp-pari shell:
+
+fun(e,a)=(1-a)^e/(1-2*a^e)
+mul(a,b,c)={local(m,x,p);if(b-c<1/10000,(b+c)/2,m=1;x=b;forstep(p=c,b,(b-c)/8,if(fun(a,p)<m,m=fun(a,p);x=p));mul(a,(b+x)/2,(c+x)/2))}
+contfracpnqn(contfrac(mul(log(2*2-1)/log(2),1/2,0),5))
+contfracpnqn(contfrac(mul(log(3*2-1)/log(3),1/2,0),5))
+contfracpnqn(contfrac(mul(log(4*2-1)/log(4),1/2,0),5))
+contfracpnqn(contfrac(mul(log(6*2-1)/log(6),1/2,0),3))
+contfracpnqn(contfrac(mul(log(8*2-1)/log(8),1/2,0),3))
+
+  ,
+  |\
+  | \
+  +----,
+  |    |
+  |    |
+  |    |\
+  |    | \
+  +----+--`
+  ^ n2 ^n1^
+
+  For an actual implementation, the assumption that M(n)=n^e is
+  incorrect, as a consequence also the assumption that ML(n)=k*M(n)
+  with a constant k is wrong.
+
+  But theory suggest us two things:
+  - the best the multiplication product is (lower e), the more k
+    approaches 1, and a approaches 0.
+
+  - A value for a smaller than optimal is probably less bad than a
+    bigger one: e.g. let e=log(3)/log(2), a=0.3058_ the optimal
+    value, and k(a)=0.808_ the mul/mullo speed ratio. We get
+    k(a+1/6)=0.929_ but k(a-1/6)=0.865_.
+*/
+
+static mp_size_t
+mpn_sqrlo_itch (mp_size_t n)
+{
+  return 2*n;
+}
+
+/*
+    mpn_dc_sqrlo requires a scratch space of 2*n limbs at tp.
+    It accepts tp == rp.
+*/
+static void
+mpn_dc_sqrlo (mp_ptr rp, mp_srcptr xp, mp_size_t n, mp_ptr tp)
+{
+  mp_size_t n2, n1;
+  ASSERT (n >= 2);
+  ASSERT (! MPN_OVERLAP_P (rp, n, xp, n));
+  ASSERT (MPN_SAME_OR_SEPARATE2_P(rp, n, tp, 2*n));
+
+  /* Divide-and-conquer */
+
+  /* We need fractional approximation of the value 0 < a <= 1/2
+     giving the minimum in the function k=(1-a)^e/(1-2*a^e).
+  */
+  if (MAYBE_range_basecase && BELOW_THRESHOLD (n, SQR_TOOM2_THRESHOLD*36/(36-11)))
+    n1 = n >> 1;
+  else if (MAYBE_range_toom22 && BELOW_THRESHOLD (n, SQR_TOOM3_THRESHOLD*36/(36-11)))
+    n1 = n * 11 / (size_t) 36;	/* n1 ~= n*(1-.694...) */
+  else if (BELOW_THRESHOLD (n, SQR_TOOM4_THRESHOLD*40/(40-9)))
+    n1 = n * 9 / (size_t) 40;	/* n1 ~= n*(1-.775...) */
+  else if (BELOW_THRESHOLD (n, SQR_TOOM8_THRESHOLD*10/9))
+    n1 = n * 7 / (size_t) 39;	/* n1 ~= n*(1-.821...) */
+  /* n1 = n * 4 / (size_t) 31;	// n1 ~= n*(1-.871...) [TOOM66] */
+  else
+    n1 = n / (size_t) 10;		/* n1 ~= n*(1-.899...) [TOOM88] */
+
+  n2 = n - n1;
+
+  /* Split as x = x1 2^(n2 GMP_NUMB_BITS) + x0 */
+
+  /* x0 ^ 2 */
+  mpn_sqr (tp, xp, n2);
+  MPN_COPY (rp, tp, n2);
+
+  /* x1 * x0 * 2^(n2 GMP_NUMB_BITS) */
+  if (BELOW_THRESHOLD (n1, MULLO_BASECASE_THRESHOLD))
+    mpn_mul_basecase (tp + n, xp + n2, n1, xp, n1);
+  else if (BELOW_THRESHOLD (n1, MULLO_DC_THRESHOLD))
+    mpn_mullo_basecase (tp + n, xp + n2, xp, n1);
+  else
+    mpn_mullo_n (tp + n, xp + n2, xp, n1);
+  /* mpn_dc_mullo_n (tp + n, xp + n2, xp, n1, tp + n); */
+#if HAVE_NATIVE_mpn_addlsh1_n
+  mpn_addlsh1_n (rp + n2, tp + n2, tp + n, n1);
+#else
+  mpn_lshift (rp + n2, tp + n, n1, 1);
+  mpn_add_n (rp + n2, rp + n2, tp + n2, n1);
+#endif
+}
+
+/* Avoid zero allocations when MULLO_BASECASE_THRESHOLD is 0.  */
+#define SQR_BASECASE_ALLOC \
+ (SQRLO_BASECASE_THRESHOLD_LIMIT == 0 ? 1 : 2*SQRLO_BASECASE_THRESHOLD_LIMIT)
+
+/* FIXME: This function should accept a temporary area; dc_sqrlo
+   accepts a pointer tp, and handle the case tp == rp, do the same here.
+*/
+
+void
+mpn_sqrlo (mp_ptr rp, mp_srcptr xp, mp_size_t n)
+{
+  ASSERT (n >= 1);
+  ASSERT (! MPN_OVERLAP_P (rp, n, xp, n));
+
+  if (BELOW_THRESHOLD (n, SQRLO_BASECASE_THRESHOLD))
+    {
+      /* FIXME: smarter criteria? */
+#if HAVE_NATIVE_mpn_mullo_basecase || ! HAVE_NATIVE_mpn_sqr_basecase
+      /* mullo computes as many products as sqr, but directly writes
+	 on the result area. */
+      mpn_mullo_basecase (rp, xp, xp, n);
+#else
+      /* Allocate workspace of fixed size on stack: fast! */
+      mp_limb_t tp[SQR_BASECASE_ALLOC];
+      mpn_sqr_basecase (tp, xp, n);
+      MPN_COPY (rp, tp, n);
+#endif
+    }
+  else if (BELOW_THRESHOLD (n, SQRLO_DC_THRESHOLD))
+    {
+      mpn_sqrlo_basecase (rp, xp, n);
+    }
+  else
+    {
+      mp_ptr tp;
+      TMP_DECL;
+      TMP_MARK;
+      tp = TMP_ALLOC_LIMBS (mpn_sqrlo_itch (n));
+      if (BELOW_THRESHOLD (n, SQRLO_SQR_THRESHOLD))
+	{
+	  mpn_dc_sqrlo (rp, xp, n, tp);
+	}
+      else
+	{
+	  /* For really large operands, use plain mpn_mul_n but throw away upper n
+	     limbs of result.  */
+#if !TUNE_PROGRAM_BUILD && (SQRLO_SQR_THRESHOLD > SQR_FFT_THRESHOLD)
+	  mpn_fft_mul (tp, xp, n, xp, n);
+#else
+	  mpn_sqr (tp, xp, n);
+#endif
+	  MPN_COPY (rp, tp, n);
+	}
+      TMP_FREE;
+    }
+}
diff --git a/third_party/gmp/mpn/generic/sqrlo_basecase.c b/third_party/gmp/mpn/generic/sqrlo_basecase.c
new file mode 100644
index 0000000..3148609
--- /dev/null
+++ b/third_party/gmp/mpn/generic/sqrlo_basecase.c
@@ -0,0 +1,194 @@
+/* mpn_sqrlo_basecase -- Internal routine to square a natural number
+   of length n.
+
+   THIS IS AN INTERNAL FUNCTION WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH THIS FUNCTION THROUGH DOCUMENTED INTERFACES.
+
+
+Copyright 1991-1994, 1996, 1997, 2000-2005, 2008, 2010, 2011, 2015,
+2016 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#ifndef SQRLO_SHORTCUT_MULTIPLICATIONS
+#if HAVE_NATIVE_mpn_addmul_1
+#define SQRLO_SHORTCUT_MULTIPLICATIONS 0
+#else
+#define SQRLO_SHORTCUT_MULTIPLICATIONS 1
+#endif
+#endif
+
+#if HAVE_NATIVE_mpn_sqr_diagonal
+#define MPN_SQR_DIAGONAL(rp, up, n)					\
+  mpn_sqr_diagonal (rp, up, n)
+#else
+#define MPN_SQR_DIAGONAL(rp, up, n)					\
+  do {									\
+    mp_size_t _i;							\
+    for (_i = 0; _i < (n); _i++)					\
+      {									\
+	mp_limb_t ul, lpl;						\
+	ul = (up)[_i];							\
+	umul_ppmm ((rp)[2 * _i + 1], lpl, ul, ul << GMP_NAIL_BITS);	\
+	(rp)[2 * _i] = lpl >> GMP_NAIL_BITS;				\
+      }									\
+  } while (0)
+#endif
+
+#define MPN_SQRLO_DIAGONAL(rp, up, n)					\
+  do {									\
+    mp_size_t nhalf;							\
+    nhalf = (n) >> 1;							\
+    MPN_SQR_DIAGONAL ((rp), (up), nhalf);				\
+    if (((n) & 1) != 0)							\
+      {									\
+	mp_limb_t op;							\
+	op = (up)[nhalf];						\
+	(rp)[(n) - 1] = (op * op) & GMP_NUMB_MASK;			\
+      }									\
+  } while (0)
+
+#if HAVE_NATIVE_mpn_addlsh1_n_ip1
+#define MPN_SQRLO_DIAG_ADDLSH1(rp, tp, up, n)				\
+  do {									\
+    MPN_SQRLO_DIAGONAL((rp), (up), (n));				\
+    mpn_addlsh1_n_ip1 ((rp) + 1, (tp), (n) - 1);			\
+  } while (0)
+#else
+#define MPN_SQRLO_DIAG_ADDLSH1(rp, tp, up, n)				\
+  do {									\
+    MPN_SQRLO_DIAGONAL((rp), (up), (n));				\
+    mpn_lshift ((tp), (tp), (n) - 1, 1);				\
+    mpn_add_n ((rp) + 1, (rp) + 1, (tp), (n) - 1);			\
+  } while (0)
+#endif
+
+/* Avoid zero allocations when SQRLO_LO_THRESHOLD is 0 (this code not used). */
+#define SQRLO_BASECASE_ALLOC						\
+  (SQRLO_DC_THRESHOLD_LIMIT < 2 ? 1 : SQRLO_DC_THRESHOLD_LIMIT - 1)
+
+/* Default mpn_sqrlo_basecase using mpn_addmul_1.  */
+#ifndef SQRLO_SPECIAL_CASES
+#define SQRLO_SPECIAL_CASES 2
+#endif
+
+#if TUNE_PROGRAM_BUILD || WANT_FAT_BINARY
+#define MAYBE_special_cases 1
+#else
+#define MAYBE_special_cases \
+  ((SQRLO_BASECASE_THRESHOLD <= SQRLO_SPECIAL_CASES) && (SQRLO_DC_THRESHOLD != 0))
+#endif
+
+void
+mpn_sqrlo_basecase (mp_ptr rp, mp_srcptr up, mp_size_t n)
+{
+  mp_limb_t ul;
+
+  ASSERT (n >= 1);
+  ASSERT (! MPN_OVERLAP_P (rp, n, up, n));
+
+  ul = up[0];
+
+  if (MAYBE_special_cases && n <= SQRLO_SPECIAL_CASES)
+    {
+#if SQRLO_SPECIAL_CASES == 1
+      rp[0] = (ul * ul) & GMP_NUMB_MASK;
+#else
+      if (n == 1)
+	rp[0] = (ul * ul) & GMP_NUMB_MASK;
+      else
+	{
+	  mp_limb_t hi, lo, ul1;
+	  umul_ppmm (hi, lo, ul, ul << GMP_NAIL_BITS);
+	  rp[0] = lo >> GMP_NAIL_BITS;
+	  ul1 = up[1];
+#if SQRLO_SPECIAL_CASES == 2
+	  rp[1] = (hi + ul * ul1 * 2) & GMP_NUMB_MASK;
+#else
+	  if (n == 2)
+	    rp[1] = (hi + ul * ul1 * 2) & GMP_NUMB_MASK;
+	  else
+	    {
+	      mp_limb_t hi1;
+#if GMP_NAIL_BITS != 0
+	      ul <<= 1;
+#endif
+	      umul_ppmm (hi1, lo, ul1 << GMP_NAIL_BITS, ul);
+	      hi1 += ul * up[2];
+#if GMP_NAIL_BITS == 0
+	      hi1 = (hi1 << 1) | (lo >> (GMP_LIMB_BITS - 1));
+	      add_ssaaaa(rp[2], rp[1], hi1, lo << 1, ul1 * ul1, hi);
+#else
+	      hi += lo >> GMP_NAIL_BITS;
+	      rp[1] = hi & GMP_NUMB_MASK;
+	      rp[2] = (hi1 + ul1 * ul1 + (hi >> GMP_NUMB_BITS)) & GMP_NUMB_MASK;
+#endif
+	    }
+#endif
+	}
+#endif
+    }
+  else
+    {
+      mp_limb_t tp[SQRLO_BASECASE_ALLOC];
+      mp_size_t i;
+
+      /* must fit n-1 limbs in tp */
+      ASSERT (n <= SQRLO_DC_THRESHOLD_LIMIT);
+
+      --n;
+#if SQRLO_SHORTCUT_MULTIPLICATIONS
+      {
+	mp_limb_t cy;
+
+	cy = ul * up[n] + mpn_mul_1 (tp, up + 1, n - 1, ul);
+	for (i = 1; 2 * i + 1 < n; ++i)
+	  {
+	    ul = up[i];
+	    cy += ul * up[n - i] + mpn_addmul_1 (tp + 2 * i, up + i + 1, n - 2 * i - 1, ul);
+	  }
+	tp [n-1] = (cy + ((n & 1)?up[i] * up[i + 1]:0)) & GMP_NUMB_MASK;
+      }
+#else
+      mpn_mul_1 (tp, up + 1, n, ul);
+      for (i = 1; 2 * i < n; ++i)
+	mpn_addmul_1 (tp + 2 * i, up + i + 1, n - 2 * i, up[i]);
+#endif
+
+      MPN_SQRLO_DIAG_ADDLSH1 (rp, tp, up, n + 1);
+    }
+}
+#undef SQRLO_SPECIAL_CASES
+#undef MAYBE_special_cases
+#undef SQRLO_BASECASE_ALLOC
+#undef SQRLO_SHORTCUT_MULTIPLICATIONS
+#undef MPN_SQR_DIAGONAL
+#undef MPN_SQRLO_DIAGONAL
+#undef MPN_SQRLO_DIAG_ADDLSH1
diff --git a/third_party/gmp/mpn/generic/sqrmod_bnm1.c b/third_party/gmp/mpn/generic/sqrmod_bnm1.c
new file mode 100644
index 0000000..0a27d7b
--- /dev/null
+++ b/third_party/gmp/mpn/generic/sqrmod_bnm1.c
@@ -0,0 +1,312 @@
+/* sqrmod_bnm1.c -- squaring mod B^n-1.
+
+   Contributed to the GNU project by Niels Möller, Torbjorn Granlund and
+   Marco Bodrato.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009, 2010, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/* Input is {ap,rn}; output is {rp,rn}, computation is
+   mod B^rn - 1, and values are semi-normalised; zero is represented
+   as either 0 or B^n - 1.  Needs a scratch of 2rn limbs at tp.
+   tp==rp is allowed. */
+static void
+mpn_bc_sqrmod_bnm1 (mp_ptr rp, mp_srcptr ap, mp_size_t rn, mp_ptr tp)
+{
+  mp_limb_t cy;
+
+  ASSERT (0 < rn);
+
+  mpn_sqr (tp, ap, rn);
+  cy = mpn_add_n (rp, tp, tp + rn, rn);
+  /* If cy == 1, then the value of rp is at most B^rn - 2, so there can
+   * be no overflow when adding in the carry. */
+  MPN_INCR_U (rp, rn, cy);
+}
+
+
+/* Input is {ap,rn+1}; output is {rp,rn+1}, in
+   semi-normalised representation, computation is mod B^rn + 1. Needs
+   a scratch area of 2rn + 2 limbs at tp; tp == rp is allowed.
+   Output is normalised. */
+static void
+mpn_bc_sqrmod_bnp1 (mp_ptr rp, mp_srcptr ap, mp_size_t rn, mp_ptr tp)
+{
+  mp_limb_t cy;
+
+  ASSERT (0 < rn);
+
+  mpn_sqr (tp, ap, rn + 1);
+  ASSERT (tp[2*rn+1] == 0);
+  ASSERT (tp[2*rn] < GMP_NUMB_MAX);
+  cy = tp[2*rn] + mpn_sub_n (rp, tp, tp+rn, rn);
+  rp[rn] = 0;
+  MPN_INCR_U (rp, rn+1, cy);
+}
+
+
+/* Computes {rp,MIN(rn,2an)} <- {ap,an}^2 Mod(B^rn-1)
+ *
+ * The result is expected to be ZERO if and only if the operand
+ * already is. Otherwise the class [0] Mod(B^rn-1) is represented by
+ * B^rn-1.
+ * It should not be a problem if sqrmod_bnm1 is used to
+ * compute the full square with an <= 2*rn, because this condition
+ * implies (B^an-1)^2 < (B^rn-1) .
+ *
+ * Requires rn/4 < an <= rn
+ * Scratch need: rn/2 + (need for recursive call OR rn + 3). This gives
+ *
+ * S(n) <= rn/2 + MAX (rn + 4, S(n/2)) <= 3/2 rn + 4
+ */
+void
+mpn_sqrmod_bnm1 (mp_ptr rp, mp_size_t rn, mp_srcptr ap, mp_size_t an, mp_ptr tp)
+{
+  ASSERT (0 < an);
+  ASSERT (an <= rn);
+
+  if ((rn & 1) != 0 || BELOW_THRESHOLD (rn, SQRMOD_BNM1_THRESHOLD))
+    {
+      if (UNLIKELY (an < rn))
+	{
+	  if (UNLIKELY (2*an <= rn))
+	    {
+	      mpn_sqr (rp, ap, an);
+	    }
+	  else
+	    {
+	      mp_limb_t cy;
+	      mpn_sqr (tp, ap, an);
+	      cy = mpn_add (rp, tp, rn, tp + rn, 2*an - rn);
+	      MPN_INCR_U (rp, rn, cy);
+	    }
+	}
+      else
+	mpn_bc_sqrmod_bnm1 (rp, ap, rn, tp);
+    }
+  else
+    {
+      mp_size_t n;
+      mp_limb_t cy;
+      mp_limb_t hi;
+
+      n = rn >> 1;
+
+      ASSERT (2*an > n);
+
+      /* Compute xm = a^2 mod (B^n - 1), xp = a^2 mod (B^n + 1)
+	 and crt together as
+
+	 x = -xp * B^n + (B^n + 1) * [ (xp + xm)/2 mod (B^n-1)]
+      */
+
+#define a0 ap
+#define a1 (ap + n)
+
+#define xp  tp	/* 2n + 2 */
+      /* am1  maybe in {xp, n} */
+#define sp1 (tp + 2*n + 2)
+      /* ap1  maybe in {sp1, n + 1} */
+
+      {
+	mp_srcptr am1;
+	mp_size_t anm;
+	mp_ptr so;
+
+	if (LIKELY (an > n))
+	  {
+	    so = xp + n;
+	    am1 = xp;
+	    cy = mpn_add (xp, a0, n, a1, an - n);
+	    MPN_INCR_U (xp, n, cy);
+	    anm = n;
+	  }
+	else
+	  {
+	    so = xp;
+	    am1 = a0;
+	    anm = an;
+	  }
+
+	mpn_sqrmod_bnm1 (rp, n, am1, anm, so);
+      }
+
+      {
+	int       k;
+	mp_srcptr ap1;
+	mp_size_t anp;
+
+	if (LIKELY (an > n)) {
+	  ap1 = sp1;
+	  cy = mpn_sub (sp1, a0, n, a1, an - n);
+	  sp1[n] = 0;
+	  MPN_INCR_U (sp1, n + 1, cy);
+	  anp = n + ap1[n];
+	} else {
+	  ap1 = a0;
+	  anp = an;
+	}
+
+	if (BELOW_THRESHOLD (n, MUL_FFT_MODF_THRESHOLD))
+	  k=0;
+	else
+	  {
+	    int mask;
+	    k = mpn_fft_best_k (n, 1);
+	    mask = (1<<k) -1;
+	    while (n & mask) {k--; mask >>=1;};
+	  }
+	if (k >= FFT_FIRST_K)
+	  xp[n] = mpn_mul_fft (xp, n, ap1, anp, ap1, anp, k);
+	else if (UNLIKELY (ap1 == a0))
+	  {
+	    ASSERT (anp <= n);
+	    ASSERT (2*anp > n);
+	    mpn_sqr (xp, a0, an);
+	    anp = 2*an - n;
+	    cy = mpn_sub (xp, xp, n, xp + n, anp);
+	    xp[n] = 0;
+	    MPN_INCR_U (xp, n+1, cy);
+	  }
+	else
+	  mpn_bc_sqrmod_bnp1 (xp, ap1, n, xp);
+      }
+
+      /* Here the CRT recomposition begins.
+
+	 xm <- (xp + xm)/2 = (xp + xm)B^n/2 mod (B^n-1)
+	 Division by 2 is a bitwise rotation.
+
+	 Assumes xp normalised mod (B^n+1).
+
+	 The residue class [0] is represented by [B^n-1]; except when
+	 both input are ZERO.
+      */
+
+#if HAVE_NATIVE_mpn_rsh1add_n || HAVE_NATIVE_mpn_rsh1add_nc
+#if HAVE_NATIVE_mpn_rsh1add_nc
+      cy = mpn_rsh1add_nc(rp, rp, xp, n, xp[n]); /* B^n = 1 */
+      hi = cy << (GMP_NUMB_BITS - 1);
+      cy = 0;
+      /* next update of rp[n-1] will set cy = 1 only if rp[n-1]+=hi
+	 overflows, i.e. a further increment will not overflow again. */
+#else /* ! _nc */
+      cy = xp[n] + mpn_rsh1add_n(rp, rp, xp, n); /* B^n = 1 */
+      hi = (cy<<(GMP_NUMB_BITS-1))&GMP_NUMB_MASK; /* (cy&1) << ... */
+      cy >>= 1;
+      /* cy = 1 only if xp[n] = 1 i.e. {xp,n} = ZERO, this implies that
+	 the rsh1add was a simple rshift: the top bit is 0. cy=1 => hi=0. */
+#endif
+#if GMP_NAIL_BITS == 0
+      add_ssaaaa(cy, rp[n-1], cy, rp[n-1], CNST_LIMB(0), hi);
+#else
+      cy += (hi & rp[n-1]) >> (GMP_NUMB_BITS-1);
+      rp[n-1] ^= hi;
+#endif
+#else /* ! HAVE_NATIVE_mpn_rsh1add_n */
+#if HAVE_NATIVE_mpn_add_nc
+      cy = mpn_add_nc(rp, rp, xp, n, xp[n]);
+#else /* ! _nc */
+      cy = xp[n] + mpn_add_n(rp, rp, xp, n); /* xp[n] == 1 implies {xp,n} == ZERO */
+#endif
+      cy += (rp[0]&1);
+      mpn_rshift(rp, rp, n, 1);
+      ASSERT (cy <= 2);
+      hi = (cy<<(GMP_NUMB_BITS-1))&GMP_NUMB_MASK; /* (cy&1) << ... */
+      cy >>= 1;
+      /* We can have cy != 0 only if hi = 0... */
+      ASSERT ((rp[n-1] & GMP_NUMB_HIGHBIT) == 0);
+      rp[n-1] |= hi;
+      /* ... rp[n-1] + cy can not overflow, the following INCR is correct. */
+#endif
+      ASSERT (cy <= 1);
+      /* Next increment can not overflow, read the previous comments about cy. */
+      ASSERT ((cy == 0) || ((rp[n-1] & GMP_NUMB_HIGHBIT) == 0));
+      MPN_INCR_U(rp, n, cy);
+
+      /* Compute the highest half:
+	 ([(xp + xm)/2 mod (B^n-1)] - xp ) * B^n
+       */
+      if (UNLIKELY (2*an < rn))
+	{
+	  /* Note that in this case, the only way the result can equal
+	     zero mod B^{rn} - 1 is if the input is zero, and
+	     then the output of both the recursive calls and this CRT
+	     reconstruction is zero, not B^{rn} - 1. */
+	  cy = mpn_sub_n (rp + n, rp, xp, 2*an - n);
+
+	  /* FIXME: This subtraction of the high parts is not really
+	     necessary, we do it to get the carry out, and for sanity
+	     checking. */
+	  cy = xp[n] + mpn_sub_nc (xp + 2*an - n, rp + 2*an - n,
+				   xp + 2*an - n, rn - 2*an, cy);
+	  ASSERT (mpn_zero_p (xp + 2*an - n+1, rn - 1 - 2*an));
+	  cy = mpn_sub_1 (rp, rp, 2*an, cy);
+	  ASSERT (cy == (xp + 2*an - n)[0]);
+	}
+      else
+	{
+	  cy = xp[n] + mpn_sub_n (rp + n, rp, xp, n);
+	  /* cy = 1 only if {xp,n+1} is not ZERO, i.e. {rp,n} is not ZERO.
+	     DECR will affect _at most_ the lowest n limbs. */
+	  MPN_DECR_U (rp, 2*n, cy);
+	}
+#undef a0
+#undef a1
+#undef xp
+#undef sp1
+    }
+}
+
+mp_size_t
+mpn_sqrmod_bnm1_next_size (mp_size_t n)
+{
+  mp_size_t nh;
+
+  if (BELOW_THRESHOLD (n,     SQRMOD_BNM1_THRESHOLD))
+    return n;
+  if (BELOW_THRESHOLD (n, 4 * (SQRMOD_BNM1_THRESHOLD - 1) + 1))
+    return (n + (2-1)) & (-2);
+  if (BELOW_THRESHOLD (n, 8 * (SQRMOD_BNM1_THRESHOLD - 1) + 1))
+    return (n + (4-1)) & (-4);
+
+  nh = (n + 1) >> 1;
+
+  if (BELOW_THRESHOLD (nh, SQR_FFT_MODF_THRESHOLD))
+    return (n + (8-1)) & (-8);
+
+  return 2 * mpn_fft_next_size (nh, mpn_fft_best_k (nh, 1));
+}
diff --git a/third_party/gmp/mpn/generic/sqrtrem.c b/third_party/gmp/mpn/generic/sqrtrem.c
new file mode 100644
index 0000000..cc6dd9c
--- /dev/null
+++ b/third_party/gmp/mpn/generic/sqrtrem.c
@@ -0,0 +1,555 @@
+/* mpn_sqrtrem -- square root and remainder
+
+   Contributed to the GNU project by Paul Zimmermann (most code),
+   Torbjorn Granlund (mpn_sqrtrem1) and Marco Bodrato (mpn_dc_sqrt).
+
+   THE FUNCTIONS IN THIS FILE EXCEPT mpn_sqrtrem ARE INTERNAL WITH MUTABLE
+   INTERFACES.  IT IS ONLY SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.
+   IN FACT, IT IS ALMOST GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A
+   FUTURE GMP RELEASE.
+
+Copyright 1999-2002, 2004, 2005, 2008, 2010, 2012, 2015, 2017 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+/* See "Karatsuba Square Root", reference in gmp.texi.  */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "longlong.h"
+#define USE_DIVAPPR_Q 1
+#define TRACE(x)
+
+static const unsigned char invsqrttab[384] = /* The common 0x100 was removed */
+{
+  0xff,0xfd,0xfb,0xf9,0xf7,0xf5,0xf3,0xf2, /* sqrt(1/80)..sqrt(1/87) */
+  0xf0,0xee,0xec,0xea,0xe9,0xe7,0xe5,0xe4, /* sqrt(1/88)..sqrt(1/8f) */
+  0xe2,0xe0,0xdf,0xdd,0xdb,0xda,0xd8,0xd7, /* sqrt(1/90)..sqrt(1/97) */
+  0xd5,0xd4,0xd2,0xd1,0xcf,0xce,0xcc,0xcb, /* sqrt(1/98)..sqrt(1/9f) */
+  0xc9,0xc8,0xc6,0xc5,0xc4,0xc2,0xc1,0xc0, /* sqrt(1/a0)..sqrt(1/a7) */
+  0xbe,0xbd,0xbc,0xba,0xb9,0xb8,0xb7,0xb5, /* sqrt(1/a8)..sqrt(1/af) */
+  0xb4,0xb3,0xb2,0xb0,0xaf,0xae,0xad,0xac, /* sqrt(1/b0)..sqrt(1/b7) */
+  0xaa,0xa9,0xa8,0xa7,0xa6,0xa5,0xa4,0xa3, /* sqrt(1/b8)..sqrt(1/bf) */
+  0xa2,0xa0,0x9f,0x9e,0x9d,0x9c,0x9b,0x9a, /* sqrt(1/c0)..sqrt(1/c7) */
+  0x99,0x98,0x97,0x96,0x95,0x94,0x93,0x92, /* sqrt(1/c8)..sqrt(1/cf) */
+  0x91,0x90,0x8f,0x8e,0x8d,0x8c,0x8c,0x8b, /* sqrt(1/d0)..sqrt(1/d7) */
+  0x8a,0x89,0x88,0x87,0x86,0x85,0x84,0x83, /* sqrt(1/d8)..sqrt(1/df) */
+  0x83,0x82,0x81,0x80,0x7f,0x7e,0x7e,0x7d, /* sqrt(1/e0)..sqrt(1/e7) */
+  0x7c,0x7b,0x7a,0x79,0x79,0x78,0x77,0x76, /* sqrt(1/e8)..sqrt(1/ef) */
+  0x76,0x75,0x74,0x73,0x72,0x72,0x71,0x70, /* sqrt(1/f0)..sqrt(1/f7) */
+  0x6f,0x6f,0x6e,0x6d,0x6d,0x6c,0x6b,0x6a, /* sqrt(1/f8)..sqrt(1/ff) */
+  0x6a,0x69,0x68,0x68,0x67,0x66,0x66,0x65, /* sqrt(1/100)..sqrt(1/107) */
+  0x64,0x64,0x63,0x62,0x62,0x61,0x60,0x60, /* sqrt(1/108)..sqrt(1/10f) */
+  0x5f,0x5e,0x5e,0x5d,0x5c,0x5c,0x5b,0x5a, /* sqrt(1/110)..sqrt(1/117) */
+  0x5a,0x59,0x59,0x58,0x57,0x57,0x56,0x56, /* sqrt(1/118)..sqrt(1/11f) */
+  0x55,0x54,0x54,0x53,0x53,0x52,0x52,0x51, /* sqrt(1/120)..sqrt(1/127) */
+  0x50,0x50,0x4f,0x4f,0x4e,0x4e,0x4d,0x4d, /* sqrt(1/128)..sqrt(1/12f) */
+  0x4c,0x4b,0x4b,0x4a,0x4a,0x49,0x49,0x48, /* sqrt(1/130)..sqrt(1/137) */
+  0x48,0x47,0x47,0x46,0x46,0x45,0x45,0x44, /* sqrt(1/138)..sqrt(1/13f) */
+  0x44,0x43,0x43,0x42,0x42,0x41,0x41,0x40, /* sqrt(1/140)..sqrt(1/147) */
+  0x40,0x3f,0x3f,0x3e,0x3e,0x3d,0x3d,0x3c, /* sqrt(1/148)..sqrt(1/14f) */
+  0x3c,0x3b,0x3b,0x3a,0x3a,0x39,0x39,0x39, /* sqrt(1/150)..sqrt(1/157) */
+  0x38,0x38,0x37,0x37,0x36,0x36,0x35,0x35, /* sqrt(1/158)..sqrt(1/15f) */
+  0x35,0x34,0x34,0x33,0x33,0x32,0x32,0x32, /* sqrt(1/160)..sqrt(1/167) */
+  0x31,0x31,0x30,0x30,0x2f,0x2f,0x2f,0x2e, /* sqrt(1/168)..sqrt(1/16f) */
+  0x2e,0x2d,0x2d,0x2d,0x2c,0x2c,0x2b,0x2b, /* sqrt(1/170)..sqrt(1/177) */
+  0x2b,0x2a,0x2a,0x29,0x29,0x29,0x28,0x28, /* sqrt(1/178)..sqrt(1/17f) */
+  0x27,0x27,0x27,0x26,0x26,0x26,0x25,0x25, /* sqrt(1/180)..sqrt(1/187) */
+  0x24,0x24,0x24,0x23,0x23,0x23,0x22,0x22, /* sqrt(1/188)..sqrt(1/18f) */
+  0x21,0x21,0x21,0x20,0x20,0x20,0x1f,0x1f, /* sqrt(1/190)..sqrt(1/197) */
+  0x1f,0x1e,0x1e,0x1e,0x1d,0x1d,0x1d,0x1c, /* sqrt(1/198)..sqrt(1/19f) */
+  0x1c,0x1b,0x1b,0x1b,0x1a,0x1a,0x1a,0x19, /* sqrt(1/1a0)..sqrt(1/1a7) */
+  0x19,0x19,0x18,0x18,0x18,0x18,0x17,0x17, /* sqrt(1/1a8)..sqrt(1/1af) */
+  0x17,0x16,0x16,0x16,0x15,0x15,0x15,0x14, /* sqrt(1/1b0)..sqrt(1/1b7) */
+  0x14,0x14,0x13,0x13,0x13,0x12,0x12,0x12, /* sqrt(1/1b8)..sqrt(1/1bf) */
+  0x12,0x11,0x11,0x11,0x10,0x10,0x10,0x0f, /* sqrt(1/1c0)..sqrt(1/1c7) */
+  0x0f,0x0f,0x0f,0x0e,0x0e,0x0e,0x0d,0x0d, /* sqrt(1/1c8)..sqrt(1/1cf) */
+  0x0d,0x0c,0x0c,0x0c,0x0c,0x0b,0x0b,0x0b, /* sqrt(1/1d0)..sqrt(1/1d7) */
+  0x0a,0x0a,0x0a,0x0a,0x09,0x09,0x09,0x09, /* sqrt(1/1d8)..sqrt(1/1df) */
+  0x08,0x08,0x08,0x07,0x07,0x07,0x07,0x06, /* sqrt(1/1e0)..sqrt(1/1e7) */
+  0x06,0x06,0x06,0x05,0x05,0x05,0x04,0x04, /* sqrt(1/1e8)..sqrt(1/1ef) */
+  0x04,0x04,0x03,0x03,0x03,0x03,0x02,0x02, /* sqrt(1/1f0)..sqrt(1/1f7) */
+  0x02,0x02,0x01,0x01,0x01,0x01,0x00,0x00  /* sqrt(1/1f8)..sqrt(1/1ff) */
+};
+
+/* Compute s = floor(sqrt(a0)), and *rp = a0 - s^2.  */
+
+#if GMP_NUMB_BITS > 32
+#define MAGIC CNST_LIMB(0x10000000000)	/* 0xffe7debbfc < MAGIC < 0x232b1850f410 */
+#else
+#define MAGIC CNST_LIMB(0x100000)		/* 0xfee6f < MAGIC < 0x29cbc8 */
+#endif
+
+static mp_limb_t
+mpn_sqrtrem1 (mp_ptr rp, mp_limb_t a0)
+{
+#if GMP_NUMB_BITS > 32
+  mp_limb_t a1;
+#endif
+  mp_limb_t x0, t2, t, x2;
+  unsigned abits;
+
+  ASSERT_ALWAYS (GMP_NAIL_BITS == 0);
+  ASSERT_ALWAYS (GMP_LIMB_BITS == 32 || GMP_LIMB_BITS == 64);
+  ASSERT (a0 >= GMP_NUMB_HIGHBIT / 2);
+
+  /* Use Newton iterations for approximating 1/sqrt(a) instead of sqrt(a),
+     since we can do the former without division.  As part of the last
+     iteration convert from 1/sqrt(a) to sqrt(a).  */
+
+  abits = a0 >> (GMP_LIMB_BITS - 1 - 8);	/* extract bits for table lookup */
+  x0 = 0x100 | invsqrttab[abits - 0x80];	/* initial 1/sqrt(a) */
+
+  /* x0 is now an 8 bits approximation of 1/sqrt(a0) */
+
+#if GMP_NUMB_BITS > 32
+  a1 = a0 >> (GMP_LIMB_BITS - 1 - 32);
+  t = (mp_limb_signed_t) (CNST_LIMB(0x2000000000000) - 0x30000 - a1 * x0 * x0) >> 16;
+  x0 = (x0 << 16) + ((mp_limb_signed_t) (x0 * t) >> (16+2));
+
+  /* x0 is now a 16 bits approximation of 1/sqrt(a0) */
+
+  t2 = x0 * (a0 >> (32-8));
+  t = t2 >> 25;
+  t = ((mp_limb_signed_t) ((a0 << 14) - t * t - MAGIC) >> (32-8));
+  x0 = t2 + ((mp_limb_signed_t) (x0 * t) >> 15);
+  x0 >>= 32;
+#else
+  t2 = x0 * (a0 >> (16-8));
+  t = t2 >> 13;
+  t = ((mp_limb_signed_t) ((a0 << 6) - t * t - MAGIC) >> (16-8));
+  x0 = t2 + ((mp_limb_signed_t) (x0 * t) >> 7);
+  x0 >>= 16;
+#endif
+
+  /* x0 is now a full limb approximation of sqrt(a0) */
+
+  x2 = x0 * x0;
+  if (x2 + 2*x0 <= a0 - 1)
+    {
+      x2 += 2*x0 + 1;
+      x0++;
+    }
+
+  *rp = a0 - x2;
+  return x0;
+}
+
+
+#define Prec (GMP_NUMB_BITS >> 1)
+#if ! defined(SQRTREM2_INPLACE)
+#define SQRTREM2_INPLACE 0
+#endif
+
+/* same as mpn_sqrtrem, but for size=2 and {np, 2} normalized
+   return cc such that {np, 2} = sp[0]^2 + cc*2^GMP_NUMB_BITS + rp[0] */
+#if SQRTREM2_INPLACE
+#define CALL_SQRTREM2_INPLACE(sp,rp) mpn_sqrtrem2 (sp, rp)
+static mp_limb_t
+mpn_sqrtrem2 (mp_ptr sp, mp_ptr rp)
+{
+  mp_srcptr np = rp;
+#else
+#define CALL_SQRTREM2_INPLACE(sp,rp) mpn_sqrtrem2 (sp, rp, rp)
+static mp_limb_t
+mpn_sqrtrem2 (mp_ptr sp, mp_ptr rp, mp_srcptr np)
+{
+#endif
+  mp_limb_t q, u, np0, sp0, rp0, q2;
+  int cc;
+
+  ASSERT (np[1] >= GMP_NUMB_HIGHBIT / 2);
+
+  np0 = np[0];
+  sp0 = mpn_sqrtrem1 (rp, np[1]);
+  rp0 = rp[0];
+  /* rp0 <= 2*sp0 < 2^(Prec + 1) */
+  rp0 = (rp0 << (Prec - 1)) + (np0 >> (Prec + 1));
+  q = rp0 / sp0;
+  /* q <= 2^Prec, if q = 2^Prec, reduce the overestimate. */
+  q -= q >> Prec;
+  /* now we have q < 2^Prec */
+  u = rp0 - q * sp0;
+  /* now we have (rp[0]<<Prec + np0>>Prec)/2 = q * sp0 + u */
+  sp0 = (sp0 << Prec) | q;
+  cc = u >> (Prec - 1);
+  rp0 = ((u << (Prec + 1)) & GMP_NUMB_MASK) + (np0 & ((CNST_LIMB (1) << (Prec + 1)) - 1));
+  /* subtract q * q from rp */
+  q2 = q * q;
+  cc -= rp0 < q2;
+  rp0 -= q2;
+  if (cc < 0)
+    {
+      rp0 += sp0;
+      cc += rp0 < sp0;
+      --sp0;
+      rp0 += sp0;
+      cc += rp0 < sp0;
+    }
+
+  rp[0] = rp0;
+  sp[0] = sp0;
+  return cc;
+}
+
+/* writes in {sp, n} the square root (rounded towards zero) of {np, 2n},
+   and in {np, n} the low n limbs of the remainder, returns the high
+   limb of the remainder (which is 0 or 1).
+   Assumes {np, 2n} is normalized, i.e. np[2n-1] >= B/4
+   where B=2^GMP_NUMB_BITS.
+   Needs a scratch of n/2+1 limbs. */
+static mp_limb_t
+mpn_dc_sqrtrem (mp_ptr sp, mp_ptr np, mp_size_t n, mp_limb_t approx, mp_ptr scratch)
+{
+  mp_limb_t q;			/* carry out of {sp, n} */
+  int c, b;			/* carry out of remainder */
+  mp_size_t l, h;
+
+  ASSERT (n > 1);
+  ASSERT (np[2 * n - 1] >= GMP_NUMB_HIGHBIT / 2);
+
+  l = n / 2;
+  h = n - l;
+  if (h == 1)
+    q = CALL_SQRTREM2_INPLACE (sp + l, np + 2 * l);
+  else
+    q = mpn_dc_sqrtrem (sp + l, np + 2 * l, h, 0, scratch);
+  if (q != 0)
+    ASSERT_CARRY (mpn_sub_n (np + 2 * l, np + 2 * l, sp + l, h));
+  TRACE(printf("tdiv_qr(,,,,%u,,%u) -> %u\n", (unsigned) n, (unsigned) h, (unsigned) (n - h + 1)));
+  mpn_tdiv_qr (scratch, np + l, 0, np + l, n, sp + l, h);
+  q += scratch[l];
+  c = scratch[0] & 1;
+  mpn_rshift (sp, scratch, l, 1);
+  sp[l - 1] |= (q << (GMP_NUMB_BITS - 1)) & GMP_NUMB_MASK;
+  if (UNLIKELY ((sp[0] & approx) != 0)) /* (sp[0] & mask) > 1 */
+    return 1; /* Remainder is non-zero */
+  q >>= 1;
+  if (c != 0)
+    c = mpn_add_n (np + l, np + l, sp + l, h);
+  TRACE(printf("sqr(,,%u)\n", (unsigned) l));
+  mpn_sqr (np + n, sp, l);
+  b = q + mpn_sub_n (np, np, np + n, 2 * l);
+  c -= (l == h) ? b : mpn_sub_1 (np + 2 * l, np + 2 * l, 1, (mp_limb_t) b);
+
+  if (c < 0)
+    {
+      q = mpn_add_1 (sp + l, sp + l, h, q);
+#if HAVE_NATIVE_mpn_addlsh1_n_ip1 || HAVE_NATIVE_mpn_addlsh1_n
+      c += mpn_addlsh1_n_ip1 (np, sp, n) + 2 * q;
+#else
+      c += mpn_addmul_1 (np, sp, n, CNST_LIMB(2)) + 2 * q;
+#endif
+      c -= mpn_sub_1 (np, np, n, CNST_LIMB(1));
+      q -= mpn_sub_1 (sp, sp, n, CNST_LIMB(1));
+    }
+
+  return c;
+}
+
+#if USE_DIVAPPR_Q
+static void
+mpn_divappr_q (mp_ptr qp, mp_srcptr np, mp_size_t nn, mp_srcptr dp, mp_size_t dn, mp_ptr scratch)
+{
+  gmp_pi1_t inv;
+  mp_limb_t qh;
+  ASSERT (dn > 2);
+  ASSERT (nn >= dn);
+  ASSERT ((dp[dn-1] & GMP_NUMB_HIGHBIT) != 0);
+
+  MPN_COPY (scratch, np, nn);
+  invert_pi1 (inv, dp[dn-1], dp[dn-2]);
+  if (BELOW_THRESHOLD (dn, DC_DIVAPPR_Q_THRESHOLD))
+    qh = mpn_sbpi1_divappr_q (qp, scratch, nn, dp, dn, inv.inv32);
+  else if (BELOW_THRESHOLD (dn, MU_DIVAPPR_Q_THRESHOLD))
+    qh = mpn_dcpi1_divappr_q (qp, scratch, nn, dp, dn, &inv);
+  else
+    {
+      mp_size_t itch = mpn_mu_divappr_q_itch (nn, dn, 0);
+      TMP_DECL;
+      TMP_MARK;
+      /* Sadly, scratch is too small. */
+      qh = mpn_mu_divappr_q (qp, np, nn, dp, dn, TMP_ALLOC_LIMBS (itch));
+      TMP_FREE;
+    }
+  qp [nn - dn] = qh;
+}
+#endif
+
+/* writes in {sp, n} the square root (rounded towards zero) of {np, 2n-odd},
+   returns zero if the operand was a perfect square, one otherwise.
+   Assumes {np, 2n-odd}*4^nsh is normalized, i.e. B > np[2n-1-odd]*4^nsh >= B/4
+   where B=2^GMP_NUMB_BITS.
+   THINK: In the odd case, three more (dummy) limbs are taken into account,
+   when nsh is maximal, two limbs are discarded from the result of the
+   division. Too much? Is a single dummy limb enough? */
+static int
+mpn_dc_sqrt (mp_ptr sp, mp_srcptr np, mp_size_t n, unsigned nsh, unsigned odd)
+{
+  mp_limb_t q;			/* carry out of {sp, n} */
+  int c;			/* carry out of remainder */
+  mp_size_t l, h;
+  mp_ptr qp, tp, scratch;
+  TMP_DECL;
+  TMP_MARK;
+
+  ASSERT (np[2 * n - 1 - odd] != 0);
+  ASSERT (n > 4);
+  ASSERT (nsh < GMP_NUMB_BITS / 2);
+
+  l = (n - 1) / 2;
+  h = n - l;
+  ASSERT (n >= l + 2 && l + 2 >= h && h > l && l >= 1 + odd);
+  scratch = TMP_ALLOC_LIMBS (l + 2 * n + 5 - USE_DIVAPPR_Q); /* n + 2-USE_DIVAPPR_Q */
+  tp = scratch + n + 2 - USE_DIVAPPR_Q; /* n + h + 1, but tp [-1] is writable */
+  if (nsh != 0)
+    {
+      /* o is used to exactly set the lowest bits of the dividend, is it needed? */
+      int o = l > (1 + odd);
+      ASSERT_NOCARRY (mpn_lshift (tp - o, np + l - 1 - o - odd, n + h + 1 + o, 2 * nsh));
+    }
+  else
+    MPN_COPY (tp, np + l - 1 - odd, n + h + 1);
+  q = mpn_dc_sqrtrem (sp + l, tp + l + 1, h, 0, scratch);
+  if (q != 0)
+    ASSERT_CARRY (mpn_sub_n (tp + l + 1, tp + l + 1, sp + l, h));
+  qp = tp + n + 1; /* l + 2 */
+  TRACE(printf("div(appr)_q(,,%u,,%u) -> %u \n", (unsigned) n+1, (unsigned) h, (unsigned) (n + 1 - h + 1)));
+#if USE_DIVAPPR_Q
+  mpn_divappr_q (qp, tp, n + 1, sp + l, h, scratch);
+#else
+  mpn_div_q (qp, tp, n + 1, sp + l, h, scratch);
+#endif
+  q += qp [l + 1];
+  c = 1;
+  if (q > 1)
+    {
+      /* FIXME: if s!=0 we will shift later, a noop on this area. */
+      MPN_FILL (sp, l, GMP_NUMB_MAX);
+    }
+  else
+    {
+      /* FIXME: if s!=0 we will shift again later, shift just once. */
+      mpn_rshift (sp, qp + 1, l, 1);
+      sp[l - 1] |= q << (GMP_NUMB_BITS - 1);
+      if (((qp[0] >> (2 + USE_DIVAPPR_Q)) | /* < 3 + 4*USE_DIVAPPR_Q */
+	   (qp[1] & (GMP_NUMB_MASK >> ((GMP_NUMB_BITS >> odd)- nsh - 1)))) == 0)
+	{
+	  mp_limb_t cy;
+	  /* Approximation is not good enough, the extra limb(+ nsh bits)
+	     is smaller than needed to absorb the possible error. */
+	  /* {qp + 1, l + 1} equals 2*{sp, l} */
+	  /* FIXME: use mullo or wrap-around, or directly evaluate
+	     remainder with a single sqrmod_bnm1. */
+	  TRACE(printf("mul(,,%u,,%u)\n", (unsigned) h, (unsigned) (l+1)));
+	  ASSERT_NOCARRY (mpn_mul (scratch, sp + l, h, qp + 1, l + 1));
+	  /* Compute the remainder of the previous mpn_div(appr)_q. */
+	  cy = mpn_sub_n (tp + 1, tp + 1, scratch, h);
+#if USE_DIVAPPR_Q || WANT_ASSERT
+	  MPN_DECR_U (tp + 1 + h, l, cy);
+#if USE_DIVAPPR_Q
+	  ASSERT (mpn_cmp (tp + 1 + h, scratch + h, l) <= 0);
+	  if (mpn_cmp (tp + 1 + h, scratch + h, l) < 0)
+	    {
+	      /* May happen only if div result was not exact. */
+#if HAVE_NATIVE_mpn_addlsh1_n_ip1 || HAVE_NATIVE_mpn_addlsh1_n
+	      cy = mpn_addlsh1_n_ip1 (tp + 1, sp + l, h);
+#else
+	      cy = mpn_addmul_1 (tp + 1, sp + l, h, CNST_LIMB(2));
+#endif
+	      ASSERT_NOCARRY (mpn_add_1 (tp + 1 + h, tp + 1 + h, l, cy));
+	      MPN_DECR_U (sp, l, 1);
+	    }
+	  /* Can the root be exact when a correction was needed? We
+	     did not find an example, but it depends on divappr
+	     internals, and we can not assume it true in general...*/
+	  /* else */
+#else /* WANT_ASSERT */
+	  ASSERT (mpn_cmp (tp + 1 + h, scratch + h, l) == 0);
+#endif
+#endif
+	  if (mpn_zero_p (tp + l + 1, h - l))
+	    {
+	      TRACE(printf("sqr(,,%u)\n", (unsigned) l));
+	      mpn_sqr (scratch, sp, l);
+	      c = mpn_cmp (tp + 1, scratch + l, l);
+	      if (c == 0)
+		{
+		  if (nsh != 0)
+		    {
+		      mpn_lshift (tp, np, l, 2 * nsh);
+		      np = tp;
+		    }
+		  c = mpn_cmp (np, scratch + odd, l - odd);
+		}
+	      if (c < 0)
+		{
+		  MPN_DECR_U (sp, l, 1);
+		  c = 1;
+		}
+	    }
+	}
+    }
+  TMP_FREE;
+
+  if ((odd | nsh) != 0)
+    mpn_rshift (sp, sp, n, nsh + (odd ? GMP_NUMB_BITS / 2 : 0));
+  return c;
+}
+
+
+mp_size_t
+mpn_sqrtrem (mp_ptr sp, mp_ptr rp, mp_srcptr np, mp_size_t nn)
+{
+  mp_limb_t cc, high, rl;
+  int c;
+  mp_size_t rn, tn;
+  TMP_DECL;
+
+  ASSERT (nn > 0);
+  ASSERT_MPN (np, nn);
+
+  ASSERT (np[nn - 1] != 0);
+  ASSERT (rp == NULL || MPN_SAME_OR_SEPARATE_P (np, rp, nn));
+  ASSERT (rp == NULL || ! MPN_OVERLAP_P (sp, (nn + 1) / 2, rp, nn));
+  ASSERT (! MPN_OVERLAP_P (sp, (nn + 1) / 2, np, nn));
+
+  high = np[nn - 1];
+  if (high & (GMP_NUMB_HIGHBIT | (GMP_NUMB_HIGHBIT / 2)))
+    c = 0;
+  else
+    {
+      count_leading_zeros (c, high);
+      c -= GMP_NAIL_BITS;
+
+      c = c / 2; /* we have to shift left by 2c bits to normalize {np, nn} */
+    }
+  if (nn == 1) {
+    if (c == 0)
+      {
+	sp[0] = mpn_sqrtrem1 (&rl, high);
+	if (rp != NULL)
+	  rp[0] = rl;
+      }
+    else
+      {
+	cc = mpn_sqrtrem1 (&rl, high << (2*c)) >> c;
+	sp[0] = cc;
+	if (rp != NULL)
+	  rp[0] = rl = high - cc*cc;
+      }
+    return rl != 0;
+  }
+  if (nn == 2) {
+    mp_limb_t tp [2];
+    if (rp == NULL) rp = tp;
+    if (c == 0)
+      {
+#if SQRTREM2_INPLACE
+	rp[1] = high;
+	rp[0] = np[0];
+	cc = CALL_SQRTREM2_INPLACE (sp, rp);
+#else
+	cc = mpn_sqrtrem2 (sp, rp, np);
+#endif
+	rp[1] = cc;
+	return ((rp[0] | cc) != 0) + cc;
+      }
+    else
+      {
+	rl = np[0];
+	rp[1] = (high << (2*c)) | (rl >> (GMP_NUMB_BITS - 2*c));
+	rp[0] = rl << (2*c);
+	CALL_SQRTREM2_INPLACE (sp, rp);
+	cc = sp[0] >>= c;	/* c != 0, the highest bit of the root cc is 0. */
+	rp[0] = rl -= cc*cc;	/* Computed modulo 2^GMP_LIMB_BITS, because it's smaller. */
+	return rl != 0;
+      }
+  }
+  tn = (nn + 1) / 2; /* 2*tn is the smallest even integer >= nn */
+
+  if ((rp == NULL) && (nn > 8))
+    return mpn_dc_sqrt (sp, np, tn, c, nn & 1);
+  TMP_MARK;
+  if (((nn & 1) | c) != 0)
+    {
+      mp_limb_t s0[1], mask;
+      mp_ptr tp, scratch;
+      TMP_ALLOC_LIMBS_2 (tp, 2 * tn, scratch, tn / 2 + 1);
+      tp[0] = 0;	     /* needed only when 2*tn > nn, but saves a test */
+      if (c != 0)
+	mpn_lshift (tp + (nn & 1), np, nn, 2 * c);
+      else
+	MPN_COPY (tp + (nn & 1), np, nn);
+      c += (nn & 1) ? GMP_NUMB_BITS / 2 : 0;		/* c now represents k */
+      mask = (CNST_LIMB (1) << c) - 1;
+      rl = mpn_dc_sqrtrem (sp, tp, tn, (rp == NULL) ? mask - 1 : 0, scratch);
+      /* We have 2^(2k)*N = S^2 + R where k = c + (2tn-nn)*GMP_NUMB_BITS/2,
+	 thus 2^(2k)*N = (S-s0)^2 + 2*S*s0 - s0^2 + R where s0=S mod 2^k */
+      s0[0] = sp[0] & mask;	/* S mod 2^k */
+      rl += mpn_addmul_1 (tp, sp, tn, 2 * s0[0]);	/* R = R + 2*s0*S */
+      cc = mpn_submul_1 (tp, s0, 1, s0[0]);
+      rl -= (tn > 1) ? mpn_sub_1 (tp + 1, tp + 1, tn - 1, cc) : cc;
+      mpn_rshift (sp, sp, tn, c);
+      tp[tn] = rl;
+      if (rp == NULL)
+	rp = tp;
+      c = c << 1;
+      if (c < GMP_NUMB_BITS)
+	tn++;
+      else
+	{
+	  tp++;
+	  c -= GMP_NUMB_BITS;
+	}
+      if (c != 0)
+	mpn_rshift (rp, tp, tn, c);
+      else
+	MPN_COPY_INCR (rp, tp, tn);
+      rn = tn;
+    }
+  else
+    {
+      if (rp != np)
+	{
+	  if (rp == NULL) /* nn <= 8 */
+	    rp = TMP_SALLOC_LIMBS (nn);
+	  MPN_COPY (rp, np, nn);
+	}
+      rn = tn + (rp[tn] = mpn_dc_sqrtrem (sp, rp, tn, 0, TMP_ALLOC_LIMBS(tn / 2 + 1)));
+    }
+
+  MPN_NORMALIZE (rp, rn);
+
+  TMP_FREE;
+  return rn;
+}
diff --git a/third_party/gmp/mpn/generic/strongfibo.c b/third_party/gmp/mpn/generic/strongfibo.c
new file mode 100644
index 0000000..ffd038a
--- /dev/null
+++ b/third_party/gmp/mpn/generic/strongfibo.c
@@ -0,0 +1,216 @@
+/* mpn_fib2m -- calculate Fibonacci numbers, modulo m.
+
+Contributed to the GNU project by Marco Bodrato.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2001, 2002, 2005, 2009, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp-impl.h"
+
+/* Stores |{ap,n}-{bp,n}| in {rp,n},
+   returns the sign of {ap,n}-{bp,n}. */
+static int
+abs_sub_n (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n)
+{
+  mp_limb_t  x, y;
+  while (--n >= 0)
+    {
+      x = ap[n];
+      y = bp[n];
+      if (x != y)
+        {
+          ++n;
+          if (x > y)
+            {
+              ASSERT_NOCARRY (mpn_sub_n (rp, ap, bp, n));
+              return 1;
+            }
+          else
+            {
+              ASSERT_NOCARRY (mpn_sub_n (rp, bp, ap, n));
+              return -1;
+            }
+        }
+      rp[n] = 0;
+    }
+  return 0;
+}
+
+/* Computes at most count terms of the sequence needed by the
+   Lucas-Lehmer-Riesel test, indexing backward:
+   L_i = L_{i+1}^2 - 2
+
+   The sequence is computed modulo M = {mp, mn}.
+   The starting point is given in L_{count+1} = {lp, mn}.
+   The scratch pointed by sp, needs a space of at least 3 * mn + 1 limbs.
+
+   Returns the index i>0 if L_i = 0 (mod M) is found within the
+   computed count terms of the sequence.  Otherwise it returns zero.
+
+   Note: (+/-2)^2-2=2, (+/-1)^2-2=-1, 0^2-2=-2
+ */
+
+static mp_bitcnt_t
+mpn_llriter (mp_ptr lp, mp_srcptr mp, mp_size_t mn, mp_bitcnt_t count, mp_ptr sp)
+{
+  do
+    {
+      mpn_sqr (sp, lp, mn);
+      mpn_tdiv_qr (sp + 2 * mn, lp, 0, sp, 2 * mn, mp, mn);
+      if (lp[0] < 5)
+	{
+	  /* If L^2 % M < 5, |L^2 % M - 2| <= 2 */
+	  if (mn == 1 || mpn_zero_p (lp + 1, mn - 1))
+	    return (lp[0] == 2) ? count : 0;
+	  else
+	    MPN_DECR_U (lp, mn, 2);
+	}
+      else
+	lp[0] -= 2;
+    } while (--count != 0);
+  return 0;
+}
+
+/* Store the Lucas' number L[n] at lp (maybe), computed modulo m.  lp
+   and scratch should have room for mn*2+1 limbs.
+
+   Returns the size of L[n] normally.
+
+   If F[n] is zero modulo m, or L[n] is, returns 0 and lp is
+   undefined.
+*/
+
+static mp_size_t
+mpn_lucm (mp_ptr lp, mp_srcptr np, mp_size_t nn, mp_srcptr mp, mp_size_t mn, mp_ptr scratch)
+{
+  int		neg;
+  mp_limb_t	cy;
+
+  ASSERT (! MPN_OVERLAP_P (lp, MAX(2*mn+1,5), scratch, MAX(2*mn+1,5)));
+  ASSERT (nn > 0);
+
+  neg = mpn_fib2m (lp, scratch, np, nn, mp, mn);
+
+  /* F[n] = +/-{lp, mn}, F[n-1] = +/-{scratch, mn} */
+  if (mpn_zero_p (lp, mn))
+    return 0;
+
+  if (neg) /* One sign is opposite, use sub instead of add. */
+    {
+#if HAVE_NATIVE_mpn_rsblsh1_n || HAVE_NATIVE_mpn_sublsh1_n
+#if HAVE_NATIVE_mpn_rsblsh1_n
+      cy = mpn_rsblsh1_n (lp, lp, scratch, mn); /* L[n] = +/-(2F[n-1]-(-F[n])) */
+#else
+      cy = mpn_sublsh1_n (lp, lp, scratch, mn); /* L[n] = -/+(F[n]-(-2F[n-1])) */
+      if (cy != 0)
+	cy = mpn_add_n (lp, lp, mp, mn) - cy;
+#endif
+      if (cy > 1)
+	cy += mpn_add_n (lp, lp, mp, mn);
+#else
+      cy = mpn_lshift (scratch, scratch, mn, 1); /* 2F[n-1] */
+      if (UNLIKELY (cy))
+	cy -= mpn_sub_n (lp, scratch, lp, mn); /* L[n] = +/-(2F[n-1]-(-F[n])) */
+      else
+	abs_sub_n (lp, lp, scratch, mn);
+#endif
+      ASSERT (cy <= 1);
+    }
+  else
+    {
+#if HAVE_NATIVE_mpn_addlsh1_n
+      cy = mpn_addlsh1_n (lp, lp, scratch, mn); /* L[n] = +/-(2F[n-1]+F[n])) */
+#else
+      cy = mpn_lshift (scratch, scratch, mn, 1);
+      cy+= mpn_add_n (lp, lp, scratch, mn);
+#endif
+      ASSERT (cy <= 2);
+    }
+  while (cy || mpn_cmp (lp, mp, mn) >= 0)
+    cy -= mpn_sub_n (lp, lp, mp, mn);
+  MPN_NORMALIZE (lp, mn);
+  return mn;
+}
+
+int
+mpn_strongfibo (mp_srcptr mp, mp_size_t mn, mp_ptr scratch)
+{
+  mp_ptr	lp, sp;
+  mp_size_t	en;
+  mp_bitcnt_t	b0;
+  TMP_DECL;
+
+#if GMP_NUMB_BITS % 4 == 0
+  b0 = mpn_scan0 (mp, 0);
+#else
+  {
+    mpz_t m = MPZ_ROINIT_N(mp, mn);
+    b0 = mpz_scan0 (m, 0);
+  }
+  if (UNLIKELY (b0 == mn * GMP_NUMB_BITS))
+    {
+      en = 1;
+      scratch [0] = 1;
+    }
+  else
+#endif
+    {
+      int cnt = b0 % GMP_NUMB_BITS;
+      en = b0 / GMP_NUMB_BITS;
+      if (LIKELY (cnt != 0))
+	mpn_rshift (scratch, mp + en, mn - en, cnt);
+      else
+	MPN_COPY (scratch, mp + en, mn - en);
+      en = mn - en;
+      scratch [0] |= 1;
+      en -= scratch [en - 1] == 0;
+    }
+  TMP_MARK;
+
+  lp = TMP_ALLOC_LIMBS (4 * mn + 6);
+  sp = lp + 2 * mn + 3;
+  en = mpn_lucm (sp, scratch, en, mp, mn, lp);
+  if (en != 0 && LIKELY (--b0 != 0))
+    {
+      mpn_sqr (lp, sp, en);
+      lp [0] |= 2; /* V^2 + 2 */
+      if (LIKELY (2 * en >= mn))
+	mpn_tdiv_qr (sp, lp, 0, lp, 2 * en, mp, mn);
+      else
+	MPN_ZERO (lp + 2 * en, mn - 2 * en);
+      if (! mpn_zero_p (lp, mn) && LIKELY (--b0 != 0))
+	b0 = mpn_llriter (lp, mp, mn, b0, lp + mn + 1);
+    }
+  TMP_FREE;
+  return (b0 != 0);
+}
diff --git a/third_party/gmp/mpn/generic/sub.c b/third_party/gmp/mpn/generic/sub.c
new file mode 100644
index 0000000..df0afd6
--- /dev/null
+++ b/third_party/gmp/mpn/generic/sub.c
@@ -0,0 +1,33 @@
+/* mpn_sub - subtract mpn from mpn.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define __GMP_FORCE_mpn_sub 1
+
+#include "gmp-impl.h"
diff --git a/third_party/gmp/mpn/generic/sub_1.c b/third_party/gmp/mpn/generic/sub_1.c
new file mode 100644
index 0000000..a20f191
--- /dev/null
+++ b/third_party/gmp/mpn/generic/sub_1.c
@@ -0,0 +1,33 @@
+/* mpn_sub_1 - subtract limb from mpn.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define __GMP_FORCE_mpn_sub_1 1
+
+#include "gmp-impl.h"
diff --git a/third_party/gmp/mpn/generic/sub_err1_n.c b/third_party/gmp/mpn/generic/sub_err1_n.c
new file mode 100644
index 0000000..beca57e
--- /dev/null
+++ b/third_party/gmp/mpn/generic/sub_err1_n.c
@@ -0,0 +1,100 @@
+/* mpn_sub_err1_n -- sub_n with one error term
+
+   Contributed by David Harvey.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/*
+  Computes:
+
+  (1) {rp,n} := {up,n} - {vp,n} (just like mpn_sub_n) with incoming borrow cy,
+  return value is borrow out.
+
+  (2) Let c[i+1] = borrow from i-th limb subtraction (c[0] = cy).
+  Computes c[1]*yp[n-1] + ... + c[n]*yp[0], stores two-limb result at ep.
+
+  Requires n >= 1.
+
+  None of the outputs may overlap each other or any of the inputs, except
+  that {rp,n} may be equal to {up,n} or {vp,n}.
+*/
+mp_limb_t
+mpn_sub_err1_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp,
+		mp_ptr ep, mp_srcptr yp,
+                mp_size_t n, mp_limb_t cy)
+{
+  mp_limb_t el, eh, ul, vl, yl, zl, rl, sl, cy1, cy2;
+
+  ASSERT (n >= 1);
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, up, n));
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, vp, n));
+  ASSERT (! MPN_OVERLAP_P (rp, n, yp, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 2, up, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 2, vp, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 2, yp, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 2, rp, n));
+
+  yp += n - 1;
+  el = eh = 0;
+
+  do
+    {
+      yl = *yp--;
+      ul = *up++;
+      vl = *vp++;
+
+      /* ordinary sub_n */
+      SUBC_LIMB (cy1, sl, ul, vl);
+      SUBC_LIMB (cy2, rl, sl, cy);
+      cy = cy1 | cy2;
+      *rp++ = rl;
+
+      /* update (eh:el) */
+      zl = (-cy) & yl;
+      el += zl;
+      eh += el < zl;
+    }
+  while (--n);
+
+#if GMP_NAIL_BITS != 0
+  eh = (eh << GMP_NAIL_BITS) + (el >> GMP_NUMB_BITS);
+  el &= GMP_NUMB_MASK;
+#endif
+
+  ep[0] = el;
+  ep[1] = eh;
+
+  return cy;
+}
diff --git a/third_party/gmp/mpn/generic/sub_err2_n.c b/third_party/gmp/mpn/generic/sub_err2_n.c
new file mode 100644
index 0000000..1edf8d6
--- /dev/null
+++ b/third_party/gmp/mpn/generic/sub_err2_n.c
@@ -0,0 +1,116 @@
+/* mpn_sub_err2_n -- sub_n with two error terms
+
+   Contributed by David Harvey.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/*
+  Computes:
+
+  (1) {rp,n} := {up,n} - {vp,n} (just like mpn_sub_n) with incoming borrow cy,
+  return value is borrow out.
+
+  (2) Let c[i+1] = borrow from i-th limb subtraction (c[0] = cy).
+  Computes c[1]*yp1[n-1] + ... + c[n]*yp1[0],
+           c[1]*yp2[n-1] + ... + c[n]*yp2[0],
+  stores two-limb results at {ep,2} and {ep+2,2} respectively.
+
+  Requires n >= 1.
+
+  None of the outputs may overlap each other or any of the inputs, except
+  that {rp,n} may be equal to {up,n} or {vp,n}.
+*/
+mp_limb_t
+mpn_sub_err2_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp,
+                mp_ptr ep, mp_srcptr yp1, mp_srcptr yp2,
+                mp_size_t n, mp_limb_t cy)
+{
+  mp_limb_t el1, eh1, el2, eh2, ul, vl, yl1, yl2, zl1, zl2, rl, sl, cy1, cy2;
+
+  ASSERT (n >= 1);
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, up, n));
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, vp, n));
+  ASSERT (! MPN_OVERLAP_P (rp, n, yp1, n));
+  ASSERT (! MPN_OVERLAP_P (rp, n, yp2, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 4, up, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 4, vp, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 4, yp1, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 4, yp2, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 4, rp, n));
+
+  yp1 += n - 1;
+  yp2 += n - 1;
+  el1 = eh1 = 0;
+  el2 = eh2 = 0;
+
+  do
+    {
+      yl1 = *yp1--;
+      yl2 = *yp2--;
+      ul = *up++;
+      vl = *vp++;
+
+      /* ordinary sub_n */
+      SUBC_LIMB (cy1, sl, ul, vl);
+      SUBC_LIMB (cy2, rl, sl, cy);
+      cy = cy1 | cy2;
+      *rp++ = rl;
+
+      /* update (eh1:el1) */
+      zl1 = (-cy) & yl1;
+      el1 += zl1;
+      eh1 += el1 < zl1;
+
+      /* update (eh2:el2) */
+      zl2 = (-cy) & yl2;
+      el2 += zl2;
+      eh2 += el2 < zl2;
+    }
+  while (--n);
+
+#if GMP_NAIL_BITS != 0
+  eh1 = (eh1 << GMP_NAIL_BITS) + (el1 >> GMP_NUMB_BITS);
+  el1 &= GMP_NUMB_MASK;
+  eh2 = (eh2 << GMP_NAIL_BITS) + (el2 >> GMP_NUMB_BITS);
+  el2 &= GMP_NUMB_MASK;
+#endif
+
+  ep[0] = el1;
+  ep[1] = eh1;
+  ep[2] = el2;
+  ep[3] = eh2;
+
+  return cy;
+}
diff --git a/third_party/gmp/mpn/generic/sub_err3_n.c b/third_party/gmp/mpn/generic/sub_err3_n.c
new file mode 100644
index 0000000..2db3c63
--- /dev/null
+++ b/third_party/gmp/mpn/generic/sub_err3_n.c
@@ -0,0 +1,131 @@
+/* mpn_sub_err3_n -- sub_n with three error terms
+
+   Contributed by David Harvey.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/*
+  Computes:
+
+  (1) {rp,n} := {up,n} - {vp,n} (just like mpn_sub_n) with incoming borrow cy,
+  return value is borrow out.
+
+  (2) Let c[i+1] = borrow from i-th limb subtraction (c[0] = cy).
+  Computes c[1]*yp1[n-1] + ... + c[n]*yp1[0],
+           c[1]*yp2[n-1] + ... + c[n]*yp2[0],
+           c[1]*yp3[n-1] + ... + c[n]*yp3[0],
+  stores two-limb results at {ep,2}, {ep+2,2} and {ep+4,2} respectively.
+
+  Requires n >= 1.
+
+  None of the outputs may overlap each other or any of the inputs, except
+  that {rp,n} may be equal to {up,n} or {vp,n}.
+*/
+mp_limb_t
+mpn_sub_err3_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp,
+                mp_ptr ep, mp_srcptr yp1, mp_srcptr yp2, mp_srcptr yp3,
+                mp_size_t n, mp_limb_t cy)
+{
+  mp_limb_t el1, eh1, el2, eh2, el3, eh3, ul, vl, yl1, yl2, yl3, zl1, zl2, zl3, rl, sl, cy1, cy2;
+
+  ASSERT (n >= 1);
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, up, n));
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, vp, n));
+  ASSERT (! MPN_OVERLAP_P (rp, n, yp1, n));
+  ASSERT (! MPN_OVERLAP_P (rp, n, yp2, n));
+  ASSERT (! MPN_OVERLAP_P (rp, n, yp3, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 6, up, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 6, vp, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 6, yp1, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 6, yp2, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 6, yp3, n));
+  ASSERT (! MPN_OVERLAP_P (ep, 6, rp, n));
+
+  yp1 += n - 1;
+  yp2 += n - 1;
+  yp3 += n - 1;
+  el1 = eh1 = 0;
+  el2 = eh2 = 0;
+  el3 = eh3 = 0;
+
+  do
+    {
+      yl1 = *yp1--;
+      yl2 = *yp2--;
+      yl3 = *yp3--;
+      ul = *up++;
+      vl = *vp++;
+
+      /* ordinary sub_n */
+      SUBC_LIMB (cy1, sl, ul, vl);
+      SUBC_LIMB (cy2, rl, sl, cy);
+      cy = cy1 | cy2;
+      *rp++ = rl;
+
+      /* update (eh1:el1) */
+      zl1 = (-cy) & yl1;
+      el1 += zl1;
+      eh1 += el1 < zl1;
+
+      /* update (eh2:el2) */
+      zl2 = (-cy) & yl2;
+      el2 += zl2;
+      eh2 += el2 < zl2;
+
+      /* update (eh3:el3) */
+      zl3 = (-cy) & yl3;
+      el3 += zl3;
+      eh3 += el3 < zl3;
+    }
+  while (--n);
+
+#if GMP_NAIL_BITS != 0
+  eh1 = (eh1 << GMP_NAIL_BITS) + (el1 >> GMP_NUMB_BITS);
+  el1 &= GMP_NUMB_MASK;
+  eh2 = (eh2 << GMP_NAIL_BITS) + (el2 >> GMP_NUMB_BITS);
+  el2 &= GMP_NUMB_MASK;
+  eh3 = (eh3 << GMP_NAIL_BITS) + (el3 >> GMP_NUMB_BITS);
+  el3 &= GMP_NUMB_MASK;
+#endif
+
+  ep[0] = el1;
+  ep[1] = eh1;
+  ep[2] = el2;
+  ep[3] = eh2;
+  ep[4] = el3;
+  ep[5] = eh3;
+
+  return cy;
+}
diff --git a/third_party/gmp/mpn/generic/sub_n.c b/third_party/gmp/mpn/generic/sub_n.c
new file mode 100644
index 0000000..b192c96
--- /dev/null
+++ b/third_party/gmp/mpn/generic/sub_n.c
@@ -0,0 +1,89 @@
+/* mpn_sub_n -- Subtract equal length limb vectors.
+
+Copyright 1992-1994, 1996, 2000, 2002, 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+#if GMP_NAIL_BITS == 0
+
+mp_limb_t
+mpn_sub_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n)
+{
+  mp_limb_t ul, vl, sl, rl, cy, cy1, cy2;
+
+  ASSERT (n >= 1);
+  ASSERT (MPN_SAME_OR_INCR_P (rp, up, n));
+  ASSERT (MPN_SAME_OR_INCR_P (rp, vp, n));
+
+  cy = 0;
+  do
+    {
+      ul = *up++;
+      vl = *vp++;
+      sl = ul - vl;
+      cy1 = sl > ul;
+      rl = sl - cy;
+      cy2 = rl > sl;
+      cy = cy1 | cy2;
+      *rp++ = rl;
+    }
+  while (--n != 0);
+
+  return cy;
+}
+
+#endif
+
+#if GMP_NAIL_BITS >= 1
+
+mp_limb_t
+mpn_sub_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n)
+{
+  mp_limb_t ul, vl, rl, cy;
+
+  ASSERT (n >= 1);
+  ASSERT (MPN_SAME_OR_INCR_P (rp, up, n));
+  ASSERT (MPN_SAME_OR_INCR_P (rp, vp, n));
+
+  cy = 0;
+  do
+    {
+      ul = *up++;
+      vl = *vp++;
+      rl = ul - vl - cy;
+      cy = rl >> (GMP_LIMB_BITS - 1);
+      *rp++ = rl & GMP_NUMB_MASK;
+    }
+  while (--n != 0);
+
+  return cy;
+}
+
+#endif
diff --git a/third_party/gmp/mpn/generic/submul_1.c b/third_party/gmp/mpn/generic/submul_1.c
new file mode 100644
index 0000000..4744274
--- /dev/null
+++ b/third_party/gmp/mpn/generic/submul_1.c
@@ -0,0 +1,144 @@
+/* mpn_submul_1 -- multiply the N long limb vector pointed to by UP by VL,
+   subtract the N least significant limbs of the product from the limb
+   vector pointed to by RP.  Return the most significant limb of the
+   product, adjusted for carry-out from the subtraction.
+
+Copyright 1992-1994, 1996, 2000, 2002, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+#if GMP_NAIL_BITS == 0
+
+mp_limb_t
+mpn_submul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t v0)
+{
+  mp_limb_t u0, crec, c, p1, p0, r0;
+
+  ASSERT (n >= 1);
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, up, n));
+
+  crec = 0;
+  do
+    {
+      u0 = *up++;
+      umul_ppmm (p1, p0, u0, v0);
+
+      r0 = *rp;
+
+      p0 = r0 - p0;
+      c = r0 < p0;
+
+      p1 = p1 + c;
+
+      r0 = p0 - crec;		/* cycle 0, 3, ... */
+      c = p0 < r0;		/* cycle 1, 4, ... */
+
+      crec = p1 + c;		/* cycle 2, 5, ... */
+
+      *rp++ = r0;
+    }
+  while (--n != 0);
+
+  return crec;
+}
+
+#endif
+
+#if GMP_NAIL_BITS == 1
+
+mp_limb_t
+mpn_submul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t v0)
+{
+  mp_limb_t shifted_v0, u0, r0, p0, p1, prev_p1, cl, xl, c1, c2, c3;
+
+  ASSERT (n >= 1);
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, up, n));
+  ASSERT_MPN (rp, n);
+  ASSERT_MPN (up, n);
+  ASSERT_LIMB (v0);
+
+  shifted_v0 = v0 << GMP_NAIL_BITS;
+  cl = 0;
+  prev_p1 = 0;
+  do
+    {
+      u0 = *up++;
+      r0 = *rp;
+      umul_ppmm (p1, p0, u0, shifted_v0);
+      p0 >>= GMP_NAIL_BITS;
+      SUBC_LIMB (c1, xl, r0, prev_p1);
+      SUBC_LIMB (c2, xl, xl, p0);
+      SUBC_LIMB (c3, xl, xl, cl);
+      cl = c1 + c2 + c3;
+      *rp++ = xl;
+      prev_p1 = p1;
+    }
+  while (--n != 0);
+
+  return prev_p1 + cl;
+}
+
+#endif
+
+#if GMP_NAIL_BITS >= 2
+
+mp_limb_t
+mpn_submul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t v0)
+{
+  mp_limb_t shifted_v0, u0, r0, p0, p1, prev_p1, xw, cl, xl;
+
+  ASSERT (n >= 1);
+  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, up, n));
+  ASSERT_MPN (rp, n);
+  ASSERT_MPN (up, n);
+  ASSERT_LIMB (v0);
+
+  shifted_v0 = v0 << GMP_NAIL_BITS;
+  cl = 0;
+  prev_p1 = 0;
+  do
+    {
+      u0 = *up++;
+      r0 = *rp;
+      umul_ppmm (p1, p0, u0, shifted_v0);
+      p0 >>= GMP_NAIL_BITS;
+      xw = r0 - (prev_p1 + p0) + cl;
+      cl = (mp_limb_signed_t) xw >> GMP_NUMB_BITS; /* FIXME: non-portable */
+      xl = xw & GMP_NUMB_MASK;
+      *rp++ = xl;
+      prev_p1 = p1;
+    }
+  while (--n != 0);
+
+  return prev_p1 - cl;
+}
+
+#endif
diff --git a/third_party/gmp/mpn/generic/tdiv_qr.c b/third_party/gmp/mpn/generic/tdiv_qr.c
new file mode 100644
index 0000000..92ff33c
--- /dev/null
+++ b/third_party/gmp/mpn/generic/tdiv_qr.c
@@ -0,0 +1,386 @@
+/* mpn_tdiv_qr -- Divide the numerator (np,nn) by the denominator (dp,dn) and
+   write the nn-dn+1 quotient limbs at qp and the dn remainder limbs at rp.  If
+   qxn is non-zero, generate that many fraction limbs and append them after the
+   other quotient limbs, and update the remainder accordingly.  The input
+   operands are unaffected.
+
+   Preconditions:
+   1. The most significant limb of the divisor must be non-zero.
+   2. nn >= dn, even if qxn is non-zero.  (??? relax this ???)
+
+   The time complexity of this is O(qn*qn+M(dn,qn)), where M(m,n) is the time
+   complexity of multiplication.
+
+Copyright 1997, 2000-2002, 2005, 2009, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+void
+mpn_tdiv_qr (mp_ptr qp, mp_ptr rp, mp_size_t qxn,
+	     mp_srcptr np, mp_size_t nn, mp_srcptr dp, mp_size_t dn)
+{
+  ASSERT_ALWAYS (qxn == 0);
+
+  ASSERT (nn >= 0);
+  ASSERT (dn >= 0);
+  ASSERT (dn == 0 || dp[dn - 1] != 0);
+  ASSERT (! MPN_OVERLAP_P (qp, nn - dn + 1 + qxn, np, nn));
+  ASSERT (! MPN_OVERLAP_P (qp, nn - dn + 1 + qxn, dp, dn));
+
+  switch (dn)
+    {
+    case 0:
+      DIVIDE_BY_ZERO;
+
+    case 1:
+      {
+	rp[0] = mpn_divrem_1 (qp, (mp_size_t) 0, np, nn, dp[0]);
+	return;
+      }
+
+    case 2:
+      {
+	mp_ptr n2p;
+	mp_limb_t qhl, cy;
+	TMP_DECL;
+	TMP_MARK;
+	if ((dp[1] & GMP_NUMB_HIGHBIT) == 0)
+	  {
+	    int cnt;
+	    mp_limb_t d2p[2];
+	    count_leading_zeros (cnt, dp[1]);
+	    cnt -= GMP_NAIL_BITS;
+	    d2p[1] = (dp[1] << cnt) | (dp[0] >> (GMP_NUMB_BITS - cnt));
+	    d2p[0] = (dp[0] << cnt) & GMP_NUMB_MASK;
+	    n2p = TMP_ALLOC_LIMBS (nn + 1);
+	    cy = mpn_lshift (n2p, np, nn, cnt);
+	    n2p[nn] = cy;
+	    qhl = mpn_divrem_2 (qp, 0L, n2p, nn + (cy != 0), d2p);
+	    if (cy == 0)
+	      qp[nn - 2] = qhl;	/* always store nn-2+1 quotient limbs */
+	    rp[0] = (n2p[0] >> cnt)
+	      | ((n2p[1] << (GMP_NUMB_BITS - cnt)) & GMP_NUMB_MASK);
+	    rp[1] = (n2p[1] >> cnt);
+	  }
+	else
+	  {
+	    n2p = TMP_ALLOC_LIMBS (nn);
+	    MPN_COPY (n2p, np, nn);
+	    qhl = mpn_divrem_2 (qp, 0L, n2p, nn, dp);
+	    qp[nn - 2] = qhl;	/* always store nn-2+1 quotient limbs */
+	    rp[0] = n2p[0];
+	    rp[1] = n2p[1];
+	  }
+	TMP_FREE;
+	return;
+      }
+
+    default:
+      {
+	int adjust;
+	gmp_pi1_t dinv;
+	TMP_DECL;
+	TMP_MARK;
+	adjust = np[nn - 1] >= dp[dn - 1];	/* conservative tests for quotient size */
+	if (nn + adjust >= 2 * dn)
+	  {
+	    mp_ptr n2p, d2p;
+	    mp_limb_t cy;
+	    int cnt;
+
+	    qp[nn - dn] = 0;			  /* zero high quotient limb */
+	    if ((dp[dn - 1] & GMP_NUMB_HIGHBIT) == 0) /* normalize divisor */
+	      {
+		count_leading_zeros (cnt, dp[dn - 1]);
+		cnt -= GMP_NAIL_BITS;
+		d2p = TMP_ALLOC_LIMBS (dn);
+		mpn_lshift (d2p, dp, dn, cnt);
+		n2p = TMP_ALLOC_LIMBS (nn + 1);
+		cy = mpn_lshift (n2p, np, nn, cnt);
+		n2p[nn] = cy;
+		nn += adjust;
+	      }
+	    else
+	      {
+		cnt = 0;
+		d2p = (mp_ptr) dp;
+		n2p = TMP_ALLOC_LIMBS (nn + 1);
+		MPN_COPY (n2p, np, nn);
+		n2p[nn] = 0;
+		nn += adjust;
+	      }
+
+	    invert_pi1 (dinv, d2p[dn - 1], d2p[dn - 2]);
+	    if (BELOW_THRESHOLD (dn, DC_DIV_QR_THRESHOLD))
+	      mpn_sbpi1_div_qr (qp, n2p, nn, d2p, dn, dinv.inv32);
+	    else if (BELOW_THRESHOLD (dn, MUPI_DIV_QR_THRESHOLD) ||   /* fast condition */
+		     BELOW_THRESHOLD (nn, 2 * MU_DIV_QR_THRESHOLD) || /* fast condition */
+		     (double) (2 * (MU_DIV_QR_THRESHOLD - MUPI_DIV_QR_THRESHOLD)) * dn /* slow... */
+		     + (double) MUPI_DIV_QR_THRESHOLD * nn > (double) dn * nn)    /* ...condition */
+	      mpn_dcpi1_div_qr (qp, n2p, nn, d2p, dn, &dinv);
+	    else
+	      {
+		mp_size_t itch = mpn_mu_div_qr_itch (nn, dn, 0);
+		mp_ptr scratch = TMP_ALLOC_LIMBS (itch);
+		mpn_mu_div_qr (qp, rp, n2p, nn, d2p, dn, scratch);
+		n2p = rp;
+	      }
+
+	    if (cnt != 0)
+	      mpn_rshift (rp, n2p, dn, cnt);
+	    else
+	      MPN_COPY (rp, n2p, dn);
+	    TMP_FREE;
+	    return;
+	  }
+
+	/* When we come here, the numerator/partial remainder is less
+	   than twice the size of the denominator.  */
+
+	  {
+	    /* Problem:
+
+	       Divide a numerator N with nn limbs by a denominator D with dn
+	       limbs forming a quotient of qn=nn-dn+1 limbs.  When qn is small
+	       compared to dn, conventional division algorithms perform poorly.
+	       We want an algorithm that has an expected running time that is
+	       dependent only on qn.
+
+	       Algorithm (very informally stated):
+
+	       1) Divide the 2 x qn most significant limbs from the numerator
+		  by the qn most significant limbs from the denominator.  Call
+		  the result qest.  This is either the correct quotient, but
+		  might be 1 or 2 too large.  Compute the remainder from the
+		  division.  (This step is implemented by an mpn_divrem call.)
+
+	       2) Is the most significant limb from the remainder < p, where p
+		  is the product of the most significant limb from the quotient
+		  and the next(d)?  (Next(d) denotes the next ignored limb from
+		  the denominator.)  If it is, decrement qest, and adjust the
+		  remainder accordingly.
+
+	       3) Is the remainder >= qest?  If it is, qest is the desired
+		  quotient.  The algorithm terminates.
+
+	       4) Subtract qest x next(d) from the remainder.  If there is
+		  borrow out, decrement qest, and adjust the remainder
+		  accordingly.
+
+	       5) Skip one word from the denominator (i.e., let next(d) denote
+		  the next less significant limb.  */
+
+	    mp_size_t qn;
+	    mp_ptr n2p, d2p;
+	    mp_ptr tp;
+	    mp_limb_t cy;
+	    mp_size_t in, rn;
+	    mp_limb_t quotient_too_large;
+	    unsigned int cnt;
+
+	    qn = nn - dn;
+	    qp[qn] = 0;				/* zero high quotient limb */
+	    qn += adjust;			/* qn cannot become bigger */
+
+	    if (qn == 0)
+	      {
+		MPN_COPY (rp, np, dn);
+		TMP_FREE;
+		return;
+	      }
+
+	    in = dn - qn;		/* (at least partially) ignored # of limbs in ops */
+	    /* Normalize denominator by shifting it to the left such that its
+	       most significant bit is set.  Then shift the numerator the same
+	       amount, to mathematically preserve quotient.  */
+	    if ((dp[dn - 1] & GMP_NUMB_HIGHBIT) == 0)
+	      {
+		count_leading_zeros (cnt, dp[dn - 1]);
+		cnt -= GMP_NAIL_BITS;
+
+		d2p = TMP_ALLOC_LIMBS (qn);
+		mpn_lshift (d2p, dp + in, qn, cnt);
+		d2p[0] |= dp[in - 1] >> (GMP_NUMB_BITS - cnt);
+
+		n2p = TMP_ALLOC_LIMBS (2 * qn + 1);
+		cy = mpn_lshift (n2p, np + nn - 2 * qn, 2 * qn, cnt);
+		if (adjust)
+		  {
+		    n2p[2 * qn] = cy;
+		    n2p++;
+		  }
+		else
+		  {
+		    n2p[0] |= np[nn - 2 * qn - 1] >> (GMP_NUMB_BITS - cnt);
+		  }
+	      }
+	    else
+	      {
+		cnt = 0;
+		d2p = (mp_ptr) dp + in;
+
+		n2p = TMP_ALLOC_LIMBS (2 * qn + 1);
+		MPN_COPY (n2p, np + nn - 2 * qn, 2 * qn);
+		if (adjust)
+		  {
+		    n2p[2 * qn] = 0;
+		    n2p++;
+		  }
+	      }
+
+	    /* Get an approximate quotient using the extracted operands.  */
+	    if (qn == 1)
+	      {
+		mp_limb_t q0, r0;
+		udiv_qrnnd (q0, r0, n2p[1], n2p[0] << GMP_NAIL_BITS, d2p[0] << GMP_NAIL_BITS);
+		n2p[0] = r0 >> GMP_NAIL_BITS;
+		qp[0] = q0;
+	      }
+	    else if (qn == 2)
+	      mpn_divrem_2 (qp, 0L, n2p, 4L, d2p); /* FIXME: obsolete function */
+	    else
+	      {
+		invert_pi1 (dinv, d2p[qn - 1], d2p[qn - 2]);
+		if (BELOW_THRESHOLD (qn, DC_DIV_QR_THRESHOLD))
+		  mpn_sbpi1_div_qr (qp, n2p, 2 * qn, d2p, qn, dinv.inv32);
+		else if (BELOW_THRESHOLD (qn, MU_DIV_QR_THRESHOLD))
+		  mpn_dcpi1_div_qr (qp, n2p, 2 * qn, d2p, qn, &dinv);
+		else
+		  {
+		    mp_size_t itch = mpn_mu_div_qr_itch (2 * qn, qn, 0);
+		    mp_ptr scratch = TMP_ALLOC_LIMBS (itch);
+		    mp_ptr r2p = rp;
+		    if (np == r2p)	/* If N and R share space, put ... */
+		      r2p += nn - qn;	/* intermediate remainder at N's upper end. */
+		    mpn_mu_div_qr (qp, r2p, n2p, 2 * qn, d2p, qn, scratch);
+		    MPN_COPY (n2p, r2p, qn);
+		  }
+	      }
+
+	    rn = qn;
+	    /* Multiply the first ignored divisor limb by the most significant
+	       quotient limb.  If that product is > the partial remainder's
+	       most significant limb, we know the quotient is too large.  This
+	       test quickly catches most cases where the quotient is too large;
+	       it catches all cases where the quotient is 2 too large.  */
+	    {
+	      mp_limb_t dl, x;
+	      mp_limb_t h, dummy;
+
+	      if (in - 2 < 0)
+		dl = 0;
+	      else
+		dl = dp[in - 2];
+
+#if GMP_NAIL_BITS == 0
+	      x = (dp[in - 1] << cnt) | ((dl >> 1) >> ((~cnt) % GMP_LIMB_BITS));
+#else
+	      x = (dp[in - 1] << cnt) & GMP_NUMB_MASK;
+	      if (cnt != 0)
+		x |= dl >> (GMP_NUMB_BITS - cnt);
+#endif
+	      umul_ppmm (h, dummy, x, qp[qn - 1] << GMP_NAIL_BITS);
+
+	      if (n2p[qn - 1] < h)
+		{
+		  mp_limb_t cy;
+
+		  mpn_decr_u (qp, (mp_limb_t) 1);
+		  cy = mpn_add_n (n2p, n2p, d2p, qn);
+		  if (cy)
+		    {
+		      /* The partial remainder is safely large.  */
+		      n2p[qn] = cy;
+		      ++rn;
+		    }
+		}
+	    }
+
+	    quotient_too_large = 0;
+	    if (cnt != 0)
+	      {
+		mp_limb_t cy1, cy2;
+
+		/* Append partially used numerator limb to partial remainder.  */
+		cy1 = mpn_lshift (n2p, n2p, rn, GMP_NUMB_BITS - cnt);
+		n2p[0] |= np[in - 1] & (GMP_NUMB_MASK >> cnt);
+
+		/* Update partial remainder with partially used divisor limb.  */
+		cy2 = mpn_submul_1 (n2p, qp, qn, dp[in - 1] & (GMP_NUMB_MASK >> cnt));
+		if (qn != rn)
+		  {
+		    ASSERT_ALWAYS (n2p[qn] >= cy2);
+		    n2p[qn] -= cy2;
+		  }
+		else
+		  {
+		    n2p[qn] = cy1 - cy2; /* & GMP_NUMB_MASK; */
+
+		    quotient_too_large = (cy1 < cy2);
+		    ++rn;
+		  }
+		--in;
+	      }
+	    /* True: partial remainder now is neutral, i.e., it is not shifted up.  */
+
+	    tp = TMP_ALLOC_LIMBS (dn);
+
+	    if (in < qn)
+	      {
+		if (in == 0)
+		  {
+		    MPN_COPY (rp, n2p, rn);
+		    ASSERT_ALWAYS (rn == dn);
+		    goto foo;
+		  }
+		mpn_mul (tp, qp, qn, dp, in);
+	      }
+	    else
+	      mpn_mul (tp, dp, in, qp, qn);
+
+	    cy = mpn_sub (n2p, n2p, rn, tp + in, qn);
+	    MPN_COPY (rp + in, n2p, dn - in);
+	    quotient_too_large |= cy;
+	    cy = mpn_sub_n (rp, np, tp, in);
+	    cy = mpn_sub_1 (rp + in, rp + in, rn, cy);
+	    quotient_too_large |= cy;
+	  foo:
+	    if (quotient_too_large)
+	      {
+		mpn_decr_u (qp, (mp_limb_t) 1);
+		mpn_add_n (rp, rp, dp, dn);
+	      }
+	  }
+	TMP_FREE;
+	return;
+      }
+    }
+}
diff --git a/third_party/gmp/mpn/generic/toom22_mul.c b/third_party/gmp/mpn/generic/toom22_mul.c
new file mode 100644
index 0000000..64f024a
--- /dev/null
+++ b/third_party/gmp/mpn/generic/toom22_mul.c
@@ -0,0 +1,221 @@
+/* mpn_toom22_mul -- Multiply {ap,an} and {bp,bn} where an >= bn.  Or more
+   accurately, bn <= an < 2bn.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2006-2010, 2012, 2014, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+/* Evaluate in: -1, 0, +inf
+
+  <-s--><--n-->
+   ____ ______
+  |_a1_|___a0_|
+   |b1_|___b0_|
+   <-t-><--n-->
+
+  v0  =  a0     * b0       #   A(0)*B(0)
+  vm1 = (a0- a1)*(b0- b1)  #  A(-1)*B(-1)
+  vinf=      a1 *     b1   # A(inf)*B(inf)
+*/
+
+#if TUNE_PROGRAM_BUILD || WANT_FAT_BINARY
+#define MAYBE_mul_toom22   1
+#else
+#define MAYBE_mul_toom22						\
+  (MUL_TOOM33_THRESHOLD >= 2 * MUL_TOOM22_THRESHOLD)
+#endif
+
+#define TOOM22_MUL_N_REC(p, a, b, n, ws)				\
+  do {									\
+    if (! MAYBE_mul_toom22						\
+	|| BELOW_THRESHOLD (n, MUL_TOOM22_THRESHOLD))			\
+      mpn_mul_basecase (p, a, n, b, n);					\
+    else								\
+      mpn_toom22_mul (p, a, n, b, n, ws);				\
+  } while (0)
+
+/* Normally, this calls mul_basecase or toom22_mul.  But when when the fraction
+   MUL_TOOM33_THRESHOLD / MUL_TOOM22_THRESHOLD is large, an initially small
+   relative unbalance will become a larger and larger relative unbalance with
+   each recursion (the difference s-t will be invariant over recursive calls).
+   Therefore, we need to call toom32_mul.  FIXME: Suppress depending on
+   MUL_TOOM33_THRESHOLD / MUL_TOOM22_THRESHOLD and on MUL_TOOM22_THRESHOLD.  */
+#define TOOM22_MUL_REC(p, a, an, b, bn, ws)				\
+  do {									\
+    if (! MAYBE_mul_toom22						\
+	|| BELOW_THRESHOLD (bn, MUL_TOOM22_THRESHOLD))			\
+      mpn_mul_basecase (p, a, an, b, bn);				\
+    else if (4 * an < 5 * bn)						\
+      mpn_toom22_mul (p, a, an, b, bn, ws);				\
+    else								\
+      mpn_toom32_mul (p, a, an, b, bn, ws);				\
+  } while (0)
+
+void
+mpn_toom22_mul (mp_ptr pp,
+		mp_srcptr ap, mp_size_t an,
+		mp_srcptr bp, mp_size_t bn,
+		mp_ptr scratch)
+{
+  const int __gmpn_cpuvec_initialized = 1;
+  mp_size_t n, s, t;
+  int vm1_neg;
+  mp_limb_t cy, cy2;
+  mp_ptr asm1;
+  mp_ptr bsm1;
+
+#define a0  ap
+#define a1  (ap + n)
+#define b0  bp
+#define b1  (bp + n)
+
+  s = an >> 1;
+  n = an - s;
+  t = bn - n;
+
+  ASSERT (an >= bn);
+
+  ASSERT (0 < s && s <= n && s >= n - 1);
+  ASSERT (0 < t && t <= s);
+
+  asm1 = pp;
+  bsm1 = pp + n;
+
+  vm1_neg = 0;
+
+  /* Compute asm1.  */
+  if (s == n)
+    {
+      if (mpn_cmp (a0, a1, n) < 0)
+	{
+	  mpn_sub_n (asm1, a1, a0, n);
+	  vm1_neg = 1;
+	}
+      else
+	{
+	  mpn_sub_n (asm1, a0, a1, n);
+	}
+    }
+  else /* n - s == 1 */
+    {
+      if (a0[s] == 0 && mpn_cmp (a0, a1, s) < 0)
+	{
+	  mpn_sub_n (asm1, a1, a0, s);
+	  asm1[s] = 0;
+	  vm1_neg = 1;
+	}
+      else
+	{
+	  asm1[s] = a0[s] - mpn_sub_n (asm1, a0, a1, s);
+	}
+    }
+
+  /* Compute bsm1.  */
+  if (t == n)
+    {
+      if (mpn_cmp (b0, b1, n) < 0)
+	{
+	  mpn_sub_n (bsm1, b1, b0, n);
+	  vm1_neg ^= 1;
+	}
+      else
+	{
+	  mpn_sub_n (bsm1, b0, b1, n);
+	}
+    }
+  else
+    {
+      if (mpn_zero_p (b0 + t, n - t) && mpn_cmp (b0, b1, t) < 0)
+	{
+	  mpn_sub_n (bsm1, b1, b0, t);
+	  MPN_ZERO (bsm1 + t, n - t);
+	  vm1_neg ^= 1;
+	}
+      else
+	{
+	  mpn_sub (bsm1, b0, n, b1, t);
+	}
+    }
+
+#define v0	pp				/* 2n */
+#define vinf	(pp + 2 * n)			/* s+t */
+#define vm1	scratch				/* 2n */
+#define scratch_out	scratch + 2 * n
+
+  /* vm1, 2n limbs */
+  TOOM22_MUL_N_REC (vm1, asm1, bsm1, n, scratch_out);
+
+  if (s > t)  TOOM22_MUL_REC (vinf, a1, s, b1, t, scratch_out);
+  else        TOOM22_MUL_N_REC (vinf, a1, b1, s, scratch_out);
+
+  /* v0, 2n limbs */
+  TOOM22_MUL_N_REC (v0, ap, bp, n, scratch_out);
+
+  /* H(v0) + L(vinf) */
+  cy = mpn_add_n (pp + 2 * n, v0 + n, vinf, n);
+
+  /* L(v0) + H(v0) */
+  cy2 = cy + mpn_add_n (pp + n, pp + 2 * n, v0, n);
+
+  /* L(vinf) + H(vinf) */
+  cy += mpn_add (pp + 2 * n, pp + 2 * n, n, vinf + n, s + t - n);
+
+  if (vm1_neg)
+    cy += mpn_add_n (pp + n, pp + n, vm1, 2 * n);
+  else {
+    cy -= mpn_sub_n (pp + n, pp + n, vm1, 2 * n);
+    if (UNLIKELY (cy + 1 == 0)) { /* cy is negative */
+      /* The total contribution of v0+vinf-vm1 can not be negative. */
+#if WANT_ASSERT
+      /* The borrow in cy stops the propagation of the carry cy2, */
+      ASSERT (cy2 == 1);
+      cy += mpn_add_1 (pp + 2 * n, pp + 2 * n, n, cy2);
+      ASSERT (cy == 0);
+#else
+      /* we simply fill the area with zeros. */
+      MPN_FILL (pp + 2 * n, n, 0);
+#endif
+      return;
+    }
+  }
+
+  ASSERT (cy  <= 2);
+  ASSERT (cy2 <= 2);
+
+  MPN_INCR_U (pp + 2 * n, s + t, cy2);
+  /* if s+t==n, cy is zero, but we should not access pp[3*n] at all. */
+  MPN_INCR_U (pp + 3 * n, s + t - n, cy);
+}
diff --git a/third_party/gmp/mpn/generic/toom2_sqr.c b/third_party/gmp/mpn/generic/toom2_sqr.c
new file mode 100644
index 0000000..4eaa141
--- /dev/null
+++ b/third_party/gmp/mpn/generic/toom2_sqr.c
@@ -0,0 +1,155 @@
+/* mpn_toom2_sqr -- Square {ap,an}.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2006-2010, 2012, 2014, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+/* Evaluate in: -1, 0, +inf
+
+  <-s--><--n-->
+   ____ ______
+  |_a1_|___a0_|
+
+  v0  =  a0     ^2  #   A(0)^2
+  vm1 = (a0- a1)^2  #  A(-1)^2
+  vinf=      a1 ^2  # A(inf)^2
+*/
+
+#if TUNE_PROGRAM_BUILD || WANT_FAT_BINARY
+#define MAYBE_sqr_toom2   1
+#else
+#define MAYBE_sqr_toom2							\
+  (SQR_TOOM3_THRESHOLD >= 2 * SQR_TOOM2_THRESHOLD)
+#endif
+
+#define TOOM2_SQR_REC(p, a, n, ws)					\
+  do {									\
+    if (! MAYBE_sqr_toom2						\
+	|| BELOW_THRESHOLD (n, SQR_TOOM2_THRESHOLD))			\
+      mpn_sqr_basecase (p, a, n);					\
+    else								\
+      mpn_toom2_sqr (p, a, n, ws);					\
+  } while (0)
+
+void
+mpn_toom2_sqr (mp_ptr pp,
+	       mp_srcptr ap, mp_size_t an,
+	       mp_ptr scratch)
+{
+  const int __gmpn_cpuvec_initialized = 1;
+  mp_size_t n, s;
+  mp_limb_t cy, cy2;
+  mp_ptr asm1;
+
+#define a0  ap
+#define a1  (ap + n)
+
+  s = an >> 1;
+  n = an - s;
+
+  ASSERT (0 < s && s <= n && s >= n - 1);
+
+  asm1 = pp;
+
+  /* Compute asm1.  */
+  if (s == n)
+    {
+      if (mpn_cmp (a0, a1, n) < 0)
+	{
+	  mpn_sub_n (asm1, a1, a0, n);
+	}
+      else
+	{
+	  mpn_sub_n (asm1, a0, a1, n);
+	}
+    }
+  else /* n - s == 1 */
+    {
+      if (a0[s] == 0 && mpn_cmp (a0, a1, s) < 0)
+	{
+	  mpn_sub_n (asm1, a1, a0, s);
+	  asm1[s] = 0;
+	}
+      else
+	{
+	  asm1[s] = a0[s] - mpn_sub_n (asm1, a0, a1, s);
+	}
+    }
+
+#define v0	pp				/* 2n */
+#define vinf	(pp + 2 * n)			/* s+s */
+#define vm1	scratch				/* 2n */
+#define scratch_out	scratch + 2 * n
+
+  /* vm1, 2n limbs */
+  TOOM2_SQR_REC (vm1, asm1, n, scratch_out);
+
+  /* vinf, s+s limbs */
+  TOOM2_SQR_REC (vinf, a1, s, scratch_out);
+
+  /* v0, 2n limbs */
+  TOOM2_SQR_REC (v0, ap, n, scratch_out);
+
+  /* H(v0) + L(vinf) */
+  cy = mpn_add_n (pp + 2 * n, v0 + n, vinf, n);
+
+  /* L(v0) + H(v0) */
+  cy2 = cy + mpn_add_n (pp + n, pp + 2 * n, v0, n);
+
+  /* L(vinf) + H(vinf) */
+  cy += mpn_add (pp + 2 * n, pp + 2 * n, n, vinf + n, s + s - n);
+
+  cy -= mpn_sub_n (pp + n, pp + n, vm1, 2 * n);
+
+  ASSERT (cy + 1 <= 3);
+  ASSERT (cy2 <= 2);
+
+  if (LIKELY (cy <= 2)) {
+    MPN_INCR_U (pp + 2 * n, s + s, cy2);
+    MPN_INCR_U (pp + 3 * n, s + s - n, cy);
+  } else { /* cy is negative */
+    /* The total contribution of v0+vinf-vm1 can not be negative. */
+#if WANT_ASSERT
+    /* The borrow in cy stops the propagation of the carry cy2, */
+    ASSERT (cy2 == 1);
+    cy += mpn_add_1 (pp + 2 * n, pp + 2 * n, n, cy2);
+    ASSERT (cy == 0);
+#else
+    /* we simply fill the area with zeros. */
+    MPN_FILL (pp + 2 * n, n, 0);
+#endif
+  }
+}
diff --git a/third_party/gmp/mpn/generic/toom32_mul.c b/third_party/gmp/mpn/generic/toom32_mul.c
new file mode 100644
index 0000000..f03ba56
--- /dev/null
+++ b/third_party/gmp/mpn/generic/toom32_mul.c
@@ -0,0 +1,322 @@
+/* mpn_toom32_mul -- Multiply {ap,an} and {bp,bn} where an is nominally 1.5
+   times as large as bn.  Or more accurately, bn < an < 3bn.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+   Improvements by Marco Bodrato and Niels Möller.
+
+   The idea of applying toom to unbalanced multiplication is due to Marco
+   Bodrato and Alberto Zanoni.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2006-2010 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+/* Evaluate in: -1, 0, +1, +inf
+
+  <-s-><--n--><--n-->
+   ___ ______ ______
+  |a2_|___a1_|___a0_|
+	|_b1_|___b0_|
+	<-t--><--n-->
+
+  v0  =  a0         * b0      #   A(0)*B(0)
+  v1  = (a0+ a1+ a2)*(b0+ b1) #   A(1)*B(1)      ah  <= 2  bh <= 1
+  vm1 = (a0- a1+ a2)*(b0- b1) #  A(-1)*B(-1)    |ah| <= 1  bh = 0
+  vinf=          a2 *     b1  # A(inf)*B(inf)
+*/
+
+#define TOOM32_MUL_N_REC(p, a, b, n, ws)				\
+  do {									\
+    mpn_mul_n (p, a, b, n);						\
+  } while (0)
+
+void
+mpn_toom32_mul (mp_ptr pp,
+		mp_srcptr ap, mp_size_t an,
+		mp_srcptr bp, mp_size_t bn,
+		mp_ptr scratch)
+{
+  mp_size_t n, s, t;
+  int vm1_neg;
+  mp_limb_t cy;
+  mp_limb_signed_t hi;
+  mp_limb_t ap1_hi, bp1_hi;
+
+#define a0  ap
+#define a1  (ap + n)
+#define a2  (ap + 2 * n)
+#define b0  bp
+#define b1  (bp + n)
+
+  /* Required, to ensure that s + t >= n. */
+  ASSERT (bn + 2 <= an && an + 6 <= 3*bn);
+
+  n = 1 + (2 * an >= 3 * bn ? (an - 1) / (size_t) 3 : (bn - 1) >> 1);
+
+  s = an - 2 * n;
+  t = bn - n;
+
+  ASSERT (0 < s && s <= n);
+  ASSERT (0 < t && t <= n);
+  ASSERT (s + t >= n);
+
+  /* Product area of size an + bn = 3*n + s + t >= 4*n + 2. */
+#define ap1 (pp)		/* n, most significant limb in ap1_hi */
+#define bp1 (pp + n)		/* n, most significant bit in bp1_hi */
+#define am1 (pp + 2*n)		/* n, most significant bit in hi */
+#define bm1 (pp + 3*n)		/* n */
+#define v1 (scratch)		/* 2n + 1 */
+#define vm1 (pp)		/* 2n + 1 */
+#define scratch_out (scratch + 2*n + 1) /* Currently unused. */
+
+  /* Scratch need: 2*n + 1 + scratch for the recursive multiplications. */
+
+  /* FIXME: Keep v1[2*n] and vm1[2*n] in scalar variables? */
+
+  /* Compute ap1 = a0 + a1 + a2, am1 = a0 - a1 + a2 */
+  ap1_hi = mpn_add (ap1, a0, n, a2, s);
+#if HAVE_NATIVE_mpn_add_n_sub_n
+  if (ap1_hi == 0 && mpn_cmp (ap1, a1, n) < 0)
+    {
+      ap1_hi = mpn_add_n_sub_n (ap1, am1, a1, ap1, n) >> 1;
+      hi = 0;
+      vm1_neg = 1;
+    }
+  else
+    {
+      cy = mpn_add_n_sub_n (ap1, am1, ap1, a1, n);
+      hi = ap1_hi - (cy & 1);
+      ap1_hi += (cy >> 1);
+      vm1_neg = 0;
+    }
+#else
+  if (ap1_hi == 0 && mpn_cmp (ap1, a1, n) < 0)
+    {
+      ASSERT_NOCARRY (mpn_sub_n (am1, a1, ap1, n));
+      hi = 0;
+      vm1_neg = 1;
+    }
+  else
+    {
+      hi = ap1_hi - mpn_sub_n (am1, ap1, a1, n);
+      vm1_neg = 0;
+    }
+  ap1_hi += mpn_add_n (ap1, ap1, a1, n);
+#endif
+
+  /* Compute bp1 = b0 + b1 and bm1 = b0 - b1. */
+  if (t == n)
+    {
+#if HAVE_NATIVE_mpn_add_n_sub_n
+      if (mpn_cmp (b0, b1, n) < 0)
+	{
+	  cy = mpn_add_n_sub_n (bp1, bm1, b1, b0, n);
+	  vm1_neg ^= 1;
+	}
+      else
+	{
+	  cy = mpn_add_n_sub_n (bp1, bm1, b0, b1, n);
+	}
+      bp1_hi = cy >> 1;
+#else
+      bp1_hi = mpn_add_n (bp1, b0, b1, n);
+
+      if (mpn_cmp (b0, b1, n) < 0)
+	{
+	  ASSERT_NOCARRY (mpn_sub_n (bm1, b1, b0, n));
+	  vm1_neg ^= 1;
+	}
+      else
+	{
+	  ASSERT_NOCARRY (mpn_sub_n (bm1, b0, b1, n));
+	}
+#endif
+    }
+  else
+    {
+      /* FIXME: Should still use mpn_add_n_sub_n for the main part. */
+      bp1_hi = mpn_add (bp1, b0, n, b1, t);
+
+      if (mpn_zero_p (b0 + t, n - t) && mpn_cmp (b0, b1, t) < 0)
+	{
+	  ASSERT_NOCARRY (mpn_sub_n (bm1, b1, b0, t));
+	  MPN_ZERO (bm1 + t, n - t);
+	  vm1_neg ^= 1;
+	}
+      else
+	{
+	  ASSERT_NOCARRY (mpn_sub (bm1, b0, n, b1, t));
+	}
+    }
+
+  TOOM32_MUL_N_REC (v1, ap1, bp1, n, scratch_out);
+  if (ap1_hi == 1)
+    {
+      cy = bp1_hi + mpn_add_n (v1 + n, v1 + n, bp1, n);
+    }
+  else if (ap1_hi == 2)
+    {
+#if HAVE_NATIVE_mpn_addlsh1_n
+      cy = 2 * bp1_hi + mpn_addlsh1_n (v1 + n, v1 + n, bp1, n);
+#else
+      cy = 2 * bp1_hi + mpn_addmul_1 (v1 + n, bp1, n, CNST_LIMB(2));
+#endif
+    }
+  else
+    cy = 0;
+  if (bp1_hi != 0)
+    cy += mpn_add_n (v1 + n, v1 + n, ap1, n);
+  v1[2 * n] = cy;
+
+  TOOM32_MUL_N_REC (vm1, am1, bm1, n, scratch_out);
+  if (hi)
+    hi = mpn_add_n (vm1+n, vm1+n, bm1, n);
+
+  vm1[2*n] = hi;
+
+  /* v1 <-- (v1 + vm1) / 2 = x0 + x2 */
+  if (vm1_neg)
+    {
+#if HAVE_NATIVE_mpn_rsh1sub_n
+      mpn_rsh1sub_n (v1, v1, vm1, 2*n+1);
+#else
+      mpn_sub_n (v1, v1, vm1, 2*n+1);
+      ASSERT_NOCARRY (mpn_rshift (v1, v1, 2*n+1, 1));
+#endif
+    }
+  else
+    {
+#if HAVE_NATIVE_mpn_rsh1add_n
+      mpn_rsh1add_n (v1, v1, vm1, 2*n+1);
+#else
+      mpn_add_n (v1, v1, vm1, 2*n+1);
+      ASSERT_NOCARRY (mpn_rshift (v1, v1, 2*n+1, 1));
+#endif
+    }
+
+  /* We get x1 + x3 = (x0 + x2) - (x0 - x1 + x2 - x3), and hence
+
+     y = x1 + x3 + (x0 + x2) * B
+       = (x0 + x2) * B + (x0 + x2) - vm1.
+
+     y is 3*n + 1 limbs, y = y0 + y1 B + y2 B^2. We store them as
+     follows: y0 at scratch, y1 at pp + 2*n, and y2 at scratch + n
+     (already in place, except for carry propagation).
+
+     We thus add
+
+   B^3  B^2   B    1
+    |    |    |    |
+   +-----+----+
+ + |  x0 + x2 |
+   +----+-----+----+
+ +      |  x0 + x2 |
+	+----------+
+ -      |  vm1     |
+ --+----++----+----+-
+   | y2  | y1 | y0 |
+   +-----+----+----+
+
+  Since we store y0 at the same location as the low half of x0 + x2, we
+  need to do the middle sum first. */
+
+  hi = vm1[2*n];
+  cy = mpn_add_n (pp + 2*n, v1, v1 + n, n);
+  MPN_INCR_U (v1 + n, n + 1, cy + v1[2*n]);
+
+  /* FIXME: Can we get rid of this second vm1_neg conditional by
+     swapping the location of +1 and -1 values? */
+  if (vm1_neg)
+    {
+      cy = mpn_add_n (v1, v1, vm1, n);
+      hi += mpn_add_nc (pp + 2*n, pp + 2*n, vm1 + n, n, cy);
+      MPN_INCR_U (v1 + n, n+1, hi);
+    }
+  else
+    {
+      cy = mpn_sub_n (v1, v1, vm1, n);
+      hi += mpn_sub_nc (pp + 2*n, pp + 2*n, vm1 + n, n, cy);
+      MPN_DECR_U (v1 + n, n+1, hi);
+    }
+
+  TOOM32_MUL_N_REC (pp, a0, b0, n, scratch_out);
+  /* vinf, s+t limbs.  Use mpn_mul for now, to handle unbalanced operands */
+  if (s > t)  mpn_mul (pp+3*n, a2, s, b1, t);
+  else        mpn_mul (pp+3*n, b1, t, a2, s);
+
+  /* Remaining interpolation.
+
+     y * B + x0 + x3 B^3 - x0 B^2 - x3 B
+     = (x1 + x3) B + (x0 + x2) B^2 + x0 + x3 B^3 - x0 B^2 - x3 B
+     = y0 B + y1 B^2 + y3 B^3 + Lx0 + H x0 B
+       + L x3 B^3 + H x3 B^4 - Lx0 B^2 - H x0 B^3 - L x3 B - H x3 B^2
+     = L x0 + (y0 + H x0 - L x3) B + (y1 - L x0 - H x3) B^2
+       + (y2 - (H x0 - L x3)) B^3 + H x3 B^4
+
+	  B^4       B^3       B^2        B         1
+ |         |         |         |         |         |
+   +-------+                   +---------+---------+
+   |  Hx3  |                   | Hx0-Lx3 |    Lx0  |
+   +------+----------+---------+---------+---------+
+	  |    y2    |  y1     |   y0    |
+	  ++---------+---------+---------+
+	  -| Hx0-Lx3 | - Lx0   |
+	   +---------+---------+
+		      | - Hx3  |
+		      +--------+
+
+    We must take into account the carry from Hx0 - Lx3.
+  */
+
+  cy = mpn_sub_n (pp + n, pp + n, pp+3*n, n);
+  hi = scratch[2*n] + cy;
+
+  cy = mpn_sub_nc (pp + 2*n, pp + 2*n, pp, n, cy);
+  hi -= mpn_sub_nc (pp + 3*n, scratch + n, pp + n, n, cy);
+
+  hi += mpn_add (pp + n, pp + n, 3*n, scratch, n);
+
+  /* FIXME: Is support for s + t == n needed? */
+  if (LIKELY (s + t > n))
+    {
+      hi -= mpn_sub (pp + 2*n, pp + 2*n, 2*n, pp + 4*n, s+t-n);
+
+      if (hi < 0)
+	MPN_DECR_U (pp + 4*n, s+t-n, -hi);
+      else
+	MPN_INCR_U (pp + 4*n, s+t-n, hi);
+    }
+  else
+    ASSERT (hi == 0);
+}
diff --git a/third_party/gmp/mpn/generic/toom33_mul.c b/third_party/gmp/mpn/generic/toom33_mul.c
new file mode 100644
index 0000000..8f49f42
--- /dev/null
+++ b/third_party/gmp/mpn/generic/toom33_mul.c
@@ -0,0 +1,315 @@
+/* mpn_toom33_mul -- Multiply {ap,an} and {p,bn} where an and bn are close in
+   size.  Or more accurately, bn <= an < (3/2)bn.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+   Additional improvements by Marco Bodrato.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2006-2008, 2010, 2012, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+/* Evaluate in: -1, 0, +1, +2, +inf
+
+  <-s--><--n--><--n-->
+   ____ ______ ______
+  |_a2_|___a1_|___a0_|
+   |b2_|___b1_|___b0_|
+   <-t-><--n--><--n-->
+
+  v0  =  a0         * b0          #   A(0)*B(0)
+  v1  = (a0+ a1+ a2)*(b0+ b1+ b2) #   A(1)*B(1)      ah  <= 2  bh <= 2
+  vm1 = (a0- a1+ a2)*(b0- b1+ b2) #  A(-1)*B(-1)    |ah| <= 1  bh <= 1
+  v2  = (a0+2a1+4a2)*(b0+2b1+4b2) #   A(2)*B(2)      ah  <= 6  bh <= 6
+  vinf=          a2 *         b2  # A(inf)*B(inf)
+*/
+
+#if TUNE_PROGRAM_BUILD || WANT_FAT_BINARY
+#define MAYBE_mul_basecase 1
+#define MAYBE_mul_toom33   1
+#else
+#define MAYBE_mul_basecase						\
+  (MUL_TOOM33_THRESHOLD < 3 * MUL_TOOM22_THRESHOLD)
+#define MAYBE_mul_toom33						\
+  (MUL_TOOM44_THRESHOLD >= 3 * MUL_TOOM33_THRESHOLD)
+#endif
+
+/* FIXME: TOOM33_MUL_N_REC is not quite right for a balanced
+   multiplication at the infinity point. We may have
+   MAYBE_mul_basecase == 0, and still get s just below
+   MUL_TOOM22_THRESHOLD. If MUL_TOOM33_THRESHOLD == 7, we can even get
+   s == 1 and mpn_toom22_mul will crash.
+*/
+
+#define TOOM33_MUL_N_REC(p, a, b, n, ws)				\
+  do {									\
+    if (MAYBE_mul_basecase						\
+	&& BELOW_THRESHOLD (n, MUL_TOOM22_THRESHOLD))			\
+      mpn_mul_basecase (p, a, n, b, n);					\
+    else if (! MAYBE_mul_toom33						\
+	     || BELOW_THRESHOLD (n, MUL_TOOM33_THRESHOLD))		\
+      mpn_toom22_mul (p, a, n, b, n, ws);				\
+    else								\
+      mpn_toom33_mul (p, a, n, b, n, ws);				\
+  } while (0)
+
+void
+mpn_toom33_mul (mp_ptr pp,
+		mp_srcptr ap, mp_size_t an,
+		mp_srcptr bp, mp_size_t bn,
+		mp_ptr scratch)
+{
+  const int __gmpn_cpuvec_initialized = 1;
+  mp_size_t n, s, t;
+  int vm1_neg;
+  mp_limb_t cy, vinf0;
+  mp_ptr gp;
+  mp_ptr as1, asm1, as2;
+  mp_ptr bs1, bsm1, bs2;
+
+#define a0  ap
+#define a1  (ap + n)
+#define a2  (ap + 2*n)
+#define b0  bp
+#define b1  (bp + n)
+#define b2  (bp + 2*n)
+
+  n = (an + 2) / (size_t) 3;
+
+  s = an - 2 * n;
+  t = bn - 2 * n;
+
+  ASSERT (an >= bn);
+
+  ASSERT (0 < s && s <= n);
+  ASSERT (0 < t && t <= n);
+
+  as1  = scratch + 4 * n + 4;
+  asm1 = scratch + 2 * n + 2;
+  as2 = pp + n + 1;
+
+  bs1 = pp;
+  bsm1 = scratch + 3 * n + 3; /* we need 4n+4 <= 4n+s+t */
+  bs2 = pp + 2 * n + 2;
+
+  gp = scratch;
+
+  vm1_neg = 0;
+
+  /* Compute as1 and asm1.  */
+  cy = mpn_add (gp, a0, n, a2, s);
+#if HAVE_NATIVE_mpn_add_n_sub_n
+  if (cy == 0 && mpn_cmp (gp, a1, n) < 0)
+    {
+      cy = mpn_add_n_sub_n (as1, asm1, a1, gp, n);
+      as1[n] = cy >> 1;
+      asm1[n] = 0;
+      vm1_neg = 1;
+    }
+  else
+    {
+      mp_limb_t cy2;
+      cy2 = mpn_add_n_sub_n (as1, asm1, gp, a1, n);
+      as1[n] = cy + (cy2 >> 1);
+      asm1[n] = cy - (cy2 & 1);
+    }
+#else
+  as1[n] = cy + mpn_add_n (as1, gp, a1, n);
+  if (cy == 0 && mpn_cmp (gp, a1, n) < 0)
+    {
+      mpn_sub_n (asm1, a1, gp, n);
+      asm1[n] = 0;
+      vm1_neg = 1;
+    }
+  else
+    {
+      cy -= mpn_sub_n (asm1, gp, a1, n);
+      asm1[n] = cy;
+    }
+#endif
+
+  /* Compute as2.  */
+#if HAVE_NATIVE_mpn_rsblsh1_n
+  cy = mpn_add_n (as2, a2, as1, s);
+  if (s != n)
+    cy = mpn_add_1 (as2 + s, as1 + s, n - s, cy);
+  cy += as1[n];
+  cy = 2 * cy + mpn_rsblsh1_n (as2, a0, as2, n);
+#else
+#if HAVE_NATIVE_mpn_addlsh1_n
+  cy  = mpn_addlsh1_n (as2, a1, a2, s);
+  if (s != n)
+    cy = mpn_add_1 (as2 + s, a1 + s, n - s, cy);
+  cy = 2 * cy + mpn_addlsh1_n (as2, a0, as2, n);
+#else
+  cy = mpn_add_n (as2, a2, as1, s);
+  if (s != n)
+    cy = mpn_add_1 (as2 + s, as1 + s, n - s, cy);
+  cy += as1[n];
+  cy = 2 * cy + mpn_lshift (as2, as2, n, 1);
+  cy -= mpn_sub_n (as2, as2, a0, n);
+#endif
+#endif
+  as2[n] = cy;
+
+  /* Compute bs1 and bsm1.  */
+  cy = mpn_add (gp, b0, n, b2, t);
+#if HAVE_NATIVE_mpn_add_n_sub_n
+  if (cy == 0 && mpn_cmp (gp, b1, n) < 0)
+    {
+      cy = mpn_add_n_sub_n (bs1, bsm1, b1, gp, n);
+      bs1[n] = cy >> 1;
+      bsm1[n] = 0;
+      vm1_neg ^= 1;
+    }
+  else
+    {
+      mp_limb_t cy2;
+      cy2 = mpn_add_n_sub_n (bs1, bsm1, gp, b1, n);
+      bs1[n] = cy + (cy2 >> 1);
+      bsm1[n] = cy - (cy2 & 1);
+    }
+#else
+  bs1[n] = cy + mpn_add_n (bs1, gp, b1, n);
+  if (cy == 0 && mpn_cmp (gp, b1, n) < 0)
+    {
+      mpn_sub_n (bsm1, b1, gp, n);
+      bsm1[n] = 0;
+      vm1_neg ^= 1;
+    }
+  else
+    {
+      cy -= mpn_sub_n (bsm1, gp, b1, n);
+      bsm1[n] = cy;
+    }
+#endif
+
+  /* Compute bs2.  */
+#if HAVE_NATIVE_mpn_rsblsh1_n
+  cy = mpn_add_n (bs2, b2, bs1, t);
+  if (t != n)
+    cy = mpn_add_1 (bs2 + t, bs1 + t, n - t, cy);
+  cy += bs1[n];
+  cy = 2 * cy + mpn_rsblsh1_n (bs2, b0, bs2, n);
+#else
+#if HAVE_NATIVE_mpn_addlsh1_n
+  cy  = mpn_addlsh1_n (bs2, b1, b2, t);
+  if (t != n)
+    cy = mpn_add_1 (bs2 + t, b1 + t, n - t, cy);
+  cy = 2 * cy + mpn_addlsh1_n (bs2, b0, bs2, n);
+#else
+  cy  = mpn_add_n (bs2, bs1, b2, t);
+  if (t != n)
+    cy = mpn_add_1 (bs2 + t, bs1 + t, n - t, cy);
+  cy += bs1[n];
+  cy = 2 * cy + mpn_lshift (bs2, bs2, n, 1);
+  cy -= mpn_sub_n (bs2, bs2, b0, n);
+#endif
+#endif
+  bs2[n] = cy;
+
+  ASSERT (as1[n] <= 2);
+  ASSERT (bs1[n] <= 2);
+  ASSERT (asm1[n] <= 1);
+  ASSERT (bsm1[n] <= 1);
+  ASSERT (as2[n] <= 6);
+  ASSERT (bs2[n] <= 6);
+
+#define v0    pp				/* 2n */
+#define v1    (pp + 2 * n)			/* 2n+1 */
+#define vinf  (pp + 4 * n)			/* s+t */
+#define vm1   scratch				/* 2n+1 */
+#define v2    (scratch + 2 * n + 1)		/* 2n+2 */
+#define scratch_out  (scratch + 5 * n + 5)
+
+  /* vm1, 2n+1 limbs */
+#ifdef SMALLER_RECURSION
+  TOOM33_MUL_N_REC (vm1, asm1, bsm1, n, scratch_out);
+  cy = 0;
+  if (asm1[n] != 0)
+    cy = bsm1[n] + mpn_add_n (vm1 + n, vm1 + n, bsm1, n);
+  if (bsm1[n] != 0)
+    cy += mpn_add_n (vm1 + n, vm1 + n, asm1, n);
+  vm1[2 * n] = cy;
+#else
+  TOOM33_MUL_N_REC (vm1, asm1, bsm1, n + 1, scratch_out);
+#endif
+
+  TOOM33_MUL_N_REC (v2, as2, bs2, n + 1, scratch_out);	/* v2, 2n+1 limbs */
+
+  /* vinf, s+t limbs */
+  if (s > t)  mpn_mul (vinf, a2, s, b2, t);
+  else        TOOM33_MUL_N_REC (vinf, a2, b2, s, scratch_out);
+
+  vinf0 = vinf[0];				/* v1 overlaps with this */
+
+#ifdef SMALLER_RECURSION
+  /* v1, 2n+1 limbs */
+  TOOM33_MUL_N_REC (v1, as1, bs1, n, scratch_out);
+  if (as1[n] == 1)
+    {
+      cy = bs1[n] + mpn_add_n (v1 + n, v1 + n, bs1, n);
+    }
+  else if (as1[n] != 0)
+    {
+#if HAVE_NATIVE_mpn_addlsh1_n_ip1
+      cy = 2 * bs1[n] + mpn_addlsh1_n_ip1 (v1 + n, bs1, n);
+#else
+      cy = 2 * bs1[n] + mpn_addmul_1 (v1 + n, bs1, n, CNST_LIMB(2));
+#endif
+    }
+  else
+    cy = 0;
+  if (bs1[n] == 1)
+    {
+      cy += mpn_add_n (v1 + n, v1 + n, as1, n);
+    }
+  else if (bs1[n] != 0)
+    {
+#if HAVE_NATIVE_mpn_addlsh1_n_ip1
+      cy += mpn_addlsh1_n_ip1 (v1 + n, as1, n);
+#else
+      cy += mpn_addmul_1 (v1 + n, as1, n, CNST_LIMB(2));
+#endif
+    }
+  v1[2 * n] = cy;
+#else
+  cy = vinf[1];
+  TOOM33_MUL_N_REC (v1, as1, bs1, n + 1, scratch_out);
+  vinf[1] = cy;
+#endif
+
+  TOOM33_MUL_N_REC (v0, ap, bp, n, scratch_out);	/* v0, 2n limbs */
+
+  mpn_toom_interpolate_5pts (pp, v2, vm1, n, s + t, vm1_neg, vinf0);
+}
diff --git a/third_party/gmp/mpn/generic/toom3_sqr.c b/third_party/gmp/mpn/generic/toom3_sqr.c
new file mode 100644
index 0000000..7be15bf
--- /dev/null
+++ b/third_party/gmp/mpn/generic/toom3_sqr.c
@@ -0,0 +1,225 @@
+/* mpn_toom3_sqr -- Square {ap,an}.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+   Additional improvements by Marco Bodrato.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2006-2010, 2012, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+/* Evaluate in: -1, 0, +1, +2, +inf
+
+  <-s--><--n--><--n-->
+   ____ ______ ______
+  |_a2_|___a1_|___a0_|
+
+  v0  =  a0         ^2 #   A(0)^2
+  v1  = (a0+ a1+ a2)^2 #   A(1)^2    ah  <= 2
+  vm1 = (a0- a1+ a2)^2 #  A(-1)^2   |ah| <= 1
+  v2  = (a0+2a1+4a2)^2 #   A(2)^2    ah  <= 6
+  vinf=          a2 ^2 # A(inf)^2
+*/
+
+#if TUNE_PROGRAM_BUILD || WANT_FAT_BINARY
+#define MAYBE_sqr_basecase 1
+#define MAYBE_sqr_toom3   1
+#else
+#define MAYBE_sqr_basecase						\
+  (SQR_TOOM3_THRESHOLD < 3 * SQR_TOOM2_THRESHOLD)
+#define MAYBE_sqr_toom3							\
+  (SQR_TOOM4_THRESHOLD >= 3 * SQR_TOOM3_THRESHOLD)
+#endif
+
+#define TOOM3_SQR_REC(p, a, n, ws)					\
+  do {									\
+    if (MAYBE_sqr_basecase						\
+	&& BELOW_THRESHOLD (n, SQR_TOOM2_THRESHOLD))			\
+      mpn_sqr_basecase (p, a, n);					\
+    else if (! MAYBE_sqr_toom3						\
+	     || BELOW_THRESHOLD (n, SQR_TOOM3_THRESHOLD))		\
+      mpn_toom2_sqr (p, a, n, ws);					\
+    else								\
+      mpn_toom3_sqr (p, a, n, ws);					\
+  } while (0)
+
+void
+mpn_toom3_sqr (mp_ptr pp,
+	       mp_srcptr ap, mp_size_t an,
+	       mp_ptr scratch)
+{
+  const int __gmpn_cpuvec_initialized = 1;
+  mp_size_t n, s;
+  mp_limb_t cy, vinf0;
+  mp_ptr gp;
+  mp_ptr as1, asm1, as2;
+
+#define a0  ap
+#define a1  (ap + n)
+#define a2  (ap + 2*n)
+
+  n = (an + 2) / (size_t) 3;
+
+  s = an - 2 * n;
+
+  ASSERT (0 < s && s <= n);
+
+  as1 = scratch + 4 * n + 4;
+  asm1 = scratch + 2 * n + 2;
+  as2 = pp + n + 1;
+
+  gp = scratch;
+
+  /* Compute as1 and asm1.  */
+  cy = mpn_add (gp, a0, n, a2, s);
+#if HAVE_NATIVE_mpn_add_n_sub_n
+  if (cy == 0 && mpn_cmp (gp, a1, n) < 0)
+    {
+      cy = mpn_add_n_sub_n (as1, asm1, a1, gp, n);
+      as1[n] = cy >> 1;
+      asm1[n] = 0;
+    }
+  else
+    {
+      mp_limb_t cy2;
+      cy2 = mpn_add_n_sub_n (as1, asm1, gp, a1, n);
+      as1[n] = cy + (cy2 >> 1);
+      asm1[n] = cy - (cy2 & 1);
+    }
+#else
+  as1[n] = cy + mpn_add_n (as1, gp, a1, n);
+  if (cy == 0 && mpn_cmp (gp, a1, n) < 0)
+    {
+      mpn_sub_n (asm1, a1, gp, n);
+      asm1[n] = 0;
+    }
+  else
+    {
+      cy -= mpn_sub_n (asm1, gp, a1, n);
+      asm1[n] = cy;
+    }
+#endif
+
+  /* Compute as2.  */
+#if HAVE_NATIVE_mpn_rsblsh1_n
+  cy = mpn_add_n (as2, a2, as1, s);
+  if (s != n)
+    cy = mpn_add_1 (as2 + s, as1 + s, n - s, cy);
+  cy += as1[n];
+  cy = 2 * cy + mpn_rsblsh1_n (as2, a0, as2, n);
+#else
+#if HAVE_NATIVE_mpn_addlsh1_n
+  cy  = mpn_addlsh1_n (as2, a1, a2, s);
+  if (s != n)
+    cy = mpn_add_1 (as2 + s, a1 + s, n - s, cy);
+  cy = 2 * cy + mpn_addlsh1_n (as2, a0, as2, n);
+#else
+  cy = mpn_add_n (as2, a2, as1, s);
+  if (s != n)
+    cy = mpn_add_1 (as2 + s, as1 + s, n - s, cy);
+  cy += as1[n];
+  cy = 2 * cy + mpn_lshift (as2, as2, n, 1);
+  cy -= mpn_sub_n (as2, as2, a0, n);
+#endif
+#endif
+  as2[n] = cy;
+
+  ASSERT (as1[n] <= 2);
+  ASSERT (asm1[n] <= 1);
+
+#define v0    pp				/* 2n */
+#define v1    (pp + 2 * n)			/* 2n+1 */
+#define vinf  (pp + 4 * n)			/* s+s */
+#define vm1   scratch				/* 2n+1 */
+#define v2    (scratch + 2 * n + 1)		/* 2n+2 */
+#define scratch_out  (scratch + 5 * n + 5)
+
+  /* vm1, 2n+1 limbs */
+#ifdef SMALLER_RECURSION
+  TOOM3_SQR_REC (vm1, asm1, n, scratch_out);
+  cy = 0;
+  if (asm1[n] != 0)
+    cy = asm1[n] + mpn_add_n (vm1 + n, vm1 + n, asm1, n);
+  if (asm1[n] != 0)
+    cy += mpn_add_n (vm1 + n, vm1 + n, asm1, n);
+  vm1[2 * n] = cy;
+#else
+  TOOM3_SQR_REC (vm1, asm1, n + 1, scratch_out);
+#endif
+
+  TOOM3_SQR_REC (v2, as2, n + 1, scratch_out);	/* v2, 2n+1 limbs */
+
+  TOOM3_SQR_REC (vinf, a2, s, scratch_out);	/* vinf, s+s limbs */
+
+  vinf0 = vinf[0];				/* v1 overlaps with this */
+
+#ifdef SMALLER_RECURSION
+  /* v1, 2n+1 limbs */
+  TOOM3_SQR_REC (v1, as1, n, scratch_out);
+  if (as1[n] == 1)
+    {
+      cy = as1[n] + mpn_add_n (v1 + n, v1 + n, as1, n);
+    }
+  else if (as1[n] != 0)
+    {
+#if HAVE_NATIVE_mpn_addlsh1_n_ip1
+      cy = 2 * as1[n] + mpn_addlsh1_n_ip1 (v1 + n, as1, n);
+#else
+      cy = 2 * as1[n] + mpn_addmul_1 (v1 + n, as1, n, CNST_LIMB(2));
+#endif
+    }
+  else
+    cy = 0;
+  if (as1[n] == 1)
+    {
+      cy += mpn_add_n (v1 + n, v1 + n, as1, n);
+    }
+  else if (as1[n] != 0)
+    {
+#if HAVE_NATIVE_mpn_addlsh1_n_ip1
+      cy += mpn_addlsh1_n_ip1 (v1 + n, as1, n);
+#else
+      cy += mpn_addmul_1 (v1 + n, as1, n, CNST_LIMB(2));
+#endif
+    }
+  v1[2 * n] = cy;
+#else
+  cy = vinf[1];
+  TOOM3_SQR_REC (v1, as1, n + 1, scratch_out);
+  vinf[1] = cy;
+#endif
+
+  TOOM3_SQR_REC (v0, ap, n, scratch_out);	/* v0, 2n limbs */
+
+  mpn_toom_interpolate_5pts (pp, v2, vm1, n, s + s, 0, vinf0);
+}
diff --git a/third_party/gmp/mpn/generic/toom42_mul.c b/third_party/gmp/mpn/generic/toom42_mul.c
new file mode 100644
index 0000000..2dfba9b
--- /dev/null
+++ b/third_party/gmp/mpn/generic/toom42_mul.c
@@ -0,0 +1,234 @@
+/* mpn_toom42_mul -- Multiply {ap,an} and {bp,bn} where an is nominally twice
+   as large as bn.  Or more accurately, (3/2)bn < an < 4bn.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+   Additional improvements by Marco Bodrato.
+
+   The idea of applying toom to unbalanced multiplication is due to Marco
+   Bodrato and Alberto Zanoni.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2006-2008, 2012, 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+/* Evaluate in: -1, 0, +1, +2, +inf
+
+  <-s-><--n--><--n--><--n-->
+   ___ ______ ______ ______
+  |a3_|___a2_|___a1_|___a0_|
+	       |_b1_|___b0_|
+	       <-t--><--n-->
+
+  v0  =  a0             * b0      #   A(0)*B(0)
+  v1  = (a0+ a1+ a2+ a3)*(b0+ b1) #   A(1)*B(1)      ah  <= 3  bh <= 1
+  vm1 = (a0- a1+ a2- a3)*(b0- b1) #  A(-1)*B(-1)    |ah| <= 1  bh  = 0
+  v2  = (a0+2a1+4a2+8a3)*(b0+2b1) #   A(2)*B(2)      ah  <= 14 bh <= 2
+  vinf=              a3 *     b1  # A(inf)*B(inf)
+*/
+
+#define TOOM42_MUL_N_REC(p, a, b, n, ws)				\
+  do {									\
+    mpn_mul_n (p, a, b, n);						\
+  } while (0)
+
+void
+mpn_toom42_mul (mp_ptr pp,
+		mp_srcptr ap, mp_size_t an,
+		mp_srcptr bp, mp_size_t bn,
+		mp_ptr scratch)
+{
+  mp_size_t n, s, t;
+  int vm1_neg;
+  mp_limb_t cy, vinf0;
+  mp_ptr a0_a2;
+  mp_ptr as1, asm1, as2;
+  mp_ptr bs1, bsm1, bs2;
+  mp_ptr tmp;
+  TMP_DECL;
+
+#define a0  ap
+#define a1  (ap + n)
+#define a2  (ap + 2*n)
+#define a3  (ap + 3*n)
+#define b0  bp
+#define b1  (bp + n)
+
+  n = an >= 2 * bn ? (an + 3) >> 2 : (bn + 1) >> 1;
+
+  s = an - 3 * n;
+  t = bn - n;
+
+  ASSERT (0 < s && s <= n);
+  ASSERT (0 < t && t <= n);
+
+  TMP_MARK;
+
+  tmp = TMP_ALLOC_LIMBS (6 * n + 5);
+  as1  = tmp; tmp += n + 1;
+  asm1 = tmp; tmp += n + 1;
+  as2  = tmp; tmp += n + 1;
+  bs1  = tmp; tmp += n + 1;
+  bsm1 = tmp; tmp += n;
+  bs2  = tmp; tmp += n + 1;
+
+  a0_a2 = pp;
+
+  /* Compute as1 and asm1.  */
+  vm1_neg = mpn_toom_eval_dgr3_pm1 (as1, asm1, ap, n, s, a0_a2) & 1;
+
+  /* Compute as2.  */
+#if HAVE_NATIVE_mpn_addlsh1_n
+  cy  = mpn_addlsh1_n (as2, a2, a3, s);
+  if (s != n)
+    cy = mpn_add_1 (as2 + s, a2 + s, n - s, cy);
+  cy = 2 * cy + mpn_addlsh1_n (as2, a1, as2, n);
+  cy = 2 * cy + mpn_addlsh1_n (as2, a0, as2, n);
+#else
+  cy  = mpn_lshift (as2, a3, s, 1);
+  cy += mpn_add_n (as2, a2, as2, s);
+  if (s != n)
+    cy = mpn_add_1 (as2 + s, a2 + s, n - s, cy);
+  cy = 2 * cy + mpn_lshift (as2, as2, n, 1);
+  cy += mpn_add_n (as2, a1, as2, n);
+  cy = 2 * cy + mpn_lshift (as2, as2, n, 1);
+  cy += mpn_add_n (as2, a0, as2, n);
+#endif
+  as2[n] = cy;
+
+  /* Compute bs1 and bsm1.  */
+  if (t == n)
+    {
+#if HAVE_NATIVE_mpn_add_n_sub_n
+      if (mpn_cmp (b0, b1, n) < 0)
+	{
+	  cy = mpn_add_n_sub_n (bs1, bsm1, b1, b0, n);
+	  vm1_neg ^= 1;
+	}
+      else
+	{
+	  cy = mpn_add_n_sub_n (bs1, bsm1, b0, b1, n);
+	}
+      bs1[n] = cy >> 1;
+#else
+      bs1[n] = mpn_add_n (bs1, b0, b1, n);
+
+      if (mpn_cmp (b0, b1, n) < 0)
+	{
+	  mpn_sub_n (bsm1, b1, b0, n);
+	  vm1_neg ^= 1;
+	}
+      else
+	{
+	  mpn_sub_n (bsm1, b0, b1, n);
+	}
+#endif
+    }
+  else
+    {
+      bs1[n] = mpn_add (bs1, b0, n, b1, t);
+
+      if (mpn_zero_p (b0 + t, n - t) && mpn_cmp (b0, b1, t) < 0)
+	{
+	  mpn_sub_n (bsm1, b1, b0, t);
+	  MPN_ZERO (bsm1 + t, n - t);
+	  vm1_neg ^= 1;
+	}
+      else
+	{
+	  mpn_sub (bsm1, b0, n, b1, t);
+	}
+    }
+
+  /* Compute bs2, recycling bs1. bs2=bs1+b1  */
+  mpn_add (bs2, bs1, n + 1, b1, t);
+
+  ASSERT (as1[n] <= 3);
+  ASSERT (bs1[n] <= 1);
+  ASSERT (asm1[n] <= 1);
+/*ASSERT (bsm1[n] == 0);*/
+  ASSERT (as2[n] <= 14);
+  ASSERT (bs2[n] <= 2);
+
+#define v0    pp				/* 2n */
+#define v1    (pp + 2 * n)			/* 2n+1 */
+#define vinf  (pp + 4 * n)			/* s+t */
+#define vm1   scratch				/* 2n+1 */
+#define v2    (scratch + 2 * n + 1)		/* 2n+2 */
+#define scratch_out	scratch + 4 * n + 4	/* Currently unused. */
+
+  /* vm1, 2n+1 limbs */
+  TOOM42_MUL_N_REC (vm1, asm1, bsm1, n, scratch_out);
+  cy = 0;
+  if (asm1[n] != 0)
+    cy = mpn_add_n (vm1 + n, vm1 + n, bsm1, n);
+  vm1[2 * n] = cy;
+
+  TOOM42_MUL_N_REC (v2, as2, bs2, n + 1, scratch_out);	/* v2, 2n+1 limbs */
+
+  /* vinf, s+t limbs */
+  if (s > t)  mpn_mul (vinf, a3, s, b1, t);
+  else        mpn_mul (vinf, b1, t, a3, s);
+
+  vinf0 = vinf[0];				/* v1 overlaps with this */
+
+  /* v1, 2n+1 limbs */
+  TOOM42_MUL_N_REC (v1, as1, bs1, n, scratch_out);
+  if (as1[n] == 1)
+    {
+      cy = bs1[n] + mpn_add_n (v1 + n, v1 + n, bs1, n);
+    }
+  else if (as1[n] == 2)
+    {
+#if HAVE_NATIVE_mpn_addlsh1_n
+      cy = 2 * bs1[n] + mpn_addlsh1_n (v1 + n, v1 + n, bs1, n);
+#else
+      cy = 2 * bs1[n] + mpn_addmul_1 (v1 + n, bs1, n, CNST_LIMB(2));
+#endif
+    }
+  else if (as1[n] == 3)
+    {
+      cy = 3 * bs1[n] + mpn_addmul_1 (v1 + n, bs1, n, CNST_LIMB(3));
+    }
+  else
+    cy = 0;
+  if (bs1[n] != 0)
+    cy += mpn_add_n (v1 + n, v1 + n, as1, n);
+  v1[2 * n] = cy;
+
+  TOOM42_MUL_N_REC (v0, ap, bp, n, scratch_out);	/* v0, 2n limbs */
+
+  mpn_toom_interpolate_5pts (pp, v2, vm1, n, s + t, vm1_neg, vinf0);
+
+  TMP_FREE;
+}
diff --git a/third_party/gmp/mpn/generic/toom42_mulmid.c b/third_party/gmp/mpn/generic/toom42_mulmid.c
new file mode 100644
index 0000000..f581b10
--- /dev/null
+++ b/third_party/gmp/mpn/generic/toom42_mulmid.c
@@ -0,0 +1,237 @@
+/* mpn_toom42_mulmid -- toom42 middle product
+
+   Contributed by David Harvey.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT'LL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+
+
+/*
+  Middle product of {ap,2n-1} and {bp,n}, output written to {rp,n+2}.
+
+  Neither ap nor bp may overlap rp.
+
+  Must have n >= 4.
+
+  Amount of scratch space required is given by mpn_toom42_mulmid_itch().
+
+  FIXME: this code assumes that n is small compared to GMP_NUMB_MAX. The exact
+  requirements should be clarified.
+*/
+void
+mpn_toom42_mulmid (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n,
+                   mp_ptr scratch)
+{
+  mp_limb_t cy, e[12], zh, zl;
+  mp_size_t m;
+  int neg;
+
+  ASSERT (n >= 4);
+  ASSERT (! MPN_OVERLAP_P (rp, n + 2, ap, 2*n - 1));
+  ASSERT (! MPN_OVERLAP_P (rp, n + 2, bp, n));
+
+  ap += n & 1;   /* handle odd row and diagonal later */
+  m = n / 2;
+
+  /* (e0h:e0l) etc are correction terms, in 2's complement */
+#define e0l (e[0])
+#define e0h (e[1])
+#define e1l (e[2])
+#define e1h (e[3])
+#define e2l (e[4])
+#define e2h (e[5])
+#define e3l (e[6])
+#define e3h (e[7])
+#define e4l (e[8])
+#define e4h (e[9])
+#define e5l (e[10])
+#define e5h (e[11])
+
+#define s (scratch + 2)
+#define t (rp + m + 2)
+#define p0 rp
+#define p1 scratch
+#define p2 (rp + m)
+#define next_scratch (scratch + 3*m + 1)
+
+  /*
+            rp                            scratch
+  |---------|-----------|    |---------|---------|----------|
+  0         m         2m+2   0         m         2m        3m+1
+            <----p2---->       <-------------s------------->
+  <----p0----><---t---->     <----p1---->
+  */
+
+  /* compute {s,3m-1} = {a,3m-1} + {a+m,3m-1} and error terms e0, e1, e2, e3 */
+  cy = mpn_add_err1_n (s, ap, ap + m, &e0l, bp + m, m - 1, 0);
+  cy = mpn_add_err2_n (s + m - 1, ap + m - 1, ap + 2*m - 1, &e1l,
+		       bp + m, bp, m, cy);
+  mpn_add_err1_n (s + 2*m - 1, ap + 2*m - 1, ap + 3*m - 1, &e3l, bp, m, cy);
+
+  /* compute t = (-1)^neg * ({b,m} - {b+m,m}) and error terms e4, e5 */
+  if (mpn_cmp (bp + m, bp, m) < 0)
+    {
+      ASSERT_NOCARRY (mpn_sub_err2_n (t, bp, bp + m, &e4l,
+				      ap + m - 1, ap + 2*m - 1, m, 0));
+      neg = 1;
+    }
+  else
+    {
+      ASSERT_NOCARRY (mpn_sub_err2_n (t, bp + m, bp, &e4l,
+				      ap + m - 1, ap + 2*m - 1, m, 0));
+      neg = 0;
+    }
+
+  /* recursive middle products. The picture is:
+
+      b[2m-1]   A   A   A   B   B   B   -   -   -   -   -
+      ...       -   A   A   A   B   B   B   -   -   -   -
+      b[m]      -   -   A   A   A   B   B   B   -   -   -
+      b[m-1]    -   -   -   C   C   C   D   D   D   -   -
+      ...       -   -   -   -   C   C   C   D   D   D   -
+      b[0]      -   -   -   -   -   C   C   C   D   D   D
+               a[0]   ...  a[m]  ...  a[2m]    ...    a[4m-2]
+  */
+
+  if (m < MULMID_TOOM42_THRESHOLD)
+    {
+      /* A + B */
+      mpn_mulmid_basecase (p0, s, 2*m - 1, bp + m, m);
+      /* accumulate high limbs of p0 into e1 */
+      ADDC_LIMB (cy, e1l, e1l, p0[m]);
+      e1h += p0[m + 1] + cy;
+      /* (-1)^neg * (B - C)   (overwrites first m limbs of s) */
+      mpn_mulmid_basecase (p1, ap + m, 2*m - 1, t, m);
+      /* C + D   (overwrites t) */
+      mpn_mulmid_basecase (p2, s + m, 2*m - 1, bp, m);
+    }
+  else
+    {
+      /* as above, but use toom42 instead */
+      mpn_toom42_mulmid (p0, s, bp + m, m, next_scratch);
+      ADDC_LIMB (cy, e1l, e1l, p0[m]);
+      e1h += p0[m + 1] + cy;
+      mpn_toom42_mulmid (p1, ap + m, t, m, next_scratch);
+      mpn_toom42_mulmid (p2, s + m, bp, m, next_scratch);
+    }
+
+  /* apply error terms */
+
+  /* -e0 at rp[0] */
+  SUBC_LIMB (cy, rp[0], rp[0], e0l);
+  SUBC_LIMB (cy, rp[1], rp[1], e0h + cy);
+  if (UNLIKELY (cy))
+    {
+      cy = (m > 2) ? mpn_sub_1 (rp + 2, rp + 2, m - 2, 1) : 1;
+      SUBC_LIMB (cy, e1l, e1l, cy);
+      e1h -= cy;
+    }
+
+  /* z = e1 - e2 + high(p0) */
+  SUBC_LIMB (cy, zl, e1l, e2l);
+  zh = e1h - e2h - cy;
+
+  /* z at rp[m] */
+  ADDC_LIMB (cy, rp[m], rp[m], zl);
+  zh = (zh + cy) & GMP_NUMB_MASK;
+  ADDC_LIMB (cy, rp[m + 1], rp[m + 1], zh);
+  cy -= (zh >> (GMP_NUMB_BITS - 1));
+  if (UNLIKELY (cy))
+    {
+      if (cy == 1)
+	mpn_add_1 (rp + m + 2, rp + m + 2, m, 1);
+      else /* cy == -1 */
+	mpn_sub_1 (rp + m + 2, rp + m + 2, m, 1);
+    }
+
+  /* e3 at rp[2*m] */
+  ADDC_LIMB (cy, rp[2*m], rp[2*m], e3l);
+  rp[2*m + 1] = (rp[2*m + 1] + e3h + cy) & GMP_NUMB_MASK;
+
+  /* e4 at p1[0] */
+  ADDC_LIMB (cy, p1[0], p1[0], e4l);
+  ADDC_LIMB (cy, p1[1], p1[1], e4h + cy);
+  if (UNLIKELY (cy))
+    mpn_add_1 (p1 + 2, p1 + 2, m, 1);
+
+  /* -e5 at p1[m] */
+  SUBC_LIMB (cy, p1[m], p1[m], e5l);
+  p1[m + 1] = (p1[m + 1] - e5h - cy) & GMP_NUMB_MASK;
+
+  /* adjustment if p1 ends up negative */
+  cy = (p1[m + 1] >> (GMP_NUMB_BITS - 1));
+
+  /* add (-1)^neg * (p1 - B^m * p1) to output */
+  if (neg)
+    {
+      mpn_sub_1 (rp + m + 2, rp + m + 2, m, cy);
+      mpn_add (rp, rp, 2*m + 2, p1, m + 2);             /* A + C */
+      mpn_sub_n (rp + m, rp + m, p1, m + 2);            /* B + D */
+    }
+  else
+    {
+      mpn_add_1 (rp + m + 2, rp + m + 2, m, cy);
+      mpn_sub (rp, rp, 2*m + 2, p1, m + 2);             /* A + C */
+      mpn_add_n (rp + m, rp + m, p1, m + 2);            /* B + D */
+    }
+
+  /* odd row and diagonal */
+  if (n & 1)
+    {
+      /*
+        Products marked E are already done. We need to do products marked O.
+
+        OOOOO----
+        -EEEEO---
+        --EEEEO--
+        ---EEEEO-
+        ----EEEEO
+       */
+
+      /* first row of O's */
+      cy = mpn_addmul_1 (rp, ap - 1, n, bp[n - 1]);
+      ADDC_LIMB (rp[n + 1], rp[n], rp[n], cy);
+
+      /* O's on diagonal */
+      /* FIXME: should probably define an interface "mpn_mulmid_diag_1"
+         that can handle the sum below. Currently we're relying on
+         mulmid_basecase being pretty fast for a diagonal sum like this,
+	 which is true at least for the K8 asm version, but surely false
+	 for the generic version. */
+      mpn_mulmid_basecase (e, ap + n - 1, n - 1, bp, n - 1);
+      mpn_add_n (rp + n - 1, rp + n - 1, e, 3);
+    }
+}
diff --git a/third_party/gmp/mpn/generic/toom43_mul.c b/third_party/gmp/mpn/generic/toom43_mul.c
new file mode 100644
index 0000000..0650138
--- /dev/null
+++ b/third_party/gmp/mpn/generic/toom43_mul.c
@@ -0,0 +1,233 @@
+/* mpn_toom43_mul -- Multiply {ap,an} and {bp,bn} where an is nominally 4/3
+   times as large as bn.  Or more accurately, bn < an < 2 bn.
+
+   Contributed to the GNU project by Marco Bodrato.
+
+   The idea of applying toom to unbalanced multiplication is due to Marco
+   Bodrato and Alberto Zanoni.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+/* Evaluate in: -2, -1, 0, +1, +2, +inf
+
+  <-s-><--n--><--n--><--n-->
+   ___ ______ ______ ______
+  |a3_|___a2_|___a1_|___a0_|
+	|_b2_|___b1_|___b0_|
+	<-t--><--n--><--n-->
+
+  v0  =  a0             * b0          #   A(0)*B(0)
+  v1  = (a0+ a1+ a2+ a3)*(b0+ b1+ b2) #   A(1)*B(1)      ah  <= 3  bh <= 2
+  vm1 = (a0- a1+ a2- a3)*(b0- b1+ b2) #  A(-1)*B(-1)    |ah| <= 1 |bh|<= 1
+  v2  = (a0+2a1+4a2+8a3)*(b0+2b1+4b2) #   A(2)*B(2)      ah  <= 14 bh <= 6
+  vm2 = (a0-2a1+4a2-8a3)*(b0-2b1+4b2) #  A(-2)*B(-2)    |ah| <= 9 |bh|<= 4
+  vinf=              a3 *         b2  # A(inf)*B(inf)
+*/
+
+void
+mpn_toom43_mul (mp_ptr pp,
+		mp_srcptr ap, mp_size_t an,
+		mp_srcptr bp, mp_size_t bn, mp_ptr scratch)
+{
+  mp_size_t n, s, t;
+  enum toom6_flags flags;
+  mp_limb_t cy;
+
+#define a0  ap
+#define a1  (ap + n)
+#define a2  (ap + 2 * n)
+#define a3  (ap + 3 * n)
+#define b0  bp
+#define b1  (bp + n)
+#define b2  (bp + 2 * n)
+
+  n = 1 + (3 * an >= 4 * bn ? (an - 1) >> 2 : (bn - 1) / (size_t) 3);
+
+  s = an - 3 * n;
+  t = bn - 2 * n;
+
+  ASSERT (0 < s && s <= n);
+  ASSERT (0 < t && t <= n);
+
+  /* This is true whenever an >= 25 or bn >= 19, I think. It
+     guarantees that we can fit 5 values of size n+1 in the product
+     area. */
+  ASSERT (s+t >= 5);
+
+#define v0    pp				/* 2n */
+#define vm1   (scratch)				/* 2n+1 */
+#define v1    (pp + 2*n)			/* 2n+1 */
+#define vm2   (scratch + 2 * n + 1)		/* 2n+1 */
+#define v2    (scratch + 4 * n + 2)		/* 2n+1 */
+#define vinf  (pp + 5 * n)			/* s+t */
+#define bs1    pp				/* n+1 */
+#define bsm1  (scratch + 2 * n + 2)		/* n+1 */
+#define asm1  (scratch + 3 * n + 3)		/* n+1 */
+#define asm2  (scratch + 4 * n + 4)		/* n+1 */
+#define bsm2  (pp + n + 1)			/* n+1 */
+#define bs2   (pp + 2 * n + 2)			/* n+1 */
+#define as2   (pp + 3 * n + 3)			/* n+1 */
+#define as1   (pp + 4 * n + 4)			/* n+1 */
+
+  /* Total sccratch need is 6 * n + 3 + 1; we allocate one extra
+     limb, because products will overwrite 2n+2 limbs. */
+
+#define a0a2  scratch
+#define b0b2  scratch
+#define a1a3  asm1
+#define b1d   bsm1
+
+  /* Compute as2 and asm2.  */
+  flags = (enum toom6_flags) (toom6_vm2_neg & mpn_toom_eval_dgr3_pm2 (as2, asm2, ap, n, s, a1a3));
+
+  /* Compute bs2 and bsm2.  */
+  b1d[n] = mpn_lshift (b1d, b1, n, 1);			/*       2b1      */
+  cy  = mpn_lshift (b0b2, b2, t, 2);			/*  4b2           */
+  cy += mpn_add_n (b0b2, b0b2, b0, t);			/*  4b2      + b0 */
+  if (t != n)
+    cy = mpn_add_1 (b0b2 + t, b0 + t, n - t, cy);
+  b0b2[n] = cy;
+
+#if HAVE_NATIVE_mpn_add_n_sub_n
+  if (mpn_cmp (b0b2, b1d, n+1) < 0)
+    {
+      mpn_add_n_sub_n (bs2, bsm2, b1d, b0b2, n+1);
+      flags = (enum toom6_flags) (flags ^ toom6_vm2_neg);
+    }
+  else
+    {
+      mpn_add_n_sub_n (bs2, bsm2, b0b2, b1d, n+1);
+    }
+#else
+  mpn_add_n (bs2, b0b2, b1d, n+1);
+  if (mpn_cmp (b0b2, b1d, n+1) < 0)
+    {
+      mpn_sub_n (bsm2, b1d, b0b2, n+1);
+      flags = (enum toom6_flags) (flags ^ toom6_vm2_neg);
+    }
+  else
+    {
+      mpn_sub_n (bsm2, b0b2, b1d, n+1);
+    }
+#endif
+
+  /* Compute as1 and asm1.  */
+  flags = (enum toom6_flags) (flags ^ (toom6_vm1_neg & mpn_toom_eval_dgr3_pm1 (as1, asm1, ap, n, s, a0a2)));
+
+  /* Compute bs1 and bsm1.  */
+  bsm1[n] = mpn_add (bsm1, b0, n, b2, t);
+#if HAVE_NATIVE_mpn_add_n_sub_n
+  if (bsm1[n] == 0 && mpn_cmp (bsm1, b1, n) < 0)
+    {
+      cy = mpn_add_n_sub_n (bs1, bsm1, b1, bsm1, n);
+      bs1[n] = cy >> 1;
+      flags = (enum toom6_flags) (flags ^ toom6_vm1_neg);
+    }
+  else
+    {
+      cy = mpn_add_n_sub_n (bs1, bsm1, bsm1, b1, n);
+      bs1[n] = bsm1[n] + (cy >> 1);
+      bsm1[n]-= cy & 1;
+    }
+#else
+  bs1[n] = bsm1[n] + mpn_add_n (bs1, bsm1, b1, n);
+  if (bsm1[n] == 0 && mpn_cmp (bsm1, b1, n) < 0)
+    {
+      mpn_sub_n (bsm1, b1, bsm1, n);
+      flags = (enum toom6_flags) (flags ^ toom6_vm1_neg);
+    }
+  else
+    {
+      bsm1[n] -= mpn_sub_n (bsm1, bsm1, b1, n);
+    }
+#endif
+
+  ASSERT (as1[n] <= 3);
+  ASSERT (bs1[n] <= 2);
+  ASSERT (asm1[n] <= 1);
+  ASSERT (bsm1[n] <= 1);
+  ASSERT (as2[n] <=14);
+  ASSERT (bs2[n] <= 6);
+  ASSERT (asm2[n] <= 9);
+  ASSERT (bsm2[n] <= 4);
+
+  /* vm1, 2n+1 limbs */
+  mpn_mul_n (vm1, asm1, bsm1, n+1);  /* W4 */
+
+  /* vm2, 2n+1 limbs */
+  mpn_mul_n (vm2, asm2, bsm2, n+1);  /* W2 */
+
+  /* v2, 2n+1 limbs */
+  mpn_mul_n (v2, as2, bs2, n+1);  /* W1 */
+
+  /* v1, 2n+1 limbs */
+  mpn_mul_n (v1, as1, bs1, n+1);  /* W3 */
+
+  /* vinf, s+t limbs */   /* W0 */
+  if (s > t)  mpn_mul (vinf, a3, s, b2, t);
+  else        mpn_mul (vinf, b2, t, a3, s);
+
+  /* v0, 2n limbs */
+  mpn_mul_n (v0, ap, bp, n);  /* W5 */
+
+  mpn_toom_interpolate_6pts (pp, n, flags, vm1, vm2, v2, t + s);
+
+#undef v0
+#undef vm1
+#undef v1
+#undef vm2
+#undef v2
+#undef vinf
+#undef bs1
+#undef bs2
+#undef bsm1
+#undef bsm2
+#undef asm1
+#undef asm2
+/* #undef as1 */
+/* #undef as2 */
+#undef a0a2
+#undef b0b2
+#undef a1a3
+#undef b1d
+#undef a0
+#undef a1
+#undef a2
+#undef a3
+#undef b0
+#undef b1
+#undef b2
+}
diff --git a/third_party/gmp/mpn/generic/toom44_mul.c b/third_party/gmp/mpn/generic/toom44_mul.c
new file mode 100644
index 0000000..77d5083
--- /dev/null
+++ b/third_party/gmp/mpn/generic/toom44_mul.c
@@ -0,0 +1,235 @@
+/* mpn_toom44_mul -- Multiply {ap,an} and {bp,bn} where an and bn are close in
+   size.  Or more accurately, bn <= an < (4/3)bn.
+
+   Contributed to the GNU project by Torbjorn Granlund and Marco Bodrato.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2006-2008, 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+/* Evaluate in: 0, +1, -1, +2, -2, 1/2, +inf
+
+  <-s--><--n--><--n--><--n-->
+   ____ ______ ______ ______
+  |_a3_|___a2_|___a1_|___a0_|
+   |b3_|___b2_|___b1_|___b0_|
+   <-t-><--n--><--n--><--n-->
+
+  v0  =   a0             *  b0              #    A(0)*B(0)
+  v1  = ( a0+ a1+ a2+ a3)*( b0+ b1+ b2+ b3) #    A(1)*B(1)      ah  <= 3   bh  <= 3
+  vm1 = ( a0- a1+ a2- a3)*( b0- b1+ b2- b3) #   A(-1)*B(-1)    |ah| <= 1  |bh| <= 1
+  v2  = ( a0+2a1+4a2+8a3)*( b0+2b1+4b2+8b3) #    A(2)*B(2)      ah  <= 14  bh  <= 14
+  vm2 = ( a0-2a1+4a2-8a3)*( b0-2b1+4b2-8b3) #    A(2)*B(2)      ah  <= 9  |bh| <= 9
+  vh  = (8a0+4a1+2a2+ a3)*(8b0+4b1+2b2+ b3) #  A(1/2)*B(1/2)    ah  <= 14  bh  <= 14
+  vinf=               a3 *          b2      #  A(inf)*B(inf)
+*/
+
+#if TUNE_PROGRAM_BUILD
+#define MAYBE_mul_basecase 1
+#define MAYBE_mul_toom22   1
+#define MAYBE_mul_toom44   1
+#else
+#define MAYBE_mul_basecase						\
+  (MUL_TOOM44_THRESHOLD < 4 * MUL_TOOM22_THRESHOLD)
+#define MAYBE_mul_toom22						\
+  (MUL_TOOM44_THRESHOLD < 4 * MUL_TOOM33_THRESHOLD)
+#define MAYBE_mul_toom44						\
+  (MUL_TOOM6H_THRESHOLD >= 4 * MUL_TOOM44_THRESHOLD)
+#endif
+
+#define TOOM44_MUL_N_REC(p, a, b, n, ws)				\
+  do {									\
+    if (MAYBE_mul_basecase						\
+	&& BELOW_THRESHOLD (n, MUL_TOOM22_THRESHOLD))			\
+      mpn_mul_basecase (p, a, n, b, n);					\
+    else if (MAYBE_mul_toom22						\
+	     && BELOW_THRESHOLD (n, MUL_TOOM33_THRESHOLD))		\
+      mpn_toom22_mul (p, a, n, b, n, ws);				\
+    else if (! MAYBE_mul_toom44						\
+	     || BELOW_THRESHOLD (n, MUL_TOOM44_THRESHOLD))		\
+      mpn_toom33_mul (p, a, n, b, n, ws);				\
+    else								\
+      mpn_toom44_mul (p, a, n, b, n, ws);				\
+  } while (0)
+
+/* Use of scratch space. In the product area, we store
+
+      ___________________
+     |vinf|____|_v1_|_v0_|
+      s+t  2n-1 2n+1  2n
+
+   The other recursive products, vm1, v2, vm2, vh are stored in the
+   scratch area. When computing them, we use the product area for
+   intermediate values.
+
+   Next, we compute v1. We can store the intermediate factors at v0
+   and at vh + 2n + 2.
+
+   Finally, for v0 and vinf, factors are parts of the input operands,
+   and we need scratch space only for the recursive multiplication.
+
+   In all, if S(an) is the scratch need, the needed space is bounded by
+
+     S(an) <= 4 (2*ceil(an/4) + 1) + 1 + S(ceil(an/4) + 1)
+
+   which should give S(n) = 8 n/3 + c log(n) for some constant c.
+*/
+
+void
+mpn_toom44_mul (mp_ptr pp,
+		mp_srcptr ap, mp_size_t an,
+		mp_srcptr bp, mp_size_t bn,
+		mp_ptr scratch)
+{
+  mp_size_t n, s, t;
+  mp_limb_t cy;
+  enum toom7_flags flags;
+
+#define a0  ap
+#define a1  (ap + n)
+#define a2  (ap + 2*n)
+#define a3  (ap + 3*n)
+#define b0  bp
+#define b1  (bp + n)
+#define b2  (bp + 2*n)
+#define b3  (bp + 3*n)
+
+  ASSERT (an >= bn);
+
+  n = (an + 3) >> 2;
+
+  s = an - 3 * n;
+  t = bn - 3 * n;
+
+  ASSERT (0 < s && s <= n);
+  ASSERT (0 < t && t <= n);
+  ASSERT (s >= t);
+
+  /* NOTE: The multiplications to v2, vm2, vh and vm1 overwrites the
+   * following limb, so these must be computed in order, and we need a
+   * one limb gap to tp. */
+#define v0    pp				/* 2n */
+#define v1    (pp + 2 * n)			/* 2n+1 */
+#define vinf  (pp + 6 * n)			/* s+t */
+#define v2    scratch				/* 2n+1 */
+#define vm2   (scratch + 2 * n + 1)		/* 2n+1 */
+#define vh    (scratch + 4 * n + 2)		/* 2n+1 */
+#define vm1   (scratch + 6 * n + 3)		/* 2n+1 */
+#define tp (scratch + 8*n + 5)
+
+  /* apx and bpx must not overlap with v1 */
+#define apx   pp				/* n+1 */
+#define amx   (pp + n + 1)			/* n+1 */
+#define bmx   (pp + 2*n + 2)			/* n+1 */
+#define bpx   (pp + 4*n + 2)			/* n+1 */
+
+  /* Total scratch need: 8*n + 5 + scratch for recursive calls. This
+     gives roughly 32 n/3 + log term. */
+
+  /* Compute apx = a0 + 2 a1 + 4 a2 + 8 a3 and amx = a0 - 2 a1 + 4 a2 - 8 a3.  */
+  flags = (enum toom7_flags) (toom7_w1_neg & mpn_toom_eval_dgr3_pm2 (apx, amx, ap, n, s, tp));
+
+  /* Compute bpx = b0 + 2 b1 + 4 b2 + 8 b3 and bmx = b0 - 2 b1 + 4 b2 - 8 b3.  */
+  flags = (enum toom7_flags) (flags ^ (toom7_w1_neg & mpn_toom_eval_dgr3_pm2 (bpx, bmx, bp, n, t, tp)));
+
+  TOOM44_MUL_N_REC (v2, apx, bpx, n + 1, tp);	/* v2,  2n+1 limbs */
+  TOOM44_MUL_N_REC (vm2, amx, bmx, n + 1, tp);	/* vm2,  2n+1 limbs */
+
+  /* Compute apx = 8 a0 + 4 a1 + 2 a2 + a3 = (((2*a0 + a1) * 2 + a2) * 2 + a3 */
+#if HAVE_NATIVE_mpn_addlsh1_n
+  cy = mpn_addlsh1_n (apx, a1, a0, n);
+  cy = 2*cy + mpn_addlsh1_n (apx, a2, apx, n);
+  if (s < n)
+    {
+      mp_limb_t cy2;
+      cy2 = mpn_addlsh1_n (apx, a3, apx, s);
+      apx[n] = 2*cy + mpn_lshift (apx + s, apx + s, n - s, 1);
+      MPN_INCR_U (apx + s, n+1-s, cy2);
+    }
+  else
+    apx[n] = 2*cy + mpn_addlsh1_n (apx, a3, apx, n);
+#else
+  cy = mpn_lshift (apx, a0, n, 1);
+  cy += mpn_add_n (apx, apx, a1, n);
+  cy = 2*cy + mpn_lshift (apx, apx, n, 1);
+  cy += mpn_add_n (apx, apx, a2, n);
+  cy = 2*cy + mpn_lshift (apx, apx, n, 1);
+  apx[n] = cy + mpn_add (apx, apx, n, a3, s);
+#endif
+
+  /* Compute bpx = 8 b0 + 4 b1 + 2 b2 + b3 = (((2*b0 + b1) * 2 + b2) * 2 + b3 */
+#if HAVE_NATIVE_mpn_addlsh1_n
+  cy = mpn_addlsh1_n (bpx, b1, b0, n);
+  cy = 2*cy + mpn_addlsh1_n (bpx, b2, bpx, n);
+  if (t < n)
+    {
+      mp_limb_t cy2;
+      cy2 = mpn_addlsh1_n (bpx, b3, bpx, t);
+      bpx[n] = 2*cy + mpn_lshift (bpx + t, bpx + t, n - t, 1);
+      MPN_INCR_U (bpx + t, n+1-t, cy2);
+    }
+  else
+    bpx[n] = 2*cy + mpn_addlsh1_n (bpx, b3, bpx, n);
+#else
+  cy = mpn_lshift (bpx, b0, n, 1);
+  cy += mpn_add_n (bpx, bpx, b1, n);
+  cy = 2*cy + mpn_lshift (bpx, bpx, n, 1);
+  cy += mpn_add_n (bpx, bpx, b2, n);
+  cy = 2*cy + mpn_lshift (bpx, bpx, n, 1);
+  bpx[n] = cy + mpn_add (bpx, bpx, n, b3, t);
+#endif
+
+  ASSERT (apx[n] < 15);
+  ASSERT (bpx[n] < 15);
+
+  TOOM44_MUL_N_REC (vh, apx, bpx, n + 1, tp);	/* vh,  2n+1 limbs */
+
+  /* Compute apx = a0 + a1 + a2 + a3 and amx = a0 - a1 + a2 - a3.  */
+  flags = (enum toom7_flags) (flags | (toom7_w3_neg & mpn_toom_eval_dgr3_pm1 (apx, amx, ap, n, s, tp)));
+
+  /* Compute bpx = b0 + b1 + b2 + b3 and bmx = b0 - b1 + b2 - b3.  */
+  flags = (enum toom7_flags) (flags ^ (toom7_w3_neg & mpn_toom_eval_dgr3_pm1 (bpx, bmx, bp, n, t, tp)));
+
+  TOOM44_MUL_N_REC (vm1, amx, bmx, n + 1, tp);	/* vm1,  2n+1 limbs */
+  /* Clobbers amx, bmx. */
+  TOOM44_MUL_N_REC (v1, apx, bpx, n + 1, tp);	/* v1,  2n+1 limbs */
+
+  TOOM44_MUL_N_REC (v0, a0, b0, n, tp);
+  if (s > t)
+    mpn_mul (vinf, a3, s, b3, t);
+  else
+    TOOM44_MUL_N_REC (vinf, a3, b3, s, tp);	/* vinf, s+t limbs */
+
+  mpn_toom_interpolate_7pts (pp, n, flags, vm2, vm1, v2, vh, s + t, tp);
+}
diff --git a/third_party/gmp/mpn/generic/toom4_sqr.c b/third_party/gmp/mpn/generic/toom4_sqr.c
new file mode 100644
index 0000000..aec84c1
--- /dev/null
+++ b/third_party/gmp/mpn/generic/toom4_sqr.c
@@ -0,0 +1,163 @@
+/* mpn_toom4_sqr -- Square {ap,an}.
+
+   Contributed to the GNU project by Torbjorn Granlund and Marco Bodrato.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2006-2010, 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+/* Evaluate in: -1, -1/2, 0, +1/2, +1, +2, +inf
+
+  <-s--><--n--><--n--><--n-->
+   ____ ______ ______ ______
+  |_a3_|___a2_|___a1_|___a0_|
+
+  v0  =   a0             ^2 #    A(0)^2
+  v1  = ( a0+ a1+ a2+ a3)^2 #    A(1)^2   ah  <= 3
+  vm1 = ( a0- a1+ a2- a3)^2 #   A(-1)^2  |ah| <= 1
+  v2  = ( a0+2a1+4a2+8a3)^2 #    A(2)^2   ah  <= 14
+  vh  = (8a0+4a1+2a2+ a3)^2 #  A(1/2)^2   ah  <= 14
+  vmh = (8a0-4a1+2a2- a3)^2 # A(-1/2)^2  -4<=ah<=9
+  vinf=               a3 ^2 #  A(inf)^2
+*/
+
+#if TUNE_PROGRAM_BUILD
+#define MAYBE_sqr_basecase 1
+#define MAYBE_sqr_toom2   1
+#define MAYBE_sqr_toom4   1
+#else
+#define MAYBE_sqr_basecase						\
+  (SQR_TOOM4_THRESHOLD < 4 * SQR_TOOM2_THRESHOLD)
+#define MAYBE_sqr_toom2							\
+  (SQR_TOOM4_THRESHOLD < 4 * SQR_TOOM3_THRESHOLD)
+#define MAYBE_sqr_toom4							\
+  (SQR_TOOM6_THRESHOLD >= 4 * SQR_TOOM4_THRESHOLD)
+#endif
+
+#define TOOM4_SQR_REC(p, a, n, ws)					\
+  do {									\
+    if (MAYBE_sqr_basecase						\
+	&& BELOW_THRESHOLD (n, SQR_TOOM2_THRESHOLD))			\
+      mpn_sqr_basecase (p, a, n);					\
+    else if (MAYBE_sqr_toom2						\
+	     && BELOW_THRESHOLD (n, SQR_TOOM3_THRESHOLD))		\
+      mpn_toom2_sqr (p, a, n, ws);					\
+    else if (! MAYBE_sqr_toom4						\
+	     || BELOW_THRESHOLD (n, SQR_TOOM4_THRESHOLD))		\
+      mpn_toom3_sqr (p, a, n, ws);					\
+    else								\
+      mpn_toom4_sqr (p, a, n, ws);					\
+  } while (0)
+
+void
+mpn_toom4_sqr (mp_ptr pp,
+	       mp_srcptr ap, mp_size_t an,
+	       mp_ptr scratch)
+{
+  mp_size_t n, s;
+  mp_limb_t cy;
+
+#define a0  ap
+#define a1  (ap + n)
+#define a2  (ap + 2*n)
+#define a3  (ap + 3*n)
+
+  n = (an + 3) >> 2;
+
+  s = an - 3 * n;
+
+  ASSERT (0 < s && s <= n);
+
+  /* NOTE: The multiplications to v2, vm2, vh and vm1 overwrites the
+   * following limb, so these must be computed in order, and we need a
+   * one limb gap to tp. */
+#define v0    pp				/* 2n */
+#define v1    (pp + 2 * n)			/* 2n+1 */
+#define vinf  (pp + 6 * n)			/* s+t */
+#define v2    scratch				/* 2n+1 */
+#define vm2   (scratch + 2 * n + 1)		/* 2n+1 */
+#define vh    (scratch + 4 * n + 2)		/* 2n+1 */
+#define vm1   (scratch + 6 * n + 3)		/* 2n+1 */
+#define tp (scratch + 8*n + 5)
+
+  /* No overlap with v1 */
+#define apx   pp				/* n+1 */
+#define amx   (pp + 4*n + 2)			/* n+1 */
+
+  /* Total scratch need: 8*n + 5 + scratch for recursive calls. This
+     gives roughly 32 n/3 + log term. */
+
+  /* Compute apx = a0 + 2 a1 + 4 a2 + 8 a3 and amx = a0 - 2 a1 + 4 a2 - 8 a3.  */
+  mpn_toom_eval_dgr3_pm2 (apx, amx, ap, n, s, tp);
+
+  TOOM4_SQR_REC (v2, apx, n + 1, tp);	/* v2,  2n+1 limbs */
+  TOOM4_SQR_REC (vm2, amx, n + 1, tp);	/* vm2,  2n+1 limbs */
+
+  /* Compute apx = 8 a0 + 4 a1 + 2 a2 + a3 = (((2*a0 + a1) * 2 + a2) * 2 + a3 */
+#if HAVE_NATIVE_mpn_addlsh1_n
+  cy = mpn_addlsh1_n (apx, a1, a0, n);
+  cy = 2*cy + mpn_addlsh1_n (apx, a2, apx, n);
+  if (s < n)
+    {
+      mp_limb_t cy2;
+      cy2 = mpn_addlsh1_n (apx, a3, apx, s);
+      apx[n] = 2*cy + mpn_lshift (apx + s, apx + s, n - s, 1);
+      MPN_INCR_U (apx + s, n+1-s, cy2);
+    }
+  else
+    apx[n] = 2*cy + mpn_addlsh1_n (apx, a3, apx, n);
+#else
+  cy = mpn_lshift (apx, a0, n, 1);
+  cy += mpn_add_n (apx, apx, a1, n);
+  cy = 2*cy + mpn_lshift (apx, apx, n, 1);
+  cy += mpn_add_n (apx, apx, a2, n);
+  cy = 2*cy + mpn_lshift (apx, apx, n, 1);
+  apx[n] = cy + mpn_add (apx, apx, n, a3, s);
+#endif
+
+  ASSERT (apx[n] < 15);
+
+  TOOM4_SQR_REC (vh, apx, n + 1, tp);	/* vh,  2n+1 limbs */
+
+  /* Compute apx = a0 + a1 + a2 + a3 and amx = a0 - a1 + a2 - a3.  */
+  mpn_toom_eval_dgr3_pm1 (apx, amx, ap, n, s, tp);
+
+  TOOM4_SQR_REC (v1, apx, n + 1, tp);	/* v1,  2n+1 limbs */
+  TOOM4_SQR_REC (vm1, amx, n + 1, tp);	/* vm1,  2n+1 limbs */
+
+  TOOM4_SQR_REC (v0, a0, n, tp);
+  TOOM4_SQR_REC (vinf, a3, s, tp);	/* vinf, 2s limbs */
+
+  mpn_toom_interpolate_7pts (pp, n, (enum toom7_flags) 0, vm2, vm1, v2, vh, 2*s, tp);
+}
diff --git a/third_party/gmp/mpn/generic/toom52_mul.c b/third_party/gmp/mpn/generic/toom52_mul.c
new file mode 100644
index 0000000..974059b
--- /dev/null
+++ b/third_party/gmp/mpn/generic/toom52_mul.c
@@ -0,0 +1,256 @@
+/* mpn_toom52_mul -- Multiply {ap,an} and {bp,bn} where an is nominally 4/3
+   times as large as bn.  Or more accurately, bn < an < 2 bn.
+
+   Contributed to the GNU project by Marco Bodrato.
+
+   The idea of applying toom to unbalanced multiplication is due to Marco
+   Bodrato and Alberto Zanoni.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+/* Evaluate in: -2, -1, 0, +1, +2, +inf
+
+  <-s-><--n--><--n--><--n--><--n-->
+   ___ ______ ______ ______ ______
+  |a4_|___a3_|___a2_|___a1_|___a0_|
+			|b1|___b0_|
+			<t-><--n-->
+
+  v0  =  a0                  * b0      #   A(0)*B(0)
+  v1  = (a0+ a1+ a2+ a3+  a4)*(b0+ b1) #   A(1)*B(1)      ah  <= 4   bh <= 1
+  vm1 = (a0- a1+ a2- a3+  a4)*(b0- b1) #  A(-1)*B(-1)    |ah| <= 2   bh  = 0
+  v2  = (a0+2a1+4a2+8a3+16a4)*(b0+2b1) #   A(2)*B(2)      ah  <= 30  bh <= 2
+  vm2 = (a0-2a1+4a2-8a3+16a4)*(b0-2b1) #  A(-2)*B(-2)    |ah| <= 20 |bh|<= 1
+  vinf=                   a4 *     b1  # A(inf)*B(inf)
+
+  Some slight optimization in evaluation are taken from the paper:
+  "Towards Optimal Toom-Cook Multiplication for Univariate and
+  Multivariate Polynomials in Characteristic 2 and 0."
+*/
+
+void
+mpn_toom52_mul (mp_ptr pp,
+		mp_srcptr ap, mp_size_t an,
+		mp_srcptr bp, mp_size_t bn, mp_ptr scratch)
+{
+  mp_size_t n, s, t;
+  enum toom6_flags flags;
+
+#define a0  ap
+#define a1  (ap + n)
+#define a2  (ap + 2 * n)
+#define a3  (ap + 3 * n)
+#define a4  (ap + 4 * n)
+#define b0  bp
+#define b1  (bp + n)
+
+  n = 1 + (2 * an >= 5 * bn ? (an - 1) / (size_t) 5 : (bn - 1) >> 1);
+
+  s = an - 4 * n;
+  t = bn - n;
+
+  ASSERT (0 < s && s <= n);
+  ASSERT (0 < t && t <= n);
+
+  /* Ensures that 5 values of n+1 limbs each fits in the product area.
+     Borderline cases are an = 32, bn = 8, n = 7, and an = 36, bn = 9,
+     n = 8. */
+  ASSERT (s+t >= 5);
+
+#define v0    pp				/* 2n */
+#define vm1   (scratch)				/* 2n+1 */
+#define v1    (pp + 2 * n)			/* 2n+1 */
+#define vm2   (scratch + 2 * n + 1)		/* 2n+1 */
+#define v2    (scratch + 4 * n + 2)		/* 2n+1 */
+#define vinf  (pp + 5 * n)			/* s+t */
+#define bs1    pp				/* n+1 */
+#define bsm1  (scratch + 2 * n + 2)		/* n   */
+#define asm1  (scratch + 3 * n + 3)		/* n+1 */
+#define asm2  (scratch + 4 * n + 4)		/* n+1 */
+#define bsm2  (pp + n + 1)			/* n+1 */
+#define bs2   (pp + 2 * n + 2)			/* n+1 */
+#define as2   (pp + 3 * n + 3)			/* n+1 */
+#define as1   (pp + 4 * n + 4)			/* n+1 */
+
+  /* Scratch need is 6 * n + 3 + 1. We need one extra limb, because
+     products will overwrite 2n+2 limbs. */
+
+#define a0a2  scratch
+#define a1a3  asm1
+
+  /* Compute as2 and asm2.  */
+  flags = (enum toom6_flags) (toom6_vm2_neg & mpn_toom_eval_pm2 (as2, asm2, 4, ap, n, s, a1a3));
+
+  /* Compute bs1 and bsm1.  */
+  if (t == n)
+    {
+#if HAVE_NATIVE_mpn_add_n_sub_n
+      mp_limb_t cy;
+
+      if (mpn_cmp (b0, b1, n) < 0)
+	{
+	  cy = mpn_add_n_sub_n (bs1, bsm1, b1, b0, n);
+	  flags = (enum toom6_flags) (flags ^ toom6_vm1_neg);
+	}
+      else
+	{
+	  cy = mpn_add_n_sub_n (bs1, bsm1, b0, b1, n);
+	}
+      bs1[n] = cy >> 1;
+#else
+      bs1[n] = mpn_add_n (bs1, b0, b1, n);
+      if (mpn_cmp (b0, b1, n) < 0)
+	{
+	  mpn_sub_n (bsm1, b1, b0, n);
+	  flags = (enum toom6_flags) (flags ^ toom6_vm1_neg);
+	}
+      else
+	{
+	  mpn_sub_n (bsm1, b0, b1, n);
+	}
+#endif
+    }
+  else
+    {
+      bs1[n] = mpn_add (bs1, b0, n, b1, t);
+      if (mpn_zero_p (b0 + t, n - t) && mpn_cmp (b0, b1, t) < 0)
+	{
+	  mpn_sub_n (bsm1, b1, b0, t);
+	  MPN_ZERO (bsm1 + t, n - t);
+	  flags = (enum toom6_flags) (flags ^ toom6_vm1_neg);
+	}
+      else
+	{
+	  mpn_sub (bsm1, b0, n, b1, t);
+	}
+    }
+
+  /* Compute bs2 and bsm2, recycling bs1 and bsm1. bs2=bs1+b1; bsm2=bsm1-b1  */
+  mpn_add (bs2, bs1, n+1, b1, t);
+  if (flags & toom6_vm1_neg)
+    {
+      bsm2[n] = mpn_add (bsm2, bsm1, n, b1, t);
+      flags = (enum toom6_flags) (flags ^ toom6_vm2_neg);
+    }
+  else
+    {
+      bsm2[n] = 0;
+      if (t == n)
+	{
+	  if (mpn_cmp (bsm1, b1, n) < 0)
+	    {
+	      mpn_sub_n (bsm2, b1, bsm1, n);
+	      flags = (enum toom6_flags) (flags ^ toom6_vm2_neg);
+	    }
+	  else
+	    {
+	      mpn_sub_n (bsm2, bsm1, b1, n);
+	    }
+	}
+      else
+	{
+	  if (mpn_zero_p (bsm1 + t, n - t) && mpn_cmp (bsm1, b1, t) < 0)
+	    {
+	      mpn_sub_n (bsm2, b1, bsm1, t);
+	      MPN_ZERO (bsm2 + t, n - t);
+	      flags = (enum toom6_flags) (flags ^ toom6_vm2_neg);
+	    }
+	  else
+	    {
+	      mpn_sub (bsm2, bsm1, n, b1, t);
+	    }
+	}
+    }
+
+  /* Compute as1 and asm1.  */
+  flags = (enum toom6_flags) (flags ^ (toom6_vm1_neg & mpn_toom_eval_pm1 (as1, asm1, 4, ap, n, s, a0a2)));
+
+  ASSERT (as1[n] <= 4);
+  ASSERT (bs1[n] <= 1);
+  ASSERT (asm1[n] <= 2);
+/*   ASSERT (bsm1[n] <= 1); */
+  ASSERT (as2[n] <=30);
+  ASSERT (bs2[n] <= 2);
+  ASSERT (asm2[n] <= 20);
+  ASSERT (bsm2[n] <= 1);
+
+  /* vm1, 2n+1 limbs */
+  mpn_mul (vm1, asm1, n+1, bsm1, n);  /* W4 */
+
+  /* vm2, 2n+1 limbs */
+  mpn_mul_n (vm2, asm2, bsm2, n+1);  /* W2 */
+
+  /* v2, 2n+1 limbs */
+  mpn_mul_n (v2, as2, bs2, n+1);  /* W1 */
+
+  /* v1, 2n+1 limbs */
+  mpn_mul_n (v1, as1, bs1, n+1);  /* W3 */
+
+  /* vinf, s+t limbs */   /* W0 */
+  if (s > t)  mpn_mul (vinf, a4, s, b1, t);
+  else        mpn_mul (vinf, b1, t, a4, s);
+
+  /* v0, 2n limbs */
+  mpn_mul_n (v0, ap, bp, n);  /* W5 */
+
+  mpn_toom_interpolate_6pts (pp, n, flags, vm1, vm2, v2, t + s);
+
+#undef v0
+#undef vm1
+#undef v1
+#undef vm2
+#undef v2
+#undef vinf
+#undef bs1
+#undef bs2
+#undef bsm1
+#undef bsm2
+#undef asm1
+#undef asm2
+#undef as1
+#undef as2
+#undef a0a2
+#undef b0b2
+#undef a1a3
+#undef a0
+#undef a1
+#undef a2
+#undef a3
+#undef b0
+#undef b1
+#undef b2
+
+}
diff --git a/third_party/gmp/mpn/generic/toom53_mul.c b/third_party/gmp/mpn/generic/toom53_mul.c
new file mode 100644
index 0000000..c934297
--- /dev/null
+++ b/third_party/gmp/mpn/generic/toom53_mul.c
@@ -0,0 +1,331 @@
+/* mpn_toom53_mul -- Multiply {ap,an} and {bp,bn} where an is nominally 5/3
+   times as large as bn.  Or more accurately, (4/3)bn < an < (5/2)bn.
+
+   Contributed to the GNU project by Torbjorn Granlund and Marco Bodrato.
+
+   The idea of applying toom to unbalanced multiplication is due to Marco
+   Bodrato and Alberto Zanoni.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2006-2008, 2012, 2014, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+/* Evaluate in: 0, +1, -1, +2, -2, 1/2, +inf
+
+  <-s-><--n--><--n--><--n--><--n-->
+   ___ ______ ______ ______ ______
+  |a4_|___a3_|___a2_|___a1_|___a0_|
+	       |__b2|___b1_|___b0_|
+	       <-t--><--n--><--n-->
+
+  v0  =    a0                  *  b0          #    A(0)*B(0)
+  v1  = (  a0+ a1+ a2+ a3+  a4)*( b0+ b1+ b2) #    A(1)*B(1)      ah  <= 4   bh <= 2
+  vm1 = (  a0- a1+ a2- a3+  a4)*( b0- b1+ b2) #   A(-1)*B(-1)    |ah| <= 2   bh <= 1
+  v2  = (  a0+2a1+4a2+8a3+16a4)*( b0+2b1+4b2) #    A(2)*B(2)      ah  <= 30  bh <= 6
+  vm2 = (  a0-2a1+4a2-8a3+16a4)*( b0-2b1+4b2) #    A(2)*B(2)     -9<=ah<=20 -1<=bh<=4
+  vh  = (16a0+8a1+4a2+2a3+  a4)*(4b0+2b1+ b2) #  A(1/2)*B(1/2)    ah  <= 30  bh <= 6
+  vinf=                     a4 *          b2  #  A(inf)*B(inf)
+*/
+
+void
+mpn_toom53_mul (mp_ptr pp,
+		mp_srcptr ap, mp_size_t an,
+		mp_srcptr bp, mp_size_t bn,
+		mp_ptr scratch)
+{
+  mp_size_t n, s, t;
+  mp_limb_t cy;
+  mp_ptr gp;
+  mp_ptr as1, asm1, as2, asm2, ash;
+  mp_ptr bs1, bsm1, bs2, bsm2, bsh;
+  mp_ptr tmp;
+  enum toom7_flags flags;
+  TMP_DECL;
+
+#define a0  ap
+#define a1  (ap + n)
+#define a2  (ap + 2*n)
+#define a3  (ap + 3*n)
+#define a4  (ap + 4*n)
+#define b0  bp
+#define b1  (bp + n)
+#define b2  (bp + 2*n)
+
+  n = 1 + (3 * an >= 5 * bn ? (an - 1) / (size_t) 5 : (bn - 1) / (size_t) 3);
+
+  s = an - 4 * n;
+  t = bn - 2 * n;
+
+  ASSERT (0 < s && s <= n);
+  ASSERT (0 < t && t <= n);
+
+  TMP_MARK;
+
+  tmp = TMP_ALLOC_LIMBS (10 * (n + 1));
+  as1  = tmp; tmp += n + 1;
+  asm1 = tmp; tmp += n + 1;
+  as2  = tmp; tmp += n + 1;
+  asm2 = tmp; tmp += n + 1;
+  ash  = tmp; tmp += n + 1;
+  bs1  = tmp; tmp += n + 1;
+  bsm1 = tmp; tmp += n + 1;
+  bs2  = tmp; tmp += n + 1;
+  bsm2 = tmp; tmp += n + 1;
+  bsh  = tmp; tmp += n + 1;
+
+  gp = pp;
+
+  /* Compute as1 and asm1.  */
+  flags = (enum toom7_flags) (toom7_w3_neg & mpn_toom_eval_pm1 (as1, asm1, 4, ap, n, s, gp));
+
+  /* Compute as2 and asm2. */
+  flags = (enum toom7_flags) (flags | (toom7_w1_neg & mpn_toom_eval_pm2 (as2, asm2, 4, ap, n, s, gp)));
+
+  /* Compute ash = 16 a0 + 8 a1 + 4 a2 + 2 a3 + a4
+     = 2*(2*(2*(2*a0 + a1) + a2) + a3) + a4  */
+#if HAVE_NATIVE_mpn_addlsh1_n
+  cy = mpn_addlsh1_n (ash, a1, a0, n);
+  cy = 2*cy + mpn_addlsh1_n (ash, a2, ash, n);
+  cy = 2*cy + mpn_addlsh1_n (ash, a3, ash, n);
+  if (s < n)
+    {
+      mp_limb_t cy2;
+      cy2 = mpn_addlsh1_n (ash, a4, ash, s);
+      ash[n] = 2*cy + mpn_lshift (ash + s, ash + s, n - s, 1);
+      MPN_INCR_U (ash + s, n+1-s, cy2);
+    }
+  else
+    ash[n] = 2*cy + mpn_addlsh1_n (ash, a4, ash, n);
+#else
+  cy = mpn_lshift (ash, a0, n, 1);
+  cy += mpn_add_n (ash, ash, a1, n);
+  cy = 2*cy + mpn_lshift (ash, ash, n, 1);
+  cy += mpn_add_n (ash, ash, a2, n);
+  cy = 2*cy + mpn_lshift (ash, ash, n, 1);
+  cy += mpn_add_n (ash, ash, a3, n);
+  cy = 2*cy + mpn_lshift (ash, ash, n, 1);
+  ash[n] = cy + mpn_add (ash, ash, n, a4, s);
+#endif
+
+  /* Compute bs1 and bsm1.  */
+  bs1[n] = mpn_add (bs1, b0, n, b2, t);		/* b0 + b2 */
+#if HAVE_NATIVE_mpn_add_n_sub_n
+  if (bs1[n] == 0 && mpn_cmp (bs1, b1, n) < 0)
+    {
+      bs1[n] = mpn_add_n_sub_n (bs1, bsm1, b1, bs1, n) >> 1;
+      bsm1[n] = 0;
+      flags = (enum toom7_flags) (flags ^ toom7_w3_neg);
+    }
+  else
+    {
+      cy = mpn_add_n_sub_n (bs1, bsm1, bs1, b1, n);
+      bsm1[n] = bs1[n] - (cy & 1);
+      bs1[n] += (cy >> 1);
+    }
+#else
+  if (bs1[n] == 0 && mpn_cmp (bs1, b1, n) < 0)
+    {
+      mpn_sub_n (bsm1, b1, bs1, n);
+      bsm1[n] = 0;
+      flags = (enum toom7_flags) (flags ^ toom7_w3_neg);
+    }
+  else
+    {
+      bsm1[n] = bs1[n] - mpn_sub_n (bsm1, bs1, b1, n);
+    }
+  bs1[n] += mpn_add_n (bs1, bs1, b1, n);  /* b0+b1+b2 */
+#endif
+
+  /* Compute bs2 and bsm2. */
+#if HAVE_NATIVE_mpn_addlsh_n || HAVE_NATIVE_mpn_addlsh2_n
+#if HAVE_NATIVE_mpn_addlsh2_n
+  cy = mpn_addlsh2_n (bs2, b0, b2, t);
+#else /* HAVE_NATIVE_mpn_addlsh_n */
+  cy = mpn_addlsh_n (bs2, b0, b2, t, 2);
+#endif
+  if (t < n)
+    cy = mpn_add_1 (bs2 + t, b0 + t, n - t, cy);
+  bs2[n] = cy;
+#else
+  cy = mpn_lshift (gp, b2, t, 2);
+  bs2[n] = mpn_add (bs2, b0, n, gp, t);
+  MPN_INCR_U (bs2 + t, n+1-t, cy);
+#endif
+
+  gp[n] = mpn_lshift (gp, b1, n, 1);
+
+#if HAVE_NATIVE_mpn_add_n_sub_n
+  if (mpn_cmp (bs2, gp, n+1) < 0)
+    {
+      ASSERT_NOCARRY (mpn_add_n_sub_n (bs2, bsm2, gp, bs2, n+1));
+      flags = (enum toom7_flags) (flags ^ toom7_w1_neg);
+    }
+  else
+    {
+      ASSERT_NOCARRY (mpn_add_n_sub_n (bs2, bsm2, bs2, gp, n+1));
+    }
+#else
+  if (mpn_cmp (bs2, gp, n+1) < 0)
+    {
+      ASSERT_NOCARRY (mpn_sub_n (bsm2, gp, bs2, n+1));
+      flags = (enum toom7_flags) (flags ^ toom7_w1_neg);
+    }
+  else
+    {
+      ASSERT_NOCARRY (mpn_sub_n (bsm2, bs2, gp, n+1));
+    }
+  mpn_add_n (bs2, bs2, gp, n+1);
+#endif
+
+  /* Compute bsh = 4 b0 + 2 b1 + b2 = 2*(2*b0 + b1)+b2.  */
+#if HAVE_NATIVE_mpn_addlsh1_n
+  cy = mpn_addlsh1_n (bsh, b1, b0, n);
+  if (t < n)
+    {
+      mp_limb_t cy2;
+      cy2 = mpn_addlsh1_n (bsh, b2, bsh, t);
+      bsh[n] = 2*cy + mpn_lshift (bsh + t, bsh + t, n - t, 1);
+      MPN_INCR_U (bsh + t, n+1-t, cy2);
+    }
+  else
+    bsh[n] = 2*cy + mpn_addlsh1_n (bsh, b2, bsh, n);
+#else
+  cy = mpn_lshift (bsh, b0, n, 1);
+  cy += mpn_add_n (bsh, bsh, b1, n);
+  cy = 2*cy + mpn_lshift (bsh, bsh, n, 1);
+  bsh[n] = cy + mpn_add (bsh, bsh, n, b2, t);
+#endif
+
+  ASSERT (as1[n] <= 4);
+  ASSERT (bs1[n] <= 2);
+  ASSERT (asm1[n] <= 2);
+  ASSERT (bsm1[n] <= 1);
+  ASSERT (as2[n] <= 30);
+  ASSERT (bs2[n] <= 6);
+  ASSERT (asm2[n] <= 20);
+  ASSERT (bsm2[n] <= 4);
+  ASSERT (ash[n] <= 30);
+  ASSERT (bsh[n] <= 6);
+
+#define v0    pp				/* 2n */
+#define v1    (pp + 2 * n)			/* 2n+1 */
+#define vinf  (pp + 6 * n)			/* s+t */
+#define v2    scratch				/* 2n+1 */
+#define vm2   (scratch + 2 * n + 1)		/* 2n+1 */
+#define vh    (scratch + 4 * n + 2)		/* 2n+1 */
+#define vm1   (scratch + 6 * n + 3)		/* 2n+1 */
+#define scratch_out (scratch + 8 * n + 4)		/* 2n+1 */
+  /* Total scratch need: 10*n+5 */
+
+  /* Must be in allocation order, as they overwrite one limb beyond
+   * 2n+1. */
+  mpn_mul_n (v2, as2, bs2, n + 1);		/* v2, 2n+1 limbs */
+  mpn_mul_n (vm2, asm2, bsm2, n + 1);		/* vm2, 2n+1 limbs */
+  mpn_mul_n (vh, ash, bsh, n + 1);		/* vh, 2n+1 limbs */
+
+  /* vm1, 2n+1 limbs */
+#ifdef SMALLER_RECURSION
+  mpn_mul_n (vm1, asm1, bsm1, n);
+  if (asm1[n] == 1)
+    {
+      cy = bsm1[n] + mpn_add_n (vm1 + n, vm1 + n, bsm1, n);
+    }
+  else if (asm1[n] == 2)
+    {
+#if HAVE_NATIVE_mpn_addlsh1_n_ip1
+      cy = 2 * bsm1[n] + mpn_addlsh1_n_ip1 (vm1 + n, bsm1, n);
+#else
+      cy = 2 * bsm1[n] + mpn_addmul_1 (vm1 + n, bsm1, n, CNST_LIMB(2));
+#endif
+    }
+  else
+    cy = 0;
+  if (bsm1[n] != 0)
+    cy += mpn_add_n (vm1 + n, vm1 + n, asm1, n);
+  vm1[2 * n] = cy;
+#else /* SMALLER_RECURSION */
+  vm1[2 * n] = 0;
+  mpn_mul_n (vm1, asm1, bsm1, n + ((asm1[n] | bsm1[n]) != 0));
+#endif /* SMALLER_RECURSION */
+
+  /* v1, 2n+1 limbs */
+#ifdef SMALLER_RECURSION
+  mpn_mul_n (v1, as1, bs1, n);
+  if (as1[n] == 1)
+    {
+      cy = bs1[n] + mpn_add_n (v1 + n, v1 + n, bs1, n);
+    }
+  else if (as1[n] == 2)
+    {
+#if HAVE_NATIVE_mpn_addlsh1_n_ip1
+      cy = 2 * bs1[n] + mpn_addlsh1_n_ip1 (v1 + n, bs1, n);
+#else
+      cy = 2 * bs1[n] + mpn_addmul_1 (v1 + n, bs1, n, CNST_LIMB(2));
+#endif
+    }
+  else if (as1[n] != 0)
+    {
+      cy = as1[n] * bs1[n] + mpn_addmul_1 (v1 + n, bs1, n, as1[n]);
+    }
+  else
+    cy = 0;
+  if (bs1[n] == 1)
+    {
+      cy += mpn_add_n (v1 + n, v1 + n, as1, n);
+    }
+  else if (bs1[n] == 2)
+    {
+#if HAVE_NATIVE_mpn_addlsh1_n_ip1
+      cy += mpn_addlsh1_n_ip1 (v1 + n, as1, n);
+#else
+      cy += mpn_addmul_1 (v1 + n, as1, n, CNST_LIMB(2));
+#endif
+    }
+  v1[2 * n] = cy;
+#else /* SMALLER_RECURSION */
+  v1[2 * n] = 0;
+  mpn_mul_n (v1, as1, bs1, n + ((as1[n] | bs1[n]) != 0));
+#endif /* SMALLER_RECURSION */
+
+  mpn_mul_n (v0, a0, b0, n);			/* v0, 2n limbs */
+
+  /* vinf, s+t limbs */
+  if (s > t)  mpn_mul (vinf, a4, s, b2, t);
+  else        mpn_mul (vinf, b2, t, a4, s);
+
+  mpn_toom_interpolate_7pts (pp, n, flags, vm2, vm1, v2, vh, s + t,
+			     scratch_out);
+
+  TMP_FREE;
+}
diff --git a/third_party/gmp/mpn/generic/toom54_mul.c b/third_party/gmp/mpn/generic/toom54_mul.c
new file mode 100644
index 0000000..343b02e
--- /dev/null
+++ b/third_party/gmp/mpn/generic/toom54_mul.c
@@ -0,0 +1,142 @@
+/* Implementation of the algorithm for Toom-Cook 4.5-way.
+
+   Contributed to the GNU project by Marco Bodrato.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* Toom-4.5, the splitting 5x4 unbalanced version.
+   Evaluate in: infinity, +4, -4, +2, -2, +1, -1, 0.
+
+  <--s-><--n--><--n--><--n--><--n-->
+   ____ ______ ______ ______ ______
+  |_a4_|__a3__|__a2__|__a1__|__a0__|
+	  |b3_|__b2__|__b1__|__b0__|
+	  <-t-><--n--><--n--><--n-->
+
+*/
+#define TOOM_54_MUL_N_REC(p, a, b, n, ws)		\
+  do {	mpn_mul_n (p, a, b, n);				\
+  } while (0)
+
+#define TOOM_54_MUL_REC(p, a, na, b, nb, ws)		\
+  do {	mpn_mul (p, a, na, b, nb);			\
+  } while (0)
+
+void
+mpn_toom54_mul (mp_ptr pp,
+		mp_srcptr ap, mp_size_t an,
+		mp_srcptr bp, mp_size_t bn, mp_ptr scratch)
+{
+  mp_size_t n, s, t;
+  int sign;
+
+  /***************************** decomposition *******************************/
+#define a4  (ap + 4 * n)
+#define b3  (bp + 3 * n)
+
+  ASSERT (an >= bn);
+  n = 1 + (4 * an >= 5 * bn ? (an - 1) / (size_t) 5 : (bn - 1) / (size_t) 4);
+
+  s = an - 4 * n;
+  t = bn - 3 * n;
+
+  ASSERT (0 < s && s <= n);
+  ASSERT (0 < t && t <= n);
+  /* Required by mpn_toom_interpolate_8pts. */
+  ASSERT ( s + t >= n );
+  ASSERT ( s + t > 4);
+  ASSERT ( n > 2);
+
+#define   r8    pp				/* 2n   */
+#define   r7    scratch				/* 3n+1 */
+#define   r5    (pp + 3*n)			/* 3n+1 */
+#define   v0    (pp + 3*n)			/* n+1 */
+#define   v1    (pp + 4*n+1)			/* n+1 */
+#define   v2    (pp + 5*n+2)			/* n+1 */
+#define   v3    (pp + 6*n+3)			/* n+1 */
+#define   r3    (scratch + 3 * n + 1)		/* 3n+1 */
+#define   r1    (pp + 7*n)			/* s+t <= 2*n */
+#define   ws    (scratch + 6 * n + 2)		/* ??? */
+
+  /* Alloc also 3n+1 limbs for ws... mpn_toom_interpolate_8pts may
+     need all of them, when DO_mpn_sublsh_n usea a scratch  */
+  /********************** evaluation and recursive calls *********************/
+  /* $\pm4$ */
+  sign = mpn_toom_eval_pm2exp (v2, v0, 4, ap, n, s, 2, pp)
+       ^ mpn_toom_eval_pm2exp (v3, v1, 3, bp, n, t, 2, pp);
+  TOOM_54_MUL_N_REC(pp, v0, v1, n + 1, ws); /* A(-4)*B(-4) */
+  TOOM_54_MUL_N_REC(r3, v2, v3, n + 1, ws); /* A(+4)*B(+4) */
+  mpn_toom_couple_handling (r3, 2*n+1, pp, sign, n, 2, 4);
+
+  /* $\pm1$ */
+  sign = mpn_toom_eval_pm1 (v2, v0, 4, ap, n, s,    pp)
+       ^ mpn_toom_eval_dgr3_pm1 (v3, v1, bp, n, t,    pp);
+  TOOM_54_MUL_N_REC(pp, v0, v1, n + 1, ws); /* A(-1)*B(-1) */
+  TOOM_54_MUL_N_REC(r7, v2, v3, n + 1, ws); /* A(1)*B(1) */
+  mpn_toom_couple_handling (r7, 2*n+1, pp, sign, n, 0, 0);
+
+  /* $\pm2$ */
+  sign = mpn_toom_eval_pm2 (v2, v0, 4, ap, n, s, pp)
+       ^ mpn_toom_eval_dgr3_pm2 (v3, v1, bp, n, t, pp);
+  TOOM_54_MUL_N_REC(pp, v0, v1, n + 1, ws); /* A(-2)*B(-2) */
+  TOOM_54_MUL_N_REC(r5, v2, v3, n + 1, ws); /* A(+2)*B(+2) */
+  mpn_toom_couple_handling (r5, 2*n+1, pp, sign, n, 1, 2);
+
+  /* A(0)*B(0) */
+  TOOM_54_MUL_N_REC(pp, ap, bp, n, ws);
+
+  /* Infinity */
+  if (s > t) {
+    TOOM_54_MUL_REC(r1, a4, s, b3, t, ws);
+  } else {
+    TOOM_54_MUL_REC(r1, b3, t, a4, s, ws);
+  };
+
+  mpn_toom_interpolate_8pts (pp, n, r3, r7, s + t, ws);
+
+#undef a4
+#undef b3
+#undef r1
+#undef r3
+#undef r5
+#undef v0
+#undef v1
+#undef v2
+#undef v3
+#undef r7
+#undef r8
+#undef ws
+}
diff --git a/third_party/gmp/mpn/generic/toom62_mul.c b/third_party/gmp/mpn/generic/toom62_mul.c
new file mode 100644
index 0000000..d971cc0
--- /dev/null
+++ b/third_party/gmp/mpn/generic/toom62_mul.c
@@ -0,0 +1,310 @@
+/* mpn_toom62_mul -- Multiply {ap,an} and {bp,bn} where an is nominally 3 times
+   as large as bn.  Or more accurately, (5/2)bn < an < 6bn.
+
+   Contributed to the GNU project by Torbjorn Granlund and Marco Bodrato.
+
+   The idea of applying toom to unbalanced multiplication is due to Marco
+   Bodrato and Alberto Zanoni.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2006-2008, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+/* Evaluate in:
+   0, +1, -1, +2, -2, 1/2, +inf
+
+  <-s-><--n--><--n--><--n--><--n--><--n-->
+   ___ ______ ______ ______ ______ ______
+  |a5_|___a4_|___a3_|___a2_|___a1_|___a0_|
+			     |_b1_|___b0_|
+			     <-t--><--n-->
+
+  v0  =    a0                       *   b0      #    A(0)*B(0)
+  v1  = (  a0+  a1+ a2+ a3+  a4+  a5)*( b0+ b1) #    A(1)*B(1)      ah  <= 5   bh <= 1
+  vm1 = (  a0-  a1+ a2- a3+  a4-  a5)*( b0- b1) #   A(-1)*B(-1)    |ah| <= 2   bh  = 0
+  v2  = (  a0+ 2a1+4a2+8a3+16a4+32a5)*( b0+2b1) #    A(2)*B(2)      ah  <= 62  bh <= 2
+  vm2 = (  a0- 2a1+4a2-8a3+16a4-32a5)*( b0-2b1) #   A(-2)*B(-2)    -41<=ah<=20 -1<=bh<=0
+  vh  = (32a0+16a1+8a2+4a3+ 2a4+  a5)*(2b0+ b1) #  A(1/2)*B(1/2)    ah  <= 62  bh <= 2
+  vinf=                           a5 *      b1  #  A(inf)*B(inf)
+*/
+
+void
+mpn_toom62_mul (mp_ptr pp,
+		mp_srcptr ap, mp_size_t an,
+		mp_srcptr bp, mp_size_t bn,
+		mp_ptr scratch)
+{
+  mp_size_t n, s, t;
+  mp_limb_t cy;
+  mp_ptr as1, asm1, as2, asm2, ash;
+  mp_ptr bs1, bsm1, bs2, bsm2, bsh;
+  mp_ptr gp;
+  enum toom7_flags aflags, bflags;
+  TMP_DECL;
+
+#define a0  ap
+#define a1  (ap + n)
+#define a2  (ap + 2*n)
+#define a3  (ap + 3*n)
+#define a4  (ap + 4*n)
+#define a5  (ap + 5*n)
+#define b0  bp
+#define b1  (bp + n)
+
+  n = 1 + (an >= 3 * bn ? (an - 1) / (size_t) 6 : (bn - 1) >> 1);
+
+  s = an - 5 * n;
+  t = bn - n;
+
+  ASSERT (0 < s && s <= n);
+  ASSERT (0 < t && t <= n);
+
+  TMP_MARK;
+
+  as1 = TMP_SALLOC_LIMBS (n + 1);
+  asm1 = TMP_SALLOC_LIMBS (n + 1);
+  as2 = TMP_SALLOC_LIMBS (n + 1);
+  asm2 = TMP_SALLOC_LIMBS (n + 1);
+  ash = TMP_SALLOC_LIMBS (n + 1);
+
+  bs1 = TMP_SALLOC_LIMBS (n + 1);
+  bsm1 = TMP_SALLOC_LIMBS (n);
+  bs2 = TMP_SALLOC_LIMBS (n + 1);
+  bsm2 = TMP_SALLOC_LIMBS (n + 1);
+  bsh = TMP_SALLOC_LIMBS (n + 1);
+
+  gp = pp;
+
+  /* Compute as1 and asm1.  */
+  aflags = (enum toom7_flags) (toom7_w3_neg & mpn_toom_eval_pm1 (as1, asm1, 5, ap, n, s, gp));
+
+  /* Compute as2 and asm2. */
+  aflags = (enum toom7_flags) (aflags | (toom7_w1_neg & mpn_toom_eval_pm2 (as2, asm2, 5, ap, n, s, gp)));
+
+  /* Compute ash = 32 a0 + 16 a1 + 8 a2 + 4 a3 + 2 a4 + a5
+     = 2*(2*(2*(2*(2*a0 + a1) + a2) + a3) + a4) + a5  */
+
+#if HAVE_NATIVE_mpn_addlsh1_n
+  cy = mpn_addlsh1_n (ash, a1, a0, n);
+  cy = 2*cy + mpn_addlsh1_n (ash, a2, ash, n);
+  cy = 2*cy + mpn_addlsh1_n (ash, a3, ash, n);
+  cy = 2*cy + mpn_addlsh1_n (ash, a4, ash, n);
+  if (s < n)
+    {
+      mp_limb_t cy2;
+      cy2 = mpn_addlsh1_n (ash, a5, ash, s);
+      ash[n] = 2*cy + mpn_lshift (ash + s, ash + s, n - s, 1);
+      MPN_INCR_U (ash + s, n+1-s, cy2);
+    }
+  else
+    ash[n] = 2*cy + mpn_addlsh1_n (ash, a5, ash, n);
+#else
+  cy = mpn_lshift (ash, a0, n, 1);
+  cy += mpn_add_n (ash, ash, a1, n);
+  cy = 2*cy + mpn_lshift (ash, ash, n, 1);
+  cy += mpn_add_n (ash, ash, a2, n);
+  cy = 2*cy + mpn_lshift (ash, ash, n, 1);
+  cy += mpn_add_n (ash, ash, a3, n);
+  cy = 2*cy + mpn_lshift (ash, ash, n, 1);
+  cy += mpn_add_n (ash, ash, a4, n);
+  cy = 2*cy + mpn_lshift (ash, ash, n, 1);
+  ash[n] = cy + mpn_add (ash, ash, n, a5, s);
+#endif
+
+  /* Compute bs1 and bsm1.  */
+  if (t == n)
+    {
+#if HAVE_NATIVE_mpn_add_n_sub_n
+      if (mpn_cmp (b0, b1, n) < 0)
+	{
+	  cy = mpn_add_n_sub_n (bs1, bsm1, b1, b0, n);
+	  bflags = toom7_w3_neg;
+	}
+      else
+	{
+	  cy = mpn_add_n_sub_n (bs1, bsm1, b0, b1, n);
+	  bflags = (enum toom7_flags) 0;
+	}
+      bs1[n] = cy >> 1;
+#else
+      bs1[n] = mpn_add_n (bs1, b0, b1, n);
+      if (mpn_cmp (b0, b1, n) < 0)
+	{
+	  mpn_sub_n (bsm1, b1, b0, n);
+	  bflags = toom7_w3_neg;
+	}
+      else
+	{
+	  mpn_sub_n (bsm1, b0, b1, n);
+	  bflags = (enum toom7_flags) 0;
+	}
+#endif
+    }
+  else
+    {
+      bs1[n] = mpn_add (bs1, b0, n, b1, t);
+      if (mpn_zero_p (b0 + t, n - t) && mpn_cmp (b0, b1, t) < 0)
+	{
+	  mpn_sub_n (bsm1, b1, b0, t);
+	  MPN_ZERO (bsm1 + t, n - t);
+	  bflags = toom7_w3_neg;
+	}
+      else
+	{
+	  mpn_sub (bsm1, b0, n, b1, t);
+	  bflags = (enum toom7_flags) 0;
+	}
+    }
+
+  /* Compute bs2 and bsm2. Recycling bs1 and bsm1; bs2=bs1+b1, bsm2 =
+     bsm1 - b1 */
+  mpn_add (bs2, bs1, n + 1, b1, t);
+  if (bflags & toom7_w3_neg)
+    {
+      bsm2[n] = mpn_add (bsm2, bsm1, n, b1, t);
+      bflags = (enum toom7_flags) (bflags | toom7_w1_neg);
+    }
+  else
+    {
+      /* FIXME: Simplify this logic? */
+      if (t < n)
+	{
+	  if (mpn_zero_p (bsm1 + t, n - t) && mpn_cmp (bsm1, b1, t) < 0)
+	    {
+	      ASSERT_NOCARRY (mpn_sub_n (bsm2, b1, bsm1, t));
+	      MPN_ZERO (bsm2 + t, n + 1 - t);
+	      bflags = (enum toom7_flags) (bflags | toom7_w1_neg);
+	    }
+	  else
+	    {
+	      ASSERT_NOCARRY (mpn_sub (bsm2, bsm1, n, b1, t));
+	      bsm2[n] = 0;
+	    }
+	}
+      else
+	{
+	  if (mpn_cmp (bsm1, b1, n) < 0)
+	    {
+	      ASSERT_NOCARRY (mpn_sub_n (bsm2, b1, bsm1, n));
+	      bflags = (enum toom7_flags) (bflags | toom7_w1_neg);
+	    }
+	  else
+	    {
+	      ASSERT_NOCARRY (mpn_sub_n (bsm2, bsm1, b1, n));
+	    }
+	  bsm2[n] = 0;
+	}
+    }
+
+  /* Compute bsh, recycling bs1. bsh=bs1+b0;  */
+  bsh[n] = bs1[n] + mpn_add_n (bsh, bs1, b0, n);
+
+  ASSERT (as1[n] <= 5);
+  ASSERT (bs1[n] <= 1);
+  ASSERT (asm1[n] <= 2);
+  ASSERT (as2[n] <= 62);
+  ASSERT (bs2[n] <= 2);
+  ASSERT (asm2[n] <= 41);
+  ASSERT (bsm2[n] <= 1);
+  ASSERT (ash[n] <= 62);
+  ASSERT (bsh[n] <= 2);
+
+#define v0    pp				/* 2n */
+#define v1    (pp + 2 * n)			/* 2n+1 */
+#define vinf  (pp + 6 * n)			/* s+t */
+#define v2    scratch				/* 2n+1 */
+#define vm2   (scratch + 2 * n + 1)		/* 2n+1 */
+#define vh    (scratch + 4 * n + 2)		/* 2n+1 */
+#define vm1   (scratch + 6 * n + 3)		/* 2n+1 */
+#define scratch_out (scratch + 8 * n + 4)		/* 2n+1 */
+  /* Total scratch need: 10*n+5 */
+
+  /* Must be in allocation order, as they overwrite one limb beyond
+   * 2n+1. */
+  mpn_mul_n (v2, as2, bs2, n + 1);		/* v2, 2n+1 limbs */
+  mpn_mul_n (vm2, asm2, bsm2, n + 1);		/* vm2, 2n+1 limbs */
+  mpn_mul_n (vh, ash, bsh, n + 1);		/* vh, 2n+1 limbs */
+
+  /* vm1, 2n+1 limbs */
+  mpn_mul_n (vm1, asm1, bsm1, n);
+  cy = 0;
+  if (asm1[n] == 1)
+    {
+      cy = mpn_add_n (vm1 + n, vm1 + n, bsm1, n);
+    }
+  else if (asm1[n] == 2)
+    {
+#if HAVE_NATIVE_mpn_addlsh1_n
+      cy = mpn_addlsh1_n (vm1 + n, vm1 + n, bsm1, n);
+#else
+      cy = mpn_addmul_1 (vm1 + n, bsm1, n, CNST_LIMB(2));
+#endif
+    }
+  vm1[2 * n] = cy;
+
+  /* v1, 2n+1 limbs */
+  mpn_mul_n (v1, as1, bs1, n);
+  if (as1[n] == 1)
+    {
+      cy = bs1[n] + mpn_add_n (v1 + n, v1 + n, bs1, n);
+    }
+  else if (as1[n] == 2)
+    {
+#if HAVE_NATIVE_mpn_addlsh1_n
+      cy = 2 * bs1[n] + mpn_addlsh1_n (v1 + n, v1 + n, bs1, n);
+#else
+      cy = 2 * bs1[n] + mpn_addmul_1 (v1 + n, bs1, n, CNST_LIMB(2));
+#endif
+    }
+  else if (as1[n] != 0)
+    {
+      cy = as1[n] * bs1[n] + mpn_addmul_1 (v1 + n, bs1, n, as1[n]);
+    }
+  else
+    cy = 0;
+  if (bs1[n] != 0)
+    cy += mpn_add_n (v1 + n, v1 + n, as1, n);
+  v1[2 * n] = cy;
+
+  mpn_mul_n (v0, a0, b0, n);			/* v0, 2n limbs */
+
+  /* vinf, s+t limbs */
+  if (s > t)  mpn_mul (vinf, a5, s, b1, t);
+  else        mpn_mul (vinf, b1, t, a5, s);
+
+  mpn_toom_interpolate_7pts (pp, n, (enum toom7_flags) (aflags ^ bflags),
+			     vm2, vm1, v2, vh, s + t, scratch_out);
+
+  TMP_FREE;
+}
diff --git a/third_party/gmp/mpn/generic/toom63_mul.c b/third_party/gmp/mpn/generic/toom63_mul.c
new file mode 100644
index 0000000..181996d
--- /dev/null
+++ b/third_party/gmp/mpn/generic/toom63_mul.c
@@ -0,0 +1,231 @@
+/* Implementation of the algorithm for Toom-Cook 4.5-way.
+
+   Contributed to the GNU project by Marco Bodrato.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+/* Stores |{ap,n}-{bp,n}| in {rp,n}, returns the sign. */
+static int
+abs_sub_n (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n)
+{
+  mp_limb_t  x, y;
+  while (--n >= 0)
+    {
+      x = ap[n];
+      y = bp[n];
+      if (x != y)
+	{
+	  n++;
+	  if (x > y)
+	    {
+	      mpn_sub_n (rp, ap, bp, n);
+	      return 0;
+	    }
+	  else
+	    {
+	      mpn_sub_n (rp, bp, ap, n);
+	      return ~0;
+	    }
+	}
+      rp[n] = 0;
+    }
+  return 0;
+}
+
+static int
+abs_sub_add_n (mp_ptr rm, mp_ptr rp, mp_srcptr rs, mp_size_t n) {
+  int result;
+  result = abs_sub_n (rm, rp, rs, n);
+  ASSERT_NOCARRY(mpn_add_n (rp, rp, rs, n));
+  return result;
+}
+
+
+/* Toom-4.5, the splitting 6x3 unbalanced version.
+   Evaluate in: infinity, +4, -4, +2, -2, +1, -1, 0.
+
+  <--s-><--n--><--n--><--n--><--n--><--n-->
+   ____ ______ ______ ______ ______ ______
+  |_a5_|__a4__|__a3__|__a2__|__a1__|__a0__|
+			|b2_|__b1__|__b0__|
+			<-t-><--n--><--n-->
+
+*/
+#define TOOM_63_MUL_N_REC(p, a, b, n, ws)		\
+  do {	mpn_mul_n (p, a, b, n);				\
+  } while (0)
+
+#define TOOM_63_MUL_REC(p, a, na, b, nb, ws)		\
+  do {	mpn_mul (p, a, na, b, nb);			\
+  } while (0)
+
+void
+mpn_toom63_mul (mp_ptr pp,
+		mp_srcptr ap, mp_size_t an,
+		mp_srcptr bp, mp_size_t bn, mp_ptr scratch)
+{
+  mp_size_t n, s, t;
+  mp_limb_t cy;
+  int sign;
+
+  /***************************** decomposition *******************************/
+#define a5  (ap + 5 * n)
+#define b0  (bp + 0 * n)
+#define b1  (bp + 1 * n)
+#define b2  (bp + 2 * n)
+
+  ASSERT (an >= bn);
+  n = 1 + (an >= 2 * bn ? (an - 1) / (size_t) 6 : (bn - 1) / (size_t) 3);
+
+  s = an - 5 * n;
+  t = bn - 2 * n;
+
+  ASSERT (0 < s && s <= n);
+  ASSERT (0 < t && t <= n);
+  /* WARNING! it assumes s+t>=n */
+  ASSERT ( s + t >= n );
+  ASSERT ( s + t > 4);
+  /* WARNING! it assumes n>1 */
+  ASSERT ( n > 2);
+
+#define   r8    pp				/* 2n   */
+#define   r7    scratch				/* 3n+1 */
+#define   r5    (pp + 3*n)			/* 3n+1 */
+#define   v0    (pp + 3*n)			/* n+1 */
+#define   v1    (pp + 4*n+1)			/* n+1 */
+#define   v2    (pp + 5*n+2)			/* n+1 */
+#define   v3    (pp + 6*n+3)			/* n+1 */
+#define   r3    (scratch + 3 * n + 1)		/* 3n+1 */
+#define   r1    (pp + 7*n)			/* s+t <= 2*n */
+#define   ws    (scratch + 6 * n + 2)		/* ??? */
+
+  /* Alloc also 3n+1 limbs for ws... mpn_toom_interpolate_8pts may
+     need all of them, when DO_mpn_sublsh_n usea a scratch  */
+/*   if (scratch == NULL) scratch = TMP_SALLOC_LIMBS (9 * n + 3); */
+
+  /********************** evaluation and recursive calls *********************/
+  /* $\pm4$ */
+  sign = mpn_toom_eval_pm2exp (v2, v0, 5, ap, n, s, 2, pp);
+  pp[n] = mpn_lshift (pp, b1, n, 2); /* 4b1 */
+  /* FIXME: use addlsh */
+  v3[t] = mpn_lshift (v3, b2, t, 4);/* 16b2 */
+  if ( n == t )
+    v3[n]+= mpn_add_n (v3, v3, b0, n); /* 16b2+b0 */
+  else
+    v3[n] = mpn_add (v3, b0, n, v3, t+1); /* 16b2+b0 */
+  sign ^= abs_sub_add_n (v1, v3, pp, n + 1);
+  TOOM_63_MUL_N_REC(pp, v0, v1, n + 1, ws); /* A(-4)*B(-4) */
+  TOOM_63_MUL_N_REC(r3, v2, v3, n + 1, ws); /* A(+4)*B(+4) */
+  mpn_toom_couple_handling (r3, 2*n+1, pp, sign, n, 2, 4);
+
+  /* $\pm1$ */
+  sign = mpn_toom_eval_pm1 (v2, v0, 5, ap, n, s,    pp);
+  /* Compute bs1 and bsm1. Code taken from toom33 */
+  cy = mpn_add (ws, b0, n, b2, t);
+#if HAVE_NATIVE_mpn_add_n_sub_n
+  if (cy == 0 && mpn_cmp (ws, b1, n) < 0)
+    {
+      cy = mpn_add_n_sub_n (v3, v1, b1, ws, n);
+      v3[n] = cy >> 1;
+      v1[n] = 0;
+      sign = ~sign;
+    }
+  else
+    {
+      mp_limb_t cy2;
+      cy2 = mpn_add_n_sub_n (v3, v1, ws, b1, n);
+      v3[n] = cy + (cy2 >> 1);
+      v1[n] = cy - (cy2 & 1);
+    }
+#else
+  v3[n] = cy + mpn_add_n (v3, ws, b1, n);
+  if (cy == 0 && mpn_cmp (ws, b1, n) < 0)
+    {
+      mpn_sub_n (v1, b1, ws, n);
+      v1[n] = 0;
+      sign = ~sign;
+    }
+  else
+    {
+      cy -= mpn_sub_n (v1, ws, b1, n);
+      v1[n] = cy;
+    }
+#endif
+  TOOM_63_MUL_N_REC(pp, v0, v1, n + 1, ws); /* A(-1)*B(-1) */
+  TOOM_63_MUL_N_REC(r7, v2, v3, n + 1, ws); /* A(1)*B(1) */
+  mpn_toom_couple_handling (r7, 2*n+1, pp, sign, n, 0, 0);
+
+  /* $\pm2$ */
+  sign = mpn_toom_eval_pm2 (v2, v0, 5, ap, n, s, pp);
+  pp[n] = mpn_lshift (pp, b1, n, 1); /* 2b1 */
+  /* FIXME: use addlsh or addlsh2 */
+  v3[t] = mpn_lshift (v3, b2, t, 2);/* 4b2 */
+  if ( n == t )
+    v3[n]+= mpn_add_n (v3, v3, b0, n); /* 4b2+b0 */
+  else
+    v3[n] = mpn_add (v3, b0, n, v3, t+1); /* 4b2+b0 */
+  sign ^= abs_sub_add_n (v1, v3, pp, n + 1);
+  TOOM_63_MUL_N_REC(pp, v0, v1, n + 1, ws); /* A(-2)*B(-2) */
+  TOOM_63_MUL_N_REC(r5, v2, v3, n + 1, ws); /* A(+2)*B(+2) */
+  mpn_toom_couple_handling (r5, 2*n+1, pp, sign, n, 1, 2);
+
+  /* A(0)*B(0) */
+  TOOM_63_MUL_N_REC(pp, ap, bp, n, ws);
+
+  /* Infinity */
+  if (s > t) {
+    TOOM_63_MUL_REC(r1, a5, s, b2, t, ws);
+  } else {
+    TOOM_63_MUL_REC(r1, b2, t, a5, s, ws);
+  };
+
+  mpn_toom_interpolate_8pts (pp, n, r3, r7, s + t, ws);
+
+#undef a5
+#undef b0
+#undef b1
+#undef b2
+#undef r1
+#undef r3
+#undef r5
+#undef v0
+#undef v1
+#undef v2
+#undef v3
+#undef r7
+#undef r8
+#undef ws
+}
diff --git a/third_party/gmp/mpn/generic/toom6_sqr.c b/third_party/gmp/mpn/generic/toom6_sqr.c
new file mode 100644
index 0000000..336eef9
--- /dev/null
+++ b/third_party/gmp/mpn/generic/toom6_sqr.c
@@ -0,0 +1,181 @@
+/* Implementation of the squaring algorithm with Toom-Cook 6.5-way.
+
+   Contributed to the GNU project by Marco Bodrato.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+
+#if GMP_NUMB_BITS < 21
+#error Not implemented.
+#endif
+
+
+#if TUNE_PROGRAM_BUILD
+#define MAYBE_sqr_basecase 1
+#define MAYBE_sqr_above_basecase   1
+#define MAYBE_sqr_toom2   1
+#define MAYBE_sqr_above_toom2   1
+#define MAYBE_sqr_toom3   1
+#define MAYBE_sqr_above_toom3   1
+#define MAYBE_sqr_above_toom4   1
+#else
+#ifdef  SQR_TOOM8_THRESHOLD
+#define SQR_TOOM6_MAX ((SQR_TOOM8_THRESHOLD+6*2-1+5)/6)
+#else
+#define SQR_TOOM6_MAX					\
+  ((SQR_FFT_THRESHOLD <= MP_SIZE_T_MAX - (6*2-1+5)) ?	\
+   ((SQR_FFT_THRESHOLD+6*2-1+5)/6)			\
+   : MP_SIZE_T_MAX )
+#endif
+#define MAYBE_sqr_basecase					\
+  (SQR_TOOM6_THRESHOLD < 6 * SQR_TOOM2_THRESHOLD)
+#define MAYBE_sqr_above_basecase				\
+  (SQR_TOOM6_MAX >=  SQR_TOOM2_THRESHOLD)
+#define MAYBE_sqr_toom2						\
+  (SQR_TOOM6_THRESHOLD < 6 * SQR_TOOM3_THRESHOLD)
+#define MAYBE_sqr_above_toom2					\
+  (SQR_TOOM6_MAX >= SQR_TOOM3_THRESHOLD)
+#define MAYBE_sqr_toom3						\
+  (SQR_TOOM6_THRESHOLD < 6 * SQR_TOOM4_THRESHOLD)
+#define MAYBE_sqr_above_toom3					\
+  (SQR_TOOM6_MAX >= SQR_TOOM4_THRESHOLD)
+#define MAYBE_sqr_above_toom4					\
+  (SQR_TOOM6_MAX >= SQR_TOOM6_THRESHOLD)
+#endif
+
+#define TOOM6_SQR_REC(p, a, n, ws)					\
+  do {									\
+    if (MAYBE_sqr_basecase && ( !MAYBE_sqr_above_basecase		\
+	|| BELOW_THRESHOLD (n, SQR_TOOM2_THRESHOLD)))			\
+      mpn_sqr_basecase (p, a, n);					\
+    else if (MAYBE_sqr_toom2 && ( !MAYBE_sqr_above_toom2		\
+	     || BELOW_THRESHOLD (n, SQR_TOOM3_THRESHOLD)))		\
+      mpn_toom2_sqr (p, a, n, ws);					\
+    else if (MAYBE_sqr_toom3 && ( !MAYBE_sqr_above_toom3		\
+	     || BELOW_THRESHOLD (n, SQR_TOOM4_THRESHOLD)))		\
+      mpn_toom3_sqr (p, a, n, ws);					\
+    else if (! MAYBE_sqr_above_toom4					\
+	     || BELOW_THRESHOLD (n, SQR_TOOM6_THRESHOLD))		\
+      mpn_toom4_sqr (p, a, n, ws);					\
+    else								\
+      mpn_toom6_sqr (p, a, n, ws);					\
+  } while (0)
+
+void
+mpn_toom6_sqr  (mp_ptr pp, mp_srcptr ap, mp_size_t an, mp_ptr scratch)
+{
+  mp_size_t n, s;
+
+  /***************************** decomposition *******************************/
+
+  ASSERT( an >= 18 );
+
+  n = 1 + (an - 1) / (size_t) 6;
+
+  s = an - 5 * n;
+
+  ASSERT (0 < s && s <= n);
+
+#define   r4    (pp + 3 * n)			/* 3n+1 */
+#define   r2    (pp + 7 * n)			/* 3n+1 */
+#define   r0    (pp +11 * n)			/* s+t <= 2*n */
+#define   r5    (scratch)			/* 3n+1 */
+#define   r3    (scratch + 3 * n + 1)		/* 3n+1 */
+#define   r1    (scratch + 6 * n + 2)		/* 3n+1 */
+#define   v0    (pp + 7 * n)			/* n+1 */
+#define   v2    (pp + 9 * n+2)			/* n+1 */
+#define   wse   (scratch + 9 * n + 3)		/* 3n+1 */
+
+  /* Alloc also 3n+1 limbs for ws... toom_interpolate_12pts may
+     need all of them, when DO_mpn_sublsh_n usea a scratch  */
+/*   if (scratch== NULL) */
+/*     scratch = TMP_SALLOC_LIMBS (12 * n + 6); */
+
+  /********************** evaluation and recursive calls *********************/
+  /* $\pm1/2$ */
+  mpn_toom_eval_pm2rexp (v2, v0, 5, ap, n, s, 1, pp);
+  TOOM6_SQR_REC(pp, v0, n + 1, wse); /* A(-1/2)*B(-1/2)*2^. */
+  TOOM6_SQR_REC(r5, v2, n + 1, wse); /* A(+1/2)*B(+1/2)*2^. */
+  mpn_toom_couple_handling (r5, 2 * n + 1, pp, 0, n, 1, 0);
+
+  /* $\pm1$ */
+  mpn_toom_eval_pm1 (v2, v0, 5, ap, n, s,    pp);
+  TOOM6_SQR_REC(pp, v0, n + 1, wse); /* A(-1)*B(-1) */
+  TOOM6_SQR_REC(r3, v2, n + 1, wse); /* A(1)*B(1) */
+  mpn_toom_couple_handling (r3, 2 * n + 1, pp, 0, n, 0, 0);
+
+  /* $\pm4$ */
+  mpn_toom_eval_pm2exp (v2, v0, 5, ap, n, s, 2, pp);
+  TOOM6_SQR_REC(pp, v0, n + 1, wse); /* A(-4)*B(-4) */
+  TOOM6_SQR_REC(r1, v2, n + 1, wse); /* A(+4)*B(+4) */
+  mpn_toom_couple_handling (r1, 2 * n + 1, pp, 0, n, 2, 4);
+
+  /* $\pm1/4$ */
+  mpn_toom_eval_pm2rexp (v2, v0, 5, ap, n, s, 2, pp);
+  TOOM6_SQR_REC(pp, v0, n + 1, wse); /* A(-1/4)*B(-1/4)*4^. */
+  TOOM6_SQR_REC(r4, v2, n + 1, wse); /* A(+1/4)*B(+1/4)*4^. */
+  mpn_toom_couple_handling (r4, 2 * n + 1, pp, 0, n, 2, 0);
+
+  /* $\pm2$ */
+  mpn_toom_eval_pm2 (v2, v0, 5, ap, n, s, pp);
+  TOOM6_SQR_REC(pp, v0, n + 1, wse); /* A(-2)*B(-2) */
+  TOOM6_SQR_REC(r2, v2, n + 1, wse); /* A(+2)*B(+2) */
+  mpn_toom_couple_handling (r2, 2 * n + 1, pp, 0, n, 1, 2);
+
+#undef v0
+#undef v2
+
+  /* A(0)*B(0) */
+  TOOM6_SQR_REC(pp, ap, n, wse);
+
+  mpn_toom_interpolate_12pts (pp, r1, r3, r5, n, 2 * s, 0, wse);
+
+#undef r0
+#undef r1
+#undef r2
+#undef r3
+#undef r4
+#undef r5
+
+}
+#undef TOOM6_SQR_REC
+#undef MAYBE_sqr_basecase
+#undef MAYBE_sqr_above_basecase
+#undef MAYBE_sqr_toom2
+#undef MAYBE_sqr_above_toom2
+#undef MAYBE_sqr_toom3
+#undef MAYBE_sqr_above_toom3
+#undef MAYBE_sqr_above_toom4
diff --git a/third_party/gmp/mpn/generic/toom6h_mul.c b/third_party/gmp/mpn/generic/toom6h_mul.c
new file mode 100644
index 0000000..637f2a5
--- /dev/null
+++ b/third_party/gmp/mpn/generic/toom6h_mul.c
@@ -0,0 +1,262 @@
+/* Implementation of the multiplication algorithm for Toom-Cook 6.5-way.
+
+   Contributed to the GNU project by Marco Bodrato.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009, 2010, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+
+#if GMP_NUMB_BITS < 21
+#error Not implemented.
+#endif
+
+#if TUNE_PROGRAM_BUILD
+#define MAYBE_mul_basecase 1
+#define MAYBE_mul_toom22   1
+#define MAYBE_mul_toom33   1
+#define MAYBE_mul_toom6h   1
+#else
+#define MAYBE_mul_basecase						\
+  (MUL_TOOM6H_THRESHOLD < 6 * MUL_TOOM22_THRESHOLD)
+#define MAYBE_mul_toom22						\
+  (MUL_TOOM6H_THRESHOLD < 6 * MUL_TOOM33_THRESHOLD)
+#define MAYBE_mul_toom33						\
+  (MUL_TOOM6H_THRESHOLD < 6 * MUL_TOOM44_THRESHOLD)
+#define MAYBE_mul_toom6h						\
+  (MUL_FFT_THRESHOLD >= 6 * MUL_TOOM6H_THRESHOLD)
+#endif
+
+#define TOOM6H_MUL_N_REC(p, a, b, f, p2, a2, b2, n, ws)			\
+  do {									\
+    if (MAYBE_mul_basecase						\
+	&& BELOW_THRESHOLD (n, MUL_TOOM22_THRESHOLD)) {			\
+      mpn_mul_basecase (p, a, n, b, n);					\
+      if (f)								\
+	mpn_mul_basecase (p2, a2, n, b2, n);				\
+    } else if (MAYBE_mul_toom22						\
+	       && BELOW_THRESHOLD (n, MUL_TOOM33_THRESHOLD)) {		\
+      mpn_toom22_mul (p, a, n, b, n, ws);				\
+      if (f)								\
+	mpn_toom22_mul (p2, a2, n, b2, n, ws);				\
+    } else if (MAYBE_mul_toom33						\
+	       && BELOW_THRESHOLD (n, MUL_TOOM44_THRESHOLD)) {		\
+      mpn_toom33_mul (p, a, n, b, n, ws);				\
+      if (f)								\
+	mpn_toom33_mul (p2, a2, n, b2, n, ws);				\
+    } else if (! MAYBE_mul_toom6h					\
+	       || BELOW_THRESHOLD (n, MUL_TOOM6H_THRESHOLD)) {		\
+      mpn_toom44_mul (p, a, n, b, n, ws);				\
+      if (f)								\
+	mpn_toom44_mul (p2, a2, n, b2, n, ws);				\
+    } else {								\
+      mpn_toom6h_mul (p, a, n, b, n, ws);				\
+      if (f)								\
+	mpn_toom6h_mul (p2, a2, n, b2, n, ws);				\
+    }									\
+  } while (0)
+
+#define TOOM6H_MUL_REC(p, a, na, b, nb, ws)		\
+  do { mpn_mul (p, a, na, b, nb);			\
+  } while (0)
+
+/* Toom-6.5 , compute the product {pp,an+bn} <- {ap,an} * {bp,bn}
+   With: an >= bn >= 46, an*6 <  bn * 17.
+   It _may_ work with bn<=46 and bn*17 < an*6 < bn*18
+
+   Evaluate in: infinity, +4, -4, +2, -2, +1, -1, +1/2, -1/2, +1/4, -1/4, 0.
+*/
+/* Estimate on needed scratch:
+   S(n) <= (n+5)\6*10+4+MAX(S((n+5)\6),1+2*(n+5)\6),
+   since n>42; S(n) <= ceil(log(n)/log(6))*(10+4)+n*12\6 < n*2 + lg2(n)*6
+ */
+
+void
+mpn_toom6h_mul   (mp_ptr pp,
+		  mp_srcptr ap, mp_size_t an,
+		  mp_srcptr bp, mp_size_t bn, mp_ptr scratch)
+{
+  mp_size_t n, s, t;
+  int p, q, half;
+  int sign;
+
+  /***************************** decomposition *******************************/
+
+  ASSERT (an >= bn);
+  /* Can not handle too much unbalancement */
+  ASSERT (bn >= 42);
+  /* Can not handle too much unbalancement */
+  ASSERT ((an*3 <  bn * 8) || (bn >= 46 && an * 6 <  bn * 17));
+
+  /* Limit num/den is a rational number between
+     (12/11)^(log(4)/log(2*4-1)) and (12/11)^(log(6)/log(2*6-1))             */
+#define LIMIT_numerator (18)
+#define LIMIT_denominat (17)
+
+  if (LIKELY (an * LIMIT_denominat < LIMIT_numerator * bn)) /* is 6*... < 6*... */
+    {
+      n = 1 + (an - 1) / (size_t) 6;
+      p = q = 5;
+      half = 0;
+
+      s = an - 5 * n;
+      t = bn - 5 * n;
+    }
+  else {
+    if (an * 5 * LIMIT_numerator < LIMIT_denominat * 7 * bn)
+      { p = 7; q = 6; }
+    else if (an * 5 * LIMIT_denominat < LIMIT_numerator * 7 * bn)
+      { p = 7; q = 5; }
+    else if (an * LIMIT_numerator < LIMIT_denominat * 2 * bn)  /* is 4*... < 8*... */
+      { p = 8; q = 5; }
+    else if (an * LIMIT_denominat < LIMIT_numerator * 2 * bn)  /* is 4*... < 8*... */
+      { p = 8; q = 4; }
+    else
+      { p = 9; q = 4; }
+
+    half = (p ^ q) & 1;
+    n = 1 + (q * an >= p * bn ? (an - 1) / (size_t) p : (bn - 1) / (size_t) q);
+    p--; q--;
+
+    s = an - p * n;
+    t = bn - q * n;
+
+    /* With LIMIT = 16/15, the following recover is needed only if bn<=73*/
+    if (half) { /* Recover from badly chosen splitting */
+      if (UNLIKELY (s<1)) {p--; s+=n; half=0;}
+      else if (UNLIKELY (t<1)) {q--; t+=n; half=0;}
+    }
+  }
+#undef LIMIT_numerator
+#undef LIMIT_denominat
+
+  ASSERT (0 < s && s <= n);
+  ASSERT (0 < t && t <= n);
+  ASSERT (half || s + t > 3);
+  ASSERT (n > 2);
+
+#define   r4    (pp + 3 * n)			/* 3n+1 */
+#define   r2    (pp + 7 * n)			/* 3n+1 */
+#define   r0    (pp +11 * n)			/* s+t <= 2*n */
+#define   r5    (scratch)			/* 3n+1 */
+#define   r3    (scratch + 3 * n + 1)		/* 3n+1 */
+#define   r1    (scratch + 6 * n + 2)		/* 3n+1 */
+#define   v0    (pp + 7 * n)			/* n+1 */
+#define   v1    (pp + 8 * n+1)			/* n+1 */
+#define   v2    (pp + 9 * n+2)			/* n+1 */
+#define   v3    (scratch + 9 * n + 3)		/* n+1 */
+#define   wsi   (scratch + 9 * n + 3)		/* 3n+1 */
+#define   wse   (scratch +10 * n + 4)		/* 2n+1 */
+
+  /* Alloc also 3n+1 limbs for wsi... toom_interpolate_12pts may
+     need all of them  */
+/*   if (scratch == NULL) */
+/*     scratch = TMP_SALLOC_LIMBS(mpn_toom6_sqr_itch(n * 6)); */
+  ASSERT (12 * n + 6 <= mpn_toom6h_mul_itch(an,bn));
+  ASSERT (12 * n + 6 <= mpn_toom6_sqr_itch(n * 6));
+
+  /********************** evaluation and recursive calls *********************/
+  /* $\pm1/2$ */
+  sign = mpn_toom_eval_pm2rexp (v2, v0, p, ap, n, s, 1, pp) ^
+	 mpn_toom_eval_pm2rexp (v3, v1, q, bp, n, t, 1, pp);
+  /* A(-1/2)*B(-1/2)*2^. */ /* A(+1/2)*B(+1/2)*2^. */
+  TOOM6H_MUL_N_REC(pp, v0, v1, 2, r5, v2, v3, n + 1, wse);
+  mpn_toom_couple_handling (r5, 2 * n + 1, pp, sign, n, 1+half , half);
+
+  /* $\pm1$ */
+  sign = mpn_toom_eval_pm1 (v2, v0, p, ap, n, s,    pp);
+  if (UNLIKELY (q == 3))
+    sign ^= mpn_toom_eval_dgr3_pm1 (v3, v1, bp, n, t,    pp);
+  else
+    sign ^= mpn_toom_eval_pm1 (v3, v1, q, bp, n, t,    pp);
+  /* A(-1)*B(-1) */ /* A(1)*B(1) */
+  TOOM6H_MUL_N_REC(pp, v0, v1, 2, r3, v2, v3, n + 1, wse);
+  mpn_toom_couple_handling (r3, 2 * n + 1, pp, sign, n, 0, 0);
+
+  /* $\pm4$ */
+  sign = mpn_toom_eval_pm2exp (v2, v0, p, ap, n, s, 2, pp) ^
+	 mpn_toom_eval_pm2exp (v3, v1, q, bp, n, t, 2, pp);
+  /* A(-4)*B(-4) */
+  TOOM6H_MUL_N_REC(pp, v0, v1, 2, r1, v2, v3, n + 1, wse); /* A(+4)*B(+4) */
+  mpn_toom_couple_handling (r1, 2 * n + 1, pp, sign, n, 2, 4);
+
+  /* $\pm1/4$ */
+  sign = mpn_toom_eval_pm2rexp (v2, v0, p, ap, n, s, 2, pp) ^
+	 mpn_toom_eval_pm2rexp (v3, v1, q, bp, n, t, 2, pp);
+  /* A(-1/4)*B(-1/4)*4^. */ /* A(+1/4)*B(+1/4)*4^. */
+  TOOM6H_MUL_N_REC(pp, v0, v1, 2, r4, v2, v3, n + 1, wse);
+  mpn_toom_couple_handling (r4, 2 * n + 1, pp, sign, n, 2*(1+half), 2*(half));
+
+  /* $\pm2$ */
+  sign = mpn_toom_eval_pm2 (v2, v0, p, ap, n, s, pp) ^
+	 mpn_toom_eval_pm2 (v3, v1, q, bp, n, t, pp);
+  /* A(-2)*B(-2) */ /* A(+2)*B(+2) */
+  TOOM6H_MUL_N_REC(pp, v0, v1, 2, r2, v2, v3, n + 1, wse);
+  mpn_toom_couple_handling (r2, 2 * n + 1, pp, sign, n, 1, 2);
+
+#undef v0
+#undef v1
+#undef v2
+#undef v3
+#undef wse
+
+  /* A(0)*B(0) */
+  TOOM6H_MUL_N_REC(pp, ap, bp, 0, pp, ap, bp, n, wsi);
+
+  /* Infinity */
+  if (UNLIKELY (half != 0)) {
+    if (s > t) {
+      TOOM6H_MUL_REC(r0, ap + p * n, s, bp + q * n, t, wsi);
+    } else {
+      TOOM6H_MUL_REC(r0, bp + q * n, t, ap + p * n, s, wsi);
+    };
+  };
+
+  mpn_toom_interpolate_12pts (pp, r1, r3, r5, n, s+t, half, wsi);
+
+#undef r0
+#undef r1
+#undef r2
+#undef r3
+#undef r4
+#undef r5
+#undef wsi
+}
+
+#undef TOOM6H_MUL_N_REC
+#undef TOOM6H_MUL_REC
+#undef MAYBE_mul_basecase
+#undef MAYBE_mul_toom22
+#undef MAYBE_mul_toom33
+#undef MAYBE_mul_toom6h
diff --git a/third_party/gmp/mpn/generic/toom8_sqr.c b/third_party/gmp/mpn/generic/toom8_sqr.c
new file mode 100644
index 0000000..03e5c64
--- /dev/null
+++ b/third_party/gmp/mpn/generic/toom8_sqr.c
@@ -0,0 +1,225 @@
+/* Implementation of the squaring algorithm with Toom-Cook 8.5-way.
+
+   Contributed to the GNU project by Marco Bodrato.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+#if GMP_NUMB_BITS < 29
+#error Not implemented.
+#endif
+
+#if GMP_NUMB_BITS < 43
+#define BIT_CORRECTION 1
+#define CORRECTION_BITS GMP_NUMB_BITS
+#else
+#define BIT_CORRECTION 0
+#define CORRECTION_BITS 0
+#endif
+
+#ifndef SQR_TOOM8_THRESHOLD
+#define SQR_TOOM8_THRESHOLD MUL_TOOM8H_THRESHOLD
+#endif
+
+#ifndef SQR_TOOM6_THRESHOLD
+#define SQR_TOOM6_THRESHOLD MUL_TOOM6H_THRESHOLD
+#endif
+
+#if TUNE_PROGRAM_BUILD
+#define MAYBE_sqr_basecase 1
+#define MAYBE_sqr_above_basecase   1
+#define MAYBE_sqr_toom2   1
+#define MAYBE_sqr_above_toom2   1
+#define MAYBE_sqr_toom3   1
+#define MAYBE_sqr_above_toom3   1
+#define MAYBE_sqr_toom4   1
+#define MAYBE_sqr_above_toom4   1
+#define MAYBE_sqr_above_toom6   1
+#else
+#define SQR_TOOM8_MAX					\
+  ((SQR_FFT_THRESHOLD <= MP_SIZE_T_MAX - (8*2-1+7)) ?	\
+   ((SQR_FFT_THRESHOLD+8*2-1+7)/8)			\
+   : MP_SIZE_T_MAX )
+#define MAYBE_sqr_basecase					\
+  (SQR_TOOM8_THRESHOLD < 8 * SQR_TOOM2_THRESHOLD)
+#define MAYBE_sqr_above_basecase				\
+  (SQR_TOOM8_MAX >= SQR_TOOM2_THRESHOLD)
+#define MAYBE_sqr_toom2						\
+  (SQR_TOOM8_THRESHOLD < 8 * SQR_TOOM3_THRESHOLD)
+#define MAYBE_sqr_above_toom2					\
+  (SQR_TOOM8_MAX >= SQR_TOOM3_THRESHOLD)
+#define MAYBE_sqr_toom3						\
+  (SQR_TOOM8_THRESHOLD < 8 * SQR_TOOM4_THRESHOLD)
+#define MAYBE_sqr_above_toom3					\
+  (SQR_TOOM8_MAX >= SQR_TOOM4_THRESHOLD)
+#define MAYBE_sqr_toom4						\
+  (SQR_TOOM8_THRESHOLD < 8 * SQR_TOOM6_THRESHOLD)
+#define MAYBE_sqr_above_toom4					\
+  (SQR_TOOM8_MAX >= SQR_TOOM6_THRESHOLD)
+#define MAYBE_sqr_above_toom6					\
+  (SQR_TOOM8_MAX >= SQR_TOOM8_THRESHOLD)
+#endif
+
+#define TOOM8_SQR_REC(p, a, f, p2, a2, n, ws)				\
+  do {									\
+    if (MAYBE_sqr_basecase && ( !MAYBE_sqr_above_basecase		\
+	|| BELOW_THRESHOLD (n, SQR_TOOM2_THRESHOLD))) {			\
+      mpn_sqr_basecase (p, a, n);					\
+      if (f) mpn_sqr_basecase (p2, a2, n);				\
+    } else if (MAYBE_sqr_toom2 && ( !MAYBE_sqr_above_toom2		\
+	     || BELOW_THRESHOLD (n, SQR_TOOM3_THRESHOLD))) {		\
+      mpn_toom2_sqr (p, a, n, ws);					\
+      if (f) mpn_toom2_sqr (p2, a2, n, ws);				\
+    } else if (MAYBE_sqr_toom3 && ( !MAYBE_sqr_above_toom3		\
+	     || BELOW_THRESHOLD (n, SQR_TOOM4_THRESHOLD))) {		\
+      mpn_toom3_sqr (p, a, n, ws);					\
+      if (f) mpn_toom3_sqr (p2, a2, n, ws);				\
+    } else if (MAYBE_sqr_toom4 && ( !MAYBE_sqr_above_toom4		\
+	     || BELOW_THRESHOLD (n, SQR_TOOM6_THRESHOLD))) {		\
+      mpn_toom4_sqr (p, a, n, ws);					\
+      if (f) mpn_toom4_sqr (p2, a2, n, ws);				\
+    } else if (! MAYBE_sqr_above_toom6					\
+	     || BELOW_THRESHOLD (n, SQR_TOOM8_THRESHOLD)) {		\
+      mpn_toom6_sqr (p, a, n, ws);					\
+      if (f) mpn_toom6_sqr (p2, a2, n, ws);				\
+    } else {								\
+      mpn_toom8_sqr (p, a, n, ws);					\
+      if (f) mpn_toom8_sqr (p2, a2, n, ws);				\
+    }									\
+  } while (0)
+
+void
+mpn_toom8_sqr  (mp_ptr pp, mp_srcptr ap, mp_size_t an, mp_ptr scratch)
+{
+  mp_size_t n, s;
+
+  /***************************** decomposition *******************************/
+
+  ASSERT ( an >= 40 );
+
+  n = 1 + ((an - 1)>>3);
+
+  s = an - 7 * n;
+
+  ASSERT (0 < s && s <= n);
+  ASSERT ( s + s > 3 );
+
+#define   r6    (pp + 3 * n)			/* 3n+1 */
+#define   r4    (pp + 7 * n)			/* 3n+1 */
+#define   r2    (pp +11 * n)			/* 3n+1 */
+#define   r0    (pp +15 * n)			/* s+t <= 2*n */
+#define   r7    (scratch)			/* 3n+1 */
+#define   r5    (scratch + 3 * n + 1)		/* 3n+1 */
+#define   r3    (scratch + 6 * n + 2)		/* 3n+1 */
+#define   r1    (scratch + 9 * n + 3)		/* 3n+1 */
+#define   v0    (pp +11 * n)			/* n+1 */
+#define   v2    (pp +13 * n+2)			/* n+1 */
+#define   wse   (scratch +12 * n + 4)		/* 3n+1 */
+
+  /* Alloc also 3n+1 limbs for ws... toom_interpolate_16pts may
+     need all of them, when DO_mpn_sublsh_n usea a scratch  */
+/*   if (scratch == NULL) */
+/*     scratch = TMP_SALLOC_LIMBS (30 * n + 6); */
+
+  /********************** evaluation and recursive calls *********************/
+  /* $\pm1/8$ */
+  mpn_toom_eval_pm2rexp (v2, v0, 7, ap, n, s, 3, pp);
+  /* A(-1/8)*B(-1/8)*8^. */ /* A(+1/8)*B(+1/8)*8^. */
+  TOOM8_SQR_REC(pp, v0, 2, r7, v2, n + 1, wse);
+  mpn_toom_couple_handling (r7, 2 * n + 1 + BIT_CORRECTION, pp, 0, n, 3, 0);
+
+  /* $\pm1/4$ */
+  mpn_toom_eval_pm2rexp (v2, v0, 7, ap, n, s, 2, pp);
+  /* A(-1/4)*B(-1/4)*4^. */ /* A(+1/4)*B(+1/4)*4^. */
+  TOOM8_SQR_REC(pp, v0, 2, r5, v2, n + 1, wse);
+  mpn_toom_couple_handling (r5, 2 * n + 1, pp, 0, n, 2, 0);
+
+  /* $\pm2$ */
+  mpn_toom_eval_pm2 (v2, v0, 7, ap, n, s, pp);
+  /* A(-2)*B(-2) */ /* A(+2)*B(+2) */
+  TOOM8_SQR_REC(pp, v0, 2, r3, v2, n + 1, wse);
+  mpn_toom_couple_handling (r3, 2 * n + 1, pp, 0, n, 1, 2);
+
+  /* $\pm8$ */
+  mpn_toom_eval_pm2exp (v2, v0, 7, ap, n, s, 3, pp);
+  /* A(-8)*B(-8) */ /* A(+8)*B(+8) */
+  TOOM8_SQR_REC(pp, v0, 2, r1, v2, n + 1, wse);
+  mpn_toom_couple_handling (r1, 2 * n + 1 + BIT_CORRECTION, pp, 0, n, 3, 6);
+
+  /* $\pm1/2$ */
+  mpn_toom_eval_pm2rexp (v2, v0, 7, ap, n, s, 1, pp);
+  /* A(-1/2)*B(-1/2)*2^. */ /* A(+1/2)*B(+1/2)*2^. */
+  TOOM8_SQR_REC(pp, v0, 2, r6, v2, n + 1, wse);
+  mpn_toom_couple_handling (r6, 2 * n + 1, pp, 0, n, 1, 0);
+
+  /* $\pm1$ */
+  mpn_toom_eval_pm1 (v2, v0, 7, ap, n, s,    pp);
+  /* A(-1)*B(-1) */ /* A(1)*B(1) */
+  TOOM8_SQR_REC(pp, v0, 2, r4, v2, n + 1, wse);
+  mpn_toom_couple_handling (r4, 2 * n + 1, pp, 0, n, 0, 0);
+
+  /* $\pm4$ */
+  mpn_toom_eval_pm2exp (v2, v0, 7, ap, n, s, 2, pp);
+  /* A(-4)*B(-4) */ /* A(+4)*B(+4) */
+  TOOM8_SQR_REC(pp, v0, 2, r2, v2, n + 1, wse);
+  mpn_toom_couple_handling (r2, 2 * n + 1, pp, 0, n, 2, 4);
+
+#undef v0
+#undef v2
+
+  /* A(0)*B(0) */
+  TOOM8_SQR_REC(pp, ap, 0, pp, ap, n, wse);
+
+  mpn_toom_interpolate_16pts (pp, r1, r3, r5, r7, n, 2 * s, 0, wse);
+
+#undef r0
+#undef r1
+#undef r2
+#undef r3
+#undef r4
+#undef r5
+#undef r6
+#undef wse
+
+}
+
+#undef TOOM8_SQR_REC
+#undef MAYBE_sqr_basecase
+#undef MAYBE_sqr_above_basecase
+#undef MAYBE_sqr_toom2
+#undef MAYBE_sqr_above_toom2
+#undef MAYBE_sqr_toom3
+#undef MAYBE_sqr_above_toom3
+#undef MAYBE_sqr_above_toom4
diff --git a/third_party/gmp/mpn/generic/toom8h_mul.c b/third_party/gmp/mpn/generic/toom8h_mul.c
new file mode 100644
index 0000000..5ba259a
--- /dev/null
+++ b/third_party/gmp/mpn/generic/toom8h_mul.c
@@ -0,0 +1,305 @@
+/* Implementation of the multiplication algorithm for Toom-Cook 8.5-way.
+
+   Contributed to the GNU project by Marco Bodrato.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009, 2010, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+
+#if GMP_NUMB_BITS < 29
+#error Not implemented.
+#endif
+
+#if GMP_NUMB_BITS < 43
+#define BIT_CORRECTION 1
+#define CORRECTION_BITS GMP_NUMB_BITS
+#else
+#define BIT_CORRECTION 0
+#define CORRECTION_BITS 0
+#endif
+
+
+#if TUNE_PROGRAM_BUILD
+#define MAYBE_mul_basecase 1
+#define MAYBE_mul_toom22   1
+#define MAYBE_mul_toom33   1
+#define MAYBE_mul_toom44   1
+#define MAYBE_mul_toom8h   1
+#else
+#define MAYBE_mul_basecase						\
+  (MUL_TOOM8H_THRESHOLD < 8 * MUL_TOOM22_THRESHOLD)
+#define MAYBE_mul_toom22						\
+  (MUL_TOOM8H_THRESHOLD < 8 * MUL_TOOM33_THRESHOLD)
+#define MAYBE_mul_toom33						\
+  (MUL_TOOM8H_THRESHOLD < 8 * MUL_TOOM44_THRESHOLD)
+#define MAYBE_mul_toom44						\
+  (MUL_TOOM8H_THRESHOLD < 8 * MUL_TOOM6H_THRESHOLD)
+#define MAYBE_mul_toom8h						\
+  (MUL_FFT_THRESHOLD >= 8 * MUL_TOOM8H_THRESHOLD)
+#endif
+
+#define TOOM8H_MUL_N_REC(p, a, b, f, p2, a2, b2, n, ws)			\
+  do {									\
+    if (MAYBE_mul_basecase						\
+	&& BELOW_THRESHOLD (n, MUL_TOOM22_THRESHOLD)) {			\
+      mpn_mul_basecase (p, a, n, b, n);					\
+      if (f) mpn_mul_basecase (p2, a2, n, b2, n);			\
+    } else if (MAYBE_mul_toom22						\
+	     && BELOW_THRESHOLD (n, MUL_TOOM33_THRESHOLD)) {		\
+      mpn_toom22_mul (p, a, n, b, n, ws);				\
+      if (f) mpn_toom22_mul (p2, a2, n, b2, n, ws);			\
+    } else if (MAYBE_mul_toom33						\
+	     && BELOW_THRESHOLD (n, MUL_TOOM44_THRESHOLD)) {		\
+      mpn_toom33_mul (p, a, n, b, n, ws);				\
+      if (f) mpn_toom33_mul (p2, a2, n, b2, n, ws);			\
+    } else if (MAYBE_mul_toom44						\
+	     && BELOW_THRESHOLD (n, MUL_TOOM6H_THRESHOLD)) {		\
+      mpn_toom44_mul (p, a, n, b, n, ws);				\
+      if (f) mpn_toom44_mul (p2, a2, n, b2, n, ws);			\
+    } else if (! MAYBE_mul_toom8h					\
+	     || BELOW_THRESHOLD (n, MUL_TOOM8H_THRESHOLD)) {		\
+      mpn_toom6h_mul (p, a, n, b, n, ws);				\
+      if (f) mpn_toom6h_mul (p2, a2, n, b2, n, ws);			\
+    } else {								\
+      mpn_toom8h_mul (p, a, n, b, n, ws);				\
+      if (f) mpn_toom8h_mul (p2, a2, n, b2, n, ws);			\
+    }									\
+  } while (0)
+
+#define TOOM8H_MUL_REC(p, a, na, b, nb, ws)		\
+  do { mpn_mul (p, a, na, b, nb); } while (0)
+
+/* Toom-8.5 , compute the product {pp,an+bn} <- {ap,an} * {bp,bn}
+   With: an >= bn >= 86, an*5 <  bn * 11.
+   It _may_ work with bn<=?? and bn*?? < an*? < bn*??
+
+   Evaluate in: infinity, +8,-8,+4,-4,+2,-2,+1,-1,+1/2,-1/2,+1/4,-1/4,+1/8,-1/8,0.
+*/
+/* Estimate on needed scratch:
+   S(n) <= (n+7)\8*13+5+MAX(S((n+7)\8),1+2*(n+7)\8),
+   since n>80; S(n) <= ceil(log(n/10)/log(8))*(13+5)+n*15\8 < n*15\8 + lg2(n)*6
+ */
+
+void
+mpn_toom8h_mul   (mp_ptr pp,
+		  mp_srcptr ap, mp_size_t an,
+		  mp_srcptr bp, mp_size_t bn, mp_ptr scratch)
+{
+  mp_size_t n, s, t;
+  int p, q, half;
+  int sign;
+
+  /***************************** decomposition *******************************/
+
+  ASSERT (an >= bn);
+  /* Can not handle too small operands */
+  ASSERT (bn >= 86);
+  /* Can not handle too much unbalancement */
+  ASSERT (an <= bn*4);
+  ASSERT (GMP_NUMB_BITS > 11*3 || an*4 <= bn*11);
+  ASSERT (GMP_NUMB_BITS > 10*3 || an*1 <= bn* 2);
+  ASSERT (GMP_NUMB_BITS >  9*3 || an*2 <= bn* 3);
+
+  /* Limit num/den is a rational number between
+     (16/15)^(log(6)/log(2*6-1)) and (16/15)^(log(8)/log(2*8-1))             */
+#define LIMIT_numerator (21)
+#define LIMIT_denominat (20)
+
+  if (LIKELY (an == bn) || an * (LIMIT_denominat>>1) < LIMIT_numerator * (bn>>1) ) /* is 8*... < 8*... */
+    {
+      half = 0;
+      n = 1 + ((an - 1)>>3);
+      p = q = 7;
+      s = an - 7 * n;
+      t = bn - 7 * n;
+    }
+  else
+    {
+      if (an * 13 < 16 * bn) /* (an*7*LIMIT_numerator<LIMIT_denominat*9*bn) */
+	{ p = 9; q = 8; }
+      else if (GMP_NUMB_BITS <= 9*3 ||
+	       an *(LIMIT_denominat>>1) < (LIMIT_numerator/7*9) * (bn>>1))
+	{ p = 9; q = 7; }
+      else if (an * 10 < 33 * (bn>>1)) /* (an*3*LIMIT_numerator<LIMIT_denominat*5*bn) */
+	{ p =10; q = 7; }
+      else if (GMP_NUMB_BITS <= 10*3 ||
+	       an * (LIMIT_denominat/5) < (LIMIT_numerator/3) * bn)
+	{ p =10; q = 6; }
+      else if (an * 6 < 13 * bn) /*(an * 5 * LIMIT_numerator < LIMIT_denominat *11 * bn)*/
+	{ p =11; q = 6; }
+      else if (GMP_NUMB_BITS <= 11*3 ||
+	       an * 4 < 9 * bn)
+	{ p =11; q = 5; }
+      else if (an *(LIMIT_numerator/3) < LIMIT_denominat * bn)  /* is 4*... <12*... */
+	{ p =12; q = 5; }
+      else if (GMP_NUMB_BITS <= 12*3 ||
+	       an * 9 < 28 * bn )  /* is 4*... <12*... */
+	{ p =12; q = 4; }
+      else
+	{ p =13; q = 4; }
+
+      half = (p+q)&1;
+      n = 1 + (q * an >= p * bn ? (an - 1) / (size_t) p : (bn - 1) / (size_t) q);
+      p--; q--;
+
+      s = an - p * n;
+      t = bn - q * n;
+
+      if(half) { /* Recover from badly chosen splitting */
+	if (UNLIKELY (s<1)) {p--; s+=n; half=0;}
+	else if (UNLIKELY (t<1)) {q--; t+=n; half=0;}
+      }
+    }
+#undef LIMIT_numerator
+#undef LIMIT_denominat
+
+  ASSERT (0 < s && s <= n);
+  ASSERT (0 < t && t <= n);
+  ASSERT (half || s + t > 3);
+  ASSERT (n > 2);
+
+#define   r6    (pp + 3 * n)			/* 3n+1 */
+#define   r4    (pp + 7 * n)			/* 3n+1 */
+#define   r2    (pp +11 * n)			/* 3n+1 */
+#define   r0    (pp +15 * n)			/* s+t <= 2*n */
+#define   r7    (scratch)			/* 3n+1 */
+#define   r5    (scratch + 3 * n + 1)		/* 3n+1 */
+#define   r3    (scratch + 6 * n + 2)		/* 3n+1 */
+#define   r1    (scratch + 9 * n + 3)		/* 3n+1 */
+#define   v0    (pp +11 * n)			/* n+1 */
+#define   v1    (pp +12 * n+1)			/* n+1 */
+#define   v2    (pp +13 * n+2)			/* n+1 */
+#define   v3    (scratch +12 * n + 4)		/* n+1 */
+#define   wsi   (scratch +12 * n + 4)		/* 3n+1 */
+#define   wse   (scratch +13 * n + 5)		/* 2n+1 */
+
+  /* Alloc also 3n+1 limbs for wsi... toom_interpolate_16pts may
+     need all of them  */
+/*   if (scratch == NULL) */
+/*     scratch = TMP_SALLOC_LIMBS(mpn_toom8_sqr_itch(n * 8)); */
+  ASSERT (15 * n + 6 <= mpn_toom8h_mul_itch (an, bn));
+  ASSERT (15 * n + 6 <= mpn_toom8_sqr_itch (n * 8));
+
+  /********************** evaluation and recursive calls *********************/
+
+  /* $\pm1/8$ */
+  sign = mpn_toom_eval_pm2rexp (v2, v0, p, ap, n, s, 3, pp) ^
+	 mpn_toom_eval_pm2rexp (v3, v1, q, bp, n, t, 3, pp);
+  /* A(-1/8)*B(-1/8)*8^. */ /* A(+1/8)*B(+1/8)*8^. */
+  TOOM8H_MUL_N_REC(pp, v0, v1, 2, r7, v2, v3, n + 1, wse);
+  mpn_toom_couple_handling (r7, 2 * n + 1 + BIT_CORRECTION, pp, sign, n, 3*(1+half), 3*(half));
+
+  /* $\pm1/4$ */
+  sign = mpn_toom_eval_pm2rexp (v2, v0, p, ap, n, s, 2, pp) ^
+	 mpn_toom_eval_pm2rexp (v3, v1, q, bp, n, t, 2, pp);
+  /* A(-1/4)*B(-1/4)*4^. */ /* A(+1/4)*B(+1/4)*4^. */
+  TOOM8H_MUL_N_REC(pp, v0, v1, 2, r5, v2, v3, n + 1, wse);
+  mpn_toom_couple_handling (r5, 2 * n + 1, pp, sign, n, 2*(1+half), 2*(half));
+
+  /* $\pm2$ */
+  sign = mpn_toom_eval_pm2 (v2, v0, p, ap, n, s, pp) ^
+	 mpn_toom_eval_pm2 (v3, v1, q, bp, n, t, pp);
+  /* A(-2)*B(-2) */ /* A(+2)*B(+2) */
+  TOOM8H_MUL_N_REC(pp, v0, v1, 2, r3, v2, v3, n + 1, wse);
+  mpn_toom_couple_handling (r3, 2 * n + 1, pp, sign, n, 1, 2);
+
+  /* $\pm8$ */
+  sign = mpn_toom_eval_pm2exp (v2, v0, p, ap, n, s, 3, pp) ^
+	 mpn_toom_eval_pm2exp (v3, v1, q, bp, n, t, 3, pp);
+  /* A(-8)*B(-8) */ /* A(+8)*B(+8) */
+  TOOM8H_MUL_N_REC(pp, v0, v1, 2, r1, v2, v3, n + 1, wse);
+  mpn_toom_couple_handling (r1, 2 * n + 1 + BIT_CORRECTION, pp, sign, n, 3, 6);
+
+  /* $\pm1/2$ */
+  sign = mpn_toom_eval_pm2rexp (v2, v0, p, ap, n, s, 1, pp) ^
+	 mpn_toom_eval_pm2rexp (v3, v1, q, bp, n, t, 1, pp);
+  /* A(-1/2)*B(-1/2)*2^. */ /* A(+1/2)*B(+1/2)*2^. */
+  TOOM8H_MUL_N_REC(pp, v0, v1, 2, r6, v2, v3, n + 1, wse);
+  mpn_toom_couple_handling (r6, 2 * n + 1, pp, sign, n, 1+half, half);
+
+  /* $\pm1$ */
+  sign = mpn_toom_eval_pm1 (v2, v0, p, ap, n, s,    pp);
+  if (GMP_NUMB_BITS > 12*3 && UNLIKELY (q == 3))
+    sign ^= mpn_toom_eval_dgr3_pm1 (v3, v1, bp, n, t,    pp);
+  else
+    sign ^= mpn_toom_eval_pm1 (v3, v1, q, bp, n, t,    pp);
+  /* A(-1)*B(-1) */ /* A(1)*B(1) */
+  TOOM8H_MUL_N_REC(pp, v0, v1, 2, r4, v2, v3, n + 1, wse);
+  mpn_toom_couple_handling (r4, 2 * n + 1, pp, sign, n, 0, 0);
+
+  /* $\pm4$ */
+  sign = mpn_toom_eval_pm2exp (v2, v0, p, ap, n, s, 2, pp) ^
+	 mpn_toom_eval_pm2exp (v3, v1, q, bp, n, t, 2, pp);
+  /* A(-4)*B(-4) */ /* A(+4)*B(+4) */
+  TOOM8H_MUL_N_REC(pp, v0, v1, 2, r2, v2, v3, n + 1, wse);
+  mpn_toom_couple_handling (r2, 2 * n + 1, pp, sign, n, 2, 4);
+
+#undef v0
+#undef v1
+#undef v2
+#undef v3
+#undef wse
+
+  /* A(0)*B(0) */
+  TOOM8H_MUL_N_REC(pp, ap, bp, 0, pp, ap, bp, n, wsi);
+
+  /* Infinity */
+  if (UNLIKELY (half != 0)) {
+    if (s > t) {
+      TOOM8H_MUL_REC(r0, ap + p * n, s, bp + q * n, t, wsi);
+    } else {
+      TOOM8H_MUL_REC(r0, bp + q * n, t, ap + p * n, s, wsi);
+    };
+  };
+
+  mpn_toom_interpolate_16pts (pp, r1, r3, r5, r7, n, s+t, half, wsi);
+
+#undef r0
+#undef r1
+#undef r2
+#undef r3
+#undef r4
+#undef r5
+#undef r6
+#undef wsi
+}
+
+#undef TOOM8H_MUL_N_REC
+#undef TOOM8H_MUL_REC
+#undef MAYBE_mul_basecase
+#undef MAYBE_mul_toom22
+#undef MAYBE_mul_toom33
+#undef MAYBE_mul_toom44
+#undef MAYBE_mul_toom8h
diff --git a/third_party/gmp/mpn/generic/toom_couple_handling.c b/third_party/gmp/mpn/generic/toom_couple_handling.c
new file mode 100644
index 0000000..cd253f7
--- /dev/null
+++ b/third_party/gmp/mpn/generic/toom_couple_handling.c
@@ -0,0 +1,80 @@
+/* Helper function for high degree Toom-Cook algorithms.
+
+   Contributed to the GNU project by Marco Bodrato.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009, 2010 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+/* Gets {pp,n} and (sign?-1:1)*{np,n}. Computes at once:
+     {pp,n} <- ({pp,n}+{np,n})/2^{ps+1}
+     {pn,n} <- ({pp,n}-{np,n})/2^{ns+1}
+   Finally recompose them obtaining:
+     {pp,n+off} <- {pp,n}+{np,n}*2^{off*GMP_NUMB_BITS}
+*/
+void
+mpn_toom_couple_handling (mp_ptr pp, mp_size_t n, mp_ptr np,
+			  int nsign, mp_size_t off, int ps, int ns)
+{
+  if (nsign) {
+#ifdef HAVE_NATIVE_mpn_rsh1sub_n
+    mpn_rsh1sub_n (np, pp, np, n);
+#else
+    mpn_sub_n (np, pp, np, n);
+    mpn_rshift (np, np, n, 1);
+#endif
+  } else {
+#ifdef HAVE_NATIVE_mpn_rsh1add_n
+    mpn_rsh1add_n (np, pp, np, n);
+#else
+    mpn_add_n (np, pp, np, n);
+    mpn_rshift (np, np, n, 1);
+#endif
+  }
+
+#ifdef HAVE_NATIVE_mpn_rsh1sub_n
+  if (ps == 1)
+    mpn_rsh1sub_n (pp, pp, np, n);
+  else
+#endif
+  {
+    mpn_sub_n (pp, pp, np, n);
+    if (ps > 0)
+      mpn_rshift (pp, pp, n, ps);
+  }
+  if (ns > 0)
+    mpn_rshift (np, np, n, ns);
+  pp[n] = mpn_add_n (pp+off, pp+off, np, n-off);
+  ASSERT_NOCARRY (mpn_add_1(pp+n, np+n-off, off, pp[n]) );
+}
diff --git a/third_party/gmp/mpn/generic/toom_eval_dgr3_pm1.c b/third_party/gmp/mpn/generic/toom_eval_dgr3_pm1.c
new file mode 100644
index 0000000..5f491b6
--- /dev/null
+++ b/third_party/gmp/mpn/generic/toom_eval_dgr3_pm1.c
@@ -0,0 +1,72 @@
+/* mpn_toom_eval_dgr3_pm1 -- Evaluate a degree 3 polynomial in +1 and -1
+
+   Contributed to the GNU project by Niels Möller
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+int
+mpn_toom_eval_dgr3_pm1 (mp_ptr xp1, mp_ptr xm1,
+			mp_srcptr xp, mp_size_t n, mp_size_t x3n, mp_ptr tp)
+{
+  int neg;
+
+  ASSERT (x3n > 0);
+  ASSERT (x3n <= n);
+
+  xp1[n] = mpn_add_n (xp1, xp, xp + 2*n, n);
+  tp[n] = mpn_add (tp, xp + n, n, xp + 3*n, x3n);
+
+  neg = (mpn_cmp (xp1, tp, n + 1) < 0) ? ~0 : 0;
+
+#if HAVE_NATIVE_mpn_add_n_sub_n
+  if (neg)
+    mpn_add_n_sub_n (xp1, xm1, tp, xp1, n + 1);
+  else
+    mpn_add_n_sub_n (xp1, xm1, xp1, tp, n + 1);
+#else
+  if (neg)
+    mpn_sub_n (xm1, tp, xp1, n + 1);
+  else
+    mpn_sub_n (xm1, xp1, tp, n + 1);
+
+  mpn_add_n (xp1, xp1, tp, n + 1);
+#endif
+
+  ASSERT (xp1[n] <= 3);
+  ASSERT (xm1[n] <= 1);
+
+  return neg;
+}
diff --git a/third_party/gmp/mpn/generic/toom_eval_dgr3_pm2.c b/third_party/gmp/mpn/generic/toom_eval_dgr3_pm2.c
new file mode 100644
index 0000000..55e6b89
--- /dev/null
+++ b/third_party/gmp/mpn/generic/toom_eval_dgr3_pm2.c
@@ -0,0 +1,97 @@
+/* mpn_toom_eval_dgr3_pm2 -- Evaluate a degree 3 polynomial in +2 and -2
+
+   Contributed to the GNU project by Niels Möller
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+/* Needs n+1 limbs of temporary storage. */
+int
+mpn_toom_eval_dgr3_pm2 (mp_ptr xp2, mp_ptr xm2,
+			mp_srcptr xp, mp_size_t n, mp_size_t x3n, mp_ptr tp)
+{
+  mp_limb_t cy;
+  int neg;
+
+  ASSERT (x3n > 0);
+  ASSERT (x3n <= n);
+
+  /* (x0 + 4 * x2) +/- (2 x1 + 8 x_3) */
+#if HAVE_NATIVE_mpn_addlsh_n || HAVE_NATIVE_mpn_addlsh2_n
+#if HAVE_NATIVE_mpn_addlsh2_n
+  xp2[n] = mpn_addlsh2_n (xp2, xp, xp + 2*n, n);
+
+  cy = mpn_addlsh2_n (tp, xp + n, xp + 3*n, x3n);
+#else /* HAVE_NATIVE_mpn_addlsh_n */
+  xp2[n] = mpn_addlsh_n (xp2, xp, xp + 2*n, n, 2);
+
+  cy = mpn_addlsh_n (tp, xp + n, xp + 3*n, x3n, 2);
+#endif
+  if (x3n < n)
+    cy = mpn_add_1 (tp + x3n, xp + n + x3n, n - x3n, cy);
+  tp[n] = cy;
+#else
+  cy = mpn_lshift (tp, xp + 2*n, n, 2);
+  xp2[n] = cy + mpn_add_n (xp2, tp, xp, n);
+
+  tp[x3n] = mpn_lshift (tp, xp + 3*n, x3n, 2);
+  if (x3n < n)
+    tp[n] = mpn_add (tp, xp + n, n, tp, x3n + 1);
+  else
+    tp[n] += mpn_add_n (tp, xp + n, tp, n);
+#endif
+  mpn_lshift (tp, tp, n+1, 1);
+
+  neg = (mpn_cmp (xp2, tp, n + 1) < 0) ? ~0 : 0;
+
+#if HAVE_NATIVE_mpn_add_n_sub_n
+  if (neg)
+    mpn_add_n_sub_n (xp2, xm2, tp, xp2, n + 1);
+  else
+    mpn_add_n_sub_n (xp2, xm2, xp2, tp, n + 1);
+#else
+  if (neg)
+    mpn_sub_n (xm2, tp, xp2, n + 1);
+  else
+    mpn_sub_n (xm2, xp2, tp, n + 1);
+
+  mpn_add_n (xp2, xp2, tp, n + 1);
+#endif
+
+  ASSERT (xp2[n] < 15);
+  ASSERT (xm2[n] < 10);
+
+  return neg;
+}
diff --git a/third_party/gmp/mpn/generic/toom_eval_pm1.c b/third_party/gmp/mpn/generic/toom_eval_pm1.c
new file mode 100644
index 0000000..a8cfa93
--- /dev/null
+++ b/third_party/gmp/mpn/generic/toom_eval_pm1.c
@@ -0,0 +1,89 @@
+/* mpn_toom_eval_pm1 -- Evaluate a polynomial in +1 and -1
+
+   Contributed to the GNU project by Niels Möller
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+/* Evaluates a polynomial of degree k > 3, in the points +1 and -1. */
+int
+mpn_toom_eval_pm1 (mp_ptr xp1, mp_ptr xm1, unsigned k,
+		   mp_srcptr xp, mp_size_t n, mp_size_t hn, mp_ptr tp)
+{
+  unsigned i;
+  int neg;
+
+  ASSERT (k >= 4);
+
+  ASSERT (hn > 0);
+  ASSERT (hn <= n);
+
+  /* The degree k is also the number of full-size coefficients, so
+   * that last coefficient, of size hn, starts at xp + k*n. */
+
+  xp1[n] = mpn_add_n (xp1, xp, xp + 2*n, n);
+  for (i = 4; i < k; i += 2)
+    ASSERT_NOCARRY (mpn_add (xp1, xp1, n+1, xp+i*n, n));
+
+  tp[n] = mpn_add_n (tp, xp + n, xp + 3*n, n);
+  for (i = 5; i < k; i += 2)
+    ASSERT_NOCARRY (mpn_add (tp, tp, n+1, xp+i*n, n));
+
+  if (k & 1)
+    ASSERT_NOCARRY (mpn_add (tp, tp, n+1, xp+k*n, hn));
+  else
+    ASSERT_NOCARRY (mpn_add (xp1, xp1, n+1, xp+k*n, hn));
+
+  neg = (mpn_cmp (xp1, tp, n + 1) < 0) ? ~0 : 0;
+
+#if HAVE_NATIVE_mpn_add_n_sub_n
+  if (neg)
+    mpn_add_n_sub_n (xp1, xm1, tp, xp1, n + 1);
+  else
+    mpn_add_n_sub_n (xp1, xm1, xp1, tp, n + 1);
+#else
+  if (neg)
+    mpn_sub_n (xm1, tp, xp1, n + 1);
+  else
+    mpn_sub_n (xm1, xp1, tp, n + 1);
+
+  mpn_add_n (xp1, xp1, tp, n + 1);
+#endif
+
+  ASSERT (xp1[n] <= k);
+  ASSERT (xm1[n] <= k/2 + 1);
+
+  return neg;
+}
diff --git a/third_party/gmp/mpn/generic/toom_eval_pm2.c b/third_party/gmp/mpn/generic/toom_eval_pm2.c
new file mode 100644
index 0000000..be682c7
--- /dev/null
+++ b/third_party/gmp/mpn/generic/toom_eval_pm2.c
@@ -0,0 +1,130 @@
+/* mpn_toom_eval_pm2 -- Evaluate a polynomial in +2 and -2
+
+   Contributed to the GNU project by Niels Möller and Marco Bodrato
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/* DO_addlsh2(d,a,b,n,cy) computes cy,{d,n} <- {a,n} + 4*(cy,{b,n}), it
+   can be used as DO_addlsh2(d,a,d,n,d[n]), for accumulation on {d,n+1}. */
+#if HAVE_NATIVE_mpn_addlsh2_n
+#define DO_addlsh2(d, a, b, n, cy)	\
+do {					\
+  (cy) <<= 2;				\
+  (cy) += mpn_addlsh2_n(d, a, b, n);	\
+} while (0)
+#else
+#if HAVE_NATIVE_mpn_addlsh_n
+#define DO_addlsh2(d, a, b, n, cy)	\
+do {					\
+  (cy) <<= 2;				\
+  (cy) += mpn_addlsh_n(d, a, b, n, 2);	\
+} while (0)
+#else
+/* The following is not a general substitute for addlsh2.
+   It is correct if d == b, but it is not if d == a.  */
+#define DO_addlsh2(d, a, b, n, cy)	\
+do {					\
+  (cy) <<= 2;				\
+  (cy) += mpn_lshift(d, b, n, 2);	\
+  (cy) += mpn_add_n(d, d, a, n);	\
+} while (0)
+#endif
+#endif
+
+/* Evaluates a polynomial of degree 2 < k < GMP_NUMB_BITS, in the
+   points +2 and -2. */
+int
+mpn_toom_eval_pm2 (mp_ptr xp2, mp_ptr xm2, unsigned k,
+		   mp_srcptr xp, mp_size_t n, mp_size_t hn, mp_ptr tp)
+{
+  int i;
+  int neg;
+  mp_limb_t cy;
+
+  ASSERT (k >= 3);
+  ASSERT (k < GMP_NUMB_BITS);
+
+  ASSERT (hn > 0);
+  ASSERT (hn <= n);
+
+  /* The degree k is also the number of full-size coefficients, so
+   * that last coefficient, of size hn, starts at xp + k*n. */
+
+  cy = 0;
+  DO_addlsh2 (xp2, xp + (k-2) * n, xp + k * n, hn, cy);
+  if (hn != n)
+    cy = mpn_add_1 (xp2 + hn, xp + (k-2) * n + hn, n - hn, cy);
+  for (i = k - 4; i >= 0; i -= 2)
+    DO_addlsh2 (xp2, xp + i * n, xp2, n, cy);
+  xp2[n] = cy;
+
+  k--;
+
+  cy = 0;
+  DO_addlsh2 (tp, xp + (k-2) * n, xp + k * n, n, cy);
+  for (i = k - 4; i >= 0; i -= 2)
+    DO_addlsh2 (tp, xp + i * n, tp, n, cy);
+  tp[n] = cy;
+
+  if (k & 1)
+    ASSERT_NOCARRY(mpn_lshift (tp , tp , n + 1, 1));
+  else
+    ASSERT_NOCARRY(mpn_lshift (xp2, xp2, n + 1, 1));
+
+  neg = (mpn_cmp (xp2, tp, n + 1) < 0) ? ~0 : 0;
+
+#if HAVE_NATIVE_mpn_add_n_sub_n
+  if (neg)
+    mpn_add_n_sub_n (xp2, xm2, tp, xp2, n + 1);
+  else
+    mpn_add_n_sub_n (xp2, xm2, xp2, tp, n + 1);
+#else /* !HAVE_NATIVE_mpn_add_n_sub_n */
+  if (neg)
+    mpn_sub_n (xm2, tp, xp2, n + 1);
+  else
+    mpn_sub_n (xm2, xp2, tp, n + 1);
+
+  mpn_add_n (xp2, xp2, tp, n + 1);
+#endif /* !HAVE_NATIVE_mpn_add_n_sub_n */
+
+  ASSERT (xp2[n] < (1<<(k+2))-1);
+  ASSERT (xm2[n] < ((1<<(k+3))-1 - (1^k&1))/3);
+
+  neg ^= ((k & 1) - 1);
+
+  return neg;
+}
+
+#undef DO_addlsh2
diff --git a/third_party/gmp/mpn/generic/toom_eval_pm2exp.c b/third_party/gmp/mpn/generic/toom_eval_pm2exp.c
new file mode 100644
index 0000000..c3c4651
--- /dev/null
+++ b/third_party/gmp/mpn/generic/toom_eval_pm2exp.c
@@ -0,0 +1,127 @@
+/* mpn_toom_eval_pm2exp -- Evaluate a polynomial in +2^k and -2^k
+
+   Contributed to the GNU project by Niels Möller
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+/* Evaluates a polynomial of degree k > 2, in the points +2^shift and -2^shift. */
+int
+mpn_toom_eval_pm2exp (mp_ptr xp2, mp_ptr xm2, unsigned k,
+		      mp_srcptr xp, mp_size_t n, mp_size_t hn, unsigned shift,
+		      mp_ptr tp)
+{
+  unsigned i;
+  int neg;
+#if HAVE_NATIVE_mpn_addlsh_n
+  mp_limb_t cy;
+#endif
+
+  ASSERT (k >= 3);
+  ASSERT (shift*k < GMP_NUMB_BITS);
+
+  ASSERT (hn > 0);
+  ASSERT (hn <= n);
+
+  /* The degree k is also the number of full-size coefficients, so
+   * that last coefficient, of size hn, starts at xp + k*n. */
+
+#if HAVE_NATIVE_mpn_addlsh_n
+  xp2[n] = mpn_addlsh_n (xp2, xp, xp + 2*n, n, 2*shift);
+  for (i = 4; i < k; i += 2)
+    xp2[n] += mpn_addlsh_n (xp2, xp2, xp + i*n, n, i*shift);
+
+  tp[n] = mpn_lshift (tp, xp+n, n, shift);
+  for (i = 3; i < k; i+= 2)
+    tp[n] += mpn_addlsh_n (tp, tp, xp+i*n, n, i*shift);
+
+  if (k & 1)
+    {
+      cy = mpn_addlsh_n (tp, tp, xp+k*n, hn, k*shift);
+      MPN_INCR_U (tp + hn, n+1 - hn, cy);
+    }
+  else
+    {
+      cy = mpn_addlsh_n (xp2, xp2, xp+k*n, hn, k*shift);
+      MPN_INCR_U (xp2 + hn, n+1 - hn, cy);
+    }
+
+#else /* !HAVE_NATIVE_mpn_addlsh_n */
+  xp2[n] = mpn_lshift (tp, xp+2*n, n, 2*shift);
+  xp2[n] += mpn_add_n (xp2, xp, tp, n);
+  for (i = 4; i < k; i += 2)
+    {
+      xp2[n] += mpn_lshift (tp, xp + i*n, n, i*shift);
+      xp2[n] += mpn_add_n (xp2, xp2, tp, n);
+    }
+
+  tp[n] = mpn_lshift (tp, xp+n, n, shift);
+  for (i = 3; i < k; i+= 2)
+    {
+      tp[n] += mpn_lshift (xm2, xp + i*n, n, i*shift);
+      tp[n] += mpn_add_n (tp, tp, xm2, n);
+    }
+
+  xm2[hn] = mpn_lshift (xm2, xp + k*n, hn, k*shift);
+  if (k & 1)
+    mpn_add (tp, tp, n+1, xm2, hn+1);
+  else
+    mpn_add (xp2, xp2, n+1, xm2, hn+1);
+#endif /* !HAVE_NATIVE_mpn_addlsh_n */
+
+  neg = (mpn_cmp (xp2, tp, n + 1) < 0) ? ~0 : 0;
+
+#if HAVE_NATIVE_mpn_add_n_sub_n
+  if (neg)
+    mpn_add_n_sub_n (xp2, xm2, tp, xp2, n + 1);
+  else
+    mpn_add_n_sub_n (xp2, xm2, xp2, tp, n + 1);
+#else /* !HAVE_NATIVE_mpn_add_n_sub_n */
+  if (neg)
+    mpn_sub_n (xm2, tp, xp2, n + 1);
+  else
+    mpn_sub_n (xm2, xp2, tp, n + 1);
+
+  mpn_add_n (xp2, xp2, tp, n + 1);
+#endif /* !HAVE_NATIVE_mpn_add_n_sub_n */
+
+  /* FIXME: the following asserts are useless if (k+1)*shift >= GMP_LIMB_BITS */
+  ASSERT ((k+1)*shift >= GMP_LIMB_BITS ||
+	  xp2[n] < ((CNST_LIMB(1)<<((k+1)*shift))-1)/((CNST_LIMB(1)<<shift)-1));
+  ASSERT ((k+2)*shift >= GMP_LIMB_BITS ||
+	  xm2[n] < ((CNST_LIMB(1)<<((k+2)*shift))-((k&1)?(CNST_LIMB(1)<<shift):1))/((CNST_LIMB(1)<<(2*shift))-1));
+
+  return neg;
+}
diff --git a/third_party/gmp/mpn/generic/toom_eval_pm2rexp.c b/third_party/gmp/mpn/generic/toom_eval_pm2rexp.c
new file mode 100644
index 0000000..6cd62fb
--- /dev/null
+++ b/third_party/gmp/mpn/generic/toom_eval_pm2rexp.c
@@ -0,0 +1,101 @@
+/* mpn_toom_eval_pm2rexp -- Evaluate a polynomial in +2^-k and -2^-k
+
+   Contributed to the GNU project by Marco Bodrato
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+#if HAVE_NATIVE_mpn_addlsh_n
+#define DO_mpn_addlsh_n(dst,src,n,s,ws) mpn_addlsh_n(dst,dst,src,n,s)
+#else
+static mp_limb_t
+DO_mpn_addlsh_n(mp_ptr dst, mp_srcptr src, mp_size_t n, unsigned int s, mp_ptr ws)
+{
+#if USE_MUL_1 && 0
+  return mpn_addmul_1(dst,src,n,CNST_LIMB(1) <<(s));
+#else
+  mp_limb_t __cy;
+  __cy = mpn_lshift(ws,src,n,s);
+  return    __cy + mpn_add_n(dst,dst,ws,n);
+#endif
+}
+#endif
+
+/* Evaluates a polynomial of degree k >= 3. */
+int
+mpn_toom_eval_pm2rexp (mp_ptr rp, mp_ptr rm,
+		      unsigned int q, mp_srcptr ap, mp_size_t n, mp_size_t t,
+		      unsigned int s, mp_ptr ws)
+{
+  unsigned int i;
+  int neg;
+  /* {ap,q*n+t} -> {rp,n+1} {rm,n+1} , with {ws, n+1}*/
+  ASSERT (n >= t);
+  ASSERT (s != 0); /* or _eval_pm1 should be used */
+  ASSERT (q > 1);
+  ASSERT (s*q < GMP_NUMB_BITS);
+  rp[n] = mpn_lshift(rp, ap, n, s*q);
+  ws[n] = mpn_lshift(ws, ap+n, n, s*(q-1));
+  if( (q & 1) != 0) {
+    ASSERT_NOCARRY(mpn_add(ws,ws,n+1,ap+n*q,t));
+    rp[n] += DO_mpn_addlsh_n(rp, ap+n*(q-1), n, s, rm);
+  } else {
+    ASSERT_NOCARRY(mpn_add(rp,rp,n+1,ap+n*q,t));
+  }
+  for(i=2; i<q-1; i++)
+  {
+    rp[n] += DO_mpn_addlsh_n(rp, ap+n*i, n, s*(q-i), rm);
+    i++;
+    ws[n] += DO_mpn_addlsh_n(ws, ap+n*i, n, s*(q-i), rm);
+  };
+
+  neg = (mpn_cmp (rp, ws, n + 1) < 0) ? ~0 : 0;
+
+#if HAVE_NATIVE_mpn_add_n_sub_n
+  if (neg)
+    mpn_add_n_sub_n (rp, rm, ws, rp, n + 1);
+  else
+    mpn_add_n_sub_n (rp, rm, rp, ws, n + 1);
+#else /* !HAVE_NATIVE_mpn_add_n_sub_n */
+  if (neg)
+    mpn_sub_n (rm, ws, rp, n + 1);
+  else
+    mpn_sub_n (rm, rp, ws, n + 1);
+
+  ASSERT_NOCARRY (mpn_add_n (rp, rp, ws, n + 1));
+#endif /* !HAVE_NATIVE_mpn_add_n_sub_n */
+
+  return neg;
+}
diff --git a/third_party/gmp/mpn/generic/toom_interpolate_12pts.c b/third_party/gmp/mpn/generic/toom_interpolate_12pts.c
new file mode 100644
index 0000000..347e341
--- /dev/null
+++ b/third_party/gmp/mpn/generic/toom_interpolate_12pts.c
@@ -0,0 +1,370 @@
+/* Interpolation for the algorithm Toom-Cook 6.5-way.
+
+   Contributed to the GNU project by Marco Bodrato.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009, 2010, 2012, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+
+#if HAVE_NATIVE_mpn_sublsh_n
+#define DO_mpn_sublsh_n(dst,src,n,s,ws) mpn_sublsh_n(dst,dst,src,n,s)
+#else
+static mp_limb_t
+DO_mpn_sublsh_n(mp_ptr dst, mp_srcptr src, mp_size_t n, unsigned int s, mp_ptr ws)
+{
+#if USE_MUL_1 && 0
+  return mpn_submul_1(dst,src,n,CNST_LIMB(1) <<(s));
+#else
+  mp_limb_t __cy;
+  __cy = mpn_lshift(ws,src,n,s);
+  return    __cy + mpn_sub_n(dst,dst,ws,n);
+#endif
+}
+#endif
+
+#if HAVE_NATIVE_mpn_addlsh_n
+#define DO_mpn_addlsh_n(dst,src,n,s,ws) mpn_addlsh_n(dst,dst,src,n,s)
+#else
+static mp_limb_t
+DO_mpn_addlsh_n(mp_ptr dst, mp_srcptr src, mp_size_t n, unsigned int s, mp_ptr ws)
+{
+#if USE_MUL_1 && 0
+  return mpn_addmul_1(dst,src,n,CNST_LIMB(1) <<(s));
+#else
+  mp_limb_t __cy;
+  __cy = mpn_lshift(ws,src,n,s);
+  return    __cy + mpn_add_n(dst,dst,ws,n);
+#endif
+}
+#endif
+
+#if HAVE_NATIVE_mpn_subrsh
+#define DO_mpn_subrsh(dst,nd,src,ns,s,ws) mpn_subrsh(dst,nd,src,ns,s)
+#else
+/* FIXME: This is not a correct definition, it assumes no carry */
+#define DO_mpn_subrsh(dst,nd,src,ns,s,ws)				\
+do {									\
+  mp_limb_t __cy;							\
+  MPN_DECR_U (dst, nd, src[0] >> s);					\
+  __cy = DO_mpn_sublsh_n (dst, src + 1, ns - 1, GMP_NUMB_BITS - s, ws);	\
+  MPN_DECR_U (dst + ns - 1, nd - ns + 1, __cy);				\
+} while (0)
+#endif
+
+
+#if GMP_NUMB_BITS < 21
+#error Not implemented: Both sublsh_n(,,,20) should be corrected.
+#endif
+
+#if GMP_NUMB_BITS < 16
+#error Not implemented: divexact_by42525 needs splitting.
+#endif
+
+#if GMP_NUMB_BITS < 12
+#error Not implemented: Hard to adapt...
+#endif
+
+/* FIXME: tuneup should decide the best variant */
+#ifndef AORSMUL_FASTER_AORS_AORSLSH
+#define AORSMUL_FASTER_AORS_AORSLSH 1
+#endif
+#ifndef AORSMUL_FASTER_AORS_2AORSLSH
+#define AORSMUL_FASTER_AORS_2AORSLSH 1
+#endif
+#ifndef AORSMUL_FASTER_2AORSLSH
+#define AORSMUL_FASTER_2AORSLSH 1
+#endif
+#ifndef AORSMUL_FASTER_3AORSLSH
+#define AORSMUL_FASTER_3AORSLSH 1
+#endif
+
+#define BINVERT_9 \
+  ((((GMP_NUMB_MAX / 9) << (6 - GMP_NUMB_BITS % 6)) * 8 & GMP_NUMB_MAX) | 0x39)
+
+#define BINVERT_255 \
+  (GMP_NUMB_MAX - ((GMP_NUMB_MAX / 255) << (8 - GMP_NUMB_BITS % 8)))
+
+  /* FIXME: find some more general expressions for 2835^-1, 42525^-1 */
+#if GMP_LIMB_BITS == 32
+#define BINVERT_2835  (GMP_NUMB_MASK &		CNST_LIMB(0x53E3771B))
+#define BINVERT_42525 (GMP_NUMB_MASK &		CNST_LIMB(0x9F314C35))
+#else
+#if GMP_LIMB_BITS == 64
+#define BINVERT_2835  (GMP_NUMB_MASK &	CNST_LIMB(0x938CC70553E3771B))
+#define BINVERT_42525 (GMP_NUMB_MASK &	CNST_LIMB(0xE7B40D449F314C35))
+#endif
+#endif
+
+#ifndef mpn_divexact_by255
+#if GMP_NUMB_BITS % 8 == 0
+#define mpn_divexact_by255(dst,src,size) \
+  (255 & 1 * mpn_bdiv_dbm1 (dst, src, size, __GMP_CAST (mp_limb_t, GMP_NUMB_MASK / 255)))
+#else
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1
+#define mpn_divexact_by255(dst,src,size) mpn_pi1_bdiv_q_1(dst,src,size,CNST_LIMB(255),BINVERT_255,0)
+#else
+#define mpn_divexact_by255(dst,src,size) mpn_divexact_1(dst,src,size,CNST_LIMB(255))
+#endif
+#endif
+#endif
+
+#ifndef mpn_divexact_by9x4
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1
+#define mpn_divexact_by9x4(dst,src,size) mpn_pi1_bdiv_q_1(dst,src,size,CNST_LIMB(9),BINVERT_9,2)
+#else
+#define mpn_divexact_by9x4(dst,src,size) mpn_divexact_1(dst,src,size,CNST_LIMB(9)<<2)
+#endif
+#endif
+
+#ifndef mpn_divexact_by42525
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1 && defined(BINVERT_42525)
+#define mpn_divexact_by42525(dst,src,size) mpn_pi1_bdiv_q_1(dst,src,size,CNST_LIMB(42525),BINVERT_42525,0)
+#else
+#define mpn_divexact_by42525(dst,src,size) mpn_divexact_1(dst,src,size,CNST_LIMB(42525))
+#endif
+#endif
+
+#ifndef mpn_divexact_by2835x4
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1 && defined(BINVERT_2835)
+#define mpn_divexact_by2835x4(dst,src,size) mpn_pi1_bdiv_q_1(dst,src,size,CNST_LIMB(2835),BINVERT_2835,2)
+#else
+#define mpn_divexact_by2835x4(dst,src,size) mpn_divexact_1(dst,src,size,CNST_LIMB(2835)<<2)
+#endif
+#endif
+
+/* Interpolation for Toom-6.5 (or Toom-6), using the evaluation
+   points: infinity(6.5 only), +-4, +-2, +-1, +-1/4, +-1/2, 0. More precisely,
+   we want to compute f(2^(GMP_NUMB_BITS * n)) for a polynomial f of
+   degree 11 (or 10), given the 12 (rsp. 11) values:
+
+     r0 = limit at infinity of f(x) / x^11,
+     r1 = f(4),f(-4),
+     r2 = f(2),f(-2),
+     r3 = f(1),f(-1),
+     r4 = f(1/4),f(-1/4),
+     r5 = f(1/2),f(-1/2),
+     r6 = f(0).
+
+   All couples of the form f(n),f(-n) must be already mixed with
+   toom_couple_handling(f(n),...,f(-n),...)
+
+   The result is stored in {pp, spt + 7*n (or 6*n)}.
+   At entry, r6 is stored at {pp, 2n},
+   r4 is stored at {pp + 3n, 3n + 1}.
+   r2 is stored at {pp + 7n, 3n + 1}.
+   r0 is stored at {pp +11n, spt}.
+
+   The other values are 3n+1 limbs each (with most significant limbs small).
+
+   Negative intermediate results are stored two-complemented.
+   Inputs are destroyed.
+*/
+
+void
+mpn_toom_interpolate_12pts (mp_ptr pp, mp_ptr r1, mp_ptr r3, mp_ptr r5,
+			mp_size_t n, mp_size_t spt, int half, mp_ptr wsi)
+{
+  mp_limb_t cy;
+  mp_size_t n3;
+  mp_size_t n3p1;
+  n3 = 3 * n;
+  n3p1 = n3 + 1;
+
+#define   r4    (pp + n3)			/* 3n+1 */
+#define   r2    (pp + 7 * n)			/* 3n+1 */
+#define   r0    (pp +11 * n)			/* s+t <= 2*n */
+
+  /******************************* interpolation *****************************/
+  if (half != 0) {
+    cy = mpn_sub_n (r3, r3, r0, spt);
+    MPN_DECR_U (r3 + spt, n3p1 - spt, cy);
+
+    cy = DO_mpn_sublsh_n (r2, r0, spt, 10, wsi);
+    MPN_DECR_U (r2 + spt, n3p1 - spt, cy);
+    DO_mpn_subrsh(r5, n3p1, r0, spt, 2, wsi);
+
+    cy = DO_mpn_sublsh_n (r1, r0, spt, 20, wsi);
+    MPN_DECR_U (r1 + spt, n3p1 - spt, cy);
+    DO_mpn_subrsh(r4, n3p1, r0, spt, 4, wsi);
+  };
+
+  r4[n3] -= DO_mpn_sublsh_n (r4 + n, pp, 2 * n, 20, wsi);
+  DO_mpn_subrsh(r1 + n, 2 * n + 1, pp, 2 * n, 4, wsi);
+
+#if HAVE_NATIVE_mpn_add_n_sub_n
+  mpn_add_n_sub_n (r1, r4, r4, r1, n3p1);
+#else
+  ASSERT_NOCARRY(mpn_add_n (wsi, r1, r4, n3p1));
+  mpn_sub_n (r4, r4, r1, n3p1); /* can be negative */
+  MP_PTR_SWAP(r1, wsi);
+#endif
+
+  r5[n3] -= DO_mpn_sublsh_n (r5 + n, pp, 2 * n, 10, wsi);
+  DO_mpn_subrsh(r2 + n, 2 * n + 1, pp, 2 * n, 2, wsi);
+
+#if HAVE_NATIVE_mpn_add_n_sub_n
+  mpn_add_n_sub_n (r2, r5, r5, r2, n3p1);
+#else
+  mpn_sub_n (wsi, r5, r2, n3p1); /* can be negative */
+  ASSERT_NOCARRY(mpn_add_n (r2, r2, r5, n3p1));
+  MP_PTR_SWAP(r5, wsi);
+#endif
+
+  r3[n3] -= mpn_sub_n (r3+n, r3+n, pp, 2 * n);
+
+#if AORSMUL_FASTER_AORS_AORSLSH
+  mpn_submul_1 (r4, r5, n3p1, 257); /* can be negative */
+#else
+  mpn_sub_n (r4, r4, r5, n3p1); /* can be negative */
+  DO_mpn_sublsh_n (r4, r5, n3p1, 8, wsi); /* can be negative */
+#endif
+  /* A division by 2835x4 follows. Warning: the operand can be negative! */
+  mpn_divexact_by2835x4(r4, r4, n3p1);
+  if ((r4[n3] & (GMP_NUMB_MAX << (GMP_NUMB_BITS-3))) != 0)
+    r4[n3] |= (GMP_NUMB_MAX << (GMP_NUMB_BITS-2));
+
+#if AORSMUL_FASTER_2AORSLSH
+  mpn_addmul_1 (r5, r4, n3p1, 60); /* can be negative */
+#else
+  DO_mpn_sublsh_n (r5, r4, n3p1, 2, wsi); /* can be negative */
+  DO_mpn_addlsh_n (r5, r4, n3p1, 6, wsi); /* can give a carry */
+#endif
+  mpn_divexact_by255(r5, r5, n3p1);
+
+  ASSERT_NOCARRY(DO_mpn_sublsh_n (r2, r3, n3p1, 5, wsi));
+
+#if AORSMUL_FASTER_3AORSLSH
+  ASSERT_NOCARRY(mpn_submul_1 (r1, r2, n3p1, 100));
+#else
+  ASSERT_NOCARRY(DO_mpn_sublsh_n (r1, r2, n3p1, 6, wsi));
+  ASSERT_NOCARRY(DO_mpn_sublsh_n (r1, r2, n3p1, 5, wsi));
+  ASSERT_NOCARRY(DO_mpn_sublsh_n (r1, r2, n3p1, 2, wsi));
+#endif
+  ASSERT_NOCARRY(DO_mpn_sublsh_n (r1, r3, n3p1, 9, wsi));
+  mpn_divexact_by42525(r1, r1, n3p1);
+
+#if AORSMUL_FASTER_AORS_2AORSLSH
+  ASSERT_NOCARRY(mpn_submul_1 (r2, r1, n3p1, 225));
+#else
+  ASSERT_NOCARRY(mpn_sub_n (r2, r2, r1, n3p1));
+  ASSERT_NOCARRY(DO_mpn_addlsh_n (r2, r1, n3p1, 5, wsi));
+  ASSERT_NOCARRY(DO_mpn_sublsh_n (r2, r1, n3p1, 8, wsi));
+#endif
+  mpn_divexact_by9x4(r2, r2, n3p1);
+
+  ASSERT_NOCARRY(mpn_sub_n (r3, r3, r2, n3p1));
+
+#ifdef HAVE_NATIVE_mpn_rsh1sub_n
+  mpn_rsh1sub_n (r4, r2, r4, n3p1);
+  r4 [n3p1 - 1] &= GMP_NUMB_MASK >> 1;
+#else
+  mpn_sub_n (r4, r2, r4, n3p1);
+  ASSERT_NOCARRY(mpn_rshift(r4, r4, n3p1, 1));
+#endif
+  ASSERT_NOCARRY(mpn_sub_n (r2, r2, r4, n3p1));
+
+#ifdef HAVE_NATIVE_mpn_rsh1add_n
+  mpn_rsh1add_n (r5, r5, r1, n3p1);
+  r5 [n3p1 - 1] &= GMP_NUMB_MASK >> 1;
+#else
+  mpn_add_n (r5, r5, r1, n3p1);
+  ASSERT_NOCARRY(mpn_rshift(r5, r5, n3p1, 1));
+#endif
+
+  /* last interpolation steps... */
+  ASSERT_NOCARRY(mpn_sub_n (r3, r3, r1, n3p1));
+  ASSERT_NOCARRY(mpn_sub_n (r1, r1, r5, n3p1));
+  /* ... could be mixed with recomposition
+	||H-r5|M-r5|L-r5|   ||H-r1|M-r1|L-r1|
+  */
+
+  /***************************** recomposition *******************************/
+  /*
+    pp[] prior to operations:
+    |M r0|L r0|___||H r2|M r2|L r2|___||H r4|M r4|L r4|____|H_r6|L r6|pp
+
+    summation scheme for remaining operations:
+    |__12|n_11|n_10|n__9|n__8|n__7|n__6|n__5|n__4|n__3|n__2|n___|n___|pp
+    |M r0|L r0|___||H r2|M r2|L r2|___||H r4|M r4|L r4|____|H_r6|L r6|pp
+	||H r1|M r1|L r1|   ||H r3|M r3|L r3|   ||H_r5|M_r5|L_r5|
+  */
+
+  cy = mpn_add_n (pp + n, pp + n, r5, n);
+  cy = mpn_add_1 (pp + 2 * n, r5 + n, n, cy);
+#if HAVE_NATIVE_mpn_add_nc
+  cy = r5[n3] + mpn_add_nc(pp + n3, pp + n3, r5 + 2 * n, n, cy);
+#else
+  MPN_INCR_U (r5 + 2 * n, n + 1, cy);
+  cy = r5[n3] + mpn_add_n (pp + n3, pp + n3, r5 + 2 * n, n);
+#endif
+  MPN_INCR_U (pp + n3 + n, 2 * n + 1, cy);
+
+  pp[2 * n3]+= mpn_add_n (pp + 5 * n, pp + 5 * n, r3, n);
+  cy = mpn_add_1 (pp + 2 * n3, r3 + n, n, pp[2 * n3]);
+#if HAVE_NATIVE_mpn_add_nc
+  cy = r3[n3] + mpn_add_nc(pp + 7 * n, pp + 7 * n, r3 + 2 * n, n, cy);
+#else
+  MPN_INCR_U (r3 + 2 * n, n + 1, cy);
+  cy = r3[n3] + mpn_add_n (pp + 7 * n, pp + 7 * n, r3 + 2 * n, n);
+#endif
+  MPN_INCR_U (pp + 8 * n, 2 * n + 1, cy);
+
+  pp[10*n]+=mpn_add_n (pp + 9 * n, pp + 9 * n, r1, n);
+  if (half) {
+    cy = mpn_add_1 (pp + 10 * n, r1 + n, n, pp[10 * n]);
+#if HAVE_NATIVE_mpn_add_nc
+    if (LIKELY (spt > n)) {
+      cy = r1[n3] + mpn_add_nc(pp + 11 * n, pp + 11 * n, r1 + 2 * n, n, cy);
+      MPN_INCR_U (pp + 4 * n3, spt - n, cy);
+    } else {
+      ASSERT_NOCARRY(mpn_add_nc(pp + 11 * n, pp + 11 * n, r1 + 2 * n, spt, cy));
+    }
+#else
+    MPN_INCR_U (r1 + 2 * n, n + 1, cy);
+    if (LIKELY (spt > n)) {
+      cy = r1[n3] + mpn_add_n (pp + 11 * n, pp + 11 * n, r1 + 2 * n, n);
+      MPN_INCR_U (pp + 4 * n3, spt - n, cy);
+    } else {
+      ASSERT_NOCARRY(mpn_add_n (pp + 11 * n, pp + 11 * n, r1 + 2 * n, spt));
+    }
+#endif
+  } else {
+    ASSERT_NOCARRY(mpn_add_1 (pp + 10 * n, r1 + n, spt, pp[10 * n]));
+  }
+
+#undef   r0
+#undef   r2
+#undef   r4
+}
diff --git a/third_party/gmp/mpn/generic/toom_interpolate_16pts.c b/third_party/gmp/mpn/generic/toom_interpolate_16pts.c
new file mode 100644
index 0000000..5d76bba
--- /dev/null
+++ b/third_party/gmp/mpn/generic/toom_interpolate_16pts.c
@@ -0,0 +1,541 @@
+/* Interpolation for the algorithm Toom-Cook 8.5-way.
+
+   Contributed to the GNU project by Marco Bodrato.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009, 2010, 2012, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+#if GMP_NUMB_BITS < 29
+#error Not implemented: Both sublsh_n(,,,28) should be corrected; r2 and r5 need one more LIMB.
+#endif
+
+#if GMP_NUMB_BITS < 28
+#error Not implemented: divexact_by188513325 and _by182712915 will not work.
+#endif
+
+
+#if HAVE_NATIVE_mpn_sublsh_n
+#define DO_mpn_sublsh_n(dst,src,n,s,ws) mpn_sublsh_n(dst,dst,src,n,s)
+#else
+static mp_limb_t
+DO_mpn_sublsh_n(mp_ptr dst, mp_srcptr src, mp_size_t n, unsigned int s, mp_ptr ws)
+{
+#if USE_MUL_1 && 0
+  return mpn_submul_1(dst,src,n,CNST_LIMB(1) <<(s));
+#else
+  mp_limb_t __cy;
+  __cy = mpn_lshift(ws,src,n,s);
+  return    __cy + mpn_sub_n(dst,dst,ws,n);
+#endif
+}
+#endif
+
+#if HAVE_NATIVE_mpn_addlsh_n
+#define DO_mpn_addlsh_n(dst,src,n,s,ws) mpn_addlsh_n(dst,dst,src,n,s)
+#else
+static mp_limb_t
+DO_mpn_addlsh_n(mp_ptr dst, mp_srcptr src, mp_size_t n, unsigned int s, mp_ptr ws)
+{
+#if USE_MUL_1 && 0
+  return mpn_addmul_1(dst,src,n,CNST_LIMB(1) <<(s));
+#else
+  mp_limb_t __cy;
+  __cy = mpn_lshift(ws,src,n,s);
+  return    __cy + mpn_add_n(dst,dst,ws,n);
+#endif
+}
+#endif
+
+#if HAVE_NATIVE_mpn_subrsh
+#define DO_mpn_subrsh(dst,nd,src,ns,s,ws) mpn_subrsh(dst,nd,src,ns,s)
+#else
+/* FIXME: This is not a correct definition, it assumes no carry */
+#define DO_mpn_subrsh(dst,nd,src,ns,s,ws)				\
+do {									\
+  mp_limb_t __cy;							\
+  MPN_DECR_U (dst, nd, src[0] >> s);					\
+  __cy = DO_mpn_sublsh_n (dst, src + 1, ns - 1, GMP_NUMB_BITS - s, ws);	\
+  MPN_DECR_U (dst + ns - 1, nd - ns + 1, __cy);				\
+} while (0)
+#endif
+
+
+/* FIXME: tuneup should decide the best variant */
+#ifndef AORSMUL_FASTER_AORS_AORSLSH
+#define AORSMUL_FASTER_AORS_AORSLSH 1
+#endif
+#ifndef AORSMUL_FASTER_AORS_2AORSLSH
+#define AORSMUL_FASTER_AORS_2AORSLSH 1
+#endif
+#ifndef AORSMUL_FASTER_2AORSLSH
+#define AORSMUL_FASTER_2AORSLSH 1
+#endif
+#ifndef AORSMUL_FASTER_3AORSLSH
+#define AORSMUL_FASTER_3AORSLSH 1
+#endif
+
+#if GMP_NUMB_BITS < 43
+#define BIT_CORRECTION 1
+#define CORRECTION_BITS GMP_NUMB_BITS
+#else
+#define BIT_CORRECTION 0
+#define CORRECTION_BITS 0
+#endif
+
+#define BINVERT_9 \
+  ((((GMP_NUMB_MAX / 9) << (6 - GMP_NUMB_BITS % 6)) * 8 & GMP_NUMB_MAX) | 0x39)
+
+#define BINVERT_255 \
+  (GMP_NUMB_MAX - ((GMP_NUMB_MAX / 255) << (8 - GMP_NUMB_BITS % 8)))
+
+  /* FIXME: find some more general expressions for inverses */
+#if GMP_LIMB_BITS == 32
+#define BINVERT_2835  (GMP_NUMB_MASK &		CNST_LIMB(0x53E3771B))
+#define BINVERT_42525 (GMP_NUMB_MASK &		CNST_LIMB(0x9F314C35))
+#define BINVERT_182712915 (GMP_NUMB_MASK &	CNST_LIMB(0x550659DB))
+#define BINVERT_188513325 (GMP_NUMB_MASK &	CNST_LIMB(0xFBC333A5))
+#define BINVERT_255x182712915L (GMP_NUMB_MASK &	CNST_LIMB(0x6FC4CB25))
+#define BINVERT_255x188513325L (GMP_NUMB_MASK &	CNST_LIMB(0x6864275B))
+#if GMP_NAIL_BITS == 0
+#define BINVERT_255x182712915H CNST_LIMB(0x1B649A07)
+#define BINVERT_255x188513325H CNST_LIMB(0x06DB993A)
+#else /* GMP_NAIL_BITS != 0 */
+#define BINVERT_255x182712915H \
+  (GMP_NUMB_MASK & CNST_LIMB((0x1B649A07<<GMP_NAIL_BITS) | (0x6FC4CB25>>GMP_NUMB_BITS)))
+#define BINVERT_255x188513325H \
+  (GMP_NUMB_MASK & CNST_LIMB((0x06DB993A<<GMP_NAIL_BITS) | (0x6864275B>>GMP_NUMB_BITS)))
+#endif
+#else
+#if GMP_LIMB_BITS == 64
+#define BINVERT_2835  (GMP_NUMB_MASK &	CNST_LIMB(0x938CC70553E3771B))
+#define BINVERT_42525 (GMP_NUMB_MASK &	CNST_LIMB(0xE7B40D449F314C35))
+#define BINVERT_255x182712915  (GMP_NUMB_MASK &	CNST_LIMB(0x1B649A076FC4CB25))
+#define BINVERT_255x188513325  (GMP_NUMB_MASK &	CNST_LIMB(0x06DB993A6864275B))
+#endif
+#endif
+
+#ifndef mpn_divexact_by255
+#if GMP_NUMB_BITS % 8 == 0
+#define mpn_divexact_by255(dst,src,size) \
+  (255 & 1 * mpn_bdiv_dbm1 (dst, src, size, __GMP_CAST (mp_limb_t, GMP_NUMB_MASK / 255)))
+#else
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1
+#define mpn_divexact_by255(dst,src,size) mpn_pi1_bdiv_q_1(dst,src,size,CNST_LIMB(255),BINVERT_255,0)
+#else
+#define mpn_divexact_by255(dst,src,size) mpn_divexact_1(dst,src,size,CNST_LIMB(255))
+#endif
+#endif
+#endif
+
+#ifndef mpn_divexact_by255x4
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1
+#define mpn_divexact_by255x4(dst,src,size) mpn_pi1_bdiv_q_1(dst,src,size,CNST_LIMB(255),BINVERT_255,2)
+#else
+#define mpn_divexact_by255x4(dst,src,size) mpn_divexact_1(dst,src,size,CNST_LIMB(255)<<2)
+#endif
+#endif
+
+#ifndef mpn_divexact_by9x16
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1
+#define mpn_divexact_by9x16(dst,src,size) mpn_pi1_bdiv_q_1(dst,src,size,CNST_LIMB(9),BINVERT_9,4)
+#else
+#define mpn_divexact_by9x16(dst,src,size) mpn_divexact_1(dst,src,size,CNST_LIMB(9)<<4)
+#endif
+#endif
+
+#ifndef mpn_divexact_by42525x16
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1 && defined(BINVERT_42525)
+#define mpn_divexact_by42525x16(dst,src,size) mpn_pi1_bdiv_q_1(dst,src,size,CNST_LIMB(42525),BINVERT_42525,4)
+#else
+#define mpn_divexact_by42525x16(dst,src,size) mpn_divexact_1(dst,src,size,CNST_LIMB(42525)<<4)
+#endif
+#endif
+
+#ifndef mpn_divexact_by2835x64
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1 && defined(BINVERT_2835)
+#define mpn_divexact_by2835x64(dst,src,size) mpn_pi1_bdiv_q_1(dst,src,size,CNST_LIMB(2835),BINVERT_2835,6)
+#else
+#define mpn_divexact_by2835x64(dst,src,size) mpn_divexact_1(dst,src,size,CNST_LIMB(2835)<<6)
+#endif
+#endif
+
+#ifndef  mpn_divexact_by255x182712915
+#if GMP_NUMB_BITS < 36
+#if HAVE_NATIVE_mpn_bdiv_q_2_pi2 && defined(BINVERT_255x182712915H)
+/* FIXME: use mpn_bdiv_q_2_pi2 */
+#endif
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1 && defined(BINVERT_182712915)
+#define mpn_divexact_by255x182712915(dst,src,size)				\
+  do {										\
+    mpn_pi1_bdiv_q_1(dst,src,size,CNST_LIMB(182712915),BINVERT_182712915,0);	\
+    mpn_divexact_by255(dst,dst,size);						\
+  } while(0)
+#else
+#define mpn_divexact_by255x182712915(dst,src,size)	\
+  do {							\
+    mpn_divexact_1(dst,src,size,CNST_LIMB(182712915));	\
+    mpn_divexact_by255(dst,dst,size);			\
+  } while(0)
+#endif
+#else /* GMP_NUMB_BITS > 35 */
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1 && defined(BINVERT_255x182712915)
+#define mpn_divexact_by255x182712915(dst,src,size) \
+  mpn_pi1_bdiv_q_1(dst,src,size,255*CNST_LIMB(182712915),BINVERT_255x182712915,0)
+#else
+#define mpn_divexact_by255x182712915(dst,src,size) mpn_divexact_1(dst,src,size,255*CNST_LIMB(182712915))
+#endif
+#endif /* GMP_NUMB_BITS >?< 36 */
+#endif
+
+#ifndef  mpn_divexact_by255x188513325
+#if GMP_NUMB_BITS < 36
+#if HAVE_NATIVE_mpn_bdiv_q_1_pi2 && defined(BINVERT_255x188513325H)
+/* FIXME: use mpn_bdiv_q_1_pi2 */
+#endif
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1 && defined(BINVERT_188513325)
+#define mpn_divexact_by255x188513325(dst,src,size)			\
+  do {									\
+    mpn_pi1_bdiv_q_1(dst,src,size,CNST_LIMB(188513325),BINVERT_188513325,0);	\
+    mpn_divexact_by255(dst,dst,size);					\
+  } while(0)
+#else
+#define mpn_divexact_by255x188513325(dst,src,size)	\
+  do {							\
+    mpn_divexact_1(dst,src,size,CNST_LIMB(188513325));	\
+    mpn_divexact_by255(dst,dst,size);			\
+  } while(0)
+#endif
+#else /* GMP_NUMB_BITS > 35 */
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1 && defined(BINVERT_255x188513325)
+#define mpn_divexact_by255x188513325(dst,src,size) \
+  mpn_pi1_bdiv_q_1(dst,src,size,255*CNST_LIMB(188513325),BINVERT_255x188513325,0)
+#else
+#define mpn_divexact_by255x188513325(dst,src,size) mpn_divexact_1(dst,src,size,255*CNST_LIMB(188513325))
+#endif
+#endif /* GMP_NUMB_BITS >?< 36 */
+#endif
+
+/* Interpolation for Toom-8.5 (or Toom-8), using the evaluation
+   points: infinity(8.5 only), +-8, +-4, +-2, +-1, +-1/4, +-1/2,
+   +-1/8, 0. More precisely, we want to compute
+   f(2^(GMP_NUMB_BITS * n)) for a polynomial f of degree 15 (or
+   14), given the 16 (rsp. 15) values:
+
+     r0 = limit at infinity of f(x) / x^15,
+     r1 = f(8),f(-8),
+     r2 = f(4),f(-4),
+     r3 = f(2),f(-2),
+     r4 = f(1),f(-1),
+     r5 = f(1/4),f(-1/4),
+     r6 = f(1/2),f(-1/2),
+     r7 = f(1/8),f(-1/8),
+     r8 = f(0).
+
+   All couples of the form f(n),f(-n) must be already mixed with
+   toom_couple_handling(f(n),...,f(-n),...)
+
+   The result is stored in {pp, spt + 7*n (or 8*n)}.
+   At entry, r8 is stored at {pp, 2n},
+   r6 is stored at {pp + 3n, 3n + 1}.
+   r4 is stored at {pp + 7n, 3n + 1}.
+   r2 is stored at {pp +11n, 3n + 1}.
+   r0 is stored at {pp +15n, spt}.
+
+   The other values are 3n+1 limbs each (with most significant limbs small).
+
+   Negative intermediate results are stored two-complemented.
+   Inputs are destroyed.
+*/
+
+void
+mpn_toom_interpolate_16pts (mp_ptr pp, mp_ptr r1, mp_ptr r3, mp_ptr r5, mp_ptr r7,
+			mp_size_t n, mp_size_t spt, int half, mp_ptr wsi)
+{
+  mp_limb_t cy;
+  mp_size_t n3;
+  mp_size_t n3p1;
+  n3 = 3 * n;
+  n3p1 = n3 + 1;
+
+#define   r6    (pp + n3)			/* 3n+1 */
+#define   r4    (pp + 7 * n)			/* 3n+1 */
+#define   r2    (pp +11 * n)			/* 3n+1 */
+#define   r0    (pp +15 * n)			/* s+t <= 2*n */
+
+  ASSERT( spt <= 2 * n );
+  /******************************* interpolation *****************************/
+  if( half != 0) {
+    cy = mpn_sub_n (r4, r4, r0, spt);
+    MPN_DECR_U (r4 + spt, n3p1 - spt, cy);
+
+    cy = DO_mpn_sublsh_n (r3, r0, spt, 14, wsi);
+    MPN_DECR_U (r3 + spt, n3p1 - spt, cy);
+    DO_mpn_subrsh(r6, n3p1, r0, spt, 2, wsi);
+
+    cy = DO_mpn_sublsh_n (r2, r0, spt, 28, wsi);
+    MPN_DECR_U (r2 + spt, n3p1 - spt, cy);
+    DO_mpn_subrsh(r5, n3p1, r0, spt, 4, wsi);
+
+    cy = DO_mpn_sublsh_n (r1 + BIT_CORRECTION, r0, spt, 42 - CORRECTION_BITS, wsi);
+#if BIT_CORRECTION
+    cy = mpn_sub_1 (r1 + spt + BIT_CORRECTION, r1 + spt + BIT_CORRECTION,
+		    n3p1 - spt - BIT_CORRECTION, cy);
+    ASSERT (BIT_CORRECTION > 0 || cy == 0);
+    /* FIXME: assumes r7[n3p1] is writable (it is if r5 follows). */
+    cy = r7[n3p1];
+    r7[n3p1] = 0x80;
+#else
+    MPN_DECR_U (r1 + spt + BIT_CORRECTION, n3p1 - spt - BIT_CORRECTION, cy);
+#endif
+    DO_mpn_subrsh(r7, n3p1 + BIT_CORRECTION, r0, spt, 6, wsi);
+#if BIT_CORRECTION
+    /* FIXME: assumes r7[n3p1] is writable. */
+    ASSERT ( BIT_CORRECTION > 0 || r7[n3p1] == 0x80 );
+    r7[n3p1] = cy;
+#endif
+  };
+
+  r5[n3] -= DO_mpn_sublsh_n (r5 + n, pp, 2 * n, 28, wsi);
+  DO_mpn_subrsh(r2 + n, 2 * n + 1, pp, 2 * n, 4, wsi);
+
+#if HAVE_NATIVE_mpn_add_n_sub_n
+  mpn_add_n_sub_n (r2, r5, r5, r2, n3p1);
+#else
+  mpn_sub_n (wsi, r5, r2, n3p1); /* can be negative */
+  ASSERT_NOCARRY(mpn_add_n (r2, r2, r5, n3p1));
+  MP_PTR_SWAP(r5, wsi);
+#endif
+
+  r6[n3] -= DO_mpn_sublsh_n (r6 + n, pp, 2 * n, 14, wsi);
+  DO_mpn_subrsh(r3 + n, 2 * n + 1, pp, 2 * n, 2, wsi);
+
+#if HAVE_NATIVE_mpn_add_n_sub_n
+  mpn_add_n_sub_n (r3, r6, r6, r3, n3p1);
+#else
+  ASSERT_NOCARRY(mpn_add_n (wsi, r3, r6, n3p1));
+  mpn_sub_n (r6, r6, r3, n3p1); /* can be negative */
+  MP_PTR_SWAP(r3, wsi);
+#endif
+
+  cy = DO_mpn_sublsh_n (r7 + n + BIT_CORRECTION, pp, 2 * n, 42 - CORRECTION_BITS, wsi);
+#if BIT_CORRECTION
+  MPN_DECR_U (r1 + n, 2 * n + 1, pp[0] >> 6);
+  cy = DO_mpn_sublsh_n (r1 + n, pp + 1, 2 * n - 1, GMP_NUMB_BITS - 6, wsi);
+  cy = mpn_sub_1(r1 + 3 * n - 1, r1 + 3 * n - 1, 2, cy);
+  ASSERT ( BIT_CORRECTION > 0 || cy != 0 );
+#else
+  r7[n3] -= cy;
+  DO_mpn_subrsh(r1 + n, 2 * n + 1, pp, 2 * n, 6, wsi);
+#endif
+
+#if HAVE_NATIVE_mpn_add_n_sub_n
+  mpn_add_n_sub_n (r1, r7, r7, r1, n3p1);
+#else
+  mpn_sub_n (wsi, r7, r1, n3p1); /* can be negative */
+  mpn_add_n (r1, r1, r7, n3p1);  /* if BIT_CORRECTION != 0, can give a carry. */
+  MP_PTR_SWAP(r7, wsi);
+#endif
+
+  r4[n3] -= mpn_sub_n (r4+n, r4+n, pp, 2 * n);
+
+#if AORSMUL_FASTER_2AORSLSH
+  mpn_submul_1 (r5, r6, n3p1, 1028); /* can be negative */
+#else
+  DO_mpn_sublsh_n (r5, r6, n3p1, 2, wsi); /* can be negative */
+  DO_mpn_sublsh_n (r5, r6, n3p1,10, wsi); /* can be negative */
+#endif
+
+  mpn_submul_1 (r7, r5, n3p1, 1300); /* can be negative */
+#if AORSMUL_FASTER_3AORSLSH
+  mpn_submul_1 (r7, r6, n3p1, 1052688); /* can be negative */
+#else
+  DO_mpn_sublsh_n (r7, r6, n3p1, 4, wsi); /* can be negative */
+  DO_mpn_sublsh_n (r7, r6, n3p1,12, wsi); /* can be negative */
+  DO_mpn_sublsh_n (r7, r6, n3p1,20, wsi); /* can be negative */
+#endif
+  mpn_divexact_by255x188513325(r7, r7, n3p1);
+
+  mpn_submul_1 (r5, r7, n3p1, 12567555); /* can be negative */
+  /* A division by 2835x64 follows. Warning: the operand can be negative! */
+  mpn_divexact_by2835x64(r5, r5, n3p1);
+  if ((r5[n3] & (GMP_NUMB_MAX << (GMP_NUMB_BITS-7))) != 0)
+    r5[n3] |= (GMP_NUMB_MAX << (GMP_NUMB_BITS-6));
+
+#if AORSMUL_FASTER_AORS_AORSLSH
+  mpn_submul_1 (r6, r7, n3p1, 4095); /* can be negative */
+#else
+  mpn_add_n (r6, r6, r7, n3p1); /* can give a carry */
+  DO_mpn_sublsh_n (r6, r7, n3p1, 12, wsi); /* can be negative */
+#endif
+#if AORSMUL_FASTER_2AORSLSH
+  mpn_addmul_1 (r6, r5, n3p1, 240); /* can be negative */
+#else
+  DO_mpn_addlsh_n (r6, r5, n3p1, 8, wsi); /* can give a carry */
+  DO_mpn_sublsh_n (r6, r5, n3p1, 4, wsi); /* can be negative */
+#endif
+  /* A division by 255x4 follows. Warning: the operand can be negative! */
+  mpn_divexact_by255x4(r6, r6, n3p1);
+  if ((r6[n3] & (GMP_NUMB_MAX << (GMP_NUMB_BITS-3))) != 0)
+    r6[n3] |= (GMP_NUMB_MAX << (GMP_NUMB_BITS-2));
+
+  ASSERT_NOCARRY(DO_mpn_sublsh_n (r3, r4, n3p1, 7, wsi));
+
+  ASSERT_NOCARRY(DO_mpn_sublsh_n (r2, r4, n3p1, 13, wsi));
+  ASSERT_NOCARRY(mpn_submul_1 (r2, r3, n3p1, 400));
+
+  /* If GMP_NUMB_BITS < 42 next operations on r1 can give a carry!*/
+  DO_mpn_sublsh_n (r1, r4, n3p1, 19, wsi);
+  mpn_submul_1 (r1, r2, n3p1, 1428);
+  mpn_submul_1 (r1, r3, n3p1, 112896);
+  mpn_divexact_by255x182712915(r1, r1, n3p1);
+
+  ASSERT_NOCARRY(mpn_submul_1 (r2, r1, n3p1, 15181425));
+  mpn_divexact_by42525x16(r2, r2, n3p1);
+
+#if AORSMUL_FASTER_AORS_2AORSLSH
+  ASSERT_NOCARRY(mpn_submul_1 (r3, r1, n3p1, 3969));
+#else
+  ASSERT_NOCARRY(mpn_sub_n (r3, r3, r1, n3p1));
+  ASSERT_NOCARRY(DO_mpn_addlsh_n (r3, r1, n3p1, 7, wsi));
+  ASSERT_NOCARRY(DO_mpn_sublsh_n (r3, r1, n3p1, 12, wsi));
+#endif
+  ASSERT_NOCARRY(mpn_submul_1 (r3, r2, n3p1, 900));
+  mpn_divexact_by9x16(r3, r3, n3p1);
+
+  ASSERT_NOCARRY(mpn_sub_n (r4, r4, r1, n3p1));
+  ASSERT_NOCARRY(mpn_sub_n (r4, r4, r3, n3p1));
+  ASSERT_NOCARRY(mpn_sub_n (r4, r4, r2, n3p1));
+
+#ifdef HAVE_NATIVE_mpn_rsh1add_n
+  mpn_rsh1add_n (r6, r2, r6, n3p1);
+  r6 [n3p1 - 1] &= GMP_NUMB_MASK >> 1;
+#else
+  mpn_add_n (r6, r2, r6, n3p1);
+  ASSERT_NOCARRY(mpn_rshift(r6, r6, n3p1, 1));
+#endif
+  ASSERT_NOCARRY(mpn_sub_n (r2, r2, r6, n3p1));
+
+#ifdef HAVE_NATIVE_mpn_rsh1sub_n
+  mpn_rsh1sub_n (r5, r3, r5, n3p1);
+  r5 [n3p1 - 1] &= GMP_NUMB_MASK >> 1;
+#else
+  mpn_sub_n (r5, r3, r5, n3p1);
+  ASSERT_NOCARRY(mpn_rshift(r5, r5, n3p1, 1));
+#endif
+  ASSERT_NOCARRY(mpn_sub_n (r3, r3, r5, n3p1));
+
+#ifdef HAVE_NATIVE_mpn_rsh1add_n
+  mpn_rsh1add_n (r7, r1, r7, n3p1);
+  r7 [n3p1 - 1] &= GMP_NUMB_MASK >> 1;
+#else
+  mpn_add_n (r7, r1, r7, n3p1);
+  ASSERT_NOCARRY(mpn_rshift(r7, r7, n3p1, 1));
+#endif
+  ASSERT_NOCARRY(mpn_sub_n (r1, r1, r7, n3p1));
+
+  /* last interpolation steps... */
+  /* ... could be mixed with recomposition
+	||H-r7|M-r7|L-r7|   ||H-r5|M-r5|L-r5|
+  */
+
+  /***************************** recomposition *******************************/
+  /*
+    pp[] prior to operations:
+    |M r0|L r0|___||H r2|M r2|L r2|___||H r4|M r4|L r4|___||H r6|M r6|L r6|____|H_r8|L r8|pp
+
+    summation scheme for remaining operations:
+    |__16|n_15|n_14|n_13|n_12|n_11|n_10|n__9|n__8|n__7|n__6|n__5|n__4|n__3|n__2|n___|n___|pp
+    |M r0|L r0|___||H r2|M r2|L r2|___||H r4|M r4|L r4|___||H r6|M r6|L r6|____|H_r8|L r8|pp
+	||H r1|M r1|L r1|   ||H r3|M r3|L r3|   ||H_r5|M_r5|L_r5|   ||H r7|M r7|L r7|
+  */
+
+  cy = mpn_add_n (pp + n, pp + n, r7, n);
+  cy = mpn_add_1 (pp + 2 * n, r7 + n, n, cy);
+#if HAVE_NATIVE_mpn_add_nc
+  cy = r7[n3] + mpn_add_nc(pp + n3, pp + n3, r7 + 2 * n, n, cy);
+#else
+  MPN_INCR_U (r7 + 2 * n, n + 1, cy);
+  cy = r7[n3] + mpn_add_n (pp + n3, pp + n3, r7 + 2 * n, n);
+#endif
+  MPN_INCR_U (pp + 4 * n, 2 * n + 1, cy);
+
+  pp[2 * n3]+= mpn_add_n (pp + 5 * n, pp + 5 * n, r5, n);
+  cy = mpn_add_1 (pp + 2 * n3, r5 + n, n, pp[2 * n3]);
+#if HAVE_NATIVE_mpn_add_nc
+  cy = r5[n3] + mpn_add_nc(pp + 7 * n, pp + 7 * n, r5 + 2 * n, n, cy);
+#else
+  MPN_INCR_U (r5 + 2 * n, n + 1, cy);
+  cy = r5[n3] + mpn_add_n (pp + 7 * n, pp + 7 * n, r5 + 2 * n, n);
+#endif
+  MPN_INCR_U (pp + 8 * n, 2 * n + 1, cy);
+
+  pp[10 * n]+= mpn_add_n (pp + 9 * n, pp + 9 * n, r3, n);
+  cy = mpn_add_1 (pp + 10 * n, r3 + n, n, pp[10 * n]);
+#if HAVE_NATIVE_mpn_add_nc
+  cy = r3[n3] + mpn_add_nc(pp +11 * n, pp +11 * n, r3 + 2 * n, n, cy);
+#else
+  MPN_INCR_U (r3 + 2 * n, n + 1, cy);
+  cy = r3[n3] + mpn_add_n (pp +11 * n, pp +11 * n, r3 + 2 * n, n);
+#endif
+  MPN_INCR_U (pp +12 * n, 2 * n + 1, cy);
+
+  pp[14 * n]+=mpn_add_n (pp +13 * n, pp +13 * n, r1, n);
+  if ( half ) {
+    cy = mpn_add_1 (pp + 14 * n, r1 + n, n, pp[14 * n]);
+#if HAVE_NATIVE_mpn_add_nc
+    if(LIKELY(spt > n)) {
+      cy = r1[n3] + mpn_add_nc(pp + 15 * n, pp + 15 * n, r1 + 2 * n, n, cy);
+      MPN_INCR_U (pp + 16 * n, spt - n, cy);
+    } else {
+      ASSERT_NOCARRY(mpn_add_nc(pp + 15 * n, pp + 15 * n, r1 + 2 * n, spt, cy));
+    }
+#else
+    MPN_INCR_U (r1 + 2 * n, n + 1, cy);
+    if(LIKELY(spt > n)) {
+      cy = r1[n3] + mpn_add_n (pp + 15 * n, pp + 15 * n, r1 + 2 * n, n);
+      MPN_INCR_U (pp + 16 * n, spt - n, cy);
+    } else {
+      ASSERT_NOCARRY(mpn_add_n (pp + 15 * n, pp + 15 * n, r1 + 2 * n, spt));
+    }
+#endif
+  } else {
+    ASSERT_NOCARRY(mpn_add_1 (pp + 14 * n, r1 + n, spt, pp[14 * n]));
+  }
+
+#undef   r0
+#undef   r2
+#undef   r4
+#undef   r6
+}
diff --git a/third_party/gmp/mpn/generic/toom_interpolate_5pts.c b/third_party/gmp/mpn/generic/toom_interpolate_5pts.c
new file mode 100644
index 0000000..466ab85
--- /dev/null
+++ b/third_party/gmp/mpn/generic/toom_interpolate_5pts.c
@@ -0,0 +1,198 @@
+/* mpn_toom_interpolate_5pts -- Interpolate for toom3, 33, 42.
+
+   Contributed to the GNU project by Robert Harley.
+   Improvements by Paul Zimmermann and Marco Bodrato.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2000-2003, 2005-2007, 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpn_toom_interpolate_5pts (mp_ptr c, mp_ptr v2, mp_ptr vm1,
+			   mp_size_t k, mp_size_t twor, int sa,
+			   mp_limb_t vinf0)
+{
+  mp_limb_t cy, saved;
+  mp_size_t twok;
+  mp_size_t kk1;
+  mp_ptr c1, v1, c3, vinf;
+
+  twok = k + k;
+  kk1 = twok + 1;
+
+  c1 = c  + k;
+  v1 = c1 + k;
+  c3 = v1 + k;
+  vinf = c3 + k;
+
+#define v0 (c)
+  /* (1) v2 <- v2-vm1 < v2+|vm1|,       (16 8 4 2 1) - (1 -1 1 -1  1) =
+     thus 0 <= v2 < 50*B^(2k) < 2^6*B^(2k)             (15 9 3  3  0)
+  */
+  if (sa)
+    ASSERT_NOCARRY (mpn_add_n (v2, v2, vm1, kk1));
+  else
+    ASSERT_NOCARRY (mpn_sub_n (v2, v2, vm1, kk1));
+
+  /* {c,2k} {c+2k,2k+1} {c+4k+1,2r-1} {t,2k+1} {t+2k+1,2k+1} {t+4k+2,2r}
+       v0       v1       hi(vinf)       |vm1|     v2-vm1      EMPTY */
+
+  ASSERT_NOCARRY (mpn_divexact_by3 (v2, v2, kk1));    /* v2 <- v2 / 3 */
+						      /* (5 3 1 1 0)*/
+
+  /* {c,2k} {c+2k,2k+1} {c+4k+1,2r-1} {t,2k+1} {t+2k+1,2k+1} {t+4k+2,2r}
+       v0       v1      hi(vinf)       |vm1|     (v2-vm1)/3    EMPTY */
+
+  /* (2) vm1 <- tm1 := (v1 - vm1) / 2  [(1 1 1 1 1) - (1 -1 1 -1 1)] / 2 =
+     tm1 >= 0                                         (0  1 0  1 0)
+     No carry comes out from {v1, kk1} +/- {vm1, kk1},
+     and the division by two is exact.
+     If (sa!=0) the sign of vm1 is negative */
+  if (sa)
+    {
+#ifdef HAVE_NATIVE_mpn_rsh1add_n
+      mpn_rsh1add_n (vm1, v1, vm1, kk1);
+#else
+      ASSERT_NOCARRY (mpn_add_n (vm1, v1, vm1, kk1));
+      ASSERT_NOCARRY (mpn_rshift (vm1, vm1, kk1, 1));
+#endif
+    }
+  else
+    {
+#ifdef HAVE_NATIVE_mpn_rsh1sub_n
+      mpn_rsh1sub_n (vm1, v1, vm1, kk1);
+#else
+      ASSERT_NOCARRY (mpn_sub_n (vm1, v1, vm1, kk1));
+      ASSERT_NOCARRY (mpn_rshift (vm1, vm1, kk1, 1));
+#endif
+    }
+
+  /* {c,2k} {c+2k,2k+1} {c+4k+1,2r-1} {t,2k+1} {t+2k+1,2k+1} {t+4k+2,2r}
+       v0       v1        hi(vinf)       tm1     (v2-vm1)/3    EMPTY */
+
+  /* (3) v1 <- t1 := v1 - v0    (1 1 1 1 1) - (0 0 0 0 1) = (1 1 1 1 0)
+     t1 >= 0
+  */
+  vinf[0] -= mpn_sub_n (v1, v1, c, twok);
+
+  /* {c,2k} {c+2k,2k+1} {c+4k+1,2r-1} {t,2k+1} {t+2k+1,2k+1} {t+4k+2,2r}
+       v0     v1-v0        hi(vinf)       tm1     (v2-vm1)/3    EMPTY */
+
+  /* (4) v2 <- t2 := ((v2-vm1)/3-t1)/2 = (v2-vm1-3*t1)/6
+     t2 >= 0                  [(5 3 1 1 0) - (1 1 1 1 0)]/2 = (2 1 0 0 0)
+  */
+#ifdef HAVE_NATIVE_mpn_rsh1sub_n
+  mpn_rsh1sub_n (v2, v2, v1, kk1);
+#else
+  ASSERT_NOCARRY (mpn_sub_n (v2, v2, v1, kk1));
+  ASSERT_NOCARRY (mpn_rshift (v2, v2, kk1, 1));
+#endif
+
+  /* {c,2k} {c+2k,2k+1} {c+4k+1,2r-1} {t,2k+1} {t+2k+1,2k+1} {t+4k+2,2r}
+       v0     v1-v0        hi(vinf)     tm1    (v2-vm1-3t1)/6    EMPTY */
+
+  /* (5) v1 <- t1-tm1           (1 1 1 1 0) - (0 1 0 1 0) = (1 0 1 0 0)
+     result is v1 >= 0
+  */
+  ASSERT_NOCARRY (mpn_sub_n (v1, v1, vm1, kk1));
+
+  /* We do not need to read the value in vm1, so we add it in {c+k, ...} */
+  cy = mpn_add_n (c1, c1, vm1, kk1);
+  MPN_INCR_U (c3 + 1, twor + k - 1, cy); /* 2n-(3k+1) = 2r+k-1 */
+  /* Memory allocated for vm1 is now free, it can be recycled ...*/
+
+  /* (6) v2 <- v2 - 2*vinf,     (2 1 0 0 0) - 2*(1 0 0 0 0) = (0 1 0 0 0)
+     result is v2 >= 0 */
+  saved = vinf[0];       /* Remember v1's highest byte (will be overwritten). */
+  vinf[0] = vinf0;       /* Set the right value for vinf0                     */
+#ifdef HAVE_NATIVE_mpn_sublsh1_n_ip1
+  cy = mpn_sublsh1_n_ip1 (v2, vinf, twor);
+#else
+  /* Overwrite unused vm1 */
+  cy = mpn_lshift (vm1, vinf, twor, 1);
+  cy += mpn_sub_n (v2, v2, vm1, twor);
+#endif
+  MPN_DECR_U (v2 + twor, kk1 - twor, cy);
+
+  /* Current matrix is
+     [1 0 0 0 0; vinf
+      0 1 0 0 0; v2
+      1 0 1 0 0; v1
+      0 1 0 1 0; vm1
+      0 0 0 0 1] v0
+     Some values already are in-place (we added vm1 in the correct position)
+     | vinf|  v1 |  v0 |
+	      | vm1 |
+     One still is in a separated area
+	| +v2 |
+     We have to compute v1-=vinf; vm1 -= v2,
+	   |-vinf|
+	      | -v2 |
+     Carefully reordering operations we can avoid to compute twice the sum
+     of the high half of v2 plus the low half of vinf.
+  */
+
+  /* Add the high half of t2 in {vinf} */
+  if ( LIKELY(twor > k + 1) ) { /* This is the expected flow  */
+    cy = mpn_add_n (vinf, vinf, v2 + k, k + 1);
+    MPN_INCR_U (c3 + kk1, twor - k - 1, cy); /* 2n-(5k+1) = 2r-k-1 */
+  } else { /* triggered only by very unbalanced cases like
+	      (k+k+(k-2))x(k+k+1) , should be handled by toom32 */
+    ASSERT_NOCARRY (mpn_add_n (vinf, vinf, v2 + k, twor));
+  }
+  /* (7) v1 <- v1 - vinf,       (1 0 1 0 0) - (1 0 0 0 0) = (0 0 1 0 0)
+     result is >= 0 */
+  /* Side effect: we also subtracted (high half) vm1 -= v2 */
+  cy = mpn_sub_n (v1, v1, vinf, twor);          /* vinf is at most twor long.  */
+  vinf0 = vinf[0];                     /* Save again the right value for vinf0 */
+  vinf[0] = saved;
+  MPN_DECR_U (v1 + twor, kk1 - twor, cy);       /* Treat the last bytes.       */
+
+  /* (8) vm1 <- vm1-v2          (0 1 0 1 0) - (0 1 0 0 0) = (0 0 0 1 0)
+     Operate only on the low half.
+  */
+  cy = mpn_sub_n (c1, c1, v2, k);
+  MPN_DECR_U (v1, kk1, cy);
+
+  /********************* Beginning the final phase **********************/
+
+  /* Most of the recomposition was done */
+
+  /* add t2 in {c+3k, ...}, but only the low half */
+  cy = mpn_add_n (c3, c3, v2, k);
+  vinf[0] += cy;
+  ASSERT(vinf[0] >= cy); /* No carry */
+  MPN_INCR_U (vinf, twor, vinf0); /* Add vinf0, propagate carry. */
+
+#undef v0
+}
diff --git a/third_party/gmp/mpn/generic/toom_interpolate_6pts.c b/third_party/gmp/mpn/generic/toom_interpolate_6pts.c
new file mode 100644
index 0000000..eb23661
--- /dev/null
+++ b/third_party/gmp/mpn/generic/toom_interpolate_6pts.c
@@ -0,0 +1,241 @@
+/* mpn_toom_interpolate_6pts -- Interpolate for toom43, 52
+
+   Contributed to the GNU project by Marco Bodrato.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009, 2010, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#define BINVERT_3 MODLIMB_INVERSE_3
+
+/* For odd divisors, mpn_divexact_1 works fine with two's complement. */
+#ifndef mpn_divexact_by3
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1
+#define mpn_divexact_by3(dst,src,size) mpn_pi1_bdiv_q_1(dst,src,size,3,BINVERT_3,0)
+#else
+#define mpn_divexact_by3(dst,src,size) mpn_divexact_1(dst,src,size,3)
+#endif
+#endif
+
+/* Interpolation for Toom-3.5, using the evaluation points: infinity,
+   1, -1, 2, -2. More precisely, we want to compute
+   f(2^(GMP_NUMB_BITS * n)) for a polynomial f of degree 5, given the
+   six values
+
+     w5 = f(0),
+     w4 = f(-1),
+     w3 = f(1)
+     w2 = f(-2),
+     w1 = f(2),
+     w0 = limit at infinity of f(x) / x^5,
+
+   The result is stored in {pp, 5*n + w0n}. At entry, w5 is stored at
+   {pp, 2n}, w3 is stored at {pp + 2n, 2n+1}, and w0 is stored at
+   {pp + 5n, w0n}. The other values are 2n + 1 limbs each (with most
+   significant limbs small). f(-1) and f(-2) may be negative, signs
+   determined by the flag bits. All intermediate results are positive.
+   Inputs are destroyed.
+
+   Interpolation sequence was taken from the paper: "Integer and
+   Polynomial Multiplication: Towards Optimal Toom-Cook Matrices".
+   Some slight variations were introduced: adaptation to "gmp
+   instruction set", and a final saving of an operation by interlacing
+   interpolation and recomposition phases.
+*/
+
+void
+mpn_toom_interpolate_6pts (mp_ptr pp, mp_size_t n, enum toom6_flags flags,
+			   mp_ptr w4, mp_ptr w2, mp_ptr w1,
+			   mp_size_t w0n)
+{
+  mp_limb_t cy;
+  /* cy6 can be stored in w1[2*n], cy4 in w4[0], embankment in w2[0] */
+  mp_limb_t cy4, cy6, embankment;
+
+  ASSERT( n > 0 );
+  ASSERT( 2*n >= w0n && w0n > 0 );
+
+#define w5  pp					/* 2n   */
+#define w3  (pp + 2 * n)			/* 2n+1 */
+#define w0  (pp + 5 * n)			/* w0n  */
+
+  /* Interpolate with sequence:
+     W2 =(W1 - W2)>>2
+     W1 =(W1 - W5)>>1
+     W1 =(W1 - W2)>>1
+     W4 =(W3 - W4)>>1
+     W2 =(W2 - W4)/3
+     W3 = W3 - W4 - W5
+     W1 =(W1 - W3)/3
+     // Last steps are mixed with recomposition...
+     W2 = W2 - W0<<2
+     W4 = W4 - W2
+     W3 = W3 - W1
+     W2 = W2 - W0
+  */
+
+  /* W2 =(W1 - W2)>>2 */
+  if (flags & toom6_vm2_neg)
+    mpn_add_n (w2, w1, w2, 2 * n + 1);
+  else
+    mpn_sub_n (w2, w1, w2, 2 * n + 1);
+  mpn_rshift (w2, w2, 2 * n + 1, 2);
+
+  /* W1 =(W1 - W5)>>1 */
+  w1[2*n] -= mpn_sub_n (w1, w1, w5, 2*n);
+  mpn_rshift (w1, w1, 2 * n + 1, 1);
+
+  /* W1 =(W1 - W2)>>1 */
+#if HAVE_NATIVE_mpn_rsh1sub_n
+  mpn_rsh1sub_n (w1, w1, w2, 2 * n + 1);
+#else
+  mpn_sub_n (w1, w1, w2, 2 * n + 1);
+  mpn_rshift (w1, w1, 2 * n + 1, 1);
+#endif
+
+  /* W4 =(W3 - W4)>>1 */
+  if (flags & toom6_vm1_neg)
+    {
+#if HAVE_NATIVE_mpn_rsh1add_n
+      mpn_rsh1add_n (w4, w3, w4, 2 * n + 1);
+#else
+      mpn_add_n (w4, w3, w4, 2 * n + 1);
+      mpn_rshift (w4, w4, 2 * n + 1, 1);
+#endif
+    }
+  else
+    {
+#if HAVE_NATIVE_mpn_rsh1sub_n
+      mpn_rsh1sub_n (w4, w3, w4, 2 * n + 1);
+#else
+      mpn_sub_n (w4, w3, w4, 2 * n + 1);
+      mpn_rshift (w4, w4, 2 * n + 1, 1);
+#endif
+    }
+
+  /* W2 =(W2 - W4)/3 */
+  mpn_sub_n (w2, w2, w4, 2 * n + 1);
+  mpn_divexact_by3 (w2, w2, 2 * n + 1);
+
+  /* W3 = W3 - W4 - W5 */
+  mpn_sub_n (w3, w3, w4, 2 * n + 1);
+  w3[2 * n] -= mpn_sub_n (w3, w3, w5, 2 * n);
+
+  /* W1 =(W1 - W3)/3 */
+  mpn_sub_n (w1, w1, w3, 2 * n + 1);
+  mpn_divexact_by3 (w1, w1, 2 * n + 1);
+
+  /*
+    [1 0 0 0 0 0;
+     0 1 0 0 0 0;
+     1 0 1 0 0 0;
+     0 1 0 1 0 0;
+     1 0 1 0 1 0;
+     0 0 0 0 0 1]
+
+    pp[] prior to operations:
+     |_H w0__|_L w0__|______||_H w3__|_L w3__|_H w5__|_L w5__|
+
+    summation scheme for remaining operations:
+     |______________5|n_____4|n_____3|n_____2|n______|n______|pp
+     |_H w0__|_L w0__|______||_H w3__|_L w3__|_H w5__|_L w5__|
+				    || H w4  | L w4  |
+		    || H w2  | L w2  |
+	    || H w1  | L w1  |
+			    ||-H w1  |-L w1  |
+		     |-H w0  |-L w0 ||-H w2  |-L w2  |
+  */
+  cy = mpn_add_n (pp + n, pp + n, w4, 2 * n + 1);
+  MPN_INCR_U (pp + 3 * n + 1, n, cy);
+
+  /* W2 -= W0<<2 */
+#if HAVE_NATIVE_mpn_sublsh_n || HAVE_NATIVE_mpn_sublsh2_n_ip1
+#if HAVE_NATIVE_mpn_sublsh2_n_ip1
+  cy = mpn_sublsh2_n_ip1 (w2, w0, w0n);
+#else
+  cy = mpn_sublsh_n (w2, w2, w0, w0n, 2);
+#endif
+#else
+  /* {W4,2*n+1} is now free and can be overwritten. */
+  cy = mpn_lshift(w4, w0, w0n, 2);
+  cy+= mpn_sub_n(w2, w2, w4, w0n);
+#endif
+  MPN_DECR_U (w2 + w0n, 2 * n + 1 - w0n, cy);
+
+  /* W4L = W4L - W2L */
+  cy = mpn_sub_n (pp + n, pp + n, w2, n);
+  MPN_DECR_U (w3, 2 * n + 1, cy);
+
+  /* W3H = W3H + W2L */
+  cy4 = w3[2 * n] + mpn_add_n (pp + 3 * n, pp + 3 * n, w2, n);
+  /* W1L + W2H */
+  cy = w2[2 * n] + mpn_add_n (pp + 4 * n, w1, w2 + n, n);
+  MPN_INCR_U (w1 + n, n + 1, cy);
+
+  /* W0 = W0 + W1H */
+  if (LIKELY (w0n > n))
+    cy6 = w1[2 * n] + mpn_add_n (w0, w0, w1 + n, n);
+  else
+    cy6 = mpn_add_n (w0, w0, w1 + n, w0n);
+
+  /*
+    summation scheme for the next operation:
+     |...____5|n_____4|n_____3|n_____2|n______|n______|pp
+     |...w0___|_w1_w2_|_H w3__|_L w3__|_H w5__|_L w5__|
+		     ...-w0___|-w1_w2 |
+  */
+  /* if(LIKELY(w0n>n)) the two operands below DO overlap! */
+  cy = mpn_sub_n (pp + 2 * n, pp + 2 * n, pp + 4 * n, n + w0n);
+
+  /* embankment is a "dirty trick" to avoid carry/borrow propagation
+     beyond allocated memory */
+  embankment = w0[w0n - 1] - 1;
+  w0[w0n - 1] = 1;
+  if (LIKELY (w0n > n)) {
+    if (cy4 > cy6)
+      MPN_INCR_U (pp + 4 * n, w0n + n, cy4 - cy6);
+    else
+      MPN_DECR_U (pp + 4 * n, w0n + n, cy6 - cy4);
+    MPN_DECR_U (pp + 3 * n + w0n, 2 * n, cy);
+    MPN_INCR_U (w0 + n, w0n - n, cy6);
+  } else {
+    MPN_INCR_U (pp + 4 * n, w0n + n, cy4);
+    MPN_DECR_U (pp + 3 * n + w0n, 2 * n, cy + cy6);
+  }
+  w0[w0n - 1] += embankment;
+
+#undef w5
+#undef w3
+#undef w0
+
+}
diff --git a/third_party/gmp/mpn/generic/toom_interpolate_7pts.c b/third_party/gmp/mpn/generic/toom_interpolate_7pts.c
new file mode 100644
index 0000000..167c45b
--- /dev/null
+++ b/third_party/gmp/mpn/generic/toom_interpolate_7pts.c
@@ -0,0 +1,274 @@
+/* mpn_toom_interpolate_7pts -- Interpolate for toom44, 53, 62.
+
+   Contributed to the GNU project by Niels Möller.
+   Improvements by Marco Bodrato.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2006, 2007, 2009, 2014, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#define BINVERT_3 MODLIMB_INVERSE_3
+
+#define BINVERT_9 \
+  ((((GMP_NUMB_MAX / 9) << (6 - GMP_NUMB_BITS % 6)) * 8 & GMP_NUMB_MAX) | 0x39)
+
+#define BINVERT_15 \
+  ((((GMP_NUMB_MAX >> (GMP_NUMB_BITS % 4)) / 15) * 14 * 16 & GMP_NUMB_MAX) + 15)
+
+/* For the various mpn_divexact_byN here, fall back to using either
+   mpn_pi1_bdiv_q_1 or mpn_divexact_1.  The former has less overhead and is
+   many faster if it is native.  For now, since mpn_divexact_1 is native on
+   several platforms where mpn_pi1_bdiv_q_1 does not yet exist, do not use
+   mpn_pi1_bdiv_q_1 unconditionally.  FIXME.  */
+
+/* For odd divisors, mpn_divexact_1 works fine with two's complement. */
+#ifndef mpn_divexact_by3
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1
+#define mpn_divexact_by3(dst,src,size) mpn_pi1_bdiv_q_1(dst,src,size,3,BINVERT_3,0)
+#else
+#define mpn_divexact_by3(dst,src,size) mpn_divexact_1(dst,src,size,3)
+#endif
+#endif
+
+#ifndef mpn_divexact_by9
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1
+#define mpn_divexact_by9(dst,src,size) mpn_pi1_bdiv_q_1(dst,src,size,9,BINVERT_9,0)
+#else
+#define mpn_divexact_by9(dst,src,size) mpn_divexact_1(dst,src,size,9)
+#endif
+#endif
+
+#ifndef mpn_divexact_by15
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1
+#define mpn_divexact_by15(dst,src,size) mpn_pi1_bdiv_q_1(dst,src,size,15,BINVERT_15,0)
+#else
+#define mpn_divexact_by15(dst,src,size) mpn_divexact_1(dst,src,size,15)
+#endif
+#endif
+
+/* Interpolation for toom4, using the evaluation points 0, infinity,
+   1, -1, 2, -2, 1/2. More precisely, we want to compute
+   f(2^(GMP_NUMB_BITS * n)) for a polynomial f of degree 6, given the
+   seven values
+
+     w0 = f(0),
+     w1 = f(-2),
+     w2 = f(1),
+     w3 = f(-1),
+     w4 = f(2)
+     w5 = 64 * f(1/2)
+     w6 = limit at infinity of f(x) / x^6,
+
+   The result is 6*n + w6n limbs. At entry, w0 is stored at {rp, 2n },
+   w2 is stored at { rp + 2n, 2n+1 }, and w6 is stored at { rp + 6n,
+   w6n }. The other values are 2n + 1 limbs each (with most
+   significant limbs small). f(-1) and f(-1/2) may be negative, signs
+   determined by the flag bits. Inputs are destroyed.
+
+   Needs (2*n + 1) limbs of temporary storage.
+*/
+
+void
+mpn_toom_interpolate_7pts (mp_ptr rp, mp_size_t n, enum toom7_flags flags,
+			   mp_ptr w1, mp_ptr w3, mp_ptr w4, mp_ptr w5,
+			   mp_size_t w6n, mp_ptr tp)
+{
+  mp_size_t m;
+  mp_limb_t cy;
+
+  m = 2*n + 1;
+#define w0 rp
+#define w2 (rp + 2*n)
+#define w6 (rp + 6*n)
+
+  ASSERT (w6n > 0);
+  ASSERT (w6n <= 2*n);
+
+  /* Using formulas similar to Marco Bodrato's
+
+     W5 = W5 + W4
+     W1 =(W4 - W1)/2
+     W4 = W4 - W0
+     W4 =(W4 - W1)/4 - W6*16
+     W3 =(W2 - W3)/2
+     W2 = W2 - W3
+
+     W5 = W5 - W2*65      May be negative.
+     W2 = W2 - W6 - W0
+     W5 =(W5 + W2*45)/2   Now >= 0 again.
+     W4 =(W4 - W2)/3
+     W2 = W2 - W4
+
+     W1 = W5 - W1         May be negative.
+     W5 =(W5 - W3*8)/9
+     W3 = W3 - W5
+     W1 =(W1/15 + W5)/2   Now >= 0 again.
+     W5 = W5 - W1
+
+     where W0 = f(0), W1 = f(-2), W2 = f(1), W3 = f(-1),
+	   W4 = f(2), W5 = f(1/2), W6 = f(oo),
+
+     Note that most intermediate results are positive; the ones that
+     may be negative are represented in two's complement. We must
+     never shift right a value that may be negative, since that would
+     invalidate the sign bit. On the other hand, divexact by odd
+     numbers work fine with two's complement.
+  */
+
+  mpn_add_n (w5, w5, w4, m);
+  if (flags & toom7_w1_neg)
+    {
+#ifdef HAVE_NATIVE_mpn_rsh1add_n
+      mpn_rsh1add_n (w1, w1, w4, m);
+#else
+      mpn_add_n (w1, w1, w4, m);  ASSERT (!(w1[0] & 1));
+      mpn_rshift (w1, w1, m, 1);
+#endif
+    }
+  else
+    {
+#ifdef HAVE_NATIVE_mpn_rsh1sub_n
+      mpn_rsh1sub_n (w1, w4, w1, m);
+#else
+      mpn_sub_n (w1, w4, w1, m);  ASSERT (!(w1[0] & 1));
+      mpn_rshift (w1, w1, m, 1);
+#endif
+    }
+  mpn_sub (w4, w4, m, w0, 2*n);
+  mpn_sub_n (w4, w4, w1, m);  ASSERT (!(w4[0] & 3));
+  mpn_rshift (w4, w4, m, 2); /* w4>=0 */
+
+  tp[w6n] = mpn_lshift (tp, w6, w6n, 4);
+  mpn_sub (w4, w4, m, tp, w6n+1);
+
+  if (flags & toom7_w3_neg)
+    {
+#ifdef HAVE_NATIVE_mpn_rsh1add_n
+      mpn_rsh1add_n (w3, w3, w2, m);
+#else
+      mpn_add_n (w3, w3, w2, m);  ASSERT (!(w3[0] & 1));
+      mpn_rshift (w3, w3, m, 1);
+#endif
+    }
+  else
+    {
+#ifdef HAVE_NATIVE_mpn_rsh1sub_n
+      mpn_rsh1sub_n (w3, w2, w3, m);
+#else
+      mpn_sub_n (w3, w2, w3, m);  ASSERT (!(w3[0] & 1));
+      mpn_rshift (w3, w3, m, 1);
+#endif
+    }
+
+  mpn_sub_n (w2, w2, w3, m);
+
+  mpn_submul_1 (w5, w2, m, 65);
+  mpn_sub (w2, w2, m, w6, w6n);
+  mpn_sub (w2, w2, m, w0, 2*n);
+
+  mpn_addmul_1 (w5, w2, m, 45);  ASSERT (!(w5[0] & 1));
+  mpn_rshift (w5, w5, m, 1);
+  mpn_sub_n (w4, w4, w2, m);
+
+  mpn_divexact_by3 (w4, w4, m);
+  mpn_sub_n (w2, w2, w4, m);
+
+  mpn_sub_n (w1, w5, w1, m);
+  mpn_lshift (tp, w3, m, 3);
+  mpn_sub_n (w5, w5, tp, m);
+  mpn_divexact_by9 (w5, w5, m);
+  mpn_sub_n (w3, w3, w5, m);
+
+  mpn_divexact_by15 (w1, w1, m);
+#ifdef HAVE_NATIVE_mpn_rsh1add_n
+  mpn_rsh1add_n (w1, w1, w5, m);
+  w1[m - 1] &= GMP_NUMB_MASK >> 1;
+#else
+  mpn_add_n (w1, w1, w5, m);  ASSERT (!(w1[0] & 1));
+  mpn_rshift (w1, w1, m, 1); /* w1>=0 now */
+#endif
+
+  mpn_sub_n (w5, w5, w1, m);
+
+  /* These bounds are valid for the 4x4 polynomial product of toom44,
+   * and they are conservative for toom53 and toom62. */
+  ASSERT (w1[2*n] < 2);
+  ASSERT (w2[2*n] < 3);
+  ASSERT (w3[2*n] < 4);
+  ASSERT (w4[2*n] < 3);
+  ASSERT (w5[2*n] < 2);
+
+  /* Addition chain. Note carries and the 2n'th limbs that need to be
+   * added in.
+   *
+   * Special care is needed for w2[2n] and the corresponding carry,
+   * since the "simple" way of adding it all together would overwrite
+   * the limb at wp[2*n] and rp[4*n] (same location) with the sum of
+   * the high half of w3 and the low half of w4.
+   *
+   *         7    6    5    4    3    2    1    0
+   *    |    |    |    |    |    |    |    |    |
+   *                  ||w3 (2n+1)|
+   *             ||w4 (2n+1)|
+   *        ||w5 (2n+1)|        ||w1 (2n+1)|
+   *  + | w6 (w6n)|        ||w2 (2n+1)| w0 (2n) |  (share storage with r)
+   *  -----------------------------------------------
+   *  r |    |    |    |    |    |    |    |    |
+   *        c7   c6   c5   c4   c3                 Carries to propagate
+   */
+
+  cy = mpn_add_n (rp + n, rp + n, w1, m);
+  MPN_INCR_U (w2 + n + 1, n , cy);
+  cy = mpn_add_n (rp + 3*n, rp + 3*n, w3, n);
+  MPN_INCR_U (w3 + n, n + 1, w2[2*n] + cy);
+  cy = mpn_add_n (rp + 4*n, w3 + n, w4, n);
+  MPN_INCR_U (w4 + n, n + 1, w3[2*n] + cy);
+  cy = mpn_add_n (rp + 5*n, w4 + n, w5, n);
+  MPN_INCR_U (w5 + n, n + 1, w4[2*n] + cy);
+  if (w6n > n + 1)
+    {
+      cy = mpn_add_n (rp + 6*n, rp + 6*n, w5 + n, n + 1);
+      MPN_INCR_U (rp + 7*n + 1, w6n - n - 1, cy);
+    }
+  else
+    {
+      ASSERT_NOCARRY (mpn_add_n (rp + 6*n, rp + 6*n, w5 + n, w6n));
+#if WANT_ASSERT
+      {
+	mp_size_t i;
+	for (i = w6n; i <= n; i++)
+	  ASSERT (w5[n + i] == 0);
+      }
+#endif
+    }
+}
diff --git a/third_party/gmp/mpn/generic/toom_interpolate_8pts.c b/third_party/gmp/mpn/generic/toom_interpolate_8pts.c
new file mode 100644
index 0000000..5e65fab
--- /dev/null
+++ b/third_party/gmp/mpn/generic/toom_interpolate_8pts.c
@@ -0,0 +1,211 @@
+/* mpn_toom_interpolate_8pts -- Interpolate for toom54, 63, 72.
+
+   Contributed to the GNU project by Marco Bodrato.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009, 2011, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#define BINVERT_3 MODLIMB_INVERSE_3
+
+#define BINVERT_15 \
+  ((((GMP_NUMB_MAX >> (GMP_NUMB_BITS % 4)) / 15) * 14 * 16 & GMP_NUMB_MAX) + 15)
+
+#define BINVERT_45 ((BINVERT_15 * BINVERT_3) & GMP_NUMB_MASK)
+
+#ifndef mpn_divexact_by3
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1
+#define mpn_divexact_by3(dst,src,size) mpn_pi1_bdiv_q_1(dst,src,size,3,BINVERT_3,0)
+#else
+#define mpn_divexact_by3(dst,src,size) mpn_divexact_1(dst,src,size,3)
+#endif
+#endif
+
+#ifndef mpn_divexact_by45
+#if GMP_NUMB_BITS % 12 == 0
+#define mpn_divexact_by45(dst,src,size) \
+  (63 & 19 * mpn_bdiv_dbm1 (dst, src, size, __GMP_CAST (mp_limb_t, GMP_NUMB_MASK / 45)))
+#else
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1
+#define mpn_divexact_by45(dst,src,size) mpn_pi1_bdiv_q_1(dst,src,size,45,BINVERT_45,0)
+#else
+#define mpn_divexact_by45(dst,src,size) mpn_divexact_1(dst,src,size,45)
+#endif
+#endif
+#endif
+
+#if HAVE_NATIVE_mpn_sublsh2_n_ip1
+#define DO_mpn_sublsh2_n(dst,src,n,ws) mpn_sublsh2_n_ip1(dst,src,n)
+#else
+#define DO_mpn_sublsh2_n(dst,src,n,ws) DO_mpn_sublsh_n(dst,src,n,2,ws)
+#endif
+
+#if HAVE_NATIVE_mpn_sublsh_n
+#define DO_mpn_sublsh_n(dst,src,n,s,ws) mpn_sublsh_n (dst,dst,src,n,s)
+#else
+static mp_limb_t
+DO_mpn_sublsh_n (mp_ptr dst, mp_srcptr src, mp_size_t n, unsigned int s, mp_ptr ws)
+{
+#if USE_MUL_1 && 0
+  return mpn_submul_1(dst,src,n,CNST_LIMB(1) <<(s));
+#else
+  mp_limb_t __cy;
+  __cy = mpn_lshift (ws,src,n,s);
+  return __cy + mpn_sub_n (dst,dst,ws,n);
+#endif
+}
+#endif
+
+
+#if HAVE_NATIVE_mpn_subrsh
+#define DO_mpn_subrsh(dst,nd,src,ns,s,ws) mpn_subrsh (dst,nd,src,ns,s)
+#else
+/* This is not a correct definition, it assumes no carry */
+#define DO_mpn_subrsh(dst,nd,src,ns,s,ws)				\
+do {									\
+  mp_limb_t __cy;							\
+  MPN_DECR_U (dst, nd, src[0] >> s);					\
+  __cy = DO_mpn_sublsh_n (dst, src + 1, ns - 1, GMP_NUMB_BITS - s, ws);	\
+  MPN_DECR_U (dst + ns - 1, nd - ns + 1, __cy);				\
+} while (0)
+#endif
+
+/* Interpolation for Toom-4.5 (or Toom-4), using the evaluation
+   points: infinity(4.5 only), 4, -4, 2, -2, 1, -1, 0. More precisely,
+   we want to compute f(2^(GMP_NUMB_BITS * n)) for a polynomial f of
+   degree 7 (or 6), given the 8 (rsp. 7) values:
+
+     r1 = limit at infinity of f(x) / x^7,
+     r2 = f(4),
+     r3 = f(-4),
+     r4 = f(2),
+     r5 = f(-2),
+     r6 = f(1),
+     r7 = f(-1),
+     r8 = f(0).
+
+   All couples of the form f(n),f(-n) must be already mixed with
+   toom_couple_handling(f(n),...,f(-n),...)
+
+   The result is stored in {pp, spt + 7*n (or 6*n)}.
+   At entry, r8 is stored at {pp, 2n},
+   r5 is stored at {pp + 3n, 3n + 1}.
+
+   The other values are 2n+... limbs each (with most significant limbs small).
+
+   All intermediate results are positive.
+   Inputs are destroyed.
+*/
+
+void
+mpn_toom_interpolate_8pts (mp_ptr pp, mp_size_t n,
+			   mp_ptr r3, mp_ptr r7,
+			   mp_size_t spt, mp_ptr ws)
+{
+  mp_limb_signed_t cy;
+  mp_ptr r5, r1;
+  r5 = (pp + 3 * n);			/* 3n+1 */
+  r1 = (pp + 7 * n);			/* spt */
+
+  /******************************* interpolation *****************************/
+
+  DO_mpn_subrsh(r3+n, 2 * n + 1, pp, 2 * n, 4, ws);
+  cy = DO_mpn_sublsh_n (r3, r1, spt, 12, ws);
+  MPN_DECR_U (r3 + spt, 3 * n + 1 - spt, cy);
+
+  DO_mpn_subrsh(r5+n, 2 * n + 1, pp, 2 * n, 2, ws);
+  cy = DO_mpn_sublsh_n (r5, r1, spt, 6, ws);
+  MPN_DECR_U (r5 + spt, 3 * n + 1 - spt, cy);
+
+  r7[3*n] -= mpn_sub_n (r7+n, r7+n, pp, 2 * n);
+  cy = mpn_sub_n (r7, r7, r1, spt);
+  MPN_DECR_U (r7 + spt, 3 * n + 1 - spt, cy);
+
+  ASSERT_NOCARRY(mpn_sub_n (r3, r3, r5, 3 * n + 1));
+  ASSERT_NOCARRY(mpn_rshift(r3, r3, 3 * n + 1, 2));
+
+  ASSERT_NOCARRY(mpn_sub_n (r5, r5, r7, 3 * n + 1));
+
+  ASSERT_NOCARRY(mpn_sub_n (r3, r3, r5, 3 * n + 1));
+
+  mpn_divexact_by45 (r3, r3, 3 * n + 1);
+
+  ASSERT_NOCARRY(mpn_divexact_by3 (r5, r5, 3 * n + 1));
+
+  ASSERT_NOCARRY(DO_mpn_sublsh2_n (r5, r3, 3 * n + 1, ws));
+
+  /* last interpolation steps... */
+  /* ... are mixed with recomposition */
+
+  /***************************** recomposition *******************************/
+  /*
+    pp[] prior to operations:
+     |_H r1|_L r1|____||_H r5|_M_r5|_L r5|_____|_H r8|_L r8|pp
+
+    summation scheme for remaining operations:
+     |____8|n___7|n___6|n___5|n___4|n___3|n___2|n____|n____|pp
+     |_H r1|_L r1|____||_H*r5|_M r5|_L r5|_____|_H_r8|_L r8|pp
+	  ||_H r3|_M r3|_L*r3|
+				  ||_H_r7|_M_r7|_L_r7|
+		      ||-H r3|-M r3|-L*r3|
+				  ||-H*r5|-M_r5|-L_r5|
+  */
+
+  cy = mpn_add_n (pp + n, pp + n, r7, n); /* Hr8+Lr7-Lr5 */
+  cy-= mpn_sub_n (pp + n, pp + n, r5, n);
+  if (cy > 0) {
+    MPN_INCR_U (r7 + n, 2*n + 1, 1);
+    cy = 0;
+  }
+
+  cy = mpn_sub_nc (pp + 2*n, r7 + n, r5 + n, n, -cy); /* Mr7-Mr5 */
+  MPN_DECR_U (r7 + 2*n, n + 1, cy);
+
+  cy = mpn_add_n (pp + 3*n, r5, r7+ 2*n, n+1); /* Hr7+Lr5 */
+  r5[3*n]+= mpn_add_n (r5 + 2*n, r5 + 2*n, r3, n); /* Hr5+Lr3 */
+  cy-= mpn_sub_n (pp + 3*n, pp + 3*n, r5 + 2*n, n+1); /* Hr7-Hr5+Lr5-Lr3 */
+  if (UNLIKELY(0 > cy))
+    MPN_DECR_U (r5 + n + 1, 2*n, 1);
+  else
+    MPN_INCR_U (r5 + n + 1, 2*n, cy);
+
+  ASSERT_NOCARRY(mpn_sub_n(pp + 4*n, r5 + n, r3 + n, 2*n +1)); /* Mr5-Mr3,Hr5-Hr3 */
+
+  cy = mpn_add_1 (pp + 6*n, r3 + n, n, pp[6*n]);
+  MPN_INCR_U (r3 + 2*n, n + 1, cy);
+  cy = mpn_add_n (pp + 7*n, pp + 7*n, r3 + 2*n, n);
+  if (LIKELY(spt != n))
+    MPN_INCR_U (pp + 8*n, spt - n, cy + r3[3*n]);
+  else
+    ASSERT (r3[3*n] + cy == 0);
+}
diff --git a/third_party/gmp/mpn/generic/trialdiv.c b/third_party/gmp/mpn/generic/trialdiv.c
new file mode 100644
index 0000000..65e089f
--- /dev/null
+++ b/third_party/gmp/mpn/generic/trialdiv.c
@@ -0,0 +1,131 @@
+/* mpn_trialdiv -- find small factors of an mpn number using trial division.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+   THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.  IT IS ONLY
+   SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT IT WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009, 2010, 2012, 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+/*
+   This function finds the first (smallest) factor represented in
+   trialdivtab.h.  It does not stop the factoring effort just because it has
+   reached some sensible limit, such as the square root of the input number.
+
+   The caller can limit the factoring effort by passing NPRIMES.  The function
+   will then divide until that limit, or perhaps a few primes more.  A position
+   which only mpn_trialdiv can make sense of is returned in the WHERE
+   parameter.  It can be used for restarting the factoring effort; the first
+   call should pass 0 here.
+
+   Input:        1. A non-negative number T = {tp,tn}
+                 2. NPRIMES as described above,
+                 3. *WHERE as described above.
+   Output:       1. *WHERE updated as described above.
+                 2. Return value is non-zero if we found a factor, else zero
+                    To get the actual prime factor, compute the mod B inverse
+                    of the return value.
+*/
+
+#include "gmp-impl.h"
+
+struct gmp_primes_dtab {
+  mp_limb_t binv;
+  mp_limb_t lim;
+};
+
+struct gmp_primes_ptab {
+  mp_limb_t ppp;	/* primes, multiplied together */
+  mp_limb_t cps[7];	/* ppp values pre-computed for mpn_mod_1s_4p */
+  gmp_uint_least32_t idx:24;	/* index of  first primes in dtab */
+  gmp_uint_least32_t np :8;	/* number of primes related to this entry */
+};
+
+
+static const struct gmp_primes_dtab gmp_primes_dtab[] =
+{
+#define WANT_dtab
+#define P(p,inv,lim) {inv,lim}
+#include "trialdivtab.h"
+#undef WANT_dtab
+#undef P
+  {0,0}
+};
+
+static const struct gmp_primes_ptab gmp_primes_ptab[] =
+{
+#define WANT_ptab
+#include "trialdivtab.h"
+#undef WANT_ptab
+};
+
+#define PTAB_LINES (sizeof (gmp_primes_ptab) / sizeof (gmp_primes_ptab[0]))
+
+/* FIXME: We could optimize out one of the outer loop conditions if we
+   had a final ptab entry with a huge np field.  */
+mp_limb_t
+mpn_trialdiv (mp_srcptr tp, mp_size_t tn, mp_size_t nprimes, int *where)
+{
+  mp_limb_t ppp;
+  const mp_limb_t *cps;
+  const struct gmp_primes_dtab *dp;
+  long i, j, idx, np;
+  mp_limb_t r, q;
+
+  ASSERT (tn >= 1);
+
+  for (i = *where; i < PTAB_LINES; i++)
+    {
+      ppp = gmp_primes_ptab[i].ppp;
+      cps = gmp_primes_ptab[i].cps;
+
+      r = mpn_mod_1s_4p (tp, tn, ppp << cps[1], cps);
+
+      idx = gmp_primes_ptab[i].idx;
+      np = gmp_primes_ptab[i].np;
+
+      /* Check divisibility by individual primes.  */
+      dp = &gmp_primes_dtab[idx] + np;
+      for (j = -np; j < 0; j++)
+	{
+	  q = r * dp[j].binv;
+	  if (q <= dp[j].lim)
+	    {
+	      *where = i;
+	      return dp[j].binv;
+	    }
+	}
+
+      nprimes -= np;
+      if (nprimes <= 0)
+	return 0;
+    }
+  return 0;
+}
diff --git a/third_party/gmp/mpn/generic/udiv_w_sdiv.c b/third_party/gmp/mpn/generic/udiv_w_sdiv.c
new file mode 100644
index 0000000..7907135
--- /dev/null
+++ b/third_party/gmp/mpn/generic/udiv_w_sdiv.c
@@ -0,0 +1,141 @@
+/* mpn_udiv_w_sdiv -- implement udiv_qrnnd on machines with only signed
+   division.
+
+   Contributed by Peter L. Montgomery.
+
+   THIS IS AN INTERNAL FUNCTION WITH A MUTABLE INTERFACE.  IT IS ONLY SAFE
+   TO REACH THIS FUNCTION THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS
+   ALMOST GUARANTEED THAT THIS FUNCTION WILL CHANGE OR DISAPPEAR IN A FUTURE
+   GNU MP RELEASE.
+
+
+Copyright 1992, 1994, 1996, 2000, 2011, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+mp_limb_t
+mpn_udiv_w_sdiv (mp_limb_t *rp, mp_limb_t a1, mp_limb_t a0, mp_limb_t d)
+{
+  mp_limb_t q, r;
+  mp_limb_t c0, c1, b1;
+
+  ASSERT (d != 0);
+  ASSERT (a1 < d);
+
+  if ((mp_limb_signed_t) d >= 0)
+    {
+      if (a1 < d - a1 - (a0 >> (GMP_LIMB_BITS - 1)))
+	{
+	  /* dividend, divisor, and quotient are nonnegative */
+	  sdiv_qrnnd (q, r, a1, a0, d);
+	}
+      else
+	{
+	  /* Compute c1*2^32 + c0 = a1*2^32 + a0 - 2^31*d */
+	  sub_ddmmss (c1, c0, a1, a0, d >> 1, d << (GMP_LIMB_BITS - 1));
+	  /* Divide (c1*2^32 + c0) by d */
+	  sdiv_qrnnd (q, r, c1, c0, d);
+	  /* Add 2^31 to quotient */
+	  q += (mp_limb_t) 1 << (GMP_LIMB_BITS - 1);
+	}
+    }
+  else
+    {
+      b1 = d >> 1;			/* d/2, between 2^30 and 2^31 - 1 */
+      c1 = a1 >> 1;			/* A/2 */
+      c0 = (a1 << (GMP_LIMB_BITS - 1)) + (a0 >> 1);
+
+      if (a1 < b1)			/* A < 2^32*b1, so A/2 < 2^31*b1 */
+	{
+	  sdiv_qrnnd (q, r, c1, c0, b1); /* (A/2) / (d/2) */
+
+	  r = 2*r + (a0 & 1);		/* Remainder from A/(2*b1) */
+	  if ((d & 1) != 0)
+	    {
+	      if (r >= q)
+		r = r - q;
+	      else if (q - r <= d)
+		{
+		  r = r - q + d;
+		  q--;
+		}
+	      else
+		{
+		  r = r - q + 2*d;
+		  q -= 2;
+		}
+	    }
+	}
+      else if (c1 < b1)			/* So 2^31 <= (A/2)/b1 < 2^32 */
+	{
+	  c1 = (b1 - 1) - c1;
+	  c0 = ~c0;			/* logical NOT */
+
+	  sdiv_qrnnd (q, r, c1, c0, b1); /* (A/2) / (d/2) */
+
+	  q = ~q;			/* (A/2)/b1 */
+	  r = (b1 - 1) - r;
+
+	  r = 2*r + (a0 & 1);		/* A/(2*b1) */
+
+	  if ((d & 1) != 0)
+	    {
+	      if (r >= q)
+		r = r - q;
+	      else if (q - r <= d)
+		{
+		  r = r - q + d;
+		  q--;
+		}
+	      else
+		{
+		  r = r - q + 2*d;
+		  q -= 2;
+		}
+	    }
+	}
+      else				/* Implies c1 = b1 */
+	{				/* Hence a1 = d - 1 = 2*b1 - 1 */
+	  if (a0 >= -d)
+	    {
+	      q = -CNST_LIMB(1);
+	      r = a0 + d;
+	    }
+	  else
+	    {
+	      q = -CNST_LIMB(2);
+	      r = a0 + 2*d;
+	    }
+	}
+    }
+
+  *rp = r;
+  return q;
+}
diff --git a/third_party/gmp/mpn/generic/zero.c b/third_party/gmp/mpn/generic/zero.c
new file mode 100644
index 0000000..1a05453
--- /dev/null
+++ b/third_party/gmp/mpn/generic/zero.c
@@ -0,0 +1,41 @@
+/* mpn_zero
+
+Copyright 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpn_zero (mp_ptr rp, mp_size_t n)
+{
+  mp_size_t i;
+
+  rp += n;
+  for (i = -n; i != 0; i++)
+    rp[i] = 0;
+}
diff --git a/third_party/gmp/mpn/generic/zero_p.c b/third_party/gmp/mpn/generic/zero_p.c
new file mode 100644
index 0000000..c92f9b8
--- /dev/null
+++ b/third_party/gmp/mpn/generic/zero_p.c
@@ -0,0 +1,33 @@
+/* mpn_zero_p (x,xsize) -- Return 1 if X is zero, 0 if it is non-zero.
+
+Copyright 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define __GMP_FORCE_mpn_zero_p 1
+
+#include "gmp-impl.h"
diff --git a/third_party/gmp/mpn/ia64/README b/third_party/gmp/mpn/ia64/README
new file mode 100644
index 0000000..45c2d63
--- /dev/null
+++ b/third_party/gmp/mpn/ia64/README
@@ -0,0 +1,281 @@
+Copyright 2000-2005 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.
+
+
+
+                      IA-64 MPN SUBROUTINES
+
+
+This directory contains mpn functions for the IA-64 architecture.
+
+
+CODE ORGANIZATION
+
+	mpn/ia64          itanium-2, and generic ia64
+
+The code here has been optimized primarily for Itanium 2.  Very few Itanium 1
+chips were ever sold, and Itanium 2 is more powerful, so the latter is what
+we concentrate on.
+
+
+
+CHIP NOTES
+
+The IA-64 ISA keeps instructions three and three in 128 bit bundles.
+Programmers/compilers need to put explicit breaks `;;' when there are WAW or
+RAW dependencies, with some notable exceptions.  Such "breaks" are typically
+at the end of a bundle, but can be put between operations within some bundle
+types too.
+
+The Itanium 1 and Itanium 2 implementations can under ideal conditions
+execute two bundles per cycle.  The Itanium 1 allows 4 of these instructions
+to do integer operations, while the Itanium 2 allows all 6 to be integer
+operations.
+
+Taken cloop branches seem to insert a bubble into the pipeline most of the
+time on Itanium 1.
+
+Loads to the fp registers bypass the L1 cache and thus get extremely long
+latencies, 9 cycles on the Itanium 1 and 6 cycles on the Itanium 2.
+
+The software pipeline stuff using br.ctop instruction causes delays, since
+many issue slots are taken up by instructions with zero predicates, and
+since many extra instructions are needed to set things up.  These features
+are clearly designed for code density, not speed.
+
+Misc pipeline limitations (Itanium 1):
+* The getf.sig instruction can only execute in M0.
+* At most four integer instructions/cycle.
+* Nops take up resources like any plain instructions.
+
+Misc pipeline limitations (Itanium 2):
+* The getf.sig instruction can only execute in M0.
+* Nops take up resources like any plain instructions.
+
+
+ASSEMBLY SYNTAX
+
+.align pads with nops in a text segment, but gas 2.14 and earlier
+incorrectly byte-swaps its nop bundle in big endian mode (eg. hpux), making
+it come out as break instructions.  We use the ALIGN() macro in
+mpn/ia64/ia64-defs.m4 when it might be executed across.  That macro
+suppresses any .align if the problem is detected by configure.  Lack of
+alignment might hurt performance but will at least be correct.
+
+foo:: to create a global symbol is not accepted by gas.  Use separate
+".global foo" and "foo:" instead.
+
+.global is the standard global directive.  gas accepts .globl, but hpux "as"
+doesn't.
+
+.proc / .endp generates the appropriate .type and .size information for ELF,
+so the latter directives don't need to be given explicitly.
+
+.pred.rel "mutex"... is standard for annotating predicate register
+relationships.  gas also accepts .pred.rel.mutex, but hpux "as" doesn't.
+
+.pred directives can't be put on a line with a label, like
+".Lfoo: .pred ...", the HP assembler on HP-UX 11.23 rejects that.
+gas is happy with it, and past versions of HP had seemed ok.
+
+// is the standard comment sequence, but we prefer "C" since it inhibits m4
+macro expansion.  See comments in ia64-defs.m4.
+
+
+REGISTER USAGE
+
+Special:
+   r0: constant 0
+   r1: global pointer (gp)
+   r8: return value
+   r12: stack pointer (sp)
+   r13: thread pointer (tp)
+Caller-saves: r8-r11 r14-r31 f6-f15 f32-f127
+Caller-saves but rotating: r32-
+
+
+================================================================
+mpn_add_n, mpn_sub_n:
+
+The current code runs at 1.25 c/l on Itanium 2.
+
+================================================================
+mpn_mul_1:
+
+The current code runs at 2 c/l on Itanium 2.
+
+Using a blocked approach, working off of 4 separate places in the operands,
+one could make use of the xma accumulation, and approach 1 c/l.
+
+	ldf8 [up]
+	xma.l
+	xma.hu
+	stf8  [wrp]
+
+================================================================
+mpn_addmul_1:
+
+The current code runs at 2 c/l on Itanium 2.
+
+It seems possible to use a blocked approach, as with mpn_mul_1.  We should
+read rp[] to integer registers, allowing for just one getf.sig per cycle.
+
+	ld8  [rp]
+	ldf8 [up]
+	xma.l
+	xma.hu
+	getf.sig
+	add+add+cmp+cmp
+	st8  [wrp]
+
+These 10 instructions can be scheduled to approach 1.667 cycles, and with
+the 4 cycle latency of xma, this means we need at least 3 blocks.  Using
+ldfp8 we could approach 1.583 c/l.
+
+================================================================
+mpn_submul_1:
+
+The current code runs at 2.25 c/l on Itanium 2.  Getting to 2 c/l requires
+ldfp8 with all alignment headache that implies.
+
+================================================================
+mpn_addmul_N
+
+For best speed, we need to give up using mpn_addmul_2 as the main multiply
+building block, and instead take multiple v limbs per loop.  For the Itanium
+1, we need to take about 8 limbs at a time for full speed.  For the Itanium
+2, something like mpn_addmul_4 should be enough.
+
+The add+cmp+cmp+add we use on the other codes is optimal for shortening
+recurrencies (1 cycle) but the sequence takes up 4 execution slots.  When
+recurrency depth is not critical, a more standard 3-cycle add+cmp+add is
+better.
+
+/* First load the 8 values from v */
+	ldfp8		v0, v1 = [r35], 16;;
+	ldfp8		v2, v3 = [r35], 16;;
+	ldfp8		v4, v5 = [r35], 16;;
+	ldfp8		v6, v7 = [r35], 16;;
+
+/* In the inner loop, get a new U limb and store a result limb. */
+	mov		lc = un
+Loop:	ldf8		u0 = [r33], 8
+	ld8		r0 = [r32]
+	xma.l		lp0 = v0, u0, hp0
+	xma.hu		hp0 = v0, u0, hp0
+	xma.l		lp1 = v1, u0, hp1
+	xma.hu		hp1 = v1, u0, hp1
+	xma.l		lp2 = v2, u0, hp2
+	xma.hu		hp2 = v2, u0, hp2
+	xma.l		lp3 = v3, u0, hp3
+	xma.hu		hp3 = v3, u0, hp3
+	xma.l		lp4 = v4, u0, hp4
+	xma.hu		hp4 = v4, u0, hp4
+	xma.l		lp5 = v5, u0, hp5
+	xma.hu		hp5 = v5, u0, hp5
+	xma.l		lp6 = v6, u0, hp6
+	xma.hu		hp6 = v6, u0, hp6
+	xma.l		lp7 = v7, u0, hp7
+	xma.hu		hp7 = v7, u0, hp7
+	getf.sig	l0 = lp0
+	getf.sig	l1 = lp1
+	getf.sig	l2 = lp2
+	getf.sig	l3 = lp3
+	getf.sig	l4 = lp4
+	getf.sig	l5 = lp5
+	getf.sig	l6 = lp6
+	add+cmp+add	xx, l0, r0
+	add+cmp+add	acc0, acc1, l1
+	add+cmp+add	acc1, acc2, l2
+	add+cmp+add	acc2, acc3, l3
+	add+cmp+add	acc3, acc4, l4
+	add+cmp+add	acc4, acc5, l5
+	add+cmp+add	acc5, acc6, l6
+	getf.sig	acc6 = lp7
+	st8		[r32] = xx, 8
+	br.cloop Loop
+
+	49 insn at max 6 insn/cycle:		8.167 cycles/limb8
+	11 memops at max 2 memops/cycle:	5.5 cycles/limb8
+	16 fpops at max 2 fpops/cycle:		8 cycles/limb8
+	21 intops at max 4 intops/cycle:	5.25 cycles/limb8
+	11+21 memops+intops at max 4/cycle	8 cycles/limb8
+
+================================================================
+mpn_lshift, mpn_rshift
+
+The current code runs at 1 cycle/limb on Itanium 2.
+
+Using 63 separate loops, we could use the double-word shrp instruction.
+That instruction has a plain single-cycle latency.  We need 63 loops since
+this instruction only accept immediate count.  That would lead to a somewhat
+silly code size, but the speed would be 0.75 c/l on Itanium 2 (by using shrp
+each cycle plus shl/shr going down I1 for a further limb every second
+cycle).
+
+================================================================
+mpn_copyi, mpn_copyd
+
+The current code runs at 0.5 c/l on Itanium 2.  But that is just for L1
+cache hit.  The 4-way unrolled loop takes just 2 cycles, and thus load-use
+scheduling isn't great.  It might be best to actually use modulo scheduled
+loops, since that will allow us to do better load-use scheduling without too
+much unrolling.
+
+Depending on size or operand alignment, we get 1 c/l or 0.5 c/l on Itanium
+2, according to tune/speed.  Cache bank conflicts?
+
+
+
+REFERENCES
+
+Intel Itanium Architecture Software Developer's Manual, volumes 1 to 3,
+Intel document 245317-004, 245318-004, 245319-004 October 2002.  Volume 1
+includes an Itanium optimization guide.
+
+Intel Itanium Processor-specific Application Binary Interface (ABI), Intel
+document 245370-003, May 2001.  Describes C type sizes, dynamic linking,
+etc.
+
+Intel Itanium Architecture Assembly Language Reference Guide, Intel document
+248801-004, 2000-2002.  Describes assembly instruction syntax and other
+directives.
+
+Itanium Software Conventions and Runtime Architecture Guide, Intel document
+245358-003, May 2001.  Describes calling conventions, including stack
+unwinding requirements.
+
+Intel Itanium Processor Reference Manual for Software Optimization, Intel
+document 245473-003, November 2001.
+
+Intel Itanium-2 Processor Reference Manual for Software Development and
+Optimization, Intel document 251110-003, May 2004.
+
+All the above documents can be found online at
+
+    http://developer.intel.com/design/itanium/manuals.htm
diff --git a/third_party/gmp/mpn/ia64/add_n_sub_n.asm b/third_party/gmp/mpn/ia64/add_n_sub_n.asm
new file mode 100644
index 0000000..c15afaa
--- /dev/null
+++ b/third_party/gmp/mpn/ia64/add_n_sub_n.asm
@@ -0,0 +1,307 @@
+dnl  IA-64 mpn_add_n_sub_n -- mpn parallel addition and subtraction.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2010 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C           cycles/limb
+C Itanium:      ?
+C Itanium 2:    2.25
+
+C INPUT PARAMETERS
+define(`sp', `r32')
+define(`dp', `r33')
+define(`up', `r34')
+define(`vp', `r35')
+define(`n',  `r36')
+
+C Some useful aliases for registers we use
+define(`u0',`r16') define(`u1',`r17') define(`u2',`r18') define(`u3',`r19')
+define(`v0',`r20') define(`v1',`r21') define(`v2',`r22') define(`v3',`r23')
+define(`s0',`r24') define(`s1',`r25') define(`s2',`r26') define(`s3',`r27')
+define(`d0',`r28') define(`d1',`r29') define(`d2',`r30') define(`d3',`r31')
+define(`up0',`up')
+define(`up1',`r14')
+define(`vp0',`vp')
+define(`vp1',`r15')
+
+
+ASM_START()
+PROLOGUE(mpn_add_n_sub_n)
+	.prologue
+	.save	ar.lc, r2
+	.body
+ifdef(`HAVE_ABI_32',`
+	addp4	sp = 0, sp		C				M I
+	addp4	dp = 0, dp		C				M I
+	nop.i	0
+	addp4	up = 0, up		C				M I
+	addp4	vp = 0, vp		C				M I
+	zxt4	n = n			C				I
+	;;
+')
+
+	and	r9 = 3, n		C				M I
+	mov.i	r2 = ar.lc		C				I0
+	add	up1 = 8, up0		C				M I
+	add	vp1 = 8, vp0		C				M I
+	add	r8 = -2, n		C				M I
+	add	r10 = 256, up		C				M I
+	;;
+	shr.u	r8 = r8, 2		C				I0
+	cmp.eq	p10, p0 = 0, r9		C				M I
+	cmp.eq	p11, p0 = 2, r9		C				M I
+	cmp.eq	p12, p0 = 3, r9		C				M I
+	add	r11 = 256, vp		C				M I
+	;;
+	mov.i	ar.lc = r8		C				I0
+  (p10)	br	L(b0)			C				B
+  (p11)	br	L(b2)			C				B
+  (p12)	br	L(b3)			C				B
+
+L(b1):	ld8	u3 = [up0], 8		C				M01
+	add	up1 = 8, up1		C				M I
+	cmpltu	p14, p15 = 4, n		C				M I
+	ld8	v3 = [vp0], 8		C				M01
+	add	vp1 = 8, vp1		C				M I
+	;;
+	add	s3 = u3, v3		C				M I
+	sub	d3 = u3, v3		C				M I
+	mov	r8 = 0			C				M I
+	;;
+	cmpltu	p9, p0 = s3, v3		C  carry from add3		M I
+	cmpltu	p13, p0 = u3, v3	C borrow from sub3		M I
+  (p15)	br	L(cj1)			C				B
+	st8	[sp] = s3, 8		C				M23
+	st8	[dp] = d3, 8		C				M23
+	br	L(c0)			C				B
+
+L(b0):	cmp.ne	p9, p0 = r0, r0		C				M I
+	cmp.ne	p13, p0 = r0, r0	C				M I
+L(c0):	ld8	u0 = [up0], 16		C				M01
+	ld8	u1 = [up1], 16		C				M01
+	;;
+	ld8	v0 = [vp0], 16		C				M01
+	ld8	v1 = [vp1], 16		C				M01
+	;;
+	ld8	u2 = [up0], 16		C				M01
+	ld8	u3 = [up1], 16		C				M01
+	;;
+	ld8	v2 = [vp0], 16		C				M01
+	ld8	v3 = [vp1], 16		C				M01
+	;;
+	add	s0 = u0, v0		C				M I
+	add	s1 = u1, v1		C				M I
+	sub	d0 = u0, v0		C				M I
+	sub	d1 = u1, v1		C				M I
+	;;
+	cmpltu	p6, p0 = s0, v0		C  carry from add0		M I
+	cmpltu	p7, p0 = s1, v1		C  carry from add1		M I
+	cmpltu	p10, p0 = u0, v0	C borrow from sub0		M I
+	cmpltu	p11, p0 = u1, v1	C borrow from sub1		M I
+	;;
+	nop	0			C
+	br.cloop.dptk	L(top)		C				B
+	br	L(end)			C				B
+
+L(b3):	ld8	u1 = [up0], 8		C				M01
+	add	up1 = 8, up1		C				M I
+	ld8	v1 = [vp0], 8		C				M01
+	;;
+	add	vp1 = 8, vp1		C				M I
+	add	s1 = u1, v1		C				M I
+	sub	d1 = u1, v1		C				M I
+	;;
+	cmpltu	p7, p0 = s1, v1		C  carry from add1		M I
+	cmpltu	p11, p0 = u1, v1	C borrow from sub1		M I
+	;;
+	st8	[sp] = s1, 8		C				M23
+	st8	[dp] = d1, 8		C				M23
+	br	L(c2)			C				B
+
+	ALIGN(32)
+L(b2):	cmp.ne	p7, p0 = r0, r0		C				M I
+	cmp.ne	p11, p0 = r0, r0	C				M I
+	nop	0
+L(c2):	ld8	u2 = [up0], 16		C				M01
+	ld8	u3 = [up1], 16		C				M01
+	cmpltu	p14, p0 = 4, n		C				M I
+	;;
+	ld8	v2 = [vp0], 16		C				M01
+	ld8	v3 = [vp1], 16		C				M01
+  (p14)	br	L(gt4)			C				B
+	;;
+	add	s2 = u2, v2		C				M I
+	add	s3 = u3, v3		C				M I
+	sub	d2 = u2, v2		C				M I
+	sub	d3 = u3, v3		C				M I
+	;;
+	cmpltu	p8, p0 = s2, v2		C  carry from add0		M I
+	cmpltu	p9, p0 = s3, v3		C  carry from add3		M I
+	cmpltu	p12, p0 = u2, v2	C borrow from sub2		M I
+	cmpltu	p13, p0 = u3, v3	C borrow from sub3		M I
+	br	L(cj2)			C				B
+	;;
+L(gt4):	ld8	u0 = [up0], 16		C				M01
+	ld8	u1 = [up1], 16		C				M01
+	;;
+	ld8	v0 = [vp0], 16		C				M01
+	ld8	v1 = [vp1], 16		C				M01
+	;;
+	add	s2 = u2, v2		C				M I
+	add	s3 = u3, v3		C				M I
+	sub	d2 = u2, v2		C				M I
+	sub	d3 = u3, v3		C				M I
+	;;
+	cmpltu	p8, p0 = s2, v2		C  carry from add0		M I
+	cmpltu	p9, p0 = s3, v3		C  carry from add1		M I
+	cmpltu	p12, p0 = u2, v2	C borrow from sub0		M I
+	cmpltu	p13, p0 = u3, v3	C borrow from sub1		M I
+	br.cloop.dptk	L(mid)		C				B
+
+	ALIGN(32)
+L(top):
+	ld8	u0 = [up0], 16		C				M01
+	ld8	u1 = [up1], 16		C				M01
+   (p9)	cmpeqor	p6, p0 = -1, s0		C				M I
+   (p9)	add	s0 = 1, s0		C				M I
+  (p13)	cmpeqor	p10, p0 = 0, d0		C				M I
+  (p13)	add	d0 = -1, d0		C				M I
+	;;
+	ld8	v0 = [vp0], 16		C				M01
+	ld8	v1 = [vp1], 16		C				M01
+   (p6)	cmpeqor	p7, p0 = -1, s1		C				M I
+   (p6)	add	s1 = 1, s1		C				M I
+  (p10)	cmpeqor	p11, p0 = 0, d1		C				M I
+  (p10)	add	d1 = -1, d1		C				M I
+	;;
+	st8	[sp] = s0, 8		C				M23
+	st8	[dp] = d0, 8		C				M23
+	add	s2 = u2, v2		C				M I
+	add	s3 = u3, v3		C				M I
+	sub	d2 = u2, v2		C				M I
+	sub	d3 = u3, v3		C				M I
+	;;
+	st8	[sp] = s1, 8		C				M23
+	st8	[dp] = d1, 8		C				M23
+	cmpltu	p8, p0 = s2, v2		C  carry from add2		M I
+	cmpltu	p9, p0 = s3, v3		C  carry from add3		M I
+	cmpltu	p12, p0 = u2, v2	C borrow from sub2		M I
+	cmpltu	p13, p0 = u3, v3	C borrow from sub3		M I
+	;;
+L(mid):
+	ld8	u2 = [up0], 16		C				M01
+	ld8	u3 = [up1], 16		C				M01
+   (p7)	cmpeqor	p8, p0 = -1, s2		C				M I
+   (p7)	add	s2 = 1, s2		C				M I
+  (p11)	cmpeqor	p12, p0 = 0, d2		C				M I
+  (p11)	add	d2 = -1, d2		C				M I
+	;;
+	ld8	v2 = [vp0], 16		C				M01
+	ld8	v3 = [vp1], 16		C				M01
+   (p8)	cmpeqor	p9, p0 = -1, s3		C				M I
+   (p8)	add	s3 = 1, s3		C				M I
+  (p12)	cmpeqor	p13, p0 = 0, d3		C				M I
+  (p12)	add	d3 = -1, d3		C				M I
+	;;
+	st8	[sp] = s2, 8		C				M23
+	st8	[dp] = d2, 8		C				M23
+	add	s0 = u0, v0		C				M I
+	add	s1 = u1, v1		C				M I
+	sub	d0 = u0, v0		C				M I
+	sub	d1 = u1, v1		C				M I
+	;;
+	st8	[sp] = s3, 8		C				M23
+	st8	[dp] = d3, 8		C				M23
+	cmpltu	p6, p0 = s0, v0		C  carry from add0		M I
+	cmpltu	p7, p0 = s1, v1		C  carry from add1		M I
+	cmpltu	p10, p0 = u0, v0	C borrow from sub0		M I
+	cmpltu	p11, p0 = u1, v1	C borrow from sub1		M I
+	;;
+	lfetch	[r10], 32		C				M?
+	lfetch	[r11], 32		C				M?
+	br.cloop.dptk	L(top)		C				B
+	;;
+
+L(end):
+	nop	0
+	nop	0
+   (p9)	cmpeqor	p6, p0 = -1, s0		C				M I
+   (p9)	add	s0 = 1, s0		C				M I
+  (p13)	cmpeqor	p10, p0 = 0, d0		C				M I
+  (p13)	add	d0 = -1, d0		C				M I
+	;;
+	nop	0
+	nop	0
+   (p6)	cmpeqor	p7, p0 = -1, s1		C				M I
+   (p6)	add	s1 = 1, s1		C				M I
+  (p10)	cmpeqor	p11, p0 = 0, d1		C				M I
+  (p10)	add	d1 = -1, d1		C				M I
+	;;
+	st8	[sp] = s0, 8		C				M23
+	st8	[dp] = d0, 8		C				M23
+	add	s2 = u2, v2		C				M I
+	add	s3 = u3, v3		C				M I
+	sub	d2 = u2, v2		C				M I
+	sub	d3 = u3, v3		C				M I
+	;;
+	st8	[sp] = s1, 8		C				M23
+	st8	[dp] = d1, 8		C				M23
+	cmpltu	p8, p0 = s2, v2		C  carry from add2		M I
+	cmpltu	p9, p0 = s3, v3		C  carry from add3		M I
+	cmpltu	p12, p0 = u2, v2	C borrow from sub2		M I
+	cmpltu	p13, p0 = u3, v3	C borrow from sub3		M I
+	;;
+L(cj2):
+   (p7)	cmpeqor	p8, p0 = -1, s2		C				M I
+   (p7)	add	s2 = 1, s2		C				M I
+  (p11)	cmpeqor	p12, p0 = 0, d2		C				M I
+  (p11)	add	d2 = -1, d2		C				M I
+	mov	r8 = 0			C				M I
+	nop	0
+	;;
+	st8	[sp] = s2, 8		C				M23
+	st8	[dp] = d2, 8		C				M23
+   (p8)	cmpeqor	p9, p0 = -1, s3		C				M I
+   (p8)	add	s3 = 1, s3		C				M I
+  (p12)	cmpeqor	p13, p0 = 0, d3		C				M I
+  (p12)	add	d3 = -1, d3		C				M I
+	;;
+L(cj1):
+   (p9)	mov	r8 = 2			C				M I
+	;;
+	mov.i	ar.lc = r2		C				I0
+  (p13)	add	r8 = 1, r8		C				M I
+	st8	[sp] = s3		C				M23
+	st8	[dp] = d3		C				M23
+	br.ret.sptk.many b0		C				B
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/ia64/addmul_1.asm b/third_party/gmp/mpn/ia64/addmul_1.asm
new file mode 100644
index 0000000..ffa3297
--- /dev/null
+++ b/third_party/gmp/mpn/ia64/addmul_1.asm
@@ -0,0 +1,602 @@
+dnl  IA-64 mpn_addmul_1 -- Multiply a limb vector with a limb and add the
+dnl  result to a second limb vector.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2000-2005, 2007 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C         cycles/limb
+C Itanium:    3.0
+C Itanium 2:  2.0
+
+C TODO
+C  * Further optimize feed-in and wind-down code, both for speed and code size.
+C  * Handle low limb input and results specially, using a common stf8 in the
+C    epilogue.
+C  * Use 1 c/l carry propagation scheme in wind-down code.
+C  * Use extra pointer registers for `up' and rp to speed up feed-in loads.
+C  * Work out final differences with mul_1.asm.  That function is 300 bytes
+C    smaller than this due to better loop scheduling and thus simpler feed-in
+C    code.
+
+C INPUT PARAMETERS
+define(`rp', `r32')
+define(`up', `r33')
+define(`n', `r34')
+define(`vl', `r35')
+
+ASM_START()
+PROLOGUE(mpn_addmul_1)
+	.prologue
+	.save	ar.lc, r2
+	.body
+
+ifdef(`HAVE_ABI_32',
+`	addp4		rp = 0, rp		C M I
+	addp4		up = 0, up		C M I
+	zxt4		n = n			C I
+	;;
+')
+{.mmi
+	adds		r15 = -1, n		C M I
+	mov		r20 = rp		C M I
+	mov.i		r2 = ar.lc		C I0
+}
+{.mmi
+	ldf8		f7 = [up], 8		C M
+	ldf8		f8 = [rp], 8		C M
+	and		r14 = 3, n		C M I
+	;;
+}
+{.mmi
+	setf.sig	f6 = vl			C M2 M3
+	cmp.eq		p10, p0 = 0, r14	C M I
+	shr.u		r31 = r15, 2		C I0
+}
+{.mmi
+	cmp.eq		p11, p0 = 2, r14	C M I
+	cmp.eq		p12, p0 = 3, r14	C M I
+	nop.i		0			C I
+	;;
+}
+{.mii
+	cmp.ne		p6, p7 = r0, r0		C M I
+	mov.i		ar.lc = r31		C I0
+	cmp.ne		p8, p9 = r0, r0		C M I
+}
+{.bbb
+  (p10)	br.dptk		.Lb00			C B
+  (p11)	br.dptk		.Lb10			C B
+  (p12)	br.dptk		.Lb11			C B
+	;;
+}
+
+.Lb01:	br.cloop.dptk	.grt1			C B
+
+	xma.l		f39 = f7, f6, f8	C F
+	xma.hu		f43 = f7, f6, f8	C F
+	;;
+	getf.sig	r8 = f43		C M2
+	stf8		[r20] = f39		C M2 M3
+	mov.i		ar.lc = r2		C I0
+	br.ret.sptk.many b0			C B
+
+.grt1:
+	ldf8		f32 = [up], 8
+	ldf8		f44 = [rp], 8
+	;;
+	ldf8		f33 = [up], 8
+	ldf8		f45 = [rp], 8
+	;;
+	ldf8		f34 = [up], 8
+	xma.l		f39 = f7, f6, f8
+	ldf8		f46 = [rp], 8
+	xma.hu		f43 = f7, f6, f8
+	;;
+	ldf8		f35 = [up], 8
+	ldf8		f47 = [rp], 8
+	br.cloop.dptk	.grt5
+
+	xma.l		f36 = f32, f6, f44
+	xma.hu		f40 = f32, f6, f44
+	;;
+	stf8		[r20] = f39, 8
+	xma.l		f37 = f33, f6, f45
+	xma.hu		f41 = f33, f6, f45
+	;;
+	getf.sig	r31 = f43
+	getf.sig	r24 = f36
+	xma.l		f38 = f34, f6, f46
+	xma.hu		f42 = f34, f6, f46
+	;;
+	getf.sig	r28 = f40
+	getf.sig	r25 = f37
+	xma.l		f39 = f35, f6, f47
+	xma.hu		f43 = f35, f6, f47
+	;;
+	getf.sig	r29 = f41
+	getf.sig	r26 = f38
+	br		.Lcj5
+
+.grt5:
+	mov		r30 = 0
+	xma.l		f36 = f32, f6, f44
+	xma.hu		f40 = f32, f6, f44
+	;;
+	ldf8		f32 = [up], 8
+	xma.l		f37 = f33, f6, f45
+	ldf8		f44 = [rp], 8
+	xma.hu		f41 = f33, f6, f45
+	;;
+	ldf8		f33 = [up], 8
+	getf.sig	r27 = f39
+	;;
+	getf.sig	r31 = f43
+	xma.l		f38 = f34, f6, f46
+	ldf8		f45 = [rp], 8
+	xma.hu		f42 = f34, f6, f46
+	;;
+	ldf8		f34 = [up], 8
+	getf.sig	r24 = f36
+	;;
+	getf.sig	r28 = f40
+	xma.l		f39 = f35, f6, f47
+	ldf8		f46 = [rp], 8
+	xma.hu		f43 = f35, f6, f47
+	;;
+	ldf8		f35 = [up], 8
+	getf.sig	r25 = f37
+	br.cloop.dptk	.Loop
+	br		.Le0
+
+
+.Lb10:	ldf8		f35 = [up], 8
+	ldf8		f47 = [rp], 8
+	br.cloop.dptk	.grt2
+
+	xma.l		f38 = f7, f6, f8
+	xma.hu		f42 = f7, f6, f8
+	;;
+	xma.l		f39 = f35, f6, f47
+	xma.hu		f43 = f35, f6, f47
+	;;
+	getf.sig	r30 = f42
+	stf8		[r20] = f38, 8
+	getf.sig	r27 = f39
+	getf.sig	r8 = f43
+	br		.Lcj2
+
+.grt2:
+	ldf8		f32 = [up], 8
+	ldf8		f44 = [rp], 8
+	;;
+	ldf8		f33 = [up], 8
+	xma.l		f38 = f7, f6, f8
+	ldf8		f45 = [rp], 8
+	xma.hu		f42 = f7, f6, f8
+	;;
+	ldf8		f34 = [up], 8
+	xma.l		f39 = f35, f6, f47
+	ldf8		f46 = [rp], 8
+	xma.hu		f43 = f35, f6, f47
+	;;
+	ldf8		f35 = [up], 8
+	ldf8		f47 = [rp], 8
+	br.cloop.dptk	.grt6
+
+	stf8		[r20] = f38, 8
+	xma.l		f36 = f32, f6, f44
+	xma.hu		f40 = f32, f6, f44
+	;;
+	getf.sig	r30 = f42
+	getf.sig	r27 = f39
+	xma.l		f37 = f33, f6, f45
+	xma.hu		f41 = f33, f6, f45
+	;;
+	getf.sig	r31 = f43
+	getf.sig	r24 = f36
+	xma.l		f38 = f34, f6, f46
+	xma.hu		f42 = f34, f6, f46
+	;;
+	getf.sig	r28 = f40
+	getf.sig	r25 = f37
+	xma.l		f39 = f35, f6, f47
+	xma.hu		f43 = f35, f6, f47
+	br		.Lcj6
+
+.grt6:
+	mov		r29 = 0
+	xma.l		f36 = f32, f6, f44
+	xma.hu		f40 = f32, f6, f44
+	;;
+	ldf8		f32 = [up], 8
+	getf.sig	r26 = f38
+	;;
+	getf.sig	r30 = f42
+	xma.l		f37 = f33, f6, f45
+	ldf8		f44 = [rp], 8
+	xma.hu		f41 = f33, f6, f45
+	;;
+	ldf8		f33 = [up], 8
+	getf.sig	r27 = f39
+	;;
+	getf.sig	r31 = f43
+	xma.l		f38 = f34, f6, f46
+	ldf8		f45 = [rp], 8
+	xma.hu		f42 = f34, f6, f46
+	;;
+	ldf8		f34 = [up], 8
+	getf.sig	r24 = f36
+	br		.LL10
+
+
+.Lb11:	ldf8		f34 = [up], 8
+	ldf8		f46 = [rp], 8
+	;;
+	ldf8		f35 = [up], 8
+	ldf8		f47 = [rp], 8
+	br.cloop.dptk	.grt3
+	;;
+
+	xma.l		f37 = f7, f6, f8
+	xma.hu		f41 = f7, f6, f8
+	xma.l		f38 = f34, f6, f46
+	xma.hu		f42 = f34, f6, f46
+	xma.l		f39 = f35, f6, f47
+	xma.hu		f43 = f35, f6, f47
+	;;
+	getf.sig	r29 = f41
+	stf8		[r20] = f37, 8
+	getf.sig	r26 = f38
+	getf.sig	r30 = f42
+	getf.sig	r27 = f39
+	getf.sig	r8 = f43
+	br		.Lcj3
+
+.grt3:
+	ldf8		f32 = [up], 8
+	xma.l		f37 = f7, f6, f8
+	ldf8		f44 = [rp], 8
+	xma.hu		f41 = f7, f6, f8
+	;;
+	ldf8		f33 = [up], 8
+	xma.l		f38 = f34, f6, f46
+	ldf8		f45 = [rp], 8
+	xma.hu		f42 = f34, f6, f46
+	;;
+	ldf8		f34 = [up], 8
+	xma.l		f39 = f35, f6, f47
+	ldf8		f46 = [rp], 8
+	xma.hu		f43 = f35, f6, f47
+	;;
+	ldf8		f35 = [up], 8
+	getf.sig	r25 = f37		C FIXME
+	ldf8		f47 = [rp], 8
+	br.cloop.dptk	.grt7
+
+	getf.sig	r29 = f41
+	stf8		[r20] = f37, 8		C FIXME
+	xma.l		f36 = f32, f6, f44
+	getf.sig	r26 = f38
+	xma.hu		f40 = f32, f6, f44
+	;;
+	getf.sig	r30 = f42
+	xma.l		f37 = f33, f6, f45
+	getf.sig	r27 = f39
+	xma.hu		f41 = f33, f6, f45
+	;;
+	getf.sig	r31 = f43
+	xma.l		f38 = f34, f6, f46
+	getf.sig	r24 = f36
+	xma.hu		f42 = f34, f6, f46
+	br		.Lcj7
+
+.grt7:
+	getf.sig	r29 = f41
+	xma.l		f36 = f32, f6, f44
+	mov		r28 = 0
+	xma.hu		f40 = f32, f6, f44
+	;;
+	ldf8		f32 = [up], 8
+	getf.sig	r26 = f38
+	;;
+	getf.sig	r30 = f42
+	xma.l		f37 = f33, f6, f45
+	ldf8		f44 = [rp], 8
+	xma.hu		f41 = f33, f6, f45
+	;;
+	ldf8		f33 = [up], 8
+	getf.sig	r27 = f39
+	br		.LL11
+
+
+.Lb00:	ldf8		f33 = [up], 8
+	ldf8		f45 = [rp], 8
+	;;
+	ldf8		f34 = [up], 8
+	ldf8		f46 = [rp], 8
+	;;
+	ldf8		f35 = [up], 8
+	xma.l		f36 = f7, f6, f8
+	ldf8		f47 = [rp], 8
+	xma.hu		f40 = f7, f6, f8
+	br.cloop.dptk	.grt4
+
+	xma.l		f37 = f33, f6, f45
+	xma.hu		f41 = f33, f6, f45
+	xma.l		f38 = f34, f6, f46
+	xma.hu		f42 = f34, f6, f46
+	;;
+	getf.sig	r28 = f40
+	stf8		[r20] = f36, 8
+	xma.l		f39 = f35, f6, f47
+	getf.sig	r25 = f37
+	xma.hu		f43 = f35, f6, f47
+	;;
+	getf.sig	r29 = f41
+	getf.sig	r26 = f38
+	getf.sig	r30 = f42
+	getf.sig	r27 = f39
+	br		.Lcj4
+
+.grt4:
+	ldf8		f32 = [up], 8
+	xma.l		f37 = f33, f6, f45
+	ldf8		f44 = [rp], 8
+	xma.hu		f41 = f33, f6, f45
+	;;
+	ldf8		f33 = [up], 8
+	xma.l		f38 = f34, f6, f46
+	ldf8		f45 = [rp], 8
+	xma.hu		f42 = f34, f6, f46
+	;;
+	ldf8		f34 = [up], 8
+	getf.sig	r24 = f36		C FIXME
+	xma.l		f39 = f35, f6, f47
+	ldf8		f46 = [rp], 8
+	getf.sig	r28 = f40
+	xma.hu		f43 = f35, f6, f47
+	;;
+	ldf8		f35 = [up], 8
+	getf.sig	r25 = f37
+	ldf8		f47 = [rp], 8
+	br.cloop.dptk	.grt8
+
+	getf.sig	r29 = f41
+	stf8		[r20] = f36, 8		C FIXME
+	xma.l		f36 = f32, f6, f44
+	getf.sig	r26 = f38
+	getf.sig	r30 = f42
+	xma.hu		f40 = f32, f6, f44
+	;;
+	xma.l		f37 = f33, f6, f45
+	getf.sig	r27 = f39
+	xma.hu		f41 = f33, f6, f45
+	br		.Lcj8
+
+.grt8:
+	getf.sig	r29 = f41
+	xma.l		f36 = f32, f6, f44
+	mov		r31 = 0
+	xma.hu		f40 = f32, f6, f44
+	;;
+	ldf8		f32 = [up], 8
+	getf.sig	r26 = f38
+	br		.LL00
+
+
+C *** MAIN LOOP START ***
+	ALIGN(32)				C insn	fed	cycle #
+.Loop:
+	.pred.rel "mutex", p6, p7		C num	by	i1 i2
+	getf.sig	r29 = f41		C 00	16	0   0
+	xma.l		f36 = f32, f6, f44	C 01	06,15	0   0
+   (p6)	add		r14 = r30, r27, 1	C 02		0   0
+	ldf8		f47 = [rp], 8		C 03		0   0
+	xma.hu		f40 = f32, f6, f44	C 04	06,15	0   0
+   (p7)	add		r14 = r30, r27		C 05		0   0
+	;;
+	.pred.rel "mutex", p6, p7
+	ldf8		f32 = [up], 8		C 06		1   1
+   (p6)	cmp.leu		p8, p9 = r14, r27	C 07		1   1
+   (p7)	cmp.ltu		p8, p9 = r14, r27	C 08		1   1
+	getf.sig	r26 = f38		C 09	25	2   1
+	st8		[r20] = r14, 8		C 10		2   1
+	nop.b		0			C 11		2   1
+	;;
+.LL00:
+	.pred.rel "mutex", p8, p9
+	getf.sig	r30 = f42		C 12	28	3   2
+	xma.l		f37 = f33, f6, f45	C 13	18,27	3   2
+   (p8)	add		r16 = r31, r24, 1	C 14		3   2
+	ldf8		f44 = [rp], 8		C 15		3   2
+	xma.hu		f41 = f33, f6, f45	C 16	18,27	3   2
+   (p9)	add		r16 = r31, r24		C 17		3   2
+	;;
+	.pred.rel "mutex", p8, p9
+	ldf8		f33 = [up], 8		C 18		4   3
+   (p8)	cmp.leu		p6, p7 = r16, r24	C 19		4   3
+   (p9)	cmp.ltu		p6, p7 = r16, r24	C 20		4   3
+	getf.sig	r27 = f39		C 21	37	5   3
+	st8		[r20] = r16, 8		C 22		5   3
+	nop.b		0			C 23		5   3
+	;;
+.LL11:
+	.pred.rel "mutex", p6, p7
+	getf.sig	r31 = f43		C 24	40	6   4
+	xma.l		f38 = f34, f6, f46	C 25	30,39	6   4
+   (p6)	add		r14 = r28, r25, 1	C 26		6   4
+	ldf8		f45 = [rp], 8		C 27		6   4
+	xma.hu		f42 = f34, f6, f46	C 28	30,39	6   4
+   (p7)	add		r14 = r28, r25		C 29		6   4
+	;;
+	.pred.rel "mutex", p6, p7
+	ldf8		f34 = [up], 8		C 30		7   5
+   (p6)	cmp.leu		p8, p9 = r14, r25	C 31		7   5
+   (p7)	cmp.ltu		p8, p9 = r14, r25	C 32		7   5
+	getf.sig	r24 = f36		C 33	01	8   5
+	st8		[r20] = r14, 8		C 34		8   5
+	nop.b		0			C 35		8   5
+	;;
+.LL10:
+	.pred.rel "mutex", p8, p9
+	getf.sig	r28 = f40		C 36	04	9   6
+	xma.l		f39 = f35, f6, f47	C 37	42,03	9   6
+   (p8)	add		r16 = r29, r26, 1	C 38		9   6
+	ldf8		f46 = [rp], 8		C 39		9   6
+	xma.hu		f43 = f35, f6, f47	C 40	42,03	9   6
+   (p9)	add		r16 = r29, r26		C 41		9   6
+	;;
+	.pred.rel "mutex", p8, p9
+	ldf8		f35 = [up], 8		C 42	       10   7
+   (p8)	cmp.leu		p6, p7 = r16, r26	C 43	       10   7
+   (p9)	cmp.ltu		p6, p7 = r16, r26	C 44	       10   7
+	getf.sig	r25 = f37		C 45	13     11   7
+	st8		[r20] = r16, 8		C 46	       11   7
+	br.cloop.dptk	.Loop			C 47	       11   7
+C *** MAIN LOOP END ***
+	;;
+.Le0:
+	.pred.rel "mutex", p6, p7
+	getf.sig	r29 = f41		C
+	xma.l		f36 = f32, f6, f44	C
+   (p6)	add		r14 = r30, r27, 1	C
+	ldf8		f47 = [rp], 8		C
+	xma.hu		f40 = f32, f6, f44	C
+   (p7)	add		r14 = r30, r27		C
+	;;
+	.pred.rel "mutex", p6, p7
+   (p6)	cmp.leu		p8, p9 = r14, r27	C
+   (p7)	cmp.ltu		p8, p9 = r14, r27	C
+	getf.sig	r26 = f38		C
+	st8		[r20] = r14, 8		C
+	;;
+	.pred.rel "mutex", p8, p9
+	getf.sig	r30 = f42		C
+	xma.l		f37 = f33, f6, f45	C
+   (p8)	add		r16 = r31, r24, 1	C
+	xma.hu		f41 = f33, f6, f45	C
+   (p9)	add		r16 = r31, r24		C
+	;;
+	.pred.rel "mutex", p8, p9
+   (p8)	cmp.leu		p6, p7 = r16, r24	C
+   (p9)	cmp.ltu		p6, p7 = r16, r24	C
+	getf.sig	r27 = f39		C
+	st8		[r20] = r16, 8		C
+	;;
+.Lcj8:
+	.pred.rel "mutex", p6, p7
+	getf.sig	r31 = f43		C
+	xma.l		f38 = f34, f6, f46	C
+   (p6)	add		r14 = r28, r25, 1	C
+	xma.hu		f42 = f34, f6, f46	C
+   (p7)	add		r14 = r28, r25		C
+	;;
+	.pred.rel "mutex", p6, p7
+   (p6)	cmp.leu		p8, p9 = r14, r25	C
+   (p7)	cmp.ltu		p8, p9 = r14, r25	C
+	getf.sig	r24 = f36		C
+	st8		[r20] = r14, 8		C
+	;;
+.Lcj7:
+	.pred.rel "mutex", p8, p9
+	getf.sig	r28 = f40		C
+	xma.l		f39 = f35, f6, f47	C
+   (p8)	add		r16 = r29, r26, 1	C
+	xma.hu		f43 = f35, f6, f47	C
+   (p9)	add		r16 = r29, r26		C
+	;;
+	.pred.rel "mutex", p8, p9
+   (p8)	cmp.leu		p6, p7 = r16, r26	C
+   (p9)	cmp.ltu		p6, p7 = r16, r26	C
+	getf.sig	r25 = f37		C
+	st8		[r20] = r16, 8		C
+	;;
+.Lcj6:
+	.pred.rel "mutex", p6, p7
+	getf.sig	r29 = f41		C
+   (p6)	add		r14 = r30, r27, 1	C
+   (p7)	add		r14 = r30, r27		C
+	;;
+	.pred.rel "mutex", p6, p7
+   (p6)	cmp.leu		p8, p9 = r14, r27	C
+   (p7)	cmp.ltu		p8, p9 = r14, r27	C
+	getf.sig	r26 = f38		C
+	st8		[r20] = r14, 8		C
+	;;
+.Lcj5:
+	.pred.rel "mutex", p8, p9
+	getf.sig	r30 = f42		C
+   (p8)	add		r16 = r31, r24, 1	C
+   (p9)	add		r16 = r31, r24		C
+	;;
+	.pred.rel "mutex", p8, p9
+   (p8)	cmp.leu		p6, p7 = r16, r24	C
+   (p9)	cmp.ltu		p6, p7 = r16, r24	C
+	getf.sig	r27 = f39		C
+	st8		[r20] = r16, 8		C
+	;;
+.Lcj4:
+	.pred.rel "mutex", p6, p7
+	getf.sig	r8 = f43		C
+   (p6)	add		r14 = r28, r25, 1	C
+   (p7)	add		r14 = r28, r25		C
+	;;
+	.pred.rel "mutex", p6, p7
+	st8		[r20] = r14, 8		C
+   (p6)	cmp.leu		p8, p9 = r14, r25	C
+   (p7)	cmp.ltu		p8, p9 = r14, r25	C
+	;;
+.Lcj3:
+	.pred.rel "mutex", p8, p9
+   (p8)	add		r16 = r29, r26, 1	C
+   (p9)	add		r16 = r29, r26		C
+	;;
+	.pred.rel "mutex", p8, p9
+	st8		[r20] = r16, 8		C
+   (p8)	cmp.leu		p6, p7 = r16, r26	C
+   (p9)	cmp.ltu		p6, p7 = r16, r26	C
+	;;
+.Lcj2:
+	.pred.rel "mutex", p6, p7
+   (p6)	add		r14 = r30, r27, 1	C
+   (p7)	add		r14 = r30, r27		C
+	;;
+	.pred.rel "mutex", p6, p7
+	st8		[r20] = r14		C
+   (p6)	cmp.leu		p8, p9 = r14, r27	C
+   (p7)	cmp.ltu		p8, p9 = r14, r27	C
+	;;
+   (p8)	add		r8 = 1, r8		C M I
+	mov.i		ar.lc = r2		C I0
+	br.ret.sptk.many b0			C B
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/ia64/addmul_2.asm b/third_party/gmp/mpn/ia64/addmul_2.asm
new file mode 100644
index 0000000..86e8de4
--- /dev/null
+++ b/third_party/gmp/mpn/ia64/addmul_2.asm
@@ -0,0 +1,715 @@
+dnl  IA-64 mpn_addmul_2 -- Multiply a n-limb number with a 2-limb number and
+dnl  add the result to a (n+1)-limb number.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2004, 2005, 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C         cycles/limb
+C Itanium:    3.65
+C Itanium 2:  1.625
+
+C TODO
+C  * Clean up variable names, and try to decrease the number of distinct
+C    registers used.
+C  * Clean up feed-in code to not require zeroing several registers.
+C  * Make sure we don't depend on uninitialised predicate registers.
+C  * Could perhaps save a few cycles by using 1 c/l carry propagation in
+C    wind-down code.
+C  * Ultimately rewrite.  The problem with this code is that it first uses a
+C    loaded u value in one xma pair, then leaves it live over several unrelated
+C    xma pairs, before it uses it again.  It should actually be quite possible
+C    to just swap some aligned xma pairs around.  But we should then schedule
+C    u loads further from the first use.
+
+C INPUT PARAMETERS
+define(`rp',`r32')
+define(`up',`r33')
+define(`n',`r34')
+define(`vp',`r35')
+
+define(`srp',`r3')
+
+define(`v0',`f6')
+define(`v1',`f7')
+
+define(`s0',`r14')
+define(`acc0',`r15')
+
+define(`pr0_0',`r16') define(`pr0_1',`r17')
+define(`pr0_2',`r18') define(`pr0_3',`r19')
+
+define(`pr1_0',`r20') define(`pr1_1',`r21')
+define(`pr1_2',`r22') define(`pr1_3',`r23')
+
+define(`acc1_0',`r24') define(`acc1_1',`r25')
+define(`acc1_2',`r26') define(`acc1_3',`r27')
+
+dnl define(`',`r28')
+dnl define(`',`r29')
+dnl define(`',`r30')
+dnl define(`',`r31')
+
+define(`fp0b_0',`f8') define(`fp0b_1',`f9')
+define(`fp0b_2',`f10') define(`fp0b_3',`f11')
+
+define(`fp1a_0',`f12') define(`fp1a_1',`f13')
+define(`fp1a_2',`f14') define(`fp1a_3',`f15')
+
+define(`fp1b_0',`f32') define(`fp1b_1',`f33')
+define(`fp1b_2',`f34') define(`fp1b_3',`f35')
+
+define(`fp2a_0',`f36') define(`fp2a_1',`f37')
+define(`fp2a_2',`f38') define(`fp2a_3',`f39')
+
+define(`r_0',`f40') define(`r_1',`f41')
+define(`r_2',`f42') define(`r_3',`f43')
+
+define(`u_0',`f44') define(`u_1',`f45')
+define(`u_2',`f46') define(`u_3',`f47')
+
+define(`rx',`f48')
+define(`ux',`f49')
+define(`ry',`f50')
+define(`uy',`f51')
+
+ASM_START()
+PROLOGUE(mpn_addmul_2s)
+	.prologue
+	.save	ar.lc, r2
+	.body
+
+ifdef(`HAVE_ABI_32',`
+ {.mmi;		addp4	rp = 0, rp		C			M I
+		addp4	up = 0, up		C			M I
+		addp4	vp = 0, vp		C			M I
+}{.mmi;		nop	1
+		nop	1
+		zxt4	n = n			C			I
+	;;
+}')
+
+ {.mmi;		ldf8	ux = [up], 8		C			M
+		ldf8	v0 = [vp], 8		C			M
+		mov	r2 = ar.lc		C			I0
+}{.mmi;		ldf8	rx = [rp], 8		C			M
+		and	r14 = 3, n		C			M I
+		add	n = -2, n		C			M I
+	;;
+}{.mmi;		ldf8	uy = [up], 8		C			M
+		ldf8	v1 = [vp]		C			M
+		shr.u	n = n, 2		C			I0
+}{.mmi;		ldf8	ry = [rp], -8		C			M
+		cmp.eq	p14, p0 = 1, r14	C			M I
+		cmp.eq	p11, p0 = 2, r14	C			M I
+	;;
+}{.mmi;		add	srp = 16, rp		C			M I
+		cmp.eq	p15, p0 = 3, r14	C			M I
+		mov	ar.lc = n		C			I0
+}{.bbb;	(p14)	br.dptk	L(x01)			C			B
+	(p11)	br.dptk	L(x10)			C			B
+	(p15)	br.dptk	L(x11)			C			B
+	;;
+}
+L(x00):		cmp.ne	p6, p0 = r0, r0		C suppress initial xma pair
+		mov	fp2a_3 = f0
+		br	L(b00)
+L(x01):		cmp.ne	p14, p0 = r0, r0	C suppress initial xma pair
+		mov	fp2a_2 = f0
+		br	L(b01)
+L(x10):		cmp.ne	p11, p0 = r0, r0	C suppress initial xma pair
+		mov	fp2a_1 = f0
+		br	L(b10)
+L(x11):		cmp.ne	p15, p0 = r0, r0	C suppress initial xma pair
+		mov	fp2a_0 = f0
+		br	L(b11)
+
+EPILOGUE()
+
+PROLOGUE(mpn_addmul_2)
+	.prologue
+	.save	ar.lc, r2
+	.body
+
+ifdef(`HAVE_ABI_32',`
+ {.mmi;		addp4	rp = 0, rp		C			M I
+		addp4	up = 0, up		C			M I
+		addp4	vp = 0, vp		C			M I
+}{.mmi;		nop	1
+		nop	1
+		zxt4	n = n			C			I
+	;;
+}')
+
+ {.mmi;		ldf8	ux = [up], 8		C			M
+		ldf8	v0 = [vp], 8		C			M
+		mov	r2 = ar.lc		C			I0
+}{.mmi;		ldf8	rx = [rp], 8		C			M
+		and	r14 = 3, n		C			M I
+		add	n = -2, n		C			M I
+	;;
+}{.mmi;		ldf8	uy = [up], 8		C			M
+		ldf8	v1 = [vp]		C			M
+		shr.u	n = n, 2		C			I0
+}{.mmi;		ldf8	ry = [rp], -8		C			M
+		cmp.eq	p14, p0 = 1, r14	C			M I
+		cmp.eq	p11, p0 = 2, r14	C			M I
+	;;
+}{.mmi;		add	srp = 16, rp		C			M I
+		cmp.eq	p15, p6 = 3, r14	C			M I
+		mov	ar.lc = n		C			I0
+}{.bbb;	(p14)	br.dptk	L(b01)			C			B
+	(p11)	br.dptk	L(b10)			C			B
+	(p15)	br.dptk	L(b11)			C			B
+	;;
+}
+	ALIGN(32)
+L(b00):
+ {.mmi;		ldf8	r_1 = [srp], 8
+		ldf8	u_1 = [up], 8
+		mov	acc1_2 = 0
+}{.mmi;		mov	pr1_2 = 0
+		mov	pr0_3 = 0
+		cmp.ne	p8, p9 = r0, r0
+	;;
+}{.mfi;		ldf8	r_2 = [srp], 8
+		xma.l	fp0b_3 = ux, v0, rx
+		cmp.ne	p12, p13 = r0, r0
+}{.mfb;		ldf8	u_2 = [up], 8
+		xma.hu	fp1b_3 = ux, v0, rx
+		br.cloop.dptk	L(gt4)
+}
+		xma.l	fp0b_0 = uy, v0, ry
+		xma.hu	fp1a_0 = uy, v0, ry
+	;;
+		getfsig	acc0 = fp0b_3
+	(p6)	xma.hu	fp2a_3 = ux, v1, fp1b_3		C suppressed for addmul_2s
+	(p6)	xma.l	fp1b_3 = ux, v1, fp1b_3		C suppressed for addmul_2s
+	;;
+		xma.l	fp0b_1 = u_1, v0, r_1
+		xma.hu	fp1a_1 = u_1, v0, r_1
+	;;
+		getfsig	pr0_0 = fp0b_0
+		xma.l	fp1b_0 = uy, v1, fp1a_0
+		xma.hu	fp2a_0 = uy, v1, fp1a_0
+	;;
+		getfsig	pr1_3 = fp1b_3
+		getfsig	acc1_3 = fp2a_3
+		xma.l	fp0b_2 = u_2, v0, r_2
+		xma.hu	fp1a_2 = u_2, v0, r_2
+		br	L(cj4)
+
+L(gt4):		xma.l	fp0b_0 = uy, v0, ry
+		xma.hu	fp1a_0 = uy, v0, ry
+	;;
+		ldf8	r_3 = [srp], 8
+		getfsig	acc0 = fp0b_3
+	(p6)	xma.hu	fp2a_3 = ux, v1, fp1b_3		C suppressed for addmul_2s
+		ldf8	u_3 = [up], 8
+	(p6)	xma.l	fp1b_3 = ux, v1, fp1b_3		C suppressed for addmul_2s
+	;;
+		xma.l	fp0b_1 = u_1, v0, r_1
+		xma.hu	fp1a_1 = u_1, v0, r_1
+	;;
+		ldf8	r_0 = [srp], 8
+		getfsig	pr0_0 = fp0b_0
+		xma.l	fp1b_0 = uy, v1, fp1a_0
+		xma.hu	fp2a_0 = uy, v1, fp1a_0
+	;;
+		ldf8	u_0 = [up], 8
+		getfsig	pr1_3 = fp1b_3
+		xma.l	fp0b_2 = u_2, v0, r_2
+	;;
+		getfsig	acc1_3 = fp2a_3
+		xma.hu	fp1a_2 = u_2, v0, r_2
+		br	L(00)
+
+
+	ALIGN(32)
+L(b01):
+ {.mmi;		ldf8	r_0 = [srp], 8		C M
+		ldf8	u_0 = [up], 8		C M
+		mov	acc1_1 = 0		C M I
+}{.mmi;		mov	pr1_1 = 0		C M I
+		mov	pr0_2 = 0		C M I
+		cmp.ne	p6, p7 = r0, r0		C M I
+	;;
+}{.mfi;		ldf8	r_1 = [srp], 8		C M
+		xma.l	fp0b_2 = ux, v0, rx	C F
+		cmp.ne	p10, p11 = r0, r0	C M I
+}{.mfi;		ldf8	u_1 = [up], 8		C M
+		xma.hu	fp1b_2 = ux, v0, rx	C F
+		nop	1
+	;;
+}		xma.l	fp0b_3 = uy, v0, ry	C F
+		xma.hu	fp1a_3 = uy, v0, ry	C F
+	;;
+ {.mmf;		getfsig	acc0 = fp0b_2		C M
+		ldf8	r_2 = [srp], 8		C M
+	(p14)	xma.hu	fp2a_2 = ux, v1,fp1b_2	C F	suppressed for addmul_2s
+}{.mfb;		ldf8	u_2 = [up], 8		C M
+	(p14)	xma.l	fp1b_2 = ux, v1,fp1b_2	C F	suppressed for addmul_2s
+		br.cloop.dptk	L(gt5)
+}
+		xma.l	fp0b_0 = u_0, v0, r_0	C F
+		xma.hu	fp1a_0 = u_0, v0, r_0	C F
+	;;
+		getfsig	pr0_3 = fp0b_3		C M
+		xma.l	fp1b_3 = uy, v1,fp1a_3	C F
+		xma.hu	fp2a_3 = uy, v1,fp1a_3	C F
+	;;
+		getfsig	pr1_2 = fp1b_2		C M
+		getfsig	acc1_2 = fp2a_2		C M
+		xma.l	fp0b_1 = u_1, v0, r_1	C F
+		xma.hu	fp1a_1 = u_1, v0, r_1	C F
+		br	L(cj5)
+
+L(gt5):		xma.l	fp0b_0 = u_0, v0, r_0
+		xma.hu	fp1a_0 = u_0, v0, r_0
+	;;
+		getfsig	pr0_3 = fp0b_3
+		ldf8	r_3 = [srp], 8
+		xma.l	fp1b_3 = uy, v1, fp1a_3
+		xma.hu	fp2a_3 = uy, v1, fp1a_3
+	;;
+		ldf8	u_3 = [up], 8
+		getfsig	pr1_2 = fp1b_2
+		xma.l	fp0b_1 = u_1, v0, r_1
+	;;
+		getfsig	acc1_2 = fp2a_2
+		xma.hu	fp1a_1 = u_1, v0, r_1
+		br	L(01)
+
+
+	ALIGN(32)
+L(b10):		br.cloop.dptk	L(gt2)
+		xma.l	fp0b_1 = ux, v0, rx
+		xma.hu	fp1b_1 = ux, v0, rx
+	;;
+		xma.l	fp0b_2 = uy, v0, ry
+		xma.hu	fp1a_2 = uy, v0, ry
+	;;
+		stf8	[rp] = fp0b_1, 8
+	(p11)	xma.hu	fp2a_1 = ux, v1, fp1b_1		C suppressed for addmul_2s
+	(p11)	xma.l	fp1b_1 = ux, v1, fp1b_1		C suppressed for addmul_2s
+	;;
+		getfsig	acc0 = fp0b_2
+		xma.l	fp1b_2 = uy, v1, fp1a_2
+		xma.hu	fp2a_2 = uy, v1, fp1a_2
+	;;
+		getfsig	pr1_1 = fp1b_1
+		getfsig	acc1_1 = fp2a_1
+		mov	ar.lc = r2
+		getfsig	pr1_2 = fp1b_2
+		getfsig	r8 = fp2a_2
+	;;
+		add	s0 = pr1_1, acc0
+	;;
+		st8	[rp] = s0, 8
+		cmp.ltu	p8, p9 = s0, pr1_1
+		sub	r31 = -1, acc1_1
+	;;
+	.pred.rel "mutex", p8, p9
+	(p8)	add	acc0 = pr1_2, acc1_1, 1
+	(p9)	add	acc0 = pr1_2, acc1_1
+	(p8)	cmp.leu	p10, p0 = r31, pr1_2
+	(p9)	cmp.ltu	p10, p0 = r31, pr1_2
+	;;
+		st8	[rp] = acc0, 8
+	(p10)	add	r8 = 1, r8
+		br.ret.sptk.many b0
+
+
+L(gt2):
+ {.mmi;		ldf8	r_3 = [srp], 8
+		ldf8	u_3 = [up], 8
+		mov	acc1_0 = 0
+	;;
+}{.mfi;		ldf8	r_0 = [srp], 8
+		xma.l	fp0b_1 = ux, v0, rx
+		mov	pr1_0 = 0
+}{.mfi;		ldf8	u_0 = [up], 8
+		xma.hu	fp1b_1 = ux, v0, rx
+		mov	pr0_1 = 0
+	;;
+}		xma.l	fp0b_2 = uy, v0, ry
+		xma.hu	fp1a_2 = uy, v0, ry
+	;;
+		getfsig	acc0 = fp0b_1
+		ldf8	r_1 = [srp], 8
+	(p11)	xma.hu	fp2a_1 = ux, v1, fp1b_1		C suppressed for addmul_2s
+	(p11)	xma.l	fp1b_1 = ux, v1, fp1b_1		C suppressed for addmul_2s
+	;;
+		ldf8	u_1 = [up], 8
+		xma.l	fp0b_3 = u_3, v0, r_3
+		xma.hu	fp1a_3 = u_3, v0, r_3
+	;;
+		getfsig	pr0_2 = fp0b_2
+		ldf8	r_2 = [srp], 8
+		xma.l	fp1b_2 = uy, v1, fp1a_2
+		xma.hu	fp2a_2 = uy, v1, fp1a_2
+	;;
+		ldf8	u_2 = [up], 8
+		getfsig	pr1_1 = fp1b_1
+	;;
+ {.mfi;		getfsig	acc1_1 = fp2a_1
+		xma.l	fp0b_0 = u_0, v0, r_0
+		cmp.ne	p8, p9 = r0, r0
+}{.mfb;		cmp.ne	p12, p13 = r0, r0
+		xma.hu	fp1a_0 = u_0, v0, r_0
+		br.cloop.sptk.clr	L(top)
+}
+		br.many	L(end)
+
+
+	ALIGN(32)
+L(b11):		ldf8	r_2 = [srp], 8
+		mov	pr1_3 = 0
+		mov	pr0_0 = 0
+	;;
+		ldf8	u_2 = [up], 8
+		mov	acc1_3 = 0
+		br.cloop.dptk	L(gt3)
+	;;
+		cmp.ne	p6, p7 = r0, r0
+		xma.l	fp0b_0 = ux, v0, rx
+		xma.hu	fp1b_0 = ux, v0, rx
+	;;
+		cmp.ne	p10, p11 = r0, r0
+		xma.l	fp0b_1 = uy, v0, ry
+		xma.hu	fp1a_1 = uy, v0, ry
+	;;
+		getfsig	acc0 = fp0b_0
+	(p15)	xma.hu	fp2a_0 = ux, v1, fp1b_0		C suppressed for addmul_2s
+	(p15)	xma.l	fp1b_0 = ux, v1, fp1b_0		C suppressed for addmul_2s
+	;;
+		xma.l	fp0b_2 = uy, v1, r_2
+		xma.hu	fp1a_2 = uy, v1, r_2
+	;;
+		getfsig	pr0_1 = fp0b_1
+		xma.l	fp1b_1 = u_2, v0, fp1a_1
+		xma.hu	fp2a_1 = u_2, v0, fp1a_1
+	;;
+		getfsig	pr1_0 = fp1b_0
+		getfsig	acc1_0 = fp2a_0
+		br	L(cj3)
+
+L(gt3):		ldf8	r_3 = [srp], 8
+		xma.l	fp0b_0 = ux, v0, rx
+		cmp.ne	p10, p11 = r0, r0
+		ldf8	u_3 = [up], 8
+		xma.hu	fp1b_0 = ux, v0, rx
+		cmp.ne	p6, p7 = r0, r0
+	;;
+		xma.l	fp0b_1 = uy, v0, ry
+		xma.hu	fp1a_1 = uy, v0, ry
+	;;
+		getfsig	acc0 = fp0b_0
+		ldf8	r_0 = [srp], 8
+	(p15)	xma.hu	fp2a_0 = ux, v1, fp1b_0		C suppressed for addmul_2s
+		ldf8	u_0 = [up], 8
+	(p15)	xma.l	fp1b_0 = ux, v1, fp1b_0		C suppressed for addmul_2s
+	;;
+		xma.l	fp0b_2 = u_2, v0, r_2
+		xma.hu	fp1a_2 = u_2, v0, r_2
+	;;
+		getfsig	pr0_1 = fp0b_1
+		ldf8	r_1 = [srp], 8
+		xma.l	fp1b_1 = uy, v1, fp1a_1
+		xma.hu	fp2a_1 = uy, v1, fp1a_1
+	;;
+		ldf8	u_1 = [up], 8
+		getfsig	pr1_0 = fp1b_0
+	;;
+		getfsig	acc1_0 = fp2a_0
+		xma.l	fp0b_3 = u_3, v0, r_3
+		xma.hu	fp1a_3 = u_3, v0, r_3
+		br	L(11)
+
+
+C *** MAIN LOOP START ***
+	ALIGN(32)
+L(top):						C 00
+	.pred.rel "mutex", p12, p13
+		getfsig	pr0_3 = fp0b_3
+		ldf8	r_3 = [srp], 8
+		xma.l	fp1b_3 = u_3, v1, fp1a_3
+	(p12)	add	s0 = pr1_0, acc0, 1
+	(p13)	add	s0 = pr1_0, acc0
+		xma.hu	fp2a_3 = u_3, v1, fp1a_3
+	;;					C 01
+	.pred.rel "mutex", p8, p9
+	.pred.rel "mutex", p12, p13
+		ldf8	u_3 = [up], 8
+		getfsig	pr1_2 = fp1b_2
+	(p8)	cmp.leu	p6, p7 = acc0, pr0_1
+	(p9)	cmp.ltu	p6, p7 = acc0, pr0_1
+	(p12)	cmp.leu	p10, p11 = s0, pr1_0
+	(p13)	cmp.ltu	p10, p11 = s0, pr1_0
+	;;					C 02
+	.pred.rel "mutex", p6, p7
+		getfsig	acc1_2 = fp2a_2
+		st8	[rp] = s0, 8
+		xma.l	fp0b_1 = u_1, v0, r_1
+	(p6)	add	acc0 = pr0_2, acc1_0, 1
+	(p7)	add	acc0 = pr0_2, acc1_0
+		xma.hu	fp1a_1 = u_1, v0, r_1
+	;;					C 03
+L(01):
+	.pred.rel "mutex", p10, p11
+		getfsig	pr0_0 = fp0b_0
+		ldf8	r_0 = [srp], 8
+		xma.l	fp1b_0 = u_0, v1, fp1a_0
+	(p10)	add	s0 = pr1_1, acc0, 1
+	(p11)	add	s0 = pr1_1, acc0
+		xma.hu	fp2a_0 = u_0, v1, fp1a_0
+	;;					C 04
+	.pred.rel "mutex", p6, p7
+	.pred.rel "mutex", p10, p11
+		ldf8	u_0 = [up], 8
+		getfsig	pr1_3 = fp1b_3
+	(p6)	cmp.leu	p8, p9 = acc0, pr0_2
+	(p7)	cmp.ltu	p8, p9 = acc0, pr0_2
+	(p10)	cmp.leu	p12, p13 = s0, pr1_1
+	(p11)	cmp.ltu	p12, p13 = s0, pr1_1
+	;;					C 05
+	.pred.rel "mutex", p8, p9
+		getfsig	acc1_3 = fp2a_3
+		st8	[rp] = s0, 8
+		xma.l	fp0b_2 = u_2, v0, r_2
+	(p8)	add	acc0 = pr0_3, acc1_1, 1
+	(p9)	add	acc0 = pr0_3, acc1_1
+		xma.hu	fp1a_2 = u_2, v0, r_2
+	;;					C 06
+L(00):
+	.pred.rel "mutex", p12, p13
+		getfsig	pr0_1 = fp0b_1
+		ldf8	r_1 = [srp], 8
+		xma.l	fp1b_1 = u_1, v1, fp1a_1
+	(p12)	add	s0 = pr1_2, acc0, 1
+	(p13)	add	s0 = pr1_2, acc0
+		xma.hu	fp2a_1 = u_1, v1, fp1a_1
+	;;					C 07
+	.pred.rel "mutex", p8, p9
+	.pred.rel "mutex", p12, p13
+		ldf8	u_1 = [up], 8
+		getfsig	pr1_0 = fp1b_0
+	(p8)	cmp.leu	p6, p7 = acc0, pr0_3
+	(p9)	cmp.ltu	p6, p7 = acc0, pr0_3
+	(p12)	cmp.leu	p10, p11 = s0, pr1_2
+	(p13)	cmp.ltu	p10, p11 = s0, pr1_2
+	;;					C 08
+	.pred.rel "mutex", p6, p7
+		getfsig	acc1_0 = fp2a_0
+		st8	[rp] = s0, 8
+		xma.l	fp0b_3 = u_3, v0, r_3
+	(p6)	add	acc0 = pr0_0, acc1_2, 1
+	(p7)	add	acc0 = pr0_0, acc1_2
+		xma.hu	fp1a_3 = u_3, v0, r_3
+	;;					C 09
+L(11):
+	.pred.rel "mutex", p10, p11
+		getfsig	pr0_2 = fp0b_2
+		ldf8	r_2 = [srp], 8
+		xma.l	fp1b_2 = u_2, v1, fp1a_2
+	(p10)	add	s0 = pr1_3, acc0, 1
+	(p11)	add	s0 = pr1_3, acc0
+		xma.hu	fp2a_2 = u_2, v1, fp1a_2
+	;;					C 10
+	.pred.rel "mutex", p6, p7
+	.pred.rel "mutex", p10, p11
+		ldf8	u_2 = [up], 8
+		getfsig	pr1_1 = fp1b_1
+	(p6)	cmp.leu	p8, p9 = acc0, pr0_0
+	(p7)	cmp.ltu	p8, p9 = acc0, pr0_0
+	(p10)	cmp.leu	p12, p13 = s0, pr1_3
+	(p11)	cmp.ltu	p12, p13 = s0, pr1_3
+	;;					C 11
+	.pred.rel "mutex", p8, p9
+		getfsig	acc1_1 = fp2a_1
+		st8	[rp] = s0, 8
+		xma.l	fp0b_0 = u_0, v0, r_0
+	(p8)	add	acc0 = pr0_1, acc1_3, 1
+	(p9)	add	acc0 = pr0_1, acc1_3
+		xma.hu	fp1a_0 = u_0, v0, r_0
+L(10):		br.cloop.sptk.clr	L(top)	C 12
+	;;
+C *** MAIN LOOP END ***
+L(end):
+	.pred.rel "mutex", p12, p13
+ {.mfi;		getfsig	pr0_3 = fp0b_3
+		xma.l	fp1b_3 = u_3, v1, fp1a_3
+	(p12)	add	s0 = pr1_0, acc0, 1
+}{.mfi;	(p13)	add	s0 = pr1_0, acc0
+		xma.hu	fp2a_3 = u_3, v1, fp1a_3
+		nop	1
+	;;
+}	.pred.rel "mutex", p8, p9
+	.pred.rel "mutex", p12, p13
+ {.mmi;		getfsig	pr1_2 = fp1b_2
+		st8	[rp] = s0, 8
+	(p8)	cmp.leu	p6, p7 = acc0, pr0_1
+}{.mmi;	(p9)	cmp.ltu	p6, p7 = acc0, pr0_1
+	(p12)	cmp.leu	p10, p11 = s0, pr1_0
+	(p13)	cmp.ltu	p10, p11 = s0, pr1_0
+	;;
+}	.pred.rel "mutex", p6, p7
+ {.mfi;		getfsig	acc1_2 = fp2a_2
+		xma.l	fp0b_1 = u_1, v0, r_1
+		nop	1
+}{.mmf;	(p6)	add	acc0 = pr0_2, acc1_0, 1
+	(p7)	add	acc0 = pr0_2, acc1_0
+		xma.hu	fp1a_1 = u_1, v0, r_1
+	;;
+}
+L(cj5):
+	.pred.rel "mutex", p10, p11
+ {.mfi;		getfsig	pr0_0 = fp0b_0
+		xma.l	fp1b_0 = u_0, v1, fp1a_0
+	(p10)	add	s0 = pr1_1, acc0, 1
+}{.mfi;	(p11)	add	s0 = pr1_1, acc0
+		xma.hu	fp2a_0 = u_0, v1, fp1a_0
+		nop	1
+	;;
+}	.pred.rel "mutex", p6, p7
+	.pred.rel "mutex", p10, p11
+ {.mmi;		getfsig	pr1_3 = fp1b_3
+	st8	[rp] = s0, 8
+	(p6)	cmp.leu	p8, p9 = acc0, pr0_2
+}{.mmi;	(p7)	cmp.ltu	p8, p9 = acc0, pr0_2
+	(p10)	cmp.leu	p12, p13 = s0, pr1_1
+	(p11)	cmp.ltu	p12, p13 = s0, pr1_1
+	;;
+}	.pred.rel "mutex", p8, p9
+ {.mfi;		getfsig	acc1_3 = fp2a_3
+		xma.l	fp0b_2 = u_2, v0, r_2
+		nop	1
+}{.mmf;	(p8)	add	acc0 = pr0_3, acc1_1, 1
+	(p9)	add	acc0 = pr0_3, acc1_1
+		xma.hu	fp1a_2 = u_2, v0, r_2
+	;;
+}
+L(cj4):
+	.pred.rel "mutex", p12, p13
+ {.mfi;		getfsig	pr0_1 = fp0b_1
+		xma.l	fp1b_1 = u_1, v1, fp1a_1
+	(p12)	add	s0 = pr1_2, acc0, 1
+}{.mfi;	(p13)	add	s0 = pr1_2, acc0
+		xma.hu	fp2a_1 = u_1, v1, fp1a_1
+		nop	1
+	;;
+}	.pred.rel "mutex", p8, p9
+	.pred.rel "mutex", p12, p13
+ {.mmi;		getfsig	pr1_0 = fp1b_0
+		st8	[rp] = s0, 8
+	(p8)	cmp.leu	p6, p7 = acc0, pr0_3
+}{.mmi;	(p9)	cmp.ltu	p6, p7 = acc0, pr0_3
+	(p12)	cmp.leu	p10, p11 = s0, pr1_2
+	(p13)	cmp.ltu	p10, p11 = s0, pr1_2
+	;;
+}	.pred.rel "mutex", p6, p7
+ {.mmi;		getfsig	acc1_0 = fp2a_0
+	(p6)	add	acc0 = pr0_0, acc1_2, 1
+	(p7)	add	acc0 = pr0_0, acc1_2
+	;;
+}
+L(cj3):
+	.pred.rel "mutex", p10, p11
+ {.mfi;		getfsig	pr0_2 = fp0b_2
+		xma.l	fp1b_2 = u_2, v1, fp1a_2
+	(p10)	add	s0 = pr1_3, acc0, 1
+}{.mfi;	(p11)	add	s0 = pr1_3, acc0
+		xma.hu	fp2a_2 = u_2, v1, fp1a_2
+		nop	1
+	;;
+}	.pred.rel "mutex", p6, p7
+	.pred.rel "mutex", p10, p11
+ {.mmi;		getfsig	pr1_1 = fp1b_1
+		st8	[rp] = s0, 8
+	(p6)	cmp.leu	p8, p9 = acc0, pr0_0
+}{.mmi;	(p7)	cmp.ltu	p8, p9 = acc0, pr0_0
+	(p10)	cmp.leu	p12, p13 = s0, pr1_3
+	(p11)	cmp.ltu	p12, p13 = s0, pr1_3
+	;;
+}	.pred.rel "mutex", p8, p9
+ {.mmi;		getfsig	acc1_1 = fp2a_1
+	(p8)	add	acc0 = pr0_1, acc1_3, 1
+	(p9)	add	acc0 = pr0_1, acc1_3
+	;;
+}	.pred.rel "mutex", p12, p13
+ {.mmi;	(p12)	add	s0 = pr1_0, acc0, 1
+	(p13)	add	s0 = pr1_0, acc0
+		nop	1
+	;;
+}	.pred.rel "mutex", p8, p9
+	.pred.rel "mutex", p12, p13
+ {.mmi;		getfsig	pr1_2 = fp1b_2
+		st8	[rp] = s0, 8
+	(p8)	cmp.leu	p6, p7 = acc0, pr0_1
+}{.mmi;	(p9)	cmp.ltu	p6, p7 = acc0, pr0_1
+	(p12)	cmp.leu	p10, p11 = s0, pr1_0
+	(p13)	cmp.ltu	p10, p11 = s0, pr1_0
+	;;
+}	.pred.rel "mutex", p6, p7
+ {.mmi;		getfsig	r8 = fp2a_2
+	(p6)	add	acc0 = pr0_2, acc1_0, 1
+	(p7)	add	acc0 = pr0_2, acc1_0
+	;;
+}	.pred.rel "mutex", p10, p11
+ {.mmi;	(p10)	add	s0 = pr1_1, acc0, 1
+	(p11)	add	s0 = pr1_1, acc0
+	(p6)	cmp.leu	p8, p9 = acc0, pr0_2
+	;;
+}	.pred.rel "mutex", p10, p11
+ {.mmi;	(p7)	cmp.ltu	p8, p9 = acc0, pr0_2
+	(p10)	cmp.leu	p12, p13 = s0, pr1_1
+	(p11)	cmp.ltu	p12, p13 = s0, pr1_1
+	;;
+}	.pred.rel "mutex", p8, p9
+ {.mmi;		st8	[rp] = s0, 8
+	(p8)	add	acc0 = pr1_2, acc1_1, 1
+	(p9)	add	acc0 = pr1_2, acc1_1
+	;;
+}	.pred.rel "mutex", p8, p9
+ {.mmi;	(p8)	cmp.leu	p10, p11 = acc0, pr1_2
+	(p9)	cmp.ltu	p10, p11 = acc0, pr1_2
+	(p12)	add	acc0 = 1, acc0
+	;;
+}{.mmi;		st8	[rp] = acc0, 8
+	(p12)	cmpeqor	p10, p0 = 0, acc0
+		nop	1
+	;;
+}{.mib;	(p10)	add	r8 = 1, r8
+		mov	ar.lc = r2
+		br.ret.sptk.many b0
+}
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/ia64/aors_n.asm b/third_party/gmp/mpn/ia64/aors_n.asm
new file mode 100644
index 0000000..7705ce6
--- /dev/null
+++ b/third_party/gmp/mpn/ia64/aors_n.asm
@@ -0,0 +1,852 @@
+dnl  IA-64 mpn_add_n/mpn_sub_n -- mpn addition and subtraction.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2003-2005, 2010, 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C           cycles/limb
+C Itanium:      2.67
+C Itanium 2:    1.25
+
+C TODO
+C  * Consider using special code for small n, using something like
+C    "switch (8 * (n >= 8) + (n mod 8))" to enter it and feed-in code.
+C  * The non-nc code was trimmed cycle for cycle to its current state.  It is
+C    probably hard to save more that an odd cycle there.  The nc code is much
+C    cruder (since tune/speed doesn't have any applicable direct measurements).
+C  * Without the nc entry points, this becomes around 1800 bytes of object
+C    code; the nc code adds over 1000 bytes.  We should perhaps sacrifice a
+C    few cycles for the non-nc code and let it fall into the nc code.
+
+C INPUT PARAMETERS
+define(`rp', `r32')
+define(`up', `r33')
+define(`vp', `r34')
+define(`n',  `r35')
+define(`cy', `r36')
+
+ifdef(`OPERATION_add_n',`
+  define(ADDSUB,	add)
+  define(CND,		ltu)
+  define(INCR,		1)
+  define(LIM,		-1)
+  define(LIM2,		0)
+  define(func,    mpn_add_n)
+  define(func_nc, mpn_add_nc)
+')
+ifdef(`OPERATION_sub_n',`
+  define(ADDSUB,	sub)
+  define(CND,		gtu)
+  define(INCR,		-1)
+  define(LIM,		0)
+  define(LIM2,		-1)
+  define(func,    mpn_sub_n)
+  define(func_nc, mpn_sub_nc)
+')
+
+define(PFDIST, 500)
+
+C Some useful aliases for registers we use
+define(`u0',`r14') define(`u1',`r15') define(`u2',`r16') define(`u3',`r17')
+define(`v0',`r24') define(`v1',`r25') define(`v2',`r26') define(`v3',`r27')
+define(`w0',`r28') define(`w1',`r29') define(`w2',`r30') define(`w3',`r31')
+define(`rpx',`r3')
+define(`upadv',`r20') define(`vpadv',`r21')
+
+MULFUNC_PROLOGUE(mpn_add_n mpn_add_nc mpn_sub_n mpn_sub_nc)
+
+ASM_START()
+PROLOGUE(func_nc)
+	.prologue
+	.save	ar.lc, r2
+	.body
+ifdef(`HAVE_ABI_32',`
+		addp4	rp = 0, rp		C			M I
+		addp4	up = 0, up		C			M I
+		nop.i	0
+		addp4	vp = 0, vp		C			M I
+		nop.m	0
+		zxt4	n = n			C			I
+	;;
+')
+
+ {.mmi;		ld8	r11 = [vp], 8		C			M01
+		ld8	r10 = [up], 8		C			M01
+		mov	r2 = ar.lc		C			I0
+}{.mmi;		and	r14 = 7, n		C			M I
+		cmp.lt	p15, p14 = 8, n		C			M I
+		add	n = -6, n		C			M I
+	;;
+}{.mmi;		add	upadv = PFDIST, up	C Merging these lines into the feed-in
+		add	vpadv = PFDIST, vp	C code could save a cycle per call at
+		mov	r23 = cy		C the expense of code size.
+	;;
+}{.mmi;		cmp.eq	p6, p0 = 1, r14		C			M I
+		cmp.eq	p7, p0 = 2, r14		C			M I
+		cmp.eq	p8, p0 = 3, r14		C			M I
+}{.bbb;	(p6)	br.dptk	.Lc001			C			B
+	(p7)	br.dptk	.Lc010			C			B
+	(p8)	br.dptk	.Lc011			C			B
+	;;
+}{.mmi;		cmp.eq	p9, p0 = 4, r14		C			M I
+		cmp.eq	p10, p0 = 5, r14	C			M I
+		cmp.eq	p11, p0 = 6, r14	C			M I
+}{.bbb;	(p9)	br.dptk	.Lc100			C			B
+	(p10)	br.dptk	.Lc101			C			B
+	(p11)	br.dptk	.Lc110			C			B
+	;;
+}{.mmi;		ld8	r19 = [vp], 8		C			M01
+		ld8	r18 = [up], 8		C			M01
+		cmp.ne	p13, p0 = 0, cy		C copy cy to p13	M I
+}{.mmb;		cmp.eq	p12, p0 = 7, r14	C			M I
+		nop	0
+	(p12)	br.dptk	.Lc111			C			B
+	;;
+}
+
+.Lc000:
+ {.mmi;		ld8	v3 = [vp], 8		C			M01
+		ld8	u3 = [up], 8		C			M01
+		shr.u	n = n, 3		C			I0
+	;;
+}{.mmi;		add	vpadv = PFDIST, vp	C			M I
+		ld8	v0 = [vp], 8		C			M01
+		mov	ar.lc = n		C			I0
+}{.mmi;		ld8	u0 = [up], 8		C			M01
+		ADDSUB	w1 = r10, r11		C			M I
+		nop	0
+	;;
+}{.mmi;		add	upadv = PFDIST, up	C			M I
+		ld8	v1 = [vp], 8		C			M01
+		cmp.CND	p7, p0 = w1, r10	C			M I
+}{.mmi;		ld8	u1 = [up], 8		C			M01
+		ADDSUB	w2 = r18, r19		C			M I
+		add	rpx = 8, rp		C			M I
+	;;
+}{.mmi;		ld8	v2 = [vp], 8		C			M01
+		cmp.CND	p8, p0 = w2, r18	C			M I
+	(p13)	cmpeqor	p7, p0 = LIM, w1	C			M I
+}{.mmi;		ld8	u2 = [up], 8		C			M01
+	(p13)	add	w1 = INCR, w1		C			M I
+		ADDSUB	w3 = u3, v3		C			M I
+	;;
+}{.mmi;		ld8	v3 = [vp], 8		C			M01
+		cmp.CND	p9, p0 = w3, u3		C			M I
+	(p7)	cmpeqor	p8, p0 = LIM, w2	C			M I
+}{.mmb;		ld8	u3 = [up], 8		C			M01
+	(p7)	add	w2 = INCR, w2		C			M I
+		br	L(m0)
+}
+
+.Lc001:
+ {.mmi;	(p15)	ld8	v1 = [vp], 8		C			M01
+	(p15)	ld8	u1 = [up], 8		C			M01
+		ADDSUB	w0 = r10, r11		C			M I
+}{.mmb;		nop	0
+		nop	0
+	(p15)	br	L(0)
+	;;
+}{.mmi;		cmp.ne	p9, p0 = 0, r23		C			M I
+		mov	r8 = 0
+		cmp.CND	p6, p0 = w0, r10	C			M I
+	;;
+}{.mmb;	(p9)	cmpeqor	p6, p0 = LIM, w0	C			M I
+	(p9)	add	w0 = INCR, w0		C			M I
+		br	L(cj1)			C			B
+}
+L(0):
+ {.mmi;		ld8	v2 = [vp], 8		C			M01
+		ld8	u2 = [up], 8		C			M01
+		shr.u	n = n, 3		C			I0
+	;;
+}{.mmi;		ld8	v3 = [vp], 8		C			M01
+		ld8	u3 = [up], 8		C			M01
+		mov	ar.lc = n		C			I0
+}{.mmi;		nop	0
+		cmp.ne	p9, p0 = 0, r23		C			M I
+		nop	0
+	;;
+}{.mmi;		ld8	v0 = [vp], 8		C			M01
+		cmp.CND	p6, p0 = w0, r10	C			M I
+		add	rpx = 16, rp		C			M I
+}{.mmb;		ld8	u0 = [up], 8		C			M01
+		ADDSUB	w1 = u1, v1		C			M I
+		br	L(c1)			C			B
+}
+
+.Lc010:
+ {.mmi;		ld8	v0 = [vp], 8		C			M01
+		ld8	u0 = [up], 8		C			M01
+		mov	r8 = 0			C			M I
+}{.mmb;		ADDSUB	w3 = r10, r11		C			M I
+		cmp.ne	p8, p0 = 0, r23		C			M I
+	(p15)	br	L(1)			C			B
+	;;
+}{.mmi;		cmp.CND	p9, p0 = w3, r10	C			M I
+		ADDSUB	w0 = u0, v0		C			M I
+	(p8)	add	w3 = INCR, w3		C			M I
+	;;
+}{.mmb;		cmp.CND	p6, p0 = w0, u0		C			M I
+	(p8)	cmpeqor	p9, p0 = LIM2, w3	C			M I
+		br	L(cj2)			C			B
+}
+L(1):
+ {.mmi;		ld8	v1 = [vp], 8		C			M01
+		ld8	u1 = [up], 8		C			M01
+		shr.u	n = n, 3		C			I0
+	;;
+}{.mmi;		ld8	v2 = [vp], 8		C			M01
+		ld8	u2 = [up], 8		C			M01
+		mov	ar.lc = n		C			I0
+	;;
+}{.mmi;		ld8	v3 = [vp], 8		C			M01
+		ld8	u3 = [up], 8		C			M01
+		cmp.CND	p9, p0 = w3, r10	C			M I
+	;;
+}{.mmi;	(p8)	cmpeqor	p9, p0 = LIM, w3	C			M I
+	(p8)	add	w3 = INCR, w3		C			M I
+		ADDSUB	w0 = u0, v0		C			M I
+}{.mmb;		add	rpx = 24, rp		C			M I
+		nop	0
+		br	L(m23)			C			B
+}
+
+.Lc011:
+ {.mmi;		ld8	v3 = [vp], 8		C			M01
+		ld8	u3 = [up], 8		C			M01
+		shr.u	n = n, 3		C			I0
+}{.mmi;		ADDSUB	w2 = r10, r11		C			M I
+		cmp.ne	p7, p0 = 0, r23		C			M I
+		nop	0
+	;;
+}{.mmb;		ld8	v0 = [vp], 8		C			M01
+		ld8	u0 = [up], 8		C			M01
+	(p15)	br	L(2)			C			B
+}{.mmi;		cmp.CND	p8, p0 = w2, r10	C			M I
+		ADDSUB	w3 = u3, v3		C			M I
+		nop	0
+	;;
+}{.mmb;	(p7)	cmpeqor	p8, p0 = LIM, w2	C			M I
+	(p7)	add	w2 = INCR, w2		C			M I
+		br	L(cj3)			C			B
+}
+L(2):
+ {.mmi;		ld8	v1 = [vp], 8		C			M01
+		ld8	u1 = [up], 8		C			M01
+		ADDSUB	w3 = u3, v3		C			M I
+	;;
+}{.mmi;		ld8	v2 = [vp], 8		C			M01
+		ld8	u2 = [up], 8		C			M01
+		cmp.CND	p8, p0 = w2, r10	C			M I
+	;;
+}{.mmi;		ld8	v3 = [vp], 8		C			M01
+		cmp.CND	p9, p0 = w3, u3		C			M I
+		mov	ar.lc = n		C			I0
+}{.mmi;		ld8	u3 = [up], 8		C			M01
+	(p7)	cmpeqor	p8, p0 = LIM, w2	C			M I
+	(p7)	add	w2 = INCR, w2		C			M I
+	;;
+}{.mmi;		add	rpx = 32, rp		C			M I
+		st8	[rp] = w2, 8		C			M23
+	(p8)	cmpeqor	p9, p0 = LIM, w3	C			M I
+}{.mmb;	(p8)	add	w3 = INCR, w3		C			M I
+		ADDSUB	w0 = u0, v0		C			M I
+		br	L(m23)
+}
+
+.Lc100:
+ {.mmi;		ld8	v2 = [vp], 8		C			M01
+		ld8	u2 = [up], 8		C			M01
+		shr.u	n = n, 3		C			I0
+}{.mmi;		ADDSUB	w1 = r10, r11		C			M I
+		nop	0
+		nop	0
+	;;
+}{.mmi;		ld8	v3 = [vp], 8		C			M01
+		ld8	u3 = [up], 8		C			M01
+		add	rpx = 8, rp		C			M I
+}{.mmi;		cmp.ne	p6, p0 = 0, r23		C			M I
+		cmp.CND	p7, p0 = w1, r10	C			M I
+		nop	0
+	;;
+}{.mmi;		ld8	v0 = [vp], 8		C			M01
+		ld8	u0 = [up], 8		C			M01
+		ADDSUB	w2 = u2, v2		C			M I
+}{.mmb;	(p6)	cmpeqor	p7, p0 = LIM, w1	C			M I
+	(p6)	add	w1 = INCR, w1		C			M I
+	(p14)	br	L(cj4)
+	;;
+}{.mmi;		ld8	v1 = [vp], 8		C			M01
+		ld8	u1 = [up], 8		C			M01
+		mov	ar.lc = n		C			I0
+	;;
+}{.mmi;		ld8	v2 = [vp], 8		C			M01
+		cmp.CND	p8, p0 = w2, u2		C			M I
+		nop	0
+}{.mmi;		ld8	u2 = [up], 8		C			M01
+		nop	0
+		ADDSUB	w3 = u3, v3		C			M I
+	;;
+}{.mmi;		ld8	v3 = [vp], 8		C			M01
+		cmp.CND	p9, p0 = w3, u3		C			M I
+	(p7)	cmpeqor	p8, p0 = LIM, w2	C			M I
+}{.mmb;		ld8	u3 = [up], 8		C			M01
+	(p7)	add	w2 = INCR, w2		C			M I
+		br	L(m4)
+}
+
+.Lc101:
+ {.mmi;		ld8	v1 = [vp], 8		C			M01
+		ld8	u1 = [up], 8		C			M01
+		shr.u	n = n, 3		C			I0
+	;;
+}{.mmi;		ld8	v2 = [vp], 8		C			M01
+		ld8	u2 = [up], 8		C			M01
+		mov	ar.lc = n		C			I0
+	;;
+}{.mmi;		ld8	v3 = [vp], 8		C			M01
+		ld8	u3 = [up], 8		C			M01
+		ADDSUB	w0 = r10, r11		C			M I
+}{.mmi;		cmp.ne	p9, p0 = 0, r23		C			M I
+		add	rpx = 16, rp		C			M I
+		nop	0
+	;;
+}{.mmi;		ld8	v0 = [vp], 8		C			M01
+		ld8	u0 = [up], 8		C			M01
+		cmp.CND	p6, p0 = w0, r10	C			M I
+}{.mbb;		ADDSUB	w1 = u1, v1		C			M I
+	(p15)	br	L(c5)			C			B
+		br	L(end)			C			B
+}
+
+.Lc110:
+ {.mmi;		ld8	v0 = [vp], 8		C			M01
+		ld8	u0 = [up], 8		C			M01
+		shr.u	n = n, 3		C			I0
+	;;
+}{.mmi;		add	upadv = PFDIST, up	C			M I
+		add	vpadv = PFDIST, vp	C			M I
+		mov	ar.lc = n		C			I0
+}{.mmi;		ld8	v1 = [vp], 8		C			M01
+		ld8	u1 = [up], 8		C			M01
+		ADDSUB	w3 = r10, r11		C			M I
+	;;
+}{.mmi;		ld8	v2 = [vp], 8		C			M01
+		ld8	u2 = [up], 8		C			M01
+		ADDSUB	w0 = u0, v0		C			M I
+}{.mmi;		cmp.CND	p9, p0 = w3, r10	C			M I
+		cmp.ne	p8, p0 = 0, r23		C			M I
+		add	rpx = 24, rp		C			M I
+	;;
+}{.mmi;		ld8	v3 = [vp], 8		C			M01
+		ld8	u3 = [up], 8		C			M01
+		nop	0
+}{.mmb;	(p8)	cmpeqor	p9, p0 = LIM, w3	C			M I
+	(p8)	add	w3 = INCR, w3		C			M I
+		br	L(m67)			C			B
+}
+
+.Lc111:
+ {.mmi;		ld8	v0 = [vp], 8		C			M01
+		ld8	u0 = [up], 8		C			M01
+		shr.u	n = n, 3		C			I0
+	;;
+}{.mmi;		add	upadv = PFDIST, up	C			M I
+		ld8	v1 = [vp], 8		C			M01
+		mov	ar.lc = n		C			I0
+}{.mmi;		ld8	u1 = [up], 8		C			M01
+		ADDSUB	w2 = r10, r11		C			M I
+		nop	0
+	;;
+}{.mmi;		add	vpadv = PFDIST, vp	C			M I
+		ld8	v2 = [vp], 8		C			M01
+		cmp.CND	p8, p0 = w2, r10	C			M I
+}{.mmi;		ld8	u2 = [up], 8		C			M01
+		ADDSUB	w3 = r18, r19		C			M I
+		nop	0
+	;;
+}{.mmi;		ld8	v3 = [vp], 8		C			M01
+		cmp.CND	p9, p0 = w3, r18	C			M I
+	(p13)	cmpeqor	p8, p0 = LIM, w2	C			M I
+}{.mmi;		ld8	u3 = [up], 8		C			M01
+	(p13)	add	w2 = INCR, w2		C			M I
+		nop	0
+	;;
+}{.mmi;		add	rpx = 32, rp		C			M I
+		st8	[rp] = w2, 8		C			M23
+	(p8)	cmpeqor	p9, p0 = LIM, w3	C			M I
+}{.mmb;	(p8)	add	w3 = INCR, w3		C			M I
+		ADDSUB	w0 = u0, v0		C			M I
+		br	L(m67)
+}
+EPILOGUE()
+
+PROLOGUE(func)
+	.prologue
+	.save	ar.lc, r2
+	.body
+ifdef(`HAVE_ABI_32',`
+		addp4	rp = 0, rp		C			M I
+		addp4	up = 0, up		C			M I
+		nop.i	0
+		addp4	vp = 0, vp		C			M I
+		nop.m	0
+		zxt4	n = n			C			I
+	;;
+')
+
+ {.mmi;		ld8	r11 = [vp], 8		C			M01
+		ld8	r10 = [up], 8		C			M01
+		mov	r2 = ar.lc		C			I0
+}{.mmi;		and	r14 = 7, n		C			M I
+		cmp.lt	p15, p14 = 8, n		C			M I
+		add	n = -6, n		C			M I
+	;;
+}{.mmi;		cmp.eq	p6, p0 = 1, r14		C			M I
+		cmp.eq	p7, p0 = 2, r14		C			M I
+		cmp.eq	p8, p0 = 3, r14		C			M I
+}{.bbb;	(p6)	br.dptk	.Lb001			C			B
+	(p7)	br.dptk	.Lb010			C			B
+	(p8)	br.dptk	.Lb011			C			B
+	;;
+}{.mmi;		cmp.eq	p9, p0 = 4, r14		C			M I
+		cmp.eq	p10, p0 = 5, r14	C			M I
+		cmp.eq	p11, p0 = 6, r14	C			M I
+}{.bbb;	(p9)	br.dptk	.Lb100			C			B
+	(p10)	br.dptk	.Lb101			C			B
+	(p11)	br.dptk	.Lb110			C			B
+	;;
+}{.mmi;		ld8	r19 = [vp], 8		C			M01
+		ld8	r18 = [up], 8		C			M01
+		cmp.ne	p13, p0 = r0, r0	C clear "CF"		M I
+}{.mmb;		cmp.eq	p12, p0 = 7, r14	C			M I
+		mov	r23 = 0			C			M I
+	(p12)	br.dptk	.Lb111			C			B
+	;;
+}
+
+.Lb000:
+ {.mmi;		ld8	v3 = [vp], 8		C			M01
+		ld8	u3 = [up], 8		C			M01
+		shr.u	n = n, 3		C			I0
+	;;
+}{.mmi;		ld8	v0 = [vp], 8		C			M01
+		ld8	u0 = [up], 8		C			M01
+		ADDSUB	w1 = r10, r11		C			M I
+	;;
+}{.mmi;		ld8	v1 = [vp], 8		C			M01
+		cmp.CND	p7, p0 = w1, r10	C			M I
+		mov	ar.lc = n		C			I0
+}{.mmi;		ld8	u1 = [up], 8		C			M01
+		ADDSUB	w2 = r18, r19		C			M I
+		add	rpx = 8, rp		C			M I
+	;;
+}{.mmi;		add	upadv = PFDIST, up
+		add	vpadv = PFDIST, vp
+		cmp.CND	p8, p0 = w2, r18	C			M I
+}{.mmi;		ld8	v2 = [vp], 8		C			M01
+		ld8	u2 = [up], 8		C			M01
+		ADDSUB	w3 = u3, v3		C			M I
+	;;
+}{.mmi;		ld8	v3 = [vp], 8		C			M01
+		cmp.CND	p9, p0 = w3, u3		C			M I
+	(p7)	cmpeqor	p8, p0 = LIM, w2	C			M I
+}{.mmb;		ld8	u3 = [up], 8		C			M01
+	(p7)	add	w2 = INCR, w2		C			M I
+		br	L(m0)			C			B
+}
+
+	ALIGN(32)
+.Lb001:
+ {.mmi;		ADDSUB	w0 = r10, r11		C			M I
+	(p15)	ld8	v1 = [vp], 8		C			M01
+		mov	r8 = 0			C			M I
+	;;
+}{.mmb;		cmp.CND	p6, p0 = w0, r10	C			M I
+	(p15)	ld8	u1 = [up], 8		C			M01
+	(p14)	br	L(cj1)			C			B
+	;;
+}{.mmi;		add	upadv = PFDIST, up
+		add	vpadv = PFDIST, vp
+		shr.u	n = n, 3		C			I0
+}{.mmi;		ld8	v2 = [vp], 8		C			M01
+		ld8	u2 = [up], 8		C			M01
+		cmp.CND	p6, p0 = w0, r10	C			M I
+	;;
+}{.mmi;		ld8	v3 = [vp], 8		C			M01
+		ld8	u3 = [up], 8		C			M01
+		mov	ar.lc = n		C			I0
+	;;
+}{.mmi;		ld8	v0 = [vp], 8		C			M01
+		ld8	u0 = [up], 8		C			M01
+		ADDSUB	w1 = u1, v1		C			M I
+	;;
+}{.mmi;		ld8	v1 = [vp], 8		C			M01
+		cmp.CND	p7, p0 = w1, u1		C			M I
+		ADDSUB	w2 = u2, v2		C			M I
+}{.mmb;		ld8	u1 = [up], 8		C			M01
+		add	rpx = 16, rp		C			M I
+		br	L(m1)			C			B
+}
+
+	ALIGN(32)
+.Lb010:
+ {.mmi;		ld8	v0 = [vp], 8		C			M01
+		ld8	u0 = [up], 8		C			M01
+		shr.u	n = n, 3		C			I0
+}{.mmb;		ADDSUB	w3 = r10, r11		C			M I
+		nop	0
+	(p15)	br	L(gt2)			C			B
+	;;
+}{.mmi;		cmp.CND	p9, p0 = w3, r10	C			M I
+		ADDSUB	w0 = u0, v0		C			M I
+		mov	r8 = 0			C			M I
+	;;
+}{.mmb;		nop	0
+		cmp.CND	p6, p0 = w0, u0		C			M I
+		br	L(cj2)			C			B
+}
+L(gt2):
+ {.mmi;		ld8	v1 = [vp], 8		C			M01
+		ld8	u1 = [up], 8		C			M01
+		nop	0
+	;;
+}{.mmi;		add	upadv = PFDIST, up
+		add	vpadv = PFDIST, vp
+		mov	ar.lc = n		C			I0
+}{.mmi;		ld8	v2 = [vp], 8		C			M01
+		ld8	u2 = [up], 8		C			M01
+		nop	0
+	;;
+}{.mmi;		ld8	v3 = [vp], 8		C			M01
+		cmp.CND	p9, p0 = w3, r10	C			M I
+		ADDSUB	w0 = u0, v0		C			M I
+}{.mmb;		ld8	u3 = [up], 8		C			M01
+		add	rpx = 24, rp		C			M I
+		br	L(m23)			C			B
+}
+
+	ALIGN(32)
+.Lb011:
+ {.mmi;		ld8	v3 = [vp], 8		C			M01
+		ld8	u3 = [up], 8		C			M01
+		ADDSUB	w2 = r10, r11		C			M I
+	;;
+}{.mmb;		ld8	v0 = [vp], 8		C			M01
+		ld8	u0 = [up], 8		C			M01
+	(p15)	br	L(3)			C			B
+}{.mmb;		cmp.CND	p8, p0 = w2, r10	C			M I
+		ADDSUB	w3 = u3, v3		C			M I
+		br	L(cj3)			C			B
+}
+L(3):
+ {.mmi;		ld8	v1 = [vp], 8		C			M01
+		ld8	u1 = [up], 8		C			M01
+		shr.u	n = n, 3		C			I0
+	;;
+}{.mmi;		add	upadv = PFDIST, up
+		add	vpadv = PFDIST, vp
+		ADDSUB	w3 = u3, v3		C			M I
+}{.mmi;		ld8	v2 = [vp], 8		C			M01
+		ld8	u2 = [up], 8		C			M01
+		cmp.CND	p8, p0 = w2, r10	C			M I
+	;;
+}{.mmi;		ld8	v3 = [vp], 8		C			M01
+		cmp.CND	p9, p0 = w3, u3		C			M I
+		mov	ar.lc = n		C			I0
+}{.mmi;		ld8	u3 = [up], 8		C			M01
+		nop	0
+		nop	0
+	;;
+}{.mmi;		add	rpx = 32, rp		C			M I
+		st8	[rp] = w2, 8		C			M23
+	(p8)	cmpeqor	p9, p0 = LIM, w3	C			M I
+}{.mmb;	(p8)	add	w3 = INCR, w3		C			M I
+		ADDSUB	w0 = u0, v0		C			M I
+		br	L(m23)			C			B
+}
+
+	ALIGN(32)
+.Lb100:
+ {.mmi;		ld8	v2 = [vp], 8		C			M01
+		ld8	u2 = [up], 8		C			M01
+		shr.u	n = n, 3		C			I0
+	;;
+}{.mmi;		ld8	v3 = [vp], 8		C			M01
+		ld8	u3 = [up], 8		C			M01
+		ADDSUB	w1 = r10, r11		C			M I
+	;;
+}{.mmi;		ld8	v0 = [vp], 8		C			M01
+		ld8	u0 = [up], 8		C			M01
+		cmp.CND	p7, p0 = w1, r10	C			M I
+}{.mmb;		nop	0
+		ADDSUB	w2 = u2, v2		C			M I
+	(p14)	br	L(cj4)			C			B
+	;;
+}
+L(gt4):
+ {.mmi;		add	upadv = PFDIST, up
+		add	vpadv = PFDIST, vp
+		mov	ar.lc = n		C			I0
+}{.mmi;		ld8	v1 = [vp], 8		C			M01
+		ld8	u1 = [up], 8		C			M01
+		nop	0
+	;;
+}{.mmi;		ld8	v2 = [vp], 8		C			M01
+		cmp.CND	p8, p0 = w2, u2		C			M I
+		nop	0
+}{.mmi;		ld8	u2 = [up], 8		C			M01
+		ADDSUB	w3 = u3, v3		C			M I
+		add	rpx = 8, rp		C			M I
+	;;
+}{.mmi;		ld8	v3 = [vp], 8		C			M01
+		cmp.CND	p9, p0 = w3, u3		C			M I
+	(p7)	cmpeqor	p8, p0 = LIM, w2	C			M I
+}{.mmb;		ld8	u3 = [up], 8		C			M01
+	(p7)	add	w2 = INCR, w2		C			M I
+		br	L(m4)			C			B
+}
+
+	ALIGN(32)
+.Lb101:
+ {.mmi;		ld8	v1 = [vp], 8		C			M01
+		ld8	u1 = [up], 8		C			M01
+		shr.u	n = n, 3		C			I0
+	;;
+}{.mmi;		ld8	v2 = [vp], 8		C			M01
+		ld8	u2 = [up], 8		C			M01
+		ADDSUB	w0 = r10, r11		C			M I
+	;;
+}{.mmi;		add	upadv = PFDIST, up
+		add	vpadv = PFDIST, vp
+		add	rpx = 16, rp		C			M I
+}{.mmi;		ld8	v3 = [vp], 8		C			M01
+		ld8	u3 = [up], 8		C			M01
+		nop	0
+	;;
+}{.mmi;		ld8	v0 = [vp], 8		C			M01
+		cmp.CND	p6, p0 = w0, r10	C			M I
+		nop	0
+}{.mmb;		ld8	u0 = [up], 8		C			M01
+		ADDSUB	w1 = u1, v1		C			M I
+	(p14)	br	L(cj5)			C			B
+	;;
+}
+L(gt5):
+ {.mmi;		ld8	v1 = [vp], 8		C			M01
+		cmp.CND	p7, p0 = w1, u1		C			M I
+		mov	ar.lc = n		C			I0
+}{.mmb;		ld8	u1 = [up], 8		C			M01
+		ADDSUB	w2 = u2, v2		C			M I
+		br	L(m5)			C			B
+}
+
+	ALIGN(32)
+.Lb110:
+ {.mmi;		ld8	v0 = [vp], 8		C			M01
+		ld8	u0 = [up], 8		C			M01
+		shr.u	n = n, 3		C			I0
+	;;
+}{.mmi;		ld8	v1 = [vp], 8		C			M01
+		ld8	u1 = [up], 8		C			M01
+		ADDSUB	w3 = r10, r11		C			M I
+	;;
+}{.mmi;		add	upadv = PFDIST, up
+		add	vpadv = PFDIST, vp
+		mov	ar.lc = n		C			I0
+}{.mmi;		ld8	v2 = [vp], 8		C			M01
+		ld8	u2 = [up], 8		C			M01
+		nop	0
+	;;
+}{.mmi;		ld8	v3 = [vp], 8		C			M01
+		cmp.CND	p9, p0 = w3, r10	C			M I
+		ADDSUB	w0 = u0, v0		C			M I
+}{.mmb;		ld8	u3 = [up], 8		C			M01
+		add	rpx = 24, rp		C			M I
+		br	L(m67)			C			B
+}
+
+	ALIGN(32)
+.Lb111:
+ {.mmi;		ld8	v0 = [vp], 8		C			M01
+		ld8	u0 = [up], 8		C			M01
+		shr.u	n = n, 3		C			I0
+	;;
+}{.mmi;		ld8	v1 = [vp], 8		C			M01
+		ld8	u1 = [up], 8		C			M01
+		ADDSUB	w2 = r10, r11		C			M I
+	;;
+}{.mmi;		ld8	v2 = [vp], 8		C			M01
+		cmp.CND	p8, p0 = w2, r10	C			M I
+		mov	ar.lc = n		C			I0
+}{.mmi;		ld8	u2 = [up], 8		C			M01
+		ADDSUB	w3 = r18, r19		C			M I
+		nop	0
+	;;
+}{.mmi;		add	upadv = PFDIST, up
+		add	vpadv = PFDIST, vp
+		nop	0
+}{.mmi;		ld8	v3 = [vp], 8		C			M01
+		ld8	u3 = [up], 8		C			M01
+		cmp.CND	p9, p0 = w3, r18	C			M I
+	;;
+}{.mmi;		add	rpx = 32, rp		C			M I
+		st8	[rp] = w2, 8		C			M23
+	(p8)	cmpeqor	p9, p0 = LIM, w3	C			M I
+}{.mmb;	(p8)	add	w3 = INCR, w3		C			M I
+		ADDSUB	w0 = u0, v0		C			M I
+		br	L(m67)			C			B
+}
+
+C *** MAIN LOOP START ***
+	ALIGN(32)
+L(top):
+L(c5):		ld8	v1 = [vp], 8		C			M01
+		cmp.CND	p7, p0 = w1, u1		C			M I
+	(p9)	cmpeqor	p6, p0 = LIM, w0	C			M I
+		ld8	u1 = [up], 8		C			M01
+	(p9)	add	w0 = INCR, w0		C			M I
+		ADDSUB	w2 = u2, v2		C			M I
+	;;
+L(m5):		ld8	v2 = [vp], 8		C			M01
+		cmp.CND	p8, p0 = w2, u2		C			M I
+	(p6)	cmpeqor	p7, p0 = LIM, w1	C			M I
+		ld8	u2 = [up], 8		C			M01
+	(p6)	add	w1 = INCR, w1		C			M I
+		ADDSUB	w3 = u3, v3		C			M I
+	;;
+		st8	[rp] = w0, 8		C			M23
+		ld8	v3 = [vp], 8		C			M01
+		cmp.CND	p9, p0 = w3, u3		C			M I
+	(p7)	cmpeqor	p8, p0 = LIM, w2	C			M I
+		ld8	u3 = [up], 8		C			M01
+	(p7)	add	w2 = INCR, w2		C			M I
+	;;
+L(m4):		st8	[rp] = w1, 16		C			M23
+		st8	[rpx] = w2, 32		C			M23
+	(p8)	cmpeqor	p9, p0 = LIM, w3	C			M I
+		lfetch	[upadv], 64
+	(p8)	add	w3 = INCR, w3		C			M I
+		ADDSUB	w0 = u0, v0		C			M I
+	;;
+L(m23):		st8	[rp] = w3, 8		C			M23
+		ld8	v0 = [vp], 8		C			M01
+		cmp.CND	p6, p0 = w0, u0		C			M I
+		ld8	u0 = [up], 8		C			M01
+		ADDSUB	w1 = u1, v1		C			M I
+		nop.b	0
+	;;
+L(c1):		ld8	v1 = [vp], 8		C			M01
+		cmp.CND	p7, p0 = w1, u1		C			M I
+	(p9)	cmpeqor	p6, p0 = LIM, w0	C			M I
+		ld8	u1 = [up], 8		C			M01
+	(p9)	add	w0 = INCR, w0		C			M I
+		ADDSUB	w2 = u2, v2		C			M I
+	;;
+L(m1):		ld8	v2 = [vp], 8		C			M01
+		cmp.CND	p8, p0 = w2, u2		C			M I
+	(p6)	cmpeqor	p7, p0 = LIM, w1	C			M I
+		ld8	u2 = [up], 8		C			M01
+	(p6)	add	w1 = INCR, w1		C			M I
+		ADDSUB	w3 = u3, v3		C			M I
+	;;
+		st8	[rp] = w0, 8		C			M23
+		ld8	v3 = [vp], 8		C			M01
+		cmp.CND	p9, p0 = w3, u3		C			M I
+	(p7)	cmpeqor	p8, p0 = LIM, w2	C			M I
+		ld8	u3 = [up], 8		C			M01
+	(p7)	add	w2 = INCR, w2		C			M I
+	;;
+L(m0):		st8	[rp] = w1, 16		C			M23
+		st8	[rpx] = w2, 32		C			M23
+	(p8)	cmpeqor	p9, p0 = LIM, w3	C			M I
+		lfetch	[vpadv], 64
+	(p8)	add	w3 = INCR, w3		C			M I
+		ADDSUB	w0 = u0, v0		C			M I
+	;;
+L(m67):		st8	[rp] = w3, 8		C			M23
+		ld8	v0 = [vp], 8		C			M01
+		cmp.CND	p6, p0 = w0, u0		C			M I
+		ld8	u0 = [up], 8		C			M01
+		ADDSUB	w1 = u1, v1		C			M I
+		br.cloop.dptk	L(top)		C			B
+	;;
+C *** MAIN LOOP END ***
+
+L(end):
+ {.mmi;	(p9)	cmpeqor	p6, p0 = LIM, w0	C			M I
+	(p9)	add	w0 = INCR, w0		C			M I
+		mov	ar.lc = r2		C			I0
+}
+L(cj5):
+ {.mmi;		cmp.CND	p7, p0 = w1, u1		C			M I
+		ADDSUB	w2 = u2, v2		C			M I
+		nop	0
+	;;
+}{.mmi;		st8	[rp] = w0, 8		C			M23
+	(p6)	cmpeqor	p7, p0 = LIM, w1	C			M I
+	(p6)	add	w1 = INCR, w1		C			M I
+}
+L(cj4):
+ {.mmi;		cmp.CND	p8, p0 = w2, u2		C			M I
+		ADDSUB	w3 = u3, v3		C			M I
+		nop	0
+	;;
+}{.mmi;		st8	[rp] = w1, 8		C			M23
+	(p7)	cmpeqor	p8, p0 = LIM, w2	C			M I
+	(p7)	add	w2 = INCR, w2		C			M I
+}
+L(cj3):
+ {.mmi;		cmp.CND	p9, p0 = w3, u3		C			M I
+		ADDSUB	w0 = u0, v0		C			M I
+		nop	0
+	;;
+}{.mmi;		st8	[rp] = w2, 8		C			M23
+	(p8)	cmpeqor	p9, p0 = LIM, w3	C			M I
+	(p8)	add	w3 = INCR, w3		C			M I
+}{.mmi;		cmp.CND	p6, p0 = w0, u0		C			M I
+		nop	0
+		mov	r8 = 0			C			M I
+	;;
+}
+L(cj2):
+ {.mmi;		st8	[rp] = w3, 8		C			M23
+	(p9)	cmpeqor	p6, p0 = LIM, w0	C			M I
+	(p9)	add	w0 = INCR, w0		C			M I
+	;;
+}
+L(cj1):
+ {.mmb;		st8	[rp] = w0, 8		C			M23
+	(p6)	mov	r8 = 1			C			M I
+		br.ret.sptk.many b0		C			B
+}
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/ia64/aorsorrlsh1_n.asm b/third_party/gmp/mpn/ia64/aorsorrlsh1_n.asm
new file mode 100644
index 0000000..9b58b9e
--- /dev/null
+++ b/third_party/gmp/mpn/ia64/aorsorrlsh1_n.asm
@@ -0,0 +1,48 @@
+dnl  IA-64 mpn_addlsh1_n, mpn_sublsh1_n, mpn_rsblsh1_n
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2003-2005, 2010, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C           cycles/limb
+C Itanium:      3.0
+C Itanium 2:    1.5
+
+
+define(LSH,		1)
+
+ifdef(`OPERATION_addlsh1_n',`define(`DO_add')')
+ifdef(`OPERATION_sublsh1_n',`define(`DO_sub')')
+ifdef(`OPERATION_rsblsh1_n',`define(`DO_rsb')')
+
+MULFUNC_PROLOGUE(mpn_addlsh1_n mpn_sublsh1_n mpn_rsblsh1_n)
+
+include_mpn(`ia64/aorsorrlshC_n.asm')
diff --git a/third_party/gmp/mpn/ia64/aorsorrlsh2_n.asm b/third_party/gmp/mpn/ia64/aorsorrlsh2_n.asm
new file mode 100644
index 0000000..39b384a
--- /dev/null
+++ b/third_party/gmp/mpn/ia64/aorsorrlsh2_n.asm
@@ -0,0 +1,48 @@
+dnl  IA-64 mpn_addlsh2_n, mpn_sublsh2_n, mpn_rsblsh2_n
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2003-2005, 2010, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C           cycles/limb
+C Itanium:      3.0
+C Itanium 2:    1.5
+
+
+define(LSH,		2)
+
+ifdef(`OPERATION_addlsh2_n',`define(`DO_add')')
+ifdef(`OPERATION_sublsh2_n',`define(`DO_sub')')
+ifdef(`OPERATION_rsblsh2_n',`define(`DO_rsb')')
+
+MULFUNC_PROLOGUE(mpn_addlsh2_n mpn_sublsh2_n mpn_rsblsh2_n)
+
+include_mpn(`ia64/aorsorrlshC_n.asm')
diff --git a/third_party/gmp/mpn/ia64/aorsorrlshC_n.asm b/third_party/gmp/mpn/ia64/aorsorrlshC_n.asm
new file mode 100644
index 0000000..2703ce2
--- /dev/null
+++ b/third_party/gmp/mpn/ia64/aorsorrlshC_n.asm
@@ -0,0 +1,412 @@
+dnl  IA-64 mpn_addlshC_n, mpn_sublshC_n, mpn_rsblshC_n.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2003-2005, 2010, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+C           cycles/limb
+C Itanium:      ?
+C Itanium 2:    1.5
+
+C TODO
+C  * Use shladd in feed-in code (for mpn_addlshC_n).
+C  * Rewrite loop to schedule loads closer to use, since we do prefetch.
+
+C INPUT PARAMETERS
+define(`rp', `r32')
+define(`up', `r33')
+define(`vp', `r34')
+define(`n',  `r35')
+
+ifdef(`DO_add', `
+  define(`ADDSUB',     `add	$1 = $2, $3')
+  define(`CMP',        `cmp.ltu	$1,p0 = $2, $3')
+  define(`INCR',       1)
+  define(`LIM',        -1)
+  define(`func',        mpn_addlsh`'LSH`'_n)')
+ifdef(`DO_sub', `
+  define(`ADDSUB',     `sub	$1 = $2, $3')
+  define(`CMP',        `cmp.gtu	$1,p0 = $2, $3')
+  define(`INCR',       -1)
+  define(`LIM',        0)
+  define(`func',        mpn_sublsh`'LSH`'_n)')
+ifdef(`DO_rsb', `
+  define(`ADDSUB',     `sub	$1 = $3, $2')
+  define(`CMP',        `cmp.gtu	$1,p0 = $2, $4')
+  define(`INCR',       -1)
+  define(`LIM',        0)
+  define(`func',        mpn_rsblsh`'LSH`'_n)')
+
+define(PFDIST, 500)
+
+define(`u0',`r14') define(`u1',`r15') define(`u2',`r16') define(`u3',`r17')
+define(`v0',`r18') define(`v1',`r19') define(`v2',`r20') define(`v3',`r21')
+define(`w0',`r22') define(`w1',`r23') define(`w2',`r24') define(`w3',`r25')
+define(`s0',`r26') define(`s1',`r27') define(`s2',`r28') define(`s3',`r29')
+define(`x0',`r30') define(`x1',`r31') define(`x2',`r3')  define(`x3',`r9')
+
+C r3 r8 r9 r10 r11
+
+ASM_START()
+PROLOGUE(func)
+	.prologue
+	.save	ar.lc, r2
+	.body
+ifdef(`HAVE_ABI_32',`
+	addp4	rp = 0, rp		C			M I
+	addp4	up = 0, up		C			M I
+	nop.i	0
+	addp4	vp = 0, vp		C			M I
+	nop.m	0
+	zxt4	n = n			C			I
+	;;
+')
+ {.mmi;	ld8	r11 = [vp], 8		C			M01
+	ld8	r10 = [up], 8		C			M01
+	mov.i	r2 = ar.lc		C			I0
+}{.mmi;	and	r14 = 3, n		C			M I
+	cmp.lt	p15, p0 = 4, n		C			M I
+	add	n = -5, n		C			M I
+	;;
+}{.mmi;	cmp.eq	p6, p0 = 1, r14		C			M I
+	cmp.eq	p7, p0 = 2, r14		C			M I
+	cmp.eq	p8, p0 = 3, r14		C			M I
+}{.bbb
+  (p6)	br.dptk	.Lb01			C			B
+  (p7)	br.dptk	.Lb10			C			B
+  (p8)	br.dptk	.Lb11			C			B
+}
+
+.Lb00:
+ {.mmi;	ld8	v0 = [vp], 8		C			M01
+	ld8	u0 = [up], 8		C			M01
+	shr.u	n = n, 2		C			I0
+	;;
+}{.mmi;	ld8	v1 = [vp], 8		C			M01
+	ld8	u1 = [up], 8		C			M01
+	shl	x3 = r11, LSH		C			I0
+	;;
+}{.mmi;	ld8	v2 = [vp], 8		C			M01
+	ld8	u2 = [up], 8		C			M01
+	shrp	x0 = v0, r11, 64-LSH	C			I0
+}{.mmb;	ADDSUB(	w3, r10, x3)		C			M I
+	nop	0
+  (p15)	br.dpnt	.grt4			C			B
+	;;
+}{.mii;	CMP(	p7, w3, r10, x3)	C			M II0
+	shrp	x1 = v1, v0, 64-LSH	C			I0
+	ADDSUB(	w0, u0, x0)		C			M I
+	;;
+}{.mii;	CMP(	p8, w0, u0, x0)		C			M I
+	shrp	x2 = v2, v1, 64-LSH	C			I0
+	ADDSUB(	w1, u1, x1)		C			M I
+}{.mmb;	nop	0
+	nop	0
+	br	.Lcj4			C			B
+}
+ALIGN(32)
+.grt4:
+ {.mii;	ld8	v3 = [vp], 8		C			M01
+	shrp	x0 = v0, r11, 64-LSH	C			I0
+	CMP(	p8, w3, r10, x3)	C			M I
+	;;
+}{.mmi;	ld8	u3 = [up], 8		C			M01
+	add	r11 = PFDIST, vp
+	shrp	x1 = v1, v0, 64-LSH	C			I0
+}{.mmi;	ld8	v0 = [vp], 8		C			M01
+	ADDSUB(	w0, u0, x0)		C			M I
+	nop	0
+	;;
+}{.mmi;	CMP(	p6, w0, u0, x0)		C			M I
+	add	r10 = PFDIST, up
+	mov.i	ar.lc = n		C			I0
+}{.mmb;	ADDSUB(	w1, u1, x1)		C			M I
+	ld8	u0 = [up], 8		C			M01
+	br	.LL00			C			B
+}
+
+	ALIGN(32)
+.Lb01:
+ifdef(`DO_add',
+`	shladd	w2 = r11, LSH, r10	C			M I
+	shr.u	r8 = r11, 64-LSH	C retval		I0
+  (p15)	br.dpnt	.grt1			C			B
+	;;
+',`
+	shl	x2 = r11, LSH		C			I0
+  (p15)	br.dpnt	.grt1			C			B
+	;;
+	ADDSUB(	w2, r10, x2)		C			M I
+	shr.u	r8 = r11, 64-LSH	C retval		I0
+	;;
+')
+	CMP(	p6, w2, r10, x2)	C			M I
+	br		.Lcj1
+
+.grt1:	ld8	v3 = [vp], 8		C			M01
+	ld8	u3 = [up], 8		C			M01
+	shr.u	n = n, 2		C			I0
+	;;
+	ld8	v0 = [vp], 8		C			M01
+	ld8	u0 = [up], 8		C			M01
+	mov.i	ar.lc = n		C FIXME swap with next	I0
+ifdef(`DO_add',
+`',`
+	ADDSUB(	w2, r10, x2)
+')
+	;;
+ {.mmi;	ld8	v1 = [vp], 8		C			M01
+	ld8	u1 = [up], 8		C			M01
+	shrp	x3 = v3, r11, 64-LSH	C			I0
+	;;
+}{.mmi;	ld8	v2 = [vp], 8		C			M01
+	ld8	u2 = [up], 8		C			M01
+	shrp	x0 = v0, v3, 64-LSH	C			I0
+}{.mmb;	CMP(	p6, w2, r10, x2)	C			M I
+	ADDSUB(	w3, u3, x3)		C			M I
+	br.cloop.dptk	.grt5		C			B
+	;;
+}{.mmi;	CMP(	p7, w3, u3, x3)		C			M I
+	ADDSUB(	w0, u0, x0)		C			M I
+	shrp	x1 = v1, v0, 64-LSH	C			I0
+}{.mmb;	nop	0
+	nop	0
+	br	.Lcj5			C			B
+}
+.grt5:
+ {.mmi;	add	r10 = PFDIST, up
+	add	r11 = PFDIST, vp
+	shrp	x0 = v0, v3, 64-LSH	C			I0
+}{.mmb;	ld8	v3 = [vp], 8		C			M01
+	CMP(	p8, w3, u3, x3)		C			M I
+	br	.LL01			C			B
+}
+	ALIGN(32)
+.Lb10:
+ {.mmi;	ld8	v2 = [vp], 8		C			M01
+	ld8	u2 = [up], 8		C			M01
+	shl	x1 = r11, LSH		C			I0
+}{.mmb;	nop	0
+	nop	0
+  (p15)	br.dpnt	.grt2			C			B
+	;;
+}{.mmi;	ADDSUB(	w1, r10, x1)		C			M I
+	nop	0
+	shrp	x2 = v2, r11, 64-LSH	C			I0
+	;;
+}{.mmi;	CMP(	p9, w1, r10, x1)	C			M I
+	ADDSUB(	w2, u2, x2)		C			M I
+	shr.u	r8 = v2, 64-LSH		C retval		I0
+	;;
+}{.mmb;	CMP(	p6, w2, u2, x2)		C			M I
+	nop	0
+	br	.Lcj2			C			B
+}
+.grt2:
+ {.mmi;	ld8	v3 = [vp], 8		C			M01
+	ld8	u3 = [up], 8		C			M01
+	shr.u	n = n, 2		C			I0
+	;;
+}{.mmi;	ld8	v0 = [vp], 8		C			M01
+	ld8	u0 = [up], 8		C			M01
+	mov.i	ar.lc = n		C			I0
+}{.mmi;	ADDSUB(	w1, r10, x1)		C			M I
+	nop	0
+	nop	0
+	;;
+}{.mii;	ld8	v1 = [vp], 8		C			M01
+	shrp	x2 = v2, r11, 64-LSH	C			I0
+	CMP(	p8, w1, r10, x1)	C			M I
+	;;
+}{.mmi;	add	r10 = PFDIST, up
+	ld8	u1 = [up], 8		C			M01
+	shrp	x3 = v3, v2, 64-LSH	C			I0
+}{.mmi;	add	r11 = PFDIST, vp
+	ld8	v2 = [vp], 8		C			M01
+	ADDSUB(	w2, u2, x2)		C			M I
+	;;
+}{.mmi;	CMP(	p6, w2, u2, x2)		C			M I
+	ld8	u2 = [up], 8		C			M01
+	shrp	x0 = v0, v3, 64-LSH	C			I0
+}{.mib;	ADDSUB(	w3, u3, x3)		C			M I
+	nop	0
+	br.cloop.dpnt	L(top)		C			B
+}
+	br	L(end)			C			B
+.Lb11:
+ {.mmi;	ld8	v1 = [vp], 8		C			M01
+	ld8	u1 = [up], 8		C			M01
+	shl	x0 = r11, LSH		C			I0
+	;;
+}{.mmi;	ld8	v2 = [vp], 8		C			M01
+	ld8	u2 = [up], 8		C			M01
+	shr.u	n = n, 2		C			I0
+}{.mmb;	nop	0
+	nop	0
+  (p15)	br.dpnt	.grt3			C			B
+	;;
+}{.mii;	nop	0
+	shrp	x1 = v1, r11, 64-LSH	C			I0
+	ADDSUB(	w0, r10, x0)		C			M I
+	;;
+}{.mii;	CMP(	p8, w0, r10, x0)	C			M I
+	shrp	x2 = v2, v1, 64-LSH	C			I0
+	ADDSUB(	w1, u1, x1)		C			M I
+	;;
+}{.mmb;	CMP(	p9, w1, u1, x1)		C			M I
+	ADDSUB(	w2, u2, x2)		C			M I
+	br	.Lcj3			C			B
+}
+.grt3:
+ {.mmi;	ld8	v3 = [vp], 8		C			M01
+	ld8	u3 = [up], 8		C			M01
+	shrp	x1 = v1, r11, 64-LSH	C			I0
+}{.mmi;	ADDSUB(	w0, r10, x0)		C			M I
+	nop	0
+	nop	0
+	;;
+}{.mmi;	ld8	v0 = [vp], 8		C			M01
+	CMP(	p6, w0, r10, x0)	C			M I
+	mov.i	ar.lc = n		C			I0
+}{.mmi;	ld8	u0 = [up], 8		C			M01
+	ADDSUB(	w1, u1, x1)		C			M I
+	nop	0
+	;;
+}{.mmi;	add	r10 = PFDIST, up
+	add	r11 = PFDIST, vp
+	shrp	x2 = v2, v1, 64-LSH	C			I0
+}{.mmb;	ld8	v1 = [vp], 8		C			M01
+	CMP(	p8, w1, u1, x1)		C			M I
+	br	.LL11			C			B
+}
+
+C *** MAIN LOOP START ***
+	ALIGN(32)
+L(top):	st8	[rp] = w1, 8		C			M23
+	lfetch	[r10], 32
+   (p8)	cmpeqor	p6, p0 = LIM, w2	C			M I
+   (p8)	add	w2 = INCR, w2		C			M I
+	ld8	v3 = [vp], 8		C			M01
+	CMP(	p8, w3, u3, x3)		C			M I
+	;;
+.LL01:	ld8	u3 = [up], 8		C			M01
+	shrp	x1 = v1, v0, 64-LSH	C			I0
+   (p6)	cmpeqor	p8, p0 = LIM, w3	C			M I
+   (p6)	add	w3 = INCR, w3		C			M I
+	ld8	v0 = [vp], 8		C			M01
+	ADDSUB(	w0, u0, x0)		C			M I
+	;;
+	st8	[rp] = w2, 8		C			M23
+	CMP(	p6, w0, u0, x0)		C			M I
+	nop.b	0
+	ld8	u0 = [up], 8		C			M01
+	lfetch	[r11], 32
+	ADDSUB(	w1, u1, x1)		C			M I
+	;;
+.LL00:	st8	[rp] = w3, 8		C			M23
+	shrp	x2 = v2, v1, 64-LSH	C			I0
+   (p8)	cmpeqor	p6, p0 = LIM, w0	C			M I
+   (p8)	add	w0 = INCR, w0		C			M I
+	ld8	v1 = [vp], 8		C			M01
+	CMP(	p8, w1, u1, x1)		C			M I
+	;;
+.LL11:	ld8	u1 = [up], 8		C			M01
+	shrp	x3 = v3, v2, 64-LSH	C			I0
+   (p6)	cmpeqor	p8, p0 = LIM, w1	C			M I
+   (p6)	add	w1 = INCR, w1		C			M I
+	ld8	v2 = [vp], 8		C			M01
+	ADDSUB(	w2, u2, x2)		C			M I
+	;;
+ {.mmi;	st8	[rp] = w0, 8		C			M23
+	CMP(	p6, w2, u2, x2)		C			M I
+	shrp	x0 = v0, v3, 64-LSH	C			I0
+}{.mib;
+	ld8	u2 = [up], 8		C			M01
+	ADDSUB(	w3, u3, x3)		C			M I
+	br.cloop.dptk	L(top)		C			B
+	;;
+}
+C *** MAIN LOOP END ***
+
+L(end):
+ {.mmi;	st8	[rp] = w1, 8		C			M23
+   (p8)	cmpeqor	p6, p0 = LIM, w2	C			M I
+	shrp	x1 = v1, v0, 64-LSH	C			I0
+}{.mmi;
+   (p8)	add	w2 = INCR, w2		C			M I
+	CMP(	p7, w3, u3, x3)		C			M I
+	ADDSUB(	w0, u0, x0)		C			M I
+	;;
+}
+.Lcj5:
+ {.mmi;	st8	[rp] = w2, 8		C			M23
+   (p6)	cmpeqor	p7, p0 = LIM, w3	C			M I
+	shrp	x2 = v2, v1, 64-LSH	C			I0
+}{.mmi;
+   (p6)	add	w3 = INCR, w3		C			M I
+	CMP(	p8, w0, u0, x0)		C			M I
+	ADDSUB(	w1, u1, x1)		C			M I
+	;;
+}
+.Lcj4:
+ {.mmi;	st8	[rp] = w3, 8		C			M23
+   (p7)	cmpeqor	p8, p0 = LIM, w0	C			M I
+	mov.i	ar.lc = r2		C			I0
+}{.mmi;
+   (p7)	add	w0 = INCR, w0		C			M I
+	CMP(	p9, w1, u1, x1)		C			M I
+	ADDSUB(	w2, u2, x2)		C			M I
+	;;
+}
+.Lcj3:
+ {.mmi;	st8	[rp] = w0, 8		C			M23
+   (p8)	cmpeqor	p9, p0 = LIM, w1	C			M I
+	shr.u	r8 = v2, 64-LSH		C			I0
+}{.mmi;
+   (p8)	add	w1 = INCR, w1		C			M I
+	CMP(	p6, w2, u2, x2)		C			M I
+	nop	0
+	;;
+}
+.Lcj2:
+ {.mmi;	st8	[rp] = w1, 8		C			M23
+   (p9)	cmpeqor	p6, p0 = LIM, w2	C			M I
+   (p9)	add	w2 = INCR, w2		C			M I
+	;;
+}
+.Lcj1:
+ {.mmb;	st8	[rp] = w2		C			M23
+ifdef(`DO_rsb',`
+   (p6)	add	r8 = -1, r8		C			M I
+',`
+   (p6)	add	r8 = 1, r8		C			M I
+')	br.ret.sptk.many b0		C			B
+}
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/ia64/bdiv_dbm1c.asm b/third_party/gmp/mpn/ia64/bdiv_dbm1c.asm
new file mode 100644
index 0000000..47e4553
--- /dev/null
+++ b/third_party/gmp/mpn/ia64/bdiv_dbm1c.asm
@@ -0,0 +1,516 @@
+dnl  IA-64 mpn_bdiv_dbm1.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2008, 2009 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C         cycles/limb
+C Itanium:    4
+C Itanium 2:  2
+
+C TODO
+C  * Optimize feed-in and wind-down code, both for speed and code size.
+
+C INPUT PARAMETERS
+define(`rp', `r32')
+define(`up', `r33')
+define(`n', `r34')
+define(`bd', `r35')
+
+ASM_START()
+PROLOGUE(mpn_bdiv_dbm1c)
+	.prologue
+	.save		ar.lc, r2
+	.body
+
+ifdef(`HAVE_ABI_32',
+`	addp4		rp = 0, rp		C M I
+	addp4		up = 0, up		C M I
+	zxt4		n = n			C I
+	;;
+')
+{.mmb
+	mov		r15 = r36		C M I
+	ldf8		f9 = [up], 8		C M
+	nop.b		0			C B
+}
+.Lcommon:
+{.mii
+	adds		r16 = -1, n		C M I
+	mov		r2 = ar.lc		C I0
+	and		r14 = 3, n		C M I
+	;;
+}
+{.mii
+	setf.sig	f6 = bd			C M2 M3
+	shr.u		r31 = r16, 2		C I0
+	cmp.eq		p10, p0 = 0, r14	C M I
+}
+{.mii
+	nop.m		0			C M
+	cmp.eq		p11, p0 = 2, r14	C M I
+	cmp.eq		p12, p0 = 3, r14	C M I
+	;;
+}
+{.mii
+	cmp.ne		p6, p7 = r0, r0		C M I
+	mov.i		ar.lc = r31		C I0
+	cmp.ne		p8, p9 = r0, r0		C M I
+}
+{.bbb
+  (p10)	br.dptk		.Lb00			C B
+  (p11)	br.dptk		.Lb10			C B
+  (p12)	br.dptk		.Lb11			C B
+	;;
+}
+
+.Lb01:	br.cloop.dptk	.grt1
+	;;
+	xma.l		f38 = f9, f6, f0
+	xma.hu		f39 = f9, f6, f0
+	;;
+	getf.sig	r26 = f38
+	getf.sig	r27 = f39
+	br		.Lcj1
+
+.grt1:	ldf8		f10 = [r33], 8
+	;;
+	ldf8		f11 = [r33], 8
+	;;
+	ldf8		f12 = [r33], 8
+	;;
+	xma.l		f38 = f9, f6, f0
+	xma.hu		f39 = f9, f6, f0
+	;;
+	ldf8		f13 = [r33], 8
+	;;
+	xma.l		f32 = f10, f6, f0
+	xma.hu		f33 = f10, f6, f0
+	br.cloop.dptk	.grt5
+
+	;;
+	getf.sig	r26 = f38
+	xma.l		f34 = f11, f6, f0
+	xma.hu		f35 = f11, f6, f0
+	;;
+	getf.sig	r27 = f39
+	;;
+	getf.sig	r20 = f32
+	xma.l		f36 = f12, f6, f0
+	xma.hu		f37 = f12, f6, f0
+	;;
+	getf.sig	r21 = f33
+	;;
+	getf.sig	r22 = f34
+	xma.l		f38 = f13, f6, f0
+	xma.hu		f39 = f13, f6, f0
+	br		.Lcj5
+
+.grt5:	ldf8		f10 = [r33], 8
+	;;
+	getf.sig	r26 = f38
+	xma.l		f34 = f11, f6, f0
+	xma.hu		f35 = f11, f6, f0
+	;;
+	getf.sig	r27 = f39
+	ldf8		f11 = [r33], 8
+	;;
+	getf.sig	r20 = f32
+	xma.l		f36 = f12, f6, f0
+	xma.hu		f37 = f12, f6, f0
+	;;
+	getf.sig	r21 = f33
+	ldf8		f12 = [r33], 8
+	;;
+	getf.sig	r22 = f34
+	xma.l		f38 = f13, f6, f0
+	xma.hu		f39 = f13, f6, f0
+	br		.LL01
+
+.Lb10:	ldf8		f13 = [r33], 8
+	br.cloop.dptk	.grt2
+	;;
+
+	xma.l		f36 = f9, f6, f0
+	xma.hu		f37 = f9, f6, f0
+	;;
+	xma.l		f38 = f13, f6, f0
+	xma.hu		f39 = f13, f6, f0
+	;;
+	getf.sig	r24 = f36
+	;;
+	getf.sig	r25 = f37
+	;;
+	getf.sig	r26 = f38
+	;;
+	getf.sig	r27 = f39
+	br		.Lcj2
+
+.grt2:	ldf8		f10 = [r33], 8
+	;;
+	ldf8		f11 = [r33], 8
+	;;
+	xma.l		f36 = f9, f6, f0
+	xma.hu		f37 = f9, f6, f0
+	;;
+	ldf8		f12 = [r33], 8
+	;;
+	xma.l		f38 = f13, f6, f0
+	xma.hu		f39 = f13, f6, f0
+	;;
+	ldf8		f13 = [r33], 8
+	;;
+	getf.sig	r24 = f36
+	xma.l		f32 = f10, f6, f0
+	xma.hu		f33 = f10, f6, f0
+	br.cloop.dptk	.grt6
+
+	getf.sig	r25 = f37
+	;;
+	getf.sig	r26 = f38
+	xma.l		f34 = f11, f6, f0
+	xma.hu		f35 = f11, f6, f0
+	;;
+	getf.sig	r27 = f39
+	;;
+	getf.sig	r20 = f32
+	xma.l		f36 = f12, f6, f0
+	xma.hu		f37 = f12, f6, f0
+	br		.Lcj6
+
+.grt6:	getf.sig	r25 = f37
+	ldf8		f10 = [r33], 8
+	;;
+	getf.sig	r26 = f38
+	xma.l		f34 = f11, f6, f0
+	xma.hu		f35 = f11, f6, f0
+	;;
+	getf.sig	r27 = f39
+	ldf8		f11 = [r33], 8
+	;;
+	getf.sig	r20 = f32
+	xma.l		f36 = f12, f6, f0
+	xma.hu		f37 = f12, f6, f0
+	br		.LL10
+
+
+.Lb11:	ldf8		f12 = [r33], 8
+	;;
+	ldf8		f13 = [r33], 8
+	br.cloop.dptk	.grt3
+	;;
+
+	xma.l		f34 = f9, f6, f0
+	xma.hu		f35 = f9, f6, f0
+	;;
+	xma.l		f36 = f12, f6, f0
+	xma.hu		f37 = f12, f6, f0
+	;;
+	getf.sig	r22 = f34
+	xma.l		f38 = f13, f6, f0
+	xma.hu		f39 = f13, f6, f0
+	;;
+	getf.sig	r23 = f35
+	;;
+	getf.sig	r24 = f36
+	;;
+	getf.sig	r25 = f37
+	;;
+	getf.sig	r26 = f38
+	br		.Lcj3
+
+.grt3:	ldf8		f10 = [r33], 8
+	;;
+	xma.l		f34 = f9, f6, f0
+	xma.hu		f35 = f9, f6, f0
+	;;
+	ldf8		f11 = [r33], 8
+	;;
+	xma.l		f36 = f12, f6, f0
+	xma.hu		f37 = f12, f6, f0
+	;;
+	ldf8		f12 = [r33], 8
+	;;
+	getf.sig	r22 = f34
+	xma.l		f38 = f13, f6, f0
+	xma.hu		f39 = f13, f6, f0
+	;;
+	getf.sig	r23 = f35
+	ldf8		f13 = [r33], 8
+	;;
+	getf.sig	r24 = f36
+	xma.l		f32 = f10, f6, f0
+	xma.hu		f33 = f10, f6, f0
+	br.cloop.dptk	.grt7
+
+	getf.sig	r25 = f37
+	;;
+	getf.sig	r26 = f38
+	xma.l		f34 = f11, f6, f0
+	xma.hu		f35 = f11, f6, f0
+	br		.Lcj7
+
+.grt7:	getf.sig	r25 = f37
+	ldf8		f10 = [r33], 8
+	;;
+	getf.sig	r26 = f38
+	xma.l		f34 = f11, f6, f0
+	xma.hu		f35 = f11, f6, f0
+	br		.LL11
+
+
+.Lb00:	ldf8		f11 = [r33], 8
+	;;
+	ldf8		f12 = [r33], 8
+	;;
+	ldf8		f13 = [r33], 8
+	br.cloop.dptk	.grt4
+	;;
+
+	xma.l		f32 = f9, f6, f0
+	xma.hu		f33 = f9, f6, f0
+	;;
+	xma.l		f34 = f11, f6, f0
+	xma.hu		f35 = f11, f6, f0
+	;;
+	getf.sig	r20 = f32
+	xma.l		f36 = f12, f6, f0
+	xma.hu		f37 = f12, f6, f0
+	;;
+	getf.sig	r21 = f33
+	;;
+	getf.sig	r22 = f34
+	xma.l		f38 = f13, f6, f0
+	xma.hu		f39 = f13, f6, f0
+	;;
+	getf.sig	r23 = f35
+	;;
+	getf.sig	r24 = f36
+	br		.Lcj4
+
+.grt4:	xma.l		f32 = f9, f6, f0
+	xma.hu		f33 = f9, f6, f0
+	;;
+	ldf8		f10 = [r33], 8
+	;;
+	xma.l		f34 = f11, f6, f0
+	xma.hu		f35 = f11, f6, f0
+	;;
+	ldf8		f11 = [r33], 8
+	;;
+	getf.sig	r20 = f32
+	xma.l		f36 = f12, f6, f0
+	xma.hu		f37 = f12, f6, f0
+	;;
+	getf.sig	r21 = f33
+	ldf8		f12 = [r33], 8
+	;;
+	getf.sig	r22 = f34
+	xma.l		f38 = f13, f6, f0
+	xma.hu		f39 = f13, f6, f0
+	;;
+	getf.sig	r23 = f35
+	ldf8		f13 = [r33], 8
+	;;
+	getf.sig	r24 = f36
+	xma.l		f32 = f10, f6, f0
+	xma.hu		f33 = f10, f6, f0
+	br.cloop.dptk	.LL00
+	br		.Lcj8
+
+C *** MAIN LOOP START ***
+	ALIGN(32)
+.Ltop:
+	.pred.rel "mutex",p6,p7
+C	.mfi
+	getf.sig	r24 = f36
+	xma.l		f32 = f10, f6, f0
+  (p6)	sub		r15 = r19, r27, 1
+C	.mfi
+	st8		[r32] = r19, 8
+	xma.hu		f33 = f10, f6, f0
+  (p7)	sub		r15 = r19, r27
+	;;
+.LL00:
+C	.mfi
+	getf.sig	r25 = f37
+	nop.f 0
+	cmp.ltu		p6, p7 = r15, r20
+C	.mib
+	ldf8		f10 = [r33], 8
+	sub		r16 = r15, r20
+	nop.b 0
+	;;
+
+C	.mfi
+	getf.sig	r26 = f38
+	xma.l		f34 = f11, f6, f0
+  (p6)	sub		r15 = r16, r21, 1
+C	.mfi
+	st8		[r32] = r16, 8
+	xma.hu		f35 = f11, f6, f0
+  (p7)	sub		r15 = r16, r21
+	;;
+.LL11:
+C	.mfi
+	getf.sig	r27 = f39
+	nop.f 0
+	cmp.ltu		p6, p7 = r15, r22
+C	.mib
+	ldf8		f11 = [r33], 8
+	sub		r17 = r15, r22
+	nop.b 0
+	;;
+
+C	.mfi
+	getf.sig	r20 = f32
+	xma.l		f36 = f12, f6, f0
+  (p6)	sub		r15 = r17, r23, 1
+C	.mfi
+	st8		[r32] = r17, 8
+	xma.hu		f37 = f12, f6, f0
+  (p7)	sub		r15 = r17, r23
+	;;
+.LL10:
+C	.mfi
+	getf.sig	r21 = f33
+	nop.f 0
+	cmp.ltu		p6, p7 = r15, r24
+C	.mib
+	ldf8		f12 = [r33], 8
+	sub		r18 = r15, r24
+	nop.b 0
+	;;
+
+C	.mfi
+	getf.sig	r22 = f34
+	xma.l		f38 = f13, f6, f0
+  (p6)	sub		r15 = r18, r25, 1
+C	.mfi
+	st8		[r32] = r18, 8
+	xma.hu		f39 = f13, f6, f0
+  (p7)	sub		r15 = r18, r25
+	;;
+.LL01:
+C	.mfi
+	getf.sig	r23 = f35
+	nop.f 0
+	cmp.ltu		p6, p7 = r15, r26
+C	.mib
+	ldf8		f13 = [r33], 8
+	sub		r19 = r15, r26
+	br.cloop.sptk.few .Ltop
+C *** MAIN LOOP END ***
+	;;
+
+	getf.sig	r24 = f36
+	xma.l		f32 = f10, f6, f0
+  (p6)	sub		r15 = r19, r27, 1
+	st8		[r32] = r19, 8
+	xma.hu		f33 = f10, f6, f0
+  (p7)	sub		r15 = r19, r27
+	;;
+.Lcj8:	getf.sig	r25 = f37
+	cmp.ltu		p6, p7 = r15, r20
+	sub		r16 = r15, r20
+	;;
+	getf.sig	r26 = f38
+	xma.l		f34 = f11, f6, f0
+  (p6)	sub		r15 = r16, r21, 1
+	st8		[r32] = r16, 8
+	xma.hu		f35 = f11, f6, f0
+  (p7)	sub		r15 = r16, r21
+	;;
+.Lcj7:	getf.sig	r27 = f39
+	cmp.ltu		p6, p7 = r15, r22
+	sub		r17 = r15, r22
+	;;
+	getf.sig	r20 = f32
+	xma.l		f36 = f12, f6, f0
+  (p6)	sub		r15 = r17, r23, 1
+	st8		[r32] = r17, 8
+	xma.hu		f37 = f12, f6, f0
+  (p7)	sub		r15 = r17, r23
+	;;
+.Lcj6:	getf.sig	r21 = f33
+	cmp.ltu		p6, p7 = r15, r24
+	sub		r18 = r15, r24
+	;;
+	getf.sig	r22 = f34
+	xma.l		f38 = f13, f6, f0
+  (p6)	sub		r15 = r18, r25, 1
+	st8		[r32] = r18, 8
+	xma.hu		f39 = f13, f6, f0
+  (p7)	sub		r15 = r18, r25
+	;;
+.Lcj5:	getf.sig	r23 = f35
+	cmp.ltu		p6, p7 = r15, r26
+	sub		r19 = r15, r26
+	;;
+	getf.sig	r24 = f36
+  (p6)	sub		r15 = r19, r27, 1
+	st8		[r32] = r19, 8
+  (p7)	sub		r15 = r19, r27
+	;;
+.Lcj4:	getf.sig	r25 = f37
+	cmp.ltu		p6, p7 = r15, r20
+	sub		r16 = r15, r20
+	;;
+	getf.sig	r26 = f38
+  (p6)	sub		r15 = r16, r21, 1
+	st8		[r32] = r16, 8
+  (p7)	sub		r15 = r16, r21
+	;;
+.Lcj3:	getf.sig	r27 = f39
+	cmp.ltu		p6, p7 = r15, r22
+	sub		r17 = r15, r22
+	;;
+  (p6)	sub		r15 = r17, r23, 1
+	st8		[r32] = r17, 8
+  (p7)	sub		r15 = r17, r23
+	;;
+.Lcj2:	cmp.ltu		p6, p7 = r15, r24
+	sub		r18 = r15, r24
+	;;
+  (p6)	sub		r15 = r18, r25, 1
+	st8		[r32] = r18, 8
+  (p7)	sub		r15 = r18, r25
+	;;
+.Lcj1:	cmp.ltu		p6, p7 = r15, r26
+	sub		r19 = r15, r26
+	;;
+  (p6)	sub		r8 = r19, r27, 1
+	st8		[r32] = r19
+  (p7)	sub		r8 = r19, r27
+	mov ar.lc = r2
+	br.ret.sptk.many b0
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/ia64/cnd_aors_n.asm b/third_party/gmp/mpn/ia64/cnd_aors_n.asm
new file mode 100644
index 0000000..edd0552
--- /dev/null
+++ b/third_party/gmp/mpn/ia64/cnd_aors_n.asm
@@ -0,0 +1,264 @@
+dnl  IA-64 mpn_cnd_add_n/mpn_cnd_sub_n.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C           cycles/limb
+C Itanium:      ?
+C Itanium 2:    1.5
+
+C INPUT PARAMETERS
+define(`cnd', `r32')
+define(`rp',  `r33')
+define(`up',  `r34')
+define(`vp',  `r35')
+define(`n',   `r36')
+
+ifdef(`OPERATION_cnd_add_n',`
+  define(ADDSUB,	add)
+  define(CND,		ltu)
+  define(INCR,		1)
+  define(LIM,		-1)
+  define(func,    mpn_cnd_add_n)
+')
+ifdef(`OPERATION_cnd_sub_n',`
+  define(ADDSUB,	sub)
+  define(CND,		gtu)
+  define(INCR,		-1)
+  define(LIM,		0)
+  define(func,    mpn_cnd_sub_n)
+')
+
+define(PFDIST, 160)
+
+C Some useful aliases for registers we use
+define(`u0',`r14') define(`u1',`r15') define(`u2',`r16') define(`u3',`r17')
+define(`x0',`r20') define(`x1',`r21') define(`x2',`r22') define(`x3',`r23')
+define(`v0',`r24') define(`v1',`r25') define(`v2',`r26') define(`v3',`r27')
+define(`w0',`r28') define(`w1',`r29') define(`w2',`r30') define(`w3',`r31')
+define(`up1',`up') define(`up2',`r8') define(`upadv',`r1')
+define(`vp1',`vp') define(`vp2',`r9') define(`vpadv',`r11')
+define(`rp1',`rp') define(`rp2',`r10')
+
+MULFUNC_PROLOGUE(mpn_cnd_add_n mpn_cnd_sub_n)
+
+ASM_START()
+PROLOGUE(func)
+	.prologue
+	.save	ar.lc, r2
+	.body
+ifdef(`HAVE_ABI_32',`
+	addp4	rp = 0, rp		C				M I
+	addp4	up = 0, up		C				M I
+	nop.i	0
+	addp4	vp = 0, vp		C				M I
+	nop.m	0
+	zxt4	n = n			C				I
+	;;
+')
+ {.mmi;	and	r3 = 3, n		C				M I
+	add	n = -1, n		C				M I
+	mov	r2 = ar.lc		C				I0
+}{.mmi;	cmp.ne	p6, p7 = 0, cnd		C				M I
+	add	vp2 = 8, vp		C				M I
+	add	up2 = 8, up		C				M I
+	;;
+}{.mmi;	add	upadv = PFDIST, up	C				M I
+	add	vpadv = PFDIST, vp	C				M I
+	shr.u	n = n, 2		C				I0
+	.pred.rel "mutex", p6, p7
+}{.mmi;	add	rp2 = 8, rp		C				M I
+   (p6)	mov	cnd = -1		C				M I
+   (p7)	mov	cnd = 0			C				M I
+	;;
+}	cmp.eq	p9, p0 = 1, r3		C				M I
+	cmp.eq	p7, p0 = 2, r3		C				M I
+	cmp.eq	p8, p0 = 3, r3		C				M I
+   (p9)	br	L(b1)			C				B
+   (p7)	br	L(b2)			C				B
+   (p8)	br	L(b3)			C				B
+	;;
+L(b0):
+ {.mmi;	ld8	v2 = [vp1], 16		C				M01
+	ld8	v3 = [vp2], 16		C				M01
+	mov	ar.lc = n		C				I0
+	;;
+}	ld8	u2 = [up1], 16		C				M01
+	ld8	u3 = [up2], 16		C				M01
+	and	x2 = v2, cnd		C				M I
+	and	x3 = v3, cnd		C				M I
+	;;
+	ADDSUB	w2 = u2, x2		C				M I
+	ADDSUB	w3 = u3, x3		C				M I
+	;;
+	ld8	v0 = [vp1], 16		C				M01
+	ld8	v1 = [vp2], 16		C				M01
+	cmp.CND	p8, p0 = w2, u2		C				M I
+	cmp.CND	p9, p0 = w3, u3		C				M I
+	br	L(lo0)
+
+L(b1):	ld8	v1 = [vp1], 8		C				M01
+	add	vp2 = 8, vp2		C				M I
+	add	rp2 = 8, rp2		C				M I
+	;;
+	ld8	u1 = [up1], 8		C				M01
+	add	up2 = 8, up2		C				M I
+	and	x1 = v1, cnd		C				M I
+	;;
+	ADDSUB	w1 = u1, x1		C				M I
+	cmp.ne	p10, p0 = 0, n
+	add	n = -1, n
+	;;
+	cmp.CND	p7, p0 = w1, u1		C				M I
+	st8	[rp1] = w1, 8		C				M23
+  (p10)	br	L(b0)
+	;;
+	mov	r8 = 0			C				M I
+	br	L(e1)
+
+L(b3):	ld8	v3 = [vp1], 8		C				M01
+	add	vp2 = 8, vp2		C				M I
+	add	rp2 = 8, rp2		C				M I
+	;;
+	ld8	u3 = [up1], 8		C				M01
+	add	up2 = 8, up2		C				M I
+	and	x3 = v3, cnd		C				M I
+	;;
+	ADDSUB	w3 = u3, x3		C				M I
+	;;
+	cmp.CND	p9, p0 = w3, u3		C				M I
+	st8	[rp1] = w3, 8		C				M23
+	C fall through
+
+L(b2):
+ {.mmi;	ld8	v0 = [vp1], 16		C				M01
+	ld8	v1 = [vp2], 16		C				M01
+	mov	ar.lc = n		C				I0
+	;;
+}	ld8	u0 = [up1], 16		C				M01
+	ld8	u1 = [up2], 16		C				M01
+	and	x0 = v0, cnd		C				M I
+	and	x1 = v1, cnd		C				M I
+	;;
+	ADDSUB	w0 = u0, x0		C				M I
+	ADDSUB	w1 = u1, x1		C				M I
+	br.cloop.dptk	L(gt2)		C				B
+	;;
+	cmp.CND	p6, p0 = w0, u0		C				M I
+	br		L(e2)		C				B
+L(gt2):
+	ld8	v2 = [vp1], 16		C				M01
+	ld8	v3 = [vp2], 16		C				M01
+	cmp.CND	p6, p0 = w0, u0		C				M I
+	cmp.CND	p7, p0 = w1, u1		C				M I
+	br		L(lo2)		C				B
+
+
+C *** MAIN LOOP START ***
+C	ALIGN(32)
+L(top):
+ {.mmi;	ld8	v2 = [vp1], 16		C				M01
+	ld8	v3 = [vp2], 16		C				M01
+	cmp.CND	p6, p0 = w0, u0		C				M I
+}{.mmi;	st8	[rp1] = w2, 16		C				M23
+	st8	[rp2] = w3, 16		C				M23
+	cmp.CND	p7, p0 = w1, u1		C				M I
+	;;
+}
+L(lo2):
+ {.mmi;	ld8	u2 = [up1], 16		C				M01
+	ld8	u3 = [up2], 16		C				M01
+   (p9)	cmpeqor	p6, p0 = LIM, w0	C				M I
+}{.mmi;	and	x2 = v2, cnd		C				M I
+	and	x3 = v3, cnd		C				M I
+   (p9)	add	w0 = INCR, w0		C				M I
+	;;
+}{.mmi;	ADDSUB	w2 = u2, x2		C				M I
+   (p6)	cmpeqor	p7, p0 = LIM, w1	C				M I
+   (p6)	add	w1 = INCR, w1		C				M I
+}{.mmi;	ADDSUB	w3 = u3, x3		C				M I
+	lfetch	[upadv], 32
+	nop	0
+	;;
+}{.mmi;	ld8	v0 = [vp1], 16		C				M01
+	ld8	v1 = [vp2], 16		C				M01
+	cmp.CND	p8, p0 = w2, u2		C				M I
+}{.mmi;	st8	[rp1] = w0, 16		C				M23
+	st8	[rp2] = w1, 16		C				M23
+	cmp.CND	p9, p0 = w3, u3		C				M I
+	;;
+}
+L(lo0):
+ {.mmi;	ld8	u0 = [up1], 16		C				M01
+	ld8	u1 = [up2], 16		C				M01
+   (p7)	cmpeqor	p8, p0 = LIM, w2	C				M I
+}{.mmi;	and	x0 = v0, cnd		C				M I
+	and	x1 = v1, cnd		C				M I
+   (p7)	add	w2 = INCR, w2		C				M I
+	;;
+}{.mmi;	ADDSUB	w0 = u0, x0		C				M I
+   (p8)	cmpeqor	p9, p0 = LIM, w3	C				M I
+   (p8)	add	w3 = INCR, w3		C				M I
+}{.mmb;	ADDSUB	w1 = u1, x1		C				M I
+	lfetch	[vpadv], 32
+	br.cloop.dptk	L(top)		C				B
+	;;
+}
+C *** MAIN LOOP END ***
+
+
+L(end):
+ {.mmi;	st8	[rp1] = w2, 16		C				M23
+	st8	[rp2] = w3, 16		C				M23
+	cmp.CND	p6, p0 = w0, u0		C				M I
+	;;
+}
+L(e2):
+ {.mmi;	cmp.CND	p7, p0 = w1, u1		C				M I
+   (p9)	cmpeqor	p6, p0 = LIM, w0	C				M I
+   (p9)	add	w0 = INCR, w0		C				M I
+	;;
+}{.mmi;	mov	r8 = 0			C				M I
+   (p6)	cmpeqor	p7, p0 = LIM, w1	C				M I
+   (p6)	add	w1 = INCR, w1		C				M I
+	;;
+}{.mmi;	st8	[rp1] = w0, 16		C				M23
+	st8	[rp2] = w1, 16		C				M23
+	mov	ar.lc = r2		C				I0
+}
+L(e1):
+ {.mmb;	nop	0
+   (p7)	mov	r8 = 1			C				M I
+	br.ret.sptk.many b0		C				B
+}
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/ia64/copyd.asm b/third_party/gmp/mpn/ia64/copyd.asm
new file mode 100644
index 0000000..b94a1af
--- /dev/null
+++ b/third_party/gmp/mpn/ia64/copyd.asm
@@ -0,0 +1,186 @@
+dnl  IA-64 mpn_copyd -- copy limb vector, decrementing.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2001, 2002, 2004 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C         cycles/limb
+C Itanium:    1
+C Itanium 2:  0.5
+
+C INPUT PARAMETERS
+C rp = r32
+C sp = r33
+C n = r34
+
+ASM_START()
+PROLOGUE(mpn_copyd)
+	.prologue
+	.save ar.lc, r2
+	.body
+ifdef(`HAVE_ABI_32',
+`	addp4		r32 = 0, r32
+	addp4		r33 = 0, r33
+	sxt4		r34 = r34
+	;;
+')
+{.mmi
+	shladd		r32 = r34, 3, r32
+	shladd		r33 = r34, 3, r33
+	mov.i		r2 = ar.lc
+}
+{.mmi
+	and		r14 = 3, r34
+	cmp.ge		p14, p15 = 3, r34
+	add		r34 = -4, r34
+	;;
+}
+{.mmi
+	cmp.eq		p8, p0 = 1, r14
+	cmp.eq		p10, p0 = 2, r14
+	cmp.eq		p12, p0 = 3, r14
+}
+{.bbb
+  (p8)	br.dptk		.Lb01
+  (p10)	br.dptk		.Lb10
+  (p12)	br.dptk		.Lb11
+}
+
+.Lb00:	C  n = 0, 4, 8, 12, ...
+	add		r32 = -8, r32
+	add		r33 = -8, r33
+  (p14)	br.dptk		.Ls00
+	;;
+	add		r21 = -8, r33
+	ld8		r16 = [r33], -16
+	shr		r15 = r34, 2
+	;;
+	ld8		r17 = [r21], -16
+	mov.i		ar.lc = r15
+	ld8		r18 = [r33], -16
+	add		r20 = -8, r32
+	;;
+	ld8		r19 = [r21], -16
+	br.cloop.dptk	.Loop
+	;;
+	br.sptk		.Lend
+	;;
+
+.Lb01:	C  n = 1, 5, 9, 13, ...
+	add		r21 = -8, r33
+	add		r20 = -8, r32
+	add		r33 = -16, r33
+	add		r32 = -16, r32
+	;;
+	ld8		r19 = [r21], -16
+	shr		r15 = r34, 2
+  (p14)	br.dptk		.Ls01
+	;;
+	ld8		r16 = [r33], -16
+	mov.i		ar.lc = r15
+	;;
+	ld8		r17 = [r21], -16
+	ld8		r18 = [r33], -16
+	br.sptk		.Li01
+	;;
+
+.Lb10:	C  n = 2,6, 10, 14, ...
+	add		r21 = -16, r33
+	shr		r15 = r34, 2
+	add		r20 = -16, r32
+	add		r32 = -8, r32
+	add		r33 = -8, r33
+	;;
+	ld8		r18 = [r33], -16
+	ld8		r19 = [r21], -16
+	mov.i		ar.lc = r15
+  (p14)	br.dptk		.Ls10
+	;;
+	ld8		r16 = [r33], -16
+	ld8		r17 = [r21], -16
+	br.sptk		.Li10
+	;;
+
+.Lb11:	C  n = 3, 7, 11, 15, ...
+	add		r21 = -8, r33
+	add		r20 = -8, r32
+	add		r33 = -16, r33
+	add		r32 = -16, r32
+	;;
+	ld8		r17 = [r21], -16
+	shr		r15 = r34, 2
+	;;
+	ld8		r18 = [r33], -16
+	mov.i		ar.lc = r15
+	ld8		r19 = [r21], -16
+  (p14)	br.dptk		.Ls11
+	;;
+	ld8		r16 = [r33], -16
+	br.sptk		.Li11
+	;;
+
+	ALIGN(32)
+.Loop:
+.Li00:
+{.mmb
+	st8		[r32] = r16, -16
+	ld8		r16 = [r33], -16
+	nop.b		0
+}
+.Li11:
+{.mmb
+	st8		[r20] = r17, -16
+	ld8		r17 = [r21], -16
+	nop.b		0
+	;;
+}
+.Li10:
+{.mmb
+	st8		[r32] = r18, -16
+	ld8		r18 = [r33], -16
+	nop.b		0
+}
+.Li01:
+{.mmb
+	st8		[r20] = r19, -16
+	ld8		r19 = [r21], -16
+	br.cloop.dptk	.Loop
+	;;
+}
+.Lend:	st8		[r32] = r16, -16
+.Ls11:	st8		[r20] = r17, -16
+	;;
+.Ls10:	st8		[r32] = r18, -16
+.Ls01:	st8		[r20] = r19, -16
+.Ls00:	mov.i		ar.lc = r2
+	br.ret.sptk.many b0
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/ia64/copyi.asm b/third_party/gmp/mpn/ia64/copyi.asm
new file mode 100644
index 0000000..49ed192
--- /dev/null
+++ b/third_party/gmp/mpn/ia64/copyi.asm
@@ -0,0 +1,182 @@
+dnl  IA-64 mpn_copyi -- copy limb vector, incrementing.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2001, 2002, 2004 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C         cycles/limb
+C Itanium:    1
+C Itanium 2:  0.5
+
+C INPUT PARAMETERS
+C rp = r32
+C sp = r33
+C n = r34
+
+ASM_START()
+PROLOGUE(mpn_copyi)
+	.prologue
+	.save ar.lc, r2
+	.body
+ifdef(`HAVE_ABI_32',
+`	addp4		r32 = 0, r32
+	addp4		r33 = 0, r33
+	sxt4		r34 = r34
+	;;
+')
+{.mmi
+	nop		0
+	nop		0
+	mov.i		r2 = ar.lc
+}
+{.mmi
+	and		r14 = 3, r34
+	cmp.ge		p14, p15 = 3, r34
+	add		r34 = -4, r34
+	;;
+}
+{.mmi
+	cmp.eq		p8, p0 = 1, r14
+	cmp.eq		p10, p0 = 2, r14
+	cmp.eq		p12, p0 = 3, r14
+}
+{.bbb
+  (p8)	br.dptk		.Lb01
+  (p10)	br.dptk		.Lb10
+  (p12)	br.dptk		.Lb11
+}
+
+.Lb00:	C  n = 0, 4, 8, 12, ...
+  (p14)	br.dptk		.Ls00
+	;;
+	add		r21 = 8, r33
+	ld8		r16 = [r33], 16
+	shr		r15 = r34, 2
+	;;
+	ld8		r17 = [r21], 16
+	mov.i		ar.lc = r15
+	ld8		r18 = [r33], 16
+	add		r20 = 8, r32
+	;;
+	ld8		r19 = [r21], 16
+	br.cloop.dptk	.Loop
+	;;
+	br.sptk		.Lend
+	;;
+
+.Lb01:	C  n = 1, 5, 9, 13, ...
+	add		r21 = 0, r33
+	add		r20 = 0, r32
+	add		r33 = 8, r33
+	add		r32 = 8, r32
+	;;
+	ld8		r19 = [r21], 16
+	shr		r15 = r34, 2
+  (p14)	br.dptk		.Ls01
+	;;
+	ld8		r16 = [r33], 16
+	mov.i		ar.lc = r15
+	;;
+	ld8		r17 = [r21], 16
+	ld8		r18 = [r33], 16
+	br.sptk		.Li01
+	;;
+
+.Lb10:	C  n = 2,6, 10, 14, ...
+	add		r21 = 8, r33
+	add		r20 = 8, r32
+	ld8		r18 = [r33], 16
+	shr		r15 = r34, 2
+	;;
+	ld8		r19 = [r21], 16
+	mov.i		ar.lc = r15
+  (p14)	br.dptk		.Ls10
+	;;
+	ld8		r16 = [r33], 16
+	ld8		r17 = [r21], 16
+	br.sptk		.Li10
+	;;
+
+.Lb11:	C  n = 3, 7, 11, 15, ...
+	add		r21 = 0, r33
+	add		r20 = 0, r32
+	add		r33 = 8, r33
+	add		r32 = 8, r32
+	;;
+	ld8		r17 = [r21], 16
+	shr		r15 = r34, 2
+	;;
+	ld8		r18 = [r33], 16
+	mov.i		ar.lc = r15
+	ld8		r19 = [r21], 16
+  (p14)	br.dptk		.Ls11
+	;;
+	ld8		r16 = [r33], 16
+	br.sptk		.Li11
+	;;
+
+	ALIGN(32)
+.Loop:
+.Li00:
+{.mmb
+	st8		[r32] = r16, 16
+	ld8		r16 = [r33], 16
+	nop.b		0
+}
+.Li11:
+{.mmb
+	st8		[r20] = r17, 16
+	ld8		r17 = [r21], 16
+	nop.b		0
+	;;
+}
+.Li10:
+{.mmb
+	st8		[r32] = r18, 16
+	ld8		r18 = [r33], 16
+	nop.b		0
+}
+.Li01:
+{.mmb
+	st8		[r20] = r19, 16
+	ld8		r19 = [r21], 16
+	br.cloop.dptk	.Loop
+	;;
+}
+.Lend:	st8		[r32] = r16, 16
+.Ls11:	st8		[r20] = r17, 16
+	;;
+.Ls10:	st8		[r32] = r18, 16
+.Ls01:	st8		[r20] = r19, 16
+.Ls00:	mov.i		ar.lc = r2
+	br.ret.sptk.many b0
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/ia64/dive_1.asm b/third_party/gmp/mpn/ia64/dive_1.asm
new file mode 100644
index 0000000..5e4a273
--- /dev/null
+++ b/third_party/gmp/mpn/ia64/dive_1.asm
@@ -0,0 +1,236 @@
+dnl  IA-64 mpn_divexact_1 -- mpn by limb exact division.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund and Kevin Ryde.
+
+dnl  Copyright 2003-2005, 2010 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C            cycles/limb
+C Itanium:      16
+C Itanium 2:     8
+
+C INPUT PARAMETERS
+define(`rp', `r32')
+define(`up', `r33')
+define(`n',  `r34')
+define(`divisor', `r35')
+
+define(`lshift', `r24')
+define(`rshift', `r25')
+
+C This code is a bit messy, and not as similar to mode1o.asm as desired.
+
+C The critical path during initialization is for computing the inverse of the
+C divisor.  Since odd divisors are probably common, we conditionally execute
+C the initial count_trailing_zeros code and the downshift.
+
+C Possible improvement: Merge more of the feed-in code into the inverse
+C computation.
+
+ASM_START()
+	.text
+	.align	32
+.Ltab:
+data1	0,0x01, 0,0xAB, 0,0xCD, 0,0xB7, 0,0x39, 0,0xA3, 0,0xC5, 0,0xEF
+data1	0,0xF1, 0,0x1B, 0,0x3D, 0,0xA7, 0,0x29, 0,0x13, 0,0x35, 0,0xDF
+data1	0,0xE1, 0,0x8B, 0,0xAD, 0,0x97, 0,0x19, 0,0x83, 0,0xA5, 0,0xCF
+data1	0,0xD1, 0,0xFB, 0,0x1D, 0,0x87, 0,0x09, 0,0xF3, 0,0x15, 0,0xBF
+data1	0,0xC1, 0,0x6B, 0,0x8D, 0,0x77, 0,0xF9, 0,0x63, 0,0x85, 0,0xAF
+data1	0,0xB1, 0,0xDB, 0,0xFD, 0,0x67, 0,0xE9, 0,0xD3, 0,0xF5, 0,0x9F
+data1	0,0xA1, 0,0x4B, 0,0x6D, 0,0x57, 0,0xD9, 0,0x43, 0,0x65, 0,0x8F
+data1	0,0x91, 0,0xBB, 0,0xDD, 0,0x47, 0,0xC9, 0,0xB3, 0,0xD5, 0,0x7F
+data1	0,0x81, 0,0x2B, 0,0x4D, 0,0x37, 0,0xB9, 0,0x23, 0,0x45, 0,0x6F
+data1	0,0x71, 0,0x9B, 0,0xBD, 0,0x27, 0,0xA9, 0,0x93, 0,0xB5, 0,0x5F
+data1	0,0x61, 0,0x0B, 0,0x2D, 0,0x17, 0,0x99, 0,0x03, 0,0x25, 0,0x4F
+data1	0,0x51, 0,0x7B, 0,0x9D, 0,0x07, 0,0x89, 0,0x73, 0,0x95, 0,0x3F
+data1	0,0x41, 0,0xEB, 0,0x0D, 0,0xF7, 0,0x79, 0,0xE3, 0,0x05, 0,0x2F
+data1	0,0x31, 0,0x5B, 0,0x7D, 0,0xE7, 0,0x69, 0,0x53, 0,0x75, 0,0x1F
+data1	0,0x21, 0,0xCB, 0,0xED, 0,0xD7, 0,0x59, 0,0xC3, 0,0xE5, 0,0x0F
+data1	0,0x11, 0,0x3B, 0,0x5D, 0,0xC7, 0,0x49, 0,0x33, 0,0x55, 0,0xFF
+
+
+PROLOGUE(mpn_divexact_1)
+	.prologue
+	.save		ar.lc, r2
+	.body
+
+ {.mmi;	add		r8 = -1, divisor	C M0
+	nop		0			C M1
+	tbit.z		p8, p9 = divisor, 0	C I0
+}
+ifdef(`HAVE_ABI_32',
+`	addp4		rp = 0, rp		C M2  rp extend
+	addp4		up = 0, up		C M3  up extend
+	sxt4		n = n')			C I1  size extend
+	;;
+.Lhere:
+ {.mmi;	ld8		r20 = [up], 8		C M0  up[0]
+  (p8)	andcm		r8 = r8, divisor	C M1
+	mov		r15 = ip		C I0  .Lhere
+	;;
+}{.mii
+	.pred.rel "mutex", p8, p9
+  (p9)	mov		rshift = 0		C M0
+  (p8)	popcnt		rshift = r8		C I0 r8 = cnt_lo_zeros(divisor)
+	cmp.eq		p6, p10 = 1, n		C I1
+	;;
+}{.mii;	add		r9 = .Ltab-.Lhere, r15	C M0
+  (p8)	shr.u		divisor = divisor, rshift C I0
+	nop		0			C I1
+	;;
+}{.mmi;	add		n = -4, n		C M0  size-1
+  (p10)	ld8		r21 = [up], 8		C M1  up[1]
+	mov		r14 = 2			C M1  2
+}{.mfi;	setf.sig	f6 = divisor		C M2  divisor
+	mov		f9 = f0			C M3  carry		FIXME
+	zxt1		r3 = divisor		C I1  divisor low byte
+	;;
+}{.mmi;	add		r3 = r9, r3		C M0  table offset ip and index
+	sub		r16 = 0, divisor	C M1  -divisor
+	mov		r2 = ar.lc		C I0
+}{.mmi;	sub		lshift = 64, rshift	C M2
+	setf.sig	f13 = r14		C M3  2 in significand
+	mov		r17 = -1		C I1  -1
+	;;
+}{.mmi;	ld1		r3 = [r3]		C M0  inverse, 8 bits
+	nop		0			C M1
+	mov		ar.lc = n		C I0  size-1 loop count
+}{.mmi;	setf.sig	f12 = r16		C M2  -divisor
+	setf.sig	f8 = r17		C M3  -1
+	cmp.eq		p7, p0 = -2, n		C I1
+	;;
+}{.mmi;	setf.sig	f7 = r3			C M2  inverse, 8 bits
+	cmp.eq		p8, p0 = -1, n		C M0
+	shr.u		r23 = r20, rshift	C I0
+	;;
+}
+
+	C f6	divisor
+	C f7	inverse, being calculated
+	C f8	-1, will be -inverse
+	C f9	carry
+	C f12	-divisor
+	C f13	2
+	C f14	scratch
+
+	xmpy.l		f14 = f13, f7		C Newton 2*i
+	xmpy.l		f7 = f7, f7		C Newton i*i
+	;;
+	xma.l		f7 = f7, f12, f14	C Newton i*i*-d + 2*i, 16 bits
+	;;
+	setf.sig	f10 = r23		C speculative, used iff n = 1
+	xmpy.l		f14 = f13, f7		C Newton 2*i
+	shl		r22 = r21, lshift	C speculative, used iff n > 1
+	xmpy.l		f7 = f7, f7		C Newton i*i
+	;;
+	or		r31 = r22, r23		C speculative, used iff n > 1
+	xma.l		f7 = f7, f12, f14	C Newton i*i*-d + 2*i, 32 bits
+	shr.u		r23 = r21, rshift	C speculative, used iff n > 1
+	;;
+	setf.sig	f11 = r31		C speculative, used iff n > 1
+	xmpy.l		f14 = f13, f7		C Newton 2*i
+	xmpy.l		f7 = f7, f7		C Newton i*i
+	;;
+	xma.l		f7 = f7, f12, f14	C Newton i*i*-d + 2*i, 64 bits
+
+  (p7)	br.cond.dptk	.Ln2
+  (p10)	br.cond.dptk	.grt3
+	;;
+
+.Ln1:	xmpy.l		f12 = f10, f7		C q = ulimb * inverse
+	br		.Lx1
+
+.Ln2:
+	xmpy.l		f8 = f7, f8		C -inverse = inverse * -1
+	xmpy.l		f12 = f11, f7		C q = ulimb * inverse
+	setf.sig	f11 = r23
+	br		.Lx2
+
+.grt3:
+	ld8		r21 = [up], 8		C up[2]
+	xmpy.l		f8 = f7, f8		C -inverse = inverse * -1
+	;;
+	shl		r22 = r21, lshift
+	;;
+	xmpy.l		f12 = f11, f7		C q = ulimb * inverse
+	;;
+	or		r31 = r22, r23
+	shr.u		r23 = r21, rshift
+	;;
+	setf.sig	f11 = r31
+  (p8)	br.cond.dptk	.Lx3			C branch for n = 3
+	;;
+	ld8		r21 = [up], 8
+	br		.Lent
+
+.Ltop:	ld8		r21 = [up], 8
+	xma.l		f12 = f9, f8, f10	C q = c * -inverse + si
+	nop.b		0
+	;;
+.Lent:	add		r16 = 160, up
+	shl		r22 = r21, lshift
+	nop.b		0
+	;;
+	stf8		[rp] = f12, 8
+	xma.hu		f9 = f12, f6, f9	C c = high(q * divisor + c)
+	nop.b		0
+	nop.m		0
+	xmpy.l		f10 = f11, f7		C si = ulimb * inverse
+	nop.b		0
+	;;
+	or		r31 = r22, r23
+	shr.u		r23 = r21, rshift
+	nop.b		0
+	;;
+	lfetch		[r16]
+	setf.sig	f11 = r31
+	br.cloop.sptk.few.clr .Ltop
+
+
+	xma.l		f12 = f9, f8, f10	C q = c * -inverse + si
+	;;
+.Lx3:	stf8		[rp] = f12, 8
+	xma.hu		f9 = f12, f6, f9	C c = high(q * divisor + c)
+	xmpy.l		f10 = f11, f7		C si = ulimb * inverse
+	;;
+	setf.sig	f11 = r23
+	;;
+	xma.l		f12 = f9, f8, f10	C q = c * -inverse + si
+	;;
+.Lx2:	stf8		[rp] = f12, 8
+	xma.hu		f9 = f12, f6, f9	C c = high(q * divisor + c)
+	xmpy.l		f10 = f11, f7		C si = ulimb * inverse
+	;;
+	xma.l		f12 = f9, f8, f10	C q = c * -inverse + si
+	;;
+.Lx1:	stf8		[rp] = f12, 8
+	mov		ar.lc = r2		C I0
+	br.ret.sptk.many b0
+EPILOGUE()
diff --git a/third_party/gmp/mpn/ia64/divrem_1.asm b/third_party/gmp/mpn/ia64/divrem_1.asm
new file mode 100644
index 0000000..e887820
--- /dev/null
+++ b/third_party/gmp/mpn/ia64/divrem_1.asm
@@ -0,0 +1,477 @@
+dnl  IA-64 mpn_divrem_1 and mpn_preinv_divrem_1 -- Divide an mpn number by an
+dnl  unnormalized limb.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2002, 2004, 2005 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C         cycles/limb
+C Itanium:    40-42
+C Itanium 2:  29-30
+
+C This was generated by gcc, then the loops were optimized.  The preinv entry
+C point was shoehorned into the file.  Lots of things outside the loops could
+C be streamlined.  It would probably be a good idea to merge the loops for
+C normalized and unnormalized divisor, since the shifting stuff is done for
+C free in parallel with other operations.  It would even be possible to merge
+C all loops, if the ld8 were made conditional.
+
+C TODO
+C  * Consider delaying inversion for normalized mpn_divrem_1 entry till after
+C    computing leading limb.
+C  * Inline and interleave limb inversion code with loop setup code.
+
+ASM_START()
+
+C HP's assembler requires these declarations for importing mpn_invert_limb
+	.global	mpn_invert_limb
+	.type	mpn_invert_limb,@function
+
+C INPUT PARAMETERS
+C rp    = r32
+C qxn   = r33
+C up    = r34
+C n     = r35
+C vl    = r36
+C vlinv = r37  (preinv only)
+C cnt = r38    (preinv only)
+
+PROLOGUE(mpn_preinv_divrem_1)
+	.prologue
+	.save	ar.pfs, r42
+	alloc		r42 = ar.pfs, 7, 8, 1, 0
+	.save	ar.lc, r44
+	mov		r44 = ar.lc
+	.save	rp, r41
+	mov		r41 = b0
+	.body
+ifdef(`HAVE_ABI_32',
+`	addp4		r32 = 0, r32
+	sxt4		r33 = r33
+	addp4		r34 = 0, r34
+	sxt4		r35 = r35
+	;;
+')
+	mov		r40 = r38
+	shladd		r34 = r35, 3, r34
+	;;
+	adds		r34 = -8, r34
+	;;
+	ld8		r39 = [r34], -8
+	;;
+
+	add		r15 = r35, r33
+	;;
+	mov		r8 = r37
+	shladd		r32 = r15, 3, r32	C r32 = rp + n + qxn
+	cmp.le		p8, p0 = 0, r36
+	;;
+	adds		r32 = -8, r32		C r32 = rp + n + qxn - 1
+	cmp.leu		p6, p7 = r36, r39
+   (p8)	br.cond.dpnt	.Lpunnorm
+	;;
+
+   (p6)	addl		r15 = 1, r0
+   (p7)	mov		r15 = r0
+	;;
+   (p6)	sub		r38 = r39, r36
+   (p7)	mov		r38 = r39
+	st8		[r32] = r15, -8
+	adds		r35 = -2, r35		C un -= 2
+	br	.Lpn
+
+.Lpunnorm:
+   (p6)	add		r34 = 8, r34
+	mov		r38 = 0			C r = 0
+	shl		r36 = r36, r40
+   (p6)	br.cond.dptk	.Lpu
+	;;
+	shl		r38 = r39, r40		C r = ahigh << cnt
+	cmp.ne		p8, p0 = 1, r35
+	st8		[r32] = r0, -8
+	adds		r35 = -1, r35		C un--
+   (p8)	br.cond.dpnt	.Lpu
+
+	mov		r23 = 1
+	;;
+	setf.sig	f6 = r8
+	setf.sig	f12 = r23
+	br		.L435
+EPILOGUE()
+
+
+PROLOGUE(mpn_divrem_1)
+	.prologue
+	.save	ar.pfs, r42
+	alloc		r42 = ar.pfs, 5, 8, 1, 0
+	.save	ar.lc, r44
+	mov		r44 = ar.lc
+	.save	rp, r41
+	mov		r41 = b0
+	.body
+ifdef(`HAVE_ABI_32',
+`	addp4		r32 = 0, r32
+	sxt4		r33 = r33
+	addp4		r34 = 0, r34
+	sxt4		r35 = r35
+	;;
+')
+	mov		r38 = r0
+	add		r15 = r35, r33
+	;;
+	cmp.ne		p6, p7 = 0, r15
+	;;
+   (p7)	mov		r8 = r0
+   (p7)	br.cond.dpnt	.Lret
+	shladd		r14 = r15, 3, r32	C r14 = rp + n + qxn
+	cmp.le		p6, p7 = 0, r36
+	;;
+	adds		r32 = -8, r14		C r32 = rp + n + qxn - 1
+   (p6)	br.cond.dpnt	.Lunnorm
+	cmp.eq		p6, p7 = 0, r35
+   (p6)	br.cond.dpnt	.L179
+	shladd		r14 = r35, 3, r34
+	;;
+	adds		r14 = -8, r14
+	adds		r35 = -1, r35
+	;;
+	ld8		r38 = [r14]
+	;;
+	cmp.leu		p6, p7 = r36, r38
+	;;
+   (p6)	addl		r15 = 1, r0
+   (p7)	mov		r15 = r0
+	;;
+	st8		[r32] = r15, -8
+  (p6)	sub		r38 = r38, r36
+
+.L179:
+	mov		r45 = r36
+	adds		r35 = -1, r35
+	br.call.sptk.many b0 = mpn_invert_limb
+	;;
+	shladd		r34 = r35, 3, r34
+.Lpn:
+	mov		r23 = 1
+	;;
+	setf.sig	f6 = r8
+	setf.sig	f12 = r23
+	cmp.le		p6, p7 = 0, r35
+	mov		r40 = 0
+   (p7)	br.cond.dpnt	.L435
+	setf.sig	f10 = r36
+	mov		ar.lc = r35
+	setf.sig	f7 = r38
+	;;
+	sub		r28 = -1, r36
+C Develop quotient limbs for normalized divisor
+.Loop1:		C 00				C q=r18 nh=r38/f7
+	ld8		r20 = [r34], -8
+	xma.hu		f11 = f7, f6, f0
+	;;	C 04
+	xma.l		f8 = f11, f12, f7	C q = q + nh
+	;;	C 08
+	getf.sig	r18 = f8
+	xma.hu		f9 = f8, f10, f0
+	xma.l		f8 = f8, f10, f0
+	;;	C 12
+	getf.sig	r16 = f9
+		C 13
+	getf.sig	r15 = f8
+	;;	C 18
+	cmp.ltu		p6, p7 = r20, r15
+	sub		r15 = r20, r15
+	sub		r16 = r38, r16
+	;;	C 19
+   (p6)	cmp.ne		p8, p9 = 1, r16		C is rH != 0?
+   (p7)	cmp.ne		p8, p9 = 0, r16		C is rH != 0?
+   (p6)	add		r16 = -1, r16
+   (p0)	cmp.ne.unc	p6, p7 = r0, r0
+	;;	C 20
+   (p8)	cmp.ltu		p6, p7 = r15, r36
+   (p8)	sub		r15 = r15, r36
+   (p8)	add		r18 = 1, r18		C q = q + 1;	done if: rH > 0
+	;;	C 21
+	.pred.rel "mutex",p6,p7
+   (p6)	cmp.ne		p8, p9 = 1, r16		C is rH != 0 still?
+   (p7)	cmp.ne		p8, p9 = 0, r16		C is rH != 0 still?
+	cmp.ltu		p6, p7 = r15, r36	C speculative
+	sub		r28 = r15, r36		C speculative, just for cmp
+	;;	C 22
+   (p8)	cmp.ltu		p6, p7 = r28, r36	C redo last cmp if needed
+   (p8)	mov		r15 = r28
+   (p8)	add		r18 = 1, r18		C q = q + 1;	done if: rH > 0
+	;;	C 23
+   (p6)	setf.sig	f7 = r15
+   (p7)	sub		r15 = r15, r36
+   (p7)	add		r18 = 1, r18		C q = q + 1;	done if: rH > 0
+	;;	C 24
+   (p7)	setf.sig	f7 = r15
+	st8		[r32] = r18, -8
+	mov		r38 = r15
+	br.cloop.dptk	.Loop1
+		C 29/30
+	br.sptk		.L435
+	;;
+.Lunnorm:
+	mux1		r16 = r36, @rev
+	cmp.eq		p6, p7 = 0, r35
+   (p6)	br.cond.dpnt	.L322
+	shladd		r34 = r35, 3, r34
+	;;
+	adds		r34 = -8, r34
+	;;
+	ld8		r39 = [r34]
+	;;
+	cmp.leu		p6, p7 = r36, r39
+   (p6)	br.cond.dptk	.L322
+	adds		r34 = -8, r34
+	;;
+	mov		r38 = r39
+	;;
+	cmp.ne		p6, p7 = 1, r15
+	st8		[r32] = r0, -8
+	;;
+   (p7)	mov		r8 = r38
+   (p7)	br.cond.dpnt	.Lret
+	adds		r35 = -1, r35
+.L322:
+	sub		r14 = r0, r16
+	;;
+	or		r14 = r16, r14
+	;;
+	mov		r16 = -8
+	czx1.l		r14 = r14
+	;;
+	shladd		r16 = r14, 3, r16
+	;;
+	shr.u		r14 = r36, r16
+	;;
+	cmp.geu		p6, p7 = 15, r14
+	;;
+   (p7)	shr.u		r14 = r14, 4
+   (p7)	adds		r16 = 4, r16
+	;;
+	cmp.geu		p6, p7 = 3, r14
+	;;
+   (p7)	shr.u		r14 = r14, 2
+   (p7)	adds		r16 = 2, r16
+	;;
+	tbit.nz		p6, p7 = r14, 1
+	;;
+	.pred.rel "mutex",p6,p7
+  (p6)	sub		r40 = 62, r16
+  (p7)	sub		r40 = 63, r16
+	;;
+	shl		r45 = r36, r40
+	shl		r36 = r36, r40
+	shl		r38 = r38, r40
+	br.call.sptk.many b0 = mpn_invert_limb
+	;;
+.Lpu:
+	mov		r23 = 1
+	;;
+	setf.sig	f6 = r8
+	setf.sig	f12 = r23
+	cmp.eq		p6, p7 = 0, r35
+   (p6)	br.cond.dpnt	.L435
+	sub		r16 = 64, r40
+	adds		r35 = -2, r35
+	;;
+	ld8		r39 = [r34], -8
+	cmp.le		p6, p7 = 0, r35
+	;;
+	shr.u		r14 = r39, r16
+	;;
+	or		r38 = r14, r38
+   (p7)	br.cond.dpnt	.Lend3
+	;;
+	mov		r22 = r16
+	setf.sig	f10 = r36
+	setf.sig	f7 = r38
+	mov		ar.lc = r35
+	;;
+C Develop quotient limbs for unnormalized divisor
+.Loop3:
+	ld8		r14 = [r34], -8
+	xma.hu		f11 = f7, f6, f0
+	;;
+	xma.l		f8 = f11, f12, f7	C q = q + nh
+	;;
+	getf.sig	r18 = f8
+	xma.hu		f9 = f8, f10, f0
+	shl		r20 = r39, r40
+	xma.l		f8 = f8, f10, f0
+	shr.u		r24 = r14, r22
+	;;
+	getf.sig	r16 = f9
+	getf.sig	r15 = f8
+	or		r20 = r24, r20
+	;;
+	cmp.ltu		p6, p7 = r20, r15
+	sub		r15 = r20, r15
+	sub		r16 = r38, r16
+	;;
+   (p6)	cmp.ne		p8, p9 = 1, r16		C is rH != 0?
+   (p7)	cmp.ne		p8, p9 = 0, r16		C is rH != 0?
+   (p6)	add		r16 = -1, r16
+   (p0)	cmp.ne.unc	p6, p7 = r0, r0
+	;;
+   (p8)	cmp.ltu		p6, p7 = r15, r36
+   (p8)	sub		r15 = r15, r36
+   (p8)	add		r18 = 1, r18		C q = q + 1;	done if: rH > 0
+	;;
+	.pred.rel "mutex",p6,p7
+   (p6)	cmp.ne		p8, p9 = 1, r16		C is rH != 0 still?
+   (p7)	cmp.ne		p8, p9 = 0, r16		C is rH != 0 still?
+	cmp.ltu		p6, p7 = r15, r36	C speculative
+	sub		r28 = r15, r36		C speculative, just for cmp
+	;;
+   (p8)	cmp.ltu		p6, p7 = r28, r36	C redo last cmp if needed
+   (p8)	mov		r15 = r28
+   (p8)	add		r18 = 1, r18		C q = q + 1;	done if: rH > 0
+	;;
+   (p6)	setf.sig	f7 = r15
+   (p7)	sub		r15 = r15, r36
+   (p7)	add		r18 = 1, r18		C q = q + 1;	done if: rH > 0
+	;;
+   (p7)	setf.sig	f7 = r15
+	st8		[r32] = r18, -8
+	mov		r39 = r14
+	mov		r38 = r15
+	br.cloop.dptk	.Loop3
+	;;
+.Lend3:
+	setf.sig	f10 = r36
+	setf.sig	f7 = r38
+	;;
+	xma.hu		f11 = f7, f6, f0
+	;;
+	xma.l		f8 = f11, f12, f7	C q = q + nh
+	;;
+	getf.sig	r18 = f8
+	xma.hu		f9 = f8, f10, f0
+	shl		r20 = r39, r40
+	xma.l		f8 = f8, f10, f0
+	;;
+	getf.sig	r16 = f9
+	getf.sig	r15 = f8
+	;;
+	cmp.ltu		p6, p7 = r20, r15
+	sub		r15 = r20, r15
+	sub		r16 = r38, r16
+	;;
+   (p6)	cmp.ne		p8, p9 = 1, r16		C is rH != 0?
+   (p7)	cmp.ne		p8, p9 = 0, r16		C is rH != 0?
+   (p6)	add		r16 = -1, r16
+   (p0)	cmp.ne.unc	p6, p7 = r0, r0
+	;;
+   (p8)	cmp.ltu		p6, p7 = r15, r36
+   (p8)	sub		r15 = r15, r36
+   (p8)	add		r18 = 1, r18		C q = q + 1;	done if: rH > 0
+	;;
+	.pred.rel "mutex",p6,p7
+   (p6)	cmp.ne		p8, p9 = 1, r16		C is rH != 0 still?
+   (p7)	cmp.ne		p8, p9 = 0, r16		C is rH != 0 still?
+	;;
+   (p8)	sub		r15 = r15, r36
+   (p8)	add		r18 = 1, r18		C q = q + 1;	done if: rH > 0
+	;;
+	cmp.ltu		p6, p7 = r15, r36
+	;;
+   (p7)	sub		r15 = r15, r36
+   (p7)	add		r18 = 1, r18		C q = q + 1;	done if: rH > 0
+	;;
+	st8		[r32] = r18, -8
+	mov		r38 = r15
+.L435:
+	adds		r35 = -1, r33
+	cmp.le		p6, p7 = 1, r33
+   (p7)	br.cond.dpnt	.Lend4
+	;;
+	setf.sig	f7 = r38
+	setf.sig	f10 = r36
+	mov		ar.lc = r35
+	;;
+.Loop4:
+	xma.hu		f11 = f7, f6, f0
+	;;
+	xma.l		f8 = f11, f12, f7	C q = q + nh
+	;;
+	getf.sig	r18 = f8
+	xma.hu		f9 = f8, f10, f0
+	xma.l		f8 = f8, f10, f0
+	;;
+	getf.sig	r16 = f9
+	getf.sig	r15 = f8
+	;;
+	cmp.ltu		p6, p7 = 0, r15
+	sub		r15 = 0, r15
+	sub		r16 = r38, r16
+	;;
+   (p6)	cmp.ne		p8, p9 = 1, r16		C is rH != 0?
+   (p7)	cmp.ne		p8, p9 = 0, r16		C is rH != 0?
+   (p6)	add		r16 = -1, r16
+   (p0)	cmp.ne.unc	p6, p7 = r0, r0
+	;;
+   (p8)	cmp.ltu		p6, p7 = r15, r36
+   (p8)	sub		r15 = r15, r36
+   (p8)	add		r18 = 1, r18		C q = q + 1;	done if: rH > 0
+	;;
+	.pred.rel "mutex",p6,p7
+   (p6)	cmp.ne		p8, p9 = 1, r16		C is rH != 0 still?
+   (p7)	cmp.ne		p8, p9 = 0, r16		C is rH != 0 still?
+	cmp.ltu		p6, p7 = r15, r36	C speculative
+	sub		r28 = r15, r36		C speculative, just for cmp
+	;;
+   (p8)	cmp.ltu		p6, p7 = r28, r36	C redo last cmp if needed
+   (p8)	mov		r15 = r28
+   (p8)	add		r18 = 1, r18		C q = q + 1;	done if: rH > 0
+	;;
+   (p6)	setf.sig	f7 = r15
+   (p7)	sub		r15 = r15, r36
+   (p7)	add		r18 = 1, r18		C q = q + 1;	done if: rH > 0
+	;;
+   (p7)	setf.sig	f7 = r15
+	st8		[r32] = r18, -8
+	mov		r38 = r15
+	br.cloop.dptk	.Loop4
+	;;
+.Lend4:
+	shr.u		r8 = r38, r40
+.Lret:
+	mov		ar.pfs = r42
+	mov		ar.lc = r44
+	mov		b0 = r41
+	br.ret.sptk.many b0
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/ia64/divrem_2.asm b/third_party/gmp/mpn/ia64/divrem_2.asm
new file mode 100644
index 0000000..9864311
--- /dev/null
+++ b/third_party/gmp/mpn/ia64/divrem_2.asm
@@ -0,0 +1,280 @@
+dnl  IA-64 mpn_divrem_2 -- Divide an mpn number by a normalized 2-limb number.
+
+dnl  Copyright 2010, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C               norm   frac
+C itanium 1
+C itanium 2     29     29
+
+
+C TODO
+C  * Inline and interleave limb inversion code with loop setup code.
+C  * We should use explicit bundling in much of the code, since it typically
+C    cuts some cycles with the GNU assembler.
+
+
+ASM_START()
+
+C HP's assembler requires these declarations for importing mpn_invert_limb
+	.global	mpn_invert_limb
+	.type	mpn_invert_limb,@function
+
+C INPUT PARAMETERS
+C qp   = r32
+C fn   = r33
+C np   = r34
+C nn   = r35
+C dp   = r36
+
+define(`f0x1', `f15')
+
+ASM_START()
+PROLOGUE(mpn_divrem_2)
+	.prologue
+ifdef(`HAVE_ABI_32',
+`	addp4		r32 = 0, r32		C M I
+	addp4		r34 = 0, r34		C M I
+	zxt4		r35 = r35		C I
+	addp4		r36 = 0, r36		C M I
+	nop.m		0
+	zxt4		r33 = r33		C I
+	;;
+')
+	.save ar.pfs, r42
+	alloc	 r42 = ar.pfs, 5, 9, 1, 0
+	shladd	 r34 = r35, 3, r34
+	adds	 r14 = 8, r36
+	mov	 r43 = r1
+	;;
+	adds	 r15 = -8, r34
+	ld8	 r39 = [r14]
+	.save ar.lc, r45
+	mov	 r45 = ar.lc
+	adds	 r14 = -16, r34
+	mov	 r40 = r0
+	adds	 r34 = -24, r34
+	;;
+	ld8	 r38 = [r15]
+	.save rp, r41
+	mov	 r41 = b0
+	.body
+	ld8	 r36 = [r36]
+	ld8	 r37 = [r14]
+	;;
+	cmp.gtu	 p6, p7 = r39, r38
+  (p6)	br.cond.dptk .L8
+	;;
+	cmp.leu	 p8, p9 = r36, r37
+	cmp.geu	 p6, p7 = r39, r38
+	;;
+  (p8)	cmp4.ne.and.orcm p6, p7 = 0, r0
+  (p7)	br.cond.dptk .L51
+.L8:
+	add	 r14 = r33, r35		// un + fn
+	mov	 r46 = r39		// argument to mpn_invert_limb
+	;;
+	adds	 r35 = -3, r14
+	;;
+	cmp.gt	 p12, p0 = r0, r35
+  (p12)	br.cond.dpnt L(end)
+	br.call.sptk.many b0 = mpn_invert_limb
+	;;
+	setf.sig f11 = r8		// di (non-final)
+	setf.sig f34 = r39		// d1
+	setf.sig f33 = r36		// d0
+	mov	 r1 = r43
+	;;
+	mov	 r17 = 1
+	setf.sig f9 = r38		// n2
+	xma.l	 f6 = f11, f34, f0	// t0 = LO(di * d1)
+	;;
+	setf.sig f10 = r37		// n1
+	setf.sig f15 = r17		// 1
+	xma.hu	 f8 = f11, f33, f0	// s0 = HI(di * d0)
+	;;
+	getf.sig r17 = f6
+	getf.sig r16 = f8
+	mov	 ar.lc = r35
+	;;
+	sub	 r18 = r0, r39		// -d1
+	add	 r14 = r17, r36
+	;;
+	setf.sig f14 = r18		// -d1
+	cmp.leu	 p8, p9 = r17, r14
+	add	 r16 = r14, r16
+	;;
+  (p9)	adds	 r19 = 0, r0
+  (p8)	adds	 r19 = -1, r0
+	cmp.gtu	 p6, p7 = r14, r16
+	;;
+  (p6)	adds	 r19 = 1, r19
+	;;
+ifelse(1,1,`
+	cmp.gt	 p7, p6 = r0, r19
+	;;
+  (p6)	adds	 r8 = -1, r8		// di--
+  (p6)	sub	 r14 = r16, r39		// t0 -= d1
+  (p6)	cmp.ltu	 p6, p7 = r16, r39	// cy for: t0 - d1
+	;;
+  (p6)	cmp.gt	 p9, p8 = 1, r19
+  (p7)	cmp.gt	 p9, p8 = 0, r19
+  (p6)	adds	 r19 = -1, r19		// t1 -= cy
+	mov	 r16 = r14
+	;;
+  (p8)	adds	 r8 = -1, r8		// di--
+  (p8)	sub	 r14 = r16, r39		// t0 -= d1
+  (p8)	cmp.ltu	 p8, p9 = r16, r39	// cy for: t0 - d1
+	;;
+  (p8)	cmp.gt	 p7, p6 = 1, r19
+  (p9)	cmp.gt	 p7, p6 = 0, r19
+  (p8)	adds	 r19 = -1, r19		// t1 -= cy
+	mov	 r16 = r14
+	;;
+  (p6)	adds	 r8 = -1, r8		// di--
+  (p6)	sub	 r14 = r16, r39		// t0 -= d1
+  (p6)	cmp.ltu	 p6, p7 = r16, r39	// cy for: t0 - d1
+	;;
+  (p6)	cmp.gt	 p9, p8 = 1, r19
+  (p7)	cmp.gt	 p9, p8 = 0, r19
+  (p6)	adds	 r19 = -1, r19		// t1 -= cy
+	mov	 r16 = r14
+	;;
+  (p8)	adds	 r8 = -1, r8		// di--
+  (p8)	sub	 r14 = r16, r39		// t0 -= d1
+  (p8)	cmp.ltu	 p8, p9 = r16, r39	// cy for: t0 - d1
+	;;
+  (p8)	adds	 r19 = -1, r19		// t1 -= cy
+	mov	 r16 = r14
+',`
+	cmp.gt	 p8, p9 = r0, r19
+  (p8)	br.cond.dpnt .L46
+.L52:
+	cmp.leu	 p6, p7 = r39, r16
+	sub	 r14 = r16, r39
+	adds	 r8 = -1, r8
+	;;
+  (p7)	adds	 r19 = -1, r19
+	mov	 r16 = r14
+	;;
+  (p7)	cmp.gt	 p8, p9 = r0, r19
+  (p9)	br.cond.dptk .L52
+.L46:
+')
+	setf.sig f32 = r8		// di
+	shladd	 r32 = r35, 3, r32
+	;;
+
+	ALIGN(16)
+L(top):	nop 0
+	nop 0
+	cmp.gt	 p8, p9 = r33, r35
+	;;
+ (p8)	mov	 r37 = r0
+ (p9)	ld8	 r37 = [r34], -8
+	xma.hu	 f8 = f9, f32, f10	//				0,29
+	xma.l	 f12 = f9, f32, f10	//				0
+	;;
+	getf.sig r20 = f12		// q0				4
+	xma.l	 f13 = f15, f8, f9	// q += n2			4
+	sub	 r8 = -1, r36		// bitnot d0
+	;;
+	getf.sig r18 = f13		//				8
+	xma.l	 f7 = f14, f13, f10	//				8
+	xma.l	 f6 = f33, f13, f33	// t0 = LO(d0*q+d0)		8
+	xma.hu	 f9 = f33, f13, f33	// t1 = HI(d0*q+d0)		9
+	;;
+	getf.sig r38 = f7		// n1				12
+	getf.sig r16 = f6		//				13
+	getf.sig r19 = f9		//				14
+	;;
+	sub	 r38 = r38, r39		// n1 -= d1			17
+	;;
+	cmp.ne	 p9, p0 = r0, r0	// clear p9
+	cmp.leu	 p10, p11 = r16, r37	// cy for: n0 - t0		18
+	;;
+	sub	 r37 = r37, r16		// n0 -= t0			19
+  (p11)	sub	 r38 = r38, r19, 1	// n1 -= t1 - cy		19
+  (p10)	sub	 r38 = r38, r19		// n1 -= t1			19
+	;;
+	cmp.gtu	 p6, p7 = r20, r38	// n1 >= q0			20
+	;;
+  (p7)	cmp.ltu	 p9, p0 = r8, r37	//				21
+  (p6)	add	 r18 = 1, r18		//
+  (p7)	add	 r37 = r37, r36		//				21
+  (p7)	add	 r38 = r38, r39		//				21
+	;;
+	setf.sig f10 = r37		// n1				22
+  (p9)	add	 r38 = 1, r38		//				22
+	;;
+	setf.sig f9 = r38		// n2				23
+	cmp.gtu	 p6, p7 = r39, r38	//				23
+  (p7)	br.cond.spnt L(fix)
+L(bck):	st8	 [r32] = r18, -8
+	adds	 r35 = -1, r35
+	br.cloop.sptk.few L(top)
+	;;
+
+L(end):	add	r14 = 8, r34
+	add	r15 = 16, r34
+	mov	 b0 = r41
+	;;
+	st8	[r14] = r37
+	st8	[r15] = r38
+	mov	 ar.pfs = r42
+	mov	 r8 = r40
+	mov	 ar.lc = r45
+	br.ret.sptk.many b0
+	;;
+.L51:
+	.pred.rel "mutex", p8, p9
+	sub	 r37 = r37, r36
+  (p9)	sub	 r38 = r38, r39, 1
+  (p8)	sub	 r38 = r38, r39
+	adds	 r40 = 1, r0
+	br .L8
+	;;
+
+L(fix):	cmp.geu	 p6, p7 = r39, r38
+	cmp.leu	 p8, p9 = r36, r37
+	;;
+  (p8)	cmp4.ne.and.orcm p6, p7 = 0, r0
+  (p6)	br.cond.dptk L(bck)
+	sub	 r37 = r37, r36
+  (p9)	sub	 r38 = r38, r39, 1
+  (p8)	sub	 r38 = r38, r39
+	adds	 r18 = 1, r18
+	;;
+	setf.sig f9 = r38		// n2
+	setf.sig f10 = r37		// n1
+	br	 L(bck)
+
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/ia64/gcd_11.asm b/third_party/gmp/mpn/ia64/gcd_11.asm
new file mode 100644
index 0000000..6137227
--- /dev/null
+++ b/third_party/gmp/mpn/ia64/gcd_11.asm
@@ -0,0 +1,110 @@
+dnl  Itanium-2 mpn_gcd_11
+
+dnl  Copyright 2002-2005, 2012, 2013, 2015, 2019 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C           cycles/bitpair (1x1 gcd)
+C Itanium:       ?
+C Itanium 2:     4.5
+
+
+ASM_START()
+
+C ctz_table[n] is the number of trailing zeros on n, or MAXSHIFT if n==0.
+
+deflit(MAXSHIFT, 7)
+deflit(MASK, eval((m4_lshift(1,MAXSHIFT))-1))
+
+	.rodata
+	ALIGN(m4_lshift(1,MAXSHIFT))	C align table to allow using dep
+ctz_table:
+	data1	MAXSHIFT
+forloop(i,1,MASK,
+`	data1	m4_count_trailing_zeros(i)-1
+')
+
+define(`x0', r32)
+define(`y0', r33)
+
+PROLOGUE(mpn_gcd_11)
+	.prologue
+	.body
+		addl	r22 = @ltoff(ctz_table), r1
+	;;
+		ld8	r22 = [r22]
+		br	L(ent)
+	;;
+
+	ALIGN(32)
+L(top):
+	.pred.rel "mutex", p6,p7
+ {.mmi;	(p7)	mov	y0 = x0
+	(p6)	sub	x0 = x0, y0
+		dep	r21 = r19, r22, 0, MAXSHIFT	C concat(table,lowbits)
+}{.mmi;		and	r20 = MASK, r19
+	(p7)	mov	x0 = r19
+		and	r23 = 6, r19
+	;;
+}{.mmi;		cmp.eq	p6,p0 = 4, r23
+		cmp.eq	p7,p0 = 0, r23
+		shr.u	x0 = x0, 1		C shift-by-1, always OK
+}{.mmb;		ld1	r16 = [r21]
+		cmp.eq	p10,p0 = 0, r20
+	(p10)	br.spnt.few.clr	 L(count_better)
+	;;
+}
+L(bck):
+	.pred.rel "mutex", p6,p7
+ {.mii;		nop	0
+	(p6)	shr.u	x0 = x0, 1		C u was ...100 before shift-by-1 above
+	(p7)	shr.u	x0 = x0, r16		C u was ...000 before shift-by-1 above
+	;;
+}
+L(ent):
+ {.mmi;		sub	r19 = y0, x0
+		cmp.gtu	p6,p7 = x0, y0
+		cmp.ne	p8,p0 = x0, y0
+}{.mmb;		nop	0
+		nop	0
+	(p8)	br.sptk.few.clr L(top)
+}
+
+L(end):		mov	r8 = y0
+		br.ret.sptk.many b0
+
+L(count_better):
+		add	r20 = -1, x0
+	;;
+		andcm	r23 = r20, x0
+	;;
+		popcnt	r16 = r23
+		br	L(bck)
+EPILOGUE()
diff --git a/third_party/gmp/mpn/ia64/gmp-mparam.h b/third_party/gmp/mpn/ia64/gmp-mparam.h
new file mode 100644
index 0000000..34d2bf3
--- /dev/null
+++ b/third_party/gmp/mpn/ia64/gmp-mparam.h
@@ -0,0 +1,212 @@
+/* gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+/* 900MHz Itanium2 (olympic.gmplib.org) */
+/* FFT tuning limit = 59,194,709 */
+/* Generated by tuneup.c, 2019-10-13, gcc 4.2 */
+
+#define MOD_1_1P_METHOD                      2  /* 17.40% faster than 1 */
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          8
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          6
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        18
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD         0  /* never mpn_mod_1s_2p */
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     13
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1N_PI1_METHOD                 1  /* 1.35% faster than 2 */
+#define DIV_QR_1_NORM_THRESHOLD          MP_SIZE_T_MAX  /* never */
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD              10
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD        MP_SIZE_T_MAX  /* never */
+
+#define DIV_1_VS_MUL_1_PERCENT             316
+
+#define MUL_TOOM22_THRESHOLD                47
+#define MUL_TOOM33_THRESHOLD                89
+#define MUL_TOOM44_THRESHOLD               220
+#define MUL_TOOM6H_THRESHOLD               327
+#define MUL_TOOM8H_THRESHOLD               454
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      97
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     153
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     143
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     153
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     226
+
+#define SQR_BASECASE_THRESHOLD              11
+#define SQR_TOOM2_THRESHOLD                 98
+#define SQR_TOOM3_THRESHOLD                135
+#define SQR_TOOM4_THRESHOLD                272
+#define SQR_TOOM6_THRESHOLD                354
+#define SQR_TOOM8_THRESHOLD                490
+
+#define MULMID_TOOM42_THRESHOLD             99
+
+#define MULMOD_BNM1_THRESHOLD               23
+#define SQRMOD_BNM1_THRESHOLD               27
+
+#define MUL_FFT_MODF_THRESHOLD             840  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    840, 5}, {     30, 6}, {     16, 5}, {     33, 6}, \
+    {     17, 5}, {     36, 6}, {     35, 7}, {     18, 6}, \
+    {     37, 7}, {     19, 6}, {     42, 7}, {     37, 8}, \
+    {     19, 7}, {     43, 8}, {     23, 7}, {     47, 8}, \
+    {     43, 9}, {     23, 8}, {     51, 9}, {     27, 8}, \
+    {     57, 9}, {     31, 8}, {     63, 9}, {     35, 8}, \
+    {     71, 9}, {     43,10}, {     23, 9}, {     55,10}, \
+    {     31, 9}, {     71,10}, {     39, 9}, {     83,10}, \
+    {     47, 9}, {     99,10}, {     55,11}, {     31,10}, \
+    {     87,11}, {     47,10}, {    111,12}, {     31,11}, \
+    {     63,10}, {    135,11}, {     79,10}, {    167,11}, \
+    {     95,10}, {    191,11}, {    111,12}, {     63,11}, \
+    {    143,10}, {    287,11}, {    159,12}, {     95,11}, \
+    {    207,13}, {     63,12}, {    127,11}, {    271,12}, \
+    {    159,11}, {    335,10}, {    671,12}, {    191,10}, \
+    {    799,12}, {    223,13}, {    127,12}, {    287,11}, \
+    {    607,12}, {    319,11}, {    671,13}, {    191,12}, \
+    {    383,11}, {    799,10}, {   1599,12}, {    415,11}, \
+    {    863,14}, {    127,13}, {    255,12}, {    543,11}, \
+    {   1119,12}, {    607,13}, {    319,12}, {    735,11}, \
+    {   1471,12}, {    863,13}, {    447,12}, {    927,11}, \
+    {   1855,12}, {    959,14}, {    255,13}, {    511,12}, \
+    {   1055,11}, {   2111,12}, {   1119,13}, {    575,12}, \
+    {   1247,13}, {    639,12}, {   1311,13}, {    703,12}, \
+    {   1471,13}, {    831,12}, {   1727,13}, {    895,12}, \
+    {   1791,13}, {    959,15}, {    255,14}, {    511,13}, \
+    {   1087,12}, {   2239,13}, {   1215,14}, {    639,13}, \
+    {   1471,14}, {    767,13}, {   1727,14}, {    895,13}, \
+    {   1855,12}, {   3711,13}, {   1919,15}, {    511,14}, \
+    {   1023,13}, {   2111,12}, {   4223,13}, {   2175,14}, \
+    {   1151,13}, {   2495,14}, {   1279,13}, {   2623,14}, \
+    {   1407,15}, {    767,14}, {   1663,13}, {   3455,14}, \
+    {   1919,16}, {    511,15}, {   1023,14}, {   2175,13}, \
+    {   4479,14}, {   2431,15}, {   1279,14}, {   2943,15}, \
+    {   1535,14}, {   3455,15}, {   1791,14}, {  16384,15}, \
+    {  32768,16}, {  65536,17}, { 131072,18}, { 262144,19}, \
+    { 524288,20}, {1048576,21}, {2097152,22}, {4194304,23}, \
+    {8388608,24} }
+#define MUL_FFT_TABLE3_SIZE 149
+#define MUL_FFT_THRESHOLD                 8576
+
+#define SQR_FFT_MODF_THRESHOLD             765  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    765, 5}, {     36, 6}, {     37, 7}, {     19, 6}, \
+    {     42, 7}, {     43, 8}, {     37, 9}, {     19, 8}, \
+    {     43, 9}, {     23, 8}, {     49, 9}, {     27, 8}, \
+    {     57, 9}, {     43,10}, {     23, 9}, {     55,10}, \
+    {     31, 9}, {     71,10}, {     39, 9}, {     83,10}, \
+    {     47, 9}, {     99,10}, {     55,11}, {     31,10}, \
+    {     87,11}, {     47,10}, {    111,12}, {     31,11}, \
+    {     63,10}, {    135,11}, {     79,10}, {    175,11}, \
+    {     95,10}, {    199,11}, {    111,12}, {     63,11}, \
+    {    159,12}, {     95,11}, {    191,10}, {    399,11}, \
+    {    207,13}, {     63,12}, {    127,10}, {    511, 9}, \
+    {   1023,10}, {    527,11}, {    271,12}, {    159,10}, \
+    {    703,12}, {    191,11}, {    399,10}, {    799,11}, \
+    {    431,12}, {    223,13}, {    127,12}, {    255,11}, \
+    {    527,10}, {   1055,11}, {    559,12}, {    287,11}, \
+    {    607,10}, {   1215,11}, {    703,13}, {    191,12}, \
+    {    383,11}, {    799,12}, {    415,11}, {    863,12}, \
+    {    447,14}, {    127,13}, {    255,12}, {    511,11}, \
+    {   1055,12}, {    543,11}, {   1119,12}, {    607,11}, \
+    {   1215,12}, {    735,13}, {    383,12}, {    799,11}, \
+    {   1599,12}, {    863,13}, {    447,12}, {    991,14}, \
+    {    255,13}, {    511,12}, {   1055,11}, {   2111,12}, \
+    {   1119,13}, {    575,12}, {   1215,13}, {    639,12}, \
+    {   1311,13}, {    703,12}, {   1407,14}, {    383,13}, \
+    {    767,12}, {   1599,13}, {    831,12}, {   1727,13}, \
+    {    895,12}, {   1791,13}, {    959,12}, {   1919,15}, \
+    {    255,14}, {    511,13}, {   1023,12}, {   2047,13}, \
+    {   1087,12}, {   2239,13}, {   1151,12}, {   2303,13}, \
+    {   1215,14}, {    639,13}, {   1279,12}, {   2559,13}, \
+    {   1471,14}, {    767,13}, {   1727,14}, {    895,13}, \
+    {   1919,15}, {    511,14}, {   1023,13}, {   2239,14}, \
+    {   1151,13}, {   2495,14}, {   1279,13}, {   2623,14}, \
+    {   1407,15}, {    767,14}, {   1663,13}, {   3455,14}, \
+    {   1919,16}, {    511,15}, {   1023,14}, {   2175,13}, \
+    {   4479,14}, {   2431,15}, {   1279,14}, {   2943,15}, \
+    {   1535,14}, {   3455,15}, {   1791,14}, {  16384,15}, \
+    {  32768,16}, {  65536,17}, { 131072,18}, { 262144,19}, \
+    { 524288,20}, {1048576,21}, {2097152,22}, {4194304,23}, \
+    {8388608,24} }
+#define SQR_FFT_TABLE3_SIZE 153
+#define SQR_FFT_THRESHOLD                 6272
+
+#define MULLO_BASECASE_THRESHOLD            39
+#define MULLO_DC_THRESHOLD                   0  /* never mpn_mullo_basecase */
+#define MULLO_MUL_N_THRESHOLD            17050
+#define SQRLO_BASECASE_THRESHOLD             0  /* always */
+#define SQRLO_DC_THRESHOLD                 134
+#define SQRLO_SQR_THRESHOLD              12322
+
+#define DC_DIV_QR_THRESHOLD                 73
+#define DC_DIVAPPR_Q_THRESHOLD             262
+#define DC_BDIV_QR_THRESHOLD               111
+#define DC_BDIV_Q_THRESHOLD                315
+
+#define INV_MULMOD_BNM1_THRESHOLD           92
+#define INV_NEWTON_THRESHOLD                15
+#define INV_APPR_THRESHOLD                  17
+
+#define BINV_NEWTON_THRESHOLD              280
+#define REDC_1_TO_REDC_2_THRESHOLD           0  /* always */
+#define REDC_2_TO_REDC_N_THRESHOLD         172
+
+#define MU_DIV_QR_THRESHOLD               1470
+#define MU_DIVAPPR_Q_THRESHOLD            1210
+#define MUPI_DIV_QR_THRESHOLD                0  /* always */
+#define MU_BDIV_QR_THRESHOLD              1566
+#define MU_BDIV_Q_THRESHOLD               1787
+
+#define POWM_SEC_TABLE  3,22,139,1867
+
+#define GET_STR_DC_THRESHOLD                14
+#define GET_STR_PRECOMPUTE_THRESHOLD        42
+#define SET_STR_DC_THRESHOLD              1339
+#define SET_STR_PRECOMPUTE_THRESHOLD      3934
+
+#define FAC_DSC_THRESHOLD                  866
+#define FAC_ODD_THRESHOLD                    0  /* always */
+
+#define MATRIX22_STRASSEN_THRESHOLD         20
+#define HGCD2_DIV1_METHOD                    3  /* 13.73% faster than 1 */
+#define HGCD_THRESHOLD                     129
+#define HGCD_APPR_THRESHOLD                202
+#define HGCD_REDUCE_THRESHOLD             4455
+#define GCD_DC_THRESHOLD                   658
+#define GCDEXT_DC_THRESHOLD                469
+#define JACOBI_BASE_METHOD                   2  /* 0.62% faster than 4 */
+
+/* Tuneup completed successfully, took 199042 seconds */
diff --git a/third_party/gmp/mpn/ia64/hamdist.asm b/third_party/gmp/mpn/ia64/hamdist.asm
new file mode 100644
index 0000000..477df4c
--- /dev/null
+++ b/third_party/gmp/mpn/ia64/hamdist.asm
@@ -0,0 +1,365 @@
+dnl  IA-64 mpn_hamdist -- mpn hamming distance.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2003-2005 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C           cycles/limb
+C Itanium:       2
+C Itanium 2:     1
+
+C INPUT PARAMETERS
+define(`up', `r32')
+define(`vp', `r33')
+define(`n', `r34')
+
+define(`u0',`r16') define(`u1',`r17') define(`u2',`r18') define(`u3',`r19')
+define(`v0',`r20') define(`v1',`r21') define(`v2',`r22') define(`v3',`r23')
+define(`x0',`r24') define(`x1',`r25') define(`x2',`r26') define(`x3',`r27')
+define(`c0',`r28') define(`c1',`r29') define(`c2',`r30') define(`c3',`r31')
+define(`s',`r8')
+
+
+ASM_START()
+PROLOGUE(mpn_hamdist)
+	.prologue
+ifdef(`HAVE_ABI_32',
+`	addp4		up = 0, up		C			M I
+	addp4		vp = 0, vp		C			M I
+	zxt4		n = n			C			I
+	;;
+')
+
+ {.mmi;	ld8		r10 = [up], 8		C load first ulimb	M01
+	ld8		r11 = [vp], 8		C load first vlimb	M01
+	mov.i		r2 = ar.lc		C save ar.lc		I0
+}{.mmi;	and		r14 = 3, n		C			M I
+	cmp.lt		p15, p0 = 4, n		C small count?		M I
+	add		n = -5, n		C			M I
+	;;
+}{.mmi;	cmp.eq		p6, p0 = 1, r14		C			M I
+	cmp.eq		p7, p0 = 2, r14		C			M I
+	cmp.eq		p8, p0 = 3, r14		C			M I
+}{.bbb
+  (p6)	br.dptk		.Lb01			C			B
+  (p7)	br.dptk		.Lb10			C			B
+  (p8)	br.dptk		.Lb11			C			B
+}
+
+
+.Lb00:	ld8		u1 = [up], 8		C			M01
+	ld8		v1 = [vp], 8		C			M01
+	shr.u		n = n, 2		C			I0
+	xor		x0 = r10, r11		C			M I
+	;;
+	ld8		u2 = [up], 8		C			M01
+	ld8		v2 = [vp], 8		C			M01
+	mov.i		ar.lc = n		C			I0
+	xor		x1 = u1, v1		C			M I
+	;;
+	ld8		u3 = [up], 8		C			M01
+	ld8		v3 = [vp], 8		C			M01
+	xor		x2 = u2, v2		C			M I
+	mov		s = 0			C			M I
+  (p15)	br.cond.dptk	.grt4			C			B
+	;;
+	popcnt		c0 = x0			C			I0
+	xor		x3 = u3, v3		C			M I
+	;;
+	popcnt		c1 = x1			C			I0
+	;;
+	popcnt		c2 = x2			C			I0
+	br		.Lcj4			C			B
+
+.grt4:	ld8		u0 = [up], 8		C			M01
+	ld8		v0 = [vp], 8		C			M01
+	xor		x1 = u1, v1		C			M I
+	;;
+	ld8		u1 = [up], 8		C			M01
+	ld8		v1 = [vp], 8		C			M01
+	xor		x2 = u2, v2		C			M I
+	;;
+	ld8		u2 = [up], 8		C			M01
+	ld8		v2 = [vp], 8		C			M01
+	popcnt		c0 = x0			C			I0
+	xor		x3 = u3, v3		C			M I
+	;;
+	ld8		u3 = [up], 8		C			M01
+	ld8		v3 = [vp], 8		C			M01
+	popcnt		c1 = x1			C			I0
+	xor		x0 = u0, v0		C			M I
+	br.cloop.dpnt	.grt8			C			B
+
+	popcnt		c2 = x2			C			I0
+	xor		x1 = u1, v1		C			M I
+	br		.Lcj8			C			B
+
+.grt8:	ld8		u0 = [up], 8		C			M01
+	ld8		v0 = [vp], 8		C			M01
+	popcnt		c2 = x2			C			I0
+	xor		x1 = u1, v1		C			M I
+	br		.LL00			C			B
+
+
+.Lb01:	xor		x3 = r10, r11		C			M I
+	shr.u		n = n, 2		C			I0
+  (p15)	br.cond.dptk	.grt1			C			B
+	;;
+	popcnt		r8 = x3			C			I0
+	br.ret.sptk.many b0			C			B
+
+.grt1:	ld8		u0 = [up], 8		C			M01
+	ld8		v0 = [vp], 8		C			M01
+	mov.i		ar.lc = n		C			I0
+	;;
+	ld8		u1 = [up], 8		C			M01
+	ld8		v1 = [vp], 8		C			M01
+	mov		s = 0			C			M I
+	;;
+	ld8		u2 = [up], 8		C			M01
+	ld8		v2 = [vp], 8		C			M01
+	;;
+	ld8		u3 = [up], 8		C			M01
+	ld8		v3 = [vp], 8		C			M01
+	xor		x0 = u0, v0		C			M I
+	br.cloop.dpnt	.grt5			C			B
+
+	xor		x1 = u1, v1		C			M I
+	;;
+	popcnt		c3 = x3			C			I0
+	xor		x2 = u2, v2		C			M I
+	;;
+	popcnt		c0 = x0			C			I0
+	xor		x3 = u3, v3		C			M I
+	;;
+	popcnt		c1 = x1			C			I0
+	br		.Lcj5			C			B
+
+.grt5:	ld8		u0 = [up], 8		C			M01
+	ld8		v0 = [vp], 8		C			M01
+	xor		x1 = u1, v1		C			M I
+	;;
+	ld8		u1 = [up], 8		C			M01
+	ld8		v1 = [vp], 8		C			M01
+	popcnt		c3 = x3			C			I0
+	xor		x2 = u2, v2		C			M I
+	;;
+	ld8		u2 = [up], 8		C			M01
+	ld8		v2 = [vp], 8		C			M01
+	popcnt		c0 = x0			C			I0
+	xor		x3 = u3, v3		C			M I
+	;;
+	ld8		u3 = [up], 8		C			M01
+	ld8		v3 = [vp], 8		C			M01
+	popcnt		c1 = x1			C			I0
+	xor		x0 = u0, v0		C			M I
+	br.cloop.dpnt	.Loop			C			B
+	br		.Lend			C			B
+
+
+.Lb10:	ld8		u3 = [up], 8		C			M01
+	ld8		v3 = [vp], 8		C			M01
+	xor		x2 = r10, r11		C			M I
+  (p15)	br.cond.dptk	.grt2			C			B
+	;;
+	xor		x3 = u3, v3		C			M I
+	;;
+	popcnt		c2 = x2			C			I0
+	;;
+	popcnt		c3 = x3			C			I0
+	;;
+	add		s = c2, c3		C			M I
+	br.ret.sptk.many b0			C			B
+
+.grt2:	ld8		u0 = [up], 8		C			M01
+	ld8		v0 = [vp], 8		C			M01
+	shr.u		n = n, 2		C			I0
+	;;
+	ld8		u1 = [up], 8		C			M01
+	ld8		v1 = [vp], 8		C			M01
+	mov.i		ar.lc = n		C			I0
+	mov		s = 0			C			M I
+	;;
+	ld8		u2 = [up], 8		C			M01
+	ld8		v2 = [vp], 8		C			M01
+	xor		x3 = u3, v3		C			M I
+	;;
+	ld8		u3 = [up], 8		C			M01
+	ld8		v3 = [vp], 8		C			M01
+	xor		x0 = u0, v0		C			M I
+	br.cloop.dptk	.grt6			C			B
+
+	popcnt		c2 = x2			C			I0
+	xor		x1 = u1, v1		C			M I
+	;;
+	popcnt		c3 = x3			C			I0
+	xor		x2 = u2, v2		C			M I
+	;;
+	popcnt		c0 = x0			C			I0
+	xor		x3 = u3, v3		C			M I
+	br		.Lcj6			C			B
+
+.grt6:	ld8		u0 = [up], 8		C			M01
+	ld8		v0 = [vp], 8		C			M01
+	popcnt		c2 = x2			C			I0
+	xor		x1 = u1, v1		C			M I
+	;;
+	ld8		u1 = [up], 8		C			M01
+	ld8		v1 = [vp], 8		C			M01
+	popcnt		c3 = x3			C			I0
+	xor		x2 = u2, v2		C			M I
+	;;
+	ld8		u2 = [up], 8		C			M01
+	ld8		v2 = [vp], 8		C			M01
+	popcnt		c0 = x0			C			I0
+	xor		x3 = u3, v3		C			M I
+	br		.LL10			C			B
+
+
+.Lb11:	ld8		u2 = [up], 8		C			M01
+	ld8		v2 = [vp], 8		C			M01
+	shr.u		n = n, 2		C			I0
+	xor		x1 = r10, r11		C			M I
+	;;
+	ld8		u3 = [up], 8		C			M01
+	ld8		v3 = [vp], 8		C			M01
+	xor		x2 = u2, v2		C			M I
+  (p15)	br.cond.dptk	.grt3			C			B
+	;;
+	xor		x3 = u3, v3		C			M I
+	;;
+	popcnt		c1 = x1			C			I0
+	;;
+	popcnt		c2 = x2			C			I0
+	;;
+	popcnt		c3 = x3			C			I0
+	;;
+	add		s = c1, c2		C			M I
+	;;
+	add		s = s, c3		C			M I
+	br.ret.sptk.many b0			C			B
+
+.grt3:	ld8		u0 = [up], 8		C			M01
+	ld8		v0 = [vp], 8		C			M01
+	mov.i		ar.lc = n		C			I0
+	;;
+	ld8		u1 = [up], 8		C			M01
+	ld8		v1 = [vp], 8		C			M01
+	mov		s = 0			C			M I
+	;;
+	ld8		u2 = [up], 8		C			M01
+	ld8		v2 = [vp], 8		C			M01
+	xor		x3 = u3, v3		C			M I
+	;;
+	ld8		u3 = [up], 8		C			M01
+	ld8		v3 = [vp], 8		C			M01
+	popcnt		c1 = x1			C			I0
+	xor		x0 = u0, v0		C			M I
+	br.cloop.dptk	.grt7			C			B
+	popcnt		c2 = x2			C			I0
+	xor		x1 = u1, v1		C			M I
+	;;
+	popcnt		c3 = x3			C			I0
+	xor		x2 = u2, v2		C			M I
+	br		.Lcj7			C			B
+
+.grt7:	ld8		u0 = [up], 8		C			M01
+	ld8		v0 = [vp], 8		C			M01
+	popcnt		c2 = x2			C			I0
+	xor		x1 = u1, v1		C			M I
+	;;
+	ld8		u1 = [up], 8		C			M01
+	ld8		v1 = [vp], 8		C			M01
+	popcnt		c3 = x3			C			I0
+	xor		x2 = u2, v2		C			M I
+	br		.LL11			C			B
+
+
+	ALIGN(32)
+.Loop:	ld8		u0 = [up], 8		C			M01
+	ld8		v0 = [vp], 8		C			M01
+	popcnt		c2 = x2			C			I0
+	add		s = s, c3		C			M I
+	xor		x1 = u1, v1		C			M I
+	nop.b		1			C			-
+	;;
+.LL00:	ld8		u1 = [up], 8		C			M01
+	ld8		v1 = [vp], 8		C			M01
+	popcnt		c3 = x3			C			I0
+	add		s = s, c0		C			M I
+	xor		x2 = u2, v2		C			M I
+	nop.b		1			C			-
+	;;
+.LL11:	ld8		u2 = [up], 8		C			M01
+	ld8		v2 = [vp], 8		C			M01
+	popcnt		c0 = x0			C			I0
+	add		s = s, c1		C			M I
+	xor		x3 = u3, v3		C			M I
+	nop.b		1			C			-
+	;;
+.LL10:	ld8		u3 = [up], 8		C			M01
+	ld8		v3 = [vp], 8		C			M01
+	popcnt		c1 = x1			C			I0
+	add		s = s, c2		C			M I
+	xor		x0 = u0, v0		C			M I
+	br.cloop.dptk	.Loop			C			B
+	;;
+
+.Lend:	popcnt		c2 = x2			C			I0
+	add		s = s, c3		C			M I
+	xor		x1 = u1, v1		C			M I
+	;;
+.Lcj8:	popcnt		c3 = x3			C			I0
+	add		s = s, c0		C			M I
+	xor		x2 = u2, v2		C			M I
+	;;
+.Lcj7:	popcnt		c0 = x0			C			I0
+	add		s = s, c1		C			M I
+	xor		x3 = u3, v3		C			M I
+	;;
+.Lcj6:	popcnt		c1 = x1			C			I0
+	add		s = s, c2		C			M I
+	;;
+.Lcj5:	popcnt		c2 = x2			C			I0
+	add		s = s, c3		C			M I
+	;;
+.Lcj4:	popcnt		c3 = x3			C			I0
+	add		s = s, c0		C			M I
+	;;
+	add		s = s, c1		C			M I
+	;;
+	add		s = s, c2		C			M I
+	;;
+	add		s = s, c3		C			M I
+	mov.i		ar.lc = r2		C			I0
+	br.ret.sptk.many b0			C			B
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/ia64/ia64-defs.m4 b/third_party/gmp/mpn/ia64/ia64-defs.m4
new file mode 100644
index 0000000..f71d280
--- /dev/null
+++ b/third_party/gmp/mpn/ia64/ia64-defs.m4
@@ -0,0 +1,147 @@
+divert(-1)
+
+
+dnl  Copyright 2000, 2002, 2003 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+dnl  ia64 assembler comments are C++ style "//" to the end of line.  gas
+dnl  also accepts "#" as a comment, if it's the first non-blank on a line.
+dnl
+dnl  BSD m4 can't handle a multi-character comment like "//" (see notes in
+dnl  mpn/asm-defs.m4).  For now the default "#" is left, but with care taken
+dnl  not to put any macros after "foo#" (since of course they won't expand).
+
+
+define(`ASM_START',
+m4_assert_numargs(0)
+`')
+
+
+dnl  Called: PROLOGUE_cpu(GSYM_PREFIX`'foo)
+dnl          EPILOGUE_cpu(GSYM_PREFIX`'foo)
+dnl
+dnl  32-byte alignment is used for the benefit of itanium-2, where the code
+dnl  fetcher will only take 2 bundles from a 32-byte aligned target.  At
+dnl  16mod32 it only reads 1 in the first cycle.  This might not make any
+dnl  difference if the rotate buffers are full or there's other work holding
+dnl  up execution, but we use 32-bytes to give the best chance of peak
+dnl  throughput.
+dnl
+dnl  We can use .align here despite the gas bug noted in mpn/ia64/README,
+dnl  since we're not expecting to execute across a PROLOGUE(), at least not
+dnl  currently.
+
+define(`PROLOGUE_cpu',
+m4_assert_numargs(1)
+	`
+	.text
+	.align	32
+	.global	$1#
+	.proc	$1#
+$1:')
+
+define(`EPILOGUE_cpu',
+m4_assert_numargs(1)
+	`
+	.endp	$1#
+')
+
+define(`DATASTART',
+	`dnl
+	DATA
+$1:')
+define(`DATAEND',`dnl')
+
+define(`ASM_END',`dnl')
+
+
+dnl  Usage: ALIGN(bytes)
+dnl
+dnl  Emit a ".align" directive.  "bytes" is eval()ed, so can be an
+dnl  expression.
+dnl
+dnl  This version overrides the definition in mpn/asm-defs.m4.  We suppress
+dnl  any .align if the gas byte-swapped-nops bug was detected by configure
+dnl  GMP_ASM_IA64_ALIGN_OK.
+
+define(`ALIGN',
+m4_assert_numargs(1)
+m4_assert_defined(`IA64_ALIGN_OK')
+`ifelse(IA64_ALIGN_OK,no,,
+`.align	eval($1)')')
+
+
+dnl  Usage: ASSERT([pr] [,code])
+dnl
+dnl  Require that the given predicate register is true after executing the
+dnl  test code.  For example,
+dnl
+dnl         ASSERT(p6,
+dnl         `       cmp.eq  p6,p0 = r3, r4')
+dnl
+dnl  If the predicate register argument is empty then nothing is tested, the
+dnl  code is just executed.  This can be used for setups required by later
+dnl  ASSERTs.  The code argument can be omitted to just test a predicate
+dnl  with no special setup code.
+dnl
+dnl  For convenience, stops are inserted before and after the code emitted.
+
+define(ASSERT,
+m4_assert_numargs_range(1,2)
+m4_assert_defined(`WANT_ASSERT')
+`ifelse(WANT_ASSERT,1,
+`	;;
+ifelse(`$2',,,
+`$2
+	;;
+')
+ifelse(`$1',,,
+`($1)	br	.LASSERTok`'ASSERT_label_counter ;;
+	cmp.ne	p6,p6 = r0, r0	C illegal instruction
+	;;
+.LASSERTok`'ASSERT_label_counter:
+define(`ASSERT_label_counter',eval(ASSERT_label_counter+1))
+')
+')')
+define(`ASSERT_label_counter',1)
+
+define(`getfsig', `getf.sig')
+define(`setfsig', `setf.sig')
+define(`cmpeq',   `cmp.eq')
+define(`cmpne',   `cmp.ne')
+define(`cmpltu',  `cmp.ltu')
+define(`cmpleu',  `cmp.leu')
+define(`cmpgtu',  `cmp.gtu')
+define(`cmpgeu',  `cmp.geu')
+define(`cmple',   `cmp.le')
+define(`cmpgt',   `cmp.gt')
+define(`cmpeqor', `cmp.eq.or')
+define(`cmpequc', `cmp.eq.unc')
+
+divert
diff --git a/third_party/gmp/mpn/ia64/invert_limb.asm b/third_party/gmp/mpn/ia64/invert_limb.asm
new file mode 100644
index 0000000..5effdda
--- /dev/null
+++ b/third_party/gmp/mpn/ia64/invert_limb.asm
@@ -0,0 +1,105 @@
+dnl  IA-64 mpn_invert_limb -- Invert a normalized limb.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund and Kevin Ryde.
+
+dnl  Copyright 2000, 2002, 2004 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C d = r32
+
+C           cycles
+C Itanium:    74
+C Itanium 2:  50+6
+
+C It should be possible to avoid the xmpy.hu and the following tests by
+C explicitly chopping in the last fma.  That would save about 10 cycles.
+
+ASM_START()
+	.sdata
+	.align 16
+ifdef(`HAVE_DOUBLE_IEEE_LITTLE_ENDIAN',`
+.LC0:	data4 0x00000000, 0x80000000, 0x0000403f, 0x00000000	C 2^64
+.LC1:	data4 0x00000000, 0x80000000, 0x0000407f, 0x00000000	C 2^128
+
+',`ifdef(`HAVE_DOUBLE_IEEE_BIG_ENDIAN',`
+.LC0:	data4 0x403f8000, 0x00000000, 0x00000000, 0x00000000	C 2^64
+.LC1:	data4 0x407f8000, 0x00000000, 0x00000000, 0x00000000	C 2^128
+
+',`m4_error(`Oops, need to know float endianness
+')')')
+
+
+PROLOGUE(mpn_invert_limb)
+		C 00
+	addl		r14 = @gprel(.LC0), gp
+	addl		r15 = @gprel(.LC1), gp
+	setf.sig	f7 = r32
+	add		r9 = r32, r32		C check for d = 2^63
+	;;	C 01
+	ldfe		f10 = [r14]		C 2^64
+	ldfe		f8 = [r15]		C 2^128
+	cmp.eq		p6, p0 = 0, r9		C check for d = 2^63
+	mov		r8 = -1			C retval for 2^63
+   (p6)	br.ret.spnt.many b0
+	;;	C 07
+	fmpy.s1		f11 = f7, f10		C f11 = d * 2^64
+	fnma.s1		f6 = f7, f10, f8	C f6 = 2^128 - d * 2^64
+	;;	C 11
+	frcpa.s1	f8, p6 = f6, f7
+	;;	C 15
+   (p6)	fnma.s1		f9 = f7, f8, f1
+   (p6)	fmpy.s1		f10 = f6, f8
+	;;	C 19
+   (p6)	fmpy.s1		f11 = f9, f9
+   (p6)	fma.s1		f10 = f9, f10, f10
+	;;	C 23
+   (p6)	fma.s1		f8 = f9, f8, f8
+   (p6)	fma.s1		f9 = f11, f10, f10
+	;;	C 27
+   (p6)	fma.s1		f8 = f11, f8, f8
+   (p6)	fnma.s1		f10 = f7, f9, f6
+	;;	C 31
+   (p6)	fma.s1		f8 = f10, f8, f9
+	;;	C 35
+	fcvt.fxu.trunc.s1 f8 = f8
+	;;	C 39
+	getf.sig	r8 = f8
+	xmpy.hu		f10 = f8, f7		C di * d
+	;;	C 43
+	getf.sig	r14 = f10
+	andcm		r9 = -1, r32		C one's complement
+	;;	C 48
+	cmp.ltu		p6, p0 = r9, r14	C got overflow?
+	;;	C 49
+   (p6)	add		r8 = -1, r8		C adjust di down
+	br.ret.sptk.many b0
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/ia64/logops_n.asm b/third_party/gmp/mpn/ia64/logops_n.asm
new file mode 100644
index 0000000..e4a2f61
--- /dev/null
+++ b/third_party/gmp/mpn/ia64/logops_n.asm
@@ -0,0 +1,292 @@
+dnl  IA-64 mpn_and_n, mpn_andn_n, mpn_nand_n, mpn_ior_n, mpn_iorn_n,
+dnl  mpn_nior_n, mpn_xor_n, mpn_xnor_n -- mpn bitwise logical operations.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2003-2005 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C           cycles/limb
+C Itanium:      2
+C Itanium 2:    1
+
+C TODO
+C  * Use rp,rpx scheme of aors_n.asm to allow parallel stores (useful in
+C    wind-down code).
+
+C INPUT PARAMETERS
+define(`rp', `r32')
+define(`up', `r33')
+define(`vp', `r34')
+define(`n', `r35')
+
+ifdef(`OPERATION_and_n',
+`	define(`func',`mpn_and_n')
+	define(`logop',		`and	$1 = $2, $3')
+	define(`notormov',	`mov	$1 = $2')')
+ifdef(`OPERATION_andn_n',
+`	define(`func',`mpn_andn_n')
+	define(`logop',		`andcm	$1 = $2, $3')
+	define(`notormov',	`mov	$1 = $2')')
+ifdef(`OPERATION_nand_n',
+`	define(`func',`mpn_nand_n')
+	define(`logop',		`and	$1 = $2, $3')
+	define(`notormov',	`sub	$1 = -1, $2')')
+ifdef(`OPERATION_ior_n',
+`	define(`func',`mpn_ior_n')
+	define(`logop',		`or	$1 = $2, $3')
+	define(`notormov',	`mov	$1 = $2')')
+ifdef(`OPERATION_iorn_n',
+`	define(`func',`mpn_iorn_n')
+	define(`logop',		`andcm	$1 = $3, $2')
+	define(`notormov',	`sub	$1 = -1, $2')')
+ifdef(`OPERATION_nior_n',
+`	define(`func',`mpn_nior_n')
+	define(`logop',		`or	$1 = $2, $3')
+	define(`notormov',	`sub	$1 = -1, $2')')
+ifdef(`OPERATION_xor_n',
+`	define(`func',`mpn_xor_n')
+	define(`logop',		`xor	$1 = $2, $3')
+	define(`notormov',	`mov	$1 = $2')')
+ifdef(`OPERATION_xnor_n',
+`	define(`func',`mpn_xnor_n')
+	define(`logop',		`xor	$1 = $2, $3')
+	define(`notormov',	`sub	$1 = -1, $2')')
+
+MULFUNC_PROLOGUE(mpn_and_n mpn_andn_n mpn_nand_n mpn_ior_n mpn_iorn_n mpn_nior_n mpn_xor_n mpn_xnor_n)
+
+ASM_START()
+PROLOGUE(func)
+	.prologue
+	.save	ar.lc, r2
+	.body
+ifdef(`HAVE_ABI_32',
+`	addp4	rp = 0, rp			C			M I
+	addp4	up = 0, up			C			M I
+	addp4	vp = 0, vp			C			M I
+	nop.m		0
+	nop.m		0
+	zxt4	n = n				C			I
+	;;
+')
+{.mmi
+	ld8		r10 = [up], 8		C			M
+	ld8		r11 = [vp], 8		C			M
+	mov.i		r2 = ar.lc		C			I0
+}
+{.mmi
+	and		r14 = 3, n		C			M I
+	cmp.lt		p15, p14 = 4, n		C			M I
+	shr.u		n = n, 2		C			I0
+	;;
+}
+{.mmi
+	cmp.eq		p6, p0 = 1, r14		C			M I
+	cmp.eq		p7, p0 = 2, r14		C			M I
+	cmp.eq		p8, p0 = 3, r14		C			M I
+}
+{.bbb
+   (p6)	br.dptk		.Lb01			C			B
+   (p7)	br.dptk		.Lb10			C			B
+   (p8)	br.dptk		.Lb11			C			B
+}
+
+.Lb00:	ld8		r17 = [up], 8		C			M
+	ld8		r21 = [vp], 8		C			M
+	add		n = -2, n		C			M I
+	;;
+	ld8		r18 = [up], 8		C			M
+	ld8		r22 = [vp], 8		C			M
+	;;
+	ld8		r19 = [up], 8		C			M
+	ld8		r23 = [vp], 8		C			M
+  (p15)	br.cond.dpnt	.grt4			C			B
+
+	logop(		r14, r10, r11)		C			M I
+	;;
+	logop(		r15, r17, r21)		C			M I
+	notormov(	r8, r14)		C			M I
+	br		.Lcj4			C			B
+
+.grt4:	logop(		r14, r10, r11)		C			M I
+	ld8		r16 = [up], 8		C			M
+	ld8		r20 = [vp], 8		C			M
+	;;
+	logop(		r15, r17, r21)		C			M I
+	ld8		r17 = [up], 8		C			M
+	mov.i		ar.lc = n		C			I0
+	notormov(	r8, r14)		C			M I
+	ld8		r21 = [vp], 8		C			M
+	br		.LL00			C			B
+
+.Lb01:	add		n = -1, n		C			M I
+	logop(		r15, r10, r11)		C			M I
+  (p15)	br.cond.dpnt	.grt1			C			B
+	;;
+
+	notormov(	r9, r15)		C			M I
+	br		.Lcj1			C			B
+
+.grt1:	ld8		r16 = [up], 8		C			M
+	ld8		r20 = [vp], 8		C			M
+	;;
+	ld8		r17 = [up], 8		C			M
+	ld8		r21 = [vp], 8		C			M
+	mov.i		ar.lc = n		C			I0
+	;;
+	ld8		r18 = [up], 8		C			M
+	ld8		r22 = [vp], 8		C			M
+	;;
+	ld8		r19 = [up], 8		C			M
+	ld8		r23 = [vp], 8		C			M
+	br.cloop.dptk	.grt5			C			B
+	;;
+
+	logop(		r14, r16, r20)		C			M I
+	notormov(	r9, r15)		C			M I
+	br		.Lcj5			C			B
+
+.grt5:	logop(		r14, r16, r20)		C			M I
+	ld8		r16 = [up], 8		C			M
+	notormov(	r9, r15)		C			M I
+	ld8		r20 = [vp], 8		C			M
+	br		.LL01			C			B
+
+.Lb10:	ld8		r19 = [up], 8		C			M
+	ld8		r23 = [vp], 8		C			M
+  (p15)	br.cond.dpnt	.grt2			C			B
+
+	logop(		r14, r10, r11)		C			M I
+	;;
+	logop(		r15, r19, r23)		C			M I
+	notormov(	r8, r14)		C			M I
+	br		.Lcj2			C			B
+
+.grt2:	ld8		r16 = [up], 8		C			M
+	ld8		r20 = [vp], 8		C			M
+	add		n = -1, n		C			M I
+	;;
+	ld8		r17 = [up], 8		C			M
+	ld8		r21 = [vp], 8		C			M
+	logop(		r14, r10, r11)		C			M I
+	;;
+	ld8		r18 = [up], 8		C			M
+	ld8		r22 = [vp], 8		C			M
+	mov.i		ar.lc = n		C			I0
+	;;
+	logop(		r15, r19, r23)		C			M I
+	ld8		r19 = [up], 8		C			M
+	notormov(	r8, r14)		C			M I
+	ld8		r23 = [vp], 8		C			M
+	br.cloop.dptk	.Loop			C			B
+	br		.Lcj6			C			B
+
+.Lb11:	ld8		r18 = [up], 8		C			M
+	ld8		r22 = [vp], 8		C			M
+	add		n = -1, n		C			M I
+	;;
+	ld8		r19 = [up], 8		C			M
+	ld8		r23 = [vp], 8		C			M
+	logop(		r15, r10, r11)		C			M I
+  (p15)	br.cond.dpnt	.grt3			C			B
+	;;
+
+	logop(		r14, r18, r22)		C			M I
+	notormov(	r9, r15)		C			M I
+	br		.Lcj3			C			B
+
+.grt3:	ld8		r16 = [up], 8		C			M
+	ld8		r20 = [vp], 8		C			M
+	;;
+	ld8		r17 = [up], 8		C			M
+	ld8		r21 = [vp], 8		C			M
+	mov.i		ar.lc = n		C			I0
+	;;
+	logop(		r14, r18, r22)		C			M I
+	ld8		r18 = [up], 8		C			M
+	notormov(	r9, r15)		C			M I
+	ld8		r22 = [vp], 8		C			M
+	br		.LL11			C			B
+
+C *** MAIN LOOP START ***
+	ALIGN(32)
+.Loop:	st8		[rp] = r8, 8		C			M
+	logop(		r14, r16, r20)		C			M I
+	notormov(	r9, r15)		C			M I
+	ld8		r16 = [up], 8		C			M
+	ld8		r20 = [vp], 8		C			M
+	nop.b		0
+	;;
+.LL01:	st8		[rp] = r9, 8		C			M
+	logop(		r15, r17, r21)		C			M I
+	notormov(	r8, r14)		C			M I
+	ld8		r17 = [up], 8		C			M
+	ld8		r21 = [vp], 8		C			M
+	nop.b		0
+	;;
+.LL00:	st8		[rp] = r8, 8		C			M
+	logop(		r14, r18, r22)		C			M I
+	notormov(	r9, r15)		C			M I
+	ld8		r18 = [up], 8		C			M
+	ld8		r22 = [vp], 8		C			M
+	nop.b		0
+	;;
+.LL11:	st8		[rp] = r9, 8		C			M
+	logop(		r15, r19, r23)		C			M I
+	notormov(	r8, r14)		C			M I
+	ld8		r19 = [up], 8		C			M
+	ld8		r23 = [vp], 8		C			M
+	br.cloop.dptk	.Loop	;;		C			B
+C *** MAIN LOOP END ***
+
+.Lcj6:	st8		[rp] = r8, 8		C			M
+	logop(		r14, r16, r20)		C			M I
+	notormov(	r9, r15)		C			M I
+	;;
+.Lcj5:	st8		[rp] = r9, 8		C			M
+	logop(		r15, r17, r21)		C			M I
+	notormov(	r8, r14)		C			M I
+	;;
+.Lcj4:	st8		[rp] = r8, 8		C			M
+	logop(		r14, r18, r22)		C			M I
+	notormov(	r9, r15)		C			M I
+	;;
+.Lcj3:	st8		[rp] = r9, 8		C			M
+	logop(		r15, r19, r23)		C			M I
+	notormov(	r8, r14)		C			M I
+	;;
+.Lcj2:	st8		[rp] = r8, 8		C			M
+	notormov(	r9, r15)		C			M I
+	;;
+.Lcj1:	st8		[rp] = r9, 8		C			M
+	mov.i		ar.lc = r2		C			I0
+	br.ret.sptk.many b0			C			B
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/ia64/lorrshift.asm b/third_party/gmp/mpn/ia64/lorrshift.asm
new file mode 100644
index 0000000..694aaf0
--- /dev/null
+++ b/third_party/gmp/mpn/ia64/lorrshift.asm
@@ -0,0 +1,358 @@
+dnl  IA-64 mpn_lshift/mpn_rshift.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2000-2005 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C           cycles/limb
+C Itanium:      2
+C Itanium 2:    1
+
+C This code is scheduled deeply since the plain shift instructions shr and shl
+C have a latency of 4 (on Itanium) or 3 (on Itanium 2).  Poor scheduling of
+C these instructions cause a 10 cycle replay trap on Itanium.
+
+C The ld8 scheduling should probably be decreased to make the function smaller.
+C Good lfetch  will make sure we never stall anyway.
+
+C We should actually issue the first ld8 at cycle 0, and the first BSH/FSH pair
+C at cycle 2.  Judicious use of predicates could allow us to issue more ld8's
+C in the prologue.
+
+
+C INPUT PARAMETERS
+define(`rp', `r32')
+define(`up', `r33')
+define(`n',  `r34')
+define(`cnt',`r35')
+
+define(`tnc',`r9')
+
+ifdef(`OPERATION_lshift',`
+	define(`FSH',`shl')
+	define(`BSH',`shr.u')
+	define(`UPD',`-8')
+	define(`POFF',`-512')
+	define(`PUPD',`-32')
+	define(`func',`mpn_lshift')
+')
+ifdef(`OPERATION_rshift',`
+	define(`FSH',`shr.u')
+	define(`BSH',`shl')
+	define(`UPD',`8')
+	define(`POFF',`512')
+	define(`PUPD',`32')
+	define(`func',`mpn_rshift')
+')
+
+MULFUNC_PROLOGUE(mpn_lshift mpn_rshift)
+
+ASM_START()
+PROLOGUE(func)
+	.prologue
+	.save	ar.lc, r2
+	.body
+ifdef(`HAVE_ABI_32',
+`	addp4	rp = 0, rp		C			M I
+	addp4	up = 0, up		C		M I
+	sxt4	n = n			C		M I
+	nop.m		0
+	nop.m		0
+	zxt4	cnt = cnt		C		I
+	;;
+')
+
+ {.mmi;	cmp.lt	p14, p15 = 4, n		C		M I
+	and	r14 = 3, n		C		M I
+	mov.i	r2 = ar.lc		C		I0
+}{.mmi;	add	r15 = -1, n		C		M I
+	sub	tnc = 64, cnt		C		M I
+	add	r16 = -5, n
+	;;
+}{.mmi;	cmp.eq	p6, p0 = 1, r14		C		M I
+	cmp.eq	p7, p0 = 2, r14		C		M I
+	shr.u	n = r16, 2		C		I0
+}{.mmi;	cmp.eq	p8, p0 = 3, r14		C		M I
+ifdef(`OPERATION_lshift',
+`	shladd	up = r15, 3, up		C		M I
+	shladd	rp = r15, 3, rp')	C		M I
+	;;
+}{.mmi;	add	r11 = POFF, up		C		M I
+	ld8	r10 = [up], UPD		C		M01
+	mov.i	ar.lc = n		C		I0
+}{.bbb;
+   (p6)	br.dptk	.Lb01
+   (p7)	br.dptk	.Lb10
+   (p8)	br.dptk	.Lb11
+	;; }
+
+.Lb00:	ld8	r19 = [up], UPD
+	;;
+	ld8	r16 = [up], UPD
+	;;
+	ld8	r17 = [up], UPD
+	BSH	r8 = r10, tnc		C function return value
+	;;
+	FSH	r24 = r10, cnt
+	BSH	r25 = r19, tnc
+  (p14)	br.cond.dptk	.grt4
+	;;
+	FSH	r26 = r19, cnt
+	BSH	r27 = r16, tnc
+	;;
+	FSH	r20 = r16, cnt
+	BSH	r21 = r17, tnc
+	;;
+	or	r14 = r25, r24
+	FSH	r22 = r17, cnt
+	BSH	r23 = r10, tnc
+	br	.Lr4
+
+.grt4:	ld8	r18 = [up], UPD
+	FSH	r26 = r19, cnt
+	BSH	r27 = r16, tnc
+	;;
+	ld8	r19 = [up], UPD
+	FSH	r20 = r16, cnt
+	BSH	r21 = r17, tnc
+	;;
+	ld8	r16 = [up], UPD
+	FSH	r22 = r17, cnt
+	BSH	r23 = r18, tnc
+	;;
+	or	r14 = r25, r24
+	ld8	r17 = [up], UPD
+	br.cloop.dpnt	.Ltop
+	br	.Lbot
+
+.Lb01:
+  (p15)	BSH	r8 = r10, tnc		C function return value	I
+  (p15)	FSH	r22 = r10, cnt		C		I
+  (p15)	br.cond.dptk	.Lr1		C return	B
+
+.grt1:	ld8	r18 = [up], UPD
+	;;
+	ld8	r19 = [up], UPD
+	BSH	r8 = r10, tnc		C function return value
+	;;
+	ld8	r16 = [up], UPD
+	FSH	r22 = r10, cnt
+	BSH	r23 = r18, tnc
+	;;
+	ld8	r17 = [up], UPD
+	FSH	r24 = r18, cnt
+	BSH	r25 = r19, tnc
+	br.cloop.dpnt	.grt5
+	;;
+	or	r15 = r23, r22
+	FSH	r26 = r19, cnt
+	BSH	r27 = r16, tnc
+	;;
+	FSH	r20 = r16, cnt
+	BSH	r21 = r17, tnc
+	br	.Lr5
+
+.grt5:	ld8	r18 = [up], UPD
+	FSH	r26 = r19, cnt
+	BSH	r27 = r16, tnc
+	;;
+	ld8	r19 = [up], UPD
+	FSH	r20 = r16, cnt
+	BSH	r21 = r17, tnc
+	;;
+	or	r15 = r23, r22
+	ld8	r16 = [up], UPD
+	br	.LL01
+
+
+.Lb10:	ld8	r17 = [up], UPD
+  (p14)	br.cond.dptk	.grt2
+
+	BSH	r8 = r10, tnc		C function return value
+	;;
+	FSH	r20 = r10, cnt
+	BSH	r21 = r17, tnc
+	;;
+	or	r14 = r21, r20
+	FSH	r22 = r17, cnt
+	br	.Lr2			C return
+
+.grt2:	ld8	r18 = [up], UPD
+	BSH	r8 = r10, tnc		C function return value
+	;;
+	ld8	r19 = [up], UPD
+	FSH	r20 = r10, cnt
+	BSH	r21 = r17, tnc
+	;;
+	ld8	r16 = [up], UPD
+	FSH	r22 = r17, cnt
+	BSH	r23 = r18, tnc
+	;;
+ {.mmi;	ld8	r17 = [up], UPD
+	or	r14 = r21, r20
+	FSH	r24 = r18, cnt
+}{.mib;	nop	0
+	BSH	r25 = r19, tnc
+	br.cloop.dpnt	.grt6
+	;; }
+
+	FSH	r26 = r19, cnt
+	BSH	r27 = r16, tnc
+	br	.Lr6
+
+.grt6:	ld8	r18 = [up], UPD
+	FSH	r26 = r19, cnt
+	BSH	r27 = r16, tnc
+	;;
+	ld8	r19 = [up], UPD
+	br	.LL10
+
+
+.Lb11:	ld8	r16 = [up], UPD
+	;;
+	ld8	r17 = [up], UPD
+	BSH	r8 = r10, tnc		C function return value
+  (p14)	br.cond.dptk	.grt3
+	;;
+
+	FSH	r26 = r10, cnt
+	BSH	r27 = r16, tnc
+	;;
+	FSH	r20 = r16, cnt
+	BSH	r21 = r17, tnc
+	;;
+	or	r15 = r27, r26
+	FSH	r22 = r17, cnt
+	br	.Lr3			C return
+
+.grt3:	ld8	r18 = [up], UPD
+	FSH	r26 = r10, cnt
+	BSH	r27 = r16, tnc
+	;;
+	ld8	r19 = [up], UPD
+	FSH	r20 = r16, cnt
+	BSH	r21 = r17, tnc
+	;;
+	ld8	r16 = [up], UPD
+	FSH	r22 = r17, cnt
+	BSH	r23 = r18, tnc
+	;;
+	ld8	r17 = [up], UPD
+	br.cloop.dpnt	.grt7
+
+	or	r15 = r27, r26
+	FSH	r24 = r18, cnt
+	BSH	r25 = r19, tnc
+	br	.Lr7
+
+.grt7:	or	r15 = r27, r26
+	FSH	r24 = r18, cnt
+	BSH	r25 = r19, tnc
+	ld8	r18 = [up], UPD
+	br	.LL11
+
+C *** MAIN LOOP START ***
+	ALIGN(32)
+.Ltop:
+ {.mmi;	st8	[rp] = r14, UPD		C M2
+	or	r15 = r27, r26		C M3
+	FSH	r24 = r18, cnt		C I0
+}{.mmi;	ld8	r18 = [up], UPD		C M1
+	lfetch	[r11], PUPD
+	BSH	r25 = r19, tnc		C I1
+	;; }
+.LL11:
+ {.mmi;	st8	[rp] = r15, UPD
+	or	r14 = r21, r20
+	FSH	r26 = r19, cnt
+}{.mmi;	ld8	r19 = [up], UPD
+	nop.m	0
+	BSH	r27 = r16, tnc
+	;; }
+.LL10:
+ {.mmi;	st8	[rp] = r14, UPD
+	or	r15 = r23, r22
+	FSH	r20 = r16, cnt
+}{.mmi;	ld8	r16 = [up], UPD
+	nop.m	0
+	BSH	r21 = r17, tnc
+	;; }
+.LL01:
+ {.mmi;	st8	[rp] = r15, UPD
+	or	r14 = r25, r24
+	FSH	r22 = r17, cnt
+}{.mib;	ld8	r17 = [up], UPD
+	BSH	r23 = r18, tnc
+	br.cloop.dptk	.Ltop
+	;; }
+C *** MAIN LOOP END ***
+
+.Lbot:
+ {.mmi;	st8	[rp] = r14, UPD
+	or	r15 = r27, r26
+	FSH	r24 = r18, cnt
+}{.mib;	nop	0
+	BSH	r25 = r19, tnc
+	nop	0
+	;; }
+.Lr7:
+ {.mmi;	st8	[rp] = r15, UPD
+	or	r14 = r21, r20
+	FSH	r26 = r19, cnt
+}{.mib;	nop	0
+	BSH	r27 = r16, tnc
+	nop	0
+	;; }
+.Lr6:
+ {.mmi;	st8	[rp] = r14, UPD
+	or	r15 = r23, r22
+	FSH	r20 = r16, cnt
+}{.mib;	nop	0
+	BSH	r21 = r17, tnc
+	nop	0
+	;; }
+.Lr5:	st8	[rp] = r15, UPD
+	or	r14 = r25, r24
+	FSH	r22 = r17, cnt
+	;;
+.Lr4:	st8	[rp] = r14, UPD
+	or	r15 = r27, r26
+	;;
+.Lr3:	st8	[rp] = r15, UPD
+	or	r14 = r21, r20
+	;;
+.Lr2:	st8	[rp] = r14, UPD
+	;;
+.Lr1:	st8	[rp] = r22, UPD		C		M23
+	mov	ar.lc = r2		C		I0
+	br.ret.sptk.many b0		C		B
+EPILOGUE(func)
+ASM_END()
diff --git a/third_party/gmp/mpn/ia64/lshiftc.asm b/third_party/gmp/mpn/ia64/lshiftc.asm
new file mode 100644
index 0000000..e8cec87
--- /dev/null
+++ b/third_party/gmp/mpn/ia64/lshiftc.asm
@@ -0,0 +1,463 @@
+dnl  IA-64 mpn_lshiftc.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2000-2005, 2010 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C           cycles/limb
+C Itanium:      ?
+C Itanium 2:    1.25
+
+C This code is scheduled deeply since the plain shift instructions shr and shl
+C have a latency of 4 (on Itanium) or 3 (on Itanium 2).  Poor scheduling of
+C these instructions cause a 10 cycle replay trap on Itanium.
+
+C The ld8 scheduling should probably be decreased to make the function smaller.
+C Good lfetch  will make sure we never stall anyway.
+
+C We should actually issue the first ld8 at cycle 0, and the first BSH/FSH pair
+C at cycle 2.  Judicious use of predicates could allow us to issue more ld8's
+C in the prologue.
+
+
+C INPUT PARAMETERS
+define(`rp', `r32')
+define(`up', `r33')
+define(`n',  `r34')
+define(`cnt',`r35')
+
+define(`tnc',`r9')
+
+define(`FSH',`shl')
+define(`BSH',`shr.u')
+define(`UPD',`-8')
+define(`POFF',`-512')
+define(`PUPD',`-32')
+define(`func',`mpn_lshiftc')
+
+ASM_START()
+PROLOGUE(mpn_lshiftc)
+	.prologue
+	.save	ar.lc, r2
+	.body
+ifdef(`HAVE_ABI_32',
+`	addp4	rp = 0, rp		C				M I
+	addp4	up = 0, up		C				M I
+	sxt4	n = n			C				M I
+	nop.m		0
+	nop.m		0
+	zxt4	cnt = cnt		C				I
+	;;
+')
+
+ {.mmi;	nop	0			C				M I
+	and	r14 = 3, n		C				M I
+	mov.i	r2 = ar.lc		C				I0
+}{.mmi;	add	r15 = -1, n		C				M I
+	sub	tnc = 64, cnt		C				M I
+	nop	0
+	;;
+}{.mmi;	cmp.eq	p6, p0 = 1, r14		C				M I
+	cmp.eq	p7, p0 = 2, r14		C				M I
+	shr.u	n = r15, 2		C				I0
+}{.mmi;	cmp.eq	p8, p0 = 3, r14		C				M I
+	shladd	up = r15, 3, up		C				M I
+	shladd	rp = r15, 3, rp		C				M I
+	;;
+}{.mmi;	add	r11 = POFF, up		C				M I
+	ld8	r10 = [up], UPD		C				M01
+	mov.i	ar.lc = n		C				I0
+}{.bbb;
+   (p6)	br.dptk	.Lb01
+   (p7)	br.dptk	.Lb10
+   (p8)	br.dptk	.Lb11
+	;; }
+
+.Lb00:
+	ld8	r19 = [up], UPD
+	;;
+	ld8	r16 = [up], UPD
+	;;
+	ld8	r17 = [up], UPD
+	BSH	r8 = r10, tnc
+	br.cloop.dptk	L(gt4)
+	;;
+	FSH	r24 = r10, cnt
+	BSH	r25 = r19, tnc
+	;;
+	FSH	r26 = r19, cnt
+	BSH	r27 = r16, tnc
+	;;
+	FSH	r20 = r16, cnt
+	BSH	r21 = r17, tnc
+	;;
+	or	r14 = r25, r24
+	FSH	r22 = r17, cnt
+	;;
+	or	r15 = r27, r26
+	sub	r31 = -1, r14
+	br	.Lr4
+
+L(gt4):
+ {.mmi;	nop	0
+	nop	0
+	FSH	r24 = r10, cnt
+}{.mmi;	ld8	r18 = [up], UPD
+	nop	0
+	BSH	r25 = r19, tnc
+	;; }
+ {.mmi;	nop	0
+	nop	0
+	FSH	r26 = r19, cnt
+}{.mmi;	ld8	r19 = [up], UPD
+	nop	0
+	BSH	r27 = r16, tnc
+	;; }
+ {.mmi;	nop	0
+	nop	0
+	FSH	r20 = r16, cnt
+}{.mmi;	ld8	r16 = [up], UPD
+	nop	0
+	BSH	r21 = r17, tnc
+	;; }
+ {.mmi;	nop	0
+	or	r14 = r25, r24
+	FSH	r22 = r17, cnt
+}{.mib;	ld8	r17 = [up], UPD
+	BSH	r23 = r18, tnc
+	br.cloop.dptk	L(gt8)
+	;; }
+ {.mmi;	nop	0
+	or	r15 = r27, r26
+	FSH	r24 = r18, cnt
+}{.mib;	sub	r31 = -1, r14
+	BSH	r25 = r19, tnc
+	br	.Lr8 }
+
+L(gt8):
+	or	r15 = r27, r26
+	FSH	r24 = r18, cnt
+	ld8	r18 = [up], UPD
+	sub	r31 = -1, r14
+	BSH	r25 = r19, tnc
+	br	.LL00
+
+.Lb01:
+	br.cloop.dptk	L(gt1)
+	;;
+	BSH	r8 = r10, tnc
+	FSH	r22 = r10, cnt
+	;;
+	sub	r31 = -1, r22
+	br	.Lr1
+	;;
+L(gt1):
+	ld8	r18 = [up], UPD
+	BSH	r8 = r10, tnc
+	FSH	r22 = r10, cnt
+	;;
+	ld8	r19 = [up], UPD
+	;;
+	ld8	r16 = [up], UPD
+	;;
+	ld8	r17 = [up], UPD
+	BSH	r23 = r18, tnc
+	br.cloop.dptk	L(gt5)
+	;;
+	nop	0
+	FSH	r24 = r18, cnt
+	BSH	r25 = r19, tnc
+	;;
+	nop	0
+	FSH	r26 = r19, cnt
+	BSH	r27 = r16, tnc
+	;;
+	or	r15 = r23, r22
+	FSH	r20 = r16, cnt
+	BSH	r21 = r17, tnc
+	;;
+	or	r14 = r25, r24
+	FSH	r22 = r17, cnt
+	sub	r31 = -1, r15
+	br	.Lr5
+
+L(gt5):
+ {.mmi;	nop	0
+	nop	0
+	FSH	r24 = r18, cnt
+}{.mmi;	ld8	r18 = [up], UPD
+	nop	0
+	BSH	r25 = r19, tnc
+	;; }
+ {.mmi;	nop	0
+	nop	0
+	FSH	r26 = r19, cnt
+}{.mmi;	ld8	r19 = [up], UPD
+	nop	0
+	BSH	r27 = r16, tnc
+	;; }
+ {.mmi;	nop	0
+	or	r15 = r23, r22
+	FSH	r20 = r16, cnt
+}{.mmi;	ld8	r16 = [up], UPD
+	nop	0
+	BSH	r21 = r17, tnc
+	;; }
+ {.mmi;	or	r14 = r25, r24
+	sub	r31 = -1, r15
+	FSH	r22 = r17, cnt
+}{.mib;	ld8	r17 = [up], UPD
+	BSH	r23 = r18, tnc
+	br	L(end)
+	;; }
+
+.Lb10:
+	ld8	r17 = [up], UPD
+	br.cloop.dptk	L(gt2)
+	;;
+	BSH	r8 = r10, tnc
+	FSH	r20 = r10, cnt
+	;;
+	BSH	r21 = r17, tnc
+	FSH	r22 = r17, cnt
+	;;
+	or	r14 = r21, r20
+	;;
+	sub	r31 = -1, r14
+	br	.Lr2
+	;;
+L(gt2):
+	ld8	r18 = [up], UPD
+	BSH	r8 = r10, tnc
+	FSH	r20 = r10, cnt
+	;;
+	ld8	r19 = [up], UPD
+	;;
+	ld8	r16 = [up], UPD
+	BSH	r21 = r17, tnc
+	FSH	r22 = r17, cnt
+	;;
+	ld8	r17 = [up], UPD
+	BSH	r23 = r18, tnc
+	br.cloop.dptk	L(gt6)
+	;;
+	nop	0
+	FSH	r24 = r18, cnt
+	BSH	r25 = r19, tnc
+	;;
+	or	r14 = r21, r20
+	FSH	r26 = r19, cnt
+	BSH	r27 = r16, tnc
+	;;
+ {.mmi;	nop	0
+	or	r15 = r23, r22
+	FSH	r20 = r16, cnt
+}{.mib;	sub	r31 = -1, r14
+	BSH	r21 = r17, tnc
+	br	.Lr6
+	;; }
+L(gt6):
+ {.mmi;	nop	0
+	nop	0
+	FSH	r24 = r18, cnt
+}{.mmi;	ld8	r18 = [up], UPD
+	nop	0
+	BSH	r25 = r19, tnc
+	;; }
+ {.mmi; nop   0
+	or	r14 = r21, r20
+	FSH	r26 = r19, cnt
+}{.mmi;	ld8	r19 = [up], UPD
+	nop	0
+	BSH	r27 = r16, tnc
+	;; }
+ {.mmi;	or	r15 = r23, r22
+	sub	r31 = -1, r14
+	FSH	r20 = r16, cnt
+}{.mib;	ld8	r16 = [up], UPD
+	BSH	r21 = r17, tnc
+	br	.LL10
+}
+
+.Lb11:
+	ld8	r16 = [up], UPD
+	;;
+	ld8	r17 = [up], UPD
+	BSH	r8 = r10, tnc
+	FSH	r26 = r10, cnt
+	br.cloop.dptk	L(gt3)
+	;;
+	BSH	r27 = r16, tnc
+	;;
+	FSH	r20 = r16, cnt
+	BSH	r21 = r17, tnc
+	;;
+	FSH	r22 = r17, cnt
+	;;
+	or	r15 = r27, r26
+	;;
+	or	r14 = r21, r20
+	sub	r31 = -1, r15
+	br	.Lr3
+	;;
+L(gt3):
+	ld8	r18 = [up], UPD
+	;;
+	ld8	r19 = [up], UPD
+	BSH	r27 = r16, tnc
+	;;
+ {.mmi;	nop	0
+	nop	0
+	FSH	r20 = r16, cnt
+}{.mmi;	ld8	r16 = [up], UPD
+	nop	0
+	BSH	r21 = r17, tnc
+	;;
+}{.mmi;	nop	0
+	nop	0
+	FSH	r22 = r17, cnt
+}{.mib;	ld8	r17 = [up], UPD
+	BSH	r23 = r18, tnc
+	br.cloop.dptk	L(gt7)
+	;; }
+	or	r15 = r27, r26
+	FSH	r24 = r18, cnt
+	BSH	r25 = r19, tnc
+	;;
+ {.mmi;	nop	0
+	or	r14 = r21, r20
+	FSH	r26 = r19, cnt
+}{.mib;	sub	r31 = -1, r15
+	BSH	r27 = r16, tnc
+	br	.Lr7
+}
+L(gt7):
+ {.mmi;	nop	0
+	or	r15 = r27, r26
+	FSH	r24 = r18, cnt
+}{.mmi;	ld8	r18 = [up], UPD
+	nop	0
+	BSH	r25 = r19, tnc
+	;; }
+ {.mmi;	or	r14 = r21, r20
+	sub	r31 = -1, r15
+	FSH	r26 = r19, cnt
+}{.mib;	ld8	r19 = [up], UPD
+	BSH	r27 = r16, tnc
+	br	.LL11
+}
+
+C *** MAIN LOOP START ***
+	ALIGN(32)
+L(top):
+.LL01:
+ {.mmi;	st8	[rp] = r31, UPD		C M2
+	or	r15 = r27, r26		C M3
+	FSH	r24 = r18, cnt		C I0
+}{.mmi;	ld8	r18 = [up], UPD		C M0
+	sub	r31 = -1, r14		C M1
+	BSH	r25 = r19, tnc		C I1
+	;; }
+.LL00:
+ {.mmi;	st8	[rp] = r31, UPD
+	or	r14 = r21, r20
+	FSH	r26 = r19, cnt
+}{.mmi;	ld8	r19 = [up], UPD
+	sub	r31 = -1, r15
+	BSH	r27 = r16, tnc
+	;; }
+.LL11:
+ {.mmi;	st8	[rp] = r31, UPD
+	or	r15 = r23, r22
+	FSH	r20 = r16, cnt
+}{.mmi;	ld8	r16 = [up], UPD
+	sub	r31 = -1, r14
+	BSH	r21 = r17, tnc
+	;; }
+.LL10:
+ {.mmi;	st8	[rp] = r31, UPD
+	or	r14 = r25, r24
+	FSH	r22 = r17, cnt
+}{.mmi;	ld8	r17 = [up], UPD
+	sub	r31 = -1, r15
+	BSH	r23 = r18, tnc
+	;; }
+L(end):	lfetch		[r11], PUPD
+	br.cloop.dptk	L(top)
+C *** MAIN LOOP END ***
+
+ {.mmi;	st8	[rp] = r31, UPD
+	or	r15 = r27, r26
+	FSH	r24 = r18, cnt
+}{.mib;	sub	r31 = -1, r14
+	BSH	r25 = r19, tnc
+	nop	0
+	;; }
+.Lr8:
+ {.mmi;	st8	[rp] = r31, UPD
+	or	r14 = r21, r20
+	FSH	r26 = r19, cnt
+}{.mib;	sub	r31 = -1, r15
+	BSH	r27 = r16, tnc
+	nop	0
+	;; }
+.Lr7:
+ {.mmi;	st8	[rp] = r31, UPD
+	or	r15 = r23, r22
+	FSH	r20 = r16, cnt
+}{.mib;	sub	r31 = -1, r14
+	BSH	r21 = r17, tnc
+	nop	0
+	;; }
+.Lr6:	st8	[rp] = r31, UPD
+	or	r14 = r25, r24
+	FSH	r22 = r17, cnt
+	sub	r31 = -1, r15
+	;;
+.Lr5:	st8	[rp] = r31, UPD
+	or	r15 = r27, r26
+	sub	r31 = -1, r14
+	;;
+.Lr4:	st8	[rp] = r31, UPD
+	or	r14 = r21, r20
+	sub	r31 = -1, r15
+	;;
+.Lr3:	st8	[rp] = r31, UPD
+	sub	r31 = -1, r14
+	;;
+.Lr2:	st8	[rp] = r31, UPD
+	sub	r31 = -1, r22
+	;;
+.Lr1:	st8	[rp] = r31, UPD		C				M23
+	mov	ar.lc = r2		C				I0
+	br.ret.sptk.many b0		C				B
+EPILOGUE(func)
+ASM_END()
diff --git a/third_party/gmp/mpn/ia64/mod_34lsub1.asm b/third_party/gmp/mpn/ia64/mod_34lsub1.asm
new file mode 100644
index 0000000..7789117
--- /dev/null
+++ b/third_party/gmp/mpn/ia64/mod_34lsub1.asm
@@ -0,0 +1,237 @@
+dnl  IA-64 mpn_mod_34lsub1
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2003-2005, 2010 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C           cycles/limb
+C Itanium:      ?
+C Itanium 2:    1
+
+
+C INPUT PARAMETERS
+define(`up', `r32')
+define(`n',  `r33')
+
+C Some useful aliases for registers we use
+define(`u0',`r14') define(`u1',`r15') define(`u2',`r16')
+define(`a0',`r17') define(`a1',`r18') define(`a2',`r19')
+define(`c0',`r20') define(`c1',`r21') define(`c2',`r22')
+
+C This is a fairly simple-minded implementation.  One could approach 0.67 c/l
+C with a more sophisticated implementation.  If we're really crazy, we could
+C super-unroll, storing carries just in predicate registers, then copy them to
+C a general register, and population count them from there.  That'd bring us
+C close to 3 insn/limb, for nearly 0.5 c/l.
+
+C Computing n/3 needs 16 cycles, which is a lot of startup overhead.
+C We therefore use a plain while-style loop:
+C	add		n = -3, n
+C	cmp.le		p9, p0 = 3, n
+C  (p9)	br.cond		.Loop
+C Alternatively, we could table n/3 for, say, n < 256, and predicate the
+C 16-cycle code.
+
+C The summing-up code at the end was written quickly, and could surely be
+C vastly improved.
+
+ASM_START()
+PROLOGUE(mpn_mod_34lsub1)
+	.prologue
+	.save	ar.lc, r2
+	.body
+ifdef(`HAVE_ABI_32',`
+	addp4		up = 0, up		C			M I
+	nop.m		0
+	zxt4		n = n			C			I
+	;;
+')
+
+ifelse(0,1,`
+	movl		r14 = 0xAAAAAAAAAAAAAAAB
+	;;
+	setf.sig	f6 = r14
+	setf.sig	f7 = r33
+	;;
+	xmpy.hu		f6 = f6, f7
+	;;
+	getf.sig	r8 = f6
+	;;
+	shr.u		r8 = r8, 1		C Loop count
+	;;
+	mov.i		ar.lc = r8
+')
+
+	ld8	u0 = [up], 8
+	cmp.ne	p9, p0 = 1, n
+  (p9)	br	L(gt1)
+	;;
+	shr.u	r8 = u0, 48
+	dep.z	r27 = u0, 0, 48
+	;;
+	add	r8 = r8, r27
+	br.ret.sptk.many b0
+
+
+L(gt1):
+ {.mmi;	nop.m	0
+	mov	a0 = 0
+	add	n = -2, n
+}{.mmi;	mov	c0 = 0
+	mov	c1 = 0
+	mov	c2 = 0
+	;;
+}{.mmi;	ld8	u1 = [up], 8
+	mov	a1 = 0
+	cmp.ltu	p6, p0 = r0, r0		C clear p6
+}{.mmb;	cmp.gt	p9, p0 = 3, n
+	mov	a2 = 0
+  (p9)	br.cond.dptk	L(end)
+	;;
+}
+	ALIGN(32)
+L(top):
+ {.mmi;	ld8	u2 = [up], 8
+  (p6)	add	c0 = 1, c0
+	cmp.ltu	p7, p0 = a0, u0
+}{.mmb;	sub	a0 = a0, u0
+	add	n = -3, n
+	nop.b	0
+	;;
+}{.mmi;	ld8	u0 = [up], 8
+  (p7)	add	c1 = 1, c1
+	cmp.ltu	p8, p0 = a1, u1
+}{.mmb;	sub	a1 = a1, u1
+	cmp.le	p9, p0 = 3, n
+	nop.b	0
+	;;
+}{.mmi;	ld8	u1 = [up], 8
+  (p8)	add	c2 = 1, c2
+	cmp.ltu	p6, p0 = a2, u2
+}{.mmb;	sub	a2 = a2, u2
+	nop.m	0
+dnl	br.cloop.dptk	L(top)
+  (p9)	br.cond.dptk	L(top)
+	;;
+}
+L(end):
+	cmp.eq	p10, p0 = 0, n
+	cmp.eq	p11, p0 = 1, n
+  (p10)	br	L(0)
+
+L(2):
+ {.mmi;	ld8	u2 = [up], 8
+  (p6)	add	c0 = 1, c0
+	cmp.ltu	p7, p0 = a0, u0
+}{.mmb;	sub	a0 = a0, u0
+	nop.m	0
+  (p11)	br	L(1)
+	;;
+}	ld8	u0 = [up], 8
+  (p7)	add	c1 = 1, c1
+	cmp.ltu	p8, p0 = a1, u1
+	sub	a1 = a1, u1
+	;;
+  (p8)	add	c2 = 1, c2
+	cmp.ltu	p6, p0 = a2, u2
+	sub	a2 = a2, u2
+	;;
+  (p6)	add	c0 = 1, c0
+	cmp.ltu	p7, p0 = a0, u0
+	sub	a0 = a0, u0
+	;;
+  (p7)	add	c1 = 1, c1
+	br	L(com)
+
+
+L(1):
+  (p7)	add	c1 = 1, c1
+	cmp.ltu	p8, p0 = a1, u1
+	sub	a1 = a1, u1
+	;;
+  (p8)	add	c2 = 1, c2
+	cmp.ltu	p6, p0 = a2, u2
+	sub	a2 = a2, u2
+	;;
+  (p6)	add	c0 = 1, c0
+	br	L(com)
+
+
+L(0):
+  (p6)	add	c0 = 1, c0
+	cmp.ltu	p7, p0 = a0, u0
+	sub	a0 = a0, u0
+	;;
+  (p7)	add	c1 = 1, c1
+	cmp.ltu	p8, p0 = a1, u1
+	sub	a1 = a1, u1
+	;;
+  (p8)	add	c2 = 1, c2
+
+L(com):
+C |     a2    |     a1    |     a0    |
+C |        |        |        |        |
+	shr.u	r24 = a0, 48		C 16 bits
+	shr.u	r25 = a1, 32		C 32 bits
+	shr.u	r26 = a2, 16		C 48 bits
+	;;
+	shr.u	r10 = c0, 48		C 16 bits, always zero
+	shr.u	r11 = c1, 32		C 32 bits
+	shr.u	r30 = c2, 16		C 48 bits
+	;;
+	dep.z	r27 = a0,  0, 48	C 48 bits
+	dep.z	r28 = a1, 16, 32	C 48 bits
+	dep.z	r29 = a2, 32, 16	C 48 bits
+	dep.z	r31 = c0,  0, 48	C 48 bits
+	dep.z	r14 = c1, 16, 32	C 48 bits
+	dep.z	r15 = c2, 32, 16	C 48 bits
+	;;
+ {.mmi;	add	r24 = r24, r25
+	add	r26 = r26, r27
+	add	r28 = r28, r29
+}{.mmi;	add	r10 = r10, r11
+	add	r30 = r30, r31
+	add	r14 = r14, r15
+	;;
+}
+	movl	r8 = 0xffffffffffff0
+	add	r24 = r24, r26
+	add	r10 = r10, r30
+	;;
+	add	r24 = r24, r28
+	add	r10 = r10, r14
+	;;
+	sub	r8 = r8, r24
+	;;
+	add	r8 = r8, r10
+	br.ret.sptk.many b0
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/ia64/mode1o.asm b/third_party/gmp/mpn/ia64/mode1o.asm
new file mode 100644
index 0000000..14d5e81
--- /dev/null
+++ b/third_party/gmp/mpn/ia64/mode1o.asm
@@ -0,0 +1,342 @@
+dnl  Itanium-2 mpn_modexact_1c_odd -- mpn by 1 exact remainder.
+
+dnl  Contributed to the GNU project by Kevin Ryde.
+
+dnl  Copyright 2003-2005 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C            cycles/limb
+C Itanium:      15
+C Itanium 2:     8
+
+
+dnl  Usage: ABI32(`code')
+dnl
+dnl  Emit the given code only under HAVE_ABI_32.
+dnl
+define(ABI32,
+m4_assert_onearg()
+`ifdef(`HAVE_ABI_32',`$1')')
+
+
+C mp_limb_t mpn_modexact_1c_odd (mp_srcptr src, mp_size_t size,
+C                                mp_limb_t divisor, mp_limb_t carry);
+C
+C The modexact algorithm is usually conceived as a dependent chain
+C
+C	l = src[i] - c
+C	q = low(l * inverse)
+C	c = high(q*divisor) + (src[i]<c)
+C
+C but we can work the src[i]-c into an xma by calculating si=src[i]*inverse
+C separately (off the dependent chain) and using
+C
+C	q = low(c * inverse + si)
+C	c = high(q*divisor + c)
+C
+C This means the dependent chain is simply xma.l followed by xma.hu, for a
+C total 8 cycles/limb on itanium-2.
+C
+C The reason xma.hu works for the new c is that the low of q*divisor is
+C src[i]-c (being the whole purpose of the q generated, and it can be
+C verified algebraically).  If there was an underflow from src[i]-c, then
+C there will be an overflow from (src-c)+c, thereby adding 1 to the new c
+C the same as the borrow bit (src[i]<c) gives in the first style shown.
+C
+C Incidentally, fcmp is not an option for treating src[i]-c, since it
+C apparently traps to the kernel for unnormalized operands like those used
+C and generated by ldf8 and xma.  On one GNU/Linux system it took about 1200
+C cycles.
+C
+C
+C First Limb:
+C
+C The first limb uses q = (src[0]-c) * inverse shown in the first style.
+C This lets us get the first q as soon as the inverse is ready, without
+C going through si=s*inverse.  Basically at the start we have c and can use
+C it while waiting for the inverse, whereas for the second and subsequent
+C limbs it's the other way around, ie. we have the inverse and are waiting
+C for c.
+C
+C At .Lentry the first two instructions in the loop have been done already.
+C The load of f11=src[1] at the start (predicated on size>=2), and the
+C calculation of q by the initial different scheme.
+C
+C
+C Entry Sequence:
+C
+C In the entry sequence, the critical path is the calculation of the
+C inverse, so this is begun first and optimized.  Apart from that, ar.lc is
+C established nice and early so the br.cloop's should predict perfectly.
+C And the load for the low limbs src[0] and src[1] can be initiated long
+C ahead of where they're needed.
+C
+C
+C Inverse Calculation:
+C
+C The initial 8-bit inverse is calculated using a table lookup.  If it hits
+C L1 (which is likely if we're called several times) then it should take a
+C total 4 cycles, otherwise hopefully L2 for 9 cycles.  This is considered
+C the best approach, on balance.  It could be done bitwise, but that would
+C probably be about 14 cycles (2 per bit beyond the first couple).  Or it
+C could be taken from 4 bits to 8 with xmpy doubling as used beyond 8 bits,
+C but that would be about 11 cycles.
+C
+C The table is not the same as binvert_limb_table, instead it's 256 bytes,
+C designed to be indexed by the low byte of the divisor.  The divisor is
+C always odd, so the relevant data is every second byte in the table.  The
+C padding lets us use zxt1 instead of extr.u, the latter would cost an extra
+C cycle because it must go down I0, and we're using the first I0 slot to get
+C ip.  The extra 128 bytes of padding should be insignificant compared to
+C typical ia64 code bloat.
+C
+C Having the table in .text allows us to use IP-relative addressing,
+C avoiding a fetch from ltoff.  .rodata is apparently not suitable for use
+C IP-relative, it gets a linker relocation overflow on GNU/Linux.
+C
+C
+C Load Scheduling:
+C
+C In the main loop, the data loads are scheduled for an L2 hit, which means
+C 6 cycles for the data ready to use.  In fact we end up 7 cycles ahead.  In
+C any case that scheduling is achieved simply by doing the load (and xmpy.l
+C for "si") in the immediately preceding iteration.
+C
+C The main loop requires size >= 2, and we handle size==1 by an initial
+C br.cloop to enter the loop only if size>1.  Since ar.lc is established
+C early, this should predict perfectly.
+C
+C
+C Not done:
+C
+C Consideration was given to using a plain "(src[0]-c) % divisor" for
+C size==1, but cycle counting suggests about 50 for the sort of approach
+C taken by gcc __umodsi3, versus about 47 for the modexact.  (Both assuming
+C L1 hits for their respective fetching.)
+C
+C Consideration was given to a test for high<divisor and replacing the last
+C loop iteration with instead c-=src[size-1] followed by c+=d if underflow.
+C Branching on high<divisor wouldn't be good since a mispredict would cost
+C more than the loop iteration saved, and the condition is of course data
+C dependent.  So the theory would be to shorten the loop count if
+C high<divisor, and predicate extra operations at the end.  That would mean
+C a gain of 6 when high<divisor, or a cost of 2 if not.
+C
+C Whether such a tradeoff is a win on average depends on assumptions about
+C how many bits in the high and the divisor.  If both are uniformly
+C distributed then high<divisor about 50% of the time.  But smallish
+C divisors (less chance of high<divisor) might be more likely from
+C applications (mpz_divisible_ui, mpz_gcd_ui, etc).  Though biggish divisors
+C would be normal internally from say mpn/generic/perfsqr.c.  On balance,
+C for the moment, it's felt the gain is not really enough to be worth the
+C trouble.
+C
+C
+C Enhancement:
+C
+C Process two source limbs per iteration using a two-limb inverse and a
+C sequence like
+C
+C	ql  = low (c * il + sil)	quotient low limb
+C	qlc = high(c * il + sil)
+C	qh1 = low (c * ih + sih)	quotient high, partial
+C
+C	cl = high (ql * d + c)		carry out of low
+C	qh = low (qlc * 1 + qh1)	quotient high limb
+C
+C	new c = high (qh * d + cl)	carry out of high
+C
+C This would be 13 cycles/iteration, giving 6.5 cycles/limb.  The two limb
+C s*inverse as sih:sil = sh:sl * ih:il would be calculated off the dependent
+C chain with 4 multiplies.  The bigger inverse would take extra time to
+C calculate, but a one limb iteration to handle an odd size could be done as
+C soon as 64-bits of inverse were ready.
+C
+C Perhaps this could even extend to a 3 limb inverse, which might promise 17
+C or 18 cycles for 3 limbs, giving 5.66 or 6.0 cycles/limb.
+C
+
+ASM_START()
+	.explicit
+
+	.text
+	.align	32
+.Ltable:
+data1	0,0x01, 0,0xAB, 0,0xCD, 0,0xB7, 0,0x39, 0,0xA3, 0,0xC5, 0,0xEF
+data1	0,0xF1, 0,0x1B, 0,0x3D, 0,0xA7, 0,0x29, 0,0x13, 0,0x35, 0,0xDF
+data1	0,0xE1, 0,0x8B, 0,0xAD, 0,0x97, 0,0x19, 0,0x83, 0,0xA5, 0,0xCF
+data1	0,0xD1, 0,0xFB, 0,0x1D, 0,0x87, 0,0x09, 0,0xF3, 0,0x15, 0,0xBF
+data1	0,0xC1, 0,0x6B, 0,0x8D, 0,0x77, 0,0xF9, 0,0x63, 0,0x85, 0,0xAF
+data1	0,0xB1, 0,0xDB, 0,0xFD, 0,0x67, 0,0xE9, 0,0xD3, 0,0xF5, 0,0x9F
+data1	0,0xA1, 0,0x4B, 0,0x6D, 0,0x57, 0,0xD9, 0,0x43, 0,0x65, 0,0x8F
+data1	0,0x91, 0,0xBB, 0,0xDD, 0,0x47, 0,0xC9, 0,0xB3, 0,0xD5, 0,0x7F
+data1	0,0x81, 0,0x2B, 0,0x4D, 0,0x37, 0,0xB9, 0,0x23, 0,0x45, 0,0x6F
+data1	0,0x71, 0,0x9B, 0,0xBD, 0,0x27, 0,0xA9, 0,0x93, 0,0xB5, 0,0x5F
+data1	0,0x61, 0,0x0B, 0,0x2D, 0,0x17, 0,0x99, 0,0x03, 0,0x25, 0,0x4F
+data1	0,0x51, 0,0x7B, 0,0x9D, 0,0x07, 0,0x89, 0,0x73, 0,0x95, 0,0x3F
+data1	0,0x41, 0,0xEB, 0,0x0D, 0,0xF7, 0,0x79, 0,0xE3, 0,0x05, 0,0x2F
+data1	0,0x31, 0,0x5B, 0,0x7D, 0,0xE7, 0,0x69, 0,0x53, 0,0x75, 0,0x1F
+data1	0,0x21, 0,0xCB, 0,0xED, 0,0xD7, 0,0x59, 0,0xC3, 0,0xE5, 0,0x0F
+data1	0,0x11, 0,0x3B, 0,0x5D, 0,0xC7, 0,0x49, 0,0x33, 0,0x55, 0,0xFF
+
+
+PROLOGUE(mpn_modexact_1c_odd)
+
+	C r32	src
+	C r33	size
+	C r34	divisor
+	C r35	carry
+
+	.prologue
+.Lhere:
+{ .mmi;	add	r33 = -1, r33		C M0  size-1
+	mov	r14 = 2			C M1  2
+	mov	r15 = ip		C I0  .Lhere
+}{.mmi;	setf.sig f6 = r34		C M2  divisor
+	setf.sig f9 = r35		C M3  carry
+	zxt1	r3 = r34		C I1  divisor low byte
+}	;;
+
+{ .mmi;	add	r3 = .Ltable-.Lhere, r3	C M0  table offset ip and index
+	sub	r16 = 0, r34		C M1  -divisor
+	.save	ar.lc, r2
+	mov	r2 = ar.lc		C I0
+}{.mmi;	.body
+	setf.sig f13 = r14		C M2  2 in significand
+	mov	r17 = -1		C M3  -1
+ABI32(`	zxt4	r33 = r33')		C I1  size extend
+}	;;
+
+{ .mmi;	add	r3 = r3, r15		C M0  table entry address
+ABI32(` addp4	r32 = 0, r32')		C M1  src extend
+	mov	ar.lc = r33		C I0  size-1 loop count
+}{.mmi;	setf.sig f12 = r16		C M2  -divisor
+	setf.sig f8 = r17		C M3  -1
+}	;;
+
+{ .mmi;	ld1	r3 = [r3]		C M0  inverse, 8 bits
+	ldf8	f10 = [r32], 8		C M1  src[0]
+	cmp.ne	p6,p0 = 0, r33		C I0  test size!=1
+}	;;
+
+	C Wait for table load.
+	C Hope for an L1 hit of 1 cycles to ALU, but could be more.
+	setf.sig f7 = r3		C M2  inverse, 8 bits
+(p6)	ldf8	f11 = [r32], 8		C M1  src[1], if size!=1
+	;;
+
+	C 5 cycles
+
+	C f6	divisor
+	C f7	inverse, being calculated
+	C f8	-1, will be -inverse
+	C f9	carry
+	C f10	src[0]
+	C f11	src[1]
+	C f12	-divisor
+	C f13	2
+	C f14	scratch
+
+	xmpy.l	f14 = f13, f7		C 2*i
+	xmpy.l	f7 = f7, f7		C i*i
+	;;
+	xma.l	f7 = f7, f12, f14	C i*i*-d + 2*i, inverse 16 bits
+	;;
+
+	xmpy.l	f14 = f13, f7		C 2*i
+	xmpy.l	f7 = f7, f7		C i*i
+	;;
+	xma.l	f7 = f7, f12, f14	C i*i*-d + 2*i, inverse 32 bits
+	;;
+
+	xmpy.l	f14 = f13, f7		C 2*i
+	xmpy.l	f7 = f7, f7		C i*i
+	;;
+
+	xma.l	f7 = f7, f12, f14	C i*i*-d + 2*i, inverse 64 bits
+	xma.l	f10 = f9, f8, f10	C sc = c * -1 + src[0]
+	;;
+ASSERT(p6, `
+	xmpy.l	f15 = f6, f7 ;;	C divisor*inverse
+	getf.sig r31 = f15 ;;
+	cmp.eq	p6,p0 = 1, r31	C should == 1
+')
+
+	xmpy.l	f10 = f10, f7		C q = sc * inverse
+	xmpy.l	f8 = f7, f8		C -inverse = inverse * -1
+	br.cloop.sptk.few.clr .Lentry	C main loop, if size > 1
+	;;
+
+	C size==1, finish up now
+	xma.hu	f9 = f10, f6, f9	C c = high(q * divisor + c)
+	mov	ar.lc = r2		C I0
+	;;
+	getf.sig r8 = f9		C M2  return c
+	br.ret.sptk.many b0
+
+
+
+.Ltop:
+	C r2	saved ar.lc
+	C f6	divisor
+	C f7	inverse
+	C f8	-inverse
+	C f9	carry
+	C f10	src[i] * inverse
+	C f11	scratch src[i+1]
+
+	add	r16 = 160, r32
+	ldf8	f11 = [r32], 8		C src[i+1]
+	;;
+	C 2 cycles
+
+	lfetch	[r16]
+	xma.l	f10 = f9, f8, f10	C q = c * -inverse + si
+	;;
+	C 3 cycles
+
+.Lentry:
+	xma.hu	f9 = f10, f6, f9	C c = high(q * divisor + c)
+	xmpy.l	f10 = f11, f7		C si = src[i] * inverse
+	br.cloop.sptk.few.clr .Ltop
+	;;
+
+
+
+	xma.l	f10 = f9, f8, f10	C q = c * -inverse + si
+	mov	ar.lc = r2		C I0
+	;;
+	xma.hu	f9 = f10, f6, f9	C c = high(q * divisor + c)
+	;;
+	getf.sig r8 = f9		C M2  return c
+	br.ret.sptk.many b0
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/ia64/mul_1.asm b/third_party/gmp/mpn/ia64/mul_1.asm
new file mode 100644
index 0000000..21bf6d0
--- /dev/null
+++ b/third_party/gmp/mpn/ia64/mul_1.asm
@@ -0,0 +1,584 @@
+dnl  IA-64 mpn_mul_1, mpn_mul_1c -- Multiply a limb vector with a limb and
+dnl  store the result in a second limb vector.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2000-2004, 2006, 2007 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C         cycles/limb
+C Itanium:    4.0
+C Itanium 2:  2.0
+
+C TODO
+C  * Further optimize feed-in and wind-down code, both for speed and code size.
+C  * Handle low limb input and results specially, using a common stf8 in the
+C    epilogue.
+C  * Use 1 c/l carry propagation scheme in wind-down code.
+C  * Use extra pointer register for `up' to speed up feed-in loads.
+C  * Work out final differences with addmul_1.asm.
+
+C INPUT PARAMETERS
+define(`rp', `r32')
+define(`up', `r33')
+define(`n', `r34')
+define(`vl', `r35')
+define(`cy', `r36')	C for mpn_mul_1c
+
+ASM_START()
+PROLOGUE(mpn_mul_1)
+	.prologue
+	.save	ar.lc, r2
+	.body
+
+ifdef(`HAVE_ABI_32',
+`	addp4		rp = 0, rp		C M I
+	addp4		up = 0, up		C M I
+	zxt4		n = n			C I
+	;;
+')
+{.mfi
+	adds		r15 = -1, n		C M I
+	mov		f9 = f0			C F
+	mov.i		r2 = ar.lc		C I0
+}
+{.mmi
+	ldf8		f7 = [up], 8		C M
+	nop.m		0			C M
+	and		r14 = 3, n		C M I
+	;;
+}
+.Lcommon:
+{.mii
+	setf.sig	f6 = vl			C M2 M3
+	shr.u		r31 = r15, 2		C I0
+	cmp.eq		p10, p0 = 0, r14	C M I
+}
+{.mii
+	cmp.eq		p11, p0 = 2, r14	C M I
+	cmp.eq		p12, p0 = 3, r14	C M I
+	nop.i		0			C I
+	;;
+}
+{.mii
+	cmp.ne		p6, p7 = r0, r0		C M I
+	mov.i		ar.lc = r31		C I0
+	cmp.ne		p8, p9 = r0, r0		C M I
+}
+{.bbb
+  (p10)	br.dptk		.Lb00			C B
+  (p11)	br.dptk		.Lb10			C B
+  (p12)	br.dptk		.Lb11			C B
+	;;
+}
+
+.Lb01:	mov		r20 = 0
+	br.cloop.dptk	.grt1			C B
+
+	xma.l		f39 = f7, f6, f9	C F
+	xma.hu		f43 = f7, f6, f9	C F
+	;;
+	getf.sig	r8 = f43		C M2
+	stf8		[rp] = f39		C M2 M3
+	mov.i		ar.lc = r2		C I0
+	br.ret.sptk.many b0			C B
+
+.grt1:
+	ldf8		f32 = [up], 8
+	;;
+	ldf8		f33 = [up], 8
+	;;
+	ldf8		f34 = [up], 8
+	xma.l		f39 = f7, f6, f9
+	xma.hu		f43 = f7, f6, f9
+	;;
+	ldf8		f35 = [up], 8
+	br.cloop.dptk	.grt5
+
+	xma.l		f36 = f32, f6, f0
+	xma.hu		f40 = f32, f6, f0
+	;;
+	stf8		[rp] = f39, 8
+	xma.l		f37 = f33, f6, f0
+	xma.hu		f41 = f33, f6, f0
+	;;
+	getf.sig	r21 = f43
+	getf.sig	r18 = f36
+	xma.l		f38 = f34, f6, f0
+	xma.hu		f42 = f34, f6, f0
+	;;
+	getf.sig	r22 = f40
+	getf.sig	r19 = f37
+	xma.l		f39 = f35, f6, f0
+	xma.hu		f43 = f35, f6, f0
+	;;
+	getf.sig	r23 = f41
+	getf.sig	r16 = f38
+	br		.Lcj5
+
+.grt5:
+	xma.l		f36 = f32, f6, f0
+	xma.hu		f40 = f32, f6, f0
+	;;
+	getf.sig	r17 = f39
+	ldf8		f32 = [up], 8
+	xma.l		f37 = f33, f6, f0
+	xma.hu		f41 = f33, f6, f0
+	;;
+	getf.sig	r21 = f43
+	ldf8		f33 = [up], 8
+	xma.l		f38 = f34, f6, f0
+	;;
+	getf.sig	r18 = f36
+	xma.hu		f42 = f34, f6, f0
+	;;
+	getf.sig	r22 = f40
+	ldf8		f34 = [up], 8
+	xma.l		f39 = f35, f6, f0
+	;;
+	getf.sig	r19 = f37
+	xma.hu		f43 = f35, f6, f0
+	br		.LL01
+
+
+.Lb10:	ldf8		f35 = [up], 8
+	mov		r23 = 0
+	br.cloop.dptk	.grt2
+
+	xma.l		f38 = f7, f6, f9
+	xma.hu		f42 = f7, f6, f9
+	;;
+	stf8		[rp] = f38, 8
+	xma.l		f39 = f35, f6, f42
+	xma.hu		f43 = f35, f6, f42
+	;;
+	getf.sig	r8 = f43
+	stf8		[rp] = f39
+	mov.i		ar.lc = r2
+	br.ret.sptk.many b0
+
+
+.grt2:
+	ldf8		f32 = [up], 8
+	;;
+	ldf8		f33 = [up], 8
+	xma.l		f38 = f7, f6, f9
+	xma.hu		f42 = f7, f6, f9
+	;;
+	ldf8		f34 = [up], 8
+	xma.l		f39 = f35, f6, f0
+	xma.hu		f43 = f35, f6, f0
+	;;
+	ldf8		f35 = [up], 8
+	br.cloop.dptk	.grt6
+
+	stf8		[rp] = f38, 8
+	xma.l		f36 = f32, f6, f0
+	xma.hu		f40 = f32, f6, f0
+	;;
+	getf.sig	r20 = f42
+	getf.sig	r17 = f39
+	xma.l		f37 = f33, f6, f0
+	xma.hu		f41 = f33, f6, f0
+	;;
+	getf.sig	r21 = f43
+	getf.sig	r18 = f36
+	xma.l		f38 = f34, f6, f0
+	xma.hu		f42 = f34, f6, f0
+	;;
+	getf.sig	r22 = f40
+	getf.sig	r19 = f37
+	xma.l		f39 = f35, f6, f0
+	xma.hu		f43 = f35, f6, f0
+	br		.Lcj6
+
+.grt6:
+	getf.sig	r16 = f38
+	xma.l		f36 = f32, f6, f0
+	xma.hu		f40 = f32, f6, f0
+	;;
+	getf.sig	r20 = f42
+	ldf8		f32 = [up], 8
+	xma.l		f37 = f33, f6, f0
+	;;
+	getf.sig	r17 = f39
+	xma.hu		f41 = f33, f6, f0
+	;;
+	getf.sig	r21 = f43
+	ldf8		f33 = [up], 8
+	xma.l		f38 = f34, f6, f0
+	;;
+	getf.sig	r18 = f36
+	xma.hu		f42 = f34, f6, f0
+	br		.LL10
+
+
+.Lb11:	ldf8		f34 = [up], 8
+	mov		r22 = 0
+	;;
+	ldf8		f35 = [up], 8
+	br.cloop.dptk	.grt3
+	;;
+
+	xma.l		f37 = f7, f6, f9
+	xma.hu		f41 = f7, f6, f9
+	xma.l		f38 = f34, f6, f0
+	xma.hu		f42 = f34, f6, f0
+	xma.l		f39 = f35, f6, f0
+	xma.hu		f43 = f35, f6, f0
+	;;
+	getf.sig	r23 = f41
+	stf8		[rp] = f37, 8
+	getf.sig	r16 = f38
+	getf.sig	r20 = f42
+	getf.sig	r17 = f39
+	getf.sig	r8 = f43
+	br		.Lcj3
+
+.grt3:
+	ldf8		f32 = [up], 8
+	xma.l		f37 = f7, f6, f9
+	xma.hu		f41 = f7, f6, f9
+	;;
+	ldf8		f33 = [up], 8
+	xma.l		f38 = f34, f6, f0
+	xma.hu		f42 = f34, f6, f0
+	;;
+	getf.sig	r19 = f37
+	ldf8		f34 = [up], 8
+	xma.l		f39 = f35, f6, f0
+	xma.hu		f43 = f35, f6, f0
+	;;
+	getf.sig	r23 = f41
+	ldf8		f35 = [up], 8
+	br.cloop.dptk	.grt7
+
+	getf.sig	r16 = f38
+	xma.l		f36 = f32, f6, f0
+	getf.sig	r20 = f42
+	xma.hu		f40 = f32, f6, f0
+	;;
+	getf.sig	r17 = f39
+	xma.l		f37 = f33, f6, f0
+	getf.sig	r21 = f43
+	xma.hu		f41 = f33, f6, f0
+	;;
+	getf.sig	r18 = f36
+	st8		[rp] = r19, 8
+	xma.l		f38 = f34, f6, f0
+	xma.hu		f42 = f34, f6, f0
+	br		.Lcj7
+
+.grt7:
+	getf.sig	r16 = f38
+	xma.l		f36 = f32, f6, f0
+	xma.hu		f40 = f32, f6, f0
+	;;
+	getf.sig	r20 = f42
+	ldf8		f32 = [up], 8
+	xma.l		f37 = f33, f6, f0
+	;;
+	getf.sig	r17 = f39
+	xma.hu		f41 = f33, f6, f0
+	br		.LL11
+
+
+.Lb00:	ldf8		f33 = [up], 8
+	mov		r21 = 0
+	;;
+	ldf8		f34 = [up], 8
+	;;
+	ldf8		f35 = [up], 8
+	xma.l		f36 = f7, f6, f9
+	xma.hu		f40 = f7, f6, f9
+	br.cloop.dptk	.grt4
+
+	xma.l		f37 = f33, f6, f0
+	xma.hu		f41 = f33, f6, f0
+	xma.l		f38 = f34, f6, f0
+	xma.hu		f42 = f34, f6, f0
+	;;
+	getf.sig	r22 = f40
+	stf8		[rp] = f36, 8
+	xma.l		f39 = f35, f6, f0
+	getf.sig	r19 = f37
+	xma.hu		f43 = f35, f6, f0
+	;;
+	getf.sig	r23 = f41
+	getf.sig	r16 = f38
+	getf.sig	r20 = f42
+	getf.sig	r17 = f39
+	br		.Lcj4
+
+.grt4:
+	ldf8		f32 = [up], 8
+	xma.l		f37 = f33, f6, f0
+	xma.hu		f41 = f33, f6, f0
+	;;
+	getf.sig	r18 = f36
+	ldf8		f33 = [up], 8
+	xma.l		f38 = f34, f6, f0
+	xma.hu		f42 = f34, f6, f0
+	;;
+	getf.sig	r22 = f40
+	ldf8		f34 = [up], 8
+	xma.l		f39 = f35, f6, f0
+	;;
+	getf.sig	r19 = f37
+	getf.sig	r23 = f41
+	xma.hu		f43 = f35, f6, f0
+	ldf8		f35 = [up], 8
+	br.cloop.dptk	.grt8
+
+	getf.sig	r16 = f38
+	xma.l		f36 = f32, f6, f0
+	getf.sig	r20 = f42
+	xma.hu		f40 = f32, f6, f0
+	;;
+	getf.sig	r17 = f39
+	st8		[rp] = r18, 8
+	xma.l		f37 = f33, f6, f0
+	xma.hu		f41 = f33, f6, f0
+	br		.Lcj8
+
+.grt8:
+	getf.sig	r16 = f38
+	xma.l		f36 = f32, f6, f0
+	xma.hu		f40 = f32, f6, f0
+	br		.LL00
+
+
+C *** MAIN LOOP START ***
+	ALIGN(32)
+.Loop:
+	.pred.rel "mutex",p6,p7
+	getf.sig	r16 = f38
+	xma.l		f36 = f32, f6, f0
+   (p6)	cmp.leu		p8, p9 = r24, r17
+	st8		[rp] = r24, 8
+	xma.hu		f40 = f32, f6, f0
+   (p7)	cmp.ltu		p8, p9 = r24, r17
+	;;
+.LL00:
+	.pred.rel "mutex",p8,p9
+	getf.sig	r20 = f42
+   (p8)	add		r24 = r18, r21, 1
+	nop.b		0
+	ldf8		f32 = [up], 8
+   (p9)	add		r24 = r18, r21
+	nop.b		0
+	;;
+	.pred.rel "mutex",p8,p9
+	getf.sig	r17 = f39
+	xma.l		f37 = f33, f6, f0
+   (p8)	cmp.leu		p6, p7 = r24, r18
+	st8		[rp] = r24, 8
+	xma.hu		f41 = f33, f6, f0
+   (p9)	cmp.ltu		p6, p7 = r24, r18
+	;;
+.LL11:
+	.pred.rel "mutex",p6,p7
+	getf.sig	r21 = f43
+   (p6)	add		r24 = r19, r22, 1
+	nop.b		0
+	ldf8		f33 = [up], 8
+   (p7)	add		r24 = r19, r22
+	nop.b		0
+	;;
+	.pred.rel "mutex",p6,p7
+	getf.sig	r18 = f36
+	xma.l		f38 = f34, f6, f0
+   (p6)	cmp.leu		p8, p9 = r24, r19
+	st8		[rp] = r24, 8
+	xma.hu		f42 = f34, f6, f0
+   (p7)	cmp.ltu		p8, p9 = r24, r19
+	;;
+.LL10:
+	.pred.rel "mutex",p8,p9
+	getf.sig	r22 = f40
+   (p8)	add		r24 = r16, r23, 1
+	nop.b		0
+	ldf8		f34 = [up], 8
+   (p9)	add		r24 = r16, r23
+	nop.b		0
+	;;
+	.pred.rel "mutex",p8,p9
+	getf.sig	r19 = f37
+	xma.l		f39 = f35, f6, f0
+   (p8)	cmp.leu		p6, p7 = r24, r16
+	st8		[rp] = r24, 8
+	xma.hu		f43 = f35, f6, f0
+   (p9)	cmp.ltu		p6, p7 = r24, r16
+	;;
+.LL01:
+	.pred.rel "mutex",p6,p7
+	getf.sig	r23 = f41
+   (p6)	add		r24 = r17, r20, 1
+	nop.b		0
+	ldf8		f35 = [up], 8
+   (p7)	add		r24 = r17, r20
+	br.cloop.dptk	.Loop
+C *** MAIN LOOP END ***
+	;;
+
+.Lcj9:
+	.pred.rel "mutex",p6,p7
+	getf.sig	r16 = f38
+	xma.l		f36 = f32, f6, f0
+   (p6)	cmp.leu		p8, p9 = r24, r17
+	st8		[rp] = r24, 8
+	xma.hu		f40 = f32, f6, f0
+   (p7)	cmp.ltu		p8, p9 = r24, r17
+	;;
+	.pred.rel "mutex",p8,p9
+	getf.sig	r20 = f42
+   (p8)	add		r24 = r18, r21, 1
+   (p9)	add		r24 = r18, r21
+	;;
+	.pred.rel "mutex",p8,p9
+	getf.sig	r17 = f39
+	xma.l		f37 = f33, f6, f0
+   (p8)	cmp.leu		p6, p7 = r24, r18
+	st8		[rp] = r24, 8
+	xma.hu		f41 = f33, f6, f0
+   (p9)	cmp.ltu		p6, p7 = r24, r18
+	;;
+.Lcj8:
+	.pred.rel "mutex",p6,p7
+	getf.sig	r21 = f43
+   (p6)	add		r24 = r19, r22, 1
+   (p7)	add		r24 = r19, r22
+	;;
+	.pred.rel "mutex",p6,p7
+	getf.sig	r18 = f36
+	xma.l		f38 = f34, f6, f0
+   (p6)	cmp.leu		p8, p9 = r24, r19
+	st8		[rp] = r24, 8
+	xma.hu		f42 = f34, f6, f0
+   (p7)	cmp.ltu		p8, p9 = r24, r19
+	;;
+.Lcj7:
+	.pred.rel "mutex",p8,p9
+	getf.sig	r22 = f40
+   (p8)	add		r24 = r16, r23, 1
+   (p9)	add		r24 = r16, r23
+	;;
+	.pred.rel "mutex",p8,p9
+	getf.sig	r19 = f37
+	xma.l		f39 = f35, f6, f0
+   (p8)	cmp.leu		p6, p7 = r24, r16
+	st8		[rp] = r24, 8
+	xma.hu		f43 = f35, f6, f0
+   (p9)	cmp.ltu		p6, p7 = r24, r16
+	;;
+.Lcj6:
+	.pred.rel "mutex",p6,p7
+	getf.sig	r23 = f41
+   (p6)	add		r24 = r17, r20, 1
+   (p7)	add		r24 = r17, r20
+	;;
+	.pred.rel "mutex",p6,p7
+   (p6)	cmp.leu		p8, p9 = r24, r17
+   (p7)	cmp.ltu		p8, p9 = r24, r17
+	getf.sig	r16 = f38
+	st8		[rp] = r24, 8
+	;;
+.Lcj5:
+	.pred.rel "mutex",p8,p9
+	getf.sig	r20 = f42
+   (p8)	add		r24 = r18, r21, 1
+   (p9)	add		r24 = r18, r21
+	;;
+	.pred.rel "mutex",p8,p9
+   (p8)	cmp.leu		p6, p7 = r24, r18
+   (p9)	cmp.ltu		p6, p7 = r24, r18
+	getf.sig	r17 = f39
+	st8		[rp] = r24, 8
+	;;
+.Lcj4:
+	.pred.rel "mutex",p6,p7
+	getf.sig	r8 = f43
+   (p6)	add		r24 = r19, r22, 1
+   (p7)	add		r24 = r19, r22
+	;;
+	.pred.rel "mutex",p6,p7
+	st8		[rp] = r24, 8
+   (p6)	cmp.leu		p8, p9 = r24, r19
+   (p7)	cmp.ltu		p8, p9 = r24, r19
+	;;
+.Lcj3:
+	.pred.rel "mutex",p8,p9
+   (p8)	add		r24 = r16, r23, 1
+   (p9)	add		r24 = r16, r23
+	;;
+	.pred.rel "mutex",p8,p9
+	st8		[rp] = r24, 8
+   (p8)	cmp.leu		p6, p7 = r24, r16
+   (p9)	cmp.ltu		p6, p7 = r24, r16
+	;;
+.Lcj2:
+	.pred.rel "mutex",p6,p7
+   (p6)	add		r24 = r17, r20, 1
+   (p7)	add		r24 = r17, r20
+	;;
+	.pred.rel "mutex",p6,p7
+	st8		[rp] = r24, 8
+   (p6)	cmp.leu		p8, p9 = r24, r17
+   (p7)	cmp.ltu		p8, p9 = r24, r17
+	;;
+   (p8)	add		r8 = 1, r8
+	mov.i		ar.lc = r2
+	br.ret.sptk.many b0
+EPILOGUE()
+
+PROLOGUE(mpn_mul_1c)
+	.prologue
+	.save	ar.lc, r2
+	.body
+
+ifdef(`HAVE_ABI_32',
+`	addp4		rp = 0, rp		C M I
+	addp4		up = 0, up		C M I
+	zxt4		n = n			C I
+	;;
+')
+{.mmi
+	adds		r15 = -1, n		C M I
+	setf.sig	f9 = cy			C M2 M3
+	mov.i		r2 = ar.lc		C I0
+}
+{.mmb
+	ldf8		f7 = [up], 8		C M
+	and		r14 = 3, n		C M I
+	br.sptk		.Lcommon
+	;;
+}
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/ia64/mul_2.asm b/third_party/gmp/mpn/ia64/mul_2.asm
new file mode 100644
index 0000000..5343f64
--- /dev/null
+++ b/third_party/gmp/mpn/ia64/mul_2.asm
@@ -0,0 +1,625 @@
+dnl  IA-64 mpn_mul_2 -- Multiply a n-limb number with a 2-limb number and store
+dnl  store the result to a (n+1)-limb number.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2004, 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C         cycles/limb
+C Itanium:    ?
+C Itanium 2:  1.5
+
+C TODO
+C  * Clean up variable names, and try to decrease the number of distinct
+C    registers used.
+C  * Clean up feed-in code to not require zeroing several registers.
+C  * Make sure we don't depend on uninitialized predicate registers.
+C  * Could perhaps save a few cycles by using 1 c/l carry propagation in
+C    wind-down code.
+C  * Ultimately rewrite.  The problem with this code is that it first uses a
+C    loaded u value in one xma pair, then leaves it live over several unrelated
+C    xma pairs, before it uses it again.  It should actually be quite possible
+C    to just swap some aligned xma pairs around.  But we should then schedule
+C    u loads further from the first use.
+
+C INPUT PARAMETERS
+define(`rp',`r32')
+define(`up',`r33')
+define(`n',`r34')
+define(`vp',`r35')
+
+define(`srp',`r3')
+
+define(`v0',`f6')
+define(`v1',`f7')
+
+define(`s0',`r14')
+define(`acc0',`r15')
+
+define(`pr0_0',`r16') define(`pr0_1',`r17')
+define(`pr0_2',`r18') define(`pr0_3',`r19')
+
+define(`pr1_0',`r20') define(`pr1_1',`r21')
+define(`pr1_2',`r22') define(`pr1_3',`r23')
+
+define(`acc1_0',`r24') define(`acc1_1',`r25')
+define(`acc1_2',`r26') define(`acc1_3',`r27')
+
+dnl define(`',`r28')
+dnl define(`',`r29')
+dnl define(`',`r30')
+dnl define(`',`r31')
+
+define(`fp0b_0',`f8') define(`fp0b_1',`f9')
+define(`fp0b_2',`f10') define(`fp0b_3',`f11')
+
+define(`fp1a_0',`f12') define(`fp1a_1',`f13')
+define(`fp1a_2',`f14') define(`fp1a_3',`f15')
+
+define(`fp1b_0',`f32') define(`fp1b_1',`f33')
+define(`fp1b_2',`f34') define(`fp1b_3',`f35')
+
+define(`fp2a_0',`f36') define(`fp2a_1',`f37')
+define(`fp2a_2',`f38') define(`fp2a_3',`f39')
+
+define(`u_0',`f44') define(`u_1',`f45')
+define(`u_2',`f46') define(`u_3',`f47')
+
+define(`ux',`f49')
+define(`uy',`f51')
+
+ASM_START()
+PROLOGUE(mpn_mul_2)
+	.prologue
+	.save	ar.lc, r2
+	.body
+
+ifdef(`HAVE_ABI_32',`
+ {.mmi;		addp4	rp = 0, rp		C			M I
+		addp4	up = 0, up		C			M I
+		addp4	vp = 0, vp		C			M I
+}{.mmi;		nop	1
+		nop	1
+		zxt4	n = n			C			I
+	;;
+}')
+
+ {.mmi;		ldf8	ux = [up], 8		C			M
+		ldf8	v0 = [vp], 8		C			M
+		mov	r2 = ar.lc		C			I0
+}{.mmi;		nop	1			C			M
+		and	r14 = 3, n		C			M I
+		add	n = -2, n		C			M I
+	;;
+}{.mmi;		ldf8	uy = [up], 8		C			M
+		ldf8	v1 = [vp]		C			M
+		shr.u	n = n, 2		C			I0
+}{.mmi;		nop	1			C			M
+		cmp.eq	p10, p0 = 1, r14	C			M I
+		cmp.eq	p11, p0 = 2, r14	C			M I
+	;;
+}{.mmi;		nop	1			C			M
+		cmp.eq	p12, p0 = 3, r14	C			M I
+		mov	ar.lc = n		C			I0
+}{.bbb;	(p10)	br.dptk	L(b01)			C			B
+	(p11)	br.dptk	L(b10)			C			B
+	(p12)	br.dptk	L(b11)			C			B
+	;;
+}
+	ALIGN(32)
+L(b00):		ldf8	u_1 = [up], 8
+		mov	acc1_2 = 0
+		mov	pr1_2 = 0
+		mov	pr0_3 = 0
+		cmp.ne	p8, p9 = r0, r0
+	;;
+		xma.l	fp0b_3 = ux, v0, f0
+		cmp.ne	p12, p13 = r0, r0
+		ldf8	u_2 = [up], 8
+		xma.hu	fp1a_3 = ux, v0, f0
+		br.cloop.dptk	L(gt4)
+
+		xma.l	fp0b_0 = uy, v0, f0
+		xma.hu	fp1a_0 = uy, v0, f0
+	;;
+		getfsig	acc0 = fp0b_3
+		xma.l	fp1b_3 = ux, v1, fp1a_3
+		xma.hu	fp2a_3 = ux, v1, fp1a_3
+	;;
+		xma.l	fp0b_1 = u_1, v0, f0
+		xma.hu	fp1a_1 = u_1, v0, f0
+	;;
+		getfsig	pr0_0 = fp0b_0
+		xma.l	fp1b_0 = uy, v1, fp1a_0
+		xma.hu	fp2a_0 = uy, v1, fp1a_0
+	;;
+		getfsig	pr1_3 = fp1b_3
+		getfsig	acc1_3 = fp2a_3
+		xma.l	fp0b_2 = u_2, v0, f0
+		xma.hu	fp1a_2 = u_2, v0, f0
+		br	L(cj4)
+
+L(gt4):		xma.l	fp0b_0 = uy, v0, f0
+		xma.hu	fp1a_0 = uy, v0, f0
+	;;
+		getfsig	acc0 = fp0b_3
+		xma.l	fp1b_3 = ux, v1, fp1a_3
+		ldf8	u_3 = [up], 8
+		xma.hu	fp2a_3 = ux, v1, fp1a_3
+	;;
+		xma.l	fp0b_1 = u_1, v0, f0
+		xma.hu	fp1a_1 = u_1, v0, f0
+	;;
+		getfsig	pr0_0 = fp0b_0
+		xma.l	fp1b_0 = uy, v1, fp1a_0
+		xma.hu	fp2a_0 = uy, v1, fp1a_0
+	;;
+		ldf8	u_0 = [up], 8
+		getfsig	pr1_3 = fp1b_3
+		xma.l	fp0b_2 = u_2, v0, f0
+	;;
+		getfsig	acc1_3 = fp2a_3
+		xma.hu	fp1a_2 = u_2, v0, f0
+		br	L(00)
+
+
+	ALIGN(32)
+L(b01):		ldf8	u_0 = [up], 8		C M
+		mov	acc1_1 = 0		C M I
+		mov	pr1_1 = 0		C M I
+		mov	pr0_2 = 0		C M I
+		cmp.ne	p6, p7 = r0, r0		C M I
+	;;
+		xma.l	fp0b_2 = ux, v0, f0	C F
+		cmp.ne	p10, p11 = r0, r0	C M I
+		ldf8	u_1 = [up], 8		C M
+		xma.hu	fp1a_2 = ux, v0, f0	C F
+	;;
+		xma.l	fp0b_3 = uy, v0, f0	C F
+		xma.hu	fp1a_3 = uy, v0, f0	C F
+	;;
+		getfsig	acc0 = fp0b_2		C M
+		xma.l	fp1b_2 = ux, v1,fp1a_2	C F
+		ldf8	u_2 = [up], 8		C M
+		xma.hu	fp2a_2 = ux, v1,fp1a_2	C F
+		br.cloop.dptk	L(gt5)
+
+		xma.l	fp0b_0 = u_0, v0, f0	C F
+		xma.hu	fp1a_0 = u_0, v0, f0	C F
+	;;
+		getfsig	pr0_3 = fp0b_3		C M
+		xma.l	fp1b_3 = uy, v1,fp1a_3	C F
+		xma.hu	fp2a_3 = uy, v1,fp1a_3	C F
+	;;
+		getfsig	pr1_2 = fp1b_2		C M
+		getfsig	acc1_2 = fp2a_2		C M
+		xma.l	fp0b_1 = u_1, v0, f0	C F
+		xma.hu	fp1a_1 = u_1, v0, f0	C F
+		br	L(cj5)
+
+L(gt5):		xma.l	fp0b_0 = u_0, v0, f0
+		xma.hu	fp1a_0 = u_0, v0, f0
+	;;
+		getfsig	pr0_3 = fp0b_3
+		xma.l	fp1b_3 = uy, v1, fp1a_3
+		xma.hu	fp2a_3 = uy, v1, fp1a_3
+	;;
+		ldf8	u_3 = [up], 8
+		getfsig	pr1_2 = fp1b_2
+		xma.l	fp0b_1 = u_1, v0, f0
+	;;
+		getfsig	acc1_2 = fp2a_2
+		xma.hu	fp1a_1 = u_1, v0, f0
+		br	L(01)
+
+
+	ALIGN(32)
+L(b10):		br.cloop.dptk	L(gt2)
+		xma.l	fp0b_1 = ux, v0, f0
+		xma.hu	fp1a_1 = ux, v0, f0
+	;;
+		xma.l	fp0b_2 = uy, v0, f0
+		xma.hu	fp1a_2 = uy, v0, f0
+	;;
+		stf8	[rp] = fp0b_1, 8
+		xma.l	fp1b_1 = ux, v1, fp1a_1
+		xma.hu	fp2a_1 = ux, v1, fp1a_1
+	;;
+		getfsig	acc0 = fp0b_2
+		xma.l	fp1b_2 = uy, v1, fp1a_2
+		xma.hu	fp2a_2 = uy, v1, fp1a_2
+	;;
+		getfsig	pr1_1 = fp1b_1
+		getfsig	acc1_1 = fp2a_1
+		mov	ar.lc = r2
+		getfsig	pr1_2 = fp1b_2
+		getfsig	r8 = fp2a_2
+	;;
+		add	s0 = pr1_1, acc0
+	;;
+		st8	[rp] = s0, 8
+		cmp.ltu	p8, p9 = s0, pr1_1
+		sub	r31 = -1, acc1_1
+	;;
+	.pred.rel "mutex", p8, p9
+	(p8)	add	acc0 = pr1_2, acc1_1, 1
+	(p9)	add	acc0 = pr1_2, acc1_1
+	(p8)	cmp.leu	p10, p0 = r31, pr1_2
+	(p9)	cmp.ltu	p10, p0 = r31, pr1_2
+	;;
+		st8	[rp] = acc0, 8
+	(p10)	add	r8 = 1, r8
+		br.ret.sptk.many b0
+
+L(gt2):		ldf8	u_3 = [up], 8
+		mov	acc1_0 = 0
+		mov	pr1_0 = 0
+	;;
+		mov	pr0_1 = 0
+		xma.l	fp0b_1 = ux, v0, f0
+		ldf8	u_0 = [up], 8
+		xma.hu	fp1a_1 = ux, v0, f0
+	;;
+		xma.l	fp0b_2 = uy, v0, f0
+		xma.hu	fp1a_2 = uy, v0, f0
+	;;
+		getfsig	acc0 = fp0b_1
+		xma.l	fp1b_1 = ux, v1, fp1a_1
+		xma.hu	fp2a_1 = ux, v1, fp1a_1
+	;;
+		ldf8	u_1 = [up], 8
+		xma.l	fp0b_3 = u_3, v0, f0
+		xma.hu	fp1a_3 = u_3, v0, f0
+	;;
+		getfsig	pr0_2 = fp0b_2
+		xma.l	fp1b_2 = uy, v1, fp1a_2
+		xma.hu	fp2a_2 = uy, v1, fp1a_2
+	;;
+		ldf8	u_2 = [up], 8
+		getfsig	pr1_1 = fp1b_1
+	;;
+ {.mfi;		getfsig	acc1_1 = fp2a_1
+		xma.l	fp0b_0 = u_0, v0, f0
+		cmp.ne	p8, p9 = r0, r0
+}{.mfb;		cmp.ne	p12, p13 = r0, r0
+		xma.hu	fp1a_0 = u_0, v0, f0
+		br	L(10)
+}
+
+	ALIGN(32)
+L(b11):		mov	acc1_3 = 0
+		mov	pr1_3 = 0
+		mov	pr0_0 = 0
+		ldf8	u_2 = [up], 8
+		cmp.ne	p6, p7 = r0, r0
+		br.cloop.dptk	L(gt3)
+	;;
+		xma.l	fp0b_0 = ux, v0, f0
+		xma.hu	fp1a_0 = ux, v0, f0
+	;;
+		cmp.ne	p10, p11 = r0, r0
+		xma.l	fp0b_1 = uy, v0, f0
+		xma.hu	fp1a_1 = uy, v0, f0
+	;;
+		getfsig	acc0 = fp0b_0
+		xma.l	fp1b_0 = ux, v1, fp1a_0
+		xma.hu	fp2a_0 = ux, v1, fp1a_0
+	;;
+		xma.l	fp0b_2 = u_2, v0, f0
+		xma.hu	fp1a_2 = u_2, v0, f0
+	;;
+		getfsig	pr0_1 = fp0b_1
+		xma.l	fp1b_1 = uy, v1, fp1a_1
+		xma.hu	fp2a_1 = uy, v1, fp1a_1
+	;;
+		getfsig	pr1_0 = fp1b_0
+		getfsig	acc1_0 = fp2a_0
+		br	L(cj3)
+
+L(gt3):		xma.l	fp0b_0 = ux, v0, f0
+		cmp.ne	p10, p11 = r0, r0
+		ldf8	u_3 = [up], 8
+		xma.hu	fp1a_0 = ux, v0, f0
+	;;
+		xma.l	fp0b_1 = uy, v0, f0
+		xma.hu	fp1a_1 = uy, v0, f0
+	;;
+		getfsig	acc0 = fp0b_0
+		xma.l	fp1b_0 = ux, v1, fp1a_0
+		ldf8	u_0 = [up], 8
+		xma.hu	fp2a_0 = ux, v1, fp1a_0
+	;;
+		xma.l	fp0b_2 = u_2, v0, f0
+		xma.hu	fp1a_2 = u_2, v0, f0
+	;;
+		getfsig	pr0_1 = fp0b_1
+		xma.l	fp1b_1 = uy, v1, fp1a_1
+		xma.hu	fp2a_1 = uy, v1, fp1a_1
+	;;
+		ldf8	u_1 = [up], 8
+		getfsig	pr1_0 = fp1b_0
+	;;
+		getfsig	acc1_0 = fp2a_0
+		xma.l	fp0b_3 = u_3, v0, f0
+		xma.hu	fp1a_3 = u_3, v0, f0
+		br	L(11)
+
+
+C *** MAIN LOOP START ***
+	ALIGN(32)
+L(top):						C 00
+	.pred.rel "mutex", p8, p9
+	.pred.rel "mutex", p12, p13
+		ldf8	u_3 = [up], 8
+		getfsig	pr1_2 = fp1b_2
+	(p8)	cmp.leu	p6, p7 = acc0, pr0_1
+	(p9)	cmp.ltu	p6, p7 = acc0, pr0_1
+	(p12)	cmp.leu	p10, p11 = s0, pr1_0
+	(p13)	cmp.ltu	p10, p11 = s0, pr1_0
+	;;					C 01
+	.pred.rel "mutex", p6, p7
+		getfsig	acc1_2 = fp2a_2
+		st8	[rp] = s0, 8
+		xma.l	fp0b_1 = u_1, v0, f0
+	(p6)	add	acc0 = pr0_2, acc1_0, 1
+	(p7)	add	acc0 = pr0_2, acc1_0
+		xma.hu	fp1a_1 = u_1, v0, f0
+	;;					C 02
+L(01):
+	.pred.rel "mutex", p10, p11
+		getfsig	pr0_0 = fp0b_0
+		xma.l	fp1b_0 = u_0, v1, fp1a_0
+	(p10)	add	s0 = pr1_1, acc0, 1
+	(p11)	add	s0 = pr1_1, acc0
+		xma.hu	fp2a_0 = u_0, v1, fp1a_0
+		nop	1
+	;;					C 03
+	.pred.rel "mutex", p6, p7
+	.pred.rel "mutex", p10, p11
+		ldf8	u_0 = [up], 8
+		getfsig	pr1_3 = fp1b_3
+	(p6)	cmp.leu	p8, p9 = acc0, pr0_2
+	(p7)	cmp.ltu	p8, p9 = acc0, pr0_2
+	(p10)	cmp.leu	p12, p13 = s0, pr1_1
+	(p11)	cmp.ltu	p12, p13 = s0, pr1_1
+	;;					C 04
+	.pred.rel "mutex", p8, p9
+		getfsig	acc1_3 = fp2a_3
+		st8	[rp] = s0, 8
+		xma.l	fp0b_2 = u_2, v0, f0
+	(p8)	add	acc0 = pr0_3, acc1_1, 1
+	(p9)	add	acc0 = pr0_3, acc1_1
+		xma.hu	fp1a_2 = u_2, v0, f0
+	;;					C 05
+L(00):
+	.pred.rel "mutex", p12, p13
+		getfsig	pr0_1 = fp0b_1
+		xma.l	fp1b_1 = u_1, v1, fp1a_1
+	(p12)	add	s0 = pr1_2, acc0, 1
+	(p13)	add	s0 = pr1_2, acc0
+		xma.hu	fp2a_1 = u_1, v1, fp1a_1
+		nop	1
+	;;					C 06
+	.pred.rel "mutex", p8, p9
+	.pred.rel "mutex", p12, p13
+		ldf8	u_1 = [up], 8
+		getfsig	pr1_0 = fp1b_0
+	(p8)	cmp.leu	p6, p7 = acc0, pr0_3
+	(p9)	cmp.ltu	p6, p7 = acc0, pr0_3
+	(p12)	cmp.leu	p10, p11 = s0, pr1_2
+	(p13)	cmp.ltu	p10, p11 = s0, pr1_2
+	;;					C 07
+	.pred.rel "mutex", p6, p7
+		getfsig	acc1_0 = fp2a_0
+		st8	[rp] = s0, 8
+		xma.l	fp0b_3 = u_3, v0, f0
+	(p6)	add	acc0 = pr0_0, acc1_2, 1
+	(p7)	add	acc0 = pr0_0, acc1_2
+		xma.hu	fp1a_3 = u_3, v0, f0
+	;;					C 08
+L(11):
+	.pred.rel "mutex", p10, p11
+		getfsig	pr0_2 = fp0b_2
+		xma.l	fp1b_2 = u_2, v1, fp1a_2
+	(p10)	add	s0 = pr1_3, acc0, 1
+	(p11)	add	s0 = pr1_3, acc0
+		xma.hu	fp2a_2 = u_2, v1, fp1a_2
+		nop	1
+	;;					C 09
+	.pred.rel "mutex", p6, p7
+	.pred.rel "mutex", p10, p11
+		ldf8	u_2 = [up], 8
+		getfsig	pr1_1 = fp1b_1
+	(p6)	cmp.leu	p8, p9 = acc0, pr0_0
+	(p7)	cmp.ltu	p8, p9 = acc0, pr0_0
+	(p10)	cmp.leu	p12, p13 = s0, pr1_3
+	(p11)	cmp.ltu	p12, p13 = s0, pr1_3
+	;;					C 10
+	.pred.rel "mutex", p8, p9
+		getfsig	acc1_1 = fp2a_1
+		st8	[rp] = s0, 8
+		xma.l	fp0b_0 = u_0, v0, f0
+	(p8)	add	acc0 = pr0_1, acc1_3, 1
+	(p9)	add	acc0 = pr0_1, acc1_3
+		xma.hu	fp1a_0 = u_0, v0, f0
+	;;					C 11
+L(10):
+	.pred.rel "mutex", p12, p13
+		getfsig	pr0_3 = fp0b_3
+		xma.l	fp1b_3 = u_3, v1, fp1a_3
+	(p12)	add	s0 = pr1_0, acc0, 1
+	(p13)	add	s0 = pr1_0, acc0
+		xma.hu	fp2a_3 = u_3, v1, fp1a_3
+		br.cloop.dptk	L(top)
+	;;
+C *** MAIN LOOP END ***
+
+	.pred.rel "mutex", p8, p9
+	.pred.rel "mutex", p12, p13
+ {.mmi;		getfsig	pr1_2 = fp1b_2
+		st8	[rp] = s0, 8
+	(p8)	cmp.leu	p6, p7 = acc0, pr0_1
+}{.mmi;	(p9)	cmp.ltu	p6, p7 = acc0, pr0_1
+	(p12)	cmp.leu	p10, p11 = s0, pr1_0
+	(p13)	cmp.ltu	p10, p11 = s0, pr1_0
+	;;
+}	.pred.rel "mutex", p6, p7
+ {.mfi;		getfsig	acc1_2 = fp2a_2
+		xma.l	fp0b_1 = u_1, v0, f0
+		nop	1
+}{.mmf;	(p6)	add	acc0 = pr0_2, acc1_0, 1
+	(p7)	add	acc0 = pr0_2, acc1_0
+		xma.hu	fp1a_1 = u_1, v0, f0
+	;;
+}
+L(cj5):
+	.pred.rel "mutex", p10, p11
+ {.mfi;		getfsig	pr0_0 = fp0b_0
+		xma.l	fp1b_0 = u_0, v1, fp1a_0
+	(p10)	add	s0 = pr1_1, acc0, 1
+}{.mfi;	(p11)	add	s0 = pr1_1, acc0
+		xma.hu	fp2a_0 = u_0, v1, fp1a_0
+		nop	1
+	;;
+}	.pred.rel "mutex", p6, p7
+	.pred.rel "mutex", p10, p11
+ {.mmi;		getfsig	pr1_3 = fp1b_3
+		st8	[rp] = s0, 8
+	(p6)	cmp.leu	p8, p9 = acc0, pr0_2
+}{.mmi;	(p7)	cmp.ltu	p8, p9 = acc0, pr0_2
+	(p10)	cmp.leu	p12, p13 = s0, pr1_1
+	(p11)	cmp.ltu	p12, p13 = s0, pr1_1
+	;;
+}	.pred.rel "mutex", p8, p9
+ {.mfi;		getfsig	acc1_3 = fp2a_3
+		xma.l	fp0b_2 = u_2, v0, f0
+		nop	1
+}{.mmf;	(p8)	add	acc0 = pr0_3, acc1_1, 1
+	(p9)	add	acc0 = pr0_3, acc1_1
+		xma.hu	fp1a_2 = u_2, v0, f0
+	;;
+}
+L(cj4):
+	.pred.rel "mutex", p12, p13
+ {.mfi;		getfsig	pr0_1 = fp0b_1
+		xma.l	fp1b_1 = u_1, v1, fp1a_1
+	(p12)	add	s0 = pr1_2, acc0, 1
+}{.mfi;	(p13)	add	s0 = pr1_2, acc0
+		xma.hu	fp2a_1 = u_1, v1, fp1a_1
+		nop	1
+	;;
+}	.pred.rel "mutex", p8, p9
+	.pred.rel "mutex", p12, p13
+ {.mmi;		getfsig	pr1_0 = fp1b_0
+		st8	[rp] = s0, 8
+	(p8)	cmp.leu	p6, p7 = acc0, pr0_3
+}{.mmi;	(p9)	cmp.ltu	p6, p7 = acc0, pr0_3
+	(p12)	cmp.leu	p10, p11 = s0, pr1_2
+	(p13)	cmp.ltu	p10, p11 = s0, pr1_2
+	;;
+}	.pred.rel "mutex", p6, p7
+ {.mmi;		getfsig	acc1_0 = fp2a_0
+	(p6)	add	acc0 = pr0_0, acc1_2, 1
+	(p7)	add	acc0 = pr0_0, acc1_2
+	;;
+}
+L(cj3):
+	.pred.rel "mutex", p10, p11
+ {.mfi;		getfsig	pr0_2 = fp0b_2
+		xma.l	fp1b_2 = u_2, v1, fp1a_2
+	(p10)	add	s0 = pr1_3, acc0, 1
+}{.mfi;	(p11)	add	s0 = pr1_3, acc0
+		xma.hu	fp2a_2 = u_2, v1, fp1a_2
+		nop	1
+	;;
+}	.pred.rel "mutex", p6, p7
+	.pred.rel "mutex", p10, p11
+ {.mmi;		getfsig	pr1_1 = fp1b_1
+		st8	[rp] = s0, 8
+	(p6)	cmp.leu	p8, p9 = acc0, pr0_0
+}{.mmi;	(p7)	cmp.ltu	p8, p9 = acc0, pr0_0
+	(p10)	cmp.leu	p12, p13 = s0, pr1_3
+	(p11)	cmp.ltu	p12, p13 = s0, pr1_3
+	;;
+}	.pred.rel "mutex", p8, p9
+ {.mmi;		getfsig	acc1_1 = fp2a_1
+	(p8)	add	acc0 = pr0_1, acc1_3, 1
+	(p9)	add	acc0 = pr0_1, acc1_3
+	;;
+}	.pred.rel "mutex", p12, p13
+ {.mmi;	(p12)	add	s0 = pr1_0, acc0, 1
+	(p13)	add	s0 = pr1_0, acc0
+		nop	1
+	;;
+}	.pred.rel "mutex", p8, p9
+	.pred.rel "mutex", p12, p13
+ {.mmi;		getfsig	pr1_2 = fp1b_2
+		st8	[rp] = s0, 8
+	(p8)	cmp.leu	p6, p7 = acc0, pr0_1
+}{.mmi;	(p9)	cmp.ltu	p6, p7 = acc0, pr0_1
+	(p12)	cmp.leu	p10, p11 = s0, pr1_0
+	(p13)	cmp.ltu	p10, p11 = s0, pr1_0
+	;;
+}	.pred.rel "mutex", p6, p7
+ {.mmi;		getfsig	r8 = fp2a_2
+	(p6)	add	acc0 = pr0_2, acc1_0, 1
+	(p7)	add	acc0 = pr0_2, acc1_0
+	;;
+}	.pred.rel "mutex", p10, p11
+ {.mmi;	(p10)	add	s0 = pr1_1, acc0, 1
+	(p11)	add	s0 = pr1_1, acc0
+	(p6)	cmp.leu	p8, p9 = acc0, pr0_2
+	;;
+}	.pred.rel "mutex", p10, p11
+ {.mmi;	(p7)	cmp.ltu	p8, p9 = acc0, pr0_2
+	(p10)	cmp.leu	p12, p13 = s0, pr1_1
+	(p11)	cmp.ltu	p12, p13 = s0, pr1_1
+	;;
+}	.pred.rel "mutex", p8, p9
+ {.mmi;		st8	[rp] = s0, 8
+	(p8)	add	acc0 = pr1_2, acc1_1, 1
+	(p9)	add	acc0 = pr1_2, acc1_1
+	;;
+}	.pred.rel "mutex", p8, p9
+ {.mmi;	(p8)	cmp.leu	p10, p11 = acc0, pr1_2
+	(p9)	cmp.ltu	p10, p11 = acc0, pr1_2
+	(p12)	add	acc0 = 1, acc0
+	;;
+}{.mmi;		st8	[rp] = acc0, 8
+	(p12)	cmpeqor	p10, p0 = 0, acc0
+		nop	1
+	;;
+}{.mib;	(p10)	add	r8 = 1, r8
+		mov	ar.lc = r2
+		br.ret.sptk.many b0
+}
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/ia64/popcount.asm b/third_party/gmp/mpn/ia64/popcount.asm
new file mode 100644
index 0000000..c0b5c5c
--- /dev/null
+++ b/third_party/gmp/mpn/ia64/popcount.asm
@@ -0,0 +1,200 @@
+dnl  IA-64 mpn_popcount -- mpn population count.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2000-2005 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C           cycles/limb
+C Itanium:       1.5
+C Itanium 2:     1
+
+C INPUT PARAMETERS
+define(`up', `r32')
+define(`n', `r33')
+
+define(`u0',`r16') define(`u1',`r17') define(`u2',`r18') define(`u3',`r19')
+define(`c0',`r28') define(`c1',`r29') define(`c2',`r30') define(`c3',`r31')
+define(`s',`r8')
+
+
+ASM_START()
+PROLOGUE(mpn_popcount)
+	.prologue
+ifdef(`HAVE_ABI_32',
+`	addp4		up = 0, up		C			M I
+	nop.m		0
+	zxt4		n = n			C			I
+	;;
+')
+
+ {.mmi;	add		r9 = 512, up		C prefetch pointer	M I
+	ld8		r10 = [up], 8		C load first limb	M01
+	mov.i		r2 = ar.lc		C save ar.lc		I0
+}{.mmi;	and		r14 = 3, n		C			M I
+	cmp.lt		p15, p14 = 4, n		C small count?		M I
+	add		n = -5, n		C			M I
+	;;
+}{.mmi;	cmp.eq		p6, p0 = 1, r14		C			M I
+	cmp.eq		p7, p0 = 2, r14		C			M I
+	cmp.eq		p8, p0 = 3, r14		C			M I
+}{.bbb
+  (p6)	br.dptk		.Lb01			C			B
+  (p7)	br.dptk		.Lb10			C			B
+  (p8)	br.dptk		.Lb11			C			B
+}
+
+
+.Lb00:	ld8		u1 = [up], 8		C			M01
+	shr.u		n = n, 2		C			I0
+	mov		s = 0			C			M I
+	;;
+	ld8		u2 = [up], 8		C			M01
+	popcnt		c0 = r10		C			I0
+	mov.i		ar.lc = n		C			I0
+	;;
+	ld8		u3 = [up], 8		C			M01
+	popcnt		c1 = u1			C			I0
+  (p15)	br.cond.dptk	.grt4			C			B
+	;;
+	nop.m	0				C			-
+	nop.m	0				C			-
+	popcnt		c2 = u2			C			I0
+	;;
+	mov		s = c0			C			M I
+	popcnt		c3 = u3			C			I0
+	br		.Lcj4			C			B
+
+.grt4:	ld8		u0 = [up], 8		C			M01
+	popcnt		c2 = u2			C			I0
+	br		.LL00			C			B
+
+
+.Lb01:
+	popcnt		s = r10			C			I0
+  (p14)	br.ret.sptk.many b0			C			B
+
+.grt1:	ld8		u0 = [up], 8		C			M01
+	shr.u		n = n, 2		C			I0
+	;;
+	ld8		u1 = [up], 8		C			M01
+	mov.i		ar.lc = n		C			I0
+	;;
+	ld8		u2 = [up], 8		C			M01
+	popcnt		c0 = u0			C			I0
+	mov		c3 = 0			C			I0
+
+	;;
+	ld8		u3 = [up], 8		C			M01
+	popcnt		c1 = u1			C			I0
+	br.cloop.dptk	.Loop			C			B
+	br		.Lend			C			B
+
+
+.Lb10:	ld8		u3 = [up], 8		C			M01
+	shr.u		n = n, 2		C			I0
+  (p15)	br.cond.dptk	.grt2			C			B
+
+	popcnt		s = r10			C			I0
+	;;
+	popcnt		c3 = u3			C			I0
+	br		.Lcj2			C			B
+
+.grt2:	ld8		u0 = [up], 8		C			M01
+	mov.i		ar.lc = n		C			I0
+	popcnt		c2 = r10		C			I0
+	;;
+	ld8		u1 = [up], 8		C			M01
+	popcnt		c3 = u3			C			I0
+	mov		s = 0			C			M I
+	;;
+	ld8		u2 = [up], 8		C			M01
+	popcnt		c0 = u0			C			I0
+	br		.LL10			C			B
+
+
+.Lb11:	ld8		u2 = [up], 8		C			M01
+	shr.u		n = n, 2		C			I0
+	mov		s = 0			C			M I
+	;;
+	ld8		u3 = [up], 8		C			M01
+	popcnt		s = r10			C			I0
+  (p15)	br.cond.dptk	.grt3			C			B
+
+	popcnt		c2 = u2			C			I0
+	;;
+	popcnt		c3 = u3			C			I0
+	br		.Lcj3			C			B
+
+.grt3:	ld8		u0 = [up], 8		C			M01
+	popcnt		c2 = u2			C			I0
+	mov.i		ar.lc = n		C			I0
+	mov		c1 = 0
+	;;
+	ld8		u1 = [up], 8		C			M01
+	popcnt		c3 = u3			C			I0
+	br		.LL11			C			B
+
+
+.Loop:	ld8		u0 = [up], 8		C			M01
+	popcnt		c2 = u2			C			I0
+	add		s = s, c3		C			M I
+	;;
+.LL00:	ld8		u1 = [up], 8		C			M01
+	popcnt		c3 = u3			C			I0
+	add		s = s, c0		C			M I
+	;;
+.LL11:	ld8		u2 = [up], 8		C			M01
+	popcnt		c0 = u0			C			I0
+	add		s = s, c1		C			M I
+	;;
+.LL10:	ld8		u3 = [up], 8		C			M01
+	popcnt		c1 = u1			C			I0
+	add		s = s, c2		C			M I
+	lfetch		[r9], 32		C			M01
+	nop.m		0			C			-
+	br.cloop.dptk	.Loop			C			B
+	;;
+
+.Lend:	popcnt		c2 = u2			C			I0
+	add		s = s, c3		C			M I
+	;;
+	popcnt		c3 = u3			C			I0
+	add		s = s, c0		C			M I
+	;;
+.Lcj4:	add		s = s, c1		C			M I
+	;;
+.Lcj3:	add		s = s, c2		C			M I
+	;;
+.Lcj2:	add		s = s, c3		C			M I
+	mov.i		ar.lc = r2		C			I0
+	br.ret.sptk.many b0			C			B
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/ia64/rsh1aors_n.asm b/third_party/gmp/mpn/ia64/rsh1aors_n.asm
new file mode 100644
index 0000000..3c7defb
--- /dev/null
+++ b/third_party/gmp/mpn/ia64/rsh1aors_n.asm
@@ -0,0 +1,447 @@
+dnl  IA-64 mpn_rsh1add_n/mpn_rsh1sub_n -- rp[] = (up[] +- vp[]) >> 1.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2003-2005 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C         cycles/limb
+C Itanium:    2.5
+C Itanium 2:  1.5
+
+C TODO
+C  * Rewrite function entry code using aorslsh1_n.asm style.
+C  * Micro-optimize feed-in and wind-down code.
+
+C INPUT PARAMETERS
+define(`rp',`r32')
+define(`up',`r33')
+define(`vp',`r34')
+define(`n',`r35')
+
+ifdef(`OPERATION_rsh1add_n',`
+  define(ADDSUB,       add)
+  define(PRED,	       ltu)
+  define(INCR,	       1)
+  define(LIM,	       -1)
+  define(func, mpn_rsh1add_n)
+')
+ifdef(`OPERATION_rsh1sub_n',`
+  define(ADDSUB,       sub)
+  define(PRED,	       gtu)
+  define(INCR,	       -1)
+  define(LIM,	       0)
+  define(func, mpn_rsh1sub_n)
+')
+
+C Some useful aliases for registers we use
+define(`u0',`r14') define(`u1',`r15') define(`u2',`r16') define(`u3',`r17')
+define(`v0',`r18') define(`v1',`r19') define(`v2',`r20') define(`v3',`r21')
+define(`w0',`r22') define(`w1',`r23') define(`w2',`r24') define(`w3',`r25')
+define(`x0',`r26') define(`x1',`r9') define(`x2',`r30') define(`x3',`r31')
+
+MULFUNC_PROLOGUE(mpn_rsh1add_n mpn_rsh1sub_n)
+
+ASM_START()
+PROLOGUE(func)
+	.prologue
+	.save	ar.lc, r2
+	.body
+ifdef(`HAVE_ABI_32',`
+	addp4		rp = 0, rp		C			M I
+	addp4		up = 0, up		C			M I
+	addp4		vp = 0, vp		C			M I
+	nop.m		0
+	nop.m		0
+	zxt4		n = n			C			I
+	;;
+')
+ {.mmi;	ld8		r11 = [vp], 8		C			M01
+	ld8		r10 = [up], 8		C			M01
+	mov.i		r2 = ar.lc		C			I0
+}{.mmi;	and		r14 = 3, n		C			M I
+	cmp.lt		p15, p0 = 4, n		C			M I
+	add		n = -4, n		C			M I
+	;;
+}{.mmi;	cmp.eq		p6, p0 = 1, r14		C			M I
+	cmp.eq		p7, p0 = 2, r14		C			M I
+	cmp.eq		p8, p0 = 3, r14		C			M I
+}{.bbb
+  (p6)	br.dptk		.Lb01			C			B
+  (p7)	br.dptk		.Lb10			C			B
+  (p8)	br.dptk		.Lb11			C			B
+}
+
+.Lb00:	ld8		v0 = [vp], 8		C			M01
+	ld8		u0 = [up], 8		C			M01
+	shr.u		n = n, 2		C			I0
+	;;
+	ld8		v1 = [vp], 8		C			M01
+	ld8		u1 = [up], 8		C			M01
+	ADDSUB		w3 = r10, r11		C			M I
+	;;
+	ld8		v2 = [vp], 8		C			M01
+	ld8		u2 = [up], 8		C			M01
+  (p15)	br.dpnt		.grt4			C			B
+	;;
+
+	cmp.PRED	p7, p0 = w3, r10	C			M I
+	and		r8 = 1, w3		C			M I
+	ADDSUB		w0 = u0, v0		C			M I
+	;;
+	cmp.PRED	p8, p0 = w0, u0		C			M I
+	ADDSUB		w1 = u1, v1		C			M I
+	;;
+	cmp.PRED	p9, p0 = w1, u1		C			M I
+   (p7)	cmp.eq.or	p8, p0 = LIM, w0	C			M I
+   (p7)	add		w0 = INCR, w0		C			M I
+	;;
+	shrp		x3 = w0, w3, 1		C			I0
+	ADDSUB		w2 = u2, v2		C			M I
+   (p8)	cmp.eq.or	p9, p0 = LIM, w1	C			M I
+   (p8)	add		w1 = INCR, w1		C			M I
+	br		.Lcj4			C			B
+
+.grt4:	ld8		v3 = [vp], 8		C			M01
+	cmp.PRED	p7, p0 = w3, r10	C			M I
+	ld8		u3 = [up], 8		C			M01
+	and		r8 = 1, w3		C			M I
+	;;
+	ADDSUB		w0 = u0, v0		C			M I
+	ld8		v0 = [vp], 8		C			M01
+	add		n = -1, n
+	;;
+	cmp.PRED	p8, p0 = w0, u0		C			M I
+	ld8		u0 = [up], 8		C			M01
+	ADDSUB		w1 = u1, v1		C			M I
+	;;
+	ld8		v1 = [vp], 8		C			M01
+	mov.i		ar.lc = n		C			I0
+	cmp.PRED	p9, p0 = w1, u1		C			M I
+	ld8		u1 = [up], 8		C			M01
+   (p7)	cmp.eq.or	p8, p0 = LIM, w0	C			M I
+   (p7)	add		w0 = INCR, w0		C			M I
+	;;
+	ADDSUB		w2 = u2, v2		C			M I
+	ld8		v2 = [vp], 8		C			M01
+	shrp		x3 = w0, w3, 1		C			I0
+   (p8)	cmp.eq.or	p9, p0 = LIM, w1	C			M I
+   (p8)	add		w1 = INCR, w1		C			M I
+	br		.LL00			C			B
+
+
+.Lb01:	ADDSUB		w2 = r10, r11		C			M I
+	shr.u		n = n, 2		C			I0
+  (p15)	br.dpnt		.grt1			C			B
+	;;
+
+	cmp.PRED	p6, p7 = w2, r10	C			M I
+	shr.u		x2 = w2, 1		C			I0
+	and		r8 = 1, w2		C			M I
+	;;
+   (p6)	dep		x2 = -1, x2, 63, 1	C			I0
+	br		.Lcj1			C			B
+
+.grt1:	ld8		v3 = [vp], 8		C			M01
+	ld8		u3 = [up], 8		C			M01
+	;;
+	ld8		v0 = [vp], 8		C			M01
+	ld8		u0 = [up], 8		C			M01
+	mov.i		ar.lc = n		C FIXME swap with next	I0
+	;;
+	ld8		v1 = [vp], 8		C			M01
+	ld8		u1 = [up], 8		C			M01
+	;;
+	ld8		v2 = [vp], 8		C			M01
+	ld8		u2 = [up], 8		C			M01
+	cmp.PRED	p6, p0 = w2, r10	C			M I
+	and		r8 = 1, w2		C			M I
+	ADDSUB		w3 = u3, v3		C			M I
+	br.cloop.dptk	.grt5			C			B
+	;;
+
+	cmp.PRED	p7, p0 = w3, u3		C			M I
+	;;
+	ADDSUB		w0 = u0, v0		C			M I
+   (p6)	cmp.eq.or	p7, p0 = LIM, w3	C			M I
+   (p6)	add		w3 = INCR, w3		C			M I
+	;;
+	cmp.PRED	p8, p0 = w0, u0		C			M I
+	shrp		x2 = w3, w2, 1		C			I0
+	ADDSUB		w1 = u1, v1		C			M I
+	;;
+	cmp.PRED	p9, p0 = w1, u1		C			M I
+   (p7)	cmp.eq.or	p8, p0 = LIM, w0	C			M I
+   (p7)	add		w0 = INCR, w0		C			M I
+	br		.Lcj5			C			B
+
+.grt5:	ld8		v3 = [vp], 8		C			M01
+	cmp.PRED	p7, p0 = w3, u3		C			M I
+	ld8		u3 = [up], 8		C			M01
+	;;
+	ADDSUB		w0 = u0, v0		C			M I
+	ld8		v0 = [vp], 8		C			M01
+   (p6)	cmp.eq.or	p7, p0 = LIM, w3	C			M I
+   (p6)	add		w3 = INCR, w3		C			M I
+	;;
+	cmp.PRED	p8, p0 = w0, u0		C			M I
+	shrp		x2 = w3, w2, 1		C			I0
+	ld8		u0 = [up], 8		C			M01
+	ADDSUB		w1 = u1, v1		C			M I
+	;;
+	ld8		v1 = [vp], 8		C			M01
+	cmp.PRED	p9, p0 = w1, u1		C			M I
+	ld8		u1 = [up], 8		C			M01
+   (p7)	cmp.eq.or	p8, p0 = LIM, w0	C			M I
+   (p7)	add		w0 = INCR, w0		C			M I
+	br		.LL01			C			B
+
+
+.Lb10:	ld8		v2 = [vp], 8		C			M01
+	ld8		u2 = [up], 8		C			M01
+	shr.u		n = n, 2		C			I0
+	ADDSUB		w1 = r10, r11		C			M I
+  (p15)	br.dpnt		.grt2			C			B
+	;;
+
+	cmp.PRED	p9, p0 = w1, r10	C			M I
+	and		r8 = 1, w1		C			M I
+	ADDSUB		w2 = u2, v2		C			M I
+	;;
+	cmp.PRED	p6, p0 = w2, u2		C			M I
+	;;
+   (p9)	cmp.eq.or	p6, p0 = LIM, w2	C			M I
+   (p9)	add		w2 = INCR, w2		C			M I
+	;;
+	shrp		x1 = w2, w1, 1		C			I0
+	shr.u		x2 = w2, 1		C			I0
+	br		.Lcj2			C			B
+
+.grt2:	ld8		v3 = [vp], 8		C			M01
+	ld8		u3 = [up], 8		C			M01
+	;;
+	ld8		v0 = [vp], 8		C			M01
+	ld8		u0 = [up], 8		C			M01
+	mov.i		ar.lc = n		C			I0
+	;;
+	ld8		v1 = [vp], 8		C			M01
+	cmp.PRED	p9, p0 = w1, r10	C			M I
+	ld8		u1 = [up], 8		C			M01
+	and		r8 = 1, w1		C			M I
+	;;
+	ADDSUB		w2 = u2, v2		C			M I
+	ld8		v2 = [vp], 8		C			M01
+	;;
+	cmp.PRED	p6, p0 = w2, u2		C			M I
+	ld8		u2 = [up], 8		C			M01
+	ADDSUB		w3 = u3, v3		C			M I
+	br.cloop.dptk	.grt6			C			B
+	;;
+
+	cmp.PRED	p7, p0 = w3, u3		C			M I
+   (p9)	cmp.eq.or	p6, p0 = LIM, w2	C			M I
+   (p9)	add		w2 = INCR, w2		C			M I
+	;;
+	shrp		x1 = w2, w1, 1		C			I0
+	ADDSUB		w0 = u0, v0		C			M I
+   (p6)	cmp.eq.or	p7, p0 = LIM, w3	C			M I
+   (p6)	add		w3 = INCR, w3		C			M I
+	br		.Lcj6			C			B
+
+.grt6:	ld8		v3 = [vp], 8		C			M01
+	cmp.PRED	p7, p0 = w3, u3		C			M I
+	ld8		u3 = [up], 8		C			M01
+   (p9)	cmp.eq.or	p6, p0 = LIM, w2	C			M I
+   (p9)	add		w2 = INCR, w2		C			M I
+	;;
+	shrp		x1 = w2, w1, 1		C			I0
+	ADDSUB		w0 = u0, v0		C			M I
+	ld8		v0 = [vp], 8		C			M01
+   (p6)	cmp.eq.or	p7, p0 = LIM, w3	C			M I
+   (p6)	add		w3 = INCR, w3		C			M I
+	br		.LL10			C			B
+
+
+.Lb11:	ld8		v1 = [vp], 8		C			M01
+	ld8		u1 = [up], 8		C			M01
+	shr.u		n = n, 2		C			I0
+	;;
+	ld8		v2 = [vp], 8		C			M01
+	ld8		u2 = [up], 8		C			M01
+	ADDSUB		w0 = r10, r11		C			M I
+  (p15)	br.dpnt		.grt3			C			B
+	;;
+
+	cmp.PRED	p8, p0 = w0, r10	C			M I
+	ADDSUB		w1 = u1, v1		C			M I
+	and		r8 = 1, w0		C			M I
+	;;
+	cmp.PRED	p9, p0 = w1, u1		C			M I
+	;;
+	ADDSUB		w2 = u2, v2		C			M I
+   (p8)	cmp.eq.or	p9, p0 = LIM, w1	C			M I
+   (p8)	add		w1 = INCR, w1		C			M I
+	;;
+	cmp.PRED	p6, p0 = w2, u2		C			M I
+	shrp		x0 = w1, w0, 1		C			I0
+	;;
+   (p9)	cmp.eq.or	p6, p0 = LIM, w2	C			M I
+   (p9)	add		w2 = INCR, w2		C			M I
+	br		.Lcj3			C			B
+
+.grt3:	ld8		v3 = [vp], 8		C			M01
+	ld8		u3 = [up], 8		C			M01
+	;;
+	ld8		v0 = [vp], 8		C			M01
+	mov.i		ar.lc = n		C			I0
+	cmp.PRED	p8, p0 = w0, r10	C			M I
+	ld8		u0 = [up], 8		C			M01
+	ADDSUB		w1 = u1, v1		C			M I
+	and		r8 = 1, w0		C			M I
+	;;
+	ld8		v1 = [vp], 8		C			M01
+	cmp.PRED	p9, p0 = w1, u1		C			M I
+	ld8		u1 = [up], 8		C			M01
+	;;
+	ADDSUB		w2 = u2, v2		C			M I
+	ld8		v2 = [vp], 8		C			M01
+   (p8)	cmp.eq.or	p9, p0 = LIM, w1	C			M I
+   (p8)	add		w1 = INCR, w1		C			M I
+	;;
+	cmp.PRED	p6, p0 = w2, u2		C			M I
+	shrp		x0 = w1, w0, 1		C			I0
+	ld8		u2 = [up], 8		C			M01
+	ADDSUB		w3 = u3, v3		C			M I
+	br.cloop.dptk	.grt7			C			B
+	;;
+
+	cmp.PRED	p7, p0 = w3, u3		C			M I
+   (p9)	cmp.eq.or	p6, p0 = LIM, w2	C			M I
+   (p9)	add		w2 = INCR, w2		C			M I
+	br		.Lcj7			C			B
+
+.grt7:	ld8		v3 = [vp], 8		C			M01
+	cmp.PRED	p7, p0 = w3, u3		C			M I
+	ld8		u3 = [up], 8		C			M01
+   (p9)	cmp.eq.or	p6, p0 = LIM, w2	C			M I
+   (p9)	add		w2 = INCR, w2		C			M I
+	br		.LL11			C			B
+
+
+C *** MAIN LOOP START ***
+	ALIGN(32)
+.Loop:	st8		[rp] = x3, 8		C			M23
+	ld8		v3 = [vp], 8		C			M01
+	cmp.PRED	p7, p0 = w3, u3		C			M I
+	ld8		u3 = [up], 8		C			M01
+   (p9)	cmp.eq.or	p6, p0 = LIM, w2	C			M I
+   (p9)	add		w2 = INCR, w2		C			M I
+	;;
+.LL11:	st8		[rp] = x0, 8		C			M23
+	shrp		x1 = w2, w1, 1		C			I0
+	ADDSUB		w0 = u0, v0		C			M I
+	ld8		v0 = [vp], 8		C			M01
+   (p6)	cmp.eq.or	p7, p0 = LIM, w3	C			M I
+   (p6)	add		w3 = INCR, w3		C			M I
+	;;
+.LL10:	cmp.PRED	p8, p0 = w0, u0		C			M I
+	shrp		x2 = w3, w2, 1		C			I0
+	nop.b		0
+	ld8		u0 = [up], 8		C			M01
+	ADDSUB		w1 = u1, v1		C			M I
+	nop.b		0
+	;;
+	st8		[rp] = x1, 8		C			M23
+	ld8		v1 = [vp], 8		C			M01
+	cmp.PRED	p9, p0 = w1, u1		C			M I
+	ld8		u1 = [up], 8		C			M01
+   (p7)	cmp.eq.or	p8, p0 = LIM, w0	C			M I
+   (p7)	add		w0 = INCR, w0		C			M I
+	;;
+.LL01:	st8		[rp] = x2, 8		C			M23
+	shrp		x3 = w0, w3, 1		C			I0
+	ADDSUB		w2 = u2, v2		C			M I
+	ld8		v2 = [vp], 8		C			M01
+   (p8)	cmp.eq.or	p9, p0 = LIM, w1	C			M I
+   (p8)	add		w1 = INCR, w1		C			M I
+	;;
+.LL00:	cmp.PRED	p6, p0 = w2, u2		C			M I
+	shrp		x0 = w1, w0, 1		C			I0
+	nop.b		0
+	ld8		u2 = [up], 8		C			M01
+	ADDSUB		w3 = u3, v3		C			M I
+	br.cloop.dptk	.Loop			C			B
+	;;
+C *** MAIN LOOP END ***
+
+.Lskip:	st8		[rp] = x3, 8		C			M23
+	cmp.PRED	p7, p0 = w3, u3		C			M I
+   (p9)	cmp.eq.or	p6, p0 = LIM, w2	C			M I
+   (p9)	add		w2 = INCR, w2		C			M I
+	;;
+.Lcj7:	st8		[rp] = x0, 8		C			M23
+	shrp		x1 = w2, w1, 1		C			I0
+	ADDSUB		w0 = u0, v0		C			M I
+   (p6)	cmp.eq.or	p7, p0 = LIM, w3	C			M I
+   (p6)	add		w3 = INCR, w3		C			M I
+	;;
+.Lcj6:	cmp.PRED	p8, p0 = w0, u0		C			M I
+	shrp		x2 = w3, w2, 1		C			I0
+	ADDSUB		w1 = u1, v1		C			M I
+	;;
+	st8		[rp] = x1, 8		C			M23
+	cmp.PRED	p9, p0 = w1, u1		C			M I
+   (p7)	cmp.eq.or	p8, p0 = LIM, w0	C			M I
+   (p7)	add		w0 = INCR, w0		C			M I
+	;;
+.Lcj5:	st8		[rp] = x2, 8		C			M23
+	shrp		x3 = w0, w3, 1		C			I0
+	ADDSUB		w2 = u2, v2		C			M I
+   (p8)	cmp.eq.or	p9, p0 = LIM, w1	C			M I
+   (p8)	add		w1 = INCR, w1		C			M I
+	;;
+.Lcj4:	cmp.PRED	p6, p0 = w2, u2		C			M I
+	shrp		x0 = w1, w0, 1		C			I0
+	;;
+	st8		[rp] = x3, 8		C			M23
+   (p9)	cmp.eq.or	p6, p0 = LIM, w2	C			M I
+   (p9)	add		w2 = INCR, w2		C			M I
+	;;
+.Lcj3:	st8		[rp] = x0, 8		C			M23
+	shrp		x1 = w2, w1, 1		C			I0
+	shr.u		x2 = w2, 1		C			I0
+	;;
+.Lcj2:	st8		[rp] = x1, 8		C			M23
+   (p6)	dep		x2 = -1, x2, 63, 1	C			I0
+	;;
+.Lcj1:	st8		[rp] = x2		C			M23
+	mov.i		ar.lc = r2		C			I0
+	br.ret.sptk.many b0			C			B
+EPILOGUE()
diff --git a/third_party/gmp/mpn/ia64/sec_tabselect.asm b/third_party/gmp/mpn/ia64/sec_tabselect.asm
new file mode 100644
index 0000000..9b11cde
--- /dev/null
+++ b/third_party/gmp/mpn/ia64/sec_tabselect.asm
@@ -0,0 +1,148 @@
+dnl  IA-64 mpn_sec_tabselect.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C           cycles/limb
+C Itanium:       ?
+C Itanium 2:     2.5
+
+C NOTES
+C  * Using software pipelining could trivially yield 2 c/l without unrolling,
+C    or 1+epsilon with unrolling.  (This code was modelled after the powerpc64
+C    code, for simplicity.)
+
+C mpn_sec_tabselect (mp_limb_t *rp, mp_limb_t *tp, mp_size_t n, mp_size_t nents, mp_size_t which)
+define(`rp',     `r32')
+define(`tp',     `r33')
+define(`n',      `r34')
+define(`nents',  `r35')
+define(`which',  `r36')
+
+define(`mask',   `r8')
+
+define(`rp1',     `r32')
+define(`tp1',     `r33')
+define(`rp2',     `r14')
+define(`tp2',     `r15')
+
+ASM_START()
+PROLOGUE(mpn_sec_tabselect)
+	.prologue
+	.save	ar.lc, r2
+	.body
+ifdef(`HAVE_ABI_32',`
+ {.mmi;	addp4	rp = 0, rp		C			M I
+	addp4	tp = 0, tp		C			M I
+	zxt4	n = n			C			I
+}{.mii;	nop	0
+	zxt4	nents = nents		C			I
+	zxt4	which = which		C			I
+	;;
+}')
+ {.mmi;	add	rp2 = 8, rp1
+	add	tp2 = 8, tp1
+	add	r6 = -2, n
+	;;
+}{.mmi;	cmp.eq	p10, p0 = 1, n
+	and	r9 = 1, n		C set cr0 for use in inner loop
+	shr.u	r6 = r6, 1		C inner loop count
+	;;
+}{.mmi;	cmp.eq	p8, p0 = 0, r9
+	sub	which = nents, which
+	shl	n = n, 3
+	;;
+}
+L(outer):
+ {.mmi;	cmp.eq	p6, p7 = which, nents	C are we at the selected table entry?
+	nop	0
+	mov	ar.lc = r6		C			I0
+	;;
+}{.mmb;
+  (p6)	mov	mask = -1
+  (p7)	mov	mask = 0
+  (p8)	br.dptk	L(top)			C branch to loop entry if n even
+	;;
+}{.mmi;	ld8	r16 = [tp1], 8
+	add	tp2 = 8, tp2
+	nop	0
+	;;
+}{.mmi;	ld8	r18 = [rp1]
+	and	r16 = r16, mask
+	nop	0
+	;;
+}{.mmi;	andcm	r18 = r18, mask
+	;;
+	or	r16 = r16, r18
+	nop	0
+	;;
+}{.mmb;	st8	[rp1] = r16, 8
+	add	rp2 = 8, rp2
+  (p10)	br.dpnt	L(end)
+}
+	ALIGN(32)
+L(top):
+ {.mmi;	ld8	r16 = [tp1], 16
+	ld8	r17 = [tp2], 16
+	nop	0
+	;;
+}{.mmi;	ld8	r18 = [rp1]
+	and	r16 = r16, mask
+	nop	0
+}{.mmi;	ld8	r19 = [rp2]
+	and	r17 = r17, mask
+	nop	0
+	;;
+}{.mmi;	andcm	r18 = r18, mask
+	andcm	r19 = r19, mask
+	nop	0
+	;;
+}{.mmi;	or	r16 = r16, r18
+	or	r17 = r17, r19
+	nop	0
+	;;
+}{.mmb;	st8	[rp1] = r16, 16
+	st8	[rp2] = r17, 16
+	br.cloop.dptk	L(top)
+	;;
+}
+L(end):
+ {.mmi;	sub	rp1 = rp1, n		C move rp back to beginning
+	sub	rp2 = rp2, n		C move rp back to beginning
+	cmp.ne	p9, p0 = 1, nents
+}{.mmb;	add	nents = -1, nents
+	nop	0
+  (p9)	br.dptk	L(outer)
+	;;
+}{.mib;	nop	0
+	nop	0
+	br.ret.sptk.many b0
+}
+EPILOGUE()
diff --git a/third_party/gmp/mpn/ia64/sqr_diag_addlsh1.asm b/third_party/gmp/mpn/ia64/sqr_diag_addlsh1.asm
new file mode 100644
index 0000000..727f489
--- /dev/null
+++ b/third_party/gmp/mpn/ia64/sqr_diag_addlsh1.asm
@@ -0,0 +1,156 @@
+dnl  IA-64 mpn_sqr_diag_addlsh1
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2010, 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C           cycles/limb
+C Itanium:      ?
+C Itanium 2:    2	Unrolling could bring it to 1.5 + epsilon
+
+C Exact performance table.  The 2nd line is this code, the 3rd line is ctop-
+C less code.  In an assembly sqr_basecase, the ctop-full numbers will become a
+C few cycles better since we can mitigate the many I0 instructions.
+C
+C 1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19  20
+C -  20  22  24  26  28  30  32  34  36  38  40  42  44  46  48  50  52  54  56 Needs updating
+C -  13  16  17  18  20  21  23  25  26  30  31  31  33  34  36  38  39  42  43
+
+C We should keep in mind that this code takes linear time in a O(n^2) context
+C and that it will only be used under SQR_TOOM2_THRESHOLD, which might become
+C around 60.  Keeping overhead down for smallish operands (< 10) is more
+C important than optimal cycle counts.
+
+C TODO
+C  * Make sure we don't depend on uninitialised r-registers, f-registers, or
+C  * p-registers.
+C  * Optimise by doing first two loop iterations in function header.
+
+C INPUT PARAMETERS
+define(`rp_param', `r32')  define(`rp', `r14')		C size: 2n
+define(`tp_param', `r33')  define(`tp', `r15')		C size: 2n - 2
+define(`up_param', `r34')  define(`up', `r31')		C size: n
+define(`n',  `r35')
+
+ifdef(`HAVE_ABI_32',`
+	define(`ABI64', `')
+	define(`ABI32', `$1')
+',`
+	define(`ABI64', `$1')
+	define(`ABI32', `')
+')
+
+ASM_START()
+PROLOGUE(mpn_sqr_diag_addlsh1)
+
+	.prologue
+	.save	ar.pfs, r2
+	.save	ar.lc, r3
+	.body
+
+ {.mii;		alloc	r2 = ar.pfs, 4,24,0,24	C			M
+		mov	r3 = ar.lc		C			I0
+	ABI64(`	nop	4711		')
+	ABI32(`	zxt4	n = n		')
+}{.mmi;	ABI64(`	mov	tp = tp_param	')	C			M I
+	ABI32(`	addp4	tp = 0, tp_param')	C			M I
+	ABI64(`	mov	up = up_param	')	C			M I
+	ABI32(`	addp4	up = 0, up_param')	C			M I
+	ABI64(`	mov	rp = rp_param	')	C			M I
+	ABI32(`	addp4	rp = 0, rp_param')	C			M I
+	;;
+}{.mmi;		ld8	r36 = [tp], 8		C			M
+		add	r20 = -2, n		C			M I
+		mov	r9 = ar.ec		C			I0
+	;;
+}{.mmi;		ld8	r32 = [tp], 8		C			M
+		mov	r16 = 0			C			M I
+		mov	ar.ec = 7		C			I0
+	;;
+}{.mmi;		nop	4711
+		mov	r44 = 0			C			M I
+		mov	ar.lc = r20		C			I0
+	;;
+}{.mii;		mov	r33 = 0
+		mov	r10 = pr		C			I0
+		mov	pr.rot = 0x30000	C			I0
+	;;
+}		br.cexit.spnt.few.clr	L(end)
+
+dnl *** MAIN LOOP START ***
+	ALIGN(32)
+L(top):
+ {.mfi;	(p18)	ldf8	f33 = [up], 8		C			M
+	(p20)	xma.l	f36 = f35, f35, f42	C			F
+	(p41)	cmpequc	p50, p0 = -1, r44	C			M I
+}{.mfi;		setfsig	f40 = r16		C			M23
+	(p20)	xma.hu	f38 = f35, f35, f42	C			F
+	(p23)	add	r50 = r41, r49		C			M I
+	;;
+}{.mmi;	(p16)	ld8	r36 = [tp], 8		C			M
+	(p23)	cmpltu	p40, p0 = r50, r41	C cyout hi		M I
+	(p19)	shrp	r45 = r38, r35, 63	C non-critical		I0
+}{.mmi;	(p21)	getfsig	r39 = f39		C hi			M2
+	(p24)	st8	[rp] = r51, 8		C hi			M23
+	(p41)	add	r44 = 1, r44		C			M I
+	;;
+}{.mmi;	(p16)	ld8	r32 = [tp], 8		C			M
+	(p50)	cmpeqor	p40, p0 = -1, r50	C cyout hi		M I
+	(p17)	shrp	r16 = r33, r37, 63	C critical		I0
+}{.mmi;	(p21)	getfsig	r42 = f37		C lo			M2
+	(p23)	st8	[rp] = r44, 8		C lo			M23
+	(p50)	add	r50 = 1, r50		C			M I
+	;;
+}		br.ctop.sptk.few.clr L(top)	C			B
+dnl *** MAIN LOOP END ***
+	;;
+L(end):
+ {.mmi;		nop	4711
+	(p41)	add	r44 = 1, r44		C			M I
+		shr.u	r48 = r39, 63		C			I0
+	;;
+}{.mmi;		st8	[rp] = r51, 8		C			M23
+	(p41)	cmpequc	p6, p0 = 0, r44		C			M I
+		add	r50 = r41, r48		C			M I
+	;;
+}{.mmi;		st8	[rp] = r44, 8		C			M23
+	(p6)	add	r50 = 1, r50		C			M I
+		mov	ar.lc = r3		C			I0
+	;;
+}{.mii;		st8	[rp] = r50		C			M23
+		mov	ar.ec = r9		C			I0
+		mov	pr = r10		C			I0
+	;;
+}{.mib;		nop	4711
+		mov	ar.pfs = r2		C			I0
+		br.ret.sptk.many b0		C			B
+}
+EPILOGUE()
diff --git a/third_party/gmp/mpn/ia64/submul_1.asm b/third_party/gmp/mpn/ia64/submul_1.asm
new file mode 100644
index 0000000..cb2a552
--- /dev/null
+++ b/third_party/gmp/mpn/ia64/submul_1.asm
@@ -0,0 +1,647 @@
+dnl  IA-64 mpn_submul_1 -- Multiply a limb vector with a limb and subtract the
+dnl  result from a second limb vector.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2000-2004 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C         cycles/limb
+C Itanium:    4.0
+C Itanium 2:  2.25 (alignment dependent, sometimes it seems to need 3 c/l)
+
+C TODO
+C  * Optimize feed-in and wind-down code, both for speed and code size.
+C  * Handle low limb input and results specially, using a common stf8 in the
+C    epilogue.
+C  * Delay r8, r10 initialization, put cmp-p6 in 1st bundle and br .Ldone in
+C    2nd bundle.  This will allow the bbb bundle to be one cycle earlier and
+C    save a cycle.
+
+C INPUT PARAMETERS
+define(`rp', `r32')
+define(`up', `r33')
+define(`n',  `r34')
+define(`vl', `r35')
+
+ASM_START()
+PROLOGUE(mpn_submul_1)
+	.prologue
+	.save	ar.lc, r2
+	.body
+
+ifdef(`HAVE_ABI_32',
+`	addp4		rp = 0, rp		C M I
+	addp4		up = 0, up		C M I
+	zxt4		n = n			C I
+	;;
+')
+{.mmi
+	mov		r10 = rp		C M I
+	mov		r9 = up			C M I
+	sub		vl = r0, vl		C M I	negate vl
+}
+{.mmi
+	ldf8		f8 = [rp], 8		C M
+	ldf8		f7 = [up], 8		C M
+	add		r19 = -1, n		C M I	n - 1
+	;;
+}
+{.mmi
+	cmp.eq		p6, p0 = 0, vl		C M I
+	mov		r8 = 0			C M I	zero cylimb
+	mov		r2 = ar.lc		C I0
+}
+{.mmi
+	setf.sig	f6 = vl			C M2 M3
+	and		r14 = 3, n		C M I
+	shr.u		r19 = r19, 2		C I0
+	;;
+}
+{.mmb
+	nop		0
+	cmp.eq		p10, p0 = 0, r14	C M I
+   (p6)	br.spnt		.Ldone			C B	vl == 0
+}
+{.mmi
+	cmp.eq		p11, p0 = 2, r14	C M I
+	cmp.eq		p12, p0 = 3, r14	C M I
+	mov		ar.lc = r19		C I0
+}
+{.bbb
+  (p10)	br.dptk		.Lb00			C B
+  (p11)	br.dptk		.Lb10			C B
+  (p12)	br.dptk		.Lb11			C B
+	;;
+}
+
+.Lb01:	br.cloop.dptk	.grt1
+
+	xma.l		f39 = f7, f6, f8
+	xma.hu		f43 = f7, f6, f8
+	;;
+	getf.sig	r27 = f39			C lo
+	getf.sig	r31 = f43			C hi
+	ld8		r20 = [r9], 8
+	br		.Lcj1
+
+.grt1:	ldf8		f44 = [rp], 8
+	ldf8		f32 = [up], 8
+	;;
+	ldf8		f45 = [rp], 8
+	ldf8		f33 = [up], 8
+	;;
+	ldf8		f46 = [rp], 8
+	xma.l		f39 = f7, f6, f8
+	ldf8		f34 = [up], 8
+	xma.hu		f43 = f7, f6, f8
+	;;
+	ldf8		f47 = [rp], 8
+	xma.l		f36 = f32, f6, f44
+	ldf8		f35 = [up], 8
+	xma.hu		f40 = f32, f6, f44
+	br.cloop.dptk	.grt5
+	;;
+
+	getf.sig	r27 = f39			C lo
+	xma.l		f37 = f33, f6, f45
+	ld8		r20 = [r9], 8
+	xma.hu		f41 = f33, f6, f45
+	;;
+	getf.sig	r31 = f43			C hi
+	getf.sig	r24 = f36			C lo
+	xma.l		f38 = f34, f6, f46
+	ld8		r21 = [r9], 8
+	xma.hu		f42 = f34, f6, f46
+	;;
+	getf.sig	r28 = f40			C hi
+	getf.sig	r25 = f37			C lo
+	xma.l		f39 = f35, f6, f47
+	ld8		r22 = [r9], 8
+	xma.hu		f43 = f35, f6, f47
+	;;
+	getf.sig	r29 = f41			C hi
+	getf.sig	r26 = f38			C lo
+	ld8		r23 = [r9], 8
+	br		.Lcj5
+
+.grt5:	ldf8		f44 = [rp], 8
+	ldf8		f32 = [up], 8
+	;;
+	getf.sig	r27 = f39			C lo
+	xma.l		f37 = f33, f6, f45
+	ld8		r20 = [r9], 8
+	xma.hu		f41 = f33, f6, f45
+	;;
+	ldf8		f45 = [rp], 8
+	getf.sig	r31 = f43			C hi
+	ldf8		f33 = [up], 8
+	;;
+	getf.sig	r24 = f36			C lo
+	xma.l		f38 = f34, f6, f46
+	ld8		r21 = [r9], 8
+	xma.hu		f42 = f34, f6, f46
+	;;
+	ldf8		f46 = [rp], 8
+	getf.sig	r28 = f40			C hi
+	ldf8		f34 = [up], 8
+	;;
+	getf.sig	r25 = f37			C lo
+	xma.l		f39 = f35, f6, f47
+	ld8		r22 = [r9], 8
+	xma.hu		f43 = f35, f6, f47
+	;;
+	ldf8		f47 = [rp], 8
+	getf.sig	r29 = f41			C hi
+	ldf8		f35 = [up], 8
+	;;
+	getf.sig	r26 = f38			C lo
+	xma.l		f36 = f32, f6, f44
+	ld8		r23 = [r9], 8
+	xma.hu		f40 = f32, f6, f44
+	br.cloop.dptk	.Loop
+	br		.Lend
+
+
+.Lb10:	ldf8		f47 = [rp], 8
+	ldf8		f35 = [up], 8
+	br.cloop.dptk	.grt2
+
+	xma.l		f38 = f7, f6, f8
+	xma.hu		f42 = f7, f6, f8
+	;;
+	xma.l		f39 = f35, f6, f47
+	xma.hu		f43 = f35, f6, f47
+	;;
+	getf.sig	r26 = f38			C lo
+	getf.sig	r30 = f42			C hi
+	ld8		r23 = [r9], 8
+	;;
+	getf.sig	r27 = f39			C lo
+	getf.sig	r31 = f43			C hi
+	ld8		r20 = [r9], 8
+	br		.Lcj2
+
+.grt2:	ldf8		f44 = [rp], 8
+	ldf8		f32 = [up], 8
+	;;
+	ldf8		f45 = [rp], 8
+	ldf8		f33 = [up], 8
+	xma.l		f38 = f7, f6, f8
+	xma.hu		f42 = f7, f6, f8
+	;;
+	ldf8		f46 = [rp], 8
+	ldf8		f34 = [up], 8
+	xma.l		f39 = f35, f6, f47
+	xma.hu		f43 = f35, f6, f47
+	;;
+	ldf8		f47 = [rp], 8
+	ldf8		f35 = [up], 8
+	;;
+	getf.sig	r26 = f38			C lo
+	xma.l		f36 = f32, f6, f44
+	ld8		r23 = [r9], 8
+	xma.hu		f40 = f32, f6, f44
+	br.cloop.dptk	.grt6
+
+	getf.sig	r30 = f42			C hi
+	;;
+	getf.sig	r27 = f39			C lo
+	xma.l		f37 = f33, f6, f45
+	ld8		r20 = [r9], 8
+	xma.hu		f41 = f33, f6, f45
+	;;
+	getf.sig	r31 = f43			C hi
+	getf.sig	r24 = f36			C lo
+	xma.l		f38 = f34, f6, f46
+	ld8		r21 = [r9], 8
+	xma.hu		f42 = f34, f6, f46
+	;;
+	getf.sig	r28 = f40			C hi
+	getf.sig	r25 = f37			C lo
+	xma.l		f39 = f35, f6, f47
+	ld8		r22 = [r9], 8
+	xma.hu		f43 = f35, f6, f47
+	br		.Lcj6
+
+.grt6:	ldf8		f44 = [rp], 8
+	getf.sig	r30 = f42			C hi
+	ldf8		f32 = [up], 8
+	;;
+	getf.sig	r27 = f39			C lo
+	xma.l		f37 = f33, f6, f45
+	ld8		r20 = [r9], 8
+	xma.hu		f41 = f33, f6, f45
+	;;
+	ldf8		f45 = [rp], 8
+	getf.sig	r31 = f43			C hi
+	ldf8		f33 = [up], 8
+	;;
+	getf.sig	r24 = f36			C lo
+	xma.l		f38 = f34, f6, f46
+	ld8		r21 = [r9], 8
+	xma.hu		f42 = f34, f6, f46
+	;;
+	ldf8		f46 = [rp], 8
+	getf.sig	r28 = f40			C hi
+	ldf8		f34 = [up], 8
+	;;
+	getf.sig	r25 = f37			C lo
+	xma.l		f39 = f35, f6, f47
+	ld8		r22 = [r9], 8
+	xma.hu		f43 = f35, f6, f47
+	br		.LL10
+
+
+.Lb11:	ldf8		f46 = [rp], 8
+	ldf8		f34 = [up], 8
+	;;
+	ldf8		f47 = [rp], 8
+	ldf8		f35 = [up], 8
+	br.cloop.dptk	.grt3
+
+	xma.l		f37 = f7, f6, f8
+	xma.hu		f41 = f7, f6, f8
+	;;
+	xma.l		f38 = f34, f6, f46
+	xma.hu		f42 = f34, f6, f46
+	;;
+	getf.sig	r25 = f37			C lo
+	xma.l		f39 = f35, f6, f47
+	xma.hu		f43 = f35, f6, f47
+	;;
+	getf.sig	r29 = f41			C hi
+	ld8		r22 = [r9], 8
+	;;
+	getf.sig	r26 = f38			C lo
+	getf.sig	r30 = f42			C hi
+	ld8		r23 = [r9], 8
+	;;
+	getf.sig	r27 = f39			C lo
+	getf.sig	r31 = f43			C hi
+	ld8		r20 = [r9], 8
+	br		.Lcj3
+
+.grt3:	ldf8		f44 = [rp], 8
+	xma.l		f37 = f7, f6, f8
+	ldf8		f32 = [up], 8
+	xma.hu		f41 = f7, f6, f8
+	;;
+	ldf8		f45 = [rp], 8
+	xma.l		f38 = f34, f6, f46
+	ldf8		f33 = [up], 8
+	xma.hu		f42 = f34, f6, f46
+	;;
+	ldf8		f46 = [rp], 8
+	ldf8		f34 = [up], 8
+	;;
+	getf.sig	r25 = f37			C lo
+	xma.l		f39 = f35, f6, f47
+	ld8		r22 = [r9], 8
+	xma.hu		f43 = f35, f6, f47
+	;;
+	ldf8		f47 = [rp], 8
+	getf.sig	r29 = f41			C hi
+	ldf8		f35 = [up], 8
+	;;
+	getf.sig	r26 = f38			C lo
+	xma.l		f36 = f32, f6, f44
+	ld8		r23 = [r9], 8
+	xma.hu		f40 = f32, f6, f44
+	br.cloop.dptk	.grt7
+	;;
+
+	getf.sig	r30 = f42			C hi
+	getf.sig	r27 = f39			C lo
+	xma.l		f37 = f33, f6, f45
+	ld8		r20 = [r9], 8
+	xma.hu		f41 = f33, f6, f45
+	;;
+	getf.sig	r31 = f43			C hi
+	getf.sig	r24 = f36			C lo
+	xma.l		f38 = f34, f6, f46
+	ld8		r21 = [r9], 8
+	xma.hu		f42 = f34, f6, f46
+	br		.Lcj7
+
+.grt7:	ldf8		f44 = [rp], 8
+	getf.sig	r30 = f42			C hi
+	ldf8		f32 = [up], 8
+	;;
+	getf.sig	r27 = f39			C lo
+	xma.l		f37 = f33, f6, f45
+	ld8		r20 = [r9], 8
+	xma.hu		f41 = f33, f6, f45
+	;;
+	ldf8		f45 = [rp], 8
+	getf.sig	r31 = f43			C hi
+	ldf8		f33 = [up], 8
+	;;
+	getf.sig	r24 = f36			C lo
+	xma.l		f38 = f34, f6, f46
+	ld8		r21 = [r9], 8
+	xma.hu		f42 = f34, f6, f46
+	br		.LL11
+
+
+.Lb00:	ldf8		f45 = [rp], 8
+	ldf8		f33 = [up], 8
+	;;
+	ldf8		f46 = [rp], 8
+	ldf8		f34 = [up], 8
+	;;
+	ldf8		f47 = [rp], 8
+	xma.l		f36 = f7, f6, f8
+	ldf8		f35 = [up], 8
+	xma.hu		f40 = f7, f6, f8
+	br.cloop.dptk	.grt4
+
+	xma.l		f37 = f33, f6, f45
+	xma.hu		f41 = f33, f6, f45
+	;;
+	getf.sig	r24 = f36			C lo
+	xma.l		f38 = f34, f6, f46
+	ld8		r21 = [r9], 8
+	xma.hu		f42 = f34, f6, f46
+	;;
+	getf.sig	r28 = f40			C hi
+	xma.l		f39 = f35, f6, f47
+	getf.sig	r25 = f37			C lo
+	ld8		r22 = [r9], 8
+	xma.hu		f43 = f35, f6, f47
+	;;
+	getf.sig	r29 = f41			C hi
+	getf.sig	r26 = f38			C lo
+	ld8		r23 = [r9], 8
+	;;
+	getf.sig	r30 = f42			C hi
+	getf.sig	r27 = f39			C lo
+	ld8		r20 = [r9], 8
+	br		.Lcj4
+
+.grt4:	ldf8		f44 = [rp], 8
+	xma.l		f37 = f33, f6, f45
+	ldf8		f32 = [up], 8
+	xma.hu		f41 = f33, f6, f45
+	;;
+	ldf8		f45 = [rp], 8
+	ldf8		f33 = [up], 8
+	xma.l		f38 = f34, f6, f46
+	getf.sig	r24 = f36			C lo
+	ld8		r21 = [r9], 8
+	xma.hu		f42 = f34, f6, f46
+	;;
+	ldf8		f46 = [rp], 8
+	getf.sig	r28 = f40			C hi
+	ldf8		f34 = [up], 8
+	xma.l		f39 = f35, f6, f47
+	getf.sig	r25 = f37			C lo
+	ld8		r22 = [r9], 8
+	xma.hu		f43 = f35, f6, f47
+	;;
+	ldf8		f47 = [rp], 8
+	getf.sig	r29 = f41			C hi
+	ldf8		f35 = [up], 8
+	;;
+	getf.sig	r26 = f38			C lo
+	xma.l		f36 = f32, f6, f44
+	ld8		r23 = [r9], 8
+	xma.hu		f40 = f32, f6, f44
+	br.cloop.dptk	.grt8
+	;;
+
+	getf.sig	r30 = f42			C hi
+	getf.sig	r27 = f39			C lo
+	xma.l		f37 = f33, f6, f45
+	ld8		r20 = [r9], 8
+	xma.hu		f41 = f33, f6, f45
+	br		.Lcj8
+
+.grt8:	ldf8		f44 = [rp], 8
+	getf.sig	r30 = f42			C hi
+	ldf8		f32 = [up], 8
+	;;
+	getf.sig	r27 = f39			C lo
+	xma.l		f37 = f33, f6, f45
+	ld8		r20 = [r9], 8
+	xma.hu		f41 = f33, f6, f45
+	br		.LL00
+
+	ALIGN(32)
+.Loop:
+{.mmi
+	ldf8		f44 = [rp], 8
+	cmp.ltu		p6, p0 = r27, r8	C lo cmp
+	sub		r14 = r27, r8		C lo sub
+}
+{.mmi
+	getf.sig	r30 = f42			C hi
+	ldf8		f32 = [up], 8
+	sub		r8 = r20, r31		C hi sub
+	;;				C 01
+}
+{.mmf
+	getf.sig	r27 = f39			C lo
+	st8		[r10] = r14, 8
+	xma.l		f37 = f33, f6, f45
+}
+{.mfi
+	ld8		r20 = [r9], 8
+	xma.hu		f41 = f33, f6, f45
+   (p6)	add		r8 = 1, r8
+	;;				C 02
+}
+{.mmi
+.LL00:	ldf8		f45 = [rp], 8
+	cmp.ltu		p6, p0 = r24, r8
+	sub		r14 = r24, r8
+}
+{.mmi
+	getf.sig	r31 = f43			C hi
+	ldf8		f33 = [up], 8
+	sub		r8 = r21, r28
+	;;				C 03
+}
+{.mmf
+	getf.sig	r24 = f36			C lo
+	st8		[r10] = r14, 8
+	xma.l		f38 = f34, f6, f46
+}
+{.mfi
+	ld8		r21 = [r9], 8
+	xma.hu		f42 = f34, f6, f46
+   (p6)	add		r8 = 1, r8
+	;;				C 04
+}
+{.mmi
+.LL11:	ldf8		f46 = [rp], 8
+	cmp.ltu		p6, p0 = r25, r8
+	sub		r14 = r25, r8
+}
+{.mmi
+	getf.sig	r28 = f40			C hi
+	ldf8		f34 = [up], 8
+	sub		r8 = r22, r29
+	;;				C 05
+}
+{.mmf
+	getf.sig	r25 = f37			C lo
+	st8		[r10] = r14, 8
+	xma.l		f39 = f35, f6, f47
+}
+{.mfi
+	ld8		r22 = [r9], 8
+	xma.hu		f43 = f35, f6, f47
+   (p6)	add		r8 = 1, r8
+	;;				C 06
+}
+{.mmi
+.LL10:	ldf8		f47 = [rp], 8
+	cmp.ltu		p6, p0 = r26, r8
+	sub		r14 = r26, r8
+}
+{.mmi
+	getf.sig	r29 = f41			C hi
+	ldf8		f35 = [up], 8
+	sub		r8 = r23, r30
+	;;				C 07
+}
+{.mmf
+	getf.sig	r26 = f38			C lo
+	st8		[r10] = r14, 8
+	xma.l		f36 = f32, f6, f44
+}
+{.mfi
+	ld8		r23 = [r9], 8
+	xma.hu		f40 = f32, f6, f44
+   (p6)	add		r8 = 1, r8
+}
+	br.cloop.dptk	.Loop
+	;;
+
+.Lend:
+	cmp.ltu		p6, p0 = r27, r8
+	sub		r14 = r27, r8
+	getf.sig	r30 = f42
+	sub		r8 = r20, r31
+	;;
+	getf.sig	r27 = f39
+	st8		[r10] = r14, 8
+	xma.l		f37 = f33, f6, f45
+	ld8		r20 = [r9], 8
+	xma.hu		f41 = f33, f6, f45
+   (p6)	add		r8 = 1, r8
+	;;
+.Lcj8:
+	cmp.ltu		p6, p0 = r24, r8
+	sub		r14 = r24, r8
+	getf.sig	r31 = f43
+	sub		r8 = r21, r28
+	;;
+	getf.sig	r24 = f36
+	st8		[r10] = r14, 8
+	xma.l		f38 = f34, f6, f46
+	ld8		r21 = [r9], 8
+	xma.hu		f42 = f34, f6, f46
+   (p6)	add		r8 = 1, r8
+	;;
+.Lcj7:
+	cmp.ltu		p6, p0 = r25, r8
+	sub		r14 = r25, r8
+	getf.sig	r28 = f40
+	sub		r8 = r22, r29
+	;;
+	getf.sig	r25 = f37
+	st8		[r10] = r14, 8
+	xma.l		f39 = f35, f6, f47
+	ld8		r22 = [r9], 8
+	xma.hu		f43 = f35, f6, f47
+   (p6)	add		r8 = 1, r8
+	;;
+.Lcj6:
+	cmp.ltu		p6, p0 = r26, r8
+	sub		r14 = r26, r8
+	getf.sig	r29 = f41
+	sub		r8 = r23, r30
+	;;
+	getf.sig	r26 = f38
+	st8		[r10] = r14, 8
+	ld8		r23 = [r9], 8
+   (p6)	add		r8 = 1, r8
+	;;
+.Lcj5:
+	cmp.ltu		p6, p0 = r27, r8
+	sub		r14 = r27, r8
+	getf.sig	r30 = f42
+	sub		r8 = r20, r31
+	;;
+	getf.sig	r27 = f39
+	st8		[r10] = r14, 8
+	ld8		r20 = [r9], 8
+   (p6)	add		r8 = 1, r8
+	;;
+.Lcj4:
+	cmp.ltu		p6, p0 = r24, r8
+	sub		r14 = r24, r8
+	getf.sig	r31 = f43
+	sub		r8 = r21, r28
+	;;
+	st8		[r10] = r14, 8
+   (p6)	add		r8 = 1, r8
+	;;
+.Lcj3:
+	cmp.ltu		p6, p0 = r25, r8
+	sub		r14 = r25, r8
+	sub		r8 = r22, r29
+	;;
+	st8		[r10] = r14, 8
+   (p6)	add		r8 = 1, r8
+	;;
+.Lcj2:
+	cmp.ltu		p6, p0 = r26, r8
+	sub		r14 = r26, r8
+	sub		r8 = r23, r30
+	;;
+	st8		[r10] = r14, 8
+   (p6)	add		r8 = 1, r8
+	;;
+.Lcj1:
+	cmp.ltu		p6, p0 = r27, r8
+	sub		r14 = r27, r8
+	sub		r8 = r20, r31
+	;;
+	st8		[r10] = r14, 8
+	mov		ar.lc = r2
+   (p6)	add		r8 = 1, r8
+	br.ret.sptk.many b0
+.Ldone:	mov		ar.lc = r2
+	br.ret.sptk.many b0
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/lisp/gmpasm-mode.el b/third_party/gmp/mpn/lisp/gmpasm-mode.el
new file mode 100644
index 0000000..6f2fea0
--- /dev/null
+++ b/third_party/gmp/mpn/lisp/gmpasm-mode.el
@@ -0,0 +1,385 @@
+;;; gmpasm-mode.el -- GNU MP asm and m4 editing mode.
+
+
+;; Copyright 1999-2002 Free Software Foundation, Inc.
+
+;;   This file is part of the GNU MP Library.
+;;
+;;   The GNU MP Library is free software; you can redistribute it and/or modify
+;;   it under the terms of either:
+;;
+;;     * the GNU Lesser General Public License as published by the Free
+;;       Software Foundation; either version 3 of the License, or (at your
+;;       option) any later version.
+;;
+;;   or
+;;
+;;     * the GNU General Public License as published by the Free Software
+;;       Foundation; either version 2 of the License, or (at your option) any
+;;       later version.
+;;
+;;   or both in parallel, as here.
+;;
+;;   The GNU MP Library is distributed in the hope that it will be useful, but
+;;   WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;;   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+;;   for more details.
+;;
+;;   You should have received copies of the GNU General Public License and the
+;;   GNU Lesser General Public License along with the GNU MP Library.  If not,
+;;   see https://www.gnu.org/licenses/.
+
+
+;;; Commentary:
+;;
+;; gmpasm-mode is a major mode for editing m4 processed assembler code and
+;; m4 macro files in GMP.  It's similar to m4-mode, but has a number of
+;; settings better suited to GMP.
+;;
+;;
+;; Install
+;; -------
+;;
+;; To make M-x gmpasm-mode available, put gmpasm-mode.el somewhere in your
+;; load-path and the following in your .emacs
+;;
+;;	(autoload 'gmpasm-mode "gmpasm-mode" nil t)
+;;
+;; To use gmpasm-mode automatically on all .asm and .m4 files, put the
+;; following in your .emacs
+;;
+;;	(add-to-list 'auto-mode-alist '("\\.asm\\'" . gmpasm-mode))
+;;	(add-to-list 'auto-mode-alist '("\\.m4\\'" . gmpasm-mode))
+;;
+;; To have gmpasm-mode only on gmp files, try instead something like the
+;; following, which uses it only in a directory starting with "gmp", or a
+;; sub-directory of such.
+;;
+;;	(add-to-list 'auto-mode-alist
+;;	             '("/gmp.*/.*\\.\\(asm\\|m4\\)\\'" . gmpasm-mode))
+;;
+;; Byte compiling will slightly speed up loading.  If you want a docstring
+;; in the autoload you can use M-x update-file-autoloads if you set it up
+;; right.
+;;
+;;
+;; Emacsen
+;; -------
+;;
+;; GNU Emacs 20.x, 21.x and XEmacs 20.x all work well.  GNU Emacs 19.x
+;; should work if replacements for the various 20.x-isms are available,
+;; though comment-region with "C" doesn't do the right thing.
+
+
+;;; Code:
+
+(defgroup gmpasm nil
+  "GNU MP m4 and asm editing."
+  :prefix "gmpasm-"
+  :group 'languages)
+
+(defcustom gmpasm-mode-hook nil
+  "*Hook called by `gmpasm-mode'."
+  :type 'hook
+  :group 'gmpasm)
+
+(defcustom gmpasm-comment-start-regexp "\\([#;!@*|C]\\|//\\)"
+  "*Regexp matching possible comment styles.
+See `gmpasm-mode' docstring for how this is used.
+
+Commenting styles within GMP include
+  #   - alpha, i386, i960, vax, traditional unix
+  ;   - a29k, clipper, hppa, m88k, ppc
+  !   - sh, sparc, z8000
+  |   - m68k
+  @   - arm
+  *   - cray
+  C   - GMP m4, see mpn/asm-defs.m4
+  //  - ia64"
+  :type 'regexp
+  :group 'gmpasm)
+
+
+(defun gmpasm-add-to-list-second (list-var element)
+  "(gmpasm-add-to-list-second LIST-VAR ELEMENT)
+
+Add ELEMENT to LIST-VAR as the second element in the list, if it isn't
+already in the list.  If LIST-VAR is nil, then ELEMENT is just added as the
+sole element in the list.
+
+This is like `add-to-list', but it puts the new value second in the list.
+
+The first cons cell is copied rather than changed in-place, so references to
+the list elsewhere won't be affected."
+
+  (if (member element (symbol-value list-var))
+      (symbol-value list-var)
+    (set list-var
+	 (if (symbol-value list-var)
+	     (cons (car (symbol-value list-var))
+		   (cons element
+			 (cdr (symbol-value list-var))))
+	   (list element)))))
+
+
+(defun gmpasm-remove-from-list (list-var element)
+  "(gmpasm-remove-from-list LIST-VAR ELEMENT)
+
+Remove ELEMENT from LIST-VAR, using `copy-sequence' and `delete'.
+This is vaguely like `add-to-list', but the element is removed from the list.
+The list is copied rather than changed in-place, so references to it elsewhere
+aren't affected."
+
+;; Only the portion of the list up to the removed element needs to be
+;; copied, but there's no need to bother arranging that, since this function
+;; is only used for a couple of initializations.
+
+  (set list-var (delete element (copy-sequence (symbol-value list-var)))))
+
+
+(defvar gmpasm-mode-map
+  (let ((map (make-sparse-keymap)))
+
+    ;; assembler and dnl commenting
+    (define-key map "\C-c\C-c" 'comment-region)
+    (define-key map "\C-c\C-d" 'gmpasm-comment-region-dnl)
+
+    ;; kill an M-x compile, since it's not hard to put m4 into an infinite
+    ;; loop
+    (define-key map "\C-c\C-k" 'kill-compilation)
+
+    map)
+  "Keymap for `gmpasm-mode'.")
+
+
+(defvar gmpasm-mode-syntax-table
+  (let ((table (make-syntax-table)))
+    ;; underscore left as a symbol char, like C mode
+
+    ;; m4 quotes
+    (modify-syntax-entry ?`  "('"  table)
+    (modify-syntax-entry ?'  ")`"  table)
+
+    table)
+  "Syntax table used in `gmpasm-mode'.
+
+'#' and '\n' aren't set as comment syntax.  In m4 these are a comment
+outside quotes, but not inside.  Omitting a syntax entry ensures that when
+inside quotes emacs treats parentheses and apostrophes the same way that m4
+does.  When outside quotes this is not quite right, but having it right when
+nesting expressions is more important.
+
+'*', '!' or '|' aren't setup as comment syntax either, on CPUs which use
+these for comments.  The GMP macro setups don't set them in m4 changecom(),
+since that prevents them being used in eval() expressions, and on that basis
+they don't change the way quotes and parentheses are treated by m4 and
+should be treated by emacs.")
+
+
+(defvar gmpasm-font-lock-keywords
+  (eval-when-compile
+    (list
+     (cons
+      (concat
+       "\\b"
+       (regexp-opt
+	'("deflit" "defreg" "defframe" "defframe_pushl"
+	  "define_not_for_expansion"
+	  "m4_error" "m4_warning"
+	  "ASM_START" "ASM_END"
+	  "PROLOGUE" "PROLOGUE_GP" "MULFUNC_PROLOGUE" "EPILOGUE"
+	  "DATASTART" "DATAEND"
+	  "forloop"
+	  "TEXT" "DATA" "ALIGN" "W32" "FLOAT64"
+	  "builtin" "changecom" "changequote" "changeword" "debugfile"
+	  "debugmode" "decr" "define" "defn" "divert" "divnum" "dumpdef"
+	  "errprint" "esyscmd" "eval" "__file__" "format" "gnu" "ifdef"
+	  "ifelse" "include" "incr" "index" "indir" "len" "__line__"
+	  "m4exit" "m4wrap" "maketemp" "patsubst" "popdef" "pushdef"
+	  "regexp" "shift" "sinclude" "substr" "syscmd" "sysval"
+	  "traceoff" "traceon" "translit" "undefine" "undivert" "unix")
+	t)
+       "\\b") 'font-lock-keyword-face)))
+
+  "`font-lock-keywords' for `gmpasm-mode'.
+
+The keywords are m4 builtins and some of the GMP macros used in asm files.
+L doesn't look good fontified, so it's omitted.
+
+The right assembler comment regexp is added dynamically buffer-local (with
+dnl too).")
+
+
+;; Initialized if gmpasm-mode finds filladapt loaded.
+(defvar gmpasm-filladapt-token-table nil
+  "Filladapt token table used in `gmpasm-mode'.")
+(defvar gmpasm-filladapt-token-match-table nil
+  "Filladapt token match table used in `gmpasm-mode'.")
+(defvar gmpasm-filladapt-token-conversion-table nil
+  "Filladapt token conversion table used in `gmpasm-mode'.")
+
+
+;;;###autoload
+(defun gmpasm-mode ()
+  "A major mode for editing GNU MP asm and m4 files.
+
+\\{gmpasm-mode-map}
+`comment-start' and `comment-end' are set buffer-local to assembler
+commenting appropriate for the CPU by looking for something matching
+`gmpasm-comment-start-regexp' at the start of a line, or \"#\" is used if
+there's no match (if \"#\" isn't what you want, type in a desired comment
+and do \\[gmpasm-mode] to reinitialize).
+
+`adaptive-fill-regexp' is set buffer-local to the standard regexp with
+`comment-start' and dnl added.  If filladapt.el has been loaded it similarly
+gets `comment-start' and dnl added as buffer-local fill prefixes.
+
+Font locking has the m4 builtins, some of the GMP macros, m4 dnl commenting,
+and assembler commenting (based on the `comment-start' determined).
+
+Note that `gmpasm-comment-start-regexp' is only matched as a whole word, so
+the `C' in it is only matched as a whole word, not on something that happens
+to start with `C'.  Also it's only the particular `comment-start' determined
+that's added for filling etc, not the whole `gmpasm-comment-start-regexp'.
+
+`gmpasm-mode-hook' is run after initializations are complete."
+
+  (interactive)
+  (kill-all-local-variables)
+  (setq major-mode 'gmpasm-mode
+        mode-name  "gmpasm")
+  (use-local-map gmpasm-mode-map)
+  (set-syntax-table gmpasm-mode-syntax-table)
+  (setq fill-column 76)
+
+  ;; Short instructions might fit with 32, but anything with labels or
+  ;; expressions soon needs the comments pushed out to column 40.
+  (setq comment-column 40)
+
+  ;; Don't want to find out the hard way which dumb assemblers don't like a
+  ;; missing final newline.
+  (set (make-local-variable 'require-final-newline) t)
+
+  ;; The first match of gmpasm-comment-start-regexp at the start of a line
+  ;; determines comment-start, or "#" if no match.
+  (set (make-local-variable 'comment-start)
+       (save-excursion
+	 (goto-char (point-min))
+	 (if (re-search-forward
+	      (concat "^\\(" gmpasm-comment-start-regexp "\\)\\(\\s-\\|$\\)")
+	      nil t)
+	     (match-string 1)
+	   "#")))
+  (set (make-local-variable 'comment-end) "")
+
+  ;; If comment-start ends in an alphanumeric then \b is used to match it
+  ;; only as a separate word.  The test is for an alphanumeric rather than
+  ;; \w since we might try # or ! as \w characters but without wanting \b on
+  ;; them.
+  (let ((comment-regexp
+	 (concat (regexp-quote comment-start)
+		 (if (string-match "[a-zA-Z0-9]\\'" comment-start) "\\b"))))
+
+    ;; Whitespace is required before a comment-start so m4 $# doesn't match
+    ;; when comment-start is "#".
+    (set (make-local-variable 'comment-start-skip)
+	 (concat "\\(^\\|\\s-\\)\\(\\<dnl\\>\\|" comment-regexp "\\)[ \t]*"))
+
+    ;; Comment fontification based on comment-start, and always with dnl.
+    ;; Same treatment of a space before "#" as in comment-start-skip, but
+    ;; don't fontify that space.
+    (add-to-list (make-local-variable 'gmpasm-font-lock-keywords)
+		 (list (concat "\\(^\\|\\s-\\)\\(\\(\\<dnl\\>\\|"
+			       comment-regexp
+			       "\\).*$\\)")
+		       2 'font-lock-comment-face))
+
+    (set (make-local-variable 'font-lock-defaults)
+	 '(gmpasm-font-lock-keywords
+	   t	         ; no syntactic fontification (of strings etc)
+	   nil           ; no case-fold
+	   ((?_ . "w"))  ; _ part of a word while fontifying
+	   ))
+
+    ;; Paragraphs are separated by blank lines, or lines with only dnl or
+    ;; comment-start.
+    (set (make-local-variable 'paragraph-separate)
+	 (concat "[ \t\f]*\\(\\(" comment-regexp "\\|dnl\\)[ \t]*\\)*$"))
+    (set (make-local-variable 'paragraph-start)
+	 (concat "\f\\|" paragraph-separate))
+
+    ;; Some sort of "def...(" m4 define, possibly with ` for quoting.
+    ;; Could do something with PROLOGUE here, but in GMP the filename is
+    ;; enough, it's not normally necessary to say the function name.
+    (set (make-local-variable 'add-log-current-defun-header-regexp)
+	 "^def[a-z0-9_]+(`?\\([a-zA-Z0-9_]+\\)")
+
+    ;; Adaptive fill gets dnl and comment-start as comment style prefixes on
+    ;; top of the standard regexp (which has # and ; already actually).
+    (set (make-local-variable 'adaptive-fill-regexp)
+	 (concat "[ \t]*\\(\\("
+		 comment-regexp
+		 "\\|dnl\\|[-|#;>*]+\\|(?[0-9]+[.)]\\)[ \t]*\\)*"))
+    (set (make-local-variable 'adaptive-fill-first-line-regexp)
+	 "\\`\\([ \t]*dnl\\)?[ \t]*\\'")
+
+    (when (fboundp 'filladapt-mode)
+      (unless gmpasm-filladapt-token-table
+	(setq gmpasm-filladapt-token-table
+	      filladapt-token-table)
+	(setq gmpasm-filladapt-token-match-table
+	      filladapt-token-match-table)
+	(setq gmpasm-filladapt-token-conversion-table
+	      filladapt-token-conversion-table)
+
+	;; Numbered bullet points like "2.1" get matched at the start of a
+	;; line when it's really something like "2.1 cycles/limb", so remove
+	;; this from the list.  The regexp for "1.", "2." etc is left
+	;; though.
+	(gmpasm-remove-from-list 'gmpasm-filladapt-token-table
+				 '("[0-9]+\\(\\.[0-9]+\\)+[ \t]"
+				   bullet))
+
+	;; "%" as a comment prefix interferes with register names on some
+	;; CPUs, like %eax on x86, so remove this.
+	(gmpasm-remove-from-list 'gmpasm-filladapt-token-table
+				 '("%+" postscript-comment))
+
+	(add-to-list 'gmpasm-filladapt-token-match-table
+		     '(gmpasm-comment gmpasm-comment))
+	(add-to-list 'gmpasm-filladapt-token-conversion-table
+		     '(gmpasm-comment . exact)))
+
+      (set (make-local-variable 'filladapt-token-table)
+	   gmpasm-filladapt-token-table)
+      (set (make-local-variable 'filladapt-token-match-table)
+	   gmpasm-filladapt-token-match-table)
+      (set (make-local-variable 'filladapt-token-conversion-table)
+	   gmpasm-filladapt-token-conversion-table)
+
+      ;; Add dnl and comment-start as fill prefixes.
+      ;; Comments in filladapt.el say filladapt-token-table must begin
+      ;; with ("^" beginning-of-line), so put our addition second.
+      (gmpasm-add-to-list-second 'filladapt-token-table
+				 (list (concat "dnl[ \t]\\|" comment-regexp)
+				       'gmpasm-comment))))
+
+  (run-hooks 'gmpasm-mode-hook))
+
+
+(defun gmpasm-comment-region-dnl (beg end &optional arg)
+  "(gmpasm-comment-region-dnl BEG END &optional ARG)
+
+Comment or uncomment each line in the region using `dnl'.
+With \\[universal-argument] prefix arg, uncomment each line in region.
+This is `comment-region', but using \"dnl\"."
+
+  (interactive "r\nP")
+  (let ((comment-start "dnl")
+	(comment-end ""))
+    (comment-region beg end arg)))
+
+
+(provide 'gmpasm-mode)
+
+;;; gmpasm-mode.el ends here
diff --git a/third_party/gmp/mpn/m4-ccas b/third_party/gmp/mpn/m4-ccas
new file mode 100755
index 0000000..16d80c6
--- /dev/null
+++ b/third_party/gmp/mpn/m4-ccas
@@ -0,0 +1,107 @@
+#!/bin/sh
+#
+# A helper script for Makeasm.am .asm.lo rule.
+
+# Copyright 2001 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+
+# Usage: m4-ccas --m4=M4 CC ... file.asm ...
+#
+# Process file.asm with the given M4 plus any -D arguments, then
+# assemble with the given CC plus all arguments.
+#
+# The M4 command must be in a single --m4= argument, and will be split
+# on whitespace.  When CC is invoked file.asm is replaced with a
+# temporary .s file which is the M4 output.
+#
+# To allow parallel builds, the temp file name is based on the .asm
+# file name, which will be the output object filename for all uses we
+# put this script to.
+
+M4=
+CC=
+DEFS=
+ASM=
+SEEN_O=no
+
+for i in "$@"; do
+  case $i in
+    --m4=*)
+      M4=`echo "$i" | sed 's/^--m4=//'`
+      ;;
+    -D*)
+      DEFS="$DEFS $i"
+      CC="$CC $i"
+      ;;
+    *.asm)
+      if test -n "$ASM"; then
+        echo "Only one .asm file permitted"
+        exit 1
+      fi
+      BASENAME=`echo "$i" | sed -e 's/\.asm$//' -e 's/^.*[\\/:]//'`
+      TMP=tmp-$BASENAME.s
+      ASM=$i
+      CC="$CC $TMP"
+      ;;
+    -o)
+      SEEN_O=yes
+      CC="$CC $i"
+      ;;
+    *)
+      CC="$CC $i"
+      ;;
+  esac
+done
+
+if test -z "$M4"; then
+  echo "No --m4 specified"
+  exit 1
+fi
+
+if test -z "$ASM"; then
+  echo "No .asm specified"
+  exit 1
+fi
+
+# Libtool adds it's own -o when sending output to .libs/foo.o, but not
+# when just wanting foo.o in the current directory.  We need an
+# explicit -o in both cases since we're assembling tmp-foo.s.
+#
+if test $SEEN_O = no; then
+  CC="$CC -o $BASENAME.o"
+fi
+
+echo "$M4 $DEFS $ASM >$TMP"
+$M4 $DEFS $ASM >$TMP || exit
+
+echo "$CC"
+$CC || exit
+
+# Comment this out to preserve .s intermediates
+rm -f $TMP
diff --git a/third_party/gmp/mpn/m68k/README b/third_party/gmp/mpn/m68k/README
new file mode 100644
index 0000000..5261564
--- /dev/null
+++ b/third_party/gmp/mpn/m68k/README
@@ -0,0 +1,138 @@
+Copyright 2001, 2003, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.
+
+
+
+
+
+                      M68K MPN SUBROUTINES
+
+
+This directory contains mpn functions for various m68k family chips.
+
+
+CODE ORGANIZATION
+
+	m68k             m68000, m68010, m68060
+	m68k/mc68020     m68020, m68030, m68040, and CPU32
+
+
+The m5200 "coldfire", which is m68000 less a few instructions, currently has
+no assembler code support.
+
+
+STATUS
+
+The code herein is old and poorly maintained.  If somebody really cared, it
+could be optimized substantially.  For example,
+
+* mpn_add_n and mpn_sub_n could, with more unrolling be improved from 6 to
+  close to 4 c/l (on m68040).
+
+* The multiplication loops could be sped up by using the FPU.
+
+* mpn_lshift by 31 should use the special-case mpn_rshift by 1 code, and
+  vice versa mpn_rshift by 31 use the special lshift by 1, when operand
+  overlap permits.
+
+* On 68000, mpn_mul_1, mpn_addmul_1 and mpn_submul_1 could check for a
+  16-bit multiplier and use two multiplies per limb, not four.
+
+  Similarly various other _1 operations like mpn_mod_1, mpn_divrem_1,
+  mpn_divexact_1, mpn_modexact_1c_odd.
+
+* On 68000, mpn_lshift and mpn_rshift could use a roll and mask instead of
+  lsrl and lsll.  This promises to be a speedup, effectively trading a 6+2*n
+  shift for one or two 4 cycle masks.  Suggested by Jean-Charles Meyrignac.
+
+* config.guess detects 68000, 68010, CPU32 and 68020 by running some code,
+  but relies on system information for 030, 040 and 060.  Can they be
+  identified by running some code?  Currently this only makes a difference
+  to the compiler options selected, since we have no specific asm code for
+  those chips.
+
+One novel idea for 68000 would be to use a 16-bit limb instead of 32-bits.
+This would suit the native 16x16 multiply, but might make it difficult to
+get full value from the native 32x32 add/sub/etc.  This would be an ABI
+option, and would select "__GMP_SHORT_LIMB" in gmp.h.
+
+Naturally an entirely new set of asm subroutines would be needed for a
+16-bit limb.  Also there's various places in the C code assuming limb>=long,
+which would need to be updated, eg. mpz_set_ui.  Some of the nails changes
+may have helped cover some of this.
+
+
+ASM FILES
+
+The .asm files are put through m4 for macro processing, and with the help of
+configure give either MIT or Motorola syntax.  The generic mpn/asm-defs.m4
+is used, together with mpn/m68k/m68k-defs.m4.  See comments in those files.
+
+Not all possible syntax variations are covered.  GCC config/m68k for
+instance has things like $ for immediates on CRDS or reversed cmp order for
+AT&T SGS.  These could probably be handled if anyone really needs it.
+
+
+CALLING CONVENTIONS
+
+The SVR4 standard has an int of 32 bits, and all parameters 32-bit aligned
+on the stack.
+
+PalmOS and perhaps various embedded systems intended for 68000 however use
+an int of 16 bits and parameters only 16-bit aligned on the stack.  This is
+generated by "gcc -mshort" (and is the default for the PalmOS gcc port, we
+believe).
+
+The asm files adapt to these two ABIs by checking sizeof(unsigned), coming
+through config.m4 as SIZEOF_UNSIGNED.  Only mpn_lshift and mpn_rshift are
+affected, all other routines take longs and pointers, which are 32-bits in
+both cases.
+
+Strictly speaking the size of an int doesn't determine the stack padding
+convention.  But if int is 16 bits then we can definitely say the host
+system is not SVR4, and therefore may as well assume we're in 16-bit stack
+alignment.
+
+
+REFERENCES
+
+"Motorola M68000 Family Programmer's Reference Manual", available online,
+
+	http://e-www.motorola.com/brdata/PDFDB/docs/M68000PM.pdf
+
+"System V Application Binary Interface: Motorola 68000 Processor Family
+Supplement", AT&T, 1990, ISBN 0-13-877553-6.  Has details of calling
+conventions and ELF style PIC coding.
+
+
+
+----------------
+Local variables:
+mode: text
+fill-column: 76
+End:
diff --git a/third_party/gmp/mpn/m68k/aors_n.asm b/third_party/gmp/mpn/m68k/aors_n.asm
new file mode 100644
index 0000000..f7d379e
--- /dev/null
+++ b/third_party/gmp/mpn/m68k/aors_n.asm
@@ -0,0 +1,99 @@
+dnl  mc68020 mpn_add_n, mpn_sub_n -- add or subtract limb vectors
+
+dnl  Copyright 1992, 1994, 1996, 1999-2003, 2005 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C         cycles/limb
+C 68040:      6
+
+ifdef(`OPERATION_add_n',`
+  define(M4_inst,       addxl)
+  define(M4_function_n, mpn_add_n)
+',`ifdef(`OPERATION_sub_n',`
+  define(M4_inst,       subxl)
+  define(M4_function_n, mpn_sub_n)
+',
+`m4_error(`Need OPERATION_add_n or OPERATION_sub_n
+')')')
+
+MULFUNC_PROLOGUE(mpn_add_n mpn_sub_n)
+
+
+C INPUT PARAMETERS
+C res_ptr	(sp + 4)
+C s1_ptr	(sp + 8)
+C s2_ptr	(sp + 12)
+C size		(sp + 16)
+
+
+PROLOGUE(M4_function_n)
+
+C Save used registers on the stack.
+	movel	d2, M(-,sp)
+	movel	a2, M(-,sp)
+
+C Copy the arguments to registers.  Better use movem?
+	movel	M(sp,12), a2
+	movel	M(sp,16), a0
+	movel	M(sp,20), a1
+	movel	M(sp,24), d2
+
+	eorw	#1, d2
+	lsrl	#1, d2
+	bcc	L(L1)
+	subql	#1, d2	C clears cy as side effect
+
+L(Loop):
+	movel	M(a0,+), d0
+	movel	M(a1,+), d1
+	M4_inst	d1, d0
+	movel	d0, M(a2,+)
+L(L1):	movel	M(a0,+), d0
+	movel	M(a1,+), d1
+	M4_inst	d1, d0
+	movel	d0, M(a2,+)
+
+	dbf	d2, L(Loop)		C loop until 16 lsb of %4 == -1
+	subxl	d0, d0			C d0 <= -cy; save cy as 0 or -1 in d0
+	subl	#0x10000, d2
+	bcs	L(L2)
+	addl	d0, d0			C restore cy
+	bra	L(Loop)
+
+L(L2):
+	negl	d0
+
+C Restore used registers from stack frame.
+	movel	M(sp,+), a2
+	movel	M(sp,+), d2
+
+	rts
+
+EPILOGUE(M4_function_n)
diff --git a/third_party/gmp/mpn/m68k/gmp-mparam.h b/third_party/gmp/mpn/m68k/gmp-mparam.h
new file mode 100644
index 0000000..9ac7b41
--- /dev/null
+++ b/third_party/gmp/mpn/m68k/gmp-mparam.h
@@ -0,0 +1,76 @@
+/* gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2000-2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+
+/* 25MHz 68040 */
+
+/* Generated by tuneup.c, 2004-02-05, gcc 3.2 */
+
+#define MUL_TOOM22_THRESHOLD             14
+#define MUL_TOOM33_THRESHOLD             90
+
+#define SQR_BASECASE_THRESHOLD            5
+#define SQR_TOOM2_THRESHOLD              28
+#define SQR_TOOM3_THRESHOLD              98
+
+#define DIV_SB_PREINV_THRESHOLD       MP_SIZE_T_MAX  /* never */
+#define DIV_DC_THRESHOLD                 55
+#define POWM_THRESHOLD                   65
+
+#define HGCD_THRESHOLD                  116
+#define GCD_ACCEL_THRESHOLD               3
+#define GCD_DC_THRESHOLD                590
+#define JACOBI_BASE_METHOD                2
+
+#define DIVREM_1_NORM_THRESHOLD       MP_SIZE_T_MAX  /* never */
+#define DIVREM_1_UNNORM_THRESHOLD     MP_SIZE_T_MAX  /* never */
+#define MOD_1_NORM_THRESHOLD          MP_SIZE_T_MAX  /* never */
+#define MOD_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define USE_PREINV_DIVREM_1               0
+#define USE_PREINV_MOD_1                  0
+#define DIVREM_2_THRESHOLD            MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD          MP_SIZE_T_MAX  /* never */
+#define MODEXACT_1_ODD_THRESHOLD      MP_SIZE_T_MAX  /* never */
+
+#define GET_STR_DC_THRESHOLD             18
+#define GET_STR_PRECOMPUTE_THRESHOLD     43
+#define SET_STR_THRESHOLD               937
+
+#define MUL_FFT_TABLE  { 336, 672, 1408, 3584, 10240, 24576, 0 }
+#define MUL_FFT_MODF_THRESHOLD          296
+#define MUL_FFT_THRESHOLD              1728
+
+#define SQR_FFT_TABLE  { 336, 736, 1408, 3584, 10240, 24576, 0 }
+#define SQR_FFT_MODF_THRESHOLD          296
+#define SQR_FFT_THRESHOLD              2304
diff --git a/third_party/gmp/mpn/m68k/lshift.asm b/third_party/gmp/mpn/m68k/lshift.asm
new file mode 100644
index 0000000..f202abf
--- /dev/null
+++ b/third_party/gmp/mpn/m68k/lshift.asm
@@ -0,0 +1,175 @@
+dnl  mc68020 mpn_lshift -- mpn left shift.
+
+dnl  Copyright 1996, 1999-2003 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C           cycles/limb
+C        shift==1  shift>1
+C 68040:    5         12
+
+
+C mp_limb_t mpn_lshift (mp_ptr res_ptr, mp_srcptr s_ptr, mp_size_t s_size,
+C                       unsigned cnt);
+C
+C The "cnt" parameter is either 16 bits or 32 bits depending on
+C SIZEOF_UNSIGNED (see ABI notes in mpn/m68k/README).  The value is of
+C course only 1 to 31.  When loaded as 16 bits there's garbage in the upper
+C half, hence the use of cmpw.  The shift instructions take the their count
+C modulo 64, so the upper part doesn't matter to them either.
+C
+
+C INPUT PARAMETERS
+C res_ptr	(sp + 4)
+C s_ptr		(sp + 8)
+C s_size	(sp + 12)
+C cnt		(sp + 16)
+
+define(res_ptr, `a1')
+define(s_ptr,   `a0')
+define(s_size,  `d6')
+define(cnt,     `d4')
+
+ifdef(`SIZEOF_UNSIGNED',,
+`m4_error(`SIZEOF_UNSIGNED not defined, should be in config.m4
+')')
+
+PROLOGUE(mpn_lshift)
+C Save used registers on the stack.
+	moveml	d2-d6/a2, M(-,sp)
+
+C Copy the arguments to registers.
+	movel	M(sp,28), res_ptr
+	movel	M(sp,32), s_ptr
+	movel	M(sp,36), s_size
+ifelse(SIZEOF_UNSIGNED,2,
+`	movew	M(sp,40), cnt',
+`	movel	M(sp,40), cnt')
+
+	moveql	#1, d5
+	cmpw	d5, cnt
+	bne	L(Lnormal)
+	cmpl	s_ptr, res_ptr
+	bls	L(Lspecial)		C jump if s_ptr >= res_ptr
+
+ifelse(scale_available_p,1,`
+	lea	M(s_ptr,s_size,l,4), a2
+',`
+	movel	s_size, d0
+	asll	#2, d0
+	lea	M(s_ptr,d0,l), a2
+')
+	cmpl	res_ptr, a2
+	bls	L(Lspecial)		C jump if res_ptr >= s_ptr + s_size
+
+L(Lnormal):
+	moveql	#32, d5
+	subl	cnt, d5
+
+ifelse(scale_available_p,1,`
+	lea	M(s_ptr,s_size,l,4), s_ptr
+	lea	M(res_ptr,s_size,l,4), res_ptr
+',`
+	movel	s_size, d0
+	asll	#2, d0
+	addl	d0, s_ptr
+	addl	d0, res_ptr
+')
+	movel	M(-,s_ptr), d2
+	movel	d2, d0
+	lsrl	d5, d0		C compute carry limb
+
+	lsll	cnt, d2
+	movel	d2, d1
+	subql	#1, s_size
+	beq	L(Lend)
+	lsrl	#1, s_size
+	bcs	L(L1)
+	subql	#1, s_size
+
+L(Loop):
+	movel	M(-,s_ptr), d2
+	movel	d2, d3
+	lsrl	d5, d3
+	orl	d3, d1
+	movel	d1, M(-,res_ptr)
+	lsll	cnt, d2
+L(L1):
+	movel	M(-,s_ptr), d1
+	movel	d1, d3
+	lsrl	d5, d3
+	orl	d3, d2
+	movel	d2, M(-,res_ptr)
+	lsll	cnt, d1
+
+	dbf	s_size, L(Loop)
+	subl	#0x10000, s_size
+	bcc	L(Loop)
+
+L(Lend):
+	movel	d1, M(-,res_ptr)	C store least significant limb
+
+C Restore used registers from stack frame.
+	moveml	M(sp,+), d2-d6/a2
+	rts
+
+C We loop from least significant end of the arrays, which is only
+C permissable if the source and destination don't overlap, since the
+C function is documented to work for overlapping source and destination.
+
+L(Lspecial):
+	clrl	d0			C initialize carry
+	eorw	#1, s_size
+	lsrl	#1, s_size
+	bcc	L(LL1)
+	subql	#1, s_size
+
+L(LLoop):
+	movel	M(s_ptr,+), d2
+	addxl	d2, d2
+	movel	d2, M(res_ptr,+)
+L(LL1):
+	movel	M(s_ptr,+), d2
+	addxl	d2, d2
+	movel	d2, M(res_ptr,+)
+
+	dbf	s_size, L(LLoop)
+	addxl	d0, d0		C save cy in lsb
+	subl	#0x10000, s_size
+	bcs	L(LLend)
+	lsrl	#1, d0		C restore cy
+	bra	L(LLoop)
+
+L(LLend):
+C Restore used registers from stack frame.
+	moveml	M(sp,+), d2-d6/a2
+	rts
+
+EPILOGUE(mpn_lshift)
diff --git a/third_party/gmp/mpn/m68k/m68k-defs.m4 b/third_party/gmp/mpn/m68k/m68k-defs.m4
new file mode 100644
index 0000000..15289f6
--- /dev/null
+++ b/third_party/gmp/mpn/m68k/m68k-defs.m4
@@ -0,0 +1,230 @@
+divert(-1)
+
+dnl  m4 macros for 68k assembler.
+
+dnl  Copyright 2001-2003 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+dnl  The default m4 `#' commenting interferes with the assembler syntax for
+dnl  immediates.  `|' would be correct, but it interferes with "||" in
+dnl  eval().  Would like to disable commenting, but that's not possible (see
+dnl  mpn/asm-defs.m4), so use `;' which should be harmless.
+
+changecom(;)
+
+
+dnl  Called: PROLOGUE_cpu(GSYM_PREFIX`'foo)
+dnl
+dnl  Same as the standard PROLOGUE, but align to 2 bytes not 4.
+
+define(`PROLOGUE_cpu',
+m4_assert_numargs(1)
+`	TEXT
+	ALIGN(2)
+	GLOBL	`$1' GLOBL_ATTR
+	TYPE(`$1',`function')
+`$1'LABEL_SUFFIX')
+
+
+dnl  Usage: d0, etc
+dnl
+dnl  Expand to d0 or %d0 according to the assembler's requirements.
+dnl
+dnl  Actually d0 expands to `d0' or %`d0', the quotes protecting against
+dnl  further expansion.  Definitions are made even if d0 is to be just `d0',
+dnl  so that any m4 quoting problems will show up everywhere, not just on a
+dnl  %d0 system.
+dnl
+dnl  Care must be taken with quoting when using these in a definition.  For
+dnl  instance the quotes in the following are essential or two %'s will be
+dnl  produced when `counter' is used.
+dnl
+dnl         define(counter, `d7')
+dnl
+
+dnl  Called: m68k_reg(r)
+define(m68k_reg,
+m4_assert_numargs(1)
+m4_assert_defined(`WANT_REGISTER_PERCENT')
+`ifelse(WANT_REGISTER_PERCENT,yes,%)`$1'')
+
+dnl  Usage: m68k_defreg(r)
+define(m68k_defreg,
+m4_assert_numargs(1)
+`deflit($1,`m68k_reg(`$1')')')
+
+m68k_defreg(d0)
+m68k_defreg(d1)
+m68k_defreg(d2)
+m68k_defreg(d3)
+m68k_defreg(d4)
+m68k_defreg(d5)
+m68k_defreg(d6)
+m68k_defreg(d7)
+
+m68k_defreg(a0)
+m68k_defreg(a1)
+m68k_defreg(a2)
+m68k_defreg(a3)
+m68k_defreg(a4)
+m68k_defreg(a5)
+m68k_defreg(a6)
+m68k_defreg(a7)
+
+m68k_defreg(sp)
+m68k_defreg(pc)
+
+
+dnl  Usage: M(base)
+dnl         M(base,displacement)
+dnl         M(base,index,size)
+dnl         M(base,index,size,scale)
+dnl         M(base,+)
+dnl         M(-,base)
+dnl
+dnl  `base' is an address register, `index' is a data register, `size' is w
+dnl  or l, and scale is 1, 2, 4 or 8.
+dnl
+dnl  M(-,base) has it's arguments that way around to emphasise it's a
+dnl  pre-decrement, as opposed to M(base,+) a post-increment.
+dnl
+dnl  Enhancement: Add the memory indirect modes, if/when they're needed.
+
+define(M,
+m4_assert_numargs_range(1,4)
+m4_assert_defined(`WANT_ADDRESSING')
+`ifelse(WANT_ADDRESSING,mit,
+`ifelse($#,1, ``$1'@')dnl
+ifelse($#,2,
+`ifelse($2,+, ``$1'@+',
+`ifelse($1,-, ``$2'@-',
+              ``$1'@($2)')')')dnl
+ifelse($#,3,  ``$1'@(`$2':`$3')')dnl
+ifelse($#,4,  ``$1'@(`$2':`$3':$4)')',
+
+dnl  WANT_ADDRESSING `motorola'
+`ifelse($#,1, `(`$1')')dnl
+ifelse($#,2,
+`ifelse($2,+, `(`$1')+',
+`ifelse($1,-, `-(`$2')',
+              `$2(`$1')')')')dnl
+ifelse($#,3,  `(`$1',`$2'.$3)')dnl
+ifelse($#,4,  `(`$1',`$2'.$3*$4)')')')
+
+
+dnl  Usage: addl etc
+dnl
+dnl  m68k instructions with special handling for the suffix, with for
+dnl  instance addl expanding to addl or add.l as necessary.
+dnl
+dnl  See also t-m68k-defs.pl which verifies all mnemonics used in the asm
+dnl  files have entries here.
+
+dnl  Called: m68k_insn(mnemonic,suffix)
+define(m68k_insn,
+m4_assert_numargs(2)
+m4_assert_defined(`WANT_DOT_SIZE')
+`ifelse(WANT_DOT_SIZE,yes, ``$1'.``$2''',
+                           ``$1$2'')')
+
+dnl  Usage: m68k_definsn(mnemonic,suffix)
+define(m68k_definsn,
+m4_assert_numargs(2)
+`deflit($1`'$2,`m68k_insn(`$1',`$2')')')
+
+m68k_definsn(add,  l)
+m68k_definsn(addx, l)
+m68k_definsn(addq, l)
+m68k_definsn(asl,  l)
+m68k_definsn(cmp,  l)
+m68k_definsn(cmp,  w)
+m68k_definsn(clr,  l)
+m68k_definsn(divu, l)
+m68k_definsn(eor,  w)
+m68k_definsn(lsl,  l)
+m68k_definsn(lsr,  l)
+m68k_definsn(move, l)
+m68k_definsn(move, w)
+m68k_definsn(movem,l)
+m68k_definsn(moveq,l)
+m68k_definsn(mulu, l)
+m68k_definsn(neg,  l)
+m68k_definsn(or,   l)
+m68k_definsn(roxl, l)
+m68k_definsn(roxr, l)
+m68k_definsn(sub,  l)
+m68k_definsn(subx, l)
+m68k_definsn(subq, l)
+
+
+dnl  Usage: bra etc
+dnl
+dnl  Expand to `bra', `jra' or `jbra' according to what the assembler will
+dnl  accept.  The latter two give variable-sized branches in gas.
+dnl
+dnl  See also t-m68k-defs.pl which verifies all the bXX branches used in the
+dnl  asm files have entries here.
+
+dnl  Called: m68k_branch(cond)
+define(m68k_branch,
+m4_assert_numargs(1)
+m4_assert_defined(`WANT_BRANCHES')
+`ifelse(WANT_BRANCHES,jra, `j$1',
+`ifelse(WANT_BRANCHES,jbra,`jb$1',
+                           ``b$1'')')')
+
+dnl  Called: m68k_defbranch(cond)
+define(m68k_defbranch,
+m4_assert_numargs(1)
+`deflit(b$1,`m68k_branch(`$1')')')
+
+m68k_defbranch(ra)
+m68k_defbranch(cc)
+m68k_defbranch(cs)
+m68k_defbranch(ls)
+m68k_defbranch(eq)
+m68k_defbranch(ne)
+
+
+dnl  Usage: scale_available_p
+dnl
+dnl  Expand to 1 if a scale factor can be used in addressing modes, or 0 if
+dnl  not.  M(a0,d0,l,4), meaning a0+d0*4, is not available in 68000 or
+dnl  68010, but is in CPU32 and in 68020 and up.
+
+define(scale_available_p,
+`m4_ifdef_anyof_p(
+`HAVE_HOST_CPU_m68360'
+`HAVE_HOST_CPU_m68020'
+`HAVE_HOST_CPU_m68030'
+`HAVE_HOST_CPU_m68040'
+`HAVE_HOST_CPU_m68060')')
+
+
+divert
diff --git a/third_party/gmp/mpn/m68k/mc68020/aorsmul_1.asm b/third_party/gmp/mpn/m68k/mc68020/aorsmul_1.asm
new file mode 100644
index 0000000..4ee30ad
--- /dev/null
+++ b/third_party/gmp/mpn/m68k/mc68020/aorsmul_1.asm
@@ -0,0 +1,101 @@
+dnl  mc68020 mpn_addmul_1, mpn_submul_1 -- add or subtract mpn multiple.
+
+dnl  Copyright 1992, 1994, 1996, 1999-2002, 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C         cycles/limb
+C 68040:     25
+
+ifdef(`OPERATION_addmul_1',`
+  define(M4_inst,       addl)
+  define(M4_function_1, mpn_addmul_1)
+',`ifdef(`OPERATION_submul_1',`
+  define(M4_inst,       subl)
+  define(M4_function_1, mpn_submul_1)
+',
+`m4_error(`Need OPERATION_addmul_1 or OPERATION_submul_1
+')')')
+
+
+C INPUT PARAMETERS
+C res_ptr	(sp + 4)
+C s1_ptr	(sp + 8)
+C s1_size	(sp + 12)
+C s2_limb	(sp + 16)
+
+define(res_ptr, `a0')
+define(s1_ptr,  `a1')
+define(s1_size, `d2')
+define(s2_limb, `d4')
+
+MULFUNC_PROLOGUE(mpn_addmul_1 mpn_submul_1)
+
+PROLOGUE(M4_function_1)
+
+C Save used registers on the stack.
+	moveml	d2-d5, M(-,sp)
+
+C Copy the arguments to registers.  Better use movem?
+	movel	M(sp,20), res_ptr
+	movel	M(sp,24), s1_ptr
+	movel	M(sp,28), s1_size
+	movel	M(sp,32), s2_limb
+
+	eorw	#1, s1_size
+	clrl	d1
+	clrl	d5
+	lsrl	#1, s1_size
+	bcc	L(L1)
+	subql	#1, s1_size
+	subl	d0, d0		C (d0,cy) <= (0,0)
+
+L(Loop):
+	movel	M(s1_ptr,+), d3
+	mulul	s2_limb, d1:d3
+	addxl	d0, d3
+	addxl	d5, d1
+	M4_inst	d3, M(res_ptr,+)
+L(L1):	movel	M(s1_ptr,+), d3
+	mulul	s2_limb, d0:d3
+	addxl	d1, d3
+	addxl	d5, d0
+	M4_inst	d3, M(res_ptr,+)
+
+	dbf	s1_size, L(Loop)
+	addxl	d5, d0
+	subl	#0x10000, s1_size
+	bcc	L(Loop)
+
+C Restore used registers from stack frame.
+	moveml	M(sp,+), d2-d5
+
+	rts
+
+EPILOGUE(M4_function_1)
diff --git a/third_party/gmp/mpn/m68k/mc68020/mul_1.asm b/third_party/gmp/mpn/m68k/mc68020/mul_1.asm
new file mode 100644
index 0000000..f5fbb30
--- /dev/null
+++ b/third_party/gmp/mpn/m68k/mc68020/mul_1.asm
@@ -0,0 +1,96 @@
+dnl  mc68020 mpn_mul_1 -- mpn by limb multiply
+
+dnl  Copyright 1992, 1994, 1996, 1999-2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C         cycles/limb
+C 68040:     24
+
+C INPUT PARAMETERS
+C res_ptr	(sp + 4)
+C s1_ptr	(sp + 8)
+C s1_size	(sp + 12)
+C s2_limb	(sp + 16)
+
+
+define(res_ptr, `a0')
+define(s1_ptr,  `a1')
+define(s1_size, `d2')
+define(s2_limb, `d4')
+
+
+PROLOGUE(mpn_mul_1)
+
+C Save used registers on the stack.
+	moveml	d2-d4, M(-,sp)
+
+C	movel	d2, M(-,sp)
+C	movel	d3, M(-,sp)
+C	movel	d4, M(-,sp)
+
+C Copy the arguments to registers.  Better use movem?
+	movel	M(sp,16), res_ptr
+	movel	M(sp,20), s1_ptr
+	movel	M(sp,24), s1_size
+	movel	M(sp,28), s2_limb
+
+	eorw	#1, s1_size
+	clrl	d1
+	lsrl	#1, s1_size
+	bcc	L(L1)
+	subql	#1, s1_size
+	subl	d0, d0		C (d0,cy) <= (0,0)
+
+L(Loop):
+	movel	M(s1_ptr,+), d3
+	mulul	s2_limb, d1:d3
+	addxl	d0, d3
+	movel	d3, M(res_ptr,+)
+L(L1):	movel	M(s1_ptr,+), d3
+	mulul	s2_limb, d0:d3
+	addxl	d1, d3
+	movel	d3, M(res_ptr,+)
+
+	dbf	s1_size, L(Loop)
+	clrl	d3
+	addxl	d3, d0
+	subl	#0x10000, s1_size
+	bcc	L(Loop)
+
+C Restore used registers from stack frame.
+	moveml	M(sp,+), d2-d4
+
+C	movel	M(sp,+),d4
+C	movel	M(sp,+),d3
+C	movel	M(sp,+),d2
+
+	rts
+
+EPILOGUE(mpn_mul_1)
diff --git a/third_party/gmp/mpn/m68k/mc68020/udiv.asm b/third_party/gmp/mpn/m68k/mc68020/udiv.asm
new file mode 100644
index 0000000..aadeab9
--- /dev/null
+++ b/third_party/gmp/mpn/m68k/mc68020/udiv.asm
@@ -0,0 +1,45 @@
+dnl  mc68020 mpn_udiv_qrnnd -- 2x1 limb division
+
+dnl  Copyright 1999-2001 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C mp_limb_t mpn_udiv_qrnnd (mp_limb_t *rp,
+C                           mp_limb_t nh, mp_limb_t nl, mp_limb_t d);
+C
+
+PROLOGUE(mpn_udiv_qrnnd)
+	movel	M(sp,4), a0	C rp
+	movel	M(sp,8), d1	C nh
+	movel	M(sp,12), d0	C nl
+	divul	M(sp,16), d1:d0
+	movel	d1, M(a0)	C r
+	rts
+EPILOGUE(mpn_udiv_qrnnd)
diff --git a/third_party/gmp/mpn/m68k/mc68020/umul.asm b/third_party/gmp/mpn/m68k/mc68020/umul.asm
new file mode 100644
index 0000000..f19314e
--- /dev/null
+++ b/third_party/gmp/mpn/m68k/mc68020/umul.asm
@@ -0,0 +1,44 @@
+dnl  mc68020 mpn_umul_ppmm -- limb by limb multiplication
+
+dnl  Copyright 1999-2001 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C mp_limb_t mpn_umul_ppmm (mp_limb_t *lp, mp_limb_t x, mp_limb_t y);
+C
+
+PROLOGUE(mpn_umul_ppmm)
+	movel	M(sp,4), a0	C lp
+	movel	M(sp,8), d1	C x
+	movel	M(sp,12), d0	C y
+	mulul	d0, d0:d1
+	movel	d1, M(a0)	C low
+	rts
+EPILOGUE(mpn_umul_ppmm)
diff --git a/third_party/gmp/mpn/m68k/rshift.asm b/third_party/gmp/mpn/m68k/rshift.asm
new file mode 100644
index 0000000..21b5f89
--- /dev/null
+++ b/third_party/gmp/mpn/m68k/rshift.asm
@@ -0,0 +1,175 @@
+dnl  mc68020 mpn_rshift -- mpn right shift.
+
+dnl  Copyright 1996, 1999-2003 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C           cycles/limb
+C        shift==1  shift>1
+C 68040:    9         12
+
+
+C mp_limb_t mpn_rshift (mp_ptr res_ptr, mp_srcptr s_ptr, mp_size_t s_size,
+C                       unsigned cnt);
+C
+C The "cnt" parameter is either 16 bits or 32 bits depending on
+C SIZEOF_UNSIGNED (see ABI notes in mpn/m68k/README).  The value is of
+C course only 1 to 31.  When loaded as 16 bits there's garbage in the upper
+C half, hence the use of cmpw.  The shift instructions take the their count
+C modulo 64, so the upper part doesn't matter to them either.
+C
+
+C INPUT PARAMETERS
+C res_ptr	(sp + 4)
+C s_ptr		(sp + 8)
+C s_size	(sp + 12)
+C cnt		(sp + 16)
+
+define(res_ptr, `a1')
+define(s_ptr,   `a0')
+define(s_size,  `d6')
+define(cnt,     `d4')
+
+ifdef(`SIZEOF_UNSIGNED',,
+`m4_error(`SIZEOF_UNSIGNED not defined, should be in config.m4
+')')
+
+PROLOGUE(mpn_rshift)
+C Save used registers on the stack.
+	moveml	d2-d6/a2, M(-,sp)
+
+C Copy the arguments to registers.
+	movel	M(sp,28), res_ptr
+	movel	M(sp,32), s_ptr
+	movel	M(sp,36), s_size
+ifelse(SIZEOF_UNSIGNED,2,
+`	movew	M(sp,40), cnt',
+`	movel	M(sp,40), cnt')
+
+	moveql	#1, d5
+	cmpw	d5, cnt
+	bne	L(Lnormal)
+	cmpl	res_ptr, s_ptr
+	bls	L(Lspecial)		C jump if res_ptr >= s_ptr
+
+ifelse(scale_available_p,1,`
+	lea	M(res_ptr,s_size,l,4), a2
+',`
+	movel	s_size, d0
+	asll	#2, d0
+	lea	M(res_ptr,d0,l), a2
+')
+	cmpl	s_ptr, a2
+	bls	L(Lspecial)		C jump if s_ptr >= res_ptr + s_size
+
+L(Lnormal):
+	moveql	#32, d5
+	subl	cnt, d5
+	movel	M(s_ptr,+), d2
+	movel	d2, d0
+	lsll	d5, d0		C compute carry limb
+
+	lsrl	cnt, d2
+	movel	d2, d1
+	subql	#1, s_size
+	beq	L(Lend)
+	lsrl	#1, s_size
+	bcs	L(L1)
+	subql	#1, s_size
+
+L(Loop):
+	movel	M(s_ptr,+), d2
+	movel	d2, d3
+	lsll	d5, d3
+	orl	d3, d1
+	movel	d1, M(res_ptr,+)
+	lsrl	cnt, d2
+L(L1):
+	movel	M(s_ptr,+), d1
+	movel	d1, d3
+	lsll	d5, d3
+	orl	d3, d2
+	movel	d2, M(res_ptr,+)
+	lsrl	cnt, d1
+
+	dbf	s_size, L(Loop)
+	subl	#0x10000, s_size
+	bcc	L(Loop)
+
+L(Lend):
+	movel	d1, M(res_ptr)	C store most significant limb
+
+C Restore used registers from stack frame.
+	moveml	M(sp,+), d2-d6/a2
+	rts
+
+C We loop from most significant end of the arrays, which is only permissable
+C if the source and destination don't overlap, since the function is
+C documented to work for overlapping source and destination.
+
+L(Lspecial):
+ifelse(scale_available_p,1,`
+	lea	M(s_ptr,s_size,l,4), s_ptr
+	lea	M(res_ptr,s_size,l,4), res_ptr
+',`
+	movel	s_size, d0
+	asll	#2, d0
+	addl	d0, s_ptr
+	addl	d0, res_ptr
+')
+
+	clrl	d0			C initialize carry
+	eorw	#1, s_size
+	lsrl	#1, s_size
+	bcc	L(LL1)
+	subql	#1, s_size
+
+L(LLoop):
+	movel	M(-,s_ptr), d2
+	roxrl	#1, d2
+	movel	d2, M(-,res_ptr)
+L(LL1):
+	movel	M(-,s_ptr), d2
+	roxrl	#1, d2
+	movel	d2, M(-,res_ptr)
+
+	dbf	s_size, L(LLoop)
+	roxrl	#1, d0		C save cy in msb
+	subl	#0x10000, s_size
+	bcs	L(LLend)
+	addl	d0, d0		C restore cy
+	bra	L(LLoop)
+
+L(LLend):
+C Restore used registers from stack frame.
+	moveml	M(sp,+), d2-d6/a2
+	rts
+
+EPILOGUE(mpn_rshift)
diff --git a/third_party/gmp/mpn/m68k/t-m68k-defs.pl b/third_party/gmp/mpn/m68k/t-m68k-defs.pl
new file mode 100644
index 0000000..91c21fa
--- /dev/null
+++ b/third_party/gmp/mpn/m68k/t-m68k-defs.pl
@@ -0,0 +1,91 @@
+#! /usr/bin/perl -w
+
+# Copyright 2001, 2003 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+
+# Usage:  perl t-m68k-defs.pl [-t]
+#
+# Run this in the mpn/m68k source directory to check that m68k-defs.m4 has
+# m68k_defbranch()s or m68k_definsn()s for each instruction used in *.asm
+# and */*.asm.  Print nothing if everything is ok.  The -t option prints
+# some diagnostic traces.
+
+use strict;
+use Getopt::Std;
+
+my %opt;
+getopts('t', \%opt);
+
+my %branch;
+my %insn;
+
+open(FD, "<m68k-defs.m4")
+    or die "Cannot open m68k-defs.m4: $!\nIs this the mpn/m68k source directory?\n";
+my ($srcdir, $top_srcdir);
+while (<FD>) {
+    if (/^m68k_defbranch\(\s*(.*)\)/) { $branch{"b".$1} = 1; }
+    if (/^m68k_definsn\(\s*(.*),\s*(.*)\)/) { $insn{$1.$2} = 1; }
+}
+close(FD);
+
+print "branches: ", join(" ",keys(%branch)), "\n" if $opt{'t'};
+print "insns: ", join(" ",keys(%insn)), "\n" if $opt{'t'};
+
+
+foreach my $file (glob("*.asm"), glob("*/*.asm")) {
+    print "file $file\n" if $opt{'t'};
+
+    open(FD, "<$file") or die "Cannot open $file: $!";
+    while (<FD>) {
+	if (/^[ \t]*C/) { next; };
+	if (/^\t([a-z0-9]+)/) {
+	    my $opcode = $1;
+	    print "opcode $1\n" if $opt{'t'};
+
+	    # instructions with an l, w or b suffix should have a definsn
+	    # (unless they're already a defbranch)
+	    if ($opcode =~ /[lwb]$/
+		&& ! defined $insn{$opcode}
+		&& ! defined $branch{$opcode})
+	    {
+		print "$file: $.: missing m68k_definsn: $opcode\n";
+	    }
+
+	    # instructions bXX should have a defbranch (unless they're
+	    # already a definsn)
+	    if ($opcode =~ /^b/
+		&& ! defined $insn{$opcode}
+		&& ! defined $branch{$opcode})
+	    {
+		print "$file: $.: missing m68k_defbranch: $opcode\n";
+	    }
+	}
+    }
+    close(FD);
+}
diff --git a/third_party/gmp/mpn/m88k/README b/third_party/gmp/mpn/m88k/README
new file mode 100644
index 0000000..1b51e83
--- /dev/null
+++ b/third_party/gmp/mpn/m88k/README
@@ -0,0 +1,61 @@
+Copyright 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.
+
+
+
+
+
+                      M88K MPN SUBROUTINES
+
+This directory contains mpn functions for various m88k family chips.
+
+CODE ORGANIZATION
+
+	m88k             m88000, m88100
+	m88k/mc88110     m88110
+
+STATUS
+
+The code herein is old and poorly maintained.
+
+* The .s files assume the system uses a "_" underscore prefix, which
+  should be controlled by configure.
+
+* The mc88110/*.S files are using the defunct "sysdep.h" configuration
+  scheme and won't compile.
+
+Conversion to the current m4 .asm style wouldn't be difficult.
+
+
+
+
+----------------
+Local variables:
+mode: text
+fill-column: 76
+End:
diff --git a/third_party/gmp/mpn/m88k/add_n.s b/third_party/gmp/mpn/m88k/add_n.s
new file mode 100644
index 0000000..dbdb22f
--- /dev/null
+++ b/third_party/gmp/mpn/m88k/add_n.s
@@ -0,0 +1,113 @@
+; mc88100 mpn_add_n -- Add two limb vectors of the same length > 0 and store
+; sum in a third limb vector.
+
+; Copyright 1992, 1994, 1995, 2000 Free Software Foundation, Inc.
+
+;  This file is part of the GNU MP Library.
+;
+;  The GNU MP Library is free software; you can redistribute it and/or modify
+;  it under the terms of either:
+;
+;    * the GNU Lesser General Public License as published by the Free
+;      Software Foundation; either version 3 of the License, or (at your
+;      option) any later version.
+;
+;  or
+;
+;    * the GNU General Public License as published by the Free Software
+;      Foundation; either version 2 of the License, or (at your option) any
+;      later version.
+;
+;  or both in parallel, as here.
+;
+;  The GNU MP Library is distributed in the hope that it will be useful, but
+;  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+;  for more details.
+;
+;  You should have received copies of the GNU General Public License and the
+;  GNU Lesser General Public License along with the GNU MP Library.  If not,
+;  see https://www.gnu.org/licenses/.
+
+
+; INPUT PARAMETERS
+; res_ptr	r2
+; s1_ptr	r3
+; s2_ptr	r4
+; size		r5
+
+; This code has been optimized to run one instruction per clock, avoiding
+; load stalls and writeback contention.  As a result, the instruction
+; order is not always natural.
+
+; The speed is about 4.6 clocks/limb + 18 clocks/limb-vector on an 88100,
+; but on the 88110, it seems to run much slower, 6.6 clocks/limb.
+
+	text
+	align	 16
+	global	 ___gmpn_add_n
+___gmpn_add_n:
+	ld	r6,r3,0			; read first limb from s1_ptr
+	extu	r10,r5,3
+	ld	r7,r4,0			; read first limb from s2_ptr
+
+	subu.co	r5,r0,r5		; (clear carry as side effect)
+	mak	r5,r5,3<4>
+	bcnd	eq0,r5,Lzero
+
+	or	r12,r0,lo16(Lbase)
+	or.u	r12,r12,hi16(Lbase)
+	addu	r12,r12,r5		; r12 is address for entering in loop
+
+	extu	r5,r5,2			; divide by 4
+	subu	r2,r2,r5		; adjust res_ptr
+	subu	r3,r3,r5		; adjust s1_ptr
+	subu	r4,r4,r5		; adjust s2_ptr
+
+	or	r8,r6,r0
+
+	jmp.n	r12
+	 or	r9,r7,r0
+
+Loop:	addu	r3,r3,32
+	st	r8,r2,28
+	addu	r4,r4,32
+	ld	r6,r3,0
+	addu	r2,r2,32
+	ld	r7,r4,0
+Lzero:	subu	r10,r10,1		; add 0 + 8r limbs (adj loop cnt)
+Lbase:	ld	r8,r3,4
+	addu.cio r6,r6,r7
+	ld	r9,r4,4
+	st	r6,r2,0
+	ld	r6,r3,8			; add 7 + 8r limbs
+	addu.cio r8,r8,r9
+	ld	r7,r4,8
+	st	r8,r2,4
+	ld	r8,r3,12		; add 6 + 8r limbs
+	addu.cio r6,r6,r7
+	ld	r9,r4,12
+	st	r6,r2,8
+	ld	r6,r3,16		; add 5 + 8r limbs
+	addu.cio r8,r8,r9
+	ld	r7,r4,16
+	st	r8,r2,12
+	ld	r8,r3,20		; add 4 + 8r limbs
+	addu.cio r6,r6,r7
+	ld	r9,r4,20
+	st	r6,r2,16
+	ld	r6,r3,24		; add 3 + 8r limbs
+	addu.cio r8,r8,r9
+	ld	r7,r4,24
+	st	r8,r2,20
+	ld	r8,r3,28		; add 2 + 8r limbs
+	addu.cio r6,r6,r7
+	ld	r9,r4,28
+	st	r6,r2,24
+	bcnd.n	ne0,r10,Loop		; add 1 + 8r limbs
+	 addu.cio r8,r8,r9
+
+	st	r8,r2,28		; store most significant limb
+
+	jmp.n	 r1
+	 addu.ci r2,r0,r0		; return carry-out from most sign. limb
diff --git a/third_party/gmp/mpn/m88k/mc88110/add_n.S b/third_party/gmp/mpn/m88k/mc88110/add_n.S
new file mode 100644
index 0000000..c3b12b3
--- /dev/null
+++ b/third_party/gmp/mpn/m88k/mc88110/add_n.S
@@ -0,0 +1,209 @@
+; mc88110 __gmpn_add_n -- Add two limb vectors of the same length > 0 and store
+; sum in a third limb vector.
+
+; Copyright 1995, 1996, 2000 Free Software Foundation, Inc.
+
+;  This file is part of the GNU MP Library.
+;
+;  The GNU MP Library is free software; you can redistribute it and/or modify
+;  it under the terms of either:
+;
+;    * the GNU Lesser General Public License as published by the Free
+;      Software Foundation; either version 3 of the License, or (at your
+;      option) any later version.
+;
+;  or
+;
+;    * the GNU General Public License as published by the Free Software
+;      Foundation; either version 2 of the License, or (at your option) any
+;      later version.
+;
+;  or both in parallel, as here.
+;
+;  The GNU MP Library is distributed in the hope that it will be useful, but
+;  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+;  for more details.
+;
+;  You should have received copies of the GNU General Public License and the
+;  GNU Lesser General Public License along with the GNU MP Library.  If not,
+;  see https://www.gnu.org/licenses/.
+
+
+; INPUT PARAMETERS
+#define res_ptr	r2
+#define s1_ptr	r3
+#define s2_ptr	r4
+#define size	r5
+
+#include "sysdep.h"
+
+	text
+	align	16
+	global	C_SYMBOL_NAME(__gmpn_add_n)
+C_SYMBOL_NAME(__gmpn_add_n):
+	addu.co	 r0,r0,r0		; clear cy flag
+	xor	 r12,s2_ptr,res_ptr
+	bb1	 2,r12,L1
+; **  V1a  **
+L0:	bb0	 2,res_ptr,L_v1		; branch if res_ptr is aligned?
+/* Add least significant limb separately to align res_ptr and s2_ptr */
+	ld	 r10,s1_ptr,0
+	addu	 s1_ptr,s1_ptr,4
+	ld	 r8,s2_ptr,0
+	addu	 s2_ptr,s2_ptr,4
+	subu	 size,size,1
+	addu.co	 r6,r10,r8
+	st	 r6,res_ptr,0
+	addu	 res_ptr,res_ptr,4
+L_v1:	cmp	 r12,size,2
+	bb1	 lt,r12,Lend2
+
+	ld	 r10,s1_ptr,0
+	ld	 r12,s1_ptr,4
+	ld.d	 r8,s2_ptr,0
+	subu	 size,size,10
+	bcnd	 lt0,size,Lfin1
+/* Add blocks of 8 limbs until less than 8 limbs remain */
+	align	 8
+Loop1:	subu	 size,size,8
+	addu.cio r6,r10,r8
+	ld	 r10,s1_ptr,8
+	addu.cio r7,r12,r9
+	ld	 r12,s1_ptr,12
+	ld.d	 r8,s2_ptr,8
+	st.d	 r6,res_ptr,0
+	addu.cio r6,r10,r8
+	ld	 r10,s1_ptr,16
+	addu.cio r7,r12,r9
+	ld	 r12,s1_ptr,20
+	ld.d	 r8,s2_ptr,16
+	st.d	 r6,res_ptr,8
+	addu.cio r6,r10,r8
+	ld	 r10,s1_ptr,24
+	addu.cio r7,r12,r9
+	ld	 r12,s1_ptr,28
+	ld.d	 r8,s2_ptr,24
+	st.d	 r6,res_ptr,16
+	addu.cio r6,r10,r8
+	ld	 r10,s1_ptr,32
+	addu.cio r7,r12,r9
+	ld	 r12,s1_ptr,36
+	addu	 s1_ptr,s1_ptr,32
+	ld.d	 r8,s2_ptr,32
+	addu	 s2_ptr,s2_ptr,32
+	st.d	 r6,res_ptr,24
+	addu	 res_ptr,res_ptr,32
+	bcnd	 ge0,size,Loop1
+
+Lfin1:	addu	 size,size,8-2
+	bcnd	 lt0,size,Lend1
+/* Add blocks of 2 limbs until less than 2 limbs remain */
+Loope1:	addu.cio r6,r10,r8
+	ld	 r10,s1_ptr,8
+	addu.cio r7,r12,r9
+	ld	 r12,s1_ptr,12
+	ld.d	 r8,s2_ptr,8
+	st.d	 r6,res_ptr,0
+	subu	 size,size,2
+	addu	 s1_ptr,s1_ptr,8
+	addu	 s2_ptr,s2_ptr,8
+	addu	 res_ptr,res_ptr,8
+	bcnd	 ge0,size,Loope1
+Lend1:	addu.cio r6,r10,r8
+	addu.cio r7,r12,r9
+	st.d	 r6,res_ptr,0
+
+	bb0	 0,size,Lret1
+/* Add last limb */
+	ld	 r10,s1_ptr,8
+	ld	 r8,s2_ptr,8
+	addu.cio r6,r10,r8
+	st	 r6,res_ptr,8
+
+Lret1:	jmp.n	 r1
+	addu.ci	 r2,r0,r0		; return carry-out from most sign. limb
+
+L1:	xor	 r12,s1_ptr,res_ptr
+	bb1	 2,r12,L2
+; **  V1b  **
+	or	 r12,r0,s2_ptr
+	or	 s2_ptr,r0,s1_ptr
+	or	 s1_ptr,r0,r12
+	br	 L0
+
+; **  V2  **
+/* If we come here, the alignment of s1_ptr and res_ptr as well as the
+   alignment of s2_ptr and res_ptr differ.  Since there are only two ways
+   things can be aligned (that we care about) we now know that the alignment
+   of s1_ptr and s2_ptr are the same.  */
+
+L2:	cmp	 r12,size,1
+	bb1	 eq,r12,Ljone
+	bb0	 2,s1_ptr,L_v2		; branch if s1_ptr is aligned
+/* Add least significant limb separately to align res_ptr and s2_ptr */
+	ld	 r10,s1_ptr,0
+	addu	 s1_ptr,s1_ptr,4
+	ld	 r8,s2_ptr,0
+	addu	 s2_ptr,s2_ptr,4
+	subu	 size,size,1
+	addu.co	 r6,r10,r8
+	st	 r6,res_ptr,0
+	addu	 res_ptr,res_ptr,4
+
+L_v2:	subu	 size,size,8
+	bcnd	 lt0,size,Lfin2
+/* Add blocks of 8 limbs until less than 8 limbs remain */
+	align	 8
+Loop2:	subu	 size,size,8
+	ld.d	 r8,s1_ptr,0
+	ld.d	 r6,s2_ptr,0
+	addu.cio r8,r8,r6
+	st	 r8,res_ptr,0
+	addu.cio r9,r9,r7
+	st	 r9,res_ptr,4
+	ld.d	 r8,s1_ptr,8
+	ld.d	 r6,s2_ptr,8
+	addu.cio r8,r8,r6
+	st	 r8,res_ptr,8
+	addu.cio r9,r9,r7
+	st	 r9,res_ptr,12
+	ld.d	 r8,s1_ptr,16
+	ld.d	 r6,s2_ptr,16
+	addu.cio r8,r8,r6
+	st	 r8,res_ptr,16
+	addu.cio r9,r9,r7
+	st	 r9,res_ptr,20
+	ld.d	 r8,s1_ptr,24
+	ld.d	 r6,s2_ptr,24
+	addu.cio r8,r8,r6
+	st	 r8,res_ptr,24
+	addu.cio r9,r9,r7
+	st	 r9,res_ptr,28
+	addu	 s1_ptr,s1_ptr,32
+	addu	 s2_ptr,s2_ptr,32
+	addu	 res_ptr,res_ptr,32
+	bcnd	 ge0,size,Loop2
+
+Lfin2:	addu	 size,size,8-2
+	bcnd	 lt0,size,Lend2
+Loope2:	ld.d	 r8,s1_ptr,0
+	ld.d	 r6,s2_ptr,0
+	addu.cio r8,r8,r6
+	st	 r8,res_ptr,0
+	addu.cio r9,r9,r7
+	st	 r9,res_ptr,4
+	subu	 size,size,2
+	addu	 s1_ptr,s1_ptr,8
+	addu	 s2_ptr,s2_ptr,8
+	addu	 res_ptr,res_ptr,8
+	bcnd	 ge0,size,Loope2
+Lend2:	bb0	 0,size,Lret2
+/* Add last limb */
+Ljone:	ld	 r10,s1_ptr,0
+	ld	 r8,s2_ptr,0
+	addu.cio r6,r10,r8
+	st	 r6,res_ptr,0
+
+Lret2:	jmp.n	 r1
+	addu.ci	 r2,r0,r0		; return carry-out from most sign. limb
diff --git a/third_party/gmp/mpn/m88k/mc88110/addmul_1.s b/third_party/gmp/mpn/m88k/mc88110/addmul_1.s
new file mode 100644
index 0000000..321221f
--- /dev/null
+++ b/third_party/gmp/mpn/m88k/mc88110/addmul_1.s
@@ -0,0 +1,70 @@
+; mc88110 __gmpn_addmul_1 -- Multiply a limb vector with a single limb and
+; store the product in a second limb vector.
+
+; Copyright 1996, 2000 Free Software Foundation, Inc.
+
+;  This file is part of the GNU MP Library.
+;
+;  The GNU MP Library is free software; you can redistribute it and/or modify
+;  it under the terms of either:
+;
+;    * the GNU Lesser General Public License as published by the Free
+;      Software Foundation; either version 3 of the License, or (at your
+;      option) any later version.
+;
+;  or
+;
+;    * the GNU General Public License as published by the Free Software
+;      Foundation; either version 2 of the License, or (at your option) any
+;      later version.
+;
+;  or both in parallel, as here.
+;
+;  The GNU MP Library is distributed in the hope that it will be useful, but
+;  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+;  for more details.
+;
+;  You should have received copies of the GNU General Public License and the
+;  GNU Lesser General Public License along with the GNU MP Library.  If not,
+;  see https://www.gnu.org/licenses/.
+
+
+; INPUT PARAMETERS
+; res_ptr	r2
+; s1_ptr	r3
+; size		r4
+; s2_limb	r5
+
+	text
+	align	16
+	global	___gmpn_addmul_1
+___gmpn_addmul_1:
+	lda	 r3,r3[r4]
+	lda	 r8,r2[r4]		; RES_PTR in r8 since r2 is retval
+	subu	 r4,r0,r4
+	addu.co	 r2,r0,r0		; r2 = cy = 0
+
+	ld	 r6,r3[r4]
+	addu	 r4,r4,1
+	subu	 r8,r8,4
+	bcnd.n	 eq0,r4,Lend
+	 mulu.d	 r10,r6,r5
+
+Loop:	ld	 r7,r8[r4]
+	ld	 r6,r3[r4]
+	addu.cio r9,r11,r2
+	addu.ci	 r2,r10,r0
+	addu.co	 r9,r9,r7
+	st	 r9,r8[r4]
+	addu	 r4,r4,1
+	mulu.d	 r10,r6,r5
+	bcnd	 ne0,r4,Loop
+
+Lend:	ld	 r7,r8,0
+	addu.cio r9,r11,r2
+	addu.ci	 r2,r10,r0
+	addu.co	 r9,r9,r7
+	st	 r9,r8,0
+	jmp.n	 r1
+	 addu.ci r2,r2,r0
diff --git a/third_party/gmp/mpn/m88k/mc88110/mul_1.s b/third_party/gmp/mpn/m88k/mc88110/mul_1.s
new file mode 100644
index 0000000..28fd14b
--- /dev/null
+++ b/third_party/gmp/mpn/m88k/mc88110/mul_1.s
@@ -0,0 +1,68 @@
+; mc88110 __gmpn_mul_1 -- Multiply a limb vector with a single limb and
+; store the product in a second limb vector.
+
+; Copyright 1992, 1994, 1995, 2000 Free Software Foundation, Inc.
+
+;  This file is part of the GNU MP Library.
+;
+;  The GNU MP Library is free software; you can redistribute it and/or modify
+;  it under the terms of either:
+;
+;    * the GNU Lesser General Public License as published by the Free
+;      Software Foundation; either version 3 of the License, or (at your
+;      option) any later version.
+;
+;  or
+;
+;    * the GNU General Public License as published by the Free Software
+;      Foundation; either version 2 of the License, or (at your option) any
+;      later version.
+;
+;  or both in parallel, as here.
+;
+;  The GNU MP Library is distributed in the hope that it will be useful, but
+;  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+;  for more details.
+;
+;  You should have received copies of the GNU General Public License and the
+;  GNU Lesser General Public License along with the GNU MP Library.  If not,
+;  see https://www.gnu.org/licenses/.
+
+
+; INPUT PARAMETERS
+; res_ptr	r2
+; s1_ptr	r3
+; size		r4
+; s2_limb	r5
+
+	text
+	align	16
+	global	___gmpn_mul_1
+___gmpn_mul_1:
+	; Make S1_PTR and RES_PTR point at the end of their blocks
+	; and negate SIZE.
+	lda	 r3,r3[r4]
+	lda	 r8,r2[r4]		; RES_PTR in r8 since r2 is retval
+	subu	 r4,r0,r4
+
+	addu.co	 r2,r0,r0		; r2 = cy = 0
+
+	ld	 r6,r3[r4]
+	addu	 r4,r4,1
+	mulu.d	 r10,r6,r5
+	bcnd.n	 eq0,r4,Lend
+	 subu	 r8,r8,8
+
+Loop:	ld	 r6,r3[r4]
+	addu.cio r9,r11,r2
+	or	 r2,r10,r0		; could be avoided if unrolled
+	addu	 r4,r4,1
+	mulu.d	 r10,r6,r5
+	bcnd.n	 ne0,r4,Loop
+	 st	 r9,r8[r4]
+
+Lend:	addu.cio r9,r11,r2
+	st	 r9,r8,4
+	jmp.n	 r1
+	 addu.ci r2,r10,r0
diff --git a/third_party/gmp/mpn/m88k/mc88110/sub_n.S b/third_party/gmp/mpn/m88k/mc88110/sub_n.S
new file mode 100644
index 0000000..f0a8ecb
--- /dev/null
+++ b/third_party/gmp/mpn/m88k/mc88110/sub_n.S
@@ -0,0 +1,285 @@
+; mc88110 __gmpn_sub_n -- Subtract two limb vectors of the same length > 0 and
+; store difference in a third limb vector.
+
+; Copyright 1995, 1996, 2000 Free Software Foundation, Inc.
+
+;  This file is part of the GNU MP Library.
+;
+;  The GNU MP Library is free software; you can redistribute it and/or modify
+;  it under the terms of either:
+;
+;    * the GNU Lesser General Public License as published by the Free
+;      Software Foundation; either version 3 of the License, or (at your
+;      option) any later version.
+;
+;  or
+;
+;    * the GNU General Public License as published by the Free Software
+;      Foundation; either version 2 of the License, or (at your option) any
+;      later version.
+;
+;  or both in parallel, as here.
+;
+;  The GNU MP Library is distributed in the hope that it will be useful, but
+;  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+;  for more details.
+;
+;  You should have received copies of the GNU General Public License and the
+;  GNU Lesser General Public License along with the GNU MP Library.  If not,
+;  see https://www.gnu.org/licenses/.
+
+
+; INPUT PARAMETERS
+#define res_ptr	r2
+#define s1_ptr	r3
+#define s2_ptr	r4
+#define size	r5
+
+#include "sysdep.h"
+
+	text
+	align	16
+	global	C_SYMBOL_NAME(__gmpn_sub_n)
+C_SYMBOL_NAME(__gmpn_sub_n):
+	subu.co	 r0,r0,r0		; set cy flag
+	xor	 r12,s2_ptr,res_ptr
+	bb1	 2,r12,L1
+; **  V1a  **
+L0:	bb0	 2,res_ptr,L_v1		; branch if res_ptr is aligned
+/* Add least significant limb separately to align res_ptr and s2_ptr */
+	ld	 r10,s1_ptr,0
+	addu	 s1_ptr,s1_ptr,4
+	ld	 r8,s2_ptr,0
+	addu	 s2_ptr,s2_ptr,4
+	subu	 size,size,1
+	subu.co	 r6,r10,r8
+	st	 r6,res_ptr,0
+	addu	 res_ptr,res_ptr,4
+L_v1:	cmp	 r12,size,2
+	bb1	 lt,r12,Lend2
+
+	ld	 r10,s1_ptr,0
+	ld	 r12,s1_ptr,4
+	ld.d	 r8,s2_ptr,0
+	subu	 size,size,10
+	bcnd	 lt0,size,Lfin1
+/* Add blocks of 8 limbs until less than 8 limbs remain */
+	align	 8
+Loop1:	subu	 size,size,8
+	subu.cio r6,r10,r8
+	ld	 r10,s1_ptr,8
+	subu.cio r7,r12,r9
+	ld	 r12,s1_ptr,12
+	ld.d	 r8,s2_ptr,8
+	st.d	 r6,res_ptr,0
+	subu.cio r6,r10,r8
+	ld	 r10,s1_ptr,16
+	subu.cio r7,r12,r9
+	ld	 r12,s1_ptr,20
+	ld.d	 r8,s2_ptr,16
+	st.d	 r6,res_ptr,8
+	subu.cio r6,r10,r8
+	ld	 r10,s1_ptr,24
+	subu.cio r7,r12,r9
+	ld	 r12,s1_ptr,28
+	ld.d	 r8,s2_ptr,24
+	st.d	 r6,res_ptr,16
+	subu.cio r6,r10,r8
+	ld	 r10,s1_ptr,32
+	subu.cio r7,r12,r9
+	ld	 r12,s1_ptr,36
+	addu	 s1_ptr,s1_ptr,32
+	ld.d	 r8,s2_ptr,32
+	addu	 s2_ptr,s2_ptr,32
+	st.d	 r6,res_ptr,24
+	addu	 res_ptr,res_ptr,32
+	bcnd	 ge0,size,Loop1
+
+Lfin1:	addu	 size,size,8-2
+	bcnd	 lt0,size,Lend1
+/* Add blocks of 2 limbs until less than 2 limbs remain */
+Loope1:	subu.cio r6,r10,r8
+	ld	 r10,s1_ptr,8
+	subu.cio r7,r12,r9
+	ld	 r12,s1_ptr,12
+	ld.d	 r8,s2_ptr,8
+	st.d	 r6,res_ptr,0
+	subu	 size,size,2
+	addu	 s1_ptr,s1_ptr,8
+	addu	 s2_ptr,s2_ptr,8
+	addu	 res_ptr,res_ptr,8
+	bcnd	 ge0,size,Loope1
+Lend1:	subu.cio r6,r10,r8
+	subu.cio r7,r12,r9
+	st.d	 r6,res_ptr,0
+
+	bb0	 0,size,Lret1
+/* Add last limb */
+	ld	 r10,s1_ptr,8
+	ld	 r8,s2_ptr,8
+	subu.cio r6,r10,r8
+	st	 r6,res_ptr,8
+
+Lret1:	addu.ci r2,r0,r0		; return carry-out from most sign. limb
+	jmp.n	 r1
+	 xor	r2,r2,1
+
+L1:	xor	 r12,s1_ptr,res_ptr
+	bb1	 2,r12,L2
+; **  V1b  **
+	bb0	 2,res_ptr,L_v1b	; branch if res_ptr is aligned
+/* Add least significant limb separately to align res_ptr and s1_ptr */
+	ld	 r10,s2_ptr,0
+	addu	 s2_ptr,s2_ptr,4
+	ld	 r8,s1_ptr,0
+	addu	 s1_ptr,s1_ptr,4
+	subu	 size,size,1
+	subu.co	 r6,r8,r10
+	st	 r6,res_ptr,0
+	addu	 res_ptr,res_ptr,4
+L_v1b:	cmp	 r12,size,2
+	bb1	 lt,r12,Lend2
+
+	ld	 r10,s2_ptr,0
+	ld	 r12,s2_ptr,4
+	ld.d	 r8,s1_ptr,0
+	subu	 size,size,10
+	bcnd	 lt0,size,Lfin1b
+/* Add blocks of 8 limbs until less than 8 limbs remain */
+	align	 8
+Loop1b:	subu	 size,size,8
+	subu.cio r6,r8,r10
+	ld	 r10,s2_ptr,8
+	subu.cio r7,r9,r12
+	ld	 r12,s2_ptr,12
+	ld.d	 r8,s1_ptr,8
+	st.d	 r6,res_ptr,0
+	subu.cio r6,r8,r10
+	ld	 r10,s2_ptr,16
+	subu.cio r7,r9,r12
+	ld	 r12,s2_ptr,20
+	ld.d	 r8,s1_ptr,16
+	st.d	 r6,res_ptr,8
+	subu.cio r6,r8,r10
+	ld	 r10,s2_ptr,24
+	subu.cio r7,r9,r12
+	ld	 r12,s2_ptr,28
+	ld.d	 r8,s1_ptr,24
+	st.d	 r6,res_ptr,16
+	subu.cio r6,r8,r10
+	ld	 r10,s2_ptr,32
+	subu.cio r7,r9,r12
+	ld	 r12,s2_ptr,36
+	addu	 s2_ptr,s2_ptr,32
+	ld.d	 r8,s1_ptr,32
+	addu	 s1_ptr,s1_ptr,32
+	st.d	 r6,res_ptr,24
+	addu	 res_ptr,res_ptr,32
+	bcnd	 ge0,size,Loop1b
+
+Lfin1b:	addu	 size,size,8-2
+	bcnd	 lt0,size,Lend1b
+/* Add blocks of 2 limbs until less than 2 limbs remain */
+Loope1b:subu.cio r6,r8,r10
+	ld	 r10,s2_ptr,8
+	subu.cio r7,r9,r12
+	ld	 r12,s2_ptr,12
+	ld.d	 r8,s1_ptr,8
+	st.d	 r6,res_ptr,0
+	subu	 size,size,2
+	addu	 s1_ptr,s1_ptr,8
+	addu	 s2_ptr,s2_ptr,8
+	addu	 res_ptr,res_ptr,8
+	bcnd	 ge0,size,Loope1b
+Lend1b:	subu.cio r6,r8,r10
+	subu.cio r7,r9,r12
+	st.d	 r6,res_ptr,0
+
+	bb0	 0,size,Lret1b
+/* Add last limb */
+	ld	 r10,s2_ptr,8
+	ld	 r8,s1_ptr,8
+	subu.cio r6,r8,r10
+	st	 r6,res_ptr,8
+
+Lret1b:	addu.ci r2,r0,r0		; return carry-out from most sign. limb
+	jmp.n	 r1
+	 xor	r2,r2,1
+
+; **  V2  **
+/* If we come here, the alignment of s1_ptr and res_ptr as well as the
+   alignment of s2_ptr and res_ptr differ.  Since there are only two ways
+   things can be aligned (that we care about) we now know that the alignment
+   of s1_ptr and s2_ptr are the same.  */
+
+L2:	cmp	 r12,size,1
+	bb1	 eq,r12,Ljone
+	bb0	 2,s1_ptr,L_v2		; branch if s1_ptr is aligned
+/* Add least significant limb separately to align res_ptr and s2_ptr */
+	ld	 r10,s1_ptr,0
+	addu	 s1_ptr,s1_ptr,4
+	ld	 r8,s2_ptr,0
+	addu	 s2_ptr,s2_ptr,4
+	subu	 size,size,1
+	subu.co	 r6,r10,r8
+	st	 r6,res_ptr,0
+	addu	 res_ptr,res_ptr,4
+
+L_v2:	subu	 size,size,8
+	bcnd	 lt0,size,Lfin2
+/* Add blocks of 8 limbs until less than 8 limbs remain */
+	align	 8
+Loop2:	subu	 size,size,8
+	ld.d	 r8,s1_ptr,0
+	ld.d	 r6,s2_ptr,0
+	subu.cio r8,r8,r6
+	st	 r8,res_ptr,0
+	subu.cio r9,r9,r7
+	st	 r9,res_ptr,4
+	ld.d	 r8,s1_ptr,8
+	ld.d	 r6,s2_ptr,8
+	subu.cio r8,r8,r6
+	st	 r8,res_ptr,8
+	subu.cio r9,r9,r7
+	st	 r9,res_ptr,12
+	ld.d	 r8,s1_ptr,16
+	ld.d	 r6,s2_ptr,16
+	subu.cio r8,r8,r6
+	st	 r8,res_ptr,16
+	subu.cio r9,r9,r7
+	st	 r9,res_ptr,20
+	ld.d	 r8,s1_ptr,24
+	ld.d	 r6,s2_ptr,24
+	subu.cio r8,r8,r6
+	st	 r8,res_ptr,24
+	subu.cio r9,r9,r7
+	st	 r9,res_ptr,28
+	addu	 s1_ptr,s1_ptr,32
+	addu	 s2_ptr,s2_ptr,32
+	addu	 res_ptr,res_ptr,32
+	bcnd	 ge0,size,Loop2
+
+Lfin2:	addu	 size,size,8-2
+	bcnd	 lt0,size,Lend2
+Loope2:	ld.d	 r8,s1_ptr,0
+	ld.d	 r6,s2_ptr,0
+	subu.cio r8,r8,r6
+	st	 r8,res_ptr,0
+	subu.cio r9,r9,r7
+	st	 r9,res_ptr,4
+	subu	 size,size,2
+	addu	 s1_ptr,s1_ptr,8
+	addu	 s2_ptr,s2_ptr,8
+	addu	 res_ptr,res_ptr,8
+	bcnd	 ge0,size,Loope2
+Lend2:	bb0	 0,size,Lret2
+/* Add last limb */
+Ljone:	ld	 r10,s1_ptr,0
+	ld	 r8,s2_ptr,0
+	subu.cio r6,r10,r8
+	st	 r6,res_ptr,0
+
+Lret2:	addu.ci r2,r0,r0		; return carry-out from most sign. limb
+	jmp.n	 r1
+	 xor	r2,r2,1
diff --git a/third_party/gmp/mpn/m88k/mul_1.s b/third_party/gmp/mpn/m88k/mul_1.s
new file mode 100644
index 0000000..c8abdc0
--- /dev/null
+++ b/third_party/gmp/mpn/m88k/mul_1.s
@@ -0,0 +1,136 @@
+; mc88100 __gmpn_mul_1 -- Multiply a limb vector with a single limb and
+; store the product in a second limb vector.
+
+; Copyright 1992, 1994, 1995, 2000 Free Software Foundation, Inc.
+
+;  This file is part of the GNU MP Library.
+;
+;  The GNU MP Library is free software; you can redistribute it and/or modify
+;  it under the terms of either:
+;
+;    * the GNU Lesser General Public License as published by the Free
+;      Software Foundation; either version 3 of the License, or (at your
+;      option) any later version.
+;
+;  or
+;
+;    * the GNU General Public License as published by the Free Software
+;      Foundation; either version 2 of the License, or (at your option) any
+;      later version.
+;
+;  or both in parallel, as here.
+;
+;  The GNU MP Library is distributed in the hope that it will be useful, but
+;  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+;  for more details.
+;
+;  You should have received copies of the GNU General Public License and the
+;  GNU Lesser General Public License along with the GNU MP Library.  If not,
+;  see https://www.gnu.org/licenses/.
+
+
+; INPUT PARAMETERS
+; res_ptr	r2
+; s1_ptr	r3
+; size		r4
+; s2_limb	r5
+
+; Common overhead is about 11 cycles/invocation.
+
+; The speed for S2_LIMB >= 0x10000 is approximately 21 cycles/limb.  (The
+; pipeline stalls 2 cycles due to WB contention.)
+
+; The speed for S2_LIMB < 0x10000 is approximately 16 cycles/limb.  (The
+; pipeline stalls 2 cycles due to WB contention and 1 cycle due to latency.)
+
+; To enhance speed:
+; 1. Unroll main loop 4-8 times.
+; 2. Schedule code to avoid WB contention.  It might be tempting to move the
+;    ld instruction in the loops down to save 2 cycles (less WB contention),
+;    but that looses because the ultimate value will be read from outside
+;    the allocated space.  But if we handle the ultimate multiplication in
+;    the tail, we can do this.
+; 3. Make the multiplication with less instructions.  I think the code for
+;    (S2_LIMB >= 0x10000) is not minimal.
+; With these techniques the (S2_LIMB >= 0x10000) case would run in 17 or
+; less cycles/limb; the (S2_LIMB < 0x10000) case would run in 11
+; cycles/limb.  (Assuming infinite unrolling.)
+
+	text
+	align	 16
+	global	 ___gmpn_mul_1
+___gmpn_mul_1:
+
+	; Make S1_PTR and RES_PTR point at the end of their blocks
+	; and negate SIZE.
+	lda	 r3,r3[r4]
+	lda	 r6,r2[r4]	; RES_PTR in r6 since r2 is retval
+	subu	 r4,r0,r4
+
+	addu.co	 r2,r0,r0	; r2 = cy = 0
+	ld	 r9,r3[r4]
+	mask	 r7,r5,0xffff	; r7 = lo(S2_LIMB)
+	extu	 r8,r5,16	; r8 = hi(S2_LIMB)
+	bcnd.n	 eq0,r8,Lsmall	; jump if (hi(S2_LIMB) == 0)
+	 subu	 r6,r6,4
+
+; General code for any value of S2_LIMB.
+
+	; Make a stack frame and save r25 and r26
+	subu	 r31,r31,16
+	st.d	 r25,r31,8
+
+	; Enter the loop in the middle
+	br.n	L1
+	addu	 r4,r4,1
+
+Loop:	ld	 r9,r3[r4]
+	st	 r26,r6[r4]
+; bcnd	ne0,r0,0		; bubble
+	addu	 r4,r4,1
+L1:	mul	 r26,r9,r5	; low word of product	mul_1	WB ld
+	mask	 r12,r9,0xffff	; r12 = lo(s1_limb)	mask_1
+	mul	 r11,r12,r7	; r11 =  prod_0		mul_2	WB mask_1
+	mul	 r10,r12,r8	; r10 = prod_1a		mul_3
+	extu	 r13,r9,16	; r13 = hi(s1_limb)	extu_1	WB mul_1
+	mul	 r12,r13,r7	; r12 = prod_1b		mul_4	WB extu_1
+	mul	 r25,r13,r8	; r25  = prod_2		mul_5	WB mul_2
+	extu	 r11,r11,16	; r11 = hi(prod_0)	extu_2	WB mul_3
+	addu	 r10,r10,r11	;			addu_1	WB extu_2
+; bcnd	ne0,r0,0		; bubble			WB addu_1
+	addu.co	 r10,r10,r12	;				WB mul_4
+	mask.u	 r10,r10,0xffff	; move the 16 most significant bits...
+	addu.ci	 r10,r10,r0	; ...to the low half of the word...
+	rot	 r10,r10,16	; ...and put carry in pos 16.
+	addu.co	 r26,r26,r2	; add old carry limb
+	bcnd.n	 ne0,r4,Loop
+	 addu.ci r2,r25,r10	; compute new carry limb
+
+	st	 r26,r6[r4]
+	ld.d	 r25,r31,8
+	jmp.n	 r1
+	 addu	 r31,r31,16
+
+; Fast code for S2_LIMB < 0x10000
+Lsmall:
+	; Enter the loop in the middle
+	br.n	SL1
+	addu	 r4,r4,1
+
+SLoop:	ld	 r9,r3[r4]	;
+	st	 r8,r6[r4]	;
+	addu	 r4,r4,1	;
+SL1:	mul	 r8,r9,r5	; low word of product
+	mask	 r12,r9,0xffff	; r12 = lo(s1_limb)
+	extu	 r13,r9,16	; r13 = hi(s1_limb)
+	mul	 r11,r12,r7	; r11 =  prod_0
+	mul	 r12,r13,r7	; r12 = prod_1b
+	addu.cio r8,r8,r2	; add old carry limb
+	extu	 r10,r11,16	; r11 = hi(prod_0)
+	addu	 r10,r10,r12	;
+	bcnd.n	 ne0,r4,SLoop
+	extu	 r2,r10,16	; r2 = new carry limb
+
+	jmp.n	 r1
+	st	 r8,r6[r4]
diff --git a/third_party/gmp/mpn/m88k/sub_n.s b/third_party/gmp/mpn/m88k/sub_n.s
new file mode 100644
index 0000000..2bd8f09
--- /dev/null
+++ b/third_party/gmp/mpn/m88k/sub_n.s
@@ -0,0 +1,115 @@
+; mc88100 mpn_sub_n -- Subtract two limb vectors of the same length > 0 and
+; store difference in a third limb vector.
+
+; Copyright 1992, 1994, 1996, 2000 Free Software Foundation, Inc.
+
+;  This file is part of the GNU MP Library.
+;
+;  The GNU MP Library is free software; you can redistribute it and/or modify
+;  it under the terms of either:
+;
+;    * the GNU Lesser General Public License as published by the Free
+;      Software Foundation; either version 3 of the License, or (at your
+;      option) any later version.
+;
+;  or
+;
+;    * the GNU General Public License as published by the Free Software
+;      Foundation; either version 2 of the License, or (at your option) any
+;      later version.
+;
+;  or both in parallel, as here.
+;
+;  The GNU MP Library is distributed in the hope that it will be useful, but
+;  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+;  for more details.
+;
+;  You should have received copies of the GNU General Public License and the
+;  GNU Lesser General Public License along with the GNU MP Library.  If not,
+;  see https://www.gnu.org/licenses/.
+
+
+; INPUT PARAMETERS
+; res_ptr	r2
+; s1_ptr	r3
+; s2_ptr	r4
+; size		r5
+
+; This code has been optimized to run one instruction per clock, avoiding
+; load stalls and writeback contention.  As a result, the instruction
+; order is not always natural.
+
+; The speed is about 4.6 clocks/limb + 18 clocks/limb-vector on an 88100,
+; but on the 88110, it seems to run much slower, 6.6 clocks/limb.
+
+	text
+	align	 16
+	global	 ___gmpn_sub_n
+___gmpn_sub_n:
+	ld	r6,r3,0			; read first limb from s1_ptr
+	extu	r10,r5,3
+	ld	r7,r4,0			; read first limb from s2_ptr
+
+	subu	r5,r0,r5
+	mak	r5,r5,3<4>
+	bcnd.n	eq0,r5,Lzero
+	subu.co	r0,r0,r0		; initialize carry
+
+	or	r12,r0,lo16(Lbase)
+	or.u	r12,r12,hi16(Lbase)
+	addu	r12,r12,r5		; r12 is address for entering in loop
+
+	extu	r5,r5,2			; divide by 4
+	subu	r2,r2,r5		; adjust res_ptr
+	subu	r3,r3,r5		; adjust s1_ptr
+	subu	r4,r4,r5		; adjust s2_ptr
+
+	or	r8,r6,r0
+
+	jmp.n	r12
+	 or	r9,r7,r0
+
+Loop:	addu	r3,r3,32
+	st	r8,r2,28
+	addu	r4,r4,32
+	ld	r6,r3,0
+	addu	r2,r2,32
+	ld	r7,r4,0
+Lzero:	subu	r10,r10,1		; subtract 0 + 8r limbs (adj loop cnt)
+Lbase:	ld	r8,r3,4
+	subu.cio r6,r6,r7
+	ld	r9,r4,4
+	st	r6,r2,0
+	ld	r6,r3,8			; subtract 7 + 8r limbs
+	subu.cio r8,r8,r9
+	ld	r7,r4,8
+	st	r8,r2,4
+	ld	r8,r3,12		; subtract 6 + 8r limbs
+	subu.cio r6,r6,r7
+	ld	r9,r4,12
+	st	r6,r2,8
+	ld	r6,r3,16		; subtract 5 + 8r limbs
+	subu.cio r8,r8,r9
+	ld	r7,r4,16
+	st	r8,r2,12
+	ld	r8,r3,20		; subtract 4 + 8r limbs
+	subu.cio r6,r6,r7
+	ld	r9,r4,20
+	st	r6,r2,16
+	ld	r6,r3,24		; subtract 3 + 8r limbs
+	subu.cio r8,r8,r9
+	ld	r7,r4,24
+	st	r8,r2,20
+	ld	r8,r3,28		; subtract 2 + 8r limbs
+	subu.cio r6,r6,r7
+	ld	r9,r4,28
+	st	r6,r2,24
+	bcnd.n	ne0,r10,Loop		; subtract 1 + 8r limbs
+	 subu.cio r8,r8,r9
+
+	st	r8,r2,28		; store most significant limb
+
+	addu.ci r2,r0,r0		; return carry-out from most sign. limb
+	jmp.n	 r1
+	 xor	r2,r2,1
diff --git a/third_party/gmp/mpn/minithres/gmp-mparam.h b/third_party/gmp/mpn/minithres/gmp-mparam.h
new file mode 100644
index 0000000..35fcb77
--- /dev/null
+++ b/third_party/gmp/mpn/minithres/gmp-mparam.h
@@ -0,0 +1,113 @@
+/* Minimal values gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 2000, 2006, 2008-2010, 2012 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+/* The values in this file are not currently minimal.
+   Trimming them further would be good.  */
+
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          2
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          2
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD         3
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD         4
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD      1
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD            3
+
+#define MUL_TOOM22_THRESHOLD                 8
+#define MUL_TOOM33_THRESHOLD                20
+#define MUL_TOOM44_THRESHOLD                24
+#define MUL_TOOM6H_THRESHOLD                70 /* FIXME */
+#define MUL_TOOM8H_THRESHOLD                86
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      50 /* FIXME */
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD      50 /* FIXME */
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD      50 /* FIXME */
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD      50 /* FIXME */
+
+#define SQR_BASECASE_THRESHOLD               0
+#define SQR_TOOM2_THRESHOLD                  8
+#define SQR_TOOM3_THRESHOLD                 20
+#define SQR_TOOM4_THRESHOLD                 24
+#define SQR_TOOM6H_THRESHOLD                70 /* FIXME */
+#define SQR_TOOM8H_THRESHOLD                86
+
+#define MULMOD_BNM1_THRESHOLD            10
+#define SQRMOD_BNM1_THRESHOLD            10
+
+#define MUL_FFT_TABLE  {64, 256, 1024, 4096, 8192, 65536, 0}
+#define MUL_FFT_MODF_THRESHOLD  65
+#define MUL_FFT_THRESHOLD      200
+
+#define SQR_FFT_TABLE  {64, 256, 1024, 4096, 8192, 65536, 0}
+#define SQR_FFT_MODF_THRESHOLD  65
+#define SQR_FFT_THRESHOLD      200
+
+#define MULLO_BASECASE_THRESHOLD             0
+#define MULLO_DC_THRESHOLD                   2
+#define MULLO_MUL_N_THRESHOLD                4
+#define SQRLO_BASECASE_THRESHOLD             0
+#define SQRLO_DC_THRESHOLD                   2
+#define SQRLO_SQR_THRESHOLD                  4
+
+
+#define DC_DIV_QR_THRESHOLD                  6
+#define DC_DIVAPPR_Q_THRESHOLD               6
+#define DC_BDIV_QR_THRESHOLD                 4
+#define DC_BDIV_Q_THRESHOLD                  4
+
+#define INV_MULMOD_BNM1_THRESHOLD            2
+#define INV_NEWTON_THRESHOLD                 6
+#define INV_APPR_THRESHOLD                   4
+
+#define BINV_NEWTON_THRESHOLD                6
+#define REDC_1_TO_REDC_N_THRESHOLD           9
+
+#define MU_DIV_QR_THRESHOLD                  8
+#define MU_DIVAPPR_Q_THRESHOLD               8
+#define MUPI_DIV_QR_THRESHOLD                8
+#define MU_BDIV_QR_THRESHOLD                 8
+#define MU_BDIV_Q_THRESHOLD                  8
+
+#define MATRIX22_STRASSEN_THRESHOLD          2
+#define HGCD_THRESHOLD                      10
+#define GCD_DC_THRESHOLD                    20
+#define GCDEXT_SCHOENHAGE_THRESHOLD         20
+#define JACOBI_BASE_METHOD                   1
+
+#define GET_STR_DC_THRESHOLD                 4
+#define GET_STR_PRECOMPUTE_THRESHOLD        10
+#define SET_STR_THRESHOLD                   64
+#define SET_STR_PRECOMPUTE_THRESHOLD       100
+
+#define FAC_ODD_THRESHOLD                    0  /* always */
+#define FAC_DSC_THRESHOLD                   70
diff --git a/third_party/gmp/mpn/mips32/add_n.asm b/third_party/gmp/mpn/mips32/add_n.asm
new file mode 100644
index 0000000..e7d4c48
--- /dev/null
+++ b/third_party/gmp/mpn/mips32/add_n.asm
@@ -0,0 +1,124 @@
+dnl  MIPS32 mpn_add_n -- Add two limb vectors of the same length > 0 and store
+dnl  sum in a third limb vector.
+
+dnl  Copyright 1995, 2000, 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C res_ptr	$4
+C s1_ptr	$5
+C s2_ptr	$6
+C size		$7
+
+ASM_START()
+PROLOGUE(mpn_add_n)
+
+	lw	$10,0($5)
+	lw	$11,0($6)
+
+	addiu	$7,$7,-1
+	and	$9,$7,4-1	C number of limbs in first loop
+	beq	$9,$0,.L0	C if multiple of 4 limbs, skip first loop
+	 move	$2,$0
+
+	subu	$7,$7,$9
+
+.Loop0:	addiu	$9,$9,-1
+	lw	$12,4($5)
+	addu	$11,$11,$2
+	lw	$13,4($6)
+	sltu	$8,$11,$2
+	addu	$11,$10,$11
+	sltu	$2,$11,$10
+	sw	$11,0($4)
+	or	$2,$2,$8
+
+	addiu	$5,$5,4
+	addiu	$6,$6,4
+	move	$10,$12
+	move	$11,$13
+	bne	$9,$0,.Loop0
+	 addiu	$4,$4,4
+
+.L0:	beq	$7,$0,.Lend
+	 nop
+
+.Loop:	addiu	$7,$7,-4
+
+	lw	$12,4($5)
+	addu	$11,$11,$2
+	lw	$13,4($6)
+	sltu	$8,$11,$2
+	addu	$11,$10,$11
+	sltu	$2,$11,$10
+	sw	$11,0($4)
+	or	$2,$2,$8
+
+	lw	$10,8($5)
+	addu	$13,$13,$2
+	lw	$11,8($6)
+	sltu	$8,$13,$2
+	addu	$13,$12,$13
+	sltu	$2,$13,$12
+	sw	$13,4($4)
+	or	$2,$2,$8
+
+	lw	$12,12($5)
+	addu	$11,$11,$2
+	lw	$13,12($6)
+	sltu	$8,$11,$2
+	addu	$11,$10,$11
+	sltu	$2,$11,$10
+	sw	$11,8($4)
+	or	$2,$2,$8
+
+	lw	$10,16($5)
+	addu	$13,$13,$2
+	lw	$11,16($6)
+	sltu	$8,$13,$2
+	addu	$13,$12,$13
+	sltu	$2,$13,$12
+	sw	$13,12($4)
+	or	$2,$2,$8
+
+	addiu	$5,$5,16
+	addiu	$6,$6,16
+
+	bne	$7,$0,.Loop
+	 addiu	$4,$4,16
+
+.Lend:	addu	$11,$11,$2
+	sltu	$8,$11,$2
+	addu	$11,$10,$11
+	sltu	$2,$11,$10
+	sw	$11,0($4)
+	j	$31
+	or	$2,$2,$8
+EPILOGUE(mpn_add_n)
diff --git a/third_party/gmp/mpn/mips32/addmul_1.asm b/third_party/gmp/mpn/mips32/addmul_1.asm
new file mode 100644
index 0000000..9aa9e16
--- /dev/null
+++ b/third_party/gmp/mpn/mips32/addmul_1.asm
@@ -0,0 +1,101 @@
+dnl  MIPS32 mpn_addmul_1 -- Multiply a limb vector with a single limb and add
+dnl  the product to a second limb vector.
+
+dnl  Copyright 1992, 1994, 1996, 2000, 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C res_ptr	$4
+C s1_ptr	$5
+C size		$6
+C s2_limb	$7
+
+ASM_START()
+PROLOGUE(mpn_addmul_1)
+
+C feed-in phase 0
+	lw	$8,0($5)
+
+C feed-in phase 1
+	addiu	$5,$5,4
+	multu	$8,$7
+
+	addiu	$6,$6,-1
+	beq	$6,$0,$LC0
+	 move	$2,$0		C zero cy2
+
+	addiu	$6,$6,-1
+	beq	$6,$0,$LC1
+	lw	$8,0($5)	C load new s1 limb as early as possible
+
+Loop:	lw	$10,0($4)
+	mflo	$3
+	mfhi	$9
+	addiu	$5,$5,4
+	addu	$3,$3,$2	C add old carry limb to low product limb
+	multu	$8,$7
+	lw	$8,0($5)	C load new s1 limb as early as possible
+	addiu	$6,$6,-1	C decrement loop counter
+	sltu	$2,$3,$2	C carry from previous addition -> $2
+	addu	$3,$10,$3
+	sltu	$10,$3,$10
+	addu	$2,$2,$10
+	sw	$3,0($4)
+	addiu	$4,$4,4
+	bne	$6,$0,Loop
+	 addu	$2,$9,$2	C add high product limb and carry from addition
+
+C wind-down phase 1
+$LC1:	lw	$10,0($4)
+	mflo	$3
+	mfhi	$9
+	addu	$3,$3,$2
+	sltu	$2,$3,$2
+	multu	$8,$7
+	addu	$3,$10,$3
+	sltu	$10,$3,$10
+	addu	$2,$2,$10
+	sw	$3,0($4)
+	addiu	$4,$4,4
+	addu	$2,$9,$2	C add high product limb and carry from addition
+
+C wind-down phase 0
+$LC0:	lw	$10,0($4)
+	mflo	$3
+	mfhi	$9
+	addu	$3,$3,$2
+	sltu	$2,$3,$2
+	addu	$3,$10,$3
+	sltu	$10,$3,$10
+	addu	$2,$2,$10
+	sw	$3,0($4)
+	j	$31
+	addu	$2,$9,$2	C add high product limb and carry from addition
+EPILOGUE(mpn_addmul_1)
diff --git a/third_party/gmp/mpn/mips32/gmp-mparam.h b/third_party/gmp/mpn/mips32/gmp-mparam.h
new file mode 100644
index 0000000..986135d
--- /dev/null
+++ b/third_party/gmp/mpn/mips32/gmp-mparam.h
@@ -0,0 +1,72 @@
+/* gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 1999-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+
+/* Generated by tuneup.c, 2002-02-20, gcc 2.95 (R3000) */
+
+#define MUL_TOOM22_THRESHOLD             20
+#define MUL_TOOM33_THRESHOLD             50
+
+#define SQR_BASECASE_THRESHOLD            7
+#define SQR_TOOM2_THRESHOLD              57
+#define SQR_TOOM3_THRESHOLD              78
+
+#define DIV_SB_PREINV_THRESHOLD           0  /* always */
+#define DIV_DC_THRESHOLD                 57
+#define POWM_THRESHOLD                   78
+
+#define GCD_ACCEL_THRESHOLD               3
+#define JACOBI_BASE_METHOD                2
+
+#define DIVREM_1_NORM_THRESHOLD           0  /* always */
+#define DIVREM_1_UNNORM_THRESHOLD         0  /* always */
+#define MOD_1_NORM_THRESHOLD              0  /* always */
+#define MOD_1_UNNORM_THRESHOLD            0  /* always */
+#define USE_PREINV_DIVREM_1               1
+#define USE_PREINV_MOD_1                  1
+#define DIVREM_2_THRESHOLD                0  /* always */
+#define DIVEXACT_1_THRESHOLD              0  /* always */
+#define MODEXACT_1_ODD_THRESHOLD          0  /* always */
+
+#define GET_STR_DC_THRESHOLD             19
+#define GET_STR_PRECOMPUTE_THRESHOLD     25
+#define SET_STR_THRESHOLD               309
+
+#define MUL_FFT_TABLE  { 496, 1056, 2176, 5632, 14336, 40960, 0 }
+#define MUL_FFT_MODF_THRESHOLD          624
+#define MUL_FFT_THRESHOLD              5888
+
+#define SQR_FFT_TABLE  { 496, 1184, 2176, 5632, 14336, 40960, 0 }
+#define SQR_FFT_MODF_THRESHOLD          560
+#define SQR_FFT_THRESHOLD              5376
diff --git a/third_party/gmp/mpn/mips32/lshift.asm b/third_party/gmp/mpn/mips32/lshift.asm
new file mode 100644
index 0000000..6a58bb4
--- /dev/null
+++ b/third_party/gmp/mpn/mips32/lshift.asm
@@ -0,0 +1,99 @@
+dnl  MIPS32 mpn_lshift -- Left shift.
+
+dnl  Copyright 1995, 2000, 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C res_ptr	$4
+C src_ptr	$5
+C size		$6
+C cnt		$7
+
+ASM_START()
+PROLOGUE(mpn_lshift)
+	sll	$2,$6,2
+	addu	$5,$5,$2	C make r5 point at end of src
+	lw	$10,-4($5)	C load first limb
+	subu	$13,$0,$7
+	addu	$4,$4,$2	C make r4 point at end of res
+	addiu	$6,$6,-1
+	and	$9,$6,4-1	C number of limbs in first loop
+	beq	$9,$0,.L0	C if multiple of 4 limbs, skip first loop
+	 srl	$2,$10,$13	C compute function result
+
+	subu	$6,$6,$9
+
+.Loop0:	lw	$3,-8($5)
+	addiu	$4,$4,-4
+	addiu	$5,$5,-4
+	addiu	$9,$9,-1
+	sll	$11,$10,$7
+	srl	$12,$3,$13
+	move	$10,$3
+	or	$8,$11,$12
+	bne	$9,$0,.Loop0
+	 sw	$8,0($4)
+
+.L0:	beq	$6,$0,.Lend
+	 nop
+
+.Loop:	lw	$3,-8($5)
+	addiu	$4,$4,-16
+	addiu	$6,$6,-4
+	sll	$11,$10,$7
+	srl	$12,$3,$13
+
+	lw	$10,-12($5)
+	sll	$14,$3,$7
+	or	$8,$11,$12
+	sw	$8,12($4)
+	srl	$9,$10,$13
+
+	lw	$3,-16($5)
+	sll	$11,$10,$7
+	or	$8,$14,$9
+	sw	$8,8($4)
+	srl	$12,$3,$13
+
+	lw	$10,-20($5)
+	sll	$14,$3,$7
+	or	$8,$11,$12
+	sw	$8,4($4)
+	srl	$9,$10,$13
+
+	addiu	$5,$5,-16
+	or	$8,$14,$9
+	bgtz	$6,.Loop
+	 sw	$8,0($4)
+
+.Lend:	sll	$8,$10,$7
+	j	$31
+	sw	$8,-4($4)
+EPILOGUE(mpn_lshift)
diff --git a/third_party/gmp/mpn/mips32/mips-defs.m4 b/third_party/gmp/mpn/mips32/mips-defs.m4
new file mode 100644
index 0000000..5fa89ec
--- /dev/null
+++ b/third_party/gmp/mpn/mips32/mips-defs.m4
@@ -0,0 +1,80 @@
+divert(-1)
+
+dnl  m4 macros for MIPS assembly code (both 32-bit and 64-bit).
+
+
+dnl  Copyright 2000-2002 Free Software Foundation, Inc.
+dnl
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+dnl  Usage: ASM_START()
+define(`ASM_START',
+m4_assert_numargs(0)
+`	.set noreorder
+	.set nomacro')
+
+dnl  Usage: X(value)
+define(`X',
+m4_assert_numargs(1)
+`0x$1')
+
+dnl  Called: PROLOGUE_cpu(GSYM_PREFIX`'foo)
+dnl          EPILOGUE_cpu(GSYM_PREFIX`'foo)
+
+define(`PROLOGUE_cpu',
+m4_assert_numargs(1)
+`	.text
+	.align	4
+	.globl	$1
+	.ent	$1
+$1:')
+
+define(`EPILOGUE_cpu',
+m4_assert_numargs(1)
+`	.end	$1')
+
+
+dnl  Usage: r0 ... r31
+dnl         f0 ... f31
+dnl
+dnl  Map register names r0 to $0, and f0 to $f0, etc.
+dnl
+dnl  defreg() is used to protect the $ in $0 (otherwise it would represent a
+dnl  macro argument).  Double quoting is used to protect the f0 in $f0
+dnl  (otherwise it would be an infinite recursion).
+
+forloop(i,0,31,`defreg(`r'i,$i)')
+forloop(i,0,31,`deflit(`f'i,``$f''i)')
+
+
+dnl  Usage: ASM_END()
+define(`ASM_END',
+m4_assert_numargs(0)
+)
+
+divert
diff --git a/third_party/gmp/mpn/mips32/mips.m4 b/third_party/gmp/mpn/mips32/mips.m4
new file mode 100644
index 0000000..8b49e57
--- /dev/null
+++ b/third_party/gmp/mpn/mips32/mips.m4
@@ -0,0 +1,80 @@
+divert(-1)
+
+dnl  m4 macros for MIPS assembly code.
+
+
+dnl  Copyright 2000-2002 Free Software Foundation, Inc.
+dnl
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+dnl  Usage: ASM_START()
+define(`ASM_START',
+m4_assert_numargs(0)
+`	.set noreorder
+	.set nomacro')
+
+dnl  Usage: X(value)
+define(`X',
+m4_assert_numargs(1)
+`0x$1')
+
+dnl  Called: PROLOGUE_cpu(GSYM_PREFIX`'foo)
+dnl          EPILOGUE_cpu(GSYM_PREFIX`'foo)
+
+define(`PROLOGUE_cpu',
+m4_assert_numargs(1)
+`	.text
+	.align	4
+	.globl	$1
+	.ent	$1
+$1:')
+
+define(`EPILOGUE_cpu',
+m4_assert_numargs(1)
+`	.end	$1')
+
+
+dnl  Usage: r0 ... r31
+dnl         f0 ... f31
+dnl
+dnl  Map register names r0 to $0, and f0 to $f0, etc.
+dnl
+dnl  defreg() is used to protect the $ in $0 (otherwise it would represent a
+dnl  macro argument).  Double quoting is used to protect the f0 in $f0
+dnl  (otherwise it would be an infinite recursion).
+
+forloop(i,0,31,`defreg(`r'i,$i)')
+forloop(i,0,31,`deflit(`f'i,``$f''i)')
+
+
+dnl  Usage: ASM_END()
+define(`ASM_END',
+m4_assert_numargs(0)
+)
+
+divert
diff --git a/third_party/gmp/mpn/mips32/mul_1.asm b/third_party/gmp/mpn/mips32/mul_1.asm
new file mode 100644
index 0000000..4337bc2
--- /dev/null
+++ b/third_party/gmp/mpn/mips32/mul_1.asm
@@ -0,0 +1,89 @@
+dnl  MIPS32 mpn_mul_1 -- Multiply a limb vector with a single limb and store
+dnl  the product in a second limb vector.
+
+dnl  Copyright 1992, 1994, 1996, 2000, 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C res_ptr	$4
+C s1_ptr	$5
+C size		$6
+C s2_limb	$7
+
+ASM_START()
+PROLOGUE(mpn_mul_1)
+
+C feed-in phase 0
+	lw	$8,0($5)
+
+C feed-in phase 1
+	addiu	$5,$5,4
+	multu	$8,$7
+
+	addiu	$6,$6,-1
+	beq	$6,$0,$LC0
+	 move	$2,$0		C zero cy2
+
+	addiu	$6,$6,-1
+	beq	$6,$0,$LC1
+	lw	$8,0($5)	C load new s1 limb as early as possible
+
+Loop:	mflo	$10
+	mfhi	$9
+	addiu	$5,$5,4
+	addu	$10,$10,$2	C add old carry limb to low product limb
+	multu	$8,$7
+	lw	$8,0($5)	C load new s1 limb as early as possible
+	addiu	$6,$6,-1	C decrement loop counter
+	sltu	$2,$10,$2	C carry from previous addition -> $2
+	sw	$10,0($4)
+	addiu	$4,$4,4
+	bne	$6,$0,Loop
+	 addu	$2,$9,$2	C add high product limb and carry from addition
+
+C wind-down phase 1
+$LC1:	mflo	$10
+	mfhi	$9
+	addu	$10,$10,$2
+	sltu	$2,$10,$2
+	multu	$8,$7
+	sw	$10,0($4)
+	addiu	$4,$4,4
+	addu	$2,$9,$2	C add high product limb and carry from addition
+
+C wind-down phase 0
+$LC0:	mflo	$10
+	mfhi	$9
+	addu	$10,$10,$2
+	sltu	$2,$10,$2
+	sw	$10,0($4)
+	j	$31
+	addu	$2,$9,$2	C add high product limb and carry from addition
+EPILOGUE(mpn_mul_1)
diff --git a/third_party/gmp/mpn/mips32/rshift.asm b/third_party/gmp/mpn/mips32/rshift.asm
new file mode 100644
index 0000000..4b54510
--- /dev/null
+++ b/third_party/gmp/mpn/mips32/rshift.asm
@@ -0,0 +1,96 @@
+dnl  MIPS32 mpn_rshift -- Right shift.
+
+dnl  Copyright 1995, 2000, 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C res_ptr	$4
+C src_ptr	$5
+C size		$6
+C cnt		$7
+
+ASM_START()
+PROLOGUE(mpn_rshift)
+	lw	$10,0($5)	C load first limb
+	subu	$13,$0,$7
+	addiu	$6,$6,-1
+	and	$9,$6,4-1	C number of limbs in first loop
+	beq	$9,$0,.L0	C if multiple of 4 limbs, skip first loop
+	 sll	$2,$10,$13	C compute function result
+
+	subu	$6,$6,$9
+
+.Loop0:	lw	$3,4($5)
+	addiu	$4,$4,4
+	addiu	$5,$5,4
+	addiu	$9,$9,-1
+	srl	$11,$10,$7
+	sll	$12,$3,$13
+	move	$10,$3
+	or	$8,$11,$12
+	bne	$9,$0,.Loop0
+	 sw	$8,-4($4)
+
+.L0:	beq	$6,$0,.Lend
+	 nop
+
+.Loop:	lw	$3,4($5)
+	addiu	$4,$4,16
+	addiu	$6,$6,-4
+	srl	$11,$10,$7
+	sll	$12,$3,$13
+
+	lw	$10,8($5)
+	srl	$14,$3,$7
+	or	$8,$11,$12
+	sw	$8,-16($4)
+	sll	$9,$10,$13
+
+	lw	$3,12($5)
+	srl	$11,$10,$7
+	or	$8,$14,$9
+	sw	$8,-12($4)
+	sll	$12,$3,$13
+
+	lw	$10,16($5)
+	srl	$14,$3,$7
+	or	$8,$11,$12
+	sw	$8,-8($4)
+	sll	$9,$10,$13
+
+	addiu	$5,$5,16
+	or	$8,$14,$9
+	bgtz	$6,.Loop
+	 sw	$8,-4($4)
+
+.Lend:	srl	$8,$10,$7
+	j	$31
+	sw	$8,0($4)
+EPILOGUE(mpn_rshift)
diff --git a/third_party/gmp/mpn/mips32/sub_n.asm b/third_party/gmp/mpn/mips32/sub_n.asm
new file mode 100644
index 0000000..a962ce1
--- /dev/null
+++ b/third_party/gmp/mpn/mips32/sub_n.asm
@@ -0,0 +1,123 @@
+dnl  MIPS32 mpn_sub_n -- Subtract two limb vectors of the same length > 0 and
+dnl  store difference in a third limb vector.
+
+dnl  Copyright 1995, 2000, 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C res_ptr	$4
+C s1_ptr	$5
+C s2_ptr	$6
+C size		$7
+
+ASM_START()
+PROLOGUE(mpn_sub_n)
+	lw	$10,0($5)
+	lw	$11,0($6)
+
+	addiu	$7,$7,-1
+	and	$9,$7,4-1	C number of limbs in first loop
+	beq	$9,$0,.L0	C if multiple of 4 limbs, skip first loop
+	 move	$2,$0
+
+	subu	$7,$7,$9
+
+.Loop0:	addiu	$9,$9,-1
+	lw	$12,4($5)
+	addu	$11,$11,$2
+	lw	$13,4($6)
+	sltu	$8,$11,$2
+	subu	$11,$10,$11
+	sltu	$2,$10,$11
+	sw	$11,0($4)
+	or	$2,$2,$8
+
+	addiu	$5,$5,4
+	addiu	$6,$6,4
+	move	$10,$12
+	move	$11,$13
+	bne	$9,$0,.Loop0
+	 addiu	$4,$4,4
+
+.L0:	beq	$7,$0,.Lend
+	 nop
+
+.Loop:	addiu	$7,$7,-4
+
+	lw	$12,4($5)
+	addu	$11,$11,$2
+	lw	$13,4($6)
+	sltu	$8,$11,$2
+	subu	$11,$10,$11
+	sltu	$2,$10,$11
+	sw	$11,0($4)
+	or	$2,$2,$8
+
+	lw	$10,8($5)
+	addu	$13,$13,$2
+	lw	$11,8($6)
+	sltu	$8,$13,$2
+	subu	$13,$12,$13
+	sltu	$2,$12,$13
+	sw	$13,4($4)
+	or	$2,$2,$8
+
+	lw	$12,12($5)
+	addu	$11,$11,$2
+	lw	$13,12($6)
+	sltu	$8,$11,$2
+	subu	$11,$10,$11
+	sltu	$2,$10,$11
+	sw	$11,8($4)
+	or	$2,$2,$8
+
+	lw	$10,16($5)
+	addu	$13,$13,$2
+	lw	$11,16($6)
+	sltu	$8,$13,$2
+	subu	$13,$12,$13
+	sltu	$2,$12,$13
+	sw	$13,12($4)
+	or	$2,$2,$8
+
+	addiu	$5,$5,16
+	addiu	$6,$6,16
+
+	bne	$7,$0,.Loop
+	 addiu	$4,$4,16
+
+.Lend:	addu	$11,$11,$2
+	sltu	$8,$11,$2
+	subu	$11,$10,$11
+	sltu	$2,$10,$11
+	sw	$11,0($4)
+	j	$31
+	or	$2,$2,$8
+EPILOGUE(mpn_sub_n)
diff --git a/third_party/gmp/mpn/mips32/submul_1.asm b/third_party/gmp/mpn/mips32/submul_1.asm
new file mode 100644
index 0000000..335722b
--- /dev/null
+++ b/third_party/gmp/mpn/mips32/submul_1.asm
@@ -0,0 +1,101 @@
+dnl  MIPS32 mpn_submul_1 -- Multiply a limb vector with a single limb and
+dnl  subtract the product from a second limb vector.
+
+dnl  Copyright 1992, 1994, 1996, 2000, 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C res_ptr	$4
+C s1_ptr	$5
+C size		$6
+C s2_limb	$7
+
+ASM_START()
+PROLOGUE(mpn_submul_1)
+
+C feed-in phase 0
+	lw	$8,0($5)
+
+C feed-in phase 1
+	addiu	$5,$5,4
+	multu	$8,$7
+
+	addiu	$6,$6,-1
+	beq	$6,$0,$LC0
+	 move	$2,$0		C zero cy2
+
+	addiu	$6,$6,-1
+	beq	$6,$0,$LC1
+	lw	$8,0($5)	C load new s1 limb as early as possible
+
+Loop:	lw	$10,0($4)
+	mflo	$3
+	mfhi	$9
+	addiu	$5,$5,4
+	addu	$3,$3,$2	C add old carry limb to low product limb
+	multu	$8,$7
+	lw	$8,0($5)	C load new s1 limb as early as possible
+	addiu	$6,$6,-1	C decrement loop counter
+	sltu	$2,$3,$2	C carry from previous addition -> $2
+	subu	$3,$10,$3
+	sgtu	$10,$3,$10
+	addu	$2,$2,$10
+	sw	$3,0($4)
+	addiu	$4,$4,4
+	bne	$6,$0,Loop
+	 addu	$2,$9,$2	C add high product limb and carry from addition
+
+C wind-down phase 1
+$LC1:	lw	$10,0($4)
+	mflo	$3
+	mfhi	$9
+	addu	$3,$3,$2
+	sltu	$2,$3,$2
+	multu	$8,$7
+	subu	$3,$10,$3
+	sgtu	$10,$3,$10
+	addu	$2,$2,$10
+	sw	$3,0($4)
+	addiu	$4,$4,4
+	addu	$2,$9,$2	C add high product limb and carry from addition
+
+C wind-down phase 0
+$LC0:	lw	$10,0($4)
+	mflo	$3
+	mfhi	$9
+	addu	$3,$3,$2
+	sltu	$2,$3,$2
+	subu	$3,$10,$3
+	sgtu	$10,$3,$10
+	addu	$2,$2,$10
+	sw	$3,0($4)
+	j	$31
+	addu	$2,$9,$2	C add high product limb and carry from addition
+EPILOGUE(mpn_submul_1)
diff --git a/third_party/gmp/mpn/mips32/umul.asm b/third_party/gmp/mpn/mips32/umul.asm
new file mode 100644
index 0000000..1ced0eb
--- /dev/null
+++ b/third_party/gmp/mpn/mips32/umul.asm
@@ -0,0 +1,45 @@
+dnl  MIPS32 umul_ppmm -- longlong.h support.
+
+dnl  Copyright 1999, 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C plp   $4
+C u     $5
+C v     $6
+
+ASM_START()
+PROLOGUE(mpn_umul_ppmm)
+	multu	$5,$6
+	mflo	$3
+	mfhi	$2
+	j	$31
+	sw	$3,0($4)
+EPILOGUE(mpn_umul_ppmm)
diff --git a/third_party/gmp/mpn/mips64/README b/third_party/gmp/mpn/mips64/README
new file mode 100644
index 0000000..7ddd0e5
--- /dev/null
+++ b/third_party/gmp/mpn/mips64/README
@@ -0,0 +1,60 @@
+Copyright 1996 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.
+
+
+
+
+
+This directory contains mpn functions optimized for MIPS3.  Example of
+processors that implement MIPS3 are R4000, R4400, R4600, R4700, and R8000.
+
+RELEVANT OPTIMIZATION ISSUES
+
+1. On the R4000 and R4400, branches, both the plain and the "likely" ones,
+   take 3 cycles to execute.  (The fastest possible loop will take 4 cycles,
+   because of the delay insn.)
+
+   On the R4600, branches takes a single cycle
+
+   On the R8000, branches often take no noticeable cycles, as they are
+   executed in a separate function unit..
+
+2. The R4000 and R4400 have a load latency of 4 cycles.
+
+3. On the R4000 and R4400, multiplies take a data-dependent number of
+   cycles, contrary to the SGI documentation.  There seem to be 3 or 4
+   possible latencies.
+
+4. The R1x000 processors can issue one floating-point operation, two integer
+   operations, and one memory operation per cycle.  The FPU has very short
+   latencies, while the integer multiply unit is non-pipelined.  We should
+   therefore write fp based mpn_Xmul_1.
+
+STATUS
+
+Good...
diff --git a/third_party/gmp/mpn/mips64/add_n.asm b/third_party/gmp/mpn/mips64/add_n.asm
new file mode 100644
index 0000000..6856407
--- /dev/null
+++ b/third_party/gmp/mpn/mips64/add_n.asm
@@ -0,0 +1,134 @@
+dnl  MIPS64 mpn_add_n -- Add two limb vectors of the same length > 0 and store
+dnl  sum in a third limb vector.
+
+dnl  Copyright 1995, 2000-2002, 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C res_ptr	$4
+C s1_ptr	$5
+C s2_ptr	$6
+C size		$7
+
+ASM_START()
+PROLOGUE(mpn_add_nc)
+	ld	$10,0($5)
+	ld	$11,0($6)
+
+	daddiu	$7,$7,-1
+	and	$9,$7,4-1	C number of limbs in first loop
+	beq	$9,$0,.L0	C if multiple of 4 limbs, skip first loop
+	 move	$2,$8
+	b	.Loop0
+	 dsubu	$7,$7,$9
+EPILOGUE()
+PROLOGUE(mpn_add_n)
+	ld	$10,0($5)
+	ld	$11,0($6)
+
+	daddiu	$7,$7,-1
+	and	$9,$7,4-1	C number of limbs in first loop
+	beq	$9,$0,.L0	C if multiple of 4 limbs, skip first loop
+	 move	$2,$0
+
+	dsubu	$7,$7,$9
+
+.Loop0:	daddiu	$9,$9,-1
+	ld	$12,8($5)
+	daddu	$11,$11,$2
+	ld	$13,8($6)
+	sltu	$8,$11,$2
+	daddu	$11,$10,$11
+	sltu	$2,$11,$10
+	sd	$11,0($4)
+	or	$2,$2,$8
+
+	daddiu	$5,$5,8
+	daddiu	$6,$6,8
+	move	$10,$12
+	move	$11,$13
+	bne	$9,$0,.Loop0
+	 daddiu	$4,$4,8
+
+.L0:	beq	$7,$0,.Lend
+	 nop
+
+.Loop:	daddiu	$7,$7,-4
+
+	ld	$12,8($5)
+	daddu	$11,$11,$10
+	ld	$13,8($6)
+	sltu	$8,$11,$10
+	daddu	$11,$11,$2
+	sltu	$2,$11,$2
+	sd	$11,0($4)
+	or	$2,$2,$8
+
+	ld	$10,16($5)
+	daddu	$13,$13,$12
+	ld	$11,16($6)
+	sltu	$8,$13,$12
+	daddu	$13,$13,$2
+	sltu	$2,$13,$2
+	sd	$13,8($4)
+	or	$2,$2,$8
+
+	ld	$12,24($5)
+	daddu	$11,$11,$10
+	ld	$13,24($6)
+	sltu	$8,$11,$10
+	daddu	$11,$11,$2
+	sltu	$2,$11,$2
+	sd	$11,16($4)
+	or	$2,$2,$8
+
+	ld	$10,32($5)
+	daddu	$13,$13,$12
+	ld	$11,32($6)
+	sltu	$8,$13,$12
+	daddu	$13,$13,$2
+	sltu	$2,$13,$2
+	sd	$13,24($4)
+	or	$2,$2,$8
+
+	daddiu	$5,$5,32
+	daddiu	$6,$6,32
+
+	bne	$7,$0,.Loop
+	 daddiu	$4,$4,32
+
+.Lend:	daddu	$11,$11,$2
+	sltu	$8,$11,$2
+	daddu	$11,$10,$11
+	sltu	$2,$11,$10
+	sd	$11,0($4)
+	j	$31
+	or	$2,$2,$8
+EPILOGUE()
diff --git a/third_party/gmp/mpn/mips64/gmp-mparam.h b/third_party/gmp/mpn/mips64/gmp-mparam.h
new file mode 100644
index 0000000..b7fcf24
--- /dev/null
+++ b/third_party/gmp/mpn/mips64/gmp-mparam.h
@@ -0,0 +1,72 @@
+/* gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 1999-2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+
+/* Generated by tuneup.c, 2004-02-10, gcc 3.2 & MIPSpro C 7.2.1 (R1x000) */
+
+#define MUL_TOOM22_THRESHOLD             16
+#define MUL_TOOM33_THRESHOLD             89
+
+#define SQR_BASECASE_THRESHOLD            6
+#define SQR_TOOM2_THRESHOLD              32
+#define SQR_TOOM3_THRESHOLD              98
+
+#define DIV_SB_PREINV_THRESHOLD           0  /* always */
+#define DIV_DC_THRESHOLD                 53
+#define POWM_THRESHOLD                   61
+
+#define HGCD_THRESHOLD                  116
+#define GCD_ACCEL_THRESHOLD               3
+#define GCD_DC_THRESHOLD                492
+#define JACOBI_BASE_METHOD                2
+
+#define MOD_1_NORM_THRESHOLD              0  /* always */
+#define MOD_1_UNNORM_THRESHOLD            0  /* always */
+#define USE_PREINV_DIVREM_1               1
+#define USE_PREINV_MOD_1                  1
+#define DIVREM_2_THRESHOLD                0  /* always */
+#define DIVEXACT_1_THRESHOLD              0  /* always */
+#define MODEXACT_1_ODD_THRESHOLD          0  /* always */
+
+#define GET_STR_DC_THRESHOLD             21
+#define GET_STR_PRECOMPUTE_THRESHOLD     26
+#define SET_STR_THRESHOLD              3962
+
+#define MUL_FFT_TABLE  { 368, 736, 1600, 3328, 7168, 20480, 49152, 0 }
+#define MUL_FFT_MODF_THRESHOLD          264
+#define MUL_FFT_THRESHOLD              1920
+
+#define SQR_FFT_TABLE  { 368, 736, 1856, 3328, 7168, 20480, 49152, 0 }
+#define SQR_FFT_MODF_THRESHOLD          280
+#define SQR_FFT_THRESHOLD              1920
diff --git a/third_party/gmp/mpn/mips64/hilo/addmul_1.asm b/third_party/gmp/mpn/mips64/hilo/addmul_1.asm
new file mode 100644
index 0000000..8ff0976
--- /dev/null
+++ b/third_party/gmp/mpn/mips64/hilo/addmul_1.asm
@@ -0,0 +1,101 @@
+dnl  MIPS64 mpn_addmul_1 -- Multiply a limb vector with a single limb and add
+dnl  the product to a second limb vector.
+
+dnl  Copyright 1992, 1994, 1995, 2000-2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C res_ptr	$4
+C s1_ptr	$5
+C size		$6
+C s2_limb	$7
+
+ASM_START()
+PROLOGUE(mpn_addmul_1)
+
+C feed-in phase 0
+	ld	$8,0($5)
+
+C feed-in phase 1
+	daddiu	$5,$5,8
+	dmultu	$8,$7
+
+	daddiu	$6,$6,-1
+	beq	$6,$0,$LC0
+	 move	$2,$0		C zero cy2
+
+	daddiu	$6,$6,-1
+	beq	$6,$0,$LC1
+	ld	$8,0($5)	C load new s1 limb as early as possible
+
+Loop:	ld	$10,0($4)
+	mflo	$3
+	mfhi	$9
+	daddiu	$5,$5,8
+	daddu	$3,$3,$2	C add old carry limb to low product limb
+	dmultu	$8,$7
+	ld	$8,0($5)	C load new s1 limb as early as possible
+	daddiu	$6,$6,-1	C decrement loop counter
+	sltu	$2,$3,$2	C carry from previous addition -> $2
+	daddu	$3,$10,$3
+	sltu	$10,$3,$10
+	daddu	$2,$2,$10
+	sd	$3,0($4)
+	daddiu	$4,$4,8
+	bne	$6,$0,Loop
+	 daddu	$2,$9,$2	C add high product limb and carry from addition
+
+C wind-down phase 1
+$LC1:	ld	$10,0($4)
+	mflo	$3
+	mfhi	$9
+	daddu	$3,$3,$2
+	sltu	$2,$3,$2
+	dmultu	$8,$7
+	daddu	$3,$10,$3
+	sltu	$10,$3,$10
+	daddu	$2,$2,$10
+	sd	$3,0($4)
+	daddiu	$4,$4,8
+	daddu	$2,$9,$2	C add high product limb and carry from addition
+
+C wind-down phase 0
+$LC0:	ld	$10,0($4)
+	mflo	$3
+	mfhi	$9
+	daddu	$3,$3,$2
+	sltu	$2,$3,$2
+	daddu	$3,$10,$3
+	sltu	$10,$3,$10
+	daddu	$2,$2,$10
+	sd	$3,0($4)
+	j	$31
+	daddu	$2,$9,$2	C add high product limb and carry from addition
+EPILOGUE(mpn_addmul_1)
diff --git a/third_party/gmp/mpn/mips64/hilo/mul_1.asm b/third_party/gmp/mpn/mips64/hilo/mul_1.asm
new file mode 100644
index 0000000..77acf0a
--- /dev/null
+++ b/third_party/gmp/mpn/mips64/hilo/mul_1.asm
@@ -0,0 +1,92 @@
+dnl  MIPS64 mpn_mul_1 -- Multiply a limb vector with a single limb and store
+dnl  the product in a second limb vector.
+
+dnl  Copyright 1992, 1994, 1995, 2000-2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C res_ptr	$4
+C s1_ptr	$5
+C size		$6
+C s2_limb	$7
+
+ASM_START()
+PROLOGUE(mpn_mul_1)
+
+C feed-in phase 0
+	ld	$8,0($5)
+
+C feed-in phase 1
+	daddiu	$5,$5,8
+	dmultu	$8,$7
+
+	daddiu	$6,$6,-1
+	beq	$6,$0,$LC0
+	 move	$2,$0		C zero cy2
+
+	daddiu	$6,$6,-1
+	beq	$6,$0,$LC1
+	ld	$8,0($5)	C load new s1 limb as early as possible
+
+Loop:	nop
+	mflo	$10
+	mfhi	$9
+	daddiu	$5,$5,8
+	daddu	$10,$10,$2	C add old carry limb to low product limb
+	dmultu	$8,$7
+	ld	$8,0($5)	C load new s1 limb as early as possible
+	daddiu	$6,$6,-1	C decrement loop counter
+	sltu	$2,$10,$2	C carry from previous addition -> $2
+	nop
+	nop
+	sd	$10,0($4)
+	daddiu	$4,$4,8
+	bne	$6,$0,Loop
+	 daddu	$2,$9,$2	C add high product limb and carry from addition
+
+C wind-down phase 1
+$LC1:	mflo	$10
+	mfhi	$9
+	daddu	$10,$10,$2
+	sltu	$2,$10,$2
+	dmultu	$8,$7
+	sd	$10,0($4)
+	daddiu	$4,$4,8
+	daddu	$2,$9,$2	C add high product limb and carry from addition
+
+C wind-down phase 0
+$LC0:	mflo	$10
+	mfhi	$9
+	daddu	$10,$10,$2
+	sltu	$2,$10,$2
+	sd	$10,0($4)
+	j	$31
+	daddu	$2,$9,$2	C add high product limb and carry from addition
+EPILOGUE(mpn_mul_1)
diff --git a/third_party/gmp/mpn/mips64/hilo/sqr_diagonal.asm b/third_party/gmp/mpn/mips64/hilo/sqr_diagonal.asm
new file mode 100644
index 0000000..dcb87dc
--- /dev/null
+++ b/third_party/gmp/mpn/mips64/hilo/sqr_diagonal.asm
@@ -0,0 +1,77 @@
+dnl  MIPS64 mpn_sqr_diagonal.
+
+dnl  Copyright 2001, 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+dnl  INPUT PARAMETERS
+dnl  rp		$4
+dnl  up		$5
+dnl  n		$6
+
+include(`../config.m4')
+
+ASM_START()
+PROLOGUE(mpn_sqr_diagonal)
+	ld	r8,0(r5)
+	daddiu	r6,r6,-2
+	dmultu	r8,r8
+	bltz	r6,$Lend1
+	nop
+	ld	r8,8(r5)
+	beq	r6,r0,$Lend2
+	nop
+
+$Loop:	mflo	r10
+	mfhi	r9
+	daddiu	r6,r6,-1
+	sd	r10,0(r4)
+	sd	r9,8(r4)
+	dmultu	r8,r8
+	ld	r8,16(r5)
+	daddiu	r5,r5,8
+	bne	r6,r0,$Loop
+	daddiu	r4,r4,16
+
+$Lend2: mflo	r10
+	mfhi	r9
+	sd	r10,0(r4)
+	sd	r9,8(r4)
+	dmultu	r8,r8
+	mflo	r10
+	mfhi	r9
+	sd	r10,16(r4)
+	j	r31
+	sd	r9,24(r4)
+
+$Lend1: mflo	r10
+	mfhi	r9
+	sd	r10,0(r4)
+	j	r31
+	sd	r9,8(r4)
+EPILOGUE(mpn_sqr_diagonal)
diff --git a/third_party/gmp/mpn/mips64/hilo/submul_1.asm b/third_party/gmp/mpn/mips64/hilo/submul_1.asm
new file mode 100644
index 0000000..089589c
--- /dev/null
+++ b/third_party/gmp/mpn/mips64/hilo/submul_1.asm
@@ -0,0 +1,101 @@
+dnl  MIPS64 mpn_submul_1 -- Multiply a limb vector with a single limb and
+dnl  subtract the product from a second limb vector.
+
+dnl  Copyright 1992, 1994, 1995, 2000-2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C res_ptr	$4
+C s1_ptr	$5
+C size		$6
+C s2_limb	$7
+
+ASM_START()
+PROLOGUE(mpn_submul_1)
+
+C feed-in phase 0
+	ld	$8,0($5)
+
+C feed-in phase 1
+	daddiu	$5,$5,8
+	dmultu	$8,$7
+
+	daddiu	$6,$6,-1
+	beq	$6,$0,$LC0
+	 move	$2,$0		C zero cy2
+
+	daddiu	$6,$6,-1
+	beq	$6,$0,$LC1
+	ld	$8,0($5)	C load new s1 limb as early as possible
+
+Loop:	ld	$10,0($4)
+	mflo	$3
+	mfhi	$9
+	daddiu	$5,$5,8
+	daddu	$3,$3,$2	C add old carry limb to low product limb
+	dmultu	$8,$7
+	ld	$8,0($5)	C load new s1 limb as early as possible
+	daddiu	$6,$6,-1	C decrement loop counter
+	sltu	$2,$3,$2	C carry from previous addition -> $2
+	dsubu	$3,$10,$3
+	sgtu	$10,$3,$10
+	daddu	$2,$2,$10
+	sd	$3,0($4)
+	daddiu	$4,$4,8
+	bne	$6,$0,Loop
+	 daddu	$2,$9,$2	C add high product limb and carry from addition
+
+C wind-down phase 1
+$LC1:	ld	$10,0($4)
+	mflo	$3
+	mfhi	$9
+	daddu	$3,$3,$2
+	sltu	$2,$3,$2
+	dmultu	$8,$7
+	dsubu	$3,$10,$3
+	sgtu	$10,$3,$10
+	daddu	$2,$2,$10
+	sd	$3,0($4)
+	daddiu	$4,$4,8
+	daddu	$2,$9,$2	C add high product limb and carry from addition
+
+C wind-down phase 0
+$LC0:	ld	$10,0($4)
+	mflo	$3
+	mfhi	$9
+	daddu	$3,$3,$2
+	sltu	$2,$3,$2
+	dsubu	$3,$10,$3
+	sgtu	$10,$3,$10
+	daddu	$2,$2,$10
+	sd	$3,0($4)
+	j	$31
+	daddu	$2,$9,$2	C add high product limb and carry from addition
+EPILOGUE(mpn_submul_1)
diff --git a/third_party/gmp/mpn/mips64/hilo/umul.asm b/third_party/gmp/mpn/mips64/hilo/umul.asm
new file mode 100644
index 0000000..b9aac57
--- /dev/null
+++ b/third_party/gmp/mpn/mips64/hilo/umul.asm
@@ -0,0 +1,45 @@
+dnl  MIPS64 umul_ppmm -- longlong.h support.
+
+dnl  Copyright 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C plp   $4
+C u     $5
+C v     $6
+
+ASM_START()
+PROLOGUE(mpn_umul_ppmm)
+	dmultu	$5,$6
+	mflo	$3
+	mfhi	$2
+	j	$31
+	sd	$3,0($4)
+EPILOGUE(mpn_umul_ppmm)
diff --git a/third_party/gmp/mpn/mips64/lshift.asm b/third_party/gmp/mpn/mips64/lshift.asm
new file mode 100644
index 0000000..3440eaf
--- /dev/null
+++ b/third_party/gmp/mpn/mips64/lshift.asm
@@ -0,0 +1,99 @@
+dnl  MIPS64 mpn_lshift -- Left shift.
+
+dnl  Copyright 1995, 2000-2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C res_ptr	$4
+C src_ptr	$5
+C size		$6
+C cnt		$7
+
+ASM_START()
+PROLOGUE(mpn_lshift)
+	dsll	$2,$6,3
+	daddu	$5,$5,$2	C make r5 point at end of src
+	ld	$10,-8($5)	C load first limb
+	dsubu	$13,$0,$7
+	daddu	$4,$4,$2	C make r4 point at end of res
+	daddiu	$6,$6,-1
+	and	$9,$6,4-1	C number of limbs in first loop
+	beq	$9,$0,.L0	C if multiple of 4 limbs, skip first loop
+	 dsrl	$2,$10,$13	C compute function result
+
+	dsubu	$6,$6,$9
+
+.Loop0:	ld	$3,-16($5)
+	daddiu	$4,$4,-8
+	daddiu	$5,$5,-8
+	daddiu	$9,$9,-1
+	dsll	$11,$10,$7
+	dsrl	$12,$3,$13
+	move	$10,$3
+	or	$8,$11,$12
+	bne	$9,$0,.Loop0
+	 sd	$8,0($4)
+
+.L0:	beq	$6,$0,.Lend
+	 nop
+
+.Loop:	ld	$3,-16($5)
+	daddiu	$4,$4,-32
+	daddiu	$6,$6,-4
+	dsll	$11,$10,$7
+	dsrl	$12,$3,$13
+
+	ld	$10,-24($5)
+	dsll	$14,$3,$7
+	or	$8,$11,$12
+	sd	$8,24($4)
+	dsrl	$9,$10,$13
+
+	ld	$3,-32($5)
+	dsll	$11,$10,$7
+	or	$8,$14,$9
+	sd	$8,16($4)
+	dsrl	$12,$3,$13
+
+	ld	$10,-40($5)
+	dsll	$14,$3,$7
+	or	$8,$11,$12
+	sd	$8,8($4)
+	dsrl	$9,$10,$13
+
+	daddiu	$5,$5,-32
+	or	$8,$14,$9
+	bgtz	$6,.Loop
+	 sd	$8,0($4)
+
+.Lend:	dsll	$8,$10,$7
+	j	$31
+	sd	$8,-8($4)
+EPILOGUE(mpn_lshift)
diff --git a/third_party/gmp/mpn/mips64/rshift.asm b/third_party/gmp/mpn/mips64/rshift.asm
new file mode 100644
index 0000000..9253cb5
--- /dev/null
+++ b/third_party/gmp/mpn/mips64/rshift.asm
@@ -0,0 +1,96 @@
+dnl  MIPS64 mpn_rshift -- Right shift.
+
+dnl  Copyright 1995, 2000-2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C res_ptr	$4
+C src_ptr	$5
+C size		$6
+C cnt		$7
+
+ASM_START()
+PROLOGUE(mpn_rshift)
+	ld	$10,0($5)	C load first limb
+	dsubu	$13,$0,$7
+	daddiu	$6,$6,-1
+	and	$9,$6,4-1	C number of limbs in first loop
+	beq	$9,$0,.L0	C if multiple of 4 limbs, skip first loop
+	 dsll	$2,$10,$13	C compute function result
+
+	dsubu	$6,$6,$9
+
+.Loop0:	ld	$3,8($5)
+	daddiu	$4,$4,8
+	daddiu	$5,$5,8
+	daddiu	$9,$9,-1
+	dsrl	$11,$10,$7
+	dsll	$12,$3,$13
+	move	$10,$3
+	or	$8,$11,$12
+	bne	$9,$0,.Loop0
+	 sd	$8,-8($4)
+
+.L0:	beq	$6,$0,.Lend
+	 nop
+
+.Loop:	ld	$3,8($5)
+	daddiu	$4,$4,32
+	daddiu	$6,$6,-4
+	dsrl	$11,$10,$7
+	dsll	$12,$3,$13
+
+	ld	$10,16($5)
+	dsrl	$14,$3,$7
+	or	$8,$11,$12
+	sd	$8,-32($4)
+	dsll	$9,$10,$13
+
+	ld	$3,24($5)
+	dsrl	$11,$10,$7
+	or	$8,$14,$9
+	sd	$8,-24($4)
+	dsll	$12,$3,$13
+
+	ld	$10,32($5)
+	dsrl	$14,$3,$7
+	or	$8,$11,$12
+	sd	$8,-16($4)
+	dsll	$9,$10,$13
+
+	daddiu	$5,$5,32
+	or	$8,$14,$9
+	bgtz	$6,.Loop
+	 sd	$8,-8($4)
+
+.Lend:	dsrl	$8,$10,$7
+	j	$31
+	sd	$8,0($4)
+EPILOGUE(mpn_rshift)
diff --git a/third_party/gmp/mpn/mips64/sub_n.asm b/third_party/gmp/mpn/mips64/sub_n.asm
new file mode 100644
index 0000000..6a69897
--- /dev/null
+++ b/third_party/gmp/mpn/mips64/sub_n.asm
@@ -0,0 +1,134 @@
+dnl  MIPS64 mpn_sub_n -- Subtract two limb vectors of the same length > 0 and
+dnl  store difference in a third limb vector.
+
+dnl  Copyright 1995, 2000-2002, 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C res_ptr	$4
+C s1_ptr	$5
+C s2_ptr	$6
+C size		$7
+
+ASM_START()
+PROLOGUE(mpn_sub_nc)
+	ld	$10,0($5)
+	ld	$11,0($6)
+
+	daddiu	$7,$7,-1
+	and	$9,$7,4-1	C number of limbs in first loop
+	beq	$9,$0,.L0	C if multiple of 4 limbs, skip first loop
+	 move	$2,$8
+	b	.Loop0
+	 dsubu	$7,$7,$9
+EPILOGUE()
+PROLOGUE(mpn_sub_n)
+	ld	$10,0($5)
+	ld	$11,0($6)
+
+	daddiu	$7,$7,-1
+	and	$9,$7,4-1	C number of limbs in first loop
+	beq	$9,$0,.L0	C if multiple of 4 limbs, skip first loop
+	 move	$2,$0
+
+	dsubu	$7,$7,$9
+
+.Loop0:	daddiu	$9,$9,-1
+	ld	$12,8($5)
+	daddu	$11,$11,$2
+	ld	$13,8($6)
+	sltu	$8,$11,$2
+	dsubu	$11,$10,$11
+	sltu	$2,$10,$11
+	sd	$11,0($4)
+	or	$2,$2,$8
+
+	daddiu	$5,$5,8
+	daddiu	$6,$6,8
+	move	$10,$12
+	move	$11,$13
+	bne	$9,$0,.Loop0
+	 daddiu	$4,$4,8
+
+.L0:	beq	$7,$0,.Lend
+	 nop
+
+.Loop:	daddiu	$7,$7,-4
+
+	ld	$12,8($5)
+	dsubu	$11,$10,$11
+	ld	$13,8($6)
+	sltu	$8,$10,$11
+	dsubu	$14,$11,$2
+	sltu	$2,$11,$14
+	sd	$14,0($4)
+	or	$2,$2,$8
+
+	ld	$10,16($5)
+	dsubu	$13,$12,$13
+	ld	$11,16($6)
+	sltu	$8,$12,$13
+	dsubu	$14,$13,$2
+	sltu	$2,$13,$14
+	sd	$14,8($4)
+	or	$2,$2,$8
+
+	ld	$12,24($5)
+	dsubu	$11,$10,$11
+	ld	$13,24($6)
+	sltu	$8,$10,$11
+	dsubu	$14,$11,$2
+	sltu	$2,$11,$14
+	sd	$14,16($4)
+	or	$2,$2,$8
+
+	ld	$10,32($5)
+	dsubu	$13,$12,$13
+	ld	$11,32($6)
+	sltu	$8,$12,$13
+	dsubu	$14,$13,$2
+	sltu	$2,$13,$14
+	sd	$14,24($4)
+	or	$2,$2,$8
+
+	daddiu	$5,$5,32
+	daddiu	$6,$6,32
+
+	bne	$7,$0,.Loop
+	 daddiu	$4,$4,32
+
+.Lend:	daddu	$11,$11,$2
+	sltu	$8,$11,$2
+	dsubu	$11,$10,$11
+	sltu	$2,$10,$11
+	sd	$11,0($4)
+	j	$31
+	or	$2,$2,$8
+EPILOGUE()
diff --git a/third_party/gmp/mpn/pa32/README b/third_party/gmp/mpn/pa32/README
new file mode 100644
index 0000000..4323390
--- /dev/null
+++ b/third_party/gmp/mpn/pa32/README
@@ -0,0 +1,162 @@
+Copyright 1996, 1999, 2001, 2002, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.
+
+
+
+
+
+
+This directory contains mpn functions for various HP PA-RISC chips.  Code
+that runs faster on the PA7100 and later implementations, is in the pa7100
+directory.
+
+RELEVANT OPTIMIZATION ISSUES
+
+  Load and Store timing
+
+On the PA7000 no memory instructions can issue the two cycles after a store.
+For the PA7100, this is reduced to one cycle.
+
+The PA7100 has a lookup-free cache, so it helps to schedule loads and the
+dependent instruction really far from each other.
+
+STATUS
+
+1. mpn_mul_1 could be improved to 6.5 cycles/limb on the PA7100, using the
+   instructions below (but some sw pipelining is needed to avoid the
+   xmpyu-fstds delay):
+
+	fldds	s1_ptr
+
+	xmpyu
+	fstds	N(%r30)
+	xmpyu
+	fstds	N(%r30)
+
+	ldws	N(%r30)
+	ldws	N(%r30)
+	ldws	N(%r30)
+	ldws	N(%r30)
+
+	addc
+	stws	res_ptr
+	addc
+	stws	res_ptr
+
+	addib	Loop
+
+2. mpn_addmul_1 could be improved from the current 10 to 7.5 cycles/limb
+   (asymptotically) on the PA7100, using the instructions below.  With proper
+   sw pipelining and the unrolling level below, the speed becomes 8
+   cycles/limb.
+
+	fldds	s1_ptr
+	fldds	s1_ptr
+
+	xmpyu
+	fstds	N(%r30)
+	xmpyu
+	fstds	N(%r30)
+	xmpyu
+	fstds	N(%r30)
+	xmpyu
+	fstds	N(%r30)
+
+	ldws	N(%r30)
+	ldws	N(%r30)
+	ldws	N(%r30)
+	ldws	N(%r30)
+	ldws	N(%r30)
+	ldws	N(%r30)
+	ldws	N(%r30)
+	ldws	N(%r30)
+	addc
+	addc
+	addc
+	addc
+	addc	%r0,%r0,cy-limb
+
+	ldws	res_ptr
+	ldws	res_ptr
+	ldws	res_ptr
+	ldws	res_ptr
+	add
+	stws	res_ptr
+	addc
+	stws	res_ptr
+	addc
+	stws	res_ptr
+	addc
+	stws	res_ptr
+
+	addib
+
+3. For the PA8000 we have to stick to using 32-bit limbs before compiler
+   support emerges.  But we want to use 64-bit operations whenever possible,
+   in particular for loads and stores.  It is possible to handle mpn_add_n
+   efficiently by rotating (when s1/s2 are aligned), masking+bit field
+   inserting when (they are not).  The speed should double compared to the
+   code used today.
+
+
+
+
+LABEL SYNTAX
+
+The HP-UX assembler takes labels starting in column 0 with no colon,
+
+	L$loop  ldws,mb -4(0,%r25),%r22
+
+Gas on hppa GNU/Linux however requires a colon,
+
+	L$loop: ldws,mb -4(0,%r25),%r22
+
+This is covered by using LDEF() from asm-defs.m4.  An alternative would be
+to use ".label" which is accepted by both,
+
+		.label  L$loop
+		ldws,mb -4(0,%r25),%r22
+
+but that's not as nice to look at, not if you're used to assembler code
+having labels in column 0.
+
+
+
+
+REFERENCES
+
+Hewlett Packard, "HP Assembler Reference Manual", 9th edition, June 1998,
+part number 92432-90012.
+
+
+
+----------------
+Local variables:
+mode: text
+fill-column: 76
+End:
diff --git a/third_party/gmp/mpn/pa32/add_n.asm b/third_party/gmp/mpn/pa32/add_n.asm
new file mode 100644
index 0000000..46f3937
--- /dev/null
+++ b/third_party/gmp/mpn/pa32/add_n.asm
@@ -0,0 +1,63 @@
+dnl  HP-PA mpn_add_n -- Add two limb vectors of the same length > 0 and store
+dnl  sum in a third limb vector.
+
+dnl  Copyright 1992, 1994, 2000-2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C res_ptr	gr26
+C s1_ptr	gr25
+C s2_ptr	gr24
+C size		gr23
+
+C One might want to unroll this as for other processors, but it turns out that
+C the data cache contention after a store makes such unrolling useless.  We
+C can't come under 5 cycles/limb anyway.
+
+ASM_START()
+PROLOGUE(mpn_add_n)
+	ldws,ma		4(0,%r25),%r20
+	ldws,ma		4(0,%r24),%r19
+
+	addib,=		-1,%r23,L(end)	C check for (SIZE == 1)
+	 add		%r20,%r19,%r28	C add first limbs ignoring cy
+
+LDEF(loop)
+	ldws,ma		4(0,%r25),%r20
+	ldws,ma		4(0,%r24),%r19
+	stws,ma		%r28,4(0,%r26)
+	addib,<>	-1,%r23,L(loop)
+	 addc		%r20,%r19,%r28
+
+LDEF(end)
+	stws		%r28,0(0,%r26)
+	bv		0(%r2)
+	 addc		%r0,%r0,%r28
+EPILOGUE()
diff --git a/third_party/gmp/mpn/pa32/gmp-mparam.h b/third_party/gmp/mpn/pa32/gmp-mparam.h
new file mode 100644
index 0000000..377efcb
--- /dev/null
+++ b/third_party/gmp/mpn/pa32/gmp-mparam.h
@@ -0,0 +1,61 @@
+/* HP-PA 1.0 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 1999-2002, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+/* These values are for the PA7100 using GCC.  */
+/* Generated by tuneup.c, 2000-10-27. */
+
+#ifndef MUL_TOOM22_THRESHOLD
+#define MUL_TOOM22_THRESHOLD      30
+#endif
+#ifndef MUL_TOOM33_THRESHOLD
+#define MUL_TOOM33_THRESHOLD     141
+#endif
+
+#ifndef SQR_TOOM2_THRESHOLD
+#define SQR_TOOM2_THRESHOLD       59
+#endif
+#ifndef SQR_TOOM3_THRESHOLD
+#define SQR_TOOM3_THRESHOLD      177
+#endif
+
+#ifndef DIV_DC_THRESHOLD
+#define DIV_DC_THRESHOLD         108
+#endif
+
+#ifndef POWM_THRESHOLD
+#define POWM_THRESHOLD            18
+#endif
+
+#ifndef GCDEXT_THRESHOLD
+#define GCDEXT_THRESHOLD          33
+#endif
diff --git a/third_party/gmp/mpn/pa32/hppa1_1/addmul_1.asm b/third_party/gmp/mpn/pa32/hppa1_1/addmul_1.asm
new file mode 100644
index 0000000..ec2f219
--- /dev/null
+++ b/third_party/gmp/mpn/pa32/hppa1_1/addmul_1.asm
@@ -0,0 +1,106 @@
+dnl  HP-PA 1.1 mpn_addmul_1 -- Multiply a limb vector with a limb and add the
+dnl  result to a second limb vector.
+
+dnl  Copyright 1992-1994, 2000-2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C res_ptr	r26
+C s1_ptr	r25
+C size		r24
+C s2_limb	r23
+
+C This runs at 11 cycles/limb on a PA7000.  With the used instructions, it can
+C not become faster due to data cache contention after a store.  On the PA7100
+C it runs at 10 cycles/limb.
+
+C There are some ideas described in mul_1.asm that applies to this code too.
+
+ASM_START()
+PROLOGUE(mpn_addmul_1)
+C	.callinfo	frame=64,no_calls
+
+	ldo		64(%r30),%r30
+	fldws,ma	4(%r25),%fr5
+	stw		%r23,-16(%r30)		C move s2_limb ...
+	addib,=		-1,%r24,L(just_one_limb)
+	 fldws		-16(%r30),%fr4		C ... into fr4
+	add		%r0,%r0,%r0		C clear carry
+	xmpyu		%fr4,%fr5,%fr6
+	fldws,ma	4(%r25),%fr7
+	fstds		%fr6,-16(%r30)
+	xmpyu		%fr4,%fr7,%fr8
+	ldw		-12(%r30),%r19		C least significant limb in product
+	ldw		-16(%r30),%r28
+
+	fstds		%fr8,-16(%r30)
+	addib,=		-1,%r24,L(end)
+	 ldw		-12(%r30),%r1
+
+C Main loop
+LDEF(loop)
+	ldws		0(%r26),%r29
+	fldws,ma	4(%r25),%fr5
+	add		%r29,%r19,%r19
+	stws,ma		%r19,4(%r26)
+	addc		%r28,%r1,%r19
+	xmpyu		%fr4,%fr5,%fr6
+	ldw		-16(%r30),%r28
+	fstds		%fr6,-16(%r30)
+	addc		%r0,%r28,%r28
+	addib,<>	-1,%r24,L(loop)
+	 ldw		-12(%r30),%r1
+
+LDEF(end)
+	ldw		0(%r26),%r29
+	add		%r29,%r19,%r19
+	stws,ma		%r19,4(%r26)
+	addc		%r28,%r1,%r19
+	ldw		-16(%r30),%r28
+	ldws		0(%r26),%r29
+	addc		%r0,%r28,%r28
+	add		%r29,%r19,%r19
+	stws,ma		%r19,4(%r26)
+	addc		%r0,%r28,%r28
+	bv		0(%r2)
+	 ldo		-64(%r30),%r30
+
+LDEF(just_one_limb)
+	xmpyu		%fr4,%fr5,%fr6
+	ldw		0(%r26),%r29
+	fstds		%fr6,-16(%r30)
+	ldw		-12(%r30),%r1
+	ldw		-16(%r30),%r28
+	add		%r29,%r1,%r19
+	stw		%r19,0(%r26)
+	addc		%r0,%r28,%r28
+	bv		0(%r2)
+	 ldo		-64(%r30),%r30
+EPILOGUE()
diff --git a/third_party/gmp/mpn/pa32/hppa1_1/gmp-mparam.h b/third_party/gmp/mpn/pa32/hppa1_1/gmp-mparam.h
new file mode 100644
index 0000000..1261b24
--- /dev/null
+++ b/third_party/gmp/mpn/pa32/hppa1_1/gmp-mparam.h
@@ -0,0 +1,72 @@
+/* HP-PA 1.1 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 1999-2002, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+/* Generated by tuneup.c, 2004-02-07, gcc 2.8 (pa7100/100MHz) */
+
+#define MUL_TOOM22_THRESHOLD             30
+#define MUL_TOOM33_THRESHOLD             89
+
+#define SQR_BASECASE_THRESHOLD            4
+#define SQR_TOOM2_THRESHOLD              55
+#define SQR_TOOM3_THRESHOLD             101
+
+#define DIV_SB_PREINV_THRESHOLD           0  /* always */
+#define DIV_DC_THRESHOLD                 84
+#define POWM_THRESHOLD                  166
+
+#define HGCD_THRESHOLD                  231
+#define GCD_ACCEL_THRESHOLD               3
+#define GCD_DC_THRESHOLD                823
+#define JACOBI_BASE_METHOD                2
+
+#define DIVREM_1_NORM_THRESHOLD           5
+#define DIVREM_1_UNNORM_THRESHOLD        11
+#define MOD_1_NORM_THRESHOLD              5
+#define MOD_1_UNNORM_THRESHOLD           10
+#define USE_PREINV_DIVREM_1               1
+#define USE_PREINV_MOD_1                  1
+#define DIVREM_2_THRESHOLD                0  /* always */
+#define DIVEXACT_1_THRESHOLD              0  /* always */
+#define MODEXACT_1_ODD_THRESHOLD          0  /* always */
+
+#define GET_STR_DC_THRESHOLD             13
+#define GET_STR_PRECOMPUTE_THRESHOLD     23
+#define SET_STR_THRESHOLD              6589
+
+#define MUL_FFT_TABLE  { 464, 928, 1920, 4608, 14336, 40960, 0 }
+#define MUL_FFT_MODF_THRESHOLD          480
+#define MUL_FFT_THRESHOLD              3328
+
+#define SQR_FFT_TABLE  { 528, 1184, 2176, 5632, 14336, 40960, 0 }
+#define SQR_FFT_MODF_THRESHOLD          520
+#define SQR_FFT_THRESHOLD              3328
diff --git a/third_party/gmp/mpn/pa32/hppa1_1/mul_1.asm b/third_party/gmp/mpn/pa32/hppa1_1/mul_1.asm
new file mode 100644
index 0000000..6e60c2f
--- /dev/null
+++ b/third_party/gmp/mpn/pa32/hppa1_1/mul_1.asm
@@ -0,0 +1,102 @@
+dnl  HP-PA 1.1 mpn_mul_1 -- Multiply a limb vector with a limb and store the
+dnl  result in a second limb vector.
+
+dnl  Copyright 1992-1994, 2000-2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C res_ptr	r26
+C s1_ptr	r25
+C size		r24
+C s2_limb	r23
+
+C This runs at 9 cycles/limb on a PA7000.  With the used instructions, it can
+C not become faster due to data cache contention after a store.  On the PA7100
+C it runs at 7 cycles/limb.
+
+C We could use fldds to read two limbs at a time from the S1 array, and that
+C could bring down the times to 8.5 and 6.5 cycles/limb for the PA7000 and
+C PA7100, respectively.  We don't do that since it does not seem worth the
+C (alignment) troubles...
+
+C At least the PA7100 is rumored to be able to deal with cache-misses without
+C stalling instruction issue.  If this is true, and the cache is actually also
+C lockup-free, we should use a deeper software pipeline, and load from S1 very
+C early!  (The loads and stores to -12(sp) will surely be in the cache.)
+
+ASM_START()
+PROLOGUE(mpn_mul_1)
+C	.callinfo	frame=64,no_calls
+
+	ldo		64(%r30),%r30
+	fldws,ma	4(%r25),%fr5
+	stw		%r23,-16(%r30)		C move s2_limb ...
+	addib,=		-1,%r24,L(just_one_limb)
+	 fldws		-16(%r30),%fr4		C ... into fr4
+	add		%r0,%r0,%r0		C clear carry
+	xmpyu		%fr4,%fr5,%fr6
+	fldws,ma	4(%r25),%fr7
+	fstds		%fr6,-16(%r30)
+	xmpyu		%fr4,%fr7,%fr8
+	ldw		-12(%r30),%r19		C least significant limb in product
+	ldw		-16(%r30),%r28
+
+	fstds		%fr8,-16(%r30)
+	addib,=		-1,%r24,L(end)
+	 ldw		-12(%r30),%r1
+
+C Main loop
+LDEF(loop)
+	fldws,ma	4(%r25),%fr5
+	stws,ma		%r19,4(%r26)
+	addc		%r28,%r1,%r19
+	xmpyu		%fr4,%fr5,%fr6
+	ldw		-16(%r30),%r28
+	fstds		%fr6,-16(%r30)
+	addib,<>	-1,%r24,L(loop)
+	 ldw		-12(%r30),%r1
+
+LDEF(end)
+	stws,ma		%r19,4(%r26)
+	addc		%r28,%r1,%r19
+	ldw		-16(%r30),%r28
+	stws,ma		%r19,4(%r26)
+	addc		%r0,%r28,%r28
+	bv		0(%r2)
+	 ldo		-64(%r30),%r30
+
+LDEF(just_one_limb)
+	xmpyu		%fr4,%fr5,%fr6
+	fstds		%fr6,-16(%r30)
+	ldw		-16(%r30),%r28
+	ldo		-64(%r30),%r30
+	bv		0(%r2)
+	 fstws		%fr6R,0(%r26)
+EPILOGUE()
diff --git a/third_party/gmp/mpn/pa32/hppa1_1/pa7100/add_n.asm b/third_party/gmp/mpn/pa32/hppa1_1/pa7100/add_n.asm
new file mode 100644
index 0000000..b96d403
--- /dev/null
+++ b/third_party/gmp/mpn/pa32/hppa1_1/pa7100/add_n.asm
@@ -0,0 +1,83 @@
+dnl  HP-PA mpn_add_n -- Add two limb vectors of the same length > 0 and store
+dnl  sum in a third limb vector.  Optimized for the PA7100, where is runs at
+dnl  4.25 cycles/limb.
+
+dnl  Copyright 1992, 1994, 2000-2003 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C res_ptr	r26
+C s1_ptr	r25
+C s2_ptr	r24
+C size		r23
+
+ASM_START()
+PROLOGUE(mpn_add_n)
+	ldws,ma		4(0,%r25),%r20
+	ldws,ma		4(0,%r24),%r19
+
+	addib,<=	-5,%r23,L(rest)
+	 add		%r20,%r19,%r28	C add first limbs ignoring cy
+
+LDEF(loop)
+	ldws,ma		4(0,%r25),%r20
+	ldws,ma		4(0,%r24),%r19
+	stws,ma		%r28,4(0,%r26)
+	addc		%r20,%r19,%r28
+	ldws,ma		4(0,%r25),%r20
+	ldws,ma		4(0,%r24),%r19
+	stws,ma		%r28,4(0,%r26)
+	addc		%r20,%r19,%r28
+	ldws,ma		4(0,%r25),%r20
+	ldws,ma		4(0,%r24),%r19
+	stws,ma		%r28,4(0,%r26)
+	addc		%r20,%r19,%r28
+	ldws,ma		4(0,%r25),%r20
+	ldws,ma		4(0,%r24),%r19
+	stws,ma		%r28,4(0,%r26)
+	addib,>		-4,%r23,L(loop)
+	addc		%r20,%r19,%r28
+
+LDEF(rest)
+	addib,=		4,%r23,L(end)
+	nop
+
+LDEF(eloop)
+	ldws,ma		4(0,%r25),%r20
+	ldws,ma		4(0,%r24),%r19
+	stws,ma		%r28,4(0,%r26)
+	addib,>		-1,%r23,L(eloop)
+	addc		%r20,%r19,%r28
+
+LDEF(end)
+	stws		%r28,0(0,%r26)
+	bv		0(%r2)
+	 addc		%r0,%r0,%r28
+EPILOGUE()
diff --git a/third_party/gmp/mpn/pa32/hppa1_1/pa7100/addmul_1.asm b/third_party/gmp/mpn/pa32/hppa1_1/pa7100/addmul_1.asm
new file mode 100644
index 0000000..fb16100
--- /dev/null
+++ b/third_party/gmp/mpn/pa32/hppa1_1/pa7100/addmul_1.asm
@@ -0,0 +1,201 @@
+dnl  HP-PA 7100/7200 mpn_addmul_1 -- Multiply a limb vector with a limb and
+dnl  add the result to a second limb vector.
+
+dnl  Copyright 1995, 2000-2003 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+define(`res_ptr',`%r26')
+define(`s1_ptr',`%r25')
+define(`size_param',`%r24')
+define(`s2_limb',`%r23')
+
+define(`cylimb',`%r28')
+define(`s0',`%r19')
+define(`s1',`%r20')
+define(`s2',`%r3')
+define(`s3',`%r4')
+define(`lo0',`%r21')
+define(`lo1',`%r5')
+define(`lo2',`%r6')
+define(`lo3',`%r7')
+define(`hi0',`%r22')
+define(`hi1',`%r23')				C safe to reuse
+define(`hi2',`%r29')
+define(`hi3',`%r1')
+
+ASM_START()
+PROLOGUE(mpn_addmul_1)
+C	.callinfo	frame=128,no_calls
+
+	ldo	128(%r30),%r30
+	stws	s2_limb,-16(%r30)
+	add	 %r0,%r0,cylimb			C clear cy and cylimb
+	addib,<	-4,size_param,L(few_limbs)
+	fldws	-16(%r30),%fr31R
+
+	ldo	-112(%r30),%r31
+	stw	%r3,-96(%r30)
+	stw	%r4,-92(%r30)
+	stw	%r5,-88(%r30)
+	stw	%r6,-84(%r30)
+	stw	%r7,-80(%r30)
+
+	bb,>=,n	 s1_ptr,29,L(0)
+
+	fldws,ma 4(s1_ptr),%fr4
+	ldws	 0(res_ptr),s0
+	xmpyu	 %fr4,%fr31R,%fr5
+	fstds	 %fr5,-16(%r31)
+	ldws	-16(%r31),cylimb
+	ldws	-12(%r31),lo0
+	add	 s0,lo0,s0
+	addib,< -1,size_param,L(few_limbs)
+	stws,ma	 s0,4(res_ptr)
+
+C start software pipeline ----------------------------------------------------
+LDEF(0)
+	fldds,ma 8(s1_ptr),%fr4
+	fldds,ma 8(s1_ptr),%fr8
+
+	xmpyu	 %fr4L,%fr31R,%fr5
+	xmpyu	 %fr4R,%fr31R,%fr6
+	xmpyu	 %fr8L,%fr31R,%fr9
+	xmpyu	 %fr8R,%fr31R,%fr10
+
+	fstds	 %fr5,-16(%r31)
+	fstds	 %fr6,-8(%r31)
+	fstds	 %fr9,0(%r31)
+	fstds	 %fr10,8(%r31)
+
+	ldws   -16(%r31),hi0
+	ldws   -12(%r31),lo0
+	ldws	-8(%r31),hi1
+	ldws	-4(%r31),lo1
+	ldws	 0(%r31),hi2
+	ldws	 4(%r31),lo2
+	ldws	 8(%r31),hi3
+	ldws	12(%r31),lo3
+
+	addc	 lo0,cylimb,lo0
+	addc	 lo1,hi0,lo1
+	addc	 lo2,hi1,lo2
+	addc	 lo3,hi2,lo3
+
+	addib,<	 -4,size_param,L(end)
+	addc	 %r0,hi3,cylimb			C propagate carry into cylimb
+C main loop ------------------------------------------------------------------
+LDEF(loop)
+	fldds,ma 8(s1_ptr),%fr4
+	fldds,ma 8(s1_ptr),%fr8
+
+	ldws	 0(res_ptr),s0
+	xmpyu	 %fr4L,%fr31R,%fr5
+	ldws	 4(res_ptr),s1
+	xmpyu	 %fr4R,%fr31R,%fr6
+	ldws	 8(res_ptr),s2
+	xmpyu	 %fr8L,%fr31R,%fr9
+	ldws	12(res_ptr),s3
+	xmpyu	 %fr8R,%fr31R,%fr10
+
+	fstds	 %fr5,-16(%r31)
+	add	 s0,lo0,s0
+	fstds	 %fr6,-8(%r31)
+	addc	 s1,lo1,s1
+	fstds	 %fr9,0(%r31)
+	addc	 s2,lo2,s2
+	fstds	 %fr10,8(%r31)
+	addc	 s3,lo3,s3
+
+	ldws   -16(%r31),hi0
+	ldws   -12(%r31),lo0
+	ldws	-8(%r31),hi1
+	ldws	-4(%r31),lo1
+	ldws	 0(%r31),hi2
+	ldws	 4(%r31),lo2
+	ldws	 8(%r31),hi3
+	ldws	12(%r31),lo3
+
+	addc	 lo0,cylimb,lo0
+	stws,ma	 s0,4(res_ptr)
+	addc	 lo1,hi0,lo1
+	stws,ma	 s1,4(res_ptr)
+	addc	 lo2,hi1,lo2
+	stws,ma	 s2,4(res_ptr)
+	addc	 lo3,hi2,lo3
+	stws,ma	 s3,4(res_ptr)
+
+	addib,>= -4,size_param,L(loop)
+	addc	 %r0,hi3,cylimb			C propagate carry into cylimb
+C finish software pipeline ---------------------------------------------------
+LDEF(end)
+	ldws	 0(res_ptr),s0
+	ldws	 4(res_ptr),s1
+	ldws	 8(res_ptr),s2
+	ldws	12(res_ptr),s3
+
+	add	 s0,lo0,s0
+	stws,ma	 s0,4(res_ptr)
+	addc	 s1,lo1,s1
+	stws,ma	 s1,4(res_ptr)
+	addc	 s2,lo2,s2
+	stws,ma	 s2,4(res_ptr)
+	addc	 s3,lo3,s3
+	stws,ma	 s3,4(res_ptr)
+
+C restore callee-saves registers ---------------------------------------------
+	ldw	-96(%r30),%r3
+	ldw	-92(%r30),%r4
+	ldw	-88(%r30),%r5
+	ldw	-84(%r30),%r6
+	ldw	-80(%r30),%r7
+
+LDEF(few_limbs)
+	addib,=,n 4,size_param,L(ret)
+
+LDEF(loop2)
+	fldws,ma 4(s1_ptr),%fr4
+	ldws	 0(res_ptr),s0
+	xmpyu	 %fr4,%fr31R,%fr5
+	fstds	 %fr5,-16(%r30)
+	ldws	-16(%r30),hi0
+	ldws	-12(%r30),lo0
+	addc	 lo0,cylimb,lo0
+	addc	 %r0,hi0,cylimb
+	add	 s0,lo0,s0
+	stws,ma	 s0,4(res_ptr)
+	addib,<> -1,size_param,L(loop2)
+	nop
+
+LDEF(ret)
+	addc	 %r0,cylimb,cylimb
+	bv	 0(%r2)
+	ldo	 -128(%r30),%r30
+EPILOGUE(mpn_addmul_1)
diff --git a/third_party/gmp/mpn/pa32/hppa1_1/pa7100/lshift.asm b/third_party/gmp/mpn/pa32/hppa1_1/pa7100/lshift.asm
new file mode 100644
index 0000000..d65db2a
--- /dev/null
+++ b/third_party/gmp/mpn/pa32/hppa1_1/pa7100/lshift.asm
@@ -0,0 +1,95 @@
+dnl  HP-PA  mpn_lshift -- Shift a number left.
+dnl  Optimized for the PA7100, where is runs at 3.25 cycles/limb.
+
+dnl  Copyright 1992, 1994, 2000-2003 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C res_ptr	r26
+C s_ptr		r25
+C size		r24
+C cnt		r23
+
+ASM_START()
+PROLOGUE(mpn_lshift)
+	sh2add		%r24,%r25,%r25
+	sh2add		%r24,%r26,%r26
+	ldws,mb		-4(0,%r25),%r22
+	subi		32,%r23,%r1
+	mtsar		%r1
+	addib,=		-1,%r24,L(0004)
+	vshd		%r0,%r22,%r28		C compute carry out limb
+	ldws,mb		-4(0,%r25),%r29
+	addib,<=	-5,%r24,L(rest)
+	vshd		%r22,%r29,%r20
+
+LDEF(loop)
+	ldws,mb		-4(0,%r25),%r22
+	stws,mb		%r20,-4(0,%r26)
+	vshd		%r29,%r22,%r20
+	ldws,mb		-4(0,%r25),%r29
+	stws,mb		%r20,-4(0,%r26)
+	vshd		%r22,%r29,%r20
+	ldws,mb		-4(0,%r25),%r22
+	stws,mb		%r20,-4(0,%r26)
+	vshd		%r29,%r22,%r20
+	ldws,mb		-4(0,%r25),%r29
+	stws,mb		%r20,-4(0,%r26)
+	addib,>		-4,%r24,L(loop)
+	vshd		%r22,%r29,%r20
+
+LDEF(rest)
+	addib,=		4,%r24,L(end1)
+	nop
+
+LDEF(eloop)
+	ldws,mb		-4(0,%r25),%r22
+	stws,mb		%r20,-4(0,%r26)
+	addib,<=	-1,%r24,L(end2)
+	vshd		%r29,%r22,%r20
+	ldws,mb		-4(0,%r25),%r29
+	stws,mb		%r20,-4(0,%r26)
+	addib,>		-1,%r24,L(eloop)
+	vshd		%r22,%r29,%r20
+
+LDEF(end1)
+	stws,mb		%r20,-4(0,%r26)
+	vshd		%r29,%r0,%r20
+	bv		0(%r2)
+	stw		%r20,-4(0,%r26)
+
+LDEF(end2)
+	stws,mb		%r20,-4(0,%r26)
+
+LDEF(0004)
+	vshd		%r22,%r0,%r20
+	bv		0(%r2)
+	stw		%r20,-4(0,%r26)
+EPILOGUE()
diff --git a/third_party/gmp/mpn/pa32/hppa1_1/pa7100/rshift.asm b/third_party/gmp/mpn/pa32/hppa1_1/pa7100/rshift.asm
new file mode 100644
index 0000000..f7896fc
--- /dev/null
+++ b/third_party/gmp/mpn/pa32/hppa1_1/pa7100/rshift.asm
@@ -0,0 +1,92 @@
+dnl  HP-PA  mpn_rshift -- Shift a number right.
+dnl  Optimized for the PA7100, where is runs at 3.25 cycles/limb.
+
+dnl  Copyright 1992, 1994, 2000-2003 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C res_ptr	r26
+C s_ptr		r25
+C size		r24
+C cnt		r23
+
+ASM_START()
+PROLOGUE(mpn_rshift)
+	ldws,ma		4(0,%r25),%r22
+	mtsar		%r23
+	addib,=		-1,%r24,L(0004)
+	vshd		%r22,%r0,%r28		C compute carry out limb
+	ldws,ma		4(0,%r25),%r29
+	addib,<=	-5,%r24,L(rest)
+	vshd		%r29,%r22,%r20
+
+LDEF(loop)
+	ldws,ma		4(0,%r25),%r22
+	stws,ma		%r20,4(0,%r26)
+	vshd		%r22,%r29,%r20
+	ldws,ma		4(0,%r25),%r29
+	stws,ma		%r20,4(0,%r26)
+	vshd		%r29,%r22,%r20
+	ldws,ma		4(0,%r25),%r22
+	stws,ma		%r20,4(0,%r26)
+	vshd		%r22,%r29,%r20
+	ldws,ma		4(0,%r25),%r29
+	stws,ma		%r20,4(0,%r26)
+	addib,>		-4,%r24,L(loop)
+	vshd		%r29,%r22,%r20
+
+LDEF(rest)
+	addib,=		4,%r24,L(end1)
+	nop
+
+LDEF(eloop)
+	ldws,ma		4(0,%r25),%r22
+	stws,ma		%r20,4(0,%r26)
+	addib,<=	-1,%r24,L(end2)
+	vshd		%r22,%r29,%r20
+	ldws,ma		4(0,%r25),%r29
+	stws,ma		%r20,4(0,%r26)
+	addib,>		-1,%r24,L(eloop)
+	vshd		%r29,%r22,%r20
+
+LDEF(end1)
+	stws,ma		%r20,4(0,%r26)
+	vshd		%r0,%r29,%r20
+	bv		0(%r2)
+	stw		%r20,0(0,%r26)
+
+LDEF(end2)
+	stws,ma		%r20,4(0,%r26)
+
+LDEF(0004)
+	vshd		%r0,%r22,%r20
+	bv		0(%r2)
+	stw		%r20,0(0,%r26)
+EPILOGUE()
diff --git a/third_party/gmp/mpn/pa32/hppa1_1/pa7100/sub_n.asm b/third_party/gmp/mpn/pa32/hppa1_1/pa7100/sub_n.asm
new file mode 100644
index 0000000..df3f6e8
--- /dev/null
+++ b/third_party/gmp/mpn/pa32/hppa1_1/pa7100/sub_n.asm
@@ -0,0 +1,84 @@
+dnl  HP-PA mpn_sub_n -- Subtract two limb vectors of the same length > 0 and
+dnl  store difference in a third limb vector.  Optimized for the PA7100, where
+dnl  is runs at 4.25 cycles/limb.
+
+dnl  Copyright 1992, 1994, 2000-2003 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C res_ptr	r26
+C s1_ptr	r25
+C s2_ptr	r24
+C size		r23
+
+ASM_START()
+PROLOGUE(mpn_sub_n)
+	ldws,ma		4(0,%r25),%r20
+	ldws,ma		4(0,%r24),%r19
+
+	addib,<=	-5,%r23,L(rest)
+	 sub		%r20,%r19,%r28	C subtract first limbs ignoring cy
+
+LDEF(loop)
+	ldws,ma		4(0,%r25),%r20
+	ldws,ma		4(0,%r24),%r19
+	stws,ma		%r28,4(0,%r26)
+	subb		%r20,%r19,%r28
+	ldws,ma		4(0,%r25),%r20
+	ldws,ma		4(0,%r24),%r19
+	stws,ma		%r28,4(0,%r26)
+	subb		%r20,%r19,%r28
+	ldws,ma		4(0,%r25),%r20
+	ldws,ma		4(0,%r24),%r19
+	stws,ma		%r28,4(0,%r26)
+	subb		%r20,%r19,%r28
+	ldws,ma		4(0,%r25),%r20
+	ldws,ma		4(0,%r24),%r19
+	stws,ma		%r28,4(0,%r26)
+	addib,>		-4,%r23,L(loop)
+	subb		%r20,%r19,%r28
+
+LDEF(rest)
+	addib,=		4,%r23,L(end)
+	nop
+
+LDEF(eloop)
+	ldws,ma		4(0,%r25),%r20
+	ldws,ma		4(0,%r24),%r19
+	stws,ma		%r28,4(0,%r26)
+	addib,>		-1,%r23,L(eloop)
+	subb		%r20,%r19,%r28
+
+LDEF(end)
+	stws		%r28,0(0,%r26)
+	addc		%r0,%r0,%r28
+	bv		0(%r2)
+	 subi		1,%r28,%r28
+EPILOGUE()
diff --git a/third_party/gmp/mpn/pa32/hppa1_1/pa7100/submul_1.asm b/third_party/gmp/mpn/pa32/hppa1_1/pa7100/submul_1.asm
new file mode 100644
index 0000000..5ea08cb
--- /dev/null
+++ b/third_party/gmp/mpn/pa32/hppa1_1/pa7100/submul_1.asm
@@ -0,0 +1,207 @@
+dnl  HP-PA 7100/7200 mpn_submul_1 -- Multiply a limb vector with a limb and
+dnl  subtract the result from a second limb vector.
+
+dnl  Copyright 1995, 2000-2003 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+define(`res_ptr',`%r26')
+define(`s1_ptr',`%r25')
+define(`size_param',`%r24')
+define(`s2_limb',`%r23')
+
+define(`cylimb',`%r28')
+define(`s0',`%r19')
+define(`s1',`%r20')
+define(`s2',`%r3')
+define(`s3',`%r4')
+define(`lo0',`%r21')
+define(`lo1',`%r5')
+define(`lo2',`%r6')
+define(`lo3',`%r7')
+define(`hi0',`%r22')
+define(`hi1',`%r23')				C safe to reuse
+define(`hi2',`%r29')
+define(`hi3',`%r1')
+
+ASM_START()
+PROLOGUE(mpn_submul_1)
+C	.callinfo	frame=128,no_calls
+
+	ldo	128(%r30),%r30
+	stws	s2_limb,-16(%r30)
+	add	 %r0,%r0,cylimb			C clear cy and cylimb
+	addib,<	-4,size_param,L(few_limbs)
+	fldws	-16(%r30),%fr31R
+
+	ldo	-112(%r30),%r31
+	stw	%r3,-96(%r30)
+	stw	%r4,-92(%r30)
+	stw	%r5,-88(%r30)
+	stw	%r6,-84(%r30)
+	stw	%r7,-80(%r30)
+
+	bb,>=,n	 s1_ptr,29,L(0)
+
+	fldws,ma 4(s1_ptr),%fr4
+	ldws	 0(res_ptr),s0
+	xmpyu	 %fr4,%fr31R,%fr5
+	fstds	 %fr5,-16(%r31)
+	ldws	-16(%r31),cylimb
+	ldws	-12(%r31),lo0
+	sub	 s0,lo0,s0
+	add	 s0,lo0,%r0			C invert cy
+	addib,< -1,size_param,L(few_limbs)
+	stws,ma	 s0,4(res_ptr)
+
+C start software pipeline ----------------------------------------------------
+LDEF(0)
+	fldds,ma 8(s1_ptr),%fr4
+	fldds,ma 8(s1_ptr),%fr8
+
+	xmpyu	 %fr4L,%fr31R,%fr5
+	xmpyu	 %fr4R,%fr31R,%fr6
+	xmpyu	 %fr8L,%fr31R,%fr9
+	xmpyu	 %fr8R,%fr31R,%fr10
+
+	fstds	 %fr5,-16(%r31)
+	fstds	 %fr6,-8(%r31)
+	fstds	 %fr9,0(%r31)
+	fstds	 %fr10,8(%r31)
+
+	ldws   -16(%r31),hi0
+	ldws   -12(%r31),lo0
+	ldws	-8(%r31),hi1
+	ldws	-4(%r31),lo1
+	ldws	 0(%r31),hi2
+	ldws	 4(%r31),lo2
+	ldws	 8(%r31),hi3
+	ldws	12(%r31),lo3
+
+	addc	 lo0,cylimb,lo0
+	addc	 lo1,hi0,lo1
+	addc	 lo2,hi1,lo2
+	addc	 lo3,hi2,lo3
+
+	addib,<	 -4,size_param,L(end)
+	addc	 %r0,hi3,cylimb			C propagate carry into cylimb
+C main loop ------------------------------------------------------------------
+LDEF(loop)
+	fldds,ma 8(s1_ptr),%fr4
+	fldds,ma 8(s1_ptr),%fr8
+
+	ldws	 0(res_ptr),s0
+	xmpyu	 %fr4L,%fr31R,%fr5
+	ldws	 4(res_ptr),s1
+	xmpyu	 %fr4R,%fr31R,%fr6
+	ldws	 8(res_ptr),s2
+	xmpyu	 %fr8L,%fr31R,%fr9
+	ldws	12(res_ptr),s3
+	xmpyu	 %fr8R,%fr31R,%fr10
+
+	fstds	 %fr5,-16(%r31)
+	sub	 s0,lo0,s0
+	fstds	 %fr6,-8(%r31)
+	subb	 s1,lo1,s1
+	fstds	 %fr9,0(%r31)
+	subb	 s2,lo2,s2
+	fstds	 %fr10,8(%r31)
+	subb	 s3,lo3,s3
+	subb	 %r0,%r0,lo0			C these two insns ...
+	add	 lo0,lo0,%r0			C ... just invert cy
+
+	ldws   -16(%r31),hi0
+	ldws   -12(%r31),lo0
+	ldws	-8(%r31),hi1
+	ldws	-4(%r31),lo1
+	ldws	 0(%r31),hi2
+	ldws	 4(%r31),lo2
+	ldws	 8(%r31),hi3
+	ldws	12(%r31),lo3
+
+	addc	 lo0,cylimb,lo0
+	stws,ma	 s0,4(res_ptr)
+	addc	 lo1,hi0,lo1
+	stws,ma	 s1,4(res_ptr)
+	addc	 lo2,hi1,lo2
+	stws,ma	 s2,4(res_ptr)
+	addc	 lo3,hi2,lo3
+	stws,ma	 s3,4(res_ptr)
+
+	addib,>= -4,size_param,L(loop)
+	addc	 %r0,hi3,cylimb			C propagate carry into cylimb
+C finish software pipeline ---------------------------------------------------
+LDEF(end)
+	ldws	 0(res_ptr),s0
+	ldws	 4(res_ptr),s1
+	ldws	 8(res_ptr),s2
+	ldws	12(res_ptr),s3
+
+	sub	 s0,lo0,s0
+	stws,ma	 s0,4(res_ptr)
+	subb	 s1,lo1,s1
+	stws,ma	 s1,4(res_ptr)
+	subb	 s2,lo2,s2
+	stws,ma	 s2,4(res_ptr)
+	subb	 s3,lo3,s3
+	stws,ma	 s3,4(res_ptr)
+	subb	 %r0,%r0,lo0			C these two insns ...
+	add	 lo0,lo0,%r0			C ... invert cy
+
+C restore callee-saves registers ---------------------------------------------
+	ldw	-96(%r30),%r3
+	ldw	-92(%r30),%r4
+	ldw	-88(%r30),%r5
+	ldw	-84(%r30),%r6
+	ldw	-80(%r30),%r7
+
+LDEF(few_limbs)
+	addib,=,n 4,size_param,L(ret)
+
+LDEF(loop2)
+	fldws,ma 4(s1_ptr),%fr4
+	ldws	 0(res_ptr),s0
+	xmpyu	 %fr4,%fr31R,%fr5
+	fstds	 %fr5,-16(%r30)
+	ldws	-16(%r30),hi0
+	ldws	-12(%r30),lo0
+	addc	 lo0,cylimb,lo0
+	addc	 %r0,hi0,cylimb
+	sub	 s0,lo0,s0
+	add	 s0,lo0,%r0			C invert cy
+	stws,ma	 s0,4(res_ptr)
+	addib,<> -1,size_param,L(loop2)
+	nop
+
+LDEF(ret)
+	addc	 %r0,cylimb,cylimb
+	bv	 0(%r2)
+	ldo	 -128(%r30),%r30
+EPILOGUE(mpn_submul_1)
diff --git a/third_party/gmp/mpn/pa32/hppa1_1/sqr_diagonal.asm b/third_party/gmp/mpn/pa32/hppa1_1/sqr_diagonal.asm
new file mode 100644
index 0000000..1c7a18e
--- /dev/null
+++ b/third_party/gmp/mpn/pa32/hppa1_1/sqr_diagonal.asm
@@ -0,0 +1,60 @@
+dnl  HP-PA 1.1 32-bit mpn_sqr_diagonal.
+
+dnl  Copyright 2001, 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C This code runs at 6 cycles/limb on the PA7100 and 2.5 cycles/limb on PA8x00.
+C 2-way unrolling wouldn't help the PA7100; it could however bring times down
+C to 2.0 cycles/limb for the PA8x00.
+
+C INPUT PARAMETERS
+define(`rp',`%r26')
+define(`up',`%r25')
+define(`n',`%r24')
+
+ASM_START()
+PROLOGUE(mpn_sqr_diagonal)
+	ldo		4(rp),rp
+	fldws,ma	4(up),%fr4r
+	addib,=		-1,n,L(exit)
+	xmpyu		%fr4r,%fr4r,%fr5
+
+LDEF(loop)
+	fldws,ma	4(up),%fr4r
+	fstws		%fr5r,-4(rp)
+	fstws,ma	%fr5l,8(rp)
+	addib,<>	-1,n,L(loop)
+	xmpyu		%fr4r,%fr4r,%fr5
+
+LDEF(exit)
+	fstws		%fr5r,-4(rp)
+	bv		0(%r2)
+	fstws		%fr5l,0(rp)
+EPILOGUE(mpn_sqr_diagonal)
diff --git a/third_party/gmp/mpn/pa32/hppa1_1/submul_1.asm b/third_party/gmp/mpn/pa32/hppa1_1/submul_1.asm
new file mode 100644
index 0000000..a9b11d2
--- /dev/null
+++ b/third_party/gmp/mpn/pa32/hppa1_1/submul_1.asm
@@ -0,0 +1,115 @@
+dnl  HP-PA 1.1 mpn_submul_1 -- Multiply a limb vector with a limb and subtract
+dnl  the result from a second limb vector.
+
+dnl  Copyright 1992-1994, 2000-2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C res_ptr	r26
+C s1_ptr	r25
+C size		r24
+C s2_limb	r23
+
+C This runs at 12 cycles/limb on a PA7000.  With the used instructions, it can
+C not become faster due to data cache contention after a store.  On the PA7100
+C it runs at 11 cycles/limb.
+
+C There are some ideas described in mul_1.asm that applies to this code too.
+
+C It seems possible to make this run as fast as mpn_addmul_1, if we use
+C	sub,>>=	%r29,%r19,%r22
+C	addi	1,%r28,%r28
+C but that requires reworking the hairy software pipeline...
+
+ASM_START()
+PROLOGUE(mpn_submul_1)
+C	.callinfo	frame=64,no_calls
+
+	ldo		64(%r30),%r30
+	fldws,ma	4(%r25),%fr5
+	stw		%r23,-16(%r30)		C move s2_limb ...
+	addib,=		-1,%r24,L(just_one_limb)
+	 fldws		-16(%r30),%fr4		C ... into fr4
+	add		%r0,%r0,%r0		C clear carry
+	xmpyu		%fr4,%fr5,%fr6
+	fldws,ma	4(%r25),%fr7
+	fstds		%fr6,-16(%r30)
+	xmpyu		%fr4,%fr7,%fr8
+	ldw		-12(%r30),%r19		C least significant limb in product
+	ldw		-16(%r30),%r28
+
+	fstds		%fr8,-16(%r30)
+	addib,=		-1,%r24,L(end)
+	 ldw		-12(%r30),%r1
+
+C Main loop
+LDEF(loop)
+	ldws		0(%r26),%r29
+	fldws,ma	4(%r25),%fr5
+	sub		%r29,%r19,%r22
+	add		%r22,%r19,%r0
+	stws,ma		%r22,4(%r26)
+	addc		%r28,%r1,%r19
+	xmpyu		%fr4,%fr5,%fr6
+	ldw		-16(%r30),%r28
+	fstds		%fr6,-16(%r30)
+	addc		%r0,%r28,%r28
+	addib,<>	-1,%r24,L(loop)
+	 ldw		-12(%r30),%r1
+
+LDEF(end)
+	ldw		0(%r26),%r29
+	sub		%r29,%r19,%r22
+	add		%r22,%r19,%r0
+	stws,ma		%r22,4(%r26)
+	addc		%r28,%r1,%r19
+	ldw		-16(%r30),%r28
+	ldws		0(%r26),%r29
+	addc		%r0,%r28,%r28
+	sub		%r29,%r19,%r22
+	add		%r22,%r19,%r0
+	stws,ma		%r22,4(%r26)
+	addc		%r0,%r28,%r28
+	bv		0(%r2)
+	 ldo		-64(%r30),%r30
+
+LDEF(just_one_limb)
+	xmpyu		%fr4,%fr5,%fr6
+	ldw		0(%r26),%r29
+	fstds		%fr6,-16(%r30)
+	ldw		-12(%r30),%r1
+	ldw		-16(%r30),%r28
+	sub		%r29,%r1,%r22
+	add		%r22,%r1,%r0
+	stw		%r22,0(%r26)
+	addc		%r0,%r28,%r28
+	bv		0(%r2)
+	 ldo		-64(%r30),%r30
+EPILOGUE()
diff --git a/third_party/gmp/mpn/pa32/hppa1_1/udiv.asm b/third_party/gmp/mpn/pa32/hppa1_1/udiv.asm
new file mode 100644
index 0000000..626ecd2
--- /dev/null
+++ b/third_party/gmp/mpn/pa32/hppa1_1/udiv.asm
@@ -0,0 +1,102 @@
+dnl  HP-PA  __udiv_qrnnd division support, used from longlong.h.
+dnl  This version runs fast on PA 7000 and later.
+
+dnl  Copyright 1993, 1994, 2000, 2001, 2003 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C rem_ptr	gr26
+C n1		gr25
+C n0		gr24
+C d		gr23
+
+C This file has caused a lot of trouble, since it demands PIC reference to
+C static data, which triggers bugs in gas (at least version 2.7 through
+C 2.11.2).  When the bug is triggered, many bogus relocs are generated.  The
+C current solution is to stuff data right into the code, and refer it using
+C absolute offsets.  Fragile to be sure, but nothing else seems to work.
+
+ASM_START()
+ifdef(`PIC',`',
+`	RODATA
+	INT64(0000, 0x43f00000, 0x0)	C 2^64
+')
+
+PROLOGUE(mpn_udiv_qrnnd)
+C	.callinfo	frame=64,no_calls
+
+	ldo		64(%r30),%r30
+
+	stws		%r25,-16(0,%r30)	C n_hi
+	stws		%r24,-12(0,%r30)	C n_lo
+
+ifdef(`PIC',
+`	bl		.+20,%r31
+	dep		%r0,31,2,%r31
+	.word	0x0				C padding for alignment
+	.word	0x43f00000, 0x0			C 2^64
+	ldo		4(%r31),%r31',
+`	ldil		`L'%L(0000),%r31
+	ldo		R%L(0000)(%r31),%r31')
+
+	fldds		-16(0,%r30),%fr5
+	stws		%r23,-12(0,%r30)
+	comib,<=	0,%r25,L(1)
+	fcnvxf,dbl,dbl	%fr5,%fr5
+	fldds		0(0,%r31),%fr4
+	fadd,dbl	%fr4,%fr5,%fr5
+
+LDEF(1)
+	fcpy,sgl	%fr0,%fr6L
+	fldws		-12(0,%r30),%fr6R
+	fcnvxf,dbl,dbl	%fr6,%fr4
+
+	fdiv,dbl	%fr5,%fr4,%fr5
+
+	fcnvfx,dbl,dbl	%fr5,%fr4
+	fstws		%fr4R,-16(%r30)
+	xmpyu		%fr4R,%fr6R,%fr6
+	ldws		-16(%r30),%r28
+	fstds		%fr6,-16(0,%r30)
+	ldws		-12(0,%r30),%r21
+	ldws		-16(0,%r30),%r20
+	sub		%r24,%r21,%r22
+	subb		%r25,%r20,%r20
+	comib,=		0,%r20,L(2)
+	ldo		-64(%r30),%r30
+
+	add		%r22,%r23,%r22
+	ldo		-1(%r28),%r28
+
+LDEF(2)
+	bv		0(%r2)
+	stws		%r22,0(0,%r26)
+
+EPILOGUE(mpn_udiv_qrnnd)
diff --git a/third_party/gmp/mpn/pa32/hppa1_1/umul.asm b/third_party/gmp/mpn/pa32/hppa1_1/umul.asm
new file mode 100644
index 0000000..18b923c
--- /dev/null
+++ b/third_party/gmp/mpn/pa32/hppa1_1/umul.asm
@@ -0,0 +1,47 @@
+dnl  Copyright 1999, 2001 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ASM_START()
+PROLOGUE(mpn_umul_ppmm)
+C	.callinfo frame=64,no_calls
+
+	ldo	64(%r30),%r30
+	stw	%r25,-16(0,%r30)
+	fldws	-16(0,%r30),%fr22R
+	stw	%r24,-16(0,%r30)
+	fldws	-16(0,%r30),%fr22L
+	xmpyu	%fr22R,%fr22L,%fr22
+	fstds	%fr22,-16(0,%r30)
+	ldw	-16(0,%r30),%r28
+	ldw	-12(0,%r30),%r29
+	stw	%r29,0(0,%r26)
+	bv	0(%r2)
+	ldo	-64(%r30),%r30
+EPILOGUE()
diff --git a/third_party/gmp/mpn/pa32/hppa2_0/add_n.asm b/third_party/gmp/mpn/pa32/hppa2_0/add_n.asm
new file mode 100644
index 0000000..8d881b8
--- /dev/null
+++ b/third_party/gmp/mpn/pa32/hppa2_0/add_n.asm
@@ -0,0 +1,107 @@
+dnl  HP-PA 2.0 32-bit mpn_add_n -- Add two limb vectors of the same length > 0
+dnl  and store sum in a third limb vector.
+
+dnl  Copyright 1997, 1998, 2000-2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C res_ptr	gr26
+C s1_ptr	gr25
+C s2_ptr	gr24
+C size		gr23
+
+C This runs at 2 cycles/limb on PA8000.
+
+ASM_START()
+PROLOGUE(mpn_add_n)
+	sub		%r0,%r23,%r22
+	zdep		%r22,30,3,%r28		C r28 = 2 * (-n & 7)
+	zdep		%r22,29,3,%r22		C r22 = 4 * (-n & 7)
+	sub		%r25,%r22,%r25		C offset s1_ptr
+	sub		%r24,%r22,%r24		C offset s2_ptr
+	sub		%r26,%r22,%r26		C offset res_ptr
+	blr		%r28,%r0		C branch into loop
+	add		%r0,%r0,%r0		C reset carry
+
+LDEF(loop)
+	ldw		0(%r25),%r20
+	ldw		0(%r24),%r31
+	addc		%r20,%r31,%r20
+	stw		%r20,0(%r26)
+
+LDEF(7)
+	ldw		4(%r25),%r21
+	ldw		4(%r24),%r19
+	addc		%r21,%r19,%r21
+	stw		%r21,4(%r26)
+
+LDEF(6)
+	ldw		8(%r25),%r20
+	ldw		8(%r24),%r31
+	addc		%r20,%r31,%r20
+	stw		%r20,8(%r26)
+
+LDEF(5)
+	ldw		12(%r25),%r21
+	ldw		12(%r24),%r19
+	addc		%r21,%r19,%r21
+	stw		%r21,12(%r26)
+
+LDEF(4)
+	ldw		16(%r25),%r20
+	ldw		16(%r24),%r31
+	addc		%r20,%r31,%r20
+	stw		%r20,16(%r26)
+
+LDEF(3)
+	ldw		20(%r25),%r21
+	ldw		20(%r24),%r19
+	addc		%r21,%r19,%r21
+	stw		%r21,20(%r26)
+
+LDEF(2)
+	ldw		24(%r25),%r20
+	ldw		24(%r24),%r31
+	addc		%r20,%r31,%r20
+	stw		%r20,24(%r26)
+
+LDEF(1)
+	ldw		28(%r25),%r21
+	ldo		32(%r25),%r25
+	ldw		28(%r24),%r19
+	addc		%r21,%r19,%r21
+	stw		%r21,28(%r26)
+	ldo		32(%r24),%r24
+	addib,>		-8,%r23,L(loop)
+	ldo		32(%r26),%r26
+
+	bv		(%r2)
+	addc		%r0,%r0,%r28
+EPILOGUE()
diff --git a/third_party/gmp/mpn/pa32/hppa2_0/gmp-mparam.h b/third_party/gmp/mpn/pa32/hppa2_0/gmp-mparam.h
new file mode 100644
index 0000000..6016274
--- /dev/null
+++ b/third_party/gmp/mpn/pa32/hppa2_0/gmp-mparam.h
@@ -0,0 +1,167 @@
+/* gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 1999-2002, 2009, 2010 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+/* 552 MHz PA8600 (gcc61.fsffrance.org) */
+
+#define DIVREM_1_NORM_THRESHOLD              3
+#define DIVREM_1_UNNORM_THRESHOLD            3
+#define MOD_1_NORM_THRESHOLD                 3
+#define MOD_1_UNNORM_THRESHOLD               4
+#define MOD_1N_TO_MOD_1_1_THRESHOLD         11
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          8
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD         0  /* never mpn_mod_1_1p */
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        22
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     28
+#define USE_PREINV_DIVREM_1                  1
+#define DIVEXACT_1_THRESHOLD                 0  /* always */
+#define BMOD_1_TO_MOD_1_THRESHOLD           36
+
+#define MUL_TOOM22_THRESHOLD                18
+#define MUL_TOOM33_THRESHOLD                65
+#define MUL_TOOM44_THRESHOLD               166
+#define MUL_TOOM6H_THRESHOLD               202
+#define MUL_TOOM8H_THRESHOLD               333
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD     105
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     138
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     105
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     102
+
+#define SQR_BASECASE_THRESHOLD               7
+#define SQR_TOOM2_THRESHOLD                 55
+#define SQR_TOOM3_THRESHOLD                 93
+#define SQR_TOOM4_THRESHOLD                250
+#define SQR_TOOM6_THRESHOLD                306
+#define SQR_TOOM8_THRESHOLD                527
+
+#define MULMOD_BNM1_THRESHOLD               13
+#define SQRMOD_BNM1_THRESHOLD               15
+
+#define MUL_FFT_MODF_THRESHOLD             244  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    244, 5}, {      8, 4}, {     17, 5}, {     13, 6}, \
+    {      7, 5}, {     17, 6}, {      9, 5}, {     19, 6}, \
+    {     13, 7}, {      7, 6}, {     17, 7}, {      9, 6}, \
+    {     19, 7}, {     11, 6}, {     24, 7}, {     13, 8}, \
+    {      7, 7}, {     19, 8}, {     11, 7}, {     25, 8}, \
+    {     15, 7}, {     33, 8}, {     23, 9}, {     15, 8}, \
+    {     39, 9}, {     23,10}, {     15, 9}, {     31, 8}, \
+    {     67, 9}, {     39, 8}, {     79, 9}, {     47,10}, \
+    {     31, 9}, {     71, 8}, {    143, 9}, {     79,10}, \
+    {     47,11}, {     31,10}, {     63, 9}, {    127, 8}, \
+    {    255, 9}, {    135, 8}, {    271, 9}, {    143,10}, \
+    {     79, 9}, {    159, 8}, {    319, 9}, {    175, 8}, \
+    {    351,10}, {     95, 9}, {    191, 8}, {    383, 9}, \
+    {    207,11}, {     63,10}, {    127, 9}, {    255, 8}, \
+    {    511, 9}, {    271,10}, {    143, 9}, {    287, 8}, \
+    {    575,10}, {    159, 9}, {    319,10}, {    175, 9}, \
+    {    351,11}, {     95,10}, {    191, 9}, {    383,10}, \
+    {    207, 9}, {    415,12}, {     63,11}, {    127,10}, \
+    {    255, 9}, {    511,10}, {    271, 9}, {    543, 8}, \
+    {   1087,10}, {    287, 9}, {    575,10}, {    303,11}, \
+    {    159,10}, {    351, 9}, {    703, 8}, {   1407,11}, \
+    {    191,10}, {    415, 9}, {    831,11}, {    223, 9}, \
+    {    895,10}, {    479,12}, {    127,11}, {    255,10}, \
+    {    543, 9}, {   1087,11}, {    287,10}, {    607, 9}, \
+    {   1215,11}, {    351,10}, {    703, 9}, {   1407,12}, \
+    {    191,11}, {    415,10}, {    831,11}, {    479,13}, \
+    {   8192,14}, {  16384,15}, {  32768,16} }
+#define MUL_FFT_TABLE3_SIZE 107
+#define MUL_FFT_THRESHOLD                 2112
+
+#define SQR_FFT_MODF_THRESHOLD             240  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    240, 5}, {      8, 4}, {     17, 5}, {     19, 6}, \
+    {     17, 7}, {      9, 6}, {     20, 7}, {     11, 6}, \
+    {     23, 7}, {     13, 8}, {      7, 7}, {     19, 8}, \
+    {     11, 7}, {     25, 8}, {     15, 7}, {     33, 8}, \
+    {     19, 7}, {     39, 8}, {     23, 9}, {     15, 8}, \
+    {     39, 9}, {     23,10}, {     15, 9}, {     31, 8}, \
+    {     63, 9}, {     47,10}, {     31, 9}, {     63, 8}, \
+    {    127, 9}, {     71, 8}, {    143, 9}, {     79,10}, \
+    {     47,11}, {     31,10}, {     63, 9}, {    127, 8}, \
+    {    255, 7}, {    511, 9}, {    135, 8}, {    271, 9}, \
+    {    143,10}, {     79, 9}, {    159, 8}, {    319, 9}, \
+    {    175, 8}, {    351, 7}, {    703,10}, {     95, 9}, \
+    {    191, 8}, {    383, 9}, {    207,11}, {     63,10}, \
+    {    127, 9}, {    255, 8}, {    511, 9}, {    271,10}, \
+    {    143, 9}, {    287, 8}, {    575,10}, {    159, 9}, \
+    {    319,10}, {    175, 9}, {    351, 8}, {    703,11}, \
+    {     95,10}, {    191, 9}, {    383,10}, {    207, 9}, \
+    {    415,12}, {     63,11}, {    127,10}, {    255, 9}, \
+    {    511,10}, {    271, 9}, {    543, 8}, {   1087,10}, \
+    {    287, 9}, {    575,11}, {    159,10}, {    319, 9}, \
+    {    639,10}, {    351, 9}, {    703, 8}, {   1407,11}, \
+    {    191,10}, {    415, 9}, {    831,11}, {    223, 8}, \
+    {   1791,10}, {    479, 9}, {    959,12}, {    127,11}, \
+    {    255,10}, {    543,11}, {    287,10}, {    607,11}, \
+    {    319,10}, {    639,11}, {    351,10}, {    703, 9}, \
+    {   1407,12}, {    191,11}, {    415,10}, {    831,11}, \
+    {    479,10}, {    959,13}, {   8192,14}, {  16384,15}, \
+    {  32768,16} }
+#define SQR_FFT_TABLE3_SIZE 109
+#define SQR_FFT_THRESHOLD                 1600
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                 116
+#define MULLO_MUL_N_THRESHOLD             3574
+
+#define DC_DIV_QR_THRESHOLD                100
+#define DC_DIVAPPR_Q_THRESHOLD             348
+#define DC_BDIV_QR_THRESHOLD               109
+#define DC_BDIV_Q_THRESHOLD                254
+
+#define INV_MULMOD_BNM1_THRESHOLD           34
+#define INV_NEWTON_THRESHOLD               276
+#define INV_APPR_THRESHOLD                 276
+
+#define BINV_NEWTON_THRESHOLD              278
+#define REDC_1_TO_REDC_N_THRESHOLD          78
+
+#define MU_DIV_QR_THRESHOLD                979
+#define MU_DIVAPPR_Q_THRESHOLD             263
+#define MUPI_DIV_QR_THRESHOLD              102
+#define MU_BDIV_QR_THRESHOLD               807
+#define MU_BDIV_Q_THRESHOLD               1187
+
+#define MATRIX22_STRASSEN_THRESHOLD         11
+#define HGCD_THRESHOLD                     100
+#define GCD_DC_THRESHOLD                   379
+#define GCDEXT_DC_THRESHOLD                249
+#define JACOBI_BASE_METHOD                   2
+
+#define GET_STR_DC_THRESHOLD                 7
+#define GET_STR_PRECOMPUTE_THRESHOLD        16
+#define SET_STR_DC_THRESHOLD               270
+#define SET_STR_PRECOMPUTE_THRESHOLD       782
diff --git a/third_party/gmp/mpn/pa32/hppa2_0/sqr_diagonal.asm b/third_party/gmp/mpn/pa32/hppa2_0/sqr_diagonal.asm
new file mode 100644
index 0000000..c55112f
--- /dev/null
+++ b/third_party/gmp/mpn/pa32/hppa2_0/sqr_diagonal.asm
@@ -0,0 +1,112 @@
+dnl  HP-PA 32-bit mpn_sqr_diagonal optimized for the PA8x00.
+
+dnl  Copyright 2001, 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C This code runs at 6 cycles/limb on the PA7100 and 2 cycles/limb on PA8x00.
+C The 2-way unrolling is actually not helping the PA7100.
+
+C INPUT PARAMETERS
+define(`rp',`%r26')
+define(`up',`%r25')
+define(`n',`%r24')
+
+ASM_START()
+PROLOGUE(mpn_sqr_diagonal)
+
+	fldws,ma	4(up),%fr4r
+	addib,=		-1,n,L(end1)
+	ldo		4(rp),rp
+
+	fldws,ma	4(up),%fr6r
+	addib,=		-1,n,L(end2)
+	xmpyu		%fr4r,%fr4r,%fr5
+
+	fldws,ma	4(up),%fr4r
+	addib,=		-1,n,L(end3)
+	xmpyu		%fr6r,%fr6r,%fr7
+
+
+LDEF(loop)
+	fldws,ma	4(up),%fr6r
+	fstws		%fr5r,-4(rp)
+	fstws,ma	%fr5l,8(rp)
+	addib,=		-1,n,L(exite)
+	xmpyu		%fr4r,%fr4r,%fr5
+	fldws,ma	4(up),%fr4r
+	fstws		%fr7r,-4(rp)
+	fstws,ma	%fr7l,8(rp)
+	addib,<>	-1,n,L(loop)
+	xmpyu		%fr6r,%fr6r,%fr7
+
+LDEF(exito)
+	fstws		%fr5r,-4(rp)
+	fstws		%fr5l,0(rp)
+	xmpyu		%fr4r,%fr4r,%fr5
+	fstws		%fr7r,4(rp)
+	fstws		%fr7l,8(rp)
+	fstws,mb	%fr5r,12(rp)
+	bv		0(%r2)
+	fstws		%fr5l,4(rp)
+
+LDEF(exite)
+	fstws		%fr7r,-4(rp)
+	fstws		%fr7l,0(rp)
+	xmpyu		%fr6r,%fr6r,%fr7
+	fstws		%fr5r,4(rp)
+	fstws		%fr5l,8(rp)
+	fstws,mb	%fr7r,12(rp)
+	bv		0(%r2)
+	fstws		%fr7l,4(rp)
+
+LDEF(end1)
+	xmpyu		%fr4r,%fr4r,%fr5
+	fstws		%fr5r,-4(rp)
+	bv		0(%r2)
+	fstws,ma	%fr5l,8(rp)
+
+LDEF(end2)
+	xmpyu		%fr6r,%fr6r,%fr7
+	fstws		%fr5r,-4(rp)
+	fstws		%fr5l,0(rp)
+	fstws		%fr7r,4(rp)
+	bv		0(%r2)
+	fstws		%fr7l,8(rp)
+
+LDEF(end3)
+	fstws		%fr5r,-4(rp)
+	fstws		%fr5l,0(rp)
+	xmpyu		%fr4r,%fr4r,%fr5
+	fstws		%fr7r,4(rp)
+	fstws		%fr7l,8(rp)
+	fstws,mb	%fr5r,12(rp)
+	bv		0(%r2)
+	fstws		%fr5l,4(rp)
+EPILOGUE(mpn_sqr_diagonal)
diff --git a/third_party/gmp/mpn/pa32/hppa2_0/sub_n.asm b/third_party/gmp/mpn/pa32/hppa2_0/sub_n.asm
new file mode 100644
index 0000000..47b3163
--- /dev/null
+++ b/third_party/gmp/mpn/pa32/hppa2_0/sub_n.asm
@@ -0,0 +1,107 @@
+dnl  HP-PA 2.0 32-bit mpn_sub_n -- Subtract two limb vectors of the same
+dnl  length > 0 and store difference in a third limb vector.
+
+dnl  Copyright 1997, 1998, 2000-2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C res_ptr	gr26
+C s1_ptr	gr25
+C s2_ptr	gr24
+C size		gr23
+
+C This runs at 2 cycles/limb on PA8000.
+
+ASM_START()
+PROLOGUE(mpn_sub_n)
+	sub		%r0,%r23,%r22
+	zdep		%r22,30,3,%r28		C r28 = 2 * (-n & 7)
+	zdep		%r22,29,3,%r22		C r22 = 4 * (-n & 7)
+	sub		%r25,%r22,%r25		C offset s1_ptr
+	sub		%r24,%r22,%r24		C offset s2_ptr
+	blr		%r28,%r0		C branch into loop
+	sub		%r26,%r22,%r26		C offset res_ptr and set carry
+
+LDEF(loop)
+	ldw		0(%r25),%r20
+	ldw		0(%r24),%r31
+	subb		%r20,%r31,%r20
+	stw		%r20,0(%r26)
+
+LDEF(7)
+	ldw		4(%r25),%r21
+	ldw		4(%r24),%r19
+	subb		%r21,%r19,%r21
+	stw		%r21,4(%r26)
+
+LDEF(6)
+	ldw		8(%r25),%r20
+	ldw		8(%r24),%r31
+	subb		%r20,%r31,%r20
+	stw		%r20,8(%r26)
+
+LDEF(5)
+	ldw		12(%r25),%r21
+	ldw		12(%r24),%r19
+	subb		%r21,%r19,%r21
+	stw		%r21,12(%r26)
+
+LDEF(4)
+	ldw		16(%r25),%r20
+	ldw		16(%r24),%r31
+	subb		%r20,%r31,%r20
+	stw		%r20,16(%r26)
+
+LDEF(3)
+	ldw		20(%r25),%r21
+	ldw		20(%r24),%r19
+	subb		%r21,%r19,%r21
+	stw		%r21,20(%r26)
+
+LDEF(2)
+	ldw		24(%r25),%r20
+	ldw		24(%r24),%r31
+	subb		%r20,%r31,%r20
+	stw		%r20,24(%r26)
+
+LDEF(1)
+	ldw		28(%r25),%r21
+	ldo		32(%r25),%r25
+	ldw		28(%r24),%r19
+	subb		%r21,%r19,%r21
+	stw		%r21,28(%r26)
+	ldo		32(%r24),%r24
+	addib,>		-8,%r23,L(loop)
+	ldo		32(%r26),%r26
+
+	addc		%r0,%r0,%r28
+	bv		(%r2)
+	subi		1,%r28,%r28
+EPILOGUE()
diff --git a/third_party/gmp/mpn/pa32/lshift.asm b/third_party/gmp/mpn/pa32/lshift.asm
new file mode 100644
index 0000000..5ea497c
--- /dev/null
+++ b/third_party/gmp/mpn/pa32/lshift.asm
@@ -0,0 +1,75 @@
+dnl  HP-PA  mpn_lshift -- Shift a number left.
+
+dnl  Copyright 1992, 1994, 2000-2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C res_ptr	gr26
+C s_ptr		gr25
+C size		gr24
+C cnt		gr23
+
+ASM_START()
+PROLOGUE(mpn_lshift)
+	sh2add		%r24,%r25,%r25
+	sh2add		%r24,%r26,%r26
+	ldws,mb		-4(0,%r25),%r22
+	subi		32,%r23,%r1
+	mtsar		%r1
+	addib,=		-1,%r24,L(0004)
+	vshd		%r0,%r22,%r28		C compute carry out limb
+	ldws,mb		-4(0,%r25),%r29
+	addib,=		-1,%r24,L(0002)
+	vshd		%r22,%r29,%r20
+
+LDEF(loop)
+	ldws,mb		-4(0,%r25),%r22
+	stws,mb		%r20,-4(0,%r26)
+	addib,=		-1,%r24,L(0003)
+	vshd		%r29,%r22,%r20
+	ldws,mb		-4(0,%r25),%r29
+	stws,mb		%r20,-4(0,%r26)
+	addib,<>	-1,%r24,L(loop)
+	vshd		%r22,%r29,%r20
+
+LDEF(0002)
+	stws,mb		%r20,-4(0,%r26)
+	vshd		%r29,%r0,%r20
+	bv		0(%r2)
+	stw		%r20,-4(0,%r26)
+
+LDEF(0003)
+	stws,mb		%r20,-4(0,%r26)
+
+LDEF(0004)
+	vshd		%r22,%r0,%r20
+	bv		0(%r2)
+	stw		%r20,-4(0,%r26)
+EPILOGUE()
diff --git a/third_party/gmp/mpn/pa32/pa-defs.m4 b/third_party/gmp/mpn/pa32/pa-defs.m4
new file mode 100644
index 0000000..b26e715
--- /dev/null
+++ b/third_party/gmp/mpn/pa32/pa-defs.m4
@@ -0,0 +1,64 @@
+divert(-1)
+
+dnl  m4 macros for HPPA assembler.
+
+dnl  Copyright 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+dnl  hppa assembler comments are introduced with ";".
+dnl
+dnl  For cooperation with cpp, apparently lines "# 123" set the line number,
+dnl  and other lines starting with a "#" are ignored.
+
+changecom(;)
+
+
+dnl  Called: PROLOGUE_cpu(GSYM_PREFIX`'foo)
+dnl          EPILOGUE_cpu(GSYM_PREFIX`'foo)
+dnl
+dnl  These are the same as the basic PROLOGUE_cpu and EPILOGUE_cpu in
+dnl  mpn/asm-defs.m4, but using .proc / .procend.  These are standard and on
+dnl  an ELF system they do what .type and .size normally do.
+
+define(`PROLOGUE_cpu',
+m4_assert_numargs(1)
+	`.code
+	ALIGN(8)
+	.export	`$1',entry
+`$1'LABEL_SUFFIX'
+	.proc
+	.callinfo)	dnl  This is really bogus, but allows us to compile
+			dnl  again on hppa machines.
+
+
+define(`EPILOGUE_cpu',
+m4_assert_numargs(1)
+`	.procend')
+
+divert
diff --git a/third_party/gmp/mpn/pa32/rshift.asm b/third_party/gmp/mpn/pa32/rshift.asm
new file mode 100644
index 0000000..c5eac83
--- /dev/null
+++ b/third_party/gmp/mpn/pa32/rshift.asm
@@ -0,0 +1,72 @@
+dnl  HP-PA  mpn_rshift -- Shift a number right.
+
+dnl  Copyright 1992, 1994, 2000-2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C res_ptr	gr26
+C s_ptr		gr25
+C size		gr24
+C cnt		gr23
+
+ASM_START()
+PROLOGUE(mpn_rshift)
+	ldws,ma		4(0,%r25),%r22
+	mtsar		%r23
+	addib,=		-1,%r24,L(0004)
+	vshd		%r22,%r0,%r28		C compute carry out limb
+	ldws,ma		4(0,%r25),%r29
+	addib,=		-1,%r24,L(0002)
+	vshd		%r29,%r22,%r20
+
+LDEF(loop)
+	ldws,ma		4(0,%r25),%r22
+	stws,ma		%r20,4(0,%r26)
+	addib,=		-1,%r24,L(0003)
+	vshd		%r22,%r29,%r20
+	ldws,ma		4(0,%r25),%r29
+	stws,ma		%r20,4(0,%r26)
+	addib,<>	-1,%r24,L(loop)
+	vshd		%r29,%r22,%r20
+
+LDEF(0002)
+	stws,ma		%r20,4(0,%r26)
+	vshd		%r0,%r29,%r20
+	bv		0(%r2)
+	stw		%r20,0(0,%r26)
+
+LDEF(0003)
+	stws,ma		%r20,4(0,%r26)
+
+LDEF(0004)
+	vshd		%r0,%r22,%r20
+	bv		0(%r2)
+	stw		%r20,0(0,%r26)
+EPILOGUE()
diff --git a/third_party/gmp/mpn/pa32/sub_n.asm b/third_party/gmp/mpn/pa32/sub_n.asm
new file mode 100644
index 0000000..9c71655
--- /dev/null
+++ b/third_party/gmp/mpn/pa32/sub_n.asm
@@ -0,0 +1,64 @@
+dnl  HP-PA mpn_sub_n -- Subtract two limb vectors of the same length > 0 and
+dnl  store difference in a third limb vector.
+
+dnl  Copyright 1992, 1994, 2000-2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C res_ptr	gr26
+C s1_ptr	gr25
+C s2_ptr	gr24
+C size		gr23
+
+C One might want to unroll this as for other processors, but it turns out that
+C the data cache contention after a store makes such unrolling useless.  We
+C can't come under 5 cycles/limb anyway.
+
+ASM_START()
+PROLOGUE(mpn_sub_n)
+	ldws,ma		4(0,%r25),%r20
+	ldws,ma		4(0,%r24),%r19
+
+	addib,=		-1,%r23,L(end)	C check for (SIZE == 1)
+	 sub		%r20,%r19,%r28	C subtract first limbs ignoring cy
+
+LDEF(loop)
+	ldws,ma		4(0,%r25),%r20
+	ldws,ma		4(0,%r24),%r19
+	stws,ma		%r28,4(0,%r26)
+	addib,<>	-1,%r23,L(loop)
+	 subb		%r20,%r19,%r28
+
+LDEF(end)
+	stws		%r28,0(0,%r26)
+	addc		%r0,%r0,%r28
+	bv		0(%r2)
+	 subi		1,%r28,%r28
+EPILOGUE()
diff --git a/third_party/gmp/mpn/pa32/udiv.asm b/third_party/gmp/mpn/pa32/udiv.asm
new file mode 100644
index 0000000..addbf41
--- /dev/null
+++ b/third_party/gmp/mpn/pa32/udiv.asm
@@ -0,0 +1,291 @@
+dnl  HP-PA  __udiv_qrnnd division support, used from longlong.h.
+dnl  This version runs fast on pre-PA7000 CPUs.
+
+dnl  Copyright 1993, 1994, 2000-2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C rem_ptr	gr26
+C n1		gr25
+C n0		gr24
+C d		gr23
+
+C The code size is a bit excessive.  We could merge the last two ds;addc
+C sequences by simply moving the "bb,< Odd" instruction down.  The only
+C trouble is the FFFFFFFF code that would need some hacking.
+
+ASM_START()
+PROLOGUE(mpn_udiv_qrnnd)
+	comb,<		%r23,0,L(largedivisor)
+	 sub		%r0,%r23,%r1		C clear cy as side-effect
+	ds		%r0,%r1,%r0
+	addc		%r24,%r24,%r24
+	ds		%r25,%r23,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r23,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r23,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r23,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r23,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r23,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r23,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r23,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r23,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r23,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r23,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r23,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r23,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r23,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r23,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r23,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r23,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r23,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r23,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r23,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r23,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r23,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r23,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r23,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r23,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r23,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r23,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r23,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r23,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r23,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r23,%r25
+	addc		%r24,%r24,%r28
+	ds		%r25,%r23,%r25
+	comclr,>=	%r25,%r0,%r0
+	addl		%r25,%r23,%r25
+	stws		%r25,0(0,%r26)
+	bv		0(%r2)
+	 addc		%r28,%r28,%r28
+
+LDEF(largedivisor)
+	extru		%r24,31,1,%r19		C r19 = n0 & 1
+	bb,<		%r23,31,L(odd)
+	 extru		%r23,30,31,%r22		C r22 = d >> 1
+	shd		%r25,%r24,1,%r24	C r24 = new n0
+	extru		%r25,30,31,%r25		C r25 = new n1
+	sub		%r0,%r22,%r21
+	ds		%r0,%r21,%r0
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	comclr,>=	%r25,%r0,%r0
+	addl		%r25,%r22,%r25
+	sh1addl		%r25,%r19,%r25
+	stws		%r25,0(0,%r26)
+	bv		0(%r2)
+	 addc		%r24,%r24,%r28
+
+LDEF(odd)
+	addib,sv,n	1,%r22,L(FFFFFFFF)	C r22 = (d / 2 + 1)
+	shd		%r25,%r24,1,%r24	C r24 = new n0
+	extru		%r25,30,31,%r25		C r25 = new n1
+	sub		%r0,%r22,%r21
+	ds		%r0,%r21,%r0
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r24
+	ds		%r25,%r22,%r25
+	addc		%r24,%r24,%r28
+	comclr,>=	%r25,%r0,%r0
+	addl		%r25,%r22,%r25
+	sh1addl		%r25,%r19,%r25
+C We have computed (n1,,n0) / (d + 1), q' = r28, r' = r25
+	add,nuv		%r28,%r25,%r25
+	addl		%r25,%r1,%r25
+	addc		%r0,%r28,%r28
+	sub,<<		%r25,%r23,%r0
+	addl		%r25,%r1,%r25
+	stws		%r25,0(0,%r26)
+	bv		0(%r2)
+	 addc		%r0,%r28,%r28
+
+C This is just a special case of the code above.
+C We come here when d == 0xFFFFFFFF
+LDEF(FFFFFFFF)
+	add,uv		%r25,%r24,%r24
+	sub,<<		%r24,%r23,%r0
+	ldo		1(%r24),%r24
+	stws		%r24,0(0,%r26)
+	bv		0(%r2)
+	 addc		%r0,%r25,%r28
+EPILOGUE()
diff --git a/third_party/gmp/mpn/pa64/README b/third_party/gmp/mpn/pa64/README
new file mode 100644
index 0000000..a51ce02
--- /dev/null
+++ b/third_party/gmp/mpn/pa64/README
@@ -0,0 +1,78 @@
+Copyright 1999, 2001, 2002, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.
+
+
+
+
+This directory contains mpn functions for 64-bit PA-RISC 2.0.
+
+PIPELINE SUMMARY
+
+The PA8x00 processors have an orthogonal 4-way out-of-order pipeline.  Each
+cycle two ALU operations and two MEM operations can issue, but just one of the
+MEM operations may be a store.  The two ALU operations can be almost any
+combination of non-memory operations.  Unlike every other processor, integer
+and fp operations are completely equal here; they both count as just ALU
+operations.
+
+Unfortunately, some operations cause hickups in the pipeline.  Combining
+carry-consuming operations like ADD,DC with operations that does not set carry
+like ADD,L cause long delays.  Skip operations also seem to cause hickups.  If
+several ADD,DC are issued consecutively, or if plain carry-generating ADD feed
+ADD,DC, stalling does not occur.  We can effectively issue two ADD,DC
+operations/cycle.
+
+Latency scheduling is not as important as making sure to have a mix of ALU and
+MEM operations, but for full pipeline utilization, it is still a good idea to
+do some amount of latency scheduling.
+
+Like for all other processors, RAW memory scheduling is critically important.
+Since integer multiplication takes place in the floating-point unit, the GMP
+code needs to handle this problem frequently.
+
+STATUS
+
+* mpn_lshift and mpn_rshift run at 1.5 cycles/limb on PA8000 and at 1.0
+  cycles/limb on PA8500.  With latency scheduling, the numbers could
+  probably be improved to 1.0 cycles/limb for all PA8x00 chips.
+
+* mpn_add_n and mpn_sub_n run at 2.0 cycles/limb on PA8000 and at about
+  1.6875 cycles/limb on PA8500.  With latency scheduling, this could
+  probably be improved to get close to 1.5 cycles/limb.  A problem is the
+  stalling of carry-inputting instructions after instructions that do not
+  write to carry.
+
+* mpn_mul_1, mpn_addmul_1, and mpn_submul_1 run at between 5.625 and 6.375
+  on PA8500 and later, and about a cycle/limb slower on older chips.  The
+  code uses ADD,DC for adjacent limbs, and relies heavily on reordering.
+
+
+REFERENCES
+
+Hewlett Packard, "64-Bit Runtime Architecture for PA-RISC 2.0", version 3.3,
+October 1997.
diff --git a/third_party/gmp/mpn/pa64/addmul_1.asm b/third_party/gmp/mpn/pa64/addmul_1.asm
new file mode 100644
index 0000000..2cb9af9
--- /dev/null
+++ b/third_party/gmp/mpn/pa64/addmul_1.asm
@@ -0,0 +1,693 @@
+dnl  HP-PA 2.0 64-bit mpn_addmul_1 -- Multiply a limb vector with a limb and
+dnl  add the result to a second limb vector.
+
+dnl  Copyright 1998-2000, 2002, 2003 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		    cycles/limb
+C 8000,8200:		7
+C 8500,8600,8700:	6.375
+
+C  The feed-in and wind-down code has not yet been scheduled.  Many cycles
+C  could be saved there per call.
+
+C  DESCRIPTION:
+C  The main loop "BIG" is 4-way unrolled, mainly to allow
+C  effective use of ADD,DC.  Delays in moving data via the cache from the FP
+C  registers to the IU registers, have demanded a deep software pipeline, and
+C  a lot of stack slots for partial products in flight.
+C
+C  CODE STRUCTURE:
+C  save-some-registers
+C  do 0, 1, 2, or 3 limbs
+C  if done, restore-some-regs and return
+C  save-many-regs
+C  do 4, 8, ... limb
+C  restore-all-regs
+
+C  STACK LAYOUT:
+C  HP-PA stack grows upwards.  We could allocate 8 fewer slots by using the
+C  slots marked FREE, as well as some slots in the caller's "frame marker".
+C
+C -00 <- r30
+C -08  FREE
+C -10  tmp
+C -18  tmp
+C -20  tmp
+C -28  tmp
+C -30  tmp
+C -38  tmp
+C -40  tmp
+C -48  tmp
+C -50  tmp
+C -58  tmp
+C -60  tmp
+C -68  tmp
+C -70  tmp
+C -78  tmp
+C -80  tmp
+C -88  tmp
+C -90  FREE
+C -98  FREE
+C -a0  FREE
+C -a8  FREE
+C -b0  r13
+C -b8  r12
+C -c0  r11
+C -c8  r10
+C -d0  r8
+C -d8  r8
+C -e0  r7
+C -e8  r6
+C -f0  r5
+C -f8  r4
+C -100 r3
+C  Previous frame:
+C  [unused area]
+C -38/-138 vlimb home slot.  For 2.0N, the vlimb arg will arrive here.
+
+
+include(`../config.m4')
+
+C INPUT PARAMETERS:
+define(`rp',`%r26')	C
+define(`up',`%r25')	C
+define(`n',`%r24')	C
+define(`vlimb',`%r23')	C
+
+define(`climb',`%r23')	C
+
+ifdef(`HAVE_ABI_2_0w',
+`	.level	2.0w
+',`	.level	2.0
+')
+PROLOGUE(mpn_addmul_1)
+
+ifdef(`HAVE_ABI_2_0w',
+`	std		vlimb, -0x38(%r30)	C store vlimb into "home" slot
+')
+	std,ma		%r3, 0x100(%r30)
+	std		%r4, -0xf8(%r30)
+	std		%r5, -0xf0(%r30)
+	ldo		0(%r0), climb		C clear climb
+	fldd		-0x138(%r30), %fr8	C put vlimb in fp register
+
+define(`p032a1',`%r1')	C
+define(`p032a2',`%r19')	C
+
+define(`m032',`%r20')	C
+define(`m096',`%r21')	C
+
+define(`p000a',`%r22')	C
+define(`p064a',`%r29')	C
+
+define(`s000',`%r31')	C
+
+define(`ma000',`%r4')	C
+define(`ma064',`%r20')	C
+
+define(`r000',`%r3')	C
+
+	extrd,u		n, 63, 2, %r5
+	cmpb,=		%r5, %r0, L(BIG)
+	nop
+
+	fldd		0(up), %fr4
+	ldo		8(up), up
+	xmpyu		%fr8R, %fr4L, %fr22
+	xmpyu		%fr8L, %fr4R, %fr23
+	fstd		%fr22, -0x78(%r30)	C mid product to  -0x78..-0x71
+	xmpyu		%fr8R, %fr4R, %fr24
+	xmpyu		%fr8L, %fr4L, %fr25
+	fstd		%fr23, -0x70(%r30)	C mid product to  -0x70..-0x69
+	fstd		%fr24, -0x80(%r30)	C low product to  -0x80..-0x79
+	addib,<>	-1, %r5, L(two_or_more)
+	fstd		%fr25, -0x68(%r30)	C high product to -0x68..-0x61
+LDEF(one)
+	ldd		-0x78(%r30), p032a1
+	ldd		-0x70(%r30), p032a2
+	ldd		-0x80(%r30), p000a
+	b		L(0_one_out)
+	ldd		-0x68(%r30), p064a
+
+LDEF(two_or_more)
+	fldd		0(up), %fr4
+	ldo		8(up), up
+	xmpyu		%fr8R, %fr4L, %fr22
+	xmpyu		%fr8L, %fr4R, %fr23
+	ldd		-0x78(%r30), p032a1
+	fstd		%fr22, -0x78(%r30)	C mid product to  -0x78..-0x71
+	xmpyu		%fr8R, %fr4R, %fr24
+	xmpyu		%fr8L, %fr4L, %fr25
+	ldd		-0x70(%r30), p032a2
+	fstd		%fr23, -0x70(%r30)	C mid product to  -0x70..-0x69
+	ldd		-0x80(%r30), p000a
+	fstd		%fr24, -0x80(%r30)	C low product to  -0x80..-0x79
+	ldd		-0x68(%r30), p064a
+	addib,<>	-1, %r5, L(three_or_more)
+	fstd		%fr25, -0x68(%r30)	C high product to -0x68..-0x61
+LDEF(two)
+	add		p032a1, p032a2, m032
+	add,dc		%r0, %r0, m096
+	depd,z		m032, 31, 32, ma000
+	extrd,u		m032, 31, 32, ma064
+	ldd		0(rp), r000
+	b		L(0_two_out)
+	depd		m096, 31, 32, ma064
+
+LDEF(three_or_more)
+	fldd		0(up), %fr4
+	add		p032a1, p032a2, m032
+	add,dc		%r0, %r0, m096
+	depd,z		m032, 31, 32, ma000
+	extrd,u		m032, 31, 32, ma064
+	ldd		0(rp), r000
+C	addib,=		-1, %r5, L(0_out)
+	depd		m096, 31, 32, ma064
+LDEF(loop0)
+C	xmpyu		%fr8R, %fr4L, %fr22
+C	xmpyu		%fr8L, %fr4R, %fr23
+C	ldd		-0x78(%r30), p032a1
+C	fstd		%fr22, -0x78(%r30)	C mid product to  -0x78..-0x71
+C
+C	xmpyu		%fr8R, %fr4R, %fr24
+C	xmpyu		%fr8L, %fr4L, %fr25
+C	ldd		-0x70(%r30), p032a2
+C	fstd		%fr23, -0x70(%r30)	C mid product to  -0x70..-0x69
+C
+C	ldo		8(rp), rp
+C	add		climb, p000a, s000
+C	ldd		-0x80(%r30), p000a
+C	fstd		%fr24, -0x80(%r30)	C low product to  -0x80..-0x79
+C
+C	add,dc		p064a, %r0, climb
+C	ldo		8(up), up
+C	ldd		-0x68(%r30), p064a
+C	fstd		%fr25, -0x68(%r30)	C high product to -0x68..-0x61
+C
+C	add		ma000, s000, s000
+C	add,dc		ma064, climb, climb
+C	fldd		0(up), %fr4
+C
+C	add		r000, s000, s000
+C	add,dc		%r0, climb, climb
+C	std		s000, -8(rp)
+C
+C	add		p032a1, p032a2, m032
+C	add,dc		%r0, %r0, m096
+C
+C	depd,z		m032, 31, 32, ma000
+C	extrd,u		m032, 31, 32, ma064
+C	ldd		0(rp), r000
+C	addib,<>	-1, %r5, L(loop0)
+C	depd		m096, 31, 32, ma064
+LDEF(0_out)
+	ldo		8(up), up
+	xmpyu		%fr8R, %fr4L, %fr22
+	xmpyu		%fr8L, %fr4R, %fr23
+	ldd		-0x78(%r30), p032a1
+	fstd		%fr22, -0x78(%r30)	C mid product to  -0x78..-0x71
+	xmpyu		%fr8R, %fr4R, %fr24
+	xmpyu		%fr8L, %fr4L, %fr25
+	ldd		-0x70(%r30), p032a2
+	fstd		%fr23, -0x70(%r30)	C mid product to  -0x70..-0x69
+	ldo		8(rp), rp
+	add		climb, p000a, s000
+	ldd		-0x80(%r30), p000a
+	fstd		%fr24, -0x80(%r30)	C low product to  -0x80..-0x79
+	add,dc		p064a, %r0, climb
+	ldd		-0x68(%r30), p064a
+	fstd		%fr25, -0x68(%r30)	C high product to -0x68..-0x61
+	add		ma000, s000, s000
+	add,dc		ma064, climb, climb
+	add		r000, s000, s000
+	add,dc		%r0, climb, climb
+	std		s000, -8(rp)
+	add		p032a1, p032a2, m032
+	add,dc		%r0, %r0, m096
+	depd,z		m032, 31, 32, ma000
+	extrd,u		m032, 31, 32, ma064
+	ldd		0(rp), r000
+	depd		m096, 31, 32, ma064
+LDEF(0_two_out)
+	ldd		-0x78(%r30), p032a1
+	ldd		-0x70(%r30), p032a2
+	ldo		8(rp), rp
+	add		climb, p000a, s000
+	ldd		-0x80(%r30), p000a
+	add,dc		p064a, %r0, climb
+	ldd		-0x68(%r30), p064a
+	add		ma000, s000, s000
+	add,dc		ma064, climb, climb
+	add		r000, s000, s000
+	add,dc		%r0, climb, climb
+	std		s000, -8(rp)
+LDEF(0_one_out)
+	add		p032a1, p032a2, m032
+	add,dc		%r0, %r0, m096
+	depd,z		m032, 31, 32, ma000
+	extrd,u		m032, 31, 32, ma064
+	ldd		0(rp), r000
+	depd		m096, 31, 32, ma064
+
+	add		climb, p000a, s000
+	add,dc		p064a, %r0, climb
+	add		ma000, s000, s000
+	add,dc		ma064, climb, climb
+	add		r000, s000, s000
+	add,dc		%r0, climb, climb
+	std		s000, 0(rp)
+
+	cmpib,>=	4, n, L(done)
+	ldo		8(rp), rp
+
+C 4-way unrolled code.
+
+LDEF(BIG)
+
+define(`p032a1',`%r1')	C
+define(`p032a2',`%r19')	C
+define(`p096b1',`%r20')	C
+define(`p096b2',`%r21')	C
+define(`p160c1',`%r22')	C
+define(`p160c2',`%r29')	C
+define(`p224d1',`%r31')	C
+define(`p224d2',`%r3')	C
+			C
+define(`m032',`%r4')	C
+define(`m096',`%r5')	C
+define(`m160',`%r6')	C
+define(`m224',`%r7')	C
+define(`m288',`%r8')	C
+			C
+define(`p000a',`%r1')	C
+define(`p064a',`%r19')	C
+define(`p064b',`%r20')	C
+define(`p128b',`%r21')	C
+define(`p128c',`%r22')	C
+define(`p192c',`%r29')	C
+define(`p192d',`%r31')	C
+define(`p256d',`%r3')	C
+			C
+define(`s000',`%r10')	C
+define(`s064',`%r11')	C
+define(`s128',`%r12')	C
+define(`s192',`%r13')	C
+			C
+define(`ma000',`%r9')	C
+define(`ma064',`%r4')	C
+define(`ma128',`%r5')	C
+define(`ma192',`%r6')	C
+define(`ma256',`%r7')	C
+			C
+define(`r000',`%r1')	C
+define(`r064',`%r19')	C
+define(`r128',`%r20')	C
+define(`r192',`%r21')	C
+
+	std		%r6, -0xe8(%r30)
+	std		%r7, -0xe0(%r30)
+	std		%r8, -0xd8(%r30)
+	std		%r9, -0xd0(%r30)
+	std		%r10, -0xc8(%r30)
+	std		%r11, -0xc0(%r30)
+	std		%r12, -0xb8(%r30)
+	std		%r13, -0xb0(%r30)
+
+ifdef(`HAVE_ABI_2_0w',
+`	extrd,u		n, 61, 62, n		C right shift 2
+',`	extrd,u		n, 61, 30, n		C right shift 2, zero extend
+')
+
+LDEF(4_or_more)
+	fldd		0(up), %fr4
+	fldd		8(up), %fr5
+	fldd		16(up), %fr6
+	fldd		24(up), %fr7
+	xmpyu		%fr8R, %fr4L, %fr22
+	xmpyu		%fr8L, %fr4R, %fr23
+	xmpyu		%fr8R, %fr5L, %fr24
+	xmpyu		%fr8L, %fr5R, %fr25
+	xmpyu		%fr8R, %fr6L, %fr26
+	xmpyu		%fr8L, %fr6R, %fr27
+	fstd		%fr22, -0x78(%r30)	C mid product to  -0x78..-0x71
+	xmpyu		%fr8R, %fr7L, %fr28
+	xmpyu		%fr8L, %fr7R, %fr29
+	fstd		%fr23, -0x70(%r30)	C mid product to  -0x70..-0x69
+	xmpyu		%fr8R, %fr4R, %fr30
+	xmpyu		%fr8L, %fr4L, %fr31
+	fstd		%fr24, -0x38(%r30)	C mid product to  -0x38..-0x31
+	xmpyu		%fr8R, %fr5R, %fr22
+	xmpyu		%fr8L, %fr5L, %fr23
+	fstd		%fr25, -0x30(%r30)	C mid product to  -0x30..-0x29
+	xmpyu		%fr8R, %fr6R, %fr24
+	xmpyu		%fr8L, %fr6L, %fr25
+	fstd		%fr26, -0x58(%r30)	C mid product to  -0x58..-0x51
+	xmpyu		%fr8R, %fr7R, %fr26
+	fstd		%fr27, -0x50(%r30)	C mid product to  -0x50..-0x49
+	addib,<>	-1, n, L(8_or_more)
+	xmpyu		%fr8L, %fr7L, %fr27
+	fstd		%fr28, -0x18(%r30)	C mid product to  -0x18..-0x11
+	fstd		%fr29, -0x10(%r30)	C mid product to  -0x10..-0x09
+	fstd		%fr30, -0x80(%r30)	C low product to  -0x80..-0x79
+	fstd		%fr31, -0x68(%r30)	C high product to -0x68..-0x61
+	fstd		%fr22, -0x40(%r30)	C low product to  -0x40..-0x39
+	fstd		%fr23, -0x28(%r30)	C high product to -0x28..-0x21
+	fstd		%fr24, -0x60(%r30)	C low product to  -0x60..-0x59
+	fstd		%fr25, -0x48(%r30)	C high product to -0x48..-0x41
+	fstd		%fr26, -0x20(%r30)	C low product to  -0x20..-0x19
+	fstd		%fr27, -0x88(%r30)	C high product to -0x88..-0x81
+	ldd		-0x78(%r30), p032a1
+	ldd		-0x70(%r30), p032a2
+	ldd		-0x38(%r30), p096b1
+	ldd		-0x30(%r30), p096b2
+	ldd		-0x58(%r30), p160c1
+	ldd		-0x50(%r30), p160c2
+	ldd		-0x18(%r30), p224d1
+	ldd		-0x10(%r30), p224d2
+	b		L(end1)
+	nop
+
+LDEF(8_or_more)
+	fstd		%fr28, -0x18(%r30)	C mid product to  -0x18..-0x11
+	fstd		%fr29, -0x10(%r30)	C mid product to  -0x10..-0x09
+	ldo		32(up), up
+	fstd		%fr30, -0x80(%r30)	C low product to  -0x80..-0x79
+	fstd		%fr31, -0x68(%r30)	C high product to -0x68..-0x61
+	fstd		%fr22, -0x40(%r30)	C low product to  -0x40..-0x39
+	fstd		%fr23, -0x28(%r30)	C high product to -0x28..-0x21
+	fstd		%fr24, -0x60(%r30)	C low product to  -0x60..-0x59
+	fstd		%fr25, -0x48(%r30)	C high product to -0x48..-0x41
+	fstd		%fr26, -0x20(%r30)	C low product to  -0x20..-0x19
+	fstd		%fr27, -0x88(%r30)	C high product to -0x88..-0x81
+	fldd		0(up), %fr4
+	fldd		8(up), %fr5
+	fldd		16(up), %fr6
+	fldd		24(up), %fr7
+	xmpyu		%fr8R, %fr4L, %fr22
+	ldd		-0x78(%r30), p032a1
+	xmpyu		%fr8L, %fr4R, %fr23
+	xmpyu		%fr8R, %fr5L, %fr24
+	ldd		-0x70(%r30), p032a2
+	xmpyu		%fr8L, %fr5R, %fr25
+	xmpyu		%fr8R, %fr6L, %fr26
+	ldd		-0x38(%r30), p096b1
+	xmpyu		%fr8L, %fr6R, %fr27
+	fstd		%fr22, -0x78(%r30)	C mid product to  -0x78..-0x71
+	xmpyu		%fr8R, %fr7L, %fr28
+	ldd		-0x30(%r30), p096b2
+	xmpyu		%fr8L, %fr7R, %fr29
+	fstd		%fr23, -0x70(%r30)	C mid product to  -0x70..-0x69
+	xmpyu		%fr8R, %fr4R, %fr30
+	ldd		-0x58(%r30), p160c1
+	xmpyu		%fr8L, %fr4L, %fr31
+	fstd		%fr24, -0x38(%r30)	C mid product to  -0x38..-0x31
+	xmpyu		%fr8R, %fr5R, %fr22
+	ldd		-0x50(%r30), p160c2
+	xmpyu		%fr8L, %fr5L, %fr23
+	fstd		%fr25, -0x30(%r30)	C mid product to  -0x30..-0x29
+	xmpyu		%fr8R, %fr6R, %fr24
+	ldd		-0x18(%r30), p224d1
+	xmpyu		%fr8L, %fr6L, %fr25
+	fstd		%fr26, -0x58(%r30)	C mid product to  -0x58..-0x51
+	xmpyu		%fr8R, %fr7R, %fr26
+	ldd		-0x10(%r30), p224d2
+	fstd		%fr27, -0x50(%r30)	C mid product to  -0x50..-0x49
+	addib,=		-1, n, L(end2)
+	xmpyu		%fr8L, %fr7L, %fr27
+LDEF(loop)
+	add		p032a1, p032a2, m032
+	ldd		-0x80(%r30), p000a
+	add,dc		p096b1, p096b2, m096
+	fstd		%fr28, -0x18(%r30)	C mid product to  -0x18..-0x11
+
+	add,dc		p160c1, p160c2, m160
+	ldd		-0x68(%r30), p064a
+	add,dc		p224d1, p224d2, m224
+	fstd		%fr29, -0x10(%r30)	C mid product to  -0x10..-0x09
+
+	add,dc		%r0, %r0, m288
+	ldd		-0x40(%r30), p064b
+	ldo		32(up), up
+	fstd		%fr30, -0x80(%r30)	C low product to  -0x80..-0x79
+
+	depd,z		m032, 31, 32, ma000
+	ldd		-0x28(%r30), p128b
+	extrd,u		m032, 31, 32, ma064
+	fstd		%fr31, -0x68(%r30)	C high product to -0x68..-0x61
+
+	depd		m096, 31, 32, ma064
+	ldd		-0x60(%r30), p128c
+	extrd,u		m096, 31, 32, ma128
+	fstd		%fr22, -0x40(%r30)	C low product to  -0x40..-0x39
+
+	depd		m160, 31, 32, ma128
+	ldd		-0x48(%r30), p192c
+	extrd,u		m160, 31, 32, ma192
+	fstd		%fr23, -0x28(%r30)	C high product to -0x28..-0x21
+
+	depd		m224, 31, 32, ma192
+	ldd		-0x20(%r30), p192d
+	extrd,u		m224, 31, 32, ma256
+	fstd		%fr24, -0x60(%r30)	C low product to  -0x60..-0x59
+
+	depd		m288, 31, 32, ma256
+	ldd		-0x88(%r30), p256d
+	add		climb, p000a, s000
+	fstd		%fr25, -0x48(%r30)	C high product to -0x48..-0x41
+
+	add,dc		p064a, p064b, s064
+	ldd		0(rp), r000
+	add,dc		p128b, p128c, s128
+	fstd		%fr26, -0x20(%r30)	C low product to  -0x20..-0x19
+
+	add,dc		p192c, p192d, s192
+	ldd		8(rp), r064
+	add,dc		p256d, %r0, climb
+	fstd		%fr27, -0x88(%r30)	C high product to -0x88..-0x81
+
+	ldd		16(rp), r128
+	add		ma000, s000, s000	C accum mid 0
+	ldd		24(rp), r192
+	add,dc		ma064, s064, s064	C accum mid 1
+
+	add,dc		ma128, s128, s128	C accum mid 2
+	fldd		0(up), %fr4
+	add,dc		ma192, s192, s192	C accum mid 3
+	fldd		8(up), %fr5
+
+	add,dc		ma256, climb, climb
+	fldd		16(up), %fr6
+	add		r000, s000, s000	C accum rlimb 0
+	fldd		24(up), %fr7
+
+	add,dc		r064, s064, s064	C accum rlimb 1
+	add,dc		r128, s128, s128	C accum rlimb 2
+	std		s000, 0(rp)
+
+	add,dc		r192, s192, s192	C accum rlimb 3
+	add,dc		%r0, climb, climb
+	std		s064, 8(rp)
+
+	xmpyu		%fr8R, %fr4L, %fr22
+	ldd		-0x78(%r30), p032a1
+	xmpyu		%fr8L, %fr4R, %fr23
+	std		s128, 16(rp)
+
+	xmpyu		%fr8R, %fr5L, %fr24
+	ldd		-0x70(%r30), p032a2
+	xmpyu		%fr8L, %fr5R, %fr25
+	std		s192, 24(rp)
+
+	xmpyu		%fr8R, %fr6L, %fr26
+	ldd		-0x38(%r30), p096b1
+	xmpyu		%fr8L, %fr6R, %fr27
+	fstd		%fr22, -0x78(%r30)	C mid product to  -0x78..-0x71
+
+	xmpyu		%fr8R, %fr7L, %fr28
+	ldd		-0x30(%r30), p096b2
+	xmpyu		%fr8L, %fr7R, %fr29
+	fstd		%fr23, -0x70(%r30)	C mid product to  -0x70..-0x69
+
+	xmpyu		%fr8R, %fr4R, %fr30
+	ldd		-0x58(%r30), p160c1
+	xmpyu		%fr8L, %fr4L, %fr31
+	fstd		%fr24, -0x38(%r30)	C mid product to  -0x38..-0x31
+
+	xmpyu		%fr8R, %fr5R, %fr22
+	ldd		-0x50(%r30), p160c2
+	xmpyu		%fr8L, %fr5L, %fr23
+	fstd		%fr25, -0x30(%r30)	C mid product to  -0x30..-0x29
+
+	xmpyu		%fr8R, %fr6R, %fr24
+	ldd		-0x18(%r30), p224d1
+	xmpyu		%fr8L, %fr6L, %fr25
+	fstd		%fr26, -0x58(%r30)	C mid product to  -0x58..-0x51
+
+	xmpyu		%fr8R, %fr7R, %fr26
+	ldd		-0x10(%r30), p224d2
+	fstd		%fr27, -0x50(%r30)	C mid product to  -0x50..-0x49
+	xmpyu		%fr8L, %fr7L, %fr27
+
+	addib,<>	-1, n, L(loop)
+	ldo		32(rp), rp
+
+LDEF(end2)
+	add		p032a1, p032a2, m032
+	ldd		-0x80(%r30), p000a
+	add,dc		p096b1, p096b2, m096
+	fstd		%fr28, -0x18(%r30)	C mid product to  -0x18..-0x11
+	add,dc		p160c1, p160c2, m160
+	ldd		-0x68(%r30), p064a
+	add,dc		p224d1, p224d2, m224
+	fstd		%fr29, -0x10(%r30)	C mid product to  -0x10..-0x09
+	add,dc		%r0, %r0, m288
+	ldd		-0x40(%r30), p064b
+	fstd		%fr30, -0x80(%r30)	C low product to  -0x80..-0x79
+	depd,z		m032, 31, 32, ma000
+	ldd		-0x28(%r30), p128b
+	extrd,u		m032, 31, 32, ma064
+	fstd		%fr31, -0x68(%r30)	C high product to -0x68..-0x61
+	depd		m096, 31, 32, ma064
+	ldd		-0x60(%r30), p128c
+	extrd,u		m096, 31, 32, ma128
+	fstd		%fr22, -0x40(%r30)	C low product to  -0x40..-0x39
+	depd		m160, 31, 32, ma128
+	ldd		-0x48(%r30), p192c
+	extrd,u		m160, 31, 32, ma192
+	fstd		%fr23, -0x28(%r30)	C high product to -0x28..-0x21
+	depd		m224, 31, 32, ma192
+	ldd		-0x20(%r30), p192d
+	extrd,u		m224, 31, 32, ma256
+	fstd		%fr24, -0x60(%r30)	C low product to  -0x60..-0x59
+	depd		m288, 31, 32, ma256
+	ldd		-0x88(%r30), p256d
+	add		climb, p000a, s000
+	fstd		%fr25, -0x48(%r30)	C high product to -0x48..-0x41
+	add,dc		p064a, p064b, s064
+	ldd		0(rp), r000
+	add,dc		p128b, p128c, s128
+	fstd		%fr26, -0x20(%r30)	C low product to  -0x20..-0x19
+	add,dc		p192c, p192d, s192
+	ldd		8(rp), r064
+	add,dc		p256d, %r0, climb
+	fstd		%fr27, -0x88(%r30)	C high product to -0x88..-0x81
+	ldd		16(rp), r128
+	add		ma000, s000, s000	C accum mid 0
+	ldd		24(rp), r192
+	add,dc		ma064, s064, s064	C accum mid 1
+	add,dc		ma128, s128, s128	C accum mid 2
+	add,dc		ma192, s192, s192	C accum mid 3
+	add,dc		ma256, climb, climb
+	add		r000, s000, s000	C accum rlimb 0
+	add,dc		r064, s064, s064	C accum rlimb 1
+	add,dc		r128, s128, s128	C accum rlimb 2
+	std		s000, 0(rp)
+	add,dc		r192, s192, s192	C accum rlimb 3
+	add,dc		%r0, climb, climb
+	std		s064, 8(rp)
+	ldd		-0x78(%r30), p032a1
+	std		s128, 16(rp)
+	ldd		-0x70(%r30), p032a2
+	std		s192, 24(rp)
+	ldd		-0x38(%r30), p096b1
+	ldd		-0x30(%r30), p096b2
+	ldd		-0x58(%r30), p160c1
+	ldd		-0x50(%r30), p160c2
+	ldd		-0x18(%r30), p224d1
+	ldd		-0x10(%r30), p224d2
+	ldo		32(rp), rp
+
+LDEF(end1)
+	add		p032a1, p032a2, m032
+	ldd		-0x80(%r30), p000a
+	add,dc		p096b1, p096b2, m096
+	add,dc		p160c1, p160c2, m160
+	ldd		-0x68(%r30), p064a
+	add,dc		p224d1, p224d2, m224
+	add,dc		%r0, %r0, m288
+	ldd		-0x40(%r30), p064b
+	depd,z		m032, 31, 32, ma000
+	ldd		-0x28(%r30), p128b
+	extrd,u		m032, 31, 32, ma064
+	depd		m096, 31, 32, ma064
+	ldd		-0x60(%r30), p128c
+	extrd,u		m096, 31, 32, ma128
+	depd		m160, 31, 32, ma128
+	ldd		-0x48(%r30), p192c
+	extrd,u		m160, 31, 32, ma192
+	depd		m224, 31, 32, ma192
+	ldd		-0x20(%r30), p192d
+	extrd,u		m224, 31, 32, ma256
+	depd		m288, 31, 32, ma256
+	ldd		-0x88(%r30), p256d
+	add		climb, p000a, s000
+	add,dc		p064a, p064b, s064
+	ldd		0(rp), r000
+	add,dc		p128b, p128c, s128
+	add,dc		p192c, p192d, s192
+	ldd		8(rp), r064
+	add,dc		p256d, %r0, climb
+	ldd		16(rp), r128
+	add		ma000, s000, s000	C accum mid 0
+	ldd		24(rp), r192
+	add,dc		ma064, s064, s064	C accum mid 1
+	add,dc		ma128, s128, s128	C accum mid 2
+	add,dc		ma192, s192, s192	C accum mid 3
+	add,dc		ma256, climb, climb
+	add		r000, s000, s000	C accum rlimb 0
+	add,dc		r064, s064, s064	C accum rlimb 1
+	add,dc		r128, s128, s128	C accum rlimb 2
+	std		s000, 0(rp)
+	add,dc		r192, s192, s192	C accum rlimb 3
+	add,dc		%r0, climb, climb
+	std		s064, 8(rp)
+	std		s128, 16(rp)
+	std		s192, 24(rp)
+
+	ldd		-0xb0(%r30), %r13
+	ldd		-0xb8(%r30), %r12
+	ldd		-0xc0(%r30), %r11
+	ldd		-0xc8(%r30), %r10
+	ldd		-0xd0(%r30), %r9
+	ldd		-0xd8(%r30), %r8
+	ldd		-0xe0(%r30), %r7
+	ldd		-0xe8(%r30), %r6
+LDEF(done)
+ifdef(`HAVE_ABI_2_0w',
+`	copy		climb, %r28
+',`	extrd,u		climb, 63, 32, %r29
+	extrd,u		climb, 31, 32, %r28
+')
+	ldd		-0xf0(%r30), %r5
+	ldd		-0xf8(%r30), %r4
+	bve		(%r2)
+	ldd,mb		-0x100(%r30), %r3
+EPILOGUE(mpn_addmul_1)
diff --git a/third_party/gmp/mpn/pa64/aors_n.asm b/third_party/gmp/mpn/pa64/aors_n.asm
new file mode 100644
index 0000000..ab4536f
--- /dev/null
+++ b/third_party/gmp/mpn/pa64/aors_n.asm
@@ -0,0 +1,130 @@
+dnl  HP-PA 2.0 mpn_add_n, mpn_sub_n
+
+dnl  Copyright 1997, 2000, 2002, 2003, 2009, 2010 Free Software Foundation,
+dnl  Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+dnl  This runs at 2 cycles/limb on PA8000 and 1.6875 cycles/limb on PA8500.  It
+dnl  should be possible to reach the cache bandwidth 1.5 cycles/limb at least
+dnl  with PA8500.  The problem now is stalling of the first ADD,DC after LDO,
+dnl  where the processor gets confused about where carry comes from.
+
+include(`../config.m4')
+
+dnl INPUT PARAMETERS
+define(`rp',`%r26')
+define(`up',`%r25')
+define(`vp',`%r24')
+define(`n',`%r23')
+
+ifdef(`OPERATION_add_n', `
+	define(ADCSBC,	      `add,dc')
+	define(INITCY,	      `addi -1,%r22,%r0')
+	define(func,	      mpn_add_n)
+	define(func_nc,	      mpn_add_nc)')
+ifdef(`OPERATION_sub_n', `
+	define(ADCSBC,	      `sub,db')
+	define(INITCY,	      `subi 0,%r22,%r0')
+	define(func,	      mpn_sub_n)
+	define(func_nc,	      mpn_sub_nc)')
+
+MULFUNC_PROLOGUE(mpn_add_n mpn_add_nc mpn_sub_n mpn_sub_nc)
+
+ifdef(`HAVE_ABI_2_0w',
+`       .level  2.0w
+',`     .level  2.0
+')
+PROLOGUE(func_nc)
+ifdef(`HAVE_ABI_2_0w',
+`	b		L(com)
+	nop
+',`	b		L(com)
+	ldw		-52(%r30), %r22
+')
+EPILOGUE()
+PROLOGUE(func)
+	ldi		0, %r22
+LDEF(com)
+	sub		%r0, n, %r21
+	depw,z		%r21, 30, 3, %r28	C r28 = 2 * (-n & 7)
+	depw,z		%r21, 28, 3, %r21	C r21 = 8 * (-n & 7)
+	sub		up, %r21, up		C offset up
+	sub		vp, %r21, vp		C offset vp
+	sub		rp, %r21, rp		C offset rp
+	blr		%r28, %r0		C branch into loop
+	INITCY
+
+LDEF(loop)
+	ldd		0(up), %r20
+	ldd		0(vp), %r31
+	ADCSBC		%r20, %r31, %r20
+	std		%r20, 0(rp)
+LDEF(7)	ldd		8(up), %r21
+	ldd		8(vp), %r19
+	ADCSBC		%r21, %r19, %r21
+	std		%r21, 8(rp)
+LDEF(6)	ldd		16(up), %r20
+	ldd		16(vp), %r31
+	ADCSBC		%r20, %r31, %r20
+	std		%r20, 16(rp)
+LDEF(5)	ldd		24(up), %r21
+	ldd		24(vp), %r19
+	ADCSBC		%r21, %r19, %r21
+	std		%r21, 24(rp)
+LDEF(4)	ldd		32(up), %r20
+	ldd		32(vp), %r31
+	ADCSBC		%r20, %r31, %r20
+	std		%r20, 32(rp)
+LDEF(3)	ldd		40(up), %r21
+	ldd		40(vp), %r19
+	ADCSBC		%r21, %r19, %r21
+	std		%r21, 40(rp)
+LDEF(2)	ldd		48(up), %r20
+	ldd		48(vp), %r31
+	ADCSBC		%r20, %r31, %r20
+	std		%r20, 48(rp)
+LDEF(1)	ldd		56(up), %r21
+	ldd		56(vp), %r19
+	ADCSBC		%r21, %r19, %r21
+	ldo		64(up), up
+	std		%r21, 56(rp)
+	ldo		64(vp), vp
+	addib,>		-8, n, L(loop)
+	ldo		64(rp), rp
+
+	add,dc		%r0, %r0, %r29
+ifdef(`OPERATION_sub_n',`
+	subi		1, %r29, %r29
+')
+	bve		(%r2)
+ifdef(`HAVE_ABI_2_0w',
+`	copy		%r29, %r28
+',`	ldi		0, %r28
+')
+EPILOGUE()
diff --git a/third_party/gmp/mpn/pa64/aorslsh1_n.asm b/third_party/gmp/mpn/pa64/aorslsh1_n.asm
new file mode 100644
index 0000000..2a55dde
--- /dev/null
+++ b/third_party/gmp/mpn/pa64/aorslsh1_n.asm
@@ -0,0 +1,228 @@
+dnl  PA64 mpn_addlsh1_n/mpn_sublsh1_n -- rp[] = up[] +- (vp[] << 1).
+
+dnl  Copyright 2003 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		    cycles/limb
+C 8000,8200:		2
+C 8500,8600,8700:	1.75
+
+C TODO
+C  * Write special feed-in code for each (n mod 8). (See the ia64 code.)
+C  * Try to make this run at closer to 1.5 c/l.
+C  * Set up register aliases (define(`u0',`%r19')).
+C  * Explicitly align loop.
+
+dnl INPUT PARAMETERS
+define(`rp',`%r26')
+define(`up',`%r25')
+define(`vp',`%r24')
+define(`n',`%r23')
+
+ifdef(`OPERATION_addlsh1_n',`
+  define(ADCSBC,	`add,dc')
+  define(INITC,		`ldi	0,')
+  define(func, mpn_addlsh1_n)
+')
+ifdef(`OPERATION_sublsh1_n',`
+  define(ADCSBC,	`sub,db')
+  define(INITC,		`ldi	1,')
+  define(func, mpn_sublsh1_n)
+')
+
+MULFUNC_PROLOGUE(mpn_addlsh1_n mpn_sublsh1_n)
+
+ifdef(`HAVE_ABI_2_0w',`
+  define(LEVEL,		`.level 2.0w')
+  define(RETREG,	`%r28')
+  define(CLRRET1,	`dnl')
+')
+ifdef(`HAVE_ABI_2_0n',`
+  define(LEVEL,		`.level 2.0')
+  define(RETREG,	`%r29')
+  define(CLRRET1,	`ldi	0, %r28')
+')
+
+	LEVEL
+PROLOGUE(func)
+	std,ma		%r3, 0x100(%r30)	C save reg
+
+	INITC		%r1			C init saved cy
+
+C Primitive code for the first (n mod 8) limbs:
+	extrd,u		n, 63, 3, %r22		C count for loop0
+	comib,=		0, %r22, L(unrolled)	C skip loop0?
+	copy		%r0, %r28
+LDEF(loop0)
+	ldd	0(vp), %r21
+	ldo		8(vp), vp
+	ldd	0(up), %r19
+	ldo		8(up), up
+	shrpd	%r21, %r28, 63, %r31
+	addi		-1, %r1, %r0		C restore cy
+	ADCSBC	%r19, %r31, %r29
+	std	%r29, 0(rp)
+	add,dc		%r0, %r0, %r1		C save cy
+	copy	%r21, %r28
+	addib,>		-1, %r22, L(loop0)
+	ldo		8(rp), rp
+
+	addib,>=	-8, n, L(unrolled)
+	addi		-1, %r1, %r0		C restore cy
+
+	shrpd	%r0, %r28, 63, %r28
+	ADCSBC	%r0, %r28, RETREG
+ifdef(`OPERATION_sublsh1_n',
+`	sub	%r0, RETREG, RETREG')
+	CLRRET1
+
+	bve		(%r2)
+	ldd,mb		-0x100(%r30), %r3
+
+
+LDEF(unrolled)
+	std		%r4, -0xf8(%r30)	C save reg
+	ldd	0(vp), %r4
+	std		%r5, -0xf0(%r30)	C save reg
+	ldd	8(vp), %r5
+	std		%r6, -0xe8(%r30)	C save reg
+	ldd	16(vp), %r6
+	std		%r7, -0xe0(%r30)	C save reg
+
+	ldd	24(vp), %r7
+	shrpd	%r4, %r28, 63, %r31
+	std		%r8, -0xd8(%r30)	C save reg
+	ldd	32(vp), %r8
+	shrpd	%r5, %r4, 63, %r4
+	std		%r9, -0xd0(%r30)	C save reg
+	ldd	40(vp), %r9
+	shrpd	%r6, %r5, 63, %r5
+	ldd	48(vp), %r3
+	shrpd	%r7, %r6, 63, %r6
+	ldd	56(vp), %r28
+	shrpd	%r8, %r7, 63, %r7
+	ldd	0(up), %r19
+	shrpd	%r9, %r8, 63, %r8
+	ldd	8(up), %r20
+	shrpd	%r3, %r9, 63, %r9
+	ldd	16(up), %r21
+	shrpd	%r28, %r3, 63, %r3
+	ldd	24(up), %r22
+
+	nop					C alignment FIXME
+	addib,<=	-8, n, L(end)
+	addi		-1, %r1, %r0		C restore cy
+LDEF(loop)
+	ADCSBC	%r19, %r31, %r29
+	ldd	32(up), %r19
+	std	%r29, 0(rp)
+	ADCSBC	%r20, %r4, %r29
+	ldd	40(up), %r20
+	std	%r29, 8(rp)
+	ADCSBC	%r21, %r5, %r29
+	ldd	48(up), %r21
+	std	%r29, 16(rp)
+	ADCSBC	%r22, %r6, %r29
+	ldd	56(up), %r22
+	std	%r29, 24(rp)
+	ADCSBC	%r19, %r7, %r29
+	ldd	64(vp), %r4
+	std	%r29, 32(rp)
+	ADCSBC	%r20, %r8, %r29
+	ldd	72(vp), %r5
+	std	%r29, 40(rp)
+	ADCSBC	%r21, %r9, %r29
+	ldd	80(vp), %r6
+	std	%r29, 48(rp)
+	ADCSBC	%r22, %r3, %r29
+	std	%r29, 56(rp)
+
+	add,dc		%r0, %r0, %r1		C save cy
+
+	ldd	88(vp), %r7
+	shrpd	%r4, %r28, 63, %r31
+	ldd	96(vp), %r8
+	shrpd	%r5, %r4, 63, %r4
+	ldd	104(vp), %r9
+	shrpd	%r6, %r5, 63, %r5
+	ldd	112(vp), %r3
+	shrpd	%r7, %r6, 63, %r6
+	ldd	120(vp), %r28
+	shrpd	%r8, %r7, 63, %r7
+	ldd	64(up), %r19
+	shrpd	%r9, %r8, 63, %r8
+	ldd	72(up), %r20
+	shrpd	%r3, %r9, 63, %r9
+	ldd	80(up), %r21
+	shrpd	%r28, %r3, 63, %r3
+	ldd	88(up), %r22
+
+	ldo		64(vp), vp
+	ldo		64(rp), rp
+	ldo		64(up), up
+	addib,>		-8, n, L(loop)
+	addi		-1, %r1, %r0		C restore cy
+LDEF(end)
+	ADCSBC	%r19, %r31, %r29
+	ldd	32(up), %r19
+	std	%r29, 0(rp)
+	ADCSBC	%r20, %r4, %r29
+	ldd	40(up), %r20
+	std	%r29, 8(rp)
+	ADCSBC	%r21, %r5, %r29
+	ldd	48(up), %r21
+	std	%r29, 16(rp)
+	ADCSBC	%r22, %r6, %r29
+	ldd	56(up), %r22
+	std	%r29, 24(rp)
+	ADCSBC	%r19, %r7, %r29
+	ldd		-0xf8(%r30), %r4	C restore reg
+	std	%r29, 32(rp)
+	ADCSBC	%r20, %r8, %r29
+	ldd		-0xf0(%r30), %r5	C restore reg
+	std	%r29, 40(rp)
+	ADCSBC	%r21, %r9, %r29
+	ldd		-0xe8(%r30), %r6	C restore reg
+	std	%r29, 48(rp)
+	ADCSBC	%r22, %r3, %r29
+	ldd		-0xe0(%r30), %r7	C restore reg
+	std	%r29, 56(rp)
+
+	shrpd	%r0, %r28, 63, %r28
+	ldd		-0xd8(%r30), %r8	C restore reg
+	ADCSBC	%r0, %r28, RETREG
+ifdef(`OPERATION_sublsh1_n',
+`	sub	%r0, RETREG, RETREG')
+	CLRRET1
+
+	ldd		-0xd0(%r30), %r9	C restore reg
+	bve		(%r2)
+	ldd,mb		-0x100(%r30), %r3	C restore reg
+EPILOGUE()
diff --git a/third_party/gmp/mpn/pa64/gmp-mparam.h b/third_party/gmp/mpn/pa64/gmp-mparam.h
new file mode 100644
index 0000000..c2719c3
--- /dev/null
+++ b/third_party/gmp/mpn/pa64/gmp-mparam.h
@@ -0,0 +1,247 @@
+/* gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 1999-2004, 2008-2010 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+/* 440MHz PA8200 */
+
+#define DIVREM_1_NORM_THRESHOLD              0  /* always */
+#define DIVREM_1_UNNORM_THRESHOLD            0  /* always */
+#define MOD_1_1P_METHOD                      2
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          4
+#define MOD_1U_TO_MOD_1_1_THRESHOLD         10
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD         0  /* never mpn_mod_1_1p */
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        14
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     11
+#define USE_PREINV_DIVREM_1                  1
+#define DIV_QR_2_PI2_THRESHOLD              21
+#define DIVEXACT_1_THRESHOLD                 0  /* always */
+#define BMOD_1_TO_MOD_1_THRESHOLD        MP_SIZE_T_MAX  /* never */
+
+#define MUL_TOOM22_THRESHOLD                31
+#define MUL_TOOM33_THRESHOLD               114
+#define MUL_TOOM44_THRESHOLD               179
+#define MUL_TOOM6H_THRESHOLD               222
+#define MUL_TOOM8H_THRESHOLD               296
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD     130
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     229
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     129
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD      54
+
+#define SQR_BASECASE_THRESHOLD               5
+#define SQR_TOOM2_THRESHOLD                 58
+#define SQR_TOOM3_THRESHOLD                153
+#define SQR_TOOM4_THRESHOLD                278
+#define SQR_TOOM6_THRESHOLD                  0  /* always */
+#define SQR_TOOM8_THRESHOLD                  0  /* always */
+
+#define MULMID_TOOM42_THRESHOLD             56
+
+#define MULMOD_BNM1_THRESHOLD               15
+#define SQRMOD_BNM1_THRESHOLD               19
+
+#define POWM_SEC_TABLE  2,23,228,1084
+
+#define MUL_FFT_MODF_THRESHOLD             336  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    336, 5}, {     11, 4}, {     23, 5}, {     21, 6}, \
+    {     11, 5}, {     23, 6}, {     21, 7}, {     11, 6}, \
+    {     23, 7}, {     15, 6}, {     31, 7}, {     21, 8}, \
+    {     11, 7}, {     24, 8}, {     13, 7}, {     27, 8}, \
+    {     15, 7}, {     31, 8}, {     19, 7}, {     39, 8}, \
+    {     27, 9}, {     15, 8}, {     33, 9}, {     19, 8}, \
+    {     39, 9}, {     23, 8}, {     47, 9}, {     27,10}, \
+    {     15, 9}, {     39,10}, {     23, 9}, {     51,10}, \
+    {     31, 9}, {     67,10}, {     39, 9}, {     79,10}, \
+    {     47, 9}, {     95,10}, {     55,11}, {     31,10}, \
+    {     63, 9}, {    127,10}, {     71, 8}, {    287,10}, \
+    {     79,11}, {     47,10}, {     95, 9}, {    191, 8}, \
+    {    383, 7}, {    767,10}, {    103, 9}, {    207, 8}, \
+    {    415, 7}, {    831,12}, {     31,11}, {     63,10}, \
+    {    127, 9}, {    255, 8}, {    543, 7}, {   1087, 6}, \
+    {   2175,10}, {    143, 9}, {    287, 8}, {    575,11}, \
+    {     79, 9}, {    319, 8}, {    639, 7}, {   1279, 9}, \
+    {    335, 8}, {    671,10}, {    175, 9}, {    351, 8}, \
+    {    703,11}, {     95,10}, {    191, 9}, {    383, 8}, \
+    {    767,10}, {    207, 9}, {    415, 8}, {    831, 7}, \
+    {   1663,11}, {    111,10}, {    223, 9}, {    447, 8}, \
+    {    895,12}, {     63,11}, {    127,10}, {    255, 9}, \
+    {    543, 8}, {   1087, 7}, {   2175,10}, {    287, 9}, \
+    {    575, 8}, {   1215, 7}, {   2431,10}, {    319, 9}, \
+    {    639, 8}, {   1279,10}, {    335, 9}, {    671, 8}, \
+    {   1343, 9}, {    703, 8}, {   1407,12}, {     95,11}, \
+    {    191,10}, {    383,11}, {    207, 9}, {    831, 8}, \
+    {   1663,11}, {    223,10}, {    447, 9}, {    959,13}, \
+    {     63,12}, {    127,11}, {    255, 8}, {   2047,11}, \
+    {    271,10}, {    543, 9}, {   1087, 8}, {   2175,11}, \
+    {    287,10}, {    575, 9}, {   1215, 8}, {   2431,11}, \
+    {    319,10}, {    671, 9}, {   1343, 8}, {   2687,11}, \
+    {    351,10}, {    703, 9}, {   1471, 8}, {   2943,12}, \
+    {    191,11}, {    383, 8}, {   3071,11}, {    415,10}, \
+    {    831, 9}, {   1663,11}, {    479,10}, {    959, 9}, \
+    {   1919, 8}, {   3839,13}, {    127,12}, {    255,11}, \
+    {    543,10}, {   1087, 9}, {   2175,12}, {    287,11}, \
+    {    607,10}, {   1215, 9}, {   2431, 8}, {   4863,12}, \
+    {    319,11}, {    671,10}, {   1343,13}, {    191, 9}, \
+    {   3071,12}, {    415,11}, {    831,10}, {   1663, 8}, \
+    {   6655, 9}, {   3455,12}, {    447, 9}, {   3583,13}, \
+    {    255,12}, {    511,11}, {   1023,10}, {   2175,13}, \
+    {    319,11}, {   1279,12}, {    671,10}, {   2815,12}, \
+    {    735,10}, {   2943, 9}, {   5887,13}, {    383,12}, \
+    {    767,11}, {   1535,10}, {   3071,13}, {    447,10}, \
+    {   3583,12}, {    959,13}, {    511,12}, {   1087,13}, \
+    {    639,12}, {   1343,13}, {    767,11}, {   3071,13}, \
+    {    831,12}, {   1663,11}, {   3455,10}, {   6911,13}, \
+    {    895,14}, {    511,13}, {   1023,12}, {   2047,13}, \
+    {   1087,12}, {   2303,13}, {   1215,12}, {   2431,14}, \
+    {    639,13}, {   1279,12}, {   2559,13}, {   1343,12}, \
+    {   2687,11}, {   5375,13}, {   1407,12}, {   2815,11}, \
+    {   5631,12}, {   2943,13}, {   1535,12}, {   3199,13}, \
+    {   1663,12}, {   3327,13}, {   1727,14}, {    895,13}, \
+    {   1791,12}, {   3583,13}, {   1919,15}, {    511,14}, \
+    {   1023,13}, {   2047,12}, {   4095,14}, {   1151,13}, \
+    {   2431,14}, {   1279,13}, {   2687,14}, {   1407,13}, \
+    {   2815,12}, {   5631,15}, {    767,14}, {   1535,13}, \
+    {   3071,14}, {   1663,13}, {   3327,14}, {   1791,13}, \
+    {   3583,14}, {   1919,15}, {   1023,14}, {   2303,13}, \
+    {   4607,14}, {   2431,13}, {   4863,15}, {  32768,16}, \
+    {  65536,17}, { 131072,18}, { 262144,19}, { 524288,20}, \
+    {1048576,21}, {2097152,22}, {4194304,23}, {8388608,24} }
+#define MUL_FFT_TABLE3_SIZE 252
+#define MUL_FFT_THRESHOLD                 2368
+
+#define SQR_FFT_MODF_THRESHOLD             284  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    284, 5}, {      9, 4}, {     21, 5}, {     21, 6}, \
+    {     11, 5}, {     23, 6}, {     25, 7}, {     25, 8}, \
+    {     13, 7}, {     27, 8}, {     15, 7}, {     31, 8}, \
+    {     27, 9}, {     15, 8}, {     33, 9}, {     19, 8}, \
+    {     39, 9}, {     23, 8}, {     47, 9}, {     27,10}, \
+    {     15, 9}, {     39,10}, {     23, 9}, {     51,11}, \
+    {     15,10}, {     31, 9}, {     67,10}, {     39, 9}, \
+    {     79,10}, {     47, 9}, {     95,10}, {     55,11}, \
+    {     31,10}, {     63, 8}, {    255, 7}, {    511,10}, \
+    {     71, 8}, {    287, 7}, {    575,10}, {     79,11}, \
+    {     47,10}, {     95, 9}, {    191, 8}, {    383, 7}, \
+    {    767,10}, {    103, 9}, {    207, 8}, {    415,12}, \
+    {     31,11}, {     63,10}, {    127, 9}, {    255, 8}, \
+    {    543, 7}, {   1087, 8}, {    575, 7}, {   1151,11}, \
+    {     79, 8}, {    639, 7}, {   1279, 9}, {    335, 8}, \
+    {    671, 7}, {   1343,10}, {    175, 8}, {    703, 7}, \
+    {   1407,11}, {     95,10}, {    191, 9}, {    383, 8}, \
+    {    767,10}, {    207, 9}, {    415, 8}, {    831, 7}, \
+    {   1663, 9}, {    447, 8}, {    895,12}, {     63,11}, \
+    {    127,10}, {    255, 9}, {    543, 8}, {   1087, 7}, \
+    {   2175, 9}, {    575, 8}, {   1151,10}, {    303, 9}, \
+    {    607, 8}, {   1215, 7}, {   2431,10}, {    319, 9}, \
+    {    639, 8}, {   1279, 9}, {    671, 8}, {   1343, 7}, \
+    {   2687,10}, {    351, 9}, {    703, 8}, {   1407,12}, \
+    {     95,11}, {    191,10}, {    383, 9}, {    767,11}, \
+    {    207,10}, {    415, 9}, {    831, 8}, {   1663,11}, \
+    {    223,10}, {    447, 9}, {    895,13}, {     63,11}, \
+    {    255,10}, {    543, 8}, {   2175,11}, {    287,10}, \
+    {    575, 9}, {   1151,10}, {    607, 9}, {   1215, 8}, \
+    {   2431,11}, {    319, 9}, {   1279,10}, {    671, 9}, \
+    {   1343, 8}, {   2687,11}, {    351,10}, {    703, 9}, \
+    {   1407,10}, {    735,12}, {    191,11}, {    383,10}, \
+    {    831, 9}, {   1663,12}, {    223,11}, {    447,10}, \
+    {    895,11}, {    479, 9}, {   1919, 8}, {   3839,12}, \
+    {    255,11}, {    511,10}, {   1023,11}, {    543,10}, \
+    {   1087, 9}, {   2175,12}, {    287,11}, {    575,10}, \
+    {   1151,11}, {    607,10}, {   1215, 9}, {   2431, 8}, \
+    {   4863,10}, {   1279,11}, {    671,10}, {   1343, 9}, \
+    {   2687,12}, {    351,11}, {    703,10}, {   1407,11}, \
+    {    735,13}, {    191, 9}, {   3071, 7}, {  12287,11}, \
+    {    799,12}, {    415,11}, {    831,10}, {   1663,12}, \
+    {    447, 8}, {   7167,12}, {    479, 9}, {   3839,14}, \
+    {    127,13}, {    255,12}, {    511,11}, {   1023,12}, \
+    {    543,10}, {   2175, 9}, {   4607,11}, {   1215,10}, \
+    {   2431,11}, {   1279,10}, {   2559,13}, {    383,12}, \
+    {    767,11}, {   1535,12}, {    799,10}, {   3199, 9}, \
+    {   6399,12}, {    895,13}, {    511,12}, {   1023,11}, \
+    {   2047,12}, {   1087,13}, {    575,12}, {   1151,10}, \
+    {   4607,13}, {    639,12}, {   1279,11}, {   2687,14}, \
+    {    383,13}, {    767,11}, {   3071,12}, {   1599,13}, \
+    {    895,12}, {   1791,11}, {   3583,13}, {    959,15}, \
+    {    255,12}, {   2175,13}, {   1215,14}, {    639,13}, \
+    {   1279,12}, {   2559,13}, {   1343,12}, {   2687,13}, \
+    {   1471,11}, {   5887,14}, {    767,13}, {   1535,12}, \
+    {   3071,13}, {   1599,12}, {   3199,13}, {   1663,12}, \
+    {   3327,13}, {   1727,14}, {    895,13}, {   1791,12}, \
+    {   3583,15}, {    511,14}, {   1023,13}, {   2175,14}, \
+    {   1151,12}, {   4607,13}, {   2431,14}, {   1279,13}, \
+    {   2687,14}, {   1407,13}, {   2815,15}, {    767,13}, \
+    {   3199,14}, {   1663,13}, {   3327,14}, {   1791,13}, \
+    {   3583,14}, {   1919,15}, {   1023,14}, {   2047,13}, \
+    {   4095,14}, {   2303,13}, {   4607,14}, {   2431,15}, \
+    {  32768,16}, {  65536,17}, { 131072,18}, { 262144,19}, \
+    { 524288,20}, {1048576,21}, {2097152,22}, {4194304,23}, \
+    {8388608,24} }
+#define SQR_FFT_TABLE3_SIZE 257
+#define SQR_FFT_THRESHOLD                 1856
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                 113
+#define MULLO_MUL_N_THRESHOLD             4658
+
+#define DC_DIV_QR_THRESHOLD                123
+#define DC_DIVAPPR_Q_THRESHOLD             372
+#define DC_BDIV_QR_THRESHOLD               142
+#define DC_BDIV_Q_THRESHOLD                312
+
+#define INV_MULMOD_BNM1_THRESHOLD           58
+#define INV_NEWTON_THRESHOLD               315
+#define INV_APPR_THRESHOLD                 315
+
+#define BINV_NEWTON_THRESHOLD              360
+#define REDC_1_TO_REDC_N_THRESHOLD         101
+
+#define MU_DIV_QR_THRESHOLD                979
+#define MU_DIVAPPR_Q_THRESHOLD            1142
+#define MUPI_DIV_QR_THRESHOLD               93
+#define MU_BDIV_QR_THRESHOLD               889
+#define MU_BDIV_Q_THRESHOLD               1187
+
+#define MATRIX22_STRASSEN_THRESHOLD          9
+#define HGCD_THRESHOLD                     234
+#define HGCD_APPR_THRESHOLD                300
+#define HGCD_REDUCE_THRESHOLD             1553
+#define GCD_DC_THRESHOLD                   684
+#define GCDEXT_DC_THRESHOLD                525
+#define JACOBI_BASE_METHOD                   2
+
+#define GET_STR_DC_THRESHOLD                21
+#define GET_STR_PRECOMPUTE_THRESHOLD        24
+#define SET_STR_DC_THRESHOLD              1951
+#define SET_STR_PRECOMPUTE_THRESHOLD      4034
diff --git a/third_party/gmp/mpn/pa64/lshift.asm b/third_party/gmp/mpn/pa64/lshift.asm
new file mode 100644
index 0000000..c0fc292
--- /dev/null
+++ b/third_party/gmp/mpn/pa64/lshift.asm
@@ -0,0 +1,114 @@
+dnl  HP-PA 2.0 mpn_lshift -- Left shift.
+
+dnl  Copyright 1997, 2000, 2002, 2003 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+dnl  This runs at 1.5 cycles/limb on PA8000 and 1.0 cycles/limb on PA8500.
+
+include(`../config.m4')
+
+dnl  INPUT PARAMETERS
+define(`rp',`%r26')
+define(`up',`%r25')
+define(`n',`%r24')
+define(`cnt',`%r23')
+
+ifdef(`HAVE_ABI_2_0w',
+`       .level  2.0w
+',`     .level  2.0
+')
+PROLOGUE(mpn_lshift)
+	shladd		n, 3, up, up
+	shladd		n, 3, rp, rp
+	subi		64, cnt, cnt
+	mtsar		cnt
+	ldd		-8(up), %r21
+	addib,=		-1, n, L(end)
+	shrpd		%r0, %r21, %sar, %r29	C compute carry out limb
+	depw,z		n, 31, 3, %r28		C r28 = (size & 7)
+	sub		%r0, n, %r22
+	depw,z		%r22, 28, 3, %r22	C r22 = 8 * (-size & 7)
+	add		up, %r22, up		C offset up
+	blr		%r28, %r0		C branch into jump table
+	add		rp, %r22, rp		C offset rp
+	b		L(0)
+	nop
+	b		L(1)
+	copy		%r21, %r20
+	b		L(2)
+	nop
+	b		L(3)
+	copy		%r21, %r20
+	b		L(4)
+	nop
+	b		L(5)
+	copy		%r21, %r20
+	b		L(6)
+	nop
+	b		L(7)
+	copy		%r21, %r20
+
+LDEF(loop)
+LDEF(0)	ldd		-16(up), %r20
+	shrpd		%r21, %r20, %sar, %r21
+	std		%r21, -8(rp)
+LDEF(7)	ldd		-24(up), %r21
+	shrpd		%r20, %r21, %sar, %r20
+	std		%r20, -16(rp)
+LDEF(6)	ldd		-32(up), %r20
+	shrpd		%r21, %r20, %sar, %r21
+	std		%r21, -24(rp)
+LDEF(5)	ldd		-40(up), %r21
+	shrpd		%r20, %r21, %sar, %r20
+	std		%r20, -32(rp)
+LDEF(4)	ldd		-48(up), %r20
+	shrpd		%r21, %r20, %sar, %r21
+	std		%r21, -40(rp)
+LDEF(3)	ldd		-56(up), %r21
+	shrpd		%r20, %r21, %sar, %r20
+	std		%r20, -48(rp)
+LDEF(2)	ldd		-64(up), %r20
+	shrpd		%r21, %r20, %sar, %r21
+	std		%r21, -56(rp)
+LDEF(1)	ldd		-72(up), %r21
+	ldo		-64(up), up
+	shrpd		%r20, %r21, %sar, %r20
+	std		%r20, -64(rp)
+	addib,>		-8, n, L(loop)
+	ldo		-64(rp), rp
+
+LDEF(end)
+	shrpd		%r21, %r0, %sar, %r21
+	std		%r21, -8(rp)
+	bve		(%r2)
+ifdef(`HAVE_ABI_2_0w',
+`	copy		%r29,%r28
+',`	extrd,u		%r29, 31, 32, %r28
+')
+EPILOGUE(mpn_lshift)
diff --git a/third_party/gmp/mpn/pa64/mul_1.asm b/third_party/gmp/mpn/pa64/mul_1.asm
new file mode 100644
index 0000000..6935c23
--- /dev/null
+++ b/third_party/gmp/mpn/pa64/mul_1.asm
@@ -0,0 +1,646 @@
+dnl  HP-PA 2.0 64-bit mpn_mul_1 -- Multiply a limb vector with a limb and store
+dnl  the result in a second limb vector.
+
+dnl  Copyright 1998-2000, 2002, 2003 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		    cycles/limb
+C 8000,8200:		6.5
+C 8500,8600,8700:	5.625
+
+C  The feed-in and wind-down code has not yet been scheduled.  Many cycles
+C  could be saved there per call.
+
+C  DESCRIPTION:
+C  The main loop "BIG" is 4-way unrolled, mainly to allow
+C  effective use of ADD,DC.  Delays in moving data via the cache from the FP
+C  registers to the IU registers, have demanded a deep software pipeline, and
+C  a lot of stack slots for partial products in flight.
+C
+C  CODE STRUCTURE:
+C  save-some-registers
+C  do 0, 1, 2, or 3 limbs
+C  if done, restore-some-regs and return
+C  save-many-regs
+C  do 4, 8, ... limb
+C  restore-all-regs
+
+C  STACK LAYOUT:
+C  HP-PA stack grows upwards.  We could allocate 8 fewer slots by using the
+C  slots marked FREE, as well as some slots in the caller's "frame marker".
+C
+C -00 <- r30
+C -08  FREE
+C -10  tmp
+C -18  tmp
+C -20  tmp
+C -28  tmp
+C -30  tmp
+C -38  tmp
+C -40  tmp
+C -48  tmp
+C -50  tmp
+C -58  tmp
+C -60  tmp
+C -68  tmp
+C -70  tmp
+C -78  tmp
+C -80  tmp
+C -88  tmp
+C -90  FREE
+C -98  FREE
+C -a0  FREE
+C -a8  FREE
+C -b0  r13
+C -b8  r12
+C -c0  r11
+C -c8  r10
+C -d0  r8
+C -d8  r8
+C -e0  r7
+C -e8  r6
+C -f0  r5
+C -f8  r4
+C -100 r3
+C  Previous frame:
+C  [unused area]
+C -38/-138 vlimb home slot.  For 2.0N, the vlimb arg will arrive here.
+
+
+include(`../config.m4')
+
+C INPUT PARAMETERS:
+define(`rp',`%r26')	C
+define(`up',`%r25')	C
+define(`n',`%r24')	C
+define(`vlimb',`%r23')	C
+
+define(`climb',`%r23')	C
+
+ifdef(`HAVE_ABI_2_0w',
+`	.level	2.0w
+',`	.level	2.0
+')
+PROLOGUE(mpn_mul_1)
+
+ifdef(`HAVE_ABI_2_0w',
+`	std		vlimb, -0x38(%r30)	C store vlimb into "home" slot
+')
+	std,ma		%r3, 0x100(%r30)
+	std		%r4, -0xf8(%r30)
+	std		%r5, -0xf0(%r30)
+	ldo		0(%r0), climb		C clear climb
+	fldd		-0x138(%r30), %fr8	C put vlimb in fp register
+
+define(`p032a1',`%r1')	C
+define(`p032a2',`%r19')	C
+
+define(`m032',`%r20')	C
+define(`m096',`%r21')	C
+
+define(`p000a',`%r22')	C
+define(`p064a',`%r29')	C
+
+define(`s000',`%r31')	C
+
+define(`ma000',`%r4')	C
+define(`ma064',`%r20')	C
+
+C define(`r000',`%r3')	C	FIXME don't save r3 for n < 4.
+
+	extrd,u		n, 63, 2, %r5
+	cmpb,=		%r5, %r0, L(BIG)
+	nop
+
+	fldd		0(up), %fr4
+	ldo		8(up), up
+	xmpyu		%fr8R, %fr4L, %fr22
+	xmpyu		%fr8L, %fr4R, %fr23
+	fstd		%fr22, -0x78(%r30)	C mid product to  -0x78..-0x71
+	xmpyu		%fr8R, %fr4R, %fr24
+	xmpyu		%fr8L, %fr4L, %fr25
+	fstd		%fr23, -0x70(%r30)	C mid product to  -0x70..-0x69
+	fstd		%fr24, -0x80(%r30)	C low product to  -0x80..-0x79
+	addib,<>	-1, %r5, L(two_or_more)
+	fstd		%fr25, -0x68(%r30)	C high product to -0x68..-0x61
+LDEF(one)
+	ldd		-0x78(%r30), p032a1
+	ldd		-0x70(%r30), p032a2
+	ldd		-0x80(%r30), p000a
+	b		L(0_one_out)
+	ldd		-0x68(%r30), p064a
+
+LDEF(two_or_more)
+	fldd		0(up), %fr4
+	ldo		8(up), up
+	xmpyu		%fr8R, %fr4L, %fr22
+	xmpyu		%fr8L, %fr4R, %fr23
+	ldd		-0x78(%r30), p032a1
+	fstd		%fr22, -0x78(%r30)	C mid product to  -0x78..-0x71
+	xmpyu		%fr8R, %fr4R, %fr24
+	xmpyu		%fr8L, %fr4L, %fr25
+	ldd		-0x70(%r30), p032a2
+	fstd		%fr23, -0x70(%r30)	C mid product to  -0x70..-0x69
+	ldd		-0x80(%r30), p000a
+	fstd		%fr24, -0x80(%r30)	C low product to  -0x80..-0x79
+	ldd		-0x68(%r30), p064a
+	addib,<>	-1, %r5, L(three_or_more)
+	fstd		%fr25, -0x68(%r30)	C high product to -0x68..-0x61
+LDEF(two)
+	add		p032a1, p032a2, m032
+	add,dc		%r0, %r0, m096
+	depd,z		m032, 31, 32, ma000
+	extrd,u		m032, 31, 32, ma064
+	b		L(0_two_out)
+	depd		m096, 31, 32, ma064
+
+LDEF(three_or_more)
+	fldd		0(up), %fr4
+	add		p032a1, p032a2, m032
+	add,dc		%r0, %r0, m096
+	depd,z		m032, 31, 32, ma000
+	extrd,u		m032, 31, 32, ma064
+C	addib,=		-1, %r5, L(0_out)
+	depd		m096, 31, 32, ma064
+LDEF(loop0)
+C	xmpyu		%fr8R, %fr4L, %fr22
+C	xmpyu		%fr8L, %fr4R, %fr23
+C	ldd		-0x78(%r30), p032a1
+C	fstd		%fr22, -0x78(%r30)	C mid product to  -0x78..-0x71
+C
+C	xmpyu		%fr8R, %fr4R, %fr24
+C	xmpyu		%fr8L, %fr4L, %fr25
+C	ldd		-0x70(%r30), p032a2
+C	fstd		%fr23, -0x70(%r30)	C mid product to  -0x70..-0x69
+C
+C	ldo		8(rp), rp
+C	add		climb, p000a, s000
+C	ldd		-0x80(%r30), p000a
+C	fstd		%fr24, -0x80(%r30)	C low product to  -0x80..-0x79
+C
+C	add,dc		p064a, %r0, climb
+C	ldo		8(up), up
+C	ldd		-0x68(%r30), p064a
+C	fstd		%fr25, -0x68(%r30)	C high product to -0x68..-0x61
+C
+C	add		ma000, s000, s000
+C	add,dc		ma064, climb, climb
+C	fldd		0(up), %fr4
+C
+C	std		s000, -8(rp)
+C
+C	add		p032a1, p032a2, m032
+C	add,dc		%r0, %r0, m096
+C
+C	depd,z		m032, 31, 32, ma000
+C	extrd,u		m032, 31, 32, ma064
+C	addib,<>	-1, %r5, L(loop0)
+C	depd		m096, 31, 32, ma064
+LDEF(0_out)
+	ldo		8(up), up
+	xmpyu		%fr8R, %fr4L, %fr22
+	xmpyu		%fr8L, %fr4R, %fr23
+	ldd		-0x78(%r30), p032a1
+	fstd		%fr22, -0x78(%r30)	C mid product to  -0x78..-0x71
+	xmpyu		%fr8R, %fr4R, %fr24
+	xmpyu		%fr8L, %fr4L, %fr25
+	ldd		-0x70(%r30), p032a2
+	fstd		%fr23, -0x70(%r30)	C mid product to  -0x70..-0x69
+	ldo		8(rp), rp
+	add		climb, p000a, s000
+	ldd		-0x80(%r30), p000a
+	fstd		%fr24, -0x80(%r30)	C low product to  -0x80..-0x79
+	add,dc		p064a, %r0, climb
+	ldd		-0x68(%r30), p064a
+	fstd		%fr25, -0x68(%r30)	C high product to -0x68..-0x61
+	add		ma000, s000, s000
+	add,dc		ma064, climb, climb
+	std		s000, -8(rp)
+	add		p032a1, p032a2, m032
+	add,dc		%r0, %r0, m096
+	depd,z		m032, 31, 32, ma000
+	extrd,u		m032, 31, 32, ma064
+	depd		m096, 31, 32, ma064
+LDEF(0_two_out)
+	ldd		-0x78(%r30), p032a1
+	ldd		-0x70(%r30), p032a2
+	ldo		8(rp), rp
+	add		climb, p000a, s000
+	ldd		-0x80(%r30), p000a
+	add,dc		p064a, %r0, climb
+	ldd		-0x68(%r30), p064a
+	add		ma000, s000, s000
+	add,dc		ma064, climb, climb
+	std		s000, -8(rp)
+LDEF(0_one_out)
+	add		p032a1, p032a2, m032
+	add,dc		%r0, %r0, m096
+	depd,z		m032, 31, 32, ma000
+	extrd,u		m032, 31, 32, ma064
+	depd		m096, 31, 32, ma064
+
+	add		climb, p000a, s000
+	add,dc		p064a, %r0, climb
+	add		ma000, s000, s000
+	add,dc		ma064, climb, climb
+	std		s000, 0(rp)
+
+	cmpib,>=	4, n, L(done)
+	ldo		8(rp), rp
+
+C 4-way unrolled code.
+
+LDEF(BIG)
+
+define(`p032a1',`%r1')	C
+define(`p032a2',`%r19')	C
+define(`p096b1',`%r20')	C
+define(`p096b2',`%r21')	C
+define(`p160c1',`%r22')	C
+define(`p160c2',`%r29')	C
+define(`p224d1',`%r31')	C
+define(`p224d2',`%r3')	C
+			C
+define(`m032',`%r4')	C
+define(`m096',`%r5')	C
+define(`m160',`%r6')	C
+define(`m224',`%r7')	C
+define(`m288',`%r8')	C
+			C
+define(`p000a',`%r1')	C
+define(`p064a',`%r19')	C
+define(`p064b',`%r20')	C
+define(`p128b',`%r21')	C
+define(`p128c',`%r22')	C
+define(`p192c',`%r29')	C
+define(`p192d',`%r31')	C
+define(`p256d',`%r3')	C
+			C
+define(`s000',`%r10')	C
+define(`s064',`%r11')	C
+define(`s128',`%r12')	C
+define(`s192',`%r13')	C
+			C
+define(`ma000',`%r9')	C
+define(`ma064',`%r4')	C
+define(`ma128',`%r5')	C
+define(`ma192',`%r6')	C
+define(`ma256',`%r7')	C
+
+	std		%r6, -0xe8(%r30)
+	std		%r7, -0xe0(%r30)
+	std		%r8, -0xd8(%r30)
+	std		%r9, -0xd0(%r30)
+	std		%r10, -0xc8(%r30)
+	std		%r11, -0xc0(%r30)
+	std		%r12, -0xb8(%r30)
+	std		%r13, -0xb0(%r30)
+
+ifdef(`HAVE_ABI_2_0w',
+`	extrd,u		n, 61, 62, n		C right shift 2
+',`	extrd,u		n, 61, 30, n		C right shift 2, zero extend
+')
+
+LDEF(4_or_more)
+	fldd		0(up), %fr4
+	fldd		8(up), %fr5
+	fldd		16(up), %fr6
+	fldd		24(up), %fr7
+	xmpyu		%fr8R, %fr4L, %fr22
+	xmpyu		%fr8L, %fr4R, %fr23
+	xmpyu		%fr8R, %fr5L, %fr24
+	xmpyu		%fr8L, %fr5R, %fr25
+	xmpyu		%fr8R, %fr6L, %fr26
+	xmpyu		%fr8L, %fr6R, %fr27
+	fstd		%fr22, -0x78(%r30)	C mid product to  -0x78..-0x71
+	xmpyu		%fr8R, %fr7L, %fr28
+	xmpyu		%fr8L, %fr7R, %fr29
+	fstd		%fr23, -0x70(%r30)	C mid product to  -0x70..-0x69
+	xmpyu		%fr8R, %fr4R, %fr30
+	xmpyu		%fr8L, %fr4L, %fr31
+	fstd		%fr24, -0x38(%r30)	C mid product to  -0x38..-0x31
+	xmpyu		%fr8R, %fr5R, %fr22
+	xmpyu		%fr8L, %fr5L, %fr23
+	fstd		%fr25, -0x30(%r30)	C mid product to  -0x30..-0x29
+	xmpyu		%fr8R, %fr6R, %fr24
+	xmpyu		%fr8L, %fr6L, %fr25
+	fstd		%fr26, -0x58(%r30)	C mid product to  -0x58..-0x51
+	xmpyu		%fr8R, %fr7R, %fr26
+	fstd		%fr27, -0x50(%r30)	C mid product to  -0x50..-0x49
+	addib,<>	-1, n, L(8_or_more)
+	xmpyu		%fr8L, %fr7L, %fr27
+	fstd		%fr28, -0x18(%r30)	C mid product to  -0x18..-0x11
+	fstd		%fr29, -0x10(%r30)	C mid product to  -0x10..-0x09
+	fstd		%fr30, -0x80(%r30)	C low product to  -0x80..-0x79
+	fstd		%fr31, -0x68(%r30)	C high product to -0x68..-0x61
+	fstd		%fr22, -0x40(%r30)	C low product to  -0x40..-0x39
+	fstd		%fr23, -0x28(%r30)	C high product to -0x28..-0x21
+	fstd		%fr24, -0x60(%r30)	C low product to  -0x60..-0x59
+	fstd		%fr25, -0x48(%r30)	C high product to -0x48..-0x41
+	fstd		%fr26, -0x20(%r30)	C low product to  -0x20..-0x19
+	fstd		%fr27, -0x88(%r30)	C high product to -0x88..-0x81
+	ldd		-0x78(%r30), p032a1
+	ldd		-0x70(%r30), p032a2
+	ldd		-0x38(%r30), p096b1
+	ldd		-0x30(%r30), p096b2
+	ldd		-0x58(%r30), p160c1
+	ldd		-0x50(%r30), p160c2
+	ldd		-0x18(%r30), p224d1
+	ldd		-0x10(%r30), p224d2
+	b		L(end1)
+	nop
+
+LDEF(8_or_more)
+	fstd		%fr28, -0x18(%r30)	C mid product to  -0x18..-0x11
+	fstd		%fr29, -0x10(%r30)	C mid product to  -0x10..-0x09
+	ldo		32(up), up
+	fstd		%fr30, -0x80(%r30)	C low product to  -0x80..-0x79
+	fstd		%fr31, -0x68(%r30)	C high product to -0x68..-0x61
+	fstd		%fr22, -0x40(%r30)	C low product to  -0x40..-0x39
+	fstd		%fr23, -0x28(%r30)	C high product to -0x28..-0x21
+	fstd		%fr24, -0x60(%r30)	C low product to  -0x60..-0x59
+	fstd		%fr25, -0x48(%r30)	C high product to -0x48..-0x41
+	fstd		%fr26, -0x20(%r30)	C low product to  -0x20..-0x19
+	fstd		%fr27, -0x88(%r30)	C high product to -0x88..-0x81
+	fldd		0(up), %fr4
+	fldd		8(up), %fr5
+	fldd		16(up), %fr6
+	fldd		24(up), %fr7
+	xmpyu		%fr8R, %fr4L, %fr22
+	ldd		-0x78(%r30), p032a1
+	xmpyu		%fr8L, %fr4R, %fr23
+	xmpyu		%fr8R, %fr5L, %fr24
+	ldd		-0x70(%r30), p032a2
+	xmpyu		%fr8L, %fr5R, %fr25
+	xmpyu		%fr8R, %fr6L, %fr26
+	ldd		-0x38(%r30), p096b1
+	xmpyu		%fr8L, %fr6R, %fr27
+	fstd		%fr22, -0x78(%r30)	C mid product to  -0x78..-0x71
+	xmpyu		%fr8R, %fr7L, %fr28
+	ldd		-0x30(%r30), p096b2
+	xmpyu		%fr8L, %fr7R, %fr29
+	fstd		%fr23, -0x70(%r30)	C mid product to  -0x70..-0x69
+	xmpyu		%fr8R, %fr4R, %fr30
+	ldd		-0x58(%r30), p160c1
+	xmpyu		%fr8L, %fr4L, %fr31
+	fstd		%fr24, -0x38(%r30)	C mid product to  -0x38..-0x31
+	xmpyu		%fr8R, %fr5R, %fr22
+	ldd		-0x50(%r30), p160c2
+	xmpyu		%fr8L, %fr5L, %fr23
+	fstd		%fr25, -0x30(%r30)	C mid product to  -0x30..-0x29
+	xmpyu		%fr8R, %fr6R, %fr24
+	ldd		-0x18(%r30), p224d1
+	xmpyu		%fr8L, %fr6L, %fr25
+	fstd		%fr26, -0x58(%r30)	C mid product to  -0x58..-0x51
+	xmpyu		%fr8R, %fr7R, %fr26
+	ldd		-0x10(%r30), p224d2
+	fstd		%fr27, -0x50(%r30)	C mid product to  -0x50..-0x49
+	addib,=		-1, n, L(end2)
+	xmpyu		%fr8L, %fr7L, %fr27
+LDEF(loop)
+	add		p032a1, p032a2, m032
+	ldd		-0x80(%r30), p000a
+	add,dc		p096b1, p096b2, m096
+	fstd		%fr28, -0x18(%r30)	C mid product to  -0x18..-0x11
+
+	add,dc		p160c1, p160c2, m160
+	ldd		-0x68(%r30), p064a
+	add,dc		p224d1, p224d2, m224
+	fstd		%fr29, -0x10(%r30)	C mid product to  -0x10..-0x09
+
+	add,dc		%r0, %r0, m288
+	ldd		-0x40(%r30), p064b
+	ldo		32(up), up
+	fstd		%fr30, -0x80(%r30)	C low product to  -0x80..-0x79
+
+	depd,z		m032, 31, 32, ma000
+	ldd		-0x28(%r30), p128b
+	extrd,u		m032, 31, 32, ma064
+	fstd		%fr31, -0x68(%r30)	C high product to -0x68..-0x61
+
+	depd		m096, 31, 32, ma064
+	ldd		-0x60(%r30), p128c
+	extrd,u		m096, 31, 32, ma128
+	fstd		%fr22, -0x40(%r30)	C low product to  -0x40..-0x39
+
+	depd		m160, 31, 32, ma128
+	ldd		-0x48(%r30), p192c
+	extrd,u		m160, 31, 32, ma192
+	fstd		%fr23, -0x28(%r30)	C high product to -0x28..-0x21
+
+	depd		m224, 31, 32, ma192
+	ldd		-0x20(%r30), p192d
+	extrd,u		m224, 31, 32, ma256
+	fstd		%fr24, -0x60(%r30)	C low product to  -0x60..-0x59
+
+	depd		m288, 31, 32, ma256
+	ldd		-0x88(%r30), p256d
+	add		climb, p000a, s000
+	fstd		%fr25, -0x48(%r30)	C high product to -0x48..-0x41
+
+	add,dc		p064a, p064b, s064
+	add,dc		p128b, p128c, s128
+	fstd		%fr26, -0x20(%r30)	C low product to  -0x20..-0x19
+
+	add,dc		p192c, p192d, s192
+	add,dc		p256d, %r0, climb
+	fstd		%fr27, -0x88(%r30)	C high product to -0x88..-0x81
+
+	add		ma000, s000, s000	C accum mid 0
+	fldd		0(up), %fr4
+	add,dc		ma064, s064, s064	C accum mid 1
+	std		s000, 0(rp)
+
+	add,dc		ma128, s128, s128	C accum mid 2
+	fldd		8(up), %fr5
+	add,dc		ma192, s192, s192	C accum mid 3
+	std		s064, 8(rp)
+
+	add,dc		ma256, climb, climb
+	fldd		16(up), %fr6
+	std		s128, 16(rp)
+
+	xmpyu		%fr8R, %fr4L, %fr22
+	ldd		-0x78(%r30), p032a1
+	xmpyu		%fr8L, %fr4R, %fr23
+	fldd		24(up), %fr7
+
+	xmpyu		%fr8R, %fr5L, %fr24
+	ldd		-0x70(%r30), p032a2
+	xmpyu		%fr8L, %fr5R, %fr25
+	std		s192, 24(rp)
+
+	xmpyu		%fr8R, %fr6L, %fr26
+	ldd		-0x38(%r30), p096b1
+	xmpyu		%fr8L, %fr6R, %fr27
+	fstd		%fr22, -0x78(%r30)	C mid product to  -0x78..-0x71
+
+	xmpyu		%fr8R, %fr7L, %fr28
+	ldd		-0x30(%r30), p096b2
+	xmpyu		%fr8L, %fr7R, %fr29
+	fstd		%fr23, -0x70(%r30)	C mid product to  -0x70..-0x69
+
+	xmpyu		%fr8R, %fr4R, %fr30
+	ldd		-0x58(%r30), p160c1
+	xmpyu		%fr8L, %fr4L, %fr31
+	fstd		%fr24, -0x38(%r30)	C mid product to  -0x38..-0x31
+
+	xmpyu		%fr8R, %fr5R, %fr22
+	ldd		-0x50(%r30), p160c2
+	xmpyu		%fr8L, %fr5L, %fr23
+	fstd		%fr25, -0x30(%r30)	C mid product to  -0x30..-0x29
+
+	xmpyu		%fr8R, %fr6R, %fr24
+	ldd		-0x18(%r30), p224d1
+	xmpyu		%fr8L, %fr6L, %fr25
+	fstd		%fr26, -0x58(%r30)	C mid product to  -0x58..-0x51
+
+	xmpyu		%fr8R, %fr7R, %fr26
+	ldd		-0x10(%r30), p224d2
+	fstd		%fr27, -0x50(%r30)	C mid product to  -0x50..-0x49
+	xmpyu		%fr8L, %fr7L, %fr27
+
+	addib,<>	-1, n, L(loop)
+	ldo		32(rp), rp
+
+LDEF(end2)
+	add		p032a1, p032a2, m032
+	ldd		-0x80(%r30), p000a
+	add,dc		p096b1, p096b2, m096
+	fstd		%fr28, -0x18(%r30)	C mid product to  -0x18..-0x11
+	add,dc		p160c1, p160c2, m160
+	ldd		-0x68(%r30), p064a
+	add,dc		p224d1, p224d2, m224
+	fstd		%fr29, -0x10(%r30)	C mid product to  -0x10..-0x09
+	add,dc		%r0, %r0, m288
+	ldd		-0x40(%r30), p064b
+	fstd		%fr30, -0x80(%r30)	C low product to  -0x80..-0x79
+	depd,z		m032, 31, 32, ma000
+	ldd		-0x28(%r30), p128b
+	extrd,u		m032, 31, 32, ma064
+	fstd		%fr31, -0x68(%r30)	C high product to -0x68..-0x61
+	depd		m096, 31, 32, ma064
+	ldd		-0x60(%r30), p128c
+	extrd,u		m096, 31, 32, ma128
+	fstd		%fr22, -0x40(%r30)	C low product to  -0x40..-0x39
+	depd		m160, 31, 32, ma128
+	ldd		-0x48(%r30), p192c
+	extrd,u		m160, 31, 32, ma192
+	fstd		%fr23, -0x28(%r30)	C high product to -0x28..-0x21
+	depd		m224, 31, 32, ma192
+	ldd		-0x20(%r30), p192d
+	extrd,u		m224, 31, 32, ma256
+	fstd		%fr24, -0x60(%r30)	C low product to  -0x60..-0x59
+	depd		m288, 31, 32, ma256
+	ldd		-0x88(%r30), p256d
+	add		climb, p000a, s000
+	fstd		%fr25, -0x48(%r30)	C high product to -0x48..-0x41
+	add,dc		p064a, p064b, s064
+	add,dc		p128b, p128c, s128
+	fstd		%fr26, -0x20(%r30)	C low product to  -0x20..-0x19
+	add,dc		p192c, p192d, s192
+	add,dc		p256d, %r0, climb
+	fstd		%fr27, -0x88(%r30)	C high product to -0x88..-0x81
+	add		ma000, s000, s000	C accum mid 0
+	add,dc		ma064, s064, s064	C accum mid 1
+	add,dc		ma128, s128, s128	C accum mid 2
+	add,dc		ma192, s192, s192	C accum mid 3
+	add,dc		ma256, climb, climb
+	std		s000, 0(rp)
+	std		s064, 8(rp)
+	ldd		-0x78(%r30), p032a1
+	std		s128, 16(rp)
+	ldd		-0x70(%r30), p032a2
+	std		s192, 24(rp)
+	ldd		-0x38(%r30), p096b1
+	ldd		-0x30(%r30), p096b2
+	ldd		-0x58(%r30), p160c1
+	ldd		-0x50(%r30), p160c2
+	ldd		-0x18(%r30), p224d1
+	ldd		-0x10(%r30), p224d2
+	ldo		32(rp), rp
+
+LDEF(end1)
+	add		p032a1, p032a2, m032
+	ldd		-0x80(%r30), p000a
+	add,dc		p096b1, p096b2, m096
+	add,dc		p160c1, p160c2, m160
+	ldd		-0x68(%r30), p064a
+	add,dc		p224d1, p224d2, m224
+	add,dc		%r0, %r0, m288
+	ldd		-0x40(%r30), p064b
+	depd,z		m032, 31, 32, ma000
+	ldd		-0x28(%r30), p128b
+	extrd,u		m032, 31, 32, ma064
+	depd		m096, 31, 32, ma064
+	ldd		-0x60(%r30), p128c
+	extrd,u		m096, 31, 32, ma128
+	depd		m160, 31, 32, ma128
+	ldd		-0x48(%r30), p192c
+	extrd,u		m160, 31, 32, ma192
+	depd		m224, 31, 32, ma192
+	ldd		-0x20(%r30), p192d
+	extrd,u		m224, 31, 32, ma256
+	depd		m288, 31, 32, ma256
+	ldd		-0x88(%r30), p256d
+	add		climb, p000a, s000
+	add,dc		p064a, p064b, s064
+	add,dc		p128b, p128c, s128
+	add,dc		p192c, p192d, s192
+	add,dc		p256d, %r0, climb
+	add		ma000, s000, s000	C accum mid 0
+	add,dc		ma064, s064, s064	C accum mid 1
+	add,dc		ma128, s128, s128	C accum mid 2
+	add,dc		ma192, s192, s192	C accum mid 3
+	add,dc		ma256, climb, climb
+	std		s000, 0(rp)
+	std		s064, 8(rp)
+	std		s128, 16(rp)
+	std		s192, 24(rp)
+
+	ldd		-0xb0(%r30), %r13
+	ldd		-0xb8(%r30), %r12
+	ldd		-0xc0(%r30), %r11
+	ldd		-0xc8(%r30), %r10
+	ldd		-0xd0(%r30), %r9
+	ldd		-0xd8(%r30), %r8
+	ldd		-0xe0(%r30), %r7
+	ldd		-0xe8(%r30), %r6
+LDEF(done)
+ifdef(`HAVE_ABI_2_0w',
+`	copy		climb, %r28
+',`	extrd,u		climb, 63, 32, %r29
+	extrd,u		climb, 31, 32, %r28
+')
+	ldd		-0xf0(%r30), %r5
+	ldd		-0xf8(%r30), %r4
+	bve		(%r2)
+	ldd,mb		-0x100(%r30), %r3
+EPILOGUE(mpn_mul_1)
diff --git a/third_party/gmp/mpn/pa64/rshift.asm b/third_party/gmp/mpn/pa64/rshift.asm
new file mode 100644
index 0000000..cfc242e
--- /dev/null
+++ b/third_party/gmp/mpn/pa64/rshift.asm
@@ -0,0 +1,111 @@
+dnl  HP-PA 2.0 mpn_rshift -- Right shift.
+
+dnl  Copyright 1997, 2000, 2002, 2003 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+dnl  This runs at 1.5 cycles/limb on PA8000 and 1.0 cycles/limb on PA8500.
+
+include(`../config.m4')
+
+dnl  INPUT PARAMETERS
+define(`rp',`%r26')
+define(`up',`%r25')
+define(`n',`%r24')
+define(`cnt',`%r23')
+
+ifdef(`HAVE_ABI_2_0w',
+`       .level  2.0w
+',`     .level  2.0
+')
+PROLOGUE(mpn_rshift)
+	mtsar		cnt
+	ldd		0(up), %r21
+	addib,=		-1, n, L(end)
+	shrpd		%r21, %r0, %sar, %r29	C compute carry out limb
+	depw,z		n, 31, 3, %r28		C r28 = (size & 7)
+	sub		%r0, n, %r22
+	depw,z		%r22, 28, 3, %r22	C r22 = 8 * (-size & 7)
+	sub		up, %r22, up		C offset up
+	blr		%r28, %r0		C branch into jump table
+	sub		rp, %r22, rp		C offset rp
+	b		L(0)
+	nop
+	b		L(1)
+	copy		%r21, %r20
+	b		L(2)
+	nop
+	b		L(3)
+	copy		%r21, %r20
+	b		L(4)
+	nop
+	b		L(5)
+	copy		%r21, %r20
+	b		L(6)
+	nop
+	b		L(7)
+	copy		%r21, %r20
+
+LDEF(loop)
+LDEF(0)	ldd		8(up), %r20
+	shrpd		%r20, %r21, %sar, %r21
+	std		%r21, 0(rp)
+LDEF(7)	ldd		16(up), %r21
+	shrpd		%r21, %r20, %sar, %r20
+	std		%r20, 8(rp)
+LDEF(6)	ldd		24(up), %r20
+	shrpd		%r20, %r21, %sar, %r21
+	std		%r21, 16(rp)
+LDEF(5)	ldd		32(up), %r21
+	shrpd		%r21, %r20, %sar, %r20
+	std		%r20, 24(rp)
+LDEF(4)	ldd		40(up), %r20
+	shrpd		%r20, %r21, %sar, %r21
+	std		%r21, 32(rp)
+LDEF(3)	ldd		48(up), %r21
+	shrpd		%r21, %r20, %sar, %r20
+	std		%r20, 40(rp)
+LDEF(2)	ldd		56(up), %r20
+	shrpd		%r20, %r21, %sar, %r21
+	std		%r21, 48(rp)
+LDEF(1)	ldd		64(up), %r21
+	ldo		64(up), up
+	shrpd		%r21, %r20, %sar, %r20
+	std		%r20, 56(rp)
+	addib,>		-8, n, L(loop)
+	ldo		64(rp), rp
+
+LDEF(end)
+	shrpd		%r0, %r21, %sar, %r21
+	std		%r21, 0(rp)
+	bve		(%r2)
+ifdef(`HAVE_ABI_2_0w',
+`	copy		%r29,%r28
+',`	extrd,u		%r29, 31, 32, %r28
+')
+EPILOGUE(mpn_rshift)
diff --git a/third_party/gmp/mpn/pa64/sqr_diagonal.asm b/third_party/gmp/mpn/pa64/sqr_diagonal.asm
new file mode 100644
index 0000000..f6fadc9
--- /dev/null
+++ b/third_party/gmp/mpn/pa64/sqr_diagonal.asm
@@ -0,0 +1,191 @@
+dnl  HP-PA 2.0 64-bit mpn_sqr_diagonal.
+
+dnl  Copyright 2001-2003 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+dnl  This code runs at 7.25 cycles/limb on PA8000 and 7.75 cycles/limb on
+dnl  PA8500.  The cache would saturate at 5 cycles/limb, so there is some room
+dnl  for optimization.
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+define(`rp',`%r26')
+define(`up',`%r25')
+define(`n',`%r24')
+
+define(`p00',`%r28')
+define(`p32',`%r29')
+define(`p64',`%r31')
+define(`t0',`%r19')
+define(`t1',`%r20')
+
+ifdef(`HAVE_ABI_2_0w',
+`	.level	2.0w
+',`	.level	2.0
+')
+PROLOGUE(mpn_sqr_diagonal)
+	ldo		128(%r30),%r30
+
+	fldds,ma	8(up),%fr8
+	addib,=		-1,n,L(end1)
+	nop
+	fldds,ma	8(up),%fr4
+	xmpyu		%fr8l,%fr8r,%fr10
+	fstd		%fr10,-120(%r30)
+	xmpyu		%fr8r,%fr8r,%fr9
+	fstd		%fr9,0(rp)
+	xmpyu		%fr8l,%fr8l,%fr11
+	fstd		%fr11,8(rp)
+	addib,=		-1,n,L(end2)
+	ldo		16(rp),rp
+
+LDEF(loop)
+	fldds,ma	8(up),%fr8		C load next up limb
+	xmpyu		%fr4l,%fr4r,%fr6
+	fstd		%fr6,-128(%r30)
+	xmpyu		%fr4r,%fr4r,%fr5	C multiply in fp regs
+	fstd		%fr5,0(rp)
+	xmpyu		%fr4l,%fr4l,%fr7
+	fstd		%fr7,8(rp)
+	ldd		-120(%r30),p32
+	ldd		-16(rp),p00		C accumulate in int regs
+	ldd		-8(rp),p64
+	depd,z		p32,30,31,t0
+	add		t0,p00,p00
+	std		p00,-16(rp)
+	extrd,u		p32,32,33,t1
+	add,dc		t1,p64,p64
+	std		p64,-8(rp)
+	addib,=		-1,n,L(exit)
+	ldo		16(rp),rp
+
+	fldds,ma	8(up),%fr4
+	xmpyu		%fr8l,%fr8r,%fr10
+	fstd		%fr10,-120(%r30)
+	xmpyu		%fr8r,%fr8r,%fr9
+	fstd		%fr9,0(rp)
+	xmpyu		%fr8l,%fr8l,%fr11
+	fstd		%fr11,8(rp)
+	ldd		-128(%r30),p32
+	ldd		-16(rp),p00
+	ldd		-8(rp),p64
+	depd,z		p32,30,31,t0
+	add		t0,p00,p00
+	std		p00,-16(rp)
+	extrd,u		p32,32,33,t1
+	add,dc		t1,p64,p64
+	std		p64,-8(rp)
+	addib,<>	-1,n,L(loop)
+	ldo		16(rp),rp
+
+LDEF(end2)
+	xmpyu		%fr4l,%fr4r,%fr6
+	fstd		%fr6,-128(%r30)
+	xmpyu		%fr4r,%fr4r,%fr5
+	fstd		%fr5,0(rp)
+	xmpyu		%fr4l,%fr4l,%fr7
+	fstd		%fr7,8(rp)
+	ldd		-120(%r30),p32
+	ldd		-16(rp),p00
+	ldd		-8(rp),p64
+	depd,z		p32,30,31,t0
+	add		t0,p00,p00
+	std		p00,-16(rp)
+	extrd,u		p32,32,33,t1
+	add,dc		t1,p64,p64
+	std		p64,-8(rp)
+	ldo		16(rp),rp
+	ldd		-128(%r30),p32
+	ldd		-16(rp),p00
+	ldd		-8(rp),p64
+	depd,z		p32,30,31,t0
+	add		t0,p00,p00
+	std		p00,-16(rp)
+	extrd,u		p32,32,33,t1
+	add,dc		t1,p64,p64
+	std		p64,-8(rp)
+	bve		(%r2)
+	ldo		-128(%r30),%r30
+
+LDEF(exit)
+	xmpyu		%fr8l,%fr8r,%fr10
+	fstd		%fr10,-120(%r30)
+	xmpyu		%fr8r,%fr8r,%fr9
+	fstd		%fr9,0(rp)
+	xmpyu		%fr8l,%fr8l,%fr11
+	fstd		%fr11,8(rp)
+	ldd		-128(%r30),p32
+	ldd		-16(rp),p00
+	ldd		-8(rp),p64
+	depd,z		p32,31,32,t0
+	add		t0,p00,p00
+	extrd,u		p32,31,32,t1
+	add,dc		t1,p64,p64
+	add		t0,p00,p00
+	add,dc		t1,p64,p64
+	std		p00,-16(rp)
+	std		p64,-8(rp)
+	ldo		16(rp),rp
+	ldd		-120(%r30),p32
+	ldd		-16(rp),p00
+	ldd		-8(rp),p64
+	depd,z		p32,31,32,t0
+	add		t0,p00,p00
+	extrd,u		p32,31,32,t1
+	add,dc		t1,p64,p64
+	add		t0,p00,p00
+	add,dc		t1,p64,p64
+	std		p00,-16(rp)
+	std		p64,-8(rp)
+	bve		(%r2)
+	ldo		-128(%r30),%r30
+
+LDEF(end1)
+	xmpyu		%fr8l,%fr8r,%fr10
+	fstd		%fr10,-128(%r30)
+	xmpyu		%fr8r,%fr8r,%fr9
+	fstd		%fr9,0(rp)
+	xmpyu		%fr8l,%fr8l,%fr11
+	fstd		%fr11,8(rp)
+	ldo		16(rp),rp
+	ldd		-128(%r30),p32
+	ldd		-16(rp),p00
+	ldd		-8(rp),p64
+	depd,z		p32,31,32,t0
+	add		t0,p00,p00
+	extrd,u		p32,31,32,t1
+	add,dc		t1,p64,p64
+	add		t0,p00,p00
+	add,dc		t1,p64,p64
+	std		p00,-16(rp)
+	std		p64,-8(rp)
+	bve		(%r2)
+	ldo		-128(%r30),%r30
+EPILOGUE(mpn_sqr_diagonal)
diff --git a/third_party/gmp/mpn/pa64/submul_1.asm b/third_party/gmp/mpn/pa64/submul_1.asm
new file mode 100644
index 0000000..f8a1968
--- /dev/null
+++ b/third_party/gmp/mpn/pa64/submul_1.asm
@@ -0,0 +1,700 @@
+dnl  HP-PA 2.0 64-bit mpn_submul_1 -- Multiply a limb vector with a limb and
+dnl  subtract the result from a second limb vector.
+
+dnl  Copyright 1998-2000, 2002, 2003 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		    cycles/limb
+C 8000,8200:		7
+C 8500,8600,8700:	6.5
+
+C  The feed-in and wind-down code has not yet been scheduled.  Many cycles
+C  could be saved there per call.
+
+C  DESCRIPTION:
+C  The main loop "BIG" is 4-way unrolled, mainly to allow
+C  effective use of ADD,DC.  Delays in moving data via the cache from the FP
+C  registers to the IU registers, have demanded a deep software pipeline, and
+C  a lot of stack slots for partial products in flight.
+C
+C  CODE STRUCTURE:
+C  save-some-registers
+C  do 0, 1, 2, or 3 limbs
+C  if done, restore-some-regs and return
+C  save-many-regs
+C  do 4, 8, ... limb
+C  restore-all-regs
+
+C  STACK LAYOUT:
+C  HP-PA stack grows upwards.  We could allocate 8 fewer slots by using the
+C  slots marked FREE, as well as some slots in the caller's "frame marker".
+C
+C -00 <- r30
+C -08  FREE
+C -10  tmp
+C -18  tmp
+C -20  tmp
+C -28  tmp
+C -30  tmp
+C -38  tmp
+C -40  tmp
+C -48  tmp
+C -50  tmp
+C -58  tmp
+C -60  tmp
+C -68  tmp
+C -70  tmp
+C -78  tmp
+C -80  tmp
+C -88  tmp
+C -90  FREE
+C -98  FREE
+C -a0  FREE
+C -a8  FREE
+C -b0  r13
+C -b8  r12
+C -c0  r11
+C -c8  r10
+C -d0  r8
+C -d8  r8
+C -e0  r7
+C -e8  r6
+C -f0  r5
+C -f8  r4
+C -100 r3
+C  Previous frame:
+C  [unused area]
+C -38/-138 vlimb home slot.  For 2.0N, the vlimb arg will arrive here.
+
+
+include(`../config.m4')
+
+C INPUT PARAMETERS:
+define(`rp',`%r26')	C
+define(`up',`%r25')	C
+define(`n',`%r24')	C
+define(`vlimb',`%r23')	C
+
+define(`climb',`%r23')	C
+
+ifdef(`HAVE_ABI_2_0w',
+`	.level	2.0w
+',`	.level	2.0
+')
+PROLOGUE(mpn_submul_1)
+
+ifdef(`HAVE_ABI_2_0w',
+`	std		vlimb, -0x38(%r30)	C store vlimb into "home" slot
+')
+	std,ma		%r3, 0x100(%r30)
+	std		%r4, -0xf8(%r30)
+	std		%r5, -0xf0(%r30)
+	ldo		0(%r0), climb		C clear climb
+	fldd		-0x138(%r30), %fr8	C put vlimb in fp register
+
+define(`p032a1',`%r1')	C
+define(`p032a2',`%r19')	C
+
+define(`m032',`%r20')	C
+define(`m096',`%r21')	C
+
+define(`p000a',`%r22')	C
+define(`p064a',`%r29')	C
+
+define(`s000',`%r31')	C
+
+define(`ma000',`%r4')	C
+define(`ma064',`%r20')	C
+
+define(`r000',`%r3')	C
+
+	extrd,u		n, 63, 2, %r5
+	cmpb,=		%r5, %r0, L(BIG)
+	nop
+
+	fldd		0(up), %fr4
+	ldo		8(up), up
+	xmpyu		%fr8R, %fr4L, %fr22
+	xmpyu		%fr8L, %fr4R, %fr23
+	fstd		%fr22, -0x78(%r30)	C mid product to  -0x78..-0x71
+	xmpyu		%fr8R, %fr4R, %fr24
+	xmpyu		%fr8L, %fr4L, %fr25
+	fstd		%fr23, -0x70(%r30)	C mid product to  -0x70..-0x69
+	fstd		%fr24, -0x80(%r30)	C low product to  -0x80..-0x79
+	addib,<>	-1, %r5, L(two_or_more)
+	fstd		%fr25, -0x68(%r30)	C high product to -0x68..-0x61
+LDEF(one)
+	ldd		-0x78(%r30), p032a1
+	ldd		-0x70(%r30), p032a2
+	ldd		-0x80(%r30), p000a
+	b		L(0_one_out)
+	ldd		-0x68(%r30), p064a
+
+LDEF(two_or_more)
+	fldd		0(up), %fr4
+	ldo		8(up), up
+	xmpyu		%fr8R, %fr4L, %fr22
+	xmpyu		%fr8L, %fr4R, %fr23
+	ldd		-0x78(%r30), p032a1
+	fstd		%fr22, -0x78(%r30)	C mid product to  -0x78..-0x71
+	xmpyu		%fr8R, %fr4R, %fr24
+	xmpyu		%fr8L, %fr4L, %fr25
+	ldd		-0x70(%r30), p032a2
+	fstd		%fr23, -0x70(%r30)	C mid product to  -0x70..-0x69
+	ldd		-0x80(%r30), p000a
+	fstd		%fr24, -0x80(%r30)	C low product to  -0x80..-0x79
+	ldd		-0x68(%r30), p064a
+	addib,<>	-1, %r5, L(three_or_more)
+	fstd		%fr25, -0x68(%r30)	C high product to -0x68..-0x61
+LDEF(two)
+	add		p032a1, p032a2, m032
+	add,dc		%r0, %r0, m096
+	depd,z		m032, 31, 32, ma000
+	extrd,u		m032, 31, 32, ma064
+	ldd		0(rp), r000
+	b		L(0_two_out)
+	depd		m096, 31, 32, ma064
+
+LDEF(three_or_more)
+	fldd		0(up), %fr4
+	add		p032a1, p032a2, m032
+	add,dc		%r0, %r0, m096
+	depd,z		m032, 31, 32, ma000
+	extrd,u		m032, 31, 32, ma064
+	ldd		0(rp), r000
+C	addib,=		-1, %r5, L(0_out)
+	depd		m096, 31, 32, ma064
+LDEF(loop0)
+C	xmpyu		%fr8R, %fr4L, %fr22
+C	xmpyu		%fr8L, %fr4R, %fr23
+C	ldd		-0x78(%r30), p032a1
+C	fstd		%fr22, -0x78(%r30)	C mid product to  -0x78..-0x71
+C
+C	xmpyu		%fr8R, %fr4R, %fr24
+C	xmpyu		%fr8L, %fr4L, %fr25
+C	ldd		-0x70(%r30), p032a2
+C	fstd		%fr23, -0x70(%r30)	C mid product to  -0x70..-0x69
+C
+C	ldo		8(rp), rp
+C	add		climb, p000a, s000
+C	ldd		-0x80(%r30), p000a
+C	fstd		%fr24, -0x80(%r30)	C low product to  -0x80..-0x79
+C
+C	add,dc		p064a, %r0, climb
+C	ldo		8(up), up
+C	ldd		-0x68(%r30), p064a
+C	fstd		%fr25, -0x68(%r30)	C high product to -0x68..-0x61
+C
+C	add		ma000, s000, s000
+C	add,dc		ma064, climb, climb
+C	fldd		0(up), %fr4
+C
+C	sub		r000, s000, s000
+C	sub,db		%r0, climb, climb
+C	sub		%r0, climb, climb
+C	std		s000, -8(rp)
+C
+C	add		p032a1, p032a2, m032
+C	add,dc		%r0, %r0, m096
+C
+C	depd,z		m032, 31, 32, ma000
+C	extrd,u		m032, 31, 32, ma064
+C	ldd		0(rp), r000
+C	addib,<>	-1, %r5, L(loop0)
+C	depd		m096, 31, 32, ma064
+LDEF(0_out)
+	ldo		8(up), up
+	xmpyu		%fr8R, %fr4L, %fr22
+	xmpyu		%fr8L, %fr4R, %fr23
+	ldd		-0x78(%r30), p032a1
+	fstd		%fr22, -0x78(%r30)	C mid product to  -0x78..-0x71
+	xmpyu		%fr8R, %fr4R, %fr24
+	xmpyu		%fr8L, %fr4L, %fr25
+	ldd		-0x70(%r30), p032a2
+	fstd		%fr23, -0x70(%r30)	C mid product to  -0x70..-0x69
+	ldo		8(rp), rp
+	add		climb, p000a, s000
+	ldd		-0x80(%r30), p000a
+	fstd		%fr24, -0x80(%r30)	C low product to  -0x80..-0x79
+	add,dc		p064a, %r0, climb
+	ldd		-0x68(%r30), p064a
+	fstd		%fr25, -0x68(%r30)	C high product to -0x68..-0x61
+	add		ma000, s000, s000
+	add,dc		ma064, climb, climb
+	sub		r000, s000, s000
+	sub,db		%r0, climb, climb
+	sub		%r0, climb, climb
+	std		s000, -8(rp)
+	add		p032a1, p032a2, m032
+	add,dc		%r0, %r0, m096
+	depd,z		m032, 31, 32, ma000
+	extrd,u		m032, 31, 32, ma064
+	ldd		0(rp), r000
+	depd		m096, 31, 32, ma064
+LDEF(0_two_out)
+	ldd		-0x78(%r30), p032a1
+	ldd		-0x70(%r30), p032a2
+	ldo		8(rp), rp
+	add		climb, p000a, s000
+	ldd		-0x80(%r30), p000a
+	add,dc		p064a, %r0, climb
+	ldd		-0x68(%r30), p064a
+	add		ma000, s000, s000
+	add,dc		ma064, climb, climb
+	sub		r000, s000, s000
+	sub,db		%r0, climb, climb
+	sub		%r0, climb, climb
+	std		s000, -8(rp)
+LDEF(0_one_out)
+	add		p032a1, p032a2, m032
+	add,dc		%r0, %r0, m096
+	depd,z		m032, 31, 32, ma000
+	extrd,u		m032, 31, 32, ma064
+	ldd		0(rp), r000
+	depd		m096, 31, 32, ma064
+
+	add		climb, p000a, s000
+	add,dc		p064a, %r0, climb
+	add		ma000, s000, s000
+	add,dc		ma064, climb, climb
+	sub		r000, s000, s000
+	sub,db		%r0, climb, climb
+	sub		%r0, climb, climb
+	std		s000, 0(rp)
+
+	cmpib,>=	4, n, L(done)
+	ldo		8(rp), rp
+
+C 4-way unrolled code.
+
+LDEF(BIG)
+
+define(`p032a1',`%r1')	C
+define(`p032a2',`%r19')	C
+define(`p096b1',`%r20')	C
+define(`p096b2',`%r21')	C
+define(`p160c1',`%r22')	C
+define(`p160c2',`%r29')	C
+define(`p224d1',`%r31')	C
+define(`p224d2',`%r3')	C
+			C
+define(`m032',`%r4')	C
+define(`m096',`%r5')	C
+define(`m160',`%r6')	C
+define(`m224',`%r7')	C
+define(`m288',`%r8')	C
+			C
+define(`p000a',`%r1')	C
+define(`p064a',`%r19')	C
+define(`p064b',`%r20')	C
+define(`p128b',`%r21')	C
+define(`p128c',`%r22')	C
+define(`p192c',`%r29')	C
+define(`p192d',`%r31')	C
+define(`p256d',`%r3')	C
+			C
+define(`s000',`%r10')	C
+define(`s064',`%r11')	C
+define(`s128',`%r12')	C
+define(`s192',`%r13')	C
+			C
+define(`ma000',`%r9')	C
+define(`ma064',`%r4')	C
+define(`ma128',`%r5')	C
+define(`ma192',`%r6')	C
+define(`ma256',`%r7')	C
+			C
+define(`r000',`%r1')	C
+define(`r064',`%r19')	C
+define(`r128',`%r20')	C
+define(`r192',`%r21')	C
+
+	std		%r6, -0xe8(%r30)
+	std		%r7, -0xe0(%r30)
+	std		%r8, -0xd8(%r30)
+	std		%r9, -0xd0(%r30)
+	std		%r10, -0xc8(%r30)
+	std		%r11, -0xc0(%r30)
+	std		%r12, -0xb8(%r30)
+	std		%r13, -0xb0(%r30)
+
+ifdef(`HAVE_ABI_2_0w',
+`	extrd,u		n, 61, 62, n		C right shift 2
+',`	extrd,u		n, 61, 30, n		C right shift 2, zero extend
+')
+
+LDEF(4_or_more)
+	fldd		0(up), %fr4
+	fldd		8(up), %fr5
+	fldd		16(up), %fr6
+	fldd		24(up), %fr7
+	xmpyu		%fr8R, %fr4L, %fr22
+	xmpyu		%fr8L, %fr4R, %fr23
+	xmpyu		%fr8R, %fr5L, %fr24
+	xmpyu		%fr8L, %fr5R, %fr25
+	xmpyu		%fr8R, %fr6L, %fr26
+	xmpyu		%fr8L, %fr6R, %fr27
+	fstd		%fr22, -0x78(%r30)	C mid product to  -0x78..-0x71
+	xmpyu		%fr8R, %fr7L, %fr28
+	xmpyu		%fr8L, %fr7R, %fr29
+	fstd		%fr23, -0x70(%r30)	C mid product to  -0x70..-0x69
+	xmpyu		%fr8R, %fr4R, %fr30
+	xmpyu		%fr8L, %fr4L, %fr31
+	fstd		%fr24, -0x38(%r30)	C mid product to  -0x38..-0x31
+	xmpyu		%fr8R, %fr5R, %fr22
+	xmpyu		%fr8L, %fr5L, %fr23
+	fstd		%fr25, -0x30(%r30)	C mid product to  -0x30..-0x29
+	xmpyu		%fr8R, %fr6R, %fr24
+	xmpyu		%fr8L, %fr6L, %fr25
+	fstd		%fr26, -0x58(%r30)	C mid product to  -0x58..-0x51
+	xmpyu		%fr8R, %fr7R, %fr26
+	fstd		%fr27, -0x50(%r30)	C mid product to  -0x50..-0x49
+	addib,<>	-1, n, L(8_or_more)
+	xmpyu		%fr8L, %fr7L, %fr27
+	fstd		%fr28, -0x18(%r30)	C mid product to  -0x18..-0x11
+	fstd		%fr29, -0x10(%r30)	C mid product to  -0x10..-0x09
+	fstd		%fr30, -0x80(%r30)	C low product to  -0x80..-0x79
+	fstd		%fr31, -0x68(%r30)	C high product to -0x68..-0x61
+	fstd		%fr22, -0x40(%r30)	C low product to  -0x40..-0x39
+	fstd		%fr23, -0x28(%r30)	C high product to -0x28..-0x21
+	fstd		%fr24, -0x60(%r30)	C low product to  -0x60..-0x59
+	fstd		%fr25, -0x48(%r30)	C high product to -0x48..-0x41
+	fstd		%fr26, -0x20(%r30)	C low product to  -0x20..-0x19
+	fstd		%fr27, -0x88(%r30)	C high product to -0x88..-0x81
+	ldd		-0x78(%r30), p032a1
+	ldd		-0x70(%r30), p032a2
+	ldd		-0x38(%r30), p096b1
+	ldd		-0x30(%r30), p096b2
+	ldd		-0x58(%r30), p160c1
+	ldd		-0x50(%r30), p160c2
+	ldd		-0x18(%r30), p224d1
+	ldd		-0x10(%r30), p224d2
+	b		L(end1)
+	nop
+
+LDEF(8_or_more)
+	fstd		%fr28, -0x18(%r30)	C mid product to  -0x18..-0x11
+	fstd		%fr29, -0x10(%r30)	C mid product to  -0x10..-0x09
+	ldo		32(up), up
+	fstd		%fr30, -0x80(%r30)	C low product to  -0x80..-0x79
+	fstd		%fr31, -0x68(%r30)	C high product to -0x68..-0x61
+	fstd		%fr22, -0x40(%r30)	C low product to  -0x40..-0x39
+	fstd		%fr23, -0x28(%r30)	C high product to -0x28..-0x21
+	fstd		%fr24, -0x60(%r30)	C low product to  -0x60..-0x59
+	fstd		%fr25, -0x48(%r30)	C high product to -0x48..-0x41
+	fstd		%fr26, -0x20(%r30)	C low product to  -0x20..-0x19
+	fstd		%fr27, -0x88(%r30)	C high product to -0x88..-0x81
+	fldd		0(up), %fr4
+	fldd		8(up), %fr5
+	fldd		16(up), %fr6
+	fldd		24(up), %fr7
+	xmpyu		%fr8R, %fr4L, %fr22
+	ldd		-0x78(%r30), p032a1
+	xmpyu		%fr8L, %fr4R, %fr23
+	xmpyu		%fr8R, %fr5L, %fr24
+	ldd		-0x70(%r30), p032a2
+	xmpyu		%fr8L, %fr5R, %fr25
+	xmpyu		%fr8R, %fr6L, %fr26
+	ldd		-0x38(%r30), p096b1
+	xmpyu		%fr8L, %fr6R, %fr27
+	fstd		%fr22, -0x78(%r30)	C mid product to  -0x78..-0x71
+	xmpyu		%fr8R, %fr7L, %fr28
+	ldd		-0x30(%r30), p096b2
+	xmpyu		%fr8L, %fr7R, %fr29
+	fstd		%fr23, -0x70(%r30)	C mid product to  -0x70..-0x69
+	xmpyu		%fr8R, %fr4R, %fr30
+	ldd		-0x58(%r30), p160c1
+	xmpyu		%fr8L, %fr4L, %fr31
+	fstd		%fr24, -0x38(%r30)	C mid product to  -0x38..-0x31
+	xmpyu		%fr8R, %fr5R, %fr22
+	ldd		-0x50(%r30), p160c2
+	xmpyu		%fr8L, %fr5L, %fr23
+	fstd		%fr25, -0x30(%r30)	C mid product to  -0x30..-0x29
+	xmpyu		%fr8R, %fr6R, %fr24
+	ldd		-0x18(%r30), p224d1
+	xmpyu		%fr8L, %fr6L, %fr25
+	fstd		%fr26, -0x58(%r30)	C mid product to  -0x58..-0x51
+	xmpyu		%fr8R, %fr7R, %fr26
+	ldd		-0x10(%r30), p224d2
+	fstd		%fr27, -0x50(%r30)	C mid product to  -0x50..-0x49
+	addib,=		-1, n, L(end2)
+	xmpyu		%fr8L, %fr7L, %fr27
+LDEF(loop)
+	add		p032a1, p032a2, m032
+	ldd		-0x80(%r30), p000a
+	add,dc		p096b1, p096b2, m096
+	fstd		%fr28, -0x18(%r30)	C mid product to  -0x18..-0x11
+
+	add,dc		p160c1, p160c2, m160
+	ldd		-0x68(%r30), p064a
+	add,dc		p224d1, p224d2, m224
+	fstd		%fr29, -0x10(%r30)	C mid product to  -0x10..-0x09
+
+	add,dc		%r0, %r0, m288
+	ldd		-0x40(%r30), p064b
+	ldo		32(up), up
+	fstd		%fr30, -0x80(%r30)	C low product to  -0x80..-0x79
+
+	depd,z		m032, 31, 32, ma000
+	ldd		-0x28(%r30), p128b
+	extrd,u		m032, 31, 32, ma064
+	fstd		%fr31, -0x68(%r30)	C high product to -0x68..-0x61
+
+	depd		m096, 31, 32, ma064
+	ldd		-0x60(%r30), p128c
+	extrd,u		m096, 31, 32, ma128
+	fstd		%fr22, -0x40(%r30)	C low product to  -0x40..-0x39
+
+	depd		m160, 31, 32, ma128
+	ldd		-0x48(%r30), p192c
+	extrd,u		m160, 31, 32, ma192
+	fstd		%fr23, -0x28(%r30)	C high product to -0x28..-0x21
+
+	depd		m224, 31, 32, ma192
+	ldd		-0x20(%r30), p192d
+	extrd,u		m224, 31, 32, ma256
+	fstd		%fr24, -0x60(%r30)	C low product to  -0x60..-0x59
+
+	depd		m288, 31, 32, ma256
+	ldd		-0x88(%r30), p256d
+	add		climb, p000a, s000
+	fstd		%fr25, -0x48(%r30)	C high product to -0x48..-0x41
+
+	add,dc		p064a, p064b, s064
+	ldd		0(rp), r000
+	add,dc		p128b, p128c, s128
+	fstd		%fr26, -0x20(%r30)	C low product to  -0x20..-0x19
+
+	add,dc		p192c, p192d, s192
+	ldd		8(rp), r064
+	add,dc		p256d, %r0, climb
+	fstd		%fr27, -0x88(%r30)	C high product to -0x88..-0x81
+
+	ldd		16(rp), r128
+	add		ma000, s000, s000	C accum mid 0
+	ldd		24(rp), r192
+	add,dc		ma064, s064, s064	C accum mid 1
+
+	add,dc		ma128, s128, s128	C accum mid 2
+	fldd		0(up), %fr4
+	add,dc		ma192, s192, s192	C accum mid 3
+	fldd		8(up), %fr5
+
+	add,dc		ma256, climb, climb
+	fldd		16(up), %fr6
+	sub		r000, s000, s000	C accum rlimb 0
+	fldd		24(up), %fr7
+
+	sub,db		r064, s064, s064	C accum rlimb 1
+	sub,db		r128, s128, s128	C accum rlimb 2
+	std		s000, 0(rp)
+
+	sub,db		r192, s192, s192	C accum rlimb 3
+	sub,db		%r0, climb, climb
+	sub		%r0, climb, climb
+	std		s064, 8(rp)
+
+	xmpyu		%fr8R, %fr4L, %fr22
+	ldd		-0x78(%r30), p032a1
+	xmpyu		%fr8L, %fr4R, %fr23
+	std		s128, 16(rp)
+
+	xmpyu		%fr8R, %fr5L, %fr24
+	ldd		-0x70(%r30), p032a2
+	xmpyu		%fr8L, %fr5R, %fr25
+	std		s192, 24(rp)
+
+	xmpyu		%fr8R, %fr6L, %fr26
+	ldd		-0x38(%r30), p096b1
+	xmpyu		%fr8L, %fr6R, %fr27
+	fstd		%fr22, -0x78(%r30)	C mid product to  -0x78..-0x71
+
+	xmpyu		%fr8R, %fr7L, %fr28
+	ldd		-0x30(%r30), p096b2
+	xmpyu		%fr8L, %fr7R, %fr29
+	fstd		%fr23, -0x70(%r30)	C mid product to  -0x70..-0x69
+
+	xmpyu		%fr8R, %fr4R, %fr30
+	ldd		-0x58(%r30), p160c1
+	xmpyu		%fr8L, %fr4L, %fr31
+	fstd		%fr24, -0x38(%r30)	C mid product to  -0x38..-0x31
+
+	xmpyu		%fr8R, %fr5R, %fr22
+	ldd		-0x50(%r30), p160c2
+	xmpyu		%fr8L, %fr5L, %fr23
+	fstd		%fr25, -0x30(%r30)	C mid product to  -0x30..-0x29
+
+	xmpyu		%fr8R, %fr6R, %fr24
+	ldd		-0x18(%r30), p224d1
+	xmpyu		%fr8L, %fr6L, %fr25
+	fstd		%fr26, -0x58(%r30)	C mid product to  -0x58..-0x51
+
+	xmpyu		%fr8R, %fr7R, %fr26
+	ldd		-0x10(%r30), p224d2
+	fstd		%fr27, -0x50(%r30)	C mid product to  -0x50..-0x49
+	xmpyu		%fr8L, %fr7L, %fr27
+
+	addib,<>	-1, n, L(loop)
+	ldo		32(rp), rp
+
+LDEF(end2)
+	add		p032a1, p032a2, m032
+	ldd		-0x80(%r30), p000a
+	add,dc		p096b1, p096b2, m096
+	fstd		%fr28, -0x18(%r30)	C mid product to  -0x18..-0x11
+	add,dc		p160c1, p160c2, m160
+	ldd		-0x68(%r30), p064a
+	add,dc		p224d1, p224d2, m224
+	fstd		%fr29, -0x10(%r30)	C mid product to  -0x10..-0x09
+	add,dc		%r0, %r0, m288
+	ldd		-0x40(%r30), p064b
+	fstd		%fr30, -0x80(%r30)	C low product to  -0x80..-0x79
+	depd,z		m032, 31, 32, ma000
+	ldd		-0x28(%r30), p128b
+	extrd,u		m032, 31, 32, ma064
+	fstd		%fr31, -0x68(%r30)	C high product to -0x68..-0x61
+	depd		m096, 31, 32, ma064
+	ldd		-0x60(%r30), p128c
+	extrd,u		m096, 31, 32, ma128
+	fstd		%fr22, -0x40(%r30)	C low product to  -0x40..-0x39
+	depd		m160, 31, 32, ma128
+	ldd		-0x48(%r30), p192c
+	extrd,u		m160, 31, 32, ma192
+	fstd		%fr23, -0x28(%r30)	C high product to -0x28..-0x21
+	depd		m224, 31, 32, ma192
+	ldd		-0x20(%r30), p192d
+	extrd,u		m224, 31, 32, ma256
+	fstd		%fr24, -0x60(%r30)	C low product to  -0x60..-0x59
+	depd		m288, 31, 32, ma256
+	ldd		-0x88(%r30), p256d
+	add		climb, p000a, s000
+	fstd		%fr25, -0x48(%r30)	C high product to -0x48..-0x41
+	add,dc		p064a, p064b, s064
+	ldd		0(rp), r000
+	add,dc		p128b, p128c, s128
+	fstd		%fr26, -0x20(%r30)	C low product to  -0x20..-0x19
+	add,dc		p192c, p192d, s192
+	ldd		8(rp), r064
+	add,dc		p256d, %r0, climb
+	fstd		%fr27, -0x88(%r30)	C high product to -0x88..-0x81
+	ldd		16(rp), r128
+	add		ma000, s000, s000	C accum mid 0
+	ldd		24(rp), r192
+	add,dc		ma064, s064, s064	C accum mid 1
+	add,dc		ma128, s128, s128	C accum mid 2
+	add,dc		ma192, s192, s192	C accum mid 3
+	add,dc		ma256, climb, climb
+	sub		r000, s000, s000	C accum rlimb 0
+	sub,db		r064, s064, s064	C accum rlimb 1
+	sub,db		r128, s128, s128	C accum rlimb 2
+	std		s000, 0(rp)
+	sub,db		r192, s192, s192	C accum rlimb 3
+	sub,db		%r0, climb, climb
+	sub		%r0, climb, climb
+	std		s064, 8(rp)
+	ldd		-0x78(%r30), p032a1
+	std		s128, 16(rp)
+	ldd		-0x70(%r30), p032a2
+	std		s192, 24(rp)
+	ldd		-0x38(%r30), p096b1
+	ldd		-0x30(%r30), p096b2
+	ldd		-0x58(%r30), p160c1
+	ldd		-0x50(%r30), p160c2
+	ldd		-0x18(%r30), p224d1
+	ldd		-0x10(%r30), p224d2
+	ldo		32(rp), rp
+
+LDEF(end1)
+	add		p032a1, p032a2, m032
+	ldd		-0x80(%r30), p000a
+	add,dc		p096b1, p096b2, m096
+	add,dc		p160c1, p160c2, m160
+	ldd		-0x68(%r30), p064a
+	add,dc		p224d1, p224d2, m224
+	add,dc		%r0, %r0, m288
+	ldd		-0x40(%r30), p064b
+	depd,z		m032, 31, 32, ma000
+	ldd		-0x28(%r30), p128b
+	extrd,u		m032, 31, 32, ma064
+	depd		m096, 31, 32, ma064
+	ldd		-0x60(%r30), p128c
+	extrd,u		m096, 31, 32, ma128
+	depd		m160, 31, 32, ma128
+	ldd		-0x48(%r30), p192c
+	extrd,u		m160, 31, 32, ma192
+	depd		m224, 31, 32, ma192
+	ldd		-0x20(%r30), p192d
+	extrd,u		m224, 31, 32, ma256
+	depd		m288, 31, 32, ma256
+	ldd		-0x88(%r30), p256d
+	add		climb, p000a, s000
+	add,dc		p064a, p064b, s064
+	ldd		0(rp), r000
+	add,dc		p128b, p128c, s128
+	add,dc		p192c, p192d, s192
+	ldd		8(rp), r064
+	add,dc		p256d, %r0, climb
+	ldd		16(rp), r128
+	add		ma000, s000, s000	C accum mid 0
+	ldd		24(rp), r192
+	add,dc		ma064, s064, s064	C accum mid 1
+	add,dc		ma128, s128, s128	C accum mid 2
+	add,dc		ma192, s192, s192	C accum mid 3
+	add,dc		ma256, climb, climb
+	sub		r000, s000, s000	C accum rlimb 0
+	sub,db		r064, s064, s064	C accum rlimb 1
+	sub,db		r128, s128, s128	C accum rlimb 2
+	std		s000, 0(rp)
+	sub,db		r192, s192, s192	C accum rlimb 3
+	sub,db		%r0, climb, climb
+	sub		%r0, climb, climb
+	std		s064, 8(rp)
+	std		s128, 16(rp)
+	std		s192, 24(rp)
+
+	ldd		-0xb0(%r30), %r13
+	ldd		-0xb8(%r30), %r12
+	ldd		-0xc0(%r30), %r11
+	ldd		-0xc8(%r30), %r10
+	ldd		-0xd0(%r30), %r9
+	ldd		-0xd8(%r30), %r8
+	ldd		-0xe0(%r30), %r7
+	ldd		-0xe8(%r30), %r6
+LDEF(done)
+ifdef(`HAVE_ABI_2_0w',
+`	copy		climb, %r28
+',`	extrd,u		climb, 63, 32, %r29
+	extrd,u		climb, 31, 32, %r28
+')
+	ldd		-0xf0(%r30), %r5
+	ldd		-0xf8(%r30), %r4
+	bve		(%r2)
+	ldd,mb		-0x100(%r30), %r3
+EPILOGUE(mpn_submul_1)
diff --git a/third_party/gmp/mpn/pa64/udiv.asm b/third_party/gmp/mpn/pa64/udiv.asm
new file mode 100644
index 0000000..1380a85
--- /dev/null
+++ b/third_party/gmp/mpn/pa64/udiv.asm
@@ -0,0 +1,125 @@
+dnl  HP-PA 2.0 64-bit mpn_udiv_qrnnd_r.
+
+dnl  Copyright 2001-2003 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C This runs at about 280 cycles on both PA8000 and PA8500, corresponding to a
+C bit more than 4 cycles/bit.
+
+C INPUT PARAMETERS
+define(`n1',`%r26')
+define(`n0',`%r25')
+define(`d',`%r24')
+define(`remptr',`%r23')
+
+define(`q',`%r28')
+define(`dn',`%r29')
+
+define(`old_divstep',
+       `add,dc		n0,n0,n0
+	add,dc		n1,n1,n1
+	sub,*<<		n1,d,%r22
+	copy		%r22,n1')
+
+define(`divstep',
+       `add		n0,n0,n0
+	add,dc		n1,n1,n1
+	sub		n1,d,%r1
+	add,dc		q,q,q
+	cmpclr,*<<	n1,d,%r0
+	copy		%r1,n1
+')
+
+ifdef(`HAVE_ABI_2_0w',
+`	.level	2.0w
+',`	.level	2.0
+')
+PROLOGUE(mpn_udiv_qrnnd_r)
+ifdef(`HAVE_ABI_2_0n',
+`	depd		%r25,31,32,%r26
+	depd		%r23,31,32,%r24
+	copy		%r24,%r25
+	ldd		-56(%r30),%r24
+	ldw		-60(%r30),%r23
+')
+	ldi		0,q
+	cmpib,*>=	0,d,L(large_divisor)
+	ldi		8,%r31		C setup loop counter
+
+	sub		%r0,d,dn
+LDEF(Loop)
+	divstep divstep divstep divstep divstep divstep divstep divstep
+	addib,<>	-1,%r31,L(Loop)
+	nop
+
+ifdef(`HAVE_ABI_2_0n',
+`	copy		%r28,%r29
+	extrd,u		%r28,31,32,%r28
+')
+	bve		(%r2)
+	std		n1,0(remptr)	C store remainder
+
+LDEF(large_divisor)
+	extrd,u		n0,63,1,%r19	C save lsb of dividend
+	shrpd		n1,n0,1,n0	C n0 = lo(n1n0 >> 1)
+	shrpd		%r0,n1,1,n1	C n1 = hi(n1n0 >> 1)
+	extrd,u		d,63,1,%r20	C save lsb of divisor
+	shrpd		%r0,d,1,d	C d = floor(orig_d / 2)
+	add,l		%r20,d,d	C d = ceil(orig_d / 2)
+
+	sub		%r0,d,dn
+LDEF(Loop2)
+	divstep divstep divstep divstep divstep divstep divstep divstep
+	addib,<>	-1,%r31,L(Loop2)
+	nop
+
+	cmpib,*=	0,%r20,L(even_divisor)
+	shladd		n1,1,%r19,n1	C shift in omitted dividend lsb
+
+	add		d,d,d		C restore orig...
+	sub		d,%r20,d	C ...d value
+	sub		%r0,d,dn	C r21 = -d
+
+	add,*nuv	n1,q,n1		C fix remainder for omitted divisor lsb
+	add,l		n1,dn,n1	C adjust remainder if rem. fix carried
+	add,dc		%r0,q,q		C adjust quotient accordingly
+
+	sub,*<<		n1,d,%r0	C remainder >= divisor?
+	add,l		n1,dn,n1	C adjust remainder
+	add,dc		%r0,q,q		C adjust quotient
+
+LDEF(even_divisor)
+ifdef(`HAVE_ABI_2_0n',
+`	copy		%r28,%r29
+	extrd,u		%r28,31,32,%r28
+')
+	bve		(%r2)
+	std		n1,0(remptr)	C store remainder
+EPILOGUE(mpn_udiv_qrnnd_r)
diff --git a/third_party/gmp/mpn/pa64/umul.asm b/third_party/gmp/mpn/pa64/umul.asm
new file mode 100644
index 0000000..bd5a71f
--- /dev/null
+++ b/third_party/gmp/mpn/pa64/umul.asm
@@ -0,0 +1,97 @@
+dnl  Copyright 1999, 2000, 2002, 2003 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+dnl  Optimizations:
+dnl  * Avoid skip instructions
+dnl  * Put carry-generating and carry-consuming insns consecutively
+dnl  * Don't allocate any stack, "home" positions for parameters could be used.
+
+include(`../config.m4')
+
+define(`p0',`%r28')
+define(`p1',`%r29')
+define(`t32',`%r19')
+define(`t0',`%r20')
+define(`t1',`%r21')
+define(`x',`%r22')
+define(`m0',`%r23')
+define(`m1',`%r24')
+
+ifdef(`HAVE_ABI_2_0w',
+`	.level	2.0w
+',`	.level	2.0
+')
+PROLOGUE(mpn_umul_ppmm_r)
+	ldo		128(%r30),%r30
+ifdef(`HAVE_ABI_2_0w',
+`	std		%r26,-64(%r30)
+	std		%r25,-56(%r30)
+	copy		%r24,%r31
+',`
+	depd		%r25,31,32,%r26
+	std		%r26,-64(%r30)
+	depd		%r23,31,32,%r24
+	std		%r24,-56(%r30)
+	ldw		-180(%r30),%r31
+')
+
+	fldd		-64(%r30),%fr4
+	fldd		-56(%r30),%fr5
+
+	xmpyu		%fr5R,%fr4R,%fr6
+	fstd		%fr6,-128(%r30)
+	xmpyu		%fr5R,%fr4L,%fr7
+	fstd		%fr7,-120(%r30)
+	xmpyu		%fr5L,%fr4R,%fr8
+	fstd		%fr8,-112(%r30)
+	xmpyu		%fr5L,%fr4L,%fr9
+	fstd		%fr9,-104(%r30)
+
+	depdi,z		1,31,1,t32		C t32 = 2^32
+
+	ldd		-128(%r30),p0		C lo = low 64 bit of product
+	ldd		-120(%r30),m0		C m0 = mid0 64 bit of product
+	ldd		-112(%r30),m1		C m1 = mid1 64 bit of product
+	ldd		-104(%r30),p1		C hi = high 64 bit of product
+
+	add,l,*nuv	m0,m1,x			C x = m1+m0
+	 add,l		t32,p1,p1		C propagate carry to mid of p1
+	depd,z		x,31,32,t0		C lo32(m1+m0)
+	add		t0,p0,p0
+	extrd,u		x,31,32,t1		C hi32(m1+m0)
+	add,dc		t1,p1,p1
+
+	std		p0,0(%r31)		C store low half of product
+ifdef(`HAVE_ABI_2_0w',
+`	copy		p1,%r28			C return val in %r28
+',`	extrd,u		p1,31,32,%r28		C return val in %r28,%r29
+')
+	bve		(%r2)
+	ldo		-128(%r30),%r30
+EPILOGUE(mpn_umul_ppmm_r)
diff --git a/third_party/gmp/mpn/power/add_n.asm b/third_party/gmp/mpn/power/add_n.asm
new file mode 100644
index 0000000..6d6ca73
--- /dev/null
+++ b/third_party/gmp/mpn/power/add_n.asm
@@ -0,0 +1,83 @@
+dnl  IBM POWER mpn_add_n -- Add two limb vectors of equal, non-zero length.
+
+dnl  Copyright 1992, 1994-1996, 1999-2001, 2005 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+dnl  INPUT PARAMETERS
+dnl  res_ptr	r3
+dnl  s1_ptr	r4
+dnl  s2_ptr	r5
+dnl  size	r6
+
+include(`../config.m4')
+
+ASM_START()
+PROLOGUE(mpn_add_n)
+	andil.	10,6,1		C odd or even number of limbs?
+	l	8,0(4)		C load least significant s1 limb
+	l	0,0(5)		C load least significant s2 limb
+	cal	3,-4(3)		C offset res_ptr, it's updated before it's used
+	sri	10,6,1		C count for unrolled loop
+	a	7,0,8		C add least significant limbs, set cy
+	mtctr	10		C copy count into CTR
+	beq	0,Leven		C branch if even # of limbs (# of limbs >= 2)
+
+C We have an odd # of limbs.  Add the first limbs separately.
+	cmpi	1,10,0		C is count for unrolled loop zero?
+	bc	4,6,L1		C bne cr1,L1 (misassembled by gas)
+	st	7,4(3)
+	aze	3,10		C use the fact that r10 is zero...
+	br			C return
+
+C We added least significant limbs.  Now reload the next limbs to enter loop.
+L1:	lu	8,4(4)		C load s1 limb and update s1_ptr
+	lu	0,4(5)		C load s2 limb and update s2_ptr
+	stu	7,4(3)
+	ae	7,0,8		C add limbs, set cy
+Leven:	lu	9,4(4)		C load s1 limb and update s1_ptr
+	lu	10,4(5)		C load s2 limb and update s2_ptr
+	bdz	Lend		C If done, skip loop
+
+Loop:	lu	8,4(4)		C load s1 limb and update s1_ptr
+	lu	0,4(5)		C load s2 limb and update s2_ptr
+	ae	11,10,9		C add previous limbs with cy, set cy
+	stu	7,4(3)		C
+	lu	9,4(4)		C load s1 limb and update s1_ptr
+	lu	10,4(5)		C load s2 limb and update s2_ptr
+	ae	7,0,8		C add previous limbs with cy, set cy
+	stu	11,4(3)		C
+	bdn	Loop		C decrement CTR and loop back
+
+Lend:	ae	11,10,9		C add limbs with cy, set cy
+	st	7,4(3)		C
+	st	11,8(3)		C
+	lil	3,0		C load cy into ...
+	aze	3,3		C ... return value register
+	br
+EPILOGUE(mpn_add_n)
diff --git a/third_party/gmp/mpn/power/addmul_1.asm b/third_party/gmp/mpn/power/addmul_1.asm
new file mode 100644
index 0000000..76d8df3
--- /dev/null
+++ b/third_party/gmp/mpn/power/addmul_1.asm
@@ -0,0 +1,126 @@
+dnl  IBM POWER mpn_addmul_1 -- Multiply a limb vector with a limb and add the
+dnl  result to a second limb vector.
+
+dnl  Copyright 1992, 1994, 1999-2001 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+dnl  INPUT PARAMETERS
+dnl  res_ptr	r3
+dnl  s1_ptr	r4
+dnl  size	r5
+dnl  s2_limb	r6
+
+dnl  The POWER architecture has no unsigned 32x32->64 bit multiplication
+dnl  instruction.  To obtain that operation, we have to use the 32x32->64
+dnl  signed multiplication instruction, and add the appropriate compensation to
+dnl  the high limb of the result.  We add the multiplicand if the multiplier
+dnl  has its most significant bit set, and we add the multiplier if the
+dnl  multiplicand has its most significant bit set.  We need to preserve the
+dnl  carry flag between each iteration, so we have to compute the compensation
+dnl  carefully (the natural, srai+and doesn't work).  Since all POWER can
+dnl  branch in zero cycles, we use conditional branches for the compensation.
+
+include(`../config.m4')
+
+ASM_START()
+PROLOGUE(mpn_addmul_1)
+	cal	3,-4(3)
+	l	0,0(4)
+	cmpi	0,6,0
+	mtctr	5
+	mul	9,0,6
+	srai	7,0,31
+	and	7,7,6
+	mfmq	8
+	cax	9,9,7
+	l	7,4(3)
+	a	8,8,7		C add res_limb
+	blt	Lneg
+Lpos:	bdz	Lend
+
+Lploop:	lu	0,4(4)
+	stu	8,4(3)
+	cmpi	0,0,0
+	mul	10,0,6
+	mfmq	0
+	ae	8,0,9		C low limb + old_cy_limb + old cy
+	l	7,4(3)
+	aze	10,10		C propagate cy to new cy_limb
+	a	8,8,7		C add res_limb
+	bge	Lp0
+	cax	10,10,6		C adjust high limb for negative limb from s1
+Lp0:	bdz	Lend0
+	lu	0,4(4)
+	stu	8,4(3)
+	cmpi	0,0,0
+	mul	9,0,6
+	mfmq	0
+	ae	8,0,10
+	l	7,4(3)
+	aze	9,9
+	a	8,8,7
+	bge	Lp1
+	cax	9,9,6		C adjust high limb for negative limb from s1
+Lp1:	bdn	Lploop
+
+	b	Lend
+
+Lneg:	cax	9,9,0
+	bdz	Lend
+Lnloop:	lu	0,4(4)
+	stu	8,4(3)
+	cmpi	0,0,0
+	mul	10,0,6
+	mfmq	7
+	ae	8,7,9
+	l	7,4(3)
+	ae	10,10,0		C propagate cy to new cy_limb
+	a	8,8,7		C add res_limb
+	bge	Ln0
+	cax	10,10,6		C adjust high limb for negative limb from s1
+Ln0:	bdz	Lend0
+	lu	0,4(4)
+	stu	8,4(3)
+	cmpi	0,0,0
+	mul	9,0,6
+	mfmq	7
+	ae	8,7,10
+	l	7,4(3)
+	ae	9,9,0		C propagate cy to new cy_limb
+	a	8,8,7		C add res_limb
+	bge	Ln1
+	cax	9,9,6		C adjust high limb for negative limb from s1
+Ln1:	bdn	Lnloop
+	b	Lend
+
+Lend0:	cal	9,0(10)
+Lend:	st	8,4(3)
+	aze	3,9
+	br
+EPILOGUE(mpn_addmul_1)
diff --git a/third_party/gmp/mpn/power/gmp-mparam.h b/third_party/gmp/mpn/power/gmp-mparam.h
new file mode 100644
index 0000000..7cb36f9
--- /dev/null
+++ b/third_party/gmp/mpn/power/gmp-mparam.h
@@ -0,0 +1,69 @@
+/* POWER gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2002-2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+/* Generated by tuneup.c, 2003-02-10, gcc 3.2, POWER2 66.7MHz */
+
+#define MUL_TOOM22_THRESHOLD             12
+#define MUL_TOOM33_THRESHOLD             75
+
+#define SQR_BASECASE_THRESHOLD            7
+#define SQR_TOOM2_THRESHOLD              28
+#define SQR_TOOM3_THRESHOLD              86
+
+#define DIV_SB_PREINV_THRESHOLD       MP_SIZE_T_MAX  /* never */
+#define DIV_DC_THRESHOLD                 36
+#define POWM_THRESHOLD                   69
+
+#define HGCD_THRESHOLD                   97
+#define GCD_ACCEL_THRESHOLD               3
+#define GCD_DC_THRESHOLD                590
+#define JACOBI_BASE_METHOD                2
+
+#define DIVREM_1_NORM_THRESHOLD          12
+#define DIVREM_1_UNNORM_THRESHOLD     MP_SIZE_T_MAX  /* never */
+#define MOD_1_NORM_THRESHOLD             10
+#define MOD_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define USE_PREINV_DIVREM_1               0
+#define USE_PREINV_MOD_1                  1
+#define DIVREM_2_THRESHOLD               11
+#define DIVEXACT_1_THRESHOLD              0  /* always */
+#define MODEXACT_1_ODD_THRESHOLD          0  /* always */
+
+#define GET_STR_DC_THRESHOLD             10
+#define GET_STR_PRECOMPUTE_THRESHOLD     20
+#define SET_STR_THRESHOLD              2899
+
+#define MUL_FFT_TABLE  { 336, 800, 1408, 3584, 10240, 24576, 0 }
+#define MUL_FFT_MODF_THRESHOLD          296
+#define MUL_FFT_THRESHOLD              2304
+
+#define SQR_FFT_TABLE  { 336, 800, 1408, 3584, 10240, 24576, 0 }
+#define SQR_FFT_MODF_THRESHOLD          296
+#define SQR_FFT_THRESHOLD              2304
diff --git a/third_party/gmp/mpn/power/lshift.asm b/third_party/gmp/mpn/power/lshift.asm
new file mode 100644
index 0000000..efa2105
--- /dev/null
+++ b/third_party/gmp/mpn/power/lshift.asm
@@ -0,0 +1,61 @@
+dnl  IBM POWER mpn_lshift -- Shift a number left.
+
+dnl  Copyright 1992, 1994, 1999-2001 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+dnl  INPUT PARAMETERS
+dnl  res_ptr	r3
+dnl  s_ptr	r4
+dnl  size	r5
+dnl  cnt	r6
+
+include(`../config.m4')
+
+ASM_START()
+PROLOGUE(mpn_lshift)
+	sli	0,5,2
+	cax	9,3,0
+	cax	4,4,0
+	sfi	8,6,32
+	mtctr	5		C put limb count in CTR loop register
+	lu	0,-4(4)		C read most significant limb
+	sre	3,0,8		C compute carry out limb, and init MQ register
+	bdz	Lend2		C if just one limb, skip loop
+	lu	0,-4(4)		C read 2:nd most significant limb
+	sreq	7,0,8		C compute most significant limb of result
+	bdz	Lend		C if just two limb, skip loop
+Loop:	lu	0,-4(4)		C load next lower limb
+	stu	7,-4(9)		C store previous result during read latency
+	sreq	7,0,8		C compute result limb
+	bdn	Loop		C loop back until CTR is zero
+Lend:	stu	7,-4(9)		C store 2:nd least significant limb
+Lend2:	sle	7,0,6		C compute least significant limb
+	st	7,-4(9)		C store it
+	br
+EPILOGUE(mpn_lshift)
diff --git a/third_party/gmp/mpn/power/mul_1.asm b/third_party/gmp/mpn/power/mul_1.asm
new file mode 100644
index 0000000..38b7b66
--- /dev/null
+++ b/third_party/gmp/mpn/power/mul_1.asm
@@ -0,0 +1,113 @@
+dnl  IBM POWER mpn_mul_1 -- Multiply a limb vector with a limb and store the
+dnl  result in a second limb vector.
+
+dnl  Copyright 1992, 1994, 1999-2001 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+dnl  INPUT PARAMETERS
+dnl  res_ptr	r3
+dnl  s1_ptr	r4
+dnl  size	r5
+dnl  s2_limb	r6
+
+dnl  The POWER architecture has no unsigned 32x32->64 bit multiplication
+dnl  instruction.  To obtain that operation, we have to use the 32x32->64
+dnl  signed multiplication instruction, and add the appropriate compensation to
+dnl  the high limb of the result.  We add the multiplicand if the multiplier
+dnl  has its most significant bit set, and we add the multiplier if the
+dnl  multiplicand has its most significant bit set.  We need to preserve the
+dnl  carry flag between each iteration, so we have to compute the compensation
+dnl  carefully (the natural, srai+and doesn't work).  Since all POWER can
+dnl  branch in zero cycles, we use conditional branches for the compensation.
+
+include(`../config.m4')
+
+ASM_START()
+PROLOGUE(mpn_mul_1)
+	cal	3,-4(3)
+	l	0,0(4)
+	cmpi	0,6,0
+	mtctr	5
+	mul	9,0,6
+	srai	7,0,31
+	and	7,7,6
+	mfmq	8
+	ai	0,0,0		C reset carry
+	cax	9,9,7
+	blt	Lneg
+Lpos:	bdz	Lend
+Lploop:	lu	0,4(4)
+	stu	8,4(3)
+	cmpi	0,0,0
+	mul	10,0,6
+	mfmq	0
+	ae	8,0,9
+	bge	Lp0
+	cax	10,10,6		C adjust high limb for negative limb from s1
+Lp0:	bdz	Lend0
+	lu	0,4(4)
+	stu	8,4(3)
+	cmpi	0,0,0
+	mul	9,0,6
+	mfmq	0
+	ae	8,0,10
+	bge	Lp1
+	cax	9,9,6		C adjust high limb for negative limb from s1
+Lp1:	bdn	Lploop
+	b	Lend
+
+Lneg:	cax	9,9,0
+	bdz	Lend
+Lnloop:	lu	0,4(4)
+	stu	8,4(3)
+	cmpi	0,0,0
+	mul	10,0,6
+	cax	10,10,0		C adjust high limb for negative s2_limb
+	mfmq	0
+	ae	8,0,9
+	bge	Ln0
+	cax	10,10,6		C adjust high limb for negative limb from s1
+Ln0:	bdz	Lend0
+	lu	0,4(4)
+	stu	8,4(3)
+	cmpi	0,0,0
+	mul	9,0,6
+	cax	9,9,0		C adjust high limb for negative s2_limb
+	mfmq	0
+	ae	8,0,10
+	bge	Ln1
+	cax	9,9,6		C adjust high limb for negative limb from s1
+Ln1:	bdn	Lnloop
+	b	Lend
+
+Lend0:	cal	9,0(10)
+Lend:	st	8,4(3)
+	aze	3,9
+	br
+EPILOGUE(mpn_mul_1)
diff --git a/third_party/gmp/mpn/power/rshift.asm b/third_party/gmp/mpn/power/rshift.asm
new file mode 100644
index 0000000..1d1815c
--- /dev/null
+++ b/third_party/gmp/mpn/power/rshift.asm
@@ -0,0 +1,59 @@
+dnl  IBM POWER mpn_rshift -- Shift a number right.
+
+dnl  Copyright 1992, 1994, 1999-2001 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+dnl  INPUT PARAMETERS
+dnl  res_ptr	r3
+dnl  s_ptr	r4
+dnl  size	r5
+dnl  cnt	r6
+
+include(`../config.m4')
+
+ASM_START()
+PROLOGUE(mpn_rshift)
+	sfi	8,6,32
+	mtctr	5		C put limb count in CTR loop register
+	l	0,0(4)		C read least significant limb
+	ai	9,3,-4		C adjust res_ptr since it's offset in the stu:s
+	sle	3,0,8		C compute carry limb, and init MQ register
+	bdz	Lend2		C if just one limb, skip loop
+	lu	0,4(4)		C read 2:nd least significant limb
+	sleq	7,0,8		C compute least significant limb of result
+	bdz	Lend		C if just two limb, skip loop
+Loop:	lu	0,4(4)		C load next higher limb
+	stu	7,4(9)		C store previous result during read latency
+	sleq	7,0,8		C compute result limb
+	bdn	Loop		C loop back until CTR is zero
+Lend:	stu	7,4(9)		C store 2:nd most significant limb
+Lend2:	sre	7,0,6		C compute most significant limb
+	st	7,4(9)		C store it
+	br
+EPILOGUE(mpn_rshift)
diff --git a/third_party/gmp/mpn/power/sdiv.asm b/third_party/gmp/mpn/power/sdiv.asm
new file mode 100644
index 0000000..4a9ed14
--- /dev/null
+++ b/third_party/gmp/mpn/power/sdiv.asm
@@ -0,0 +1,39 @@
+dnl  Copyright 1999, 2001 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ASM_START()
+PROLOGUE(mpn_sdiv_qrnnd)
+	mtmq	5
+	div	0,4,6
+	mfmq	9
+	st	9,0(3)
+	mr	3,0
+	br
+EPILOGUE(mpn_sdiv_qrnnd)
diff --git a/third_party/gmp/mpn/power/sub_n.asm b/third_party/gmp/mpn/power/sub_n.asm
new file mode 100644
index 0000000..390c802
--- /dev/null
+++ b/third_party/gmp/mpn/power/sub_n.asm
@@ -0,0 +1,85 @@
+dnl  IBM POWER mpn_sub_n -- Subtract two limb vectors of equal, non-zero
+dnl  length.
+
+dnl  Copyright 1992, 1994-1996, 1999-2001, 2005 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+dnl  INPUT PARAMETERS
+dnl  res_ptr	r3
+dnl  s1_ptr	r4
+dnl  s2_ptr	r5
+dnl  size	r6
+
+include(`../config.m4')
+
+ASM_START()
+PROLOGUE(mpn_sub_n)
+	andil.	10,6,1		C odd or even number of limbs?
+	l	8,0(4)		C load least significant s1 limb
+	l	0,0(5)		C load least significant s2 limb
+	cal	3,-4(3)		C offset res_ptr, it's updated before it's used
+	sri	10,6,1		C count for unrolled loop
+	sf	7,0,8		C subtract least significant limbs, set cy
+	mtctr	10		C copy count into CTR
+	beq	0,Leven		C branch if even # of limbs (# of limbs >= 2)
+
+C We have an odd # of limbs.  Add the first limbs separately.
+	cmpi	1,10,0		C is count for unrolled loop zero?
+	bc	4,6,L1		C bne cr1,L1 (misassembled by gas)
+	st	7,4(3)
+	sfe	3,0,0		C load !cy into ...
+	sfi	3,3,0		C ... return value register
+	br			C return
+
+C We added least significant limbs.  Now reload the next limbs to enter loop.
+L1:	lu	8,4(4)		C load s1 limb and update s1_ptr
+	lu	0,4(5)		C load s2 limb and update s2_ptr
+	stu	7,4(3)
+	sfe	7,0,8		C subtract limbs, set cy
+Leven:	lu	9,4(4)		C load s1 limb and update s1_ptr
+	lu	10,4(5)		C load s2 limb and update s2_ptr
+	bdz	Lend		C If done, skip loop
+
+Loop:	lu	8,4(4)		C load s1 limb and update s1_ptr
+	lu	0,4(5)		C load s2 limb and update s2_ptr
+	sfe	11,10,9		C subtract previous limbs with cy, set cy
+	stu	7,4(3)		C
+	lu	9,4(4)		C load s1 limb and update s1_ptr
+	lu	10,4(5)		C load s2 limb and update s2_ptr
+	sfe	7,0,8		C subtract previous limbs with cy, set cy
+	stu	11,4(3)		C
+	bdn	Loop		C decrement CTR and loop back
+
+Lend:	sfe	11,10,9		C subtract limbs with cy, set cy
+	st	7,4(3)		C
+	st	11,8(3)		C
+	sfe	3,0,0		C load !cy into ...
+	sfi	3,3,0		C ... return value register
+	br
+EPILOGUE(mpn_sub_n)
diff --git a/third_party/gmp/mpn/power/submul_1.asm b/third_party/gmp/mpn/power/submul_1.asm
new file mode 100644
index 0000000..1788e0d
--- /dev/null
+++ b/third_party/gmp/mpn/power/submul_1.asm
@@ -0,0 +1,131 @@
+dnl  IBM POWER mpn_submul_1 -- Multiply a limb vector with a limb and subtract
+dnl  the result from a second limb vector.
+
+dnl  Copyright 1992, 1994, 1999-2001 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+dnl  INPUT PARAMETERS
+dnl  res_ptr	r3
+dnl  s1_ptr	r4
+dnl  size	r5
+dnl  s2_limb	r6
+
+dnl  The POWER architecture has no unsigned 32x32->64 bit multiplication
+dnl  instruction.  To obtain that operation, we have to use the 32x32->64
+dnl  signed multiplication instruction, and add the appropriate compensation to
+dnl  the high limb of the result.  We add the multiplicand if the multiplier
+dnl  has its most significant bit set, and we add the multiplier if the
+dnl  multiplicand has its most significant bit set.  We need to preserve the
+dnl  carry flag between each iteration, so we have to compute the compensation
+dnl  carefully (the natural, srai+and doesn't work).  Since all POWER can
+dnl  branch in zero cycles, we use conditional branches for the compensation.
+
+include(`../config.m4')
+
+ASM_START()
+PROLOGUE(mpn_submul_1)
+	cal	3,-4(3)
+	l	0,0(4)
+	cmpi	0,6,0
+	mtctr	5
+	mul	9,0,6
+	srai	7,0,31
+	and	7,7,6
+	mfmq	11
+	cax	9,9,7
+	l	7,4(3)
+	sf	8,11,7		C add res_limb
+	a	11,8,11		C invert cy (r11 is junk)
+	blt	Lneg
+Lpos:	bdz	Lend
+
+Lploop:	lu	0,4(4)
+	stu	8,4(3)
+	cmpi	0,0,0
+	mul	10,0,6
+	mfmq	0
+	ae	11,0,9		C low limb + old_cy_limb + old cy
+	l	7,4(3)
+	aze	10,10		C propagate cy to new cy_limb
+	sf	8,11,7		C add res_limb
+	a	11,8,11		C invert cy (r11 is junk)
+	bge	Lp0
+	cax	10,10,6		C adjust high limb for negative limb from s1
+Lp0:	bdz	Lend0
+	lu	0,4(4)
+	stu	8,4(3)
+	cmpi	0,0,0
+	mul	9,0,6
+	mfmq	0
+	ae	11,0,10
+	l	7,4(3)
+	aze	9,9
+	sf	8,11,7
+	a	11,8,11		C invert cy (r11 is junk)
+	bge	Lp1
+	cax	9,9,6		C adjust high limb for negative limb from s1
+Lp1:	bdn	Lploop
+
+	b	Lend
+
+Lneg:	cax	9,9,0
+	bdz	Lend
+Lnloop:	lu	0,4(4)
+	stu	8,4(3)
+	cmpi	0,0,0
+	mul	10,0,6
+	mfmq	7
+	ae	11,7,9
+	l	7,4(3)
+	ae	10,10,0		C propagate cy to new cy_limb
+	sf	8,11,7		C add res_limb
+	a	11,8,11		C invert cy (r11 is junk)
+	bge	Ln0
+	cax	10,10,6		C adjust high limb for negative limb from s1
+Ln0:	bdz	Lend0
+	lu	0,4(4)
+	stu	8,4(3)
+	cmpi	0,0,0
+	mul	9,0,6
+	mfmq	7
+	ae	11,7,10
+	l	7,4(3)
+	ae	9,9,0		C propagate cy to new cy_limb
+	sf	8,11,7		C add res_limb
+	a	11,8,11		C invert cy (r11 is junk)
+	bge	Ln1
+	cax	9,9,6		C adjust high limb for negative limb from s1
+Ln1:	bdn	Lnloop
+	b	Lend
+
+Lend0:	cal	9,0(10)
+Lend:	st	8,4(3)
+	aze	3,9
+	br
+EPILOGUE(mpn_submul_1)
diff --git a/third_party/gmp/mpn/power/umul.asm b/third_party/gmp/mpn/power/umul.asm
new file mode 100644
index 0000000..5a0599e
--- /dev/null
+++ b/third_party/gmp/mpn/power/umul.asm
@@ -0,0 +1,43 @@
+dnl  Copyright 1999, 2001 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ASM_START()
+PROLOGUE(mpn_umul_ppmm)
+	mul	9,4,5
+	srai	0,4,31
+	and	0,0,5
+	srai	5,5,31
+	and	5,5,4
+	cax	0,0,5
+	mfmq	11
+	st	11,0(3)
+	cax	3,9,0
+	br
+EPILOGUE(mpn_umul_ppmm)
diff --git a/third_party/gmp/mpn/powerpc32/750/com.asm b/third_party/gmp/mpn/powerpc32/750/com.asm
new file mode 100644
index 0000000..1b8b574
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc32/750/com.asm
@@ -0,0 +1,79 @@
+dnl  PowerPC 750 mpn_com -- mpn bitwise one's complement
+
+dnl  Copyright 2002, 2003 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C                cycles/limb
+C 603e:            ?
+C 604e:            3.0
+C 75x (G3):        2.0
+C 7400,7410 (G4):  2.0
+C 744x,745x (G4+): 3.0
+
+C void mpn_com (mp_ptr dst, mp_srcptr src, mp_size_t size);
+C
+C This loop form is necessary for the claimed speed.
+
+ASM_START()
+PROLOGUE(mpn_com)
+
+	C r3	dst
+	C r4	src
+	C r5	size
+
+	mtctr	r5		C size
+	lwz	r5, 0(r4)	C src low limb
+
+	sub	r4, r4, r3	C src-dst
+	subi	r3, r3, 4	C dst-4
+
+	addi	r4, r4, 8	C src-dst+8
+	bdz	L(one)
+
+L(top):
+	C r3	&dst[i-1]
+	C r4	src-dst
+	C r5	src[i]
+	C r6	scratch
+
+	not	r6, r5		C ~src[i]
+	lwzx	r5, r4,r3	C src[i+1]
+
+	stwu	r6, 4(r3)	C dst[i]
+	bdnz	L(top)
+
+L(one):
+	not	r6, r5
+
+	stw	r6, 4(r3)	C dst[size-1]
+	blr
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc32/750/gmp-mparam.h b/third_party/gmp/mpn/powerpc32/750/gmp-mparam.h
new file mode 100644
index 0000000..3667e85
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc32/750/gmp-mparam.h
@@ -0,0 +1,192 @@
+/* PowerPC-32 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2002, 2004, 2009, 2010 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+
+/* This file is used for 75x (G3) and for 7400/7410 (G4), both which have
+   much slow multiply instructions.  */
+
+/* 450 MHz PPC 7400 */
+
+#define DIVREM_1_NORM_THRESHOLD              0  /* always */
+#define DIVREM_1_UNNORM_THRESHOLD            0  /* always */
+#define MOD_1_NORM_THRESHOLD                 3
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD         11
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          7
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        11
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        18
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     38
+#define USE_PREINV_DIVREM_1                  1
+#define DIVEXACT_1_THRESHOLD                 0  /* always */
+#define BMOD_1_TO_MOD_1_THRESHOLD        MP_SIZE_T_MAX  /* never */
+
+#define MUL_TOOM22_THRESHOLD                10
+#define MUL_TOOM33_THRESHOLD                38
+#define MUL_TOOM44_THRESHOLD                99
+#define MUL_TOOM6H_THRESHOLD               141
+#define MUL_TOOM8H_THRESHOLD               212
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      65
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD      69
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD      65
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD      66
+
+#define SQR_BASECASE_THRESHOLD               4
+#define SQR_TOOM2_THRESHOLD                 18
+#define SQR_TOOM3_THRESHOLD                 57
+#define SQR_TOOM4_THRESHOLD                142
+#define SQR_TOOM6_THRESHOLD                173
+#define SQR_TOOM8_THRESHOLD                309
+
+#define MULMOD_BNM1_THRESHOLD                9
+#define SQRMOD_BNM1_THRESHOLD               11
+
+#define MUL_FFT_MODF_THRESHOLD             220  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    220, 5}, {     13, 6}, {      7, 5}, {     15, 6}, \
+    {      8, 5}, {     17, 6}, {      9, 5}, {     19, 6}, \
+    {     13, 7}, {      7, 6}, {     17, 7}, {      9, 6}, \
+    {     19, 7}, {     11, 6}, {     23, 7}, {     13, 8}, \
+    {      7, 7}, {     19, 8}, {     11, 7}, {     23, 9}, \
+    {      7, 8}, {     15, 7}, {     33, 8}, {     19, 7}, \
+    {     39, 8}, {     23, 9}, {     15, 8}, {     39, 9}, \
+    {     23, 8}, {     47,10}, {     15, 9}, {     31, 8}, \
+    {     67, 9}, {     55,10}, {     31, 9}, {     63, 8}, \
+    {    127, 7}, {    255, 9}, {     71, 8}, {    143, 7}, \
+    {    287, 9}, {     79,10}, {     47, 9}, {     95,11}, \
+    {     31,10}, {     63, 9}, {    127, 8}, {    255, 9}, \
+    {    143, 8}, {    287,10}, {     79, 9}, {    159, 8}, \
+    {    319, 9}, {    175, 8}, {    351, 7}, {    703,10}, \
+    {     95, 9}, {    191, 8}, {    383, 9}, {    207,10}, \
+    {    111,11}, {     63,10}, {    127, 9}, {    255,10}, \
+    {    143, 9}, {    287, 8}, {    575,10}, {    159, 9}, \
+    {    319,10}, {    175, 9}, {    351, 8}, {    703,11}, \
+    {     95,10}, {    191, 9}, {    383,10}, {    207, 9}, \
+    {    415, 8}, {    831,12}, {     63,11}, {    127,10}, \
+    {    255, 9}, {    511,10}, {    271, 9}, {    543,10}, \
+    {    287, 9}, {    575,11}, {    159,10}, {    351, 9}, \
+    {    703, 8}, {   1407,11}, {    191,10}, {    415, 9}, \
+    {    831,11}, {    223,10}, {    447, 9}, {    895,12}, \
+    {    127,11}, {    255,10}, {    543,11}, {    287,10}, \
+    {    575,11}, {    351,10}, {    703, 9}, {   1407,12}, \
+    {    191,11}, {    415,10}, {    831,11}, {    447,10}, \
+    {    895,13}, {    127,12}, {    255,11}, {    543,10}, \
+    {   1087,11}, {    575,12}, {    319,11}, {    703,10}, \
+    {   1407,12}, {    383,11}, {    831,12}, {    447,11}, \
+    {    895,10}, {   1791,11}, {    959,13}, {    255,12}, \
+    {    511,11}, {   1087,12}, {    575,11}, {   1215,12}, \
+    {    703,11}, {   1407,13}, {    383,12}, {    895,11}, \
+    {   1791,12}, {    959,14}, {    255,13}, {    511,12}, \
+    {   1215,13}, {    639,12}, {   1407,13}, {    895,12}, \
+    {   1919,14}, {    511,13}, {   1023,12}, {   2047,13}, \
+    {   1151,12}, {   2303,13}, {   1407,14}, {    767,13}, \
+    {   1919,10}, {  15359,12}, {   4096,13}, {   8192,14}, \
+    {  16384,15}, {  32768,16} }
+#define MUL_FFT_TABLE3_SIZE 154
+#define MUL_FFT_THRESHOLD                 2688
+
+#define SQR_FFT_MODF_THRESHOLD             184  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    184, 5}, {      6, 4}, {     13, 5}, {     13, 6}, \
+    {      7, 5}, {     15, 6}, {     13, 7}, {      7, 6}, \
+    {     16, 7}, {      9, 6}, {     19, 7}, {     11, 6}, \
+    {     23, 7}, {     13, 8}, {      7, 7}, {     19, 8}, \
+    {     11, 7}, {     25, 9}, {      7, 8}, {     15, 7}, \
+    {     31, 8}, {     19, 7}, {     39, 8}, {     27, 9}, \
+    {     15, 8}, {     39, 9}, {     23,10}, {     15, 9}, \
+    {     31, 8}, {     63, 9}, {     39, 8}, {     79, 9}, \
+    {     47, 8}, {     95,10}, {     31, 9}, {     63, 8}, \
+    {    127, 7}, {    255, 9}, {     71, 8}, {    143, 7}, \
+    {    287, 9}, {     79, 8}, {    159,10}, {     47, 9}, \
+    {     95,11}, {     31,10}, {     63, 9}, {    127, 8}, \
+    {    255, 9}, {    143, 8}, {    287, 7}, {    575,10}, \
+    {     79, 9}, {    159, 8}, {    319, 9}, {    175, 8}, \
+    {    351,10}, {     95, 9}, {    191, 8}, {    383, 9}, \
+    {    207,10}, {    111,11}, {     63,10}, {    127, 9}, \
+    {    255,10}, {    143, 9}, {    287, 8}, {    575,10}, \
+    {    159, 9}, {    319,10}, {    175, 9}, {    351,11}, \
+    {     95,10}, {    191, 9}, {    383,10}, {    207, 9}, \
+    {    415, 8}, {    831,10}, {    223,12}, {     63,11}, \
+    {    127,10}, {    255, 9}, {    511,10}, {    287, 9}, \
+    {    575,11}, {    159,10}, {    351, 9}, {    703,11}, \
+    {    191,10}, {    415, 9}, {    831,11}, {    223,10}, \
+    {    447, 9}, {    895,12}, {    127,11}, {    255,10}, \
+    {    511,11}, {    287,10}, {    575,11}, {    319,10}, \
+    {    639,11}, {    351,10}, {    703, 9}, {   1407,12}, \
+    {    191,11}, {    383,10}, {    767,11}, {    415,10}, \
+    {    831,11}, {    447,10}, {    895,13}, {    127,12}, \
+    {    255,11}, {    511,10}, {   1023,11}, {    575,12}, \
+    {    319,11}, {    703,10}, {   1407,12}, {    383,11}, \
+    {    831,12}, {    447,11}, {    895,10}, {   1791,11}, \
+    {    959,13}, {    255,12}, {    511,11}, {   1023,12}, \
+    {    575,11}, {   1215,12}, {    703,11}, {   1407,13}, \
+    {    383,12}, {    895,11}, {   1791,12}, {    959,14}, \
+    {    255,13}, {    511,12}, {   1215,13}, {    639,12}, \
+    {   1471,13}, {    767,12}, {   1535,13}, {    895,12}, \
+    {   1919,14}, {    511,13}, {   1151,12}, {   2431,13}, \
+    {   1407,14}, {    767,13}, {   1919,15}, {  32768,16} }
+#define SQR_FFT_TABLE3_SIZE 152
+#define SQR_FFT_THRESHOLD                 1728
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  33
+#define MULLO_MUL_N_THRESHOLD             5240
+
+#define DC_DIV_QR_THRESHOLD                 31
+#define DC_DIVAPPR_Q_THRESHOLD             108
+#define DC_BDIV_QR_THRESHOLD                35
+#define DC_BDIV_Q_THRESHOLD                 88
+
+#define INV_MULMOD_BNM1_THRESHOLD           42
+#define INV_NEWTON_THRESHOLD               149
+#define INV_APPR_THRESHOLD                 125
+
+#define BINV_NEWTON_THRESHOLD              156
+#define REDC_1_TO_REDC_N_THRESHOLD          39
+
+#define MU_DIV_QR_THRESHOLD                807
+#define MU_DIVAPPR_Q_THRESHOLD             807
+#define MUPI_DIV_QR_THRESHOLD               66
+#define MU_BDIV_QR_THRESHOLD               667
+#define MU_BDIV_Q_THRESHOLD                807
+
+#define MATRIX22_STRASSEN_THRESHOLD         11
+#define HGCD_THRESHOLD                      87
+#define GCD_DC_THRESHOLD                   233
+#define GCDEXT_DC_THRESHOLD                198
+#define JACOBI_BASE_METHOD                   1
+
+#define GET_STR_DC_THRESHOLD                12
+#define GET_STR_PRECOMPUTE_THRESHOLD        28
+#define SET_STR_DC_THRESHOLD               390
+#define SET_STR_PRECOMPUTE_THRESHOLD       814
diff --git a/third_party/gmp/mpn/powerpc32/750/lshift.asm b/third_party/gmp/mpn/powerpc32/750/lshift.asm
new file mode 100644
index 0000000..3a1c1a7
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc32/750/lshift.asm
@@ -0,0 +1,155 @@
+dnl  PowerPC 750 mpn_lshift -- mpn left shift.
+
+dnl  Copyright 2002, 2003 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C       cycles/limb
+C 750:     3.0
+C 7400:    3.0
+
+
+C mp_limb_t mpn_lshift (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                       unsigned shift);
+C
+C This code is the same per-limb speed as mpn/powerpc32/lshift.asm, but
+C smaller and saving about 30 or so cycles of overhead.
+
+ASM_START()
+PROLOGUE(mpn_lshift)
+
+	C r3	dst
+	C r4	src
+	C r5	size
+	C r6	shift
+
+	mtctr	r5		C size
+	slwi	r5, r5, 2	C 4*size
+
+	subfic	r7, r6, 32	C 32-shift
+	add	r4, r4, r5	C &src[size]
+
+	add	r5, r3, r5	C &dst[size]
+	lwz	r8, -4(r4)	C src[size-1]
+	bdz	L(one)
+
+	lwzu	r9, -8(r4)	C src[size-2]
+
+	srw	r3, r8, r7	C return value
+	slw	r8, r8, r6	C src[size-1] << shift
+	bdz	L(two)
+
+
+L(top):
+	C r3	return value
+	C r4	src, incrementing
+	C r5	dst, incrementing
+	C r6	lshift
+	C r7	32-shift
+	C r8	src[i+1] << shift
+	C r9	src[i]
+	C r10
+
+	lwzu	r10, -4(r4)
+	srw	r11, r9, r7
+
+	or	r8, r8, r11
+	stwu	r8, -4(r5)
+
+	slw	r8, r9, r6
+	bdz	L(odd)
+
+	C r8	src[i+1] << shift
+	C r9
+	C r10	src[i]
+
+	lwzu	r9, -4(r4)
+	srw	r11, r10, r7
+
+	or	r8, r8, r11
+	stwu	r8, -4(r5)
+
+	slw	r8, r10, r6
+	bdnz	L(top)
+
+
+L(two):
+	C r3	return value
+	C r4
+	C r5	&dst[2]
+	C r6	shift
+	C r7	32-shift
+	C r8	src[1] << shift
+	C r9	src[0]
+	C r10
+
+	srw	r11, r9, r7
+	slw	r12, r9, r6	C src[0] << shift
+
+	or	r8, r8, r11
+	stw	r12, -8(r5)	C dst[0]
+
+	stw	r8, -4(r5)	C dst[1]
+	blr
+
+
+L(odd):
+	C r3	return value
+	C r4
+	C r5	&dst[2]
+	C r6	shift
+	C r7	32-shift
+	C r8	src[1] << shift
+	C r9
+	C r10	src[0]
+
+	srw	r11, r10, r7
+	slw	r12, r10, r6
+
+	or	r8, r8, r11
+	stw	r12, -8(r5)	C dst[0]
+
+	stw	r8, -4(r5)	C dst[1]
+	blr
+
+
+L(one):
+	C r5	&dst[1]
+	C r6	shift
+	C r7	32-shift
+	C r8	src[0]
+
+	srw	r3, r8, r7	C return value
+	slw	r8, r8, r6	C src[size-1] << shift
+
+	stw	r8, -4(r5)	C dst[0]
+	blr
+
+EPILOGUE(mpn_lshift)
diff --git a/third_party/gmp/mpn/powerpc32/750/rshift.asm b/third_party/gmp/mpn/powerpc32/750/rshift.asm
new file mode 100644
index 0000000..4825fee
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc32/750/rshift.asm
@@ -0,0 +1,153 @@
+dnl  PowerPC 750 mpn_rshift -- mpn right shift.
+
+dnl  Copyright 2002, 2003 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C       cycles/limb
+C 750:     3.0
+C 7400:    3.0
+
+
+C mp_limb_t mpn_rshift (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                       unsigned shift);
+C
+C This code is the same per-limb speed as mpn/powerpc32/rshift.asm, but
+C smaller and saving about 30 or so cycles of overhead.
+
+ASM_START()
+PROLOGUE(mpn_rshift)
+
+	C r3	dst
+	C r4	src
+	C r5	size
+	C r6	shift
+
+	mtctr	r5		C size
+	lwz	r8, 0(r4)	C src[0]
+
+	subfic	r7, r6, 32	C 32-shift
+	addi	r5, r3, -4	C dst-4
+
+	slw	r3, r8, r7	C return value
+	bdz	L(one)
+
+	lwzu	r9, 4(r4)	C src[1]
+	srw	r8, r8, r6	C src[0] >> shift
+	bdz	L(two)
+
+
+L(top):
+	C r3	return value
+	C r4	src, incrementing
+	C r5	dst, incrementing
+	C r6	shift
+	C r7	32-shift
+	C r8	src[i-1] >> shift
+	C r9	src[i]
+	C r10
+
+	lwzu	r10, 4(r4)
+	slw	r11, r9, r7
+
+	or	r8, r8, r11
+	stwu	r8, 4(r5)
+
+	srw	r8, r9, r6
+	bdz	L(odd)
+
+	C r8	src[i-1] >> shift
+	C r9
+	C r10	src[i]
+
+	lwzu	r9, 4(r4)
+	slw	r11, r10, r7
+
+	or	r8, r8, r11
+	stwu	r8, 4(r5)
+
+	srw	r8, r10, r6
+	bdnz	L(top)
+
+
+L(two):
+	C r3	return value
+	C r4
+	C r5	&dst[size-2]
+	C r6	shift
+	C r7	32-shift
+	C r8	src[size-2] >> shift
+	C r9	src[size-1]
+	C r10
+
+	slw	r11, r9, r7
+	srw	r12, r9, r6	C src[size-1] >> shift
+
+	or	r8, r8, r11
+	stw	r12, 8(r5)	C dst[size-1]
+
+	stw	r8, 4(r5)	C dst[size-2]
+	blr
+
+
+L(odd):
+	C r3	return value
+	C r4
+	C r5	&dst[size-2]
+	C r6	shift
+	C r7	32-shift
+	C r8	src[size-2] >> shift
+	C r9
+	C r10	src[size-1]
+
+	slw	r11, r10, r7
+	srw	r12, r10, r6
+
+	or	r8, r8, r11
+	stw	r12, 8(r5)	C dst[size-1]
+
+	stw	r8, 4(r5)	C dst[size-2]
+	blr
+
+
+L(one):
+	C r3	return value
+	C r4
+	C r5	dst-4
+	C r6	shift
+	C r7
+	C r8	src[0]
+
+	srw	r8, r8, r6
+
+	stw	r8, 4(r5)	C dst[0]
+	blr
+
+EPILOGUE(mpn_rshift)
diff --git a/third_party/gmp/mpn/powerpc32/README b/third_party/gmp/mpn/powerpc32/README
new file mode 100644
index 0000000..887e78b
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc32/README
@@ -0,0 +1,180 @@
+Copyright 2002, 2005 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.
+
+
+
+
+
+                    POWERPC 32-BIT MPN SUBROUTINES
+
+
+This directory contains mpn functions for various 32-bit PowerPC chips.
+
+
+CODE ORGANIZATION
+
+	directory	  used for
+	================================================
+	powerpc           generic, 604, 604e, 744x, 745x
+	powerpc/750       740, 750, 7400, 7410
+
+
+The top-level powerpc directory is currently mostly aimed at 604/604e but
+should be reasonable on all powerpcs.
+
+
+
+STATUS
+
+The code is quite well optimized for the 604e, other chips have had less
+attention.
+
+Altivec SIMD available in 74xx might hold some promise, but unfortunately
+GMP only guarantees 32-bit data alignment, so there's lots of fiddling
+around with partial operations at the start and end of limb vectors.  A
+128-bit limb would be a novel idea, but is unlikely to be practical, since
+it would have to work with ordinary +, -, * etc in the C code.
+
+Also, Altivec isn't very well suited for the GMP multiplication needs.
+Using floating-point based multiplication has much better better performance
+potential for all current powerpcs, both the ones with slow integer multiply
+units (603, 740, 750, 7400, 7410) and those with fast (604, 604e, 744x,
+745x).  This is because all powerpcs do some level of pipelining in the FPU:
+
+603 and 750 can sustain one fmadd every 2nd cycle.
+604 and 604e can sustain one fmadd per cycle.
+7400 and 7410 can sustain 3 fmadd in 4 cycles.
+744x and 745x can sustain 4 fmadd in 5 cycles.
+
+
+
+REGISTER NAMES
+
+The normal powerpc convention is to give registers as plain numbers, like
+"mtctr 6", but on Apple MacOS X (powerpc*-*-rhapsody* and
+powerpc*-*-darwin*) the assembler demands an "r" like "mtctr r6".  Note
+however when register 0 in an instruction means a literal zero the "r" is
+omitted, for instance "lwzx r6,0,r7".
+
+The GMP code uses the "r" forms, powerpc-defs.m4 transforms them to plain
+numbers according to what GMP_ASM_POWERPC_R_REGISTERS finds is needed.
+(Note that this style isn't fully general, as the identifier r4 and the
+register r4 will not be distinguishable on some systems.  However, this is
+not a problem for the limited GMP assembly usage.)
+
+
+
+GLOBAL REFERENCES
+
+Linux non-PIC
+	lis	9, __gmp_binvert_limb_table@ha
+	rlwinm	11, 5, 31, 25, 31
+	la	9, __gmp_binvert_limb_table@l(9)
+	lbzx	11, 9, 11
+
+Linux PIC (FIXME)
+.LCL0:
+	.long .LCTOC1-.LCF0
+	bcl	20, 31, .LCF0
+.LCF0:
+	mflr	30
+	lwz	7, .LCL0-.LCF0(30)
+	add	30, 7, 30
+	lwz	11, .LC0-.LCTOC1(30)
+	rlwinm	3, 5, 31, 25, 31
+	lbzx	7, 11, 3
+
+AIX (always PIC)
+LC..0:
+	.tc __gmp_binvert_limb_table[TC],__gmp_binvert_limb_table[RW]
+	lwz	9, LC..0(2)
+	rlwinm	0, 5, 31, 25, 31
+	lbzx	0, 9, 0
+
+Darwin (non-PIC)
+	lis	r2, ha16(___gmp_binvert_limb_table)
+	rlwinm	r9, r5, 31, 25, 31
+	la	r2, lo16(___gmp_binvert_limb_table)(r2)
+	lbzx	r0, r2, r9
+Darwin (PIC)
+	mflr	r0
+	bcl	20, 31, L0001$pb
+L0001$pb:
+	mflr	r7
+	mtlr	r0
+	addis	r2, r7, ha16(L___gmp_binvert_limb_table$non_lazy_ptr-L0001$pb)
+	rlwinm	r9, r5, 31, 25, 31
+	lwz	r2, lo16(L___gmp_binvert_limb_table$non_lazy_ptr-L0001$pb)(r2)
+	lbzx	r0, r2, r9
+------
+	.non_lazy_symbol_pointer
+L___gmp_binvert_limb_table$non_lazy_ptr:
+	.indirect_symbol ___gmp_binvert_limb_table
+	.long	0
+	.subsections_via_symbols
+
+
+For GNU/Linux and Darwin, we might want to duplicate __gmp_binvert_limb_table
+into the text section in this file.  We should thus be able to reach it like
+this:
+
+	blr	L0
+L0:	mflr	r2
+	rlwinm	r9, r5, 31, 25, 31
+	addi	r9, r9, lo16(local_binvert_table-L0)
+	lbzx	r0, r2, r9
+
+
+
+REFERENCES
+
+PowerPC Microprocessor Family: The Programming Environments for 32-bit
+Microprocessors, IBM document G522-0290-01, 2000.
+
+PowerPC 604e RISC Microprocessor User's Manual with Supplement for PowerPC
+604 Microprocessor, IBM document G552-0330-00, Freescale document
+MPC604EUM/AD, 3/1998.
+
+MPC7410/MPC7400 RISC Microprocessor User's Manual, Freescale document
+MPC7400UM/D, rev 1, 11/2002.
+
+MPC7450 RISC Microprocessor Family Reference Manual, Freescale document
+MPC7450UM, rev 5, 1/2005.
+
+The above are available online from
+
+	http://www.ibm.com/chips/techlib/techlib.nsf/productfamilies/PowerPC
+	http://www.freescale.com/PowerPC
+
+
+
+----------------
+Local variables:
+mode: text
+fill-column: 76
+End:
diff --git a/third_party/gmp/mpn/powerpc32/addlsh1_n.asm b/third_party/gmp/mpn/powerpc32/addlsh1_n.asm
new file mode 100644
index 0000000..71645c3
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc32/addlsh1_n.asm
@@ -0,0 +1,100 @@
+dnl  PowerPC-32 mpn_addlsh1_n -- rp[] = up[] + (vp[] << 1)
+
+dnl  Copyright 2003, 2005, 2007 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                cycles/limb
+C 603e:            ?
+C 604e:            4.0
+C 75x (G3):        5.0
+C 7400,7410 (G4):  5.0
+C 744x,745x (G4+): 5.0
+C power4/ppc970:   4.25
+C power5:          5.0
+
+C INPUT PARAMETERS
+C rp	r3
+C up	r4
+C vp	r5
+C n	r6
+
+define(`rp',`r3')
+define(`up',`r4')
+define(`vp',`r5')
+
+define(`s0',`r6')
+define(`s1',`r7')
+define(`u0',`r8')
+define(`v0',`r10')
+define(`v1',`r11')
+
+ASM_START()
+PROLOGUE(mpn_addlsh1_n)
+	mtctr	r6		C copy n in ctr
+	addic	r31, r31, 0	C clear cy
+
+	lwz	v0, 0(vp)	C load v limb
+	lwz	u0, 0(up)	C load u limb
+	addi	up, up, -4	C update up
+	addi	rp, rp, -4	C update rp
+	slwi	s1, v0, 1
+	bdz	L(end)		C If done, skip loop
+
+L(loop):
+	lwz	v1, 4(vp)	C load v limb
+	adde	s1, s1, u0	C add limbs with cy, set cy
+	srwi	s0, v0, 31	C shift down previous v limb
+	stw	s1, 4(rp)	C store result limb
+	lwzu	u0, 8(up)	C load u limb and update up
+	rlwimi	s0, v1, 1, 0,30	C left shift v limb and merge with prev v limb
+
+	bdz	L(exit)		C decrement ctr and exit if done
+
+	lwzu	v0, 8(vp)	C load v limb and update vp
+	adde	s0, s0, u0	C add limbs with cy, set cy
+	srwi	s1, v1, 31	C shift down previous v limb
+	stwu	s0, 8(rp)	C store result limb and update rp
+	lwz	u0, 4(up)	C load u limb
+	rlwimi	s1, v0, 1, 0,30	C left shift v limb and merge with prev v limb
+
+	bdnz	L(loop)		C decrement ctr and loop back
+
+L(end):	adde	r7, s1, u0
+	srwi	r4, v0, 31
+	stw	r7, 4(rp)	C store last result limb
+	addze	r3, r4
+	blr
+L(exit):
+	adde	r7, s0, u0
+	srwi	r4, v1, 31
+	stw	r7, 8(rp)	C store last result limb
+	addze	r3, r4
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc32/addmul_1.asm b/third_party/gmp/mpn/powerpc32/addmul_1.asm
new file mode 100644
index 0000000..07486df
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc32/addmul_1.asm
@@ -0,0 +1,159 @@
+dnl  PowerPC-32 mpn_addmul_1 -- Multiply a limb vector with a limb and add the
+dnl  result to a second limb vector.
+
+dnl  Copyright 1995, 1997, 1998, 2000-2003, 2005 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                cycles/limb
+C 603e:            ?
+C 604e:            6.75
+C 75x (G3):        8.7-14.3
+C 7400,7410 (G4):  8.7-14.3
+C 744x,745x (G4+): 9.5
+C power4/ppc970:   6.25
+C power5:          6.25
+
+C INPUT PARAMETERS
+C rp	r3
+C up	r4
+C n	r5
+C vl	r6
+
+C This is optimized for the PPC604.  It has not been tuned for other
+C PowerPC processors.
+C
+C Loop Analysis for the 604:
+C 12 mem insn
+C 8 serializing insn
+C 8 int multiply
+C 25 int reg write
+C 9 int ops (8 of which serialize)
+C
+C The multiply insns need 16 cycles/4limb.
+C The integer register writes will need 13 cycles/4limb.
+C All-in-all, it should be possible to get to 4 or 5 cycles/limb on PPC604,
+C but that will require some clever FPNOPS and BNOPS for exact
+C issue control.
+
+
+ASM_START()
+PROLOGUE(mpn_addmul_1)
+	cmpwi	cr0,r5,9	C more than 9 limbs?
+	bgt	cr0,L(big)	C branch if more than 9 limbs
+
+	mtctr	r5
+	lwz	r0,0(r4)
+	mullw	r7,r0,r6
+	mulhwu	r10,r0,r6
+	lwz	r9,0(r3)
+	addc	r8,r7,r9
+	addi	r3,r3,-4
+	bdz	L(end)
+L(loop):
+	lwzu	r0,4(r4)
+	stwu	r8,4(r3)
+	mullw	r8,r0,r6
+	adde	r7,r8,r10
+	mulhwu	r10,r0,r6
+	lwz	r9,4(r3)
+	addze	r10,r10
+	addc	r8,r7,r9
+	bdnz	L(loop)
+L(end):	stw	r8,4(r3)
+	addze	r3,r10
+	blr
+
+L(big):	stwu	r1,-16(r1)
+	addi	r5,r5,-1
+	stw	r30,8(r1)
+	srwi	r0,r5,2
+	stw	r31,12(r1)
+	mtctr	r0
+
+	lwz	r7,0(r4)
+	mullw	r8,r7,r6
+	mulhwu	r0,r7,r6
+	lwz	r7,0(r3)
+	addc	r8,r8,r7
+	stw	r8,0(r3)
+
+L(loopU):
+	lwz	r7,4(r4)
+	lwz	r12,8(r4)
+	lwz	r30,12(r4)
+	lwzu	r31,16(r4)
+	mullw	r8,r7,r6
+	mullw	r9,r12,r6
+	mullw	r10,r30,r6
+	mullw	r11,r31,r6
+	adde	r8,r8,r0	C add cy_limb
+	mulhwu	r0,r7,r6
+	lwz	r7,4(r3)
+	adde	r9,r9,r0
+	mulhwu	r0,r12,r6
+	lwz	r12,8(r3)
+	adde	r10,r10,r0
+	mulhwu	r0,r30,r6
+	lwz	r30,12(r3)
+	adde	r11,r11,r0
+	mulhwu	r0,r31,r6
+	lwz	r31,16(r3)
+	addze	r0,r0		C new cy_limb
+	addc	r8,r8,r7
+	stw	r8,4(r3)
+	adde	r9,r9,r12
+	stw	r9,8(r3)
+	adde	r10,r10,r30
+	stw	r10,12(r3)
+	adde	r11,r11,r31
+	stwu	r11,16(r3)
+	bdnz	L(loopU)
+
+	andi.	r31,r5,3
+	mtctr	r31
+	beq	cr0,L(endx)
+
+L(loopE):
+	lwzu	r7,4(r4)
+	mullw	r8,r7,r6
+	adde	r8,r8,r0	C add cy_limb
+	mulhwu	r0,r7,r6
+	lwz	r7,4(r3)
+	addze	r0,r0		C new cy_limb
+	addc	r8,r8,r7
+	stwu	r8,4(r3)
+	bdnz	L(loopE)
+L(endx):
+	addze	r3,r0
+	lwz	r30,8(r1)
+	lwz	r31,12(r1)
+	addi	r1,r1,16
+	blr
+EPILOGUE(mpn_addmul_1)
diff --git a/third_party/gmp/mpn/powerpc32/aix.m4 b/third_party/gmp/mpn/powerpc32/aix.m4
new file mode 100644
index 0000000..fde2020
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc32/aix.m4
@@ -0,0 +1,82 @@
+divert(-1)
+dnl  m4 macros for AIX 32-bit assembly.
+
+dnl  Copyright 2000-2002, 2005, 2006 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+define(`ASM_START',
+`	.toc')
+
+dnl  Called: PROLOGUE_cpu(GSYM_PREFIX`'foo)
+dnl          EPILOGUE_cpu(GSYM_PREFIX`'foo)
+dnl
+dnl  Don't want ELF style .size in the epilogue.
+
+define(`PROLOGUE_cpu',
+m4_assert_numargs(1)
+	`
+	.globl	$1
+	.globl	.$1
+	.csect	[DS], 2
+$1:
+	.long	.$1, TOC[tc0], 0
+	.csect	[PR]
+	.align	2
+.$1:')
+
+define(`EPILOGUE_cpu',
+m4_assert_numargs(1)
+`')
+
+define(`TOC_ENTRY', `')
+
+define(`LEA',
+m4_assert_numargs(2)
+`define(`TOC_ENTRY',
+`	.toc
+tc$2:
+	.tc	$2[TC], $2')'
+`	lwz	$1, tc$2(2)')
+
+define(`EXTERN',
+m4_assert_numargs(1)
+`	.globl	$1')
+
+define(`DEF_OBJECT',
+m4_assert_numargs_range(1,2)
+`	.csect	[RO], 3
+	ALIGN(ifelse($#,1,2,$2))
+$1:
+')
+
+define(`END_OBJECT',
+m4_assert_numargs(1))
+
+define(`ASM_END', `TOC_ENTRY')
+
+divert
diff --git a/third_party/gmp/mpn/powerpc32/aors_n.asm b/third_party/gmp/mpn/powerpc32/aors_n.asm
new file mode 100644
index 0000000..25ece09
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc32/aors_n.asm
@@ -0,0 +1,157 @@
+dnl  PowerPC-32 mpn_add_n and mpn_sub_n.
+
+dnl  Copyright 2002, 2005, 2007 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                   cycles/limb
+C 603e:                  ?
+C 604e:                  ?		old: 3.25
+C 75x (G3):              ?		old: 3.5
+C 7400,7410 (G4):        3.25
+C 744x,745x (G4+):       4
+C POWER3/PPC630          2
+C POWER4/PPC970          2.4
+C POWER5                 2.75
+C POWER6               40-140
+C POWER7                 3
+
+C INPUT PARAMETERS
+define(`rp',	`r3')
+define(`up',	`r4')
+define(`vp',	`r5')
+define(`n',	`r6')
+define(`cy',	`r7')
+
+ifdef(`OPERATION_add_n', `
+	define(ADCSBC,	adde)
+	define(func,	mpn_add_n)
+	define(func_nc,	mpn_add_nc)
+	define(IFADD,	`$1')
+	define(IFSUB,	`')')
+ifdef(`OPERATION_sub_n', `
+	define(ADCSBC,	subfe)
+	define(func,	mpn_sub_n)
+	define(func_nc,	mpn_sub_nc)
+	define(IFADD,	`')
+	define(IFSUB,	`$1')')
+
+MULFUNC_PROLOGUE(mpn_add_n mpn_add_nc mpn_sub_n mpn_sub_nc)
+
+ASM_START()
+
+PROLOGUE(func_nc)
+IFADD(`	addic	r0, cy, -1')		C set carry from argument
+IFSUB(`	subfic	r0, cy, 0')		C set carry from argument
+	b	L(ent)
+EPILOGUE()
+
+PROLOGUE(func)
+IFADD(`	addic	r0, n, 0')		C clear carry
+IFSUB(`	addic	r0, n, -1')		C set carry
+L(ent):	andi.	r0, n, 3
+	addi	r3, r3, -12
+	addi	n, n, 1
+	cmpwi	cr7, r0, 2
+	srwi	r0, n, 2
+	sub	r4, r4, r3
+	sub	r5, r5, r3
+	mtctr	r0
+	bne	cr0, L(n00)
+
+	lwzx	r7, r4, r3		C n = 4, 8, 12, ...
+	lwzx	r8, r5, r3
+	addi	r3, r3, 4
+	lwzx	r9, r4, r3
+	ADCSBC	r7, r8, r7
+	lwzx	r10, r5, r3
+	addi	r3, r3, 4
+	b	L(00)
+
+L(n00):	bge	cr7, L(n01)
+	cmpwi	cr0, r0, 0		C n = 1, 5, 9, 13, ...
+	lwzx	r0, r4, r3
+	lwzx	r6, r5, r3
+	addi	r3, r3, 4
+	ADCSBC	r0, r6, r0
+	ble	L(ret)
+L(gt1):	lwzx	r7, r4, r3
+	lwzx	r8, r5, r3
+	addi	r3, r3, 4
+	b	L(01)
+
+L(n10):
+	lwzx	r9, r4, r3		C n = 3, 7, 11, 15, ...
+	lwzx	r10, r5, r3
+	addi	r3, r3, 4
+	lwzx	r11, r4, r3
+	ADCSBC	r9, r10, r9
+	lwzx	r12, r5, r3
+	addi	r3, r3, 4
+	b	L(11)
+
+L(n01):	bne	cr7, L(n10)
+	cmpwi	cr0, r0, 0		C n = 2, 6, 10, 14, ...
+	lwzx	r11, r4, r3
+	lwzx	r12, r5, r3
+	addi	r3, r3, 4
+	lwzx	r0, r4, r3
+	ADCSBC	r11, r12, r11
+	lwzx	r6, r5, r3
+	addi	r3, r3, 4
+	ble	cr0, L(end)
+
+
+L(lp):	lwzx	r7, r4, r3
+	ADCSBC	r0, r6, r0
+	lwzx	r8, r5, r3
+	stwu	r11, 4(r3)
+L(01):	lwzx	r9, r4, r3
+	ADCSBC	r7, r8, r7
+	lwzx	r10, r5, r3
+	stwu	r0, 4(r3)
+L(00):	lwzx	r11, r4, r3
+	ADCSBC	r9, r10, r9
+	lwzx	r12, r5, r3
+	stwu	r7, 4(r3)
+L(11):	lwzx	r0, r4, r3
+	ADCSBC	r11, r12, r11
+	lwzx	r6, r5, r3
+	stwu	r9, 4(r3)
+	bdnz	L(lp)
+
+L(end):	ADCSBC	r0, r6, r0
+	stw	r11, 4(r3)
+L(ret):	stw	r0, 8(r3)
+IFADD(`	li	r3, 0	')
+IFADD(`	addze	r3, r3	')
+IFSUB(`	subfe	r3, r0, r0')
+IFSUB(`	neg	r3, r3')
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc32/bdiv_dbm1c.asm b/third_party/gmp/mpn/powerpc32/bdiv_dbm1c.asm
new file mode 100644
index 0000000..72b2c48
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc32/bdiv_dbm1c.asm
@@ -0,0 +1,131 @@
+dnl  PPC32 mpn_bdiv_dbm1c.
+
+dnl  Copyright 2008 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                cycles/limb
+C 603e:            ?
+C 604e:            ?
+C 75x (G3):        ?
+C 7400,7410 (G4):  9.43
+C 744x,745x (G4+): 6.28
+C power4/ppc970:   ?
+C power5:          ?
+
+C TODO
+C  * Nothing to do...
+
+C INPUT PARAMETERS
+define(`rp', `r3')
+define(`up', `r4')
+define(`n',  `r5')
+define(`bd', `r6')
+define(`cy', `r7')
+
+ASM_START()
+PROLOGUE(mpn_bdiv_dbm1c)
+	lwz	r0, 0(r4)
+
+	rlwinm.	r12, r5, 0,30,31
+	cmplwi	cr6, r12, 2
+	cmplwi	cr7, r5, 4
+	addi	r5, r5, 1
+	srwi	r5, r5, 2
+	mtctr	r5
+	beq	cr0, L(b00)
+	blt	cr6, L(b01)
+	beq	cr6, L(b10)
+
+L(b11):	mullw	r5, r0, r6
+	mulhwu	r12, r0, r6
+	lwz	r0, 4(r4)
+	addi	r4, r4, -12
+	addi	r3, r3, -12
+	b	L(3)
+
+L(b00):	mullw	r9, r0, r6
+	mulhwu	r8, r0, r6
+	lwz	r0, 4(r4)
+	addi	r4, r4, -8
+	addi	r3, r3, -8
+	b	L(0)
+
+L(b01):	mullw	r5, r0, r6
+	mulhwu	r12, r0, r6
+	addi	r3, r3, -4
+	ble	cr7, L(e1)
+	lwz	r0, 4(r4)
+	addi	r4, r4, -4
+	b	L(1)
+
+L(b10):	mullw	r9, r0, r6
+	mulhwu	r8, r0, r6
+	lwz	r0, 4(r4)
+	ble	cr7, L(e2)
+
+	ALIGN(16)
+L(top):	mullw	r5, r0, r6
+	mulhwu	r12, r0, r6
+	subfc	r11, r9, r7
+	lwz	r0, 8(r4)
+	subfe	r7, r8, r11
+	stw	r11, 0(r3)
+L(1):	mullw	r9, r0, r6
+	mulhwu	r8, r0, r6
+	subfc	r11, r5, r7
+	lwz	r0, 12(r4)
+	subfe	r7, r12, r11
+	stw	r11, 4(r3)
+L(0):	mullw	r5, r0, r6
+	mulhwu	r12, r0, r6
+	subfc	r11, r9, r7
+	lwz	r0, 16(r4)
+	subfe	r7, r8, r11
+	stw	r11, 8(r3)
+L(3):	mullw	r9, r0, r6
+	mulhwu	r8, r0, r6
+	subfc	r11, r5, r7
+	lwz	r0, 20(r4)
+	subfe	r7, r12, r11
+	stw	r11, 12(r3)
+	addi	r4, r4, 16
+	addi	r3, r3, 16
+	bdnz	L(top)
+
+L(e2):	mullw	r5, r0, r6
+	mulhwu	r12, r0, r6
+	subfc	r11, r9, r7
+	subfe	r7, r8, r11
+	stw	r11, 0(r3)
+L(e1):	subfc	r11, r5, r7
+	stw	r11, 4(r3)
+	subfe	r3, r12, r11
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc32/darwin.m4 b/third_party/gmp/mpn/powerpc32/darwin.m4
new file mode 100644
index 0000000..db42268
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc32/darwin.m4
@@ -0,0 +1,91 @@
+divert(-1)
+dnl  m4 macros for Mac OS 32-bit assembly.
+
+dnl  Copyright 2005, 2006 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+define(`ASM_START',`')
+
+dnl  Called: PROLOGUE_cpu(GSYM_PREFIX`'foo[,toc])
+dnl          EPILOGUE_cpu(GSYM_PREFIX`'foo)
+dnl
+
+define(`PROLOGUE_cpu',
+m4_assert_numargs_range(1,2)
+`ifelse(`$2',toc,,
+`ifelse(`$2',,,`m4_error(`Unrecognised PROLOGUE parameter')')')dnl
+	.text
+	.globl	$1
+	.align	3
+$1:')
+
+define(`EPILOGUE_cpu',
+m4_assert_numargs(1))
+
+
+dnl  LEA -- Load Effective Address.
+
+define(`LEA',
+m4_assert_numargs(2)
+`ifdef(`PIC',
+`	mflr	r0			C save return address
+	bcl	20, 31, 1f
+1:	mflr	$1
+	addis	$1, $1, ha16($2-1b)
+	la	$1, lo16($2-1b)($1)
+	mtlr	r0			C restore return address
+',`
+	lis	$1, ha16($2)
+	la	$1, lo16($2)($1)
+')')
+
+define(`LEAL',
+m4_assert_numargs(2)
+`LEA($1,$2)')
+
+
+define(`EXTERN',
+m4_assert_numargs(1)
+`dnl')
+
+define(`DEF_OBJECT',
+m4_assert_numargs_range(1,2)
+`	.const
+	ALIGN(ifelse($#,1,2,$2))
+$1:
+')
+
+define(`END_OBJECT',
+m4_assert_numargs(1))
+
+define(`ASM_END', `dnl')
+
+ifdef(`PIC',`
+define(`PIC_SLOW')')
+
+divert
diff --git a/third_party/gmp/mpn/powerpc32/diveby3.asm b/third_party/gmp/mpn/powerpc32/diveby3.asm
new file mode 100644
index 0000000..288a7d3
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc32/diveby3.asm
@@ -0,0 +1,93 @@
+dnl  PowerPC-32 mpn_divexact_by3 -- mpn by 3 exact division
+
+dnl  Copyright 2002, 2003, 2005, 2006 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                cycles/limb
+C 603e:              ?
+C 604e:              5
+C 75x (G3):          ?
+C 7400,7410 (G4):    8
+C 744x,745x (G4+):   6
+C power4/ppc970:    12
+C power5:            ?
+
+C void mpn_divexact_by3 (mp_ptr dst, mp_srcptr src, mp_size_t size);
+C
+C We avoid the slow subfe instruction and instead rely on an extremely unlikely
+C branch.
+C
+C The mullw has the inverse in the first operand, since 0xAA..AB won't allow
+C any early-out.  The src[] data normally won't either, but there's at least
+C a chance, whereas 0xAA..AB never will.  If, for instance, src[] is all
+C zeros (not a sensible input of course) we run at 7.0 c/l on ppc750.
+C
+C The mulhwu has the "3" multiplier in the second operand, which lets 750 and
+C 7400 use an early-out.
+
+C INPUT PARAMETERS
+define(`rp', `r3')
+define(`up', `r4')
+define(`n',  `r5')
+define(`cy', `r6')
+
+ASM_START()
+PROLOGUE(mpn_divexact_by3c)
+	lwz	r11, 0(up)
+	mtctr	n
+	lis	r12, 0xAAAA
+	ori	r12, r12, 0xAAAB
+	li	r10, 3
+
+	cmplw	cr7, cy, r11
+	subf	r11, cy, r11
+
+	mullw	r0, r11, r12
+	stw	r0, 0(rp)
+	bdz	L(one)
+
+L(top):	lwzu	r9, 4(up)
+	mulhwu	r7, r0, r10
+	bgt-	cr7, L(adj)		C very unlikely branch
+L(bko):	cmplw	cr7, r7, r9
+	subf	r0, r7, r9
+	mullw	r0, r12, r0
+	stwu	r0, 4(rp)
+	bdnz	L(top)
+
+L(one):	mulhwu	r3, r0, r10
+	blelr+	cr7
+	addi	r3, r3, 1
+	blr
+
+L(adj):	addi	r7, r7, 1
+	b	L(bko)
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/powerpc32/divrem_2.asm b/third_party/gmp/mpn/powerpc32/divrem_2.asm
new file mode 100644
index 0000000..74423f4
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc32/divrem_2.asm
@@ -0,0 +1,182 @@
+dnl  PPC-32 mpn_divrem_2 -- Divide an mpn number by a normalized 2-limb number.
+
+dnl  Copyright 2007, 2008, 2012, 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		cycles/limb
+C		norm	frac
+C 7410		~36.5	~36.5
+C 744x, 745x	 29	 29
+
+C INPUT PARAMETERS
+C qp  = r3
+C fn  = r4
+C up  = r5
+C un  = r6
+C d   = r7
+
+C TODO
+C  * Decrease register usage.
+C  * Make sure mul operands and optimal for early-out.
+C  * Check that things work well for a shared library build.
+C  * Write an invert_limb, perhaps inline, perhaps as a private call.  Or at
+C    least vastly improve the current __udiv_qrnnd_c based code.
+
+
+ASM_START()
+PROLOGUE(mpn_divrem_2)
+	stwu	r1, -32(r1)
+	slwi	r0, r6, 2
+	add	r5, r5, r0
+	stmw	r28, 8(r1)
+	addi	r29, r5, -8		C up = up_param + un - 2
+	lwz	r10, 4(r7)
+	lwz	r12, 4(r29)
+	addi	r8, r3, -12
+	lwz	r7, 0(r7)
+	cmplw	cr7, r12, r10
+	lwz	r28, 0(r29)
+	blt-	cr7, L(2)
+	bgt+	cr7, L(4)
+	cmplw	cr7, r28, r7
+	blt-	cr7, L(2)
+L(4):	subfc	r28, r7, r28
+	subfe	r12, r10, r12
+	li	r3, 1
+	b	L(6)
+L(2):	li	r3, 0
+
+L(6):	add	r0, r4, r6
+	addic.	r30, r0, -2
+	ble-	cr0, L(ret)
+
+	slwi	r9, r0, 2
+	add	r8, r8, r9		C rp += un + fn
+	mtctr	r30
+
+C Compute di from d1
+	srwi	r11, r10, 16
+	nor	r0, r10, r10
+	divwu	r31, r0, r11
+	rlwinm	r5, r10, 0, 16, 31
+	mullw	r9, r11, r31
+	mullw	r6, r5, r31
+	subf	r0, r9, r0
+	slwi	r0, r0, 16
+	ori	r0, r0, 65535
+	cmplw	cr7, r0, r6
+	bge-	cr7, L(9)
+	add	r0, r0, r10
+	cmplw	cr7, r0, r10
+	cmplw	cr6, r6, r0
+	addi	r31, r31, -1		C q1--
+	crorc	28, 28, 25
+	blt+	cr7, L(9)
+	addi	r31, r31, -1		C q1--
+	add	r0, r0, r10
+L(9):	subf	r0, r6, r0
+	divwu	r6, r0, r11
+	mullw	r9, r11, r6
+	mullw	r11, r5, r6
+	subf	r0, r9, r0
+	slwi	r0, r0, 16
+	ori	r0, r0, 65535
+	cmplw	cr7, r0, r11
+	bge-	cr7, L(13)
+	add	r0, r0, r10
+	cmplw	cr7, r0, r10
+	cmplw	cr6, r11, r0
+	addi	r6, r6, -1		C q0--
+	crorc	28, 28, 25
+	blt+	cr7, L(13)
+C	add	r0, r0, r10		C final remainder
+	addi	r6, r6, -1		C q0--
+L(13):	rlwimi	r6, r31, 16, 0, 15	C assemble final quotient
+
+C Adjust di by including d0
+	mullw	r9, r10, r6		C t0 = LO(di * d1)
+	addc	r11, r9, r7
+	subfe	r0, r1, r1
+	mulhwu	r9, r6, r7		C s1 = HI(di * d0)
+	addc	r9, r11, r9
+	addze.	r0, r0
+	blt	cr0, L(17)
+L(18):	subfc	r9, r10, r9
+	addi	r6, r6, -1
+	addme.	r0, r0
+	bge+	cr0, L(18)
+L(17):
+
+C r0  r3  r4  r5  r6  r7  r8  r9 r10 r11 r12 r28 r29 r30 r31
+C     msl         di  d0  qp     d1          fn  up  un
+L(loop):
+	mullw	r0, r12, r6		C q0 = LO(n2 * di)
+	cmpw	cr7, r30, r4
+	addc	r31, r0, r28		C q0 += n1
+	mulhwu	r9, r12, r6		C q  = HI(n2 * di)
+	adde	r12, r9, r12		C q  += n2
+	addi	r30, r30, -1
+	mullw	r0, r10, r12		C d1 * q
+	li	r9, 0
+	subf	r0, r0, r28		C n1 -= d1 * q
+	addi	r5, r12, 1
+	ble-	cr7, L(23)
+	lwzu	r9, -4(r29)
+L(23):	mullw	r11, r12, r7		C t0 = LO(d0 * q)
+	subfc	r28, r7, r9		C n0 -= d0
+	subfe	r0, r10, r0		C n1 -= d1
+	mulhwu	r12, r12, r7		C t1 = HI(d0 * q)
+	subfc	r28, r11, r28		C n0 -= t0
+	subfe	r12, r12, r0		C n1 -= t1
+	cmplw	cr7, r12, r31
+	blt+	cr7, L(24)
+	addc	r28, r28, r7
+	adde	r12, r12, r10
+	addi	r5, r5, -1
+L(24):	cmplw	cr7, r12, r10
+	bge-	cr7, L(fix)
+L(bck):	stw	r5, 0(r8)
+	addi	r8, r8, -4
+	bdnz	L(loop)
+
+L(ret):	stw	r28, 0(r29)
+	stw	r12, 4(r29)
+	lmw	r28, 8(r1)
+	addi	r1, r1, 32
+	blr
+
+L(fix):	cmplw	cr6, r28, r7
+	bgt+	cr7, L(28)
+	blt-	cr6, L(bck)
+L(28):	subfc	r28, r7, r28
+	subfe	r12, r10, r12
+	addi	r5, r5, 1
+	b	L(bck)
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc32/eabi.m4 b/third_party/gmp/mpn/powerpc32/eabi.m4
new file mode 100644
index 0000000..cd7633c
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc32/eabi.m4
@@ -0,0 +1,86 @@
+divert(-1)
+dnl  m4 macros for powerpc32 eABI assembly.
+
+dnl  Copyright 2003, 2005, 2006 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+define(`ASM_START',`')
+
+dnl  Called: PROLOGUE_cpu(GSYM_PREFIX`'foo)
+dnl          EPILOGUE_cpu(GSYM_PREFIX`'foo)
+dnl
+
+define(`PROLOGUE_cpu',
+m4_assert_numargs(1)
+	`
+	.section	".text"
+	.align	3
+	.globl	$1
+	.type	$1, @function
+$1:')
+
+define(`EPILOGUE_cpu',
+m4_assert_numargs(1)
+`	.size	$1, .-$1')
+
+dnl  This ought to support PIC, but it is unclear how that is done for eABI
+define(`LEA',
+m4_assert_numargs(2)
+`
+	lis	$1, $2@ha
+	la	$1, $2@l($1)
+')
+
+define(`EXTERN',
+m4_assert_numargs(1)
+`dnl')
+
+define(`DEF_OBJECT',
+m4_assert_numargs_range(1,2)
+`
+	.section	.rodata
+	ALIGN(ifelse($#,1,2,$2))
+	.type	$1, @object
+$1:
+')
+
+define(`END_OBJECT',
+m4_assert_numargs(1)
+`	.size	$1, .-$1')
+
+define(`ASM_END', `dnl')
+
+ifdef(`PIC',`
+define(`PIC_SLOW')')
+
+dnl  64-bit "long long" parameters are put in an even-odd pair, skipping an
+dnl  even register if that was in turn.  I wish somebody could explain why that
+dnl  is a good idea.
+define(`BROKEN_LONGLONG_PARAM')
+
+divert
diff --git a/third_party/gmp/mpn/powerpc32/elf.m4 b/third_party/gmp/mpn/powerpc32/elf.m4
new file mode 100644
index 0000000..1ed9c12
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc32/elf.m4
@@ -0,0 +1,100 @@
+divert(-1)
+dnl  m4 macros for powerpc32 GNU/Linux assembly.
+
+dnl  Copyright 2003, 2005, 2006 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+define(`ASM_START',`')
+
+dnl  Called: PROLOGUE_cpu(GSYM_PREFIX`'foo[,toc])
+dnl          EPILOGUE_cpu(GSYM_PREFIX`'foo)
+dnl
+
+define(`PROLOGUE_cpu',
+m4_assert_numargs_range(1,2)
+`ifelse(`$2',toc,,
+`ifelse(`$2',,,`m4_error(`Unrecognised PROLOGUE parameter')')')dnl
+	.section	".text"
+	.align	3
+	.globl	$1
+	.type	$1, @function
+$1:')
+
+define(`EPILOGUE_cpu',
+m4_assert_numargs(1)
+`	.size	$1, .-$1')
+
+define(`LEA',
+m4_assert_numargs(2)
+`ifdef(`PIC',`
+	mflr	r0
+	bcl	20, 31, 1f
+1:	mflr	$1
+	addis	$1, $1, (_GLOBAL_OFFSET_TABLE_-1b)@ha
+	addi	$1, $1, (_GLOBAL_OFFSET_TABLE_-1b)@l
+	mtlr	r0
+	lwz	$1, $2@got($1)
+',`
+	lis	$1, $2@ha
+	la	$1, $2@l($1)
+')')
+
+
+define(`LEAL',
+m4_assert_numargs(2)
+`LEA($1,$2)')
+
+
+define(`EXTERN',
+m4_assert_numargs(1)
+`dnl')
+
+define(`DEF_OBJECT',
+m4_assert_numargs_range(1,2)
+`
+	.section	.rodata
+	ALIGN(ifelse($#,1,2,$2))
+	.type	$1, @object
+$1:
+')
+
+define(`END_OBJECT',
+m4_assert_numargs(1)
+`	.size	$1, .-$1')
+
+define(`ASM_END', `dnl')
+
+ifdef(`PIC',`
+define(`PIC_SLOW')')
+
+dnl  64-bit "long long" parameters are put in an even-odd pair, skipping an
+dnl  even register if that was in turn.  I wish somebody could explain why that
+dnl  is a good idea.
+define(`BROKEN_LONGLONG_PARAM')
+
+divert
diff --git a/third_party/gmp/mpn/powerpc32/gmp-mparam.h b/third_party/gmp/mpn/powerpc32/gmp-mparam.h
new file mode 100644
index 0000000..e835a39
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc32/gmp-mparam.h
@@ -0,0 +1,222 @@
+/* PowerPC-32 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 1999-2004, 2008-2010, 2014, 2015 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+
+/* This file is supposed to be used for 604, 604e, 744x/745x/747x (G4+), i.e.,
+   32-bit PowerPC processors with reasonably fast integer multiply insns.  The
+   values below are chosen to be best for the latter processors, since 604 is
+   largely irrelevant today.
+
+   In mpn/powerpc32/750/gmp-mparam.h there are values for 75x (G3) and for
+   7400/7410 (G4), both which have much slower multiply instructions.  */
+
+/* 1417 MHz PPC 7447A */
+/* FFT tuning limit = 15 M */
+/* Generated by tuneup.c, 2015-10-08, gcc 4.6 */
+
+#define DIVREM_1_NORM_THRESHOLD              0  /* always */
+#define DIVREM_1_UNNORM_THRESHOLD            0  /* always */
+#define MOD_1_1P_METHOD                      1
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          8
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          6
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD         8
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        45
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     18
+#define USE_PREINV_DIVREM_1                  1
+#define DIV_QR_1N_PI1_METHOD                 1
+#define DIV_QR_1_NORM_THRESHOLD              2
+#define DIV_QR_1_UNNORM_THRESHOLD            1
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always */
+#define BMOD_1_TO_MOD_1_THRESHOLD           69
+
+#define MUL_TOOM22_THRESHOLD                14
+#define MUL_TOOM33_THRESHOLD                73
+#define MUL_TOOM44_THRESHOLD               106
+#define MUL_TOOM6H_THRESHOLD               156
+#define MUL_TOOM8H_THRESHOLD               236
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      73
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD      71
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD      73
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD      72
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD      82
+
+#define SQR_BASECASE_THRESHOLD               0  /* always */
+#define SQR_TOOM2_THRESHOLD                 22
+#define SQR_TOOM3_THRESHOLD                 74
+#define SQR_TOOM4_THRESHOLD                142
+#define SQR_TOOM6_THRESHOLD                190
+#define SQR_TOOM8_THRESHOLD                333
+
+#define MULMID_TOOM42_THRESHOLD             32
+
+#define MULMOD_BNM1_THRESHOLD                9
+#define SQRMOD_BNM1_THRESHOLD               13
+
+#define MUL_FFT_MODF_THRESHOLD             284  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    284, 5}, {     15, 6}, {      8, 5}, {     17, 6}, \
+    {      9, 5}, {     19, 6}, {     17, 7}, {      9, 6}, \
+    {     20, 7}, {     11, 6}, {     23, 7}, {     13, 8}, \
+    {      7, 7}, {     19, 8}, {     11, 7}, {     25, 9}, \
+    {      7, 8}, {     15, 7}, {     33, 8}, {     19, 7}, \
+    {     39, 8}, {     23, 7}, {     47, 8}, {     27, 9}, \
+    {     15, 8}, {     39, 9}, {     23, 8}, {     47,10}, \
+    {     15, 9}, {     31, 8}, {     67, 9}, {     39, 8}, \
+    {     79, 9}, {     47, 8}, {     95,10}, {     31, 9}, \
+    {     71, 8}, {    143, 9}, {     79,10}, {     47, 9}, \
+    {     95,11}, {     31,10}, {     63, 9}, {    127, 8}, \
+    {    255, 9}, {    135, 8}, {    271, 9}, {    143,10}, \
+    {     79, 9}, {    159, 8}, {    319, 9}, {    175,10}, \
+    {     95, 9}, {    191, 8}, {    383, 9}, {    207, 8}, \
+    {    415,11}, {     63,10}, {    127, 9}, {    255, 8}, \
+    {    511, 9}, {    271,10}, {    143, 9}, {    287, 8}, \
+    {    575,10}, {    159, 9}, {    319,10}, {    175,11}, \
+    {     95,10}, {    191, 9}, {    383,10}, {    207, 9}, \
+    {    415, 8}, {    831,12}, {     63,11}, {    127,10}, \
+    {    255, 9}, {    511,10}, {    271, 9}, {    543, 8}, \
+    {   1087,10}, {    287, 9}, {    575,11}, {    159,10}, \
+    {    319, 9}, {    639,10}, {    351, 9}, {    703,11}, \
+    {    191,10}, {    415, 9}, {    831,11}, {    223,10}, \
+    {    447, 9}, {    895,10}, {    479, 9}, {    959,12}, \
+    {    127,11}, {    255,10}, {    543, 9}, {   1087,11}, \
+    {    287,10}, {    607,11}, {    319,10}, {    639,11}, \
+    {    351,10}, {    703, 9}, {   1407,12}, {    191,11}, \
+    {    383,10}, {    767,11}, {    415,10}, {    831,11}, \
+    {    447,10}, {    895,11}, {    479,10}, {    959,13}, \
+    {    127,12}, {    255,11}, {    543,10}, {   1087,11}, \
+    {    607,12}, {    319,11}, {    639,10}, {   1279,11}, \
+    {    703,10}, {   1407,12}, {    383,11}, {    831,12}, \
+    {    447,11}, {    959,13}, {    255,12}, {    511,11}, \
+    {   1087,12}, {    575,11}, {   1215,10}, {   2431,12}, \
+    {    639,11}, {   1279,12}, {    703,11}, {   1407,13}, \
+    {    383,12}, {    959,14}, {    255,13}, {    511,12}, \
+    {   1215,11}, {   2431,13}, {    639,12}, {   1471,13}, \
+    {    767,12}, {   1599,13}, {    895,12}, {   1919,14}, \
+    {    511,13}, {   1023,12}, {   2111,13}, {   1151,12}, \
+    {   2431,13}, {   1407,14}, {    767,13}, {   1535,12}, \
+    {   3071,13}, {   8192,14}, {  16384,15}, {  32768,16} }
+#define MUL_FFT_TABLE3_SIZE 164
+#define MUL_FFT_THRESHOLD                 3712
+
+#define SQR_FFT_MODF_THRESHOLD             248  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    248, 5}, {     17, 6}, {      9, 5}, {     19, 6}, \
+    {     17, 7}, {      9, 6}, {     20, 7}, {     11, 6}, \
+    {     23, 7}, {     13, 8}, {      7, 7}, {     19, 8}, \
+    {     11, 7}, {     25, 9}, {      7, 8}, {     15, 7}, \
+    {     33, 8}, {     19, 7}, {     39, 8}, {     27, 9}, \
+    {     15, 8}, {     39, 9}, {     23, 8}, {     47,10}, \
+    {     15, 9}, {     31, 8}, {     63, 9}, {     39, 8}, \
+    {     79, 9}, {     47,10}, {     31, 9}, {     63, 8}, \
+    {    127, 9}, {     71, 8}, {    143, 9}, {     79,10}, \
+    {     47, 9}, {     95,11}, {     31,10}, {     63, 9}, \
+    {    127, 8}, {    255, 7}, {    511, 9}, {    143,10}, \
+    {     79, 9}, {    159, 8}, {    319, 9}, {    175, 8}, \
+    {    351,10}, {     95, 9}, {    191, 8}, {    383, 9}, \
+    {    207, 8}, {    415, 7}, {    831,11}, {     63,10}, \
+    {    127, 9}, {    255, 8}, {    511,10}, {    143, 9}, \
+    {    287, 8}, {    575,10}, {    159, 9}, {    319,10}, \
+    {    175, 9}, {    351,11}, {     95,10}, {    191, 9}, \
+    {    383,10}, {    207, 9}, {    415, 8}, {    831,12}, \
+    {     63,11}, {    127,10}, {    255, 9}, {    511,10}, \
+    {    271, 9}, {    543,10}, {    287, 9}, {    575,11}, \
+    {    159,10}, {    319, 9}, {    639,10}, {    351, 9}, \
+    {    703,11}, {    191,10}, {    383, 9}, {    767,10}, \
+    {    415, 9}, {    831,11}, {    223,10}, {    447, 9}, \
+    {    895,12}, {    127,11}, {    255,10}, {    543,11}, \
+    {    287,10}, {    607,11}, {    319,10}, {    639,11}, \
+    {    351,10}, {    703, 9}, {   1407,12}, {    191,11}, \
+    {    383,10}, {    767,11}, {    415,10}, {    831,11}, \
+    {    447,10}, {    895,11}, {    479,13}, {    127,12}, \
+    {    255,11}, {    543,10}, {   1087,11}, {    607,12}, \
+    {    319,11}, {    639,10}, {   1279,11}, {    703,10}, \
+    {   1407,12}, {    383,11}, {    831,12}, {    447,11}, \
+    {    959,13}, {    255,12}, {    511,11}, {   1087,12}, \
+    {    575,11}, {   1215,12}, {    639,11}, {   1279,12}, \
+    {    703,11}, {   1407,13}, {    383,12}, {    959,14}, \
+    {    255,13}, {    511,12}, {   1215,13}, {    639,12}, \
+    {   1471,13}, {    767,12}, {   1599,13}, {    895,12}, \
+    {   1919,14}, {    511,13}, {   1023,12}, {   2111,13}, \
+    {   1151,12}, {   2431,13}, {   1407,14}, {    767,13}, \
+    {   1535,12}, {   3199,13}, {   8192,14}, {  16384,15}, \
+    {  32768,16} }
+#define SQR_FFT_TABLE3_SIZE 157
+#define SQR_FFT_THRESHOLD                 2688
+
+#define MULLO_BASECASE_THRESHOLD             2
+#define MULLO_DC_THRESHOLD                  50
+#define MULLO_MUL_N_THRESHOLD             6633
+#define SQRLO_BASECASE_THRESHOLD             4
+#define SQRLO_DC_THRESHOLD                 115
+#define SQRLO_SQR_THRESHOLD               5274
+
+#define DC_DIV_QR_THRESHOLD                 43
+#define DC_DIVAPPR_Q_THRESHOLD             141
+#define DC_BDIV_QR_THRESHOLD                51
+#define DC_BDIV_Q_THRESHOLD                120
+
+#define INV_MULMOD_BNM1_THRESHOLD           43
+#define INV_NEWTON_THRESHOLD               173
+#define INV_APPR_THRESHOLD                 156
+
+#define BINV_NEWTON_THRESHOLD              204
+#define REDC_1_TO_REDC_N_THRESHOLD          51
+
+#define MU_DIV_QR_THRESHOLD               1017
+#define MU_DIVAPPR_Q_THRESHOLD            1078
+#define MUPI_DIV_QR_THRESHOLD               84
+#define MU_BDIV_QR_THRESHOLD               872
+#define MU_BDIV_Q_THRESHOLD               1078
+
+#define POWM_SEC_TABLE  1,16,102,428,1378
+
+#define GET_STR_DC_THRESHOLD                12
+#define GET_STR_PRECOMPUTE_THRESHOLD        27
+#define SET_STR_DC_THRESHOLD               781
+#define SET_STR_PRECOMPUTE_THRESHOLD      1505
+
+#define FAC_DSC_THRESHOLD                  141
+#define FAC_ODD_THRESHOLD                   34
+
+#define MATRIX22_STRASSEN_THRESHOLD         12
+#define HGCD_THRESHOLD                     118
+#define HGCD_APPR_THRESHOLD                161
+#define HGCD_REDUCE_THRESHOLD             1679
+#define GCD_DC_THRESHOLD                   351
+#define GCDEXT_DC_THRESHOLD                273
+#define JACOBI_BASE_METHOD                   4
diff --git a/third_party/gmp/mpn/powerpc32/invert_limb.asm b/third_party/gmp/mpn/powerpc32/invert_limb.asm
new file mode 100644
index 0000000..612bfe5
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc32/invert_limb.asm
@@ -0,0 +1,142 @@
+dnl  PowerPC-32 mpn_invert_limb -- Invert a normalized limb.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		 cycles/limb
+C 603e:		      ?
+C 604e:		      ?
+C 75x (G3):	      ?
+C 7400,7410 (G4):     ?
+C 744x,745x (G4+):   32
+C power4/ppc970:      ?
+C power5:	      ?
+
+EXTERN(approx_tab)
+
+ASM_START()
+PROLOGUE(mpn_invert_limb)
+	rlwinm	r6, r3, 11, 22, 30	C extract bits 30..22 to pos 2^1
+	srwi	r10, r3, 11		C extract bits 31..11
+	LEA(	r9, approx_tab)		C N.B. clobbers r0 for ELF and Darwin
+	lhzx	r9, r9, r6		C w2
+	addi	r0, r10, 1
+	mullw	r11, r9, r9
+	slwi	r9, r9, 4
+	mulhwu	r7, r11, r0
+	rlwinm	r11, r3, 0, 31, 31	C extract bit 0
+	addi	r0, r9, -1
+	srwi	r9, r3, 1		C d >> 1
+	subf	r0, r7, r0		C w1
+	add	r9, r9, r11		C d31
+	mullw	r9, r0, r9		C w1 * d31
+	srwi	r10, r0, 1		C w1 >> 1
+	neg	r11, r11
+	and	r11, r10, r11
+	subf	r11, r9, r11
+	mulhwu	r9, r11, r0
+	slwi	r0, r0, 15
+	srwi	r9, r9, 1
+	add	r0, r9, r0		C w0
+	mullw	r10, r0, r3
+	mulhwu	r9, r0, r3
+	addc	r11, r10, r3
+	adde	r3, r9, r3
+	subf	r3, r3, r0
+	blr
+EPILOGUE()
+
+DEF_OBJECT(approx_tab)
+	.short 0x7fe1,0x7fa1,0x7f61,0x7f22,0x7ee3,0x7ea4,0x7e65,0x7e27
+	.short 0x7de9,0x7dab,0x7d6d,0x7d30,0x7cf3,0x7cb6,0x7c79,0x7c3d
+	.short 0x7c00,0x7bc4,0x7b89,0x7b4d,0x7b12,0x7ad7,0x7a9c,0x7a61
+	.short 0x7a27,0x79ec,0x79b2,0x7979,0x793f,0x7906,0x78cc,0x7894
+	.short 0x785b,0x7822,0x77ea,0x77b2,0x777a,0x7742,0x770b,0x76d3
+	.short 0x769c,0x7665,0x762f,0x75f8,0x75c2,0x758c,0x7556,0x7520
+	.short 0x74ea,0x74b5,0x7480,0x744b,0x7416,0x73e2,0x73ad,0x7379
+	.short 0x7345,0x7311,0x72dd,0x72aa,0x7277,0x7243,0x7210,0x71de
+	.short 0x71ab,0x7179,0x7146,0x7114,0x70e2,0x70b1,0x707f,0x704e
+	.short 0x701c,0x6feb,0x6fba,0x6f8a,0x6f59,0x6f29,0x6ef9,0x6ec8
+	.short 0x6e99,0x6e69,0x6e39,0x6e0a,0x6ddb,0x6dab,0x6d7d,0x6d4e
+	.short 0x6d1f,0x6cf1,0x6cc2,0x6c94,0x6c66,0x6c38,0x6c0a,0x6bdd
+	.short 0x6bb0,0x6b82,0x6b55,0x6b28,0x6afb,0x6acf,0x6aa2,0x6a76
+	.short 0x6a49,0x6a1d,0x69f1,0x69c6,0x699a,0x696e,0x6943,0x6918
+	.short 0x68ed,0x68c2,0x6897,0x686c,0x6842,0x6817,0x67ed,0x67c3
+	.short 0x6799,0x676f,0x6745,0x671b,0x66f2,0x66c8,0x669f,0x6676
+	.short 0x664d,0x6624,0x65fc,0x65d3,0x65aa,0x6582,0x655a,0x6532
+	.short 0x650a,0x64e2,0x64ba,0x6493,0x646b,0x6444,0x641c,0x63f5
+	.short 0x63ce,0x63a7,0x6381,0x635a,0x6333,0x630d,0x62e7,0x62c1
+	.short 0x629a,0x6275,0x624f,0x6229,0x6203,0x61de,0x61b8,0x6193
+	.short 0x616e,0x6149,0x6124,0x60ff,0x60da,0x60b6,0x6091,0x606d
+	.short 0x6049,0x6024,0x6000,0x5fdc,0x5fb8,0x5f95,0x5f71,0x5f4d
+	.short 0x5f2a,0x5f07,0x5ee3,0x5ec0,0x5e9d,0x5e7a,0x5e57,0x5e35
+	.short 0x5e12,0x5def,0x5dcd,0x5dab,0x5d88,0x5d66,0x5d44,0x5d22
+	.short 0x5d00,0x5cde,0x5cbd,0x5c9b,0x5c7a,0x5c58,0x5c37,0x5c16
+	.short 0x5bf5,0x5bd4,0x5bb3,0x5b92,0x5b71,0x5b51,0x5b30,0x5b10
+	.short 0x5aef,0x5acf,0x5aaf,0x5a8f,0x5a6f,0x5a4f,0x5a2f,0x5a0f
+	.short 0x59ef,0x59d0,0x59b0,0x5991,0x5972,0x5952,0x5933,0x5914
+	.short 0x58f5,0x58d6,0x58b7,0x5899,0x587a,0x585b,0x583d,0x581f
+	.short 0x5800,0x57e2,0x57c4,0x57a6,0x5788,0x576a,0x574c,0x572e
+	.short 0x5711,0x56f3,0x56d5,0x56b8,0x569b,0x567d,0x5660,0x5643
+	.short 0x5626,0x5609,0x55ec,0x55cf,0x55b2,0x5596,0x5579,0x555d
+	.short 0x5540,0x5524,0x5507,0x54eb,0x54cf,0x54b3,0x5497,0x547b
+	.short 0x545f,0x5443,0x5428,0x540c,0x53f0,0x53d5,0x53b9,0x539e
+	.short 0x5383,0x5368,0x534c,0x5331,0x5316,0x52fb,0x52e0,0x52c6
+	.short 0x52ab,0x5290,0x5276,0x525b,0x5240,0x5226,0x520c,0x51f1
+	.short 0x51d7,0x51bd,0x51a3,0x5189,0x516f,0x5155,0x513b,0x5121
+	.short 0x5108,0x50ee,0x50d5,0x50bb,0x50a2,0x5088,0x506f,0x5056
+	.short 0x503c,0x5023,0x500a,0x4ff1,0x4fd8,0x4fbf,0x4fa6,0x4f8e
+	.short 0x4f75,0x4f5c,0x4f44,0x4f2b,0x4f13,0x4efa,0x4ee2,0x4eca
+	.short 0x4eb1,0x4e99,0x4e81,0x4e69,0x4e51,0x4e39,0x4e21,0x4e09
+	.short 0x4df1,0x4dda,0x4dc2,0x4daa,0x4d93,0x4d7b,0x4d64,0x4d4d
+	.short 0x4d35,0x4d1e,0x4d07,0x4cf0,0x4cd8,0x4cc1,0x4caa,0x4c93
+	.short 0x4c7d,0x4c66,0x4c4f,0x4c38,0x4c21,0x4c0b,0x4bf4,0x4bde
+	.short 0x4bc7,0x4bb1,0x4b9a,0x4b84,0x4b6e,0x4b58,0x4b41,0x4b2b
+	.short 0x4b15,0x4aff,0x4ae9,0x4ad3,0x4abd,0x4aa8,0x4a92,0x4a7c
+	.short 0x4a66,0x4a51,0x4a3b,0x4a26,0x4a10,0x49fb,0x49e5,0x49d0
+	.short 0x49bb,0x49a6,0x4990,0x497b,0x4966,0x4951,0x493c,0x4927
+	.short 0x4912,0x48fe,0x48e9,0x48d4,0x48bf,0x48ab,0x4896,0x4881
+	.short 0x486d,0x4858,0x4844,0x482f,0x481b,0x4807,0x47f3,0x47de
+	.short 0x47ca,0x47b6,0x47a2,0x478e,0x477a,0x4766,0x4752,0x473e
+	.short 0x472a,0x4717,0x4703,0x46ef,0x46db,0x46c8,0x46b4,0x46a1
+	.short 0x468d,0x467a,0x4666,0x4653,0x4640,0x462c,0x4619,0x4606
+	.short 0x45f3,0x45e0,0x45cd,0x45ba,0x45a7,0x4594,0x4581,0x456e
+	.short 0x455b,0x4548,0x4536,0x4523,0x4510,0x44fe,0x44eb,0x44d8
+	.short 0x44c6,0x44b3,0x44a1,0x448f,0x447c,0x446a,0x4458,0x4445
+	.short 0x4433,0x4421,0x440f,0x43fd,0x43eb,0x43d9,0x43c7,0x43b5
+	.short 0x43a3,0x4391,0x437f,0x436d,0x435c,0x434a,0x4338,0x4327
+	.short 0x4315,0x4303,0x42f2,0x42e0,0x42cf,0x42bd,0x42ac,0x429b
+	.short 0x4289,0x4278,0x4267,0x4256,0x4244,0x4233,0x4222,0x4211
+	.short 0x4200,0x41ef,0x41de,0x41cd,0x41bc,0x41ab,0x419a,0x418a
+	.short 0x4179,0x4168,0x4157,0x4147,0x4136,0x4125,0x4115,0x4104
+	.short 0x40f4,0x40e3,0x40d3,0x40c2,0x40b2,0x40a2,0x4091,0x4081
+	.short 0x4071,0x4061,0x4050,0x4040,0x4030,0x4020,0x4010,0x4000
+END_OBJECT(approx_tab)
+ASM_END()
diff --git a/third_party/gmp/mpn/powerpc32/lshift.asm b/third_party/gmp/mpn/powerpc32/lshift.asm
new file mode 100644
index 0000000..ce85d4d
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc32/lshift.asm
@@ -0,0 +1,168 @@
+dnl  PowerPC-32 mpn_lshift -- Shift a number left.
+
+dnl  Copyright 1995, 1998, 2000, 2002-2005 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                cycles/limb
+C 603e:            ?
+C 604e:            3.0
+C 75x (G3):        3.0
+C 7400,7410 (G4):  3.0
+C 7445,7455 (G4+): 2.5
+C 7447,7457 (G4+): 2.25
+C power4/ppc970:   2.5
+C power5:          2.5
+
+C INPUT PARAMETERS
+C rp	r3
+C up	r4
+C n	r5
+C cnt	r6
+
+ASM_START()
+PROLOGUE(mpn_lshift)
+	cmpwi	cr0, r5, 30	C more than 30 limbs?
+	slwi	r0, r5, 2
+	add	r4, r4, r0	C make r4 point at end of s1
+	add	r7, r3, r0	C make r7 point at end of res
+	bgt	L(BIG)		C branch if more than 12 limbs
+
+	mtctr	r5		C copy size into CTR
+	subfic	r8, r6, 32
+	lwzu	r11, -4(r4)	C load first s1 limb
+	srw	r3, r11, r8	C compute function return value
+	bdz	L(end1)
+
+L(oop):	lwzu	r10, -4(r4)
+	slw	r9, r11, r6
+	srw	r12, r10, r8
+	or	r9, r9, r12
+	stwu	r9, -4(r7)
+	bdz	L(end2)
+	lwzu	r11, -4(r4)
+	slw	r9, r10, r6
+	srw	r12, r11, r8
+	or	r9, r9, r12
+	stwu	r9, -4(r7)
+	bdnz	L(oop)
+
+L(end1):
+	slw	r0, r11, r6
+	stw	r0, -4(r7)
+	blr
+L(end2):
+	slw	r0, r10, r6
+	stw	r0, -4(r7)
+	blr
+
+L(BIG):
+	stwu	r1, -48(r1)
+	stmw	r24, 8(r1)	C save registers we are supposed to preserve
+	lwzu	r9, -4(r4)
+	subfic	r8, r6, 32
+	srw	r3, r9, r8	C compute function return value
+	slw	r0, r9, r6
+	addi	r5, r5, -1
+
+	andi.	r10, r5, 3	C count for spill loop
+	beq	L(e)
+	mtctr	r10
+	lwzu	r28, -4(r4)
+	bdz	L(xe0)
+
+L(loop0):
+	slw	r12, r28, r6
+	srw	r24, r28, r8
+	lwzu	r28, -4(r4)
+	or	r24, r0, r24
+	stwu	r24, -4(r7)
+	mr	r0, r12
+	bdnz	L(loop0)	C taken at most once!
+
+L(xe0):	slw	r12, r28, r6
+	srw	r24, r28, r8
+	or	r24, r0, r24
+	stwu	r24, -4(r7)
+	mr	r0, r12
+
+L(e):	srwi	r5, r5, 2	C count for unrolled loop
+	addi	r5, r5, -1
+	mtctr	r5
+	lwz	r28, -4(r4)
+	lwz	r29, -8(r4)
+	lwz	r30, -12(r4)
+	lwzu	r31, -16(r4)
+
+L(loopU):
+	slw	r9, r28, r6
+	srw	r24, r28, r8
+	lwz	r28, -4(r4)
+	slw	r10, r29, r6
+	srw	r25, r29, r8
+	lwz	r29, -8(r4)
+	slw	r11, r30, r6
+	srw	r26, r30, r8
+	lwz	r30, -12(r4)
+	slw	r12, r31, r6
+	srw	r27, r31, r8
+	lwzu	r31, -16(r4)
+	or	r24, r0, r24
+	stw	r24, -4(r7)
+	or	r25, r9, r25
+	stw	r25, -8(r7)
+	or	r26, r10, r26
+	stw	r26, -12(r7)
+	or	r27, r11, r27
+	stwu	r27, -16(r7)
+	mr	r0, r12
+	bdnz	L(loopU)
+
+	slw	r9, r28, r6
+	srw	r24, r28, r8
+	slw	r10, r29, r6
+	srw	r25, r29, r8
+	slw	r11, r30, r6
+	srw	r26, r30, r8
+	slw	r12, r31, r6
+	srw	r27, r31, r8
+	or	r24, r0, r24
+	stw	r24, -4(r7)
+	or	r25, r9, r25
+	stw	r25, -8(r7)
+	or	r26, r10, r26
+	stw	r26, -12(r7)
+	or	r27, r11, r27
+	stw	r27, -16(r7)
+
+	stw	r12, -20(r7)
+	lmw	r24, 8(r1)	C restore registers
+	addi	r1, r1, 48
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc32/lshiftc.asm b/third_party/gmp/mpn/powerpc32/lshiftc.asm
new file mode 100644
index 0000000..b683def
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc32/lshiftc.asm
@@ -0,0 +1,170 @@
+dnl  PowerPC-32 mpn_lshiftc.
+
+dnl  Copyright 1995, 1998, 2000, 2002-2005, 2010 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                cycles/limb
+C 603e:            ?
+C 604e:            3.0
+C 75x (G3):        3.0
+C 7400,7410 (G4):  3.0
+C 7445,7455 (G4+): 2.5
+C 7447,7457 (G4+): 2.25
+C power4/ppc970:   2.5
+C power5:          2.5
+
+C INPUT PARAMETERS
+C rp	r3
+C up	r4
+C n	r5
+C cnt	r6
+
+ASM_START()
+PROLOGUE(mpn_lshiftc)
+	cmpwi	cr0, r5, 30	C more than 30 limbs?
+	slwi	r0, r5, 2
+	add	r4, r4, r0	C make r4 point at end of s1
+	add	r7, r3, r0	C make r7 point at end of res
+	bgt	L(BIG)		C branch if more than 12 limbs
+
+	mtctr	r5		C copy size into CTR
+	subfic	r8, r6, 32
+	lwzu	r11, -4(r4)	C load first s1 limb
+	srw	r3, r11, r8	C compute function return value
+	bdz	L(end1)
+
+L(oop):	lwzu	r10, -4(r4)
+	slw	r9, r11, r6
+	srw	r12, r10, r8
+	nor	r9, r9, r12
+	stwu	r9, -4(r7)
+	bdz	L(end2)
+	lwzu	r11, -4(r4)
+	slw	r9, r10, r6
+	srw	r12, r11, r8
+	nor	r9, r9, r12
+	stwu	r9, -4(r7)
+	bdnz	L(oop)
+
+L(end1):
+	slw	r0, r11, r6
+	nor	r0, r0, r0
+	stw	r0, -4(r7)
+	blr
+L(end2):
+	slw	r0, r10, r6
+	nor	r0, r0, r0
+	stw	r0, -4(r7)
+	blr
+
+L(BIG):
+	stwu	r1, -48(r1)
+	stmw	r24, 8(r1)	C save registers we are supposed to preserve
+	lwzu	r9, -4(r4)
+	subfic	r8, r6, 32
+	srw	r3, r9, r8	C compute function return value
+	slw	r0, r9, r6
+	addi	r5, r5, -1
+
+	andi.	r10, r5, 3	C count for spill loop
+	beq	L(e)
+	mtctr	r10
+	lwzu	r28, -4(r4)
+	bdz	L(xe0)
+
+L(loop0):
+	slw	r12, r28, r6
+	srw	r24, r28, r8
+	lwzu	r28, -4(r4)
+	nor	r24, r0, r24
+	stwu	r24, -4(r7)
+	mr	r0, r12
+	bdnz	L(loop0)	C taken at most once!
+
+L(xe0):	slw	r12, r28, r6
+	srw	r24, r28, r8
+	nor	r24, r0, r24
+	stwu	r24, -4(r7)
+	mr	r0, r12
+
+L(e):	srwi	r5, r5, 2	C count for unrolled loop
+	addi	r5, r5, -1
+	mtctr	r5
+	lwz	r28, -4(r4)
+	lwz	r29, -8(r4)
+	lwz	r30, -12(r4)
+	lwzu	r31, -16(r4)
+
+L(loopU):
+	slw	r9, r28, r6
+	srw	r24, r28, r8
+	lwz	r28, -4(r4)
+	slw	r10, r29, r6
+	srw	r25, r29, r8
+	lwz	r29, -8(r4)
+	slw	r11, r30, r6
+	srw	r26, r30, r8
+	lwz	r30, -12(r4)
+	slw	r12, r31, r6
+	srw	r27, r31, r8
+	lwzu	r31, -16(r4)
+	nor	r24, r0, r24
+	stw	r24, -4(r7)
+	nor	r25, r9, r25
+	stw	r25, -8(r7)
+	nor	r26, r10, r26
+	stw	r26, -12(r7)
+	nor	r27, r11, r27
+	stwu	r27, -16(r7)
+	mr	r0, r12
+	bdnz	L(loopU)
+
+	slw	r9, r28, r6
+	srw	r24, r28, r8
+	slw	r10, r29, r6
+	srw	r25, r29, r8
+	slw	r11, r30, r6
+	srw	r26, r30, r8
+	slw	r12, r31, r6
+	srw	r27, r31, r8
+	nor	r24, r0, r24
+	stw	r24, -4(r7)
+	nor	r25, r9, r25
+	stw	r25, -8(r7)
+	nor	r26, r10, r26
+	stw	r26, -12(r7)
+	nor	r27, r11, r27
+	stw	r27, -16(r7)
+	nor	r12, r12, r12
+	stw	r12, -20(r7)
+	lmw	r24, 8(r1)	C restore registers
+	addi	r1, r1, 48
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc32/mod_34lsub1.asm b/third_party/gmp/mpn/powerpc32/mod_34lsub1.asm
new file mode 100644
index 0000000..6d7fe4d
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc32/mod_34lsub1.asm
@@ -0,0 +1,145 @@
+dnl  PowerPC-32 mpn_mod_34lsub1 -- mpn remainder mod 2^24-1.
+
+dnl  Copyright 2002, 2003, 2005 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C                cycles/limb
+C 603e:            ?
+C 604e:            3
+C 75x (G3):        3
+C 7400,7410 (G4):  3
+C 744x,745x (G4+): 3
+C power4/ppc970:   2.5
+C power5:          2.5
+
+C mp_limb_t mpn_mod_34lsub1 (mp_srcptr src, mp_size_t size)
+C
+C There seems no need to schedule the loads back, the code is still 3.0 c/l
+C on 750/7400 no matter where they're placed.
+C
+C Alternatives:
+C
+C Fetching half words would allow add instead for accumulating, instead of
+C adde and its serialization.  An outer loop would be required though, since
+C 2^16 halfwords can overflow.  lhz+add would be 2.0 c/l, but if there's
+C also a bdz or bdnz for each and a pointer update say every three limbs
+C then the total would be 2.67 c/l which isn't much faster than the current
+C simpler code.
+
+ASM_START()
+PROLOGUE(mpn_mod_34lsub1)
+
+	C r3	src
+	C r4	size
+
+	mtctr	r4
+	addic	r6, r3, 8		C &src[2], and clear CA
+
+	lwz	r3, 0(r3)		C acc0 = src[0]
+	bdz	L(done)
+
+	lwz	r4, -4(r6)		C acc1 = src[1]
+	bdz	L(two)
+
+	lwz	r5, 0(r6)		C acc2 = src[2]
+	lis	r7, 0			C no carry if just three limbs
+
+	bdz	L(three)
+	lis	r7, 1			C 0x10000 carry pos
+
+L(top):
+	C r3	acc0
+	C r4	acc1
+	C r5	acc2
+	C r6	src, incrementing
+	C r7	carry pos
+
+	lwz	r0, 4(r6)
+	adde	r3, r3, r0
+	bdz	L(end0)
+
+	lwz	r0, 8(r6)
+	adde	r4, r4, r0
+	bdz	L(end1)
+
+	lwzu	r0, 12(r6)
+	adde	r5, r5, r0
+	bdnz	L(top)
+
+
+	srwi	r7, r7, 8
+L(end0):
+	srwi	r7, r7, 8
+L(end1):
+	subfe	r0, r0, r0		C -1 if not CA
+
+	andc	r7, r7, r0		C final carry, 0x10000, 0x100, 1 or 0
+L(three):
+	rlwinm	r6, r3, 0,8,31		C acc0 low
+
+	add	r7, r7, r6
+	rlwinm	r6, r3, 8,24,31		C acc0 high
+
+	add	r7, r7, r6
+	rlwinm	r6, r4, 8,8,23		C acc1 low
+
+	add	r7, r7, r6
+	rlwinm	r6, r4, 16,16,31	C acc1 high
+
+	add	r7, r7, r6
+	rlwinm	r6, r5, 16,8,15		C acc2 low
+
+	add	r7, r7, r6
+	rlwinm	r6, r5, 24,8,31		C acc2 high
+
+	add	r3, r7, r6
+
+L(done):
+	blr
+
+L(two):
+	C r3	acc0
+	C r4	acc1
+
+	rlwinm	r5, r3, 8,24,31		C acc0 high
+	rlwinm	r3, r3, 0,8,31		C acc0 low
+
+	add	r3, r3, r5		C acc0 high + low
+	rlwinm	r5, r4, 16,16,31	C acc1 high
+
+	add	r3, r3, r5		C add acc1 high
+	rlwinm	r5, r4, 8,8,23		C acc1 low
+
+	add	r3, r3, r5		C add acc1 low
+
+	blr
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc32/mode1o.asm b/third_party/gmp/mpn/powerpc32/mode1o.asm
new file mode 100644
index 0000000..e8a6b5e
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc32/mode1o.asm
@@ -0,0 +1,127 @@
+dnl  PowerPC-32 mpn_modexact_1_odd -- mpn by limb exact remainder.
+
+dnl  Copyright 2002, 2003, 2005, 2006 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C                cycles/limb
+C 603e:             ?
+C 604e:             6.0
+C 75x (G3):         6.0-13.0, depending on divisor
+C 7400,7410 (G4):   6.0-13.0, depending on divisor
+C 744x,745x (G4+):  8.0-10.0, depending on divisor
+C power4/ppc970:   12.0
+C power5:          12.0
+
+
+C mp_limb_t mpn_modexact_1_odd (mp_srcptr src, mp_size_t size,
+C                               mp_limb_t divisor);
+C mp_limb_t mpn_modexact_1c_odd (mp_srcptr src, mp_size_t size,
+C                                mp_limb_t divisor, mp_limb_t carry);
+C
+C For PIC, the inverse is established arithmetically since it measures about
+C 5 cycles faster than the nonsense needed to access binvert_limb_table in
+C SVR4 or Darwin style PIC.  AIX might be better, since it avoids bl/mflr to
+C get at the GOT/TOC/whatever.
+C
+C Using divwu for size==1 measured about 10 cycles slower on 604e, or about
+C 3-5 cycles faster on 750.  For now it doesn't seem worth bothering with.
+C
+C The loop allows an early-out on mullw for the inverse, and on mulhwu for
+C the divisor.  So the fastest is for instance divisor==1 (inverse==-1), and
+C the slowest is anything giving a full 32-bits in both, such as
+C divisor==0xDEADBEEF (inverse==0x904B300F).  These establish the stated
+C range above for 750 and 7400.
+
+
+ASM_START()
+
+EXTERN(binvert_limb_table)
+
+PROLOGUE(mpn_modexact_1_odd)
+	li	r6, 0
+
+PROLOGUE(mpn_modexact_1c_odd)
+
+	mtctr	r4			C size
+
+ifdef(`PIC_SLOW',`
+C Load from our table with PIC is so slow on Linux and Darwin that we avoid it
+	rlwinm	r7, r5, 1,28,28		C (divisor << 1) & 8
+	rlwinm	r8, r5, 2,28,28		C (divisor << 2) & 8
+	xor	r7, r7, r8		C ((divisor << 1) ^ (divisor << 2)) & 8
+	rlwinm	r4, r5, 0,28,31		C divisor low 4 bits, speedup mullw
+	xor	r4, r4, r7		C inverse, 4 bits
+	mullw	r7, r4, r4		C i*i
+	slwi	r4, r4, 1		C 2*i
+	rlwinm	r8, r5, 0,24,31		C divisor low 8 bits, speedup mullw
+	mullw	r7, r7, r8		C i*i*d
+	sub	r4, r4, r7		C inverse, 8 bits
+',`
+	LEA(	r7, binvert_limb_table)
+	rlwinm	r4, r5, 31,25,31	C (divisor/2) & 0x7F
+	lbzx	r4, r4,r7		C inverse, 8 bits
+')
+
+	mullw	r7, r4, r4		C i*i
+	slwi	r4, r4, 1		C 2*i
+	mullw	r7, r5, r7		C i*i*d   [i*i is 16 bits, so second operand]
+	sub	r4, r4, r7		C inverse, 16 bits
+	mullw	r7, r4, r4		C i*i
+	slwi	r4, r4, 1		C 2*i
+	mullw	r7, r7, r5		C i*i*d
+	lwz	r0, 0(r3)		C src[0]
+	sub	r4, r4, r7		C inverse, 32 bits
+	subfc	r7, r6, r0		C l = src[0] - carry
+
+	mullw	r7, r7, r4		C q = l * inverse
+	bdz	L(one)
+
+	lwzu	r0, 4(r3)		C src[1]
+	mulhwu	r6, r7, r5		C carry = high(q*divisor)
+	subfe	r7, r6, r0		C l = src[1] - carry
+	bdz	L(two)
+
+L(top):
+	mullw	r7, r7, r4		C q = l * inverse
+	lwzu	r0, 4(r3)		C src[i]
+	mulhwu	r6, r7, r5		C carry = high(q*divisor)
+	subfe	r7, r6, r0		C l = src[i] - carry
+	bdnz	L(top)
+
+L(two):	mullw	r7, r7, r4		C q = l * inverse
+L(one):	subfe	r3, r3, r3		C ca 0 or -1
+	mulhwu	r6, r7, r5		C carry = high(q*divisor)
+	subf	r3, r3, r6		C carry + ca
+	blr
+
+EPILOGUE(mpn_modexact_1c_odd)
+EPILOGUE(mpn_modexact_1_odd)
+ASM_END()
diff --git a/third_party/gmp/mpn/powerpc32/mul_1.asm b/third_party/gmp/mpn/powerpc32/mul_1.asm
new file mode 100644
index 0000000..e42087c
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc32/mul_1.asm
@@ -0,0 +1,101 @@
+dnl  PowerPC-32 mpn_mul_1 -- Multiply a limb vector with a limb and store the
+dnl  result in a second limb vector.
+
+dnl  Copyright 1995, 1997, 2000, 2002, 2003, 2005 Free Software Foundation,
+dnl  Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                cycles/limb
+C 603e:            ?
+C 604e:            4.0
+C 75x (G3):        4.5-11
+C 7400,7410 (G4):  4.5-11
+C 744x,745x (G4+): 6.0
+C power4/ppc970:   6.0
+C power5:          5.63
+
+C INPUT PARAMETERS
+C rp	r3
+C up	r4
+C n	r5
+C vl	r6
+
+ASM_START()
+PROLOGUE(mpn_mul_1)
+	mtctr	r5
+	addi	r3,r3,-4	C adjust res_ptr, it's offset before it's used
+	li	r12,0		C clear upper product reg
+	addic	r0,r0,0		C clear cy
+C Start software pipeline
+	lwz	r8,0(r4)
+	bdz	L(end3)
+	lwzu	r9,4(r4)
+	mullw	r11,r8,r6
+	mulhwu	r0,r8,r6
+	bdz	L(end1)
+C Software pipelined main loop
+L(loop):
+	lwz	r8,4(r4)
+	mullw	r10,r9,r6
+	adde	r5,r11,r12
+	mulhwu	r12,r9,r6
+	stw	r5,4(r3)
+	bdz	L(end2)
+	lwzu	r9,8(r4)
+	mullw	r11,r8,r6
+	adde	r7,r10,r0
+	mulhwu	r0,r8,r6
+	stwu	r7,8(r3)
+	bdnz	L(loop)
+C Finish software pipeline
+L(end1):
+	mullw	r10,r9,r6
+	adde	r5,r11,r12
+	mulhwu	r12,r9,r6
+	stw	r5,4(r3)
+	adde	r7,r10,r0
+	stwu	r7,8(r3)
+	addze	r3,r12
+	blr
+L(end2):
+	mullw	r11,r8,r6
+	adde	r7,r10,r0
+	mulhwu	r0,r8,r6
+	stwu	r7,8(r3)
+	adde	r5,r11,r12
+	stw	r5,4(r3)
+	addze	r3,r0
+	blr
+L(end3):
+	mullw	r11,r8,r6
+	stw	r11,4(r3)
+	mulhwu	r3,r8,r6
+	blr
+EPILOGUE(mpn_mul_1)
diff --git a/third_party/gmp/mpn/powerpc32/p3-p7/aors_n.asm b/third_party/gmp/mpn/powerpc32/p3-p7/aors_n.asm
new file mode 100644
index 0000000..3b6685e
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc32/p3-p7/aors_n.asm
@@ -0,0 +1,187 @@
+dnl  PowerPC-32 mpn_add_n/mpn_sub_n -- mpn addition and subtraction.
+
+dnl  Copyright 1999-2001, 2003-2005, 2007, 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                   cycles/limb
+C POWER3/PPC630          1.5
+C POWER4/PPC970          2
+C POWER5                 2
+C POWER6                 2.78
+C POWER7               2.15-2.87
+
+C This code is based on powerpc64/aors_n.asm.
+
+C INPUT PARAMETERS
+C rp	r3
+C up	r4
+C vp	r5
+C n	r6
+
+ifdef(`OPERATION_add_n',`
+  define(ADDSUBC,	adde)
+  define(ADDSUB,	addc)
+  define(func,		mpn_add_n)
+  define(func_nc,	mpn_add_nc)
+  define(GENRVAL,	`addi	r3, r3, 1')
+  define(SETCBR,	`addic	r0, $1, -1')
+  define(CLRCB,		`addic	r0, r0, 0')
+')
+ifdef(`OPERATION_sub_n',`
+  define(ADDSUBC,	subfe)
+  define(ADDSUB,	subfc)
+  define(func,		mpn_sub_n)
+  define(func_nc,	mpn_sub_nc)
+  define(GENRVAL,	`neg	r3, r3')
+  define(SETCBR,	`subfic	r0, $1, 0')
+  define(CLRCB,		`addic	r0, r1, -1')
+')
+
+MULFUNC_PROLOGUE(mpn_add_n mpn_add_nc mpn_sub_n mpn_sub_nc)
+
+ASM_START()
+PROLOGUE(func_nc)
+	SETCBR(r7)
+	b	L(ent)
+EPILOGUE()
+
+PROLOGUE(func)
+	CLRCB
+L(ent):	stwu	r1, -32(r1)
+	rlwinm.	r0, r6, 0,30,31	C r0 = n & 3, set cr0
+	cmpwi	cr6, r0, 2
+	stw	r28, 8(r1)
+	addi	r6, r6, 3	C compute count...
+	stw	r29, 12(r1)
+	srwi	r6, r6, 2	C ...for ctr
+	stw	r30, 16(r1)
+	mtctr	r6		C copy count into ctr
+	stw	r31, 20(r1)
+	beq	cr0, L(b00)
+	blt	cr6, L(b01)
+	beq	cr6, L(b10)
+
+L(b11):	lwz	r8, 0(r4)	C load s1 limb
+	lwz	r9, 0(r5)	C load s2 limb
+	lwz	r10, 4(r4)	C load s1 limb
+	lwz	r11, 4(r5)	C load s2 limb
+	lwz	r12, 8(r4)	C load s1 limb
+	addi	r4, r4, 12
+	lwz	r0, 8(r5)	C load s2 limb
+	addi	r5, r5, 12
+	ADDSUBC	r29, r9, r8
+	ADDSUBC	r30, r11, r10
+	ADDSUBC	r31, r0, r12
+	stw	r29, 0(r3)
+	stw	r30, 4(r3)
+	stw	r31, 8(r3)
+	addi	r3, r3, 12
+	bdnz	L(go)
+	b	L(ret)
+
+L(b01):	lwz	r12, 0(r4)	C load s1 limb
+	addi	r4, r4, 4
+	lwz	r0, 0(r5)	C load s2 limb
+	addi	r5, r5, 4
+	ADDSUBC	r31, r0, r12	C add
+	stw	r31, 0(r3)
+	addi	r3, r3, 4
+	bdnz	L(go)
+	b	L(ret)
+
+L(b10):	lwz	r10, 0(r4)	C load s1 limb
+	lwz	r11, 0(r5)	C load s2 limb
+	lwz	r12, 4(r4)	C load s1 limb
+	addi	r4, r4, 8
+	lwz	r0, 4(r5)	C load s2 limb
+	addi	r5, r5, 8
+	ADDSUBC	r30, r11, r10	C add
+	ADDSUBC	r31, r0, r12	C add
+	stw	r30, 0(r3)
+	stw	r31, 4(r3)
+	addi	r3, r3, 8
+	bdnz	L(go)
+	b	L(ret)
+
+L(b00):	C INITCY		C clear/set cy
+L(go):	lwz	r6, 0(r4)	C load s1 limb
+	lwz	r7, 0(r5)	C load s2 limb
+	lwz	r8, 4(r4)	C load s1 limb
+	lwz	r9, 4(r5)	C load s2 limb
+	lwz	r10, 8(r4)	C load s1 limb
+	lwz	r11, 8(r5)	C load s2 limb
+	lwz	r12, 12(r4)	C load s1 limb
+	lwz	r0, 12(r5)	C load s2 limb
+	bdz	L(end)
+
+	addi	r4, r4, 16
+	addi	r5, r5, 16
+
+	ALIGN(16)
+L(top):	ADDSUBC	r28, r7, r6
+	lwz	r6, 0(r4)	C load s1 limb
+	lwz	r7, 0(r5)	C load s2 limb
+	ADDSUBC	r29, r9, r8
+	lwz	r8, 4(r4)	C load s1 limb
+	lwz	r9, 4(r5)	C load s2 limb
+	ADDSUBC	r30, r11, r10
+	lwz	r10, 8(r4)	C load s1 limb
+	lwz	r11, 8(r5)	C load s2 limb
+	ADDSUBC	r31, r0, r12
+	lwz	r12, 12(r4)	C load s1 limb
+	lwz	r0, 12(r5)	C load s2 limb
+	stw	r28, 0(r3)
+	addi	r4, r4, 16
+	stw	r29, 4(r3)
+	addi	r5, r5, 16
+	stw	r30, 8(r3)
+	stw	r31, 12(r3)
+	addi	r3, r3, 16
+	bdnz	L(top)		C decrement ctr and loop back
+
+L(end):	ADDSUBC	r28, r7, r6
+	ADDSUBC	r29, r9, r8
+	ADDSUBC	r30, r11, r10
+	ADDSUBC	r31, r0, r12
+	stw	r28, 0(r3)
+	stw	r29, 4(r3)
+	stw	r30, 8(r3)
+	stw	r31, 12(r3)
+
+L(ret):
+	lwz	r28, 8(r1)
+	lwz	r29, 12(r1)
+	subfe	r3, r0, r0	C -cy
+	lwz	r30, 16(r1)
+	GENRVAL
+	lwz	r31, 20(r1)
+	addi	r1, r1, 32
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc32/p3/gmp-mparam.h b/third_party/gmp/mpn/powerpc32/p3/gmp-mparam.h
new file mode 100644
index 0000000..3382695
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc32/p3/gmp-mparam.h
@@ -0,0 +1,155 @@
+/* PowerPC-32 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 1999-2004, 2008-2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+/* 450 MHz POWER3 */
+
+#define DIVREM_1_NORM_THRESHOLD              0  /* always */
+#define DIVREM_1_UNNORM_THRESHOLD            0  /* always */
+#define MOD_1_1P_METHOD                      2
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          3
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          2
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        12
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        18
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD      8
+#define USE_PREINV_DIVREM_1                  1
+#define DIVEXACT_1_THRESHOLD                 0  /* always */
+#define BMOD_1_TO_MOD_1_THRESHOLD        MP_SIZE_T_MAX  /* never */
+
+#define MUL_TOOM22_THRESHOLD                10
+#define MUL_TOOM33_THRESHOLD                38
+#define MUL_TOOM44_THRESHOLD                58
+#define MUL_TOOM6H_THRESHOLD               129
+#define MUL_TOOM8H_THRESHOLD               212
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      65
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD      63
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD      59
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD      64
+
+#define SQR_BASECASE_THRESHOLD               0  /* always */
+#define SQR_TOOM2_THRESHOLD                 14
+#define SQR_TOOM3_THRESHOLD                 53
+#define SQR_TOOM4_THRESHOLD                 76
+#define SQR_TOOM6_THRESHOLD                106
+#define SQR_TOOM8_THRESHOLD                284
+
+#define MULMOD_BNM1_THRESHOLD                9
+#define SQRMOD_BNM1_THRESHOLD                9
+
+#define MUL_FFT_MODF_THRESHOLD             220  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    220, 5}, {     13, 6}, {      7, 5}, {     15, 6}, \
+    {      9, 5}, {     19, 6}, {     13, 7}, {      7, 6}, \
+    {     16, 7}, {     13, 8}, {      7, 7}, {     19, 8}, \
+    {     11, 7}, {     23, 9}, {      7, 8}, {     15, 7}, \
+    {     33, 8}, {     23, 9}, {     15, 8}, {     35, 9}, \
+    {     23,10}, {     15, 9}, {     31, 8}, {     67, 9}, \
+    {     39, 8}, {     79, 9}, {     47,10}, {     31, 9}, \
+    {     63, 8}, {    127, 9}, {     71, 8}, {    143, 9}, \
+    {     79,10}, {     47,11}, {     31,10}, {     63, 9}, \
+    {    127, 8}, {    255, 9}, {    143,10}, {     79, 9}, \
+    {    159, 8}, {    319, 9}, {    175, 8}, {    351,10}, \
+    {     95, 9}, {    191, 8}, {    383,10}, {    111,11}, \
+    {     63,10}, {    127, 9}, {    255,10}, {    143, 9}, \
+    {    287, 8}, {    575,10}, {    159, 9}, {    319,10}, \
+    {    175, 9}, {    351,11}, {     95,10}, {    191, 9}, \
+    {    383,10}, {    207, 9}, {    415,12}, {     63,11}, \
+    {    127,10}, {    255, 9}, {    511,10}, {    287, 9}, \
+    {    575,11}, {    159,10}, {    351, 9}, {    703, 8}, \
+    {   1407,11}, {    191,10}, {    415,11}, {    223,10}, \
+    {    447, 9}, {    895,12}, {   4096,13}, {   8192,14}, \
+    {  16384,15}, {  32768,16} }
+#define MUL_FFT_TABLE3_SIZE 82
+#define MUL_FFT_THRESHOLD                 2688
+
+#define SQR_FFT_MODF_THRESHOLD             176  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    176, 5}, {     13, 6}, {      7, 5}, {     15, 6}, \
+    {     13, 7}, {      7, 6}, {     16, 7}, {      9, 6}, \
+    {     19, 7}, {     11, 6}, {     23, 7}, {     13, 8}, \
+    {      7, 7}, {     19, 8}, {     11, 7}, {     23, 9}, \
+    {      7, 8}, {     15, 7}, {     31, 8}, {     23, 9}, \
+    {     15, 8}, {     39, 9}, {     23,10}, {     15, 9}, \
+    {     31, 8}, {     63, 9}, {     39, 8}, {     79, 9}, \
+    {     47, 8}, {     95,10}, {     31, 9}, {     63, 8}, \
+    {    127, 9}, {     71, 8}, {    143, 7}, {    287, 6}, \
+    {    575, 9}, {     79, 8}, {    159,10}, {     47, 9}, \
+    {     95,11}, {     31,10}, {     63, 9}, {    127, 8}, \
+    {    255, 9}, {    143, 8}, {    287, 7}, {    575,10}, \
+    {     79, 9}, {    159, 8}, {    319, 9}, {    175,10}, \
+    {     95, 9}, {    191, 8}, {    383,10}, {    111, 9}, \
+    {    223,11}, {     63,10}, {    127, 9}, {    255,10}, \
+    {    143, 9}, {    287, 8}, {    575,10}, {    159, 9}, \
+    {    319,10}, {    175,11}, {     95,10}, {    191, 9}, \
+    {    383,10}, {    223,12}, {     63,11}, {    127,10}, \
+    {    287, 9}, {    575,11}, {    159,10}, {    351, 9}, \
+    {    703, 8}, {   1407,11}, {    191,10}, {    383,11}, \
+    {    223,10}, {    447, 9}, {    895,12}, {   4096,13}, \
+    {   8192,14}, {  16384,15}, {  32768,16} }
+#define SQR_FFT_TABLE3_SIZE 87
+#define SQR_FFT_THRESHOLD                 1728
+
+#define MULLO_BASECASE_THRESHOLD             2
+#define MULLO_DC_THRESHOLD                  33
+#define MULLO_MUL_N_THRESHOLD             5240
+
+#define DC_DIV_QR_THRESHOLD                 32
+#define DC_DIVAPPR_Q_THRESHOLD             123
+#define DC_BDIV_QR_THRESHOLD                34
+#define DC_BDIV_Q_THRESHOLD                 84
+
+#define INV_MULMOD_BNM1_THRESHOLD           42
+#define INV_NEWTON_THRESHOLD               129
+#define INV_APPR_THRESHOLD                 124
+
+#define BINV_NEWTON_THRESHOLD              148
+#define REDC_1_TO_REDC_N_THRESHOLD          38
+
+#define MU_DIV_QR_THRESHOLD                748
+#define MU_DIVAPPR_Q_THRESHOLD             748
+#define MUPI_DIV_QR_THRESHOLD               59
+#define MU_BDIV_QR_THRESHOLD               562
+#define MU_BDIV_Q_THRESHOLD                654
+
+#define MATRIX22_STRASSEN_THRESHOLD         11
+#define HGCD_THRESHOLD                      76
+#define GCD_DC_THRESHOLD                   205
+#define GCDEXT_DC_THRESHOLD                174
+#define JACOBI_BASE_METHOD                   1
+
+#define GET_STR_DC_THRESHOLD                14
+#define GET_STR_PRECOMPUTE_THRESHOLD        27
+#define SET_STR_DC_THRESHOLD               181
+#define SET_STR_PRECOMPUTE_THRESHOLD       525
diff --git a/third_party/gmp/mpn/powerpc32/p4/gmp-mparam.h b/third_party/gmp/mpn/powerpc32/p4/gmp-mparam.h
new file mode 100644
index 0000000..7ac59f5
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc32/p4/gmp-mparam.h
@@ -0,0 +1,209 @@
+/* PowerPC-32 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 1999-2004, 2008-2011, 2014 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+/* 1800 MHz PowerPC-970 */
+/* FFT tuning limit = 10000000 */
+/* Generated by tuneup.c, 2014-03-12, gcc 4.0 */
+
+#define DIVREM_1_NORM_THRESHOLD              0  /* always */
+#define DIVREM_1_UNNORM_THRESHOLD            0  /* always */
+#define MOD_1_1P_METHOD                      1
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          7
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          5
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD         9
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        42
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     14
+#define USE_PREINV_DIVREM_1                  1
+#define DIV_QR_1N_PI1_METHOD                 1
+#define DIV_QR_1_NORM_THRESHOLD              1
+#define DIV_QR_1_UNNORM_THRESHOLD            1
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always */
+#define BMOD_1_TO_MOD_1_THRESHOLD           45
+
+#define DIV_1_VS_MUL_1_PERCENT             225
+
+#define MUL_TOOM22_THRESHOLD                20
+#define MUL_TOOM33_THRESHOLD                73
+#define MUL_TOOM44_THRESHOLD               130
+#define MUL_TOOM6H_THRESHOLD               222
+#define MUL_TOOM8H_THRESHOLD               333
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD     107
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     108
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD      89
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD      92
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     100
+
+#define SQR_BASECASE_THRESHOLD               5
+#define SQR_TOOM2_THRESHOLD                 30
+#define SQR_TOOM3_THRESHOLD                 85
+#define SQR_TOOM4_THRESHOLD                160
+#define SQR_TOOM6_THRESHOLD                197
+#define SQR_TOOM8_THRESHOLD                357
+
+#define MULMID_TOOM42_THRESHOLD             32
+
+#define MULMOD_BNM1_THRESHOLD               15
+#define SQRMOD_BNM1_THRESHOLD               16
+
+#define MUL_FFT_MODF_THRESHOLD             444  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    444, 5}, {     17, 6}, {      9, 5}, {     21, 6}, \
+    {     11, 5}, {     23, 6}, {     21, 7}, {     11, 6}, \
+    {     24, 7}, {     13, 6}, {     28, 7}, {     15, 6}, \
+    {     31, 7}, {     21, 8}, {     11, 7}, {     27, 8}, \
+    {     15, 7}, {     33, 8}, {     19, 7}, {     41, 8}, \
+    {     23, 7}, {     47, 8}, {     27, 9}, {     15, 8}, \
+    {     39, 9}, {     23, 8}, {     51,10}, {     15, 9}, \
+    {     31, 8}, {     67, 9}, {     39, 8}, {     79, 9}, \
+    {     47, 8}, {     95,10}, {     31, 9}, {     63, 8}, \
+    {    127, 9}, {     79,10}, {     47, 9}, {     95,11}, \
+    {     31,10}, {     63, 9}, {    135,10}, {     79, 9}, \
+    {    167,10}, {     95, 9}, {    191, 8}, {    383,10}, \
+    {    111,11}, {     63,10}, {    127, 9}, {    255, 8}, \
+    {    511,10}, {    143, 9}, {    287, 8}, {    575, 9}, \
+    {    303,10}, {    159, 9}, {    319,11}, {     95,10}, \
+    {    191, 9}, {    383,12}, {     63,11}, {    127,10}, \
+    {    255, 9}, {    511,10}, {    271, 9}, {    543, 8}, \
+    {   1087,10}, {    287, 9}, {    575,10}, {    303,11}, \
+    {    159,10}, {    335, 9}, {    671, 8}, {   1343,10}, \
+    {    351, 9}, {    703,11}, {    191,10}, {    383, 9}, \
+    {    767,10}, {    415, 9}, {    831,11}, {    223,10}, \
+    {    447,12}, {    127,11}, {    255,10}, {    543, 9}, \
+    {   1087,11}, {    287,10}, {    607, 9}, {   1215,11}, \
+    {    319,10}, {    671, 9}, {   1343,11}, {    351,10}, \
+    {    703, 9}, {   1407,12}, {    191,11}, {    383,10}, \
+    {    767,11}, {    415,10}, {    831,11}, {    447,13}, \
+    {    127,12}, {    255,11}, {    543,10}, {   1087,11}, \
+    {    607,10}, {   1215,12}, {    319,11}, {    671,10}, \
+    {   1343,11}, {    703,10}, {   1407,11}, {    735,12}, \
+    {    383,11}, {    767,10}, {   1535,11}, {    831,12}, \
+    {    447,10}, {   1791,11}, {    959,13}, {    255,12}, \
+    {    511,11}, {   1087,12}, {    575,11}, {   1215,10}, \
+    {   2431,12}, {    639,11}, {   1343,12}, {    703,11}, \
+    {   1407,13}, {    383,12}, {    767,11}, {   1535,12}, \
+    {    831,11}, {   1727,10}, {   3455,11}, {   1791,12}, \
+    {    959,14}, {    255,13}, {    511,12}, {   1215,11}, \
+    {   2431,13}, {    639,12}, {   1471,13}, {    767,12}, \
+    {   1727,11}, {   3455,12}, {   1791,14}, {    511,13}, \
+    {   1151,12}, {   2431,13}, {   8192,14}, {  16384,15}, \
+    {  32768,16} }
+#define MUL_FFT_TABLE3_SIZE 157
+#define MUL_FFT_THRESHOLD                 6784
+
+#define SQR_FFT_MODF_THRESHOLD             340  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    340, 5}, {     21, 6}, {     11, 5}, {     23, 6}, \
+    {     21, 7}, {     11, 6}, {     24, 7}, {     13, 6}, \
+    {     28, 7}, {     21, 8}, {     11, 7}, {     27, 8}, \
+    {     15, 7}, {     33, 8}, {     19, 7}, {     39, 8}, \
+    {     23, 7}, {     47, 8}, {     27, 9}, {     15, 8}, \
+    {     39, 9}, {     23, 8}, {     47,10}, {     15, 9}, \
+    {     31, 8}, {     63, 9}, {     39, 8}, {     79, 9}, \
+    {     47,10}, {     31, 9}, {     79,10}, {     47, 9}, \
+    {     95,11}, {     31,10}, {     63, 9}, {    127, 8}, \
+    {    255, 9}, {    135,10}, {     79, 9}, {    159, 8}, \
+    {    319,10}, {     95, 9}, {    191, 8}, {    383, 9}, \
+    {    207,11}, {     63,10}, {    127, 9}, {    255, 8}, \
+    {    511, 9}, {    271,10}, {    143, 9}, {    287, 8}, \
+    {    575, 9}, {    303, 8}, {    607,10}, {    159, 9}, \
+    {    319,10}, {    175,11}, {     95,10}, {    191, 9}, \
+    {    383,10}, {    207,12}, {     63,11}, {    127,10}, \
+    {    255, 9}, {    511,10}, {    271, 9}, {    543, 8}, \
+    {   1087,10}, {    287, 9}, {    575,10}, {    303, 9}, \
+    {    607,11}, {    159,10}, {    319, 9}, {    639,10}, \
+    {    335, 9}, {    671,10}, {    351, 9}, {    703,11}, \
+    {    191,10}, {    383, 9}, {    767,10}, {    415, 9}, \
+    {    831,11}, {    223,10}, {    447,12}, {    127,11}, \
+    {    255,10}, {    543, 9}, {   1087,11}, {    287,10}, \
+    {    607, 9}, {   1215,11}, {    319,10}, {    671,11}, \
+    {    351,10}, {    703,12}, {    191,11}, {    383,10}, \
+    {    767,11}, {    415,10}, {    831,11}, {    479,13}, \
+    {    127,12}, {    255,11}, {    543,10}, {   1087,11}, \
+    {    607,10}, {   1215,12}, {    319,11}, {    671,10}, \
+    {   1343,11}, {    703,10}, {   1407,11}, {    735,12}, \
+    {    383,11}, {    831,12}, {    447,11}, {    959,13}, \
+    {    255,12}, {    511,11}, {   1087,12}, {    575,11}, \
+    {   1215,12}, {    639,11}, {   1343,12}, {    703,11}, \
+    {   1407,13}, {    383,12}, {    831,11}, {   1727,12}, \
+    {    959,14}, {    255,13}, {    511,12}, {   1215,13}, \
+    {    639,12}, {   1471,13}, {    767,12}, {   1727,13}, \
+    {    895,12}, {   1919,14}, {    511,13}, {   1023,12}, \
+    {   2111,13}, {   1151,12}, {   2431,13}, {   8192,14}, \
+    {  16384,15}, {  32768,16} }
+#define SQR_FFT_TABLE3_SIZE 150
+#define SQR_FFT_THRESHOLD                 4736
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  55
+#define MULLO_MUL_N_THRESHOLD            13463
+#define SQRLO_BASECASE_THRESHOLD             4
+#define SQRLO_DC_THRESHOLD                 169
+#define SQRLO_SQR_THRESHOLD               9335
+
+#define DC_DIV_QR_THRESHOLD                 50
+#define DC_DIVAPPR_Q_THRESHOLD             196
+#define DC_BDIV_QR_THRESHOLD                51
+#define DC_BDIV_Q_THRESHOLD                166
+
+#define INV_MULMOD_BNM1_THRESHOLD           50
+#define INV_NEWTON_THRESHOLD               226
+#define INV_APPR_THRESHOLD                 202
+
+#define BINV_NEWTON_THRESHOLD              228
+#define REDC_1_TO_REDC_N_THRESHOLD          67
+
+#define MU_DIV_QR_THRESHOLD               1187
+#define MU_DIVAPPR_Q_THRESHOLD            1308
+#define MUPI_DIV_QR_THRESHOLD              114
+#define MU_BDIV_QR_THRESHOLD               998
+#define MU_BDIV_Q_THRESHOLD               1142
+
+#define POWM_SEC_TABLE  3,28,78,480,1099
+
+#define GET_STR_DC_THRESHOLD                11
+#define GET_STR_PRECOMPUTE_THRESHOLD        24
+#define SET_STR_DC_THRESHOLD               381
+#define SET_STR_PRECOMPUTE_THRESHOLD      1002
+
+#define FAC_DSC_THRESHOLD                  179
+#define FAC_ODD_THRESHOLD                   28
+
+#define MATRIX22_STRASSEN_THRESHOLD          9
+#define HGCD_THRESHOLD                      93
+#define HGCD_APPR_THRESHOLD                109
+#define HGCD_REDUCE_THRESHOLD             2479
+#define GCD_DC_THRESHOLD                   379
+#define GCDEXT_DC_THRESHOLD                273
+#define JACOBI_BASE_METHOD                   4
diff --git a/third_party/gmp/mpn/powerpc32/p5/gmp-mparam.h b/third_party/gmp/mpn/powerpc32/p5/gmp-mparam.h
new file mode 100644
index 0000000..faa1e81
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc32/p5/gmp-mparam.h
@@ -0,0 +1,156 @@
+/* PowerPC-32 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 1999-2004, 2008-2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+/* 1650 MHz POWER5 */
+
+#define DIVREM_1_NORM_THRESHOLD              0  /* always */
+#define DIVREM_1_UNNORM_THRESHOLD            0  /* always */
+#define MOD_1_1P_METHOD                      1
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          8
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          6
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD         9
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        50
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     18
+#define USE_PREINV_DIVREM_1                  1
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always */
+#define BMOD_1_TO_MOD_1_THRESHOLD           61
+
+#define MUL_TOOM22_THRESHOLD                22
+#define MUL_TOOM33_THRESHOLD                57
+#define MUL_TOOM44_THRESHOLD               130
+#define MUL_TOOM6H_THRESHOLD               189
+#define MUL_TOOM8H_THRESHOLD               309
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      89
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD      99
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD      83
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD      88
+
+#define SQR_BASECASE_THRESHOLD               6
+#define SQR_TOOM2_THRESHOLD                 40
+#define SQR_TOOM3_THRESHOLD                 77
+#define SQR_TOOM4_THRESHOLD                124
+#define SQR_TOOM6_THRESHOLD                140
+#define SQR_TOOM8_THRESHOLD                238
+
+#define MULMID_TOOM42_THRESHOLD             40
+
+#define MULMOD_BNM1_THRESHOLD               15
+#define SQRMOD_BNM1_THRESHOLD               16
+
+#define POWM_SEC_TABLE  4,29,252,840,2080
+
+#define MUL_FFT_MODF_THRESHOLD             412  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    412, 5}, {     21, 6}, {     11, 5}, {     23, 6}, \
+    {     12, 5}, {     25, 6}, {     21, 7}, {     11, 6}, \
+    {     25, 7}, {     13, 6}, {     27, 7}, {     21, 8}, \
+    {     11, 7}, {     27, 8}, {     15, 7}, {     33, 8}, \
+    {     19, 7}, {     39, 8}, {     23, 7}, {     47, 8}, \
+    {     27, 9}, {     15, 8}, {     39, 9}, {     23, 8}, \
+    {     51,10}, {     15, 9}, {     31, 8}, {     67, 9}, \
+    {     39, 8}, {     79, 9}, {     55,10}, {     31, 9}, \
+    {     79,10}, {     47, 9}, {     95,11}, {     31,10}, \
+    {     63, 9}, {    135,10}, {     79, 9}, {    159,10}, \
+    {     95,11}, {     63,10}, {    127, 9}, {    255,10}, \
+    {    143, 9}, {    287,10}, {    159,11}, {     95,10}, \
+    {    191,12}, {     63,11}, {    127,10}, {    255, 9}, \
+    {    511,10}, {    271, 9}, {    543,10}, {    287,11}, \
+    {    159,10}, {    335, 9}, {    671,10}, {    351, 9}, \
+    {    703,11}, {    191,10}, {    383, 9}, {    767,10}, \
+    {    415, 9}, {    831,11}, {    223,12}, {   4096,13}, \
+    {   8192,14}, {  16384,15}, {  32768,16} }
+#define MUL_FFT_TABLE3_SIZE 71
+#define MUL_FFT_THRESHOLD                 4736
+
+#define SQR_FFT_MODF_THRESHOLD             340  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    340, 5}, {     21, 6}, {     11, 5}, {     23, 6}, \
+    {     21, 7}, {     11, 6}, {     24, 7}, {     13, 6}, \
+    {     27, 7}, {     21, 8}, {     11, 7}, {     27, 8}, \
+    {     15, 7}, {     33, 8}, {     19, 7}, {     39, 8}, \
+    {     23, 7}, {     47, 8}, {     27, 9}, {     15, 8}, \
+    {     39, 9}, {     23, 8}, {     47,10}, {     15, 9}, \
+    {     31, 8}, {     67, 9}, {     47,10}, {     31, 9}, \
+    {     71,10}, {     47,11}, {     31,10}, {     63, 9}, \
+    {    127, 8}, {    255, 9}, {    135,10}, {     79, 9}, \
+    {    159,10}, {     95, 9}, {    191,11}, {     63,10}, \
+    {    127, 9}, {    255, 8}, {    511, 9}, {    271,10}, \
+    {    143, 9}, {    287, 8}, {    575, 9}, {    303,10}, \
+    {    159,11}, {     95,10}, {    191,12}, {     63,11}, \
+    {    127,10}, {    255, 9}, {    511,10}, {    271, 9}, \
+    {    543,10}, {    287, 9}, {    575,10}, {    303,11}, \
+    {    159,10}, {    319, 9}, {    639,10}, {    335, 9}, \
+    {    671,10}, {    351,11}, {    191,10}, {    383, 9}, \
+    {    767,10}, {    415,11}, {    223,10}, {    447,12}, \
+    {   4096,13}, {   8192,14}, {  16384,15}, {  32768,16} }
+#define SQR_FFT_TABLE3_SIZE 76
+#define SQR_FFT_THRESHOLD                 3712
+
+#define MULLO_BASECASE_THRESHOLD             2
+#define MULLO_DC_THRESHOLD                  68
+#define MULLO_MUL_N_THRESHOLD             9236
+
+#define DC_DIV_QR_THRESHOLD                 69
+#define DC_DIVAPPR_Q_THRESHOLD             220
+#define DC_BDIV_QR_THRESHOLD                75
+#define DC_BDIV_Q_THRESHOLD                188
+
+#define INV_MULMOD_BNM1_THRESHOLD           54
+#define INV_NEWTON_THRESHOLD               230
+#define INV_APPR_THRESHOLD                 230
+
+#define BINV_NEWTON_THRESHOLD              278
+#define REDC_1_TO_REDC_N_THRESHOLD          87
+
+#define MU_DIV_QR_THRESHOLD               1210
+#define MU_DIVAPPR_Q_THRESHOLD            1308
+#define MUPI_DIV_QR_THRESHOLD              106
+#define MU_BDIV_QR_THRESHOLD              1017
+#define MU_BDIV_Q_THRESHOLD               1210
+
+#define MATRIX22_STRASSEN_THRESHOLD         14
+#define HGCD_THRESHOLD                     110
+#define HGCD_APPR_THRESHOLD                138
+#define HGCD_REDUCE_THRESHOLD             2578
+#define GCD_DC_THRESHOLD                   408
+#define GCDEXT_DC_THRESHOLD                298
+#define JACOBI_BASE_METHOD                   4
+
+#define GET_STR_DC_THRESHOLD                13
+#define GET_STR_PRECOMPUTE_THRESHOLD        24
+#define SET_STR_DC_THRESHOLD               527
+#define SET_STR_PRECOMPUTE_THRESHOLD      1090
diff --git a/third_party/gmp/mpn/powerpc32/p6/gmp-mparam.h b/third_party/gmp/mpn/powerpc32/p6/gmp-mparam.h
new file mode 100644
index 0000000..c9504b6
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc32/p6/gmp-mparam.h
@@ -0,0 +1,165 @@
+/* PowerPC-32 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 1999-2004, 2008-2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+/* 3500 MHz POWER6 */
+
+#define DIVREM_1_NORM_THRESHOLD              0  /* always */
+#define DIVREM_1_UNNORM_THRESHOLD            0  /* always */
+#define MOD_1_1P_METHOD                      2
+#define MOD_1_NORM_THRESHOLD                 3
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          3
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          3
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD     MP_SIZE_T_MAX
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD         0  /* never mpn_mod_1s_2p */
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD      8
+#define USE_PREINV_DIVREM_1                  1
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always */
+#define BMOD_1_TO_MOD_1_THRESHOLD        MP_SIZE_T_MAX  /* never */
+
+#define MUL_TOOM22_THRESHOLD                19
+#define MUL_TOOM33_THRESHOLD                55
+#define MUL_TOOM44_THRESHOLD                88
+#define MUL_TOOM6H_THRESHOLD               137
+#define MUL_TOOM8H_THRESHOLD               181
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      57
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD      56
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD      57
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD      56
+
+#define SQR_BASECASE_THRESHOLD               0  /* always */
+#define SQR_TOOM2_THRESHOLD                 30
+#define SQR_TOOM3_THRESHOLD                 56
+#define SQR_TOOM4_THRESHOLD                130
+#define SQR_TOOM6_THRESHOLD                189
+#define SQR_TOOM8_THRESHOLD                296
+
+#define MULMID_TOOM42_THRESHOLD             26
+
+#define MULMOD_BNM1_THRESHOLD                7
+#define SQRMOD_BNM1_THRESHOLD               12
+
+#define POWM_SEC_TABLE  2,26,127,453,1068
+
+#define MUL_FFT_MODF_THRESHOLD             212  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    212, 5}, {     13, 6}, {      7, 5}, {     15, 6}, \
+    {     13, 7}, {      7, 6}, {     16, 7}, {      9, 6}, \
+    {     19, 7}, {     13, 8}, {      7, 7}, {     19, 8}, \
+    {     11, 7}, {     25, 9}, {      7, 8}, {     15, 7}, \
+    {     31, 8}, {     19, 7}, {     39, 8}, {     23, 9}, \
+    {     15, 8}, {     39, 9}, {     23, 8}, {     47,10}, \
+    {     15, 9}, {     31, 8}, {     63, 9}, {     39, 8}, \
+    {     79, 9}, {     47,10}, {     31, 9}, {     63, 8}, \
+    {    127, 9}, {     71, 8}, {    143, 7}, {    287, 9}, \
+    {     79,10}, {     47,11}, {     31,10}, {     63, 9}, \
+    {    127, 8}, {    255, 7}, {    511, 9}, {    143, 8}, \
+    {    287,10}, {     79, 9}, {    159, 8}, {    319, 9}, \
+    {    175, 8}, {    351,10}, {     95, 9}, {    191, 8}, \
+    {    383, 9}, {    207,10}, {    111,11}, {     63,10}, \
+    {    127, 9}, {    255, 8}, {    511,10}, {    143, 9}, \
+    {    287, 8}, {    575,10}, {    159, 9}, {    319,10}, \
+    {    175, 9}, {    351,11}, {     95,10}, {    191, 9}, \
+    {    383,10}, {    207, 9}, {    415,12}, {     63,11}, \
+    {    127,10}, {    255, 9}, {    511,10}, {    287, 9}, \
+    {    575,11}, {    159,10}, {    351, 9}, {    703,11}, \
+    {    191,10}, {    415, 9}, {    831,11}, {    223,10}, \
+    {    447,12}, {   4096,13}, {   8192,14}, {  16384,15}, \
+    {  32768,16} }
+#define MUL_FFT_TABLE3_SIZE 89
+#define MUL_FFT_THRESHOLD                 1728
+
+#define SQR_FFT_MODF_THRESHOLD             184  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    184, 5}, {      6, 4}, {     13, 5}, {     13, 6}, \
+    {      7, 5}, {     15, 6}, {     13, 7}, {      7, 6}, \
+    {     16, 7}, {      9, 6}, {     19, 7}, {     11, 6}, \
+    {     23, 7}, {     13, 8}, {      7, 7}, {     19, 8}, \
+    {     11, 7}, {     23, 9}, {      7, 8}, {     23, 9}, \
+    {     15, 8}, {     39, 9}, {     23,10}, {     15, 9}, \
+    {     31, 8}, {     63, 9}, {     39, 8}, {     79, 9}, \
+    {     47,10}, {     31, 9}, {     63, 8}, {    127, 7}, \
+    {    255, 9}, {     71, 8}, {    143, 7}, {    287, 6}, \
+    {    575, 9}, {     79,10}, {     47,11}, {     31,10}, \
+    {     63, 9}, {    127, 8}, {    255, 9}, {    143, 8}, \
+    {    287, 7}, {    575,10}, {     79, 9}, {    159, 8}, \
+    {    319, 9}, {    175, 8}, {    351,10}, {     95, 9}, \
+    {    191, 8}, {    383, 9}, {    207,10}, {    111, 9}, \
+    {    223,11}, {     63,10}, {    127, 9}, {    255,10}, \
+    {    143, 9}, {    287, 8}, {    575,10}, {    159, 9}, \
+    {    319,10}, {    175, 9}, {    351,11}, {     95,10}, \
+    {    191, 9}, {    383,10}, {    207, 9}, {    415,10}, \
+    {    223,12}, {     63,11}, {    127,10}, {    255, 9}, \
+    {    511,10}, {    287, 9}, {    575,11}, {    159,10}, \
+    {    351, 9}, {    703, 8}, {   1407,11}, {    191,10}, \
+    {    415,11}, {    223,10}, {    447, 9}, {    895,12}, \
+    {   4096,13}, {   8192,14}, {  16384,15}, {  32768,16} }
+#define SQR_FFT_TABLE3_SIZE 92
+#define SQR_FFT_THRESHOLD                 1600
+
+#define MULLO_BASECASE_THRESHOLD             2
+#define MULLO_DC_THRESHOLD                  57
+#define MULLO_MUL_N_THRESHOLD             3176
+
+#define DC_DIV_QR_THRESHOLD                 52
+#define DC_DIVAPPR_Q_THRESHOLD             187
+#define DC_BDIV_QR_THRESHOLD                64
+#define DC_BDIV_Q_THRESHOLD                146
+
+#define INV_MULMOD_BNM1_THRESHOLD           68
+#define INV_NEWTON_THRESHOLD               182
+#define INV_APPR_THRESHOLD                 182
+
+#define BINV_NEWTON_THRESHOLD              186
+#define REDC_1_TO_REDC_N_THRESHOLD          60
+
+#define MU_DIV_QR_THRESHOLD                924
+#define MU_DIVAPPR_Q_THRESHOLD             807
+#define MUPI_DIV_QR_THRESHOLD               73
+#define MU_BDIV_QR_THRESHOLD               667
+#define MU_BDIV_Q_THRESHOLD                823
+
+#define MATRIX22_STRASSEN_THRESHOLD          8
+#define HGCD_THRESHOLD                      61
+#define HGCD_APPR_THRESHOLD                 50
+#define HGCD_REDUCE_THRESHOLD              974
+#define GCD_DC_THRESHOLD                   195
+#define GCDEXT_DC_THRESHOLD                134
+#define JACOBI_BASE_METHOD                   4
+
+#define GET_STR_DC_THRESHOLD                 9
+#define GET_STR_PRECOMPUTE_THRESHOLD        21
+#define SET_STR_DC_THRESHOLD               190
+#define SET_STR_PRECOMPUTE_THRESHOLD       411
diff --git a/third_party/gmp/mpn/powerpc32/p7/gmp-mparam.h b/third_party/gmp/mpn/powerpc32/p7/gmp-mparam.h
new file mode 100644
index 0000000..ad48dac
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc32/p7/gmp-mparam.h
@@ -0,0 +1,170 @@
+/* PowerPC-32 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+/* 4150 MHz POWER8/T4 */
+/* FFT tuning limit = 0.5 M */
+/* Generated by tuneup.c, 2017-02-18, gcc 6.1 */
+
+#define DIVREM_1_NORM_THRESHOLD              0  /* always */
+#define DIVREM_1_UNNORM_THRESHOLD            0  /* always */
+#define MOD_1_1P_METHOD                      1
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          9
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          8
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD         0  /* never mpn_mod_1_1p */
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        22
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     11
+#define USE_PREINV_DIVREM_1                  1
+#define DIV_QR_1N_PI1_METHOD                 2
+#define DIV_QR_1_NORM_THRESHOLD              4
+#define DIV_QR_1_UNNORM_THRESHOLD            3
+#define DIV_QR_2_PI2_THRESHOLD              15
+#define DIVEXACT_1_THRESHOLD                 0  /* always */
+#define BMOD_1_TO_MOD_1_THRESHOLD           39
+
+#define DIV_1_VS_MUL_1_PERCENT             343
+
+#define MUL_TOOM22_THRESHOLD                20
+#define MUL_TOOM33_THRESHOLD                73
+#define MUL_TOOM44_THRESHOLD               202
+#define MUL_TOOM6H_THRESHOLD               286
+#define MUL_TOOM8H_THRESHOLD               430
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD     137
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     140
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     128
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     145
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     121
+
+#define SQR_BASECASE_THRESHOLD               0  /* always */
+#define SQR_TOOM2_THRESHOLD                 26
+#define SQR_TOOM3_THRESHOLD                 97
+#define SQR_TOOM4_THRESHOLD                236
+#define SQR_TOOM6_THRESHOLD                318
+#define SQR_TOOM8_THRESHOLD                478
+
+#define MULMID_TOOM42_THRESHOLD             34
+
+#define MULMOD_BNM1_THRESHOLD               18
+#define SQRMOD_BNM1_THRESHOLD               18
+
+#define MUL_FFT_MODF_THRESHOLD             444  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    444, 5}, {     21, 6}, {     12, 5}, {     25, 6}, \
+    {     13, 5}, {     27, 6}, {     21, 7}, {     11, 6}, \
+    {     25, 7}, {     13, 6}, {     27, 7}, {     17, 6}, \
+    {     35, 7}, {     21, 8}, {     11, 7}, {     27, 8}, \
+    {     15, 7}, {     35, 8}, {     19, 7}, {     41, 8}, \
+    {     27, 9}, {     15, 8}, {     39, 9}, {     23, 8}, \
+    {     51,10}, {     15, 9}, {     31, 8}, {     63, 9}, \
+    {     39, 8}, {     79, 9}, {     47,10}, {     31, 9}, \
+    {     79,10}, {     47,11}, {     31,10}, {     63, 9}, \
+    {    135,10}, {     79, 9}, {    159,10}, {     95, 9}, \
+    {    191,10}, {    111,11}, {     63,10}, {    127, 9}, \
+    {    255,10}, {    143, 9}, {    287,10}, {    159,11}, \
+    {     95,10}, {    191,12}, {     63,11}, {    127,10}, \
+    {    255, 9}, {    511,10}, {    271, 9}, {    543, 8}, \
+    {   1087,10}, {    287,11}, {    159,10}, {    319, 9}, \
+    {    639,10}, {    351,11}, {    191,10}, {    415, 9}, \
+    {    831,11}, {    223,12}, {   4096,13}, {   8192,14}, \
+    {  16384,15}, {  32768,16} }
+#define MUL_FFT_TABLE3_SIZE 70
+#define MUL_FFT_THRESHOLD                 4544
+
+#define SQR_FFT_MODF_THRESHOLD             332  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    332, 5}, {     21, 6}, {     11, 5}, {     23, 6}, \
+    {     21, 7}, {     11, 6}, {     24, 7}, {     13, 6}, \
+    {     27, 7}, {     15, 6}, {     31, 7}, {     21, 8}, \
+    {     11, 7}, {     27, 8}, {     15, 7}, {     33, 8}, \
+    {     19, 7}, {     39, 8}, {     27, 9}, {     15, 8}, \
+    {     39, 9}, {     23, 8}, {     47,10}, {     15, 9}, \
+    {     31, 8}, {     63, 9}, {     47,10}, {     31, 9}, \
+    {     79,10}, {     47,11}, {     31,10}, {     63, 9}, \
+    {    127, 8}, {    255, 9}, {    135,10}, {     95, 9}, \
+    {    191,11}, {     63,10}, {    127, 9}, {    255, 8}, \
+    {    511, 9}, {    271,10}, {    143, 9}, {    287, 8}, \
+    {    575, 9}, {    303, 8}, {    607,10}, {    159,11}, \
+    {     95,10}, {    191,12}, {     63,11}, {    127,10}, \
+    {    255, 9}, {    511,10}, {    271, 9}, {    543,10}, \
+    {    287, 9}, {    575,10}, {    303, 9}, {    607,11}, \
+    {    159,10}, {    319, 9}, {    639,10}, {    351, 9}, \
+    {    703,11}, {    191,10}, {    383, 9}, {    767,10}, \
+    {    415,11}, {    223,10}, {    447,12}, {   4096,13}, \
+    {   8192,14}, {  16384,15}, {  32768,16} }
+#define SQR_FFT_TABLE3_SIZE 75
+#define SQR_FFT_THRESHOLD                 3520
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  36
+#define MULLO_MUL_N_THRESHOLD             8648
+#define SQRLO_BASECASE_THRESHOLD             5
+#define SQRLO_DC_THRESHOLD                 193
+#define SQRLO_SQR_THRESHOLD               6675
+
+#define DC_DIV_QR_THRESHOLD                 33
+#define DC_DIVAPPR_Q_THRESHOLD             134
+#define DC_BDIV_QR_THRESHOLD                51
+#define DC_BDIV_Q_THRESHOLD                134
+
+#define INV_MULMOD_BNM1_THRESHOLD           66
+#define INV_NEWTON_THRESHOLD               132
+#define INV_APPR_THRESHOLD                 131
+
+#define BINV_NEWTON_THRESHOLD              292
+#define REDC_1_TO_REDC_N_THRESHOLD          67
+
+#define MU_DIV_QR_THRESHOLD               1334
+#define MU_DIVAPPR_Q_THRESHOLD            1334
+#define MUPI_DIV_QR_THRESHOLD               62
+#define MU_BDIV_QR_THRESHOLD              1142
+#define MU_BDIV_Q_THRESHOLD               1470
+
+#define POWM_SEC_TABLE  3,25,114,480,1486
+
+#define GET_STR_DC_THRESHOLD                 8
+#define GET_STR_PRECOMPUTE_THRESHOLD        14
+#define SET_STR_DC_THRESHOLD               644
+#define SET_STR_PRECOMPUTE_THRESHOLD      1365
+
+#define FAC_DSC_THRESHOLD                  107
+#define FAC_ODD_THRESHOLD                   29
+
+#define MATRIX22_STRASSEN_THRESHOLD         16
+#define HGCD_THRESHOLD                      95
+#define HGCD_APPR_THRESHOLD                121
+#define HGCD_REDUCE_THRESHOLD             2681
+#define GCD_DC_THRESHOLD                   456
+#define GCDEXT_DC_THRESHOLD                386
+#define JACOBI_BASE_METHOD                   4
diff --git a/third_party/gmp/mpn/powerpc32/powerpc-defs.m4 b/third_party/gmp/mpn/powerpc32/powerpc-defs.m4
new file mode 100644
index 0000000..8a1451c
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc32/powerpc-defs.m4
@@ -0,0 +1,121 @@
+divert(-1)
+
+dnl  m4 macros for PowerPC assembler (32 and 64 bit).
+
+dnl  Copyright 2000, 2002, 2003, 2017, 2018 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+dnl  Called: PROLOGUE_cpu(GSYM_PREFIX`'foo)
+dnl
+dnl  This is the same as the default in mpn/asm-defs.m4, but with ALIGN(4)
+dnl  not 8.
+dnl
+dnl  4-byte alignment is normally enough, certainly it's what gcc gives.  We
+dnl  don't want bigger alignment within PROLOGUE since it can introduce
+dnl  padding into multiple-entrypoint routines, and with gas such padding is
+dnl  zero words, which are not valid instructions.
+
+define(`PROLOGUE_cpu',
+m4_assert_numargs(1)
+`	TEXT
+	ALIGN(4)
+	GLOBL	`$1' GLOBL_ATTR
+	TYPE(`$1',`function')
+`$1'LABEL_SUFFIX')
+
+
+dnl  Usage: r0 ... r31, cr0 ... cr7
+dnl
+dnl  Registers names, either left as "r0" etc or mapped to plain 0 etc,
+dnl  according to the result of the GMP_ASM_POWERPC_REGISTERS configure
+dnl  test.
+
+ifelse(WANT_R_REGISTERS,no,`
+forloop(i,0,31,`deflit(`r'i,i)')
+forloop(i,0,31,`deflit(`v'i,i)')
+forloop(i,0,31,`deflit(`f'i,i)')
+forloop(i,0,7, `deflit(`cr'i,i)')
+')
+
+
+dnl  Usage: ASSERT(cond,instructions)
+dnl
+dnl  If WANT_ASSERT is 1, output the given instructions and expect the given
+dnl  flags condition to then be satisfied.  For example,
+dnl
+dnl         ASSERT(eq, `cmpwi r6, 123')
+dnl
+dnl  The instructions can be omitted to just assert a flags condition with
+dnl  no extra calculation.  For example,
+dnl
+dnl         ASSERT(ne)
+dnl
+dnl  The condition can be omitted to just output the given instructions when
+dnl  assertion checking is wanted.  For example,
+dnl
+dnl         ASSERT(, `mr r11, r0')
+dnl
+dnl  Using a zero word for an illegal instruction is probably not ideal,
+dnl  since it marks the beginning of a traceback table in the 64-bit ABI.
+dnl  But assertions are only for development, so it doesn't matter too much.
+
+define(ASSERT,
+m4_assert_numargs_range(1,2)
+m4_assert_defined(`WANT_ASSERT')
+`ifelse(WANT_ASSERT,1,
+	`C ASSERT
+	$2
+ifelse(`$1',,,
+`	b$1	L(ASSERT_ok`'ASSERT_counter)
+	W32	0	C assertion failed
+L(ASSERT_ok`'ASSERT_counter):
+define(`ASSERT_counter',incr(ASSERT_counter))
+')')')
+
+define(ASSERT_counter,1)
+
+dnl  Manually assemble some new instructions
+dnl
+
+define(`maddld',m4_assert_numargs(4)`dnl
+.long eval(0x10000033+m4_lshift($1,21)+m4_lshift($2,16)+m4_lshift($3,11)+m4_lshift($4,6))')
+
+define(`maddhdu',m4_assert_numargs(4)`dnl
+.long eval(0x10000031+m4_lshift($1,21)+m4_lshift($2,16)+m4_lshift($3,11)+m4_lshift($4,6))')
+
+define(`popcntd',m4_assert_numargs(2)`dnl
+.long eval(0x7c0003f4+m4_lshift($2,21)+m4_lshift($1,16))')
+
+define(`divdeu',m4_assert_numargs(3)`dnl
+.long eval(0x7c000312+m4_lshift($1,21)+m4_lshift($2,16)+m4_lshift($3,11))')
+
+define(`addex',m4_assert_numargs(4)`dnl
+.long eval(0x7c000154+m4_lshift($1,21)+m4_lshift($2,16)+m4_lshift($3,11)+m4_lshift($4,9))')
+
+divert
diff --git a/third_party/gmp/mpn/powerpc32/rshift.asm b/third_party/gmp/mpn/powerpc32/rshift.asm
new file mode 100644
index 0000000..d86cdcb
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc32/rshift.asm
@@ -0,0 +1,166 @@
+dnl  PowerPC-32 mpn_rshift -- Shift a number right.
+
+dnl  Copyright 1995, 1998, 2000, 2002-2005 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                cycles/limb
+C 603e:            ?
+C 604e:            3.0
+C 75x (G3):        3.0
+C 7400,7410 (G4):  3.0
+C 7445,7455 (G4+): 2.5
+C 7447,7457 (G4+): 2.25
+C power4/ppc970:   2.5
+C power5:          2.5
+
+C INPUT PARAMETERS
+C rp	r3
+C up	r4
+C n	r5
+C cnt	r6
+
+ASM_START()
+PROLOGUE(mpn_rshift)
+	cmpwi	cr0, r5, 30	C more than 30 limbs?
+	addi	r7, r3, -4	C dst-4
+	bgt	L(BIG)		C branch if more than 12 limbs
+
+	mtctr	r5		C copy size into CTR
+	subfic	r8, r6, 32
+	lwz	r11, 0(r4)	C load first s1 limb
+	slw	r3, r11, r8	C compute function return value
+	bdz	L(end1)
+
+L(oop):	lwzu	r10, 4(r4)
+	srw	r9, r11, r6
+	slw	r12, r10, r8
+	or	r9, r9, r12
+	stwu	r9, 4(r7)
+	bdz	L(end2)
+	lwzu	r11, 4(r4)
+	srw	r9, r10, r6
+	slw	r12, r11, r8
+	or	r9, r9, r12
+	stwu	r9, 4(r7)
+	bdnz	L(oop)
+
+L(end1):
+	srw	r0, r11, r6
+	stw	r0, 4(r7)
+	blr
+L(end2):
+	srw	r0, r10, r6
+	stw	r0, 4(r7)
+	blr
+
+L(BIG):
+	stwu	r1, -48(r1)
+	stmw	r24, 8(r1)	C save registers we are supposed to preserve
+	lwz	r9, 0(r4)
+	subfic	r8, r6, 32
+	slw	r3, r9, r8	C compute function return value
+	srw	r0, r9, r6
+	addi	r5, r5, -1
+
+	andi.	r10, r5, 3	C count for spill loop
+	beq	L(e)
+	mtctr	r10
+	lwzu	r28, 4(r4)
+	bdz	L(xe0)
+
+L(loop0):
+	srw	r12, r28, r6
+	slw	r24, r28, r8
+	lwzu	r28, 4(r4)
+	or	r24, r0, r24
+	stwu	r24, 4(r7)
+	mr	r0, r12
+	bdnz	L(loop0)	C taken at most once!
+
+L(xe0):	srw	r12, r28, r6
+	slw	r24, r28, r8
+	or	r24, r0, r24
+	stwu	r24, 4(r7)
+	mr	r0, r12
+
+L(e):	srwi	r5, r5, 2	C count for unrolled loop
+	addi	r5, r5, -1
+	mtctr	r5
+	lwz	r28, 4(r4)
+	lwz	r29, 8(r4)
+	lwz	r30, 12(r4)
+	lwzu	r31, 16(r4)
+
+L(loopU):
+	srw	r9, r28, r6
+	slw	r24, r28, r8
+	lwz	r28, 4(r4)
+	srw	r10, r29, r6
+	slw	r25, r29, r8
+	lwz	r29, 8(r4)
+	srw	r11, r30, r6
+	slw	r26, r30, r8
+	lwz	r30, 12(r4)
+	srw	r12, r31, r6
+	slw	r27, r31, r8
+	lwzu	r31, 16(r4)
+	or	r24, r0, r24
+	stw	r24, 4(r7)
+	or	r25, r9, r25
+	stw	r25, 8(r7)
+	or	r26, r10, r26
+	stw	r26, 12(r7)
+	or	r27, r11, r27
+	stwu	r27, 16(r7)
+	mr	r0, r12
+	bdnz	L(loopU)
+
+	srw	r9, r28, r6
+	slw	r24, r28, r8
+	srw	r10, r29, r6
+	slw	r25, r29, r8
+	srw	r11, r30, r6
+	slw	r26, r30, r8
+	srw	r12, r31, r6
+	slw	r27, r31, r8
+	or	r24, r0, r24
+	stw	r24, 4(r7)
+	or	r25, r9, r25
+	stw	r25, 8(r7)
+	or	r26, r10, r26
+	stw	r26, 12(r7)
+	or	r27, r11, r27
+	stw	r27, 16(r7)
+
+	stw	r12, 20(r7)
+	lmw	r24, 8(r1)	C restore registers
+	addi	r1, r1, 48
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc32/sec_tabselect.asm b/third_party/gmp/mpn/powerpc32/sec_tabselect.asm
new file mode 100644
index 0000000..d50718e
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc32/sec_tabselect.asm
@@ -0,0 +1,143 @@
+dnl  PowerPC-32 mpn_sec_tabselect.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                   cycles/limb
+C 603e:			 ?
+C 604e:			 ?
+C 75x (G3):		 ?
+C 7400,7410 (G4):	 2.5
+C 744x,745x (G4+):	 2.0
+C power4/ppc970:	 2.0
+C power5:		 ?
+
+define(`rp',     `r3')
+define(`tp',     `r4')
+define(`n',      `r5')
+define(`nents',  `r6')
+define(`which',  `r7')
+
+define(`i',      `r8')
+define(`j',      `r9')
+define(`stride', `r12')
+define(`mask',   `r11')
+
+
+ASM_START()
+PROLOGUE(mpn_sec_tabselect)
+	stwu	r1, -32(r1)
+	addic.	j, n, -4		C outer loop induction variable
+	stmw	r27, 8(r1)
+	slwi	stride, n, 2
+
+	blt	cr0, L(outer_end)
+L(outer_top):
+	mtctr	nents
+	mr	r10, tp
+	li	r28, 0
+	li	r29, 0
+	li	r30, 0
+	li	r31, 0
+	addic.	j, j, -4		C outer loop induction variable
+	mr	i, which
+
+	ALIGN(16)
+L(top):	addic	i, i, -1		C set carry iff i != 0
+	subfe	mask, mask, mask
+	lwz	r0, 0(tp)
+	lwz	r27, 4(tp)
+	and	r0, r0, mask
+	and	r27, r27, mask
+	or	r28, r28, r0
+	or	r29, r29, r27
+	lwz	r0, 8(tp)
+	lwz	r27, 12(tp)
+	and	r0, r0, mask
+	and	r27, r27, mask
+	or	r30, r30, r0
+	or	r31, r31, r27
+	add	tp, tp, stride
+	bdnz	L(top)
+
+	stw	r28, 0(rp)
+	stw	r29, 4(rp)
+	stw	r30, 8(rp)
+	stw	r31, 12(rp)
+	addi	tp, r10, 16
+	addi	rp, rp, 16
+	bge	cr0, L(outer_top)
+L(outer_end):
+
+	andi.	r0, n, 2
+	beq	cr0, L(b0x)
+L(b1x):	mtctr	nents
+	mr	r10, tp
+	li	r28, 0
+	li	r29, 0
+	mr	i, which
+	ALIGN(16)
+L(tp2):	addic	i, i, -1
+	subfe	mask, mask, mask
+	lwz	r0, 0(tp)
+	lwz	r27, 4(tp)
+	and	r0, r0, mask
+	and	r27, r27, mask
+	or	r28, r28, r0
+	or	r29, r29, r27
+	add	tp, tp, stride
+	bdnz	L(tp2)
+	stw	r28, 0(rp)
+	stw	r29, 4(rp)
+	addi	tp, r10, 8
+	addi	rp, rp, 8
+
+L(b0x):	andi.	r0, n, 1
+	beq	cr0, L(b00)
+L(b01):	mtctr	nents
+	mr	r10, tp
+	li	r28, 0
+	mr	i, which
+	ALIGN(16)
+L(tp1):	addic	i, i, -1
+	subfe	mask, mask, mask
+	lwz	r0, 0(tp)
+	and	r0, r0, mask
+	or	r28, r28, r0
+	add	tp, tp, stride
+	bdnz	L(tp1)
+	stw	r28, 0(rp)
+
+L(b00):	lmw	r27, 8(r1)
+	addi	r1, r1, 32
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc32/sqr_diag_addlsh1.asm b/third_party/gmp/mpn/powerpc32/sqr_diag_addlsh1.asm
new file mode 100644
index 0000000..f7aba33
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc32/sqr_diag_addlsh1.asm
@@ -0,0 +1,80 @@
+dnl  PowerPC-32 mpn_sqr_diag_addlsh1.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                cycles/limb
+C 603e			 ?
+C 604e			 ?
+C 75x (G3)		 ?
+C 7400,7410 (G4)	 ?
+C 744x,745x (G4+)	 6
+C power4/ppc970		 ?
+C power5		 ?
+
+C This has been feebly optimised for 7447 but not for any other CPU.
+
+define(`rp',	r3)
+define(`tp',	r4)
+define(`up',	r5)
+define(`n',	r6)
+
+ASM_START()
+PROLOGUE(mpn_sqr_diag_addlsh1)
+	addi	n, n, -1
+	addi	tp, tp, -4
+	mtctr	n
+	lwz	r0, 0(up)
+	li	r10, 0
+	mullw	r7, r0, r0
+	stw	r7, 0(rp)
+	mulhwu	r6, r0, r0
+	addic	r31, r31, 0	C clear CF
+
+	ALIGN(16)
+L(top):	lwzu	r0, 4(up)
+	mullw	r7, r0, r0
+	lwz	r8, 4(tp)
+	lwzu	r9, 8(tp)
+	rlwimi	r10, r8, 1,0,30
+	srwi	r11, r8, 31
+	rlwimi	r11, r9, 1,0,30
+	adde	r10, r10, r6
+	adde	r11, r11, r7
+	stw	r10, 4(rp)
+	srwi	r10, r9, 31
+	mulhwu	r6, r0, r0
+	stwu	r11, 8(rp)
+	bdnz	L(top)
+
+	adde	r10, r10, r6
+	stw	r10, 4(rp)
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc32/sublsh1_n.asm b/third_party/gmp/mpn/powerpc32/sublsh1_n.asm
new file mode 100644
index 0000000..6dc6460
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc32/sublsh1_n.asm
@@ -0,0 +1,101 @@
+dnl  PowerPC-32 mpn_sublsh1_n -- rp[] = up[] - (vp[] << 1)
+
+dnl  Copyright 2003, 2005, 2007 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                cycles/limb
+C 603e:            ?
+C 604e:            4.0
+C 75x (G3):        5.0
+C 7400,7410 (G4):  5.0
+C 744x,745x (G4+): 5.0
+C power4/ppc970:   4.25
+C power5:          5.0
+
+C INPUT PARAMETERS
+C rp	r3
+C up	r4
+C vp	r5
+C n	r6
+
+define(`rp',`r3')
+define(`up',`r4')
+define(`vp',`r5')
+
+define(`s0',`r6')
+define(`s1',`r7')
+define(`u0',`r8')
+define(`v0',`r10')
+define(`v1',`r11')
+
+ASM_START()
+PROLOGUE(mpn_sublsh1_n)
+	mtctr	r6		C copy n in ctr
+
+	lwz	v0, 0(vp)	C load v limb
+	lwz	u0, 0(up)	C load u limb
+	addic	up, up, -4	C update up; set cy
+	addi	rp, rp, -4	C update rp
+	slwi	s1, v0, 1
+	bdz	L(end)		C If done, skip loop
+
+L(loop):
+	lwz	v1, 4(vp)	C load v limb
+	subfe	s1, s1, u0	C add limbs with cy, set cy
+	srwi	s0, v0, 31	C shift down previous v limb
+	stw	s1, 4(rp)	C store result limb
+	lwzu	u0, 8(up)	C load u limb and update up
+	rlwimi	s0, v1, 1, 0,30	C left shift v limb and merge with prev v limb
+
+	bdz	L(exit)		C decrement ctr and exit if done
+
+	lwzu	v0, 8(vp)	C load v limb and update vp
+	subfe	s0, s0, u0	C add limbs with cy, set cy
+	srwi	s1, v1, 31	C shift down previous v limb
+	stwu	s0, 8(rp)	C store result limb and update rp
+	lwz	u0, 4(up)	C load u limb
+	rlwimi	s1, v0, 1, 0,30	C left shift v limb and merge with prev v limb
+
+	bdnz	L(loop)		C decrement ctr and loop back
+
+L(end):	subfe	r7, s1, u0
+	srwi	r4, v0, 31
+	stw	r7, 4(rp)	C store last result limb
+	subfze	r3, r4
+	neg	r3, r3
+	blr
+L(exit):
+	subfe	r7, s0, u0
+	srwi	r4, v1, 31
+	stw	r7, 8(rp)	C store last result limb
+	subfze	r3, r4
+	neg	r3, r3
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc32/submul_1.asm b/third_party/gmp/mpn/powerpc32/submul_1.asm
new file mode 100644
index 0000000..8ef37b0
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc32/submul_1.asm
@@ -0,0 +1,151 @@
+dnl  PowerPC-32 mpn_submul_1 -- Multiply a limb vector with a limb and subtract
+dnl  the result from a second limb vector.
+
+dnl  Copyright 1995, 1997, 1998, 2000, 2002, 2005 Free Software Foundation,
+dnl  Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                cycles/limb
+C 603e:            ?
+C 604e:            7.5
+C 75x (G3):        9.3-15
+C 7400,7410 (G4):  9.3-15
+C 744x,745x (G4+): 10.5
+C power4/ppc970:   6.75
+C power5:          6.5
+
+C INPUT PARAMETERS
+C rp	r3
+C up	r4
+C n	r5
+C vl	r6
+
+C This is optimized for the PPC604.  See addmul_1.asm for additional comments.
+
+ASM_START()
+PROLOGUE(mpn_submul_1)
+	cmpwi	cr0,r5,9	C more than 9 limbs?
+	bgt	cr0,L(big)	C branch if more than 9 limbs
+
+	mtctr	r5
+	lwz	r0,0(r4)
+	mullw	r7,r0,r6
+	mulhwu	r10,r0,r6
+	lwz	r9,0(r3)
+	subfc	r8,r7,r9
+	addc	r7,r7,r8	C invert cy (r7 is junk)
+	addi	r3,r3,-4
+	bdz	L(end)
+L(loop):
+	lwzu	r0,4(r4)
+	stwu	r8,4(r3)
+	mullw	r8,r0,r6
+	adde	r7,r8,r10
+	mulhwu	r10,r0,r6
+	lwz	r9,4(r3)
+	addze	r10,r10
+	subfc	r8,r7,r9
+	addc	r7,r7,r8	C invert cy (r7 is junk)
+	bdnz	L(loop)
+L(end):	stw	r8,4(r3)
+	addze	r3,r10
+	blr
+
+L(big):	stwu	r1,-16(r1)
+	addi	r5,r5,-1
+	stw	r30,8(r1)
+	srwi	r0,r5,2
+	stw	r31,12(r1)
+	mtctr	r0
+
+	lwz	r7,0(r4)
+	mullw	r8,r7,r6
+	mulhwu	r0,r7,r6
+	lwz	r7,0(r3)
+	subfc	r7,r8,r7
+	addc	r8,r8,r7
+	stw	r7,0(r3)
+
+L(loopU):
+	lwz	r7,4(r4)
+	lwz	r12,8(r4)
+	lwz	r30,12(r4)
+	lwzu	r31,16(r4)
+	mullw	r8,r7,r6
+	mullw	r9,r12,r6
+	mullw	r10,r30,r6
+	mullw	r11,r31,r6
+	adde	r8,r8,r0	C add cy_limb
+	mulhwu	r0,r7,r6
+	lwz	r7,4(r3)
+	adde	r9,r9,r0
+	mulhwu	r0,r12,r6
+	lwz	r12,8(r3)
+	adde	r10,r10,r0
+	mulhwu	r0,r30,r6
+	lwz	r30,12(r3)
+	adde	r11,r11,r0
+	mulhwu	r0,r31,r6
+	lwz	r31,16(r3)
+	addze	r0,r0		C new cy_limb
+	subfc	r7,r8,r7
+	stw	r7,4(r3)
+	subfe	r12,r9,r12
+	stw	r12,8(r3)
+	subfe	r30,r10,r30
+	stw	r30,12(r3)
+	subfe	r31,r11,r31
+	stwu	r31,16(r3)
+	subfe	r11,r11,r11	C invert ...
+	addic	r11,r11,1	C ... carry
+	bdnz	L(loopU)
+
+	andi.	r31,r5,3
+	mtctr	r31
+	beq	cr0,L(endx)
+
+L(loopE):
+	lwzu	r7,4(r4)
+	mullw	r8,r7,r6
+	adde	r8,r8,r0	C add cy_limb
+	mulhwu	r0,r7,r6
+	lwz	r7,4(r3)
+	addze	r0,r0		C new cy_limb
+	subfc	r7,r8,r7
+	addc	r8,r8,r7
+	stwu	r7,4(r3)
+	bdnz	L(loopE)
+L(endx):
+	addze	r3,r0
+	lwz	r30,8(r1)
+	lwz	r31,12(r1)
+	addi	r1,r1,16
+	blr
+EPILOGUE(mpn_submul_1)
diff --git a/third_party/gmp/mpn/powerpc32/umul.asm b/third_party/gmp/mpn/powerpc32/umul.asm
new file mode 100644
index 0000000..a5811e1
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc32/umul.asm
@@ -0,0 +1,50 @@
+dnl  PowerPC-32 umul_ppmm -- support for longlong.h
+
+dnl  Copyright 2000, 2001 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C mp_limb_t mpn_umul_ppmm (mp_limb_t *lowptr, mp_limb_t m1, mp_limb_t m2);
+C
+
+ASM_START()
+PROLOGUE(mpn_umul_ppmm)
+
+	C r3	lowptr
+	C r4	m1
+	C r5	m2
+
+	mullw	r0, r4, r5
+	mulhwu	r9, r4, r5
+	stw	r0, 0(r3)
+	mr	r3, r9
+	blr
+
+EPILOGUE(mpn_umul_ppmm)
diff --git a/third_party/gmp/mpn/powerpc32/vmx/copyd.asm b/third_party/gmp/mpn/powerpc32/vmx/copyd.asm
new file mode 100644
index 0000000..dee7266
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc32/vmx/copyd.asm
@@ -0,0 +1,203 @@
+dnl  PowerPC-32/VMX and PowerPC-64/VMX mpn_copyd.
+
+dnl  Copyright 2006 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                16-byte coaligned      unaligned
+C                   cycles/limb        cycles/limb
+C 7400,7410 (G4):       0.5                0.64
+C 744x,745x (G4+):      0.75               0.82
+C 970 (G5):             0.78               1.02		(64-bit limbs)
+
+C STATUS
+C  * Works for all sizes and alignments.
+
+C TODO
+C  * Optimize unaligned case.  Some basic tests with 2-way and 4-way unrolling
+C    indicate that we can reach 0.56 c/l for 7400, 0.75 c/l for 745x, and 0.80
+C    c/l for 970.
+C  * Consider using VMX instructions also for head and tail, by using some
+C    read-modify-write tricks.
+C  * The VMX code is used from the smallest sizes it handles, but measurements
+C    show a large speed bump at the cutoff points.  Small copying (perhaps
+C    using some read-modify-write technique) should be optimized.
+C  * Make an mpn_com based on this code.
+
+define(`GMP_LIMB_BYTES', eval(GMP_LIMB_BITS/8))
+define(`LIMBS_PER_VR',  eval(16/GMP_LIMB_BYTES))
+define(`LIMBS_PER_2VR', eval(32/GMP_LIMB_BYTES))
+
+
+ifelse(GMP_LIMB_BITS,32,`
+	define(`LIMB32',`	$1')
+	define(`LIMB64',`')
+',`
+	define(`LIMB32',`')
+	define(`LIMB64',`	$1')
+')
+
+C INPUT PARAMETERS
+define(`rp',	`r3')
+define(`up',	`r4')
+define(`n',	`r5')
+
+define(`us',	`v4')
+
+
+ASM_START()
+PROLOGUE(mpn_copyd)
+
+LIMB32(`slwi.	r0, n, 2	')
+LIMB64(`sldi.	r0, n, 3	')
+	add	rp, rp, r0
+	add	up, up, r0
+
+LIMB32(`cmpi	cr7, n, 11	')
+LIMB64(`cmpdi	cr7, n, 5	')
+	bge	cr7, L(big)
+
+	beqlr	cr0
+
+C Handle small cases with plain operations
+	mtctr	n
+L(topS):
+LIMB32(`lwz	r0, -4(up)	')
+LIMB64(`ld	r0, -8(up)	')
+	addi	up, up, -GMP_LIMB_BYTES
+LIMB32(`stw	r0, -4(rp)	')
+LIMB64(`std	r0, -8(rp)	')
+	addi	rp, rp, -GMP_LIMB_BYTES
+	bdnz	L(topS)
+	blr
+
+C Handle large cases with VMX operations
+L(big):
+	addi	rp, rp, -16
+	addi	up, up, -16
+	mfspr	r12, 256
+	oris	r0, r12, 0xf800		C Set VRSAVE bit 0-4
+	mtspr	256, r0
+
+LIMB32(`rlwinm.	r7, rp, 30,30,31')	C (rp >> 2) mod 4
+LIMB64(`rlwinm.	r7, rp, 29,31,31')	C (rp >> 3) mod 2
+	beq	L(rp_aligned)
+
+	subf	n, r7, n
+L(top0):
+LIMB32(`lwz	r0, 12(up)	')
+LIMB64(`ld	r0, 8(up)	')
+	addi	up, up, -GMP_LIMB_BYTES
+LIMB32(`addic.	r7, r7, -1	')
+LIMB32(`stw	r0, 12(rp)	')
+LIMB64(`std	r0, 8(rp)	')
+	addi	rp, rp, -GMP_LIMB_BYTES
+LIMB32(`bne	L(top0)		')
+
+L(rp_aligned):
+
+LIMB32(`rlwinm.	r0, up, 30,30,31')	C (up >> 2) mod 4
+LIMB64(`rlwinm.	r0, up, 29,31,31')	C (up >> 3) mod 2
+
+LIMB64(`srdi	r7, n, 2	')	C loop count corresponding to n
+LIMB32(`srwi	r7, n, 3	')	C loop count corresponding to n
+	mtctr	r7			C copy n to count register
+
+	li	r10, -16
+
+	beq	L(up_aligned)
+
+	lvsl	us, 0, up
+
+	addi	up, up, 16
+LIMB32(`andi.	r0, n, 0x4	')
+LIMB64(`andi.	r0, n, 0x2	')
+	beq	L(1)
+	lvx	v0, 0, up
+	lvx	v2, r10, up
+	vperm	v3, v2, v0, us
+	stvx	v3, 0, rp
+	addi	up, up, -32
+	addi	rp, rp, -16
+	b	L(lpu)
+L(1):	lvx	v2, 0, up
+	addi	up, up, -16
+	b	L(lpu)
+
+	ALIGN(32)
+L(lpu):	lvx	v0, 0, up
+	vperm	v3, v0, v2, us
+	stvx	v3, 0, rp
+	lvx	v2, r10, up
+	addi	up, up, -32
+	vperm	v3, v2, v0, us
+	stvx	v3, r10, rp
+	addi	rp, rp, -32
+	bdnz	L(lpu)
+
+	b	L(tail)
+
+L(up_aligned):
+
+LIMB32(`andi.	r0, n, 0x4	')
+LIMB64(`andi.	r0, n, 0x2	')
+	beq	L(lpa)
+	lvx	v0, 0,   up
+	stvx	v0, 0,   rp
+	addi	up, up, -16
+	addi	rp, rp, -16
+	b	L(lpa)
+
+	ALIGN(32)
+L(lpa):	lvx	v0, 0,   up
+	lvx	v1, r10, up
+	addi	up, up, -32
+	nop
+	stvx	v0, 0,   rp
+	stvx	v1, r10, rp
+	addi	rp, rp, -32
+	bdnz	L(lpa)
+
+L(tail):
+LIMB32(`rlwinm.	r7, n, 0,30,31	')	C r7 = n mod 4
+LIMB64(`rlwinm.	r7, n, 0,31,31	')	C r7 = n mod 2
+	beq	L(ret)
+LIMB32(`li	r10, 12		')
+L(top2):
+LIMB32(`lwzx	r0, r10, up	')
+LIMB64(`ld	r0, 8(up)	')
+LIMB32(`addic.	r7, r7, -1	')
+LIMB32(`stwx	r0, r10, rp	')
+LIMB64(`std	r0, 8(rp)	')
+LIMB32(`addi	r10, r10, -GMP_LIMB_BYTES')
+LIMB32(`bne	L(top2)		')
+
+L(ret):	mtspr	256, r12
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc32/vmx/copyi.asm b/third_party/gmp/mpn/powerpc32/vmx/copyi.asm
new file mode 100644
index 0000000..992b468
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc32/vmx/copyi.asm
@@ -0,0 +1,198 @@
+dnl  PowerPC-32/VMX and PowerPC-64/VMX mpn_copyi.
+
+dnl  Copyright 2006 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                16-byte coaligned      unaligned
+C                   cycles/limb        cycles/limb
+C 7400,7410 (G4):       0.5                0.64
+C 744x,745x (G4+):      0.75               0.82
+C 970 (G5):             0.78               1.02		(64-bit limbs)
+
+C STATUS
+C  * Works for all sizes and alignments.
+
+C TODO
+C  * Optimize unaligned case.  Some basic tests with 2-way and 4-way unrolling
+C    indicate that we can reach 0.56 c/l for 7400, 0.75 c/l for 745x, and 0.80
+C    c/l for 970.
+C  * Consider using VMX instructions also for head and tail, by using some
+C    read-modify-write tricks.
+C  * The VMX code is used from the smallest sizes it handles, but measurements
+C    show a large speed bump at the cutoff points.  Small copying (perhaps
+C    using some read-modify-write technique) should be optimized.
+C  * Make an mpn_com based on this code.
+
+define(`GMP_LIMB_BYTES', eval(GMP_LIMB_BITS/8))
+define(`LIMBS_PER_VR',  eval(16/GMP_LIMB_BYTES))
+define(`LIMBS_PER_2VR', eval(32/GMP_LIMB_BYTES))
+
+
+ifelse(GMP_LIMB_BITS,32,`
+	define(`LIMB32',`	$1')
+	define(`LIMB64',`')
+',`
+	define(`LIMB32',`')
+	define(`LIMB64',`	$1')
+')
+
+C INPUT PARAMETERS
+define(`rp',	`r3')
+define(`up',	`r4')
+define(`n',	`r5')
+
+define(`us',	`v4')
+
+
+ASM_START()
+PROLOGUE(mpn_copyi)
+
+LIMB32(`cmpi	cr7, n, 11	')
+LIMB64(`cmpdi	cr7, n, 5	')
+	bge	cr7, L(big)
+
+	or.	r0, n, n
+	beqlr	cr0
+
+C Handle small cases with plain operations
+	mtctr	n
+L(topS):
+LIMB32(`lwz	r0, 0(up)	')
+LIMB64(`ld	r0, 0(up)	')
+	addi	up, up, GMP_LIMB_BYTES
+LIMB32(`stw	r0, 0(rp)	')
+LIMB64(`std	r0, 0(rp)	')
+	addi	rp, rp, GMP_LIMB_BYTES
+	bdnz	L(topS)
+	blr
+
+C Handle large cases with VMX operations
+L(big):
+	mfspr	r12, 256
+	oris	r0, r12, 0xf800		C Set VRSAVE bit 0-4
+	mtspr	256, r0
+
+LIMB32(`rlwinm.	r7, rp, 30,30,31')	C (rp >> 2) mod 4
+LIMB64(`rlwinm.	r7, rp, 29,31,31')	C (rp >> 3) mod 2
+	beq	L(rp_aligned)
+
+	subfic	r7, r7, LIMBS_PER_VR
+	subf	n, r7, n
+L(top0):
+LIMB32(`lwz	r0, 0(up)	')
+LIMB64(`ld	r0, 0(up)	')
+	addi	up, up, GMP_LIMB_BYTES
+LIMB32(`addic.	r7, r7, -1	')
+LIMB32(`stw	r0, 0(rp)	')
+LIMB64(`std	r0, 0(rp)	')
+	addi	rp, rp, GMP_LIMB_BYTES
+LIMB32(`bne	L(top0)		')
+
+L(rp_aligned):
+
+LIMB32(`rlwinm.	r0, up, 30,30,31')	C (up >> 2) mod 4
+LIMB64(`rlwinm.	r0, up, 29,31,31')	C (up >> 3) mod 2
+
+LIMB64(`srdi	r7, n, 2	')	C loop count corresponding to n
+LIMB32(`srwi	r7, n, 3	')	C loop count corresponding to n
+	mtctr	r7			C copy n to count register
+
+	li	r10, 16
+
+	beq	L(up_aligned)
+
+	lvsl	us, 0, up
+
+LIMB32(`andi.	r0, n, 0x4	')
+LIMB64(`andi.	r0, n, 0x2	')
+	beq	L(1)
+	lvx	v0, 0, up
+	lvx	v2, r10, up
+	vperm	v3, v0, v2, us
+	stvx	v3, 0, rp
+	addi	up, up, 32
+	addi	rp, rp, 16
+	b	L(lpu)
+L(1):	lvx	v2, 0, up
+	addi	up, up, 16
+	b	L(lpu)
+
+	ALIGN(32)
+L(lpu):	lvx	v0, 0, up
+	vperm	v3, v2, v0, us
+	stvx	v3, 0, rp
+	lvx	v2, r10, up
+	addi	up, up, 32
+	vperm	v3, v0, v2, us
+	stvx	v3, r10, rp
+	addi	rp, rp, 32
+	bdnz	L(lpu)
+
+	addi	up, up, -16
+	b	L(tail)
+
+L(up_aligned):
+
+LIMB32(`andi.	r0, n, 0x4	')
+LIMB64(`andi.	r0, n, 0x2	')
+	beq	L(lpa)
+	lvx	v0, 0,   up
+	stvx	v0, 0,   rp
+	addi	up, up, 16
+	addi	rp, rp, 16
+	b	L(lpa)
+
+	ALIGN(32)
+L(lpa):	lvx	v0, 0,   up
+	lvx	v1, r10, up
+	addi	up, up, 32
+	nop
+	stvx	v0, 0,   rp
+	stvx	v1, r10, rp
+	addi	rp, rp, 32
+	bdnz	L(lpa)
+
+L(tail):
+LIMB32(`rlwinm.	r7, n, 0,30,31	')	C r7 = n mod 4
+LIMB64(`rlwinm.	r7, n, 0,31,31	')	C r7 = n mod 2
+	beq	L(ret)
+LIMB32(`li	r10, 0		')
+L(top2):
+LIMB32(`lwzx	r0, r10, up	')
+LIMB64(`ld	r0, 0(up)	')
+LIMB32(`addic.	r7, r7, -1	')
+LIMB32(`stwx	r0, r10, rp	')
+LIMB64(`std	r0, 0(rp)	')
+LIMB32(`addi	r10, r10, GMP_LIMB_BYTES')
+LIMB32(`bne	L(top2)		')
+
+L(ret):	mtspr	256, r12
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc32/vmx/logops_n.asm b/third_party/gmp/mpn/powerpc32/vmx/logops_n.asm
new file mode 100644
index 0000000..d656d3b
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc32/vmx/logops_n.asm
@@ -0,0 +1,310 @@
+dnl  PowerPC-32/VMX and PowerPC-64/VMX mpn_and_n, mpn_andn_n, mpn_nand_n,
+dnl  mpn_ior_n, mpn_iorn_n, mpn_nior_n, mpn_xor_n, mpn_xnor_n -- mpn bitwise
+dnl  logical operations.
+
+dnl  Copyright 2006 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C               and,ior,andn,nior,xor    iorn,xnor         nand
+C                   cycles/limb         cycles/limb    cycles/limb
+C 7400,7410 (G4):       1.39                 ?              ?
+C 744x,745x (G4+):      1.14                1.39           1.39
+C 970:                  1.7                 2.0            2.0
+
+C STATUS
+C  * Works for all sizes and alignment for 32-bit limbs.
+C  * Works for n >= 4 for 64-bit limbs; untested for smaller operands.
+C  * Current performance makes this pointless for 970
+
+C TODO
+C  * Might want to make variants when just one of the source operands needs
+C    vperm, and when neither needs it.  The latter runs 50% faster on 7400.
+C  * Idea: If the source operands are equally aligned, we could do the logops
+C    first, then vperm before storing!  That means we never need more than one
+C    vperm, ever!
+C  * Perhaps align `rp' after initial alignment loop?
+C  * Instead of having scalar code in the beginning and end, consider using
+C    read-modify-write vector code.
+C  * Software pipeline?  Hopefully not too important, this is hairy enough
+C    already.
+C  * At least be more clever about operand loading, i.e., load v operands before
+C    u operands, since v operands are sometimes negated.
+
+define(`GMP_LIMB_BYTES', eval(GMP_LIMB_BITS/8))
+define(`LIMBS_PER_VR',  eval(16/GMP_LIMB_BYTES))
+define(`LIMBS_PER_2VR', eval(32/GMP_LIMB_BYTES))
+
+define(`vnegb', `')		C default neg-before to null
+define(`vnega', `')		C default neg-before to null
+
+ifdef(`OPERATION_and_n',
+`	define(`func',	`mpn_and_n')
+	define(`logopS',`and	$1,$2,$3')
+	define(`logop',	`vand	$1,$2,$3')')
+ifdef(`OPERATION_andn_n',
+`	define(`func',	`mpn_andn_n')
+	define(`logopS',`andc	$1,$2,$3')
+	define(`logop',	`vandc	$1,$2,$3')')
+ifdef(`OPERATION_nand_n',
+`	define(`func',	`mpn_nand_n')
+	define(`logopS',`nand	$1,$2,$3')
+	define(`logop',	`vand	$1,$2,$3')
+	define(`vnega',	`vnor	$1,$2,$2')')
+ifdef(`OPERATION_ior_n',
+`	define(`func',	`mpn_ior_n')
+	define(`logopS',`or	$1,$2,$3')
+	define(`logop',	`vor	$1,$2,$3')')
+ifdef(`OPERATION_iorn_n',
+`	define(`func',	`mpn_iorn_n')
+	define(`logopS',`orc	$1,$2,$3')
+	define(`vnegb',	`vnor	$1,$2,$2')
+	define(`logop',	`vor	$1,$2,$3')')
+ifdef(`OPERATION_nior_n',
+`	define(`func',	`mpn_nior_n')
+	define(`logopS',`nor	$1,$2,$3')
+	define(`logop',	`vnor	$1,$2,$3')')
+ifdef(`OPERATION_xor_n',
+`	define(`func',	`mpn_xor_n')
+	define(`logopS',`xor	$1,$2,$3')
+	define(`logop',	`vxor	$1,$2,$3')')
+ifdef(`OPERATION_xnor_n',
+`	define(`func',`mpn_xnor_n')
+	define(`logopS',`eqv	$1,$2,$3')
+	define(`vnegb',	`vnor	$1,$2,$2')
+	define(`logop',	`vxor	$1,$2,$3')')
+
+ifelse(GMP_LIMB_BITS,`32',`
+	define(`LIMB32',`	$1')
+	define(`LIMB64',`')
+',`
+	define(`LIMB32',`')
+	define(`LIMB64',`	$1')
+')
+
+C INPUT PARAMETERS
+define(`rp',	`r3')
+define(`up',	`r4')
+define(`vp',	`r5')
+define(`n',	`r6')
+
+define(`us',	`v8')
+define(`vs',	`v9')
+
+MULFUNC_PROLOGUE(mpn_and_n mpn_andn_n mpn_nand_n mpn_ior_n mpn_iorn_n mpn_nior_n mpn_xor_n mpn_xnor_n)
+
+ASM_START()
+PROLOGUE(func)
+
+LIMB32(`cmpwi	cr0, n, 8	')
+LIMB64(`cmpdi	cr0, n, 4	')
+	bge	L(big)
+
+	mtctr	n
+
+LIMB32(`lwz	r8, 0(up)	')
+LIMB32(`lwz	r9, 0(vp)	')
+LIMB32(`logopS(	r0, r8, r9)	')
+LIMB32(`stw	r0, 0(rp)	')
+LIMB32(`bdz	L(endS)		')
+
+L(topS):
+LIMB32(`lwzu	r8, 4(up)	')
+LIMB64(`ld	r8, 0(up)	')
+LIMB64(`addi	up, up, GMP_LIMB_BYTES	')
+LIMB32(`lwzu	r9, 4(vp)	')
+LIMB64(`ld	r9, 0(vp)	')
+LIMB64(`addi	vp, vp, GMP_LIMB_BYTES	')
+	logopS(	r0, r8, r9)
+LIMB32(`stwu	r0, 4(rp)	')
+LIMB64(`std	r0, 0(rp)	')
+LIMB64(`addi	rp, rp, GMP_LIMB_BYTES	')
+	bdnz	L(topS)
+L(endS):
+	blr
+
+L(big):	mfspr	r12, 256
+	oris	r0, r12, 0xfffc		C Set VRSAVE bit 0-13 FIXME
+	mtspr	256, r0
+
+C First loop until the destination is 16-byte aligned.  This will execute 0 or 1
+C times for 64-bit machines, and 0 to 3 times for 32-bit machines.
+
+LIMB32(`rlwinm.	r0, rp, 30,30,31')	C (rp >> 2) mod 4
+LIMB64(`rlwinm.	r0, rp, 29,31,31')	C (rp >> 3) mod 2
+	beq	L(aligned)
+
+	subfic	r7, r0, LIMBS_PER_VR
+LIMB32(`li	r10, 0		')
+	subf	n, r7, n
+L(top0):
+LIMB32(`lwz	r8, 0(up)	')
+LIMB64(`ld	r8, 0(up)	')
+	addi	up, up, GMP_LIMB_BYTES
+LIMB32(`lwz	r9, 0(vp)	')
+LIMB64(`ld	r9, 0(vp)	')
+	addi	vp, vp, GMP_LIMB_BYTES
+LIMB32(`addic.	r7, r7, -1	')
+	logopS(	r0, r8, r9)
+LIMB32(`stwx	r0, r10, rp	')
+LIMB64(`std	r0, 0(rp)	')
+LIMB32(`addi	r10, r10, GMP_LIMB_BYTES')
+LIMB32(`bne	L(top0)		')
+
+	addi	rp, rp, 16		C update rp, but preserve its alignment
+
+L(aligned):
+LIMB64(`srdi	r7, n, 1	')	C loop count corresponding to n
+LIMB32(`srwi	r7, n, 2	')	C loop count corresponding to n
+	mtctr	r7			C copy n to count register
+
+	li	r10, 16
+	lvsl	us, 0, up
+	lvsl	vs, 0, vp
+
+	lvx	v2, 0, up
+	lvx	v3, 0, vp
+	bdnz	L(gt1)
+	lvx	v0, r10, up
+	lvx	v1, r10, vp
+	vperm	v4, v2, v0, us
+	vperm	v5, v3, v1, vs
+	vnegb(	v5, v5)
+	logop(	v6, v4, v5)
+	vnega(	v6, v6)
+	stvx	v6, 0, rp
+	addi	up, up, 16
+	addi	vp, vp, 16
+	addi	rp, rp, 4
+	b	L(tail)
+
+L(gt1):	addi	up, up, 16
+	addi	vp, vp, 16
+
+L(top):	lvx	v0, 0, up
+	lvx	v1, 0, vp
+	vperm	v4, v2, v0, us
+	vperm	v5, v3, v1, vs
+	vnegb(	v5, v5)
+	logop(	v6, v4, v5)
+	vnega(	v6, v6)
+	stvx	v6, 0, rp
+	bdz	L(end)
+	lvx	v2, r10, up
+	lvx	v3, r10, vp
+	vperm	v4, v0, v2, us
+	vperm	v5, v1, v3, vs
+	vnegb(	v5, v5)
+	logop(	v6, v4, v5)
+	vnega(	v6, v6)
+	stvx	v6, r10, rp
+	addi	up, up, 32
+	addi	vp, vp, 32
+	addi	rp, rp, 32
+	bdnz	L(top)
+
+	andi.	r0, up, 15
+	vxor	v0, v0, v0
+	beq	1f
+	lvx	v0, 0, up
+1:	andi.	r0, vp, 15
+	vxor	v1, v1, v1
+	beq	1f
+	lvx	v1, 0, vp
+1:	vperm	v4, v2, v0, us
+	vperm	v5, v3, v1, vs
+	vnegb(	v5, v5)
+	logop(	v6, v4, v5)
+	vnega(	v6, v6)
+	stvx	v6, 0, rp
+	addi	rp, rp, 4
+	b	L(tail)
+
+L(end):	andi.	r0, up, 15
+	vxor	v2, v2, v2
+	beq	1f
+	lvx	v2, r10, up
+1:	andi.	r0, vp, 15
+	vxor	v3, v3, v3
+	beq	1f
+	lvx	v3, r10, vp
+1:	vperm	v4, v0, v2, us
+	vperm	v5, v1, v3, vs
+	vnegb(	v5, v5)
+	logop(	v6, v4, v5)
+	vnega(	v6, v6)
+	stvx	v6, r10, rp
+
+	addi	up, up, 16
+	addi	vp, vp, 16
+	addi	rp, rp, 20
+
+L(tail):
+LIMB32(`rlwinm.	r7, n, 0,30,31	')	C r7 = n mod 4
+LIMB64(`rlwinm.	r7, n, 0,31,31	')	C r7 = n mod 2
+	beq	L(ret)
+	addi	rp, rp, 15
+LIMB32(`rlwinm	rp, rp, 0,0,27	')
+LIMB64(`rldicr	rp, rp, 0,59	')
+	li	r10, 0
+L(top2):
+LIMB32(`lwzx	r8, r10, up	')
+LIMB64(`ldx	r8, r10, up	')
+LIMB32(`lwzx	r9, r10, vp	')
+LIMB64(`ldx	r9, r10, vp	')
+LIMB32(`addic.	r7, r7, -1	')
+	logopS(	r0, r8, r9)
+LIMB32(`stwx	r0, r10, rp	')
+LIMB64(`std	r0, 0(rp)	')
+LIMB32(`addi	r10, r10, GMP_LIMB_BYTES')
+LIMB32(`bne	L(top2)		')
+
+L(ret):	mtspr	256, r12
+	blr
+EPILOGUE()
+
+C This works for 64-bit PowerPC, since a limb ptr can only be aligned
+C in 2 relevant ways, which means we can always find a pair of aligned
+C pointers of rp, up, and vp.
+C process words until rp is 16-byte aligned
+C if (((up | vp) & 15) == 0)
+C   process with VMX without any vperm
+C else if ((up & 15) != 0 && (vp & 15) != 0)
+C   process with VMX using vperm on store data
+C else if ((up & 15) != 0)
+C   process with VMX using vperm on up data
+C else
+C   process with VMX using vperm on vp data
+C
+C	rlwinm,	r0, up, 0,28,31
+C	rlwinm	r0, vp, 0,28,31
+C	cmpwi	cr7, r0, 0
+C	cror	cr6, cr0, cr7
+C	crand	cr0, cr0, cr7
diff --git a/third_party/gmp/mpn/powerpc32/vmx/mod_34lsub1.asm b/third_party/gmp/mpn/powerpc32/vmx/mod_34lsub1.asm
new file mode 100644
index 0000000..2bb11cd
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc32/vmx/mod_34lsub1.asm
@@ -0,0 +1,388 @@
+dnl  PowerPC-32 mpn_mod_34lsub1 -- mpn remainder mod 2^24-1.
+
+dnl  Copyright 2002, 2003, 2005-2007, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+
+C                cycles/limb
+C 603e:              -
+C 604e:              -
+C 75x (G3):          -
+C 7400,7410 (G4):    1          simple load-use scheduling results in 0.75
+C 744x,745x (G4+):   0.75
+C ppc970:            0.75
+C power4:            -
+C power5:            -
+
+C TODO
+C  * Either start using the low-end masking constants, or remove them.
+C  * Merge multiple feed-in cases into a parameterized code block.
+C  * Reduce register usage.  It should be possible to almost halve it.
+
+define(`up', `r3')
+define(`n', `r4')
+
+define(`a0', `v3')
+define(`a1', `v4')
+define(`a2', `v5')
+define(`c0', `v6')
+define(`c1', `v7')
+define(`c2', `v8')
+define(`z',  `v9')
+define(`x0', `v10')
+define(`x1', `v11')
+define(`x2', `v12')
+define(`x3', `v13')
+define(`pv', `v14')
+define(`y0', `v0')
+define(`y1', `v1')
+define(`y2', `v2')
+define(`y3', `v15')
+
+ASM_START()
+PROLOGUE(mpn_mod_34lsub1)
+	cmpwi	cr0, n, 20		C tuned cutoff point
+	bge	L(large)
+
+	li	r9, 0			C result accumulator
+	mulli	r10, n, 0xb		C 0xb = ceil(32/3)
+	srwi.	r10, r10, 5		C r10 = floor(n/3), n < 32
+	beq	L(small_tail)
+	mtctr	r10
+	lwz	r6, 0(up)
+	lwz	r7, 4(up)
+	lwzu	r8, 8(up)
+	subf	n, r10, n
+	subf	n, r10, n
+	subf	n, r10, n
+	bdz	L(small_end)
+
+	ALIGN(16)
+L(los):	rlwinm	r0, r6, 0,8,31
+	add	r9, r9, r0		C add 24b from u0
+	srwi	r0, r6, 24
+	lwz	r6, 4(up)
+	rlwimi	r0, r7, 8, 0x00ffff00	C --111100
+	add	r9, r9, r0		C add 8b from u0 and 16b from u1
+	srwi	r0, r7, 16
+	lwz	r7, 8(up)
+	rlwimi	r0, r8, 16, 0x00ff0000	C --221111
+	add	r9, r9, r0		C add 16b from u1 and 8b from u2
+	srwi	r0, r8, 8		C --222222
+	lwzu	r8, 12(up)
+	add	r9, r9, r0		C add 24b from u2
+	bdnz	L(los)
+L(small_end):
+	rlwinm	r0, r6, 0,8,31
+	add	r9, r9, r0		C add 24b from u0
+	srwi	r0, r6, 24
+	rlwimi	r0, r7, 8, 0x00ffff00	C --111100
+	add	r9, r9, r0		C add 8b from u0 and 16b from u1
+	srwi	r0, r7, 16
+	rlwimi	r0, r8, 16, 0x00ff0000	C --221111
+	add	r9, r9, r0		C add 16b from u1 and 8b from u2
+	srwi	r0, r8, 8		C --222222
+	add	r9, r9, r0		C add 24b from u2
+
+	addi	up, up, 4
+	rlwinm	r0, r9, 0,8,31
+	srwi	r9, r9, 24
+	add	r9, r9, r0
+
+L(small_tail):
+	cmpi	cr0, n, 1
+	blt	L(ret)
+
+	lwz	r6, 0(up)
+	rlwinm	r0, r6, 0,8,31
+	srwi	r6, r6, 24
+	add	r9, r9, r0
+	add	r9, r9, r6
+
+	beq	L(ret)
+
+	lwz	r6, 4(up)
+	rlwinm	r0, r6, 8,8,23
+	srwi	r6, r6, 16
+	add	r9, r9, r0
+	add	r9, r9, r6
+
+L(ret):	mr	r3, r9
+	blr
+
+
+L(large):
+	stwu	r1, -32(r1)
+	mfspr	r10, 256
+	oris	r0, r10, 0xffff		C Set VRSAVE bit 0-15
+	mtspr	256, r0
+
+	andi.	r7, up, 15
+	vxor	a0, v0, v0
+	lis	r9, 0xaaaa
+	vxor	a1, v0, v0
+	ori	r9, r9, 0xaaab
+	vxor	a2, v0, v0
+	li	r5, 16
+	vxor	c0, v0, v0
+	li	r6, 32
+	vxor	c1, v0, v0
+	LEAL(	r11, cnsts)		C CAUTION clobbers r0 for elf, darwin
+	vxor	c2, v0, v0
+	vxor	z, v0, v0
+
+	beq	L(aligned16)
+
+	cmpwi	cr7, r7, 8
+	bge	cr7, L(na4)
+
+	lvx	a2, 0, up
+	addi	up, up, 16
+	vsldoi	a2, a2, z, 4
+	vsldoi	a2, z, a2, 12
+
+	addi	n, n, 9
+	mulhwu	r0, n, r9
+	srwi	r0, r0, 3		C r0 = floor(n/12)
+	mtctr	r0
+
+	mulli	r8, r0, 12
+	subf	n, r8, n
+	b	L(2)
+
+L(na4):	bne	cr7, L(na8)
+
+	lvx	a1, 0, up
+	addi	up, up, -16
+	vsldoi	a1, a1, z, 8
+	vsldoi	a1, z, a1, 8
+
+	addi	n, n, 6
+	mulhwu	r0, n, r9
+	srwi	r0, r0, 3		C r0 = floor(n/12)
+	mtctr	r0
+
+	mulli	r8, r0, 12
+	subf	n, r8, n
+	b	L(1)
+
+L(na8):
+	lvx	a0, 0, up
+	vsldoi	a0, a0, z, 12
+	vsldoi	a0, z, a0, 4
+
+	addi	n, n, 3
+	mulhwu	r0, n, r9
+	srwi	r0, r0, 3		C r0 = floor(n/12)
+	mtctr	r0
+
+	mulli	r8, r0, 12
+	subf	n, r8, n
+	b	L(0)
+
+L(aligned16):
+	mulhwu	r0, n, r9
+	srwi	r0, r0, 3		C r0 = floor(n/12)
+	mtctr	r0
+
+	mulli	r8, r0, 12
+	subf	n, r8, n
+
+	lvx	a0, 0, up
+L(0):	lvx	a1, r5, up
+L(1):	lvx	a2, r6, up
+	addi	up, up, 48
+L(2):	bdz	L(end)
+	li	r12, 256
+	li	r9, 288
+	ALIGN(32)
+L(top):
+	lvx	v0, 0, up
+	vaddcuw	v10, a0, v0
+	vadduwm	a0, a0, v0
+	vadduwm	c0, c0, v10
+
+	lvx	v1, r5, up
+	vaddcuw	v10, a1, v1
+	vadduwm	a1, a1, v1
+	vadduwm	c1, c1, v10
+
+	lvx	v2, r6, up
+	dcbt	up, r12
+	dcbt	up, r9
+	addi	up, up, 48
+	vaddcuw	v10, a2, v2
+	vadduwm	a2, a2, v2
+	vadduwm	c2, c2, v10
+	bdnz	L(top)
+
+L(end):
+C n = 0...11
+	cmpwi	cr0, n, 0
+	beq	L(sum)
+	cmpwi	cr0, n, 4
+	ble	L(tail.1..4)
+	cmpwi	cr0, n, 8
+	ble	L(tail.5..8)
+
+L(tail.9..11):
+	lvx	v0, 0, up
+	vaddcuw	v10, a0, v0
+	vadduwm	a0, a0, v0
+	vadduwm	c0, c0, v10
+
+	lvx	v1, r5, up
+	vaddcuw	v10, a1, v1
+	vadduwm	a1, a1, v1
+	vadduwm	c1, c1, v10
+
+	lvx	v2, r6, up
+
+	addi	r8, r11, 96
+	rlwinm	r3, n ,4,26,27
+	lvx	v11, r3, r8
+	vand	v2, v2, v11
+
+	vaddcuw	v10, a2, v2
+	vadduwm	a2, a2, v2
+	vadduwm	c2, c2, v10
+	b	L(sum)
+
+L(tail.5..8):
+	lvx	v0, 0, up
+	vaddcuw	v10, a0, v0
+	vadduwm	a0, a0, v0
+	vadduwm	c0, c0, v10
+
+	lvx	v1, r5, up
+
+	addi	r8, r11, 96
+	rlwinm	r3, n ,4,26,27
+	lvx	v11, r3, r8
+	vand	v1, v1, v11
+
+	vaddcuw	v10, a1, v1
+	vadduwm	a1, a1, v1
+	vadduwm	c1, c1, v10
+	b	L(sum)
+
+L(tail.1..4):
+	lvx	v0, 0, up
+
+	addi	r8, r11, 96
+	rlwinm	r3, n ,4,26,27
+	lvx	v11, r3, r8
+	vand	v0, v0, v11
+
+	vaddcuw	v10, a0, v0
+	vadduwm	a0, a0, v0
+	vadduwm	c0, c0, v10
+
+L(sum):	lvx	pv, 0, r11
+	vperm	x0, a0, z, pv		C extract 4 24-bit field from a0
+	vperm	y0, c2, z, pv
+	lvx	pv, r5, r11
+	vperm	x1, a1, z, pv		C extract 4 24-bit field from a1
+	vperm	y1, c0, z, pv		C extract 4 24-bit field from a1
+	lvx	pv, r6, r11
+	vperm	x2, a2, z, pv		C extract 4 24-bit field from a1
+	vperm	y2, c1, z, pv		C extract 4 24-bit field from a1
+	li	r10,  48
+	lvx	pv, r10, r11
+	vperm	x3, a0, z, pv		C extract remaining/partial a0 fields
+	vperm	y3, c2, z, pv		C extract remaining/partial a0 fields
+	li	r10,  64
+	lvx	pv, r10, r11
+	vperm	x3, a1, x3, pv		C insert remaining/partial a1 fields
+	vperm	y3, c0, y3, pv		C insert remaining/partial a1 fields
+	li	r10,  80
+	lvx	pv, r10, r11
+	vperm	x3, a2, x3, pv		C insert remaining/partial a2 fields
+	vperm	y3, c1, y3, pv		C insert remaining/partial a2 fields
+
+C We now have 4 128-bit accumulators to sum
+	vadduwm	x0, x0, x1
+	vadduwm	x2, x2, x3
+	vadduwm	x0, x0, x2
+
+	vadduwm	y0, y0, y1
+	vadduwm	y2, y2, y3
+	vadduwm	y0, y0, y2
+
+	vadduwm	x0, x0, y0
+
+C Reduce 32-bit fields
+	vsumsws	x0, x0, z
+
+	li	r7, 16
+	stvx	x0, r7, r1
+	lwz	r3, 28(r1)
+
+	mtspr	256, r10
+	addi	r1, r1, 32
+	blr
+EPILOGUE()
+
+C load	|      v0       |      v1       |      v2       |
+C acc	|      a0       |      a1       |      a2       |
+C carry	|      c0       |      c1       |      c2       |
+C	| 0   1   2   3 | 4   5   6   7 | 8   9  10  11 |  128
+C	|---|---|---|---|---|---|---|---|---|---|---|---|   32
+C	|  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |   24
+C	|     |     |     |     |     |     |     |     |   48
+
+C       $---------------$---------------$---------------$---------------$
+C       |   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   |
+C       |_______________________________________________________________|
+C   |           |           |           |           |           |           |
+C       <-hi16-> <--- 24 --> <--- 24 --> <--- 24 --> <--- 24 --> <-lo16->
+
+
+DEF_OBJECT(cnsts,16)
+C Permutation vectors in the order they are used above
+C #      00   01   02   03    04   05   06   07    08   09   0a   0b    0c   0d   0e   0f
+ .byte 0x10,0x01,0x02,0x03, 0x10,0x06,0x07,0x00, 0x10,0x0b,0x04,0x05, 0x10,0x08,0x09,0x0a C a0
+ .byte 0x10,0x07,0x00,0x01, 0x10,0x04,0x05,0x06, 0x10,0x09,0x0a,0x0b, 0x10,0x0e,0x0f,0x08 C a1
+ .byte 0x10,0x00,0x01,0x02, 0x10,0x05,0x06,0x07, 0x10,0x0a,0x0b,0x04, 0x10,0x0f,0x08,0x09 C a2
+ .byte 0x10,0x0d,0x0e,0x0f, 0x10,0x10,0x10,0x0c, 0x10,0x10,0x10,0x10, 0x10,0x10,0x10,0x10 C part a0
+ .byte 0x10,0x11,0x12,0x13, 0x10,0x02,0x03,0x17, 0x10,0x10,0x0c,0x0d, 0x10,0x10,0x10,0x10 C part a1
+ .byte 0x10,0x11,0x12,0x13, 0x10,0x15,0x16,0x17, 0x10,0x03,0x1a,0x1b, 0x10,0x0c,0x0d,0x0e C part a2
+C Masks for high end of number
+ .byte 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
+ .byte 0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ .byte 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ .byte 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00
+C Masks for low end of number
+C .byte	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
+C .byte	0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
+C .byte	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
+C .byte	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff
+END_OBJECT(cnsts)
diff --git a/third_party/gmp/mpn/powerpc32/vmx/popcount.asm b/third_party/gmp/mpn/powerpc32/vmx/popcount.asm
new file mode 100644
index 0000000..943c92d
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc32/vmx/popcount.asm
@@ -0,0 +1,34 @@
+dnl  PowerPC-32/VMX mpn_popcount.
+
+dnl  Copyright 2006 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+MULFUNC_PROLOGUE(mpn_popcount)
+include_mpn(`powerpc64/vmx/popcount.asm')
diff --git a/third_party/gmp/mpn/powerpc64/README b/third_party/gmp/mpn/powerpc64/README
new file mode 100644
index 0000000..50dd399
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/README
@@ -0,0 +1,166 @@
+Copyright 1999-2001, 2003-2005 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.
+
+
+
+                    POWERPC-64 MPN SUBROUTINES
+
+
+This directory contains mpn functions for 64-bit PowerPC chips.
+
+
+CODE ORGANIZATION
+
+	mpn/powerpc64          mode-neutral code
+	mpn/powerpc64/mode32   code for mode32
+	mpn/powerpc64/mode64   code for mode64
+
+
+The mode32 and mode64 sub-directories contain code which is for use in the
+respective chip mode, 32 or 64.  The top-level directory is code that's
+unaffected by the mode.
+
+The "adde" instruction is the main difference between mode32 and mode64.  It
+operates on either on a 32-bit or 64-bit quantity according to the chip mode.
+Other instructions have an operand size in their opcode and hence don't vary.
+
+
+
+POWER3/PPC630 pipeline information:
+
+Decoding is 4-way + branch and issue is 8-way with some out-of-order
+capability.
+
+Functional units:
+LS1  - ld/st unit 1
+LS2  - ld/st unit 2
+FXU1 - integer unit 1, handles any simple integer instruction
+FXU2 - integer unit 2, handles any simple integer instruction
+FXU3 - integer unit 3, handles integer multiply and divide
+FPU1 - floating-point unit 1
+FPU2 - floating-point unit 2
+
+Memory:		  Any two memory operations can issue, but memory subsystem
+		  can sustain just one store per cycle.  No need for data
+		  prefetch; the hardware has very sophisticated prefetch logic.
+Simple integer:	  2 operations (such as add, rl*)
+Integer multiply: 1 operation every 9th cycle worst case; exact timing depends
+		  on 2nd operand's most significant bit position (10 bits per
+		  cycle).  Multiply unit is not pipelined, only one multiply
+		  operation in progress is allowed.
+Integer divide:	  ?
+Floating-point:	  Any plain 2 arithmetic instructions (such as fmul, fadd, and
+		  fmadd), latency 4 cycles.
+Floating-point divide:
+		  ?
+Floating-point square root:
+		  ?
+
+POWER3/PPC630 best possible times for the main loops:
+shift:	      1.5 cycles limited by integer unit contention.
+	      With 63 special loops, one for each shift count, we could
+	      reduce the needed integer instructions to 2, which would
+	      reduce the best possible time to 1 cycle.
+add/sub:      1.5 cycles, limited by ld/st unit contention.
+mul:	      18 cycles (average) unless floating-point operations are used,
+	      but that would only help for multiplies of perhaps 10 and more
+	      limbs.
+addmul/submul:Same situation as for mul.
+
+
+POWER4/PPC970 and POWER5 pipeline information:
+
+This is a very odd pipeline, it is basically a VLIW masquerading as a plain
+architecture.  Its issue rules are not made public, and since it is so weird,
+it is very hard to figure out any useful information from experimentation.
+An example:
+
+  A well-aligned loop with nop's take 3, 4, 6, 7, ... cycles.
+    3 cycles for  0,  1,  2,  3,  4,  5,  6,  7 nop's
+    4 cycles for  8,  9, 10, 11, 12, 13, 14, 15 nop's
+    6 cycles for 16, 17, 18, 19, 20, 21, 22, 23 nop's
+    7 cycles for 24, 25, 26, 27 nop's
+    8 cycles for 28, 29, 30, 31 nop's
+    ... continues regularly
+
+
+Functional units:
+LS1  - ld/st unit 1
+LS2  - ld/st unit 2
+FXU1 - integer unit 1, handles any integer instruction
+FXU2 - integer unit 2, handles any integer instruction
+FPU1 - floating-point unit 1
+FPU2 - floating-point unit 2
+
+While this is one integer unit less than POWER3/PPC630, the remaining units
+are more powerful; here they handle multiply and divide.
+
+Memory:		  2 ld/st.  Stores go to the L2 cache, which can sustain just
+		  one store per cycle.
+		  L1 load latency: to gregs 3-4 cycles, to fregs 5-6 cycles.
+		  Operations that modify the address register might be split
+		  to use also an integer issue slot.
+Simple integer:	  2 operations every cycle, latency 2.
+Integer multiply: 2 operations every 6th cycle, latency 7 cycles.
+Integer divide:	  ?
+Floating-point:	  Any plain 2 arithmetic instructions (such as fmul, fadd, and
+		  fmadd), latency 6 cycles.
+Floating-point divide:
+		  ?
+Floating-point square root:
+		  ?
+
+
+IDEAS
+
+*mul_1: Handling one limb using mulld/mulhdu and two limbs using floating-
+point operations should give performance of about 20 cycles for 3 limbs, or 7
+cycles/limb.
+
+We should probably split the single-limb operand in 32-bit chunks, and the
+multi-limb operand in 16-bit chunks, allowing us to accumulate well in fp
+registers.
+
+Problem is to get 32-bit or 16-bit words to the fp registers.  Only 64-bit fp
+memops copies bits without fiddling with them.  We might therefore need to
+load to integer registers with zero extension, store as 64 bits into temp
+space, and then load to fp regs.  Alternatively, load directly to fp space
+and add well-chosen constants to get cancellation.  (Other part after given by
+subsequent subtraction.)
+
+Possible code mix for load-via-intregs variant:
+
+lwz,std,lfd
+fmadd,fmadd,fmul,fmul
+fctidz,stfd,ld,fctidz,stfd,ld
+add,adde
+lwz,std,lfd
+fmadd,fmadd,fmul,fmul
+fctidz,stfd,ld,fctidz,stfd,ld
+add,adde
+srd,sld,add,adde,add,adde
diff --git a/third_party/gmp/mpn/powerpc64/aix.m4 b/third_party/gmp/mpn/powerpc64/aix.m4
new file mode 100644
index 0000000..04378b8
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/aix.m4
@@ -0,0 +1,99 @@
+divert(-1)
+dnl  m4 macros for AIX 64-bit assembly.
+
+dnl  Copyright 2000-2002, 2005, 2006, 2010, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+define(`AIX')
+
+define(`ASM_START',
+	`.machine	"any"
+	.toc')
+
+dnl  Called: PROLOGUE_cpu(GSYM_PREFIX`'foo[,toc])
+dnl          EPILOGUE_cpu(GSYM_PREFIX`'foo)
+dnl
+dnl  Don't want ELF style .size in the epilogue.
+
+define(`PROLOGUE_cpu',
+m4_assert_numargs_range(1,2)
+`ifelse(`$2',toc,,
+`ifelse(`$2',,,`m4_error(`Unrecognised PROLOGUE parameter')')')dnl
+	.globl	$1
+	.globl	.$1
+	.csect	[DS], 3
+$1:
+	.llong	.$1, TOC[tc0], 0
+	.csect	.$1[PR], 6
+.$1:')
+
+define(`EPILOGUE_cpu',
+m4_assert_numargs(1)
+`')
+
+define(`TOC_ENTRY', `')
+
+define(`LEA',
+m4_assert_numargs(2)
+`define(`TOC_ENTRY',
+`	.toc
+..$2:	.tc	$2[TC], $2')'
+	`ld	$1, ..$2(2)')
+
+define(`LEAL',
+m4_assert_numargs(2)
+`LEA($1,$2)')
+
+
+define(`EXTERN',
+m4_assert_numargs(1)
+`	.globl	$1')
+
+define(`EXTERN_FUNC',
+m4_assert_numargs(1)
+`	.globl	.$1')
+
+define(`DEF_OBJECT',
+m4_assert_numargs_range(1,2)
+`	.csect	[RO], 3
+	ALIGN(ifelse($#,1,2,$2))
+$1:
+')
+
+define(`END_OBJECT',
+m4_assert_numargs(1))
+
+define(`CALL',
+	`bl	.$1
+	nop')
+
+define(`ASM_END', `TOC_ENTRY')
+
+undefine(`EXTRA_REGISTER')
+
+divert
diff --git a/third_party/gmp/mpn/powerpc64/com.asm b/third_party/gmp/mpn/powerpc64/com.asm
new file mode 100644
index 0000000..074b7ff
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/com.asm
@@ -0,0 +1,136 @@
+dnl  PowerPC-64 mpn_com.
+
+dnl  Copyright 2004, 2005, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                  cycles/limb
+C POWER3/PPC630          ?
+C POWER4/PPC970          1.25
+C POWER5                 ?
+C POWER6                 1.32
+C POWER7                 1.13
+
+C INPUT PARAMETERS
+define(`rp',	`r3')
+define(`up',	`r4')
+define(`n',	`r5')
+
+ASM_START()
+PROLOGUE(mpn_com)
+
+ifdef(`HAVE_ABI_mode32',
+`	rldicl	n, n, 0,32')
+
+	cmpdi	cr0, n, 4
+	blt	L(sml)
+
+	addi	r10, n, 4
+	srdi	r10, r10, 3
+	mtctr	r10
+
+	andi.	r0, n, 1
+	rlwinm	r11, n, 0,30,30
+	rlwinm	r12, n, 0,29,29
+	cmpdi	cr6, r11, 0
+	cmpdi	cr7, r12, 0
+
+	beq	cr0, L(xx0)
+L(xx1):	ld	r6, 0(up)
+	addi	up, up, 8
+	nor	r6, r6, r6
+	std	r6, 0(rp)
+	addi	rp, rp, 8
+
+L(xx0):	bne	cr6, L(x10)
+L(x00):	ld	r6, 0(r4)
+	ld	r7, 8(r4)
+	bne	cr7, L(100)
+L(000):	addi	rp, rp, -32
+	b	L(lo0)
+L(100):	addi	up, up, -32
+	b	L(lo4)
+L(x10):	ld	r8, 0(r4)
+	ld	r9, 8(r4)
+	bne	cr7, L(110)
+L(010):	addi	up, up, 16
+	addi	rp, rp, -16
+	b	L(lo2)
+L(110):	addi	up, up, -16
+	addi	rp, rp, -48
+	b	L(lo6)
+
+L(sml):	mtctr	n
+L(t):	ld	r6, 0(up)
+	addi	up, up, 8
+	nor	r6, r6, r6
+	std	r6, 0(rp)
+	addi	rp, rp, 8
+	bdnz	L(t)
+	blr
+
+	ALIGN(32)
+L(top):	nor	r6, r6, r6
+	nor	r7, r7, r7
+	std	r6, 0(rp)
+	std	r7, 8(rp)
+L(lo2):	ld	r6, 0(up)
+	ld	r7, 8(up)
+	nor	r8, r8, r8
+	nor	r9, r9, r9
+	std	r8, 16(rp)
+	std	r9, 24(rp)
+L(lo0):	ld	r8, 16(up)
+	ld	r9, 24(up)
+	nor	r6, r6, r6
+	nor	r7, r7, r7
+	std	r6, 32(rp)
+	std	r7, 40(rp)
+L(lo6):	ld	r6, 32(up)
+	ld	r7, 40(up)
+	nor	r8, r8, r8
+	nor	r9, r9, r9
+	std	r8, 48(rp)
+	std	r9, 56(rp)
+	addi	rp, rp, 64
+L(lo4):	ld	r8, 48(up)
+	ld	r9, 56(up)
+	addi	up, up, 64
+	bdnz	L(top)
+
+L(end):	nor	r6, r6, r6
+	nor	r7, r7, r7
+	std	r6, 0(rp)
+	std	r7, 8(rp)
+	nor	r8, r8, r8
+	nor	r9, r9, r9
+	std	r8, 16(rp)
+	std	r9, 24(rp)
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc64/copyd.asm b/third_party/gmp/mpn/powerpc64/copyd.asm
new file mode 100644
index 0000000..c6ce930
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/copyd.asm
@@ -0,0 +1,84 @@
+dnl  PowerPC-64 mpn_copyd
+
+dnl  Copyright 2004, 2005 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                  cycles/limb
+C POWER3/PPC630          1
+C POWER4/PPC970          1
+C POWER5                 ?
+C POWER6                 ?
+C POWER7                 1.4
+
+C INPUT PARAMETERS
+C rp	r3
+C up	r4
+C n	r5
+
+ASM_START()
+PROLOGUE(mpn_copyd)
+	rldic.	r0, r5, 3, 59	C r0 = (r5 & 3) << 3; cr0 = (n == 4t)?
+	cmpldi	cr6, r0, 16	C cr6 = (n cmp 4t + 2)?
+
+ifdef(`HAVE_ABI_mode32',
+`	rldic	r6, r5, 3, 32',	C byte count corresponding to n
+`	rldicr	r6, r5, 3, 60')	C byte count corresponding to n
+
+	addi	r5, r5, 4	C compute...
+ifdef(`HAVE_ABI_mode32',
+`	rldicl	r5, r5, 62,34',	C ...branch count
+`	rldicl	r5, r5, 62, 2')	C ...branch count
+	mtctr	r5
+
+	add	r4, r4, r6
+	add	r3, r3, r6
+	sub	r4, r4, r0	C offset up
+	sub	r3, r3, r0	C offset rp
+
+	beq	cr0, L(L00)
+	blt	cr6, L(L01)
+	beq	cr6, L(L10)
+	b	L(L11)
+
+	ALIGN(16)
+L(oop):	ld	r6, 24(r4)
+	std	r6, 24(r3)
+L(L11):	ld	r6, 16(r4)
+	std	r6, 16(r3)
+L(L10):	ld	r6, 8(r4)
+	std	r6, 8(r3)
+L(L01):	ld	r6, 0(r4)
+	std	r6, 0(r3)
+L(L00):	addi	r4, r4, -32
+	addi	r3, r3, -32
+	bdnz	L(oop)
+
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc64/copyi.asm b/third_party/gmp/mpn/powerpc64/copyi.asm
new file mode 100644
index 0000000..9a86cb2
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/copyi.asm
@@ -0,0 +1,78 @@
+dnl  PowerPC-64 mpn_copyi.
+
+dnl  Copyright 2004, 2005 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                  cycles/limb
+C POWER3/PPC630          1
+C POWER4/PPC970          1
+C POWER5                 ?
+C POWER6                 ?
+C POWER7                 1.4
+
+C INPUT PARAMETERS
+C rp	r3
+C up	r4
+C n	r5
+
+ASM_START()
+PROLOGUE(mpn_copyi)
+	rldic.	r0, r5, 3, 59	C r0 = (r5 & 3) << 3; cr0 = (n == 4t)?
+	cmpldi	cr6, r0, 16	C cr6 = (n cmp 4t + 2)?
+
+	addi	r5, r5, 4	C compute...
+ifdef(`HAVE_ABI_mode32',
+`	rldicl	r5, r5, 62,34',	C ...branch count
+`	rldicl	r5, r5, 62, 2')	C ...branch count
+	mtctr	r5
+
+	add	r4, r4, r0	C offset up
+	add	r3, r3, r0	C offset rp
+
+	beq	cr0, L(L00)
+	blt	cr6, L(L01)
+	beq	cr6, L(L10)
+	b	L(L11)
+
+	ALIGN(16)
+L(oop):	ld	r6, -32(r4)
+	std	r6, -32(r3)
+L(L11):	ld	r6, -24(r4)
+	std	r6, -24(r3)
+L(L10):	ld	r6, -16(r4)
+	std	r6, -16(r3)
+L(L01):	ld	r6, -8(r4)
+	std	r6, -8(r3)
+L(L00):	addi	r4, r4, 32
+	addi	r3, r3, 32
+	bdnz	L(oop)
+
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc64/darwin.m4 b/third_party/gmp/mpn/powerpc64/darwin.m4
new file mode 100644
index 0000000..2c995e7
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/darwin.m4
@@ -0,0 +1,122 @@
+divert(-1)
+dnl  m4 macros for Mac OS 64-bit assembly.
+
+dnl  Copyright 2005, 2006 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+define(`DARWIN')
+
+define(`ASM_START',`')
+
+dnl  Called: PROLOGUE_cpu(GSYM_PREFIX`'foo[,toc])
+dnl          EPILOGUE_cpu(GSYM_PREFIX`'foo)
+dnl
+
+define(`PROLOGUE_cpu',
+m4_assert_numargs_range(1,2)
+`ifelse(`$2',toc,,
+`ifelse(`$2',,,`m4_error(`Unrecognised PROLOGUE parameter')')')dnl
+	.text
+	.globl	$1
+	.align	5
+$1:')
+
+define(`lea_list', `')
+
+dnl  LEAL -- Load Effective Address Local.  This is to be used for symbols
+dnl  defined in the same file.  It will not work for externally defined
+dnl  symbols.
+
+define(`LEAL',
+m4_assert_numargs(2)
+`ifdef(`PIC',
+`
+	mflr	r0			C save return address
+	bcl	20, 31, 1f
+1:	mflr	$1
+	addis	$1, $1, ha16($2-1b)
+	la	$1, lo16($2-1b)($1)
+	mtlr	r0			C restore return address
+',`
+	lis	$1, ha16($2)
+	la	$1, lo16($2)($1)
+')')
+
+dnl  LEA -- Load Effective Address.  This is to be used for symbols defined in
+dnl  another file.  It will not work for locally defined symbols.
+
+define(`LEA',
+m4_assert_numargs(2)
+`ifdef(`PIC',
+`define(`lea_list',
+`	.non_lazy_symbol_pointer
+`L'$2`'$non_lazy_ptr:
+	.indirect_symbol $2
+	.quad	0
+')
+	mflr	r0			C save return address
+	bcl	20, 31, 1f
+1:	mflr	$1
+	addis	$1, $1, ha16(`L'$2`'$non_lazy_ptr-1b)
+	ld	$1, lo16(`L'$2`'$non_lazy_ptr-1b)($1)
+	mtlr	r0			C restore return address
+',`
+	lis	$1, ha16($2)
+	la	$1, lo16($2)($1)
+')')
+
+define(`EXTERN',
+m4_assert_numargs(1)
+`dnl')
+
+define(`EXTERN_FUNC',
+m4_assert_numargs(1)
+`dnl')
+
+define(`DEF_OBJECT',
+m4_assert_numargs_range(1,2)
+`	.const
+	ALIGN(ifelse($#,1,2,$2))
+$1:
+')
+
+define(`END_OBJECT',
+m4_assert_numargs(1))
+
+define(`CALL',
+	`bl	GSYM_PREFIX`'$1')
+
+define(`EPILOGUE_cpu',
+`lea_list'
+`define(`lea_list', `')')
+
+define(`ASM_END', `dnl')
+
+define(`EXTRA_REGISTER', r2)
+
+divert
diff --git a/third_party/gmp/mpn/powerpc64/elf.m4 b/third_party/gmp/mpn/powerpc64/elf.m4
new file mode 100644
index 0000000..ddb5a8e
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/elf.m4
@@ -0,0 +1,123 @@
+divert(-1)
+dnl  m4 macros for powerpc64 GNU/Linux assembly.
+
+dnl  Copyright 2003, 2005, 2006 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+define(`ASM_START',
+`ifdef(`ELFv2_ABI',
+`
+	.abiversion 2
+')')
+
+dnl  Called: PROLOGUE_cpu(GSYM_PREFIX`'foo[,toc])
+dnl          EPILOGUE_cpu(GSYM_PREFIX`'foo)
+dnl
+
+define(`PROLOGUE_cpu',
+m4_assert_numargs_range(1,2)
+`ifelse(`$2',toc,,
+`ifelse(`$2',,,`m4_error(`Unrecognised PROLOGUE parameter')')')dnl
+ifdef(`ELFv2_ABI',
+`
+	.globl	$1
+	.type	$1, @function
+	.section	".text"
+	.align	5
+$1:
+ifelse(`$2',toc,`
+0:	addis	2, 12, (.TOC.-0b)@ha
+	addi	2, 2, (.TOC.-0b)@l
+	.localentry $1, .-$1
+',)
+',`
+	.globl	$1
+	.globl	.$1
+	.section	".opd","aw"
+	.align	3
+$1:
+	.llong	.$1, .TOC.@tocbase, 0
+	.size	$1, 24
+	.type	.$1, @function
+	.section	".text"
+	.align	5
+.$1:
+')')
+
+define(`EPILOGUE_cpu',
+m4_assert_numargs(1)
+`ifdef(`ELFv2_ABI',`
+	.size	$1, .-$1
+',`
+	.size	.$1, .-.$1
+')')
+
+define(`TOC_ENTRY', `')
+
+define(`LEA',
+m4_assert_numargs(2)
+`define(`TOC_ENTRY',
+`	.section	".toc", "aw"
+..$2:	.tc	$2[TC], $2')'
+	`ld	$1, ..$2@toc(2)')
+
+define(`LEAL',
+m4_assert_numargs(2)
+`LEA($1,$2)')
+
+
+define(`EXTERN',
+m4_assert_numargs(1)
+`dnl')
+
+define(`EXTERN_FUNC',
+m4_assert_numargs(1)
+`dnl')
+
+define(`DEF_OBJECT',
+m4_assert_numargs_range(1,2)
+`
+	.section	.rodata
+	ALIGN(ifelse($#,1,2,$2))
+	.type	$1, @object
+$1:
+')
+
+define(`END_OBJECT',
+m4_assert_numargs(1)
+`	.size	$1, .-$1')
+
+define(`CALL',
+	`bl	GSYM_PREFIX`'$1
+	nop')
+
+define(`ASM_END', `TOC_ENTRY')
+
+undefine(`EXTRA_REGISTER')
+
+divert
diff --git a/third_party/gmp/mpn/powerpc64/logops_n.asm b/third_party/gmp/mpn/powerpc64/logops_n.asm
new file mode 100644
index 0000000..2fa6985
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/logops_n.asm
@@ -0,0 +1,151 @@
+dnl  PowerPC-64 mpn_and_n, mpn_andn_n, mpn_nand_n, mpn_ior_n, mpn_iorn_n,
+dnl  mpn_nior_n, mpn_xor_n, mpn_xnor_n -- mpn bitwise logical operations.
+
+dnl  Copyright 2003-2005 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                  cycles/limb
+C POWER3/PPC630          1.75
+C POWER4/PPC970          2.10
+C POWER5                 ?
+C POWER6                 ?
+C POWER7                 1.75
+
+C   n	   POWER3/PPC630   POWER4/PPC970
+C     1	       15.00	       15.33
+C     2		7.50		7.99
+C     3		5.33		6.00
+C     4		4.50		4.74
+C     5		4.20		4.39
+C     6		3.50		3.99
+C     7		3.14		3.64
+C     8		3.00		3.36
+C     9		3.00		3.36
+C    10		2.70		3.25
+C    11		2.63		3.11
+C    12		2.58		3.00
+C    13		2.61		3.02
+C    14		2.42		2.82
+C    15		2.40		2.79
+C    50		2.08		2.67
+C   100		1.85		2.31
+C   200		1.80		2.18
+C   400		1.77		2.14
+C  1000		1.76		2.10#
+C  2000		1.75#		2.13
+C  4000		2.30		2.57
+C  8000		2.62		2.58
+C 16000		2.52		4.25
+C 32000		2.49	       16.25
+C 64000		2.66	       18.76
+
+ifdef(`OPERATION_and_n',
+`	define(`func',`mpn_and_n')
+	define(`logop',		`and')')
+ifdef(`OPERATION_andn_n',
+`	define(`func',`mpn_andn_n')
+	define(`logop',		`andc')')
+ifdef(`OPERATION_nand_n',
+`	define(`func',`mpn_nand_n')
+	define(`logop',		`nand')')
+ifdef(`OPERATION_ior_n',
+`	define(`func',`mpn_ior_n')
+	define(`logop',		`or')')
+ifdef(`OPERATION_iorn_n',
+`	define(`func',`mpn_iorn_n')
+	define(`logop',		`orc')')
+ifdef(`OPERATION_nior_n',
+`	define(`func',`mpn_nior_n')
+	define(`logop',		`nor')')
+ifdef(`OPERATION_xor_n',
+`	define(`func',`mpn_xor_n')
+	define(`logop',		`xor')')
+ifdef(`OPERATION_xnor_n',
+`	define(`func',`mpn_xnor_n')
+	define(`logop',		`eqv')')
+
+C INPUT PARAMETERS
+C rp	r3
+C up	r4
+C vp	r5
+C n	r6
+
+MULFUNC_PROLOGUE(mpn_and_n mpn_andn_n mpn_nand_n mpn_ior_n mpn_iorn_n mpn_nior_n mpn_xor_n mpn_xnor_n)
+
+ASM_START()
+PROLOGUE(func)
+	ld	r8, 0(r4)	C read lowest u limb
+	ld	r9, 0(r5)	C read lowest v limb
+	addi	r6, r6, 3	C compute branch count (1)
+	rldic.	r0, r6, 3, 59	C r0 = (n-1 & 3) << 3; cr0 = (n == 4(t+1))?
+	cmpldi	cr6, r0, 16	C cr6 = (n cmp 4t + 3)
+
+ifdef(`HAVE_ABI_mode32',
+`	rldicl	r6, r6, 62,34',	C ...branch count
+`	rldicl	r6, r6, 62, 2')	C ...branch count
+	mtctr	r6
+
+	ld	r6, 0(r4)	C read lowest u limb (again)
+	ld	r7, 0(r5)	C read lowest v limb (again)
+
+	add	r5, r5, r0	C offset vp
+	add	r4, r4, r0	C offset up
+	add	r3, r3, r0	C offset rp
+
+	beq	cr0, L(L01)
+	blt	cr6, L(L10)
+	beq	cr6, L(L11)
+	b	L(L00)
+
+L(oop):	ld	r8, -24(r4)
+	ld	r9, -24(r5)
+	logop	r10, r6, r7
+	std	r10, -32(r3)
+L(L00):	ld	r6, -16(r4)
+	ld	r7, -16(r5)
+	logop	r10, r8, r9
+	std	r10, -24(r3)
+L(L11):	ld	r8, -8(r4)
+	ld	r9, -8(r5)
+	logop	r10, r6, r7
+	std	r10, -16(r3)
+L(L10):	ld	r6, 0(r4)
+	ld	r7, 0(r5)
+	logop	r10, r8, r9
+	std	r10, -8(r3)
+L(L01):	addi	r5, r5, 32
+	addi	r4, r4, 32
+	addi	r3, r3, 32
+	bdnz	L(oop)
+
+	logop	r10, r6, r7
+	std	r10, -32(r3)
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc64/lshift.asm b/third_party/gmp/mpn/powerpc64/lshift.asm
new file mode 100644
index 0000000..880944a
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/lshift.asm
@@ -0,0 +1,207 @@
+dnl  PowerPC-64 mpn_lshift -- rp[] = up[] << cnt
+
+dnl  Copyright 2003, 2005, 2010, 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                   cycles/limb
+C POWER3/PPC630          ?
+C POWER4/PPC970          ?
+C POWER5                 2.25
+C POWER6                 9.75
+C POWER7                 2.15
+
+C TODO
+C  * Try to reduce the number of needed live registers
+C  * Micro-optimise header code
+C  * Keep in synch with rshift.asm and lshiftc.asm
+
+C INPUT PARAMETERS
+define(`rp',  `r3')
+define(`up',  `r4')
+define(`n',   `r5')
+define(`cnt', `r6')
+
+define(`tnc',`r0')
+define(`u0',`r30')
+define(`u1',`r31')
+define(`retval',`r5')
+
+ASM_START()
+PROLOGUE(mpn_lshift)
+	std	r31, -8(r1)
+	std	r30, -16(r1)
+	subfic	tnc, cnt, 64
+	sldi	r7, n, 3	C byte count corresponding to n
+	add	up, up, r7	C up = up + n
+	add	rp, rp, r7	C rp = rp + n
+	rldicl.	r30, n, 0,62	C r30 = n & 3, set cr0
+	cmpdi	cr6, r30, 2
+	addi	r31, n, 3	C compute count...
+	ld	r10, -8(up)	C load 1st limb for b00...b11
+	srd	retval, r10, tnc
+ifdef(`HAVE_ABI_mode32',
+`	rldicl	r31, r31, 62,34',	C ...branch count
+`	srdi	r31, r31, 2')	C ...for ctr
+	mtctr	r31		C copy count into ctr
+	beq	cr0, L(b00)
+	blt	cr6, L(b01)
+	ld	r11, -16(up)	C load 2nd limb for b10 and b11
+	beq	cr6, L(b10)
+
+	ALIGN(16)
+L(b11):	sld	r8, r10, cnt
+	srd	r9, r11, tnc
+	ld	u1, -24(up)
+	addi	up, up, -24
+	sld	r12, r11, cnt
+	srd	r7, u1, tnc
+	addi	rp, rp, 16
+	bdnz	L(gt3)
+
+	or	r11, r8, r9
+	sld	r8, u1, cnt
+	b	L(cj3)
+
+	ALIGN(16)
+L(gt3):	ld	u0, -8(up)
+	or	r11, r8, r9
+	sld	r8, u1, cnt
+	srd	r9, u0, tnc
+	ld	u1, -16(up)
+	or	r10, r12, r7
+	b	L(L11)
+
+	ALIGN(32)
+L(b10):	sld	r12, r10, cnt
+	addi	rp, rp, 24
+	srd	r7, r11, tnc
+	bdnz	L(gt2)
+
+	sld	r8, r11, cnt
+	or	r10, r12, r7
+	b	L(cj2)
+
+L(gt2):	ld	u0, -24(up)
+	sld	r8, r11, cnt
+	srd	r9, u0, tnc
+	ld	u1, -32(up)
+	or	r10, r12, r7
+	sld	r12, u0, cnt
+	srd	r7, u1, tnc
+	ld	u0, -40(up)
+	or	r11, r8, r9
+	addi	up, up, -16
+	b	L(L10)
+
+	ALIGN(16)
+L(b00):	ld	u1, -16(up)
+	sld	r12, r10, cnt
+	srd	r7, u1, tnc
+	ld	u0, -24(up)
+	sld	r8, u1, cnt
+	srd	r9, u0, tnc
+	ld	u1, -32(up)
+	or	r10, r12, r7
+	sld	r12, u0, cnt
+	srd	r7, u1, tnc
+	addi	rp, rp, 8
+	bdz	L(cj4)
+
+L(gt4):	addi	up, up, -32
+	ld	u0, -8(up)
+	or	r11, r8, r9
+	b	L(L00)
+
+	ALIGN(16)
+L(b01):	bdnz	L(gt1)
+	sld	r8, r10, cnt
+	std	r8, -8(rp)
+	b	L(ret)
+
+L(gt1):	ld	u0, -16(up)
+	sld	r8, r10, cnt
+	srd	r9, u0, tnc
+	ld	u1, -24(up)
+	sld	r12, u0, cnt
+	srd	r7, u1, tnc
+	ld	u0, -32(up)
+	or	r11, r8, r9
+	sld	r8, u1, cnt
+	srd	r9, u0, tnc
+	ld	u1, -40(up)
+	addi	up, up, -40
+	or	r10, r12, r7
+	bdz	L(end)
+
+	ALIGN(32)
+L(top):	sld	r12, u0, cnt
+	srd	r7, u1, tnc
+	ld	u0, -8(up)
+	std	r11, -8(rp)
+	or	r11, r8, r9
+L(L00):	sld	r8, u1, cnt
+	srd	r9, u0, tnc
+	ld	u1, -16(up)
+	std	r10, -16(rp)
+	or	r10, r12, r7
+L(L11):	sld	r12, u0, cnt
+	srd	r7, u1, tnc
+	ld	u0, -24(up)
+	std	r11, -24(rp)
+	or	r11, r8, r9
+L(L10):	sld	r8, u1, cnt
+	srd	r9, u0, tnc
+	ld	u1, -32(up)
+	addi	up, up, -32
+	std	r10, -32(rp)
+	addi	rp, rp, -32
+	or	r10, r12, r7
+	bdnz	L(top)
+
+	ALIGN(32)
+L(end):	sld	r12, u0, cnt
+	srd	r7, u1, tnc
+	std	r11, -8(rp)
+L(cj4):	or	r11, r8, r9
+	sld	r8, u1, cnt
+	std	r10, -16(rp)
+L(cj3):	or	r10, r12, r7
+	std	r11, -24(rp)
+L(cj2):	std	r10, -32(rp)
+	std	r8, -40(rp)
+
+L(ret):	ld	r31, -8(r1)
+	ld	r30, -16(r1)
+ifdef(`HAVE_ABI_mode32',
+`	srdi	r3, retval, 32
+	mr	r4, retval
+',`	mr	r3, retval')
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc64/lshiftc.asm b/third_party/gmp/mpn/powerpc64/lshiftc.asm
new file mode 100644
index 0000000..7cf6a83
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/lshiftc.asm
@@ -0,0 +1,210 @@
+dnl  PowerPC-64 mpn_lshiftc -- rp[] = ~up[] << cnt
+
+dnl  Copyright 2003, 2005, 2010 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                   cycles/limb
+C POWER3/PPC630          ?
+C POWER4/PPC970          ?
+C POWER5                 2.25
+C POWER6                 9.5
+C POWER7                 2.15
+
+C TODO
+C  * Try to reduce the number of needed live registers
+C  * Micro-optimise header code
+C  * Keep in synch with lshift.asm and rshift.asm
+C  * Could the long-scheduled std insns be less scheduled?
+
+C INPUT PARAMETERS
+define(`rp',  `r3')
+define(`up',  `r4')
+define(`n',   `r5')
+define(`cnt', `r6')
+
+define(`tnc',`r0')
+define(`u0',`r30')
+define(`u1',`r31')
+define(`retval',`r5')
+
+ASM_START()
+PROLOGUE(mpn_lshiftc)
+	std	r31, -8(r1)
+	std	r30, -16(r1)
+	subfic	tnc, cnt, 64
+	sldi	r7, n, 3	C byte count corresponding to n
+	add	up, up, r7	C up = up + n
+	add	rp, rp, r7	C rp = rp + n
+	rldicl.	r30, n, 0,62	C r30 = n & 3, set cr0
+	cmpdi	cr6, r30, 2
+	addi	r31, n, 3	C compute count...
+	ld	r10, -8(up)	C load 1st limb for b00...b11
+	srd	retval, r10, tnc
+	srdi	r31, r31, 2	C ...for ctr
+	mtctr	r31		C copy count into ctr
+	beq	cr0, L(b00)
+	blt	cr6, L(b01)
+	ld	r11, -16(up)	C load 2nd limb for b10 and b11
+	beq	cr6, L(b10)
+
+	ALIGN(16)
+L(b11):	sld	r8, r10, cnt
+	srd	r9, r11, tnc
+	ld	u1, -24(up)
+	addi	up, up, -24
+	sld	r12, r11, cnt
+	srd	r7, u1, tnc
+	addi	rp, rp, 16
+	bdnz	L(gt3)
+
+	nor	r11, r8, r9
+	sld	r8, u1, cnt
+	nor	r8, r8, r8
+	b	L(cj3)
+
+	ALIGN(16)
+L(gt3):	ld	u0, -8(up)
+	nor	r11, r8, r9
+	sld	r8, u1, cnt
+	srd	r9, u0, tnc
+	ld	u1, -16(up)
+	nor	r10, r12, r7
+	b	L(L11)
+
+	ALIGN(32)
+L(b10):	sld	r12, r10, cnt
+	addi	rp, rp, 24
+	srd	r7, r11, tnc
+	bdnz	L(gt2)
+
+	sld	r8, r11, cnt
+	nor	r10, r12, r7
+	nor	r8, r8, r8
+	b	L(cj2)
+
+L(gt2):	ld	u0, -24(up)
+	sld	r8, r11, cnt
+	srd	r9, u0, tnc
+	ld	u1, -32(up)
+	nor	r10, r12, r7
+	sld	r12, u0, cnt
+	srd	r7, u1, tnc
+	ld	u0, -40(up)
+	nor	r11, r8, r9
+	addi	up, up, -16
+	b	L(L10)
+
+	ALIGN(16)
+L(b00):	ld	u1, -16(up)
+	sld	r12, r10, cnt
+	srd	r7, u1, tnc
+	ld	u0, -24(up)
+	sld	r8, u1, cnt
+	srd	r9, u0, tnc
+	ld	u1, -32(up)
+	nor	r10, r12, r7
+	sld	r12, u0, cnt
+	srd	r7, u1, tnc
+	addi	rp, rp, 8
+	bdz	L(cj4)
+
+L(gt4):	addi	up, up, -32
+	ld	u0, -8(up)
+	nor	r11, r8, r9
+	b	L(L00)
+
+	ALIGN(16)
+L(b01):	bdnz	L(gt1)
+	sld	r8, r10, cnt
+	nor	r8, r8, r8
+	std	r8, -8(rp)
+	b	L(ret)
+
+L(gt1):	ld	u0, -16(up)
+	sld	r8, r10, cnt
+	srd	r9, u0, tnc
+	ld	u1, -24(up)
+	sld	r12, u0, cnt
+	srd	r7, u1, tnc
+	ld	u0, -32(up)
+	nor	r11, r8, r9
+	sld	r8, u1, cnt
+	srd	r9, u0, tnc
+	ld	u1, -40(up)
+	addi	up, up, -40
+	nor	r10, r12, r7
+	bdz	L(end)
+
+	ALIGN(32)
+L(top):	sld	r12, u0, cnt
+	srd	r7, u1, tnc
+	ld	u0, -8(up)
+	std	r11, -8(rp)
+	nor	r11, r8, r9
+L(L00):	sld	r8, u1, cnt
+	srd	r9, u0, tnc
+	ld	u1, -16(up)
+	std	r10, -16(rp)
+	nor	r10, r12, r7
+L(L11):	sld	r12, u0, cnt
+	srd	r7, u1, tnc
+	ld	u0, -24(up)
+	std	r11, -24(rp)
+	nor	r11, r8, r9
+L(L10):	sld	r8, u1, cnt
+	srd	r9, u0, tnc
+	ld	u1, -32(up)
+	addi	up, up, -32
+	std	r10, -32(rp)
+	addi	rp, rp, -32
+	nor	r10, r12, r7
+	bdnz	L(top)
+
+	ALIGN(32)
+L(end):	sld	r12, u0, cnt
+	srd	r7, u1, tnc
+	std	r11, -8(rp)
+L(cj4):	nor	r11, r8, r9
+	sld	r8, u1, cnt
+	std	r10, -16(rp)
+	nor	r8, r8, r8
+L(cj3):	nor	r10, r12, r7
+	std	r11, -24(rp)
+L(cj2):	std	r10, -32(rp)
+	std	r8, -40(rp)
+
+L(ret):	ld	r31, -8(r1)
+	ld	r30, -16(r1)
+ifdef(`HAVE_ABI_mode32',
+`	srdi	r3, retval, 32
+	mr	r4, retval
+',`	mr	r3, retval')
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc64/mode32/add_n.asm b/third_party/gmp/mpn/powerpc64/mode32/add_n.asm
new file mode 100644
index 0000000..1da8087
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode32/add_n.asm
@@ -0,0 +1,86 @@
+dnl  PowerPC-64/mode32 mpn_add_n -- Add two limb vectors of the same length > 0
+dnl  and store sum in a third limb vector.
+
+dnl  Copyright 1999-2001, 2003, 2005 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		cycles/limb
+C POWER3/PPC630:     ?
+C POWER4/PPC970:     4.25
+
+C INPUT PARAMETERS
+C rp	r3
+C up	r4
+C vp	r5
+C n	r6
+
+ASM_START()
+PROLOGUE(mpn_add_n)
+	mtctr	r6		C copy size into CTR
+	addic	r0, r0, 0	C clear cy
+	ld	r8, 0(r4)	C load least significant s1 limb
+	ld	r0, 0(r5)	C load least significant s2 limb
+	addi	r3, r3, -8	C offset res_ptr, it's updated before it's used
+	bdz	L(end)		C If done, skip loop
+
+L(oop):	ld	r9, 8(r4)	C load s1 limb
+	ld	r10, 8(r5)	C load s2 limb
+	adde	r7, r0, r8	C add limbs with cy, set cy
+	srdi	r6, r0, 32
+	srdi	r11, r8, 32
+	adde	r6, r6, r11	C add high limb parts, set cy
+	std	r7, 8(r3)	C store result limb
+	bdz	L(exit)		C decrement CTR and exit if done
+	ldu	r8, 16(r4)	C load s1 limb and update s1_ptr
+	ldu	r0, 16(r5)	C load s2 limb and update s2_ptr
+	adde	r7, r10, r9	C add limbs with cy, set cy
+	srdi	r6, r10, 32
+	srdi	r11, r9, 32
+	adde	r6, r6, r11	C add high limb parts, set cy
+	stdu	r7, 16(r3)	C store result limb and update res_ptr
+	bdnz	L(oop)		C decrement CTR and loop back
+
+L(end):	adde	r7, r0, r8
+	srdi	r6, r0, 32
+	srdi	r11, r8, 32
+	adde	r6, r6, r11	C add limbs with cy, set cy
+	std	r7, 8(r3)	C store ultimate result limb
+	li	r3, 0		C load cy into ...
+	addze	r4, r3		C ... return value register
+	blr
+L(exit):	adde	r7, r10, r9
+	srdi	r6, r10, 32
+	srdi	r11, r9, 32
+	adde	r6, r6, r11	C add limbs with cy, set cy
+	std	r7, 16(r3)
+	li	r3, 0		C load cy into ...
+	addze	r4, r3		C ... return value register
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc64/mode32/addmul_1.asm b/third_party/gmp/mpn/powerpc64/mode32/addmul_1.asm
new file mode 100644
index 0000000..bdc3951
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode32/addmul_1.asm
@@ -0,0 +1,79 @@
+dnl  PowerPC-64 mpn_addmul_1 -- Multiply a limb vector with a limb and add
+dnl  the result to a second limb vector.
+
+dnl  Copyright 1999-2001, 2003, 2005 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		cycles/limb
+C POWER3/PPC630:     ?
+C POWER4/PPC970:     12.5
+
+C INPUT PARAMETERS
+C rp	r3
+C up	r4
+C n	r5
+C v	r6,r7  or  r7,r8
+
+ASM_START()
+PROLOGUE(mpn_addmul_1)
+
+ifdef(`BROKEN_LONGLONG_PARAM',
+`	rldimi	r8, r7, 32,0	C assemble vlimb from separate 32-bit arguments
+	mr	r6, r8
+',`
+	rldimi	r7, r6, 32,0	C assemble vlimb from separate 32-bit arguments
+	mr	r6, r7
+')
+	li	r7, 0		C cy_limb = 0
+	mtctr	r5
+	addic	r0, r0, 0
+	addi	r3, r3, -8
+	addi	r4, r4, -8
+
+L(oop):	ldu	r0, 8(r4)
+	mulld	r9, r0, r6
+	adde	r12, r9, r7	C add old high limb and new low limb
+	srdi	r5, r9, 32
+	srdi	r11, r7, 32
+	adde	r5, r5, r11	C add high limb parts, set cy
+	mulhdu	r7, r0, r6
+	addze	r7, r7
+	ld	r10, 8(r3)
+	addc	r9, r12, r10
+	srdi	r5, r12, 32
+	srdi	r11, r10, 32
+	adde	r5, r5, r11	C add high limb parts, set cy
+	stdu	r9, 8(r3)
+	bdnz	L(oop)
+
+	addze	r4, r7
+	srdi	r3, r4, 32
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc64/mode32/mul_1.asm b/third_party/gmp/mpn/powerpc64/mode32/mul_1.asm
new file mode 100644
index 0000000..3a17e98
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode32/mul_1.asm
@@ -0,0 +1,73 @@
+dnl  PowerPC-64 mpn_mul_1 -- Multiply a limb vector with a limb and add
+dnl  the result to a second limb vector.
+
+dnl  Copyright 1999-2001, 2003, 2005 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		cycles/limb
+C POWER3/PPC630:     ?
+C POWER4/PPC970:     10
+
+C INPUT PARAMETERS
+C rp	r3
+C up	r4
+C n	r5
+C v	r6,r7  or  r7,r8
+
+ASM_START()
+PROLOGUE(mpn_mul_1)
+
+ifdef(`BROKEN_LONGLONG_PARAM',
+`	rldimi	r8, r7, 32,0	C assemble vlimb from separate 32-bit arguments
+	mr	r6, r8
+',`
+	rldimi	r7, r6, 32,0	C assemble vlimb from separate 32-bit arguments
+	mr	r6, r7
+')
+	li	r7, 0		C cy_limb = 0
+	mtctr	r5
+	addic	r0, r0, 0
+	addi	r3, r3, -8
+	addi	r4, r4, -8
+
+L(oop):	ldu	r0, 8(r4)
+	mulld	r9, r0, r6
+	adde	r12, r9, r7	C add old high limb and new low limb
+	srdi	r5, r9, 32
+	srdi	r11, r7, 32
+	adde	r5, r5, r11	C add high limb parts, set cy
+	mulhdu	r7, r0, r6
+	stdu	r12, 8(r3)
+	bdnz	L(oop)
+
+	addze	r4, r7
+	srdi	r3, r4, 32
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc64/mode32/p4/gmp-mparam.h b/third_party/gmp/mpn/powerpc64/mode32/p4/gmp-mparam.h
new file mode 100644
index 0000000..4e805a0
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode32/p4/gmp-mparam.h
@@ -0,0 +1,182 @@
+/* PowerPC-64 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2008, 2009, 2011, 2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+/* 1800 MHz PPC970 */
+/* FFT tuning limit = 0.5 M */
+/* Generated by tuneup.c, 2017-01-01, gcc 4.0 */
+
+#define DIVREM_1_NORM_THRESHOLD              0  /* always */
+#define DIVREM_1_UNNORM_THRESHOLD            0  /* always */
+#define MOD_1_1P_METHOD                      1
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          7
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          5
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD         6
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        46
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     15
+#define USE_PREINV_DIVREM_1                  1
+#define DIV_QR_1N_PI1_METHOD                 1
+#define DIV_QR_1_NORM_THRESHOLD              2
+#define DIV_QR_1_UNNORM_THRESHOLD            2
+#define DIV_QR_2_PI2_THRESHOLD              15
+#define DIVEXACT_1_THRESHOLD                 0  /* always */
+#define BMOD_1_TO_MOD_1_THRESHOLD           88
+
+#define DIV_1_VS_MUL_1_PERCENT             269
+
+#define MUL_TOOM22_THRESHOLD                18
+#define MUL_TOOM33_THRESHOLD                60
+#define MUL_TOOM44_THRESHOLD                88
+#define MUL_TOOM6H_THRESHOLD               124
+#define MUL_TOOM8H_THRESHOLD               187
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      61
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD      91
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD      61
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD      60
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD      74
+
+#define SQR_BASECASE_THRESHOLD               4
+#define SQR_TOOM2_THRESHOLD                 28
+#define SQR_TOOM3_THRESHOLD                 90
+#define SQR_TOOM4_THRESHOLD                143
+#define SQR_TOOM6_THRESHOLD                181
+#define SQR_TOOM8_THRESHOLD                272
+
+#define MULMID_TOOM42_THRESHOLD             34
+
+#define MULMOD_BNM1_THRESHOLD               10
+#define SQRMOD_BNM1_THRESHOLD               15
+
+#define MUL_FFT_MODF_THRESHOLD             252  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    252, 5}, {     11, 6}, {      6, 5}, {     13, 6}, \
+    {      7, 5}, {     15, 6}, {     13, 5}, {     27, 6}, \
+    {     15, 7}, {      8, 6}, {     17, 7}, {      9, 6}, \
+    {     19, 7}, {     17, 8}, {      9, 7}, {     20, 8}, \
+    {     11, 7}, {     23, 8}, {     13, 9}, {      7, 8}, \
+    {     21, 9}, {     11, 8}, {     27,10}, {      7, 9}, \
+    {     15, 8}, {     33, 9}, {     19, 8}, {     39, 9}, \
+    {     23, 8}, {     47, 9}, {     27,10}, {     15, 9}, \
+    {     39,10}, {     23, 9}, {     47,11}, {     15,10}, \
+    {     31, 9}, {     67,10}, {     39, 9}, {     83,10}, \
+    {     47, 9}, {     95, 8}, {    191,10}, {     55,11}, \
+    {     31,10}, {     63, 9}, {    127, 8}, {    255,10}, \
+    {     71, 9}, {    143, 8}, {    287,10}, {     79, 9}, \
+    {    159, 8}, {    319,11}, {     47,10}, {     95, 9}, \
+    {    191, 8}, {    383,10}, {    103,12}, {     31,11}, \
+    {     63,10}, {    127, 9}, {    255, 8}, {    511,10}, \
+    {    143, 9}, {    287,11}, {     79,10}, {    159, 9}, \
+    {    319, 8}, {    639,10}, {    175, 9}, {    351, 8}, \
+    {    703,11}, {     95,10}, {    191, 9}, {    383, 8}, \
+    {    767,10}, {    207, 9}, {    415,10}, {    223, 9}, \
+    {    447,12}, {     63,11}, {    127,10}, {    255, 9}, \
+    {    511,11}, {    143,10}, {    287, 9}, {    575,11}, \
+    {    159,10}, {    319, 9}, {    639,11}, {    175,10}, \
+    {    351, 9}, {    703,12}, {     95,11}, {    191,10}, \
+    {    383, 9}, {    767,11}, {    207,10}, {    415,11}, \
+    {    223,10}, {    447,13}, {   8192,14}, {  16384,15}, \
+    {  32768,16} }
+#define MUL_FFT_TABLE3_SIZE 105
+#define MUL_FFT_THRESHOLD                 5248
+
+#define SQR_FFT_MODF_THRESHOLD             236  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    236, 5}, {     13, 6}, {     15, 7}, {      8, 6}, \
+    {     17, 7}, {      9, 6}, {     19, 7}, {     17, 8}, \
+    {      9, 7}, {     20, 8}, {     11, 7}, {     24, 8}, \
+    {     13, 9}, {      7, 8}, {     19, 9}, {     11, 8}, \
+    {     25,10}, {      7, 9}, {     15, 8}, {     33, 9}, \
+    {     19, 8}, {     39, 9}, {     23, 8}, {     47, 9}, \
+    {     27,10}, {     15, 9}, {     39,10}, {     23, 9}, \
+    {     47,11}, {     15,10}, {     31, 9}, {     67,10}, \
+    {     39, 9}, {     79, 8}, {    159,10}, {     47, 9}, \
+    {     95, 8}, {    191,11}, {     31,10}, {     63, 9}, \
+    {    127, 8}, {    255,10}, {     71, 9}, {    143, 8}, \
+    {    287,10}, {     79, 9}, {    159, 8}, {    319,11}, \
+    {     47,10}, {     95, 9}, {    191, 8}, {    383,12}, \
+    {     31,11}, {     63,10}, {    127, 9}, {    255, 8}, \
+    {    511,10}, {    143, 9}, {    287, 8}, {    575,11}, \
+    {     79,10}, {    159, 9}, {    319, 8}, {    639,10}, \
+    {    175, 9}, {    351, 8}, {    703,11}, {     95,10}, \
+    {    191, 9}, {    383, 8}, {    767,10}, {    207, 9}, \
+    {    415,10}, {    223,12}, {     63,11}, {    127,10}, \
+    {    255, 9}, {    511,11}, {    143,10}, {    287, 9}, \
+    {    575,11}, {    159,10}, {    319, 9}, {    639,11}, \
+    {    175,10}, {    351, 9}, {    703,11}, {    191,10}, \
+    {    383, 9}, {    767,11}, {    207,10}, {    415,11}, \
+    {    223,10}, {    447,13}, {   8192,14}, {  16384,15}, \
+    {  32768,16} }
+#define SQR_FFT_TABLE3_SIZE 97
+#define SQR_FFT_THRESHOLD                 3200
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  56
+#define MULLO_MUL_N_THRESHOLD             8648
+#define SQRLO_BASECASE_THRESHOLD             2
+#define SQRLO_DC_THRESHOLD                 106
+#define SQRLO_SQR_THRESHOLD               6293
+
+#define DC_DIV_QR_THRESHOLD                 28
+#define DC_DIVAPPR_Q_THRESHOLD             102
+#define DC_BDIV_QR_THRESHOLD                51
+#define DC_BDIV_Q_THRESHOLD                124
+
+#define INV_MULMOD_BNM1_THRESHOLD           34
+#define INV_NEWTON_THRESHOLD               123
+#define INV_APPR_THRESHOLD                 109
+
+#define BINV_NEWTON_THRESHOLD              206
+#define REDC_1_TO_REDC_N_THRESHOLD          51
+
+#define MU_DIV_QR_THRESHOLD                807
+#define MU_DIVAPPR_Q_THRESHOLD             807
+#define MUPI_DIV_QR_THRESHOLD               53
+#define MU_BDIV_QR_THRESHOLD               748
+#define MU_BDIV_Q_THRESHOLD                872
+
+#define POWM_SEC_TABLE  2,23,66,440,1555
+
+#define GET_STR_DC_THRESHOLD                 7
+#define GET_STR_PRECOMPUTE_THRESHOLD        17
+#define SET_STR_DC_THRESHOLD              1035
+#define SET_STR_PRECOMPUTE_THRESHOLD      2170
+
+#define FAC_DSC_THRESHOLD                  542
+#define FAC_ODD_THRESHOLD                   24
+
+#define MATRIX22_STRASSEN_THRESHOLD         10
+#define HGCD_THRESHOLD                     108
+#define HGCD_APPR_THRESHOLD                116
+#define HGCD_REDUCE_THRESHOLD             1437
+#define GCD_DC_THRESHOLD                   268
+#define GCDEXT_DC_THRESHOLD                241
+#define JACOBI_BASE_METHOD                   4
diff --git a/third_party/gmp/mpn/powerpc64/mode32/sqr_diagonal.asm b/third_party/gmp/mpn/powerpc64/mode32/sqr_diagonal.asm
new file mode 100644
index 0000000..ff5f4b3
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode32/sqr_diagonal.asm
@@ -0,0 +1,117 @@
+dnl  PowerPC-64 mpn_sqr_diagonal.
+
+dnl  Copyright 2001-2003, 2005, 2006, 20010 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		    cycles/limb
+C POWER3/PPC630		18
+C POWER4/PPC970		 ?
+C POWER5		 7.25
+C POWER6		 9.5
+
+C INPUT PARAMETERS
+define(`rp',  r3)
+define(`up',  r4)
+define(`n',   r5)
+
+ASM_START()
+PROLOGUE(mpn_sqr_diagonal)
+ifdef(`HAVE_ABI_mode32',
+`	rldicl	n, n, 0, 32')		C zero extend n
+
+	rldicl.	r0, n, 0,62		C r0 = n & 3, set cr0
+	addi	n, n, 3			C compute count...
+	cmpdi	cr6, r0, 2
+	srdi	n, n, 2			C ...for ctr
+	mtctr	n			C copy count into ctr
+	beq	cr0, L(b00)
+	blt	cr6, L(b01)
+	beq	cr6, L(b10)
+
+L(b11):	ld	r0, 0(up)
+	ld	r10, 8(up)
+	ld	r12, 16(up)
+	addi	rp, rp, -16
+	mulld	r7, r0, r0
+	mulhdu	r8, r0, r0
+	mulld	r9, r10, r10
+	mulhdu	r10, r10, r10
+	mulld	r11, r12, r12
+	mulhdu	r12, r12, r12
+	addi	up, up, 24
+	b	L(11)
+
+	ALIGN(16)
+L(b01):	ld	r0, 0(up)
+	addi	rp, rp, -48
+	addi	up, up, 8
+	mulld	r11, r0, r0
+	mulhdu	r12, r0, r0
+	b	L(01)
+
+	ALIGN(16)
+L(b10):	ld	r0, 0(up)
+	ld	r12, 8(up)
+	addi	rp, rp, -32
+	addi	up, up, 16
+	mulld	r9, r0, r0
+	mulhdu	r10, r0, r0
+	mulld	r11, r12, r12
+	mulhdu	r12, r12, r12
+	b	L(10)
+
+	ALIGN(32)
+L(b00):
+L(top):	ld	r0, 0(up)
+	ld	r8, 8(up)
+	ld	r10, 16(up)
+	ld	r12, 24(up)
+	mulld	r5, r0, r0
+	mulhdu	r6, r0, r0
+	mulld	r7, r8, r8
+	mulhdu	r8, r8, r8
+	mulld	r9, r10, r10
+	mulhdu	r10, r10, r10
+	mulld	r11, r12, r12
+	mulhdu	r12, r12, r12
+	addi	up, up, 32
+	std	r5, 0(rp)
+	std	r6, 8(rp)
+L(11):	std	r7, 16(rp)
+	std	r8, 24(rp)
+L(10):	std	r9, 32(rp)
+	std	r10, 40(rp)
+L(01):	std	r11, 48(rp)
+	std	r12, 56(rp)
+	addi	rp, rp, 64
+	bdnz	L(top)
+
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc64/mode32/sub_n.asm b/third_party/gmp/mpn/powerpc64/mode32/sub_n.asm
new file mode 100644
index 0000000..6fdc1d4
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode32/sub_n.asm
@@ -0,0 +1,88 @@
+dnl  PowerPC-64/mode32 mpn_sub_n -- Subtract two limb vectors of the same
+dnl  length and store difference in a third limb vector.
+
+dnl  Copyright 1999-2001, 2003, 2005 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		cycles/limb
+C POWER3/PPC630:     ?
+C POWER4/PPC970:     4.25
+
+C INPUT PARAMETERS
+C rp	r3
+C up	r4
+C vp	r5
+C n	r6
+
+ASM_START()
+PROLOGUE(mpn_sub_n)
+	mtctr	r6		C copy size into CTR
+	addic	r0, r6, -1	C set cy
+	ld	r8, 0(r4)	C load least significant s1 limb
+	ld	r0, 0(r5)	C load least significant s2 limb
+	addi	r3, r3, -8	C offset res_ptr, it's updated before it's used
+	bdz	L(end)		C If done, skip loop
+
+L(oop):	ld	r9, 8(r4)	C load s1 limb
+	ld	r10, 8(r5)	C load s2 limb
+	subfe	r7, r0, r8	C subtract limbs with cy, set cy
+	srdi	r6, r0, 32
+	srdi	r11, r8, 32
+	subfe	r6, r6, r11
+	std	r7, 8(r3)	C store result limb
+	bdz	L(exit)		C decrement CTR and exit if done
+	ldu	r8, 16(r4)	C load s1 limb and update s1_ptr
+	ldu	r0, 16(r5)	C load s2 limb and update s2_ptr
+	subfe	r7, r10, r9	C subtract limbs with cy, set cy
+	srdi	r6, r10, 32
+	srdi	r11, r9, 32
+	subfe	r6, r6, r11
+	stdu	r7, 16(r3)	C store result limb and update res_ptr
+	bdnz	L(oop)		C decrement CTR and loop back
+
+L(end):	subfe	r7, r0, r8
+	srdi	r6, r0, 32
+	srdi	r11, r8, 32
+	subfe	r6, r6, r11
+	std	r7, 8(r3)	C store ultimate result limb
+	subfe	r3, r0, r0	C load !cy into ...
+	subfic	r4, r3, 0	C ... return value register
+	li	r3, 0		C zero extend return value
+	blr
+L(exit):	subfe	r7, r10, r9
+	srdi	r6, r10, 32
+	srdi	r11, r9, 32
+	subfe	r6, r6, r11
+	std	r7, 16(r3)
+	subfe	r3, r0, r0	C load !cy into ...
+	subfic	r4, r3, 0	C ... return value register
+	li	r3, 0		C zero extend return value
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc64/mode32/submul_1.asm b/third_party/gmp/mpn/powerpc64/mode32/submul_1.asm
new file mode 100644
index 0000000..996eda2
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode32/submul_1.asm
@@ -0,0 +1,81 @@
+dnl  PowerPC-64 mpn_submul_1 -- Multiply a limb vector with a limb and subtract
+dnl  the result from a second limb vector.
+
+dnl  Copyright 1999-2001, 2003, 2005 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		cycles/limb
+C POWER3/PPC630:     ?
+C POWER4/PPC970:     16
+
+C INPUT PARAMETERS
+C rp	r3
+C up	r4
+C n	r5
+C v	r6,r7  or  r7,r8
+
+ASM_START()
+PROLOGUE(mpn_submul_1)
+
+ifdef(`BROKEN_LONGLONG_PARAM',
+`	rldimi	r8, r7, 32,0	C assemble vlimb from separate 32-bit arguments
+	mr	r6, r8
+',`
+	rldimi	r7, r6, 32,0	C assemble vlimb from separate 32-bit arguments
+	mr	r6, r7
+')
+	li	r7, 0		C cy_limb = 0
+	mtctr	r5
+	addic	r0, r0, 0
+	addi	r3, r3, -8
+	addi	r4, r4, -8
+
+L(oop):	ldu	r0, 8(r4)
+	mulld	r9, r0, r6
+	adde	r12, r9, r7	C add old high limb and new low limb
+	srdi	r5, r9, 32
+	srdi	r11, r7, 32
+	adde	r5, r5, r11	C add high limb parts, set cy
+	mulhdu	r7, r0, r6
+	addze	r7, r7
+	ld	r10, 8(r3)
+	subfc	r9, r12, r10
+	srdi	r5, r12, 32
+	srdi	r11, r10, 32
+	subfe	r5, r5, r11	C subtract high limb parts, set cy
+	stdu	r9, 8(r3)
+	subfe	r11, r11, r11	C invert ...
+	addic	r11, r11, 1	C ... carry
+	bdnz	L(oop)
+
+	addze	r4, r7
+	srdi	r3, r4, 32
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc64/mode64/aors_n.asm b/third_party/gmp/mpn/powerpc64/mode64/aors_n.asm
new file mode 100644
index 0000000..0e8474f
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/aors_n.asm
@@ -0,0 +1,189 @@
+dnl  PowerPC-64 mpn_add_n/mpn_sub_n -- mpn addition and subtraction.
+
+dnl  Copyright 1999-2001, 2003-2005, 2007, 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                   cycles/limb
+C POWER3/PPC630          1.5
+C POWER4/PPC970          2
+C POWER5                 2
+C POWER6                 2.63
+C POWER7               2.25-2.87
+
+C This code is a little bit slower for POWER3/PPC630 than the simple code used
+C previously, but it is much faster for POWER4/PPC970.  The reason for the
+C POWER3/PPC630 slowdown can be attributed to the saving and restoring of 4
+C registers.
+
+C INPUT PARAMETERS
+C rp	r3
+C up	r4
+C vp	r5
+C n	r6
+
+ifdef(`OPERATION_add_n',`
+  define(ADDSUBC,	adde)
+  define(ADDSUB,	addc)
+  define(func,		mpn_add_n)
+  define(func_nc,	mpn_add_nc)
+  define(GENRVAL,	`addi	r3, r3, 1')
+  define(SETCBR,	`addic	r0, $1, -1')
+  define(CLRCB,		`addic	r0, r0, 0')
+')
+ifdef(`OPERATION_sub_n',`
+  define(ADDSUBC,	subfe)
+  define(ADDSUB,	subfc)
+  define(func,		mpn_sub_n)
+  define(func_nc,	mpn_sub_nc)
+  define(GENRVAL,	`neg	r3, r3')
+  define(SETCBR,	`subfic	r0, $1, 0')
+  define(CLRCB,		`addic	r0, r1, -1')
+')
+
+MULFUNC_PROLOGUE(mpn_add_n mpn_add_nc mpn_sub_n mpn_sub_nc)
+
+ASM_START()
+PROLOGUE(func_nc)
+	SETCBR(r7)
+	b	L(ent)
+EPILOGUE()
+
+PROLOGUE(func)
+	CLRCB
+L(ent):	std	r31, -8(r1)
+	std	r30, -16(r1)
+	std	r29, -24(r1)
+	std	r28, -32(r1)
+
+	rldicl.	r0, r6, 0,62	C r0 = n & 3, set cr0
+	cmpdi	cr6, r0, 2
+	addi	r6, r6, 3	C compute count...
+	srdi	r6, r6, 2	C ...for ctr
+	mtctr	r6		C copy count into ctr
+	beq	cr0, L(b00)
+	blt	cr6, L(b01)
+	beq	cr6, L(b10)
+
+L(b11):	ld	r8, 0(r4)	C load s1 limb
+	ld	r9, 0(r5)	C load s2 limb
+	ld	r10, 8(r4)	C load s1 limb
+	ld	r11, 8(r5)	C load s2 limb
+	ld	r12, 16(r4)	C load s1 limb
+	addi	r4, r4, 24
+	ld	r0, 16(r5)	C load s2 limb
+	addi	r5, r5, 24
+	ADDSUBC	r29, r9, r8
+	ADDSUBC	r30, r11, r10
+	ADDSUBC	r31, r0, r12
+	std	r29, 0(r3)
+	std	r30, 8(r3)
+	std	r31, 16(r3)
+	addi	r3, r3, 24
+	bdnz	L(go)
+	b	L(ret)
+
+L(b01):	ld	r12, 0(r4)	C load s1 limb
+	addi	r4, r4, 8
+	ld	r0, 0(r5)	C load s2 limb
+	addi	r5, r5, 8
+	ADDSUBC	r31, r0, r12	C add
+	std	r31, 0(r3)
+	addi	r3, r3, 8
+	bdnz	L(go)
+	b	L(ret)
+
+L(b10):	ld	r10, 0(r4)	C load s1 limb
+	ld	r11, 0(r5)	C load s2 limb
+	ld	r12, 8(r4)	C load s1 limb
+	addi	r4, r4, 16
+	ld	r0, 8(r5)	C load s2 limb
+	addi	r5, r5, 16
+	ADDSUBC	r30, r11, r10	C add
+	ADDSUBC	r31, r0, r12	C add
+	std	r30, 0(r3)
+	std	r31, 8(r3)
+	addi	r3, r3, 16
+	bdnz	L(go)
+	b	L(ret)
+
+L(b00):	C INITCY		C clear/set cy
+L(go):	ld	r6, 0(r4)	C load s1 limb
+	ld	r7, 0(r5)	C load s2 limb
+	ld	r8, 8(r4)	C load s1 limb
+	ld	r9, 8(r5)	C load s2 limb
+	ld	r10, 16(r4)	C load s1 limb
+	ld	r11, 16(r5)	C load s2 limb
+	ld	r12, 24(r4)	C load s1 limb
+	ld	r0, 24(r5)	C load s2 limb
+	bdz	L(end)
+
+	addi	r4, r4, 32
+	addi	r5, r5, 32
+
+	ALIGN(16)
+L(top):	ADDSUBC	r28, r7, r6
+	ld	r6, 0(r4)	C load s1 limb
+	ld	r7, 0(r5)	C load s2 limb
+	ADDSUBC	r29, r9, r8
+	ld	r8, 8(r4)	C load s1 limb
+	ld	r9, 8(r5)	C load s2 limb
+	ADDSUBC	r30, r11, r10
+	ld	r10, 16(r4)	C load s1 limb
+	ld	r11, 16(r5)	C load s2 limb
+	ADDSUBC	r31, r0, r12
+	ld	r12, 24(r4)	C load s1 limb
+	ld	r0, 24(r5)	C load s2 limb
+	std	r28, 0(r3)
+	addi	r4, r4, 32
+	std	r29, 8(r3)
+	addi	r5, r5, 32
+	std	r30, 16(r3)
+	std	r31, 24(r3)
+	addi	r3, r3, 32
+	bdnz	L(top)		C decrement ctr and loop back
+
+L(end):	ADDSUBC	r28, r7, r6
+	ADDSUBC	r29, r9, r8
+	ADDSUBC	r30, r11, r10
+	ADDSUBC	r31, r0, r12
+	std	r28, 0(r3)
+	std	r29, 8(r3)
+	std	r30, 16(r3)
+	std	r31, 24(r3)
+
+L(ret):	ld	r31, -8(r1)
+	ld	r30, -16(r1)
+	ld	r29, -24(r1)
+	ld	r28, -32(r1)
+
+	subfe	r3, r0, r0	C -cy
+	GENRVAL
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc64/mode64/aorsmul_1.asm b/third_party/gmp/mpn/powerpc64/mode64/aorsmul_1.asm
new file mode 100644
index 0000000..0c12f9b
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/aorsmul_1.asm
@@ -0,0 +1,225 @@
+dnl  PowerPC-64 mpn_addmul_1 and mpn_submul_1.
+
+dnl  Copyright 1999-2001, 2003-2006, 2010-2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                   mpn_addmul_1    mpn_submul_1
+C                   cycles/limb     cycles/limb
+C POWER3/PPC630		6-18		6-18
+C POWER4/PPC970		 8		 8.3
+C POWER5		 8		 8.25
+C POWER6		16.25		16.75
+C POWER7		 3.77		 4.9
+
+C TODO
+C  * Try to reduce the number of needed live registers
+C  * Add support for _1c entry points
+
+C INPUT PARAMETERS
+define(`rp', `r3')
+define(`up', `r4')
+define(`n',  `r5')
+define(`vl', `r6')
+
+ifdef(`OPERATION_addmul_1',`
+  define(ADDSUBC,	adde)
+  define(ADDSUB,	addc)
+  define(func,		mpn_addmul_1)
+  define(func_nc,	mpn_addmul_1c)	C FIXME: not really supported
+  define(SM,		`')
+')
+ifdef(`OPERATION_submul_1',`
+  define(ADDSUBC,	subfe)
+  define(ADDSUB,	subfc)
+  define(func,		mpn_submul_1)
+  define(func_nc,	mpn_submul_1c)	C FIXME: not really supported
+  define(SM,		`$1')
+')
+
+MULFUNC_PROLOGUE(mpn_addmul_1 mpn_submul_1)
+
+ASM_START()
+PROLOGUE(func)
+	std	r31, -8(r1)
+	rldicl.	r0, n, 0,62	C r0 = n & 3, set cr0
+	std	r30, -16(r1)
+	cmpdi	cr6, r0, 2
+	std	r29, -24(r1)
+	addi	n, n, 3		C compute count...
+	std	r28, -32(r1)
+	srdi	n, n, 2		C ...for ctr
+	std	r27, -40(r1)
+	mtctr	n		C copy count into ctr
+	beq	cr0, L(b00)
+	blt	cr6, L(b01)
+	beq	cr6, L(b10)
+
+L(b11):	ld	r9, 0(up)
+	ld	r28, 0(rp)
+	mulld	r0, r9, r6
+	mulhdu	r12, r9, r6
+	ADDSUB	r0, r0, r28
+	std	r0, 0(rp)
+	addi	rp, rp, 8
+	ld	r9, 8(up)
+	ld	r27, 16(up)
+	addi	up, up, 24
+SM(`	subfe	r11, r11, r11 ')
+	b	L(bot)
+
+	ALIGN(16)
+L(b00):	ld	r9, 0(up)
+	ld	r27, 8(up)
+	ld	r28, 0(rp)
+	ld	r29, 8(rp)
+	mulld	r0, r9, r6
+	mulhdu	r5, r9, r6
+	mulld	r7, r27, r6
+	mulhdu	r8, r27, r6
+	addc	r7, r7, r5
+	addze	r12, r8
+	ADDSUB	r0, r0, r28
+	std	r0, 0(rp)
+	ADDSUBC	r7, r7, r29
+	std	r7, 8(rp)
+	addi	rp, rp, 16
+	ld	r9, 16(up)
+	ld	r27, 24(up)
+	addi	up, up, 32
+SM(`	subfe	r11, r11, r11 ')
+	b	L(bot)
+
+	ALIGN(16)
+L(b01):	bdnz	L(gt1)
+	ld	r9, 0(up)
+	ld	r11, 0(rp)
+	mulld	r0, r9, r6
+	mulhdu	r8, r9, r6
+	ADDSUB	r0, r0, r11
+	std	r0, 0(rp)
+SM(`	subfe	r11, r11, r11 ')
+SM(`	addic	r11, r11, 1 ')
+	addze	r3, r8
+	blr
+L(gt1):	ld	r9, 0(up)
+	ld	r27, 8(up)
+	mulld	r0, r9, r6
+	mulhdu	r5, r9, r6
+	mulld	r7, r27, r6
+	mulhdu	r8, r27, r6
+	ld	r9, 16(up)
+	ld	r28, 0(rp)
+	ld	r29, 8(rp)
+	ld	r30, 16(rp)
+	mulld	r11, r9, r6
+	mulhdu	r10, r9, r6
+	addc	r7, r7, r5
+	adde	r11, r11, r8
+	addze	r12, r10
+	ADDSUB	r0, r0, r28
+	std	r0, 0(rp)
+	ADDSUBC	r7, r7, r29
+	std	r7, 8(rp)
+	ADDSUBC	r11, r11, r30
+	std	r11, 16(rp)
+	addi	rp, rp, 24
+	ld	r9, 24(up)
+	ld	r27, 32(up)
+	addi	up, up, 40
+SM(`	subfe	r11, r11, r11 ')
+	b	L(bot)
+
+L(b10):	addic	r0, r0, 0
+	li	r12, 0		C cy_limb = 0
+	ld	r9, 0(up)
+	ld	r27, 8(up)
+	bdz	L(end)
+	addi	up, up, 16
+
+	ALIGN(16)
+L(top):	mulld	r0, r9, r6
+	mulhdu	r5, r9, r6	C 9
+	mulld	r7, r27, r6
+	mulhdu	r8, r27, r6	C 27
+	ld	r9, 0(up)
+	ld	r28, 0(rp)
+	ld	r27, 8(up)
+	ld	r29, 8(rp)
+	adde	r0, r0, r12	C 0 12
+	adde	r7, r7, r5	C 5 7
+	mulld	r5, r9, r6
+	mulhdu	r10, r9, r6	C 9
+	mulld	r11, r27, r6
+	mulhdu	r12, r27, r6	C 27
+	ld	r9, 16(up)
+	ld	r30, 16(rp)
+	ld	r27, 24(up)
+	ld	r31, 24(rp)
+	adde	r5, r5, r8	C 8 5
+	adde	r11, r11, r10	C 10 11
+	addze	r12, r12	C 12
+	ADDSUB	r0, r0, r28	C 0 28
+	std	r0, 0(rp)	C 0
+	ADDSUBC	r7, r7, r29	C 7 29
+	std	r7, 8(rp)	C 7
+	ADDSUBC	r5, r5, r30	C 5 30
+	std	r5, 16(rp)	C 5
+	ADDSUBC	r11, r11, r31	C 11 31
+	std	r11, 24(rp)	C 11
+	addi	up, up, 32
+SM(`	subfe	r11, r11, r11 ')
+	addi	rp, rp, 32
+L(bot):
+SM(`	addic	r11, r11, 1 ')
+	bdnz	L(top)
+
+L(end):	mulld	r0, r9, r6
+	mulhdu	r5, r9, r6
+	mulld	r7, r27, r6
+	mulhdu	r8, r27, r6
+	ld	r28, 0(rp)
+	ld	r29, 8(rp)
+	adde	r0, r0, r12
+	adde	r7, r7, r5
+	addze	r8, r8
+	ADDSUB	r0, r0, r28
+	std	r0, 0(rp)
+	ADDSUBC	r7, r7, r29
+	std	r7, 8(rp)
+SM(`	subfe	r11, r11, r11 ')
+SM(`	addic	r11, r11, 1 ')
+	addze	r3, r8
+	ld	r31, -8(r1)
+	ld	r30, -16(r1)
+	ld	r29, -24(r1)
+	ld	r28, -32(r1)
+	ld	r27, -40(r1)
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc64/mode64/aorsorrlsh1_n.asm b/third_party/gmp/mpn/powerpc64/mode64/aorsorrlsh1_n.asm
new file mode 100644
index 0000000..2c5400a
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/aorsorrlsh1_n.asm
@@ -0,0 +1,43 @@
+dnl  PowerPC-64 mpn_addlsh1_n, mpn_sublsh1_n, mpn_rsblsh1_n.
+
+dnl  Copyright 2003, 2005, 2009, 2010, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+define(LSH,		1)
+define(RSH,		63)
+
+ifdef(`OPERATION_addlsh1_n',`define(`DO_add')')
+ifdef(`OPERATION_sublsh1_n',`define(`DO_sub')')
+ifdef(`OPERATION_rsblsh1_n',`define(`DO_rsb')')
+
+MULFUNC_PROLOGUE(mpn_addlsh1_n mpn_sublsh1_n mpn_rsblsh1_n)
+
+include_mpn(`powerpc64/mode64/aorsorrlshC_n.asm')
diff --git a/third_party/gmp/mpn/powerpc64/mode64/aorsorrlsh2_n.asm b/third_party/gmp/mpn/powerpc64/mode64/aorsorrlsh2_n.asm
new file mode 100644
index 0000000..447791a
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/aorsorrlsh2_n.asm
@@ -0,0 +1,43 @@
+dnl  PowerPC-64 mpn_addlsh2_n, mpn_sublsh2_n, mpn_rsblsh2_n.
+
+dnl  Copyright 2003, 2005, 2009, 2010, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+define(LSH,		2)
+define(RSH,		62)
+
+ifdef(`OPERATION_addlsh2_n',`define(`DO_add')')
+ifdef(`OPERATION_sublsh2_n',`define(`DO_sub')')
+ifdef(`OPERATION_rsblsh2_n',`define(`DO_rsb')')
+
+MULFUNC_PROLOGUE(mpn_addlsh2_n mpn_sublsh2_n mpn_rsblsh2_n)
+
+include_mpn(`powerpc64/mode64/aorsorrlshC_n.asm')
diff --git a/third_party/gmp/mpn/powerpc64/mode64/aorsorrlshC_n.asm b/third_party/gmp/mpn/powerpc64/mode64/aorsorrlshC_n.asm
new file mode 100644
index 0000000..6158f54
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/aorsorrlshC_n.asm
@@ -0,0 +1,187 @@
+dnl  PowerPC-64 mpn_addlshC_n, mpn_sublshC_n, mpn_rsblshC_n.
+
+dnl  Copyright 2003, 2005, 2009, 2010, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+C                  cycles/limb
+C POWER3/PPC630          1.83   (1.5 c/l should be possible)
+C POWER4/PPC970          3      (2.0 c/l should be possible)
+C POWER5                 3
+C POWER6              3.5-47
+C POWER7                 3
+
+C STATUS
+C  * Try combining upx+up, and vpx+vp.
+C  * The worst case 47 c/l for POWER6 happens if the 3rd operand for ldx is
+C    greater than the 2nd operand.  Yes, this addition is non-commutative wrt
+C    performance.
+
+C INPUT PARAMETERS
+define(`rp', `r3')
+define(`up', `r4')
+define(`vp', `r5')
+define(`n',  `r6')
+
+ifdef(`DO_add', `
+  define(`ADDSUBC',	`addc	$1, $2, $3')
+  define(`ADDSUBE',	`adde	$1, $2, $3')
+  define(INITCY,	`addic	$1, r1, 0')
+  define(RETVAL,	`addze	r3, $1')
+  define(`func',	mpn_addlsh`'LSH`'_n)')
+ifdef(`DO_sub', `
+  define(`ADDSUBC',	`subfc	$1, $2, $3')
+  define(`ADDSUBE',	`subfe	$1, $2, $3')
+  define(INITCY,	`addic	$1, r1, -1')
+  define(RETVAL,	`subfze	r3, $1
+			neg	r3, r3')
+  define(`func',	mpn_sublsh`'LSH`'_n)')
+ifdef(`DO_rsb', `
+  define(`ADDSUBC',	`subfc	$1, $3, $2')
+  define(`ADDSUBE',	`subfe	$1, $3, $2')
+  define(INITCY,	`addic	$1, r1, -1')
+  define(RETVAL,	`addme	r3, $1')
+  define(`func',	mpn_rsblsh`'LSH`'_n)')
+
+define(`rpx', `r6')
+define(`upx', `r7')
+define(`vpx', `r12')
+
+define(`s0', `r0')  define(`s1', `r9')
+define(`u0', `r8')
+define(`v0', `r10') define(`v1', `r11')
+
+
+ASM_START()
+PROLOGUE(func)
+	cmpldi	cr0, n, 13
+	bgt	L(big)
+
+	mtctr	n		C copy n in ctr
+	INITCY(	r0)		C clear cy
+
+	ld	v0, 0(vp)	C load v limb
+	ld	u0, 0(up)	C load u limb
+	addi	up, up, -8	C update up
+	addi	rp, rp, -8	C update rp
+	sldi	s1, v0, LSH
+	bdz	L(ex1)		C If done, skip loop
+
+	ALIGN(16)
+L(lo0):	ld	v1, 8(vp)	C load v limb
+	ADDSUBE(s1, s1, u0)	C add limbs with cy, set cy
+	ldu	u0, 16(up)	C load u limb and update up
+	srdi	s0, v0, RSH	C shift down previous v limb
+	std	s1, 8(rp)	C store result limb
+	rldimi	s0, v1, LSH, 0	C left shift v limb and merge with prev v limb
+	bdz	L(ex0)		C decrement ctr and exit if done
+	ldu	v0, 16(vp)	C load v limb and update vp
+	ADDSUBE(s0, s0, u0)	C add limbs with cy, set cy
+	ld	u0, 8(up)	C load u limb
+	srdi	s1, v1, RSH	C shift down previous v limb
+	stdu	s0, 16(rp)	C store result limb and update rp
+	rldimi	s1, v0, LSH, 0	C left shift v limb and merge with prev v limb
+	bdnz	L(lo0)		C decrement ctr and loop back
+
+L(ex1):	ADDSUBE(r7, s1, u0)
+	std	r7, 8(rp)	C store last result limb
+	srdi	r0, v0, RSH
+	RETVAL(	r0)
+	blr
+L(ex0):	ADDSUBE(r7, s0, u0)
+	std	r7, 16(rp)	C store last result limb
+	srdi	r0, v1, RSH
+	RETVAL(	r0)
+	blr
+
+
+L(big):	rldicl.	r0, n, 0,63	C r0 = n & 1, set cr0
+	addi	r6, n, -1	C ...for ctr
+	srdi	r6, r6, 1	C ...for ctr
+	mtctr	r6		C copy count into ctr
+	beq	cr0, L(b0)
+
+L(b1):	ld	v1, 0(vp)
+	ld	u0, 0(up)
+	sldi	s1, v1, LSH
+	srdi	s0, v1, RSH
+	ld	v0, 8(vp)
+	ADDSUBC(s1, s1, u0)	C add limbs without cy, set cy
+	addi	rpx, rp, -16
+	addi	rp, rp, -8
+	sub	upx, up, rp
+	sub	vpx, vp, rp
+	sub	up, up, rpx
+	sub	vp, vp, rpx
+	addi	up, up, 8
+	addi	upx, upx, 16
+	addi	vp, vp, 16
+	addi	vpx, vpx, 24
+	b	L(mid)
+
+L(b0):	ld	v0, 0(vp)
+	ld	u0, 0(up)
+	sldi	s0, v0, LSH
+	srdi	s1, v0, RSH
+	ld	v1, 8(vp)
+	ADDSUBC(s0, s0, u0)	C add limbs without cy, set cy
+	addi	rpx, rp, -8
+	addi	rp, rp, -16
+	sub	upx, up, rpx
+	sub	vpx, vp, rpx
+	sub	up, up, rp
+	sub	vp, vp, rp
+	addi	up, up, 8
+	addi	upx, upx, 16
+	addi	vp, vp, 16
+	addi	vpx, vpx, 24
+
+	ALIGN(32)
+L(top):	ldx	u0, rp, up
+	ldx	v0, rp, vp
+	rldimi	s1, v1, LSH, 0
+	stdu	s0, 16(rp)
+	srdi	s0, v1, RSH
+	ADDSUBE(s1, s1, u0)	C add limbs with cy, set cy
+L(mid):	ldx	u0, rpx, upx
+	ldx	v1, rpx, vpx
+	rldimi	s0, v0, LSH, 0
+	stdu	s1, 16(rpx)
+	srdi	s1, v0, RSH
+	ADDSUBE(s0, s0, u0)	C add limbs with cy, set cy
+	bdnz	L(top)		C decrement CTR and loop back
+
+	ldx	u0, rp, up
+	rldimi	s1, v1, LSH, 0
+	std	s0, 16(rp)
+	srdi	s0, v1, RSH
+	ADDSUBE(s1, s1, u0)	C add limbs with cy, set cy
+	std	s1, 24(rp)
+
+	RETVAL(	s0)
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc64/mode64/bdiv_dbm1c.asm b/third_party/gmp/mpn/powerpc64/mode64/bdiv_dbm1c.asm
new file mode 100644
index 0000000..45cded9
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/bdiv_dbm1c.asm
@@ -0,0 +1,132 @@
+dnl  PPC64 mpn_bdiv_dbm1c.
+
+dnl  Copyright 2008, 2010 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                 cycles/limb
+C POWER3/PPC630       6-18
+C POWER4/PPC970       8.25
+C POWER5              8.5  fluctuating as function of n % 3
+C POWER6             15
+C POWER7              4.75
+
+C TODO
+C  * Nothing to do...
+
+C INPUT PARAMETERS
+define(`rp', `r3')
+define(`up', `r4')
+define(`n',  `r5')
+define(`bd', `r6')
+define(`cy', `r7')
+
+ASM_START()
+PROLOGUE(mpn_bdiv_dbm1c)
+	ld	r0, 0(r4)
+
+	rldicl.	r12, r5, 0,62
+	cmpldi	cr6, r12, 2
+	cmpldi	cr7, r5, 4
+	addi	r5, r5, 1
+	srwi	r5, r5, 2
+	mtctr	r5
+	beq	cr0, L(b00)
+	blt	cr6, L(b01)
+	beq	cr6, L(b10)
+
+	ALIGN(16)
+L(b11):	mulld	r5, r0, r6
+	mulhdu	r12, r0, r6
+	ld	r0, 8(r4)
+	addi	r4, r4, -24
+	addi	r3, r3, -24
+	b	L(3)
+
+	ALIGN(16)
+L(b00):	mulld	r9, r0, r6
+	mulhdu	r8, r0, r6
+	addi	r4, r4, -16
+	addi	r3, r3, -16
+	b	L(0)
+
+	ALIGN(16)
+L(b01):	mulld	r5, r0, r6
+	mulhdu	r12, r0, r6
+	addi	r3, r3, -8
+	ble	cr7, L(e1)
+	ld	r0, 8(r4)
+	addi	r4, r4, -8
+	b	L(1)
+
+	ALIGN(16)
+L(b10):	mulld	r9, r0, r6
+	mulhdu	r8, r0, r6
+	ble	cr7, L(e2)
+
+	ALIGN(16)
+L(top):	subfc	r11, r9, r7
+	ld	r10, 8(r4)
+	ld	r0, 16(r4)
+	subfe	r7, r8, r11
+	std	r11, 0(r3)
+	mulld	r5, r10, r6
+	mulhdu	r12, r10, r6
+L(1):	mulld	r9, r0, r6
+	mulhdu	r8, r0, r6
+	subfc	r11, r5, r7
+	subfe	r7, r12, r11
+	std	r11, 8(r3)
+L(0):	subfc	r11, r9, r7
+	ld	r10, 24(r4)
+	ld	r0, 32(r4)
+	subfe	r7, r8, r11
+	std	r11, 16(r3)
+	mulld	r5, r10, r6
+	mulhdu	r12, r10, r6
+L(3):	mulld	r9, r0, r6
+	mulhdu	r8, r0, r6
+	subfc	r11, r5, r7
+	subfe	r7, r12, r11
+	std	r11, 24(r3)
+	addi	r4, r4, 32
+	addi	r3, r3, 32
+	bdnz	L(top)
+
+L(e2):	ld	r10, 8(r4)
+	mulld	r5, r10, r6
+	mulhdu	r12, r10, r6
+	subfc	r11, r9, r7
+	subfe	r7, r8, r11
+	std	r11, 0(r3)
+L(e1):	subfc	r11, r5, r7
+	std	r11, 8(r3)
+	subfe	r3, r12, r11
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc64/mode64/bdiv_q_1.asm b/third_party/gmp/mpn/powerpc64/mode64/bdiv_q_1.asm
new file mode 100644
index 0000000..307aafc
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/bdiv_q_1.asm
@@ -0,0 +1,146 @@
+dnl  PowerPC-64 mpn_bdiv_q_1, mpn_pi1_bdiv_q_1 -- Hensel division by 1-limb
+dnl  divisor.
+
+dnl  Copyright 2006, 2010, 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C			cycles/limb
+C			norm	unorm
+C POWER3/PPC630	       13-19
+C POWER4/PPC970		16
+C POWER5		16	16
+C POWER6		37	46
+C POWER7		12	12
+C POWER8		12	12
+
+C INPUT PARAMETERS
+define(`rp', `r3')
+define(`up', `r4')
+define(`n',  `r5')
+define(`d',  `r6')
+define(`di', `r7')
+define(`cnt',`r8')
+
+define(`tnc',`r10')
+
+ASM_START()
+
+EXTERN(binvert_limb_table)
+
+PROLOGUE(mpn_bdiv_q_1,toc)
+	addi	r7, n, -1
+	cmpdi	cr1, n, 1
+	ld	r12, 0(up)
+	li	cnt, 0
+	neg	r0, d
+	and	r0, d, r0
+	cntlzd	r0, r0
+	subfic	cnt, r0, 63
+	srd	d, d, cnt
+L(7):
+	mtctr	r7
+	LEA(	r10, binvert_limb_table)
+	rldicl	r11, d, 63, 57
+	lbzx	r0, r10, r11
+	mulld	r9, r0, r0
+	sldi	r0, r0, 1
+	mulld	r9, d, r9
+	subf	r0, r9, r0
+	mulld	r10, r0, r0
+	sldi	r0, r0, 1
+	mulld	r10, d, r10
+	subf	r0, r10, r0
+	mulld	r9, r0, r0
+	sldi	r0, r0, 1
+	mulld	r9, d, r9
+	subf	di, r9, r0		C di = 1/d mod 2^64
+ifdef(`AIX',
+`	C For AIX it is not clear how to jump into another function.
+	b	.mpn_pi1_bdiv_q_1
+',`
+	C For non-AIX, dispatch into the pi1 variant.
+	bne	cr0, L(norm)
+	b	L(unorm)
+')
+EPILOGUE()
+
+PROLOGUE(mpn_pi1_bdiv_q_1)
+	cmpdi	cr0, cnt, 0
+	ld	r12, 0(up)
+	addic	r0, n, -1		C set carry as side effect
+	cmpdi	cr1, n, 1
+	mtctr	r0
+	beq	cr0, L(norm)
+
+L(unorm):
+	subfic	tnc, cnt, 64		C set carry as side effect
+	li	r5, 0
+	srd	r11, r12, cnt
+	beq	cr1, L(ed1)
+
+	ALIGN(16)
+L(tpu):	ld	r12, 8(up)
+	nop
+	addi	up, up, 8
+	sld	r0, r12, tnc
+	or	r11, r11, r0
+	subfe	r9, r5, r11
+	srd	r11, r12, cnt
+	mulld	r0, di, r9
+	mulhdu	r5, r0, d
+	std	r0, 0(rp)
+	addi	rp, rp, 8
+	bdnz	L(tpu)
+
+	subfe	r11, r5, r11
+L(ed1):	mulld	r0, di, r11
+	std	r0, 0(rp)
+	blr
+
+	ALIGN(16)
+L(norm):
+	mulld	r11, r12, di
+	mulhdu	r5, r11, d
+	std	r11, 0(rp)
+	beqlr	cr1
+
+	ALIGN(16)
+L(tpn):	ld	r9, 8(up)
+	addi	up, up, 8
+	subfe	r5, r5, r9
+	mulld	r11, di, r5
+	mulhdu	r5, r11, d	C result not used in last iteration
+	std	r11, 8(rp)
+	addi	rp, rp, 8
+	bdnz	L(tpn)
+
+	blr
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/powerpc64/mode64/cnd_aors_n.asm b/third_party/gmp/mpn/powerpc64/mode64/cnd_aors_n.asm
new file mode 100644
index 0000000..24968c1
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/cnd_aors_n.asm
@@ -0,0 +1,196 @@
+dnl  PowerPC-64 mpn_cnd_add_n/mpn_cnd_sub_n.
+
+dnl  Copyright 1999-2001, 2003-2005, 2007, 2011, 2012 Free Software Foundation,
+dnl  Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                   cycles/limb
+C POWER3/PPC630          ?
+C POWER4/PPC970          2.25
+C POWER5                 ?
+C POWER6                 3
+C POWER7                 2
+
+C INPUT PARAMETERS
+define(`cnd',  `r3')
+define(`rp',   `r4')
+define(`up',   `r5')
+define(`vp',   `r6')
+define(`n',    `r7')
+
+ifdef(`OPERATION_cnd_add_n',`
+  define(ADDSUBC,	adde)
+  define(ADDSUB,	addc)
+  define(func,		mpn_cnd_add_n)
+  define(GENRVAL,	`addi	r3, r3, 1')
+  define(SETCBR,	`addic	r0, $1, -1')
+  define(CLRCB,		`addic	r0, r0, 0')
+')
+ifdef(`OPERATION_cnd_sub_n',`
+  define(ADDSUBC,	subfe)
+  define(ADDSUB,	subfc)
+  define(func,		mpn_cnd_sub_n)
+  define(GENRVAL,	`neg	r3, r3')
+  define(SETCBR,	`subfic	r0, $1, 0')
+  define(CLRCB,		`addic	r0, r1, -1')
+')
+
+MULFUNC_PROLOGUE(mpn_cnd_add_n mpn_cnd_sub_n)
+
+ASM_START()
+PROLOGUE(func)
+	std	r31, -8(r1)
+	std	r30, -16(r1)
+	std	r29, -24(r1)
+	std	r28, -32(r1)
+	std	r27, -40(r1)
+
+	subfic	cnd, cnd, 0
+	subfe	cnd, cnd, cnd
+
+	rldicl.	r0, n, 0,62	C r0 = n & 3, set cr0
+	cmpdi	cr6, r0, 2
+	addi	n, n, 3	C compute count...
+	srdi	n, n, 2	C ...for ctr
+	mtctr	n		C copy count into ctr
+	beq	cr0, L(b00)
+	blt	cr6, L(b01)
+	beq	cr6, L(b10)
+
+L(b11):	ld	r8, 0(up)	C load s1 limb
+	ld	r9, 0(vp)	C load s2 limb
+	ld	r10, 8(up)	C load s1 limb
+	ld	r11, 8(vp)	C load s2 limb
+	ld	r12, 16(up)	C load s1 limb
+	addi	up, up, 24
+	ld	r0, 16(vp)	C load s2 limb
+	addi	vp, vp, 24
+	and	r9, r9, cnd
+	and	r11, r11, cnd
+	and	r0, r0, cnd
+	ADDSUB	r29, r9, r8
+	ADDSUBC	r30, r11, r10
+	ADDSUBC	r31, r0, r12
+	std	r29, 0(rp)
+	std	r30, 8(rp)
+	std	r31, 16(rp)
+	addi	rp, rp, 24
+	bdnz	L(go)
+	b	L(ret)
+
+L(b01):	ld	r12, 0(up)	C load s1 limb
+	addi	up, up, 8
+	ld	r0, 0(vp)	C load s2 limb
+	addi	vp, vp, 8
+	and	r0, r0, cnd
+	ADDSUB	r31, r0, r12	C add
+	std	r31, 0(rp)
+	addi	rp, rp, 8
+	bdnz	L(go)
+	b	L(ret)
+
+L(b10):	ld	r10, 0(up)	C load s1 limb
+	ld	r11, 0(vp)	C load s2 limb
+	ld	r12, 8(up)	C load s1 limb
+	addi	up, up, 16
+	ld	r0, 8(vp)	C load s2 limb
+	addi	vp, vp, 16
+	and	r11, r11, cnd
+	and	r0, r0, cnd
+	ADDSUB	r30, r11, r10	C add
+	ADDSUBC	r31, r0, r12	C add
+	std	r30, 0(rp)
+	std	r31, 8(rp)
+	addi	rp, rp, 16
+	bdnz	L(go)
+	b	L(ret)
+
+L(b00):	CLRCB			C clear/set cy
+L(go):	ld	r7, 0(up)	C load s1 limb
+	ld	r27, 0(vp)	C load s2 limb
+	ld	r8, 8(up)	C load s1 limb
+	ld	r9, 8(vp)	C load s2 limb
+	ld	r10, 16(up)	C load s1 limb
+	ld	r11, 16(vp)	C load s2 limb
+	ld	r12, 24(up)	C load s1 limb
+	ld	r0, 24(vp)	C load s2 limb
+	and	r27, r27, cnd
+	and	r9, r9, cnd
+	and	r11, r11, cnd
+	and	r0, r0, cnd
+	bdz	L(end)
+
+	addi	up, up, 32
+	addi	vp, vp, 32
+
+L(top):	ADDSUBC	r28, r27, r7
+	ld	r7, 0(up)	C load s1 limb
+	ld	r27, 0(vp)	C load s2 limb
+	ADDSUBC	r29, r9, r8
+	ld	r8, 8(up)	C load s1 limb
+	ld	r9, 8(vp)	C load s2 limb
+	ADDSUBC	r30, r11, r10
+	ld	r10, 16(up)	C load s1 limb
+	ld	r11, 16(vp)	C load s2 limb
+	ADDSUBC	r31, r0, r12
+	ld	r12, 24(up)	C load s1 limb
+	ld	r0, 24(vp)	C load s2 limb
+	std	r28, 0(rp)
+	addi	up, up, 32
+	std	r29, 8(rp)
+	addi	vp, vp, 32
+	std	r30, 16(rp)
+	std	r31, 24(rp)
+	addi	rp, rp, 32
+	and	r27, r27, cnd
+	and	r9, r9, cnd
+	and	r11, r11, cnd
+	and	r0, r0, cnd
+	bdnz	L(top)		C decrement ctr and loop back
+
+L(end):	ADDSUBC	r28, r27, r7
+	ADDSUBC	r29, r9, r8
+	ADDSUBC	r30, r11, r10
+	ADDSUBC	r31, r0, r12
+	std	r28, 0(rp)
+	std	r29, 8(rp)
+	std	r30, 16(rp)
+	std	r31, 24(rp)
+
+L(ret):	ld	r31, -8(r1)
+	ld	r30, -16(r1)
+	ld	r29, -24(r1)
+	ld	r28, -32(r1)
+	ld	r27, -40(r1)
+
+	subfe	r3, r0, r0	C -cy
+	GENRVAL
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc64/mode64/dive_1.asm b/third_party/gmp/mpn/powerpc64/mode64/dive_1.asm
new file mode 100644
index 0000000..c2d10bd
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/dive_1.asm
@@ -0,0 +1,135 @@
+dnl  PowerPC-64 mpn_divexact_1 -- mpn by limb exact division.
+
+dnl  Copyright 2006, 2010 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C			cycles/limb
+C			norm	unorm
+C POWER3/PPC630	       13-19
+C POWER4/PPC970		16
+C POWER5		16	16
+C POWER6		37	46
+C POWER7		12	12
+C POWER8		12	12
+
+C TODO
+C  * Check if n=1 code is really an improvement.  It probably isn't.
+C  * Make more similar to mode1o.asm.
+
+C INPUT PARAMETERS
+define(`rp', `r3')
+define(`up', `r4')
+define(`n',  `r5')
+define(`d',  `r6')
+
+
+ASM_START()
+
+EXTERN(binvert_limb_table)
+
+PROLOGUE(mpn_divexact_1,toc)
+	addic.	n, n, -1
+	ld	r12, 0(up)
+	bne	cr0, L(2)
+	divdu	r0, r12, d
+	std	r0, 0(rp)
+	blr
+L(2):
+	rldicl.	r0, d, 0, 63
+	li	r10, 0
+	bne	cr0, L(7)
+	neg	r0, d
+	and	r0, d, r0
+	cntlzd	r0, r0
+	subfic	r0, r0, 63
+	rldicl	r10, r0, 0, 32
+	srd	d, d, r0
+L(7):
+	mtctr	n
+	LEA(	r5, binvert_limb_table)
+	rldicl	r11, d, 63, 57
+	lbzx	r0, r5, r11
+	mulld	r9, r0, r0
+	sldi	r0, r0, 1
+	mulld	r9, d, r9
+	subf	r0, r9, r0
+	mulld	r5, r0, r0
+	sldi	r0, r0, 1
+	mulld	r5, d, r5
+	subf	r0, r5, r0
+	mulld	r9, r0, r0
+	sldi	r0, r0, 1
+	mulld	r9, d, r9
+	subf	r7, r9, r0		C r7 = 1/d mod 2^64
+
+	bne	cr0, L(norm)
+	subfic	r8, r10, 64		C set carry as side effect
+	li	r5, 0
+	srd	r11, r12, r10
+
+	ALIGN(16)
+L(loop0):
+	ld	r12, 8(up)
+	nop
+	addi	up, up, 8
+	sld	r0, r12, r8
+	or	r11, r11, r0
+	subfe	r9, r5, r11
+	srd	r11, r12, r10
+	mulld	r0, r7, r9
+	mulhdu	r5, r0, d
+	std	r0, 0(rp)
+	addi	rp, rp, 8
+	bdnz	L(loop0)
+
+	subfe	r0, r5, r11
+	mulld	r0, r7, r0
+	std	r0, 0(rp)
+	blr
+
+	ALIGN(16)
+L(norm):
+	mulld	r11, r12, r7
+	mulhdu	r5, r11, d
+	std	r11, 0(rp)
+	ALIGN(16)
+L(loop1):
+	ld	r9, 8(up)
+	addi	up, up, 8
+	subfe	r5, r5, r9
+	mulld	r11, r7, r5
+	mulhdu	r5, r11, d	C result not used in last iteration
+	std	r11, 8(rp)
+	addi	rp, rp, 8
+	bdnz	L(loop1)
+
+	blr
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/powerpc64/mode64/divrem_1.asm b/third_party/gmp/mpn/powerpc64/mode64/divrem_1.asm
new file mode 100644
index 0000000..b283877
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/divrem_1.asm
@@ -0,0 +1,274 @@
+dnl  PowerPC-64 mpn_divrem_1 -- Divide an mpn number by an unnormalized limb.
+
+dnl  Copyright 2003-2005, 2007, 2008, 2010, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                           cycles/limb
+C                       norm    unorm   frac
+C POWER3/PPC630         16-34   16-34   ~11   outdated figures
+C POWER4/PPC970          28      28      19
+C POWER5                 29      29     ~19
+C POWER6                 49      59     ~42
+C POWER7                 24.5    23     ~14
+
+C INPUT PARAMETERS
+C qp  = r3
+C fn  = r4
+C up  = r5
+C un  = r6
+C d   = r7
+
+C We use a not very predictable branch in the frac code, therefore the cycle
+C count wobbles somewhat.  With the alternative branch-free code, things run
+C considerably slower on POWER4/PPC970 and POWER5.
+
+C Add preinv entry point.
+
+
+ASM_START()
+
+EXTERN_FUNC(mpn_invert_limb)
+
+PROLOGUE(mpn_divrem_1,toc)
+
+	mfcr	r12
+	add.	r10, r6, r4
+	std	r25, -56(r1)
+	mr	r25, r4
+	mflr	r0
+	std	r26, -48(r1)
+	mr	r26, r5
+	std	r28, -32(r1)
+	mr	r28, r6
+	std	r29, -24(r1)
+	mr	r29, r3
+	li	r3, 0
+	std	r30, -16(r1)
+	mr	r30, r7
+	std	r31, -8(r1)
+	li	r31, 0
+	std	r27, -40(r1)
+	std	r0, 16(r1)
+	stw	r12, 8(r1)
+	stdu	r1, -176(r1)
+	beq-	cr0, L(1)
+	cmpdi	cr7, r7, 0
+	sldi	r0, r10, 3
+	add	r11, r0, r29
+	addi	r29, r11, -8
+	blt-	cr7, L(162)
+	cmpdi	cr4, r6, 0
+	beq+	cr4, L(71)
+L(163):
+	sldi	r9, r6, 3
+	add	r9, r9, r5
+	ld	r7, -8(r9)
+	cmpld	cr7, r7, r30
+	bge-	cr7, L(71)
+	cmpdi	cr7, r10, 1
+	li	r0, 0
+	mr	r31, r7
+	std	r0, -8(r11)
+	addi	r29, r29, -8
+	mr	r3, r7
+	beq-	cr7, L(1)
+	addi	r28, r6, -1
+	cmpdi	cr4, r28, 0
+L(71):
+	cntlzd	r27, r30
+	sld	r30, r30, r27
+	sld	r31, r31, r27
+	mr	r3, r30
+	CALL(	mpn_invert_limb)
+	beq-	cr4, L(110)
+	sldi	r9, r28, 3
+	addic.	r6, r28, -2
+	add	r9, r9, r26
+	subfic	r5, r27, 64
+	ld	r8, -8(r9)
+	srd	r0, r8, r5
+	or	r31, r31, r0
+	sld	r7, r8, r27
+	blt-	cr0, L(154)
+	addi	r28, r28, -1
+	mtctr	r28
+	sldi	r6, r6, 3
+	ALIGN(16)
+L(uloop):
+	ldx	r8, r26, r6
+	nop
+	mulld	r0, r31, r3
+	mulhdu	r10, r31, r3
+	addi	r11, r31, 1
+	srd	r9, r8, r5
+	addi	r6, r6, -8
+	or	r9, r7, r9
+	addc	r0, r0, r9
+	adde	r10, r10, r11
+	mulld	r31, r10, r30
+	subf	r31, r31, r9
+	subfc	r0, r31, r0	C r <= ql
+	subfe	r0, r0, r0	C r0 = -(r <= ql)
+	and	r9, r30, r0
+	add	r31, r31, r9
+	add	r10, r0, r10	C qh -= (r >= ql)
+	cmpld	cr7, r31, r30
+	bge-	cr7, L(164)
+L(123):
+	std	r10, 0(r29)
+	addi	r29, r29, -8
+	sld	r7, r8, r27
+	bdnz	L(uloop)
+L(154):
+	addi	r11, r31, 1
+	nop
+	mulld	r0, r31, r3
+	mulhdu	r8, r31, r3
+	addc	r0, r0, r7
+	adde	r8, r8, r11
+	mulld	r31, r8, r30
+	subf	r31, r31, r7
+	subfc	r0, r0, r31	C r >= ql
+	subfe	r0, r0, r0	C r0 = -(r >= ql)
+	not	r7, r0
+	add	r8, r7, r8	C qh -= (r >= ql)
+	andc	r0, r30, r0
+	add	r31, r31, r0
+	cmpld	cr7, r31, r30
+	bge-	cr7, L(165)
+L(134):
+	std	r8, 0(r29)
+	addi	r29, r29, -8
+L(110):
+	addic.	r0, r25, -1
+	blt-	cr0, L(156)
+	mtctr	r25
+	neg	r9, r30
+	ALIGN(16)
+L(ufloop):
+	addi	r11, r31, 1
+	nop
+	mulld	r0, r3, r31
+	mulhdu	r10, r3, r31
+	add	r10, r10, r11
+	mulld	r31, r9, r10
+ifelse(0,1,`
+	subfc	r0, r0, r31
+	subfe	r0, r0, r0	C r0 = -(r >= ql)
+	not	r7, r0
+	add	r10, r7, r10	C qh -= (r >= ql)
+	andc	r0, r30, r0
+	add	r31, r31, r0
+',`
+	cmpld	cr7, r31, r0
+	blt	cr7, L(29)
+	add	r31, r30, r31
+	addi	r10, r10, -1
+L(29):
+')
+	std	r10, 0(r29)
+	addi	r29, r29, -8
+	bdnz	L(ufloop)
+L(156):
+	srd	r3, r31, r27
+L(1):
+	addi	r1, r1, 176
+	ld	r0, 16(r1)
+	lwz	r12, 8(r1)
+	mtlr	r0
+	ld	r25, -56(r1)
+	ld	r26, -48(r1)
+	mtcrf	8, r12
+	ld	r27, -40(r1)
+	ld	r28, -32(r1)
+	ld	r29, -24(r1)
+	ld	r30, -16(r1)
+	ld	r31, -8(r1)
+	blr
+L(162):
+	cmpdi	cr7, r6, 0
+	beq-	cr7, L(8)
+	sldi	r9, r6, 3
+	addi	r29, r29, -8
+	add	r9, r9, r5
+	addi	r28, r6, -1
+	ld	r31, -8(r9)
+	subfc	r9, r7, r31
+	li	r9, 0
+	adde	r9, r9, r9
+	neg	r0, r9
+	std	r9, -8(r11)
+	and	r0, r0, r7
+	subf	r31, r0, r31
+L(8):
+	mr	r3, r30
+	CALL(	mpn_invert_limb)
+	li	r27, 0
+	addic.	r6, r28, -1
+	blt-	cr0, L(110)
+	mtctr	r28
+	sldi	r6, r6, 3
+	ALIGN(16)
+L(nloop):
+	addi	r11, r31, 1
+	ldx	r8, r26, r6
+	mulld	r0, r31, r3
+	mulhdu	r10, r31, r3
+	addi	r6, r6, -8
+	addc	r0, r0, r8
+	adde	r10, r10, r11
+	mulld	r31, r10, r30
+	subf	r31, r31, r8	C r = nl - qh * d
+	subfc	r0, r31, r0	C r <= ql
+	subfe	r0, r0, r0	C r0 = -(r <= ql)
+	and	r9, r30, r0
+	add	r31, r31, r9
+	add	r10, r0, r10	C qh -= (r >= ql)
+	cmpld	cr7, r31, r30
+	bge-	cr7, L(167)
+L(51):
+	std	r10, 0(r29)
+	addi	r29, r29, -8
+	bdnz	L(nloop)
+	b	L(110)
+
+L(164):
+	subf	r31, r30, r31
+	addi	r10, r10, 1
+	b	L(123)
+L(167):
+	subf	r31, r30, r31
+	addi	r10, r10, 1
+	b	L(51)
+L(165):
+	subf	r31, r30, r31
+	addi	r8, r8, 1
+	b	L(134)
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc64/mode64/divrem_2.asm b/third_party/gmp/mpn/powerpc64/mode64/divrem_2.asm
new file mode 100644
index 0000000..752c3d6
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/divrem_2.asm
@@ -0,0 +1,187 @@
+dnl  PPC-64 mpn_divrem_2 -- Divide an mpn number by a normalized 2-limb number.
+
+dnl  Copyright 2007, 2008 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                       cycles/limb
+C                       norm    frac
+C POWER3/PPC630
+C POWER4/PPC970         ?       ?
+C POWER5                37      ?
+C POWER6                62      ?
+C POWER6                30.5    ?
+
+C INPUT PARAMETERS
+C qp  = r3
+C fn  = r4
+C up  = r5
+C un  = r6
+C dp  = r7
+
+
+ifdef(`DARWIN',,`
+define(`r2',`r31')')		C FIXME!
+
+ASM_START()
+
+EXTERN_FUNC(mpn_invert_limb)
+
+PROLOGUE(mpn_divrem_2,toc)
+	mflr	r0
+	std	r23, -72(r1)
+	std	r24, -64(r1)
+	std	r25, -56(r1)
+	std	r26, -48(r1)
+	std	r27, -40(r1)
+	std	r28, -32(r1)
+	std	r29, -24(r1)
+	std	r30, -16(r1)
+	std	r31, -8(r1)
+	std	r0, 16(r1)
+	stdu	r1, -192(r1)
+	mr	r24, r3
+	mr	r25, r4
+	sldi	r0, r6, 3
+	add	r26, r5, r0
+	addi	r26, r26, -24
+	ld	r30, 8(r7)
+	ld	r28, 0(r7)
+	ld	r29, 16(r26)
+	ld	r31, 8(r26)
+
+ifelse(0,1,`
+	li	r23, 0
+	cmpld	cr7, r29, r30
+	blt	cr7, L(8)
+	bgt	cr7, L(9)
+	cmpld	cr0, r31, r28
+	blt	cr0, L(8)
+L(9):	subfc	r31, r28, r31
+	subfe	r29, r30, r29
+	li	r23, 1
+',`
+	li	r23, 0
+	cmpld	cr7, r29, r30
+	blt	cr7, L(8)
+	mfcr	r0
+	rlwinm	r0, r0, 30, 31, 31
+	subfc	r9, r28, r31
+	addze.	r0, r0
+	nop
+	beq	cr0, L(8)
+	subfc	r31, r28, r31
+	subfe	r29, r30, r29
+	li	r23, 1
+')
+
+L(8):
+	add	r27, r25, r6
+	addic.	r27, r27, -3
+	blt	cr0, L(18)
+	mr	r3, r30
+	CALL(	mpn_invert_limb)
+	mulld	r10, r3, r30
+	mulhdu	r0, r3, r28
+	addc	r8, r10, r28
+	subfe	r11, r1, r1
+	addc	r10, r8, r0
+	addze.	r11, r11
+	blt	cr0, L(91)
+L(40):
+	subfc	r10, r30, r10
+	addme.	r11, r11
+	addi	r3, r3, -1
+	bge	cr0, L(40)
+L(91):
+	addi	r5, r27,  1
+	mtctr	r5
+	sldi	r0, r27, 3
+	add	r24, r24, r0
+	ALIGN(16)
+L(loop):
+	mulhdu	r8, r29, r3
+	mulld	r6, r29, r3
+	addc	r6, r6, r31
+	adde	r8, r8, r29
+	cmpd	cr7, r27, r25
+	mulld	r0, r30, r8
+	mulhdu	r11, r28, r8
+	mulld	r10, r28, r8
+	subf	r31, r0, r31
+	li	r7, 0
+	blt	cr7, L(60)
+	ld	r7, 0(r26)
+	addi	r26, r26, -8
+	nop
+L(60):	subfc	r7, r28, r7
+	subfe	r31, r30, r31
+	subfc	r7, r10, r7
+	subfe	r4, r11, r31
+	subfc	r9, r6, r4
+	subfe	r9, r1, r1
+	andc	r6, r28, r9
+	andc	r0, r30, r9
+	addc	r31, r7, r6
+	adde	r29, r4, r0
+	subf	r8, r9, r8
+	cmpld	cr7, r29, r30
+	bge-	cr7, L(fix)
+L(bck):	std	r8, 0(r24)
+	addi	r24, r24, -8
+	addi	r27, r27, -1
+	bdnz	L(loop)
+L(18):
+	std	r31, 8(r26)
+	std	r29, 16(r26)
+	mr	r3, r23
+	addi	r1, r1, 192
+	ld	r0, 16(r1)
+	mtlr	r0
+	ld	r23, -72(r1)
+	ld	r24, -64(r1)
+	ld	r25, -56(r1)
+	ld	r26, -48(r1)
+	ld	r27, -40(r1)
+	ld	r28, -32(r1)
+	ld	r29, -24(r1)
+	ld	r30, -16(r1)
+	ld	r31, -8(r1)
+	blr
+L(fix):
+	mfcr	r0
+	rlwinm	r0, r0, 30, 31, 31
+	subfc	r9, r28, r31
+	addze.	r0, r0
+	beq	cr0, L(bck)
+	subfc	r31, r28, r31
+	subfe	r29, r30, r29
+	addi	r8, r8, 1
+	b	L(bck)
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc64/mode64/gcd_11.asm b/third_party/gmp/mpn/powerpc64/mode64/gcd_11.asm
new file mode 100644
index 0000000..f9792e5
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/gcd_11.asm
@@ -0,0 +1,77 @@
+dnl  PowerPC-64 mpn_gcd_11.
+
+dnl  Copyright 2000-2002, 2005, 2009, 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		    cycles/bit (approx)
+C POWER3/PPC630		 ?
+C POWER4/PPC970		 8.5	obsolete
+C POWER5		 ?
+C POWER6		 ?
+C POWER7		 9.4	obsolete
+C POWER8		 ?
+C POWER9		 ?
+C Numbers measured with: speed -CD -s16-64 -t48 mpn_gcd_1
+
+define(`u0',    `r3')
+define(`v0',    `r4')
+
+define(`mask', `r0')dnl
+define(`a1',   `r4')dnl
+define(`a2',   `r5')dnl
+define(`d1',   `r6')dnl
+define(`d2',   `r7')dnl
+define(`cnt',  `r9')dnl
+
+ASM_START()
+PROLOGUE(mpn_gcd_11)
+	li	r12, 63
+	mr	r8, v0
+	subf.	r10, u0, v0		C r10 = d - a
+	beq	L(end)
+
+	ALIGN(16)
+L(top):	subfc	r11, r8, r3		C r11 = a - d
+	and	d2, r11, r10
+	subfe	mask, mask, mask
+	cntlzd	cnt, d2
+	and	a1, r10, mask		C d - a
+	andc	a2, r11,  mask		C a - d
+	and	d1, r3, mask		C a
+	andc	d2, r8, mask		C d
+	or	r3, a1, a2		C new a
+	subf	cnt, cnt, r12
+	or	r8, d1, d2		C new d
+	srd	r3, r3, cnt
+	subf.	r10, r3, r8		C r10 = d - a
+	bne	L(top)
+
+L(end):	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc64/mode64/gmp-mparam.h b/third_party/gmp/mpn/powerpc64/mode64/gmp-mparam.h
new file mode 100644
index 0000000..f8305f4
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/gmp-mparam.h
@@ -0,0 +1,82 @@
+/* PowerPC-64 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2008, 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+/* 1600MHz PPC970 */
+
+/* Generated by tuneup.c, 2009-01-14, gcc 4.0 */
+
+#define MUL_TOOM22_THRESHOLD             14
+#define MUL_TOOM33_THRESHOLD             93
+#define MUL_TOOM44_THRESHOLD            135
+
+#define SQR_BASECASE_THRESHOLD            6
+#define SQR_TOOM2_THRESHOLD              32
+#define SQR_TOOM3_THRESHOLD              74
+#define SQR_TOOM4_THRESHOLD             136
+
+#define MULLO_BASECASE_THRESHOLD          0  /* always */
+#define MULLO_DC_THRESHOLD               44
+#define MULLO_MUL_N_THRESHOLD           234
+
+#define DIV_SB_PREINV_THRESHOLD           0  /* always */
+#define DIV_DC_THRESHOLD                 33
+#define POWM_THRESHOLD                   89
+
+#define MATRIX22_STRASSEN_THRESHOLD      15
+#define HGCD_THRESHOLD                   93
+#define GCD_DC_THRESHOLD                237
+#define GCDEXT_DC_THRESHOLD             273
+#define JACOBI_BASE_METHOD                1
+
+#define MOD_1_NORM_THRESHOLD              0  /* always */
+#define MOD_1_UNNORM_THRESHOLD            0  /* always */
+#define MOD_1_1_THRESHOLD                 6
+#define MOD_1_2_THRESHOLD                 9
+#define MOD_1_4_THRESHOLD                23
+#define USE_PREINV_DIVREM_1               0
+#define USE_PREINV_MOD_1                  0
+#define DIVEXACT_1_THRESHOLD              0  /* always (native) */
+#define MODEXACT_1_ODD_THRESHOLD          0  /* always (native) */
+
+#define GET_STR_DC_THRESHOLD             12
+#define GET_STR_PRECOMPUTE_THRESHOLD     24
+#define SET_STR_DC_THRESHOLD            650
+#define SET_STR_PRECOMPUTE_THRESHOLD   1713
+
+#define MUL_FFT_TABLE  { 336, 672, 1856, 2816, 7168, 20480, 81920, 327680, 0 }
+#define MUL_FFT_MODF_THRESHOLD          304
+#define MUL_FFT_THRESHOLD              4224
+
+#define SQR_FFT_TABLE  { 272, 672, 1600, 2816, 7168, 20480, 81920, 327680, 786432, 0 }
+#define SQR_FFT_MODF_THRESHOLD          272
+#define SQR_FFT_THRESHOLD              2688
diff --git a/third_party/gmp/mpn/powerpc64/mode64/invert_limb.asm b/third_party/gmp/mpn/powerpc64/mode64/invert_limb.asm
new file mode 100644
index 0000000..dfdba64
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/invert_limb.asm
@@ -0,0 +1,88 @@
+dnl  PowerPC-64 mpn_invert_limb -- Invert a normalized limb.
+
+dnl  Copyright 2004-2006, 2008, 2010, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                  cycles/limb (approximate)
+C POWER3/PPC630         80
+C POWER4/PPC970         86
+C POWER5                86
+C POWER6               170
+C POWER7                66
+
+ASM_START()
+PROLOGUE(mpn_invert_limb,toc)
+	LEAL(	r12, approx_tab)
+	srdi	r9, r3, 32
+	rlwinm	r9, r9, 10, 23, 30	C (d >> 55) & 0x1fe
+	srdi	r10, r3, 24		C d >> 24
+	lis	r11, 0x1000
+	rldicl	r8, r3, 0, 63		C d mod 2
+	addi	r10, r10, 1		C d40
+	sldi	r11, r11, 32		C 2^60
+	srdi	r7, r3, 1		C d/2
+	add	r7, r7, r8		C d63 = ceil(d/2)
+	neg	r8, r8			C mask = -(d mod 2)
+	lhzx	r0, r9, r12
+	mullw	r9, r0, r0		C v0*v0
+	sldi	r6, r0, 11		C v0 << 11
+	addi	r0, r6, -1		C (v0 << 11) - 1
+	mulld	r9, r9, r10		C v0*v0*d40
+	srdi	r9, r9, 40		C v0*v0*d40 >> 40
+	subf	r9, r9, r0		C v1 = (v0 << 11) - (v0*v0*d40 >> 40) - 1
+	mulld	r0, r9, r10		C v1*d40
+	sldi	r6, r9, 13		C v1 << 13
+	subf	r0, r0, r11		C 2^60 - v1*d40
+	mulld	r0, r0, r9		C v1 * (2^60 - v1*d40)
+	srdi	r0, r0, 47		C v1 * (2^60 - v1*d40) >> 47
+	add	r0, r0, r6		C v2 = (v1 << 13) + (v1 * (2^60 - v1*d40) >> 47)
+	mulld	r11, r0, r7		C v2 * d63
+	srdi	r10, r0, 1		C v2 >> 1
+	sldi	r9, r0, 31		C v2 << 31
+	and	r8, r10, r8		C (v2 >> 1) & mask
+	subf	r8, r11, r8		C ((v2 >> 1) & mask) - v2 * d63
+	mulhdu	r0, r8, r0		C p1 = v2 * (((v2 >> 1) & mask) - v2 * d63)
+	srdi	r0, r0, 1		C p1 >> 1
+	add	r0, r0, r9		C v3 = (v2 << 31) + (p1 >> 1)
+	nop
+	mulld	r11, r0, r3
+	mulhdu	r9, r0, r3
+	addc	r10, r11, r3
+	adde	r3, r9, r3
+	subf	r3, r3, r0
+	blr
+EPILOGUE()
+
+DEF_OBJECT(approx_tab)
+forloop(i,256,512-1,dnl
+`	.short	eval(0x7fd00/i)
+')dnl
+END_OBJECT(approx_tab)
+ASM_END()
diff --git a/third_party/gmp/mpn/powerpc64/mode64/mod_1_1.asm b/third_party/gmp/mpn/powerpc64/mode64/mod_1_1.asm
new file mode 100644
index 0000000..8733730
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/mod_1_1.asm
@@ -0,0 +1,164 @@
+dnl  PowerPC-64 mpn_mod_1_1p
+
+dnl  Copyright 2010, 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                   cycles/limb
+C POWER3/PPC630          ?
+C POWER4/PPC970         17
+C POWER5                16
+C POWER6                30
+C POWER7                10.2
+
+C TODO
+C  * Optimise, in particular the cps function.  This was compiler-generated and
+C    then hand optimised.
+
+C INPUT PARAMETERS
+define(`ap',  `r3')
+define(`n',   `r4')
+define(`d',   `r5')
+define(`cps', `r6')
+
+ASM_START()
+
+EXTERN_FUNC(mpn_invert_limb)
+
+PROLOGUE(mpn_mod_1_1p)
+	sldi	r10, r4, 3
+	addi	r4, r4, -1
+	add	r3, r3, r10
+	ld	r0, 16(r6)		C B1modb
+	ld	r12, 24(r6)		C B2modb
+	ld	r9, -8(r3)
+	ld	r10, -16(r3)
+	mtctr	r4
+	mulhdu	r8, r9, r0
+	mulld	r7, r9, r0
+	addc	r11, r7, r10
+	addze	r9, r8
+	bdz	L(end)
+
+	ALIGN(16)
+L(top):	ld	r4, -24(r3)
+	addi	r3, r3, -8
+	nop
+	mulld	r10, r11, r0
+	mulld	r8, r9, r12
+	mulhdu	r11, r11, r0
+	mulhdu	r9, r9, r12
+	addc	r7, r10, r4
+	addze	r10, r11
+	addc	r11, r8, r7
+	adde	r9, r9, r10
+	bdnz	L(top)
+
+L(end):
+ifdef(`HAVE_LIMB_LITTLE_ENDIAN',
+`	lwz	r0, 8(r6)',
+`	lwz	r0, 12(r6)')
+	ld	r3, 0(r6)
+	cmpdi	cr7, r0, 0
+	beq-	cr7, L(4)
+	subfic	r10, r0, 64
+	sld	r9, r9, r0
+	srd	r10, r11, r10
+	or	r9, r10, r9
+L(4):	subfc	r10, r5, r9
+	subfe	r10, r10, r10
+	nand	r10, r10, r10
+	sld	r11, r11, r0
+	and	r10, r10, r5
+	subf	r9, r10, r9
+	mulhdu	r10, r9, r3
+	mulld	r3, r9, r3
+	addi	r9, r9, 1
+	addc	r8, r3, r11
+	adde	r3, r10, r9
+	mulld	r3, r3, r5
+	subf	r3, r3, r11
+	cmpld	cr7, r8, r3
+	bge	cr7, L(5)		C FIXME: Make branch-less
+	add	r3, r3, r5
+L(5):	cmpld	cr7, r3, r5
+	bge-	cr7, L(10)
+	srd	r3, r3, r0
+	blr
+
+L(10):	subf	r3, r5, r3
+	srd	r3, r3, r0
+	blr
+EPILOGUE()
+
+PROLOGUE(mpn_mod_1_1p_cps,toc)
+	mflr	r0
+	std	r29, -24(r1)
+	std	r30, -16(r1)
+	std	r31, -8(r1)
+	cntlzd	r31, r4
+	std	r0, 16(r1)
+	extsw	r31, r31
+	mr	r29, r3
+	stdu	r1, -144(r1)
+	sld	r30, r4, r31
+	mr	r3, r30
+	CALL(	mpn_invert_limb)
+	cmpdi	cr7, r31, 0
+	neg	r0, r30
+	beq-	cr7, L(13)
+	subfic	r11, r31, 64
+	li	r0, 1
+	neg	r9, r30
+	srd	r11, r3, r11
+	sld	r0, r0, r31
+	or	r0, r11, r0
+	mulld	r0, r0, r9
+L(13):	mulhdu	r9, r0, r3
+	mulld	r11, r0, r3
+	add	r9, r0, r9
+	nor	r9, r9, r9
+	mulld	r9, r9, r30
+	cmpld	cr7, r11, r9
+	bge	cr7, L(14)
+	add	r9, r9, r30
+L(14):	addi	r1, r1, 144
+	srd	r0, r0, r31
+	std	r31, 8(r29)
+	std	r3, 0(r29)
+	std	r0, 16(r29)
+	ld	r0, 16(r1)
+	srd	r9, r9, r31
+	ld	r30, -16(r1)
+	ld	r31, -8(r1)
+	std	r9, 24(r29)
+	ld	r29, -24(r1)
+	mtlr	r0
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc64/mode64/mod_1_4.asm b/third_party/gmp/mpn/powerpc64/mode64/mod_1_4.asm
new file mode 100644
index 0000000..0b7d6bf
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/mod_1_4.asm
@@ -0,0 +1,270 @@
+dnl  PowerPC-64 mpn_mod_1s_4p
+
+dnl  Copyright 2010, 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                   cycles/limb
+C POWER3/PPC630          ?
+C POWER4/PPC970          9
+C POWER5                 9
+C POWER6                13
+C POWER7                3.5
+
+C TODO
+C  * Optimise, in particular the cps function.  This was compiler-generated and
+C    then hand optimised.
+
+C INPUT PARAMETERS
+define(`ap',  `r3')
+define(`n',   `r4')
+define(`d',   `r5')
+define(`cps', `r6')
+
+ASM_START()
+
+EXTERN_FUNC(mpn_invert_limb)
+
+PROLOGUE(mpn_mod_1s_4p)
+	std	r23, -72(r1)
+	ld	r23, 48(cps)
+	std	r24, -64(r1)
+	std	r25, -56(r1)
+	ld	r24, 32(cps)
+	ld	r25, 24(cps)
+	std	r26, -48(r1)
+	std	r27, -40(r1)
+	ld	r26, 16(cps)
+	std	r28, -32(r1)
+	std	r29, -24(r1)
+	std	r30, -16(r1)
+	std	r31, -8(r1)
+	ld	r30, 40(cps)
+
+	rldicl.	r0, n, 0,62
+	sldi	r31, n, 3
+	add	ap, ap, r31		C make ap point at end of operand
+
+	cmpdi	cr7, r0, 2
+	beq	cr0, L(b00)
+	blt	cr7, L(b01)
+	beq	cr7, L(b10)
+
+L(b11):	ld	r11, -16(ap)
+	ld	r9, -8(ap)
+	ld	r0, -24(ap)
+	mulhdu	r27, r11, r26
+	mulld	r8, r11, r26
+	mulhdu	r11, r9, r25
+	mulld	r9, r9, r25
+	addc	r31, r8, r0
+	addze	r10, r27
+	addc	r0, r9, r31
+	adde	r9, r11, r10
+	addi	ap, ap, -40
+	b	L(6)
+
+	ALIGN(16)
+L(b00):	ld	r11, -24(ap)
+	ld	r10, -16(ap)
+	ld	r9, -8(ap)
+	ld	r0, -32(ap)
+	mulld	r8, r11, r26
+	mulhdu	r7, r10, r25
+	mulhdu	r27, r11, r26
+	mulhdu	r11, r9, r24
+	mulld	r10, r10, r25
+	mulld	r9, r9, r24
+	addc	r31, r8, r0
+	addze	r0, r27
+	addc	r8, r31, r10
+	adde	r10, r0, r7
+	addc	r0, r9, r8
+	adde	r9, r11, r10
+	addi	ap, ap, -48
+	b	L(6)
+
+	ALIGN(16)
+L(b01):	li	r9, 0
+	ld	r0, -8(ap)
+	addi	ap, ap, -24
+	b	L(6)
+
+	ALIGN(16)
+L(b10):	ld	r9, -8(ap)
+	ld	r0, -16(ap)
+	addi	ap, ap, -32
+
+	ALIGN(16)
+L(6):	addi	r10, n, 3
+	srdi	r7, r10, 2
+	mtctr	r7
+	bdz	L(end)
+
+	ALIGN(16)
+L(top):	ld	r31, -16(ap)
+	ld	r10, -8(ap)
+	ld	r11, 8(ap)
+	ld	r12, 0(ap)
+	mulld	r29, r0, r30		C rl * B4modb
+	mulhdu	r0,  r0, r30		C rl * B4modb
+	mulhdu	r27, r10, r26
+	mulld	r10, r10, r26
+	mulhdu	r7, r9, r23		C rh * B5modb
+	mulld	r9, r9, r23		C rh * B5modb
+	mulhdu	r28, r11, r24
+	mulld	r11, r11, r24
+	mulhdu	r4, r12, r25
+	mulld	r12, r12, r25
+	addc	r8, r10, r31
+	addze	r10, r27
+	addi	ap, ap, -32
+	addc	r27, r8, r12
+	adde	r12, r10, r4
+	addc	r11, r27, r11
+	adde	r31, r12, r28
+	addc	r12, r11, r29
+	adde	r4, r31, r0
+	addc	r0, r9, r12
+	adde	r9, r7, r4
+	bdnz	L(top)
+
+L(end):
+ifdef(`HAVE_LIMB_LITTLE_ENDIAN',
+`	lwz	r3, 8(cps)',
+`	lwz	r3, 12(cps)')
+	mulld	r10, r9, r26
+	mulhdu	r9, r9, r26
+	addc	r11, r0, r10
+	addze	r9, r9
+	ld	r10, 0(cps)
+	subfic	r8, r3, 64
+	sld	r9, r9, r3
+	srd	r8, r11, r8
+	sld	r11, r11, r3
+	or	r9, r8, r9
+	mulld	r0, r9, r10
+	mulhdu	r10, r9, r10
+	addi	r9, r9, 1
+	addc	r8, r0, r11
+	adde	r0, r10, r9
+	mulld	r0, r0, d
+	subf	r0, r0, r11
+	cmpld	cr7, r8, r0
+	bge	cr7, L(9)
+	add	r0, r0, d
+L(9):	cmpld	cr7, r0, d
+	bge-	cr7, L(16)
+L(10):	srd	r3, r0, r3
+	ld	r23, -72(r1)
+	ld	r24, -64(r1)
+	ld	r25, -56(r1)
+	ld	r26, -48(r1)
+	ld	r27, -40(r1)
+	ld	r28, -32(r1)
+	ld	r29, -24(r1)
+	ld	r30, -16(r1)
+	ld	r31, -8(r1)
+	blr
+
+L(16):	subf	r0, d, r0
+	b	L(10)
+EPILOGUE()
+
+PROLOGUE(mpn_mod_1s_4p_cps,toc)
+	mflr	r0
+	std	r29, -24(r1)
+	std	r30, -16(r1)
+	mr	r29, r3
+	std	r0, 16(r1)
+	std	r31, -8(r1)
+	stdu	r1, -144(r1)
+	cntlzd	r31, r4
+	sld	r30, r4, r31
+	mr	r3, r30
+	CALL(	mpn_invert_limb)
+	subfic	r9, r31, 64
+	li	r10, 1
+	sld	r10, r10, r31
+	srd	r9, r3, r9
+	neg	r0, r30
+	or	r10, r10, r9
+	mulld	r10, r10, r0
+	mulhdu	r11, r10, r3
+	nor	r11, r11, r11
+	subf	r11, r10, r11
+	mulld	r11, r11, r30
+	mulld	r0, r10, r3
+	cmpld	cr7, r0, r11
+	bge	cr7, L(18)
+	add	r11, r11, r30
+L(18):	mulhdu	r9, r11, r3
+	add	r9, r11, r9
+	nor	r9, r9, r9
+	mulld	r9, r9, r30
+	mulld	r0, r11, r3
+	cmpld	cr7, r0, r9
+	bge	cr7, L(19)
+	add	r9, r9, r30
+L(19):	mulhdu	r0, r9, r3
+	add	r0, r9, r0
+	nor	r0, r0, r0
+	mulld	r0, r0, r30
+	mulld	r8, r9, r3
+	cmpld	cr7, r8, r0
+	bge	cr7, L(20)
+	add	r0, r0, r30
+L(20):	mulhdu	r8, r0, r3
+	add	r8, r0, r8
+	nor	r8, r8, r8
+	mulld	r8, r8, r30
+	mulld	r7, r0, r3
+	cmpld	cr7, r7, r8
+	bge	cr7, L(21)
+	add	r8, r8, r30
+L(21):	srd	r0, r0, r31
+	addi	r1, r1, 144
+	srd	r8, r8, r31
+	srd	r10, r10, r31
+	srd	r11, r11, r31
+	std	r0, 40(r29)
+	std	r31, 8(r29)
+	srd	r9, r9, r31
+	ld	r0, 16(r1)
+	ld	r30, -16(r1)
+	std	r8, 48(r29)
+	std	r3, 0(r29)
+	mtlr	r0
+	ld	r31, -8(r1)
+	std	r10, 16(r29)
+	std	r11, 24(r29)
+	std	r9, 32(r29)
+	ld	r29, -24(r1)
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc64/mode64/mod_34lsub1.asm b/third_party/gmp/mpn/powerpc64/mode64/mod_34lsub1.asm
new file mode 100644
index 0000000..c35e0e3
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/mod_34lsub1.asm
@@ -0,0 +1,132 @@
+dnl  PowerPC-64 mpn_mod_34lsub1 -- modulo 2^48-1.
+
+dnl  Copyright 2005 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                   cycles/limb
+C POWER3/PPC630          1.33
+C POWER4/PPC970          1.5
+C POWER5                 1.32
+C POWER6                 2.35
+C POWER7                 1
+
+C INPUT PARAMETERS
+define(`up',`r3')
+define(`n',`r4')
+
+ASM_START()
+PROLOGUE(mpn_mod_34lsub1)
+	li	r8, 0
+	li	r9, 0
+	li	r10, 0
+	li	r11, 0
+
+	cmpdi	cr6, n, 3
+	blt	cr6, L(lt3)
+
+	li	r0, -0x5556		C 0xFFFFFFFFFFFFAAAA
+	rldimi	r0, r0, 16, 32		C 0xFFFFFFFFAAAAAAAA
+	rldimi	r0, r0, 32, 63		C 0xAAAAAAAAAAAAAAAB
+	mulhdu	r0, r0, n
+	srdi	r0, r0, 1		C r0 = [n / 3]
+	mtctr	r0
+
+	ld	r5, 0(up)
+	ld	r6, 8(up)
+	ld	r7, 16(up)
+	addi	up, up, 24
+	bdz	L(end)
+
+	ALIGN(16)
+L(top):	addc	r8, r8, r5
+	nop
+	ld	r5, 0(up)
+	adde	r9, r9, r6
+	ld	r6, 8(up)
+	adde	r10, r10, r7
+	ld	r7, 16(up)
+	addi	up, up, 48
+	addze	r11, r11
+	bdz	L(endx)
+	addc	r8, r8, r5
+	nop
+	ld	r5, -24(up)
+	adde	r9, r9, r6
+	ld	r6, -16(up)
+	adde	r10, r10, r7
+	ld	r7, -8(up)
+	addze	r11, r11
+	bdnz	L(top)
+
+	addi	up, up, 24
+L(endx):
+	addi	up, up, -24
+
+L(end):	addc	r8, r8, r5
+	adde	r9, r9, r6
+	adde	r10, r10, r7
+	addze	r11, r11
+
+	sldi	r5, r0, 1
+	add	r5, r5, r0		C r11 = n / 3 * 3
+	sub	n, n, r5		C n = n mod 3
+L(lt3):	cmpdi	cr6, n, 1
+	blt	cr6, L(2)
+
+	ld	r5, 0(up)
+	addc	r8, r8, r5
+	li	r6, 0
+	beq	cr6, L(1)
+
+	ld	r6, 8(up)
+L(1):	adde	r9, r9, r6
+	addze	r10, r10
+	addze	r11, r11
+
+L(2):	rldicl	r0, r8, 0, 16		C r0 = r8 mod 2^48
+	srdi	r3, r8, 48		C r3 = r8 div 2^48
+	rldic	r4, r9, 16, 16		C r4 = (r9 mod 2^32) << 16
+	srdi	r5, r9, 32		C r5 = r9 div 2^32
+	rldic	r6, r10, 32, 16		C r6 = (r10 mod 2^16) << 32
+	srdi	r7, r10, 16		C r7 = r10 div 2^16
+
+	add	r0, r0, r3
+	add	r4, r4, r5
+	add	r6, r6, r7
+
+	add	r0, r0, r4
+	add	r6, r6, r11
+
+	add	r3, r0, r6
+	blr
+EPILOGUE()
+
+C |__r10__|__r9___|__r8___|
+C |-----|-----|-----|-----|
diff --git a/third_party/gmp/mpn/powerpc64/mode64/mode1o.asm b/third_party/gmp/mpn/powerpc64/mode64/mode1o.asm
new file mode 100644
index 0000000..726339a
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/mode1o.asm
@@ -0,0 +1,117 @@
+dnl  PowerPC-64 mpn_modexact_1_odd -- mpn by limb exact remainder.
+
+dnl  Copyright 2006 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                  cycles/limb
+C POWER3/PPC630        13-19
+C POWER4/PPC970         16
+C POWER5                16
+C POWER6                 ?
+C POWER7                12
+
+C TODO
+C  * Check if n=1 code is really an improvement.  It probably isn't.
+C  * Make more similar to dive_1.asm.
+
+C INPUT PARAMETERS
+define(`up', `r3')
+define(`n',  `r4')
+define(`d',  `r5')
+define(`cy', `r6')
+
+
+ASM_START()
+
+EXTERN(binvert_limb_table)
+
+PROLOGUE(mpn_modexact_1c_odd,toc)
+	addic.	n, n, -1		C set carry as side effect
+	ld	r8, 0(up)
+	bne	cr0, L(2)
+	cmpld	cr7, r6, r8
+	bge	cr7, L(4)
+	subf	r8, r6, r8
+	divdu	r3, r8, d
+	mulld	r3, r3, d
+	subf.	r3, r3, r8
+	beqlr	cr0
+	subf	r3, r3, d
+	blr
+
+L(4):	subf	r3, r8, r6
+	divdu	r8, r3, d
+	mulld	r8, r8, d
+	subf	r3, r8, r3
+	blr
+
+L(2):	LEA(	r7, binvert_limb_table)
+	rldicl	r9, d, 63, 57
+	mtctr	n
+	lbzx	r0, r7, r9
+	mulld	r7, r0, r0
+	sldi	r0, r0, 1
+	mulld	r7, d, r7
+	subf	r0, r7, r0
+	mulld	r9, r0, r0
+	sldi	r0, r0, 1
+	mulld	r9, d, r9
+	subf	r0, r9, r0
+	mulld	r7, r0, r0
+	sldi	r0, r0, 1
+	mulld	r7, d, r7
+	subf	r9, r7, r0
+
+	ALIGN(16)
+L(loop):
+	subfe	r0, r6, r8
+	ld	r8, 8(up)
+	addi	up, up, 8
+	mulld	r0, r9, r0
+	mulhdu	r6, r0, d
+	bdnz	L(loop)
+
+	cmpld	cr7, d, r8
+	blt	cr7, L(10)
+
+	subfe	r0, r0, r0
+	subf	r6, r0, r6
+	cmpld	cr7, r6, r8
+	subf	r3, r8, r6
+	bgelr	cr7
+	add	r3, d, r3
+	blr
+
+L(10):	subfe	r0, r6, r8
+	mulld	r0, r9, r0
+	mulhdu	r3, r0, d
+	blr
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/powerpc64/mode64/mul_1.asm b/third_party/gmp/mpn/powerpc64/mode64/mul_1.asm
new file mode 100644
index 0000000..27a8f8f
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/mul_1.asm
@@ -0,0 +1,168 @@
+dnl  PowerPC-64 mpn_mul_1 -- Multiply a limb vector with a limb and store
+dnl  the result in a second limb vector.
+
+dnl  Copyright 1999-2001, 2003-2006, 2010 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C               cycles/limb
+C POWER3/PPC630     6-18
+C POWER4/PPC970     7.25?  not updated for last file revision
+C POWER5            7.25
+C POWER6           14
+C POWER7            2.9
+
+C TODO
+C  * Try to reduce the number of needed live registers (at least r5 and r10
+C    could be combined)
+C  * Optimize feed-in code, for speed and size.
+C  * Clean up r12/r7 usage in feed-in code.
+
+C INPUT PARAMETERS
+define(`rp', `r3')
+define(`up', `r4')
+define(`n', `r5')
+define(`vl', `r6')
+
+ASM_START()
+PROLOGUE(mpn_mul_1c)
+	std	r27, -40(r1)
+	std	r26, -48(r1)
+	mr	r12, r7
+	b	L(ent)
+EPILOGUE()
+PROLOGUE(mpn_mul_1)
+	std	r27, -40(r1)
+	std	r26, -48(r1)
+	li	r12, 0		C cy_limb = 0
+L(ent):	ld	r26, 0(up)
+
+	rldicl.	r0, n, 0,62	C r0 = n & 3, set cr0
+	cmpdi	cr6, r0, 2
+	addic	n, n, 3		C compute count...
+	srdi	n, n, 2		C ...for ctr
+	mtctr	n		C copy count into ctr
+	beq	cr0, L(b00)
+	blt	cr6, L(b01)
+	beq	cr6, L(b10)
+
+L(b11):	mr	r7, r12
+	mulld	r0, r26, r6
+	mulhdu	r12, r26, r6
+	addi	up, up, 8
+	addc	r0, r0, r7
+	std	r0, 0(rp)
+	addi	rp, rp, 8
+	b	L(fic)
+
+L(b00):	ld	r27, 8(up)
+	addi	up, up, 16
+	mulld	r0, r26, r6
+	mulhdu	r5, r26, r6
+	mulld	r7, r27, r6
+	mulhdu	r8, r27, r6
+	addc	r0, r0, r12
+	adde	r7, r7, r5
+	addze	r12, r8
+	std	r0, 0(rp)
+	std	r7, 8(rp)
+	addi	rp, rp, 16
+	b	L(fic)
+
+	nop			C alignment
+L(b01):	bdnz	L(gt1)
+	mulld	r0, r26, r6
+	mulhdu	r8, r26, r6
+	addc	r0, r0, r12
+	std	r0, 0(rp)
+	b	L(ret)
+L(gt1):	ld	r27, 8(up)
+	nop
+	mulld	r0, r26, r6
+	mulhdu	r5, r26, r6
+	ld	r26, 16(up)
+	mulld	r7, r27, r6
+	mulhdu	r8, r27, r6
+	mulld	r9, r26, r6
+	mulhdu	r10, r26, r6
+	addc	r0, r0, r12
+	adde	r7, r7, r5
+	adde	r9, r9, r8
+	addze	r12, r10
+	std	r0, 0(rp)
+	std	r7, 8(rp)
+	std	r9, 16(rp)
+	addi	up, up, 24
+	addi	rp, rp, 24
+	b	L(fic)
+
+	nop
+L(fic):	ld	r26, 0(up)
+L(b10):	ld	r27, 8(up)
+	addi	up, up, 16
+	bdz	L(end)
+
+L(top):	mulld	r0, r26, r6
+	mulhdu	r5, r26, r6
+	mulld	r7, r27, r6
+	mulhdu	r8, r27, r6
+	ld	r26, 0(up)
+	ld	r27, 8(up)
+	adde	r0, r0, r12
+	adde	r7, r7, r5
+	mulld	r9, r26, r6
+	mulhdu	r10, r26, r6
+	mulld	r11, r27, r6
+	mulhdu	r12, r27, r6
+	ld	r26, 16(up)
+	ld	r27, 24(up)
+	std	r0, 0(rp)
+	adde	r9, r9, r8
+	std	r7, 8(rp)
+	adde	r11, r11, r10
+	std	r9, 16(rp)
+	addi	up, up, 32
+	std	r11, 24(rp)
+
+	addi	rp, rp, 32
+	bdnz	L(top)
+
+L(end):	mulld	r0, r26, r6
+	mulhdu	r5, r26, r6
+	mulld	r7, r27, r6
+	mulhdu	r8, r27, r6
+	adde	r0, r0, r12
+	adde	r7, r7, r5
+	std	r0, 0(rp)
+	std	r7, 8(rp)
+L(ret):	addze	r3, r8
+	ld	r27, -40(r1)
+	ld	r26, -48(r1)
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc64/mode64/mul_basecase.asm b/third_party/gmp/mpn/powerpc64/mode64/mul_basecase.asm
new file mode 100644
index 0000000..1873187
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/mul_basecase.asm
@@ -0,0 +1,708 @@
+dnl  PowerPC-64 mpn_mul_basecase.
+
+dnl  Copyright 1999-2001, 2003-2006, 2008 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                  cycles/limb
+C POWER3/PPC630         6-18
+C POWER4/PPC970          8
+C POWER5                 8
+C POWER6                24
+
+C INPUT PARAMETERS
+define(`rp', `r3')
+define(`up', `r4')
+define(`un', `r5')
+define(`vp', `r6')
+define(`vn', `r7')
+
+define(`v0',	   `r25')
+define(`outer_rp', `r22')
+define(`outer_up', `r23')
+
+ASM_START()
+PROLOGUE(mpn_mul_basecase)
+
+C Special code for un <= 2, for efficiency of these important cases,
+C and since it simplifies the default code.
+	cmpdi	cr0, un, 2
+	bgt	cr0, L(un_gt2)
+	cmpdi	cr6, vn, 1
+	ld	r7, 0(vp)
+	ld	r5, 0(up)
+	mulld	r8, r5, r7	C weight 0
+	mulhdu	r9, r5, r7	C weight 1
+	std	r8, 0(rp)
+	beq	cr0, L(2x)
+	std	r9, 8(rp)
+	blr
+	ALIGN(16)
+L(2x):	ld	r0, 8(up)
+	mulld	r8, r0, r7	C weight 1
+	mulhdu	r10, r0, r7	C weight 2
+	addc	r9, r9, r8
+	addze	r10, r10
+	bne	cr6, L(2x2)
+	std	r9, 8(rp)
+	std	r10, 16(rp)
+	blr
+	ALIGN(16)
+L(2x2):	ld	r6, 8(vp)
+	nop
+	mulld	r8, r5, r6	C weight 1
+	mulhdu	r11, r5, r6	C weight 2
+	addc	r9, r9, r8
+	std	r9, 8(rp)
+	adde	r11, r11, r10
+	mulld	r12, r0, r6	C weight 2
+	mulhdu	r0, r0, r6	C weight 3
+	addze	r0, r0
+	addc	r11, r11, r12
+	addze	r0, r0
+	std	r11, 16(rp)
+	std	r0, 24(rp)
+	blr
+
+L(un_gt2):
+	std	r31, -8(r1)
+	std	r30, -16(r1)
+	std	r29, -24(r1)
+	std	r28, -32(r1)
+	std	r27, -40(r1)
+	std	r26, -48(r1)
+	std	r25, -56(r1)
+	std	r24, -64(r1)
+	std	r23, -72(r1)
+	std	r22, -80(r1)
+
+	mr	outer_rp, rp
+	mr	outer_up, up
+
+	ld	v0, 0(vp)	C new v limb
+	addi	vp, vp, 8
+	ld	r26, 0(up)
+
+	rldicl.	r0, un, 0,62	C r0 = n & 3, set cr0
+	cmpdi	cr6, r0, 2
+	addi	un, un, 1	C compute count...
+	srdi	un, un, 2	C ...for ctr
+	mtctr	un		C copy inner loop count into ctr
+	beq	cr0, L(b0)
+	blt	cr6, L(b1)
+	beq	cr6, L(b2)
+
+
+	ALIGN(16)
+L(b3):	mulld	r0, r26, v0
+	mulhdu	r12, r26, v0
+	addic	r0, r0, 0
+	std	r0, 0(rp)
+	ld	r26, 8(up)
+	ld	r27, 16(up)
+	bdz	L(end_m_3)
+
+	ALIGN(16)
+L(lo_m_3):
+	mulld	r0, r26, v0
+	mulhdu	r31, r26, v0
+	ld	r26, 24(up)
+	nop
+	mulld	r24, r27, v0
+	mulhdu	r8, r27, v0
+	ld	r27, 32(up)
+	nop
+	adde	r0, r0, r12
+	adde	r24, r24, r31
+	mulld	r9, r26, v0
+	mulhdu	r10, r26, v0
+	ld	r26, 40(up)
+	nop
+	mulld	r11, r27, v0
+	mulhdu	r12, r27, v0
+	ld	r27, 48(up)
+	std	r0, 8(rp)
+	adde	r9, r9, r8
+	std	r24, 16(rp)
+	adde	r11, r11, r10
+	std	r9, 24(rp)
+	addi	up, up, 32
+	std	r11, 32(rp)
+	addi	rp, rp, 32
+	bdnz	L(lo_m_3)
+
+	ALIGN(16)
+L(end_m_3):
+	mulld	r0, r26, v0
+	mulhdu	r31, r26, v0
+
+	mulld	r24, r27, v0
+	mulhdu	r8, r27, v0
+
+	adde	r0, r0, r12
+	adde	r24, r24, r31
+
+	std	r0, 8(rp)
+	std	r24, 16(rp)
+	addze	r8, r8
+	std	r8, 24(rp)
+	addic.	vn, vn, -1
+	beq	L(ret)
+
+	ALIGN(16)
+L(outer_lo_3):
+	mtctr	un		C copy inner loop count into ctr
+	addi	rp, outer_rp, 8
+	mr	up, outer_up
+	addi	outer_rp, outer_rp, 8
+	ld	v0, 0(vp)	C new v limb
+	addi	vp, vp, 8
+	ld	r26, 0(up)
+	ld	r28, 0(rp)
+	mulld	r0, r26, v0
+	mulhdu	r12, r26, v0
+	addc	r0, r0, r28
+	std	r0, 0(rp)
+	ld	r26, 8(up)
+	ld	r27, 16(up)
+	bdz	L(end_3)
+
+	ALIGN(16)		C registers dying
+L(lo_3):
+	mulld	r0, r26, v0	C
+	mulhdu	r10, r26, v0	C 26
+	ld	r26, 24(up)	C
+	ld	r28, 8(rp)	C
+	mulld	r24, r27, v0	C
+	mulhdu	r8, r27, v0	C 27
+	ld	r27, 32(up)	C
+	ld	r29, 16(rp)	C
+	adde	r0, r0, r12	C 0 12
+	adde	r24, r24, r10	C 24 10
+	mulld	r9, r26, v0	C
+	mulhdu	r10, r26, v0	C 26
+	ld	r26, 40(up)	C
+	ld	r30, 24(rp)	C
+	mulld	r11, r27, v0	C
+	mulhdu	r12, r27, v0	C 27
+	ld	r27, 48(up)	C
+	ld	r31, 32(rp)	C
+	adde	r9, r9, r8	C 8 9
+	adde	r11, r11, r10	C 10 11
+	addze	r12, r12	C 12
+	addc	r0, r0, r28	C 0 28
+	std	r0, 8(rp)	C 0
+	adde	r24, r24, r29	C 7 29
+	std	r24, 16(rp)	C 7
+	adde	r9, r9, r30	C 9 30
+	std	r9, 24(rp)	C 9
+	adde	r11, r11, r31	C 11 31
+	std	r11, 32(rp)	C 11
+	addi	up, up, 32	C
+	addi	rp, rp, 32	C
+	bdnz	L(lo_3)	C
+
+	ALIGN(16)
+L(end_3):
+	mulld	r0, r26, v0
+	mulhdu	r10, r26, v0
+	ld	r28, 8(rp)
+	nop
+	mulld	r24, r27, v0
+	mulhdu	r8, r27, v0
+	ld	r29, 16(rp)
+	nop
+	adde	r0, r0, r12
+	adde	r24, r24, r10
+	addze	r8, r8
+	addc	r0, r0, r28
+	std	r0, 8(rp)
+	adde	r24, r24, r29
+	std	r24, 16(rp)
+	addze	r8, r8
+	std	r8, 24(rp)
+
+	addic.	vn, vn, -1
+	bne	L(outer_lo_3)
+	b	L(ret)
+
+
+	ALIGN(16)
+L(b0):	ld	r27, 8(up)
+	addi	up, up, 8
+	mulld	r0, r26, v0
+	mulhdu	r10, r26, v0
+	mulld	r24, r27, v0
+	mulhdu	r8, r27, v0
+	addc	r24, r24, r10
+	addze	r12, r8
+	std	r0, 0(rp)
+	std	r24, 8(rp)
+	addi	rp, rp, 8
+	ld	r26, 8(up)
+	ld	r27, 16(up)
+	bdz	L(end_m_0)
+
+	ALIGN(16)
+L(lo_m_0):
+	mulld	r0, r26, v0
+	mulhdu	r31, r26, v0
+	ld	r26, 24(up)
+	nop
+	mulld	r24, r27, v0
+	mulhdu	r8, r27, v0
+	ld	r27, 32(up)
+	nop
+	adde	r0, r0, r12
+	adde	r24, r24, r31
+	mulld	r9, r26, v0
+	mulhdu	r10, r26, v0
+	ld	r26, 40(up)
+	nop
+	mulld	r11, r27, v0
+	mulhdu	r12, r27, v0
+	ld	r27, 48(up)
+	std	r0, 8(rp)
+	adde	r9, r9, r8
+	std	r24, 16(rp)
+	adde	r11, r11, r10
+	std	r9, 24(rp)
+	addi	up, up, 32
+	std	r11, 32(rp)
+	addi	rp, rp, 32
+	bdnz	L(lo_m_0)
+
+	ALIGN(16)
+L(end_m_0):
+	mulld	r0, r26, v0
+	mulhdu	r31, r26, v0
+
+	mulld	r24, r27, v0
+	mulhdu	r8, r27, v0
+
+	adde	r0, r0, r12
+	adde	r24, r24, r31
+
+	std	r0, 8(rp)
+	addze	r8, r8
+	std	r24, 16(rp)
+	addic.	vn, vn, -1
+	std	r8, 24(rp)
+	nop
+	beq	L(ret)
+
+	ALIGN(16)
+L(outer_lo_0):
+	mtctr	un		C copy inner loop count into ctr
+	addi	rp, outer_rp, 16
+	addi	up, outer_up, 8
+	addi	outer_rp, outer_rp, 8
+	ld	v0, 0(vp)	C new v limb
+	addi	vp, vp, 8
+	ld	r26, -8(up)
+	ld	r27, 0(up)
+	ld	r28, -8(rp)
+	ld	r29, 0(rp)
+	nop
+	nop
+	mulld	r0, r26, v0
+	mulhdu	r10, r26, v0
+	mulld	r24, r27, v0
+	mulhdu	r8, r27, v0
+	addc	r24, r24, r10
+	addze	r12, r8
+	addc	r0, r0, r28
+	std	r0, -8(rp)
+	adde	r24, r24, r29
+	std	r24, 0(rp)
+	ld	r26, 8(up)
+	ld	r27, 16(up)
+	bdz	L(end_0)
+
+	ALIGN(16)		C registers dying
+L(lo_0):
+	mulld	r0, r26, v0	C
+	mulhdu	r10, r26, v0	C 26
+	ld	r26, 24(up)	C
+	ld	r28, 8(rp)	C
+	mulld	r24, r27, v0	C
+	mulhdu	r8, r27, v0	C 27
+	ld	r27, 32(up)	C
+	ld	r29, 16(rp)	C
+	adde	r0, r0, r12	C 0 12
+	adde	r24, r24, r10	C 24 10
+	mulld	r9, r26, v0	C
+	mulhdu	r10, r26, v0	C 26
+	ld	r26, 40(up)	C
+	ld	r30, 24(rp)	C
+	mulld	r11, r27, v0	C
+	mulhdu	r12, r27, v0	C 27
+	ld	r27, 48(up)	C
+	ld	r31, 32(rp)	C
+	adde	r9, r9, r8	C 8 9
+	adde	r11, r11, r10	C 10 11
+	addze	r12, r12	C 12
+	addc	r0, r0, r28	C 0 28
+	std	r0, 8(rp)	C 0
+	adde	r24, r24, r29	C 7 29
+	std	r24, 16(rp)	C 7
+	adde	r9, r9, r30	C 9 30
+	std	r9, 24(rp)	C 9
+	adde	r11, r11, r31	C 11 31
+	std	r11, 32(rp)	C 11
+	addi	up, up, 32	C
+	addi	rp, rp, 32	C
+	bdnz	L(lo_0)	C
+
+	ALIGN(16)
+L(end_0):
+	mulld	r0, r26, v0
+	mulhdu	r10, r26, v0
+	ld	r28, 8(rp)
+	nop
+	mulld	r24, r27, v0
+	mulhdu	r8, r27, v0
+	ld	r29, 16(rp)
+	nop
+	adde	r0, r0, r12
+	adde	r24, r24, r10
+	addze	r8, r8
+	addic.	vn, vn, -1
+	addc	r0, r0, r28
+	std	r0, 8(rp)
+	adde	r24, r24, r29
+	std	r24, 16(rp)
+	addze	r8, r8
+	std	r8, 24(rp)
+	bne	L(outer_lo_0)
+	b	L(ret)
+
+
+	ALIGN(16)
+L(b1):	ld	r27, 8(up)
+	nop
+	mulld	r0, r26, v0
+	mulhdu	r31, r26, v0
+	ld	r26, 16(up)
+	mulld	r24, r27, v0
+	mulhdu	r8, r27, v0
+	mulld	r9, r26, v0
+	mulhdu	r10, r26, v0
+	addc	r24, r24, r31
+	adde	r9, r9, r8
+	addze	r12, r10
+	std	r0, 0(rp)
+	std	r24, 8(rp)
+	std	r9, 16(rp)
+	addi	up, up, 16
+	addi	rp, rp, 16
+	ld	r26, 8(up)
+	ld	r27, 16(up)
+	bdz	L(end_m_1)
+
+	ALIGN(16)
+L(lo_m_1):
+	mulld	r0, r26, v0
+	mulhdu	r31, r26, v0
+	ld	r26, 24(up)
+	nop
+	mulld	r24, r27, v0
+	mulhdu	r8, r27, v0
+	ld	r27, 32(up)
+	nop
+	adde	r0, r0, r12
+	adde	r24, r24, r31
+	mulld	r9, r26, v0
+	mulhdu	r10, r26, v0
+	ld	r26, 40(up)
+	nop
+	mulld	r11, r27, v0
+	mulhdu	r12, r27, v0
+	ld	r27, 48(up)
+	std	r0, 8(rp)
+	adde	r9, r9, r8
+	std	r24, 16(rp)
+	adde	r11, r11, r10
+	std	r9, 24(rp)
+	addi	up, up, 32
+	std	r11, 32(rp)
+	addi	rp, rp, 32
+	bdnz	L(lo_m_1)
+
+	ALIGN(16)
+L(end_m_1):
+	mulld	r0, r26, v0
+	mulhdu	r31, r26, v0
+
+	mulld	r24, r27, v0
+	mulhdu	r8, r27, v0
+
+	adde	r0, r0, r12
+	adde	r24, r24, r31
+
+	std	r0, 8(rp)
+	addze	r8, r8
+	std	r24, 16(rp)
+	addic.	vn, vn, -1
+	std	r8, 24(rp)
+	nop
+	beq	L(ret)
+
+	ALIGN(16)
+L(outer_lo_1):
+	mtctr	un		C copy inner loop count into ctr
+	addi	rp, outer_rp, 24
+	addi	up, outer_up, 16
+	addi	outer_rp, outer_rp, 8
+	ld	v0, 0(vp)	C new v limb
+	addi	vp, vp, 8
+	ld	r26, -16(up)
+	ld	r27, -8(up)
+	mulld	r0, r26, v0
+	mulhdu	r31, r26, v0
+	ld	r26, 0(up)
+	ld	r28, -16(rp)
+	mulld	r24, r27, v0
+	mulhdu	r8, r27, v0
+	ld	r29, -8(rp)
+	ld	r30, 0(rp)
+	mulld	r9, r26, v0
+	mulhdu	r10, r26, v0
+	addc	r24, r24, r31
+	adde	r9, r9, r8
+	addze	r12, r10
+	addc	r0, r0, r28
+	std	r0, -16(rp)
+	adde	r24, r24, r29
+	std	r24, -8(rp)
+	adde	r9, r9, r30
+	std	r9, 0(rp)
+	ld	r26, 8(up)
+	ld	r27, 16(up)
+	bdz	L(end_1)
+
+	ALIGN(16)		C registers dying
+L(lo_1):
+	mulld	r0, r26, v0	C
+	mulhdu	r10, r26, v0	C 26
+	ld	r26, 24(up)	C
+	ld	r28, 8(rp)	C
+	mulld	r24, r27, v0	C
+	mulhdu	r8, r27, v0	C 27
+	ld	r27, 32(up)	C
+	ld	r29, 16(rp)	C
+	adde	r0, r0, r12	C 0 12
+	adde	r24, r24, r10	C 24 10
+	mulld	r9, r26, v0	C
+	mulhdu	r10, r26, v0	C 26
+	ld	r26, 40(up)	C
+	ld	r30, 24(rp)	C
+	mulld	r11, r27, v0	C
+	mulhdu	r12, r27, v0	C 27
+	ld	r27, 48(up)	C
+	ld	r31, 32(rp)	C
+	adde	r9, r9, r8	C 8 9
+	adde	r11, r11, r10	C 10 11
+	addze	r12, r12	C 12
+	addc	r0, r0, r28	C 0 28
+	std	r0, 8(rp)	C 0
+	adde	r24, r24, r29	C 7 29
+	std	r24, 16(rp)	C 7
+	adde	r9, r9, r30	C 9 30
+	std	r9, 24(rp)	C 9
+	adde	r11, r11, r31	C 11 31
+	std	r11, 32(rp)	C 11
+	addi	up, up, 32	C
+	addi	rp, rp, 32	C
+	bdnz	L(lo_1)	C
+
+	ALIGN(16)
+L(end_1):
+	mulld	r0, r26, v0
+	mulhdu	r10, r26, v0
+	ld	r28, 8(rp)
+	nop
+	mulld	r24, r27, v0
+	mulhdu	r8, r27, v0
+	ld	r29, 16(rp)
+	nop
+	adde	r0, r0, r12
+	adde	r24, r24, r10
+	addze	r8, r8
+	addic.	vn, vn, -1
+	addc	r0, r0, r28
+	std	r0, 8(rp)
+	adde	r24, r24, r29
+	std	r24, 16(rp)
+	addze	r8, r8
+	std	r8, 24(rp)
+	bne	L(outer_lo_1)
+	b	L(ret)
+
+
+	ALIGN(16)
+L(b2):	ld	r27, 8(up)
+	addi	up, up, -8
+	addi	rp, rp, -8
+	li	r12, 0
+	addic	r12, r12, 0
+
+	ALIGN(16)
+L(lo_m_2):
+	mulld	r0, r26, v0
+	mulhdu	r31, r26, v0
+	ld	r26, 24(up)
+	nop
+	mulld	r24, r27, v0
+	mulhdu	r8, r27, v0
+	ld	r27, 32(up)
+	nop
+	adde	r0, r0, r12
+	adde	r24, r24, r31
+	mulld	r9, r26, v0
+	mulhdu	r10, r26, v0
+	ld	r26, 40(up)
+	nop
+	mulld	r11, r27, v0
+	mulhdu	r12, r27, v0
+	ld	r27, 48(up)
+	std	r0, 8(rp)
+	adde	r9, r9, r8
+	std	r24, 16(rp)
+	adde	r11, r11, r10
+	std	r9, 24(rp)
+	addi	up, up, 32
+	std	r11, 32(rp)
+
+	addi	rp, rp, 32
+	bdnz	L(lo_m_2)
+
+	ALIGN(16)
+L(end_m_2):
+	mulld	r0, r26, v0
+	mulhdu	r31, r26, v0
+
+	mulld	r24, r27, v0
+	mulhdu	r8, r27, v0
+
+	adde	r0, r0, r12
+	adde	r24, r24, r31
+
+	std	r0, 8(rp)
+	addze	r8, r8
+	std	r24, 16(rp)
+	addic.	vn, vn, -1
+	std	r8, 24(rp)
+	nop
+	beq	L(ret)
+
+	ALIGN(16)
+L(outer_lo_2):
+	mtctr	un		C copy inner loop count into ctr
+	addi	rp, outer_rp, 0
+	addi	up, outer_up, -8
+	addi	outer_rp, outer_rp, 8
+	ld	v0, 0(vp)	C new v limb
+	addi	vp, vp, 8
+	ld	r26, 8(up)
+	ld	r27, 16(up)
+	li	r12, 0
+	addic	r12, r12, 0
+
+	ALIGN(16)		C registers dying
+L(lo_2):
+	mulld	r0, r26, v0	C
+	mulhdu	r10, r26, v0	C 26
+	ld	r26, 24(up)	C
+	ld	r28, 8(rp)	C
+	mulld	r24, r27, v0	C
+	mulhdu	r8, r27, v0	C 27
+	ld	r27, 32(up)	C
+	ld	r29, 16(rp)	C
+	adde	r0, r0, r12	C 0 12
+	adde	r24, r24, r10	C 24 10
+	mulld	r9, r26, v0	C
+	mulhdu	r10, r26, v0	C 26
+	ld	r26, 40(up)	C
+	ld	r30, 24(rp)	C
+	mulld	r11, r27, v0	C
+	mulhdu	r12, r27, v0	C 27
+	ld	r27, 48(up)	C
+	ld	r31, 32(rp)	C
+	adde	r9, r9, r8	C 8 9
+	adde	r11, r11, r10	C 10 11
+	addze	r12, r12	C 12
+	addc	r0, r0, r28	C 0 28
+	std	r0, 8(rp)	C 0
+	adde	r24, r24, r29	C 7 29
+	std	r24, 16(rp)	C 7
+	adde	r9, r9, r30	C 9 30
+	std	r9, 24(rp)	C 9
+	adde	r11, r11, r31	C 11 31
+	std	r11, 32(rp)	C 11
+	addi	up, up, 32	C
+	addi	rp, rp, 32	C
+	bdnz	L(lo_2)	C
+
+	ALIGN(16)
+L(end_2):
+	mulld	r0, r26, v0
+	mulhdu	r10, r26, v0
+	ld	r28, 8(rp)
+	nop
+	mulld	r24, r27, v0
+	mulhdu	r8, r27, v0
+	ld	r29, 16(rp)
+	nop
+	adde	r0, r0, r12
+	adde	r24, r24, r10
+	addze	r8, r8
+	addic.	vn, vn, -1
+	addc	r0, r0, r28
+	std	r0, 8(rp)
+	adde	r24, r24, r29
+	std	r24, 16(rp)
+	addze	r8, r8
+	std	r8, 24(rp)
+	bne	L(outer_lo_2)
+	b	L(ret)
+
+
+L(ret):	ld	r31, -8(r1)
+	ld	r30, -16(r1)
+	ld	r29, -24(r1)
+	ld	r28, -32(r1)
+	ld	r27, -40(r1)
+	ld	r26, -48(r1)
+	ld	r25, -56(r1)
+	ld	r24, -64(r1)
+	ld	r23, -72(r1)
+	ld	r22, -80(r1)
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc64/mode64/p3/gmp-mparam.h b/third_party/gmp/mpn/powerpc64/mode64/p3/gmp-mparam.h
new file mode 100644
index 0000000..61a437b
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/p3/gmp-mparam.h
@@ -0,0 +1,179 @@
+/* POWER3/PowerPC630 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2008-2010 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          7
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          3
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        18
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD         0  /* never mpn_mod_1s_2p */
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     17
+#define USE_PREINV_DIVREM_1                  0
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD        MP_SIZE_T_MAX  /* never */
+
+#define MUL_TOOM22_THRESHOLD                10
+#define MUL_TOOM33_THRESHOLD                33
+#define MUL_TOOM44_THRESHOLD                46
+#define MUL_TOOM6H_THRESHOLD                77
+#define MUL_TOOM8H_THRESHOLD               139
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      49
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD      47
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD      49
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD      49
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD      34
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 14
+#define SQR_TOOM3_THRESHOLD                 45
+#define SQR_TOOM4_THRESHOLD                 64
+#define SQR_TOOM6_THRESHOLD                 85
+#define SQR_TOOM8_THRESHOLD                139
+
+#define MULMID_TOOM42_THRESHOLD             22
+
+#define MULMOD_BNM1_THRESHOLD                8
+#define SQRMOD_BNM1_THRESHOLD               10
+
+#define MUL_FFT_MODF_THRESHOLD             220  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    220, 5}, {      9, 6}, {      5, 5}, {     11, 6}, \
+    {     13, 7}, {      7, 6}, {     15, 7}, {     13, 8}, \
+    {      7, 7}, {     15, 8}, {     13, 9}, {      7, 8}, \
+    {     19, 9}, {     11, 8}, {     23,10}, {      7, 9}, \
+    {     15, 8}, {     33, 9}, {     23,10}, {     15, 9}, \
+    {     35, 8}, {     71,10}, {     23, 9}, {     47,11}, \
+    {     15,10}, {     31, 9}, {     71,10}, {     39, 9}, \
+    {     79,10}, {     55,11}, {     31,10}, {     63, 9}, \
+    {    127,10}, {     71, 9}, {    143, 8}, {    287,10}, \
+    {     79,11}, {     47,10}, {     95, 9}, {    191,12}, \
+    {     31,11}, {     63,10}, {    127, 9}, {    255, 8}, \
+    {    511,10}, {    143, 9}, {    287,11}, {     79,10}, \
+    {    159, 9}, {    319, 8}, {    639,10}, {    175, 9}, \
+    {    351,11}, {     95,10}, {    191, 9}, {    383,11}, \
+    {    111,10}, {    223,12}, {     63,11}, {    127,10}, \
+    {    255, 9}, {    511,11}, {    143,10}, {    287, 9}, \
+    {    575,11}, {    159,10}, {    319, 9}, {    639,11}, \
+    {    175,10}, {    351,12}, {     95,11}, {    191,10}, \
+    {    383, 9}, {    767,11}, {    223,13}, {     63,12}, \
+    {    127,11}, {    255,10}, {    511,11}, {    287,10}, \
+    {    575, 9}, {   1151,12}, {    159,11}, {    319,10}, \
+    {    639,11}, {    351,12}, {    191,11}, {    383,10}, \
+    {    767,12}, {    223,11}, {    447,10}, {    895,13}, \
+    {    127,12}, {    255,11}, {    511,12}, {    287,11}, \
+    {    575,10}, {   1151,12}, {    319,11}, {    639,12}, \
+    {    351,11}, {    703,13}, {    191,12}, {    383,11}, \
+    {    767,12}, {    415,11}, {    831,10}, {   1663,12}, \
+    {    447,11}, {    895,14}, {  16384,15}, {  32768,16}, \
+    {  65536,17}, { 131072,18}, { 262144,19}, { 524288,20}, \
+    {1048576,21}, {2097152,22}, {4194304,23}, {8388608,24} }
+#define MUL_FFT_TABLE3_SIZE 120
+#define MUL_FFT_THRESHOLD                 2688
+
+#define SQR_FFT_MODF_THRESHOLD             188  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    188, 5}, {      9, 6}, {      5, 5}, {     11, 6}, \
+    {     13, 7}, {     13, 8}, {      7, 7}, {     16, 8}, \
+    {      9, 7}, {     19, 8}, {     13, 9}, {      7, 8}, \
+    {     19, 9}, {     11, 8}, {     23,10}, {      7, 9}, \
+    {     15, 8}, {     31, 9}, {     19, 8}, {     39, 9}, \
+    {     23,10}, {     15, 9}, {     39,10}, {     23,11}, \
+    {     15,10}, {     31, 9}, {     67,10}, {     39, 9}, \
+    {     79, 8}, {    159,10}, {     47, 9}, {     95, 8}, \
+    {    191,11}, {     31,10}, {     63, 9}, {    127, 8}, \
+    {    255,10}, {     71, 9}, {    143, 8}, {    287,10}, \
+    {     79, 9}, {    159,11}, {     47,10}, {     95, 9}, \
+    {    191,12}, {     31,11}, {     63,10}, {    127, 9}, \
+    {    255, 8}, {    511,10}, {    143, 9}, {    287,11}, \
+    {     79,10}, {    159, 9}, {    319, 8}, {    639,10}, \
+    {    175,11}, {     95,10}, {    191, 9}, {    383,11}, \
+    {    111,10}, {    223,12}, {     63,11}, {    127,10}, \
+    {    255, 9}, {    511,11}, {    143,10}, {    287, 9}, \
+    {    575,11}, {    159,10}, {    319, 9}, {    639,11}, \
+    {    175,12}, {     95,11}, {    191,10}, {    383, 9}, \
+    {    767,11}, {    223,13}, {     63,12}, {    127,11}, \
+    {    255,10}, {    511,11}, {    287,10}, {    575,12}, \
+    {    159,11}, {    319,10}, {    639,11}, {    351,12}, \
+    {    191,11}, {    383,10}, {    767,12}, {    223,11}, \
+    {    447,10}, {    895,13}, {    127,12}, {    255,11}, \
+    {    511,12}, {    287,11}, {    575,10}, {   1151,12}, \
+    {    319,11}, {    639,12}, {    351,13}, {    191,12}, \
+    {    383,11}, {    767,12}, {    447,11}, {    895,14}, \
+    {  16384,15}, {  32768,16}, {  65536,17}, { 131072,18}, \
+    { 262144,19}, { 524288,20}, {1048576,21}, {2097152,22}, \
+    {4194304,23}, {8388608,24} }
+#define SQR_FFT_TABLE3_SIZE 118
+#define SQR_FFT_THRESHOLD                 1728
+
+#define MULLO_BASECASE_THRESHOLD             2
+#define MULLO_DC_THRESHOLD                  27
+#define MULLO_MUL_N_THRESHOLD             2511
+
+#define DC_DIV_QR_THRESHOLD                 23
+#define DC_DIVAPPR_Q_THRESHOLD              87
+#define DC_BDIV_QR_THRESHOLD                27
+#define DC_BDIV_Q_THRESHOLD                 60
+
+#define INV_MULMOD_BNM1_THRESHOLD           27
+#define INV_NEWTON_THRESHOLD                91
+#define INV_APPR_THRESHOLD                  91
+
+#define BINV_NEWTON_THRESHOLD              115
+#define REDC_1_TO_REDC_N_THRESHOLD          31
+
+#define MU_DIV_QR_THRESHOLD                551
+#define MU_DIVAPPR_Q_THRESHOLD             551
+#define MUPI_DIV_QR_THRESHOLD               42
+#define MU_BDIV_QR_THRESHOLD               483
+#define MU_BDIV_Q_THRESHOLD                492
+
+#define POWM_SEC_TABLE  2,23,140,556,713,746
+
+#define MATRIX22_STRASSEN_THRESHOLD          8
+#define HGCD_THRESHOLD                      56
+#define HGCD_APPR_THRESHOLD                 51
+#define HGCD_REDUCE_THRESHOLD              688
+#define GCD_DC_THRESHOLD                   333
+#define GCDEXT_DC_THRESHOLD                126
+#define JACOBI_BASE_METHOD                   1
+
+#define GET_STR_DC_THRESHOLD                17
+#define GET_STR_PRECOMPUTE_THRESHOLD        28
+#define SET_STR_DC_THRESHOLD               375
+#define SET_STR_PRECOMPUTE_THRESHOLD       812
+
+#define FAC_DSC_THRESHOLD                  351
+#define FAC_ODD_THRESHOLD                    0  /* always */
diff --git a/third_party/gmp/mpn/powerpc64/mode64/p4/gmp-mparam.h b/third_party/gmp/mpn/powerpc64/mode64/p4/gmp-mparam.h
new file mode 100644
index 0000000..3c40fb9
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/p4/gmp-mparam.h
@@ -0,0 +1,214 @@
+/* POWER4/PowerPC970 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2008-2010, 2014, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+/* 1800 MHz PPC970 */
+/* FFT tuning limit = 15 M */
+/* Generated by tuneup.c, 2015-10-09, gcc 4.0 */
+
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          7
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          5
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD         9
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        22
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     16
+#define USE_PREINV_DIVREM_1                  0
+#define DIV_QR_1N_PI1_METHOD                 1
+#define DIV_QR_1_NORM_THRESHOLD              1
+#define DIV_QR_1_UNNORM_THRESHOLD            1
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           35
+
+#define DIV_1_VS_MUL_1_PERCENT             218
+
+#define MUL_TOOM22_THRESHOLD                14
+#define MUL_TOOM33_THRESHOLD                53
+#define MUL_TOOM44_THRESHOLD               136
+#define MUL_TOOM6H_THRESHOLD               197
+#define MUL_TOOM8H_THRESHOLD               272
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      89
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD      91
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD      89
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD      90
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD      76
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 22
+#define SQR_TOOM3_THRESHOLD                 73
+#define SQR_TOOM4_THRESHOLD                202
+#define SQR_TOOM6_THRESHOLD                  0  /* always */
+#define SQR_TOOM8_THRESHOLD                430
+
+#define MULMID_TOOM42_THRESHOLD             34
+
+#define MULMOD_BNM1_THRESHOLD               11
+#define SQRMOD_BNM1_THRESHOLD               13
+
+#define MUL_FFT_MODF_THRESHOLD             444  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    444, 5}, {     17, 6}, {      9, 5}, {     19, 6}, \
+    {     10, 5}, {     21, 6}, {     13, 5}, {     28, 6}, \
+    {     19, 7}, {     10, 6}, {     21, 7}, {     11, 6}, \
+    {     23, 7}, {     12, 6}, {     25, 7}, {     21, 8}, \
+    {     11, 7}, {     25, 8}, {     13, 7}, {     28, 8}, \
+    {     15, 7}, {     31, 8}, {     21, 9}, {     11, 8}, \
+    {     27, 9}, {     15, 8}, {     35, 9}, {     19, 8}, \
+    {     39, 9}, {     23, 8}, {     49, 9}, {     27,10}, \
+    {     15, 9}, {     39,10}, {     23, 9}, {     55,11}, \
+    {     15,10}, {     31, 9}, {     71,10}, {     39, 9}, \
+    {     83,10}, {     47, 9}, {     95,10}, {     55,11}, \
+    {     31,10}, {     63, 9}, {    127,10}, {     87,11}, \
+    {     47,10}, {    103,12}, {     31,11}, {     63,10}, \
+    {    135, 9}, {    271,11}, {     79,10}, {    159, 9}, \
+    {    319,10}, {    167,11}, {     95, 9}, {    383, 8}, \
+    {    767,10}, {    199,11}, {    111,12}, {     63,11}, \
+    {    127,10}, {    255, 9}, {    511,10}, {    271, 9}, \
+    {    543,11}, {    143,10}, {    287, 9}, {    575,10}, \
+    {    303, 9}, {    607,11}, {    159,10}, {    319, 9}, \
+    {    639,10}, {    335, 9}, {    671,10}, {    351,12}, \
+    {     95,10}, {    383, 9}, {    767,10}, {    415, 9}, \
+    {    831,13}, {     63,12}, {    127,11}, {    255,10}, \
+    {    511,11}, {    271,10}, {    543,11}, {    287,10}, \
+    {    575,11}, {    303,10}, {    607,12}, {    159,11}, \
+    {    319,10}, {    639,11}, {    335,10}, {    671,11}, \
+    {    351,10}, {    703,11}, {    383,10}, {    767,11}, \
+    {    415,10}, {    831,12}, {    223,10}, {    895,13}, \
+    {    127,12}, {    255,11}, {    543,12}, {    287,11}, \
+    {    607,12}, {    319,11}, {    671,12}, {    351,11}, \
+    {    703,12}, {    383,11}, {    767,12}, {    415,11}, \
+    {    895,14}, {    127,13}, {    255,12}, {    607,13}, \
+    {    319,12}, {    703,13}, {    383,12}, {    895,14}, \
+    {    255,13}, {    511,12}, {   1023,13}, {    575,12}, \
+    {   1151,13}, {    703,14}, {    383,13}, {    895,15}, \
+    {    255,14}, {    511,13}, {   1023,12}, {   2047,13}, \
+    {   1087,12}, {   2175,13}, {   1151,14}, {    639,13}, \
+    {   1343,12}, {   2687,13}, {   1407,14}, {    767,13}, \
+    {   1663,14}, {    895,15}, {  32768,16}, {  65536,17}, \
+    { 131072,18}, { 262144,19}, { 524288,20}, {1048576,21}, \
+    {2097152,22}, {4194304,23}, {8388608,24} }
+#define MUL_FFT_TABLE3_SIZE 159
+#define MUL_FFT_THRESHOLD                 9088
+
+#define SQR_FFT_MODF_THRESHOLD             344  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    344, 5}, {     15, 6}, {      8, 5}, {     17, 6}, \
+    {      9, 5}, {     19, 6}, {     10, 5}, {     21, 6}, \
+    {     13, 5}, {     28, 6}, {     21, 7}, {     11, 6}, \
+    {     23, 7}, {     12, 6}, {     25, 7}, {     14, 6}, \
+    {     29, 7}, {     21, 8}, {     11, 7}, {     25, 8}, \
+    {     13, 7}, {     27, 8}, {     15, 7}, {     31, 8}, \
+    {     21, 9}, {     11, 8}, {     27, 9}, {     15, 8}, \
+    {     35, 9}, {     19, 8}, {     39, 9}, {     23, 8}, \
+    {     47, 9}, {     27,10}, {     15, 9}, {     39,10}, \
+    {     23, 9}, {     51,11}, {     15,10}, {     31, 9}, \
+    {     67,10}, {     39, 9}, {     79,10}, {     47, 9}, \
+    {     95,10}, {     55,11}, {     31,10}, {     79,11}, \
+    {     47,10}, {     95, 9}, {    191,10}, {    103,12}, \
+    {     31,11}, {     63,10}, {    127, 9}, {    255, 8}, \
+    {    511,10}, {    135, 9}, {    271, 8}, {    543,11}, \
+    {     79, 9}, {    319, 8}, {    639,11}, {     95,10}, \
+    {    191, 9}, {    383, 8}, {    767,10}, {    207, 9}, \
+    {    415,12}, {     63,11}, {    127,10}, {    255, 9}, \
+    {    511,10}, {    271, 9}, {    543,10}, {    287, 9}, \
+    {    575,10}, {    303, 9}, {    607,10}, {    319, 9}, \
+    {    639,10}, {    335,11}, {    175,10}, {    351, 9}, \
+    {    703,11}, {    191,10}, {    383, 9}, {    767,11}, \
+    {    207,10}, {    415, 9}, {    831,13}, {     63,12}, \
+    {    127,11}, {    255,10}, {    511,11}, {    271,10}, \
+    {    543,11}, {    287,10}, {    575,11}, {    303,10}, \
+    {    607,11}, {    319,10}, {    639,11}, {    335,10}, \
+    {    671,11}, {    351,10}, {    703,12}, {    191,11}, \
+    {    383,10}, {    767,11}, {    415,10}, {    831,12}, \
+    {    223,10}, {    895,11}, {    479,13}, {    127,12}, \
+    {    255,11}, {    543,12}, {    287,11}, {    607,12}, \
+    {    319,11}, {    671,12}, {    351,11}, {    703,13}, \
+    {    191,12}, {    383,11}, {    767,12}, {    415,11}, \
+    {    831,10}, {   1663,11}, {    895,12}, {    479,14}, \
+    {    127,13}, {    255,12}, {    607,13}, {    319,12}, \
+    {    703,13}, {    383,12}, {    831,11}, {   1663,12}, \
+    {    927,14}, {    255,13}, {    511,12}, {   1023,13}, \
+    {    575,12}, {   1151,13}, {    639,12}, {   1279,13}, \
+    {    703,14}, {    383,13}, {    895,15}, {    255,14}, \
+    {    511,13}, {   1023,12}, {   2175,13}, {   1151,12}, \
+    {   2303,13}, {   1215,14}, {    639,13}, {   1343,12}, \
+    {   2687,13}, {   1407,14}, {    767,13}, {   1663,14}, \
+    {    895,15}, {  32768,16}, {  65536,17}, { 131072,18}, \
+    { 262144,19}, { 524288,20}, {1048576,21}, {2097152,22}, \
+    {4194304,23}, {8388608,24} }
+#define SQR_FFT_TABLE3_SIZE 174
+#define SQR_FFT_THRESHOLD                 6272
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  43
+#define MULLO_MUL_N_THRESHOLD            18087
+#define SQRLO_BASECASE_THRESHOLD             2
+#define SQRLO_DC_THRESHOLD                  79
+#define SQRLO_SQR_THRESHOLD              12322
+
+#define DC_DIV_QR_THRESHOLD                 42
+#define DC_DIVAPPR_Q_THRESHOLD             159
+#define DC_BDIV_QR_THRESHOLD                46
+#define DC_BDIV_Q_THRESHOLD                110
+
+#define INV_MULMOD_BNM1_THRESHOLD           26
+#define INV_NEWTON_THRESHOLD               177
+#define INV_APPR_THRESHOLD                 165
+
+#define BINV_NEWTON_THRESHOLD              198
+#define REDC_1_TO_REDC_N_THRESHOLD          56
+
+#define MU_DIV_QR_THRESHOLD               1017
+#define MU_DIVAPPR_Q_THRESHOLD            1142
+#define MUPI_DIV_QR_THRESHOLD               90
+#define MU_BDIV_QR_THRESHOLD               924
+#define MU_BDIV_Q_THRESHOLD               1017
+
+#define POWM_SEC_TABLE  7,17,86,579,1925
+
+#define GET_STR_DC_THRESHOLD                14
+#define GET_STR_PRECOMPUTE_THRESHOLD        23
+#define SET_STR_DC_THRESHOLD               788
+#define SET_STR_PRECOMPUTE_THRESHOLD      1713
+
+#define FAC_DSC_THRESHOLD                  512
+#define FAC_ODD_THRESHOLD                   25
+
+#define MATRIX22_STRASSEN_THRESHOLD         10
+#define HGCD_THRESHOLD                     113
+#define HGCD_APPR_THRESHOLD                115
+#define HGCD_REDUCE_THRESHOLD             4633
+#define GCD_DC_THRESHOLD                   330
+#define GCDEXT_DC_THRESHOLD                242
+#define JACOBI_BASE_METHOD                   4
diff --git a/third_party/gmp/mpn/powerpc64/mode64/p5/gmp-mparam.h b/third_party/gmp/mpn/powerpc64/mode64/p5/gmp-mparam.h
new file mode 100644
index 0000000..15b009c
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/p5/gmp-mparam.h
@@ -0,0 +1,219 @@
+/* POWER5 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 1999-2003, 2009, 2010 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+/* POWER5 (friggms.hpc.ntnu.no) */
+
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          6
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          5
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        15
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD         0  /* never mpn_mod_1s_2p */
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     11
+#define USE_PREINV_DIVREM_1                  0
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           40
+
+#define MUL_TOOM22_THRESHOLD                21
+#define MUL_TOOM33_THRESHOLD                24
+#define MUL_TOOM44_THRESHOLD                70
+#define MUL_TOOM6H_THRESHOLD               262
+#define MUL_TOOM8H_THRESHOLD               393
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      49
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     126
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD      85
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD      94
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD      70
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 24
+#define SQR_TOOM3_THRESHOLD                 81
+#define SQR_TOOM4_THRESHOLD                142
+#define SQR_TOOM6_THRESHOLD                189
+#define SQR_TOOM8_THRESHOLD                284
+
+#define MULMID_TOOM42_THRESHOLD             36
+
+#define MULMOD_BNM1_THRESHOLD               12
+#define SQRMOD_BNM1_THRESHOLD               15
+
+#define MUL_FFT_MODF_THRESHOLD             304  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    348, 5}, {     17, 6}, {      9, 5}, {     19, 6}, \
+    {     10, 5}, {     21, 6}, {     21, 7}, {     11, 6}, \
+    {     23, 7}, {     12, 6}, {     25, 7}, {     21, 8}, \
+    {     11, 7}, {     25, 8}, {     13, 7}, {     27, 8}, \
+    {     15, 7}, {     31, 8}, {     21, 9}, {     11, 8}, \
+    {     27, 9}, {     15, 8}, {     33, 9}, {     19, 8}, \
+    {     39, 9}, {     23, 8}, {     47, 9}, {     27,10}, \
+    {     15, 9}, {     39,10}, {     23, 9}, {     51,11}, \
+    {     15,10}, {     31, 9}, {     67,10}, {     39, 9}, \
+    {     79,10}, {     47, 9}, {     95,10}, {     55,11}, \
+    {     31,10}, {     79,11}, {     47,10}, {     95,12}, \
+    {     31,11}, {     63,10}, {    127, 9}, {    255,10}, \
+    {    135,11}, {     79,10}, {    159, 9}, {    319,11}, \
+    {     95,10}, {    191, 9}, {    383,12}, {     63,11}, \
+    {    127,10}, {    255, 9}, {    511,10}, {    271,11}, \
+    {    143,10}, {    287, 9}, {    575,10}, {    319,12}, \
+    {     95,11}, {    191,10}, {    383,13}, {     63,12}, \
+    {    127,11}, {    255,10}, {    511,11}, {    271,10}, \
+    {    543,11}, {    287,10}, {    575, 9}, {   1151,11}, \
+    {    319,10}, {    639,11}, {    351,10}, {    703,12}, \
+    {    191,11}, {    383,10}, {    767,11}, {    415,12}, \
+    {    223,11}, {    447,13}, {    127,12}, {    255,11}, \
+    {    511,10}, {   1023,11}, {    543,10}, {   1087,12}, \
+    {    287,11}, {    575,10}, {   1151,12}, {    319,11}, \
+    {    639,12}, {    351,11}, {    703,13}, {    191,12}, \
+    {    383,11}, {    767,12}, {    415,11}, {    831,12}, \
+    {    447,11}, {    895,14}, {    127,13}, {    255,12}, \
+    {    511,11}, {   1023,12}, {    543,11}, {   1087,10}, \
+    {   2175,12}, {    575,11}, {   1151,12}, {    607,13}, \
+    {    319,12}, {    639,11}, {   1279,12}, {    671,11}, \
+    {   1343,12}, {    703,11}, {   1407,13}, {    383,12}, \
+    {    767,11}, {   1535,12}, {    831,13}, {    447,12}, \
+    {    959,11}, {   1919,14}, {    255,13}, {    511,12}, \
+    {   1087,11}, {   2175,13}, {    575,12}, {   1215,11}, \
+    {   2431,10}, {   4863,13}, {    639,12}, {   1343,13}, \
+    {    703,12}, {   1407,14}, {    383,13}, {    767,12}, \
+    {   1535,13}, {    831,12}, {   1663,13}, {    959,12}, \
+    {   1919,11}, {   3839,15}, {    255,14}, {    511,13}, \
+    {   1087,12}, {   2175,13}, {   1215,12}, {   2431,11}, \
+    {   4863,14}, {    639,13}, {   1343,12}, {   2687,13}, \
+    {   1407,12}, {   2815,13}, {   1471,12}, {   2943,14}, \
+    {    767,13}, {   1599,12}, {   3199,13}, {   1663,14}, \
+    {    895,13}, {   1919,12}, {   3839,15}, {    511,14}, \
+    {   1023,13}, {   2175,14}, {   1151,13}, {   2431,12}, \
+    {   4863,14}, {   1279,13}, {   2687,14}, {   1407,13}, \
+    {   2943,15}, {    767,14}, {   1535,13}, {   3199,14}, \
+    {   1663,13}, {   3327,14}, {   1919,13}, {   3839,16}, \
+    {    511,15}, {   1023,14}, {   2431,13}, {   4863,15}, \
+    {   1279,14}, {   2943,12}, {  11775,15}, {   1535,14}, \
+    {   3327,15}, {   1791,14}, {  16384,15}, {  32768,16}, \
+    {  65536,17}, { 131072,18}, { 262144,19}, { 524288,20}, \
+    {1048576,21}, {2097152,22}, {4194304,23}, {8388608,24} }
+#define MUL_FFT_TABLE3_SIZE 208
+#define MUL_FFT_THRESHOLD                 4224
+
+#define SQR_FFT_MODF_THRESHOLD             284  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    272, 5}, {     15, 6}, {      8, 5}, {     17, 6}, \
+    {     19, 7}, {     17, 8}, {      9, 7}, {     21, 8}, \
+    {     11, 7}, {     24, 8}, {     13, 7}, {     27, 8}, \
+    {     15, 7}, {     31, 8}, {     21, 9}, {     11, 8}, \
+    {     27, 9}, {     15, 8}, {     33, 9}, {     19, 8}, \
+    {     39, 9}, {     23, 8}, {     47, 9}, {     27,10}, \
+    {     15, 9}, {     39,10}, {     23, 9}, {     47,11}, \
+    {     15,10}, {     31, 9}, {     63,10}, {     47,11}, \
+    {     31,10}, {     71, 9}, {    143,10}, {     79,11}, \
+    {     47,10}, {     95,12}, {     31,11}, {     63,10}, \
+    {    127, 9}, {    255, 8}, {    511, 9}, {    271,10}, \
+    {    143,11}, {     79,10}, {    159, 9}, {    319,10}, \
+    {    175, 9}, {    351,11}, {     95,10}, {    191, 9}, \
+    {    383,10}, {    207, 9}, {    415,12}, {     63,11}, \
+    {    127,10}, {    255, 9}, {    511,10}, {    271,11}, \
+    {    143,10}, {    287, 9}, {    575,11}, {    159,10}, \
+    {    319,11}, {    175,10}, {    351,12}, {     95,11}, \
+    {    191,10}, {    383,11}, {    207,10}, {    415,13}, \
+    {     63,12}, {    127,11}, {    255,10}, {    511,11}, \
+    {    271,10}, {    543,11}, {    287,10}, {    575,12}, \
+    {    159,11}, {    319,10}, {    639,11}, {    351,10}, \
+    {    703,12}, {    191,11}, {    383,10}, {    767,11}, \
+    {    415,12}, {    223,11}, {    447,10}, {    895,11}, \
+    {    479,10}, {    959,12}, {    255,11}, {    511,10}, \
+    {   1023,11}, {    543,12}, {    287,11}, {    575,12}, \
+    {    319,11}, {    639,12}, {    351,11}, {    703,13}, \
+    {    191,12}, {    383,11}, {    767,12}, {    415,11}, \
+    {    831,12}, {    447,11}, {    895,12}, {    479,11}, \
+    {    959,13}, {    255,12}, {    511,11}, {   1023,12}, \
+    {    543,11}, {   1087,12}, {    575,13}, {    319,12}, \
+    {    639,11}, {   1279,12}, {    703,11}, {   1407,13}, \
+    {    383,12}, {    831,13}, {    447,12}, {    959,14}, \
+    {    255,13}, {    511,12}, {   1087,13}, {    575,12}, \
+    {   1215,13}, {    639,12}, {   1279,13}, {    703,12}, \
+    {   1407,14}, {    383,13}, {    831,12}, {   1663,13}, \
+    {    959,12}, {   1919,15}, {    255,14}, {    511,13}, \
+    {   1023,12}, {   2047,13}, {   1087,12}, {   2175,13}, \
+    {   1215,14}, {    639,13}, {   1407,12}, {   2815,14}, \
+    {    767,13}, {   1663,14}, {    895,13}, {   1919,15}, \
+    {    511,14}, {   1023,13}, {   2175,14}, {   1151,13}, \
+    {   2431,12}, {   4863,14}, {   1407,13}, {   2815,15}, \
+    {    767,14}, {   1663,13}, {   3327,14}, {   1919,13}, \
+    {   3839,16}, {    511,15}, {   1023,14}, {   2431,13}, \
+    {   4863,15}, {   1279,14}, {   2943,13}, {   5887,12}, \
+    {  11775,15}, {   1535,14}, {   3327,15}, {   1791,14}, \
+    {  16384,15}, {  32768,16}, {  65536,17}, { 131072,18}, \
+    { 262144,19}, { 524288,20}, {1048576,21}, {2097152,22}, \
+    {4194304,23}, {8388608,24} }
+#define SQR_FFT_TABLE3_SIZE 190
+#define SQR_FFT_THRESHOLD                 3264
+
+#define MULLO_BASECASE_THRESHOLD             6
+#define MULLO_DC_THRESHOLD                  60
+#define MULLO_MUL_N_THRESHOLD             7463
+
+#define DC_DIV_QR_THRESHOLD                 58
+#define DC_DIVAPPR_Q_THRESHOLD             232
+#define DC_BDIV_QR_THRESHOLD                78
+#define DC_BDIV_Q_THRESHOLD                238
+
+#define INV_MULMOD_BNM1_THRESHOLD           92
+#define INV_NEWTON_THRESHOLD               155
+#define INV_APPR_THRESHOLD                 157
+
+#define BINV_NEWTON_THRESHOLD              155
+#define REDC_1_TO_REDC_N_THRESHOLD          61
+
+#define MU_DIV_QR_THRESHOLD                998
+#define MU_DIVAPPR_Q_THRESHOLD             979
+#define MUPI_DIV_QR_THRESHOLD               79
+#define MU_BDIV_QR_THRESHOLD               823
+#define MU_BDIV_Q_THRESHOLD                942
+
+#define MATRIX22_STRASSEN_THRESHOLD         14
+#define HGCD_THRESHOLD                      74
+#define HGCD_APPR_THRESHOLD                155
+#define HGCD_REDUCE_THRESHOLD             2479
+#define GCD_DC_THRESHOLD                   351
+#define GCDEXT_DC_THRESHOLD                288
+#define JACOBI_BASE_METHOD                   4
+
+#define GET_STR_DC_THRESHOLD                12
+#define GET_STR_PRECOMPUTE_THRESHOLD        21
+#define SET_STR_DC_THRESHOLD               650
+#define SET_STR_PRECOMPUTE_THRESHOLD      1585
+
+#define FAC_DSC_THRESHOLD                  662
+#define FAC_ODD_THRESHOLD                   28
diff --git a/third_party/gmp/mpn/powerpc64/mode64/p6/aorsmul_1.asm b/third_party/gmp/mpn/powerpc64/mode64/p6/aorsmul_1.asm
new file mode 100644
index 0000000..c572b91
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/p6/aorsmul_1.asm
@@ -0,0 +1,185 @@
+dnl  PowerPC-64 mpn_addmul_1 and mpn_submul_1 optimised for power6.
+
+dnl  Copyright 1999-2001, 2003-2006, 2008, 2010, 2011 Free Software Foundation,
+dnl  Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C               mpn_addmul_1    mpn_submul_1
+C               cycles/limb     cycles/limb
+C POWER3/PPC630     ?               ?
+C POWER4/PPC970     ?               ?
+C POWER5            ?               ?
+C POWER6           12.25           12.8
+C POWER7            ?               ?
+
+C TODO
+C  * Reduce register usage.
+C  * Schedule function entry code.
+C  * Unroll more.  8-way unrolling would bring us to 10 c/l, 16-way unrolling
+C    would bring us to 9 c/l.
+C  * Handle n = 1 and perhaps n = 2 separately, without saving any registers.
+
+C INPUT PARAMETERS
+define(`rp',  `r3')
+define(`up',  `r4')
+define(`n',   `r5')
+define(`v0',  `r6')
+
+ifdef(`OPERATION_addmul_1',`
+  define(ADDSUBC,	adde)
+  define(ADDSUB,	addc)
+  define(func,		mpn_addmul_1)
+  define(func_nc,	mpn_addmul_1c)	C FIXME: not really supported
+  define(AM,		`$1')
+  define(SM,		`')
+  define(CLRRSC,	`addic	$1, r0, 0')
+')
+ifdef(`OPERATION_submul_1',`
+  define(ADDSUBC,	subfe)
+  define(ADDSUB,	subfc)
+  define(func,		mpn_submul_1)
+  define(func_nc,	mpn_submul_1c)	C FIXME: not really supported
+  define(AM,		`')
+  define(SM,		`$1')
+  define(CLRRSC,	`subfc	$1, r0, r0')
+')
+
+MULFUNC_PROLOGUE(mpn_addmul_1 mpn_submul_1)
+
+ASM_START()
+PROLOGUE(func)
+	std	r31, -8(r1)
+	std	r30, -16(r1)
+	std	r29, -24(r1)
+	std	r28, -32(r1)
+	std	r27, -40(r1)
+
+	rldicl.	r0, n, 0,62	C r0 = n & 3, set cr0
+	cmpdi	cr6, r0, 2
+	addi	n, n, 3		C compute count...
+	srdi	n, n, 2		C ...for ctr
+	mtctr	n		C copy loop count into ctr
+	beq	cr0, L(b0)
+	blt	cr6, L(b1)
+	beq	cr6, L(b2)
+
+L(b3):	ld	r8, 0(up)
+	ld	r7, 8(up)
+	ld	r27, 16(up)
+	addi	up, up, 16
+	addi	rp, rp, 16
+	mulld	r5,  r8, v0
+	mulhdu	r8,  r8, v0
+	mulld	r9,  r7, v0
+	mulhdu	r7,  r7, v0
+	mulld	r11, r27, v0
+	mulhdu	r27, r27, v0
+	ld	r29, -16(rp)
+	ld	r30, -8(rp)
+	ld	r31, 0(rp)
+	addc	r9, r9, r8
+	adde	r11, r11, r7
+	addze	r12, r27
+	ADDSUB	r5, r5, r29
+	b	L(l3)
+
+L(b2):	ld	r7, 0(up)
+	ld	r27, 8(up)
+	addi	up, up, 8
+	addi	rp, rp, 8
+	mulld	r9,  r7, v0
+	mulhdu	r7,  r7, v0
+	mulld	r11, r27, v0
+	mulhdu	r27, r27, v0
+	ld	r30, -8(rp)
+	ld	r31, 0(rp)
+	addc	r11, r11, r7
+	addze	r12, r27
+	ADDSUB	r9, r9, r30
+	b	L(l2)
+
+L(b1):	ld	r27, 0(up)
+	ld	r31, 0(rp)
+	mulld	r11, r27, v0
+	mulhdu	r12, r27, v0
+	ADDSUB	r11, r11, r31
+	b	L(l1)
+
+L(b0):	addi	up, up, -8
+	addi	rp, rp, -8
+	CLRRSC(	r12)		C clear r12 and clr/set cy
+
+	ALIGN(32)
+L(top):
+SM(`	subfe	r11, r0, r0')	C complement...
+SM(`	addic	r11, r11, 1')	C ...carry flag
+	ld	r10, 8(up)
+	ld	r8, 16(up)
+	ld	r7, 24(up)
+	ld	r27, 32(up)
+	addi	up, up, 32
+	addi	rp, rp, 32
+	mulld	r0,  r10, v0
+	mulhdu	r10, r10, v0
+	mulld	r5,  r8, v0
+	mulhdu	r8,  r8, v0
+	mulld	r9,  r7, v0
+	mulhdu	r7,  r7, v0
+	mulld	r11, r27, v0
+	mulhdu	r27, r27, v0
+	ld	r28, -24(rp)
+	adde	r0, r0, r12
+	ld	r29, -16(rp)
+	adde	r5, r5, r10
+	ld	r30, -8(rp)
+	ld	r31, 0(rp)
+	adde	r9, r9, r8
+	adde	r11, r11, r7
+	addze	r12, r27
+	ADDSUB	r0, r0, r28
+	std	r0, -24(rp)
+	ADDSUBC	r5, r5, r29
+L(l3):	std	r5, -16(rp)
+	ADDSUBC	r9, r9, r30
+L(l2):	std	r9, -8(rp)
+	ADDSUBC	r11, r11, r31
+L(l1):	std	r11, 0(rp)
+	bdnz	L(top)
+
+AM(`	addze	r3, r12')
+SM(`	subfe	r11, r0, r0')		C complement...
+	ld	r31, -8(r1)
+SM(`	subf	r3, r11, r12')
+	ld	r30, -16(r1)
+	ld	r29, -24(r1)
+	ld	r28, -32(r1)
+	ld	r27, -40(r1)
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc64/mode64/p6/gmp-mparam.h b/third_party/gmp/mpn/powerpc64/mode64/p6/gmp-mparam.h
new file mode 100644
index 0000000..c7e2f89
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/p6/gmp-mparam.h
@@ -0,0 +1,160 @@
+/* POWER6 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 1999-2003, 2009-2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+/* 3500 MHz POWER6 (kolga.bibsys.no) */
+
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          3
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          3
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        12
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD         0  /* never mpn_mod_1s_2p */
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD      6
+#define USE_PREINV_DIVREM_1                  0
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           21
+
+#define MUL_TOOM22_THRESHOLD                20
+#define MUL_TOOM33_THRESHOLD                50
+#define MUL_TOOM44_THRESHOLD               106
+#define MUL_TOOM6H_THRESHOLD               274
+#define MUL_TOOM8H_THRESHOLD               339
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      62
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD      76
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD      73
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD      66
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD      88
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 24
+#define SQR_TOOM3_THRESHOLD                 49
+#define SQR_TOOM4_THRESHOLD                130
+#define SQR_TOOM6_THRESHOLD                226
+#define SQR_TOOM8_THRESHOLD                272
+
+#define MULMID_TOOM42_THRESHOLD             36
+
+#define MULMOD_BNM1_THRESHOLD               14
+#define SQRMOD_BNM1_THRESHOLD               14
+
+#define MUL_FFT_MODF_THRESHOLD             380  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    340, 5}, {     19, 6}, {     10, 5}, {     21, 6}, \
+    {     11, 5}, {     23, 6}, {     21, 7}, {     11, 6}, \
+    {     23, 7}, {     12, 6}, {     25, 7}, {     21, 8}, \
+    {     11, 7}, {     24, 8}, {     13, 7}, {     27, 8}, \
+    {     21, 9}, {     11, 8}, {     25, 9}, {     15, 8}, \
+    {     33, 9}, {     23, 8}, {     47, 9}, {     27,10}, \
+    {     15, 9}, {     39,10}, {     23, 9}, {     47,11}, \
+    {     15,10}, {     31, 9}, {     63,10}, {     47,11}, \
+    {     31,10}, {     71,11}, {     47,12}, {     31,11}, \
+    {     63,10}, {    127, 9}, {    255, 8}, {    511,10}, \
+    {    135, 9}, {    271,11}, {     79, 9}, {    319, 8}, \
+    {    639,10}, {    175,11}, {     95,10}, {    191, 9}, \
+    {    383,10}, {    207,12}, {     63,10}, {    255, 9}, \
+    {    511,10}, {    271, 9}, {    543,11}, {    143,10}, \
+    {    287, 9}, {    575,10}, {    303, 9}, {    607,10}, \
+    {    319, 9}, {    639,11}, {    175,12}, {     95,11}, \
+    {    191,10}, {    383,11}, {    207,10}, {    415,13}, \
+    {   8192,14}, {  16384,15}, {  32768,16}, {  65536,17}, \
+    { 131072,18}, { 262144,19}, { 524288,20}, {1048576,21}, \
+    {2097152,22}, {4194304,23}, {8388608,24} }
+#define MUL_FFT_TABLE3_SIZE 79
+#define MUL_FFT_THRESHOLD                 3520
+
+#define SQR_FFT_MODF_THRESHOLD             308  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    280, 5}, {     17, 6}, {      9, 5}, {     19, 6}, \
+    {     21, 7}, {     11, 6}, {     23, 7}, {     21, 8}, \
+    {     11, 7}, {     24, 8}, {     13, 7}, {     27, 8}, \
+    {     21, 9}, {     11, 8}, {     25, 9}, {     15, 8}, \
+    {     33, 9}, {     19, 8}, {     39, 9}, {     23, 8}, \
+    {     47, 9}, {     27,10}, {     15, 9}, {     39,10}, \
+    {     23, 9}, {     47,11}, {     15,10}, {     31, 9}, \
+    {     63,10}, {     47,11}, {     31,10}, {     71, 9}, \
+    {    143,11}, {     47,12}, {     31,11}, {     63, 9}, \
+    {    255, 8}, {    511, 9}, {    271,10}, {    143,11}, \
+    {     79,10}, {    159, 9}, {    319,10}, {    175, 9}, \
+    {    351,11}, {     95,10}, {    191, 9}, {    383,10}, \
+    {    207,12}, {     63,11}, {    127,10}, {    255, 9}, \
+    {    511, 8}, {   1023,10}, {    271, 9}, {    543,11}, \
+    {    143,10}, {    287, 9}, {    575,11}, {    159,10}, \
+    {    319, 9}, {    639,11}, {    175,10}, {    351,12}, \
+    {     95,11}, {    191,10}, {    383,11}, {    207,10}, \
+    {    415,13}, {   8192,14}, {  16384,15}, {  32768,16}, \
+    {  65536,17}, { 131072,18}, { 262144,19}, { 524288,20}, \
+    {1048576,21}, {2097152,22}, {4194304,23}, {8388608,24} }
+#define SQR_FFT_TABLE3_SIZE 80
+#define SQR_FFT_THRESHOLD                 2752
+
+#define MULLO_BASECASE_THRESHOLD             5
+#define MULLO_DC_THRESHOLD                  62
+#define MULLO_MUL_N_THRESHOLD             2995
+
+#define DC_DIV_QR_THRESHOLD                 59
+#define DC_DIVAPPR_Q_THRESHOLD             200
+#define DC_BDIV_QR_THRESHOLD                70
+#define DC_BDIV_Q_THRESHOLD                168
+
+#define INV_MULMOD_BNM1_THRESHOLD           53
+#define INV_NEWTON_THRESHOLD               170
+#define INV_APPR_THRESHOLD                 166
+
+#define BINV_NEWTON_THRESHOLD              220
+#define REDC_1_TO_REDC_N_THRESHOLD          67
+
+#define MU_DIV_QR_THRESHOLD                998
+#define MU_DIVAPPR_Q_THRESHOLD             942
+#define MUPI_DIV_QR_THRESHOLD               57
+#define MU_BDIV_QR_THRESHOLD               889
+#define MU_BDIV_Q_THRESHOLD               1078
+
+#define POWM_SEC_TABLE  4,26,216,804,1731
+
+#define MATRIX22_STRASSEN_THRESHOLD         13
+#define HGCD_THRESHOLD                     106
+#define HGCD_APPR_THRESHOLD                109
+#define HGCD_REDUCE_THRESHOLD             2205
+#define GCD_DC_THRESHOLD                   492
+#define GCDEXT_DC_THRESHOLD                327
+#define JACOBI_BASE_METHOD                   4
+
+#define GET_STR_DC_THRESHOLD                16
+#define GET_STR_PRECOMPUTE_THRESHOLD        28
+#define SET_STR_DC_THRESHOLD               537
+#define SET_STR_PRECOMPUTE_THRESHOLD      1576
+
+#define FAC_DSC_THRESHOLD                  426
+#define FAC_ODD_THRESHOLD                    0  /* always */
diff --git a/third_party/gmp/mpn/powerpc64/mode64/p6/mul_basecase.asm b/third_party/gmp/mpn/powerpc64/mode64/p6/mul_basecase.asm
new file mode 100644
index 0000000..3d32b46
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/p6/mul_basecase.asm
@@ -0,0 +1,589 @@
+dnl  PowerPC-64 mpn_mul_basecase.
+
+dnl  Copyright 1999-2001, 2003-2006, 2008, 2010 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		    cycles/limb
+C POWER3/PPC630		 ?
+C POWER4/PPC970		 ?
+C POWER5		 ?
+C POWER6		12.25
+
+C TODO
+C  * Reduce register usage.  At least 4 register less can be used.
+C  * Unroll more.  8-way unrolling would bring us to 10 c/l, 16-way unrolling
+C    would bring us to 9 c/l.
+C  * The bdz insns for b1 and b2 will never branch,
+C  * Align things better, perhaps by moving things like pointer updates from
+C    before to after loops.
+
+C INPUT PARAMETERS
+define(`rp', `r3')
+define(`up', `r4')
+define(`un', `r5')
+define(`vp', `r6')
+define(`vn', `r7')
+
+define(`v0',	   `r25')
+define(`outer_rp', `r22')
+define(`outer_up', `r23')
+
+ASM_START()
+PROLOGUE(mpn_mul_basecase)
+
+C Special code for un <= 2, for efficiency of these important cases,
+C and since it simplifies the default code.
+	cmpdi	cr0, un, 2
+	bgt	cr0, L(un_gt2)
+	cmpdi	cr6, vn, 1
+	ld	r7, 0(vp)
+	ld	r5, 0(up)
+	mulld	r8, r5, r7	C weight 0
+	mulhdu	r9, r5, r7	C weight 1
+	std	r8, 0(rp)
+	beq	cr0, L(2x)
+	std	r9, 8(rp)
+	blr
+	ALIGN(16)
+L(2x):	ld	r0, 8(up)
+	mulld	r8, r0, r7	C weight 1
+	mulhdu	r10, r0, r7	C weight 2
+	addc	r9, r9, r8
+	addze	r10, r10
+	bne	cr6, L(2x2)
+	std	r9, 8(rp)
+	std	r10, 16(rp)
+	blr
+	ALIGN(16)
+L(2x2):	ld	r6, 8(vp)
+	nop
+	mulld	r8, r5, r6	C weight 1
+	mulhdu	r11, r5, r6	C weight 2
+	mulld	r12, r0, r6	C weight 2
+	mulhdu	r0, r0, r6	C weight 3
+	addc	r9, r9, r8
+	std	r9, 8(rp)
+	adde	r11, r11, r10
+	addze	r0, r0
+	addc	r11, r11, r12
+	addze	r0, r0
+	std	r11, 16(rp)
+	std	r0, 24(rp)
+	blr
+
+L(un_gt2):
+	std	r31, -8(r1)
+	std	r30, -16(r1)
+	std	r29, -24(r1)
+	std	r28, -32(r1)
+	std	r27, -40(r1)
+	std	r26, -48(r1)
+	std	r25, -56(r1)
+	std	r24, -64(r1)
+	std	r23, -72(r1)
+	std	r22, -80(r1)
+	std	r21, -88(r1)
+	std	r20, -96(r1)
+
+	mr	outer_rp, rp
+	mr	outer_up, up
+
+	ld	v0, 0(vp)	C new v limb
+	addi	vp, vp, 8
+	ld	r26, 0(up)
+
+	rldicl.	r0, un, 0,62	C r0 = n & 3, set cr0
+	cmpdi	cr6, r0, 2
+	addi	un, un, 4	C compute count...
+	srdi	un, un, 2	C ...for ctr
+	mtctr	un		C copy inner loop count into ctr
+	beq	cr0, L(b0)
+	blt	cr6, L(b1)
+	beq	cr6, L(b2)
+
+
+	ALIGN(16)
+L(b3):
+	ld	r27, 8(up)
+	ld	r20, 16(up)
+	mulld	r0, r26, v0
+	mulhdu	r31, r26, v0
+	mulld	r24, r27, v0
+	mulhdu	r8, r27, v0
+	mulld	r9, r20, v0
+	mulhdu	r10, r20, v0
+	addc	r24, r24, r31
+	adde	r9, r9, r8
+	addze	r12, r10
+	std	r0, 0(rp)
+	std	r24, 8(rp)
+	std	r9, 16(rp)
+	addi	up, up, 16
+	addi	rp, rp, 16
+	bdz	L(end_m_3)
+
+	ALIGN(32)
+L(lo_m_3):
+	ld	r26, 8(up)
+	ld	r27, 16(up)
+	ld	r20, 24(up)
+	ld	r21, 32(up)
+	mulld	r0, r26, v0
+	mulhdu	r31, r26, v0
+	mulld	r24, r27, v0
+	mulhdu	r8, r27, v0
+	mulld	r9, r20, v0
+	mulhdu	r27, r20, v0
+	mulld	r11, r21, v0
+	mulhdu	r26, r21, v0
+	adde	r0, r0, r12
+	adde	r24, r24, r31
+	std	r0, 8(rp)
+	adde	r9, r9, r8
+	std	r24, 16(rp)
+	adde	r11, r11, r27
+	std	r9, 24(rp)
+	addi	up, up, 32
+	std	r11, 32(rp)
+	addi	rp, rp, 32
+	mr	r12, r26
+	bdnz	L(lo_m_3)
+
+	ALIGN(16)
+L(end_m_3):
+	addze	r12, r12
+	addic.	vn, vn, -1
+	std	r12, 8(rp)
+	beq	L(ret)
+
+	ALIGN(16)
+L(outer_lo_3):
+	mtctr	un		C copy inner loop count into ctr
+	addi	rp, outer_rp, 24
+	addi	up, outer_up, 16
+	addi	outer_rp, outer_rp, 8
+	ld	v0, 0(vp)	C new v limb
+	addi	vp, vp, 8
+	ld	r26, -16(up)
+	ld	r27, -8(up)
+	ld	r20, 0(up)
+	mulld	r0, r26, v0
+	mulhdu	r31, r26, v0
+	mulld	r24, r27, v0
+	mulhdu	r8, r27, v0
+	mulld	r9, r20, v0
+	mulhdu	r10, r20, v0
+	ld	r28, -16(rp)
+	ld	r29, -8(rp)
+	ld	r30, 0(rp)
+	addc	r24, r24, r31
+	adde	r9, r9, r8
+	addze	r12, r10
+	addc	r0, r0, r28
+	std	r0, -16(rp)
+	adde	r24, r24, r29
+	std	r24, -8(rp)
+	adde	r9, r9, r30
+	std	r9, 0(rp)
+	bdz	L(end_3)
+
+	ALIGN(32)		C registers dying
+L(lo_3):
+	ld	r26, 8(up)
+	ld	r27, 16(up)
+	ld	r20, 24(up)	C
+	ld	r21, 32(up)	C
+	addi	up, up, 32	C
+	addi	rp, rp, 32	C
+	mulld	r0, r26, v0	C
+	mulhdu	r10, r26, v0	C 26
+	mulld	r24, r27, v0	C
+	mulhdu	r8, r27, v0	C 27
+	mulld	r9, r20, v0	C
+	mulhdu	r27, r20, v0	C 26
+	mulld	r11, r21, v0	C
+	mulhdu	r26, r21, v0	C 27
+	ld	r28, -24(rp)	C
+	adde	r0, r0, r12	C 0 12
+	ld	r29, -16(rp)	C
+	adde	r24, r24, r10	C 24 10
+	ld	r30, -8(rp)	C
+	ld	r31, 0(rp)	C
+	adde	r9, r9, r8	C 8 9
+	adde	r11, r11, r27	C 27 11
+	addze	r12, r26	C 26
+	addc	r0, r0, r28	C 0 28
+	std	r0, -24(rp)	C 0
+	adde	r24, r24, r29	C 7 29
+	std	r24, -16(rp)	C 7
+	adde	r9, r9, r30	C 9 30
+	std	r9, -8(rp)	C 9
+	adde	r11, r11, r31	C 11 31
+	std	r11, 0(rp)	C 11
+	bdnz	L(lo_3)		C
+
+	ALIGN(16)
+L(end_3):
+	addze	r12, r12
+	addic.	vn, vn, -1
+	std	r12, 8(rp)
+	bne	L(outer_lo_3)
+	b	L(ret)
+
+
+	ALIGN(16)
+L(b1):
+	mulld	r0, r26, v0
+	mulhdu	r12, r26, v0
+	addic	r0, r0, 0
+	std	r0, 0(rp)
+	bdz	L(end_m_1)
+
+	ALIGN(16)
+L(lo_m_1):
+	ld	r26, 8(up)
+	ld	r27, 16(up)
+	ld	r20, 24(up)
+	ld	r21, 32(up)
+	mulld	r0, r26, v0
+	mulhdu	r31, r26, v0
+	mulld	r24, r27, v0
+	mulhdu	r8, r27, v0
+	mulld	r9, r20, v0
+	mulhdu	r27, r20, v0
+	mulld	r11, r21, v0
+	mulhdu	r26, r21, v0
+	adde	r0, r0, r12
+	adde	r24, r24, r31
+	std	r0, 8(rp)
+	adde	r9, r9, r8
+	std	r24, 16(rp)
+	adde	r11, r11, r27
+	std	r9, 24(rp)
+	addi	up, up, 32
+	std	r11, 32(rp)
+	addi	rp, rp, 32
+	mr	r12, r26
+	bdnz	L(lo_m_1)
+
+	ALIGN(16)
+L(end_m_1):
+	addze	r12, r12
+	addic.	vn, vn, -1
+	std	r12, 8(rp)
+	beq	L(ret)
+
+	ALIGN(16)
+L(outer_lo_1):
+	mtctr	un		C copy inner loop count into ctr
+	addi	rp, outer_rp, 8
+	mr	up, outer_up
+	addi	outer_rp, outer_rp, 8
+	ld	v0, 0(vp)	C new v limb
+	addi	vp, vp, 8
+	ld	r26, 0(up)
+	ld	r28, 0(rp)
+	mulld	r0, r26, v0
+	mulhdu	r12, r26, v0
+	addc	r0, r0, r28
+	std	r0, 0(rp)
+	bdz	L(end_1)
+
+	ALIGN(32)		C registers dying
+L(lo_1):
+	ld	r26, 8(up)
+	ld	r27, 16(up)
+	ld	r20, 24(up)	C
+	ld	r21, 32(up)	C
+	addi	up, up, 32	C
+	addi	rp, rp, 32	C
+	mulld	r0, r26, v0	C
+	mulhdu	r10, r26, v0	C 26
+	mulld	r24, r27, v0	C
+	mulhdu	r8, r27, v0	C 27
+	mulld	r9, r20, v0	C
+	mulhdu	r27, r20, v0	C 26
+	mulld	r11, r21, v0	C
+	mulhdu	r26, r21, v0	C 27
+	ld	r28, -24(rp)	C
+	adde	r0, r0, r12	C 0 12
+	ld	r29, -16(rp)	C
+	adde	r24, r24, r10	C 24 10
+	ld	r30, -8(rp)	C
+	ld	r31, 0(rp)	C
+	adde	r9, r9, r8	C 8 9
+	adde	r11, r11, r27	C 27 11
+	addze	r12, r26	C 26
+	addc	r0, r0, r28	C 0 28
+	std	r0, -24(rp)	C 0
+	adde	r24, r24, r29	C 7 29
+	std	r24, -16(rp)	C 7
+	adde	r9, r9, r30	C 9 30
+	std	r9, -8(rp)	C 9
+	adde	r11, r11, r31	C 11 31
+	std	r11, 0(rp)	C 11
+	bdnz	L(lo_1)		C
+
+	ALIGN(16)
+L(end_1):
+	addze	r12, r12
+	addic.	vn, vn, -1
+	std	r12, 8(rp)
+	bne	L(outer_lo_1)
+	b	L(ret)
+
+
+	ALIGN(16)
+L(b0):
+	addi	up, up, -8
+	addi	rp, rp, -8
+	li	r12, 0
+	addic	r12, r12, 0
+	bdz	L(end_m_0)
+
+	ALIGN(16)
+L(lo_m_0):
+	ld	r26, 8(up)
+	ld	r27, 16(up)
+	ld	r20, 24(up)
+	ld	r21, 32(up)
+	mulld	r0, r26, v0
+	mulhdu	r31, r26, v0
+	mulld	r24, r27, v0
+	mulhdu	r8, r27, v0
+	mulld	r9, r20, v0
+	mulhdu	r27, r20, v0
+	mulld	r11, r21, v0
+	mulhdu	r26, r21, v0
+	adde	r0, r0, r12
+	adde	r24, r24, r31
+	std	r0, 8(rp)
+	adde	r9, r9, r8
+	std	r24, 16(rp)
+	adde	r11, r11, r27
+	std	r9, 24(rp)
+	addi	up, up, 32
+	std	r11, 32(rp)
+	addi	rp, rp, 32
+	mr	r12, r26
+	bdnz	L(lo_m_0)
+
+	ALIGN(16)
+L(end_m_0):
+	addze	r12, r12
+	addic.	vn, vn, -1
+	std	r12, 8(rp)
+	beq	L(ret)
+
+	ALIGN(16)
+L(outer_lo_0):
+	mtctr	un		C copy inner loop count into ctr
+	addi	rp, outer_rp, 0
+	addi	up, outer_up, -8
+	addi	outer_rp, outer_rp, 8
+	ld	v0, 0(vp)	C new v limb
+	addi	vp, vp, 8
+	li	r12, 0
+	addic	r12, r12, 0
+	bdz	L(end_0)
+
+	ALIGN(32)		C registers dying
+L(lo_0):
+	ld	r26, 8(up)
+	ld	r27, 16(up)
+	ld	r20, 24(up)	C
+	ld	r21, 32(up)	C
+	addi	up, up, 32	C
+	addi	rp, rp, 32	C
+	mulld	r0, r26, v0	C
+	mulhdu	r10, r26, v0	C 26
+	mulld	r24, r27, v0	C
+	mulhdu	r8, r27, v0	C 27
+	mulld	r9, r20, v0	C
+	mulhdu	r27, r20, v0	C 26
+	mulld	r11, r21, v0	C
+	mulhdu	r26, r21, v0	C 27
+	ld	r28, -24(rp)	C
+	adde	r0, r0, r12	C 0 12
+	ld	r29, -16(rp)	C
+	adde	r24, r24, r10	C 24 10
+	ld	r30, -8(rp)	C
+	ld	r31, 0(rp)	C
+	adde	r9, r9, r8	C 8 9
+	adde	r11, r11, r27	C 27 11
+	addze	r12, r26	C 26
+	addc	r0, r0, r28	C 0 28
+	std	r0, -24(rp)	C 0
+	adde	r24, r24, r29	C 7 29
+	std	r24, -16(rp)	C 7
+	adde	r9, r9, r30	C 9 30
+	std	r9, -8(rp)	C 9
+	adde	r11, r11, r31	C 11 31
+	std	r11, 0(rp)	C 11
+	bdnz	L(lo_0)		C
+
+	ALIGN(16)
+L(end_0):
+	addze	r12, r12
+	addic.	vn, vn, -1
+	std	r12, 8(rp)
+	bne	L(outer_lo_0)
+	b	L(ret)
+
+
+	ALIGN(16)
+L(b2):	ld	r27, 8(up)
+	addi	up, up, 8
+	mulld	r0, r26, v0
+	mulhdu	r10, r26, v0
+	mulld	r24, r27, v0
+	mulhdu	r8, r27, v0
+	addc	r24, r24, r10
+	addze	r12, r8
+	std	r0, 0(rp)
+	std	r24, 8(rp)
+	addi	rp, rp, 8
+	bdz	L(end_m_2)
+
+	ALIGN(16)
+L(lo_m_2):
+	ld	r26, 8(up)
+	ld	r27, 16(up)
+	ld	r20, 24(up)
+	ld	r21, 32(up)
+	mulld	r0, r26, v0
+	mulhdu	r31, r26, v0
+	mulld	r24, r27, v0
+	mulhdu	r8, r27, v0
+	mulld	r9, r20, v0
+	mulhdu	r27, r20, v0
+	mulld	r11, r21, v0
+	mulhdu	r26, r21, v0
+	adde	r0, r0, r12
+	adde	r24, r24, r31
+	std	r0, 8(rp)
+	adde	r9, r9, r8
+	std	r24, 16(rp)
+	adde	r11, r11, r27
+	std	r9, 24(rp)
+	addi	up, up, 32
+	std	r11, 32(rp)
+	addi	rp, rp, 32
+	mr	r12, r26
+	bdnz	L(lo_m_2)
+
+	ALIGN(16)
+L(end_m_2):
+	addze	r12, r12
+	addic.	vn, vn, -1
+	std	r12, 8(rp)
+	beq	L(ret)
+
+	ALIGN(16)
+L(outer_lo_2):
+	mtctr	un		C copy inner loop count into ctr
+	addi	rp, outer_rp, 16
+	addi	up, outer_up, 8
+	addi	outer_rp, outer_rp, 8
+	ld	v0, 0(vp)	C new v limb
+	addi	vp, vp, 8
+	ld	r26, -8(up)
+	ld	r27, 0(up)
+	ld	r28, -8(rp)
+	ld	r29, 0(rp)
+	mulld	r0, r26, v0
+	mulhdu	r10, r26, v0
+	mulld	r24, r27, v0
+	mulhdu	r8, r27, v0
+	addc	r24, r24, r10
+	addze	r12, r8
+	addc	r0, r0, r28
+	std	r0, -8(rp)
+	adde	r24, r24, r29
+	std	r24, 0(rp)
+	bdz	L(end_2)
+
+	ALIGN(16)		C registers dying
+L(lo_2):
+	ld	r26, 8(up)
+	ld	r27, 16(up)
+	ld	r20, 24(up)	C
+	ld	r21, 32(up)	C
+	addi	up, up, 32	C
+	addi	rp, rp, 32	C
+	mulld	r0, r26, v0	C
+	mulhdu	r10, r26, v0	C 26
+	mulld	r24, r27, v0	C
+	mulhdu	r8, r27, v0	C 27
+	mulld	r9, r20, v0	C
+	mulhdu	r27, r20, v0	C 26
+	mulld	r11, r21, v0	C
+	mulhdu	r26, r21, v0	C 27
+	ld	r28, -24(rp)	C
+	adde	r0, r0, r12	C 0 12
+	ld	r29, -16(rp)	C
+	adde	r24, r24, r10	C 24 10
+	ld	r30, -8(rp)	C
+	ld	r31, 0(rp)	C
+	adde	r9, r9, r8	C 8 9
+	adde	r11, r11, r27	C 27 11
+	addze	r12, r26	C 26
+	addc	r0, r0, r28	C 0 28
+	std	r0, -24(rp)	C 0
+	adde	r24, r24, r29	C 7 29
+	std	r24, -16(rp)	C 7
+	adde	r9, r9, r30	C 9 30
+	std	r9, -8(rp)	C 9
+	adde	r11, r11, r31	C 11 31
+	std	r11, 0(rp)	C 11
+	bdnz	L(lo_2)		C
+
+	ALIGN(16)
+L(end_2):
+	addze	r12, r12
+	addic.	vn, vn, -1
+	std	r12, 8(rp)
+	bne	L(outer_lo_2)
+C	b	L(ret)
+
+L(ret):	ld	r31, -8(r1)
+	ld	r30, -16(r1)
+	ld	r29, -24(r1)
+	ld	r28, -32(r1)
+	ld	r27, -40(r1)
+	ld	r26, -48(r1)
+	ld	r25, -56(r1)
+	ld	r24, -64(r1)
+	ld	r23, -72(r1)
+	ld	r22, -80(r1)
+	ld	r21, -88(r1)
+	ld	r20, -96(r1)
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc64/mode64/p7/aormul_2.asm b/third_party/gmp/mpn/powerpc64/mode64/p7/aormul_2.asm
new file mode 100644
index 0000000..8731e01
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/p7/aormul_2.asm
@@ -0,0 +1,135 @@
+dnl  PowerPC-64 mpn_mul_2 and mpn_addmul_2.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                    cycles/limb    cycles/limb
+C			mul_2         addmul_2
+C POWER3/PPC630		 ?		 ?
+C POWER4/PPC970		 ?		 ?
+C POWER5		 ?		 ?
+C POWER6		 ?		 ?
+C POWER7-SMT4		 3		 3
+C POWER7-SMT2		 ?		 ?
+C POWER7-SMT1		 ?		 ?
+
+C INPUT PARAMETERS
+define(`rp', `r3')
+define(`up', `r4')
+define(`n',  `r5')
+define(`vp', `r6')
+
+define(`cy0', `r10')
+ifdef(`EXTRA_REGISTER',
+` define(`cy1', EXTRA_REGISTER)',
+` define(`cy1', `r31')')
+
+ifdef(`OPERATION_mul_2',`
+  define(`AM',		`')
+  define(`ADDX',	`addc')
+  define(`func',	`mpn_mul_2')
+')
+ifdef(`OPERATION_addmul_2',`
+  define(`AM',		`$1')
+  define(`ADDX',	`adde')
+  define(`func',	`mpn_addmul_2')
+')
+
+MULFUNC_PROLOGUE(mpn_mul_2 mpn_addmul_2)
+
+ASM_START()
+PROLOGUE(func)
+
+ifdef(`EXTRA_REGISTER',,`
+	std	r31, -8(r1)
+')
+	andi.	r12, n, 1
+	addi	r0, n, 1
+	srdi	r0, r0, 1
+	mtctr	r0
+	ld	r11, 0(vp)		C v0
+	li	cy0, 0
+	ld	r12, 8(vp)		C v1
+	li	cy1, 0
+	ld	r5, 0(up)
+	beq	L(lo0)
+	addi	up, up, -8
+	addi	rp, rp, -8
+	b	L(lo1)
+
+	ALIGN(32)
+L(top):
+AM(`	ld	r0, -8(rp)')
+	ld	r5, 0(up)
+AM(`	addc	r6, r6, r0')
+	ADDX	r7, r7, r8
+	addze	r9, r9
+	addc	r6, r6, cy0
+	adde	cy0, r7, cy1
+	std	r6, -8(rp)
+	addze	cy1, r9
+L(lo0):	mulld	r6, r11, r5		C v0 * u[i]  weight 0
+	mulhdu	r7, r11, r5		C v0 * u[i]  weight 1
+	mulld	r8, r12, r5		C v1 * u[i]  weight 1
+	mulhdu	r9, r12, r5		C v1 * u[i]  weight 2
+AM(`	ld	r0, 0(rp)')
+	ld	r5, 8(up)
+AM(`	addc	r6, r6, r0')
+	ADDX	r7, r7, r8
+	addze	r9, r9
+	addc	r6, r6, cy0
+	adde	cy0, r7, cy1
+	std	r6, 0(rp)
+	addze	cy1, r9
+L(lo1):	mulld	r6, r11, r5		C v0 * u[i]  weight 0
+	mulhdu	r7, r11, r5		C v0 * u[i]  weight 1
+	addi	up, up, 16
+	addi	rp, rp, 16
+	mulld	r8, r12, r5		C v1 * u[i]  weight 1
+	mulhdu	r9, r12, r5		C v1 * u[i]  weight 2
+	bdnz	L(top)
+
+L(end):
+AM(`	ld	r0, -8(rp)')
+AM(`	addc	r6, r6, r0')
+	ADDX	r7, r7, r8
+	addze	r9, r9
+	addc	r6, r6, cy0
+	std	r6, -8(rp)
+	adde	cy0, r7, cy1
+	addze	cy1, r9
+	std	cy0, 0(rp)
+	mr	r3, cy1
+
+ifdef(`EXTRA_REGISTER',,`
+	ld	r31, -8(r1)
+')
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc64/mode64/p7/aors_n.asm b/third_party/gmp/mpn/powerpc64/mode64/p7/aors_n.asm
new file mode 100644
index 0000000..857c701
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/p7/aors_n.asm
@@ -0,0 +1,128 @@
+dnl  PowerPC-64 mpn_add_n, mpn_sub_n optimised for POWER7.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		   cycles/limb
+C POWER3/PPC630		 ?
+C POWER4/PPC970		 ?
+C POWER5		 ?
+C POWER6		 ?
+C POWER7		 2.18
+
+C This is a tad bit slower than the cnd_aors_n.asm code, which is of course an
+C anomaly.
+
+ifdef(`OPERATION_add_n',`
+  define(ADDSUBC,	adde)
+  define(ADDSUB,	addc)
+  define(func,		mpn_add_n)
+  define(func_nc,	mpn_add_nc)
+  define(GENRVAL,	`addi	r3, r3, 1')
+  define(SETCBR,	`addic	r0, $1, -1')
+  define(CLRCB,		`addic	r0, r0, 0')
+')
+ifdef(`OPERATION_sub_n',`
+  define(ADDSUBC,	subfe)
+  define(ADDSUB,	subfc)
+  define(func,		mpn_sub_n)
+  define(func_nc,	mpn_sub_nc)
+  define(GENRVAL,	`neg	r3, r3')
+  define(SETCBR,	`subfic	r0, $1, 0')
+  define(CLRCB,		`addic	r0, r1, -1')
+')
+
+MULFUNC_PROLOGUE(mpn_add_n mpn_add_nc mpn_sub_n mpn_sub_nc)
+
+C INPUT PARAMETERS
+define(`rp',	`r3')
+define(`up',	`r4')
+define(`vp',	`r5')
+define(`n',	`r6')
+
+ASM_START()
+PROLOGUE(func_nc)
+	SETCBR(r7)
+	b	L(ent)
+EPILOGUE()
+
+PROLOGUE(func)
+	CLRCB
+L(ent):
+	andi.	r7, n, 1
+	beq	L(bx0)
+
+L(bx1):	ld	r7, 0(up)
+	ld	r9, 0(vp)
+	ADDSUBC	r11, r9, r7
+	std	r11, 0(rp)
+	cmpldi	cr6, n, 1
+	beq	cr6, L(end)
+	addi	up, up, 8
+	addi	vp, vp, 8
+	addi	rp, rp, 8
+
+L(bx0):	addi	r0, n, 2	C compute branch...
+	srdi	r0, r0, 2	C ...count
+	mtctr	r0
+
+	andi.	r7, n, 2
+	bne	L(mid)
+
+	addi	up, up, 16
+	addi	vp, vp, 16
+	addi	rp, rp, 16
+
+	ALIGN(32)
+L(top):	ld	r6, -16(up)
+	ld	r7, -8(up)
+	ld	r8, -16(vp)
+	ld	r9, -8(vp)
+	ADDSUBC	r10, r8, r6
+	ADDSUBC	r11, r9, r7
+	std	r10, -16(rp)
+	std	r11, -8(rp)
+L(mid):	ld	r6, 0(up)
+	ld	r7, 8(up)
+	ld	r8, 0(vp)
+	ld	r9, 8(vp)
+	ADDSUBC	r10, r8, r6
+	ADDSUBC	r11, r9, r7
+	std	r10, 0(rp)
+	std	r11, 8(rp)
+	addi	up, up, 32
+	addi	vp, vp, 32
+	addi	rp, rp, 32
+	bdnz	L(top)
+
+L(end):	subfe	r3, r0, r0	C -cy
+	GENRVAL
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc64/mode64/p7/aorsorrlsh1_n.asm b/third_party/gmp/mpn/powerpc64/mode64/p7/aorsorrlsh1_n.asm
new file mode 100644
index 0000000..ddf5fd8
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/p7/aorsorrlsh1_n.asm
@@ -0,0 +1,43 @@
+dnl  PowerPC-64 mpn_addlsh1_n, mpn_sublsh1_n, mpn_rsblsh1_n.
+
+dnl  Copyright 2003, 2005, 2009, 2010, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+define(LSH,		1)
+define(RSH,		63)
+
+ifdef(`OPERATION_addlsh1_n',`define(`DO_add')')
+ifdef(`OPERATION_sublsh1_n',`define(`DO_sub')')
+ifdef(`OPERATION_rsblsh1_n',`define(`DO_rsb')')
+
+MULFUNC_PROLOGUE(mpn_addlsh1_n mpn_sublsh1_n mpn_rsblsh1_n)
+
+include_mpn(`powerpc64/mode64/p7/aorsorrlshC_n.asm')
diff --git a/third_party/gmp/mpn/powerpc64/mode64/p7/aorsorrlsh2_n.asm b/third_party/gmp/mpn/powerpc64/mode64/p7/aorsorrlsh2_n.asm
new file mode 100644
index 0000000..3f9d88d
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/p7/aorsorrlsh2_n.asm
@@ -0,0 +1,43 @@
+dnl  PowerPC-64 mpn_addlsh2_n, mpn_sublsh2_n, mpn_rsblsh2_n.
+
+dnl  Copyright 2003, 2005, 2009, 2010, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+define(LSH,		2)
+define(RSH,		62)
+
+ifdef(`OPERATION_addlsh2_n',`define(`DO_add')')
+ifdef(`OPERATION_sublsh2_n',`define(`DO_sub')')
+ifdef(`OPERATION_rsblsh2_n',`define(`DO_rsb')')
+
+MULFUNC_PROLOGUE(mpn_addlsh2_n mpn_sublsh2_n mpn_rsblsh2_n)
+
+include_mpn(`powerpc64/mode64/p7/aorsorrlshC_n.asm')
diff --git a/third_party/gmp/mpn/powerpc64/mode64/p7/aorsorrlshC_n.asm b/third_party/gmp/mpn/powerpc64/mode64/p7/aorsorrlshC_n.asm
new file mode 100644
index 0000000..5251202
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/p7/aorsorrlshC_n.asm
@@ -0,0 +1,129 @@
+dnl  PowerPC-64 mpn_addlshC_n, mpn_sublshC_n, mpn_rsblshC_n.
+
+dnl  Copyright 2003, 2005, 2009, 2010, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+C                  cycles/limb
+C POWER3/PPC630          ?
+C POWER4/PPC970          ?
+C POWER5                 ?
+C POWER6                 ?
+C POWER7                 2.5
+
+C INPUT PARAMETERS
+define(`rp', `r3')
+define(`up', `r4')
+define(`vp', `r5')
+define(`n',  `r6')
+
+ifdef(`DO_add', `
+  define(`ADDSUBC',	`addc	$1, $2, $3')
+  define(`ADDSUBE',	`adde	$1, $2, $3')
+  define(INITCY,	`addic	$1, r1, 0')
+  define(RETVAL,	`addze	r3, $1')
+  define(`func',	mpn_addlsh`'LSH`'_n)')
+ifdef(`DO_sub', `
+  define(`ADDSUBC',	`subfc	$1, $2, $3')
+  define(`ADDSUBE',	`subfe	$1, $2, $3')
+  define(INITCY,	`addic	$1, r1, -1')
+  define(RETVAL,	`subfze	r3, $1
+			neg	r3, r3')
+  define(`func',	mpn_sublsh`'LSH`'_n)')
+ifdef(`DO_rsb', `
+  define(`ADDSUBC',	`subfc	$1, $3, $2')
+  define(`ADDSUBE',	`subfe	$1, $3, $2')
+  define(INITCY,	`addic	$1, r1, -1')
+  define(RETVAL,	`addme	r3, $1')
+  define(`func',	mpn_rsblsh`'LSH`'_n)')
+
+define(`s0', `r0')  define(`s1', `r9')
+define(`u0', `r6')  define(`u1', `r7')
+define(`v0', `r10') define(`v1', `r11')
+
+
+ASM_START()
+PROLOGUE(func)
+	rldic	r7, n, 3, 59
+	add	up, up, r7
+	add	vp, vp, r7
+	add	rp, rp, r7
+
+ifdef(`DO_add', `
+	addic	r0, n, 3	C set cy flag as side effect
+',`
+	subfc	r0, r0, r0	C set cy flag
+	addi	r0, n, 3
+')
+	srdi	r0, r0, 2
+	mtctr	r0
+
+	andi.	r0, n, 1
+	beq	L(bx0)
+
+L(bx1):	andi.	r0, n, 2
+	li	s0, 0
+	bne	L(lo3)
+	b	L(lo1)
+
+L(bx0):	andi.	r0, n, 2
+	li	s1, 0
+	bne	L(lo2)
+
+	ALIGN(32)
+L(top):	addi	rp, rp, 32
+	ld	v0, 0(vp)
+	addi	vp, vp, 32
+	rldimi	s1, v0, LSH, 0
+	ld	u0, 0(up)
+	addi	up, up, 32
+	srdi	s0, v0, RSH
+	ADDSUBE(s1, s1, u0)
+	std	s1, -32(rp)
+L(lo3):	ld	v1, -24(vp)
+	rldimi	s0, v1, LSH, 0
+	ld	u1, -24(up)
+	srdi	s1, v1, RSH
+	ADDSUBE(s0, s0, u1)
+	std	s0, -24(rp)
+L(lo2):	ld	v0, -16(vp)
+	rldimi	s1, v0, LSH, 0
+	ld	u0, -16(up)
+	srdi	s0, v0, RSH
+	ADDSUBE(s1, s1, u0)
+	std	s1, -16(rp)
+L(lo1):	ld	v1, -8(vp)
+	rldimi	s0, v1, LSH, 0
+	ld	u1, -8(up)
+	srdi	s1, v1, RSH
+	ADDSUBE(s0, s0, u1)
+	std	s0, -8(rp)
+	bdnz	L(top)		C decrement CTR and loop back
+
+	RETVAL(	s1)
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc64/mode64/p7/gcd_11.asm b/third_party/gmp/mpn/powerpc64/mode64/p7/gcd_11.asm
new file mode 100644
index 0000000..f04e896
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/p7/gcd_11.asm
@@ -0,0 +1,67 @@
+dnl  PowerPC-64 mpn_gcd_11.
+
+dnl  Copyright 2000-2002, 2005, 2009, 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		    cycles/bit (approx)
+C POWER3/PPC630		 -
+C POWER4/PPC970		 -
+C POWER5		 -
+C POWER6		 -
+C POWER7		 7.6    obsolete
+C POWER8		 ?
+C POWER9		 ?
+C Numbers measured with: speed -CD -s16-64 -t48 mpn_gcd_1
+
+C INPUT PARAMETERS
+define(`u0',    `r3')
+define(`v0',    `r4')
+
+define(`cnt',  `r9')dnl
+
+ASM_START()
+PROLOGUE(mpn_gcd_11)
+	li	r12, 63
+	b	L(odd)
+
+	ALIGN(16)
+L(top):	and	r8, r11, r10		C isolate lsb
+	cntlzd	cnt, r8
+	isel	v0, u0, v0, 29		C v = min(u,v)
+	isel	u0, r10, r11, 29	C u = |u - v|
+	subf	cnt, cnt, r12		C cnt = 63-cnt
+	srd	u0, u0, cnt
+L(odd):	cmpld	cr7, v0, u0
+	subf	r10, u0, v0		C r10 = v - u
+	subf	r11, v0, u0		C r11 = u - v
+	bne	cr7, L(top)
+
+L(end):	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc64/mode64/p7/gcd_22.asm b/third_party/gmp/mpn/powerpc64/mode64/p7/gcd_22.asm
new file mode 100644
index 0000000..ade30e4
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/p7/gcd_22.asm
@@ -0,0 +1,146 @@
+dnl  PowerPC-64 mpn_gcd_22 optimised for POWER7 and POWER8.
+
+dnl  Copyright 2000-2002, 2005, 2009, 2011-2013, 2019 Free Software Foundation,
+dnl  Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		    cycles/bit (approx)
+C POWER3/PPC630		 -
+C POWER4/PPC970		 -
+C POWER5		 -
+C POWER6		 -
+C POWER7		12.3
+C POWER8		13.4
+C POWER9		10.6
+
+C We define SLOW if this target uses a slow struct return mechanism, with
+C r3 as an implicit parameter for the struct pointer.
+undefine(`SLOW')dnl
+ifdef(`AIX',`define(`SLOW',`due to AIX')',`
+  ifdef(`DARWIN',,`
+    ifdef(`ELFv2_ABI',,`define(`SLOW',`due to ELFv1')')dnl
+  ')
+')
+
+ifdef(`SLOW',`
+define(`IFSLOW', `$1')
+define(`u1',    `r4')
+define(`u0',    `r5')
+define(`v1',    `r6')
+define(`v0',    `r7')
+',`
+define(`IFSLOW', `')
+define(`u1',    `r3')
+define(`u0',    `r4')
+define(`v1',    `r5')
+define(`v0',    `r6')
+')
+
+define(`tmp',   `r0')
+define(`t0',    `r8')
+define(`t1',    `r9')
+define(`s0',    `r10')
+define(`s1',    `r11')
+define(`cnt',   `r12')
+
+ASM_START()
+PROLOGUE(mpn_gcd_22)
+L(top):	subfc.	t0, v0, u0		C 0 12
+	beq	cr0, L(lowz)
+	subfe	t1, v1, u1		C 2 14
+	subfe.	tmp, tmp, tmp		C 4	set cr0 from the carry bit
+	subfc	s0, u0, v0		C 0
+	subfe	s1, u1, v1		C 2
+
+L(bck):	and	tmp, s0, t0		C 2
+	cntlzd	cnt, tmp		C 4
+	addi	tmp, cnt, 1		C 6
+	subfic	cnt, cnt, 63		C 6
+
+	isel	v0, v0, u0, 2		C 6	use condition set by subfe
+	isel	v1, v1, u1, 2		C 6
+	isel	u0, t0, s0, 2		C 6
+	isel	u1, t1, s1, 2		C 6
+
+	srd	u0, u0, cnt		C 8
+	sld	tmp, u1, tmp		C 8
+	srd	u1, u1, cnt		C 8
+	or	u0, u0, tmp		C 10
+
+	or.	r0, u1, v1		C 10
+	bne	L(top)
+
+
+	li	r0, 63
+	b	L(odd)
+	ALIGN(16)
+L(top1):isel	v0, u0, v0, 29		C v = min(u,v)
+	isel	u0, r10, r11, 29	C u = |u - v|
+	subf	cnt, cnt, r0		C cnt = 63-cnt
+	srd	u0, u0, cnt
+L(odd):	subf	r10, u0, v0		C r10 = v - u
+	subf	r11, v0, u0		C r11 = u - v
+	cmpld	cr7, v0, u0
+	and	r8, r11, r10		C isolate lsb
+	cntlzd	cnt, r8
+	bne	cr7, L(top1)
+
+ifdef(`SLOW',`
+	std	v0, 0(r3)
+	std	r10, 8(r3)		C zero
+',`
+	mr	r3, v0
+	li	r4, 0
+')
+	blr
+
+
+L(lowz):C We come here when v0 - u0 = 0
+	C 1. If v1 - u1 = 0, then gcd is u = v.
+	C 2. Else compute gcd_21({v1,v0}, |u1-v1|)
+	subfc.	t0, v1, u1		C 2 8
+	beq	L(end)
+	li	t1, 0
+	subfe.	tmp, tmp, tmp		C 4	set cr0 from the carry bit
+	subf	s0, u1, v1		C 2
+	li	s1, 0
+	b	L(bck)
+
+L(end):
+ifdef(`SLOW',`
+	std	v0, 0(r3)
+	std	v1, 8(r3)
+	blr
+',`
+	mr	r3, v0
+	mr	r4, v1
+	blr
+')
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc64/mode64/p7/gmp-mparam.h b/third_party/gmp/mpn/powerpc64/mode64/p7/gmp-mparam.h
new file mode 100644
index 0000000..5fa62cf
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/p7/gmp-mparam.h
@@ -0,0 +1,174 @@
+/* POWER7 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+/* 3720 MHz POWER7/SMT4 */
+/* FFT tuning limit = 0.5 M */
+/* Generated by tuneup.c, 2019-10-02, gcc 4.8 */
+
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          6
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          4
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD         8
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        16
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     13
+#define USE_PREINV_DIVREM_1                  0
+#define DIV_QR_1N_PI1_METHOD                 1  /* 3.47% faster than 2 */
+#define DIV_QR_1_NORM_THRESHOLD              1
+#define DIV_QR_1_UNNORM_THRESHOLD            1
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           27
+
+#define DIV_1_VS_MUL_1_PERCENT             341
+
+#define MUL_TOOM22_THRESHOLD                22
+#define MUL_TOOM33_THRESHOLD                71
+#define MUL_TOOM44_THRESHOLD               196
+#define MUL_TOOM6H_THRESHOLD               298
+#define MUL_TOOM8H_THRESHOLD               406
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      81
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     140
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     132
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     139
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     120
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 32
+#define SQR_TOOM3_THRESHOLD                105
+#define SQR_TOOM4_THRESHOLD                190
+#define SQR_TOOM6_THRESHOLD                318
+#define SQR_TOOM8_THRESHOLD                547
+
+#define MULMID_TOOM42_THRESHOLD             56
+
+#define MULMOD_BNM1_THRESHOLD               18
+#define SQRMOD_BNM1_THRESHOLD               20
+
+#define MUL_FFT_MODF_THRESHOLD             436  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    436, 5}, {     21, 6}, {     21, 7}, {     11, 6}, \
+    {     23, 7}, {     12, 6}, {     25, 7}, {     21, 8}, \
+    {     11, 7}, {     25, 8}, {     13, 7}, {     28, 8}, \
+    {     15, 7}, {     33, 8}, {     17, 7}, {     35, 8}, \
+    {     19, 7}, {     39, 8}, {     21, 9}, {     11, 8}, \
+    {     29, 9}, {     15, 8}, {     35, 9}, {     19, 8}, \
+    {     41, 9}, {     23, 8}, {     49, 9}, {     27,10}, \
+    {     15, 9}, {     31, 8}, {     63, 9}, {     43,10}, \
+    {     23, 9}, {     55,11}, {     15,10}, {     31, 9}, \
+    {     67,10}, {     39, 9}, {     79,10}, {     47, 9}, \
+    {     95,10}, {     55,11}, {     31,10}, {     63, 9}, \
+    {    127,10}, {     79,11}, {     47,10}, {    103,12}, \
+    {     31,11}, {     63,10}, {    135,11}, {     79,10}, \
+    {    159,11}, {     95,10}, {    191, 9}, {    383,11}, \
+    {    111,12}, {     63,11}, {    127,10}, {    255, 9}, \
+    {    511,11}, {    143,10}, {    287, 9}, {    575,11}, \
+    {    159,10}, {    319,12}, {     95,11}, {    191,10}, \
+    {    383, 9}, {    767,11}, {    207,10}, {    415,13}, \
+    {   8192,14}, {  16384,15}, {  32768,16}, {  65536,17}, \
+    { 131072,18}, { 262144,19}, { 524288,20}, {1048576,21}, \
+    {2097152,22}, {4194304,23}, {8388608,24} }
+#define MUL_FFT_TABLE3_SIZE 83
+#define MUL_FFT_THRESHOLD                 4736
+
+#define SQR_FFT_MODF_THRESHOLD             368  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    368, 5}, {     19, 6}, {     10, 5}, {     21, 6}, \
+    {     21, 7}, {     11, 6}, {     23, 7}, {     12, 6}, \
+    {     25, 7}, {     13, 6}, {     27, 7}, {     25, 8}, \
+    {     13, 7}, {     28, 8}, {     15, 7}, {     32, 8}, \
+    {     17, 7}, {     35, 8}, {     19, 7}, {     39, 8}, \
+    {     21, 9}, {     11, 8}, {     29, 9}, {     15, 8}, \
+    {     35, 9}, {     19, 8}, {     41, 9}, {     23, 8}, \
+    {     47, 9}, {     27,10}, {     15, 9}, {     31, 8}, \
+    {     63, 9}, {     39,10}, {     23, 9}, {     51,11}, \
+    {     15,10}, {     31, 9}, {     67,10}, {     39, 9}, \
+    {     79,10}, {     47, 9}, {     95,10}, {     55,11}, \
+    {     31,10}, {     79,11}, {     47,10}, {     95,12}, \
+    {     31,11}, {     63,10}, {    135,11}, {     79,10}, \
+    {    159, 9}, {    319,11}, {     95,10}, {    191, 9}, \
+    {    383,11}, {    111,12}, {     63,11}, {    127,10}, \
+    {    255, 9}, {    511,11}, {    143,10}, {    287, 9}, \
+    {    575,10}, {    303,11}, {    159,10}, {    319, 9}, \
+    {    639,12}, {     95,11}, {    191,10}, {    383, 9}, \
+    {    767,13}, {   8192,14}, {  16384,15}, {  32768,16}, \
+    {  65536,17}, { 131072,18}, { 262144,19}, { 524288,20}, \
+    {1048576,21}, {2097152,22}, {4194304,23}, {8388608,24} }
+#define SQR_FFT_TABLE3_SIZE 84
+#define SQR_FFT_THRESHOLD                 3264
+
+#define MULLO_BASECASE_THRESHOLD             3
+#define MULLO_DC_THRESHOLD                  35
+#define MULLO_MUL_N_THRESHOLD             9449
+#define SQRLO_BASECASE_THRESHOLD             3
+#define SQRLO_DC_THRESHOLD                 119
+#define SQRLO_SQR_THRESHOLD               6440
+
+#define DC_DIV_QR_THRESHOLD                 33
+#define DC_DIVAPPR_Q_THRESHOLD             124
+#define DC_BDIV_QR_THRESHOLD                62
+#define DC_BDIV_Q_THRESHOLD                144
+
+#define INV_MULMOD_BNM1_THRESHOLD           67
+#define INV_NEWTON_THRESHOLD               123
+#define INV_APPR_THRESHOLD                 123
+
+#define BINV_NEWTON_THRESHOLD              284
+#define REDC_1_TO_REDC_2_THRESHOLD          18
+#define REDC_2_TO_REDC_N_THRESHOLD         109
+
+#define MU_DIV_QR_THRESHOLD               1387
+#define MU_DIVAPPR_Q_THRESHOLD            1334
+#define MUPI_DIV_QR_THRESHOLD               50
+#define MU_BDIV_QR_THRESHOLD              1308
+#define MU_BDIV_Q_THRESHOLD               1499
+
+#define POWM_SEC_TABLE  1,23,121,579,642
+
+#define GET_STR_DC_THRESHOLD                11
+#define GET_STR_PRECOMPUTE_THRESHOLD        18
+#define SET_STR_DC_THRESHOLD              1562
+#define SET_STR_PRECOMPUTE_THRESHOLD      3100
+
+#define FAC_DSC_THRESHOLD                  774
+#define FAC_ODD_THRESHOLD                   25
+
+#define MATRIX22_STRASSEN_THRESHOLD         18
+#define HGCD2_DIV1_METHOD                    5  /* 3.27% faster than 3 */
+#define HGCD_THRESHOLD                     118
+#define HGCD_APPR_THRESHOLD                150
+#define HGCD_REDUCE_THRESHOLD             3014
+#define GCD_DC_THRESHOLD                   386
+#define GCDEXT_DC_THRESHOLD                365
+#define JACOBI_BASE_METHOD                   4  /* 27.64% faster than 1 */
diff --git a/third_party/gmp/mpn/powerpc64/mode64/p8/gmp-mparam.h b/third_party/gmp/mpn/powerpc64/mode64/p8/gmp-mparam.h
new file mode 100644
index 0000000..ed4db28
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/p8/gmp-mparam.h
@@ -0,0 +1,170 @@
+/* POWER8 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+/* 4150 MHz POWER8/SMT4 */
+/* FFT tuning limit = 0.5 M */
+/* Generated by tuneup.c, 2019-09-24, gcc 7.2 */
+
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          7
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          6
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        11
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        22
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     10
+#define USE_PREINV_DIVREM_1                  0
+#define DIV_QR_1N_PI1_METHOD                 2  /* 16.97% faster than 1 */
+#define DIV_QR_1_NORM_THRESHOLD              2
+#define DIV_QR_1_UNNORM_THRESHOLD            1
+#define DIV_QR_2_PI2_THRESHOLD               9
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           34
+
+#define DIV_1_VS_MUL_1_PERCENT             276
+
+#define MUL_TOOM22_THRESHOLD                18
+#define MUL_TOOM33_THRESHOLD                73
+#define MUL_TOOM44_THRESHOLD               195
+#define MUL_TOOM6H_THRESHOLD               278
+#define MUL_TOOM8H_THRESHOLD               406
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      73
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     131
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     121
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     138
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     106
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 32
+#define SQR_TOOM3_THRESHOLD                 97
+#define SQR_TOOM4_THRESHOLD                178
+#define SQR_TOOM6_THRESHOLD                303
+#define SQR_TOOM8_THRESHOLD                454
+
+#define MULMID_TOOM42_THRESHOLD             42
+
+#define MULMOD_BNM1_THRESHOLD               15
+#define SQRMOD_BNM1_THRESHOLD               19
+
+#define MUL_FFT_MODF_THRESHOLD             404  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    404, 5}, {     19, 6}, {     10, 5}, {     21, 6}, \
+    {     21, 7}, {     11, 6}, {     23, 7}, {     12, 6}, \
+    {     25, 7}, {     21, 8}, {     11, 7}, {     25, 8}, \
+    {     13, 7}, {     27, 8}, {     15, 7}, {     31, 8}, \
+    {     17, 7}, {     35, 8}, {     19, 7}, {     39, 8}, \
+    {     21, 9}, {     11, 8}, {     27, 9}, {     15, 8}, \
+    {     35, 9}, {     19, 8}, {     41, 9}, {     23, 8}, \
+    {     47, 9}, {     27,10}, {     15, 9}, {     39,10}, \
+    {     23, 9}, {     51,11}, {     15,10}, {     31, 9}, \
+    {     63,10}, {     39, 9}, {     79,10}, {     47, 9}, \
+    {     95,11}, {     31,10}, {     63, 9}, {    131,10}, \
+    {     79,11}, {     47,10}, {     95,12}, {     31,11}, \
+    {     63,10}, {    127, 9}, {    255,10}, {    135,11}, \
+    {     79,10}, {    159,11}, {     95, 8}, {    767, 7}, \
+    {   1599,11}, {    111,12}, {     63,11}, {    127,10}, \
+    {    255, 9}, {    511,11}, {    143,10}, {    287, 9}, \
+    {    575,11}, {    159,12}, {     95,11}, {    191,10}, \
+    {    383,13}, {   8192,14}, {  16384,15}, {  32768,16}, \
+    {  65536,17}, { 131072,18}, { 262144,19}, { 524288,20}, \
+    {1048576,21}, {2097152,22}, {4194304,23}, {8388608,24} }
+#define MUL_FFT_TABLE3_SIZE 80
+#define MUL_FFT_THRESHOLD                 4736
+
+#define SQR_FFT_MODF_THRESHOLD             340  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    340, 5}, {     19, 6}, {     10, 5}, {     21, 6}, \
+    {     21, 7}, {     11, 6}, {     23, 7}, {     21, 8}, \
+    {     11, 7}, {     25, 8}, {     13, 7}, {     27, 8}, \
+    {     15, 7}, {     31, 8}, {     21, 9}, {     11, 8}, \
+    {     27, 9}, {     15, 8}, {     33, 9}, {     19, 8}, \
+    {     41, 9}, {     23, 8}, {     47, 9}, {     27,10}, \
+    {     15, 9}, {     39,10}, {     23, 9}, {     47,11}, \
+    {     15,10}, {     31, 9}, {     67,10}, {     39, 9}, \
+    {     79,10}, {     47,11}, {     31,10}, {     79,11}, \
+    {     47,10}, {     95,12}, {     31,11}, {     63,10}, \
+    {    127, 9}, {    255,11}, {     79, 9}, {    319,11}, \
+    {     95,10}, {    191,12}, {     63,11}, {    127,10}, \
+    {    255, 9}, {    511,10}, {    271,11}, {    143,10}, \
+    {    287, 9}, {    575,10}, {    303, 9}, {    607,10}, \
+    {    319,12}, {     95,11}, {    191,10}, {    383,13}, \
+    {   8192,14}, {  16384,15}, {  32768,16}, {  65536,17}, \
+    { 131072,18}, { 262144,19}, { 524288,20}, {1048576,21}, \
+    {2097152,22}, {4194304,23}, {8388608,24} }
+#define SQR_FFT_TABLE3_SIZE 71
+#define SQR_FFT_THRESHOLD                 3264
+
+#define MULLO_BASECASE_THRESHOLD             3
+#define MULLO_DC_THRESHOLD                  33
+#define MULLO_MUL_N_THRESHOLD             9174
+#define SQRLO_BASECASE_THRESHOLD             0  /* always */
+#define SQRLO_DC_THRESHOLD                 114
+#define SQRLO_SQR_THRESHOLD               6461
+
+#define DC_DIV_QR_THRESHOLD                 38
+#define DC_DIVAPPR_Q_THRESHOLD             158
+#define DC_BDIV_QR_THRESHOLD                48
+#define DC_BDIV_Q_THRESHOLD                112
+
+#define INV_MULMOD_BNM1_THRESHOLD           74
+#define INV_NEWTON_THRESHOLD               132
+#define INV_APPR_THRESHOLD                 131
+
+#define BINV_NEWTON_THRESHOLD              278
+#define REDC_1_TO_REDC_2_THRESHOLD          56
+#define REDC_2_TO_REDC_N_THRESHOLD           0  /* always */
+
+#define MU_DIV_QR_THRESHOLD               1142
+#define MU_DIVAPPR_Q_THRESHOLD            1142
+#define MUPI_DIV_QR_THRESHOLD               46
+#define MU_BDIV_QR_THRESHOLD              1142
+#define MU_BDIV_Q_THRESHOLD               1470
+
+#define POWM_SEC_TABLE  3,19,117,672,1867
+
+#define GET_STR_DC_THRESHOLD                11
+#define GET_STR_PRECOMPUTE_THRESHOLD        18
+#define SET_STR_DC_THRESHOLD               608
+#define SET_STR_PRECOMPUTE_THRESHOLD      2405
+
+#define FAC_DSC_THRESHOLD                  164
+#define FAC_ODD_THRESHOLD                    0  /* always */
+
+#define MATRIX22_STRASSEN_THRESHOLD         14
+#define HGCD2_DIV1_METHOD                    1  /* 6.88% faster than 3 */
+#define HGCD_THRESHOLD                     114
+#define HGCD_APPR_THRESHOLD                118
+#define HGCD_REDUCE_THRESHOLD             2205
+#define GCD_DC_THRESHOLD                   440
+#define GCDEXT_DC_THRESHOLD                345
+#define JACOBI_BASE_METHOD                   1  /* 0.74% faster than 4 */
diff --git a/third_party/gmp/mpn/powerpc64/mode64/p8/invert_limb.asm b/third_party/gmp/mpn/powerpc64/mode64/p8/invert_limb.asm
new file mode 100644
index 0000000..53ea0e0
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/p8/invert_limb.asm
@@ -0,0 +1,53 @@
+dnl  PowerPC-64 mpn_invert_limb -- Invert a normalized limb.
+
+dnl  Copyright 2015, 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                  cycles/limb (approximate)
+C POWER3/PPC630         -
+C POWER4/PPC970         -
+C POWER5                -
+C POWER6                -
+C POWER7                ?
+C POWER8               32
+
+C This runs on POWER7 and later, but is faster only on later CPUs.
+C We might want to inline this, considering its small footprint.
+
+ASM_START()
+PROLOGUE(mpn_invert_limb)
+	sldi.	r4, r3, 1
+	neg	r5, r3
+	divdeu(	r3, r5, r3)
+	beq-	L(1)
+	blr
+L(1):	li	r3, -1
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc64/mode64/p9/add_n_sub_n.asm b/third_party/gmp/mpn/powerpc64/mode64/p9/add_n_sub_n.asm
new file mode 100644
index 0000000..2426a00
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/p9/add_n_sub_n.asm
@@ -0,0 +1,112 @@
+dnl  PowerPC-64 mpn_add_n_sub_n optimised for POWER9.
+
+dnl  Copyright 2018 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		   cycles/limb
+C POWER3/PPC630		 -
+C POWER4/PPC970		 -
+C POWER5		 -
+C POWER6		 -
+C POWER7		 -
+C POWER8		 -
+C POWER9		 2.25
+
+
+C INPUT PARAMETERS
+define(`arp',	`r3')
+define(`srp',	`r4')
+define(`up',	`r5')
+define(`vp',	`r6')
+define(`n',	`r7')
+
+ASM_START()
+PROLOGUE(mpn_add_n_sub_n)
+	cmpdi	cr7, n, 2
+	subfo	r0, r0, r0		C clear OV
+	rldicl.	r9, n, 0, 63		C n & 1
+	beq	cr0, L(bx0)
+
+L(bx1):	ld	r10, 0(up)
+	ld	r11, 0(vp)
+	ble	cr7, L(1)
+	srdi	r7, r7, 1
+	mtctr	r7
+	ld	r8, 8(up)
+	ld	r9, 8(vp)
+	addex(	r0, r10, r11, 0)
+	subfc	r12, r11, r10
+	addi	up, up, -8
+	addi	vp, vp, -8
+	b	L(lo1)
+
+L(bx0):	ld	r8, 0(up)
+	ld	r9, 0(vp)
+	ld	r10, 8(up)
+	ld	r11, 8(vp)
+	addex(	r0, r8, r9, 0)
+	subfc	r12, r9, r8
+	addi	arp, arp, 8
+	addi	srp, srp, 8
+	ble	cr7, L(end)
+	addi	r7, r7, -1
+	srdi	r7, r7, 1
+	mtctr	r7
+
+L(top):	ld	r8, 16(up)
+	ld	r9, 16(vp)
+	std	r0, -8(arp)
+	std	r12, -8(srp)
+	addex(	r0, r10, r11, 0)
+	subfe	r12, r11, r10
+L(lo1):	ld	r10, 24(up)
+	ld	r11, 24(vp)
+	std	r0, 0(arp)
+	std	r12, 0(srp)
+	addex(	r0, r8, r9, 0)
+	subfe	r12, r9, r8
+	addi	up, up, 16
+	addi	vp, vp, 16
+	addi	arp, arp, 16
+	addi	srp, srp, 16
+	bdnz	L(top)
+
+L(end):	std	r0, -8(arp)
+	std	r12, -8(srp)
+L(1):	addex(	r0, r10, r11, 0)
+	subfe	r12, r11, r10
+	std	r0, 0(arp)
+	std	r12, 0(srp)
+	subfe	r3, r3, r3
+	addex(	r3, r3, r3, 0)
+	rldicl	r3, r3, 1, 62
+	blr
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/powerpc64/mode64/p9/addmul_1.asm b/third_party/gmp/mpn/powerpc64/mode64/p9/addmul_1.asm
new file mode 100644
index 0000000..8f49606
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/p9/addmul_1.asm
@@ -0,0 +1,130 @@
+dnl  Power9 mpn_addmul_1.
+
+dnl  Copyright 2017, 2018 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                   cycles/limb
+C POWER3/PPC630		 -
+C POWER4/PPC970		 -
+C POWER5		 -
+C POWER6		 -
+C POWER7		 -
+C POWER8		 -
+C POWER9		 2.5
+
+C TODO
+C  * Schedule for Power9 pipeline.
+C  * Unroll 4x if that proves beneficial.
+C  * This is marginally faster (but much smaller) than ../aorsmul_1.asm.
+
+C INPUT PARAMETERS
+define(`rp', `r3')
+define(`up', `r4')
+define(`n',  `r5')
+define(`v0', `r6')
+
+ASM_START()
+PROLOGUE(mpn_addmul_1)
+	cmpdi	cr6, n, 2
+	addi	r0, n, -1	C FIXME: postpone
+	srdi	r0, r0, 1	C FIXME: postpone
+	mtctr	r0		C FIXME: postpone
+	rldicl.	r0, n, 0,63	C r0 = n & 3, set cr0
+	bne	cr0, L(b1)
+
+L(b0):	ld	r10, 0(rp)
+	ld	r12, 0(up)
+	ld	r11, 8(rp)
+	ld	r0, 8(up)
+	maddld(	r9, r12, v0, r10)
+	maddhdu(r7, r12, v0, r10)
+	ble	cr6, L(2)
+	ld	r10, 16(rp)
+	ld	r12, 16(up)
+	maddld(	r8, r0, v0, r11)
+	maddhdu(r5, r0, v0, r11)
+	addic	up, up, 16
+	addi	rp, rp, -8
+	b	L(mid)
+
+L(b1):	ld	r11, 0(rp)
+	ld	r0, 0(up)
+	ble	cr6, L(1)
+	ld	r10, 8(rp)
+	ld	r12, 8(up)
+	maddld(	r8, r0, v0, r11)
+	maddhdu(r5, r0, v0, r11)
+	ld	r11, 16(rp)
+	ld	r0, 16(up)
+	maddld(	r9, r12, v0, r10)
+	maddhdu(r7, r12, v0, r10)
+	addic	up, up, 24
+	bdz	L(end)
+
+	ALIGN(16)
+L(top):	ld	r10, 24(rp)
+	ld	r12, 0(up)
+	std	r8, 0(rp)
+	adde	r9, r5, r9
+	maddld(	r8, r0, v0, r11)	C W:0,2,4
+	maddhdu(r5, r0, v0, r11)	C W:1,3,5
+L(mid):	ld	r11, 32(rp)
+	ld	r0, 8(up)
+	std	r9, 8(rp)
+	adde	r8, r7, r8
+	maddld(	r9, r12, v0, r10)	C W:1,3,5
+	maddhdu(r7, r12, v0, r10)	C W:2,4,6
+	addi	rp, rp, 16
+	addi	up, up, 16
+	bdnz	L(top)
+
+L(end):	std	r8, 0(rp)
+	maddld(	r8, r0, v0, r11)
+	adde	r9, r5, r9
+	maddhdu(r5, r0, v0, r11)
+	std	r9, 8(rp)
+	adde	r8, r7, r8
+	std	r8, 16(rp)
+	addze	r3, r5
+	blr
+
+L(2):	maddld(	r8, r0, v0, r11)
+	maddhdu(r5, r0, v0, r11)
+	std	r9, 0(rp)
+	addc	r8, r7, r8
+	std	r8, 8(rp)
+	addze	r3, r5
+	blr
+
+L(1):	maddld(	r8,  r0, v0, r11)
+	std	r8, 0(rp)
+	maddhdu(r3, r0, v0, r11)
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc64/mode64/p9/addmul_2.asm b/third_party/gmp/mpn/powerpc64/mode64/p9/addmul_2.asm
new file mode 100644
index 0000000..1dd59ea
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/p9/addmul_2.asm
@@ -0,0 +1,182 @@
+dnl  Power9 mpn_addmul_2.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2018 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of the GNU Lesser General Public License as published
+dnl  by the Free Software Foundation; either version 3 of the License, or (at
+dnl  your option) any later version.
+
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+dnl  License for more details.
+
+dnl  You should have received a copy of the GNU Lesser General Public License
+dnl  along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C         cycles/limb
+C power9:    1.62
+
+C STATUS
+C  * Not written with any power9 pipeline understanding.
+C  * The 4x unrolling was not motivated by any timing tests.
+C  * No local scheduling for performance tweaking has been done.
+C  * Decrease load scheduling!
+
+define(`rp', `r3')
+define(`up', `r4')
+define(`n',  `r5')		C Note: Reused as scratch
+define(`vp', `r6')		C Note: Reused for v1
+
+define(`v0', `r7')
+define(`v1', `r6')
+
+
+ASM_START()
+PROLOGUE(mpn_addmul_2)
+	std	r26, -48(r1)
+	std	r27, -40(r1)
+	std	r28, -32(r1)
+	std	r29, -24(r1)
+	std	r30, -16(r1)
+	std	r31, -8(r1)
+
+	subfic	r0, r1, 0	C clear CA
+	subfo	r0, r0, r0	C clear OV and r0
+
+	cmpdi	cr7, n, 4
+
+	ld	v0, 0(vp)
+	ld	v1, 8(vp)
+
+	srdi	r10, n, 2
+	mtctr	r10
+
+	rldicl.	r9, n, 0, 63
+	bne	cr0, L(bx1)
+
+L(bx0):	rldicl. r9, n, 63, 63
+
+	ld	r28, 0(rp)
+	ld	r8, 0(up)
+	ld	r11, 8(rp)
+	ld	r9, 8(up)
+	maddld(	r26, r8, v0, r28)
+	maddhdu(r31, r8, v0, r28)
+	blt	cr7, L(2)
+	ld	r28, 16(rp)
+	mulld	r5, r8, v1
+	mulhdu	r10, r8, v1
+	bne	cr0, L(b10)
+
+L(b00):	addi	up, up, -8
+	addi	rp, rp, -24
+	b	L(lo0)
+
+L(b10):	addi	up, up, 8
+	addi	rp, rp, -8
+	b	L(lo2)
+
+L(2):	addi	rp, rp, -8
+	mulld	r5, r8, v1
+	mulhdu	r10, r8, v1
+	b	L(cj2)
+
+L(bx1):	rldicl. r9, n, 63, 63
+
+	ld	r29, 0(rp)
+	ld	r9, 0(up)
+	ld	r10, 8(rp)
+	ld	r8, 8(up)
+	maddld(	r27, r9, v0, r29)
+	maddhdu(r30, r9, v0, r29)
+	ld	r29, 16(rp)
+	mulld	r12, r9, v1
+	mulhdu	r11, r9, v1
+	bne	cr0, L(b11)
+
+L(b01):	addi	rp, rp, -16
+	b	L(lo1)
+L(b11):	addi	up, up, 16
+	blt	cr7, L(end)
+
+L(top):	ld	r9, 0(up)
+	maddld(	r26, r8, v0, r10)	C 0  4   -> adde
+	maddhdu(r31, r8, v0, r10)	C 1  5
+	adde	r0, r27, r0		C    7 11
+	ld	r28, 24(rp)
+	std	r0, 0(rp)
+	maddld(	r5, r8, v1, r29)	C 1  5   -> addex
+	maddhdu(r10, r8, v1, r29)	C 2  6
+	addex(	r0, r12, r30, 0)	C    8 12
+L(lo2):	ld	r8, 8(up)
+	maddld(	r27, r9, v0, r11)	C 1  5   -> adde
+	maddhdu(r30, r9, v0, r11)	C 2  6
+	adde	r0, r26, r0		C    8 12
+	ld	r29, 32(rp)
+	std	r0, 8(rp)
+	maddld(	r12, r9, v1, r28)	C 2  6   -> addex
+	maddhdu(r11, r9, v1, r28)	C 3  7
+	addex(	r0, r5, r31, 0)		C 5  9 13
+L(lo1):	ld	r9, 16(up)
+	maddld(	r26, r8, v0, r10)	C 2  6   -> adde
+	maddhdu(r31, r8, v0, r10)	C 3  7
+	adde	r0, r27, r0		C    5  9 13
+	ld	r28, 40(rp)
+	std	r0, 16(rp)
+	maddld(	r5, r8, v1, r29)	C 3  7   -> addex
+	maddhdu(r10, r8, v1, r29)	C 4  8
+	addex(	r0, r12, r30, 0)	C    6 10
+L(lo0):	ld	r8, 24(up)
+	maddld(	r27, r9, v0, r11)	C 3  7   -> adde
+	maddhdu(r30, r9, v0, r11)	C 4  8
+	adde	r0, r26, r0		C    6 10
+	ld	r29, 48(rp)
+	std	r0, 24(rp)
+	maddld(	r12, r9, v1, r28)	C 4  8   -> addex
+	maddhdu(r11, r9, v1, r28)	C 5  9
+	addex(	r0, r5, r31, 0)		C    7 11
+	addi	up, up, 32
+	addi	rp, rp, 32
+	bdnz	L(top)
+
+L(end):	ld	r9, 0(up)
+	maddld(	r26, r8, v0, r10)	C 0  4
+	maddhdu(r31, r8, v0, r10)	C 1  5
+	adde	r0, r27, r0		C    7 11
+	std	r0, 0(rp)		C		-4
+	maddld(	r5, r8, v1, r29)	C 1  5
+	maddhdu(r10, r8, v1, r29)	C 2  6
+	addex(	r0, r12, r30, 0)	C    8 12
+L(cj2):	maddld(	r27, r9, v0, r11)	C 1  5		-2
+	maddhdu(r30, r9, v0, r11)	C 2  6		-1
+	adde	r0, r26, r0		C    8 12	-3
+	std	r0, 8(rp)		C		-3
+	mulld	r12, r9, v1		C 2  6		-1
+	mulhdu	r11, r9, v1		C 3  7		0 = return limb
+	addex(	r0, r5, r31, 0)		C 5  9 13
+	adde	r0, r27, r0		C    5  9 13	-2
+	std	r0, 16(rp)		C		-2
+	addex(	r0, r12, r30, 0)	C    6 10	-1
+	adde	r0, r0, r10		C		-1
+	std	r0, 24(rp)		C		-1
+	li	r4, 0
+	addze	r3, r11
+	addex(	r3, r3, r4, 0)
+
+L(ret):	ld	r26, -48(r1)
+	ld	r27, -40(r1)
+	ld	r28, -32(r1)
+	ld	r29, -24(r1)
+	ld	r30, -16(r1)
+	ld	r31, -8(r1)
+	blr
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/powerpc64/mode64/p9/aorsmul_1.asm b/third_party/gmp/mpn/powerpc64/mode64/p9/aorsmul_1.asm
new file mode 100644
index 0000000..e4ca3a8
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/p9/aorsmul_1.asm
@@ -0,0 +1,179 @@
+dnl  POWER9 mpn_addmul_1 and mpn_submul_1.
+
+dnl  Copyright 2018 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                   mpn_addmul_1    mpn_submul_1
+C                   cycles/limb     cycles/limb
+C POWER3/PPC630		 -		 -
+C POWER4/PPC970		 -		 -
+C POWER5		 -		 -
+C POWER6		 -		 -
+C POWER7		 -		 -
+C POWER8		 -		 -
+C POWER9		 2.63		 2.63
+
+C INPUT PARAMETERS
+define(`rp', `r3')
+define(`up', `r4')
+define(`n',  `r5')
+define(`v0', `r6')
+
+
+ifdef(`OPERATION_addmul_1',`
+  define(`ADDSUBC',	adde)
+  define(`ADDSUB',	addc)
+  define(`func',	mpn_addmul_1)
+  define(`AM',		`$1')
+  define(`SM',		`')
+')
+ifdef(`OPERATION_submul_1',`
+  define(`ADDSUBC',	subfe)
+  define(`ADDSUB',	subfc)
+  define(`func',	mpn_submul_1)
+  define(`AM',		`')
+  define(`SM',		`$1')
+')
+
+MULFUNC_PROLOGUE(mpn_addmul_1 mpn_submul_1)
+
+ASM_START()
+PROLOGUE(func)
+	cmpdi	cr7, n, 3
+	srdi	r10, n, 2
+	mtctr	r10
+	rldicl.	r9, n, 0, 63
+	ld	r11, 0(up)
+	bne	cr0, L(bx1)
+
+L(bx0):	rldicl. r9, n, 63, 63
+AM(`	subfzeo	r12, n		')	C ov = 0, ca = 0
+AM(`	li	r12, 0		')
+SM(`	subfco	r12, r12, r12	')	C r12 = 0, ov = 0, ca = 1
+	ld	r9, 8(up)
+	mulld	r0, r11, v0
+	mulhdu	r5, r11, v0
+	blt	cr7, L(2)
+	ld	r8, 16(up)
+	bne	cr0, L(b10)
+
+L(b00):	addi	rp, rp, -24
+	b	L(lo0)
+L(b10):	addi	rp, rp, -8
+	addi	up, up, 16
+	b	L(lo2)
+
+L(2):	addi	rp, rp, -8
+	b	L(cj2)
+
+L(bx1):	rldicl. r9, n, 63, 63
+AM(`	subfzeo	r5, n		')	C ov = 0, ca = 0
+AM(`	li	r5, 0		')
+SM(`	subfco	r5, r5, r5	')	C r5 = 0, ov = 0, ca = 1
+	blt	cr7, L(1)
+	ld	r8, 8(up)
+	mulld	r7, r11, v0
+	mulhdu	r12, r11, v0
+	ld	r9, 16(up)
+	bne	cr0, L(b11)
+
+L(b01):	addi	rp, rp, -16
+	addi	up, up, 8
+	b	L(lo1)
+
+L(1):	mulld	r7, r11, v0
+	mulhdu	r12, r11, v0
+	ld	r11, 0(rp)
+	ADDSUB	r10, r7, r11
+	std	r10, 0(rp)
+AM(`	addze	r3, r12		')
+SM(`	subfe	r0, r0, r0	')
+SM(`	sub	r3, r12, r0	')
+	blr
+
+L(b11):	addi	up, up, 24
+	ble	cr7, L(end)
+
+	ALIGN(16)
+L(top):	ld	r11, 0(rp)
+	mulld	r0, r8, v0
+	addex(	r7, r7, r5, 0)
+	mulhdu	r5, r8, v0
+	ld	r8, 0(up)
+	ADDSUBC	r10, r7, r11
+	std	r10, 0(rp)
+L(lo2):	ld	r11, 8(rp)
+	mulld	r7, r9, v0
+	addex(	r0, r0, r12, 0)
+	mulhdu	r12, r9, v0
+	ld	r9, 8(up)
+	ADDSUBC	r10, r0, r11
+	std	r10, 8(rp)
+L(lo1):	ld	r11, 16(rp)
+	mulld	r0, r8, v0
+	addex(	r7, r7, r5, 0)
+	mulhdu	r5, r8, v0
+	ld	r8, 16(up)
+	ADDSUBC	r10, r7, r11
+	std	r10, 16(rp)
+L(lo0):	ld	r11, 24(rp)
+	mulld	r7, r9, v0
+	addex(	r0, r0, r12, 0)
+	mulhdu	r12, r9, v0
+	ld	r9, 24(up)
+	ADDSUBC	r10, r0, r11
+	std	r10, 24(rp)
+	addi	up, up, 32
+	addi	rp, rp, 32
+	bdnz	L(top)
+
+L(end):	ld	r11, 0(rp)
+	mulld	r0, r8, v0
+	addex(	r7, r7, r5, 0)
+	mulhdu	r5, r8, v0
+	ADDSUBC	r10, r7, r11
+	std	r10, 0(rp)
+L(cj2):	ld	r11, 8(rp)
+	mulld	r7, r9, v0
+	addex(	r0, r0, r12, 0)
+	mulhdu	r12, r9, v0
+	ADDSUBC	r10, r0, r11
+	std	r10, 8(rp)
+	ld	r11, 16(rp)
+	addex(	r7, r7, r5, 0)
+	ADDSUBC	r10, r7, r11
+	std	r10, 16(rp)
+	li	r0, 0
+	addex(	r3, r12, r0, 0)
+AM(`	addze	r3, r3		')
+SM(`	subfe	r0, r0, r0	')
+SM(`	sub	r3, r3, r0	')
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc64/mode64/p9/gcd_11.asm b/third_party/gmp/mpn/powerpc64/mode64/p9/gcd_11.asm
new file mode 100644
index 0000000..2dc982d
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/p9/gcd_11.asm
@@ -0,0 +1,64 @@
+dnl  PowerPC-64 mpn_gcd_11.
+
+dnl  Copyright 2000-2002, 2005, 2009, 2011-2013, 2019 Free Software Foundation,
+dnl  Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		    cycles/bit (approx)
+C POWER3/PPC630		 -
+C POWER4/PPC970		 -
+C POWER5		 -
+C POWER6		 -
+C POWER7		 -
+C POWER8		 -
+C POWER9		 5.75
+C Numbers measured with: speed -CD -s16-64 -t48 mpn_gcd_1
+
+define(`u0',    `r3')
+define(`v0',    `r4')
+
+define(`cnt',  `r9')dnl
+
+ASM_START()
+PROLOGUE(mpn_gcd_11)
+	b	L(odd)
+
+	ALIGN(16)
+L(top):	isel	v0, u0, v0, 29		C v = min(u,v)
+	isel	u0, r10, r11, 29	C u = |v - u|
+	srd	u0, u0, cnt
+L(odd):	subf	r10, u0, v0		C r10 = v - u
+	subf	r11, v0, u0		C r11 = u - v
+	cmpld	cr7, v0, u0
+	cnttzd	cnt, r10
+	bne	cr7, L(top)
+
+L(end):	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc64/mode64/p9/gcd_22.asm b/third_party/gmp/mpn/powerpc64/mode64/p9/gcd_22.asm
new file mode 100644
index 0000000..12d11b0
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/p9/gcd_22.asm
@@ -0,0 +1,143 @@
+dnl  PowerPC-64 mpn_gcd_22 optimised for POWER9.
+
+dnl  Copyright 2000-2002, 2005, 2009, 2011-2013, 2019 Free Software Foundation,
+dnl  Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		    cycles/bit (approx)
+C POWER3/PPC630		 -
+C POWER4/PPC970		 -
+C POWER5		 -
+C POWER6		 -
+C POWER7		 -
+C POWER8		 -
+C POWER9		 9.58
+
+C We define SLOW if this target uses a slow struct return mechanism, with
+C r3 as an implicit parameter for the struct pointer.
+undefine(`SLOW')dnl
+ifdef(`AIX',`define(`SLOW',`due to AIX')',`
+  ifdef(`DARWIN',,`
+    ifdef(`ELFv2_ABI',,`define(`SLOW',`due to ELFv1')')dnl
+  ')
+')
+
+ifdef(`SLOW',`
+define(`IFSLOW', `$1')
+define(`u1',    `r4')
+define(`u0',    `r5')
+define(`v1',    `r6')
+define(`v0',    `r7')
+',`
+define(`IFSLOW', `')
+define(`u1',    `r3')
+define(`u0',    `r4')
+define(`v1',    `r5')
+define(`v0',    `r6')
+')
+
+define(`tmp',   `r0')
+define(`t0',    `r8')
+define(`t1',    `r9')
+define(`s0',    `r10')
+define(`s1',    `r11')
+define(`cnt',   `r12')
+
+ASM_START()
+PROLOGUE(mpn_gcd_22)
+	cmpld	cr7, v0, u0
+L(top):	subfc	t0, v0, u0		C 0 12
+	beq	cr7, L(lowz)
+	subfe	t1, v1, u1		C 2 14
+	subfe.	tmp, tmp, tmp		C 4	set cr0 from the carry bit
+	subfc	s0, u0, v0		C 0
+	subfe	s1, u1, v1		C 2
+
+L(bck):	cnttzd	cnt, t0			C 2
+	subfic	tmp, cnt, 64		C 4
+
+	isel	v0, v0, u0, 2		C 6	use condition set by subfe
+	isel	u0, t0, s0, 2		C 6
+	isel	v1, v1, u1, 2		C 6
+	isel	u1, t1, s1, 2		C 6
+
+	srd	u0, u0, cnt		C 8
+	sld	tmp, u1, tmp		C 8
+	srd	u1, u1, cnt		C 8
+	or	u0, u0, tmp		C 10
+
+	or.	r0, u1, v1		C 10
+	cmpld	cr7, v0, u0
+	bne	L(top)
+
+
+	b	L(odd)
+	ALIGN(16)
+L(top1):isel	v0, u0, v0, 29		C v = min(u,v)
+	isel	u0, r10, r11, 29	C u = |u - v|
+	srd	u0, u0, cnt
+L(odd):	subf	r10, u0, v0		C r10 = v - u
+	subf	r11, v0, u0		C r11 = u - v
+	cmpld	cr7, v0, u0
+	cnttzd	cnt, r10
+	bne	cr7, L(top1)
+
+ifdef(`SLOW',`
+	std	v0, 0(r3)
+	std	r10, 8(r3)
+',`
+	mr	r3, v0
+	li	r4, 0
+')
+	blr
+
+
+L(lowz):C We come here when v0 - u0 = 0
+	C 1. If v1 - u1 = 0, then gcd is u = v.
+	C 2. Else compute gcd_21({v1,v0}, |u1-v1|)
+	subfc.	t0, v1, u1		C 2 8
+	beq	L(end)
+	li	t1, 0
+	subfe.	tmp, tmp, tmp		C 4	set cr0 from the carry bit
+	subf	s0, u1, v1		C 2
+	li	s1, 0
+	b	L(bck)
+
+L(end):
+ifdef(`SLOW',`
+	std	v0, 0(r3)
+	std	v1, 8(r3)
+	blr
+',`
+	mr	r3, v0
+	mr	r4, v1
+	blr
+')
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc64/mode64/p9/gmp-mparam.h b/third_party/gmp/mpn/powerpc64/mode64/p9/gmp-mparam.h
new file mode 100644
index 0000000..5650def
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/p9/gmp-mparam.h
@@ -0,0 +1,253 @@
+/* POWER9 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+/* 2200MHz POWER9 */
+/* FFT tuning limit = 221,245,838 */
+/* Generated by tuneup.c, 2019-10-29, gcc 8.3 */
+
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          8
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          5
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD         7
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        44
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     11
+#define USE_PREINV_DIVREM_1                  0
+#define DIV_QR_1N_PI1_METHOD                 2  /* 19.28% faster than 1 */
+#define DIV_QR_1_NORM_THRESHOLD              3
+#define DIV_QR_1_UNNORM_THRESHOLD            2
+#define DIV_QR_2_PI2_THRESHOLD               7
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           33
+
+#define DIV_1_VS_MUL_1_PERCENT             365
+
+#define MUL_TOOM22_THRESHOLD                34
+#define MUL_TOOM33_THRESHOLD               109
+#define MUL_TOOM44_THRESHOLD               458
+#define MUL_TOOM6H_THRESHOLD               517
+#define MUL_TOOM8H_THRESHOLD               608
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD     113
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     292
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     204
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     211
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     178
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 46
+#define SQR_TOOM3_THRESHOLD                158
+#define SQR_TOOM4_THRESHOLD                674
+#define SQR_TOOM6_THRESHOLD                  0  /* always */
+#define SQR_TOOM8_THRESHOLD                898
+
+#define MULMID_TOOM42_THRESHOLD             70
+
+#define MULMOD_BNM1_THRESHOLD               17
+#define SQRMOD_BNM1_THRESHOLD               25
+
+#define MUL_FFT_MODF_THRESHOLD             404  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    404, 5}, {     23, 6}, {     12, 5}, {     25, 6}, \
+    {     13, 5}, {     27, 6}, {     27, 7}, {     14, 6}, \
+    {     29, 7}, {     15, 6}, {     31, 7}, {     25, 8}, \
+    {     13, 7}, {     28, 8}, {     15, 7}, {     32, 8}, \
+    {     17, 7}, {     35, 8}, {     27, 9}, {     15, 8}, \
+    {     35, 9}, {     19, 8}, {     39, 9}, {     23, 8}, \
+    {     47, 9}, {     27,10}, {     15, 9}, {     31, 8}, \
+    {     63, 9}, {     35, 8}, {     71, 9}, {     39,10}, \
+    {     23, 9}, {     51,11}, {     15,10}, {     31, 9}, \
+    {     71,10}, {     39, 9}, {     83,10}, {     47, 9}, \
+    {     95,10}, {     55,11}, {     31,10}, {     79,11}, \
+    {     47,10}, {     95,12}, {     31,11}, {     63,10}, \
+    {    135,11}, {     79,10}, {    159,11}, {     95,12}, \
+    {     63,11}, {    127,10}, {    255, 9}, {    511,11}, \
+    {    143,10}, {    287, 9}, {    575,10}, {    303,11}, \
+    {    159,12}, {     95,11}, {    191,13}, {     63,12}, \
+    {    127,11}, {    255,10}, {    511,11}, {    271,10}, \
+    {    543,11}, {    287,10}, {    575,11}, {    303,12}, \
+    {    159,11}, {    319,10}, {    639,11}, {    335,10}, \
+    {    671,11}, {    351,10}, {    703,11}, {    367,10}, \
+    {    735,12}, {    191,11}, {    383,10}, {    767,11}, \
+    {    415,10}, {    831,12}, {    223,11}, {    447,10}, \
+    {    895,11}, {    479,13}, {    127,12}, {    255,11}, \
+    {    511,10}, {   1023,11}, {    543,12}, {    287,11}, \
+    {    575,10}, {   1151,11}, {    607,12}, {    319,11}, \
+    {    639,10}, {   1279,11}, {    671,12}, {    351,11}, \
+    {    703,10}, {   1407,11}, {    735,13}, {    191,12}, \
+    {    383,11}, {    767,10}, {   1535,11}, {    799,12}, \
+    {    415,11}, {    831,10}, {   1663,11}, {    863,12}, \
+    {    447,11}, {    895,12}, {    479,14}, {    127,13}, \
+    {    255,12}, {    511,11}, {   1023,12}, {    543,11}, \
+    {   1087,12}, {    575,11}, {   1151,12}, {    607,13}, \
+    {    319,12}, {    639,11}, {   1279,12}, {    671,11}, \
+    {   1343,12}, {    703,11}, {   1407,12}, {    735,11}, \
+    {   1471,13}, {    383,12}, {    767,11}, {   1535,12}, \
+    {    799,11}, {   1599,12}, {    831,11}, {   1663,13}, \
+    {    447,12}, {    895,11}, {   1791,12}, {    959,14}, \
+    {    255,13}, {    511,12}, {   1087,11}, {   2175,13}, \
+    {    575,12}, {   1215,13}, {    639,12}, {   1343,13}, \
+    {    703,12}, {   1471,14}, {    383,13}, {    767,12}, \
+    {   1599,13}, {    831,12}, {   1727,13}, {    895,11}, \
+    {   3583,12}, {   1919,15}, {    255,14}, {    511,13}, \
+    {   1087,12}, {   2175,13}, {   1215,14}, {    639,13}, \
+    {   1343,12}, {   2687,13}, {   1471,14}, {    767,13}, \
+    {   1599,12}, {   3199,13}, {   1727,14}, {    895,13}, \
+    {   1919,15}, {    511,14}, {   1023,13}, {   2175,14}, \
+    {   1151,13}, {   2431,12}, {   4863,14}, {   1279,13}, \
+    {   2687,14}, {   1407,13}, {   2943,15}, {    767,14}, \
+    {   1535,13}, {   3199,14}, {   1663,13}, {   3455,12}, \
+    {   6911,14}, {   1919,16}, {    511,15}, {   1023,14}, \
+    {   2175,13}, {   4479,14}, {   2431,13}, {   4863,15}, \
+    {   1279,14}, {   2943,13}, {   5887,15}, {   1535,14}, \
+    {   3455,13}, {   6911,15}, {   1791,14}, {   3839,13}, \
+    {   7679,16}, {   1023,15}, {   2047,14}, {   4351,15}, \
+    {   2303,14}, {   4863,15}, {   2815,14}, {   5887,16}, \
+    {   1535,15}, {   3327,14}, {   6911,15}, {   3839,14}, \
+    {   7679,17}, {   1023,16}, {   2047,15}, {   4351,14}, \
+    {   8959,15}, {   4863,16}, {   2559,15}, {   5887,14}, \
+    {  11775,16}, {   3071,15}, {  32768,16}, {  65536,17}, \
+    { 131072,18}, { 262144,19}, { 524288,20}, {1048576,21}, \
+    {2097152,22}, {4194304,23}, {8388608,24} }
+#define MUL_FFT_TABLE3_SIZE 243
+#define MUL_FFT_THRESHOLD                 3712
+
+#define SQR_FFT_MODF_THRESHOLD             404  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    404, 5}, {     25, 6}, {     13, 5}, {     27, 6}, \
+    {     29, 7}, {     15, 6}, {     31, 7}, {     25, 8}, \
+    {     13, 7}, {     28, 8}, {     15, 7}, {     32, 8}, \
+    {     17, 7}, {     35, 8}, {     29, 9}, {     15, 8}, \
+    {     35, 9}, {     19, 8}, {     41, 9}, {     23, 8}, \
+    {     47, 9}, {     27,10}, {     15, 9}, {     39,10}, \
+    {     23, 9}, {     51,11}, {     15,10}, {     31, 9}, \
+    {     71,10}, {     39, 9}, {     83,10}, {     47, 9}, \
+    {     95,10}, {     55,11}, {     31,10}, {     79,11}, \
+    {     47,10}, {     95,12}, {     31,11}, {     63,10}, \
+    {    127, 9}, {    255,10}, {    135,11}, {     79,10}, \
+    {    159,11}, {     95,12}, {     63,11}, {    127,10}, \
+    {    255, 9}, {    511,10}, {    271,11}, {    143,10}, \
+    {    287, 9}, {    575,10}, {    303,11}, {    159,12}, \
+    {     95,13}, {     63,12}, {    127,11}, {    255,10}, \
+    {    511,11}, {    271,10}, {    543,11}, {    287,10}, \
+    {    575,11}, {    303,12}, {    159,11}, {    319,10}, \
+    {    639,11}, {    335,10}, {    671,11}, {    351,10}, \
+    {    703,11}, {    367,10}, {    735,12}, {    191,11}, \
+    {    383,10}, {    767,11}, {    415,12}, {    223,11}, \
+    {    447,10}, {    895,13}, {    127,12}, {    255,11}, \
+    {    511,10}, {   1023,11}, {    543,12}, {    287,11}, \
+    {    575,10}, {   1151,11}, {    607,12}, {    319,11}, \
+    {    671,12}, {    351,11}, {    703,10}, {   1407,11}, \
+    {    735,13}, {    191,12}, {    383,11}, {    767,10}, \
+    {   1535,12}, {    415,11}, {    831,12}, {    447,11}, \
+    {    895,12}, {    479,14}, {    127,13}, {    255,12}, \
+    {    511,11}, {   1023,12}, {    543,11}, {   1087,12}, \
+    {    575,11}, {   1151,12}, {    607,13}, {    319,12}, \
+    {    639,11}, {   1279,12}, {    671,11}, {   1343,12}, \
+    {    703,11}, {   1407,12}, {    735,13}, {    383,12}, \
+    {    767,11}, {   1535,12}, {    799,11}, {   1599,12}, \
+    {    831,13}, {    447,12}, {    895,11}, {   1791,12}, \
+    {    959,14}, {    255,13}, {    511,12}, {   1023,11}, \
+    {   2047,12}, {   1087,13}, {    575,12}, {   1215,13}, \
+    {    639,12}, {   1343,13}, {    703,12}, {   1407,14}, \
+    {    383,13}, {    767,12}, {   1599,13}, {    831,12}, \
+    {   1727,13}, {    895,12}, {   1791,13}, {    959,15}, \
+    {    255,14}, {    511,13}, {   1023,12}, {   2047,13}, \
+    {   1087,12}, {   2175,13}, {   1215,14}, {    639,13}, \
+    {   1343,12}, {   2687,13}, {   1471,14}, {    767,13}, \
+    {   1599,12}, {   3199,13}, {   1727,14}, {    895,13}, \
+    {   1919,15}, {    511,14}, {   1023,13}, {   2175,14}, \
+    {   1151,13}, {   2431,12}, {   4863,14}, {   1279,13}, \
+    {   2687,14}, {   1407,13}, {   2815,15}, {    767,14}, \
+    {   1535,13}, {   3199,14}, {   1663,13}, {   3455,14}, \
+    {   1919,16}, {    511,15}, {   1023,14}, {   2175,13}, \
+    {   4479,14}, {   2431,13}, {   4863,15}, {   1279,14}, \
+    {   2943,13}, {   5887,15}, {   1535,14}, {   3455,13}, \
+    {   6911,15}, {   1791,14}, {   3839,16}, {   1023,15}, \
+    {   2047,14}, {   4479,15}, {   2303,14}, {   4863,15}, \
+    {   2559,14}, {   5119,15}, {   2815,14}, {   5887,16}, \
+    {   1535,15}, {   3327,14}, {   6911,15}, {   3839,17}, \
+    {   1023,16}, {   2047,15}, {   4351,14}, {   8959,15}, \
+    {   4863,16}, {   2559,15}, {   5887,14}, {  11775,16}, \
+    {   3071,15}, {  32768,16}, {  65536,17}, { 131072,18}, \
+    { 262144,19}, { 524288,20}, {1048576,21}, {2097152,22}, \
+    {4194304,23}, {8388608,24} }
+#define SQR_FFT_TABLE3_SIZE 230
+#define SQR_FFT_THRESHOLD                 3264
+
+#define MULLO_BASECASE_THRESHOLD             3
+#define MULLO_DC_THRESHOLD                  39
+#define MULLO_MUL_N_THRESHOLD             7246
+#define SQRLO_BASECASE_THRESHOLD             6
+#define SQRLO_DC_THRESHOLD                  40
+#define SQRLO_SQR_THRESHOLD               6440
+
+#define DC_DIV_QR_THRESHOLD                 30
+#define DC_DIVAPPR_Q_THRESHOLD              88
+#define DC_BDIV_QR_THRESHOLD                35
+#define DC_BDIV_Q_THRESHOLD                 62
+
+#define INV_MULMOD_BNM1_THRESHOLD           79
+#define INV_NEWTON_THRESHOLD                11
+#define INV_APPR_THRESHOLD                  11
+
+#define BINV_NEWTON_THRESHOLD              264
+#define REDC_1_TO_REDC_2_THRESHOLD           8
+#define REDC_2_TO_REDC_N_THRESHOLD          79
+
+#define MU_DIV_QR_THRESHOLD               1442
+#define MU_DIVAPPR_Q_THRESHOLD            1470
+#define MUPI_DIV_QR_THRESHOLD                0  /* always */
+#define MU_BDIV_QR_THRESHOLD              1470
+#define MU_BDIV_Q_THRESHOLD               1652
+
+#define POWM_SEC_TABLE  1,16,151,839
+
+#define GET_STR_DC_THRESHOLD                 7
+#define GET_STR_PRECOMPUTE_THRESHOLD        15
+#define SET_STR_DC_THRESHOLD               406
+#define SET_STR_PRECOMPUTE_THRESHOLD       885
+
+#define FAC_DSC_THRESHOLD                  179
+#define FAC_ODD_THRESHOLD                   53
+
+#define MATRIX22_STRASSEN_THRESHOLD         19
+#define HGCD2_DIV1_METHOD                    1  /* 9.10% faster than 3 */
+#define HGCD_THRESHOLD                      45
+#define HGCD_APPR_THRESHOLD                 50
+#define HGCD_REDUCE_THRESHOLD             2479
+#define GCD_DC_THRESHOLD                   321
+#define GCDEXT_DC_THRESHOLD                258
+#define JACOBI_BASE_METHOD                   4  /* 15.45% faster than 1 */
+
+/* Tuneup completed successfully, took 179422 seconds */
diff --git a/third_party/gmp/mpn/powerpc64/mode64/p9/mul_1.asm b/third_party/gmp/mpn/powerpc64/mode64/p9/mul_1.asm
new file mode 100644
index 0000000..363f095
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/p9/mul_1.asm
@@ -0,0 +1,126 @@
+dnl  Power9 mpn_mul_1.
+
+dnl  Copyright 2017, 2018 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                   cycles/limb
+C POWER3/PPC630		 ?
+C POWER4/PPC970		 ?
+C POWER5		 ?
+C POWER6		 ?
+C POWER7		 ?
+C POWER8		 ?
+C POWER9		 2.47
+
+C TODO
+C  * Schedule for Power9 pipeline.
+C  * Unroll 4x if that proves beneficial.
+C  * This is marginally faster (but much smaller) than ../mul_1.asm.
+
+C INPUT PARAMETERS
+define(`rp', `r3')
+define(`up', `r4')
+define(`n',  `r5')
+define(`v0', `r6')
+
+ASM_START()
+PROLOGUE(mpn_mul_1c)
+	b	L(ent)
+EPILOGUE()
+PROLOGUE(mpn_mul_1)
+	li	r7, 0
+L(ent):	ld	r11, 0(up)
+	cmpdi	cr6, n, 2
+	addi	r0, n, -1	C FIXME: postpone
+	srdi	r0, r0, 1	C FIXME: postpone
+	mtctr	r0		C FIXME: postpone
+	rldicl.	r12, n, 0,63	C r0 = n & 3, set cr0
+	bne	cr0, L(b1)
+
+L(b0):	ld	r0, 8(up)
+	maddld(	r9, r11, v0, r7)
+	maddhdu(r7, r11, v0, r7)
+	ble	cr6, L(2)
+	ld	r12, 16(up)
+	mulld	r8, r0, v0
+	mulhdu	r5, r0, v0
+	addic	up, up, 16
+	addi	rp, rp, -8
+	b	L(mid)
+
+L(b1):	ld	r0, 0(up)
+	ble	cr6, L(1)
+	ld	r12, 8(up)
+	maddld(	r8, r11, v0, r7)
+	maddhdu(r5, r11, v0, r7)
+	ld	r0, 16(up)
+	mulld	r9, r12, v0
+	mulhdu	r7, r12, v0
+	addic	up, up, 24
+	bdz	L(end)
+
+	ALIGN(16)
+L(top):	ld	r12, 0(up)
+	std	r8, 0(rp)
+	adde	r9, r5, r9
+	mulld	r8, r0, v0
+	mulhdu	r5, r0, v0
+L(mid):	ld	r0, 8(up)
+	std	r9, 8(rp)
+	adde	r8, r7, r8
+	mulld	r9, r12, v0
+	mulhdu	r7, r12, v0
+	addi	rp, rp, 16
+	addi	up, up, 16
+	bdnz	L(top)
+
+L(end):	std	r8, 0(rp)
+	mulld	r8, r0, v0
+	adde	r9, r5, r9
+	mulhdu	r5, r0, v0
+	std	r9, 8(rp)
+	adde	r8, r7, r8
+	std	r8, 16(rp)
+	addze	r3, r5
+	blr
+
+L(2):	mulld	r8, r0, v0
+	mulhdu	r5, r0, v0
+	std	r9, 0(rp)
+	addc	r8, r7, r8
+	std	r8, 8(rp)
+	addze	r3, r5
+	blr
+
+L(1):	maddld(	r8,  r0, v0, r7)
+	std	r8, 0(rp)
+	maddhdu(r3, r0, v0, r7)
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc64/mode64/p9/mul_2.asm b/third_party/gmp/mpn/powerpc64/mode64/p9/mul_2.asm
new file mode 100644
index 0000000..632b6cb
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/p9/mul_2.asm
@@ -0,0 +1,170 @@
+dnl  Power9 mpn_mul_2.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2018 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of the GNU Lesser General Public License as published
+dnl  by the Free Software Foundation; either version 3 of the License, or (at
+dnl  your option) any later version.
+
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+dnl  License for more details.
+
+dnl  You should have received a copy of the GNU Lesser General Public License
+dnl  along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C         cycles/limb
+C power9:    1.58
+
+C STATUS
+C  * Not written with any power9 pipeline understanding.
+C  * The 4x unrolling was not motivated by any timing tests.
+C  * No local scheduling for performance tweaking has been done.
+C  * Decrease load scheduling!
+
+define(`rp', `r3')
+define(`up', `r4')
+define(`n',  `r5')		C Note: Reused as scratch
+define(`vp', `r6')		C Note: Reused for v1
+
+define(`v0', `r7')
+define(`v1', `r6')
+
+
+ASM_START()
+PROLOGUE(mpn_mul_2)
+	std	r28, -32(r1)
+	std	r29, -24(r1)
+	std	r30, -16(r1)
+	std	r31, -8(r1)
+
+	subfic	r0, n, 0	C clear CA
+	subfo	r0, r0, r0	C clear OV and r0
+
+	cmpdi	cr7, n, 4
+
+	ld	v0, 0(vp)
+	ld	v1, 8(vp)
+
+	srdi	r10, n, 2
+	mtctr	r10
+
+	rldicl.	r9, n, 0, 63
+	bne	cr0, L(bx1)
+
+L(bx0):	rldicl. r9, n, 63, 63
+
+	ld	r8, 0(up)
+	ld	r9, 8(up)
+	li	r11, 0
+	mulld	r28, r8, v0
+	mulhdu	r31, r8, v0
+	blt	cr7, L(2)
+	mulld	r5, r8, v1
+	mulhdu	r10, r8, v1
+	bne	cr0, L(b10)
+
+L(b00):	addi	up, up, -8
+	addi	rp, rp, -24
+	b	L(lo0)
+
+L(b10):	addi	up, up, 8
+	addi	rp, rp, -8
+	b	L(lo2)
+
+L(2):	addi	rp, rp, -8
+	mulld	r5, r8, v1
+	mulhdu	r10, r8, v1
+	b	L(cj2)
+
+L(bx1):	rldicl. r9, n, 63, 63
+
+	ld	r9, 0(up)
+	ld	r8, 8(up)
+	li	r10, 0
+	mulld	r29, r9, v0
+	mulhdu	r30, r9, v0
+	mulld	r12, r9, v1
+	mulhdu	r11, r9, v1
+	bne	cr0, L(b11)
+
+L(b01):	addi	rp, rp, -16
+	b	L(lo1)
+L(b11):	addi	up, up, 16
+	blt	cr7, L(end)
+
+L(top):	ld	r9, 0(up)
+	maddld(	r28, r8, v0, r10)	C 0  4   -> adde
+	maddhdu(r31, r8, v0, r10)	C 1  5
+	adde	r0, r29, r0		C    7 11
+	std	r0, 0(rp)
+	mulld	r5, r8, v1		C 1  5   -> addex
+	mulhdu	r10, r8, v1		C 2  6
+	addex(	r0, r12, r30, 0)	C    8 12
+L(lo2):	ld	r8, 8(up)
+	maddld(	r29, r9, v0, r11)	C 1  5   -> adde
+	maddhdu(r30, r9, v0, r11)	C 2  6
+	adde	r0, r28, r0		C    8 12
+	std	r0, 8(rp)
+	mulld	r12, r9, v1		C 2  6   -> addex
+	mulhdu	r11, r9, v1		C 3  7
+	addex(	r0, r5, r31, 0)		C 5  9 13
+L(lo1):	ld	r9, 16(up)
+	maddld(	r28, r8, v0, r10)	C 2  6   -> adde
+	maddhdu(r31, r8, v0, r10)	C 3  7
+	adde	r0, r29, r0		C    5  9 13
+	std	r0, 16(rp)
+	mulld	r5, r8, v1		C 3  7   -> addex
+	mulhdu	r10, r8, v1		C 4  8
+	addex(	r0, r12, r30, 0)	C    6 10
+L(lo0):	ld	r8, 24(up)
+	maddld(	r29, r9, v0, r11)	C 3  7   -> adde
+	maddhdu(r30, r9, v0, r11)	C 4  8
+	adde	r0, r28, r0		C    6 10
+	std	r0, 24(rp)
+	mulld	r12, r9, v1		C 4  8   -> addex
+	mulhdu	r11, r9, v1		C 5  9
+	addex(	r0, r5, r31, 0)		C    7 11
+	addi	up, up, 32
+	addi	rp, rp, 32
+	bdnz	L(top)
+
+L(end):	ld	r9, 0(up)
+	maddld(	r28, r8, v0, r10)	C 0  4
+	maddhdu(r31, r8, v0, r10)	C 1  5
+	adde	r0, r29, r0		C    7 11
+	std	r0, 0(rp)		C		-4
+	mulld	r5, r8, v1		C 1  5
+	mulhdu	r10, r8, v1		C 2  6
+	addex(	r0, r12, r30, 0)	C    8 12
+L(cj2):	maddld(	r29, r9, v0, r11)	C 1  5		-2
+	maddhdu(r30, r9, v0, r11)	C 2  6		-1
+	adde	r0, r28, r0		C    8 12	-3
+	std	r0, 8(rp)		C		-3
+	mulld	r12, r9, v1		C 2  6		-1
+	mulhdu	r11, r9, v1		C 3  7		0 = return limb
+	addex(	r0, r5, r31, 0)		C 5  9 13
+	adde	r0, r29, r0		C    5  9 13	-2
+	std	r0, 16(rp)		C		-2
+	addex(	r0, r12, r30, 0)	C    6 10	-1
+	adde	r0, r0, r10		C		-1
+	std	r0, 24(rp)		C		-1
+	li	r4, 0
+	addze	r3, r11
+	addex(	r3, r3, r4, 0)
+
+L(ret):	ld	r28, -32(r1)
+	ld	r29, -24(r1)
+	ld	r30, -16(r1)
+	ld	r31, -8(r1)
+	blr
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/powerpc64/mode64/p9/mul_basecase.asm b/third_party/gmp/mpn/powerpc64/mode64/p9/mul_basecase.asm
new file mode 100644
index 0000000..8f3d322
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/p9/mul_basecase.asm
@@ -0,0 +1,415 @@
+dnl  Power9 mpn_mul_basecase.
+
+dnl  Copyright 1999-2001, 2003-2006, 2008, 2017-2018 Free Software Foundation,
+dnl  Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                  cycles/limb
+C POWER3/PPC630          -
+C POWER4/PPC970          -
+C POWER5                 -
+C POWER6                 -
+C POWER7                 -
+C POWER8                 -
+C POWER9                 1.62
+
+C TODO
+C  * Check if (inner) loop alignment affects performance.
+C  * Could we schedule loads less in addmul_2/mul_2? That would save some regs
+C    and make the tail code more manageable.
+C  * Postpone some register saves to main loop.
+C  * Perhaps write more small operands (3x1, 3x2, 3x3) code.
+C  * Consider restoring rp,up after loop using arithmetic, eliminating rp2, up2.
+C    On the other hand, the current rp,up restore register are useful for OSP.
+C  * Do OSP. This should save a lot with the current deep addmul_2 pipeline.
+
+C INPUT PARAMETERS
+define(`rp', `r3')
+define(`up', `r4')
+define(`un', `r5')
+define(`vp', `r6')
+define(`vn', `r7')
+
+define(`v0', `r0')
+define(`v1', `r7')
+define(`rp2', `r24')
+define(`up2', `r25')
+
+ASM_START()
+PROLOGUE(mpn_mul_basecase)
+	cmpdi	cr0, un, 2
+	bgt	cr0, L(un_gt2)
+	cmpdi	cr6, vn, 1
+	ld	r7, 0(vp)
+	ld	r5, 0(up)
+	mulld	r8, r5, r7	C weight 0
+	mulhdu	r9, r5, r7	C weight 1
+	std	r8, 0(rp)
+	beq	cr0, L(2x)
+	std	r9, 8(rp)
+	blr
+	ALIGN(16)
+L(2x):	ld	r0, 8(up)
+	mulld	r8, r0, r7	C weight 1
+	mulhdu	r10, r0, r7	C weight 2
+	addc	r9, r9, r8
+	addze	r10, r10
+	bne	cr6, L(2x2)
+	std	r9, 8(rp)
+	std	r10, 16(rp)
+	blr
+	ALIGN(16)
+L(2x2):	ld	r6, 8(vp)
+	mulld	r8, r5, r6	C weight 1
+	mulhdu	r11, r5, r6	C weight 2
+	addc	r9, r9, r8
+	std	r9, 8(rp)
+	adde	r11, r11, r10
+	mulld	r12, r0, r6	C weight 2
+	mulhdu	r0, r0, r6	C weight 3
+	addze	r0, r0
+	addc	r11, r11, r12
+	addze	r0, r0
+	std	r11, 16(rp)
+	std	r0, 24(rp)
+	blr
+
+L(un_gt2):
+	std	r22, -80(r1)
+	std	r23, -72(r1)
+	std	r24, -64(r1)
+	std	r25, -56(r1)
+	std	r26, -48(r1)
+	std	r27, -40(r1)
+	std	r28, -32(r1)
+	std	r29, -24(r1)
+	std	r30, -16(r1)
+	std	r31, -8(r1)
+	mr	rp2, r3			C rp
+	mr	up2, r4			C up
+	srdi	r22, r5, 2		C un
+	subfic	r23, r7, 0		C -vn, clear CA
+	subfo	r0, r0, r0		C clear OV (and r0)
+
+	cmpdi	cr6, un, 3
+	rldicl	r0, un, 0, 63		C r0 = un & 1
+	cmpdi	cr7, r0, 0
+	rldicl	r0, un, 63, 63		C FIXME: unused for vn = 1
+	cmpdi	cr5, r0, 0		C FIXME: unused for vn = 1
+
+	ld	v0, 0(vp)
+	rldicl.	r9, vn, 0, 63
+	beq	cr0, L(vn_evn)
+
+L(vn_odd):
+	addi	r10, un, -2
+	ld	r5, 0(up)
+	srdi	r10, r10, 1
+	mtctr	r10
+	bne	cr7, L(m1_b1)
+
+L(m1_b0):
+	ld	r10, 8(up)
+	mulld	r9, r5, v0
+	mulhdu	r11, r5, v0
+	ld	r12, 16(up)
+	mulld	r8, r10, v0
+	mulhdu	r5, r10, v0
+	addi	rp, rp, -8
+	b	L(m1_mid)
+
+L(m1_b1):
+	ld	r12, 8(up)
+	mulld	r8, r5, v0
+	mulhdu	r5, r5, v0
+	ld	r10, 16(up)
+	mulld	r9, r12, v0
+	mulhdu	r11, r12, v0
+	addi	up, up, 8
+	beq	cr6, L(m1_end)		C jump taken means un = 3, vn = {1,3}
+
+	ALIGN(16)
+L(m1_top):
+	ld	r12, 16(up)
+	std	r8, 0(rp)
+	adde	r9, r5, r9
+	mulld	r8, r10, v0
+	mulhdu	r5, r10, v0
+L(m1_mid):
+	ld	r10, 24(up)
+	std	r9, 8(rp)
+	adde	r8, r11, r8
+	mulld	r9, r12, v0
+	mulhdu	r11, r12, v0
+	addi	rp, rp, 16
+	addi	up, up, 16
+	bdnz	L(m1_top)
+
+L(m1_end):
+	std	r8, 0(rp)
+	mulld	r8, r10, v0
+	adde	r9, r5, r9
+	mulhdu	r5, r10, v0
+	std	r9, 8(rp)
+	adde	r8, r11, r8
+	std	r8, 16(rp)
+	addze	r10, r5
+	std	r10, 24(rp)
+
+	addi	rp2, rp2, 8
+	addi	vp, vp, 8
+	addic.	r23, r23, 1
+	b	L(do_outer)
+
+L(vn_evn):
+	ld	v1, 8(vp)
+	addi	r23, r23, 2
+	mtctr	r22
+	bne	cr7, L(m2_bx1)
+
+L(m2_bx0):
+	ld	r8, 0(up)
+	ld	r9, 8(up)
+	li	r11, 0
+	mulld	r28, r8, v0
+	mulhdu	r31, r8, v0
+	mulld	r5, r8, v1
+	mulhdu	r10, r8, v1
+	li	r12, 0
+	bne	cr5, L(m2_b10)
+
+L(m2_b00):
+	addi	up, up, -8
+	addi	rp, rp, -24
+	b	L(m2_lo0)
+
+L(m2_b10):
+	addi	up, up, 8
+	addi	rp, rp, -8
+	b	L(m2_lo2)
+
+L(m2_bx1):
+	ld	r9, 0(up)
+	ld	r8, 8(up)
+	li	r10, 0
+	mulld	r29, r9, v0
+	mulhdu	r30, r9, v0
+	mulld	r12, r9, v1
+	mulhdu	r11, r9, v1
+	li	r5, 0
+	bne	cr5, L(m2_b11)
+
+L(m2_b01):
+	addi	rp, rp, -16
+	b	L(m2_lo1)
+L(m2_b11):
+	addi	up, up, 16
+	beq	cr6, L(m2_end)		C taken means un = 3, vn = 2. We're done.
+
+L(m2_top):
+	ld	r9, 0(up)
+	maddld(	r28, r8, v0, r10)
+	maddhdu(r31, r8, v0, r10)
+	adde	r5, r29, r5
+	std	r5, 0(rp)
+	mulld	r5, r8, v1
+	mulhdu	r10, r8, v1
+	addex(	r12, r12, r30, 0)
+L(m2_lo2):
+	ld	r8, 8(up)
+	maddld(	r29, r9, v0, r11)
+	maddhdu(r30, r9, v0, r11)
+	adde	r12, r28, r12
+	std	r12, 8(rp)
+	mulld	r12, r9, v1
+	mulhdu	r11, r9, v1
+	addex(	r5, r5, r31, 0)
+L(m2_lo1):
+	ld	r9, 16(up)
+	maddld(	r28, r8, v0, r10)
+	maddhdu(r31, r8, v0, r10)
+	adde	r5, r29, r5
+	std	r5, 16(rp)
+	mulld	r5, r8, v1
+	mulhdu	r10, r8, v1
+	addex(	r12, r12, r30, 0)
+L(m2_lo0):
+	ld	r8, 24(up)
+	maddld(	r29, r9, v0, r11)
+	maddhdu(r30, r9, v0, r11)
+	adde	r12, r28, r12
+	std	r12, 24(rp)
+	mulld	r12, r9, v1
+	mulhdu	r11, r9, v1
+	addex(	r5, r5, r31, 0)
+	addi	up, up, 32
+	addi	rp, rp, 32
+	bdnz	L(m2_top)
+
+L(m2_end):
+	ld	r9, 0(up)
+	maddld(	r28, r8, v0, r10)
+	maddhdu(r31, r8, v0, r10)
+	adde	r5, r29, r5
+	std	r5, 0(rp)
+	mulld	r5, r8, v1
+	mulhdu	r10, r8, v1
+	b	L(cj)
+
+L(outer):
+	ld	v0, 0(vp)
+	ld	v1, 8(vp)
+	addi	r23, r23, 2
+	mtctr	r22
+	bne	cr7, L(bx1)
+
+L(bx0):	ld	r26, 0(rp2)
+	ld	r8, 0(up2)
+	ld	r11, 8(rp2)
+	ld	r9, 8(up2)
+	maddld(	r28, r8, v0, r26)
+	maddhdu(r31, r8, v0, r26)
+	ld	r26, 16(rp2)
+	mulld	r5, r8, v1
+	mulhdu	r10, r8, v1
+	li	r12, 0
+	bne	cr5, L(b10)
+
+L(b00):	addi	up, up2, -8
+	addi	rp, rp2, -24
+	b	L(lo0)
+
+L(b10):	addi	up, up2, 8
+	addi	rp, rp2, -8
+	b	L(lo2)
+
+L(bx1):	ld	r27, 0(rp2)
+	ld	r9, 0(up2)
+	ld	r10, 8(rp2)
+	ld	r8, 8(up2)
+	maddld(	r29, r9, v0, r27)
+	maddhdu(r30, r9, v0, r27)
+	ld	r27, 16(rp2)
+	mulld	r12, r9, v1
+	mulhdu	r11, r9, v1
+	li	r5, 0
+	bne	cr5, L(b11)
+
+L(b01):	addi	up, up2, 0
+	addi	rp, rp2, -16
+	b	L(lo1)
+L(b11):	addi	up, up2, 16
+	addi	rp, rp2, 0
+	beq	cr6, L(end)		C taken means un = 3, vn = 3. We're done.
+
+L(top):	ld	r9, 0(up)
+	maddld(	r28, r8, v0, r10)
+	maddhdu(r31, r8, v0, r10)
+	adde	r5, r29, r5
+	ld	r26, 24(rp)
+	std	r5, 0(rp)
+	maddld(	r5, r8, v1, r27)
+	maddhdu(r10, r8, v1, r27)
+	addex(	r12, r12, r30, 0)
+L(lo2):	ld	r8, 8(up)
+	maddld(	r29, r9, v0, r11)
+	maddhdu(r30, r9, v0, r11)
+	adde	r12, r28, r12
+	ld	r27, 32(rp)
+	std	r12, 8(rp)
+	maddld(	r12, r9, v1, r26)
+	maddhdu(r11, r9, v1, r26)
+	addex(	r5, r5, r31, 0)
+L(lo1):	ld	r9, 16(up)
+	maddld(	r28, r8, v0, r10)
+	maddhdu(r31, r8, v0, r10)
+	adde	r5, r29, r5
+	ld	r26, 40(rp)
+	std	r5, 16(rp)
+	maddld(	r5, r8, v1, r27)
+	maddhdu(r10, r8, v1, r27)
+	addex(	r12, r12, r30, 0)
+L(lo0):	ld	r8, 24(up)
+	maddld(	r29, r9, v0, r11)
+	maddhdu(r30, r9, v0, r11)
+	adde	r12, r28, r12
+	ld	r27, 48(rp)
+	std	r12, 24(rp)
+	maddld(	r12, r9, v1, r26)
+	maddhdu(r11, r9, v1, r26)
+	addex(	r5, r5, r31, 0)
+	addi	up, up, 32
+	addi	rp, rp, 32
+	bdnz	L(top)
+
+L(end):	ld	r9, 0(up)
+	maddld(	r28, r8, v0, r10)
+	maddhdu(r31, r8, v0, r10)
+	adde	r5, r29, r5
+	std	r5, 0(rp)
+	maddld(	r5, r8, v1, r27)
+	maddhdu(r10, r8, v1, r27)
+L(cj):	addex(	r12, r12, r30, 0)
+	maddld(	r29, r9, v0, r11)
+	maddhdu(r30, r9, v0, r11)
+	adde	r12, r28, r12
+	std	r12, 8(rp)
+	mulld	r12, r9, v1
+	mulhdu	r11, r9, v1
+	addex(	r5, r5, r31, 0)
+	adde	r5, r29, r5
+	std	r5, 16(rp)
+	addex(	r12, r12, r30, 0)
+	adde	r12, r12, r10
+	std	r12, 24(rp)
+	li	r4, 0
+	addze	r5, r11
+	addex(	r5, r5, r4, 0)
+	std	r5, 32(rp)
+
+	cmpdi	cr0, r23, 0
+	addi	rp2, rp2, 16
+	addi	vp, vp, 16
+L(do_outer):
+	bne	cr0, L(outer)
+L(ret):
+	ld	r22, -80(r1)
+	ld	r23, -72(r1)
+	ld	r24, -64(r1)
+	ld	r25, -56(r1)
+	ld	r26, -48(r1)
+	ld	r27, -40(r1)
+	ld	r28, -32(r1)
+	ld	r29, -24(r1)
+	ld	r30, -16(r1)
+	ld	r31, -8(r1)
+	blr
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/powerpc64/mode64/p9/sqr_basecase.asm b/third_party/gmp/mpn/powerpc64/mode64/p9/sqr_basecase.asm
new file mode 100644
index 0000000..2d4fa63
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/p9/sqr_basecase.asm
@@ -0,0 +1,555 @@
+dnl  Power9 mpn_sqr_basecase.
+
+dnl  Copyright 1999-2001, 2003-2006, 2008, 2017-2018 Free Software Foundation,
+dnl  Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                  cycles/limb
+C POWER3/PPC630          -
+C POWER4/PPC970          -
+C POWER5                 -
+C POWER6                 -
+C POWER7                 -
+C POWER8                 -
+C POWER9                 1.62
+
+C TODO
+C  * Completely separate evn and odd code into two outer loops. Also consider
+C    unrolling these two outer loops and thereby eliminate all branches.
+C  * Avoid the reloading of u1 before every loop start.
+C  * Reduce register usage.
+C  * Consider getting rid of cy and instead load 3 u limbs, use addc+adde+adde.
+C  * Consider skewing conditional adjustments to allow mask creation with subfe
+C    like in the un=3 code. It might streamline the adjustments (or not).
+
+C INPUT PARAMETERS
+define(`rp', `r3')
+define(`up', `r4')
+define(`un', `r5')
+
+define(`u0', `r0')
+define(`u1', `r7')
+define(`rp2', `r24')
+define(`up2', `r25')
+define(`cy',  `r6')
+
+define(`LSHU1U0',`
+	addc	u0, u0, u0
+	adde	u1, u1, u1
+	li	cy, 0
+	addze	cy, cy
+')
+define(`LSHU1U',`
+	addc	u0, u0, u0
+	add	u0, u0, cy
+	adde	u1, u1, u1
+	li	cy, 0
+	addze	cy, cy
+')
+define(`LSHU1UF',`
+	addc	u0, u0, u0
+	add	u0, u0, cy
+	adde	u1, u1, u1
+')
+define(`LSHU1UHF',`
+	add	u0, u0, u0
+	add	u0, u0, cy
+')
+C These are cleverer replacements, but they tend to leave CA set, disturbing
+C the main accumulation code! Breaking that false dependency might have a
+C positive performance impact. Note that the subfe here results in a mask for
+C our adjustments.
+define(`xLSHU1U0',`
+	addc	u0, u0, u0
+	adde	u1, u1, u1
+	subfe	cy, cy, cy
+')
+define(`xLSHU1U',`
+	subfic	cy, cy, 0
+	adde	u0, u0, u0
+	adde	u1, u1, u1
+	subfe	cy, cy, cy
+')
+define(`xLSHU1U',`
+	subfic	cy, cy, 0
+	adde	u0, u0, u0
+')
+
+ASM_START()
+PROLOGUE(mpn_sqr_basecase)
+	ld	r0, 0(up)	C n = 1
+	mulld	r8, r0, r0	C weight 0
+	mulhdu	r9, r0, r0	C weight 1
+	std	r8, 0(rp)
+	cmpdi	cr0, un, 2
+	bge	cr0, L(ge2)
+	std	r9, 8(rp)
+	blr
+
+L(ge2):	bgt	cr0, L(gt2)
+	ld	r6, 8(up)
+	mulld	r10, r6, r6	C u1 * u1
+	mulhdu	r11, r6, r6	C u1 * u1
+	mulld	r4, r6, r0	C u1 * u0
+	mulhdu	r5, r6, r0	C u1 * u0
+	addc	r4, r4, r4
+	adde	r5, r5, r5
+	addze	r11, r11
+	addc	r9, r9, r4
+	adde	r10, r10, r5
+	addze	r11, r11
+	std	r9, 8(rp)
+	std	r10, 16(rp)
+	std	r11, 24(rp)
+	blr
+
+L(gt2):	cmpdi	cr0, un, 3
+	bgt	cr0, L(gt3)
+	std	r30, -16(r1)
+	std	r31, -8(r1)
+	subfo	r12, r12, r12		C clear OV (and result register)
+	ld	r8, 8(r4)
+	mulld	r5, r8, r8		C W2
+	mulhdu	r10, r8, r8		C W3
+	sradi	r11, u0, 63		C CAUTION: clobbers CA
+	and	r11, r11, r8		C W3
+	addc	u0, u0, u0
+	adde	u1, r8, r8
+	subfe	r6, r6, r6		C	mask
+	ld	r4, 16(r4)		C W2
+	mulld	r12, r8, u0		C W1	u1 x u0
+	mulhdu	r8, r8, u0		C W2	u1 x u0
+	maddld(	r31, r4, u0, r11)	C W2
+	maddhdu(r30, r4, u0, r11)	C W3
+	andc	r6, r4, r6		C W4
+	addc	r9, r12, r9		C W1
+	std	r9, 8(rp)		C W1
+	mulld	r9, r4, u1		C W3
+	mulhdu	r11, r4, u1		C W4
+	addex(	r5, r5, r8, 0)		C W2
+	adde	r5, r31, r5		C W2
+	std	r5, 16(rp)		C W2
+	maddld(	r5, r4, r4, r6)		C W4	u2^2
+	maddhdu(r6, r4, r4, r6)		C W5	u2^2
+	addex(	r9, r9, r30, 0)		C W3
+	adde	r9, r9, r10		C W3
+	std	r9, 24(rp)		C W3
+	adde	r5, r5, r11		C W4
+	addze	r6, r6			C W5
+	li	r8, 0
+	addex(	r5, r5, r8, 0)		C W4
+	std	r5, 32(rp)		C W4
+	addex(	r6, r6, r8, 0)		C W5
+	std	r6, 40(rp)		C W5
+	ld	r30, -16(r1)
+	ld	r31, -8(r1)
+	blr
+
+L(gt3):	std	r22, -80(r1)
+	std	r23, -72(r1)
+	std	r24, -64(r1)
+	std	r25, -56(r1)
+	std	r26, -48(r1)
+	std	r27, -40(r1)
+	std	r28, -32(r1)
+	std	r29, -24(r1)
+	std	r30, -16(r1)
+	std	r31, -8(r1)
+
+	mr	rp2, rp
+	mr	up2, up
+	addi	r22, un, -1		C count for loop FIXME: Adjust
+	subfo	r0, r0, r0		C clear OV (and r0)
+	rldicl	r0, un, 0, 63		C r0 = un & 1
+	cmpdi	cr7, r0, 0
+
+	ld	u0, 0(up2)
+	ld	u1, 8(up2)
+
+	cmpdi	cr5, r22, 4
+	srdi	r31, r22, 2
+	addi	r22, r22, -2
+	mtctr	r31
+
+	beq	cr7, L(m2_evn)
+L(m2_odd):
+	rldicl.	r31, r22, 63, 63	C r22 & 2
+	mulld	r23, u0, u0
+	mulhdu	r12, u0, u0
+	mulld	r5, u1, u1
+	mulhdu	r10, u1, u1
+
+	sradi	r11, u0, 63
+	and	r11, r11, u1
+
+	LSHU1U0
+
+	ld	r8, 8(up2)
+	ld	r9, 16(up2)
+	mulld	r28, r8, u0		C W	u1 x u0
+	mulhdu	r31, r8, u0		C W	u1 x u0
+	std	r23, 0(rp2)
+
+	bne	cr0, L(m2_11)
+L(m2_01):
+	addi	up, up2, 16
+	addi	rp, rp2, 0
+	b	L(m2_lo2)
+L(m2_11):
+	addi	up, up2, 0
+	addi	rp, rp2, -16
+	b	L(m2_lo0)
+
+L(m2_evn):
+	rldicl.	r31, r22, 63, 63	C r22 & 2
+	mulld	r23, u0, u0
+	mulhdu	r5, u0, u0
+	mulld	r12, u1, u1
+	mulhdu	r11, u1, u1
+
+	sradi	r10, u0, 63
+	and	r10, r10, u1
+
+	LSHU1U0
+
+	ld	r9, 8(up2)
+	ld	r8, 16(up2)
+	mulld	r29, r9, u0		C W	u1 x u0
+	mulhdu	r30, r9, u0		C W	u1 x u0
+	std	r23, 0(rp2)
+
+	beq	cr0, L(m2_10)
+L(m2_00):
+	addi	up, up2, 8
+	addi	rp, rp2, -8
+	b	L(m2_lo1)
+L(m2_10):
+	addi	up, up2, 24
+	addi	rp, rp2, 8
+	ble	cr5, L(m2_end)
+
+L(m2_top):
+	ld	r9, 0(up)
+	maddld(	r28, r8, u0, r10)
+	maddhdu(r31, r8, u0, r10)
+	adde	r5, r29, r5
+	std	r5, 0(rp)
+	mulld	r5, r8, u1
+	mulhdu	r10, r8, u1
+	addex(	r12, r12, r30, 0)
+L(m2_lo2):
+	ld	r8, 8(up)
+	maddld(	r29, r9, u0, r11)
+	maddhdu(r30, r9, u0, r11)
+	adde	r12, r28, r12
+	std	r12, 8(rp)
+	mulld	r12, r9, u1
+	mulhdu	r11, r9, u1
+	addex(	r5, r5, r31, 0)
+L(m2_lo1):
+	ld	r9, 16(up)
+	maddld(	r28, r8, u0, r10)
+	maddhdu(r31, r8, u0, r10)
+	adde	r5, r29, r5
+	std	r5, 16(rp)
+	mulld	r5, r8, u1
+	mulhdu	r10, r8, u1
+	addex(	r12, r12, r30, 0)
+L(m2_lo0):
+	ld	r8, 24(up)
+	maddld(	r29, r9, u0, r11)
+	maddhdu(r30, r9, u0, r11)
+	adde	r12, r28, r12
+	std	r12, 24(rp)
+	mulld	r12, r9, u1
+	mulhdu	r11, r9, u1
+	addex(	r5, r5, r31, 0)
+	addi	up, up, 32
+	addi	rp, rp, 32
+	bdnz	L(m2_top)
+
+L(m2_end):
+	ld	r9, 0(up)
+	maddld(	r28, r8, u0, r10)
+	maddhdu(r31, r8, u0, r10)
+	adde	r5, r29, r5
+	std	r5, 0(rp)
+	mulld	r5, r8, u1
+	mulhdu	r10, r8, u1
+	b	L(cj)			C jump to addmul_2 tail
+
+L(outer):
+	addi	up2, up2, 16
+	addi	rp2, rp2, 32
+
+	ld	u0, 0(up2)
+	ld	u1, 8(up2)
+
+	cmpdi	cr5, r22, 4
+	srdi	r31, r22, 2
+	addi	r22, r22, -2
+	mtctr	r31
+
+	ld	r26, 0(rp2)
+	ld	r27, 16(rp2)
+
+	rldicl.	r31, r22, 63, 63	C r22 & 2
+	beq	cr7, L(evn)
+
+L(odd):	maddld(	r23, u0, u0, r26)	C W	u2^2
+	maddhdu(r12, u0, u0, r26)	C W	u2^2
+	maddld(	r5, u1, u1, r27)	C W	u3^2
+	maddhdu(r10, u1, u1, r27)	C W	u3^2
+	ld	r26, 8(rp2)
+
+	ld	r8, -8(up2)
+	sradi	r8, r8, 63		C CAUTION: clobbers CA
+	and	r8, r8, u0
+	sradi	r11, u0, 63		C CAUTION: clobbers CA
+	and	r11, r11, u1
+
+	LSHU1U
+
+	addc	r23, r23, r8
+
+	ld	r8, 8(up2)
+	ld	r9, 16(up2)
+	maddld(	r28, r8, u0, r26)	C W	u3 x u2
+	maddhdu(r31, r8, u0, r26)	C W	u3 x u2
+	ld	r26, 24(rp2)
+	std	r23, 0(rp2)		C W0
+
+	bne	cr0, L(11)
+L(01):
+	addi	up, up2, 16
+	addi	rp, rp2, 0
+	b	L(lo2)
+L(11):
+	addi	up, up2, 0
+	addi	rp, rp2, -16
+	b	L(lo0)
+
+L(evn):	maddld(	r23, u0, u0, r26)	C W	u2^2
+	maddhdu(r5, u0, u0, r26)	C W	u2^2
+	maddld(	r12, u1, u1, r27)	C W	u3^2
+	maddhdu(r11, u1, u1, r27)	C W	u3^2
+	ld	r27, 8(rp2)
+
+	ld	r9, -8(up2)
+	sradi	r9, r9, 63		C CAUTION: clobbers CA
+	and	r9, r9, u0
+	sradi	r10, u0, 63		C CAUTION: clobbers CA
+	and	r10, r10, u1
+
+	LSHU1U
+
+	addc	r23, r23, r9
+
+	ld	r9, 8(up2)
+	ld	r8, 16(up2)
+	maddld(	r29, r9, u0, r27)	C W	u3 x u2
+	maddhdu(r30, r9, u0, r27)	C W	u3 x u2
+	ld	r27, 24(rp2)
+	std	r23, 0(rp2)		C W0
+
+	beq	cr0, L(10)
+L(00):
+	addi	up, up2, 8
+	addi	rp, rp2, -8
+	b	L(lo1)
+L(10):
+	addi	up, up2, 24
+	addi	rp, rp2, 8
+	ble	cr5, L(end)
+
+L(top):	ld	r9, 0(up)
+	maddld(	r28, r8, u0, r10)
+	maddhdu(r31, r8, u0, r10)
+	adde	r5, r29, r5
+	ld	r26, 24(rp)
+	std	r5, 0(rp)
+	maddld(	r5, r8, u1, r27)
+	maddhdu(r10, r8, u1, r27)
+	addex(	r12, r12, r30, 0)
+L(lo2):	ld	r8, 8(up)
+	maddld(	r29, r9, u0, r11)
+	maddhdu(r30, r9, u0, r11)
+	adde	r12, r28, r12
+	ld	r27, 32(rp)
+	std	r12, 8(rp)
+	maddld(	r12, r9, u1, r26)
+	maddhdu(r11, r9, u1, r26)
+	addex(	r5, r5, r31, 0)
+L(lo1):	ld	r9, 16(up)
+	maddld(	r28, r8, u0, r10)
+	maddhdu(r31, r8, u0, r10)
+	adde	r5, r29, r5
+	ld	r26, 40(rp)
+	std	r5, 16(rp)
+	maddld(	r5, r8, u1, r27)
+	maddhdu(r10, r8, u1, r27)
+	addex(	r12, r12, r30, 0)
+L(lo0):	ld	r8, 24(up)
+	maddld(	r29, r9, u0, r11)
+	maddhdu(r30, r9, u0, r11)
+	adde	r12, r28, r12
+	ld	r27, 48(rp)
+	std	r12, 24(rp)
+	maddld(	r12, r9, u1, r26)
+	maddhdu(r11, r9, u1, r26)
+	addex(	r5, r5, r31, 0)
+	addi	up, up, 32
+	addi	rp, rp, 32
+	bdnz	L(top)
+
+L(end):	ld	r9, 0(up)
+	maddld(	r28, r8, u0, r10)
+	maddhdu(r31, r8, u0, r10)
+	adde	r5, r29, r5
+	std	r5, 0(rp)
+	maddld(	r5, r8, u1, r27)
+	maddhdu(r10, r8, u1, r27)
+L(cj):	addex(	r12, r12, r30, 0)
+	maddld(	r29, r9, u0, r11)
+	maddhdu(r30, r9, u0, r11)
+	adde	r12, r28, r12
+	std	r12, 8(rp)
+	mulld	r12, r9, u1
+	mulhdu	r11, r9, u1
+	addex(	r5, r5, r31, 0)
+	adde	r5, r29, r5
+	std	r5, 16(rp)
+	addex(	r12, r12, r30, 0)
+	adde	r12, r12, r10
+	std	r12, 24(rp)
+	li	r4, 0
+	addze	r5, r11
+	addex(	r5, r5, r4, 0)
+	std	r5, 32(rp)
+	bgt	cr5, L(outer)
+
+L(corner):
+	ld	u0, 16(up2)
+	ld	u1, 24(up2)
+	ld	r26, 32(rp2)
+	bne	cr7, L(corner_odd)
+
+L(corner_evn):
+	ld	r27, 40(rp2)
+	maddld(	r23, u0, u0, r26)	C W	u2^2
+	maddhdu(r5, u0, u0, r26)	C W	u2^2
+	mulld	r12, u1, u1		C W	u3^2
+	mulhdu	r11, u1, u1		C W	u3^2
+
+	ld	r9, 8(up2)
+	sradi	r9, r9, 63		C CAUTION: clobbers CA
+	and	r9, r9, u0
+	sradi	r10, u0, 63		C CAUTION: clobbers CA
+	and	r10, r10, u1
+
+	LSHU1UHF
+
+	addc	r23, r23, r9
+
+	ld	r9, 24(up2)
+	maddld(	r29, r9, u0, r27)	C W	u3 x u2
+	maddhdu(r30, r9, u0, r27)	C W	u3 x u2
+	std	r23, 32(rp2)
+	adde	r5, r29, r5
+	std	r5, 40(rp2)
+	addex(	r12, r12, r30, 0)
+	adde	r12, r12, r10		C W	FIXME can this co?
+	std	r12, 48(rp2)
+	li	r4, 0
+	addex(	r5, r11, r4, 0)
+	addze	r5, r5
+	std	r5, 56(rp2)
+	b	L(ret)
+
+L(corner_odd):
+	ld	r27, 48(rp2)
+	maddld(	r23, u0, u0, r26)	C W	u2^2
+	maddhdu(r12, u0, u0, r26)	C W	u2^2
+	maddld(	r5, u1, u1, r27)	C W	u3^2
+	maddhdu(r10, u1, u1, r27)	C W	u3^2
+	ld	r26, 40(rp2)
+
+	ld	r8, 8(up2)
+	sradi	r8, r8, 63		C CAUTION: clobbers CA
+	and	r8, r8, u0
+	sradi	r11, u0, 63		C CAUTION: clobbers CA
+	and	r11, r11, u1
+
+	LSHU1UF
+
+	addc	r23, r23, r8
+
+	ld	r8, 24(up2)
+	ld	r9, 32(up2)
+	maddld(	r28, r8, u0, r26)	C W	u3 x u2
+	maddhdu(r31, r8, u0, r26)	C W	u3 x u2
+	std	r23, 32(rp2)
+	maddld(	r29, r9, u0, r11)
+	maddhdu(r30, r9, u0, r11)
+	adde	r12, r28, r12
+	std	r12, 40(rp2)
+	mulld	r12, r9, u1
+	mulhdu	r11, r9, u1
+	addex(	r5, r5, r31, 0)
+	adde	r5, r29, r5
+	std	r5, 48(rp2)
+	addex(	r12, r12, r30, 0)
+	adde	r12, r12, r10
+	std	r12, 56(rp2)
+	mulld	r23, r9, r9		C W	u2^2
+	mulhdu	r12, r9, r9		C W	u2^2
+	adde	r23, r23, r11
+	addze	r12, r12
+	sradi	r4, r8, 63		C CAUTION: clobbers CA
+	and	r4, r4, r9
+	addex(	r23, r23, r4, 0)
+	std	r23, 64(rp2)
+	li	r4, 0
+	addex(	r12, r12, r4, 0)
+	std	r12, 72(rp2)
+
+L(ret):	ld	r22, -80(r1)
+	ld	r23, -72(r1)
+	ld	r24, -64(r1)
+	ld	r25, -56(r1)
+	ld	r26, -48(r1)
+	ld	r27, -40(r1)
+	ld	r28, -32(r1)
+	ld	r29, -24(r1)
+	ld	r30, -16(r1)
+	ld	r31, -8(r1)
+	blr
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/powerpc64/mode64/rsh1aors_n.asm b/third_party/gmp/mpn/powerpc64/mode64/rsh1aors_n.asm
new file mode 100644
index 0000000..1f57bdf
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/rsh1aors_n.asm
@@ -0,0 +1,173 @@
+dnl  PowerPC-64 mpn_rsh1add_n, mpn_rsh1sub_n
+
+dnl  Copyright 2003, 2005, 2010, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		   cycles/limb
+C POWER3/PPC630		 ?
+C POWER4/PPC970		 2.9
+C POWER5		 ?
+C POWER6		 3.5
+C POWER7		 2.25
+
+define(`rp', `r3')
+define(`up', `r4')
+define(`vp', `r5')
+define(`n',  `r6')
+
+ifdef(`OPERATION_rsh1add_n', `
+  define(`ADDSUBC',	`addc')
+  define(`ADDSUBE',	`adde')
+  define(INITCY,	`addic	$1, r1, 0')
+  define(`func',	mpn_rsh1add_n)')
+ifdef(`OPERATION_rsh1sub_n', `
+  define(`ADDSUBC',	`subfc')
+  define(`ADDSUBE',	`subfe')
+  define(INITCY,	`addic	$1, r1, -1')
+  define(`func',	mpn_rsh1sub_n)')
+
+define(`s0', `r9')
+define(`s1', `r7')
+define(`x0', `r0')
+define(`x1', `r12')
+define(`u0', `r8')
+define(`v0', `r10')
+
+MULFUNC_PROLOGUE(mpn_rsh1add_n mpn_rsh1sub_n)
+
+ASM_START()
+PROLOGUE(func)
+	ld	u0, 0(up)
+	ld	v0, 0(vp)
+
+	cmpdi	cr6, n, 2
+
+	addi	r0, n, 1
+	srdi	r0, r0, 2
+	mtctr	r0			C copy size to count register
+
+	andi.	r0, n, 1
+	bne	cr0, L(bx1)
+
+L(bx0):	ADDSUBC	x1, v0, u0
+	ld	u0, 8(up)
+	ld	v0, 8(vp)
+	ADDSUBE	x0, v0, u0
+	ble	cr6, L(n2)
+	ld	u0, 16(up)
+	ld	v0, 16(vp)
+	srdi	s0, x1, 1
+	rldicl	r11, x1, 0, 63		C return value
+	ADDSUBE	x1, v0, u0
+	andi.	n, n, 2
+	bne	cr0, L(b10)
+L(b00):	addi	rp, rp, -24
+	b	L(lo0)
+L(b10):	addi	up, up, 16
+	addi	vp, vp, 16
+	addi	rp, rp, -8
+	b	L(lo2)
+
+	ALIGN(16)
+L(bx1):	ADDSUBC	x0, v0, u0
+	ble	cr6, L(n1)
+	ld	u0, 8(up)
+	ld	v0, 8(vp)
+	ADDSUBE	x1, v0, u0
+	ld	u0, 16(up)
+	ld	v0, 16(vp)
+	srdi	s1, x0, 1
+	rldicl	r11, x0, 0, 63		C return value
+	ADDSUBE	x0, v0, u0
+	andi.	n, n, 2
+	bne	cr0, L(b11)
+L(b01):	addi	up, up, 8
+	addi	vp, vp, 8
+	addi	rp, rp, -16
+	b	L(lo1)
+L(b11):	addi	up, up, 24
+	addi	vp, vp, 24
+	bdz	L(end)
+
+	ALIGN(32)
+L(top):	ld	u0, 0(up)
+	ld	v0, 0(vp)
+	srdi	s0, x1, 1
+	rldimi	s1, x1, 63, 0
+	std	s1, 0(rp)
+	ADDSUBE	x1, v0, u0
+L(lo2):	ld	u0, 8(up)
+	ld	v0, 8(vp)
+	srdi	s1, x0, 1
+	rldimi	s0, x0, 63, 0
+	std	s0, 8(rp)
+	ADDSUBE	x0, v0, u0
+L(lo1):	ld	u0, 16(up)
+	ld	v0, 16(vp)
+	srdi	s0, x1, 1
+	rldimi	s1, x1, 63, 0
+	std	s1, 16(rp)
+	ADDSUBE	x1, v0, u0
+L(lo0):	ld	u0, 24(up)
+	ld	v0, 24(vp)
+	srdi	s1, x0, 1
+	rldimi	s0, x0, 63, 0
+	std	s0, 24(rp)
+	ADDSUBE	x0, v0, u0
+	addi	up, up, 32
+	addi	vp, vp, 32
+	addi	rp, rp, 32
+	bdnz	L(top)
+
+L(end):	srdi	s0, x1, 1
+	rldimi	s1, x1, 63, 0
+	std	s1, 0(rp)
+L(cj2):	srdi	s1, x0, 1
+	rldimi	s0, x0, 63, 0
+	std	s0, 8(rp)
+L(cj1):	ADDSUBE	x1, x1, x1		C pseudo-depends on x1
+	rldimi	s1, x1, 63, 0
+	std	s1, 16(rp)
+	mr	r3, r11
+	blr
+
+L(n1):	srdi	s1, x0, 1
+	rldicl	r11, x0, 0, 63		C return value
+	ADDSUBE	x1, x1, x1		C pseudo-depends on x1
+	rldimi	s1, x1, 63, 0
+	std	s1, 0(rp)
+	mr	r3, r11
+	blr
+
+L(n2):	addi	rp, rp, -8
+	srdi	s0, x1, 1
+	rldicl	r11, x1, 0, 63		C return value
+	b	L(cj2)
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc64/mode64/sqr_basecase.asm b/third_party/gmp/mpn/powerpc64/mode64/sqr_basecase.asm
new file mode 100644
index 0000000..e76bb88
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/mode64/sqr_basecase.asm
@@ -0,0 +1,863 @@
+dnl  PowerPC-64 mpn_sqr_basecase.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 1999-2001, 2003-2006, 2008, 2010, 2011 Free Software Foundation,
+dnl  Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                  cycles/limb
+C POWER3/PPC630         6-18
+C POWER4/PPC970          8
+C POWER5                 8
+C POWER6                16.25
+C POWER7                 3.77
+
+C NOTES
+C  * This is very crude, cleanup!
+C  * Try to reduce the number of needed live registers.
+C  * Rewrite for POWER6 to use 8 consecutive muls, not 2 groups of 4.  The
+C    cost will be more live registers.
+C  * Rewrite for POWER7 to use addmul_2 building blocks; this will reduce code
+C    size a lot and speed things up perhaps 25%.
+C  * Use computed goto in order to compress the code.
+C  * Implement a larger final corner.
+C  * Schedule callee-saves register saves into other insns.  This could save
+C    about 5 cycles/call.  (We cannot analogously optimise the restores, since
+C    the sqr_diag_addlsh1 loop has no wind-down code as currently written.)
+C  * Should the alternating std/adde sequences be split?  Some pipelines handle
+C    adde poorly, and might sequentialise all these instructions.
+C  * The sqr_diag_addlsh1 loop was written for POWER6 and its preferences for
+C    adjacent integer multiply insns.  Except for the multiply insns, the code
+C    was not carefully optimised for POWER6 or any other CPU.
+C  * Perform cross-jumping in sqr_diag_addlsh1's feed-in code, into the loop.
+
+C INPUT PARAMETERS
+define(`rp', `r3')
+define(`up', `r4')
+define(`n',  `r5')
+
+define(`rp_outer', `r25')
+define(`up_outer', `r21')
+define(`rp_saved', `r22')
+define(`up_saved', `r23')
+define(`n_saved',  `r24')
+
+ASM_START()
+PROLOGUE(mpn_sqr_basecase)
+	cmpdi	cr0, n, 2
+	bge	cr0, L(ge2)
+	ld	r5, 0(up)	C n = 1
+	nop
+	mulld	r8, r5, r5	C weight 0
+	mulhdu	r9, r5, r5	C weight 1
+	std	r8, 0(rp)
+	std	r9, 8(rp)
+	blr
+	ALIGN(16)
+L(ge2):	bgt	cr0, L(gt2)
+	ld	r0, 0(up)	C n = 2
+	nop
+	mulld	r8, r0, r0	C u0 * u0
+	mulhdu	r9, r0, r0	C u0 * u0
+	ld	r6, 8(up)
+	mulld	r10, r6, r6	C u1 * u1
+	mulhdu	r11, r6, r6	C u1 * u1
+	mulld	r4, r6, r0	C u1 * u0
+	mulhdu	r5, r6, r0	C u1 * u0
+	addc	r4, r4, r4
+	adde	r5, r5, r5
+	addze	r11, r11
+	addc	r9, r9, r4
+	adde	r10, r10, r5
+	addze	r11, r11
+	std	r8, 0(rp)
+	std	r9, 8(rp)
+	std	r10, 16(rp)
+	std	r11, 24(rp)
+	blr
+
+	ALIGN(16)
+L(gt2):	std	r31,  -8(r1)
+	std	r30, -16(r1)
+	std	r29, -24(r1)
+	std	r28, -32(r1)
+	std	r27, -40(r1)
+	std	r26, -48(r1)
+	std	r25, -56(r1)
+	std	r24, -64(r1)
+	std	r23, -72(r1)
+	std	r22, -80(r1)
+	std	r21, -88(r1)
+
+	mr	rp_saved, rp
+	mr	up_saved, up
+	mr	n_saved, n
+	mr	rp_outer, rp
+	mr	up_outer, up
+
+	rldicl.	r0, n, 0,62	C r0 = n & 3, set cr0
+	cmpdi	cr6, r0, 2
+	addic	r7, n, 2	C compute count...
+	srdi	r7, r7, 2	C ...for ctr
+	mtctr	r7		C copy count into ctr
+	beq-	cr0, L(b0)
+	blt-	cr6, L(b1)
+	beq-	cr6, L(b2)
+
+L(b3):	ld	r6, 0(up)
+	ld	r9, 8(up)
+	ld	r27, 16(up)
+	addi	up, up, 24
+	li	r12, 0		C carry limb
+	bdz	L(em3)
+
+	ALIGN(16)
+L(tm3):	mulld	r0, r9, r6
+	mulhdu	r26, r9, r6
+	mulld	r7, r27, r6
+	mulhdu	r8, r27, r6
+	ld	r9, 0(up)
+	ld	r27, 8(up)
+	adde	r0, r0, r12
+	adde	r7, r7, r26
+	mulld	r26, r9, r6
+	mulhdu	r10, r9, r6
+	mulld	r11, r27, r6
+	mulhdu	r12, r27, r6
+	ld	r9, 16(up)
+	ld	r27, 24(up)
+	std	r0, 8(rp)
+	adde	r26, r26, r8
+	std	r7, 16(rp)
+	adde	r11, r11, r10
+	std	r26, 24(rp)
+	addi	up, up, 32
+	std	r11, 32(rp)
+	addi	rp, rp, 32
+	bdnz	L(tm3)
+
+L(em3):	mulld	r0, r9, r6
+	mulhdu	r26, r9, r6
+	mulld	r7, r27, r6
+	mulhdu	r8, r27, r6
+	adde	r0, r0, r12
+	adde	r7, r7, r26
+	std	r0, 8(rp)
+	std	r7, 16(rp)
+	addze	r8, r8
+	std	r8, 24(rp)
+	addi	n, n, 2
+	b	L(outer_loop)
+
+L(b0):	ld	r6, 0(up)
+	ld	r27, 8(up)
+	mulld	r7, r27, r6
+	mulhdu	r12, r27, r6
+	std	r7, 8(rp)
+	addi	rp, rp, 8
+	ld	r9, 16(up)
+	ld	r27, 24(up)
+	addi	up, up, 32
+	bdz	L(em0)
+
+	ALIGN(16)
+L(tm0):	mulld	r0, r9, r6
+	mulhdu	r26, r9, r6
+	mulld	r7, r27, r6
+	mulhdu	r8, r27, r6
+	ld	r9, 0(up)
+	ld	r27, 8(up)
+	adde	r0, r0, r12
+	adde	r7, r7, r26
+	mulld	r26, r9, r6
+	mulhdu	r10, r9, r6
+	mulld	r11, r27, r6
+	mulhdu	r12, r27, r6
+	ld	r9, 16(up)
+	ld	r27, 24(up)
+	std	r0, 8(rp)
+	adde	r26, r26, r8
+	std	r7, 16(rp)
+	adde	r11, r11, r10
+	std	r26, 24(rp)
+	addi	up, up, 32
+	std	r11, 32(rp)
+	addi	rp, rp, 32
+	bdnz	L(tm0)
+
+L(em0):	mulld	r0, r9, r6
+	mulhdu	r26, r9, r6
+	mulld	r7, r27, r6
+	mulhdu	r8, r27, r6
+	adde	r0, r0, r12
+	adde	r7, r7, r26
+	std	r0, 8(rp)
+	std	r7, 16(rp)
+	addze	r8, r8
+	std	r8, 24(rp)
+	addi	n, n, 2
+	b	L(outer_loop_ent_2)
+
+L(b1):	ld	r6, 0(up)
+	ld	r9, 8(up)
+	ld	r27, 16(up)
+	mulld	r0, r9, r6
+	mulhdu	r26, r9, r6
+	mulld	r7, r27, r6
+	mulhdu	r12, r27, r6
+	addc	r7, r7, r26
+	std	r0, 8(rp)
+	std	r7, 16(rp)
+	addi	rp, rp, 16
+	ld	r9, 24(up)
+	ld	r27, 32(up)
+	addi	up, up, 40
+	bdz	L(em1)
+
+	ALIGN(16)
+L(tm1):	mulld	r0, r9, r6
+	mulhdu	r26, r9, r6
+	mulld	r7, r27, r6
+	mulhdu	r8, r27, r6
+	ld	r9, 0(up)
+	ld	r27, 8(up)
+	adde	r0, r0, r12
+	adde	r7, r7, r26
+	mulld	r26, r9, r6
+	mulhdu	r10, r9, r6
+	mulld	r11, r27, r6
+	mulhdu	r12, r27, r6
+	ld	r9, 16(up)
+	ld	r27, 24(up)
+	std	r0, 8(rp)
+	adde	r26, r26, r8
+	std	r7, 16(rp)
+	adde	r11, r11, r10
+	std	r26, 24(rp)
+	addi	up, up, 32
+	std	r11, 32(rp)
+	addi	rp, rp, 32
+	bdnz	L(tm1)
+
+L(em1):	mulld	r0, r9, r6
+	mulhdu	r26, r9, r6
+	mulld	r7, r27, r6
+	mulhdu	r8, r27, r6
+	adde	r0, r0, r12
+	adde	r7, r7, r26
+	std	r0, 8(rp)
+	std	r7, 16(rp)
+	addze	r8, r8
+	std	r8, 24(rp)
+	addi	n, n, 2
+	b	L(outer_loop_ent_3)
+
+L(b2):	addi	r7, r7, -1	C FIXME
+	mtctr	r7		C FIXME
+	ld	r6, 0(up)
+	ld	r9, 8(up)
+	ld	r27, 16(up)
+	mulld	r0, r9, r6
+	mulhdu	r26, r9, r6
+	mulld	r7, r27, r6
+	mulhdu	r8, r27, r6
+	ld	r9, 24(up)
+	mulld	r11, r9, r6
+	mulhdu	r10, r9, r6
+	addc	r7, r7, r26
+	adde	r11, r11, r8
+	addze	r12, r10
+	std	r0, 8(rp)
+	std	r7, 16(rp)
+	std	r11, 24(rp)
+	addi	rp, rp, 24
+	ld	r9, 32(up)
+	ld	r27, 40(up)
+	addi	up, up, 48
+	bdz	L(em2)
+
+	ALIGN(16)
+L(tm2):	mulld	r0, r9, r6
+	mulhdu	r26, r9, r6
+	mulld	r7, r27, r6
+	mulhdu	r8, r27, r6
+	ld	r9, 0(up)
+	ld	r27, 8(up)
+	adde	r0, r0, r12
+	adde	r7, r7, r26
+	mulld	r26, r9, r6
+	mulhdu	r10, r9, r6
+	mulld	r11, r27, r6
+	mulhdu	r12, r27, r6
+	ld	r9, 16(up)
+	ld	r27, 24(up)
+	std	r0, 8(rp)
+	adde	r26, r26, r8
+	std	r7, 16(rp)
+	adde	r11, r11, r10
+	std	r26, 24(rp)
+	addi	up, up, 32
+	std	r11, 32(rp)
+	addi	rp, rp, 32
+	bdnz	L(tm2)
+
+L(em2):	mulld	r0, r9, r6
+	mulhdu	r26, r9, r6
+	mulld	r7, r27, r6
+	mulhdu	r8, r27, r6
+	adde	r0, r0, r12
+	adde	r7, r7, r26
+	std	r0, 8(rp)
+	std	r7, 16(rp)
+	addze	r8, r8
+	std	r8, 24(rp)
+	addi	n, n, 2
+	b	L(outer_loop_ent_0)
+
+
+L(outer_loop):
+	addi	n, n, -1
+	addi	up_outer, up_outer, 8
+	addi	rp_outer, rp_outer, 16
+
+	mr	up, up_outer
+	addi	rp, rp_outer, 8
+
+	srdi	r0, n, 2
+	mtctr	r0
+
+	bdz	L(outer_end)
+
+	ld	r6, 0(up)
+	ld	r9, 8(up)
+	ld	r27, 16(up)
+	mulld	r0, r9, r6
+	mulhdu	r26, r9, r6
+	mulld	r7, r27, r6
+	mulhdu	r8, r27, r6
+	ld	r9, 24(up)
+	ld	r28, 0(rp)
+	ld	r29, 8(rp)
+	ld	r30, 16(rp)
+	mulld	r11, r9, r6
+	mulhdu	r10, r9, r6
+	addc	r7, r7, r26
+	adde	r11, r11, r8
+	addze	r12, r10
+	addc	r0, r0, r28
+	std	r0, 0(rp)
+	adde	r7, r7, r29
+	std	r7, 8(rp)
+	adde	r11, r11, r30
+	std	r11, 16(rp)
+	addi	rp, rp, 24
+	ld	r9, 32(up)
+	ld	r27, 40(up)
+	addi	up, up, 48
+	bdz	L(ea1)
+
+	ALIGN(16)
+L(ta1):	mulld	r0, r9, r6
+	mulhdu	r26, r9, r6	C 9
+	mulld	r7, r27, r6
+	mulhdu	r8, r27, r6	C 27
+	ld	r9, 0(up)
+	ld	r28, 0(rp)
+	ld	r27, 8(up)
+	ld	r29, 8(rp)
+	adde	r0, r0, r12	C 0 12
+	adde	r7, r7, r26	C 5 7
+	mulld	r26, r9, r6
+	mulhdu	r10, r9, r6	C 9
+	mulld	r11, r27, r6
+	mulhdu	r12, r27, r6	C 27
+	ld	r9, 16(up)
+	ld	r30, 16(rp)
+	ld	r27, 24(up)
+	ld	r31, 24(rp)
+	adde	r26, r26, r8	C 8 5
+	adde	r11, r11, r10	C 10 11
+	addze	r12, r12	C 12
+	addc	r0, r0, r28	C 0 28
+	std	r0, 0(rp)	C 0
+	adde	r7, r7, r29	C 7 29
+	std	r7, 8(rp)	C 7
+	adde	r26, r26, r30	C 5 30
+	std	r26, 16(rp)	C 5
+	adde	r11, r11, r31	C 11 31
+	std	r11, 24(rp)	C 11
+	addi	up, up, 32
+	addi	rp, rp, 32
+	bdnz	L(ta1)
+
+L(ea1):	mulld	r0, r9, r6
+	mulhdu	r26, r9, r6
+	mulld	r7, r27, r6
+	mulhdu	r8, r27, r6
+	ld	r28, 0(rp)
+	ld	r29, 8(rp)
+	adde	r0, r0, r12
+	adde	r7, r7, r26
+	addze	r8, r8
+	addc	r0, r0, r28
+	std	r0, 0(rp)
+	adde	r7, r7, r29
+	std	r7, 8(rp)
+	addze	r8, r8
+	std	r8, 16(rp)
+
+L(outer_loop_ent_0):
+	addi	n, n, -1
+	addi	up_outer, up_outer, 8
+	addi	rp_outer, rp_outer, 16
+
+	mr	up, up_outer
+	addi	rp, rp_outer, 8
+
+	srdi	r0, n, 2
+	mtctr	r0
+
+	ld	r6, 0(up)
+	ld	r9, 8(up)
+	ld	r27, 16(up)
+	ld	r28, 0(rp)
+	ld	r29, 8(rp)
+	mulld	r0, r9, r6
+	mulhdu	r26, r9, r6
+	mulld	r7, r27, r6
+	mulhdu	r8, r27, r6
+	addc	r0, r0, r28
+	adde	r7, r7, r26
+	addze	r12, r8
+	std	r0, 0(rp)
+	adde	r7, r7, r29
+	std	r7, 8(rp)
+	addi	rp, rp, 16
+	ld	r9, 24(up)
+	ld	r27, 32(up)
+	addi	up, up, 40
+	bdz	L(ea0)
+
+	ALIGN(16)
+L(ta0):	mulld	r0, r9, r6
+	mulhdu	r26, r9, r6	C 9
+	mulld	r7, r27, r6
+	mulhdu	r8, r27, r6	C 27
+	ld	r9, 0(up)
+	ld	r28, 0(rp)
+	ld	r27, 8(up)
+	ld	r29, 8(rp)
+	adde	r0, r0, r12	C 0 12
+	adde	r7, r7, r26	C 5 7
+	mulld	r26, r9, r6
+	mulhdu	r10, r9, r6	C 9
+	mulld	r11, r27, r6
+	mulhdu	r12, r27, r6	C 27
+	ld	r9, 16(up)
+	ld	r30, 16(rp)
+	ld	r27, 24(up)
+	ld	r31, 24(rp)
+	adde	r26, r26, r8	C 8 5
+	adde	r11, r11, r10	C 10 11
+	addze	r12, r12	C 12
+	addc	r0, r0, r28	C 0 28
+	std	r0, 0(rp)	C 0
+	adde	r7, r7, r29	C 7 29
+	std	r7, 8(rp)	C 7
+	adde	r26, r26, r30	C 5 30
+	std	r26, 16(rp)	C 5
+	adde	r11, r11, r31	C 11 31
+	std	r11, 24(rp)	C 11
+	addi	up, up, 32
+	addi	rp, rp, 32
+	bdnz	L(ta0)
+
+L(ea0):	mulld	r0, r9, r6
+	mulhdu	r26, r9, r6
+	mulld	r7, r27, r6
+	mulhdu	r8, r27, r6
+	ld	r28, 0(rp)
+	ld	r29, 8(rp)
+	adde	r0, r0, r12
+	adde	r7, r7, r26
+	addze	r8, r8
+	addc	r0, r0, r28
+	std	r0, 0(rp)
+	adde	r7, r7, r29
+	std	r7, 8(rp)
+	addze	r8, r8
+	std	r8, 16(rp)
+
+L(outer_loop_ent_3):
+	addi	n, n, -1
+	addi	up_outer, up_outer, 8
+	addi	rp_outer, rp_outer, 16
+
+	mr	up, up_outer
+	addi	rp, rp_outer, 8
+
+	srdi	r0, n, 2
+	mtctr	r0
+
+	ld	r6, 0(up)
+	ld	r9, 8(up)
+	ld	r28, 0(rp)
+	mulld	r0, r9, r6
+	mulhdu	r12, r9, r6
+	addc	r0, r0, r28
+	std	r0, 0(rp)
+	addi	rp, rp, 8
+	ld	r9, 16(up)
+	ld	r27, 24(up)
+	addi	up, up, 32
+	bdz	L(ea3)
+
+	ALIGN(16)
+L(ta3):	mulld	r0, r9, r6
+	mulhdu	r26, r9, r6	C 9
+	mulld	r7, r27, r6
+	mulhdu	r8, r27, r6	C 27
+	ld	r9, 0(up)
+	ld	r28, 0(rp)
+	ld	r27, 8(up)
+	ld	r29, 8(rp)
+	adde	r0, r0, r12	C 0 12
+	adde	r7, r7, r26	C 5 7
+	mulld	r26, r9, r6
+	mulhdu	r10, r9, r6	C 9
+	mulld	r11, r27, r6
+	mulhdu	r12, r27, r6	C 27
+	ld	r9, 16(up)
+	ld	r30, 16(rp)
+	ld	r27, 24(up)
+	ld	r31, 24(rp)
+	adde	r26, r26, r8	C 8 5
+	adde	r11, r11, r10	C 10 11
+	addze	r12, r12	C 12
+	addc	r0, r0, r28	C 0 28
+	std	r0, 0(rp)	C 0
+	adde	r7, r7, r29	C 7 29
+	std	r7, 8(rp)	C 7
+	adde	r26, r26, r30	C 5 30
+	std	r26, 16(rp)	C 5
+	adde	r11, r11, r31	C 11 31
+	std	r11, 24(rp)	C 11
+	addi	up, up, 32
+	addi	rp, rp, 32
+	bdnz	L(ta3)
+
+L(ea3):	mulld	r0, r9, r6
+	mulhdu	r26, r9, r6
+	mulld	r7, r27, r6
+	mulhdu	r8, r27, r6
+	ld	r28, 0(rp)
+	ld	r29, 8(rp)
+	adde	r0, r0, r12
+	adde	r7, r7, r26
+	addze	r8, r8
+	addc	r0, r0, r28
+	std	r0, 0(rp)
+	adde	r7, r7, r29
+	std	r7, 8(rp)
+	addze	r8, r8
+	std	r8, 16(rp)
+
+
+L(outer_loop_ent_2):
+	addi	n, n, -1
+	addi	up_outer, up_outer, 8
+	addi	rp_outer, rp_outer, 16
+
+	mr	up, up_outer
+	addi	rp, rp_outer, 8
+
+	srdi	r0, n, 2
+	mtctr	r0
+
+	addic	r0, r0, 0
+	li	r12, 0		C cy_limb = 0
+	ld	r6, 0(up)
+	ld	r9, 8(up)
+	ld	r27, 16(up)
+	bdz	L(ea2)
+	addi	up, up, 24
+
+	ALIGN(16)
+L(ta2):	mulld	r0, r9, r6
+	mulhdu	r26, r9, r6	C 9
+	mulld	r7, r27, r6
+	mulhdu	r8, r27, r6	C 27
+	ld	r9, 0(up)
+	ld	r28, 0(rp)
+	ld	r27, 8(up)
+	ld	r29, 8(rp)
+	adde	r0, r0, r12	C 0 12
+	adde	r7, r7, r26	C 5 7
+	mulld	r26, r9, r6
+	mulhdu	r10, r9, r6	C 9
+	mulld	r11, r27, r6
+	mulhdu	r12, r27, r6	C 27
+	ld	r9, 16(up)
+	ld	r30, 16(rp)
+	ld	r27, 24(up)
+	ld	r31, 24(rp)
+	adde	r26, r26, r8	C 8 5
+	adde	r11, r11, r10	C 10 11
+	addze	r12, r12	C 12
+	addc	r0, r0, r28	C 0 28
+	std	r0, 0(rp)	C 0
+	adde	r7, r7, r29	C 7 29
+	std	r7, 8(rp)	C 7
+	adde	r26, r26, r30	C 5 30
+	std	r26, 16(rp)	C 5
+	adde	r11, r11, r31	C 11 31
+	std	r11, 24(rp)	C 11
+	addi	up, up, 32
+	addi	rp, rp, 32
+	bdnz	L(ta2)
+
+L(ea2):	mulld	r0, r9, r6
+	mulhdu	r26, r9, r6
+	mulld	r7, r27, r6
+	mulhdu	r8, r27, r6
+	ld	r28, 0(rp)
+	ld	r29, 8(rp)
+	adde	r0, r0, r12
+	adde	r7, r7, r26
+	addze	r8, r8
+	addc	r0, r0, r28
+	std	r0, 0(rp)
+	adde	r7, r7, r29
+	std	r7, 8(rp)
+	addze	r8, r8
+	std	r8, 16(rp)
+
+	b	L(outer_loop)
+
+L(outer_end):
+	ld	r6, 0(up)
+	ld	r9, 8(up)
+	ld	r11, 0(rp)
+	mulld	r0, r9, r6
+	mulhdu	r8, r9, r6
+	addc	r0, r0, r11
+	std	r0, 0(rp)
+	addze	r8, r8
+	std	r8, 8(rp)
+
+define(`rp',  `rp_saved')
+define(`up',  `r5')
+define(`n',   `r6')
+define(`climb',	`r0')
+
+	addi	r4, rp_saved, 8
+	mr	r5, up_saved
+	mr	r6, n_saved
+
+	rldicl.	r0, n, 0,62		C r0 = n & 3, set cr0
+	cmpdi	cr6, r0, 2
+	addi	n, n, 2			C compute count...
+	srdi	n, n, 2			C ...for ctr
+	mtctr	n			C put loop count into ctr
+	beq	cr0, L(xb0)
+	blt	cr6, L(xb1)
+	beq	cr6, L(xb2)
+
+L(xb3):	ld	r6,   0(up)
+	ld	r7,   8(up)
+	ld	r12, 16(up)
+	addi	up, up, 24
+	mulld	r24, r6, r6
+	mulhdu	r25, r6, r6
+	mulld	r26, r7, r7
+	mulhdu	r27, r7, r7
+	mulld	r28, r12, r12
+	mulhdu	r29, r12, r12
+	ld	r10,  8(rp)
+	ld	r11, 16(rp)
+	ld	r6,  24(rp)
+	ld	r7,  32(rp)
+	addc	r10, r10, r10
+	adde	r11, r11, r11
+	adde	r6, r6, r6
+	adde	r7, r7, r7
+	addze	climb, r29
+	addc	r10, r10, r25
+	adde	r11, r11, r26
+	adde	r6, r6, r27
+	adde	r7, r7, r28
+	std	r24,  0(rp)
+	std	r10,  8(rp)
+	std	r11, 16(rp)
+	std	r6,  24(rp)
+	std	r7,  32(rp)
+	addi	rp, rp, 40
+	bdnz	L(top)
+	b	L(end)
+
+L(xb2):	ld	r6,  0(up)
+	ld	r7,  8(up)
+	addi	up, up, 16
+	mulld	r24, r6, r6
+	mulhdu	r25, r6, r6
+	mulld	r26, r7, r7
+	mulhdu	r27, r7, r7
+	ld	r10,  8(rp)
+	ld	r11, 16(rp)
+	addc	r10, r10, r10
+	adde	r11, r11, r11
+	addze	climb, r27
+	addc	r10, r10, r25
+	adde	r11, r11, r26
+	std	r24,  0(rp)
+	std	r10,  8(rp)
+	std	r11, 16(rp)
+	addi	rp, rp, 24
+	bdnz	L(top)
+	b	L(end)
+
+L(xb0):	ld	r6,   0(up)
+	ld	r7,   8(up)
+	ld	r12, 16(up)
+	ld	r23, 24(up)
+	addi	up, up, 32
+	mulld	r24, r6, r6
+	mulhdu	r25, r6, r6
+	mulld	r26, r7, r7
+	mulhdu	r27, r7, r7
+	mulld	r28, r12, r12
+	mulhdu	r29, r12, r12
+	mulld	r30, r23, r23
+	mulhdu	r31, r23, r23
+	ld	r10,  8(rp)
+	ld	r11, 16(rp)
+	ld	r6,  24(rp)
+	ld	r7,  32(rp)
+	ld	r12, 40(rp)
+	ld	r23, 48(rp)
+	addc	r10, r10, r10
+	adde	r11, r11, r11
+	adde	r6, r6, r6
+	adde	r7, r7, r7
+	adde	r12, r12, r12
+	adde	r23, r23, r23
+	addze	climb, r31
+	std	r24,  0(rp)
+	addc	r10, r10, r25
+	std	r10,  8(rp)
+	adde	r11, r11, r26
+	std	r11, 16(rp)
+	adde	r6, r6, r27
+	std	r6,  24(rp)
+	adde	r7, r7, r28
+	std	r7,  32(rp)
+	adde	r12, r12, r29
+	std	r12, 40(rp)
+	adde	r23, r23, r30
+	std	r23, 48(rp)
+	addi	rp, rp, 56
+	bdnz	L(top)
+	b	L(end)
+
+L(xb1):	ld	r6,  0(up)
+	addi	up, up, 8
+	mulld	r24, r6, r6
+	mulhdu	climb, r6, r6
+	std	r24, 0(rp)
+	addic	rp, rp, 8		C clear carry as side-effect
+
+	ALIGN(32)
+L(top):	ld	r6,   0(up)
+	ld	r7,   8(up)
+	ld	r12, 16(up)
+	ld	r23, 24(up)
+	addi	up, up, 32
+	mulld	r24, r6, r6
+	mulhdu	r25, r6, r6
+	mulld	r26, r7, r7
+	mulhdu	r27, r7, r7
+	mulld	r28, r12, r12
+	mulhdu	r29, r12, r12
+	mulld	r30, r23, r23
+	mulhdu	r31, r23, r23
+	ld	r8,   0(rp)
+	ld	r9,   8(rp)
+	adde	r8, r8, r8
+	adde	r9, r9, r9
+	ld	r10, 16(rp)
+	ld	r11, 24(rp)
+	adde	r10, r10, r10
+	adde	r11, r11, r11
+	ld	r6,  32(rp)
+	ld	r7,  40(rp)
+	adde	r6, r6, r6
+	adde	r7, r7, r7
+	ld	r12, 48(rp)
+	ld	r23, 56(rp)
+	adde	r12, r12, r12
+	adde	r23, r23, r23
+	addze	r31, r31
+	addc	r8, r8, climb
+	std	r8,   0(rp)
+	adde	r9, r9, r24
+	std	r9,   8(rp)
+	adde	r10, r10, r25
+	std	r10, 16(rp)
+	adde	r11, r11, r26
+	std	r11, 24(rp)
+	adde	r6, r6, r27
+	std	r6,  32(rp)
+	adde	r7, r7, r28
+	std	r7,  40(rp)
+	adde	r12, r12, r29
+	std	r12, 48(rp)
+	adde	r23, r23, r30
+	std	r23, 56(rp)
+	mr	climb, r31
+	addi	rp, rp, 64
+	bdnz	L(top)
+
+L(end):	addze	climb, climb
+	std	climb,  0(rp)
+
+	ld	r31,  -8(r1)
+	ld	r30, -16(r1)
+	ld	r29, -24(r1)
+	ld	r28, -32(r1)
+	ld	r27, -40(r1)
+	ld	r26, -48(r1)
+	ld	r25, -56(r1)
+	ld	r24, -64(r1)
+	ld	r23, -72(r1)
+	ld	r22, -80(r1)
+	ld	r21, -88(r1)
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc64/p6/lshift.asm b/third_party/gmp/mpn/powerpc64/p6/lshift.asm
new file mode 100644
index 0000000..1a200fb
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/p6/lshift.asm
@@ -0,0 +1,132 @@
+dnl  PowerPC-64 mpn_lshift -- rp[] = up[] << cnt
+
+dnl  Copyright 2003, 2005, 2010, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		    cycles/limb
+C POWER3/PPC630		 ?
+C POWER4/PPC970		 ?
+C POWER5		 2.25
+C POWER6		 4
+
+C TODO
+C  * Micro-optimise header code
+C  * Perhaps do 4-way unrolling, for 2.5 c/l on POWER6.  The code is 4236
+C    bytes, 4-way code would become about 50% larger.
+
+C INPUT PARAMETERS
+define(`rp_param',  `r3')
+define(`up',  `r4')
+define(`n',   `r5')
+define(`cnt', `r6')
+
+define(`tnc',`r0')
+define(`retval',`r3')
+define(`rp',  `r7')
+
+ASM_START()
+PROLOGUE(mpn_lshift,toc)
+
+ifdef(`HAVE_ABI_mode32',`
+	rldicl	n, n, 0,32		C FIXME: avoid this zero extend
+')
+	mflr	r12
+	sldi	r8, n, 3
+	sldi	r10, cnt, 6		C multiply cnt by size of a SHIFT block
+	LEAL(	r11, L(e1))		C address of L(e1) label in SHIFT(1)
+	add	up, up, r8		C make up point at end of up[]
+	add	r11, r11, r10		C address of L(oN) for N = cnt
+	srdi	r10, n, 1
+	add	rp, rp_param, r8	C make rp point at end of rp[]
+	subfic	tnc, cnt, 64
+	rlwinm.	r8, n, 0,31,31		C extract bit 0
+	mtctr	r10
+	beq	L(evn)
+
+L(odd):	ld	r9, -8(up)
+	cmpdi	cr0, n, 1		C n = 1?
+	beq	L(1)
+	ld	r8, -16(up)
+	addi	r11, r11, -84		C L(o1) - L(e1) - 64
+	mtlr	r11
+	srd	r3, r9, tnc		C retval
+	addi	up, up, 8
+	addi	rp, rp, -8
+	blr				C branch to L(oN)
+
+L(evn):	ld	r8, -8(up)
+	ld	r9, -16(up)
+	addi	r11, r11, -64
+	mtlr	r11
+	srd	r3, r8, tnc		C retval
+	blr				C branch to L(eN)
+
+L(1):	srd	r3, r9, tnc		C retval
+	sld	r8, r9, cnt
+	std	r8, -8(rp)
+	mtlr	r12
+ifdef(`HAVE_ABI_mode32',
+`	mr	r4, r3
+	srdi	r3, r3, 32
+')
+	blr
+
+
+define(SHIFT,`
+L(lo$1):ld	r8, -24(up)
+	std	r11, -8(rp)
+	addi	rp, rp, -16
+L(o$1):	srdi	r10, r8, eval(64-$1)
+	rldimi	r10, r9, $1, 0
+	ld	r9, -32(up)
+	addi	up, up, -16
+	std	r10, 0(rp)
+L(e$1):	srdi	r11, r9, eval(64-$1)
+	rldimi	r11, r8, $1, 0
+	bdnz	L(lo$1)
+	std	r11, -8(rp)
+	sldi	r10, r9, $1
+	b	L(com)
+	nop
+	nop
+')
+
+	ALIGN(64)
+forloop(`i',1,63,`SHIFT(i)')
+
+L(com):	std	r10, -16(rp)
+	mtlr	r12
+ifdef(`HAVE_ABI_mode32',
+`	mr	r4, r3
+	srdi	r3, r3, 32
+')
+	blr
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/powerpc64/p6/lshiftc.asm b/third_party/gmp/mpn/powerpc64/p6/lshiftc.asm
new file mode 100644
index 0000000..e4b3caa
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/p6/lshiftc.asm
@@ -0,0 +1,136 @@
+dnl  PowerPC-64 mpn_lshiftc -- rp[] = ~up[] << cnt
+
+dnl  Copyright 2003, 2005, 2010, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		    cycles/limb
+C POWER3/PPC630		 ?
+C POWER4/PPC970		 ?
+C POWER5		 2.25
+C POWER6		 4
+
+C TODO
+C  * Micro-optimise header code
+C  * Perhaps do 4-way unrolling, for 2.5 c/l on POWER6.  The code is 4236
+C    bytes, 4-way code would become about 50% larger.
+
+C INPUT PARAMETERS
+define(`rp_param',  `r3')
+define(`up',  `r4')
+define(`n',   `r5')
+define(`cnt', `r6')
+
+define(`tnc',`r0')
+define(`retval',`r3')
+define(`rp',  `r7')
+
+ASM_START()
+PROLOGUE(mpn_lshiftc,toc)
+
+ifdef(`HAVE_ABI_mode32',`
+	rldicl	n, n, 0,32		C FIXME: avoid this zero extend
+')
+	mflr	r12
+	sldi	r8, n, 3
+	sldi	r10, cnt, 6		C multiply cnt by size of a SHIFT block
+	LEAL(	r11, L(e1))		C address of L(e1) label in SHIFT(1)
+	add	up, up, r8		C make up point at end of up[]
+	add	r11, r11, r10		C address of L(oN) for N = cnt
+	srdi	r10, n, 1
+	add	rp, rp_param, r8	C make rp point at end of rp[]
+	subfic	tnc, cnt, 64
+	rlwinm.	r8, n, 0,31,31		C extract bit 0
+	mtctr	r10
+	beq	L(evn)
+
+L(odd):	ld	r9, -8(up)
+	cmpdi	cr0, n, 1		C n = 1?
+	beq	L(1)
+	ld	r8, -16(up)
+	addi	r11, r11, -88		C L(o1) - L(e1) - 64
+	mtlr	r11
+	srd	r3, r9, tnc		C retval
+	addi	up, up, 8
+	addi	rp, rp, -8
+	blr				C branch to L(oN)
+
+L(evn):	ld	r8, -8(up)
+	ld	r9, -16(up)
+	addi	r11, r11, -64
+	mtlr	r11
+	srd	r3, r8, tnc		C retval
+	blr				C branch to L(eN)
+
+L(1):	srd	r3, r9, tnc		C retval
+	sld	r8, r9, cnt
+	nor	r8, r8, r8
+	std	r8, -8(rp)
+	mtlr	r12
+ifdef(`HAVE_ABI_mode32',
+`	mr	r4, r3
+	srdi	r3, r3, 32
+')
+	blr
+
+
+define(SHIFT,`
+L(lo$1):ld	r8, -24(up)
+	nor	r11, r11, r11
+	std	r11, -8(rp)
+	addi	rp, rp, -16
+L(o$1):	srdi	r10, r8, eval(64-$1)
+	rldimi	r10, r9, $1, 0
+	ld	r9, -32(up)
+	addi	up, up, -16
+	nor	r10, r10, r10
+	std	r10, 0(rp)
+L(e$1):	srdi	r11, r9, eval(64-$1)
+	rldimi	r11, r8, $1, 0
+	bdnz	L(lo$1)
+	sldi	r10, r9, $1
+	b	L(com)
+	nop
+')
+
+	ALIGN(64)
+forloop(`i',1,63,`SHIFT(i)')
+
+L(com):	nor	r11, r11, r11
+	nor	r10, r10, r10
+	std	r11, -8(rp)
+	std	r10, -16(rp)
+	mtlr	r12
+ifdef(`HAVE_ABI_mode32',
+`	mr	r4, r3
+	srdi	r3, r3, 32
+')
+	blr
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/powerpc64/p6/rshift.asm b/third_party/gmp/mpn/powerpc64/p6/rshift.asm
new file mode 100644
index 0000000..9e848c1
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/p6/rshift.asm
@@ -0,0 +1,131 @@
+dnl  PowerPC-64 mpn_rshift -- rp[] = up[] << cnt
+
+dnl  Copyright 2003, 2005, 2010, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		    cycles/limb
+C POWER3/PPC630		 ?
+C POWER4/PPC970		 ?
+C POWER5		 2
+C POWER6		 3.5  (mysteriously 3.0 for cnt=1)
+
+C TODO
+C  * Micro-optimise header code
+C  * Perhaps do 4-way unrolling, for 2.5 c/l on POWER6.  The code is 4248
+C    bytes, 4-way code would become about 50% larger.
+
+C INPUT PARAMETERS
+define(`rp_param',  `r3')
+define(`up',  `r4')
+define(`n',   `r5')
+define(`cnt', `r6')
+
+define(`tnc',`r0')
+define(`retval',`r3')
+define(`rp',  `r7')
+
+ASM_START()
+PROLOGUE(mpn_rshift,toc)
+
+ifdef(`HAVE_ABI_mode32',`
+	rldicl	n, n, 0,32		C FIXME: avoid this zero extend
+')
+	mflr	r12
+	LEAL(	r11, L(e1))		C address of L(e1) label in SHIFT(1)
+	sldi	r10, cnt, 6		C multiply cnt by size of a SHIFT block
+	add	r11, r11, r10		C address of L(oN) for N = cnt
+	srdi	r10, n, 1
+	mr	rp, rp_param
+	subfic	tnc, cnt, 64
+	rlwinm.	r8, n, 0,31,31		C extract bit 0
+	mtctr	r10
+	beq	L(evn)
+
+L(odd):	ld	r9, 0(up)
+	cmpdi	cr0, n, 1		C n = 1?
+	beq	L(1)
+	ld	r8, 8(up)
+	addi	r11, r11, -84		C L(o1) - L(e1) - 64
+	mtlr	r11
+	sld	r3, r9, tnc		C retval
+	addi	up, up, 8
+	addi	rp, rp, 8
+	blr				C branch to L(oN)
+
+L(evn):	ld	r8, 0(up)
+	ld	r9, 8(up)
+	addi	r11, r11, -64
+	mtlr	r11
+	sld	r3, r8, tnc		C retval
+	addi	up, up, 16
+	blr				C branch to L(eN)
+
+L(1):	sld	r3, r9, tnc		C retval
+	srd	r8, r9, cnt
+	std	r8, 0(rp)
+	mtlr	r12
+ifdef(`HAVE_ABI_mode32',
+`	mr	r4, r3
+	srdi	r3, r3, 32
+')
+	blr
+
+
+define(SHIFT,`
+L(lo$1):ld	r8, 0(up)
+	std	r11, 0(rp)
+	addi	rp, rp, 16
+L(o$1):	srdi	r10, r9, $1
+	rldimi	r10, r8, eval(64-$1), 0
+	ld	r9, 8(up)
+	addi	up, up, 16
+	std	r10, -8(rp)
+L(e$1):	srdi	r11, r8, $1
+	rldimi	r11, r9, eval(64-$1), 0
+	bdnz	L(lo$1)
+	std	r11, 0(rp)
+	srdi	r10, r9, $1
+	b	L(com)
+	nop
+	nop
+')
+
+	ALIGN(64)
+forloop(`i',1,63,`SHIFT(i)')
+
+L(com):	std	r10, 8(rp)
+	mtlr	r12
+ifdef(`HAVE_ABI_mode32',
+`	mr	r4, r3
+	srdi	r3, r3, 32
+')
+	blr
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/powerpc64/p7/copyd.asm b/third_party/gmp/mpn/powerpc64/p7/copyd.asm
new file mode 100644
index 0000000..f04ca58
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/p7/copyd.asm
@@ -0,0 +1,128 @@
+dnl  PowerPC-64 mpn_copyd.
+
+dnl  Copyright 2004, 2005, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                  cycles/limb
+C POWER3/PPC630          ?
+C POWER4/PPC970          ?
+C POWER5                 ?
+C POWER6                 1.25
+C POWER7                 1.09
+
+C INPUT PARAMETERS
+define(`rp',	`r3')
+define(`up',	`r4')
+define(`n',	`r5')
+
+ASM_START()
+PROLOGUE(mpn_copyd)
+
+ifdef(`HAVE_ABI_mode32',
+`	rldicl	n, n, 0,32')
+
+	sldi	r0, n, 3
+	add	up, up, r0		C point at u[] end
+	add	rp, rp, r0		C point at r[] end
+
+	cmpdi	cr0, n, 4
+	blt	L(sml)
+
+	addi	r10, n, 4
+	srdi	r10, r10, 3
+	mtctr	r10
+
+	andi.	r0, n, 1
+	rlwinm	r11, n, 0,30,30
+	rlwinm	r12, n, 0,29,29
+	cmpdi	cr6, r11, 0
+	cmpdi	cr7, r12, 0
+
+	beq	cr0, L(xx0)
+L(xx1):	ld	r6, -8(up)
+	addi	up, up, -8
+	std	r6, -8(rp)
+	addi	rp, rp, -8
+
+L(xx0):	bne	cr6, L(x10)
+L(x00):	ld	r6, -8(up)
+	ld	r7, -16(up)
+	bne	cr7, L(100)
+L(000):	addi	rp, rp, 32
+	b	L(lo0)
+L(100):	addi	up, up, 32
+	b	L(lo4)
+L(x10):	ld	r8, -8(up)
+	ld	r9, -16(up)
+	bne	cr7, L(110)
+L(010):	addi	up, up, -16
+	addi	rp, rp, 16
+	b	L(lo2)
+L(110):	addi	up, up, 16
+	addi	rp, rp, 48
+	b	L(lo6)
+
+L(sml):	cmpdi	cr0, n, 0
+	beqlr-	cr0
+	mtctr	n
+L(t):	ld	r6, -8(up)
+	addi	up, up, -8
+	std	r6, -8(rp)
+	addi	rp, rp, -8
+	bdnz	L(t)
+	blr
+
+	ALIGN(32)
+L(top):	std	r6, -8(rp)
+	std	r7, -16(rp)
+L(lo2):	ld	r6, -8(up)
+	ld	r7, -16(up)
+	std	r8, -24(rp)
+	std	r9, -32(rp)
+L(lo0):	ld	r8, -24(up)
+	ld	r9, -32(up)
+	std	r6, -40(rp)
+	std	r7, -48(rp)
+L(lo6):	ld	r6, -40(up)
+	ld	r7, -48(up)
+	std	r8, -56(rp)
+	std	r9, -64(rp)
+	addi	rp, rp, -64
+L(lo4):	ld	r8, -56(up)
+	ld	r9, -64(up)
+	addi	up, up, -64
+	bdnz	L(top)
+
+L(end):	std	r6, -8(rp)
+	std	r7, -16(rp)
+	std	r8, -24(rp)
+	std	r9, -32(rp)
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc64/p7/copyi.asm b/third_party/gmp/mpn/powerpc64/p7/copyi.asm
new file mode 100644
index 0000000..854cf9f
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/p7/copyi.asm
@@ -0,0 +1,129 @@
+dnl  PowerPC-64 mpn_copyi.
+
+dnl  Copyright 2004, 2005, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                  cycles/limb
+C POWER3/PPC630          ?
+C POWER4/PPC970          ?
+C POWER5                 ?
+C POWER6                 1.25
+C POWER7                 1.09
+
+C INPUT PARAMETERS
+define(`rp',	`r3')
+define(`up',	`r4')
+define(`n',	`r5')
+
+C TODO
+C  * Try rolling the two loop leading std to the end, allowing the code to
+C    handle also n = 2.
+C  * Consider using 4 pointers, schedule ptr update early wrt use.
+
+ASM_START()
+PROLOGUE(mpn_copyi)
+
+ifdef(`HAVE_ABI_mode32',
+`	rldicl	n, n, 0,32')
+
+	cmpdi	cr0, n, 4
+	blt	L(sml)
+
+	addi	r10, n, 4
+	srdi	r10, r10, 3
+	mtctr	r10
+
+	andi.	r0, n, 1
+	rlwinm	r11, n, 0,30,30
+	rlwinm	r12, n, 0,29,29
+	cmpdi	cr6, r11, 0
+	cmpdi	cr7, r12, 0
+
+	beq	cr0, L(xx0)
+L(xx1):	ld	r6, 0(up)
+	addi	up, up, 8
+	std	r6, 0(rp)
+	addi	rp, rp, 8
+
+L(xx0):	bne	cr6, L(x10)
+L(x00):	ld	r6, 0(up)
+	ld	r7, 8(up)
+	bne	cr7, L(100)
+L(000):	addi	rp, rp, -32
+	b	L(lo0)
+L(100):	addi	up, up, -32
+	b	L(lo4)
+L(x10):	ld	r8, 0(up)
+	ld	r9, 8(up)
+	bne	cr7, L(110)
+L(010):	addi	up, up, 16
+	addi	rp, rp, -16
+	b	L(lo2)
+L(110):	addi	up, up, -16
+	addi	rp, rp, -48
+	b	L(lo6)
+
+L(sml):	cmpdi	cr0, n, 0
+	beqlr-	cr0
+	mtctr	n
+L(t):	ld	r6, 0(up)
+	addi	up, up, 8
+	std	r6, 0(rp)
+	addi	rp, rp, 8
+	bdnz	L(t)
+	blr
+
+	ALIGN(32)
+L(top):	std	r6, 0(rp)
+	std	r7, 8(rp)
+L(lo2):	ld	r6, 0(up)
+	ld	r7, 8(up)
+	std	r8, 16(rp)
+	std	r9, 24(rp)
+L(lo0):	ld	r8, 16(up)
+	ld	r9, 24(up)
+	std	r6, 32(rp)
+	std	r7, 40(rp)
+L(lo6):	ld	r6, 32(up)
+	ld	r7, 40(up)
+	std	r8, 48(rp)
+	std	r9, 56(rp)
+	addi	rp, rp, 64
+L(lo4):	ld	r8, 48(up)
+	ld	r9, 56(up)
+	addi	up, up, 64
+	bdnz	L(top)
+
+L(end):	std	r6, 0(rp)
+	std	r7, 8(rp)
+	std	r8, 16(rp)
+	std	r9, 24(rp)
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc64/p7/hamdist.asm b/third_party/gmp/mpn/powerpc64/p7/hamdist.asm
new file mode 100644
index 0000000..960b3bc
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/p7/hamdist.asm
@@ -0,0 +1,110 @@
+dnl  PowerPC-64 mpn_hamdist.
+
+dnl  Copyright 2012, 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                   cycles/limb
+C POWER3/PPC630          -
+C POWER4/PPC970          -
+C POWER5                 -
+C POWER6                 -
+C POWER7                 2.87
+
+define(`up', r3)
+define(`vp', r4)
+define(`n',  r5)
+
+ASM_START()
+PROLOGUE(mpn_hamdist)
+	std	r30, -16(r1)
+	std	r31, -8(r1)
+
+	addi	r0, n, 1
+ifdef(`HAVE_ABI_mode32',
+`	rldicl	r0, r0, 63,33',	C ...branch count
+`	srdi	r0, r0, 1')	C ...for ctr
+	mtctr	r0
+
+	andi.	r0, n, 1
+
+	li	r0, 0
+	li	r12, 0
+
+	beq	L(evn)
+
+L(odd):	ld	r6, 0(up)
+	addi	up, up, 8
+	ld	r8, 0(vp)
+	addi	vp, vp, 8
+	xor	r10, r6, r8
+	popcntd(r0, r10)
+	bdz	L(e1)
+
+L(evn):	ld	r6, 0(up)
+	ld	r8, 0(vp)
+	ld	r7, 8(up)
+	ld	r9, 8(vp)
+	xor	r10, r6, r8
+	addi	up, up, 16
+	addi	vp, vp, 16
+	li	r30, 0
+	li	r31, 0
+	bdz	L(end)
+
+	nop
+	nop
+C	ALIGN(16)
+L(top):	add	r0, r0, r30
+	ld	r6, 0(up)
+	ld	r8, 0(vp)
+	xor	r11, r7, r9
+	popcntd(r30, r10)
+	add	r12, r12, r31
+	ld	r7, 8(up)
+	ld	r9, 8(vp)
+	xor	r10, r6, r8
+	popcntd(r31, r11)
+	addi	up, up, 16
+	addi	vp, vp, 16
+	bdnz	L(top)
+
+L(end):	add	r0, r0, r30
+	xor	r11, r7, r9
+	popcntd(r30, r10)
+	add	r12, r12, r31
+	popcntd(r31, r11)
+
+	add	r0, r0, r30
+	add	r12, r12, r31
+L(e1):	add	r3, r0, r12
+	ld	r30, -16(r1)
+	ld	r31, -8(r1)
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc64/p7/popcount.asm b/third_party/gmp/mpn/powerpc64/p7/popcount.asm
new file mode 100644
index 0000000..129ffef
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/p7/popcount.asm
@@ -0,0 +1,90 @@
+dnl  PowerPC-64 mpn_popcount.
+
+dnl  Copyright 2012, 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                   cycles/limb
+C POWER3/PPC630          -
+C POWER4/PPC970          -
+C POWER5                 -
+C POWER6                 -
+C POWER7                 2
+
+define(`up', r3)
+define(`n',  r4)
+
+ASM_START()
+PROLOGUE(mpn_popcount)
+	addi	r0, n, 1
+ifdef(`HAVE_ABI_mode32',
+`	rldicl	r0, r0, 63,33',	C ...branch count
+`	srdi	r0, r0, 1')	C ...for ctr
+	mtctr	r0
+
+	andi.	r0, n, 1
+
+	li	r0, 0
+	li	r12, 0
+	beq	L(evn)
+
+L(odd):	ld	r4, 0(up)
+	addi	up, up, 8
+	popcntd(r0, r4)
+	bdz	L(e1)
+
+L(evn):	ld	r4, 0(up)
+	ld	r5, 8(up)
+	popcntd(r8, r4)
+	popcntd(r9, r5)
+	bdz	L(e2)
+
+	ld	r4, 16(up)
+	ld	r5, 24(up)
+	bdz	L(e4)
+	addi	up, up, 32
+
+L(top):	add	r0, r0, r8
+	popcntd(r8, r4)
+	ld	r4, 0(up)
+	add	r12, r12, r9
+	popcntd(r9, r5)
+	ld	r5, 8(up)
+	addi	up, up, 16
+	bdnz	L(top)
+
+L(e4):	add	r0, r0, r8
+	popcntd(r8, r4)
+	add	r12, r12, r9
+	popcntd(r9, r5)
+L(e2):	add	r0, r0, r8
+	add	r12, r12, r9
+L(e1):	add	r3, r0, r12
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc64/rshift.asm b/third_party/gmp/mpn/powerpc64/rshift.asm
new file mode 100644
index 0000000..7654a16
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/rshift.asm
@@ -0,0 +1,207 @@
+dnl  PowerPC-64 mpn_rshift -- rp[] = up[] >> cnt
+
+dnl  Copyright 2003, 2005, 2010, 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                   cycles/limb
+C POWER3/PPC630          ?
+C POWER4/PPC970          ?
+C POWER5                 2.25
+C POWER6                 9.75
+C POWER7                 2.15
+
+C TODO
+C  * Try to reduce the number of needed live registers
+C  * Micro-optimise header code
+C  * Keep in synch with lshift.asm and lshiftc.asm
+
+C INPUT PARAMETERS
+define(`rp',  `r3')
+define(`up',  `r4')
+define(`n',   `r5')
+define(`cnt', `r6')
+
+define(`tnc',`r0')
+define(`u0',`r30')
+define(`u1',`r31')
+define(`retval',`r5')
+
+ASM_START()
+PROLOGUE(mpn_rshift)
+	std	r31, -8(r1)
+	std	r30, -16(r1)
+	subfic	tnc, cnt, 64
+C	sldi	r30, n, 3	C byte count corresponding to n
+C	add	rp, rp, r30	C rp = rp + n
+C	add	up, up, r30	C up = up + n
+	rldicl.	r30, n, 0,62	C r30 = n & 3, set cr0
+	cmpdi	cr6, r30, 2
+	addi	r31, n, 3	C compute count...
+	ld	r10, 0(up)	C load 1st limb for b00...b11
+	sld	retval, r10, tnc
+ifdef(`HAVE_ABI_mode32',
+`	rldicl	r31, r31, 62,34',	C ...branch count
+`	srdi	r31, r31, 2')	C ...for ctr
+	mtctr	r31		C copy count into ctr
+	beq	cr0, L(b00)
+	blt	cr6, L(b01)
+	ld	r11, 8(up)	C load 2nd limb for b10 and b11
+	beq	cr6, L(b10)
+
+	ALIGN(16)
+L(b11):	srd	r8, r10, cnt
+	sld	r9, r11, tnc
+	ld	u1, 16(up)
+	addi	up, up, 24
+	srd	r12, r11, cnt
+	sld	r7, u1, tnc
+	addi	rp, rp, -16
+	bdnz	L(gt3)
+
+	or	r11, r8, r9
+	srd	r8, u1, cnt
+	b	L(cj3)
+
+	ALIGN(16)
+L(gt3):	ld	u0, 0(up)
+	or	r11, r8, r9
+	srd	r8, u1, cnt
+	sld	r9, u0, tnc
+	ld	u1, 8(up)
+	or	r10, r12, r7
+	b	L(L11)
+
+	ALIGN(32)
+L(b10):	srd	r12, r10, cnt
+	addi	rp, rp, -24
+	sld	r7, r11, tnc
+	bdnz	L(gt2)
+
+	srd	r8, r11, cnt
+	or	r10, r12, r7
+	b	L(cj2)
+
+L(gt2):	ld	u0, 16(up)
+	srd	r8, r11, cnt
+	sld	r9, u0, tnc
+	ld	u1, 24(up)
+	or	r10, r12, r7
+	srd	r12, u0, cnt
+	sld	r7, u1, tnc
+	ld	u0, 32(up)
+	or	r11, r8, r9
+	addi	up, up, 16
+	b	L(L10)
+
+	ALIGN(16)
+L(b00):	ld	u1, 8(up)
+	srd	r12, r10, cnt
+	sld	r7, u1, tnc
+	ld	u0, 16(up)
+	srd	r8, u1, cnt
+	sld	r9, u0, tnc
+	ld	u1, 24(up)
+	or	r10, r12, r7
+	srd	r12, u0, cnt
+	sld	r7, u1, tnc
+	addi	rp, rp, -8
+	bdz	L(cj4)
+
+L(gt4):	addi	up, up, 32
+	ld	u0, 0(up)
+	or	r11, r8, r9
+	b	L(L00)
+
+	ALIGN(16)
+L(b01):	bdnz	L(gt1)
+	srd	r8, r10, cnt
+	std	r8, 0(rp)
+	b	L(ret)
+
+L(gt1):	ld	u0, 8(up)
+	srd	r8, r10, cnt
+	sld	r9, u0, tnc
+	ld	u1, 16(up)
+	srd	r12, u0, cnt
+	sld	r7, u1, tnc
+	ld	u0, 24(up)
+	or	r11, r8, r9
+	srd	r8, u1, cnt
+	sld	r9, u0, tnc
+	ld	u1, 32(up)
+	addi	up, up, 40
+	or	r10, r12, r7
+	bdz	L(end)
+
+	ALIGN(32)
+L(top):	srd	r12, u0, cnt
+	sld	r7, u1, tnc
+	ld	u0, 0(up)
+	std	r11, 0(rp)
+	or	r11, r8, r9
+L(L00):	srd	r8, u1, cnt
+	sld	r9, u0, tnc
+	ld	u1, 8(up)
+	std	r10, 8(rp)
+	or	r10, r12, r7
+L(L11):	srd	r12, u0, cnt
+	sld	r7, u1, tnc
+	ld	u0, 16(up)
+	std	r11, 16(rp)
+	or	r11, r8, r9
+L(L10):	srd	r8, u1, cnt
+	sld	r9, u0, tnc
+	ld	u1, 24(up)
+	addi	up, up, 32
+	std	r10, 24(rp)
+	addi	rp, rp, 32
+	or	r10, r12, r7
+	bdnz	L(top)
+
+	ALIGN(32)
+L(end):	srd	r12, u0, cnt
+	sld	r7, u1, tnc
+	std	r11, 0(rp)
+L(cj4):	or	r11, r8, r9
+	srd	r8, u1, cnt
+	std	r10, 8(rp)
+L(cj3):	or	r10, r12, r7
+	std	r11, 16(rp)
+L(cj2):	std	r10, 24(rp)
+	std	r8, 32(rp)
+
+L(ret):	ld	r31, -8(r1)
+	ld	r30, -16(r1)
+ifdef(`HAVE_ABI_mode32',
+`	srdi	r3, retval, 32
+	mr	r4, retval
+',`	mr	r3, retval')
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc64/sec_tabselect.asm b/third_party/gmp/mpn/powerpc64/sec_tabselect.asm
new file mode 100644
index 0000000..085577c
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/sec_tabselect.asm
@@ -0,0 +1,147 @@
+dnl  PowerPC-64 mpn_sec_tabselect.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                   cycles/limb
+C POWER3/PPC630		 1.75
+C POWER4/PPC970		 2.0
+C POWER5		 ?
+C POWER6		 5.0
+C POWER7		 1.75
+
+define(`rp',     `r3')
+define(`tp',     `r4')
+define(`n',      `r5')
+define(`nents',  `r6')
+define(`which',  `r7')
+
+define(`i',      `r8')
+define(`j',      `r9')
+define(`stride', `r12')
+define(`mask',   `r11')
+
+
+ASM_START()
+PROLOGUE(mpn_sec_tabselect)
+	addic.	j, n, -4		C outer loop induction variable
+	std	r31, -8(r1)
+	std	r30, -16(r1)
+	std	r29, -24(r1)
+	std	r28, -32(r1)
+	std	r27, -40(r1)
+	sldi	stride, n, 3
+
+	blt	cr0, L(outer_end)
+L(outer_top):
+	mtctr	nents
+	mr	r10, tp
+	li	r28, 0
+	li	r29, 0
+	li	r30, 0
+	li	r31, 0
+	addic.	j, j, -4		C outer loop induction variable
+	mr	i, which
+
+	ALIGN(16)
+L(top):	addic	i, i, -1		C set carry iff i != 0
+	subfe	mask, mask, mask
+	ld	r0, 0(tp)
+	ld	r27, 8(tp)
+	and	r0, r0, mask
+	and	r27, r27, mask
+	or	r28, r28, r0
+	or	r29, r29, r27
+	ld	r0, 16(tp)
+	ld	r27, 24(tp)
+	and	r0, r0, mask
+	and	r27, r27, mask
+	or	r30, r30, r0
+	or	r31, r31, r27
+	add	tp, tp, stride
+	bdnz	L(top)
+
+	std	r28, 0(rp)
+	std	r29, 8(rp)
+	std	r30, 16(rp)
+	std	r31, 24(rp)
+	addi	tp, r10, 32
+	addi	rp, rp, 32
+	bge	cr0, L(outer_top)
+L(outer_end):
+
+	rldicl.	r0, n, 63, 63
+	beq	cr0, L(b0x)
+L(b1x):	mtctr	nents
+	mr	r10, tp
+	li	r28, 0
+	li	r29, 0
+	mr	i, which
+	ALIGN(16)
+L(tp2):	addic	i, i, -1
+	subfe	mask, mask, mask
+	ld	r0, 0(tp)
+	ld	r27, 8(tp)
+	and	r0, r0, mask
+	and	r27, r27, mask
+	or	r28, r28, r0
+	or	r29, r29, r27
+	add	tp, tp, stride
+	bdnz	L(tp2)
+	std	r28, 0(rp)
+	std	r29, 8(rp)
+	addi	tp, r10, 16
+	addi	rp, rp, 16
+
+L(b0x):	rldicl.	r0, n, 0, 63
+	beq	cr0, L(b00)
+L(b01):	mtctr	nents
+	mr	r10, tp
+	li	r28, 0
+	mr	i, which
+	ALIGN(16)
+L(tp1):	addic	i, i, -1
+	subfe	mask, mask, mask
+	ld	r0, 0(tp)
+	and	r0, r0, mask
+	or	r28, r28, r0
+	add	tp, tp, stride
+	bdnz	L(tp1)
+	std	r28, 0(rp)
+
+L(b00):	ld	r31, -8(r1)
+	ld	r30, -16(r1)
+	ld	r29, -24(r1)
+	ld	r28, -32(r1)
+	ld	r27, -40(r1)
+	blr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/powerpc64/umul.asm b/third_party/gmp/mpn/powerpc64/umul.asm
new file mode 100644
index 0000000..7fcc72f
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/umul.asm
@@ -0,0 +1,53 @@
+dnl  PowerPC-64 umul_ppmm -- support for longlong.h
+
+dnl  Copyright 2000, 2001, 2005 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C mp_limb_t mpn_umul_ppmm (mp_limb_t *lowptr, mp_limb_t m1, mp_limb_t m2);
+C
+
+ASM_START()
+PROLOGUE(mpn_umul_ppmm)
+
+	C r3	lowptr
+	C r4	m1
+	C r5	m2
+
+	mulld	r0, r4, r5
+	mulhdu	r4, r4, r5
+	std	r0, 0(r3)
+ifdef(`HAVE_ABI_mode32',
+`	srdi	r3, r4, 32
+',`	mr	r3, r4
+')
+	blr
+
+EPILOGUE(mpn_umul_ppmm)
diff --git a/third_party/gmp/mpn/powerpc64/vmx/popcount.asm b/third_party/gmp/mpn/powerpc64/vmx/popcount.asm
new file mode 100644
index 0000000..b95fb88
--- /dev/null
+++ b/third_party/gmp/mpn/powerpc64/vmx/popcount.asm
@@ -0,0 +1,230 @@
+dnl  PowerPC-32/VMX and PowerPC-64/VMX mpn_popcount.
+
+dnl  Copyright 2006, 2010 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                   cycles/limb
+C 7400,7410 (G4):       ?
+C 744x,745x (G4+):      1.125
+C 970 (G5):             2.25
+
+C TODO
+C  * Rewrite the awkward huge n outer loop code.
+C  * Two lvx, two vperm, and two vxor could make us a similar hamdist.
+C  * Compress cnsts table in 64-bit mode, only half the values are needed.
+
+define(`GMP_LIMB_BYTES', eval(GMP_LIMB_BITS/8))
+define(`LIMBS_PER_VR',  eval(16/GMP_LIMB_BYTES))
+define(`LIMBS_PER_2VR', eval(32/GMP_LIMB_BYTES))
+
+define(`OPERATION_popcount')
+
+define(`ap',	`r3')
+define(`n',	`r4')
+
+define(`rtab',	`v10')
+define(`cnt4',	`v11')
+
+ifelse(GMP_LIMB_BITS,32,`
+	define(`LIMB32',`	$1')
+	define(`LIMB64',`')
+',`
+	define(`LIMB32',`')
+	define(`LIMB64',`	$1')
+')
+
+C The inner loop handles up to 2^34 bits, i.e., 2^31 64-limbs, due to overflow
+C in vsum4ubs.  For large operands, we work in chunks, of size LIMBS_PER_CHUNK.
+define(`LIMBS_PER_CHUNK', 0x1000)
+define(`LIMBS_CHUNK_THRES', 0x1001)
+
+ASM_START()
+PROLOGUE(mpn_popcount,toc)
+	mfspr	r10, 256
+	oris	r0, r10, 0xfffc		C Set VRSAVE bit 0-13
+	mtspr	256, r0
+
+ifdef(`HAVE_ABI_mode32',
+`	rldicl	n, n, 0, 32')		C zero extend n
+
+C Load various constants into vector registers
+	LEAL(	r11, cnsts)
+	li	r12, 16
+	vspltisb cnt4, 4		C 0x0404...04 used as shift count
+
+	li	r7, 160
+	lvx	rtab, 0, r11
+
+LIMB64(`lis	r0, LIMBS_CHUNK_THRES	')
+LIMB64(`cmpd	cr7, n, r0		')
+
+	lvx	v0, 0, ap
+	addi	r7, r11, 80
+	rlwinm	r6, ap, 2,26,29
+	lvx	v8, r7, r6
+	vand	v0, v0, v8
+
+LIMB32(`rlwinm	r8, ap, 30,30,31	')
+LIMB64(`rlwinm	r8, ap, 29,31,31	')
+	add	n, n, r8		C compensate n for rounded down `ap'
+
+	vxor	v1, v1, v1
+	li	r8, 0			C grand total count
+
+	vxor	v12, v12, v12		C zero total count
+	vxor	v13, v13, v13		C zero total count
+
+	addic.	n, n, -LIMBS_PER_VR
+	ble	L(sum)
+
+	addic.	n, n, -LIMBS_PER_VR
+	ble	L(lsum)
+
+C For 64-bit machines, handle huge n that would overflow vsum4ubs
+LIMB64(`ble	cr7, L(small)		')
+LIMB64(`addis	r9, n, -LIMBS_PER_CHUNK	') C remaining n
+LIMB64(`lis	n, LIMBS_PER_CHUNK	')
+
+	ALIGN(16)
+L(small):
+LIMB32(`srwi	r7, n, 3	')	C loop count corresponding to n
+LIMB64(`srdi	r7, n, 2	')	C loop count corresponding to n
+	addi	r7, r7, 1
+	mtctr	r7			C copy n to count register
+	b	L(ent)
+
+	ALIGN(16)
+L(top):
+	lvx	v0, 0, ap
+L(ent):	lvx	v1, r12, ap
+	addi	ap, ap, 32
+	vsrb	v8, v0, cnt4
+	vsrb	v9, v1, cnt4
+	vperm	v2, rtab, rtab, v0
+	vperm	v3, rtab, rtab, v8
+	vperm	v4, rtab, rtab, v1
+	vperm	v5, rtab, rtab, v9
+	vaddubm	v6, v2, v3
+	vaddubm	v7, v4, v5
+	vsum4ubs v12, v6, v12
+	vsum4ubs v13, v7, v13
+	bdnz	L(top)
+
+	andi.	n, n, eval(LIMBS_PER_2VR-1)
+	beq	L(rt)
+
+	lvx	v0, 0, ap
+	vxor	v1, v1, v1
+	cmpwi	n, LIMBS_PER_VR
+	ble	L(sum)
+L(lsum):
+	vor	v1, v0, v0
+	lvx	v0, r12, ap
+L(sum):
+LIMB32(`rlwinm	r6, n, 4,26,27	')
+LIMB64(`rlwinm	r6, n, 5,26,26	')
+	addi	r7, r11, 16
+	lvx	v8, r7, r6
+	vand	v0, v0, v8
+	vsrb	v8, v0, cnt4
+	vsrb	v9, v1, cnt4
+	vperm	v2, rtab, rtab, v0
+	vperm	v3, rtab, rtab, v8
+	vperm	v4, rtab, rtab, v1
+	vperm	v5, rtab, rtab, v9
+	vaddubm	v6, v2, v3
+	vaddubm	v7, v4, v5
+	vsum4ubs v12, v6, v12
+	vsum4ubs v13, v7, v13
+
+	ALIGN(16)
+L(rt):	vadduwm	v3, v12, v13
+	li	r7, -16			C FIXME: does all ppc32 and ppc64 ABIs
+	stvx	v3, r7, r1		C FIXME: ...support storing below sp?
+
+	lwz	r7, -16(r1)
+	add	r8, r8, r7
+	lwz	r7, -12(r1)
+	add	r8, r8, r7
+	lwz	r7, -8(r1)
+	add	r8, r8, r7
+	lwz	r7, -4(r1)
+	add	r8, r8, r7
+
+C Handle outer loop for huge n.  We inherit cr7 and r0 from above.
+LIMB64(`ble	cr7, L(ret)
+	vxor	v12, v12, v12		C zero total count
+	vxor	v13, v13, v13		C zero total count
+	mr	n, r9
+	cmpd	cr7, n, r0
+	ble	cr7, L(2)
+	addis	r9, n, -LIMBS_PER_CHUNK	C remaining n
+	lis	n, LIMBS_PER_CHUNK
+L(2):	srdi	r7, n, 2		C loop count corresponding to n
+	mtctr	r7			C copy n to count register
+	b	L(top)
+')
+
+	ALIGN(16)
+L(ret):	mr	r3, r8
+	mtspr	256, r10
+	blr
+EPILOGUE()
+
+DEF_OBJECT(cnsts,16)
+C Counts for vperm
+	.byte	0x00,0x01,0x01,0x02,0x01,0x02,0x02,0x03
+	.byte	0x01,0x02,0x02,0x03,0x02,0x03,0x03,0x04
+C Masks for high end of number
+	.byte	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
+	.byte	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
+
+	.byte	0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00
+	.byte	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+
+	.byte	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
+	.byte	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+
+	.byte	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
+	.byte	0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00
+C Masks for low end of number
+	.byte	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
+	.byte	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
+
+	.byte	0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff
+	.byte	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
+
+	.byte	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+	.byte	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
+
+	.byte	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+	.byte	0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff
+END_OBJECT(cnsts)
+ASM_END()
diff --git a/third_party/gmp/mpn/riscv/64/aors_n.asm b/third_party/gmp/mpn/riscv/64/aors_n.asm
new file mode 100644
index 0000000..6e38083
--- /dev/null
+++ b/third_party/gmp/mpn/riscv/64/aors_n.asm
@@ -0,0 +1,89 @@
+dnl  RISC-V/64 mpn_add_n and mpn_sub_n.
+
+dnl  Copyright 2016 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C  INPUT PARAMETERS
+define(`rp',	`a0')
+define(`up',	`a1')
+define(`vp',	`a2')
+define(`n',	`a3')
+
+ifdef(`OPERATION_add_n',`
+    define(`ADDSUB',	`add')
+    define(`CMPCY',	`sltu	$1, $2, $3')
+    define(`func',	`mpn_add_n')
+')
+ifdef(`OPERATION_sub_n',`
+    define(`ADDSUB',	`sub')
+    define(`CMPCY',	`sltu	$1, $3, $2')
+    define(`func',	`mpn_sub_n')
+')
+
+MULFUNC_PROLOGUE(mpn_add_n mpn_sub_n)
+
+ASM_START()
+PROLOGUE(func)
+	li	t6, 0
+
+	andi	t0, n, 1
+	beq	t0, x0, L(top)
+	addi	up, up, 8
+	addi	vp, vp, -8
+	addi	rp, rp, -8
+	addi	n, n, -1
+	j	L(mid)
+
+L(top):	ld	a4, 0(up)
+	ld	a6, 0(vp)
+	addi	n, n, -2	C bookkeeping
+	addi	up, up, 16	C bookkeeping
+	ADDSUB	t0, a4, a6
+	CMPCY(	t2, t0, a4)
+	ADDSUB	t4, t0, t6	C cycle 3, 9, ...
+	CMPCY(	t3, t4, t0)	C cycle 4, 10, ...
+	sd	t4, 0(rp)
+	add	t6, t2, t3	C cycle 5, 11, ...
+L(mid):	ld	a5, -8(up)
+	ld	a7, 8(vp)
+	addi	vp, vp, 16	C bookkeeping
+	addi	rp, rp, 16	C bookkeeping
+	ADDSUB	t1, a5, a7
+	CMPCY(	t2, t1, a5)
+	ADDSUB	t4, t1, t6	C cycle 0, 6, ...
+	CMPCY(	t3, t4, t1)	C cycle 1, 7, ...
+	sd	t4, -8(rp)
+	add	t6, t2, t3	C cycle 2, 8, ...
+	bne	n, x0, L(top)	C bookkeeping
+
+L(end):	mv	a0, t6
+	ret
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/riscv/64/aorsmul_1.asm b/third_party/gmp/mpn/riscv/64/aorsmul_1.asm
new file mode 100644
index 0000000..1125a9f
--- /dev/null
+++ b/third_party/gmp/mpn/riscv/64/aorsmul_1.asm
@@ -0,0 +1,75 @@
+dnl  RISC-V/64 mpn_addmul_1 and mpn_submul_1.
+
+dnl  Copyright 2016 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C  INPUT PARAMETERS
+define(`rp',	`a0')
+define(`up',	`a1')
+define(`n',	`a2')
+define(`v0',	`a3')
+
+ifdef(`OPERATION_addmul_1',`
+    define(`ADDSUB',	`add')
+    define(`CMPCY',	`sltu	$1, $2, $3')
+    define(`func',	`mpn_addmul_1')
+')
+ifdef(`OPERATION_submul_1',`
+    define(`ADDSUB',	`sub')
+    define(`CMPCY',	`sltu	$1, $3, $2')
+    define(`func',	`mpn_submul_1')
+')
+
+MULFUNC_PROLOGUE(mpn_addmul_1 mpn_submul_1)
+
+ASM_START()
+PROLOGUE(func)
+	li	a6, 0
+
+L(top):	ld	a7, 0(up)
+	addi	up, up, 8	C bookkeeping
+	ld	a4, 0(rp)
+	addi	rp, rp, 8	C bookkeeping
+	mul	a5, a7, v0
+	addi	n, n, -1	C bookkeeping
+	mulhu	a7, a7, v0
+	ADDSUB	a5, a4, a5
+	ADDSUB	a6, a5, a6	C cycle 0, 3, ...
+	CMPCY(	a4, a5, a4)
+	add	a4, a4, a7
+	CMPCY(	a5, a6, a5)	C cycle 1, 4, ...
+	sd	a6, -8(rp)
+	add	a6, a4, a5	C cycle 2, 5, ...
+	bne	n, x0, L(top)	C bookkeeping
+
+L(end):	mv	a0, a6
+	ret
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/riscv/64/mul_1.asm b/third_party/gmp/mpn/riscv/64/mul_1.asm
new file mode 100644
index 0000000..e35eaa9
--- /dev/null
+++ b/third_party/gmp/mpn/riscv/64/mul_1.asm
@@ -0,0 +1,58 @@
+dnl  RISC-V/64 mpn_mul_1.
+
+dnl  Copyright 2016 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C  INPUT PARAMETERS
+define(`rp',	`a0')
+define(`up',	`a1')
+define(`n',	`a2')
+define(`v0',	`a3')
+
+ASM_START()
+PROLOGUE(mpn_mul_1)
+	li	a6, 0
+
+L(top):	ld	a7, 0(up)
+	addi	up, up, 8	C bookkeeping
+	addi	rp, rp, 8	C bookkeeping
+	mul	a5, a7, v0
+	addi	n, n, -1	C bookkeeping
+	mulhu	a7, a7, v0
+	add	a6, a5, a6	C cycle 0, 3, ...
+	sltu	a5, a6, a5	C cycle 1, 4, ...
+	sd	a6, -8(rp)
+	add	a6, a7, a5	C cycle 2, 5, ...
+	bne	n, x0, L(top)	C bookkeeping
+
+L(end):	mv	a0, a6
+	ret
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/s390_32/README b/third_party/gmp/mpn/s390_32/README
new file mode 100644
index 0000000..59519ba
--- /dev/null
+++ b/third_party/gmp/mpn/s390_32/README
@@ -0,0 +1,37 @@
+All current (2001) S/390 and z/Architecture machines are single-issue,
+but some newer machines have a deep pipeline.  Software-pipelining is
+therefore beneficial.
+
+* mpn_add_n, mpn_sub_n: Use code along the lines below.  Two-way unrolling
+  would be adequate.
+
+  mp_limb_t
+  mpn_add_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n)
+  {
+    mp_limb_t a, b, r, cy;
+    mp_size_t i;
+    mp_limb_t mm = -1;
+
+    cy = 0;
+    up += n;
+    vp += n;
+    rp += n;
+    i = -n;
+    do
+      {
+	a = up[i];
+	b = vp[i];
+	r = a + b + cy;
+	rp[i] = r;
+	cy = (((a & b) | ((a | b) & (r ^ mm)))) >> 31;
+	i++;
+      }
+    while (i < 0);
+    return cy;
+  }
+
+* mpn_lshift, mpn_rshift: Use SLDL/SRDL, and two-way unrolling.
+
+* mpn_mul_1, mpn_addmul_1, mpn_submul_1: For machines with just signed
+  multiply (MR), use two loops, similar to the corresponding VAX or
+  POWER functions.  Handle carry like for mpn_add_n.
diff --git a/third_party/gmp/mpn/s390_32/addmul_1.asm b/third_party/gmp/mpn/s390_32/addmul_1.asm
new file mode 100644
index 0000000..97189a8
--- /dev/null
+++ b/third_party/gmp/mpn/s390_32/addmul_1.asm
@@ -0,0 +1,93 @@
+dnl  S/390 mpn_addmul_1 -- Multiply a limb vector with a limb and add the
+dnl  result to a second limb vector.
+
+dnl  Copyright 2001 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+define(`rp',2)
+define(`up',3)
+define(`n',4)
+define(`vlimb',5)
+define(`cylimb',7)
+
+ASM_START()
+PROLOGUE(mpn_addmul_1)
+	stm	6,7,24(15)
+	slr	cylimb,cylimb	# clear cylimb
+	ltr	vlimb,vlimb
+	jnl	.Loopp
+
+.Loopn:	l	1,0(up)		# load from u
+	lr	6,1		#
+	mr	0,vlimb		# multiply signed
+	alr	0,6		# add vlimb to phi
+	sra	6,31		# make mask
+	nr	6,vlimb		# 0 or vlimb
+	alr	0,6		# conditionally add vlimb to phi
+	alr	1,cylimb	# add carry limb to plo
+	brc	8+4,+8		# branch if not carry
+	ahi	0,1		# increment phi
+	l	6,0(rp)		# load r limb
+	alr	6,1		# add u limb to plo
+	brc	8+4,+8		# branch if not carry
+	ahi	0,1		# increment phi
+	lr	cylimb,0	# new cylimb
+	st	6,0(rp)		# store
+	la	up,4(,up)
+	la	rp,4(,rp)
+	brct	n,.Loopn
+
+	lr	2,cylimb
+	lm	6,7,24(15)
+	br	14
+
+.Loopp:	l	1,0(up)		# load from u
+	lr	6,1		#
+	mr	0,vlimb		# multiply signed
+	sra	6,31		# make mask
+	nr	6,vlimb		# 0 or vlimb
+	alr	0,6		# conditionally add vlimb to phi
+	alr	1,cylimb	# add carry limb to plo
+	brc	8+4,+8		# branch if not carry
+	ahi	0,1		# increment phi
+	l	6,0(rp)		# load r limb
+	alr	6,1		# add u limb to plo
+	brc	8+4,+8		# branch if not carry
+	ahi	0,1		# increment phi
+	lr	cylimb,0	# new cylimb
+	st	6,0(rp)		# store
+	la	up,4(,up)
+	la	rp,4(,rp)
+	brct	n,.Loopp
+
+	lr	2,cylimb
+	lm	6,7,24(15)
+	br	14
+EPILOGUE(mpn_addmul_1)
diff --git a/third_party/gmp/mpn/s390_32/copyd.asm b/third_party/gmp/mpn/s390_32/copyd.asm
new file mode 100644
index 0000000..ff252bc
--- /dev/null
+++ b/third_party/gmp/mpn/s390_32/copyd.asm
@@ -0,0 +1,145 @@
+dnl  S/390-32 mpn_copyd
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+C            cycles/limb
+C            cycles/limb
+C z900		 1.65
+C z990           1.125
+C z9		 ?
+C z10		 ?
+C z196		 ?
+
+C FIXME:
+C  * Avoid saving/restoring callee-saves registers for n < 3.  This could be
+C    done by setting rp=r1, up=r2, i=r0 and r3,r4,r5 for clock regs.
+C    We could then use r3...r10 in main loop.
+
+C INPUT PARAMETERS
+define(`rp_param',	`%r2')
+define(`up_param',	`%r3')
+define(`n',		`%r4')
+
+define(`rp',	`%r8')
+define(`up',	`%r9')
+
+ASM_START()
+PROLOGUE(mpn_copyd)
+	stm	%r6, %r11, 24(%r15)
+
+	lr	%r1, n
+	sll	%r1, 2
+	la	%r10, 8(n)
+	ahi	%r1, -32
+	srl	%r10, 3
+	lhi	%r11, -32
+
+	la	rp, 0(%r1,rp_param)	C FIXME use lay on z990 and later
+	la	up, 0(%r1,up_param)	C FIXME use lay on z990 and later
+
+	lhi	%r7, 7
+	nr	%r7, n			C n mod 8
+	chi	%r7, 2
+	jh	L(b34567)
+	chi	%r7, 1
+	je	L(b1)
+	jh	L(b2)
+
+L(b0):	brct	%r10, L(top)
+	j	L(end)
+
+L(b1):	l	%r0, 28(up)
+	ahi	up, -4
+	st	%r0, 28(rp)
+	ahi	rp, -4
+	brct	%r10, L(top)
+	j	L(end)
+
+L(b2):	lm	%r0, %r1, 24(up)
+	ahi	up, -8
+	stm	%r0, %r1, 24(rp)
+	ahi	rp, -8
+	brct	%r10, L(top)
+	j	L(end)
+
+L(b34567):
+	chi	%r7, 4
+	jl	L(b3)
+	je	L(b4)
+	chi	%r7, 6
+	je	L(b6)
+	jh	L(b7)
+
+L(b5):	lm	%r0, %r4, 12(up)
+	ahi	up, -20
+	stm	%r0, %r4, 12(rp)
+	ahi	rp, -20
+	brct	%r10, L(top)
+	j	L(end)
+
+L(b3):	lm	%r0, %r2, 20(up)
+	ahi	up, -12
+	stm	%r0, %r2, 20(rp)
+	ahi	rp, -12
+	brct	%r10, L(top)
+	j	L(end)
+
+L(b4):	lm	%r0, %r3, 16(up)
+	ahi	up, -16
+	stm	%r0, %r3, 16(rp)
+	ahi	rp, -16
+	brct	%r10, L(top)
+	j	L(end)
+
+L(b6):	lm	%r0, %r5, 8(up)
+	ahi	up, -24
+	stm	%r0, %r5, 8(rp)
+	ahi	rp, -24
+	brct	%r10, L(top)
+	j	L(end)
+
+L(b7):	lm	%r0, %r6, 4(up)
+	ahi	up, -28
+	stm	%r0, %r6, 4(rp)
+	ahi	rp, -28
+	brct	%r10, L(top)
+	j	L(end)
+
+L(top):	lm	%r0, %r7, 0(up)
+	la	up, 0(%r11,up)
+	stm	%r0, %r7, 0(rp)
+	la	rp, 0(%r11,rp)
+	brct	%r10, L(top)
+
+L(end):	lm	%r6, %r11, 24(%r15)
+	br	%r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/s390_32/copyi.asm b/third_party/gmp/mpn/s390_32/copyi.asm
new file mode 100644
index 0000000..1df32f1
--- /dev/null
+++ b/third_party/gmp/mpn/s390_32/copyi.asm
@@ -0,0 +1,69 @@
+dnl  S/390-32 mpn_copyi
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+C            cycles/limb
+C z900		 0.75
+C z990           0.375
+C z9		 ?
+C z10		 ?
+C z196		 ?
+
+C NOTE
+C  * This is based on GNU libc memcpy which was written by Martin Schwidefsky.
+
+C INPUT PARAMETERS
+define(`rp',	`%r2')
+define(`up',	`%r3')
+define(`n',	`%r4')
+
+ASM_START()
+PROLOGUE(mpn_copyi)
+	ltr	%r4, %r4
+	sll	%r4, 2
+	je	L(rtn)
+	ahi	%r4, -1
+	lr	%r5, %r4
+	srl	%r5, 8
+	ltr	%r5, %r5		C < 256 bytes to copy?
+	je	L(1)
+
+L(top):	mvc	0(256, rp), 0(up)
+	la	rp, 256(rp)
+	la	up, 256(up)
+	brct	%r5, L(top)
+
+L(1):	bras	%r5, L(2)		C make r5 point to mvc insn
+	mvc	0(1, rp), 0(up)
+L(2):	ex	%r4, 0(%r5)		C execute mvc with length ((n-1) mod 256)+1
+L(rtn):	br	%r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/s390_32/esame/addmul_1.asm b/third_party/gmp/mpn/s390_32/esame/addmul_1.asm
new file mode 100644
index 0000000..4375b74
--- /dev/null
+++ b/third_party/gmp/mpn/s390_32/esame/addmul_1.asm
@@ -0,0 +1,72 @@
+dnl  S/390-32 mpn_addmul_1 for systems with MLR instruction
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C            cycles/limb
+C z900		18.5
+C z990		10
+C z9		 ?
+C z10		 ?
+C z196		 ?
+
+C INPUT PARAMETERS
+define(`rp',	`%r2')
+define(`up',	`%r3')
+define(`n',	`%r4')
+define(`v0',	`%r5')
+
+define(`z',	`%r9')
+
+ASM_START()
+PROLOGUE(mpn_addmul_1)
+	stm	%r9, %r12, 36(%r15)
+	lhi	%r12, 0			C zero index register
+	ahi	%r12, 0			C clear carry fla
+	lhi	%r11, 0			C clear carry limb
+	lhi	z, 0			C clear carry limb
+
+L(top):	l	%r1, 0(%r12,up)
+	l	%r10, 0(%r12,rp)
+	mlr	%r0, v0
+	alcr	%r1, %r10
+	alcr	%r0, z
+	alr	%r1, %r11
+	lr	%r11, %r0
+	st	%r1, 0(%r12,rp)
+	la	%r12, 4(%r12)
+	brct	n, L(top)
+
+	lhi	%r2, 0
+	alcr	%r2, %r11
+
+	lm	%r9, %r12, 36(%r15)
+	br	%r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/s390_32/esame/aors_n.asm b/third_party/gmp/mpn/s390_32/esame/aors_n.asm
new file mode 100644
index 0000000..98b0dbc
--- /dev/null
+++ b/third_party/gmp/mpn/s390_32/esame/aors_n.asm
@@ -0,0 +1,137 @@
+dnl  S/390-32 mpn_add_n and mpn_sub_n.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C            cycles/limb
+C z900		 ?
+C z990	      2.75-3		(fast for even n, slow for odd n)
+C z9		 ?
+C z10		 ?
+C z196		 ?
+
+C TODO
+C  * Optimise for small n
+C  * Use r0 and save/restore one less register
+C  * Using logops_n's v1 inner loop operand order make the loop about 20%
+C    faster, at the expense of highly alignment-dependent performance.
+
+C INPUT PARAMETERS
+define(`rp',	`%r2')
+define(`up',	`%r3')
+define(`vp',	`%r4')
+define(`n',	`%r5')
+
+ifdef(`OPERATION_add_n', `
+  define(ADSB,		al)
+  define(ADSBCR,	alcr)
+  define(ADSBC,		alc)
+  define(RETVAL,`dnl
+	lhi	%r2, 0
+	alcr	%r2, %r2')
+  define(func,		mpn_add_n)
+  define(func_nc,	mpn_add_nc)')
+ifdef(`OPERATION_sub_n', `
+  define(ADSB,		sl)
+  define(ADSBCR,	slbr)
+  define(ADSBC,		slb)
+  define(RETVAL,`dnl
+	slbr	%r2, %r2
+	lcr	%r2, %r2')
+  define(func,		mpn_sub_n)
+  define(func_nc,	mpn_sub_nc)')
+
+MULFUNC_PROLOGUE(mpn_add_n mpn_sub_n)
+
+ASM_START()
+PROLOGUE(func)
+	stm	%r6, %r8, 24(%r15)
+
+	ahi	n, 3
+	lhi	%r7, 3
+	lr	%r1, n
+	srl	%r1, 2
+	nr	%r7, n			C n mod 4
+	je	L(b1)
+	chi	%r7, 2
+	jl	L(b2)
+	jne	L(b0)
+
+L(b3):	lm	%r5, %r7, 0(up)
+	la	up, 12(up)
+	ADSB	%r5, 0(vp)
+	ADSBC	%r6, 4(vp)
+	ADSBC	%r7, 8(vp)
+	la	vp, 12(vp)
+	stm	%r5, %r7, 0(rp)
+	la	rp, 12(rp)
+	brct	%r1, L(top)
+	j	L(end)
+
+L(b0):	lm	%r5, %r8, 0(up)		C This redundant insns is no mistake,
+	la	up, 16(up)		C it is needed to make main loop run
+	ADSB	%r5, 0(vp)		C fast for n = 0 (mod 4).
+	ADSBC	%r6, 4(vp)
+	j	L(m0)
+
+L(b1):	l	%r5, 0(up)
+	la	up, 4(up)
+	ADSB	%r5, 0(vp)
+	la	vp, 4(vp)
+	st	%r5, 0(rp)
+	la	rp, 4(rp)
+	brct	%r1, L(top)
+	j	L(end)
+
+L(b2):	lm	%r5, %r6, 0(up)
+	la	up, 8(up)
+	ADSB	%r5, 0(vp)
+	ADSBC	%r6, 4(vp)
+	la	vp, 8(vp)
+	stm	%r5, %r6, 0(rp)
+	la	rp, 8(rp)
+	brct	%r1, L(top)
+	j	L(end)
+
+L(top):	lm	%r5, %r8, 0(up)
+	la	up, 16(up)
+	ADSBC	%r5, 0(vp)
+	ADSBC	%r6, 4(vp)
+L(m0):	ADSBC	%r7, 8(vp)
+	ADSBC	%r8, 12(vp)
+	la	vp, 16(vp)
+	stm	%r5, %r8, 0(rp)
+	la	rp, 16(rp)
+	brct	%r1, L(top)
+
+L(end):	RETVAL
+	lm	%r6, %r8, 24(%r15)
+	br	%r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/s390_32/esame/aorslsh1_n.asm b/third_party/gmp/mpn/s390_32/esame/aorslsh1_n.asm
new file mode 100644
index 0000000..f2b222b
--- /dev/null
+++ b/third_party/gmp/mpn/s390_32/esame/aorslsh1_n.asm
@@ -0,0 +1,173 @@
+dnl  S/390-32 mpn_addlsh1_n
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C            cycles/limb
+C z900		 9.25
+C z990		 5
+C z9		 ?
+C z10		 ?
+C z196		 ?
+
+C TODO
+C  * Optimise for small n
+C  * Compute RETVAL for sublsh1_n less stupidly
+
+C INPUT PARAMETERS
+define(`rp',	`%r2')
+define(`up',	`%r3')
+define(`vp',	`%r4')
+define(`n',	`%r5')
+
+ifdef(`OPERATION_addlsh1_n',`
+  define(ADDSUBC,       alr)
+  define(ADDSUBE,       alcr)
+  define(INITCY,        `lhi	%r13, -1')
+  define(RETVAL,        `alr	%r1, %r13
+			lhi	%r2, 2
+			alr	%r2, %r1')
+  define(func, mpn_addlsh1_n)
+')
+ifdef(`OPERATION_sublsh1_n',`
+  define(ADDSUBC,       slr)
+  define(ADDSUBE,       slbr)
+  define(INITCY,        `lhi	%r13, 0')
+  define(RETVAL,        `slr	%r1, %r13
+			lhi	%r2, 1
+			alr	%r2, %r1')
+  define(func, mpn_sublsh1_n)
+')
+
+MULFUNC_PROLOGUE(mpn_addlsh1_n mpn_sublsh1_n)
+
+ASM_START()
+PROLOGUE(func)
+	stm	%r6, %r13, 24(%r15)
+
+	la	%r0, 3(n)
+	lhi	%r7, 3
+	srl	%r0, 2
+	nr	%r7, n			C n mod 4
+	je	L(b0)
+	chi	%r7, 2
+	jl	L(b1)
+	je	L(b2)
+
+L(b3):	lm	%r5, %r7, 0(up)
+	la	up, 12(up)
+	lm	%r9, %r11, 0(vp)
+	la	vp, 12(vp)
+
+	alr	%r9, %r9
+	alcr	%r10, %r10
+	alcr	%r11, %r11
+	slbr	%r1, %r1
+
+	ADDSUBC	%r5, %r9
+	ADDSUBE	%r6, %r10
+	ADDSUBE	%r7, %r11
+	slbr	%r13, %r13
+
+	stm	%r5, %r7, 0(rp)
+	la	rp, 12(rp)
+	brct	%r0, L(top)
+	j	L(end)
+
+L(b0):	lhi	%r1, -1
+	INITCY
+	j	L(top)
+
+L(b1):	l	%r5, 0(up)
+	la	up, 4(up)
+	l	%r9, 0(vp)
+	la	vp, 4(vp)
+
+	alr	%r9, %r9
+	slbr	%r1, %r1
+	ADDSUBC	%r5, %r9
+	slbr	%r13, %r13
+
+	st	%r5, 0(rp)
+	la	rp, 4(rp)
+	brct	%r0, L(top)
+	j	L(end)
+
+L(b2):	lm	%r5, %r6, 0(up)
+	la	up, 8(up)
+	lm	%r9, %r10, 0(vp)
+	la	vp, 8(vp)
+
+	alr	%r9, %r9
+	alcr	%r10, %r10
+	slbr	%r1, %r1
+
+	ADDSUBC	%r5, %r9
+	ADDSUBE	%r6, %r10
+	slbr	%r13, %r13
+
+	stm	%r5, %r6, 0(rp)
+	la	rp, 8(rp)
+	brct	%r0, L(top)
+	j	L(end)
+
+L(top):	lm	%r9, %r12, 0(vp)
+	la	vp, 16(vp)
+
+	ahi	%r1, 1			C restore carry
+
+	alcr	%r9, %r9
+	alcr	%r10, %r10
+	alcr	%r11, %r11
+	alcr	%r12, %r12
+
+	slbr	%r1, %r1		C save carry
+
+	lm	%r5, %r8, 0(up)
+	la	up, 16(up)
+
+	ahi	%r13, 1			C restore carry
+
+	ADDSUBE	%r5, %r9
+	ADDSUBE	%r6, %r10
+	ADDSUBE	%r7, %r11
+	ADDSUBE	%r8, %r12
+
+	slbr	%r13, %r13
+
+	stm	%r5, %r8, 0(rp)
+	la	rp, 16(rp)
+	brct	%r0, L(top)
+
+L(end):
+	RETVAL
+	lm	%r6, %r13, 24(%r15)
+	br	%r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/s390_32/esame/bdiv_dbm1c.asm b/third_party/gmp/mpn/s390_32/esame/bdiv_dbm1c.asm
new file mode 100644
index 0000000..568a2a4
--- /dev/null
+++ b/third_party/gmp/mpn/s390_32/esame/bdiv_dbm1c.asm
@@ -0,0 +1,65 @@
+dnl  S/390-32 mpn_bdiv_dbm1c for systems with MLR instruction.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C            cycles/limb
+C z900		14
+C z990		10
+C z9		 ?
+C z10		 ?
+C z196		 ?
+
+C INPUT PARAMETERS
+define(`qp',	  `%r2')
+define(`up',	  `%r3')
+define(`n',	  `%r4')
+define(`bd',	  `%r5')
+define(`cy',	  `%r6')
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_bdiv_dbm1c)
+	stm	%r6, %r7, 24(%r15)
+	lhi	%r7, 0			C zero index register
+
+L(top):	l	%r1, 0(%r7,up)
+	mlr	%r0, bd
+	slr	%r6, %r1
+	st	%r6, 0(%r7,qp)
+	slbr	%r6, %r0
+	la	%r7, 4(%r7)
+	brct	n, L(top)
+
+	lr	%r2, %r6
+	lm	%r6, %r7, 24(%r15)
+	br	%r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/s390_32/esame/gmp-mparam.h b/third_party/gmp/mpn/s390_32/esame/gmp-mparam.h
new file mode 100644
index 0000000..c0e5046
--- /dev/null
+++ b/third_party/gmp/mpn/s390_32/esame/gmp-mparam.h
@@ -0,0 +1,177 @@
+/* S/390-32 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 2000-2008-2011, 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+/* 4400 MHz IBM z196 running in 32-bit mode */
+/* FFT tuning limit = 0.5M */
+/* Generated by tuneup.c, 2017-01-02, gcc 4.9 */
+
+#define DIVREM_1_NORM_THRESHOLD          MP_SIZE_T_MAX  /* never */
+#define DIVREM_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define MOD_1_1P_METHOD                      2
+#define MOD_1_NORM_THRESHOLD             MP_SIZE_T_MAX  /* never */
+#define MOD_1_UNNORM_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD         45
+#define MOD_1U_TO_MOD_1_1_THRESHOLD         18
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD         0  /* never mpn_mod_1_1p */
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD     MP_SIZE_T_MAX
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD      3
+#define USE_PREINV_DIVREM_1                  0
+#define DIV_QR_1N_PI1_METHOD                 1
+#define DIV_QR_1_NORM_THRESHOLD          MP_SIZE_T_MAX  /* never */
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 6
+#define BMOD_1_TO_MOD_1_THRESHOLD            0  /* always */
+
+#define DIV_1_VS_MUL_1_PERCENT             320
+
+#define MUL_TOOM22_THRESHOLD                12
+#define MUL_TOOM33_THRESHOLD                81
+#define MUL_TOOM44_THRESHOLD               130
+#define MUL_TOOM6H_THRESHOLD               173
+#define MUL_TOOM8H_THRESHOLD               260
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      81
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD      91
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD      83
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD      86
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     112
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 18
+#define SQR_TOOM3_THRESHOLD                 69
+#define SQR_TOOM4_THRESHOLD                178
+#define SQR_TOOM6_THRESHOLD                254
+#define SQR_TOOM8_THRESHOLD                406
+
+#define MULMID_TOOM42_THRESHOLD             30
+
+#define MULMOD_BNM1_THRESHOLD               12
+#define SQRMOD_BNM1_THRESHOLD                7
+
+#define MUL_FFT_MODF_THRESHOLD             276  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    276, 5}, {     15, 6}, {      8, 5}, {     17, 6}, \
+    {      9, 5}, {     19, 6}, {     13, 7}, {      7, 6}, \
+    {     17, 7}, {      9, 6}, {     19, 7}, {     11, 6}, \
+    {     23, 7}, {     13, 8}, {      7, 7}, {     19, 8}, \
+    {     11, 7}, {     25, 8}, {     15, 7}, {     31, 8}, \
+    {     19, 7}, {     39, 8}, {     23, 9}, {     15, 8}, \
+    {     39, 9}, {     23,10}, {     15, 9}, {     31, 8}, \
+    {     67, 9}, {     39, 8}, {     79, 9}, {     47,10}, \
+    {     31, 9}, {     71, 8}, {    143, 9}, {     79,10}, \
+    {     47,11}, {     31,10}, {     63, 9}, {    127, 8}, \
+    {    255, 7}, {    511, 9}, {    143,10}, {     79, 9}, \
+    {    159, 8}, {    319, 9}, {    175, 8}, {    351,10}, \
+    {     95, 9}, {    191, 8}, {    383,11}, {     63,10}, \
+    {    127, 9}, {    255, 8}, {    511,10}, {    143, 9}, \
+    {    287, 8}, {    575,10}, {    159, 9}, {    319,10}, \
+    {    175, 9}, {    351,11}, {     95,10}, {    191, 9}, \
+    {    383,12}, {     63,11}, {    127,10}, {    255, 9}, \
+    {    511,10}, {    271, 9}, {    543, 8}, {   1087,10}, \
+    {    287, 9}, {    575,11}, {    159,10}, {    351, 9}, \
+    {    703, 8}, {   1407,11}, {    191,10}, {    415, 9}, \
+    {    831,11}, {    223,10}, {    479, 9}, {    959, 8}, \
+    {   1919,12}, {   4096,13}, {   8192,14}, {  16384,15}, \
+    {  32768,16} }
+#define MUL_FFT_TABLE3_SIZE 89
+#define MUL_FFT_THRESHOLD                 2688
+
+#define SQR_FFT_MODF_THRESHOLD             240  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    240, 5}, {     17, 6}, {     17, 7}, {      9, 6}, \
+    {     19, 7}, {     11, 6}, {     23, 7}, {     13, 8}, \
+    {      7, 7}, {     19, 8}, {     11, 7}, {     25, 8}, \
+    {     15, 7}, {     33, 8}, {     19, 7}, {     39, 8}, \
+    {     23, 9}, {     15, 8}, {     39, 9}, {     23,10}, \
+    {     15, 9}, {     31, 8}, {     63, 9}, {     47,10}, \
+    {     31, 9}, {     63, 8}, {    127, 9}, {     71, 8}, \
+    {    143,10}, {     47,11}, {     31,10}, {     63, 9}, \
+    {    127, 8}, {    255, 7}, {    511, 9}, {    143,10}, \
+    {     79, 9}, {    159, 8}, {    319, 9}, {    175, 8}, \
+    {    351, 7}, {    703,10}, {     95, 9}, {    191, 8}, \
+    {    383, 9}, {    207, 8}, {    415,11}, {     63,10}, \
+    {    127, 9}, {    255, 8}, {    511,10}, {    143, 9}, \
+    {    287, 8}, {    575,10}, {    159, 9}, {    319,10}, \
+    {    175, 9}, {    351, 8}, {    703, 7}, {   1407,11}, \
+    {     95,10}, {    191, 9}, {    383,10}, {    207, 9}, \
+    {    415,12}, {     63,11}, {    127,10}, {    255, 9}, \
+    {    511,10}, {    287, 9}, {    575,11}, {    159,10}, \
+    {    351, 9}, {    703, 8}, {   1407,11}, {    191,10}, \
+    {    415, 9}, {    831,11}, {    223,10}, {    479,12}, \
+    {   4096,13}, {   8192,14}, {  16384,15}, {  32768,16} }
+#define SQR_FFT_TABLE3_SIZE 84
+#define SQR_FFT_THRESHOLD                 1856
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  27
+#define MULLO_MUL_N_THRESHOLD             5240
+#define SQRLO_BASECASE_THRESHOLD             0  /* always */
+#define SQRLO_DC_THRESHOLD                  65
+#define SQRLO_SQR_THRESHOLD               3470
+
+#define DC_DIV_QR_THRESHOLD                 32
+#define DC_DIVAPPR_Q_THRESHOLD             135
+#define DC_BDIV_QR_THRESHOLD                32
+#define DC_BDIV_Q_THRESHOLD                 80
+
+#define INV_MULMOD_BNM1_THRESHOLD           42
+#define INV_NEWTON_THRESHOLD               177
+#define INV_APPR_THRESHOLD                 139
+
+#define BINV_NEWTON_THRESHOLD              179
+#define REDC_1_TO_REDC_N_THRESHOLD          39
+
+#define MU_DIV_QR_THRESHOLD                872
+#define MU_DIVAPPR_Q_THRESHOLD             998
+#define MUPI_DIV_QR_THRESHOLD               66
+#define MU_BDIV_QR_THRESHOLD               748
+#define MU_BDIV_Q_THRESHOLD                906
+
+#define POWM_SEC_TABLE  9,34,257,946,2913
+
+#define GET_STR_DC_THRESHOLD                10
+#define GET_STR_PRECOMPUTE_THRESHOLD        16
+#define SET_STR_DC_THRESHOLD              1045
+#define SET_STR_PRECOMPUTE_THRESHOLD      1800
+
+#define FAC_DSC_THRESHOLD                   77
+#define FAC_ODD_THRESHOLD                   24
+
+#define MATRIX22_STRASSEN_THRESHOLD         15
+#define HGCD_THRESHOLD                     121
+#define HGCD_APPR_THRESHOLD                142
+#define HGCD_REDUCE_THRESHOLD             1679
+#define GCD_DC_THRESHOLD                   389
+#define GCDEXT_DC_THRESHOLD                285
+#define JACOBI_BASE_METHOD                   4
diff --git a/third_party/gmp/mpn/s390_32/esame/mul_1.asm b/third_party/gmp/mpn/s390_32/esame/mul_1.asm
new file mode 100644
index 0000000..04be963
--- /dev/null
+++ b/third_party/gmp/mpn/s390_32/esame/mul_1.asm
@@ -0,0 +1,66 @@
+dnl  S/390-32 mpn_mul_1 for systems with MLR instruction
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C            cycles/limb
+C z900		14
+C z990		 9
+C z9		 ?
+C z10		 ?
+C z196		 ?
+
+C INPUT PARAMETERS
+define(`rp',	`%r2')
+define(`up',	`%r3')
+define(`n',	`%r4')
+define(`v0',	`%r5')
+
+ASM_START()
+PROLOGUE(mpn_mul_1)
+	stm	%r11, %r12, 44(%r15)
+	lhi	%r12, 0			C zero index register
+	ahi	%r12, 0			C clear carry flag
+	lhi	%r11, 0			C clear carry limb
+
+L(top):	l	%r1, 0(%r12,up)
+	mlr	%r0, v0
+	alcr	%r1, %r11
+	lr	%r11, %r0		C copy high part to carry limb
+	st	%r1, 0(%r12,rp)
+	la	%r12, 4(%r12)
+	brct	n, L(top)
+
+	lhi	%r2, 0
+	alcr	%r2, %r11
+
+	lm	%r11, %r12, 44(%r15)
+	br	%r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/s390_32/esame/mul_basecase.asm b/third_party/gmp/mpn/s390_32/esame/mul_basecase.asm
new file mode 100644
index 0000000..2c8138d
--- /dev/null
+++ b/third_party/gmp/mpn/s390_32/esame/mul_basecase.asm
@@ -0,0 +1,130 @@
+dnl  S/390-32/esame mpn_mul_basecase.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C            cycles/limb
+C z900		 ?
+C z990		 ?
+C z9		 ?
+C z10		 ?
+C z196		 ?
+
+C TODO
+C  * Perhaps add special case for un <= 2.
+C  * Replace loops by faster code.  The mul_1 and addmul_1 loops could be sped
+C    up by about 10%.
+
+C INPUT PARAMETERS
+define(`rp',	`%r2')
+define(`up',	`%r3')
+define(`un',	`%r4')
+define(`vp',	`%r5')
+define(`vn',	`%r6')
+
+define(`zero',	`%r8')
+
+ASM_START()
+PROLOGUE(mpn_mul_basecase)
+	chi	un, 2
+	jhe	L(ge2)
+
+C un = vn = 1
+	l	%r1, 0(vp)
+	ml	%r0, 0(up)
+	st	%r1, 0(rp)
+	st	%r0, 4(rp)
+	br	%r14
+
+L(ge2):	C jne	L(gen)
+
+
+L(gen):
+C mul_1 =======================================================================
+
+	stm	%r6, %r12, 24(%r15)
+	lhi	zero, 0
+	ahi	un, -1
+
+	l	%r7, 0(vp)
+	l	%r11, 0(up)
+	lhi	%r12, 4			C init index register
+	mlr	%r10, %r7
+	lr	%r9, un
+	st	%r11, 0(rp)
+	cr	%r15, %r15		C clear carry flag
+
+L(tm):	l	%r1, 0(%r12,up)
+	mlr	%r0, %r7
+	alcr	%r1, %r10
+	lr	%r10, %r0		C copy high part to carry limb
+	st	%r1, 0(%r12,rp)
+	la	%r12, 4(%r12)
+	brct	%r9, L(tm)
+
+	alcr	%r0, zero
+	st	%r0, 0(%r12,rp)
+
+C addmul_1 loop ===============================================================
+
+	ahi	vn, -1
+	je	L(outer_end)
+L(outer_loop):
+
+	la	rp, 4(rp)		C rp += 1
+	la	vp, 4(vp)		C up += 1
+	l	%r7, 0(vp)
+	l	%r11, 0(up)
+	lhi	%r12, 4			C init index register
+	mlr	%r10, %r7
+	lr	%r9, un
+	al	%r11, 0(rp)
+	st	%r11, 0(rp)
+
+L(tam):	l	%r1, 0(%r12,up)
+	l	%r11, 0(%r12,rp)
+	mlr	%r0, %r7
+	alcr	%r1, %r11
+	alcr	%r0, zero
+	alr	%r1, %r10
+	lr	%r10, %r0
+	st	%r1, 0(%r12,rp)
+	la	%r12, 4(%r12)
+	brct	%r9, L(tam)
+
+	alcr	%r0, zero
+	st	%r0, 0(%r12,rp)
+
+	brct	vn, L(outer_loop)
+L(outer_end):
+
+	lm	%r6, %r12, 24(%r15)
+	br	%r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/s390_32/esame/sqr_basecase.asm b/third_party/gmp/mpn/s390_32/esame/sqr_basecase.asm
new file mode 100644
index 0000000..f45f87a
--- /dev/null
+++ b/third_party/gmp/mpn/s390_32/esame/sqr_basecase.asm
@@ -0,0 +1,203 @@
+dnl  S/390-32 mpn_sqr_basecase.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C            cycles/limb
+C z900		 ?
+C z990		23
+C z9		 ?
+C z10		 ?
+C z196		 ?
+
+C TODO
+C  * Clean up.
+C  * Stop iterating addmul_1 loop at latest for n = 2, implement longer tail.
+C    This will ask for basecase handling of n = 3.
+C  * Update counters and pointers more straightforwardly, possibly lowering
+C    register usage.
+C  * Should we use this allocation-free style for more sqr_basecase asm
+C    implementations?  The only disadvantage is that it requires R != U.
+C  * Replace loops by faster code.  The mul_1 and addmul_1 loops could be sped
+C    up by about 10%.  The sqr_diag_addlsh1 loop could probably be sped up even
+C    more.
+
+C INPUT PARAMETERS
+define(`rp',	`%r2')
+define(`up',	`%r3')
+define(`n',	`%r4')
+
+define(`zero',	`%r8')
+define(`rp_saved',	`%r9')
+define(`up_saved',	`%r13')
+define(`n_saved',	`%r14')
+
+ASM_START()
+PROLOGUE(mpn_sqr_basecase)
+	ahi	n, -2
+	jhe	L(ge2)
+
+C n = 1
+	l	%r5, 0(up)
+	mlr	%r4, %r5
+	st	%r5, 0(rp)
+	st	%r4, 4(rp)
+	br	%r14
+
+L(ge2):	jne	L(gen)
+
+C n = 2
+	stm	%r6, %r8, 24(%r15)
+	lhi	zero, 0
+
+	l	%r5, 0(up)
+	mlr	%r4, %r5		C u0 * u0
+	l	%r1, 4(up)
+	mlr	%r0, %r1		C u1 * u1
+	st	%r5, 0(rp)
+
+	l	%r7, 0(up)
+	ml	%r6, 4(up)		C u0 * u1
+	alr	%r7, %r7
+	alcr	%r6, %r6
+	alcr	%r0, zero
+
+	alr	%r4, %r7
+	alcr	%r1, %r6
+	alcr	%r0, zero
+	st	%r4, 4(rp)
+	st	%r1, 8(rp)
+	st	%r0, 12(rp)
+
+	lm	%r6, %r8, 24(%r15)
+	br	%r14
+
+L(gen):
+C mul_1 =======================================================================
+
+	stm	%r6, %r14, 24(%r15)
+	lhi	zero, 0
+	lr	up_saved, up
+	lr	rp_saved, rp
+	lr	n_saved, n
+
+	l	%r6, 0(up)
+	l	%r11, 4(up)
+	lhi	%r12, 8		C init index register
+	mlr	%r10, %r6
+	lr	%r5, n
+	st	%r11, 4(rp)
+	cr	%r15, %r15		C clear carry flag
+
+L(tm):	l	%r1, 0(%r12,up)
+	mlr	%r0, %r6
+	alcr	%r1, %r10
+	lr	%r10, %r0		C copy high part to carry limb
+	st	%r1, 0(%r12,rp)
+	la	%r12, 4(%r12)
+	brct	%r5, L(tm)
+
+	alcr	%r0, zero
+	st	%r0, 0(%r12,rp)
+
+C addmul_1 loop ===============================================================
+
+	ahi	n, -1
+	je	L(outer_end)
+L(outer_loop):
+
+	la	rp, 8(rp)		C rp += 2
+	la	up, 4(up)		C up += 1
+	l	%r6, 0(up)
+	l	%r11, 4(up)
+	lhi	%r12, 8		C init index register
+	mlr	%r10, %r6
+	lr	%r5, n
+	al	%r11, 4(rp)
+	st	%r11, 4(rp)
+
+L(tam):	l	%r1, 0(%r12,up)
+	l	%r7, 0(%r12,rp)
+	mlr	%r0, %r6
+	alcr	%r1, %r7
+	alcr	%r0, zero
+	alr	%r1, %r10
+	lr	%r10, %r0
+	st	%r1, 0(%r12,rp)
+	la	%r12, 4(%r12)
+	brct	%r5, L(tam)
+
+	alcr	%r0, zero
+	st	%r0, 0(%r12,rp)
+
+	brct	n, L(outer_loop)
+L(outer_end):
+
+	l	%r6, 4(up)
+	l	%r1, 8(up)
+	lr	%r7, %r0		C Same as: l %r7, 12(,rp)
+	mlr	%r0, %r6
+	alr	%r1, %r7
+	alcr	%r0, zero
+	st	%r1, 12(rp)
+	st	%r0, 16(rp)
+
+C sqr_diag_addlsh1 ============================================================
+
+define(`up', `up_saved')
+define(`rp', `rp_saved')
+	la	n, 1(n_saved)
+
+	l	%r1, 0(up)
+	mlr	%r0, %r1
+	st	%r1, 0(rp)
+C	clr	%r15, %r15		C clear carry (already clear per above)
+
+L(top):	l	%r11, 4(up)
+	la	up, 4(up)
+	l	%r6, 4(rp)
+	l	%r7, 8(rp)
+	mlr	%r10, %r11
+	alcr	%r6, %r6
+	alcr	%r7, %r7
+	alcr	%r10, zero		C propagate carry to high product limb
+	alr	%r6, %r0
+	alcr	%r7, %r11
+	stm	%r6, %r7, 4(rp)
+	la	rp, 8(rp)
+	lr	%r0, %r10		C copy carry limb
+	brct	n, L(top)
+
+	alcr	%r0, zero
+	st	%r0, 4(rp)
+
+	lm	%r6, %r14, 24(%r15)
+	br	%r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/s390_32/esame/submul_1.asm b/third_party/gmp/mpn/s390_32/esame/submul_1.asm
new file mode 100644
index 0000000..a71e57e
--- /dev/null
+++ b/third_party/gmp/mpn/s390_32/esame/submul_1.asm
@@ -0,0 +1,70 @@
+dnl  S/390-32 mpn_submul_1 for systems with MLR instruction.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C            cycles/limb
+C z900		20
+C z990		11
+C z9		 ?
+C z10		 ?
+C z196		 ?
+
+C INPUT PARAMETERS
+define(`rp',	`%r2')
+define(`up',	`%r3')
+define(`n',	`%r4')
+define(`v0',	`%r5')
+
+ASM_START()
+PROLOGUE(mpn_submul_1)
+	stm	%r9, %r12, 36(%r15)
+	lhi	%r12, 0
+	slr	%r11, %r11
+
+L(top):	l	%r1, 0(%r12, up)
+	l	%r10, 0(%r12, rp)
+	mlr	%r0, v0
+	slbr	%r10, %r1
+	slbr	%r9, %r9
+	slr	%r0, %r9		C conditional incr
+	slr	%r10, %r11
+	lr	%r11, %r0
+	st	%r10, 0(%r12, rp)
+	la	%r12, 4(%r12)
+	brct	%r4,  L(top)
+
+	lr	%r2, %r11
+	slbr	%r9, %r9
+	slr	%r2, %r9
+
+	lm	%r9, %r12, 36(%r15)
+	br	%r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/s390_32/gmp-mparam.h b/third_party/gmp/mpn/s390_32/gmp-mparam.h
new file mode 100644
index 0000000..1aca74a
--- /dev/null
+++ b/third_party/gmp/mpn/s390_32/gmp-mparam.h
@@ -0,0 +1,138 @@
+/* S/390-32 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 2000-2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+/* 770 MHz IBM z900 running in 32-bit mode, using just traditional insns */
+
+#define DIVREM_1_NORM_THRESHOLD              0  /* always */
+#define DIVREM_1_UNNORM_THRESHOLD            5
+#define MOD_1_1P_METHOD                      2
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               5
+#define MOD_1N_TO_MOD_1_1_THRESHOLD      MP_SIZE_T_MAX  /* never */
+#define MOD_1U_TO_MOD_1_1_THRESHOLD         15
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD         0  /* never mpn_mod_1_1p */
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        30
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD  MP_SIZE_T_MAX  /* never */
+#define USE_PREINV_DIVREM_1                  1
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always */
+#define BMOD_1_TO_MOD_1_THRESHOLD        MP_SIZE_T_MAX  /* never */
+
+#define MUL_TOOM22_THRESHOLD                19
+#define MUL_TOOM33_THRESHOLD               114
+#define MUL_TOOM44_THRESHOLD               166
+#define MUL_TOOM6H_THRESHOLD               226
+#define MUL_TOOM8H_THRESHOLD               333
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD     106
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     122
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     105
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     113
+
+#define SQR_BASECASE_THRESHOLD               7
+#define SQR_TOOM2_THRESHOLD                 40
+#define SQR_TOOM3_THRESHOLD                126
+#define SQR_TOOM4_THRESHOLD                192
+#define SQR_TOOM6_THRESHOLD                246
+#define SQR_TOOM8_THRESHOLD                357
+
+#define MULMID_TOOM42_THRESHOLD             28
+
+#define MULMOD_BNM1_THRESHOLD               12
+#define SQRMOD_BNM1_THRESHOLD               18
+
+#define MUL_FFT_MODF_THRESHOLD             244  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    244, 5}, {     13, 6}, {      7, 5}, {     15, 6}, \
+    {      8, 5}, {     17, 6}, {     13, 7}, {      7, 6}, \
+    {     16, 7}, {      9, 6}, {     19, 7}, {     11, 6}, \
+    {     23, 7}, {     13, 8}, {      7, 7}, {     19, 8}, \
+    {     11, 7}, {     25, 9}, {      7, 8}, {     15, 7}, \
+    {     33, 8}, {     19, 7}, {     39, 8}, {     23, 7}, \
+    {     47, 8}, {     27, 9}, {     15, 8}, {     39, 9}, \
+    {     23, 8}, {     47,10}, {     15, 9}, {     31, 8}, \
+    {     63, 9}, {     39, 8}, {     79, 9}, {     47,10}, \
+    {     31, 9}, {     63, 8}, {    127, 9}, {     71, 8}, \
+    {    143, 9}, {     79,10}, {     47,11}, {   2048,12}, \
+    {   4096,13}, {   8192,14}, {  16384,15}, {  32768,16} }
+#define MUL_FFT_TABLE3_SIZE 48
+#define MUL_FFT_THRESHOLD                 2688
+
+#define SQR_FFT_MODF_THRESHOLD             216  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    216, 5}, {      7, 4}, {     15, 5}, {     17, 6}, \
+    {     13, 7}, {      7, 6}, {     17, 7}, {      9, 6}, \
+    {     20, 7}, {     11, 6}, {     23, 7}, {     13, 8}, \
+    {      7, 7}, {     19, 8}, {     11, 7}, {     25, 9}, \
+    {      7, 8}, {     15, 7}, {     33, 8}, {     19, 7}, \
+    {     39, 8}, {     23, 9}, {     15, 8}, {     39, 9}, \
+    {     23, 8}, {     47,10}, {     15, 9}, {     31, 8}, \
+    {     63, 9}, {     39, 8}, {     79, 9}, {     47,10}, \
+    {     31, 9}, {     63, 8}, {    127, 9}, {     71, 8}, \
+    {    143, 9}, {     79,10}, {     47,11}, {   2048,12}, \
+    {   4096,13}, {   8192,14}, {  16384,15}, {  32768,16} }
+#define SQR_FFT_TABLE3_SIZE 44
+#define SQR_FFT_THRESHOLD                 1856
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  61
+#define MULLO_MUL_N_THRESHOLD             5240
+
+#define DC_DIV_QR_THRESHOLD                 70
+#define DC_DIVAPPR_Q_THRESHOLD             234
+#define DC_BDIV_QR_THRESHOLD                59
+#define DC_BDIV_Q_THRESHOLD                137
+
+#define INV_MULMOD_BNM1_THRESHOLD           36
+#define INV_NEWTON_THRESHOLD               327
+#define INV_APPR_THRESHOLD                 268
+
+#define BINV_NEWTON_THRESHOLD              324
+#define REDC_1_TO_REDC_N_THRESHOLD          63
+
+#define MU_DIV_QR_THRESHOLD               1099
+#define MU_DIVAPPR_Q_THRESHOLD            1360
+#define MUPI_DIV_QR_THRESHOLD              138
+#define MU_BDIV_QR_THRESHOLD               889
+#define MU_BDIV_Q_THRESHOLD               1234
+
+#define MATRIX22_STRASSEN_THRESHOLD         18
+#define HGCD_THRESHOLD                     167
+#define GCD_DC_THRESHOLD                   518
+#define GCDEXT_DC_THRESHOLD                378
+#define JACOBI_BASE_METHOD                   2
+
+#define GET_STR_DC_THRESHOLD                14
+#define GET_STR_PRECOMPUTE_THRESHOLD        25
+#define SET_STR_DC_THRESHOLD               577
+#define SET_STR_PRECOMPUTE_THRESHOLD      1217
diff --git a/third_party/gmp/mpn/s390_32/logops_n.asm b/third_party/gmp/mpn/s390_32/logops_n.asm
new file mode 100644
index 0000000..1f2cd2a
--- /dev/null
+++ b/third_party/gmp/mpn/s390_32/logops_n.asm
@@ -0,0 +1,295 @@
+dnl  S/390-32 logops.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C cycles/limb     variant 1           variant 2       variant 3
+C	        rp!=up  rp=up
+C z900		 ?	 ?		 ?		 ?
+C z990		 2.5	 1		 2.75		 2.75
+C z9		 ?			 ?		 ?
+C z10		 ?			 ?		 ?
+C z196		 ?			 ?		 ?
+
+C INPUT PARAMETERS
+define(`rp',	`%r2')
+define(`up',	`%r3')
+define(`vp',	`%r4')
+define(`nn',	`%r5')
+
+ifdef(`OPERATION_and_n',`
+  define(`func',`mpn_and_n')
+  define(`VARIANT_1')
+  define(`LOGOPC',`nc')
+  define(`LOGOP',`n')')
+ifdef(`OPERATION_andn_n',`
+  define(`func',`mpn_andn_n')
+  define(`VARIANT_2')
+  define(`LOGOP',`n')')
+ifdef(`OPERATION_nand_n',`
+  define(`func',`mpn_nand_n')
+  define(`VARIANT_3')
+  define(`LOGOP',`n')')
+ifdef(`OPERATION_ior_n',`
+  define(`func',`mpn_ior_n')
+  define(`VARIANT_1')
+  define(`LOGOPC',`oc')
+  define(`LOGOP',`o')')
+ifdef(`OPERATION_iorn_n',`
+  define(`func',`mpn_iorn_n')
+  define(`VARIANT_2')
+  define(`LOGOP',`o')')
+ifdef(`OPERATION_nior_n',`
+  define(`func',`mpn_nior_n')
+  define(`VARIANT_3')
+  define(`LOGOP',`o')')
+ifdef(`OPERATION_xor_n',`
+  define(`func',`mpn_xor_n')
+  define(`VARIANT_1')
+  define(`LOGOPC',`xc')
+  define(`LOGOP',`x')')
+ifdef(`OPERATION_xnor_n',`
+  define(`func',`mpn_xnor_n')
+  define(`VARIANT_2')
+  define(`LOGOP',`x')')
+
+MULFUNC_PROLOGUE(mpn_and_n mpn_andn_n mpn_nand_n mpn_ior_n mpn_iorn_n mpn_nior_n mpn_xor_n mpn_xnor_n)
+
+ASM_START()
+PROLOGUE(func)
+ifdef(`VARIANT_1',`
+	cr	rp, up
+	jne	L(normal)
+
+	sll	nn, 2
+	ahi	nn, -1
+	lr	%r1, nn
+	srl	%r1, 8
+	ltr	%r1, %r1		C < 256 bytes to copy?
+	je	L(1)
+
+L(tp):	LOGOPC	0(256, rp), 0(vp)
+	la	rp, 256(rp)
+	la	vp, 256(vp)
+	brct	%r1, L(tp)
+
+L(1):	bras	%r1, L(2)		C make r1 point to mvc insn
+	LOGOPC	0(1, rp), 0(vp)
+L(2):	ex	nn, 0(%r1)		C execute mvc with length ((nn-1) mod 256)+1
+L(rtn):	br	%r14
+
+
+L(normal):
+	stm	%r6, %r8, 12(%r15)
+	ahi	nn, 3
+	lhi	%r7, 3
+	lr	%r0, nn
+	srl	%r0, 2
+	nr	%r7, nn			C nn mod 4
+	je	L(b1)
+	chi	%r7, 2
+	jl	L(b2)
+	jne	L(top)
+
+L(b3):	lm	%r5, %r7, 0(up)
+	la	up, 12(up)
+	LOGOP	%r5, 0(vp)
+	LOGOP	%r6, 4(vp)
+	LOGOP	%r7, 8(vp)
+	stm	%r5, %r7, 0(rp)
+	la	rp, 12(rp)
+	la	vp, 12(vp)
+	j	L(mid)
+
+L(b1):	l	%r5, 0(up)
+	la	up, 4(up)
+	LOGOP	%r5, 0(vp)
+	st	%r5, 0(rp)
+	la	rp, 4(rp)
+	la	vp, 4(vp)
+	j	L(mid)
+
+L(b2):	lm	%r5, %r6, 0(up)
+	la	up, 8(up)
+	LOGOP	%r5, 0(vp)
+	LOGOP	%r6, 4(vp)
+	stm	%r5, %r6, 0(rp)
+	la	rp, 8(rp)
+	la	vp, 8(vp)
+	j	L(mid)
+
+L(top):	lm	%r5, %r8, 0(up)
+	la	up, 16(up)
+	LOGOP	%r5, 0(vp)
+	LOGOP	%r6, 4(vp)
+	LOGOP	%r7, 8(vp)
+	LOGOP	%r8, 12(vp)
+	stm	%r5, %r8, 0(rp)
+	la	rp, 16(rp)
+	la	vp, 16(vp)
+L(mid):	brct	%r0, L(top)
+
+	lm	%r6, %r8, 12(%r15)
+	br	%r14
+')
+
+ifdef(`VARIANT_2',`
+	stm	%r6, %r8, 12(%r15)
+	lhi	%r1, -1
+
+	ahi	nn, 3
+	lhi	%r7, 3
+	lr	%r0, nn
+	srl	%r0, 2
+	nr	%r7, nn			C nn mod 4
+	je	L(b1)
+	chi	%r7, 2
+	jl	L(b2)
+	jne	L(top)
+
+L(b3):	lm	%r5, %r7, 0(vp)
+	la	vp, 12(vp)
+	xr	%r5, %r1
+	xr	%r6, %r1
+	xr	%r7, %r1
+	LOGOP	%r5, 0(up)
+	LOGOP	%r6, 4(up)
+	LOGOP	%r7, 8(up)
+	stm	%r5, %r7, 0(rp)
+	la	rp, 12(rp)
+	la	up, 12(up)
+	j	L(mid)
+
+L(b1):	l	%r5, 0(vp)
+	la	vp, 4(vp)
+	xr	%r5, %r1
+	LOGOP	%r5, 0(up)
+	st	%r5, 0(rp)
+	la	rp, 4(rp)
+	la	up, 4(up)
+	j	L(mid)
+
+L(b2):	lm	%r5, %r6, 0(vp)
+	la	vp, 8(vp)
+	xr	%r5, %r1
+	xr	%r6, %r1
+	LOGOP	%r5, 0(up)
+	LOGOP	%r6, 4(up)
+	stm	%r5, %r6, 0(rp)
+	la	rp, 8(rp)
+	la	up, 8(up)
+	j	L(mid)
+
+L(top):	lm	%r5, %r8, 0(vp)
+	la	vp, 16(vp)
+	xr	%r5, %r1
+	xr	%r6, %r1
+	xr	%r7, %r1
+	xr	%r8, %r1
+	LOGOP	%r5, 0(up)
+	LOGOP	%r6, 4(up)
+	LOGOP	%r7, 8(up)
+	LOGOP	%r8, 12(up)
+	la	up, 16(up)
+	stm	%r5, %r8, 0(rp)
+	la	rp, 16(rp)
+L(mid):	brct	%r0, L(top)
+
+	lm	%r6, %r8, 12(%r15)
+	br	%r14
+')
+
+ifdef(`VARIANT_3',`
+	stm	%r6, %r8, 12(%r15)
+	lhi	%r1, -1
+
+	ahi	nn, 3
+	lhi	%r7, 3
+	lr	%r0, nn
+	srl	%r0, 2
+	nr	%r7, nn			C nn mod 4
+	je	L(b1)
+	chi	%r7, 2
+	jl	L(b2)
+	jne	L(top)
+
+L(b3):	lm	%r5, %r7, 0(vp)
+	la	vp, 12(vp)
+	LOGOP	%r5, 0(up)
+	LOGOP	%r6, 4(up)
+	xr	%r5, %r1
+	xr	%r6, %r1
+	LOGOP	%r7, 8(up)
+	xr	%r7, %r1
+	stm	%r5, %r7, 0(rp)
+	la	rp, 12(rp)
+	la	up, 12(up)
+	j	L(mid)
+
+L(b1):	l	%r5, 0(vp)
+	la	vp, 4(vp)
+	LOGOP	%r5, 0(up)
+	xr	%r5, %r1
+	st	%r5, 0(rp)
+	la	rp, 4(rp)
+	la	up, 4(up)
+	j	L(mid)
+
+L(b2):	lm	%r5, %r6, 0(vp)
+	la	vp, 8(vp)
+	LOGOP	%r5, 0(up)
+	LOGOP	%r6, 4(up)
+	xr	%r5, %r1
+	xr	%r6, %r1
+	stm	%r5, %r6, 0(rp)
+	la	rp, 8(rp)
+	la	up, 8(up)
+	j	L(mid)
+
+L(top):	lm	%r5, %r8, 0(vp)
+	la	vp, 16(vp)
+	LOGOP	%r5, 0(up)
+	LOGOP	%r6, 4(up)
+	xr	%r5, %r1
+	xr	%r6, %r1
+	LOGOP	%r7, 8(up)
+	LOGOP	%r8, 12(up)
+	xr	%r7, %r1
+	xr	%r8, %r1
+	stm	%r5, %r8, 0(rp)
+	la	up, 16(up)
+	la	rp, 16(rp)
+L(mid):	brct	%r0, L(top)
+
+	lm	%r6, %r8, 12(%r15)
+	br	%r14
+')
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/s390_32/lshift.asm b/third_party/gmp/mpn/s390_32/lshift.asm
new file mode 100644
index 0000000..da7d76e
--- /dev/null
+++ b/third_party/gmp/mpn/s390_32/lshift.asm
@@ -0,0 +1,144 @@
+dnl  S/390-32 mpn_lshift.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C            cycles/limb
+C z900		 6
+C z990	         3
+C z9		 ?
+C z10		 ?
+C z196		 ?
+
+C TODO
+C  *
+
+C INPUT PARAMETERS
+define(`rp',	`%r2')
+define(`up',	`%r3')
+define(`n',	`%r4')
+define(`cnt',	`%r5')
+
+ASM_START()
+PROLOGUE(mpn_lshift)
+	lr	%r1, n
+	sll	%r1, 2
+	stm	%r6, %r12, 24(%r15)
+	la	up, 0(%r1,up)		C put up near end of U
+	la	rp, 0(%r1,rp)		C put rp near end of R
+	ahi	up, -20
+	ahi	rp, -16
+	lhi	%r8, 32
+	sr	%r8, cnt
+	l	%r12, 16(up)
+	srl	%r12, 0(%r8)		C return value
+	lhi	%r7, 3
+	nr	%r7, n
+	srl	n, 2
+	je	L(b0)
+	chi	%r7, 2
+	jl	L(b1)
+	je	L(b2)
+
+L(b3):	l	%r10, 16(up)
+	l	%r11, 12(up)
+	l	%r9,   8(up)
+	ahi	up, -8
+	lr	%r8, %r11
+	sldl	%r10, 0(cnt)
+	sldl	%r8,  0(cnt)
+	st	%r10, 12(rp)
+	st	%r8,   8(rp)
+	ahi	rp, -8
+	ltr	n, n
+	je	L(end)
+	j	L(top)
+
+L(b2):	l	%r10, 16(up)
+	l	%r11, 12(up)
+	ahi	up, -4
+	sldl	%r10, 0(cnt)
+	st	%r10, 12(rp)
+	ahi	rp, -4
+	ltr	n, n
+	je	L(end)
+	j	L(top)
+
+L(b1):	ltr	n, n
+	je	L(end)
+	j	L(top)
+
+L(b0):	l	%r10,16(up)
+	l	%r8, 12(up)
+	l	%r6,  8(up)
+	l	%r0,  4(up)
+	ahi	up, -12
+	lr	%r11, %r8
+	lr	%r9,  %r6
+	lr	%r7,  %r0
+	sldl	%r10,0(cnt)
+	sldl	%r8, 0(cnt)
+	sldl	%r6, 0(cnt)
+	st	%r10, 12(rp)
+	st	%r8,   8(rp)
+	st	%r6,   4(rp)
+	ahi	rp, -12
+	ahi	n, -1
+	je	L(end)
+
+	ALIGN(8)
+L(top):	l	%r10, 16(up)
+	l	%r8,  12(up)
+	l	%r6,   8(up)
+	l	%r0,   4(up)
+	l	%r1,   0(up)
+	lr	%r11, %r8
+	lr	%r9,  %r6
+	lr	%r7,  %r0
+	ahi	up, -16
+	sldl	%r10, 0(cnt)
+	sldl	%r8,  0(cnt)
+	sldl	%r6,  0(cnt)
+	sldl	%r0,  0(cnt)
+	st	%r10, 12(rp)
+	st	%r8,   8(rp)
+	st	%r6,   4(rp)
+	st	%r0,   0(rp)
+	ahi	rp, -16
+	brct	n, L(top)
+
+L(end):	l	%r10, 16(up)
+	sll	%r10, 0(cnt)
+	st	%r10, 12(rp)
+
+	lr	%r2, %r12
+	lm	%r6, %r12, 24(%r15)
+	br	%r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/s390_32/lshiftc.asm b/third_party/gmp/mpn/s390_32/lshiftc.asm
new file mode 100644
index 0000000..f601673
--- /dev/null
+++ b/third_party/gmp/mpn/s390_32/lshiftc.asm
@@ -0,0 +1,156 @@
+dnl  S/390-32 mpn_lshiftc.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C            cycles/limb
+C z900		 7
+C z990	         3.375
+C z9		 ?
+C z10		 ?
+C z196		 ?
+
+C TODO
+C  *
+
+C INPUT PARAMETERS
+define(`rp',	`%r2')
+define(`up',	`%r3')
+define(`n',	`%r4')
+define(`cnt',	`%r5')
+
+ASM_START()
+PROLOGUE(mpn_lshiftc)
+	lr	%r1, n
+	sll	%r1, 2
+	stm	%r6, %r13, 24(%r15)
+	la	up, 0(%r1,up)		C put up near end of U
+	la	rp, 0(%r1,rp)		C put rp near end of R
+	ahi	up, -20
+	ahi	rp, -16
+	lhi	%r8, 32
+	sr	%r8, cnt
+	l	%r12, 16(up)
+	srl	%r12, 0(%r8)		C return value
+	lhi	%r13, -1
+	lhi	%r7, 3
+	nr	%r7, n
+	srl	n, 2
+	je	L(b0)
+	chi	%r7, 2
+	jl	L(b1)
+	je	L(b2)
+
+L(b3):	l	%r10, 16(up)
+	l	%r11, 12(up)
+	l	%r9,   8(up)
+	ahi	up, -8
+	lr	%r8, %r11
+	sldl	%r10, 0(cnt)
+	sldl	%r8,  0(cnt)
+	xr	%r10, %r13
+	xr	%r8, %r13
+	st	%r10, 12(rp)
+	st	%r8,   8(rp)
+	ahi	rp, -8
+	ltr	n, n
+	je	L(end)
+	j	L(top)
+
+L(b2):	l	%r10, 16(up)
+	l	%r11, 12(up)
+	ahi	up, -4
+	sldl	%r10, 0(cnt)
+	xr	%r10, %r13
+	st	%r10, 12(rp)
+	ahi	rp, -4
+	ltr	n, n
+	je	L(end)
+	j	L(top)
+
+L(b1):	ltr	n, n
+	je	L(end)
+	j	L(top)
+
+L(b0):	l	%r10,16(up)
+	l	%r8, 12(up)
+	l	%r6,  8(up)
+	l	%r0,  4(up)
+	ahi	up, -12
+	lr	%r11, %r8
+	lr	%r9,  %r6
+	lr	%r7,  %r0
+	sldl	%r10,0(cnt)
+	sldl	%r8, 0(cnt)
+	sldl	%r6, 0(cnt)
+	xr	%r10, %r13
+	xr	%r8, %r13
+	xr	%r6, %r13
+	st	%r10, 12(rp)
+	st	%r8,   8(rp)
+	st	%r6,   4(rp)
+	ahi	rp, -12
+	ahi	n, -1
+	je	L(end)
+
+	ALIGN(8)
+L(top):	l	%r10, 16(up)
+	l	%r8,  12(up)
+	l	%r6,   8(up)
+	l	%r0,   4(up)
+	l	%r1,   0(up)
+	lr	%r11, %r8
+	lr	%r9,  %r6
+	lr	%r7,  %r0
+	ahi	up, -16
+	sldl	%r10, 0(cnt)
+	sldl	%r8,  0(cnt)
+	sldl	%r6,  0(cnt)
+	sldl	%r0,  0(cnt)
+	xr	%r10, %r13
+	xr	%r8, %r13
+	xr	%r6, %r13
+	xr	%r0, %r13
+	st	%r10, 12(rp)
+	st	%r8,   8(rp)
+	st	%r6,   4(rp)
+	st	%r0,   0(rp)
+	ahi	rp, -16
+	brct	n, L(top)
+
+L(end):	l	%r10, 16(up)
+	sll	%r10, 0(cnt)
+	xr	%r10, %r13
+	st	%r10, 12(rp)
+
+	lr	%r2, %r12
+	lm	%r6, %r13, 24(%r15)
+	br	%r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/s390_32/mul_1.asm b/third_party/gmp/mpn/s390_32/mul_1.asm
new file mode 100644
index 0000000..e3ad0c5
--- /dev/null
+++ b/third_party/gmp/mpn/s390_32/mul_1.asm
@@ -0,0 +1,85 @@
+dnl  S/390 mpn_mul_1 -- Multiply a limb vector with a limb and store the
+dnl  result in a second limb vector.
+
+dnl  Copyright 2001 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+define(`rp',2)
+define(`up',3)
+define(`n',4)
+define(`vlimb',5)
+define(`cylimb',7)
+
+ASM_START()
+PROLOGUE(mpn_mul_1)
+	stm	6,7,24(15)
+	slr	cylimb,cylimb	# clear cylimb
+	ltr	vlimb,vlimb
+	jnl	.Loopp
+
+.Loopn:	l	1,0(up)		# load from u
+	lr	6,1		#
+	mr	0,vlimb		# multiply signed
+	alr	0,6		# add vlimb to phi
+	sra	6,31		# make mask
+	nr	6,vlimb		# 0 or vlimb
+	alr	0,6		# conditionally add vlimb to phi
+	alr	1,cylimb	# add carry limb to plo
+	brc	8+4,+8		# branch if not carry
+	ahi	0,1		# increment phi
+	lr	cylimb,0	# new cylimb
+	st	1,0(rp)		# store
+	la	up,4(,up)
+	la	rp,4(,rp)
+	brct	n,.Loopn
+
+	lr	2,cylimb
+	lm	6,7,24(15)
+	br	14
+
+.Loopp:	l	1,0(up)		# load from u
+	lr	6,1		#
+	mr	0,vlimb		# multiply signed
+	sra	6,31		# make mask
+	nr	6,vlimb		# 0 or vlimb
+	alr	0,6		# conditionally add vlimb to phi
+	alr	1,cylimb	# add carry limb to plo
+	brc	8+4,+8		# branch if not carry
+	ahi	0,1		# increment phi
+	lr	cylimb,0	# new cylimb
+	st	1,0(rp)		# store
+	la	up,4(,up)
+	la	rp,4(,rp)
+	brct	n,.Loopp
+
+	lr	2,cylimb
+	lm	6,7,24(15)
+	br	14
+EPILOGUE(mpn_mul_1)
diff --git a/third_party/gmp/mpn/s390_32/rshift.asm b/third_party/gmp/mpn/s390_32/rshift.asm
new file mode 100644
index 0000000..5f2cf37
--- /dev/null
+++ b/third_party/gmp/mpn/s390_32/rshift.asm
@@ -0,0 +1,138 @@
+dnl  S/390-32 mpn_rshift.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C            cycles/limb
+C z900		 6
+C z990	         3
+C z9		 ?
+C z10		 ?
+C z196		 ?
+
+C TODO
+C  *
+
+C INPUT PARAMETERS
+define(`rp',	`%r2')
+define(`up',	`%r3')
+define(`n',	`%r4')
+define(`cnt',	`%r5')
+
+ASM_START()
+PROLOGUE(mpn_rshift)
+	stm	%r6, %r12, 24(%r15)
+	lhi	%r8, 32
+	sr	%r8, cnt
+	l	%r12, 0(up)
+	sll	%r12, 0(%r8)		C return value
+	lhi	%r7, 3
+	nr	%r7, n
+	srl	n, 2
+	je	L(b0)
+	chi	%r7, 2
+	jl	L(b1)
+	je	L(b2)
+
+L(b3):	l	%r11, 0(up)
+	l	%r10, 4(up)
+	l	%r8,  8(up)
+	ahi	up, 8
+	lr	%r9, %r10
+	srdl	%r10, 0(cnt)
+	srdl	%r8,  0(cnt)
+	st	%r11, 0(rp)
+	st	%r9,  4(rp)
+	ahi	rp, 8
+	ltr	n, n
+	je	L(end)
+	j	L(top)
+
+L(b2):	l	%r11, 0(up)
+	l	%r10, 4(up)
+	ahi	up, 4
+	srdl	%r10, 0(cnt)
+	st	%r11, 0(rp)
+	ahi	rp, 4
+	ltr	n, n
+	je	L(end)
+	j	L(top)
+
+L(b1):	ltr	n, n
+	je	L(end)
+	j	L(top)
+
+L(b0):	l	%r11, 0(up)
+	l	%r9,  4(up)
+	l	%r7,  8(up)
+	l	%r1, 12(up)
+	ahi	up, 12
+	lr	%r10, %r9
+	lr	%r8,  %r7
+	lr	%r6,  %r1
+	srdl	%r10, 0(cnt)
+	srdl	%r8,  0(cnt)
+	srdl	%r6,  0(cnt)
+	st	%r11, 0(rp)
+	st	%r9,  4(rp)
+	st	%r7,  8(rp)
+	ahi	rp, 12
+	ahi	n, -1
+	je	L(end)
+
+	ALIGN(8)
+L(top):	l	%r11, 0(up)
+	l	%r9,  4(up)
+	l	%r7,  8(up)
+	l	%r1, 12(up)
+	l	%r0, 16(up)
+	lr	%r10, %r9
+	lr	%r8,  %r7
+	lr	%r6,  %r1
+	ahi	up, 16
+	srdl	%r10, 0(cnt)
+	srdl	%r8,  0(cnt)
+	srdl	%r6,  0(cnt)
+	srdl	%r0,  0(cnt)
+	st	%r11, 0(rp)
+	st	%r9,  4(rp)
+	st	%r7,  8(rp)
+	st	%r1, 12(rp)
+	ahi	rp, 16
+	brct	n, L(top)
+
+L(end):	l	%r11, 0(up)
+	srl	%r11, 0(cnt)
+	st	%r11, 0(rp)
+
+	lr	%r2, %r12
+	lm	%r6, %r12, 24(%r15)
+	br	%r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/s390_32/submul_1.asm b/third_party/gmp/mpn/s390_32/submul_1.asm
new file mode 100644
index 0000000..da7d849
--- /dev/null
+++ b/third_party/gmp/mpn/s390_32/submul_1.asm
@@ -0,0 +1,93 @@
+dnl  S/390 mpn_submul_1 -- Multiply a limb vector with a limb and subtract the
+dnl  result from a second limb vector.
+
+dnl  Copyright 2001 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+define(`rp',2)
+define(`up',3)
+define(`n',4)
+define(`vlimb',5)
+define(`cylimb',7)
+
+ASM_START()
+PROLOGUE(mpn_submul_1)
+	stm	6,7,24(15)
+	slr	cylimb,cylimb	# clear cylimb
+	ltr	vlimb,vlimb
+	jnl	.Loopp
+
+.Loopn:	l	1,0(up)		# load from u
+	lr	6,1		#
+	mr	0,vlimb		# multiply signed
+	alr	0,6		# add vlimb to phi
+	sra	6,31		# make mask
+	nr	6,vlimb		# 0 or vlimb
+	alr	0,6		# conditionally add vlimb to phi
+	alr	1,cylimb	# add carry limb to plo
+	brc	8+4,+8		# branch if not carry
+	ahi	0,1		# increment phi
+	l	6,0(rp)		# load r limb
+	slr	6,1		# add u limb to plo
+	brc	2+1,+8		# branch if not carry
+	ahi	0,1		# increment phi
+	lr	cylimb,0	# new cylimb
+	st	6,0(rp)		# store
+	la	up,4(,up)
+	la	rp,4(,rp)
+	brct	n,.Loopn
+
+	lr	2,cylimb
+	lm	6,7,24(15)
+	br	14
+
+.Loopp:	l	1,0(up)		# load from u
+	lr	6,1		#
+	mr	0,vlimb		# multiply signed
+	sra	6,31		# make mask
+	nr	6,vlimb		# 0 or vlimb
+	alr	0,6		# conditionally add vlimb to phi
+	alr	1,cylimb	# add carry limb to plo
+	brc	8+4,+8		# branch if not carry
+	ahi	0,1		# increment phi
+	l	6,0(rp)		# load r limb
+	slr	6,1		# add u limb to plo
+	brc	2+1,+8		# branch if not carry
+	ahi	0,1		# increment phi
+	lr	cylimb,0	# new cylimb
+	st	6,0(rp)		# store
+	la	up,4(,up)
+	la	rp,4(,rp)
+	brct	n,.Loopp
+
+	lr	2,cylimb
+	lm	6,7,24(15)
+	br	14
+EPILOGUE(mpn_submul_1)
diff --git a/third_party/gmp/mpn/s390_64/README b/third_party/gmp/mpn/s390_64/README
new file mode 100644
index 0000000..53702db
--- /dev/null
+++ b/third_party/gmp/mpn/s390_64/README
@@ -0,0 +1,88 @@
+Copyright 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.
+
+
+
+There are 5 generations of 64-bit s390 processors, z900, z990, z9,
+z10, and z196.  The current GMP code was optimised for the two oldest,
+z900 and z990.
+
+
+mpn_copyi
+
+This code makes use of a loop around MVC.  It almost surely runs very
+close to optimally.  A small improvement could be done by using one
+MVC for size 256 bytes, now we use two (we use an extra MVC when
+copying any multiple of 256 bytes).
+
+
+mpn_copyd
+
+We have tried several feed-in variants here, branch tree, jump table
+and computed goto.  The fastest (on z990) turned out to be computed
+goto.
+
+An approach not tried is EX of LMG and STMG, modifying the register set
+on-the-fly.  Using that trick, we could completely avoid using
+separate feed-in paths.
+
+
+mpn_lshift, mpn_rshift
+
+The current code runs at pipeline decode bandwidth on z990.
+
+
+mpn_add_n, mpn_sub_n
+
+The current code is 4-way unrolled.  It should be unrolled more, at
+least 8x, in order to reach 2.5 c/l.
+
+
+mpn_mul_1, mpn_addmul_1, mpn_submul_1
+
+The current code is very naive, but due to the non-pipelined nature of
+MLGR on z900 and z990, more sophisticated code would not gain much.
+
+On z10 one would need to cluster at least 4 MLGR together, in order to
+reduce stalling.
+
+On z196, one surely want to use unrolling and pipelining, to perhaps
+reach around 12 c/l.  A major issue here and on z10 is ALCGR's 3 cycle
+stalling.
+
+
+mpn_mul_2, mpn_addmul_2
+
+At least for older machines (z900, z990) with very slow MLGR, we
+should use Karatsuba's algorithm on 2-limb units, making mul_2 and
+addmul_2 the main multiplication primitives.  The newer machines might
+benefit less from this approach, perhaps in particular z10, where MLGR
+clustering is more important.
+
+With Karatsuba, one could hope for around 16 cycles per accumulated
+128 cross product, on z990.
diff --git a/third_party/gmp/mpn/s390_64/addmul_1.asm b/third_party/gmp/mpn/s390_64/addmul_1.asm
new file mode 100644
index 0000000..84cca12
--- /dev/null
+++ b/third_party/gmp/mpn/s390_64/addmul_1.asm
@@ -0,0 +1,72 @@
+dnl  S/390-64 mpn_addmul_1
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C            cycles/limb
+C z900		34
+C z990		23
+C z9		 ?
+C z10		28
+C z196		 ?
+
+C INPUT PARAMETERS
+define(`rp',	`%r2')
+define(`up',	`%r3')
+define(`n',	`%r4')
+define(`v0',	`%r5')
+
+define(`z',	`%r9')
+
+ASM_START()
+PROLOGUE(mpn_addmul_1)
+	stmg	%r9, %r12, 72(%r15)
+	lghi	%r12, 0			C zero index register
+	aghi	%r12, 0			C clear carry flag
+	lghi	%r11, 0			C clear carry limb
+	lghi	z, 0			C keep register zero
+
+L(top):	lg	%r1, 0(%r12,up)
+	lg	%r10, 0(%r12,rp)
+	mlgr	%r0, v0
+	alcgr	%r1, %r10
+	alcgr	%r0, z
+	algr	%r1, %r11
+	lgr	%r11, %r0
+	stg	%r1, 0(%r12,rp)
+	la	%r12, 8(%r12)
+	brctg	n, L(top)
+
+	lghi	%r2, 0
+	alcgr	%r2, %r11
+
+	lmg	%r9, %r12, 72(%r15)
+	br	%r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/s390_64/aorrlsh1_n.asm b/third_party/gmp/mpn/s390_64/aorrlsh1_n.asm
new file mode 100644
index 0000000..697259e
--- /dev/null
+++ b/third_party/gmp/mpn/s390_64/aorrlsh1_n.asm
@@ -0,0 +1,168 @@
+dnl  S/390-64 mpn_addlsh1_n and mpn_rsblsh1_n.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C            cycles/limb
+C z900		 9
+C z990		 4.75
+C z9		 ?
+C z10		11
+C z196		 ?
+
+C TODO
+C  * Optimise for small n, avoid 'la' like in aors_n.asm.
+C  * Tune to reach 3.5 c/l.  For addlsh1, we could let the main alcgr propagate
+C    carry to the lsh1 alcgr.
+C  * Compute RETVAL for sublsh1_n less stupidly.
+
+C INPUT PARAMETERS
+define(`rp',	`%r2')
+define(`up',	`%r3')
+define(`vp',	`%r4')
+define(`n',	`%r5')
+
+ifdef(`OPERATION_addlsh1_n',`
+  define(ADSB,		alg)
+  define(ADSBC,		alcg)
+  define(INITCY,	`lghi	%r9, -1')
+  define(RETVAL,	`la	%r2, 2(%r1,%r9)')
+  define(func, mpn_addlsh1_n)
+')
+ifdef(`OPERATION_rsblsh1_n',`
+  define(ADSB,		slg)
+  define(ADSBC,		slbg)
+  define(INITCY,	`lghi	%r9, 0')
+  define(RETVAL,`dnl
+	algr	%r1, %r9
+	lghi	%r2, 1
+	algr	%r2, %r1')
+  define(func, mpn_rsblsh1_n)
+')
+
+MULFUNC_PROLOGUE(mpn_addlsh1_n mpn_rsblsh1_n)
+
+ASM_START()
+PROLOGUE(func)
+	stmg	%r6, %r9, 48(%r15)
+
+	aghi	n, 3
+	lghi	%r7, 3
+	srlg	%r0, n, 2
+	ngr	%r7, n			C n mod 4
+	je	L(b1)
+	cghi	%r7, 2
+	jl	L(b2)
+	jne	L(b0)
+
+L(b3):	lmg	%r5, %r7, 0(vp)
+	la	vp, 24(vp)
+
+	algr	%r5, %r5
+	alcgr	%r6, %r6
+	alcgr	%r7, %r7
+	slbgr	%r1, %r1
+
+	ADSB	%r5, 0(up)
+	ADSBC	%r6, 8(up)
+	ADSBC	%r7, 16(up)
+	la	up, 24(up)
+	slbgr	%r9, %r9
+
+	stmg	%r5, %r7, 0(rp)
+	la	rp, 24(rp)
+	brctg	%r0, L(top)
+	j	L(end)
+
+L(b0):	lghi	%r1, -1
+	INITCY
+	j	L(top)
+
+L(b1):	lg	%r5, 0(vp)
+	la	vp, 8(vp)
+
+	algr	%r5, %r5
+	slbgr	%r1, %r1
+	ADSB	%r5, 0(up)
+	la	up, 8(up)
+	slbgr	%r9, %r9
+
+	stg	%r5, 0(rp)
+	la	rp, 8(rp)
+	brctg	%r0, L(top)
+	j	L(end)
+
+L(b2):	lmg	%r5, %r6, 0(vp)
+	la	vp, 16(vp)
+
+	algr	%r5, %r5
+	alcgr	%r6, %r6
+	slbgr	%r1, %r1
+
+	ADSB	%r5, 0(up)
+	ADSBC	%r6, 8(up)
+	la	up, 16(up)
+	slbgr	%r9, %r9
+
+	stmg	%r5, %r6, 0(rp)
+	la	rp, 16(rp)
+	brctg	%r0, L(top)
+	j	L(end)
+
+L(top):	lmg	%r5, %r8, 0(vp)
+	la	vp, 32(vp)
+
+	aghi	%r1, 1			C restore carry
+
+	alcgr	%r5, %r5
+	alcgr	%r6, %r6
+	alcgr	%r7, %r7
+	alcgr	%r8, %r8
+
+	slbgr	%r1, %r1		C save carry
+
+	aghi	%r9, 1			C restore carry
+
+	ADSBC	%r5, 0(up)
+	ADSBC	%r6, 8(up)
+	ADSBC	%r7, 16(up)
+	ADSBC	%r8, 24(up)
+	la	up, 32(up)
+
+	slbgr	%r9, %r9		C save carry
+
+	stmg	%r5, %r8, 0(rp)
+	la	rp, 32(rp)
+	brctg	%r0, L(top)
+
+L(end):	RETVAL
+	lmg	%r6, %r9, 48(%r15)
+	br	%r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/s390_64/aors_n.asm b/third_party/gmp/mpn/s390_64/aors_n.asm
new file mode 100644
index 0000000..a3c3ca7
--- /dev/null
+++ b/third_party/gmp/mpn/s390_64/aors_n.asm
@@ -0,0 +1,136 @@
+dnl  S/390-64 mpn_add_n and mpn_sub_n.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C            cycles/limb
+C z900		 5.5
+C z990		 3
+C z9		 ?
+C z10		 6
+C z196		 ?
+
+C TODO
+C  * Optimise for small n
+C  * Use r0 and save/restore one less register
+C  * Using logops_n's v1 inner loop operand order make the loop about 20%
+C    faster, at the expense of highly alignment-dependent performance.
+
+C INPUT PARAMETERS
+define(`rp',	`%r2')
+define(`up',	`%r3')
+define(`vp',	`%r4')
+define(`n',	`%r5')
+
+ifdef(`OPERATION_add_n', `
+  define(ADSB,		alg)
+  define(ADSBCR,	alcgr)
+  define(ADSBC,		alcg)
+  define(RETVAL,`dnl
+	lghi	%r2, 0
+	alcgr	%r2, %r2')
+  define(func,		mpn_add_n)
+  define(func_nc,	mpn_add_nc)')
+ifdef(`OPERATION_sub_n', `
+  define(ADSB,		slg)
+  define(ADSBCR,	slbgr)
+  define(ADSBC,		slbg)
+  define(RETVAL,`dnl
+	slbgr	%r2, %r2
+	lcgr	%r2, %r2')
+  define(func,		mpn_sub_n)
+  define(func_nc,	mpn_sub_nc)')
+
+MULFUNC_PROLOGUE(mpn_add_n mpn_sub_n)
+
+ASM_START()
+PROLOGUE(func)
+	stmg	%r6, %r8, 48(%r15)
+
+	aghi	n, 3
+	lghi	%r7, 3
+	srlg	%r1, n, 2
+	ngr	%r7, n			C n mod 4
+	je	L(b1)
+	cghi	%r7, 2
+	jl	L(b2)
+	jne	L(b0)
+
+L(b3):	lmg	%r5, %r7, 0(up)
+	la	up, 24(up)
+	ADSB	%r5, 0(vp)
+	ADSBC	%r6, 8(vp)
+	ADSBC	%r7, 16(vp)
+	la	vp, 24(vp)
+	stmg	%r5, %r7, 0(rp)
+	la	rp, 24(rp)
+	brctg	%r1, L(top)
+	j	L(end)
+
+L(b0):	lmg	%r5, %r8, 0(up)		C This redundant insns is no mistake,
+	la	up, 32(up)		C it is needed to make main loop run
+	ADSB	%r5, 0(vp)		C fast for n = 0 (mod 4).
+	ADSBC	%r6, 8(vp)
+	j	L(m0)
+
+L(b1):	lg	%r5, 0(up)
+	la	up, 8(up)
+	ADSB	%r5, 0(vp)
+	la	vp, 8(vp)
+	stg	%r5, 0(rp)
+	la	rp, 8(rp)
+	brctg	%r1, L(top)
+	j	L(end)
+
+L(b2):	lmg	%r5, %r6, 0(up)
+	la	up, 16(up)
+	ADSB	%r5, 0(vp)
+	ADSBC	%r6, 8(vp)
+	la	vp, 16(vp)
+	stmg	%r5, %r6, 0(rp)
+	la	rp, 16(rp)
+	brctg	%r1, L(top)
+	j	L(end)
+
+L(top):	lmg	%r5, %r8, 0(up)
+	la	up, 32(up)
+	ADSBC	%r5, 0(vp)
+	ADSBC	%r6, 8(vp)
+L(m0):	ADSBC	%r7, 16(vp)
+	ADSBC	%r8, 24(vp)
+	la	vp, 32(vp)
+	stmg	%r5, %r8, 0(rp)
+	la	rp, 32(rp)
+	brctg	%r1, L(top)
+
+L(end):	RETVAL
+	lmg	%r6, %r8, 48(%r15)
+	br	%r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/s390_64/bdiv_dbm1c.asm b/third_party/gmp/mpn/s390_64/bdiv_dbm1c.asm
new file mode 100644
index 0000000..35e900a
--- /dev/null
+++ b/third_party/gmp/mpn/s390_64/bdiv_dbm1c.asm
@@ -0,0 +1,65 @@
+dnl  S/390-64 mpn_bdiv_dbm1c
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C            cycles/limb
+C z900		29
+C z990		22
+C z9		 ?
+C z10		19
+C z196		 ?
+
+C INPUT PARAMETERS
+define(`qp',	  `%r2')
+define(`up',	  `%r3')
+define(`n',	  `%r4')
+define(`bd',	  `%r5')
+define(`cy',	  `%r6')
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_bdiv_dbm1c)
+	stmg	%r6, %r7, 48(%r15)
+	lghi	%r7, 0			C zero index register
+
+L(top):	lg	%r1, 0(%r7,up)
+	mlgr	%r0, bd
+	slgr	%r6, %r1
+	stg	%r6, 0(%r7,qp)
+	la	%r7, 8(%r7)
+	slbgr	%r6, %r0
+	brctg	n, L(top)
+
+	lgr	%r2, %r6
+	lmg	%r6, %r7, 48(%r15)
+	br	%r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/s390_64/copyd.asm b/third_party/gmp/mpn/s390_64/copyd.asm
new file mode 100644
index 0000000..8631e19
--- /dev/null
+++ b/third_party/gmp/mpn/s390_64/copyd.asm
@@ -0,0 +1,144 @@
+dnl  S/390-64 mpn_copyd
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+C            cycles/limb
+C z900		 2.67
+C z990           1.5
+C z9		 ?
+C z10		 1.8
+C z196		 ?
+
+C FIXME:
+C  * Avoid saving/restoring callee-saves registers for n < 3.  This could be
+C    done by setting rp=r1, up=r2, i=r0 and r3,r4,r5 for clock regs.
+C    We could then use r3...r10 in main loop.
+C  * Could we use some EX trick, modifying lmg/stmg, for the feed-in code?
+
+C INPUT PARAMETERS
+define(`rp_param',	`%r2')
+define(`up_param',	`%r3')
+define(`n',		`%r4')
+
+define(`rp',	`%r8')
+define(`up',	`%r9')
+
+ASM_START()
+PROLOGUE(mpn_copyd)
+	stmg	%r6, %r11, 48(%r15)
+
+	sllg	%r1, n, 3
+	la	%r10, 8(n)
+	aghi	%r1, -64
+	srlg	%r10, %r10, 3
+	lghi	%r11, -64
+
+	la	rp, 0(%r1,rp_param)	C FIXME use lay on z990 and later
+	la	up, 0(%r1,up_param)	C FIXME use lay on z990 and later
+
+	lghi	%r7, 7
+	ngr	%r7, n			C n mod 8
+	cghi	%r7, 2
+	jh	L(b34567)
+	cghi	%r7, 1
+	je	L(b1)
+	jh	L(b2)
+
+L(b0):	brctg	%r10, L(top)
+	j	L(end)
+
+L(b1):	lg	%r0, 56(up)
+	aghi	up, -8
+	stg	%r0, 56(rp)
+	aghi	rp, -8
+	brctg	%r10, L(top)
+	j	L(end)
+
+L(b2):	lmg	%r0, %r1, 48(up)
+	aghi	up, -16
+	stmg	%r0, %r1, 48(rp)
+	aghi	rp, -16
+	brctg	%r10, L(top)
+	j	L(end)
+
+L(b34567):
+	cghi	%r7, 4
+	jl	L(b3)
+	je	L(b4)
+	cghi	%r7, 6
+	je	L(b6)
+	jh	L(b7)
+
+L(b5):	lmg	%r0, %r4, 24(up)
+	aghi	up, -40
+	stmg	%r0, %r4, 24(rp)
+	aghi	rp, -40
+	brctg	%r10, L(top)
+	j	L(end)
+
+L(b3):	lmg	%r0, %r2, 40(up)
+	aghi	up, -24
+	stmg	%r0, %r2, 40(rp)
+	aghi	rp, -24
+	brctg	%r10, L(top)
+	j	L(end)
+
+L(b4):	lmg	%r0, %r3, 32(up)
+	aghi	up, -32
+	stmg	%r0, %r3, 32(rp)
+	aghi	rp, -32
+	brctg	%r10, L(top)
+	j	L(end)
+
+L(b6):	lmg	%r0, %r5, 16(up)
+	aghi	up, -48
+	stmg	%r0, %r5, 16(rp)
+	aghi	rp, -48
+	brctg	%r10, L(top)
+	j	L(end)
+
+L(b7):	lmg	%r0, %r6, 8(up)
+	aghi	up, -56
+	stmg	%r0, %r6, 8(rp)
+	aghi	rp, -56
+	brctg	%r10, L(top)
+	j	L(end)
+
+L(top):	lmg	%r0, %r7, 0(up)
+	la	up, 0(%r11,up)
+	stmg	%r0, %r7, 0(rp)
+	la	rp, 0(%r11,rp)
+	brctg	%r10, L(top)
+
+L(end):	lmg	%r6, %r11, 48(%r15)
+	br	%r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/s390_64/copyi.asm b/third_party/gmp/mpn/s390_64/copyi.asm
new file mode 100644
index 0000000..bfb8881
--- /dev/null
+++ b/third_party/gmp/mpn/s390_64/copyi.asm
@@ -0,0 +1,68 @@
+dnl  S/390-64 mpn_copyi
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+C            cycles/limb
+C z900		 1.25
+C z990           0.75
+C z9		 ?
+C z10		 1
+C z196		 ?
+
+C NOTE
+C  * This is based on GNU libc memcpy which was written by Martin Schwidefsky.
+
+C INPUT PARAMETERS
+define(`rp',	`%r2')
+define(`up',	`%r3')
+define(`n',	`%r4')
+
+ASM_START()
+PROLOGUE(mpn_copyi)
+	ltgr	%r4, %r4
+	sllg	%r4, %r4, 3
+	je	L(rtn)
+	aghi	%r4, -1
+	srlg	%r5, %r4, 8
+	ltgr	%r5, %r5		C < 256 bytes to copy?
+	je	L(1)
+
+L(top):	mvc	0(256, rp), 0(up)
+	la	rp, 256(rp)
+	la	up, 256(up)
+	brctg	%r5, L(top)
+
+L(1):	bras	%r5, L(2)		C make r5 point to mvc insn
+	mvc	0(1, rp), 0(up)
+L(2):	ex	%r4, 0(%r5)		C execute mvc with length ((n-1) mod 256)+1
+L(rtn):	br	%r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/s390_64/gmp-mparam.h b/third_party/gmp/mpn/s390_64/gmp-mparam.h
new file mode 100644
index 0000000..062c3d2
--- /dev/null
+++ b/third_party/gmp/mpn/s390_64/gmp-mparam.h
@@ -0,0 +1,181 @@
+/* S/390-64 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 2000-2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+/* 4400 MHz z196 */
+/* Generated by tuneup.c, 2017-01-02, gcc 4.9 */
+
+#define DIVREM_1_NORM_THRESHOLD          MP_SIZE_T_MAX  /* never */
+#define DIVREM_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define MOD_1_1P_METHOD                      2
+#define MOD_1_NORM_THRESHOLD             MP_SIZE_T_MAX  /* never */
+#define MOD_1_UNNORM_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD         14
+#define MOD_1U_TO_MOD_1_1_THRESHOLD         15
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD         0  /* never mpn_mod_1_1p */
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        31
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD      2
+#define USE_PREINV_DIVREM_1                  0
+#define DIV_QR_1N_PI1_METHOD                 1
+#define DIV_QR_1_NORM_THRESHOLD          MP_SIZE_T_MAX  /* never */
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD              10
+#define DIVEXACT_1_THRESHOLD                 4
+#define BMOD_1_TO_MOD_1_THRESHOLD            0  /* always */
+
+#define DIV_1_VS_MUL_1_PERCENT             317
+
+#define MUL_TOOM22_THRESHOLD                14
+#define MUL_TOOM33_THRESHOLD                45
+#define MUL_TOOM44_THRESHOLD               121
+#define MUL_TOOM6H_THRESHOLD               177
+#define MUL_TOOM8H_THRESHOLD               260
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      81
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD      78
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD      81
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD      88
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     118
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 13
+#define SQR_TOOM3_THRESHOLD                 89
+#define SQR_TOOM4_THRESHOLD                242
+#define SQR_TOOM6_THRESHOLD                363
+#define SQR_TOOM8_THRESHOLD                482
+
+#define MULMID_TOOM42_THRESHOLD             38
+
+#define MULMOD_BNM1_THRESHOLD                9
+#define SQRMOD_BNM1_THRESHOLD                9
+
+#define MUL_FFT_MODF_THRESHOLD             236  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    236, 5}, {     11, 6}, {      6, 5}, {     13, 6}, \
+    {     13, 7}, {      7, 6}, {     15, 7}, {      8, 6}, \
+    {     17, 7}, {     17, 8}, {      9, 7}, {     19, 8}, \
+    {     13, 9}, {      7, 8}, {     19, 9}, {     11, 8}, \
+    {     25,10}, {      7, 9}, {     15, 8}, {     33, 9}, \
+    {     19, 8}, {     39, 9}, {     23,10}, {     15, 9}, \
+    {     39,10}, {     23, 9}, {     47,11}, {     15,10}, \
+    {     31, 9}, {     67,10}, {     39, 9}, {     79,10}, \
+    {     47,11}, {     31,10}, {     63, 9}, {    127, 8}, \
+    {    255,10}, {     71, 9}, {    143, 8}, {    287, 7}, \
+    {    575, 9}, {    159,11}, {     47,12}, {     31,11}, \
+    {     63,10}, {    127, 9}, {    255, 8}, {    511,10}, \
+    {    143, 9}, {    287,11}, {     79,10}, {    159, 9}, \
+    {    319, 8}, {    639,10}, {    175, 9}, {    351, 8}, \
+    {    703,11}, {     95,10}, {    191, 9}, {    383, 8}, \
+    {    767,10}, {    207, 9}, {    415, 8}, {    831,10}, \
+    {    223,12}, {     63,11}, {    127,10}, {    255, 9}, \
+    {    511,11}, {    143,10}, {    287, 9}, {    575, 8}, \
+    {   1151,11}, {    159,10}, {    319, 9}, {    639,11}, \
+    {    175,10}, {    351, 9}, {    703, 8}, {   1407,12}, \
+    {     95,11}, {    191,10}, {    383, 9}, {    767,11}, \
+    {    207,10}, {    415, 9}, {    831,11}, {    223,13}, \
+    {   8192,14}, {  16384,15}, {  32768,16}, {  65536,17}, \
+    { 131072,18}, { 262144,19}, { 524288,20}, {1048576,21}, \
+    {2097152,22}, {4194304,23}, {8388608,24} }
+#define MUL_FFT_TABLE3_SIZE 99
+#define MUL_FFT_THRESHOLD                 2240
+
+#define SQR_FFT_MODF_THRESHOLD             220  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    220, 5}, {      7, 4}, {     15, 5}, {     13, 6}, \
+    {      7, 5}, {     15, 6}, {      8, 5}, {     17, 6}, \
+    {     13, 7}, {      7, 6}, {     15, 7}, {      8, 6}, \
+    {     17, 7}, {      9, 6}, {     19, 7}, {     13, 8}, \
+    {      7, 7}, {     17, 8}, {      9, 7}, {     20, 8}, \
+    {     11, 7}, {     23, 8}, {     13, 9}, {      7, 8}, \
+    {     19, 9}, {     11, 8}, {     23, 9}, {     15, 8}, \
+    {     31, 9}, {     19, 8}, {     39, 9}, {     23,10}, \
+    {     15, 9}, {     39,10}, {     23,11}, {     15,10}, \
+    {     31, 9}, {     63,10}, {     47,11}, {     31,10}, \
+    {     63, 9}, {    127, 8}, {    255,10}, {     71, 9}, \
+    {    143, 8}, {    287,11}, {     47,12}, {     31,11}, \
+    {     63,10}, {    127, 9}, {    255, 8}, {    511,10}, \
+    {    143, 9}, {    287, 8}, {    575, 7}, {   1151,10}, \
+    {    159, 9}, {    319, 8}, {    639,10}, {    175, 9}, \
+    {    351, 8}, {    703,11}, {     95,10}, {    191, 9}, \
+    {    383,12}, {     63,11}, {    127,10}, {    255, 9}, \
+    {    511,11}, {    143,10}, {    287, 9}, {    575, 8}, \
+    {   1151,11}, {    159,10}, {    319, 9}, {    639,11}, \
+    {    175,10}, {    351, 9}, {    703,12}, {     95,11}, \
+    {    191,10}, {    383,11}, {    207,13}, {   8192,14}, \
+    {  16384,15}, {  32768,16}, {  65536,17}, { 131072,18}, \
+    { 262144,19}, { 524288,20}, {1048576,21}, {2097152,22}, \
+    {4194304,23}, {8388608,24} }
+#define SQR_FFT_TABLE3_SIZE 94
+#define SQR_FFT_THRESHOLD                 1728
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  38
+#define MULLO_MUL_N_THRESHOLD             4392
+#define SQRLO_BASECASE_THRESHOLD             0  /* always */
+#define SQRLO_DC_THRESHOLD                  54
+#define SQRLO_SQR_THRESHOLD               3176
+
+#define DC_DIV_QR_THRESHOLD                 42
+#define DC_DIVAPPR_Q_THRESHOLD             148
+#define DC_BDIV_QR_THRESHOLD                46
+#define DC_BDIV_Q_THRESHOLD                107
+
+#define INV_MULMOD_BNM1_THRESHOLD           34
+#define INV_NEWTON_THRESHOLD               163
+#define INV_APPR_THRESHOLD                 131
+
+#define BINV_NEWTON_THRESHOLD              183
+#define REDC_1_TO_REDC_N_THRESHOLD          43
+
+#define MU_DIV_QR_THRESHOLD                807
+#define MU_DIVAPPR_Q_THRESHOLD             942
+#define MUPI_DIV_QR_THRESHOLD               78
+#define MU_BDIV_QR_THRESHOLD               680
+#define MU_BDIV_Q_THRESHOLD                828
+
+#define POWM_SEC_TABLE  3,35,285,1603
+
+#define GET_STR_DC_THRESHOLD                12
+#define GET_STR_PRECOMPUTE_THRESHOLD        21
+#define SET_STR_DC_THRESHOLD              1391
+#define SET_STR_PRECOMPUTE_THRESHOLD      2872
+
+#define FAC_DSC_THRESHOLD                  151
+#define FAC_ODD_THRESHOLD                   23
+
+#define MATRIX22_STRASSEN_THRESHOLD         15
+#define HGCD_THRESHOLD                     135
+#define HGCD_APPR_THRESHOLD                169
+#define HGCD_REDUCE_THRESHOLD             1437
+#define GCD_DC_THRESHOLD                   469
+#define GCDEXT_DC_THRESHOLD                342
+#define JACOBI_BASE_METHOD                   4
diff --git a/third_party/gmp/mpn/s390_64/invert_limb.asm b/third_party/gmp/mpn/s390_64/invert_limb.asm
new file mode 100644
index 0000000..edcebdd
--- /dev/null
+++ b/third_party/gmp/mpn/s390_64/invert_limb.asm
@@ -0,0 +1,94 @@
+dnl  S/390-64 mpn_invert_limb
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2011, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C            cycles/limb
+C z900	       142
+C z990          86
+C z9		 ?
+C z10	       120
+C z196		 ?
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_invert_limb)
+	stg	%r9, 72(%r15)
+	srlg	%r9, %r2, 55
+	agr	%r9, %r9
+	larl	%r4, approx_tab-512
+	srlg	%r3, %r2, 24
+	aghi	%r3, 1
+	lghi	%r5, 1
+	llgh	%r4, 0(%r9, %r4)
+	sllg	%r9, %r4, 11
+	msgr	%r4, %r4
+	msgr	%r4, %r3
+	srlg	%r4, %r4, 40
+	aghi	%r9, -1
+	sgr	%r9, %r4
+	sllg	%r0, %r9, 60
+	sllg	%r1, %r9, 13
+	msgr	%r9, %r9
+	msgr	%r9, %r3
+	sgr	%r0, %r9
+	ngr	%r5, %r2
+	srlg	%r4, %r2, 1
+	srlg	%r3, %r0, 47
+	agr	%r3, %r1
+	agr	%r4, %r5
+	msgr	%r4, %r3
+	srlg	%r1, %r3, 1
+	lcgr	%r5, %r5
+	ngr	%r1, %r5
+	sgr	%r1, %r4
+	mlgr	%r0, %r3
+	srlg	%r9, %r0, 1
+	sllg	%r4, %r3, 31
+	agr	%r4, %r9
+	lgr	%r1, %r4
+	mlgr	%r0, %r2
+	algr	%r1, %r2
+	alcgr	%r0, %r2
+	lgr	%r2, %r4
+	sgr	%r2, %r0
+	lg	%r9, 72(%r15)
+	br	%r14
+EPILOGUE()
+	RODATA
+	ALIGN(2)
+approx_tab:
+forloop(i,256,512-1,dnl
+`	.word	eval(0x7fd00/i)
+')dnl
+ASM_END()
diff --git a/third_party/gmp/mpn/s390_64/logops_n.asm b/third_party/gmp/mpn/s390_64/logops_n.asm
new file mode 100644
index 0000000..914cfb6
--- /dev/null
+++ b/third_party/gmp/mpn/s390_64/logops_n.asm
@@ -0,0 +1,291 @@
+dnl  S/390-64 logops.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C cycles/limb     variant 1           variant 2       variant 3
+C	        rp!=up  rp=up
+C z900		 4.5	 2.25		 5.5		 5.5
+C z990		 2.75	 2		 3.25		 3.25
+C z9		 ?			 ?		 ?
+C z10		 3.25			 3.75		 3.75
+C z196		 ?			 ?		 ?
+
+C INPUT PARAMETERS
+define(`rp',	`%r2')
+define(`up',	`%r3')
+define(`vp',	`%r4')
+define(`n',	`%r5')
+
+ifdef(`OPERATION_and_n',`
+  define(`func',`mpn_and_n')
+  define(`VARIANT_1')
+  define(`LOGOPC',`nc')
+  define(`LOGOP',`ng')')
+ifdef(`OPERATION_andn_n',`
+  define(`func',`mpn_andn_n')
+  define(`VARIANT_2')
+  define(`LOGOP',`ng')')
+ifdef(`OPERATION_nand_n',`
+  define(`func',`mpn_nand_n')
+  define(`VARIANT_3')
+  define(`LOGOP',`ng')')
+ifdef(`OPERATION_ior_n',`
+  define(`func',`mpn_ior_n')
+  define(`VARIANT_1')
+  define(`LOGOPC',`oc')
+  define(`LOGOP',`og')')
+ifdef(`OPERATION_iorn_n',`
+  define(`func',`mpn_iorn_n')
+  define(`VARIANT_2')
+  define(`LOGOP',`og')')
+ifdef(`OPERATION_nior_n',`
+  define(`func',`mpn_nior_n')
+  define(`VARIANT_3')
+  define(`LOGOP',`og')')
+ifdef(`OPERATION_xor_n',`
+  define(`func',`mpn_xor_n')
+  define(`VARIANT_1')
+  define(`LOGOPC',`xc')
+  define(`LOGOP',`xg')')
+ifdef(`OPERATION_xnor_n',`
+  define(`func',`mpn_xnor_n')
+  define(`VARIANT_2')
+  define(`LOGOP',`xg')')
+
+MULFUNC_PROLOGUE(mpn_and_n mpn_andn_n mpn_nand_n mpn_ior_n mpn_iorn_n mpn_nior_n mpn_xor_n mpn_xnor_n)
+
+ASM_START()
+PROLOGUE(func)
+ifdef(`VARIANT_1',`
+	cgr	rp, up
+	jne	L(normal)
+
+	sllg	n, n, 3
+	aghi	n, -1
+	srlg	%r1, n, 8
+	ltgr	%r1, %r1		C < 256 bytes to copy?
+	je	L(1)
+
+L(tp):	LOGOPC	0(256, rp), 0(vp)
+	la	rp, 256(rp)
+	la	vp, 256(vp)
+	brctg	%r1, L(tp)
+
+L(1):	bras	%r1, L(2)		C make r1 point to mvc insn
+	LOGOPC	0(1, rp), 0(vp)
+L(2):	ex	n, 0(%r1)		C execute mvc with length ((n-1) mod 256)+1
+L(rtn):	br	%r14
+
+
+L(normal):
+	stmg	%r6, %r8, 48(%r15)
+	aghi	n, 3
+	lghi	%r7, 3
+	srlg	%r0, n, 2
+	ngr	%r7, n			C n mod 4
+	je	L(b1)
+	cghi	%r7, 2
+	jl	L(b2)
+	jne	L(top)
+
+L(b3):	lmg	%r5, %r7, 0(up)
+	la	up, 24(up)
+	LOGOP	%r5, 0(vp)
+	LOGOP	%r6, 8(vp)
+	LOGOP	%r7, 16(vp)
+	stmg	%r5, %r7, 0(rp)
+	la	rp, 24(rp)
+	la	vp, 24(vp)
+	j	L(mid)
+
+L(b1):	lg	%r5, 0(up)
+	la	up, 8(up)
+	LOGOP	%r5, 0(vp)
+	stg	%r5, 0(rp)
+	la	rp, 8(rp)
+	la	vp, 8(vp)
+	j	L(mid)
+
+L(b2):	lmg	%r5, %r6, 0(up)
+	la	up, 16(up)
+	LOGOP	%r5, 0(vp)
+	LOGOP	%r6, 8(vp)
+	stmg	%r5, %r6, 0(rp)
+	la	rp, 16(rp)
+	la	vp, 16(vp)
+	j	L(mid)
+
+L(top):	lmg	%r5, %r8, 0(up)
+	la	up, 32(up)
+	LOGOP	%r5, 0(vp)
+	LOGOP	%r6, 8(vp)
+	LOGOP	%r7, 16(vp)
+	LOGOP	%r8, 24(vp)
+	stmg	%r5, %r8, 0(rp)
+	la	rp, 32(rp)
+	la	vp, 32(vp)
+L(mid):	brctg	%r0, L(top)
+
+	lmg	%r6, %r8, 48(%r15)
+	br	%r14
+')
+
+ifdef(`VARIANT_2',`
+	stmg	%r6, %r8, 48(%r15)
+	lghi	%r1, -1
+
+	aghi	n, 3
+	lghi	%r7, 3
+	srlg	%r0, n, 2
+	ngr	%r7, n			C n mod 4
+	je	L(b1)
+	cghi	%r7, 2
+	jl	L(b2)
+	jne	L(top)
+
+L(b3):	lmg	%r5, %r7, 0(vp)
+	la	vp, 24(vp)
+	xgr	%r5, %r1
+	xgr	%r6, %r1
+	xgr	%r7, %r1
+	LOGOP	%r5, 0(up)
+	LOGOP	%r6, 8(up)
+	LOGOP	%r7, 16(up)
+	stmg	%r5, %r7, 0(rp)
+	la	rp, 24(rp)
+	la	up, 24(up)
+	j	L(mid)
+
+L(b1):	lg	%r5, 0(vp)
+	la	vp, 8(vp)
+	xgr	%r5, %r1
+	LOGOP	%r5, 0(up)
+	stg	%r5, 0(rp)
+	la	rp, 8(rp)
+	la	up, 8(up)
+	j	L(mid)
+
+L(b2):	lmg	%r5, %r6, 0(vp)
+	la	vp, 16(vp)
+	xgr	%r5, %r1
+	xgr	%r6, %r1
+	LOGOP	%r5, 0(up)
+	LOGOP	%r6, 8(up)
+	stmg	%r5, %r6, 0(rp)
+	la	rp, 16(rp)
+	la	up, 16(up)
+	j	L(mid)
+
+L(top):	lmg	%r5, %r8, 0(vp)
+	la	vp, 32(vp)
+	xgr	%r5, %r1
+	xgr	%r6, %r1
+	xgr	%r7, %r1
+	xgr	%r8, %r1
+	LOGOP	%r5, 0(up)
+	LOGOP	%r6, 8(up)
+	LOGOP	%r7, 16(up)
+	LOGOP	%r8, 24(up)
+	la	up, 32(up)
+	stmg	%r5, %r8, 0(rp)
+	la	rp, 32(rp)
+L(mid):	brctg	%r0, L(top)
+
+	lmg	%r6, %r8, 48(%r15)
+	br	%r14
+')
+
+ifdef(`VARIANT_3',`
+	stmg	%r6, %r8, 48(%r15)
+	lghi	%r1, -1
+
+	aghi	n, 3
+	lghi	%r7, 3
+	srlg	%r0, n, 2
+	ngr	%r7, n			C n mod 4
+	je	L(b1)
+	cghi	%r7, 2
+	jl	L(b2)
+	jne	L(top)
+
+L(b3):	lmg	%r5, %r7, 0(vp)
+	la	vp, 24(vp)
+	LOGOP	%r5, 0(up)
+	LOGOP	%r6, 8(up)
+	xgr	%r5, %r1
+	xgr	%r6, %r1
+	LOGOP	%r7, 16(up)
+	xgr	%r7, %r1
+	stmg	%r5, %r7, 0(rp)
+	la	rp, 24(rp)
+	la	up, 24(up)
+	j	L(mid)
+
+L(b1):	lg	%r5, 0(vp)
+	la	vp, 8(vp)
+	LOGOP	%r5, 0(up)
+	xgr	%r5, %r1
+	stg	%r5, 0(rp)
+	la	rp, 8(rp)
+	la	up, 8(up)
+	j	L(mid)
+
+L(b2):	lmg	%r5, %r6, 0(vp)
+	la	vp, 16(vp)
+	LOGOP	%r5, 0(up)
+	LOGOP	%r6, 8(up)
+	xgr	%r5, %r1
+	xgr	%r6, %r1
+	stmg	%r5, %r6, 0(rp)
+	la	rp, 16(rp)
+	la	up, 16(up)
+	j	L(mid)
+
+L(top):	lmg	%r5, %r8, 0(vp)
+	la	vp, 32(vp)
+	LOGOP	%r5, 0(up)
+	LOGOP	%r6, 8(up)
+	xgr	%r5, %r1
+	xgr	%r6, %r1
+	LOGOP	%r7, 16(up)
+	LOGOP	%r8, 24(up)
+	xgr	%r7, %r1
+	xgr	%r8, %r1
+	stmg	%r5, %r8, 0(rp)
+	la	up, 32(up)
+	la	rp, 32(rp)
+L(mid):	brctg	%r0, L(top)
+
+	lmg	%r6, %r8, 48(%r15)
+	br	%r14
+')
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/s390_64/lshift.asm b/third_party/gmp/mpn/s390_64/lshift.asm
new file mode 100644
index 0000000..4dae035
--- /dev/null
+++ b/third_party/gmp/mpn/s390_64/lshift.asm
@@ -0,0 +1,196 @@
+dnl  S/390-64 mpn_lshift.
+
+dnl  Copyright 2011, 2012, 2014 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C            cycles/limb
+C z900		 7
+C z990           3
+C z9		 ?
+C z10		 6
+C z196		 ?
+
+C NOTES
+C  * This uses discrete loads and stores in a software pipeline.  Using lmg and
+C    stmg is not faster.
+C  * One could assume more pipelining could approach 2.5 c/l, but we have not
+C    found any 8-way loop that runs better than the current 4-way loop.
+C  * Consider using the same feed-in code for 1 <= n <= 3 as for n mod 4,
+C    similarly to the x86_64 sqr_basecase feed-in.
+
+C INPUT PARAMETERS
+define(`rp',	`%r2')
+define(`up',	`%r3')
+define(`n',	`%r4')
+define(`cnt',	`%r5')
+
+define(`tnc',	`%r6')
+
+ASM_START()
+PROLOGUE(mpn_lshift)
+	cghi	n, 3
+	jh	L(gt1)
+
+	stmg	%r6, %r7, 48(%r15)
+	larl	%r1, L(tab)-4
+	lcgr	tnc, cnt
+	sllg	n, n, 2
+	b	0(n,%r1)
+L(tab):	j	L(n1)
+	j	L(n2)
+	j	L(n3)
+
+L(n1):	lg	%r1, 0(up)
+	sllg	%r0, %r1, 0(cnt)
+	stg	%r0, 0(rp)
+	srlg	%r2, %r1, 0(tnc)
+	lg	%r6, 48(%r15)		C restoring r7 not needed
+	br	%r14
+
+L(n2):	lg	%r1, 8(up)
+	srlg	%r4, %r1, 0(tnc)
+	sllg	%r0, %r1, 0(cnt)
+	j	L(cj)
+
+L(n3):	lg	%r1, 16(up)
+	srlg	%r4, %r1, 0(tnc)
+	sllg	%r0, %r1, 0(cnt)
+	lg	%r1, 8(up)
+	srlg	%r7, %r1, 0(tnc)
+	ogr	%r7, %r0
+	sllg	%r0, %r1, 0(cnt)
+	stg	%r7, 16(rp)
+L(cj):	lg	%r1, 0(up)
+	srlg	%r7, %r1, 0(tnc)
+	ogr	%r7, %r0
+	sllg	%r0, %r1, 0(cnt)
+	stg	%r7, 8(rp)
+	stg	%r0, 0(rp)
+	lgr	%r2, %r4
+	lmg	%r6, %r7, 48(%r15)
+	br	%r14
+
+L(gt1):	stmg	%r6, %r13, 48(%r15)
+	lcgr	tnc, cnt		C tnc = -cnt
+
+	sllg	%r1, n, 3
+	srlg	%r0, n, 2		C loop count
+
+	agr	up, %r1			C point up at end of U
+	agr	rp, %r1			C point rp at end of R
+	aghi	up, -56
+	aghi	rp, -40
+
+	lghi	%r7, 3
+	ngr	%r7, n
+	je	L(b0)
+	cghi	%r7, 2
+	jl	L(b1)
+	je	L(b2)
+
+L(b3):	lg	%r7, 48(up)
+	srlg	%r9, %r7, 0(tnc)
+	sllg	%r11, %r7, 0(cnt)
+	lg	%r8, 40(up)
+	lg	%r7, 32(up)
+	srlg	%r4, %r8, 0(tnc)
+	sllg	%r13, %r8, 0(cnt)
+	ogr	%r11, %r4
+	la	rp, 16(rp)
+	j	L(lm3)
+
+L(b2):	lg	%r8, 48(up)
+	lg	%r7, 40(up)
+	srlg	%r9, %r8, 0(tnc)
+	sllg	%r13, %r8, 0(cnt)
+	la	rp, 24(rp)
+	la	up, 8(up)
+	j	L(lm2)
+
+L(b1):	lg	%r7, 48(up)
+	srlg	%r9, %r7, 0(tnc)
+	sllg	%r11, %r7, 0(cnt)
+	lg	%r8, 40(up)
+	lg	%r7, 32(up)
+	srlg	%r4, %r8, 0(tnc)
+	sllg	%r10, %r8, 0(cnt)
+	ogr	%r11, %r4
+	la	rp, 32(rp)
+	la	up, 16(up)
+	j	L(lm1)
+
+L(b0):	lg	%r8, 48(up)
+	lg	%r7, 40(up)
+	srlg	%r9, %r8, 0(tnc)
+	sllg	%r10, %r8, 0(cnt)
+	la	rp, 40(rp)
+	la	up, 24(up)
+	j	L(lm0)
+
+	ALIGN(8)
+L(top):	srlg	%r4, %r8, 0(tnc)
+	sllg	%r13, %r8, 0(cnt)
+	ogr	%r11, %r4
+	stg	%r10, 24(rp)
+L(lm3):	stg	%r11, 16(rp)
+L(lm2):	srlg	%r12, %r7, 0(tnc)
+	sllg	%r11, %r7, 0(cnt)
+	lg	%r8, 24(up)
+	lg	%r7, 16(up)
+	ogr	%r13, %r12
+	srlg	%r4, %r8, 0(tnc)
+	sllg	%r10, %r8, 0(cnt)
+	ogr	%r11, %r4
+	stg	%r13, 8(rp)
+L(lm1):	stg	%r11, 0(rp)
+L(lm0):	srlg	%r12, %r7, 0(tnc)
+	aghi	rp, -32
+	sllg	%r11, %r7, 0(cnt)
+	lg	%r8, 8(up)
+	lg	%r7, 0(up)
+	aghi	up, -32
+	ogr	%r10, %r12
+	brctg	%r0, L(top)
+
+L(end):	srlg	%r4, %r8, 0(tnc)
+	sllg	%r13, %r8, 0(cnt)
+	ogr	%r11, %r4
+	stg	%r10, 24(rp)
+	stg	%r11, 16(rp)
+	srlg	%r12, %r7, 0(tnc)
+	sllg	%r11, %r7, 0(cnt)
+	ogr	%r13, %r12
+	stg	%r13, 8(rp)
+	stg	%r11, 0(rp)
+	lgr	%r2, %r9
+
+	lmg	%r6, %r13, 48(%r15)
+	br	%r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/s390_64/lshiftc.asm b/third_party/gmp/mpn/s390_64/lshiftc.asm
new file mode 100644
index 0000000..92552d5
--- /dev/null
+++ b/third_party/gmp/mpn/s390_64/lshiftc.asm
@@ -0,0 +1,207 @@
+dnl  S/390-64 mpn_lshiftc.
+
+dnl  Copyright 2011, 2014 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C            cycles/limb
+C z900		 9
+C z990           3.5
+C z9		 ?
+C z10		 7
+C z196		 ?
+
+C NOTES
+C  * See notes in lshift.asm.
+
+C INPUT PARAMETERS
+define(`rp',	`%r2')
+define(`up',	`%r3')
+define(`n',	`%r4')
+define(`cnt',	`%r5')
+
+define(`tnc',	`%r6')
+
+ASM_START()
+PROLOGUE(mpn_lshiftc)
+	cghi	n, 3
+	jh	L(gt1)
+
+	stmg	%r6, %r8, 48(%r15)
+	larl	%r1, L(tab)-4
+	lcgr	tnc, cnt
+	sllg	n, n, 2
+	lghi	%r8, -1
+	b	0(n,%r1)
+L(tab):	j	L(n1)
+	j	L(n2)
+	j	L(n3)
+
+L(n1):	lg	%r1, 0(up)
+	sllg	%r0, %r1, 0(cnt)
+	xgr	%r0, %r8
+	stg	%r0, 0(rp)
+	srlg	%r2, %r1, 0(tnc)
+	lmg	%r6, %r8, 48(%r15)
+	br	%r14
+
+L(n2):	lg	%r1, 8(up)
+	srlg	%r4, %r1, 0(tnc)
+	sllg	%r0, %r1, 0(cnt)
+	j	L(cj)
+
+L(n3):	lg	%r1, 16(up)
+	srlg	%r4, %r1, 0(tnc)
+	sllg	%r0, %r1, 0(cnt)
+	lg	%r1, 8(up)
+	srlg	%r7, %r1, 0(tnc)
+	ogr	%r7, %r0
+	sllg	%r0, %r1, 0(cnt)
+	xgr	%r7, %r8
+	stg	%r7, 16(rp)
+L(cj):	lg	%r1, 0(up)
+	srlg	%r7, %r1, 0(tnc)
+	ogr	%r7, %r0
+	sllg	%r0, %r1, 0(cnt)
+	xgr	%r7, %r8
+	xgr	%r0, %r8
+	stg	%r7, 8(rp)
+	stg	%r0, 0(rp)
+	lgr	%r2, %r4
+	lmg	%r6, %r8, 48(%r15)
+	br	%r14
+
+L(gt1):	stmg	%r6, %r14, 48(%r15)
+	lcgr	tnc, cnt		C tnc = -cnt
+
+	sllg	%r1, n, 3
+	srlg	%r0, n, 2		C loop count
+
+	agr	up, %r1			C point up at end of U
+	agr	rp, %r1			C point rp at end of R
+	aghi	up, -56
+	aghi	rp, -40
+
+	lghi	%r7, 3
+	lghi	%r14, -1
+	ngr	%r7, n
+	je	L(b0)
+	cghi	%r7, 2
+	jl	L(b1)
+	je	L(b2)
+
+L(b3):	lg	%r7, 48(up)
+	srlg	%r9, %r7, 0(tnc)
+	sllg	%r11, %r7, 0(cnt)
+	lg	%r8, 40(up)
+	lg	%r7, 32(up)
+	srlg	%r4, %r8, 0(tnc)
+	sllg	%r13, %r8, 0(cnt)
+	ogr	%r11, %r4
+	la	rp, 16(rp)
+	xgr	%r11, %r14
+	j	L(lm3)
+
+L(b2):	lg	%r8, 48(up)
+	lg	%r7, 40(up)
+	srlg	%r9, %r8, 0(tnc)
+	sllg	%r13, %r8, 0(cnt)
+	la	rp, 24(rp)
+	la	up, 8(up)
+	j	L(lm2)
+
+L(b1):	lg	%r7, 48(up)
+	srlg	%r9, %r7, 0(tnc)
+	sllg	%r11, %r7, 0(cnt)
+	lg	%r8, 40(up)
+	lg	%r7, 32(up)
+	srlg	%r4, %r8, 0(tnc)
+	sllg	%r10, %r8, 0(cnt)
+	ogr	%r11, %r4
+	la	rp, 32(rp)
+	la	up, 16(up)
+	xgr	%r11, %r14
+	j	L(lm1)
+
+L(b0):	lg	%r8, 48(up)
+	lg	%r7, 40(up)
+	srlg	%r9, %r8, 0(tnc)
+	sllg	%r10, %r8, 0(cnt)
+	la	rp, 40(rp)
+	la	up, 24(up)
+	j	L(lm0)
+
+	ALIGN(8)
+L(top):	srlg	%r4, %r8, 0(tnc)
+	sllg	%r13, %r8, 0(cnt)
+	ogr	%r11, %r4
+	xgr	%r10, %r14
+	xgr	%r11, %r14
+	stg	%r10, 24(rp)
+L(lm3):	stg	%r11, 16(rp)
+L(lm2):	srlg	%r12, %r7, 0(tnc)
+	sllg	%r11, %r7, 0(cnt)
+	lg	%r8, 24(up)
+	lg	%r7, 16(up)
+	ogr	%r13, %r12
+	srlg	%r4, %r8, 0(tnc)
+	sllg	%r10, %r8, 0(cnt)
+	ogr	%r11, %r4
+	xgr	%r13, %r14
+	xgr	%r11, %r14
+	stg	%r13, 8(rp)
+L(lm1):	stg	%r11, 0(rp)
+L(lm0):	srlg	%r12, %r7, 0(tnc)
+	aghi	rp, -32
+	sllg	%r11, %r7, 0(cnt)
+	lg	%r8, 8(up)
+	lg	%r7, 0(up)
+	aghi	up, -32
+	ogr	%r10, %r12
+	brctg	%r0, L(top)
+
+L(end):	srlg	%r4, %r8, 0(tnc)
+	sllg	%r13, %r8, 0(cnt)
+	ogr	%r11, %r4
+	xgr	%r10, %r14
+	xgr	%r11, %r14
+	stg	%r10, 24(rp)
+	stg	%r11, 16(rp)
+	srlg	%r12, %r7, 0(tnc)
+	sllg	%r11, %r7, 0(cnt)
+	ogr	%r13, %r12
+	xgr	%r13, %r14
+	xgr	%r11, %r14
+	stg	%r13, 8(rp)
+	stg	%r11, 0(rp)
+	lgr	%r2, %r9
+
+	lmg	%r6, %r14, 48(%r15)
+	br	%r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/s390_64/mod_34lsub1.asm b/third_party/gmp/mpn/s390_64/mod_34lsub1.asm
new file mode 100644
index 0000000..fd40011
--- /dev/null
+++ b/third_party/gmp/mpn/s390_64/mod_34lsub1.asm
@@ -0,0 +1,109 @@
+dnl  S/390-64 mpn_mod_34lsub1
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C            cycles/limb
+C z900		 5.8
+C z990           2
+C z9		 ?
+C z10		 4.5
+C z196		 ?
+
+C TODO
+C  * Optimise summation code, see x86_64.
+
+C INPUT PARAMETERS
+define(`rp',	`%r2')
+define(`n',	`%r3')
+
+ASM_START()
+PROLOGUE(mpn_mod_34lsub1)
+	stmg	%r7, %r12, 56(%r15)
+	lghi	%r11, 0
+	lghi	%r12, 0
+	lghi	%r0, 0
+	lghi	%r8, 0
+	lghi	%r9, 0
+	lghi	%r10, 0
+	lghi	%r7, 0
+	aghi	%r3, -3
+	jl	.L3
+
+L(top):	alg	%r0, 0(%r2)
+	alcg	%r12, 8(%r2)
+	alcg	%r11, 16(%r2)
+	alcgr	%r8, %r7
+	la	%r2, 24(%r2)
+	aghi	%r3, -3
+	jnl	L(top)
+
+	lgr	%r7, %r8
+	srlg	%r1, %r11, 16
+	nihh	%r7, 0			C 0xffffffffffff
+	agr	%r7, %r1
+	srlg	%r8, %r8, 48
+	agr	%r7, %r8
+	sllg	%r11, %r11, 32
+	nihh	%r11, 0
+	agr	%r7, %r11
+.L3:
+	cghi	%r3, -3
+	je	.L6
+	alg	%r0, 0(%r2)
+	alcgr	%r10, %r10
+	cghi	%r3, -2
+	je	.L6
+	alg	%r12, 8(%r2)
+	alcgr	%r9, %r9
+.L6:
+	srlg	%r1, %r0, 48
+	nihh	%r0, 0			C 0xffffffffffff
+	agr	%r0, %r1
+	agr	%r0, %r7
+	srlg	%r1, %r12, 32
+	agr	%r0, %r1
+	srlg	%r1, %r10, 32
+	agr	%r0, %r1
+	llgfr	%r12, %r12
+	srlg	%r1, %r9, 16
+	sllg	%r12, %r12, 16
+	llgfr	%r10, %r10
+	agr	%r0, %r1
+	llill	%r2, 65535
+	agr	%r0, %r12
+	sllg	%r10, %r10, 16
+	ngr	%r2, %r9
+	agr	%r0, %r10
+	sllg	%r2, %r2, 32
+	agr	%r2, %r0
+	lmg	%r7, %r12, 56(%r15)
+	br	%r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/s390_64/mul_1.asm b/third_party/gmp/mpn/s390_64/mul_1.asm
new file mode 100644
index 0000000..a8f6da9
--- /dev/null
+++ b/third_party/gmp/mpn/s390_64/mul_1.asm
@@ -0,0 +1,66 @@
+dnl  S/390-64 mpn_mul_1
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C            cycles/limb
+C z900		29
+C z990		22
+C z9		 ?
+C z10		20
+C z196		 ?
+
+C INPUT PARAMETERS
+define(`rp',	`%r2')
+define(`up',	`%r3')
+define(`n',	`%r4')
+define(`v0',	`%r5')
+
+ASM_START()
+PROLOGUE(mpn_mul_1)
+	stmg	%r11, %r12, 88(%r15)
+	lghi	%r12, 0			C zero index register
+	aghi	%r12, 0			C clear carry flag
+	lghi	%r11, 0			C clear carry limb
+
+L(top):	lg	%r1, 0(%r12,up)
+	mlgr	%r0, v0
+	alcgr	%r1, %r11
+	lgr	%r11, %r0		C copy high part to carry limb
+	stg	%r1, 0(%r12,rp)
+	la	%r12, 8(%r12)
+	brctg	n, L(top)
+
+	lghi	%r2, 0
+	alcgr	%r2, %r11
+
+	lmg	%r11, %r12, 88(%r15)
+	br	%r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/s390_64/mul_basecase.asm b/third_party/gmp/mpn/s390_64/mul_basecase.asm
new file mode 100644
index 0000000..7d14ea9
--- /dev/null
+++ b/third_party/gmp/mpn/s390_64/mul_basecase.asm
@@ -0,0 +1,130 @@
+dnl  S/390-64 mpn_mul_basecase.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C            cycles/limb
+C z900		 ?
+C z990		23
+C z9		 ?
+C z10		28
+C z196		 ?
+
+C TODO
+C  * Perhaps add special case for un <= 2.
+C  * Replace loops by faster code.  The mul_1 and addmul_1 loops could be sped
+C    up by about 10%.
+
+C INPUT PARAMETERS
+define(`rp',	`%r2')
+define(`up',	`%r3')
+define(`un',	`%r4')
+define(`vp',	`%r5')
+define(`vn',	`%r6')
+
+define(`zero',	`%r8')
+
+ASM_START()
+PROLOGUE(mpn_mul_basecase)
+	cghi	un, 2
+	jhe	L(ge2)
+
+C un = vn = 1
+	lg	%r1, 0(vp)
+	mlg	%r0, 0(up)
+	stg	%r1, 0(rp)
+	stg	%r0, 8(rp)
+	br	%r14
+
+L(ge2):	C jne	L(gen)
+
+
+L(gen):
+C mul_1 =======================================================================
+
+	stmg	%r6, %r12, 48(%r15)
+	lghi	zero, 0
+	aghi	un, -1
+
+	lg	%r7, 0(vp)
+	lg	%r11, 0(up)
+	lghi	%r12, 8			C init index register
+	mlgr	%r10, %r7
+	lgr	%r9, un
+	stg	%r11, 0(rp)
+	cr	%r15, %r15		C clear carry flag
+
+L(tm):	lg	%r1, 0(%r12,up)
+	mlgr	%r0, %r7
+	alcgr	%r1, %r10
+	lgr	%r10, %r0		C copy high part to carry limb
+	stg	%r1, 0(%r12,rp)
+	la	%r12, 8(%r12)
+	brctg	%r9, L(tm)
+
+	alcgr	%r0, zero
+	stg	%r0, 0(%r12,rp)
+
+C addmul_1 loop ===============================================================
+
+	aghi	vn, -1
+	je	L(outer_end)
+L(outer_loop):
+
+	la	rp, 8(rp)		C rp += 1
+	la	vp, 8(vp)		C up += 1
+	lg	%r7, 0(vp)
+	lg	%r11, 0(up)
+	lghi	%r12, 8			C init index register
+	mlgr	%r10, %r7
+	lgr	%r9, un
+	alg	%r11, 0(rp)
+	stg	%r11, 0(rp)
+
+L(tam):	lg	%r1, 0(%r12,up)
+	lg	%r11, 0(%r12,rp)
+	mlgr	%r0, %r7
+	alcgr	%r1, %r11
+	alcgr	%r0, zero
+	algr	%r1, %r10
+	lgr	%r10, %r0
+	stg	%r1, 0(%r12,rp)
+	la	%r12, 8(%r12)
+	brctg	%r9, L(tam)
+
+	alcgr	%r0, zero
+	stg	%r0, 0(%r12,rp)
+
+	brctg	vn, L(outer_loop)
+L(outer_end):
+
+	lmg	%r6, %r12, 48(%r15)
+	br	%r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/s390_64/rshift.asm b/third_party/gmp/mpn/s390_64/rshift.asm
new file mode 100644
index 0000000..e870971
--- /dev/null
+++ b/third_party/gmp/mpn/s390_64/rshift.asm
@@ -0,0 +1,195 @@
+dnl  S/390-64 mpn_rshift.
+
+dnl  Copyright 2011, 2014 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C            cycles/limb
+C z900		 7
+C z990           3
+C z9		 ?
+C z10		 6
+C z196		 ?
+
+C NOTES
+C  * See notes in lshift.asm.
+
+C INPUT PARAMETERS
+define(`rp',	`%r2')
+define(`up',	`%r3')
+define(`n',	`%r4')
+define(`cnt',	`%r5')
+
+define(`tnc',	`%r6')
+
+ASM_START()
+PROLOGUE(mpn_rshift)
+	cghi	n, 3
+	jh	L(gt1)
+
+	stmg	%r6, %r7, 48(%r15)
+	larl	%r1, L(tab)-4
+	lcgr	tnc, cnt
+	sllg	n, n, 2
+	b	0(n,%r1)
+L(tab):	j	L(n1)
+	j	L(n2)
+	j	L(n3)
+
+L(n1):	lg	%r1, 0(up)
+	srlg	%r0, %r1, 0(cnt)
+	stg	%r0, 0(rp)
+	sllg	%r2, %r1, 0(tnc)
+	lg	%r6, 48(%r15)		C restoring r7 not needed
+	br	%r14
+
+L(n2):	lg	%r1, 0(up)
+	sllg	%r4, %r1, 0(tnc)
+	srlg	%r0, %r1, 0(cnt)
+	lg	%r1, 8(up)
+	sllg	%r7, %r1, 0(tnc)
+	ogr	%r7, %r0
+	srlg	%r0, %r1, 0(cnt)
+	stg	%r7, 0(rp)
+	stg	%r0, 8(rp)
+	lgr	%r2, %r4
+	lmg	%r6, %r7, 48(%r15)
+	br	%r14
+
+
+L(n3):	lg	%r1, 0(up)
+	sllg	%r4, %r1, 0(tnc)
+	srlg	%r0, %r1, 0(cnt)
+	lg	%r1, 8(up)
+	sllg	%r7, %r1, 0(tnc)
+	ogr	%r7, %r0
+	srlg	%r0, %r1, 0(cnt)
+	stg	%r7, 0(rp)
+	lg	%r1, 16(up)
+	sllg	%r7, %r1, 0(tnc)
+	ogr	%r7, %r0
+	srlg	%r0, %r1, 0(cnt)
+	stg	%r7, 8(rp)
+	stg	%r0, 16(rp)
+	lgr	%r2, %r4
+	lmg	%r6, %r7, 48(%r15)
+	br	%r14
+
+L(gt1):	stmg	%r6, %r13, 48(%r15)
+	lcgr	tnc, cnt		C tnc = -cnt
+
+	sllg	%r1, n, 3
+	srlg	%r0, n, 2		C loop count
+
+	lghi	%r7, 3
+	ngr	%r7, n
+	je	L(b0)
+	cghi	%r7, 2
+	jl	L(b1)
+	je	L(b2)
+
+L(b3):	aghi	rp, -8
+	lg	%r7, 0(up)
+	sllg	%r9, %r7, 0(tnc)
+	srlg	%r11, %r7, 0(cnt)
+	lg	%r8, 8(up)
+	lg	%r7, 16(up)
+	sllg	%r4, %r8, 0(tnc)
+	srlg	%r13, %r8, 0(cnt)
+	ogr	%r11, %r4
+	la	up, 24(up)
+	j	L(lm3)
+
+L(b2):	aghi	rp, -16
+	lg	%r8, 0(up)
+	lg	%r7, 8(up)
+	sllg	%r9, %r8, 0(tnc)
+	srlg	%r13, %r8, 0(cnt)
+	la	up, 16(up)
+	j	L(lm2)
+
+L(b1):	aghi	rp, -24
+	lg	%r7, 0(up)
+	sllg	%r9, %r7, 0(tnc)
+	srlg	%r11, %r7, 0(cnt)
+	lg	%r8, 8(up)
+	lg	%r7, 16(up)
+	sllg	%r4, %r8, 0(tnc)
+	srlg	%r10, %r8, 0(cnt)
+	ogr	%r11, %r4
+	la	up, 8(up)
+	j	L(lm1)
+
+L(b0):	aghi	rp, -32
+	lg	%r8, 0(up)
+	lg	%r7, 8(up)
+	sllg	%r9, %r8, 0(tnc)
+	srlg	%r10, %r8, 0(cnt)
+	j	L(lm0)
+
+	ALIGN(8)
+L(top):	sllg	%r4, %r8, 0(tnc)
+	srlg	%r13, %r8, 0(cnt)
+	ogr	%r11, %r4
+	stg	%r10, 0(rp)
+L(lm3):	stg	%r11, 8(rp)
+L(lm2):	sllg	%r12, %r7, 0(tnc)
+	srlg	%r11, %r7, 0(cnt)
+	lg	%r8, 0(up)
+	lg	%r7, 8(up)
+	ogr	%r13, %r12
+	sllg	%r4, %r8, 0(tnc)
+	srlg	%r10, %r8, 0(cnt)
+	ogr	%r11, %r4
+	stg	%r13, 16(rp)
+L(lm1):	stg	%r11, 24(rp)
+L(lm0):	sllg	%r12, %r7, 0(tnc)
+	aghi	rp, 32
+	srlg	%r11, %r7, 0(cnt)
+	lg	%r8, 16(up)
+	lg	%r7, 24(up)
+	aghi	up, 32
+	ogr	%r10, %r12
+	brctg	%r0, L(top)
+
+L(end):	sllg	%r4, %r8, 0(tnc)
+	srlg	%r13, %r8, 0(cnt)
+	ogr	%r11, %r4
+	stg	%r10, 0(rp)
+	stg	%r11, 8(rp)
+	sllg	%r12, %r7, 0(tnc)
+	srlg	%r11, %r7, 0(cnt)
+	ogr	%r13, %r12
+	stg	%r13, 16(rp)
+	stg	%r11, 24(rp)
+	lgr	%r2, %r9
+
+	lmg	%r6, %r13, 48(%r15)
+	br	%r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/s390_64/sqr_basecase.asm b/third_party/gmp/mpn/s390_64/sqr_basecase.asm
new file mode 100644
index 0000000..bf31bd5
--- /dev/null
+++ b/third_party/gmp/mpn/s390_64/sqr_basecase.asm
@@ -0,0 +1,203 @@
+dnl  S/390-64 mpn_sqr_basecase.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C            cycles/limb
+C z900		 ?
+C z990		23
+C z9		 ?
+C z10		28
+C z196		 ?
+
+C TODO
+C  * Clean up.
+C  * Stop iterating addmul_1 loop at latest for n = 2, implement longer tail.
+C    This will ask for basecase handling of n = 3.
+C  * Update counters and pointers more straightforwardly, possibly lowering
+C    register usage.
+C  * Should we use this allocation-free style for more sqr_basecase asm
+C    implementations?  The only disadvantage is that it requires R != U.
+C  * Replace loops by faster code.  The mul_1 and addmul_1 loops could be sped
+C    up by about 10%.  The sqr_diag_addlsh1 loop could probably be sped up even
+C    more.
+
+C INPUT PARAMETERS
+define(`rp',	`%r2')
+define(`up',	`%r3')
+define(`n',	`%r4')
+
+define(`zero',	`%r8')
+define(`rp_saved',	`%r9')
+define(`up_saved',	`%r13')
+define(`n_saved',	`%r14')
+
+ASM_START()
+PROLOGUE(mpn_sqr_basecase)
+	aghi	n, -2
+	jhe	L(ge2)
+
+C n = 1
+	lg	%r5, 0(up)
+	mlgr	%r4, %r5
+	stg	%r5, 0(rp)
+	stg	%r4, 8(rp)
+	br	%r14
+
+L(ge2):	jne	L(gen)
+
+C n = 2
+	stmg	%r6, %r8, 48(%r15)
+	lghi	zero, 0
+
+	lg	%r5, 0(up)
+	mlgr	%r4, %r5		C u0 * u0
+	lg	%r1, 8(up)
+	mlgr	%r0, %r1		C u1 * u1
+	stg	%r5, 0(rp)
+
+	lg	%r7, 0(up)
+	mlg	%r6, 8(up)		C u0 * u1
+	algr	%r7, %r7
+	alcgr	%r6, %r6
+	alcgr	%r0, zero
+
+	algr	%r4, %r7
+	alcgr	%r1, %r6
+	alcgr	%r0, zero
+	stg	%r4, 8(rp)
+	stg	%r1, 16(rp)
+	stg	%r0, 24(rp)
+
+	lmg	%r6, %r8, 48(%r15)
+	br	%r14
+
+L(gen):
+C mul_1 =======================================================================
+
+	stmg	%r6, %r14, 48(%r15)
+	lghi	zero, 0
+	lgr	up_saved, up
+	lgr	rp_saved, rp
+	lgr	n_saved, n
+
+	lg	%r6, 0(up)
+	lg	%r11, 8(up)
+	lghi	%r12, 16		C init index register
+	mlgr	%r10, %r6
+	lgr	%r5, n
+	stg	%r11, 8(rp)
+	cr	%r15, %r15		C clear carry flag
+
+L(tm):	lg	%r1, 0(%r12,up)
+	mlgr	%r0, %r6
+	alcgr	%r1, %r10
+	lgr	%r10, %r0		C copy high part to carry limb
+	stg	%r1, 0(%r12,rp)
+	la	%r12, 8(%r12)
+	brctg	%r5, L(tm)
+
+	alcgr	%r0, zero
+	stg	%r0, 0(%r12,rp)
+
+C addmul_1 loop ===============================================================
+
+	aghi	n, -1
+	je	L(outer_end)
+L(outer_loop):
+
+	la	rp, 16(rp)		C rp += 2
+	la	up, 8(up)		C up += 1
+	lg	%r6, 0(up)
+	lg	%r11, 8(up)
+	lghi	%r12, 16		C init index register
+	mlgr	%r10, %r6
+	lgr	%r5, n
+	alg	%r11, 8(rp)
+	stg	%r11, 8(rp)
+
+L(tam):	lg	%r1, 0(%r12,up)
+	lg	%r7, 0(%r12,rp)
+	mlgr	%r0, %r6
+	alcgr	%r1, %r7
+	alcgr	%r0, zero
+	algr	%r1, %r10
+	lgr	%r10, %r0
+	stg	%r1, 0(%r12,rp)
+	la	%r12, 8(%r12)
+	brctg	%r5, L(tam)
+
+	alcgr	%r0, zero
+	stg	%r0, 0(%r12,rp)
+
+	brctg	n, L(outer_loop)
+L(outer_end):
+
+	lg	%r6, 8(up)
+	lg	%r1, 16(up)
+	lgr	%r7, %r0		C Same as: lg %r7, 24(,rp)
+	mlgr	%r0, %r6
+	algr	%r1, %r7
+	alcgr	%r0, zero
+	stg	%r1, 24(rp)
+	stg	%r0, 32(rp)
+
+C sqr_diag_addlsh1 ============================================================
+
+define(`up', `up_saved')
+define(`rp', `rp_saved')
+	la	n, 1(n_saved)
+
+	lg	%r1, 0(up)
+	mlgr	%r0, %r1
+	stg	%r1, 0(rp)
+C	clr	%r15, %r15		C clear carry (already clear per above)
+
+L(top):	lg	%r11, 8(up)
+	la	up, 8(up)
+	lg	%r6, 8(rp)
+	lg	%r7, 16(rp)
+	mlgr	%r10, %r11
+	alcgr	%r6, %r6
+	alcgr	%r7, %r7
+	alcgr	%r10, zero		C propagate carry to high product limb
+	algr	%r6, %r0
+	alcgr	%r7, %r11
+	stmg	%r6, %r7, 8(rp)
+	la	rp, 16(rp)
+	lgr	%r0, %r10		C copy carry limb
+	brctg	n, L(top)
+
+	alcgr	%r0, zero
+	stg	%r0, 8(rp)
+
+	lmg	%r6, %r14, 48(%r15)
+	br	%r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/s390_64/sublsh1_n.asm b/third_party/gmp/mpn/s390_64/sublsh1_n.asm
new file mode 100644
index 0000000..50f127a
--- /dev/null
+++ b/third_party/gmp/mpn/s390_64/sublsh1_n.asm
@@ -0,0 +1,169 @@
+dnl  S/390-64 mpn_sublsh1_n
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C            cycles/limb
+C z900		10
+C z990		 5
+C z9		 ?
+C z10		12
+C z196		 ?
+
+C TODO
+C  * Optimise for small n
+C  * Compute RETVAL for sublsh1_n less stupidly
+
+C INPUT PARAMETERS
+define(`rp',	`%r2')
+define(`up',	`%r3')
+define(`vp',	`%r4')
+define(`n',	`%r5')
+
+ifdef(`OPERATION_addlsh1_n',`
+  define(ADSBR,		algr)
+  define(ADSBCR,	alcgr)
+  define(INITCY,	`lghi	%r13, -1')
+  define(RETVAL,	`la	%r2, 2(%r1,%r13)')
+  define(func, mpn_addlsh1_n)
+')
+ifdef(`OPERATION_sublsh1_n',`
+  define(ADSBR,		slgr)
+  define(ADSBCR,	slbgr)
+  define(INITCY,	`lghi	%r13, 0')
+  define(RETVAL,`dnl
+	slgr	%r1, %r13
+	lghi	%r2, 1
+	algr	%r2, %r1')
+  define(func, mpn_sublsh1_n)
+')
+
+ASM_START()
+PROLOGUE(mpn_sublsh1_n)
+	stmg	%r6, %r13, 48(%r15)
+
+	aghi	n, 3
+	lghi	%r7, 3
+	srlg	%r0, n, 2
+	ngr	%r7, n			C n mod 4
+	je	L(b1)
+	cghi	%r7, 2
+	jl	L(b2)
+	jne	L(b0)
+
+L(b3):	lmg	%r5, %r7, 0(up)
+	la	up, 24(up)
+	lmg	%r9, %r11, 0(vp)
+	la	vp, 24(vp)
+
+	algr	%r9, %r9
+	alcgr	%r10, %r10
+	alcgr	%r11, %r11
+	slbgr	%r1, %r1
+
+	ADSBR	%r5, %r9
+	ADSBCR	%r6, %r10
+	ADSBCR	%r7, %r11
+	slbgr	%r13, %r13
+
+	stmg	%r5, %r7, 0(rp)
+	la	rp, 24(rp)
+	brctg	%r0, L(top)
+	j	L(end)
+
+L(b0):	lghi	%r1, -1
+	INITCY
+	j	L(top)
+
+L(b1):	lg	%r5, 0(up)
+	la	up, 8(up)
+	lg	%r9, 0(vp)
+	la	vp, 8(vp)
+
+	algr	%r9, %r9
+	slbgr	%r1, %r1
+	ADSBR	%r5, %r9
+	slbgr	%r13, %r13
+
+	stg	%r5, 0(rp)
+	la	rp, 8(rp)
+	brctg	%r0, L(top)
+	j	L(end)
+
+L(b2):	lmg	%r5, %r6, 0(up)
+	la	up, 16(up)
+	lmg	%r9, %r10, 0(vp)
+	la	vp, 16(vp)
+
+	algr	%r9, %r9
+	alcgr	%r10, %r10
+	slbgr	%r1, %r1
+
+	ADSBR	%r5, %r9
+	ADSBCR	%r6, %r10
+	slbgr	%r13, %r13
+
+	stmg	%r5, %r6, 0(rp)
+	la	rp, 16(rp)
+	brctg	%r0, L(top)
+	j	L(end)
+
+L(top):	lmg	%r9, %r12, 0(vp)
+	la	vp, 32(vp)
+
+	aghi	%r1, 1			C restore carry
+
+	alcgr	%r9, %r9
+	alcgr	%r10, %r10
+	alcgr	%r11, %r11
+	alcgr	%r12, %r12
+
+	slbgr	%r1, %r1		C save carry
+
+	lmg	%r5, %r8, 0(up)
+	la	up, 32(up)
+
+	aghi	%r13, 1			C restore carry
+
+	ADSBCR	%r5, %r9
+	ADSBCR	%r6, %r10
+	ADSBCR	%r7, %r11
+	ADSBCR	%r8, %r12
+
+	slbgr	%r13, %r13		C save carry
+
+	stmg	%r5, %r8, 0(rp)
+	la	rp, 32(rp)
+	brctg	%r0, L(top)
+
+L(end):	RETVAL
+	lmg	%r6, %r13, 48(%r15)
+	br	%r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/s390_64/submul_1.asm b/third_party/gmp/mpn/s390_64/submul_1.asm
new file mode 100644
index 0000000..91c4b06
--- /dev/null
+++ b/third_party/gmp/mpn/s390_64/submul_1.asm
@@ -0,0 +1,70 @@
+dnl  S/390-64 mpn_submul_1
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C            cycles/limb
+C z900		35
+C z990		24
+C z9		 ?
+C z10		28
+C z196		 ?
+
+C INPUT PARAMETERS
+define(`rp',	`%r2')
+define(`up',	`%r3')
+define(`n',	`%r4')
+define(`v0',	`%r5')
+
+ASM_START()
+PROLOGUE(mpn_submul_1)
+	stmg	%r9, %r12, 72(%r15)
+	lghi	%r12, 0
+	slgr	%r11, %r11
+
+L(top):	lg	%r1, 0(%r12, up)
+	lg	%r10, 0(%r12, rp)
+	mlgr	%r0, v0
+	slbgr	%r10, %r1
+	slbgr	%r9, %r9
+	slgr	%r0, %r9		C conditional incr
+	slgr	%r10, %r11
+	lgr	%r11, %r0
+	stg	%r10, 0(%r12, rp)
+	la	%r12, 8(%r12)
+	brctg	%r4,  L(top)
+
+	lgr	%r2, %r11
+	slbgr	%r9, %r9
+	slgr	%r2, %r9
+
+	lmg	%r9, %r12, 72(%r15)
+	br	%r14
+EPILOGUE()
diff --git a/third_party/gmp/mpn/s390_64/z10/gmp-mparam.h b/third_party/gmp/mpn/s390_64/z10/gmp-mparam.h
new file mode 100644
index 0000000..c3a9416
--- /dev/null
+++ b/third_party/gmp/mpn/s390_64/z10/gmp-mparam.h
@@ -0,0 +1,233 @@
+/* S/390-64 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 2000-2011, 2014, 2015 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+/* 4400 MHz IBM z10 */
+/* FFT tuning limit = 30 M */
+/* Generated by tuneup.c, 2015-10-09, gcc 4.8 */
+
+#define DIVREM_1_NORM_THRESHOLD              0  /* always */
+#define DIVREM_1_UNNORM_THRESHOLD            3
+#define MOD_1_1P_METHOD                      2
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               3
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          6
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          5
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        15
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        17
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     24
+#define USE_PREINV_DIVREM_1                  1
+#define DIV_QR_1N_PI1_METHOD                 1
+#define DIV_QR_1_NORM_THRESHOLD              2
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always */
+#define BMOD_1_TO_MOD_1_THRESHOLD           48
+
+#define MUL_TOOM22_THRESHOLD                 9
+#define MUL_TOOM33_THRESHOLD                65
+#define MUL_TOOM44_THRESHOLD                94
+#define MUL_TOOM6H_THRESHOLD               129
+#define MUL_TOOM8H_THRESHOLD               187
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      65
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD      61
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD      62
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD      64
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD      85
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 11
+#define SQR_TOOM3_THRESHOLD                 80
+#define SQR_TOOM4_THRESHOLD                118
+#define SQR_TOOM6_THRESHOLD                189
+#define SQR_TOOM8_THRESHOLD                236
+
+#define MULMID_TOOM42_THRESHOLD             24
+
+#define MULMOD_BNM1_THRESHOLD                7
+#define SQRMOD_BNM1_THRESHOLD                9
+
+#define MUL_FFT_MODF_THRESHOLD             252  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    252, 5}, {      9, 6}, {      5, 5}, {     11, 6}, \
+    {      6, 5}, {     13, 6}, {      7, 5}, {     15, 6}, \
+    {     13, 7}, {      7, 6}, {     15, 7}, {     13, 8}, \
+    {      7, 7}, {     15, 8}, {      9, 7}, {     19, 8}, \
+    {     11, 7}, {     23, 8}, {     13, 9}, {      7, 8}, \
+    {     15, 7}, {     31, 8}, {     19, 9}, {     11, 8}, \
+    {     27,10}, {      7, 9}, {     15, 8}, {     31, 9}, \
+    {     19, 8}, {     41, 9}, {     27,10}, {     15, 9}, \
+    {     39,10}, {     23, 9}, {     47,11}, {     15,10}, \
+    {     31, 9}, {     67,10}, {     39, 9}, {     79,10}, \
+    {     47,11}, {     31,10}, {     63, 9}, {    127, 8}, \
+    {    255,10}, {     71, 9}, {    143, 8}, {    287, 7}, \
+    {    575, 6}, {   1151,10}, {     79,11}, {     47,12}, \
+    {     31,11}, {     63,10}, {    127, 9}, {    255, 8}, \
+    {    511,10}, {    143,11}, {     79,10}, {    159, 9}, \
+    {    319, 8}, {    639,10}, {    175, 8}, {    703,11}, \
+    {     95,10}, {    191, 9}, {    383, 8}, {    767, 9}, \
+    {    415, 8}, {    831, 7}, {   1663,10}, {    239, 9}, \
+    {    479,12}, {     63,11}, {    127,10}, {    255, 9}, \
+    {    511,11}, {    143,10}, {    287, 9}, {    575, 8}, \
+    {   1151,10}, {    319, 9}, {    639,11}, {    175,10}, \
+    {    351, 9}, {    703, 8}, {   1407, 7}, {   2815,11}, \
+    {    191,10}, {    383, 9}, {    767,10}, {    415,11}, \
+    {    223,10}, {    447, 9}, {    895,13}, {     63,11}, \
+    {    255,10}, {    575, 9}, {   1151,12}, {    159,11}, \
+    {    319,10}, {    639, 9}, {   1279,10}, {    703, 9}, \
+    {   1407,12}, {    191,10}, {    767,11}, {    415,12}, \
+    {    223,11}, {    447,10}, {    895,11}, {    479,13}, \
+    {    127,12}, {    255,11}, {    511,12}, {    287,10}, \
+    {   1151,12}, {    319,11}, {    703,10}, {   1407, 9}, \
+    {   2815,12}, {    383,11}, {    767,12}, {    415,11}, \
+    {    831,10}, {   1663,12}, {    447,11}, {    895,10}, \
+    {   1791, 9}, {   3583,12}, {    479,11}, {    959,10}, \
+    {   1919, 9}, {   3839,12}, {    511, 9}, {   4095, 6}, \
+    {  32767, 8}, {   8447,11}, {   1151,13}, {    319,12}, \
+    {    639,10}, {   2559,12}, {    703,10}, {   2815,12}, \
+    {    831,11}, {   1663,12}, {    895,11}, {   1791,12}, \
+    {    959,11}, {   1919,14}, {    255,13}, {    511,11}, \
+    {   2047,12}, {   1215,10}, {   4863,11}, {   2559,14}, \
+    {    383,12}, {   1535,13}, {    831,12}, {   1663,13}, \
+    {    895,12}, {   1791,11}, {   3583,15}, {    255,14}, \
+    {    511,13}, {   1151,14}, {    639,13}, {   1279,12}, \
+    {   2559,13}, {   1407,12}, {   2815,14}, {    767,13}, \
+    {   1663,10}, {  13311,14}, {    895,13}, {   1791,12}, \
+    {   3583,13}, {   1919,12}, {   3839,10}, {  15359,14}, \
+    {   1151,13}, {   2431,12}, {   4863,14}, {   1279,13}, \
+    {   2559,14}, {   1407,13}, {   2815,15}, {    767,14}, \
+    {   1791,13}, {   8192,14}, {  16384,15}, {  32768,16}, \
+    {  65536,17}, { 131072,18}, { 262144,19}, { 524288,20}, \
+    {1048576,21}, {2097152,22}, {4194304,23}, {8388608,24} }
+#define MUL_FFT_TABLE3_SIZE 200
+#define MUL_FFT_THRESHOLD                 1728
+
+#define SQR_FFT_MODF_THRESHOLD             212  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    212, 5}, {      7, 4}, {     15, 5}, {      9, 4}, \
+    {     19, 6}, {      5, 5}, {     11, 6}, {      6, 5}, \
+    {     13, 6}, {      7, 5}, {     15, 6}, {      9, 5}, \
+    {     19, 6}, {     13, 7}, {      7, 6}, {     15, 7}, \
+    {      9, 6}, {     19, 7}, {     13, 8}, {      7, 7}, \
+    {     16, 8}, {      9, 7}, {     19, 8}, {     11, 7}, \
+    {     23, 8}, {     13, 9}, {      7, 8}, {     19, 9}, \
+    {     11, 8}, {     25,10}, {      7, 9}, {     15, 8}, \
+    {     31, 9}, {     23,10}, {     15, 9}, {     39,10}, \
+    {     23,11}, {     15,10}, {     31, 9}, {     63,10}, \
+    {     47,11}, {     31,10}, {     63, 9}, {    127, 8}, \
+    {    255,10}, {     71, 9}, {    143, 8}, {    287, 7}, \
+    {    575,11}, {     47,12}, {     31,11}, {     63,10}, \
+    {    127, 9}, {    255, 8}, {    511,10}, {    143, 9}, \
+    {    287, 8}, {    575, 7}, {   1151,11}, {     79,10}, \
+    {    159, 9}, {    319,10}, {    175, 9}, {    351, 8}, \
+    {    703, 7}, {   1407,10}, {    191, 9}, {    383,10}, \
+    {    207,11}, {    111,10}, {    223,12}, {     63,11}, \
+    {    127,10}, {    255, 9}, {    511,11}, {    143,10}, \
+    {    287, 9}, {    575, 8}, {   1151,11}, {    159,10}, \
+    {    319, 9}, {    639,11}, {    175,10}, {    351, 9}, \
+    {    703, 8}, {   1407,11}, {    191,10}, {    383,11}, \
+    {    207,10}, {    415,11}, {    223,10}, {    447,13}, \
+    {     63,12}, {    127,11}, {    255,10}, {    511,11}, \
+    {    287,10}, {    575, 9}, {   1151,12}, {    159,11}, \
+    {    319,10}, {    639,11}, {    351,10}, {    703, 9}, \
+    {   1407,12}, {    191,11}, {    383,10}, {    767,11}, \
+    {    415,12}, {    223,11}, {    447,10}, {    895, 9}, \
+    {   1791,13}, {    127,12}, {    255,11}, {    511,12}, \
+    {    287,11}, {    575,10}, {   1151,11}, {    607,12}, \
+    {    319,11}, {    639,12}, {    351,11}, {    703,10}, \
+    {   1407,13}, {    191,12}, {    383,11}, {    767,12}, \
+    {    415,11}, {    831,10}, {   1663,12}, {    447,11}, \
+    {    895,10}, {   1791,14}, {    127,13}, {    255,12}, \
+    {    511,11}, {   1023,10}, {   2047,11}, {   1151,12}, \
+    {    607,13}, {    319,11}, {   1279, 9}, {   5119, 8}, \
+    {  10751, 4}, { 172031, 7}, {  22015,11}, {   1407,10}, \
+    {   2943, 8}, {  11775, 9}, {   6143,12}, {    831, 8}, \
+    {  13311,11}, {   1791,14}, {    255,11}, {   2047,13}, \
+    {    575,12}, {   1151,13}, {    639,12}, {   1279,13}, \
+    {    703,12}, {   1407,11}, {   2815,12}, {   1471, 9}, \
+    {  11775,13}, {    767,12}, {   1535,13}, {    831,12}, \
+    {   1663,13}, {    895,11}, {   3583,13}, {    959,12}, \
+    {   1919,10}, {   7679, 9}, {  15359,11}, {   3967,14}, \
+    {    511,13}, {   1151,12}, {   2303,13}, {   1215,14}, \
+    {    639,13}, {   1279,12}, {   2559,14}, {    767,13}, \
+    {   1663,14}, {    895,15}, {    511,13}, {   2047,14}, \
+    {   1279,13}, {   2815,15}, {    767,14}, {   1791,13}, \
+    {   3583,16}, {  65536,17}, { 131072,18}, { 262144,19}, \
+    { 524288,20}, {1048576,21}, {2097152,22}, {4194304,23}, \
+    {8388608,24} }
+#define SQR_FFT_TABLE3_SIZE 201
+#define SQR_FFT_THRESHOLD                 1344
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  33
+#define MULLO_MUL_N_THRESHOLD             2586
+#define SQRLO_BASECASE_THRESHOLD             0  /* always */
+#define SQRLO_DC_THRESHOLD                  63
+#define SQRLO_SQR_THRESHOLD               2663
+
+#define DC_DIV_QR_THRESHOLD                 37
+#define DC_DIVAPPR_Q_THRESHOLD             143
+#define DC_BDIV_QR_THRESHOLD                37
+#define DC_BDIV_Q_THRESHOLD                 86
+
+#define INV_MULMOD_BNM1_THRESHOLD           16
+#define INV_NEWTON_THRESHOLD               147
+#define INV_APPR_THRESHOLD                 141
+
+#define BINV_NEWTON_THRESHOLD              141
+#define REDC_1_TO_REDC_N_THRESHOLD          39
+
+#define MU_DIV_QR_THRESHOLD                807
+#define MU_DIVAPPR_Q_THRESHOLD             807
+#define MUPI_DIV_QR_THRESHOLD               81
+#define MU_BDIV_QR_THRESHOLD               654
+#define MU_BDIV_Q_THRESHOLD                792
+
+#define POWM_SEC_TABLE  1,28,163,1083,2111
+
+#define GET_STR_DC_THRESHOLD                19
+#define GET_STR_PRECOMPUTE_THRESHOLD        33
+#define SET_STR_DC_THRESHOLD               898
+#define SET_STR_PRECOMPUTE_THRESHOLD      2031
+
+#define FAC_DSC_THRESHOLD                  372
+#define FAC_ODD_THRESHOLD                   23
+
+#define MATRIX22_STRASSEN_THRESHOLD         17
+#define HGCD_THRESHOLD                     105
+#define HGCD_APPR_THRESHOLD                111
+#define HGCD_REDUCE_THRESHOLD             1137
+#define GCD_DC_THRESHOLD                   285
+#define GCDEXT_DC_THRESHOLD                210
+#define JACOBI_BASE_METHOD                   4
diff --git a/third_party/gmp/mpn/sh/add_n.asm b/third_party/gmp/mpn/sh/add_n.asm
new file mode 100644
index 0000000..79d17d0
--- /dev/null
+++ b/third_party/gmp/mpn/sh/add_n.asm
@@ -0,0 +1,59 @@
+dnl  SH mpn_add_n -- Add two limb vectors of the same length > 0 and store sum
+dnl  in a third limb vector.
+
+dnl  Copyright 1995, 1997, 2000, 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C rp		r4
+C up		r5
+C vp		r6
+C n		r7
+
+changecom(blah)			C disable # to make all C comments below work
+
+ASM_START()
+PROLOGUE(mpn_add_n)
+	mov	#0,r3		C clear cy save reg
+
+L(top):	mov.l	@r5+,r1
+	mov.l	@r6+,r2
+	shlr	r3		C restore cy
+	addc	r2,r1
+	movt	r3		C save cy
+	mov.l	r1,@r4
+	dt	r7
+	bf.s	L(top)
+	 add	#4,r4
+
+	rts
+	mov	r3,r0		C return carry-out from most significant limb
+EPILOGUE()
diff --git a/third_party/gmp/mpn/sh/sh2/addmul_1.asm b/third_party/gmp/mpn/sh/sh2/addmul_1.asm
new file mode 100644
index 0000000..c914b29
--- /dev/null
+++ b/third_party/gmp/mpn/sh/sh2/addmul_1.asm
@@ -0,0 +1,65 @@
+dnl  SH2 mpn_addmul_1 -- Multiply a limb vector with a limb and add the result
+dnl  to a second limb vector.
+
+dnl  Copyright 1995, 2000, 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C res_ptr	r4
+C s1_ptr	r5
+C size		r6
+C s2_limb	r7
+
+changecom(blah)			C disable # to make all C comments below work
+
+ASM_START()
+PROLOGUE(mpn_addmul_1)
+	mov	#0,r2		C cy_limb = 0
+	mov	#0,r0		C Keep r0 = 0 for entire loop
+	clrt
+
+L(top):	mov.l	@r5+,r3
+	dmulu.l	r3,r7
+	sts	macl,r1
+	addc	r2,r1		C lo_prod += old cy_limb
+	sts	mach,r2		C new cy_limb = hi_prod
+	mov.l	@r4,r3
+	addc	r0,r2		C cy_limb += T, T = 0
+	addc	r3,r1
+	addc	r0,r2		C cy_limb += T, T = 0
+	dt	r6
+	mov.l	r1,@r4
+	bf.s	L(top)
+	add	#4,r4
+
+	rts
+	mov	r2,r0
+EPILOGUE()
diff --git a/third_party/gmp/mpn/sh/sh2/mul_1.asm b/third_party/gmp/mpn/sh/sh2/mul_1.asm
new file mode 100644
index 0000000..83548a6
--- /dev/null
+++ b/third_party/gmp/mpn/sh/sh2/mul_1.asm
@@ -0,0 +1,62 @@
+dnl  SH2 mpn_mul_1 -- Multiply a limb vector with a limb and store the result
+dnl  in a second limb vector.
+
+dnl  Copyright 1995, 2000, 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C res_ptr	r4
+C s1_ptr	r5
+C size		r6
+C s2_limb	r7
+
+changecom(blah)			C disable # to make all C comments below work
+
+ASM_START()
+PROLOGUE(mpn_mul_1)
+	mov	#0,r2		C cy_limb = 0
+	mov	#0,r0		C Keep r0 = 0 for entire loop
+	clrt
+
+L(top):	mov.l	@r5+,r3
+	dmulu.l	r3,r7
+	sts	macl,r1
+	addc	r2,r1
+	sts	mach,r2
+	addc	r0,r2		C propagate carry to cy_limb (dt clobbers T)
+	dt	r6
+	mov.l	r1,@r4
+	bf.s	L(top)
+	add	#4,r4
+
+	rts
+	mov	r2,r0
+EPILOGUE()
diff --git a/third_party/gmp/mpn/sh/sh2/submul_1.asm b/third_party/gmp/mpn/sh/sh2/submul_1.asm
new file mode 100644
index 0000000..bef2abd
--- /dev/null
+++ b/third_party/gmp/mpn/sh/sh2/submul_1.asm
@@ -0,0 +1,65 @@
+dnl  SH2 mpn_submul_1 -- Multiply a limb vector with a limb and subtract the
+dnl  result from a second limb vector.
+
+dnl  Copyright 1995, 2000, 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C res_ptr	r4
+C s1_ptr	r5
+C size		r6
+C s2_limb	r7
+
+changecom(blah)			C disable # to make all C comments below work
+
+ASM_START()
+PROLOGUE(mpn_submul_1)
+	mov	#0,r2		C cy_limb = 0
+	mov	#0,r0		C Keep r0 = 0 for entire loop
+	clrt
+
+L(top):	mov.l	@r5+,r3
+	dmulu.l	r3,r7
+	sts	macl,r1
+	addc	r2,r1		C lo_prod += old cy_limb
+	sts	mach,r2		C new cy_limb = hi_prod
+	mov.l	@r4,r3
+	addc	r0,r2		C cy_limb += T, T = 0
+	subc	r1,r3
+	addc	r0,r2		C cy_limb += T, T = 0
+	dt	r6
+	mov.l	r3,@r4
+	bf.s	L(top)
+	add	#4,r4
+
+	rts
+	mov	r2,r0
+EPILOGUE()
diff --git a/third_party/gmp/mpn/sh/sub_n.asm b/third_party/gmp/mpn/sh/sub_n.asm
new file mode 100644
index 0000000..465bc80
--- /dev/null
+++ b/third_party/gmp/mpn/sh/sub_n.asm
@@ -0,0 +1,59 @@
+dnl  SH mpn_sub_n -- Subtract two limb vectors of the same length > 0 and store
+dnl  difference in a third limb vector.
+
+dnl  Copyright 1995, 1997, 2000, 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C rp		r4
+C up		r5
+C vp		r6
+C n		r7
+
+changecom(blah)			C disable # to make all C comments below work
+
+ASM_START()
+PROLOGUE(mpn_sub_n)
+	mov	#0,r3		C clear cy save reg
+
+L(top):	mov.l	@r5+,r1
+	mov.l	@r6+,r2
+	shlr	r3		C restore cy
+	subc	r2,r1
+	movt	r3		C save cy
+	mov.l	r1,@r4
+	dt	r7
+	bf.s	L(top)
+	 add	#4,r4
+
+	rts
+	mov	r3,r0		C return carry-out from most significant limb
+EPILOGUE()
diff --git a/third_party/gmp/mpn/sparc32/README b/third_party/gmp/mpn/sparc32/README
new file mode 100644
index 0000000..f2dd116
--- /dev/null
+++ b/third_party/gmp/mpn/sparc32/README
@@ -0,0 +1,71 @@
+Copyright 1996, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.
+
+
+
+
+
+This directory contains mpn functions for various SPARC chips.  Code that
+runs only on version 8 SPARC implementations, is in the v8 subdirectory.
+
+RELEVANT OPTIMIZATION ISSUES
+
+  Load and Store timing
+
+On most early SPARC implementations, the ST instructions takes multiple
+cycles, while a STD takes just a single cycle more than an ST.  For the CPUs
+in SPARCstation I and II, the times are 3 and 4 cycles, respectively.
+Therefore, combining two ST instructions into a STD when possible is a
+significant optimization.
+
+Later SPARC implementations have single cycle ST.
+
+For SuperSPARC, we can perform just one memory instruction per cycle, even
+if up to two integer instructions can be executed in its pipeline.  For
+programs that perform so many memory operations that there are not enough
+non-memory operations to issue in parallel with all memory operations, using
+LDD and STD when possible helps.
+
+UltraSPARC-1/2 has very slow integer multiplication.  In the v9 subdirectory,
+we therefore use floating-point multiplication.
+
+STATUS
+
+1. On a SuperSPARC, mpn_lshift and mpn_rshift run at 3 cycles/limb, or 2.5
+   cycles/limb asymptotically.  We could optimize speed for special counts
+   by using ADDXCC.
+
+2. On a SuperSPARC, mpn_add_n and mpn_sub_n runs at 2.5 cycles/limb, or 2
+   cycles/limb asymptotically.
+
+3. mpn_mul_1 runs at what is believed to be optimal speed.
+
+4. On SuperSPARC, mpn_addmul_1 and mpn_submul_1 could both be improved by a
+   cycle by avoiding one of the add instructions.  See a29k/addmul_1.
+
+The speed of the code for other SPARC implementations is uncertain.
diff --git a/third_party/gmp/mpn/sparc32/add_n.asm b/third_party/gmp/mpn/sparc32/add_n.asm
new file mode 100644
index 0000000..8549195
--- /dev/null
+++ b/third_party/gmp/mpn/sparc32/add_n.asm
@@ -0,0 +1,245 @@
+dnl  SPARC mpn_add_n -- Add two limb vectors of the same length > 0 and store
+dnl  sum in a third limb vector.
+
+dnl  Copyright 1995, 1996, 2000 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+define(res_ptr,%o0)
+define(s1_ptr,%o1)
+define(s2_ptr,%o2)
+define(n,%o3)
+
+ASM_START()
+PROLOGUE(mpn_add_n)
+	xor	s2_ptr,res_ptr,%g1
+	andcc	%g1,4,%g0
+	bne	L(1)			C branch if alignment differs
+	nop
+C **  V1a  **
+L(0):	andcc	res_ptr,4,%g0		C res_ptr unaligned? Side effect: cy=0
+	be	L(v1)			C if no, branch
+	nop
+C Add least significant limb separately to align res_ptr and s2_ptr
+	ld	[s1_ptr],%g4
+	add	s1_ptr,4,s1_ptr
+	ld	[s2_ptr],%g2
+	add	s2_ptr,4,s2_ptr
+	add	n,-1,n
+	addcc	%g4,%g2,%o4
+	st	%o4,[res_ptr]
+	add	res_ptr,4,res_ptr
+L(v1):	addx	%g0,%g0,%o4		C save cy in register
+	cmp	n,2			C if n < 2 ...
+	bl	L(end2)			C ... branch to tail code
+	subcc	%g0,%o4,%g0		C restore cy
+
+	ld	[s1_ptr+0],%g4
+	addcc	n,-10,n
+	ld	[s1_ptr+4],%g1
+	ldd	[s2_ptr+0],%g2
+	blt	L(fin1)
+	subcc	%g0,%o4,%g0		C restore cy
+C Add blocks of 8 limbs until less than 8 limbs remain
+L(loop1):
+	addxcc	%g4,%g2,%o4
+	ld	[s1_ptr+8],%g4
+	addxcc	%g1,%g3,%o5
+	ld	[s1_ptr+12],%g1
+	ldd	[s2_ptr+8],%g2
+	std	%o4,[res_ptr+0]
+	addxcc	%g4,%g2,%o4
+	ld	[s1_ptr+16],%g4
+	addxcc	%g1,%g3,%o5
+	ld	[s1_ptr+20],%g1
+	ldd	[s2_ptr+16],%g2
+	std	%o4,[res_ptr+8]
+	addxcc	%g4,%g2,%o4
+	ld	[s1_ptr+24],%g4
+	addxcc	%g1,%g3,%o5
+	ld	[s1_ptr+28],%g1
+	ldd	[s2_ptr+24],%g2
+	std	%o4,[res_ptr+16]
+	addxcc	%g4,%g2,%o4
+	ld	[s1_ptr+32],%g4
+	addxcc	%g1,%g3,%o5
+	ld	[s1_ptr+36],%g1
+	ldd	[s2_ptr+32],%g2
+	std	%o4,[res_ptr+24]
+	addx	%g0,%g0,%o4		C save cy in register
+	addcc	n,-8,n
+	add	s1_ptr,32,s1_ptr
+	add	s2_ptr,32,s2_ptr
+	add	res_ptr,32,res_ptr
+	bge	L(loop1)
+	subcc	%g0,%o4,%g0		C restore cy
+
+L(fin1):
+	addcc	n,8-2,n
+	blt	L(end1)
+	subcc	%g0,%o4,%g0		C restore cy
+C Add blocks of 2 limbs until less than 2 limbs remain
+L(loope1):
+	addxcc	%g4,%g2,%o4
+	ld	[s1_ptr+8],%g4
+	addxcc	%g1,%g3,%o5
+	ld	[s1_ptr+12],%g1
+	ldd	[s2_ptr+8],%g2
+	std	%o4,[res_ptr+0]
+	addx	%g0,%g0,%o4		C save cy in register
+	addcc	n,-2,n
+	add	s1_ptr,8,s1_ptr
+	add	s2_ptr,8,s2_ptr
+	add	res_ptr,8,res_ptr
+	bge	L(loope1)
+	subcc	%g0,%o4,%g0		C restore cy
+L(end1):
+	addxcc	%g4,%g2,%o4
+	addxcc	%g1,%g3,%o5
+	std	%o4,[res_ptr+0]
+	addx	%g0,%g0,%o4		C save cy in register
+
+	andcc	n,1,%g0
+	be	L(ret1)
+	subcc	%g0,%o4,%g0		C restore cy
+C Add last limb
+	ld	[s1_ptr+8],%g4
+	ld	[s2_ptr+8],%g2
+	addxcc	%g4,%g2,%o4
+	st	%o4,[res_ptr+8]
+
+L(ret1):
+	retl
+	addx	%g0,%g0,%o0	C return carry-out from most sign. limb
+
+L(1):	xor	s1_ptr,res_ptr,%g1
+	andcc	%g1,4,%g0
+	bne	L(2)
+	nop
+C **  V1b  **
+	mov	s2_ptr,%g1
+	mov	s1_ptr,s2_ptr
+	b	L(0)
+	mov	%g1,s1_ptr
+
+C **  V2  **
+C If we come here, the alignment of s1_ptr and res_ptr as well as the
+C alignment of s2_ptr and res_ptr differ.  Since there are only two ways
+C things can be aligned (that we care about) we now know that the alignment
+C of s1_ptr and s2_ptr are the same.
+
+L(2):	cmp	n,1
+	be	L(jone)
+	nop
+	andcc	s1_ptr,4,%g0		C s1_ptr unaligned? Side effect: cy=0
+	be	L(v2)			C if no, branch
+	nop
+C Add least significant limb separately to align s1_ptr and s2_ptr
+	ld	[s1_ptr],%g4
+	add	s1_ptr,4,s1_ptr
+	ld	[s2_ptr],%g2
+	add	s2_ptr,4,s2_ptr
+	add	n,-1,n
+	addcc	%g4,%g2,%o4
+	st	%o4,[res_ptr]
+	add	res_ptr,4,res_ptr
+
+L(v2):	addx	%g0,%g0,%o4		C save cy in register
+	addcc	n,-8,n
+	blt	L(fin2)
+	subcc	%g0,%o4,%g0		C restore cy
+C Add blocks of 8 limbs until less than 8 limbs remain
+L(loop2):
+	ldd	[s1_ptr+0],%g2
+	ldd	[s2_ptr+0],%o4
+	addxcc	%g2,%o4,%g2
+	st	%g2,[res_ptr+0]
+	addxcc	%g3,%o5,%g3
+	st	%g3,[res_ptr+4]
+	ldd	[s1_ptr+8],%g2
+	ldd	[s2_ptr+8],%o4
+	addxcc	%g2,%o4,%g2
+	st	%g2,[res_ptr+8]
+	addxcc	%g3,%o5,%g3
+	st	%g3,[res_ptr+12]
+	ldd	[s1_ptr+16],%g2
+	ldd	[s2_ptr+16],%o4
+	addxcc	%g2,%o4,%g2
+	st	%g2,[res_ptr+16]
+	addxcc	%g3,%o5,%g3
+	st	%g3,[res_ptr+20]
+	ldd	[s1_ptr+24],%g2
+	ldd	[s2_ptr+24],%o4
+	addxcc	%g2,%o4,%g2
+	st	%g2,[res_ptr+24]
+	addxcc	%g3,%o5,%g3
+	st	%g3,[res_ptr+28]
+	addx	%g0,%g0,%o4		C save cy in register
+	addcc	n,-8,n
+	add	s1_ptr,32,s1_ptr
+	add	s2_ptr,32,s2_ptr
+	add	res_ptr,32,res_ptr
+	bge	L(loop2)
+	subcc	%g0,%o4,%g0		C restore cy
+
+L(fin2):
+	addcc	n,8-2,n
+	blt	L(end2)
+	subcc	%g0,%o4,%g0		C restore cy
+L(loope2):
+	ldd	[s1_ptr+0],%g2
+	ldd	[s2_ptr+0],%o4
+	addxcc	%g2,%o4,%g2
+	st	%g2,[res_ptr+0]
+	addxcc	%g3,%o5,%g3
+	st	%g3,[res_ptr+4]
+	addx	%g0,%g0,%o4		C save cy in register
+	addcc	n,-2,n
+	add	s1_ptr,8,s1_ptr
+	add	s2_ptr,8,s2_ptr
+	add	res_ptr,8,res_ptr
+	bge	L(loope2)
+	subcc	%g0,%o4,%g0		C restore cy
+L(end2):
+	andcc	n,1,%g0
+	be	L(ret2)
+	subcc	%g0,%o4,%g0		C restore cy
+C Add last limb
+L(jone):
+	ld	[s1_ptr],%g4
+	ld	[s2_ptr],%g2
+	addxcc	%g4,%g2,%o4
+	st	%o4,[res_ptr]
+
+L(ret2):
+	retl
+	addx	%g0,%g0,%o0	C return carry-out from most sign. limb
+EPILOGUE(mpn_add_n)
diff --git a/third_party/gmp/mpn/sparc32/addmul_1.asm b/third_party/gmp/mpn/sparc32/addmul_1.asm
new file mode 100644
index 0000000..92d5d78
--- /dev/null
+++ b/third_party/gmp/mpn/sparc32/addmul_1.asm
@@ -0,0 +1,155 @@
+dnl  SPARC mpn_addmul_1 -- Multiply a limb vector with a limb and add the
+dnl  result to a second limb vector.
+
+dnl  Copyright 1992-1994, 2000 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C res_ptr	o0
+C s1_ptr	o1
+C size		o2
+C s2_limb	o3
+
+ASM_START()
+PROLOGUE(mpn_addmul_1)
+	C Make S1_PTR and RES_PTR point at the end of their blocks
+	C and put (- 4 x SIZE) in index/loop counter.
+	sll	%o2,2,%o2
+	add	%o0,%o2,%o4	C RES_PTR in o4 since o0 is retval
+	add	%o1,%o2,%o1
+	sub	%g0,%o2,%o2
+
+	cmp	%o3,0xfff
+	bgu	L(large)
+	nop
+
+	ld	[%o1+%o2],%o5
+	mov	0,%o0
+	b	L(0)
+	 add	%o4,-4,%o4
+L(loop0):
+	addcc	%o5,%g1,%g1
+	ld	[%o1+%o2],%o5
+	addx	%o0,%g0,%o0
+	st	%g1,[%o4+%o2]
+L(0):	wr	%g0,%o3,%y
+	sra	%o5,31,%g2
+	and	%o3,%g2,%g2
+	andcc	%g1,0,%g1
+	mulscc	%g1,%o5,%g1
+	mulscc	%g1,%o5,%g1
+	mulscc	%g1,%o5,%g1
+	mulscc	%g1,%o5,%g1
+	mulscc	%g1,%o5,%g1
+	mulscc	%g1,%o5,%g1
+	mulscc	%g1,%o5,%g1
+	mulscc	%g1,%o5,%g1
+	mulscc	%g1,%o5,%g1
+	mulscc	%g1,%o5,%g1
+	mulscc	%g1,%o5,%g1
+	mulscc	%g1,%o5,%g1
+	mulscc	%g1,0,%g1
+	sra	%g1,20,%g4
+	sll	%g1,12,%g1
+	rd	%y,%g3
+	srl	%g3,20,%g3
+	or	%g1,%g3,%g1
+
+	addcc	%g1,%o0,%g1
+	addx	%g2,%g4,%o0	C add sign-compensation and cy to hi limb
+	addcc	%o2,4,%o2	C loop counter
+	bne	L(loop0)
+	 ld	[%o4+%o2],%o5
+
+	addcc	%o5,%g1,%g1
+	addx	%o0,%g0,%o0
+	retl
+	st	%g1,[%o4+%o2]
+
+L(large):
+	ld	[%o1+%o2],%o5
+	mov	0,%o0
+	sra	%o3,31,%g4	C g4 = mask of ones iff S2_LIMB < 0
+	b	L(1)
+	 add	%o4,-4,%o4
+L(loop):
+	addcc	%o5,%g3,%g3
+	ld	[%o1+%o2],%o5
+	addx	%o0,%g0,%o0
+	st	%g3,[%o4+%o2]
+L(1):	wr	%g0,%o5,%y
+	and	%o5,%g4,%g2
+	andcc	%g0,%g0,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%g0,%g1
+	rd	%y,%g3
+	addcc	%g3,%o0,%g3
+	addx	%g2,%g1,%o0
+	addcc	%o2,4,%o2
+	bne	L(loop)
+	 ld	[%o4+%o2],%o5
+
+	addcc	%o5,%g3,%g3
+	addx	%o0,%g0,%o0
+	retl
+	st	%g3,[%o4+%o2]
+EPILOGUE(mpn_addmul_1)
diff --git a/third_party/gmp/mpn/sparc32/gmp-mparam.h b/third_party/gmp/mpn/sparc32/gmp-mparam.h
new file mode 100644
index 0000000..a3bc612
--- /dev/null
+++ b/third_party/gmp/mpn/sparc32/gmp-mparam.h
@@ -0,0 +1,67 @@
+/* SPARC v7 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 1999-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+/* Generated by tuneup.c, 2002-03-13, gcc 2.95, Weitek 8701 */
+
+#define MUL_TOOM22_THRESHOLD              8
+#define MUL_TOOM33_THRESHOLD            466
+
+#define SQR_BASECASE_THRESHOLD            4
+#define SQR_TOOM2_THRESHOLD              16
+#define SQR_TOOM3_THRESHOLD             258
+
+#define DIV_SB_PREINV_THRESHOLD           4
+#define DIV_DC_THRESHOLD                 28
+#define POWM_THRESHOLD                   28
+
+#define GCD_ACCEL_THRESHOLD               3
+#define JACOBI_BASE_METHOD                2
+
+#define DIVREM_1_NORM_THRESHOLD           3
+#define DIVREM_1_UNNORM_THRESHOLD         4
+#define MOD_1_NORM_THRESHOLD              3
+#define MOD_1_UNNORM_THRESHOLD            4
+#define USE_PREINV_DIVREM_1               1
+#define USE_PREINV_MOD_1                  1
+#define DIVREM_2_THRESHOLD                0  /* always */
+#define DIVEXACT_1_THRESHOLD            120
+#define MODEXACT_1_ODD_THRESHOLD      MP_SIZE_T_MAX  /* never */
+
+#define GET_STR_DC_THRESHOLD             21
+#define GET_STR_PRECOMPUTE_THRESHOLD     25
+#define SET_STR_THRESHOLD              1012
+
+#define MUL_FFT_TABLE  { 272, 672, 1152, 3584, 10240, 24576, 0 }
+#define MUL_FFT_MODF_THRESHOLD          264
+#define MUL_FFT_THRESHOLD              2304
+
+#define SQR_FFT_TABLE  { 304, 736, 1152, 3584, 10240, 24576, 0 }
+#define SQR_FFT_MODF_THRESHOLD          248
+#define SQR_FFT_THRESHOLD              2304
diff --git a/third_party/gmp/mpn/sparc32/lshift.asm b/third_party/gmp/mpn/sparc32/lshift.asm
new file mode 100644
index 0000000..8321343
--- /dev/null
+++ b/third_party/gmp/mpn/sparc32/lshift.asm
@@ -0,0 +1,105 @@
+dnl  SPARC mpn_lshift -- Shift a number left.
+
+dnl  Copyright 1995, 1996, 2000 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C res_ptr	%o0
+C src_ptr	%o1
+C size		%o2
+C cnt		%o3
+
+ASM_START()
+PROLOGUE(mpn_lshift)
+	sll	%o2,2,%g1
+	add	%o1,%g1,%o1	C make %o1 point at end of src
+	ld	[%o1-4],%g2	C load first limb
+	sub	%g0,%o3,%o5	C negate shift count
+	add	%o0,%g1,%o0	C make %o0 point at end of res
+	add	%o2,-1,%o2
+	andcc	%o2,4-1,%g4	C number of limbs in first loop
+	srl	%g2,%o5,%g1	C compute function result
+	be	L(0)		C if multiple of 4 limbs, skip first loop
+	st	%g1,[%sp+80]
+
+	sub	%o2,%g4,%o2	C adjust count for main loop
+
+L(loop0):
+	ld	[%o1-8],%g3
+	add	%o0,-4,%o0
+	add	%o1,-4,%o1
+	addcc	%g4,-1,%g4
+	sll	%g2,%o3,%o4
+	srl	%g3,%o5,%g1
+	mov	%g3,%g2
+	or	%o4,%g1,%o4
+	bne	L(loop0)
+	 st	%o4,[%o0+0]
+
+L(0):	tst	%o2
+	be	L(end)
+	 nop
+
+L(loop):
+	ld	[%o1-8],%g3
+	add	%o0,-16,%o0
+	addcc	%o2,-4,%o2
+	sll	%g2,%o3,%o4
+	srl	%g3,%o5,%g1
+
+	ld	[%o1-12],%g2
+	sll	%g3,%o3,%g4
+	or	%o4,%g1,%o4
+	st	%o4,[%o0+12]
+	srl	%g2,%o5,%g1
+
+	ld	[%o1-16],%g3
+	sll	%g2,%o3,%o4
+	or	%g4,%g1,%g4
+	st	%g4,[%o0+8]
+	srl	%g3,%o5,%g1
+
+	ld	[%o1-20],%g2
+	sll	%g3,%o3,%g4
+	or	%o4,%g1,%o4
+	st	%o4,[%o0+4]
+	srl	%g2,%o5,%g1
+
+	add	%o1,-16,%o1
+	or	%g4,%g1,%g4
+	bne	L(loop)
+	 st	%g4,[%o0+0]
+
+L(end):	sll	%g2,%o3,%g2
+	st	%g2,[%o0-4]
+	retl
+	ld	[%sp+80],%o0
+EPILOGUE(mpn_lshift)
diff --git a/third_party/gmp/mpn/sparc32/mul_1.asm b/third_party/gmp/mpn/sparc32/mul_1.asm
new file mode 100644
index 0000000..42b4168
--- /dev/null
+++ b/third_party/gmp/mpn/sparc32/mul_1.asm
@@ -0,0 +1,146 @@
+dnl  SPARC mpn_mul_1 -- Multiply a limb vector with a limb and store
+dnl  the result in a second limb vector.
+
+dnl  Copyright 1992-1994, 2000 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C res_ptr	o0
+C s1_ptr	o1
+C size		o2
+C s2_limb	o3
+
+ASM_START()
+PROLOGUE(mpn_mul_1)
+	C Make S1_PTR and RES_PTR point at the end of their blocks
+	C and put (- 4 x SIZE) in index/loop counter.
+	sll	%o2,2,%o2
+	add	%o0,%o2,%o4	C RES_PTR in o4 since o0 is retval
+	add	%o1,%o2,%o1
+	sub	%g0,%o2,%o2
+
+	cmp	%o3,0xfff
+	bgu	L(large)
+	nop
+
+	ld	[%o1+%o2],%o5
+	mov	0,%o0
+	b	L(0)
+	 add	%o4,-4,%o4
+L(loop0):
+	st	%g1,[%o4+%o2]
+L(0):	wr	%g0,%o3,%y
+	sra	%o5,31,%g2
+	and	%o3,%g2,%g2
+	andcc	%g1,0,%g1
+	mulscc	%g1,%o5,%g1
+	mulscc	%g1,%o5,%g1
+	mulscc	%g1,%o5,%g1
+	mulscc	%g1,%o5,%g1
+	mulscc	%g1,%o5,%g1
+	mulscc	%g1,%o5,%g1
+	mulscc	%g1,%o5,%g1
+	mulscc	%g1,%o5,%g1
+	mulscc	%g1,%o5,%g1
+	mulscc	%g1,%o5,%g1
+	mulscc	%g1,%o5,%g1
+	mulscc	%g1,%o5,%g1
+	mulscc	%g1,0,%g1
+	sra	%g1,20,%g4
+	sll	%g1,12,%g1
+	rd	%y,%g3
+	srl	%g3,20,%g3
+	or	%g1,%g3,%g1
+
+	addcc	%g1,%o0,%g1
+	addx	%g2,%g4,%o0	C add sign-compensation and cy to hi limb
+	addcc	%o2,4,%o2	C loop counter
+	bne,a	L(loop0)
+	 ld	[%o1+%o2],%o5
+
+	retl
+	st	%g1,[%o4+%o2]
+
+
+L(large):
+	ld	[%o1+%o2],%o5
+	mov	0,%o0
+	sra	%o3,31,%g4	C g4 = mask of ones iff S2_LIMB < 0
+	b	L(1)
+	 add	%o4,-4,%o4
+L(loop):
+	st	%g3,[%o4+%o2]
+L(1):	wr	%g0,%o5,%y
+	and	%o5,%g4,%g2	C g2 = S1_LIMB iff S2_LIMB < 0, else 0
+	andcc	%g0,%g0,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%g0,%g1
+	rd	%y,%g3
+	addcc	%g3,%o0,%g3
+	addx	%g2,%g1,%o0	C add sign-compensation and cy to hi limb
+	addcc	%o2,4,%o2	C loop counter
+	bne,a	L(loop)
+	 ld	[%o1+%o2],%o5
+
+	retl
+	st	%g3,[%o4+%o2]
+EPILOGUE(mpn_mul_1)
diff --git a/third_party/gmp/mpn/sparc32/rshift.asm b/third_party/gmp/mpn/sparc32/rshift.asm
new file mode 100644
index 0000000..e155476
--- /dev/null
+++ b/third_party/gmp/mpn/sparc32/rshift.asm
@@ -0,0 +1,102 @@
+dnl  SPARC mpn_rshift -- Shift a number right.
+
+dnl  Copyright 1995, 1996, 2000 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C res_ptr	%o0
+C src_ptr	%o1
+C size		%o2
+C cnt		%o3
+
+ASM_START()
+PROLOGUE(mpn_rshift)
+	ld	[%o1],%g2	C load first limb
+	sub	%g0,%o3,%o5	C negate shift count
+	add	%o2,-1,%o2
+	andcc	%o2,4-1,%g4	C number of limbs in first loop
+	sll	%g2,%o5,%g1	C compute function result
+	be	L(0)		C if multiple of 4 limbs, skip first loop
+	st	%g1,[%sp+80]
+
+	sub	%o2,%g4,%o2	C adjust count for main loop
+
+L(loop0):
+	ld	[%o1+4],%g3
+	add	%o0,4,%o0
+	add	%o1,4,%o1
+	addcc	%g4,-1,%g4
+	srl	%g2,%o3,%o4
+	sll	%g3,%o5,%g1
+	mov	%g3,%g2
+	or	%o4,%g1,%o4
+	bne	L(loop0)
+	 st	%o4,[%o0-4]
+
+L(0):	tst	%o2
+	be	L(end)
+	 nop
+
+L(loop):
+	ld	[%o1+4],%g3
+	add	%o0,16,%o0
+	addcc	%o2,-4,%o2
+	srl	%g2,%o3,%o4
+	sll	%g3,%o5,%g1
+
+	ld	[%o1+8],%g2
+	srl	%g3,%o3,%g4
+	or	%o4,%g1,%o4
+	st	%o4,[%o0-16]
+	sll	%g2,%o5,%g1
+
+	ld	[%o1+12],%g3
+	srl	%g2,%o3,%o4
+	or	%g4,%g1,%g4
+	st	%g4,[%o0-12]
+	sll	%g3,%o5,%g1
+
+	ld	[%o1+16],%g2
+	srl	%g3,%o3,%g4
+	or	%o4,%g1,%o4
+	st	%o4,[%o0-8]
+	sll	%g2,%o5,%g1
+
+	add	%o1,16,%o1
+	or	%g4,%g1,%g4
+	bne	L(loop)
+	 st	%g4,[%o0-4]
+
+L(end):	srl	%g2,%o3,%g2
+	st	%g2,[%o0-0]
+	retl
+	ld	[%sp+80],%o0
+EPILOGUE(mpn_rshift)
diff --git a/third_party/gmp/mpn/sparc32/sparc-defs.m4 b/third_party/gmp/mpn/sparc32/sparc-defs.m4
new file mode 100644
index 0000000..33a0c53
--- /dev/null
+++ b/third_party/gmp/mpn/sparc32/sparc-defs.m4
@@ -0,0 +1,93 @@
+divert(-1)
+
+dnl  m4 macros for SPARC assembler (32 and 64 bit).
+
+
+dnl  Copyright 2002, 2011, 2013, 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+changecom(;)	dnl cannot use default # since that's used in REGISTER decls
+
+
+dnl  Usage: REGISTER(reg,attr)
+dnl
+dnl  Give a ".register reg,attr" directive, if the assembler supports it.
+dnl  HAVE_REGISTER comes from the GMP_ASM_SPARC_REGISTER configure test.
+
+define(REGISTER,
+m4_assert_numargs(2)
+m4_assert_defined(`HAVE_REGISTER')
+`ifelse(HAVE_REGISTER,yes,
+`.register `$1',`$2'')')
+
+
+C Testing mechanism for running newer code on older processors
+ifdef(`FAKE_T3',`
+  include_mpn(`sparc64/ultrasparct3/missing.m4')
+',`
+  define(`addxccc',	``addxccc'	$1, $2, $3')
+  define(`addxc',	``addxc'	$1, $2, $3')
+  define(`umulxhi',	``umulxhi'	$1, $2, $3')
+  define(`lzcnt',	``lzd'	$1, $2')
+')
+
+dnl  Usage: LEA64(symbol,reg,pic_reg)
+dnl
+dnl  Use whatever 64-bit code sequence is appropriate to load "symbol" into
+dnl  register "reg", potentially using register "pic_reg" to perform the
+dnl  calculations.
+dnl
+dnl  Caveat: We used to use the setx pseudo insn here, but some GNU/Linux
+dnl  releases causes invalid code or relocs for that.
+dnl
+dnl  Optimisation 1: Use thunk call instead of RDPC which causes pipeline
+dnl  replay for some sparcs.
+dnl
+dnl  Optimisation 2: Do the two symbol building sequences in parallel instead
+dnl  of one after the other.  That might need one more scratch register.
+
+define(LEA64,
+m4_assert_numargs(3)
+m4_assert_defined(`HAVE_GOTDATA')
+`ifdef(`PIC',`
+	rd	%pc, %`$2'
+	sethi	%hi(_GLOBAL_OFFSET_TABLE_+4), %`$3'
+	add	%`$3', %lo(_GLOBAL_OFFSET_TABLE_+8), %`$3'
+	add	%`$2', %`$3', %`$3'
+	sethi	%gdop_hix22(`$1'), %`$2'
+	xor	%`$2', %gdop_lox10(`$1'), %`$2'
+	ldx	[%`$3' + %`$2'], %`$2', %gdop(`$1')
+',`
+	sethi	%h44(`$1'), %`$2'
+	or	%`$2', %m44(`$1'), %`$2'
+	sllx	%`$2', 12, %`$2'
+	or	%`$2', %l44(`$1'), %$2
+')')
+
+divert
diff --git a/third_party/gmp/mpn/sparc32/sub_n.asm b/third_party/gmp/mpn/sparc32/sub_n.asm
new file mode 100644
index 0000000..24a576d
--- /dev/null
+++ b/third_party/gmp/mpn/sparc32/sub_n.asm
@@ -0,0 +1,335 @@
+dnl  SPARC mpn_sub_n -- Subtract two limb vectors of the same length > 0 and
+dnl  store difference in a third limb vector.
+
+dnl  Copyright 1995, 1996, 2000 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+define(res_ptr,%o0)
+define(s1_ptr,%o1)
+define(s2_ptr,%o2)
+define(n,%o3)
+
+ASM_START()
+PROLOGUE(mpn_sub_n)
+	xor	s2_ptr,res_ptr,%g1
+	andcc	%g1,4,%g0
+	bne	L(1)			C branch if alignment differs
+	nop
+C **  V1a  **
+	andcc	res_ptr,4,%g0		C res_ptr unaligned? Side effect: cy=0
+	be	L(v1)			C if no, branch
+	nop
+C Add least significant limb separately to align res_ptr and s2_ptr
+	ld	[s1_ptr],%g4
+	add	s1_ptr,4,s1_ptr
+	ld	[s2_ptr],%g2
+	add	s2_ptr,4,s2_ptr
+	add	n,-1,n
+	subcc	%g4,%g2,%o4
+	st	%o4,[res_ptr]
+	add	res_ptr,4,res_ptr
+L(v1):	addx	%g0,%g0,%o4		C save cy in register
+	cmp	n,2			C if n < 2 ...
+	bl	L(end2)			C ... branch to tail code
+	subcc	%g0,%o4,%g0		C restore cy
+
+	ld	[s1_ptr+0],%g4
+	addcc	n,-10,n
+	ld	[s1_ptr+4],%g1
+	ldd	[s2_ptr+0],%g2
+	blt	L(fin1)
+	subcc	%g0,%o4,%g0		C restore cy
+C Add blocks of 8 limbs until less than 8 limbs remain
+L(loop1):
+	subxcc	%g4,%g2,%o4
+	ld	[s1_ptr+8],%g4
+	subxcc	%g1,%g3,%o5
+	ld	[s1_ptr+12],%g1
+	ldd	[s2_ptr+8],%g2
+	std	%o4,[res_ptr+0]
+	subxcc	%g4,%g2,%o4
+	ld	[s1_ptr+16],%g4
+	subxcc	%g1,%g3,%o5
+	ld	[s1_ptr+20],%g1
+	ldd	[s2_ptr+16],%g2
+	std	%o4,[res_ptr+8]
+	subxcc	%g4,%g2,%o4
+	ld	[s1_ptr+24],%g4
+	subxcc	%g1,%g3,%o5
+	ld	[s1_ptr+28],%g1
+	ldd	[s2_ptr+24],%g2
+	std	%o4,[res_ptr+16]
+	subxcc	%g4,%g2,%o4
+	ld	[s1_ptr+32],%g4
+	subxcc	%g1,%g3,%o5
+	ld	[s1_ptr+36],%g1
+	ldd	[s2_ptr+32],%g2
+	std	%o4,[res_ptr+24]
+	addx	%g0,%g0,%o4		C save cy in register
+	addcc	n,-8,n
+	add	s1_ptr,32,s1_ptr
+	add	s2_ptr,32,s2_ptr
+	add	res_ptr,32,res_ptr
+	bge	L(loop1)
+	subcc	%g0,%o4,%g0		C restore cy
+
+L(fin1):
+	addcc	n,8-2,n
+	blt	L(end1)
+	subcc	%g0,%o4,%g0		C restore cy
+C Add blocks of 2 limbs until less than 2 limbs remain
+L(loope1):
+	subxcc	%g4,%g2,%o4
+	ld	[s1_ptr+8],%g4
+	subxcc	%g1,%g3,%o5
+	ld	[s1_ptr+12],%g1
+	ldd	[s2_ptr+8],%g2
+	std	%o4,[res_ptr+0]
+	addx	%g0,%g0,%o4		C save cy in register
+	addcc	n,-2,n
+	add	s1_ptr,8,s1_ptr
+	add	s2_ptr,8,s2_ptr
+	add	res_ptr,8,res_ptr
+	bge	L(loope1)
+	subcc	%g0,%o4,%g0		C restore cy
+L(end1):
+	subxcc	%g4,%g2,%o4
+	subxcc	%g1,%g3,%o5
+	std	%o4,[res_ptr+0]
+	addx	%g0,%g0,%o4		C save cy in register
+
+	andcc	n,1,%g0
+	be	L(ret1)
+	subcc	%g0,%o4,%g0		C restore cy
+C Add last limb
+	ld	[s1_ptr+8],%g4
+	ld	[s2_ptr+8],%g2
+	subxcc	%g4,%g2,%o4
+	st	%o4,[res_ptr+8]
+
+L(ret1):
+	retl
+	addx	%g0,%g0,%o0	C return carry-out from most sign. limb
+
+L(1):	xor	s1_ptr,res_ptr,%g1
+	andcc	%g1,4,%g0
+	bne	L(2)
+	nop
+C **  V1b  **
+	andcc	res_ptr,4,%g0		C res_ptr unaligned? Side effect: cy=0
+	be	L(v1b)			C if no, branch
+	nop
+C Add least significant limb separately to align res_ptr and s1_ptr
+	ld	[s2_ptr],%g4
+	add	s2_ptr,4,s2_ptr
+	ld	[s1_ptr],%g2
+	add	s1_ptr,4,s1_ptr
+	add	n,-1,n
+	subcc	%g2,%g4,%o4
+	st	%o4,[res_ptr]
+	add	res_ptr,4,res_ptr
+L(v1b):	addx	%g0,%g0,%o4		C save cy in register
+	cmp	n,2			C if n < 2 ...
+	bl	L(end2)			C ... branch to tail code
+	subcc	%g0,%o4,%g0		C restore cy
+
+	ld	[s2_ptr+0],%g4
+	addcc	n,-10,n
+	ld	[s2_ptr+4],%g1
+	ldd	[s1_ptr+0],%g2
+	blt	L(fin1b)
+	subcc	%g0,%o4,%g0		C restore cy
+C Add blocks of 8 limbs until less than 8 limbs remain
+L(loop1b):
+	subxcc	%g2,%g4,%o4
+	ld	[s2_ptr+8],%g4
+	subxcc	%g3,%g1,%o5
+	ld	[s2_ptr+12],%g1
+	ldd	[s1_ptr+8],%g2
+	std	%o4,[res_ptr+0]
+	subxcc	%g2,%g4,%o4
+	ld	[s2_ptr+16],%g4
+	subxcc	%g3,%g1,%o5
+	ld	[s2_ptr+20],%g1
+	ldd	[s1_ptr+16],%g2
+	std	%o4,[res_ptr+8]
+	subxcc	%g2,%g4,%o4
+	ld	[s2_ptr+24],%g4
+	subxcc	%g3,%g1,%o5
+	ld	[s2_ptr+28],%g1
+	ldd	[s1_ptr+24],%g2
+	std	%o4,[res_ptr+16]
+	subxcc	%g2,%g4,%o4
+	ld	[s2_ptr+32],%g4
+	subxcc	%g3,%g1,%o5
+	ld	[s2_ptr+36],%g1
+	ldd	[s1_ptr+32],%g2
+	std	%o4,[res_ptr+24]
+	addx	%g0,%g0,%o4		C save cy in register
+	addcc	n,-8,n
+	add	s1_ptr,32,s1_ptr
+	add	s2_ptr,32,s2_ptr
+	add	res_ptr,32,res_ptr
+	bge	L(loop1b)
+	subcc	%g0,%o4,%g0		C restore cy
+
+L(fin1b):
+	addcc	n,8-2,n
+	blt	L(end1b)
+	subcc	%g0,%o4,%g0		C restore cy
+C Add blocks of 2 limbs until less than 2 limbs remain
+L(loope1b):
+	subxcc	%g2,%g4,%o4
+	ld	[s2_ptr+8],%g4
+	subxcc	%g3,%g1,%o5
+	ld	[s2_ptr+12],%g1
+	ldd	[s1_ptr+8],%g2
+	std	%o4,[res_ptr+0]
+	addx	%g0,%g0,%o4		C save cy in register
+	addcc	n,-2,n
+	add	s1_ptr,8,s1_ptr
+	add	s2_ptr,8,s2_ptr
+	add	res_ptr,8,res_ptr
+	bge	L(loope1b)
+	subcc	%g0,%o4,%g0		C restore cy
+L(end1b):
+	subxcc	%g2,%g4,%o4
+	subxcc	%g3,%g1,%o5
+	std	%o4,[res_ptr+0]
+	addx	%g0,%g0,%o4		C save cy in register
+
+	andcc	n,1,%g0
+	be	L(ret1b)
+	subcc	%g0,%o4,%g0		C restore cy
+C Add last limb
+	ld	[s2_ptr+8],%g4
+	ld	[s1_ptr+8],%g2
+	subxcc	%g2,%g4,%o4
+	st	%o4,[res_ptr+8]
+
+L(ret1b):
+	retl
+	addx	%g0,%g0,%o0		C return carry-out from most sign. limb
+
+C **  V2  **
+C If we come here, the alignment of s1_ptr and res_ptr as well as the
+C alignment of s2_ptr and res_ptr differ.  Since there are only two ways
+C things can be aligned (that we care about) we now know that the alignment
+C of s1_ptr and s2_ptr are the same.
+
+L(2):	cmp	n,1
+	be	L(jone)
+	nop
+	andcc	s1_ptr,4,%g0		C s1_ptr unaligned? Side effect: cy=0
+	be	L(v2)			C if no, branch
+	nop
+C Add least significant limb separately to align s1_ptr and s2_ptr
+	ld	[s1_ptr],%g4
+	add	s1_ptr,4,s1_ptr
+	ld	[s2_ptr],%g2
+	add	s2_ptr,4,s2_ptr
+	add	n,-1,n
+	subcc	%g4,%g2,%o4
+	st	%o4,[res_ptr]
+	add	res_ptr,4,res_ptr
+
+L(v2):	addx	%g0,%g0,%o4		C save cy in register
+	addcc	n,-8,n
+	blt	L(fin2)
+	subcc	%g0,%o4,%g0		C restore cy
+C Add blocks of 8 limbs until less than 8 limbs remain
+L(loop2):
+	ldd	[s1_ptr+0],%g2
+	ldd	[s2_ptr+0],%o4
+	subxcc	%g2,%o4,%g2
+	st	%g2,[res_ptr+0]
+	subxcc	%g3,%o5,%g3
+	st	%g3,[res_ptr+4]
+	ldd	[s1_ptr+8],%g2
+	ldd	[s2_ptr+8],%o4
+	subxcc	%g2,%o4,%g2
+	st	%g2,[res_ptr+8]
+	subxcc	%g3,%o5,%g3
+	st	%g3,[res_ptr+12]
+	ldd	[s1_ptr+16],%g2
+	ldd	[s2_ptr+16],%o4
+	subxcc	%g2,%o4,%g2
+	st	%g2,[res_ptr+16]
+	subxcc	%g3,%o5,%g3
+	st	%g3,[res_ptr+20]
+	ldd	[s1_ptr+24],%g2
+	ldd	[s2_ptr+24],%o4
+	subxcc	%g2,%o4,%g2
+	st	%g2,[res_ptr+24]
+	subxcc	%g3,%o5,%g3
+	st	%g3,[res_ptr+28]
+	addx	%g0,%g0,%o4		C save cy in register
+	addcc	n,-8,n
+	add	s1_ptr,32,s1_ptr
+	add	s2_ptr,32,s2_ptr
+	add	res_ptr,32,res_ptr
+	bge	L(loop2)
+	subcc	%g0,%o4,%g0		C restore cy
+
+L(fin2):
+	addcc	n,8-2,n
+	blt	L(end2)
+	subcc	%g0,%o4,%g0		C restore cy
+L(loope2):
+	ldd	[s1_ptr+0],%g2
+	ldd	[s2_ptr+0],%o4
+	subxcc	%g2,%o4,%g2
+	st	%g2,[res_ptr+0]
+	subxcc	%g3,%o5,%g3
+	st	%g3,[res_ptr+4]
+	addx	%g0,%g0,%o4		C save cy in register
+	addcc	n,-2,n
+	add	s1_ptr,8,s1_ptr
+	add	s2_ptr,8,s2_ptr
+	add	res_ptr,8,res_ptr
+	bge	L(loope2)
+	subcc	%g0,%o4,%g0		C restore cy
+L(end2):
+	andcc	n,1,%g0
+	be	L(ret2)
+	subcc	%g0,%o4,%g0		C restore cy
+C Add last limb
+L(jone):
+	ld	[s1_ptr],%g4
+	ld	[s2_ptr],%g2
+	subxcc	%g4,%g2,%o4
+	st	%o4,[res_ptr]
+
+L(ret2):
+	retl
+	addx	%g0,%g0,%o0		C return carry-out from most sign. limb
+EPILOGUE(mpn_sub_n)
diff --git a/third_party/gmp/mpn/sparc32/submul_1.asm b/third_party/gmp/mpn/sparc32/submul_1.asm
new file mode 100644
index 0000000..73f9377
--- /dev/null
+++ b/third_party/gmp/mpn/sparc32/submul_1.asm
@@ -0,0 +1,155 @@
+dnl  SPARC mpn_submul_1 -- Multiply a limb vector with a limb and subtract
+dnl  the result from a second limb vector.
+
+dnl  Copyright 1992-1994, 2000 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C res_ptr	o0
+C s1_ptr	o1
+C size		o2
+C s2_limb	o3
+
+ASM_START()
+PROLOGUE(mpn_submul_1)
+	C Make S1_PTR and RES_PTR point at the end of their blocks
+	C and put (- 4 x SIZE) in index/loop counter.
+	sll	%o2,2,%o2
+	add	%o0,%o2,%o4	C RES_PTR in o4 since o0 is retval
+	add	%o1,%o2,%o1
+	sub	%g0,%o2,%o2
+
+	cmp	%o3,0xfff
+	bgu	L(large)
+	nop
+
+	ld	[%o1+%o2],%o5
+	mov	0,%o0
+	b	L(0)
+	 add	%o4,-4,%o4
+L(loop0):
+	subcc	%o5,%g1,%g1
+	ld	[%o1+%o2],%o5
+	addx	%o0,%g0,%o0
+	st	%g1,[%o4+%o2]
+L(0):	wr	%g0,%o3,%y
+	sra	%o5,31,%g2
+	and	%o3,%g2,%g2
+	andcc	%g1,0,%g1
+	mulscc	%g1,%o5,%g1
+	mulscc	%g1,%o5,%g1
+	mulscc	%g1,%o5,%g1
+	mulscc	%g1,%o5,%g1
+	mulscc	%g1,%o5,%g1
+	mulscc	%g1,%o5,%g1
+	mulscc	%g1,%o5,%g1
+	mulscc	%g1,%o5,%g1
+	mulscc	%g1,%o5,%g1
+	mulscc	%g1,%o5,%g1
+	mulscc	%g1,%o5,%g1
+	mulscc	%g1,%o5,%g1
+	mulscc	%g1,0,%g1
+	sra	%g1,20,%g4
+	sll	%g1,12,%g1
+	rd	%y,%g3
+	srl	%g3,20,%g3
+	or	%g1,%g3,%g1
+
+	addcc	%g1,%o0,%g1
+	addx	%g2,%g4,%o0	C add sign-compensation and cy to hi limb
+	addcc	%o2,4,%o2	C loop counter
+	bne	L(loop0)
+	 ld	[%o4+%o2],%o5
+
+	subcc	%o5,%g1,%g1
+	addx	%o0,%g0,%o0
+	retl
+	st	%g1,[%o4+%o2]
+
+L(large):
+	ld	[%o1+%o2],%o5
+	mov	0,%o0
+	sra	%o3,31,%g4	C g4 = mask of ones iff S2_LIMB < 0
+	b	L(1)
+	 add	%o4,-4,%o4
+L(loop):
+	subcc	%o5,%g3,%g3
+	ld	[%o1+%o2],%o5
+	addx	%o0,%g0,%o0
+	st	%g3,[%o4+%o2]
+L(1):	wr	%g0,%o5,%y
+	and	%o5,%g4,%g2
+	andcc	%g0,%g0,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%g0,%g1
+	rd	%y,%g3
+	addcc	%g3,%o0,%g3
+	addx	%g2,%g1,%o0
+	addcc	%o2,4,%o2
+	bne	L(loop)
+	 ld	[%o4+%o2],%o5
+
+	subcc	%o5,%g3,%g3
+	addx	%o0,%g0,%o0
+	retl
+	st	%g3,[%o4+%o2]
+EPILOGUE(mpn_submul_1)
diff --git a/third_party/gmp/mpn/sparc32/udiv.asm b/third_party/gmp/mpn/sparc32/udiv.asm
new file mode 100644
index 0000000..23ab3de
--- /dev/null
+++ b/third_party/gmp/mpn/sparc32/udiv.asm
@@ -0,0 +1,167 @@
+dnl  SPARC v7 __udiv_qrnnd division support, used from longlong.h.
+dnl  This is for v7 CPUs with a floating-point unit.
+
+dnl  Copyright 1993, 1994, 1996, 2000 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C rem_ptr	i0
+C n1		i1
+C n0		i2
+C d		i3
+
+ASM_START()
+
+ifdef(`PIC',
+`	TEXT
+L(getpc):
+	retl
+	nop')
+
+	TEXT
+	ALIGN(8)
+L(C0):	.double	0r4294967296
+L(C1):	.double	0r2147483648
+
+PROLOGUE(mpn_udiv_qrnnd)
+	save	%sp,-104,%sp
+	st	%i1,[%fp-8]
+	ld	[%fp-8],%f10
+
+ifdef(`PIC',
+`L(pc):	call	L(getpc)		C put address of this insn in %o7
+	ldd	[%o7+L(C0)-L(pc)],%f8',
+`	sethi	%hi(L(C0)),%o7
+	ldd	[%o7+%lo(L(C0))],%f8')
+
+	fitod	%f10,%f4
+	cmp	%i1,0
+	bge	L(248)
+	mov	%i0,%i5
+	faddd	%f4,%f8,%f4
+L(248):
+	st	%i2,[%fp-8]
+	ld	[%fp-8],%f10
+	fmuld	%f4,%f8,%f6
+	cmp	%i2,0
+	bge	L(249)
+	fitod	%f10,%f2
+	faddd	%f2,%f8,%f2
+L(249):
+	st	%i3,[%fp-8]
+	faddd	%f6,%f2,%f2
+	ld	[%fp-8],%f10
+	cmp	%i3,0
+	bge	L(250)
+	fitod	%f10,%f4
+	faddd	%f4,%f8,%f4
+L(250):
+	fdivd	%f2,%f4,%f2
+
+ifdef(`PIC',
+`	ldd	[%o7+L(C1)-L(pc)],%f4',
+`	sethi	%hi(L(C1)),%o7
+	ldd	[%o7+%lo(L(C1))],%f4')
+
+	fcmped	%f2,%f4
+	nop
+	fbge,a	L(251)
+	fsubd	%f2,%f4,%f2
+	fdtoi	%f2,%f2
+	st	%f2,[%fp-8]
+	b	L(252)
+	ld	[%fp-8],%i4
+L(251):
+	fdtoi	%f2,%f2
+	st	%f2,[%fp-8]
+	ld	[%fp-8],%i4
+	sethi	%hi(-2147483648),%g2
+	xor	%i4,%g2,%i4
+L(252):
+	wr	%g0,%i4,%y
+	sra	%i3,31,%g2
+	and	%i4,%g2,%g2
+	andcc	%g0,0,%g1
+	mulscc	%g1,%i3,%g1
+	mulscc	%g1,%i3,%g1
+	mulscc	%g1,%i3,%g1
+	mulscc	%g1,%i3,%g1
+	mulscc	%g1,%i3,%g1
+	mulscc	%g1,%i3,%g1
+	mulscc	%g1,%i3,%g1
+	mulscc	%g1,%i3,%g1
+	mulscc	%g1,%i3,%g1
+	mulscc	%g1,%i3,%g1
+	mulscc	%g1,%i3,%g1
+	mulscc	%g1,%i3,%g1
+	mulscc	%g1,%i3,%g1
+	mulscc	%g1,%i3,%g1
+	mulscc	%g1,%i3,%g1
+	mulscc	%g1,%i3,%g1
+	mulscc	%g1,%i3,%g1
+	mulscc	%g1,%i3,%g1
+	mulscc	%g1,%i3,%g1
+	mulscc	%g1,%i3,%g1
+	mulscc	%g1,%i3,%g1
+	mulscc	%g1,%i3,%g1
+	mulscc	%g1,%i3,%g1
+	mulscc	%g1,%i3,%g1
+	mulscc	%g1,%i3,%g1
+	mulscc	%g1,%i3,%g1
+	mulscc	%g1,%i3,%g1
+	mulscc	%g1,%i3,%g1
+	mulscc	%g1,%i3,%g1
+	mulscc	%g1,%i3,%g1
+	mulscc	%g1,%i3,%g1
+	mulscc	%g1,%i3,%g1
+	mulscc	%g1,0,%g1
+	add	%g1,%g2,%i0
+	rd	%y,%g3
+	subcc	%i2,%g3,%o7
+	subxcc	%i1,%i0,%g0
+	be	L(253)
+	cmp	%o7,%i3
+
+	add	%i4,-1,%i0
+	add	%o7,%i3,%o7
+	st	%o7,[%i5]
+	ret
+	restore
+L(253):
+	blu	L(246)
+	mov	%i4,%i0
+	add	%i4,1,%i0
+	sub	%o7,%i3,%o7
+L(246):
+	st	%o7,[%i5]
+	ret
+	restore
+EPILOGUE(mpn_udiv_qrnnd)
diff --git a/third_party/gmp/mpn/sparc32/udiv_nfp.asm b/third_party/gmp/mpn/sparc32/udiv_nfp.asm
new file mode 100644
index 0000000..ebbb820
--- /dev/null
+++ b/third_party/gmp/mpn/sparc32/udiv_nfp.asm
@@ -0,0 +1,202 @@
+dnl  SPARC v7 __udiv_qrnnd division support, used from longlong.h.
+dnl  This is for v7 CPUs without a floating-point unit.
+
+dnl  Copyright 1993, 1994, 1996, 2000 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C rem_ptr	o0
+C n1		o1
+C n0		o2
+C d		o3
+
+ASM_START()
+PROLOGUE(mpn_udiv_qrnnd)
+	tst	%o3
+	bneg	L(largedivisor)
+	mov	8,%g1
+
+	b	L(p1)
+	addxcc	%o2,%o2,%o2
+
+L(plop):
+	bcc	L(n1)
+	addxcc	%o2,%o2,%o2
+L(p1):	addx	%o1,%o1,%o1
+	subcc	%o1,%o3,%o4
+	bcc	L(n2)
+	addxcc	%o2,%o2,%o2
+L(p2):	addx	%o1,%o1,%o1
+	subcc	%o1,%o3,%o4
+	bcc	L(n3)
+	addxcc	%o2,%o2,%o2
+L(p3):	addx	%o1,%o1,%o1
+	subcc	%o1,%o3,%o4
+	bcc	L(n4)
+	addxcc	%o2,%o2,%o2
+L(p4):	addx	%o1,%o1,%o1
+	addcc	%g1,-1,%g1
+	bne	L(plop)
+	subcc	%o1,%o3,%o4
+	bcc	L(n5)
+	addxcc	%o2,%o2,%o2
+L(p5):	st	%o1,[%o0]
+	retl
+	xnor	%g0,%o2,%o0
+
+L(nlop):
+	bcc	L(p1)
+	addxcc	%o2,%o2,%o2
+L(n1):	addx	%o4,%o4,%o4
+	subcc	%o4,%o3,%o1
+	bcc	L(p2)
+	addxcc	%o2,%o2,%o2
+L(n2):	addx	%o4,%o4,%o4
+	subcc	%o4,%o3,%o1
+	bcc	L(p3)
+	addxcc	%o2,%o2,%o2
+L(n3):	addx	%o4,%o4,%o4
+	subcc	%o4,%o3,%o1
+	bcc	L(p4)
+	addxcc	%o2,%o2,%o2
+L(n4):	addx	%o4,%o4,%o4
+	addcc	%g1,-1,%g1
+	bne	L(nlop)
+	subcc	%o4,%o3,%o1
+	bcc	L(p5)
+	addxcc	%o2,%o2,%o2
+L(n5):	st	%o4,[%o0]
+	retl
+	xnor	%g0,%o2,%o0
+
+L(largedivisor):
+	and	%o2,1,%o5	C %o5 = n0 & 1
+
+	srl	%o2,1,%o2
+	sll	%o1,31,%g2
+	or	%g2,%o2,%o2	C %o2 = lo(n1n0 >> 1)
+	srl	%o1,1,%o1	C %o1 = hi(n1n0 >> 1)
+
+	and	%o3,1,%g2
+	srl	%o3,1,%g3	C %g3 = floor(d / 2)
+	add	%g3,%g2,%g3	C %g3 = ceil(d / 2)
+
+	b	L(Lp1)
+	addxcc	%o2,%o2,%o2
+
+L(Lplop):
+	bcc	L(Ln1)
+	addxcc	%o2,%o2,%o2
+L(Lp1):	addx	%o1,%o1,%o1
+	subcc	%o1,%g3,%o4
+	bcc	L(Ln2)
+	addxcc	%o2,%o2,%o2
+L(Lp2):	addx	%o1,%o1,%o1
+	subcc	%o1,%g3,%o4
+	bcc	L(Ln3)
+	addxcc	%o2,%o2,%o2
+L(Lp3):	addx	%o1,%o1,%o1
+	subcc	%o1,%g3,%o4
+	bcc	L(Ln4)
+	addxcc	%o2,%o2,%o2
+L(Lp4):	addx	%o1,%o1,%o1
+	addcc	%g1,-1,%g1
+	bne	L(Lplop)
+	subcc	%o1,%g3,%o4
+	bcc	L(Ln5)
+	addxcc	%o2,%o2,%o2
+L(Lp5):	add	%o1,%o1,%o1	C << 1
+	tst	%g2
+	bne	L(oddp)
+	add	%o5,%o1,%o1
+	st	%o1,[%o0]
+	retl
+	xnor	%g0,%o2,%o0
+
+L(Lnlop):
+	bcc	L(Lp1)
+	addxcc	%o2,%o2,%o2
+L(Ln1):	addx	%o4,%o4,%o4
+	subcc	%o4,%g3,%o1
+	bcc	L(Lp2)
+	addxcc	%o2,%o2,%o2
+L(Ln2):	addx	%o4,%o4,%o4
+	subcc	%o4,%g3,%o1
+	bcc	L(Lp3)
+	addxcc	%o2,%o2,%o2
+L(Ln3):	addx	%o4,%o4,%o4
+	subcc	%o4,%g3,%o1
+	bcc	L(Lp4)
+	addxcc	%o2,%o2,%o2
+L(Ln4):	addx	%o4,%o4,%o4
+	addcc	%g1,-1,%g1
+	bne	L(Lnlop)
+	subcc	%o4,%g3,%o1
+	bcc	L(Lp5)
+	addxcc	%o2,%o2,%o2
+L(Ln5):	add	%o4,%o4,%o4	C << 1
+	tst	%g2
+	bne	L(oddn)
+	add	%o5,%o4,%o4
+	st	%o4,[%o0]
+	retl
+	xnor	%g0,%o2,%o0
+
+L(oddp):
+	xnor	%g0,%o2,%o2
+	C q' in %o2. r' in %o1
+	addcc	%o1,%o2,%o1
+	bcc	L(Lp6)
+	addx	%o2,0,%o2
+	sub	%o1,%o3,%o1
+L(Lp6):	subcc	%o1,%o3,%g0
+	bcs	L(Lp7)
+	subx	%o2,-1,%o2
+	sub	%o1,%o3,%o1
+L(Lp7):	st	%o1,[%o0]
+	retl
+	mov	%o2,%o0
+
+L(oddn):
+	xnor	%g0,%o2,%o2
+	C q' in %o2. r' in %o4
+	addcc	%o4,%o2,%o4
+	bcc	L(Ln6)
+	addx	%o2,0,%o2
+	sub	%o4,%o3,%o4
+L(Ln6):	subcc	%o4,%o3,%g0
+	bcs	L(Ln7)
+	subx	%o2,-1,%o2
+	sub	%o4,%o3,%o4
+L(Ln7):	st	%o4,[%o0]
+	retl
+	mov	%o2,%o0
+EPILOGUE(mpn_udiv_qrnnd)
diff --git a/third_party/gmp/mpn/sparc32/ultrasparct1/add_n.asm b/third_party/gmp/mpn/sparc32/ultrasparct1/add_n.asm
new file mode 100644
index 0000000..c781596
--- /dev/null
+++ b/third_party/gmp/mpn/sparc32/ultrasparct1/add_n.asm
@@ -0,0 +1,70 @@
+dnl  SPARC T1 32-bit mpn_add_n.
+
+dnl  Copyright 2010 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+define(`rp',  %o0)
+define(`ap',  %o1)
+define(`bp',  %o2)
+define(`n',   %o3)
+define(`cy',  %o4)
+
+define(`i',   %o3)
+
+MULFUNC_PROLOGUE(mpn_add_n mpn_add_nc)
+
+ASM_START()
+PROLOGUE(mpn_add_nc)
+	b	L(ent)
+	srl	cy, 0, cy	C strip any bogus high bits
+EPILOGUE()
+
+PROLOGUE(mpn_add_n)
+	mov	0, cy
+L(ent):	srl	n, 0, n		C strip any bogus high bits
+	sll	n, 2, n
+	add	ap, n, ap
+	add	bp, n, bp
+	add	rp, n, rp
+	neg	n, i
+
+L(top):	lduw	[ap+i], %g1
+	lduw	[bp+i], %g2
+	add	%g1, %g2, %g3
+	add	%g3, cy, %g3
+	stw	%g3, [rp+i]
+	add	i, 4, i
+	brnz	i, L(top)
+	srlx	%g3, 32, cy
+
+	retl
+	mov	cy, %o0		C return value
+EPILOGUE()
diff --git a/third_party/gmp/mpn/sparc32/ultrasparct1/addmul_1.asm b/third_party/gmp/mpn/sparc32/ultrasparct1/addmul_1.asm
new file mode 100644
index 0000000..89da186
--- /dev/null
+++ b/third_party/gmp/mpn/sparc32/ultrasparct1/addmul_1.asm
@@ -0,0 +1,90 @@
+dnl  SPARC T1 32-bit mpn_addmul_1.
+
+dnl  Contributed to the GNU project by David Miller.
+
+dnl  Copyright 2010, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		   cycles/limb
+C UltraSPARC T1:       24
+C UltraSPARC T2:       19
+C UltraSPARC T3:       19
+C UltraSPARC T4:       5
+
+C INPUT PARAMETERS
+define(`rp',	`%i0')
+define(`up',	`%i1')
+define(`n',	`%i2')
+define(`v0',	`%i3')
+
+ASM_START()
+PROLOGUE(mpn_addmul_1)
+	save	%sp, -96, %sp
+	srl	n, 0, %o4
+	srl	v0, 0, %g1
+	subcc	%o4, 1, %o4
+	be	L(final_one)
+	 clr	%o5
+
+L(top):	lduw	[up+0], %l0
+	lduw	[rp+0], %l2
+	lduw	[up+4], %l1
+	lduw	[rp+4], %l3
+	mulx	%l0, %g1, %g3
+	add	up, 8, up
+	mulx	%l1, %g1, %o3
+	sub	%o4, 2, %o4
+	add	rp, 8, rp
+	add	%l2, %g3, %g3
+	add	%o5, %g3, %g3
+	stw	%g3, [rp-8]
+	srlx	%g3, 32, %o5
+	add	%l3, %o3, %o3
+	add	%o5, %o3, %o3
+	stw	%o3, [rp-4]
+	brgz	%o4, L(top)
+	 srlx	%o3, 32, %o5
+
+	brlz,pt	%o4, L(done)
+	 nop
+
+L(final_one):
+	lduw	[up+0], %l0
+	lduw	[rp+0], %l2
+	mulx	%l0, %g1, %g3
+	add	%l2, %g3, %g3
+	add	%o5, %g3, %g3
+	stw	%g3, [rp+0]
+	srlx	%g3, 32, %o5
+
+L(done):
+	ret
+	 restore %o5, 0, %o0
+EPILOGUE()
diff --git a/third_party/gmp/mpn/sparc32/ultrasparct1/gmp-mparam.h b/third_party/gmp/mpn/sparc32/ultrasparct1/gmp-mparam.h
new file mode 100644
index 0000000..6f9d5a4
--- /dev/null
+++ b/third_party/gmp/mpn/sparc32/ultrasparct1/gmp-mparam.h
@@ -0,0 +1,153 @@
+/* UltraSPARC T 32-bit gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 2000-2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define DIVREM_1_NORM_THRESHOLD              0  /* always */
+#define DIVREM_1_UNNORM_THRESHOLD            3
+#define MOD_1_1P_METHOD                      2
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          9
+#define MOD_1U_TO_MOD_1_1_THRESHOLD         10
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD         0  /* never mpn_mod_1_1p */
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        21
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     22
+#define USE_PREINV_DIVREM_1                  1
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always */
+#define BMOD_1_TO_MOD_1_THRESHOLD           35
+
+#define MUL_TOOM22_THRESHOLD                14
+#define MUL_TOOM33_THRESHOLD                98
+#define MUL_TOOM44_THRESHOLD               166
+#define MUL_TOOM6H_THRESHOLD               226
+#define MUL_TOOM8H_THRESHOLD               333
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      97
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     139
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD      97
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD      98
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     120
+
+#define SQR_BASECASE_THRESHOLD               6
+#define SQR_TOOM2_THRESHOLD                 34
+#define SQR_TOOM3_THRESHOLD                110
+#define SQR_TOOM4_THRESHOLD                178
+#define SQR_TOOM6_THRESHOLD                240
+#define SQR_TOOM8_THRESHOLD                333
+
+#define MULMID_TOOM42_THRESHOLD             22
+
+#define MULMOD_BNM1_THRESHOLD                9
+#define SQRMOD_BNM1_THRESHOLD               13
+
+#define MUL_FFT_MODF_THRESHOLD             280  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    280, 5}, {     15, 6}, {      8, 5}, {     17, 6}, \
+    {      9, 5}, {     19, 6}, {     13, 7}, {      7, 6}, \
+    {     17, 7}, {      9, 6}, {     20, 7}, {     11, 6}, \
+    {     23, 7}, {     13, 8}, {      7, 7}, {     21, 8}, \
+    {     11, 7}, {     25, 9}, {      7, 8}, {     15, 7}, \
+    {     33, 8}, {     19, 7}, {     41, 8}, {     23, 7}, \
+    {     49, 8}, {     27, 9}, {     15, 8}, {     31, 7}, \
+    {     63, 8}, {     39, 9}, {     23, 8}, {     47,10}, \
+    {     15, 9}, {     31, 8}, {     67, 9}, {     39, 8}, \
+    {     79, 9}, {     47,10}, {     31, 9}, {     79,10}, \
+    {     47,11}, {     31,10}, {     63, 9}, {    127, 8}, \
+    {    255,10}, {     79, 9}, {    159, 8}, {    319,10}, \
+    {     95, 9}, {    191, 8}, {    383,11}, {     63,10}, \
+    {    127, 9}, {    255,10}, {    143, 9}, {    287,10}, \
+    {    159, 9}, {    319,10}, {    175,11}, {     95,10}, \
+    {    191, 9}, {    383,12}, {   4096,13}, {   8192,14}, \
+    {  16384,15}, {  32768,16} }
+#define MUL_FFT_TABLE3_SIZE 66
+#define MUL_FFT_THRESHOLD                 3712
+
+#define SQR_FFT_MODF_THRESHOLD             240  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    240, 5}, {     15, 6}, {      8, 5}, {     17, 6}, \
+    {     13, 7}, {      7, 6}, {     17, 7}, {      9, 6}, \
+    {     20, 7}, {     11, 6}, {     23, 7}, {     13, 8}, \
+    {      7, 7}, {     19, 8}, {     11, 7}, {     25, 9}, \
+    {      7, 8}, {     15, 7}, {     33, 8}, {     19, 7}, \
+    {     39, 8}, {     23, 7}, {     47, 8}, {     27, 9}, \
+    {     15, 8}, {     39, 9}, {     23, 8}, {     47,10}, \
+    {     15, 9}, {     31, 8}, {     63, 9}, {     39, 8}, \
+    {     79, 9}, {     47,10}, {     31, 9}, {     63, 8}, \
+    {    127, 9}, {     71, 8}, {    143, 9}, {     79,10}, \
+    {     47,11}, {     31,10}, {     63, 9}, {    127, 8}, \
+    {    255, 9}, {    143,10}, {     79, 9}, {    159, 8}, \
+    {    319, 9}, {    175,10}, {     95, 9}, {    191, 8}, \
+    {    383, 9}, {    207,11}, {     63,10}, {    127, 9}, \
+    {    255,10}, {    143, 9}, {    287,10}, {    159, 9}, \
+    {    319,10}, {    175,11}, {     95,10}, {    191, 9}, \
+    {    383,10}, {    207,12}, {   4096,13}, {   8192,14}, \
+    {  16384,15}, {  32768,16} }
+#define SQR_FFT_TABLE3_SIZE 70
+#define SQR_FFT_THRESHOLD                 2624
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  51
+#define MULLO_MUL_N_THRESHOLD             6633
+
+#define DC_DIV_QR_THRESHOLD                 51
+#define DC_DIVAPPR_Q_THRESHOLD             202
+#define DC_BDIV_QR_THRESHOLD                47
+#define DC_BDIV_Q_THRESHOLD                124
+
+#define INV_MULMOD_BNM1_THRESHOLD           26
+#define INV_NEWTON_THRESHOLD               266
+#define INV_APPR_THRESHOLD                 222
+
+#define BINV_NEWTON_THRESHOLD              296
+#define REDC_1_TO_REDC_N_THRESHOLD          59
+
+#define MU_DIV_QR_THRESHOLD               1334
+#define MU_DIVAPPR_Q_THRESHOLD            1499
+#define MUPI_DIV_QR_THRESHOLD              116
+#define MU_BDIV_QR_THRESHOLD              1057
+#define MU_BDIV_Q_THRESHOLD               1334
+
+#define POWM_SEC_TABLE  6,35,213,724,2618
+
+#define MATRIX22_STRASSEN_THRESHOLD         15
+#define HGCD_THRESHOLD                      84
+#define HGCD_APPR_THRESHOLD                101
+#define HGCD_REDUCE_THRESHOLD             1437
+#define GCD_DC_THRESHOLD                   372
+#define GCDEXT_DC_THRESHOLD                253
+#define JACOBI_BASE_METHOD                   2
+
+#define GET_STR_DC_THRESHOLD                12
+#define GET_STR_PRECOMPUTE_THRESHOLD        27
+#define SET_STR_DC_THRESHOLD               399
+#define SET_STR_PRECOMPUTE_THRESHOLD       885
+
+#define FAC_DSC_THRESHOLD                  179
+#define FAC_ODD_THRESHOLD                   29
diff --git a/third_party/gmp/mpn/sparc32/ultrasparct1/mul_1.asm b/third_party/gmp/mpn/sparc32/ultrasparct1/mul_1.asm
new file mode 100644
index 0000000..0239cd2
--- /dev/null
+++ b/third_party/gmp/mpn/sparc32/ultrasparct1/mul_1.asm
@@ -0,0 +1,83 @@
+dnl  SPARC T1 32-bit mpn_mul_1.
+
+dnl  Contributed to the GNU project by David Miller.
+
+dnl  Copyright 2010, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		   cycles/limb
+C UltraSPARC T1:       20
+C UltraSPARC T2:       18
+C UltraSPARC T3:       18
+C UltraSPARC T4:       4
+
+C INPUT PARAMETERS
+define(`rp',	`%o0')
+define(`up',	`%o1')
+define(`n',	`%o2')
+define(`v0',	`%o3')
+
+ASM_START()
+PROLOGUE(mpn_mul_1)
+	srl	n, 0, n
+	srl	v0, 0, v0
+	subcc	n, 1, n
+	be	L(final_one)
+	 clr	%o5
+
+L(top):	lduw	[up+0], %g1
+	lduw	[up+4], %g2
+	mulx	%g1, v0, %g3
+	add	up, 8, up
+	mulx	%g2, v0, %o4
+	sub	n, 2, n
+	add	rp, 8, rp
+	add	%o5, %g3, %g3
+	stw	%g3, [rp-8]
+	srlx	%g3, 32, %o5
+	add	%o5, %o4, %o4
+	stw	%o4, [rp-4]
+	brgz	n, L(top)
+	 srlx	%o4, 32, %o5
+
+	brlz,pt	n, L(done)
+	 nop
+
+L(final_one):
+	lduw	[up+0], %g1
+	mulx	%g1, v0, %g3
+	add	%o5, %g3, %g3
+	stw	%g3, [rp+0]
+	srlx	%g3, 32, %o5
+
+L(done):
+	retl
+	 mov	%o5, %o0
+EPILOGUE()
diff --git a/third_party/gmp/mpn/sparc32/ultrasparct1/sqr_diagonal.asm b/third_party/gmp/mpn/sparc32/ultrasparct1/sqr_diagonal.asm
new file mode 100644
index 0000000..3b906ef
--- /dev/null
+++ b/third_party/gmp/mpn/sparc32/ultrasparct1/sqr_diagonal.asm
@@ -0,0 +1,55 @@
+dnl  SPARC T1 32-bit mpn_sqr_diagonal.
+
+dnl  Copyright 2010 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+define(`rp',	`%o0')
+define(`up',	`%o1')
+define(`n',	`%o2')
+
+ASM_START()
+PROLOGUE(mpn_sqr_diagonal)
+	deccc	n			C n--
+	nop
+
+L(top):	lduw	[up+0], %g1
+	add	up, 4, up		C up++
+	mulx	%g1, %g1, %g3
+	stw	%g3, [rp+0]
+	srlx	%g3, 32, %g4
+	stw	%g4, [rp+4]
+	add	rp, 8, rp		C rp += 2
+	bnz	%icc, L(top)
+	deccc	n			C n--
+
+	retl
+	nop
+EPILOGUE()
diff --git a/third_party/gmp/mpn/sparc32/ultrasparct1/sub_n.asm b/third_party/gmp/mpn/sparc32/ultrasparct1/sub_n.asm
new file mode 100644
index 0000000..946bc3f
--- /dev/null
+++ b/third_party/gmp/mpn/sparc32/ultrasparct1/sub_n.asm
@@ -0,0 +1,70 @@
+dnl  SPARC T1 32-bit mpn_sub_n.
+
+dnl  Copyright 2010 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+define(`rp',  %o0)
+define(`ap',  %o1)
+define(`bp',  %o2)
+define(`n',   %o3)
+define(`cy',  %o4)
+
+define(`i',   %o3)
+
+MULFUNC_PROLOGUE(mpn_sub_n mpn_sub_nc)
+
+ASM_START()
+PROLOGUE(mpn_sub_nc)
+	b	L(ent)
+	srl	cy, 0, cy	C strip any bogus high bits
+EPILOGUE()
+
+PROLOGUE(mpn_sub_n)
+	mov	0, cy
+L(ent):	srl	n, 0, n		C strip any bogus high bits
+	sll	n, 2, n
+	add	ap, n, ap
+	add	bp, n, bp
+	add	rp, n, rp
+	neg	n, i
+
+L(top):	lduw	[ap+i], %g1
+	lduw	[bp+i], %g2
+	sub	%g1, %g2, %g3
+	sub	%g3, cy, %g3
+	stw	%g3, [rp+i]
+	add	i, 4, i
+	brnz	i, L(top)
+	srlx	%g3, 63, cy
+
+	retl
+	mov	cy, %o0		C return value
+EPILOGUE()
diff --git a/third_party/gmp/mpn/sparc32/ultrasparct1/submul_1.asm b/third_party/gmp/mpn/sparc32/ultrasparct1/submul_1.asm
new file mode 100644
index 0000000..8920070
--- /dev/null
+++ b/third_party/gmp/mpn/sparc32/ultrasparct1/submul_1.asm
@@ -0,0 +1,91 @@
+dnl  SPARC T1 32-bit mpn_submul_1.
+
+dnl  Contributed to the GNU project by David Miller.
+
+dnl  Copyright 2010, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		   cycles/limb
+C UltraSPARC T1:       24
+C UltraSPARC T2:       19
+C UltraSPARC T3:       19
+C UltraSPARC T4:       5
+
+C INPUT PARAMETERS
+define(`rp',	`%i0')
+define(`up',	`%i1')
+define(`n',	`%i2')
+define(`v0',	`%i3')
+
+ASM_START()
+PROLOGUE(mpn_submul_1)
+	save	%sp, -96, %sp
+	srl	n, 0, %o4
+	srl	v0, 0, %g1
+	subcc	%o4, 1, %o4
+	be	L(final_one)
+	 subcc	%g0, 0, %o5
+
+L(top):	lduw	[up+0], %l0
+	lduw	[rp+0], %l2
+	lduw	[up+4], %l1
+	lduw	[rp+4], %l3
+	mulx	%l0, %g1, %g3
+	add	up, 8, up
+	mulx	%l1, %g1, %o3
+	sub	%o4, 2, %o4
+	add	rp, 8, rp
+	addx	%o5, %g3, %g3
+	srlx	%g3, 32, %o5
+	subcc	%l2, %g3, %g3
+	stw	%g3, [rp-8]
+	addx	%o5, %o3, %o3
+	srlx	%o3, 32, %o5
+	subcc	%l3, %o3, %o3
+	brgz	%o4, L(top)
+	 stw	%o3, [rp-4]
+
+	brlz,pt	%o4, L(done)
+	 nop
+
+L(final_one):
+	lduw	[up+0], %l0
+	lduw	[rp+0], %l2
+	mulx	%l0, %g1, %g3
+	addx	%o5, %g3, %g3
+	srlx	%g3, 32, %o5
+	subcc	%l2, %g3, %g3
+	stw	%g3, [rp+0]
+
+L(done):
+	addx	%o5, 0, %o5
+	ret
+	 restore %o5, 0, %o0
+EPILOGUE()
diff --git a/third_party/gmp/mpn/sparc32/umul.asm b/third_party/gmp/mpn/sparc32/umul.asm
new file mode 100644
index 0000000..3a20b95
--- /dev/null
+++ b/third_party/gmp/mpn/sparc32/umul.asm
@@ -0,0 +1,77 @@
+dnl  SPARC mpn_umul_ppmm -- support for longlong.h for non-gcc.
+
+dnl  Copyright 1995, 1996, 2000 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+ASM_START()
+PROLOGUE(mpn_umul_ppmm)
+	wr	%g0,%o1,%y
+	sra	%o2,31,%g2	C Don't move this insn
+	and	%o1,%g2,%g2	C Don't move this insn
+	andcc	%g0,0,%g1	C Don't move this insn
+	mulscc	%g1,%o2,%g1
+	mulscc	%g1,%o2,%g1
+	mulscc	%g1,%o2,%g1
+	mulscc	%g1,%o2,%g1
+	mulscc	%g1,%o2,%g1
+	mulscc	%g1,%o2,%g1
+	mulscc	%g1,%o2,%g1
+	mulscc	%g1,%o2,%g1
+	mulscc	%g1,%o2,%g1
+	mulscc	%g1,%o2,%g1
+	mulscc	%g1,%o2,%g1
+	mulscc	%g1,%o2,%g1
+	mulscc	%g1,%o2,%g1
+	mulscc	%g1,%o2,%g1
+	mulscc	%g1,%o2,%g1
+	mulscc	%g1,%o2,%g1
+	mulscc	%g1,%o2,%g1
+	mulscc	%g1,%o2,%g1
+	mulscc	%g1,%o2,%g1
+	mulscc	%g1,%o2,%g1
+	mulscc	%g1,%o2,%g1
+	mulscc	%g1,%o2,%g1
+	mulscc	%g1,%o2,%g1
+	mulscc	%g1,%o2,%g1
+	mulscc	%g1,%o2,%g1
+	mulscc	%g1,%o2,%g1
+	mulscc	%g1,%o2,%g1
+	mulscc	%g1,%o2,%g1
+	mulscc	%g1,%o2,%g1
+	mulscc	%g1,%o2,%g1
+	mulscc	%g1,%o2,%g1
+	mulscc	%g1,%o2,%g1
+	mulscc	%g1,0,%g1
+	rd	%y,%g3
+	st	%g3,[%o0]
+	retl
+	add	%g1,%g2,%o0
+EPILOGUE(mpn_umul_ppmm)
diff --git a/third_party/gmp/mpn/sparc32/v8/addmul_1.asm b/third_party/gmp/mpn/sparc32/v8/addmul_1.asm
new file mode 100644
index 0000000..0052092
--- /dev/null
+++ b/third_party/gmp/mpn/sparc32/v8/addmul_1.asm
@@ -0,0 +1,131 @@
+dnl  SPARC v8 mpn_addmul_1 -- Multiply a limb vector with a limb and
+dnl  add the result to a second limb vector.
+
+dnl  Copyright 1992-1995, 2000 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C res_ptr	o0
+C s1_ptr	o1
+C size		o2
+C s2_limb	o3
+
+ASM_START()
+PROLOGUE(mpn_addmul_1)
+	orcc	%g0,%g0,%g2
+	ld	[%o1+0],%o4	C 1
+
+	sll	%o2,4,%g1
+	and	%g1,(4-1)<<4,%g1
+ifdef(`PIC',
+`	mov	%o7,%g4		C Save return address register
+0:	call	1f
+	add	%o7,L(1)-0b,%g3
+1:	mov	%g4,%o7		C Restore return address register
+',
+`	sethi	%hi(L(1)),%g3
+	or	%g3,%lo(L(1)),%g3
+')
+	jmp	%g3+%g1
+	nop
+L(1):
+L(L00):	add	%o0,-4,%o0
+	b	L(loop00)	C 4, 8, 12, ...
+	add	%o1,-4,%o1
+	nop
+L(L01):	b	L(loop01)	C 1, 5, 9, ...
+	nop
+	nop
+	nop
+L(L10):	add	%o0,-12,%o0	C 2, 6, 10, ...
+	b	L(loop10)
+	add	%o1,4,%o1
+	nop
+L(L11):	add	%o0,-8,%o0	C 3, 7, 11, ...
+	b	L(loop11)
+	add	%o1,-8,%o1
+	nop
+
+L(loop):
+	addcc	%g3,%g2,%g3	C 1
+	ld	[%o1+4],%o4	C 2
+	rd	%y,%g2		C 1
+	addx	%g0,%g2,%g2
+	ld	[%o0+0],%g1	C 2
+	addcc	%g1,%g3,%g3
+	st	%g3,[%o0+0]	C 1
+L(loop00):
+	umul	%o4,%o3,%g3	C 2
+	ld	[%o0+4],%g1	C 2
+	addxcc	%g3,%g2,%g3	C 2
+	ld	[%o1+8],%o4	C 3
+	rd	%y,%g2		C 2
+	addx	%g0,%g2,%g2
+	nop
+	addcc	%g1,%g3,%g3
+	st	%g3,[%o0+4]	C 2
+L(loop11):
+	umul	%o4,%o3,%g3	C 3
+	addxcc	%g3,%g2,%g3	C 3
+	ld	[%o1+12],%o4	C 4
+	rd	%y,%g2		C 3
+	add	%o1,16,%o1
+	addx	%g0,%g2,%g2
+	ld	[%o0+8],%g1	C 2
+	addcc	%g1,%g3,%g3
+	st	%g3,[%o0+8]	C 3
+L(loop10):
+	umul	%o4,%o3,%g3	C 4
+	addxcc	%g3,%g2,%g3	C 4
+	ld	[%o1+0],%o4	C 1
+	rd	%y,%g2		C 4
+	addx	%g0,%g2,%g2
+	ld	[%o0+12],%g1	C 2
+	addcc	%g1,%g3,%g3
+	st	%g3,[%o0+12]	C 4
+	add	%o0,16,%o0
+	addx	%g0,%g2,%g2
+L(loop01):
+	addcc	%o2,-4,%o2
+	bg	L(loop)
+	umul	%o4,%o3,%g3	C 1
+
+	addcc	%g3,%g2,%g3	C 4
+	rd	%y,%g2		C 4
+	addx	%g0,%g2,%g2
+	ld	[%o0+0],%g1	C 2
+	addcc	%g1,%g3,%g3
+	st	%g3,[%o0+0]	C 4
+	addx	%g0,%g2,%o0
+
+	retl
+	 nop
+EPILOGUE(mpn_addmul_1)
diff --git a/third_party/gmp/mpn/sparc32/v8/gmp-mparam.h b/third_party/gmp/mpn/sparc32/v8/gmp-mparam.h
new file mode 100644
index 0000000..e57897b
--- /dev/null
+++ b/third_party/gmp/mpn/sparc32/v8/gmp-mparam.h
@@ -0,0 +1,73 @@
+/* SPARC v8 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 1999-2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+/* Generated by tuneup.c, 2004-02-07, gcc 2.95 */
+
+#define MUL_TOOM22_THRESHOLD             10
+#define MUL_TOOM33_THRESHOLD             65
+
+#define SQR_BASECASE_THRESHOLD            4
+#define SQR_TOOM2_THRESHOLD              18
+#define SQR_TOOM3_THRESHOLD              65
+
+#define DIV_SB_PREINV_THRESHOLD           5
+#define DIV_DC_THRESHOLD                 24
+#define POWM_THRESHOLD                   38
+
+#define HGCD_THRESHOLD                   69
+#define GCD_ACCEL_THRESHOLD               3
+#define GCD_DC_THRESHOLD                498
+#define JACOBI_BASE_METHOD                2
+
+#define DIVREM_1_NORM_THRESHOLD           6
+#define DIVREM_1_UNNORM_THRESHOLD        11
+#define MOD_1_NORM_THRESHOLD              5
+#define MOD_1_UNNORM_THRESHOLD            9
+#define USE_PREINV_DIVREM_1               1
+#define USE_PREINV_MOD_1                  1
+#define DIVREM_2_THRESHOLD                0  /* always */
+#define DIVEXACT_1_THRESHOLD              0  /* always */
+#define MODEXACT_1_ODD_THRESHOLD          4
+
+#define GET_STR_DC_THRESHOLD             14
+#define GET_STR_PRECOMPUTE_THRESHOLD     23
+#define SET_STR_THRESHOLD              1679
+
+#define MUL_FFT_TABLE  { 272, 672, 1152, 2560, 10240, 24576, 0 }
+#define MUL_FFT_MODF_THRESHOLD          264
+#define MUL_FFT_THRESHOLD              1792
+
+#define SQR_FFT_TABLE  { 304, 672, 1152, 3584, 10240, 24576, 0 }
+#define SQR_FFT_MODF_THRESHOLD          264
+#define SQR_FFT_THRESHOLD              1728
diff --git a/third_party/gmp/mpn/sparc32/v8/mul_1.asm b/third_party/gmp/mpn/sparc32/v8/mul_1.asm
new file mode 100644
index 0000000..e26c853
--- /dev/null
+++ b/third_party/gmp/mpn/sparc32/v8/mul_1.asm
@@ -0,0 +1,112 @@
+dnl  SPARC v8 mpn_mul_1 -- Multiply a limb vector with a single limb and
+dnl  store the product in a second limb vector.
+
+dnl  Copyright 1992, 1994, 1995, 2000 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C res_ptr	o0
+C s1_ptr	o1
+C size		o2
+C s2_limb	o3
+
+ASM_START()
+PROLOGUE(mpn_mul_1)
+	sll	%o2,4,%g1
+	and	%g1,(4-1)<<4,%g1
+ifdef(`PIC',
+`	mov	%o7,%g4		C Save return address register
+0:	call	1f
+	add	%o7,L(1)-0b,%g3
+1:	mov	%g4,%o7		C Restore return address register
+',
+`	sethi	%hi(L(1)),%g3
+	or	%g3,%lo(L(1)),%g3
+')
+	jmp	%g3+%g1
+	ld	[%o1+0],%o4	C 1
+L(1):
+L(L00):	add	%o0,-4,%o0
+	add	%o1,-4,%o1
+	b	L(loop00)	C 4, 8, 12, ...
+	orcc	%g0,%g0,%g2
+L(L01):	b	L(loop01)	C 1, 5, 9, ...
+	orcc	%g0,%g0,%g2
+	nop
+	nop
+L(L10):	add	%o0,-12,%o0	C 2, 6, 10, ...
+	add	%o1,4,%o1
+	b	L(loop10)
+	orcc	%g0,%g0,%g2
+	nop
+L(L11):	add	%o0,-8,%o0	C 3, 7, 11, ...
+	add	%o1,-8,%o1
+	b	L(loop11)
+	orcc	%g0,%g0,%g2
+
+L(loop):
+	addcc	%g3,%g2,%g3	C 1
+	ld	[%o1+4],%o4	C 2
+	st	%g3,[%o0+0]	C 1
+	rd	%y,%g2		C 1
+L(loop00):
+	umul	%o4,%o3,%g3	C 2
+	addxcc	%g3,%g2,%g3	C 2
+	ld	[%o1+8],%o4	C 3
+	st	%g3,[%o0+4]	C 2
+	rd	%y,%g2		C 2
+L(loop11):
+	umul	%o4,%o3,%g3	C 3
+	addxcc	%g3,%g2,%g3	C 3
+	ld	[%o1+12],%o4	C 4
+	add	%o1,16,%o1
+	st	%g3,[%o0+8]	C 3
+	rd	%y,%g2		C 3
+L(loop10):
+	umul	%o4,%o3,%g3	C 4
+	addxcc	%g3,%g2,%g3	C 4
+	ld	[%o1+0],%o4	C 1
+	st	%g3,[%o0+12]	C 4
+	add	%o0,16,%o0
+	rd	%y,%g2		C 4
+	addx	%g0,%g2,%g2
+L(loop01):
+	addcc	%o2,-4,%o2
+	bg	L(loop)
+	umul	%o4,%o3,%g3	C 1
+
+	addcc	%g3,%g2,%g3	C 4
+	st	%g3,[%o0+0]	C 4
+	rd	%y,%g2		C 4
+
+	retl
+	addx	%g0,%g2,%o0
+EPILOGUE(mpn_mul_1)
diff --git a/third_party/gmp/mpn/sparc32/v8/submul_1.asm b/third_party/gmp/mpn/sparc32/v8/submul_1.asm
new file mode 100644
index 0000000..187314e
--- /dev/null
+++ b/third_party/gmp/mpn/sparc32/v8/submul_1.asm
@@ -0,0 +1,67 @@
+dnl  SPARC v8 mpn_submul_1 -- Multiply a limb vector with a limb and
+dnl  subtract the result from a second limb vector.
+
+dnl  Copyright 1992-1994, 2000 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C res_ptr	o0
+C s1_ptr	o1
+C size		o2
+C s2_limb	o3
+
+ASM_START()
+PROLOGUE(mpn_submul_1)
+	sub	%g0,%o2,%o2		C negate ...
+	sll	%o2,2,%o2		C ... and scale size
+	sub	%o1,%o2,%o1		C o1 is offset s1_ptr
+	sub	%o0,%o2,%g1		C g1 is offset res_ptr
+
+	mov	0,%o0			C clear cy_limb
+
+L(loop):
+	ld	[%o1+%o2],%o4
+	ld	[%g1+%o2],%g2
+	umul	%o4,%o3,%o5
+	rd	%y,%g3
+	addcc	%o5,%o0,%o5
+	addx	%g3,0,%o0
+	subcc	%g2,%o5,%g2
+	addx	%o0,0,%o0
+	st	%g2,[%g1+%o2]
+
+	addcc	%o2,4,%o2
+	bne	L(loop)
+	 nop
+
+	retl
+	 nop
+EPILOGUE(mpn_submul_1)
diff --git a/third_party/gmp/mpn/sparc32/v8/supersparc/gmp-mparam.h b/third_party/gmp/mpn/sparc32/v8/supersparc/gmp-mparam.h
new file mode 100644
index 0000000..1ac9239
--- /dev/null
+++ b/third_party/gmp/mpn/sparc32/v8/supersparc/gmp-mparam.h
@@ -0,0 +1,73 @@
+/* SuperSPARC gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 1999-2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+/* Generated by tuneup.c, 2004-02-10, gcc 3.3 */
+
+#define MUL_TOOM22_THRESHOLD             14
+#define MUL_TOOM33_THRESHOLD             81
+
+#define SQR_BASECASE_THRESHOLD            5
+#define SQR_TOOM2_THRESHOLD              28
+#define SQR_TOOM3_THRESHOLD              86
+
+#define DIV_SB_PREINV_THRESHOLD           0  /* always */
+#define DIV_DC_THRESHOLD                 26
+#define POWM_THRESHOLD                   79
+
+#define HGCD_THRESHOLD                   97
+#define GCD_ACCEL_THRESHOLD               3
+#define GCD_DC_THRESHOLD                470
+#define JACOBI_BASE_METHOD                2
+
+#define DIVREM_1_NORM_THRESHOLD           0  /* always */
+#define DIVREM_1_UNNORM_THRESHOLD         3
+#define MOD_1_NORM_THRESHOLD              0  /* always */
+#define MOD_1_UNNORM_THRESHOLD            3
+#define USE_PREINV_DIVREM_1               1
+#define USE_PREINV_MOD_1                  1
+#define DIVREM_2_THRESHOLD                0  /* always */
+#define DIVEXACT_1_THRESHOLD              0  /* always */
+#define MODEXACT_1_ODD_THRESHOLD          0  /* always */
+
+#define GET_STR_DC_THRESHOLD             19
+#define GET_STR_PRECOMPUTE_THRESHOLD     34
+#define SET_STR_THRESHOLD              3524
+
+#define MUL_FFT_TABLE  { 304, 800, 1408, 3584, 10240, 24576, 0 }
+#define MUL_FFT_MODF_THRESHOLD          264
+#define MUL_FFT_THRESHOLD              2304
+
+#define SQR_FFT_TABLE  { 336, 800, 1408, 3584, 10240, 24576, 0 }
+#define SQR_FFT_MODF_THRESHOLD          280
+#define SQR_FFT_THRESHOLD              2304
diff --git a/third_party/gmp/mpn/sparc32/v8/supersparc/udiv.asm b/third_party/gmp/mpn/sparc32/v8/supersparc/udiv.asm
new file mode 100644
index 0000000..12f66ce
--- /dev/null
+++ b/third_party/gmp/mpn/sparc32/v8/supersparc/udiv.asm
@@ -0,0 +1,131 @@
+dnl  SuperSPARC mpn_udiv_qrnnd division support, used from longlong.h.
+dnl  This is for SuperSPARC only, to compensate for its semi-functional
+dnl  udiv instruction.
+
+dnl  Copyright 1993, 1994, 1996, 2000 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C rem_ptr	i0
+C n1		i1
+C n0		i2
+C d		i3
+
+ASM_START()
+
+ifdef(`PIC',
+`	TEXT
+L(getpc):
+	retl
+	nop')
+
+	TEXT
+	ALIGN(8)
+L(C0):	.double	0r4294967296
+L(C1):	.double	0r2147483648
+
+PROLOGUE(mpn_udiv_qrnnd)
+	save	%sp,-104,%sp
+	st	%i1,[%fp-8]
+	ld	[%fp-8],%f10
+
+ifdef(`PIC',
+`L(pc):	call	L(getpc)		C put address of this insn in %o7
+	ldd	[%o7+L(C0)-L(pc)],%f8',
+`	sethi	%hi(L(C0)),%o7
+	ldd	[%o7+%lo(L(C0))],%f8')
+
+	fitod	%f10,%f4
+	cmp	%i1,0
+	bge	L(248)
+	mov	%i0,%i5
+	faddd	%f4,%f8,%f4
+L(248):
+	st	%i2,[%fp-8]
+	ld	[%fp-8],%f10
+	fmuld	%f4,%f8,%f6
+	cmp	%i2,0
+	bge	L(249)
+	fitod	%f10,%f2
+	faddd	%f2,%f8,%f2
+L(249):
+	st	%i3,[%fp-8]
+	faddd	%f6,%f2,%f2
+	ld	[%fp-8],%f10
+	cmp	%i3,0
+	bge	L(250)
+	fitod	%f10,%f4
+	faddd	%f4,%f8,%f4
+L(250):
+	fdivd	%f2,%f4,%f2
+
+ifdef(`PIC',
+`	ldd	[%o7+L(C1)-L(pc)],%f4',
+`	sethi	%hi(L(C1)),%o7
+	ldd	[%o7+%lo(L(C1))],%f4')
+
+	fcmped	%f2,%f4
+	nop
+	fbge,a	L(251)
+	fsubd	%f2,%f4,%f2
+	fdtoi	%f2,%f2
+	st	%f2,[%fp-8]
+	b	L(252)
+	ld	[%fp-8],%i4
+L(251):
+	fdtoi	%f2,%f2
+	st	%f2,[%fp-8]
+	ld	[%fp-8],%i4
+	sethi	%hi(-2147483648),%g2
+	xor	%i4,%g2,%i4
+L(252):
+	umul	%i3,%i4,%g3
+	rd	%y,%i0
+	subcc	%i2,%g3,%o7
+	subxcc	%i1,%i0,%g0
+	be	L(253)
+	cmp	%o7,%i3
+
+	add	%i4,-1,%i0
+	add	%o7,%i3,%o7
+	st	%o7,[%i5]
+	ret
+	restore
+L(253):
+	blu	L(246)
+	mov	%i4,%i0
+	add	%i4,1,%i0
+	sub	%o7,%i3,%o7
+L(246):
+	st	%o7,[%i5]
+	ret
+	restore
+EPILOGUE(mpn_udiv_qrnnd)
diff --git a/third_party/gmp/mpn/sparc32/v8/udiv.asm b/third_party/gmp/mpn/sparc32/v8/udiv.asm
new file mode 100644
index 0000000..12f66ce
--- /dev/null
+++ b/third_party/gmp/mpn/sparc32/v8/udiv.asm
@@ -0,0 +1,131 @@
+dnl  SuperSPARC mpn_udiv_qrnnd division support, used from longlong.h.
+dnl  This is for SuperSPARC only, to compensate for its semi-functional
+dnl  udiv instruction.
+
+dnl  Copyright 1993, 1994, 1996, 2000 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C rem_ptr	i0
+C n1		i1
+C n0		i2
+C d		i3
+
+ASM_START()
+
+ifdef(`PIC',
+`	TEXT
+L(getpc):
+	retl
+	nop')
+
+	TEXT
+	ALIGN(8)
+L(C0):	.double	0r4294967296
+L(C1):	.double	0r2147483648
+
+PROLOGUE(mpn_udiv_qrnnd)
+	save	%sp,-104,%sp
+	st	%i1,[%fp-8]
+	ld	[%fp-8],%f10
+
+ifdef(`PIC',
+`L(pc):	call	L(getpc)		C put address of this insn in %o7
+	ldd	[%o7+L(C0)-L(pc)],%f8',
+`	sethi	%hi(L(C0)),%o7
+	ldd	[%o7+%lo(L(C0))],%f8')
+
+	fitod	%f10,%f4
+	cmp	%i1,0
+	bge	L(248)
+	mov	%i0,%i5
+	faddd	%f4,%f8,%f4
+L(248):
+	st	%i2,[%fp-8]
+	ld	[%fp-8],%f10
+	fmuld	%f4,%f8,%f6
+	cmp	%i2,0
+	bge	L(249)
+	fitod	%f10,%f2
+	faddd	%f2,%f8,%f2
+L(249):
+	st	%i3,[%fp-8]
+	faddd	%f6,%f2,%f2
+	ld	[%fp-8],%f10
+	cmp	%i3,0
+	bge	L(250)
+	fitod	%f10,%f4
+	faddd	%f4,%f8,%f4
+L(250):
+	fdivd	%f2,%f4,%f2
+
+ifdef(`PIC',
+`	ldd	[%o7+L(C1)-L(pc)],%f4',
+`	sethi	%hi(L(C1)),%o7
+	ldd	[%o7+%lo(L(C1))],%f4')
+
+	fcmped	%f2,%f4
+	nop
+	fbge,a	L(251)
+	fsubd	%f2,%f4,%f2
+	fdtoi	%f2,%f2
+	st	%f2,[%fp-8]
+	b	L(252)
+	ld	[%fp-8],%i4
+L(251):
+	fdtoi	%f2,%f2
+	st	%f2,[%fp-8]
+	ld	[%fp-8],%i4
+	sethi	%hi(-2147483648),%g2
+	xor	%i4,%g2,%i4
+L(252):
+	umul	%i3,%i4,%g3
+	rd	%y,%i0
+	subcc	%i2,%g3,%o7
+	subxcc	%i1,%i0,%g0
+	be	L(253)
+	cmp	%o7,%i3
+
+	add	%i4,-1,%i0
+	add	%o7,%i3,%o7
+	st	%o7,[%i5]
+	ret
+	restore
+L(253):
+	blu	L(246)
+	mov	%i4,%i0
+	add	%i4,1,%i0
+	sub	%o7,%i3,%o7
+L(246):
+	st	%o7,[%i5]
+	ret
+	restore
+EPILOGUE(mpn_udiv_qrnnd)
diff --git a/third_party/gmp/mpn/sparc32/v8/umul.asm b/third_party/gmp/mpn/sparc32/v8/umul.asm
new file mode 100644
index 0000000..1a2e84b
--- /dev/null
+++ b/third_party/gmp/mpn/sparc32/v8/umul.asm
@@ -0,0 +1,40 @@
+dnl  SPARC v8 mpn_umul_ppmm -- support for longlong.h for non-gcc.
+
+dnl  Copyright 1995, 1996, 2000 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+ASM_START()
+PROLOGUE(mpn_umul_ppmm)
+	umul	%o1,%o2,%g2
+	st	%g2,[%o0]
+	retl
+	rd	%y,%o0
+EPILOGUE(mpn_umul_ppmm)
diff --git a/third_party/gmp/mpn/sparc32/v9/README b/third_party/gmp/mpn/sparc32/v9/README
new file mode 100644
index 0000000..9b39713
--- /dev/null
+++ b/third_party/gmp/mpn/sparc32/v9/README
@@ -0,0 +1,4 @@
+Code for SPARC processors implementing version 9 of the SPARC architecture.
+This code is for systems that doesn't preserve the full 64-bit contents of
+integer register at context switch.  For other systems (such as Solaris 7 or
+later) use the code in ../../sparc64.
diff --git a/third_party/gmp/mpn/sparc32/v9/add_n.asm b/third_party/gmp/mpn/sparc32/v9/add_n.asm
new file mode 100644
index 0000000..7bd5974
--- /dev/null
+++ b/third_party/gmp/mpn/sparc32/v9/add_n.asm
@@ -0,0 +1,129 @@
+dnl  SPARC mpn_add_n -- Add two limb vectors of the same length > 0 and store
+dnl  sum in a third limb vector.
+
+dnl  Copyright 2001 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+define(rp,%o0)
+define(s1p,%o1)
+define(s2p,%o2)
+define(n,%o3)
+define(cy,%g1)
+
+C This code uses 64-bit operations on `o' and `g' registers.  It doesn't
+C require that `o' registers' upper 32 bits are preserved by the operating
+C system, but if they are not, they must be zeroed.  That is indeed what
+C happens at least on Slowaris 2.5 and 2.6.
+
+C On UltraSPARC 1 and 2, this code runs at 3 cycles/limb from the Dcache and at
+C about 10 cycles/limb from the Ecache.
+
+ASM_START()
+PROLOGUE(mpn_add_n)
+	lduw	[s1p+0],%o4
+	lduw	[s2p+0],%o5
+	addcc	n,-2,n
+	bl,pn	%icc,L(end1)
+	lduw	[s1p+4],%g2
+	lduw	[s2p+4],%g3
+	be,pn	%icc,L(end2)
+	mov	0,cy
+
+	.align	16
+L(loop):
+	add	%o4,%o5,%g4
+	add	rp,8,rp
+	lduw	[s1p+8],%o4
+	fitod	%f0,%f2
+C ---
+	add	cy,%g4,%g4
+	addcc	n,-1,n
+	lduw	[s2p+8],%o5
+	fitod	%f0,%f2
+C ---
+	srlx	%g4,32,cy
+	add	s2p,8,s2p
+	stw	%g4,[rp-8]
+	be,pn	%icc,L(exito)+4
+C ---
+	add	%g2,%g3,%g4
+	addcc	n,-1,n
+	lduw	[s1p+12],%g2
+	fitod	%f0,%f2
+C ---
+	add	cy,%g4,%g4
+	add	s1p,8,s1p
+	lduw	[s2p+4],%g3
+	fitod	%f0,%f2
+C ---
+	srlx	%g4,32,cy
+	bne,pt	%icc,L(loop)
+	stw	%g4,[rp-4]
+C ---
+L(exite):
+	add	%o4,%o5,%g4
+	add	cy,%g4,%g4
+	srlx	%g4,32,cy
+	stw	%g4,[rp+0]
+	add	%g2,%g3,%g4
+	add	cy,%g4,%g4
+	stw	%g4,[rp+4]
+	retl
+	srlx	%g4,32,%o0
+
+L(exito):
+	add	%g2,%g3,%g4
+	add	cy,%g4,%g4
+	srlx	%g4,32,cy
+	stw	%g4,[rp-4]
+	add	%o4,%o5,%g4
+	add	cy,%g4,%g4
+	stw	%g4,[rp+0]
+	retl
+	srlx	%g4,32,%o0
+
+L(end1):
+	add	%o4,%o5,%g4
+	stw	%g4,[rp+0]
+	retl
+	srlx	%g4,32,%o0
+
+L(end2):
+	add	%o4,%o5,%g4
+	srlx	%g4,32,cy
+	stw	%g4,[rp+0]
+	add	%g2,%g3,%g4
+	add	cy,%g4,%g4
+	stw	%g4,[rp+4]
+	retl
+	srlx	%g4,32,%o0
+EPILOGUE(mpn_add_n)
diff --git a/third_party/gmp/mpn/sparc32/v9/addmul_1.asm b/third_party/gmp/mpn/sparc32/v9/addmul_1.asm
new file mode 100644
index 0000000..2adf7a8
--- /dev/null
+++ b/third_party/gmp/mpn/sparc32/v9/addmul_1.asm
@@ -0,0 +1,306 @@
+dnl  SPARC v9 32-bit mpn_addmul_1 -- Multiply a limb vector with a limb and add
+dnl  the result to a second limb vector.
+
+dnl  Copyright 1998, 2000, 2001, 2003 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C Algorithm: We use two floating-point multiplies per limb product, with the
+C invariant v operand split into two 16-bit pieces, and the u operand split
+C into 32-bit pieces.  We convert the two 48-bit products and transfer them to
+C the integer unit.
+
+C		   cycles/limb
+C UltraSPARC 1&2:     6.5
+C UltraSPARC 3:	      ?
+
+C Possible optimizations:
+C   1. Combine 32-bit memory operations into 64-bit operations.  Since we're
+C      memory bandwidth limited, this could save 1.5 cycles/limb.
+C   2. Unroll the inner loop.  Since we already use alternate temporary areas,
+C      it is very straightforward to unroll, using an exit branch midways.
+C      Unrolling would allow deeper scheduling which could improve speed for L2
+C      cache case.
+C   3. For mpn_mul_1: Use more alternating temp areas.  The std'es and ldx'es
+C      aren't sufficiently apart-scheduled with just two temp areas.
+C   4. Specialize for particular v values.  If its upper 16 bits are zero, we
+C      could save many operations.
+
+C INPUT PARAMETERS
+C rp	i0
+C up	i1
+C n	i2
+C v	i3
+
+define(`FSIZE',224)
+
+ASM_START()
+PROLOGUE(mpn_addmul_1)
+	add	%sp, -FSIZE, %sp
+	sethi	%hi(0xffff), %g1
+	srl	%o3, 16, %g2
+	or	%g1, %lo(0xffff), %g1
+	and	%o3, %g1, %g1
+	stx	%g1, [%sp+104]
+	stx	%g2, [%sp+112]
+	ldd	[%sp+104], %f6
+	ldd	[%sp+112], %f8
+	fxtod	%f6, %f6
+	fxtod	%f8, %f8
+	ld	[%sp+104], %f10		C zero f10
+
+	mov	0, %g3			C cy = 0
+
+define(`fanop', `fitod %f18, %f0')	C  A quasi nop running in the FA pipe
+
+	add	%sp, 160, %o5		C point in scratch area
+	and	%o5, -32, %o5		C align at 0 (mod 32) in scratch area
+
+	subcc	%o2, 1, %o2
+	ld	[%o1], %f11		C read up[i]
+	add	%o1, 4, %o1		C up++
+	bne,pt	%icc, .L_two_or_more
+	fxtod	%f10, %f2
+
+	fmuld	%f2, %f8, %f16
+	fmuld	%f2, %f6, %f4
+	fdtox	%f16, %f14
+	fdtox	%f4, %f12
+	std	%f14, [%o5+16]
+	std	%f12, [%o5+24]
+	ldx	[%o5+16], %g2		C p16
+	ldx	[%o5+24], %g1		C p0
+	lduw	[%o0], %g5		C read rp[i]
+	b	.L1
+	add	%o0, -16, %o0
+
+	.align	16
+.L_two_or_more:
+	subcc	%o2, 1, %o2
+	ld	[%o1], %f11		C read up[i]
+	fmuld	%f2, %f8, %f16
+	fmuld	%f2, %f6, %f4
+	add	%o1, 4, %o1		C up++
+	bne,pt	%icc, .L_three_or_more
+	fxtod	%f10, %f2
+
+	fdtox	%f16, %f14
+	fdtox	%f4, %f12
+	std	%f14, [%o5+16]
+	fmuld	%f2, %f8, %f16
+	std	%f12, [%o5+24]
+	fmuld	%f2, %f6, %f4
+	fdtox	%f16, %f14
+	fdtox	%f4, %f12
+	std	%f14, [%o5+0]
+	std	%f12, [%o5+8]
+	lduw	[%o0], %g5		C read rp[i]
+	ldx	[%o5+16], %g2		C p16
+	ldx	[%o5+24], %g1		C p0
+	b	.L2
+	add	%o0, -12, %o0
+
+	.align	16
+.L_three_or_more:
+	subcc	%o2, 1, %o2
+	ld	[%o1], %f11		C read up[i]
+	fdtox	%f16, %f14
+	fdtox	%f4, %f12
+	std	%f14, [%o5+16]
+	fmuld	%f2, %f8, %f16
+	std	%f12, [%o5+24]
+	fmuld	%f2, %f6, %f4
+	add	%o1, 4, %o1		C up++
+	bne,pt	%icc, .L_four_or_more
+	fxtod	%f10, %f2
+
+	fdtox	%f16, %f14
+	fdtox	%f4, %f12
+	std	%f14, [%o5+0]
+	fmuld	%f2, %f8, %f16
+	std	%f12, [%o5+8]
+	fmuld	%f2, %f6, %f4
+	fdtox	%f16, %f14
+	ldx	[%o5+16], %g2		C p16
+	fdtox	%f4, %f12
+	ldx	[%o5+24], %g1		C p0
+	std	%f14, [%o5+16]
+	std	%f12, [%o5+24]
+	lduw	[%o0], %g5		C read rp[i]
+	b	.L3
+	add	%o0, -8, %o0
+
+	.align	16
+.L_four_or_more:
+	subcc	%o2, 1, %o2
+	ld	[%o1], %f11		C read up[i]
+	fdtox	%f16, %f14
+	fdtox	%f4, %f12
+	std	%f14, [%o5+0]
+	fmuld	%f2, %f8, %f16
+	std	%f12, [%o5+8]
+	fmuld	%f2, %f6, %f4
+	add	%o1, 4, %o1		C up++
+	bne,pt	%icc, .L_five_or_more
+	fxtod	%f10, %f2
+
+	fdtox	%f16, %f14
+	ldx	[%o5+16], %g2		C p16
+	fdtox	%f4, %f12
+	ldx	[%o5+24], %g1		C p0
+	std	%f14, [%o5+16]
+	fmuld	%f2, %f8, %f16
+	std	%f12, [%o5+24]
+	fmuld	%f2, %f6, %f4
+	add	%o1, 4, %o1		C up++
+	lduw	[%o0], %g5		C read rp[i]
+	b	.L4
+	add	%o0, -4, %o0
+
+	.align	16
+.L_five_or_more:
+	subcc	%o2, 1, %o2
+	ld	[%o1], %f11		C read up[i]
+	fdtox	%f16, %f14
+	ldx	[%o5+16], %g2		C p16
+	fdtox	%f4, %f12
+	ldx	[%o5+24], %g1		C p0
+	std	%f14, [%o5+16]
+	fmuld	%f2, %f8, %f16
+	std	%f12, [%o5+24]
+	fmuld	%f2, %f6, %f4
+	add	%o1, 4, %o1		C up++
+	lduw	[%o0], %g5		C read rp[i]
+	bne,pt	%icc, .Loop
+	fxtod	%f10, %f2
+	b,a	.L5
+
+C BEGIN MAIN LOOP
+	.align 16
+C -- 0
+.Loop:	nop
+	subcc	%o2, 1, %o2
+	ld	[%o1], %f11		C read up[i]
+	fdtox	%f16, %f14
+C -- 1
+	sllx	%g2, 16, %g4		C (p16 << 16)
+	add	%o0, 4, %o0		C rp++
+	ldx	[%o5+0], %g2		C p16
+	fdtox	%f4, %f12
+C -- 2
+	nop
+	add	%g1, %g4, %g4		C p = p0 + (p16 << 16)
+	ldx	[%o5+8], %g1		C p0
+	fanop
+C -- 3
+	nop
+	add	%g3, %g4, %g4		C p += cy
+	std	%f14, [%o5+0]
+	fmuld	%f2, %f8, %f16
+C -- 4
+	nop
+	add	%g5, %g4, %g4		C p += rp[i]
+	std	%f12, [%o5+8]
+	fmuld	%f2, %f6, %f4
+C -- 5
+	xor	%o5, 16, %o5		C alternate scratch variables
+	add	%o1, 4, %o1		C up++
+	stw	%g4, [%o0-4]
+	fanop
+C -- 6
+	srlx	%g4, 32, %g3		C new cy
+	lduw	[%o0], %g5		C read rp[i]
+	bne,pt	%icc, .Loop
+	fxtod	%f10, %f2
+C END MAIN LOOP
+
+.L5:	fdtox	%f16, %f14
+	sllx	%g2, 16, %g4		C (p16 << 16)
+	ldx	[%o5+0], %g2		C p16
+	fdtox	%f4, %f12
+	add	%g1, %g4, %g4		C p = p0 + (p16 << 16)
+	ldx	[%o5+8], %g1		C p0
+	add	%g4, %g3, %g4		C p += cy
+	std	%f14, [%o5+0]
+	fmuld	%f2, %f8, %f16
+	add	%g5, %g4, %g4		C p += rp[i]
+	std	%f12, [%o5+8]
+	fmuld	%f2, %f6, %f4
+	xor	%o5, 16, %o5
+	stw	%g4, [%o0+0]
+	srlx	%g4, 32, %g3		C new cy
+	lduw	[%o0+4], %g5		C read rp[i]
+
+.L4:	fdtox	%f16, %f14
+	sllx	%g2, 16, %g4		C (p16 << 16)
+	ldx	[%o5+0], %g2		C p16
+	fdtox	%f4, %f12
+	add	%g1, %g4, %g4		C p = p0 + (p16 << 16)
+	ldx	[%o5+8], %g1		C p0
+	add	%g3, %g4, %g4		C p += cy
+	std	%f14, [%o5+0]
+	add	%g5, %g4, %g4		C p += rp[i]
+	std	%f12, [%o5+8]
+	xor	%o5, 16, %o5
+	stw	%g4, [%o0+4]
+	srlx	%g4, 32, %g3		C new cy
+	lduw	[%o0+8], %g5		C read rp[i]
+
+.L3:	sllx	%g2, 16, %g4		C (p16 << 16)
+	ldx	[%o5+0], %g2		C p16
+	add	%g1, %g4, %g4		C p = p0 + (p16 << 16)
+	ldx	[%o5+8], %g1		C p0
+	add	%g3, %g4, %g4		C p += cy
+	add	%g5, %g4, %g4		C p += rp[i]
+	xor	%o5, 16, %o5
+	stw	%g4, [%o0+8]
+	srlx	%g4, 32, %g3		C new cy
+	lduw	[%o0+12], %g5		C read rp[i]
+
+.L2:	sllx	%g2, 16, %g4		C (p16 << 16)
+	ldx	[%o5+0], %g2		C p16
+	add	%g1, %g4, %g4		C p = p0 + (p16 << 16)
+	ldx	[%o5+8], %g1		C p0
+	add	%g3, %g4, %g4		C p += cy
+	add	%g5, %g4, %g4		C p += rp[i]
+	stw	%g4, [%o0+12]
+	srlx	%g4, 32, %g3		C new cy
+	lduw	[%o0+16], %g5		C read rp[i]
+
+.L1:	sllx	%g2, 16, %g4		C (p16 << 16)
+	add	%g1, %g4, %g4		C p = p0 + (p16 << 16)
+	add	%g3, %g4, %g4		C p += cy
+	add	%g5, %g4, %g4		C p += rp[i]
+	stw	%g4, [%o0+16]
+	srlx	%g4, 32, %g3		C new cy
+
+	mov	%g3, %o0
+	retl
+	sub	%sp, -FSIZE, %sp
+EPILOGUE(mpn_addmul_1)
diff --git a/third_party/gmp/mpn/sparc32/v9/gmp-mparam.h b/third_party/gmp/mpn/sparc32/v9/gmp-mparam.h
new file mode 100644
index 0000000..f909e2c
--- /dev/null
+++ b/third_party/gmp/mpn/sparc32/v9/gmp-mparam.h
@@ -0,0 +1,204 @@
+/* SPARC v9 32-bit gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 1999-2002, 2004, 2009-2011, 2014 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+/* 1593 MHz ultrasparc3 running Solaris 10 (swift.nada.kth.se) */
+/* FFT tuning limit = 25000000 */
+/* Generated by tuneup.c, 2014-03-16, gcc 3.4 */
+
+#define DIVREM_1_NORM_THRESHOLD              3
+#define DIVREM_1_UNNORM_THRESHOLD            4
+#define MOD_1_1P_METHOD                      2
+#define MOD_1_NORM_THRESHOLD                 3
+#define MOD_1_UNNORM_THRESHOLD               4
+#define MOD_1N_TO_MOD_1_1_THRESHOLD         13
+#define MOD_1U_TO_MOD_1_1_THRESHOLD         12
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD         0  /* never mpn_mod_1_1p */
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        22
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     32
+#define USE_PREINV_DIVREM_1                  1
+#define DIV_QR_1N_PI1_METHOD                 1
+#define DIV_QR_1_NORM_THRESHOLD              4
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always */
+#define BMOD_1_TO_MOD_1_THRESHOLD        MP_SIZE_T_MAX  /* never */
+
+#define MUL_TOOM22_THRESHOLD                28
+#define MUL_TOOM33_THRESHOLD                43
+#define MUL_TOOM44_THRESHOLD               126
+#define MUL_TOOM6H_THRESHOLD               161
+#define MUL_TOOM8H_THRESHOLD               208
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      73
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD      80
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD      85
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD      55
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD      72
+
+#define SQR_BASECASE_THRESHOLD               4
+#define SQR_TOOM2_THRESHOLD                 64
+#define SQR_TOOM3_THRESHOLD                 85
+#define SQR_TOOM4_THRESHOLD                152
+#define SQR_TOOM6_THRESHOLD                185
+#define SQR_TOOM8_THRESHOLD                324
+
+#define MULMID_TOOM42_THRESHOLD             64
+
+#define MULMOD_BNM1_THRESHOLD               12
+#define SQRMOD_BNM1_THRESHOLD               16
+
+#define MUL_FFT_MODF_THRESHOLD             288  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    288, 5}, {      9, 4}, {     19, 5}, {     11, 6}, \
+    {      6, 5}, {     14, 6}, {      8, 5}, {     17, 6}, \
+    {      9, 5}, {     20, 6}, {     13, 7}, {      7, 6}, \
+    {     16, 7}, {      9, 6}, {     19, 7}, {     11, 6}, \
+    {     23, 7}, {     13, 8}, {      7, 7}, {     15, 6}, \
+    {     31, 7}, {     19, 8}, {     11, 7}, {     23, 9}, \
+    {      7, 8}, {     15, 7}, {     31, 8}, {     19, 7}, \
+    {     39, 8}, {     27, 9}, {     15, 8}, {     31, 7}, \
+    {     63, 8}, {     39, 9}, {     23, 8}, {     47,10}, \
+    {     15, 9}, {     31, 8}, {     67, 9}, {     39, 8}, \
+    {     79, 9}, {     47,10}, {     31, 9}, {     71, 8}, \
+    {    143, 9}, {     79,10}, {     47, 9}, {     95,11}, \
+    {     31,10}, {     63, 9}, {    135, 8}, {    271, 9}, \
+    {    143, 8}, {    287,10}, {     79, 9}, {    175,10}, \
+    {     95, 9}, {    191, 8}, {    383,10}, {    111,11}, \
+    {     63,10}, {    143, 9}, {    287, 8}, {    575,10}, \
+    {    175,11}, {     95,10}, {    191, 9}, {    415, 8}, \
+    {    831,12}, {     63,11}, {    127,10}, {    287, 9}, \
+    {    575,11}, {    159,10}, {    351, 9}, {    703,11}, \
+    {    191,10}, {    415, 9}, {    831,11}, {    223,10}, \
+    {    447, 9}, {    895, 8}, {   1791,12}, {    127,11}, \
+    {    287,10}, {    607, 9}, {   1215, 8}, {   2431,11}, \
+    {    319, 9}, {   1279,11}, {    351,12}, {    191,11}, \
+    {    415,10}, {    831,11}, {    447,10}, {    895, 9}, \
+    {   1791,11}, {    479,13}, {    127,12}, {    255,11}, \
+    {    575,10}, {   1151,11}, {    607,12}, {    319,11}, \
+    {    703,12}, {    383,11}, {    831,12}, {    447,11}, \
+    {    895,10}, {   1791,11}, {    959,13}, {    255,12}, \
+    {    575,11}, {   1215,10}, {   2431,12}, {    703,13}, \
+    {    383,12}, {    959,14}, {    255,13}, {    511,12}, \
+    {   1087,11}, {   2175,12}, {   1215,11}, {   2431,13}, \
+    {    639,12}, {   1407,11}, {   2943,13}, {    895,12}, \
+    {   1919,14}, {    511,13}, {   1151,12}, {   2431,13}, \
+    {   1407,14}, {    767,13}, {   1791,15}, {    511,14}, \
+    {   1023,13}, {   2431,14}, {   1279,13}, {   2943,12}, \
+    {   5887,14}, {  16384,15}, {  32768,16} }
+#define MUL_FFT_TABLE3_SIZE 143
+#define MUL_FFT_THRESHOLD                 2240
+
+#define SQR_FFT_MODF_THRESHOLD             244  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    244, 5}, {      8, 4}, {     17, 5}, {     17, 6}, \
+    {      9, 5}, {     19, 6}, {     17, 7}, {      9, 6}, \
+    {     20, 7}, {     11, 6}, {     23, 7}, {     13, 8}, \
+    {      7, 7}, {     19, 8}, {     11, 7}, {     25, 9}, \
+    {      7, 8}, {     15, 7}, {     33, 8}, {     19, 7}, \
+    {     39, 8}, {     23, 9}, {     15, 8}, {     39, 9}, \
+    {     23,10}, {     15, 9}, {     31, 8}, {     63, 9}, \
+    {     47,10}, {     31, 9}, {     63, 8}, {    127, 9}, \
+    {     71, 8}, {    143, 7}, {    287, 9}, {     79,10}, \
+    {     47,11}, {     31,10}, {     63, 9}, {    127, 8}, \
+    {    255, 9}, {    143, 8}, {    287,10}, {     79, 9}, \
+    {    159, 8}, {    319, 9}, {    175, 8}, {    351, 7}, \
+    {    703,10}, {     95, 9}, {    191, 8}, {    383, 9}, \
+    {    207, 8}, {    415, 9}, {    223,11}, {     63,10}, \
+    {    127, 9}, {    271,10}, {    143, 9}, {    287, 8}, \
+    {    575,10}, {    159, 9}, {    319,10}, {    175, 9}, \
+    {    351, 8}, {    703,11}, {     95,10}, {    191, 9}, \
+    {    383,10}, {    207, 9}, {    415, 8}, {    831,10}, \
+    {    223,12}, {     63,11}, {    127,10}, {    271, 9}, \
+    {    543,10}, {    287, 9}, {    575,11}, {    159,10}, \
+    {    319, 9}, {    639,10}, {    351, 9}, {    703, 8}, \
+    {   1407,11}, {    191,10}, {    415, 9}, {    831,11}, \
+    {    223,10}, {    447, 9}, {    895,10}, {    479,12}, \
+    {    127,11}, {    255,10}, {    543,11}, {    287,10}, \
+    {    575,11}, {    319,10}, {    639,11}, {    351,10}, \
+    {    703,12}, {    191,11}, {    415,10}, {    831,11}, \
+    {    447,10}, {    895, 9}, {   1791,13}, {    127,12}, \
+    {    255,11}, {    575,12}, {    319,11}, {    703,10}, \
+    {   1407,12}, {    383,11}, {    831,12}, {    447,11}, \
+    {    959,10}, {   1919, 9}, {   3839,13}, {    255,12}, \
+    {    575,11}, {   1151,12}, {    703,11}, {   1407,13}, \
+    {    383,12}, {    959,14}, {    255,13}, {    511,12}, \
+    {   1215,11}, {   2431,13}, {    639,12}, {   1407,13}, \
+    {    767,12}, {   1599,13}, {    895,12}, {   1919,14}, \
+    {    511,13}, {   1151,12}, {   2431,13}, {   1407,12}, \
+    {   2815,14}, {    767,13}, {   1535,12}, {   3071,13}, \
+    {   1919,15}, {    511,14}, {   1023,13}, {   2431,14}, \
+    {   1279,13}, {   2943,12}, {   5887,14}, {  16384,15}, \
+    {  32768,16} }
+#define SQR_FFT_TABLE3_SIZE 153
+#define SQR_FFT_THRESHOLD                 2112
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                 144
+#define MULLO_MUL_N_THRESHOLD             4292
+
+#define DC_DIV_QR_THRESHOLD                 74
+#define DC_DIVAPPR_Q_THRESHOLD             406
+#define DC_BDIV_QR_THRESHOLD                63
+#define DC_BDIV_Q_THRESHOLD                363
+
+#define INV_MULMOD_BNM1_THRESHOLD          108
+#define INV_NEWTON_THRESHOLD               351
+#define INV_APPR_THRESHOLD                 303
+
+#define BINV_NEWTON_THRESHOLD              354
+#define REDC_1_TO_REDC_N_THRESHOLD          61
+
+#define MU_DIV_QR_THRESHOLD                998
+#define MU_DIVAPPR_Q_THRESHOLD            1099
+#define MUPI_DIV_QR_THRESHOLD              118
+#define MU_BDIV_QR_THRESHOLD               807
+#define MU_BDIV_Q_THRESHOLD                979
+
+#define POWM_SEC_TABLE  3,22,127,624,779,2351
+
+#define MATRIX22_STRASSEN_THRESHOLD          7
+#define HGCD_THRESHOLD                      90
+#define HGCD_APPR_THRESHOLD                123
+#define HGCD_REDUCE_THRESHOLD             1494
+#define GCD_DC_THRESHOLD                   283
+#define GCDEXT_DC_THRESHOLD                192
+#define JACOBI_BASE_METHOD                   4
+
+#define GET_STR_DC_THRESHOLD                12
+#define GET_STR_PRECOMPUTE_THRESHOLD        27
+#define SET_STR_DC_THRESHOLD               290
+#define SET_STR_PRECOMPUTE_THRESHOLD       634
+
+#define FAC_DSC_THRESHOLD                  156
+#define FAC_ODD_THRESHOLD                   25
diff --git a/third_party/gmp/mpn/sparc32/v9/mul_1.asm b/third_party/gmp/mpn/sparc32/v9/mul_1.asm
new file mode 100644
index 0000000..40aeffa
--- /dev/null
+++ b/third_party/gmp/mpn/sparc32/v9/mul_1.asm
@@ -0,0 +1,287 @@
+dnl  SPARC v9 32-bit mpn_mul_1 -- Multiply a limb vector with a limb and store
+dnl  the result in a second limb vector.
+
+dnl  Copyright 1998, 2000, 2001, 2003 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C Algorithm: We use two floating-point multiplies per limb product, with the
+C invariant v operand split into two 16-bit pieces, and the u operand split
+C into 32-bit pieces.  We convert the two 48-bit products and transfer them to
+C the integer unit.
+
+C		   cycles/limb
+C UltraSPARC 1&2:     6.5
+C UltraSPARC 3:	      ?
+
+C Possible optimizations:
+C   1. Combine 32-bit memory operations into 64-bit operations.  Since we're
+C      memory bandwidth limited, this could save 1.5 cycles/limb.
+C   2. Unroll the inner loop.  Since we already use alternate temporary areas,
+C      it is very straightforward to unroll, using an exit branch midways.
+C      Unrolling would allow deeper scheduling which could improve speed for L2
+C      cache case.
+C   3. For mpn_mul_1: Use more alternating temp areas.  The std'es and ldx'es
+C      aren't sufficiently apart-scheduled with just two temp areas.
+C   4. Specialize for particular v values.  If its upper 16 bits are zero, we
+C      could save many operations.
+
+C INPUT PARAMETERS
+C rp	i0
+C up	i1
+C n	i2
+C v	i3
+
+define(`FSIZE',224)
+
+ASM_START()
+PROLOGUE(mpn_mul_1)
+	add	%sp, -FSIZE, %sp
+	sethi	%hi(0xffff), %g1
+	srl	%o3, 16, %g2
+	or	%g1, %lo(0xffff), %g1
+	and	%o3, %g1, %g1
+	stx	%g1, [%sp+104]
+	stx	%g2, [%sp+112]
+	ldd	[%sp+104], %f6
+	ldd	[%sp+112], %f8
+	fxtod	%f6, %f6
+	fxtod	%f8, %f8
+	ld	[%sp+104], %f10		C zero f10
+
+	mov	0, %g3			C cy = 0
+
+define(`fanop', `fitod %f18, %f0')	C  A quasi nop running in the FA pipe
+
+	add	%sp, 160, %o5		C point in scratch area
+	and	%o5, -32, %o5		C align at 0 (mod 32) in scratch area
+
+	subcc	%o2, 1, %o2
+	ld	[%o1], %f11		C read up[i]
+	add	%o1, 4, %o1		C up++
+	bne,pt	%icc, .L_two_or_more
+	fxtod	%f10, %f2
+
+	fmuld	%f2, %f8, %f16
+	fmuld	%f2, %f6, %f4
+	fdtox	%f16, %f14
+	fdtox	%f4, %f12
+	std	%f14, [%o5+16]
+	std	%f12, [%o5+24]
+	ldx	[%o5+16], %g2		C p16
+	ldx	[%o5+24], %g1		C p0
+	b	.L1
+	add	%o0, -16, %o0
+
+	.align	16
+.L_two_or_more:
+	subcc	%o2, 1, %o2
+	ld	[%o1], %f11		C read up[i]
+	fmuld	%f2, %f8, %f16
+	fmuld	%f2, %f6, %f4
+	add	%o1, 4, %o1		C up++
+	bne,pt	%icc, .L_three_or_more
+	fxtod	%f10, %f2
+
+	fdtox	%f16, %f14
+	fdtox	%f4, %f12
+	std	%f14, [%o5+16]
+	fmuld	%f2, %f8, %f16
+	std	%f12, [%o5+24]
+	fmuld	%f2, %f6, %f4
+	fdtox	%f16, %f14
+	fdtox	%f4, %f12
+	std	%f14, [%o5+0]
+	std	%f12, [%o5+8]
+	ldx	[%o5+16], %g2		C p16
+	ldx	[%o5+24], %g1		C p0
+	b	.L2
+	add	%o0, -12, %o0
+
+	.align	16
+.L_three_or_more:
+	subcc	%o2, 1, %o2
+	ld	[%o1], %f11		C read up[i]
+	fdtox	%f16, %f14
+	fdtox	%f4, %f12
+	std	%f14, [%o5+16]
+	fmuld	%f2, %f8, %f16
+	std	%f12, [%o5+24]
+	fmuld	%f2, %f6, %f4
+	add	%o1, 4, %o1		C up++
+	bne,pt	%icc, .L_four_or_more
+	fxtod	%f10, %f2
+
+	fdtox	%f16, %f14
+	fdtox	%f4, %f12
+	std	%f14, [%o5+0]
+	fmuld	%f2, %f8, %f16
+	std	%f12, [%o5+8]
+	fmuld	%f2, %f6, %f4
+	fdtox	%f16, %f14
+	ldx	[%o5+16], %g2		C p16
+	fdtox	%f4, %f12
+	ldx	[%o5+24], %g1		C p0
+	std	%f14, [%o5+16]
+	std	%f12, [%o5+24]
+	b	.L3
+	add	%o0, -8, %o0
+
+	.align	16
+.L_four_or_more:
+	subcc	%o2, 1, %o2
+	ld	[%o1], %f11		C read up[i]
+	fdtox	%f16, %f14
+	fdtox	%f4, %f12
+	std	%f14, [%o5+0]
+	fmuld	%f2, %f8, %f16
+	std	%f12, [%o5+8]
+	fmuld	%f2, %f6, %f4
+	add	%o1, 4, %o1		C up++
+	bne,pt	%icc, .L_five_or_more
+	fxtod	%f10, %f2
+
+	fdtox	%f16, %f14
+	ldx	[%o5+16], %g2		C p16
+	fdtox	%f4, %f12
+	ldx	[%o5+24], %g1		C p0
+	std	%f14, [%o5+16]
+	fmuld	%f2, %f8, %f16
+	std	%f12, [%o5+24]
+	fmuld	%f2, %f6, %f4
+	add	%o1, 4, %o1		C up++
+	b	.L4
+	add	%o0, -4, %o0
+
+	.align	16
+.L_five_or_more:
+	subcc	%o2, 1, %o2
+	ld	[%o1], %f11		C read up[i]
+	fdtox	%f16, %f14
+	ldx	[%o5+16], %g2		C p16
+	fdtox	%f4, %f12
+	ldx	[%o5+24], %g1		C p0
+	std	%f14, [%o5+16]
+	fmuld	%f2, %f8, %f16
+	std	%f12, [%o5+24]
+	fmuld	%f2, %f6, %f4
+	add	%o1, 4, %o1		C up++
+	bne,pt	%icc, .Loop
+	fxtod	%f10, %f2
+	b,a	.L5
+
+C BEGIN MAIN LOOP
+	.align 16
+C -- 0
+.Loop:	nop
+	subcc	%o2, 1, %o2
+	ld	[%o1], %f11		C read up[i]
+	fdtox	%f16, %f14
+C -- 1
+	sllx	%g2, 16, %g4		C (p16 << 16)
+	add	%o0, 4, %o0		C rp++
+	ldx	[%o5+0], %g2		C p16
+	fdtox	%f4, %f12
+C -- 2
+	nop
+	add	%g1, %g4, %g4		C p = p0 + (p16 << 16)
+	ldx	[%o5+8], %g1		C p0
+	fanop
+C -- 3
+	nop
+	add	%g3, %g4, %g4		C p += cy
+	std	%f14, [%o5+0]
+	fmuld	%f2, %f8, %f16
+C -- 4
+	srlx	%g4, 32, %g3		C new cy
+	add	%o1, 4, %o1		C up++
+	std	%f12, [%o5+8]
+	fmuld	%f2, %f6, %f4
+C -- 5
+	xor	%o5, 16, %o5		C alternate scratch variables
+	stw	%g4, [%o0-4]
+	bne,pt	%icc, .Loop
+	fxtod	%f10, %f2
+C END MAIN LOOP
+
+.L5:	fdtox	%f16, %f14
+	sllx	%g2, 16, %g4		C (p16 << 16)
+	ldx	[%o5+0], %g2		C p16
+	fdtox	%f4, %f12
+	add	%g1, %g4, %g4		C p = p0 + (p16 << 16)
+	ldx	[%o5+8], %g1		C p0
+	add	%g4, %g3, %g4		C p += cy
+	std	%f14, [%o5+0]
+	fmuld	%f2, %f8, %f16
+	std	%f12, [%o5+8]
+	fmuld	%f2, %f6, %f4
+	xor	%o5, 16, %o5
+	stw	%g4, [%o0+0]
+	srlx	%g4, 32, %g3		C new cy
+
+.L4:	fdtox	%f16, %f14
+	sllx	%g2, 16, %g4		C (p16 << 16)
+	ldx	[%o5+0], %g2		C p16
+	fdtox	%f4, %f12
+	add	%g1, %g4, %g4		C p = p0 + (p16 << 16)
+	ldx	[%o5+8], %g1		C p0
+	add	%g3, %g4, %g4		C p += cy
+	std	%f14, [%o5+0]
+	std	%f12, [%o5+8]
+	xor	%o5, 16, %o5
+	stw	%g4, [%o0+4]
+	srlx	%g4, 32, %g3		C new cy
+
+.L3:	sllx	%g2, 16, %g4		C (p16 << 16)
+	ldx	[%o5+0], %g2		C p16
+	add	%g1, %g4, %g4		C p = p0 + (p16 << 16)
+	ldx	[%o5+8], %g1		C p0
+	add	%g3, %g4, %g4		C p += cy
+	xor	%o5, 16, %o5
+	stw	%g4, [%o0+8]
+	srlx	%g4, 32, %g3		C new cy
+
+.L2:	sllx	%g2, 16, %g4		C (p16 << 16)
+	ldx	[%o5+0], %g2		C p16
+	add	%g1, %g4, %g4		C p = p0 + (p16 << 16)
+	ldx	[%o5+8], %g1		C p0
+	add	%g3, %g4, %g4		C p += cy
+	stw	%g4, [%o0+12]
+	srlx	%g4, 32, %g3		C new cy
+
+.L1:	sllx	%g2, 16, %g4		C (p16 << 16)
+	add	%g1, %g4, %g4		C p = p0 + (p16 << 16)
+	add	%g3, %g4, %g4		C p += cy
+	stw	%g4, [%o0+16]
+	srlx	%g4, 32, %g3		C new cy
+
+	mov	%g3, %o0
+	retl
+	sub	%sp, -FSIZE, %sp
+EPILOGUE(mpn_mul_1)
diff --git a/third_party/gmp/mpn/sparc32/v9/sqr_diagonal.asm b/third_party/gmp/mpn/sparc32/v9/sqr_diagonal.asm
new file mode 100644
index 0000000..e024279
--- /dev/null
+++ b/third_party/gmp/mpn/sparc32/v9/sqr_diagonal.asm
@@ -0,0 +1,462 @@
+dnl  SPARC v9 32-bit mpn_sqr_diagonal.
+
+dnl  Copyright 2001, 2003 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C rp	i0
+C up	i1
+C n	i2
+
+C This code uses a very deep software pipeline, due to the need for moving data
+C forth and back between the integer registers and floating-point registers.
+C
+C A VIS variant of this code would make the pipeline less deep, since the
+C masking now done in the integer unit could take place in the floating-point
+C unit using the FAND instruction.  It would be possible to save several cycles
+C too.
+C
+C On UltraSPARC 1 and 2, this code runs at 11 cycles/limb from the Dcache and
+C not much slower from the Ecache.  It would perhaps be possible to shave off
+C one cycle, but not easily.  We cannot do better than 10 cycles/limb with the
+C used instructions, since we have 10 memory operations per limb.  But a VIS
+C variant could run three cycles faster than the corresponding non-VIS code.
+
+C This is non-pipelined code showing the algorithm:
+C
+C .Loop:
+C	lduw	[up+0],%g4		C 00000000hhhhllll
+C	sllx	%g4,16,%g3		C 0000hhhhllll0000
+C	or	%g3,%g4,%g2		C 0000hhhhXXXXllll
+C	andn	%g2,%g5,%g2		C 0000hhhh0000llll
+C	stx	%g2,[%fp+80]
+C	ldd	[%fp+80],%f0
+C	fitod	%f0,%f4			C hi16
+C	fitod	%f1,%f6			C lo16
+C	ld	[up+0],%f9
+C	fxtod	%f8,%f2
+C	fmuld	%f2,%f4,%f4
+C	fmuld	%f2,%f6,%f6
+C	fdtox	%f4,%f4
+C	fdtox	%f6,%f6
+C	std	%f4,[%fp-24]
+C	std	%f6,[%fp-16]
+C	ldx	[%fp-24],%g2
+C	ldx	[%fp-16],%g1
+C	sllx	%g2,16,%g2
+C	add	%g2,%g1,%g1
+C	stw	%g1,[rp+0]
+C	srlx	%g1,32,%l0
+C	stw	%l0,[rp+4]
+C	add	up,4,up
+C	subcc	n,1,n
+C	bne,pt	%icc,.Loop
+C	add	rp,8,rp
+
+define(`fanop',`fitod %f12,%f10')	dnl  A quasi nop running in the FA pipe
+
+ASM_START()
+
+	TEXT
+	ALIGN(4)
+.Lnoll:
+	.word	0
+
+PROLOGUE(mpn_sqr_diagonal)
+	save	%sp,-256,%sp
+
+ifdef(`PIC',
+`.Lpc:	rd	%pc,%o7
+	ld	[%o7+.Lnoll-.Lpc],%f8',
+`	sethi	%hi(.Lnoll),%g1
+	ld	[%g1+%lo(.Lnoll)],%f8')
+
+	sethi	%hi(0xffff0000),%g5
+	add	%i1,-8,%i1
+
+	lduw	[%i1+8],%g4
+	add	%i1,4,%i1		C s1_ptr++
+	sllx	%g4,16,%g3		C 0000hhhhllll0000
+	or	%g3,%g4,%g2		C 0000hhhhXXXXllll
+	subcc	%i2,1,%i2
+	bne,pt	%icc,.L_grt_1
+	andn	%g2,%g5,%g2		C 0000hhhh0000llll
+
+	add	%i1,4,%i1		C s1_ptr++
+	stx	%g2,[%fp+80]
+	ld	[%i1],%f9
+	ldd	[%fp+80],%f0
+	fxtod	%f8,%f2
+	fitod	%f0,%f4
+	fitod	%f1,%f6
+	fmuld	%f2,%f4,%f4
+	fmuld	%f2,%f6,%f6
+	fdtox	%f4,%f4
+	fdtox	%f6,%f6
+	std	%f4,[%fp-24]
+	std	%f6,[%fp-16]
+
+	add	%fp, 80, %l3
+	add	%fp, -24, %l4
+	add	%fp, 72, %l5
+	b	.L1
+	add	%fp, -40, %l6
+
+.L_grt_1:
+	stx	%g2,[%fp+80]
+	lduw	[%i1+8],%g4
+	add	%i1,4,%i1		C s1_ptr++
+	sllx	%g4,16,%g3		C 0000hhhhllll0000
+	or	%g3,%g4,%g2		C 0000hhhhXXXXllll
+	subcc	%i2,1,%i2
+	bne,pt	%icc,.L_grt_2
+	andn	%g2,%g5,%g2		C 0000hhhh0000llll
+
+	stx	%g2,[%fp+72]
+	ld	[%i1],%f9
+	add	%i1,4,%i1		C s1_ptr++
+	ldd	[%fp+80],%f0
+	fxtod	%f8,%f2
+	fitod	%f0,%f4
+	fitod	%f1,%f6
+	fmuld	%f2,%f4,%f4
+	ld	[%i1],%f9
+	fmuld	%f2,%f6,%f6
+	ldd	[%fp+72],%f0
+	fdtox	%f4,%f4
+	fdtox	%f6,%f6
+	std	%f4,[%fp-24]
+	fxtod	%f8,%f2
+	std	%f6,[%fp-16]
+	fitod	%f0,%f4
+	fitod	%f1,%f6
+	fmuld	%f2,%f4,%f4
+	fmuld	%f2,%f6,%f6
+	fdtox	%f4,%f4
+
+	add	%fp, 72, %l3
+	add	%fp, -40, %l4
+	add	%fp, 80, %l5
+	b	.L2
+	add	%fp, -24, %l6
+
+.L_grt_2:
+	stx	%g2,[%fp+72]
+	lduw	[%i1+8],%g4
+	ld	[%i1],%f9
+	add	%i1,4,%i1		C s1_ptr++
+	ldd	[%fp+80],%f0
+	sllx	%g4,16,%g3		C 0000hhhhllll0000
+	or	%g3,%g4,%g2		C 0000hhhhXXXXllll
+	subcc	%i2,1,%i2
+	fxtod	%f8,%f2
+	bne,pt	%icc,.L_grt_3
+	andn	%g2,%g5,%g2		C 0000hhhh0000llll
+
+	stx	%g2,[%fp+80]
+	fitod	%f0,%f4
+	fitod	%f1,%f6
+	fmuld	%f2,%f4,%f4
+	ld	[%i1],%f9
+	fmuld	%f2,%f6,%f6
+	add	%i1,4,%i1		C s1_ptr++
+	ldd	[%fp+72],%f0
+	fdtox	%f4,%f4
+	fdtox	%f6,%f6
+	std	%f4,[%fp-24]
+	fxtod	%f8,%f2
+	std	%f6,[%fp-16]
+	fitod	%f0,%f4
+	fitod	%f1,%f6
+	fmuld	%f2,%f4,%f4
+	ld	[%i1],%f9
+	add	%fp, 80, %l3
+	fmuld	%f2,%f6,%f6
+	add	%fp, -24, %l4
+	ldd	[%fp+80],%f0
+	add	%fp, 72, %l5
+	fdtox	%f4,%f4
+	b	.L3
+	add	%fp, -40, %l6
+
+.L_grt_3:
+	stx	%g2,[%fp+80]
+	fitod	%f0,%f4
+	lduw	[%i1+8],%g4
+	fitod	%f1,%f6
+	fmuld	%f2,%f4,%f4
+	ld	[%i1],%f9
+	fmuld	%f2,%f6,%f6
+	add	%i1,4,%i1		C s1_ptr++
+	ldd	[%fp+72],%f0
+	fdtox	%f4,%f4
+	sllx	%g4,16,%g3		C 0000hhhhllll0000
+	fdtox	%f6,%f6
+	or	%g3,%g4,%g2		C 0000hhhhXXXXllll
+	subcc	%i2,1,%i2
+	std	%f4,[%fp-24]
+	fxtod	%f8,%f2
+	std	%f6,[%fp-16]
+	bne,pt	%icc,.L_grt_4
+	andn	%g2,%g5,%g2		C 0000hhhh0000llll
+
+	stx	%g2,[%fp+72]
+	fitod	%f0,%f4
+	fitod	%f1,%f6
+	add	%fp, 72, %l3
+	fmuld	%f2,%f4,%f4
+	add	%fp, -40, %l4
+	ld	[%i1],%f9
+	fmuld	%f2,%f6,%f6
+	add	%i1,4,%i1		C s1_ptr++
+	ldd	[%fp+80],%f0
+	add	%fp, 80, %l5
+	fdtox	%f4,%f4
+	b	.L4
+	add	%fp, -24, %l6
+
+.L_grt_4:
+	stx	%g2,[%fp+72]
+	fitod	%f0,%f4
+	lduw	[%i1+8],%g4
+	fitod	%f1,%f6
+	fmuld	%f2,%f4,%f4
+	ld	[%i1],%f9
+	fmuld	%f2,%f6,%f6
+	add	%i1,4,%i1		C s1_ptr++
+	ldd	[%fp+80],%f0
+	fdtox	%f4,%f4
+	sllx	%g4,16,%g3		C 0000hhhhllll0000
+	fdtox	%f6,%f6
+	or	%g3,%g4,%g2		C 0000hhhhXXXXllll
+	subcc	%i2,1,%i2
+	std	%f4,[%fp-40]
+	fxtod	%f8,%f2
+	std	%f6,[%fp-32]
+	be,pn	%icc,.L5
+	andn	%g2,%g5,%g2		C 0000hhhh0000llll
+
+	b,a	.Loop
+
+	.align	16
+C --- LOOP BEGIN
+.Loop:	nop
+	nop
+	stx	%g2,[%fp+80]
+	fitod	%f0,%f4
+C ---
+	nop
+	nop
+	lduw	[%i1+8],%g4
+	fitod	%f1,%f6
+C ---
+	nop
+	nop
+	ldx	[%fp-24],%g2		C p16
+	fanop
+C ---
+	nop
+	nop
+	ldx	[%fp-16],%g1		C p0
+	fmuld	%f2,%f4,%f4
+C ---
+	sllx	%g2,16,%g2		C align p16
+	add	%i0,8,%i0		C res_ptr++
+	ld	[%i1],%f9
+	fmuld	%f2,%f6,%f6
+C ---
+	add	%g2,%g1,%g1		C add p16 to p0 (ADD1)
+	add	%i1,4,%i1		C s1_ptr++
+	ldd	[%fp+72],%f0
+	fanop
+C ---
+	srlx	%g1,32,%l0
+	nop
+	stw	%g1,[%i0-8]
+	fdtox	%f4,%f4
+C ---
+	sllx	%g4,16,%g3		C 0000hhhhllll0000
+	nop
+	stw	%l0,[%i0-4]
+	fdtox	%f6,%f6
+C ---
+	or	%g3,%g4,%g2		C 0000hhhhXXXXllll
+	subcc	%i2,1,%i2
+	std	%f4,[%fp-24]
+	fxtod	%f8,%f2
+C ---
+	std	%f6,[%fp-16]
+	andn	%g2,%g5,%g2		C 0000hhhh0000llll
+	be,pn	%icc,.Lend
+	fanop
+C ---  LOOP MIDDLE
+	nop
+	nop
+	stx	%g2,[%fp+72]
+	fitod	%f0,%f4
+C ---
+	nop
+	nop
+	lduw	[%i1+8],%g4
+	fitod	%f1,%f6
+C ---
+	nop
+	nop
+	ldx	[%fp-40],%g2		C p16
+	fanop
+C ---
+	nop
+	nop
+	ldx	[%fp-32],%g1		C p0
+	fmuld	%f2,%f4,%f4
+C ---
+	sllx	%g2,16,%g2		C align p16
+	add	%i0,8,%i0		C res_ptr++
+	ld	[%i1],%f9
+	fmuld	%f2,%f6,%f6
+C ---
+	add	%g2,%g1,%g1		C add p16 to p0 (ADD1)
+	add	%i1,4,%i1		C s1_ptr++
+	ldd	[%fp+80],%f0
+	fanop
+C ---
+	srlx	%g1,32,%l0
+	nop
+	stw	%g1,[%i0-8]
+	fdtox	%f4,%f4
+C ---
+	sllx	%g4,16,%g3		C 0000hhhhllll0000
+	nop
+	stw	%l0,[%i0-4]
+	fdtox	%f6,%f6
+C ---
+	or	%g3,%g4,%g2		C 0000hhhhXXXXllll
+	subcc	%i2,1,%i2
+	std	%f4,[%fp-40]
+	fxtod	%f8,%f2
+C ---
+	std	%f6,[%fp-32]
+	andn	%g2,%g5,%g2		C 0000hhhh0000llll
+	bne,pt	%icc,.Loop
+	fanop
+C --- LOOP END
+
+.L5:	add	%fp, 80, %l3
+	add	%fp, -24, %l4
+	add	%fp, 72, %l5
+	b	.Ltail
+	add	%fp, -40, %l6
+
+.Lend:	add	%fp, 72, %l3
+	add	%fp, -40, %l4
+	add	%fp, 80, %l5
+	add	%fp, -24, %l6
+.Ltail:	stx	%g2,[%l3]
+	fitod	%f0,%f4
+	fitod	%f1,%f6
+	ldx	[%l4],%g2		C p16
+	ldx	[%l4+8],%g1		C p0
+	fmuld	%f2,%f4,%f4
+	sllx	%g2,16,%g2		C align p16
+	add	%i0,8,%i0		C res_ptr++
+	ld	[%i1],%f9
+	fmuld	%f2,%f6,%f6
+	add	%g2,%g1,%g1		C add p16 to p0 (ADD1)
+	add	%i1,4,%i1		C s1_ptr++
+	ldd	[%l5],%f0
+	srlx	%g1,32,%l0
+	stw	%g1,[%i0-8]
+	fdtox	%f4,%f4
+	stw	%l0,[%i0-4]
+.L4:	fdtox	%f6,%f6
+	std	%f4,[%l4]
+	fxtod	%f8,%f2
+	std	%f6,[%l4+8]
+
+	fitod	%f0,%f4
+	fitod	%f1,%f6
+	ldx	[%l6],%g2		C p16
+	ldx	[%l6+8],%g1		C p0
+	fmuld	%f2,%f4,%f4
+	sllx	%g2,16,%g2		C align p16
+	add	%i0,8,%i0		C res_ptr++
+	ld	[%i1],%f9
+	fmuld	%f2,%f6,%f6
+	add	%g2,%g1,%g1		C add p16 to p0 (ADD1)
+	ldd	[%l3],%f0
+	srlx	%g1,32,%l0
+	stw	%g1,[%i0-8]
+	fdtox	%f4,%f4
+	stw	%l0,[%i0-4]
+.L3:	fdtox	%f6,%f6
+	std	%f4,[%l6]
+	fxtod	%f8,%f2
+	std	%f6,[%l6+8]
+
+	fitod	%f0,%f4
+	fitod	%f1,%f6
+	ldx	[%l4],%g2		C p16
+	ldx	[%l4+8],%g1		C p0
+	fmuld	%f2,%f4,%f4
+	sllx	%g2,16,%g2		C align p16
+	add	%i0,8,%i0		C res_ptr++
+	fmuld	%f2,%f6,%f6
+	add	%g2,%g1,%g1		C add p16 to p0 (ADD1)
+	srlx	%g1,32,%l0
+	stw	%g1,[%i0-8]
+	fdtox	%f4,%f4
+	stw	%l0,[%i0-4]
+.L2:	fdtox	%f6,%f6
+	std	%f4,[%l4]
+	std	%f6,[%l4+8]
+
+	ldx	[%l6],%g2		C p16
+	ldx	[%l6+8],%g1		C p0
+	sllx	%g2,16,%g2		C align p16
+	add	%i0,8,%i0		C res_ptr++
+	add	%g2,%g1,%g1		C add p16 to p0 (ADD1)
+	srlx	%g1,32,%l0
+	stw	%g1,[%i0-8]
+	stw	%l0,[%i0-4]
+
+.L1:	ldx	[%l4],%g2		C p16
+	ldx	[%l4+8],%g1		C p0
+	sllx	%g2,16,%g2		C align p16
+	add	%i0,8,%i0		C res_ptr++
+	add	%g2,%g1,%g1		C add p16 to p0 (ADD1)
+	srlx	%g1,32,%l0
+	stw	%g1,[%i0-8]
+	stw	%l0,[%i0-4]
+
+	ret
+	restore	%g0,%g0,%o0
+
+EPILOGUE(mpn_sqr_diagonal)
diff --git a/third_party/gmp/mpn/sparc32/v9/sub_n.asm b/third_party/gmp/mpn/sparc32/v9/sub_n.asm
new file mode 100644
index 0000000..636c73b
--- /dev/null
+++ b/third_party/gmp/mpn/sparc32/v9/sub_n.asm
@@ -0,0 +1,129 @@
+dnl  SPARC mpn_sub_n -- Subtract two limb vectors of the same length > 0 and
+dnl  store difference in a third limb vector.
+
+dnl  Copyright 2001 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+define(rp,%o0)
+define(s1p,%o1)
+define(s2p,%o2)
+define(n,%o3)
+define(cy,%g1)
+
+C This code uses 64-bit operations on `o' and `g' registers.  It doesn't
+C require that `o' registers' upper 32 bits are preserved by the operating
+C system, but if they are not, they must be zeroed.  That is indeed what
+C happens at least on Slowaris 2.5 and 2.6.
+
+C On UltraSPARC 1 and 2, this code runs at 3 cycles/limb from the Dcache and at
+C about 10 cycles/limb from the Ecache.
+
+ASM_START()
+PROLOGUE(mpn_sub_n)
+	lduw	[s1p+0],%o4
+	lduw	[s2p+0],%o5
+	addcc	n,-2,n
+	bl,pn	%icc,L(end1)
+	lduw	[s1p+4],%g2
+	lduw	[s2p+4],%g3
+	be,pn	%icc,L(end2)
+	mov	0,cy
+
+	.align	16
+L(loop):
+	sub	%o4,%o5,%g4
+	add	rp,8,rp
+	lduw	[s1p+8],%o4
+	fitod	%f0,%f2
+C ---
+	sub	%g4,cy,%g4
+	addcc	n,-1,n
+	lduw	[s2p+8],%o5
+	fitod	%f0,%f2
+C ---
+	srlx	%g4,63,cy
+	add	s2p,8,s2p
+	stw	%g4,[rp-8]
+	be,pn	%icc,L(exito)+4
+C ---
+	sub	%g2,%g3,%g4
+	addcc	n,-1,n
+	lduw	[s1p+12],%g2
+	fitod	%f0,%f2
+C ---
+	sub	%g4,cy,%g4
+	add	s1p,8,s1p
+	lduw	[s2p+4],%g3
+	fitod	%f0,%f2
+C ---
+	srlx	%g4,63,cy
+	bne,pt	%icc,L(loop)
+	stw	%g4,[rp-4]
+C ---
+L(exite):
+	sub	%o4,%o5,%g4
+	sub	%g4,cy,%g4
+	srlx	%g4,63,cy
+	stw	%g4,[rp+0]
+	sub	%g2,%g3,%g4
+	sub	%g4,cy,%g4
+	stw	%g4,[rp+4]
+	retl
+	srlx	%g4,63,%o0
+
+L(exito):
+	sub	%g2,%g3,%g4
+	sub	%g4,cy,%g4
+	srlx	%g4,63,cy
+	stw	%g4,[rp-4]
+	sub	%o4,%o5,%g4
+	sub	%g4,cy,%g4
+	stw	%g4,[rp+0]
+	retl
+	srlx	%g4,63,%o0
+
+L(end1):
+	sub	%o4,%o5,%g4
+	stw	%g4,[rp+0]
+	retl
+	srlx	%g4,63,%o0
+
+L(end2):
+	sub	%o4,%o5,%g4
+	srlx	%g4,63,cy
+	stw	%g4,[rp+0]
+	sub	%g2,%g3,%g4
+	sub	%g4,cy,%g4
+	stw	%g4,[rp+4]
+	retl
+	srlx	%g4,63,%o0
+EPILOGUE(mpn_sub_n)
diff --git a/third_party/gmp/mpn/sparc32/v9/submul_1.asm b/third_party/gmp/mpn/sparc32/v9/submul_1.asm
new file mode 100644
index 0000000..92d0ce7
--- /dev/null
+++ b/third_party/gmp/mpn/sparc32/v9/submul_1.asm
@@ -0,0 +1,316 @@
+dnl  SPARC v9 32-bit mpn_submul_1 -- Multiply a limb vector with a limb and
+dnl  subtract the result from a second limb vector.
+
+dnl  Copyright 1998, 2000, 2001, 2003 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C Algorithm: We use two floating-point multiplies per limb product, with the
+C invariant v operand split into two 16-bit pieces, and the u operand split
+C into 32-bit pieces.  We convert the two 48-bit products and transfer them to
+C the integer unit.
+
+C		   cycles/limb
+C UltraSPARC 1&2:     6.5
+C UltraSPARC 3:	      ?
+
+C Possible optimizations:
+C   1. Combine 32-bit memory operations into 64-bit operations.  Since we're
+C      memory bandwidth limited, this could save 1.5 cycles/limb.
+C   2. Unroll the inner loop.  Since we already use alternate temporary areas,
+C      it is very straightforward to unroll, using an exit branch midways.
+C      Unrolling would allow deeper scheduling which could improve speed for L2
+C      cache case.
+C   3. For mpn_mul_1: Use more alternating temp areas.  The std'es and ldx'es
+C      aren't sufficiently apart-scheduled with just two temp areas.
+C   4. Specialize for particular v values.  If its upper 16 bits are zero, we
+C      could save many operations.
+
+C INPUT PARAMETERS
+C rp	i0
+C up	i1
+C n	i2
+C v	i3
+
+define(`FSIZE',224)
+
+ASM_START()
+PROLOGUE(mpn_submul_1)
+	add	%sp, -FSIZE, %sp
+	sethi	%hi(0xffff), %g1
+	srl	%o3, 16, %g2
+	or	%g1, %lo(0xffff), %g1
+	and	%o3, %g1, %g1
+	stx	%g1, [%sp+104]
+	stx	%g2, [%sp+112]
+	ldd	[%sp+104], %f6
+	ldd	[%sp+112], %f8
+	fxtod	%f6, %f6
+	fxtod	%f8, %f8
+	ld	[%sp+104], %f10		C zero f10
+
+	mov	0, %g3			C cy = 0
+
+define(`fanop', `fitod %f18, %f0')	C  A quasi nop running in the FA pipe
+
+	add	%sp, 160, %o5		C point in scratch area
+	and	%o5, -32, %o5		C align at 0 (mod 32) in scratch area
+
+	subcc	%o2, 1, %o2
+	ld	[%o1], %f11		C read up[i]
+	add	%o1, 4, %o1		C up++
+	bne,pt	%icc, .L_two_or_more
+	fxtod	%f10, %f2
+
+	fmuld	%f2, %f8, %f16
+	fmuld	%f2, %f6, %f4
+	fdtox	%f16, %f14
+	fdtox	%f4, %f12
+	std	%f14, [%o5+16]
+	std	%f12, [%o5+24]
+	ldx	[%o5+16], %g2		C p16
+	ldx	[%o5+24], %g1		C p0
+	lduw	[%o0], %g5		C read rp[i]
+	b	.L1
+	add	%o0, -16, %o0
+
+	.align	16
+.L_two_or_more:
+	subcc	%o2, 1, %o2
+	ld	[%o1], %f11		C read up[i]
+	fmuld	%f2, %f8, %f16
+	fmuld	%f2, %f6, %f4
+	add	%o1, 4, %o1		C up++
+	bne,pt	%icc, .L_three_or_more
+	fxtod	%f10, %f2
+
+	fdtox	%f16, %f14
+	fdtox	%f4, %f12
+	std	%f14, [%o5+16]
+	fmuld	%f2, %f8, %f16
+	std	%f12, [%o5+24]
+	fmuld	%f2, %f6, %f4
+	fdtox	%f16, %f14
+	fdtox	%f4, %f12
+	std	%f14, [%o5+0]
+	std	%f12, [%o5+8]
+	lduw	[%o0], %g5		C read rp[i]
+	ldx	[%o5+16], %g2		C p16
+	ldx	[%o5+24], %g1		C p0
+	b	.L2
+	add	%o0, -12, %o0
+
+	.align	16
+.L_three_or_more:
+	subcc	%o2, 1, %o2
+	ld	[%o1], %f11		C read up[i]
+	fdtox	%f16, %f14
+	fdtox	%f4, %f12
+	std	%f14, [%o5+16]
+	fmuld	%f2, %f8, %f16
+	std	%f12, [%o5+24]
+	fmuld	%f2, %f6, %f4
+	add	%o1, 4, %o1		C up++
+	bne,pt	%icc, .L_four_or_more
+	fxtod	%f10, %f2
+
+	fdtox	%f16, %f14
+	fdtox	%f4, %f12
+	std	%f14, [%o5+0]
+	fmuld	%f2, %f8, %f16
+	std	%f12, [%o5+8]
+	fmuld	%f2, %f6, %f4
+	fdtox	%f16, %f14
+	ldx	[%o5+16], %g2		C p16
+	fdtox	%f4, %f12
+	ldx	[%o5+24], %g1		C p0
+	std	%f14, [%o5+16]
+	std	%f12, [%o5+24]
+	lduw	[%o0], %g5		C read rp[i]
+	b	.L3
+	add	%o0, -8, %o0
+
+	.align	16
+.L_four_or_more:
+	subcc	%o2, 1, %o2
+	ld	[%o1], %f11		C read up[i]
+	fdtox	%f16, %f14
+	fdtox	%f4, %f12
+	std	%f14, [%o5+0]
+	fmuld	%f2, %f8, %f16
+	std	%f12, [%o5+8]
+	fmuld	%f2, %f6, %f4
+	add	%o1, 4, %o1		C up++
+	bne,pt	%icc, .L_five_or_more
+	fxtod	%f10, %f2
+
+	fdtox	%f16, %f14
+	ldx	[%o5+16], %g2		C p16
+	fdtox	%f4, %f12
+	ldx	[%o5+24], %g1		C p0
+	std	%f14, [%o5+16]
+	fmuld	%f2, %f8, %f16
+	std	%f12, [%o5+24]
+	fmuld	%f2, %f6, %f4
+	add	%o1, 4, %o1		C up++
+	lduw	[%o0], %g5		C read rp[i]
+	b	.L4
+	add	%o0, -4, %o0
+
+	.align	16
+.L_five_or_more:
+	subcc	%o2, 1, %o2
+	ld	[%o1], %f11		C read up[i]
+	fdtox	%f16, %f14
+	ldx	[%o5+16], %g2		C p16
+	fdtox	%f4, %f12
+	ldx	[%o5+24], %g1		C p0
+	std	%f14, [%o5+16]
+	fmuld	%f2, %f8, %f16
+	std	%f12, [%o5+24]
+	fmuld	%f2, %f6, %f4
+	add	%o1, 4, %o1		C up++
+	lduw	[%o0], %g5		C read rp[i]
+	bne,pt	%icc, .Loop
+	fxtod	%f10, %f2
+	b,a	.L5
+
+C BEGIN MAIN LOOP
+	.align 16
+C -- 0
+.Loop:	sub	%g0, %g3, %g3
+	subcc	%o2, 1, %o2
+	ld	[%o1], %f11		C read up[i]
+	fdtox	%f16, %f14
+C -- 1
+	sllx	%g2, 16, %g4		C (p16 << 16)
+	add	%o0, 4, %o0		C rp++
+	ldx	[%o5+0], %g2		C p16
+	fdtox	%f4, %f12
+C -- 2
+	srl	%g3, 0, %g3		C zero most significant 32 bits
+	add	%g1, %g4, %g4		C p = p0 + (p16 << 16)
+	ldx	[%o5+8], %g1		C p0
+	fanop
+C -- 3
+	nop
+	add	%g3, %g4, %g4		C p += cy
+	std	%f14, [%o5+0]
+	fmuld	%f2, %f8, %f16
+C -- 4
+	nop
+	sub	%g5, %g4, %g4		C p += rp[i]
+	std	%f12, [%o5+8]
+	fmuld	%f2, %f6, %f4
+C -- 5
+	xor	%o5, 16, %o5		C alternate scratch variables
+	add	%o1, 4, %o1		C up++
+	stw	%g4, [%o0-4]
+	fanop
+C -- 6
+	srlx	%g4, 32, %g3		C new cy
+	lduw	[%o0], %g5		C read rp[i]
+	bne,pt	%icc, .Loop
+	fxtod	%f10, %f2
+C END MAIN LOOP
+
+.L5:	sub	%g0, %g3, %g3
+	fdtox	%f16, %f14
+	sllx	%g2, 16, %g4		C (p16 << 16)
+	ldx	[%o5+0], %g2		C p16
+	fdtox	%f4, %f12
+	srl	%g3, 0, %g3		C zero most significant 32 bits
+	add	%g1, %g4, %g4		C p = p0 + (p16 << 16)
+	ldx	[%o5+8], %g1		C p0
+	add	%g4, %g3, %g4		C p += cy
+	std	%f14, [%o5+0]
+	fmuld	%f2, %f8, %f16
+	sub	%g5, %g4, %g4		C p += rp[i]
+	std	%f12, [%o5+8]
+	fmuld	%f2, %f6, %f4
+	xor	%o5, 16, %o5
+	stw	%g4, [%o0+0]
+	srlx	%g4, 32, %g3		C new cy
+	lduw	[%o0+4], %g5		C read rp[i]
+
+	sub	%g0, %g3, %g3
+.L4:	fdtox	%f16, %f14
+	sllx	%g2, 16, %g4		C (p16 << 16)
+	ldx	[%o5+0], %g2		C p16
+	fdtox	%f4, %f12
+	srl	%g3, 0, %g3		C zero most significant 32 bits
+	add	%g1, %g4, %g4		C p = p0 + (p16 << 16)
+	ldx	[%o5+8], %g1		C p0
+	add	%g3, %g4, %g4		C p += cy
+	std	%f14, [%o5+0]
+	sub	%g5, %g4, %g4		C p += rp[i]
+	std	%f12, [%o5+8]
+	xor	%o5, 16, %o5
+	stw	%g4, [%o0+4]
+	srlx	%g4, 32, %g3		C new cy
+	lduw	[%o0+8], %g5		C read rp[i]
+
+	sub	%g0, %g3, %g3
+.L3:	sllx	%g2, 16, %g4		C (p16 << 16)
+	ldx	[%o5+0], %g2		C p16
+	srl	%g3, 0, %g3		C zero most significant 32 bits
+	add	%g1, %g4, %g4		C p = p0 + (p16 << 16)
+	ldx	[%o5+8], %g1		C p0
+	add	%g3, %g4, %g4		C p += cy
+	sub	%g5, %g4, %g4		C p += rp[i]
+	xor	%o5, 16, %o5
+	stw	%g4, [%o0+8]
+	srlx	%g4, 32, %g3		C new cy
+	lduw	[%o0+12], %g5		C read rp[i]
+
+	sub	%g0, %g3, %g3
+.L2:	sllx	%g2, 16, %g4		C (p16 << 16)
+	ldx	[%o5+0], %g2		C p16
+	srl	%g3, 0, %g3		C zero most significant 32 bits
+	add	%g1, %g4, %g4		C p = p0 + (p16 << 16)
+	ldx	[%o5+8], %g1		C p0
+	add	%g3, %g4, %g4		C p += cy
+	sub	%g5, %g4, %g4		C p += rp[i]
+	stw	%g4, [%o0+12]
+	srlx	%g4, 32, %g3		C new cy
+	lduw	[%o0+16], %g5		C read rp[i]
+
+	sub	%g0, %g3, %g3
+.L1:	sllx	%g2, 16, %g4		C (p16 << 16)
+	srl	%g3, 0, %g3		C zero most significant 32 bits
+	add	%g1, %g4, %g4		C p = p0 + (p16 << 16)
+	add	%g3, %g4, %g4		C p += cy
+	sub	%g5, %g4, %g4		C p += rp[i]
+	stw	%g4, [%o0+16]
+	srlx	%g4, 32, %g3		C new cy
+
+	sub	%g0, %g3, %o0
+	retl
+	sub	%sp, -FSIZE, %sp
+EPILOGUE(mpn_submul_1)
diff --git a/third_party/gmp/mpn/sparc32/v9/udiv.asm b/third_party/gmp/mpn/sparc32/v9/udiv.asm
new file mode 100644
index 0000000..61dde97
--- /dev/null
+++ b/third_party/gmp/mpn/sparc32/v9/udiv.asm
@@ -0,0 +1,52 @@
+dnl  SPARC v9 32-bit mpn_udiv_qrnnd - division support for longlong.h.
+
+dnl  Copyright 2002, 2003 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+C rem_ptr	o0
+C n1		o1
+C n0		o2
+C d		o3
+
+ASM_START()
+PROLOGUE(mpn_udiv_qrnnd)
+	sllx	%o1, 32, %g1		C shift upper dividend limb
+	srl	%o2, 0, %g2		C zero extend lower dividend limb
+	srl	%o3, 0, %g3		C zero extend divisor
+	or	%g2, %g1, %g1		C assemble 64-bit dividend
+	udivx	%g1, %g3, %g1
+	mulx	%g1, %g3, %g4
+	sub	%g2, %g4, %g2
+	st	%g2, [%o0]		C store remainder
+	retl
+	mov	%g1, %o0		C return quotient
+EPILOGUE(mpn_udiv_qrnnd)
diff --git a/third_party/gmp/mpn/sparc64/README b/third_party/gmp/mpn/sparc64/README
new file mode 100644
index 0000000..e2c051a
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/README
@@ -0,0 +1,125 @@
+Copyright 1997, 1999-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.
+
+
+
+
+
+This directory contains mpn functions for 64-bit V9 SPARC
+
+RELEVANT OPTIMIZATION ISSUES
+
+Notation:
+  IANY = shift/add/sub/logical/sethi
+  IADDLOG = add/sub/logical/sethi
+  MEM = ld*/st*
+  FA = fadd*/fsub*/f*to*/fmov*
+  FM = fmul*
+
+UltraSPARC can issue four instructions per cycle, with these restrictions:
+* Two IANY instructions, but only one of these may be a shift.  If there is a
+  shift and an IANY instruction, the shift must precede the IANY instruction.
+* One FA.
+* One FM.
+* One branch.
+* One MEM.
+* IANY/IADDLOG/MEM must be insn 1, 2, or 3 in an issue bundle.  Taken branches
+  should not be in slot 4, since that makes the delay insn come from separate
+  bundle.
+* If two IANY/IADDLOG instructions are to be executed in the same cycle and one
+  of these is setting the condition codes, that instruction must be the second
+  one.
+
+To summarize, ignoring branches, these are the bundles that can reach the peak
+execution speed:
+
+insn1	iany	iany	mem	iany	iany	mem	iany	iany	mem
+insn2	iaddlog	mem	iany	mem	iaddlog	iany	mem	iaddlog	iany
+insn3	mem	iaddlog	iaddlog	fa	fa	fa	fm	fm	fm
+insn4	fa/fm	fa/fm	fa/fm	fm	fm	fm	fa	fa	fa
+
+The 64-bit integer multiply instruction mulx takes from 5 cycles to 35 cycles,
+depending on the position of the most significant bit of the first source
+operand.  When used for 32x32->64 multiplication, it needs 20 cycles.
+Furthermore, it stalls the processor while executing.  We stay away from that
+instruction, and instead use floating-point operations.
+
+Floating-point add and multiply units are fully pipelined.  The latency for
+UltraSPARC-1/2 is 3 cycles and for UltraSPARC-3 it is 4 cycles.
+
+Integer conditional move instructions cannot dual-issue with other integer
+instructions.  No conditional move can issue 1-5 cycles after a load.  (This
+might have been fixed for UltraSPARC-3.)
+
+The UltraSPARC-3 pipeline is very simular to the one of UltraSPARC-1/2 , but is
+somewhat slower.  Branches execute slower, and there may be other new stalls.
+But integer multiply doesn't stall the entire CPU and also has a much lower
+latency.  But it's still not pipelined, and thus useless for our needs.
+
+STATUS
+
+* mpn_lshift, mpn_rshift: The current code runs at 2.0 cycles/limb on
+  UltraSPARC-1/2 and 2.65 on UltraSPARC-3.  For UltraSPARC-1/2, the IEU0
+  functional unit is saturated with shifts.
+
+* mpn_add_n, mpn_sub_n: The current code runs at 4 cycles/limb on
+  UltraSPARC-1/2 and 4.5 cycles/limb on UltraSPARC-3.  The 4 instruction
+  recurrency is the speed limiter.
+
+* mpn_addmul_1: The current code runs at 14 cycles/limb asymptotically on
+  UltraSPARC-1/2 and 17.5 cycles/limb on UltraSPARC-3.  On UltraSPARC-1/2, the
+  code sustains 4 instructions/cycle.  It might be possible to invent a better
+  way of summing the intermediate 49-bit operands, but it is unlikely that it
+  will save enough instructions to save an entire cycle.
+
+  The load-use of the u operand is not enough scheduled for good L2 cache
+  performance.  The UltraSPARC-1/2 L1 cache is direct mapped, and since we use
+  temporary stack slots that will conflict with the u and r operands, we miss
+  to L2 very often.  The load-use of the std/ldx pairs via the stack are
+  perhaps over-scheduled.
+
+  It would be possible to save two instructions: (1) The mov could be avoided
+  if the std/ldx were less scheduled.  (2) The ldx of the r operand could be
+  split into two ld instructions, saving the shifts/masks.
+
+  It should be possible to reach 14 cycles/limb for UltraSPARC-3 if the fp
+  operations where rescheduled for this processor's 4-cycle latency.
+
+* mpn_mul_1: The current code is a straightforward edit of the mpn_addmul_1
+  code.  It would be possible to shave one or two cycles from it, with some
+  labour.
+
+* mpn_submul_1: Simpleminded code just calling mpn_mul_1 + mpn_sub_n.  This
+  means that it runs at 18 cycles/limb on UltraSPARC-1/2 and 23 cycles/limb on
+  UltraSPARC-3.  It would be possible to either match the mpn_addmul_1
+  performance, or in the worst case use one more instruction group.
+
+* US1/US2 cache conflict resolving.  The direct mapped L1 date cache of US1/US2
+  is a problem for mul_1, addmul_1 (and a prospective submul_1).  We should
+  allocate a larger cache area, and put the stack temp area in a place that
+  doesn't cause cache conflicts.
diff --git a/third_party/gmp/mpn/sparc64/copyd.asm b/third_party/gmp/mpn/sparc64/copyd.asm
new file mode 100644
index 0000000..ab105d3
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/copyd.asm
@@ -0,0 +1,89 @@
+dnl  SPARC v9 mpn_copyd -- Copy a limb vector, decrementing.
+
+dnl  Copyright 1999-2003 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		   cycles/limb
+C UltraSPARC 1&2:	 2
+C UltraSPARC 3:		 2.5
+C UltraSPARC T1:	17
+C UltraSPARC T3:	 6
+C UltraSPARC T4/T5:	 2
+
+C INPUT PARAMETERS
+C rptr	%o0
+C sptr	%o1
+C n	%o2
+
+ASM_START()
+	REGISTER(%g2,#scratch)
+	REGISTER(%g3,#scratch)
+PROLOGUE(mpn_copyd)
+	sllx	%o2,3,%g1
+	add	%g1,%o0,%o0
+	add	%g1,%o1,%o1
+	addcc	%o2,-8,%o2
+	bl,pt	%xcc,L(end01234567)
+	nop
+L(loop1):
+	ldx	[%o1-8],%g1
+	ldx	[%o1-16],%g2
+	ldx	[%o1-24],%g3
+	ldx	[%o1-32],%g4
+	ldx	[%o1-40],%g5
+	ldx	[%o1-48],%o3
+	ldx	[%o1-56],%o4
+	ldx	[%o1-64],%o5
+	add	%o1,-64,%o1
+	stx	%g1,[%o0-8]
+	stx	%g2,[%o0-16]
+	stx	%g3,[%o0-24]
+	stx	%g4,[%o0-32]
+	stx	%g5,[%o0-40]
+	stx	%o3,[%o0-48]
+	stx	%o4,[%o0-56]
+	stx	%o5,[%o0-64]
+	addcc	%o2,-8,%o2
+	bge,pt	%xcc,L(loop1)
+	add	%o0,-64,%o0
+L(end01234567):
+	addcc	%o2,8,%o2
+	bz,pn	%xcc,L(end)
+	nop
+L(loop2):
+	ldx	[%o1-8],%g1
+	add	%o1,-8,%o1
+	addcc	%o2,-1,%o2
+	stx	%g1,[%o0-8]
+	bg,pt	%xcc,L(loop2)
+	add	%o0,-8,%o0
+L(end):	retl
+	nop
+EPILOGUE(mpn_copyd)
diff --git a/third_party/gmp/mpn/sparc64/copyi.asm b/third_party/gmp/mpn/sparc64/copyi.asm
new file mode 100644
index 0000000..45663dc
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/copyi.asm
@@ -0,0 +1,86 @@
+dnl  SPARC v9 mpn_copyi -- Copy a limb vector, incrementing.
+
+dnl  Copyright 1999-2003 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		   cycles/limb
+C UltraSPARC 1&2:	 2
+C UltraSPARC 3:		 2.5
+C UltraSPARC T1:	17
+C UltraSPARC T3:	 6
+C UltraSPARC T4/T5:	 2
+
+C INPUT PARAMETERS
+C rptr	%o0
+C sptr	%o1
+C n	%o2
+
+ASM_START()
+	REGISTER(%g2,#scratch)
+	REGISTER(%g3,#scratch)
+PROLOGUE(mpn_copyi)
+	addcc	%o2,-8,%o2
+	bl,pt	%xcc,L(end01234567)
+	nop
+L(loop1):
+	ldx	[%o1+0],%g1
+	ldx	[%o1+8],%g2
+	ldx	[%o1+16],%g3
+	ldx	[%o1+24],%g4
+	ldx	[%o1+32],%g5
+	ldx	[%o1+40],%o3
+	ldx	[%o1+48],%o4
+	ldx	[%o1+56],%o5
+	add	%o1,64,%o1
+	stx	%g1,[%o0+0]
+	stx	%g2,[%o0+8]
+	stx	%g3,[%o0+16]
+	stx	%g4,[%o0+24]
+	stx	%g5,[%o0+32]
+	stx	%o3,[%o0+40]
+	stx	%o4,[%o0+48]
+	stx	%o5,[%o0+56]
+	addcc	%o2,-8,%o2
+	bge,pt	%xcc,L(loop1)
+	add	%o0,64,%o0
+L(end01234567):
+	addcc	%o2,8,%o2
+	bz,pn	%xcc,L(end)
+	nop
+L(loop2):
+	ldx	[%o1+0],%g1
+	add	%o1,8,%o1
+	addcc	%o2,-1,%o2
+	stx	%g1,[%o0+0]
+	bg,pt	%xcc,L(loop2)
+	add	%o0,8,%o0
+L(end):	retl
+	nop
+EPILOGUE(mpn_copyi)
diff --git a/third_party/gmp/mpn/sparc64/dive_1.c b/third_party/gmp/mpn/sparc64/dive_1.c
new file mode 100644
index 0000000..4264f29
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/dive_1.c
@@ -0,0 +1,161 @@
+/* UltraSPARC 64 mpn_divexact_1 -- mpn by limb exact division.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2000, 2001, 2003, 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#include "mpn/sparc64/sparc64.h"
+
+
+/*                 64-bit divisor   32-bit divisor
+                    cycles/limb      cycles/limb
+                     (approx)         (approx)
+   Ultrasparc 2i:      110               70
+*/
+
+
+/* There are two key ideas here to reduce mulx's.  Firstly when the divisor
+   is 32-bits the high of q*d can be calculated without the two 32x32->64
+   cross-products involving the high 32-bits of the divisor, that being zero
+   of course.  Secondly umul_ppmm_lowequal and umul_ppmm_half_lowequal save
+   one mulx (each) knowing the low of q*d is equal to the input limb l.
+
+   For size==1, a simple udivx is used.  This is faster than calculating an
+   inverse.
+
+   For a 32-bit divisor and small sizes, an attempt was made at a simple
+   udivx loop (two per 64-bit limb), but it turned out to be slower than
+   mul-by-inverse.  At size==2 the inverse is about 260 cycles total
+   compared to a udivx at 291.  Perhaps the latter would suit when size==2
+   but the high 32-bits of the second limb is zero (saving one udivx), but
+   it doesn't seem worth a special case just for that.  */
+
+void
+mpn_divexact_1 (mp_ptr dst, mp_srcptr src, mp_size_t size, mp_limb_t divisor)
+{
+  mp_limb_t  inverse, s, s_next, c, l, ls, q;
+  unsigned   rshift, lshift;
+  mp_limb_t  lshift_mask;
+  mp_limb_t  divisor_h;
+
+  ASSERT (size >= 1);
+  ASSERT (divisor != 0);
+  ASSERT (MPN_SAME_OR_SEPARATE_P (dst, src, size));
+  ASSERT_MPN (src, size);
+  ASSERT_LIMB (divisor);
+
+  s = *src++;                 /* src low limb */
+  size--;
+  if (size == 0)
+    {
+      *dst = s / divisor;
+      return;
+    }
+
+  if ((divisor & 1) == 0)
+    {
+      count_trailing_zeros (rshift, divisor);
+      divisor >>= rshift;
+      lshift = 64 - rshift;
+
+      lshift_mask = MP_LIMB_T_MAX;
+    }
+  else
+    {
+      rshift = 0;
+
+      /* rshift==0 means no shift, so must mask out other part in this case */
+      lshift = 0;
+      lshift_mask = 0;
+    }
+
+  binvert_limb (inverse, divisor);
+
+  c = 0;
+  divisor_h = HIGH32 (divisor);
+
+  if (divisor_h == 0)
+    {
+      /* 32-bit divisor */
+      do
+        {
+          s_next = *src++;
+          ls = (s >> rshift) | ((s_next << lshift) & lshift_mask);
+          s = s_next;
+
+          SUBC_LIMB (c, l, ls, c);
+
+          q = l * inverse;
+          *dst++ = q;
+
+          umul_ppmm_half_lowequal (l, q, divisor, l);
+          c += l;
+
+          size--;
+        }
+      while (size != 0);
+
+      ls = s >> rshift;
+      l = ls - c;
+      q = l * inverse;
+      *dst = q;
+    }
+  else
+    {
+      /* 64-bit divisor */
+      mp_limb_t  divisor_l = LOW32 (divisor);
+      do
+        {
+          s_next = *src++;
+          ls = (s >> rshift) | ((s_next << lshift) & lshift_mask);
+          s = s_next;
+
+          SUBC_LIMB (c, l, ls, c);
+
+          q = l * inverse;
+          *dst++ = q;
+
+          umul_ppmm_lowequal (l, q, divisor, divisor_h, divisor_l, l);
+          c += l;
+
+          size--;
+        }
+      while (size != 0);
+
+      ls = s >> rshift;
+      l = ls - c;
+      q = l * inverse;
+      *dst = q;
+    }
+}
diff --git a/third_party/gmp/mpn/sparc64/divrem_1.c b/third_party/gmp/mpn/sparc64/divrem_1.c
new file mode 100644
index 0000000..ac94565
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/divrem_1.c
@@ -0,0 +1,242 @@
+/* UltraSparc 64 mpn_divrem_1 -- mpn by limb division.
+
+Copyright 1991, 1993, 1994, 1996, 1998-2001, 2003 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#include "mpn/sparc64/sparc64.h"
+
+
+/*                   64-bit divisor       32-bit divisor
+                       cycles/limb          cycles/limb
+                        (approx)             (approx)
+                   integer  fraction    integer  fraction
+   Ultrasparc 2i:    160      160          122      96
+*/
+
+
+/* 32-bit divisors are treated in special case code.  This requires 4 mulx
+   per limb instead of 8 in the general case.
+
+   For big endian systems we need HALF_ENDIAN_ADJ included in the src[i]
+   addressing, to get the two halves of each limb read in the correct order.
+   This is kept in an adj variable.  Doing that measures about 4 c/l faster
+   than just writing HALF_ENDIAN_ADJ(i) in the integer loop.  The latter
+   shouldn't be 6 cycles worth of work, but perhaps it doesn't schedule well
+   (on gcc 3.2.1 at least).  The fraction loop doesn't seem affected, but we
+   still use a variable since that ought to work out best.  */
+
+mp_limb_t
+mpn_divrem_1 (mp_ptr qp_limbptr, mp_size_t xsize_limbs,
+              mp_srcptr ap_limbptr, mp_size_t size_limbs, mp_limb_t d_limb)
+{
+  mp_size_t  total_size_limbs;
+  mp_size_t  i;
+
+  ASSERT (xsize_limbs >= 0);
+  ASSERT (size_limbs >= 0);
+  ASSERT (d_limb != 0);
+  /* FIXME: What's the correct overlap rule when xsize!=0? */
+  ASSERT (MPN_SAME_OR_SEPARATE_P (qp_limbptr + xsize_limbs,
+                                  ap_limbptr, size_limbs));
+
+  total_size_limbs = size_limbs + xsize_limbs;
+  if (UNLIKELY (total_size_limbs == 0))
+    return 0;
+
+  /* udivx is good for total_size==1, and no need to bother checking
+     limb<divisor, since if that's likely the caller should check */
+  if (UNLIKELY (total_size_limbs == 1))
+    {
+      mp_limb_t  a, q;
+      a = (LIKELY (size_limbs != 0) ? ap_limbptr[0] : 0);
+      q = a / d_limb;
+      qp_limbptr[0] = q;
+      return a - q*d_limb;
+    }
+
+  if (d_limb <= CNST_LIMB(0xFFFFFFFF))
+    {
+      mp_size_t  size, xsize, total_size, adj;
+      unsigned   *qp, n1, n0, q, r, nshift, norm_rmask;
+      mp_limb_t  dinv_limb;
+      const unsigned *ap;
+      int        norm, norm_rshift;
+
+      size = 2 * size_limbs;
+      xsize = 2 * xsize_limbs;
+      total_size = size + xsize;
+
+      ap = (unsigned *) ap_limbptr;
+      qp = (unsigned *) qp_limbptr;
+
+      qp += xsize;
+      r = 0;        /* initial remainder */
+
+      if (LIKELY (size != 0))
+        {
+          n1 = ap[size-1 + HALF_ENDIAN_ADJ(1)];
+
+          /* If the length of the source is uniformly distributed, then
+             there's a 50% chance of the high 32-bits being zero, which we
+             can skip.  */
+          if (n1 == 0)
+            {
+              n1 = ap[size-2 + HALF_ENDIAN_ADJ(0)];
+              total_size--;
+              size--;
+              ASSERT (size > 0);  /* because always even */
+              qp[size + HALF_ENDIAN_ADJ(1)] = 0;
+            }
+
+          /* Skip a division if high < divisor (high quotient 0).  Testing
+             here before before normalizing will still skip as often as
+             possible.  */
+          if (n1 < d_limb)
+            {
+              r = n1;
+              size--;
+              qp[size + HALF_ENDIAN_ADJ(size)] = 0;
+              total_size--;
+              if (total_size == 0)
+                return r;
+            }
+        }
+
+      count_leading_zeros_32 (norm, d_limb);
+      norm -= 32;
+      d_limb <<= norm;
+      r <<= norm;
+
+      norm_rshift = 32 - norm;
+      norm_rmask = (norm == 0 ? 0 : 0xFFFFFFFF);
+
+      invert_half_limb (dinv_limb, d_limb);
+
+      if (LIKELY (size != 0))
+        {
+          i = size - 1;
+          adj = HALF_ENDIAN_ADJ (i);
+          n1 = ap[i + adj];
+          adj = -adj;
+          r |= ((n1 >> norm_rshift) & norm_rmask);
+          for ( ; i > 0; i--)
+            {
+              n0 = ap[i-1 + adj];
+              adj = -adj;
+              nshift = (n1 << norm) | ((n0 >> norm_rshift) & norm_rmask);
+              udiv_qrnnd_half_preinv (q, r, r, nshift, d_limb, dinv_limb);
+              qp[i + adj] = q;
+              n1 = n0;
+            }
+          nshift = n1 << norm;
+          udiv_qrnnd_half_preinv (q, r, r, nshift, d_limb, dinv_limb);
+          qp[0 + HALF_ENDIAN_ADJ(0)] = q;
+        }
+      qp -= xsize;
+      adj = HALF_ENDIAN_ADJ (0);
+      for (i = xsize-1; i >= 0; i--)
+        {
+          udiv_qrnnd_half_preinv (q, r, r, 0, d_limb, dinv_limb);
+          adj = -adj;
+          qp[i + adj] = q;
+        }
+
+      return r >> norm;
+    }
+  else
+    {
+      mp_srcptr  ap;
+      mp_ptr     qp;
+      mp_size_t  size, xsize, total_size;
+      mp_limb_t  d, n1, n0, q, r, dinv, nshift, norm_rmask;
+      int        norm, norm_rshift;
+
+      ap = ap_limbptr;
+      qp = qp_limbptr;
+      size = size_limbs;
+      xsize = xsize_limbs;
+      total_size = total_size_limbs;
+      d = d_limb;
+
+      qp += total_size;   /* above high limb */
+      r = 0;              /* initial remainder */
+
+      if (LIKELY (size != 0))
+        {
+          /* Skip a division if high < divisor (high quotient 0).  Testing
+             here before before normalizing will still skip as often as
+             possible.  */
+          n1 = ap[size-1];
+          if (n1 < d)
+            {
+              r = n1;
+              *--qp = 0;
+              total_size--;
+              if (total_size == 0)
+                return r;
+              size--;
+            }
+        }
+
+      count_leading_zeros (norm, d);
+      d <<= norm;
+      r <<= norm;
+
+      norm_rshift = GMP_LIMB_BITS - norm;
+      norm_rmask = (norm == 0 ? 0 : ~CNST_LIMB(0));
+
+      invert_limb (dinv, d);
+
+      if (LIKELY (size != 0))
+        {
+          n1 = ap[size-1];
+          r |= ((n1 >> norm_rshift) & norm_rmask);
+          for (i = size-2; i >= 0; i--)
+            {
+              n0 = ap[i];
+              nshift = (n1 << norm) | ((n0 >> norm_rshift) & norm_rmask);
+              udiv_qrnnd_preinv (q, r, r, nshift, d, dinv);
+              *--qp = q;
+              n1 = n0;
+            }
+          nshift = n1 << norm;
+          udiv_qrnnd_preinv (q, r, r, nshift, d, dinv);
+          *--qp = q;
+        }
+      for (i = 0; i < xsize; i++)
+        {
+          udiv_qrnnd_preinv (q, r, r, CNST_LIMB(0), d, dinv);
+          *--qp = q;
+        }
+      return r >> norm;
+    }
+}
diff --git a/third_party/gmp/mpn/sparc64/gcd_11.asm b/third_party/gmp/mpn/sparc64/gcd_11.asm
new file mode 100644
index 0000000..5564751
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/gcd_11.asm
@@ -0,0 +1,88 @@
+dnl  SPARC64 mpn_gcd_11.
+
+dnl  Based on the K7 gcd_1.asm, by Kevin Ryde.  Rehacked for SPARC by Torbjörn
+dnl  Granlund.
+
+dnl  Copyright 2000-2002, 2005, 2009, 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C		  cycles/bit (approx)
+C UltraSPARC 1&2:	 5.1
+C UltraSPARC 3:		 5.0
+C UltraSPARC T1:	11.4
+C UltraSPARC T3:	10
+C UltraSPARC T4:	 6
+C Numbers measured with: speed -CD -s32-64 -t32 mpn_gcd_1
+
+C ctz_table[n] is the number of trailing zeros on n, or MAXSHIFT if n==0.
+
+deflit(MAXSHIFT, 7)
+deflit(MASK, eval((m4_lshift(1,MAXSHIFT))-1))
+
+	RODATA
+	TYPE(ctz_table,object)
+ctz_table:
+	.byte	MAXSHIFT
+forloop(i,1,MASK,
+`	.byte	m4_count_trailing_zeros(i)
+')
+	SIZE(ctz_table,.-ctz_table)
+
+define(`u0',    `%o0')
+define(`v0',    `%o1')
+
+ASM_START()
+	REGISTER(%g2,#scratch)
+	REGISTER(%g3,#scratch)
+PROLOGUE(mpn_gcd_11)
+	LEA64(ctz_table, o5, g4)
+	b	L(odd)
+	 mov	u0, %o4
+
+	ALIGN(16)
+L(top):	movcc	%xcc, %o4, v0		C v = min(u,v)
+	movcc	%xcc, %o2, %o0		C u = |v - u]
+L(mid):	ldub	[%o5+%g3], %g5		C
+	brz,a,pn %g3, L(shift_alot)	C
+	 srlx	%o0, MAXSHIFT, %o0
+	srlx	%o0, %g5, %o4		C new u, odd
+L(odd):	subcc	v0, %o4, %o2		C v - u, set flags for branch and movcc
+	sub	%o4, v0, %o0		C u - v
+	bnz,pt	%xcc, L(top)		C
+	 and	%o2, MASK, %g3		C extract low MAXSHIFT bits from (v-u)
+
+	retl
+	 mov	v0, %o0
+
+L(shift_alot):
+	b	L(mid)
+	 and	%o0, MASK, %g3		C
+EPILOGUE()
diff --git a/third_party/gmp/mpn/sparc64/gmp-mparam.h b/third_party/gmp/mpn/sparc64/gmp-mparam.h
new file mode 100644
index 0000000..5ac2c46
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/gmp-mparam.h
@@ -0,0 +1,139 @@
+/* Sparc64 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 1999-2002, 2004, 2006, 2008-2010 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+/* 500 MHz ultrasparc2 running GNU/Linux */
+
+#define DIVREM_1_NORM_THRESHOLD              3
+#define DIVREM_1_UNNORM_THRESHOLD            4
+#define MOD_1_NORM_THRESHOLD                 3
+#define MOD_1_UNNORM_THRESHOLD               3
+#define MOD_1N_TO_MOD_1_1_THRESHOLD      MP_SIZE_T_MAX  /* never */
+#define MOD_1U_TO_MOD_1_1_THRESHOLD         22
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD         0  /* never mpn_mod_1_1p */
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        27
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD  MP_SIZE_T_MAX  /* never */
+#define USE_PREINV_DIVREM_1                  1
+#define DIVEXACT_1_THRESHOLD                 0  /* always */
+#define BMOD_1_TO_MOD_1_THRESHOLD        MP_SIZE_T_MAX  /* never */
+
+#define MUL_TOOM22_THRESHOLD                30
+#define MUL_TOOM33_THRESHOLD               187
+#define MUL_TOOM44_THRESHOLD               278
+#define MUL_TOOM6H_THRESHOLD               278
+#define MUL_TOOM8H_THRESHOLD               357
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD     201
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     199
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     154
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     107
+
+#define SQR_BASECASE_THRESHOLD              13
+#define SQR_TOOM2_THRESHOLD                 69
+#define SQR_TOOM3_THRESHOLD                116
+#define SQR_TOOM4_THRESHOLD                336
+#define SQR_TOOM6_THRESHOLD                336
+#define SQR_TOOM8_THRESHOLD                454
+
+#define MULMOD_BNM1_THRESHOLD               17
+#define SQRMOD_BNM1_THRESHOLD               23
+
+#define MUL_FFT_MODF_THRESHOLD             248  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    248, 5}, {      9, 4}, {     19, 6}, {      5, 5}, \
+    {     15, 6}, {      8, 5}, {     17, 6}, {     21, 7}, \
+    {     19, 8}, {     11, 7}, {     25, 8}, {     15, 7}, \
+    {     31, 8}, {     27, 9}, {     15, 8}, {     33, 9}, \
+    {     19, 8}, {     39, 9}, {     27,10}, {     15, 9}, \
+    {     39,10}, {     23, 9}, {     47,11}, {     15,10}, \
+    {     31, 9}, {     67,10}, {     39, 9}, {     79,10}, \
+    {     47,11}, {     31,10}, {     63, 9}, {    127, 8}, \
+    {    255,10}, {     71, 9}, {    143, 8}, {    287,10}, \
+    {     79,11}, {     47,12}, {   4096,13}, {   8192,14}, \
+    {  16384,15}, {  32768,16}, {  65536,17}, { 131072,18}, \
+    { 262144,19}, { 524288,20}, {1048576,21}, {2097152,22}, \
+    {4194304,23}, {8388608,24} }
+#define MUL_FFT_TABLE3_SIZE 50
+#define MUL_FFT_THRESHOLD                 1984
+
+#define SQR_FFT_MODF_THRESHOLD             236  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    236, 5}, {      8, 4}, {     17, 5}, {     19, 6}, \
+    {     10, 5}, {     21, 6}, {     19, 7}, {     10, 6}, \
+    {     21, 7}, {     21, 8}, {     21, 9}, {     11, 8}, \
+    {     23, 9}, {     19, 8}, {     43, 9}, {     23,10}, \
+    {     15, 9}, {     43,10}, {     23,11}, {     15,10}, \
+    {     31, 9}, {     63,10}, {     47, 8}, {    191,11}, \
+    {     31,10}, {     63, 8}, {    255, 7}, {    511, 9}, \
+    {    135, 8}, {    271,10}, {     71, 9}, {    143, 8}, \
+    {    287, 7}, {    575,11}, {     47, 9}, {    191, 8}, \
+    {    383,12}, {   4096,13}, {   8192,14}, {  16384,15}, \
+    {  32768,16}, {  65536,17}, { 131072,18}, { 262144,19}, \
+    { 524288,20}, {1048576,21}, {2097152,22}, {4194304,23}, \
+    {8388608,24} }
+#define SQR_FFT_TABLE3_SIZE 49
+#define SQR_FFT_THRESHOLD                 1120
+
+#define MULLO_BASECASE_THRESHOLD            16
+#define MULLO_DC_THRESHOLD                  41
+#define MULLO_MUL_N_THRESHOLD             3791
+
+#define DC_DIV_QR_THRESHOLD                 27
+#define DC_DIVAPPR_Q_THRESHOLD             100
+#define DC_BDIV_QR_THRESHOLD                47
+#define DC_BDIV_Q_THRESHOLD                174
+
+#define INV_MULMOD_BNM1_THRESHOLD           58
+#define INV_NEWTON_THRESHOLD                13
+#define INV_APPR_THRESHOLD                   9
+
+#define BINV_NEWTON_THRESHOLD              187
+#define REDC_1_TO_REDC_2_THRESHOLD          10
+#define REDC_2_TO_REDC_N_THRESHOLD         115
+
+#define MU_DIV_QR_THRESHOLD                680
+#define MU_DIVAPPR_Q_THRESHOLD             618
+#define MUPI_DIV_QR_THRESHOLD                0  /* always */
+#define MU_BDIV_QR_THRESHOLD               748
+#define MU_BDIV_Q_THRESHOLD                889
+
+#define MATRIX22_STRASSEN_THRESHOLD         13
+#define HGCD_THRESHOLD                      53
+#define GCD_DC_THRESHOLD                   283
+#define GCDEXT_DC_THRESHOLD                186
+#define JACOBI_BASE_METHOD                   2
+
+#define GET_STR_DC_THRESHOLD                13
+#define GET_STR_PRECOMPUTE_THRESHOLD        16
+#define SET_STR_DC_THRESHOLD               390
+#define SET_STR_PRECOMPUTE_THRESHOLD      1665
diff --git a/third_party/gmp/mpn/sparc64/lshift.asm b/third_party/gmp/mpn/sparc64/lshift.asm
new file mode 100644
index 0000000..90bbb45
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/lshift.asm
@@ -0,0 +1,140 @@
+dnl  SPARC v9 mpn_lshift
+
+dnl  Contributed to the GNU project by David Miller.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		    cycles/limb
+C UltraSPARC 1&2:	 2
+C UltraSPARC 3:		 2.5
+C UltraSPARC T1:	17.5
+C UltraSPARC T3:	 8
+C UltraSPARC T4:	 3
+
+C INPUT PARAMETERS
+define(`rp',     `%i0')
+define(`up',     `%i1')
+define(`n',      `%i2')
+define(`cnt',    `%i3')
+
+define(`tcnt',   `%i4')
+define(`retval', `%i5')
+define(`u0',     `%l0')
+define(`u1',     `%l1')
+define(`r0',     `%l6')
+define(`r1',     `%l7')
+define(`u0_off', `%o0')
+define(`u1_off', `%o1')
+define(`r0_off', `%o2')
+define(`r1_off', `%o3')
+
+ASM_START()
+	REGISTER(%g2,#scratch)
+	REGISTER(%g3,#scratch)
+PROLOGUE(mpn_lshift)
+	save	%sp, -176, %sp
+
+	sllx	n, 3, n
+	sub	%g0, cnt, tcnt
+
+	sub	up, 8, u1_off
+	add	rp, (5 * 8), r1_off
+
+	ldx	[n + u1_off], u1	C WAS: up - 8
+	add	u1_off, (3 * 8), u1_off
+
+	sub	r1_off, 8, r0_off
+	sub	u1_off, 8, u0_off
+
+	subcc	n, (3 * 8), n
+	srlx	u1, tcnt, retval
+
+	bl,pn	%xcc, L(end12)
+	 sllx	u1, cnt, %l3
+
+	ldx	[n + u0_off], u0	C WAS: up - 16
+	subcc	n, (2 * 8), n
+
+	ldx	[n + u1_off], u1	C WAS: up - 24
+
+	bl,pn	%xcc, L(end34)
+	 srlx	u0, tcnt, %l4
+
+	b,a	L(top)
+	ALIGN(16)
+L(top):
+	sllx	u0, cnt, %l2
+	or	%l4, %l3, r0
+
+	ldx	[n + u0_off], u0	C WAS: up - 16
+	srlx	u1, tcnt, %l5
+
+	stx	r0, [n + r0_off]	C WAS: rp - 8
+	subcc	n, (2 * 8), n
+
+	sllx	u1, cnt, %l3
+	or	%l2, %l5, r1
+
+	ldx	[n + u1_off], u1	C WAS: up - 24
+	srlx	u0, tcnt, %l4
+
+	bge,pt	%xcc, L(top)
+	 stx	r1, [n + r1_off]	C WAS: rp - 16
+
+L(end34):
+	sllx	u0, cnt, %l2
+	or	%l4, %l3, r0
+
+	srlx	u1, tcnt, %l5
+	stx	r0, [n + r0_off]	C WAS: rp - 8
+
+	or	%l2, %l5, r1
+	sub	n, (2 * 8), %o5
+
+	sllx	u1, cnt, %l3
+	stx	r1, [%o5 + r1_off]	C WAS: rp - 16
+
+L(end12):
+	andcc	n, 8, %g0
+	bz,pn	%xcc, L(done)
+	 nop
+
+	ldx	[n + u0_off], u1
+	srlx	u1, tcnt, %l4
+	or	%l4, %l3, r0
+	stx	r0, [r0_off - 24]
+	sllx	u1, cnt, %l3
+L(done):
+	stx	%l3, [r0_off - 32]
+
+	ret
+	restore retval, 0, %o0
+EPILOGUE()
diff --git a/third_party/gmp/mpn/sparc64/lshiftc.asm b/third_party/gmp/mpn/sparc64/lshiftc.asm
new file mode 100644
index 0000000..4a0f0a3
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/lshiftc.asm
@@ -0,0 +1,147 @@
+dnl  SPARC v9 mpn_lshiftc
+
+dnl  Contributed to the GNU project by David Miller.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		    cycles/limb
+C UltraSPARC 1&2:	 3
+C UltraSPARC 3:		 3
+C UltraSPARC T1:	17
+C UltraSPARC T3:	10
+C UltraSPARC T4:	 3.5
+
+C INPUT PARAMETERS
+define(`rp',     `%i0')
+define(`up',     `%i1')
+define(`n',      `%i2')
+define(`cnt',    `%i3')
+
+define(`tcnt',   `%i4')
+define(`retval', `%i5')
+define(`u0',     `%l0')
+define(`u1',     `%l1')
+define(`r0',     `%l6')
+define(`r1',     `%l7')
+define(`u0_off', `%o0')
+define(`u1_off', `%o1')
+define(`r0_off', `%o2')
+define(`r1_off', `%o3')
+
+ASM_START()
+	REGISTER(%g2,#scratch)
+	REGISTER(%g3,#scratch)
+PROLOGUE(mpn_lshiftc)
+	save	%sp, -176, %sp
+
+	sllx	n, 3, n
+	sub	%g0, cnt, tcnt
+
+	sub	up, 8, u1_off
+	add	rp, (5 * 8), r1_off
+
+	ldx	[n + u1_off], u1	C WAS: up - 8
+	add	u1_off, (3 * 8), u1_off
+
+	sub	r1_off, 8, r0_off
+	sub	u1_off, 8, u0_off
+
+	subcc	n, (3 * 8), n
+	srlx	u1, tcnt, retval
+
+	bl,pn	%xcc, L(end12)
+	 sllx	u1, cnt, %l3
+
+	ldx	[n + u0_off], u0	C WAS: up - 16
+	subcc	n, (2 * 8), n
+
+	ldx	[n + u1_off], u1	C WAS: up - 24
+
+	bl,pn	%xcc, L(end34)
+	 srlx	u0, tcnt, %l4
+
+	b,a	L(top)
+	ALIGN(16)
+L(top):
+	not	%l3, %l3
+	sllx	u0, cnt, %l2
+
+	andn	%l3, %l4, r0
+	ldx	[n + u0_off], u0	C WAS: up - 16
+
+	srlx	u1, tcnt, %l5
+	stx	r0, [n + r0_off]	C WAS: rp - 8
+
+	subcc	n, (2 * 8), n
+	not	%l2, %l2
+
+	sllx	u1, cnt, %l3
+	andn	%l2, %l5, r1
+
+	ldx	[n + u1_off], u1	C WAS: up - 24
+	srlx	u0, tcnt, %l4
+
+	bge,pt	%xcc, L(top)
+	 stx	r1, [n + r1_off]	C WAS: rp - 16
+
+L(end34):
+	not	%l3, %l3
+	sllx	u0, cnt, %l2
+
+	andn	%l3, %l4, r0
+	srlx	u1, tcnt, %l5
+
+	stx	r0, [n + r0_off]	C WAS: rp - 8
+	not	%l2, %l2
+
+	andn	%l2, %l5, r1
+	sub	n, (2 * 8), %o5
+
+	sllx	u1, cnt, %l3
+	stx	r1, [%o5 + r1_off]	C WAS: rp - 16
+
+L(end12):
+	andcc	n, 8, %g0
+	bz	%xcc, L(done)+4
+	 not	%l3, %l3
+
+	ldx	[n + u0_off], u1
+	srlx	u1, tcnt, %l4
+	andn	%l3, %l4, r0
+	stx	r0, [r0_off - 24]
+	sllx	u1, cnt, %l3
+L(done):
+	not	%l3, %l3
+	stx	%l3, [r0_off - 32]
+
+	ret
+	restore retval, 0, %o0
+EPILOGUE()
diff --git a/third_party/gmp/mpn/sparc64/mod_1.c b/third_party/gmp/mpn/sparc64/mod_1.c
new file mode 100644
index 0000000..ab53f9d
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/mod_1.c
@@ -0,0 +1,238 @@
+/* UltraSPARC 64 mpn_mod_1 -- mpn by limb remainder.
+
+Copyright 1991, 1993, 1994, 1999-2001, 2003, 2010 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#include "mpn/sparc64/sparc64.h"
+
+
+/*                 64-bit divisor   32-bit divisor
+                    cycles/limb      cycles/limb
+                     (approx)         (approx)
+   Ultrasparc 2i:      160               120
+*/
+
+
+/* 32-bit divisors are treated in special case code.  This requires 4 mulx
+   per limb instead of 8 in the general case.
+
+   For big endian systems we need HALF_ENDIAN_ADJ included in the src[i]
+   addressing, to get the two halves of each limb read in the correct order.
+   This is kept in an adj variable.  Doing that measures about 6 c/l faster
+   than just writing HALF_ENDIAN_ADJ(i) in the loop.  The latter shouldn't
+   be 6 cycles worth of work, but perhaps it doesn't schedule well (on gcc
+   3.2.1 at least).
+
+   A simple udivx/umulx loop for the 32-bit case was attempted for small
+   sizes, but at size==2 it was only about the same speed and at size==3 was
+   slower.  */
+
+static mp_limb_t
+mpn_mod_1_anynorm (mp_srcptr src_limbptr, mp_size_t size_limbs, mp_limb_t d_limb)
+{
+  int        norm, norm_rshift;
+  mp_limb_t  src_high_limb;
+  mp_size_t  i;
+
+  ASSERT (size_limbs >= 0);
+  ASSERT (d_limb != 0);
+
+  if (UNLIKELY (size_limbs == 0))
+    return 0;
+
+  src_high_limb = src_limbptr[size_limbs-1];
+
+  /* udivx is good for size==1, and no need to bother checking limb<divisor,
+     since if that's likely the caller should check */
+  if (UNLIKELY (size_limbs == 1))
+    return src_high_limb % d_limb;
+
+  if (d_limb <= CNST_LIMB(0xFFFFFFFF))
+    {
+      unsigned   *src, n1, n0, r, dummy_q, nshift, norm_rmask;
+      mp_size_t  size, adj;
+      mp_limb_t  dinv_limb;
+
+      size = 2 * size_limbs;    /* halfwords */
+      src = (unsigned *) src_limbptr;
+
+      /* prospective initial remainder, if < d */
+      r = src_high_limb >> 32;
+
+      /* If the length of the source is uniformly distributed, then there's
+         a 50% chance of the high 32-bits being zero, which we can skip.  */
+      if (r == 0)
+        {
+          r = (unsigned) src_high_limb;
+          size--;
+          ASSERT (size > 0);  /* because always even */
+        }
+
+      /* Skip a division if high < divisor.  Having the test here before
+         normalizing will still skip as often as possible.  */
+      if (r < d_limb)
+        {
+          size--;
+          ASSERT (size > 0);  /* because size==1 handled above */
+        }
+      else
+        r = 0;
+
+      count_leading_zeros_32 (norm, d_limb);
+      norm -= 32;
+      d_limb <<= norm;
+
+      norm_rshift = 32 - norm;
+      norm_rmask = (norm == 0 ? 0 : 0xFFFFFFFF);
+      i = size-1;
+      adj = HALF_ENDIAN_ADJ (i);
+      n1 = src [i + adj];
+      r = (r << norm) | ((n1 >> norm_rshift) & norm_rmask);
+
+      invert_half_limb (dinv_limb, d_limb);
+      adj = -adj;
+
+      for (i--; i >= 0; i--)
+        {
+          n0 = src [i + adj];
+          adj = -adj;
+          nshift = (n1 << norm) | ((n0 >> norm_rshift) & norm_rmask);
+          udiv_qrnnd_half_preinv (dummy_q, r, r, nshift, d_limb, dinv_limb);
+          n1 = n0;
+        }
+
+      /* same as loop, but without n0 */
+      nshift = n1 << norm;
+      udiv_qrnnd_half_preinv (dummy_q, r, r, nshift, d_limb, dinv_limb);
+
+      ASSERT ((r & ((1 << norm) - 1)) == 0);
+      return r >> norm;
+    }
+  else
+    {
+      mp_srcptr  src;
+      mp_size_t  size;
+      mp_limb_t  n1, n0, r, dinv, dummy_q, nshift, norm_rmask;
+
+      src = src_limbptr;
+      size = size_limbs;
+      r = src_high_limb;  /* initial remainder */
+
+      /* Skip a division if high < divisor.  Having the test here before
+         normalizing will still skip as often as possible.  */
+      if (r < d_limb)
+        {
+          size--;
+          ASSERT (size > 0);  /* because size==1 handled above */
+        }
+      else
+        r = 0;
+
+      count_leading_zeros (norm, d_limb);
+      d_limb <<= norm;
+
+      norm_rshift = GMP_LIMB_BITS - norm;
+      norm_rmask = (norm == 0 ? 0 : 0xFFFFFFFF);
+
+      src += size;
+      n1 = *--src;
+      r = (r << norm) | ((n1 >> norm_rshift) & norm_rmask);
+
+      invert_limb (dinv, d_limb);
+
+      for (i = size-2; i >= 0; i--)
+        {
+          n0 = *--src;
+          nshift = (n1 << norm) | ((n0 >> norm_rshift) & norm_rmask);
+          udiv_qrnnd_preinv (dummy_q, r, r, nshift, d_limb, dinv);
+          n1 = n0;
+        }
+
+      /* same as loop, but without n0 */
+      nshift = n1 << norm;
+      udiv_qrnnd_preinv (dummy_q, r, r, nshift, d_limb, dinv);
+
+      ASSERT ((r & ((CNST_LIMB(1) << norm) - 1)) == 0);
+      return r >> norm;
+    }
+}
+
+mp_limb_t
+mpn_mod_1 (mp_srcptr ap, mp_size_t n, mp_limb_t b)
+{
+  ASSERT (n >= 0);
+  ASSERT (b != 0);
+
+  /* Should this be handled at all?  Rely on callers?  Note un==0 is currently
+     required by mpz/fdiv_r_ui.c and possibly other places.  */
+  if (n == 0)
+    return 0;
+
+  if (UNLIKELY ((b & GMP_NUMB_HIGHBIT) != 0))
+    {
+      if (BELOW_THRESHOLD (n, MOD_1N_TO_MOD_1_1_THRESHOLD))
+	{
+	  return mpn_mod_1_anynorm (ap, n, b);
+	}
+      else
+	{
+	  mp_limb_t pre[4];
+	  mpn_mod_1_1p_cps (pre, b);
+	  return mpn_mod_1_1p (ap, n, b, pre);
+	}
+    }
+  else
+    {
+      if (BELOW_THRESHOLD (n, MOD_1U_TO_MOD_1_1_THRESHOLD))
+	{
+	  return mpn_mod_1_anynorm (ap, n, b);
+	}
+      else if (BELOW_THRESHOLD (n, MOD_1_1_TO_MOD_1_2_THRESHOLD))
+	{
+	  mp_limb_t pre[4];
+	  mpn_mod_1_1p_cps (pre, b);
+	  return mpn_mod_1_1p (ap, n, b << pre[1], pre);
+	}
+      else if (BELOW_THRESHOLD (n, MOD_1_2_TO_MOD_1_4_THRESHOLD) || UNLIKELY (b > GMP_NUMB_MASK / 4))
+	{
+	  mp_limb_t pre[5];
+	  mpn_mod_1s_2p_cps (pre, b);
+	  return mpn_mod_1s_2p (ap, n, b << pre[1], pre);
+	}
+      else
+	{
+	  mp_limb_t pre[7];
+	  mpn_mod_1s_4p_cps (pre, b);
+	  return mpn_mod_1s_4p (ap, n, b << pre[1], pre);
+	}
+    }
+}
diff --git a/third_party/gmp/mpn/sparc64/mod_1_4.c b/third_party/gmp/mpn/sparc64/mod_1_4.c
new file mode 100644
index 0000000..735a402
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/mod_1_4.c
@@ -0,0 +1,235 @@
+/* mpn_mod_1s_4p (ap, n, b, cps)
+   Divide (ap,,n) by b.  Return the single-limb remainder.
+   Requires that d < B / 4.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+   Based on a suggestion by Peter L. Montgomery.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2008-2010 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#include "mpn/sparc64/sparc64.h"
+
+void
+mpn_mod_1s_4p_cps (mp_limb_t cps[7], mp_limb_t b)
+{
+  mp_limb_t bi;
+  mp_limb_t B1modb, B2modb, B3modb, B4modb, B5modb;
+  int cnt;
+
+  ASSERT (b <= (~(mp_limb_t) 0) / 4);
+
+  count_leading_zeros (cnt, b);
+
+  b <<= cnt;
+  invert_limb (bi, b);
+
+  cps[0] = bi;
+  cps[1] = cnt;
+
+  B1modb = -b * ((bi >> (GMP_LIMB_BITS-cnt)) | (CNST_LIMB(1) << cnt));
+  ASSERT (B1modb <= b);		/* NB: not fully reduced mod b */
+  cps[2] = B1modb >> cnt;
+
+  udiv_rnnd_preinv (B2modb, B1modb, CNST_LIMB(0), b, bi);
+  cps[3] = B2modb >> cnt;
+
+  udiv_rnnd_preinv (B3modb, B2modb, CNST_LIMB(0), b, bi);
+  cps[4] = B3modb >> cnt;
+
+  udiv_rnnd_preinv (B4modb, B3modb, CNST_LIMB(0), b, bi);
+  cps[5] = B4modb >> cnt;
+
+  udiv_rnnd_preinv (B5modb, B4modb, CNST_LIMB(0), b, bi);
+  cps[6] = B5modb >> cnt;
+
+#if WANT_ASSERT
+  {
+    int i;
+    b = cps[2];
+    for (i = 3; i <= 6; i++)
+      {
+	b += cps[i];
+	ASSERT (b >= cps[i]);
+      }
+  }
+#endif
+}
+
+mp_limb_t
+mpn_mod_1s_4p (mp_srcptr ap, mp_size_t n, mp_limb_t b, const mp_limb_t cps[7])
+{
+  mp_limb_t rh, rl, bi, ph, pl, ch, cl, r;
+  mp_limb_t B1modb, B2modb, B3modb, B4modb, B5modb;
+  mp_size_t i;
+  int cnt;
+
+  ASSERT (n >= 1);
+
+  B1modb = cps[2];
+  B2modb = cps[3];
+  B3modb = cps[4];
+  B4modb = cps[5];
+  B5modb = cps[6];
+
+  if ((b >> 32) == 0)
+    {
+      switch (n & 3)
+	{
+	case 0:
+	  umul_ppmm_s (ph, pl, ap[n - 3], B1modb);
+	  add_ssaaaa (ph, pl, ph, pl, CNST_LIMB(0), ap[n - 4]);
+	  umul_ppmm_s (ch, cl, ap[n - 2], B2modb);
+	  add_ssaaaa (ph, pl, ph, pl, ch, cl);
+	  umul_ppmm_s (rh, rl, ap[n - 1], B3modb);
+	  add_ssaaaa (rh, rl, rh, rl, ph, pl);
+	  n -= 4;
+	  break;
+	case 1:
+	  rh = 0;
+	  rl = ap[n - 1];
+	  n -= 1;
+	  break;
+	case 2:
+	  rh = ap[n - 1];
+	  rl = ap[n - 2];
+	  n -= 2;
+	  break;
+	case 3:
+	  umul_ppmm_s (ph, pl, ap[n - 2], B1modb);
+	  add_ssaaaa (ph, pl, ph, pl, CNST_LIMB(0), ap[n - 3]);
+	  umul_ppmm_s (rh, rl, ap[n - 1], B2modb);
+	  add_ssaaaa (rh, rl, rh, rl, ph, pl);
+	  n -= 3;
+	  break;
+	}
+
+      for (i = n - 4; i >= 0; i -= 4)
+	{
+	  /* rr = ap[i]				< B
+		+ ap[i+1] * (B mod b)		<= (B-1)(b-1)
+		+ ap[i+2] * (B^2 mod b)		<= (B-1)(b-1)
+		+ ap[i+3] * (B^3 mod b)		<= (B-1)(b-1)
+		+ LO(rr)  * (B^4 mod b)		<= (B-1)(b-1)
+		+ HI(rr)  * (B^5 mod b)		<= (B-1)(b-1)
+	  */
+	  umul_ppmm_s (ph, pl, ap[i + 1], B1modb);
+	  add_ssaaaa (ph, pl, ph, pl, CNST_LIMB(0), ap[i + 0]);
+
+	  umul_ppmm_s (ch, cl, ap[i + 2], B2modb);
+	  add_ssaaaa (ph, pl, ph, pl, ch, cl);
+
+	  umul_ppmm_s (ch, cl, ap[i + 3], B3modb);
+	  add_ssaaaa (ph, pl, ph, pl, ch, cl);
+
+	  umul_ppmm_s (ch, cl, rl, B4modb);
+	  add_ssaaaa (ph, pl, ph, pl, ch, cl);
+
+	  umul_ppmm_s (rh, rl, rh, B5modb);
+	  add_ssaaaa (rh, rl, rh, rl, ph, pl);
+	}
+
+      umul_ppmm_s (rh, cl, rh, B1modb);
+      add_ssaaaa (rh, rl, rh, rl, CNST_LIMB(0), cl);
+    }
+  else
+    {
+      switch (n & 3)
+	{
+	case 0:
+	  umul_ppmm (ph, pl, ap[n - 3], B1modb);
+	  add_ssaaaa (ph, pl, ph, pl, 0, ap[n - 4]);
+	  umul_ppmm (ch, cl, ap[n - 2], B2modb);
+	  add_ssaaaa (ph, pl, ph, pl, ch, cl);
+	  umul_ppmm (rh, rl, ap[n - 1], B3modb);
+	  add_ssaaaa (rh, rl, rh, rl, ph, pl);
+	  n -= 4;
+	  break;
+	case 1:
+	  rh = 0;
+	  rl = ap[n - 1];
+	  n -= 1;
+	  break;
+	case 2:
+	  rh = ap[n - 1];
+	  rl = ap[n - 2];
+	  n -= 2;
+	  break;
+	case 3:
+	  umul_ppmm (ph, pl, ap[n - 2], B1modb);
+	  add_ssaaaa (ph, pl, ph, pl, 0, ap[n - 3]);
+	  umul_ppmm (rh, rl, ap[n - 1], B2modb);
+	  add_ssaaaa (rh, rl, rh, rl, ph, pl);
+	  n -= 3;
+	  break;
+	}
+
+      for (i = n - 4; i >= 0; i -= 4)
+	{
+	  /* rr = ap[i]				< B
+		+ ap[i+1] * (B mod b)		<= (B-1)(b-1)
+		+ ap[i+2] * (B^2 mod b)		<= (B-1)(b-1)
+		+ ap[i+3] * (B^3 mod b)		<= (B-1)(b-1)
+		+ LO(rr)  * (B^4 mod b)		<= (B-1)(b-1)
+		+ HI(rr)  * (B^5 mod b)		<= (B-1)(b-1)
+	  */
+	  umul_ppmm (ph, pl, ap[i + 1], B1modb);
+	  add_ssaaaa (ph, pl, ph, pl, 0, ap[i + 0]);
+
+	  umul_ppmm (ch, cl, ap[i + 2], B2modb);
+	  add_ssaaaa (ph, pl, ph, pl, ch, cl);
+
+	  umul_ppmm (ch, cl, ap[i + 3], B3modb);
+	  add_ssaaaa (ph, pl, ph, pl, ch, cl);
+
+	  umul_ppmm (ch, cl, rl, B4modb);
+	  add_ssaaaa (ph, pl, ph, pl, ch, cl);
+
+	  umul_ppmm (rh, rl, rh, B5modb);
+	  add_ssaaaa (rh, rl, rh, rl, ph, pl);
+	}
+
+      umul_ppmm (rh, cl, rh, B1modb);
+      add_ssaaaa (rh, rl, rh, rl, 0, cl);
+    }
+
+  bi = cps[0];
+  cnt = cps[1];
+
+  r = (rh << cnt) | (rl >> (GMP_LIMB_BITS - cnt));
+  udiv_rnnd_preinv (r, r, rl << cnt, b, bi);
+
+  return r >> cnt;
+}
diff --git a/third_party/gmp/mpn/sparc64/mode1o.c b/third_party/gmp/mpn/sparc64/mode1o.c
new file mode 100644
index 0000000..771c999
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/mode1o.c
@@ -0,0 +1,196 @@
+/* UltraSPARC 64 mpn_modexact_1c_odd -- mpn by limb exact style remainder.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2000-2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#include "mpn/sparc64/sparc64.h"
+
+
+/*                 64-bit divisor   32-bit divisor
+                    cycles/limb      cycles/limb
+                     (approx)         (approx)
+   Ultrasparc 2i:       ?                ?
+*/
+
+
+/* This implementation reduces the number of multiplies done, knowing that
+   on ultrasparc 1 and 2 the mulx instruction stalls the whole chip.
+
+   The key idea is to use the fact that the low limb of q*d equals l, this
+   being the whole purpose of the q calculated.  It means there's no need to
+   calculate the lowest 32x32->64 part of the q*d, instead it can be
+   inferred from l and the other three 32x32->64 parts.  See sparc64.h for
+   details.
+
+   When d is 32-bits, the same applies, but in this case there's only one
+   other 32x32->64 part (ie. HIGH(q)*d).
+
+   The net effect is that for 64-bit divisor each limb is 4 mulx, or for
+   32-bit divisor each is 2 mulx.
+
+   Enhancements:
+
+   No doubt this could be done in assembler, if that helped the scheduling,
+   or perhaps guaranteed good code irrespective of the compiler.
+
+   Alternatives:
+
+   It might be possibly to use floating point.  The loop is dominated by
+   multiply latency, so not sure if floats would improve that.  One
+   possibility would be to take two limbs at a time, with a 128 bit inverse,
+   if there's enough registers, which could effectively use float throughput
+   to reduce total latency across two limbs.  */
+
+#define ASSERT_RETVAL(r)                \
+  ASSERT (orig_c < d ? r < d : r <= d)
+
+mp_limb_t
+mpn_modexact_1c_odd (mp_srcptr src, mp_size_t size, mp_limb_t d, mp_limb_t orig_c)
+{
+  mp_limb_t  c = orig_c;
+  mp_limb_t  s, l, q, h, inverse;
+
+  ASSERT (size >= 1);
+  ASSERT (d & 1);
+  ASSERT_MPN (src, size);
+  ASSERT_LIMB (d);
+  ASSERT_LIMB (c);
+
+  /* udivx is faster than 10 or 12 mulx's for one limb via an inverse */
+  if (size == 1)
+    {
+      s = src[0];
+      if (s > c)
+	{
+	  l = s-c;
+	  h = l % d;
+	  if (h != 0)
+	    h = d - h;
+	}
+      else
+	{
+	  l = c-s;
+	  h = l % d;
+	}
+      return h;
+    }
+
+  binvert_limb (inverse, d);
+
+  if (d <= 0xFFFFFFFF)
+    {
+      s = *src++;
+      size--;
+      do
+        {
+          SUBC_LIMB (c, l, s, c);
+          s = *src++;
+          q = l * inverse;
+          umul_ppmm_half_lowequal (h, q, d, l);
+          c += h;
+          size--;
+        }
+      while (size != 0);
+
+      if (s <= d)
+        {
+          /* With high s <= d the final step can be a subtract and addback.
+             If c==0 then the addback will restore to l>=0.  If c==d then
+             will get l==d if s==0, but that's ok per the function
+             definition.  */
+
+          l = c - s;
+          l += (l > c ? d : 0);
+
+          ASSERT_RETVAL (l);
+          return l;
+        }
+      else
+        {
+          /* Can't skip a divide, just do the loop code once more. */
+          SUBC_LIMB (c, l, s, c);
+          q = l * inverse;
+          umul_ppmm_half_lowequal (h, q, d, l);
+          c += h;
+
+          ASSERT_RETVAL (c);
+          return c;
+        }
+    }
+  else
+    {
+      mp_limb_t  dl = LOW32 (d);
+      mp_limb_t  dh = HIGH32 (d);
+      long i;
+
+      s = *src++;
+      size--;
+      do
+        {
+          SUBC_LIMB (c, l, s, c);
+          s = *src++;
+          q = l * inverse;
+          umul_ppmm_lowequal (h, q, d, dh, dl, l);
+          c += h;
+          size--;
+        }
+      while (size != 0);
+
+      if (s <= d)
+        {
+          /* With high s <= d the final step can be a subtract and addback.
+             If c==0 then the addback will restore to l>=0.  If c==d then
+             will get l==d if s==0, but that's ok per the function
+             definition.  */
+
+          l = c - s;
+          l += (l > c ? d : 0);
+
+          ASSERT_RETVAL (l);
+          return l;
+        }
+      else
+        {
+          /* Can't skip a divide, just do the loop code once more. */
+          SUBC_LIMB (c, l, s, c);
+          q = l * inverse;
+          umul_ppmm_lowequal (h, q, d, dh, dl, l);
+          c += h;
+
+          ASSERT_RETVAL (c);
+          return c;
+        }
+    }
+}
diff --git a/third_party/gmp/mpn/sparc64/rshift.asm b/third_party/gmp/mpn/sparc64/rshift.asm
new file mode 100644
index 0000000..3f8e11f
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/rshift.asm
@@ -0,0 +1,142 @@
+dnl  SPARC v9 mpn_rshift
+
+dnl  Contributed to the GNU project by David Miller.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		    cycles/limb
+C UltraSPARC 1&2:	 2
+C UltraSPARC 3:		 2.5
+C UltraSPARC T1:	17.5
+C UltraSPARC T3:	 8
+C UltraSPARC T4:	 3
+
+C INPUT PARAMETERS
+define(`rp',     `%i0')
+define(`up',     `%i1')
+define(`n',      `%i2')
+define(`cnt',    `%i3')
+
+define(`tcnt',   `%i4')
+define(`retval', `%i5')
+define(`u0',     `%l0')
+define(`u1',     `%l1')
+define(`r0',     `%l6')
+define(`r1',     `%l7')
+define(`u0_off', `%o0')
+define(`u1_off', `%o1')
+define(`r0_off', `%o2')
+define(`r1_off', `%o3')
+
+ASM_START()
+	REGISTER(%g2,#scratch)
+	REGISTER(%g3,#scratch)
+PROLOGUE(mpn_rshift)
+	save	%sp, -176, %sp
+
+	sllx	n, 3, n
+	sub	%g0, cnt, tcnt
+
+	add	up, n, up
+	add	rp, n, rp
+
+	neg	n, n
+	sub	up, (2 * 8), u0_off
+	sub	rp, (5 * 8), r0_off
+
+	ldx	[n + up], u1		C WAS: up + 0
+	sub	u0_off, (1 * 8), u1_off
+	sub	r0_off, (1 * 8), r1_off
+
+	subcc	n, -(3 * 8), n
+	sllx	u1, tcnt, retval
+
+	bg,pn	%xcc, L(end12)
+	 srlx	u1, cnt, %l3
+
+	ldx	[n + u0_off], u0	C WAS: up + 0
+	subcc	n, -(2 * 8), n
+
+	ldx	[n + u1_off], u1	C WAS: up + 8
+
+	bg,pn	%xcc, L(end34)
+	 sllx	u0, tcnt, %l4
+
+	b,a	L(top)
+	ALIGN(16)
+L(top):
+	srlx	u0, cnt, %l2
+	or	%l3, %l4, r0
+
+	ldx	[n + u0_off], u0	C WAS: up + 0
+	sllx	u1, tcnt, %l5
+
+	stx	r0, [n + r0_off]	C WAS: rp + 0
+	subcc	n, -(2 * 8), n
+
+	srlx	u1, cnt, %l3
+	or	%l2, %l5, r1
+
+	ldx	[n + u1_off], u1	C WAS: up + 8
+	sllx	u0, tcnt, %l4
+
+	ble,pt	%xcc, L(top)
+	 stx	r1, [n + r1_off]	C WAS: rp + 8
+
+L(end34):
+	srlx	u0, cnt, %l2
+	or	%l3, %l4, r0
+
+	sllx	u1, tcnt, %l5
+	stx	r0, [n + r0_off]	C WAS: rp + 0
+
+	or	%l2, %l5, r1
+	sub	n, -(2 * 8), %o5
+
+	srlx	u1, cnt, %l3
+	stx	r1, [%o5 + r1_off]	C WAS: rp + 8
+
+L(end12):
+	andcc	n, 8, %g0
+	bz,pn	%xcc, L(done)
+	 nop
+
+	ldx	[n + u0_off], u1
+	sllx	u1, tcnt, %l4
+	or	%l3, %l4, r0
+	stx	r0, [r0_off + 24]
+	srlx	u1, cnt, %l3
+L(done):
+	stx	%l3, [r0_off + 32]
+
+	ret
+	restore retval, 0, %o0
+EPILOGUE()
diff --git a/third_party/gmp/mpn/sparc64/sec_tabselect.asm b/third_party/gmp/mpn/sparc64/sec_tabselect.asm
new file mode 100644
index 0000000..22e0dc5
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/sec_tabselect.asm
@@ -0,0 +1,162 @@
+dnl  SPARC v9 mpn_sec_tabselect.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund and David Miller.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		   cycles/limb
+C UltraSPARC 1&2:	 2 hopefully
+C UltraSPARC 3:		 3
+C UltraSPARC T1:	17
+C UltraSPARC T3:	 ?
+C UltraSPARC T4/T5:	 2.25 hopefully
+
+C INPUT PARAMETERS
+define(`rp',     `%i0')
+define(`tp',     `%i1')
+define(`n',      `%i2')
+define(`nents',  `%i3')
+define(`which',  `%i4')
+
+define(`i',      `%g1')
+define(`j',      `%g3')
+define(`stride', `%g4')
+define(`tporig', `%g5')
+define(`mask',   `%o0')
+
+define(`data0',  `%l0')
+define(`data1',  `%l1')
+define(`data2',  `%l2')
+define(`data3',  `%l3')
+define(`t0',     `%l4')
+define(`t1',     `%l5')
+define(`t2',     `%l6')
+define(`t3',     `%l7')
+
+ASM_START()
+	REGISTER(%g2,#scratch)
+	REGISTER(%g3,#scratch)
+PROLOGUE(mpn_sec_tabselect)
+	save	%sp, -176, %sp
+
+	sllx	n, 3, stride
+	sub	n, 4, j
+	brlz	j, L(outer_end)
+	 mov	tp, tporig
+
+L(outer_loop):
+	clr	data0
+	clr	data1
+	clr	data2
+	clr	data3
+	mov	tporig, tp
+	mov	nents, i
+	mov	which, %o1
+
+L(top):	subcc	%o1, 1, %o1		C set carry iff o1 = 0
+	ldx	[tp + 0], t0
+	subc	%g0, %g0, mask
+	ldx	[tp + 8], t1
+	sub	i, 1, i
+	ldx	[tp + 16], t2
+	ldx	[tp + 24], t3
+	add	tp, stride, tp
+	and	t0, mask, t0
+	and	t1, mask, t1
+	or	t0, data0, data0
+	and	t2, mask, t2
+	or	t1, data1, data1
+	and	t3, mask, t3
+	or	t2, data2, data2
+	brnz	i, L(top)
+	 or	t3, data3, data3
+
+	stx	data0, [rp + 0]
+	subcc	j, 4, j
+	stx	data1, [rp + 8]
+	stx	data2, [rp + 16]
+	stx	data3, [rp + 24]
+	add	tporig, (4 * 8), tporig
+
+	brgez	j, L(outer_loop)
+	 add	rp, (4 * 8), rp
+L(outer_end):
+
+
+	andcc	n, 2, %g0
+	be	L(b0x)
+	 nop
+L(b1x):	clr	data0
+	clr	data1
+	mov	tporig, tp
+	mov	nents, i
+	mov	which, %o1
+
+L(tp2):	subcc	%o1, 1, %o1
+	ldx	[tp + 0], t0
+	subc	%g0, %g0, mask
+	ldx	[tp + 8], t1
+	sub	i, 1, i
+	add	tp, stride, tp
+	and	t0, mask, t0
+	and	t1, mask, t1
+	or	t0, data0, data0
+	brnz	i, L(tp2)
+	 or	t1, data1, data1
+
+	stx	data0, [rp + 0]
+	stx	data1, [rp + 8]
+	add	tporig, (2 * 8), tporig
+	add	rp, (2 * 8), rp
+
+
+L(b0x):	andcc	n, 1, %g0
+	be	L(b00)
+	 nop
+L(b01):	clr	data0
+	mov	tporig, tp
+	mov	nents, i
+	mov	which, %o1
+
+L(tp1):	subcc	%o1, 1, %o1
+	ldx	[tp + 0], t0
+	subc	%g0, %g0, mask
+	sub	i, 1, i
+	add	tp, stride, tp
+	and	t0, mask, t0
+	brnz	i, L(tp1)
+	 or	t0, data0, data0
+
+	stx	data0, [rp + 0]
+
+L(b00):	 ret
+	  restore
+EPILOGUE()
diff --git a/third_party/gmp/mpn/sparc64/sparc64.h b/third_party/gmp/mpn/sparc64/sparc64.h
new file mode 100644
index 0000000..8698a82
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/sparc64.h
@@ -0,0 +1,217 @@
+/* UltraSPARC 64 support macros.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#define LOW32(x)   ((x) & 0xFFFFFFFF)
+#define HIGH32(x)  ((x) >> 32)
+
+
+/* Halfword number i in src is accessed as src[i+HALF_ENDIAN_ADJ(i)].
+   Plain src[i] would be incorrect in big endian, HALF_ENDIAN_ADJ has the
+   effect of swapping the two halves in this case.  */
+#if HAVE_LIMB_BIG_ENDIAN
+#define HALF_ENDIAN_ADJ(i)  (1 - (((i) & 1) << 1))   /* +1 even, -1 odd */
+#endif
+#if HAVE_LIMB_LITTLE_ENDIAN
+#define HALF_ENDIAN_ADJ(i)  0                        /* no adjust */
+#endif
+#ifndef HALF_ENDIAN_ADJ
+Error, error, unknown limb endianness;
+#endif
+
+
+/* umul_ppmm_lowequal sets h to the high limb of q*d, assuming the low limb
+   of that product is equal to l.  dh and dl are the 32-bit halves of d.
+
+   |-----high----||----low-----|
+   +------+------+
+   |             |                 ph = qh * dh
+   +------+------+
+          +------+------+
+          |             |          pm1 = ql * dh
+          +------+------+
+          +------+------+
+          |             |          pm2 = qh * dl
+          +------+------+
+                 +------+------+
+                 |             |   pl = ql * dl (not calculated)
+                 +------+------+
+
+   Knowing that the low 64 bits is equal to l means that LOW(pm1) + LOW(pm2)
+   + HIGH(pl) == HIGH(l).  The only thing we need from those product parts
+   is whether they produce a carry into the high.
+
+   pm_l = LOW(pm1)+LOW(pm2) is done to contribute its carry, then the only
+   time there's a further carry from LOW(pm_l)+HIGH(pl) is if LOW(pm_l) >
+   HIGH(l).  pl is never actually calculated.  */
+
+#define umul_ppmm_lowequal(h, q, d, dh, dl, l)  \
+  do {                                          \
+    mp_limb_t  ql, qh, ph, pm1, pm2, pm_l;      \
+    ASSERT (dh == HIGH32(d));                   \
+    ASSERT (dl == LOW32(d));                    \
+    ASSERT (q*d == l);                          \
+                                                \
+    ql = LOW32 (q);                             \
+    qh = HIGH32 (q);                            \
+                                                \
+    pm1 = ql * dh;                              \
+    pm2 = qh * dl;                              \
+    ph  = qh * dh;                              \
+                                                \
+    pm_l = LOW32 (pm1) + LOW32 (pm2);           \
+                                                \
+    (h) = ph + HIGH32 (pm1) + HIGH32 (pm2)      \
+      + HIGH32 (pm_l) + ((pm_l << 32) > l);     \
+                                                \
+    ASSERT_HIGH_PRODUCT (h, q, d);              \
+  } while (0)
+
+
+/* Set h to the high of q*d, assuming the low limb of that product is equal
+   to l, and that d fits in 32-bits.
+
+   |-----high----||----low-----|
+          +------+------+
+          |             |          pm = qh * dl
+          +------+------+
+                 +------+------+
+                 |             |   pl = ql * dl (not calculated)
+                 +------+------+
+
+   Knowing that LOW(pm) + HIGH(pl) == HIGH(l) (mod 2^32) means that the only
+   time there's a carry from that sum is when LOW(pm) > HIGH(l).  There's no
+   need to calculate pl to determine this.  */
+
+#define umul_ppmm_half_lowequal(h, q, d, l)     \
+  do {                                          \
+    mp_limb_t pm;                               \
+    ASSERT (q*d == l);                          \
+    ASSERT (HIGH32(d) == 0);                    \
+                                                \
+    pm = HIGH32(q) * d;                         \
+    (h) = HIGH32(pm) + ((pm << 32) > l);        \
+    ASSERT_HIGH_PRODUCT (h, q, d);              \
+  } while (0)
+
+
+/* check that h is the high limb of x*y */
+#if WANT_ASSERT
+#define ASSERT_HIGH_PRODUCT(h, x, y)    \
+  do {                                  \
+    mp_limb_t  want_h, dummy;           \
+    umul_ppmm (want_h, dummy, x, y);    \
+    ASSERT (h == want_h);               \
+  } while (0)
+#else
+#define ASSERT_HIGH_PRODUCT(h, q, d)    \
+  do { } while (0)
+#endif
+
+
+/* Multiply u anv v, where v < 2^32.  */
+#define umul_ppmm_s(w1, w0, u, v)					\
+  do {									\
+    UWtype __x0, __x2;							\
+    UWtype __ul, __vl, __uh;						\
+    UWtype __u = (u), __v = (v);					\
+									\
+    __ul = __ll_lowpart (__u);						\
+    __uh = __ll_highpart (__u);						\
+    __vl = __ll_lowpart (__v);						\
+									\
+    __x0 = (UWtype) __ul * __vl;					\
+    __x2 = (UWtype) __uh * __vl;					\
+									\
+    (w1) = (__x2 + (__x0 >> W_TYPE_SIZE/2)) >> W_TYPE_SIZE/2;		\
+    (w0) = (__x2 << W_TYPE_SIZE/2) + __x0;				\
+  } while (0)
+
+/* Count the leading zeros on a limb, but assuming it fits in 32 bits.
+   The count returned will be in the range 32 to 63.
+   This is the 32-bit generic C count_leading_zeros from longlong.h. */
+#define count_leading_zeros_32(count, x)                                      \
+  do {                                                                        \
+    mp_limb_t  __xr = (x);                                                    \
+    unsigned   __a;                                                           \
+    ASSERT ((x) != 0);                                                        \
+    ASSERT ((x) <= CNST_LIMB(0xFFFFFFFF));                                    \
+    __a = __xr < ((UWtype) 1 << 16) ? (__xr < ((UWtype) 1 << 8) ? 1 : 8 + 1)  \
+      : (__xr < ((UWtype) 1 << 24)  ? 16 + 1 : 24 + 1);                       \
+                                                                              \
+    (count) = W_TYPE_SIZE + 1 - __a - __clz_tab[__xr >> __a];                 \
+  } while (0)
+
+
+/* Set inv to a 32-bit inverse floor((b*(b-d)-1) / d), knowing that d fits
+   32 bits and is normalized (high bit set).  */
+#define invert_half_limb(inv, d)                \
+  do {                                          \
+    mp_limb_t  _n;                              \
+    ASSERT ((d) <= 0xFFFFFFFF);                 \
+    ASSERT ((d) & 0x80000000);                  \
+    _n = (((mp_limb_t) -(d)) << 32) - 1;        \
+    (inv) = (mp_limb_t) (unsigned) (_n / (d));  \
+  } while (0)
+
+
+/* Divide nh:nl by d, setting q to the quotient and r to the remainder.
+   q, r, nh and nl are 32-bits each, d_limb is 32-bits but in an mp_limb_t,
+   dinv_limb is similarly a 32-bit inverse but in an mp_limb_t.  */
+
+#define udiv_qrnnd_half_preinv(q, r, nh, nl, d_limb, dinv_limb)         \
+  do {                                                                  \
+    unsigned   _n2, _n10, _n1, _nadj, _q11n, _xh, _r, _q;               \
+    mp_limb_t  _n, _x;                                                  \
+    ASSERT (d_limb <= 0xFFFFFFFF);                                      \
+    ASSERT (dinv_limb <= 0xFFFFFFFF);                                   \
+    ASSERT (d_limb & 0x80000000);                                       \
+    ASSERT (nh < d_limb);                                               \
+    _n10 = (nl);                                                        \
+    _n2 = (nh);                                                         \
+    _n1 = (int) _n10 >> 31;                                             \
+    _nadj = _n10 + (_n1 & d_limb);                                      \
+    _x = dinv_limb * (_n2 - _n1) + _nadj;                               \
+    _q11n = ~(_n2 + HIGH32 (_x));             /* -q1-1 */               \
+    _n = ((mp_limb_t) _n2 << 32) + _n10;                                \
+    _x = _n + d_limb * _q11n;                 /* n-q1*d-d */            \
+    _xh = HIGH32 (_x) - d_limb;               /* high(n-q1*d-d) */      \
+    ASSERT (_xh == 0 || _xh == ~0);                                     \
+    _r = _x + (d_limb & _xh);                 /* addback */             \
+    _q = _xh - _q11n;                         /* q1+1-addback */        \
+    ASSERT (_r < d_limb);                                               \
+    ASSERT (d_limb * _q + _r == _n);                                    \
+    (r) = _r;                                                           \
+    (q) = _q;                                                           \
+  } while (0)
diff --git a/third_party/gmp/mpn/sparc64/ultrasparc1234/add_n.asm b/third_party/gmp/mpn/sparc64/ultrasparc1234/add_n.asm
new file mode 100644
index 0000000..92374d2
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/ultrasparc1234/add_n.asm
@@ -0,0 +1,241 @@
+dnl  SPARC v9 mpn_add_n -- Add two limb vectors of the same length > 0 and
+dnl  store sum in a third limb vector.
+
+dnl  Copyright 2001-2003, 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		   cycles/limb
+C UltraSPARC 1&2:     4
+C UltraSPARC 3:	      4.5
+
+C Compute carry-out from the most significant bits of u,v, and r, where
+C r=u+v+carry_in, using logic operations.
+
+C This code runs at 4 cycles/limb on UltraSPARC 1 and 2.  It has a 4 insn
+C recurrency, and the UltraSPARC 1 and 2 the IE units are 100% saturated.
+C Therefore, it seems futile to try to optimize this any further...
+
+C INPUT PARAMETERS
+define(`rp', `%i0')
+define(`up', `%i1')
+define(`vp', `%i2')
+define(`n',  `%i3')
+
+define(`u0', `%l0')
+define(`u1', `%l2')
+define(`u2', `%l4')
+define(`u3', `%l6')
+define(`v0', `%l1')
+define(`v1', `%l3')
+define(`v2', `%l5')
+define(`v3', `%l7')
+
+define(`cy',`%i4')
+
+define(`fanop',`fitod %f0,%f2')		dnl  A quasi nop running in the FA pipe
+define(`fmnop',`fmuld %f0,%f0,%f4')	dnl  A quasi nop running in the FM pipe
+
+ASM_START()
+	REGISTER(%g2,#scratch)
+	REGISTER(%g3,#scratch)
+PROLOGUE(mpn_add_nc)
+	save	%sp,-160,%sp
+
+	fitod	%f0,%f0		C make sure f0 contains small, quiet number
+	subcc	n,4,%g0
+	bl,pn	%xcc,.Loop0
+	nop
+	b,a	L(com)
+EPILOGUE()
+
+PROLOGUE(mpn_add_n)
+	save	%sp,-160,%sp
+
+	fitod	%f0,%f0		C make sure f0 contains small, quiet number
+	subcc	n,4,%g0
+	bl,pn	%xcc,.Loop0
+	mov	0,cy
+L(com):
+	ldx	[up+0],u0
+	ldx	[vp+0],v0
+	add	up,32,up
+	ldx	[up-24],u1
+	ldx	[vp+8],v1
+	add	vp,32,vp
+	ldx	[up-16],u2
+	ldx	[vp-16],v2
+	ldx	[up-8],u3
+	ldx	[vp-8],v3
+	subcc	n,8,n
+	add	u0,v0,%g1	C main add
+	add	%g1,cy,%g5	C carry add
+	or	u0,v0,%g2
+	bl,pn	%xcc,.Lend4567
+	fanop
+	b,a	.Loop
+
+	.align	16
+C START MAIN LOOP
+.Loop:	andn	%g2,%g5,%g2
+	and	u0,v0,%g3
+	ldx	[up+0],u0
+	fanop
+C --
+	or	%g3,%g2,%g2
+	ldx	[vp+0],v0
+	add	up,32,up
+	fanop
+C --
+	srlx	%g2,63,cy
+	add	u1,v1,%g1
+	stx	%g5,[rp+0]
+	fanop
+C --
+	add	%g1,cy,%g5
+	or	u1,v1,%g2
+	fmnop
+	fanop
+C --
+	andn	%g2,%g5,%g2
+	and	u1,v1,%g3
+	ldx	[up-24],u1
+	fanop
+C --
+	or	%g3,%g2,%g2
+	ldx	[vp+8],v1
+	add	vp,32,vp
+	fanop
+C --
+	srlx	%g2,63,cy
+	add	u2,v2,%g1
+	stx	%g5,[rp+8]
+	fanop
+C --
+	add	%g1,cy,%g5
+	or	u2,v2,%g2
+	fmnop
+	fanop
+C --
+	andn	%g2,%g5,%g2
+	and	u2,v2,%g3
+	ldx	[up-16],u2
+	fanop
+C --
+	or	%g3,%g2,%g2
+	ldx	[vp-16],v2
+	add	rp,32,rp
+	fanop
+C --
+	srlx	%g2,63,cy
+	add	u3,v3,%g1
+	stx	%g5,[rp-16]
+	fanop
+C --
+	add	%g1,cy,%g5
+	or	u3,v3,%g2
+	fmnop
+	fanop
+C --
+	andn	%g2,%g5,%g2
+	and	u3,v3,%g3
+	ldx	[up-8],u3
+	fanop
+C --
+	or	%g3,%g2,%g2
+	subcc	n,4,n
+	ldx	[vp-8],v3
+	fanop
+C --
+	srlx	%g2,63,cy
+	add	u0,v0,%g1
+	stx	%g5,[rp-8]
+	fanop
+C --
+	add	%g1,cy,%g5
+	or	u0,v0,%g2
+	bge,pt	%xcc,.Loop
+	fanop
+C END MAIN LOOP
+.Lend4567:
+	andn	%g2,%g5,%g2
+	and	u0,v0,%g3
+	or	%g3,%g2,%g2
+	srlx	%g2,63,cy
+	add	u1,v1,%g1
+	stx	%g5,[rp+0]
+	add	%g1,cy,%g5
+	or	u1,v1,%g2
+	andn	%g2,%g5,%g2
+	and	u1,v1,%g3
+	or	%g3,%g2,%g2
+	srlx	%g2,63,cy
+	add	u2,v2,%g1
+	stx	%g5,[rp+8]
+	add	%g1,cy,%g5
+	or	u2,v2,%g2
+	andn	%g2,%g5,%g2
+	and	u2,v2,%g3
+	or	%g3,%g2,%g2
+	add	rp,32,rp
+	srlx	%g2,63,cy
+	add	u3,v3,%g1
+	stx	%g5,[rp-16]
+	add	%g1,cy,%g5
+	or	u3,v3,%g2
+	andn	%g2,%g5,%g2
+	and	u3,v3,%g3
+	or	%g3,%g2,%g2
+	srlx	%g2,63,cy
+	stx	%g5,[rp-8]
+
+	addcc	n,4,n
+	bz,pn	%xcc,.Lret
+	fanop
+
+.Loop0:	ldx	[up],u0
+	add	up,8,up
+	ldx	[vp],v0
+	add	vp,8,vp
+	add	rp,8,rp
+	subcc	n,1,n
+	add	u0,v0,%g1
+	or	u0,v0,%g2
+	add	%g1,cy,%g5
+	and	u0,v0,%g3
+	andn	%g2,%g5,%g2
+	stx	%g5,[rp-8]
+	or	%g3,%g2,%g2
+	bnz,pt	%xcc,.Loop0
+	srlx	%g2,63,cy
+
+.Lret:	mov	cy,%i0
+	ret
+	restore
+EPILOGUE()
diff --git a/third_party/gmp/mpn/sparc64/ultrasparc1234/addmul_1.asm b/third_party/gmp/mpn/sparc64/ultrasparc1234/addmul_1.asm
new file mode 100644
index 0000000..48a9414
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/ultrasparc1234/addmul_1.asm
@@ -0,0 +1,606 @@
+dnl  SPARC v9 64-bit mpn_addmul_1 -- Multiply a limb vector with a limb and add
+dnl  the result to a second limb vector.
+
+dnl  Copyright 1998, 2000-2004 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		   cycles/limb
+C UltraSPARC 1&2:     14
+C UltraSPARC 3:	      17.5
+
+C Algorithm: We use eight floating-point multiplies per limb product, with the
+C invariant v operand split into four 16-bit pieces, and the up operand split
+C into 32-bit pieces.  We sum pairs of 48-bit partial products using
+C floating-point add, then convert the four 49-bit product-sums and transfer
+C them to the integer unit.
+
+C Possible optimizations:
+C   0. Rewrite to use algorithm of mpn_addmul_2.
+C   1. Align the stack area where we transfer the four 49-bit product-sums
+C      to a 32-byte boundary.  That would minimize the cache collision.
+C      (UltraSPARC-1/2 use a direct-mapped cache.)  (Perhaps even better would
+C      be to align the area to map to the area immediately before up?)
+C   2. Sum the 4 49-bit quantities using 32-bit operations, as in the
+C      develop mpn_addmul_2.  This would save many integer instructions.
+C   3. Unrolling.  Questionable if it is worth the code expansion, given that
+C      it could only save 1 cycle/limb.
+C   4. Specialize for particular v values.  If its upper 32 bits are zero, we
+C      could save many operations, in the FPU (fmuld), but more so in the IEU
+C      since we'll be summing 48-bit quantities, which might be simpler.
+C   5. Ideally, we should schedule the f2/f3 and f4/f5 RAW further apart, and
+C      the i00,i16,i32,i48 RAW less apart.  The latter apart-scheduling should
+C      not be greater than needed for L2 cache latency, and also not so great
+C      that i16 needs to be copied.
+C   6. Avoid performing mem+fa+fm in the same cycle, at least not when we want
+C      to get high IEU bandwidth.  (12 of the 14 cycles will be free for 2 IEU
+C      ops.)
+
+C Instruction classification (as per UltraSPARC-1/2 functional units):
+C    8 FM
+C   10 FA
+C   12 MEM
+C   10 ISHIFT + 14 IADDLOG
+C    1 BRANCH
+C   55 insns totally (plus one mov insn that should be optimized out)
+
+C The loop executes 56 instructions in 14 cycles on UltraSPARC-1/2, i.e we
+C sustain the peak execution rate of 4 instructions/cycle.
+
+C INPUT PARAMETERS
+C rp	i0
+C up	i1
+C n	i2
+C v	i3
+
+ASM_START()
+	REGISTER(%g2,#scratch)
+	REGISTER(%g3,#scratch)
+
+define(`p00', `%f8') define(`p16',`%f10') define(`p32',`%f12') define(`p48',`%f14')
+define(`r32',`%f16') define(`r48',`%f18') define(`r64',`%f20') define(`r80',`%f22')
+define(`v00',`%f24') define(`v16',`%f26') define(`v32',`%f28') define(`v48',`%f30')
+define(`u00',`%f32') define(`u32', `%f34')
+define(`a00',`%f36') define(`a16',`%f38') define(`a32',`%f40') define(`a48',`%f42')
+define(`cy',`%g1')
+define(`rlimb',`%g3')
+define(`i00',`%l0') define(`i16',`%l1') define(`i32',`%l2') define(`i48',`%l3')
+define(`xffffffff',`%l7')
+define(`xffff',`%o0')
+
+PROLOGUE(mpn_addmul_1)
+
+C Initialization.  (1) Split v operand into four 16-bit chunks and store them
+C as IEEE double in fp registers.  (2) Clear upper 32 bits of fp register pairs
+C f2 and f4.  (3) Store masks in registers aliased to `xffff' and `xffffffff'.
+
+	save	%sp, -256, %sp
+	mov	-1, %g4
+	srlx	%g4, 48, xffff		C store mask in register `xffff'
+	and	%i3, xffff, %g2
+	stx	%g2, [%sp+2223+0]
+	srlx	%i3, 16, %g3
+	and	%g3, xffff, %g3
+	stx	%g3, [%sp+2223+8]
+	srlx	%i3, 32, %g2
+	and	%g2, xffff, %g2
+	stx	%g2, [%sp+2223+16]
+	srlx	%i3, 48, %g3
+	stx	%g3, [%sp+2223+24]
+	srlx	%g4, 32, xffffffff	C store mask in register `xffffffff'
+
+	sllx	%i2, 3, %i2
+	mov	0, cy			C clear cy
+	add	%i0, %i2, %i0
+	add	%i1, %i2, %i1
+	neg	%i2
+	add	%i1, 4, %i5
+	add	%i0, -32, %i4
+	add	%i0, -16, %i0
+
+	ldd	[%sp+2223+0], v00
+	ldd	[%sp+2223+8], v16
+	ldd	[%sp+2223+16], v32
+	ldd	[%sp+2223+24], v48
+	ld	[%sp+2223+0],%f2	C zero f2
+	ld	[%sp+2223+0],%f4	C zero f4
+	ld	[%i5+%i2], %f3		C read low 32 bits of up[i]
+	ld	[%i1+%i2], %f5		C read high 32 bits of up[i]
+	fxtod	v00, v00
+	fxtod	v16, v16
+	fxtod	v32, v32
+	fxtod	v48, v48
+
+C Start real work.  (We sneakingly read f3 and f5 above...)
+C The software pipeline is very deep, requiring 4 feed-in stages.
+
+	fxtod	%f2, u00
+	fxtod	%f4, u32
+	fmuld	u00, v00, a00
+	fmuld	u00, v16, a16
+	fmuld	u00, v32, p32
+	fmuld	u32, v00, r32
+	fmuld	u00, v48, p48
+	addcc	%i2, 8, %i2
+	bnz,pt	%xcc, .L_two_or_more
+	fmuld	u32, v16, r48
+
+.L_one:
+	fmuld	u32, v32, r64	C FIXME not urgent
+	faddd	p32, r32, a32
+	fdtox	a00, a00
+	faddd	p48, r48, a48
+	fmuld	u32, v48, r80	C FIXME not urgent
+	fdtox	a16, a16
+	fdtox	a32, a32
+	fdtox	a48, a48
+	std	a00, [%sp+2223+0]
+	std	a16, [%sp+2223+8]
+	std	a32, [%sp+2223+16]
+	std	a48, [%sp+2223+24]
+	add	%i2, 8, %i2
+
+	fdtox	r64, a00
+	ldx	[%i0+%i2], rlimb	C read rp[i]
+	fdtox	r80, a16
+	ldx	[%sp+2223+0], i00
+	ldx	[%sp+2223+8], i16
+	ldx	[%sp+2223+16], i32
+	ldx	[%sp+2223+24], i48
+	std	a00, [%sp+2223+0]
+	std	a16, [%sp+2223+8]
+	add	%i2, 8, %i2
+
+	srlx	rlimb, 32, %g4		C HI(rlimb)
+	and	rlimb, xffffffff, %g5	C LO(rlimb)
+	add	i00, %g5, %g5		C i00+ now in g5
+	ldx	[%sp+2223+0], i00
+	srlx	i16, 48, %l4		C (i16 >> 48)
+	mov	i16, %g2
+	ldx	[%sp+2223+8], i16
+	srlx	i48, 16, %l5		C (i48 >> 16)
+	add	i32, %g4, %g4		C i32+ now in g4
+	sllx	i48, 32, %l6		C (i48 << 32)
+	srlx	%g4, 32, %o3		C (i32 >> 32)
+	add	%l5, %l4, %o1		C hi64- in %o1
+	std	a00, [%sp+2223+0]
+	sllx	%g4, 16, %o2		C (i32 << 16)
+	add	%o3, %o1, %o1		C hi64 in %o1   1st ASSIGNMENT
+	std	a16, [%sp+2223+8]
+	sllx	%o1, 48, %o3		C (hi64 << 48)
+	add	%g2, %o2, %o2		C mi64- in %o2
+	add	%l6, %o2, %o2		C mi64- in %o2
+	sub	%o2, %o3, %o2		C mi64 in %o2   1st ASSIGNMENT
+	add	cy, %g5, %o4		C x = prev(i00) + cy
+	b	.L_out_1
+	add	%i2, 8, %i2
+
+.L_two_or_more:
+	ld	[%i5+%i2], %f3		C read low 32 bits of up[i]
+	fmuld	u32, v32, r64	C FIXME not urgent
+	faddd	p32, r32, a32
+	ld	[%i1+%i2], %f5		C read high 32 bits of up[i]
+	fdtox	a00, a00
+	faddd	p48, r48, a48
+	fmuld	u32, v48, r80	C FIXME not urgent
+	fdtox	a16, a16
+	fdtox	a32, a32
+	fxtod	%f2, u00
+	fxtod	%f4, u32
+	fdtox	a48, a48
+	std	a00, [%sp+2223+0]
+	fmuld	u00, v00, p00
+	std	a16, [%sp+2223+8]
+	fmuld	u00, v16, p16
+	std	a32, [%sp+2223+16]
+	fmuld	u00, v32, p32
+	std	a48, [%sp+2223+24]
+	faddd	p00, r64, a00
+	fmuld	u32, v00, r32
+	faddd	p16, r80, a16
+	fmuld	u00, v48, p48
+	addcc	%i2, 8, %i2
+	bnz,pt	%xcc, .L_three_or_more
+	fmuld	u32, v16, r48
+
+.L_two:
+	fmuld	u32, v32, r64	C FIXME not urgent
+	faddd	p32, r32, a32
+	fdtox	a00, a00
+	ldx	[%i0+%i2], rlimb	C read rp[i]
+	faddd	p48, r48, a48
+	fmuld	u32, v48, r80	C FIXME not urgent
+	fdtox	a16, a16
+	ldx	[%sp+2223+0], i00
+	fdtox	a32, a32
+	ldx	[%sp+2223+8], i16
+	ldx	[%sp+2223+16], i32
+	ldx	[%sp+2223+24], i48
+	fdtox	a48, a48
+	std	a00, [%sp+2223+0]
+	std	a16, [%sp+2223+8]
+	std	a32, [%sp+2223+16]
+	std	a48, [%sp+2223+24]
+	add	%i2, 8, %i2
+
+	fdtox	r64, a00
+	srlx	rlimb, 32, %g4		C HI(rlimb)
+	and	rlimb, xffffffff, %g5	C LO(rlimb)
+	ldx	[%i0+%i2], rlimb	C read rp[i]
+	add	i00, %g5, %g5		C i00+ now in g5
+	fdtox	r80, a16
+	ldx	[%sp+2223+0], i00
+	srlx	i16, 48, %l4		C (i16 >> 48)
+	mov	i16, %g2
+	ldx	[%sp+2223+8], i16
+	srlx	i48, 16, %l5		C (i48 >> 16)
+	add	i32, %g4, %g4		C i32+ now in g4
+	ldx	[%sp+2223+16], i32
+	sllx	i48, 32, %l6		C (i48 << 32)
+	ldx	[%sp+2223+24], i48
+	srlx	%g4, 32, %o3		C (i32 >> 32)
+	add	%l5, %l4, %o1		C hi64- in %o1
+	std	a00, [%sp+2223+0]
+	sllx	%g4, 16, %o2		C (i32 << 16)
+	add	%o3, %o1, %o1		C hi64 in %o1   1st ASSIGNMENT
+	std	a16, [%sp+2223+8]
+	sllx	%o1, 48, %o3		C (hi64 << 48)
+	add	%g2, %o2, %o2		C mi64- in %o2
+	add	%l6, %o2, %o2		C mi64- in %o2
+	sub	%o2, %o3, %o2		C mi64 in %o2   1st ASSIGNMENT
+	add	cy, %g5, %o4		C x = prev(i00) + cy
+	b	.L_out_2
+	add	%i2, 8, %i2
+
+.L_three_or_more:
+	ld	[%i5+%i2], %f3		C read low 32 bits of up[i]
+	fmuld	u32, v32, r64	C FIXME not urgent
+	faddd	p32, r32, a32
+	ld	[%i1+%i2], %f5		C read high 32 bits of up[i]
+	fdtox	a00, a00
+	ldx	[%i0+%i2], rlimb	C read rp[i]
+	faddd	p48, r48, a48
+	fmuld	u32, v48, r80	C FIXME not urgent
+	fdtox	a16, a16
+	ldx	[%sp+2223+0], i00
+	fdtox	a32, a32
+	ldx	[%sp+2223+8], i16
+	fxtod	%f2, u00
+	ldx	[%sp+2223+16], i32
+	fxtod	%f4, u32
+	ldx	[%sp+2223+24], i48
+	fdtox	a48, a48
+	std	a00, [%sp+2223+0]
+	fmuld	u00, v00, p00
+	std	a16, [%sp+2223+8]
+	fmuld	u00, v16, p16
+	std	a32, [%sp+2223+16]
+	fmuld	u00, v32, p32
+	std	a48, [%sp+2223+24]
+	faddd	p00, r64, a00
+	fmuld	u32, v00, r32
+	faddd	p16, r80, a16
+	fmuld	u00, v48, p48
+	addcc	%i2, 8, %i2
+	bnz,pt	%xcc, .L_four_or_more
+	fmuld	u32, v16, r48
+
+.L_three:
+	fmuld	u32, v32, r64	C FIXME not urgent
+	faddd	p32, r32, a32
+	fdtox	a00, a00
+	srlx	rlimb, 32, %g4		C HI(rlimb)
+	and	rlimb, xffffffff, %g5	C LO(rlimb)
+	ldx	[%i0+%i2], rlimb	C read rp[i]
+	faddd	p48, r48, a48
+	add	i00, %g5, %g5		C i00+ now in g5
+	fmuld	u32, v48, r80	C FIXME not urgent
+	fdtox	a16, a16
+	ldx	[%sp+2223+0], i00
+	fdtox	a32, a32
+	srlx	i16, 48, %l4		C (i16 >> 48)
+	mov	i16, %g2
+	ldx	[%sp+2223+8], i16
+	srlx	i48, 16, %l5		C (i48 >> 16)
+	add	i32, %g4, %g4		C i32+ now in g4
+	ldx	[%sp+2223+16], i32
+	sllx	i48, 32, %l6		C (i48 << 32)
+	ldx	[%sp+2223+24], i48
+	fdtox	a48, a48
+	srlx	%g4, 32, %o3		C (i32 >> 32)
+	add	%l5, %l4, %o1		C hi64- in %o1
+	std	a00, [%sp+2223+0]
+	sllx	%g4, 16, %o2		C (i32 << 16)
+	add	%o3, %o1, %o1		C hi64 in %o1   1st ASSIGNMENT
+	std	a16, [%sp+2223+8]
+	sllx	%o1, 48, %o3		C (hi64 << 48)
+	add	%g2, %o2, %o2		C mi64- in %o2
+	std	a32, [%sp+2223+16]
+	add	%l6, %o2, %o2		C mi64- in %o2
+	std	a48, [%sp+2223+24]
+	sub	%o2, %o3, %o2		C mi64 in %o2   1st ASSIGNMENT
+	add	cy, %g5, %o4		C x = prev(i00) + cy
+	b	.L_out_3
+	add	%i2, 8, %i2
+
+.L_four_or_more:
+	ld	[%i5+%i2], %f3		C read low 32 bits of up[i]
+	fmuld	u32, v32, r64	C FIXME not urgent
+	faddd	p32, r32, a32
+	ld	[%i1+%i2], %f5		C read high 32 bits of up[i]
+	fdtox	a00, a00
+	srlx	rlimb, 32, %g4		C HI(rlimb)
+	and	rlimb, xffffffff, %g5	C LO(rlimb)
+	ldx	[%i0+%i2], rlimb	C read rp[i]
+	faddd	p48, r48, a48
+	add	i00, %g5, %g5		C i00+ now in g5
+	fmuld	u32, v48, r80	C FIXME not urgent
+	fdtox	a16, a16
+	ldx	[%sp+2223+0], i00
+	fdtox	a32, a32
+	srlx	i16, 48, %l4		C (i16 >> 48)
+	mov	i16, %g2
+	ldx	[%sp+2223+8], i16
+	fxtod	%f2, u00
+	srlx	i48, 16, %l5		C (i48 >> 16)
+	add	i32, %g4, %g4		C i32+ now in g4
+	ldx	[%sp+2223+16], i32
+	fxtod	%f4, u32
+	sllx	i48, 32, %l6		C (i48 << 32)
+	ldx	[%sp+2223+24], i48
+	fdtox	a48, a48
+	srlx	%g4, 32, %o3		C (i32 >> 32)
+	add	%l5, %l4, %o1		C hi64- in %o1
+	std	a00, [%sp+2223+0]
+	fmuld	u00, v00, p00
+	sllx	%g4, 16, %o2		C (i32 << 16)
+	add	%o3, %o1, %o1		C hi64 in %o1   1st ASSIGNMENT
+	std	a16, [%sp+2223+8]
+	fmuld	u00, v16, p16
+	sllx	%o1, 48, %o3		C (hi64 << 48)
+	add	%g2, %o2, %o2		C mi64- in %o2
+	std	a32, [%sp+2223+16]
+	fmuld	u00, v32, p32
+	add	%l6, %o2, %o2		C mi64- in %o2
+	std	a48, [%sp+2223+24]
+	faddd	p00, r64, a00
+	fmuld	u32, v00, r32
+	sub	%o2, %o3, %o2		C mi64 in %o2   1st ASSIGNMENT
+	faddd	p16, r80, a16
+	fmuld	u00, v48, p48
+	add	cy, %g5, %o4		C x = prev(i00) + cy
+	addcc	%i2, 8, %i2
+	bnz,pt	%xcc, .Loop
+	fmuld	u32, v16, r48
+
+.L_four:
+	b,a	.L_out_4
+
+C BEGIN MAIN LOOP
+	.align	16
+.Loop:
+C 00
+	srlx	%o4, 16, %o5		C (x >> 16)
+	ld	[%i5+%i2], %f3		C read low 32 bits of up[i]
+	fmuld	u32, v32, r64	C FIXME not urgent
+	faddd	p32, r32, a32
+C 01
+	add	%o5, %o2, %o2		C mi64 in %o2   2nd ASSIGNMENT
+	and	%o4, xffff, %o5		C (x & 0xffff)
+	ld	[%i1+%i2], %f5		C read high 32 bits of up[i]
+	fdtox	a00, a00
+C 02
+	srlx	rlimb, 32, %g4		C HI(rlimb)
+	and	rlimb, xffffffff, %g5	C LO(rlimb)
+	ldx	[%i0+%i2], rlimb	C read rp[i]
+	faddd	p48, r48, a48
+C 03
+	srlx	%o2, 48, %o7		C (mi64 >> 48)
+	add	i00, %g5, %g5		C i00+ now in g5
+	fmuld	u32, v48, r80	C FIXME not urgent
+	fdtox	a16, a16
+C 04
+	sllx	%o2, 16, %i3		C (mi64 << 16)
+	add	%o7, %o1, cy		C new cy
+	ldx	[%sp+2223+0], i00
+	fdtox	a32, a32
+C 05
+	srlx	i16, 48, %l4		C (i16 >> 48)
+	mov	i16, %g2
+	ldx	[%sp+2223+8], i16
+	fxtod	%f2, u00
+C 06
+	srlx	i48, 16, %l5		C (i48 >> 16)
+	add	i32, %g4, %g4		C i32+ now in g4
+	ldx	[%sp+2223+16], i32
+	fxtod	%f4, u32
+C 07
+	sllx	i48, 32, %l6		C (i48 << 32)
+	or	%i3, %o5, %o5
+	ldx	[%sp+2223+24], i48
+	fdtox	a48, a48
+C 08
+	srlx	%g4, 32, %o3		C (i32 >> 32)
+	add	%l5, %l4, %o1		C hi64- in %o1
+	std	a00, [%sp+2223+0]
+	fmuld	u00, v00, p00
+C 09
+	sllx	%g4, 16, %o2		C (i32 << 16)
+	add	%o3, %o1, %o1		C hi64 in %o1   1st ASSIGNMENT
+	std	a16, [%sp+2223+8]
+	fmuld	u00, v16, p16
+C 10
+	sllx	%o1, 48, %o3		C (hi64 << 48)
+	add	%g2, %o2, %o2		C mi64- in %o2
+	std	a32, [%sp+2223+16]
+	fmuld	u00, v32, p32
+C 11
+	add	%l6, %o2, %o2		C mi64- in %o2
+	std	a48, [%sp+2223+24]
+	faddd	p00, r64, a00
+	fmuld	u32, v00, r32
+C 12
+	sub	%o2, %o3, %o2		C mi64 in %o2   1st ASSIGNMENT
+	stx	%o5, [%i4+%i2]
+	faddd	p16, r80, a16
+	fmuld	u00, v48, p48
+C 13
+	add	cy, %g5, %o4		C x = prev(i00) + cy
+	addcc	%i2, 8, %i2
+	bnz,pt	%xcc, .Loop
+	fmuld	u32, v16, r48
+C END MAIN LOOP
+
+.L_out_4:
+	srlx	%o4, 16, %o5		C (x >> 16)
+	fmuld	u32, v32, r64	C FIXME not urgent
+	faddd	p32, r32, a32
+	add	%o5, %o2, %o2		C mi64 in %o2   2nd ASSIGNMENT
+	and	%o4, xffff, %o5		C (x & 0xffff)
+	fdtox	a00, a00
+	srlx	rlimb, 32, %g4		C HI(rlimb)
+	and	rlimb, xffffffff, %g5	C LO(rlimb)
+	ldx	[%i0+%i2], rlimb	C read rp[i]
+	faddd	p48, r48, a48
+	srlx	%o2, 48, %o7		C (mi64 >> 48)
+	add	i00, %g5, %g5		C i00+ now in g5
+	fmuld	u32, v48, r80	C FIXME not urgent
+	fdtox	a16, a16
+	sllx	%o2, 16, %i3		C (mi64 << 16)
+	add	%o7, %o1, cy		C new cy
+	ldx	[%sp+2223+0], i00
+	fdtox	a32, a32
+	srlx	i16, 48, %l4		C (i16 >> 48)
+	mov	i16, %g2
+	ldx	[%sp+2223+8], i16
+	srlx	i48, 16, %l5		C (i48 >> 16)
+	add	i32, %g4, %g4		C i32+ now in g4
+	ldx	[%sp+2223+16], i32
+	sllx	i48, 32, %l6		C (i48 << 32)
+	or	%i3, %o5, %o5
+	ldx	[%sp+2223+24], i48
+	fdtox	a48, a48
+	srlx	%g4, 32, %o3		C (i32 >> 32)
+	add	%l5, %l4, %o1		C hi64- in %o1
+	std	a00, [%sp+2223+0]
+	sllx	%g4, 16, %o2		C (i32 << 16)
+	add	%o3, %o1, %o1		C hi64 in %o1   1st ASSIGNMENT
+	std	a16, [%sp+2223+8]
+	sllx	%o1, 48, %o3		C (hi64 << 48)
+	add	%g2, %o2, %o2		C mi64- in %o2
+	std	a32, [%sp+2223+16]
+	add	%l6, %o2, %o2		C mi64- in %o2
+	std	a48, [%sp+2223+24]
+	sub	%o2, %o3, %o2		C mi64 in %o2   1st ASSIGNMENT
+	stx	%o5, [%i4+%i2]
+	add	cy, %g5, %o4		C x = prev(i00) + cy
+	add	%i2, 8, %i2
+.L_out_3:
+	srlx	%o4, 16, %o5		C (x >> 16)
+	add	%o5, %o2, %o2		C mi64 in %o2   2nd ASSIGNMENT
+	and	%o4, xffff, %o5		C (x & 0xffff)
+	fdtox	r64, a00
+	srlx	rlimb, 32, %g4		C HI(rlimb)
+	and	rlimb, xffffffff, %g5	C LO(rlimb)
+	ldx	[%i0+%i2], rlimb	C read rp[i]
+	srlx	%o2, 48, %o7		C (mi64 >> 48)
+	add	i00, %g5, %g5		C i00+ now in g5
+	fdtox	r80, a16
+	sllx	%o2, 16, %i3		C (mi64 << 16)
+	add	%o7, %o1, cy		C new cy
+	ldx	[%sp+2223+0], i00
+	srlx	i16, 48, %l4		C (i16 >> 48)
+	mov	i16, %g2
+	ldx	[%sp+2223+8], i16
+	srlx	i48, 16, %l5		C (i48 >> 16)
+	add	i32, %g4, %g4		C i32+ now in g4
+	ldx	[%sp+2223+16], i32
+	sllx	i48, 32, %l6		C (i48 << 32)
+	or	%i3, %o5, %o5
+	ldx	[%sp+2223+24], i48
+	srlx	%g4, 32, %o3		C (i32 >> 32)
+	add	%l5, %l4, %o1		C hi64- in %o1
+	std	a00, [%sp+2223+0]
+	sllx	%g4, 16, %o2		C (i32 << 16)
+	add	%o3, %o1, %o1		C hi64 in %o1   1st ASSIGNMENT
+	std	a16, [%sp+2223+8]
+	sllx	%o1, 48, %o3		C (hi64 << 48)
+	add	%g2, %o2, %o2		C mi64- in %o2
+	add	%l6, %o2, %o2		C mi64- in %o2
+	sub	%o2, %o3, %o2		C mi64 in %o2   1st ASSIGNMENT
+	stx	%o5, [%i4+%i2]
+	add	cy, %g5, %o4		C x = prev(i00) + cy
+	add	%i2, 8, %i2
+.L_out_2:
+	srlx	%o4, 16, %o5		C (x >> 16)
+	add	%o5, %o2, %o2		C mi64 in %o2   2nd ASSIGNMENT
+	and	%o4, xffff, %o5		C (x & 0xffff)
+	srlx	rlimb, 32, %g4		C HI(rlimb)
+	and	rlimb, xffffffff, %g5	C LO(rlimb)
+	srlx	%o2, 48, %o7		C (mi64 >> 48)
+	add	i00, %g5, %g5		C i00+ now in g5
+	sllx	%o2, 16, %i3		C (mi64 << 16)
+	add	%o7, %o1, cy		C new cy
+	ldx	[%sp+2223+0], i00
+	srlx	i16, 48, %l4		C (i16 >> 48)
+	mov	i16, %g2
+	ldx	[%sp+2223+8], i16
+	srlx	i48, 16, %l5		C (i48 >> 16)
+	add	i32, %g4, %g4		C i32+ now in g4
+	sllx	i48, 32, %l6		C (i48 << 32)
+	or	%i3, %o5, %o5
+	srlx	%g4, 32, %o3		C (i32 >> 32)
+	add	%l5, %l4, %o1		C hi64- in %o1
+	sllx	%g4, 16, %o2		C (i32 << 16)
+	add	%o3, %o1, %o1		C hi64 in %o1   1st ASSIGNMENT
+	sllx	%o1, 48, %o3		C (hi64 << 48)
+	add	%g2, %o2, %o2		C mi64- in %o2
+	add	%l6, %o2, %o2		C mi64- in %o2
+	sub	%o2, %o3, %o2		C mi64 in %o2   1st ASSIGNMENT
+	stx	%o5, [%i4+%i2]
+	add	cy, %g5, %o4		C x = prev(i00) + cy
+	add	%i2, 8, %i2
+.L_out_1:
+	srlx	%o4, 16, %o5		C (x >> 16)
+	add	%o5, %o2, %o2		C mi64 in %o2   2nd ASSIGNMENT
+	and	%o4, xffff, %o5		C (x & 0xffff)
+	srlx	%o2, 48, %o7		C (mi64 >> 48)
+	sllx	%o2, 16, %i3		C (mi64 << 16)
+	add	%o7, %o1, cy		C new cy
+	or	%i3, %o5, %o5
+	stx	%o5, [%i4+%i2]
+
+	sllx	i00, 0, %g2
+	add	%g2, cy, cy
+	sllx	i16, 16, %g3
+	add	%g3, cy, cy
+
+	return	%i7+8
+	mov	cy, %o0
+EPILOGUE(mpn_addmul_1)
diff --git a/third_party/gmp/mpn/sparc64/ultrasparc1234/addmul_2.asm b/third_party/gmp/mpn/sparc64/ultrasparc1234/addmul_2.asm
new file mode 100644
index 0000000..37674d7
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/ultrasparc1234/addmul_2.asm
@@ -0,0 +1,551 @@
+dnl  SPARC v9 64-bit mpn_addmul_2 -- Multiply an n limb number with 2-limb
+dnl  number and add the result to a n limb vector.
+
+dnl  Copyright 2002, 2003 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                  cycles/limb
+C UltraSPARC 1&2:      9
+C UltraSPARC 3:       10
+
+C Algorithm: We use 16 floating-point multiplies per limb product, with the
+C 2-limb v operand split into eight 16-bit pieces, and the n-limb u operand
+C split into 32-bit pieces.  We sum four 48-bit partial products using
+C floating-point add, then convert the resulting four 50-bit quantities and
+C transfer them to the integer unit.
+
+C Possible optimizations:
+C   1. Align the stack area where we transfer the four 50-bit product-sums
+C      to a 32-byte boundary.  That would minimize the cache collision.
+C      (UltraSPARC-1/2 use a direct-mapped cache.)  (Perhaps even better would
+C      be to align the area to map to the area immediately before up?)
+C   2. Perform two of the fp->int conversions with integer instructions.  We
+C      can get almost ten free IEU slots, if we clean up bookkeeping and the
+C      silly carry-limb code.
+C   3. For an mpn_addmul_1 based on this, we need to fix the silly carry-limb
+C      code.
+
+C OSP (Overlapping software pipeline) version of mpn_mul_basecase:
+C Operand swap will require 8 LDDA and 8 FXTOD, which will mean 8 cycles.
+C FI	= 20
+C L	=  9 x un * vn
+C WDFI	= 10 x vn / 2
+C WD	= 4
+
+C Instruction classification (as per UltraSPARC functional units).
+C Assuming silly carry code is fixed.  Includes bookkeeping.
+C
+C               mpn_addmul_X     mpn_mul_X
+C                1       2       1       2
+C               ==========      ==========
+C      FM        8      16       8      16
+C      FA       10      18      10      18
+C     MEM       12      12      10      10
+C  ISHIFT        6       6       6       6
+C IADDLOG       11      11      10      10
+C  BRANCH        1       1       1       1
+C
+C TOTAL IEU     17      17      16      16
+C TOTAL         48      64      45      61
+C
+C IEU cycles     8.5     8.5     8       8
+C MEM cycles    12      12      10      10
+C ISSUE cycles  12      16      11.25   15.25
+C FPU cycles    10      18      10      18
+C cycles/loop   12      18      12      18
+C cycles/limb   12       9      12       9
+
+
+C INPUT PARAMETERS
+C rp[n + 1]	i0
+C up[n]		i1
+C n		i2
+C vp[2]		i3
+
+
+ASM_START()
+	REGISTER(%g2,#scratch)
+	REGISTER(%g3,#scratch)
+
+C Combine registers:
+C u00_hi= u32_hi
+C u00_lo= u32_lo
+C a000  = out000
+C a016  = out016
+C Free: f52 f54
+
+
+define(`p000', `%f8')  define(`p016',`%f10')
+define(`p032',`%f12')  define(`p048',`%f14')
+define(`p064',`%f16')  define(`p080',`%f18')
+define(`p096a',`%f20') define(`p112a',`%f22')
+define(`p096b',`%f56') define(`p112b',`%f58')
+
+define(`out000',`%f0') define(`out016',`%f6')
+
+define(`v000',`%f24')  define(`v016',`%f26')
+define(`v032',`%f28')  define(`v048',`%f30')
+define(`v064',`%f44')  define(`v080',`%f46')
+define(`v096',`%f48')  define(`v112',`%f50')
+
+define(`u00',`%f32')   define(`u32', `%f34')
+
+define(`a000',`%f36')  define(`a016',`%f38')
+define(`a032',`%f40')  define(`a048',`%f42')
+define(`a064',`%f60')  define(`a080',`%f62')
+
+define(`u00_hi',`%f2') define(`u32_hi',`%f4')
+define(`u00_lo',`%f3') define(`u32_lo',`%f5')
+
+define(`cy',`%g1')
+define(`rlimb',`%g3')
+define(`i00',`%l0')    define(`i16',`%l1')
+define(`r00',`%l2')    define(`r32',`%l3')
+define(`xffffffff',`%l7')
+define(`xffff',`%o0')
+
+
+PROLOGUE(mpn_addmul_2)
+
+C Initialization.  (1) Split v operand into eight 16-bit chunks and store them
+C as IEEE double in fp registers.  (2) Clear upper 32 bits of fp register pairs
+C f2 and f4.  (3) Store masks in registers aliased to `xffff' and `xffffffff'.
+C This code could be better scheduled.
+
+	save	%sp, -256, %sp
+
+ifdef(`HAVE_VIS',
+`	mov	-1, %g4
+	wr	%g0, 0xD2, %asi
+	srlx	%g4, 32, xffffffff	C store mask in register `xffffffff'
+	ldda	[%i3+6] %asi, v000
+	ldda	[%i3+4] %asi, v016
+	ldda	[%i3+2] %asi, v032
+	ldda	[%i3+0] %asi, v048
+	fxtod	v000, v000
+	ldda	[%i3+14] %asi, v064
+	fxtod	v016, v016
+	ldda	[%i3+12] %asi, v080
+	fxtod	v032, v032
+	ldda	[%i3+10] %asi, v096
+	fxtod	v048, v048
+	ldda	[%i3+8] %asi, v112
+	fxtod	v064, v064
+	fxtod	v080, v080
+	fxtod	v096, v096
+	fxtod	v112, v112
+	fzero	u00_hi
+	fzero	u32_hi
+',
+`	mov	-1, %g4
+	ldx	[%i3+0], %l0		C vp[0]
+	srlx	%g4, 48, xffff		C store mask in register `xffff'
+	ldx	[%i3+8], %l1		C vp[1]
+
+	and	%l0, xffff, %g2
+	stx	%g2, [%sp+2223+0]
+	srlx	%l0, 16, %g3
+	and	%g3, xffff, %g3
+	stx	%g3, [%sp+2223+8]
+	srlx	%l0, 32, %g2
+	and	%g2, xffff, %g2
+	stx	%g2, [%sp+2223+16]
+	srlx	%l0, 48, %g3
+	stx	%g3, [%sp+2223+24]
+	and	%l1, xffff, %g2
+	stx	%g2, [%sp+2223+32]
+	srlx	%l1, 16, %g3
+	and	%g3, xffff, %g3
+	stx	%g3, [%sp+2223+40]
+	srlx	%l1, 32, %g2
+	and	%g2, xffff, %g2
+	stx	%g2, [%sp+2223+48]
+	srlx	%l1, 48, %g3
+	stx	%g3, [%sp+2223+56]
+
+	srlx	%g4, 32, xffffffff	C store mask in register `xffffffff'
+
+	ldd	[%sp+2223+0], v000
+	ldd	[%sp+2223+8], v016
+	ldd	[%sp+2223+16], v032
+	ldd	[%sp+2223+24], v048
+	fxtod	v000, v000
+	ldd	[%sp+2223+32], v064
+	fxtod	v016, v016
+	ldd	[%sp+2223+40], v080
+	fxtod	v032, v032
+	ldd	[%sp+2223+48], v096
+	fxtod	v048, v048
+	ldd	[%sp+2223+56], v112
+	fxtod	v064, v064
+	ld	[%sp+2223+0], u00_hi	C zero u00_hi
+	fxtod	v080, v080
+	ld	[%sp+2223+0], u32_hi	C zero u32_hi
+	fxtod	v096, v096
+	fxtod	v112, v112
+')
+C Initialization done.
+	mov	0, %g2
+	mov	0, rlimb
+	mov	0, %g4
+	add	%i0, -8, %i0		C BOOKKEEPING
+
+C Start software pipeline.
+
+	ld	[%i1+4], u00_lo		C read low 32 bits of up[i]
+	fxtod	u00_hi, u00
+C mid
+	ld	[%i1+0], u32_lo		C read high 32 bits of up[i]
+	fmuld	u00, v000, a000
+	fmuld	u00, v016, a016
+	fmuld	u00, v032, a032
+	fmuld	u00, v048, a048
+	add	%i2, -1, %i2		C BOOKKEEPING
+	fmuld	u00, v064, p064
+	add	%i1, 8, %i1		C BOOKKEEPING
+	fxtod	u32_hi, u32
+	fmuld	u00, v080, p080
+	fmuld	u00, v096, p096a
+	brnz,pt	%i2, .L_2_or_more
+	 fmuld	u00, v112, p112a
+
+.L1:	fdtox	a000, out000
+	fmuld	u32, v000, p000
+	fdtox	a016, out016
+	fmuld	u32, v016, p016
+	fmovd	p064, a064
+	fmuld	u32, v032, p032
+	fmovd	p080, a080
+	fmuld	u32, v048, p048
+	std	out000, [%sp+2223+16]
+	faddd	p000, a032, a000
+	fmuld	u32, v064, p064
+	std	out016, [%sp+2223+24]
+	fxtod	u00_hi, u00
+	faddd	p016, a048, a016
+	fmuld	u32, v080, p080
+	faddd	p032, a064, a032
+	fmuld	u32, v096, p096b
+	faddd	p048, a080, a048
+	fmuld	u32, v112, p112b
+C mid
+	fdtox	a000, out000
+	fdtox	a016, out016
+	faddd	p064, p096a, a064
+	faddd	p080, p112a, a080
+	std	out000, [%sp+2223+0]
+	b	.L_wd2
+	 std	out016, [%sp+2223+8]
+
+.L_2_or_more:
+	ld	[%i1+4], u00_lo		C read low 32 bits of up[i]
+	fdtox	a000, out000
+	fmuld	u32, v000, p000
+	fdtox	a016, out016
+	fmuld	u32, v016, p016
+	fmovd	p064, a064
+	fmuld	u32, v032, p032
+	fmovd	p080, a080
+	fmuld	u32, v048, p048
+	std	out000, [%sp+2223+16]
+	faddd	p000, a032, a000
+	fmuld	u32, v064, p064
+	std	out016, [%sp+2223+24]
+	fxtod	u00_hi, u00
+	faddd	p016, a048, a016
+	fmuld	u32, v080, p080
+	faddd	p032, a064, a032
+	fmuld	u32, v096, p096b
+	faddd	p048, a080, a048
+	fmuld	u32, v112, p112b
+C mid
+	ld	[%i1+0], u32_lo		C read high 32 bits of up[i]
+	fdtox	a000, out000
+	fmuld	u00, v000, p000
+	fdtox	a016, out016
+	fmuld	u00, v016, p016
+	faddd	p064, p096a, a064
+	fmuld	u00, v032, p032
+	faddd	p080, p112a, a080
+	fmuld	u00, v048, p048
+	add	%i2, -1, %i2		C BOOKKEEPING
+	std	out000, [%sp+2223+0]
+	faddd	p000, a032, a000
+	fmuld	u00, v064, p064
+	add	%i1, 8, %i1		C BOOKKEEPING
+	std	out016, [%sp+2223+8]
+	fxtod	u32_hi, u32
+	faddd	p016, a048, a016
+	fmuld	u00, v080, p080
+	faddd	p032, a064, a032
+	fmuld	u00, v096, p096a
+	faddd	p048, a080, a048
+	brnz,pt	%i2, .L_3_or_more
+	 fmuld	u00, v112, p112a
+
+	b	.Lend
+	 nop
+
+C  64      32       0
+C   .       .       .
+C   .       |__rXXX_|	32
+C   .      |___cy___|	34
+C   .  |_______i00__|	50
+C  |_______i16__|   .	50
+
+
+C BEGIN MAIN LOOP
+	.align	16
+.L_3_or_more:
+.Loop:	ld	[%i1+4], u00_lo		C read low 32 bits of up[i]
+	and	%g2, xffffffff, %g2
+	fdtox	a000, out000
+	fmuld	u32, v000, p000
+C
+	lduw	[%i0+4+8], r00		C read low 32 bits of rp[i]
+	add	%g2, rlimb, %l5
+	fdtox	a016, out016
+	fmuld	u32, v016, p016
+C
+	srlx	%l5, 32, cy
+	ldx	[%sp+2223+16], i00
+	faddd	p064, p096b, a064
+	fmuld	u32, v032, p032
+C
+	add	%g4, cy, cy		C new cy
+	ldx	[%sp+2223+24], i16
+	faddd	p080, p112b, a080
+	fmuld	u32, v048, p048
+C
+	nop
+	std	out000, [%sp+2223+16]
+	faddd	p000, a032, a000
+	fmuld	u32, v064, p064
+C
+	add	i00, r00, rlimb
+	add	%i0, 8, %i0		C BOOKKEEPING
+	std	out016, [%sp+2223+24]
+	fxtod	u00_hi, u00
+C
+	sllx	i16, 16, %g2
+	add	cy, rlimb, rlimb
+	faddd	p016, a048, a016
+	fmuld	u32, v080, p080
+C
+	srlx	i16, 16, %g4
+	add	%g2, rlimb, %l5
+	faddd	p032, a064, a032
+	fmuld	u32, v096, p096b
+C
+	stw	%l5, [%i0+4]
+	nop
+	faddd	p048, a080, a048
+	fmuld	u32, v112, p112b
+C midloop
+	ld	[%i1+0], u32_lo		C read high 32 bits of up[i]
+	and	%g2, xffffffff, %g2
+	fdtox	a000, out000
+	fmuld	u00, v000, p000
+C
+	lduw	[%i0+0], r32		C read high 32 bits of rp[i]
+	add	%g2, rlimb, %l5
+	fdtox	a016, out016
+	fmuld	u00, v016, p016
+C
+	srlx	%l5, 32, cy
+	ldx	[%sp+2223+0], i00
+	faddd	p064, p096a, a064
+	fmuld	u00, v032, p032
+C
+	add	%g4, cy, cy		C new cy
+	ldx	[%sp+2223+8], i16
+	faddd	p080, p112a, a080
+	fmuld	u00, v048, p048
+C
+	add	%i2, -1, %i2		C BOOKKEEPING
+	std	out000, [%sp+2223+0]
+	faddd	p000, a032, a000
+	fmuld	u00, v064, p064
+C
+	add	i00, r32, rlimb
+	add	%i1, 8, %i1		C BOOKKEEPING
+	std	out016, [%sp+2223+8]
+	fxtod	u32_hi, u32
+C
+	sllx	i16, 16, %g2
+	add	cy, rlimb, rlimb
+	faddd	p016, a048, a016
+	fmuld	u00, v080, p080
+C
+	srlx	i16, 16, %g4
+	add	%g2, rlimb, %l5
+	faddd	p032, a064, a032
+	fmuld	u00, v096, p096a
+C
+	stw	%l5, [%i0+0]
+	faddd	p048, a080, a048
+	brnz,pt	%i2, .Loop
+	 fmuld	u00, v112, p112a
+C END MAIN LOOP
+
+C WIND-DOWN PHASE 1
+.Lend:	and	%g2, xffffffff, %g2
+	fdtox	a000, out000
+	fmuld	u32, v000, p000
+	lduw	[%i0+4+8], r00		C read low 32 bits of rp[i]
+	add	%g2, rlimb, %l5
+	fdtox	a016, out016
+	fmuld	u32, v016, p016
+	srlx	%l5, 32, cy
+	ldx	[%sp+2223+16], i00
+	faddd	p064, p096b, a064
+	fmuld	u32, v032, p032
+	add	%g4, cy, cy		C new cy
+	ldx	[%sp+2223+24], i16
+	faddd	p080, p112b, a080
+	fmuld	u32, v048, p048
+	std	out000, [%sp+2223+16]
+	faddd	p000, a032, a000
+	fmuld	u32, v064, p064
+	add	i00, r00, rlimb
+	add	%i0, 8, %i0		C BOOKKEEPING
+	std	out016, [%sp+2223+24]
+	sllx	i16, 16, %g2
+	add	cy, rlimb, rlimb
+	faddd	p016, a048, a016
+	fmuld	u32, v080, p080
+	srlx	i16, 16, %g4
+	add	%g2, rlimb, %l5
+	faddd	p032, a064, a032
+	fmuld	u32, v096, p096b
+	stw	%l5, [%i0+4]
+	faddd	p048, a080, a048
+	fmuld	u32, v112, p112b
+C mid
+	and	%g2, xffffffff, %g2
+	fdtox	a000, out000
+	lduw	[%i0+0], r32		C read high 32 bits of rp[i]
+	add	%g2, rlimb, %l5
+	fdtox	a016, out016
+	srlx	%l5, 32, cy
+	ldx	[%sp+2223+0], i00
+	faddd	p064, p096a, a064
+	add	%g4, cy, cy		C new cy
+	ldx	[%sp+2223+8], i16
+	faddd	p080, p112a, a080
+	std	out000, [%sp+2223+0]
+	add	i00, r32, rlimb
+	std	out016, [%sp+2223+8]
+	sllx	i16, 16, %g2
+	add	cy, rlimb, rlimb
+	srlx	i16, 16, %g4
+	add	%g2, rlimb, %l5
+	stw	%l5, [%i0+0]
+
+C WIND-DOWN PHASE 2
+.L_wd2:	and	%g2, xffffffff, %g2
+	fdtox	a032, out000
+	lduw	[%i0+4+8], r00		C read low 32 bits of rp[i]
+	add	%g2, rlimb, %l5
+	fdtox	a048, out016
+	srlx	%l5, 32, cy
+	ldx	[%sp+2223+16], i00
+	add	%g4, cy, cy		C new cy
+	ldx	[%sp+2223+24], i16
+	std	out000, [%sp+2223+16]
+	add	i00, r00, rlimb
+	add	%i0, 8, %i0		C BOOKKEEPING
+	std	out016, [%sp+2223+24]
+	sllx	i16, 16, %g2
+	add	cy, rlimb, rlimb
+	srlx	i16, 16, %g4
+	add	%g2, rlimb, %l5
+	stw	%l5, [%i0+4]
+C mid
+	and	%g2, xffffffff, %g2
+	fdtox	a064, out000
+	lduw	[%i0+0], r32		C read high 32 bits of rp[i]
+	add	%g2, rlimb, %l5
+	fdtox	a080, out016
+	srlx	%l5, 32, cy
+	ldx	[%sp+2223+0], i00
+	add	%g4, cy, cy		C new cy
+	ldx	[%sp+2223+8], i16
+	std	out000, [%sp+2223+0]
+	add	i00, r32, rlimb
+	std	out016, [%sp+2223+8]
+	sllx	i16, 16, %g2
+	add	cy, rlimb, rlimb
+	srlx	i16, 16, %g4
+	add	%g2, rlimb, %l5
+	stw	%l5, [%i0+0]
+
+C WIND-DOWN PHASE 3
+.L_wd3:	and	%g2, xffffffff, %g2
+	fdtox	p096b, out000
+	add	%g2, rlimb, %l5
+	fdtox	p112b, out016
+	srlx	%l5, 32, cy
+	ldx	[%sp+2223+16], rlimb
+	add	%g4, cy, cy		C new cy
+	ldx	[%sp+2223+24], i16
+	std	out000, [%sp+2223+16]
+	add	%i0, 8, %i0		C BOOKKEEPING
+	std	out016, [%sp+2223+24]
+	sllx	i16, 16, %g2
+	add	cy, rlimb, rlimb
+	srlx	i16, 16, %g4
+	add	%g2, rlimb, %l5
+	stw	%l5, [%i0+4]
+C mid
+	and	%g2, xffffffff, %g2
+	add	%g2, rlimb, %l5
+	srlx	%l5, 32, cy
+	ldx	[%sp+2223+0], rlimb
+	add	%g4, cy, cy		C new cy
+	ldx	[%sp+2223+8], i16
+	sllx	i16, 16, %g2
+	add	cy, rlimb, rlimb
+	srlx	i16, 16, %g4
+	add	%g2, rlimb, %l5
+	stw	%l5, [%i0+0]
+
+	and	%g2, xffffffff, %g2
+	add	%g2, rlimb, %l5
+	srlx	%l5, 32, cy
+	ldx	[%sp+2223+16], i00
+	add	%g4, cy, cy		C new cy
+	ldx	[%sp+2223+24], i16
+
+	sllx	i16, 16, %g2
+	add	i00, cy, cy
+	return	%i7+8
+	add	%g2, cy, %o0
+EPILOGUE(mpn_addmul_2)
diff --git a/third_party/gmp/mpn/sparc64/ultrasparc1234/lshiftc.asm b/third_party/gmp/mpn/sparc64/ultrasparc1234/lshiftc.asm
new file mode 100644
index 0000000..47286d5
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/ultrasparc1234/lshiftc.asm
@@ -0,0 +1,165 @@
+dnl  SPARC v9 mpn_lshiftc
+
+dnl  Copyright 1996, 2000-2003, 2010 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+C		   cycles/limb
+C UltraSPARC 1&2:     3
+C UltraSPARC 3:	      2.67
+
+C INPUT PARAMETERS
+define(`rp', `%i0')
+define(`up', `%i1')
+define(`n',  `%i2')
+define(`cnt',`%i3')
+
+define(`u0', `%l0')
+define(`u1', `%l2')
+define(`u2', `%l4')
+define(`u3', `%l6')
+
+define(`tnc',`%i4')
+
+define(`fanop',`fitod %f0,%f2')		dnl  A quasi nop running in the FA pipe
+
+ASM_START()
+	REGISTER(%g2,#scratch)
+	REGISTER(%g3,#scratch)
+PROLOGUE(mpn_lshiftc)
+	save	%sp,-160,%sp
+
+	sllx	n,3,%g1
+	sub	%g0,cnt,tnc		C negate shift count
+	add	up,%g1,up		C make %o1 point at end of src
+	add	rp,%g1,rp		C make %o0 point at end of res
+	ldx	[up-8],u3		C load first limb
+	subcc	n,5,n
+	srlx	u3,tnc,%i5		C compute function result
+	bl,pn	%xcc,.Lend1234
+	sllx	u3,cnt,%g3
+
+	subcc	n,4,n
+	ldx	[up-16],u0
+	ldx	[up-24],u1
+	add	up,-32,up
+	ldx	[up-0],u2
+	ldx	[up-8],u3
+	srlx	u0,tnc,%g2
+	bl,pn	%xcc,.Lend5678
+	not	%g3, %g3
+
+	b,a	.Loop
+	ALIGN(16)
+.Loop:
+	sllx	u0,cnt,%g1
+	andn	%g3,%g2,%g3
+	ldx	[up-16],u0
+	fanop
+C --
+	srlx	u1,tnc,%g2
+	subcc	n,4,n
+	stx	%g3,[rp-8]
+	not	%g1, %g1
+C --
+	sllx	u1,cnt,%g3
+	andn	%g1,%g2,%g1
+	ldx	[up-24],u1
+	fanop
+C --
+	srlx	u2,tnc,%g2
+	stx	%g1,[rp-16]
+	add	up,-32,up
+	not	%g3, %g3
+C --
+	sllx	u2,cnt,%g1
+	andn	%g3,%g2,%g3
+	ldx	[up-0],u2
+	fanop
+C --
+	srlx	u3,tnc,%g2
+	stx	%g3,[rp-24]
+	add	rp,-32,rp
+	not	%g1, %g1
+C --
+	sllx	u3,cnt,%g3
+	andn	%g1,%g2,%g1
+	ldx	[up-8],u3
+	fanop
+C --
+	srlx	u0,tnc,%g2
+	stx	%g1,[rp-0]
+	bge,pt	%xcc,.Loop
+	not	%g3, %g3
+C --
+.Lend5678:
+	sllx	u0,cnt,%g1
+	andn	%g3,%g2,%g3
+	srlx	u1,tnc,%g2
+	stx	%g3,[rp-8]
+	not	%g1, %g1
+	sllx	u1,cnt,%g3
+	andn	%g1,%g2,%g1
+	srlx	u2,tnc,%g2
+	stx	%g1,[rp-16]
+	not	%g3, %g3
+	sllx	u2,cnt,%g1
+	andn	%g3,%g2,%g3
+	srlx	u3,tnc,%g2
+	stx	%g3,[rp-24]
+	add	rp,-32,rp
+	not	%g1, %g1
+	sllx	u3,cnt,%g3		C carry...
+	andn	%g1,%g2,%g1
+	stx	%g1,[rp-0]
+
+.Lend1234:
+	addcc	n,4,n
+	bz,pn	%xcc,.Lret
+	fanop
+.Loop0:
+	add	rp,-8,rp
+	subcc	n,1,n
+	ldx	[up-16],u3
+	add	up,-8,up
+	srlx	u3,tnc,%g2
+	not	%g3, %g3
+	andn	%g3,%g2,%g3
+	stx	%g3,[rp]
+	sllx	u3,cnt,%g3
+	bnz,pt	%xcc,.Loop0
+	fanop
+.Lret:
+	not	%g3, %g3
+	stx	%g3,[rp-8]
+	mov	%i5,%i0
+	ret
+	restore
+EPILOGUE()
diff --git a/third_party/gmp/mpn/sparc64/ultrasparc1234/mul_1.asm b/third_party/gmp/mpn/sparc64/ultrasparc1234/mul_1.asm
new file mode 100644
index 0000000..871d562
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/ultrasparc1234/mul_1.asm
@@ -0,0 +1,580 @@
+dnl  SPARC v9 64-bit mpn_mul_1 -- Multiply a limb vector with a limb and store
+dnl  the result in a second limb vector.
+
+dnl  Copyright 1998, 2000-2003 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		   cycles/limb
+C UltraSPARC 1&2:     14
+C UltraSPARC 3:	      18.5
+
+C Algorithm: We use eight floating-point multiplies per limb product, with the
+C invariant v operand split into four 16-bit pieces, and the s1 operand split
+C into 32-bit pieces.  We sum pairs of 48-bit partial products using
+C floating-point add, then convert the four 49-bit product-sums and transfer
+C them to the integer unit.
+
+C Possible optimizations:
+C   1. Align the stack area where we transfer the four 49-bit product-sums
+C      to a 32-byte boundary.  That would minimize the cache collision.
+C      (UltraSPARC-1/2 use a direct-mapped cache.)  (Perhaps even better would
+C      be to align the area to map to the area immediately before s1?)
+C   2. Sum the 4 49-bit quantities using 32-bit operations, as in the
+C      develop mpn_addmul_2.  This would save many integer instructions.
+C   3. Unrolling.  Questionable if it is worth the code expansion, given that
+C      it could only save 1 cycle/limb.
+C   4. Specialize for particular v values.  If its upper 32 bits are zero, we
+C      could save many operations, in the FPU (fmuld), but more so in the IEU
+C      since we'll be summing 48-bit quantities, which might be simpler.
+C   5. Ideally, we should schedule the f2/f3 and f4/f5 RAW further apart, and
+C      the i00,i16,i32,i48 RAW less apart.  The latter apart-scheduling should
+C      not be greater than needed for L2 cache latency, and also not so great
+C      that i16 needs to be copied.
+C   6. Avoid performing mem+fa+fm in the same cycle, at least not when we want
+C      to get high IEU bandwidth.  (12 of the 14 cycles will be free for 2 IEU
+C      ops.)
+
+C Instruction classification (as per UltraSPARC-1/2 functional units):
+C    8 FM
+C   10 FA
+C   11 MEM
+C   9 ISHIFT + 10? IADDLOG
+C    1 BRANCH
+C   49 insns totally (plus three mov insns that should be optimized out)
+
+C The loop executes 53 instructions in 14 cycles on UltraSPARC-1/2, i.e we
+C sustain 3.79 instructions/cycle.
+
+C INPUT PARAMETERS
+C rp	i0
+C up	i1
+C n	i2
+C v	i3
+
+ASM_START()
+	REGISTER(%g2,#scratch)
+	REGISTER(%g3,#scratch)
+
+define(`p00', `%f8') define(`p16',`%f10') define(`p32',`%f12') define(`p48',`%f14')
+define(`r32',`%f16') define(`r48',`%f18') define(`r64',`%f20') define(`r80',`%f22')
+define(`v00',`%f24') define(`v16',`%f26') define(`v32',`%f28') define(`v48',`%f30')
+define(`u00',`%f32') define(`u32', `%f34')
+define(`a00',`%f36') define(`a16',`%f38') define(`a32',`%f40') define(`a48',`%f42')
+define(`cy',`%g1')
+define(`rlimb',`%g3')
+define(`i00',`%l0') define(`i16',`%l1') define(`i32',`%l2') define(`i48',`%l3')
+define(`xffffffff',`%l7')
+define(`xffff',`%o0')
+
+PROLOGUE(mpn_mul_1)
+
+C Initialization.  (1) Split v operand into four 16-bit chunks and store them
+C as IEEE double in fp registers.  (2) Clear upper 32 bits of fp register pairs
+C f2 and f4.  (3) Store masks in registers aliased to `xffff' and `xffffffff'.
+
+	save	%sp, -256, %sp
+	mov	-1, %g4
+	srlx	%g4, 48, xffff		C store mask in register `xffff'
+	and	%i3, xffff, %g2
+	stx	%g2, [%sp+2223+0]
+	srlx	%i3, 16, %g3
+	and	%g3, xffff, %g3
+	stx	%g3, [%sp+2223+8]
+	srlx	%i3, 32, %g2
+	and	%g2, xffff, %g2
+	stx	%g2, [%sp+2223+16]
+	srlx	%i3, 48, %g3
+	stx	%g3, [%sp+2223+24]
+	srlx	%g4, 32, xffffffff	C store mask in register `xffffffff'
+
+	sllx	%i2, 3, %i2
+	mov	0, cy			C clear cy
+	add	%i0, %i2, %i0
+	add	%i1, %i2, %i1
+	neg	%i2
+	add	%i1, 4, %i5
+	add	%i0, -32, %i4
+	add	%i0, -16, %i0
+
+	ldd	[%sp+2223+0], v00
+	ldd	[%sp+2223+8], v16
+	ldd	[%sp+2223+16], v32
+	ldd	[%sp+2223+24], v48
+	ld	[%sp+2223+0],%f2	C zero f2
+	ld	[%sp+2223+0],%f4	C zero f4
+	ld	[%i5+%i2], %f3		C read low 32 bits of up[i]
+	ld	[%i1+%i2], %f5		C read high 32 bits of up[i]
+	fxtod	v00, v00
+	fxtod	v16, v16
+	fxtod	v32, v32
+	fxtod	v48, v48
+
+C Start real work.  (We sneakingly read f3 and f5 above...)
+C The software pipeline is very deep, requiring 4 feed-in stages.
+
+	fxtod	%f2, u00
+	fxtod	%f4, u32
+	fmuld	u00, v00, a00
+	fmuld	u00, v16, a16
+	fmuld	u00, v32, p32
+	fmuld	u32, v00, r32
+	fmuld	u00, v48, p48
+	addcc	%i2, 8, %i2
+	bnz,pt	%xcc, .L_two_or_more
+	fmuld	u32, v16, r48
+
+.L_one:
+	fmuld	u32, v32, r64	C FIXME not urgent
+	faddd	p32, r32, a32
+	fdtox	a00, a00
+	faddd	p48, r48, a48
+	fmuld	u32, v48, r80	C FIXME not urgent
+	fdtox	a16, a16
+	fdtox	a32, a32
+	fdtox	a48, a48
+	std	a00, [%sp+2223+0]
+	std	a16, [%sp+2223+8]
+	std	a32, [%sp+2223+16]
+	std	a48, [%sp+2223+24]
+	add	%i2, 8, %i2
+
+	fdtox	r64, a00
+	fdtox	r80, a16
+	ldx	[%sp+2223+0], i00
+	ldx	[%sp+2223+8], i16
+	ldx	[%sp+2223+16], i32
+	ldx	[%sp+2223+24], i48
+	std	a00, [%sp+2223+0]
+	std	a16, [%sp+2223+8]
+	add	%i2, 8, %i2
+
+	mov	i00, %g5		C i00+ now in g5
+	ldx	[%sp+2223+0], i00
+	srlx	i16, 48, %l4		C (i16 >> 48)
+	mov	i16, %g2
+	ldx	[%sp+2223+8], i16
+	srlx	i48, 16, %l5		C (i48 >> 16)
+	mov	i32, %g4		C i32+ now in g4
+	sllx	i48, 32, %l6		C (i48 << 32)
+	srlx	%g4, 32, %o3		C (i32 >> 32)
+	add	%l5, %l4, %o1		C hi64- in %o1
+	std	a00, [%sp+2223+0]
+	sllx	%g4, 16, %o2		C (i32 << 16)
+	add	%o3, %o1, %o1		C hi64 in %o1   1st ASSIGNMENT
+	std	a16, [%sp+2223+8]
+	sllx	%o1, 48, %o3		C (hi64 << 48)
+	add	%g2, %o2, %o2		C mi64- in %o2
+	add	%l6, %o2, %o2		C mi64- in %o2
+	sub	%o2, %o3, %o2		C mi64 in %o2   1st ASSIGNMENT
+	add	cy, %g5, %o4		C x = prev(i00) + cy
+	b	.L_out_1
+	add	%i2, 8, %i2
+
+.L_two_or_more:
+	ld	[%i5+%i2], %f3		C read low 32 bits of up[i]
+	fmuld	u32, v32, r64	C FIXME not urgent
+	faddd	p32, r32, a32
+	ld	[%i1+%i2], %f5		C read high 32 bits of up[i]
+	fdtox	a00, a00
+	faddd	p48, r48, a48
+	fmuld	u32, v48, r80	C FIXME not urgent
+	fdtox	a16, a16
+	fdtox	a32, a32
+	fxtod	%f2, u00
+	fxtod	%f4, u32
+	fdtox	a48, a48
+	std	a00, [%sp+2223+0]
+	fmuld	u00, v00, p00
+	std	a16, [%sp+2223+8]
+	fmuld	u00, v16, p16
+	std	a32, [%sp+2223+16]
+	fmuld	u00, v32, p32
+	std	a48, [%sp+2223+24]
+	faddd	p00, r64, a00
+	fmuld	u32, v00, r32
+	faddd	p16, r80, a16
+	fmuld	u00, v48, p48
+	addcc	%i2, 8, %i2
+	bnz,pt	%xcc, .L_three_or_more
+	fmuld	u32, v16, r48
+
+.L_two:
+	fmuld	u32, v32, r64	C FIXME not urgent
+	faddd	p32, r32, a32
+	fdtox	a00, a00
+	faddd	p48, r48, a48
+	fmuld	u32, v48, r80	C FIXME not urgent
+	fdtox	a16, a16
+	ldx	[%sp+2223+0], i00
+	fdtox	a32, a32
+	ldx	[%sp+2223+8], i16
+	ldx	[%sp+2223+16], i32
+	ldx	[%sp+2223+24], i48
+	fdtox	a48, a48
+	std	a00, [%sp+2223+0]
+	std	a16, [%sp+2223+8]
+	std	a32, [%sp+2223+16]
+	std	a48, [%sp+2223+24]
+	add	%i2, 8, %i2
+
+	fdtox	r64, a00
+	mov	i00, %g5		C i00+ now in g5
+	fdtox	r80, a16
+	ldx	[%sp+2223+0], i00
+	srlx	i16, 48, %l4		C (i16 >> 48)
+	mov	i16, %g2
+	ldx	[%sp+2223+8], i16
+	srlx	i48, 16, %l5		C (i48 >> 16)
+	mov	i32, %g4		C i32+ now in g4
+	ldx	[%sp+2223+16], i32
+	sllx	i48, 32, %l6		C (i48 << 32)
+	ldx	[%sp+2223+24], i48
+	srlx	%g4, 32, %o3		C (i32 >> 32)
+	add	%l5, %l4, %o1		C hi64- in %o1
+	std	a00, [%sp+2223+0]
+	sllx	%g4, 16, %o2		C (i32 << 16)
+	add	%o3, %o1, %o1		C hi64 in %o1   1st ASSIGNMENT
+	std	a16, [%sp+2223+8]
+	sllx	%o1, 48, %o3		C (hi64 << 48)
+	add	%g2, %o2, %o2		C mi64- in %o2
+	add	%l6, %o2, %o2		C mi64- in %o2
+	sub	%o2, %o3, %o2		C mi64 in %o2   1st ASSIGNMENT
+	add	cy, %g5, %o4		C x = prev(i00) + cy
+	b	.L_out_2
+	add	%i2, 8, %i2
+
+.L_three_or_more:
+	ld	[%i5+%i2], %f3		C read low 32 bits of up[i]
+	fmuld	u32, v32, r64	C FIXME not urgent
+	faddd	p32, r32, a32
+	ld	[%i1+%i2], %f5		C read high 32 bits of up[i]
+	fdtox	a00, a00
+	faddd	p48, r48, a48
+	fmuld	u32, v48, r80	C FIXME not urgent
+	fdtox	a16, a16
+	ldx	[%sp+2223+0], i00
+	fdtox	a32, a32
+	ldx	[%sp+2223+8], i16
+	fxtod	%f2, u00
+	ldx	[%sp+2223+16], i32
+	fxtod	%f4, u32
+	ldx	[%sp+2223+24], i48
+	fdtox	a48, a48
+	std	a00, [%sp+2223+0]
+	fmuld	u00, v00, p00
+	std	a16, [%sp+2223+8]
+	fmuld	u00, v16, p16
+	std	a32, [%sp+2223+16]
+	fmuld	u00, v32, p32
+	std	a48, [%sp+2223+24]
+	faddd	p00, r64, a00
+	fmuld	u32, v00, r32
+	faddd	p16, r80, a16
+	fmuld	u00, v48, p48
+	addcc	%i2, 8, %i2
+	bnz,pt	%xcc, .L_four_or_more
+	fmuld	u32, v16, r48
+
+.L_three:
+	fmuld	u32, v32, r64	C FIXME not urgent
+	faddd	p32, r32, a32
+	fdtox	a00, a00
+	faddd	p48, r48, a48
+	mov	i00, %g5		C i00+ now in g5
+	fmuld	u32, v48, r80	C FIXME not urgent
+	fdtox	a16, a16
+	ldx	[%sp+2223+0], i00
+	fdtox	a32, a32
+	srlx	i16, 48, %l4		C (i16 >> 48)
+	mov	i16, %g2
+	ldx	[%sp+2223+8], i16
+	srlx	i48, 16, %l5		C (i48 >> 16)
+	mov	i32, %g4		C i32+ now in g4
+	ldx	[%sp+2223+16], i32
+	sllx	i48, 32, %l6		C (i48 << 32)
+	ldx	[%sp+2223+24], i48
+	fdtox	a48, a48
+	srlx	%g4, 32, %o3		C (i32 >> 32)
+	add	%l5, %l4, %o1		C hi64- in %o1
+	std	a00, [%sp+2223+0]
+	sllx	%g4, 16, %o2		C (i32 << 16)
+	add	%o3, %o1, %o1		C hi64 in %o1   1st ASSIGNMENT
+	std	a16, [%sp+2223+8]
+	sllx	%o1, 48, %o3		C (hi64 << 48)
+	add	%g2, %o2, %o2		C mi64- in %o2
+	std	a32, [%sp+2223+16]
+	add	%l6, %o2, %o2		C mi64- in %o2
+	std	a48, [%sp+2223+24]
+	sub	%o2, %o3, %o2		C mi64 in %o2   1st ASSIGNMENT
+	add	cy, %g5, %o4		C x = prev(i00) + cy
+	b	.L_out_3
+	add	%i2, 8, %i2
+
+.L_four_or_more:
+	ld	[%i5+%i2], %f3		C read low 32 bits of up[i]
+	fmuld	u32, v32, r64	C FIXME not urgent
+	faddd	p32, r32, a32
+	ld	[%i1+%i2], %f5		C read high 32 bits of up[i]
+	fdtox	a00, a00
+	faddd	p48, r48, a48
+	mov	i00, %g5		C i00+ now in g5
+	fmuld	u32, v48, r80	C FIXME not urgent
+	fdtox	a16, a16
+	ldx	[%sp+2223+0], i00
+	fdtox	a32, a32
+	srlx	i16, 48, %l4		C (i16 >> 48)
+	mov	i16, %g2
+	ldx	[%sp+2223+8], i16
+	fxtod	%f2, u00
+	srlx	i48, 16, %l5		C (i48 >> 16)
+	mov	i32, %g4		C i32+ now in g4
+	ldx	[%sp+2223+16], i32
+	fxtod	%f4, u32
+	sllx	i48, 32, %l6		C (i48 << 32)
+	ldx	[%sp+2223+24], i48
+	fdtox	a48, a48
+	srlx	%g4, 32, %o3		C (i32 >> 32)
+	add	%l5, %l4, %o1		C hi64- in %o1
+	std	a00, [%sp+2223+0]
+	fmuld	u00, v00, p00
+	sllx	%g4, 16, %o2		C (i32 << 16)
+	add	%o3, %o1, %o1		C hi64 in %o1   1st ASSIGNMENT
+	std	a16, [%sp+2223+8]
+	fmuld	u00, v16, p16
+	sllx	%o1, 48, %o3		C (hi64 << 48)
+	add	%g2, %o2, %o2		C mi64- in %o2
+	std	a32, [%sp+2223+16]
+	fmuld	u00, v32, p32
+	add	%l6, %o2, %o2		C mi64- in %o2
+	std	a48, [%sp+2223+24]
+	faddd	p00, r64, a00
+	fmuld	u32, v00, r32
+	sub	%o2, %o3, %o2		C mi64 in %o2   1st ASSIGNMENT
+	faddd	p16, r80, a16
+	fmuld	u00, v48, p48
+	add	cy, %g5, %o4		C x = prev(i00) + cy
+	addcc	%i2, 8, %i2
+	bnz,pt	%xcc, .Loop
+	fmuld	u32, v16, r48
+
+.L_four:
+	b,a	.L_out_4
+
+C BEGIN MAIN LOOP
+	.align	16
+.Loop:
+C 00
+	srlx	%o4, 16, %o5		C (x >> 16)
+	ld	[%i5+%i2], %f3		C read low 32 bits of up[i]
+	fmuld	u32, v32, r64	C FIXME not urgent
+	faddd	p32, r32, a32
+C 01
+	add	%o5, %o2, %o2		C mi64 in %o2   2nd ASSIGNMENT
+	and	%o4, xffff, %o5		C (x & 0xffff)
+	ld	[%i1+%i2], %f5		C read high 32 bits of up[i]
+	fdtox	a00, a00
+C 02
+	faddd	p48, r48, a48
+C 03
+	srlx	%o2, 48, %o7		C (mi64 >> 48)
+	mov	i00, %g5		C i00+ now in g5
+	fmuld	u32, v48, r80	C FIXME not urgent
+	fdtox	a16, a16
+C 04
+	sllx	%o2, 16, %i3		C (mi64 << 16)
+	add	%o7, %o1, cy		C new cy
+	ldx	[%sp+2223+0], i00
+	fdtox	a32, a32
+C 05
+	srlx	i16, 48, %l4		C (i16 >> 48)
+	mov	i16, %g2
+	ldx	[%sp+2223+8], i16
+	fxtod	%f2, u00
+C 06
+	srlx	i48, 16, %l5		C (i48 >> 16)
+	mov	i32, %g4		C i32+ now in g4
+	ldx	[%sp+2223+16], i32
+	fxtod	%f4, u32
+C 07
+	sllx	i48, 32, %l6		C (i48 << 32)
+	or	%i3, %o5, %o5
+	ldx	[%sp+2223+24], i48
+	fdtox	a48, a48
+C 08
+	srlx	%g4, 32, %o3		C (i32 >> 32)
+	add	%l5, %l4, %o1		C hi64- in %o1
+	std	a00, [%sp+2223+0]
+	fmuld	u00, v00, p00
+C 09
+	sllx	%g4, 16, %o2		C (i32 << 16)
+	add	%o3, %o1, %o1		C hi64 in %o1   1st ASSIGNMENT
+	std	a16, [%sp+2223+8]
+	fmuld	u00, v16, p16
+C 10
+	sllx	%o1, 48, %o3		C (hi64 << 48)
+	add	%g2, %o2, %o2		C mi64- in %o2
+	std	a32, [%sp+2223+16]
+	fmuld	u00, v32, p32
+C 11
+	add	%l6, %o2, %o2		C mi64- in %o2
+	std	a48, [%sp+2223+24]
+	faddd	p00, r64, a00
+	fmuld	u32, v00, r32
+C 12
+	sub	%o2, %o3, %o2		C mi64 in %o2   1st ASSIGNMENT
+	stx	%o5, [%i4+%i2]
+	faddd	p16, r80, a16
+	fmuld	u00, v48, p48
+C 13
+	add	cy, %g5, %o4		C x = prev(i00) + cy
+	addcc	%i2, 8, %i2
+	bnz,pt	%xcc, .Loop
+	fmuld	u32, v16, r48
+C END MAIN LOOP
+
+.L_out_4:
+	srlx	%o4, 16, %o5		C (x >> 16)
+	fmuld	u32, v32, r64	C FIXME not urgent
+	faddd	p32, r32, a32
+	add	%o5, %o2, %o2		C mi64 in %o2   2nd ASSIGNMENT
+	and	%o4, xffff, %o5		C (x & 0xffff)
+	fdtox	a00, a00
+	faddd	p48, r48, a48
+	srlx	%o2, 48, %o7		C (mi64 >> 48)
+	mov	i00, %g5		C i00+ now in g5
+	fmuld	u32, v48, r80	C FIXME not urgent
+	fdtox	a16, a16
+	sllx	%o2, 16, %i3		C (mi64 << 16)
+	add	%o7, %o1, cy		C new cy
+	ldx	[%sp+2223+0], i00
+	fdtox	a32, a32
+	srlx	i16, 48, %l4		C (i16 >> 48)
+	mov	i16, %g2
+	ldx	[%sp+2223+8], i16
+	srlx	i48, 16, %l5		C (i48 >> 16)
+	mov	i32, %g4		C i32+ now in g4
+	ldx	[%sp+2223+16], i32
+	sllx	i48, 32, %l6		C (i48 << 32)
+	or	%i3, %o5, %o5
+	ldx	[%sp+2223+24], i48
+	fdtox	a48, a48
+	srlx	%g4, 32, %o3		C (i32 >> 32)
+	add	%l5, %l4, %o1		C hi64- in %o1
+	std	a00, [%sp+2223+0]
+	sllx	%g4, 16, %o2		C (i32 << 16)
+	add	%o3, %o1, %o1		C hi64 in %o1   1st ASSIGNMENT
+	std	a16, [%sp+2223+8]
+	sllx	%o1, 48, %o3		C (hi64 << 48)
+	add	%g2, %o2, %o2		C mi64- in %o2
+	std	a32, [%sp+2223+16]
+	add	%l6, %o2, %o2		C mi64- in %o2
+	std	a48, [%sp+2223+24]
+	sub	%o2, %o3, %o2		C mi64 in %o2   1st ASSIGNMENT
+	stx	%o5, [%i4+%i2]
+	add	cy, %g5, %o4		C x = prev(i00) + cy
+	add	%i2, 8, %i2
+.L_out_3:
+	srlx	%o4, 16, %o5		C (x >> 16)
+	add	%o5, %o2, %o2		C mi64 in %o2   2nd ASSIGNMENT
+	and	%o4, xffff, %o5		C (x & 0xffff)
+	fdtox	r64, a00
+	srlx	%o2, 48, %o7		C (mi64 >> 48)
+	mov	i00, %g5		C i00+ now in g5
+	fdtox	r80, a16
+	sllx	%o2, 16, %i3		C (mi64 << 16)
+	add	%o7, %o1, cy		C new cy
+	ldx	[%sp+2223+0], i00
+	srlx	i16, 48, %l4		C (i16 >> 48)
+	mov	i16, %g2
+	ldx	[%sp+2223+8], i16
+	srlx	i48, 16, %l5		C (i48 >> 16)
+	mov	i32, %g4		C i32+ now in g4
+	ldx	[%sp+2223+16], i32
+	sllx	i48, 32, %l6		C (i48 << 32)
+	or	%i3, %o5, %o5
+	ldx	[%sp+2223+24], i48
+	srlx	%g4, 32, %o3		C (i32 >> 32)
+	add	%l5, %l4, %o1		C hi64- in %o1
+	std	a00, [%sp+2223+0]
+	sllx	%g4, 16, %o2		C (i32 << 16)
+	add	%o3, %o1, %o1		C hi64 in %o1   1st ASSIGNMENT
+	std	a16, [%sp+2223+8]
+	sllx	%o1, 48, %o3		C (hi64 << 48)
+	add	%g2, %o2, %o2		C mi64- in %o2
+	add	%l6, %o2, %o2		C mi64- in %o2
+	sub	%o2, %o3, %o2		C mi64 in %o2   1st ASSIGNMENT
+	stx	%o5, [%i4+%i2]
+	add	cy, %g5, %o4		C x = prev(i00) + cy
+	add	%i2, 8, %i2
+.L_out_2:
+	srlx	%o4, 16, %o5		C (x >> 16)
+	add	%o5, %o2, %o2		C mi64 in %o2   2nd ASSIGNMENT
+	and	%o4, xffff, %o5		C (x & 0xffff)
+	srlx	%o2, 48, %o7		C (mi64 >> 48)
+	mov	i00, %g5		C i00+ now in g5
+	sllx	%o2, 16, %i3		C (mi64 << 16)
+	add	%o7, %o1, cy		C new cy
+	ldx	[%sp+2223+0], i00
+	srlx	i16, 48, %l4		C (i16 >> 48)
+	mov	i16, %g2
+	ldx	[%sp+2223+8], i16
+	srlx	i48, 16, %l5		C (i48 >> 16)
+	mov	i32, %g4		C i32+ now in g4
+	sllx	i48, 32, %l6		C (i48 << 32)
+	or	%i3, %o5, %o5
+	srlx	%g4, 32, %o3		C (i32 >> 32)
+	add	%l5, %l4, %o1		C hi64- in %o1
+	sllx	%g4, 16, %o2		C (i32 << 16)
+	add	%o3, %o1, %o1		C hi64 in %o1   1st ASSIGNMENT
+	sllx	%o1, 48, %o3		C (hi64 << 48)
+	add	%g2, %o2, %o2		C mi64- in %o2
+	add	%l6, %o2, %o2		C mi64- in %o2
+	sub	%o2, %o3, %o2		C mi64 in %o2   1st ASSIGNMENT
+	stx	%o5, [%i4+%i2]
+	add	cy, %g5, %o4		C x = prev(i00) + cy
+	add	%i2, 8, %i2
+.L_out_1:
+	srlx	%o4, 16, %o5		C (x >> 16)
+	add	%o5, %o2, %o2		C mi64 in %o2   2nd ASSIGNMENT
+	and	%o4, xffff, %o5		C (x & 0xffff)
+	srlx	%o2, 48, %o7		C (mi64 >> 48)
+	sllx	%o2, 16, %i3		C (mi64 << 16)
+	add	%o7, %o1, cy		C new cy
+	or	%i3, %o5, %o5
+	stx	%o5, [%i4+%i2]
+
+	sllx	i00, 0, %g2
+	add	%g2, cy, cy
+	sllx	i16, 16, %g3
+	add	%g3, cy, cy
+
+	return	%i7+8
+	mov	cy, %o0
+EPILOGUE(mpn_mul_1)
diff --git a/third_party/gmp/mpn/sparc64/ultrasparc1234/sqr_diagonal.asm b/third_party/gmp/mpn/sparc64/ultrasparc1234/sqr_diagonal.asm
new file mode 100644
index 0000000..43c69d3
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/ultrasparc1234/sqr_diagonal.asm
@@ -0,0 +1,342 @@
+dnl  SPARC v9 64-bit mpn_sqr_diagonal.
+
+dnl  Copyright 2001, 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		   cycles/limb
+C UltraSPARC 1&2:     22
+C UltraSPARC 3:	      36
+
+C This was generated by the Sun C compiler.  It runs at 22 cycles/limb on the
+C UltraSPARC-1/2, three cycles slower than theoretically possible for optimal
+C code using the same algorithm.  For 1-3 limbs, a special loop was generated,
+C which causes performance problems in particular for 2 and 3 limbs.
+C Ultimately, this should be replaced by hand-written code in the same software
+C pipeline style as e.g., addmul_1.asm.
+
+ASM_START()
+	REGISTER(%g2,#scratch)
+	REGISTER(%g3,#scratch)
+PROLOGUE(mpn_sqr_diagonal)
+	save	%sp, -240, %sp
+
+	sethi	%hi(0x1ffc00), %o0
+	sethi	%hi(0x3ffc00), %o1
+	add	%o0, 1023, %o7
+	cmp	%i2, 4
+	add	%o1, 1023, %o4
+	or	%g0, %i1, %g1
+	or	%g0, %i0, %o0
+	bl,pn	%xcc, .Lsmall
+	or	%g0, 0, %g2
+
+	ldx	[%i1], %o1
+	add	%i1, 24, %g1
+	or	%g0, 3, %g2
+	srlx	%o1, 42, %g3
+	stx	%g3, [%sp+2279]
+	and	%o1, %o7, %o2
+	stx	%o2, [%sp+2263]
+	srlx	%o1, 21, %o1
+	ldd	[%sp+2279], %f0
+	and	%o1, %o7, %o1
+	stx	%o1, [%sp+2271]
+	ldx	[%i1+8], %o2
+	fxtod	%f0, %f12
+	srlx	%o2, 21, %o1
+	and	%o2, %o7, %g3
+	ldd	[%sp+2263], %f2
+	fmuld	%f12, %f12, %f10
+	srlx	%o2, 42, %o2
+	ldd	[%sp+2271], %f0
+	and	%o1, %o7, %o1
+	fxtod	%f2, %f8
+	stx	%o2, [%sp+2279]
+	stx	%o1, [%sp+2271]
+	fxtod	%f0, %f0
+	stx	%g3, [%sp+2263]
+	fdtox	%f10, %f14
+	fmuld	%f12, %f8, %f6
+	ldx	[%i1+16], %o2
+	std	%f14, [%sp+2255]
+	fmuld	%f0, %f0, %f2
+	fmuld	%f8, %f8, %f10
+	srlx	%o2, 42, %o1
+	faddd	%f6, %f6, %f6
+	fmuld	%f12, %f0, %f12
+	fmuld	%f0, %f8, %f8
+	ldd	[%sp+2279], %f0
+	ldd	[%sp+2263], %f4
+	fdtox	%f10, %f10
+	std	%f10, [%sp+2239]
+	faddd	%f2, %f6, %f6
+	ldd	[%sp+2271], %f2
+	fdtox	%f12, %f12
+	std	%f12, [%sp+2247]
+	fdtox	%f8, %f8
+	std	%f8, [%sp+2231]
+	fdtox	%f6, %f6
+	std	%f6, [%sp+2223]
+
+.Loop:	srlx	%o2, 21, %g3
+	stx	%o1, [%sp+2279]
+	add	%g2, 1, %g2
+	and	%g3, %o7, %o1
+	ldx	[%sp+2255], %g4
+	cmp	%g2, %i2
+	stx	%o1, [%sp+2271]
+	add	%g1, 8, %g1
+	add	%o0, 16, %o0
+	ldx	[%sp+2239], %o1
+	fxtod	%f0, %f10
+	fxtod	%f4, %f14
+	ldx	[%sp+2231], %i0
+	ldx	[%sp+2223], %g5
+	ldx	[%sp+2247], %g3
+	and	%o2, %o7, %o2
+	fxtod	%f2, %f8
+	fmuld	%f10, %f10, %f0
+	stx	%o2, [%sp+2263]
+	fmuld	%f10, %f14, %f6
+	ldx	[%g1-8], %o2
+	fmuld	%f10, %f8, %f12
+	fdtox	%f0, %f2
+	ldd	[%sp+2279], %f0
+	fmuld	%f8, %f8, %f4
+	faddd	%f6, %f6, %f6
+	fmuld	%f14, %f14, %f10
+	std	%f2, [%sp+2255]
+	sllx	%g4, 20, %g4
+	ldd	[%sp+2271], %f2
+	fmuld	%f8, %f14, %f8
+	sllx	%i0, 22, %i1
+	fdtox	%f12, %f12
+	std	%f12, [%sp+2247]
+	sllx	%g5, 42, %i0
+	add	%o1, %i1, %o1
+	faddd	%f4, %f6, %f6
+	ldd	[%sp+2263], %f4
+	add	%o1, %i0, %o1
+	add	%g3, %g4, %g3
+	fdtox	%f10, %f10
+	std	%f10, [%sp+2239]
+	srlx	%o1, 42, %g4
+	and	%g5, %o4, %i0
+	fdtox	%f8, %f8
+	std	%f8, [%sp+2231]
+	srlx	%g5, 22, %g5
+	sub	%g4, %i0, %g4
+	fdtox	%f6, %f6
+	std	%f6, [%sp+2223]
+	srlx	%g4, 63, %g4
+	add	%g3, %g5, %g3
+	add	%g3, %g4, %g3
+	stx	%o1, [%o0-16]
+	srlx	%o2, 42, %o1
+	bl,pt	%xcc, .Loop
+	stx	%g3, [%o0-8]
+
+	stx	%o1, [%sp+2279]
+	srlx	%o2, 21, %o1
+	fxtod	%f0, %f16
+	ldx	[%sp+2223], %g3
+	fxtod	%f4, %f6
+	and	%o2, %o7, %o3
+	stx	%o3, [%sp+2263]
+	fxtod	%f2, %f4
+	and	%o1, %o7, %o1
+	ldx	[%sp+2231], %o2
+	sllx	%g3, 42, %g4
+	fmuld	%f16, %f16, %f14
+	stx	%o1, [%sp+2271]
+	fmuld	%f16, %f6, %f8
+	add	%o0, 48, %o0
+	ldx	[%sp+2239], %o1
+	sllx	%o2, 22, %o2
+	fmuld	%f4, %f4, %f10
+	ldx	[%sp+2255], %o3
+	fdtox	%f14, %f14
+	fmuld	%f4, %f6, %f2
+	std	%f14, [%sp+2255]
+	faddd	%f8, %f8, %f12
+	add	%o1, %o2, %o2
+	fmuld	%f16, %f4, %f4
+	ldd	[%sp+2279], %f0
+	sllx	%o3, 20, %g5
+	add	%o2, %g4, %o2
+	fmuld	%f6, %f6, %f6
+	srlx	%o2, 42, %o3
+	and	%g3, %o4, %g4
+	srlx	%g3, 22, %g3
+	faddd	%f10, %f12, %f16
+	ldd	[%sp+2271], %f12
+	ldd	[%sp+2263], %f8
+	fxtod	%f0, %f0
+	sub	%o3, %g4, %o3
+	ldx	[%sp+2247], %o1
+	srlx	%o3, 63, %o3
+	fdtox	%f2, %f10
+	fxtod	%f8, %f8
+	std	%f10, [%sp+2231]
+	fdtox	%f6, %f6
+	std	%f6, [%sp+2239]
+	add	%o1, %g5, %o1
+	fmuld	%f0, %f0, %f2
+	fdtox	%f16, %f16
+	std	%f16, [%sp+2223]
+	add	%o1, %g3, %o1
+	fdtox	%f4, %f4
+	std	%f4, [%sp+2247]
+	fmuld	%f0, %f8, %f10
+	fxtod	%f12, %f12
+	add	%o1, %o3, %o1
+	stx	%o2, [%o0-48]
+	fmuld	%f8, %f8, %f6
+	stx	%o1, [%o0-40]
+	fdtox	%f2, %f2
+	ldx	[%sp+2231], %o2
+	faddd	%f10, %f10, %f10
+	ldx	[%sp+2223], %g3
+	fmuld	%f12, %f12, %f4
+	fdtox	%f6, %f6
+	ldx	[%sp+2239], %o1
+	sllx	%o2, 22, %o2
+	fmuld	%f12, %f8, %f8
+	sllx	%g3, 42, %g5
+	ldx	[%sp+2255], %o3
+	fmuld	%f0, %f12, %f0
+	add	%o1, %o2, %o2
+	faddd	%f4, %f10, %f4
+	ldx	[%sp+2247], %o1
+	add	%o2, %g5, %o2
+	and	%g3, %o4, %g4
+	fdtox	%f8, %f8
+	sllx	%o3, 20, %g5
+	std	%f8, [%sp+2231]
+	fdtox	%f0, %f0
+	srlx	%o2, 42, %o3
+	add	%o1, %g5, %o1
+	fdtox	%f4, %f4
+	srlx	%g3, 22, %g3
+	sub	%o3, %g4, %o3
+	std	%f6, [%sp+2239]
+	std	%f4, [%sp+2223]
+	srlx	%o3, 63, %o3
+	add	%o1, %g3, %o1
+	std	%f2, [%sp+2255]
+	add	%o1, %o3, %o1
+	std	%f0, [%sp+2247]
+	stx	%o2, [%o0-32]
+	stx	%o1, [%o0-24]
+	ldx	[%sp+2231], %o2
+	ldx	[%sp+2223], %o3
+	ldx	[%sp+2239], %o1
+	sllx	%o2, 22, %o2
+	sllx	%o3, 42, %g5
+	ldx	[%sp+2255], %g4
+	and	%o3, %o4, %g3
+	add	%o1, %o2, %o2
+	ldx	[%sp+2247], %o1
+	add	%o2, %g5, %o2
+	stx	%o2, [%o0-16]
+	sllx	%g4, 20, %g4
+	srlx	%o2, 42, %o2
+	add	%o1, %g4, %o1
+	srlx	%o3, 22, %o3
+	sub	%o2, %g3, %o2
+	srlx	%o2, 63, %o2
+	add	%o1, %o3, %o1
+	add	%o1, %o2, %o1
+	stx	%o1, [%o0-8]
+	ret
+	restore	%g0, %g0, %g0
+.Lsmall:
+	ldx	[%g1], %o2
+.Loop0:
+	and	%o2, %o7, %o1
+	stx	%o1, [%sp+2263]
+	add	%g2, 1, %g2
+	srlx	%o2, 21, %o1
+	add	%g1, 8, %g1
+	srlx	%o2, 42, %o2
+	stx	%o2, [%sp+2279]
+	and	%o1, %o7, %o1
+	ldd	[%sp+2263], %f0
+	cmp	%g2, %i2
+	stx	%o1, [%sp+2271]
+	fxtod	%f0, %f6
+	ldd	[%sp+2279], %f0
+	ldd	[%sp+2271], %f4
+	fxtod	%f0, %f2
+	fmuld	%f6, %f6, %f0
+	fxtod	%f4, %f10
+	fmuld	%f2, %f6, %f4
+	fdtox	%f0, %f0
+	std	%f0, [%sp+2239]
+	fmuld	%f10, %f6, %f8
+	fmuld	%f10, %f10, %f0
+	faddd	%f4, %f4, %f6
+	fmuld	%f2, %f2, %f4
+	fdtox	%f8, %f8
+	std	%f8, [%sp+2231]
+	fmuld	%f2, %f10, %f2
+	faddd	%f0, %f6, %f0
+	fdtox	%f4, %f4
+	std	%f4, [%sp+2255]
+	fdtox	%f2, %f2
+	std	%f2, [%sp+2247]
+	fdtox	%f0, %f0
+	std	%f0, [%sp+2223]
+	ldx	[%sp+2239], %o1
+	ldx	[%sp+2255], %g4
+	ldx	[%sp+2231], %o2
+	sllx	%g4, 20, %g4
+	ldx	[%sp+2223], %o3
+	sllx	%o2, 22, %o2
+	sllx	%o3, 42, %g5
+	add	%o1, %o2, %o2
+	ldx	[%sp+2247], %o1
+	add	%o2, %g5, %o2
+	stx	%o2, [%o0]
+	and	%o3, %o4, %g3
+	srlx	%o2, 42, %o2
+	add	%o1, %g4, %o1
+	srlx	%o3, 22, %o3
+	sub	%o2, %g3, %o2
+	srlx	%o2, 63, %o2
+	add	%o1, %o3, %o1
+	add	%o1, %o2, %o1
+	stx	%o1, [%o0+8]
+	add	%o0, 16, %o0
+	bl,a,pt	%xcc, .Loop0
+	ldx	[%g1], %o2
+	ret
+	restore	%g0, %g0, %g0
+EPILOGUE(mpn_sqr_diagonal)
diff --git a/third_party/gmp/mpn/sparc64/ultrasparc1234/sub_n.asm b/third_party/gmp/mpn/sparc64/ultrasparc1234/sub_n.asm
new file mode 100644
index 0000000..9fb7f70
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/ultrasparc1234/sub_n.asm
@@ -0,0 +1,241 @@
+dnl  SPARC v9 mpn_sub_n -- Subtract two limb vectors of the same length > 0 and
+dnl  store difference in a third limb vector.
+
+dnl  Copyright 2001-2003, 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		   cycles/limb
+C UltraSPARC 1&2:     4
+C UltraSPARC 3:	      4.5
+
+C Compute carry-out from the most significant bits of u,v, and r, where
+C r=u-v-carry_in, using logic operations.
+
+C This code runs at 4 cycles/limb on UltraSPARC 1 and 2.  It has a 4 insn
+C recurrency, and the UltraSPARC 1 and 2 the IE units are 100% saturated.
+C Therefore, it seems futile to try to optimize this any further...
+
+C INPUT PARAMETERS
+define(`rp',`%i0')
+define(`up',`%i1')
+define(`vp',`%i2')
+define(`n',`%i3')
+
+define(`u0',`%l0')
+define(`u1',`%l2')
+define(`u2',`%l4')
+define(`u3',`%l6')
+define(`v0',`%l1')
+define(`v1',`%l3')
+define(`v2',`%l5')
+define(`v3',`%l7')
+
+define(`cy',`%i4')
+
+define(`fanop',`fitod %f0,%f2')		dnl  A quasi nop running in the FA pipe
+define(`fmnop',`fmuld %f0,%f0,%f4')	dnl  A quasi nop running in the FM pipe
+
+ASM_START()
+	REGISTER(%g2,#scratch)
+	REGISTER(%g3,#scratch)
+PROLOGUE(mpn_sub_nc)
+	save	%sp,-160,%sp
+
+	fitod	%f0,%f0		C make sure f0 contains small, quiet number
+	subcc	n,4,%g0
+	bl,pn	%xcc,.Loop0
+	nop
+	b,a	L(com)
+EPILOGUE()
+
+PROLOGUE(mpn_sub_n)
+	save	%sp,-160,%sp
+
+	fitod	%f0,%f0		C make sure f0 contains small, quiet number
+	subcc	n,4,%g0
+	bl,pn	%xcc,.Loop0
+	mov	0,cy
+L(com):
+	ldx	[up+0],u0
+	ldx	[vp+0],v0
+	add	up,32,up
+	ldx	[up-24],u1
+	ldx	[vp+8],v1
+	add	vp,32,vp
+	ldx	[up-16],u2
+	ldx	[vp-16],v2
+	ldx	[up-8],u3
+	ldx	[vp-8],v3
+	subcc	n,8,n
+	sub	u0,v0,%g1	C main sub
+	sub	%g1,cy,%g5	C carry sub
+	orn	u0,v0,%g2
+	bl,pn	%xcc,.Lend4567
+	fanop
+	b,a	.Loop
+
+	.align	16
+C START MAIN LOOP
+.Loop:	orn	%g5,%g2,%g2
+	andn	u0,v0,%g3
+	ldx	[up+0],u0
+	fanop
+C --
+	andn	%g2,%g3,%g2
+	ldx	[vp+0],v0
+	add	up,32,up
+	fanop
+C --
+	srlx	%g2,63,cy
+	sub	u1,v1,%g1
+	stx	%g5,[rp+0]
+	fanop
+C --
+	sub	%g1,cy,%g5
+	orn	u1,v1,%g2
+	fmnop
+	fanop
+C --
+	orn	%g5,%g2,%g2
+	andn	u1,v1,%g3
+	ldx	[up-24],u1
+	fanop
+C --
+	andn	%g2,%g3,%g2
+	ldx	[vp+8],v1
+	add	vp,32,vp
+	fanop
+C --
+	srlx	%g2,63,cy
+	sub	u2,v2,%g1
+	stx	%g5,[rp+8]
+	fanop
+C --
+	sub	%g1,cy,%g5
+	orn	u2,v2,%g2
+	fmnop
+	fanop
+C --
+	orn	%g5,%g2,%g2
+	andn	u2,v2,%g3
+	ldx	[up-16],u2
+	fanop
+C --
+	andn	%g2,%g3,%g2
+	ldx	[vp-16],v2
+	add	rp,32,rp
+	fanop
+C --
+	srlx	%g2,63,cy
+	sub	u3,v3,%g1
+	stx	%g5,[rp-16]
+	fanop
+C --
+	sub	%g1,cy,%g5
+	orn	u3,v3,%g2
+	fmnop
+	fanop
+C --
+	orn	%g5,%g2,%g2
+	andn	u3,v3,%g3
+	ldx	[up-8],u3
+	fanop
+C --
+	andn	%g2,%g3,%g2
+	subcc	n,4,n
+	ldx	[vp-8],v3
+	fanop
+C --
+	srlx	%g2,63,cy
+	sub	u0,v0,%g1
+	stx	%g5,[rp-8]
+	fanop
+C --
+	sub	%g1,cy,%g5
+	orn	u0,v0,%g2
+	bge,pt	%xcc,.Loop
+	fanop
+C END MAIN LOOP
+.Lend4567:
+	orn	%g5,%g2,%g2
+	andn	u0,v0,%g3
+	andn	%g2,%g3,%g2
+	srlx	%g2,63,cy
+	sub	u1,v1,%g1
+	stx	%g5,[rp+0]
+	sub	%g1,cy,%g5
+	orn	u1,v1,%g2
+	orn	%g5,%g2,%g2
+	andn	u1,v1,%g3
+	andn	%g2,%g3,%g2
+	srlx	%g2,63,cy
+	sub	u2,v2,%g1
+	stx	%g5,[rp+8]
+	sub	%g1,cy,%g5
+	orn	u2,v2,%g2
+	orn	%g5,%g2,%g2
+	andn	u2,v2,%g3
+	andn	%g2,%g3,%g2
+	add	rp,32,rp
+	srlx	%g2,63,cy
+	sub	u3,v3,%g1
+	stx	%g5,[rp-16]
+	sub	%g1,cy,%g5
+	orn	u3,v3,%g2
+	orn	%g5,%g2,%g2
+	andn	u3,v3,%g3
+	andn	%g2,%g3,%g2
+	srlx	%g2,63,cy
+	stx	%g5,[rp-8]
+
+	addcc	n,4,n
+	bz,pn	%xcc,.Lret
+	fanop
+
+.Loop0:	ldx	[up],u0
+	add	up,8,up
+	ldx	[vp],v0
+	add	vp,8,vp
+	add	rp,8,rp
+	subcc	n,1,n
+	sub	u0,v0,%g1
+	orn	u0,v0,%g2
+	sub	%g1,cy,%g5
+	andn	u0,v0,%g3
+	orn	%g5,%g2,%g2
+	stx	%g5,[rp-8]
+	andn	%g2,%g3,%g2
+	bnz,pt	%xcc,.Loop0
+	srlx	%g2,63,cy
+
+.Lret:	mov	cy,%i0
+	ret
+	restore
+EPILOGUE(mpn_sub_n)
diff --git a/third_party/gmp/mpn/sparc64/ultrasparc1234/submul_1.asm b/third_party/gmp/mpn/sparc64/ultrasparc1234/submul_1.asm
new file mode 100644
index 0000000..0bdb566
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/ultrasparc1234/submul_1.asm
@@ -0,0 +1,68 @@
+dnl  SPARC v9 64-bit mpn_submul_1 -- Multiply a limb vector with a limb and
+dnl  subtract the result from a second limb vector.
+
+dnl  Copyright 2001-2003 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		   cycles/limb
+C UltraSPARC 1&2:     18
+C UltraSPARC 3:	      23
+
+C INPUT PARAMETERS
+C rp	i0
+C up	i1
+C n	i2
+C v	i3
+
+ASM_START()
+	REGISTER(%g2,#scratch)
+
+PROLOGUE(mpn_submul_1)
+	save	%sp,-176,%sp
+
+	sllx	%i2, 3, %g2
+	or	%g0, %i1, %o1
+	add	%g2, 15, %o0
+	or	%g0, %i2, %o2
+	and	%o0, -16, %o0
+	sub	%sp, %o0, %sp
+	add	%sp, 2223, %o0
+	or	%g0, %o0, %l0
+	call	mpn_mul_1
+	or	%g0, %i3, %o3
+	or	%g0, %o0, %l1		C preserve carry value from mpn_mul_1
+	or	%g0, %i0, %o0
+	or	%g0, %i0, %o1
+	or	%g0, %l0, %o2
+	call	mpn_sub_n
+	or	%g0, %i2, %o3
+	ret
+	restore	%l1, %o0, %o0		C sum carry values
+EPILOGUE(mpn_submul_1)
diff --git a/third_party/gmp/mpn/sparc64/ultrasparc34/gmp-mparam.h b/third_party/gmp/mpn/sparc64/ultrasparc34/gmp-mparam.h
new file mode 100644
index 0000000..c88e680
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/ultrasparc34/gmp-mparam.h
@@ -0,0 +1,222 @@
+/* ultrasparc3/4 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 1999-2002, 2004, 2006, 2008-2010, 2014, 2015 Free
+Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+/* 1593 MHz ultrasparc3 running Solaris 10 (swift.nada.kth.se) */
+/* FFT tuning limit = 100 M */
+/* Generated by tuneup.c, 2015-10-09, gcc 3.4 */
+
+#define DIVREM_1_NORM_THRESHOLD              0  /* always */
+#define DIVREM_1_UNNORM_THRESHOLD            0  /* always */
+#define MOD_1_1P_METHOD                      2
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          7
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          5
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        22
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD         0  /* never mpn_mod_1s_2p */
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     29
+#define USE_PREINV_DIVREM_1                  1
+#define DIV_QR_1N_PI1_METHOD                 1
+#define DIV_QR_1_NORM_THRESHOLD              2
+#define DIV_QR_1_UNNORM_THRESHOLD            1
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always */
+#define BMOD_1_TO_MOD_1_THRESHOLD        MP_SIZE_T_MAX  /* never */
+
+#define MUL_TOOM22_THRESHOLD                28
+#define MUL_TOOM33_THRESHOLD                93
+#define MUL_TOOM44_THRESHOLD               142
+#define MUL_TOOM6H_THRESHOLD               165
+#define MUL_TOOM8H_THRESHOLD               278
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      93
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     114
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD      88
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD      50
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD      67
+
+#define SQR_BASECASE_THRESHOLD               7
+#define SQR_TOOM2_THRESHOLD                 70
+#define SQR_TOOM3_THRESHOLD                101
+#define SQR_TOOM4_THRESHOLD                184
+#define SQR_TOOM6_THRESHOLD                  0  /* always */
+#define SQR_TOOM8_THRESHOLD                339
+
+#define MULMID_TOOM42_THRESHOLD             40
+
+#define MULMOD_BNM1_THRESHOLD               14
+#define SQRMOD_BNM1_THRESHOLD                9
+
+#define MUL_FFT_MODF_THRESHOLD             212  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    212, 5}, {     13, 6}, {     17, 7}, {      9, 6}, \
+    {     19, 7}, {     17, 8}, {      9, 7}, {     20, 8}, \
+    {     11, 7}, {     23, 8}, {     13, 9}, {      7, 8}, \
+    {     19, 9}, {     11, 8}, {     25,10}, {      7, 9}, \
+    {     15, 8}, {     33, 9}, {     19, 8}, {     39, 9}, \
+    {     23, 8}, {     47, 9}, {     27,10}, {     15, 9}, \
+    {     39,10}, {     23, 9}, {     47,11}, {     15,10}, \
+    {     31, 9}, {     63, 8}, {    127, 7}, {    255, 9}, \
+    {     67,10}, {     39, 9}, {     79, 8}, {    159, 7}, \
+    {    319, 9}, {     83,10}, {     47, 9}, {     95, 8}, \
+    {    191, 7}, {    383,10}, {     55,11}, {     31,10}, \
+    {     63, 9}, {    127, 8}, {    255, 7}, {    511,10}, \
+    {     71, 9}, {    143, 8}, {    287,10}, {     79, 9}, \
+    {    159, 8}, {    319, 9}, {    175, 8}, {    351,11}, \
+    {     47,10}, {     95, 9}, {    191, 8}, {    383, 7}, \
+    {    767,10}, {    103,12}, {     31,11}, {     63,10}, \
+    {    127, 9}, {    287,11}, {     79,10}, {    159, 9}, \
+    {    319, 8}, {    639,10}, {    175, 9}, {    351, 8}, \
+    {    703,11}, {     95,10}, {    207, 9}, {    415,11}, \
+    {    111,10}, {    223, 9}, {    479,12}, {     63,11}, \
+    {    127,10}, {    255,11}, {    143,10}, {    287, 9}, \
+    {    575,10}, {    319, 9}, {    639,11}, {    175,10}, \
+    {    351,11}, {    191,10}, {    383,11}, {    207,10}, \
+    {    415,11}, {    223,10}, {    447,13}, {     63,12}, \
+    {    127,11}, {    287,10}, {    575,11}, {    319,10}, \
+    {    703,12}, {    191,11}, {    383,12}, {    223,11}, \
+    {    447,13}, {    127,12}, {    287,11}, {    575,12}, \
+    {    351,13}, {    191,12}, {    479,14}, {    127,13}, \
+    {    255,12}, {    575,13}, {    319,12}, {    703,13}, \
+    {    383,12}, {    767,13}, {    447,12}, {    895,14}, \
+    {    255,13}, {    511,12}, {   1023,13}, {    575,12}, \
+    {   1151,13}, {    703,14}, {    383,13}, {    831,12}, \
+    {   1663,13}, {    895,15}, {    255,14}, {    511,13}, \
+    {   1151,14}, {    639,13}, {   1407,12}, {   2815,14}, \
+    {    767,13}, {   1663,14}, {    895,13}, {   1791,15}, \
+    {    511,14}, {   1023,13}, {   2047,14}, {   1151,13}, \
+    {   2303,14}, {   1407,13}, {   2815,15}, {    767,14}, \
+    {   1791,16}, {    511,15}, {   1023,14}, {   2303,15}, \
+    {   1279,14}, {   2815,15}, {   1535,14}, {   3199,15}, \
+    {   1791,16}, {   1023,15}, {   2047,14}, {   4223,15}, \
+    {   2303,14}, {   4863,15}, {   2815,16}, {  65536,17}, \
+    { 131072,18}, { 262144,19}, { 524288,20}, {1048576,21}, \
+    {2097152,22}, {4194304,23}, {8388608,24} }
+#define MUL_FFT_TABLE3_SIZE 171
+#define MUL_FFT_THRESHOLD                 2240
+
+#define SQR_FFT_MODF_THRESHOLD             244  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    244, 5}, {      8, 4}, {     17, 5}, {     15, 6}, \
+    {      8, 5}, {     17, 6}, {     17, 7}, {      9, 6}, \
+    {     19, 7}, {     17, 8}, {      9, 7}, {     20, 8}, \
+    {     11, 7}, {     23, 8}, {     13, 9}, {      7, 8}, \
+    {     19, 9}, {     11, 8}, {     25,10}, {      7, 9}, \
+    {     15, 8}, {     31, 9}, {     19, 8}, {     39, 9}, \
+    {     27,10}, {     15, 9}, {     39,10}, {     23, 9}, \
+    {     47,11}, {     15,10}, {     31, 9}, {     67,10}, \
+    {     39, 9}, {     79, 8}, {    159,10}, {     47, 9}, \
+    {     95,10}, {     55,11}, {     31,10}, {     63, 9}, \
+    {    127, 8}, {    255,10}, {     71, 9}, {    143, 8}, \
+    {    287, 7}, {    575,10}, {     79, 9}, {    159,11}, \
+    {     47, 9}, {    191, 8}, {    383, 7}, {    767, 9}, \
+    {    207,12}, {     31,11}, {     63,10}, {    127, 9}, \
+    {    255, 8}, {    511,10}, {    135, 9}, {    271,10}, \
+    {    143, 9}, {    287,11}, {     79,10}, {    159, 9}, \
+    {    319, 8}, {    639,10}, {    175, 9}, {    351, 8}, \
+    {    703, 7}, {   1407,11}, {     95,10}, {    191, 9}, \
+    {    383, 8}, {    767,10}, {    207, 9}, {    415,10}, \
+    {    223, 9}, {    447,12}, {     63,11}, {    127,10}, \
+    {    271, 9}, {    543,10}, {    287, 9}, {    575, 8}, \
+    {   1151,11}, {    159,10}, {    319, 9}, {    639,10}, \
+    {    351, 9}, {    703, 8}, {   1407, 7}, {   2815,11}, \
+    {    207,10}, {    415, 9}, {    831,11}, {    223,10}, \
+    {    447, 9}, {    895,13}, {     63,11}, {    271,10}, \
+    {    543,11}, {    287,12}, {    159,11}, {    351,10}, \
+    {    703,12}, {    191,11}, {    415,10}, {    831,12}, \
+    {    223,13}, {    127,12}, {    255,11}, {    511,10}, \
+    {   1023,11}, {    543,12}, {    287,11}, {    607,12}, \
+    {    319,11}, {    639,12}, {    415,11}, {    895,12}, \
+    {    479,14}, {    127,13}, {    255,12}, {    543,11}, \
+    {   1087,12}, {    575,11}, {   1151,13}, {    319,12}, \
+    {    639,11}, {   1279,12}, {    703,10}, {   2815,12}, \
+    {    831,11}, {   1663,13}, {    447,12}, {    959,14}, \
+    {    255,13}, {    511,12}, {   1087,13}, {    703,12}, \
+    {   1407,14}, {    383,13}, {    767,12}, {   1535,13}, \
+    {    895,15}, {    255,14}, {    511,13}, {   1215,14}, \
+    {    639,13}, {   1279,14}, {    767,13}, {   1663,14}, \
+    {    895,13}, {   1919,15}, {    511,14}, {   1023,13}, \
+    {   2175,14}, {   1151,13}, {   2431,14}, {   1407,15}, \
+    {    767,14}, {   1791,16}, {    511,15}, {   1023,14}, \
+    {   2303,15}, {   1279,14}, {   2815,15}, {   1535,14}, \
+    {   3199,15}, {   1791,16}, {   1023,15}, {   2047,14}, \
+    {   4351,15}, {   2303,14}, {   4863,15}, {   2815,16}, \
+    {  65536,17}, { 131072,18}, { 262144,19}, { 524288,20}, \
+    {1048576,21}, {2097152,22}, {4194304,23}, {8388608,24} }
+#define SQR_FFT_TABLE3_SIZE 184
+#define SQR_FFT_THRESHOLD                 1728
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  29
+#define MULLO_MUL_N_THRESHOLD             4392
+#define SQRLO_BASECASE_THRESHOLD             2
+#define SQRLO_DC_THRESHOLD                  63
+#define SQRLO_SQR_THRESHOLD               3176
+
+#define DC_DIV_QR_THRESHOLD                 16
+#define DC_DIVAPPR_Q_THRESHOLD              64
+#define DC_BDIV_QR_THRESHOLD                30
+#define DC_BDIV_Q_THRESHOLD                 86
+
+#define INV_MULMOD_BNM1_THRESHOLD           58
+#define INV_NEWTON_THRESHOLD                17
+#define INV_APPR_THRESHOLD                  15
+
+#define BINV_NEWTON_THRESHOLD              109
+#define REDC_1_TO_REDC_2_THRESHOLD           0  /* always */
+#define REDC_2_TO_REDC_N_THRESHOLD         117
+
+#define MU_DIV_QR_THRESHOLD                618
+#define MU_DIVAPPR_Q_THRESHOLD             618
+#define MUPI_DIV_QR_THRESHOLD                0  /* always */
+#define MU_BDIV_QR_THRESHOLD               680
+#define MU_BDIV_Q_THRESHOLD                807
+
+#define POWM_SEC_TABLE  3,22,102,579,1555
+
+#define GET_STR_DC_THRESHOLD                20
+#define GET_STR_PRECOMPUTE_THRESHOLD        28
+#define SET_STR_DC_THRESHOLD               381
+#define SET_STR_PRECOMPUTE_THRESHOLD      1042
+
+#define FAC_DSC_THRESHOLD                  462
+#define FAC_ODD_THRESHOLD                    0  /* always */
+
+#define MATRIX22_STRASSEN_THRESHOLD         12
+#define HGCD_THRESHOLD                      45
+#define HGCD_APPR_THRESHOLD                 50
+#define HGCD_REDUCE_THRESHOLD             1094
+#define GCD_DC_THRESHOLD                   126
+#define GCDEXT_DC_THRESHOLD                132
+#define JACOBI_BASE_METHOD                   4
diff --git a/third_party/gmp/mpn/sparc64/ultrasparct1/add_n.asm b/third_party/gmp/mpn/sparc64/ultrasparct1/add_n.asm
new file mode 100644
index 0000000..954c7f6
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/ultrasparct1/add_n.asm
@@ -0,0 +1,68 @@
+dnl  SPARC v9 mpn_add_n for T1/T2.
+
+dnl  Copyright 2010 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		   cycles/limb
+C UltraSPARC T1:	 ?
+C UltraSPARC T2:	 ?
+
+C INPUT PARAMETERS
+define(`rp', `%o0')
+define(`up', `%o1')
+define(`vp', `%o2')
+define(`n',  `%o3')
+define(`cy', `%o4')
+
+ASM_START()
+	REGISTER(%g2,#scratch)
+	REGISTER(%g3,#scratch)
+PROLOGUE(mpn_add_nc)
+	b,a	L(ent)
+EPILOGUE()
+PROLOGUE(mpn_add_n)
+	mov	0, cy
+L(ent):	cmp	%g0, cy
+L(top):	ldx	[up+0], %o4
+	add	up, 8, up
+	ldx	[vp+0], %o5
+	add	vp, 8, vp
+	add	rp, 8, rp
+	add	n, -1, n
+	srlx	%o4, 32, %g1
+	srlx	%o5, 32, %g2
+	addccc	%o4, %o5, %g3
+	addccc	%g1, %g2, %g0
+	brgz	n, L(top)
+	 stx	%g3, [rp-8]
+
+	retl
+	addc	%g0, %g0, %o0
+EPILOGUE()
diff --git a/third_party/gmp/mpn/sparc64/ultrasparct1/addlsh1_n.asm b/third_party/gmp/mpn/sparc64/ultrasparct1/addlsh1_n.asm
new file mode 100644
index 0000000..3134797
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/ultrasparct1/addlsh1_n.asm
@@ -0,0 +1,41 @@
+dnl  SPARC v9 mpn_addlsh1_n for T1/T2.
+
+dnl  Copyright 2010 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+define(LSH,             1)
+define(RSH,             63)
+
+define(func, mpn_addlsh1_n)
+
+MULFUNC_PROLOGUE(mpn_addlsh1_n)
+
+include_mpn(`sparc64/ultrasparct1/addlshC_n.asm')
diff --git a/third_party/gmp/mpn/sparc64/ultrasparct1/addlsh2_n.asm b/third_party/gmp/mpn/sparc64/ultrasparct1/addlsh2_n.asm
new file mode 100644
index 0000000..ee1afd0
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/ultrasparct1/addlsh2_n.asm
@@ -0,0 +1,41 @@
+dnl  SPARC v9 mpn_addlsh2_n for T1/T2.
+
+dnl  Copyright 2010 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+define(LSH,             2)
+define(RSH,             62)
+
+define(func, mpn_addlsh2_n)
+
+MULFUNC_PROLOGUE(mpn_addlsh2_n)
+
+include_mpn(`sparc64/ultrasparct1/addlshC_n.asm')
diff --git a/third_party/gmp/mpn/sparc64/ultrasparct1/addlshC_n.asm b/third_party/gmp/mpn/sparc64/ultrasparct1/addlshC_n.asm
new file mode 100644
index 0000000..5be9a0d
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/ultrasparct1/addlshC_n.asm
@@ -0,0 +1,69 @@
+dnl  SPARC v9 mpn_addlshC_n for T1/T2.
+
+dnl  Copyright 2010 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+C		   cycles/limb
+C UltraSPARC T1:	21
+C UltraSPARC T2:	 ?
+
+C INPUT PARAMETERS
+define(`rp', `%o0')
+define(`up', `%o1')
+define(`vp', `%o2')
+define(`n',  `%o3')
+define(`cy', `%o4')
+
+ASM_START()
+	REGISTER(%g2,#scratch)
+	REGISTER(%g3,#scratch)
+PROLOGUE(func)
+	mov	0, cy
+	mov	0, %g5
+	cmp	%g0, cy
+L(top):	ldx	[up+0], %o4
+	add	up, 8, up
+	ldx	[vp+0], %o5
+	add	vp, 8, vp
+	add	rp, 8, rp
+
+	sllx	%o5, LSH, %g4
+	add	n, -1, n
+	or	%g5, %g4, %g4
+	srlx	%o5, RSH, %g5
+
+	srlx	%o4, 32, %g1
+	srlx	%g4, 32, %g2
+	addccc	%o4, %g4, %g3
+	addccc	%g1, %g2, %g0
+	brgz	n, L(top)
+	 stx	%g3, [rp-8]
+
+	retl
+	addc	%g5, %g0, %o0
+EPILOGUE()
diff --git a/third_party/gmp/mpn/sparc64/ultrasparct1/addmul_1.asm b/third_party/gmp/mpn/sparc64/ultrasparct1/addmul_1.asm
new file mode 100644
index 0000000..29dba96
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/ultrasparct1/addmul_1.asm
@@ -0,0 +1,86 @@
+dnl  SPARC v9 mpn_addmul_1 for T1/T2.
+
+dnl  Copyright 2010 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		   cycles/limb
+C UltraSPARC T1:	74
+C UltraSPARC T2:	 ?
+
+C INPUT PARAMETERS
+define(`rp', `%i0')
+define(`up', `%i1')
+define(`n',  `%i2')
+define(`v0', `%i3')
+
+ASM_START()
+	REGISTER(%g2,#scratch)
+	REGISTER(%g3,#scratch)
+PROLOGUE(mpn_addmul_1)
+	save	%sp, -176, %sp
+	mov	1, %o2
+	mov	%i0, %g2
+	srlx	%i3, 32, %o4
+	sllx	%o2, 32, %o2
+	srl	%i3, 0, %i3
+	mov	0, %g3
+	mov	0, %i0
+
+L(top):	ldx	[%i1+%g3], %g1
+	srl	%g1, 0, %g4
+	mulx	%g4, %i3, %o5
+	srlx	%g1, 32, %g1
+	mulx	%g1, %i3, %g5
+	mulx	%g4, %o4, %g4
+	mulx	%g1, %o4, %g1
+	srlx	%o5, 32, %o1
+	add	%g5, %o1, %o1
+	addcc	%o1, %g4, %g4
+	srl	%o5, 0, %o0
+	ldx	[%g2+%g3], %o5
+	sllx	%g4, 32, %o1
+	add	%g1, %o2, %l1
+	movlu	%xcc, %l1, %g1
+	add	%o1, %o0, %l0
+	addcc	%l0, %i0, %g5
+	srlx	%g4, 32, %i0
+	add	%i0, 1, %g4
+	movlu	%xcc, %g4, %i0
+	addcc	%o5, %g5, %g5
+	stx	%g5, [%g2+%g3]
+	add	%i0, 1, %g4
+	movlu	%xcc, %g4, %i0
+	add	%i2, -1, %i2
+	add	%i0, %g1, %i0
+	brnz,pt	%i2, L(top)
+	 add	%g3, 8, %g3
+	return	%i7+8
+	 nop
+EPILOGUE()
diff --git a/third_party/gmp/mpn/sparc64/ultrasparct1/gmp-mparam.h b/third_party/gmp/mpn/sparc64/ultrasparct1/gmp-mparam.h
new file mode 100644
index 0000000..99db78a
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/ultrasparct1/gmp-mparam.h
@@ -0,0 +1,154 @@
+/* Sparc64 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 1999-2002, 2004, 2006, 2008-2010 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+/* 1000 MHz ultrasparc t1 running GNU/Linux */
+
+#define DIVREM_1_NORM_THRESHOLD              0  /* always */
+#define DIVREM_1_UNNORM_THRESHOLD            0  /* always */
+#define MOD_1_1P_METHOD                      2
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD         13
+#define MOD_1U_TO_MOD_1_1_THRESHOLD      MP_SIZE_T_MAX
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD         0  /* never mpn_mod_1_1p */
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD         0  /* never mpn_mod_1s_2p */
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     34
+#define USE_PREINV_DIVREM_1                  1
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always */
+#define BMOD_1_TO_MOD_1_THRESHOLD        MP_SIZE_T_MAX  /* never */
+
+#define MUL_TOOM22_THRESHOLD                 8
+#define MUL_TOOM33_THRESHOLD                50
+#define MUL_TOOM44_THRESHOLD                99
+#define MUL_TOOM6H_THRESHOLD               125
+#define MUL_TOOM8H_THRESHOLD               187
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      65
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD      77
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD      65
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD      50
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD      34
+
+#define SQR_BASECASE_THRESHOLD               0  /* always */
+#define SQR_TOOM2_THRESHOLD                 14
+#define SQR_TOOM3_THRESHOLD                 57
+#define SQR_TOOM4_THRESHOLD                133
+#define SQR_TOOM6_THRESHOLD                156
+#define SQR_TOOM8_THRESHOLD                260
+
+#define MULMID_TOOM42_THRESHOLD             12
+
+#define MULMOD_BNM1_THRESHOLD                7
+#define SQRMOD_BNM1_THRESHOLD                7
+
+#define MUL_FFT_MODF_THRESHOLD             176  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    176, 5}, {      7, 6}, {      4, 5}, {      9, 6}, \
+    {      5, 5}, {     11, 6}, {     11, 7}, {      6, 6}, \
+    {     13, 7}, {      7, 6}, {     15, 7}, {      9, 8}, \
+    {      5, 7}, {     13, 8}, {      7, 7}, {     15, 6}, \
+    {     32, 7}, {     24, 8}, {     21, 9}, {     11, 8}, \
+    {     23,10}, {      7, 9}, {     15, 8}, {     33, 9}, \
+    {     19, 8}, {     39, 9}, {     23,10}, {     15, 9}, \
+    {     43,10}, {     23,11}, {     15,10}, {     31, 9}, \
+    {     63, 8}, {    127, 9}, {     67,10}, {     39, 9}, \
+    {     79, 8}, {    159,10}, {     47, 9}, {     95,11}, \
+    {   2048,12}, {   4096,13}, {   8192,14}, {  16384,15}, \
+    {  32768,16}, {  65536,17}, { 131072,18}, { 262144,19}, \
+    { 524288,20}, {1048576,21}, {2097152,22}, {4194304,23}, \
+    {8388608,24} }
+#define MUL_FFT_TABLE3_SIZE 53
+#define MUL_FFT_THRESHOLD                 1728
+
+
+#define SQR_FFT_MODF_THRESHOLD             148  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    148, 5}, {      7, 6}, {      4, 5}, {      9, 6}, \
+    {      5, 5}, {     11, 6}, {     11, 7}, {      6, 6}, \
+    {     13, 7}, {      7, 6}, {     15, 7}, {     13, 8}, \
+    {      7, 7}, {     16, 8}, {      9, 6}, {     38, 7}, \
+    {     20, 8}, {     11, 7}, {     24, 8}, {     13, 9}, \
+    {      7, 7}, {     30, 8}, {     19, 9}, {     11, 8}, \
+    {     25,10}, {      7, 9}, {     15, 8}, {     31, 9}, \
+    {     19, 8}, {     39, 9}, {     27,10}, {     15, 9}, \
+    {     39,10}, {     23, 9}, {     47, 8}, {     95, 9}, \
+    {     51,11}, {     15,10}, {     31, 8}, {    127,10}, \
+    {     39, 9}, {     79, 8}, {    159,10}, {     47, 9}, \
+    {     95,11}, {   2048,12}, {   4096,13}, {   8192,14}, \
+    {  16384,15}, {  32768,16}, {  65536,17}, { 131072,18}, \
+    { 262144,19}, { 524288,20}, {1048576,21}, {2097152,22}, \
+    {4194304,23}, {8388608,24} }
+#define SQR_FFT_TABLE3_SIZE 58
+#define SQR_FFT_THRESHOLD                 1344
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  28
+#define MULLO_MUL_N_THRESHOLD             3176
+
+#define DC_DIV_QR_THRESHOLD                 27
+#define DC_DIVAPPR_Q_THRESHOLD             106
+#define DC_BDIV_QR_THRESHOLD                27
+#define DC_BDIV_Q_THRESHOLD                 62
+
+#define INV_MULMOD_BNM1_THRESHOLD           14
+#define INV_NEWTON_THRESHOLD               163
+#define INV_APPR_THRESHOLD                 117
+
+#define BINV_NEWTON_THRESHOLD              166
+#define REDC_1_TO_REDC_N_THRESHOLD          31
+
+#define MU_DIV_QR_THRESHOLD                734
+#define MU_DIVAPPR_Q_THRESHOLD             748
+#define MUPI_DIV_QR_THRESHOLD               67
+#define MU_BDIV_QR_THRESHOLD               562
+#define MU_BDIV_Q_THRESHOLD                734
+
+#define POWM_SEC_TABLE  4,29,188,643,2741
+
+#define MATRIX22_STRASSEN_THRESHOLD         11
+#define HGCD_THRESHOLD                      58
+#define HGCD_APPR_THRESHOLD                 55
+#define HGCD_REDUCE_THRESHOLD              637
+#define GCD_DC_THRESHOLD                   186
+#define GCDEXT_DC_THRESHOLD                140
+#define JACOBI_BASE_METHOD                   3
+
+#define GET_STR_DC_THRESHOLD                20
+#define GET_STR_PRECOMPUTE_THRESHOLD        33
+#define SET_STR_DC_THRESHOLD               268
+#define SET_STR_PRECOMPUTE_THRESHOLD       960
+
+#define FAC_DSC_THRESHOLD                  268
+#define FAC_ODD_THRESHOLD                    0  /* always */
diff --git a/third_party/gmp/mpn/sparc64/ultrasparct1/mul_1.asm b/third_party/gmp/mpn/sparc64/ultrasparct1/mul_1.asm
new file mode 100644
index 0000000..1fea2a1
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/ultrasparct1/mul_1.asm
@@ -0,0 +1,82 @@
+dnl  SPARC v9 mpn_mul_1 for T1/T2.
+
+dnl  Copyright 2010 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		   cycles/limb
+C UltraSPARC T1:	68
+C UltraSPARC T2:	 ?
+
+C INPUT PARAMETERS
+define(`rp', `%i0')
+define(`up', `%i1')
+define(`n',  `%i2')
+define(`v0', `%i3')
+
+ASM_START()
+	REGISTER(%g2,#scratch)
+	REGISTER(%g3,#scratch)
+PROLOGUE(mpn_mul_1)
+	save	%sp, -176, %sp
+	mov	1, %o2
+	mov	%i0, %g2
+	srlx	%i3, 32, %o4
+	sllx	%o2, 32, %o2
+	srl	%i3, 0, %i3
+	mov	0, %g3
+	mov	0, %i0
+
+L(top):	ldx	[%i1+%g3], %g1
+	srl	%g1, 0, %g4
+	mulx	%g4, %i3, %o5
+	srlx	%g1, 32, %g1
+	mulx	%g1, %i3, %g5
+	mulx	%g4, %o4, %g4
+	mulx	%g1, %o4, %g1
+	srlx	%o5, 32, %o1
+	add	%g5, %o1, %o1
+	addcc	%o1, %g4, %g4
+	srl	%o5, 0, %o0
+	sllx	%g4, 32, %o1
+	add	%g1, %o2, %l1
+	movlu	%xcc, %l1, %g1
+	add	%o1, %o0, %l0
+	addcc	%l0, %i0, %g5
+	srlx	%g4, 32, %i0
+	add	%i0, 1, %g4
+	movlu	%xcc, %g4, %i0
+	stx	%g5, [%g2+%g3]
+	add	%i2, -1, %i2
+	add	%i0, %g1, %i0
+	brnz,pt	%i2, L(top)
+	 add	%g3, 8, %g3
+	return	%i7+8
+	 nop
+EPILOGUE()
diff --git a/third_party/gmp/mpn/sparc64/ultrasparct1/rsblsh1_n.asm b/third_party/gmp/mpn/sparc64/ultrasparct1/rsblsh1_n.asm
new file mode 100644
index 0000000..51bd4ab
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/ultrasparct1/rsblsh1_n.asm
@@ -0,0 +1,41 @@
+dnl  SPARC v9 mpn_rsblsh1_n for T1/T2.
+
+dnl  Copyright 2010 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+define(LSH,             1)
+define(RSH,             63)
+
+define(func, mpn_rsblsh1_n)
+
+MULFUNC_PROLOGUE(mpn_rsblsh1_n)
+
+include_mpn(`sparc64/ultrasparct1/rsblshC_n.asm')
diff --git a/third_party/gmp/mpn/sparc64/ultrasparct1/rsblsh2_n.asm b/third_party/gmp/mpn/sparc64/ultrasparct1/rsblsh2_n.asm
new file mode 100644
index 0000000..f0d208e
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/ultrasparct1/rsblsh2_n.asm
@@ -0,0 +1,41 @@
+dnl  SPARC v9 mpn_rsblsh2_n for T1/T2.
+
+dnl  Copyright 2010 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+define(LSH,             2)
+define(RSH,             62)
+
+define(func, mpn_rsblsh2_n)
+
+MULFUNC_PROLOGUE(mpn_rsblsh2_n)
+
+include_mpn(`sparc64/ultrasparct1/rsblshC_n.asm')
diff --git a/third_party/gmp/mpn/sparc64/ultrasparct1/rsblshC_n.asm b/third_party/gmp/mpn/sparc64/ultrasparct1/rsblshC_n.asm
new file mode 100644
index 0000000..7c03e9f
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/ultrasparct1/rsblshC_n.asm
@@ -0,0 +1,69 @@
+dnl  SPARC v9 mpn_rsblshC_n for T1/T2.
+
+dnl  Copyright 2010 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+C		   cycles/limb
+C UltraSPARC T1:	21
+C UltraSPARC T2:	 ?
+
+C INPUT PARAMETERS
+define(`rp', `%o0')
+define(`up', `%o1')
+define(`vp', `%o2')
+define(`n',  `%o3')
+define(`cy', `%o4')
+
+ASM_START()
+	REGISTER(%g2,#scratch)
+	REGISTER(%g3,#scratch)
+PROLOGUE(func)
+	mov	0, cy
+	mov	0, %g5
+	cmp	%g0, cy
+L(top):	ldx	[up+0], %o4
+	add	up, 8, up
+	ldx	[vp+0], %o5
+	add	vp, 8, vp
+	add	rp, 8, rp
+
+	sllx	%o5, LSH, %g4
+	add	n, -1, n
+	or	%g5, %g4, %g4
+	srlx	%o5, RSH, %g5
+
+	srlx	%o4, 32, %g1
+	srlx	%g4, 32, %g2
+	subccc	%g4, %o4, %g3
+	subccc	%g2, %g1, %g0
+	brgz	n, L(top)
+	 stx	%g3, [rp-8]
+
+	retl
+	subc	%g5, %g0, %o0
+EPILOGUE()
diff --git a/third_party/gmp/mpn/sparc64/ultrasparct1/sub_n.asm b/third_party/gmp/mpn/sparc64/ultrasparct1/sub_n.asm
new file mode 100644
index 0000000..c2af89f
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/ultrasparct1/sub_n.asm
@@ -0,0 +1,68 @@
+dnl  SPARC v9 mpn_sub_n for T1/T2.
+
+dnl  Copyright 2010 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		   cycles/limb
+C UltraSPARC T1:	 ?
+C UltraSPARC T2:	 ?
+
+C INPUT PARAMETERS
+define(`rp', `%o0')
+define(`up', `%o1')
+define(`vp', `%o2')
+define(`n',  `%o3')
+define(`cy', `%o4')
+
+ASM_START()
+	REGISTER(%g2,#scratch)
+	REGISTER(%g3,#scratch)
+PROLOGUE(mpn_sub_nc)
+	b,a	L(ent)
+EPILOGUE()
+PROLOGUE(mpn_sub_n)
+	mov	0, cy
+L(ent):	cmp	%g0, cy
+L(top):	ldx	[up+0], %o4
+	add	up, 8, up
+	ldx	[vp+0], %o5
+	add	vp, 8, vp
+	add	rp, 8, rp
+	add	n, -1, n
+	srlx	%o4, 32, %g1
+	srlx	%o5, 32, %g2
+	subccc	%o4, %o5, %g3
+	subccc	%g1, %g2, %g0
+	brgz	n, L(top)
+	 stx	%g3, [rp-8]
+
+	retl
+	addc	%g0, %g0, %o0
+EPILOGUE()
diff --git a/third_party/gmp/mpn/sparc64/ultrasparct1/sublsh1_n.asm b/third_party/gmp/mpn/sparc64/ultrasparct1/sublsh1_n.asm
new file mode 100644
index 0000000..8c8fa80
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/ultrasparct1/sublsh1_n.asm
@@ -0,0 +1,41 @@
+dnl  SPARC v9 mpn_sublsh1_n for T1/T2.
+
+dnl  Copyright 2010 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+define(LSH,             1)
+define(RSH,             63)
+
+define(func, mpn_sublsh1_n)
+
+MULFUNC_PROLOGUE(mpn_sublsh1_n)
+
+include_mpn(`sparc64/ultrasparct1/sublshC_n.asm')
diff --git a/third_party/gmp/mpn/sparc64/ultrasparct1/sublsh2_n.asm b/third_party/gmp/mpn/sparc64/ultrasparct1/sublsh2_n.asm
new file mode 100644
index 0000000..2fd5eee
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/ultrasparct1/sublsh2_n.asm
@@ -0,0 +1,41 @@
+dnl  SPARC v9 mpn_sublsh2_n for T1/T2.
+
+dnl  Copyright 2010 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+define(LSH,             2)
+define(RSH,             62)
+
+define(func, mpn_sublsh2_n)
+
+MULFUNC_PROLOGUE(mpn_sublsh2_n)
+
+include_mpn(`sparc64/ultrasparct1/sublshC_n.asm')
diff --git a/third_party/gmp/mpn/sparc64/ultrasparct1/sublshC_n.asm b/third_party/gmp/mpn/sparc64/ultrasparct1/sublshC_n.asm
new file mode 100644
index 0000000..01eafef
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/ultrasparct1/sublshC_n.asm
@@ -0,0 +1,69 @@
+dnl  SPARC v9 mpn_sublshC_n for T1/T2.
+
+dnl  Copyright 2010 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+C		   cycles/limb
+C UltraSPARC T1:	21
+C UltraSPARC T2:	 ?
+
+C INPUT PARAMETERS
+define(`rp', `%o0')
+define(`up', `%o1')
+define(`vp', `%o2')
+define(`n',  `%o3')
+define(`cy', `%o4')
+
+ASM_START()
+	REGISTER(%g2,#scratch)
+	REGISTER(%g3,#scratch)
+PROLOGUE(func)
+	mov	0, cy
+	mov	0, %g5
+	cmp	%g0, cy
+L(top):	ldx	[up+0], %o4
+	add	up, 8, up
+	ldx	[vp+0], %o5
+	add	vp, 8, vp
+	add	rp, 8, rp
+
+	sllx	%o5, LSH, %g4
+	add	n, -1, n
+	or	%g5, %g4, %g4
+	srlx	%o5, RSH, %g5
+
+	srlx	%o4, 32, %g1
+	srlx	%g4, 32, %g2
+	subccc	%o4, %g4, %g3
+	subccc	%g1, %g2, %g0
+	brgz	n, L(top)
+	 stx	%g3, [rp-8]
+
+	retl
+	addc	%g5, %g0, %o0
+EPILOGUE()
diff --git a/third_party/gmp/mpn/sparc64/ultrasparct1/submul_1.asm b/third_party/gmp/mpn/sparc64/ultrasparct1/submul_1.asm
new file mode 100644
index 0000000..4f553a8
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/ultrasparct1/submul_1.asm
@@ -0,0 +1,86 @@
+dnl  SPARC v9 mpn_submul_1 for T1/T2.
+
+dnl  Copyright 2010 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		   cycles/limb
+C UltraSPARC T1:	74
+C UltraSPARC T2:	 ?
+
+C INPUT PARAMETERS
+define(`rp', `%i0')
+define(`up', `%i1')
+define(`n',  `%i2')
+define(`v0', `%i3')
+
+ASM_START()
+	REGISTER(%g2,#scratch)
+	REGISTER(%g3,#scratch)
+PROLOGUE(mpn_submul_1)
+	save	%sp, -176, %sp
+	mov	1, %o2
+	mov	%i0, %g2
+	srlx	%i3, 32, %o4
+	sllx	%o2, 32, %o2
+	srl	%i3, 0, %i3
+	mov	0, %g3
+	mov	0, %i0
+
+L(top):	ldx	[%i1+%g3], %g1
+	srl	%g1, 0, %g4
+	mulx	%g4, %i3, %o5
+	srlx	%g1, 32, %g1
+	mulx	%g1, %i3, %g5
+	mulx	%g4, %o4, %g4
+	mulx	%g1, %o4, %g1
+	srlx	%o5, 32, %o1
+	add	%g5, %o1, %o1
+	addcc	%o1, %g4, %g4
+	srl	%o5, 0, %o0
+	ldx	[%g2+%g3], %o5
+	sllx	%g4, 32, %o1
+	add	%g1, %o2, %l1
+	movlu	%xcc, %l1, %g1
+	add	%o1, %o0, %l0
+	addcc	%l0, %i0, %g5
+	srlx	%g4, 32, %i0
+	add	%i0, 1, %g4
+	movlu	%xcc, %g4, %i0
+	subcc	%o5, %g5, %g5
+	stx	%g5, [%g2+%g3]
+	add	%i0, 1, %g4
+	movlu	%xcc, %g4, %i0
+	add	%i2, -1, %i2
+	add	%i0, %g1, %i0
+	brnz,pt	%i2, L(top)
+	 add	%g3, 8, %g3
+	return	%i7+8
+	 nop
+EPILOGUE()
diff --git a/third_party/gmp/mpn/sparc64/ultrasparct3/add_n.asm b/third_party/gmp/mpn/sparc64/ultrasparct3/add_n.asm
new file mode 100644
index 0000000..0170746
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/ultrasparct3/add_n.asm
@@ -0,0 +1,126 @@
+dnl  SPARC v9 mpn_add_n for T3/T4.
+
+dnl  Contributed to the GNU project by David Miller.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		   cycles/limb
+C UltraSPARC T3:	 8
+C UltraSPARC T4:	 3
+
+C INPUT PARAMETERS
+define(`rp', `%i0')
+define(`up', `%i1')
+define(`vp', `%i2')
+define(`n',  `%i3')
+define(`cy', `%i4')
+
+define(`u0_off', `%l2')
+define(`u1_off', `%l3')
+define(`loop_n', `%l6')
+define(`tmp', `%l7')
+
+ASM_START()
+	REGISTER(%g2,#scratch)
+	REGISTER(%g3,#scratch)
+PROLOGUE(mpn_add_nc)
+	save	%sp, -176, %sp
+	b,a	L(ent)
+EPILOGUE()
+PROLOGUE(mpn_add_n)
+	save	%sp, -176, %sp
+
+	mov	0, cy
+L(ent):
+	subcc	n, 1, n
+	be	L(final_one)
+	 cmp	%g0, cy
+
+	ldx	[up + 0], %o4
+	sllx	n, 3, tmp
+
+	ldx	[vp + 0], %o5
+	add	up, tmp, u0_off
+
+	ldx	[up + 8], %g5
+	neg	tmp, loop_n
+
+	ldx	[vp + 8], %g1
+	add	u0_off, 8, u1_off
+
+	sub	loop_n, -(2 * 8), loop_n
+
+	brgez,pn loop_n, L(loop_tail)
+	 add	vp, (2 * 8), vp
+
+	b,a	L(top)
+	ALIGN(16)
+L(top):
+	addxccc(%o4, %o5, tmp)
+	ldx	[vp + 0], %o5
+
+	add	rp, (2 * 8), rp
+	ldx	[loop_n + u0_off], %o4
+
+	add	vp, (2 * 8), vp
+	stx	tmp, [rp - 16]
+
+	addxccc(%g1, %g5, tmp)
+	ldx	[vp - 8], %g1
+
+	ldx	[loop_n + u1_off], %g5
+	sub	loop_n, -(2 * 8), loop_n
+
+	brlz	loop_n, L(top)
+	 stx	tmp, [rp - 8]
+
+L(loop_tail):
+	addxccc(%o4, %o5, %g3)
+	add	loop_n, u0_off, up
+
+	addxccc(%g1, %g5, %g5)
+	stx	%g3, [rp + 0]
+
+	brgz,pt	loop_n, L(done)
+	 stx	%g5, [rp + 8]
+
+	add	rp, (2 * 8), rp
+L(final_one):
+	ldx	[up+0], %o4
+	ldx	[vp+0], %o5
+	addxccc(%o4, %o5, %g3)
+	stx	%g3, [rp+0]
+
+L(done):
+	addxc(%g0, %g0, %i0)
+	ret
+	 restore
+EPILOGUE()
diff --git a/third_party/gmp/mpn/sparc64/ultrasparct3/addmul_1.asm b/third_party/gmp/mpn/sparc64/ultrasparct3/addmul_1.asm
new file mode 100644
index 0000000..939811e
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/ultrasparct3/addmul_1.asm
@@ -0,0 +1,182 @@
+dnl  SPARC v9 mpn_addmul_1 for T3/T4/T5.
+
+dnl  Contributed to the GNU project by David Miller and Torbjörn Granlund.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		   cycles/limb
+C UltraSPARC T3:	26
+C UltraSPARC T4:	4.5
+
+C INPUT PARAMETERS
+define(`rp', `%i0')
+define(`up', `%i1')
+define(`n',  `%i2')
+define(`v0', `%i3')
+
+define(`u0',  `%l0')
+define(`u1',  `%l1')
+define(`u2',  `%l2')
+define(`u3',  `%l3')
+define(`r0',  `%l4')
+define(`r1',  `%l5')
+define(`r2',  `%l6')
+define(`r3',  `%l7')
+
+ASM_START()
+	REGISTER(%g2,#scratch)
+	REGISTER(%g3,#scratch)
+PROLOGUE(mpn_addmul_1)
+	save	%sp, -176, %sp
+	ldx	[up+0], %g1
+
+	and	n, 3, %g3
+	brz	%g3, L(b0)
+	 addcc	%g0, %g0, %g5			C clear carry limb, flag
+	cmp	%g3, 2
+	bcs	%xcc, L(b01)
+	 nop
+	be	%xcc, L(b10)
+	 ldx	[up+8], %g5
+
+L(b11):	ldx	[up+16], u3
+	mulx	%g1, v0, %o2
+	umulxhi(%g1, v0, %o3)
+	ldx	[rp+0], r1
+	mulx	%g5, v0, %o4
+	ldx	[rp+8], r2
+	umulxhi(%g5, v0, %o5)
+	ldx	[rp+16], r3
+	mulx	u3, v0, %g4
+	umulxhi(u3, v0, %g5)
+	addcc	%o3, %o4, %o4
+	addxccc(%o5, %g4, %g4)
+	addxc(	%g0, %g5, %g5)
+	addcc	r1, %o2, r1
+	stx	r1, [rp+0]
+	addxccc(r2, %o4, r2)
+	stx	r2, [rp+8]
+	addxccc(r3, %g4, r3)
+	stx	r3, [rp+16]
+	add	n, -3, n
+	add	up, 24, up
+	brz	n, L(xit)
+	 add	rp, 24, rp
+	b	L(com)
+	 nop
+
+L(b10):	mulx	%g1, v0, %o4
+	ldx	[rp+0], r2
+	umulxhi(%g1, v0, %o5)
+	ldx	[rp+8], r3
+	mulx	%g5, v0, %g4
+	umulxhi(%g5, v0, %g5)
+	addcc	%o5, %g4, %g4
+	addxc(	%g0, %g5, %g5)
+	addcc	r2, %o4, r2
+	stx	r2, [rp+0]
+	addxccc(r3, %g4, r3)
+	stx	r3, [rp+8]
+	add	n, -2, n
+	add	up, 16, up
+	brz	n, L(xit)
+	 add	rp, 16, rp
+	b	L(com)
+	 nop
+
+L(b01):	ldx	[rp+0], r3
+	mulx	%g1, v0, %g4
+	umulxhi(%g1, v0, %g5)
+	addcc	r3, %g4, r3
+	stx	r3, [rp+0]
+	add	n, -1, n
+	add	up, 8, up
+	brz	n, L(xit)
+	 add	rp, 8, rp
+
+L(com):	ldx	[up+0], %g1
+L(b0):	ldx	[up+8], u1
+	ldx	[up+16], u2
+	ldx	[up+24], u3
+	mulx	%g1, v0, %o0
+	umulxhi(%g1, v0, %o1)
+	b	L(lo0)
+	 nop
+
+	ALIGN(16)
+L(top):	ldx	[up+0], u0
+	addxc(	%g0, %g5, %g5)		C propagate carry into carry limb
+	ldx	[up+8], u1
+	addcc	r0, %o0, r0
+	ldx	[up+16], u2
+	addxccc(r1, %o2, r1)
+	ldx	[up+24], u3
+	addxccc(r2, %o4, r2)
+	stx	r0, [rp-32]
+	addxccc(r3, %g4, r3)
+	stx	r1, [rp-24]
+	mulx	u0, v0, %o0
+	stx	r2, [rp-16]
+	umulxhi(u0, v0, %o1)
+	stx	r3, [rp-8]
+L(lo0):	mulx	u1, v0, %o2
+	ldx	[rp+0], r0
+	umulxhi(u1, v0, %o3)
+	ldx	[rp+8], r1
+	mulx	u2, v0, %o4
+	ldx	[rp+16], r2
+	umulxhi(u2, v0, %o5)
+	ldx	[rp+24], r3
+	mulx	u3, v0, %g4
+	addxccc(%g5, %o0, %o0)
+	umulxhi(u3, v0, %g5)
+	add	up, 32, up
+	addxccc(%o1, %o2, %o2)
+	add	rp, 32, rp
+	addxccc(%o3, %o4, %o4)
+	add	n, -4, n
+	addxccc(%o5, %g4, %g4)
+	brgz	n, L(top)
+	 nop
+
+	addxc(	%g0, %g5, %g5)
+	addcc	r0, %o0, r0
+	stx	r0, [rp-32]
+	addxccc(r1, %o2, r1)
+	stx	r1, [rp-24]
+	addxccc(r2, %o4, r2)
+	stx	r2, [rp-16]
+	addxccc(r3, %g4, r3)
+	stx	r3, [rp-8]
+L(xit):	addxc(	%g0, %g5, %i0)
+	ret
+	 restore
+EPILOGUE()
diff --git a/third_party/gmp/mpn/sparc64/ultrasparct3/aormul_2.asm b/third_party/gmp/mpn/sparc64/ultrasparct3/aormul_2.asm
new file mode 100644
index 0000000..ccc6a44
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/ultrasparct3/aormul_2.asm
@@ -0,0 +1,228 @@
+dnl  SPARC v9 mpn_mul_2 and mpn_addmul_2 for T3/T4/T5.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C		    cycles/limb      cycles/limb
+C		       mul_2           addmul_2
+C UltraSPARC T3:	22.5		 23.5
+C UltraSPARC T4:	 3.25		 3.75
+
+
+C The code is reasonably scheduled but also relies on OoO.  There was hope that
+C this could run at around 3.0 and 3.5 c/l respectively, on T4.  Two cycles per
+C iteration needs to be removed.
+C
+C We could almost use 2-way unrolling, but currently the wN registers live too
+C long.  By changing add x,w1,w1 to add x,w1,w0, i.e. migrate the values down-
+C wards, 2-way unrolling should become possible.  With n-indexed addressing it
+C should run no slower.
+C
+C The rp loads to g1/g3 are very much over-scheduled.  Presumably, they could
+C be postponed a full way, and then just one register could be used.
+
+C INPUT PARAMETERS
+define(`rp', `%i0')
+define(`up', `%i1')
+define(`n',  `%i2')
+define(`vp', `%i3')
+
+define(`v0', `%o0')
+define(`v1', `%o1')
+
+define(`w0', `%o2')
+define(`w1', `%o3')
+define(`w2', `%o4')
+define(`w3', `%o5')
+
+ifdef(`OPERATION_mul_2',`
+      define(`AM2',      `')
+      define(`ADDX',	 `addcc`'$1')
+      define(`func',     `mpn_mul_2')
+')
+ifdef(`OPERATION_addmul_2',`
+      define(`AM2',      `$1')
+      define(`ADDX',	 `addxccc($1,$2,$3)')
+      define(`func',     `mpn_addmul_2')
+')
+
+
+MULFUNC_PROLOGUE(mpn_mul_2 mpn_addmul_2)
+
+ASM_START()
+	REGISTER(%g2,#scratch)
+	REGISTER(%g3,#scratch)
+PROLOGUE(func)
+	save	%sp, -176, %sp
+
+	ldx	[vp+0], v0		C load v0
+	and	n, 3, %g5
+	ldx	[vp+8], v1		C load v1
+	add	n, -6, n
+	ldx	[up+0], %g4
+	brz	%g5, L(b0)
+	 cmp	%g5, 2
+	bcs	L(b1)
+	 nop
+	be	L(b2)
+	 nop
+
+L(b3):
+AM2(`	ldx	[rp+0], %g1')
+	mulx	%g4, v0, w2
+	umulxhi(%g4, v0, w3)
+	ldx	[up+8], %i5
+	mulx	%g4, v1, %l3
+	umulxhi(%g4, v1, %l7)
+AM2(`	ldx	[rp+8], %g3')
+	add	up, -8, up
+	add	rp, -8, rp
+	b	L(lo3)
+	 mov	0, w0
+
+L(b2):
+AM2(`	ldx	[rp+0], %g3')
+	mulx	%g4, v0, w3
+	umulxhi(%g4, v0, w0)
+	ldx	[up+8], %i4
+	mulx	%g4, v1, %l1
+	umulxhi(%g4, v1, %l5)
+AM2(`	ldx	[rp+8], %g1')
+	add	rp, 16, rp
+	brlz	n, L(end)
+	 mov	0, w1
+	ba	L(top)
+	 add	up, 16, up
+
+L(b1):
+AM2(`	ldx	[rp+0], %g1')
+	mulx	%g4, v0, w0
+	umulxhi(%g4, v0, w1)
+	ldx	[up+8], %i5
+	mulx	%g4, v1, %l3
+	umulxhi(%g4, v1, %l7)
+AM2(`	ldx	[rp+8], %g3')
+	add	up, 8, up
+	add	rp, 8, rp
+	b	L(lo1)
+	 mov	0, w2
+
+L(b0):
+AM2(`	ldx	[rp+0], %g3')
+	mulx	%g4, v0, w1
+	umulxhi(%g4, v0, w2)
+	ldx	[up+8], %i4
+	mulx	%g4, v1, %l1
+	umulxhi(%g4, v1, %l5)
+AM2(`	ldx	[rp+8], %g1')
+	b	L(lo0)
+	 mov	0, w3
+
+	ALIGN(16)			C cycle
+L(top):	mulx	%i4, v0, %l2		C 0->5
+	umulxhi(%i4, v0, %l6)		C 0->5
+	ldx	[up+0], %i5		C 1->6
+AM2(`	addcc	w3, %g3, w3')		C 1
+	stx	w3, [rp-16]		C 2
+	ADDX(`	%l1, w0, w0')		C 2
+	addxccc(%l5, w1, w1)		C 3
+	mulx	%i4, v1, %l3		C 3->9
+	umulxhi(%i4, v1, %l7)		C 4->9
+AM2(`	ldx	[rp+0], %g3')		C 4
+	addcc	%l2, w0, w0		C 5
+	addxccc(%l6, w1, w1)		C 5
+	addxc(	%g0, %g0, w2)		C 6
+L(lo1):	mulx	%i5, v0, %l0		C 6
+	umulxhi(%i5, v0, %l4)		C 7
+	ldx	[up+8], %i4		C 7
+AM2(`	addcc	w0, %g1, w0')		C 8
+	stx	w0, [rp-8]		C 8
+	ADDX(`	%l3, w1, w1')		C 9
+	addxccc(%l7, w2, w2)		C 9
+	mulx	%i5, v1, %l1		C 10
+	umulxhi(%i5, v1, %l5)		C 10
+AM2(`	ldx	[rp+8], %g1')		C 11
+	addcc	%l0, w1, w1		C 11
+	addxccc(%l4, w2, w2)		C 12
+	addxc(	%g0, %g0, w3)		C 12
+L(lo0):	mulx	%i4, v0, %l2		C 13
+	umulxhi(%i4, v0, %l6)		C 13
+	ldx	[up+16], %i5		C 14
+AM2(`	addcc	w1, %g3, w1')		C 14
+	stx	w1, [rp+0]		C 15
+	ADDX(`	%l1, w2, w2')		C 15
+	addxccc(%l5, w3, w3)		C 16
+	mulx	%i4, v1, %l3		C 16
+	umulxhi(%i4, v1, %l7)		C 17
+AM2(`	ldx	[rp+16], %g3')		C 17
+	addcc	%l2, w2, w2		C 18
+	addxccc(%l6, w3, w3)		C 18
+	addxc(	%g0, %g0, w0)		C 19
+L(lo3):	mulx	%i5, v0, %l0		C 19
+	umulxhi(%i5, v0, %l4)		C 20
+	ldx	[up+24], %i4		C 20
+AM2(`	addcc	w2, %g1, w2')		C 21
+	stx	w2, [rp+8]		C 21
+	ADDX(`	%l3, w3, w3')		C 22
+	addxccc(%l7, w0, w0)		C 22
+	mulx	%i5, v1, %l1		C 23
+	umulxhi(%i5, v1, %l5)		C 23
+AM2(`	ldx	[rp+24], %g1')		C 24
+	addcc	%l0, w3, w3		C 24
+	addxccc(%l4, w0, w0)		C 25
+	addxc(	%g0, %g0, w1)		C 25
+	add	up, 32, up
+	add	rp, 32, rp
+	brgz	n, L(top)
+	 add	n, -4, n
+
+L(end):	mulx	%i4, v0, %l2
+	umulxhi(%i4, v0, %l6)
+AM2(`	addcc	w3, %g3, w3')
+	stx	w3, [rp-16]
+	ADDX(`	%l1, w0, w0')
+	addxccc(%l5, w1, w1)
+	mulx	%i4, v1, %l3
+	umulxhi(%i4, v1, %l7)
+	addcc	%l2, w0, w0
+	addxccc(%l6, w1, w1)
+	addxc(	%g0, %g0, w2)
+AM2(`	addcc	w0, %g1, w0')
+	stx	w0, [rp-8]
+	ADDX(`	%l3, w1, w1')
+	stx	w1, [rp+0]
+	addxc(%l7, w2, %i0)
+
+	ret
+	 restore
+EPILOGUE()
diff --git a/third_party/gmp/mpn/sparc64/ultrasparct3/aormul_4.asm b/third_party/gmp/mpn/sparc64/ultrasparct3/aormul_4.asm
new file mode 100644
index 0000000..845f6d6
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/ultrasparct3/aormul_4.asm
@@ -0,0 +1,219 @@
+dnl  SPARC v9 mpn_mul_4 and mpn_addmul_4 for T3/T4/T5.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C		    cycles/limb      cycles/limb
+C		       mul_4           addmul_4
+C UltraSPARC T3:	21.5		22.0
+C UltraSPARC T4:	 2.625		 2.75
+
+
+C The code is well-scheduled and relies on OoO very little.  There is hope that
+C this will run at around 2.5 and 2.75 c/l respectively, on T4.
+
+define(`rp', `%i0')
+define(`up', `%i1')
+define(`n',  `%i2')
+define(`vp', `%i3')
+
+define(`v0', `%g1')
+define(`v1', `%o7')
+define(`v2', `%g2')
+define(`v3', `%i3')
+
+define(`w0', `%o0')
+define(`w1', `%o1')
+define(`w2', `%o2')
+define(`w3', `%o3')
+define(`w4', `%o4')
+
+define(`r0', `%o5')
+
+define(`u0', `%i4')
+define(`u1', `%i5')
+
+define(`rp0', `rp')
+define(`rp1', `%g3')
+define(`rp2', `%g4')
+define(`up0', `up')
+define(`up1', `%g5')
+
+ifdef(`OPERATION_mul_4',`
+      define(`AM4',      `')
+      define(`ADDX',	 `addcc`'$1')
+      define(`func',     `mpn_mul_4')
+')
+ifdef(`OPERATION_addmul_4',`
+      define(`AM4',      `$1')
+      define(`ADDX',	 `addxccc($1,$2,$3)')
+      define(`func',     `mpn_addmul_4')
+')
+
+
+MULFUNC_PROLOGUE(mpn_mul_4 mpn_addmul_4)
+
+ASM_START()
+	REGISTER(%g2,#scratch)
+	REGISTER(%g3,#scratch)
+PROLOGUE(func)
+	save	%sp, -176, %sp
+
+	ldx	[up + 0], u1		C load up[0] early
+	andcc	n, 1, %g0		C is n odd?
+	ldx	[vp + 0], v0
+	sllx	n, 3, n
+	ldx	[vp + 8], v1
+	add	n, -28, n
+	ldx	[vp + 16], v2
+	add	rp, -16, rp
+	ldx	[vp + 24], v3
+	add	up, n, up0
+	add	rp, n, rp0
+	add	up0, 8, up1
+	add	rp0, 8, rp1
+	add	rp0, 16, rp2
+	mulx	u1, v0, %l0
+	mov	0, w0
+	mulx	u1, v1, %l1
+	mov	0, w1
+	mulx	u1, v2, %l2
+	mov	0, w2
+	mulx	u1, v3, %l3
+	mov	0, w3
+
+	be	L(evn)
+	 neg	n, n
+
+L(odd):	mov	u1, u0
+	ldx	[up1 + n], u1
+AM4(`	ldx	[rp2 + n], r0')
+	umulxhi(u0, v0, %l4)
+	umulxhi(u0, v1, %l5)
+	umulxhi(u0, v2, %l6)
+	umulxhi(u0, v3, %l7)
+	b	L(mid)
+	 add	n, 8, n
+
+L(evn):	ldx	[up1 + n], u0
+AM4(`	ldx	[rp2 + n], r0')
+	umulxhi(u1, v0, %l4)
+	umulxhi(u1, v1, %l5)
+	umulxhi(u1, v2, %l6)
+	umulxhi(u1, v3, %l7)
+	add	n, 16, n
+
+	ALIGN(16)
+L(top):	addcc	%l0, w0, w0
+	mulx	u0, v0, %l0	C w 0
+	addxccc(%l1, w1, w1)
+	mulx	u0, v1, %l1	C w 1
+	addxccc(%l2, w2, w2)
+	mulx	u0, v2, %l2	C w 2
+	addxccc(%l3, w3, w3)
+	mulx	u0, v3, %l3	C w 3
+	ldx	[up0 + n], u1
+	addxc(	%g0, %g0, w4)
+AM4(`	addcc	r0, w0, w0')
+	stx	w0, [rp0 + n]
+	ADDX(`	%l4, w1, w0')
+	umulxhi(u0, v0, %l4)	C w 1
+AM4(`	ldx	[rp1 + n], r0')
+	addxccc(%l5, w2, w1)
+	umulxhi(u0, v1, %l5)	C w 2
+	addxccc(%l6, w3, w2)
+	umulxhi(u0, v2, %l6)	C w 3
+	addxc(	%l7, w4, w3)
+	umulxhi(u0, v3, %l7)	C w 4
+L(mid):	addcc	%l0, w0, w0
+	mulx	u1, v0, %l0	C w 1
+	addxccc(%l1, w1, w1)
+	mulx	u1, v1, %l1	C w 2
+	addxccc(%l2, w2, w2)
+	mulx	u1, v2, %l2	C w 3
+	addxccc(%l3, w3, w3)
+	mulx	u1, v3, %l3	C w 4
+	ldx	[up1 + n], u0
+	addxc(	%g0, %g0, w4)
+AM4(`	addcc	r0, w0, w0')
+	stx	w0, [rp1 + n]
+	ADDX(`	%l4, w1, w0')
+	umulxhi(u1, v0, %l4)	C w 2
+AM4(`	ldx	[rp2 + n], r0')
+	addxccc(%l5, w2, w1)
+	umulxhi(u1, v1, %l5)	C w 3
+	addxccc(%l6, w3, w2)
+	umulxhi(u1, v2, %l6)	C w 4
+	addxc(	%l7, w4, w3)
+	umulxhi(u1, v3, %l7)	C w 5
+	brlz	n, L(top)
+	 add	n, 16, n
+
+L(end):	addcc	%l0, w0, w0
+	mulx	u0, v0, %l0
+	addxccc(%l1, w1, w1)
+	mulx	u0, v1, %l1
+	addxccc(%l2, w2, w2)
+	mulx	u0, v2, %l2
+	addxccc(%l3, w3, w3)
+	mulx	u0, v3, %l3
+	addxc(	%g0, %g0, w4)
+AM4(`	addcc	r0, w0, w0')
+	stx	w0, [rp0 + n]
+	ADDX(`	%l4, w1, w0')
+	umulxhi(u0, v0, %l4)
+AM4(`	ldx	[rp1 + n], r0')
+	addxccc(%l5, w2, w1)
+	umulxhi(u0, v1, %l5)
+	addxccc(%l6, w3, w2)
+	umulxhi(u0, v2, %l6)
+	addxc(	%l7, w4, w3)
+	umulxhi(u0, v3, %l7)
+	addcc	%l0, w0, w0
+	addxccc(%l1, w1, w1)
+	addxccc(%l2, w2, w2)
+	addxccc(%l3, w3, w3)
+	addxc(	%g0, %g0, w4)
+AM4(`	addcc	r0, w0, w0')
+	stx	w0, [rp1 + n]
+	ADDX(`	%l4, w1, w0')
+	addxccc(%l5, w2, w1)
+	addxccc(%l6, w3, w2)
+	stx	w0, [rp2 + n]
+	add	n, 16, n
+	stx	w1, [rp1 + n]
+	stx	w2, [rp2 + n]
+	addxc(	%l7, w4, %i0)
+	ret
+	 restore
+EPILOGUE()
diff --git a/third_party/gmp/mpn/sparc64/ultrasparct3/aorslsh_n.asm b/third_party/gmp/mpn/sparc64/ultrasparct3/aorslsh_n.asm
new file mode 100644
index 0000000..1014b1b
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/ultrasparct3/aorslsh_n.asm
@@ -0,0 +1,147 @@
+dnl  SPARC v9 mpn_addlsh_n and mpn_sublsh_n for T3/T4/T5.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		   cycles/limb
+C UltraSPARC T3:	11
+C UltraSPARC T4:	 4
+
+C For sublsh_n we combine the two shifted limbs using xnor, using the identity
+C (a xor not b) = (not (a xor b)) which equals (not (a or b)) when (a and b) =
+C 0 as it is in our usage.  This gives us the ones complement for free.
+C Unfortunately, the same trick will not work for rsblsh_n, which will instead
+C require a separate negation.
+C
+C FIXME: Add rsblsh_n to this file.
+
+define(`rp', `%i0')
+define(`up', `%i1')
+define(`vp', `%i2')
+define(`n',  `%i3')
+define(`cnt',`%i4')
+
+define(`tnc',`%o5')
+
+ifdef(`OPERATION_addlsh_n',`
+  define(`INITCY', `subcc	%g0, 0, %g0')
+  define(`MERGE',  `or')
+  define(`func',   `mpn_addlsh_n')
+')
+ifdef(`OPERATION_sublsh_n',`
+  define(`INITCY', `subcc	%g0, 1, %g0')
+  define(`MERGE',  `xnor')
+  define(`func',   `mpn_sublsh_n')
+')
+
+define(`rp0',  `rp')
+define(`rp1',  `%o2')
+define(`up0',  `up')
+define(`up1',  `%o3')
+define(`vp0',  `vp')
+define(`vp1',  `%o4')
+
+MULFUNC_PROLOGUE(mpn_addlsh_n mpn_sublsh_n)
+ASM_START()
+	REGISTER(%g2,#scratch)
+	REGISTER(%g3,#scratch)
+PROLOGUE(func)
+	save	%sp, -176, %sp
+	mov	64, tnc
+	sub	tnc, cnt, tnc
+
+	andcc	n, 1, %g0
+	sllx	n, 3, n
+	add	n, -16, n
+	add	up, n, up0
+	add	vp, n, vp0
+	add	rp, n, rp0
+	add	up0, 8, up1
+	add	vp0, 8, vp1
+	add	rp0, -8, rp1
+	add	rp0, -16, rp0
+	neg	n, n
+	be	L(evn)
+	 INITCY
+
+L(odd):	ldx	[vp0 + n], %l1
+	mov	0, %l2
+	ldx	[up0 + n], %l5
+	sllx	%l1, cnt, %g3
+	brgez	n, L(wd1)
+	 add	n, 8, n
+	ldx	[vp0 + n], %l0
+	b	L(lo1)
+	 sllx	%l1, cnt, %g3
+
+L(evn):	ldx	[vp0 + n], %l0
+	mov	0, %l3
+	ldx	[up0 + n], %l4
+	ldx	[vp1 + n], %l1
+	b	L(lo0)
+	 sllx	%l0, cnt, %g1
+
+L(top):	addxccc(%l6, %l4, %o0)
+	ldx	[vp0 + n], %l0
+	sllx	%l1, cnt, %g3
+	stx	%o0, [rp0 + n]
+L(lo1):	srlx	%l1, tnc, %l3
+	MERGE	%l2, %g3, %l7
+	ldx	[up0 + n], %l4
+	addxccc(%l7, %l5, %o1)
+	ldx	[vp1 + n], %l1
+	sllx	%l0, cnt, %g1
+	stx	%o1, [rp1 + n]
+L(lo0):	srlx	%l0, tnc, %l2
+	MERGE	%l3, %g1, %l6
+	ldx	[up1 + n], %l5
+	brlz,pt	n, L(top)
+	 add	n, 16, n
+
+	addxccc(%l6, %l4, %o0)
+	sllx	%l1, cnt, %g3
+	stx	%o0, [rp0 + n]
+L(wd1):	srlx	%l1, tnc, %l3
+	MERGE	%l2, %g3, %l7
+	addxccc(%l7, %l5, %o1)
+	stx	%o1, [rp1 + n]
+
+ifdef(`OPERATION_addlsh_n',
+`	addxc(	%l3, %g0, %i0)')
+ifdef(`OPERATION_sublsh_n',
+`	addxc(	%g0, %g0, %g1)
+	add	%g1, -1, %g1
+	sub	%l3, %g1, %i0')
+
+	ret
+	 restore
+EPILOGUE()
diff --git a/third_party/gmp/mpn/sparc64/ultrasparct3/bdiv_dbm1c.asm b/third_party/gmp/mpn/sparc64/ultrasparct3/bdiv_dbm1c.asm
new file mode 100644
index 0000000..550860d
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/ultrasparct3/bdiv_dbm1c.asm
@@ -0,0 +1,147 @@
+dnl  SPARC T3/T4/T5 mpn_bdiv_dbm1c.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                  cycles/limb
+C UltraSPARC T3:	25
+C UltraSPARC T4/T5:	 4
+
+C INPUT PARAMETERS
+define(`qp',  `%i0')
+define(`ap',  `%i1')
+define(`n',   `%i2')
+define(`bd',  `%i3')
+define(`h',   `%i4')
+
+define(`plo0',`%g4')  define(`plo1',`%g5')
+define(`phi0',`%l0')  define(`phi1',`%l1')
+define(`a0',  `%g1')  define(`a1',  `%g3')
+
+ASM_START()
+	REGISTER(%g2,#scratch)
+	REGISTER(%g3,#scratch)
+PROLOGUE(mpn_bdiv_dbm1c)
+	save	%sp, -176, %sp
+
+	and	n, 3, %g5
+	ldx	[ap + 0], %g2
+	add	n, -5, n
+	brz	%g5, L(b0)
+	 cmp	%g5, 2
+	bcs	%xcc, L(b1)
+	 nop
+	be	%xcc, L(b2)
+	 nop
+
+L(b3):	ldx	[ap + 8], a0
+	mulx	bd, %g2, plo1
+	umulxhi(bd, %g2, phi1)
+	ldx	[ap + 16], a1
+	add	qp, -24, qp
+	b	L(lo3)
+	 add	ap, -8, ap
+
+L(b2):	ldx	[ap + 8], a1
+	mulx	bd, %g2, plo0
+	umulxhi(bd, %g2, phi0)
+	brlz,pt n, L(wd2)
+	 nop
+L(gt2):	ldx	[ap + 16], a0
+	add	ap, 16, ap
+	b	L(lo2)
+	 add	n, -1, n
+
+L(b1):	mulx	bd, %g2, plo1
+	 umulxhi(bd, %g2, phi1)
+	brlz,pn	n, L(wd1)
+	 add	qp, -8, qp
+L(gt1):	ldx	[ap + 8], a0
+	ldx	[ap + 16], a1
+	b	L(lo1)
+	 add	ap, 8, ap
+
+L(b0):	ldx	[ap + 8], a1
+	mulx	bd, %g2, plo0
+	umulxhi(bd, %g2, phi0)
+	ldx	[ap + 16], a0
+	b	L(lo0)
+	 add	qp, -16, qp
+
+L(top):	ldx	[ap + 0], a0
+	sub	h, phi1, h
+L(lo2):	mulx	bd, a1, plo1
+	umulxhi(bd, a1, phi1)
+	subcc	h, plo0, h
+	addxc(	phi0, %g0, phi0)
+	stx	h, [qp + 0]
+	ldx	[ap + 8], a1
+	sub	h, phi0, h
+L(lo1):	mulx	bd, a0, plo0
+	umulxhi(bd, a0, phi0)
+	subcc	h, plo1, h
+	addxc(	phi1, %g0, phi1)
+	stx	h, [qp + 8]
+	ldx	[ap + 16], a0
+	sub	h, phi1, h
+L(lo0):	mulx	bd, a1, plo1
+	umulxhi(bd, a1, phi1)
+	subcc	h, plo0, h
+	addxc(	phi0, %g0, phi0)
+	stx	h, [qp + 16]
+	ldx	[ap + 24], a1
+	sub	h, phi0, h
+L(lo3):	mulx	bd, a0, plo0
+	umulxhi(bd, a0, phi0)
+	subcc	h, plo1, h
+	addxc(	phi1, %g0, phi1)
+	stx	h, [qp + 24]
+	add	ap, 32, ap
+	add	qp, 32, qp
+	brgz,pt	n, L(top)
+	 add	n, -4, n
+
+L(end):	sub	h, phi1, h
+L(wd2):	mulx	bd, a1, plo1
+	umulxhi(bd, a1, phi1)
+	subcc	h, plo0, h
+	addxc(	phi0, %g0, phi0)
+	stx	h, [qp + 0]
+	sub	h, phi0, h
+L(wd1):	subcc	h, plo1, h
+	addxc(	phi1, %g0, phi1)
+	stx	h, [qp + 8]
+	sub	h, phi1, %i0
+
+	ret
+	 restore
+EPILOGUE()
diff --git a/third_party/gmp/mpn/sparc64/ultrasparct3/bdiv_q_1.asm b/third_party/gmp/mpn/sparc64/ultrasparct3/bdiv_q_1.asm
new file mode 100644
index 0000000..9847047
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/ultrasparct3/bdiv_q_1.asm
@@ -0,0 +1,137 @@
+dnl  SPARC T3/T4/T5 mpn_bdiv_q_1.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013, 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                  cycles/limb
+C UltraSPARC T3:	31
+C UltraSPARC T4/T5:	20-26  hits 20 early, then sharply drops
+
+C INPUT PARAMETERS
+define(`qp',  `%i0')
+define(`ap',  `%i1')
+define(`n',   `%i2')
+define(`d',   `%i3')
+define(`dinv',`%i4')
+define(`cnt', `%i5')
+
+define(`tnc', `%o2')
+
+ASM_START()
+	REGISTER(%g2,#scratch)
+	REGISTER(%g3,#scratch)
+PROLOGUE(mpn_bdiv_q_1)
+	save	%sp, -176, %sp
+	ldx	[ap], %o5
+	add	d, -1, %g1
+	andn	%g1, d, %g1
+	popc	%g1, cnt
+
+	srlx	d, cnt, d
+	srlx	d, 1, %g1
+	and	%g1, 127, %g1
+	LEA64(binvert_limb_table, g2, g4)
+	ldub	[%g2+%g1], %g1
+	add	%g1, %g1, %g2
+	mulx	%g1, %g1, %g1
+	mulx	%g1, d, %g1
+	sub	%g2, %g1, %g2
+	add	%g2, %g2, %g1
+	mulx	%g2, %g2, %g2
+	mulx	%g2, d, %g2
+	sub	%g1, %g2, %g1
+	add	%g1, %g1, %o7
+	mulx	%g1, %g1, %g1
+	mulx	%g1, d, %g1
+	add	n, -2, n
+	brz,pt	cnt, L(norm)
+	 sub	%o7, %g1, dinv
+
+	brlz,pt	n, L(edu)
+	 srlx	%o5, cnt, %o5
+	b	L(eee)
+	 mov	0, %g4
+EPILOGUE()
+
+PROLOGUE(mpn_pi1_bdiv_q_1)
+	save	%sp, -176, %sp
+	ldx	[ap], %o5
+
+	brz,pt	cnt, L(norm)
+	 add	n, -2, n
+
+L(unorm):
+	brlz,pt	n, L(edu)
+	 srlx	%o5, cnt, %o5
+	mov	0, %g4
+L(eee):	sub	%g0, cnt, tnc
+
+L(tpu):	ldx	[ap+8], %g3
+	add	ap, 8, ap
+	sllx	%g3, tnc, %g5
+	or	%g5, %o5, %g5
+	srlx	%g3, cnt, %o5
+	subcc	%g5, %g4, %g4
+	mulx	%g4, dinv, %g1
+	stx	%g1, [qp]
+	add	qp, 8, qp
+	umulxhi(d, %g1, %g1)
+	addxc(	%g1, %g0, %g4)
+	brgz,pt	n, L(tpu)
+	 add	n, -1, n
+
+	sub	%o5, %g4, %o5
+L(edu):	mulx	%o5, dinv, %g1
+	return	%i7+8
+	 stx	%g1, [%o0]
+
+L(norm):
+	mulx	dinv, %o5, %g1
+	brlz,pt	n, L(edn)
+	 stx	%g1, [qp]
+	add	qp, 8, qp
+	addcc	%g0, 0, %g4
+
+L(tpn):	umulxhi(d, %g1, %g1)
+	ldx	[ap+8], %g5
+	add	ap, 8, ap
+	addxc(	%g1, %g0, %g1)
+	subcc	%g5, %g1, %g1
+	mulx	%g1, dinv, %g1
+	stx	%g1, [qp]
+	add	qp, 8, qp
+	brgz,pt	n, L(tpn)
+	 add	n, -1, n
+
+L(edn):	return	%i7+8
+	 nop
+EPILOGUE()
diff --git a/third_party/gmp/mpn/sparc64/ultrasparct3/cnd_aors_n.asm b/third_party/gmp/mpn/sparc64/ultrasparct3/cnd_aors_n.asm
new file mode 100644
index 0000000..49ccaec
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/ultrasparct3/cnd_aors_n.asm
@@ -0,0 +1,145 @@
+dnl  SPARC v9 mpn_cnd_add_n and mpn_cnd_sub_n for T3/T4/T5.
+
+dnl  Contributed to the GNU project by David Miller and Torbjörn Granlund.
+
+dnl  Copyright 2013, 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		   cycles/limb
+C UltraSPARC T3:	 8.5
+C UltraSPARC T4:	 3
+
+C We use a double-pointer trick to allow indexed addressing.  Its setup
+C cost might be a problem in these functions, since we don't expect huge n
+C arguments.
+C
+C For sub we need ~(a & mask) = (~a | ~mask) but by complementing mask we can
+C instead do ~(a & ~mask) = (~a | mask), allowing us to use the orn insn.
+
+C INPUT PARAMETERS
+define(`cnd', `%i0')
+define(`rp',  `%i1')
+define(`up',  `%i2')
+define(`vp',  `%i3')
+define(`n',   `%i4')
+
+define(`mask',   `cnd')
+define(`up0', `%l0')  define(`up1', `%l1')
+define(`vp0', `%l2')  define(`vp1', `%l3')
+define(`rp0', `%g4')  define(`rp1', `%g5')
+define(`u0',  `%l4')  define(`u1',  `%l5')
+define(`v0',  `%l6')  define(`v1',  `%l7')
+define(`x0',  `%g1')  define(`x1',  `%g3')
+define(`w0',  `%g1')  define(`w1',  `%g3')
+
+ifdef(`OPERATION_cnd_add_n',`
+  define(`LOGOP',   `and	$1, $2, $3')
+  define(`MAKEMASK',`cmp	%g0, $1
+		     addxc(	%g0, %g0, $2)
+		     neg	$2, $2')
+  define(`INITCY',  `addcc	%g0, 0, %g0')
+  define(`RETVAL',  `addxc(	%g0, %g0, %i0)')
+  define(`func',    `mpn_cnd_add_n')
+')
+ifdef(`OPERATION_cnd_sub_n',`
+  define(`LOGOP',   `orn	$2, $1, $3')
+  define(`MAKEMASK',`cmp	$1, 1
+		     addxc(	%g0, %g0, $2)
+		     neg	$2, $2')
+  define(`INITCY',  `subcc	%g0, 1, %g0')
+  define(`RETVAL',  `addxc(	%g0, %g0, %i0)
+		     xor	%i0, 1, %i0')
+  define(`func',    `mpn_cnd_sub_n')
+')
+
+MULFUNC_PROLOGUE(mpn_cnd_add_n mpn_cnd_sub_n)
+
+ASM_START()
+	REGISTER(%g2,#scratch)
+	REGISTER(%g3,#scratch)
+PROLOGUE(func)
+	save	%sp, -176, %sp
+
+	MAKEMASK(cnd,mask)
+
+	andcc	n, 1, %g0
+	sllx	n, 3, n
+	add	n, -16, n
+	add	vp, n, vp0
+	add	up, n, up0
+	add	rp, n, rp0
+	neg	n, n
+	be	L(evn)
+	 INITCY
+
+L(odd):	ldx	[vp0 + n], v1
+	ldx	[up0 + n], u1
+	LOGOP(	v1, mask, x1)
+	addxccc(u1, x1, w1)
+	stx	w1, [rp0 + n]
+	add	n, 8, n
+	brgz	n, L(rtn)
+	 nop
+
+L(evn):	add	vp0, 8, vp1
+	add	up0, 8, up1
+	add	rp0, -24, rp1
+	ldx	[vp0 + n], v0
+	ldx	[vp1 + n], v1
+	ldx	[up0 + n], u0
+	ldx	[up1 + n], u1
+	add	n, 16, n
+	brgz	n, L(end)
+	 add	rp0, -16, rp0
+
+L(top):	LOGOP(	v0, mask, x0)
+	ldx	[vp0 + n], v0
+	LOGOP(	v1, mask, x1)
+	ldx	[vp1 + n], v1
+	addxccc(u0, x0, w0)
+	ldx	[up0 + n], u0
+	addxccc(u1, x1, w1)
+	ldx	[up1 + n], u1
+	stx	w0, [rp0 + n]
+	add	n, 16, n
+	brlez	n, L(top)
+	 stx	w1, [rp1 + n]
+
+L(end):	LOGOP(	v0, mask, x0)
+	LOGOP(	v1, mask, x1)
+	addxccc(u0, x0, w0)
+	addxccc(u1, x1, w1)
+	stx	w0, [rp0 + n]
+	stx	w1, [rp1 + 32]
+
+L(rtn):	RETVAL
+	ret
+	 restore
+EPILOGUE()
diff --git a/third_party/gmp/mpn/sparc64/ultrasparct3/dive_1.asm b/third_party/gmp/mpn/sparc64/ultrasparct3/dive_1.asm
new file mode 100644
index 0000000..d7dbdf9
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/ultrasparct3/dive_1.asm
@@ -0,0 +1,129 @@
+dnl  SPARC T3/T4/T5 mpn_divexact_1.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                  cycles/limb
+C UltraSPARC T3:	31
+C UltraSPARC T4/T5:	20-26  hits 20 early, then sharply drops
+
+C INPUT PARAMETERS
+define(`qp',  `%i0')
+define(`ap',  `%i1')
+define(`n',   `%i2')
+define(`d',   `%i3')
+
+define(`dinv',`%o4')
+
+ASM_START()
+	REGISTER(%g2,#scratch)
+	REGISTER(%g3,#scratch)
+PROLOGUE(mpn_divexact_1)
+	save	%sp, -176, %sp
+	cmp	n, 1
+	bne,pt	%xcc, L(gt1)
+	 ldx	[ap], %o5
+	udivx	%o5, d, %g1
+	stx	%g1, [qp]
+	return	%i7+8
+	 nop
+
+L(gt1):	add	d, -1, %g1
+	andn	%g1, d, %g1
+	popc	%g1, %i4		C i4 = count_trailing_zeros(d)
+
+	srlx	d, %i4, d
+	srlx	d, 1, %g1
+	and	%g1, 127, %g1
+
+	LEA64(binvert_limb_table, g2, g4)
+	ldub	[%g2+%g1], %g1
+	add	%g1, %g1, %g2
+	mulx	%g1, %g1, %g1
+	mulx	%g1, d, %g1
+	sub	%g2, %g1, %g2
+	add	%g2, %g2, %g1
+	mulx	%g2, %g2, %g2
+	mulx	%g2, d, %g2
+	sub	%g1, %g2, %g1
+	add	%g1, %g1, %o7
+	mulx	%g1, %g1, %g1
+	mulx	%g1, d, %g1
+	add	n, -2, n
+	brz,pt	%i4, L(norm)
+	 sub	%o7, %g1, dinv
+
+L(unnorm):
+	mov	0, %g4
+	sub	%g0, %i4, %o2
+	srlx	%o5, %i4, %o5
+L(top_unnorm):
+	ldx	[ap+8], %g3
+	add	ap, 8, ap
+	sllx	%g3, %o2, %g5
+	or	%g5, %o5, %g5
+	srlx	%g3, %i4, %o5
+	subcc	%g5, %g4, %g4
+	mulx	%g4, dinv, %g1
+	stx	%g1, [qp]
+	add	qp, 8, qp
+	umulxhi(d, %g1, %g1)
+	addxc(	%g1, %g0, %g4)
+	brgz,pt	n, L(top_unnorm)
+	 add	n, -1, n
+
+	sub	%o5, %g4, %g4
+	mulx	%g4, dinv, %g1
+	stx	%g1, [qp]
+	return	%i7+8
+	 nop
+
+L(norm):
+	mulx	dinv, %o5, %g1
+	stx	%g1, [qp]
+	add	qp, 8, qp
+	addcc	%g0, 0, %g4
+L(top_norm):
+	umulxhi(d, %g1, %g1)
+	ldx	[ap+8], %g5
+	add	ap, 8, ap
+	addxc(	%g1, %g0, %g1)
+	subcc	%g5, %g1, %g1
+	mulx	%g1, dinv, %g1
+	stx	%g1, [qp]
+	add	qp, 8, qp
+	brgz,pt	n, L(top_norm)
+	 add	n, -1, n
+
+	return	%i7+8
+	 nop
+EPILOGUE()
diff --git a/third_party/gmp/mpn/sparc64/ultrasparct3/hamdist.asm b/third_party/gmp/mpn/sparc64/ultrasparct3/hamdist.asm
new file mode 100644
index 0000000..20ed8bf
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/ultrasparct3/hamdist.asm
@@ -0,0 +1,78 @@
+dnl  SPARC v9 mpn_hamdist for T3/T4.
+
+dnl  Contributed to the GNU project by David Miller.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		   cycles/limb
+C UltraSPARC T3:	18
+C UltraSPARC T4:	 3.5
+
+C INPUT PARAMETERS
+define(`up',   `%o0')
+define(`vp',   `%o1')
+define(`n',    `%o2')
+define(`pcnt', `%o5')
+
+ASM_START()
+	REGISTER(%g2,#scratch)
+	REGISTER(%g3,#scratch)
+PROLOGUE(mpn_hamdist)
+	subcc	n, 1, n
+	be	L(final_one)
+	 clr	pcnt
+L(top):
+	ldx	[up + 0], %g1
+	ldx	[vp + 0], %g2
+	ldx	[up + 8], %o4
+	ldx	[vp + 8], %g3
+	sub	n, 2, n
+	xor	%g1, %g2, %g1
+	add	up, 16, up
+	popc	%g1, %g2
+	add	vp, 16, vp
+	xor	%o4, %g3, %o4
+	add	pcnt, %g2, pcnt
+	popc	%o4, %g3
+	brgz	n, L(top)
+	 add	pcnt, %g3, pcnt
+	brlz,pt	n, L(done)
+	 nop
+L(final_one):
+	ldx	[up + 0], %g1
+	ldx	[vp + 0], %g2
+	xor	%g1,%g2, %g1
+	popc	%g1, %g2
+	add	pcnt, %g2, pcnt
+L(done):
+	retl
+	 mov	pcnt, %o0
+EPILOGUE()
diff --git a/third_party/gmp/mpn/sparc64/ultrasparct3/invert_limb.asm b/third_party/gmp/mpn/sparc64/ultrasparct3/invert_limb.asm
new file mode 100644
index 0000000..4da49cf
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/ultrasparct3/invert_limb.asm
@@ -0,0 +1,92 @@
+dnl  SPARC T3/T4/T5 mpn_invert_limb.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                  cycles/limb
+C UltraSPARC T3:	 ?
+C UltraSPARC T4/T5:	 ?
+
+C INPUT PARAMETERS
+define(`d',  `%o0')
+
+ASM_START()
+	REGISTER(%g2,#scratch)
+	REGISTER(%g3,#scratch)
+PROLOGUE(mpn_invert_limb)
+	srlx	d, 54, %g1
+	LEA64(approx_tab, g2, g3)
+	and	%g1, 0x1fe, %g1
+	srlx	d, 24, %g4
+	lduh	[%g2+%g1], %g3
+	add	%g4, 1, %g4
+	sllx	%g3, 11, %g2
+	add	%g2, -1, %g2
+	mulx	%g3, %g3, %g3
+	mulx	%g3, %g4, %g3
+	srlx	%g3, 40, %g3
+	sub	%g2, %g3, %g2
+	sllx	%g2, 60, %g1
+	mulx	%g2, %g2, %g3
+	mulx	%g3, %g4, %g4
+	sub	%g1, %g4, %g1
+	srlx	%g1, 47, %g1
+	sllx	%g2, 13, %g2
+	add	%g1, %g2, %g1
+	and	d, 1, %g2
+	srlx	%g1, 1, %g4
+	sub	%g0, %g2, %g3
+	and	%g4, %g3, %g3
+	srlx	d, 1, %g4
+	add	%g4, %g2, %g2
+	mulx	%g1, %g2, %g2
+	sub	%g3, %g2, %g2
+	umulxhi(%g1, %g2, %g2)
+	srlx	%g2, 1, %g2
+	sllx	%g1, 31, %g1
+	add	%g2, %g1, %g1
+	mulx	%g1, d, %g3
+	umulxhi(d, %g1, %g4)
+	addcc	%g3, d, %g0
+	addxc(	%g4, d, %o0)
+	jmp	%o7+8
+	 sub	%g1, %o0, %o0
+EPILOGUE()
+
+	RODATA
+	ALIGN(2)
+	TYPE(	approx_tab, object)
+	SIZE(	approx_tab, 512)
+approx_tab:
+forloop(i,256,512-1,dnl
+`	.half	eval(0x7fd00/i)
+')dnl
diff --git a/third_party/gmp/mpn/sparc64/ultrasparct3/missing.asm b/third_party/gmp/mpn/sparc64/ultrasparct3/missing.asm
new file mode 100644
index 0000000..c79032d
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/ultrasparct3/missing.asm
@@ -0,0 +1,77 @@
+dnl  SPARC v9-2011 simulation support.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ASM_START()
+PROLOGUE(__gmpn_umulh)
+	save	%sp, -176, %sp
+	ldx	[%sp+2047+176+256], %o0
+	ldx	[%sp+2047+176+256+8], %o1
+	rd	%ccr, %o4
+	srl	%o0, 0, %l4
+	srl	%o1, 0, %l1
+	srlx	%o1, 32, %o1
+	mulx	%o1, %l4, %l2
+	srlx	%o0, 32, %o0
+	mulx	%o0, %l1, %l3
+	mulx	%l1, %l4, %l1
+	srlx	%l1, 32, %l1
+	add	%l2, %l1, %l2
+	addcc	%l2, %l3, %l2
+	mulx	%o1, %o0, %o1
+	mov	0, %l1
+	movcs	%xcc, 1, %l1
+	sllx	%l1, 32, %l1
+	add	%o1, %l1, %o1
+	srlx	%l2, 32, %o0
+	add	%o1, %o0, %o0
+	stx	%o0, [%sp+2047+176+256]
+	wr	%o4, 0, %ccr
+	ret
+	 restore
+EPILOGUE()
+
+PROLOGUE(__gmpn_lzcnt)
+	save	%sp, -176, %sp
+	ldx	[%sp+2047+176+256], %o0
+	brz,a	%o0, 2f
+	 mov	64, %o1
+	brlz	%o0, 2f
+	 mov	0, %o1
+1:	sllx	%o0, 1, %o0
+	brgz	%o0, 1b
+	 add	%o1, 1, %o1
+	stx	%o1, [%sp+2047+176+256]
+2:	ret
+	 restore
+EPILOGUE()
diff --git a/third_party/gmp/mpn/sparc64/ultrasparct3/missing.m4 b/third_party/gmp/mpn/sparc64/ultrasparct3/missing.m4
new file mode 100644
index 0000000..e5d6d8e
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/ultrasparct3/missing.m4
@@ -0,0 +1,88 @@
+dnl  SPARC v9-2011 simulation support.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+dnl Usage addxccc(r1,r2,r3, t1)
+dnl  64-bit add with carry-in and carry-out
+dnl  FIXME: Register g2 must not be destination
+
+define(`addxccc',`dnl
+	add	%sp, -512, %sp
+	stx	%g2, [%sp+2047+256+16]
+	mov	0, %g2
+	movcs	%xcc, -1, %g2
+	addcc	%g2, 1, %g0
+	addccc	$1, $2, $3
+	ldx	[%sp+2047+256+16], %g2
+	sub	%sp, -512, %sp
+')
+
+
+dnl Usage addxc(r1,r2,r3, t1,t2)
+dnl  64-bit add with carry-in
+
+define(`addxc',`dnl
+	bcc	%xcc, 1f
+	 add	$1, $2, $3
+	add	$3, 1, $3
+1:
+')
+
+
+dnl Usage umulxhi(r1,r2,r3)
+dnl  64-bit multiply returning upper 64 bits
+dnl  Calls __gmpn_umulh using a non-standard calling convention
+
+define(`umulxhi',`dnl
+	add	%sp, -512, %sp
+	stx	$1, [%sp+2047+256]
+	stx	$2, [%sp+2047+256+8]
+	stx	%o7, [%sp+2047+256+16]
+	call	__gmpn_umulh
+	 nop
+	ldx	[%sp+2047+256+16], %o7
+	ldx	[%sp+2047+256], $3
+	sub	%sp, -512, %sp
+')
+dnl Usage lzcnt(r1,r2)
+dnl  Plain count leading zeros
+dnl  Calls __gmpn_lzcnt using a non-standard calling convention
+
+define(`lzcnt',`dnl
+	add	%sp, -512, %sp
+	stx	%o7, [%sp+2047+256+16]
+	call	__gmpn_lzcnt
+	 stx	$1, [%sp+2047+256]
+	ldx	[%sp+2047+256+16], %o7
+	ldx	[%sp+2047+256], $2
+	sub	%sp, -512, %sp
+')
diff --git a/third_party/gmp/mpn/sparc64/ultrasparct3/mod_1_4.asm b/third_party/gmp/mpn/sparc64/ultrasparct3/mod_1_4.asm
new file mode 100644
index 0000000..08facbd
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/ultrasparct3/mod_1_4.asm
@@ -0,0 +1,233 @@
+dnl  SPARC T3/T4/T5 mpn_mod_1s_4p.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                  cycles/limb
+C UltraSPARC T3:	30
+C UltraSPARC T4/T5:	 4
+
+C INPUT PARAMETERS
+define(`ap',  `%o0')
+define(`n',   `%o1')
+define(`d',   `%o2')
+define(`cps', `%o3')
+
+
+ASM_START()
+	REGISTER(%g2,#scratch)
+	REGISTER(%g3,#scratch)
+PROLOGUE(mpn_mod_1s_4p)
+	save	%sp, -176, %sp
+	ldx	[%i3+16], %o4
+	ldx	[%i3+24], %o3
+	ldx	[%i3+32], %o2
+	ldx	[%i3+40], %o1
+	ldx	[%i3+48], %o0
+
+	and	%i1, 3, %g3
+	sllx	%i1, 3, %g1
+	add	%i0, %g1, %i0
+	brz	%g3, L(b00)
+	 cmp	%g3, 2
+	bcs	%xcc, L(b01)
+	 nop
+	be	%xcc, L(b10)
+	 nop
+
+L(b11):	ldx	[%i0-16], %g2
+	mulx	%g2, %o4, %g5
+	umulxhi(%g2, %o4, %g3)
+	ldx	[%i0-24], %g4
+	addcc	%g5, %g4, %g5
+	addxc(	%g3, %g0, %g4)
+	ldx	[%i0-8], %g2
+	mulx	%g2, %o3, %g1
+	umulxhi(%g2, %o3, %g3)
+	addcc	%g1, %g5, %g1
+	addxc(	%g3, %g4, %g2)
+	ba,pt	%xcc, .L8
+	 add	%i0, -32, %i0
+
+L(b00):	ldx	[%i0-24], %g3
+	mulx	%g3, %o4, %g2
+	umulxhi(%g3, %o4, %g5)
+	ldx	[%i0-32], %g4
+	addcc	%g2, %g4, %g2
+	addxc(	%g5, %g0, %g3)
+	ldx	[%i0-16], %g4
+	mulx	%g4, %o3, %g5
+	umulxhi(%g4, %o3, %i5)
+	addcc	%g2, %g5, %g5
+	addxc(	%g3, %i5, %g4)
+	ldx	[%i0-8], %g2
+	mulx	%g2, %o2, %g1
+	umulxhi(%g2, %o2, %g3)
+	addcc	%g1, %g5, %g1
+	addxc(	%g3, %g4, %g2)
+	ba,pt	%xcc, .L8
+	 add	%i0, -40, %i0
+
+L(b01):	ldx	[%i0-8], %g1
+	mov	0, %g2
+	ba,pt	%xcc, .L8
+	 add	%i0, -16, %i0
+
+L(b10):	ldx	[%i0-8], %g2
+	ldx	[%i0-16], %g1
+	add	%i0, -24, %i0
+
+.L8:	add	%i1, -5, %g3
+	brlz,pn	%g3, L(end)
+	 nop
+
+L(top):	ldx	[%i0-16], %i4
+	mulx	%i4, %o4, %o5
+	umulxhi(%i4, %o4, %i1)
+	ldx	[%i0-24], %i5
+	addcc	%o5, %i5, %o5
+	addxc(	%i1, %g0, %i4)
+	ldx	[%i0-8], %i5
+	mulx	%i5, %o3, %o7
+	umulxhi(%i5, %o3, %i1)
+	addcc	%o5, %o7, %o7
+	addxc(	%i4, %i1, %i5)
+	ldx	[%i0+0], %g4
+	mulx	%g4, %o2, %i1
+	umulxhi(%g4, %o2, %i4)
+	addcc	%o7, %i1, %i1
+	addxc(	%i5, %i4, %g4)
+	mulx	%g1, %o1, %i5
+	umulxhi(%g1, %o1, %i4)
+	addcc	%i1, %i5, %i5
+	addxc(	%g4, %i4, %g5)
+	mulx	%g2, %o0, %g1
+	umulxhi(%g2, %o0, %g4)
+	addcc	%g1, %i5, %g1
+	addxc(	%g4, %g5, %g2)
+	add	%g3, -4, %g3
+	brgez,pt %g3, L(top)
+	 add	%i0, -32, %i0
+
+L(end):	mulx	%g2, %o4, %g5
+	umulxhi(%g2, %o4, %g3)
+	addcc	%g1, %g5, %g5
+	addxc(	%g3, %g0, %g2)
+	ldx	[%i3+8], %i0
+	ldx	[%i3], %g4
+	sub	%g0, %i0, %i5
+	srlx	%g5, %i5, %i5
+	sllx	%g2, %i0, %g2
+	or	%i5, %g2, %g1
+	mulx	%g1, %g4, %l7
+	umulxhi(%g1, %g4, %g3)
+	sllx	%g5, %i0, %g2
+	add	%g1, 1, %g1
+	addcc	%l7, %g2, %g5
+	addxc(	%g3, %g1, %g1)
+	mulx	%g1, %i2, %g1
+	sub	%g2, %g1, %g2
+	cmp	%g2, %g5
+	add	%i2, %g2, %g1
+	movlu	%xcc, %g2, %g1
+	subcc	%g1, %i2, %g2
+	movgeu	%xcc, %g2, %g1
+	return	%i7+8
+	 srlx	%g1, %o0, %o0
+EPILOGUE()
+
+PROLOGUE(mpn_mod_1s_4p_cps)
+	save	%sp, -176, %sp
+	lzcnt(	%i1, %i5)
+	sllx	%i1, %i5, %i1
+	call	mpn_invert_limb, 0
+	 mov	%i1, %o0
+	stx	%o0, [%i0]
+	sra	%i5, 0, %g1
+	stx	%g1, [%i0+8]
+	sub	%g0, %i5, %g2
+	srlx	%o0, %g2, %g2
+	mov	1, %g1
+	sllx	%g1, %i5, %g1
+	or	%g2, %g1, %g2
+	sub	%g0, %i1, %g1
+	mulx	%g2, %g1, %g2
+	srlx	%g2, %i5, %g1
+	stx	%g1, [%i0+16]
+
+	umulxhi(%o0, %g2, %g3)
+	add	%g2, %g3, %g3
+	xnor	%g0, %g3, %g3
+	mulx	%g3, %i1, %g3
+	mulx	%g2, %o0, %g2
+	cmp	%g2, %g3
+	add	%i1, %g3, %g1
+	movgeu	%xcc, %g3, %g1
+	srlx	%g1, %i5, %g2
+	stx	%g2, [%i0+24]
+
+	umulxhi(%o0, %g1, %g3)
+	add	%g1, %g3, %g3
+	xnor	%g0, %g3, %g3
+	mulx	%g3, %i1, %g3
+	mulx	%g1, %o0, %g1
+	cmp	%g1, %g3
+	add	%i1, %g3, %g2
+	movgeu	%xcc, %g3, %g2
+	srlx	%g2, %i5, %g1
+	stx	%g1, [%i0+32]
+
+	umulxhi(%o0, %g2, %g3)
+	add	%g2, %g3, %g3
+	xnor	%g0, %g3, %g3
+	mulx	%g3, %i1, %g3
+	mulx	%g2, %o0, %g2
+	cmp	%g2, %g3
+	add	%i1, %g3, %g1
+	movgeu	%xcc, %g3, %g1
+	srlx	%g1, %i5, %g2
+	stx	%g2, [%i0+40]
+
+	umulxhi(%o0, %g1, %g2)
+	add	%g1, %g2, %g2
+	xnor	%g0, %g2, %g2
+	mulx	%g2, %i1, %g2
+	mulx	%g1, %o0, %o0
+	cmp	%o0, %g2
+	add	%i1, %g2, %g3
+	movgeu	%xcc, %g2, %g3
+	srlx	%g3, %i5, %i5
+	stx	%i5, [%i0+48]
+
+	return	%i7+8
+	 nop
+EPILOGUE()
diff --git a/third_party/gmp/mpn/sparc64/ultrasparct3/mod_34lsub1.asm b/third_party/gmp/mpn/sparc64/ultrasparct3/mod_34lsub1.asm
new file mode 100644
index 0000000..8744280
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/ultrasparct3/mod_34lsub1.asm
@@ -0,0 +1,117 @@
+dnl  SPARC v9 mpn_mod_34lsub1 for T3/T4/T5.
+
+dnl  Copyright 2005, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		    cycles/limb
+C UltraSPARC T1:	 -
+C UltraSPARC T3:	 5
+C UltraSPARC T4:	 1.57
+
+C This is based on the powerpc64/mode64 code.
+
+C INPUT PARAMETERS
+define(`up', `%i0')
+define(`n',  `%i1')
+
+ASM_START()
+	REGISTER(%g2,#scratch)
+	REGISTER(%g3,#scratch)
+PROLOGUE(mpn_mod_34lsub1)
+	save	%sp, -176, %sp
+
+	mov	0, %g1
+	mov	0, %g3
+	mov	0, %g4
+	addcc	%g0, 0, %g5
+
+	add	n, -3, n
+	brlz	n, L(lt3)
+	 nop
+
+	add	n, -3, n
+	ldx	[up+0], %l5
+	ldx	[up+8], %l6
+	ldx	[up+16], %l7
+	brlz	n, L(end)
+	 add	up, 24, up
+
+	ALIGN(16)
+L(top):	addxccc(%g1, %l5, %g1)
+	ldx	[up+0], %l5
+	addxccc(%g3, %l6, %g3)
+	ldx	[up+8], %l6
+	addxccc(%g4, %l7, %g4)
+	ldx	[up+16], %l7
+	add	n, -3, n
+	brgez	n, L(top)
+	 add	up, 24, up
+
+L(end):	addxccc(	%g1, %l5, %g1)
+	addxccc(%g3, %l6, %g3)
+	addxccc(%g4, %l7, %g4)
+	addxc(	%g5, %g0, %g5)
+
+L(lt3):	cmp	n, -2
+	blt	L(2)
+	 nop
+
+	ldx	[up+0], %l5
+	mov	0, %l6
+	beq	L(1)
+	 addcc	%g1, %l5, %g1
+
+	ldx	[up+8], %l6
+L(1):	addxccc(%g3, %l6, %g3)
+	addxccc(%g4, %g0, %g4)
+	addxc(	%g5, %g0, %g5)
+
+L(2):	sllx	%g1, 16, %l0
+	srlx	%l0, 16, %l0		C %l0 = %g1 mod 2^48
+	srlx	%g1, 48, %l3		C %l3 = %g1 div 2^48
+	srl	%g3, 0, %g1
+	sllx	%g1, 16, %l4		C %l4 = (%g3 mod 2^32) << 16
+	srlx	%g3, 32, %l5		C %l5 = %g3 div 2^32
+	sethi	%hi(0xffff0000), %g1
+	andn	%g4, %g1, %g1
+	sllx	%g1, 32, %l6		C %l6 = (%g4 mod 2^16) << 32
+	srlx	%g4, 16, %l7		C %l7 = %g4 div 2^16
+
+	add	%l0, %l3, %l0
+	add	%l4, %l5, %l4
+	add	%l6, %l7, %l6
+
+	add	%l0, %l4, %l0
+	add	%l6, %g5, %l6
+
+	add	%l0, %l6, %i0
+	ret
+	 restore
+EPILOGUE()
diff --git a/third_party/gmp/mpn/sparc64/ultrasparct3/mode1o.asm b/third_party/gmp/mpn/sparc64/ultrasparct3/mode1o.asm
new file mode 100644
index 0000000..494e1d3
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/ultrasparct3/mode1o.asm
@@ -0,0 +1,82 @@
+dnl  SPARC T3/T4/T5 mpn_modexact_1c_odd.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C                  cycles/limb
+C UltraSPARC T3:	30
+C UltraSPARC T4/T5:	26
+
+C INPUT PARAMETERS
+define(`ap',  `%o0')
+define(`n',   `%o1')
+define(`d',   `%o2')
+define(`cy',  `%o3')
+
+define(`dinv',`%o5')
+define(`a0',  `%g1')
+
+ASM_START()
+	REGISTER(%g2,#scratch)
+	REGISTER(%g3,#scratch)
+PROLOGUE(mpn_modexact_1c_odd)
+	srlx	d, 1, %g1
+	and	%g1, 127, %g1
+
+	LEA64(binvert_limb_table, g2, g4)
+	ldub	[%g2+%g1], %g1
+	add	%g1, %g1, %g2
+	mulx	%g1, %g1, %g1
+	mulx	%g1, d, %g1
+	sub	%g2, %g1, %g2
+	add	%g2, %g2, %g1
+	mulx	%g2, %g2, %g2
+	mulx	%g2, d, %g2
+	sub	%g1, %g2, %g1
+	add	%g1, %g1, %o5
+	mulx	%g1, %g1, %g1
+	mulx	%g1, d, %g1
+	sub	%o5, %g1, dinv
+	add	n, -1, n
+
+L(top):	ldx	[ap], a0
+	add	ap, 8, ap
+	subcc	a0, cy, %g3
+	mulx	%g3, dinv, %g5
+	umulxhi(d, %g5, %g5)
+	addxc(	%g5, %g0, cy)
+	brnz,pt	n, L(top)
+	 add	n, -1, n
+
+	retl
+	 mov	cy, %o0
+EPILOGUE()
diff --git a/third_party/gmp/mpn/sparc64/ultrasparct3/mul_1.asm b/third_party/gmp/mpn/sparc64/ultrasparct3/mul_1.asm
new file mode 100644
index 0000000..af05d62
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/ultrasparct3/mul_1.asm
@@ -0,0 +1,174 @@
+dnl  SPARC v9 mpn_mul_1 for T3/T4/T5.
+
+dnl  Contributed to the GNU project by David Miller and Torbjörn Granlund.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		   cycles/limb
+C UltraSPARC T3:	23
+C UltraSPARC T4:	 3
+
+C INPUT PARAMETERS
+define(`rp', `%i0')
+define(`up', `%i1')
+define(`n',  `%i2')
+define(`v0', `%i3')
+
+ASM_START()
+	REGISTER(%g2,#scratch)
+	REGISTER(%g3,#scratch)
+PROLOGUE(mpn_mul_1)
+	save	%sp, -176, %sp
+
+	and	n, 3, %g5
+	add	n, -4, n
+	brz	%g5, L(b0)
+	 cmp	%g5, 2
+	bcs	%xcc, L(b1)
+	 nop
+	be	%xcc, L(b2)
+	 nop
+
+L(b3):	addcc	%g0, %g0, %i5
+	ldx	[up+0], %l0
+	ldx	[up+8], %l1
+	ldx	[up+16], %l2
+	mulx	%l0, v0, %o0
+	umulxhi(%l0, v0, %o1)
+	brgz	n, L(gt3)
+	 add	rp, -8, rp
+	mulx	%l1, v0, %o2
+	umulxhi(%l1, v0, %o3)
+	b	L(wd3)
+	 nop
+L(gt3):	ldx	[up+24], %l3
+	mulx	%l1, v0, %o2
+	umulxhi(%l1, v0, %o3)
+	add	up, 24, up
+	b	L(lo3)
+	 add	n, -3, n
+
+L(b2):	addcc	%g0, %g0, %o1
+	ldx	[up+0], %l1
+	ldx	[up+8], %l2
+	brgz	n, L(gt2)
+	 add	rp, -16, rp
+	mulx	%l1, v0, %o2
+	umulxhi(%l1, v0, %o3)
+	mulx	%l2, v0, %o4
+	umulxhi(%l2, v0, %o5)
+	b	L(wd2)
+	 nop
+L(gt2):	ldx	[up+16], %l3
+	mulx	%l1, v0, %o2
+	umulxhi(%l1, v0, %o3)
+	ldx	[up+24], %l0
+	mulx	%l2, v0, %o4
+	umulxhi(%l2, v0, %o5)
+	add	up, 16, up
+	b	L(lo2)
+	 add	n, -2, n
+
+L(b1):	addcc	%g0, %g0, %o3
+	ldx	[up+0], %l2
+	brgz	n, L(gt1)
+	nop
+	mulx	%l2, v0, %o4
+	stx	%o4, [rp+0]
+	umulxhi(%l2, v0, %i0)
+	ret
+	 restore
+L(gt1):	ldx	[up+8], %l3
+	ldx	[up+16], %l0
+	mulx	%l2, v0, %o4
+	umulxhi(%l2, v0, %o5)
+	ldx	[up+24], %l1
+	mulx	%l3, v0, %i4
+	umulxhi(%l3, v0, %i5)
+	add	rp, -24, rp
+	add	up, 8, up
+	b	L(lo1)
+	 add	n, -1, n
+
+L(b0):	addcc	%g0, %g0, %o5
+	ldx	[up+0], %l3
+	ldx	[up+8], %l0
+	ldx	[up+16], %l1
+	mulx	%l3, v0, %i4
+	umulxhi(%l3, v0, %i5)
+	ldx	[up+24], %l2
+	mulx	%l0, v0, %o0
+	umulxhi(%l0, v0, %o1)
+	b	L(lo0)
+	 nop
+
+	ALIGN(16)
+L(top):	ldx	[up+0], %l3	C 0
+	addxccc(%i4, %o5, %i4)	C 0
+	mulx	%l1, v0, %o2	C 1
+	stx	%i4, [rp+0]	C 1
+	umulxhi(%l1, v0, %o3)	C 2
+L(lo3):	ldx	[up+8], %l0	C 2
+	addxccc(%o0, %i5, %o0)	C 3
+	mulx	%l2, v0, %o4	C 3
+	stx	%o0, [rp+8]	C 4
+	umulxhi(%l2, v0, %o5)	C 4
+L(lo2):	ldx	[up+16], %l1	C 5
+	addxccc(%o2, %o1, %o2)	C 5
+	mulx	%l3, v0, %i4	C 6
+	stx	%o2, [rp+16]	C 6
+	umulxhi(%l3, v0, %i5)	C 7
+L(lo1):	ldx	[up+24], %l2	C 7
+	addxccc(%o4, %o3, %o4)	C 8
+	mulx	%l0, v0, %o0	C 8
+	stx	%o4, [rp+24]	C 9
+	umulxhi(%l0, v0, %o1)	C 9
+	add	rp, 32, rp	C 10
+L(lo0):	add	up, 32, up	C 10
+	brgz	n, L(top)	C 11
+	 add	n, -4, n	C 11
+
+L(end):	addxccc(%i4, %o5, %i4)
+	mulx	%l1, v0, %o2
+	stx	%i4, [rp+0]
+	umulxhi(%l1, v0, %o3)
+	addxccc(%o0, %i5, %o0)
+L(wd3):	mulx	%l2, v0, %o4
+	stx	%o0, [rp+8]
+	umulxhi(%l2, v0, %o5)
+	addxccc(%o2, %o1, %o2)
+L(wd2):	stx	%o2, [rp+16]
+	addxccc(%o4, %o3, %o4)
+	stx	%o4, [rp+24]
+	addxc(	%g0, %o5, %i0)
+	ret
+	 restore
+EPILOGUE()
diff --git a/third_party/gmp/mpn/sparc64/ultrasparct3/popcount.asm b/third_party/gmp/mpn/sparc64/ultrasparct3/popcount.asm
new file mode 100644
index 0000000..de80f3c
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/ultrasparct3/popcount.asm
@@ -0,0 +1,70 @@
+dnl  SPARC v9 mpn_popcount for T3/T4.
+
+dnl  Contributed to the GNU project by David Miller.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		   cycles/limb
+C UltraSPARC T3:	15
+C UltraSPARC T4:	 2.5
+
+C INPUT PARAMETERS
+define(`up',   `%o0')
+define(`n',    `%o1')
+define(`pcnt', `%o5')
+
+ASM_START()
+	REGISTER(%g2,#scratch)
+	REGISTER(%g3,#scratch)
+PROLOGUE(mpn_popcount)
+	subcc	n, 1, n
+	be	L(final_one)
+	 clr	pcnt
+L(top):
+	ldx	[up + 0], %g1
+	sub	n, 2, n
+	ldx	[up + 8], %o4
+	add	up, 16, up
+	popc	%g1, %g2
+	popc	%o4, %g3
+	add	pcnt, %g2, pcnt
+	brgz	n, L(top)
+	 add	pcnt, %g3, pcnt
+	brlz,pt	n, L(done)
+	 nop
+L(final_one):
+	ldx	[up + 0], %g1
+	popc	%g1, %g2
+	add	pcnt, %g2, pcnt
+L(done):
+	retl
+	 mov	pcnt, %o0
+EPILOGUE()
diff --git a/third_party/gmp/mpn/sparc64/ultrasparct3/sqr_diag_addlsh1.asm b/third_party/gmp/mpn/sparc64/ultrasparct3/sqr_diag_addlsh1.asm
new file mode 100644
index 0000000..d46499f
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/ultrasparct3/sqr_diag_addlsh1.asm
@@ -0,0 +1,93 @@
+dnl  SPARC v9 mpn_sqr_diag_addlsh1 for T3/T4/T5.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		   cycles/limb
+C UltraSPARC T3:	?
+C UltraSPARC T4:	>= 4.5
+
+
+define(`rp', `%i0')
+define(`tp', `%i1')
+define(`up', `%i2')
+define(`n',  `%i3')
+
+ASM_START()
+	REGISTER(%g2,#scratch)
+	REGISTER(%g3,#scratch)
+PROLOGUE(mpn_sqr_diag_addlsh1)
+	save	%sp, -176, %sp
+
+	ldx	[up+0], %g1
+	mulx	%g1, %g1, %o0
+	umulxhi(%g1, %g1, %g2)
+	stx	%o0, [rp+0]
+
+	ldx	[up+8], %g1
+	ldx	[tp+0], %g4
+	ldx	[tp+8], %g5
+	mulx	%g1, %g1, %o0
+	orcc	%g0, %g0, %o5
+	b	L(dm)
+	 add	n, -2, n
+
+	ALIGN(16)
+L(top):	ldx	[up+8], %g1
+	addcc	%g4, %o2, %o2
+	addxccc(%g5, %o0, %g3)
+	ldx	[tp+16], %g4
+	ldx	[tp+24], %g5
+	mulx	%g1, %g1, %o0
+	stx	%o2, [rp+8]
+	stx	%g3, [rp+16]
+	add	rp, 16, rp
+	add	tp, 16, tp
+L(dm):	add	%g2, %o5, %o2
+	umulxhi(%g1, %g1, %g2)
+	addxccc(%g4, %g4, %g4)
+	addxccc(%g5, %g5, %g5)
+	add	up, 8, up
+	addxc(	%g0, %g0, %o5)
+	brnz	n, L(top)
+	 add	n, -1, n
+
+	addcc	%o2, %g4, %g4
+	addxccc(%o0, %g5, %g5)
+	stx	%g4, [rp+8]
+	stx	%g5, [rp+16]
+	addxc(	%o5, %g2, %g2)
+	stx	%g2, [rp+24]
+
+	ret
+	 restore
+EPILOGUE()
diff --git a/third_party/gmp/mpn/sparc64/ultrasparct3/sub_n.asm b/third_party/gmp/mpn/sparc64/ultrasparct3/sub_n.asm
new file mode 100644
index 0000000..0e4bc93
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/ultrasparct3/sub_n.asm
@@ -0,0 +1,144 @@
+dnl  SPARC v9 mpn_sub_n for T3/T4.
+
+dnl  Contributed to the GNU project by David Miller.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		   cycles/limb
+C UltraSPARC T3:	 8
+C UltraSPARC T4:	 3
+
+C INPUT PARAMETERS
+define(`rp', `%i0')
+define(`up', `%i1')
+define(`vp', `%i2')
+define(`n',  `%i3')
+define(`cy', `%i4')
+
+define(`u0_off', `%l0')
+define(`u1_off', `%l1')
+define(`v0_off', `%l2')
+define(`v1_off', `%l3')
+define(`r0_off', `%l4')
+define(`r1_off', `%l5')
+define(`loop_n', `%l6')
+define(`tmp', `%l7')
+
+ASM_START()
+	REGISTER(%g2,#scratch)
+	REGISTER(%g3,#scratch)
+PROLOGUE(mpn_sub_nc)
+	save	%sp, -176, %sp
+	ba,pt	%xcc, L(ent)
+	 xor	cy, 1, cy
+EPILOGUE()
+PROLOGUE(mpn_sub_n)
+	save	%sp, -176, %sp
+	mov	1, cy
+L(ent):
+	subcc	n, 1, n
+	be	L(final_one)
+	 cmp	%g0, cy
+
+	ldx	[up + 0], %o4
+	sllx	n, 3, tmp
+
+	ldx	[vp + 0], %o5
+	add	up, tmp, u0_off
+
+	ldx	[up + 8], %g5
+	add	vp, tmp, v0_off
+
+	ldx	[vp + 8], %g1
+	add	rp, tmp, r0_off
+
+	neg	tmp, loop_n
+	add	u0_off, 8, u1_off
+
+	add	v0_off, 8, v1_off
+	sub	loop_n, -(2 * 8), loop_n
+
+	sub	r0_off, 16, r0_off
+	brgez,pn loop_n, L(loop_tail)
+	 sub	r0_off, 8, r1_off
+
+	b,a	L(top)
+	ALIGN(16)
+L(top):
+	xnor	%o5, 0, tmp
+	ldx	[loop_n + v0_off], %o5
+
+	addxccc(%o4, tmp, %g3)
+	ldx	[loop_n + u0_off], %o4
+
+	xnor	%g1, 0, %g1
+	stx	%g3, [loop_n + r0_off]
+
+	addxccc(%g5, %g1, tmp)
+	ldx	[loop_n + v1_off], %g1
+
+	ldx	[loop_n + u1_off], %g5
+	sub	loop_n, -(2 * 8), loop_n
+
+	brlz	loop_n, L(top)
+	 stx	tmp, [loop_n + r1_off]
+
+L(loop_tail):
+	xnor	%o5, 0, tmp
+	xnor	%g1, 0, %g1
+
+	addxccc(%o4, tmp, %g3)
+	add	loop_n, u0_off, up
+
+	addxccc(%g5, %g1, %g5)
+	add	loop_n, r0_off, rp
+
+	stx	%g3, [rp + 0]
+	add	loop_n, v0_off, vp
+
+	brgz,pt	loop_n, L(done)
+	 stx	%g5, [rp + 8]
+
+	add	rp, (2 * 8), rp
+
+L(final_one):
+	ldx	[up+0], %o4
+	ldx	[vp+0], %o5
+	xnor	%o5, %g0, %o5
+	addxccc(%o4, %o5, %g3)
+	stx	%g3, [rp+0]
+
+L(done):
+	clr	%i0
+	movcc	%xcc, 1, %i0
+	ret
+	 restore
+EPILOGUE()
diff --git a/third_party/gmp/mpn/sparc64/ultrasparct3/submul_1.asm b/third_party/gmp/mpn/sparc64/ultrasparct3/submul_1.asm
new file mode 100644
index 0000000..5635d1b
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/ultrasparct3/submul_1.asm
@@ -0,0 +1,170 @@
+dnl  SPARC v9 mpn_submul_1 for T3/T4/T5.
+
+dnl  Contributed to the GNU project by David Miller and Torbjörn Granlund.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		   cycles/limb
+C UltraSPARC T3:	26
+C UltraSPARC T4:	 4.5
+
+C INPUT PARAMETERS
+define(`rp', `%i0')
+define(`up', `%i1')
+define(`n',  `%i2')
+define(`v0', `%i3')
+
+ASM_START()
+	REGISTER(%g2,#scratch)
+	REGISTER(%g3,#scratch)
+PROLOGUE(mpn_submul_1)
+	save	%sp, -176, %sp
+	ldx	[up+0], %g1
+
+	and	n, 3, %g5
+	add	n, -4, n
+	brz	%g5, L(b00)
+	 cmp	%g5, 2
+	bcs	%xcc, L(b01)
+	 nop
+	bne	%xcc, L(b11)
+	 ldx	[up+8], %g4
+
+L(b10):	add	up, 16, up
+	addcc	%g0, 0, %g3
+	mulx	%g1, v0, %l4
+	umulxhi(%g1, v0, %l5)
+	ldx	[rp+0], %o2
+	mulx	%g4, v0, %l6
+	umulxhi(%g4, v0, %l7)
+	brlz	n, L(wd2)
+	 nop
+L(gt2):	ldx	[up+0], %o0
+	b	L(lo2)
+	 nop
+
+L(b00):	add	rp, -16, rp
+	addcc	%g0, 0, %g3
+	ldx	[up+8], %o1
+	mulx	%g1, v0, %l0
+	umulxhi(%g1, v0, %l1)
+	ldx	[up+16], %o0
+	ldx	[rp+16], %o2
+	mulx	%o1, v0, %l2
+	umulxhi(%o1, v0, %l3)
+	b	     L(lo0)
+	 nop
+
+L(b01):	add	up, 8, up
+	add	rp, -8, rp
+	addcc	%g0, 0, %g3
+	ldx	[rp+8], %o3
+	mulx	%g1, v0, %l6
+	umulxhi(%g1, v0, %l7)
+	brlz	n, L(wd1)
+	 nop
+	ldx	[up+0], %o0
+	ldx	[up+8], %o1
+	mulx	%o0, v0, %l0
+	umulxhi(%o0, v0, %l1)
+	b	L(lo1)
+	 nop
+
+L(b11):	add	up, 24, up
+	add	rp, 8, rp
+	addcc	%g0, 0, %g3
+	mulx	%g1, v0, %l2
+	umulxhi(%g1, v0, %l3)
+	ldx	[up-8], %o1
+	ldx	[rp-8], %o3
+	mulx	%g4, v0, %l4
+	umulxhi(%g4, v0, %l5)
+	brlz	n, L(end)
+	 nop
+
+	ALIGN(16)
+L(top):	ldx	[up+0], %o0
+	addxccc(%g3, %l2, %g1)
+	ldx	[rp+0], %o2
+	addxc(	%g0, %l3, %g3)
+	mulx	%o1, v0, %l6
+	subcc	%o3, %g1, %g4
+	umulxhi(%o1, v0, %l7)
+	stx	%g4, [rp-8]
+L(lo2):	ldx	[up+8], %o1
+	addxccc(%g3, %l4, %g1)
+	ldx	[rp+8], %o3
+	addxc(	%g0, %l5, %g3)
+	mulx	%o0, v0, %l0
+	subcc	%o2, %g1, %g4
+	umulxhi(%o0, v0, %l1)
+	stx	%g4, [rp+0]
+L(lo1):	ldx	[up+16], %o0
+	addxccc(%g3, %l6, %g1)
+	ldx	[rp+16], %o2
+	addxc(	%g0, %l7, %g3)
+	mulx	%o1, v0, %l2
+	subcc	%o3, %g1, %g4
+	umulxhi(%o1, v0, %l3)
+	stx	%g4, [rp+8]
+L(lo0):	ldx	[up+24], %o1
+	addxccc(%g3, %l0, %g1)
+	ldx	[rp+24], %o3
+	addxc(	%g0, %l1, %g3)
+	mulx	%o0, v0, %l4
+	subcc	%o2, %g1, %g4
+	umulxhi(%o0, v0, %l5)
+	stx	%g4, [rp+16]
+	add	n, -4, n
+	add	up, 32, up
+	brgez	n, L(top)
+	 add	rp, 32, rp
+
+L(end):	addxccc(%g3, %l2, %g1)
+	ldx	[rp+0], %o2
+	addxc(	%g0, %l3, %g3)
+	mulx	%o1, v0, %l6
+	subcc	%o3, %g1, %g4
+	umulxhi(%o1, v0, %l7)
+	stx	%g4, [rp-8]
+L(wd2):	addxccc(%g3, %l4, %g1)
+	ldx	[rp+8], %o3
+	addxc(	%g0, %l5, %g3)
+	subcc	%o2, %g1, %g4
+	stx	%g4, [rp+0]
+L(wd1):	addxccc(%g3, %l6, %g1)
+	addxc(	%g0, %l7, %g3)
+	subcc	%o3, %g1, %g4
+	stx	%g4, [rp+8]
+	addxc(	%g0, %g3, %i0)
+	ret
+	 restore
+EPILOGUE()
diff --git a/third_party/gmp/mpn/sparc64/ultrasparct45/gmp-mparam.h b/third_party/gmp/mpn/sparc64/ultrasparct45/gmp-mparam.h
new file mode 100644
index 0000000..2fecdba
--- /dev/null
+++ b/third_party/gmp/mpn/sparc64/ultrasparct45/gmp-mparam.h
@@ -0,0 +1,173 @@
+/* Sparc64 T4-T5 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+/* 3600 MHz ultrasparct5 running GNU/Linux */
+/* FFT tuning limit = 0.5 M */
+/* Generated by tuneup.c, 2019-10-01, gcc 7.4 */
+
+#define DIVREM_1_NORM_THRESHOLD              3
+#define DIVREM_1_UNNORM_THRESHOLD            3
+#define MOD_1_1P_METHOD                      2  /* 0.34% faster than 1 */
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               3
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          6
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          6
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD         8
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD         0  /* never mpn_mod_1s_2p */
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     13
+#define USE_PREINV_DIVREM_1                  1
+#define DIV_QR_1N_PI1_METHOD                 2  /* 27.84% faster than 1 */
+#define DIV_QR_1_NORM_THRESHOLD              3
+#define DIV_QR_1_UNNORM_THRESHOLD            2
+#define DIV_QR_2_PI2_THRESHOLD               5
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           19
+
+#define DIV_1_VS_MUL_1_PERCENT             654
+
+#define MUL_TOOM22_THRESHOLD                40
+#define MUL_TOOM33_THRESHOLD               129
+#define MUL_TOOM44_THRESHOLD               372
+#define MUL_TOOM6H_THRESHOLD               494
+#define MUL_TOOM8H_THRESHOLD               656
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD     126
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     247
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     225
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     219
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     188
+
+#define SQR_BASECASE_THRESHOLD              20
+#define SQR_TOOM2_THRESHOLD                 59
+#define SQR_TOOM3_THRESHOLD                107
+#define SQR_TOOM4_THRESHOLD                298
+#define SQR_TOOM6_THRESHOLD                399
+#define SQR_TOOM8_THRESHOLD                562
+
+#define MULMID_TOOM42_THRESHOLD             48
+
+#define MULMOD_BNM1_THRESHOLD               25
+#define SQRMOD_BNM1_THRESHOLD               23
+
+#define MUL_FFT_MODF_THRESHOLD             555  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    555, 5}, {     29, 6}, {     31, 7}, {     31, 8}, \
+    {     17, 7}, {     36, 8}, {     19, 7}, {     39, 8}, \
+    {     21, 7}, {     43, 8}, {     29, 9}, {     15, 8}, \
+    {     31, 7}, {     63, 8}, {     35, 9}, {     19, 8}, \
+    {     43, 9}, {     23, 8}, {     51, 9}, {     27, 8}, \
+    {     57,10}, {     15, 8}, {     61, 9}, {     31, 8}, \
+    {     67, 9}, {     35, 8}, {     71, 9}, {     39, 8}, \
+    {     81, 9}, {     43,10}, {     23, 9}, {     59,11}, \
+    {     15,10}, {     31, 9}, {     71,10}, {     39, 9}, \
+    {     87,10}, {     47, 9}, {     99,10}, {     55, 9}, \
+    {    115,11}, {     31,10}, {     63, 9}, {    131,10}, \
+    {     87,11}, {     47,10}, {    111, 9}, {    223,12}, \
+    {     31,11}, {     63,10}, {    135,11}, {     79,10}, \
+    {    159,11}, {     95,10}, {    191,11}, {    111,12}, \
+    {     63,11}, {    143,10}, {    287,11}, {    159,12}, \
+    {     95,11}, {    191,10}, {    383, 9}, {    767,13}, \
+    {   8192,14}, {  16384,15}, {  32768,16}, {  65536,17}, \
+    { 131072,18}, { 262144,19}, { 524288,20}, {1048576,21}, \
+    {2097152,22}, {4194304,23}, {8388608,24} }
+#define MUL_FFT_TABLE3_SIZE 75
+#define MUL_FFT_THRESHOLD                 5760
+
+#define SQR_FFT_MODF_THRESHOLD             372  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    372, 5}, {     23, 6}, {     12, 5}, {     25, 6}, \
+    {     25, 7}, {     13, 6}, {     27, 7}, {     25, 8}, \
+    {     13, 7}, {     28, 8}, {     15, 7}, {     31, 8}, \
+    {     27, 9}, {     15, 8}, {     35, 9}, {     19, 8}, \
+    {     41, 9}, {     23, 8}, {     47, 9}, {     27,10}, \
+    {     15, 9}, {     39,10}, {     23, 9}, {     51,11}, \
+    {     15,10}, {     31, 9}, {     67,10}, {     39, 9}, \
+    {     79,10}, {     47, 9}, {     95,10}, {     55,11}, \
+    {     31,10}, {     79,11}, {     47,10}, {     95,12}, \
+    {     31,11}, {     63,10}, {    135,11}, {     79,10}, \
+    {    159, 9}, {    319,11}, {     95,10}, {    191, 9}, \
+    {    383,11}, {    111,12}, {     63,11}, {    127,10}, \
+    {    255, 9}, {    511,10}, {    271,11}, {    143,10}, \
+    {    287, 9}, {    575,10}, {    303, 9}, {    607,11}, \
+    {    159,10}, {    319, 9}, {    639,12}, {     95,11}, \
+    {    191,10}, {    383, 9}, {    767,11}, {    207,13}, \
+    {   8192,14}, {  16384,15}, {  32768,16}, {  65536,17}, \
+    { 131072,18}, { 262144,19}, { 524288,20}, {1048576,21}, \
+    {2097152,22}, {4194304,23}, {8388608,24} }
+#define SQR_FFT_TABLE3_SIZE 75
+#define SQR_FFT_THRESHOLD                 3776
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  35
+#define MULLO_MUL_N_THRESHOLD            11278
+#define SQRLO_BASECASE_THRESHOLD             0  /* always */
+#define SQRLO_DC_THRESHOLD                 168
+#define SQRLO_SQR_THRESHOLD               7511
+
+#define DC_DIV_QR_THRESHOLD                 36
+#define DC_DIVAPPR_Q_THRESHOLD             103
+#define DC_BDIV_QR_THRESHOLD                28
+#define DC_BDIV_Q_THRESHOLD                 88
+
+#define INV_MULMOD_BNM1_THRESHOLD           78
+#define INV_NEWTON_THRESHOLD               181
+#define INV_APPR_THRESHOLD                 118
+
+#define BINV_NEWTON_THRESHOLD              296
+#define REDC_1_TO_REDC_2_THRESHOLD           4
+#define REDC_2_TO_REDC_N_THRESHOLD          79
+
+#define MU_DIV_QR_THRESHOLD               1970
+#define MU_DIVAPPR_Q_THRESHOLD            1970
+#define MUPI_DIV_QR_THRESHOLD               82
+#define MU_BDIV_QR_THRESHOLD              1528
+#define MU_BDIV_Q_THRESHOLD               1970
+
+#define POWM_SEC_TABLE  1,58,102,1509
+
+#define GET_STR_DC_THRESHOLD                15
+#define GET_STR_PRECOMPUTE_THRESHOLD        29
+#define SET_STR_DC_THRESHOLD               686
+#define SET_STR_PRECOMPUTE_THRESHOLD      2717
+
+#define FAC_DSC_THRESHOLD                  336
+#define FAC_ODD_THRESHOLD                   24
+
+#define MATRIX22_STRASSEN_THRESHOLD         32
+#define HGCD2_DIV1_METHOD                    1  /* 0.66% faster than 3 */
+#define HGCD_THRESHOLD                      57
+#define HGCD_APPR_THRESHOLD                 50
+#define HGCD_REDUCE_THRESHOLD             3389
+#define GCD_DC_THRESHOLD                   386
+#define GCDEXT_DC_THRESHOLD                288
+#define JACOBI_BASE_METHOD                   4  /* 2.50% faster than 3 */
diff --git a/third_party/gmp/mpn/thumb/add_n.asm b/third_party/gmp/mpn/thumb/add_n.asm
new file mode 100644
index 0000000..08ed60b
--- /dev/null
+++ b/third_party/gmp/mpn/thumb/add_n.asm
@@ -0,0 +1,63 @@
+dnl  ARM/Thumb mpn_add_n.
+
+dnl  Copyright 1997, 2000, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+define(`rp',	r0)
+define(`up',	r1)
+define(`vp',	r2)
+define(`n',	r3)
+
+ASM_START()
+	.thumb
+PROLOGUE(mpn_add_nc)
+	push	{r4, r5, r6}
+	ldr	r6, [sp, #12]		C init carry save register
+	sub	r6, #1
+	b	L(top)
+EPILOGUE()
+PROLOGUE(mpn_add_n)
+	push	{r4, r5, r6}
+	neg	r6, n			C init carry save register
+
+L(top):	ldmia	up!, {r4}		C load next limb from S1
+	cmp	n, r6			C tricky carry restore
+	ldmia	vp!, {r5}		C load next limb from S2
+	adc	r4, r5
+	stmia	rp!, {r4}		C store result limb to RES
+	sbc	r6, r6			C save negated carry
+	sub	n, #1
+	bne	L(top)
+
+	add	r0, r6, #1
+	pop	{r4, r5, r6}
+	bx	lr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/thumb/sub_n.asm b/third_party/gmp/mpn/thumb/sub_n.asm
new file mode 100644
index 0000000..a385720
--- /dev/null
+++ b/third_party/gmp/mpn/thumb/sub_n.asm
@@ -0,0 +1,63 @@
+dnl  ARM/Thumb mpn_sub_n.
+
+dnl  Copyright 1997, 2000, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C INPUT PARAMETERS
+define(`rp',	r0)
+define(`up',	r1)
+define(`vp',	r2)
+define(`n',	r3)
+
+ASM_START()
+	.thumb
+PROLOGUE(mpn_sub_nc)
+	push	{r4, r5, r6}
+	ldr	r6, [sp, #12]		C init carry save register
+	neg	r6, r6
+	b	L(top)
+EPILOGUE()
+PROLOGUE(mpn_sub_n)
+	push	{r4, r5, r6}
+	mov	r6, n			C init carry save register
+
+L(top):	ldmia	up!, {r4}		C load next limb from S1
+	cmp	n, r6			C tricky carry restore
+	ldmia	vp!, {r5}		C load next limb from S2
+	sbc	r4, r5
+	stmia	rp!, {r4}		C store result limb to RES
+	sbc	r6, r6			C save negated carry
+	sub	n, #1
+	bne	L(top)
+
+	neg	r0, r6
+	pop	{r4, r5, r6}
+	bx	lr
+EPILOGUE()
diff --git a/third_party/gmp/mpn/vax/add_n.asm b/third_party/gmp/mpn/vax/add_n.asm
new file mode 100644
index 0000000..0a0bf78
--- /dev/null
+++ b/third_party/gmp/mpn/vax/add_n.asm
@@ -0,0 +1,64 @@
+dnl  VAX mpn_add_n -- Add two limb vectors of the same length > 0 and store sum
+dnl  in a third limb vector.
+
+dnl  Copyright 1999, 2000, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ASM_START()
+PROLOGUE(mpn_add_n)
+	.word	0x0
+	movl	16(ap), r0
+	movl	12(ap), r1
+	movl	8(ap), r2
+	movl	4(ap), r3
+	mnegl	r0, r5
+	addl2	$3, r0
+	ashl	$-2, r0, r0	C unroll loop count
+	bicl2	$-4, r5		C mask out low 2 bits
+	movaq	(r5)[r5], r5	C 9x
+	jmp	L(top)[r5]
+
+L(top):	movl	(r2)+, r4
+	adwc	(r1)+, r4
+	movl	r4, (r3)+
+	movl	(r2)+, r4
+	adwc	(r1)+, r4
+	movl	r4, (r3)+
+	movl	(r2)+, r4
+	adwc	(r1)+, r4
+	movl	r4, (r3)+
+	movl	(r2)+, r4
+	adwc	(r1)+, r4
+	movl	r4, (r3)+
+	sobgtr	r0, L(top)
+
+	adwc	r0, r0
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/vax/addmul_1.asm b/third_party/gmp/mpn/vax/addmul_1.asm
new file mode 100644
index 0000000..8a6f636
--- /dev/null
+++ b/third_party/gmp/mpn/vax/addmul_1.asm
@@ -0,0 +1,124 @@
+dnl  VAX mpn_addmul_1 -- Multiply a limb vector with a limb and add the result
+dnl  to a second limb vector.
+
+dnl  Copyright 1992, 1994, 1996, 2000, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ASM_START()
+PROLOGUE(mpn_addmul_1)
+	.word	0xfc0
+	movl	12(ap), r4
+	movl	8(ap), r8
+	movl	4(ap), r9
+	clrl	r3
+	incl	r4
+	ashl	$-1, r4, r7
+	clrl	r11
+	movl	16(ap), r6
+	jlss	L(v0_big)
+	jlbc	r4, L(1)
+
+C Loop for v0 < 0x80000000
+L(tp1):	movl	(r8)+, r1
+	jlss	L(1n0)
+	emul	r1, r6, $0, r2
+	addl2	r11, r2
+	adwc	$0, r3
+	addl2	r2, (r9)+
+	adwc	$0, r3
+L(1):	movl	(r8)+, r1
+	jlss	L(1n1)
+L(1p1):	emul	r1, r6, $0, r10
+	addl2	r3, r10
+	adwc	$0, r11
+	addl2	r10, (r9)+
+	adwc	$0, r11
+
+	sobgtr	r7, L(tp1)
+	movl	r11, r0
+	ret
+
+L(1n0):	emul	r1, r6, $0, r2
+	addl2	r11, r2
+	adwc	r6, r3
+	addl2	r2, (r9)+
+	adwc	$0, r3
+	movl	(r8)+, r1
+	jgeq	L(1p1)
+L(1n1):	emul	r1, r6, $0, r10
+	addl2	r3, r10
+	adwc	r6, r11
+	addl2	r10, (r9)+
+	adwc	$0, r11
+
+	sobgtr	r7, L(tp1)
+	movl	r11, r0
+	ret
+
+L(v0_big):
+	jlbc	r4, L(2)
+
+C Loop for v0 >= 0x80000000
+L(tp2):	movl	(r8)+, r1
+	jlss	L(2n0)
+	emul	r1, r6, $0, r2
+	addl2	r11, r2
+	adwc	r1, r3
+	addl2	r2, (r9)+
+	adwc	$0, r3
+L(2):	movl	(r8)+, r1
+	jlss	L(2n1)
+L(2p1):	emul	r1, r6, $0, r10
+	addl2	r3, r10
+	adwc	r1, r11
+	addl2	r10, (r9)+
+	adwc	$0, r11
+
+	sobgtr	r7, L(tp2)
+	movl	r11, r0
+	ret
+
+L(2n0):	emul	r1, r6, $0, r2
+	addl2	r11, r2
+	adwc	r6, r3
+	addl2	r2, (r9)+
+	adwc	r1, r3
+	movl	(r8)+, r1
+	jgeq	L(2p1)
+L(2n1):	emul	r1, r6, $0, r10
+	addl2	r3, r10
+	adwc	r6, r11
+	addl2	r10, (r9)+
+	adwc	r1, r11
+
+	sobgtr	r7, L(tp2)
+	movl	r11, r0
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/vax/elf.m4 b/third_party/gmp/mpn/vax/elf.m4
new file mode 100644
index 0000000..e04f0ba
--- /dev/null
+++ b/third_party/gmp/mpn/vax/elf.m4
@@ -0,0 +1,54 @@
+divert(-1)
+
+dnl  m4 macros for VAX assembler.
+
+dnl  Copyright 2001, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+defreg(r0,`%r``''0')
+defreg(r1,`%r``''1')
+defreg(r2,`%r``''2')
+defreg(r3,`%r``''3')
+defreg(r4,`%r``''4')
+defreg(r5,`%r``''5')
+defreg(r6,`%r``''6')
+defreg(r7,`%r``''7')
+defreg(r8,`%r``''8')
+defreg(r9,`%r``''9')
+defreg(r10,`%r``''10')
+defreg(r11,`%r``''11')
+defreg(r12,`%r``''12')
+defreg(r13,`%r``''13')
+defreg(r14,`%r``''14')
+defreg(r15,`%r``''15')
+defreg(ap,`%a``''p')
+
+define(`foo', blablabla)
+
+divert
diff --git a/third_party/gmp/mpn/vax/gmp-mparam.h b/third_party/gmp/mpn/vax/gmp-mparam.h
new file mode 100644
index 0000000..9f20b9b
--- /dev/null
+++ b/third_party/gmp/mpn/vax/gmp-mparam.h
@@ -0,0 +1,60 @@
+/* VAX gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+/* These numbers were measured manually using the tune/speed program.
+   The standard tune/tuneup takes too long.  (VAX 8800) */
+
+#define MUL_TOOM22_THRESHOLD             14
+#define MUL_TOOM33_THRESHOLD            110
+
+#define SQR_BASECASE_THRESHOLD            6
+#define SQR_TOOM2_THRESHOLD              42
+#define SQR_TOOM3_THRESHOLD             250
+
+/* #define DIV_SB_PREINV_THRESHOLD         */
+/* #define DIV_DC_THRESHOLD                */
+/* #define POWM_THRESHOLD                  */
+
+/* #define GCD_ACCEL_THRESHOLD             */
+/* #define JACOBI_BASE_METHOD              */
+
+/* #define DIVREM_1_NORM_THRESHOLD         */
+/* #define DIVREM_1_UNNORM_THRESHOLD       */
+/* #define MOD_1_NORM_THRESHOLD            */
+/* #define MOD_1_UNNORM_THRESHOLD          */
+/* #define USE_PREINV_DIVREM_1             */
+/* #define USE_PREINV_MOD_1                */
+/* #define DIVREM_2_THRESHOLD              */
+/* #define DIVEXACT_1_THRESHOLD            */
+/* #define MODEXACT_1_ODD_THRESHOLD        */
+
+/* #define GET_STR_DC_THRESHOLD            */
+/* #define GET_STR_PRECOMPUTE_THRESHOLD    */
+#define SET_STR_THRESHOLD              3400
diff --git a/third_party/gmp/mpn/vax/lshift.asm b/third_party/gmp/mpn/vax/lshift.asm
new file mode 100644
index 0000000..941e999
--- /dev/null
+++ b/third_party/gmp/mpn/vax/lshift.asm
@@ -0,0 +1,59 @@
+dnl  VAX mpn_lshift -- left shift.
+
+dnl  Copyright 1999-2001, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ASM_START()
+PROLOGUE(mpn_lshift)
+	.word	0x1c0
+	movl	4(ap), r7
+	movl	8(ap), r6
+	movl	12(ap), r1
+	movl	16(ap), r8
+
+	moval	(r6)[r1], r6
+	moval	(r7)[r1], r7
+	clrl	r3
+	movl	-(r6), r2
+	ashq	r8, r2, r4
+	movl	r5, r0
+	movl	r2, r3
+	decl	r1
+	jeql	L(end)
+
+L(top):	movl	-(r6), r2
+	ashq	r8, r2, r4
+	movl	r5, -(r7)
+	movl	r2, r3
+	sobgtr	r1, L(top)
+
+L(end):	movl	r4, -4(r7)
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/vax/mul_1.asm b/third_party/gmp/mpn/vax/mul_1.asm
new file mode 100644
index 0000000..8e4dcd2
--- /dev/null
+++ b/third_party/gmp/mpn/vax/mul_1.asm
@@ -0,0 +1,118 @@
+dnl  VAX mpn_mul_1 -- Multiply a limb vector with a limb and store the result
+dnl  in a second limb vector.
+
+dnl  Copyright 1992, 1994, 1996, 2000, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ASM_START()
+PROLOGUE(mpn_mul_1)
+	.word	0xfc0
+	movl	12(ap), r4
+	movl	8(ap), r8
+	movl	4(ap), r9
+	clrl	r3
+	incl	r4
+	ashl	$-1, r4, r7
+	clrl	r11
+	movl	16(ap), r6
+	jlss	L(v0_big)
+	jlbc	r4, L(1)
+
+C Loop for v0 < 0x80000000
+L(tp1):	movl	(r8)+, r1
+	jlss	L(1n0)
+	emul	r1, r6, $0, r2
+	addl2	r11, r2
+	adwc	$0, r3
+	movl	r2, (r9)+
+L(1):	movl	(r8)+, r1
+	jlss	L(1n1)
+L(1p1):	emul	r1, r6, $0, r10
+	addl2	r3, r10
+	adwc	$0, r11
+	movl	r10, (r9)+
+
+	sobgtr	r7, L(tp1)
+	movl	r11, r0
+	ret
+
+L(1n0):	emul	r1, r6, $0, r2
+	addl2	r11, r2
+	adwc	r6, r3
+	movl	r2, (r9)+
+	movl	(r8)+, r1
+	jgeq	L(1p1)
+L(1n1):	emul	r1, r6, $0, r10
+	addl2	r3, r10
+	adwc	r6, r11
+	movl	r10, (r9)+
+
+	sobgtr	r7, L(tp1)
+	movl	r11, r0
+	ret
+
+L(v0_big):
+	jlbc	r4, L(2)
+
+C Loop for v0 >= 0x80000000
+L(tp2):	movl	(r8)+, r1
+	jlss	L(2n0)
+	emul	r1, r6, $0, r2
+	addl2	r11, r2
+	adwc	r1, r3
+	movl	r2, (r9)+
+L(2):	movl	(r8)+, r1
+	jlss	L(2n1)
+L(2p1):	emul	r1, r6, $0, r10
+	addl2	r3, r10
+	adwc	r1, r11
+	movl	r10, (r9)+
+
+	sobgtr	r7, L(tp2)
+	movl	r11, r0
+	ret
+
+L(2n0):	emul	r1, r6, $0, r2
+	addl2	r1, r3
+	addl2	r11, r2
+	adwc	r6, r3
+	movl	r2, (r9)+
+	movl	(r8)+, r1
+	jgeq	L(2p1)
+L(2n1):	emul	r1, r6, $0, r10
+	addl2	r1, r11
+	addl2	r3, r10
+	adwc	r6, r11
+	movl	r10, (r9)+
+
+	sobgtr	r7, L(tp2)
+	movl	r11, r0
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/vax/rshift.asm b/third_party/gmp/mpn/vax/rshift.asm
new file mode 100644
index 0000000..00b2daa
--- /dev/null
+++ b/third_party/gmp/mpn/vax/rshift.asm
@@ -0,0 +1,57 @@
+dnl  VAX mpn_rshift -- right shift.
+
+dnl  Copyright 1999-2001, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ASM_START()
+PROLOGUE(mpn_rshift)
+	.word	0x1c0
+	movl	4(ap), r7
+	movl	8(ap), r6
+	movl	12(ap), r1
+	movl	16(ap), r8
+
+	movl	(r6)+, r2
+	subl3	r8, $32, r8
+	ashl	r8, r2, r0
+	decl	r1
+	jeql	L(end)
+
+L(top):	movl	(r6)+, r3
+	ashq	r8, r2, r4
+	movl	r5, (r7)+
+	movl	r3, r2
+	sobgtr	r1, L(top)
+
+L(end):	clrl	r3
+	ashq	r8, r2, r4
+	movl	r5, (r7)
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/vax/sub_n.asm b/third_party/gmp/mpn/vax/sub_n.asm
new file mode 100644
index 0000000..2844ef2
--- /dev/null
+++ b/third_party/gmp/mpn/vax/sub_n.asm
@@ -0,0 +1,64 @@
+dnl  VAX mpn_sub_n -- Subtract two limb vectors of the same length > 0 and
+dnl  store difference in a third limb vector.
+
+dnl  Copyright 1999, 2000, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ASM_START()
+PROLOGUE(mpn_sub_n)
+	.word	0x0
+	movl	16(ap), r0
+	movl	12(ap), r1
+	movl	8(ap), r2
+	movl	4(ap), r3
+	mnegl	r0, r5
+	addl2	$3, r0
+	ashl	$-2, r0, r0	C unroll loop count
+	bicl2	$-4, r5		C mask out low 2 bits
+	movaq	(r5)[r5], r5	C 9x
+	jmp	L(top)[r5]
+
+L(top):	movl	(r2)+, r4
+	sbwc	(r1)+, r4
+	movl	r4, (r3)+
+	movl	(r2)+, r4
+	sbwc	(r1)+, r4
+	movl	r4, (r3)+
+	movl	(r2)+, r4
+	sbwc	(r1)+, r4
+	movl	r4, (r3)+
+	movl	(r2)+, r4
+	sbwc	(r1)+, r4
+	movl	r4, (r3)+
+	sobgtr	r0, L(top)
+
+	adwc	r0, r0
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/vax/submul_1.asm b/third_party/gmp/mpn/vax/submul_1.asm
new file mode 100644
index 0000000..60d47fc
--- /dev/null
+++ b/third_party/gmp/mpn/vax/submul_1.asm
@@ -0,0 +1,124 @@
+dnl  VAX mpn_submul_1 -- Multiply a limb vector with a limb and subtract the
+dnl  result from a second limb vector.
+
+dnl  Copyright 1992, 1994, 1996, 2000, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ASM_START()
+PROLOGUE(mpn_submul_1)
+	.word	0xfc0
+	movl	12(ap), r4
+	movl	8(ap), r8
+	movl	4(ap), r9
+	clrl	r3
+	incl	r4
+	ashl	$-1, r4, r7
+	clrl	r11
+	movl	16(ap), r6
+	jlss	L(v0_big)
+	jlbc	r4, L(1)
+
+C Loop for v0 < 0x80000000
+L(tp1):	movl	(r8)+, r1
+	jlss	L(1n0)
+	emul	r1, r6, $0, r2
+	addl2	r11, r2
+	adwc	$0, r3
+	subl2	r2, (r9)+
+	adwc	$0, r3
+L(1):	movl	(r8)+, r1
+	jlss	L(1n1)
+L(1p1):	emul	r1, r6, $0, r10
+	addl2	r3, r10
+	adwc	$0, r11
+	subl2	r10, (r9)+
+	adwc	$0, r11
+
+	sobgtr	r7, L(tp1)
+	movl	r11, r0
+	ret
+
+L(1n0):	emul	r1, r6, $0, r2
+	addl2	r11, r2
+	adwc	r6, r3
+	subl2	r2, (r9)+
+	adwc	$0, r3
+	movl	(r8)+, r1
+	jgeq	L(1p1)
+L(1n1):	emul	r1, r6, $0, r10
+	addl2	r3, r10
+	adwc	r6, r11
+	subl2	r10, (r9)+
+	adwc	$0, r11
+
+	sobgtr	r7, L(tp1)
+	movl	r11, r0
+	ret
+
+L(v0_big):
+	jlbc	r4, L(2)
+
+C Loop for v0 >= 0x80000000
+L(tp2):	movl	(r8)+, r1
+	jlss	L(2n0)
+	emul	r1, r6, $0, r2
+	addl2	r11, r2
+	adwc	r1, r3
+	subl2	r2, (r9)+
+	adwc	$0, r3
+L(2):	movl	(r8)+, r1
+	jlss	L(2n1)
+L(2p1):	emul	r1, r6, $0, r10
+	addl2	r3, r10
+	adwc	r1, r11
+	subl2	r10, (r9)+
+	adwc	$0, r11
+
+	sobgtr	r7, L(tp2)
+	movl	r11, r0
+	ret
+
+L(2n0):	emul	r1, r6, $0, r2
+	addl2	r11, r2
+	adwc	r6, r3
+	subl2	r2, (r9)+
+	adwc	r1, r3
+	movl	(r8)+, r1
+	jgeq	L(2p1)
+L(2n1):	emul	r1, r6, $0, r10
+	addl2	r3, r10
+	adwc	r6, r11
+	subl2	r10, (r9)+
+	adwc	r1, r11
+
+	sobgtr	r7, L(tp2)
+	movl	r11, r0
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/README b/third_party/gmp/mpn/x86/README
new file mode 100644
index 0000000..8d7ac90
--- /dev/null
+++ b/third_party/gmp/mpn/x86/README
@@ -0,0 +1,525 @@
+Copyright 1999-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.
+
+
+
+
+
+                      X86 MPN SUBROUTINES
+
+
+This directory contains mpn functions for various 80x86 chips.
+
+
+CODE ORGANIZATION
+
+	x86               i386, generic
+	x86/i486          i486
+	x86/pentium       Intel Pentium (P5, P54)
+	x86/pentium/mmx   Intel Pentium with MMX (P55)
+	x86/p6            Intel Pentium Pro
+	x86/p6/mmx        Intel Pentium II, III
+	x86/p6/p3mmx      Intel Pentium III
+	x86/k6            \ AMD K6
+	x86/k6/mmx        /
+	x86/k6/k62mmx     AMD K6-2
+	x86/k7            \ AMD Athlon
+	x86/k7/mmx        /
+	x86/pentium4      \
+	x86/pentium4/mmx  | Intel Pentium 4
+	x86/pentium4/sse2 /
+
+
+The top-level x86 directory contains blended style code, meant to be
+reasonable on all x86s.
+
+
+
+STATUS
+
+The code is well-optimized for AMD and Intel chips, but there's nothing
+specific for Cyrix chips, nor for actual 80386 and 80486 chips.
+
+
+
+ASM FILES
+
+The x86 .asm files are BSD style assembler code, first put through m4 for
+macro processing.  The generic mpn/asm-defs.m4 is used, together with
+mpn/x86/x86-defs.m4.  See comments in those files.
+
+The code is meant for use with GNU "gas" or a system "as".  There's no
+support for assemblers that demand Intel style code.
+
+
+
+STACK FRAME
+
+m4 macros are used to define the parameters passed on the stack, and these
+act like comments on what the stack frame looks like too.  For example,
+mpn_mul_1() has the following.
+
+        defframe(PARAM_MULTIPLIER, 16)
+        defframe(PARAM_SIZE,       12)
+        defframe(PARAM_SRC,         8)
+        defframe(PARAM_DST,         4)
+
+PARAM_MULTIPLIER becomes `FRAME+16(%esp)', and the others similarly.  The
+return address is at offset 0, but there's not normally any need to access
+that.
+
+FRAME is redefined as necessary through the code so it's the number of bytes
+pushed on the stack, and hence the offsets in the parameter macros stay
+correct.  At the start of a routine FRAME should be zero.
+
+        deflit(`FRAME',0)
+	...
+	deflit(`FRAME',4)
+	...
+	deflit(`FRAME',8)
+	...
+
+Helper macros FRAME_pushl(), FRAME_popl(), FRAME_addl_esp() and
+FRAME_subl_esp() exist to adjust FRAME for the effect of those instructions,
+and can be used instead of explicit definitions if preferred.
+defframe_pushl() is a combination FRAME_pushl() and defframe().
+
+There's generally some slackness in redefining FRAME.  If new values aren't
+going to get used then the redefinitions are omitted to keep from cluttering
+up the code.  This happens for instance at the end of a routine, where there
+might be just four pops and then a ret, so FRAME isn't getting used.
+
+Local variables and saved registers can be similarly defined, with negative
+offsets representing stack space below the initial stack pointer.  For
+example,
+
+	defframe(SAVE_ESI,   -4)
+	defframe(SAVE_EDI,   -8)
+	defframe(VAR_COUNTER,-12)
+
+	deflit(STACK_SPACE, 12)
+
+Here STACK_SPACE gets used in a "subl $STACK_SPACE, %esp" to allocate the
+space, and that instruction must be followed by a redefinition of FRAME
+(setting it equal to STACK_SPACE) to reflect the change in %esp.
+
+Definitions for pushed registers are only put in when they're going to be
+used.  If registers are just saved and restored with pushes and pops then
+definitions aren't made.
+
+
+
+ASSEMBLER EXPRESSIONS
+
+Only addition and subtraction seem to be universally available, certainly
+that's all the Solaris 8 "as" seems to accept.  If expressions are wanted
+then m4 eval() should be used.
+
+In particular note that a "/" anywhere in a line starts a comment in Solaris
+"as", and in some configurations of gas too.
+
+	addl	$32/2, %eax           <-- wrong
+
+	addl	$eval(32/2), %eax     <-- right
+
+Binutils gas/config/tc-i386.c has a choice between "/" being a comment
+anywhere in a line, or only at the start.  FreeBSD patches 2.9.1 to select
+the latter, and from 2.9.5 it's the default for GNU/Linux too.
+
+
+
+ASSEMBLER COMMENTS
+
+Solaris "as" doesn't support "#" commenting, using /* */ instead.  For that
+reason "C" commenting is used (see asm-defs.m4) and the intermediate ".s"
+files have no comments.
+
+Any comments before include(`../config.m4') must use m4 "dnl", since it's
+only after the include that "C" is available.  By convention "dnl" is also
+used for comments about m4 macros.
+
+
+
+TEMPORARY LABELS
+
+Temporary numbered labels like "1:" used as "1f" or "1b" are available in
+"gas" and Solaris "as", but not in SCO "as".  Normal L() labels should be
+used instead, possibly with a counter to make them unique, see jadcl0() in
+x86-defs.m4 for instance.  A separate counter for each macro makes it
+possible to nest them, for instance movl_text_address() can be used within
+an ASSERT().
+
+"1:" etc must be avoided in gcc __asm__ blocks too.  "%=" for generating a
+unique number looks like a good alternative, but is that actually a
+documented feature?  In any case this problem doesn't currently arise.
+
+
+
+ZERO DISPLACEMENTS
+
+In a couple of places addressing modes like 0(%ebx) with a byte-sized zero
+displacement are wanted, rather than (%ebx) with no displacement.  These are
+either for computed jumps or to get desirable code alignment.  Explicit
+.byte sequences are used to ensure the assembler doesn't turn 0(%ebx) into
+(%ebx).  The Zdisp() macro in x86-defs.m4 is used for this.
+
+Current gas 2.9.5 or recent 2.9.1 leave 0(%ebx) as written, but old gas
+1.92.3 changes it.  In general changing would be the sort of "optimization"
+an assembler might perform, hence explicit ".byte"s are used where
+necessary.
+
+
+
+SHLD/SHRD INSTRUCTIONS
+
+The %cl count forms of double shift instructions like "shldl %cl,%eax,%ebx"
+must be written "shldl %eax,%ebx" for some assemblers.  gas takes either,
+Solaris "as" doesn't allow %cl, gcc generates %cl for gas and NeXT (which is
+gas), and omits %cl elsewhere.
+
+For GMP an autoconf test GMP_ASM_X86_SHLDL_CL is used to determine whether
+%cl should be used, and the macros shldl, shrdl, shldw and shrdw in
+mpn/x86/x86-defs.m4 pass through or omit %cl as necessary.  See the comments
+with those macros for usage.
+
+
+
+IMUL INSTRUCTION
+
+GCC config/i386/i386.md (cvs rev 1.187, 21 Oct 00) under *mulsi3_1 notes
+that the following two forms produce identical object code
+
+	imul	$12, %eax
+	imul	$12, %eax, %eax
+
+but that the former isn't accepted by some assemblers, in particular the SCO
+OSR5 COFF assembler.  GMP follows GCC and uses only the latter form.
+
+(This applies only to immediate operands, the three operand form is only
+valid with an immediate.)
+
+
+
+DIRECTION FLAG
+
+The x86 calling conventions say that the direction flag should be clear at
+function entry and exit.  (See iBCS2 and SVR4 ABI books, references below.)
+Although this has been so since the year dot, it's not absolutely clear
+whether it's universally respected.  Since it's better to be safe than
+sorry, GMP follows glibc and does a "cld" if it depends on the direction
+flag being clear.  This happens only in a few places.
+
+
+
+POSITION INDEPENDENT CODE
+
+  Coding Style
+
+    Defining the symbol PIC in m4 processing selects SVR4 / ELF style
+    position independent code.  This is necessary for shared libraries
+    because they can be mapped into different processes at different virtual
+    addresses.  Actually, relocations are allowed but text pages with
+    relocations aren't shared, defeating the purpose of a shared library.
+
+    The GOT is used to access global data, and the PLT is used for
+    functions.  The use of the PLT adds a fixed cost to every function call,
+    and the GOT adds a cost to any function accessing global variables.
+    These are small but might be noticeable when working with small
+    operands.
+
+  Scope
+
+    It's intended, as a matter of policy, that references within libgmp are
+    resolved within libgmp.  Certainly there's no need for an application to
+    replace any internals, and we take the view that there's no value in an
+    application subverting anything documented either.
+
+    Resolving references within libgmp in theory means calls can be made with a
+    plain PC-relative call instruction, which is faster and smaller than going
+    through the PLT, and data references can be similarly PC-relative, saving a
+    GOT entry and fetch from there.  Unfortunately the normal linker behaviour
+    doesn't allow us to do this.
+
+    By default an R_386_PC32 PC-relative reference, either for a call or for
+    data, is left in libgmp.so by the linker so that it can be resolved at
+    runtime to a location in the application or another shared library.  This
+    means a text segment relocation which we don't want.
+
+  -Bsymbolic
+
+    Under the "-Bsymbolic" option, the linker resolves references to symbols
+    within libgmp.so.  This gives us the desired effect for R_386_PC32,
+    ie. it's resolved at link time.  It also resolves R_386_PLT32 calls
+    directly to their target without creating a PLT entry (though if this is
+    done to normal compiler-generated code it still leaves a setup of %ebx
+    to _GLOBAL_OFFSET_TABLE_ which may then be unnecessary).
+
+    Unfortunately -Bsymbolic does bad things to global variables defined in
+    a shared library but accessed by non-PIC code from the mainline (or a
+    static library).
+
+    The problem is that the mainline needs a fixed data address to avoid
+    text segment relocations, so space is allocated in its data segment and
+    the value from the variable is copied from the shared library's data
+    segment when the library is loaded.  Under -Bsymbolic, however,
+    references in the shared library are then resolved still to the shared
+    library data area.  Not surprisingly it bombs badly to have mainline
+    code and library code accessing different locations for what should be
+    one variable.
+
+    Note that this -Bsymbolic effect for the shared library is not just for
+    R_386_PC32 offsets which might have been cooked up in assembler, but is
+    done also for the contents of GOT entries.  -Bsymbolic simply applies a
+    general rule that symbols are resolved first from the local module.
+
+  Visibility Attributes
+
+    GCC __attribute__ ((visibility ("protected"))), which is available in
+    recent versions, eg. 3.3, is probably what we'd like to use.  It makes
+    gcc generate plain PC-relative calls to indicated functions, and directs
+    the linker to resolve references to the given function within the link
+    module.
+
+    Unfortunately, as of debian binutils 2.13.90.0.16 at least, the
+    resulting libgmp.so comes out with text segment relocations, references
+    are not resolved at link time.  If the gcc description is to be believed
+    this is this not how it should work.  If a symbol cannot be overridden
+    by another module then surely references within that module can be
+    resolved immediately (ie. at link time).
+
+  Present
+
+    In any case, all this means that we have no optimizations we can
+    usefully make to function or variable usages, neither for assembler nor
+    C code.  Perhaps in the future the visibility attribute will work as
+    we'd like.
+
+
+
+
+GLOBAL OFFSET TABLE
+
+The magic _GLOBAL_OFFSET_TABLE_ used by code establishing the address of the
+GOT sometimes requires an extra underscore prefix.  SVR4 systems and NetBSD
+don't need a prefix, OpenBSD does need one.  Note that NetBSD and OpenBSD
+are both a.out underscore systems, so the prefix for _GLOBAL_OFFSET_TABLE_
+is not simply the same as the prefix for ordinary globals.
+
+In any case in the asm code we write _GLOBAL_OFFSET_TABLE_ and let a macro
+in x86-defs.m4 add an extra underscore if required (according to a configure
+test).
+
+Old gas 1.92.3 which comes with FreeBSD 2.2.8 gets a segmentation fault when
+asked to assemble the following,
+
+        L1:
+            addl  $_GLOBAL_OFFSET_TABLE_+[.-L1], %ebx
+
+It seems that using the label in the same instruction it refers to is the
+problem, since a nop in between works.  But the simplest workaround is to
+follow gcc and omit the +[.-L1] since it does nothing,
+
+            addl  $_GLOBAL_OFFSET_TABLE_, %ebx
+
+Current gas 2.10 generates incorrect object code when %eax is used in such a
+construction (with or without +[.-L1]),
+
+            addl  $_GLOBAL_OFFSET_TABLE_, %eax
+
+The R_386_GOTPC gets a displacement of 2 rather than the 1 appropriate for
+the 1 byte opcode of "addl $n,%eax".  The best workaround is just to use any
+other register, since then it's a two byte opcode+mod/rm.  GCC for example
+always uses %ebx (which is needed for calls through the PLT).
+
+A similar problem occurs in an leal (again with or without a +[.-L1]),
+
+            leal  _GLOBAL_OFFSET_TABLE_(%edi), %ebx
+
+This time the R_386_GOTPC gets a displacement of 0 rather than the 2
+appropriate for the opcode and mod/rm, making this form unusable.
+
+
+
+
+SIMPLE LOOPS
+
+The overheads in setting up for an unrolled loop can mean that at small
+sizes a simple loop is faster.  Making small sizes go fast is important,
+even if it adds a cycle or two to bigger sizes.  To this end various
+routines choose between a simple loop and an unrolled loop according to
+operand size.  The path to the simple loop, or to special case code for
+small sizes, is always as fast as possible.
+
+Adding a simple loop requires a conditional jump to choose between the
+simple and unrolled code.  The size of a branch misprediction penalty
+affects whether a simple loop is worthwhile.
+
+The convention is for an m4 definition UNROLL_THRESHOLD to set the crossover
+point, with sizes < UNROLL_THRESHOLD using the simple loop, sizes >=
+UNROLL_THRESHOLD using the unrolled loop.  If position independent code adds
+a couple of cycles to an unrolled loop setup, the threshold will vary with
+PIC or non-PIC.  Something like the following is typical.
+
+	deflit(UNROLL_THRESHOLD, ifdef(`PIC',10,8))
+
+There's no automated way to determine the threshold.  Setting it to a small
+value and then to a big value makes it possible to measure the simple and
+unrolled loops each over a range of sizes, from which the crossover point
+can be determined.  Alternately, just adjust the threshold up or down until
+there's no more speedups.
+
+
+
+UNROLLED LOOP CODING
+
+The x86 addressing modes allow a byte displacement of -128 to +127, making
+it possible to access 256 bytes, which is 64 limbs, without adjusting
+pointer registers within the loop.  Dword sized displacements can be used
+too, but they increase code size, and unrolling to 64 ought to be enough.
+
+When unrolling to the full 64 limbs/loop, the limb at the top of the loop
+will have a displacement of -128, so pointers have to have a corresponding
++128 added before entering the loop.  When unrolling to 32 limbs/loop
+displacements 0 to 127 can be used with 0 at the top of the loop and no
+adjustment needed to the pointers.
+
+Where 64 limbs/loop is supported, the +128 adjustment is done only when 64
+limbs/loop is selected.  Usually the gain in speed using 64 instead of 32 or
+16 is small, so support for 64 limbs/loop is generally only for comparison.
+
+
+
+COMPUTED JUMPS
+
+When working from least significant limb to most significant limb (most
+routines) the computed jump and pointer calculations in preparation for an
+unrolled loop are as follows.
+
+	S = operand size in limbs
+	N = number of limbs per loop (UNROLL_COUNT)
+	L = log2 of unrolling (UNROLL_LOG2)
+	M = mask for unrolling (UNROLL_MASK)
+	C = code bytes per limb in the loop
+	B = bytes per limb (4 for x86)
+
+	computed jump            (-S & M) * C + entrypoint
+	subtract from pointers   (-S & M) * B
+	initial loop counter     (S-1) >> L
+	displacements            0 to B*(N-1)
+
+The loop counter is decremented at the end of each loop, and the looping
+stops when the decrement takes the counter to -1.  The displacements are for
+the addressing accessing each limb, eg. a load with "movl disp(%ebx), %eax".
+
+Usually the multiply by "C" can be handled without an imul, using instead an
+leal, or a shift and subtract.
+
+When working from most significant to least significant limb (eg. mpn_lshift
+and mpn_copyd), the calculations change as follows.
+
+	add to pointers          (-S & M) * B
+	displacements            0 to -B*(N-1)
+
+
+
+OLD GAS 1.92.3
+
+This version comes with FreeBSD 2.2.8 and has a couple of gremlins that
+affect GMP code.
+
+Firstly, an expression involving two forward references to labels comes out
+as zero.  For example,
+
+		addl	$bar-foo, %eax
+	foo:
+		nop
+	bar:
+
+This should lead to "addl $1, %eax", but it comes out as "addl $0, %eax".
+When only one forward reference is involved, it works correctly, as for
+example,
+
+	foo:
+		addl	$bar-foo, %eax
+		nop
+	bar:
+
+Secondly, an expression involving two labels can't be used as the
+displacement for an leal.  For example,
+
+	foo:
+		nop
+	bar:
+		leal	bar-foo(%eax,%ebx,8), %ecx
+
+A slightly cryptic error is given, "Unimplemented segment type 0 in
+parse_operand".  When only one label is used it's ok, and the label can be a
+forward reference too, as for example,
+
+		leal	foo(%eax,%ebx,8), %ecx
+		nop
+	foo:
+
+These problems only affect PIC computed jump calculations.  The workarounds
+are just to do an leal without a displacement and then an addl, and to make
+sure the code is placed so that there's at most one forward reference in the
+addl.
+
+
+
+REFERENCES
+
+"Intel Architecture Software Developer's Manual", volumes 1, 2a, 2b, 3a, 3b,
+2006, order numbers 253665 through 253669.  Available on-line,
+
+	ftp://download.intel.com/design/Pentium4/manuals/25366518.pdf
+	ftp://download.intel.com/design/Pentium4/manuals/25366618.pdf
+	ftp://download.intel.com/design/Pentium4/manuals/25366718.pdf
+	ftp://download.intel.com/design/Pentium4/manuals/25366818.pdf
+	ftp://download.intel.com/design/Pentium4/manuals/25366918.pdf
+
+
+"System V Application Binary Interface", Unix System Laboratories Inc, 1992,
+published by Prentice Hall, ISBN 0-13-880410-9.  And the "Intel386 Processor
+Supplement", AT&T, 1991, ISBN 0-13-877689-X.  These have details of calling
+conventions and ELF shared library PIC coding.  Versions of both available
+on-line,
+
+	http://www.sco.com/developer/devspecs
+
+"Intel386 Family Binary Compatibility Specification 2", Intel Corporation,
+published by McGraw-Hill, 1991, ISBN 0-07-031219-2.  (Same as the above 386
+ABI supplement.)
+
+
+
+----------------
+Local variables:
+mode: text
+fill-column: 76
+End:
diff --git a/third_party/gmp/mpn/x86/aors_n.asm b/third_party/gmp/mpn/x86/aors_n.asm
new file mode 100644
index 0000000..5d359f5
--- /dev/null
+++ b/third_party/gmp/mpn/x86/aors_n.asm
@@ -0,0 +1,202 @@
+dnl  x86 mpn_add_n/mpn_sub_n -- mpn addition and subtraction.
+
+dnl  Copyright 1992, 1994-1996, 1999-2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C     cycles/limb
+C P5	3.375
+C P6	3.125
+C K6	3.5
+C K7	2.25
+C P4	8.75
+
+
+ifdef(`OPERATION_add_n',`
+	define(M4_inst,        adcl)
+	define(M4_function_n,  mpn_add_n)
+	define(M4_function_nc, mpn_add_nc)
+
+',`ifdef(`OPERATION_sub_n',`
+	define(M4_inst,        sbbl)
+	define(M4_function_n,  mpn_sub_n)
+	define(M4_function_nc, mpn_sub_nc)
+
+',`m4_error(`Need OPERATION_add_n or OPERATION_sub_n
+')')')
+
+MULFUNC_PROLOGUE(mpn_add_n mpn_add_nc mpn_sub_n mpn_sub_nc)
+
+
+C mp_limb_t M4_function_n (mp_ptr dst, mp_srcptr src1, mp_srcptr src2,
+C                          mp_size_t size);
+C mp_limb_t M4_function_nc (mp_ptr dst, mp_srcptr src1, mp_srcptr src2,
+C	                    mp_size_t size, mp_limb_t carry);
+
+defframe(PARAM_CARRY,20)
+defframe(PARAM_SIZE, 16)
+defframe(PARAM_SRC2, 12)
+defframe(PARAM_SRC1, 8)
+defframe(PARAM_DST,  4)
+
+	TEXT
+	ALIGN(8)
+
+PROLOGUE(M4_function_nc)
+deflit(`FRAME',0)
+
+	pushl	%edi		FRAME_pushl()
+	pushl	%esi		FRAME_pushl()
+
+	movl	PARAM_DST,%edi
+	movl	PARAM_SRC1,%esi
+	movl	PARAM_SRC2,%edx
+	movl	PARAM_SIZE,%ecx
+
+	movl	%ecx,%eax
+	shrl	$3,%ecx			C compute count for unrolled loop
+	negl	%eax
+	andl	$7,%eax			C get index where to start loop
+	jz	L(oopgo)		C necessary special case for 0
+	incl	%ecx			C adjust loop count
+	shll	$2,%eax			C adjustment for pointers...
+	subl	%eax,%edi		C ... since they are offset ...
+	subl	%eax,%esi		C ... by a constant when we ...
+	subl	%eax,%edx		C ... enter the loop
+	shrl	$2,%eax			C restore previous value
+
+ifdef(`PIC',`
+	C Calculate start address in loop for PIC.  Due to limitations in
+	C old gas, LF(M4_function_n,oop)-L(0a)-3 cannot be put into the leal
+	call	L(0a)
+L(0a):	leal	(%eax,%eax,8),%eax
+	addl	(%esp),%eax
+	addl	$L(oop)-L(0a)-3,%eax
+	addl	$4,%esp
+',`
+	C Calculate start address in loop for non-PIC.
+	leal	L(oop)-3(%eax,%eax,8),%eax
+')
+
+	C These lines initialize carry from the 5th parameter.  Should be
+	C possible to simplify.
+	pushl	%ebp		FRAME_pushl()
+	movl	PARAM_CARRY,%ebp
+	shrl	%ebp			C shift bit 0 into carry
+	popl	%ebp		FRAME_popl()
+
+	jmp	*%eax			C jump into loop
+
+EPILOGUE()
+
+
+	ALIGN(16)
+PROLOGUE(M4_function_n)
+deflit(`FRAME',0)
+
+	pushl	%edi		FRAME_pushl()
+	pushl	%esi		FRAME_pushl()
+
+	movl	PARAM_DST,%edi
+	movl	PARAM_SRC1,%esi
+	movl	PARAM_SRC2,%edx
+	movl	PARAM_SIZE,%ecx
+
+	movl	%ecx,%eax
+	shrl	$3,%ecx			C compute count for unrolled loop
+	negl	%eax
+	andl	$7,%eax			C get index where to start loop
+	jz	L(oop)			C necessary special case for 0
+	incl	%ecx			C adjust loop count
+	shll	$2,%eax			C adjustment for pointers...
+	subl	%eax,%edi		C ... since they are offset ...
+	subl	%eax,%esi		C ... by a constant when we ...
+	subl	%eax,%edx		C ... enter the loop
+	shrl	$2,%eax			C restore previous value
+
+ifdef(`PIC',`
+	C Calculate start address in loop for PIC.  Due to limitations in
+	C some assemblers, L(oop)-L(0b)-3 cannot be put into the leal
+	call	L(0b)
+L(0b):	leal	(%eax,%eax,8),%eax
+	addl	(%esp),%eax
+	addl	$L(oop)-L(0b)-3,%eax
+	addl	$4,%esp
+',`
+	C Calculate start address in loop for non-PIC.
+	leal	L(oop)-3(%eax,%eax,8),%eax
+')
+	jmp	*%eax			C jump into loop
+
+L(oopgo):
+	pushl	%ebp		FRAME_pushl()
+	movl	PARAM_CARRY,%ebp
+	shrl	%ebp			C shift bit 0 into carry
+	popl	%ebp		FRAME_popl()
+
+	ALIGN(16)
+L(oop):	movl	(%esi),%eax
+	M4_inst	(%edx),%eax
+	movl	%eax,(%edi)
+	movl	4(%esi),%eax
+	M4_inst	4(%edx),%eax
+	movl	%eax,4(%edi)
+	movl	8(%esi),%eax
+	M4_inst	8(%edx),%eax
+	movl	%eax,8(%edi)
+	movl	12(%esi),%eax
+	M4_inst	12(%edx),%eax
+	movl	%eax,12(%edi)
+	movl	16(%esi),%eax
+	M4_inst	16(%edx),%eax
+	movl	%eax,16(%edi)
+	movl	20(%esi),%eax
+	M4_inst	20(%edx),%eax
+	movl	%eax,20(%edi)
+	movl	24(%esi),%eax
+	M4_inst	24(%edx),%eax
+	movl	%eax,24(%edi)
+	movl	28(%esi),%eax
+	M4_inst	28(%edx),%eax
+	movl	%eax,28(%edi)
+	leal	32(%edi),%edi
+	leal	32(%esi),%esi
+	leal	32(%edx),%edx
+	decl	%ecx
+	jnz	L(oop)
+
+	sbbl	%eax,%eax
+	negl	%eax
+
+	popl	%esi
+	popl	%edi
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/aorsmul_1.asm b/third_party/gmp/mpn/x86/aorsmul_1.asm
new file mode 100644
index 0000000..54a8905
--- /dev/null
+++ b/third_party/gmp/mpn/x86/aorsmul_1.asm
@@ -0,0 +1,156 @@
+dnl  x86 __gmpn_addmul_1 (for 386 and 486) -- Multiply a limb vector with a
+dnl  limb and add the result to a second limb vector.
+
+dnl  Copyright 1992, 1994, 1997, 1999-2002, 2005 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C			    cycles/limb
+C P5				14.75
+C P6 model 0-8,10-12		 7.5
+C P6 model 9  (Banias)		 6.7
+C P6 model 13 (Dothan)		 6.75
+C P4 model 0  (Willamette)	24.0
+C P4 model 1  (?)		24.0
+C P4 model 2  (Northwood)	24.0
+C P4 model 3  (Prescott)
+C P4 model 4  (Nocona)
+C Intel Atom
+C AMD K6			12.5
+C AMD K7			 5.25
+C AMD K8
+C AMD K10
+
+
+ifdef(`OPERATION_addmul_1',`
+      define(M4_inst,        addl)
+      define(M4_function_1,  mpn_addmul_1)
+
+',`ifdef(`OPERATION_submul_1',`
+      define(M4_inst,        subl)
+      define(M4_function_1,  mpn_submul_1)
+
+',`m4_error(`Need OPERATION_addmul_1 or OPERATION_submul_1
+')')')
+
+MULFUNC_PROLOGUE(mpn_addmul_1 mpn_submul_1)
+
+
+C mp_limb_t M4_function_1 (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                          mp_limb_t mult);
+
+define(PARAM_MULTIPLIER, `FRAME+16(%esp)')
+define(PARAM_SIZE,       `FRAME+12(%esp)')
+define(PARAM_SRC,        `FRAME+8(%esp)')
+define(PARAM_DST,        `FRAME+4(%esp)')
+
+	TEXT
+	ALIGN(8)
+
+PROLOGUE(M4_function_1)
+deflit(`FRAME',0)
+
+	pushl	%edi
+	pushl	%esi
+	pushl	%ebx
+	pushl	%ebp
+deflit(`FRAME',16)
+
+	movl	PARAM_DST,%edi
+	movl	PARAM_SRC,%esi
+	movl	PARAM_SIZE,%ecx
+
+	xorl	%ebx,%ebx
+	andl	$3,%ecx
+	jz	L(end0)
+
+L(oop0):
+	movl	(%esi),%eax
+	mull	PARAM_MULTIPLIER
+	leal	4(%esi),%esi
+	addl	%ebx,%eax
+	movl	$0,%ebx
+	adcl	%ebx,%edx
+	M4_inst	%eax,(%edi)
+	adcl	%edx,%ebx	C propagate carry into cylimb
+
+	leal	4(%edi),%edi
+	decl	%ecx
+	jnz	L(oop0)
+
+L(end0):
+	movl	PARAM_SIZE,%ecx
+	shrl	$2,%ecx
+	jz	L(end)
+
+	ALIGN(8)
+L(oop):	movl	(%esi),%eax
+	mull	PARAM_MULTIPLIER
+	addl	%eax,%ebx
+	movl	$0,%ebp
+	adcl	%edx,%ebp
+
+	movl	4(%esi),%eax
+	mull	PARAM_MULTIPLIER
+	M4_inst	%ebx,(%edi)
+	adcl	%eax,%ebp	C new lo + cylimb
+	movl	$0,%ebx
+	adcl	%edx,%ebx
+
+	movl	8(%esi),%eax
+	mull	PARAM_MULTIPLIER
+	M4_inst	%ebp,4(%edi)
+	adcl	%eax,%ebx	C new lo + cylimb
+	movl	$0,%ebp
+	adcl	%edx,%ebp
+
+	movl	12(%esi),%eax
+	mull	PARAM_MULTIPLIER
+	M4_inst	%ebx,8(%edi)
+	adcl	%eax,%ebp	C new lo + cylimb
+	movl	$0,%ebx
+	adcl	%edx,%ebx
+
+	M4_inst	%ebp,12(%edi)
+	adcl	$0,%ebx		C propagate carry into cylimb
+
+	leal	16(%esi),%esi
+	leal	16(%edi),%edi
+	decl	%ecx
+	jnz	L(oop)
+
+L(end):	movl	%ebx,%eax
+
+	popl	%ebp
+	popl	%ebx
+	popl	%esi
+	popl	%edi
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/atom/aorrlsh1_n.asm b/third_party/gmp/mpn/x86/atom/aorrlsh1_n.asm
new file mode 100644
index 0000000..cd1a650
--- /dev/null
+++ b/third_party/gmp/mpn/x86/atom/aorrlsh1_n.asm
@@ -0,0 +1,53 @@
+dnl  Intel Atom mpn_rsblsh1_n -- rp[] = (vp[] << 1) - up[]
+
+dnl  Contributed to the GNU project by Marco Bodrato.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+define(LSH, 1)
+define(RSH, 31)
+
+ifdef(`OPERATION_addlsh1_n', `
+	define(M4_inst,        adc)
+	define(M4_opp,         sub)
+	define(M4_function,    mpn_addlsh1_n)
+	define(M4_function_c,  mpn_addlsh1_nc)
+',`ifdef(`OPERATION_rsblsh1_n', `
+	define(M4_inst,        sbb)
+	define(M4_opp,         add)
+	define(M4_function,    mpn_rsblsh1_n)
+	define(M4_function_c,  mpn_rsblsh1_nc)
+',`m4_error(`Need OPERATION_addlsh1_n or OPERATION_rsblsh1_n
+')')')
+
+MULFUNC_PROLOGUE(mpn_addlsh1_n mpn_addlsh1_nc mpn_rsblsh1_n mpn_rsblsh1_nc)
+
+include_mpn(`x86/atom/aorrlshC_n.asm')
diff --git a/third_party/gmp/mpn/x86/atom/aorrlsh2_n.asm b/third_party/gmp/mpn/x86/atom/aorrlsh2_n.asm
new file mode 100644
index 0000000..10f4419
--- /dev/null
+++ b/third_party/gmp/mpn/x86/atom/aorrlsh2_n.asm
@@ -0,0 +1,53 @@
+dnl  Intel Atom mpn_addlsh2_n/mpn_rsblsh2_n -- rp[] = (vp[] << 2) +- up[]
+
+dnl  Contributed to the GNU project by Marco Bodrato.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+define(LSH, 2)
+define(RSH, 30)
+
+ifdef(`OPERATION_addlsh2_n', `
+	define(M4_inst,        adcl)
+	define(M4_opp,         subl)
+	define(M4_function,    mpn_addlsh2_n)
+	define(M4_function_c,  mpn_addlsh2_nc)
+',`ifdef(`OPERATION_rsblsh2_n', `
+	define(M4_inst,        sbbl)
+	define(M4_opp,         addl)
+	define(M4_function,    mpn_rsblsh2_n)
+	define(M4_function_c,  mpn_rsblsh2_nc)
+',`m4_error(`Need OPERATION_addlsh2_n or OPERATION_rsblsh2_n
+')')')
+
+MULFUNC_PROLOGUE(mpn_addlsh2_n mpn_addlsh2_nc mpn_rsblsh2_n mpn_rsblsh2_nc)
+
+include_mpn(`x86/atom/aorrlshC_n.asm')
diff --git a/third_party/gmp/mpn/x86/atom/aorrlshC_n.asm b/third_party/gmp/mpn/x86/atom/aorrlshC_n.asm
new file mode 100644
index 0000000..71cfe49
--- /dev/null
+++ b/third_party/gmp/mpn/x86/atom/aorrlshC_n.asm
@@ -0,0 +1,156 @@
+dnl  Intel Atom mpn_addlshC_n/mpn_rsblshC_n -- rp[] = (vp[] << C) +- up[]
+
+dnl  Contributed to the GNU project by Marco Bodrato.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C mp_limb_t mpn_addlshC_n (mp_ptr dst, mp_srcptr src1, mp_srcptr src2,
+C                          mp_size_t size);
+C mp_limb_t mpn_addlshC_nc (mp_ptr dst, mp_srcptr src1, mp_srcptr src2,
+C                           mp_size_t size, mp_limb_t carry);
+C mp_limb_t mpn_rsblshC_n (mp_ptr dst, mp_srcptr src1, mp_srcptr src2,
+C                          mp_size_t size);
+C mp_limb_t mpn_rsblshC_nc (mp_ptr dst, mp_srcptr src1, mp_srcptr src2,
+C                           mp_size_t size, mp_signed_limb_t carry);
+
+C				cycles/limb
+C P5
+C P6 model 0-8,10-12
+C P6 model 9  (Banias)
+C P6 model 13 (Dothan)
+C P4 model 0  (Willamette)
+C P4 model 1  (?)
+C P4 model 2  (Northwood)
+C P4 model 3  (Prescott)
+C P4 model 4  (Nocona)
+C Intel Atom			 6
+C AMD K6
+C AMD K7
+C AMD K8
+C AMD K10
+
+defframe(PARAM_CORB,	20)
+defframe(PARAM_SIZE,	16)
+defframe(PARAM_DBLD,	12)
+defframe(PARAM_SRC,	 8)
+defframe(PARAM_DST,	 4)
+
+dnl  re-use parameter space
+define(VAR_COUNT,`PARAM_SIZE')
+define(SAVE_EBP,`PARAM_DBLD')
+define(SAVE_VP,`PARAM_SRC')
+define(SAVE_UP,`PARAM_DST')
+
+define(M, eval(m4_lshift(1,LSH)))
+define(`rp',  `%edi')
+define(`up',  `%esi')
+define(`vp',  `%ebx')
+
+ASM_START()
+	TEXT
+	ALIGN(8)
+
+PROLOGUE(M4_function_c)
+deflit(`FRAME',0)
+	movl	PARAM_CORB, %eax
+	movl	%eax, %edx
+	shr	$LSH, %edx
+	andl	$1, %edx
+	M4_opp	%edx, %eax
+	jmp	L(start_nc)
+EPILOGUE()
+
+PROLOGUE(M4_function)
+deflit(`FRAME',0)
+
+	xor	%eax, %eax
+	xor	%edx, %edx
+L(start_nc):
+	push	rp			FRAME_pushl()
+
+	mov	PARAM_SIZE, %ecx	C size
+	mov	PARAM_DST, rp
+	mov	up, SAVE_UP
+	incl	%ecx			C size + 1
+	mov	PARAM_SRC, up
+	mov	vp, SAVE_VP
+	shr	%ecx			C (size+1)\2
+	mov	PARAM_DBLD, vp
+	mov	%ebp, SAVE_EBP
+	mov	%ecx, VAR_COUNT
+	jnc	L(entry)		C size odd
+
+	shr	%edx			C size even
+	mov	(vp), %ecx
+	lea	4(vp), vp
+	lea	(%eax,%ecx,M), %edx
+	mov	%ecx, %eax
+	lea	-4(up), up
+	lea	-4(rp), rp
+	jmp	L(enteven)
+
+	ALIGN(16)
+L(oop):
+	lea	(%eax,%ecx,M), %ebp
+	shr	$RSH, %ecx
+	mov	4(vp), %eax
+	shr	%edx
+	lea	8(vp), vp
+	M4_inst	(up), %ebp
+	lea	(%ecx,%eax,M), %edx
+	mov	%ebp, (rp)
+L(enteven):
+	M4_inst	4(up), %edx
+	lea	8(up), up
+	mov	%edx, 4(rp)
+	adc	%edx, %edx
+	shr	$RSH, %eax
+	lea	8(rp), rp
+L(entry):
+	mov	(vp), %ecx
+	decl	VAR_COUNT
+	jnz	L(oop)
+
+	lea	(%eax,%ecx,M), %ebp
+	shr	$RSH, %ecx
+	shr	%edx
+	mov	SAVE_VP, vp
+	M4_inst	(up), %ebp
+	mov	%ecx, %eax
+	mov	SAVE_UP, up
+	M4_inst	$0, %eax
+	mov	%ebp, (rp)
+	mov	SAVE_EBP, %ebp
+	pop	rp			FRAME_popl()
+	ret
+EPILOGUE()
+
+ASM_END()
diff --git a/third_party/gmp/mpn/x86/atom/aors_n.asm b/third_party/gmp/mpn/x86/atom/aors_n.asm
new file mode 100644
index 0000000..45ec287
--- /dev/null
+++ b/third_party/gmp/mpn/x86/atom/aors_n.asm
@@ -0,0 +1,159 @@
+dnl  Intel Atom mpn_add_n/mpn_sub_n -- rp[] = up[] +- vp[].
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  Contributed to the GNU project by Marco Bodrato.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C			    cycles/limb
+C P5
+C P6 model 0-8,10-12
+C P6 model 9  (Banias)
+C P6 model 13 (Dothan)
+C P4 model 0  (Willamette)
+C P4 model 1  (?)
+C P4 model 2  (Northwood)
+C P4 model 3  (Prescott)
+C P4 model 4  (Nocona)
+C Intel Atom			 3
+C AMD K6
+C AMD K7
+C AMD K8
+C AMD K10
+
+ifdef(`OPERATION_add_n', `
+	define(M4_inst,        adcl)
+	define(M4_function_n,  mpn_add_n)
+	define(M4_function_nc, mpn_add_nc)
+	define(M4_description, add)
+',`ifdef(`OPERATION_sub_n', `
+	define(M4_inst,        sbbl)
+	define(M4_function_n,  mpn_sub_n)
+	define(M4_function_nc, mpn_sub_nc)
+	define(M4_description, subtract)
+',`m4_error(`Need OPERATION_add_n or OPERATION_sub_n
+')')')
+
+MULFUNC_PROLOGUE(mpn_add_n mpn_add_nc mpn_sub_n mpn_sub_nc)
+
+C mp_limb_t M4_function_n (mp_ptr dst, mp_srcptr src1, mp_srcptr src2,
+C                         mp_size_t size);
+C mp_limb_t M4_function_nc (mp_ptr dst, mp_srcptr src1, mp_srcptr src2,
+C	                   mp_size_t size, mp_limb_t carry);
+C
+C Calculate src1,size M4_description src2,size, and store the result in
+C dst,size.  The return value is the carry bit from the top of the result (1
+C or 0).
+C
+C The _nc version accepts 1 or 0 for an initial carry into the low limb of
+C the calculation.  Note values other than 1 or 0 here will lead to garbage
+C results.
+
+defframe(PARAM_CARRY,20)
+defframe(PARAM_SIZE, 16)
+defframe(PARAM_SRC2, 12)
+defframe(PARAM_SRC1, 8)
+defframe(PARAM_DST,  4)
+
+dnl  re-use parameter space
+define(SAVE_RP,`PARAM_SIZE')
+define(SAVE_VP,`PARAM_SRC1')
+define(SAVE_UP,`PARAM_DST')
+
+define(`rp',  `%edi')
+define(`up',  `%esi')
+define(`vp',  `%ebx')
+define(`cy',  `%ecx')
+define(`r1',  `%ecx')
+define(`r2',  `%edx')
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+deflit(`FRAME',0)
+
+PROLOGUE(M4_function_n)
+	xor	cy, cy			C carry
+L(start):
+	mov	PARAM_SIZE, %eax	C size
+	mov	rp, SAVE_RP
+	mov	PARAM_DST, rp
+	mov	up, SAVE_UP
+	mov	PARAM_SRC1, up
+	shr	%eax			C size >> 1
+	mov	vp, SAVE_VP
+	mov	PARAM_SRC2, vp
+	jz	L(one)			C size == 1
+	jc	L(three)		C size % 2 == 1
+
+	shr	cy
+	mov	(up), r2
+	lea	4(up), up
+	lea	4(vp), vp
+	lea	-4(rp), rp
+	jmp	L(entry)
+L(one):
+	shr	cy
+	mov	(up), r1
+	jmp	L(end)
+L(three):
+	shr	cy
+	mov	(up), r1
+
+	ALIGN(16)
+L(oop):
+	M4_inst	(vp), r1
+	lea	8(up), up
+	mov	-4(up), r2
+	lea	8(vp), vp
+	mov	r1, (rp)
+L(entry):
+	M4_inst	-4(vp), r2
+	lea	8(rp), rp
+	dec	%eax
+	mov	(up), r1
+	mov	r2, -4(rp)
+	jnz	L(oop)
+
+L(end):					C %eax is zero here
+	mov	SAVE_UP, up
+	M4_inst	(vp), r1
+	mov	SAVE_VP, vp
+	mov	r1, (rp)
+	adc	%eax, %eax
+	mov	SAVE_RP, rp
+	ret
+EPILOGUE()
+
+PROLOGUE(M4_function_nc)
+	mov	PARAM_CARRY, cy		C carry
+	jmp	L(start)
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86/atom/aorslshC_n.asm b/third_party/gmp/mpn/x86/atom/aorslshC_n.asm
new file mode 100644
index 0000000..75ace65
--- /dev/null
+++ b/third_party/gmp/mpn/x86/atom/aorslshC_n.asm
@@ -0,0 +1,247 @@
+dnl  Intel Atom mpn_addlshC_n/mpn_sublshC_n -- rp[] = up[] +- (vp[] << C)
+
+dnl  Contributed to the GNU project by Marco Bodrato.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C mp_limb_t mpn_addlshC_n_ip1 (mp_ptr dst, mp_srcptr src, mp_size_t size);
+C mp_limb_t mpn_addlshC_nc_ip1 (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C				mp_limb_t carry);
+C mp_limb_t mpn_sublshC_n_ip1 (mp_ptr dst, mp_srcptr src, mp_size_t size,);
+C mp_limb_t mpn_sublshC_nc_ip1 (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C				mp_signed_limb_t borrow);
+
+defframe(PARAM_CORB,	16)
+defframe(PARAM_SIZE,	12)
+defframe(PARAM_SRC,	 8)
+defframe(PARAM_DST,	 4)
+
+C mp_limb_t mpn_addlshC_n (mp_ptr dst, mp_srcptr src1, mp_srcptr src2,
+C                          mp_size_t size,);
+C mp_limb_t mpn_addlshC_nc (mp_ptr dst, mp_srcptr src1, mp_srcptr src2,
+C                           mp_size_t size, mp_limb_t carry);
+C mp_limb_t mpn_sublshC_n (mp_ptr dst, mp_srcptr src1, mp_srcptr src2,
+C                          mp_size_t size,);
+C mp_limb_t mpn_sublshC_nc (mp_ptr dst, mp_srcptr src1, mp_srcptr src2,
+C                           mp_size_t size, mp_limb_t borrow);
+
+C if src1 == dst, _ip1 is used
+
+C					cycles/limb
+C				dst!=src1,src2	dst==src1
+C P5
+C P6 model 0-8,10-12
+C P6 model 9  (Banias)
+C P6 model 13 (Dothan)
+C P4 model 0  (Willamette)
+C P4 model 1  (?)
+C P4 model 2  (Northwood)
+C P4 model 3  (Prescott)
+C P4 model 4  (Nocona)
+C Intel Atom			 7		 6
+C AMD K6
+C AMD K7
+C AMD K8
+C AMD K10
+
+defframe(GPARAM_CORB,	20)
+defframe(GPARAM_SIZE,	16)
+defframe(GPARAM_SRC2,	12)
+
+dnl  re-use parameter space
+define(SAVE_EBP,`PARAM_SIZE')
+define(SAVE_EBX,`PARAM_SRC')
+define(SAVE_UP,`PARAM_DST')
+
+define(M, eval(m4_lshift(1,LSH)))
+define(`rp',  `%edi')
+define(`up',  `%esi')
+
+ASM_START()
+	TEXT
+	ALIGN(8)
+
+PROLOGUE(M4_ip_function_c)
+deflit(`FRAME',0)
+	movl	PARAM_CORB, %ecx
+	movl	%ecx, %edx
+	shr	$LSH, %edx
+	andl	$1, %edx
+	M4_opp	%edx, %ecx
+	jmp	L(start_nc)
+EPILOGUE()
+
+PROLOGUE(M4_ip_function)
+deflit(`FRAME',0)
+
+	xor	%ecx, %ecx
+	xor	%edx, %edx
+L(start_nc):
+	push	rp			FRAME_pushl()
+	mov	PARAM_DST, rp
+	mov	up, SAVE_UP
+	mov	PARAM_SRC, up
+	mov	%ebx, SAVE_EBX
+	mov	PARAM_SIZE, %ebx	C size
+L(inplace):
+	incl	%ebx			C size + 1
+	shr	%ebx			C (size+1)\2
+	mov	%ebp, SAVE_EBP
+	jnc	L(entry)		C size odd
+
+	add	%edx, %edx		C size even
+	mov	%ecx, %ebp
+	mov	(up), %ecx
+	lea	-4(rp), rp
+	lea	(%ebp,%ecx,M), %eax
+	lea	4(up), up
+	jmp	L(enteven)
+
+	ALIGN(16)
+L(oop):
+	lea	(%ecx,%eax,M), %ebp
+	shr	$RSH, %eax
+	mov	4(up), %ecx
+	add	%edx, %edx
+	lea	8(up), up
+	M4_inst	%ebp, (rp)
+	lea	(%eax,%ecx,M), %eax
+
+L(enteven):
+	M4_inst	%eax, 4(rp)
+	lea	8(rp), rp
+
+	sbb	%edx, %edx
+	shr	$RSH, %ecx
+
+L(entry):
+	mov	(up), %eax
+	decl	%ebx
+	jnz	L(oop)
+
+	lea	(%ecx,%eax,M), %ebp
+	shr	$RSH, %eax
+	shr	%edx
+	M4_inst	%ebp, (rp)
+	mov	SAVE_UP, up
+	adc	$0, %eax
+	mov	SAVE_EBP, %ebp
+	mov	SAVE_EBX, %ebx
+	pop	rp			FRAME_popl()
+	ret
+EPILOGUE()
+
+PROLOGUE(M4_function_c)
+deflit(`FRAME',0)
+	movl	GPARAM_CORB, %ecx
+	movl	%ecx, %edx
+	shr	$LSH, %edx
+	andl	$1, %edx
+	M4_opp	%edx, %ecx
+	jmp	L(generic_nc)
+EPILOGUE()
+
+PROLOGUE(M4_function)
+deflit(`FRAME',0)
+
+	xor	%ecx, %ecx
+	xor	%edx, %edx
+L(generic_nc):
+	push	rp			FRAME_pushl()
+	mov	PARAM_DST, rp
+	mov	up, SAVE_UP
+	mov	PARAM_SRC, up
+	cmp	rp, up
+	mov	%ebx, SAVE_EBX
+	jne	L(general)
+	mov	GPARAM_SIZE, %ebx	C size
+	mov	GPARAM_SRC2, up
+	jmp	L(inplace)
+
+L(general):
+	mov	GPARAM_SIZE, %eax	C size
+	mov	%ebx, SAVE_EBX
+	incl	%eax			C size + 1
+	mov	up, %ebx		C vp
+	mov	GPARAM_SRC2, up		C up
+	shr	%eax			C (size+1)\2
+	mov	%ebp, SAVE_EBP
+	mov	%eax, GPARAM_SIZE
+	jnc	L(entry2)		C size odd
+
+	add	%edx, %edx		C size even
+	mov	%ecx, %ebp
+	mov	(up), %ecx
+	lea	-4(rp), rp
+	lea	-4(%ebx), %ebx
+	lea	(%ebp,%ecx,M), %eax
+	lea	4(up), up
+	jmp	L(enteven2)
+
+	ALIGN(16)
+L(oop2):
+	lea	(%ecx,%eax,M), %ebp
+	shr	$RSH, %eax
+	mov	4(up), %ecx
+	add	%edx, %edx
+	lea	8(up), up
+	mov	(%ebx), %edx
+	M4_inst	%ebp, %edx
+	lea	(%eax,%ecx,M), %eax
+	mov	%edx, (rp)
+L(enteven2):
+	mov	4(%ebx), %edx
+	lea	8(%ebx), %ebx
+	M4_inst	%eax, %edx
+	mov	%edx, 4(rp)
+	sbb	%edx, %edx
+	shr	$RSH, %ecx
+	lea	8(rp), rp
+L(entry2):
+	mov	(up), %eax
+	decl	GPARAM_SIZE
+	jnz	L(oop2)
+
+	lea	(%ecx,%eax,M), %ebp
+	shr	$RSH, %eax
+	shr	%edx
+	mov	(%ebx), %edx
+	M4_inst	%ebp, %edx
+	mov	%edx, (rp)
+	mov	SAVE_UP, up
+	adc	$0, %eax
+	mov	SAVE_EBP, %ebp
+	mov	SAVE_EBX, %ebx
+	pop	rp			FRAME_popl()
+	ret
+EPILOGUE()
+
+ASM_END()
diff --git a/third_party/gmp/mpn/x86/atom/bdiv_q_1.asm b/third_party/gmp/mpn/x86/atom/bdiv_q_1.asm
new file mode 100644
index 0000000..31e908e
--- /dev/null
+++ b/third_party/gmp/mpn/x86/atom/bdiv_q_1.asm
@@ -0,0 +1,35 @@
+dnl  Intel Atom mpn_bdiv_q_1, mpn_pi1_bdiv_q_1 -- schoolbook Hensel
+dnl  division by 1-limb divisor, returning quotient only.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+MULFUNC_PROLOGUE(mpn_bdiv_q_1 mpn_pi1_bdiv_q_1)
+include_mpn(`x86/pentium/bdiv_q_1.asm')
diff --git a/third_party/gmp/mpn/x86/atom/cnd_add_n.asm b/third_party/gmp/mpn/x86/atom/cnd_add_n.asm
new file mode 100644
index 0000000..50bf2ad
--- /dev/null
+++ b/third_party/gmp/mpn/x86/atom/cnd_add_n.asm
@@ -0,0 +1,113 @@
+dnl  X86 mpn_cnd_add_n optimised for Intel Atom.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C			    cycles/limb
+C P5				 ?
+C P6 model 0-8,10-12		 ?
+C P6 model 9   (Banias)		 ?
+C P6 model 13  (Dothan)		 ?
+C P4 model 0-1 (Willamette)	 ?
+C P4 model 2   (Northwood)	 ?
+C P4 model 3-4 (Prescott)	 ?
+C Intel atom			 4.67
+C AMD K6			 ?
+C AMD K7			 ?
+C AMD K8			 ?
+
+
+define(`rp',  `%edi')
+define(`up',  `%esi')
+define(`vp',  `%ebp')
+define(`n',   `%ecx')
+define(`cnd', `20(%esp)')
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_cnd_add_n)
+	push	%edi
+	push	%esi
+	push	%ebx
+	push	%ebp
+
+	mov	cnd, %eax		C make cnd into a mask (1)
+	mov	24(%esp), rp
+	neg	%eax			C make cnd into a mask (1)
+	mov	28(%esp), up
+	sbb	%eax, %eax		C make cnd into a mask (1)
+	mov	32(%esp), vp
+	mov	%eax, cnd		C make cnd into a mask (1)
+	mov	36(%esp), n
+
+	xor	%edx, %edx
+
+	shr	$1, n
+	jnc	L(top)
+
+	mov	0(vp), %eax
+	and	cnd, %eax
+	lea	4(vp), vp
+	add	0(up), %eax
+	lea	4(rp), rp
+	lea	4(up), up
+	sbb	%edx, %edx
+	mov	%eax, -4(rp)
+	inc	n
+	dec	n
+	je	L(end)
+
+L(top):	sbb	%edx, %edx
+	mov	0(vp), %eax
+	and	cnd, %eax
+	lea	8(vp), vp
+	lea	8(rp), rp
+	mov	-4(vp), %ebx
+	and	cnd, %ebx
+	add	%edx, %edx
+	adc	0(up), %eax
+	lea	8(up), up
+	mov	%eax, -8(rp)
+	adc	-4(up), %ebx
+	dec	n
+	mov	%ebx, -4(rp)
+	jne	L(top)
+
+L(end):	mov	$0, %eax
+	adc	%eax, %eax
+
+	pop	%ebp
+	pop	%ebx
+	pop	%esi
+	pop	%edi
+	ret
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86/atom/cnd_sub_n.asm b/third_party/gmp/mpn/x86/atom/cnd_sub_n.asm
new file mode 100644
index 0000000..221bedc
--- /dev/null
+++ b/third_party/gmp/mpn/x86/atom/cnd_sub_n.asm
@@ -0,0 +1,124 @@
+dnl  X86 mpn_cnd_sub_n optimised for Intel Atom.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C			    cycles/limb
+C P5				 ?
+C P6 model 0-8,10-12		 ?
+C P6 model 9   (Banias)		 ?
+C P6 model 13  (Dothan)		 ?
+C P4 model 0-1 (Willamette)	 ?
+C P4 model 2   (Northwood)	 ?
+C P4 model 3-4 (Prescott)	 ?
+C Intel atom			 5.67
+C AMD K6			 ?
+C AMD K7			 ?
+C AMD K8			 ?
+
+
+define(`rp',  `%edi')
+define(`up',  `%esi')
+define(`vp',  `%ebp')
+define(`n',   `%ecx')
+define(`cnd', `20(%esp)')
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_cnd_sub_n)
+	push	%edi
+	push	%esi
+	push	%ebx
+	push	%ebp
+
+	mov	cnd, %eax		C make cnd into a mask (1)
+	mov	24(%esp), rp
+	neg	%eax			C make cnd into a mask (1)
+	mov	28(%esp), up
+	sbb	%eax, %eax		C make cnd into a mask (1)
+	mov	32(%esp), vp
+	mov	%eax, cnd		C make cnd into a mask (1)
+	mov	36(%esp), n
+
+	xor	%edx, %edx
+
+	inc	n
+	shr	n
+	jnc	L(ent)
+
+	mov	0(vp), %eax
+	and	cnd, %eax
+	lea	4(vp), vp
+	mov	0(up), %edx
+	sub	%eax, %edx
+	lea	4(rp), rp
+	lea	4(up), up
+	mov	%edx, -4(rp)
+	sbb	%edx, %edx		C save cy
+
+L(ent):	mov	0(vp), %ebx
+	and	cnd, %ebx
+	add	%edx, %edx		C restore cy
+	mov	0(up), %edx
+	dec	n
+	je	L(end)
+
+L(top):	sbb	%ebx, %edx
+	mov	4(vp), %eax
+	mov	%edx, 0(rp)
+	sbb	%edx, %edx		C save cy
+	mov	8(vp), %ebx
+	lea	8(up), up
+	and	cnd, %ebx
+	and	cnd, %eax
+	add	%edx, %edx		C restore cy
+	mov	-4(up), %edx
+	lea	8(rp), rp
+	sbb	%eax, %edx
+	mov	%edx, -4(rp)
+	dec	n
+	mov	0(up), %edx
+	lea	8(vp), vp
+	jne	L(top)
+
+L(end):	sbb	%ebx, %edx
+	mov	%edx, 0(rp)
+
+	mov	$0, %eax
+	adc	%eax, %eax
+
+	pop	%ebp
+	pop	%ebx
+	pop	%esi
+	pop	%edi
+	ret
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86/atom/dive_1.asm b/third_party/gmp/mpn/x86/atom/dive_1.asm
new file mode 100644
index 0000000..71036a1
--- /dev/null
+++ b/third_party/gmp/mpn/x86/atom/dive_1.asm
@@ -0,0 +1,34 @@
+dnl  Intel Atom mpn_divexact_1 -- mpn by limb exact division.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+MULFUNC_PROLOGUE(mpn_divexact_1)
+include_mpn(`x86/pentium/dive_1.asm')
diff --git a/third_party/gmp/mpn/x86/atom/gmp-mparam.h b/third_party/gmp/mpn/x86/atom/gmp-mparam.h
new file mode 100644
index 0000000..e025bb7
--- /dev/null
+++ b/third_party/gmp/mpn/x86/atom/gmp-mparam.h
@@ -0,0 +1,214 @@
+/* Intel Atom/32 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+/* 1600 MHz Diamondville (Atom 330) */
+/* FFT tuning limit = 67,000,000 */
+/* Generated by tuneup.c, 2019-10-18, gcc 8.3 */
+
+#define MOD_1_NORM_THRESHOLD                 3
+#define MOD_1_UNNORM_THRESHOLD               5
+#define MOD_1N_TO_MOD_1_1_THRESHOLD         11
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          5
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        10
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD         0  /* never mpn_mod_1s_2p */
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     17
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1N_PI1_METHOD                 1  /* 72.60% faster than 2 */
+#define DIV_QR_1_NORM_THRESHOLD          MP_SIZE_T_MAX  /* never */
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           35
+
+#define DIV_1_VS_MUL_1_PERCENT             236
+
+#define MUL_TOOM22_THRESHOLD                22
+#define MUL_TOOM33_THRESHOLD                81
+#define MUL_TOOM44_THRESHOLD               178
+#define MUL_TOOM6H_THRESHOLD               270
+#define MUL_TOOM8H_THRESHOLD               399
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      97
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     126
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     115
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     129
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     115
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 32
+#define SQR_TOOM3_THRESHOLD                117
+#define SQR_TOOM4_THRESHOLD                178
+#define SQR_TOOM6_THRESHOLD                366
+#define SQR_TOOM8_THRESHOLD                527
+
+#define MULMID_TOOM42_THRESHOLD             50
+
+#define MULMOD_BNM1_THRESHOLD               13
+#define SQRMOD_BNM1_THRESHOLD               17
+
+#define MUL_FFT_MODF_THRESHOLD             404  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    404, 5}, {     21, 6}, {     11, 5}, {     23, 6}, \
+    {     12, 5}, {     25, 6}, {     13, 5}, {     27, 6}, \
+    {     21, 7}, {     11, 6}, {     25, 7}, {     13, 6}, \
+    {     27, 7}, {     15, 6}, {     31, 7}, {     21, 8}, \
+    {     11, 7}, {     27, 8}, {     15, 7}, {     35, 8}, \
+    {     19, 7}, {     39, 8}, {     23, 7}, {     47, 8}, \
+    {     27, 9}, {     15, 8}, {     39, 9}, {     23, 8}, \
+    {     51,10}, {     15, 9}, {     31, 8}, {     67, 9}, \
+    {     39, 8}, {     79, 9}, {     47, 8}, {     95,10}, \
+    {     31, 9}, {     79,10}, {     47, 9}, {     95,11}, \
+    {     31,10}, {     63, 9}, {    135,10}, {     79, 9}, \
+    {    159,10}, {     95, 9}, {    191,10}, {    111,11}, \
+    {     63,10}, {    127, 9}, {    255, 8}, {    511,10}, \
+    {    143, 9}, {    287, 8}, {    575, 9}, {    303,10}, \
+    {    159,11}, {     95,10}, {    191, 9}, {    383,12}, \
+    {     63,11}, {    127,10}, {    255, 9}, {    511,10}, \
+    {    271, 9}, {    543,10}, {    287, 9}, {    575,10}, \
+    {    303,11}, {    159,10}, {    351, 9}, {    703,10}, \
+    {    367, 9}, {    735,11}, {    191,10}, {    383, 9}, \
+    {    767,10}, {    415,11}, {    223,10}, {    447,12}, \
+    {    127,11}, {    255,10}, {    543,11}, {    287,10}, \
+    {    607,11}, {    319,10}, {    671,11}, {    351,10}, \
+    {    735,12}, {    191,11}, {    383,10}, {    767,11}, \
+    {    415,10}, {    831,11}, {    447,13}, {    127,12}, \
+    {    255,11}, {    543,10}, {   1087,11}, {    607,12}, \
+    {    319,11}, {    735,12}, {    383,11}, {    831,12}, \
+    {    447,11}, {    959,13}, {    255,12}, {    511,11}, \
+    {   1087,12}, {    575,11}, {   1215,12}, {    639,11}, \
+    {   1279,12}, {    703,11}, {   1407,13}, {    383,12}, \
+    {    831,11}, {   1663,12}, {    959,14}, {    255,13}, \
+    {    511,12}, {   1215,13}, {    639,12}, {   1471,13}, \
+    {    767,12}, {   1599,13}, {    895,12}, {   1791,14}, \
+    {    511,13}, {   1023,12}, {   2111,13}, {   1151,12}, \
+    {   2431,13}, {   1407,14}, {    767,13}, {   1663,12}, \
+    {   3455,13}, {   1791,15}, {    511,14}, {   1023,13}, \
+    {   2431,14}, {   1279,13}, {   2943,12}, {   5887,14}, \
+    {   1535,13}, {   3455,14}, {   1791,13}, {   3839,15}, \
+    {   1023,14}, {   2047,13}, {   4223,14}, {   2303,13}, \
+    {   4991,12}, {   9983,14}, {   2815,13}, {   5887,15}, \
+    {   1535,14}, {   3839,16} }
+#define MUL_FFT_TABLE3_SIZE 158
+#define MUL_FFT_THRESHOLD                 4544
+
+#define SQR_FFT_MODF_THRESHOLD             368  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    368, 5}, {     23, 6}, {     12, 5}, {     25, 6}, \
+    {     13, 5}, {     27, 6}, {     25, 7}, {     13, 6}, \
+    {     28, 7}, {     15, 6}, {     31, 7}, {     17, 6}, \
+    {     35, 7}, {     21, 8}, {     11, 7}, {     27, 8}, \
+    {     15, 7}, {     35, 8}, {     19, 7}, {     41, 8}, \
+    {     23, 7}, {     47, 8}, {     27, 9}, {     15, 8}, \
+    {     39, 9}, {     23, 8}, {     51,10}, {     15, 9}, \
+    {     31, 8}, {     63, 9}, {     39, 8}, {     79, 9}, \
+    {     47,10}, {     31, 9}, {     79,10}, {     47, 9}, \
+    {     95,11}, {     31,10}, {     63, 9}, {    127, 8}, \
+    {    255, 9}, {    135,10}, {     79, 9}, {    159, 8}, \
+    {    319,10}, {     95, 9}, {    191,11}, {     63,10}, \
+    {    127, 9}, {    255, 8}, {    511, 9}, {    271,10}, \
+    {    143, 9}, {    287, 8}, {    575, 9}, {    303,10}, \
+    {    159, 9}, {    319,11}, {     95,10}, {    191, 9}, \
+    {    383,12}, {     63,11}, {    127,10}, {    255, 9}, \
+    {    511,10}, {    271, 9}, {    543,10}, {    287, 9}, \
+    {    575,10}, {    303, 9}, {    607,11}, {    159,10}, \
+    {    319, 9}, {    639,10}, {    335, 9}, {    671,10}, \
+    {    351, 9}, {    703,11}, {    191,10}, {    383, 9}, \
+    {    767,10}, {    415,11}, {    223,10}, {    447,12}, \
+    {    127,11}, {    255,10}, {    543,11}, {    287,10}, \
+    {    607,11}, {    319,10}, {    671,11}, {    351,10}, \
+    {    703,12}, {    191,11}, {    383,10}, {    767,11}, \
+    {    415,10}, {    831,11}, {    447,13}, {    127,12}, \
+    {    255,11}, {    543,10}, {   1087,11}, {    607,12}, \
+    {    319,11}, {    671,10}, {   1343,11}, {    735,12}, \
+    {    383,11}, {    831,12}, {    447,11}, {    959,13}, \
+    {    255,12}, {    511,11}, {   1087,12}, {    575,11}, \
+    {   1215,12}, {    639,11}, {   1343,12}, {    703,13}, \
+    {    383,12}, {    959,14}, {    255,13}, {    511,12}, \
+    {   1215,13}, {    639,12}, {   1471,13}, {    767,12}, \
+    {   1599,13}, {    895,14}, {    511,13}, {   1023,12}, \
+    {   2111,13}, {   1151,12}, {   2431,13}, {   1407,14}, \
+    {    767,13}, {   1663,12}, {   3455,15}, {    511,14}, \
+    {   1023,13}, {   2175,12}, {   4351,13}, {   2431,14}, \
+    {   1279,13}, {   2943,12}, {   5887,14}, {   1535,13}, \
+    {   3455,14}, {   1791,13}, {   3839,15}, {   1023,14}, \
+    {   2047,13}, {   4351,14}, {   2303,13}, {   4991,12}, \
+    {   9983,14}, {   2815,13}, {   5887,15}, {   1535,14}, \
+    {   3839,16} }
+#define SQR_FFT_TABLE3_SIZE 161
+#define SQR_FFT_THRESHOLD                 3712
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  56
+#define MULLO_MUL_N_THRESHOLD             8907
+#define SQRLO_BASECASE_THRESHOLD             6
+#define SQRLO_DC_THRESHOLD                 111
+#define SQRLO_SQR_THRESHOLD               6654
+
+#define DC_DIV_QR_THRESHOLD                 67
+#define DC_DIVAPPR_Q_THRESHOLD             252
+#define DC_BDIV_QR_THRESHOLD                63
+#define DC_BDIV_Q_THRESHOLD                172
+
+#define INV_MULMOD_BNM1_THRESHOLD           42
+#define INV_NEWTON_THRESHOLD               250
+#define INV_APPR_THRESHOLD                 250
+
+#define BINV_NEWTON_THRESHOLD              276
+#define REDC_1_TO_REDC_N_THRESHOLD          68
+
+#define MU_DIV_QR_THRESHOLD               1334
+#define MU_DIVAPPR_Q_THRESHOLD            1442
+#define MUPI_DIV_QR_THRESHOLD              116
+#define MU_BDIV_QR_THRESHOLD              1142
+#define MU_BDIV_Q_THRESHOLD               1341
+
+#define POWM_SEC_TABLE  1,16,98,376,1259
+
+#define GET_STR_DC_THRESHOLD                12
+#define GET_STR_PRECOMPUTE_THRESHOLD        23
+#define SET_STR_DC_THRESHOLD               298
+#define SET_STR_PRECOMPUTE_THRESHOLD      1037
+
+#define FAC_DSC_THRESHOLD                  171
+#define FAC_ODD_THRESHOLD                   34
+
+#define MATRIX22_STRASSEN_THRESHOLD         17
+#define HGCD2_DIV1_METHOD                    3  /* 3.71% faster than 1 */
+#define HGCD_THRESHOLD                     128
+#define HGCD_APPR_THRESHOLD                186
+#define HGCD_REDUCE_THRESHOLD             2479
+#define GCD_DC_THRESHOLD                   465
+#define GCDEXT_DC_THRESHOLD                339
+#define JACOBI_BASE_METHOD                   3  /* 2.58% faster than 2 */
+
+/* Tuneup completed successfully, took 214190 seconds */
diff --git a/third_party/gmp/mpn/x86/atom/logops_n.asm b/third_party/gmp/mpn/x86/atom/logops_n.asm
new file mode 100644
index 0000000..3cb6d73
--- /dev/null
+++ b/third_party/gmp/mpn/x86/atom/logops_n.asm
@@ -0,0 +1,151 @@
+dnl  Intel Atom mpn_and_n,...,mpn_xnor_n -- bitwise logical operations.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  Contributed to the GNU project by Marco Bodrato.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C				   cycles/limb
+C				op	nop	opn
+C P5
+C P6 model 0-8,10-12
+C P6 model 9  (Banias)
+C P6 model 13 (Dothan)
+C P4 model 0  (Willamette)
+C P4 model 1  (?)
+C P4 model 2  (Northwood)
+C P4 model 3  (Prescott)
+C P4 model 4  (Nocona)
+C Intel Atom			 3	 3.5	 3.5
+C AMD K6
+C AMD K7
+C AMD K8
+C AMD K10
+
+define(M4_choose_op,
+`ifdef(`OPERATION_$1',`
+define(`M4_function', `mpn_$1')
+define(`M4_want_pre', `$4')
+define(`M4_inst',     `$3')
+define(`M4_want_post',`$2')
+')')
+define(M4pre, `ifelse(M4_want_pre, yes,`$1')')
+define(M4post,`ifelse(M4_want_post,yes,`$1')')
+
+M4_choose_op( and_n,     , andl,    )
+M4_choose_op( andn_n,    , andl, yes)
+M4_choose_op( nand_n, yes, andl,    )
+M4_choose_op( ior_n,     ,  orl,    )
+M4_choose_op( iorn_n,    ,  orl, yes)
+M4_choose_op( nior_n, yes,  orl,    )
+M4_choose_op( xor_n,     , xorl,    )
+M4_choose_op( xnor_n, yes, xorl,    )
+
+ifdef(`M4_function',,
+`m4_error(`Unrecognised or undefined OPERATION symbol
+')')
+
+MULFUNC_PROLOGUE(mpn_and_n mpn_andn_n mpn_nand_n mpn_ior_n mpn_iorn_n mpn_nior_n mpn_xor_n mpn_xnor_n)
+
+C void M4_function (mp_ptr dst, mp_srcptr src2, mp_srcptr src1, mp_size_t size);
+C
+
+defframe(PARAM_SIZE, 16)
+defframe(PARAM_SRC1, 12)
+defframe(PARAM_SRC2, 8)
+defframe(PARAM_DST,  4)
+
+dnl  re-use parameter space
+define(SAVE_RP,`PARAM_SIZE')
+define(SAVE_VP,`PARAM_SRC1')
+define(SAVE_UP,`PARAM_DST')
+
+define(`rp',  `%edi')
+define(`up',  `%esi')
+define(`vp',  `%ebx')
+define(`cnt', `%eax')
+define(`r1',  `%ecx')
+define(`r2',  `%edx')
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+deflit(`FRAME',0)
+
+PROLOGUE(M4_function)
+	mov	PARAM_SIZE, cnt		C size
+	mov	rp, SAVE_RP
+	mov	PARAM_DST, rp
+	mov	up, SAVE_UP
+	mov	PARAM_SRC1, up
+	shr	cnt			C size >> 1
+	mov	vp, SAVE_VP
+	mov	PARAM_SRC2, vp
+	mov	(up), r1
+	jz	L(end)			C size == 1
+	jnc	L(even)			C size % 2 == 0
+
+	ALIGN(16)
+L(oop):
+M4pre(`	notl_or_xorl_GMP_NUMB_MASK(r1)')
+	M4_inst	(vp), r1
+	lea	8(up), up
+	mov	-4(up), r2
+M4post(`	notl_or_xorl_GMP_NUMB_MASK(r1)')
+	lea	8(vp), vp
+	mov	r1, (rp)
+L(entry):
+M4pre(`	notl_or_xorl_GMP_NUMB_MASK(r2)')
+	M4_inst	-4(vp), r2
+	lea	8(rp), rp
+M4post(`	notl_or_xorl_GMP_NUMB_MASK(r2)')
+	dec	cnt
+	mov	(up), r1
+	mov	r2, -4(rp)
+	jnz	L(oop)
+
+L(end):
+M4pre(`	notl_or_xorl_GMP_NUMB_MASK(r1)')
+	mov	SAVE_UP, up
+	M4_inst	(vp), r1
+M4post(`notl_or_xorl_GMP_NUMB_MASK(r1)')
+	mov	SAVE_VP, vp
+	mov	r1, (rp)
+	mov	SAVE_RP, rp
+	ret
+
+L(even):
+	mov	r1, r2
+	lea	4(up), up
+	lea	4(vp), vp
+	lea	-4(rp), rp
+	jmp	L(entry)
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86/atom/lshift.asm b/third_party/gmp/mpn/x86/atom/lshift.asm
new file mode 100644
index 0000000..f2c70dd
--- /dev/null
+++ b/third_party/gmp/mpn/x86/atom/lshift.asm
@@ -0,0 +1,218 @@
+dnl  Intel Atom mpn_lshift -- mpn left shift.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund and Marco Bodrato.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C mp_limb_t mpn_lshift (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C			unsigned cnt);
+
+C				  cycles/limb
+C				cnt!=1	cnt==1
+C P5
+C P6 model 0-8,10-12
+C P6 model 9  (Banias)
+C P6 model 13 (Dothan)
+C P4 model 0  (Willamette)
+C P4 model 1  (?)
+C P4 model 2  (Northwood)
+C P4 model 3  (Prescott)
+C P4 model 4  (Nocona)
+C Intel Atom			 5	 2.5
+C AMD K6
+C AMD K7
+C AMD K8
+C AMD K10
+
+defframe(PARAM_CNT, 16)
+defframe(PARAM_SIZE,12)
+defframe(PARAM_SRC,  8)
+defframe(PARAM_DST,  4)
+
+dnl  re-use parameter space
+define(SAVE_UP,`PARAM_CNT')
+define(VAR_COUNT,`PARAM_SIZE')
+define(SAVE_EBX,`PARAM_SRC')
+define(SAVE_EBP,`PARAM_DST')
+
+define(`rp',  `%edi')
+define(`up',  `%esi')
+define(`cnt',  `%ecx')
+
+ASM_START()
+	TEXT
+	ALIGN(8)
+deflit(`FRAME',0)
+PROLOGUE(mpn_lshift)
+	mov	PARAM_CNT, cnt
+	mov	PARAM_SIZE, %edx
+	mov	up, SAVE_UP
+	mov	PARAM_SRC, up
+	push	rp			FRAME_pushl()
+	mov	PARAM_DST, rp
+
+C We can use faster code for shift-by-1 under certain conditions.
+	cmp	$1,cnt
+	jne	L(normal)
+	cmpl	rp, up
+	jnc	L(special)		C jump if s_ptr + 1 >= res_ptr
+	leal	(up,%edx,4),%eax
+	cmpl	%eax,rp
+	jnc	L(special)		C jump if res_ptr >= s_ptr + size
+
+L(normal):
+	lea	-4(up,%edx,4), up
+	mov	%ebx, SAVE_EBX
+	lea	-4(rp,%edx,4), rp
+
+	shr	%edx
+	mov	(up), %eax
+	mov	%edx, VAR_COUNT
+	jnc	L(evn)
+
+	mov	%eax, %ebx
+	shl	%cl, %ebx
+	neg	cnt
+	shr	%cl, %eax
+	test	%edx, %edx
+	jnz	L(gt1)
+	mov	%ebx, (rp)
+	jmp	L(quit)
+
+L(gt1):	mov	%ebp, SAVE_EBP
+	push	%eax
+	mov	-4(up), %eax
+	mov	%eax, %ebp
+	shr	%cl, %eax
+	jmp	L(lo1)
+
+L(evn):	mov	%ebp, SAVE_EBP
+	neg	cnt
+	mov	%eax, %ebp
+	mov	-4(up), %edx
+	shr	%cl, %eax
+	mov	%edx, %ebx
+	shr	%cl, %edx
+	neg	cnt
+	decl	VAR_COUNT
+	lea	4(rp), rp
+	lea	-4(up), up
+	jz	L(end)
+	push	%eax			FRAME_pushl()
+
+	ALIGN(8)
+L(top):	shl	%cl, %ebp
+	or	%ebp, %edx
+	shl	%cl, %ebx
+	neg	cnt
+	mov	-4(up), %eax
+	mov	%eax, %ebp
+	mov	%edx, -4(rp)
+	shr	%cl, %eax
+	lea	-8(rp), rp
+L(lo1):	mov	-8(up), %edx
+	or	%ebx, %eax
+	mov	%edx, %ebx
+	shr	%cl, %edx
+	lea	-8(up), up
+	neg	cnt
+	mov	%eax, (rp)
+	decl	VAR_COUNT
+	jg	L(top)
+
+	pop	%eax			FRAME_popl()
+L(end):
+	shl	%cl, %ebp
+	shl	%cl, %ebx
+	or	%ebp, %edx
+	mov	SAVE_EBP, %ebp
+	mov	%edx, -4(rp)
+	mov	%ebx, -8(rp)
+
+L(quit):
+	mov	SAVE_UP, up
+	mov	SAVE_EBX, %ebx
+	pop	rp			FRAME_popl()
+	ret
+
+L(special):
+deflit(`FRAME',4)
+	lea	3(%edx), %eax		C size + 3
+	dec	%edx			C size - 1
+	mov	(up), %ecx
+	shr	$2, %eax		C (size + 3) / 4
+	and	$3, %edx		C (size - 1) % 4
+	jz	L(goloop)		C jmp if  size == 1 (mod 4)
+	shr	%edx
+	jnc	L(odd)			C jum if  size == 3 (mod 4)
+
+	add	%ecx, %ecx
+	lea	4(up), up
+	mov	%ecx, (rp)
+	mov	(up), %ecx
+	lea	4(rp), rp
+
+	dec	%edx
+	jnz	L(goloop)		C jump if  size == 0 (mod 4)
+L(odd):	lea	-8(up), up
+	lea	-8(rp), rp
+	jmp	L(sentry)		C reached if size == 2 or 3 (mod 4)
+
+L(sloop):
+	adc	%ecx, %ecx
+	mov	4(up), %edx
+	mov	%ecx, (rp)
+	adc	%edx, %edx
+	mov	8(up), %ecx
+	mov	%edx, 4(rp)
+L(sentry):
+	adc	%ecx, %ecx
+	mov	12(up), %edx
+	mov	%ecx, 8(rp)
+	adc	%edx, %edx
+	lea	16(up), up
+	mov	%edx, 12(rp)
+	lea	16(rp), rp
+	mov	(up), %ecx
+L(goloop):
+	decl	%eax
+	jnz	L(sloop)
+
+L(squit):
+	adc	%ecx, %ecx
+	mov	%ecx, (rp)
+	adc	%eax, %eax
+
+	mov	SAVE_UP, up
+	pop	rp			FRAME_popl()
+	ret
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86/atom/lshiftc.asm b/third_party/gmp/mpn/x86/atom/lshiftc.asm
new file mode 100644
index 0000000..5be53ed
--- /dev/null
+++ b/third_party/gmp/mpn/x86/atom/lshiftc.asm
@@ -0,0 +1,159 @@
+dnl  Intel Atom mpn_lshiftc -- mpn left shift with complement.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund and Marco Bodrato.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C mp_limb_t mpn_lshiftc (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C			 unsigned cnt);
+
+C				cycles/limb
+C P5
+C P6 model 0-8,10-12
+C P6 model 9  (Banias)
+C P6 model 13 (Dothan)
+C P4 model 0  (Willamette)
+C P4 model 1  (?)
+C P4 model 2  (Northwood)
+C P4 model 3  (Prescott)
+C P4 model 4  (Nocona)
+C Intel Atom			 5.5
+C AMD K6
+C AMD K7
+C AMD K8
+C AMD K10
+
+defframe(PARAM_CNT, 16)
+defframe(PARAM_SIZE,12)
+defframe(PARAM_SRC,  8)
+defframe(PARAM_DST,  4)
+
+dnl  re-use parameter space
+define(SAVE_UP,`PARAM_CNT')
+define(VAR_COUNT,`PARAM_SIZE')
+define(SAVE_EBX,`PARAM_SRC')
+define(SAVE_EBP,`PARAM_DST')
+
+define(`rp',  `%edi')
+define(`up',  `%esi')
+define(`cnt',  `%ecx')
+
+ASM_START()
+	TEXT
+
+PROLOGUE(mpn_lshiftc)
+deflit(`FRAME',0)
+	mov	PARAM_CNT, cnt
+	mov	PARAM_SIZE, %edx
+	mov	up, SAVE_UP
+	mov	PARAM_SRC, up
+	push	rp			FRAME_pushl()
+	mov	PARAM_DST, rp
+
+	lea	-4(up,%edx,4), up
+	mov	%ebx, SAVE_EBX
+	lea	-4(rp,%edx,4), rp
+
+	shr	%edx
+	mov	(up), %eax
+	mov	%edx, VAR_COUNT
+	jnc	L(evn)
+
+	mov	%eax, %ebx
+	shl	%cl, %ebx
+	neg	cnt
+	shr	%cl, %eax
+	test	%edx, %edx
+	jnz	L(gt1)
+	not	%ebx
+	mov	%ebx, (rp)
+	jmp	L(quit)
+
+L(gt1):	mov	%ebp, SAVE_EBP
+	push	%eax
+	mov	-4(up), %eax
+	mov	%eax, %ebp
+	shr	%cl, %eax
+	jmp	L(lo1)
+
+L(evn):	mov	%ebp, SAVE_EBP
+	neg	cnt
+	mov	%eax, %ebp
+	mov	-4(up), %edx
+	shr	%cl, %eax
+	mov	%edx, %ebx
+	shr	%cl, %edx
+	neg	cnt
+	decl	VAR_COUNT
+	lea	4(rp), rp
+	lea	-4(up), up
+	jz	L(end)
+	push	%eax			FRAME_pushl()
+
+L(top):	shl	%cl, %ebp
+	or	%ebp, %edx
+	shl	%cl, %ebx
+	neg	cnt
+	not	%edx
+	mov	-4(up), %eax
+	mov	%eax, %ebp
+	mov	%edx, -4(rp)
+	shr	%cl, %eax
+	lea	-8(rp), rp
+L(lo1):	mov	-8(up), %edx
+	or	%ebx, %eax
+	mov	%edx, %ebx
+	shr	%cl, %edx
+	not	%eax
+	lea	-8(up), up
+	neg	cnt
+	mov	%eax, (rp)
+	decl	VAR_COUNT
+	jg	L(top)
+
+	pop	%eax			FRAME_popl()
+L(end):
+	shl	%cl, %ebp
+	shl	%cl, %ebx
+	or	%ebp, %edx
+	mov	SAVE_EBP, %ebp
+	not	%edx
+	not	%ebx
+	mov	%edx, -4(rp)
+	mov	%ebx, -8(rp)
+
+L(quit):
+	mov	SAVE_UP, up
+	mov	SAVE_EBX, %ebx
+	pop	rp			FRAME_popl()
+	ret
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86/atom/mmx/copyd.asm b/third_party/gmp/mpn/x86/atom/mmx/copyd.asm
new file mode 100644
index 0000000..b80fb03
--- /dev/null
+++ b/third_party/gmp/mpn/x86/atom/mmx/copyd.asm
@@ -0,0 +1,34 @@
+dnl  Intel Atom mpn_copyd -- copy limb vector, decrementing.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+MULFUNC_PROLOGUE(mpn_copyd)
+include_mpn(`x86/k7/mmx/copyd.asm')
diff --git a/third_party/gmp/mpn/x86/atom/mmx/copyi.asm b/third_party/gmp/mpn/x86/atom/mmx/copyi.asm
new file mode 100644
index 0000000..49b6b8d
--- /dev/null
+++ b/third_party/gmp/mpn/x86/atom/mmx/copyi.asm
@@ -0,0 +1,34 @@
+dnl  Intel Atom mpn_copyi -- copy limb vector, incrementing.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+MULFUNC_PROLOGUE(mpn_copyi)
+include_mpn(`x86/k7/mmx/copyi.asm')
diff --git a/third_party/gmp/mpn/x86/atom/mmx/hamdist.asm b/third_party/gmp/mpn/x86/atom/mmx/hamdist.asm
new file mode 100644
index 0000000..3fe8253
--- /dev/null
+++ b/third_party/gmp/mpn/x86/atom/mmx/hamdist.asm
@@ -0,0 +1,34 @@
+dnl  Intel Atom mpn_hamdist -- hamming distance.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+MULFUNC_PROLOGUE(mpn_hamdist)
+include_mpn(`x86/k7/mmx/popham.asm')
diff --git a/third_party/gmp/mpn/x86/atom/mod_34lsub1.asm b/third_party/gmp/mpn/x86/atom/mod_34lsub1.asm
new file mode 100644
index 0000000..6d57ba3
--- /dev/null
+++ b/third_party/gmp/mpn/x86/atom/mod_34lsub1.asm
@@ -0,0 +1,34 @@
+dnl  Intel Atom mpn_mod_34lsub1 -- remainder modulo 2^24-1.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+MULFUNC_PROLOGUE(mpn_mod_34lsub1)
+include_mpn(`x86/p6/mod_34lsub1.asm')
diff --git a/third_party/gmp/mpn/x86/atom/mode1o.asm b/third_party/gmp/mpn/x86/atom/mode1o.asm
new file mode 100644
index 0000000..c9ee6bd
--- /dev/null
+++ b/third_party/gmp/mpn/x86/atom/mode1o.asm
@@ -0,0 +1,34 @@
+dnl  Intel Atom mpn_modexact_1_odd -- exact division style remainder.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+MULFUNC_PROLOGUE(mpn_modexact_1_odd mpn_modexact_1c_odd)
+include_mpn(`x86/pentium/mode1o.asm')
diff --git a/third_party/gmp/mpn/x86/atom/rshift.asm b/third_party/gmp/mpn/x86/atom/rshift.asm
new file mode 100644
index 0000000..1cb5dbe
--- /dev/null
+++ b/third_party/gmp/mpn/x86/atom/rshift.asm
@@ -0,0 +1,152 @@
+dnl  Intel Atom mpn_rshift -- mpn right shift.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  Converted from AMD64 by Marco Bodrato.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C mp_limb_t mpn_rshift (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C			unsigned cnt);
+
+C				cycles/limb
+C P5
+C P6 model 0-8,10-12
+C P6 model 9  (Banias)
+C P6 model 13 (Dothan)
+C P4 model 0  (Willamette)
+C P4 model 1  (?)
+C P4 model 2  (Northwood)
+C P4 model 3  (Prescott)
+C P4 model 4  (Nocona)
+C Intel Atom			 5
+C AMD K6
+C AMD K7
+C AMD K8
+C AMD K10
+
+defframe(PARAM_CNT, 16)
+defframe(PARAM_SIZE,12)
+defframe(PARAM_SRC,  8)
+defframe(PARAM_DST,  4)
+
+dnl  re-use parameter space
+define(SAVE_UP,`PARAM_CNT')
+define(VAR_COUNT,`PARAM_SIZE')
+define(SAVE_EBX,`PARAM_SRC')
+define(SAVE_EBP,`PARAM_DST')
+
+define(`rp',  `%edi')
+define(`up',  `%esi')
+define(`cnt',  `%ecx')
+
+ASM_START()
+	TEXT
+	ALIGN(8)
+deflit(`FRAME',0)
+PROLOGUE(mpn_rshift)
+	mov	PARAM_CNT, cnt
+	mov	PARAM_SIZE, %edx
+	mov	up, SAVE_UP
+	mov	PARAM_SRC, up
+	push	rp			FRAME_pushl()
+	mov	PARAM_DST, rp
+	mov	%ebx, SAVE_EBX
+
+	shr	%edx
+	mov	(up), %eax
+	mov	%edx, VAR_COUNT
+	jnc	L(evn)
+
+	mov	%eax, %ebx
+	shr	%cl, %ebx
+	neg	cnt
+	shl	%cl, %eax
+	test	%edx, %edx
+	jnz	L(gt1)
+	mov	%ebx, (rp)
+	jmp	L(quit)
+
+L(gt1):	mov	%ebp, SAVE_EBP
+	push	%eax
+	mov	4(up), %eax
+	mov	%eax, %ebp
+	shl	%cl, %eax
+	jmp	L(lo1)
+
+L(evn):	mov	%ebp, SAVE_EBP
+	neg	cnt
+	mov	%eax, %ebp
+	mov	4(up), %edx
+	shl	%cl, %eax
+	mov	%edx, %ebx
+	shl	%cl, %edx
+	neg	cnt
+	decl	VAR_COUNT
+	lea	-4(rp), rp
+	lea	4(up), up
+	jz	L(end)
+	push	%eax			FRAME_pushl()
+
+	ALIGN(8)
+L(top):	shr	%cl, %ebp
+	or	%ebp, %edx
+	shr	%cl, %ebx
+	neg	cnt
+	mov	4(up), %eax
+	mov	%eax, %ebp
+	mov	%edx, 4(rp)
+	shl	%cl, %eax
+	lea	8(rp), rp
+L(lo1):	mov	8(up), %edx
+	or	%ebx, %eax
+	mov	%edx, %ebx
+	shl	%cl, %edx
+	lea	8(up), up
+	neg	cnt
+	mov	%eax, (rp)
+	decl	VAR_COUNT
+	jg	L(top)
+
+	pop	%eax			FRAME_popl()
+L(end):
+	shr	%cl, %ebp
+	shr	%cl, %ebx
+	or	%ebp, %edx
+	mov	SAVE_EBP, %ebp
+	mov	%edx, 4(rp)
+	mov	%ebx, 8(rp)
+
+L(quit):
+	mov	SAVE_UP, up
+	mov	SAVE_EBX, %ebx
+	pop	rp			FRAME_popl()
+	ret
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86/atom/sse2/aorsmul_1.asm b/third_party/gmp/mpn/x86/atom/sse2/aorsmul_1.asm
new file mode 100644
index 0000000..969a14a
--- /dev/null
+++ b/third_party/gmp/mpn/x86/atom/sse2/aorsmul_1.asm
@@ -0,0 +1,174 @@
+dnl x86-32 mpn_addmul_1 and mpn_submul_1 optimised for Intel Atom.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund and Marco Bodrato.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C			    cycles/limb
+C			    cycles/limb
+C P5				 -
+C P6 model 0-8,10-12		 -
+C P6 model 9  (Banias)
+C P6 model 13 (Dothan)
+C P4 model 0  (Willamette)
+C P4 model 1  (?)
+C P4 model 2  (Northwood)
+C P4 model 3  (Prescott)
+C P4 model 4  (Nocona)
+C Intel Atom			 8
+C AMD K6
+C AMD K7			 -
+C AMD K8
+C AMD K10
+
+define(`rp', `%edi')
+define(`up', `%esi')
+define(`n',  `%ecx')
+
+ifdef(`OPERATION_addmul_1',`
+	define(ADDSUB,  add)
+	define(func_1,  mpn_addmul_1)
+	define(func_1c, mpn_addmul_1c)')
+ifdef(`OPERATION_submul_1',`
+	define(ADDSUB,  sub)
+	define(func_1,  mpn_submul_1)
+	define(func_1c, mpn_submul_1c)')
+
+MULFUNC_PROLOGUE(mpn_addmul_1 mpn_addmul_1c mpn_submul_1 mpn_submul_1c)
+
+	TEXT
+	ALIGN(16)
+PROLOGUE(func_1)
+	xor	%edx, %edx
+L(ent):	push	%edi
+	push	%esi
+	push	%ebx
+	mov	16(%esp), rp
+	mov	20(%esp), up
+	mov	24(%esp), n
+	movd	28(%esp), %mm7
+	test	$1, n
+	jz	L(fi0or2)
+	movd	(up), %mm0
+	pmuludq	%mm7, %mm0
+	shr	$2, n
+	jnc	L(fi1)
+
+L(fi3):	lea	-8(up), up
+	lea	-8(rp), rp
+	movd	12(up), %mm1
+	movd	%mm0, %ebx
+	pmuludq	%mm7, %mm1
+	add	$1, n			C increment and clear carry
+	jmp	L(lo3)
+
+L(fi1):	movd	%mm0, %ebx
+	jz	L(wd1)
+	movd	4(up), %mm1
+	pmuludq	%mm7, %mm1
+	jmp	L(lo1)
+
+L(fi0or2):
+	movd	(up), %mm1
+	pmuludq	%mm7, %mm1
+	shr	$2, n
+	movd	4(up), %mm0
+	jc	L(fi2)
+	lea	-4(up), up
+	lea	-4(rp), rp
+	movd	%mm1, %eax
+	pmuludq	%mm7, %mm0
+	jmp	L(lo0)
+
+L(fi2):	lea	4(up), up
+	add	$1, n			C increment and clear carry
+	movd	%mm1, %eax
+	lea	-12(rp), rp
+	jmp	L(lo2)
+
+C	ALIGN(16)			C alignment seems irrelevant
+L(top):	movd	4(up), %mm1
+	adc	$0, %edx
+	ADDSUB	%eax, 12(rp)
+	movd	%mm0, %ebx
+	pmuludq	%mm7, %mm1
+	lea	16(rp), rp
+L(lo1):	psrlq	$32, %mm0
+	adc	%edx, %ebx
+	movd	%mm0, %edx
+	movd	%mm1, %eax
+	movd	8(up), %mm0
+	pmuludq	%mm7, %mm0
+	adc	$0, %edx
+	ADDSUB	%ebx, (rp)
+L(lo0):	psrlq	$32, %mm1
+	adc	%edx, %eax
+	movd	%mm1, %edx
+	movd	%mm0, %ebx
+	movd	12(up), %mm1
+	pmuludq	%mm7, %mm1
+	adc	$0, %edx
+	ADDSUB	%eax, 4(rp)
+L(lo3):	psrlq	$32, %mm0
+	adc	%edx, %ebx
+	movd	%mm0, %edx
+	movd	%mm1, %eax
+	lea	16(up), up
+	movd	(up), %mm0
+	adc	$0, %edx
+	ADDSUB	%ebx, 8(rp)
+L(lo2):	psrlq	$32, %mm1
+	adc	%edx, %eax
+	movd	%mm1, %edx
+	pmuludq	%mm7, %mm0
+	dec	n
+	jnz	L(top)
+
+L(end):	adc	n, %edx			C n is zero here
+	ADDSUB	%eax, 12(rp)
+	movd	%mm0, %ebx
+	lea	16(rp), rp
+L(wd1):	psrlq	$32, %mm0
+	adc	%edx, %ebx
+	movd	%mm0, %eax
+	adc	n, %eax
+	ADDSUB	%ebx, (rp)
+	emms
+	adc	n, %eax
+	pop	%ebx
+	pop	%esi
+	pop	%edi
+	ret
+EPILOGUE()
+PROLOGUE(func_1c)
+	mov	20(%esp), %edx		C carry
+	jmp	L(ent)
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/atom/sse2/bdiv_dbm1c.asm b/third_party/gmp/mpn/x86/atom/sse2/bdiv_dbm1c.asm
new file mode 100644
index 0000000..782e914
--- /dev/null
+++ b/third_party/gmp/mpn/x86/atom/sse2/bdiv_dbm1c.asm
@@ -0,0 +1,34 @@
+dnl  Intel Atom  mpn_bdiv_dbm1.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+MULFUNC_PROLOGUE(mpn_bdiv_dbm1c)
+include_mpn(`x86/pentium4/sse2/bdiv_dbm1c.asm')
diff --git a/third_party/gmp/mpn/x86/atom/sse2/divrem_1.asm b/third_party/gmp/mpn/x86/atom/sse2/divrem_1.asm
new file mode 100644
index 0000000..f84709a
--- /dev/null
+++ b/third_party/gmp/mpn/x86/atom/sse2/divrem_1.asm
@@ -0,0 +1,34 @@
+dnl  Intel Atom mpn_divrem_1 -- mpn by limb division.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+MULFUNC_PROLOGUE(mpn_preinv_divrem_1 mpn_divrem_1c mpn_divrem_1)
+include_mpn(`x86/pentium4/sse2/divrem_1.asm')
diff --git a/third_party/gmp/mpn/x86/atom/sse2/mod_1_1.asm b/third_party/gmp/mpn/x86/atom/sse2/mod_1_1.asm
new file mode 100644
index 0000000..ae6581d
--- /dev/null
+++ b/third_party/gmp/mpn/x86/atom/sse2/mod_1_1.asm
@@ -0,0 +1,34 @@
+dnl  Intel Atom/SSE2 mpn_mod_1_1.
+
+dnl  Copyright 2009, 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+MULFUNC_PROLOGUE(mpn_mod_1_1p)
+include_mpn(`x86/pentium4/sse2/mod_1_1.asm')
diff --git a/third_party/gmp/mpn/x86/atom/sse2/mod_1_4.asm b/third_party/gmp/mpn/x86/atom/sse2/mod_1_4.asm
new file mode 100644
index 0000000..31faa3f
--- /dev/null
+++ b/third_party/gmp/mpn/x86/atom/sse2/mod_1_4.asm
@@ -0,0 +1,34 @@
+dnl  Intel Atom/SSE2 mpn_mod_1_4.
+
+dnl  Copyright 2009, 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+MULFUNC_PROLOGUE(mpn_mod_1s_4p)
+include_mpn(`x86/pentium4/sse2/mod_1_4.asm')
diff --git a/third_party/gmp/mpn/x86/atom/sse2/mul_1.asm b/third_party/gmp/mpn/x86/atom/sse2/mul_1.asm
new file mode 100644
index 0000000..aa3bb97
--- /dev/null
+++ b/third_party/gmp/mpn/x86/atom/sse2/mul_1.asm
@@ -0,0 +1,124 @@
+dnl  Intel Atom mpn_mul_1.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund and Marco Bodrato.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C			    cycles/limb
+C			    cycles/limb
+C P5				 -
+C P6 model 0-8,10-12		 -
+C P6 model 9  (Banias)
+C P6 model 13 (Dothan)
+C P4 model 0  (Willamette)
+C P4 model 1  (?)
+C P4 model 2  (Northwood)
+C P4 model 3  (Prescott)
+C P4 model 4  (Nocona)
+C Intel Atom			 7.5
+C AMD K6			 -
+C AMD K7			 -
+C AMD K8
+C AMD K10
+
+defframe(PARAM_CARRY,20)
+defframe(PARAM_MUL,  16)
+defframe(PARAM_SIZE, 12)
+defframe(PARAM_SRC,  8)
+defframe(PARAM_DST,  4)
+
+define(`rp', `%edx')
+define(`up', `%esi')
+define(`n',  `%ecx')
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+deflit(`FRAME',0)
+
+PROLOGUE(mpn_mul_1c)
+	movd	PARAM_CARRY, %mm6	C carry
+	jmp	L(ent)
+EPILOGUE()
+
+	ALIGN(8)			C for compact code
+PROLOGUE(mpn_mul_1)
+	pxor	%mm6, %mm6
+L(ent):	push	%esi			FRAME_pushl()
+	mov	PARAM_SRC, up
+	mov	PARAM_SIZE, %eax	C size
+	movd	PARAM_MUL, %mm7
+	movd	(up), %mm0
+	mov	%eax, n
+	and	$3, %eax
+	pmuludq	%mm7, %mm0
+	mov	PARAM_DST, rp
+	jz	L(lo0)
+	cmp	$2, %eax
+	lea	-16(up,%eax,4),up
+	lea	-16(rp,%eax,4),rp
+	jc	L(lo1)
+	jz	L(lo2)
+	jmp	L(lo3)
+
+	ALIGN(16)
+L(top):	movd	(up), %mm0
+	pmuludq	%mm7, %mm0
+	psrlq	$32, %mm6
+	lea	16(rp), rp
+L(lo0):	paddq	%mm0, %mm6
+	movd	4(up), %mm0
+	pmuludq	%mm7, %mm0
+	movd	%mm6, (rp)
+	psrlq	$32, %mm6
+L(lo3):	paddq	%mm0, %mm6
+	movd	8(up), %mm0
+	pmuludq	%mm7, %mm0
+	movd	%mm6, 4(rp)
+	psrlq	$32, %mm6
+L(lo2):	paddq	%mm0, %mm6
+	movd	12(up), %mm0
+	pmuludq	%mm7, %mm0
+	movd	%mm6, 8(rp)
+	psrlq	$32, %mm6
+L(lo1):	paddq	%mm0, %mm6
+	sub	$4, n
+	movd	%mm6, 12(rp)
+	lea	16(up), up
+	ja	L(top)
+
+	psrlq	$32, %mm6
+	movd	%mm6, %eax
+	emms
+	pop	%esi			FRAME_popl()
+	ret
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86/atom/sse2/mul_basecase.asm b/third_party/gmp/mpn/x86/atom/sse2/mul_basecase.asm
new file mode 100644
index 0000000..97d3aeb
--- /dev/null
+++ b/third_party/gmp/mpn/x86/atom/sse2/mul_basecase.asm
@@ -0,0 +1,501 @@
+dnl  x86 mpn_mul_basecase -- Multiply two limb vectors and store the result in
+dnl  a third limb vector.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund and Marco Bodrato.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C TODO
+C  * Check if 'jmp N(%esp)' is well-predicted enough to allow us to combine the
+C    4 large loops into one; we could use it for the outer loop branch.
+C  * Optimise code outside of inner loops.
+C  * Write combined addmul_1 feed-in a wind-down code, and use when iterating
+C    outer each loop.  ("Overlapping software pipelining")
+C  * Postpone push of ebx until we know vn > 1.  Perhaps use caller-saves regs
+C    for inlined mul_1, allowing us to postpone all pushes.
+C  * Perhaps write special code for vn <= un < M, for some small M.
+
+C void mpn_mul_basecase (mp_ptr wp,
+C                        mp_srcptr xp, mp_size_t xn,
+C                        mp_srcptr yp, mp_size_t yn);
+C
+
+define(`rp',  `%edi')
+define(`up',  `%esi')
+define(`un',  `%ecx')
+define(`vp',  `%ebp')
+define(`vn',  `36(%esp)')
+
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_mul_basecase)
+	push	%edi
+	push	%esi
+	push	%ebx
+	push	%ebp
+	mov	20(%esp), rp
+	mov	24(%esp), up
+	mov	28(%esp), un
+	mov	32(%esp), vp
+
+	movd	(up), %mm0
+	movd	(vp), %mm7
+	pmuludq	%mm7, %mm0
+	pxor	%mm6, %mm6
+
+	mov	un, %eax
+	and	$3, %eax
+	jz	L(of0)
+	cmp	$2, %eax
+	jc	L(of1)
+	jz	L(of2)
+
+C ================================================================
+	jmp	L(m3)
+	ALIGN(16)
+L(lm3):	movd	-4(up), %mm0
+	pmuludq	%mm7, %mm0
+	psrlq	$32, %mm6
+	lea	16(rp), rp
+	paddq	%mm0, %mm6
+	movd	(up), %mm0
+	pmuludq	%mm7, %mm0
+	movd	%mm6, -4(rp)
+	psrlq	$32, %mm6
+L(m3):	paddq	%mm0, %mm6
+	movd	4(up), %mm0
+	pmuludq	%mm7, %mm0
+	movd	%mm6, (rp)
+	psrlq	$32, %mm6
+	paddq	%mm0, %mm6
+	movd	8(up), %mm0
+	pmuludq	%mm7, %mm0
+	movd	%mm6, 4(rp)
+	psrlq	$32, %mm6
+	paddq	%mm0, %mm6
+	sub	$4, un
+	movd	%mm6, 8(rp)
+	lea	16(up), up
+	ja	L(lm3)
+
+	psrlq	$32, %mm6
+	movd	%mm6, 12(rp)
+
+	decl	vn
+	jz	L(done)
+	lea	-8(rp), rp
+
+L(ol3):	mov	28(%esp), un
+	neg	un
+	lea	4(vp), vp
+	movd	(vp), %mm7	C read next V limb
+	mov	24(%esp), up
+	lea	16(rp,un,4), rp
+
+	movd	(up), %mm0
+	pmuludq	%mm7, %mm0
+	sar	$2, un
+	movd	4(up), %mm1
+	movd	%mm0, %ebx
+	pmuludq	%mm7, %mm1
+	lea	-8(up), up
+	xor	%edx, %edx	C zero edx and CF
+	jmp	L(a3)
+
+L(la3):	movd	4(up), %mm1
+	adc	$0, %edx
+	add	%eax, 12(rp)
+	movd	%mm0, %ebx
+	pmuludq	%mm7, %mm1
+	lea	16(rp), rp
+	psrlq	$32, %mm0
+	adc	%edx, %ebx
+	movd	%mm0, %edx
+	movd	%mm1, %eax
+	movd	8(up), %mm0
+	pmuludq	%mm7, %mm0
+	adc	$0, %edx
+	add	%ebx, (rp)
+	psrlq	$32, %mm1
+	adc	%edx, %eax
+	movd	%mm1, %edx
+	movd	%mm0, %ebx
+	movd	12(up), %mm1
+	pmuludq	%mm7, %mm1
+	adc	$0, %edx
+	add	%eax, 4(rp)
+L(a3):	psrlq	$32, %mm0
+	adc	%edx, %ebx
+	movd	%mm0, %edx
+	movd	%mm1, %eax
+	lea	16(up), up
+	movd	(up), %mm0
+	adc	$0, %edx
+	add	%ebx, 8(rp)
+	psrlq	$32, %mm1
+	adc	%edx, %eax
+	movd	%mm1, %edx
+	pmuludq	%mm7, %mm0
+	inc	un
+	jnz	L(la3)
+
+	adc	un, %edx	C un is zero here
+	add	%eax, 12(rp)
+	movd	%mm0, %ebx
+	psrlq	$32, %mm0
+	adc	%edx, %ebx
+	movd	%mm0, %eax
+	adc	un, %eax
+	add	%ebx, 16(rp)
+	adc	un, %eax
+	mov	%eax, 20(rp)
+
+	decl	vn
+	jnz	L(ol3)
+	jmp	L(done)
+
+C ================================================================
+	ALIGN(16)
+L(lm0):	movd	(up), %mm0
+	pmuludq	%mm7, %mm0
+	psrlq	$32, %mm6
+	lea	16(rp), rp
+L(of0):	paddq	%mm0, %mm6
+	movd	4(up), %mm0
+	pmuludq	%mm7, %mm0
+	movd	%mm6, (rp)
+	psrlq	$32, %mm6
+	paddq	%mm0, %mm6
+	movd	8(up), %mm0
+	pmuludq	%mm7, %mm0
+	movd	%mm6, 4(rp)
+	psrlq	$32, %mm6
+	paddq	%mm0, %mm6
+	movd	12(up), %mm0
+	pmuludq	%mm7, %mm0
+	movd	%mm6, 8(rp)
+	psrlq	$32, %mm6
+	paddq	%mm0, %mm6
+	sub	$4, un
+	movd	%mm6, 12(rp)
+	lea	16(up), up
+	ja	L(lm0)
+
+	psrlq	$32, %mm6
+	movd	%mm6, 16(rp)
+
+	decl	vn
+	jz	L(done)
+	lea	-4(rp), rp
+
+L(ol0):	mov	28(%esp), un
+	neg	un
+	lea	4(vp), vp
+	movd	(vp), %mm7	C read next V limb
+	mov	24(%esp), up
+	lea	20(rp,un,4), rp
+
+	movd	(up), %mm1
+	pmuludq	%mm7, %mm1
+	sar	$2, un
+	movd	4(up), %mm0
+	lea	-4(up), up
+	movd	%mm1, %eax
+	pmuludq	%mm7, %mm0
+	xor	%edx, %edx	C zero edx and CF
+	jmp	L(a0)
+
+L(la0):	movd	4(up), %mm1
+	adc	$0, %edx
+	add	%eax, 12(rp)
+	movd	%mm0, %ebx
+	pmuludq	%mm7, %mm1
+	lea	16(rp), rp
+	psrlq	$32, %mm0
+	adc	%edx, %ebx
+	movd	%mm0, %edx
+	movd	%mm1, %eax
+	movd	8(up), %mm0
+	pmuludq	%mm7, %mm0
+	adc	$0, %edx
+	add	%ebx, (rp)
+L(a0):	psrlq	$32, %mm1
+	adc	%edx, %eax
+	movd	%mm1, %edx
+	movd	%mm0, %ebx
+	movd	12(up), %mm1
+	pmuludq	%mm7, %mm1
+	adc	$0, %edx
+	add	%eax, 4(rp)
+	psrlq	$32, %mm0
+	adc	%edx, %ebx
+	movd	%mm0, %edx
+	movd	%mm1, %eax
+	lea	16(up), up
+	movd	(up), %mm0
+	adc	$0, %edx
+	add	%ebx, 8(rp)
+	psrlq	$32, %mm1
+	adc	%edx, %eax
+	movd	%mm1, %edx
+	pmuludq	%mm7, %mm0
+	inc	un
+	jnz	L(la0)
+
+	adc	un, %edx	C un is zero here
+	add	%eax, 12(rp)
+	movd	%mm0, %ebx
+	psrlq	$32, %mm0
+	adc	%edx, %ebx
+	movd	%mm0, %eax
+	adc	un, %eax
+	add	%ebx, 16(rp)
+	adc	un, %eax
+	mov	%eax, 20(rp)
+
+	decl	vn
+	jnz	L(ol0)
+	jmp	L(done)
+
+C ================================================================
+	ALIGN(16)
+L(lm1):	movd	-12(up), %mm0
+	pmuludq	%mm7, %mm0
+	psrlq	$32, %mm6
+	lea	16(rp), rp
+	paddq	%mm0, %mm6
+	movd	-8(up), %mm0
+	pmuludq	%mm7, %mm0
+	movd	%mm6, -12(rp)
+	psrlq	$32, %mm6
+	paddq	%mm0, %mm6
+	movd	-4(up), %mm0
+	pmuludq	%mm7, %mm0
+	movd	%mm6, -8(rp)
+	psrlq	$32, %mm6
+	paddq	%mm0, %mm6
+	movd	(up), %mm0
+	pmuludq	%mm7, %mm0
+	movd	%mm6, -4(rp)
+	psrlq	$32, %mm6
+L(of1):	paddq	%mm0, %mm6
+	sub	$4, un
+	movd	%mm6, (rp)
+	lea	16(up), up
+	ja	L(lm1)
+
+	psrlq	$32, %mm6
+	movd	%mm6, 4(rp)
+
+	decl	vn
+	jz	L(done)
+	lea	-16(rp), rp
+
+L(ol1):	mov	28(%esp), un
+	neg	un
+	lea	4(vp), vp
+	movd	(vp), %mm7	C read next V limb
+	mov	24(%esp), up
+	lea	24(rp,un,4), rp
+
+	movd	(up), %mm0
+	pmuludq	%mm7, %mm0
+	sar	$2, un
+	movd	%mm0, %ebx
+	movd	4(up), %mm1
+	pmuludq	%mm7, %mm1
+	xor	%edx, %edx	C zero edx and CF
+	inc	un
+	jmp	L(a1)
+
+L(la1):	movd	4(up), %mm1
+	adc	$0, %edx
+	add	%eax, 12(rp)
+	movd	%mm0, %ebx
+	pmuludq	%mm7, %mm1
+	lea	16(rp), rp
+L(a1):	psrlq	$32, %mm0
+	adc	%edx, %ebx
+	movd	%mm0, %edx
+	movd	%mm1, %eax
+	movd	8(up), %mm0
+	pmuludq	%mm7, %mm0
+	adc	$0, %edx
+	add	%ebx, (rp)
+	psrlq	$32, %mm1
+	adc	%edx, %eax
+	movd	%mm1, %edx
+	movd	%mm0, %ebx
+	movd	12(up), %mm1
+	pmuludq	%mm7, %mm1
+	adc	$0, %edx
+	add	%eax, 4(rp)
+	psrlq	$32, %mm0
+	adc	%edx, %ebx
+	movd	%mm0, %edx
+	movd	%mm1, %eax
+	lea	16(up), up
+	movd	(up), %mm0
+	adc	$0, %edx
+	add	%ebx, 8(rp)
+	psrlq	$32, %mm1
+	adc	%edx, %eax
+	movd	%mm1, %edx
+	pmuludq	%mm7, %mm0
+	inc	un
+	jnz	L(la1)
+
+	adc	un, %edx	C un is zero here
+	add	%eax, 12(rp)
+	movd	%mm0, %ebx
+	psrlq	$32, %mm0
+	adc	%edx, %ebx
+	movd	%mm0, %eax
+	adc	un, %eax
+	add	%ebx, 16(rp)
+	adc	un, %eax
+	mov	%eax, 20(rp)
+
+	decl	vn
+	jnz	L(ol1)
+	jmp	L(done)
+
+C ================================================================
+	ALIGN(16)
+L(lm2):	movd	-8(up), %mm0
+	pmuludq	%mm7, %mm0
+	psrlq	$32, %mm6
+	lea	16(rp), rp
+	paddq	%mm0, %mm6
+	movd	-4(up), %mm0
+	pmuludq	%mm7, %mm0
+	movd	%mm6, -8(rp)
+	psrlq	$32, %mm6
+	paddq	%mm0, %mm6
+	movd	(up), %mm0
+	pmuludq	%mm7, %mm0
+	movd	%mm6, -4(rp)
+	psrlq	$32, %mm6
+L(of2):	paddq	%mm0, %mm6
+	movd	4(up), %mm0
+	pmuludq	%mm7, %mm0
+	movd	%mm6, (rp)
+	psrlq	$32, %mm6
+	paddq	%mm0, %mm6
+	sub	$4, un
+	movd	%mm6, 4(rp)
+	lea	16(up), up
+	ja	L(lm2)
+
+	psrlq	$32, %mm6
+	movd	%mm6, 8(rp)
+
+	decl	vn
+	jz	L(done)
+	lea	-12(rp), rp
+
+L(ol2):	mov	28(%esp), un
+	neg	un
+	lea	4(vp), vp
+	movd	(vp), %mm7	C read next V limb
+	mov	24(%esp), up
+	lea	12(rp,un,4), rp
+
+	movd	(up), %mm1
+	pmuludq	%mm7, %mm1
+	sar	$2, un
+	movd	4(up), %mm0
+	lea	4(up), up
+	movd	%mm1, %eax
+	xor	%edx, %edx	C zero edx and CF
+	jmp	L(lo2)
+
+L(la2):	movd	4(up), %mm1
+	adc	$0, %edx
+	add	%eax, 12(rp)
+	movd	%mm0, %ebx
+	pmuludq	%mm7, %mm1
+	lea	16(rp), rp
+	psrlq	$32, %mm0
+	adc	%edx, %ebx
+	movd	%mm0, %edx
+	movd	%mm1, %eax
+	movd	8(up), %mm0
+	pmuludq	%mm7, %mm0
+	adc	$0, %edx
+	add	%ebx, (rp)
+	psrlq	$32, %mm1
+	adc	%edx, %eax
+	movd	%mm1, %edx
+	movd	%mm0, %ebx
+	movd	12(up), %mm1
+	pmuludq	%mm7, %mm1
+	adc	$0, %edx
+	add	%eax, 4(rp)
+	psrlq	$32, %mm0
+	adc	%edx, %ebx
+	movd	%mm0, %edx
+	movd	%mm1, %eax
+	lea	16(up), up
+	movd	(up), %mm0
+	adc	$0, %edx
+	add	%ebx, 8(rp)
+L(lo2):	psrlq	$32, %mm1
+	adc	%edx, %eax
+	movd	%mm1, %edx
+	pmuludq	%mm7, %mm0
+	inc	un
+	jnz	L(la2)
+
+	adc	un, %edx	C un is zero here
+	add	%eax, 12(rp)
+	movd	%mm0, %ebx
+	psrlq	$32, %mm0
+	adc	%edx, %ebx
+	movd	%mm0, %eax
+	adc	un, %eax
+	add	%ebx, 16(rp)
+	adc	un, %eax
+	mov	%eax, 20(rp)
+
+	decl	vn
+	jnz	L(ol2)
+C	jmp	L(done)
+
+C ================================================================
+L(done):
+	emms
+	pop	%ebp
+	pop	%ebx
+	pop	%esi
+	pop	%edi
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/atom/sse2/popcount.asm b/third_party/gmp/mpn/x86/atom/sse2/popcount.asm
new file mode 100644
index 0000000..7847aec
--- /dev/null
+++ b/third_party/gmp/mpn/x86/atom/sse2/popcount.asm
@@ -0,0 +1,35 @@
+dnl  Intel Atom mpn_popcount -- population count.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+MULFUNC_PROLOGUE(mpn_popcount)
+include_mpn(`x86/pentium4/sse2/popcount.asm')
diff --git a/third_party/gmp/mpn/x86/atom/sse2/sqr_basecase.asm b/third_party/gmp/mpn/x86/atom/sse2/sqr_basecase.asm
new file mode 100644
index 0000000..af19ed8
--- /dev/null
+++ b/third_party/gmp/mpn/x86/atom/sse2/sqr_basecase.asm
@@ -0,0 +1,634 @@
+dnl  x86 mpn_sqr_basecase -- square an mpn number, optimised for atom.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund and Marco Bodrato.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C TODO
+C  * Check if 'jmp N(%esp)' is well-predicted enough to allow us to combine the
+C    4 large loops into one; we could use it for the outer loop branch.
+C  * Optimise code outside of inner loops.
+C  * Write combined addmul_1 feed-in a wind-down code, and use when iterating
+C    outer each loop.  ("Overlapping software pipelining")
+C  * Perhaps use caller-saves regs for inlined mul_1, allowing us to postpone
+C    all pushes.
+C  * Perhaps write special code for n < M, for some small M.
+C  * Replace inlined addmul_1 with smaller code from aorsmul_1.asm, or perhaps
+C    with even less pipelined code.
+C  * We run the outer loop until we have a 2-limb by 1-limb addmul_1 left.
+C    Consider breaking out earlier, saving high the cost of short loops.
+
+C void mpn_sqr_basecase (mp_ptr wp,
+C                        mp_srcptr xp, mp_size_t xn);
+
+define(`rp',  `%edi')
+define(`up',  `%esi')
+define(`n',   `%ecx')
+
+define(`un',  `%ebp')
+
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_sqr_basecase)
+	push	%edi
+	push	%esi
+	mov	12(%esp), rp
+	mov	16(%esp), up
+	mov	20(%esp), n
+
+	lea	4(rp), rp	C write triangular product starting at rp[1]
+	dec	n
+	movd	(up), %mm7
+
+	jz	L(one)
+	lea	4(up), up
+	push	%ebx
+	push	%ebp
+	mov	n, %eax
+
+	movd	(up), %mm0
+	neg	n
+	pmuludq	%mm7, %mm0
+	pxor	%mm6, %mm6
+	mov	n, un
+
+	and	$3, %eax
+	jz	L(of0)
+	cmp	$2, %eax
+	jc	L(of1)
+	jz	L(of2)
+
+C ================================================================
+	jmp	L(m3)
+	ALIGN(16)
+L(lm3):	movd	-4(up), %mm0
+	pmuludq	%mm7, %mm0
+	psrlq	$32, %mm6
+	lea	16(rp), rp
+	paddq	%mm0, %mm6
+	movd	(up), %mm0
+	pmuludq	%mm7, %mm0
+	movd	%mm6, -4(rp)
+	psrlq	$32, %mm6
+L(m3):	paddq	%mm0, %mm6
+	movd	4(up), %mm0
+	pmuludq	%mm7, %mm0
+	movd	%mm6, (rp)
+	psrlq	$32, %mm6
+	paddq	%mm0, %mm6
+	movd	8(up), %mm0
+	pmuludq	%mm7, %mm0
+	movd	%mm6, 4(rp)
+	psrlq	$32, %mm6
+	paddq	%mm0, %mm6
+	add	$4, un
+	movd	%mm6, 8(rp)
+	lea	16(up), up
+	js	L(lm3)
+
+	psrlq	$32, %mm6
+	movd	%mm6, 12(rp)
+
+	inc	n
+C	jz	L(done)
+  lea	-12(up), up
+  lea	4(rp), rp
+	jmp	L(ol2)
+
+C ================================================================
+	ALIGN(16)
+L(lm0):	movd	(up), %mm0
+	pmuludq	%mm7, %mm0
+	psrlq	$32, %mm6
+	lea	16(rp), rp
+L(of0):	paddq	%mm0, %mm6
+	movd	4(up), %mm0
+	pmuludq	%mm7, %mm0
+	movd	%mm6, (rp)
+	psrlq	$32, %mm6
+	paddq	%mm0, %mm6
+	movd	8(up), %mm0
+	pmuludq	%mm7, %mm0
+	movd	%mm6, 4(rp)
+	psrlq	$32, %mm6
+	paddq	%mm0, %mm6
+	movd	12(up), %mm0
+	pmuludq	%mm7, %mm0
+	movd	%mm6, 8(rp)
+	psrlq	$32, %mm6
+	paddq	%mm0, %mm6
+	add	$4, un
+	movd	%mm6, 12(rp)
+	lea	16(up), up
+	js	L(lm0)
+
+	psrlq	$32, %mm6
+	movd	%mm6, 16(rp)
+
+	inc	n
+C	jz	L(done)
+  lea	-8(up), up
+  lea	8(rp), rp
+	jmp	L(ol3)
+
+C ================================================================
+	ALIGN(16)
+L(lm1):	movd	-12(up), %mm0
+	pmuludq	%mm7, %mm0
+	psrlq	$32, %mm6
+	lea	16(rp), rp
+	paddq	%mm0, %mm6
+	movd	-8(up), %mm0
+	pmuludq	%mm7, %mm0
+	movd	%mm6, -12(rp)
+	psrlq	$32, %mm6
+	paddq	%mm0, %mm6
+	movd	-4(up), %mm0
+	pmuludq	%mm7, %mm0
+	movd	%mm6, -8(rp)
+	psrlq	$32, %mm6
+	paddq	%mm0, %mm6
+	movd	(up), %mm0
+	pmuludq	%mm7, %mm0
+	movd	%mm6, -4(rp)
+	psrlq	$32, %mm6
+L(of1):	paddq	%mm0, %mm6
+	add	$4, un
+	movd	%mm6, (rp)
+	lea	16(up), up
+	js	L(lm1)
+
+	psrlq	$32, %mm6
+	movd	%mm6, 4(rp)
+
+	inc	n
+	jz	L(done)		C goes away when we add special n=2 code
+  lea	-20(up), up
+  lea	-4(rp), rp
+	jmp	L(ol0)
+
+C ================================================================
+	ALIGN(16)
+L(lm2):	movd	-8(up), %mm0
+	pmuludq	%mm7, %mm0
+	psrlq	$32, %mm6
+	lea	16(rp), rp
+	paddq	%mm0, %mm6
+	movd	-4(up), %mm0
+	pmuludq	%mm7, %mm0
+	movd	%mm6, -8(rp)
+	psrlq	$32, %mm6
+	paddq	%mm0, %mm6
+	movd	(up), %mm0
+	pmuludq	%mm7, %mm0
+	movd	%mm6, -4(rp)
+	psrlq	$32, %mm6
+L(of2):	paddq	%mm0, %mm6
+	movd	4(up), %mm0
+	pmuludq	%mm7, %mm0
+	movd	%mm6, (rp)
+	psrlq	$32, %mm6
+	paddq	%mm0, %mm6
+	add	$4, un
+	movd	%mm6, 4(rp)
+	lea	16(up), up
+	js	L(lm2)
+
+	psrlq	$32, %mm6
+	movd	%mm6, 8(rp)
+
+	inc	n
+C	jz	L(done)
+  lea	-16(up), up
+C  lea	(rp), rp
+C	jmp	L(ol1)
+
+C ================================================================
+
+L(ol1):	lea	4(up,n,4), up
+	movd	(up), %mm7	C read next U invariant limb
+	lea	8(rp,n,4), rp
+	mov	n, un
+
+	movd	4(up), %mm1
+	pmuludq	%mm7, %mm1
+	sar	$2, un
+	movd	%mm1, %ebx
+	inc	un
+	jz	L(re1)
+
+	movd	8(up), %mm0
+	pmuludq	%mm7, %mm0
+	xor	%edx, %edx	C zero edx and CF
+	jmp	L(a1)
+
+L(la1):	adc	$0, %edx
+	add	%ebx, 12(rp)
+	movd	%mm0, %eax
+	pmuludq	%mm7, %mm1
+	lea	16(rp), rp
+	psrlq	$32, %mm0
+	adc	%edx, %eax
+	movd	%mm0, %edx
+	movd	%mm1, %ebx
+	movd	8(up), %mm0
+	pmuludq	%mm7, %mm0
+	adc	$0, %edx
+	add	%eax, (rp)
+L(a1):	psrlq	$32, %mm1
+	adc	%edx, %ebx
+	movd	%mm1, %edx
+	movd	%mm0, %eax
+	movd	12(up), %mm1
+	pmuludq	%mm7, %mm1
+	adc	$0, %edx
+	add	%ebx, 4(rp)
+	psrlq	$32, %mm0
+	adc	%edx, %eax
+	movd	%mm0, %edx
+	movd	%mm1, %ebx
+	lea	16(up), up
+	movd	(up), %mm0
+	adc	$0, %edx
+	add	%eax, 8(rp)
+	psrlq	$32, %mm1
+	adc	%edx, %ebx
+	movd	%mm1, %edx
+	pmuludq	%mm7, %mm0
+	inc	un
+	movd	4(up), %mm1
+	jnz	L(la1)
+
+	adc	un, %edx	C un is zero here
+	add	%ebx, 12(rp)
+	movd	%mm0, %eax
+	pmuludq	%mm7, %mm1
+	lea	16(rp), rp
+	psrlq	$32, %mm0
+	adc	%edx, %eax
+	movd	%mm0, %edx
+	movd	%mm1, %ebx
+	adc	un, %edx
+	add	%eax, (rp)
+	psrlq	$32, %mm1
+	adc	%edx, %ebx
+	movd	%mm1, %eax
+	adc	un, %eax
+	add	%ebx, 4(rp)
+	adc	un, %eax
+	mov	%eax, 8(rp)
+
+	inc	n
+
+C ================================================================
+
+L(ol0):	lea	(up,n,4), up
+	movd	4(up), %mm7	C read next U invariant limb
+	lea	4(rp,n,4), rp
+	mov	n, un
+
+	movd	8(up), %mm0
+	pmuludq	%mm7, %mm0
+	sar	$2, un
+	movd	12(up), %mm1
+	movd	%mm0, %eax
+	pmuludq	%mm7, %mm1
+	xor	%edx, %edx	C zero edx and CF
+	jmp	L(a0)
+
+L(la0):	adc	$0, %edx
+	add	%ebx, 12(rp)
+	movd	%mm0, %eax
+	pmuludq	%mm7, %mm1
+	lea	16(rp), rp
+	psrlq	$32, %mm0
+	adc	%edx, %eax
+	movd	%mm0, %edx
+	movd	%mm1, %ebx
+	movd	8(up), %mm0
+	pmuludq	%mm7, %mm0
+	adc	$0, %edx
+	add	%eax, (rp)
+	psrlq	$32, %mm1
+	adc	%edx, %ebx
+	movd	%mm1, %edx
+	movd	%mm0, %eax
+	movd	12(up), %mm1
+	pmuludq	%mm7, %mm1
+	adc	$0, %edx
+	add	%ebx, 4(rp)
+L(a0):	psrlq	$32, %mm0
+	adc	%edx, %eax
+	movd	%mm0, %edx
+	movd	%mm1, %ebx
+	lea	16(up), up
+	movd	(up), %mm0
+	adc	$0, %edx
+	add	%eax, 8(rp)
+	psrlq	$32, %mm1
+	adc	%edx, %ebx
+	movd	%mm1, %edx
+	pmuludq	%mm7, %mm0
+	inc	un
+	movd	4(up), %mm1
+	jnz	L(la0)
+
+	adc	un, %edx	C un is zero here
+	add	%ebx, 12(rp)
+	movd	%mm0, %eax
+	pmuludq	%mm7, %mm1
+	lea	16(rp), rp
+	psrlq	$32, %mm0
+	adc	%edx, %eax
+	movd	%mm0, %edx
+	movd	%mm1, %ebx
+	adc	un, %edx
+	add	%eax, (rp)
+	psrlq	$32, %mm1
+	adc	%edx, %ebx
+	movd	%mm1, %eax
+	adc	un, %eax
+	add	%ebx, 4(rp)
+	adc	un, %eax
+	mov	%eax, 8(rp)
+
+	inc	n
+
+C ================================================================
+
+L(ol3):	lea	12(up,n,4), up
+	movd	-8(up), %mm7	C read next U invariant limb
+	lea	(rp,n,4), rp	C put rp back
+	mov	n, un
+
+	movd	-4(up), %mm1
+	pmuludq	%mm7, %mm1
+	sar	$2, un
+	movd	%mm1, %ebx
+	movd	(up), %mm0
+	xor	%edx, %edx	C zero edx and CF
+	jmp	L(a3)
+
+L(la3):	adc	$0, %edx
+	add	%ebx, 12(rp)
+	movd	%mm0, %eax
+	pmuludq	%mm7, %mm1
+	lea	16(rp), rp
+	psrlq	$32, %mm0
+	adc	%edx, %eax
+	movd	%mm0, %edx
+	movd	%mm1, %ebx
+	movd	8(up), %mm0
+	pmuludq	%mm7, %mm0
+	adc	$0, %edx
+	add	%eax, (rp)
+	psrlq	$32, %mm1
+	adc	%edx, %ebx
+	movd	%mm1, %edx
+	movd	%mm0, %eax
+	movd	12(up), %mm1
+	pmuludq	%mm7, %mm1
+	adc	$0, %edx
+	add	%ebx, 4(rp)
+	psrlq	$32, %mm0
+	adc	%edx, %eax
+	movd	%mm0, %edx
+	movd	%mm1, %ebx
+	lea	16(up), up
+	movd	(up), %mm0
+	adc	$0, %edx
+	add	%eax, 8(rp)
+L(a3):	psrlq	$32, %mm1
+	adc	%edx, %ebx
+	movd	%mm1, %edx
+	pmuludq	%mm7, %mm0
+	inc	un
+	movd	4(up), %mm1
+	jnz	L(la3)
+
+	adc	un, %edx	C un is zero here
+	add	%ebx, 12(rp)
+	movd	%mm0, %eax
+	pmuludq	%mm7, %mm1
+	lea	16(rp), rp
+	psrlq	$32, %mm0
+	adc	%edx, %eax
+	movd	%mm0, %edx
+	movd	%mm1, %ebx
+	adc	un, %edx
+	add	%eax, (rp)
+	psrlq	$32, %mm1
+	adc	%edx, %ebx
+	movd	%mm1, %eax
+	adc	un, %eax
+	add	%ebx, 4(rp)
+	adc	un, %eax
+	mov	%eax, 8(rp)
+
+	inc	n
+
+C ================================================================
+
+L(ol2):	lea	8(up,n,4), up
+	movd	-4(up), %mm7	C read next U invariant limb
+	lea	12(rp,n,4), rp
+	mov	n, un
+
+	movd	(up), %mm0
+	pmuludq	%mm7, %mm0
+	xor	%edx, %edx
+	sar	$2, un
+	movd	4(up), %mm1
+	test	un, un		C clear carry
+	movd	%mm0, %eax
+	pmuludq	%mm7, %mm1
+	inc	un
+	jnz	L(a2)
+	jmp	L(re2)
+
+L(la2):	adc	$0, %edx
+	add	%ebx, 12(rp)
+	movd	%mm0, %eax
+	pmuludq	%mm7, %mm1
+	lea	16(rp), rp
+L(a2):	psrlq	$32, %mm0
+	adc	%edx, %eax
+	movd	%mm0, %edx
+	movd	%mm1, %ebx
+	movd	8(up), %mm0
+	pmuludq	%mm7, %mm0
+	adc	$0, %edx
+	add	%eax, (rp)
+	psrlq	$32, %mm1
+	adc	%edx, %ebx
+	movd	%mm1, %edx
+	movd	%mm0, %eax
+	movd	12(up), %mm1
+	pmuludq	%mm7, %mm1
+	adc	$0, %edx
+	add	%ebx, 4(rp)
+	psrlq	$32, %mm0
+	adc	%edx, %eax
+	movd	%mm0, %edx
+	movd	%mm1, %ebx
+	lea	16(up), up
+	movd	(up), %mm0
+	adc	$0, %edx
+	add	%eax, 8(rp)
+	psrlq	$32, %mm1
+	adc	%edx, %ebx
+	movd	%mm1, %edx
+	pmuludq	%mm7, %mm0
+	inc	un
+	movd	4(up), %mm1
+	jnz	L(la2)
+
+	adc	un, %edx	C un is zero here
+	add	%ebx, 12(rp)
+	movd	%mm0, %eax
+	pmuludq	%mm7, %mm1
+	lea	16(rp), rp
+	psrlq	$32, %mm0
+	adc	%edx, %eax
+	movd	%mm0, %edx
+	movd	%mm1, %ebx
+	adc	un, %edx
+	add	%eax, (rp)
+	psrlq	$32, %mm1
+	adc	%edx, %ebx
+	movd	%mm1, %eax
+	adc	un, %eax
+	add	%ebx, 4(rp)
+	adc	un, %eax
+	mov	%eax, 8(rp)
+
+	inc	n
+	jmp	L(ol1)
+
+C ================================================================
+L(re2):	psrlq	$32, %mm0
+	movd	(up), %mm7	C read next U invariant limb
+	adc	%edx, %eax
+	movd	%mm0, %edx
+	movd	%mm1, %ebx
+	adc	un, %edx
+	add	%eax, (rp)
+	lea	4(rp), rp
+	psrlq	$32, %mm1
+	adc	%edx, %ebx
+	movd	%mm1, %eax
+	movd	4(up), %mm1
+	adc	un, %eax
+	add	%ebx, (rp)
+	pmuludq	%mm7, %mm1
+	adc	un, %eax
+	mov	%eax, 4(rp)
+	movd	%mm1, %ebx
+
+L(re1):	psrlq	$32, %mm1
+	add	%ebx, 4(rp)
+	movd	%mm1, %eax
+	adc	un, %eax
+	xor	n, n		C make n zeroness assumption below true
+	mov	%eax, 8(rp)
+
+L(done):			C n is zero here
+	mov	24(%esp), up
+	mov	28(%esp), %eax
+
+	movd	(up), %mm0
+	inc	%eax
+	pmuludq	%mm0, %mm0
+	lea	4(up), up
+	mov	20(%esp), rp
+	shr	%eax
+	movd	%mm0, (rp)
+	psrlq	$32, %mm0
+	lea	-12(rp), rp
+	mov	%eax, 28(%esp)
+	jnc	L(odd)
+
+	movd	%mm0, %ebp
+	movd	(up), %mm0
+	lea	8(rp), rp
+	pmuludq	%mm0, %mm0
+	lea	-4(up), up
+	add	8(rp), %ebp
+	movd	%mm0, %edx
+	adc	12(rp), %edx
+	rcr	n
+	jmp	L(ent)
+
+C	ALIGN(16)		C alignment seems irrelevant
+L(top):	movd	(up), %mm1
+	adc	n, n
+	movd	%mm0, %eax
+	pmuludq	%mm1, %mm1
+	movd	4(up), %mm0
+	adc	(rp), %eax
+	movd	%mm1, %ebx
+	pmuludq	%mm0, %mm0
+	psrlq	$32, %mm1
+	adc	4(rp), %ebx
+	movd	%mm1, %ebp
+	movd	%mm0, %edx
+	adc	8(rp), %ebp
+	adc	12(rp), %edx
+	rcr	n		C FIXME: isn't this awfully slow on atom???
+	adc	%eax, (rp)
+	adc	%ebx, 4(rp)
+L(ent):	lea	8(up), up
+	adc	%ebp, 8(rp)
+	psrlq	$32, %mm0
+	adc	%edx, 12(rp)
+L(odd):	decl	28(%esp)
+	lea	16(rp), rp
+	jnz	L(top)
+
+L(end):	adc	n, n
+	movd	%mm0, %eax
+	adc	n, %eax
+	mov	%eax, (rp)
+
+L(rtn):	emms
+	pop	%ebp
+	pop	%ebx
+	pop	%esi
+	pop	%edi
+	ret
+
+L(one):	pmuludq	%mm7, %mm7
+	movq	%mm7, -4(rp)
+	emms
+	pop	%esi
+	pop	%edi
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/atom/sublsh1_n.asm b/third_party/gmp/mpn/x86/atom/sublsh1_n.asm
new file mode 100644
index 0000000..d3e7e5b
--- /dev/null
+++ b/third_party/gmp/mpn/x86/atom/sublsh1_n.asm
@@ -0,0 +1,34 @@
+dnl  Intel Atom mpn_sublsh1_n -- rp[] = up[] - (vp[] << 1)
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+MULFUNC_PROLOGUE(mpn_sublsh1_n_ip1)
+include_mpn(`x86/k7/sublsh1_n.asm')
diff --git a/third_party/gmp/mpn/x86/atom/sublsh2_n.asm b/third_party/gmp/mpn/x86/atom/sublsh2_n.asm
new file mode 100644
index 0000000..79405cf
--- /dev/null
+++ b/third_party/gmp/mpn/x86/atom/sublsh2_n.asm
@@ -0,0 +1,57 @@
+dnl  Intel Atom mpn_addlsh2_n/mpn_sublsh2_n -- rp[] = up[] +- (vp[] << 2).
+
+dnl  Contributed to the GNU project by Marco Bodrato.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+define(LSH, 2)
+define(RSH, 30)
+
+ifdef(`OPERATION_addlsh2_n', `
+	define(M4_inst,		adcl)
+	define(M4_opp,		subl)
+	define(M4_function,	mpn_addlsh2_n)
+	define(M4_function_c,	mpn_addlsh2_nc)
+	define(M4_ip_function_c, mpn_addlsh2_nc_ip1)
+	define(M4_ip_function,	mpn_addlsh2_n_ip1)
+',`ifdef(`OPERATION_sublsh2_n', `
+	define(M4_inst,		sbbl)
+	define(M4_opp,		addl)
+	define(M4_function,	mpn_sublsh2_n)
+	define(M4_function_c,	mpn_sublsh2_nc)
+	define(M4_ip_function_c, mpn_sublsh2_nc_ip1)
+	define(M4_ip_function,	mpn_sublsh2_n_ip1)
+',`m4_error(`Need OPERATION_addlsh2_n or OPERATION_sublsh2_n
+')')')
+
+MULFUNC_PROLOGUE(mpn_sublsh2_n mpn_sublsh2_nc mpn_sublsh2_n_ip1 mpn_sublsh2_nc_ip1)
+
+include_mpn(`x86/atom/aorslshC_n.asm')
diff --git a/third_party/gmp/mpn/x86/bd1/gmp-mparam.h b/third_party/gmp/mpn/x86/bd1/gmp-mparam.h
new file mode 100644
index 0000000..254cfea
--- /dev/null
+++ b/third_party/gmp/mpn/x86/bd1/gmp-mparam.h
@@ -0,0 +1,211 @@
+/* AMD bd1 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+/* 3600-3800 MHz Bulldozer Zambezi */
+/* FFT tuning limit = 67,000,000 */
+/* Generated by tuneup.c, 2019-10-27, gcc 8.3 */
+
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          7
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          4
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        15
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD         0  /* never mpn_mod_1s_2p */
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     13
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1N_PI1_METHOD                 1  /* 59.59% faster than 2 */
+#define DIV_QR_1_NORM_THRESHOLD              5
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           27
+
+#define DIV_1_VS_MUL_1_PERCENT             245
+
+#define MUL_TOOM22_THRESHOLD                32
+#define MUL_TOOM33_THRESHOLD                89
+#define MUL_TOOM44_THRESHOLD               154
+#define MUL_TOOM6H_THRESHOLD               230
+#define MUL_TOOM8H_THRESHOLD               351
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      89
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     110
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     101
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     111
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     130
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 46
+#define SQR_TOOM3_THRESHOLD                 87
+#define SQR_TOOM4_THRESHOLD                216
+#define SQR_TOOM6_THRESHOLD                294
+#define SQR_TOOM8_THRESHOLD                442
+
+#define MULMID_TOOM42_THRESHOLD             50
+
+#define MULMOD_BNM1_THRESHOLD               22
+#define SQRMOD_BNM1_THRESHOLD               26
+
+#define MUL_FFT_MODF_THRESHOLD             636  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    636, 5}, {     28, 6}, {     15, 5}, {     31, 6}, \
+    {     28, 7}, {     15, 6}, {     33, 7}, {     17, 6}, \
+    {     35, 7}, {     19, 6}, {     39, 7}, {     23, 6}, \
+    {     47, 7}, {     29, 8}, {     15, 7}, {     35, 8}, \
+    {     19, 7}, {     41, 8}, {     23, 7}, {     47, 8}, \
+    {     27, 7}, {     55, 8}, {     31, 7}, {     63, 8}, \
+    {     43, 9}, {     23, 8}, {     55, 9}, {     31, 8}, \
+    {     67, 9}, {     39, 8}, {     79, 9}, {     47, 8}, \
+    {     95, 9}, {     55,10}, {     31, 9}, {     79,10}, \
+    {     47, 9}, {     95,11}, {     31,10}, {     63, 9}, \
+    {    135,10}, {     79, 9}, {    159,10}, {     95, 9}, \
+    {    191,11}, {     63, 7}, {   1023, 8}, {    543,11}, \
+    {     95,10}, {    191,12}, {     63,11}, {    127,10}, \
+    {    255, 9}, {    511,10}, {    271,11}, {    159,10}, \
+    {    319, 9}, {    639,10}, {    335,11}, {    191,10}, \
+    {    399,11}, {    223,12}, {    127,11}, {    255,10}, \
+    {    543,11}, {    287,10}, {    607,11}, {    319,10}, \
+    {    639,12}, {    191,11}, {    383,10}, {    799,11}, \
+    {    415,13}, {    127,12}, {    255,11}, {    543,10}, \
+    {   1087,11}, {    607,12}, {    319,11}, {    671,10}, \
+    {   1343,11}, {    735,12}, {    383,11}, {    799,10}, \
+    {   1599,11}, {    863,12}, {    447,11}, {    895,13}, \
+    {    255,12}, {    511,11}, {   1087,12}, {    575,11}, \
+    {   1215,12}, {    639,11}, {   1343,12}, {    703,11}, \
+    {   1471,13}, {    383,12}, {    767,11}, {   1599,12}, \
+    {    831,11}, {   1727,12}, {    895,14}, {    255,13}, \
+    {    511,12}, {   1087,11}, {   2239,10}, {   4479,12}, \
+    {   1215,13}, {    639,12}, {   1471,11}, {   2943,13}, \
+    {    767,12}, {   1727,11}, {   3455,13}, {    895,12}, \
+    {   1919,14}, {    511,13}, {   1023,12}, {   2239,11}, \
+    {   4479,13}, {   1151,12}, {   2495,11}, {   4991,13}, \
+    {   1279,12}, {   2623,13}, {   1407,12}, {   2943,14}, \
+    {    767,13}, {   1663,12}, {   3455,13}, {   1919,15}, \
+    {    511,14}, {   1023,13}, {   2175,12}, {   4479,13}, \
+    {   2431,12}, {   4991,14}, {   1279,13}, {   2943,12}, \
+    {   5887,14}, {   1535,13}, {   3455,14}, {   1791,13}, \
+    {   3967,12}, {   7935,15}, {   1023,14}, {   2047,13}, \
+    {   4479,14}, {   2303,13}, {   4991,12}, {   9983,14}, \
+    {   2815,13}, {   5887,15}, {   1535,14}, {   3327,13}, \
+    {   6911,14}, {   3839,13}, {   7935,16} }
+#define MUL_FFT_TABLE3_SIZE 159
+#define MUL_FFT_THRESHOLD                 6784
+
+#define SQR_FFT_MODF_THRESHOLD             565  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    565, 5}, {     29, 6}, {     15, 5}, {     32, 6}, \
+    {     17, 5}, {     35, 6}, {     29, 7}, {     15, 6}, \
+    {     33, 7}, {     17, 6}, {     35, 7}, {     19, 6}, \
+    {     39, 7}, {     23, 6}, {     47, 7}, {     35, 8}, \
+    {     19, 7}, {     41, 8}, {     23, 7}, {     49, 8}, \
+    {     27, 7}, {     55, 8}, {     43, 9}, {     23, 8}, \
+    {     55, 9}, {     31, 8}, {     67, 9}, {     39, 8}, \
+    {     79, 9}, {     47, 8}, {     95, 9}, {     55,10}, \
+    {     31, 9}, {     79,10}, {     47, 9}, {     95,11}, \
+    {     31,10}, {     63, 9}, {    135,10}, {     79, 9}, \
+    {    159,10}, {     95,11}, {     63,10}, {    159,11}, \
+    {    127,10}, {    255, 9}, {    511,10}, {    271, 9}, \
+    {    543,11}, {    159,10}, {    319, 9}, {    639,10}, \
+    {    335, 9}, {    671,11}, {    191,10}, {    415,11}, \
+    {    223,12}, {    127,11}, {    255,10}, {    543,11}, \
+    {    287,10}, {    607,11}, {    319,10}, {    671,12}, \
+    {    191,11}, {    383,10}, {    799,11}, {    415,10}, \
+    {    831,13}, {    127,12}, {    255,11}, {    543,10}, \
+    {   1087,11}, {    607,12}, {    319,11}, {    671,10}, \
+    {   1343,11}, {    735,12}, {    383,11}, {    863,12}, \
+    {    447,11}, {    959,13}, {    255,12}, {    511,11}, \
+    {   1087,12}, {    575,11}, {   1215,12}, {    639,11}, \
+    {   1343,12}, {    703,13}, {    383,12}, {    767,11}, \
+    {   1535,12}, {    831,11}, {   1727,12}, {    895,11}, \
+    {   1791,12}, {    959,14}, {    255,13}, {    511,12}, \
+    {   1087,11}, {   2239,10}, {   4479,12}, {   1215,13}, \
+    {    639,12}, {   1471,11}, {   2943,13}, {    767,12}, \
+    {   1727,13}, {    895,12}, {   1919,14}, {    511,13}, \
+    {   1023,12}, {   2239,11}, {   4479,13}, {   1151,12}, \
+    {   2495,11}, {   4991,13}, {   1279,12}, {   2623,13}, \
+    {   1407,12}, {   2943,14}, {    767,13}, {   1663,12}, \
+    {   3455,13}, {   1919,15}, {    511,14}, {   1023,13}, \
+    {   2175,12}, {   4479,13}, {   2431,12}, {   4991,14}, \
+    {   1279,13}, {   2943,12}, {   5887,14}, {   1535,13}, \
+    {   3455,14}, {   1791,13}, {   3967,15}, {   1023,14}, \
+    {   2047,13}, {   4479,14}, {   2303,13}, {   4991,12}, \
+    {   9983,14}, {   2815,13}, {   5887,15}, {   1535,14}, \
+    {   3327,13}, {   6783,14}, {   3839,13}, {   7679,16} }
+#define SQR_FFT_TABLE3_SIZE 152
+#define SQR_FFT_THRESHOLD                 5760
+
+#define MULLO_BASECASE_THRESHOLD             3
+#define MULLO_DC_THRESHOLD                  31
+#define MULLO_MUL_N_THRESHOLD            13463
+#define SQRLO_BASECASE_THRESHOLD             0  /* always */
+#define SQRLO_DC_THRESHOLD                  33
+#define SQRLO_SQR_THRESHOLD              11278
+
+#define DC_DIV_QR_THRESHOLD                 52
+#define DC_DIVAPPR_Q_THRESHOLD             198
+#define DC_BDIV_QR_THRESHOLD                48
+#define DC_BDIV_Q_THRESHOLD                126
+
+#define INV_MULMOD_BNM1_THRESHOLD           82
+#define INV_NEWTON_THRESHOLD               212
+#define INV_APPR_THRESHOLD                 202
+
+#define BINV_NEWTON_THRESHOLD              238
+#define REDC_1_TO_REDC_N_THRESHOLD          55
+
+#define MU_DIV_QR_THRESHOLD               1652
+#define MU_DIVAPPR_Q_THRESHOLD            1528
+#define MUPI_DIV_QR_THRESHOLD              110
+#define MU_BDIV_QR_THRESHOLD              1442
+#define MU_BDIV_Q_THRESHOLD               1528
+
+#define POWM_SEC_TABLE  1,20,96,386,1221,2698
+
+#define GET_STR_DC_THRESHOLD                11
+#define GET_STR_PRECOMPUTE_THRESHOLD        21
+#define SET_STR_DC_THRESHOLD               100
+#define SET_STR_PRECOMPUTE_THRESHOLD       762
+
+#define FAC_DSC_THRESHOLD                  118
+#define FAC_ODD_THRESHOLD                   34
+
+#define MATRIX22_STRASSEN_THRESHOLD         16
+#define HGCD2_DIV1_METHOD                    4  /* 1.22% faster than 3 */
+#define HGCD_THRESHOLD                      67
+#define HGCD_APPR_THRESHOLD                150
+#define HGCD_REDUCE_THRESHOLD             3389
+#define GCD_DC_THRESHOLD                   483
+#define GCDEXT_DC_THRESHOLD                345
+#define JACOBI_BASE_METHOD                   4  /* 5.07% faster than 1 */
+
+/* Tuneup completed successfully, took 65358 seconds */
diff --git a/third_party/gmp/mpn/x86/bd2/gmp-mparam.h b/third_party/gmp/mpn/x86/bd2/gmp-mparam.h
new file mode 100644
index 0000000..6893da7
--- /dev/null
+++ b/third_party/gmp/mpn/x86/bd2/gmp-mparam.h
@@ -0,0 +1,214 @@
+/* AMD bd2 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+/* 4000-4200 MHz Piledriver Vishera  */
+/* FFT tuning limit = 67,000,000 */
+/* Generated by tuneup.c, 2019-10-23, gcc 8.3 */
+
+#define MOD_1_NORM_THRESHOLD                 3
+#define MOD_1_UNNORM_THRESHOLD               4
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          6
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          4
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        18
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD         0  /* never mpn_mod_1s_2p */
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     12
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1N_PI1_METHOD                 1  /* 40.87% faster than 2 */
+#define DIV_QR_1_NORM_THRESHOLD              5
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           24
+
+#define DIV_1_VS_MUL_1_PERCENT             254
+
+#define MUL_TOOM22_THRESHOLD                32
+#define MUL_TOOM33_THRESHOLD                73
+#define MUL_TOOM44_THRESHOLD               151
+#define MUL_TOOM6H_THRESHOLD               222
+#define MUL_TOOM8H_THRESHOLD               351
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      85
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     110
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     100
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     110
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     130
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 44
+#define SQR_TOOM3_THRESHOLD                 93
+#define SQR_TOOM4_THRESHOLD                212
+#define SQR_TOOM6_THRESHOLD                318
+#define SQR_TOOM8_THRESHOLD                466
+
+#define MULMID_TOOM42_THRESHOLD             66
+
+#define MULMOD_BNM1_THRESHOLD               20
+#define SQRMOD_BNM1_THRESHOLD               23
+
+#define MUL_FFT_MODF_THRESHOLD             595  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    595, 5}, {     27, 6}, {     29, 7}, {     15, 6}, \
+    {     33, 7}, {     17, 6}, {     35, 7}, {     19, 6}, \
+    {     39, 7}, {     23, 6}, {     47, 7}, {     29, 8}, \
+    {     15, 7}, {     35, 8}, {     19, 7}, {     41, 8}, \
+    {     23, 7}, {     49, 8}, {     31, 7}, {     63, 8}, \
+    {     39, 9}, {     23, 8}, {     55, 9}, {     31, 8}, \
+    {     67, 9}, {     39, 8}, {     83, 9}, {     47, 8}, \
+    {     95, 9}, {     55,10}, {     31, 9}, {     79,10}, \
+    {     47, 9}, {     95,11}, {     31,10}, {     63, 9}, \
+    {    135,10}, {     79, 9}, {    159,10}, {     95, 9}, \
+    {    191,11}, {     63,10}, {    143, 7}, {   1215, 9}, \
+    {    319, 8}, {    639, 9}, {    335, 8}, {    671, 9}, \
+    {    351,10}, {    191,12}, {     63,11}, {    127,10}, \
+    {    271,11}, {    159,10}, {    319, 9}, {    639,10}, \
+    {    335,11}, {    191,10}, {    399,11}, {    223,12}, \
+    {    127,11}, {    255,10}, {    543,11}, {    287,10}, \
+    {    607,11}, {    319,10}, {    671,12}, {    191,11}, \
+    {    383,10}, {    799,11}, {    415,13}, {    127,12}, \
+    {    255,11}, {    543,10}, {   1087,11}, {    607,12}, \
+    {    319,11}, {    671,10}, {   1343,11}, {    735,10}, \
+    {   1471,12}, {    383,11}, {    799,10}, {   1599,11}, \
+    {    863,12}, {    447,11}, {    895,13}, {    255,12}, \
+    {    511,11}, {   1087,12}, {    575,11}, {   1215,12}, \
+    {    639,11}, {   1343,12}, {    703,11}, {   1471,13}, \
+    {    383,12}, {    767,11}, {   1599,12}, {    831,11}, \
+    {   1727,12}, {    895,14}, {    255,13}, {    511,12}, \
+    {   1087,11}, {   2239,12}, {   1215,13}, {    639,12}, \
+    {   1471,11}, {   2943,13}, {    767,12}, {   1727,13}, \
+    {    895,12}, {   1919,14}, {    511,13}, {   1023,12}, \
+    {   2239,13}, {   1151,12}, {   2431,13}, {   1279,12}, \
+    {   2623,13}, {   1407,12}, {   2943,14}, {    767,13}, \
+    {   1535,12}, {   3135,13}, {   1663,12}, {   3455,13}, \
+    {   1919,15}, {    511,14}, {   1023,13}, {   2175,12}, \
+    {   4479,13}, {   2431,14}, {   1279,13}, {   2943,12}, \
+    {   5887,14}, {   1535,13}, {   3455,14}, {   1791,13}, \
+    {   3967,12}, {   7935,11}, {  15871,15}, {   1023,14}, \
+    {   2047,13}, {   4479,14}, {   2303,13}, {   4991,12}, \
+    {   9983,14}, {   2815,13}, {   5887,15}, {   1535,14}, \
+    {   3839,13}, {   7935,12}, {  15871,16} }
+#define MUL_FFT_TABLE3_SIZE 155
+#define MUL_FFT_THRESHOLD                 6784
+
+#define SQR_FFT_MODF_THRESHOLD             555  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    555, 5}, {     28, 6}, {     15, 5}, {     31, 6}, \
+    {     16, 5}, {     33, 6}, {     29, 7}, {     15, 6}, \
+    {     33, 7}, {     17, 6}, {     36, 7}, {     19, 6}, \
+    {     39, 7}, {     23, 6}, {     47, 7}, {     29, 8}, \
+    {     15, 7}, {     35, 8}, {     19, 7}, {     43, 8}, \
+    {     23, 7}, {     49, 8}, {     31, 7}, {     63, 8}, \
+    {     43, 9}, {     23, 8}, {     55, 9}, {     31, 8}, \
+    {     67, 9}, {     39, 8}, {     79, 9}, {     47, 8}, \
+    {     95, 9}, {     55,10}, {     31, 9}, {     79,10}, \
+    {     47, 9}, {     95,11}, {     31,10}, {     63, 9}, \
+    {    135,10}, {     79, 9}, {    159,10}, {     95,11}, \
+    {     63,10}, {    143, 9}, {    287,10}, {    159,11}, \
+    {     95,10}, {    191, 6}, {   3071, 5}, {   6399, 6}, \
+    {   3455, 7}, {   1791, 8}, {    959,10}, {    255, 9}, \
+    {    511,10}, {    271,11}, {    159,10}, {    319, 9}, \
+    {    639,10}, {    335, 9}, {    671,10}, {    351,11}, \
+    {    191,10}, {    399, 9}, {    799,10}, {    415,11}, \
+    {    223,12}, {    127,11}, {    255,10}, {    543,11}, \
+    {    287,10}, {    607,11}, {    319,10}, {    671,11}, \
+    {    351,12}, {    191,11}, {    383,10}, {    799,11}, \
+    {    415,13}, {    127,12}, {    255,11}, {    543,10}, \
+    {   1087,11}, {    607,12}, {    319,11}, {    671,10}, \
+    {   1343,11}, {    735,12}, {    383,11}, {    799,10}, \
+    {   1599,11}, {    863,12}, {    447,11}, {    927,13}, \
+    {    255,12}, {    511,11}, {   1055,10}, {   2111,11}, \
+    {   1087,12}, {    575,11}, {   1215,12}, {    639,11}, \
+    {   1343,12}, {    703,13}, {    383,12}, {    767,11}, \
+    {   1599,12}, {    831,11}, {   1727,10}, {   3455,12}, \
+    {    959,14}, {    255,13}, {    511,12}, {   1023,11}, \
+    {   2111,12}, {   1087,11}, {   2239,10}, {   4479,12}, \
+    {   1215,13}, {    639,12}, {   1471,11}, {   2943,13}, \
+    {    767,12}, {   1727,11}, {   3455,13}, {    895,12}, \
+    {   1855,14}, {    511,13}, {   1023,12}, {   2239,13}, \
+    {   1151,12}, {   2495,13}, {   1279,12}, {   2623,13}, \
+    {   1407,12}, {   2943,14}, {    767,13}, {   1663,12}, \
+    {   3455,13}, {   1791,15}, {    511,14}, {   1023,13}, \
+    {   2175,12}, {   4479,13}, {   2431,14}, {   1279,13}, \
+    {   2943,12}, {   5887,14}, {   1535,13}, {   3455,14}, \
+    {   1791,13}, {   3967,12}, {   7935,15}, {   1023,14}, \
+    {   2047,13}, {   4479,14}, {   2303,13}, {   4991,12}, \
+    {   9983,14}, {   2815,13}, {   5887,15}, {   1535,14}, \
+    {   3839,13}, {   7935,16} }
+#define SQR_FFT_TABLE3_SIZE 166
+#define SQR_FFT_THRESHOLD                 5760
+
+#define MULLO_BASECASE_THRESHOLD             3
+#define MULLO_DC_THRESHOLD                  34
+#define MULLO_MUL_N_THRESHOLD            13463
+#define SQRLO_BASECASE_THRESHOLD             8
+#define SQRLO_DC_THRESHOLD                  43
+#define SQRLO_SQR_THRESHOLD              11278
+
+#define DC_DIV_QR_THRESHOLD                 75
+#define DC_DIVAPPR_Q_THRESHOLD             200
+#define DC_BDIV_QR_THRESHOLD                71
+#define DC_BDIV_Q_THRESHOLD                119
+
+#define INV_MULMOD_BNM1_THRESHOLD           74
+#define INV_NEWTON_THRESHOLD               266
+#define INV_APPR_THRESHOLD                 214
+
+#define BINV_NEWTON_THRESHOLD              278
+#define REDC_1_TO_REDC_N_THRESHOLD          71
+
+#define MU_DIV_QR_THRESHOLD               1652
+#define MU_DIVAPPR_Q_THRESHOLD            1589
+#define MUPI_DIV_QR_THRESHOLD              122
+#define MU_BDIV_QR_THRESHOLD              1442
+#define MU_BDIV_Q_THRESHOLD               1597
+
+#define POWM_SEC_TABLE  1,22,96,289,1259
+
+#define GET_STR_DC_THRESHOLD                11
+#define GET_STR_PRECOMPUTE_THRESHOLD        20
+#define SET_STR_DC_THRESHOLD               173
+#define SET_STR_PRECOMPUTE_THRESHOLD       454
+
+#define FAC_DSC_THRESHOLD                   90
+#define FAC_ODD_THRESHOLD                   34
+
+#define MATRIX22_STRASSEN_THRESHOLD         19
+#define HGCD2_DIV1_METHOD                    1  /* 5.80% faster than 3 */
+#define HGCD_THRESHOLD                      74
+#define HGCD_APPR_THRESHOLD                 50
+#define HGCD_REDUCE_THRESHOLD             3389
+#define GCD_DC_THRESHOLD                   456
+#define GCDEXT_DC_THRESHOLD                345
+#define JACOBI_BASE_METHOD                   4  /* 17.07% faster than 1 */
+
+/* Tuneup completed successfully, took 53914 seconds */
diff --git a/third_party/gmp/mpn/x86/bd4/gmp-mparam.h b/third_party/gmp/mpn/x86/bd4/gmp-mparam.h
new file mode 100644
index 0000000..6c20d0f
--- /dev/null
+++ b/third_party/gmp/mpn/x86/bd4/gmp-mparam.h
@@ -0,0 +1,225 @@
+/* AMD bd4 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+/* 3800-4200 MHz Excavator/Bristol Ridge  */
+/* FFT tuning limit = 67,000,000 */
+/* Generated by tuneup.c, 2019-10-23, gcc 8.3 */
+
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          8
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          6
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        27
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        50
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     13
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1N_PI1_METHOD                 1  /* 28.45% faster than 2 */
+#define DIV_QR_1_NORM_THRESHOLD              4
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD              13
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           28
+
+#define DIV_1_VS_MUL_1_PERCENT             314
+
+#define MUL_TOOM22_THRESHOLD                32
+#define MUL_TOOM33_THRESHOLD                73
+#define MUL_TOOM44_THRESHOLD               166
+#define MUL_TOOM6H_THRESHOLD               270
+#define MUL_TOOM8H_THRESHOLD               357
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      69
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     114
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     103
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     121
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     154
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 42
+#define SQR_TOOM3_THRESHOLD                 89
+#define SQR_TOOM4_THRESHOLD                208
+#define SQR_TOOM6_THRESHOLD                306
+#define SQR_TOOM8_THRESHOLD                454
+
+#define MULMID_TOOM42_THRESHOLD             68
+
+#define MULMOD_BNM1_THRESHOLD               19
+#define SQRMOD_BNM1_THRESHOLD               18
+
+#define MUL_FFT_MODF_THRESHOLD             570  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    570, 5}, {     25, 6}, {     13, 5}, {     27, 6}, \
+    {     25, 7}, {     13, 6}, {     27, 7}, {     15, 6}, \
+    {     32, 7}, {     17, 6}, {     35, 7}, {     19, 6}, \
+    {     39, 7}, {     27, 8}, {     15, 7}, {     35, 8}, \
+    {     19, 7}, {     41, 8}, {     23, 7}, {     47, 8}, \
+    {     27, 9}, {     15, 8}, {     31, 7}, {     63, 8}, \
+    {     39, 9}, {     23, 8}, {     51,10}, {     15, 9}, \
+    {     31, 8}, {     67, 9}, {     39, 8}, {     79, 9}, \
+    {     47, 8}, {     95,10}, {     31, 9}, {     79,10}, \
+    {     47, 9}, {     95,11}, {     31,10}, {     63, 9}, \
+    {    135,10}, {     79, 9}, {    159,10}, {     95, 9}, \
+    {    191,11}, {     63,10}, {    143, 6}, {   2303, 5}, \
+    {   4735, 4}, {   9471, 5}, {   4863, 7}, {   1279, 9}, \
+    {    335, 8}, {    671, 9}, {    351, 8}, {    703,10}, \
+    {    191,12}, {     63,11}, {    127,10}, {    255, 9}, \
+    {    511,10}, {    271, 9}, {    543,11}, {    159,10}, \
+    {    319, 9}, {    639,10}, {    335, 9}, {    671, 8}, \
+    {   1343,10}, {    351, 9}, {    703,10}, {    367, 9}, \
+    {    735,11}, {    191,10}, {    383, 9}, {    767,10}, \
+    {    399, 9}, {    799, 8}, {   1599,10}, {    415,11}, \
+    {    223,12}, {    127,11}, {    255,10}, {    543, 9}, \
+    {   1087,11}, {    287,10}, {    607, 9}, {   1215,11}, \
+    {    319,10}, {    671, 9}, {   1343,11}, {    351,12}, \
+    {    191,11}, {    383,10}, {    799,11}, {    415,10}, \
+    {    863,13}, {    127,12}, {    255,11}, {    543,10}, \
+    {   1087,11}, {    607,10}, {   1215, 9}, {   2431,12}, \
+    {    319,11}, {    671,10}, {   1343,11}, {    735,10}, \
+    {   1471, 9}, {   2943,12}, {    383,11}, {    799,10}, \
+    {   1599,11}, {    863,10}, {   1727,12}, {    447,11}, \
+    {    959,10}, {   1919,13}, {    255,12}, {    511,11}, \
+    {   1087,12}, {    575,11}, {   1215,10}, {   2431,12}, \
+    {    639,11}, {   1343,12}, {    703,11}, {   1471,10}, \
+    {   2943,13}, {    383,12}, {    767,11}, {   1599,12}, \
+    {    831,11}, {   1727,10}, {   3455,12}, {    959,11}, \
+    {   1919,10}, {   3839,13}, {    511,12}, {   1087,11}, \
+    {   2239,12}, {   1215,11}, {   2431,13}, {    639,12}, \
+    {   1471,11}, {   2943,10}, {   5887,13}, {    767,12}, \
+    {   1727,11}, {   3455,13}, {    895,12}, {   1919,11}, \
+    {   3839,14}, {    511,13}, {   1023,12}, {   2239,13}, \
+    {   1151,12}, {   2431,13}, {   1279,12}, {   2559,13}, \
+    {   1407,12}, {   2943,11}, {   5887,14}, {    767,13}, \
+    {   1663,12}, {   3455,13}, {   1919,12}, {   3839,15}, \
+    {    511,14}, {   1023,13}, {   2175,12}, {   4479,13}, \
+    {   2431,14}, {   1279,13}, {   2943,12}, {   5887,14}, \
+    {   1535,13}, {   3455,14}, {   1791,13}, {   3967,12}, \
+    {   7935,15}, {   1023,14}, {   2047,13}, {   4479,14}, \
+    {   2303,13}, {   4991,12}, {   9983,14}, {   2815,13}, \
+    {   5887,15}, {   1535,14}, {   3839,13}, {   7935,16} }
+#define MUL_FFT_TABLE3_SIZE 192
+#define MUL_FFT_THRESHOLD                 5760
+
+#define SQR_FFT_MODF_THRESHOLD             476  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    476, 5}, {     28, 6}, {     15, 5}, {     31, 6}, \
+    {     16, 5}, {     33, 6}, {     29, 7}, {     15, 6}, \
+    {     33, 7}, {     17, 6}, {     36, 7}, {     19, 6}, \
+    {     39, 7}, {     29, 8}, {     15, 7}, {     35, 8}, \
+    {     19, 7}, {     41, 8}, {     23, 7}, {     47, 8}, \
+    {     27, 9}, {     15, 8}, {     39, 9}, {     23, 8}, \
+    {     51, 9}, {     31, 8}, {     67, 9}, {     39, 8}, \
+    {     79, 9}, {     47, 8}, {     95,10}, {     31, 9}, \
+    {     79,10}, {     47, 9}, {     95,11}, {     31,10}, \
+    {     63, 9}, {    135,10}, {     95, 9}, {    191,10}, \
+    {    111,11}, {     63,10}, {    127, 9}, {    255,10}, \
+    {    143, 9}, {    287, 8}, {    575,10}, {    159,11}, \
+    {     95,10}, {    191,12}, {     63,10}, {    255, 9}, \
+    {    511,10}, {    271, 9}, {    543,10}, {    287, 9}, \
+    {    575,11}, {    159,10}, {    319, 9}, {    639,10}, \
+    {    335, 9}, {    671,10}, {    351, 9}, {    735,11}, \
+    {    191,10}, {    383, 9}, {    767,10}, {    399, 9}, \
+    {    799,10}, {    415, 9}, {    863,12}, {    127,11}, \
+    {    255,10}, {    511, 9}, {   1023,10}, {    543,11}, \
+    {    287,10}, {    607, 9}, {   1215,11}, {    319,10}, \
+    {    671, 9}, {   1343,11}, {    351,10}, {    735,12}, \
+    {    191,11}, {    383,10}, {    799,11}, {    415,10}, \
+    {    863,13}, {    127,12}, {    255,11}, {    511,10}, \
+    {   1055,11}, {    543,10}, {   1087,11}, {    607,10}, \
+    {   1215,12}, {    319,11}, {    671,10}, {   1343,11}, \
+    {    735,10}, {   1471,12}, {    383,11}, {    799,10}, \
+    {   1599,11}, {    863,10}, {   1727,12}, {    447,11}, \
+    {    959,13}, {    255,12}, {    511,11}, {   1087,12}, \
+    {    575,11}, {   1215,12}, {    639,11}, {   1343,12}, \
+    {    703,11}, {   1471,13}, {    383,12}, {    767,11}, \
+    {   1599,12}, {    831,11}, {   1727,12}, {    959,11}, \
+    {   1919,14}, {    255,13}, {    511,12}, {   1023,11}, \
+    {   2047,12}, {   1087,11}, {   2239,12}, {   1215,11}, \
+    {   2431,13}, {    639,12}, {   1471,11}, {   2943,13}, \
+    {    767,12}, {   1727,13}, {    895,12}, {   1983,14}, \
+    {    511,13}, {   1023,12}, {   2239,13}, {   1151,12}, \
+    {   2431,13}, {   1279,12}, {   2559,13}, {   1407,12}, \
+    {   2943,14}, {    767,13}, {   1663,12}, {   3455,13}, \
+    {   1919,12}, {   3839,15}, {    511,14}, {   1023,13}, \
+    {   2175,12}, {   4479,13}, {   2431,14}, {   1279,13}, \
+    {   2943,12}, {   5887,14}, {   1535,13}, {   3455,14}, \
+    {   1791,13}, {   3967,15}, {   1023,14}, {   2047,13}, \
+    {   4479,14}, {   2303,13}, {   4991,12}, {   9983,14}, \
+    {   2815,13}, {   5887,15}, {   1535,14}, {   3839,16} }
+#define SQR_FFT_TABLE3_SIZE 176
+#define SQR_FFT_THRESHOLD                 4736
+
+#define MULLO_BASECASE_THRESHOLD             3
+#define MULLO_DC_THRESHOLD                  54
+#define MULLO_MUL_N_THRESHOLD            10950
+#define SQRLO_BASECASE_THRESHOLD            10
+#define SQRLO_DC_THRESHOLD                  77
+#define SQRLO_SQR_THRESHOLD               9449
+
+#define DC_DIV_QR_THRESHOLD                 84
+#define DC_DIVAPPR_Q_THRESHOLD             252
+#define DC_BDIV_QR_THRESHOLD                79
+#define DC_BDIV_Q_THRESHOLD                 80
+
+#define INV_MULMOD_BNM1_THRESHOLD           71
+#define INV_NEWTON_THRESHOLD               254
+#define INV_APPR_THRESHOLD                 266
+
+#define BINV_NEWTON_THRESHOLD              294
+#define REDC_1_TO_REDC_N_THRESHOLD          79
+
+#define MU_DIV_QR_THRESHOLD               1652
+#define MU_DIVAPPR_Q_THRESHOLD            1528
+#define MUPI_DIV_QR_THRESHOLD              122
+#define MU_BDIV_QR_THRESHOLD              1387
+#define MU_BDIV_Q_THRESHOLD               1528
+
+#define POWM_SEC_TABLE  1,16,96,480,960
+
+#define GET_STR_DC_THRESHOLD                12
+#define GET_STR_PRECOMPUTE_THRESHOLD        19
+#define SET_STR_DC_THRESHOLD               264
+#define SET_STR_PRECOMPUTE_THRESHOLD       542
+
+#define FAC_DSC_THRESHOLD                   91
+#define FAC_ODD_THRESHOLD                   29
+
+#define MATRIX22_STRASSEN_THRESHOLD         19
+#define HGCD2_DIV1_METHOD                    1  /* 9.73% faster than 3 */
+#define HGCD_THRESHOLD                      55
+#define HGCD_APPR_THRESHOLD                 50
+#define HGCD_REDUCE_THRESHOLD             3389
+#define GCD_DC_THRESHOLD                   562
+#define GCDEXT_DC_THRESHOLD                416
+#define JACOBI_BASE_METHOD                   4  /* 16.50% faster than 1 */
+
+/* Tuneup completed successfully, took 49179 seconds */
diff --git a/third_party/gmp/mpn/x86/bdiv_dbm1c.asm b/third_party/gmp/mpn/x86/bdiv_dbm1c.asm
new file mode 100644
index 0000000..0288c47
--- /dev/null
+++ b/third_party/gmp/mpn/x86/bdiv_dbm1c.asm
@@ -0,0 +1,129 @@
+dnl  x86 mpn_bdiv_dbm1.
+
+dnl  Copyright 2008, 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C			    cycles/limb
+C P5
+C P6 model 0-8,10-12)
+C P6 model 9  (Banias)
+C P6 model 13 (Dothan)		 5.1
+C P4 model 0  (Willamette)
+C P4 model 1  (?)
+C P4 model 2  (Northwood)	13.67
+C P4 model 3  (Prescott)
+C P4 model 4  (Nocona)
+C Intel Atom
+C AMD K6
+C AMD K7			 3.5
+C AMD K8
+C AMD K10
+
+
+C TODO
+C  * Optimize for more x86 processors
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_bdiv_dbm1c)
+	mov	16(%esp), %ecx		C d
+	push	%esi
+	mov	12(%esp), %esi		C ap
+	push	%edi
+	mov	12(%esp), %edi		C qp
+	push	%ebp
+	mov	24(%esp), %ebp		C n
+	push	%ebx
+
+	mov	(%esi), %eax
+	mul	%ecx
+	mov	36(%esp), %ebx
+	sub	%eax, %ebx
+	mov	%ebx, (%edi)
+	sbb	%edx, %ebx
+
+	mov	%ebp, %eax
+	and	$3, %eax
+	jz	L(b0)
+	cmp	$2, %eax
+	jc	L(b1)
+	jz	L(b2)
+
+L(b3):	lea	-8(%esi), %esi
+	lea	8(%edi), %edi
+	add	$-3, %ebp
+	jmp	L(3)
+
+L(b0):	mov	4(%esi), %eax
+	lea	-4(%esi), %esi
+	lea	12(%edi), %edi
+	add	$-4, %ebp
+	jmp	L(0)
+
+L(b2):	mov	4(%esi), %eax
+	lea	4(%esi), %esi
+	lea	4(%edi), %edi
+	add	$-2, %ebp
+	jmp	L(2)
+
+	ALIGN(8)
+L(top):	mov	4(%esi), %eax
+	mul	%ecx
+	lea	16(%edi), %edi
+	sub	%eax, %ebx
+	mov	8(%esi), %eax
+	mov	%ebx, -12(%edi)
+	sbb	%edx, %ebx
+L(0):	mul	%ecx
+	sub	%eax, %ebx
+	mov	%ebx, -8(%edi)
+	sbb	%edx, %ebx
+L(3):	mov	12(%esi), %eax
+	mul	%ecx
+	sub	%eax, %ebx
+	mov	%ebx, -4(%edi)
+	mov	16(%esi), %eax
+	lea	16(%esi), %esi
+	sbb	%edx, %ebx
+L(2):	mul	%ecx
+	sub	%eax, %ebx
+	mov	%ebx, 0(%edi)
+	sbb	%edx, %ebx
+L(b1):	add	$-4, %ebp
+	jns	L(top)
+
+	mov	%ebx, %eax
+	pop	%ebx
+	pop	%ebp
+	pop	%edi
+	pop	%esi
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/bdiv_q_1.asm b/third_party/gmp/mpn/x86/bdiv_q_1.asm
new file mode 100644
index 0000000..132de06
--- /dev/null
+++ b/third_party/gmp/mpn/x86/bdiv_q_1.asm
@@ -0,0 +1,208 @@
+dnl  x86 mpn_bdiv_q_1 -- mpn by limb exact division.
+
+dnl  Rearranged from mpn/x86/dive_1.asm by Marco Bodrato.
+
+dnl  Copyright 2001, 2002, 2007, 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C     cycles/limb
+C P54    30.0
+C P55    29.0
+C P6     13.0 odd divisor, 12.0 even (strangely)
+C K6     14.0
+C K7     12.0
+C P4     42.0
+
+MULFUNC_PROLOGUE(mpn_bdiv_q_1 mpn_pi1_bdiv_q_1)
+
+defframe(PARAM_SHIFT,  24)
+defframe(PARAM_INVERSE,20)
+defframe(PARAM_DIVISOR,16)
+defframe(PARAM_SIZE,   12)
+defframe(PARAM_SRC,    8)
+defframe(PARAM_DST,    4)
+
+dnl  re-use parameter space
+define(VAR_INVERSE,`PARAM_SRC')
+
+	TEXT
+
+C mp_limb_t
+C mpn_pi1_bdiv_q_1 (mp_ptr dst, mp_srcptr src, mp_size_t size, mp_limb_t divisor,
+C		    mp_limb_t inverse, int shift)
+
+	ALIGN(16)
+PROLOGUE(mpn_pi1_bdiv_q_1)
+deflit(`FRAME',0)
+
+	movl	PARAM_SHIFT, %ecx
+	pushl	%ebp	FRAME_pushl()
+
+	movl	PARAM_INVERSE, %eax
+	movl	PARAM_SIZE, %ebp
+	pushl	%ebx	FRAME_pushl()
+L(common):
+	pushl	%edi	FRAME_pushl()
+	pushl	%esi	FRAME_pushl()
+
+	movl	PARAM_SRC, %esi
+	movl	PARAM_DST, %edi
+
+	leal	(%esi,%ebp,4), %esi	C src end
+	leal	(%edi,%ebp,4), %edi	C dst end
+	negl	%ebp			C -size
+
+	movl	%eax, VAR_INVERSE
+	movl	(%esi,%ebp,4), %eax	C src[0]
+
+	xorl	%ebx, %ebx
+	xorl	%edx, %edx
+
+	incl	%ebp
+	jz	L(one)
+
+	movl	(%esi,%ebp,4), %edx	C src[1]
+
+	shrdl(	%cl, %edx, %eax)
+
+	movl	VAR_INVERSE, %edx
+	jmp	L(entry)
+
+
+	ALIGN(8)
+	nop	C k6 code alignment
+	nop
+L(top):
+	C eax	q
+	C ebx	carry bit, 0 or -1
+	C ecx	shift
+	C edx	carry limb
+	C esi	src end
+	C edi	dst end
+	C ebp	counter, limbs, negative
+
+	movl	-4(%esi,%ebp,4), %eax
+	subl	%ebx, %edx		C accumulate carry bit
+
+	movl	(%esi,%ebp,4), %ebx
+
+	shrdl(	%cl, %ebx, %eax)
+
+	subl	%edx, %eax		C apply carry limb
+	movl	VAR_INVERSE, %edx
+
+	sbbl	%ebx, %ebx
+
+L(entry):
+	imull	%edx, %eax
+
+	movl	%eax, -4(%edi,%ebp,4)
+	movl	PARAM_DIVISOR, %edx
+
+	mull	%edx
+
+	incl	%ebp
+	jnz	L(top)
+
+
+	movl	-4(%esi), %eax		C src high limb
+L(one):
+	shrl	%cl, %eax
+	popl	%esi	FRAME_popl()
+
+	addl	%ebx, %eax		C apply carry bit
+
+	subl	%edx, %eax		C apply carry limb
+
+	imull	VAR_INVERSE, %eax
+
+	movl	%eax, -4(%edi)
+
+	popl	%edi
+	popl	%ebx
+	popl	%ebp
+
+	ret
+
+EPILOGUE()
+
+C mp_limb_t mpn_bdiv_q_1 (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                           mp_limb_t divisor);
+C
+
+	ALIGN(16)
+PROLOGUE(mpn_bdiv_q_1)
+deflit(`FRAME',0)
+
+	movl	PARAM_DIVISOR, %eax
+	pushl	%ebp	FRAME_pushl()
+
+	movl	$-1, %ecx		C shift count
+	movl	PARAM_SIZE, %ebp
+
+	pushl	%ebx	FRAME_pushl()
+
+L(strip_twos):
+	incl	%ecx
+
+	shrl	%eax
+	jnc	L(strip_twos)
+
+	leal	1(%eax,%eax), %ebx	C d without twos
+	andl	$127, %eax		C d/2, 7 bits
+
+ifdef(`PIC',`
+	LEA(	binvert_limb_table, %edx)
+	movzbl	(%eax,%edx), %eax		C inv 8 bits
+',`
+	movzbl	binvert_limb_table(%eax), %eax	C inv 8 bits
+')
+
+	leal	(%eax,%eax), %edx	C 2*inv
+	movl	%ebx, PARAM_DIVISOR	C d without twos
+	imull	%eax, %eax		C inv*inv
+	imull	%ebx, %eax		C inv*inv*d
+	subl	%eax, %edx		C inv = 2*inv - inv*inv*d
+
+	leal	(%edx,%edx), %eax	C 2*inv
+	imull	%edx, %edx		C inv*inv
+	imull	%ebx, %edx		C inv*inv*d
+	subl	%edx, %eax		C inv = 2*inv - inv*inv*d
+
+	ASSERT(e,`	C expect d*inv == 1 mod 2^GMP_LIMB_BITS
+	pushl	%eax	FRAME_pushl()
+	imull	PARAM_DIVISOR, %eax
+	cmpl	$1, %eax
+	popl	%eax	FRAME_popl()')
+
+	jmp	L(common)
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86/bt1/gmp-mparam.h b/third_party/gmp/mpn/x86/bt1/gmp-mparam.h
new file mode 100644
index 0000000..302dbc6
--- /dev/null
+++ b/third_party/gmp/mpn/x86/bt1/gmp-mparam.h
@@ -0,0 +1,218 @@
+/* x86/bobcat gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+/* NOTE: In a fat binary build SQR_TOOM2_THRESHOLD here cannot be greater than
+   the value in mpn/x86/k7/gmp-mparam.h.  The latter is used as a hard limit in
+   k7/sqr_basecase.asm.  */
+
+/* 1600 MHz AMD Bobcat Zacate E-350 */
+/* FFT tuning limit = 67,000,000 */
+/* Generated by tuneup.c, 2019-10-17, gcc 8.3 */
+
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD         10
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          6
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        16
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD         0  /* never mpn_mod_1s_2p */
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     21
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1N_PI1_METHOD                 1  /* 57.16% faster than 2 */
+#define DIV_QR_1_NORM_THRESHOLD              3
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           36
+
+#define DIV_1_VS_MUL_1_PERCENT             199
+
+#define MUL_TOOM22_THRESHOLD                28
+#define MUL_TOOM33_THRESHOLD                93
+#define MUL_TOOM44_THRESHOLD               166
+#define MUL_TOOM6H_THRESHOLD               270
+#define MUL_TOOM8H_THRESHOLD               478
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD     102
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     177
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     169
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     113
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     143
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 50
+#define SQR_TOOM3_THRESHOLD                 89
+#define SQR_TOOM4_THRESHOLD                248
+#define SQR_TOOM6_THRESHOLD                342
+#define SQR_TOOM8_THRESHOLD                470
+
+#define MULMID_TOOM42_THRESHOLD             72
+
+#define MULMOD_BNM1_THRESHOLD               20
+#define SQRMOD_BNM1_THRESHOLD               21
+
+#define MUL_FFT_MODF_THRESHOLD             630  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    630, 5}, {     25, 6}, {     13, 5}, {     27, 6}, \
+    {     15, 5}, {     31, 6}, {     27, 7}, {     15, 6}, \
+    {     33, 7}, {     17, 6}, {     35, 7}, {     19, 6}, \
+    {     39, 7}, {     23, 6}, {     47, 7}, {     29, 8}, \
+    {     15, 7}, {     35, 8}, {     19, 7}, {     41, 8}, \
+    {     23, 7}, {     49, 8}, {     27, 7}, {     55, 9}, \
+    {     15, 8}, {     31, 7}, {     63, 8}, {     43, 9}, \
+    {     23, 8}, {     55, 9}, {     31, 8}, {     67, 9}, \
+    {     39, 8}, {     79, 9}, {     47, 8}, {     95, 9}, \
+    {     55,10}, {     31, 9}, {     79,10}, {     47, 6}, \
+    {    767, 7}, {    399, 6}, {    799, 7}, {    415, 8}, \
+    {    235, 7}, {    479, 9}, {    135,10}, {     79, 9}, \
+    {    159,10}, {     95, 9}, {    191,11}, {     63,10}, \
+    {    159,11}, {     95,10}, {    191,12}, {     63,11}, \
+    {    127,10}, {    255, 9}, {    511,10}, {    271, 9}, \
+    {    543,11}, {    159,10}, {    319, 9}, {    639,10}, \
+    {    335, 9}, {    671,11}, {    191,10}, {    383, 9}, \
+    {    767,10}, {    399, 9}, {    799,11}, {    223,12}, \
+    {    127,11}, {    255,10}, {    543, 9}, {   1087,11}, \
+    {    287,10}, {    607, 9}, {   1215,11}, {    319,10}, \
+    {    671,11}, {    351,12}, {    191,11}, {    383,10}, \
+    {    799,11}, {    415,13}, {    127,12}, {    255,11}, \
+    {    543,10}, {   1087,11}, {    607,10}, {   1215,12}, \
+    {    319,11}, {    671,10}, {   1343,11}, {    735,10}, \
+    {   1471,12}, {    383,11}, {    799,10}, {   1599,11}, \
+    {    863,12}, {    447,11}, {    991,13}, {    255,12}, \
+    {    511,11}, {   1087,12}, {    575,11}, {   1215,12}, \
+    {    639,11}, {   1343,12}, {    703,11}, {   1471,13}, \
+    {    383,12}, {    767,11}, {   1599,12}, {    831,11}, \
+    {   1727,12}, {    959,14}, {    255,13}, {    511,12}, \
+    {   1215,13}, {    639,12}, {   1471,13}, {    767,12}, \
+    {   1727,13}, {    895,12}, {   1919,14}, {    511,13}, \
+    {   1023,12}, {   2111,13}, {   1151,12}, {   2431,13}, \
+    {   1407,14}, {    767,13}, {   1663,12}, {   3455,13}, \
+    {   1919,15}, {    511,14}, {   1023,13}, {   2175,12}, \
+    {   4479,13}, {   2431,14}, {   1279,13}, {   2943,12}, \
+    {   5887,14}, {   1535,13}, {   3455,14}, {   1791,13}, \
+    {   3967,15}, {   1023,14}, {   2047,13}, {   4479,14}, \
+    {   2303,13}, {   4991,12}, {   9983,14}, {   2815,13}, \
+    {   5887,15}, {   1535,14}, {   3839,16} }
+#define MUL_FFT_TABLE3_SIZE 159
+#define MUL_FFT_THRESHOLD                 7424
+
+#define SQR_FFT_MODF_THRESHOLD             500  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    500, 5}, {     25, 6}, {     13, 5}, {     27, 6}, \
+    {     28, 7}, {     15, 6}, {     32, 7}, {     17, 6}, \
+    {     35, 7}, {     19, 6}, {     39, 7}, {     23, 6}, \
+    {     47, 7}, {     27, 8}, {     15, 7}, {     35, 8}, \
+    {     19, 7}, {     41, 8}, {     23, 7}, {     47, 8}, \
+    {     27, 9}, {     15, 8}, {     31, 7}, {     63, 8}, \
+    {     39, 9}, {     23, 8}, {     51, 9}, {     31, 8}, \
+    {     67, 9}, {     39, 8}, {     79, 9}, {     47, 8}, \
+    {     95, 9}, {     55,10}, {     31, 9}, {     79,10}, \
+    {     47, 9}, {     95,11}, {     31,10}, {     63, 9}, \
+    {    127, 6}, {   1087, 7}, {    575, 8}, {    303, 9}, \
+    {    159,10}, {     95,11}, {     63,10}, {    127, 9}, \
+    {    255,10}, {    143, 9}, {    287,10}, {    159,11}, \
+    {     95,10}, {    191,12}, {     63,11}, {    127,10}, \
+    {    255, 9}, {    511,10}, {    271, 9}, {    543,10}, \
+    {    287, 9}, {    575,11}, {    159,10}, {    319, 9}, \
+    {    639,10}, {    335, 9}, {    671,10}, {    351,11}, \
+    {    191,10}, {    383, 9}, {    767,10}, {    399, 9}, \
+    {    799,10}, {    415, 9}, {    831,12}, {    127,11}, \
+    {    255,10}, {    543,11}, {    287,10}, {    607,11}, \
+    {    319,10}, {    671,11}, {    351,10}, {    703,12}, \
+    {    191,11}, {    383,10}, {    799,11}, {    415,10}, \
+    {    831,13}, {    127,12}, {    255,11}, {    543,10}, \
+    {   1087,11}, {    607,12}, {    319,11}, {    671,10}, \
+    {   1343,11}, {    735,10}, {   1471,12}, {    383,11}, \
+    {    799,10}, {   1599,11}, {    863,12}, {    447,11}, \
+    {    959,13}, {    255,12}, {    511,11}, {   1087,12}, \
+    {    575,11}, {   1215,12}, {    639,11}, {   1343,12}, \
+    {    703,11}, {   1471,13}, {    383,12}, {    767,11}, \
+    {   1599,12}, {    831,11}, {   1727,12}, {    959,14}, \
+    {    255,13}, {    511,12}, {   1215,13}, {    639,12}, \
+    {   1471,13}, {    767,12}, {   1727,13}, {    895,12}, \
+    {   1919,14}, {    511,13}, {   1023,12}, {   2111,13}, \
+    {   1151,12}, {   2431,13}, {   1407,14}, {    767,13}, \
+    {   1663,12}, {   3455,13}, {   1919,15}, {    511,14}, \
+    {   1023,13}, {   2175,12}, {   4479,13}, {   2431,14}, \
+    {   1279,13}, {   2943,12}, {   5887,14}, {   1535,13}, \
+    {   3455,14}, {   1791,13}, {   3839,15}, {   1023,14}, \
+    {   2047,13}, {   4479,14}, {   2303,13}, {   4991,12}, \
+    {   9983,14}, {   2815,13}, {   5887,15}, {   1535,14}, \
+    {   3839,16} }
+#define SQR_FFT_TABLE3_SIZE 161
+#define SQR_FFT_THRESHOLD                 5760
+
+#define MULLO_BASECASE_THRESHOLD             9
+#define MULLO_DC_THRESHOLD                  48
+#define MULLO_MUL_N_THRESHOLD            14281
+#define SQRLO_BASECASE_THRESHOLD             7
+#define SQRLO_DC_THRESHOLD                 146
+#define SQRLO_SQR_THRESHOLD              11278
+
+#define DC_DIV_QR_THRESHOLD                 77
+#define DC_DIVAPPR_Q_THRESHOLD             240
+#define DC_BDIV_QR_THRESHOLD                83
+#define DC_BDIV_Q_THRESHOLD                182
+
+#define INV_MULMOD_BNM1_THRESHOLD           74
+#define INV_NEWTON_THRESHOLD               252
+#define INV_APPR_THRESHOLD                 252
+
+#define BINV_NEWTON_THRESHOLD              252
+#define REDC_1_TO_REDC_N_THRESHOLD          79
+
+#define MU_DIV_QR_THRESHOLD               1787
+#define MU_DIVAPPR_Q_THRESHOLD            1718
+#define MUPI_DIV_QR_THRESHOLD              122
+#define MU_BDIV_QR_THRESHOLD              1470
+#define MU_BDIV_Q_THRESHOLD               1713
+
+#define POWM_SEC_TABLE  1,16,96,563,1317,1867
+
+#define GET_STR_DC_THRESHOLD                19
+#define GET_STR_PRECOMPUTE_THRESHOLD        32
+#define SET_STR_DC_THRESHOLD               254
+#define SET_STR_PRECOMPUTE_THRESHOLD       907
+
+#define FAC_DSC_THRESHOLD                  224
+#define FAC_ODD_THRESHOLD                   55
+
+#define MATRIX22_STRASSEN_THRESHOLD         23
+#define HGCD2_DIV1_METHOD                    3  /* 3.59% faster than 5 */
+#define HGCD_THRESHOLD                      85
+#define HGCD_APPR_THRESHOLD                152
+#define HGCD_REDUCE_THRESHOLD             3389
+#define GCD_DC_THRESHOLD                   531
+#define GCDEXT_DC_THRESHOLD                386
+#define JACOBI_BASE_METHOD                   3  /* 0.92% faster than 1 */
+
+/* Tuneup completed successfully, took 159946 seconds */
diff --git a/third_party/gmp/mpn/x86/bt2/gmp-mparam.h b/third_party/gmp/mpn/x86/bt2/gmp-mparam.h
new file mode 100644
index 0000000..f936cb7
--- /dev/null
+++ b/third_party/gmp/mpn/x86/bt2/gmp-mparam.h
@@ -0,0 +1,214 @@
+/* x86/bobcat gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+/* NOTE: In a fat binary build SQR_TOOM2_THRESHOLD here cannot be greater than
+   the value in mpn/x86/k7/gmp-mparam.h.  The latter is used as a hard limit in
+   k7/sqr_basecase.asm.  */
+
+/* 2050 MHz AMD Jaguar/Kabini */
+/* FFT tuning limit = 67,000,000 */
+/* Generated by tuneup.c, 2019-10-24, gcc 8.3 */
+
+#define MOD_1_NORM_THRESHOLD                 4
+#define MOD_1_UNNORM_THRESHOLD               6
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          4
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          4
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        18
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD         0  /* never mpn_mod_1s_2p */
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD      9
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1N_PI1_METHOD                 1  /* 47.53% faster than 2 */
+#define DIV_QR_1_NORM_THRESHOLD          MP_SIZE_T_MAX  /* never */
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           27
+
+#define DIV_1_VS_MUL_1_PERCENT             243
+
+#define MUL_TOOM22_THRESHOLD                32
+#define MUL_TOOM33_THRESHOLD                90
+#define MUL_TOOM44_THRESHOLD               154
+#define MUL_TOOM6H_THRESHOLD               286
+#define MUL_TOOM8H_THRESHOLD               478
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      97
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     152
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     103
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     113
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     154
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 38
+#define SQR_TOOM3_THRESHOLD                126
+#define SQR_TOOM4_THRESHOLD                220
+#define SQR_TOOM6_THRESHOLD                318
+#define SQR_TOOM8_THRESHOLD                502
+
+#define MULMID_TOOM42_THRESHOLD             68
+
+#define MULMOD_BNM1_THRESHOLD               19
+#define SQRMOD_BNM1_THRESHOLD               25
+
+#define MUL_FFT_MODF_THRESHOLD             570  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    570, 5}, {     25, 6}, {     13, 5}, {     27, 6}, \
+    {     15, 5}, {     31, 6}, {     28, 7}, {     15, 6}, \
+    {     33, 7}, {     17, 6}, {     35, 7}, {     19, 6}, \
+    {     39, 7}, {     23, 6}, {     47, 7}, {     27, 8}, \
+    {     15, 7}, {     35, 8}, {     19, 7}, {     41, 8}, \
+    {     23, 7}, {     49, 8}, {     31, 7}, {     63, 8}, \
+    {     39, 9}, {     23, 8}, {     55, 9}, {     31, 8}, \
+    {     67, 9}, {     39, 8}, {     79, 9}, {     47, 8}, \
+    {     95, 9}, {     55,10}, {     31, 9}, {     79,10}, \
+    {     47, 9}, {     95,11}, {     31,10}, {     63, 9}, \
+    {    135,10}, {     79, 9}, {    159,10}, {     95,11}, \
+    {     63,10}, {    159,11}, {     95,10}, {    191,12}, \
+    {     63,11}, {    127,10}, {    255, 9}, {    511,10}, \
+    {    271, 9}, {    543,10}, {    287,11}, {    159,10}, \
+    {    319, 9}, {    639,10}, {    335, 9}, {    671,11}, \
+    {    191,10}, {    383, 9}, {    767,10}, {    399, 9}, \
+    {    799,10}, {    415,11}, {    223,12}, {    127,11}, \
+    {    255,10}, {    543,11}, {    287,10}, {    607, 9}, \
+    {   1215,11}, {    319,10}, {    671,11}, {    351,12}, \
+    {    191,11}, {    383,10}, {    799,11}, {    415,13}, \
+    {    127,12}, {    255,11}, {    543,10}, {   1087,11}, \
+    {    607,10}, {   1215,12}, {    319,11}, {    671,10}, \
+    {   1343,11}, {    735,10}, {   1471,12}, {    383,11}, \
+    {    799,10}, {   1599,11}, {    863,12}, {    447,11}, \
+    {    991,13}, {    255,12}, {    511,11}, {   1087,12}, \
+    {    575,11}, {   1215,12}, {    639,11}, {   1343,12}, \
+    {    703,11}, {   1471,13}, {    383,12}, {    767,11}, \
+    {   1599,12}, {    831,11}, {   1727,12}, {    959,14}, \
+    {    255,13}, {    511,12}, {   1215,13}, {    639,12}, \
+    {   1471,13}, {    767,12}, {   1727,13}, {    895,12}, \
+    {   1919,14}, {    511,13}, {   1023,12}, {   2111,13}, \
+    {   1151,12}, {   2431,13}, {   1407,14}, {    767,13}, \
+    {   1663,12}, {   3455,13}, {   1919,15}, {    511,14}, \
+    {   1023,13}, {   2175,12}, {   4479,13}, {   2431,14}, \
+    {   1279,13}, {   2943,12}, {   5887,14}, {   1535,13}, \
+    {   3455,14}, {   1791,13}, {   3967,15}, {   1023,14}, \
+    {   2047,13}, {   4479,14}, {   2303,13}, {   4991,12}, \
+    {   9983,14}, {   2815,13}, {   5887,15}, {   1535,14}, \
+    {   3839,16} }
+#define MUL_FFT_TABLE3_SIZE 153
+#define MUL_FFT_THRESHOLD                 5760
+
+#define SQR_FFT_MODF_THRESHOLD             530  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    530, 5}, {     27, 6}, {     15, 5}, {     31, 6}, \
+    {     28, 7}, {     15, 6}, {     33, 7}, {     17, 6}, \
+    {     35, 7}, {     19, 6}, {     39, 7}, {     23, 6}, \
+    {     47, 7}, {     29, 8}, {     15, 7}, {     35, 8}, \
+    {     19, 7}, {     41, 8}, {     23, 7}, {     49, 8}, \
+    {     31, 7}, {     63, 8}, {     39, 9}, {     23, 8}, \
+    {     55, 9}, {     31, 8}, {     67, 9}, {     39, 8}, \
+    {     79, 9}, {     47, 8}, {     95, 9}, {     55,10}, \
+    {     31, 9}, {     79,10}, {     47, 9}, {     95,11}, \
+    {     31,10}, {     63, 9}, {    135,10}, {     95,11}, \
+    {     63,10}, {    143, 9}, {    287,10}, {    159,11}, \
+    {     95,12}, {     63,11}, {    127,10}, {    255, 9}, \
+    {    511,10}, {    271, 9}, {    543,10}, {    287,11}, \
+    {    159,10}, {    319, 9}, {    639,10}, {    335, 9}, \
+    {    671,10}, {    351,11}, {    191,10}, {    383, 9}, \
+    {    767,10}, {    399, 9}, {    799,12}, {    127,11}, \
+    {    255,10}, {    543,11}, {    287,10}, {    607, 9}, \
+    {   1215,11}, {    319,10}, {    671,11}, {    351,12}, \
+    {    191,11}, {    383,10}, {    799,11}, {    415,10}, \
+    {    831,13}, {    127,12}, {    255,11}, {    543,10}, \
+    {   1087,11}, {    607,10}, {   1215,12}, {    319,11}, \
+    {    671,10}, {   1343,11}, {    735,10}, {   1471,12}, \
+    {    383,11}, {    799,10}, {   1599,11}, {    863,12}, \
+    {    447,11}, {    991,13}, {    255,12}, {    511,11}, \
+    {   1087,12}, {    575,11}, {   1215,12}, {    639,11}, \
+    {   1343,12}, {    703,11}, {   1471,13}, {    383,12}, \
+    {    767,11}, {   1599,12}, {    831,11}, {   1727,12}, \
+    {    959,11}, {   1919,14}, {    255,13}, {    511,12}, \
+    {   1215,13}, {    639,12}, {   1471,13}, {    767,12}, \
+    {   1727,13}, {    895,12}, {   1919,14}, {    511,13}, \
+    {   1023,12}, {   2111,13}, {   1151,12}, {   2495,13}, \
+    {   1407,14}, {    767,13}, {   1663,12}, {   3455,13}, \
+    {   1919,15}, {    511,14}, {   1023,13}, {   2175,12}, \
+    {   4479,13}, {   2431,14}, {   1279,13}, {   2943,12}, \
+    {   5887,14}, {   1535,13}, {   3455,14}, {   1791,13}, \
+    {   3967,15}, {   1023,14}, {   2047,13}, {   4479,14}, \
+    {   2303,13}, {   4991,12}, {   9983,14}, {   2815,13}, \
+    {   5887,15}, {   1535,14}, {   3839,16} }
+#define SQR_FFT_TABLE3_SIZE 151
+#define SQR_FFT_THRESHOLD                 4736
+
+#define MULLO_BASECASE_THRESHOLD             8
+#define MULLO_DC_THRESHOLD                  44
+#define MULLO_MUL_N_THRESHOLD            11278
+#define SQRLO_BASECASE_THRESHOLD            13
+#define SQRLO_DC_THRESHOLD                  62
+#define SQRLO_SQR_THRESHOLD               8907
+
+#define DC_DIV_QR_THRESHOLD                 79
+#define DC_DIVAPPR_Q_THRESHOLD             228
+#define DC_BDIV_QR_THRESHOLD                75
+#define DC_BDIV_Q_THRESHOLD                136
+
+#define INV_MULMOD_BNM1_THRESHOLD           90
+#define INV_NEWTON_THRESHOLD               260
+#define INV_APPR_THRESHOLD                 236
+
+#define BINV_NEWTON_THRESHOLD              294
+#define REDC_1_TO_REDC_N_THRESHOLD          80
+
+#define MU_DIV_QR_THRESHOLD               1787
+#define MU_DIVAPPR_Q_THRESHOLD            1718
+#define MUPI_DIV_QR_THRESHOLD              118
+#define MU_BDIV_QR_THRESHOLD              1442
+#define MU_BDIV_Q_THRESHOLD               1652
+
+#define POWM_SEC_TABLE  1,16,96,615,865,1442
+
+#define GET_STR_DC_THRESHOLD                16
+#define GET_STR_PRECOMPUTE_THRESHOLD        27
+#define SET_STR_DC_THRESHOLD               252
+#define SET_STR_PRECOMPUTE_THRESHOLD       638
+
+#define FAC_DSC_THRESHOLD                  141
+#define FAC_ODD_THRESHOLD                   39
+
+#define MATRIX22_STRASSEN_THRESHOLD         19
+#define HGCD2_DIV1_METHOD                    1  /* 13.65% faster than 3 */
+#define HGCD_THRESHOLD                      81
+#define HGCD_APPR_THRESHOLD                 66
+#define HGCD_REDUCE_THRESHOLD             3389
+#define GCD_DC_THRESHOLD                   531
+#define GCDEXT_DC_THRESHOLD                345
+#define JACOBI_BASE_METHOD                   1  /* 0.84% faster than 4 */
+
+/* Tuneup completed successfully, took 103818 seconds */
diff --git a/third_party/gmp/mpn/x86/cnd_aors_n.asm b/third_party/gmp/mpn/x86/cnd_aors_n.asm
new file mode 100644
index 0000000..74f4917
--- /dev/null
+++ b/third_party/gmp/mpn/x86/cnd_aors_n.asm
@@ -0,0 +1,124 @@
+dnl  X86 mpn_cnd_add_n, mpn_cnd_sub_n
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C			    cycles/limb
+C P5				 ?
+C P6 model 0-8,10-12		 ?
+C P6 model 9   (Banias)		 ?
+C P6 model 13  (Dothan)		 5.4
+C P4 model 0-1 (Willamette)	 ?
+C P4 model 2   (Northwood)	14.5
+C P4 model 3-4 (Prescott)	21
+C Intel atom			11
+C AMD K6			 ?
+C AMD K7			 3.4
+C AMD K8			 ?
+
+
+define(`rp',  `%edi')
+define(`up',  `%esi')
+define(`vp',  `%ebp')
+define(`n',   `%ecx')
+define(`cnd', `20(%esp)')
+define(`cy',  `%edx')
+
+ifdef(`OPERATION_cnd_add_n', `
+	define(ADDSUB,	      add)
+	define(ADCSBB,	      adc)
+	define(func,	      mpn_cnd_add_n)')
+ifdef(`OPERATION_cnd_sub_n', `
+	define(ADDSUB,	      sub)
+	define(ADCSBB,	      sbb)
+	define(func,	      mpn_cnd_sub_n)')
+
+MULFUNC_PROLOGUE(mpn_cnd_add_n mpn_cnd_sub_n)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(func)
+	add	$-16, %esp
+	mov	%ebp, (%esp)
+	mov	%ebx, 4(%esp)
+	mov	%esi, 8(%esp)
+	mov	%edi, 12(%esp)
+
+	C make cnd into a full mask
+	mov	cnd, %eax
+	neg	%eax
+	sbb	%eax, %eax
+	mov	%eax, cnd
+
+	C load parameters into registers
+	mov	24(%esp), rp
+	mov	28(%esp), up
+	mov	32(%esp), vp
+	mov	36(%esp), n
+
+	mov	(vp), %eax
+	mov	(up), %ebx
+
+	C put operand pointers just beyond their last limb
+	lea	(vp,n,4), vp
+	lea	(up,n,4), up
+	lea	-4(rp,n,4), rp
+	neg	n
+
+	and	cnd, %eax
+	ADDSUB	%eax, %ebx
+	sbb	cy, cy
+	inc	n
+	je	L(end)
+
+	ALIGN(16)
+L(top):	mov	(vp,n,4), %eax
+	and	cnd, %eax
+	mov	%ebx, (rp,n,4)
+	mov	(up,n,4), %ebx
+	add	cy, cy
+	ADCSBB	%eax, %ebx
+	sbb	cy, cy
+	inc	n
+	jne	L(top)
+
+L(end):	mov	%ebx, (rp)
+	xor	%eax, %eax
+	sub	cy, %eax
+
+	mov	(%esp), %ebp
+	mov	4(%esp), %ebx
+	mov	8(%esp), %esi
+	mov	12(%esp), %edi
+	add	$16, %esp
+	ret
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86/copyd.asm b/third_party/gmp/mpn/x86/copyd.asm
new file mode 100644
index 0000000..51fa195
--- /dev/null
+++ b/third_party/gmp/mpn/x86/copyd.asm
@@ -0,0 +1,91 @@
+dnl  x86 mpn_copyd -- copy limb vector, decrementing.
+
+dnl  Copyright 1999-2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C     cycles/limb  startup (approx)
+C P5	  1.0	      40
+C P6	  2.4	      70
+C K6	  1.0	      55
+C K7	  1.3	      75
+C P4	  2.6	     175
+C
+C (Startup time includes some function call overheads.)
+
+
+C void mpn_copyd (mp_ptr dst, mp_srcptr src, mp_size_t size);
+C
+C Copy src,size to dst,size, working from high to low addresses.
+C
+C The code here is very generic and can be expected to be reasonable on all
+C the x86 family.
+
+defframe(PARAM_SIZE,12)
+defframe(PARAM_SRC, 8)
+defframe(PARAM_DST, 4)
+deflit(`FRAME',0)
+
+	TEXT
+	ALIGN(32)
+
+PROLOGUE(mpn_copyd)
+	C eax	saved esi
+	C ebx
+	C ecx	counter
+	C edx	saved edi
+	C esi	src
+	C edi	dst
+	C ebp
+
+	movl	PARAM_SIZE, %ecx
+	movl	%esi, %eax
+
+	movl	PARAM_SRC, %esi
+	movl	%edi, %edx
+
+	movl	PARAM_DST, %edi
+	leal	-4(%esi,%ecx,4), %esi
+
+	leal	-4(%edi,%ecx,4), %edi
+
+	std
+
+	rep
+	movsl
+
+	cld
+
+	movl	%eax, %esi
+	movl	%edx, %edi
+
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/copyi.asm b/third_party/gmp/mpn/x86/copyi.asm
new file mode 100644
index 0000000..f6b0354
--- /dev/null
+++ b/third_party/gmp/mpn/x86/copyi.asm
@@ -0,0 +1,99 @@
+dnl  x86 mpn_copyi -- copy limb vector, incrementing.
+
+dnl  Copyright 1999-2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C     cycles/limb  startup (approx)
+C P5	  1.0	      35
+C P6	  0.75	      45
+C K6	  1.0	      30
+C K7	  1.3	      65
+C P4	  1.0	     120
+C
+C (Startup time includes some function call overheads.)
+
+
+C void mpn_copyi (mp_ptr dst, mp_srcptr src, mp_size_t size);
+C
+C Copy src,size to dst,size, working from low to high addresses.
+C
+C The code here is very generic and can be expected to be reasonable on all
+C the x86 family.
+C
+C P6 -  An MMX based copy was tried, but was found to be slower than a rep
+C       movs in all cases.  The fastest MMX found was 0.8 cycles/limb (when
+C       fully aligned).  A rep movs seems to have a startup time of about 15
+C       cycles, but doing something special for small sizes could lead to a
+C       branch misprediction that would destroy any saving.  For now a plain
+C       rep movs seems ok.
+C
+C K62 - We used to have a big chunk of code doing an MMX copy at 0.56 c/l if
+C       aligned or a 1.0 rep movs if not.  But that seemed excessive since
+C       it only got an advantage half the time, and even then only showed it
+C       above 50 limbs or so.
+
+defframe(PARAM_SIZE,12)
+defframe(PARAM_SRC, 8)
+defframe(PARAM_DST, 4)
+deflit(`FRAME',0)
+
+	TEXT
+	ALIGN(32)
+
+	C eax	saved esi
+	C ebx
+	C ecx	counter
+	C edx	saved edi
+	C esi	src
+	C edi	dst
+	C ebp
+
+PROLOGUE(mpn_copyi)
+
+	movl	PARAM_SIZE, %ecx
+	movl	%esi, %eax
+
+	movl	PARAM_SRC, %esi
+	movl	%edi, %edx
+
+	movl	PARAM_DST, %edi
+
+	cld	C better safe than sorry, see mpn/x86/README
+
+	rep
+	movsl
+
+	movl	%eax, %esi
+	movl	%edx, %edi
+
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/core2/gmp-mparam.h b/third_party/gmp/mpn/x86/core2/gmp-mparam.h
new file mode 100644
index 0000000..8a44ad1
--- /dev/null
+++ b/third_party/gmp/mpn/x86/core2/gmp-mparam.h
@@ -0,0 +1,210 @@
+/* x86/core2 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+/* 3000 MHz Penryn */
+/* FFT tuning limit = 67,000,000 */
+/* Generated by tuneup.c, 2019-10-20, gcc 8.3 */
+
+#define MOD_1_NORM_THRESHOLD             MP_SIZE_T_MAX  /* never */
+#define MOD_1_UNNORM_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          9
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          8
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD         9
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD         0  /* never mpn_mod_1s_2p */
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD      3
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1N_PI1_METHOD                 2  /* 22.20% faster than 1 */
+#define DIV_QR_1_NORM_THRESHOLD          MP_SIZE_T_MAX  /* never */
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD               9
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           18
+
+#define DIV_1_VS_MUL_1_PERCENT             277
+
+#define MUL_TOOM22_THRESHOLD                24
+#define MUL_TOOM33_THRESHOLD                93
+#define MUL_TOOM44_THRESHOLD               136
+#define MUL_TOOM6H_THRESHOLD               300
+#define MUL_TOOM8H_THRESHOLD               478
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      91
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     153
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD      93
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD      94
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     130
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 34
+#define SQR_TOOM3_THRESHOLD                117
+#define SQR_TOOM4_THRESHOLD                184
+#define SQR_TOOM6_THRESHOLD                262
+#define SQR_TOOM8_THRESHOLD                597
+
+#define MULMID_TOOM42_THRESHOLD             70
+
+#define MULMOD_BNM1_THRESHOLD               17
+#define SQRMOD_BNM1_THRESHOLD               25
+
+#define MUL_FFT_MODF_THRESHOLD             505  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    505, 5}, {     28, 6}, {     15, 5}, {     31, 6}, \
+    {     29, 7}, {     15, 6}, {     32, 7}, {     17, 6}, \
+    {     35, 7}, {     19, 6}, {     39, 7}, {     29, 8}, \
+    {     15, 7}, {     35, 8}, {     19, 7}, {     43, 8}, \
+    {     23, 7}, {     47, 8}, {     27, 9}, {     15, 8}, \
+    {     31, 7}, {     63, 8}, {     43, 9}, {     23, 8}, \
+    {     55, 9}, {     31, 8}, {     67, 9}, {     39, 8}, \
+    {     79, 9}, {     55,10}, {     31, 9}, {     79,10}, \
+    {     47, 9}, {     95,11}, {     31,10}, {     63, 9}, \
+    {    135,10}, {     79, 9}, {    159,10}, {     95,11}, \
+    {     63, 9}, {    255,10}, {    159,11}, {     95,10}, \
+    {    191,12}, {     63,11}, {    127,10}, {    271, 9}, \
+    {    543,10}, {    287,11}, {    159,10}, {    335, 9}, \
+    {    671,10}, {    351,11}, {    191,10}, {    399, 9}, \
+    {    799,11}, {    223,12}, {    127,11}, {    255,10}, \
+    {    543,11}, {    287,10}, {    607,11}, {    319,10}, \
+    {    671,11}, {    351,12}, {    191,11}, {    383,10}, \
+    {    799,11}, {    415,13}, {    127,12}, {    255,11}, \
+    {    543,10}, {   1087,11}, {    607,12}, {    319,11}, \
+    {    671,10}, {   1343,11}, {    735,10}, {   1471,12}, \
+    {    383,11}, {    799,10}, {   1599,11}, {    863,12}, \
+    {    447,11}, {    959,13}, {    255,12}, {    511,11}, \
+    {   1087,12}, {    575,11}, {   1215,12}, {    639,11}, \
+    {   1343,12}, {    703,11}, {   1471,13}, {    383,12}, \
+    {    767,11}, {   1599,12}, {    831,11}, {   1727,12}, \
+    {    959,14}, {    255,13}, {    511,12}, {   1087,11}, \
+    {   2239,12}, {   1215,13}, {    639,12}, {   1471,11}, \
+    {   2943,13}, {    767,12}, {   1727,13}, {    895,12}, \
+    {   1919,14}, {    511,13}, {   1023,12}, {   2239,13}, \
+    {   1151,12}, {   2431,13}, {   1407,12}, {   2943,14}, \
+    {    767,13}, {   1663,12}, {   3455,13}, {   1919,15}, \
+    {    511,14}, {   1023,13}, {   2175,12}, {   4479,13}, \
+    {   2431,14}, {   1279,13}, {   2943,12}, {   5887,14}, \
+    {   1535,13}, {   3455,14}, {   1791,13}, {   3967,12}, \
+    {   7935,15}, {   1023,14}, {   2047,13}, {   4479,14}, \
+    {   2303,13}, {   4991,12}, {   9983,14}, {   2815,13}, \
+    {   5887,15}, {   1535,14}, {   3839,16} }
+#define MUL_FFT_TABLE3_SIZE 147
+#define MUL_FFT_THRESHOLD                 6784
+
+#define SQR_FFT_MODF_THRESHOLD             464  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    464, 5}, {     28, 6}, {     15, 5}, {     31, 6}, \
+    {     29, 7}, {     15, 6}, {     32, 7}, {     17, 6}, \
+    {     35, 7}, {     19, 6}, {     39, 7}, {     29, 8}, \
+    {     15, 7}, {     35, 8}, {     19, 7}, {     41, 8}, \
+    {     23, 7}, {     49, 8}, {     27, 9}, {     15, 8}, \
+    {     39, 9}, {     23, 8}, {     51,10}, {     15, 9}, \
+    {     31, 8}, {     67, 9}, {     39, 8}, {     79, 9}, \
+    {     47, 8}, {     95, 9}, {     55,10}, {     31, 9}, \
+    {     79,10}, {     47, 9}, {     95,11}, {     31,10}, \
+    {     63, 9}, {    127,10}, {     79, 9}, {    159,10}, \
+    {     95,11}, {     63,10}, {    127, 9}, {    255,10}, \
+    {    143, 9}, {    287, 5}, {   4863, 6}, {   2495, 7}, \
+    {   1343, 8}, {    703, 9}, {    367,12}, {     63,11}, \
+    {    127,10}, {    303,11}, {    159,10}, {    319, 9}, \
+    {    639,10}, {    335, 9}, {    671,10}, {    351, 9}, \
+    {    703,10}, {    367,11}, {    191,10}, {    383, 9}, \
+    {    767,10}, {    399, 9}, {    799,10}, {    415, 9}, \
+    {    831,12}, {    127,11}, {    255,10}, {    543,11}, \
+    {    287,10}, {    607,11}, {    319,10}, {    671,11}, \
+    {    351,10}, {    703,12}, {    191,11}, {    383,10}, \
+    {    799,11}, {    415,10}, {    863,13}, {    127,12}, \
+    {    255,11}, {    543,10}, {   1087,11}, {    607,12}, \
+    {    319,11}, {    671,10}, {   1343,11}, {    735,10}, \
+    {   1471,12}, {    383,11}, {    799,10}, {   1599,11}, \
+    {    863,12}, {    447,11}, {    959,13}, {    255,12}, \
+    {    511,11}, {   1087,12}, {    575,11}, {   1215,12}, \
+    {    639,11}, {   1343,12}, {    703,11}, {   1407,13}, \
+    {    383,12}, {    767,11}, {   1599,12}, {    831,11}, \
+    {   1727,12}, {    959,14}, {    255,13}, {    511,12}, \
+    {   1215,13}, {    639,12}, {   1471,11}, {   2943,13}, \
+    {    767,12}, {   1727,13}, {    895,12}, {   1919,14}, \
+    {    511,13}, {   1023,12}, {   2111,13}, {   1151,12}, \
+    {   2431,13}, {   1407,12}, {   2943,14}, {    767,13}, \
+    {   1663,12}, {   3455,13}, {   1919,15}, {    511,14}, \
+    {   1023,13}, {   2175,12}, {   4479,13}, {   2431,14}, \
+    {   1279,13}, {   2943,12}, {   5887,14}, {   1535,13}, \
+    {   3455,14}, {   1791,13}, {   3967,15}, {   1023,14}, \
+    {   2047,13}, {   4479,14}, {   2303,13}, {   4991,12}, \
+    {   9983,14}, {   2815,13}, {   5887,15}, {   1535,14}, \
+    {   3839,16} }
+#define SQR_FFT_TABLE3_SIZE 157
+#define SQR_FFT_THRESHOLD                 5312
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  36
+#define MULLO_MUL_N_THRESHOLD            13463
+#define SQRLO_BASECASE_THRESHOLD             0  /* always */
+#define SQRLO_DC_THRESHOLD                 140
+#define SQRLO_SQR_THRESHOLD              10393
+
+#define DC_DIV_QR_THRESHOLD                 32
+#define DC_DIVAPPR_Q_THRESHOLD             116
+#define DC_BDIV_QR_THRESHOLD                76
+#define DC_BDIV_Q_THRESHOLD                180
+
+#define INV_MULMOD_BNM1_THRESHOLD           46
+#define INV_NEWTON_THRESHOLD               138
+#define INV_APPR_THRESHOLD                 123
+
+#define BINV_NEWTON_THRESHOLD              306
+#define REDC_1_TO_REDC_N_THRESHOLD          82
+
+#define MU_DIV_QR_THRESHOLD               1499
+#define MU_DIVAPPR_Q_THRESHOLD            1442
+#define MUPI_DIV_QR_THRESHOLD               63
+#define MU_BDIV_QR_THRESHOLD              1442
+#define MU_BDIV_Q_THRESHOLD               1589
+
+#define POWM_SEC_TABLE  1,22,66,428,1035
+
+#define GET_STR_DC_THRESHOLD                13
+#define GET_STR_PRECOMPUTE_THRESHOLD        18
+#define SET_STR_DC_THRESHOLD               732
+#define SET_STR_PRECOMPUTE_THRESHOLD      1118
+
+#define FAC_DSC_THRESHOLD                  115
+#define FAC_ODD_THRESHOLD                   50
+
+#define MATRIX22_STRASSEN_THRESHOLD         25
+#define HGCD2_DIV1_METHOD                    1  /* 5.78% faster than 3 */
+#define HGCD_THRESHOLD                     121
+#define HGCD_APPR_THRESHOLD                151
+#define HGCD_REDUCE_THRESHOLD             3259
+#define GCD_DC_THRESHOLD                   368
+#define GCDEXT_DC_THRESHOLD                306
+#define JACOBI_BASE_METHOD                   4  /* 14.19% faster than 1 */
+
+/* Tuneup completed successfully, took 67142 seconds */
diff --git a/third_party/gmp/mpn/x86/coreibwl/gmp-mparam.h b/third_party/gmp/mpn/x86/coreibwl/gmp-mparam.h
new file mode 100644
index 0000000..7b58cad
--- /dev/null
+++ b/third_party/gmp/mpn/x86/coreibwl/gmp-mparam.h
@@ -0,0 +1,216 @@
+/* x86/coreibwl gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+/* 3400-3800 MHz Intel Xeon E3-1285Lv4 Broadwell */
+/* FFT tuning limit = 67,000,000 */
+/* Generated by tuneup.c, 2019-10-20, gcc 8.3 */
+
+#define MOD_1_NORM_THRESHOLD                15
+#define MOD_1_UNNORM_THRESHOLD              16
+#define MOD_1N_TO_MOD_1_1_THRESHOLD         10
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          8
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD         0  /* never mpn_mod_1_1p */
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        10
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     11
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1N_PI1_METHOD                 1  /* 21.34% faster than 2 */
+#define DIV_QR_1_NORM_THRESHOLD             14
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD              29
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           19
+
+#define DIV_1_VS_MUL_1_PERCENT             295
+
+#define MUL_TOOM22_THRESHOLD                26
+#define MUL_TOOM33_THRESHOLD                97
+#define MUL_TOOM44_THRESHOLD               220
+#define MUL_TOOM6H_THRESHOLD               306
+#define MUL_TOOM8H_THRESHOLD               454
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      93
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     153
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     154
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     169
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     136
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 44
+#define SQR_TOOM3_THRESHOLD                134
+#define SQR_TOOM4_THRESHOLD                242
+#define SQR_TOOM6_THRESHOLD                342
+#define SQR_TOOM8_THRESHOLD                502
+
+#define MULMID_TOOM42_THRESHOLD             98
+
+#define MULMOD_BNM1_THRESHOLD               20
+#define SQRMOD_BNM1_THRESHOLD               23
+
+#define MUL_FFT_MODF_THRESHOLD             540  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    540, 5}, {     29, 6}, {     15, 5}, {     31, 6}, \
+    {     16, 5}, {     33, 6}, {     17, 5}, {     36, 6}, \
+    {     25, 7}, {     13, 6}, {     29, 7}, {     15, 6}, \
+    {     33, 7}, {     17, 6}, {     36, 7}, {     19, 6}, \
+    {     39, 7}, {     21, 6}, {     43, 7}, {     23, 6}, \
+    {     47, 7}, {     29, 8}, {     15, 7}, {     35, 8}, \
+    {     19, 7}, {     43, 8}, {     23, 7}, {     49, 8}, \
+    {     27, 7}, {     55, 9}, {     15, 8}, {     31, 7}, \
+    {     63, 8}, {     43, 9}, {     23, 8}, {     55,10}, \
+    {     15, 9}, {     31, 8}, {     67, 9}, {     39, 8}, \
+    {     83, 9}, {     47, 8}, {     95, 9}, {     55,10}, \
+    {     31, 9}, {     79,10}, {     47, 9}, {     95,11}, \
+    {     31,10}, {     63, 9}, {    135,10}, {     79, 9}, \
+    {    159,10}, {     95, 9}, {    191,10}, {    111,11}, \
+    {     63,10}, {    143, 9}, {    287,10}, {    159,11}, \
+    {     95, 7}, {   1599, 8}, {    831, 9}, {    431, 8}, \
+    {    863, 9}, {    447,10}, {    239, 9}, {    479,10}, \
+    {    255, 9}, {    511,10}, {    287,11}, {    159,10}, \
+    {    319, 9}, {    639,10}, {    335, 9}, {    671,11}, \
+    {    191,10}, {    383, 9}, {    767,10}, {    399,11}, \
+    {    223,12}, {    127,11}, {    255,10}, {    511, 9}, \
+    {   1023,11}, {    287,10}, {    607,11}, {    319,10}, \
+    {    671,11}, {    351,12}, {    191,11}, {    383,10}, \
+    {    799,11}, {    415,13}, {    127,12}, {    255,11}, \
+    {    543,10}, {   1119,11}, {    607,12}, {    319,11}, \
+    {    671,10}, {   1343,11}, {    735,12}, {    383,11}, \
+    {    799,10}, {   1599,11}, {    863,12}, {    447,11}, \
+    {    959,13}, {    255,12}, {    511,11}, {   1119,12}, \
+    {    575,11}, {   1215,12}, {    639,11}, {   1343,12}, \
+    {    703,11}, {   1407,13}, {    383,12}, {    767,11}, \
+    {   1599,12}, {    831,11}, {   1727,12}, {    959,14}, \
+    {    255,13}, {    511,12}, {   1215,13}, {    639,12}, \
+    {   1471,13}, {    767,12}, {   1727,13}, {    895,12}, \
+    {   1919,14}, {    511,13}, {   1023,12}, {   2239,13}, \
+    {   1151,12}, {   2431,13}, {   1279,12}, {   2623,13}, \
+    {   1407,12}, {   2815,14}, {    767,13}, {   1535,12}, \
+    {   3135,13}, {   1663,12}, {   3455,13}, {   1919,15}, \
+    {    511,14}, {   1023,13}, {   2175,12}, {   4479,13}, \
+    {   2431,14}, {   1279,13}, {   2943,12}, {   5887,14}, \
+    {   1535,13}, {   3455,14}, {   1791,13}, {   3839,15}, \
+    {   1023,14}, {   2047,13}, {   4479,14}, {   2303,13}, \
+    {   4991,12}, {   9983,14}, {   2559,13}, {   5247,14}, \
+    {   2815,13}, {   5887,15}, {   1535,14}, {   3839,16} }
+#define MUL_FFT_TABLE3_SIZE 172
+#define MUL_FFT_THRESHOLD                 7424
+
+#define SQR_FFT_MODF_THRESHOLD             472  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    472, 5}, {     29, 6}, {     15, 5}, {     33, 6}, \
+    {     37, 7}, {     19, 6}, {     40, 7}, {     29, 8}, \
+    {     15, 7}, {     35, 8}, {     19, 7}, {     43, 8}, \
+    {     23, 7}, {     49, 8}, {     27, 9}, {     15, 8}, \
+    {     31, 7}, {     63, 8}, {     43, 9}, {     23, 8}, \
+    {     55,10}, {     15, 9}, {     31, 8}, {     67, 9}, \
+    {     39, 8}, {     83, 9}, {     47, 8}, {     95, 9}, \
+    {     55,10}, {     31, 9}, {     79,10}, {     47, 9}, \
+    {     95,11}, {     31,10}, {     63, 9}, {    135,10}, \
+    {     79, 9}, {    159,10}, {     95,11}, {     63,10}, \
+    {    127, 9}, {    255,10}, {    143, 9}, {    287,10}, \
+    {    159,11}, {     95,12}, {     63,11}, {    127,10}, \
+    {    271, 9}, {    543, 6}, {   4479, 7}, {   2431, 8}, \
+    {   1247, 7}, {   2495, 8}, {   1279,10}, {    351,11}, \
+    {    191,10}, {    399, 9}, {    799,10}, {    415,12}, \
+    {    127,11}, {    255,10}, {    543,11}, {    287,10}, \
+    {    607,11}, {    319,10}, {    639,11}, {    351,12}, \
+    {    191,11}, {    383,10}, {    799,11}, {    415,10}, \
+    {    831,13}, {    127,12}, {    255,11}, {    511,10}, \
+    {   1023,11}, {    543,10}, {   1087,11}, {    607,12}, \
+    {    319,11}, {    671,10}, {   1343,11}, {    735,12}, \
+    {    383,11}, {    799,10}, {   1599,11}, {    863,12}, \
+    {    447,11}, {    927,13}, {    255,12}, {    511,11}, \
+    {   1087,12}, {    575,11}, {   1215,12}, {    639,11}, \
+    {   1343,12}, {    703,11}, {   1471,13}, {    383,12}, \
+    {    767,11}, {   1599,12}, {    831,11}, {   1663,12}, \
+    {    895,11}, {   1855,14}, {    255,13}, {    511,12}, \
+    {   1023,11}, {   2047,12}, {   1087,11}, {   2239,12}, \
+    {   1215,13}, {    639,12}, {   1471,13}, {    767,12}, \
+    {   1663,13}, {    895,12}, {   1983,14}, {    511,13}, \
+    {   1023,12}, {   2239,13}, {   1151,12}, {   2495,13}, \
+    {   1279,12}, {   2623,13}, {   1407,14}, {    767,13}, \
+    {   1535,12}, {   3135,13}, {   1663,12}, {   3455,13}, \
+    {   1919,15}, {    511,14}, {   1023,13}, {   2175,12}, \
+    {   4479,13}, {   2431,14}, {   1279,13}, {   2943,12}, \
+    {   5887,14}, {   1535,13}, {   3455,14}, {   1791,13}, \
+    {   3839,15}, {   1023,14}, {   2047,13}, {   4479,14}, \
+    {   2303,13}, {   4991,12}, {   9983,14}, {   2815,13}, \
+    {   5887,15}, {   1535,14}, {   3327,13}, {   6783,14}, \
+    {   3839,16} }
+#define SQR_FFT_TABLE3_SIZE 157
+#define SQR_FFT_THRESHOLD                 5568
+
+#define MULLO_BASECASE_THRESHOLD            16
+#define MULLO_DC_THRESHOLD                  37
+#define MULLO_MUL_N_THRESHOLD            14281
+#define SQRLO_BASECASE_THRESHOLD             0  /* always */
+#define SQRLO_DC_THRESHOLD                 137
+#define SQRLO_SQR_THRESHOLD              10821
+
+#define DC_DIV_QR_THRESHOLD                 54
+#define DC_DIVAPPR_Q_THRESHOLD             146
+#define DC_BDIV_QR_THRESHOLD                98
+#define DC_BDIV_Q_THRESHOLD                218
+
+#define INV_MULMOD_BNM1_THRESHOLD           50
+#define INV_NEWTON_THRESHOLD               173
+#define INV_APPR_THRESHOLD                 165
+
+#define BINV_NEWTON_THRESHOLD              278
+#define REDC_1_TO_REDC_N_THRESHOLD          79
+
+#define MU_DIV_QR_THRESHOLD               1787
+#define MU_DIVAPPR_Q_THRESHOLD            1787
+#define MUPI_DIV_QR_THRESHOLD               78
+#define MU_BDIV_QR_THRESHOLD              1589
+#define MU_BDIV_Q_THRESHOLD               1830
+
+#define POWM_SEC_TABLE  1,16,126,416,932
+
+#define GET_STR_DC_THRESHOLD                11
+#define GET_STR_PRECOMPUTE_THRESHOLD        17
+#define SET_STR_DC_THRESHOLD               306
+#define SET_STR_PRECOMPUTE_THRESHOLD       894
+
+#define FAC_DSC_THRESHOLD                  141
+#define FAC_ODD_THRESHOLD                   34
+
+#define MATRIX22_STRASSEN_THRESHOLD         20
+#define HGCD2_DIV1_METHOD                    3  /* 5.97% faster than 1 */
+#define HGCD_THRESHOLD                      73
+#define HGCD_APPR_THRESHOLD                123
+#define HGCD_REDUCE_THRESHOLD             3664
+#define GCD_DC_THRESHOLD                   562
+#define GCDEXT_DC_THRESHOLD                465
+#define JACOBI_BASE_METHOD                   1  /* 31.16% faster than 3 */
+
+/* Tuneup completed successfully, took 35114 seconds */
diff --git a/third_party/gmp/mpn/x86/coreihwl/gmp-mparam.h b/third_party/gmp/mpn/x86/coreihwl/gmp-mparam.h
new file mode 100644
index 0000000..ea4ac11
--- /dev/null
+++ b/third_party/gmp/mpn/x86/coreihwl/gmp-mparam.h
@@ -0,0 +1,215 @@
+/* x86/coreihwl gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+/* 3600-4000 MHz Intel Xeon E3-1271v3 Haswell */
+/* FFT tuning limit = 67,000,000 */
+/* Generated by tuneup.c, 2019-10-21, gcc 8.3 */
+
+#define MOD_1_NORM_THRESHOLD                17
+#define MOD_1_UNNORM_THRESHOLD              17
+#define MOD_1N_TO_MOD_1_1_THRESHOLD         10
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          9
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD         0  /* never mpn_mod_1_1p */
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        10
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD      5
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1N_PI1_METHOD                 1  /* 11.44% faster than 2 */
+#define DIV_QR_1_NORM_THRESHOLD             13
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           21
+
+#define DIV_1_VS_MUL_1_PERCENT             296
+
+#define MUL_TOOM22_THRESHOLD                28
+#define MUL_TOOM33_THRESHOLD               108
+#define MUL_TOOM44_THRESHOLD               232
+#define MUL_TOOM6H_THRESHOLD               306
+#define MUL_TOOM8H_THRESHOLD               478
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD     109
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     183
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     113
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     113
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     136
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 44
+#define SQR_TOOM3_THRESHOLD                141
+#define SQR_TOOM4_THRESHOLD                384
+#define SQR_TOOM6_THRESHOLD                517
+#define SQR_TOOM8_THRESHOLD                698
+
+#define MULMID_TOOM42_THRESHOLD             98
+
+#define MULMOD_BNM1_THRESHOLD               20
+#define SQRMOD_BNM1_THRESHOLD               23
+
+#define MUL_FFT_MODF_THRESHOLD             565  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    565, 5}, {     28, 6}, {     15, 5}, {     31, 6}, \
+    {     16, 5}, {     33, 6}, {     29, 7}, {     15, 6}, \
+    {     33, 7}, {     17, 6}, {     36, 7}, {     19, 6}, \
+    {     39, 7}, {     21, 6}, {     43, 7}, {     23, 6}, \
+    {     47, 7}, {     29, 8}, {     15, 7}, {     35, 8}, \
+    {     19, 7}, {     43, 8}, {     23, 7}, {     47, 8}, \
+    {     27, 7}, {     55, 9}, {     15, 8}, {     31, 7}, \
+    {     63, 8}, {     43, 9}, {     23, 8}, {     55, 9}, \
+    {     31, 8}, {     71, 9}, {     39, 8}, {     83, 9}, \
+    {     47, 8}, {     95, 9}, {     55,10}, {     31, 9}, \
+    {     79,10}, {     47, 9}, {     95,11}, {     31,10}, \
+    {     63, 9}, {    135,10}, {     79, 9}, {    159,10}, \
+    {     95, 9}, {    191,10}, {    111,11}, {     63,10}, \
+    {    143, 9}, {    287,10}, {    159,11}, {     95,10}, \
+    {    191, 6}, {   3199, 7}, {   1727, 9}, {    447,10}, \
+    {    239, 9}, {    479,10}, {    287,11}, {    159,10}, \
+    {    319, 9}, {    639,10}, {    335, 9}, {    671,11}, \
+    {    191,10}, {    399, 9}, {    799,10}, {    415,11}, \
+    {    223,12}, {    127,11}, {    255,10}, {    511, 9}, \
+    {   1023,10}, {    527,11}, {    287,10}, {    607,11}, \
+    {    319,10}, {    671,12}, {    191,11}, {    383,10}, \
+    {    799,11}, {    415,13}, {    127,12}, {    255,11}, \
+    {    511,10}, {   1023,11}, {    543,10}, {   1087,11}, \
+    {    607,12}, {    319,11}, {    671,10}, {   1343,11}, \
+    {    735,12}, {    383,11}, {    799,10}, {   1599,11}, \
+    {    863,12}, {    447,11}, {    991,13}, {    255,12}, \
+    {    511,11}, {   1087,12}, {    575,11}, {   1215,12}, \
+    {    639,11}, {   1343,12}, {    703,11}, {   1407,13}, \
+    {    383,12}, {    767,11}, {   1599,12}, {    831,11}, \
+    {   1727,12}, {    959,11}, {   1919,14}, {    255,13}, \
+    {    511,12}, {   1087,11}, {   2239,12}, {   1215,13}, \
+    {    639,12}, {   1471,13}, {    767,12}, {   1727,13}, \
+    {    895,12}, {   1919,14}, {    511,13}, {   1023,12}, \
+    {   2239,13}, {   1151,12}, {   2431,13}, {   1279,12}, \
+    {   2623,13}, {   1407,14}, {    767,13}, {   1663,12}, \
+    {   3455,13}, {   1919,15}, {    511,14}, {   1023,13}, \
+    {   2175,12}, {   4479,13}, {   2431,14}, {   1279,13}, \
+    {   2943,12}, {   5887,14}, {   1535,13}, {   3455,14}, \
+    {   1791,13}, {   3967,15}, {   1023,14}, {   2047,13}, \
+    {   4479,14}, {   2303,13}, {   4991,14}, {   2559,13}, \
+    {   5375,14}, {   2815,13}, {   5887,15}, {   1535,14}, \
+    {   3839,16} }
+#define MUL_FFT_TABLE3_SIZE 165
+#define MUL_FFT_THRESHOLD                 7808
+
+#define SQR_FFT_MODF_THRESHOLD             560  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    560, 5}, {     29, 6}, {     15, 5}, {     31, 6}, \
+    {     16, 5}, {     33, 6}, {     17, 5}, {     36, 6}, \
+    {     29, 7}, {     15, 6}, {     33, 7}, {     17, 6}, \
+    {     36, 7}, {     19, 6}, {     40, 7}, {     21, 6}, \
+    {     43, 7}, {     23, 6}, {     47, 7}, {     29, 8}, \
+    {     15, 7}, {     35, 8}, {     19, 7}, {     43, 8}, \
+    {     23, 7}, {     49, 8}, {     27, 7}, {     55, 9}, \
+    {     15, 8}, {     31, 7}, {     63, 8}, {     43, 9}, \
+    {     23, 8}, {     55,10}, {     15, 9}, {     31, 8}, \
+    {     67, 9}, {     39, 8}, {     79, 9}, {     47, 8}, \
+    {     95, 9}, {     55,10}, {     31, 9}, {     79,10}, \
+    {     47, 9}, {     95,11}, {     31,10}, {     63, 9}, \
+    {    135,10}, {     79, 9}, {    159,10}, {     95,11}, \
+    {     63,10}, {    143, 9}, {    287,10}, {    159,11}, \
+    {     95,12}, {     63,11}, {    127, 9}, {    511, 5}, \
+    {   8959, 7}, {   2431, 8}, {   1247, 7}, {   2495, 8}, \
+    {   1279, 9}, {    671,10}, {    367,11}, {    191,10}, \
+    {    399, 9}, {    799,10}, {    415,12}, {    127,11}, \
+    {    255,10}, {    527,11}, {    287,10}, {    607,11}, \
+    {    319,10}, {    671,11}, {    351,10}, {    703,12}, \
+    {    191,11}, {    383,10}, {    799,11}, {    415,10}, \
+    {    831,13}, {    127,11}, {    543,10}, {   1119,11}, \
+    {    607,12}, {    319,11}, {    671,10}, {   1343,11}, \
+    {    735,12}, {    383,11}, {    863,12}, {    447,11}, \
+    {    991,12}, {    511,11}, {   1119,12}, {    575,11}, \
+    {   1215,12}, {    639,11}, {   1343,12}, {    703,13}, \
+    {    383,12}, {    767,11}, {   1599,12}, {    831,11}, \
+    {   1727,12}, {    959,11}, {   1983,13}, {    511,12}, \
+    {   1087,11}, {   2239,12}, {   1215,13}, {    639,12}, \
+    {   1471,13}, {    767,12}, {   1727,13}, {    895,12}, \
+    {   1983,14}, {    511,13}, {   1023,12}, {   2239,13}, \
+    {   1151,12}, {   2495,13}, {   1279,12}, {   2623,13}, \
+    {   1407,14}, {    767,13}, {   1663,12}, {   3455,13}, \
+    {   1919,15}, {    511,14}, {   1023,13}, {   2175,12}, \
+    {   4479,13}, {   2431,14}, {   1279,13}, {   2943,12}, \
+    {   5887,14}, {   1535,13}, {   3455,14}, {   1791,13}, \
+    {   3967,15}, {   1023,14}, {   2047,13}, {   4479,14}, \
+    {   2303,13}, {   4991,12}, {   9983,14}, {   2559,13}, \
+    {   5119,14}, {   2815,13}, {   5887,15}, {   1535,14}, \
+    {   3327,13}, {   6911,14}, {   3839,16} }
+#define SQR_FFT_TABLE3_SIZE 159
+#define SQR_FFT_THRESHOLD                 5568
+
+#define MULLO_BASECASE_THRESHOLD            17
+#define MULLO_DC_THRESHOLD                  40
+#define MULLO_MUL_N_THRESHOLD            14281
+#define SQRLO_BASECASE_THRESHOLD             0  /* always */
+#define SQRLO_DC_THRESHOLD                 141
+#define SQRLO_SQR_THRESHOLD              10821
+
+#define DC_DIV_QR_THRESHOLD                 30
+#define DC_DIVAPPR_Q_THRESHOLD             190
+#define DC_BDIV_QR_THRESHOLD                67
+#define DC_BDIV_Q_THRESHOLD                254
+
+#define INV_MULMOD_BNM1_THRESHOLD           54
+#define INV_NEWTON_THRESHOLD               157
+#define INV_APPR_THRESHOLD                 163
+
+#define BINV_NEWTON_THRESHOLD              236
+#define REDC_1_TO_REDC_N_THRESHOLD          79
+
+#define MU_DIV_QR_THRESHOLD               1895
+#define MU_DIVAPPR_Q_THRESHOLD            1718
+#define MUPI_DIV_QR_THRESHOLD               54
+#define MU_BDIV_QR_THRESHOLD              1589
+#define MU_BDIV_Q_THRESHOLD               1898
+
+#define POWM_SEC_TABLE  1,16,95,480,1442
+
+#define GET_STR_DC_THRESHOLD                10
+#define GET_STR_PRECOMPUTE_THRESHOLD        16
+#define SET_STR_DC_THRESHOLD               372
+#define SET_STR_PRECOMPUTE_THRESHOLD      1037
+
+#define FAC_DSC_THRESHOLD                  141
+#define FAC_ODD_THRESHOLD                   34
+
+#define MATRIX22_STRASSEN_THRESHOLD         21
+#define HGCD2_DIV1_METHOD                    3  /* 6.26% faster than 1 */
+#define HGCD_THRESHOLD                      70
+#define HGCD_APPR_THRESHOLD                129
+#define HGCD_REDUCE_THRESHOLD             3664
+#define GCD_DC_THRESHOLD                   573
+#define GCDEXT_DC_THRESHOLD                483
+#define JACOBI_BASE_METHOD                   1  /* 27.01% faster than 3 */
+
+/* Tuneup completed successfully, took 35232 seconds */
diff --git a/third_party/gmp/mpn/x86/coreinhm/gmp-mparam.h b/third_party/gmp/mpn/x86/coreinhm/gmp-mparam.h
new file mode 100644
index 0000000..4428b4b
--- /dev/null
+++ b/third_party/gmp/mpn/x86/coreinhm/gmp-mparam.h
@@ -0,0 +1,223 @@
+/* x86/coreinhm gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+/* 2933-3200 MHz Intel Xeon X3470 Nehalem */
+/* FFT tuning limit = 67,000,000 */
+/* Generated by tuneup.c, 2019-10-23, gcc 8.3 */
+
+#define MOD_1_NORM_THRESHOLD                36
+#define MOD_1_UNNORM_THRESHOLD              40
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          8
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          7
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        12
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD         0  /* never mpn_mod_1s_2p */
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD      3
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1N_PI1_METHOD                 1  /* 42.59% faster than 2 */
+#define DIV_QR_1_NORM_THRESHOLD          MP_SIZE_T_MAX  /* never */
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD               9
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           17
+
+#define DIV_1_VS_MUL_1_PERCENT             288
+
+#define MUL_TOOM22_THRESHOLD                24
+#define MUL_TOOM33_THRESHOLD                93
+#define MUL_TOOM44_THRESHOLD               214
+#define MUL_TOOM6H_THRESHOLD               306
+#define MUL_TOOM8H_THRESHOLD               430
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      93
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     134
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     145
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD      94
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     118
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 38
+#define SQR_TOOM3_THRESHOLD                133
+#define SQR_TOOM4_THRESHOLD                212
+#define SQR_TOOM6_THRESHOLD                318
+#define SQR_TOOM8_THRESHOLD                620
+
+#define MULMID_TOOM42_THRESHOLD             68
+
+#define MULMOD_BNM1_THRESHOLD               17
+#define SQRMOD_BNM1_THRESHOLD               23
+
+#define MUL_FFT_MODF_THRESHOLD             595  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    595, 5}, {     28, 6}, {     15, 5}, {     31, 6}, \
+    {     17, 5}, {     35, 6}, {     28, 7}, {     15, 6}, \
+    {     33, 7}, {     17, 6}, {     36, 7}, {     19, 6}, \
+    {     39, 7}, {     23, 6}, {     47, 7}, {     27, 8}, \
+    {     15, 7}, {     35, 8}, {     19, 7}, {     43, 8}, \
+    {     23, 7}, {     49, 8}, {     27, 9}, {     15, 8}, \
+    {     31, 7}, {     63, 8}, {     43, 9}, {     23, 8}, \
+    {     51, 9}, {     31, 8}, {     67, 9}, {     39, 8}, \
+    {     79, 9}, {     47, 8}, {     99, 9}, {     55,10}, \
+    {     31, 9}, {     63, 8}, {    127, 9}, {     79,10}, \
+    {     47, 9}, {     95,11}, {     31,10}, {     63, 9}, \
+    {    135,10}, {     79, 9}, {    159,10}, {     95, 9}, \
+    {    191,11}, {     63, 9}, {    255,10}, {    159,11}, \
+    {     95,10}, {    191,12}, {     63,11}, {    127,10}, \
+    {    255, 9}, {    511,10}, {    271, 9}, {    543,11}, \
+    {    159,10}, {    335,11}, {    191,10}, {    383, 9}, \
+    {    767,10}, {    399,12}, {    127,11}, {    255,10}, \
+    {    511, 9}, {   1023,10}, {    543, 9}, {   1087,11}, \
+    {    287,10}, {    607,11}, {    319,10}, {    671,12}, \
+    {    191,11}, {    383,10}, {    767,13}, {    127,12}, \
+    {    255,11}, {    511,10}, {   1023,11}, {    543,10}, \
+    {   1119,11}, {    607,12}, {    319,11}, {    671,10}, \
+    {   1343,11}, {    735,10}, {   1471,12}, {    383,11}, \
+    {    799,10}, {   1599,11}, {    863,10}, {   1727,12}, \
+    {    447,11}, {    959,13}, {    255,12}, {    511,11}, \
+    {   1119,12}, {    575,11}, {   1215,10}, {   2431,12}, \
+    {    639,11}, {   1343,12}, {    703,11}, {   1471,10}, \
+    {   2943,13}, {    383,12}, {    767,11}, {   1599,12}, \
+    {    831,11}, {   1727,10}, {   3455,12}, {    959,14}, \
+    {    255,13}, {    511,12}, {   1087,11}, {   2239,10}, \
+    {   4479,12}, {   1215,11}, {   2431,13}, {    639,12}, \
+    {   1471,11}, {   2943,13}, {    767,12}, {   1727,11}, \
+    {   3455,13}, {    895,12}, {   1983,14}, {    511,13}, \
+    {   1023,12}, {   2239,11}, {   4479,13}, {   1151,12}, \
+    {   2431,13}, {   1279,12}, {   2559,13}, {   1407,12}, \
+    {   2943,11}, {   5887,14}, {    767,13}, {   1663,12}, \
+    {   3455,13}, {   1919,12}, {   3839,15}, {    511,14}, \
+    {   1023,13}, {   2175,12}, {   4479,13}, {   2431,14}, \
+    {   1279,13}, {   2943,12}, {   5887,14}, {   1535,13}, \
+    {   3455,14}, {   1791,13}, {   3967,15}, {   1023,14}, \
+    {   2047,13}, {   4479,14}, {   2303,13}, {   4991,12}, \
+    {   9983,14}, {   2815,13}, {   6015,15}, {   1535,14}, \
+    {   3839,13}, {   7679,16} }
+#define MUL_FFT_TABLE3_SIZE 170
+#define MUL_FFT_THRESHOLD                 6784
+
+#define SQR_FFT_MODF_THRESHOLD             525  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    525, 5}, {     29, 6}, {     15, 5}, {     33, 6}, \
+    {     17, 5}, {     35, 6}, {     29, 7}, {     15, 6}, \
+    {     33, 7}, {     17, 6}, {     35, 7}, {     19, 6}, \
+    {     39, 7}, {     23, 6}, {     47, 7}, {     29, 8}, \
+    {     15, 7}, {     35, 8}, {     19, 7}, {     41, 8}, \
+    {     23, 7}, {     49, 8}, {     27, 7}, {     55, 9}, \
+    {     15, 8}, {     31, 7}, {     63, 8}, {     39, 9}, \
+    {     23, 8}, {     55, 9}, {     31, 8}, {     67, 9}, \
+    {     39, 8}, {     79, 9}, {     47, 8}, {     95, 9}, \
+    {     55,10}, {     31, 9}, {     79,10}, {     47, 9}, \
+    {     95,11}, {     31,10}, {     63, 9}, {    135,10}, \
+    {     79, 9}, {    159,10}, {     95,11}, {     63,10}, \
+    {    143, 9}, {    287,10}, {    159, 6}, {   2687, 7}, \
+    {   1407, 9}, {    367, 8}, {    735, 9}, {    383,10}, \
+    {    207, 9}, {    415,11}, {    127,10}, {    271, 9}, \
+    {    543,10}, {    287,11}, {    159,10}, {    319, 9}, \
+    {    639,10}, {    335, 9}, {    671,10}, {    351,11}, \
+    {    191,10}, {    383, 9}, {    767,10}, {    399, 9}, \
+    {    799,10}, {    415,12}, {    127,11}, {    255,10}, \
+    {    511, 9}, {   1023,10}, {    543,11}, {    287,10}, \
+    {    607,11}, {    319,10}, {    671,11}, {    351,12}, \
+    {    191,11}, {    383,10}, {    799,11}, {    415,13}, \
+    {    127,12}, {    255,11}, {    511,10}, {   1023,11}, \
+    {    543,10}, {   1087,11}, {    607,10}, {   1215,12}, \
+    {    319,11}, {    671,10}, {   1343,11}, {    735,10}, \
+    {   1471,12}, {    383,11}, {    799,10}, {   1599,11}, \
+    {    863,10}, {   1727,12}, {    447,11}, {    991,10}, \
+    {   1983,13}, {    255,12}, {    511,11}, {   1119,12}, \
+    {    575,11}, {   1215,10}, {   2431,12}, {    639,11}, \
+    {   1343,12}, {    703,11}, {   1471,13}, {    383,12}, \
+    {    767,11}, {   1599,12}, {    831,11}, {   1727,10}, \
+    {   3455,12}, {    895,11}, {   1791,12}, {    959,11}, \
+    {   1983,14}, {    255,13}, {    511,12}, {   1023,11}, \
+    {   2047,12}, {   1087,11}, {   2239,12}, {   1215,11}, \
+    {   2431,13}, {    639,12}, {   1471,11}, {   2943,13}, \
+    {    767,12}, {   1727,11}, {   3455,13}, {    895,12}, \
+    {   1983,11}, {   3967,14}, {    511,13}, {   1023,12}, \
+    {   2239,13}, {   1151,12}, {   2495,13}, {   1279,12}, \
+    {   2623,13}, {   1407,12}, {   2943,14}, {    767,13}, \
+    {   1663,12}, {   3455,13}, {   1919,12}, {   3967,15}, \
+    {    511,14}, {   1023,13}, {   2175,12}, {   4479,13}, \
+    {   2431,12}, {   4863,14}, {   1279,13}, {   2943,12}, \
+    {   5887,14}, {   1535,13}, {   3455,14}, {   1791,13}, \
+    {   3967,12}, {   7935,15}, {   1023,14}, {   2047,13}, \
+    {   4479,14}, {   2303,13}, {   4991,12}, {   9983,14}, \
+    {   2815,13}, {   5887,15}, {   1535,14}, {   3327,13}, \
+    {   6655,14}, {   3839,13}, {   7935,16} }
+#define SQR_FFT_TABLE3_SIZE 187
+#define SQR_FFT_THRESHOLD                 5312
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  43
+#define MULLO_MUL_N_THRESHOLD            13463
+#define SQRLO_BASECASE_THRESHOLD             9
+#define SQRLO_DC_THRESHOLD                  42
+#define SQRLO_SQR_THRESHOLD              10323
+
+#define DC_DIV_QR_THRESHOLD                 43
+#define DC_DIVAPPR_Q_THRESHOLD             132
+#define DC_BDIV_QR_THRESHOLD                83
+#define DC_BDIV_Q_THRESHOLD                130
+
+#define INV_MULMOD_BNM1_THRESHOLD           46
+#define INV_NEWTON_THRESHOLD               189
+#define INV_APPR_THRESHOLD                 167
+
+#define BINV_NEWTON_THRESHOLD              372
+#define REDC_1_TO_REDC_N_THRESHOLD          83
+
+#define MU_DIV_QR_THRESHOLD               1589
+#define MU_DIVAPPR_Q_THRESHOLD            1589
+#define MUPI_DIV_QR_THRESHOLD               97
+#define MU_BDIV_QR_THRESHOLD              1589
+#define MU_BDIV_Q_THRESHOLD               1718
+
+#define POWM_SEC_TABLE  1,28,96,473,803
+
+#define GET_STR_DC_THRESHOLD                12
+#define GET_STR_PRECOMPUTE_THRESHOLD        16
+#define SET_STR_DC_THRESHOLD               145
+#define SET_STR_PRECOMPUTE_THRESHOLD       419
+
+#define FAC_DSC_THRESHOLD                  114
+#define FAC_ODD_THRESHOLD                   57
+
+#define MATRIX22_STRASSEN_THRESHOLD         20
+#define HGCD2_DIV1_METHOD                    1  /* 1.03% faster than 3 */
+#define HGCD_THRESHOLD                     117
+#define HGCD_APPR_THRESHOLD                137
+#define HGCD_REDUCE_THRESHOLD             3524
+#define GCD_DC_THRESHOLD                   389
+#define GCDEXT_DC_THRESHOLD                318
+#define JACOBI_BASE_METHOD                   4  /* 6.10% faster than 1 */
+
+/* Tuneup completed successfully, took 67994 seconds */
diff --git a/third_party/gmp/mpn/x86/coreisbr/gmp-mparam.h b/third_party/gmp/mpn/x86/coreisbr/gmp-mparam.h
new file mode 100644
index 0000000..23d708a
--- /dev/null
+++ b/third_party/gmp/mpn/x86/coreisbr/gmp-mparam.h
@@ -0,0 +1,215 @@
+/* x86/coreisbr gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+/* 3400-3800 MHz Intel Xeon E3-1270 Sandy Bridge */
+/* FFT tuning limit = 67,000,000 */
+/* Generated by tuneup.c, 2019-10-24, gcc 8.3 */
+
+#define MOD_1_NORM_THRESHOLD                28
+#define MOD_1_UNNORM_THRESHOLD              26
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          9
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          7
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        11
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD         0  /* never mpn_mod_1s_2p */
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD      4
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1N_PI1_METHOD                 2  /* 88.29% faster than 1 */
+#define DIV_QR_1_NORM_THRESHOLD             21
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD              14
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           20
+
+#define DIV_1_VS_MUL_1_PERCENT             297
+
+#define MUL_TOOM22_THRESHOLD                32
+#define MUL_TOOM33_THRESHOLD               105
+#define MUL_TOOM44_THRESHOLD               190
+#define MUL_TOOM6H_THRESHOLD               294
+#define MUL_TOOM8H_THRESHOLD               478
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD     109
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     144
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     116
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     129
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     160
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 48
+#define SQR_TOOM3_THRESHOLD                163
+#define SQR_TOOM4_THRESHOLD                250
+#define SQR_TOOM6_THRESHOLD                354
+#define SQR_TOOM8_THRESHOLD                502
+
+#define MULMID_TOOM42_THRESHOLD             98
+
+#define MULMOD_BNM1_THRESHOLD               19
+#define SQRMOD_BNM1_THRESHOLD               23
+
+#define MUL_FFT_MODF_THRESHOLD             666  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    666, 5}, {     28, 6}, {     15, 5}, {     31, 6}, \
+    {     28, 7}, {     15, 6}, {     33, 7}, {     17, 6}, \
+    {     36, 7}, {     19, 6}, {     39, 7}, {     23, 6}, \
+    {     47, 7}, {     29, 8}, {     15, 7}, {     35, 8}, \
+    {     19, 7}, {     41, 8}, {     23, 7}, {     49, 8}, \
+    {     27, 7}, {     55, 8}, {     31, 7}, {     63, 8}, \
+    {     43, 9}, {     23, 8}, {     55, 9}, {     31, 8}, \
+    {     71, 9}, {     39, 8}, {     79, 9}, {     47, 8}, \
+    {     99, 9}, {     55,10}, {     31, 9}, {     79,10}, \
+    {     47, 9}, {     95,11}, {     31,10}, {     63, 9}, \
+    {    135,10}, {     79, 9}, {    159,10}, {     95, 9}, \
+    {    191,11}, {     63,10}, {    159, 7}, {   1343, 8}, \
+    {    703, 9}, {    367, 8}, {    735, 9}, {    383,10}, \
+    {    207,11}, {    127,10}, {    255, 9}, {    511,10}, \
+    {    271, 9}, {    543,10}, {    287,11}, {    159,10}, \
+    {    319, 9}, {    639,10}, {    335,11}, {    191,10}, \
+    {    383, 9}, {    767,11}, {    223,12}, {    127,11}, \
+    {    255,10}, {    543,11}, {    287,10}, {    607, 9}, \
+    {   1215,11}, {    319,10}, {    671,12}, {    191,11}, \
+    {    383,10}, {    799,13}, {    127,12}, {    255,11}, \
+    {    511,10}, {   1023,11}, {    543,10}, {   1087,11}, \
+    {    607,10}, {   1215,12}, {    319,11}, {    671,10}, \
+    {   1343,11}, {    735,10}, {   1471,12}, {    383,11}, \
+    {    799,10}, {   1599,11}, {    863,12}, {    447,11}, \
+    {    959,13}, {    255,12}, {    511,11}, {   1087,12}, \
+    {    575,11}, {   1215,12}, {    639,11}, {   1343,12}, \
+    {    703,11}, {   1471,13}, {    383,12}, {    767,11}, \
+    {   1599,12}, {    831,11}, {   1727,12}, {    959,14}, \
+    {    255,13}, {    511,12}, {   1087,11}, {   2239,12}, \
+    {   1215,13}, {    639,12}, {   1471,11}, {   2943,13}, \
+    {    767,12}, {   1727,11}, {   3455,13}, {    895,12}, \
+    {   1983,14}, {    511,13}, {   1023,12}, {   2239,13}, \
+    {   1151,12}, {   2495,13}, {   1279,12}, {   2623,13}, \
+    {   1407,12}, {   2943,14}, {    767,13}, {   1535,12}, \
+    {   3071,13}, {   1663,12}, {   3455,13}, {   1919,15}, \
+    {    511,14}, {   1023,13}, {   2175,12}, {   4479,13}, \
+    {   2431,14}, {   1279,13}, {   2943,12}, {   5887,14}, \
+    {   1535,13}, {   3455,14}, {   1791,13}, {   3967,15}, \
+    {   1023,14}, {   2047,13}, {   4479,14}, {   2303,13}, \
+    {   4991,12}, {   9983,14}, {   2815,13}, {   5887,15}, \
+    {   1535,14}, {   3839,13}, {   7679,16} }
+#define MUL_FFT_TABLE3_SIZE 163
+#define MUL_FFT_THRESHOLD                 7552
+
+#define SQR_FFT_MODF_THRESHOLD             570  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    570, 5}, {     28, 6}, {     15, 5}, {     32, 6}, \
+    {     17, 5}, {     35, 6}, {     29, 7}, {     15, 6}, \
+    {     33, 7}, {     17, 6}, {     36, 7}, {     19, 6}, \
+    {     40, 7}, {     23, 6}, {     47, 7}, {     29, 8}, \
+    {     15, 7}, {     35, 8}, {     19, 7}, {     43, 8}, \
+    {     23, 7}, {     49, 8}, {     27, 7}, {     55, 8}, \
+    {     31, 7}, {     63, 8}, {     43, 9}, {     23, 8}, \
+    {     55, 9}, {     31, 8}, {     67, 9}, {     39, 8}, \
+    {     79, 9}, {     47, 8}, {     95, 9}, {     55,10}, \
+    {     31, 9}, {     79,10}, {     47, 9}, {     95,11}, \
+    {     31,10}, {     63, 9}, {    135,10}, {     79, 9}, \
+    {    159,10}, {     95,11}, {     63,10}, {    159,11}, \
+    {     95,10}, {    191,12}, {     63, 8}, {   1023, 9}, \
+    {    543,11}, {    159,10}, {    319, 9}, {    639,10}, \
+    {    335,11}, {    191,10}, {    383, 9}, {    767,10}, \
+    {    399, 9}, {    799,12}, {    127,11}, {    255,10}, \
+    {    511, 9}, {   1023,10}, {    543,11}, {    287,10}, \
+    {    607,11}, {    319,10}, {    671,11}, {    351,12}, \
+    {    191,11}, {    383,10}, {    799,13}, {    127,12}, \
+    {    255,11}, {    511,10}, {   1023,11}, {    543,10}, \
+    {   1087,11}, {    607,12}, {    319,11}, {    671,10}, \
+    {   1343,11}, {    735,10}, {   1471,12}, {    383,11}, \
+    {    799,10}, {   1599,11}, {    863,12}, {    447,11}, \
+    {    991,13}, {    255,12}, {    511,11}, {   1087,12}, \
+    {    575,11}, {   1215,12}, {    639,11}, {   1343,12}, \
+    {    703,11}, {   1471,13}, {    383,12}, {    767,11}, \
+    {   1599,12}, {    831,11}, {   1727,12}, {    959,11}, \
+    {   1919,14}, {    255,13}, {    511,12}, {   1023,11}, \
+    {   2047,12}, {   1087,11}, {   2239,12}, {   1215,11}, \
+    {   2431,13}, {    639,12}, {   1471,13}, {    767,12}, \
+    {   1727,13}, {    895,12}, {   1983,14}, {    511,13}, \
+    {   1023,12}, {   2239,13}, {   1151,12}, {   2495,13}, \
+    {   1279,12}, {   2623,13}, {   1407,12}, {   2943,14}, \
+    {    767,13}, {   1663,12}, {   3455,13}, {   1919,12}, \
+    {   3967,15}, {    511,14}, {   1023,13}, {   2175,12}, \
+    {   4479,13}, {   2431,12}, {   4863,14}, {   1279,13}, \
+    {   2943,12}, {   5887,14}, {   1535,13}, {   3455,14}, \
+    {   1791,13}, {   3967,15}, {   1023,14}, {   2047,13}, \
+    {   4479,14}, {   2303,13}, {   4991,12}, {   9983,14}, \
+    {   2559,13}, {   5119,14}, {   2815,13}, {   5887,15}, \
+    {   1535,14}, {   3839,13}, {   7679,16} }
+#define SQR_FFT_TABLE3_SIZE 163
+#define SQR_FFT_THRESHOLD                 5760
+
+#define MULLO_BASECASE_THRESHOLD            16
+#define MULLO_DC_THRESHOLD                  46
+#define MULLO_MUL_N_THRESHOLD            14281
+#define SQRLO_BASECASE_THRESHOLD             0  /* always */
+#define SQRLO_DC_THRESHOLD                 159
+#define SQRLO_SQR_THRESHOLD              11317
+
+#define DC_DIV_QR_THRESHOLD                 47
+#define DC_DIVAPPR_Q_THRESHOLD             191
+#define DC_BDIV_QR_THRESHOLD               107
+#define DC_BDIV_Q_THRESHOLD                232
+
+#define INV_MULMOD_BNM1_THRESHOLD           62
+#define INV_NEWTON_THRESHOLD               181
+#define INV_APPR_THRESHOLD                 182
+
+#define BINV_NEWTON_THRESHOLD              378
+#define REDC_1_TO_REDC_N_THRESHOLD          91
+
+#define MU_DIV_QR_THRESHOLD               1858
+#define MU_DIVAPPR_Q_THRESHOLD            1858
+#define MUPI_DIV_QR_THRESHOLD               77
+#define MU_BDIV_QR_THRESHOLD              1830
+#define MU_BDIV_Q_THRESHOLD               2166
+
+#define POWM_SEC_TABLE  1,16,126,428,1442
+
+#define GET_STR_DC_THRESHOLD                10
+#define GET_STR_PRECOMPUTE_THRESHOLD        16
+#define SET_STR_DC_THRESHOLD               418
+#define SET_STR_PRECOMPUTE_THRESHOLD      1104
+
+#define FAC_DSC_THRESHOLD                  149
+#define FAC_ODD_THRESHOLD                   34
+
+#define MATRIX22_STRASSEN_THRESHOLD         21
+#define HGCD2_DIV1_METHOD                    1  /* 5.54% faster than 4 */
+#define HGCD_THRESHOLD                      66
+#define HGCD_APPR_THRESHOLD                135
+#define HGCD_REDUCE_THRESHOLD             4284
+#define GCD_DC_THRESHOLD                   642
+#define GCDEXT_DC_THRESHOLD                465
+#define JACOBI_BASE_METHOD                   3  /* 14.76% faster than 4 */
+
+/* Tuneup completed successfully, took 44241 seconds */
diff --git a/third_party/gmp/mpn/x86/darwin.m4 b/third_party/gmp/mpn/x86/darwin.m4
new file mode 100644
index 0000000..c449216
--- /dev/null
+++ b/third_party/gmp/mpn/x86/darwin.m4
@@ -0,0 +1,102 @@
+divert(-1)
+dnl  Copyright 2007, 2011, 2012, 2014 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+define(`DARWIN')
+
+
+dnl  Usage LEA(symbol,reg)
+dnl  Usage LEAL(symbol_local_to_file,reg)
+dnl
+dnl  We maintain lists of stuff to append in load_eip and darwin_bd.  The
+dnl  `index' stuff is needed to suppress repeated definitions.  To avoid
+dnl  getting fooled by "var" and "var1", we add 'bol ' (the end of
+dnl  'indirect_symbol') at the beginning and and a newline at the end.  This
+dnl  might be a bit fragile.
+
+define(`LEA',
+m4_assert_numargs(2)
+`ifdef(`PIC',`
+ifelse(index(defn(`load_eip'), `$2'),-1,
+`m4append(`load_eip',
+`	TEXT
+	ALIGN(16)
+L(movl_eip_`'substr($2,1)):
+	movl	(%esp), $2
+	ret_internal
+')')
+ifelse(index(defn(`darwin_bd'), `bol $1
+'),-1,
+`m4append(`darwin_bd',
+`	.section __IMPORT,__pointers,non_lazy_symbol_pointers
+L($1`'$non_lazy_ptr):
+	.indirect_symbol $1
+	.long	 0
+')')
+	call	L(movl_eip_`'substr($2,1))
+	movl	L($1`'$non_lazy_ptr)-.($2), $2
+',`
+	movl	`$'$1, $2
+')')
+
+define(`LEAL',
+m4_assert_numargs(2)
+`ifdef(`PIC',`
+ifelse(index(defn(`load_eip'), `$2'),-1,
+`m4append(`load_eip',
+`	TEXT
+	ALIGN(16)
+L(movl_eip_`'substr($2,1)):
+	movl	(%esp), $2
+	ret_internal
+')')
+	call	L(movl_eip_`'substr($2,1))
+	leal	$1-.($2), $2
+',`
+	movl	`$'$1, $2
+')')
+
+
+dnl ASM_END
+
+define(`ASM_END',`load_eip`'darwin_bd')
+
+define(`load_eip', `')		dnl updated in LEA
+define(`darwin_bd', `')		dnl updated in LEA
+
+
+dnl  Usage: CALL(funcname)
+dnl
+
+define(`CALL',
+m4_assert_numargs(1)
+`call	GSYM_PREFIX`'$1')
+
+undefine(`PIC_WITH_EBX')
+
+divert`'dnl
diff --git a/third_party/gmp/mpn/x86/dive_1.asm b/third_party/gmp/mpn/x86/dive_1.asm
new file mode 100644
index 0000000..5bb0f45
--- /dev/null
+++ b/third_party/gmp/mpn/x86/dive_1.asm
@@ -0,0 +1,190 @@
+dnl  x86 mpn_divexact_1 -- mpn by limb exact division.
+
+dnl  Copyright 2001, 2002, 2007 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C     cycles/limb
+C P54    30.0
+C P55    29.0
+C P6     13.0 odd divisor, 12.0 even (strangely)
+C K6     14.0
+C K7     12.0
+C P4     42.0
+
+
+C mp_limb_t mpn_divexact_1 (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                           mp_limb_t divisor);
+C
+
+defframe(PARAM_DIVISOR,16)
+defframe(PARAM_SIZE,   12)
+defframe(PARAM_SRC,    8)
+defframe(PARAM_DST,    4)
+
+dnl  re-use parameter space
+define(VAR_INVERSE,`PARAM_SRC')
+
+	TEXT
+
+	ALIGN(16)
+PROLOGUE(mpn_divexact_1)
+deflit(`FRAME',0)
+
+	movl	PARAM_DIVISOR, %eax
+	pushl	%ebp	FRAME_pushl()
+
+	movl	PARAM_SIZE, %ebp
+	pushl	%edi	FRAME_pushl()
+
+	pushl	%ebx	FRAME_pushl()
+	movl	$-1, %ecx		C shift count
+
+	pushl	%esi	FRAME_pushl()
+
+L(strip_twos):
+	incl	%ecx
+
+	shrl	%eax
+	jnc	L(strip_twos)
+
+	leal	1(%eax,%eax), %ebx	C d without twos
+	andl	$127, %eax		C d/2, 7 bits
+
+ifdef(`PIC',`
+	LEA(	binvert_limb_table, %edx)
+	movzbl	(%eax,%edx), %eax		C inv 8 bits
+',`
+	movzbl	binvert_limb_table(%eax), %eax	C inv 8 bits
+')
+
+	leal	(%eax,%eax), %edx	C 2*inv
+	movl	%ebx, PARAM_DIVISOR	C d without twos
+
+	imull	%eax, %eax		C inv*inv
+
+	movl	PARAM_SRC, %esi
+	movl	PARAM_DST, %edi
+
+	imull	%ebx, %eax		C inv*inv*d
+
+	subl	%eax, %edx		C inv = 2*inv - inv*inv*d
+	leal	(%edx,%edx), %eax	C 2*inv
+
+	imull	%edx, %edx		C inv*inv
+
+	leal	(%esi,%ebp,4), %esi	C src end
+	leal	(%edi,%ebp,4), %edi	C dst end
+	negl	%ebp			C -size
+
+	imull	%ebx, %edx		C inv*inv*d
+
+	subl	%edx, %eax		C inv = 2*inv - inv*inv*d
+
+	ASSERT(e,`	C expect d*inv == 1 mod 2^GMP_LIMB_BITS
+	pushl	%eax	FRAME_pushl()
+	imull	PARAM_DIVISOR, %eax
+	cmpl	$1, %eax
+	popl	%eax	FRAME_popl()')
+
+	movl	%eax, VAR_INVERSE
+	movl	(%esi,%ebp,4), %eax	C src[0]
+
+	xorl	%ebx, %ebx
+	xorl	%edx, %edx
+
+	incl	%ebp
+	jz	L(one)
+
+	movl	(%esi,%ebp,4), %edx	C src[1]
+
+	shrdl(	%cl, %edx, %eax)
+
+	movl	VAR_INVERSE, %edx
+	jmp	L(entry)
+
+
+	ALIGN(8)
+	nop	C k6 code alignment
+	nop
+L(top):
+	C eax	q
+	C ebx	carry bit, 0 or -1
+	C ecx	shift
+	C edx	carry limb
+	C esi	src end
+	C edi	dst end
+	C ebp	counter, limbs, negative
+
+	movl	-4(%esi,%ebp,4), %eax
+	subl	%ebx, %edx		C accumulate carry bit
+
+	movl	(%esi,%ebp,4), %ebx
+
+	shrdl(	%cl, %ebx, %eax)
+
+	subl	%edx, %eax		C apply carry limb
+	movl	VAR_INVERSE, %edx
+
+	sbbl	%ebx, %ebx
+
+L(entry):
+	imull	%edx, %eax
+
+	movl	%eax, -4(%edi,%ebp,4)
+	movl	PARAM_DIVISOR, %edx
+
+	mull	%edx
+
+	incl	%ebp
+	jnz	L(top)
+
+
+	movl	-4(%esi), %eax		C src high limb
+L(one):
+	shrl	%cl, %eax
+	popl	%esi	FRAME_popl()
+
+	addl	%ebx, %eax		C apply carry bit
+	popl	%ebx	FRAME_popl()
+
+	subl	%edx, %eax		C apply carry limb
+
+	imull	VAR_INVERSE, %eax
+
+	movl	%eax, -4(%edi)
+
+	popl	%edi
+	popl	%ebp
+
+	ret
+
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86/divrem_1.asm b/third_party/gmp/mpn/x86/divrem_1.asm
new file mode 100644
index 0000000..255d493
--- /dev/null
+++ b/third_party/gmp/mpn/x86/divrem_1.asm
@@ -0,0 +1,233 @@
+dnl  x86 mpn_divrem_1 -- mpn by limb division extending to fractional quotient.
+
+dnl  Copyright 1999-2003, 2007 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C       cycles/limb
+C 486   approx 43 maybe
+C P5        44
+C P6        39
+C P6MMX     39
+C K6        22
+C K7        42
+C P4        58
+
+
+C mp_limb_t mpn_divrem_1 (mp_ptr dst, mp_size_t xsize,
+C                         mp_srcptr src, mp_size_t size, mp_limb_t divisor);
+C mp_limb_t mpn_divrem_1c (mp_ptr dst, mp_size_t xsize,
+C                          mp_srcptr src, mp_size_t size, mp_limb_t divisor,
+C                          mp_limb_t carry);
+C
+C Divide src,size by divisor and store the quotient in dst+xsize,size.
+C Extend the division to fractional quotient limbs in dst,xsize.  Return the
+C remainder.  Either or both xsize and size can be 0.
+C
+C mpn_divrem_1c takes a carry parameter which is an initial high limb,
+C effectively one extra limb at the top of src,size.  Must have
+C carry<divisor.
+C
+C
+C Essentially the code is the same as the division based part of
+C mpn/generic/divrem_1.c, but has the advantage that we get the desired divl
+C instruction even when gcc is not being used (when longlong.h only has the
+C rather slow generic C udiv_qrnnd().
+C
+C A test is done to see if the high limb is less than the divisor, and if so
+C one less div is done.  A div is between 20 and 40 cycles on the various
+C x86s, so assuming high<divisor about half the time, then this test saves
+C half that amount.  The branch misprediction penalty on each chip is less
+C than half a div.
+C
+C
+C Notes for P5:
+C
+C It might be thought that moving the load down to pair with the store would
+C save 1 cycle, but that doesn't seem to happen in practice, and in any case
+C would be a mere 2.2% saving, so it's hardly worth bothering about.
+C
+C A mul-by-inverse might be a possibility for P5, as done in
+C mpn/x86/pentium/mod_1.asm.  The number of auxiliary instructions required
+C is a hinderance, but there could be a 10-15% speedup available.
+C
+C
+C Notes for K6:
+C
+C K6 has its own version of this code, using loop and paying attention to
+C cache line boundary crossings.  The target 20 c/l can be had with the
+C decl+jnz of the present code by pairing up the load and store in the
+C loops.  But it's considered easier not to introduce complexity just for
+C that, but instead let k6 have its own code.
+C
+
+defframe(PARAM_CARRY,  24)
+defframe(PARAM_DIVISOR,20)
+defframe(PARAM_SIZE,   16)
+defframe(PARAM_SRC,    12)
+defframe(PARAM_XSIZE,  8)
+defframe(PARAM_DST,    4)
+
+	TEXT
+	ALIGN(16)
+
+PROLOGUE(mpn_divrem_1c)
+deflit(`FRAME',0)
+
+	movl	PARAM_SIZE, %ecx
+	pushl	%edi		FRAME_pushl()
+
+	movl	PARAM_SRC, %edi
+	pushl	%esi		FRAME_pushl()
+
+	movl	PARAM_DIVISOR, %esi
+	pushl	%ebx		FRAME_pushl()
+
+	movl	PARAM_DST, %ebx
+	pushl	%ebp		FRAME_pushl()
+
+	movl	PARAM_XSIZE, %ebp
+	orl	%ecx, %ecx
+
+	movl	PARAM_CARRY, %edx
+	jz	L(fraction)
+
+	leal	-4(%ebx,%ebp,4), %ebx	C dst one limb below integer part
+	jmp	L(integer_top)
+
+EPILOGUE()
+
+
+PROLOGUE(mpn_divrem_1)
+deflit(`FRAME',0)
+
+	movl	PARAM_SIZE, %ecx
+	pushl	%edi		FRAME_pushl()
+
+	movl	PARAM_SRC, %edi
+	pushl	%esi		FRAME_pushl()
+
+	movl	PARAM_DIVISOR, %esi
+	orl	%ecx,%ecx
+
+	jz	L(size_zero)
+	pushl	%ebx		FRAME_pushl()
+
+	movl	-4(%edi,%ecx,4), %eax	C src high limb
+	xorl	%edx, %edx
+
+	movl	PARAM_DST, %ebx
+	pushl	%ebp		FRAME_pushl()
+
+	movl	PARAM_XSIZE, %ebp
+	cmpl	%esi, %eax
+
+	leal	-4(%ebx,%ebp,4), %ebx	C dst one limb below integer part
+	jae	L(integer_entry)
+
+
+	C high<divisor, so high of dst is zero, and avoid one div
+
+	movl	%edx, (%ebx,%ecx,4)
+	decl	%ecx
+
+	movl	%eax, %edx
+	jz	L(fraction)
+
+
+L(integer_top):
+	C eax	scratch (quotient)
+	C ebx	dst+4*xsize-4
+	C ecx	counter
+	C edx	scratch (remainder)
+	C esi	divisor
+	C edi	src
+	C ebp	xsize
+
+	movl	-4(%edi,%ecx,4), %eax
+L(integer_entry):
+
+	divl	%esi
+
+	movl	%eax, (%ebx,%ecx,4)
+	decl	%ecx
+	jnz	L(integer_top)
+
+
+L(fraction):
+	orl	%ebp, %ecx
+	jz	L(done)
+
+	movl	PARAM_DST, %ebx
+
+
+L(fraction_top):
+	C eax	scratch (quotient)
+	C ebx	dst
+	C ecx	counter
+	C edx	scratch (remainder)
+	C esi	divisor
+	C edi
+	C ebp
+
+	xorl	%eax, %eax
+
+	divl	%esi
+
+	movl	%eax, -4(%ebx,%ecx,4)
+	decl	%ecx
+	jnz	L(fraction_top)
+
+
+L(done):
+	popl	%ebp
+	movl	%edx, %eax
+	popl	%ebx
+	popl	%esi
+	popl	%edi
+	ret
+
+
+L(size_zero):
+deflit(`FRAME',8)
+	movl	PARAM_XSIZE, %ecx
+	xorl	%eax, %eax
+
+	movl	PARAM_DST, %edi
+
+	cld	C better safe than sorry, see mpn/x86/README
+
+	rep
+	stosl
+
+	popl	%esi
+	popl	%edi
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/divrem_2.asm b/third_party/gmp/mpn/x86/divrem_2.asm
new file mode 100644
index 0000000..4c38ad0
--- /dev/null
+++ b/third_party/gmp/mpn/x86/divrem_2.asm
@@ -0,0 +1,199 @@
+dnl  x86 mpn_divrem_2 -- Divide an mpn number by a normalized 2-limb number.
+
+dnl  Copyright 2007, 2008 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C		norm	frac
+C 486
+C P5
+C P6-13		29.2
+C P6-15		*26
+C K6
+C K7		22
+C K8		*19
+C P4-f1
+C P4-f2		*65
+C P4-f3
+C P4-f4		*72
+
+C A star means numbers not updated for the latest version of the code.
+
+
+C TODO
+C  * Perhaps keep ecx or esi in stack slot, freeing up a reg for q0.
+C  * The loop has not been carefully tuned.  We should at the very least do
+C    some local insn swapping.
+C  * The code outside the main loop is what gcc generated.  Clean up!
+C  * Clean up stack slot usage.
+
+C INPUT PARAMETERS
+C qp
+C fn
+C up_param
+C un_param
+C dp
+
+
+C eax ebx ecx edx esi edi ebp
+C         cnt         qp
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_divrem_2)
+	push	%ebp
+	push	%edi
+	push	%esi
+	push	%ebx
+	sub	$36, %esp
+	mov	68(%esp), %ecx		C un
+	mov	72(%esp), %esi		C dp
+	movl	$0, 32(%esp)
+	lea	0(,%ecx,4), %edi
+	add	64(%esp), %edi		C up
+	mov	(%esi), %ebx
+	mov	4(%esi), %eax
+	mov	%ebx, 20(%esp)
+	sub	$12, %edi
+	mov	%eax, 24(%esp)
+	mov	%edi, 12(%esp)
+	mov	8(%edi), %ebx
+	mov	4(%edi), %ebp
+	cmp	%eax, %ebx
+	jb	L(8)
+	seta	%dl
+	cmp	20(%esp), %ebp
+	setae	%al
+	orb	%dl, %al		C "orb" form to placate Sun tools
+	jne	L(35)
+L(8):
+	mov	60(%esp), %esi		C fn
+	lea	-3(%esi,%ecx), %edi
+	test	%edi, %edi
+	js	L(9)
+	mov	24(%esp), %edx
+	mov	$-1, %esi
+	mov	%esi, %eax
+	mov	%esi, %ecx
+	not	%edx
+	divl	24(%esp)
+	mov	%eax, %esi
+	imul	24(%esp), %eax
+	mov	%eax, (%esp)
+	mov	%esi, %eax
+	mull	20(%esp)
+	mov	(%esp), %eax
+	add	20(%esp), %eax
+	adc	$0, %ecx
+	add	%eax, %edx
+	adc	$0, %ecx
+	mov	%ecx, %eax
+	js	L(32)
+L(36):	dec	%esi
+	sub	24(%esp), %edx
+	sbb	$0, %eax
+	jns	L(36)
+L(32):
+	mov	%esi, 16(%esp)		C di
+	mov	%edi, %ecx		C un
+	mov	12(%esp), %esi		C up
+	mov	24(%esp), %eax
+	neg	%eax
+	mov	%eax, 4(%esp)		C -d1
+	ALIGN(16)
+	nop
+
+C eax ebx ecx edx esi edi ebp  0    4   8   12  16  20  24  28  32   56  60
+C     n2  un      up      n1   q0  -d1          di  d0  d1      msl  qp  fn
+
+L(loop):
+	mov	16(%esp), %eax		C di
+	mul	%ebx
+	add	%ebp, %eax
+	mov	%eax, (%esp)		C q0
+	adc	%ebx, %edx
+	mov	%edx, %edi		C q
+	imul	4(%esp), %edx
+	mov	20(%esp), %eax
+	lea	(%edx, %ebp), %ebx	C n1 -= ...
+	mul	%edi
+	xor	%ebp, %ebp
+	cmp	60(%esp), %ecx
+	jl	L(19)
+	mov	(%esi), %ebp
+	sub	$4, %esi
+L(19):	sub	20(%esp), %ebp
+	sbb	24(%esp), %ebx
+	sub	%eax, %ebp
+	sbb	%edx, %ebx
+	mov	20(%esp), %eax		C d1
+	inc	%edi
+	xor	%edx, %edx
+	cmp	(%esp), %ebx
+	adc	$-1, %edx		C mask
+	add	%edx, %edi		C q--
+	and	%edx, %eax		C d0 or 0
+	and	24(%esp), %edx		C d1 or 0
+	add	%eax, %ebp
+	adc	%edx, %ebx
+	cmp	24(%esp), %ebx
+	jae	L(fix)
+L(bck):	mov	56(%esp), %edx
+	mov	%edi, (%edx, %ecx, 4)
+	dec	%ecx
+	jns	L(loop)
+
+L(9):	mov	64(%esp), %esi		C up
+	mov	%ebp, (%esi)
+	mov	%ebx, 4(%esi)
+	mov	32(%esp), %eax
+	add	$36, %esp
+	pop	%ebx
+	pop	%esi
+	pop	%edi
+	pop	%ebp
+	ret
+
+L(fix):	seta	%dl
+	cmp	20(%esp), %ebp
+	setae	%al
+	orb	%dl, %al		C "orb" form to placate Sun tools
+	je	L(bck)
+	inc	%edi
+	sub	20(%esp), %ebp
+	sbb	24(%esp), %ebx
+	jmp	L(bck)
+
+L(35):	sub	20(%esp), %ebp
+	sbb	24(%esp), %ebx
+	movl	$1, 32(%esp)
+	jmp	L(8)
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/fat/com.c b/third_party/gmp/mpn/x86/fat/com.c
new file mode 100644
index 0000000..d359d4c
--- /dev/null
+++ b/third_party/gmp/mpn/x86/fat/com.c
@@ -0,0 +1,32 @@
+/* Fat binary fallback mpn_com.
+
+Copyright 2003, 2009, 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "mpn/generic/com.c"
diff --git a/third_party/gmp/mpn/x86/fat/fat.c b/third_party/gmp/mpn/x86/fat/fat.c
new file mode 100644
index 0000000..18be05a
--- /dev/null
+++ b/third_party/gmp/mpn/x86/fat/fat.c
@@ -0,0 +1,499 @@
+/* x86 fat binary initializers.
+
+   THE FUNCTIONS AND VARIABLES IN THIS FILE ARE FOR INTERNAL USE ONLY.
+   THEY'RE ALMOST CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR
+   COMPLETELY IN FUTURE GNU MP RELEASES.
+
+Copyright 2003, 2004, 2011-2013, 2015, 2017, 2018 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>    /* for printf */
+#include <stdlib.h>   /* for getenv */
+#include <string.h>
+
+#include "gmp-impl.h"
+
+/* Change this to "#define TRACE(x) x" for some traces. */
+#define TRACE(x)
+
+
+/* fat_entry.asm */
+long __gmpn_cpuid (char [12], int);
+int  __gmpn_cpuid_available (void);
+
+
+#if WANT_FAKE_CPUID
+/* The "name"s in the table are values for the GMP_CPU_TYPE environment
+   variable.  Anything can be used, but for now it's the canonical cpu types
+   as per config.guess/config.sub.  */
+
+#define __gmpn_cpuid            fake_cpuid
+#define __gmpn_cpuid_available  fake_cpuid_available
+
+#define MAKE_FMS(family, model)						\
+  ((((family) & 0xf) << 8) + (((family) & 0xff0) << 20)			\
+   + (((model) & 0xf) << 4) + (((model)  &  0xf0) << 12))
+
+static struct {
+  const char  *name;
+  const char  *vendor;
+  unsigned    fms;
+} fake_cpuid_table[] = {
+  { "i386",       "" },
+  { "i486",       "GenuineIntel", MAKE_FMS (4, 0) },
+  { "pentium",    "GenuineIntel", MAKE_FMS (5, 0) },
+  { "pentiummmx", "GenuineIntel", MAKE_FMS (5, 4) },
+  { "pentiumpro", "GenuineIntel", MAKE_FMS (6, 0) },
+  { "pentium2",   "GenuineIntel", MAKE_FMS (6, 2) },
+  { "pentium3",   "GenuineIntel", MAKE_FMS (6, 7) },
+  { "pentium4",   "GenuineIntel", MAKE_FMS (15, 2) },
+  { "prescott",   "GenuineIntel", MAKE_FMS (15, 3) },
+  { "nocona",     "GenuineIntel", MAKE_FMS (15, 4) },
+  { "core2",      "GenuineIntel", MAKE_FMS (6, 0xf) },
+  { "nehalem",    "GenuineIntel", MAKE_FMS (6, 0x1a) },
+  { "nhm",        "GenuineIntel", MAKE_FMS (6, 0x1a) },
+  { "atom",       "GenuineIntel", MAKE_FMS (6, 0x1c) },
+  { "westmere",   "GenuineIntel", MAKE_FMS (6, 0x25) },
+  { "wsm",        "GenuineIntel", MAKE_FMS (6, 0x25) },
+  { "sandybridge","GenuineIntel", MAKE_FMS (6, 0x2a) },
+  { "sbr",        "GenuineIntel", MAKE_FMS (6, 0x2a) },
+  { "silvermont", "GenuineIntel", MAKE_FMS (6, 0x37) },
+  { "slm",        "GenuineIntel", MAKE_FMS (6, 0x37) },
+  { "haswell",    "GenuineIntel", MAKE_FMS (6, 0x3c) },
+  { "hwl",        "GenuineIntel", MAKE_FMS (6, 0x3c) },
+  { "broadwell",  "GenuineIntel", MAKE_FMS (6, 0x3d) },
+  { "bwl",        "GenuineIntel", MAKE_FMS (6, 0x3d) },
+  { "skylake",    "GenuineIntel", MAKE_FMS (6, 0x5e) },
+  { "sky",        "GenuineIntel", MAKE_FMS (6, 0x5e) },
+
+  { "k5",         "AuthenticAMD", MAKE_FMS (5, 0) },
+  { "k6",         "AuthenticAMD", MAKE_FMS (5, 3) },
+  { "k62",        "AuthenticAMD", MAKE_FMS (5, 8) },
+  { "k63",        "AuthenticAMD", MAKE_FMS (5, 9) },
+  { "athlon",     "AuthenticAMD", MAKE_FMS (6, 0) },
+  { "k8",         "AuthenticAMD", MAKE_FMS (15, 0) },
+  { "k10",        "AuthenticAMD", MAKE_FMS (16, 0) },
+  { "bobcat",     "AuthenticAMD", MAKE_FMS (20, 1) },
+  { "bulldozer",  "AuthenticAMD", MAKE_FMS (21, 1) },
+  { "piledriver", "AuthenticAMD", MAKE_FMS (21, 2) },
+  { "steamroller","AuthenticAMD", MAKE_FMS (21, 0x30) },
+  { "excavator",  "AuthenticAMD", MAKE_FMS (21, 0x60) },
+  { "jaguar",     "AuthenticAMD", MAKE_FMS (22, 1) },
+
+  { "viac3",      "CentaurHauls", MAKE_FMS (6, 0) },
+  { "viac32",     "CentaurHauls", MAKE_FMS (6, 9) },
+  { "nano",       "CentaurHauls", MAKE_FMS (6, 15) },
+};
+
+static int
+fake_cpuid_lookup (void)
+{
+  char  *s;
+  int   i;
+
+  s = getenv ("GMP_CPU_TYPE");
+  if (s == NULL)
+    {
+      printf ("Need GMP_CPU_TYPE environment variable for fake cpuid\n");
+      abort ();
+    }
+
+  for (i = 0; i < numberof (fake_cpuid_table); i++)
+    if (strcmp (s, fake_cpuid_table[i].name) == 0)
+      return i;
+
+  printf ("GMP_CPU_TYPE=%s unknown\n", s);
+  abort ();
+}
+
+static int
+fake_cpuid_available (void)
+{
+  return fake_cpuid_table[fake_cpuid_lookup()].vendor[0] != '\0';
+}
+
+static long
+fake_cpuid (char dst[12], int id)
+{
+  int  i = fake_cpuid_lookup();
+
+  switch (id) {
+  case 0:
+    memcpy (dst, fake_cpuid_table[i].vendor, 12);
+    return 0;
+  case 1:
+    return fake_cpuid_table[i].fms;
+  default:
+    printf ("fake_cpuid(): oops, unknown id %d\n", id);
+    abort ();
+  }
+}
+#endif
+
+
+typedef DECL_preinv_divrem_1 ((*preinv_divrem_1_t));
+typedef DECL_preinv_mod_1    ((*preinv_mod_1_t));
+
+struct cpuvec_t __gmpn_cpuvec = {
+  __MPN(add_n_init),
+  0,
+  0,
+  __MPN(addmul_1_init),
+  0,
+  __MPN(bdiv_dbm1c_init),
+  __MPN(cnd_add_n_init),
+  __MPN(cnd_sub_n_init),
+  __MPN(com_init),
+  __MPN(copyd_init),
+  __MPN(copyi_init),
+  __MPN(divexact_1_init),
+  __MPN(divrem_1_init),
+  __MPN(gcd_11_init),
+  __MPN(lshift_init),
+  __MPN(lshiftc_init),
+  __MPN(mod_1_init),
+  __MPN(mod_1_1p_init),
+  __MPN(mod_1_1p_cps_init),
+  __MPN(mod_1s_2p_init),
+  __MPN(mod_1s_2p_cps_init),
+  __MPN(mod_1s_4p_init),
+  __MPN(mod_1s_4p_cps_init),
+  __MPN(mod_34lsub1_init),
+  __MPN(modexact_1c_odd_init),
+  __MPN(mul_1_init),
+  __MPN(mul_basecase_init),
+  __MPN(mullo_basecase_init),
+  __MPN(preinv_divrem_1_init),
+  __MPN(preinv_mod_1_init),
+  __MPN(redc_1_init),
+  __MPN(redc_2_init),
+  __MPN(rshift_init),
+  __MPN(sqr_basecase_init),
+  __MPN(sub_n_init),
+  0,
+  __MPN(submul_1_init),
+  0
+};
+
+int __gmpn_cpuvec_initialized = 0;
+
+/* The following setups start with generic x86, then overwrite with
+   specifics for a chip, and higher versions of that chip.
+
+   The arrangement of the setups here will normally be the same as the $path
+   selections in configure.in for the respective chips.
+
+   This code is reentrant and thread safe.  We always calculate the same
+   decided_cpuvec, so if two copies of the code are running it doesn't
+   matter which completes first, both write the same to __gmpn_cpuvec.
+
+   We need to go via decided_cpuvec because if one thread has completed
+   __gmpn_cpuvec then it may be making use of the threshold values in that
+   vector.  If another thread is still running __gmpn_cpuvec_init then we
+   don't want it to write different values to those fields since some of the
+   asm routines only operate correctly up to their own defined threshold,
+   not an arbitrary value.  */
+
+void
+__gmpn_cpuvec_init (void)
+{
+  struct cpuvec_t  decided_cpuvec;
+
+  TRACE (printf ("__gmpn_cpuvec_init:\n"));
+
+  memset (&decided_cpuvec, '\0', sizeof (decided_cpuvec));
+
+  CPUVEC_SETUP_x86;
+  CPUVEC_SETUP_fat;
+
+  if (! __gmpn_cpuid_available ())
+    {
+      TRACE (printf ("  80386, or early 80486 without cpuid\n"));
+    }
+  else
+    {
+      char vendor_string[13];
+      char dummy_string[12];
+      long fms;
+      int family, model;
+
+      __gmpn_cpuid (vendor_string, 0);
+      vendor_string[12] = 0;
+
+      fms = __gmpn_cpuid (dummy_string, 1);
+      family = ((fms >> 8) & 0xf) + ((fms >> 20) & 0xff);
+      model = ((fms >> 4) & 0xf) + ((fms >> 12) & 0xf0);
+
+      if (strcmp (vendor_string, "GenuineIntel") == 0)
+        {
+          switch (family)
+            {
+            case 4:
+              TRACE (printf ("  80486 with cpuid\n"));
+              break;
+
+            case 5:
+              TRACE (printf ("  pentium\n"));
+              CPUVEC_SETUP_pentium;
+              if (model == 4 || model == 8)
+                {
+                  TRACE (printf ("  pentiummmx\n"));
+                  CPUVEC_SETUP_pentium_mmx;
+                }
+              break;
+
+            case 6:
+              TRACE (printf ("  p6\n"));
+              CPUVEC_SETUP_p6;
+	      switch (model)
+		{
+		case 0x00:
+		case 0x01:
+		  TRACE (printf ("  pentiumpro\n"));
+		  break;
+
+		case 0x02:
+		case 0x03:
+		case 0x04:
+		case 0x05:
+		case 0x06:
+		  TRACE (printf ("  pentium2\n"));
+                  CPUVEC_SETUP_p6_mmx;
+		  break;
+
+		case 0x07:
+		case 0x08:
+		case 0x0a:
+		case 0x0b:
+		case 0x0c:
+		  TRACE (printf ("  pentium3\n"));
+                  CPUVEC_SETUP_p6_mmx;
+                  CPUVEC_SETUP_p6_p3mmx;
+		  break;
+
+		case 0x09:		/* Banias */
+		case 0x0d:		/* Dothan */
+		case 0x0e:		/* Yonah */
+		  TRACE (printf ("  Banias/Dothan/Yonah\n"));
+                  CPUVEC_SETUP_p6_mmx;
+                  CPUVEC_SETUP_p6_p3mmx;
+                  CPUVEC_SETUP_p6_sse2;
+		  break;
+
+		case 0x0f:		/* Conroe Merom Kentsfield Allendale */
+		case 0x10:
+		case 0x11:
+		case 0x12:
+		case 0x13:
+		case 0x14:
+		case 0x15:
+		case 0x16:
+		case 0x17:		/* PNR Wolfdale Yorkfield */
+		case 0x18:
+		case 0x19:
+		case 0x1d:		/* PNR Dunnington */
+		  TRACE (printf ("  Conroe\n"));
+                  CPUVEC_SETUP_p6_mmx;
+                  CPUVEC_SETUP_p6_p3mmx;
+                  CPUVEC_SETUP_p6_sse2;
+		  CPUVEC_SETUP_core2;
+		  break;
+
+		case 0x1c:		/* Atom Silverthorne */
+		case 0x26:		/* Atom Lincroft */
+		case 0x27:		/* Atom Saltwell */
+		case 0x36:		/* Atom Cedarview/Saltwell */
+		  TRACE (printf ("  atom\n"));
+		  CPUVEC_SETUP_atom;
+		  CPUVEC_SETUP_atom_mmx;
+		  CPUVEC_SETUP_atom_sse2;
+		  break;
+
+		case 0x1a:		/* NHM Gainestown */
+		case 0x1b:
+		case 0x1e:		/* NHM Lynnfield/Jasper */
+		case 0x1f:
+		case 0x20:
+		case 0x21:
+		case 0x22:
+		case 0x23:
+		case 0x24:
+		case 0x25:		/* WSM Clarkdale/Arrandale */
+		case 0x28:
+		case 0x29:
+		case 0x2b:
+		case 0x2c:		/* WSM Gulftown */
+		case 0x2e:		/* NHM Beckton */
+		case 0x2f:		/* WSM Eagleton */
+		  TRACE (printf ("  nehalem/westmere\n"));
+                  CPUVEC_SETUP_p6_mmx;
+                  CPUVEC_SETUP_p6_p3mmx;
+                  CPUVEC_SETUP_p6_sse2;
+		  CPUVEC_SETUP_core2;
+		  CPUVEC_SETUP_coreinhm;
+		  break;
+
+		case 0x2a:		/* SBR */
+		case 0x2d:		/* SBR-EP */
+		case 0x3a:		/* IBR */
+		case 0x3c:		/* Haswell client */
+		case 0x3f:		/* Haswell server */
+		case 0x45:		/* Haswell ULT */
+		case 0x46:		/* Crystal Well */
+		case 0x3d:		/* Broadwell */
+		case 0x47:		/* Broadwell */
+		case 0x4f:		/* Broadwell server */
+		case 0x56:		/* Broadwell microserver */
+		case 0x4e:		/* Skylake client */
+		case 0x55:		/* Skylake server */
+		case 0x5e:		/* Skylake */
+		case 0x8e:		/* Kabylake */
+		case 0x9e:		/* Kabylake */
+		  TRACE (printf ("  sandybridge\n"));
+                  CPUVEC_SETUP_p6_mmx;
+                  CPUVEC_SETUP_p6_p3mmx;
+                  CPUVEC_SETUP_p6_sse2;
+		  CPUVEC_SETUP_core2;
+		  CPUVEC_SETUP_coreinhm;
+		  CPUVEC_SETUP_coreisbr;
+		  break;
+		}
+              break;
+
+            case 15:
+              TRACE (printf ("  pentium4\n"));
+              CPUVEC_SETUP_pentium4;
+              CPUVEC_SETUP_pentium4_mmx;
+              CPUVEC_SETUP_pentium4_sse2;
+              break;
+            }
+        }
+      else if (strcmp (vendor_string, "AuthenticAMD") == 0)
+        {
+          switch (family)
+            {
+            case 5:
+              if (model <= 3)
+                {
+                  TRACE (printf ("  k5\n"));
+                }
+              else
+                {
+                  TRACE (printf ("  k6\n"));
+                  CPUVEC_SETUP_k6;
+                  CPUVEC_SETUP_k6_mmx;
+                  if (model >= 8)
+                    {
+                      TRACE (printf ("  k62\n"));
+                      CPUVEC_SETUP_k6_k62mmx;
+                    }
+                  if (model >= 9)
+                    {
+                      TRACE (printf ("  k63\n"));
+                    }
+                }
+              break;
+            case 6:
+              TRACE (printf ("  athlon\n"));
+              CPUVEC_SETUP_k7;
+              CPUVEC_SETUP_k7_mmx;
+              break;
+
+            case 0x0f:		/* k8 */
+            case 0x11:		/* "fam 11h", mix of k8 and k10 */
+            case 0x13:		/* unknown, conservatively assume k8  */
+            case 0x16:		/* unknown, conservatively assume k8  */
+            case 0x17:		/* unknown, conservatively assume k8  */
+              TRACE (printf ("  k8\n"));
+              CPUVEC_SETUP_k7;
+              CPUVEC_SETUP_k7_mmx;
+              CPUVEC_SETUP_k8;
+	      break;
+
+            case 0x10:		/* k10 */
+            case 0x12:		/* k10 (llano) */
+              TRACE (printf ("  k10\n"));
+              CPUVEC_SETUP_k7;
+              CPUVEC_SETUP_k7_mmx;
+	      break;
+
+            case 0x14:		/* bobcat */
+              TRACE (printf ("  bobcat\n"));
+              CPUVEC_SETUP_k7;
+              CPUVEC_SETUP_k7_mmx;
+              CPUVEC_SETUP_bt1;
+	      break;
+
+            case 0x15:		/* bulldozer */
+              TRACE (printf ("  bulldozer\n"));
+              CPUVEC_SETUP_k7;
+              CPUVEC_SETUP_k7_mmx;
+	      break;
+            }
+        }
+      else if (strcmp (vendor_string, "CentaurHauls") == 0)
+        {
+          switch (family)
+            {
+            case 6:
+              TRACE (printf ("  viac3\n"));
+              if (model >= 9)
+                {
+                  TRACE (printf ("  viac32\n"));
+                }
+	      if (model >= 15)
+		{
+                  TRACE (printf ("  nano\n"));
+		  CPUVEC_SETUP_nano;
+		}
+              break;
+            }
+        }
+      else if (strcmp (vendor_string, "CyrixInstead") == 0)
+        {
+          /* Should recognize Cyrix' processors too.  */
+          TRACE (printf ("  cyrix something\n"));
+        }
+    }
+
+  /* There's no x86 generic mpn_preinv_divrem_1 or mpn_preinv_mod_1.
+     Instead default to the plain versions from whichever CPU we detected.
+     The function arguments are compatible, no need for any glue code.  */
+  if (decided_cpuvec.preinv_divrem_1 == NULL)
+    decided_cpuvec.preinv_divrem_1 =(preinv_divrem_1_t)decided_cpuvec.divrem_1;
+  if (decided_cpuvec.preinv_mod_1 == NULL)
+    decided_cpuvec.preinv_mod_1    =(preinv_mod_1_t)   decided_cpuvec.mod_1;
+
+  ASSERT_CPUVEC (decided_cpuvec);
+  CPUVEC_INSTALL (decided_cpuvec);
+
+  /* Set this once the threshold fields are ready.
+     Use volatile to prevent it getting moved.  */
+  *((volatile int *) &__gmpn_cpuvec_initialized) = 1;
+}
diff --git a/third_party/gmp/mpn/x86/fat/fat_entry.asm b/third_party/gmp/mpn/x86/fat/fat_entry.asm
new file mode 100644
index 0000000..25655cf
--- /dev/null
+++ b/third_party/gmp/mpn/x86/fat/fat_entry.asm
@@ -0,0 +1,243 @@
+dnl  x86 fat binary entrypoints.
+
+dnl  Copyright 2003, 2012, 2014 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+dnl  Forcibly disable profiling.
+dnl
+dnl  The entrypoints and inits are small enough not to worry about, the real
+dnl  routines arrived at will have any profiling.  Also, the way the code
+dnl  here ends with a jump means we won't work properly with the
+dnl  "instrument" profiling scheme anyway.
+
+define(`WANT_PROFILING',no)
+
+
+	TEXT
+
+
+dnl  Usage: FAT_ENTRY(name, offset)
+dnl
+dnl  Emit a fat binary entrypoint function of the given name.  This is the
+dnl  normal entry for applications, eg. __gmpn_add_n.
+dnl
+dnl  The code simply jumps through the function pointer in __gmpn_cpuvec at
+dnl  the given "offset" (in bytes).
+dnl
+dnl  For non-PIC, the jumps are 5 bytes each, aligning them to 8 should be
+dnl  fine for all x86s.
+dnl
+dnl  For PIC, the jumps are 20 bytes each, and are best aligned to 16 to
+dnl  ensure at least the first two instructions don't cross a cache line
+dnl  boundary.
+dnl
+dnl  Note the extra `' ahead of PROLOGUE obscures it from the HAVE_NATIVE
+dnl  grepping in configure, stopping that code trying to eval something with
+dnl  $1 in it.
+
+define(FAT_ENTRY,
+m4_assert_numargs(2)
+`	ALIGN(ifdef(`PIC',16,8))
+`'PROLOGUE($1)dnl
+ifdef(`PIC',`dnl
+ifdef(`DARWIN',`
+	call	L(movl_eip_edx)
+	movl	L(___gmpn_cpuvec)$non_lazy_ptr-.(%edx), %edx
+	jmp	*m4_empty_if_zero($2)(%edx)
+',`dnl
+	call	L(movl_eip_edx)
+L(entry_here$2):
+	addl	$_GLOBAL_OFFSET_TABLE_+[.-L(entry_here$2)], %edx
+	movl	GSYM_PREFIX`'__gmpn_cpuvec@GOT(%edx), %edx
+	jmp	*m4_empty_if_zero($2)(%edx)
+')
+',`dnl non-PIC
+	jmp	*GSYM_PREFIX`'__gmpn_cpuvec+$2
+')
+EPILOGUE()
+')
+
+
+dnl  FAT_ENTRY for each CPUVEC_FUNCS_LIST
+dnl
+
+define(`CPUVEC_offset',0)
+foreach(i,
+`FAT_ENTRY(MPN(i),CPUVEC_offset)
+define(`CPUVEC_offset',eval(CPUVEC_offset + 4))',
+CPUVEC_FUNCS_LIST)
+
+ifdef(`PIC',`
+	ALIGN(8)
+L(movl_eip_edx):
+	movl	(%esp), %edx
+	ret_internal
+ifdef(`DARWIN',`
+	.section	__IMPORT,__pointers,non_lazy_symbol_pointers
+L(___gmpn_cpuvec)$non_lazy_ptr:
+	.indirect_symbol	___gmpn_cpuvec
+	.long	0
+	TEXT
+')
+')
+
+
+dnl  Usage: FAT_INIT(name, offset)
+dnl
+dnl  Emit a fat binary initializer function of the given name.  These
+dnl  functions are the initial values for the pointers in __gmpn_cpuvec.
+dnl
+dnl  The code simply calls __gmpn_cpuvec_init, and then jumps back through
+dnl  the __gmpn_cpuvec pointer, at the given "offset" (in bytes).
+dnl  __gmpn_cpuvec_init will have stored the address of the selected
+dnl  implementation there.
+dnl
+dnl  Only one of these routines will be executed, and only once, since after
+dnl  that all the __gmpn_cpuvec pointers go to real routines.  So there's no
+dnl  need for anything special here, just something small and simple.  To
+dnl  keep code size down, "fat_init" is a shared bit of code, arrived at
+dnl  with the offset in %al.  %al is used since the movb instruction is 2
+dnl  bytes where %eax would be 4.
+dnl
+dnl  Note having `PROLOGUE in FAT_INIT obscures that PROLOGUE from the
+dnl  HAVE_NATIVE grepping in configure, preventing that code trying to eval
+dnl  something with $1 in it.
+
+define(FAT_INIT,
+m4_assert_numargs(2)
+`PROLOGUE($1)dnl
+	movb	$`'$2, %al
+	jmp	L(fat_init)
+EPILOGUE()
+')
+
+L(fat_init):
+	C al	__gmpn_cpuvec byte offset
+
+	movzbl	%al, %eax
+	pushl	%eax
+
+ifdef(`PIC',`dnl
+ifdef(`DARWIN',`
+	sub	$8, %esp
+	CALL(	__gmpn_cpuvec_init)
+	add	$8, %esp
+	call	L(movl_eip_edx)
+	movl	L(___gmpn_cpuvec)$non_lazy_ptr-.(%edx), %edx
+',`dnl
+	pushl	%ebx
+	call	L(movl_eip_ebx)
+L(init_here):
+	addl	$_GLOBAL_OFFSET_TABLE_+[.-L(init_here)], %ebx
+	CALL(	__gmpn_cpuvec_init)
+	movl	GSYM_PREFIX`'__gmpn_cpuvec@GOT(%ebx), %edx
+	popl	%ebx
+')
+	popl	%eax
+	jmp	*(%edx,%eax)
+
+L(movl_eip_ebx):
+	movl	(%esp), %ebx
+	ret_internal
+',`dnl non-PIC
+	sub	$8, %esp		C needed on Darwin, harmless elsewhere
+	CALL(	__gmpn_cpuvec_init)
+	add	$8, %esp		C needed on Darwin, harmless elsewhere
+	popl	%eax
+	jmp	*GSYM_PREFIX`'__gmpn_cpuvec(%eax)
+')
+
+dnl  FAT_INIT for each CPUVEC_FUNCS_LIST
+dnl
+
+define(`CPUVEC_offset',0)
+foreach(i,
+`FAT_INIT(MPN(i`'_init),CPUVEC_offset)
+define(`CPUVEC_offset',eval(CPUVEC_offset + 4))',
+CPUVEC_FUNCS_LIST)
+
+
+
+C long __gmpn_cpuid (char dst[12], int id);
+C
+C This is called only once, so just something simple and compact is fine.
+
+defframe(PARAM_ID,  8)
+defframe(PARAM_DST, 4)
+deflit(`FRAME',0)
+
+PROLOGUE(__gmpn_cpuid)
+	pushl	%esi		FRAME_pushl()
+	pushl	%ebx		FRAME_pushl()
+	movl	PARAM_ID, %eax
+	cpuid
+	movl	PARAM_DST, %esi
+	movl	%ebx, (%esi)
+	movl	%edx, 4(%esi)
+	movl	%ecx, 8(%esi)
+	popl	%ebx
+	popl	%esi
+	ret
+EPILOGUE()
+
+
+C int __gmpn_cpuid_available (void);
+C
+C Return non-zero if the cpuid instruction is available, which means late
+C model 80486 and higher.  80386 and early 80486 don't have cpuid.
+C
+C The test follows Intel AP-485 application note, namely that if bit 21 is
+C modifiable then cpuid is supported.  This test is reentrant and thread
+C safe, since of course any interrupt or context switch will preserve the
+C flags while we're tinkering with them.
+C
+C This is called only once, so just something simple and compact is fine.
+
+PROLOGUE(__gmpn_cpuid_available)
+	pushf
+	popl	%ecx		C old flags
+
+	movl	%ecx, %edx
+	xorl	$0x200000, %edx
+	pushl	%edx
+	popf
+	pushf
+	popl	%edx		C tweaked flags
+
+	movl	$1, %eax
+	cmpl	%ecx, %edx
+	jne	L(available)
+	xorl	%eax, %eax	C not changed, so cpuid not available
+
+L(available):
+	ret
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86/fat/gmp-mparam.h b/third_party/gmp/mpn/x86/fat/gmp-mparam.h
new file mode 100644
index 0000000..3641a6b
--- /dev/null
+++ b/third_party/gmp/mpn/x86/fat/gmp-mparam.h
@@ -0,0 +1,71 @@
+/* Fat binary x86 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 2000-2003, 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+
+/* mpn_divexact_1 is faster than mpn_divrem_1 at all sizes.  The only time
+   this might not be true currently is for actual 80386 and 80486 chips,
+   where mpn/x86/dive_1.asm might be slower than mpn/x86/divrem_1.asm, but
+   that's not worth worrying about.  */
+#define DIVEXACT_1_THRESHOLD  0
+
+/* Only some of the x86s have an mpn_preinv_divrem_1, but we set
+   USE_PREINV_DIVREM_1 so that all callers use it, and then let the
+   __gmpn_cpuvec pointer go to plain mpn_divrem_1 if there's not an actual
+   preinv.  */
+#define USE_PREINV_DIVREM_1   1
+
+#define BMOD_1_TO_MOD_1_THRESHOLD           20
+
+/* mpn_sqr_basecase is faster than mpn_mul_basecase at all sizes, no need
+   for mpn_sqr to call the latter.  */
+#define SQR_BASECASE_THRESHOLD 0
+
+/* Sensible fallbacks for these, when not taken from a cpu-specific
+   gmp-mparam.h.  */
+#define MUL_TOOM22_THRESHOLD      20
+#define MUL_TOOM33_THRESHOLD     130
+#define SQR_TOOM2_THRESHOLD       30
+#define SQR_TOOM3_THRESHOLD      200
+
+/* These are values more or less in the middle of what the typical x86 chips
+   come out as.  For a fat binary it's necessary to have values for these,
+   since the defaults for MUL_FFT_TABLE and SQR_FFT_TABLE otherwise come out
+   as non-constant array initializers.  FIXME: Perhaps these should be done
+   in the cpuvec structure like other thresholds.  */
+#define MUL_FFT_TABLE  { 464, 928, 1920, 3584, 10240, 40960, 0 }
+#define MUL_FFT_MODF_THRESHOLD          400
+#define MUL_FFT_THRESHOLD              2000
+
+#define SQR_FFT_TABLE  { 528, 1184, 1920, 4608, 14336, 40960, 0 }
+#define SQR_FFT_MODF_THRESHOLD          500
+#define SQR_FFT_THRESHOLD              3000
diff --git a/third_party/gmp/mpn/x86/fat/lshiftc.c b/third_party/gmp/mpn/x86/fat/lshiftc.c
new file mode 100644
index 0000000..9ecf489
--- /dev/null
+++ b/third_party/gmp/mpn/x86/fat/lshiftc.c
@@ -0,0 +1,32 @@
+/* Fat binary fallback mpn_lshiftc.
+
+Copyright 2003, 2009, 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "mpn/generic/lshiftc.c"
diff --git a/third_party/gmp/mpn/x86/fat/mod_1.c b/third_party/gmp/mpn/x86/fat/mod_1.c
new file mode 100644
index 0000000..4f149cc
--- /dev/null
+++ b/third_party/gmp/mpn/x86/fat/mod_1.c
@@ -0,0 +1,32 @@
+/* Fat binary fallback mpn_mod_1.
+
+Copyright 2003, 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "mpn/generic/mod_1.c"
diff --git a/third_party/gmp/mpn/x86/fat/mod_1_1.c b/third_party/gmp/mpn/x86/fat/mod_1_1.c
new file mode 100644
index 0000000..92eaa7a
--- /dev/null
+++ b/third_party/gmp/mpn/x86/fat/mod_1_1.c
@@ -0,0 +1,36 @@
+/* Fat binary fallback mpn_mod_1_1p.
+
+Copyright 2003, 2009, 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+/*
+PROLOGUE(mpn_mod_1_1p_cps)
+*/
+
+#define OPERATION_mod_1_1_cps 1
+#include "mpn/generic/mod_1_1.c"
diff --git a/third_party/gmp/mpn/x86/fat/mod_1_2.c b/third_party/gmp/mpn/x86/fat/mod_1_2.c
new file mode 100644
index 0000000..9095a61
--- /dev/null
+++ b/third_party/gmp/mpn/x86/fat/mod_1_2.c
@@ -0,0 +1,36 @@
+/* Fat binary fallback mpn_mod_1s_2p.
+
+Copyright 2003, 2009, 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+/*
+PROLOGUE(mpn_mod_1s_2p_cps)
+*/
+
+#define OPERATION_mod_1_2_cps 1
+#include "mpn/generic/mod_1_2.c"
diff --git a/third_party/gmp/mpn/x86/fat/mod_1_4.c b/third_party/gmp/mpn/x86/fat/mod_1_4.c
new file mode 100644
index 0000000..51c0def
--- /dev/null
+++ b/third_party/gmp/mpn/x86/fat/mod_1_4.c
@@ -0,0 +1,36 @@
+/* Fat binary fallback mpn_mod_1s_4p.
+
+Copyright 2003, 2009, 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+/*
+PROLOGUE(mpn_mod_1s_4p_cps)
+*/
+
+#define OPERATION_mod_1_4_cps 1
+#include "mpn/generic/mod_1_4.c"
diff --git a/third_party/gmp/mpn/x86/fat/mode1o.c b/third_party/gmp/mpn/x86/fat/mode1o.c
new file mode 100644
index 0000000..870ddb8
--- /dev/null
+++ b/third_party/gmp/mpn/x86/fat/mode1o.c
@@ -0,0 +1,32 @@
+/* Fat binary fallback mpn_modexact_1c_odd.
+
+Copyright 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "mpn/generic/mode1o.c"
diff --git a/third_party/gmp/mpn/x86/fat/mullo_basecase.c b/third_party/gmp/mpn/x86/fat/mullo_basecase.c
new file mode 100644
index 0000000..7f86be6
--- /dev/null
+++ b/third_party/gmp/mpn/x86/fat/mullo_basecase.c
@@ -0,0 +1,32 @@
+/* Fat binary fallback mpn_mullo_basecase.
+
+Copyright 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "mpn/generic/mullo_basecase.c"
diff --git a/third_party/gmp/mpn/x86/fat/redc_1.c b/third_party/gmp/mpn/x86/fat/redc_1.c
new file mode 100644
index 0000000..0025403
--- /dev/null
+++ b/third_party/gmp/mpn/x86/fat/redc_1.c
@@ -0,0 +1,32 @@
+/* Fat binary fallback mpn_redc_1.
+
+Copyright 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "mpn/generic/redc_1.c"
diff --git a/third_party/gmp/mpn/x86/fat/redc_2.c b/third_party/gmp/mpn/x86/fat/redc_2.c
new file mode 100644
index 0000000..1932d58
--- /dev/null
+++ b/third_party/gmp/mpn/x86/fat/redc_2.c
@@ -0,0 +1,32 @@
+/* Fat binary fallback mpn_redc_2.
+
+Copyright 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "mpn/generic/redc_2.c"
diff --git a/third_party/gmp/mpn/x86/gcd_11.asm b/third_party/gmp/mpn/x86/gcd_11.asm
new file mode 100644
index 0000000..af69135
--- /dev/null
+++ b/third_party/gmp/mpn/x86/gcd_11.asm
@@ -0,0 +1,126 @@
+dnl  x86 mpn_gcd_11 optimised for processors with slow BSF.
+
+dnl  Based on C version.
+
+dnl  Copyright 2019 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+dnl  Rudimentary code for x86-32, i.e. for CPUs without cmov.  Also, the bsf
+dnl  instruction is assumed to be so slow it is useless.  Instead a teble is
+dnl  used.
+dnl
+dnl  The loop benefits from OoO, in-order CPUs might want a different loop.
+dnl  The ebx and ecx registers could be combined if the assigment of ecx were
+dnl  postponed until ebx died, but that would at least hurt in-order CPUs.
+
+C	     cycles/bit (approx)
+C AMD K7	 ?
+C AMD K8,K9	 ?
+C AMD K10	 ?
+C AMD bd1	 ?
+C AMD bd2	 ?
+C AMD bd3	 ?
+C AMD bd4	 ?
+C AMD bt1	 ?
+C AMD bt2	 ?
+C AMD zn1	 ?
+C AMD zn2	 ?
+C Intel P4-2	 ?
+C Intel P4-3/4	 ?
+C Intel P6/13	 ?
+C Intel CNR	 ?
+C Intel NHM	 ?
+C Intel SBR	 ?
+C Intel IBR	 ?
+C Intel HWL	 ?
+C Intel BWL	 ?
+C Intel SKL	 ?
+C Intel atom	 ?
+C Intel SLM	 ?
+C Intel GLM	 ?
+C Intel GLM+	 ?
+C VIA nano	 ?
+C Numbers measured with: speed -CD -s8-32 -t24 mpn_gcd_1
+
+deflit(MAXSHIFT, 6)
+deflit(MASK, eval((m4_lshift(1,MAXSHIFT))-1))
+
+DEF_OBJECT(ctz_table,64)
+	.byte	MAXSHIFT
+forloop(i,1,MASK,
+`	.byte	m4_count_trailing_zeros(i)
+')
+END_OBJECT(ctz_table)
+
+define(`u0',    `%eax')
+define(`v0',    `%edx')
+
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_gcd_11)
+	push	%edi
+	push	%esi
+	push	%ebx
+
+	mov	16(%esp), u0
+	mov	20(%esp), v0
+	LEAL(	ctz_table, %esi)
+	sub	v0, u0			C u = u - v		0
+	jz	L(end)
+
+	ALIGN(16)
+L(top):	sbb	%ebx, %ebx		C mask			1
+	mov	u0, %edi		C			1
+	mov	u0, %ecx		C			1
+	and	%ebx, %edi		C			2
+	xor	%ebx, u0		C			2
+	add	%edi, v0		C v = min(u.v)		3
+	sub	%ebx, u0		C u = |u - v|		3
+L(mid):	and	$MASK, %ecx		C			2
+	movzbl	(%esi,%ecx), %ecx	C			3
+	jz	L(shift_alot)
+	shr	%cl, u0			C			4
+	sub	v0, u0			C u = u - v		0,5
+	jnz	L(top)
+
+L(end):	mov	v0, %eax
+	pop	%ebx
+	pop	%esi
+	pop	%edi
+	ret
+
+L(shift_alot):
+	shr	$MAXSHIFT, u0
+	mov	u0, %ecx
+	jmp	L(mid)
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86/geode/gmp-mparam.h b/third_party/gmp/mpn/x86/geode/gmp-mparam.h
new file mode 100644
index 0000000..cc9c9f1
--- /dev/null
+++ b/third_party/gmp/mpn/x86/geode/gmp-mparam.h
@@ -0,0 +1,141 @@
+/* Generic x86 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 2000-2002, 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+/* Generated by tuneup.c, 2011-01-30, gcc 3.4 */
+
+#define MOD_1_NORM_THRESHOLD                 6
+#define MOD_1_UNNORM_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD         17
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          9
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD         0  /* never mpn_mod_1_1p */
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        14
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD  MP_SIZE_T_MAX  /* never */
+#define USE_PREINV_DIVREM_1                  0
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           42
+
+#define MUL_TOOM22_THRESHOLD                18
+#define MUL_TOOM33_THRESHOLD                66
+#define MUL_TOOM44_THRESHOLD               105
+#define MUL_TOOM6H_THRESHOLD               141
+#define MUL_TOOM8H_THRESHOLD               212
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      62
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD      69
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD      65
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD      67
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 33
+#define SQR_TOOM3_THRESHOLD                 60
+#define SQR_TOOM4_THRESHOLD                136
+#define SQR_TOOM6_THRESHOLD                196
+#define SQR_TOOM8_THRESHOLD                292
+
+#define MULMOD_BNM1_THRESHOLD               14
+#define SQRMOD_BNM1_THRESHOLD               16
+
+#define MUL_FFT_MODF_THRESHOLD             468  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    468, 5}, {     17, 6}, {      9, 5}, {     19, 6}, \
+    {     11, 5}, {     23, 6}, {     21, 7}, {     11, 6}, \
+    {     25, 7}, {     13, 6}, {     27, 7}, {     15, 6}, \
+    {     31, 7}, {     21, 8}, {     11, 7}, {     27, 8}, \
+    {     15, 7}, {     33, 8}, {     19, 7}, {     39, 8}, \
+    {     23, 7}, {     47, 8}, {     27, 9}, {     15, 8}, \
+    {     39, 9}, {     23, 8}, {     47,10}, {     15, 9}, \
+    {     31, 8}, {     67, 9}, {     39, 8}, {     79, 9}, \
+    {     47, 8}, {     95, 9}, {     55,10}, {     31, 9}, \
+    {     63, 8}, {    127, 9}, {     79,10}, {     47, 9}, \
+    {     95,11}, {     31,10}, {     63, 9}, {    135,10}, \
+    {     79, 9}, {    159,10}, {     95, 9}, {    191,11}, \
+    {     63,10}, {    127, 9}, {    255,10}, {    143, 9}, \
+    {    287,10}, {    159,11}, {     95,10}, {    191, 9}, \
+    {    383,12}, {   4096,13}, {   8192,14}, {  16384,15}, \
+    {  32768,16} }
+#define MUL_FFT_TABLE3_SIZE 61
+#define MUL_FFT_THRESHOLD                 5504
+
+#define SQR_FFT_MODF_THRESHOLD             396  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    396, 5}, {     21, 6}, {     11, 5}, {     23, 6}, \
+    {     21, 7}, {     11, 6}, {     24, 7}, {     13, 6}, \
+    {     27, 7}, {     15, 6}, {     31, 7}, {     21, 8}, \
+    {     11, 7}, {     27, 8}, {     15, 7}, {     33, 8}, \
+    {     19, 7}, {     39, 8}, {     23, 7}, {     47, 8}, \
+    {     27, 9}, {     15, 8}, {     39, 9}, {     23, 8}, \
+    {     51,10}, {     15, 9}, {     31, 8}, {     67, 9}, \
+    {     39, 8}, {     79, 9}, {     47, 8}, {     95, 9}, \
+    {     55,10}, {     31, 9}, {     79,10}, {     47, 9}, \
+    {     95,11}, {     31,10}, {     63, 9}, {    127, 8}, \
+    {    255, 9}, {    135,10}, {     79, 9}, {    159, 8}, \
+    {    319,10}, {     95, 9}, {    191,11}, {     63,10}, \
+    {    127, 9}, {    255, 8}, {    511,10}, {    143, 9}, \
+    {    287, 8}, {    575,10}, {    159,11}, {     95,10}, \
+    {    191,12}, {   4096,13}, {   8192,14}, {  16384,15}, \
+    {  32768,16} }
+#define SQR_FFT_TABLE3_SIZE 61
+#define SQR_FFT_THRESHOLD                 3712
+
+#define MULLO_BASECASE_THRESHOLD             3
+#define MULLO_DC_THRESHOLD                  37
+#define MULLO_MUL_N_THRESHOLD            10950
+
+#define DC_DIV_QR_THRESHOLD                 59
+#define DC_DIVAPPR_Q_THRESHOLD             189
+#define DC_BDIV_QR_THRESHOLD                55
+#define DC_BDIV_Q_THRESHOLD                136
+
+#define INV_MULMOD_BNM1_THRESHOLD           50
+#define INV_NEWTON_THRESHOLD               183
+#define INV_APPR_THRESHOLD                 181
+
+#define BINV_NEWTON_THRESHOLD              204
+#define REDC_1_TO_REDC_N_THRESHOLD          54
+
+#define MU_DIV_QR_THRESHOLD               1142
+#define MU_DIVAPPR_Q_THRESHOLD            1142
+#define MUPI_DIV_QR_THRESHOLD               81
+#define MU_BDIV_QR_THRESHOLD               889
+#define MU_BDIV_Q_THRESHOLD                998
+
+#define MATRIX22_STRASSEN_THRESHOLD         13
+#define HGCD_THRESHOLD                     133
+#define GCD_DC_THRESHOLD                   451
+#define GCDEXT_DC_THRESHOLD                318
+#define JACOBI_BASE_METHOD                   1
+
+#define GET_STR_DC_THRESHOLD                15
+#define GET_STR_PRECOMPUTE_THRESHOLD        30
+#define SET_STR_DC_THRESHOLD               547
+#define SET_STR_PRECOMPUTE_THRESHOLD      1049
diff --git a/third_party/gmp/mpn/x86/gmp-mparam.h b/third_party/gmp/mpn/x86/gmp-mparam.h
new file mode 100644
index 0000000..2cb1984
--- /dev/null
+++ b/third_party/gmp/mpn/x86/gmp-mparam.h
@@ -0,0 +1,38 @@
+/* Generic x86 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+
+/* Generic x86 mpn_divexact_1 is faster than generic x86 mpn_divrem_1 on all
+   of p5, p6, k6 and k7, so use it always.  It's probably slower on 386 and
+   486, but that's too bad.  */
+#define DIVEXACT_1_THRESHOLD  0
diff --git a/third_party/gmp/mpn/x86/goldmont/gmp-mparam.h b/third_party/gmp/mpn/x86/goldmont/gmp-mparam.h
new file mode 100644
index 0000000..3d37fa3
--- /dev/null
+++ b/third_party/gmp/mpn/x86/goldmont/gmp-mparam.h
@@ -0,0 +1,219 @@
+/* Intel Goldmont/32 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+/* 2200 MHz Intel Atom C3758 Goldmont/Denverton */
+/* FFT tuning limit = 67,000,000 */
+/* Generated by tuneup.c, 2019-10-22, gcc 8.3 */
+
+#define MOD_1_NORM_THRESHOLD                 7
+#define MOD_1_UNNORM_THRESHOLD              12
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          9
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          7
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        10
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD         0  /* never mpn_mod_1s_2p */
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     12
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1N_PI1_METHOD                 1  /* 32.79% faster than 2 */
+#define DIV_QR_1_NORM_THRESHOLD             32
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           23
+
+#define DIV_1_VS_MUL_1_PERCENT             228
+
+#define MUL_TOOM22_THRESHOLD                18
+#define MUL_TOOM33_THRESHOLD                81
+#define MUL_TOOM44_THRESHOLD               193
+#define MUL_TOOM6H_THRESHOLD               286
+#define MUL_TOOM8H_THRESHOLD               399
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      81
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     138
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     125
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     137
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     185
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 32
+#define SQR_TOOM3_THRESHOLD                113
+#define SQR_TOOM4_THRESHOLD                280
+#define SQR_TOOM6_THRESHOLD                399
+#define SQR_TOOM8_THRESHOLD                547
+
+#define MULMID_TOOM42_THRESHOLD             60
+
+#define MULMOD_BNM1_THRESHOLD               13
+#define SQRMOD_BNM1_THRESHOLD               15
+
+#define MUL_FFT_MODF_THRESHOLD             368  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    368, 5}, {     21, 6}, {     11, 5}, {     23, 6}, \
+    {     21, 7}, {     11, 6}, {     25, 7}, {     13, 6}, \
+    {     27, 7}, {     15, 6}, {     31, 7}, {     21, 8}, \
+    {     11, 7}, {     27, 8}, {     15, 7}, {     33, 8}, \
+    {     19, 7}, {     39, 8}, {     23, 7}, {     47, 8}, \
+    {     27, 9}, {     15, 8}, {     39, 9}, {     23, 8}, \
+    {     47,10}, {     15, 9}, {     31, 8}, {     63, 9}, \
+    {     39, 8}, {     79, 9}, {     47,10}, {     31, 9}, \
+    {     79,10}, {     47, 9}, {     95,11}, {     31,10}, \
+    {     63, 9}, {    127, 8}, {    255, 9}, {    135,10}, \
+    {     79, 9}, {    159,10}, {     95, 9}, {    191,11}, \
+    {     63,10}, {    127, 9}, {    255, 8}, {    511,10}, \
+    {    143, 9}, {    287, 8}, {    575, 9}, {    303,10}, \
+    {    159,11}, {     95,10}, {    191,12}, {     63,11}, \
+    {    127,10}, {    255, 9}, {    511,10}, {    271, 9}, \
+    {    543,10}, {    287, 9}, {    575,10}, {    303, 9}, \
+    {    607,11}, {    159,10}, {    319, 9}, {    639,10}, \
+    {    351, 9}, {    703,11}, {    191,10}, {    383, 9}, \
+    {    767,10}, {    415, 9}, {    831,11}, {    223,10}, \
+    {    447,12}, {    127,11}, {    255,10}, {    543, 9}, \
+    {   1087,11}, {    287,10}, {    607, 9}, {   1215,11}, \
+    {    319,10}, {    671,11}, {    351,10}, {    703,12}, \
+    {    191,11}, {    383,10}, {    767,11}, {    415,10}, \
+    {    831,11}, {    447,13}, {    127,12}, {    255,11}, \
+    {    543,10}, {   1087,11}, {    607,10}, {   1215,12}, \
+    {    319,11}, {    671,10}, {   1343,11}, {    703,10}, \
+    {   1407,11}, {    735,12}, {    383,11}, {    831,12}, \
+    {    447,11}, {    959,13}, {    255,12}, {    511,11}, \
+    {   1087,12}, {    575,11}, {   1215,10}, {   2431,12}, \
+    {    639,11}, {   1343,12}, {    703,11}, {   1407,13}, \
+    {    383,12}, {    831,11}, {   1663,12}, {    959,11}, \
+    {   1919,14}, {    255,13}, {    511,12}, {   1215,11}, \
+    {   2431,13}, {    639,12}, {   1471,11}, {   2943,13}, \
+    {    767,12}, {   1727,13}, {    895,12}, {   1919,11}, \
+    {   3839,14}, {    511,13}, {   1023,12}, {   2111,13}, \
+    {   1151,12}, {   2431,13}, {   1407,12}, {   2943,14}, \
+    {    767,13}, {   1663,12}, {   3455,13}, {   1919,12}, \
+    {   3839,15}, {    511,14}, {   1023,13}, {   2431,14}, \
+    {   1279,13}, {   2943,12}, {   5887,14}, {   1535,13}, \
+    {   3455,14}, {   1791,13}, {   3839,12}, {   7679,15}, \
+    {   1023,14}, {   2303,13}, {   4991,12}, {   9983,14}, \
+    {   2559,13}, {   5119,14}, {   2815,13}, {   5887,15}, \
+    {   1535,14}, {   3839,13}, {   7679,16} }
+#define MUL_FFT_TABLE3_SIZE 171
+#define MUL_FFT_THRESHOLD                 3712
+
+#define SQR_FFT_MODF_THRESHOLD             340  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    340, 5}, {     21, 6}, {     11, 5}, {     23, 6}, \
+    {     12, 5}, {     25, 6}, {     21, 7}, {     11, 6}, \
+    {     25, 7}, {     13, 6}, {     27, 7}, {     15, 6}, \
+    {     31, 7}, {     21, 8}, {     11, 7}, {     27, 8}, \
+    {     15, 7}, {     33, 8}, {     19, 7}, {     39, 8}, \
+    {     23, 7}, {     47, 8}, {     27, 9}, {     15, 8}, \
+    {     39, 9}, {     23, 8}, {     47,10}, {     15, 9}, \
+    {     31, 8}, {     67, 9}, {     39, 8}, {     79, 9}, \
+    {     47,10}, {     31, 9}, {     79,10}, {     47,11}, \
+    {     31,10}, {     63, 9}, {    127, 8}, {    255,10}, \
+    {     79, 9}, {    159, 8}, {    319,10}, {     95, 9}, \
+    {    191,11}, {     63,10}, {    127, 9}, {    255, 8}, \
+    {    511, 9}, {    271,10}, {    143, 9}, {    287, 8}, \
+    {    575, 9}, {    303, 8}, {    607, 9}, {    319,11}, \
+    {     95,10}, {    191,12}, {     63,11}, {    127,10}, \
+    {    255, 9}, {    511,10}, {    271, 9}, {    543,10}, \
+    {    287, 9}, {    575,10}, {    303, 9}, {    607,11}, \
+    {    159,10}, {    319, 9}, {    639,10}, {    335, 9}, \
+    {    671,10}, {    351, 9}, {    703,11}, {    191,10}, \
+    {    383, 9}, {    767,10}, {    415, 9}, {    831,11}, \
+    {    223,10}, {    479,12}, {    127,11}, {    255,10}, \
+    {    543, 9}, {   1087,11}, {    287,10}, {    607, 9}, \
+    {   1215,11}, {    319,10}, {    671,11}, {    351,10}, \
+    {    703,12}, {    191,11}, {    383,10}, {    767,11}, \
+    {    415,10}, {    831,11}, {    479,13}, {    127,12}, \
+    {    255,11}, {    543,10}, {   1087,11}, {    607,10}, \
+    {   1215,12}, {    319,11}, {    671,10}, {   1343,11}, \
+    {    735,12}, {    383,11}, {    831,12}, {    447,11}, \
+    {    959,13}, {    255,12}, {    511,11}, {   1087,12}, \
+    {    575,11}, {   1215,12}, {    639,11}, {   1343,12}, \
+    {    703,11}, {   1471,13}, {    383,12}, {    831,11}, \
+    {   1663,12}, {    959,11}, {   1919,14}, {    255,13}, \
+    {    511,12}, {   1215,13}, {    639,12}, {   1471,11}, \
+    {   2943,13}, {    767,12}, {   1727,13}, {    895,12}, \
+    {   1919,14}, {    511,13}, {   1023,12}, {   2111,13}, \
+    {   1151,12}, {   2431,13}, {   1407,12}, {   2943,14}, \
+    {    767,13}, {   1663,12}, {   3455,13}, {   1919,15}, \
+    {    511,14}, {   1023,13}, {   2431,14}, {   1279,13}, \
+    {   2943,12}, {   5887,14}, {   1535,13}, {   3455,14}, \
+    {   1791,13}, {   3839,12}, {   7679,15}, {   1023,14}, \
+    {   2047,13}, {   4095,14}, {   2303,13}, {   4991,12}, \
+    {   9983,14}, {   2815,13}, {   5887,15}, {   1535,14}, \
+    {   3839,13}, {   7679,16} }
+#define SQR_FFT_TABLE3_SIZE 170
+#define SQR_FFT_THRESHOLD                 3520
+
+#define MULLO_BASECASE_THRESHOLD             5
+#define MULLO_DC_THRESHOLD                  50
+#define MULLO_MUL_N_THRESHOLD             6633
+#define SQRLO_BASECASE_THRESHOLD             0  /* always */
+#define SQRLO_DC_THRESHOLD                  95
+#define SQRLO_SQR_THRESHOLD               6633
+
+#define DC_DIV_QR_THRESHOLD                 68
+#define DC_DIVAPPR_Q_THRESHOLD             204
+#define DC_BDIV_QR_THRESHOLD                64
+#define DC_BDIV_Q_THRESHOLD                108
+
+#define INV_MULMOD_BNM1_THRESHOLD           34
+#define INV_NEWTON_THRESHOLD               276
+#define INV_APPR_THRESHOLD                 226
+
+#define BINV_NEWTON_THRESHOLD              298
+#define REDC_1_TO_REDC_N_THRESHOLD          65
+
+#define MU_DIV_QR_THRESHOLD               1528
+#define MU_DIVAPPR_Q_THRESHOLD            1589
+#define MUPI_DIV_QR_THRESHOLD              140
+#define MU_BDIV_QR_THRESHOLD              1334
+#define MU_BDIV_Q_THRESHOLD               1499
+
+#define POWM_SEC_TABLE  3,16,96,428,1317
+
+#define GET_STR_DC_THRESHOLD                13
+#define GET_STR_PRECOMPUTE_THRESHOLD        18
+#define SET_STR_DC_THRESHOLD               704
+#define SET_STR_PRECOMPUTE_THRESHOLD      1358
+
+#define FAC_DSC_THRESHOLD                   95
+#define FAC_ODD_THRESHOLD                   29
+
+#define MATRIX22_STRASSEN_THRESHOLD         15
+#define HGCD2_DIV1_METHOD                    1  /* 5.53% faster than 3 */
+#define HGCD_THRESHOLD                     172
+#define HGCD_APPR_THRESHOLD                204
+#define HGCD_REDUCE_THRESHOLD             2479
+#define GCD_DC_THRESHOLD                   610
+#define GCDEXT_DC_THRESHOLD                443
+#define JACOBI_BASE_METHOD                   4  /* 6.53% faster than 3 */
+
+/* Tuneup completed successfully, took 101563 seconds */
diff --git a/third_party/gmp/mpn/x86/i486/gmp-mparam.h b/third_party/gmp/mpn/x86/i486/gmp-mparam.h
new file mode 100644
index 0000000..aa7dbad
--- /dev/null
+++ b/third_party/gmp/mpn/x86/i486/gmp-mparam.h
@@ -0,0 +1,69 @@
+/* 80486 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2001-2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+
+/* 100MHz DX4 */
+
+/* Generated by tuneup.c, 2003-02-13, gcc 2.95 */
+
+#define MUL_TOOM22_THRESHOLD             18
+#define MUL_TOOM33_THRESHOLD            228
+
+#define SQR_BASECASE_THRESHOLD           13
+#define SQR_TOOM2_THRESHOLD              49
+#define SQR_TOOM3_THRESHOLD             238
+
+#define DIV_SB_PREINV_THRESHOLD       MP_SIZE_T_MAX  /* never */
+#define DIV_DC_THRESHOLD                 72
+#define POWM_THRESHOLD                   38
+
+#define GCD_ACCEL_THRESHOLD               3
+#define JACOBI_BASE_METHOD                2
+
+#define USE_PREINV_DIVREM_1               0
+#define USE_PREINV_MOD_1                  0
+#define DIVREM_2_THRESHOLD            MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD              0  /* always (native) */
+#define MODEXACT_1_ODD_THRESHOLD         17
+
+#define GET_STR_DC_THRESHOLD             32
+#define GET_STR_PRECOMPUTE_THRESHOLD     82
+#define SET_STR_THRESHOLD              3524
+
+#define MUL_FFT_TABLE  { 464, 928, 1920, 4608, 10240, 40960, 0 }
+#define MUL_FFT_MODF_THRESHOLD          392
+#define MUL_FFT_THRESHOLD              2816
+
+#define SQR_FFT_TABLE  { 432, 928, 1920, 4608, 14336, 40960, 0 }
+#define SQR_FFT_MODF_THRESHOLD          392
+#define SQR_FFT_THRESHOLD              2816
diff --git a/third_party/gmp/mpn/x86/k10/gmp-mparam.h b/third_party/gmp/mpn/x86/k10/gmp-mparam.h
new file mode 100644
index 0000000..eceaaae
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k10/gmp-mparam.h
@@ -0,0 +1,217 @@
+/* x86/k10 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 2000-2011, 2014-2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+/* 3200-3600 MHz K10 Thuban */
+/* FFT tuning limit = 67,000,000 */
+/* Generated by tuneup.c, 2019-10-19, gcc 8.3 */
+
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD         14
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          7
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD         0  /* never mpn_mod_1_1p */
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        18
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     22
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1N_PI1_METHOD                 1  /* 29.33% faster than 2 */
+#define DIV_QR_1_NORM_THRESHOLD              2
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           35
+
+#define DIV_1_VS_MUL_1_PERCENT             258
+
+#define MUL_TOOM22_THRESHOLD                22
+#define MUL_TOOM33_THRESHOLD                73
+#define MUL_TOOM44_THRESHOLD               124
+#define MUL_TOOM6H_THRESHOLD               274
+#define MUL_TOOM8H_THRESHOLD               430
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      81
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD      99
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD      85
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD      88
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     113
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 26
+#define SQR_TOOM3_THRESHOLD                105
+#define SQR_TOOM4_THRESHOLD                154
+#define SQR_TOOM6_THRESHOLD                238
+#define SQR_TOOM8_THRESHOLD                309
+
+#define MULMID_TOOM42_THRESHOLD             50
+
+#define MULMOD_BNM1_THRESHOLD               15
+#define SQRMOD_BNM1_THRESHOLD               18
+
+#define MUL_FFT_MODF_THRESHOLD             570  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    570, 5}, {     21, 6}, {     11, 5}, {     25, 6}, \
+    {     13, 5}, {     27, 6}, {     15, 5}, {     31, 6}, \
+    {     25, 7}, {     13, 6}, {     27, 7}, {     15, 6}, \
+    {     32, 7}, {     17, 6}, {     35, 7}, {     19, 6}, \
+    {     39, 7}, {     27, 8}, {     15, 7}, {     35, 8}, \
+    {     19, 7}, {     41, 8}, {     23, 7}, {     47, 8}, \
+    {     27, 9}, {     15, 8}, {     31, 7}, {     63, 8}, \
+    {     39, 9}, {     23, 8}, {     55, 9}, {     31, 8}, \
+    {     67, 9}, {     39, 8}, {     79, 9}, {     47, 8}, \
+    {     95, 9}, {     55,10}, {     31, 9}, {     79,10}, \
+    {     47, 9}, {     95,11}, {     31,10}, {     63, 9}, \
+    {    135,10}, {     79, 9}, {    159,10}, {     95, 9}, \
+    {    191,11}, {     63,10}, {    143, 9}, {    287,10}, \
+    {    159,11}, {     95,10}, {    191,12}, {     63,11}, \
+    {    127,10}, {    255, 9}, {    511,10}, {    271, 9}, \
+    {    543,10}, {    287,11}, {    159,10}, {    319, 9}, \
+    {    639,10}, {    335, 9}, {    671,11}, {    191,10}, \
+    {    383, 9}, {    767,10}, {    399, 9}, {    799,11}, \
+    {    223,12}, {    127,11}, {    255,10}, {    543,11}, \
+    {    287,10}, {    607, 9}, {   1215,11}, {    319,10}, \
+    {    671,12}, {    191,11}, {    383,10}, {    799,11}, \
+    {    415,13}, {    127,12}, {    255,11}, {    543,10}, \
+    {   1087,11}, {    607,10}, {   1215,12}, {    319,11}, \
+    {    671,10}, {   1343,11}, {    735,10}, {   1471, 9}, \
+    {   2943,12}, {    383,11}, {    799,10}, {   1599,11}, \
+    {    863,12}, {    447,11}, {    959,13}, {    255,12}, \
+    {    511,11}, {   1087,12}, {    575,11}, {   1215,10}, \
+    {   2431,12}, {    639,11}, {   1343,12}, {    703,11}, \
+    {   1471,10}, {   2943,13}, {    383,12}, {    767,11}, \
+    {   1599,12}, {    831,11}, {   1727,10}, {   3455,12}, \
+    {    959,11}, {   1919,14}, {    255,13}, {    511,12}, \
+    {   1087,11}, {   2239,12}, {   1215,11}, {   2431,13}, \
+    {    639,12}, {   1471,11}, {   2943,13}, {    767,12}, \
+    {   1727,11}, {   3455,13}, {    895,12}, {   1983,14}, \
+    {    511,13}, {   1023,12}, {   2239,13}, {   1151,12}, \
+    {   2431,13}, {   1407,12}, {   2943,14}, {    767,13}, \
+    {   1663,12}, {   3455,13}, {   1919,15}, {    511,14}, \
+    {   1023,13}, {   2175,12}, {   4479,13}, {   2431,14}, \
+    {   1279,13}, {   2943,12}, {   5887,14}, {   1535,13}, \
+    {   3455,14}, {   1791,13}, {   3967,15}, {   1023,14}, \
+    {   2047,13}, {   4479,14}, {   2303,13}, {   4991,14}, \
+    {   2815,13}, {   5887,15}, {   1535,14}, {   3839,16} }
+#define MUL_FFT_TABLE3_SIZE 168
+#define MUL_FFT_THRESHOLD                 7424
+
+#define SQR_FFT_MODF_THRESHOLD             525  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    525, 5}, {     25, 6}, {     13, 5}, {     28, 6}, \
+    {     25, 7}, {     13, 6}, {     27, 7}, {     15, 6}, \
+    {     31, 7}, {     17, 6}, {     35, 7}, {     19, 6}, \
+    {     39, 7}, {     27, 8}, {     15, 7}, {     35, 8}, \
+    {     19, 7}, {     41, 8}, {     23, 7}, {     47, 8}, \
+    {     27, 9}, {     15, 8}, {     31, 7}, {     63, 8}, \
+    {     39, 9}, {     23, 8}, {     51, 9}, {     31, 8}, \
+    {     67, 9}, {     39, 8}, {     79, 9}, {     55,10}, \
+    {     31, 9}, {     79,10}, {     47, 9}, {     95,11}, \
+    {     31,10}, {     63, 9}, {    127,10}, {     79, 9}, \
+    {    159,10}, {     95,11}, {     63,10}, {    143, 9}, \
+    {    287,10}, {    159,11}, {     95,10}, {    191,12}, \
+    {     63,11}, {    127,10}, {    255, 9}, {    511,10}, \
+    {    271, 9}, {    543,10}, {    287,11}, {    159,10}, \
+    {    319, 9}, {    639,10}, {    335, 9}, {    671,10}, \
+    {    351,11}, {    191,10}, {    383, 9}, {    767,10}, \
+    {    399, 9}, {    799,10}, {    415,12}, {    127,11}, \
+    {    255,10}, {    543,11}, {    287,10}, {    607,11}, \
+    {    319,10}, {    671, 9}, {   1343,11}, {    351,10}, \
+    {    703,12}, {    191,11}, {    383,10}, {    799, 9}, \
+    {   1599,11}, {    415,10}, {    831,13}, {    127,12}, \
+    {    255,11}, {    543,10}, {   1087,11}, {    607,12}, \
+    {    319,11}, {    671,10}, {   1343,11}, {    735,10}, \
+    {   1471,12}, {    383,11}, {    799,10}, {   1599,11}, \
+    {    863,10}, {   1727,12}, {    447,11}, {    959,10}, \
+    {   1919,11}, {    991,12}, {    511,11}, {   1087,12}, \
+    {    575,11}, {   1215,10}, {   2431,12}, {    639,11}, \
+    {   1343,12}, {    703,11}, {   1471,13}, {    383,12}, \
+    {    767,11}, {   1599,12}, {    831,11}, {   1727,10}, \
+    {   3455,12}, {    959,11}, {   1919,13}, {    511,12}, \
+    {   1087,11}, {   2239,12}, {   1215,11}, {   2431,13}, \
+    {    639,12}, {   1471,11}, {   2943,13}, {    767,12}, \
+    {   1727,11}, {   3455,13}, {    895,12}, {   1919,14}, \
+    {    511,13}, {   1023,12}, {   2239,13}, {   1151,12}, \
+    {   2495,13}, {   1279,12}, {   2623,13}, {   1407,12}, \
+    {   2943,14}, {    767,13}, {   1663,12}, {   3455,13}, \
+    {   1919,15}, {    511,14}, {   1023,13}, {   2175,12}, \
+    {   4351,13}, {   2431,14}, {   1279,13}, {   2943,12}, \
+    {   5887,14}, {   1535,13}, {   3455,14}, {   1791,13}, \
+    {   3967,15}, {   1023,14}, {   2047,13}, {   4351,14}, \
+    {   2303,13}, {   4991,14}, {   2815,13}, {   5887,15}, \
+    {   1535,14}, {   3839,16} }
+#define SQR_FFT_TABLE3_SIZE 166
+#define SQR_FFT_THRESHOLD                 5312
+
+#define MULLO_BASECASE_THRESHOLD             6
+#define MULLO_DC_THRESHOLD                  40
+#define MULLO_MUL_N_THRESHOLD            14281
+#define SQRLO_BASECASE_THRESHOLD             8
+#define SQRLO_DC_THRESHOLD                 113
+#define SQRLO_SQR_THRESHOLD              10323
+
+#define DC_DIV_QR_THRESHOLD                 56
+#define DC_DIVAPPR_Q_THRESHOLD             248
+#define DC_BDIV_QR_THRESHOLD                55
+#define DC_BDIV_Q_THRESHOLD                158
+
+#define INV_MULMOD_BNM1_THRESHOLD           42
+#define INV_NEWTON_THRESHOLD               254
+#define INV_APPR_THRESHOLD                 252
+
+#define BINV_NEWTON_THRESHOLD              292
+#define REDC_1_TO_REDC_N_THRESHOLD          67
+
+#define MU_DIV_QR_THRESHOLD               1589
+#define MU_DIVAPPR_Q_THRESHOLD            1558
+#define MUPI_DIV_QR_THRESHOLD              114
+#define MU_BDIV_QR_THRESHOLD              1442
+#define MU_BDIV_Q_THRESHOLD               1524
+
+#define POWM_SEC_TABLE  1,16,102,416,1378
+
+#define GET_STR_DC_THRESHOLD                13
+#define GET_STR_PRECOMPUTE_THRESHOLD        21
+#define SET_STR_DC_THRESHOLD               270
+#define SET_STR_PRECOMPUTE_THRESHOLD      1105
+
+#define FAC_DSC_THRESHOLD                  159
+#define FAC_ODD_THRESHOLD                   34
+
+#define MATRIX22_STRASSEN_THRESHOLD         17
+#define HGCD2_DIV1_METHOD                    3  /* 0.70% faster than 4 */
+#define HGCD_THRESHOLD                     130
+#define HGCD_APPR_THRESHOLD                163
+#define HGCD_REDUCE_THRESHOLD             3389
+#define GCD_DC_THRESHOLD                   573
+#define GCDEXT_DC_THRESHOLD                393
+#define JACOBI_BASE_METHOD                   4  /* 9.13% faster than 1 */
+
+/* Tuneup completed successfully, took 52901 seconds */
diff --git a/third_party/gmp/mpn/x86/k6/README b/third_party/gmp/mpn/x86/k6/README
new file mode 100644
index 0000000..1d65af3
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k6/README
@@ -0,0 +1,251 @@
+Copyright 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.
+
+
+
+
+			AMD K6 MPN SUBROUTINES
+
+
+
+This directory contains code optimized for AMD K6 CPUs, meaning K6, K6-2 and
+K6-3.
+
+The mmx subdirectory has MMX code suiting plain K6, the k62mmx subdirectory
+has MMX code suiting K6-2 and K6-3.  All chips in the K6 family have MMX,
+the separate directories are just so that ./configure can omit them if the
+assembler doesn't support MMX.
+
+
+
+
+STATUS
+
+Times for the loops, with all code and data in L1 cache, are as follows.
+
+                                 cycles/limb
+
+	mpn_add_n/sub_n            3.25 normal, 2.75 in-place
+
+	mpn_mul_1                  6.25
+	mpn_add/submul_1           7.65-8.4  (varying with data values)
+
+	mpn_mul_basecase           9.25 cycles/crossproduct (approx)
+	mpn_sqr_basecase           4.7  cycles/crossproduct (approx)
+                                   or 9.2 cycles/triangleproduct (approx)
+
+	mpn_l/rshift               3.0
+
+	mpn_divrem_1              20.0
+	mpn_mod_1                 20.0
+	mpn_divexact_by3          11.0
+
+	mpn_copyi                  1.0
+	mpn_copyd                  1.0
+
+
+K6-2 and K6-3 have dual-issue MMX and get the following improvements.
+
+	mpn_l/rshift               1.75
+
+
+Prefetching of sources hasn't yet given any joy.  With the 3DNow "prefetch"
+instruction, code seems to run slower, and with just "mov" loads it doesn't
+seem faster.  Results so far are inconsistent.  The K6 does a hardware
+prefetch of the second cache line in a sector, so the penalty for not
+prefetching in software is reduced.
+
+
+
+
+NOTES
+
+All K6 family chips have MMX, but only K6-2 and K6-3 have 3DNow.
+
+Plain K6 executes MMX instructions only in the X pipe, but K6-2 and K6-3 can
+execute them in both X and Y (and in both together).
+
+Branch misprediction penalty is 1 to 4 cycles (Optimization Manual
+chapter 6 table 12).
+
+Write-allocate L1 data cache means prefetching of destinations is unnecessary.
+Store queue is 7 entries of 64 bits each.
+
+Floating point multiplications can be done in parallel with integer
+multiplications, but there doesn't seem to be any way to make use of this.
+
+
+
+OPTIMIZATIONS
+
+Unrolled loops are used to reduce looping overhead.  The unrolling is
+configurable up to 32 limbs/loop for most routines, up to 64 for some.
+
+Sometimes computed jumps into the unrolling are used to handle sizes not a
+multiple of the unrolling.  An attractive feature of this is that times
+smoothly increase with operand size, but an indirect jump is about 6 cycles
+and the setups about another 6, so it depends on how much the unrolled code
+is faster than a simple loop as to whether a computed jump ought to be used.
+
+Position independent code is implemented using a call to get eip for
+computed jumps and a ret is always done, rather than an addl $4,%esp or a
+popl, so the CPU return address branch prediction stack stays synchronised
+with the actual stack in memory.  Such a call however still costs 4 to 7
+cycles.
+
+Branch prediction, in absence of any history, will guess forward jumps are
+not taken and backward jumps are taken.  Where possible it's arranged that
+the less likely or less important case is under a taken forward jump.
+
+
+
+MMX
+
+Putting emms or femms as late as possible in a routine seems to be fastest.
+Perhaps an emms or femms stalls until all outstanding MMX instructions have
+completed, so putting it later gives them a chance to complete on their own,
+in parallel with other operations (like register popping).
+
+The Optimization Manual chapter 5 recommends using a femms on K6-2 and K6-3
+at the start of a routine, in case it's been preceded by x87 floating point
+operations.  This isn't done because in gmp programs it's expected that x87
+floating point won't be much used and that chances are an mpn routine won't
+have been preceded by any x87 code.
+
+
+
+CODING
+
+Instructions in general code are shown paired if they can decode and execute
+together, meaning two short decode instructions with the second not
+depending on the first, only the first using the shifter, no more than one
+load, and no more than one store.
+
+K6 does some out of order execution so the pairings aren't essential, they
+just show what slots might be available.  When decoding is the limiting
+factor things can be scheduled that might not execute until later.
+
+
+
+NOTES
+
+Code alignment
+
+- if an opcode/modrm or 0Fh/opcode/modrm crosses a cache line boundary,
+  short decode is inhibited.  The cross.pl script detects this.
+
+- loops and branch targets should be aligned to 16 bytes, or ensure at least
+  2 instructions before a 32 byte boundary.  This makes use of the 16 byte
+  cache in the BTB.
+
+Addressing modes
+
+- (%esi) degrades decoding from short to vector.  0(%esi) doesn't have this
+  problem, and can be used as an equivalent, or easier is just to use a
+  different register, like %ebx.
+
+- K6 and pre-CXT core K6-2 have the following problem.  (K6-2 CXT and K6-3
+  have it fixed, these being cpuid function 1 signatures 0x588 to 0x58F).
+
+  If more than 3 bytes are needed to determine instruction length then
+  decoding degrades from direct to long, or from long to vector.  This
+  happens with forms like "0F opcode mod/rm" with mod/rm=00-xxx-100 since
+  with mod=00 the sib determines whether there's a displacement.
+
+  This affects all MMX and 3DNow instructions, and others with an 0F prefix,
+  like movzbl.  The modes affected are anything with an index and no
+  displacement, or an index but no base, and this includes (%esp) which is
+  really (,%esp,1).
+
+  The cross.pl script detects problem cases.  The workaround is to always
+  use a displacement, and to do this with Zdisp if it's zero so the
+  assembler doesn't discard it.
+
+  See Optimization Manual rev D page 67 and 3DNow Porting Guide rev B pages
+  13-14 and 36-37.
+
+Calls
+
+- indirect jumps and calls are not branch predicted, they measure about 6
+  cycles.
+
+Various
+
+- adcl      2 cycles of decode, maybe 2 cycles executing in the X pipe
+- bsf       12-27 cycles
+- emms      5 cycles
+- femms     3 cycles
+- jecxz     2 cycles taken, 13 not taken (optimization manual says 7 not taken)
+- divl      20 cycles back-to-back
+- imull     2 decode, 3 execute
+- mull      2 decode, 3 execute (optimization manual decoding sample)
+- prefetch  2 cycles
+- rcll/rcrl implicit by one bit: 2 cycles
+            immediate or %cl count: 11 + 2 per bit for dword
+                                    13 + 4 per bit for byte
+- setCC	    2 cycles
+- xchgl	%eax,reg  1.5 cycles, back-to-back (strange)
+        reg,reg   2 cycles, back-to-back
+
+
+
+
+REFERENCES
+
+"AMD-K6 Processor Code Optimization Application Note", AMD publication
+number 21924, revision D amendment 0, January 2000.  This describes K6-2 and
+K6-3.  Available on-line,
+
+http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/21924.pdf
+
+"AMD-K6 MMX Enhanced Processor x86 Code Optimization Application Note", AMD
+publication number 21828, revision A amendment 0, August 1997.  This is an
+older edition of the above document, describing plain K6.  Available
+on-line,
+
+http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/21828.pdf
+
+"3DNow Technology Manual", AMD publication number 21928G/0-March 2000.
+This describes the femms and prefetch instructions, but nothing else from
+3DNow has been used.  Available on-line,
+
+http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/21928.pdf
+
+"3DNow Instruction Porting Guide", AMD publication number 22621, revision B,
+August 1999.  This has some notes on general K6 optimizations as well as
+3DNow.  Available on-line,
+
+http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/22621.pdf
+
+
+
+----------------
+Local variables:
+mode: text
+fill-column: 76
+End:
diff --git a/third_party/gmp/mpn/x86/k6/aors_n.asm b/third_party/gmp/mpn/x86/k6/aors_n.asm
new file mode 100644
index 0000000..168f9b4
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k6/aors_n.asm
@@ -0,0 +1,337 @@
+dnl  AMD K6 mpn_add/sub_n -- mpn addition or subtraction.
+
+dnl  Copyright 1999-2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C K6: normal 3.25 cycles/limb, in-place 2.75 cycles/limb.
+
+
+ifdef(`OPERATION_add_n', `
+	define(M4_inst,        adcl)
+	define(M4_function_n,  mpn_add_n)
+	define(M4_function_nc, mpn_add_nc)
+	define(M4_description, add)
+',`ifdef(`OPERATION_sub_n', `
+	define(M4_inst,        sbbl)
+	define(M4_function_n,  mpn_sub_n)
+	define(M4_function_nc, mpn_sub_nc)
+	define(M4_description, subtract)
+',`m4_error(`Need OPERATION_add_n or OPERATION_sub_n
+')')')
+
+MULFUNC_PROLOGUE(mpn_add_n mpn_add_nc mpn_sub_n mpn_sub_nc)
+
+
+C mp_limb_t M4_function_n (mp_ptr dst, mp_srcptr src1, mp_srcptr src2,
+C                          mp_size_t size);
+C mp_limb_t M4_function_nc (mp_ptr dst, mp_srcptr src1, mp_srcptr src2,
+C	                      mp_size_t size, mp_limb_t carry);
+C
+C Calculate src1,size M4_description src2,size, and store the result in
+C dst,size.  The return value is the carry bit from the top of the result
+C (1 or 0).
+C
+C The _nc version accepts 1 or 0 for an initial carry into the low limb of
+C the calculation.  Note values other than 1 or 0 here will lead to garbage
+C results.
+C
+C Instruction decoding limits a normal dst=src1+src2 operation to 3 c/l, and
+C an in-place dst+=src to 2.5 c/l.  The unrolled loops have 1 cycle/loop of
+C loop control, which with 4 limbs/loop means an extra 0.25 c/l.
+
+define(PARAM_CARRY, `FRAME+20(%esp)')
+define(PARAM_SIZE,  `FRAME+16(%esp)')
+define(PARAM_SRC2,  `FRAME+12(%esp)')
+define(PARAM_SRC1,  `FRAME+8(%esp)')
+define(PARAM_DST,   `FRAME+4(%esp)')
+deflit(`FRAME',0)
+
+dnl  minimum 5 because the unrolled code can't handle less
+deflit(UNROLL_THRESHOLD, 5)
+
+	TEXT
+	ALIGN(32)
+
+PROLOGUE(M4_function_nc)
+	movl	PARAM_CARRY, %eax
+	jmp	L(start)
+EPILOGUE()
+
+
+PROLOGUE(M4_function_n)
+	xorl	%eax, %eax
+L(start):
+	movl	PARAM_SIZE, %ecx
+	pushl	%ebx
+FRAME_pushl()
+
+	movl	PARAM_SRC1, %ebx
+	pushl	%edi
+FRAME_pushl()
+
+	movl	PARAM_SRC2, %edx
+	cmpl	$UNROLL_THRESHOLD, %ecx
+
+	movl	PARAM_DST, %edi
+	jae	L(unroll)
+
+
+	shrl	%eax		C initial carry flag
+
+	C offset 0x21 here, close enough to aligned
+L(simple):
+	C eax	scratch
+	C ebx	src1
+	C ecx	counter
+	C edx	src2
+	C esi
+	C edi	dst
+	C ebp
+	C
+	C The store to (%edi) could be done with a stosl; it'd be smaller
+	C code, but there's no speed gain and a cld would have to be added
+	C (per mpn/x86/README).
+
+	movl	(%ebx), %eax
+	leal	4(%ebx), %ebx
+
+	M4_inst	(%edx), %eax
+
+	movl	%eax, (%edi)
+	leal	4(%edi), %edi
+
+	leal	4(%edx), %edx
+	loop	L(simple)
+
+
+	movl	$0, %eax
+	popl	%edi
+
+	setc	%al
+
+	popl	%ebx
+	ret
+
+
+C -----------------------------------------------------------------------------
+L(unroll):
+	C eax	carry
+	C ebx	src1
+	C ecx	counter
+	C edx	src2
+	C esi
+	C edi	dst
+	C ebp
+
+	cmpl	%edi, %ebx
+	pushl	%esi
+
+	je	L(inplace)
+
+ifdef(`OPERATION_add_n',`
+	cmpl	%edi, %edx
+
+	je	L(inplace_reverse)
+')
+
+	movl	%ecx, %esi
+
+	andl	$-4, %ecx
+	andl	$3, %esi
+
+	leal	(%ebx,%ecx,4), %ebx
+	leal	(%edx,%ecx,4), %edx
+	leal	(%edi,%ecx,4), %edi
+
+	negl	%ecx
+	shrl	%eax
+
+	ALIGN(32)
+L(normal_top):
+	C eax	counter, qwords, negative
+	C ebx	src1
+	C ecx	scratch
+	C edx	src2
+	C esi
+	C edi	dst
+	C ebp
+
+	movl	(%ebx,%ecx,4), %eax
+	leal	5(%ecx), %ecx
+	M4_inst	-20(%edx,%ecx,4), %eax
+	movl	%eax, -20(%edi,%ecx,4)
+
+	movl	4-20(%ebx,%ecx,4), %eax
+	M4_inst	4-20(%edx,%ecx,4), %eax
+	movl	%eax, 4-20(%edi,%ecx,4)
+
+	movl	8-20(%ebx,%ecx,4), %eax
+	M4_inst	8-20(%edx,%ecx,4), %eax
+	movl	%eax, 8-20(%edi,%ecx,4)
+
+	movl	12-20(%ebx,%ecx,4), %eax
+	M4_inst	12-20(%edx,%ecx,4), %eax
+	movl	%eax, 12-20(%edi,%ecx,4)
+
+	loop	L(normal_top)
+
+
+	decl	%esi
+	jz	L(normal_finish_one)
+	js	L(normal_done)
+
+	C two or three more limbs
+
+	movl	(%ebx), %eax
+	M4_inst	(%edx), %eax
+	movl	%eax, (%edi)
+
+	movl	4(%ebx), %eax
+	M4_inst	4(%edx), %eax
+	decl	%esi
+	movl	%eax, 4(%edi)
+
+	jz	L(normal_done)
+	movl	$2, %ecx
+
+L(normal_finish_one):
+	movl	(%ebx,%ecx,4), %eax
+	M4_inst	(%edx,%ecx,4), %eax
+	movl	%eax, (%edi,%ecx,4)
+
+L(normal_done):
+	popl	%esi
+	popl	%edi
+
+	movl	$0, %eax
+	popl	%ebx
+
+	setc	%al
+
+	ret
+
+
+C -----------------------------------------------------------------------------
+
+ifdef(`OPERATION_add_n',`
+L(inplace_reverse):
+	C dst==src2
+
+	movl	%ebx, %edx
+')
+
+L(inplace):
+	C eax	initial carry
+	C ebx
+	C ecx	size
+	C edx	src
+	C esi
+	C edi	dst
+	C ebp
+
+	leal	-1(%ecx), %esi
+	decl	%ecx
+
+	andl	$-4, %ecx
+	andl	$3, %esi
+
+	movl	(%edx), %ebx		C src low limb
+	leal	(%edx,%ecx,4), %edx
+
+	leal	(%edi,%ecx,4), %edi
+	negl	%ecx
+
+	shrl	%eax
+
+
+	ALIGN(32)
+L(inplace_top):
+	C eax
+	C ebx	next src limb
+	C ecx	size
+	C edx	src
+	C esi
+	C edi	dst
+	C ebp
+
+	M4_inst	%ebx, (%edi,%ecx,4)
+
+	movl	4(%edx,%ecx,4), %eax
+	leal	5(%ecx), %ecx
+
+	M4_inst	%eax, 4-20(%edi,%ecx,4)
+
+	movl	8-20(%edx,%ecx,4), %eax
+	movl	12-20(%edx,%ecx,4), %ebx
+
+	M4_inst	%eax, 8-20(%edi,%ecx,4)
+	M4_inst	%ebx, 12-20(%edi,%ecx,4)
+
+	movl	16-20(%edx,%ecx,4), %ebx
+	loop	L(inplace_top)
+
+
+	C now %esi is 0 to 3 representing respectively 1 to 4 limbs more
+
+	M4_inst	%ebx, (%edi)
+
+	decl	%esi
+	jz	L(inplace_finish_one)
+	js	L(inplace_done)
+
+	C two or three more limbs
+
+	movl	4(%edx), %eax
+	movl	8(%edx), %ebx
+	M4_inst	%eax, 4(%edi)
+	M4_inst	%ebx, 8(%edi)
+
+	decl	%esi
+	movl	$2, %ecx
+
+	jz	L(normal_done)
+
+L(inplace_finish_one):
+	movl	4(%edx,%ecx,4), %eax
+	M4_inst	%eax, 4(%edi,%ecx,4)
+
+L(inplace_done):
+	popl	%esi
+	popl	%edi
+
+	movl	$0, %eax
+	popl	%ebx
+
+	setc	%al
+
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/k6/aorsmul_1.asm b/third_party/gmp/mpn/x86/k6/aorsmul_1.asm
new file mode 100644
index 0000000..eaa92eb
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k6/aorsmul_1.asm
@@ -0,0 +1,391 @@
+dnl  AMD K6 mpn_addmul_1/mpn_submul_1 -- add or subtract mpn multiple.
+
+dnl  Copyright 1999-2003, 2005 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C			    cycles/limb
+C P5
+C P6 model 0-8,10-12		 5.94
+C P6 model 9  (Banias)		 5.51
+C P6 model 13 (Dothan)		 5.57
+C P4 model 0  (Willamette)
+C P4 model 1  (?)
+C P4 model 2  (Northwood)
+C P4 model 3  (Prescott)
+C P4 model 4  (Nocona)
+C AMD K6			7.65-8.5 (data dependent)
+C AMD K7
+C AMD K8
+
+
+dnl  K6:           large multipliers  small multipliers
+dnl  UNROLL_COUNT    cycles/limb       cycles/limb
+dnl        4             9.5              7.78
+dnl        8             9.0              7.78
+dnl       16             8.4              7.65
+dnl       32             8.4              8.2
+dnl
+dnl  Maximum possible unrolling with the current code is 32.
+dnl
+dnl  Unrolling to 16 limbs/loop makes the unrolled loop fit exactly in a 256
+dnl  byte block, which might explain the good speed at that unrolling.
+
+deflit(UNROLL_COUNT, 16)
+
+
+ifdef(`OPERATION_addmul_1', `
+	define(M4_inst,        addl)
+	define(M4_function_1,  mpn_addmul_1)
+	define(M4_function_1c, mpn_addmul_1c)
+',`ifdef(`OPERATION_submul_1', `
+	define(M4_inst,        subl)
+	define(M4_function_1,  mpn_submul_1)
+	define(M4_function_1c, mpn_submul_1c)
+',`m4_error(`Need OPERATION_addmul_1 or OPERATION_submul_1
+')')')
+
+MULFUNC_PROLOGUE(mpn_addmul_1 mpn_addmul_1c mpn_submul_1 mpn_submul_1c)
+
+
+C mp_limb_t mpn_addmul_1 (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                         mp_limb_t mult);
+C mp_limb_t mpn_addmul_1c (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                          mp_limb_t mult, mp_limb_t carry);
+C mp_limb_t mpn_submul_1 (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                         mp_limb_t mult);
+C mp_limb_t mpn_submul_1c (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                          mp_limb_t mult, mp_limb_t carry);
+C
+C The jadcl0()s in the unrolled loop makes the speed data dependent.  Small
+C multipliers (most significant few bits clear) result in few carry bits and
+C speeds up to 7.65 cycles/limb are attained.  Large multipliers (most
+C significant few bits set) make the carry bits 50/50 and lead to something
+C more like 8.4 c/l.  With adcl's both of these would be 9.3 c/l.
+C
+C It's important that the gains for jadcl0 on small multipliers don't come
+C at the cost of slowing down other data.  Tests on uniformly distributed
+C random data, designed to confound branch prediction, show about a 7%
+C speed-up using jadcl0 over adcl (8.93 versus 9.57 cycles/limb, with all
+C overheads included).
+C
+C In the simple loop, jadcl0() measures slower than adcl (11.9-14.7 versus
+C 11.0 cycles/limb), and hence isn't used.
+C
+C In the simple loop, note that running ecx from negative to zero and using
+C it as an index in the two movs wouldn't help.  It would save one
+C instruction (2*addl+loop becoming incl+jnz), but there's nothing unpaired
+C that would be collapsed by this.
+C
+C Attempts at a simpler main loop, with less unrolling, haven't yielded much
+C success, generally running over 9 c/l.
+C
+C
+C jadcl0
+C ------
+C
+C jadcl0() being faster than adcl $0 seems to be an artifact of two things,
+C firstly the instruction decoding and secondly the fact that there's a
+C carry bit for the jadcl0 only on average about 1/4 of the time.
+C
+C The code in the unrolled loop decodes something like the following.
+C
+C                                         decode cycles
+C		mull	%ebp                    2
+C		M4_inst	%esi, disp(%edi)        1
+C		adcl	%eax, %ecx              2
+C		movl	%edx, %esi            \ 1
+C		jnc	1f                    /
+C		incl	%esi                  \ 1
+C	1:	movl	disp(%ebx), %eax      /
+C                                              ---
+C                                               7
+C
+C In a back-to-back style test this measures 7 with the jnc not taken, or 8
+C with it taken (both when correctly predicted).  This is opposite to the
+C measurements showing small multipliers running faster than large ones.
+C Don't really know why.
+C
+C It's not clear how much branch misprediction might be costing.  The K6
+C doco says it will be 1 to 4 cycles, but presumably it's near the low end
+C of that range to get the measured results.
+C
+C
+C In the code the two carries are more or less the preceding mul product and
+C the calculation is roughly
+C
+C	x*y + u*b+v
+C
+C where b=2^32 is the size of a limb, x*y is the two carry limbs, and u and
+C v are the two limbs it's added to (being the low of the next mul, and a
+C limb from the destination).
+C
+C To get a carry requires x*y+u*b+v >= b^2, which is u*b+v >= b^2-x*y, and
+C there are b^2-(b^2-x*y) = x*y many such values, giving a probability of
+C x*y/b^2.  If x, y, u and v are random and uniformly distributed between 0
+C and b-1, then the total probability can be summed over x and y,
+C
+C	 1    b-1 b-1 x*y    1    b*(b-1)   b*(b-1)
+C	--- * sum sum --- = --- * ------- * ------- = 1/4
+C       b^2   x=0 y=1 b^2   b^4      2         2
+C
+C Actually it's a very tiny bit less than 1/4 of course.  If y is fixed,
+C then the probability is 1/2*y/b thus varying linearly between 0 and 1/2.
+
+
+ifdef(`PIC',`
+deflit(UNROLL_THRESHOLD, 9)
+',`
+deflit(UNROLL_THRESHOLD, 6)
+')
+
+defframe(PARAM_CARRY,     20)
+defframe(PARAM_MULTIPLIER,16)
+defframe(PARAM_SIZE,      12)
+defframe(PARAM_SRC,       8)
+defframe(PARAM_DST,       4)
+
+	TEXT
+	ALIGN(32)
+
+PROLOGUE(M4_function_1c)
+	pushl	%esi
+deflit(`FRAME',4)
+	movl	PARAM_CARRY, %esi
+	jmp	L(start_nc)
+EPILOGUE()
+
+PROLOGUE(M4_function_1)
+	push	%esi
+deflit(`FRAME',4)
+	xorl	%esi, %esi	C initial carry
+
+L(start_nc):
+	movl	PARAM_SIZE, %ecx
+	pushl	%ebx
+deflit(`FRAME',8)
+
+	movl	PARAM_SRC, %ebx
+	pushl	%edi
+deflit(`FRAME',12)
+
+	cmpl	$UNROLL_THRESHOLD, %ecx
+	movl	PARAM_DST, %edi
+
+	pushl	%ebp
+deflit(`FRAME',16)
+	jae	L(unroll)
+
+
+	C simple loop
+
+	movl	PARAM_MULTIPLIER, %ebp
+
+L(simple):
+	C eax	scratch
+	C ebx	src
+	C ecx	counter
+	C edx	scratch
+	C esi	carry
+	C edi	dst
+	C ebp	multiplier
+
+	movl	(%ebx), %eax
+	addl	$4, %ebx
+
+	mull	%ebp
+
+	addl	$4, %edi
+	addl	%esi, %eax
+
+	adcl	$0, %edx
+
+	M4_inst	%eax, -4(%edi)
+
+	adcl	$0, %edx
+
+	movl	%edx, %esi
+	loop	L(simple)
+
+
+	popl	%ebp
+	popl	%edi
+
+	popl	%ebx
+	movl	%esi, %eax
+
+	popl	%esi
+	ret
+
+
+
+C -----------------------------------------------------------------------------
+C The unrolled loop uses a "two carry limbs" scheme.  At the top of the loop
+C the carries are ecx=lo, esi=hi, then they swap for each limb processed.
+C For the computed jump an odd size means they start one way around, an even
+C size the other.
+C
+C VAR_JUMP holds the computed jump temporarily because there's not enough
+C registers at the point of doing the mul for the initial two carry limbs.
+C
+C The add/adc for the initial carry in %esi is necessary only for the
+C mpn_addmul/submul_1c entry points.  Duplicating the startup code to
+C eliminate this for the plain mpn_add/submul_1 doesn't seem like a good
+C idea.
+
+dnl  overlapping with parameters already fetched
+define(VAR_COUNTER, `PARAM_SIZE')
+define(VAR_JUMP,    `PARAM_DST')
+
+L(unroll):
+	C eax
+	C ebx	src
+	C ecx	size
+	C edx
+	C esi	initial carry
+	C edi	dst
+	C ebp
+
+	movl	%ecx, %edx
+	decl	%ecx
+
+	subl	$2, %edx
+	negl	%ecx
+
+	shrl	$UNROLL_LOG2, %edx
+	andl	$UNROLL_MASK, %ecx
+
+	movl	%edx, VAR_COUNTER
+	movl	%ecx, %edx
+
+	shll	$4, %edx
+	negl	%ecx
+
+	C 15 code bytes per limb
+ifdef(`PIC',`
+	call	L(pic_calc)
+L(here):
+',`
+	leal	L(entry) (%edx,%ecx,1), %edx
+')
+	movl	(%ebx), %eax		C src low limb
+
+	movl	PARAM_MULTIPLIER, %ebp
+	movl	%edx, VAR_JUMP
+
+	mull	%ebp
+
+	addl	%esi, %eax	C initial carry (from _1c)
+	jadcl0(	%edx)
+
+
+	leal	4(%ebx,%ecx,4), %ebx
+	movl	%edx, %esi	C high carry
+
+	movl	VAR_JUMP, %edx
+	leal	(%edi,%ecx,4), %edi
+
+	testl	$1, %ecx
+	movl	%eax, %ecx	C low carry
+
+	jz	L(noswap)
+	movl	%esi, %ecx	C high,low carry other way around
+
+	movl	%eax, %esi
+L(noswap):
+
+	jmp	*%edx
+
+
+ifdef(`PIC',`
+L(pic_calc):
+	C See mpn/x86/README about old gas bugs
+	leal	(%edx,%ecx,1), %edx
+	addl	$L(entry)-L(here), %edx
+	addl	(%esp), %edx
+	ret_internal
+')
+
+
+C -----------------------------------------------------------
+	ALIGN(32)
+L(top):
+deflit(`FRAME',16)
+	C eax	scratch
+	C ebx	src
+	C ecx	carry lo
+	C edx	scratch
+	C esi	carry hi
+	C edi	dst
+	C ebp	multiplier
+	C
+	C 15 code bytes per limb
+
+	leal	UNROLL_BYTES(%edi), %edi
+
+L(entry):
+forloop(`i', 0, UNROLL_COUNT/2-1, `
+	deflit(`disp0', eval(2*i*4))
+	deflit(`disp1', eval(disp0 + 4))
+
+Zdisp(	movl,	disp0,(%ebx), %eax)
+	mull	%ebp
+Zdisp(	M4_inst,%ecx, disp0,(%edi))
+	adcl	%eax, %esi
+	movl	%edx, %ecx
+	jadcl0(	%ecx)
+
+	movl	disp1(%ebx), %eax
+	mull	%ebp
+	M4_inst	%esi, disp1(%edi)
+	adcl	%eax, %ecx
+	movl	%edx, %esi
+	jadcl0(	%esi)
+')
+
+	decl	VAR_COUNTER
+
+	leal	UNROLL_BYTES(%ebx), %ebx
+	jns	L(top)
+
+
+	popl	%ebp
+	M4_inst	%ecx, UNROLL_BYTES(%edi)
+
+	popl	%edi
+	movl	%esi, %eax
+
+	popl	%ebx
+	jadcl0(	%eax)
+
+	popl	%esi
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/k6/cross.pl b/third_party/gmp/mpn/x86/k6/cross.pl
new file mode 100755
index 0000000..fc921a5
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k6/cross.pl
@@ -0,0 +1,182 @@
+#! /usr/bin/perl
+
+# Copyright 2000, 2001 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+
+# Usage: cross.pl [filename.o]...
+#
+# Produce an annotated disassembly of the given object files, indicating
+# certain code alignment and addressing mode problems afflicting K6 chips.
+# "ZZ" is used on all annotations, so this can be searched for.
+#
+# With no arguments, all .o files corresponding to .asm files are processed.
+# This is good in the mpn object directory of a k6*-*-* build.
+#
+# Code alignments of 8 bytes or more are handled.  When 32 is used, cache
+# line boundaries will fall in at offsets 0x20,0x40,etc and problems are
+# flagged at those locations.  When 16 is used, the line boundaries can also
+# fall at offsets 0x10,0x30,0x50,etc, depending where the file is loaded, so
+# problems are identified there too.  Likewise when 8 byte alignment is used
+# problems are flagged additionally at 0x08,0x18,0x28,etc.
+#
+# Usually 32 byte alignment is used for k6 routines, but less is certainly
+# possible if through good luck, or a little tweaking, cache line crossing
+# problems can be avoided at the extra locations.
+#
+# Bugs:
+#
+# Instructions without mod/rm bytes or which are already vector decoded are
+# unaffected by cache line boundary crossing, but not all of these have yet
+# been put in as exceptions.  All that occur in practice in GMP are present
+# though.
+#
+# There's no messages for using the vector decoded addressing mode (%esi),
+# but that's easy to avoid when coding.
+#
+# Future:
+#
+# Warn about jump targets that are poorly aligned (less than 2 instructions
+# before a cache line boundary).
+
+use strict;
+
+sub disassemble {
+    my ($file) = @_;
+    my ($addr,$b1,$b2,$b3, $prefix,$opcode,$modrm);
+    my $align;
+
+    open (IN, "objdump -Srfh $file |")
+	|| die "Cannot open pipe from objdump\n";
+    while (<IN>) {
+	print;
+
+	if (/^[ \t]*[0-9]+[ \t]+\.text[ \t]/ && /2\*\*([0-9]+)$/) {
+	    $align = 1 << $1;
+	    if ($align < 8) {
+		print "ZZ cross.pl cannot handle alignment < 2**3\n";
+		$align = 8
+	    }
+	}
+
+	if (/^[ \t]*([0-9a-f]*):[ \t]*([0-9a-f]+)[ \t]+([0-9a-f]+)[ \t]+([0-9a-f]+)/) {
+	    ($addr,$b1,$b2,$b3) = ($1,$2,$3,$4);
+
+	} elsif (/^[ \t]*([0-9a-f]*):[ \t]*([0-9a-f]+)[ \t]+([0-9a-f]+)/) {
+	    ($addr,$b1,$b2,$b3) = ($1,$2,$3,'');
+
+	} elsif (/^[ \t]*([0-9a-f]*):[ \t]*([0-9a-f]+)/) {
+	    ($addr,$b1,$b2,$b3) = ($1,$2,'','');
+
+	} else {
+	    next;
+	}
+
+	if ($b1 =~ /0f/) {
+	    $prefix = $b1;
+	    $opcode = $b2;
+	    $modrm = $b3;
+	} else {
+	    $prefix = '';
+	    $opcode = $b1;
+	    $modrm = $b2;
+	}
+
+	# modrm of the form 00-xxx-100 with an 0F prefix is the problem case
+	# for K6 and pre-CXT K6-2
+	if ($prefix =~ /0f/
+	    && $opcode !~ /^8/         # jcond disp32
+	    && $modrm =~ /^[0-3][4c]/) {
+	    print "ZZ ($file) >3 bytes to determine instruction length [K6]\n";
+	}
+
+	# with just an opcode, starting 1f mod 20h
+	if (($align==32 && $addr =~ /[13579bdf]f$/
+	     || $align==16 && $addr =~ /f$/
+	     || $align==8 && $addr =~ /[7f]$/)
+	    && $prefix !~ /0f/
+	    && $opcode !~ /1[012345]/ # adc
+	    && $opcode !~ /1[89abcd]/ # sbb
+	    && $opcode !~ /^4/        # inc/dec reg
+	    && $opcode !~ /^5/        # push/pop reg
+	    && $opcode !~ /68/        # push $imm32
+	    && $opcode !~ /^7/        # jcond disp8
+	    && $opcode !~ /a[89]/     # test+imm
+	    && $opcode !~ /a[a-f]/    # stos/lods/scas
+	    && $opcode !~ /b8/        # movl $imm32,%eax
+	    && $opcode !~ /d[0123]/   # rcl
+	    && $opcode !~ /e[0123]/   # loop/loopz/loopnz/jcxz
+	    && $opcode !~ /e8/        # call disp32
+	    && $opcode !~ /e[9b]/     # jmp disp32/disp8
+	    && $opcode !~ /f[89abcd]/ # clc,stc,cli,sti,cld,std
+	    && !($opcode =~ /f[67]/          # grp 1
+		 && $modrm =~ /^[2367abef]/) # mul, imul, div, idiv
+	    && $modrm !~ /^$/) {
+	    print "ZZ ($file) opcode/modrm cross 32-byte boundary\n";
+	}
+
+	# with an 0F prefix, anything starting at 1f mod 20h
+	if (($align==32 && $addr =~ /[13579bdf][f]$/
+	     || $align==16 && $addr =~ /f$/
+	     || $align==8 && $addr =~ /[7f]$/)
+	    && $prefix =~ /0f/
+	    && $opcode !~ /af/        # imul
+	    && $opcode !~ /a[45]/     # shldl
+	    && $opcode !~ /a[cd]/     # shrdl
+	    ) {
+	    print "ZZ ($file) prefix/opcode cross 32-byte boundary\n";
+	}
+
+	# with an 0F prefix, anything with mod/rm starting at 1e mod 20h
+	if (($align==32 && $addr =~ /[13579bdf][e]$/
+	     || $align==16 && $addr =~ /[e]$/
+	     || $align==8 && $addr =~ /[6e]$/)
+	    && $prefix =~ /0f/
+	     && $opcode !~ /^8/        # jcond disp32
+	     && $opcode !~ /af/        # imull reg,reg
+	     && $opcode !~ /a[45]/     # shldl
+	     && $opcode !~ /a[cd]/     # shrdl
+	    && $modrm !~ /^$/) {
+	    print "ZZ ($file) prefix/opcode/modrm cross 32-byte boundary\n";
+	}
+    }
+    close IN || die "Error from objdump (or objdump not available)\n";
+}
+
+
+my @files;
+if ($#ARGV >= 0) {
+    @files = @ARGV;
+} else {
+    @files = glob "*.asm";
+    map {s/.asm/.o/} @files;
+}
+
+foreach (@files)  {
+    disassemble($_);
+}
diff --git a/third_party/gmp/mpn/x86/k6/divrem_1.asm b/third_party/gmp/mpn/x86/k6/divrem_1.asm
new file mode 100644
index 0000000..b4cea4f
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k6/divrem_1.asm
@@ -0,0 +1,203 @@
+dnl  AMD K6 mpn_divrem_1 -- mpn by limb division.
+
+dnl  Copyright 1999-2003, 2007 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C K6: 20 cycles/limb
+
+
+C mp_limb_t mpn_divrem_1 (mp_ptr dst, mp_size_t xsize,
+C                         mp_srcptr src, mp_size_t size, mp_limb_t divisor);
+C mp_limb_t mpn_divrem_1c (mp_ptr dst, mp_size_t xsize,
+C                          mp_srcptr src, mp_size_t size, mp_limb_t divisor,
+C                          mp_limb_t carry);
+C
+C The code here is basically the same as mpn/x86/divrem_1.asm, but uses loop
+C instead of decl+jnz, since it comes out 2 cycles/limb faster.
+C
+C A test is done to see if the high limb is less than the divisor, and if so
+C one less div is done.  A div is 20 cycles, so assuming high<divisor about
+C half the time, then this test saves half that amount.  The branch
+C misprediction penalty is less than that.
+C
+C Back-to-back div instructions run at 20 cycles, the same as the loop here,
+C so it seems there's nothing to gain by rearranging the loop.  Pairing the
+C mov and loop instructions was found to gain nothing.
+C
+C Enhancements:
+C
+C The low-latency K6 multiply might be thought to suit a mul-by-inverse, but
+C that algorithm has been found to suffer from the relatively poor carry
+C handling on K6 and too many auxiliary instructions.  The fractional part
+C however could be done at about 13 c/l, if it mattered enough.
+
+defframe(PARAM_CARRY,  24)
+defframe(PARAM_DIVISOR,20)
+defframe(PARAM_SIZE,   16)
+defframe(PARAM_SRC,    12)
+defframe(PARAM_XSIZE,  8)
+defframe(PARAM_DST,    4)
+
+	TEXT
+
+	ALIGN(32)
+PROLOGUE(mpn_divrem_1c)
+deflit(`FRAME',0)
+
+	movl	PARAM_SIZE, %ecx
+	pushl	%edi		FRAME_pushl()
+
+	movl	PARAM_SRC, %edi
+	pushl	%esi		FRAME_pushl()
+
+	movl	PARAM_DIVISOR, %esi
+	pushl	%ebx		FRAME_pushl()
+
+	movl	PARAM_DST, %ebx
+	pushl	%ebp		FRAME_pushl()
+
+	movl	PARAM_XSIZE, %ebp
+	orl	%ecx, %ecx		C size
+
+	movl	PARAM_CARRY, %edx
+	jz	L(fraction)		C if size==0
+
+	leal	-4(%ebx,%ebp,4), %ebx	C dst one limb below integer part
+	jmp	L(integer_top)
+
+EPILOGUE()
+
+
+	ALIGN(16)
+PROLOGUE(mpn_divrem_1)
+deflit(`FRAME',0)
+
+	movl	PARAM_SIZE, %ecx
+	pushl	%edi		FRAME_pushl()
+
+	movl	PARAM_SRC, %edi
+	pushl	%esi		FRAME_pushl()
+
+	movl	PARAM_DIVISOR, %esi
+	orl	%ecx,%ecx		C size
+
+	jz	L(size_zero)
+	pushl	%ebx		FRAME_pushl()
+
+	movl	-4(%edi,%ecx,4), %eax	C src high limb
+	xorl	%edx, %edx
+
+	movl	PARAM_DST, %ebx
+	pushl	%ebp		FRAME_pushl()
+
+	movl	PARAM_XSIZE, %ebp
+	cmpl	%esi, %eax
+
+	leal	-4(%ebx,%ebp,4), %ebx	C dst one limb below integer part
+	jae	L(integer_entry)
+
+
+	C high<divisor, so high of dst is zero, and avoid one div
+
+	movl	%edx, (%ebx,%ecx,4)
+	decl	%ecx
+
+	movl	%eax, %edx
+	jz	L(fraction)
+
+
+L(integer_top):
+	C eax	scratch (quotient)
+	C ebx	dst+4*xsize-4
+	C ecx	counter
+	C edx	scratch (remainder)
+	C esi	divisor
+	C edi	src
+	C ebp	xsize
+
+	movl	-4(%edi,%ecx,4), %eax
+L(integer_entry):
+
+	divl	%esi
+
+	movl	%eax, (%ebx,%ecx,4)
+	loop	L(integer_top)
+
+
+L(fraction):
+	orl	%ebp, %ecx
+	jz	L(done)
+
+	movl	PARAM_DST, %ebx
+
+
+L(fraction_top):
+	C eax	scratch (quotient)
+	C ebx	dst
+	C ecx	counter
+	C edx	scratch (remainder)
+	C esi	divisor
+	C edi
+	C ebp
+
+	xorl	%eax, %eax
+
+	divl	%esi
+
+	movl	%eax, -4(%ebx,%ecx,4)
+	loop	L(fraction_top)
+
+
+L(done):
+	popl	%ebp
+	movl	%edx, %eax
+	popl	%ebx
+	popl	%esi
+	popl	%edi
+	ret
+
+
+L(size_zero):
+deflit(`FRAME',8)
+	movl	PARAM_XSIZE, %ecx
+	xorl	%eax, %eax
+
+	movl	PARAM_DST, %edi
+
+	cld	C better safe than sorry, see mpn/x86/README
+
+	rep
+	stosl
+
+	popl	%esi
+	popl	%edi
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/k6/gmp-mparam.h b/third_party/gmp/mpn/x86/k6/gmp-mparam.h
new file mode 100644
index 0000000..f03f1b2
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k6/gmp-mparam.h
@@ -0,0 +1,166 @@
+/* AMD K6 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 2000-2004, 2009, 2010 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+
+/* 450MHz K6-2 */
+
+#define MOD_1_NORM_THRESHOLD                12
+#define MOD_1_UNNORM_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD         41
+#define MOD_1U_TO_MOD_1_1_THRESHOLD         32
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD         3
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD         0
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD    128
+#define USE_PREINV_DIVREM_1                  0
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD        MP_SIZE_T_MAX  /* never */
+
+#define MUL_TOOM22_THRESHOLD                20
+#define MUL_TOOM33_THRESHOLD                69
+#define MUL_TOOM44_THRESHOLD               106
+#define MUL_TOOM6H_THRESHOLD               157
+#define MUL_TOOM8H_THRESHOLD               199
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      73
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD      69
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD      65
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD      64
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 32
+#define SQR_TOOM3_THRESHOLD                 97
+#define SQR_TOOM4_THRESHOLD                143
+#define SQR_TOOM6_THRESHOLD                222
+#define SQR_TOOM8_THRESHOLD                272
+
+#define MULMOD_BNM1_THRESHOLD               13
+#define SQRMOD_BNM1_THRESHOLD               17
+
+#define MUL_FFT_MODF_THRESHOLD             476  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    476, 5}, {     17, 6}, {      9, 5}, {     19, 6}, \
+    {     11, 5}, {     23, 6}, {     17, 7}, {      9, 6}, \
+    {     19, 7}, {     11, 6}, {     23, 7}, {     13, 6}, \
+    {     27, 7}, {     15, 6}, {     31, 7}, {     17, 6}, \
+    {     35, 7}, {     21, 8}, {     11, 7}, {     27, 8}, \
+    {     15, 7}, {     35, 8}, {     19, 7}, {     39, 8}, \
+    {     23, 7}, {     47, 8}, {     27, 9}, {     15, 8}, \
+    {     31, 7}, {     63, 8}, {     39, 9}, {     23, 8}, \
+    {     51,10}, {     15, 9}, {     31, 8}, {     67, 9}, \
+    {     47,10}, {     31, 9}, {     79,10}, {     47, 9}, \
+    {     95,11}, {     31,10}, {     63, 9}, {    135,10}, \
+    {     79, 9}, {    167,10}, {     95, 9}, {    191,10}, \
+    {    111,11}, {     63,10}, {    127, 9}, {    255,10}, \
+    {    143, 9}, {    287,10}, {    159,11}, {     95,10}, \
+    {    191, 9}, {    383,12}, {     63,11}, {    127,10}, \
+    {    255, 9}, {    511,10}, {    271, 9}, {    543,10}, \
+    {    287,11}, {    159,10}, {    351,11}, {    191,10}, \
+    {    415, 9}, {    831,11}, {    223,12}, {    127,11}, \
+    {    255,10}, {    543,11}, {    287,10}, {    575,11}, \
+    {    351,10}, {    703,12}, {    191,11}, {    415,10}, \
+    {    831,13}, {    127,12}, {    255,11}, {    543,10}, \
+    {   1087,11}, {    575,12}, {    319,11}, {    703,12}, \
+    {    383,11}, {    831,12}, {    447,11}, {    895,13}, \
+    {    255,12}, {    511,11}, {   1087,12}, {    575,11}, \
+    {   1151,12}, {    703,13}, {    383,12}, {    959,14}, \
+    {    255,13}, {    511,12}, {   1215,13}, {   8192,14}, \
+    {  16384,15}, {  32768,16} }
+#define MUL_FFT_TABLE3_SIZE 106
+#define MUL_FFT_THRESHOLD                 7424
+
+#define SQR_FFT_MODF_THRESHOLD             432  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    432, 5}, {     17, 6}, {      9, 5}, {     19, 6}, \
+    {     11, 5}, {     23, 6}, {     21, 7}, {     11, 6}, \
+    {     24, 7}, {     13, 6}, {     27, 7}, {     15, 6}, \
+    {     31, 7}, {     21, 8}, {     11, 7}, {     29, 8}, \
+    {     15, 7}, {     35, 8}, {     19, 7}, {     39, 8}, \
+    {     23, 7}, {     49, 8}, {     27, 9}, {     15, 8}, \
+    {     39, 9}, {     23, 7}, {     93, 8}, {     47, 7}, \
+    {     95, 8}, {     51,10}, {     15, 9}, {     31, 8}, \
+    {     67, 9}, {     39, 8}, {     79, 9}, {     47, 8}, \
+    {     95, 9}, {     55,10}, {     31, 9}, {     71, 8}, \
+    {    143, 9}, {     79,10}, {     47, 9}, {     95,11}, \
+    {     31,10}, {     63, 9}, {    135,10}, {     79, 9}, \
+    {    167,10}, {     95, 9}, {    191,11}, {     63,10}, \
+    {    127, 9}, {    255,10}, {    143, 9}, {    287, 8}, \
+    {    575,10}, {    159, 9}, {    319,11}, {     95,10}, \
+    {    191,12}, {     63,11}, {    127,10}, {    255, 9}, \
+    {    511,10}, {    271, 9}, {    543,10}, {    287,11}, \
+    {    159,10}, {    319, 9}, {    639,10}, {    351, 9}, \
+    {    703,11}, {    191,10}, {    415,11}, {    223,12}, \
+    {    127,11}, {    255,10}, {    543,11}, {    287,10}, \
+    {    607,11}, {    319,10}, {    639,11}, {    351,10}, \
+    {    703,12}, {    191,11}, {    415,10}, {    831,13}, \
+    {    127,12}, {    255,11}, {    543,10}, {   1087,11}, \
+    {    607,12}, {    319,11}, {    703,12}, {    383,11}, \
+    {    831,12}, {    447,13}, {    255,12}, {    511,11}, \
+    {   1087,12}, {    575,11}, {   1215,12}, {    703,13}, \
+    {    383,12}, {    895,14}, {    255,13}, {    511,12}, \
+    {   1215,13}, {   8192,14}, {  16384,15}, {  32768,16} }
+#define SQR_FFT_TABLE3_SIZE 112
+#define SQR_FFT_THRESHOLD                 7040
+
+#define MULLO_BASECASE_THRESHOLD             3
+#define MULLO_DC_THRESHOLD                  60
+#define MULLO_MUL_N_THRESHOLD            13463
+
+#define DC_DIV_QR_THRESHOLD                 78
+#define DC_DIVAPPR_Q_THRESHOLD             252
+#define DC_BDIV_QR_THRESHOLD                84
+#define DC_BDIV_Q_THRESHOLD                171
+
+#define INV_MULMOD_BNM1_THRESHOLD           55
+#define INV_NEWTON_THRESHOLD               234
+#define INV_APPR_THRESHOLD                 236
+
+#define BINV_NEWTON_THRESHOLD              268
+#define REDC_1_TO_REDC_N_THRESHOLD          67
+
+#define MU_DIV_QR_THRESHOLD               1308
+#define MU_DIVAPPR_Q_THRESHOLD            1142
+#define MUPI_DIV_QR_THRESHOLD              134
+#define MU_BDIV_QR_THRESHOLD              1164
+#define MU_BDIV_Q_THRESHOLD               1164
+
+#define MATRIX22_STRASSEN_THRESHOLD         15
+#define HGCD_THRESHOLD                     182
+#define GCD_DC_THRESHOLD                   591
+#define GCDEXT_DC_THRESHOLD                472
+#define JACOBI_BASE_METHOD                   2
+
+#define GET_STR_DC_THRESHOLD                24
+#define GET_STR_PRECOMPUTE_THRESHOLD        40
+#define SET_STR_DC_THRESHOLD               834
+#define SET_STR_PRECOMPUTE_THRESHOLD      2042
diff --git a/third_party/gmp/mpn/x86/k6/k62mmx/copyd.asm b/third_party/gmp/mpn/x86/k6/k62mmx/copyd.asm
new file mode 100644
index 0000000..f80a5a1
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k6/k62mmx/copyd.asm
@@ -0,0 +1,118 @@
+dnl  AMD K6-2 mpn_copyd -- copy limb vector, decrementing.
+
+dnl  Copyright 2001, 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C K6-2: 1.0 cycles/limb
+
+
+C void mpn_copyd (mp_ptr dst, mp_srcptr src, mp_size_t size);
+C
+C The loop here is no faster than a rep movsl at 1.0 c/l, but it avoids a 30
+C cycle startup time, which amounts for instance to a 2x speedup at 15
+C limbs.
+C
+C If dst is 4mod8 the loop would be 1.17 c/l, but that's avoided by
+C processing one limb separately to make it aligned.  This and a final odd
+C limb are handled in a branch-free fashion, ending up re-copying if the
+C special case isn't needed.
+C
+C Alternatives:
+C
+C There used to be a big unrolled version of this, running at 0.56 c/l if
+C the destination was aligned, but that seemed rather excessive for the
+C relative importance of copyd.
+C
+C If the destination alignment is ignored and just left to run at 1.17 c/l
+C some code size and a fixed few cycles can be saved.  Considering how few
+C uses copyd finds perhaps that should be favoured.  The current code has
+C the attraction of being no slower than a basic rep movsl though.
+
+defframe(PARAM_SIZE,12)
+defframe(PARAM_SRC, 8)
+defframe(PARAM_DST, 4)
+
+dnl  re-using parameter space
+define(SAVE_EBX,`PARAM_SIZE')
+
+	TEXT
+	ALIGN(16)
+
+PROLOGUE(mpn_copyd)
+deflit(`FRAME',0)
+
+	movl	PARAM_SIZE, %ecx
+	movl	%ebx, SAVE_EBX
+
+	movl	PARAM_SRC, %eax
+	movl	PARAM_DST, %edx
+
+	subl	$1, %ecx		C better code alignment than decl
+	jb	L(zero)
+
+	jz	L(one_more)
+	leal	4(%edx,%ecx,4), %ebx
+
+Zdisp(	movd,	0,(%eax,%ecx,4), %mm0)	C high limb
+Zdisp(	movd,	%mm0, 0,(%edx,%ecx,4))	C Zdisp for good code alignment
+
+	cmpl	$1, %ecx
+	je	L(one_more)
+
+	shrl	$2, %ebx
+	andl	$1, %ebx		C 1 if dst[size-2] unaligned
+
+	subl	%ebx, %ecx
+	nop				C code alignment
+
+L(top):
+	C eax	src
+	C ebx
+	C ecx	counter
+	C edx	dst
+
+	movq	-4(%eax,%ecx,4), %mm0
+	subl	$2, %ecx
+
+	movq	%mm0, 4(%edx,%ecx,4)
+	ja	L(top)
+
+
+L(one_more):
+	movd	(%eax), %mm0
+	movd	%mm0, (%edx)
+
+	movl	SAVE_EBX, %ebx
+	emms_or_femms
+L(zero):
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/k6/k62mmx/lshift.asm b/third_party/gmp/mpn/x86/k6/k62mmx/lshift.asm
new file mode 100644
index 0000000..c86575f
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k6/k62mmx/lshift.asm
@@ -0,0 +1,294 @@
+dnl  AMD K6-2 mpn_lshift -- mpn left shift.
+
+dnl  Copyright 1999, 2000, 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C K6-2: 1.75 cycles/limb
+
+
+C mp_limb_t mpn_lshift (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                       unsigned shift);
+C
+
+defframe(PARAM_SHIFT,16)
+defframe(PARAM_SIZE, 12)
+defframe(PARAM_SRC,  8)
+defframe(PARAM_DST,  4)
+deflit(`FRAME',0)
+
+dnl  used after src has been fetched
+define(VAR_RETVAL,`PARAM_SRC')
+
+dnl  minimum 9, because unrolled loop can't handle less
+deflit(UNROLL_THRESHOLD, 9)
+
+	TEXT
+	ALIGN(32)
+
+PROLOGUE(mpn_lshift)
+deflit(`FRAME',0)
+
+	C The 1 limb case can be done without the push %ebx, but it's then
+	C still the same speed.  The push is left as a free helping hand for
+	C the two_or_more code.
+
+	movl	PARAM_SIZE, %eax
+	pushl	%ebx			FRAME_pushl()
+
+	movl	PARAM_SRC, %ebx
+	decl	%eax
+
+	movl	PARAM_SHIFT, %ecx
+	jnz	L(two_or_more)
+
+	movl	(%ebx), %edx		C src limb
+	movl	PARAM_DST, %ebx
+
+	shldl(	%cl, %edx, %eax)	C return value
+
+	shll	%cl, %edx
+
+	movl	%edx, (%ebx)		C dst limb
+	popl	%ebx
+
+	ret
+
+
+C -----------------------------------------------------------------------------
+	ALIGN(16)	C avoid offset 0x1f
+L(two_or_more):
+	C eax	size-1
+	C ebx	src
+	C ecx	shift
+	C edx
+
+	movl	(%ebx,%eax,4), %edx	C src high limb
+	negl	%ecx
+
+	movd	PARAM_SHIFT, %mm6
+	addl	$32, %ecx		C 32-shift
+
+	shrl	%cl, %edx
+	cmpl	$UNROLL_THRESHOLD-1, %eax
+
+	movl	%edx, VAR_RETVAL
+	jae	L(unroll)
+
+
+	movd	%ecx, %mm7
+	movl	%eax, %ecx
+
+	movl	PARAM_DST, %eax
+
+L(simple):
+	C eax	dst
+	C ebx	src
+	C ecx	counter, size-1 to 1
+	C edx	retval
+	C
+	C mm0	scratch
+	C mm6	shift
+	C mm7	32-shift
+
+	movq	-4(%ebx,%ecx,4), %mm0
+
+	psrlq	%mm7, %mm0
+
+Zdisp(	movd,	%mm0, 0,(%eax,%ecx,4))
+	loop	L(simple)
+
+
+	movd	(%ebx), %mm0
+	popl	%ebx
+
+	psllq	%mm6, %mm0
+
+	movd	%mm0, (%eax)
+	movl	%edx, %eax
+
+	femms
+	ret
+
+
+C -----------------------------------------------------------------------------
+	ALIGN(16)
+L(unroll):
+	C eax	size-1
+	C ebx	src
+	C ecx	32-shift
+	C edx	retval (but instead VAR_RETVAL is used)
+	C
+	C mm6	shift
+
+	addl	$32, %ecx
+	movl	PARAM_DST, %edx
+
+	movd	%ecx, %mm7
+	subl	$7, %eax			C size-8
+
+	leal	(%edx,%eax,4), %ecx		C alignment of dst
+
+	movq	32-8(%ebx,%eax,4), %mm2		C src high qword
+	testb	$4, %cl
+
+	jz	L(dst_aligned)
+	psllq	%mm6, %mm2
+
+	psrlq	$32, %mm2
+	decl	%eax
+
+	movd	%mm2, 32(%edx,%eax,4)		C dst high limb
+	movq	32-8(%ebx,%eax,4), %mm2		C new src high qword
+L(dst_aligned):
+
+	movq	32-16(%ebx,%eax,4), %mm0	C src second highest qword
+
+
+	C This loop is the important bit, the rest is just support for it.
+	C Four src limbs are held at the start, and four more will be read.
+	C Four dst limbs will be written.  This schedule seems necessary for
+	C full speed.
+	C
+	C The use of size-8 lets the loop stop when %eax goes negative and
+	C leaves -4 to -1 which can be tested with test $1 and $2.
+
+L(top):
+	C eax	counter, size-8 step by -4 until <0
+	C ebx	src
+	C ecx
+	C edx	dst
+	C
+	C mm0	src next qword
+	C mm1	scratch
+	C mm2	src prev qword
+	C mm6	shift
+	C mm7	64-shift
+
+	psllq	%mm6, %mm2
+	subl	$4, %eax
+
+	movq	%mm0, %mm1
+	psrlq	%mm7, %mm0
+
+	por	%mm0, %mm2
+	movq	24(%ebx,%eax,4), %mm0
+
+	psllq	%mm6, %mm1
+	movq	%mm2, 40(%edx,%eax,4)
+
+	movq	%mm0, %mm2
+	psrlq	%mm7, %mm0
+
+	por	%mm0, %mm1
+	movq	16(%ebx,%eax,4), %mm0
+
+	movq	%mm1, 32(%edx,%eax,4)
+	jnc	L(top)
+
+
+	C Now have four limbs in mm2 (prev) and mm0 (next), plus eax mod 4.
+	C
+	C 8(%ebx) is the next source, and 24(%edx) is the next destination.
+	C %eax is between -4 and -1, representing respectively 0 to 3 extra
+	C limbs that must be read.
+
+
+	testl	$2, %eax	C testl to avoid bad cache line crossing
+	jz	L(finish_nottwo)
+
+	C Two more limbs: lshift mm2, OR it with rshifted mm0, mm0 becomes
+	C new mm2 and a new mm0 is loaded.
+
+	psllq	%mm6, %mm2
+	movq	%mm0, %mm1
+
+	psrlq	%mm7, %mm0
+	subl	$2, %eax
+
+	por	%mm0, %mm2
+	movq	16(%ebx,%eax,4), %mm0
+
+	movq	%mm2, 32(%edx,%eax,4)
+	movq	%mm1, %mm2
+L(finish_nottwo):
+
+
+	C lshift mm2, OR with rshifted mm0, mm1 becomes lshifted mm0
+
+	testb	$1, %al
+	psllq	%mm6, %mm2
+
+	movq	%mm0, %mm1
+	psrlq	%mm7, %mm0
+
+	por	%mm0, %mm2
+	psllq	%mm6, %mm1
+
+	movq	%mm2, 24(%edx,%eax,4)
+	jz	L(finish_even)
+
+
+	C Size is odd, so mm1 and one extra limb to process.
+
+	movd	(%ebx), %mm0		C src[0]
+	popl	%ebx
+deflit(`FRAME',0)
+
+	movq	%mm0, %mm2
+	psllq	$32, %mm0
+
+	psrlq	%mm7, %mm0
+
+	psllq	%mm6, %mm2
+	por	%mm0, %mm1
+
+	movq	%mm1, 4(%edx)		C dst[1,2]
+	movd	%mm2, (%edx)		C dst[0]
+
+	movl	VAR_RETVAL, %eax
+
+	femms
+	ret
+
+
+	nop	C avoid bad cache line crossing
+L(finish_even):
+deflit(`FRAME',4)
+	C Size is even, so only mm1 left to process.
+
+	movq	%mm1, (%edx)		C dst[0,1]
+	movl	VAR_RETVAL, %eax
+
+	popl	%ebx
+	femms
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/k6/k62mmx/rshift.asm b/third_party/gmp/mpn/x86/k6/k62mmx/rshift.asm
new file mode 100644
index 0000000..f604a7b
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k6/k62mmx/rshift.asm
@@ -0,0 +1,293 @@
+dnl  AMD K6-2 mpn_rshift -- mpn right shift.
+
+dnl  Copyright 1999, 2000, 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C K6-2: 1.75 cycles/limb
+
+
+C mp_limb_t mpn_rshift (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                       unsigned shift);
+C
+
+defframe(PARAM_SHIFT,16)
+defframe(PARAM_SIZE, 12)
+defframe(PARAM_SRC,  8)
+defframe(PARAM_DST,  4)
+deflit(`FRAME',0)
+
+dnl  Minimum 9, because the unrolled loop can't handle less.
+dnl
+deflit(UNROLL_THRESHOLD, 9)
+
+	TEXT
+	ALIGN(32)
+
+PROLOGUE(mpn_rshift)
+deflit(`FRAME',0)
+
+	C The 1 limb case can be done without the push %ebx, but it's then
+	C still the same speed.  The push is left as a free helping hand for
+	C the two_or_more code.
+
+	movl	PARAM_SIZE, %eax
+	pushl	%ebx			FRAME_pushl()
+
+	movl	PARAM_SRC, %ebx
+	decl	%eax
+
+	movl	PARAM_SHIFT, %ecx
+	jnz	L(two_or_more)
+
+	movl	(%ebx), %edx		C src limb
+	movl	PARAM_DST, %ebx
+
+	shrdl(	%cl, %edx, %eax)	C return value
+
+	shrl	%cl, %edx
+
+	movl	%edx, (%ebx)		C dst limb
+	popl	%ebx
+
+	ret
+
+
+C -----------------------------------------------------------------------------
+	ALIGN(16)	C avoid offset 0x1f
+L(two_or_more):
+	C eax	size-1
+	C ebx	src
+	C ecx	shift
+	C edx
+
+	movl	(%ebx), %edx	C src low limb
+	negl	%ecx
+
+	addl	$32, %ecx
+	movd	PARAM_SHIFT, %mm6
+
+	shll	%cl, %edx
+	cmpl	$UNROLL_THRESHOLD-1, %eax
+
+	jae	L(unroll)
+
+
+	C eax	size-1
+	C ebx	src
+	C ecx	32-shift
+	C edx	retval
+	C
+	C mm6	shift
+
+	movl	PARAM_DST, %ecx
+	leal	(%ebx,%eax,4), %ebx
+
+	leal	-4(%ecx,%eax,4), %ecx
+	negl	%eax
+
+	C This loop runs at about 3 cycles/limb, which is the amount of
+	C decoding, and this is despite every second access being unaligned.
+
+L(simple):
+	C eax	counter, -(size-1) to -1
+	C ebx	&src[size-1]
+	C ecx	&dst[size-1]
+	C edx	retval
+	C
+	C mm0	scratch
+	C mm6	shift
+
+Zdisp(	movq,	0,(%ebx,%eax,4), %mm0)
+	incl	%eax
+
+	psrlq	%mm6, %mm0
+
+Zdisp(	movd,	%mm0, 0,(%ecx,%eax,4))
+	jnz	L(simple)
+
+
+	movq	%mm0, (%ecx)
+	movl	%edx, %eax
+
+	popl	%ebx
+
+	femms
+	ret
+
+
+C -----------------------------------------------------------------------------
+	ALIGN(16)
+L(unroll):
+	C eax	size-1
+	C ebx	src
+	C ecx	32-shift
+	C edx	retval
+	C
+	C mm6	shift
+
+	addl	$32, %ecx
+	subl	$7, %eax		C size-8
+
+	movd	%ecx, %mm7
+	movl	PARAM_DST, %ecx
+
+	movq	(%ebx), %mm2		C src low qword
+	leal	(%ebx,%eax,4), %ebx	C src end - 32
+
+	testb	$4, %cl
+	leal	(%ecx,%eax,4), %ecx	C dst end - 32
+
+	notl	%eax			C -(size-7)
+	jz	L(dst_aligned)
+
+	psrlq	%mm6, %mm2
+	incl	%eax
+
+Zdisp(	movd,	%mm2, 0,(%ecx,%eax,4))	C dst low limb
+	movq	4(%ebx,%eax,4), %mm2	C new src low qword
+L(dst_aligned):
+
+	movq	12(%ebx,%eax,4), %mm0	C src second lowest qword
+	nop	C avoid bad cache line crossing
+
+
+	C This loop is the important bit, the rest is just support for it.
+	C Four src limbs are held at the start, and four more will be read.
+	C Four dst limbs will be written.  This schedule seems necessary for
+	C full speed.
+	C
+	C The use of -(size-7) lets the loop stop when %eax becomes >= 0 and
+	C and leaves 0 to 3 which can be tested with test $1 and $2.
+
+L(top):
+	C eax	counter, -(size-7) step by +4 until >=0
+	C ebx	src end - 32
+	C ecx	dst end - 32
+	C edx	retval
+	C
+	C mm0	src next qword
+	C mm1	scratch
+	C mm2	src prev qword
+	C mm6	shift
+	C mm7	64-shift
+
+	psrlq	%mm6, %mm2
+	addl	$4, %eax
+
+	movq	%mm0, %mm1
+	psllq	%mm7, %mm0
+
+	por	%mm0, %mm2
+	movq	4(%ebx,%eax,4), %mm0
+
+	psrlq	%mm6, %mm1
+	movq	%mm2, -12(%ecx,%eax,4)
+
+	movq	%mm0, %mm2
+	psllq	%mm7, %mm0
+
+	por	%mm0, %mm1
+	movq	12(%ebx,%eax,4), %mm0
+
+	movq	%mm1, -4(%ecx,%eax,4)
+	ja	L(top)		C jump if no carry and not zero
+
+
+
+	C Now have the four limbs in mm2 (low) and mm0 (high), and %eax is 0
+	C to 3 representing respectively 3 to 0 further limbs.
+
+	testl	$2, %eax	C testl to avoid bad cache line crossings
+	jnz	L(finish_nottwo)
+
+	C Two or three extra limbs: rshift mm2, OR it with lshifted mm0, mm0
+	C becomes new mm2 and a new mm0 is loaded.
+
+	psrlq	%mm6, %mm2
+	movq	%mm0, %mm1
+
+	psllq	%mm7, %mm0
+	addl	$2, %eax
+
+	por	%mm0, %mm2
+	movq	12(%ebx,%eax,4), %mm0
+
+	movq	%mm2, -4(%ecx,%eax,4)
+	movq	%mm1, %mm2
+L(finish_nottwo):
+
+
+	testb	$1, %al
+	psrlq	%mm6, %mm2
+
+	movq	%mm0, %mm1
+	psllq	%mm7, %mm0
+
+	por	%mm0, %mm2
+	psrlq	%mm6, %mm1
+
+	movq	%mm2, 4(%ecx,%eax,4)
+	jnz	L(finish_even)
+
+
+	C one further extra limb to process
+
+	movd	32-4(%ebx), %mm0	C src[size-1], most significant limb
+	popl	%ebx
+
+	movq	%mm0, %mm2
+	psllq	%mm7, %mm0
+
+	por	%mm0, %mm1
+	psrlq	%mm6, %mm2
+
+	movq	%mm1, 32-12(%ecx)	C dst[size-3,size-2]
+	movd	%mm2, 32-4(%ecx)	C dst[size-1]
+
+	movl	%edx, %eax		C retval
+
+	femms
+	ret
+
+
+	nop	C avoid bad cache line crossing
+L(finish_even):
+	C no further extra limbs
+
+	movq	%mm1, 32-8(%ecx)	C dst[size-2,size-1]
+	movl	%edx, %eax		C retval
+
+	popl	%ebx
+
+	femms
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/k6/mmx/com.asm b/third_party/gmp/mpn/x86/k6/mmx/com.asm
new file mode 100644
index 0000000..b747454
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k6/mmx/com.asm
@@ -0,0 +1,103 @@
+dnl  AMD K6-2 mpn_com -- mpn bitwise one's complement.
+
+dnl  Copyright 1999-2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+NAILS_SUPPORT(0-31)
+
+
+C    alignment dst/src, A=0mod8 N=4mod8
+C       A/A   A/N   N/A   N/N
+C K6-2  1.0   1.18  1.18  1.18  cycles/limb
+C K6    1.5   1.85  1.75  1.85
+
+
+C void mpn_com (mp_ptr dst, mp_srcptr src, mp_size_t size);
+C
+C Take the bitwise ones-complement of src,size and write it to dst,size.
+
+defframe(PARAM_SIZE,12)
+defframe(PARAM_SRC, 8)
+defframe(PARAM_DST, 4)
+
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_com)
+deflit(`FRAME',0)
+
+	movl	PARAM_SIZE, %ecx
+	movl	PARAM_SRC, %eax
+	movl	PARAM_DST, %edx
+	shrl	%ecx
+	jnz	L(two_or_more)
+
+	movl	(%eax), %eax
+	notl_or_xorl_GMP_NUMB_MASK(	%eax)
+	movl	%eax, (%edx)
+	ret
+
+
+L(two_or_more):
+	pushl	%ebx	FRAME_pushl()
+	pcmpeqd	%mm7, %mm7		C all ones
+
+	movl	%ecx, %ebx
+ifelse(GMP_NAIL_BITS,0,,
+`	psrld	$GMP_NAIL_BITS, %mm7')	C clear nails
+
+
+
+	ALIGN(8)
+L(top):
+	C eax	src
+	C ebx	floor(size/2)
+	C ecx	counter
+	C edx	dst
+	C
+	C mm0	scratch
+	C mm7	mask
+
+	movq	-8(%eax,%ecx,8), %mm0
+	pxor	%mm7, %mm0
+	movq	%mm0, -8(%edx,%ecx,8)
+	loop	L(top)
+
+
+	jnc	L(no_extra)
+	movl	(%eax,%ebx,8), %eax
+	notl_or_xorl_GMP_NUMB_MASK(	%eax)
+	movl	%eax, (%edx,%ebx,8)
+L(no_extra):
+
+	popl	%ebx
+	emms_or_femms
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/k6/mmx/dive_1.asm b/third_party/gmp/mpn/x86/k6/mmx/dive_1.asm
new file mode 100644
index 0000000..1bbad3a
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k6/mmx/dive_1.asm
@@ -0,0 +1,282 @@
+dnl  AMD K6 mpn_divexact_1 -- mpn by limb exact division.
+
+dnl  Copyright 2000-2002, 2007 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C         divisor
+C       odd   even
+C K6:   10.0  12.0  cycles/limb
+C K6-2: 10.0  11.5
+
+
+C void mpn_divexact_1 (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                      mp_limb_t divisor);
+C
+C A simple divl is used for size==1.  This is about 10 cycles faster for an
+C odd divisor or 20 cycles for an even divisor.
+C
+C The loops are quite sensitive to code alignment, speeds should be
+C rechecked (odd and even divisor, pic and non-pic) if contemplating
+C changing anything.
+
+defframe(PARAM_DIVISOR,16)
+defframe(PARAM_SIZE,   12)
+defframe(PARAM_SRC,    8)
+defframe(PARAM_DST,    4)
+
+dnl  re-use parameter space
+define(VAR_INVERSE,`PARAM_DST')
+
+	TEXT
+
+	ALIGN(32)
+PROLOGUE(mpn_divexact_1)
+deflit(`FRAME',0)
+
+	movl	PARAM_SIZE, %ecx
+
+	movl	PARAM_SRC, %eax
+	xorl	%edx, %edx
+
+	cmpl	$1, %ecx
+	jnz	L(two_or_more)
+
+	movl	(%eax), %eax
+
+	divl	PARAM_DIVISOR
+
+	movl	PARAM_DST, %ecx
+	movl	%eax, (%ecx)
+
+	ret
+
+
+L(two_or_more):
+	movl	PARAM_DIVISOR, %eax
+	pushl	%ebx		FRAME_pushl()
+
+	movl	PARAM_SRC, %ebx
+	pushl	%ebp		FRAME_pushl()
+
+L(strip_twos):
+	shrl	%eax
+	incl	%edx			C will get shift+1
+
+	jnc	L(strip_twos)
+	pushl	%esi		FRAME_pushl()
+
+	leal	1(%eax,%eax), %esi	C d without twos
+	andl	$127, %eax		C d/2, 7 bits
+
+ifdef(`PIC',`
+	LEA(	binvert_limb_table, %ebp)
+Zdisp(	movzbl,	0,(%eax,%ebp), %eax)
+',`
+	movzbl	binvert_limb_table(%eax), %eax	C inv 8 bits
+')
+	pushl	%edi		FRAME_pushl()
+
+	leal	(%eax,%eax), %ebp	C 2*inv
+
+	imull	%eax, %eax		C inv*inv
+
+	movl	PARAM_DST, %edi
+
+	imull	%esi, %eax		C inv*inv*d
+
+	subl	%eax, %ebp		C inv = 2*inv - inv*inv*d
+	leal	(%ebp,%ebp), %eax	C 2*inv
+
+	imull	%ebp, %ebp		C inv*inv
+
+	movl	%esi, PARAM_DIVISOR	C d without twos
+	leal	(%ebx,%ecx,4), %ebx	C src end
+
+	imull	%esi, %ebp		C inv*inv*d
+
+	leal	(%edi,%ecx,4), %edi	C dst end
+	negl	%ecx			C -size
+
+	subl	%ebp, %eax		C inv = 2*inv - inv*inv*d
+	subl	$1, %edx		C shift amount, and clear carry
+
+	ASSERT(e,`	C expect d*inv == 1 mod 2^GMP_LIMB_BITS
+	pushl	%eax	FRAME_pushl()
+	imull	PARAM_DIVISOR, %eax
+	cmpl	$1, %eax
+	popl	%eax	FRAME_popl()')
+
+	movl	%eax, VAR_INVERSE
+	jnz	L(even)
+
+	movl	(%ebx,%ecx,4), %esi	C src low limb
+	jmp	L(odd_entry)
+
+
+	ALIGN(16)
+	nop	C code alignment
+L(odd_top):
+	C eax	scratch
+	C ebx	src end
+	C ecx	counter, limbs, negative
+	C edx	inverse
+	C esi	next limb, adjusted for carry
+	C edi	dst end
+	C ebp	carry bit, 0 or -1
+
+	imull	%edx, %esi
+
+	movl	PARAM_DIVISOR, %eax
+	movl	%esi, -4(%edi,%ecx,4)
+
+	mull	%esi			C carry limb in edx
+
+	subl	%ebp, %edx		C apply carry bit
+	movl	(%ebx,%ecx,4), %esi
+
+L(odd_entry):
+	subl	%edx, %esi		C apply carry limb
+	movl	VAR_INVERSE, %edx
+
+	sbbl	%ebp, %ebp		C 0 or -1
+
+	incl	%ecx
+	jnz	L(odd_top)
+
+
+	imull	%edx, %esi
+
+	movl	%esi, -4(%edi,%ecx,4)
+
+	popl	%edi
+	popl	%esi
+
+	popl	%ebp
+	popl	%ebx
+
+	ret
+
+
+L(even):
+	C eax
+	C ebx	src end
+	C ecx	-size
+	C edx	twos
+	C esi
+	C edi	dst end
+	C ebp
+
+	xorl	%ebp, %ebp
+Zdisp(	movq,	0,(%ebx,%ecx,4), %mm0)	C src[0,1]
+
+	movd	%edx, %mm7
+	movl	VAR_INVERSE, %edx
+
+	addl	$2, %ecx
+	psrlq	%mm7, %mm0
+
+	movd	%mm0, %esi
+	jz	L(even_two)		C if only two limbs
+
+
+C Out-of-order execution is good enough to hide the load/rshift/movd
+C latency.  Having imul at the top of the loop gives 11.5 c/l instead of 12,
+C on K6-2.  In fact there's only 11 of decode, but nothing running at 11 has
+C been found.  Maybe the fact every second movq is unaligned costs the extra
+C 0.5.
+
+L(even_top):
+	C eax	scratch
+	C ebx	src end
+	C ecx	counter, limbs, negative
+	C edx	inverse
+	C esi	next limb, adjusted for carry
+	C edi	dst end
+	C ebp	carry bit, 0 or -1
+	C
+	C mm0	scratch, source limbs
+	C mm7	twos
+
+	imull	%edx, %esi
+
+	movl	%esi, -8(%edi,%ecx,4)
+	movl	PARAM_DIVISOR, %eax
+
+	mull	%esi			C carry limb in edx
+
+	movq	-4(%ebx,%ecx,4), %mm0
+	psrlq	%mm7, %mm0
+
+	movd	%mm0, %esi
+	subl	%ebp, %edx		C apply carry bit
+
+	subl	%edx, %esi		C apply carry limb
+	movl	VAR_INVERSE, %edx
+
+	sbbl	%ebp, %ebp		C 0 or -1
+
+	incl	%ecx
+	jnz	L(even_top)
+
+
+L(even_two):
+	movd	-4(%ebx), %mm0		C src high limb
+	psrlq	%mm7, %mm0
+
+	imull	%edx, %esi
+
+	movl	%esi, -8(%edi)
+	movl	PARAM_DIVISOR, %eax
+
+	mull	%esi			C carry limb in edx
+
+	movd	%mm0, %esi
+	subl	%ebp, %edx		C apply carry bit
+
+	movl	VAR_INVERSE, %eax
+	subl	%edx, %esi		C apply carry limb
+
+	imull	%eax, %esi
+
+	movl	%esi, -4(%edi)
+
+	popl	%edi
+	popl	%esi
+
+	popl	%ebp
+	popl	%ebx
+
+	emms_or_femms
+
+	ret
+
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86/k6/mmx/logops_n.asm b/third_party/gmp/mpn/x86/k6/mmx/logops_n.asm
new file mode 100644
index 0000000..e17930b
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k6/mmx/logops_n.asm
@@ -0,0 +1,226 @@
+dnl  AMD K6-2 mpn_and_n, mpn_andn_n, mpn_nand_n, mpn_ior_n, mpn_iorn_n,
+dnl  mpn_nior_n, mpn_xor_n, mpn_xnor_n -- mpn bitwise logical operations.
+
+dnl  Copyright 1999-2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+NAILS_SUPPORT(0-31)
+
+
+C         alignment dst/src1/src2, A=0mod8, N=4mod8
+C      A/A/A A/A/N A/N/A A/N/N N/A/A N/A/N N/N/A N/N/N
+C
+C K6-2  1.2   1.5   1.5   1.2   1.2   1.5   1.5   1.2   and,andn,ior,xor
+C K6-2  1.5   1.75  2.0   1.75  1.75  2.0   1.75  1.5   iorn,xnor
+C K6-2  1.75  2.0   2.0   2.0   2.0   2.0   2.0   1.75  nand,nior
+C
+C K6    1.5   1.68  1.75  1.2   1.75  1.75  1.68  1.5   and,andn,ior,xor
+C K6    2.0   2.0   2.25  2.25  2.25  2.25  2.0   2.0   iorn,xnor
+C K6    2.0   2.25  2.25  2.25  2.25  2.25  2.25  2.0   nand,nior
+
+
+dnl  M4_p and M4_i are the MMX and integer instructions
+dnl  M4_*_neg_dst means whether to negate the final result before writing
+dnl  M4_*_neg_src2 means whether to negate the src2 values before using them
+
+define(M4_choose_op,
+m4_assert_numargs(7)
+`ifdef(`OPERATION_$1',`
+define(`M4_function',  `mpn_$1')
+define(`M4_operation', `$1')
+define(`M4_p',         `$2')
+define(`M4_p_neg_dst', `$3')
+define(`M4_p_neg_src2',`$4')
+define(`M4_i',         `$5')
+define(`M4_i_neg_dst', `$6')
+define(`M4_i_neg_src2',`$7')
+')')
+
+dnl  xnor is done in "iorn" style because it's a touch faster than "nior"
+dnl  style (the two are equivalent for xor).
+dnl
+dnl  pandn can't be used with nails.
+
+M4_choose_op( and_n,  pand,0,0,  andl,0,0)
+ifelse(GMP_NAIL_BITS,0,
+`M4_choose_op(andn_n, pandn,0,0, andl,0,1)',
+`M4_choose_op(andn_n, pand,0,1,  andl,0,1)')
+M4_choose_op( nand_n, pand,1,0,  andl,1,0)
+M4_choose_op( ior_n,  por,0,0,   orl,0,0)
+M4_choose_op( iorn_n, por,0,1,   orl,0,1)
+M4_choose_op( nior_n, por,1,0,   orl,1,0)
+M4_choose_op( xor_n,  pxor,0,0,  xorl,0,0)
+M4_choose_op( xnor_n, pxor,0,1,  xorl,0,1)
+
+ifdef(`M4_function',,
+`m4_error(`Unrecognised or undefined OPERATION symbol
+')')
+
+MULFUNC_PROLOGUE(mpn_and_n mpn_andn_n mpn_nand_n mpn_ior_n mpn_iorn_n mpn_nior_n mpn_xor_n mpn_xnor_n)
+
+
+C void M4_function (mp_ptr dst, mp_srcptr src1, mp_srcptr src2,
+C                   mp_size_t size);
+C
+C Do src1,size M4_operation src2,size, storing the result in dst,size.
+C
+C Unaligned movq loads and stores are a bit slower than aligned ones.  The
+C test at the start of the routine checks the alignment of src1 and if
+C necessary processes one limb separately at the low end to make it aligned.
+C
+C The raw speeds without this alignment switch are as follows.
+C
+C           alignment dst/src1/src2, A=0mod8, N=4mod8
+C     A/A/A  A/A/N  A/N/A  A/N/N  N/A/A  N/A/N  N/N/A  N/N/N
+C
+C K6                 1.5    2.0                 1.5    2.0    and,andn,ior,xor
+C K6                 1.75   2.2                 2.0    2.28   iorn,xnor
+C K6                 2.0    2.25                2.35   2.28   nand,nior
+C
+C
+C Future:
+C
+C K6 can do one 64-bit load per cycle so each of these routines should be
+C able to approach 1.0 c/l, if aligned.  The basic and/andn/ior/xor might be
+C able to get 1.0 with just a 4 limb loop, being 3 instructions per 2 limbs.
+C The others are 4 instructions per 2 limbs, and so can only approach 1.0
+C because there's nowhere to hide some loop control.
+
+defframe(PARAM_SIZE,16)
+defframe(PARAM_SRC2,12)
+defframe(PARAM_SRC1,8)
+defframe(PARAM_DST, 4)
+deflit(`FRAME',0)
+
+	TEXT
+	ALIGN(32)
+PROLOGUE(M4_function)
+			movl	PARAM_SIZE, %ecx
+			pushl	%ebx		FRAME_pushl()
+
+			movl	PARAM_SRC1, %eax
+
+			movl	PARAM_SRC2, %ebx
+			cmpl	$1, %ecx
+
+			movl	PARAM_DST, %edx
+			ja	L(two_or_more)
+
+
+			movl	(%ebx), %ecx
+			popl	%ebx
+ifelse(M4_i_neg_src2,1,`notl_or_xorl_GMP_NUMB_MASK(	%ecx)')
+			M4_i	(%eax), %ecx
+ifelse(M4_i_neg_dst,1,`	notl_or_xorl_GMP_NUMB_MASK(	%ecx)')
+			movl	%ecx, (%edx)
+
+			ret
+
+
+L(two_or_more):
+			C eax	src1
+			C ebx	src2
+			C ecx	size
+			C edx	dst
+			C esi
+			C edi
+			C ebp
+
+			pushl	%esi		FRAME_pushl()
+			testl	$4, %eax
+			jz	L(alignment_ok)
+
+			movl	(%ebx), %esi
+			addl	$4, %ebx
+ifelse(M4_i_neg_src2,1,`notl_or_xorl_GMP_NUMB_MASK(	%esi)')
+			M4_i	(%eax), %esi
+			addl	$4, %eax
+ifelse(M4_i_neg_dst,1,`	notl_or_xorl_GMP_NUMB_MASK(	%esi)')
+			movl	%esi, (%edx)
+			addl	$4, %edx
+			decl	%ecx
+
+L(alignment_ok):
+			movl	%ecx, %esi
+			shrl	%ecx
+			jnz	L(still_two_or_more)
+
+			movl	(%ebx), %ecx
+			popl	%esi
+ifelse(M4_i_neg_src2,1,`notl_or_xorl_GMP_NUMB_MASK(	%ecx)')
+			M4_i	(%eax), %ecx
+ifelse(M4_i_neg_dst,1,`	notl_or_xorl_GMP_NUMB_MASK(	%ecx)')
+			popl	%ebx
+			movl	%ecx, (%edx)
+			ret
+
+
+L(still_two_or_more):
+ifelse(eval(M4_p_neg_src2 || M4_p_neg_dst),1,`
+			pcmpeqd	%mm7, %mm7		C all ones
+ifelse(GMP_NAIL_BITS,0,,`psrld	$GMP_NAIL_BITS, %mm7')	C clear nails
+')
+
+			ALIGN(16)
+L(top):
+			C eax	src1
+			C ebx	src2
+			C ecx	counter
+			C edx	dst
+			C esi
+			C edi
+			C ebp
+			C
+			C carry bit is low of size
+
+			movq	-8(%ebx,%ecx,8), %mm0
+ifelse(M4_p_neg_src2,1,`pxor	%mm7, %mm0')
+			M4_p	-8(%eax,%ecx,8), %mm0
+ifelse(M4_p_neg_dst,1,`	pxor	%mm7, %mm0')
+			movq	%mm0, -8(%edx,%ecx,8)
+
+			loop	L(top)
+
+
+			jnc	L(no_extra)
+
+			movl	-4(%ebx,%esi,4), %ebx
+ifelse(M4_i_neg_src2,1,`notl_or_xorl_GMP_NUMB_MASK(	%ebx)')
+			M4_i	-4(%eax,%esi,4), %ebx
+ifelse(M4_i_neg_dst,1,`	notl_or_xorl_GMP_NUMB_MASK(	%ebx)')
+			movl	%ebx, -4(%edx,%esi,4)
+L(no_extra):
+
+			popl	%esi
+			popl	%ebx
+			emms_or_femms
+			ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/k6/mmx/lshift.asm b/third_party/gmp/mpn/x86/k6/mmx/lshift.asm
new file mode 100644
index 0000000..45be582
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k6/mmx/lshift.asm
@@ -0,0 +1,130 @@
+dnl  AMD K6 mpn_lshift -- mpn left shift.
+
+dnl  Copyright 1999, 2000, 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C K6: 3.0 cycles/limb
+
+
+C mp_limb_t mpn_lshift (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                       unsigned shift);
+C
+C The loop runs at 3 cycles/limb, limited by decoding and by having 3 mmx
+C instructions.  This is despite every second fetch being unaligned.
+
+
+defframe(PARAM_SHIFT,16)
+defframe(PARAM_SIZE, 12)
+defframe(PARAM_SRC,  8)
+defframe(PARAM_DST,  4)
+
+	TEXT
+	ALIGN(32)
+
+PROLOGUE(mpn_lshift)
+deflit(`FRAME',0)
+
+	C The 1 limb case can be done without the push %ebx, but it's then
+	C still the same speed.  The push is left as a free helping hand for
+	C the two_or_more code.
+
+	movl	PARAM_SIZE, %eax
+	pushl	%ebx			FRAME_pushl()
+
+	movl	PARAM_SRC, %ebx
+	decl	%eax
+
+	movl	PARAM_SHIFT, %ecx
+	jnz	L(two_or_more)
+
+	movl	(%ebx), %edx		C src limb
+	movl	PARAM_DST, %ebx
+
+	shldl(	%cl, %edx, %eax)	C return value
+
+	shll	%cl, %edx
+
+	movl	%edx, (%ebx)		C dst limb
+	popl	%ebx
+
+	ret
+
+
+	ALIGN(16)	C avoid offset 0x1f
+	nop		C avoid bad cache line crossing
+L(two_or_more):
+	C eax	size-1
+	C ebx	src
+	C ecx	shift
+	C edx
+
+	movl	(%ebx,%eax,4), %edx	C src high limb
+	negl	%ecx
+
+	movd	PARAM_SHIFT, %mm6
+	addl	$32, %ecx		C 32-shift
+
+	shrl	%cl, %edx
+
+	movd	%ecx, %mm7
+	movl	PARAM_DST, %ecx
+
+L(top):
+	C eax	counter, size-1 to 1
+	C ebx	src
+	C ecx	dst
+	C edx	retval
+	C
+	C mm0	scratch
+	C mm6	shift
+	C mm7	32-shift
+
+	movq	-4(%ebx,%eax,4), %mm0
+	decl	%eax
+
+	psrlq	%mm7, %mm0
+
+	movd	%mm0, 4(%ecx,%eax,4)
+	jnz	L(top)
+
+
+	movd	(%ebx), %mm0
+	popl	%ebx
+
+	psllq	%mm6, %mm0
+	movl	%edx, %eax
+
+	movd	%mm0, (%ecx)
+
+	emms
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/k6/mmx/popham.asm b/third_party/gmp/mpn/x86/k6/mmx/popham.asm
new file mode 100644
index 0000000..2b19d0b
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k6/mmx/popham.asm
@@ -0,0 +1,236 @@
+dnl  AMD K6-2 mpn_popcount, mpn_hamdist -- mpn bit population count and
+dnl  hamming distance.
+
+dnl  Copyright 2000-2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C        popcount  hamdist
+C K6-2:    9.0       11.5   cycles/limb
+C K6:      12.5      13.0
+
+
+C unsigned long mpn_popcount (mp_srcptr src, mp_size_t size);
+C unsigned long mpn_hamdist (mp_srcptr src, mp_srcptr src2, mp_size_t size);
+C
+C The code here isn't optimal, but it's already a 2x speedup over the plain
+C integer mpn/generic/popcount.c,hamdist.c.
+
+
+ifdef(`OPERATION_popcount',,
+`ifdef(`OPERATION_hamdist',,
+`m4_error(`Need OPERATION_popcount or OPERATION_hamdist
+')m4exit(1)')')
+
+define(HAM,
+m4_assert_numargs(1)
+`ifdef(`OPERATION_hamdist',`$1')')
+
+define(POP,
+m4_assert_numargs(1)
+`ifdef(`OPERATION_popcount',`$1')')
+
+HAM(`
+defframe(PARAM_SIZE,   12)
+defframe(PARAM_SRC2,   8)
+defframe(PARAM_SRC,    4)
+define(M4_function,mpn_hamdist)
+')
+POP(`
+defframe(PARAM_SIZE,   8)
+defframe(PARAM_SRC,    4)
+define(M4_function,mpn_popcount)
+')
+
+MULFUNC_PROLOGUE(mpn_popcount mpn_hamdist)
+
+
+ifdef(`PIC',,`
+	dnl  non-PIC
+
+	RODATA
+	ALIGN(8)
+
+L(rodata_AAAAAAAAAAAAAAAA):
+	.long	0xAAAAAAAA
+	.long	0xAAAAAAAA
+
+L(rodata_3333333333333333):
+	.long	0x33333333
+	.long	0x33333333
+
+L(rodata_0F0F0F0F0F0F0F0F):
+	.long	0x0F0F0F0F
+	.long	0x0F0F0F0F
+
+L(rodata_000000FF000000FF):
+	.long	0x000000FF
+	.long	0x000000FF
+')
+
+	TEXT
+	ALIGN(32)
+
+POP(`ifdef(`PIC', `
+	C avoid shrl crossing a 32-byte boundary
+	nop')')
+
+PROLOGUE(M4_function)
+deflit(`FRAME',0)
+
+	movl	PARAM_SIZE, %ecx
+
+ifdef(`PIC',`
+	movl	$0xAAAAAAAA, %eax
+	movl	$0x33333333, %edx
+
+	movd	%eax, %mm7
+	movd	%edx, %mm6
+
+	movl	$0x0F0F0F0F, %eax
+	movl	$0x000000FF, %edx
+
+	punpckldq %mm7, %mm7
+	punpckldq %mm6, %mm6
+
+	movd	%eax, %mm5
+	movd	%edx, %mm4
+
+	punpckldq %mm5, %mm5
+	punpckldq %mm4, %mm4
+',`
+
+	movq	L(rodata_AAAAAAAAAAAAAAAA), %mm7
+	movq	L(rodata_3333333333333333), %mm6
+	movq	L(rodata_0F0F0F0F0F0F0F0F), %mm5
+	movq	L(rodata_000000FF000000FF), %mm4
+')
+
+define(REG_AAAAAAAAAAAAAAAA, %mm7)
+define(REG_3333333333333333, %mm6)
+define(REG_0F0F0F0F0F0F0F0F, %mm5)
+define(REG_000000FF000000FF, %mm4)
+
+
+	movl	PARAM_SRC, %eax
+HAM(`	movl	PARAM_SRC2, %edx')
+
+	pxor	%mm2, %mm2	C total
+
+	shrl	%ecx
+	jnc	L(top)
+
+Zdisp(	movd,	0,(%eax,%ecx,8), %mm1)
+
+HAM(`
+Zdisp(	movd,	0,(%edx,%ecx,8), %mm0)
+	pxor	%mm0, %mm1
+')
+
+	incl	%ecx
+	jmp	L(loaded)
+
+
+	ALIGN(16)
+POP(`	nop	C alignment to avoid crossing 32-byte boundaries')
+
+L(top):
+	C eax	src
+	C ebx
+	C ecx	counter, qwords, decrementing
+	C edx	[hamdist] src2
+	C
+	C mm0	(scratch)
+	C mm1	(scratch)
+	C mm2	total (low dword)
+	C mm3
+	C mm4	\
+	C mm5	| special constants
+	C mm6	|
+	C mm7	/
+
+	movq	-8(%eax,%ecx,8), %mm1
+HAM(`	pxor	-8(%edx,%ecx,8), %mm1')
+
+L(loaded):
+	movq	%mm1, %mm0
+	pand	REG_AAAAAAAAAAAAAAAA, %mm1
+
+	psrlq	$1, %mm1
+HAM(`	nop			C code alignment')
+
+	psubd	%mm1, %mm0	C bit pairs
+HAM(`	nop			C code alignment')
+
+
+	movq	%mm0, %mm1
+	psrlq	$2, %mm0
+
+	pand	REG_3333333333333333, %mm0
+	pand	REG_3333333333333333, %mm1
+
+	paddd	%mm1, %mm0	C nibbles
+
+
+	movq	%mm0, %mm1
+	psrlq	$4, %mm0
+
+	pand	REG_0F0F0F0F0F0F0F0F, %mm0
+	pand	REG_0F0F0F0F0F0F0F0F, %mm1
+
+	paddd	%mm1, %mm0	C bytes
+
+	movq	%mm0, %mm1
+	psrlq	$8, %mm0
+
+
+	paddb	%mm1, %mm0	C words
+
+
+	movq	%mm0, %mm1
+	psrlq	$16, %mm0
+
+	paddd	%mm1, %mm0	C dwords
+
+	pand	REG_000000FF000000FF, %mm0
+
+	paddd	%mm0, %mm2	C low to total
+	psrlq	$32, %mm0
+
+	paddd	%mm0, %mm2	C high to total
+	loop	L(top)
+
+
+
+	movd	%mm2, %eax
+	emms_or_femms
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/k6/mmx/rshift.asm b/third_party/gmp/mpn/x86/k6/mmx/rshift.asm
new file mode 100644
index 0000000..cd0382f
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k6/mmx/rshift.asm
@@ -0,0 +1,130 @@
+dnl  AMD K6 mpn_rshift -- mpn right shift.
+
+dnl  Copyright 1999, 2000, 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C K6: 3.0 cycles/limb
+
+
+C mp_limb_t mpn_rshift (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                       unsigned shift);
+C
+C The loop runs at 3 cycles/limb, limited by decoding and by having 3 mmx
+C instructions.  This is despite every second fetch being unaligned.
+
+
+defframe(PARAM_SHIFT,16)
+defframe(PARAM_SIZE, 12)
+defframe(PARAM_SRC,  8)
+defframe(PARAM_DST,  4)
+deflit(`FRAME',0)
+
+	TEXT
+	ALIGN(32)
+
+PROLOGUE(mpn_rshift)
+deflit(`FRAME',0)
+
+	C The 1 limb case can be done without the push %ebx, but it's then
+	C still the same speed.  The push is left as a free helping hand for
+	C the two_or_more code.
+
+	movl	PARAM_SIZE, %eax
+	pushl	%ebx			FRAME_pushl()
+
+	movl	PARAM_SRC, %ebx
+	decl	%eax
+
+	movl	PARAM_SHIFT, %ecx
+	jnz	L(two_or_more)
+
+	movl	(%ebx), %edx		C src limb
+	movl	PARAM_DST, %ebx
+
+	shrdl(	%cl, %edx, %eax)	C return value
+
+	shrl	%cl, %edx
+
+	movl	%edx, (%ebx)		C dst limb
+	popl	%ebx
+
+	ret
+
+
+	ALIGN(16)	C avoid offset 0x1f
+L(two_or_more):
+	C eax	size-1
+	C ebx	src
+	C ecx	shift
+	C edx
+
+	movl	(%ebx), %edx	C src low limb
+	negl	%ecx
+
+	addl	$32, %ecx	C 32-shift
+	movd	PARAM_SHIFT, %mm6
+
+	shll	%cl, %edx	C retval
+	movl	PARAM_DST, %ecx
+
+	leal	(%ebx,%eax,4), %ebx
+
+	leal	-4(%ecx,%eax,4), %ecx
+	negl	%eax
+
+
+L(simple):
+	C eax	counter (negative)
+	C ebx	&src[size-1]
+	C ecx	&dst[size-1]
+	C edx	retval
+	C
+	C mm0	scratch
+	C mm6	shift
+
+Zdisp(	movq,	0,(%ebx,%eax,4), %mm0)
+	incl	%eax
+
+	psrlq	%mm6, %mm0
+
+Zdisp(	movd,	%mm0, 0,(%ecx,%eax,4))
+	jnz	L(simple)
+
+
+	movq	%mm0, (%ecx)
+	movl	%edx, %eax
+
+	popl	%ebx
+
+	emms
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/k6/mod_34lsub1.asm b/third_party/gmp/mpn/x86/k6/mod_34lsub1.asm
new file mode 100644
index 0000000..7e30503
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k6/mod_34lsub1.asm
@@ -0,0 +1,190 @@
+dnl  AMD K6 mpn_mod_34lsub1 -- mpn remainder modulo 2**24-1.
+
+dnl  Copyright 2000-2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C K6: 2.66 cycles/limb
+
+
+C mp_limb_t mpn_mod_34lsub1 (mp_srcptr src, mp_size_t size)
+C
+C An attempt was made to use a loop like
+C
+C L(top):
+C	adcl	(%edx), %eax
+C	adcl	4(%edx), %ebx
+C	adcl	8(%edx), %esi
+C	leal	12(%edx), %edx
+C	loop	L(top)
+C
+C with %ecx starting from floor(size/3), but it still measured 2.66 c/l.
+C The form used instead can save about 6 cycles by not dividing by 3.
+C
+C In the code used, putting the "leal"s at the top of the loop is necessary
+C for the claimed speed, anywhere else costs an extra cycle per loop.
+C Perhaps a tight loop like this needs short decode instructions at the
+C branch target, which would explain the leal/loop form above taking 8
+C cycles instead of 7 too.
+
+defframe(PARAM_SIZE, 8)
+defframe(PARAM_SRC,  4)
+
+dnl  re-use parameter space
+define(SAVE_EBX, `PARAM_SIZE')
+define(SAVE_ESI, `PARAM_SRC')
+
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_mod_34lsub1)
+deflit(`FRAME',0)
+
+	movl	PARAM_SIZE, %eax
+	movl	PARAM_SRC, %edx
+
+	subl	$2, %eax
+	ja	L(three_or_more)
+
+Zdisp(	movl,	0,(%edx), %eax)		C avoid code cache line boundary
+	jne	L(one)
+
+	movl	%eax, %ecx
+	movl	4(%edx), %edx
+
+	shrl	$24, %eax		C src[0] high
+	andl	$0x00FFFFFF, %ecx	C src[0] low
+
+	addl	%ecx, %eax
+	movl	%edx, %ecx
+
+	shll	$8, %edx
+	andl	$0x00FFFF00, %edx	C src[1] high
+
+	shrl	$16, %ecx		C src[1] low
+	addl	%ecx, %eax
+
+	addl	%edx, %eax
+
+L(one):
+	ret
+
+
+L(three_or_more):
+	C eax	size-2
+	C ebx
+	C ecx
+	C edx	src
+
+	movl	%ebx, SAVE_EBX
+	xorl	%ebx, %ebx
+
+	movl	%esi, SAVE_ESI
+	pushl	%edi	FRAME_pushl()
+
+	xorl	%esi, %esi
+	xorl	%edi, %edi		C and clear carry flag
+
+L(top):
+	C eax	counter, limbs
+	C ebx	acc 0mod3
+	C ecx
+	C edx	src, incrementing
+	C esi	acc 1mod3
+	C edi	acc 2mod3
+	C ebp
+
+	leal	-2(%eax), %eax
+	leal	12(%edx), %edx
+
+	adcl	-12(%edx), %ebx
+	adcl	-8(%edx), %esi
+	adcl	-4(%edx), %edi
+
+	decl	%eax
+	jg	L(top)
+
+
+	C ecx is -3, -2 or -1 representing 0, 1 or 2 more limbs, respectively
+
+	movb	$0, %cl
+	incl	%eax
+
+	js	L(combine)		C 0 more
+
+Zdisp(	adcl,	0,(%edx), %ebx)		C avoid code cache line crossings
+
+	movb	$8, %cl
+	decl	%eax
+
+	js	L(combine)		C 1 more
+
+	adcl	4(%edx), %esi
+
+	movb	$16, %cl
+
+
+L(combine):
+	sbbl	%edx, %edx
+
+	shll	%cl, %edx		C carry
+	movl	%ebx, %eax		C 0mod3
+
+	shrl	$24, %eax		C 0mod3 high
+	andl	$0x00FFFFFF, %ebx	C 0mod3 low
+
+	subl	%edx, %eax		C apply carry
+	movl	%esi, %ecx		C 1mod3
+
+	shrl	$16, %esi		C 1mod3 high
+	addl	%ebx, %eax		C apply 0mod3 low
+
+	andl	$0x0000FFFF, %ecx
+	addl	%esi, %eax		C apply 1mod3 high
+
+	shll	$8, %ecx		C 1mod3 low
+	movl	%edi, %edx		C 2mod3
+
+	shrl	$8, %edx		C 2mod3 high
+	addl	%ecx, %eax		C apply 1mod3 low
+
+	addl	%edx, %eax		C apply 2mod3 high
+	andl	$0x000000FF, %edi
+
+	shll	$16, %edi		C 2mod3 low
+	movl	SAVE_EBX, %ebx
+
+	addl	%edi, %eax		C apply 2mod3 low
+	movl	SAVE_ESI, %esi
+
+	popl	%edi
+
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/k6/mode1o.asm b/third_party/gmp/mpn/x86/k6/mode1o.asm
new file mode 100644
index 0000000..4a338bd
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k6/mode1o.asm
@@ -0,0 +1,176 @@
+dnl  AMD K6 mpn_modexact_1_odd -- exact division style remainder.
+
+dnl  Copyright 2000-2003, 2007 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C K6: 10.0 cycles/limb
+
+
+C mp_limb_t mpn_modexact_1_odd (mp_srcptr src, mp_size_t size,
+C                               mp_limb_t divisor);
+C mp_limb_t mpn_modexact_1c_odd (mp_srcptr src, mp_size_t size,
+C                                mp_limb_t divisor, mp_limb_t carry);
+C
+C A special case for high<divisor at the end measured only about 4 cycles
+C faster, and so isn't used.
+C
+C A special case for size==1 using a divl rather than the inverse measured
+C only about 5 cycles faster, and so isn't used.  When size==1 and
+C high<divisor it can skip a division and be a full 24 cycles faster, but
+C this isn't an important case.
+
+defframe(PARAM_CARRY,  16)
+defframe(PARAM_DIVISOR,12)
+defframe(PARAM_SIZE,   8)
+defframe(PARAM_SRC,    4)
+
+	TEXT
+
+	ALIGN(32)
+PROLOGUE(mpn_modexact_1c_odd)
+deflit(`FRAME',0)
+
+	movl	PARAM_DIVISOR, %ecx
+	pushl	%esi		FRAME_pushl()
+
+	movl	PARAM_CARRY, %edx
+	jmp	L(start_1c)
+
+EPILOGUE()
+
+
+	ALIGN(16)
+PROLOGUE(mpn_modexact_1_odd)
+deflit(`FRAME',0)
+
+	movl	PARAM_DIVISOR, %ecx
+	pushl	%esi		FRAME_pushl()
+
+	xorl	%edx, %edx
+L(start_1c):
+	pushl	%edi		FRAME_pushl()
+
+	shrl	%ecx			C d/2
+	movl	PARAM_DIVISOR, %esi
+
+	andl	$127, %ecx		C d/2, 7 bits
+	pushl	%ebp		FRAME_pushl()
+
+ifdef(`PIC',`
+	LEA(	binvert_limb_table, %edi)
+Zdisp(	movzbl,	0,(%ecx,%edi), %edi)		C inv 8 bits
+',`
+	movzbl	binvert_limb_table(%ecx), %edi	C inv 8 bits
+')
+	leal	(%edi,%edi), %ecx	C 2*inv
+
+	imull	%edi, %edi		C inv*inv
+
+	movl	PARAM_SRC, %eax
+	movl	PARAM_SIZE, %ebp
+
+	imull	%esi, %edi		C inv*inv*d
+
+	pushl	%ebx		FRAME_pushl()
+	leal	(%eax,%ebp,4), %ebx	C src end
+
+	subl	%edi, %ecx		C inv = 2*inv - inv*inv*d
+	leal	(%ecx,%ecx), %edi	C 2*inv
+
+	imull	%ecx, %ecx		C inv*inv
+
+	movl	(%eax), %eax		C src low limb
+	negl	%ebp			C -size
+
+	imull	%esi, %ecx		C inv*inv*d
+
+	subl	%ecx, %edi		C inv = 2*inv - inv*inv*d
+
+	ASSERT(e,`	C d*inv == 1 mod 2^GMP_LIMB_BITS
+	pushl	%eax
+	movl	%esi, %eax
+	imull	%edi, %eax
+	cmpl	$1, %eax
+	popl	%eax')
+
+	jmp	L(entry)
+
+
+C Rotating the mul to the top of the loop saves 1 cycle, presumably by
+C hiding the loop control under the imul latency.
+C
+C The run time is 10 cycles, but decoding is only 9 (and the dependent chain
+C only 8).  It's not clear how to get down to 9 cycles.
+C
+C The xor and rcl to handle the carry bit could be an sbb instead, with the
+C the carry bit add becoming a sub, but that doesn't save anything.
+
+L(top):
+	C eax	(low product)
+	C ebx	src end
+	C ecx	carry bit, 0 or 1
+	C edx	(high product, being carry limb)
+	C esi	divisor
+	C edi	inverse
+	C ebp	counter, limbs, negative
+
+	mull	%esi
+
+	movl	(%ebx,%ebp,4), %eax
+	addl	%ecx, %edx		C apply carry bit to carry limb
+
+L(entry):
+	xorl	%ecx, %ecx
+	subl	%edx, %eax		C apply carry limb
+
+	rcll	%ecx
+
+	imull	%edi, %eax
+
+	incl	%ebp
+	jnz	L(top)
+
+
+
+	popl	%ebx
+	popl	%ebp
+
+	mull	%esi
+
+	popl	%edi
+	popl	%esi
+
+	leal	(%ecx,%edx), %eax
+
+	ret
+
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86/k6/mul_1.asm b/third_party/gmp/mpn/x86/k6/mul_1.asm
new file mode 100644
index 0000000..3ef7ec2
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k6/mul_1.asm
@@ -0,0 +1,292 @@
+dnl  AMD K6 mpn_mul_1 -- mpn by limb multiply.
+
+dnl  Copyright 1999, 2000, 2002, 2005 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C			    cycles/limb
+C P5
+C P6 model 0-8,10-12		 5.5
+C P6 model 9  (Banias)
+C P6 model 13 (Dothan)		 4.87
+C P4 model 0  (Willamette)
+C P4 model 1  (?)
+C P4 model 2  (Northwood)
+C P4 model 3  (Prescott)
+C P4 model 4  (Nocona)
+C AMD K6			 6.25
+C AMD K7
+C AMD K8
+
+
+C mp_limb_t mpn_mul_1 (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                      mp_limb_t multiplier);
+C mp_limb_t mpn_mul_1c (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                       mp_limb_t multiplier, mp_limb_t carry);
+C
+C Multiply src,size by mult and store the result in dst,size.
+C Return the carry limb from the top of the result.
+C
+C mpn_mul_1c() accepts an initial carry for the calculation, it's added into
+C the low limb of the result.
+
+defframe(PARAM_CARRY,     20)
+defframe(PARAM_MULTIPLIER,16)
+defframe(PARAM_SIZE,      12)
+defframe(PARAM_SRC,       8)
+defframe(PARAM_DST,       4)
+
+dnl  minimum 5 because the unrolled code can't handle less
+deflit(UNROLL_THRESHOLD, 5)
+
+	TEXT
+	ALIGN(32)
+
+PROLOGUE(mpn_mul_1c)
+	pushl	%esi
+deflit(`FRAME',4)
+	movl	PARAM_CARRY, %esi
+	jmp	L(start_nc)
+EPILOGUE()
+
+
+PROLOGUE(mpn_mul_1)
+	push	%esi
+deflit(`FRAME',4)
+	xorl	%esi, %esi	C initial carry
+
+L(start_nc):
+	mov	PARAM_SIZE, %ecx
+	push	%ebx
+FRAME_pushl()
+
+	movl	PARAM_SRC, %ebx
+	push	%edi
+FRAME_pushl()
+
+	movl	PARAM_DST, %edi
+	pushl	%ebp
+FRAME_pushl()
+
+	cmpl	$UNROLL_THRESHOLD, %ecx
+	movl	PARAM_MULTIPLIER, %ebp
+
+	jae	L(unroll)
+
+
+	C code offset 0x22 here, close enough to aligned
+L(simple):
+	C eax	scratch
+	C ebx	src
+	C ecx	counter
+	C edx	scratch
+	C esi	carry
+	C edi	dst
+	C ebp	multiplier
+	C
+	C this loop 8 cycles/limb
+
+	movl	(%ebx), %eax
+	addl	$4, %ebx
+
+	mull	%ebp
+
+	addl	%esi, %eax
+	movl	$0, %esi
+
+	adcl	%edx, %esi
+
+	movl	%eax, (%edi)
+	addl	$4, %edi
+
+	loop	L(simple)
+
+
+	popl	%ebp
+
+	popl	%edi
+	popl	%ebx
+
+	movl	%esi, %eax
+	popl	%esi
+
+	ret
+
+
+C -----------------------------------------------------------------------------
+C The code for each limb is 6 cycles, with instruction decoding being the
+C limiting factor.  At 4 limbs/loop and 1 cycle/loop of overhead it's 6.25
+C cycles/limb in total.
+C
+C The secret ingredient to get 6.25 is to start the loop with the mul and
+C have the load/store pair at the end.  Rotating the load/store to the top
+C is an 0.5 c/l slowdown.  (Some address generation effect probably.)
+C
+C The whole unrolled loop fits nicely in exactly 80 bytes.
+
+
+	ALIGN(16)	C already aligned to 16 here actually
+L(unroll):
+	movl	(%ebx), %eax
+	leal	-16(%ebx,%ecx,4), %ebx
+
+	leal	-16(%edi,%ecx,4), %edi
+	subl	$4, %ecx
+
+	negl	%ecx
+
+
+	ALIGN(16)	C one byte nop for this alignment
+L(top):
+	C eax	scratch
+	C ebx	&src[size-4]
+	C ecx	counter
+	C edx	scratch
+	C esi	carry
+	C edi	&dst[size-4]
+	C ebp	multiplier
+
+	mull	%ebp
+
+	addl	%esi, %eax
+	movl	$0, %esi
+
+	adcl	%edx, %esi
+
+	movl	%eax, (%edi,%ecx,4)
+	movl	4(%ebx,%ecx,4), %eax
+
+
+	mull	%ebp
+
+	addl	%esi, %eax
+	movl	$0, %esi
+
+	adcl	%edx, %esi
+
+	movl	%eax, 4(%edi,%ecx,4)
+	movl	8(%ebx,%ecx,4), %eax
+
+
+	mull	%ebp
+
+	addl	%esi, %eax
+	movl	$0, %esi
+
+	adcl	%edx, %esi
+
+	movl	%eax, 8(%edi,%ecx,4)
+	movl	12(%ebx,%ecx,4), %eax
+
+
+	mull	%ebp
+
+	addl	%esi, %eax
+	movl	$0, %esi
+
+	adcl	%edx, %esi
+
+	movl	%eax, 12(%edi,%ecx,4)
+	movl	16(%ebx,%ecx,4), %eax
+
+
+	addl	$4, %ecx
+	js	L(top)
+
+
+
+	C eax	next src limb
+	C ebx	&src[size-4]
+	C ecx	0 to 3 representing respectively 4 to 1 further limbs
+	C edx
+	C esi	carry
+	C edi	&dst[size-4]
+
+	testb	$2, %cl
+	jnz	L(finish_not_two)
+
+	mull	%ebp
+
+	addl	%esi, %eax
+	movl	$0, %esi
+
+	adcl	%edx, %esi
+
+	movl	%eax, (%edi,%ecx,4)
+	movl	4(%ebx,%ecx,4), %eax
+
+
+	mull	%ebp
+
+	addl	%esi, %eax
+	movl	$0, %esi
+
+	adcl	%edx, %esi
+
+	movl	%eax, 4(%edi,%ecx,4)
+	movl	8(%ebx,%ecx,4), %eax
+
+	addl	$2, %ecx
+L(finish_not_two):
+
+
+	testb	$1, %cl
+	jnz	L(finish_not_one)
+
+	mull	%ebp
+
+	addl	%esi, %eax
+	movl	$0, %esi
+
+	adcl	%edx, %esi
+
+	movl	%eax, 8(%edi)
+	movl	12(%ebx), %eax
+L(finish_not_one):
+
+
+	mull	%ebp
+
+	addl	%esi, %eax
+	popl	%ebp
+
+	adcl	$0, %edx
+
+	movl	%eax, 12(%edi)
+	popl	%edi
+
+	popl	%ebx
+	movl	%edx, %eax
+
+	popl	%esi
+
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/k6/mul_basecase.asm b/third_party/gmp/mpn/x86/k6/mul_basecase.asm
new file mode 100644
index 0000000..7030001
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k6/mul_basecase.asm
@@ -0,0 +1,612 @@
+dnl  AMD K6 mpn_mul_basecase -- multiply two mpn numbers.
+
+dnl  Copyright 1999-2003 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C K6: approx 9.0 cycles per cross product on 30x30 limbs (with 16 limbs/loop
+C     unrolling).
+
+
+
+dnl  K6: UNROLL_COUNT cycles/product (approx)
+dnl           8           9.75
+dnl          16           9.3
+dnl          32           9.3
+dnl  Maximum possible with the current code is 32.
+dnl
+dnl  With 16 the inner unrolled loop fits exactly in a 256 byte block, which
+dnl  might explain it's good performance.
+
+deflit(UNROLL_COUNT, 16)
+
+
+C void mpn_mul_basecase (mp_ptr wp,
+C                        mp_srcptr xp, mp_size_t xsize,
+C                        mp_srcptr yp, mp_size_t ysize);
+C
+C Calculate xp,xsize multiplied by yp,ysize, storing the result in
+C wp,xsize+ysize.
+C
+C This routine is essentially the same as mpn/generic/mul_basecase.c, but
+C it's faster because it does most of the mpn_addmul_1() entry code only
+C once.  The saving is about 10-20% on typical sizes coming from the
+C Karatsuba multiply code.
+C
+C Enhancements:
+C
+C The mul_1 loop is about 8.5 c/l, which is slower than mpn_mul_1 at 6.25
+C c/l.  Could call mpn_mul_1 when ysize is big enough to make it worthwhile.
+C
+C The main unrolled addmul loop could be shared by mpn_addmul_1, using some
+C extra stack setups and maybe 2 or 3 wasted cycles at the end.  Code saving
+C would be 256 bytes.
+
+ifdef(`PIC',`
+deflit(UNROLL_THRESHOLD, 8)
+',`
+deflit(UNROLL_THRESHOLD, 8)
+')
+
+defframe(PARAM_YSIZE,20)
+defframe(PARAM_YP,   16)
+defframe(PARAM_XSIZE,12)
+defframe(PARAM_XP,   8)
+defframe(PARAM_WP,   4)
+
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_mul_basecase)
+deflit(`FRAME',0)
+
+	movl	PARAM_XSIZE, %ecx
+	movl	PARAM_YP, %eax
+
+	movl	PARAM_XP, %edx
+	movl	(%eax), %eax	C yp low limb
+
+	cmpl	$2, %ecx
+	ja	L(xsize_more_than_two_limbs)
+	je	L(two_by_something)
+
+
+	C one limb by one limb
+
+	movl	(%edx), %edx	C xp low limb
+	movl	PARAM_WP, %ecx
+
+	mull	%edx
+
+	movl	%eax, (%ecx)
+	movl	%edx, 4(%ecx)
+	ret
+
+
+C -----------------------------------------------------------------------------
+L(two_by_something):
+	decl	PARAM_YSIZE
+	pushl	%ebx
+deflit(`FRAME',4)
+
+	movl	PARAM_WP, %ebx
+	pushl	%esi
+deflit(`FRAME',8)
+
+	movl	%eax, %ecx	C yp low limb
+	movl	(%edx), %eax	C xp low limb
+
+	movl	%edx, %esi	C xp
+	jnz	L(two_by_two)
+
+
+	C two limbs by one limb
+
+	mull	%ecx
+
+	movl	%eax, (%ebx)
+	movl	4(%esi), %eax
+
+	movl	%edx, %esi	C carry
+
+	mull	%ecx
+
+	addl	%eax, %esi
+	movl	%esi, 4(%ebx)
+
+	adcl	$0, %edx
+
+	movl	%edx, 8(%ebx)
+	popl	%esi
+
+	popl	%ebx
+	ret
+
+
+
+C -----------------------------------------------------------------------------
+	ALIGN(16)
+L(two_by_two):
+	C eax	xp low limb
+	C ebx	wp
+	C ecx	yp low limb
+	C edx
+	C esi	xp
+	C edi
+	C ebp
+deflit(`FRAME',8)
+
+	mull	%ecx		C xp[0] * yp[0]
+
+	push	%edi
+deflit(`FRAME',12)
+	movl	%eax, (%ebx)
+
+	movl	4(%esi), %eax
+	movl	%edx, %edi	C carry, for wp[1]
+
+	mull	%ecx		C xp[1] * yp[0]
+
+	addl	%eax, %edi
+	movl	PARAM_YP, %ecx
+
+	adcl	$0, %edx
+
+	movl	%edi, 4(%ebx)
+	movl	4(%ecx), %ecx	C yp[1]
+
+	movl	4(%esi), %eax	C xp[1]
+	movl	%edx, %edi	C carry, for wp[2]
+
+	mull	%ecx		C xp[1] * yp[1]
+
+	addl	%eax, %edi
+
+	adcl	$0, %edx
+
+	movl	(%esi), %eax	C xp[0]
+	movl	%edx, %esi	C carry, for wp[3]
+
+	mull	%ecx		C xp[0] * yp[1]
+
+	addl	%eax, 4(%ebx)
+	adcl	%edx, %edi
+	adcl	$0, %esi
+
+	movl	%edi, 8(%ebx)
+	popl	%edi
+
+	movl	%esi, 12(%ebx)
+	popl	%esi
+
+	popl	%ebx
+	ret
+
+
+C -----------------------------------------------------------------------------
+	ALIGN(16)
+L(xsize_more_than_two_limbs):
+
+C The first limb of yp is processed with a simple mpn_mul_1 style loop
+C inline.  Unrolling this doesn't seem worthwhile since it's only run once
+C (whereas the addmul below is run ysize-1 many times).  A call to the
+C actual mpn_mul_1 will be slowed down by the call and parameter pushing and
+C popping, and doesn't seem likely to be worthwhile on the typical 10-20
+C limb operations the Karatsuba code calls here with.
+
+	C eax	yp[0]
+	C ebx
+	C ecx	xsize
+	C edx	xp
+	C esi
+	C edi
+	C ebp
+deflit(`FRAME',0)
+
+	pushl	%edi		defframe_pushl(SAVE_EDI)
+	pushl	%ebp		defframe_pushl(SAVE_EBP)
+
+	movl	PARAM_WP, %edi
+	pushl	%esi		defframe_pushl(SAVE_ESI)
+
+	movl	%eax, %ebp
+	pushl	%ebx		defframe_pushl(SAVE_EBX)
+
+	leal	(%edx,%ecx,4), %ebx	C xp end
+	xorl	%esi, %esi
+
+	leal	(%edi,%ecx,4), %edi	C wp end of mul1
+	negl	%ecx
+
+
+L(mul1):
+	C eax	scratch
+	C ebx	xp end
+	C ecx	counter, negative
+	C edx	scratch
+	C esi	carry
+	C edi	wp end of mul1
+	C ebp	multiplier
+
+	movl	(%ebx,%ecx,4), %eax
+
+	mull	%ebp
+
+	addl	%esi, %eax
+	movl	$0, %esi
+
+	adcl	%edx, %esi
+
+	movl	%eax, (%edi,%ecx,4)
+	incl	%ecx
+
+	jnz	L(mul1)
+
+
+	movl	PARAM_YSIZE, %edx
+	movl	%esi, (%edi)		C final carry
+
+	movl	PARAM_XSIZE, %ecx
+	decl	%edx
+
+	jnz	L(ysize_more_than_one_limb)
+
+	popl	%ebx
+	popl	%esi
+	popl	%ebp
+	popl	%edi
+	ret
+
+
+L(ysize_more_than_one_limb):
+	cmpl	$UNROLL_THRESHOLD, %ecx
+	movl	PARAM_YP, %eax
+
+	jae	L(unroll)
+
+
+C -----------------------------------------------------------------------------
+C Simple addmul loop.
+C
+C Using ebx and edi pointing at the ends of their respective locations saves
+C a couple of instructions in the outer loop.  The inner loop is still 11
+C cycles, the same as the simple loop in aorsmul_1.asm.
+
+	C eax	yp
+	C ebx	xp end
+	C ecx	xsize
+	C edx	ysize-1
+	C esi
+	C edi	wp end of mul1
+	C ebp
+
+	movl	4(%eax), %ebp		C multiplier
+	negl	%ecx
+
+	movl	%ecx, PARAM_XSIZE	C -xsize
+	xorl	%esi, %esi		C initial carry
+
+	leal	4(%eax,%edx,4), %eax	C yp end
+	negl	%edx
+
+	movl	%eax, PARAM_YP
+	movl	%edx, PARAM_YSIZE
+
+	jmp	L(simple_outer_entry)
+
+
+	C aligning here saves a couple of cycles
+	ALIGN(16)
+L(simple_outer_top):
+	C edx	ysize counter, negative
+
+	movl	PARAM_YP, %eax		C yp end
+	xorl	%esi, %esi		C carry
+
+	movl	PARAM_XSIZE, %ecx	C -xsize
+	movl	%edx, PARAM_YSIZE
+
+	movl	(%eax,%edx,4), %ebp	C yp limb multiplier
+L(simple_outer_entry):
+	addl	$4, %edi
+
+
+L(simple_inner):
+	C eax	scratch
+	C ebx	xp end
+	C ecx	counter, negative
+	C edx	scratch
+	C esi	carry
+	C edi	wp end of this addmul
+	C ebp	multiplier
+
+	movl	(%ebx,%ecx,4), %eax
+
+	mull	%ebp
+
+	addl	%esi, %eax
+	movl	$0, %esi
+
+	adcl	$0, %edx
+	addl	%eax, (%edi,%ecx,4)
+	adcl	%edx, %esi
+
+	incl	%ecx
+	jnz	L(simple_inner)
+
+
+	movl	PARAM_YSIZE, %edx
+	movl	%esi, (%edi)
+
+	incl	%edx
+	jnz	L(simple_outer_top)
+
+
+	popl	%ebx
+	popl	%esi
+	popl	%ebp
+	popl	%edi
+	ret
+
+
+C -----------------------------------------------------------------------------
+C Unrolled loop.
+C
+C The unrolled inner loop is the same as in aorsmul_1.asm, see that code for
+C some comments.
+C
+C VAR_COUNTER is for the inner loop, running from VAR_COUNTER_INIT down to
+C 0, inclusive.
+C
+C VAR_JMP is the computed jump into the unrolled loop.
+C
+C PARAM_XP and PARAM_WP get offset appropriately for where the unrolled loop
+C is entered.
+C
+C VAR_XP_LOW is the least significant limb of xp, which is needed at the
+C start of the unrolled loop.  This can't just be fetched through the xp
+C pointer because of the offset applied to it.
+C
+C PARAM_YSIZE is the outer loop counter, going from -(ysize-1) up to -1,
+C inclusive.
+C
+C PARAM_YP is offset appropriately so that the PARAM_YSIZE counter can be
+C added to give the location of the next limb of yp, which is the multiplier
+C in the unrolled loop.
+C
+C PARAM_WP is similarly offset so that the PARAM_YSIZE counter can be added
+C to give the starting point in the destination for each unrolled loop (this
+C point is one limb upwards for each limb of yp processed).
+C
+C Having PARAM_YSIZE count negative to zero means it's not necessary to
+C store new values of PARAM_YP and PARAM_WP on each loop.  Those values on
+C the stack remain constant and on each loop an leal adjusts them with the
+C PARAM_YSIZE counter value.
+
+
+defframe(VAR_COUNTER,      -20)
+defframe(VAR_COUNTER_INIT, -24)
+defframe(VAR_JMP,          -28)
+defframe(VAR_XP_LOW,       -32)
+deflit(VAR_STACK_SPACE, 16)
+
+dnl  For some strange reason using (%esp) instead of 0(%esp) is a touch
+dnl  slower in this code, hence the defframe empty-if-zero feature is
+dnl  disabled.
+dnl
+dnl  If VAR_COUNTER is at (%esp), the effect is worse.  In this case the
+dnl  unrolled loop is 255 instead of 256 bytes, but quite how this affects
+dnl  anything isn't clear.
+dnl
+define(`defframe_empty_if_zero_disabled',1)
+
+L(unroll):
+	C eax	yp (not used)
+	C ebx	xp end (not used)
+	C ecx	xsize
+	C edx	ysize-1
+	C esi
+	C edi	wp end of mul1 (not used)
+	C ebp
+deflit(`FRAME', 16)
+
+	leal	-2(%ecx), %ebp	C one limb processed at start,
+	decl	%ecx		C and ebp is one less
+
+	shrl	$UNROLL_LOG2, %ebp
+	negl	%ecx
+
+	subl	$VAR_STACK_SPACE, %esp
+deflit(`FRAME', 16+VAR_STACK_SPACE)
+	andl	$UNROLL_MASK, %ecx
+
+	movl	%ecx, %esi
+	shll	$4, %ecx
+
+	movl	%ebp, VAR_COUNTER_INIT
+	negl	%esi
+
+	C 15 code bytes per limb
+ifdef(`PIC',`
+	call	L(pic_calc)
+L(unroll_here):
+',`
+	leal	L(unroll_entry) (%ecx,%esi,1), %ecx
+')
+
+	movl	PARAM_XP, %ebx
+	movl	%ebp, VAR_COUNTER
+
+	movl	PARAM_WP, %edi
+	movl	%ecx, VAR_JMP
+
+	movl	(%ebx), %eax
+	leal	4(%edi,%esi,4), %edi	C wp adjust for unrolling and mul1
+
+	leal	(%ebx,%esi,4), %ebx	C xp adjust for unrolling
+
+	movl	%eax, VAR_XP_LOW
+
+	movl	%ebx, PARAM_XP
+	movl	PARAM_YP, %ebx
+
+	leal	(%edi,%edx,4), %ecx	C wp adjust for ysize indexing
+	movl	4(%ebx), %ebp		C multiplier (yp second limb)
+
+	leal	4(%ebx,%edx,4), %ebx	C yp adjust for ysize indexing
+
+	movl	%ecx, PARAM_WP
+
+	leal	1(%esi), %ecx	C adjust parity for decl %ecx above
+
+	movl	%ebx, PARAM_YP
+	negl	%edx
+
+	movl	%edx, PARAM_YSIZE
+	jmp	L(unroll_outer_entry)
+
+
+ifdef(`PIC',`
+L(pic_calc):
+	C See mpn/x86/README about old gas bugs
+	leal	(%ecx,%esi,1), %ecx
+	addl	$L(unroll_entry)-L(unroll_here), %ecx
+	addl	(%esp), %ecx
+	ret_internal
+')
+
+
+C -----------------------------------------------------------------------------
+	C Aligning here saves a couple of cycles per loop.  Using 32 doesn't
+	C cost any extra space, since the inner unrolled loop below is
+	C aligned to 32.
+	ALIGN(32)
+L(unroll_outer_top):
+	C edx	ysize
+
+	movl	PARAM_YP, %eax
+	movl	%edx, PARAM_YSIZE	C incremented ysize counter
+
+	movl	PARAM_WP, %edi
+
+	movl	VAR_COUNTER_INIT, %ebx
+	movl	(%eax,%edx,4), %ebp	C next multiplier
+
+	movl	PARAM_XSIZE, %ecx
+	leal	(%edi,%edx,4), %edi	C adjust wp for where we are in yp
+
+	movl	VAR_XP_LOW, %eax
+	movl	%ebx, VAR_COUNTER
+
+L(unroll_outer_entry):
+	mull	%ebp
+
+	C using testb is a tiny bit faster than testl
+	testb	$1, %cl
+
+	movl	%eax, %ecx	C low carry
+	movl	VAR_JMP, %eax
+
+	movl	%edx, %esi	C high carry
+	movl	PARAM_XP, %ebx
+
+	jnz	L(unroll_noswap)
+	movl	%ecx, %esi	C high,low carry other way around
+
+	movl	%edx, %ecx
+L(unroll_noswap):
+
+	jmp	*%eax
+
+
+
+C -----------------------------------------------------------------------------
+	ALIGN(32)
+L(unroll_top):
+	C eax	scratch
+	C ebx	xp
+	C ecx	carry low
+	C edx	scratch
+	C esi	carry high
+	C edi	wp
+	C ebp	multiplier
+	C VAR_COUNTER  loop counter
+	C
+	C 15 code bytes each limb
+
+	leal	UNROLL_BYTES(%edi), %edi
+
+L(unroll_entry):
+deflit(CHUNK_COUNT,2)
+forloop(`i', 0, UNROLL_COUNT/CHUNK_COUNT-1, `
+	deflit(`disp0', eval(i*CHUNK_COUNT*4))
+	deflit(`disp1', eval(disp0 + 4))
+	deflit(`disp2', eval(disp1 + 4))
+
+	movl	disp1(%ebx), %eax
+	mull	%ebp
+Zdisp(	addl,	%ecx, disp0,(%edi))
+	adcl	%eax, %esi
+	movl	%edx, %ecx
+	jadcl0( %ecx)
+
+	movl	disp2(%ebx), %eax
+	mull	%ebp
+	addl	%esi, disp1(%edi)
+	adcl	%eax, %ecx
+	movl	%edx, %esi
+	jadcl0( %esi)
+')
+
+	decl	VAR_COUNTER
+	leal	UNROLL_BYTES(%ebx), %ebx
+
+	jns	L(unroll_top)
+
+
+	movl	PARAM_YSIZE, %edx
+	addl	%ecx, UNROLL_BYTES(%edi)
+
+	adcl	$0, %esi
+
+	incl	%edx
+	movl	%esi, UNROLL_BYTES+4(%edi)
+
+	jnz	L(unroll_outer_top)
+
+
+	movl	SAVE_ESI, %esi
+	movl	SAVE_EBP, %ebp
+	movl	SAVE_EDI, %edi
+	movl	SAVE_EBX, %ebx
+
+	addl	$FRAME, %esp
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/k6/pre_mod_1.asm b/third_party/gmp/mpn/x86/k6/pre_mod_1.asm
new file mode 100644
index 0000000..34db20d
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k6/pre_mod_1.asm
@@ -0,0 +1,146 @@
+dnl  AMD K6 mpn_preinv_mod_1 -- mpn by 1 remainder, with pre-inverted divisor.
+
+dnl  Copyright 2000, 2002, 2003 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C K6: 18.0 cycles/limb
+
+
+C mp_limb_t mpn_preinv_mod_1 (mp_srcptr src, mp_size_t size, mp_limb_t divisor,
+C                             mp_limb_t inverse);
+C
+C This code is only 2 c/l faster than a simple divl, but that's 10% so it's
+C considered worthwhile (just).
+
+defframe(PARAM_INVERSE,16)
+defframe(PARAM_DIVISOR,12)
+defframe(PARAM_SIZE,    8)
+defframe(PARAM_SRC,     4)
+
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_preinv_mod_1)
+deflit(`FRAME',0)
+
+	ASSERT(ae,`cmpl $1, PARAM_SIZE')
+	ASSERT(nz,`testl $0x80000000, PARAM_DIVISOR')
+
+	movl	PARAM_SIZE, %ecx
+	pushl	%ebp	FRAME_pushl()
+
+	movl	PARAM_SRC, %ebp
+	pushl	%edi	FRAME_pushl()
+
+	movl	PARAM_DIVISOR, %eax
+	pushl	%esi	FRAME_pushl()
+
+	movl	-4(%ebp,%ecx,4), %esi	C src high limb
+	pushl	%ebx	FRAME_pushl()
+
+	movl	%edx, %edi		C first n2 to cancel
+	subl	%eax, %esi		C first n1 = high-divisor
+
+	decl	%ecx
+	jz	L(done_sbbl)
+
+L(top):
+	C eax	scratch
+	C ebx	n10, nadj, q1
+	C ecx	counter, size to 1
+	C edx	scratch
+	C esi	n2
+	C edi	old high, for underflow test
+	C ebp	src
+
+	sbbl	%edx, %edi	    C high n-(q1+1)*d, 0 or -1
+
+L(entry):
+	andl	PARAM_DIVISOR, %edi
+L(q1_ff_top):
+	movl	-4(%ebp,%ecx,4), %ebx
+
+	addl	%esi, %edi	    C possible addback
+	movl	%ebx, %esi	    C n10
+
+	sarl	$31, %ebx	    C -n1 = 0 or -1
+	movl	%edi, %eax	    C n2
+
+	movl	PARAM_INVERSE, %edx
+	subl	%ebx, %eax	    C n2+n1
+
+	mull	%edx		    C m*(n2+n1)
+
+	andl	PARAM_DIVISOR, %ebx C -n1 & d
+	addl	%esi, %ebx	    C nadj = n10 + (-n1&d), ignoring overflow
+
+	addl	%ebx, %eax	    C low m*(n2+n1) + nadj, giving carry flag
+	leal	1(%edi), %ebx	    C n2+1
+
+	adcl	%ebx, %edx	    C 1+high(n2<<32+m*(n2+n1)+nadj) = q1+1
+
+	movl	PARAM_DIVISOR, %eax C d
+	jz	L(q1_ff)
+
+	mull	%edx		    C (q1+1)*d
+
+	subl	%eax, %esi	    C low  n-(q1+1)*d
+	loop	L(top)
+
+
+
+L(done_sbbl):
+	sbbl	%edx, %edi	    C high n-(q1+1)*d, 0 or -1
+
+	andl	PARAM_DIVISOR, %edi
+L(done_esi_edi):
+	popl	%ebx
+
+	leal	(%esi,%edi), %eax
+	popl	%esi
+
+	popl	%edi
+	popl	%ebp
+
+	ret
+
+
+C Special case for q1=0xFFFFFFFF, giving q=0xFFFFFFFF meaning the low dword
+C of q*d is simply -d and the remainder n-q*d = n10+d.  This is rarely
+C reached.
+
+L(q1_ff):
+	movl	PARAM_DIVISOR, %edi
+	loop	L(q1_ff_top)
+
+	jmp	L(done_esi_edi)
+
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/k6/sqr_basecase.asm b/third_party/gmp/mpn/x86/k6/sqr_basecase.asm
new file mode 100644
index 0000000..b7ecb5c
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k6/sqr_basecase.asm
@@ -0,0 +1,680 @@
+dnl  AMD K6 mpn_sqr_basecase -- square an mpn number.
+
+dnl  Copyright 1999-2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C K6: approx 4.7 cycles per cross product, or 9.2 cycles per triangular
+C     product (measured on the speed difference between 17 and 33 limbs,
+C     which is roughly the Karatsuba recursing range).
+
+
+dnl  SQR_TOOM2_THRESHOLD_MAX is the maximum SQR_TOOM2_THRESHOLD this
+dnl  code supports.  This value is used only by the tune program to know
+dnl  what it can go up to.  (An attempt to compile with a bigger value will
+dnl  trigger some m4_assert()s in the code, making the build fail.)
+dnl
+dnl  The value is determined by requiring the displacements in the unrolled
+dnl  addmul to fit in single bytes.  This means a maximum UNROLL_COUNT of
+dnl  63, giving a maximum SQR_TOOM2_THRESHOLD of 66.
+
+deflit(SQR_TOOM2_THRESHOLD_MAX, 66)
+
+
+dnl  Allow a value from the tune program to override config.m4.
+
+ifdef(`SQR_TOOM2_THRESHOLD_OVERRIDE',
+`define(`SQR_TOOM2_THRESHOLD',SQR_TOOM2_THRESHOLD_OVERRIDE)')
+
+
+dnl  UNROLL_COUNT is the number of code chunks in the unrolled addmul.  The
+dnl  number required is determined by SQR_TOOM2_THRESHOLD, since
+dnl  mpn_sqr_basecase only needs to handle sizes < SQR_TOOM2_THRESHOLD.
+dnl
+dnl  The first addmul is the biggest, and this takes the second least
+dnl  significant limb and multiplies it by the third least significant and
+dnl  up.  Hence for a maximum operand size of SQR_TOOM2_THRESHOLD-1
+dnl  limbs, UNROLL_COUNT needs to be SQR_TOOM2_THRESHOLD-3.
+
+m4_config_gmp_mparam(`SQR_TOOM2_THRESHOLD')
+deflit(UNROLL_COUNT, eval(SQR_TOOM2_THRESHOLD-3))
+
+
+C void mpn_sqr_basecase (mp_ptr dst, mp_srcptr src, mp_size_t size);
+C
+C The algorithm is essentially the same as mpn/generic/sqr_basecase.c, but a
+C lot of function call overheads are avoided, especially when the given size
+C is small.
+C
+C The code size might look a bit excessive, but not all of it is executed
+C and so won't fill up the code cache.  The 1x1, 2x2 and 3x3 special cases
+C clearly apply only to those sizes; mid sizes like 10x10 only need part of
+C the unrolled addmul; and big sizes like 35x35 that do need all of it will
+C at least be getting value for money, because 35x35 spends something like
+C 5780 cycles here.
+C
+C Different values of UNROLL_COUNT give slightly different speeds, between
+C 9.0 and 9.2 c/tri-prod measured on the difference between 17 and 33 limbs.
+C This isn't a big difference, but it's presumably some alignment effect
+C which if understood could give a simple speedup.
+
+defframe(PARAM_SIZE,12)
+defframe(PARAM_SRC, 8)
+defframe(PARAM_DST, 4)
+
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_sqr_basecase)
+deflit(`FRAME',0)
+
+	movl	PARAM_SIZE, %ecx
+	movl	PARAM_SRC, %eax
+
+	cmpl	$2, %ecx
+	je	L(two_limbs)
+
+	movl	PARAM_DST, %edx
+	ja	L(three_or_more)
+
+
+C -----------------------------------------------------------------------------
+C one limb only
+	C eax	src
+	C ebx
+	C ecx	size
+	C edx	dst
+
+	movl	(%eax), %eax
+	movl	%edx, %ecx
+
+	mull	%eax
+
+	movl	%eax, (%ecx)
+	movl	%edx, 4(%ecx)
+	ret
+
+
+C -----------------------------------------------------------------------------
+	ALIGN(16)
+L(two_limbs):
+	C eax	src
+	C ebx
+	C ecx	size
+	C edx	dst
+
+	pushl	%ebx
+	movl	%eax, %ebx	C src
+deflit(`FRAME',4)
+
+	movl	(%ebx), %eax
+	movl	PARAM_DST, %ecx
+
+	mull	%eax		C src[0]^2
+
+	movl	%eax, (%ecx)
+	movl	4(%ebx), %eax
+
+	movl	%edx, 4(%ecx)
+
+	mull	%eax		C src[1]^2
+
+	movl	%eax, 8(%ecx)
+	movl	(%ebx), %eax
+
+	movl	%edx, 12(%ecx)
+	movl	4(%ebx), %edx
+
+	mull	%edx		C src[0]*src[1]
+
+	addl	%eax, 4(%ecx)
+
+	adcl	%edx, 8(%ecx)
+	adcl	$0, 12(%ecx)
+
+	popl	%ebx
+	addl	%eax, 4(%ecx)
+
+	adcl	%edx, 8(%ecx)
+	adcl	$0, 12(%ecx)
+
+	ret
+
+
+C -----------------------------------------------------------------------------
+L(three_or_more):
+deflit(`FRAME',0)
+	cmpl	$4, %ecx
+	jae	L(four_or_more)
+
+
+C -----------------------------------------------------------------------------
+C three limbs
+	C eax	src
+	C ecx	size
+	C edx	dst
+
+	pushl	%ebx
+	movl	%eax, %ebx	C src
+
+	movl	(%ebx), %eax
+	movl	%edx, %ecx	C dst
+
+	mull	%eax		C src[0] ^ 2
+
+	movl	%eax, (%ecx)
+	movl	4(%ebx), %eax
+
+	movl	%edx, 4(%ecx)
+	pushl	%esi
+
+	mull	%eax		C src[1] ^ 2
+
+	movl	%eax, 8(%ecx)
+	movl	8(%ebx), %eax
+
+	movl	%edx, 12(%ecx)
+	pushl	%edi
+
+	mull	%eax		C src[2] ^ 2
+
+	movl	%eax, 16(%ecx)
+	movl	(%ebx), %eax
+
+	movl	%edx, 20(%ecx)
+	movl	4(%ebx), %edx
+
+	mull	%edx		C src[0] * src[1]
+
+	movl	%eax, %esi
+	movl	(%ebx), %eax
+
+	movl	%edx, %edi
+	movl	8(%ebx), %edx
+
+	pushl	%ebp
+	xorl	%ebp, %ebp
+
+	mull	%edx		C src[0] * src[2]
+
+	addl	%eax, %edi
+	movl	4(%ebx), %eax
+
+	adcl	%edx, %ebp
+
+	movl	8(%ebx), %edx
+
+	mull	%edx		C src[1] * src[2]
+
+	addl	%eax, %ebp
+
+	adcl	$0, %edx
+
+
+	C eax	will be dst[5]
+	C ebx
+	C ecx	dst
+	C edx	dst[4]
+	C esi	dst[1]
+	C edi	dst[2]
+	C ebp	dst[3]
+
+	xorl	%eax, %eax
+	addl	%esi, %esi
+	adcl	%edi, %edi
+	adcl	%ebp, %ebp
+	adcl	%edx, %edx
+	adcl	$0, %eax
+
+	addl	%esi, 4(%ecx)
+	adcl	%edi, 8(%ecx)
+	adcl	%ebp, 12(%ecx)
+
+	popl	%ebp
+	popl	%edi
+
+	adcl	%edx, 16(%ecx)
+
+	popl	%esi
+	popl	%ebx
+
+	adcl	%eax, 20(%ecx)
+	ASSERT(nc)
+
+	ret
+
+
+C -----------------------------------------------------------------------------
+
+defframe(SAVE_EBX,   -4)
+defframe(SAVE_ESI,   -8)
+defframe(SAVE_EDI,   -12)
+defframe(SAVE_EBP,   -16)
+defframe(VAR_COUNTER,-20)
+defframe(VAR_JMP,    -24)
+deflit(STACK_SPACE, 24)
+
+	ALIGN(16)
+L(four_or_more):
+
+	C eax	src
+	C ebx
+	C ecx	size
+	C edx	dst
+	C esi
+	C edi
+	C ebp
+
+C First multiply src[0]*src[1..size-1] and store at dst[1..size].
+C
+C A test was done calling mpn_mul_1 here to get the benefit of its unrolled
+C loop, but this was only a tiny speedup; at 35 limbs it took 24 cycles off
+C a 5780 cycle operation, which is not surprising since the loop here is 8
+C c/l and mpn_mul_1 is 6.25 c/l.
+
+	subl	$STACK_SPACE, %esp	deflit(`FRAME',STACK_SPACE)
+
+	movl	%edi, SAVE_EDI
+	leal	4(%edx), %edi
+
+	movl	%ebx, SAVE_EBX
+	leal	4(%eax), %ebx
+
+	movl	%esi, SAVE_ESI
+	xorl	%esi, %esi
+
+	movl	%ebp, SAVE_EBP
+
+	C eax
+	C ebx	src+4
+	C ecx	size
+	C edx
+	C esi
+	C edi	dst+4
+	C ebp
+
+	movl	(%eax), %ebp	C multiplier
+	leal	-1(%ecx), %ecx	C size-1, and pad to a 16 byte boundary
+
+
+	ALIGN(16)
+L(mul_1):
+	C eax	scratch
+	C ebx	src ptr
+	C ecx	counter
+	C edx	scratch
+	C esi	carry
+	C edi	dst ptr
+	C ebp	multiplier
+
+	movl	(%ebx), %eax
+	addl	$4, %ebx
+
+	mull	%ebp
+
+	addl	%esi, %eax
+	movl	$0, %esi
+
+	adcl	%edx, %esi
+
+	movl	%eax, (%edi)
+	addl	$4, %edi
+
+	loop	L(mul_1)
+
+
+C Addmul src[n]*src[n+1..size-1] at dst[2*n-1...], for each n=1..size-2.
+C
+C The last two addmuls, which are the bottom right corner of the product
+C triangle, are left to the end.  These are src[size-3]*src[size-2,size-1]
+C and src[size-2]*src[size-1].  If size is 4 then it's only these corner
+C cases that need to be done.
+C
+C The unrolled code is the same as mpn_addmul_1(), see that routine for some
+C comments.
+C
+C VAR_COUNTER is the outer loop, running from -(size-4) to -1, inclusive.
+C
+C VAR_JMP is the computed jump into the unrolled code, stepped by one code
+C chunk each outer loop.
+C
+C K6 doesn't do any branch prediction on indirect jumps, which is good
+C actually because it's a different target each time.  The unrolled addmul
+C is about 3 cycles/limb faster than a simple loop, so the 6 cycle cost of
+C the indirect jump is quickly recovered.
+
+
+dnl  This value is also implicitly encoded in a shift and add.
+dnl
+deflit(CODE_BYTES_PER_LIMB, 15)
+
+dnl  With the unmodified &src[size] and &dst[size] pointers, the
+dnl  displacements in the unrolled code fit in a byte for UNROLL_COUNT
+dnl  values up to 31.  Above that an offset must be added to them.
+dnl
+deflit(OFFSET,
+ifelse(eval(UNROLL_COUNT>31),1,
+eval((UNROLL_COUNT-31)*4),
+0))
+
+	C eax
+	C ebx	&src[size]
+	C ecx
+	C edx
+	C esi	carry
+	C edi	&dst[size]
+	C ebp
+
+	movl	PARAM_SIZE, %ecx
+	movl	%esi, (%edi)
+
+	subl	$4, %ecx
+	jz	L(corner)
+
+	movl	%ecx, %edx
+ifelse(OFFSET,0,,
+`	subl	$OFFSET, %ebx')
+
+	shll	$4, %ecx
+ifelse(OFFSET,0,,
+`	subl	$OFFSET, %edi')
+
+	negl	%ecx
+
+ifdef(`PIC',`
+	call	L(pic_calc)
+L(here):
+',`
+	leal	L(unroll_inner_end)-eval(2*CODE_BYTES_PER_LIMB)(%ecx,%edx), %ecx
+')
+	negl	%edx
+
+
+	C The calculated jump mustn't be before the start of the available
+	C code.  This is the limitation UNROLL_COUNT puts on the src operand
+	C size, but checked here using the jump address directly.
+	C
+	ASSERT(ae,`
+	movl_text_address( L(unroll_inner_start), %eax)
+	cmpl	%eax, %ecx
+	')
+
+
+C -----------------------------------------------------------------------------
+	ALIGN(16)
+L(unroll_outer_top):
+	C eax
+	C ebx	&src[size], constant
+	C ecx	VAR_JMP
+	C edx	VAR_COUNTER, limbs, negative
+	C esi	high limb to store
+	C edi	dst ptr, high of last addmul
+	C ebp
+
+	movl	-12+OFFSET(%ebx,%edx,4), %ebp	C multiplier
+	movl	%edx, VAR_COUNTER
+
+	movl	-8+OFFSET(%ebx,%edx,4), %eax	C first limb of multiplicand
+
+	mull	%ebp
+
+	testb	$1, %cl
+
+	movl	%edx, %esi	C high carry
+	movl	%ecx, %edx	C jump
+
+	movl	%eax, %ecx	C low carry
+	leal	CODE_BYTES_PER_LIMB(%edx), %edx
+
+	movl	%edx, VAR_JMP
+	leal	4(%edi), %edi
+
+	C A branch-free version of this using some xors was found to be a
+	C touch slower than just a conditional jump, despite the jump
+	C switching between taken and not taken on every loop.
+
+ifelse(eval(UNROLL_COUNT%2),0,
+	jz,jnz)	L(unroll_noswap)
+	movl	%esi, %eax	C high,low carry other way around
+
+	movl	%ecx, %esi
+	movl	%eax, %ecx
+L(unroll_noswap):
+
+	jmp	*%edx
+
+
+	C Must be on an even address here so the low bit of the jump address
+	C will indicate which way around ecx/esi should start.
+	C
+	C An attempt was made at padding here to get the end of the unrolled
+	C code to come out on a good alignment, to save padding before
+	C L(corner).  This worked, but turned out to run slower than just an
+	C ALIGN(2).  The reason for this is not clear, it might be related
+	C to the different speeds on different UNROLL_COUNTs noted above.
+
+	ALIGN(2)
+
+L(unroll_inner_start):
+	C eax	scratch
+	C ebx	src
+	C ecx	carry low
+	C edx	scratch
+	C esi	carry high
+	C edi	dst
+	C ebp	multiplier
+	C
+	C 15 code bytes each limb
+	C ecx/esi swapped on each chunk
+
+forloop(`i', UNROLL_COUNT, 1, `
+	deflit(`disp_src', eval(-i*4 + OFFSET))
+	deflit(`disp_dst', eval(disp_src - 4))
+
+	m4_assert(`disp_src>=-128 && disp_src<128')
+	m4_assert(`disp_dst>=-128 && disp_dst<128')
+
+ifelse(eval(i%2),0,`
+Zdisp(	movl,	disp_src,(%ebx), %eax)
+	mull	%ebp
+Zdisp(	addl,	%esi, disp_dst,(%edi))
+	adcl	%eax, %ecx
+	movl	%edx, %esi
+	jadcl0( %esi)
+',`
+	dnl  this one comes out last
+Zdisp(	movl,	disp_src,(%ebx), %eax)
+	mull	%ebp
+Zdisp(	addl,	%ecx, disp_dst,(%edi))
+	adcl	%eax, %esi
+	movl	%edx, %ecx
+	jadcl0( %ecx)
+')
+')
+L(unroll_inner_end):
+
+	addl	%esi, -4+OFFSET(%edi)
+
+	movl	VAR_COUNTER, %edx
+	jadcl0(	%ecx)
+
+	movl	%ecx, m4_empty_if_zero(OFFSET)(%edi)
+	movl	VAR_JMP, %ecx
+
+	incl	%edx
+	jnz	L(unroll_outer_top)
+
+
+ifelse(OFFSET,0,,`
+	addl	$OFFSET, %ebx
+	addl	$OFFSET, %edi
+')
+
+
+C -----------------------------------------------------------------------------
+	ALIGN(16)
+L(corner):
+	C ebx	&src[size]
+	C edi	&dst[2*size-5]
+
+	movl	-12(%ebx), %ebp
+
+	movl	-8(%ebx), %eax
+	movl	%eax, %ecx
+
+	mull	%ebp
+
+	addl	%eax, -4(%edi)
+	adcl	$0, %edx
+
+	movl	-4(%ebx), %eax
+	movl	%edx, %esi
+	movl	%eax, %ebx
+
+	mull	%ebp
+
+	addl	%esi, %eax
+	adcl	$0, %edx
+
+	addl	%eax, (%edi)
+	adcl	$0, %edx
+
+	movl	%edx, %esi
+	movl	%ebx, %eax
+
+	mull	%ecx
+
+	addl	%esi, %eax
+	movl	%eax, 4(%edi)
+
+	adcl	$0, %edx
+
+	movl	%edx, 8(%edi)
+
+
+C -----------------------------------------------------------------------------
+C Left shift of dst[1..2*size-2], the bit shifted out becomes dst[2*size-1].
+C The loop measures about 6 cycles/iteration, though it looks like it should
+C decode in 5.
+
+L(lshift_start):
+	movl	PARAM_SIZE, %ecx
+
+	movl	PARAM_DST, %edi
+	subl	$1, %ecx		C size-1 and clear carry
+
+	movl	PARAM_SRC, %ebx
+	movl	%ecx, %edx
+
+	xorl	%eax, %eax		C ready for adcl
+
+
+	ALIGN(16)
+L(lshift):
+	C eax
+	C ebx	src (for later use)
+	C ecx	counter, decrementing
+	C edx	size-1 (for later use)
+	C esi
+	C edi	dst, incrementing
+	C ebp
+
+	rcll	4(%edi)
+	rcll	8(%edi)
+	leal	8(%edi), %edi
+	loop	L(lshift)
+
+
+	adcl	%eax, %eax
+
+	movl	%eax, 4(%edi)		C dst most significant limb
+	movl	(%ebx), %eax		C src[0]
+
+	leal	4(%ebx,%edx,4), %ebx	C &src[size]
+	subl	%edx, %ecx		C -(size-1)
+
+
+C -----------------------------------------------------------------------------
+C Now add in the squares on the diagonal, src[0]^2, src[1]^2, ...,
+C src[size-1]^2.  dst[0] hasn't yet been set at all yet, and just gets the
+C low limb of src[0]^2.
+
+
+	mull	%eax
+
+	movl	%eax, (%edi,%ecx,8)	C dst[0]
+
+
+	ALIGN(16)
+L(diag):
+	C eax	scratch
+	C ebx	&src[size]
+	C ecx	counter, negative
+	C edx	carry
+	C esi	scratch
+	C edi	dst[2*size-2]
+	C ebp
+
+	movl	(%ebx,%ecx,4), %eax
+	movl	%edx, %esi
+
+	mull	%eax
+
+	addl	%esi, 4(%edi,%ecx,8)
+	adcl	%eax, 8(%edi,%ecx,8)
+	adcl	$0, %edx
+
+	incl	%ecx
+	jnz	L(diag)
+
+
+	movl	SAVE_EBX, %ebx
+	movl	SAVE_ESI, %esi
+
+	addl	%edx, 4(%edi)		C dst most significant limb
+
+	movl	SAVE_EDI, %edi
+	movl	SAVE_EBP, %ebp
+	addl	$FRAME, %esp
+	ret
+
+
+
+C -----------------------------------------------------------------------------
+ifdef(`PIC',`
+L(pic_calc):
+	C See mpn/x86/README about old gas bugs
+	addl	(%esp), %ecx
+	addl	$L(unroll_inner_end)-L(here)-eval(2*CODE_BYTES_PER_LIMB), %ecx
+	addl	%edx, %ecx
+	ret_internal
+')
+
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/k7/README b/third_party/gmp/mpn/x86/k7/README
new file mode 100644
index 0000000..5711b61
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k7/README
@@ -0,0 +1,174 @@
+Copyright 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.
+
+
+
+
+                      AMD K7 MPN SUBROUTINES
+
+
+This directory contains code optimized for the AMD Athlon CPU.
+
+The mmx subdirectory has routines using MMX instructions.  All Athlons have
+MMX, the separate directory is just so that configure can omit it if the
+assembler doesn't support MMX.
+
+
+
+STATUS
+
+Times for the loops, with all code and data in L1 cache.
+
+                               cycles/limb
+	mpn_add/sub_n             1.6
+
+	mpn_copyi                 0.75 or 1.0   \ varying with data alignment
+	mpn_copyd                 0.75 or 1.0   /
+
+	mpn_divrem_1             17.0 integer part, 15.0 fractional part
+	mpn_mod_1                17.0
+	mpn_divexact_by3          8.0
+
+	mpn_l/rshift              1.2
+
+	mpn_mul_1                 3.4
+	mpn_addmul/submul_1       3.9
+
+	mpn_mul_basecase          4.42 cycles/crossproduct (approx)
+        mpn_sqr_basecase          2.3 cycles/crossproduct (approx)
+				  or 4.55 cycles/triangleproduct (approx)
+
+Prefetching of sources hasn't yet been tried.
+
+
+
+NOTES
+
+cmov, MMX, 3DNow and some extensions to MMX and 3DNow are available.
+
+Write-allocate L1 data cache means prefetching of destinations is unnecessary.
+
+Floating point multiplications can be done in parallel with integer
+multiplications, but there doesn't seem to be any way to make use of this.
+
+Unsigned "mul"s can be issued every 3 cycles.  This suggests 3 is a limit on
+the speed of the multiplication routines.  The documentation shows mul
+executing in IEU0 (or maybe in IEU0 and IEU1 together), so it might be that,
+to get near 3 cycles code has to be arranged so that nothing else is issued
+to IEU0.  A busy IEU0 could explain why some code takes 4 cycles and other
+apparently equivalent code takes 5.
+
+
+
+OPTIMIZATIONS
+
+Unrolled loops are used to reduce looping overhead.  The unrolling is
+configurable up to 32 limbs/loop for most routines and up to 64 for some.
+The K7 has 64k L1 code cache so quite big unrolling is allowable.
+
+Computed jumps into the unrolling are used to handle sizes not a multiple of
+the unrolling.  An attractive feature of this is that times increase
+smoothly with operand size, but it may be that some routines should just
+have simple loops to finish up, especially when PIC adds between 2 and 16
+cycles to get %eip.
+
+Position independent code is implemented using a call to get %eip for the
+computed jumps and a ret is always done, rather than an addl $4,%esp or a
+popl, so the CPU return address branch prediction stack stays synchronised
+with the actual stack in memory.
+
+Branch prediction, in absence of any history, will guess forward jumps are
+not taken and backward jumps are taken.  Where possible it's arranged that
+the less likely or less important case is under a taken forward jump.
+
+
+
+CODING
+
+Instructions in general code have been shown grouped if they can execute
+together, which means up to three direct-path instructions which have no
+successive dependencies.  K7 always decodes three and has out-of-order
+execution, but the groupings show what slots might be available and what
+dependency chains exist.
+
+When there's vector-path instructions an effort is made to get triplets of
+direct-path instructions in between them, even if there's dependencies,
+since this maximizes decoding throughput and might save a cycle or two if
+decoding is the limiting factor.
+
+
+
+INSTRUCTIONS
+
+adcl       direct
+divl       39 cycles back-to-back
+lodsl,etc  vector
+loop       1 cycle vector (decl/jnz opens up one decode slot)
+movd reg   vector
+movd mem   direct
+mull       issue every 3 cycles, latency 4 cycles low word, 6 cycles high word
+popl	   vector (use movl for more than one pop)
+pushl	   direct, will pair with a load
+shrdl %cl  vector, 3 cycles, seems to be 3 decode too
+xorl r,r   false read dependency recognised
+
+
+
+REFERENCES
+
+"AMD Athlon Processor X86 Code Optimization Guide", AMD publication number
+22007, revision K, February 2002.  Available on-line,
+
+http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/22007.pdf
+
+"3DNow Technology Manual", AMD publication number 21928G/0-March 2000.
+This describes the femms and prefetch instructions.  Available on-line,
+
+http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/21928.pdf
+
+"AMD Extensions to the 3DNow and MMX Instruction Sets Manual", AMD
+publication number 22466, revision D, March 2000.  This describes
+instructions added in the Athlon processor, such as pswapd and the extra
+prefetch forms.  Available on-line,
+
+http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/22466.pdf
+
+"3DNow Instruction Porting Guide", AMD publication number 22621, revision B,
+August 1999.  This has some notes on general Athlon optimizations as well as
+3DNow.  Available on-line,
+
+http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/22621.pdf
+
+
+
+
+----------------
+Local variables:
+mode: text
+fill-column: 76
+End:
diff --git a/third_party/gmp/mpn/x86/k7/addlsh1_n.asm b/third_party/gmp/mpn/x86/k7/addlsh1_n.asm
new file mode 100644
index 0000000..2cba1eb
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k7/addlsh1_n.asm
@@ -0,0 +1,196 @@
+dnl  AMD K7 mpn_addlsh1_n -- rp[] = up[] + (vp[] << 1)
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund and Marco Bodrato.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C This is an attempt at an addlsh1_n for x86-32, not relying on sse2 insns.
+C The innerloop is 2*3-way unrolled, which is best we can do with the available
+C registers.  It seems tricky to use the same structure for rsblsh1_n, since we
+C cannot feed carry between operations there.
+
+C			    cycles/limb
+C P5
+C P6 model 0-8,10-12
+C P6 model 9  (Banias)
+C P6 model 13 (Dothan)		 5.4	(worse than add_n + lshift)
+C P4 model 0  (Willamette)
+C P4 model 1  (?)
+C P4 model 2  (Northwood)
+C P4 model 3  (Prescott)
+C P4 model 4  (Nocona)
+C Intel Atom			 6
+C AMD K6			 ?
+C AMD K7			 2.5
+C AMD K8
+
+C This is a basic addlsh1_n for k7, atom, and perhaps some other x86-32
+C processors.  It uses 2*3-way unrolling, for good reasons.  Unfortunately,
+C that means we need an initial magic multiply.
+C
+C It is not clear how to do sublsh1_n or rsblsh1_n using the same pattern.  We
+C cannot do rsblsh1_n since we feed carry from the shift blocks to the
+C add/subtract blocks, which is right for addition but reversed for
+C subtraction.  We could perhaps do sublsh1_n, with some extra move insns,
+C without losing any time, since we're not issue limited but carry recurrency
+C latency.
+C
+C Breaking carry recurrency might be a good idea.  We would then need separate
+C registers for the shift carry and add/subtract carry, which in turn would
+C force us to 2*2-way unrolling.
+
+defframe(PARAM_SIZE,	16)
+defframe(PARAM_DBLD,	12)
+defframe(PARAM_SRC,	 8)
+defframe(PARAM_DST,	 4)
+
+dnl  re-use parameter space
+define(VAR_COUNT,`PARAM_DST')
+define(VAR_TMP,`PARAM_DBLD')
+
+ASM_START()
+	TEXT
+	ALIGN(8)
+PROLOGUE(mpn_addlsh1_n)
+deflit(`FRAME',0)
+
+define(`rp',  `%edi')
+define(`up',  `%esi')
+define(`vp',  `%ebp')
+
+	mov	$0x2aaaaaab, %eax
+
+	push	%ebx			FRAME_pushl()
+	mov	PARAM_SIZE, %ebx	C size
+
+	push	rp			FRAME_pushl()
+	mov	PARAM_DST, rp
+
+	mul	%ebx
+
+	push	up			FRAME_pushl()
+	mov	PARAM_SRC, up
+
+	not	%edx			C count = -(size\8)-1
+	mov	%edx, VAR_COUNT
+
+	push	vp			FRAME_pushl()
+	mov	PARAM_DBLD, vp
+
+	lea	3(%edx,%edx,2), %ecx	C count*3+3 = -(size\6)*3
+	xor	%edx, %edx
+	lea	(%ebx,%ecx,2), %ebx	C size + (count*3+3)*2 = size % 6
+	or	%ebx, %ebx
+	jz	L(exact)
+
+L(oop):
+ifdef(`CPU_P6',`
+	shr	%edx ')			C restore 2nd saved carry bit
+	mov	(vp), %eax
+	adc	%eax, %eax
+	rcr	%edx			C restore 1st saved carry bit
+	lea	4(vp), vp
+	adc	(up), %eax
+	lea	4(up), up
+	adc	%edx, %edx		C save a carry bit in edx
+ifdef(`CPU_P6',`
+	adc	%edx, %edx ')		C save another carry bit in edx
+	dec	%ebx
+	mov	%eax, (rp)
+	lea	4(rp), rp
+	jnz	L(oop)
+	mov	vp, VAR_TMP
+L(exact):
+	incl	VAR_COUNT
+	jz	L(end)
+
+	ALIGN(16)
+L(top):
+ifdef(`CPU_P6',`
+	shr	%edx ')			C restore 2nd saved carry bit
+	mov	(vp), %eax
+	adc	%eax, %eax
+	mov	4(vp), %ebx
+	adc	%ebx, %ebx
+	mov	8(vp), %ecx
+	adc	%ecx, %ecx
+
+	rcr	%edx			C restore 1st saved carry bit
+
+	adc	(up), %eax
+	mov	%eax, (rp)
+	adc	4(up), %ebx
+	mov	%ebx, 4(rp)
+	adc	8(up), %ecx
+	mov	%ecx, 8(rp)
+
+	mov	12(vp), %eax
+	adc	%eax, %eax
+	mov	16(vp), %ebx
+	adc	%ebx, %ebx
+	mov	20(vp), %ecx
+	adc	%ecx, %ecx
+
+	lea	24(vp), vp
+	adc	%edx, %edx		C save a carry bit in edx
+
+	adc	12(up), %eax
+	mov	%eax, 12(rp)
+	adc	16(up), %ebx
+	mov	%ebx, 16(rp)
+	adc	20(up), %ecx
+
+	lea	24(up), up
+
+ifdef(`CPU_P6',`
+	adc	%edx, %edx ')		C save another carry bit in edx
+	mov	%ecx, 20(rp)
+	incl	VAR_COUNT
+	lea	24(rp), rp
+	jne	L(top)
+
+L(end):
+	pop	vp			FRAME_popl()
+	pop	up			FRAME_popl()
+
+ifdef(`CPU_P6',`
+	xor	%eax, %eax
+	shr	$1, %edx
+	adc	%edx, %eax
+',`
+	adc	$0, %edx
+	mov	%edx, %eax
+')
+	pop	rp			FRAME_popl()
+	pop	%ebx			FRAME_popl()
+	ret
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86/k7/aors_n.asm b/third_party/gmp/mpn/x86/k7/aors_n.asm
new file mode 100644
index 0000000..1a08072
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k7/aors_n.asm
@@ -0,0 +1,258 @@
+dnl  AMD K7 mpn_add_n/mpn_sub_n -- mpn add or subtract.
+
+dnl  Copyright 1999-2003 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C K7: 1.64 cycles/limb (at 16 limbs/loop).
+
+
+
+dnl  K7: UNROLL_COUNT cycles/limb
+dnl           8           1.9
+dnl          16           1.64
+dnl          32           1.7
+dnl          64           2.0
+dnl  Maximum possible with the current code is 64.
+
+deflit(UNROLL_COUNT, 16)
+
+
+ifdef(`OPERATION_add_n', `
+	define(M4_inst,        adcl)
+	define(M4_function_n,  mpn_add_n)
+	define(M4_function_nc, mpn_add_nc)
+	define(M4_description, add)
+',`ifdef(`OPERATION_sub_n', `
+	define(M4_inst,        sbbl)
+	define(M4_function_n,  mpn_sub_n)
+	define(M4_function_nc, mpn_sub_nc)
+	define(M4_description, subtract)
+',`m4_error(`Need OPERATION_add_n or OPERATION_sub_n
+')')')
+
+MULFUNC_PROLOGUE(mpn_add_n mpn_add_nc mpn_sub_n mpn_sub_nc)
+
+
+C mp_limb_t M4_function_n (mp_ptr dst, mp_srcptr src1, mp_srcptr src2,
+C                         mp_size_t size);
+C mp_limb_t M4_function_nc (mp_ptr dst, mp_srcptr src1, mp_srcptr src2,
+C	                   mp_size_t size, mp_limb_t carry);
+C
+C Calculate src1,size M4_description src2,size, and store the result in
+C dst,size.  The return value is the carry bit from the top of the result (1
+C or 0).
+C
+C The _nc version accepts 1 or 0 for an initial carry into the low limb of
+C the calculation.  Note values other than 1 or 0 here will lead to garbage
+C results.
+C
+C This code runs at 1.64 cycles/limb, which might be the best possible with
+C plain integer operations.  Each limb is 2 loads and 1 store, any 2 of
+C which can be done each cycle, leading to 1.5 c/l.
+
+dnl  Must have UNROLL_THRESHOLD >= 2, since the unrolled loop can't handle 1.
+ifdef(`PIC',`
+deflit(UNROLL_THRESHOLD, 8)
+',`
+deflit(UNROLL_THRESHOLD, 8)
+')
+
+defframe(PARAM_CARRY,20)
+defframe(PARAM_SIZE, 16)
+defframe(PARAM_SRC2, 12)
+defframe(PARAM_SRC1, 8)
+defframe(PARAM_DST,  4)
+
+defframe(SAVE_EBP, -4)
+defframe(SAVE_ESI, -8)
+defframe(SAVE_EBX, -12)
+defframe(SAVE_EDI, -16)
+deflit(STACK_SPACE, 16)
+
+	TEXT
+	ALIGN(32)
+deflit(`FRAME',0)
+
+PROLOGUE(M4_function_nc)
+	movl	PARAM_CARRY, %eax
+	jmp	L(start)
+EPILOGUE()
+
+PROLOGUE(M4_function_n)
+
+	xorl	%eax, %eax	C carry
+L(start):
+	movl	PARAM_SIZE, %ecx
+	subl	$STACK_SPACE, %esp
+deflit(`FRAME',STACK_SPACE)
+
+	movl	%edi, SAVE_EDI
+	movl	%ebx, SAVE_EBX
+	cmpl	$UNROLL_THRESHOLD, %ecx
+
+	movl	PARAM_SRC2, %edx
+	movl	PARAM_SRC1, %ebx
+	jae	L(unroll)
+
+	movl	PARAM_DST, %edi
+	leal	(%ebx,%ecx,4), %ebx
+	leal	(%edx,%ecx,4), %edx
+
+	leal	(%edi,%ecx,4), %edi
+	negl	%ecx
+	shrl	%eax
+
+	C This loop in in a single 16 byte code block already, so no
+	C alignment necessary.
+L(simple):
+	C eax	scratch
+	C ebx	src1
+	C ecx	counter
+	C edx	src2
+	C esi
+	C edi	dst
+	C ebp
+
+	movl	(%ebx,%ecx,4), %eax
+	M4_inst	(%edx,%ecx,4), %eax
+	movl	%eax, (%edi,%ecx,4)
+	incl	%ecx
+	jnz	L(simple)
+
+	movl	$0, %eax
+	movl	SAVE_EDI, %edi
+
+	movl	SAVE_EBX, %ebx
+	setc	%al
+	addl	$STACK_SPACE, %esp
+
+	ret
+
+
+C -----------------------------------------------------------------------------
+	C This is at 0x55, close enough to aligned.
+L(unroll):
+deflit(`FRAME',STACK_SPACE)
+	movl	%ebp, SAVE_EBP
+	andl	$-2, %ecx		C size low bit masked out
+	andl	$1, PARAM_SIZE		C size low bit kept
+
+	movl	%ecx, %edi
+	decl	%ecx
+	movl	PARAM_DST, %ebp
+
+	shrl	$UNROLL_LOG2, %ecx
+	negl	%edi
+	movl	%esi, SAVE_ESI
+
+	andl	$UNROLL_MASK, %edi
+
+ifdef(`PIC',`
+	call	L(pic_calc)
+L(here):
+',`
+	leal	L(entry) (%edi,%edi,8), %esi	C 9 bytes per
+')
+	negl	%edi
+	shrl	%eax
+
+	leal	ifelse(UNROLL_BYTES,256,128) (%ebx,%edi,4), %ebx
+	leal	ifelse(UNROLL_BYTES,256,128) (%edx,%edi,4), %edx
+	leal	ifelse(UNROLL_BYTES,256,128) (%ebp,%edi,4), %edi
+
+	jmp	*%esi
+
+
+ifdef(`PIC',`
+L(pic_calc):
+	C See mpn/x86/README about old gas bugs
+	leal	(%edi,%edi,8), %esi
+	addl	$L(entry)-L(here), %esi
+	addl	(%esp), %esi
+	ret_internal
+')
+
+
+C -----------------------------------------------------------------------------
+	ALIGN(32)
+L(top):
+	C eax	zero
+	C ebx	src1
+	C ecx	counter
+	C edx	src2
+	C esi	scratch (was computed jump)
+	C edi	dst
+	C ebp	scratch
+
+	leal	UNROLL_BYTES(%edx), %edx
+
+L(entry):
+deflit(CHUNK_COUNT, 2)
+forloop(i, 0, UNROLL_COUNT/CHUNK_COUNT-1, `
+	deflit(`disp0', eval(i*CHUNK_COUNT*4 ifelse(UNROLL_BYTES,256,-128)))
+	deflit(`disp1', eval(disp0 + 4))
+
+Zdisp(	movl,	disp0,(%ebx), %esi)
+	movl	disp1(%ebx), %ebp
+Zdisp(	M4_inst,disp0,(%edx), %esi)
+Zdisp(	movl,	%esi, disp0,(%edi))
+	M4_inst	disp1(%edx), %ebp
+	movl	%ebp, disp1(%edi)
+')
+
+	decl	%ecx
+	leal	UNROLL_BYTES(%ebx), %ebx
+	leal	UNROLL_BYTES(%edi), %edi
+	jns	L(top)
+
+
+	mov	PARAM_SIZE, %esi
+	movl	SAVE_EBP, %ebp
+	movl	$0, %eax
+
+	decl	%esi
+	js	L(even)
+
+	movl	(%ebx), %ecx
+	M4_inst	UNROLL_BYTES(%edx), %ecx
+	movl	%ecx, (%edi)
+L(even):
+
+	movl	SAVE_EDI, %edi
+	movl	SAVE_EBX, %ebx
+	setc	%al
+
+	movl	SAVE_ESI, %esi
+	addl	$STACK_SPACE, %esp
+
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/k7/aorsmul_1.asm b/third_party/gmp/mpn/x86/k7/aorsmul_1.asm
new file mode 100644
index 0000000..eec8df6
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k7/aorsmul_1.asm
@@ -0,0 +1,167 @@
+dnl  AMD K7 mpn_addmul_1/mpn_submul_1 -- add or subtract mpn multiple.
+
+dnl  Copyright 1999-2002, 2005, 2008 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C			    cycles/limb
+C P5
+C P6 model 0-8,10-12
+C P6 model 9  (Banias)		 6.5
+C P6 model 13 (Dothan)
+C P4 model 0  (Willamette)
+C P4 model 1  (?)
+C P4 model 2  (Northwood)
+C P4 model 3  (Prescott)
+C P4 model 4  (Nocona)
+C AMD K6
+C AMD K7			 3.75
+C AMD K8
+
+C TODO
+C  * Improve feed-in and wind-down code.  We beat the old code for all n != 1,
+C    but lose by 2x for n == 1.
+
+ifdef(`OPERATION_addmul_1',`
+      define(`ADDSUB',        `add')
+      define(`func',  `mpn_addmul_1')
+')
+ifdef(`OPERATION_submul_1',`
+      define(`ADDSUB',        `sub')
+      define(`func',  `mpn_submul_1')
+')
+
+MULFUNC_PROLOGUE(mpn_addmul_1 mpn_submul_1)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(func)
+	add	$-16, %esp
+	mov	%ebp, (%esp)
+	mov	%ebx, 4(%esp)
+	mov	%esi, 8(%esp)
+	mov	%edi, 12(%esp)
+
+	mov	20(%esp), %edi
+	mov	24(%esp), %esi
+	mov	28(%esp), %eax
+	mov	32(%esp), %ecx
+	mov	%eax, %ebx
+	shr	$2, %eax
+	mov	%eax, 28(%esp)
+	mov	(%esi), %eax
+	and	$3, %ebx
+	jz	L(b0)
+	cmp	$2, %ebx
+	jz	L(b2)
+	jg	L(b3)
+
+L(b1):	lea	-4(%esi), %esi
+	lea	-4(%edi), %edi
+	mul	%ecx
+	mov	%eax, %ebx
+	mov	%edx, %ebp
+	cmpl	$0, 28(%esp)
+	jz	L(cj1)
+	mov	8(%esi), %eax
+	jmp	L(1)
+
+L(b2):	mul	%ecx
+	mov	%eax, %ebp
+	mov	4(%esi), %eax
+	mov	%edx, %ebx
+	cmpl	$0, 28(%esp)
+	jne	L(2)
+	jmp	L(cj2)
+
+L(b3):	lea	-12(%esi), %esi
+	lea	-12(%edi), %edi
+	mul	%ecx
+	mov	%eax, %ebx
+	mov	%edx, %ebp
+	mov	16(%esi), %eax
+	incl	28(%esp)
+	jmp	L(3)
+
+L(b0):	lea	-8(%esi), %esi
+	lea	-8(%edi), %edi
+	mul	%ecx
+	mov	%eax, %ebp
+	mov	12(%esi), %eax
+	mov	%edx, %ebx
+	jmp	L(0)
+
+	ALIGN(16)
+L(top):	lea	16(%edi), %edi
+L(2):	mul	%ecx
+	ADDSUB	%ebp, 0(%edi)
+	mov	$0, %ebp
+	adc	%eax, %ebx
+	mov	8(%esi), %eax
+	adc	%edx, %ebp
+L(1):	mul	%ecx
+	ADDSUB	%ebx, 4(%edi)
+	mov	$0, %ebx
+	adc	%eax, %ebp
+	mov	12(%esi), %eax
+	adc	%edx, %ebx
+L(0):	mul	%ecx
+	ADDSUB	%ebp, 8(%edi)
+	mov	$0, %ebp
+	adc	%eax, %ebx
+	adc	%edx, %ebp
+	mov	16(%esi), %eax
+L(3):	mul	%ecx
+	ADDSUB	%ebx, 12(%edi)
+	adc	%eax, %ebp
+	mov	20(%esi), %eax
+	lea	16(%esi), %esi
+	mov	$0, %ebx
+	adc	%edx, %ebx
+	decl	28(%esp)
+	jnz	L(top)
+
+L(end):	lea	16(%edi), %edi
+L(cj2):	mul	%ecx
+	ADDSUB	%ebp, (%edi)
+	adc	%eax, %ebx
+	adc	$0, %edx
+L(cj1):	ADDSUB	%ebx, 4(%edi)
+	adc	$0, %edx
+	mov	%edx, %eax
+	mov	(%esp), %ebp
+	mov	4(%esp), %ebx
+	mov	8(%esp), %esi
+	mov	12(%esp), %edi
+	add	$16, %esp
+	ret
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86/k7/bdiv_q_1.asm b/third_party/gmp/mpn/x86/k7/bdiv_q_1.asm
new file mode 100644
index 0000000..2af7bb9
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k7/bdiv_q_1.asm
@@ -0,0 +1,245 @@
+dnl  AMD K7 mpn_bdiv_q_1 -- mpn by limb exact division.
+
+dnl  Rearranged from mpn/x86/k7/dive_1.asm by Marco Bodrato.
+
+dnl  Copyright 2001, 2002, 2004, 2007, 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C          cycles/limb
+C Athlon:     11.0
+C Hammer:      9.0
+
+
+C void mpn_divexact_1 (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                      mp_limb_t divisor);
+C
+C The dependent chain is mul+imul+sub for 11 cycles and that speed is
+C achieved with no special effort.  The load and shrld latencies are hidden
+C by out of order execution.
+C
+C It's a touch faster on size==1 to use the mul-by-inverse than divl.
+
+defframe(PARAM_SHIFT,  24)
+defframe(PARAM_INVERSE,20)
+defframe(PARAM_DIVISOR,16)
+defframe(PARAM_SIZE,   12)
+defframe(PARAM_SRC,    8)
+defframe(PARAM_DST,    4)
+
+defframe(SAVE_EBX,     -4)
+defframe(SAVE_ESI,     -8)
+defframe(SAVE_EDI,    -12)
+defframe(SAVE_EBP,    -16)
+defframe(VAR_INVERSE, -20)
+defframe(VAR_DST_END, -24)
+
+deflit(STACK_SPACE, 24)
+
+	TEXT
+
+C mp_limb_t
+C mpn_pi1_bdiv_q_1 (mp_ptr dst, mp_srcptr src, mp_size_t size, mp_limb_t divisor,
+C		    mp_limb_t inverse, int shift)
+	ALIGN(16)
+PROLOGUE(mpn_pi1_bdiv_q_1)
+deflit(`FRAME',0)
+
+	subl	$STACK_SPACE, %esp	deflit(`FRAME',STACK_SPACE)
+	movl	PARAM_SHIFT, %ecx	C shift count
+
+	movl	%ebp, SAVE_EBP
+	movl	PARAM_SIZE, %ebp
+
+	movl	%esi, SAVE_ESI
+	movl	PARAM_SRC, %esi
+
+	movl	%edi, SAVE_EDI
+	movl	PARAM_DST, %edi
+
+	movl	%ebx, SAVE_EBX
+
+	leal	(%esi,%ebp,4), %esi	C src end
+	leal	(%edi,%ebp,4), %edi	C dst end
+	negl	%ebp			C -size
+
+	movl	PARAM_INVERSE, %eax	C inv
+
+L(common):
+	movl	%eax, VAR_INVERSE
+	movl	(%esi,%ebp,4), %eax	C src[0]
+
+	incl	%ebp
+	jz	L(one)
+
+	movl	(%esi,%ebp,4), %edx	C src[1]
+
+	shrdl(	%cl, %edx, %eax)
+
+	movl	%edi, VAR_DST_END
+	xorl	%ebx, %ebx
+	jmp	L(entry)
+
+	ALIGN(8)
+L(top):
+	C eax	q
+	C ebx	carry bit, 0 or 1
+	C ecx	shift
+	C edx
+	C esi	src end
+	C edi	dst end
+	C ebp	counter, limbs, negative
+
+	mull	PARAM_DIVISOR		C carry limb in edx
+
+	movl	-4(%esi,%ebp,4), %eax
+	movl	(%esi,%ebp,4), %edi
+
+	shrdl(	%cl, %edi, %eax)
+
+	subl	%ebx, %eax		C apply carry bit
+	setc	%bl
+	movl	VAR_DST_END, %edi
+
+	subl	%edx, %eax		C apply carry limb
+	adcl	$0, %ebx
+
+L(entry):
+	imull	VAR_INVERSE, %eax
+
+	movl	%eax, -4(%edi,%ebp,4)
+	incl	%ebp
+	jnz	L(top)
+
+
+	mull	PARAM_DIVISOR		C carry limb in edx
+
+	movl	-4(%esi), %eax		C src high limb
+	shrl	%cl, %eax
+	movl	SAVE_ESI, %esi
+
+	subl	%ebx, %eax		C apply carry bit
+	movl	SAVE_EBX, %ebx
+	movl	SAVE_EBP, %ebp
+
+	subl	%edx, %eax		C apply carry limb
+
+	imull	VAR_INVERSE, %eax
+
+	movl	%eax, -4(%edi)
+	movl	SAVE_EDI, %edi
+	addl	$STACK_SPACE, %esp
+
+	ret
+
+L(one):
+	shrl	%cl, %eax
+	movl	SAVE_ESI, %esi
+	movl	SAVE_EBX, %ebx
+
+	imull	VAR_INVERSE, %eax
+
+	movl	SAVE_EBP, %ebp
+
+	movl	%eax, -4(%edi)
+	movl	SAVE_EDI, %edi
+	addl	$STACK_SPACE, %esp
+
+	ret
+EPILOGUE()
+
+C mp_limb_t mpn_bdiv_q_1 (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                           mp_limb_t divisor);
+C
+
+	ALIGN(16)
+PROLOGUE(mpn_bdiv_q_1)
+deflit(`FRAME',0)
+
+	movl	PARAM_DIVISOR, %eax
+	subl	$STACK_SPACE, %esp	deflit(`FRAME',STACK_SPACE)
+	movl	$-1, %ecx		C shift count
+
+	movl	%ebp, SAVE_EBP
+	movl	PARAM_SIZE, %ebp
+
+	movl	%esi, SAVE_ESI
+	movl	%edi, SAVE_EDI
+
+	C If there's usually only one or two trailing zero bits then this
+	C should be faster than bsfl.
+L(strip_twos):
+	incl	%ecx
+	shrl	%eax
+	jnc	L(strip_twos)
+
+	movl	%ebx, SAVE_EBX
+	leal	1(%eax,%eax), %ebx	C d without twos
+	andl	$127, %eax		C d/2, 7 bits
+
+ifdef(`PIC',`
+	LEA(	binvert_limb_table, %edx)
+	movzbl	(%eax,%edx), %eax		C inv 8 bits
+',`
+	movzbl	binvert_limb_table(%eax), %eax	C inv 8 bits
+')
+
+	leal	(%eax,%eax), %edx	C 2*inv
+	movl	%ebx, PARAM_DIVISOR	C d without twos
+
+	imull	%eax, %eax		C inv*inv
+
+	movl	PARAM_SRC, %esi
+	movl	PARAM_DST, %edi
+
+	imull	%ebx, %eax		C inv*inv*d
+
+	subl	%eax, %edx		C inv = 2*inv - inv*inv*d
+	leal	(%edx,%edx), %eax	C 2*inv
+
+	imull	%edx, %edx		C inv*inv
+
+	leal	(%esi,%ebp,4), %esi	C src end
+	leal	(%edi,%ebp,4), %edi	C dst end
+	negl	%ebp			C -size
+
+	imull	%ebx, %edx		C inv*inv*d
+
+	subl	%edx, %eax		C inv = 2*inv - inv*inv*d
+
+	ASSERT(e,`	C expect d*inv == 1 mod 2^GMP_LIMB_BITS
+	pushl	%eax	FRAME_pushl()
+	imull	PARAM_DIVISOR, %eax
+	cmpl	$1, %eax
+	popl	%eax	FRAME_popl()')
+
+	jmp	L(common)
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86/k7/dive_1.asm b/third_party/gmp/mpn/x86/k7/dive_1.asm
new file mode 100644
index 0000000..458bd02
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k7/dive_1.asm
@@ -0,0 +1,208 @@
+dnl  AMD K7 mpn_divexact_1 -- mpn by limb exact division.
+
+dnl  Copyright 2001, 2002, 2004, 2007 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C          cycles/limb
+C Athlon:     11.0
+C Hammer:      9.0
+
+
+C void mpn_divexact_1 (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                      mp_limb_t divisor);
+C
+C The dependent chain is mul+imul+sub for 11 cycles and that speed is
+C achieved with no special effort.  The load and shrld latencies are hidden
+C by out of order execution.
+C
+C It's a touch faster on size==1 to use the mul-by-inverse than divl.
+
+defframe(PARAM_DIVISOR,16)
+defframe(PARAM_SIZE,   12)
+defframe(PARAM_SRC,    8)
+defframe(PARAM_DST,    4)
+
+defframe(SAVE_EBX,     -4)
+defframe(SAVE_ESI,     -8)
+defframe(SAVE_EDI,    -12)
+defframe(SAVE_EBP,    -16)
+defframe(VAR_INVERSE, -20)
+defframe(VAR_DST_END, -24)
+
+deflit(STACK_SPACE, 24)
+
+	TEXT
+
+	ALIGN(16)
+PROLOGUE(mpn_divexact_1)
+deflit(`FRAME',0)
+
+	movl	PARAM_DIVISOR, %eax
+	subl	$STACK_SPACE, %esp	deflit(`FRAME',STACK_SPACE)
+	movl	$-1, %ecx		C shift count
+
+	movl	%ebp, SAVE_EBP
+	movl	PARAM_SIZE, %ebp
+
+	movl	%esi, SAVE_ESI
+	movl	%edi, SAVE_EDI
+
+	C If there's usually only one or two trailing zero bits then this
+	C should be faster than bsfl.
+L(strip_twos):
+	incl	%ecx
+	shrl	%eax
+	jnc	L(strip_twos)
+
+	movl	%ebx, SAVE_EBX
+	leal	1(%eax,%eax), %ebx	C d without twos
+	andl	$127, %eax		C d/2, 7 bits
+
+ifdef(`PIC',`
+	LEA(	binvert_limb_table, %edx)
+	movzbl	(%eax,%edx), %eax		C inv 8 bits
+',`
+	movzbl	binvert_limb_table(%eax), %eax	C inv 8 bits
+')
+
+	leal	(%eax,%eax), %edx	C 2*inv
+	movl	%ebx, PARAM_DIVISOR	C d without twos
+
+	imull	%eax, %eax		C inv*inv
+
+	movl	PARAM_SRC, %esi
+	movl	PARAM_DST, %edi
+
+	imull	%ebx, %eax		C inv*inv*d
+
+	subl	%eax, %edx		C inv = 2*inv - inv*inv*d
+	leal	(%edx,%edx), %eax	C 2*inv
+
+	imull	%edx, %edx		C inv*inv
+
+	leal	(%esi,%ebp,4), %esi	C src end
+	leal	(%edi,%ebp,4), %edi	C dst end
+	negl	%ebp			C -size
+
+	imull	%ebx, %edx		C inv*inv*d
+
+	subl	%edx, %eax		C inv = 2*inv - inv*inv*d
+
+	ASSERT(e,`	C expect d*inv == 1 mod 2^GMP_LIMB_BITS
+	pushl	%eax	FRAME_pushl()
+	imull	PARAM_DIVISOR, %eax
+	cmpl	$1, %eax
+	popl	%eax	FRAME_popl()')
+
+	movl	%eax, VAR_INVERSE
+	movl	(%esi,%ebp,4), %eax	C src[0]
+
+	incl	%ebp
+	jz	L(one)
+
+	movl	(%esi,%ebp,4), %edx	C src[1]
+
+	shrdl(	%cl, %edx, %eax)
+
+	movl	%edi, VAR_DST_END
+	xorl	%ebx, %ebx
+	jmp	L(entry)
+
+	ALIGN(8)
+L(top):
+	C eax	q
+	C ebx	carry bit, 0 or 1
+	C ecx	shift
+	C edx
+	C esi	src end
+	C edi	dst end
+	C ebp	counter, limbs, negative
+
+	mull	PARAM_DIVISOR		C carry limb in edx
+
+	movl	-4(%esi,%ebp,4), %eax
+	movl	(%esi,%ebp,4), %edi
+
+	shrdl(	%cl, %edi, %eax)
+
+	subl	%ebx, %eax		C apply carry bit
+	setc	%bl
+	movl	VAR_DST_END, %edi
+
+	subl	%edx, %eax		C apply carry limb
+	adcl	$0, %ebx
+
+L(entry):
+	imull	VAR_INVERSE, %eax
+
+	movl	%eax, -4(%edi,%ebp,4)
+	incl	%ebp
+	jnz	L(top)
+
+
+	mull	PARAM_DIVISOR		C carry limb in edx
+
+	movl	-4(%esi), %eax		C src high limb
+	shrl	%cl, %eax
+	movl	SAVE_ESI, %esi
+
+	subl	%ebx, %eax		C apply carry bit
+	movl	SAVE_EBX, %ebx
+	movl	SAVE_EBP, %ebp
+
+	subl	%edx, %eax		C apply carry limb
+
+	imull	VAR_INVERSE, %eax
+
+	movl	%eax, -4(%edi)
+	movl	SAVE_EDI, %edi
+	addl	$STACK_SPACE, %esp
+
+	ret
+
+
+L(one):
+	shrl	%cl, %eax
+	movl	SAVE_ESI, %esi
+	movl	SAVE_EBX, %ebx
+
+	imull	VAR_INVERSE, %eax
+
+	movl	SAVE_EBP, %ebp
+	movl	%eax, -4(%edi)
+
+	movl	SAVE_EDI, %edi
+	addl	$STACK_SPACE, %esp
+
+	ret
+
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86/k7/gcd_11.asm b/third_party/gmp/mpn/x86/k7/gcd_11.asm
new file mode 100644
index 0000000..2648dfd
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k7/gcd_11.asm
@@ -0,0 +1,107 @@
+dnl  x86 mpn_gcd_11 optimised for AMD K7.
+
+dnl  Contributed to the GNU project by by Kevin Ryde.  Rehacked by Torbjorn
+dnl  Granlund.
+
+dnl  Copyright 2000-2002, 2005, 2009, 2011, 2012, 2014, 2015 Free Software
+dnl  Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C	     cycles/bit (approx)
+C AMD K7	 5.31
+C AMD K8,K9	 5.33
+C AMD K10	 5.30
+C AMD bd1	 ?
+C AMD bobcat	 7.02
+C Intel P4-2	10.1
+C Intel P4-3/4	10.0
+C Intel P6/13	 5.88
+C Intel core2	 6.26
+C Intel NHM	 6.83
+C Intel SBR	 8.50
+C Intel atom	 8.90
+C VIA nano	 ?
+C Numbers measured with: speed -CD -s16-32 -t16 mpn_gcd_1
+
+
+C ctz_table[n] is the number of trailing zeros on n, or MAXSHIFT if n==0.
+
+deflit(MAXSHIFT, 6)
+deflit(MASK, eval((m4_lshift(1,MAXSHIFT))-1))
+
+DEF_OBJECT(ctz_table,64)
+	.byte	MAXSHIFT
+forloop(i,1,MASK,
+`	.byte	m4_count_trailing_zeros(i)
+')
+END_OBJECT(ctz_table)
+
+
+define(`u0',    `%eax')
+define(`v0',    `%edx')
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_gcd_11)
+	push	%edi
+	push	%esi
+
+	mov	12(%esp), %eax
+	mov	16(%esp), %edx
+
+	LEAL(	ctz_table, %esi)
+	jmp	L(odd)
+
+	ALIGN(16)			C
+L(top):	cmovc(	%ecx, %eax)		C u = |v - u|
+	cmovc(	%edi, %edx)		C v = min(u,v)
+L(mid):	and	$MASK, %ecx		C
+	movzbl	(%esi,%ecx), %ecx	C
+	jz	L(shift_alot)		C
+	shr	%cl, %eax		C
+L(odd):	mov	%eax, %edi		C
+	mov	%edx, %ecx		C
+	sub	%eax, %ecx		C
+	sub	%edx, %eax		C
+	jnz	L(top)			C
+
+L(end):	mov	%edx, %eax
+	pop	%esi
+	pop	%edi
+	ret
+
+L(shift_alot):
+	shr	$MAXSHIFT, %eax
+	mov	%eax, %ecx
+	jmp	L(mid)
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86/k7/gmp-mparam.h b/third_party/gmp/mpn/x86/k7/gmp-mparam.h
new file mode 100644
index 0000000..25b22e2
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k7/gmp-mparam.h
@@ -0,0 +1,262 @@
+/* AMD K7 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+/* 2083 MHz K7 Barton */
+/* FFT tuning limit = 49,770,069 */
+/* Generated by tuneup.c, 2019-11-09, gcc 8.3 */
+
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               3
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          8
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          4
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        24
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD         0  /* never mpn_mod_1s_2p */
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     13
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1N_PI1_METHOD                 1  /* 27.00% faster than 2 */
+#define DIV_QR_1_NORM_THRESHOLD              4
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           26
+
+#define DIV_1_VS_MUL_1_PERCENT             182
+
+#define MUL_TOOM22_THRESHOLD                28
+#define MUL_TOOM33_THRESHOLD                85
+#define MUL_TOOM44_THRESHOLD               154
+#define MUL_TOOM6H_THRESHOLD               208
+#define MUL_TOOM8H_THRESHOLD               309
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      97
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD      99
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD      97
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     102
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     121
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 50
+#define SQR_TOOM3_THRESHOLD                 86
+#define SQR_TOOM4_THRESHOLD                220
+#define SQR_TOOM6_THRESHOLD                270
+#define SQR_TOOM8_THRESHOLD                446
+
+#define MULMID_TOOM42_THRESHOLD             50
+
+#define MULMOD_BNM1_THRESHOLD               18
+#define SQRMOD_BNM1_THRESHOLD               19
+
+#define MUL_FFT_MODF_THRESHOLD             606  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    606, 5}, {     25, 6}, {     13, 5}, {     27, 6}, \
+    {     15, 5}, {     31, 6}, {     28, 7}, {     15, 6}, \
+    {     32, 7}, {     17, 6}, {     35, 7}, {     19, 6}, \
+    {     39, 7}, {     23, 6}, {     47, 7}, {     29, 8}, \
+    {     15, 7}, {     35, 8}, {     19, 7}, {     41, 8}, \
+    {     23, 7}, {     49, 8}, {     31, 7}, {     63, 8}, \
+    {     39, 9}, {     23, 8}, {     55, 9}, {     31, 8}, \
+    {     63, 7}, {    127, 8}, {     71, 9}, {     39, 6}, \
+    {    319, 9}, {     47, 8}, {     99, 6}, {    399, 9}, \
+    {     55,10}, {     31, 9}, {     63, 8}, {    127, 9}, \
+    {     79,10}, {     47, 9}, {     95, 8}, {    191, 4}, \
+    {   3135, 5}, {   1599, 4}, {   3455, 6}, {    959, 8}, \
+    {    247,10}, {     79, 9}, {    167,10}, {     95, 9}, \
+    {    199,10}, {    111,11}, {     63,10}, {    127, 9}, \
+    {    255,10}, {    143, 9}, {    287, 8}, {    575,10}, \
+    {    159, 9}, {    319, 8}, {    639, 7}, {   1279,11}, \
+    {     95,10}, {    191, 9}, {    383, 8}, {    799,10}, \
+    {    207,12}, {     63,11}, {    127,10}, {    255, 9}, \
+    {    511, 8}, {   1023,10}, {    271, 9}, {    543, 8}, \
+    {   1087, 9}, {    575,11}, {    159, 9}, {    639,10}, \
+    {    335, 9}, {    671, 8}, {   1343,10}, {    351, 9}, \
+    {    703,11}, {    191,10}, {    383, 9}, {    799, 8}, \
+    {   1599,11}, {    223,10}, {    447,12}, {    127,11}, \
+    {    255,10}, {    511, 9}, {   1023,10}, {    543, 9}, \
+    {   1087,10}, {    575, 9}, {   1151,10}, {    607, 9}, \
+    {   1215,11}, {    319,10}, {    639, 9}, {   1343,10}, \
+    {    703, 9}, {   1407,12}, {    191,11}, {    383,10}, \
+    {    767, 9}, {   1535,10}, {    799, 9}, {   1599,10}, \
+    {    831, 9}, {   1727, 8}, {   3455,11}, {    447,13}, \
+    {    127,12}, {    255,11}, {    511,10}, {   1023, 9}, \
+    {   2047,11}, {    543,10}, {   1087,11}, {    575,10}, \
+    {   1151, 9}, {   2303,11}, {    607,10}, {   1215,12}, \
+    {    319,11}, {    639,10}, {   1279,11}, {    671,10}, \
+    {   1343,11}, {    703,10}, {   1407,11}, {    735,10}, \
+    {   1471, 9}, {   2943,12}, {    383,11}, {    767,10}, \
+    {   1535,11}, {    799,10}, {   1599,11}, {    831,10}, \
+    {   1663,11}, {    863,10}, {   1727,12}, {    447,11}, \
+    {    895,10}, {   1791,11}, {    959,10}, {   1919,13}, \
+    {    255,12}, {    511,11}, {   1023,10}, {   2111,11}, \
+    {   1087,10}, {   2175,12}, {    575,11}, {   1151,10}, \
+    {   2303,11}, {   1215,10}, {   2431,12}, {    639,11}, \
+    {   1343,12}, {    703,11}, {   1407,10}, {   2815,11}, \
+    {   1471,10}, {   2943,13}, {    383,12}, {    767,11}, \
+    {   1599,12}, {    831,11}, {   1663,10}, {   3327,11}, \
+    {   1727,10}, {   3455,12}, {    895,11}, {   1855,12}, \
+    {    959,11}, {   1919,10}, {   3839,14}, {    255,13}, \
+    {    511,12}, {   1023,11}, {   2111,12}, {   1087,11}, \
+    {   2239,12}, {   1151,11}, {   2303,12}, {   1215,11}, \
+    {   2431,13}, {    639,12}, {   1343,11}, {   2687,12}, \
+    {   1407,11}, {   2815,12}, {   1471,11}, {   2943,13}, \
+    {    767,12}, {   1663,11}, {   3327,12}, {   1727,11}, \
+    {   3455,13}, {    895,12}, {   1919,11}, {   3839,12}, \
+    {   1983,14}, {    511,13}, {   1023,12}, {   2239,13}, \
+    {   1151,12}, {   2495,13}, {   1279,12}, {   2687,13}, \
+    {   1407,12}, {   2943,14}, {    767,13}, {   1535,12}, \
+    {   3135,13}, {   1663,12}, {   3455,13}, {   1791,12}, \
+    {   3583,13}, {   1919,12}, {   3967,15}, {    511,14}, \
+    {   1023,13}, {   2047,12}, {   4095,13}, {   2175,12}, \
+    {   4479,13}, {   2431,12}, {   4863,14}, {   1279,13}, \
+    {   2559,12}, {   5119,13}, {   2943,12}, {   5887,14}, \
+    {   1535,13}, {   3455,14}, {   1791,13}, {   3967,15}, \
+    {   1023,14}, {   2047,13}, {   4479,14}, {   2303,13}, \
+    {   4991,14}, {   2559,13}, {   5119,14}, {   2815,13}, \
+    {   5887,15}, {  32768,16} }
+#define MUL_FFT_TABLE3_SIZE 254
+#define MUL_FFT_THRESHOLD                 7552
+
+#define SQR_FFT_MODF_THRESHOLD             492  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    492, 5}, {     25, 6}, {     13, 5}, {     27, 6}, \
+    {     28, 7}, {     15, 6}, {     32, 7}, {     17, 6}, \
+    {     35, 7}, {     19, 6}, {     39, 7}, {     27, 8}, \
+    {     15, 7}, {     35, 8}, {     19, 7}, {     41, 8}, \
+    {     23, 7}, {     47, 8}, {     27, 9}, {     15, 8}, \
+    {     31, 7}, {     63, 8}, {     39, 9}, {     23, 8}, \
+    {     51, 9}, {     31, 8}, {     67, 9}, {     39, 8}, \
+    {     79, 9}, {     47, 8}, {     95, 9}, {     55,10}, \
+    {     31, 9}, {     79,10}, {     47, 9}, {    103,11}, \
+    {     31,10}, {     63, 9}, {    135, 8}, {    271, 9}, \
+    {    143,10}, {     79, 9}, {    167,10}, {     95, 9}, \
+    {    191, 8}, {    383,10}, {    111,11}, {     63,10}, \
+    {    127, 9}, {    255, 8}, {    511,10}, {    143, 9}, \
+    {    303,10}, {    159, 9}, {    319, 8}, {    639,11}, \
+    {     95,10}, {    191, 9}, {    383, 8}, {    767, 9}, \
+    {    399,10}, {    207,12}, {     63,11}, {    127,10}, \
+    {    255, 9}, {    511,10}, {    271, 9}, {    543, 8}, \
+    {   1087,10}, {    287, 9}, {    575,10}, {    303,11}, \
+    {    159,10}, {    319, 9}, {    639,10}, {    335, 9}, \
+    {    671, 8}, {   1343, 9}, {    703,11}, {    191,10}, \
+    {    383, 9}, {    767, 8}, {   1535,10}, {    399, 9}, \
+    {    799, 8}, {   1599, 9}, {    863,11}, {    223,10}, \
+    {    447,12}, {    127,11}, {    255,10}, {    511, 9}, \
+    {   1087,10}, {    575, 9}, {   1215,10}, {    639, 9}, \
+    {   1279,10}, {    671, 9}, {   1343,11}, {    351,10}, \
+    {    703, 9}, {   1407,10}, {    735, 9}, {   1471,12}, \
+    {    191,11}, {    383,10}, {    767, 9}, {   1535,10}, \
+    {    799, 9}, {   1599,11}, {    415,10}, {    831, 9}, \
+    {   1663,10}, {    863, 9}, {   1727, 8}, {   3455,11}, \
+    {    447,10}, {    895,13}, {    127,12}, {    255,11}, \
+    {    511,10}, {   1023, 9}, {   2047,11}, {    543,10}, \
+    {   1087, 9}, {   2175,11}, {    575,10}, {   1151, 9}, \
+    {   2303,11}, {    607,10}, {   1215, 9}, {   2431,12}, \
+    {    319,11}, {    639,10}, {   1279,11}, {    671,10}, \
+    {   1343,11}, {    703,10}, {   1407, 9}, {   2815,11}, \
+    {    735,10}, {   1471, 9}, {   2943,12}, {    383,11}, \
+    {    767,10}, {   1599,11}, {    831,10}, {   1663, 9}, \
+    {   3327,10}, {   1727,12}, {    447,11}, {    895,10}, \
+    {   1791,11}, {    959,10}, {   1919,13}, {    255,12}, \
+    {    511,11}, {   1023,10}, {   2111,11}, {   1087,10}, \
+    {   2175,12}, {    575,11}, {   1151,10}, {   2303,11}, \
+    {   1215,10}, {   2431,12}, {    639,11}, {   1343,12}, \
+    {    703,11}, {   1407,10}, {   2815,11}, {   1471,10}, \
+    {   2943,13}, {    383,12}, {    767,11}, {   1599,12}, \
+    {    831,11}, {   1663,10}, {   3327,11}, {   1727,10}, \
+    {   3455,12}, {    895,11}, {   1791,12}, {    959,11}, \
+    {   1919,10}, {   3839,14}, {    255,13}, {    511,12}, \
+    {   1023,11}, {   2111,12}, {   1087,11}, {   2239,12}, \
+    {   1151,11}, {   2303,12}, {   1215,11}, {   2431,13}, \
+    {    639,12}, {   1343,11}, {   2687,12}, {   1407,11}, \
+    {   2815,12}, {   1471,11}, {   2943,13}, {    767,12}, \
+    {   1599,11}, {   3199,12}, {   1663,11}, {   3327,12}, \
+    {   1727,11}, {   3455,13}, {    895,12}, {   1791,11}, \
+    {   3583,12}, {   1919,11}, {   3839,12}, {   1983,14}, \
+    {    511,13}, {   1023,12}, {   2239,13}, {   1151,12}, \
+    {   2431,13}, {   1279,12}, {   2687,13}, {   1407,12}, \
+    {   2943,14}, {    767,13}, {   1535,12}, {   3199,13}, \
+    {   1663,12}, {   3455,13}, {   1791,12}, {   3583,13}, \
+    {   1919,12}, {   3967,15}, {    511,14}, {   1023,13}, \
+    {   2047,12}, {   4095,13}, {   2175,12}, {   4351,13}, \
+    {   2431,14}, {   1279,13}, {   2943,12}, {   5887,14}, \
+    {   1535,13}, {   3455,14}, {   1791,13}, {   3967,15}, \
+    {   1023,14}, {   2047,13}, {   4351,14}, {   2303,13}, \
+    {   4991,14}, {   2559,13}, {   5119,14}, {   2815,13}, \
+    {   5887,15}, {  32768,16} }
+#define SQR_FFT_TABLE3_SIZE 258
+#define SQR_FFT_THRESHOLD                 5504
+
+#define MULLO_BASECASE_THRESHOLD             3
+#define MULLO_DC_THRESHOLD                  34
+#define MULLO_MUL_N_THRESHOLD            14281
+#define SQRLO_BASECASE_THRESHOLD             6
+#define SQRLO_DC_THRESHOLD                 137
+#define SQRLO_SQR_THRESHOLD              10821
+
+#define DC_DIV_QR_THRESHOLD                 45
+#define DC_DIVAPPR_Q_THRESHOLD             206
+#define DC_BDIV_QR_THRESHOLD                39
+#define DC_BDIV_Q_THRESHOLD                144
+
+#define INV_MULMOD_BNM1_THRESHOLD           54
+#define INV_NEWTON_THRESHOLD               202
+#define INV_APPR_THRESHOLD                 206
+
+#define BINV_NEWTON_THRESHOLD              224
+#define REDC_1_TO_REDC_N_THRESHOLD          63
+
+#define MU_DIV_QR_THRESHOLD               1442
+#define MU_DIVAPPR_Q_THRESHOLD            1387
+#define MUPI_DIV_QR_THRESHOLD               82
+#define MU_BDIV_QR_THRESHOLD              1308
+#define MU_BDIV_Q_THRESHOLD               1387
+
+#define POWM_SEC_TABLE  1,16,102,428,1221
+
+#define GET_STR_DC_THRESHOLD                14
+#define GET_STR_PRECOMPUTE_THRESHOLD        28
+#define SET_STR_DC_THRESHOLD               254
+#define SET_STR_PRECOMPUTE_THRESHOLD       890
+
+#define FAC_DSC_THRESHOLD                  206
+#define FAC_ODD_THRESHOLD                   29
+
+#define MATRIX22_STRASSEN_THRESHOLD         17
+#define HGCD2_DIV1_METHOD                    3  /* 3.84% faster than 4 */
+#define HGCD_THRESHOLD                     123
+#define HGCD_APPR_THRESHOLD                151
+#define HGCD_REDUCE_THRESHOLD             3389
+#define GCD_DC_THRESHOLD                   435
+#define GCDEXT_DC_THRESHOLD                318
+#define JACOBI_BASE_METHOD                   4  /* 8.04% faster than 3 */
+
+/* Tuneup completed successfully, took 175382 seconds */
diff --git a/third_party/gmp/mpn/x86/k7/invert_limb.asm b/third_party/gmp/mpn/x86/k7/invert_limb.asm
new file mode 100644
index 0000000..31a867e
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k7/invert_limb.asm
@@ -0,0 +1,194 @@
+dnl  x86 mpn_invert_limb
+
+dnl  Contributed to the GNU project by Niels Möller
+
+dnl  Copyright 2009, 2011, 2015 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C			    cycles (approx)	div
+C P5				 ?
+C P6 model 0-8,10-12		 ?
+C P6 model 9  (Banias)		 ?
+C P6 model 13 (Dothan)		 ?
+C P4 model 0  (Willamette)	 ?
+C P4 model 1  (?)		 ?
+C P4 model 2  (Northwood)	 ?
+C P4 model 3  (Prescott)	 ?
+C P4 model 4  (Nocona)		 ?
+C AMD K6			 ?
+C AMD K7			41		53
+C AMD K8			 ?
+
+C TODO
+C  * These c/l numbers are for a non-PIC build.  Consider falling back to using
+C    the 'div' instruction for PIC builds.
+C  * Perhaps use this file--or at least the algorithm--for more machines than k7.
+
+C Register usage:
+C   Input D in %edi
+C   Current approximation is in %eax and/or %ecx
+C   %ebx and %edx are temporaries
+C   %esi and %ebp are unused
+
+defframe(PARAM_DIVISOR,4)
+
+ASM_START()
+
+C Make approx_tab global to work around Apple relocation bug.
+ifdef(`DARWIN',`
+	deflit(`approx_tab', MPN(invert_limb_tab))
+	GLOBL	approx_tab')
+
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_invert_limb)
+deflit(`FRAME', 0)
+	mov	PARAM_DIVISOR, %eax
+	C Avoid push/pop on k7.
+	sub	$8, %esp	FRAME_subl_esp(8)
+	mov	%ebx, (%esp)
+	mov	%edi, 4(%esp)
+
+	mov	%eax, %edi
+	shr	$22, %eax
+ifdef(`PIC',`
+	LEAL(	approx_tab, %ebx)
+	movzwl	-1024(%ebx, %eax, 2), %eax
+',`
+	movzwl	-1024+approx_tab(%eax, %eax), %eax	C %eax = v0
+')
+
+	C v1 = (v0 << 4) - ((v0*v0*d_21) >> 32) - 1
+	mov	%eax, %ecx
+	imul	%eax, %eax
+	mov	%edi, %ebx
+	shr	$11, %ebx
+	inc	%ebx
+	mul	%ebx
+	mov	%edi, %ebx				C Prepare
+	shr	%ebx
+	sbb	%eax, %eax
+	sub	%eax, %ebx				C %ebx = d_31, %eax = mask
+	shl	$4, %ecx
+	dec	%ecx
+	sub	%edx, %ecx				C %ecx = v1
+
+	C v_2 = (v1 << 15) + ((v1 *(2^48 - v1 * d31 + (v1 >> 1) & mask)) >> 33)
+	imul	%ecx, %ebx
+	and	%ecx, %eax
+	shr	%eax
+	sub	%ebx, %eax
+	mul	%ecx
+	mov	%edi, %eax				C Prepare for next mul
+	shl	$15, %ecx
+	shr	%edx
+	add	%edx, %ecx				C %ecx = v2
+
+	mul	%ecx
+	add	%edi, %eax
+	mov	%ecx, %eax
+	adc	%edi, %edx
+	sub	%edx, %eax				C %eax = v3
+
+	mov	(%esp), %ebx
+	mov	4(%esp), %edi
+	add	$8, %esp
+
+	ret
+
+EPILOGUE()
+
+DEF_OBJECT(approx_tab,2)
+	.value	0x7fe1,0x7fa1,0x7f61,0x7f22,0x7ee3,0x7ea4,0x7e65,0x7e27
+	.value	0x7de9,0x7dab,0x7d6d,0x7d30,0x7cf3,0x7cb6,0x7c79,0x7c3d
+	.value	0x7c00,0x7bc4,0x7b89,0x7b4d,0x7b12,0x7ad7,0x7a9c,0x7a61
+	.value	0x7a27,0x79ec,0x79b2,0x7979,0x793f,0x7906,0x78cc,0x7894
+	.value	0x785b,0x7822,0x77ea,0x77b2,0x777a,0x7742,0x770b,0x76d3
+	.value	0x769c,0x7665,0x762f,0x75f8,0x75c2,0x758c,0x7556,0x7520
+	.value	0x74ea,0x74b5,0x7480,0x744b,0x7416,0x73e2,0x73ad,0x7379
+	.value	0x7345,0x7311,0x72dd,0x72aa,0x7277,0x7243,0x7210,0x71de
+	.value	0x71ab,0x7179,0x7146,0x7114,0x70e2,0x70b1,0x707f,0x704e
+	.value	0x701c,0x6feb,0x6fba,0x6f8a,0x6f59,0x6f29,0x6ef9,0x6ec8
+	.value	0x6e99,0x6e69,0x6e39,0x6e0a,0x6ddb,0x6dab,0x6d7d,0x6d4e
+	.value	0x6d1f,0x6cf1,0x6cc2,0x6c94,0x6c66,0x6c38,0x6c0a,0x6bdd
+	.value	0x6bb0,0x6b82,0x6b55,0x6b28,0x6afb,0x6acf,0x6aa2,0x6a76
+	.value	0x6a49,0x6a1d,0x69f1,0x69c6,0x699a,0x696e,0x6943,0x6918
+	.value	0x68ed,0x68c2,0x6897,0x686c,0x6842,0x6817,0x67ed,0x67c3
+	.value	0x6799,0x676f,0x6745,0x671b,0x66f2,0x66c8,0x669f,0x6676
+	.value	0x664d,0x6624,0x65fc,0x65d3,0x65aa,0x6582,0x655a,0x6532
+	.value	0x650a,0x64e2,0x64ba,0x6493,0x646b,0x6444,0x641c,0x63f5
+	.value	0x63ce,0x63a7,0x6381,0x635a,0x6333,0x630d,0x62e7,0x62c1
+	.value	0x629a,0x6275,0x624f,0x6229,0x6203,0x61de,0x61b8,0x6193
+	.value	0x616e,0x6149,0x6124,0x60ff,0x60da,0x60b6,0x6091,0x606d
+	.value	0x6049,0x6024,0x6000,0x5fdc,0x5fb8,0x5f95,0x5f71,0x5f4d
+	.value	0x5f2a,0x5f07,0x5ee3,0x5ec0,0x5e9d,0x5e7a,0x5e57,0x5e35
+	.value	0x5e12,0x5def,0x5dcd,0x5dab,0x5d88,0x5d66,0x5d44,0x5d22
+	.value	0x5d00,0x5cde,0x5cbd,0x5c9b,0x5c7a,0x5c58,0x5c37,0x5c16
+	.value	0x5bf5,0x5bd4,0x5bb3,0x5b92,0x5b71,0x5b51,0x5b30,0x5b10
+	.value	0x5aef,0x5acf,0x5aaf,0x5a8f,0x5a6f,0x5a4f,0x5a2f,0x5a0f
+	.value	0x59ef,0x59d0,0x59b0,0x5991,0x5972,0x5952,0x5933,0x5914
+	.value	0x58f5,0x58d6,0x58b7,0x5899,0x587a,0x585b,0x583d,0x581f
+	.value	0x5800,0x57e2,0x57c4,0x57a6,0x5788,0x576a,0x574c,0x572e
+	.value	0x5711,0x56f3,0x56d5,0x56b8,0x569b,0x567d,0x5660,0x5643
+	.value	0x5626,0x5609,0x55ec,0x55cf,0x55b2,0x5596,0x5579,0x555d
+	.value	0x5540,0x5524,0x5507,0x54eb,0x54cf,0x54b3,0x5497,0x547b
+	.value	0x545f,0x5443,0x5428,0x540c,0x53f0,0x53d5,0x53b9,0x539e
+	.value	0x5383,0x5368,0x534c,0x5331,0x5316,0x52fb,0x52e0,0x52c6
+	.value	0x52ab,0x5290,0x5276,0x525b,0x5240,0x5226,0x520c,0x51f1
+	.value	0x51d7,0x51bd,0x51a3,0x5189,0x516f,0x5155,0x513b,0x5121
+	.value	0x5108,0x50ee,0x50d5,0x50bb,0x50a2,0x5088,0x506f,0x5056
+	.value	0x503c,0x5023,0x500a,0x4ff1,0x4fd8,0x4fbf,0x4fa6,0x4f8e
+	.value	0x4f75,0x4f5c,0x4f44,0x4f2b,0x4f13,0x4efa,0x4ee2,0x4eca
+	.value	0x4eb1,0x4e99,0x4e81,0x4e69,0x4e51,0x4e39,0x4e21,0x4e09
+	.value	0x4df1,0x4dda,0x4dc2,0x4daa,0x4d93,0x4d7b,0x4d64,0x4d4d
+	.value	0x4d35,0x4d1e,0x4d07,0x4cf0,0x4cd8,0x4cc1,0x4caa,0x4c93
+	.value	0x4c7d,0x4c66,0x4c4f,0x4c38,0x4c21,0x4c0b,0x4bf4,0x4bde
+	.value	0x4bc7,0x4bb1,0x4b9a,0x4b84,0x4b6e,0x4b58,0x4b41,0x4b2b
+	.value	0x4b15,0x4aff,0x4ae9,0x4ad3,0x4abd,0x4aa8,0x4a92,0x4a7c
+	.value	0x4a66,0x4a51,0x4a3b,0x4a26,0x4a10,0x49fb,0x49e5,0x49d0
+	.value	0x49bb,0x49a6,0x4990,0x497b,0x4966,0x4951,0x493c,0x4927
+	.value	0x4912,0x48fe,0x48e9,0x48d4,0x48bf,0x48ab,0x4896,0x4881
+	.value	0x486d,0x4858,0x4844,0x482f,0x481b,0x4807,0x47f3,0x47de
+	.value	0x47ca,0x47b6,0x47a2,0x478e,0x477a,0x4766,0x4752,0x473e
+	.value	0x472a,0x4717,0x4703,0x46ef,0x46db,0x46c8,0x46b4,0x46a1
+	.value	0x468d,0x467a,0x4666,0x4653,0x4640,0x462c,0x4619,0x4606
+	.value	0x45f3,0x45e0,0x45cd,0x45ba,0x45a7,0x4594,0x4581,0x456e
+	.value	0x455b,0x4548,0x4536,0x4523,0x4510,0x44fe,0x44eb,0x44d8
+	.value	0x44c6,0x44b3,0x44a1,0x448f,0x447c,0x446a,0x4458,0x4445
+	.value	0x4433,0x4421,0x440f,0x43fd,0x43eb,0x43d9,0x43c7,0x43b5
+	.value	0x43a3,0x4391,0x437f,0x436d,0x435c,0x434a,0x4338,0x4327
+	.value	0x4315,0x4303,0x42f2,0x42e0,0x42cf,0x42bd,0x42ac,0x429b
+	.value	0x4289,0x4278,0x4267,0x4256,0x4244,0x4233,0x4222,0x4211
+	.value	0x4200,0x41ef,0x41de,0x41cd,0x41bc,0x41ab,0x419a,0x418a
+	.value	0x4179,0x4168,0x4157,0x4147,0x4136,0x4125,0x4115,0x4104
+	.value	0x40f4,0x40e3,0x40d3,0x40c2,0x40b2,0x40a2,0x4091,0x4081
+	.value	0x4071,0x4061,0x4050,0x4040,0x4030,0x4020,0x4010,0x4000
+END_OBJECT(approx_tab)
+ASM_END()
diff --git a/third_party/gmp/mpn/x86/k7/mmx/com.asm b/third_party/gmp/mpn/x86/k7/mmx/com.asm
new file mode 100644
index 0000000..a258c22
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k7/mmx/com.asm
@@ -0,0 +1,125 @@
+dnl  AMD Athlon mpn_com -- mpn bitwise one's complement.
+
+dnl  Copyright 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C K7: 1.0 cycles/limb
+
+
+C void mpn_com (mp_ptr dst, mp_srcptr src, mp_size_t size);
+C
+C The loop form below is necessary for the claimed speed.  It needs to be
+C aligned to a 16 byte boundary and only 16 bytes long.  Maybe that's so it
+C fits in a BTB entry.  The adjustments to %eax and %edx avoid offsets on
+C the movq's and achieve the necessary size.
+C
+C If both src and dst are 4mod8, the loop runs at 1.5 c/l.  So long as one
+C of the two is 0mod8, it runs at 1.0 c/l.  On that basis dst is checked
+C (offset by the size, as per the loop addressing) and one high limb
+C processed separately to get alignment.
+C
+C The padding for the nails case is unattractive, but shouldn't cost any
+C cycles.  Explicit .byte's guarantee the desired instructions, at a point
+C where we're probably stalled waiting for loads anyway.
+C
+C Enhancements:
+C
+C The combination load/pxor/store might be able to be unrolled to approach
+C 0.5 c/l if desired.
+
+defframe(PARAM_SIZE,12)
+defframe(PARAM_SRC, 8)
+defframe(PARAM_DST, 4)
+
+	TEXT
+	ALIGN(16)
+
+PROLOGUE(mpn_com)
+deflit(`FRAME',0)
+
+	movl	PARAM_DST, %edx
+	movl	PARAM_SIZE, %ecx
+	pcmpeqd	%mm7, %mm7
+
+	leal	(%edx,%ecx,4), %eax
+	andl	$4, %eax
+ifelse(GMP_NAIL_BITS,0,,
+`	psrld	$GMP_NAIL_BITS, %mm7')		C GMP_NUMB_MASK
+
+	movl	PARAM_SRC, %eax
+	movd	-4(%eax,%ecx,4), %mm0		C src high limb
+
+ifelse(GMP_NAIL_BITS,0,,
+`	C padding for alignment below
+	.byte	0x8d, 0xb6, 0x00, 0x00, 0x00, 0x00	C lea 0(%esi),%esi
+	.byte	0x8d, 0xbf, 0x00, 0x00, 0x00, 0x00	C lea 0(%edi),%edi
+')
+
+	jz	L(aligned)
+
+	pxor	%mm7, %mm0
+	movd	%mm0, -4(%edx,%ecx,4)		C dst high limb
+	decl	%ecx
+	jz	L(done)
+L(aligned):
+
+	addl	$4, %eax
+	addl	$4, %edx
+	decl	%ecx
+	jz	L(one)
+
+	C offset 0x30 for no nails, or 0x40 for nails
+	ALIGN(16)
+L(top):
+	C eax	src
+	C ebx
+	C ecx	counter
+	C edx	dst
+
+	subl	$2, %ecx
+	movq	(%eax,%ecx,4), %mm0
+	pxor	%mm7, %mm0
+	movq	%mm0, (%edx,%ecx,4)
+	jg	L(top)
+
+	jnz	L(done)				C if size even
+
+L(one):
+	movd	-4(%eax), %mm0			C src low limb
+	pxor	%mm7, %mm0
+	movd	%mm0, -4(%edx)			C dst low limb
+
+L(done):
+	emms
+
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/k7/mmx/copyd.asm b/third_party/gmp/mpn/x86/k7/mmx/copyd.asm
new file mode 100644
index 0000000..59ece40
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k7/mmx/copyd.asm
@@ -0,0 +1,144 @@
+dnl  AMD K7 mpn_copyd -- copy limb vector, decrementing.
+
+dnl  Copyright 1999, 2000, 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C    alignment dst/src, A=0mod8 N=4mod8
+C       A/A   A/N   N/A   N/N
+C K7    0.75  1.0   1.0   0.75
+
+
+C void mpn_copyd (mp_ptr dst, mp_srcptr src, mp_size_t size);
+C
+C The various comments in mpn/x86/k7/copyi.asm apply here too.
+
+defframe(PARAM_SIZE,12)
+defframe(PARAM_SRC, 8)
+defframe(PARAM_DST, 4)
+deflit(`FRAME',0)
+
+dnl  parameter space reused
+define(SAVE_EBX,`PARAM_SIZE')
+define(SAVE_ESI,`PARAM_SRC')
+
+dnl  minimum 5 since the unrolled code can't handle less than 5
+deflit(UNROLL_THRESHOLD, 5)
+
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_copyd)
+
+	movl	PARAM_SIZE, %ecx
+	movl	%ebx, SAVE_EBX
+
+	movl	PARAM_SRC, %eax
+	movl	PARAM_DST, %edx
+
+	cmpl	$UNROLL_THRESHOLD, %ecx
+	jae	L(unroll)
+
+	orl	%ecx, %ecx
+	jz	L(simple_done)
+
+L(simple):
+	C eax	src
+	C ebx	scratch
+	C ecx	counter
+	C edx	dst
+	C
+	C this loop is 2 cycles/limb
+
+	movl	-4(%eax,%ecx,4), %ebx
+	movl	%ebx, -4(%edx,%ecx,4)
+	decl	%ecx
+	jnz	L(simple)
+
+L(simple_done):
+	movl	SAVE_EBX, %ebx
+	ret
+
+
+L(unroll):
+	movl	%esi, SAVE_ESI
+	leal	(%eax,%ecx,4), %ebx
+	leal	(%edx,%ecx,4), %esi
+
+	andl	%esi, %ebx
+	movl	SAVE_ESI, %esi
+	subl	$4, %ecx		C size-4
+
+	testl	$4, %ebx   C testl to pad code closer to 16 bytes for L(top)
+	jz	L(aligned)
+
+	C both src and dst unaligned, process one limb to align them
+	movl	12(%eax,%ecx,4), %ebx
+	movl	%ebx, 12(%edx,%ecx,4)
+	decl	%ecx
+L(aligned):
+
+
+	ALIGN(16)
+L(top):
+	C eax	src
+	C ebx
+	C ecx	counter, limbs
+	C edx	dst
+
+	movq	8(%eax,%ecx,4), %mm0
+	movq	(%eax,%ecx,4), %mm1
+	subl	$4, %ecx
+	movq	%mm0, 16+8(%edx,%ecx,4)
+	movq	%mm1, 16(%edx,%ecx,4)
+	jns	L(top)
+
+
+	C now %ecx is -4 to -1 representing respectively 0 to 3 limbs remaining
+
+	testb	$2, %cl
+	jz	L(finish_not_two)
+
+	movq	8(%eax,%ecx,4), %mm0
+	movq	%mm0, 8(%edx,%ecx,4)
+L(finish_not_two):
+
+	testb	$1, %cl
+	jz	L(done)
+
+	movl	(%eax), %ebx
+	movl	%ebx, (%edx)
+
+L(done):
+	movl	SAVE_EBX, %ebx
+	emms
+	ret
+
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/k7/mmx/copyi.asm b/third_party/gmp/mpn/x86/k7/mmx/copyi.asm
new file mode 100644
index 0000000..9a28f92
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k7/mmx/copyi.asm
@@ -0,0 +1,157 @@
+dnl  AMD K7 mpn_copyi -- copy limb vector, incrementing.
+
+dnl  Copyright 1999, 2000, 2002, 2003 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C    alignment dst/src, A=0mod8 N=4mod8
+C       A/A   A/N   N/A   N/N
+C K7    0.75  1.0   1.0   0.75
+
+
+C void mpn_copyi (mp_ptr dst, mp_srcptr src, mp_size_t size);
+C
+C Copy src,size to dst,size.
+C
+C This code at 0.75 or 1.0 c/l is always faster than a plain rep movsl at
+C 1.33 c/l.
+C
+C The K7 can do a 64-bit load and 64-bit store in one cycle (optimization
+C guile 22007 appendix B), so 0.5 c/l should be possible, however nothing
+C under 0.7 c/l is known.  Apparently only two 32-bit stores can be done in
+C one cycle, so perhaps some scheduling is needed to ensure it's a
+C load+store in each cycle, not store+store.
+C
+C If both source and destination are unaligned then one limb is processed at
+C the start to make them aligned and so get 0.75 c/l, whereas if they'd been
+C used unaligned it would be 1.5 c/l.
+
+defframe(PARAM_SIZE,12)
+defframe(PARAM_SRC, 8)
+defframe(PARAM_DST, 4)
+
+dnl  parameter space reused
+define(SAVE_EBX,`PARAM_SIZE')
+
+dnl  minimum 5 since the unrolled code can't handle less than 5
+deflit(UNROLL_THRESHOLD, 5)
+
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_copyi)
+deflit(`FRAME',0)
+
+	movl	PARAM_SIZE, %ecx
+	movl	%ebx, SAVE_EBX
+
+	movl	PARAM_SRC, %eax
+	movl	PARAM_DST, %edx
+
+	cmpl	$UNROLL_THRESHOLD, %ecx
+	jae	L(unroll)
+
+	orl	%ecx, %ecx
+	jz	L(simple_done)
+
+L(simple):
+	C eax	src, incrementing
+	C ebx	scratch
+	C ecx	counter
+	C edx	dst, incrementing
+	C
+	C this loop is 2 cycles/limb
+
+	movl	(%eax), %ebx
+	movl	%ebx, (%edx)
+	decl	%ecx
+	leal	4(%eax), %eax
+	leal	4(%edx), %edx
+	jnz	L(simple)
+
+L(simple_done):
+	movl	SAVE_EBX, %ebx
+	ret
+
+
+L(unroll):
+	movl	%eax, %ebx
+	leal	-12(%eax,%ecx,4), %eax	C src end - 12
+	subl	$3, %ecx		C size-3
+
+	andl	%edx, %ebx
+	leal	(%edx,%ecx,4), %edx	C dst end - 12
+	negl	%ecx
+
+	testl	$4, %ebx   C testl to pad code closer to 16 bytes for L(top)
+	jz	L(aligned)
+
+	C both src and dst unaligned, process one limb to align them
+	movl	(%eax,%ecx,4), %ebx
+	movl	%ebx, (%edx,%ecx,4)
+	incl	%ecx
+L(aligned):
+
+
+	ALIGN(16)
+L(top):
+	C eax	src end - 12
+	C ebx
+	C ecx	counter, negative, limbs
+	C edx	dst end - 12
+
+	movq	(%eax,%ecx,4), %mm0
+	movq	8(%eax,%ecx,4), %mm1
+	addl	$4, %ecx
+	movq	%mm0, -16(%edx,%ecx,4)
+	movq	%mm1, -16+8(%edx,%ecx,4)
+	ja	L(top)		C jump no carry and not zero
+
+
+	C now %ecx is 0 to 3 representing respectively 3 to 0 limbs remaining
+
+	testb	$2, %cl
+	jnz	L(finish_not_two)
+
+	movq	(%eax,%ecx,4), %mm0
+	movq	%mm0, (%edx,%ecx,4)
+L(finish_not_two):
+
+	testb	$1, %cl
+	jnz	L(done)
+
+	movl	8(%eax), %ebx
+	movl	%ebx, 8(%edx)
+
+L(done):
+	movl	SAVE_EBX, %ebx
+	emms
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/k7/mmx/divrem_1.asm b/third_party/gmp/mpn/x86/k7/mmx/divrem_1.asm
new file mode 100644
index 0000000..cf34328
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k7/mmx/divrem_1.asm
@@ -0,0 +1,832 @@
+dnl  AMD K7 mpn_divrem_1, mpn_divrem_1c, mpn_preinv_divrem_1 -- mpn by limb
+dnl  division.
+
+dnl  Copyright 1999-2002, 2004 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C K7: 17.0 cycles/limb integer part, 15.0 cycles/limb fraction part.
+
+
+C mp_limb_t mpn_divrem_1 (mp_ptr dst, mp_size_t xsize,
+C                         mp_srcptr src, mp_size_t size,
+C                         mp_limb_t divisor);
+C mp_limb_t mpn_divrem_1c (mp_ptr dst, mp_size_t xsize,
+C                          mp_srcptr src, mp_size_t size,
+C                          mp_limb_t divisor, mp_limb_t carry);
+C mp_limb_t mpn_preinv_divrem_1 (mp_ptr dst, mp_size_t xsize,
+C                                mp_srcptr src, mp_size_t size,
+C                                mp_limb_t divisor, mp_limb_t inverse,
+C                                unsigned shift);
+C
+C Algorithm:
+C
+C The method and nomenclature follow part 8 of "Division by Invariant
+C Integers using Multiplication" by Granlund and Montgomery, reference in
+C gmp.texi.
+C
+C The "and"s shown in the paper are done here with "cmov"s.  "m" is written
+C for m', and "d" for d_norm, which won't cause any confusion since it's
+C only the normalized divisor that's of any use in the code.  "b" is written
+C for 2^N, the size of a limb, N being 32 here.
+C
+C The step "sdword dr = n - 2^N*d + (2^N-1-q1) * d" is instead done as
+C "n-(q1+1)*d"; this rearrangement gives the same two-limb answer.  If
+C q1==0xFFFFFFFF, then q1+1 would overflow.  We branch to a special case
+C "q1_ff" if this occurs.  Since the true quotient is either q1 or q1+1 then
+C if q1==0xFFFFFFFF that must be the right value.
+C
+C For the last and second last steps q1==0xFFFFFFFF is instead handled by an
+C sbbl to go back to 0xFFFFFFFF if an overflow occurs when adding 1.  This
+C then goes through as normal, and finding no addback required.  sbbl costs
+C an extra cycle over what the main loop code does, but it keeps code size
+C and complexity down.
+C
+C Notes:
+C
+C mpn_divrem_1 and mpn_preinv_divrem_1 avoid one division if the src high
+C limb is less than the divisor.  mpn_divrem_1c doesn't check for a zero
+C carry, since in normal circumstances that will be a very rare event.
+C
+C The test for skipping a division is branch free (once size>=1 is tested).
+C The store to the destination high limb is 0 when a divide is skipped, or
+C if it's not skipped then a copy of the src high limb is used.  The latter
+C is in case src==dst.
+C
+C There's a small bias towards expecting xsize==0, by having code for
+C xsize==0 in a straight line and xsize!=0 under forward jumps.
+C
+C Alternatives:
+C
+C If the divisor is normalized (high bit set) then a division step can
+C always be skipped, since the high destination limb is always 0 or 1 in
+C that case.  It doesn't seem worth checking for this though, since it
+C probably occurs infrequently, in particular note that big_base for a
+C decimal mpn_get_str is not normalized in a 32-bit limb.
+
+
+dnl  MUL_THRESHOLD is the value of xsize+size at which the multiply by
+dnl  inverse method is used, rather than plain "divl"s.  Minimum value 1.
+dnl
+dnl  The inverse takes about 50 cycles to calculate, but after that the
+dnl  multiply is 17 c/l versus division at 42 c/l.
+dnl
+dnl  At 3 limbs the mul is a touch faster than div on the integer part, and
+dnl  even more so on the fractional part.
+
+deflit(MUL_THRESHOLD, 3)
+
+
+defframe(PARAM_PREINV_SHIFT,   28)  dnl mpn_preinv_divrem_1
+defframe(PARAM_PREINV_INVERSE, 24)  dnl mpn_preinv_divrem_1
+defframe(PARAM_CARRY,  24)          dnl mpn_divrem_1c
+defframe(PARAM_DIVISOR,20)
+defframe(PARAM_SIZE,   16)
+defframe(PARAM_SRC,    12)
+defframe(PARAM_XSIZE,  8)
+defframe(PARAM_DST,    4)
+
+defframe(SAVE_EBX,    -4)
+defframe(SAVE_ESI,    -8)
+defframe(SAVE_EDI,    -12)
+defframe(SAVE_EBP,    -16)
+
+defframe(VAR_NORM,    -20)
+defframe(VAR_INVERSE, -24)
+defframe(VAR_SRC,     -28)
+defframe(VAR_DST,     -32)
+defframe(VAR_DST_STOP,-36)
+
+deflit(STACK_SPACE, 36)
+
+	TEXT
+	ALIGN(32)
+
+PROLOGUE(mpn_preinv_divrem_1)
+deflit(`FRAME',0)
+	movl	PARAM_XSIZE, %ecx
+	movl	PARAM_DST, %edx
+	subl	$STACK_SPACE, %esp	FRAME_subl_esp(STACK_SPACE)
+
+	movl	%esi, SAVE_ESI
+	movl	PARAM_SRC, %esi
+
+	movl	%ebx, SAVE_EBX
+	movl	PARAM_SIZE, %ebx
+
+	leal	8(%edx,%ecx,4), %edx	C &dst[xsize+2]
+	movl	%ebp, SAVE_EBP
+	movl	PARAM_DIVISOR, %ebp
+
+	movl	%edx, VAR_DST_STOP	C &dst[xsize+2]
+	movl	%edi, SAVE_EDI
+	xorl	%edi, %edi		C carry
+
+	movl	-4(%esi,%ebx,4), %eax	C src high limb
+	xor	%ecx, %ecx
+
+	C
+
+	C
+
+	cmpl	%ebp, %eax		C high cmp divisor
+
+	cmovc(	%eax, %edi)		C high is carry if high<divisor
+	cmovnc(	%eax, %ecx)		C 0 if skip div, src high if not
+					C (the latter in case src==dst)
+
+	movl	%ecx, -12(%edx,%ebx,4)	C dst high limb
+	sbbl	$0, %ebx		C skip one division if high<divisor
+	movl	PARAM_PREINV_SHIFT, %ecx
+
+	leal	-8(%edx,%ebx,4), %edx	C &dst[xsize+size]
+	movl	$32, %eax
+
+	movl	%edx, VAR_DST		C &dst[xsize+size]
+
+	shll	%cl, %ebp		C d normalized
+	subl	%ecx, %eax
+	movl	%ecx, VAR_NORM
+
+	movd	%eax, %mm7		C rshift
+	movl	PARAM_PREINV_INVERSE, %eax
+	jmp	L(start_preinv)
+
+EPILOGUE()
+
+
+	ALIGN(16)
+
+PROLOGUE(mpn_divrem_1c)
+deflit(`FRAME',0)
+	movl	PARAM_CARRY, %edx
+	movl	PARAM_SIZE, %ecx
+	subl	$STACK_SPACE, %esp
+deflit(`FRAME',STACK_SPACE)
+
+	movl	%ebx, SAVE_EBX
+	movl	PARAM_XSIZE, %ebx
+
+	movl	%edi, SAVE_EDI
+	movl	PARAM_DST, %edi
+
+	movl	%ebp, SAVE_EBP
+	movl	PARAM_DIVISOR, %ebp
+
+	movl	%esi, SAVE_ESI
+	movl	PARAM_SRC, %esi
+
+	leal	-4(%edi,%ebx,4), %edi	C &dst[xsize-1]
+	jmp	L(start_1c)
+
+EPILOGUE()
+
+
+	C offset 0xa1, close enough to aligned
+PROLOGUE(mpn_divrem_1)
+deflit(`FRAME',0)
+
+	movl	PARAM_SIZE, %ecx
+	movl	$0, %edx		C initial carry (if can't skip a div)
+	subl	$STACK_SPACE, %esp
+deflit(`FRAME',STACK_SPACE)
+
+	movl	%esi, SAVE_ESI
+	movl	PARAM_SRC, %esi
+
+	movl	%ebx, SAVE_EBX
+	movl	PARAM_XSIZE, %ebx
+
+	movl	%ebp, SAVE_EBP
+	movl	PARAM_DIVISOR, %ebp
+	orl	%ecx, %ecx		C size
+
+	movl	%edi, SAVE_EDI
+	movl	PARAM_DST, %edi
+	leal	-4(%edi,%ebx,4), %edi	C &dst[xsize-1]
+
+	jz	L(no_skip_div)		C if size==0
+	movl	-4(%esi,%ecx,4), %eax	C src high limb
+	xorl	%esi, %esi
+
+	cmpl	%ebp, %eax		C high cmp divisor
+
+	cmovc(	%eax, %edx)		C high is carry if high<divisor
+	cmovnc(	%eax, %esi)		C 0 if skip div, src high if not
+
+	movl	%esi, (%edi,%ecx,4)	C dst high limb
+	sbbl	$0, %ecx		C size-1 if high<divisor
+	movl	PARAM_SRC, %esi		C reload
+L(no_skip_div):
+
+
+L(start_1c):
+	C eax
+	C ebx	xsize
+	C ecx	size
+	C edx	carry
+	C esi	src
+	C edi	&dst[xsize-1]
+	C ebp	divisor
+
+	leal	(%ebx,%ecx), %eax	C size+xsize
+	cmpl	$MUL_THRESHOLD, %eax
+	jae	L(mul_by_inverse)
+
+
+C With MUL_THRESHOLD set to 3, the simple loops here only do 0 to 2 limbs.
+C It'd be possible to write them out without the looping, but no speedup
+C would be expected.
+C
+C Using PARAM_DIVISOR instead of %ebp measures 1 cycle/loop faster on the
+C integer part, but curiously not on the fractional part, where %ebp is a
+C (fixed) couple of cycles faster.
+
+	orl	%ecx, %ecx
+	jz	L(divide_no_integer)
+
+L(divide_integer):
+	C eax	scratch (quotient)
+	C ebx	xsize
+	C ecx	counter
+	C edx	scratch (remainder)
+	C esi	src
+	C edi	&dst[xsize-1]
+	C ebp	divisor
+
+	movl	-4(%esi,%ecx,4), %eax
+
+	divl	PARAM_DIVISOR
+
+	movl	%eax, (%edi,%ecx,4)
+	decl	%ecx
+	jnz	L(divide_integer)
+
+
+L(divide_no_integer):
+	movl	PARAM_DST, %edi
+	orl	%ebx, %ebx
+	jnz	L(divide_fraction)
+
+L(divide_done):
+	movl	SAVE_ESI, %esi
+	movl	SAVE_EDI, %edi
+	movl	%edx, %eax
+
+	movl	SAVE_EBX, %ebx
+	movl	SAVE_EBP, %ebp
+	addl	$STACK_SPACE, %esp
+
+	ret
+
+
+L(divide_fraction):
+	C eax	scratch (quotient)
+	C ebx	counter
+	C ecx
+	C edx	scratch (remainder)
+	C esi
+	C edi	dst
+	C ebp	divisor
+
+	movl	$0, %eax
+
+	divl	%ebp
+
+	movl	%eax, -4(%edi,%ebx,4)
+	decl	%ebx
+	jnz	L(divide_fraction)
+
+	jmp	L(divide_done)
+
+
+
+C -----------------------------------------------------------------------------
+
+L(mul_by_inverse):
+	C eax
+	C ebx	xsize
+	C ecx	size
+	C edx	carry
+	C esi	src
+	C edi	&dst[xsize-1]
+	C ebp	divisor
+
+	bsrl	%ebp, %eax		C 31-l
+
+	leal	12(%edi), %ebx		C &dst[xsize+2], loop dst stop
+	leal	4(%edi,%ecx,4), %edi	C &dst[xsize+size]
+
+	movl	%edi, VAR_DST
+	movl	%ebx, VAR_DST_STOP
+
+	movl	%ecx, %ebx		C size
+	movl	$31, %ecx
+
+	movl	%edx, %edi		C carry
+	movl	$-1, %edx
+
+	C
+
+	xorl	%eax, %ecx		C l
+	incl	%eax			C 32-l
+
+	shll	%cl, %ebp		C d normalized
+	movl	%ecx, VAR_NORM
+
+	movd	%eax, %mm7
+
+	movl	$-1, %eax
+	subl	%ebp, %edx		C (b-d)-1 giving edx:eax = b*(b-d)-1
+
+	divl	%ebp			C floor (b*(b-d)-1) / d
+
+L(start_preinv):
+	C eax	inverse
+	C ebx	size
+	C ecx	shift
+	C edx
+	C esi	src
+	C edi	carry
+	C ebp	divisor
+	C
+	C mm7	rshift
+
+	orl	%ebx, %ebx		C size
+	movl	%eax, VAR_INVERSE
+	leal	-12(%esi,%ebx,4), %eax	C &src[size-3]
+
+	jz	L(start_zero)
+	movl	%eax, VAR_SRC
+	cmpl	$1, %ebx
+
+	movl	8(%eax), %esi		C src high limb
+	jz	L(start_one)
+
+L(start_two_or_more):
+	movl	4(%eax), %edx		C src second highest limb
+
+	shldl(	%cl, %esi, %edi)	C n2 = carry,high << l
+
+	shldl(	%cl, %edx, %esi)	C n10 = high,second << l
+
+	cmpl	$2, %ebx
+	je	L(integer_two_left)
+	jmp	L(integer_top)
+
+
+L(start_one):
+	shldl(	%cl, %esi, %edi)	C n2 = carry,high << l
+
+	shll	%cl, %esi		C n10 = high << l
+	movl	%eax, VAR_SRC
+	jmp	L(integer_one_left)
+
+
+L(start_zero):
+	C Can be here with xsize==0 if mpn_preinv_divrem_1 had size==1 and
+	C skipped a division.
+
+	shll	%cl, %edi		C n2 = carry << l
+	movl	%edi, %eax		C return value for zero_done
+	cmpl	$0, PARAM_XSIZE
+
+	je	L(zero_done)
+	jmp	L(fraction_some)
+
+
+
+C -----------------------------------------------------------------------------
+C
+C The multiply by inverse loop is 17 cycles, and relies on some out-of-order
+C execution.  The instruction scheduling is important, with various
+C apparently equivalent forms running 1 to 5 cycles slower.
+C
+C A lower bound for the time would seem to be 16 cycles, based on the
+C following successive dependencies.
+C
+C		      cycles
+C		n2+n1	1
+C		mul	6
+C		q1+1	1
+C		mul	6
+C		sub	1
+C		addback	1
+C		       ---
+C		       16
+C
+C This chain is what the loop has already, but 16 cycles isn't achieved.
+C K7 has enough decode, and probably enough execute (depending maybe on what
+C a mul actually consumes), but nothing running under 17 has been found.
+C
+C In theory n2+n1 could be done in the sub and addback stages (by
+C calculating both n2 and n2+n1 there), but lack of registers makes this an
+C unlikely proposition.
+C
+C The jz in the loop keeps the q1+1 stage to 1 cycle.  Handling an overflow
+C from q1+1 with an "sbbl $0, %ebx" would add a cycle to the dependent
+C chain, and nothing better than 18 cycles has been found when using it.
+C The jump is taken only when q1 is 0xFFFFFFFF, and on random data this will
+C be an extremely rare event.
+C
+C Branch mispredictions will hit random occurrences of q1==0xFFFFFFFF, but
+C if some special data is coming out with this always, the q1_ff special
+C case actually runs at 15 c/l.  0x2FFF...FFFD divided by 3 is a good way to
+C induce the q1_ff case, for speed measurements or testing.  Note that
+C 0xFFF...FFF divided by 1 or 2 doesn't induce it.
+C
+C The instruction groupings and empty comments show the cycles for a naive
+C in-order view of the code (conveniently ignoring the load latency on
+C VAR_INVERSE).  This shows some of where the time is going, but is nonsense
+C to the extent that out-of-order execution rearranges it.  In this case
+C there's 19 cycles shown, but it executes at 17.
+
+	ALIGN(16)
+L(integer_top):
+	C eax	scratch
+	C ebx	scratch (nadj, q1)
+	C ecx	scratch (src, dst)
+	C edx	scratch
+	C esi	n10
+	C edi	n2
+	C ebp	divisor
+	C
+	C mm0	scratch (src qword)
+	C mm7	rshift for normalization
+
+	cmpl	$0x80000000, %esi  C n1 as 0=c, 1=nc
+	movl	%edi, %eax         C n2
+	movl	VAR_SRC, %ecx
+
+	leal	(%ebp,%esi), %ebx
+	cmovc(	%esi, %ebx)	   C nadj = n10 + (-n1 & d), ignoring overflow
+	sbbl	$-1, %eax          C n2+n1
+
+	mull	VAR_INVERSE        C m*(n2+n1)
+
+	movq	(%ecx), %mm0       C next limb and the one below it
+	subl	$4, %ecx
+
+	movl	%ecx, VAR_SRC
+
+	C
+
+	addl	%ebx, %eax         C m*(n2+n1) + nadj, low giving carry flag
+	leal	1(%edi), %ebx      C n2+1
+	movl	%ebp, %eax	   C d
+
+	C
+
+	adcl	%edx, %ebx         C 1 + high(n2<<32 + m*(n2+n1) + nadj) = q1+1
+	jz	L(q1_ff)
+	movl	VAR_DST, %ecx
+
+	mull	%ebx		   C (q1+1)*d
+
+	psrlq	%mm7, %mm0
+
+	leal	-4(%ecx), %ecx
+
+	C
+
+	subl	%eax, %esi
+	movl	VAR_DST_STOP, %eax
+
+	C
+
+	sbbl	%edx, %edi	   C n - (q1+1)*d
+	movl	%esi, %edi	   C remainder -> n2
+	leal	(%ebp,%esi), %edx
+
+	movd	%mm0, %esi
+
+	cmovc(	%edx, %edi)	   C n - q1*d if underflow from using q1+1
+	sbbl	$0, %ebx	   C q
+	cmpl	%eax, %ecx
+
+	movl	%ebx, (%ecx)
+	movl	%ecx, VAR_DST
+	jne	L(integer_top)
+
+
+L(integer_loop_done):
+
+
+C -----------------------------------------------------------------------------
+C
+C Here, and in integer_one_left below, an sbbl $0 is used rather than a jz
+C q1_ff special case.  This make the code a bit smaller and simpler, and
+C costs only 1 cycle (each).
+
+L(integer_two_left):
+	C eax	scratch
+	C ebx	scratch (nadj, q1)
+	C ecx	scratch (src, dst)
+	C edx	scratch
+	C esi	n10
+	C edi	n2
+	C ebp	divisor
+	C
+	C mm7	rshift
+
+	cmpl	$0x80000000, %esi  C n1 as 0=c, 1=nc
+	movl	%edi, %eax         C n2
+	movl	PARAM_SRC, %ecx
+
+	leal	(%ebp,%esi), %ebx
+	cmovc(	%esi, %ebx)	   C nadj = n10 + (-n1 & d), ignoring overflow
+	sbbl	$-1, %eax          C n2+n1
+
+	mull	VAR_INVERSE        C m*(n2+n1)
+
+	movd	(%ecx), %mm0	   C src low limb
+
+	movl	VAR_DST_STOP, %ecx
+
+	C
+
+	addl	%ebx, %eax         C m*(n2+n1) + nadj, low giving carry flag
+	leal	1(%edi), %ebx      C n2+1
+	movl	%ebp, %eax	   C d
+
+	adcl	%edx, %ebx         C 1 + high(n2<<32 + m*(n2+n1) + nadj) = q1+1
+
+	sbbl	$0, %ebx
+
+	mull	%ebx		   C (q1+1)*d
+
+	psllq	$32, %mm0
+
+	psrlq	%mm7, %mm0
+
+	C
+
+	subl	%eax, %esi
+
+	C
+
+	sbbl	%edx, %edi	   C n - (q1+1)*d
+	movl	%esi, %edi	   C remainder -> n2
+	leal	(%ebp,%esi), %edx
+
+	movd	%mm0, %esi
+
+	cmovc(	%edx, %edi)	   C n - q1*d if underflow from using q1+1
+	sbbl	$0, %ebx	   C q
+
+	movl	%ebx, -4(%ecx)
+
+
+C -----------------------------------------------------------------------------
+L(integer_one_left):
+	C eax	scratch
+	C ebx	scratch (nadj, q1)
+	C ecx	dst
+	C edx	scratch
+	C esi	n10
+	C edi	n2
+	C ebp	divisor
+	C
+	C mm7	rshift
+
+	movl	VAR_DST_STOP, %ecx
+	cmpl	$0x80000000, %esi  C n1 as 0=c, 1=nc
+	movl	%edi, %eax         C n2
+
+	leal	(%ebp,%esi), %ebx
+	cmovc(	%esi, %ebx)	   C nadj = n10 + (-n1 & d), ignoring overflow
+	sbbl	$-1, %eax          C n2+n1
+
+	mull	VAR_INVERSE        C m*(n2+n1)
+
+	C
+
+	C
+
+	C
+
+	addl	%ebx, %eax         C m*(n2+n1) + nadj, low giving carry flag
+	leal	1(%edi), %ebx      C n2+1
+	movl	%ebp, %eax	   C d
+
+	C
+
+	adcl	%edx, %ebx         C 1 + high(n2<<32 + m*(n2+n1) + nadj) = q1+1
+
+	sbbl	$0, %ebx           C q1 if q1+1 overflowed
+
+	mull	%ebx
+
+	C
+
+	C
+
+	C
+
+	subl	%eax, %esi
+
+	C
+
+	sbbl	%edx, %edi	   C n - (q1+1)*d
+	movl	%esi, %edi	   C remainder -> n2
+	leal	(%ebp,%esi), %edx
+
+	cmovc(	%edx, %edi)	   C n - q1*d if underflow from using q1+1
+	sbbl	$0, %ebx	   C q
+
+	movl	%ebx, -8(%ecx)
+	subl	$8, %ecx
+
+
+
+L(integer_none):
+	cmpl	$0, PARAM_XSIZE
+	jne	L(fraction_some)
+
+	movl	%edi, %eax
+L(fraction_done):
+	movl	VAR_NORM, %ecx
+L(zero_done):
+	movl	SAVE_EBP, %ebp
+
+	movl	SAVE_EDI, %edi
+	movl	SAVE_ESI, %esi
+
+	movl	SAVE_EBX, %ebx
+	addl	$STACK_SPACE, %esp
+
+	shrl	%cl, %eax
+	emms
+
+	ret
+
+
+C -----------------------------------------------------------------------------
+C
+C Special case for q1=0xFFFFFFFF, giving q=0xFFFFFFFF meaning the low dword
+C of q*d is simply -d and the remainder n-q*d = n10+d
+
+L(q1_ff):
+	C eax	(divisor)
+	C ebx	(q1+1 == 0)
+	C ecx
+	C edx
+	C esi	n10
+	C edi	n2
+	C ebp	divisor
+
+	movl	VAR_DST, %ecx
+	movl	VAR_DST_STOP, %edx
+	subl	$4, %ecx
+
+	psrlq	%mm7, %mm0
+	leal	(%ebp,%esi), %edi	C n-q*d remainder -> next n2
+	movl	%ecx, VAR_DST
+
+	movd	%mm0, %esi		C next n10
+
+	movl	$-1, (%ecx)
+	cmpl	%ecx, %edx
+	jne	L(integer_top)
+
+	jmp	L(integer_loop_done)
+
+
+
+C -----------------------------------------------------------------------------
+C
+C Being the fractional part, the "source" limbs are all zero, meaning
+C n10=0, n1=0, and hence nadj=0, leading to many instructions eliminated.
+C
+C The loop runs at 15 cycles.  The dependent chain is the same as the
+C general case above, but without the n2+n1 stage (due to n1==0), so 15
+C would seem to be the lower bound.
+C
+C A not entirely obvious simplification is that q1+1 never overflows a limb,
+C and so there's no need for the sbbl $0 or jz q1_ff from the general case.
+C q1 is the high word of m*n2+b*n2 and the following shows q1<=b-2 always.
+C rnd() means rounding down to a multiple of d.
+C
+C	m*n2 + b*n2 <= m*(d-1) + b*(d-1)
+C		     = m*d + b*d - m - b
+C		     = floor((b(b-d)-1)/d)*d + b*d - m - b
+C		     = rnd(b(b-d)-1) + b*d - m - b
+C		     = rnd(b(b-d)-1 + b*d) - m - b
+C		     = rnd(b*b-1) - m - b
+C		     <= (b-2)*b
+C
+C Unchanged from the general case is that the final quotient limb q can be
+C either q1 or q1+1, and the q1+1 case occurs often.  This can be seen from
+C equation 8.4 of the paper which simplifies as follows when n1==0 and
+C n0==0.
+C
+C	n-q1*d = (n2*k+q0*d)/b <= d + (d*d-2d)/b
+C
+C As before, the instruction groupings and empty comments show a naive
+C in-order view of the code, which is made a nonsense by out of order
+C execution.  There's 17 cycles shown, but it executes at 15.
+C
+C Rotating the store q and remainder->n2 instructions up to the top of the
+C loop gets the run time down from 16 to 15.
+
+	ALIGN(16)
+L(fraction_some):
+	C eax
+	C ebx
+	C ecx
+	C edx
+	C esi
+	C edi	carry
+	C ebp	divisor
+
+	movl	PARAM_DST, %esi
+	movl	VAR_DST_STOP, %ecx	C &dst[xsize+2]
+	movl	%edi, %eax
+
+	subl	$8, %ecx		C &dst[xsize]
+	jmp	L(fraction_entry)
+
+
+	ALIGN(16)
+L(fraction_top):
+	C eax	n2 carry, then scratch
+	C ebx	scratch (nadj, q1)
+	C ecx	dst, decrementing
+	C edx	scratch
+	C esi	dst stop point
+	C edi	(will be n2)
+	C ebp	divisor
+
+	movl	%ebx, (%ecx)	C previous q
+	movl	%eax, %edi	C remainder->n2
+
+L(fraction_entry):
+	mull	VAR_INVERSE	C m*n2
+
+	movl	%ebp, %eax	C d
+	subl	$4, %ecx	C dst
+	leal	1(%edi), %ebx
+
+	C
+
+	C
+
+	C
+
+	C
+
+	addl	%edx, %ebx	C 1 + high(n2<<32 + m*n2) = q1+1
+
+	mull	%ebx		C (q1+1)*d
+
+	C
+
+	C
+
+	C
+
+	negl	%eax		C low of n - (q1+1)*d
+
+	C
+
+	sbbl	%edx, %edi	C high of n - (q1+1)*d, caring only about carry
+	leal	(%ebp,%eax), %edx
+
+	cmovc(	%edx, %eax)	C n - q1*d if underflow from using q1+1
+	sbbl	$0, %ebx	C q
+	cmpl	%esi, %ecx
+
+	jne	L(fraction_top)
+
+
+	movl	%ebx, (%ecx)
+	jmp	L(fraction_done)
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/k7/mmx/lshift.asm b/third_party/gmp/mpn/x86/k7/mmx/lshift.asm
new file mode 100644
index 0000000..b3383cf
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k7/mmx/lshift.asm
@@ -0,0 +1,481 @@
+dnl  AMD K7 mpn_lshift -- mpn left shift.
+
+dnl  Copyright 1999-2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C K7: 1.21 cycles/limb (at 16 limbs/loop).
+
+
+
+dnl  K7: UNROLL_COUNT cycles/limb
+dnl           4           1.51
+dnl           8           1.26
+dnl          16           1.21
+dnl          32           1.2
+dnl  Maximum possible with the current code is 64.
+
+deflit(UNROLL_COUNT, 16)
+
+
+C mp_limb_t mpn_lshift (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                       unsigned shift);
+C
+C Shift src,size left by shift many bits and store the result in dst,size.
+C Zeros are shifted in at the right.  The bits shifted out at the left are
+C the return value.
+C
+C The comments in mpn_rshift apply here too.
+
+ifdef(`PIC',`
+deflit(UNROLL_THRESHOLD, 10)
+',`
+deflit(UNROLL_THRESHOLD, 10)
+')
+
+defframe(PARAM_SHIFT,16)
+defframe(PARAM_SIZE, 12)
+defframe(PARAM_SRC,  8)
+defframe(PARAM_DST,  4)
+
+defframe(SAVE_EDI, -4)
+defframe(SAVE_ESI, -8)
+defframe(SAVE_EBX, -12)
+deflit(SAVE_SIZE, 12)
+
+	TEXT
+	ALIGN(32)
+
+PROLOGUE(mpn_lshift)
+deflit(`FRAME',0)
+
+	movl	PARAM_SIZE, %eax
+	movl	PARAM_SRC, %edx
+	subl	$SAVE_SIZE, %esp
+deflit(`FRAME',SAVE_SIZE)
+
+	movl	PARAM_SHIFT, %ecx
+	movl	%edi, SAVE_EDI
+
+	movl	PARAM_DST, %edi
+	decl	%eax
+	jnz	L(more_than_one_limb)
+
+	movl	(%edx), %edx
+
+	shldl(	%cl, %edx, %eax)	C eax was decremented to zero
+
+	shll	%cl, %edx
+
+	movl	%edx, (%edi)
+	movl	SAVE_EDI, %edi
+	addl	$SAVE_SIZE, %esp
+
+	ret
+
+
+C -----------------------------------------------------------------------------
+L(more_than_one_limb):
+	C eax	size-1
+	C ebx
+	C ecx	shift
+	C edx	src
+	C esi
+	C edi	dst
+	C ebp
+
+	movd	PARAM_SHIFT, %mm6
+	movd	(%edx,%eax,4), %mm5	C src high limb
+	cmp	$UNROLL_THRESHOLD-1, %eax
+
+	jae	L(unroll)
+	negl	%ecx
+	movd	(%edx), %mm4		C src low limb
+
+	addl	$32, %ecx
+
+	movd	%ecx, %mm7
+
+L(simple_top):
+	C eax	loop counter, limbs
+	C ebx
+	C ecx
+	C edx	src
+	C esi
+	C edi	dst
+	C ebp
+	C
+	C mm0	scratch
+	C mm4	src low limb
+	C mm5	src high limb
+	C mm6	shift
+	C mm7	32-shift
+
+	movq	-4(%edx,%eax,4), %mm0
+	decl	%eax
+
+	psrlq	%mm7, %mm0
+
+	movd	%mm0, 4(%edi,%eax,4)
+	jnz	L(simple_top)
+
+
+	psllq	%mm6, %mm5
+	psllq	%mm6, %mm4
+
+	psrlq	$32, %mm5
+	movd	%mm4, (%edi)		C dst low limb
+
+	movd	%mm5, %eax		C return value
+
+	movl	SAVE_EDI, %edi
+	addl	$SAVE_SIZE, %esp
+	emms
+
+	ret
+
+
+C -----------------------------------------------------------------------------
+	ALIGN(16)
+L(unroll):
+	C eax	size-1
+	C ebx	(saved)
+	C ecx	shift
+	C edx	src
+	C esi
+	C edi	dst
+	C ebp
+	C
+	C mm5	src high limb, for return value
+	C mm6	lshift
+
+	movl	%esi, SAVE_ESI
+	movl	%ebx, SAVE_EBX
+	leal	-4(%edx,%eax,4), %edx   C &src[size-2]
+
+	testb	$4, %dl
+	movq	(%edx), %mm1		C src high qword
+
+	jz	L(start_src_aligned)
+
+
+	C src isn't aligned, process high limb (marked xxx) separately to
+	C make it so
+	C
+	C  source    -4(edx,%eax,4)
+	C                  |
+	C  +-------+-------+-------+--
+	C  |  xxx          |
+	C  +-------+-------+-------+--
+	C        0mod8   4mod8   0mod8
+	C
+	C  dest      -4(edi,%eax,4)
+	C                  |
+	C  +-------+-------+--
+	C  |  xxx  |       |
+	C  +-------+-------+--
+
+	psllq	%mm6, %mm1
+	subl	$4, %edx
+	movl	%eax, PARAM_SIZE	C size-1
+
+	psrlq	$32, %mm1
+	decl	%eax			C size-2 is new size-1
+
+	movd	%mm1, 4(%edi,%eax,4)
+	movq	(%edx), %mm1		C new src high qword
+L(start_src_aligned):
+
+
+	leal	-4(%edi,%eax,4), %edi   C &dst[size-2]
+	psllq	%mm6, %mm5
+
+	testl	$4, %edi
+	psrlq	$32, %mm5		C return value
+
+	jz	L(start_dst_aligned)
+
+
+	C dst isn't aligned, subtract 4 bytes to make it so, and pretend the
+	C shift is 32 bits extra.  High limb of dst (marked xxx) handled
+	C here separately.
+	C
+	C  source       %edx
+	C  +-------+-------+--
+	C  |      mm1      |
+	C  +-------+-------+--
+	C                0mod8   4mod8
+	C
+	C  dest         %edi
+	C  +-------+-------+-------+--
+	C  |  xxx  |
+	C  +-------+-------+-------+--
+	C        0mod8   4mod8   0mod8
+
+	movq	%mm1, %mm0
+	psllq	%mm6, %mm1
+	addl	$32, %ecx		C shift+32
+
+	psrlq	$32, %mm1
+
+	movd	%mm1, 4(%edi)
+	movq	%mm0, %mm1
+	subl	$4, %edi
+
+	movd	%ecx, %mm6		C new lshift
+L(start_dst_aligned):
+
+	decl	%eax			C size-2, two last limbs handled at end
+	movq	%mm1, %mm2		C copy of src high qword
+	negl	%ecx
+
+	andl	$-2, %eax		C round size down to even
+	addl	$64, %ecx
+
+	movl	%eax, %ebx
+	negl	%eax
+
+	andl	$UNROLL_MASK, %eax
+	decl	%ebx
+
+	shll	%eax
+
+	movd	%ecx, %mm7		C rshift = 64-lshift
+
+ifdef(`PIC',`
+	call	L(pic_calc)
+L(here):
+',`
+	leal	L(entry) (%eax,%eax,4), %esi
+')
+	shrl	$UNROLL_LOG2, %ebx	C loop counter
+
+	leal	ifelse(UNROLL_BYTES,256,128) -8(%edx,%eax,2), %edx
+	leal	ifelse(UNROLL_BYTES,256,128) (%edi,%eax,2), %edi
+	movl	PARAM_SIZE, %eax	C for use at end
+	jmp	*%esi
+
+
+ifdef(`PIC',`
+L(pic_calc):
+	C See mpn/x86/README about old gas bugs
+	leal	(%eax,%eax,4), %esi
+	addl	$L(entry)-L(here), %esi
+	addl	(%esp), %esi
+
+	ret_internal
+')
+
+
+C -----------------------------------------------------------------------------
+	ALIGN(32)
+L(top):
+	C eax	size (for use at end)
+	C ebx	loop counter
+	C ecx	rshift
+	C edx	src
+	C esi	computed jump
+	C edi	dst
+	C ebp
+	C
+	C mm0	scratch
+	C mm1	\ carry (alternating, mm2 first)
+	C mm2	/
+	C mm6	lshift
+	C mm7	rshift
+	C
+	C 10 code bytes/limb
+	C
+	C The two chunks differ in whether mm1 or mm2 hold the carry.
+	C The computed jump puts the initial carry in both mm1 and mm2.
+
+L(entry):
+deflit(CHUNK_COUNT, 4)
+forloop(i, 0, UNROLL_COUNT/CHUNK_COUNT-1, `
+	deflit(`disp0', eval(-i*CHUNK_COUNT*4 ifelse(UNROLL_BYTES,256,-128)))
+	deflit(`disp1', eval(disp0 - 8))
+
+Zdisp(	movq,	disp0,(%edx), %mm0)
+	psllq	%mm6, %mm2
+
+	movq	%mm0, %mm1
+	psrlq	%mm7, %mm0
+
+	por	%mm2, %mm0
+Zdisp(	movq,	%mm0, disp0,(%edi))
+
+
+Zdisp(	movq,	disp1,(%edx), %mm0)
+	psllq	%mm6, %mm1
+
+	movq	%mm0, %mm2
+	psrlq	%mm7, %mm0
+
+	por	%mm1, %mm0
+Zdisp(	movq,	%mm0, disp1,(%edi))
+')
+
+	subl	$UNROLL_BYTES, %edx
+	subl	$UNROLL_BYTES, %edi
+	decl	%ebx
+
+	jns	L(top)
+
+
+
+define(`disp', `m4_empty_if_zero(eval($1 ifelse(UNROLL_BYTES,256,-128)))')
+
+L(end):
+	testb	$1, %al
+	movl	SAVE_EBX, %ebx
+	psllq	%mm6, %mm2	C wanted left shifted in all cases below
+
+	movd	%mm5, %eax
+
+	movl	SAVE_ESI, %esi
+	jz	L(end_even)
+
+
+L(end_odd):
+
+	C Size odd, destination was aligned.
+	C
+	C                 source        edx+8   edx+4
+	C                 --+---------------+-------+
+	C                   |      mm2      |       |
+	C                 --+---------------+-------+
+	C
+	C dest                            edi
+	C --+---------------+---------------+-------+
+	C   |   written     |               |       |
+	C --+---------------+---------------+-------+
+	C
+	C mm6 = shift
+	C mm7 = ecx = 64-shift
+
+
+	C Size odd, destination was unaligned.
+	C
+	C                 source        edx+8   edx+4
+	C                 --+---------------+-------+
+	C                   |      mm2      |       |
+	C                 --+---------------+-------+
+	C
+	C         dest                            edi
+	C         --+---------------+---------------+
+	C           |   written     |               |
+	C         --+---------------+---------------+
+	C
+	C mm6 = shift+32
+	C mm7 = ecx = 64-(shift+32)
+
+
+	C In both cases there's one extra limb of src to fetch and combine
+	C with mm2 to make a qword at (%edi), and in the aligned case
+	C there's an extra limb of dst to be formed from that extra src limb
+	C left shifted.
+
+	movd	disp(4) (%edx), %mm0
+	testb	$32, %cl
+
+	movq	%mm0, %mm1
+	psllq	$32, %mm0
+
+	psrlq	%mm7, %mm0
+	psllq	%mm6, %mm1
+
+	por	%mm2, %mm0
+
+	movq	%mm0, disp(0) (%edi)
+	jz	L(end_odd_unaligned)
+	movd	%mm1, disp(-4) (%edi)
+L(end_odd_unaligned):
+
+	movl	SAVE_EDI, %edi
+	addl	$SAVE_SIZE, %esp
+	emms
+
+	ret
+
+
+L(end_even):
+
+	C Size even, destination was aligned.
+	C
+	C                 source        edx+8
+	C                 --+---------------+
+	C                   |      mm2      |
+	C                 --+---------------+
+	C
+	C dest                            edi
+	C --+---------------+---------------+
+	C   |   written     |               |
+	C --+---------------+---------------+
+	C
+	C mm6 = shift
+	C mm7 = ecx = 64-shift
+
+
+	C Size even, destination was unaligned.
+	C
+	C               source          edx+8
+	C                 --+---------------+
+	C                   |      mm2      |
+	C                 --+---------------+
+	C
+	C         dest                  edi+4
+	C         --+---------------+-------+
+	C           |    written    |       |
+	C         --+---------------+-------+
+	C
+	C mm6 = shift+32
+	C mm7 = ecx = 64-(shift+32)
+
+
+	C The movq for the aligned case overwrites the movd for the
+	C unaligned case.
+
+	movq	%mm2, %mm0
+	psrlq	$32, %mm2
+
+	testb	$32, %cl
+	movd	%mm2, disp(4) (%edi)
+
+	jz	L(end_even_unaligned)
+	movq	%mm0, disp(0) (%edi)
+L(end_even_unaligned):
+
+	movl	SAVE_EDI, %edi
+	addl	$SAVE_SIZE, %esp
+	emms
+
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/k7/mmx/popham.asm b/third_party/gmp/mpn/x86/k7/mmx/popham.asm
new file mode 100644
index 0000000..95965b7
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k7/mmx/popham.asm
@@ -0,0 +1,213 @@
+dnl  AMD K7 mpn_popcount, mpn_hamdist -- population count and hamming
+dnl  distance.
+
+dnl  Copyright 2000-2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C			     popcount	     hamdist
+C P3 generic			6.5		7
+C P3 model 9  (Banias)          5.7		6.1
+C P3 model 13 (Dothan)		5.75		6
+C K7				5		6
+
+C unsigned long mpn_popcount (mp_srcptr src, mp_size_t size);
+C unsigned long mpn_hamdist (mp_srcptr src, mp_srcptr src2, mp_size_t size);
+C
+C The code here is almost certainly not optimal, but is already a 3x speedup
+C over the generic C code.  The main improvement would be to interleave
+C processing of two qwords in the loop so as to fully exploit the available
+C execution units, possibly leading to 3.25 c/l (13 cycles for 4 limbs).
+C
+C The loop is based on the example "Efficient 64-bit population count using
+C MMX instructions" in the Athlon Optimization Guide, AMD document 22007,
+C page 158 of rev E (reference in mpn/x86/k7/README).
+
+ifdef(`OPERATION_popcount',,
+`ifdef(`OPERATION_hamdist',,
+`m4_error(`Need OPERATION_popcount or OPERATION_hamdist defined
+')')')
+
+define(HAM,
+m4_assert_numargs(1)
+`ifdef(`OPERATION_hamdist',`$1')')
+
+define(POP,
+m4_assert_numargs(1)
+`ifdef(`OPERATION_popcount',`$1')')
+
+HAM(`
+defframe(PARAM_SIZE,   12)
+defframe(PARAM_SRC2,   8)
+defframe(PARAM_SRC,    4)
+define(M4_function,mpn_hamdist)
+')
+POP(`
+defframe(PARAM_SIZE,   8)
+defframe(PARAM_SRC,    4)
+define(M4_function,mpn_popcount)
+')
+
+MULFUNC_PROLOGUE(mpn_popcount mpn_hamdist)
+
+
+ifdef(`PIC',,`
+	dnl  non-PIC
+
+	RODATA
+	ALIGN(8)
+
+L(rodata_AAAAAAAAAAAAAAAA):
+	.long	0xAAAAAAAA
+	.long	0xAAAAAAAA
+
+L(rodata_3333333333333333):
+	.long	0x33333333
+	.long	0x33333333
+
+L(rodata_0F0F0F0F0F0F0F0F):
+	.long	0x0F0F0F0F
+	.long	0x0F0F0F0F
+')
+
+	TEXT
+	ALIGN(32)
+
+PROLOGUE(M4_function)
+deflit(`FRAME',0)
+
+	movl	PARAM_SIZE, %ecx
+
+ifdef(`PIC',`
+	movl	$0xAAAAAAAA, %eax
+	movl	$0x33333333, %edx
+
+	movd	%eax, %mm7
+	movd	%edx, %mm6
+
+	movl	$0x0F0F0F0F, %eax
+
+	punpckldq %mm7, %mm7
+	punpckldq %mm6, %mm6
+
+	movd	%eax, %mm5
+	movd	%edx, %mm4
+
+	punpckldq %mm5, %mm5
+
+',`
+	movq	L(rodata_AAAAAAAAAAAAAAAA), %mm7
+	movq	L(rodata_3333333333333333), %mm6
+	movq	L(rodata_0F0F0F0F0F0F0F0F), %mm5
+')
+	pxor	%mm4, %mm4
+
+define(REG_AAAAAAAAAAAAAAAA,%mm7)
+define(REG_3333333333333333,%mm6)
+define(REG_0F0F0F0F0F0F0F0F,%mm5)
+define(REG_0000000000000000,%mm4)
+
+
+	movl	PARAM_SRC, %eax
+HAM(`	movl	PARAM_SRC2, %edx')
+
+	pxor	%mm2, %mm2	C total
+
+	shrl	%ecx
+	jnc	L(top)
+
+	movd	(%eax,%ecx,8), %mm1
+
+HAM(`	movd	(%edx,%ecx,8), %mm0
+	pxor	%mm0, %mm1
+')
+	orl	%ecx, %ecx
+	jmp	L(loaded)
+
+
+	ALIGN(16)
+L(top):
+	C eax	src
+	C ebx
+	C ecx	counter, qwords, decrementing
+	C edx	[hamdist] src2
+	C
+	C mm0	(scratch)
+	C mm1	(scratch)
+	C mm2	total (low dword)
+	C mm3
+	C mm4	\
+	C mm5	| special constants
+	C mm6	|
+	C mm7	/
+
+	movq	-8(%eax,%ecx,8), %mm1
+
+HAM(`	pxor	-8(%edx,%ecx,8), %mm1')
+	decl	%ecx
+
+L(loaded):
+	movq	%mm1, %mm0
+	pand	REG_AAAAAAAAAAAAAAAA, %mm1
+
+	psrlq	$1, %mm1
+
+	psubd	%mm1, %mm0	C bit pairs
+
+
+	movq	%mm0, %mm1
+	psrlq	$2, %mm0
+
+	pand	REG_3333333333333333, %mm0
+	pand	REG_3333333333333333, %mm1
+
+	paddd	%mm1, %mm0	C nibbles
+
+
+	movq	%mm0, %mm1
+	psrlq	$4, %mm0
+
+	pand	REG_0F0F0F0F0F0F0F0F, %mm0
+	pand	REG_0F0F0F0F0F0F0F0F, %mm1
+
+	paddd	%mm1, %mm0	C bytes
+
+
+	psadbw(	%mm4, %mm0)
+
+	paddd	%mm0, %mm2	C add to total
+	jnz	L(top)
+
+
+	movd	%mm2, %eax
+	emms
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/k7/mmx/rshift.asm b/third_party/gmp/mpn/x86/k7/mmx/rshift.asm
new file mode 100644
index 0000000..345d23a
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k7/mmx/rshift.asm
@@ -0,0 +1,480 @@
+dnl  AMD K7 mpn_rshift -- mpn right shift.
+
+dnl  Copyright 1999-2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C K7: 1.21 cycles/limb (at 16 limbs/loop).
+
+
+
+dnl  K7: UNROLL_COUNT cycles/limb
+dnl           4           1.51
+dnl           8           1.26
+dnl          16           1.21
+dnl          32           1.2
+dnl  Maximum possible with the current code is 64.
+
+deflit(UNROLL_COUNT, 16)
+
+
+C mp_limb_t mpn_rshift (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                       unsigned shift);
+C
+C Shift src,size right by shift many bits and store the result in dst,size.
+C Zeros are shifted in at the left.  The bits shifted out at the right are
+C the return value.
+C
+C This code uses 64-bit MMX operations, which makes it possible to handle
+C two limbs at a time, for a theoretical 1.0 cycles/limb.  Plain integer
+C code, on the other hand, suffers from shrd being a vector path decode and
+C running at 3 cycles back-to-back.
+C
+C Full speed depends on source and destination being aligned, and some hairy
+C setups and finish-ups are done to arrange this for the loop.
+
+ifdef(`PIC',`
+deflit(UNROLL_THRESHOLD, 10)
+',`
+deflit(UNROLL_THRESHOLD, 10)
+')
+
+defframe(PARAM_SHIFT,16)
+defframe(PARAM_SIZE, 12)
+defframe(PARAM_SRC,  8)
+defframe(PARAM_DST,  4)
+
+defframe(SAVE_EDI, -4)
+defframe(SAVE_ESI, -8)
+defframe(SAVE_EBX, -12)
+deflit(SAVE_SIZE, 12)
+
+	TEXT
+	ALIGN(32)
+
+PROLOGUE(mpn_rshift)
+deflit(`FRAME',0)
+
+	movl	PARAM_SIZE, %eax
+	movl	PARAM_SRC, %edx
+	subl	$SAVE_SIZE, %esp
+deflit(`FRAME',SAVE_SIZE)
+
+	movl	PARAM_SHIFT, %ecx
+	movl	%edi, SAVE_EDI
+
+	movl	PARAM_DST, %edi
+	decl	%eax
+	jnz	L(more_than_one_limb)
+
+	movl	(%edx), %edx		C src limb
+
+	shrdl(	%cl, %edx, %eax)	C eax was decremented to zero
+
+	shrl	%cl, %edx
+
+	movl	%edx, (%edi)		C dst limb
+	movl	SAVE_EDI, %edi
+	addl	$SAVE_SIZE, %esp
+
+	ret
+
+
+C -----------------------------------------------------------------------------
+L(more_than_one_limb):
+	C eax	size-1
+	C ebx
+	C ecx	shift
+	C edx	src
+	C esi
+	C edi	dst
+	C ebp
+
+	movd	PARAM_SHIFT, %mm6	C rshift
+	movd	(%edx), %mm5		C src low limb
+	cmp	$UNROLL_THRESHOLD-1, %eax
+
+	jae	L(unroll)
+	leal	(%edx,%eax,4), %edx	C &src[size-1]
+	leal	-4(%edi,%eax,4), %edi	C &dst[size-2]
+
+	movd	(%edx), %mm4		C src high limb
+	negl	%eax
+
+
+L(simple_top):
+	C eax	loop counter, limbs, negative
+	C ebx
+	C ecx	shift
+	C edx	carry
+	C edx	&src[size-1]
+	C edi	&dst[size-2]
+	C ebp
+	C
+	C mm0	scratch
+	C mm4	src high limb
+	C mm5	src low limb
+	C mm6	shift
+
+	movq	(%edx,%eax,4), %mm0
+	incl	%eax
+
+	psrlq	%mm6, %mm0
+
+	movd	%mm0, (%edi,%eax,4)
+	jnz	L(simple_top)
+
+
+	psllq	$32, %mm5
+	psrlq	%mm6, %mm4
+
+	psrlq	%mm6, %mm5
+	movd	%mm4, 4(%edi)		C dst high limb
+
+	movd	%mm5, %eax		C return value
+
+	movl	SAVE_EDI, %edi
+	addl	$SAVE_SIZE, %esp
+	emms
+
+	ret
+
+
+C -----------------------------------------------------------------------------
+	ALIGN(16)
+L(unroll):
+	C eax	size-1
+	C ebx
+	C ecx	shift
+	C edx	src
+	C esi
+	C edi	dst
+	C ebp
+	C
+	C mm5	src low limb
+	C mm6	rshift
+
+	testb	$4, %dl
+	movl	%esi, SAVE_ESI
+	movl	%ebx, SAVE_EBX
+
+	psllq	$32, %mm5
+	jz	L(start_src_aligned)
+
+
+	C src isn't aligned, process low limb separately (marked xxx) and
+	C step src and dst by one limb, making src aligned.
+	C
+	C source                  edx
+	C --+-------+-------+-------+
+	C           |          xxx  |
+	C --+-------+-------+-------+
+	C         4mod8   0mod8   4mod8
+	C
+	C         dest            edi
+	C         --+-------+-------+
+	C           |       |  xxx  |
+	C         --+-------+-------+
+
+	movq	(%edx), %mm0		C src low two limbs
+	addl	$4, %edx
+	movl	%eax, PARAM_SIZE	C size-1
+
+	addl	$4, %edi
+	decl	%eax			C size-2 is new size-1
+
+	psrlq	%mm6, %mm0
+	movl	%edi, PARAM_DST		C new dst
+
+	movd	%mm0, -4(%edi)
+L(start_src_aligned):
+
+
+	movq	(%edx), %mm1		C src low two limbs
+	decl	%eax			C size-2, two last limbs handled at end
+	testl	$4, %edi
+
+	psrlq	%mm6, %mm5
+	jz	L(start_dst_aligned)
+
+
+	C dst isn't aligned, add 4 to make it so, and pretend the shift is
+	C 32 bits extra.  Low limb of dst (marked xxx) handled here separately.
+	C
+	C          source          edx
+	C          --+-------+-------+
+	C            |      mm1      |
+	C          --+-------+-------+
+	C                  4mod8   0mod8
+	C
+	C  dest                    edi
+	C  --+-------+-------+-------+
+	C                    |  xxx  |
+	C  --+-------+-------+-------+
+	C          4mod8   0mod8   4mod8
+
+	movq	%mm1, %mm0
+	psrlq	%mm6, %mm1
+	addl	$32, %ecx		C shift+32
+
+	movd	%mm1, (%edi)
+	movq	%mm0, %mm1
+	addl	$4, %edi		C new dst
+
+	movd	%ecx, %mm6
+L(start_dst_aligned):
+
+
+	movq	%mm1, %mm2		C copy of src low two limbs
+	negl	%ecx
+	andl	$-2, %eax		C round size down to even
+
+	movl	%eax, %ebx
+	negl	%eax
+	addl	$64, %ecx
+
+	andl	$UNROLL_MASK, %eax
+	decl	%ebx
+
+	shll	%eax
+
+	movd	%ecx, %mm7		C lshift = 64-rshift
+
+ifdef(`PIC',`
+	call	L(pic_calc)
+L(here):
+',`
+	leal	L(entry) (%eax,%eax,4), %esi
+	negl	%eax
+')
+	shrl	$UNROLL_LOG2, %ebx	C loop counter
+
+	leal	ifelse(UNROLL_BYTES,256,128+) 8(%edx,%eax,2), %edx
+	leal	ifelse(UNROLL_BYTES,256,128) (%edi,%eax,2), %edi
+	movl	PARAM_SIZE, %eax	C for use at end
+
+	jmp	*%esi
+
+
+ifdef(`PIC',`
+L(pic_calc):
+	C See mpn/x86/README about old gas bugs
+	leal	(%eax,%eax,4), %esi
+	addl	$L(entry)-L(here), %esi
+	addl	(%esp), %esi
+	negl	%eax
+
+	ret_internal
+')
+
+
+C -----------------------------------------------------------------------------
+	ALIGN(64)
+L(top):
+	C eax	size, for use at end
+	C ebx	loop counter
+	C ecx	lshift
+	C edx	src
+	C esi	was computed jump
+	C edi	dst
+	C ebp
+	C
+	C mm0	scratch
+	C mm1	\ carry (alternating)
+	C mm2	/
+	C mm6	rshift
+	C mm7	lshift
+	C
+	C 10 code bytes/limb
+	C
+	C The two chunks differ in whether mm1 or mm2 hold the carry.
+	C The computed jump puts the initial carry in both mm1 and mm2.
+
+L(entry):
+deflit(CHUNK_COUNT, 4)
+forloop(i, 0, UNROLL_COUNT/CHUNK_COUNT-1, `
+	deflit(`disp0', eval(i*CHUNK_COUNT*4 ifelse(UNROLL_BYTES,256,-128)))
+	deflit(`disp1', eval(disp0 + 8))
+
+Zdisp(	movq,	disp0,(%edx), %mm0)
+	psrlq	%mm6, %mm2
+
+	movq	%mm0, %mm1
+	psllq	%mm7, %mm0
+
+	por	%mm2, %mm0
+Zdisp(	movq,	%mm0, disp0,(%edi))
+
+
+Zdisp(	movq,	disp1,(%edx), %mm0)
+	psrlq	%mm6, %mm1
+
+	movq	%mm0, %mm2
+	psllq	%mm7, %mm0
+
+	por	%mm1, %mm0
+Zdisp(	movq,	%mm0, disp1,(%edi))
+')
+
+	addl	$UNROLL_BYTES, %edx
+	addl	$UNROLL_BYTES, %edi
+	decl	%ebx
+
+	jns	L(top)
+
+
+deflit(`disp0', ifelse(UNROLL_BYTES,256,-128))
+deflit(`disp1', eval(disp0-0 + 8))
+
+	testb	$1, %al
+	psrlq	%mm6, %mm2	C wanted rshifted in all cases below
+	movl	SAVE_ESI, %esi
+
+	movd	%mm5, %eax		C return value
+
+	movl	SAVE_EBX, %ebx
+	jz	L(end_even)
+
+
+	C Size odd, destination was aligned.
+	C
+	C source
+	C       edx
+	C +-------+---------------+--
+	C |       |      mm2      |
+	C +-------+---------------+--
+	C
+	C dest                  edi
+	C +-------+---------------+---------------+--
+	C |       |               |    written    |
+	C +-------+---------------+---------------+--
+	C
+	C mm6 = shift
+	C mm7 = ecx = 64-shift
+
+
+	C Size odd, destination was unaligned.
+	C
+	C source
+	C       edx
+	C +-------+---------------+--
+	C |       |      mm2      |
+	C +-------+---------------+--
+	C
+	C dest          edi
+	C +---------------+---------------+--
+	C |               |    written    |
+	C +---------------+---------------+--
+	C
+	C mm6 = shift+32
+	C mm7 = ecx = 64-(shift+32)
+
+
+	C In both cases there's one extra limb of src to fetch and combine
+	C with mm2 to make a qword to store, and in the aligned case there's
+	C a further extra limb of dst to be formed.
+
+
+	movd	disp0(%edx), %mm0
+	movq	%mm0, %mm1
+
+	psllq	%mm7, %mm0
+	testb	$32, %cl
+
+	por	%mm2, %mm0
+	psrlq	%mm6, %mm1
+
+	movq	%mm0, disp0(%edi)
+	jz	L(finish_odd_unaligned)
+
+	movd	%mm1, disp1(%edi)
+L(finish_odd_unaligned):
+
+	movl	SAVE_EDI, %edi
+	addl	$SAVE_SIZE, %esp
+	emms
+
+	ret
+
+
+L(end_even):
+
+	C Size even, destination was aligned.
+	C
+	C source
+	C +---------------+--
+	C |      mm2      |
+	C +---------------+--
+	C
+	C dest          edi
+	C +---------------+---------------+--
+	C |               |      mm3      |
+	C +---------------+---------------+--
+	C
+	C mm6 = shift
+	C mm7 = ecx = 64-shift
+
+
+	C Size even, destination was unaligned.
+	C
+	C source
+	C +---------------+--
+	C |      mm2      |
+	C +---------------+--
+	C
+	C dest  edi
+	C +-------+---------------+--
+	C |       |      mm3      |
+	C +-------+---------------+--
+	C
+	C mm6 = shift+32
+	C mm7 = 64-(shift+32)
+
+
+	C The movd for the unaligned case is the same data as the movq for
+	C the aligned case, it's just a choice between whether one or two
+	C limbs should be written.
+
+
+	testb	$32, %cl
+	movd	%mm2, disp0(%edi)
+
+	jz	L(end_even_unaligned)
+
+	movq	%mm2, disp0(%edi)
+L(end_even_unaligned):
+
+	movl	SAVE_EDI, %edi
+	addl	$SAVE_SIZE, %esp
+	emms
+
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/k7/mod_1_1.asm b/third_party/gmp/mpn/x86/k7/mod_1_1.asm
new file mode 100644
index 0000000..1bbe6f9
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k7/mod_1_1.asm
@@ -0,0 +1,221 @@
+dnl  x86-32 mpn_mod_1_1p, requiring cmov.
+
+dnl  Contributed to the GNU project by Niels Möller and Torbjorn Granlund.
+
+dnl  Copyright 2010, 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C			    cycles/limb
+C P5				 ?
+C P6 model 0-8,10-12		 ?
+C P6 model 9  (Banias)		 ?
+C P6 model 13 (Dothan)		 ?
+C P4 model 0  (Willamette)	 ?
+C P4 model 1  (?)		 ?
+C P4 model 2  (Northwood)	 ?
+C P4 model 3  (Prescott)	 ?
+C P4 model 4  (Nocona)		 ?
+C AMD K6			 ?
+C AMD K7			 7
+C AMD K8			 ?
+
+define(`B2mb', `%ebx')
+define(`r0', `%esi')
+define(`r2', `%ebp')
+define(`t0', `%edi')
+define(`ap', `%ecx')  C Also shift count
+
+C Stack frame
+C	pre	36(%esp)
+C	b	32(%esp)
+C	n	28(%esp)
+C	ap	24(%esp)
+C	return	20(%esp)
+C	%ebp	16(%esp)
+C	%edi	12(%esp)
+C	%esi	8(%esp)
+C	%ebx	4(%esp)
+C	B2mod	(%esp)
+
+define(`B2modb', `(%esp)')
+define(`n', `28(%esp)')
+define(`b', `32(%esp)')
+define(`pre', `36(%esp)')
+
+C mp_limb_t
+C mpn_mod_1_1p (mp_srcptr ap, mp_size_t n, mp_limb_t b, mp_limb_t pre[4])
+C
+C The pre array contains bi, cnt, B1modb, B2modb
+C Note: This implementation needs B1modb only when cnt > 0
+
+ASM_START()
+	TEXT
+	ALIGN(8)
+PROLOGUE(mpn_mod_1_1p)
+	push	%ebp
+	push	%edi
+	push	%esi
+	push	%ebx
+	mov	32(%esp), %ebp		C pre[]
+
+	mov	12(%ebp), %eax		C B2modb
+	push	%eax			C Put it on stack
+
+	mov	n, %edx
+	mov	24(%esp), ap
+
+	lea	(ap, %edx, 4), ap
+	mov	-4(ap), %eax
+	cmp	$3, %edx
+	jnc	L(first)
+	mov	-8(ap), r0
+	jmp	L(reduce_two)
+
+L(first):
+	C First iteration, no r2
+	mull	B2modb
+	mov	-12(ap), r0
+	add	%eax, r0
+	mov	-8(ap), %eax
+	adc	%edx, %eax
+	sbb	r2, r2
+	subl	$3, n
+	lea	-16(ap), ap
+	jz	L(reduce_three)
+
+	mov	B2modb, B2mb
+	sub	b, B2mb
+	lea	(B2mb, r0), t0
+	jmp	L(mid)
+
+	ALIGN(16)
+L(top): C Loopmixed to 7 c/l on k7
+	add	%eax, r0
+	lea	(B2mb, r0), t0
+	mov	r2, %eax
+	adc	%edx, %eax
+	sbb	r2, r2
+L(mid):	mull	B2modb
+	and	B2modb, r2
+	add	r0, r2
+	decl	n
+	mov	(ap), r0
+	cmovc(	t0, r2)
+	lea	-4(ap), ap
+	jnz	L(top)
+
+	add	%eax, r0
+	mov	r2, %eax
+	adc	%edx, %eax
+	sbb	r2, r2
+
+L(reduce_three):
+	C Eliminate r2
+	and	b, r2
+	sub	r2, %eax
+
+L(reduce_two):
+	mov	pre, %ebp
+	movb	4(%ebp), %cl
+	test	%cl, %cl
+	jz	L(normalized)
+
+	C Unnormalized, use B1modb to reduce to size < B b
+	mull	8(%ebp)
+	xor	t0, t0
+	add	%eax, r0
+	adc	%edx, t0
+	mov	t0, %eax
+
+	C Left-shift to normalize
+	shld	%cl, r0, %eax C Always use shld?
+
+	shl	%cl, r0
+	jmp	L(udiv)
+
+L(normalized):
+	mov	%eax, t0
+	sub	b, t0
+	cmovnc(	t0, %eax)
+
+L(udiv):
+	lea	1(%eax), t0
+	mull	(%ebp)
+	mov	b, %ebx		C Needed in register for lea
+	add	r0, %eax
+	adc	t0, %edx
+	imul	%ebx, %edx
+	sub	%edx, r0
+	cmp	r0, %eax
+	lea	(%ebx, r0), %eax
+	cmovnc(	r0, %eax)
+	cmp	%ebx, %eax
+	jnc	L(fix)
+L(ok):	shr	%cl, %eax
+
+	add	$4, %esp
+	pop	%ebx
+	pop	%esi
+	pop	%edi
+	pop	%ebp
+
+	ret
+L(fix):	sub	%ebx, %eax
+	jmp	L(ok)
+EPILOGUE()
+
+PROLOGUE(mpn_mod_1_1p_cps)
+	push	%ebp
+	mov	12(%esp), %ebp
+	push	%esi
+	bsr	%ebp, %ecx
+	push	%ebx
+	xor	$31, %ecx
+	mov	16(%esp), %esi
+	sal	%cl, %ebp
+	mov	%ebp, %edx
+	not	%edx
+	mov	$-1, %eax
+	div	%ebp			C On K7, invert_limb would be a few cycles faster.
+	mov	%eax, (%esi)		C store bi
+	mov	%ecx, 4(%esi)		C store cnt
+	neg	%ebp
+	mov	$1, %edx
+	shld	%cl, %eax, %edx
+	imul	%ebp, %edx
+	shr	%cl, %edx
+	imul	%ebp, %eax
+	mov	%edx, 8(%esi)		C store B1modb
+	mov	%eax, 12(%esi)		C store B2modb
+	pop	%ebx
+	pop	%esi
+	pop	%ebp
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/k7/mod_1_4.asm b/third_party/gmp/mpn/x86/k7/mod_1_4.asm
new file mode 100644
index 0000000..bb7597e
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k7/mod_1_4.asm
@@ -0,0 +1,260 @@
+dnl  x86-32 mpn_mod_1s_4p, requiring cmov.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2009, 2010 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C			    cycles/limb
+C P5				 ?
+C P6 model 0-8,10-12		 ?
+C P6 model 9  (Banias)		 ?
+C P6 model 13 (Dothan)		 6
+C P4 model 0  (Willamette)	 ?
+C P4 model 1  (?)		 ?
+C P4 model 2  (Northwood)	15.5
+C P4 model 3  (Prescott)	 ?
+C P4 model 4  (Nocona)		 ?
+C AMD K6			 ?
+C AMD K7			 4.75
+C AMD K8			 ?
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_mod_1s_4p)
+	push	%ebp
+	push	%edi
+	push	%esi
+	push	%ebx
+	sub	$28, %esp
+	mov	60(%esp), %edi		C cps[]
+	mov	8(%edi), %eax
+	mov	12(%edi), %edx
+	mov	16(%edi), %ecx
+	mov	20(%edi), %esi
+	mov	24(%edi), %edi
+	mov	%eax, 4(%esp)
+	mov	%edx, 8(%esp)
+	mov	%ecx, 12(%esp)
+	mov	%esi, 16(%esp)
+	mov	%edi, 20(%esp)
+	mov	52(%esp), %eax		C n
+	xor	%edi, %edi
+	mov	48(%esp), %esi		C up
+	lea	-12(%esi,%eax,4), %esi
+	and	$3, %eax
+	je	L(b0)
+	cmp	$2, %eax
+	jc	L(b1)
+	je	L(b2)
+
+L(b3):	mov	4(%esi), %eax
+	mull	4(%esp)
+	mov	(%esi), %ebp
+	add	%eax, %ebp
+	adc	%edx, %edi
+	mov	8(%esi), %eax
+	mull	8(%esp)
+	lea	-12(%esi), %esi
+	jmp	L(m0)
+
+L(b0):	mov	(%esi), %eax
+	mull	4(%esp)
+	mov	-4(%esi), %ebp
+	add	%eax, %ebp
+	adc	%edx, %edi
+	mov	4(%esi), %eax
+	mull	8(%esp)
+	add	%eax, %ebp
+	adc	%edx, %edi
+	mov	8(%esi), %eax
+	mull	12(%esp)
+	lea	-16(%esi), %esi
+	jmp	L(m0)
+
+L(b1):	mov	8(%esi), %ebp
+	lea	-4(%esi), %esi
+	jmp	L(m1)
+
+L(b2):	mov	8(%esi), %edi
+	mov	4(%esi), %ebp
+	lea	-8(%esi), %esi
+	jmp	L(m1)
+
+	ALIGN(16)
+L(top):	mov	(%esi), %eax
+	mull	4(%esp)
+	mov	-4(%esi), %ebx
+	xor	%ecx, %ecx
+	add	%eax, %ebx
+	adc	%edx, %ecx
+	mov	4(%esi), %eax
+	mull	8(%esp)
+	add	%eax, %ebx
+	adc	%edx, %ecx
+	mov	8(%esi), %eax
+	mull	12(%esp)
+	add	%eax, %ebx
+	adc	%edx, %ecx
+	lea	-16(%esi), %esi
+	mov	16(%esp), %eax
+	mul	%ebp
+	add	%eax, %ebx
+	adc	%edx, %ecx
+	mov	20(%esp), %eax
+	mul	%edi
+	mov	%ebx, %ebp
+	mov	%ecx, %edi
+L(m0):	add	%eax, %ebp
+	adc	%edx, %edi
+L(m1):	subl	$4, 52(%esp)
+	ja	L(top)
+
+L(end):	mov	4(%esp), %eax
+	mul	%edi
+	mov	60(%esp), %edi
+	add	%eax, %ebp
+	adc	$0, %edx
+	mov	4(%edi), %ecx
+	mov	%edx, %esi
+	mov	%ebp, %eax
+	sal	%cl, %esi
+	mov	%ecx, %ebx
+	neg	%ecx
+	shr	%cl, %eax
+	or	%esi, %eax
+	lea	1(%eax), %esi
+	mull	(%edi)
+	mov	%ebx, %ecx
+	mov	%eax, %ebx
+	mov	%ebp, %eax
+	mov	56(%esp), %ebp
+	sal	%cl, %eax
+	add	%eax, %ebx
+	adc	%esi, %edx
+	imul	%ebp, %edx
+	sub	%edx, %eax
+	lea	(%eax,%ebp), %edx
+	cmp	%eax, %ebx
+	cmovc(	%edx, %eax)
+	mov	%eax, %edx
+	sub	%ebp, %eax
+	cmovc(	%edx, %eax)
+	add	$28, %esp
+	pop	%ebx
+	pop	%esi
+	pop	%edi
+	pop	%ebp
+	shr	%cl, %eax
+	ret
+EPILOGUE()
+
+	ALIGN(16)
+PROLOGUE(mpn_mod_1s_4p_cps)
+C CAUTION: This is the same code as in pentium4/sse2/mod_1_4.asm
+	push	%ebp
+	push	%edi
+	push	%esi
+	push	%ebx
+	mov	20(%esp), %ebp		C FIXME: avoid bp for 0-idx
+	mov	24(%esp), %ebx
+	bsr	%ebx, %ecx
+	xor	$31, %ecx
+	sal	%cl, %ebx		C b << cnt
+	mov	%ebx, %edx
+	not	%edx
+	mov	$-1, %eax
+	div	%ebx
+	xor	%edi, %edi
+	sub	%ebx, %edi
+	mov	$1, %esi
+	mov	%eax, (%ebp)		C store bi
+	mov	%ecx, 4(%ebp)		C store cnt
+	shld	%cl, %eax, %esi
+	imul	%edi, %esi
+	mov	%eax, %edi
+	mul	%esi
+
+	add	%esi, %edx
+	shr	%cl, %esi
+	mov	%esi, 8(%ebp)		C store B1modb
+
+	not	%edx
+	imul	%ebx, %edx
+	lea	(%edx,%ebx), %esi
+	cmp	%edx, %eax
+	cmovnc(	%edx, %esi)
+	mov	%edi, %eax
+	mul	%esi
+
+	add	%esi, %edx
+	shr	%cl, %esi
+	mov	%esi, 12(%ebp)		C store B2modb
+
+	not	%edx
+	imul	%ebx, %edx
+	lea	(%edx,%ebx), %esi
+	cmp	%edx, %eax
+	cmovnc(	%edx, %esi)
+	mov	%edi, %eax
+	mul	%esi
+
+	add	%esi, %edx
+	shr	%cl, %esi
+	mov	%esi, 16(%ebp)		C store B3modb
+
+	not	%edx
+	imul	%ebx, %edx
+	lea	(%edx,%ebx), %esi
+	cmp	%edx, %eax
+	cmovnc(	%edx, %esi)
+	mov	%edi, %eax
+	mul	%esi
+
+	add	%esi, %edx
+	shr	%cl, %esi
+	mov	%esi, 20(%ebp)		C store B4modb
+
+	not	%edx
+	imul	%ebx, %edx
+	add	%edx, %ebx
+	cmp	%edx, %eax
+	cmovnc(	%edx, %ebx)
+
+	shr	%cl, %ebx
+	mov	%ebx, 24(%ebp)		C store B5modb
+
+	pop	%ebx
+	pop	%esi
+	pop	%edi
+	pop	%ebp
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/k7/mod_34lsub1.asm b/third_party/gmp/mpn/x86/k7/mod_34lsub1.asm
new file mode 100644
index 0000000..ee3ad04
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k7/mod_34lsub1.asm
@@ -0,0 +1,188 @@
+dnl  AMD K7 mpn_mod_34lsub1 -- remainder modulo 2^24-1.
+
+dnl  Copyright 2000-2002, 2004, 2005, 2008 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C         cycles/limb
+C Athlon:     1
+C Hammer:     1
+
+
+C mp_limb_t mpn_mod_34lsub1 (mp_srcptr src, mp_size_t size)
+C
+C The loop form below and the 64 byte code alignment seem necessary for the
+C claimed speed.  This is a bit strange, since normally k7 isn't very
+C sensitive to such things.  Perhaps there has to be 6 instructions in the
+C first 16 bytes for the BTB entry or something.
+
+defframe(PARAM_SIZE, 8)
+defframe(PARAM_SRC,  4)
+
+dnl  re-use parameter space
+define(SAVE_EDI, `PARAM_SIZE')
+
+	TEXT
+	ALIGN(64)
+PROLOGUE(mpn_mod_34lsub1)
+deflit(`FRAME',0)
+
+	movl	PARAM_SIZE, %ecx
+	movl	PARAM_SRC, %edx
+
+	subl	$2, %ecx
+	ja	L(three_or_more)
+
+	movl	(%edx), %eax
+	jb	L(one)
+
+	movl	4(%edx), %ecx
+	movl	%eax, %edx
+	shrl	$24, %eax		C src[0] low
+
+	andl	$0xFFFFFF, %edx		C src[0] high
+	addl	%edx, %eax
+	movl	%ecx, %edx
+
+	andl	$0xFFFF, %ecx
+	shrl	$16, %edx		C src[1] high
+	addl	%edx, %eax
+
+	shll	$8, %ecx		C src[1] low
+	addl	%ecx, %eax
+
+L(one):
+	ret
+
+
+L(three_or_more):
+	C eax
+	C ebx
+	C ecx	size-2
+	C edx	src
+	C esi
+	C edi
+
+	pushl	%ebx	FRAME_pushl()
+	xorl	%eax, %eax
+	xorl	%ebx, %ebx
+
+	movl	%edi, SAVE_EDI
+	pushl	%esi	FRAME_pushl()
+	xorl	%esi, %esi		C and clear carry flag
+
+
+	C code offset 0x40 at this point
+L(top):
+	C eax	acc 0mod3
+	C ebx	acc 1mod3
+	C ecx	counter, limbs
+	C edx	src
+	C esi	acc 2mod3
+	C edi
+
+	leal	24(%edx), %edx
+	leal	-2(%ecx), %ecx
+	adcl	-24(%edx), %eax
+	adcl	-20(%edx), %ebx
+	adcl	-16(%edx), %esi
+
+	decl	%ecx
+	jng	L(done_loop)
+
+	leal	-2(%ecx), %ecx
+	adcl	-12(%edx), %eax
+	adcl	-8(%edx), %ebx
+	adcl	-4(%edx), %esi
+
+	decl	%ecx
+	jg	L(top)
+
+
+	leal	12(%edx), %edx
+
+
+L(done_loop):
+	C ecx is -2, -1 or 0 representing 0, 1 or 2 more limbs, respectively
+
+	incl	%ecx
+	movl	$0xFFFFFFFF, %edi
+	js	L(combine)
+
+	adcl	-12(%edx), %eax
+	decl	%ecx
+	movl	$0xFFFFFF00, %edi
+	js	L(combine)
+
+	adcl	-8(%edx), %ebx
+	movl	$0xFFFF0000, %edi
+
+
+L(combine):
+	C eax	acc 0mod3
+	C ebx	acc 1mod3
+	C ecx
+	C edx
+	C esi	acc 2mod3
+	C edi	mask
+
+	sbbl	%ecx, %ecx		C carry
+	movl	%eax, %edx		C 0mod3
+	shrl	$24, %eax		C 0mod3 high
+
+	andl	%edi, %ecx		C carry masked
+	andl	$0x00FFFFFF, %edx	C 0mod3 low
+	movl	%ebx, %edi		C 1mod3
+
+	subl	%ecx, %eax		C apply carry
+	shrl	$16, %ebx		C 1mod3 high
+	andl	$0xFFFF, %edi
+
+	addl	%edx, %eax		C apply 0mod3 low
+	movl	%esi, %edx		C 2mod3
+	shll	$8, %edi		C 1mod3 low
+
+	addl	%ebx, %eax		C apply 1mod3 high
+	shrl	$8, %esi		C 2mod3 high
+	movzbl	%dl, %edx		C 2mod3 low
+
+	addl	%edi, %eax		C apply 1mod3 low
+	shll	$16, %edx		C 2mod3 low
+
+	addl	%esi, %eax		C apply 2mod3 high
+	popl	%esi	FRAME_popl()
+
+	movl	SAVE_EDI, %edi
+	addl	%edx, %eax		C apply 2mod3 low
+	popl	%ebx	FRAME_popl()
+
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/k7/mode1o.asm b/third_party/gmp/mpn/x86/k7/mode1o.asm
new file mode 100644
index 0000000..2394033
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k7/mode1o.asm
@@ -0,0 +1,181 @@
+dnl  AMD K7 mpn_modexact_1_odd -- exact division style remainder.
+
+dnl  Copyright 2000-2002, 2004, 2007 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C          cycles/limb
+C Athlon:     11.0
+C Hammer:      7.0
+
+
+C mp_limb_t mpn_modexact_1_odd (mp_srcptr src, mp_size_t size,
+C                               mp_limb_t divisor);
+C mp_limb_t mpn_modexact_1c_odd (mp_srcptr src, mp_size_t size,
+C                                mp_limb_t divisor, mp_limb_t carry);
+C
+C With the loop running at just 11 cycles it doesn't seem worth bothering to
+C check for high<divisor to save one step.
+C
+C Using a divl for size==1 measures slower than the modexact method, which
+C is not too surprising since for the latter it's only about 24 cycles to
+C calculate the modular inverse.
+
+defframe(PARAM_CARRY,  16)
+defframe(PARAM_DIVISOR,12)
+defframe(PARAM_SIZE,   8)
+defframe(PARAM_SRC,    4)
+
+defframe(SAVE_EBX,     -4)
+defframe(SAVE_ESI,     -8)
+defframe(SAVE_EDI,    -12)
+defframe(SAVE_EBP,    -16)
+
+deflit(STACK_SPACE, 16)
+
+	TEXT
+
+	ALIGN(16)
+PROLOGUE(mpn_modexact_1c_odd)
+deflit(`FRAME',0)
+
+	movl	PARAM_CARRY, %ecx
+	jmp	L(start_1c)
+
+EPILOGUE()
+
+
+	ALIGN(16)
+PROLOGUE(mpn_modexact_1_odd)
+deflit(`FRAME',0)
+
+	xorl	%ecx, %ecx
+L(start_1c):
+	movl	PARAM_DIVISOR, %eax
+	subl	$STACK_SPACE, %esp	FRAME_subl_esp(STACK_SPACE)
+
+	movl	%esi, SAVE_ESI
+	movl	PARAM_DIVISOR, %esi
+
+	movl	%edi, SAVE_EDI
+
+	shrl	%eax			C d/2
+
+	andl	$127, %eax
+
+ifdef(`PIC',`
+	LEA(	binvert_limb_table, %edi)
+	movzbl	(%eax,%edi), %edi		C inv 8 bits
+',`
+	movzbl	binvert_limb_table(%eax), %edi	C inv 8 bits
+')
+
+	xorl	%edx, %edx		C initial extra carry
+	leal	(%edi,%edi), %eax	C 2*inv
+
+	imull	%edi, %edi		C inv*inv
+
+	movl	%ebp, SAVE_EBP
+	movl	PARAM_SIZE, %ebp
+
+	movl	%ebx, SAVE_EBX
+	movl	PARAM_SRC, %ebx
+
+	imull	%esi, %edi		C inv*inv*d
+
+	subl	%edi, %eax		C inv = 2*inv - inv*inv*d
+	leal	(%eax,%eax), %edi	C 2*inv
+
+	imull	%eax, %eax		C inv*inv
+
+	imull	%esi, %eax		C inv*inv*d
+
+	leal	(%ebx,%ebp,4), %ebx	C src end
+	negl	%ebp			C -size
+
+	subl	%eax, %edi		C inv = 2*inv - inv*inv*d
+
+	ASSERT(e,`	C d*inv == 1 mod 2^GMP_LIMB_BITS
+	movl	%esi, %eax
+	imull	%edi, %eax
+	cmpl	$1, %eax')
+
+
+C The dependent chain here is
+C
+C                            cycles
+C	subl	%edx, %eax	1
+C	imull	%edi, %eax	4
+C	mull	%esi		6  (high limb)
+C			      ----
+C       total		       11
+C
+C Out of order execution hides the load latency for the source data, so no
+C special scheduling is required.
+
+L(top):
+	C eax	src limb
+	C ebx	src end ptr
+	C ecx	next carry bit, 0 or 1 (or initial carry param)
+	C edx	carry limb, high of last product
+	C esi	divisor
+	C edi	inverse
+	C ebp	counter, limbs, negative
+
+	movl	(%ebx,%ebp,4), %eax
+
+	subl	%ecx, %eax		C apply carry bit
+	movl	$0, %ecx
+
+	setc	%cl			C new carry bit
+
+	subl	%edx, %eax		C apply carry limb
+	adcl	$0, %ecx
+
+	imull	%edi, %eax
+
+	mull	%esi
+
+	incl	%ebp
+	jnz	L(top)
+
+
+	movl	SAVE_ESI, %esi
+	movl	SAVE_EDI, %edi
+	leal	(%ecx,%edx), %eax
+
+	movl	SAVE_EBX, %ebx
+	movl	SAVE_EBP, %ebp
+	addl	$STACK_SPACE, %esp
+
+	ret
+
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86/k7/mul_1.asm b/third_party/gmp/mpn/x86/k7/mul_1.asm
new file mode 100644
index 0000000..755cd2e
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k7/mul_1.asm
@@ -0,0 +1,237 @@
+dnl  AMD K7 mpn_mul_1.
+
+dnl  Copyright 1999-2002, 2005, 2008 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C			    cycles/limb
+C P5
+C P6 model 0-8,10-12)
+C P6 model 9  (Banias)
+C P6 model 13 (Dothan)
+C P4 model 0  (Willamette)
+C P4 model 1  (?)
+C P4 model 2  (Northwood)
+C P4 model 3  (Prescott)
+C P4 model 4  (Nocona)
+C AMD K6
+C AMD K7			 3.25
+C AMD K8
+
+C TODO
+C  * Improve feed-in and wind-down code.  We beat the old code for all n != 1,
+C    but we might be able to do even better.
+C  * The feed-in code for mul_1c is crude.
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_mul_1c)
+	add	$-16, %esp
+	mov	%ebp, (%esp)
+	mov	%ebx, 4(%esp)
+	mov	%esi, 8(%esp)
+	mov	%edi, 12(%esp)
+
+	mov	20(%esp), %edi
+	mov	24(%esp), %esi
+	mov	28(%esp), %ebp
+	mov	32(%esp), %ecx
+	mov	%ebp, %ebx
+	shr	$2, %ebp
+	mov	%ebp, 28(%esp)
+	mov	(%esi), %eax
+	and	$3, %ebx
+	jz	L(c0)
+	cmp	$2, %ebx
+	mov	36(%esp), %ebx
+	jz	L(c2)
+	jg	L(c3)
+
+L(c1):	lea	-4(%edi), %edi
+	mul	%ecx
+	test	%ebp, %ebp
+	jnz	1f
+	add	%ebx, %eax
+	mov	%eax, 4(%edi)
+	mov	%edx, %eax
+	adc	%ebp, %eax
+	jmp	L(rt)
+1:	add	%eax, %ebx
+	mov	$0, %ebp
+	adc	%edx, %ebp
+	mov	4(%esi), %eax
+	jmp	L(1)
+
+L(c2):	lea	4(%esi), %esi
+	mul	%ecx
+	test	%ebp, %ebp
+	mov	%ebx, %ebp
+	jnz	2f
+	add	%eax, %ebp
+	mov	$0, %ebx
+	adc	%edx, %ebx
+	mov	(%esi), %eax
+	jmp	L(cj2)
+2:	add	%eax, %ebp
+	mov	$0, %ebx
+	adc	%edx, %ebx
+	mov	(%esi), %eax
+	jmp	L(2)
+
+L(c3):	lea	8(%esi), %esi
+	lea	-12(%edi), %edi
+	mul	%ecx
+	add	%eax, %ebx
+	mov	$0, %ebp
+	adc	%edx, %ebp
+	mov	-4(%esi), %eax
+	incl	28(%esp)
+	jmp	L(3)
+
+L(c0):	mov	36(%esp), %ebx
+	lea	-4(%esi), %esi
+	lea	-8(%edi), %edi
+	mul	%ecx
+	mov	%ebx, %ebp
+	add	%eax, %ebp
+	mov	$0, %ebx
+	adc	%edx, %ebx
+	mov	8(%esi), %eax
+	jmp	L(0)
+
+EPILOGUE()
+	ALIGN(16)
+PROLOGUE(mpn_mul_1)
+	add	$-16, %esp
+	mov	%ebp, (%esp)
+	mov	%ebx, 4(%esp)
+	mov	%esi, 8(%esp)
+	mov	%edi, 12(%esp)
+
+	mov	20(%esp), %edi
+	mov	24(%esp), %esi
+	mov	28(%esp), %ebp
+	mov	32(%esp), %ecx
+	mov	%ebp, %ebx
+	shr	$2, %ebp
+	mov	%ebp, 28(%esp)
+	mov	(%esi), %eax
+	and	$3, %ebx
+	jz	L(b0)
+	cmp	$2, %ebx
+	jz	L(b2)
+	jg	L(b3)
+
+L(b1):	lea	-4(%edi), %edi
+	mul	%ecx
+	test	%ebp, %ebp
+	jnz	L(gt1)
+	mov	%eax, 4(%edi)
+	mov	%edx, %eax
+	jmp	L(rt)
+L(gt1):	mov	%eax, %ebx
+	mov	%edx, %ebp
+	mov	4(%esi), %eax
+	jmp	L(1)
+
+L(b2):	lea	4(%esi), %esi
+	mul	%ecx
+	test	%ebp, %ebp
+	mov	%eax, %ebp
+	mov	%edx, %ebx
+	mov	(%esi), %eax
+	jnz	L(2)
+	jmp	L(cj2)
+
+L(b3):	lea	8(%esi), %esi
+	lea	-12(%edi), %edi
+	mul	%ecx
+	mov	%eax, %ebx
+	mov	%edx, %ebp
+	mov	-4(%esi), %eax
+	incl	28(%esp)
+	jmp	L(3)
+
+L(b0):	lea	-4(%esi), %esi
+	lea	-8(%edi), %edi
+	mul	%ecx
+	mov	%eax, %ebp
+	mov	%edx, %ebx
+	mov	8(%esi), %eax
+	jmp	L(0)
+
+	ALIGN(16)
+L(top):	mov	$0, %ebx
+	adc	%edx, %ebx
+L(2):	mul	%ecx
+	add	%eax, %ebx
+	mov	%ebp, 0(%edi)
+	mov	4(%esi), %eax
+	mov	$0, %ebp
+	adc	%edx, %ebp
+L(1):	mul	%ecx
+	add	%eax, %ebp
+	mov	8(%esi), %eax
+	mov	%ebx, 4(%edi)
+	mov	$0, %ebx
+	adc	%edx, %ebx
+L(0):	mov	%ebp, 8(%edi)
+	mul	%ecx
+	add	%eax, %ebx
+	mov	12(%esi), %eax
+	lea	16(%esi), %esi
+	mov	$0, %ebp
+	adc	%edx, %ebp
+L(3):	mov	%ebx, 12(%edi)
+	mul	%ecx
+	lea	16(%edi), %edi
+	add	%eax, %ebp
+	decl	28(%esp)
+	mov	0(%esi), %eax
+	jnz	L(top)
+
+L(end):	mov	$0, %ebx
+	adc	%edx, %ebx
+L(cj2):	mul	%ecx
+	add	%eax, %ebx
+	mov	%ebp, (%edi)
+L(cj1):	mov	%ebx, 4(%edi)
+	adc	$0, %edx
+	mov	%edx, %eax
+
+L(rt):	mov	(%esp), %ebp
+	mov	4(%esp), %ebx
+	mov	8(%esp), %esi
+	mov	12(%esp), %edi
+	add	$16, %esp
+	ret
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86/k7/mul_basecase.asm b/third_party/gmp/mpn/x86/k7/mul_basecase.asm
new file mode 100644
index 0000000..4dfb500
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k7/mul_basecase.asm
@@ -0,0 +1,602 @@
+dnl  AMD K7 mpn_mul_basecase -- multiply two mpn numbers.
+
+dnl  Copyright 1999-2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C K7: approx 4.42 cycles per cross product at around 20x20 limbs (16
+C     limbs/loop unrolling).
+
+
+
+dnl  K7 UNROLL_COUNT cycles/product (at around 20x20)
+dnl           8           4.67
+dnl          16           4.59
+dnl          32           4.42
+dnl  Maximum possible with the current code is 32.
+dnl
+dnl  At 32 the typical 13-26 limb sizes from the karatsuba code will get
+dnl  done with a straight run through a block of code, no inner loop.  Using
+dnl  32 gives 1k of code, but the k7 has a 64k L1 code cache.
+
+deflit(UNROLL_COUNT, 32)
+
+
+C void mpn_mul_basecase (mp_ptr wp,
+C                        mp_srcptr xp, mp_size_t xsize,
+C                        mp_srcptr yp, mp_size_t ysize);
+C
+C Calculate xp,xsize multiplied by yp,ysize, storing the result in
+C wp,xsize+ysize.
+C
+C This routine is essentially the same as mpn/generic/mul_basecase.c, but
+C it's faster because it does most of the mpn_addmul_1() startup
+C calculations only once.  The saving is 15-25% on typical sizes coming from
+C the Karatsuba multiply code.
+
+ifdef(`PIC',`
+deflit(UNROLL_THRESHOLD, 5)
+',`
+deflit(UNROLL_THRESHOLD, 5)
+')
+
+defframe(PARAM_YSIZE,20)
+defframe(PARAM_YP,   16)
+defframe(PARAM_XSIZE,12)
+defframe(PARAM_XP,   8)
+defframe(PARAM_WP,   4)
+
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_mul_basecase)
+deflit(`FRAME',0)
+
+	movl	PARAM_XSIZE, %ecx
+	movl	PARAM_YP, %eax
+
+	movl	PARAM_XP, %edx
+	movl	(%eax), %eax	C yp low limb
+
+	cmpl	$2, %ecx
+	ja	L(xsize_more_than_two)
+	je	L(two_by_something)
+
+
+	C one limb by one limb
+
+	mull	(%edx)
+
+	movl	PARAM_WP, %ecx
+	movl	%eax, (%ecx)
+	movl	%edx, 4(%ecx)
+	ret
+
+
+C -----------------------------------------------------------------------------
+L(two_by_something):
+deflit(`FRAME',0)
+	decl	PARAM_YSIZE
+	pushl	%ebx		defframe_pushl(`SAVE_EBX')
+	movl	%eax, %ecx	C yp low limb
+
+	movl	PARAM_WP, %ebx
+	pushl	%esi		defframe_pushl(`SAVE_ESI')
+	movl	%edx, %esi	C xp
+
+	movl	(%edx), %eax	C xp low limb
+	jnz	L(two_by_two)
+
+
+	C two limbs by one limb
+
+	mull	%ecx
+
+	movl	%eax, (%ebx)
+	movl	4(%esi), %eax
+	movl	%edx, %esi	C carry
+
+	mull	%ecx
+
+	addl	%eax, %esi
+
+	movl	%esi, 4(%ebx)
+	movl	SAVE_ESI, %esi
+
+	adcl	$0, %edx
+
+	movl	%edx, 8(%ebx)
+	movl	SAVE_EBX, %ebx
+	addl	$FRAME, %esp
+
+	ret
+
+
+
+C -----------------------------------------------------------------------------
+C Could load yp earlier into another register.
+
+	ALIGN(16)
+L(two_by_two):
+	C eax	xp low limb
+	C ebx	wp
+	C ecx	yp low limb
+	C edx
+	C esi	xp
+	C edi
+	C ebp
+
+dnl  FRAME carries on from previous
+
+	mull	%ecx		C xp[0] * yp[0]
+
+	push	%edi		defframe_pushl(`SAVE_EDI')
+	movl	%edx, %edi	C carry, for wp[1]
+
+	movl	%eax, (%ebx)
+	movl	4(%esi), %eax
+
+	mull	%ecx		C xp[1] * yp[0]
+
+	addl	%eax, %edi
+	movl	PARAM_YP, %ecx
+
+	adcl	$0, %edx
+	movl	4(%ecx), %ecx	C yp[1]
+	movl	%edi, 4(%ebx)
+
+	movl	4(%esi), %eax	C xp[1]
+	movl	%edx, %edi	C carry, for wp[2]
+
+	mull	%ecx		C xp[1] * yp[1]
+
+	addl	%eax, %edi
+
+	adcl	$0, %edx
+	movl	(%esi), %eax	C xp[0]
+
+	movl	%edx, %esi	C carry, for wp[3]
+
+	mull	%ecx		C xp[0] * yp[1]
+
+	addl	%eax, 4(%ebx)
+	adcl	%edx, %edi
+	movl	%edi, 8(%ebx)
+
+	adcl	$0, %esi
+	movl	SAVE_EDI, %edi
+	movl	%esi, 12(%ebx)
+
+	movl	SAVE_ESI, %esi
+	movl	SAVE_EBX, %ebx
+	addl	$FRAME, %esp
+
+	ret
+
+
+C -----------------------------------------------------------------------------
+	ALIGN(16)
+L(xsize_more_than_two):
+
+C The first limb of yp is processed with a simple mpn_mul_1 style loop
+C inline.  Unrolling this doesn't seem worthwhile since it's only run once
+C (whereas the addmul below is run ysize-1 many times).  A call to the
+C actual mpn_mul_1 will be slowed down by the call and parameter pushing and
+C popping, and doesn't seem likely to be worthwhile on the typical 13-26
+C limb operations the Karatsuba code calls here with.
+
+	C eax	yp[0]
+	C ebx
+	C ecx	xsize
+	C edx	xp
+	C esi
+	C edi
+	C ebp
+
+dnl  FRAME doesn't carry on from previous, no pushes yet here
+defframe(`SAVE_EBX',-4)
+defframe(`SAVE_ESI',-8)
+defframe(`SAVE_EDI',-12)
+defframe(`SAVE_EBP',-16)
+deflit(`FRAME',0)
+
+	subl	$16, %esp
+deflit(`FRAME',16)
+
+	movl	%edi, SAVE_EDI
+	movl	PARAM_WP, %edi
+
+	movl	%ebx, SAVE_EBX
+	movl	%ebp, SAVE_EBP
+	movl	%eax, %ebp
+
+	movl	%esi, SAVE_ESI
+	xorl	%ebx, %ebx
+	leal	(%edx,%ecx,4), %esi	C xp end
+
+	leal	(%edi,%ecx,4), %edi	C wp end of mul1
+	negl	%ecx
+
+
+L(mul1):
+	C eax	scratch
+	C ebx	carry
+	C ecx	counter, negative
+	C edx	scratch
+	C esi	xp end
+	C edi	wp end of mul1
+	C ebp	multiplier
+
+	movl	(%esi,%ecx,4), %eax
+
+	mull	%ebp
+
+	addl	%ebx, %eax
+	movl	%eax, (%edi,%ecx,4)
+	movl	$0, %ebx
+
+	adcl	%edx, %ebx
+	incl	%ecx
+	jnz	L(mul1)
+
+
+	movl	PARAM_YSIZE, %edx
+	movl	PARAM_XSIZE, %ecx
+
+	movl	%ebx, (%edi)		C final carry
+	decl	%edx
+
+	jnz	L(ysize_more_than_one)
+
+
+	movl	SAVE_EDI, %edi
+	movl	SAVE_EBX, %ebx
+
+	movl	SAVE_EBP, %ebp
+	movl	SAVE_ESI, %esi
+	addl	$FRAME, %esp
+
+	ret
+
+
+L(ysize_more_than_one):
+	cmpl	$UNROLL_THRESHOLD, %ecx
+	movl	PARAM_YP, %eax
+
+	jae	L(unroll)
+
+
+C -----------------------------------------------------------------------------
+	C simple addmul looping
+	C
+	C eax	yp
+	C ebx
+	C ecx	xsize
+	C edx	ysize-1
+	C esi	xp end
+	C edi	wp end of mul1
+	C ebp
+
+	leal	4(%eax,%edx,4), %ebp	C yp end
+	negl	%ecx
+	negl	%edx
+
+	movl	(%esi,%ecx,4), %eax	C xp low limb
+	movl	%edx, PARAM_YSIZE	C -(ysize-1)
+	incl	%ecx
+
+	xorl	%ebx, %ebx		C initial carry
+	movl	%ecx, PARAM_XSIZE	C -(xsize-1)
+	movl	%ebp, PARAM_YP
+
+	movl	(%ebp,%edx,4), %ebp	C yp second lowest limb - multiplier
+	jmp	L(simple_outer_entry)
+
+
+	C this is offset 0x121 so close enough to aligned
+L(simple_outer_top):
+	C ebp	ysize counter, negative
+
+	movl	PARAM_YP, %edx
+	movl	PARAM_XSIZE, %ecx	C -(xsize-1)
+	xorl	%ebx, %ebx		C carry
+
+	movl	%ebp, PARAM_YSIZE
+	addl	$4, %edi		C next position in wp
+
+	movl	(%edx,%ebp,4), %ebp	C yp limb - multiplier
+	movl	-4(%esi,%ecx,4), %eax	C xp low limb
+
+
+L(simple_outer_entry):
+
+L(simple_inner):
+	C eax	xp limb
+	C ebx	carry limb
+	C ecx	loop counter (negative)
+	C edx	scratch
+	C esi	xp end
+	C edi	wp end
+	C ebp	multiplier
+
+	mull	%ebp
+
+	addl	%eax, %ebx
+	adcl	$0, %edx
+
+	addl	%ebx, (%edi,%ecx,4)
+	movl	(%esi,%ecx,4), %eax
+	adcl	$0, %edx
+
+	incl	%ecx
+	movl	%edx, %ebx
+	jnz	L(simple_inner)
+
+
+	mull	%ebp
+
+	movl	PARAM_YSIZE, %ebp
+	addl	%eax, %ebx
+
+	adcl	$0, %edx
+	addl	%ebx, (%edi)
+
+	adcl	$0, %edx
+	incl	%ebp
+
+	movl	%edx, 4(%edi)
+	jnz	L(simple_outer_top)
+
+
+	movl	SAVE_EBX, %ebx
+	movl	SAVE_ESI, %esi
+
+	movl	SAVE_EDI, %edi
+	movl	SAVE_EBP, %ebp
+	addl	$FRAME, %esp
+
+	ret
+
+
+
+C -----------------------------------------------------------------------------
+C
+C The unrolled loop is the same as in mpn_addmul_1(), see that code for some
+C comments.
+C
+C VAR_ADJUST is the negative of how many limbs the leals in the inner loop
+C increment xp and wp.  This is used to adjust back xp and wp, and rshifted
+C to given an initial VAR_COUNTER at the top of the outer loop.
+C
+C VAR_COUNTER is for the unrolled loop, running from VAR_ADJUST/UNROLL_COUNT
+C up to -1, inclusive.
+C
+C VAR_JMP is the computed jump into the unrolled loop.
+C
+C VAR_XP_LOW is the least significant limb of xp, which is needed at the
+C start of the unrolled loop.
+C
+C PARAM_YSIZE is the outer loop counter, going from -(ysize-1) up to -1,
+C inclusive.
+C
+C PARAM_YP is offset appropriately so that the PARAM_YSIZE counter can be
+C added to give the location of the next limb of yp, which is the multiplier
+C in the unrolled loop.
+C
+C The trick with VAR_ADJUST means it's only necessary to do one fetch in the
+C outer loop to take care of xp, wp and the inner loop counter.
+
+defframe(VAR_COUNTER,  -20)
+defframe(VAR_ADJUST,   -24)
+defframe(VAR_JMP,      -28)
+defframe(VAR_XP_LOW,   -32)
+deflit(VAR_EXTRA_SPACE, 16)
+
+
+L(unroll):
+	C eax	yp
+	C ebx
+	C ecx	xsize
+	C edx	ysize-1
+	C esi	xp end
+	C edi	wp end of mul1
+	C ebp
+
+	movl	PARAM_XP, %esi
+	movl	4(%eax), %ebp		C multiplier (yp second limb)
+	leal	4(%eax,%edx,4), %eax	C yp adjust for ysize indexing
+
+	movl	PARAM_WP, %edi
+	movl	%eax, PARAM_YP
+	negl	%edx
+
+	movl	%edx, PARAM_YSIZE
+	leal	UNROLL_COUNT-2(%ecx), %ebx	C (xsize-1)+UNROLL_COUNT-1
+	decl	%ecx				C xsize-1
+
+	movl	(%esi), %eax		C xp low limb
+	andl	$-UNROLL_MASK-1, %ebx
+	negl	%ecx
+
+	subl	$VAR_EXTRA_SPACE, %esp
+deflit(`FRAME',16+VAR_EXTRA_SPACE)
+	negl	%ebx
+	andl	$UNROLL_MASK, %ecx
+
+	movl	%ebx, VAR_ADJUST
+	movl	%ecx, %edx
+	shll	$4, %ecx
+
+	sarl	$UNROLL_LOG2, %ebx
+
+	C 17 code bytes per limb
+ifdef(`PIC',`
+	call	L(pic_calc)
+L(unroll_here):
+',`
+	leal	L(unroll_entry) (%ecx,%edx,1), %ecx
+')
+	negl	%edx
+
+	movl	%eax, VAR_XP_LOW
+	movl	%ecx, VAR_JMP
+	leal	4(%edi,%edx,4), %edi	C wp and xp, adjust for unrolling,
+	leal	4(%esi,%edx,4), %esi	C  and start at second limb
+	jmp	L(unroll_outer_entry)
+
+
+ifdef(`PIC',`
+L(pic_calc):
+	C See mpn/x86/README about old gas bugs
+	leal	(%ecx,%edx,1), %ecx
+	addl	$L(unroll_entry)-L(unroll_here), %ecx
+	addl	(%esp), %ecx
+	ret_internal
+')
+
+
+C --------------------------------------------------------------------------
+	ALIGN(32)
+L(unroll_outer_top):
+	C ebp	ysize counter, negative
+
+	movl	VAR_ADJUST, %ebx
+	movl	PARAM_YP, %edx
+
+	movl	VAR_XP_LOW, %eax
+	movl	%ebp, PARAM_YSIZE	C store incremented ysize counter
+
+	leal	4(%edi,%ebx,4), %edi
+	leal	(%esi,%ebx,4), %esi
+	sarl	$UNROLL_LOG2, %ebx
+
+	movl	(%edx,%ebp,4), %ebp	C yp next multiplier
+	movl	VAR_JMP, %ecx
+
+L(unroll_outer_entry):
+	mull	%ebp
+
+	testb	$1, %cl		C and clear carry bit
+	movl	%ebx, VAR_COUNTER
+	movl	$0, %ebx
+
+	movl	$0, %ecx
+	cmovz(	%eax, %ecx)	C eax into low carry, zero into high carry limb
+	cmovnz(	%eax, %ebx)
+
+	C Extra fetch of VAR_JMP is bad, but registers are tight
+	jmp	*VAR_JMP
+
+
+C -----------------------------------------------------------------------------
+	ALIGN(32)
+L(unroll_top):
+	C eax	xp limb
+	C ebx	carry high
+	C ecx	carry low
+	C edx	scratch
+	C esi	xp+8
+	C edi	wp
+	C ebp	yp multiplier limb
+	C
+	C VAR_COUNTER  loop counter, negative
+	C
+	C 17 bytes each limb
+
+L(unroll_entry):
+
+deflit(CHUNK_COUNT,2)
+forloop(`i', 0, UNROLL_COUNT/CHUNK_COUNT-1, `
+	deflit(`disp0', eval(i*CHUNK_COUNT*4 ifelse(UNROLL_BYTES,256,-128)))
+	deflit(`disp1', eval(disp0 + 4))
+
+Zdisp(	movl,	disp0,(%esi), %eax)
+	adcl	%edx, %ebx
+
+	mull	%ebp
+
+Zdisp(	addl,	%ecx, disp0,(%edi))
+	movl	$0, %ecx
+
+	adcl	%eax, %ebx
+
+
+	movl	disp1(%esi), %eax
+	adcl	%edx, %ecx
+
+	mull	%ebp
+
+	addl	%ebx, disp1(%edi)
+	movl	$0, %ebx
+
+	adcl	%eax, %ecx
+')
+
+
+	incl	VAR_COUNTER
+	leal	UNROLL_BYTES(%esi), %esi
+	leal	UNROLL_BYTES(%edi), %edi
+
+	jnz	L(unroll_top)
+
+
+	C eax
+	C ebx	zero
+	C ecx	low
+	C edx	high
+	C esi
+	C edi	wp, pointing at second last limb)
+	C ebp
+	C
+	C carry flag to be added to high
+
+deflit(`disp0', ifelse(UNROLL_BYTES,256,-128))
+deflit(`disp1', eval(disp0-0 + 4))
+
+	movl	PARAM_YSIZE, %ebp
+	adcl	$0, %edx
+	addl	%ecx, disp0(%edi)
+
+	adcl	$0, %edx
+	incl	%ebp
+
+	movl	%edx, disp1(%edi)
+	jnz	L(unroll_outer_top)
+
+
+	movl	SAVE_ESI, %esi
+	movl	SAVE_EBP, %ebp
+
+	movl	SAVE_EDI, %edi
+	movl	SAVE_EBX, %ebx
+	addl	$FRAME, %esp
+
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/k7/sqr_basecase.asm b/third_party/gmp/mpn/x86/k7/sqr_basecase.asm
new file mode 100644
index 0000000..7b6a97e
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k7/sqr_basecase.asm
@@ -0,0 +1,635 @@
+dnl  AMD K7 mpn_sqr_basecase -- square an mpn number.
+
+dnl  Copyright 1999-2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C K7: approx 2.3 cycles/crossproduct, or 4.55 cycles/triangular product
+C     (measured on the speed difference between 25 and 50 limbs, which is
+C     roughly the Karatsuba recursing range).
+
+
+dnl  These are the same as mpn/x86/k6/sqr_basecase.asm, see that code for
+dnl  some comments.
+
+deflit(SQR_TOOM2_THRESHOLD_MAX, 66)
+
+ifdef(`SQR_TOOM2_THRESHOLD_OVERRIDE',
+`define(`SQR_TOOM2_THRESHOLD',SQR_TOOM2_THRESHOLD_OVERRIDE)')
+
+m4_config_gmp_mparam(`SQR_TOOM2_THRESHOLD')
+deflit(UNROLL_COUNT, eval(SQR_TOOM2_THRESHOLD-3))
+
+
+C void mpn_sqr_basecase (mp_ptr dst, mp_srcptr src, mp_size_t size);
+C
+C With a SQR_TOOM2_THRESHOLD around 50 this code is about 1500 bytes,
+C which is quite a bit, but is considered good value since squares big
+C enough to use most of the code will be spending quite a few cycles in it.
+
+
+defframe(PARAM_SIZE,12)
+defframe(PARAM_SRC, 8)
+defframe(PARAM_DST, 4)
+
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_sqr_basecase)
+deflit(`FRAME',0)
+
+	movl	PARAM_SIZE, %ecx
+	movl	PARAM_SRC, %eax
+	cmpl	$2, %ecx
+
+	movl	PARAM_DST, %edx
+	je	L(two_limbs)
+	ja	L(three_or_more)
+
+
+C------------------------------------------------------------------------------
+C one limb only
+	C eax	src
+	C ecx	size
+	C edx	dst
+
+	movl	(%eax), %eax
+	movl	%edx, %ecx
+
+	mull	%eax
+
+	movl	%edx, 4(%ecx)
+	movl	%eax, (%ecx)
+	ret
+
+
+C------------------------------------------------------------------------------
+C
+C Using the read/modify/write "add"s seems to be faster than saving and
+C restoring registers.  Perhaps the loads for the first set hide under the
+C mul latency and the second gets store to load forwarding.
+
+	ALIGN(16)
+L(two_limbs):
+	C eax	src
+	C ebx
+	C ecx	size
+	C edx	dst
+deflit(`FRAME',0)
+
+	pushl	%ebx		FRAME_pushl()
+	movl	%eax, %ebx	C src
+	movl	(%eax), %eax
+
+	movl	%edx, %ecx	C dst
+
+	mull	%eax		C src[0]^2
+
+	movl	%eax, (%ecx)	C dst[0]
+	movl	4(%ebx), %eax
+
+	movl	%edx, 4(%ecx)	C dst[1]
+
+	mull	%eax		C src[1]^2
+
+	movl	%eax, 8(%ecx)	C dst[2]
+	movl	(%ebx), %eax
+
+	movl	%edx, 12(%ecx)	C dst[3]
+
+	mull	4(%ebx)		C src[0]*src[1]
+
+	popl	%ebx
+
+	addl	%eax, 4(%ecx)
+	adcl	%edx, 8(%ecx)
+	adcl	$0, 12(%ecx)
+	ASSERT(nc)
+
+	addl	%eax, 4(%ecx)
+	adcl	%edx, 8(%ecx)
+	adcl	$0, 12(%ecx)
+	ASSERT(nc)
+
+	ret
+
+
+C------------------------------------------------------------------------------
+defframe(SAVE_EBX,  -4)
+defframe(SAVE_ESI,  -8)
+defframe(SAVE_EDI, -12)
+defframe(SAVE_EBP, -16)
+deflit(STACK_SPACE, 16)
+
+L(three_or_more):
+	subl	$STACK_SPACE, %esp
+	cmpl	$4, %ecx
+	jae	L(four_or_more)
+deflit(`FRAME',STACK_SPACE)
+
+
+C------------------------------------------------------------------------------
+C Three limbs
+C
+C Writing out the loads and stores separately at the end of this code comes
+C out about 10 cycles faster than using adcls to memory.
+
+	C eax	src
+	C ecx	size
+	C edx	dst
+
+	movl	%ebx, SAVE_EBX
+	movl	%eax, %ebx	C src
+	movl	(%eax), %eax
+
+	movl	%edx, %ecx	C dst
+	movl	%esi, SAVE_ESI
+	movl	%edi, SAVE_EDI
+
+	mull	%eax		C src[0] ^ 2
+
+	movl	%eax, (%ecx)
+	movl	4(%ebx), %eax
+	movl	%edx, 4(%ecx)
+
+	mull	%eax		C src[1] ^ 2
+
+	movl	%eax, 8(%ecx)
+	movl	8(%ebx), %eax
+	movl	%edx, 12(%ecx)
+
+	mull	%eax		C src[2] ^ 2
+
+	movl	%eax, 16(%ecx)
+	movl	(%ebx), %eax
+	movl	%edx, 20(%ecx)
+
+	mull	4(%ebx)		C src[0] * src[1]
+
+	movl	%eax, %esi
+	movl	(%ebx), %eax
+	movl	%edx, %edi
+
+	mull	8(%ebx)		C src[0] * src[2]
+
+	addl	%eax, %edi
+	movl	%ebp, SAVE_EBP
+	movl	$0, %ebp
+
+	movl	4(%ebx), %eax
+	adcl	%edx, %ebp
+
+	mull	8(%ebx)		C src[1] * src[2]
+
+	xorl	%ebx, %ebx
+	addl	%eax, %ebp
+
+	adcl	$0, %edx
+
+	C eax
+	C ebx	zero, will be dst[5]
+	C ecx	dst
+	C edx	dst[4]
+	C esi	dst[1]
+	C edi	dst[2]
+	C ebp	dst[3]
+
+	adcl	$0, %edx
+	addl	%esi, %esi
+
+	adcl	%edi, %edi
+	movl	4(%ecx), %eax
+
+	adcl	%ebp, %ebp
+
+	adcl	%edx, %edx
+
+	adcl	$0, %ebx
+	addl	%eax, %esi
+	movl	8(%ecx), %eax
+
+	adcl	%eax, %edi
+	movl	12(%ecx), %eax
+	movl	%esi, 4(%ecx)
+
+	adcl	%eax, %ebp
+	movl	16(%ecx), %eax
+	movl	%edi, 8(%ecx)
+
+	movl	SAVE_ESI, %esi
+	movl	SAVE_EDI, %edi
+
+	adcl	%eax, %edx
+	movl	20(%ecx), %eax
+	movl	%ebp, 12(%ecx)
+
+	adcl	%ebx, %eax
+	ASSERT(nc)
+	movl	SAVE_EBX, %ebx
+	movl	SAVE_EBP, %ebp
+
+	movl	%edx, 16(%ecx)
+	movl	%eax, 20(%ecx)
+	addl	$FRAME, %esp
+
+	ret
+
+
+C------------------------------------------------------------------------------
+L(four_or_more):
+
+C First multiply src[0]*src[1..size-1] and store at dst[1..size].
+C Further products are added in rather than stored.
+
+	C eax	src
+	C ebx
+	C ecx	size
+	C edx	dst
+	C esi
+	C edi
+	C ebp
+
+defframe(`VAR_COUNTER',-20)
+defframe(`VAR_JMP',    -24)
+deflit(EXTRA_STACK_SPACE, 8)
+
+	movl	%ebx, SAVE_EBX
+	movl	%edi, SAVE_EDI
+	leal	(%edx,%ecx,4), %edi	C &dst[size]
+
+	movl	%esi, SAVE_ESI
+	movl	%ebp, SAVE_EBP
+	leal	(%eax,%ecx,4), %esi	C &src[size]
+
+	movl	(%eax), %ebp		C multiplier
+	movl	$0, %ebx
+	decl	%ecx
+
+	negl	%ecx
+	subl	$EXTRA_STACK_SPACE, %esp
+FRAME_subl_esp(EXTRA_STACK_SPACE)
+
+L(mul_1):
+	C eax	scratch
+	C ebx	carry
+	C ecx	counter
+	C edx	scratch
+	C esi	&src[size]
+	C edi	&dst[size]
+	C ebp	multiplier
+
+	movl	(%esi,%ecx,4), %eax
+
+	mull	%ebp
+
+	addl	%ebx, %eax
+	movl	%eax, (%edi,%ecx,4)
+	movl	$0, %ebx
+
+	adcl	%edx, %ebx
+	incl	%ecx
+	jnz	L(mul_1)
+
+
+C Add products src[n]*src[n+1..size-1] at dst[2*n-1...], for each n=1..size-2.
+C
+C The last two products, which are the bottom right corner of the product
+C triangle, are left to the end.  These are src[size-3]*src[size-2,size-1]
+C and src[size-2]*src[size-1].  If size is 4 then it's only these corner
+C cases that need to be done.
+C
+C The unrolled code is the same as in mpn_addmul_1, see that routine for
+C some comments.
+C
+C VAR_COUNTER is the outer loop, running from -size+4 to -1, inclusive.
+C
+C VAR_JMP is the computed jump into the unrolled code, stepped by one code
+C chunk each outer loop.
+C
+C K7 does branch prediction on indirect jumps, which is bad since it's a
+C different target each time.  There seems no way to avoid this.
+
+dnl  This value also hard coded in some shifts and adds
+deflit(CODE_BYTES_PER_LIMB, 17)
+
+dnl  With the unmodified &src[size] and &dst[size] pointers, the
+dnl  displacements in the unrolled code fit in a byte for UNROLL_COUNT
+dnl  values up to 31, but above that an offset must be added to them.
+
+deflit(OFFSET,
+ifelse(eval(UNROLL_COUNT>31),1,
+eval((UNROLL_COUNT-31)*4),
+0))
+
+dnl  Because the last chunk of code is generated differently, a label placed
+dnl  at the end doesn't work.  Instead calculate the implied end using the
+dnl  start and how many chunks of code there are.
+
+deflit(UNROLL_INNER_END,
+`L(unroll_inner_start)+eval(UNROLL_COUNT*CODE_BYTES_PER_LIMB)')
+
+	C eax
+	C ebx	carry
+	C ecx
+	C edx
+	C esi	&src[size]
+	C edi	&dst[size]
+	C ebp
+
+	movl	PARAM_SIZE, %ecx
+	movl	%ebx, (%edi)
+
+	subl	$4, %ecx
+	jz	L(corner)
+
+	negl	%ecx
+ifelse(OFFSET,0,,`subl	$OFFSET, %edi')
+ifelse(OFFSET,0,,`subl	$OFFSET, %esi')
+
+	movl	%ecx, %edx
+	shll	$4, %ecx
+
+ifdef(`PIC',`
+	call	L(pic_calc)
+L(here):
+',`
+	leal	UNROLL_INNER_END-eval(2*CODE_BYTES_PER_LIMB)(%ecx,%edx), %ecx
+')
+
+
+	C The calculated jump mustn't come out to before the start of the
+	C code available.  This is the limit UNROLL_COUNT puts on the src
+	C operand size, but checked here directly using the jump address.
+	ASSERT(ae,
+	`movl_text_address(L(unroll_inner_start), %eax)
+	cmpl	%eax, %ecx')
+
+
+C------------------------------------------------------------------------------
+	ALIGN(16)
+L(unroll_outer_top):
+	C eax
+	C ebx	high limb to store
+	C ecx	VAR_JMP
+	C edx	VAR_COUNTER, limbs, negative
+	C esi	&src[size], constant
+	C edi	dst ptr, high of last addmul
+	C ebp
+
+	movl	-12+OFFSET(%esi,%edx,4), %ebp	C next multiplier
+	movl	-8+OFFSET(%esi,%edx,4), %eax	C first of multiplicand
+
+	movl	%edx, VAR_COUNTER
+
+	mull	%ebp
+
+define(cmovX,`ifelse(eval(UNROLL_COUNT%2),0,`cmovz($@)',`cmovnz($@)')')
+
+	testb	$1, %cl
+	movl	%edx, %ebx	C high carry
+	movl	%ecx, %edx	C jump
+
+	movl	%eax, %ecx	C low carry
+	cmovX(	%ebx, %ecx)	C high carry reverse
+	cmovX(	%eax, %ebx)	C low carry reverse
+
+	leal	CODE_BYTES_PER_LIMB(%edx), %eax
+	xorl	%edx, %edx
+	leal	4(%edi), %edi
+
+	movl	%eax, VAR_JMP
+
+	jmp	*%eax
+
+
+ifdef(`PIC',`
+L(pic_calc):
+	addl	(%esp), %ecx
+	addl	$UNROLL_INNER_END-eval(2*CODE_BYTES_PER_LIMB)-L(here), %ecx
+	addl	%edx, %ecx
+	ret_internal
+')
+
+
+	C Must be an even address to preserve the significance of the low
+	C bit of the jump address indicating which way around ecx/ebx should
+	C start.
+	ALIGN(2)
+
+L(unroll_inner_start):
+	C eax	next limb
+	C ebx	carry high
+	C ecx	carry low
+	C edx	scratch
+	C esi	src
+	C edi	dst
+	C ebp	multiplier
+
+forloop(`i', UNROLL_COUNT, 1, `
+	deflit(`disp_src', eval(-i*4 + OFFSET))
+	deflit(`disp_dst', eval(disp_src - 4))
+
+	m4_assert(`disp_src>=-128 && disp_src<128')
+	m4_assert(`disp_dst>=-128 && disp_dst<128')
+
+ifelse(eval(i%2),0,`
+Zdisp(	movl,	disp_src,(%esi), %eax)
+	adcl	%edx, %ebx
+
+	mull	%ebp
+
+Zdisp(  addl,	%ecx, disp_dst,(%edi))
+	movl	$0, %ecx
+
+	adcl	%eax, %ebx
+
+',`
+	dnl  this bit comes out last
+Zdisp(  movl,	disp_src,(%esi), %eax)
+	adcl	%edx, %ecx
+
+	mull	%ebp
+
+Zdisp(	addl,	%ebx, disp_dst,(%edi))
+
+ifelse(forloop_last,0,
+`	movl	$0, %ebx')
+
+	adcl	%eax, %ecx
+')
+')
+
+	C eax	next limb
+	C ebx	carry high
+	C ecx	carry low
+	C edx	scratch
+	C esi	src
+	C edi	dst
+	C ebp	multiplier
+
+	adcl	$0, %edx
+	addl	%ecx, -4+OFFSET(%edi)
+	movl	VAR_JMP, %ecx
+
+	adcl	$0, %edx
+
+	movl	%edx, m4_empty_if_zero(OFFSET) (%edi)
+	movl	VAR_COUNTER, %edx
+
+	incl	%edx
+	jnz	L(unroll_outer_top)
+
+
+ifelse(OFFSET,0,,`
+	addl	$OFFSET, %esi
+	addl	$OFFSET, %edi
+')
+
+
+C------------------------------------------------------------------------------
+L(corner):
+	C esi	&src[size]
+	C edi	&dst[2*size-5]
+
+	movl	-12(%esi), %ebp
+	movl	-8(%esi), %eax
+	movl	%eax, %ecx
+
+	mull	%ebp
+
+	addl	%eax, -4(%edi)
+	movl	-4(%esi), %eax
+
+	adcl	$0, %edx
+	movl	%edx, %ebx
+	movl	%eax, %esi
+
+	mull	%ebp
+
+	addl	%ebx, %eax
+
+	adcl	$0, %edx
+	addl	%eax, (%edi)
+	movl	%esi, %eax
+
+	adcl	$0, %edx
+	movl	%edx, %ebx
+
+	mull	%ecx
+
+	addl	%ebx, %eax
+	movl	%eax, 4(%edi)
+
+	adcl	$0, %edx
+	movl	%edx, 8(%edi)
+
+
+
+C Left shift of dst[1..2*size-2], high bit shifted out becomes dst[2*size-1].
+
+L(lshift_start):
+	movl	PARAM_SIZE, %eax
+	movl	PARAM_DST, %edi
+	xorl	%ecx, %ecx		C clear carry
+
+	leal	(%edi,%eax,8), %edi
+	notl	%eax			C -size-1, preserve carry
+
+	leal	2(%eax), %eax		C -(size-1)
+
+L(lshift):
+	C eax	counter, negative
+	C ebx
+	C ecx
+	C edx
+	C esi
+	C edi	dst, pointing just after last limb
+	C ebp
+
+	rcll	-4(%edi,%eax,8)
+	rcll	(%edi,%eax,8)
+	incl	%eax
+	jnz	L(lshift)
+
+	setc	%al
+
+	movl	PARAM_SRC, %esi
+	movl	%eax, -4(%edi)		C dst most significant limb
+
+	movl	PARAM_SIZE, %ecx
+
+
+C Now add in the squares on the diagonal, src[0]^2, src[1]^2, ...,
+C src[size-1]^2.  dst[0] hasn't yet been set at all yet, and just gets the
+C low limb of src[0]^2.
+
+	movl	(%esi), %eax		C src[0]
+
+	mull	%eax
+
+	leal	(%esi,%ecx,4), %esi	C src point just after last limb
+	negl	%ecx
+
+	movl	%eax, (%edi,%ecx,8)	C dst[0]
+	incl	%ecx
+
+L(diag):
+	C eax	scratch
+	C ebx	scratch
+	C ecx	counter, negative
+	C edx	carry
+	C esi	src just after last limb
+	C edi	dst just after last limb
+	C ebp
+
+	movl	(%esi,%ecx,4), %eax
+	movl	%edx, %ebx
+
+	mull	%eax
+
+	addl	%ebx, -4(%edi,%ecx,8)
+	adcl	%eax, (%edi,%ecx,8)
+	adcl	$0, %edx
+
+	incl	%ecx
+	jnz	L(diag)
+
+
+	movl	SAVE_ESI, %esi
+	movl	SAVE_EBX, %ebx
+
+	addl	%edx, -4(%edi)		C dst most significant limb
+	movl	SAVE_EDI, %edi
+
+	movl	SAVE_EBP, %ebp
+	addl	$FRAME, %esp
+
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/k7/sublsh1_n.asm b/third_party/gmp/mpn/x86/k7/sublsh1_n.asm
new file mode 100644
index 0000000..8851683
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k7/sublsh1_n.asm
@@ -0,0 +1,173 @@
+dnl  AMD K7 mpn_sublsh1_n_ip1 -- rp[] = rp[] - (up[] << 1)
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund and Marco Bodrato.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C This is an attempt at a sublsh1_n for x86-32, not relying on sse2 insns.  The
+C innerloop is 2*3-way unrolled, which is best we can do with the available
+C registers.  It seems tricky to use the same structure for rsblsh1_n, since we
+C cannot feed carry between operations there.
+
+C			    cycles/limb
+C P5
+C P6 model 0-8,10-12
+C P6 model 9  (Banias)
+C P6 model 13 (Dothan)
+C P4 model 0  (Willamette)
+C P4 model 1  (?)
+C P4 model 2  (Northwood)
+C P4 model 3  (Prescott)
+C P4 model 4  (Nocona)
+C Intel Atom			 6.75
+C AMD K6
+C AMD K7
+C AMD K8
+
+C This is a basic sublsh1_n for k7, atom, and perhaps some other x86-32
+C processors.  It uses 2*4-way unrolling, for good reasons.
+C
+C Breaking carry recurrency might be a good idea.  We would then need separate
+C registers for the shift carry and add/subtract carry, which in turn would
+C force us to 2*2-way unrolling.
+
+defframe(PARAM_SIZE,	12)
+defframe(PARAM_SRC,	 8)
+defframe(PARAM_DST,	 4)
+
+dnl  re-use parameter space
+define(VAR_COUNT,`PARAM_SIZE')
+define(SAVE_EBX,`PARAM_SRC')
+define(SAVE_EBP,`PARAM_DST')
+
+ASM_START()
+	TEXT
+	ALIGN(8)
+PROLOGUE(mpn_sublsh1_n_ip1)
+deflit(`FRAME',0)
+
+define(`rp',  `%edi')
+define(`up',  `%esi')
+
+	mov	PARAM_SIZE, %eax	C size
+	push	up			FRAME_pushl()
+	push	rp			FRAME_pushl()
+	xor	%edx, %edx
+	mov	PARAM_SRC, up
+	mov	PARAM_DST, rp
+	mov	%ebx, SAVE_EBX
+	mov	%eax, %ebx
+	shr	$3, %eax
+
+	not	%eax			C count = -(size\8)-i
+	and	$7, %ebx		C size % 8
+	jz	L(exact)
+
+L(oop):
+ifdef(`CPU_P6',`
+	shr	%edx ')			C restore 2nd saved carry bit
+	mov	(up), %ecx
+	adc	%ecx, %ecx
+	rcr	%edx			C restore 1st saved carry bit
+	lea	4(up), up
+	sbb	%ecx, (rp)
+	lea	4(rp), rp
+	adc	%edx, %edx		C save a carry bit in edx
+ifdef(`CPU_P6',`
+	adc	%edx, %edx ')		C save another carry bit in edx
+	dec	%ebx
+	jnz	L(oop)
+L(exact):
+	inc	%eax
+	jz	L(end)
+	mov	%eax, VAR_COUNT
+	mov	%ebp, SAVE_EBP
+
+	ALIGN(16)
+L(top):
+ifdef(`CPU_P6',`
+	shr	%edx ')			C restore 2nd saved carry bit
+	mov	(up), %eax
+	adc	%eax, %eax
+	mov	4(up), %ebx
+	adc	%ebx, %ebx
+	mov	8(up), %ecx
+	adc	%ecx, %ecx
+	mov	12(up), %ebp
+	adc	%ebp, %ebp
+
+	rcr	%edx			C restore 1st saved carry bit
+
+	sbb	%eax, (rp)
+	sbb	%ebx, 4(rp)
+	sbb	%ecx, 8(rp)
+	sbb	%ebp, 12(rp)
+
+	mov	16(up), %eax
+	adc	%eax, %eax
+	mov	20(up), %ebx
+	adc	%ebx, %ebx
+	mov	24(up), %ecx
+	adc	%ecx, %ecx
+	mov	28(up), %ebp
+	adc	%ebp, %ebp
+
+	lea	32(up), up
+	adc	%edx, %edx		C save a carry bit in edx
+
+	sbb	%eax, 16(rp)
+	sbb	%ebx, 20(rp)
+	sbb	%ecx, 24(rp)
+	sbb	%ebp, 28(rp)
+
+ifdef(`CPU_P6',`
+	adc	%edx, %edx ')		C save another carry bit in edx
+	incl	VAR_COUNT
+	lea	32(rp), rp
+	jne	L(top)
+
+	mov	SAVE_EBP, %ebp
+L(end):
+	mov	SAVE_EBX, %ebx
+
+ifdef(`CPU_P6',`
+	xor	%eax, %eax
+	shr	$1, %edx
+	adc	%edx, %eax
+',`
+	adc	$0, %edx
+	mov	%edx, %eax
+')
+	pop	rp			FRAME_popl()
+	pop	up			FRAME_popl()
+	ret
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86/k8/gmp-mparam.h b/third_party/gmp/mpn/x86/k8/gmp-mparam.h
new file mode 100644
index 0000000..fa71292
--- /dev/null
+++ b/third_party/gmp/mpn/x86/k8/gmp-mparam.h
@@ -0,0 +1,215 @@
+/* x86/k8 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 2000-2011, 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+/* 2500 MHz K8 Brisbane */
+/* FFT tuning limit = 67,000,000 */
+/* Generated by tuneup.c, 2019-10-20, gcc 8.3 */
+
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD         11
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          4
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        12
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD         0  /* never mpn_mod_1s_2p */
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     21
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1N_PI1_METHOD                 1  /* 36.85% faster than 2 */
+#define DIV_QR_1_NORM_THRESHOLD              3
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           44
+
+#define DIV_1_VS_MUL_1_PERCENT             251
+
+#define MUL_TOOM22_THRESHOLD                26
+#define MUL_TOOM33_THRESHOLD                78
+#define MUL_TOOM44_THRESHOLD               136
+#define MUL_TOOM6H_THRESHOLD               270
+#define MUL_TOOM8H_THRESHOLD               430
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      85
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD      91
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD      89
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD      96
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     121
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 46
+#define SQR_TOOM3_THRESHOLD                 81
+#define SQR_TOOM4_THRESHOLD                202
+#define SQR_TOOM6_THRESHOLD                300
+#define SQR_TOOM8_THRESHOLD                430
+
+#define MULMID_TOOM42_THRESHOLD             50
+
+#define MULMOD_BNM1_THRESHOLD               18
+#define SQRMOD_BNM1_THRESHOLD               22
+
+#define MUL_FFT_MODF_THRESHOLD             606  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    606, 5}, {     27, 6}, {     15, 5}, {     31, 6}, \
+    {     25, 7}, {     13, 6}, {     29, 7}, {     15, 6}, \
+    {     33, 7}, {     17, 6}, {     35, 7}, {     19, 6}, \
+    {     39, 7}, {     23, 6}, {     47, 7}, {     35, 8}, \
+    {     19, 7}, {     41, 8}, {     23, 7}, {     47, 8}, \
+    {     31, 7}, {     63, 8}, {     39, 9}, {     23, 8}, \
+    {     55, 9}, {     31, 8}, {     67, 9}, {     39, 8}, \
+    {     79, 9}, {     47, 8}, {     95, 9}, {     55,10}, \
+    {     31, 9}, {     79,10}, {     47, 9}, {    103,11}, \
+    {     31,10}, {     63, 9}, {    135,10}, {     79, 9}, \
+    {    167,10}, {     95, 9}, {    191,10}, {    111,11}, \
+    {     63,10}, {    159,11}, {     95,10}, {    191,12}, \
+    {     63,11}, {    127,10}, {    255, 9}, {    511,10}, \
+    {    271, 9}, {    543,10}, {    287,11}, {    159,10}, \
+    {    319, 9}, {    639,10}, {    335, 9}, {    671,11}, \
+    {    191,10}, {    383, 9}, {    767,10}, {    399, 9}, \
+    {    799,11}, {    223,12}, {    127,11}, {    255,10}, \
+    {    511, 9}, {   1023,10}, {    543,11}, {    287,10}, \
+    {    607,11}, {    319,10}, {    671,11}, {    351,12}, \
+    {    191,11}, {    383,10}, {    799,11}, {    415,13}, \
+    {    127,12}, {    255,11}, {    511,10}, {   1023,11}, \
+    {    543,10}, {   1087,11}, {    607,12}, {    319,11}, \
+    {    671,10}, {   1343,11}, {    735,10}, {   1471,12}, \
+    {    383,11}, {    799,10}, {   1599,11}, {    863,12}, \
+    {    447,11}, {    927,13}, {    255,12}, {    511,11}, \
+    {   1087,12}, {    575,11}, {   1215,12}, {    639,11}, \
+    {   1343,12}, {    703,11}, {   1471,13}, {    383,12}, \
+    {    767,11}, {   1599,12}, {    831,11}, {   1727,12}, \
+    {    895,11}, {   1791,12}, {    959,14}, {    255,13}, \
+    {    511,12}, {   1087,11}, {   2239,12}, {   1215,13}, \
+    {    639,12}, {   1471,13}, {    767,12}, {   1727,13}, \
+    {    895,12}, {   1919,14}, {    511,13}, {   1023,12}, \
+    {   2239,13}, {   1151,12}, {   2431,13}, {   1279,12}, \
+    {   2623,13}, {   1407,12}, {   2943,14}, {    767,13}, \
+    {   1663,12}, {   3455,13}, {   1919,15}, {    511,14}, \
+    {   1023,13}, {   2175,12}, {   4351,13}, {   2431,14}, \
+    {   1279,13}, {   2943,14}, {   1535,13}, {   3455,14}, \
+    {   1791,13}, {   3967,15}, {   1023,14}, {   2047,13}, \
+    {   4351,14}, {   2303,13}, {   4991,14}, {   2815,15}, \
+    {   1535,14}, {   3839,16} }
+#define MUL_FFT_TABLE3_SIZE 158
+#define MUL_FFT_THRESHOLD                 7296
+
+#define SQR_FFT_MODF_THRESHOLD             500  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    500, 5}, {     25, 6}, {     13, 5}, {     27, 6}, \
+    {     25, 7}, {     13, 6}, {     29, 7}, {     15, 6}, \
+    {     32, 7}, {     17, 6}, {     35, 7}, {     19, 6}, \
+    {     39, 7}, {     29, 8}, {     15, 7}, {     35, 8}, \
+    {     19, 7}, {     41, 8}, {     23, 7}, {     47, 8}, \
+    {     27, 9}, {     15, 8}, {     31, 7}, {     63, 8}, \
+    {     39, 9}, {     23, 8}, {     51, 9}, {     31, 8}, \
+    {     67, 9}, {     39, 8}, {     79, 9}, {     47, 8}, \
+    {     95,10}, {     31, 9}, {     79,10}, {     47, 9}, \
+    {     95,11}, {     31,10}, {     63, 9}, {    135,10}, \
+    {     79, 9}, {    159,10}, {     95, 9}, {    191,10}, \
+    {    111,11}, {     63,10}, {    127, 9}, {    255,10}, \
+    {    143, 9}, {    287, 8}, {    575,10}, {    159,11}, \
+    {     95,10}, {    191,12}, {     63,11}, {    127,10}, \
+    {    255, 9}, {    511,10}, {    271, 9}, {    543,10}, \
+    {    287,11}, {    159,10}, {    319, 9}, {    639,10}, \
+    {    335, 9}, {    671,10}, {    351,11}, {    191,10}, \
+    {    383, 9}, {    767,10}, {    399, 9}, {    799,10}, \
+    {    415,11}, {    223,12}, {    127,11}, {    255,10}, \
+    {    511, 9}, {   1023,10}, {    543,11}, {    287,10}, \
+    {    607, 9}, {   1215,11}, {    319,10}, {    671,11}, \
+    {    351,10}, {    703,12}, {    191,11}, {    383,10}, \
+    {    799,11}, {    415,10}, {    831,13}, {    127,12}, \
+    {    255,11}, {    511,10}, {   1023,11}, {    543,10}, \
+    {   1087,11}, {    607,12}, {    319,11}, {    671,10}, \
+    {   1343,11}, {    735,10}, {   1471,12}, {    383,11}, \
+    {    799,10}, {   1599,11}, {    863,12}, {    447,11}, \
+    {    959,13}, {    255,12}, {    511,11}, {   1087,12}, \
+    {    575,11}, {   1215,10}, {   2431,12}, {    639,11}, \
+    {   1343,12}, {    703,11}, {   1471,13}, {    383,12}, \
+    {    767,11}, {   1599,12}, {    831,11}, {   1727,12}, \
+    {    959,14}, {    255,13}, {    511,12}, {   1087,11}, \
+    {   2239,12}, {   1215,11}, {   2431,13}, {    639,12}, \
+    {   1471,13}, {    767,12}, {   1727,13}, {    895,12}, \
+    {   1919,14}, {    511,13}, {   1023,12}, {   2239,13}, \
+    {   1151,12}, {   2431,13}, {   1279,12}, {   2623,13}, \
+    {   1407,12}, {   2943,14}, {    767,13}, {   1663,12}, \
+    {   3455,13}, {   1919,15}, {    511,14}, {   1023,13}, \
+    {   2431,14}, {   1279,13}, {   2943,14}, {   1535,13}, \
+    {   3455,14}, {   1791,13}, {   3839,15}, {   1023,14}, \
+    {   2047,13}, {   4223,14}, {   2303,13}, {   4863,14}, \
+    {   2815,15}, {   1535,14}, {   3839,16} }
+#define SQR_FFT_TABLE3_SIZE 167
+#define SQR_FFT_THRESHOLD                 5504
+
+#define MULLO_BASECASE_THRESHOLD             4
+#define MULLO_DC_THRESHOLD                  29
+#define MULLO_MUL_N_THRESHOLD            14281
+#define SQRLO_BASECASE_THRESHOLD             6
+#define SQRLO_DC_THRESHOLD                 193
+#define SQRLO_SQR_THRESHOLD              10704
+
+#define DC_DIV_QR_THRESHOLD                 84
+#define DC_DIVAPPR_Q_THRESHOLD             278
+#define DC_BDIV_QR_THRESHOLD                87
+#define DC_BDIV_Q_THRESHOLD                216
+
+#define INV_MULMOD_BNM1_THRESHOLD           50
+#define INV_NEWTON_THRESHOLD               268
+#define INV_APPR_THRESHOLD                 268
+
+#define BINV_NEWTON_THRESHOLD              276
+#define REDC_1_TO_REDC_N_THRESHOLD          78
+
+#define MU_DIV_QR_THRESHOLD               1652
+#define MU_DIVAPPR_Q_THRESHOLD            1528
+#define MUPI_DIV_QR_THRESHOLD              114
+#define MU_BDIV_QR_THRESHOLD              1442
+#define MU_BDIV_Q_THRESHOLD               1466
+
+#define POWM_SEC_TABLE  1,22,102,452,1357
+
+#define GET_STR_DC_THRESHOLD                14
+#define GET_STR_PRECOMPUTE_THRESHOLD        24
+#define SET_STR_DC_THRESHOLD               270
+#define SET_STR_PRECOMPUTE_THRESHOLD      1149
+
+#define FAC_DSC_THRESHOLD                  208
+#define FAC_ODD_THRESHOLD                   48
+
+#define MATRIX22_STRASSEN_THRESHOLD         16
+#define HGCD2_DIV1_METHOD                    3  /* 4.69% faster than 1 */
+#define HGCD_THRESHOLD                     139
+#define HGCD_APPR_THRESHOLD                174
+#define HGCD_REDUCE_THRESHOLD             3389
+#define GCD_DC_THRESHOLD                   599
+#define GCDEXT_DC_THRESHOLD                419
+#define JACOBI_BASE_METHOD                   1  /* 1.57% faster than 4 */
+
+/* Tuneup completed successfully, took 83851 seconds */
diff --git a/third_party/gmp/mpn/x86/lshift.asm b/third_party/gmp/mpn/x86/lshift.asm
new file mode 100644
index 0000000..6ee6153
--- /dev/null
+++ b/third_party/gmp/mpn/x86/lshift.asm
@@ -0,0 +1,106 @@
+dnl  x86 mpn_lshift -- mpn left shift.
+
+dnl  Copyright 1992, 1994, 1996, 1999-2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C     cycles/limb
+C P54	 7.5
+C P55	 7.0
+C P6	 2.5
+C K6	 4.5
+C K7	 5.0
+C P4	14.5
+
+
+C mp_limb_t mpn_lshift (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                       unsigned shift);
+
+defframe(PARAM_SHIFT,16)
+defframe(PARAM_SIZE, 12)
+defframe(PARAM_SRC,  8)
+defframe(PARAM_DST,  4)
+
+	TEXT
+	ALIGN(8)
+PROLOGUE(mpn_lshift)
+
+	pushl	%edi
+	pushl	%esi
+	pushl	%ebx
+deflit(`FRAME',12)
+
+	movl	PARAM_DST,%edi
+	movl	PARAM_SRC,%esi
+	movl	PARAM_SIZE,%edx
+	movl	PARAM_SHIFT,%ecx
+
+	subl	$4,%esi			C adjust src
+
+	movl	(%esi,%edx,4),%ebx	C read most significant limb
+	xorl	%eax,%eax
+	shldl(	%cl, %ebx, %eax)	C compute carry limb
+	decl	%edx
+	jz	L(end)
+	pushl	%eax			C push carry limb onto stack
+	testb	$1,%dl
+	jnz	L(1)			C enter loop in the middle
+	movl	%ebx,%eax
+
+	ALIGN(8)
+L(oop):	movl	(%esi,%edx,4),%ebx	C load next lower limb
+	shldl(	%cl, %ebx, %eax)	C compute result limb
+	movl	%eax,(%edi,%edx,4)	C store it
+	decl	%edx
+L(1):	movl	(%esi,%edx,4),%eax
+	shldl(	%cl, %eax, %ebx)
+	movl	%ebx,(%edi,%edx,4)
+	decl	%edx
+	jnz	L(oop)
+
+	shll	%cl,%eax		C compute least significant limb
+	movl	%eax,(%edi)		C store it
+
+	popl	%eax			C pop carry limb
+
+	popl	%ebx
+	popl	%esi
+	popl	%edi
+	ret
+
+L(end):	shll	%cl,%ebx		C compute least significant limb
+	movl	%ebx,(%edi)		C store it
+
+	popl	%ebx
+	popl	%esi
+	popl	%edi
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/mmx/sec_tabselect.asm b/third_party/gmp/mpn/x86/mmx/sec_tabselect.asm
new file mode 100644
index 0000000..aae158a
--- /dev/null
+++ b/third_party/gmp/mpn/x86/mmx/sec_tabselect.asm
@@ -0,0 +1,163 @@
+dnl  X86 MMX mpn_sec_tabselect.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C			     cycles/limb     cycles/limb
+C			      ali,evn n	     unal,evn n
+C P5
+C P6 model 0-8,10-12
+C P6 model 9  (Banias)
+C P6 model 13 (Dothan)		 1.33		 1.87
+C P4 model 0  (Willamette)
+C P4 model 1  (?)
+C P4 model 2  (Northwood)	 2.1		 2.63
+C P4 model 3  (Prescott)
+C P4 model 4  (Nocona)		 1.7		 2.57
+C Intel Atom			 1.85		 2.7
+C AMD K6
+C AMD K7			 1.33		 1.33
+C AMD K8
+C AMD K10
+
+define(`rp',     `%edi')
+define(`tp',     `%esi')
+define(`n',      `%edx')
+define(`nents',  `%ecx')
+define(`which',  `')
+
+define(`i',      `%ebp')
+define(`j',      `%ebx')
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_sec_tabselect)
+	push	%ebx
+	push	%esi
+	push	%edi
+	push	%ebp
+
+	mov	20(%esp), rp
+	mov	24(%esp), tp
+	mov	28(%esp), n
+	mov	32(%esp), nents
+
+	movd	36(%esp), %mm6
+	punpckldq %mm6, %mm6		C 2 copies of `which'
+
+	mov	$1, %ebx
+	movd	%ebx, %mm7
+	punpckldq %mm7, %mm7		C 2 copies of 1
+
+	mov	n, j
+	add	$-4, j
+	js	L(outer_end)
+
+L(outer_top):
+	mov	nents, i
+	mov	tp, %eax
+	pxor	%mm1, %mm1
+	pxor	%mm4, %mm4
+	pxor	%mm5, %mm5
+	ALIGN(16)
+L(top):	movq	%mm6, %mm0
+	pcmpeqd	%mm1, %mm0
+	paddd	%mm7, %mm1
+	movq	(tp), %mm2
+	movq	8(tp), %mm3
+	pand	%mm0, %mm2
+	pand	%mm0, %mm3
+	por	%mm2, %mm4
+	por	%mm3, %mm5
+	lea	(tp,n,4), tp
+	add	$-1, i
+	jne	L(top)
+
+	movq	%mm4, (rp)
+	movq	%mm5, 8(rp)
+
+	lea	16(%eax), tp
+	lea	16(rp), rp
+	add	$-4, j
+	jns	L(outer_top)
+L(outer_end):
+
+	test	$2, %dl
+	jz	L(b0x)
+
+L(b1x):	mov	nents, i
+	mov	tp, %eax
+	pxor	%mm1, %mm1
+	pxor	%mm4, %mm4
+	ALIGN(16)
+L(tp2):	movq	%mm6, %mm0
+	pcmpeqd	%mm1, %mm0
+	paddd	%mm7, %mm1
+	movq	(tp), %mm2
+	pand	%mm0, %mm2
+	por	%mm2, %mm4
+	lea	(tp,n,4), tp
+	add	$-1, i
+	jne	L(tp2)
+
+	movq	%mm4, (rp)
+
+	lea	8(%eax), tp
+	lea	8(rp), rp
+
+L(b0x):	test	$1, %dl
+	jz	L(b00)
+
+L(b01):	mov	nents, i
+	pxor	%mm1, %mm1
+	pxor	%mm4, %mm4
+	ALIGN(16)
+L(tp1):	movq	%mm6, %mm0
+	pcmpeqd	%mm1, %mm0
+	paddd	%mm7, %mm1
+	movd	(tp), %mm2
+	pand	%mm0, %mm2
+	por	%mm2, %mm4
+	lea	(tp,n,4), tp
+	add	$-1, i
+	jne	L(tp1)
+
+	movd	%mm4, (rp)
+
+L(b00):	pop	%ebp
+	pop	%edi
+	pop	%esi
+	pop	%ebx
+	emms
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/mod_34lsub1.asm b/third_party/gmp/mpn/x86/mod_34lsub1.asm
new file mode 100644
index 0000000..e09e702
--- /dev/null
+++ b/third_party/gmp/mpn/x86/mod_34lsub1.asm
@@ -0,0 +1,183 @@
+dnl  Generic x86 mpn_mod_34lsub1 -- mpn remainder modulo 2^24-1.
+
+dnl  Copyright 2000-2002, 2004 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C      cycles/limb
+C P5	  3.0
+C P6	  3.66
+C K6	  3.0
+C K7	  1.3
+C P4	  9
+
+
+C mp_limb_t mpn_mod_34lsub1 (mp_srcptr src, mp_size_t size)
+C
+
+defframe(PARAM_SIZE, 8)
+defframe(PARAM_SRC,  4)
+
+dnl  re-use parameter space
+define(SAVE_EBX, `PARAM_SRC')
+
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_mod_34lsub1)
+deflit(`FRAME',0)
+
+	movl	PARAM_SIZE, %ecx
+	movl	PARAM_SRC, %edx
+
+	subl	$2, %ecx
+	ja	L(three_or_more)
+
+	movl	(%edx), %eax
+	jb	L(one)
+
+	movl	4(%edx), %ecx
+	movl	%eax, %edx
+	shrl	$24, %eax		C src[0] low
+
+	andl	$0xFFFFFF, %edx		C src[0] high
+	addl	%edx, %eax
+	movl	%ecx, %edx
+
+	andl	$0xFFFF, %ecx
+	shrl	$16, %edx		C src[1] high
+	addl	%edx, %eax
+
+	shll	$8, %ecx		C src[1] low
+	addl	%ecx, %eax
+
+L(one):
+	ret
+
+
+L(three_or_more):
+	C eax
+	C ebx
+	C ecx	size-2
+	C edx	src
+	C esi
+	C edi
+	C ebp
+
+	movl	%ebx, SAVE_EBX		C and arrange 16-byte loop alignment
+	xorl	%ebx, %ebx
+
+	pushl	%esi	FRAME_pushl()
+	xorl	%esi, %esi
+
+	pushl	%edi	FRAME_pushl()
+	xorl	%eax, %eax		C and clear carry flag
+
+
+	C offset 0x40 here
+L(top):
+	C eax	acc 0mod3
+	C ebx	acc 1mod3
+	C ecx	counter, limbs
+	C edx	src
+	C esi	acc 2mod3
+	C edi
+	C ebp
+
+	leal	12(%edx), %edx
+	leal	-2(%ecx), %ecx
+
+	adcl	-12(%edx), %eax
+	adcl	-8(%edx), %ebx
+	adcl	-4(%edx), %esi
+
+	decl	%ecx
+	jg	L(top)
+
+
+	C ecx is -2, -1 or 0 representing 0, 1 or 2 more limbs, respectively
+
+	movl	$0xFFFFFFFF, %edi
+	incl	%ecx
+	js	L(combine)
+
+	adcl	(%edx), %eax
+	movl	$0xFFFFFF00, %edi
+	decl	%ecx
+	js	L(combine)
+
+	adcl	4(%edx), %ebx
+	movl	$0xFFFF0000, %edi
+
+
+L(combine):
+	C eax	acc 0mod3
+	C ebx	acc 1mod3
+	C ecx
+	C edx
+	C esi	acc 2mod3
+	C edi	mask
+	C ebp
+
+	sbbl	%ecx, %ecx		C carry
+	movl	%eax, %edx		C 0mod3
+
+	shrl	$24, %eax		C 0mod3 high
+	andl	%edi, %ecx		C carry masked
+
+	subl	%ecx, %eax		C apply carry
+	movl	%ebx, %edi		C 1mod3
+
+	shrl	$16, %ebx		C 1mod3 high
+	andl	$0x00FFFFFF, %edx	C 0mod3 low
+
+	addl	%edx, %eax		C apply 0mod3 low
+	andl	$0xFFFF, %edi
+
+	shll	$8, %edi		C 1mod3 low
+	addl	%ebx, %eax		C apply 1mod3 high
+
+	addl	%edi, %eax		C apply 1mod3 low
+	movl	%esi, %edx		C 2mod3
+
+	shrl	$8, %esi		C 2mod3 high
+	andl	$0xFF, %edx		C 2mod3 low
+
+	shll	$16, %edx		C 2mod3 low
+	addl	%esi, %eax		C apply 2mod3 high
+
+	addl	%edx, %eax		C apply 2mod3 low
+	popl	%edi	FRAME_popl()
+
+	movl	SAVE_EBX, %ebx
+	popl	%esi	FRAME_popl()
+
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/mul_1.asm b/third_party/gmp/mpn/x86/mul_1.asm
new file mode 100644
index 0000000..421de62
--- /dev/null
+++ b/third_party/gmp/mpn/x86/mul_1.asm
@@ -0,0 +1,140 @@
+dnl  x86 mpn_mul_1 (for 386, 486, and Pentium Pro) -- Multiply a limb vector
+dnl  with a limb and store the result in a second limb vector.
+
+dnl  Copyright 1992, 1994, 1997-2002, 2005 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C			    cycles/limb
+C P5				12.5
+C P6 model 0-8,10-12		 5.5
+C P6 model 9  (Banias)
+C P6 model 13 (Dothan)		 5.25
+C P4 model 0  (Willamette)	19.0
+C P4 model 1  (?)		19.0
+C P4 model 2  (Northwood)	19.0
+C P4 model 3  (Prescott)
+C P4 model 4  (Nocona)
+C AMD K6			10.5
+C AMD K7			 4.5
+C AMD K8
+
+
+C mp_limb_t mpn_mul_1 (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                      mp_limb_t multiplier);
+
+defframe(PARAM_MULTIPLIER,16)
+defframe(PARAM_SIZE,      12)
+defframe(PARAM_SRC,       8)
+defframe(PARAM_DST,       4)
+
+	TEXT
+	ALIGN(8)
+PROLOGUE(mpn_mul_1)
+deflit(`FRAME',0)
+
+	pushl	%edi
+	pushl	%esi
+	pushl	%ebx
+	pushl	%ebp
+deflit(`FRAME',16)
+
+	movl	PARAM_DST,%edi
+	movl	PARAM_SRC,%esi
+	movl	PARAM_SIZE,%ecx
+
+	xorl	%ebx,%ebx
+	andl	$3,%ecx
+	jz	L(end0)
+
+L(oop0):
+	movl	(%esi),%eax
+	mull	PARAM_MULTIPLIER
+	leal	4(%esi),%esi
+	addl	%ebx,%eax
+	movl	$0,%ebx
+	adcl	%ebx,%edx
+	movl	%eax,(%edi)
+	movl	%edx,%ebx	C propagate carry into cylimb
+
+	leal	4(%edi),%edi
+	decl	%ecx
+	jnz	L(oop0)
+
+L(end0):
+	movl	PARAM_SIZE,%ecx
+	shrl	$2,%ecx
+	jz	L(end)
+
+
+	ALIGN(8)
+L(oop):	movl	(%esi),%eax
+	mull	PARAM_MULTIPLIER
+	addl	%eax,%ebx
+	movl	$0,%ebp
+	adcl	%edx,%ebp
+
+	movl	4(%esi),%eax
+	mull	PARAM_MULTIPLIER
+	movl	%ebx,(%edi)
+	addl	%eax,%ebp	C new lo + cylimb
+	movl	$0,%ebx
+	adcl	%edx,%ebx
+
+	movl	8(%esi),%eax
+	mull	PARAM_MULTIPLIER
+	movl	%ebp,4(%edi)
+	addl	%eax,%ebx	C new lo + cylimb
+	movl	$0,%ebp
+	adcl	%edx,%ebp
+
+	movl	12(%esi),%eax
+	mull	PARAM_MULTIPLIER
+	movl	%ebx,8(%edi)
+	addl	%eax,%ebp	C new lo + cylimb
+	movl	$0,%ebx
+	adcl	%edx,%ebx
+
+	movl	%ebp,12(%edi)
+
+	leal	16(%esi),%esi
+	leal	16(%edi),%edi
+	decl	%ecx
+	jnz	L(oop)
+
+L(end):	movl	%ebx,%eax
+
+	popl	%ebp
+	popl	%ebx
+	popl	%esi
+	popl	%edi
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/mul_basecase.asm b/third_party/gmp/mpn/x86/mul_basecase.asm
new file mode 100644
index 0000000..8339732
--- /dev/null
+++ b/third_party/gmp/mpn/x86/mul_basecase.asm
@@ -0,0 +1,223 @@
+dnl  x86 mpn_mul_basecase -- Multiply two limb vectors and store the result
+dnl  in a third limb vector.
+
+dnl  Copyright 1996-2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C     cycles/crossproduct
+C P5	  15
+C P6	   7.5
+C K6	  12.5
+C K7	   5.5
+C P4	  24
+
+
+C void mpn_mul_basecase (mp_ptr wp,
+C                        mp_srcptr xp, mp_size_t xsize,
+C                        mp_srcptr yp, mp_size_t ysize);
+C
+C This was written in a haste since the Pentium optimized code that was used
+C for all x86 machines was slow for the Pentium II.  This code would benefit
+C from some cleanup.
+C
+C To shave off some percentage of the run-time, one should make 4 variants
+C of the Louter loop, for the four different outcomes of un mod 4.  That
+C would avoid Loop0 altogether.  Code expansion would be > 4-fold for that
+C part of the function, but since it is not very large, that would be
+C acceptable.
+C
+C The mul loop (at L(oopM)) might need some tweaking.  It's current speed is
+C unknown.
+
+defframe(PARAM_YSIZE,20)
+defframe(PARAM_YP,   16)
+defframe(PARAM_XSIZE,12)
+defframe(PARAM_XP,   8)
+defframe(PARAM_WP,   4)
+
+defframe(VAR_MULTIPLIER, -4)
+defframe(VAR_COUNTER,    -8)
+deflit(VAR_STACK_SPACE,  8)
+
+	TEXT
+	ALIGN(8)
+
+PROLOGUE(mpn_mul_basecase)
+deflit(`FRAME',0)
+
+	subl	$VAR_STACK_SPACE,%esp
+	pushl	%esi
+	pushl	%ebp
+	pushl	%edi
+deflit(`FRAME',eval(VAR_STACK_SPACE+12))
+
+	movl	PARAM_XP,%esi
+	movl	PARAM_WP,%edi
+	movl	PARAM_YP,%ebp
+
+	movl	(%esi),%eax		C load xp[0]
+	mull	(%ebp)			C multiply by yp[0]
+	movl	%eax,(%edi)		C store to wp[0]
+	movl	PARAM_XSIZE,%ecx	C xsize
+	decl	%ecx			C If xsize = 1, ysize = 1 too
+	jz	L(done)
+
+	pushl	%ebx
+FRAME_pushl()
+	movl	%edx,%ebx
+
+	leal	4(%esi),%esi
+	leal	4(%edi),%edi
+
+L(oopM):
+	movl	(%esi),%eax		C load next limb at xp[j]
+	leal	4(%esi),%esi
+	mull	(%ebp)
+	addl	%ebx,%eax
+	movl	%edx,%ebx
+	adcl	$0,%ebx
+	movl	%eax,(%edi)
+	leal	4(%edi),%edi
+	decl	%ecx
+	jnz	L(oopM)
+
+	movl	%ebx,(%edi)		C most significant limb of product
+	addl	$4,%edi			C increment wp
+	movl	PARAM_XSIZE,%eax
+	shll	$2,%eax
+	subl	%eax,%edi
+	subl	%eax,%esi
+
+	movl	PARAM_YSIZE,%eax	C ysize
+	decl	%eax
+	jz	L(skip)
+	movl	%eax,VAR_COUNTER	C set index i to ysize
+
+L(outer):
+	movl	PARAM_YP,%ebp		C yp
+	addl	$4,%ebp			C make ebp point to next v limb
+	movl	%ebp,PARAM_YP
+	movl	(%ebp),%eax		C copy y limb ...
+	movl	%eax,VAR_MULTIPLIER	C ... to stack slot
+	movl	PARAM_XSIZE,%ecx
+
+	xorl	%ebx,%ebx
+	andl	$3,%ecx
+	jz	L(end0)
+
+L(oop0):
+	movl	(%esi),%eax
+	mull	VAR_MULTIPLIER
+	leal	4(%esi),%esi
+	addl	%ebx,%eax
+	movl	$0,%ebx
+	adcl	%ebx,%edx
+	addl	%eax,(%edi)
+	adcl	%edx,%ebx		C propagate carry into cylimb
+
+	leal	4(%edi),%edi
+	decl	%ecx
+	jnz	L(oop0)
+
+L(end0):
+	movl	PARAM_XSIZE,%ecx
+	shrl	$2,%ecx
+	jz	L(endX)
+
+	ALIGN(8)
+L(oopX):
+	movl	(%esi),%eax
+	mull	VAR_MULTIPLIER
+	addl	%eax,%ebx
+	movl	$0,%ebp
+	adcl	%edx,%ebp
+
+	movl	4(%esi),%eax
+	mull	VAR_MULTIPLIER
+	addl	%ebx,(%edi)
+	adcl	%eax,%ebp	C new lo + cylimb
+	movl	$0,%ebx
+	adcl	%edx,%ebx
+
+	movl	8(%esi),%eax
+	mull	VAR_MULTIPLIER
+	addl	%ebp,4(%edi)
+	adcl	%eax,%ebx	C new lo + cylimb
+	movl	$0,%ebp
+	adcl	%edx,%ebp
+
+	movl	12(%esi),%eax
+	mull	VAR_MULTIPLIER
+	addl	%ebx,8(%edi)
+	adcl	%eax,%ebp	C new lo + cylimb
+	movl	$0,%ebx
+	adcl	%edx,%ebx
+
+	addl	%ebp,12(%edi)
+	adcl	$0,%ebx		C propagate carry into cylimb
+
+	leal	16(%esi),%esi
+	leal	16(%edi),%edi
+	decl	%ecx
+	jnz	L(oopX)
+
+L(endX):
+	movl	%ebx,(%edi)
+	addl	$4,%edi
+
+	C we incremented wp and xp in the loop above; compensate
+	movl	PARAM_XSIZE,%eax
+	shll	$2,%eax
+	subl	%eax,%edi
+	subl	%eax,%esi
+
+	movl	VAR_COUNTER,%eax
+	decl	%eax
+	movl	%eax,VAR_COUNTER
+	jnz	L(outer)
+
+L(skip):
+	popl	%ebx
+	popl	%edi
+	popl	%ebp
+	popl	%esi
+	addl	$8,%esp
+	ret
+
+L(done):
+	movl	%edx,4(%edi)	   C store to wp[1]
+	popl	%edi
+	popl	%ebp
+	popl	%esi
+	addl	$8,%esp
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/nano/gmp-mparam.h b/third_party/gmp/mpn/x86/nano/gmp-mparam.h
new file mode 100644
index 0000000..cd8ac4e
--- /dev/null
+++ b/third_party/gmp/mpn/x86/nano/gmp-mparam.h
@@ -0,0 +1,162 @@
+/* x86/nano gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 2000-2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+/* Generated by tuneup.c, 2011-11-25, gcc 4.2 */
+
+#define MOD_1_1P_METHOD                      1
+#define MOD_1_NORM_THRESHOLD                 3
+#define MOD_1_UNNORM_THRESHOLD               3
+#define MOD_1N_TO_MOD_1_1_THRESHOLD         10
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          9
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD         0  /* never mpn_mod_1_1p */
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        53
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     12
+#define USE_PREINV_DIVREM_1                  1
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           32
+
+#define MUL_TOOM22_THRESHOLD                16
+#define MUL_TOOM33_THRESHOLD               132
+#define MUL_TOOM44_THRESHOLD               195
+#define MUL_TOOM6H_THRESHOLD               270
+#define MUL_TOOM8H_THRESHOLD               478
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD     129
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     138
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     130
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     135
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 28
+#define SQR_TOOM3_THRESHOLD                194
+#define SQR_TOOM4_THRESHOLD                502
+#define SQR_TOOM6_THRESHOLD                746
+#define SQR_TOOM8_THRESHOLD               1005
+
+#define MULMID_TOOM42_THRESHOLD             40
+
+#define MULMOD_BNM1_THRESHOLD               14
+#define SQRMOD_BNM1_THRESHOLD               19
+
+#define POWM_SEC_TABLE  4,23,258,828,2246
+
+#define MUL_FFT_MODF_THRESHOLD             308  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    308, 5}, {     13, 6}, {      7, 5}, {     17, 6}, \
+    {      9, 5}, {     19, 6}, {     11, 5}, {     23, 6}, \
+    {     13, 7}, {      7, 6}, {     17, 7}, {      9, 6}, \
+    {     19, 7}, {     11, 6}, {     24, 7}, {     15, 6}, \
+    {     31, 7}, {     19, 8}, {     11, 7}, {     25, 8}, \
+    {     15, 7}, {     33, 8}, {     19, 7}, {     39, 8}, \
+    {     23, 7}, {     47, 9}, {     15, 8}, {     31, 7}, \
+    {     63, 8}, {     39, 9}, {     23, 8}, {     47,10}, \
+    {     15, 9}, {     31, 8}, {     63, 9}, {     47,10}, \
+    {     31, 9}, {     71,10}, {     47, 9}, {     95,11}, \
+    {     31,10}, {     63, 9}, {    127, 8}, {    255,10}, \
+    {     79, 9}, {    159,10}, {     95, 9}, {    191,11}, \
+    {     63,10}, {    127, 9}, {    255, 8}, {    543, 9}, \
+    {    287, 8}, {    575, 7}, {   1215,10}, {    159,11}, \
+    {     95,10}, {    191,12}, {     63,11}, {    127,10}, \
+    {    255, 9}, {    543, 8}, {   1087,10}, {    287, 9}, \
+    {    607, 8}, {   1215,11}, {    159,10}, {    319, 9}, \
+    {    639,10}, {    351, 9}, {    703, 8}, {   1407, 9}, \
+    {    735, 8}, {   1471,11}, {    191,10}, {    383, 9}, \
+    {    767,10}, {    415, 9}, {    831,11}, {    223,10}, \
+    {    447, 9}, {    895,10}, {    479, 9}, {    959, 8}, \
+    {   1919,12}, {   4096,13}, {   8192,14}, {  16384,15}, \
+    {  32768,16} }
+#define MUL_FFT_TABLE3_SIZE 89
+#define MUL_FFT_THRESHOLD                 1856
+
+#define SQR_FFT_MODF_THRESHOLD             396  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    396, 5}, {     13, 6}, {      7, 5}, {     21, 6}, \
+    {     11, 5}, {     23, 6}, {     21, 7}, {     11, 6}, \
+    {     25, 7}, {     15, 6}, {     31, 7}, {     19, 6}, \
+    {     39, 7}, {     21, 8}, {     11, 7}, {     23, 6}, \
+    {     47, 7}, {     27, 8}, {     15, 7}, {     33, 8}, \
+    {     19, 7}, {     39, 8}, {     23, 7}, {     47, 8}, \
+    {     27, 9}, {     15, 8}, {     31, 7}, {     63, 8}, \
+    {     39, 9}, {     23, 8}, {     47,10}, {     15, 9}, \
+    {     31, 8}, {     63, 9}, {     39, 8}, {     79, 9}, \
+    {     47,10}, {     31, 9}, {     79,10}, {     47, 9}, \
+    {     95,11}, {     31,10}, {     63, 9}, {    127,10}, \
+    {     79, 9}, {    159,10}, {     95,11}, {     63,10}, \
+    {    127, 9}, {    255, 8}, {    543,10}, {    143, 9}, \
+    {    287, 8}, {    607, 7}, {   1215, 6}, {   2431,10}, \
+    {    159, 8}, {    639,11}, {     95,10}, {    191,12}, \
+    {     63,11}, {    127,10}, {    255, 9}, {    543, 8}, \
+    {   1087,10}, {    287, 9}, {    607, 8}, {   1215,11}, \
+    {    159,10}, {    319, 9}, {    671,10}, {    351, 9}, \
+    {    703, 8}, {   1407, 9}, {    735, 8}, {   1471, 7}, \
+    {   2943,11}, {    191,10}, {    383, 9}, {    799,10}, \
+    {    415, 9}, {    895,10}, {    479,12}, {   4096,13}, \
+    {   8192,14}, {  16384,15}, {  32768,16} }
+#define SQR_FFT_TABLE3_SIZE 87
+#define SQR_FFT_THRESHOLD                 2368
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  51
+#define MULLO_MUL_N_THRESHOLD             3369
+
+#define DC_DIV_QR_THRESHOLD                 56
+#define DC_DIVAPPR_Q_THRESHOLD             183
+#define DC_BDIV_QR_THRESHOLD                55
+#define DC_BDIV_Q_THRESHOLD                118
+
+#define INV_MULMOD_BNM1_THRESHOLD           30
+#define INV_NEWTON_THRESHOLD               266
+#define INV_APPR_THRESHOLD                 218
+
+#define BINV_NEWTON_THRESHOLD              268
+#define REDC_1_TO_REDC_N_THRESHOLD          56
+
+#define MU_DIV_QR_THRESHOLD               1308
+#define MU_DIVAPPR_Q_THRESHOLD            1528
+#define MUPI_DIV_QR_THRESHOLD              124
+#define MU_BDIV_QR_THRESHOLD               855
+#define MU_BDIV_Q_THRESHOLD               1334
+
+#define MATRIX22_STRASSEN_THRESHOLD         14
+#define HGCD_THRESHOLD                     104
+#define HGCD_APPR_THRESHOLD                139
+#define HGCD_REDUCE_THRESHOLD             2121
+#define GCD_DC_THRESHOLD                   456
+#define GCDEXT_DC_THRESHOLD                321
+#define JACOBI_BASE_METHOD                   4
+
+#define GET_STR_DC_THRESHOLD                11
+#define GET_STR_PRECOMPUTE_THRESHOLD        25
+#define SET_STR_DC_THRESHOLD               542
+#define SET_STR_PRECOMPUTE_THRESHOLD       840
diff --git a/third_party/gmp/mpn/x86/p6/README b/third_party/gmp/mpn/x86/p6/README
new file mode 100644
index 0000000..f19d47b
--- /dev/null
+++ b/third_party/gmp/mpn/x86/p6/README
@@ -0,0 +1,125 @@
+Copyright 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.
+
+
+
+
+
+                      INTEL P6 MPN SUBROUTINES
+
+
+
+This directory contains code optimized for Intel P6 class CPUs, meaning
+PentiumPro, Pentium II and Pentium III.  The mmx and p3mmx subdirectories
+have routines using MMX instructions.
+
+
+
+STATUS
+
+Times for the loops, with all code and data in L1 cache, are as follows.
+Some of these might be able to be improved.
+
+                               cycles/limb
+
+	mpn_add_n/sub_n           3.7
+
+	mpn_copyi                 0.75
+	mpn_copyd                 1.75 (or 0.75 if no overlap)
+
+	mpn_divrem_1             39.0
+	mpn_mod_1                21.5
+	mpn_divexact_by3          8.5
+
+	mpn_mul_1                 5.5
+	mpn_addmul/submul_1       6.35
+
+	mpn_l/rshift              2.5
+
+	mpn_mul_basecase          8.2 cycles/crossproduct (approx)
+	mpn_sqr_basecase          4.0 cycles/crossproduct (approx)
+				  or 7.75 cycles/triangleproduct (approx)
+
+Pentium II and III have MMX and get the following improvements.
+
+	mpn_divrem_1             25.0 integer part, 17.5 fractional part
+
+	mpn_l/rshift              1.75
+
+
+
+
+NOTES
+
+Write-allocate L1 data cache means prefetching of destinations is unnecessary.
+
+Mispredicted branches have a penalty of between 9 and 15 cycles, and even up
+to 26 cycles depending how far speculative execution has gone.  The 9 cycle
+minimum penalty comes from the issue pipeline being 9 stages.
+
+A copy with rep movs seems to copy 16 bytes at a time, since speeds for 4,
+5, 6 or 7 limb operations are all the same.  The 0.75 cycles/limb would be 3
+cycles per 16 byte block.
+
+
+
+
+CODING
+
+Instructions in general code have been shown grouped if they can execute
+together, which means up to three instructions with no successive
+dependencies, and with only the first being a multiple micro-op.
+
+P6 has out-of-order execution, so the groupings are really only showing
+dependent paths where some shuffling might allow some latencies to be
+hidden.
+
+
+
+
+REFERENCES
+
+"Intel Architecture Optimization Reference Manual", 1999, revision 001 dated
+02/99, order number 245127 (order number 730795-001 is in the document too).
+Available on-line:
+
+	http://download.intel.com/design/PentiumII/manuals/245127.htm
+
+"Intel Architecture Optimization Manual", 1997, order number 242816.  This
+is an older document mostly about P5 and not as good as the above.
+Available on-line:
+
+	http://download.intel.com/design/PentiumII/manuals/242816.htm
+
+
+
+----------------
+Local variables:
+mode: text
+fill-column: 76
+End:
diff --git a/third_party/gmp/mpn/x86/p6/aors_n.asm b/third_party/gmp/mpn/x86/p6/aors_n.asm
new file mode 100644
index 0000000..df51c2e
--- /dev/null
+++ b/third_party/gmp/mpn/x86/p6/aors_n.asm
@@ -0,0 +1,156 @@
+dnl  Intel P6 mpn_add_n/mpn_sub_n -- mpn add or subtract.
+
+dnl  Copyright 2006 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C TODO:
+C  * Avoid indexed addressing, it makes us stall on the two-ported register
+C    file.
+
+C			    cycles/limb
+C P6 model 0-8,10-12		3.17
+C P6 model 9   (Banias)		2.15
+C P6 model 13  (Dothan)		2.25
+
+
+define(`rp',	`%edi')
+define(`up',	`%esi')
+define(`vp',	`%ebx')
+define(`n',	`%ecx')
+
+ifdef(`OPERATION_add_n', `
+	define(ADCSBB,	      adc)
+	define(func,	      mpn_add_n)
+	define(func_nc,	      mpn_add_nc)')
+ifdef(`OPERATION_sub_n', `
+	define(ADCSBB,	      sbb)
+	define(func,	      mpn_sub_n)
+	define(func_nc,	      mpn_sub_nc)')
+
+MULFUNC_PROLOGUE(mpn_add_n mpn_add_nc mpn_sub_n mpn_sub_nc)
+
+ASM_START()
+
+	TEXT
+	ALIGN(16)
+
+PROLOGUE(func)
+	xor	%edx, %edx
+L(start):
+	push	%edi
+	push	%esi
+	push	%ebx
+
+	mov	16(%esp), rp
+	mov	20(%esp), up
+	mov	24(%esp), vp
+	mov	28(%esp), n
+
+	lea	(up,n,4), up
+	lea	(vp,n,4), vp
+	lea	(rp,n,4), rp
+
+	neg	n
+	mov	n, %eax
+	and	$-8, n
+	and	$7, %eax
+	shl	$2, %eax			C 4x
+ifdef(`PIC',`
+	call	L(pic_calc)
+L(here):
+',`
+	lea	L(ent) (%eax,%eax,2), %eax	C 12x
+')
+
+	shr	%edx				C set cy flag
+	jmp	*%eax
+
+ifdef(`PIC',`
+L(pic_calc):
+	C See mpn/x86/README about old gas bugs
+	lea	(%eax,%eax,2), %eax
+	add	$L(ent)-L(here), %eax
+	add	(%esp), %eax
+	ret_internal
+')
+
+L(end):
+	sbb	%eax, %eax
+	neg	%eax
+	pop	%ebx
+	pop	%esi
+	pop	%edi
+	ret
+
+	ALIGN(16)
+L(top):
+	jecxz	L(end)
+L(ent):
+Zdisp(	mov,	0,(up,n,4), %eax)
+Zdisp(	ADCSBB,	0,(vp,n,4), %eax)
+Zdisp(	mov,	%eax, 0,(rp,n,4))
+
+	mov	4(up,n,4), %edx
+	ADCSBB	4(vp,n,4), %edx
+	mov	%edx, 4(rp,n,4)
+
+	mov	8(up,n,4), %eax
+	ADCSBB	8(vp,n,4), %eax
+	mov	%eax, 8(rp,n,4)
+
+	mov	12(up,n,4), %edx
+	ADCSBB	12(vp,n,4), %edx
+	mov	%edx, 12(rp,n,4)
+
+	mov	16(up,n,4), %eax
+	ADCSBB	16(vp,n,4), %eax
+	mov	%eax, 16(rp,n,4)
+
+	mov	20(up,n,4), %edx
+	ADCSBB	20(vp,n,4), %edx
+	mov	%edx, 20(rp,n,4)
+
+	mov	24(up,n,4), %eax
+	ADCSBB	24(vp,n,4), %eax
+	mov	%eax, 24(rp,n,4)
+
+	mov	28(up,n,4), %edx
+	ADCSBB	28(vp,n,4), %edx
+	mov	%edx, 28(rp,n,4)
+
+	lea	8(n), n
+	jmp	L(top)
+
+EPILOGUE()
+
+PROLOGUE(func_nc)
+	movl	20(%esp), %edx
+	jmp	L(start)
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/p6/aorsmul_1.asm b/third_party/gmp/mpn/x86/p6/aorsmul_1.asm
new file mode 100644
index 0000000..bc8c49c
--- /dev/null
+++ b/third_party/gmp/mpn/x86/p6/aorsmul_1.asm
@@ -0,0 +1,320 @@
+dnl  Intel P6 mpn_addmul_1/mpn_submul_1 -- add or subtract mpn multiple.
+
+dnl  Copyright 1999-2002, 2005 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C			    cycles/limb
+C P5
+C P6 model 0-8,10-12		 6.44
+C P6 model 9  (Banias)		 6.15
+C P6 model 13 (Dothan)		 6.11
+C P4 model 0  (Willamette)
+C P4 model 1  (?)
+C P4 model 2  (Northwood)
+C P4 model 3  (Prescott)
+C P4 model 4  (Nocona)
+C AMD K6
+C AMD K7
+C AMD K8
+
+
+dnl  P6 UNROLL_COUNT cycles/limb
+dnl          8           6.7
+dnl         16           6.35
+dnl         32           6.3
+dnl         64           6.3
+dnl  Maximum possible with the current code is 64.
+
+deflit(UNROLL_COUNT, 16)
+
+
+ifdef(`OPERATION_addmul_1', `
+	define(M4_inst,        addl)
+	define(M4_function_1,  mpn_addmul_1)
+	define(M4_function_1c, mpn_addmul_1c)
+	define(M4_description, add it to)
+	define(M4_desc_retval, carry)
+',`ifdef(`OPERATION_submul_1', `
+	define(M4_inst,        subl)
+	define(M4_function_1,  mpn_submul_1)
+	define(M4_function_1c, mpn_submul_1c)
+	define(M4_description, subtract it from)
+	define(M4_desc_retval, borrow)
+',`m4_error(`Need OPERATION_addmul_1 or OPERATION_submul_1
+')')')
+
+MULFUNC_PROLOGUE(mpn_addmul_1 mpn_addmul_1c mpn_submul_1 mpn_submul_1c)
+
+
+C mp_limb_t M4_function_1 (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                            mp_limb_t mult);
+C mp_limb_t M4_function_1c (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                             mp_limb_t mult, mp_limb_t carry);
+C
+C Calculate src,size multiplied by mult and M4_description dst,size.
+C Return the M4_desc_retval limb from the top of the result.
+C
+C This code is pretty much the same as the K6 code.  The unrolled loop is
+C the same, but there's just a few scheduling tweaks in the setups and the
+C simple loop.
+C
+C A number of variations have been tried for the unrolled loop, with one or
+C two carries, and with loads scheduled earlier, but nothing faster than 6
+C cycles/limb has been found.
+
+ifdef(`PIC',`
+deflit(UNROLL_THRESHOLD, 5)
+',`
+deflit(UNROLL_THRESHOLD, 5)
+')
+
+defframe(PARAM_CARRY,     20)
+defframe(PARAM_MULTIPLIER,16)
+defframe(PARAM_SIZE,      12)
+defframe(PARAM_SRC,       8)
+defframe(PARAM_DST,       4)
+
+	TEXT
+	ALIGN(32)
+
+PROLOGUE(M4_function_1c)
+	pushl	%ebx
+deflit(`FRAME',4)
+	movl	PARAM_CARRY, %ebx
+	jmp	L(start_nc)
+EPILOGUE()
+
+PROLOGUE(M4_function_1)
+	push	%ebx
+deflit(`FRAME',4)
+	xorl	%ebx, %ebx	C initial carry
+
+L(start_nc):
+	movl	PARAM_SIZE, %ecx
+	pushl	%esi
+deflit(`FRAME',8)
+
+	movl	PARAM_SRC, %esi
+	pushl	%edi
+deflit(`FRAME',12)
+
+	movl	PARAM_DST, %edi
+	pushl	%ebp
+deflit(`FRAME',16)
+	cmpl	$UNROLL_THRESHOLD, %ecx
+
+	movl	PARAM_MULTIPLIER, %ebp
+	jae	L(unroll)
+
+
+	C simple loop
+	C this is offset 0x22, so close enough to aligned
+L(simple):
+	C eax	scratch
+	C ebx	carry
+	C ecx	counter
+	C edx	scratch
+	C esi	src
+	C edi	dst
+	C ebp	multiplier
+
+	movl	(%esi), %eax
+	addl	$4, %edi
+
+	mull	%ebp
+
+	addl	%ebx, %eax
+	adcl	$0, %edx
+
+	M4_inst	%eax, -4(%edi)
+	movl	%edx, %ebx
+
+	adcl	$0, %ebx
+	decl	%ecx
+
+	leal	4(%esi), %esi
+	jnz	L(simple)
+
+
+	popl	%ebp
+	popl	%edi
+
+	popl	%esi
+	movl	%ebx, %eax
+
+	popl	%ebx
+	ret
+
+
+
+C------------------------------------------------------------------------------
+C VAR_JUMP holds the computed jump temporarily because there's not enough
+C registers when doing the mul for the initial two carry limbs.
+C
+C The add/adc for the initial carry in %ebx is necessary only for the
+C mpn_add/submul_1c entry points.  Duplicating the startup code to
+C eliminate this for the plain mpn_add/submul_1 doesn't seem like a good
+C idea.
+
+dnl  overlapping with parameters already fetched
+define(VAR_COUNTER,`PARAM_SIZE')
+define(VAR_JUMP,   `PARAM_DST')
+
+	C this is offset 0x43, so close enough to aligned
+L(unroll):
+	C eax
+	C ebx	initial carry
+	C ecx	size
+	C edx
+	C esi	src
+	C edi	dst
+	C ebp
+
+	movl	%ecx, %edx
+	decl	%ecx
+
+	subl	$2, %edx
+	negl	%ecx
+
+	shrl	$UNROLL_LOG2, %edx
+	andl	$UNROLL_MASK, %ecx
+
+	movl	%edx, VAR_COUNTER
+	movl	%ecx, %edx
+
+	C 15 code bytes per limb
+ifdef(`PIC',`
+	call	L(pic_calc)
+L(here):
+',`
+	shll	$4, %edx
+	negl	%ecx
+
+	leal	L(entry) (%edx,%ecx,1), %edx
+')
+	movl	(%esi), %eax		C src low limb
+
+	movl	%edx, VAR_JUMP
+	leal	ifelse(UNROLL_BYTES,256,128+) 4(%esi,%ecx,4), %esi
+
+	mull	%ebp
+
+	addl	%ebx, %eax	C initial carry (from _1c)
+	adcl	$0, %edx
+
+	movl	%edx, %ebx	C high carry
+	leal	ifelse(UNROLL_BYTES,256,128) (%edi,%ecx,4), %edi
+
+	movl	VAR_JUMP, %edx
+	testl	$1, %ecx
+	movl	%eax, %ecx	C low carry
+
+	cmovnz(	%ebx, %ecx)	C high,low carry other way around
+	cmovnz(	%eax, %ebx)
+
+	jmp	*%edx
+
+
+ifdef(`PIC',`
+L(pic_calc):
+	shll	$4, %edx
+	negl	%ecx
+
+	C See mpn/x86/README about old gas bugs
+	leal	(%edx,%ecx,1), %edx
+	addl	$L(entry)-L(here), %edx
+
+	addl	(%esp), %edx
+
+	ret_internal
+')
+
+
+C -----------------------------------------------------------
+	ALIGN(32)
+L(top):
+deflit(`FRAME',16)
+	C eax	scratch
+	C ebx	carry hi
+	C ecx	carry lo
+	C edx	scratch
+	C esi	src
+	C edi	dst
+	C ebp	multiplier
+	C
+	C VAR_COUNTER	loop counter
+	C
+	C 15 code bytes per limb
+
+	addl	$UNROLL_BYTES, %edi
+
+L(entry):
+deflit(CHUNK_COUNT,2)
+forloop(`i', 0, UNROLL_COUNT/CHUNK_COUNT-1, `
+	deflit(`disp0', eval(i*4*CHUNK_COUNT ifelse(UNROLL_BYTES,256,-128)))
+	deflit(`disp1', eval(disp0 + 4))
+
+Zdisp(	movl,	disp0,(%esi), %eax)
+	mull	%ebp
+Zdisp(	M4_inst,%ecx, disp0,(%edi))
+	adcl	%eax, %ebx
+	movl	%edx, %ecx
+	adcl	$0, %ecx
+
+	movl	disp1(%esi), %eax
+	mull	%ebp
+	M4_inst	%ebx, disp1(%edi)
+	adcl	%eax, %ecx
+	movl	%edx, %ebx
+	adcl	$0, %ebx
+')
+
+	decl	VAR_COUNTER
+	leal	UNROLL_BYTES(%esi), %esi
+
+	jns	L(top)
+
+
+deflit(`disp0',	eval(UNROLL_BYTES ifelse(UNROLL_BYTES,256,-128)))
+
+	M4_inst	%ecx, disp0(%edi)
+	movl	%ebx, %eax
+
+	popl	%ebp
+	popl	%edi
+
+	popl	%esi
+	popl	%ebx
+	adcl	$0, %eax
+
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/p6/bdiv_q_1.asm b/third_party/gmp/mpn/x86/p6/bdiv_q_1.asm
new file mode 100644
index 0000000..a0a9d90
--- /dev/null
+++ b/third_party/gmp/mpn/x86/p6/bdiv_q_1.asm
@@ -0,0 +1,287 @@
+dnl  Intel P6 mpn_modexact_1_odd -- exact division style remainder.
+
+dnl  Rearranged from mpn/x86/p6/dive_1.asm by Marco Bodrato.
+
+dnl  Copyright 2001, 2002, 2007, 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C       odd  even  divisor
+C P6:  10.0  12.0  cycles/limb
+
+C MULFUNC_PROLOGUE(mpn_bdiv_q_1 mpn_pi1_bdiv_q_1)
+
+C The odd case is basically the same as mpn_modexact_1_odd, just with an
+C extra store, and it runs at the same 10 cycles which is the dependent
+C chain.
+C
+C The shifts for the even case aren't on the dependent chain so in principle
+C it could run the same too, but nothing running at 10 has been found.
+C Perhaps there's too many uops (an extra 4 over the odd case).
+
+defframe(PARAM_SHIFT,  24)
+defframe(PARAM_INVERSE,20)
+defframe(PARAM_DIVISOR,16)
+defframe(PARAM_SIZE,   12)
+defframe(PARAM_SRC,     8)
+defframe(PARAM_DST,     4)
+
+defframe(SAVE_EBX,     -4)
+defframe(SAVE_ESI,     -8)
+defframe(SAVE_EDI,    -12)
+defframe(SAVE_EBP,    -16)
+deflit(STACK_SPACE, 16)
+
+dnl  re-use parameter space
+define(VAR_INVERSE,`PARAM_SRC')
+
+	TEXT
+
+C mp_limb_t
+C mpn_pi1_bdiv_q_1 (mp_ptr dst, mp_srcptr src, mp_size_t size, mp_limb_t divisor,
+C		    mp_limb_t inverse, int shift)
+
+	ALIGN(16)
+PROLOGUE(mpn_pi1_bdiv_q_1)
+deflit(`FRAME',0)
+
+	subl	$STACK_SPACE, %esp	FRAME_subl_esp(STACK_SPACE)
+
+	movl	%esi, SAVE_ESI
+	movl	PARAM_SRC, %esi
+
+	movl	%ebx, SAVE_EBX
+	movl	PARAM_SIZE, %ebx
+
+	movl	%ebp, SAVE_EBP
+	movl	PARAM_INVERSE, %ebp
+
+	movl	PARAM_SHIFT, %ecx	C trailing twos
+
+L(common):
+	movl	%edi, SAVE_EDI
+	movl	PARAM_DST, %edi
+
+	leal	(%esi,%ebx,4), %esi	C src end
+
+	leal	(%edi,%ebx,4), %edi	C dst end
+	negl	%ebx			C -size
+
+	movl	(%esi,%ebx,4), %eax	C src[0]
+
+	orl	%ecx, %ecx
+	jz	L(odd_entry)
+
+	movl	%edi, PARAM_DST
+	movl	%ebp, VAR_INVERSE
+
+L(even):
+	C eax	src[0]
+	C ebx	counter, limbs, negative
+	C ecx	shift
+	C edx
+	C esi
+	C edi
+	C ebp
+
+	xorl	%ebp, %ebp		C initial carry bit
+	xorl	%edx, %edx		C initial carry limb (for size==1)
+
+	incl	%ebx
+	jz	L(even_one)
+
+	movl	(%esi,%ebx,4), %edi	C src[1]
+
+	shrdl(	%cl, %edi, %eax)
+
+	jmp	L(even_entry)
+
+
+L(even_top):
+	C eax	scratch
+	C ebx	counter, limbs, negative
+	C ecx	shift
+	C edx	scratch
+	C esi	&src[size]
+	C edi	&dst[size] and scratch
+	C ebp	carry bit
+
+	movl	(%esi,%ebx,4), %edi
+
+	mull	PARAM_DIVISOR
+
+	movl	-4(%esi,%ebx,4), %eax
+	shrdl(	%cl, %edi, %eax)
+
+	subl	%ebp, %eax
+
+	sbbl	%ebp, %ebp
+	subl	%edx, %eax
+
+	sbbl	$0, %ebp
+
+L(even_entry):
+	imull	VAR_INVERSE, %eax
+
+	movl	PARAM_DST, %edi
+	negl	%ebp
+
+	movl	%eax, -4(%edi,%ebx,4)
+	incl	%ebx
+	jnz	L(even_top)
+
+	mull	PARAM_DIVISOR
+
+	movl	-4(%esi), %eax
+
+L(even_one):
+	shrl	%cl, %eax
+	movl	SAVE_ESI, %esi
+
+	subl	%ebp, %eax
+	movl	SAVE_EBP, %ebp
+
+	subl	%edx, %eax
+	movl	SAVE_EBX, %ebx
+
+	imull	VAR_INVERSE, %eax
+
+	movl	%eax, -4(%edi)
+	movl	SAVE_EDI, %edi
+	addl	$STACK_SPACE, %esp
+
+	ret
+
+C The dependent chain here is
+C
+C	subl	%edx, %eax       1
+C	imull	%ebp, %eax       4
+C	mull	PARAM_DIVISOR    5
+C			       ----
+C	total			10
+C
+C and this is the measured speed.  No special scheduling is necessary, out
+C of order execution hides the load latency.
+
+L(odd_top):
+	C eax	scratch (src limb)
+	C ebx	counter, limbs, negative
+	C ecx	carry bit
+	C edx	carry limb, high of last product
+	C esi	&src[size]
+	C edi	&dst[size]
+	C ebp	inverse
+
+	mull	PARAM_DIVISOR
+
+	movl	(%esi,%ebx,4), %eax
+	subl	%ecx, %eax
+
+	sbbl	%ecx, %ecx
+	subl	%edx, %eax
+
+	sbbl	$0, %ecx
+
+L(odd_entry):
+	imull	%ebp, %eax
+
+	movl	%eax, (%edi,%ebx,4)
+	negl	%ecx
+
+	incl	%ebx
+	jnz	L(odd_top)
+
+
+	movl	SAVE_ESI, %esi
+
+	movl	SAVE_EDI, %edi
+
+	movl	SAVE_EBP, %ebp
+
+	movl	SAVE_EBX, %ebx
+	addl	$STACK_SPACE, %esp
+
+	ret
+
+EPILOGUE()
+
+C mp_limb_t mpn_bdiv_q_1 (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                           mp_limb_t divisor);
+C
+
+	ALIGN(16)
+PROLOGUE(mpn_bdiv_q_1)
+deflit(`FRAME',0)
+
+	movl	PARAM_DIVISOR, %eax
+	subl	$STACK_SPACE, %esp	FRAME_subl_esp(STACK_SPACE)
+
+	movl	%esi, SAVE_ESI
+	movl	PARAM_SRC, %esi
+
+	movl	%ebx, SAVE_EBX
+	movl	PARAM_SIZE, %ebx
+
+	bsfl	%eax, %ecx		C trailing twos
+
+	movl	%ebp, SAVE_EBP
+
+	shrl	%cl, %eax		C d without twos
+
+	movl	%eax, %edx
+	shrl	%eax			C d/2 without twos
+
+	movl	%edx, PARAM_DIVISOR
+	andl	$127, %eax
+
+ifdef(`PIC',`
+	LEA(	binvert_limb_table, %ebp)
+	movzbl	(%eax,%ebp), %ebp		C inv 8 bits
+',`
+	movzbl	binvert_limb_table(%eax), %ebp	C inv 8 bits
+')
+
+	leal	(%ebp,%ebp), %eax	C 2*inv
+
+	imull	%ebp, %ebp		C inv*inv
+	imull	%edx, %ebp	C inv*inv*d
+
+	subl	%ebp, %eax		C inv = 2*inv - inv*inv*d
+	leal	(%eax,%eax), %ebp	C 2*inv
+
+	imull	%eax, %eax		C inv*inv
+	imull	%edx, %eax	C inv*inv*d
+
+	subl	%eax, %ebp		C inv = 2*inv - inv*inv*d
+
+	jmp	L(common)
+
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86/p6/copyd.asm b/third_party/gmp/mpn/x86/p6/copyd.asm
new file mode 100644
index 0000000..1be7636
--- /dev/null
+++ b/third_party/gmp/mpn/x86/p6/copyd.asm
@@ -0,0 +1,178 @@
+dnl  Intel P6 mpn_copyd -- copy limb vector backwards.
+
+dnl  Copyright 2001, 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C P6: 1.75 cycles/limb, or 0.75 if no overlap
+
+
+C void mpn_copyd (mp_ptr dst, mp_srcptr src, mp_size_t size);
+C
+C An explicit loop is used because a decrementing rep movsl is a bit slow at
+C 2.4 c/l.  That rep movsl also has about a 40 cycle startup time, and the
+C code here stands a chance of being faster if the branches predict well.
+C
+C The slightly strange loop form seems necessary for the claimed speed.
+C Maybe load/store ordering affects it.
+C
+C The source and destination are checked to see if they're actually
+C overlapping, since it might be possible to use an incrementing rep movsl
+C at 0.75 c/l.  (It doesn't suffer the bad startup time of the decrementing
+C version.)
+C
+C Enhancements:
+C
+C Top speed for an all-integer copy is probably 1.0 c/l, being one load and
+C one store each cycle.  Unrolling the loop below would approach 1.0, but
+C it'd be good to know why something like store/load/subl + store/load/jnz
+C doesn't already run at 1.0 c/l.  It looks like it should decode in 2
+C cycles, but doesn't run that way.
+
+defframe(PARAM_SIZE,12)
+defframe(PARAM_SRC, 8)
+defframe(PARAM_DST, 4)
+
+dnl  re-using parameter space
+define(SAVE_ESI,`PARAM_SIZE')
+define(SAVE_EDI,`PARAM_SRC')
+
+	TEXT
+	ALIGN(16)
+
+PROLOGUE(mpn_copyd)
+deflit(`FRAME',0)
+
+	movl	PARAM_SIZE, %ecx
+
+	movl	%esi, SAVE_ESI
+	movl	PARAM_SRC, %esi
+
+	movl	%edi, SAVE_EDI
+	movl	PARAM_DST, %edi
+
+	subl	$1, %ecx
+	jb	L(zero)
+
+	movl	(%esi,%ecx,4), %eax		C src[size-1]
+	jz	L(one)
+
+	movl	-4(%esi,%ecx,4), %edx		C src[size-2]
+	subl	$2, %ecx
+	jbe	L(done_loop)			C 2 or 3 limbs only
+
+
+	C The usual overlap is
+	C
+	C     high                   low
+	C     +------------------+
+	C     |               dst|
+	C     +------------------+
+	C           +------------------+
+	C           |               src|
+	C           +------------------+
+	C
+	C We can use an incrementing copy in the following circumstances.
+	C
+	C     src+4*size<=dst, since then the regions are disjoint
+	C
+	C     src==dst, clearly (though this shouldn't occur normally)
+	C
+	C     src>dst, since in that case it's a requirement of the
+	C              parameters that src>=dst+size*4, and hence the
+	C              regions are disjoint
+	C
+
+	leal	(%edi,%ecx,4), %edx
+	cmpl	%edi, %esi
+	jae	L(use_movsl)		C src >= dst
+
+	cmpl	%edi, %edx
+	movl	4(%esi,%ecx,4), %edx	C src[size-2] again
+	jbe	L(use_movsl)		C src+4*size <= dst
+
+
+L(top):
+	C eax	prev high limb
+	C ebx
+	C ecx	counter, size-3 down to 0 or -1, inclusive, by 2s
+	C edx	prev low limb
+	C esi	src
+	C edi	dst
+	C ebp
+
+	movl	%eax, 8(%edi,%ecx,4)
+	movl	(%esi,%ecx,4), %eax
+
+	movl	%edx, 4(%edi,%ecx,4)
+	movl	-4(%esi,%ecx,4), %edx
+
+	subl	$2, %ecx
+	jnbe	L(top)
+
+
+L(done_loop):
+	movl	%eax, 8(%edi,%ecx,4)
+	movl	%edx, 4(%edi,%ecx,4)
+
+	C copy low limb (needed if size was odd, but will already have been
+	C done in the loop if size was even)
+	movl	(%esi), %eax
+L(one):
+	movl	%eax, (%edi)
+	movl	SAVE_EDI, %edi
+	movl	SAVE_ESI, %esi
+
+	ret
+
+
+L(use_movsl):
+	C eax
+	C ebx
+	C ecx	size-3
+	C edx
+	C esi	src
+	C edi	dst
+	C ebp
+
+	addl	$3, %ecx
+
+	cld		C better safe than sorry, see mpn/x86/README
+
+	rep
+	movsl
+
+L(zero):
+	movl	SAVE_ESI, %esi
+	movl	SAVE_EDI, %edi
+
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/p6/dive_1.asm b/third_party/gmp/mpn/x86/p6/dive_1.asm
new file mode 100644
index 0000000..7d61a18
--- /dev/null
+++ b/third_party/gmp/mpn/x86/p6/dive_1.asm
@@ -0,0 +1,267 @@
+dnl  Intel P6 mpn_modexact_1_odd -- exact division style remainder.
+
+dnl  Copyright 2001, 2002, 2007 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C       odd  even  divisor
+C P6:  10.0  12.0  cycles/limb
+
+
+C void mpn_divexact_1 (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                      mp_limb_t divisor);
+C
+C The odd case is basically the same as mpn_modexact_1_odd, just with an
+C extra store, and it runs at the same 10 cycles which is the dependent
+C chain.
+C
+C The shifts for the even case aren't on the dependent chain so in principle
+C it could run the same too, but nothing running at 10 has been found.
+C Perhaps there's too many uops (an extra 4 over the odd case).
+
+defframe(PARAM_DIVISOR,16)
+defframe(PARAM_SIZE,   12)
+defframe(PARAM_SRC,     8)
+defframe(PARAM_DST,     4)
+
+defframe(SAVE_EBX,     -4)
+defframe(SAVE_ESI,     -8)
+defframe(SAVE_EDI,    -12)
+defframe(SAVE_EBP,    -16)
+defframe(VAR_INVERSE, -20)
+deflit(STACK_SPACE, 20)
+
+	TEXT
+
+	ALIGN(16)
+PROLOGUE(mpn_divexact_1)
+deflit(`FRAME',0)
+
+	movl	PARAM_DIVISOR, %eax
+	subl	$STACK_SPACE, %esp	FRAME_subl_esp(STACK_SPACE)
+
+	movl	%esi, SAVE_ESI
+	movl	PARAM_SRC, %esi
+
+	movl	%ebx, SAVE_EBX
+	movl	PARAM_SIZE, %ebx
+
+	bsfl	%eax, %ecx		C trailing twos
+
+	movl	%ebp, SAVE_EBP
+
+	shrl	%cl, %eax		C d without twos
+
+	movl	%eax, %edx
+	shrl	%eax			C d/2 without twos
+
+	movl	%edx, PARAM_DIVISOR
+	andl	$127, %eax
+
+ifdef(`PIC',`
+	LEA(	binvert_limb_table, %ebp)
+	movzbl	(%eax,%ebp), %ebp		C inv 8 bits
+',`
+	movzbl	binvert_limb_table(%eax), %ebp	C inv 8 bits
+')
+
+	leal	(%ebp,%ebp), %eax	C 2*inv
+
+	imull	%ebp, %ebp		C inv*inv
+
+	movl	%edi, SAVE_EDI
+	movl	PARAM_DST, %edi
+
+	leal	(%esi,%ebx,4), %esi	C src end
+
+	imull	PARAM_DIVISOR, %ebp	C inv*inv*d
+
+	subl	%ebp, %eax		C inv = 2*inv - inv*inv*d
+	leal	(%eax,%eax), %ebp	C 2*inv
+
+	imull	%eax, %eax		C inv*inv
+
+	leal	(%edi,%ebx,4), %edi	C dst end
+	negl	%ebx			C -size
+
+	movl	%edi, PARAM_DST
+
+	imull	PARAM_DIVISOR, %eax	C inv*inv*d
+
+	subl	%eax, %ebp		C inv = 2*inv - inv*inv*d
+
+	ASSERT(e,`	C d*inv == 1 mod 2^GMP_LIMB_BITS
+	movl	PARAM_DIVISOR, %eax
+	imull	%ebp, %eax
+	cmpl	$1, %eax')
+
+	movl	%ebp, VAR_INVERSE
+	movl	(%esi,%ebx,4), %eax	C src[0]
+
+	orl	%ecx, %ecx
+	jnz	L(even)
+
+	C ecx initial carry is zero
+	jmp	L(odd_entry)
+
+
+C The dependent chain here is
+C
+C	subl	%edx, %eax       1
+C	imull	%ebp, %eax       4
+C	mull	PARAM_DIVISOR    5
+C			       ----
+C	total			10
+C
+C and this is the measured speed.  No special scheduling is necessary, out
+C of order execution hides the load latency.
+
+L(odd_top):
+	C eax	scratch (src limb)
+	C ebx	counter, limbs, negative
+	C ecx	carry bit
+	C edx	carry limb, high of last product
+	C esi	&src[size]
+	C edi	&dst[size]
+	C ebp
+
+	mull	PARAM_DIVISOR
+
+	movl	(%esi,%ebx,4), %eax
+	subl	%ecx, %eax
+
+	sbbl	%ecx, %ecx
+	subl	%edx, %eax
+
+	sbbl	$0, %ecx
+
+L(odd_entry):
+	imull	VAR_INVERSE, %eax
+
+	movl	%eax, (%edi,%ebx,4)
+	negl	%ecx
+
+	incl	%ebx
+	jnz	L(odd_top)
+
+
+	movl	SAVE_ESI, %esi
+
+	movl	SAVE_EDI, %edi
+
+	movl	SAVE_EBP, %ebp
+
+	movl	SAVE_EBX, %ebx
+	addl	$STACK_SPACE, %esp
+
+	ret
+
+
+L(even):
+	C eax	src[0]
+	C ebx	counter, limbs, negative
+	C ecx	shift
+	C edx
+	C esi
+	C edi
+	C ebp
+
+	xorl	%ebp, %ebp		C initial carry bit
+	xorl	%edx, %edx		C initial carry limb (for size==1)
+
+	incl	%ebx
+	jz	L(even_one)
+
+	movl	(%esi,%ebx,4), %edi	C src[1]
+
+	shrdl(	%cl, %edi, %eax)
+
+	jmp	L(even_entry)
+
+
+L(even_top):
+	C eax	scratch
+	C ebx	counter, limbs, negative
+	C ecx	shift
+	C edx	scratch
+	C esi	&src[size]
+	C edi	&dst[size] and scratch
+	C ebp	carry bit
+
+	movl	(%esi,%ebx,4), %edi
+
+	mull	PARAM_DIVISOR
+
+	movl	-4(%esi,%ebx,4), %eax
+	shrdl(	%cl, %edi, %eax)
+
+	subl	%ebp, %eax
+
+	sbbl	%ebp, %ebp
+	subl	%edx, %eax
+
+	sbbl	$0, %ebp
+
+L(even_entry):
+	imull	VAR_INVERSE, %eax
+
+	movl	PARAM_DST, %edi
+	negl	%ebp
+
+	movl	%eax, -4(%edi,%ebx,4)
+	incl	%ebx
+	jnz	L(even_top)
+
+
+
+	mull	PARAM_DIVISOR
+
+	movl	-4(%esi), %eax
+
+L(even_one):
+	shrl	%cl, %eax
+	movl	SAVE_ESI, %esi
+
+	subl	%ebp, %eax
+	movl	SAVE_EBP, %ebp
+
+	subl	%edx, %eax
+	movl	SAVE_EBX, %ebx
+
+	imull	VAR_INVERSE, %eax
+
+	movl	%eax, -4(%edi)
+	movl	SAVE_EDI, %edi
+	addl	$STACK_SPACE, %esp
+
+	ret
+
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86/p6/gcd_11.asm b/third_party/gmp/mpn/x86/p6/gcd_11.asm
new file mode 100644
index 0000000..80e055e
--- /dev/null
+++ b/third_party/gmp/mpn/x86/p6/gcd_11.asm
@@ -0,0 +1,83 @@
+dnl  x86 mpn_gcd_11 optimised for processors with fast BSF.
+
+dnl  Based on the K7 gcd_1.asm, by Kevin Ryde.  Rehacked by Torbjorn Granlund.
+
+dnl  Copyright 2000-2002, 2005, 2009, 2011, 2012, 2015 Free Software
+dnl  Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C	     cycles/bit (approx)
+C AMD K7	 7.80
+C AMD K8,K9	 7.79
+C AMD K10	 4.08
+C AMD bd1	 ?
+C AMD bobcat	 7.82
+C Intel P4-2	14.9
+C Intel P4-3/4	14.0
+C Intel P6/13	 5.09
+C Intel core2	 4.22
+C Intel NHM	 5.00
+C Intel SBR	 5.00
+C Intel atom	17.1
+C VIA nano	?
+C Numbers measured with: speed -CD -s16-32 -t16 mpn_gcd_1
+
+
+define(`u0',    `%eax')
+define(`v0',    `%edx')
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_gcd_11)
+	push	%edi
+	push	%esi
+
+	mov	12(%esp), %eax
+	mov	16(%esp), %edx
+	jmp	L(odd)
+
+	ALIGN(16)		C               K10   BD    C2    NHM   SBR
+L(top):	cmovc(	%esi, %eax)	C u = |v - u|   0,3   0,3   0,6   0,5   0,5
+	cmovc(	%edi, %edx)	C v = min(u,v)  0,3   0,3   2,8   1,7   1,7
+	shr	%cl, %eax	C               1,7   1,6   2,8   2,8   2,8
+L(odd):	mov	%edx, %esi	C               1     1     4     3     3
+	sub	%eax, %esi	C               2     2     5     4     4
+	bsf	%esi, %ecx	C               3     3     6     5     5
+	mov	%eax, %edi	C               2     2     3     3     4
+	sub	%edx, %eax	C               2     2     4     3     4
+	jnz	L(top)		C
+
+L(end):	mov	%edx, %eax
+	pop	%esi
+	pop	%edi
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/p6/gmp-mparam.h b/third_party/gmp/mpn/x86/p6/gmp-mparam.h
new file mode 100644
index 0000000..96c96fd
--- /dev/null
+++ b/third_party/gmp/mpn/x86/p6/gmp-mparam.h
@@ -0,0 +1,194 @@
+/* Intel P6 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 1999-2003, 2008-2010, 2012 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+
+/* NOTE: In a fat binary build SQR_TOOM2_THRESHOLD here cannot be more than the
+   value in mpn/x86/p6/gmp-mparam.h.  The latter is used as a hard limit in
+   mpn/x86/p6/sqr_basecase.asm.  */
+
+
+/* 1867 MHz P6 model 13 */
+
+#define MOD_1_NORM_THRESHOLD                 4
+#define MOD_1_UNNORM_THRESHOLD               4
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          5
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          4
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        11
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD         0  /* never mpn_mod_1s_2p */
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD      8
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           21
+
+#define MUL_TOOM22_THRESHOLD                20
+#define MUL_TOOM33_THRESHOLD                74
+#define MUL_TOOM44_THRESHOLD               181
+#define MUL_TOOM6H_THRESHOLD               252
+#define MUL_TOOM8H_THRESHOLD               363
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      73
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     114
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     115
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD      80
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 30
+#define SQR_TOOM3_THRESHOLD                101
+#define SQR_TOOM4_THRESHOLD                154
+#define SQR_TOOM6_THRESHOLD                222
+#define SQR_TOOM8_THRESHOLD                527
+
+#define MULMID_TOOM42_THRESHOLD             58
+
+#define MULMOD_BNM1_THRESHOLD               13
+#define SQRMOD_BNM1_THRESHOLD               17
+
+#define POWM_SEC_TABLE  4,23,258,768,2388
+
+#define MUL_FFT_MODF_THRESHOLD             565  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    565, 5}, {     25, 6}, {     13, 5}, {     27, 6}, \
+    {     25, 7}, {     13, 6}, {     28, 7}, {     15, 6}, \
+    {     31, 7}, {     17, 6}, {     35, 7}, {     27, 8}, \
+    {     15, 7}, {     35, 8}, {     19, 7}, {     41, 8}, \
+    {     23, 7}, {     47, 8}, {     27, 9}, {     15, 8}, \
+    {     31, 7}, {     63, 8}, {     39, 9}, {     23, 5}, \
+    {    383, 4}, {    991, 5}, {    511, 6}, {    267, 7}, \
+    {    157, 8}, {     91, 9}, {     47, 8}, {    111, 9}, \
+    {     63, 8}, {    127, 9}, {     79,10}, {     47, 9}, \
+    {     95,11}, {     31,10}, {     63, 9}, {    135,10}, \
+    {     79, 9}, {    159,10}, {     95,11}, {     63,10}, \
+    {    143, 9}, {    287,10}, {    159,11}, {     95,10}, \
+    {    191,12}, {     63,11}, {    127,10}, {    255, 9}, \
+    {    511,10}, {    271, 9}, {    543,10}, {    287,11}, \
+    {    159,10}, {    335, 9}, {    671,11}, {    191,10}, \
+    {    383, 9}, {    767,10}, {    399, 9}, {    799,10}, \
+    {    415,11}, {    223,12}, {    127,11}, {    255,10}, \
+    {    543, 9}, {   1087,11}, {    287,10}, {    607,11}, \
+    {    319,10}, {    671,12}, {    191,11}, {    383,10}, \
+    {    799,11}, {    415,10}, {    831,13}, {    127,12}, \
+    {    255,11}, {    543,10}, {   1087,11}, {    607,10}, \
+    {   1215,12}, {    319,11}, {    671,10}, {   1343,11}, \
+    {    735,10}, {   1471,12}, {    383,11}, {    799,10}, \
+    {   1599,11}, {    863,12}, {    447,11}, {    959,13}, \
+    {    255,12}, {    511,11}, {   1087,12}, {    575,11}, \
+    {   1215,12}, {    639,11}, {   1343,12}, {    703,11}, \
+    {   1471,13}, {    383,12}, {    831,11}, {   1727,12}, \
+    {    959,14}, {    255,13}, {    511,12}, {   1215,13}, \
+    {    639,12}, {   1471,11}, {   2943,13}, {    767,12}, \
+    {   1727,13}, {    895,12}, {   1919,14}, {    511,13}, \
+    {   1023,12}, {   2111,13}, {   1151,12}, {   2431,13}, \
+    {   1407,12}, {   2815,14}, {    767,13}, {   1663,12}, \
+    {   3455,13}, {   8192,14}, {  16384,15}, {  32768,16} }
+#define MUL_FFT_TABLE3_SIZE 132
+#define MUL_FFT_THRESHOLD                 6784
+
+#define SQR_FFT_MODF_THRESHOLD             472  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    472, 5}, {     25, 6}, {     13, 5}, {     27, 6}, \
+    {     25, 7}, {     13, 6}, {     27, 7}, {     15, 6}, \
+    {     31, 7}, {     17, 6}, {     35, 7}, {     27, 8}, \
+    {     15, 7}, {     35, 8}, {     19, 7}, {     41, 8}, \
+    {     23, 7}, {     49, 8}, {     27, 9}, {     15, 8}, \
+    {     39, 9}, {     23, 8}, {     51,10}, {     15, 9}, \
+    {     31, 8}, {     63, 4}, {   1023, 8}, {     67, 9}, \
+    {     39, 5}, {    639, 4}, {   1471, 6}, {    383, 7}, \
+    {    209, 8}, {    119, 9}, {     63, 7}, {    255, 8}, \
+    {    139, 9}, {     71, 8}, {    143, 9}, {     79,10}, \
+    {     47, 9}, {     95,11}, {     31,10}, {     63, 9}, \
+    {    135,10}, {     79, 9}, {    159, 8}, {    319, 9}, \
+    {    167,10}, {     95,11}, {     63,10}, {    143, 9}, \
+    {    287,10}, {    159,11}, {     95,10}, {    191,12}, \
+    {     63,11}, {    127,10}, {    255, 9}, {    543, 8}, \
+    {   1087,10}, {    287, 9}, {    575,11}, {    159,10}, \
+    {    319, 9}, {    639,10}, {    335, 9}, {    671,10}, \
+    {    351, 9}, {    703,11}, {    191,10}, {    383, 9}, \
+    {    767,10}, {    399, 9}, {    799,10}, {    415, 9}, \
+    {    831,11}, {    223,12}, {    127,11}, {    255,10}, \
+    {    543, 9}, {   1087,11}, {    287,10}, {    607, 9}, \
+    {   1215,11}, {    319,10}, {    671, 9}, {   1343,11}, \
+    {    351,10}, {    703,12}, {    191,11}, {    383,10}, \
+    {    799,11}, {    415,10}, {    831,13}, {    127,12}, \
+    {    255,11}, {    543,10}, {   1087,11}, {    607,12}, \
+    {    319,11}, {    671,10}, {   1343,11}, {    735,12}, \
+    {    383,11}, {    799,10}, {   1599,11}, {    863,12}, \
+    {    447,11}, {    959,13}, {    255,12}, {    511,11}, \
+    {   1087,12}, {    575,11}, {   1215,12}, {    639,11}, \
+    {   1343,12}, {    703,11}, {   1471,13}, {    383,12}, \
+    {    767,11}, {   1599,12}, {    831,11}, {   1727,12}, \
+    {    959,14}, {    255,13}, {    511,12}, {   1215,13}, \
+    {    639,12}, {   1471,13}, {    767,12}, {   1727,13}, \
+    {    895,12}, {   1919,14}, {    511,13}, {   1023,12}, \
+    {   2111,13}, {   1151,12}, {   2431,13}, {   1407,14}, \
+    {    767,13}, {   1663,12}, {   3455,13}, {   8192,14}, \
+    {  16384,15}, {  32768,16} }
+#define SQR_FFT_TABLE3_SIZE 146
+#define SQR_FFT_THRESHOLD                 5760
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  33
+#define MULLO_MUL_N_THRESHOLD            13463
+
+#define DC_DIV_QR_THRESHOLD                 20
+#define DC_DIVAPPR_Q_THRESHOLD              56
+#define DC_BDIV_QR_THRESHOLD                60
+#define DC_BDIV_Q_THRESHOLD                134
+
+#define INV_MULMOD_BNM1_THRESHOLD           38
+#define INV_NEWTON_THRESHOLD                66
+#define INV_APPR_THRESHOLD                  63
+
+#define BINV_NEWTON_THRESHOLD              250
+#define REDC_1_TO_REDC_N_THRESHOLD          63
+
+#define MU_DIV_QR_THRESHOLD               1164
+#define MU_DIVAPPR_Q_THRESHOLD             979
+#define MUPI_DIV_QR_THRESHOLD               38
+#define MU_BDIV_QR_THRESHOLD              1442
+#define MU_BDIV_Q_THRESHOLD               1470
+
+#define MATRIX22_STRASSEN_THRESHOLD         17
+#define HGCD_THRESHOLD                      64
+#define HGCD_APPR_THRESHOLD                105
+#define HGCD_REDUCE_THRESHOLD             3524
+#define GCD_DC_THRESHOLD                   386
+#define GCDEXT_DC_THRESHOLD                309
+#define JACOBI_BASE_METHOD                   1
+
+#define GET_STR_DC_THRESHOLD                13
+#define GET_STR_PRECOMPUTE_THRESHOLD        26
+#define SET_STR_DC_THRESHOLD               587
+#define SET_STR_PRECOMPUTE_THRESHOLD      1104
diff --git a/third_party/gmp/mpn/x86/p6/lshsub_n.asm b/third_party/gmp/mpn/x86/p6/lshsub_n.asm
new file mode 100644
index 0000000..7ada213
--- /dev/null
+++ b/third_party/gmp/mpn/x86/p6/lshsub_n.asm
@@ -0,0 +1,169 @@
+dnl  Intel P6 mpn_lshsub_n -- mpn papillion support.
+
+dnl  Copyright 2006 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C P6/13: 3.35 cycles/limb	(separate mpn_sub_n + mpn_lshift needs 4.12)
+
+C (1) The loop is not scheduled in any way, and scheduling attempts have not
+C     improved speed on P6/13.  Presumably, the K7 will want scheduling, if it
+C     at all wants to use MMX.
+C (2) We could save a register by not alternatingly using eax and edx in the
+C     loop.
+
+define(`rp',	`%edi')
+define(`up',	`%esi')
+define(`vp',	`%ebx')
+define(`n',	`%ecx')
+define(`cnt',	`%mm7')
+
+ASM_START()
+
+	TEXT
+	ALIGN(16)
+
+PROLOGUE(mpn_lshsub_n)
+	push	%edi
+	push	%esi
+	push	%ebx
+
+	mov	16(%esp), rp
+	mov	20(%esp), up
+	mov	24(%esp), vp
+	mov	28(%esp), n
+	mov	$32, %eax
+	sub	32(%esp), %eax
+	movd	%eax, cnt
+
+	lea	(up,n,4), up
+	lea	(vp,n,4), vp
+	lea	(rp,n,4), rp
+
+	neg	n
+	mov	n, %eax
+	and	$-8, n
+	and	$7, %eax
+	shl	%eax				C eax = 2x
+	lea	(%eax,%eax,4), %edx		C edx = 10x
+ifdef(`PIC',`
+	call	L(pic_calc)
+L(here):
+',`
+	lea	L(ent)(%eax,%edx,2), %eax	C eax = 22x
+')
+
+	pxor	%mm1, %mm1
+	pxor	%mm0, %mm0
+
+	jmp	*%eax
+
+ifdef(`PIC',`
+L(pic_calc):
+	C See mpn/x86/README about old gas bugs
+	lea	(%eax,%edx,2), %eax
+	add	$L(ent)-L(here), %eax
+	add	(%esp), %eax
+	ret_internal
+')
+
+L(end):	C compute (cy<<cnt) | (edx>>(32-cnt))
+	sbb	%eax, %eax
+	neg	%eax
+	mov	32(%esp), %ecx
+	shld	%cl, %edx, %eax
+
+	emms
+
+	pop	%ebx
+	pop	%esi
+	pop	%edi
+	ret
+	ALIGN(16)
+L(top):	jecxz	L(end)
+L(ent):	mov	   0(up,n,4), %eax
+	sbb	   0(vp,n,4), %eax
+	movd	   %eax, %mm0
+	punpckldq  %mm0, %mm1
+	psrlq	   %mm7, %mm1
+	movd	   %mm1, 0(rp,n,4)
+
+	mov	   4(up,n,4), %edx
+	sbb	   4(vp,n,4), %edx
+	movd	   %edx, %mm1
+	punpckldq  %mm1, %mm0
+	psrlq	   %mm7, %mm0
+	movd	   %mm0, 4(rp,n,4)
+
+	mov	   8(up,n,4), %eax
+	sbb	   8(vp,n,4), %eax
+	movd	   %eax, %mm0
+	punpckldq  %mm0, %mm1
+	psrlq	   %mm7, %mm1
+	movd	   %mm1, 8(rp,n,4)
+
+	mov	   12(up,n,4), %edx
+	sbb	   12(vp,n,4), %edx
+	movd	   %edx, %mm1
+	punpckldq  %mm1, %mm0
+	psrlq	   %mm7, %mm0
+	movd	   %mm0, 12(rp,n,4)
+
+	mov	   16(up,n,4), %eax
+	sbb	   16(vp,n,4), %eax
+	movd	   %eax, %mm0
+	punpckldq  %mm0, %mm1
+	psrlq	   %mm7, %mm1
+	movd	   %mm1, 16(rp,n,4)
+
+	mov	   20(up,n,4), %edx
+	sbb	   20(vp,n,4), %edx
+	movd	   %edx, %mm1
+	punpckldq  %mm1, %mm0
+	psrlq	   %mm7, %mm0
+	movd	   %mm0, 20(rp,n,4)
+
+	mov	   24(up,n,4), %eax
+	sbb	   24(vp,n,4), %eax
+	movd	   %eax, %mm0
+	punpckldq  %mm0, %mm1
+	psrlq	   %mm7, %mm1
+	movd	   %mm1, 24(rp,n,4)
+
+	mov	   28(up,n,4), %edx
+	sbb	   28(vp,n,4), %edx
+	movd	   %edx, %mm1
+	punpckldq  %mm1, %mm0
+	psrlq	   %mm7, %mm0
+	movd	   %mm0, 28(rp,n,4)
+
+	lea	   8(n), n
+	jmp	   L(top)
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/p6/mmx/divrem_1.asm b/third_party/gmp/mpn/x86/p6/mmx/divrem_1.asm
new file mode 100644
index 0000000..5300616
--- /dev/null
+++ b/third_party/gmp/mpn/x86/p6/mmx/divrem_1.asm
@@ -0,0 +1,767 @@
+dnl  Intel Pentium-II mpn_divrem_1 -- mpn by limb division.
+
+dnl  Copyright 1999-2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C P6MMX: 25.0 cycles/limb integer part, 17.5 cycles/limb fraction part.
+
+
+C mp_limb_t mpn_divrem_1 (mp_ptr dst, mp_size_t xsize,
+C                         mp_srcptr src, mp_size_t size,
+C                         mp_limb_t divisor);
+C mp_limb_t mpn_divrem_1c (mp_ptr dst, mp_size_t xsize,
+C                          mp_srcptr src, mp_size_t size,
+C                          mp_limb_t divisor, mp_limb_t carry);
+C mp_limb_t mpn_preinv_divrem_1 (mp_ptr dst, mp_size_t xsize,
+C                                mp_srcptr src, mp_size_t size,
+C                                mp_limb_t divisor, mp_limb_t inverse,
+C                                unsigned shift);
+C
+C This code is a lightly reworked version of mpn/x86/k7/mmx/divrem_1.asm,
+C see that file for some comments.  It's possible what's here can be improved.
+
+
+dnl  MUL_THRESHOLD is the value of xsize+size at which the multiply by
+dnl  inverse method is used, rather than plain "divl"s.  Minimum value 1.
+dnl
+dnl  The different speeds of the integer and fraction parts means that using
+dnl  xsize+size isn't quite right.  The threshold wants to be a bit higher
+dnl  for the integer part and a bit lower for the fraction part.  (Or what's
+dnl  really wanted is to speed up the integer part!)
+dnl
+dnl  The threshold is set to make the integer part right.  At 4 limbs the
+dnl  div and mul are about the same there, but on the fractional part the
+dnl  mul is much faster.
+
+deflit(MUL_THRESHOLD, 4)
+
+
+defframe(PARAM_PREINV_SHIFT,   28)  dnl mpn_preinv_divrem_1
+defframe(PARAM_PREINV_INVERSE, 24)  dnl mpn_preinv_divrem_1
+defframe(PARAM_CARRY,  24)          dnl mpn_divrem_1c
+defframe(PARAM_DIVISOR,20)
+defframe(PARAM_SIZE,   16)
+defframe(PARAM_SRC,    12)
+defframe(PARAM_XSIZE,  8)
+defframe(PARAM_DST,    4)
+
+defframe(SAVE_EBX,    -4)
+defframe(SAVE_ESI,    -8)
+defframe(SAVE_EDI,    -12)
+defframe(SAVE_EBP,    -16)
+
+defframe(VAR_NORM,    -20)
+defframe(VAR_INVERSE, -24)
+defframe(VAR_SRC,     -28)
+defframe(VAR_DST,     -32)
+defframe(VAR_DST_STOP,-36)
+
+deflit(STACK_SPACE, 36)
+
+	TEXT
+	ALIGN(16)
+
+PROLOGUE(mpn_preinv_divrem_1)
+deflit(`FRAME',0)
+	movl	PARAM_XSIZE, %ecx
+	subl	$STACK_SPACE, %esp	FRAME_subl_esp(STACK_SPACE)
+
+	movl	%esi, SAVE_ESI
+	movl	PARAM_SRC, %esi
+
+	movl	%ebx, SAVE_EBX
+	movl	PARAM_SIZE, %ebx
+
+	movl	%ebp, SAVE_EBP
+	movl	PARAM_DIVISOR, %ebp
+
+	movl	%edi, SAVE_EDI
+	movl	PARAM_DST, %edx
+
+	movl	-4(%esi,%ebx,4), %eax	C src high limb
+	xorl	%edi, %edi		C initial carry (if can't skip a div)
+
+	C
+
+	leal	8(%edx,%ecx,4), %edx	C &dst[xsize+2]
+	xor	%ecx, %ecx
+
+	movl	%edx, VAR_DST_STOP	C &dst[xsize+2]
+	cmpl	%ebp, %eax		C high cmp divisor
+
+	cmovc(	%eax, %edi)		C high is carry if high<divisor
+
+	cmovnc(	%eax, %ecx)		C 0 if skip div, src high if not
+					C (the latter in case src==dst)
+
+	movl	%ecx, -12(%edx,%ebx,4)	C dst high limb
+
+	sbbl	$0, %ebx		C skip one division if high<divisor
+	movl	PARAM_PREINV_SHIFT, %ecx
+
+	leal	-8(%edx,%ebx,4), %edx	C &dst[xsize+size]
+	movl	$32, %eax
+
+	movl	%edx, VAR_DST		C &dst[xsize+size]
+
+	shll	%cl, %ebp		C d normalized
+	subl	%ecx, %eax
+	movl	%ecx, VAR_NORM
+
+	movd	%eax, %mm7		C rshift
+	movl	PARAM_PREINV_INVERSE, %eax
+	jmp	L(start_preinv)
+
+EPILOGUE()
+
+
+
+	ALIGN(16)
+
+PROLOGUE(mpn_divrem_1c)
+deflit(`FRAME',0)
+	movl	PARAM_CARRY, %edx
+
+	movl	PARAM_SIZE, %ecx
+	subl	$STACK_SPACE, %esp
+deflit(`FRAME',STACK_SPACE)
+
+	movl	%ebx, SAVE_EBX
+	movl	PARAM_XSIZE, %ebx
+
+	movl	%edi, SAVE_EDI
+	movl	PARAM_DST, %edi
+
+	movl	%ebp, SAVE_EBP
+	movl	PARAM_DIVISOR, %ebp
+
+	movl	%esi, SAVE_ESI
+	movl	PARAM_SRC, %esi
+
+	leal	-4(%edi,%ebx,4), %edi
+	jmp	L(start_1c)
+
+EPILOGUE()
+
+
+	C offset 0x31, close enough to aligned
+PROLOGUE(mpn_divrem_1)
+deflit(`FRAME',0)
+
+	movl	PARAM_SIZE, %ecx
+	movl	$0, %edx		C initial carry (if can't skip a div)
+	subl	$STACK_SPACE, %esp
+deflit(`FRAME',STACK_SPACE)
+
+	movl	%ebp, SAVE_EBP
+	movl	PARAM_DIVISOR, %ebp
+
+	movl	%ebx, SAVE_EBX
+	movl	PARAM_XSIZE, %ebx
+
+	movl	%esi, SAVE_ESI
+	movl	PARAM_SRC, %esi
+	orl	%ecx, %ecx		C size
+
+	movl	%edi, SAVE_EDI
+	movl	PARAM_DST, %edi
+
+	leal	-4(%edi,%ebx,4), %edi	C &dst[xsize-1]
+	jz	L(no_skip_div)		C if size==0
+
+	movl	-4(%esi,%ecx,4), %eax	C src high limb
+	xorl	%esi, %esi
+	cmpl	%ebp, %eax		C high cmp divisor
+
+	cmovc(	%eax, %edx)		C high is carry if high<divisor
+
+	cmovnc(	%eax, %esi)		C 0 if skip div, src high if not
+					C (the latter in case src==dst)
+
+	movl	%esi, (%edi,%ecx,4)	C dst high limb
+
+	sbbl	$0, %ecx		C size-1 if high<divisor
+	movl	PARAM_SRC, %esi		C reload
+L(no_skip_div):
+
+
+L(start_1c):
+	C eax
+	C ebx	xsize
+	C ecx	size
+	C edx	carry
+	C esi	src
+	C edi	&dst[xsize-1]
+	C ebp	divisor
+
+	leal	(%ebx,%ecx), %eax	C size+xsize
+	cmpl	$MUL_THRESHOLD, %eax
+	jae	L(mul_by_inverse)
+
+	orl	%ecx, %ecx
+	jz	L(divide_no_integer)
+
+L(divide_integer):
+	C eax	scratch (quotient)
+	C ebx	xsize
+	C ecx	counter
+	C edx	scratch (remainder)
+	C esi	src
+	C edi	&dst[xsize-1]
+	C ebp	divisor
+
+	movl	-4(%esi,%ecx,4), %eax
+
+	divl	%ebp
+
+	movl	%eax, (%edi,%ecx,4)
+	decl	%ecx
+	jnz	L(divide_integer)
+
+
+L(divide_no_integer):
+	movl	PARAM_DST, %edi
+	orl	%ebx, %ebx
+	jnz	L(divide_fraction)
+
+L(divide_done):
+	movl	SAVE_ESI, %esi
+
+	movl	SAVE_EDI, %edi
+
+	movl	SAVE_EBX, %ebx
+	movl	%edx, %eax
+
+	movl	SAVE_EBP, %ebp
+	addl	$STACK_SPACE, %esp
+
+	ret
+
+
+L(divide_fraction):
+	C eax	scratch (quotient)
+	C ebx	counter
+	C ecx
+	C edx	scratch (remainder)
+	C esi
+	C edi	dst
+	C ebp	divisor
+
+	movl	$0, %eax
+
+	divl	%ebp
+
+	movl	%eax, -4(%edi,%ebx,4)
+	decl	%ebx
+	jnz	L(divide_fraction)
+
+	jmp	L(divide_done)
+
+
+
+C -----------------------------------------------------------------------------
+
+L(mul_by_inverse):
+	C eax
+	C ebx	xsize
+	C ecx	size
+	C edx	carry
+	C esi	src
+	C edi	&dst[xsize-1]
+	C ebp	divisor
+
+	leal	12(%edi), %ebx		C &dst[xsize+2], loop dst stop
+
+	movl	%ebx, VAR_DST_STOP
+	leal	4(%edi,%ecx,4), %edi	C &dst[xsize+size]
+
+	movl	%edi, VAR_DST
+	movl	%ecx, %ebx		C size
+
+	bsrl	%ebp, %ecx		C 31-l
+	movl	%edx, %edi		C carry
+
+	leal	1(%ecx), %eax		C 32-l
+	xorl	$31, %ecx		C l
+
+	movl	%ecx, VAR_NORM
+	movl	$-1, %edx
+
+	shll	%cl, %ebp		C d normalized
+	movd	%eax, %mm7
+
+	movl	$-1, %eax
+	subl	%ebp, %edx		C (b-d)-1 giving edx:eax = b*(b-d)-1
+
+	divl	%ebp			C floor (b*(b-d)-1) / d
+
+L(start_preinv):
+	C eax	inverse
+	C ebx	size
+	C ecx	shift
+	C edx
+	C esi	src
+	C edi	carry
+	C ebp	divisor
+	C
+	C mm7	rshift
+
+	movl	%eax, VAR_INVERSE
+	orl	%ebx, %ebx		C size
+	leal	-12(%esi,%ebx,4), %eax	C &src[size-3]
+
+	movl	%eax, VAR_SRC
+	jz	L(start_zero)
+
+	movl	8(%eax), %esi		C src high limb
+	cmpl	$1, %ebx
+	jz	L(start_one)
+
+L(start_two_or_more):
+	movl	4(%eax), %edx		C src second highest limb
+
+	shldl(	%cl, %esi, %edi)	C n2 = carry,high << l
+
+	shldl(	%cl, %edx, %esi)	C n10 = high,second << l
+
+	cmpl	$2, %ebx
+	je	L(integer_two_left)
+	jmp	L(integer_top)
+
+
+L(start_one):
+	shldl(	%cl, %esi, %edi)	C n2 = carry,high << l
+
+	shll	%cl, %esi		C n10 = high << l
+	jmp	L(integer_one_left)
+
+
+L(start_zero):
+	C Can be here with xsize==0 if mpn_preinv_divrem_1 had size==1 and
+	C skipped a division.
+
+	shll	%cl, %edi		C n2 = carry << l
+	movl	%edi, %eax		C return value for zero_done
+	cmpl	$0, PARAM_XSIZE
+
+	je	L(zero_done)
+	jmp	L(fraction_some)
+
+
+
+C -----------------------------------------------------------------------------
+C
+C This loop runs at about 25 cycles, which is probably sub-optimal, and
+C certainly more than the dependent chain would suggest.  A better loop, or
+C a better rough analysis of what's possible, would be welcomed.
+C
+C In the current implementation, the following successively dependent
+C micro-ops seem to exist.
+C
+C		       uops
+C		n2+n1	1   (addl)
+C		mul	5
+C		q1+1	3   (addl/adcl)
+C		mul	5
+C		sub	3   (subl/sbbl)
+C		addback	2   (cmov)
+C		       ---
+C		       19
+C
+C Lack of registers hinders explicit scheduling and it might be that the
+C normal out of order execution isn't able to hide enough under the mul
+C latencies.
+C
+C Using sarl/negl to pick out n1 for the n2+n1 stage is a touch faster than
+C cmov (and takes one uop off the dependent chain).  A sarl/andl/addl
+C combination was tried for the addback (despite the fact it would lengthen
+C the dependent chain) but found to be no faster.
+
+
+	ALIGN(16)
+L(integer_top):
+	C eax	scratch
+	C ebx	scratch (nadj, q1)
+	C ecx	scratch (src, dst)
+	C edx	scratch
+	C esi	n10
+	C edi	n2
+	C ebp	d
+	C
+	C mm0	scratch (src qword)
+	C mm7	rshift for normalization
+
+	movl	%esi, %eax
+	movl	%ebp, %ebx
+
+	sarl	$31, %eax          C -n1
+	movl	VAR_SRC, %ecx
+
+	andl	%eax, %ebx         C -n1 & d
+	negl	%eax               C n1
+
+	addl	%esi, %ebx         C nadj = n10 + (-n1 & d), ignoring overflow
+	addl	%edi, %eax         C n2+n1
+	movq	(%ecx), %mm0       C next src limb and the one below it
+
+	mull	VAR_INVERSE        C m*(n2+n1)
+
+	subl	$4, %ecx
+
+	movl	%ecx, VAR_SRC
+
+	C
+
+	C
+
+	addl	%ebx, %eax         C m*(n2+n1) + nadj, low giving carry flag
+	movl	%ebp, %eax	   C d
+	leal	1(%edi), %ebx      C n2+1
+
+	adcl	%edx, %ebx         C 1 + high(n2<<32 + m*(n2+n1) + nadj) = q1+1
+	jz	L(q1_ff)
+
+	mull	%ebx		   C (q1+1)*d
+
+	movl	VAR_DST, %ecx
+	psrlq	%mm7, %mm0
+
+	C
+
+	C
+
+	C
+
+	subl	%eax, %esi
+	movl	VAR_DST_STOP, %eax
+
+	sbbl	%edx, %edi	   C n - (q1+1)*d
+	movl	%esi, %edi	   C remainder -> n2
+	leal	(%ebp,%esi), %edx
+
+	cmovc(	%edx, %edi)	   C n - q1*d if underflow from using q1+1
+	movd	%mm0, %esi
+
+	sbbl	$0, %ebx	   C q
+	subl	$4, %ecx
+
+	movl	%ebx, (%ecx)
+	cmpl	%eax, %ecx
+
+	movl	%ecx, VAR_DST
+	jne	L(integer_top)
+
+
+L(integer_loop_done):
+
+
+C -----------------------------------------------------------------------------
+C
+C Here, and in integer_one_left below, an sbbl $0 is used rather than a jz
+C q1_ff special case.  This make the code a bit smaller and simpler, and
+C costs only 2 cycles (each).
+
+L(integer_two_left):
+	C eax	scratch
+	C ebx	scratch (nadj, q1)
+	C ecx	scratch (src, dst)
+	C edx	scratch
+	C esi	n10
+	C edi	n2
+	C ebp	divisor
+	C
+	C mm7	rshift
+
+
+	movl	%esi, %eax
+	movl	%ebp, %ebx
+
+	sarl	$31, %eax          C -n1
+	movl	PARAM_SRC, %ecx
+
+	andl	%eax, %ebx         C -n1 & d
+	negl	%eax               C n1
+
+	addl	%esi, %ebx         C nadj = n10 + (-n1 & d), ignoring overflow
+	addl	%edi, %eax         C n2+n1
+
+	mull	VAR_INVERSE        C m*(n2+n1)
+
+	movd	(%ecx), %mm0	   C src low limb
+
+	movl	VAR_DST_STOP, %ecx
+
+	C
+
+	C
+
+	addl	%ebx, %eax         C m*(n2+n1) + nadj, low giving carry flag
+	leal	1(%edi), %ebx      C n2+1
+	movl	%ebp, %eax	   C d
+
+	adcl	%edx, %ebx         C 1 + high(n2<<32 + m*(n2+n1) + nadj) = q1+1
+
+	sbbl	$0, %ebx
+
+	mull	%ebx		   C (q1+1)*d
+
+	psllq	$32, %mm0
+
+	psrlq	%mm7, %mm0
+
+	C
+
+	C
+
+	subl	%eax, %esi
+
+	sbbl	%edx, %edi	   C n - (q1+1)*d
+	movl	%esi, %edi	   C remainder -> n2
+	leal	(%ebp,%esi), %edx
+
+	cmovc(	%edx, %edi)	   C n - q1*d if underflow from using q1+1
+	movd	%mm0, %esi
+
+	sbbl	$0, %ebx	   C q
+
+	movl	%ebx, -4(%ecx)
+
+
+C -----------------------------------------------------------------------------
+L(integer_one_left):
+	C eax	scratch
+	C ebx	scratch (nadj, q1)
+	C ecx	scratch (dst)
+	C edx	scratch
+	C esi	n10
+	C edi	n2
+	C ebp	divisor
+	C
+	C mm7	rshift
+
+
+	movl	%esi, %eax
+	movl	%ebp, %ebx
+
+	sarl	$31, %eax          C -n1
+	movl	VAR_DST_STOP, %ecx
+
+	andl	%eax, %ebx         C -n1 & d
+	negl	%eax               C n1
+
+	addl	%esi, %ebx         C nadj = n10 + (-n1 & d), ignoring overflow
+	addl	%edi, %eax         C n2+n1
+
+	mull	VAR_INVERSE        C m*(n2+n1)
+
+	C
+
+	C
+
+	C
+
+	addl	%ebx, %eax         C m*(n2+n1) + nadj, low giving carry flag
+	leal	1(%edi), %ebx      C n2+1
+	movl	%ebp, %eax	   C d
+
+	C
+
+	adcl	%edx, %ebx         C 1 + high(n2<<32 + m*(n2+n1) + nadj) = q1+1
+
+	sbbl	$0, %ebx           C q1 if q1+1 overflowed
+
+	mull	%ebx
+
+	C
+
+	C
+
+	C
+
+	C
+
+	subl	%eax, %esi
+	movl	PARAM_XSIZE, %eax
+
+	sbbl	%edx, %edi	   C n - (q1+1)*d
+	movl	%esi, %edi	   C remainder -> n2
+	leal	(%ebp,%esi), %edx
+
+	cmovc(	%edx, %edi)	   C n - q1*d if underflow from using q1+1
+
+	sbbl	$0, %ebx	   C q
+
+	movl	%ebx, -8(%ecx)
+	subl	$8, %ecx
+
+
+
+	orl	%eax, %eax         C xsize
+	jnz	L(fraction_some)
+
+	movl	%edi, %eax
+L(fraction_done):
+	movl	VAR_NORM, %ecx
+L(zero_done):
+	movl	SAVE_EBP, %ebp
+
+	movl	SAVE_EDI, %edi
+
+	movl	SAVE_ESI, %esi
+
+	movl	SAVE_EBX, %ebx
+	addl	$STACK_SPACE, %esp
+
+	shrl	%cl, %eax
+	emms
+
+	ret
+
+
+C -----------------------------------------------------------------------------
+C
+C Special case for q1=0xFFFFFFFF, giving q=0xFFFFFFFF meaning the low dword
+C of q*d is simply -d and the remainder n-q*d = n10+d
+
+L(q1_ff):
+	C eax	(divisor)
+	C ebx	(q1+1 == 0)
+	C ecx
+	C edx
+	C esi	n10
+	C edi	n2
+	C ebp	divisor
+
+	movl	VAR_DST, %ecx
+	movl	VAR_DST_STOP, %edx
+	subl	$4, %ecx
+
+	movl	%ecx, VAR_DST
+	psrlq	%mm7, %mm0
+	leal	(%ebp,%esi), %edi	C n-q*d remainder -> next n2
+
+	movl	$-1, (%ecx)
+	movd	%mm0, %esi		C next n10
+
+	cmpl	%ecx, %edx
+	jne	L(integer_top)
+
+	jmp	L(integer_loop_done)
+
+
+
+C -----------------------------------------------------------------------------
+C
+C In the current implementation, the following successively dependent
+C micro-ops seem to exist.
+C
+C		       uops
+C		mul	5
+C		q1+1	1   (addl)
+C		mul	5
+C		sub	3   (negl/sbbl)
+C		addback	2   (cmov)
+C		       ---
+C		       16
+C
+C The loop in fact runs at about 17.5 cycles.  Using a sarl/andl/addl for
+C the addback was found to be a touch slower.
+
+
+	ALIGN(16)
+L(fraction_some):
+	C eax
+	C ebx
+	C ecx
+	C edx
+	C esi
+	C edi	carry
+	C ebp	divisor
+
+	movl	PARAM_DST, %esi
+	movl	VAR_DST_STOP, %ecx	C &dst[xsize+2]
+	movl	%edi, %eax
+
+	subl	$8, %ecx		C &dst[xsize]
+
+
+	ALIGN(16)
+L(fraction_top):
+	C eax	n2, then scratch
+	C ebx	scratch (nadj, q1)
+	C ecx	dst, decrementing
+	C edx	scratch
+	C esi	dst stop point
+	C edi	n2
+	C ebp	divisor
+
+	mull	VAR_INVERSE	C m*n2
+
+	movl	%ebp, %eax	C d
+	subl	$4, %ecx	C dst
+	leal	1(%edi), %ebx
+
+	C
+
+	C
+
+	C
+
+	addl	%edx, %ebx	C 1 + high(n2<<32 + m*n2) = q1+1
+
+	mull	%ebx		C (q1+1)*d
+
+	C
+
+	C
+
+	C
+
+	C
+
+	negl	%eax		C low of n - (q1+1)*d
+
+	sbbl	%edx, %edi	C high of n - (q1+1)*d, caring only about carry
+	leal	(%ebp,%eax), %edx
+
+	cmovc(	%edx, %eax)	C n - q1*d if underflow from using q1+1
+
+	sbbl	$0, %ebx	C q
+	movl	%eax, %edi	C remainder->n2
+	cmpl	%esi, %ecx
+
+	movl	%ebx, (%ecx)	C previous q
+	jne	L(fraction_top)
+
+
+	jmp	L(fraction_done)
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/p6/mmx/gmp-mparam.h b/third_party/gmp/mpn/x86/p6/mmx/gmp-mparam.h
new file mode 100644
index 0000000..ef29061
--- /dev/null
+++ b/third_party/gmp/mpn/x86/p6/mmx/gmp-mparam.h
@@ -0,0 +1,218 @@
+/* Intel P6/mmx gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991-2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+
+/* NOTE: In a fat binary build SQR_TOOM2_THRESHOLD here cannot be more than the
+   value in mpn/x86/p6/gmp-mparam.h.  The latter is used as a hard limit in
+   mpn/x86/p6/sqr_basecase.asm.  */
+
+
+/* 800 MHz P6 model 8 */
+/* Generated by tuneup.c, 2017-02-03, gcc 4.8 */
+
+#define MOD_1_1P_METHOD                      2
+#define MOD_1_NORM_THRESHOLD                 3
+#define MOD_1_UNNORM_THRESHOLD               4
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          7
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          7
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD         8
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        30
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     14
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1N_PI1_METHOD                 1
+#define DIV_QR_1_NORM_THRESHOLD              4
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           62
+
+#define DIV_1_VS_MUL_1_PERCENT             168
+
+#define MUL_TOOM22_THRESHOLD                22
+#define MUL_TOOM33_THRESHOLD                73
+#define MUL_TOOM44_THRESHOLD               195
+#define MUL_TOOM6H_THRESHOLD               254
+#define MUL_TOOM8H_THRESHOLD               381
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      81
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     122
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD      73
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD      80
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     100
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 30	/* WRONG value, see comment above */
+#define SQR_TOOM3_THRESHOLD                 83
+#define SQR_TOOM4_THRESHOLD                196
+#define SQR_TOOM6_THRESHOLD                214
+#define SQR_TOOM8_THRESHOLD                381
+
+#define MULMID_TOOM42_THRESHOLD             56
+
+#define MULMOD_BNM1_THRESHOLD               16
+#define SQRMOD_BNM1_THRESHOLD               17
+
+#define MUL_FFT_MODF_THRESHOLD             476  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    476, 5}, {     21, 6}, {     11, 5}, {     23, 6}, \
+    {     21, 7}, {     11, 6}, {     25, 7}, {     13, 6}, \
+    {     27, 7}, {     15, 6}, {     31, 7}, {     21, 8}, \
+    {     11, 7}, {     27, 8}, {     15, 7}, {     35, 8}, \
+    {     19, 7}, {     41, 8}, {     23, 7}, {     47, 8}, \
+    {     27, 9}, {     15, 8}, {     31, 7}, {     63, 8}, \
+    {     39, 9}, {     23, 8}, {     51,10}, {     15, 9}, \
+    {     31, 8}, {     67, 9}, {     39, 8}, {     79, 9}, \
+    {     47, 8}, {     95, 9}, {     55,10}, {     31, 9}, \
+    {     63, 8}, {    127, 9}, {     79,10}, {     47, 9}, \
+    {     95,11}, {     31,10}, {     63, 9}, {    135,10}, \
+    {     79, 9}, {    167,10}, {     95, 9}, {    199,10}, \
+    {    111,11}, {     63,10}, {    127, 9}, {    255, 8}, \
+    {    511,10}, {    143, 9}, {    287, 8}, {    575,10}, \
+    {    159,11}, {     95,10}, {    191, 9}, {    383,10}, \
+    {    207,12}, {     63,11}, {    127,10}, {    255, 9}, \
+    {    511,10}, {    271, 9}, {    543, 8}, {   1087,10}, \
+    {    287, 9}, {    575,11}, {    159,10}, {    319, 9}, \
+    {    639,10}, {    351, 9}, {    703,11}, {    191,10}, \
+    {    383, 9}, {    767,10}, {    415, 9}, {    831,11}, \
+    {    223,10}, {    447,12}, {    127,11}, {    255,10}, \
+    {    543, 9}, {   1087,11}, {    287,10}, {    607, 9}, \
+    {   1215,11}, {    319,10}, {    671,11}, {    351,10}, \
+    {    703,12}, {    191,11}, {    383,10}, {    767,11}, \
+    {    415,10}, {    831,11}, {    447,13}, {    127,12}, \
+    {    255,11}, {    543,10}, {   1087,11}, {    607,10}, \
+    {   1215,12}, {    319,11}, {    671,10}, {   1343,11}, \
+    {    703,10}, {   1407,11}, {    735,12}, {    383,11}, \
+    {    831,12}, {    447,11}, {    959,10}, {   1919,13}, \
+    {    255,12}, {    511,11}, {   1087,12}, {    575,11}, \
+    {   1215,10}, {   2431,12}, {    639,11}, {   1343,12}, \
+    {    703,11}, {   1471,13}, {    383,12}, {    767,11}, \
+    {   1535,12}, {    831,11}, {   1727,12}, {    959,11}, \
+    {   1919,14}, {    255,13}, {    511,12}, {   1215,11}, \
+    {   2431,13}, {    639,12}, {   1471,11}, {   2943,13}, \
+    {    767,12}, {   1727,13}, {    895,12}, {   1919,11}, \
+    {   3839,14}, {    511,13}, {   1023,12}, {   2111,13}, \
+    {   1151,12}, {   2431,13}, {   1279,12}, {   2559,13}, \
+    {   1407,12}, {   2943,14}, {    767,13}, {   1663,12}, \
+    {   3327,13}, {   1919,12}, {   3839,15}, {  32768,16} }
+#define MUL_FFT_TABLE3_SIZE 160
+#define MUL_FFT_THRESHOLD                 7040
+
+#define SQR_FFT_MODF_THRESHOLD             376  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    376, 5}, {     21, 6}, {     11, 5}, {     23, 6}, \
+    {     21, 7}, {     11, 6}, {     24, 7}, {     13, 6}, \
+    {     27, 7}, {     15, 6}, {     31, 7}, {     21, 8}, \
+    {     11, 7}, {     27, 8}, {     15, 7}, {     33, 8}, \
+    {     19, 7}, {     39, 8}, {     23, 7}, {     47, 8}, \
+    {     27, 9}, {     15, 8}, {     39, 9}, {     23, 8}, \
+    {     51,10}, {     15, 9}, {     31, 8}, {     67, 9}, \
+    {     39, 8}, {     79, 9}, {     47, 8}, {     95, 9}, \
+    {     55,10}, {     31, 9}, {     79,10}, {     47, 9}, \
+    {     95,11}, {     31,10}, {     63, 9}, {    127, 8}, \
+    {    255, 9}, {    135,10}, {     79, 9}, {    167,10}, \
+    {     95, 9}, {    191, 8}, {    383,10}, {    111,11}, \
+    {     63,10}, {    127, 9}, {    255, 8}, {    511, 9}, \
+    {    271,10}, {    143, 9}, {    287, 8}, {    575, 9}, \
+    {    303, 8}, {    607,10}, {    159, 9}, {    319,11}, \
+    {     95,10}, {    191, 9}, {    383,10}, {    207,12}, \
+    {     63,11}, {    127,10}, {    255, 9}, {    511,10}, \
+    {    271, 9}, {    543,10}, {    287, 9}, {    575,10}, \
+    {    303,11}, {    159,10}, {    319, 9}, {    639,10}, \
+    {    351, 9}, {    703,11}, {    191,10}, {    383, 9}, \
+    {    767,10}, {    415, 9}, {    831,11}, {    223,10}, \
+    {    479,12}, {    127,11}, {    255,10}, {    543, 9}, \
+    {   1087,11}, {    287,10}, {    607, 9}, {   1215,11}, \
+    {    319,10}, {    671,11}, {    351,10}, {    703,12}, \
+    {    191,11}, {    383,10}, {    767,11}, {    415,10}, \
+    {    831,11}, {    479,13}, {    127,12}, {    255,11}, \
+    {    543,10}, {   1087,11}, {    607,10}, {   1215,12}, \
+    {    319,11}, {    671,10}, {   1343,11}, {    703,10}, \
+    {   1407,11}, {    735,12}, {    383,11}, {    831,12}, \
+    {    447,11}, {    959,10}, {   1919,13}, {    255,12}, \
+    {    511,11}, {   1087,12}, {    575,11}, {   1215,10}, \
+    {   2431,12}, {    639,11}, {   1343,12}, {    703,11}, \
+    {   1407,13}, {    383,12}, {    831,11}, {   1727,12}, \
+    {    959,11}, {   1919,14}, {    255,13}, {    511,12}, \
+    {   1215,11}, {   2431,13}, {    639,12}, {   1471,11}, \
+    {   2943,13}, {    767,12}, {   1727,13}, {    895,12}, \
+    {   1919,11}, {   3839,14}, {    511,13}, {   1023,12}, \
+    {   2111,13}, {   1151,12}, {   2431,13}, {   1407,12}, \
+    {   2943,14}, {    767,13}, {   1535,12}, {   3071,13}, \
+    {   1663,12}, {   3455,13}, {   1919,12}, {   3839,15}, \
+    {  32768,16} }
+#define SQR_FFT_TABLE3_SIZE 161
+#define SQR_FFT_THRESHOLD                 3712
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  62
+#define MULLO_MUL_N_THRESHOLD            13463
+#define SQRLO_BASECASE_THRESHOLD             0  /* always */
+#define SQRLO_DC_THRESHOLD                 177
+#define SQRLO_SQR_THRESHOLD               8937
+
+#define DC_DIV_QR_THRESHOLD                 80
+#define DC_DIVAPPR_Q_THRESHOLD             240
+#define DC_BDIV_QR_THRESHOLD                76
+#define DC_BDIV_Q_THRESHOLD                166
+
+#define INV_MULMOD_BNM1_THRESHOLD           42
+#define INV_NEWTON_THRESHOLD               262
+#define INV_APPR_THRESHOLD                 250
+
+#define BINV_NEWTON_THRESHOLD              272
+#define REDC_1_TO_REDC_N_THRESHOLD          72
+
+#define MU_DIV_QR_THRESHOLD               1499
+#define MU_DIVAPPR_Q_THRESHOLD            1470
+#define MUPI_DIV_QR_THRESHOLD              124
+#define MU_BDIV_QR_THRESHOLD              1142
+#define MU_BDIV_Q_THRESHOLD               1341
+
+#define POWM_SEC_TABLE  1,16,96,416,1259
+
+#define GET_STR_DC_THRESHOLD                14
+#define GET_STR_PRECOMPUTE_THRESHOLD        27
+#define SET_STR_DC_THRESHOLD               270
+#define SET_STR_PRECOMPUTE_THRESHOLD      1084
+
+#define FAC_DSC_THRESHOLD                  194
+#define FAC_ODD_THRESHOLD                   25
+
+#define MATRIX22_STRASSEN_THRESHOLD         16
+#define HGCD_THRESHOLD                     124
+#define HGCD_APPR_THRESHOLD                152
+#define HGCD_REDUCE_THRESHOLD             3014
+#define GCD_DC_THRESHOLD                   474
+#define GCDEXT_DC_THRESHOLD                321
+#define JACOBI_BASE_METHOD                   1
diff --git a/third_party/gmp/mpn/x86/p6/mmx/lshift.asm b/third_party/gmp/mpn/x86/p6/mmx/lshift.asm
new file mode 100644
index 0000000..febd1c0
--- /dev/null
+++ b/third_party/gmp/mpn/x86/p6/mmx/lshift.asm
@@ -0,0 +1,38 @@
+dnl  Intel Pentium-II mpn_lshift -- mpn left shift.
+
+dnl  Copyright 2001 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+dnl  The P55 code runs well on P-II/III, but could stand some minor tweaks
+dnl  at some stage probably.
+
+include(`../config.m4')
+
+MULFUNC_PROLOGUE(mpn_lshift)
+include_mpn(`x86/pentium/mmx/lshift.asm')
diff --git a/third_party/gmp/mpn/x86/p6/mmx/popham.asm b/third_party/gmp/mpn/x86/p6/mmx/popham.asm
new file mode 100644
index 0000000..fd340e4
--- /dev/null
+++ b/third_party/gmp/mpn/x86/p6/mmx/popham.asm
@@ -0,0 +1,39 @@
+dnl  Intel Pentium-II mpn_popcount, mpn_hamdist -- population count and
+dnl  hamming distance.
+
+dnl  Copyright 2000, 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C P6MMX: popcount 11 cycles/limb (approx), hamdist 11.5 cycles/limb (approx)
+
+
+MULFUNC_PROLOGUE(mpn_popcount mpn_hamdist)
+include_mpn(`x86/k6/mmx/popham.asm')
diff --git a/third_party/gmp/mpn/x86/p6/mmx/rshift.asm b/third_party/gmp/mpn/x86/p6/mmx/rshift.asm
new file mode 100644
index 0000000..77aa190
--- /dev/null
+++ b/third_party/gmp/mpn/x86/p6/mmx/rshift.asm
@@ -0,0 +1,38 @@
+dnl  Intel Pentium-II mpn_rshift -- mpn left shift.
+
+dnl  Copyright 2001 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+dnl  The P55 code runs well on P-II/III, but could stand some minor tweaks
+dnl  at some stage probably.
+
+include(`../config.m4')
+
+MULFUNC_PROLOGUE(mpn_rshift)
+include_mpn(`x86/pentium/mmx/rshift.asm')
diff --git a/third_party/gmp/mpn/x86/p6/mod_34lsub1.asm b/third_party/gmp/mpn/x86/p6/mod_34lsub1.asm
new file mode 100644
index 0000000..b88ab5d
--- /dev/null
+++ b/third_party/gmp/mpn/x86/p6/mod_34lsub1.asm
@@ -0,0 +1,190 @@
+dnl  Intel P6 mpn_mod_34lsub1 -- remainder modulo 2^24-1.
+
+dnl  Copyright 2000-2002, 2004 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C P6: 2.0 cycles/limb
+
+C TODO
+C  Experiments with more unrolling indicate that 1.5 c/l is possible on P6-13
+C  with the current carry handling scheme.
+
+C mp_limb_t mpn_mod_34lsub1 (mp_srcptr src, mp_size_t size)
+C
+C Groups of three limbs are handled, with carry bits from 0mod3 into 1mod3
+C into 2mod3, but at that point going into a separate carries total so we
+C don't keep the carry flag live across the loop control.  Avoiding decl
+C lets us get to 2.0 c/l, as compared to the generic x86 code at 3.66.
+C
+
+defframe(PARAM_SIZE, 8)
+defframe(PARAM_SRC,  4)
+
+dnl  re-use parameter space
+define(SAVE_EBX, `PARAM_SIZE')
+define(SAVE_ESI, `PARAM_SRC')
+
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_mod_34lsub1)
+deflit(`FRAME',0)
+
+	movl	PARAM_SIZE, %ecx
+	movl	PARAM_SRC, %edx
+
+	subl	$2, %ecx		C size-2
+	movl	(%edx), %eax		C src[0]
+	ja	L(three_or_more)
+	jb	L(one)
+
+	C size==2
+
+	movl	4(%edx), %ecx		C src[1]
+
+	movl	%eax, %edx		C src[0]
+	shrl	$24, %eax		C src[0] high
+
+	andl	$0xFFFFFF, %edx		C src[0] low
+
+	addl	%edx, %eax
+	movl	%ecx, %edx		C src[1]
+	shrl	$16, %ecx		C src[1] high
+
+	andl	$0xFFFF, %edx
+	addl	%ecx, %eax
+
+	shll	$8, %edx		C src[1] low
+
+	addl	%edx, %eax
+L(one):
+	ret
+
+
+L(three_or_more):
+	C eax	src[0], initial acc 0mod3
+	C ebx
+	C ecx	size-2
+	C edx	src
+	C esi
+	C edi
+	C ebp
+
+	movl	%ebx, SAVE_EBX
+	movl	4(%edx), %ebx		C src[1], initial 1mod3
+	subl	$3, %ecx		C size-5
+
+	movl	%esi, SAVE_ESI
+	movl	8(%edx), %esi		C src[2], initial 2mod3
+
+	pushl	%edi	FRAME_pushl()
+	movl	$0, %edi		C initial carries 0mod3
+	jng	L(done)			C if size < 6
+
+
+L(top):
+	C eax	acc 0mod3
+	C ebx	acc 1mod3
+	C ecx	counter, limbs
+	C edx	src
+	C esi	acc 2mod3
+	C edi	carrys into 0mod3
+	C ebp
+
+	addl	12(%edx), %eax
+	adcl	16(%edx), %ebx
+	adcl	20(%edx), %esi
+	leal	12(%edx), %edx
+	adcl	$0, %edi
+
+	subl	$3, %ecx
+	jg	L(top)			C at least 3 more to process
+
+
+L(done):
+	C ecx is -2, -1 or 0 representing 0, 1 or 2 more limbs respectively
+	cmpl	$-1, %ecx
+	jl	L(done_0)		C if -2, meaning 0 more limbs
+
+	C 1 or 2 more limbs
+	movl	$0, %ecx
+	je	L(done_1)		C if -1, meaning 1 more limb only
+	movl	16(%edx), %ecx
+L(done_1):
+	addl	12(%edx), %eax		C 0mod3
+	adcl	%ecx, %ebx		C 1mod3
+	adcl	$0, %esi		C 2mod3
+	adcl	$0, %edi		C carries 0mod3
+
+L(done_0):
+	C eax	acc 0mod3
+	C ebx	acc 1mod3
+	C ecx
+	C edx
+	C esi	acc 2mod3
+	C edi	carries 0mod3
+	C ebp
+
+	movl	%eax, %ecx		C 0mod3
+	shrl	$24, %eax		C 0mod3 high initial total
+
+	andl	$0xFFFFFF, %ecx		C 0mod3 low
+	movl	%edi, %edx		C carries
+	shrl	$24, %edi		C carries high
+
+	addl	%ecx, %eax		C add 0mod3 low
+	andl	$0xFFFFFF, %edx		C carries 0mod3 low
+	movl	%ebx, %ecx		C 1mod3
+
+	shrl	$16, %ebx		C 1mod3 high
+	addl	%edi, %eax		C add carries high
+	addl	%edx, %eax		C add carries 0mod3 low
+
+	andl	$0xFFFF, %ecx		C 1mod3 low mask
+	addl	%ebx, %eax		C add 1mod3 high
+	movl	SAVE_EBX, %ebx
+
+	shll	$8, %ecx		C 1mod3 low
+	movl	%esi, %edx		C 2mod3
+	popl	%edi	FRAME_popl()
+
+	shrl	$8, %esi		C 2mod3 high
+	andl	$0xFF, %edx		C 2mod3 low mask
+	addl	%ecx, %eax		C add 1mod3 low
+
+	shll	$16, %edx		C 2mod3 low
+	addl	%esi, %eax		C add 2mod3 high
+	movl	SAVE_ESI, %esi
+
+	addl	%edx, %eax		C add 2mod3 low
+
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/p6/mode1o.asm b/third_party/gmp/mpn/x86/p6/mode1o.asm
new file mode 100644
index 0000000..7083195
--- /dev/null
+++ b/third_party/gmp/mpn/x86/p6/mode1o.asm
@@ -0,0 +1,170 @@
+dnl  Intel P6 mpn_modexact_1_odd -- exact division style remainder.
+
+dnl  Copyright 2000-2002, 2007 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C P6: 10.0 cycles/limb
+
+
+C mp_limb_t mpn_modexact_1_odd (mp_srcptr src, mp_size_t size,
+C                               mp_limb_t divisor);
+C mp_limb_t mpn_modexact_1c_odd (mp_srcptr src, mp_size_t size,
+C                                mp_limb_t divisor, mp_limb_t carry);
+C
+C It's not worth skipping a step at the end when high<divisor since the main
+C loop is only 10 cycles.
+
+defframe(PARAM_CARRY,  16)
+defframe(PARAM_DIVISOR,12)
+defframe(PARAM_SIZE,   8)
+defframe(PARAM_SRC,    4)
+
+dnl  Not enough room under modexact_1 to make these re-use the parameter
+dnl  space, unfortunately.
+defframe(SAVE_EBX,     -4)
+defframe(SAVE_ESI,     -8)
+defframe(SAVE_EDI,    -12)
+deflit(STACK_SPACE, 12)
+
+	TEXT
+
+	ALIGN(16)
+PROLOGUE(mpn_modexact_1c_odd)
+deflit(`FRAME',0)
+
+	movl	PARAM_CARRY, %ecx
+	jmp	L(start_1c)
+
+EPILOGUE()
+
+	ALIGN(16)
+PROLOGUE(mpn_modexact_1_odd)
+deflit(`FRAME',0)
+
+	xorl	%ecx, %ecx
+L(start_1c):
+	movl	PARAM_DIVISOR, %eax
+
+	subl	$STACK_SPACE, %esp	FRAME_subl_esp(STACK_SPACE)
+
+	movl	%esi, SAVE_ESI
+	movl	PARAM_SRC, %esi
+
+	shrl	%eax			C d/2
+	movl	%edi, SAVE_EDI
+
+	andl	$127, %eax
+
+ifdef(`PIC',`
+	LEA(	binvert_limb_table, %edi)
+	movzbl	(%eax,%edi), %edi		C inv 8 bits
+',`
+	movzbl	binvert_limb_table(%eax), %edi	C inv 8 bits
+')
+
+	xorl	%edx, %edx		C initial extra carry
+	leal	(%edi,%edi), %eax	C 2*inv
+
+	imull	%edi, %edi		C inv*inv
+
+	movl	%ebx, SAVE_EBX
+	movl	PARAM_SIZE, %ebx
+
+	imull	PARAM_DIVISOR, %edi	C inv*inv*d
+
+	subl	%edi, %eax		C inv = 2*inv - inv*inv*d
+	leal	(%eax,%eax), %edi	C 2*inv
+
+	imull	%eax, %eax		C inv*inv
+
+	imull	PARAM_DIVISOR, %eax	C inv*inv*d
+
+	leal	(%esi,%ebx,4), %esi	C src end
+	negl	%ebx			C -size
+
+	subl	%eax, %edi		C inv = 2*inv - inv*inv*d
+
+	ASSERT(e,`	C d*inv == 1 mod 2^GMP_LIMB_BITS
+	movl	PARAM_DIVISOR, %eax
+	imull	%edi, %eax
+	cmpl	$1, %eax')
+
+
+C The dependent chain here is
+C
+C	subl	%edx, %eax       1
+C	imull	%edi, %eax       4
+C	mull	PARAM_DIVISOR    5
+C			       ----
+C	total			10
+C
+C and this is the measured speed.  No special scheduling is necessary, out
+C of order execution hides the load latency.
+
+L(top):
+	C eax	scratch (src limb)
+	C ebx	counter, limbs, negative
+	C ecx	carry bit, 0 or 1
+	C edx	carry limb, high of last product
+	C esi	&src[size]
+	C edi	inverse
+	C ebp
+
+	movl	(%esi,%ebx,4), %eax
+	subl	%ecx, %eax
+
+	sbbl	%ecx, %ecx
+	subl	%edx, %eax
+
+	sbbl	$0, %ecx
+
+	imull	%edi, %eax
+
+	negl	%ecx
+
+	mull	PARAM_DIVISOR
+
+	incl	%ebx
+	jnz	L(top)
+
+
+	movl	SAVE_ESI, %esi
+	leal	(%ecx,%edx), %eax
+
+	movl	SAVE_EDI, %edi
+
+	movl	SAVE_EBX, %ebx
+	addl	$STACK_SPACE, %esp
+
+	ret
+
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86/p6/mul_basecase.asm b/third_party/gmp/mpn/x86/p6/mul_basecase.asm
new file mode 100644
index 0000000..d87bc12
--- /dev/null
+++ b/third_party/gmp/mpn/x86/p6/mul_basecase.asm
@@ -0,0 +1,607 @@
+dnl  Intel P6 mpn_mul_basecase -- multiply two mpn numbers.
+
+dnl  Copyright 1999-2003 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C P6: approx 6.5 cycles per cross product (16 limbs/loop unrolling).
+
+
+dnl  P6 UNROLL_COUNT cycles/product (approx)
+dnl           8           7
+dnl          16           6.5
+dnl          32           6.4
+dnl  Maximum possible with the current code is 32.
+
+deflit(UNROLL_COUNT, 16)
+
+
+C void mpn_mul_basecase (mp_ptr wp,
+C                        mp_srcptr xp, mp_size_t xsize,
+C                        mp_srcptr yp, mp_size_t ysize);
+C
+C This routine is essentially the same as mpn/generic/mul_basecase.c, but
+C it's faster because it does most of the mpn_addmul_1() startup
+C calculations only once.
+
+ifdef(`PIC',`
+deflit(UNROLL_THRESHOLD, 5)
+',`
+deflit(UNROLL_THRESHOLD, 5)
+')
+
+defframe(PARAM_YSIZE,20)
+defframe(PARAM_YP,   16)
+defframe(PARAM_XSIZE,12)
+defframe(PARAM_XP,   8)
+defframe(PARAM_WP,   4)
+
+	TEXT
+	ALIGN(16)
+
+PROLOGUE(mpn_mul_basecase)
+deflit(`FRAME',0)
+
+	movl	PARAM_XSIZE, %ecx
+
+	movl	PARAM_YP, %eax
+
+	movl	PARAM_XP, %edx
+
+	movl	(%eax), %eax		C yp[0]
+	cmpl	$2, %ecx
+	ja	L(xsize_more_than_two)
+	je	L(two_by_something)
+
+
+	C one limb by one limb
+
+	mull	(%edx)
+
+	movl	PARAM_WP, %ecx
+	movl	%eax, (%ecx)
+	movl	%edx, 4(%ecx)
+	ret
+
+
+C -----------------------------------------------------------------------------
+L(two_by_something):
+deflit(`FRAME',0)
+
+dnl  re-use parameter space
+define(SAVE_EBX, `PARAM_XSIZE')
+define(SAVE_ESI, `PARAM_YSIZE')
+
+	movl	%ebx, SAVE_EBX
+	cmpl	$1, PARAM_YSIZE
+	movl	%eax, %ecx		C yp[0]
+
+	movl	%esi, SAVE_ESI		C save esi
+	movl	PARAM_WP, %ebx
+	movl	%edx, %esi		C xp
+
+	movl	(%edx), %eax		C xp[0]
+	jne	L(two_by_two)
+
+
+	C two limbs by one limb
+	C
+	C eax	xp[0]
+	C ebx	wp
+	C ecx	yp[0]
+	C edx
+	C esi	xp
+
+	mull	%ecx
+
+	movl	%eax, (%ebx)
+	movl	4(%esi), %eax
+	movl	%edx, %esi		C carry
+
+	mull	%ecx
+
+	addl	%eax, %esi
+
+	movl	%esi, 4(%ebx)
+	movl	SAVE_ESI, %esi
+
+	adcl	$0, %edx
+
+	movl	%edx, 8(%ebx)
+	movl	SAVE_EBX, %ebx
+
+	ret
+
+
+
+C -----------------------------------------------------------------------------
+
+	ALIGN(16)
+L(two_by_two):
+	C eax	xp[0]
+	C ebx	wp
+	C ecx	yp[0]
+	C edx
+	C esi	xp
+	C edi
+	C ebp
+
+dnl  more parameter space re-use
+define(SAVE_EDI, `PARAM_WP')
+
+	mull	%ecx		C xp[0] * yp[0]
+
+	movl	%edi, SAVE_EDI
+	movl	%edx, %edi	C carry, for wp[1]
+
+	movl	%eax, (%ebx)
+	movl	4(%esi), %eax
+
+	mull	%ecx		C xp[1] * yp[0]
+
+	addl	%eax, %edi
+	movl	PARAM_YP, %ecx
+
+	adcl	$0, %edx
+	movl	4(%ecx), %ecx	C yp[1]
+
+	movl	%edi, 4(%ebx)
+	movl	4(%esi), %eax	C xp[1]
+	movl	%edx, %edi	C carry, for wp[2]
+
+	mull	%ecx		C xp[1] * yp[1]
+
+	addl	%eax, %edi
+	movl	(%esi), %eax	C xp[0]
+
+	adcl	$0, %edx
+	movl	%edx, %esi	C carry, for wp[3]
+
+	mull	%ecx		C xp[0] * yp[1]
+
+	addl	%eax, 4(%ebx)
+	movl	%esi, %eax
+
+	adcl	%edx, %edi
+	movl	SAVE_ESI, %esi
+
+	movl	%edi, 8(%ebx)
+
+	adcl	$0, %eax
+	movl	SAVE_EDI, %edi
+
+	movl	%eax, 12(%ebx)
+	movl	SAVE_EBX, %ebx
+
+	ret
+
+
+C -----------------------------------------------------------------------------
+	ALIGN(16)
+L(xsize_more_than_two):
+
+C The first limb of yp is processed with a simple mpn_mul_1 loop running at
+C about 6.2 c/l.  Unrolling this doesn't seem worthwhile since it's only run
+C once (whereas the addmul_1 below is run ysize-1 many times).  A call to
+C mpn_mul_1 would be slowed down by the parameter pushing and popping etc,
+C and doesn't seem likely to be worthwhile on the typical sizes reaching
+C here from the Karatsuba code.
+
+	C eax	yp[0]
+	C ebx
+	C ecx	xsize
+	C edx	xp
+	C esi
+	C edi
+	C ebp
+
+defframe(`SAVE_EBX',    -4)
+defframe(`SAVE_ESI',    -8)
+defframe(`SAVE_EDI',   -12)
+defframe(`SAVE_EBP',   -16)
+defframe(VAR_COUNTER,  -20)  dnl for use in the unroll case
+defframe(VAR_ADJUST,   -24)
+defframe(VAR_JMP,      -28)
+defframe(VAR_SWAP,     -32)
+defframe(VAR_XP_LOW,   -36)
+deflit(STACK_SPACE, 36)
+
+	subl	$STACK_SPACE, %esp
+deflit(`FRAME',STACK_SPACE)
+
+	movl	%edi, SAVE_EDI
+	movl	PARAM_WP, %edi
+
+	movl	%ebx, SAVE_EBX
+
+	movl	%ebp, SAVE_EBP
+	movl	%eax, %ebp
+
+	movl	%esi, SAVE_ESI
+	xorl	%ebx, %ebx
+	leal	(%edx,%ecx,4), %esi	C xp end
+
+	leal	(%edi,%ecx,4), %edi	C wp end of mul1
+	negl	%ecx
+
+
+L(mul1):
+	C eax	scratch
+	C ebx	carry
+	C ecx	counter, negative
+	C edx	scratch
+	C esi	xp end
+	C edi	wp end of mul1
+	C ebp	multiplier
+
+	movl	(%esi,%ecx,4), %eax
+
+	mull	%ebp
+
+	addl	%ebx, %eax
+	movl	%eax, (%edi,%ecx,4)
+	movl	$0, %ebx
+
+	adcl	%edx, %ebx
+	incl	%ecx
+	jnz	L(mul1)
+
+
+	movl	PARAM_YSIZE, %edx
+
+	movl	%ebx, (%edi)		C final carry
+	movl	PARAM_XSIZE, %ecx
+	decl	%edx
+
+	jz	L(done)			C if ysize==1
+
+	cmpl	$UNROLL_THRESHOLD, %ecx
+	movl	PARAM_YP, %eax
+	jae	L(unroll)
+
+
+C -----------------------------------------------------------------------------
+	C simple addmul looping
+	C
+	C eax	yp
+	C ebx
+	C ecx	xsize
+	C edx	ysize-1
+	C esi	xp end
+	C edi	wp end of mul1
+	C ebp
+
+	leal	4(%eax,%edx,4), %ebp	C yp end
+	negl	%ecx
+	negl	%edx
+
+	movl	%edx, PARAM_YSIZE	C -(ysize-1)
+	movl	(%esi,%ecx,4), %eax	C xp low limb
+	incl	%ecx
+
+	movl	%ecx, PARAM_XSIZE	C -(xsize-1)
+	xorl	%ebx, %ebx		C initial carry
+
+	movl	%ebp, PARAM_YP
+	movl	(%ebp,%edx,4), %ebp	C yp second lowest limb - multiplier
+	jmp	L(simple_outer_entry)
+
+
+L(simple_outer_top):
+	C ebp	ysize counter, negative
+
+	movl	PARAM_YP, %edx
+
+	movl	PARAM_XSIZE, %ecx	C -(xsize-1)
+	xorl	%ebx, %ebx		C carry
+
+	movl	%ebp, PARAM_YSIZE
+	addl	$4, %edi		C next position in wp
+
+	movl	(%edx,%ebp,4), %ebp	C yp limb - multiplier
+
+	movl	-4(%esi,%ecx,4), %eax	C xp low limb
+
+
+L(simple_outer_entry):
+
+L(simple_inner_top):
+	C eax	xp limb
+	C ebx	carry limb
+	C ecx	loop counter (negative)
+	C edx	scratch
+	C esi	xp end
+	C edi	wp end
+	C ebp	multiplier
+
+	mull	%ebp
+
+	addl	%eax, %ebx
+	adcl	$0, %edx
+
+	addl	%ebx, (%edi,%ecx,4)
+	movl	(%esi,%ecx,4), %eax
+	adcl	$0, %edx
+
+	incl	%ecx
+	movl	%edx, %ebx
+	jnz	L(simple_inner_top)
+
+
+	C separate code for last limb so outer loop counter handling can be
+	C interleaved
+
+	mull	%ebp
+
+	movl	PARAM_YSIZE, %ebp
+	addl	%eax, %ebx
+
+	adcl	$0, %edx
+
+	addl	%ebx, (%edi)
+
+	adcl	$0, %edx
+	incl	%ebp
+
+	movl	%edx, 4(%edi)
+	jnz	L(simple_outer_top)
+
+
+L(done):
+	movl	SAVE_EBX, %ebx
+
+	movl	SAVE_ESI, %esi
+
+	movl	SAVE_EDI, %edi
+
+	movl	SAVE_EBP, %ebp
+	addl	$FRAME, %esp
+
+	ret
+
+
+
+C -----------------------------------------------------------------------------
+C
+C The unrolled loop is the same as in mpn_addmul_1, see that code for some
+C comments.
+C
+C VAR_ADJUST is the negative of how many limbs the leals in the inner loop
+C increment xp and wp.  This is used to adjust xp and wp, and is rshifted to
+C given an initial VAR_COUNTER at the top of the outer loop.
+C
+C VAR_COUNTER is for the unrolled loop, running from VAR_ADJUST/UNROLL_COUNT
+C up to -1, inclusive.
+C
+C VAR_JMP is the computed jump into the unrolled loop.
+C
+C VAR_SWAP is 0 if xsize odd or 0xFFFFFFFF if xsize even, used to swap the
+C initial ebx and ecx on entry to the unrolling.
+C
+C VAR_XP_LOW is the least significant limb of xp, which is needed at the
+C start of the unrolled loop.
+C
+C PARAM_YSIZE is the outer loop counter, going from -(ysize-1) up to -1,
+C inclusive.
+C
+C PARAM_YP is offset appropriately so that the PARAM_YSIZE counter can be
+C added to give the location of the next limb of yp, which is the multiplier
+C in the unrolled loop.
+C
+C The trick with the VAR_ADJUST value means it's only necessary to do one
+C fetch in the outer loop to take care of xp, wp and the inner loop counter.
+
+
+L(unroll):
+	C eax	yp
+	C ebx
+	C ecx	xsize
+	C edx	ysize-1
+	C esi	xp end
+	C edi	wp end of mul1
+	C ebp
+
+	movl	PARAM_XP, %esi
+
+	movl	4(%eax), %ebp		C multiplier (yp second limb)
+	leal	4(%eax,%edx,4), %eax	C yp adjust for ysize indexing
+
+	movl	%eax, PARAM_YP
+	movl	PARAM_WP, %edi
+	negl	%edx
+
+	movl	%edx, PARAM_YSIZE
+	leal	UNROLL_COUNT-2(%ecx), %ebx	C (xsize-1)+UNROLL_COUNT-1
+	decl	%ecx				C xsize-1
+
+	movl	(%esi), %eax		C xp low limb
+	andl	$-UNROLL_MASK-1, %ebx
+	negl	%ecx			C -(xsize-1)
+
+	negl	%ebx
+	andl	$UNROLL_MASK, %ecx
+
+	movl	%ebx, VAR_ADJUST
+	movl	%ecx, %edx
+	shll	$4, %ecx
+
+	movl	%eax, VAR_XP_LOW
+	sarl	$UNROLL_LOG2, %ebx
+	negl	%edx
+
+	C 15 code bytes per limb
+ifdef(`PIC',`
+	call	L(pic_calc)
+L(unroll_here):
+',`
+	leal	L(unroll_inner_entry) (%ecx,%edx,1), %ecx
+')
+
+	movl	%ecx, VAR_JMP
+	movl	%edx, %ecx
+	shll	$31, %edx
+
+	sarl	$31, %edx		C 0 or -1 as xsize odd or even
+	leal	4(%edi,%ecx,4), %edi	C wp and xp, adjust for unrolling,
+	leal	4(%esi,%ecx,4), %esi	C  and start at second limb
+
+	movl	%edx, VAR_SWAP
+	jmp	L(unroll_outer_entry)
+
+
+ifdef(`PIC',`
+L(pic_calc):
+	C See mpn/x86/README about old gas bugs
+	leal	(%ecx,%edx,1), %ecx
+	addl	$L(unroll_inner_entry)-L(unroll_here), %ecx
+	addl	(%esp), %ecx
+	ret_internal
+')
+
+
+C --------------------------------------------------------------------------
+	ALIGN(16)
+L(unroll_outer_top):
+	C eax
+	C ebx
+	C ecx
+	C edx
+	C esi	xp + offset
+	C edi	wp + offset
+	C ebp	ysize counter, negative
+
+	movl	VAR_ADJUST, %ebx
+	movl	PARAM_YP, %edx
+
+	movl	VAR_XP_LOW, %eax
+	movl	%ebp, PARAM_YSIZE	C store incremented ysize counter
+
+	leal	eval(UNROLL_BYTES + 4) (%edi,%ebx,4), %edi
+	leal	(%esi,%ebx,4), %esi
+	sarl	$UNROLL_LOG2, %ebx
+
+	movl	(%edx,%ebp,4), %ebp	C yp next multiplier
+
+L(unroll_outer_entry):
+	mull	%ebp
+
+	movl	%ebx, VAR_COUNTER
+	movl	%edx, %ebx		C carry high
+	movl	%eax, %ecx		C carry low
+
+	xorl	%edx, %eax
+	movl	VAR_JMP, %edx
+
+	andl	VAR_SWAP, %eax
+
+	xorl	%eax, %ebx		C carries other way for odd index
+	xorl	%eax, %ecx
+
+	jmp	*%edx
+
+
+C -----------------------------------------------------------------------------
+
+L(unroll_inner_top):
+	C eax	xp limb
+	C ebx	carry high
+	C ecx	carry low
+	C edx	scratch
+	C esi	xp+8
+	C edi	wp
+	C ebp	yp multiplier limb
+	C
+	C VAR_COUNTER  loop counter, negative
+	C
+	C 15 bytes each limb
+
+	addl	$UNROLL_BYTES, %edi
+
+L(unroll_inner_entry):
+
+deflit(CHUNK_COUNT,2)
+forloop(`i', 0, UNROLL_COUNT/CHUNK_COUNT-1, `
+	deflit(`disp0', eval(i*CHUNK_COUNT*4 ifelse(UNROLL_BYTES,256,-128)))
+	deflit(`disp1', eval(disp0 + 4))
+
+Zdisp(	movl,	disp0,(%esi), %eax)
+	mull	%ebp
+Zdisp(	addl,	%ecx, disp0,(%edi))
+	adcl	%eax, %ebx		C new carry low
+	movl	%edx, %ecx
+	adcl	$0, %ecx		C new carry high
+
+	movl	disp1(%esi), %eax
+	mull	%ebp
+	addl	%ebx, disp1(%edi)
+	adcl	%eax, %ecx		C new carry low
+	movl	%edx, %ebx
+	adcl	$0, %ebx		C new carry high
+')
+
+
+	incl	VAR_COUNTER
+	leal	UNROLL_BYTES(%esi), %esi
+	jnz	L(unroll_inner_top)
+
+
+	C eax
+	C ebx	carry high
+	C ecx	carry low
+	C edx
+	C esi
+	C edi	wp, pointing at second last limb)
+	C ebp
+
+deflit(`disp0',	eval(UNROLL_BYTES ifelse(UNROLL_BYTES,256,-128)))
+deflit(`disp1', eval(disp0 + 4))
+
+	movl	PARAM_YSIZE, %ebp
+	addl	%ecx, disp0(%edi)	C carry low
+
+	adcl	$0, %ebx
+	incl	%ebp
+
+	movl	%ebx, disp1(%edi)	C carry high
+	jnz	L(unroll_outer_top)
+
+
+	movl	SAVE_ESI, %esi
+
+	movl	SAVE_EBP, %ebp
+
+	movl	SAVE_EDI, %edi
+
+	movl	SAVE_EBX, %ebx
+	addl	$FRAME, %esp
+
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/p6/p3mmx/popham.asm b/third_party/gmp/mpn/x86/p6/p3mmx/popham.asm
new file mode 100644
index 0000000..db2f260
--- /dev/null
+++ b/third_party/gmp/mpn/x86/p6/p3mmx/popham.asm
@@ -0,0 +1,42 @@
+dnl  Intel Pentium-III mpn_popcount, mpn_hamdist -- population count and
+dnl  hamming distance.
+
+dnl  Copyright 2000, 2002, 2004, 2007 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C			     popcount	     hamdist
+C P3 generic			6.5		7
+C P3 model 9  (Banias)		?		?
+C P3 model 13 (Dothan)		5.75		6
+
+
+MULFUNC_PROLOGUE(mpn_popcount mpn_hamdist)
+include_mpn(`x86/k7/mmx/popham.asm')
diff --git a/third_party/gmp/mpn/x86/p6/sqr_basecase.asm b/third_party/gmp/mpn/x86/p6/sqr_basecase.asm
new file mode 100644
index 0000000..8fc7fdf
--- /dev/null
+++ b/third_party/gmp/mpn/x86/p6/sqr_basecase.asm
@@ -0,0 +1,649 @@
+dnl  Intel P6 mpn_sqr_basecase -- square an mpn number.
+
+dnl  Copyright 1999, 2000, 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C P6: approx 4.0 cycles per cross product, or 7.75 cycles per triangular
+C     product (measured on the speed difference between 20 and 40 limbs,
+C     which is the Karatsuba recursing range).
+
+
+dnl  These are the same as in mpn/x86/k6/sqr_basecase.asm, see that file for
+dnl  a description.  The only difference here is that UNROLL_COUNT can go up
+dnl  to 64 (not 63) making SQR_TOOM2_THRESHOLD_MAX 67.
+
+deflit(SQR_TOOM2_THRESHOLD_MAX, 67)
+
+ifdef(`SQR_TOOM2_THRESHOLD_OVERRIDE',
+`define(`SQR_TOOM2_THRESHOLD',SQR_TOOM2_THRESHOLD_OVERRIDE)')
+
+m4_config_gmp_mparam(`SQR_TOOM2_THRESHOLD')
+deflit(UNROLL_COUNT, eval(SQR_TOOM2_THRESHOLD-3))
+
+
+C void mpn_sqr_basecase (mp_ptr dst, mp_srcptr src, mp_size_t size);
+C
+C The algorithm is basically the same as mpn/generic/sqr_basecase.c, but a
+C lot of function call overheads are avoided, especially when the given size
+C is small.
+C
+C The code size might look a bit excessive, but not all of it is executed so
+C it won't all get into the code cache.  The 1x1, 2x2 and 3x3 special cases
+C clearly apply only to those sizes; mid sizes like 10x10 only need part of
+C the unrolled addmul; and big sizes like 40x40 that do use the full
+C unrolling will least be making good use of it, because 40x40 will take
+C something like 7000 cycles.
+
+defframe(PARAM_SIZE,12)
+defframe(PARAM_SRC, 8)
+defframe(PARAM_DST, 4)
+
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_sqr_basecase)
+deflit(`FRAME',0)
+
+	movl	PARAM_SIZE, %edx
+
+	movl	PARAM_SRC, %eax
+
+	cmpl	$2, %edx
+	movl	PARAM_DST, %ecx
+	je	L(two_limbs)
+
+	movl	(%eax), %eax
+	ja	L(three_or_more)
+
+
+C -----------------------------------------------------------------------------
+C one limb only
+	C eax	src limb
+	C ebx
+	C ecx	dst
+	C edx
+
+	mull	%eax
+
+	movl	%eax, (%ecx)
+	movl	%edx, 4(%ecx)
+
+	ret
+
+
+C -----------------------------------------------------------------------------
+L(two_limbs):
+	C eax	src
+	C ebx
+	C ecx	dst
+	C edx
+
+defframe(SAVE_ESI, -4)
+defframe(SAVE_EBX, -8)
+defframe(SAVE_EDI, -12)
+defframe(SAVE_EBP, -16)
+deflit(`STACK_SPACE',16)
+
+	subl	$STACK_SPACE, %esp
+deflit(`FRAME',STACK_SPACE)
+
+	movl	%esi, SAVE_ESI
+	movl	%eax, %esi
+	movl	(%eax), %eax
+
+	mull	%eax		C src[0]^2
+
+	movl	%eax, (%ecx)	C dst[0]
+	movl	4(%esi), %eax
+
+	movl	%ebx, SAVE_EBX
+	movl	%edx, %ebx	C dst[1]
+
+	mull	%eax		C src[1]^2
+
+	movl	%edi, SAVE_EDI
+	movl	%eax, %edi	C dst[2]
+	movl	(%esi), %eax
+
+	movl	%ebp, SAVE_EBP
+	movl	%edx, %ebp	C dst[3]
+
+	mull	4(%esi)		C src[0]*src[1]
+
+	addl	%eax, %ebx
+	movl	SAVE_ESI, %esi
+
+	adcl	%edx, %edi
+
+	adcl	$0, %ebp
+	addl	%ebx, %eax
+	movl	SAVE_EBX, %ebx
+
+	adcl	%edi, %edx
+	movl	SAVE_EDI, %edi
+
+	adcl	$0, %ebp
+
+	movl	%eax, 4(%ecx)
+
+	movl	%ebp, 12(%ecx)
+	movl	SAVE_EBP, %ebp
+
+	movl	%edx, 8(%ecx)
+	addl	$FRAME, %esp
+
+	ret
+
+
+C -----------------------------------------------------------------------------
+L(three_or_more):
+	C eax	src low limb
+	C ebx
+	C ecx	dst
+	C edx	size
+deflit(`FRAME',0)
+
+	pushl	%esi	defframe_pushl(`SAVE_ESI')
+	cmpl	$4, %edx
+
+	movl	PARAM_SRC, %esi
+	jae	L(four_or_more)
+
+
+C -----------------------------------------------------------------------------
+C three limbs
+
+	C eax	src low limb
+	C ebx
+	C ecx	dst
+	C edx
+	C esi	src
+	C edi
+	C ebp
+
+	pushl	%ebp	defframe_pushl(`SAVE_EBP')
+	pushl	%edi	defframe_pushl(`SAVE_EDI')
+
+	mull	%eax		C src[0] ^ 2
+
+	movl	%eax, (%ecx)
+	movl	%edx, 4(%ecx)
+
+	movl	4(%esi), %eax
+	xorl	%ebp, %ebp
+
+	mull	%eax		C src[1] ^ 2
+
+	movl	%eax, 8(%ecx)
+	movl	%edx, 12(%ecx)
+	movl	8(%esi), %eax
+
+	pushl	%ebx	defframe_pushl(`SAVE_EBX')
+
+	mull	%eax		C src[2] ^ 2
+
+	movl	%eax, 16(%ecx)
+	movl	%edx, 20(%ecx)
+
+	movl	(%esi), %eax
+
+	mull	4(%esi)		C src[0] * src[1]
+
+	movl	%eax, %ebx
+	movl	%edx, %edi
+
+	movl	(%esi), %eax
+
+	mull	8(%esi)		C src[0] * src[2]
+
+	addl	%eax, %edi
+	movl	%edx, %ebp
+
+	adcl	$0, %ebp
+	movl	4(%esi), %eax
+
+	mull	8(%esi)		C src[1] * src[2]
+
+	xorl	%esi, %esi
+	addl	%eax, %ebp
+
+	C eax
+	C ebx	dst[1]
+	C ecx	dst
+	C edx	dst[4]
+	C esi	zero, will be dst[5]
+	C edi	dst[2]
+	C ebp	dst[3]
+
+	adcl	$0, %edx
+	addl	%ebx, %ebx
+
+	adcl	%edi, %edi
+
+	adcl	%ebp, %ebp
+
+	adcl	%edx, %edx
+	movl	4(%ecx), %eax
+
+	adcl	$0, %esi
+	addl	%ebx, %eax
+
+	movl	%eax, 4(%ecx)
+	movl	8(%ecx), %eax
+
+	adcl	%edi, %eax
+	movl	12(%ecx), %ebx
+
+	adcl	%ebp, %ebx
+	movl	16(%ecx), %edi
+
+	movl	%eax, 8(%ecx)
+	movl	SAVE_EBP, %ebp
+
+	movl	%ebx, 12(%ecx)
+	movl	SAVE_EBX, %ebx
+
+	adcl	%edx, %edi
+	movl	20(%ecx), %eax
+
+	movl	%edi, 16(%ecx)
+	movl	SAVE_EDI, %edi
+
+	adcl	%esi, %eax	C no carry out of this
+	movl	SAVE_ESI, %esi
+
+	movl	%eax, 20(%ecx)
+	addl	$FRAME, %esp
+
+	ret
+
+
+
+C -----------------------------------------------------------------------------
+defframe(VAR_COUNTER,-20)
+defframe(VAR_JMP,    -24)
+deflit(`STACK_SPACE',24)
+
+L(four_or_more):
+	C eax	src low limb
+	C ebx
+	C ecx
+	C edx	size
+	C esi	src
+	C edi
+	C ebp
+deflit(`FRAME',4)  dnl  %esi already pushed
+
+C First multiply src[0]*src[1..size-1] and store at dst[1..size].
+
+	subl	$STACK_SPACE-FRAME, %esp
+deflit(`FRAME',STACK_SPACE)
+	movl	$1, %ecx
+
+	movl	%edi, SAVE_EDI
+	movl	PARAM_DST, %edi
+
+	movl	%ebx, SAVE_EBX
+	subl	%edx, %ecx		C -(size-1)
+
+	movl	%ebp, SAVE_EBP
+	movl	$0, %ebx		C initial carry
+
+	leal	(%esi,%edx,4), %esi	C &src[size]
+	movl	%eax, %ebp		C multiplier
+
+	leal	-4(%edi,%edx,4), %edi	C &dst[size-1]
+
+
+C This loop runs at just over 6 c/l.
+
+L(mul_1):
+	C eax	scratch
+	C ebx	carry
+	C ecx	counter, limbs, negative, -(size-1) to -1
+	C edx	scratch
+	C esi	&src[size]
+	C edi	&dst[size-1]
+	C ebp	multiplier
+
+	movl	%ebp, %eax
+
+	mull	(%esi,%ecx,4)
+
+	addl	%ebx, %eax
+	movl	$0, %ebx
+
+	adcl	%edx, %ebx
+	movl	%eax, 4(%edi,%ecx,4)
+
+	incl	%ecx
+	jnz	L(mul_1)
+
+
+	movl	%ebx, 4(%edi)
+
+
+C Addmul src[n]*src[n+1..size-1] at dst[2*n-1...], for each n=1..size-2.
+C
+C The last two addmuls, which are the bottom right corner of the product
+C triangle, are left to the end.  These are src[size-3]*src[size-2,size-1]
+C and src[size-2]*src[size-1].  If size is 4 then it's only these corner
+C cases that need to be done.
+C
+C The unrolled code is the same as mpn_addmul_1(), see that routine for some
+C comments.
+C
+C VAR_COUNTER is the outer loop, running from -(size-4) to -1, inclusive.
+C
+C VAR_JMP is the computed jump into the unrolled code, stepped by one code
+C chunk each outer loop.
+
+dnl  This is also hard-coded in the address calculation below.
+deflit(CODE_BYTES_PER_LIMB, 15)
+
+dnl  With &src[size] and &dst[size-1] pointers, the displacements in the
+dnl  unrolled code fit in a byte for UNROLL_COUNT values up to 32, but above
+dnl  that an offset must be added to them.
+deflit(OFFSET,
+ifelse(eval(UNROLL_COUNT>32),1,
+eval((UNROLL_COUNT-32)*4),
+0))
+
+	C eax
+	C ebx	carry
+	C ecx
+	C edx
+	C esi	&src[size]
+	C edi	&dst[size-1]
+	C ebp
+
+	movl	PARAM_SIZE, %ecx
+
+	subl	$4, %ecx
+	jz	L(corner)
+
+	movl	%ecx, %edx
+	negl	%ecx
+
+	shll	$4, %ecx
+ifelse(OFFSET,0,,`subl	$OFFSET, %esi')
+
+ifdef(`PIC',`
+	call	L(pic_calc)
+L(here):
+',`
+	leal	L(unroll_inner_end)-eval(2*CODE_BYTES_PER_LIMB)(%ecx,%edx), %ecx
+')
+	negl	%edx
+
+ifelse(OFFSET,0,,`subl	$OFFSET, %edi')
+
+	C The calculated jump mustn't be before the start of the available
+	C code.  This is the limit that UNROLL_COUNT puts on the src operand
+	C size, but checked here using the jump address directly.
+
+	ASSERT(ae,
+	`movl_text_address( L(unroll_inner_start), %eax)
+	cmpl	%eax, %ecx')
+
+
+C -----------------------------------------------------------------------------
+	ALIGN(16)
+L(unroll_outer_top):
+	C eax
+	C ebx	high limb to store
+	C ecx	VAR_JMP
+	C edx	VAR_COUNTER, limbs, negative
+	C esi	&src[size], constant
+	C edi	dst ptr, second highest limb of last addmul
+	C ebp
+
+	movl	-12+OFFSET(%esi,%edx,4), %ebp	C multiplier
+	movl	%edx, VAR_COUNTER
+
+	movl	-8+OFFSET(%esi,%edx,4), %eax	C first limb of multiplicand
+
+	mull	%ebp
+
+define(cmovX,`ifelse(eval(UNROLL_COUNT%2),1,`cmovz($@)',`cmovnz($@)')')
+
+	testb	$1, %cl
+
+	movl	%edx, %ebx	C high carry
+	leal	4(%edi), %edi
+
+	movl	%ecx, %edx	C jump
+
+	movl	%eax, %ecx	C low carry
+	leal	CODE_BYTES_PER_LIMB(%edx), %edx
+
+	cmovX(	%ebx, %ecx)	C high carry reverse
+	cmovX(	%eax, %ebx)	C low carry reverse
+	movl	%edx, VAR_JMP
+	jmp	*%edx
+
+
+	C Must be on an even address here so the low bit of the jump address
+	C will indicate which way around ecx/ebx should start.
+
+	ALIGN(2)
+
+L(unroll_inner_start):
+	C eax	scratch
+	C ebx	carry high
+	C ecx	carry low
+	C edx	scratch
+	C esi	src pointer
+	C edi	dst pointer
+	C ebp	multiplier
+	C
+	C 15 code bytes each limb
+	C ecx/ebx reversed on each chunk
+
+forloop(`i', UNROLL_COUNT, 1, `
+	deflit(`disp_src', eval(-i*4 + OFFSET))
+	deflit(`disp_dst', eval(disp_src))
+
+	m4_assert(`disp_src>=-128 && disp_src<128')
+	m4_assert(`disp_dst>=-128 && disp_dst<128')
+
+ifelse(eval(i%2),0,`
+Zdisp(	movl,	disp_src,(%esi), %eax)
+	mull	%ebp
+Zdisp(	addl,	%ebx, disp_dst,(%edi))
+	adcl	%eax, %ecx
+	movl	%edx, %ebx
+	adcl	$0, %ebx
+',`
+	dnl  this one comes out last
+Zdisp(	movl,	disp_src,(%esi), %eax)
+	mull	%ebp
+Zdisp(	addl,	%ecx, disp_dst,(%edi))
+	adcl	%eax, %ebx
+	movl	%edx, %ecx
+	adcl	$0, %ecx
+')
+')
+L(unroll_inner_end):
+
+	addl	%ebx, m4_empty_if_zero(OFFSET)(%edi)
+
+	movl	VAR_COUNTER, %edx
+	adcl	$0, %ecx
+
+	movl	%ecx, m4_empty_if_zero(OFFSET+4)(%edi)
+	movl	VAR_JMP, %ecx
+
+	incl	%edx
+	jnz	L(unroll_outer_top)
+
+
+ifelse(OFFSET,0,,`
+	addl	$OFFSET, %esi
+	addl	$OFFSET, %edi
+')
+
+
+C -----------------------------------------------------------------------------
+	ALIGN(16)
+L(corner):
+	C eax
+	C ebx
+	C ecx
+	C edx
+	C esi	&src[size]
+	C edi	&dst[2*size-5]
+	C ebp
+
+	movl	-12(%esi), %eax
+
+	mull	-8(%esi)
+
+	addl	%eax, (%edi)
+	movl	-12(%esi), %eax
+	movl	$0, %ebx
+
+	adcl	%edx, %ebx
+
+	mull	-4(%esi)
+
+	addl	%eax, %ebx
+	movl	-8(%esi), %eax
+
+	adcl	$0, %edx
+
+	addl	%ebx, 4(%edi)
+	movl	$0, %ebx
+
+	adcl	%edx, %ebx
+
+	mull	-4(%esi)
+
+	movl	PARAM_SIZE, %ecx
+	addl	%ebx, %eax
+
+	adcl	$0, %edx
+
+	movl	%eax, 8(%edi)
+
+	movl	%edx, 12(%edi)
+	movl	PARAM_DST, %edi
+
+
+C Left shift of dst[1..2*size-2], the bit shifted out becomes dst[2*size-1].
+
+	subl	$1, %ecx		C size-1
+	xorl	%eax, %eax		C ready for final adcl, and clear carry
+
+	movl	%ecx, %edx
+	movl	PARAM_SRC, %esi
+
+
+L(lshift):
+	C eax
+	C ebx
+	C ecx	counter, size-1 to 1
+	C edx	size-1 (for later use)
+	C esi	src (for later use)
+	C edi	dst, incrementing
+	C ebp
+
+	rcll	4(%edi)
+	rcll	8(%edi)
+
+	leal	8(%edi), %edi
+	decl	%ecx
+	jnz	L(lshift)
+
+
+	adcl	%eax, %eax
+
+	movl	%eax, 4(%edi)		C dst most significant limb
+	movl	(%esi), %eax		C src[0]
+
+	leal	4(%esi,%edx,4), %esi	C &src[size]
+	subl	%edx, %ecx		C -(size-1)
+
+
+C Now add in the squares on the diagonal, src[0]^2, src[1]^2, ...,
+C src[size-1]^2.  dst[0] hasn't yet been set at all yet, and just gets the
+C low limb of src[0]^2.
+
+
+	mull	%eax
+
+	movl	%eax, (%edi,%ecx,8)	C dst[0]
+
+
+L(diag):
+	C eax	scratch
+	C ebx	scratch
+	C ecx	counter, negative
+	C edx	carry
+	C esi	&src[size]
+	C edi	dst[2*size-2]
+	C ebp
+
+	movl	(%esi,%ecx,4), %eax
+	movl	%edx, %ebx
+
+	mull	%eax
+
+	addl	%ebx, 4(%edi,%ecx,8)
+	adcl	%eax, 8(%edi,%ecx,8)
+	adcl	$0, %edx
+
+	incl	%ecx
+	jnz	L(diag)
+
+
+	movl	SAVE_ESI, %esi
+	movl	SAVE_EBX, %ebx
+
+	addl	%edx, 4(%edi)		C dst most significant limb
+
+	movl	SAVE_EDI, %edi
+	movl	SAVE_EBP, %ebp
+	addl	$FRAME, %esp
+	ret
+
+
+
+C -----------------------------------------------------------------------------
+ifdef(`PIC',`
+L(pic_calc):
+	addl	(%esp), %ecx
+	addl	$L(unroll_inner_end)-L(here)-eval(2*CODE_BYTES_PER_LIMB), %ecx
+	addl	%edx, %ecx
+	ret_internal
+')
+
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/p6/sse2/addmul_1.asm b/third_party/gmp/mpn/x86/p6/sse2/addmul_1.asm
new file mode 100644
index 0000000..144b627
--- /dev/null
+++ b/third_party/gmp/mpn/x86/p6/sse2/addmul_1.asm
@@ -0,0 +1,37 @@
+dnl  Intel P6/SSE2 mpn_addmul_1.
+
+dnl  Copyright 2008 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C TODO
+C  * Write P6 specific SSE2 code.
+
+MULFUNC_PROLOGUE(mpn_addmul_1)
+include_mpn(`x86/pentium4/sse2/addmul_1.asm')
diff --git a/third_party/gmp/mpn/x86/p6/sse2/gmp-mparam.h b/third_party/gmp/mpn/x86/p6/sse2/gmp-mparam.h
new file mode 100644
index 0000000..a1e261b
--- /dev/null
+++ b/third_party/gmp/mpn/x86/p6/sse2/gmp-mparam.h
@@ -0,0 +1,200 @@
+/* Intel P6/sse2 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 1999-2003, 2008-2010 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+
+/* NOTE: In a fat binary build SQR_TOOM2_THRESHOLD here cannot be more than the
+   value in mpn/x86/p6/gmp-mparam.h.  The latter is used as a hard limit in
+   mpn/x86/p6/sqr_basecase.asm.  */
+
+
+/* 1867 MHz P6 model 13 */
+
+#define MOD_1_NORM_THRESHOLD                 4
+#define MOD_1_UNNORM_THRESHOLD               4
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          5
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          4
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        11
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD         0  /* never mpn_mod_1s_2p */
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD      8
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           21
+
+#define MUL_TOOM22_THRESHOLD                20
+#define MUL_TOOM33_THRESHOLD                77
+#define MUL_TOOM44_THRESHOLD               169
+#define MUL_TOOM6H_THRESHOLD               246
+#define MUL_TOOM8H_THRESHOLD               381
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      73
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     114
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD      97
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD      80
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     106
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 30
+#define SQR_TOOM3_THRESHOLD                101
+#define SQR_TOOM4_THRESHOLD                154
+#define SQR_TOOM6_THRESHOLD                222
+#define SQR_TOOM8_THRESHOLD                527
+
+#define MULMID_TOOM42_THRESHOLD             58
+
+#define MULMOD_BNM1_THRESHOLD               13
+#define SQRMOD_BNM1_THRESHOLD               17
+
+#define MUL_FFT_MODF_THRESHOLD             690  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    565, 5}, {     25, 6}, {     13, 5}, {     27, 6}, \
+    {     25, 7}, {     13, 6}, {     28, 7}, {     15, 6}, \
+    {     31, 7}, {     17, 6}, {     35, 7}, {     27, 8}, \
+    {     15, 7}, {     35, 8}, {     19, 7}, {     41, 8}, \
+    {     23, 7}, {     47, 8}, {     27, 9}, {     15, 8}, \
+    {     31, 7}, {     63, 8}, {     39, 9}, {     23, 5}, \
+    {    383, 4}, {    991, 5}, {    511, 6}, {    267, 7}, \
+    {    157, 8}, {     91, 9}, {     47, 8}, {    111, 9}, \
+    {     63, 8}, {    127, 9}, {     79,10}, {     47, 9}, \
+    {     95,11}, {     31,10}, {     63, 9}, {    135,10}, \
+    {     79, 9}, {    159,10}, {     95,11}, {     63,10}, \
+    {    143, 9}, {    287,10}, {    159,11}, {     95,10}, \
+    {    191,12}, {     63,11}, {    127,10}, {    255, 9}, \
+    {    511,10}, {    271, 9}, {    543,10}, {    287,11}, \
+    {    159,10}, {    335, 9}, {    671,11}, {    191,10}, \
+    {    383, 9}, {    767,10}, {    399, 9}, {    799,10}, \
+    {    415,11}, {    223,12}, {    127,11}, {    255,10}, \
+    {    543, 9}, {   1087,11}, {    287,10}, {    607,11}, \
+    {    319,10}, {    671,12}, {    191,11}, {    383,10}, \
+    {    799,11}, {    415,10}, {    831,13}, {    127,12}, \
+    {    255,11}, {    543,10}, {   1087,11}, {    607,10}, \
+    {   1215,12}, {    319,11}, {    671,10}, {   1343,11}, \
+    {    735,10}, {   1471,12}, {    383,11}, {    799,10}, \
+    {   1599,11}, {    863,12}, {    447,11}, {    959,13}, \
+    {    255,12}, {    511,11}, {   1087,12}, {    575,11}, \
+    {   1215,12}, {    639,11}, {   1343,12}, {    703,11}, \
+    {   1471,13}, {    383,12}, {    831,11}, {   1727,12}, \
+    {    959,14}, {    255,13}, {    511,12}, {   1215,13}, \
+    {    639,12}, {   1471,11}, {   2943,13}, {    767,12}, \
+    {   1727,13}, {    895,12}, {   1919,14}, {    511,13}, \
+    {   1023,12}, {   2111,13}, {   1151,12}, {   2431,13}, \
+    {   1407,12}, {   2815,14}, {    767,13}, {   1663,12}, \
+    {   3455,13}, {   8192,14}, {  16384,15}, {  32768,16} }
+#define MUL_FFT_TABLE3_SIZE 132
+#define MUL_FFT_THRESHOLD                 7424
+
+#define SQR_FFT_MODF_THRESHOLD             565  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    472, 5}, {     25, 6}, {     13, 5}, {     27, 6}, \
+    {     25, 7}, {     13, 6}, {     27, 7}, {     15, 6}, \
+    {     31, 7}, {     17, 6}, {     35, 7}, {     27, 8}, \
+    {     15, 7}, {     35, 8}, {     19, 7}, {     41, 8}, \
+    {     23, 7}, {     49, 8}, {     27, 9}, {     15, 8}, \
+    {     39, 9}, {     23, 8}, {     51,10}, {     15, 9}, \
+    {     31, 8}, {     63, 4}, {   1023, 8}, {     67, 9}, \
+    {     39, 5}, {    639, 4}, {   1471, 6}, {    383, 7}, \
+    {    209, 8}, {    119, 9}, {     63, 7}, {    255, 8}, \
+    {    139, 9}, {     71, 8}, {    143, 9}, {     79,10}, \
+    {     47, 9}, {     95,11}, {     31,10}, {     63, 9}, \
+    {    135,10}, {     79, 9}, {    159, 8}, {    319, 9}, \
+    {    167,10}, {     95,11}, {     63,10}, {    143, 9}, \
+    {    287,10}, {    159,11}, {     95,10}, {    191,12}, \
+    {     63,11}, {    127,10}, {    255, 9}, {    543, 8}, \
+    {   1087,10}, {    287, 9}, {    575,11}, {    159,10}, \
+    {    319, 9}, {    639,10}, {    335, 9}, {    671,10}, \
+    {    351, 9}, {    703,11}, {    191,10}, {    383, 9}, \
+    {    767,10}, {    399, 9}, {    799,10}, {    415, 9}, \
+    {    831,11}, {    223,12}, {    127,11}, {    255,10}, \
+    {    543, 9}, {   1087,11}, {    287,10}, {    607, 9}, \
+    {   1215,11}, {    319,10}, {    671, 9}, {   1343,11}, \
+    {    351,10}, {    703,12}, {    191,11}, {    383,10}, \
+    {    799,11}, {    415,10}, {    831,13}, {    127,12}, \
+    {    255,11}, {    543,10}, {   1087,11}, {    607,12}, \
+    {    319,11}, {    671,10}, {   1343,11}, {    735,12}, \
+    {    383,11}, {    799,10}, {   1599,11}, {    863,12}, \
+    {    447,11}, {    959,13}, {    255,12}, {    511,11}, \
+    {   1087,12}, {    575,11}, {   1215,12}, {    639,11}, \
+    {   1343,12}, {    703,11}, {   1471,13}, {    383,12}, \
+    {    767,11}, {   1599,12}, {    831,11}, {   1727,12}, \
+    {    959,14}, {    255,13}, {    511,12}, {   1215,13}, \
+    {    639,12}, {   1471,13}, {    767,12}, {   1727,13}, \
+    {    895,12}, {   1919,14}, {    511,13}, {   1023,12}, \
+    {   2111,13}, {   1151,12}, {   2431,13}, {   1407,14}, \
+    {    767,13}, {   1663,12}, {   3455,13}, {   8192,14}, \
+    {  16384,15}, {  32768,16} }
+#define SQR_FFT_TABLE3_SIZE 146
+#define SQR_FFT_THRESHOLD                 5760
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  31
+#define MULLO_MUL_N_THRESHOLD            13463
+#define SQRLO_BASECASE_THRESHOLD             0  /* always */
+#define SQRLO_DC_THRESHOLD                 100
+#define SQRLO_SQR_THRESHOLD               9236
+
+#define DC_DIV_QR_THRESHOLD                 25
+#define DC_DIVAPPR_Q_THRESHOLD              55
+#define DC_BDIV_QR_THRESHOLD                60
+#define DC_BDIV_Q_THRESHOLD                132
+
+#define INV_MULMOD_BNM1_THRESHOLD           38
+#define INV_NEWTON_THRESHOLD                65
+#define INV_APPR_THRESHOLD                  65
+
+#define BINV_NEWTON_THRESHOLD              252
+#define REDC_1_TO_REDC_N_THRESHOLD          62
+
+#define MU_DIV_QR_THRESHOLD               1164
+#define MU_DIVAPPR_Q_THRESHOLD             748
+#define MUPI_DIV_QR_THRESHOLD               38
+#define MU_BDIV_QR_THRESHOLD              1360
+#define MU_BDIV_Q_THRESHOLD               1470
+
+#define POWM_SEC_TABLE  2,23,258,879,2246
+
+#define GET_STR_DC_THRESHOLD                13
+#define GET_STR_PRECOMPUTE_THRESHOLD        25
+#define SET_STR_DC_THRESHOLD               582
+#define SET_STR_PRECOMPUTE_THRESHOLD      1118
+
+#define FAC_DSC_THRESHOLD                  178
+#define FAC_ODD_THRESHOLD                   34
+
+#define MATRIX22_STRASSEN_THRESHOLD         17
+#define HGCD_THRESHOLD                      69
+#define HGCD_APPR_THRESHOLD                112
+#define HGCD_REDUCE_THRESHOLD             3389
+#define GCD_DC_THRESHOLD                   386
+#define GCDEXT_DC_THRESHOLD                303
+#define JACOBI_BASE_METHOD                   1
diff --git a/third_party/gmp/mpn/x86/p6/sse2/mod_1_1.asm b/third_party/gmp/mpn/x86/p6/sse2/mod_1_1.asm
new file mode 100644
index 0000000..8b7b7ad
--- /dev/null
+++ b/third_party/gmp/mpn/x86/p6/sse2/mod_1_1.asm
@@ -0,0 +1,34 @@
+dnl  Intel P6/SSE2 mpn_mod_1_1.
+
+dnl  Copyright 2009, 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+MULFUNC_PROLOGUE(mpn_mod_1_1p)
+include_mpn(`x86/pentium4/sse2/mod_1_1.asm')
diff --git a/third_party/gmp/mpn/x86/p6/sse2/mod_1_4.asm b/third_party/gmp/mpn/x86/p6/sse2/mod_1_4.asm
new file mode 100644
index 0000000..49c96c6
--- /dev/null
+++ b/third_party/gmp/mpn/x86/p6/sse2/mod_1_4.asm
@@ -0,0 +1,34 @@
+dnl  Intel P6/SSE2 mpn_mod_1_4.
+
+dnl  Copyright 2009, 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+MULFUNC_PROLOGUE(mpn_mod_1s_4p)
+include_mpn(`x86/pentium4/sse2/mod_1_4.asm')
diff --git a/third_party/gmp/mpn/x86/p6/sse2/mul_1.asm b/third_party/gmp/mpn/x86/p6/sse2/mul_1.asm
new file mode 100644
index 0000000..50e5b69
--- /dev/null
+++ b/third_party/gmp/mpn/x86/p6/sse2/mul_1.asm
@@ -0,0 +1,38 @@
+dnl  Intel P6/SSE2 mpn_mul_1.
+
+dnl  Copyright 2008 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C TODO
+C  * Write P6 specific SSE2 code.  It should reach 3 c/l.
+C    The Pentium4 code runs at 4.2 c/l.
+
+MULFUNC_PROLOGUE(mpn_mul_1)
+include_mpn(`x86/pentium4/sse2/mul_1.asm')
diff --git a/third_party/gmp/mpn/x86/p6/sse2/mul_basecase.asm b/third_party/gmp/mpn/x86/p6/sse2/mul_basecase.asm
new file mode 100644
index 0000000..4687625
--- /dev/null
+++ b/third_party/gmp/mpn/x86/p6/sse2/mul_basecase.asm
@@ -0,0 +1,35 @@
+dnl  Intel P6/SSE2 mpn_mul_basecase.
+
+dnl  Copyright 2008 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+MULFUNC_PROLOGUE(mpn_mul_basecase)
+include_mpn(`x86/pentium4/sse2/mul_basecase.asm')
diff --git a/third_party/gmp/mpn/x86/p6/sse2/popcount.asm b/third_party/gmp/mpn/x86/p6/sse2/popcount.asm
new file mode 100644
index 0000000..4c02b93
--- /dev/null
+++ b/third_party/gmp/mpn/x86/p6/sse2/popcount.asm
@@ -0,0 +1,35 @@
+dnl  Intel P6/SSE2 mpn_popcount -- population count.
+
+dnl  Copyright 2008 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+MULFUNC_PROLOGUE(mpn_popcount)
+include_mpn(`x86/pentium4/sse2/popcount.asm')
diff --git a/third_party/gmp/mpn/x86/p6/sse2/sqr_basecase.asm b/third_party/gmp/mpn/x86/p6/sse2/sqr_basecase.asm
new file mode 100644
index 0000000..76b574b
--- /dev/null
+++ b/third_party/gmp/mpn/x86/p6/sse2/sqr_basecase.asm
@@ -0,0 +1,35 @@
+dnl  Intel P6/SSE2 mpn_sqr_basecase.
+
+dnl  Copyright 2008 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+MULFUNC_PROLOGUE(mpn_sqr_basecase)
+include_mpn(`x86/pentium4/sse2/sqr_basecase.asm')
diff --git a/third_party/gmp/mpn/x86/p6/sse2/submul_1.asm b/third_party/gmp/mpn/x86/p6/sse2/submul_1.asm
new file mode 100644
index 0000000..69d940d
--- /dev/null
+++ b/third_party/gmp/mpn/x86/p6/sse2/submul_1.asm
@@ -0,0 +1,35 @@
+dnl  Intel P6/SSE2 mpn_submul_1.
+
+dnl  Copyright 2008 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+MULFUNC_PROLOGUE(mpn_submul_1)
+include_mpn(`x86/pentium4/sse2/submul_1.asm')
diff --git a/third_party/gmp/mpn/x86/pentium/README b/third_party/gmp/mpn/x86/pentium/README
new file mode 100644
index 0000000..305936b
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium/README
@@ -0,0 +1,181 @@
+Copyright 1996, 1999-2001, 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.
+
+
+
+
+
+                   INTEL PENTIUM P5 MPN SUBROUTINES
+
+
+This directory contains mpn functions optimized for Intel Pentium (P5,P54)
+processors.  The mmx subdirectory has additional code for Pentium with MMX
+(P55).
+
+
+STATUS
+
+                                cycles/limb
+
+	mpn_add_n/sub_n            2.375
+
+	mpn_mul_1                 12.0
+	mpn_add/submul_1          14.0
+
+	mpn_mul_basecase          14.2 cycles/crossproduct (approx)
+
+	mpn_sqr_basecase           8 cycles/crossproduct (approx)
+                                   or 15.5 cycles/triangleproduct (approx)
+
+	mpn_l/rshift               5.375 normal (6.0 on P54)
+				   1.875 special shift by 1 bit
+
+	mpn_divrem_1              44.0
+	mpn_mod_1                 28.0
+	mpn_divexact_by3          15.0
+
+	mpn_copyi/copyd            1.0
+
+Pentium MMX gets the following improvements
+
+	mpn_l/rshift               1.75
+
+	mpn_mul_1                 12.0 normal, 7.0 for 16-bit multiplier
+
+
+mpn_add_n and mpn_sub_n run at asymptotically 2 cycles/limb.  Due to loop
+overhead and other delays (cache refill?), they run at or near 2.5
+cycles/limb.
+
+mpn_mul_1, mpn_addmul_1, mpn_submul_1 all run 1 cycle faster than they
+should.  Intel documentation says a mul instruction is 10 cycles, but it
+measures 9 and the routines using it run as 9.
+
+
+
+P55 MMX AND X87
+
+The cost of switching between MMX and x87 floating point on P55 is about 100
+cycles (fld1/por/emms for instance).  In order to avoid that the two aren't
+mixed and currently that means using MMX and not x87.
+
+MMX offers a big speedup for lshift and rshift, and a nice speedup for
+16-bit multipliers in mpn_mul_1.  If fast code using x87 is found then
+perhaps the preference for MMX will be reversed.
+
+
+
+
+P54 SHLDL
+
+mpn_lshift and mpn_rshift run at about 6 cycles/limb on P5 and P54, but the
+documentation indicates that they should take only 43/8 = 5.375 cycles/limb,
+or 5 cycles/limb asymptotically.  The P55 runs them at the expected speed.
+
+It seems that on P54 a shldl or shrdl allows pairing in one following cycle,
+but not two.  For example, back to back repetitions of the following
+
+	shldl(	%cl, %eax, %ebx)
+	xorl	%edx, %edx
+	xorl	%esi, %esi
+
+run at 5 cycles, as expected, but repetitions of the following run at 7
+cycles, whereas 6 would be expected (and is achieved on P55),
+
+	shldl(	%cl, %eax, %ebx)
+	xorl	%edx, %edx
+	xorl	%esi, %esi
+	xorl	%edi, %edi
+	xorl	%ebp, %ebp
+
+Three xorls run at 7 cycles too, so it doesn't seem to be just that pairing
+inhibited is only in the second following cycle (or something like that).
+
+Avoiding this problem would bring P54 shifts down from 6.0 c/l to 5.5 with a
+pattern of shift, 2 loads, shift, 2 stores, shift, etc.  A start has been
+made on something like that, but it's not yet complete.
+
+
+
+
+OTHER NOTES
+
+Prefetching Destinations
+
+    Pentium doesn't allocate cache lines on writes, unlike most other modern
+    processors.  Since the functions in the mpn class do array writes, we
+    have to handle allocating the destination cache lines by reading a word
+    from it in the loops, to achieve the best performance.
+
+Prefetching Sources
+
+    Prefetching of sources is pointless since there's no out-of-order loads.
+    Any load instruction blocks until the line is brought to L1, so it may
+    as well be the load that wants the data which blocks.
+
+Data Cache Bank Clashes
+
+    Pairing of memory operations requires that the two issued operations
+    refer to different cache banks (ie. different addresses modulo 32
+    bytes).  The simplest way to ensure this is to read/write two words from
+    the same object.  If we make operations on different objects, they might
+    or might not be to the same cache bank.
+
+PIC %eip Fetching
+
+    A simple call $+5 and popl can be used to get %eip, there's no need to
+    balance calls and returns since P5 doesn't have any return stack branch
+    prediction.
+
+Float Multiplies
+
+    fmul is pairable and can be issued every 2 cycles (with a 4 cycle
+    latency for data ready to use).  This is a lot better than integer mull
+    or imull at 9 cycles non-pairing.  Unfortunately the advantage is
+    quickly eaten away by needing to throw data through memory back to the
+    integer registers to adjust for fild and fist being signed, and to do
+    things like propagating carry bits.
+
+
+
+
+
+REFERENCES
+
+"Intel Architecture Optimization Manual", 1997, order number 242816.  This
+is mostly about P5, the parts about P6 aren't relevant.  Available on-line:
+
+        http://download.intel.com/design/PentiumII/manuals/242816.htm
+
+
+
+----------------
+Local variables:
+mode: text
+fill-column: 76
+End:
diff --git a/third_party/gmp/mpn/x86/pentium/aors_n.asm b/third_party/gmp/mpn/x86/pentium/aors_n.asm
new file mode 100644
index 0000000..01ebfb9
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium/aors_n.asm
@@ -0,0 +1,203 @@
+dnl  Intel Pentium mpn_add_n/mpn_sub_n -- mpn addition and subtraction.
+
+dnl  Copyright 1992, 1994-1996, 1999, 2000, 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C P5: 2.375 cycles/limb
+
+
+ifdef(`OPERATION_add_n',`
+	define(M4_inst,        adcl)
+	define(M4_function_n,  mpn_add_n)
+	define(M4_function_nc, mpn_add_nc)
+
+',`ifdef(`OPERATION_sub_n',`
+	define(M4_inst,        sbbl)
+	define(M4_function_n,  mpn_sub_n)
+	define(M4_function_nc, mpn_sub_nc)
+
+',`m4_error(`Need OPERATION_add_n or OPERATION_sub_n
+')')')
+
+MULFUNC_PROLOGUE(mpn_add_n mpn_add_nc mpn_sub_n mpn_sub_nc)
+
+
+C mp_limb_t M4_function_n (mp_ptr dst, mp_srcptr src1, mp_srcptr src2,
+C                          mp_size_t size);
+C mp_limb_t M4_function_nc (mp_ptr dst, mp_srcptr src1, mp_srcptr src2,
+C                           mp_size_t size, mp_limb_t carry);
+
+defframe(PARAM_CARRY,20)
+defframe(PARAM_SIZE, 16)
+defframe(PARAM_SRC2, 12)
+defframe(PARAM_SRC1, 8)
+defframe(PARAM_DST,  4)
+
+	TEXT
+	ALIGN(8)
+PROLOGUE(M4_function_nc)
+
+	pushl	%edi
+	pushl	%esi
+	pushl	%ebx
+	pushl	%ebp
+deflit(`FRAME',16)
+
+	movl	PARAM_DST,%edi
+	movl	PARAM_SRC1,%esi
+	movl	PARAM_SRC2,%ebp
+	movl	PARAM_SIZE,%ecx
+
+	movl	(%ebp),%ebx
+
+	decl	%ecx
+	movl	%ecx,%edx
+	shrl	$3,%ecx
+	andl	$7,%edx
+	testl	%ecx,%ecx		C zero carry flag
+	jz	L(endgo)
+
+	pushl	%edx
+FRAME_pushl()
+	movl	PARAM_CARRY,%eax
+	shrl	%eax			C shift bit 0 into carry
+	jmp	L(oop)
+
+L(endgo):
+deflit(`FRAME',16)
+	movl	PARAM_CARRY,%eax
+	shrl	%eax			C shift bit 0 into carry
+	jmp	L(end)
+
+EPILOGUE()
+
+
+	ALIGN(8)
+PROLOGUE(M4_function_n)
+
+	pushl	%edi
+	pushl	%esi
+	pushl	%ebx
+	pushl	%ebp
+deflit(`FRAME',16)
+
+	movl	PARAM_DST,%edi
+	movl	PARAM_SRC1,%esi
+	movl	PARAM_SRC2,%ebp
+	movl	PARAM_SIZE,%ecx
+
+	movl	(%ebp),%ebx
+
+	decl	%ecx
+	movl	%ecx,%edx
+	shrl	$3,%ecx
+	andl	$7,%edx
+	testl	%ecx,%ecx		C zero carry flag
+	jz	L(end)
+	pushl	%edx
+FRAME_pushl()
+
+	ALIGN(8)
+L(oop):	movl	28(%edi),%eax		C fetch destination cache line
+	leal	32(%edi),%edi
+
+L(1):	movl	(%esi),%eax
+	movl	4(%esi),%edx
+	M4_inst	%ebx,%eax
+	movl	4(%ebp),%ebx
+	M4_inst	%ebx,%edx
+	movl	8(%ebp),%ebx
+	movl	%eax,-32(%edi)
+	movl	%edx,-28(%edi)
+
+L(2):	movl	8(%esi),%eax
+	movl	12(%esi),%edx
+	M4_inst	%ebx,%eax
+	movl	12(%ebp),%ebx
+	M4_inst	%ebx,%edx
+	movl	16(%ebp),%ebx
+	movl	%eax,-24(%edi)
+	movl	%edx,-20(%edi)
+
+L(3):	movl	16(%esi),%eax
+	movl	20(%esi),%edx
+	M4_inst	%ebx,%eax
+	movl	20(%ebp),%ebx
+	M4_inst	%ebx,%edx
+	movl	24(%ebp),%ebx
+	movl	%eax,-16(%edi)
+	movl	%edx,-12(%edi)
+
+L(4):	movl	24(%esi),%eax
+	movl	28(%esi),%edx
+	M4_inst	%ebx,%eax
+	movl	28(%ebp),%ebx
+	M4_inst	%ebx,%edx
+	movl	32(%ebp),%ebx
+	movl	%eax,-8(%edi)
+	movl	%edx,-4(%edi)
+
+	leal	32(%esi),%esi
+	leal	32(%ebp),%ebp
+	decl	%ecx
+	jnz	L(oop)
+
+	popl	%edx
+FRAME_popl()
+L(end):
+	decl	%edx			C test %edx w/o clobbering carry
+	js	L(end2)
+	incl	%edx
+L(oop2):
+	leal	4(%edi),%edi
+	movl	(%esi),%eax
+	M4_inst	%ebx,%eax
+	movl	4(%ebp),%ebx
+	movl	%eax,-4(%edi)
+	leal	4(%esi),%esi
+	leal	4(%ebp),%ebp
+	decl	%edx
+	jnz	L(oop2)
+L(end2):
+	movl	(%esi),%eax
+	M4_inst	%ebx,%eax
+	movl	%eax,(%edi)
+
+	sbbl	%eax,%eax
+	negl	%eax
+
+	popl	%ebp
+	popl	%ebx
+	popl	%esi
+	popl	%edi
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/pentium/aorsmul_1.asm b/third_party/gmp/mpn/x86/pentium/aorsmul_1.asm
new file mode 100644
index 0000000..d83cc45
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium/aorsmul_1.asm
@@ -0,0 +1,144 @@
+dnl  Intel Pentium mpn_addmul_1 -- mpn by limb multiplication.
+
+dnl  Copyright 1992, 1994, 1996, 1999, 2000, 2002 Free Software Foundation,
+dnl  Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C P5: 14.0 cycles/limb
+
+
+ifdef(`OPERATION_addmul_1', `
+      define(M4_inst,        addl)
+      define(M4_function_1,  mpn_addmul_1)
+      define(M4_function_1c, mpn_addmul_1c)
+
+',`ifdef(`OPERATION_submul_1', `
+      define(M4_inst,        subl)
+      define(M4_function_1,  mpn_submul_1)
+      define(M4_function_1c, mpn_submul_1c)
+
+',`m4_error(`Need OPERATION_addmul_1 or OPERATION_submul_1
+')')')
+
+MULFUNC_PROLOGUE(mpn_addmul_1 mpn_addmul_1c mpn_submul_1 mpn_submul_1c)
+
+
+C mp_limb_t mpn_addmul_1 (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                         mp_limb_t mult);
+C mp_limb_t mpn_addmul_1c (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                          mp_limb_t mult, mp_limb_t carry);
+C
+C mp_limb_t mpn_submul_1 (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                         mp_limb_t mult);
+C mp_limb_t mpn_submul_1c (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                          mp_limb_t mult, mp_limb_t carry);
+C
+
+defframe(PARAM_CARRY,     20)
+defframe(PARAM_MULTIPLIER,16)
+defframe(PARAM_SIZE,      12)
+defframe(PARAM_SRC,       8)
+defframe(PARAM_DST,       4)
+
+	TEXT
+
+	ALIGN(8)
+PROLOGUE(M4_function_1c)
+deflit(`FRAME',0)
+
+	movl	PARAM_CARRY, %ecx
+	pushl	%esi		FRAME_pushl()
+
+	jmp	L(start_1c)
+
+EPILOGUE()
+
+
+	ALIGN(8)
+PROLOGUE(M4_function_1)
+deflit(`FRAME',0)
+
+	xorl	%ecx, %ecx
+	pushl	%esi		FRAME_pushl()
+
+L(start_1c):
+	movl	PARAM_SRC, %esi
+	movl	PARAM_SIZE, %eax
+
+	pushl	%edi		FRAME_pushl()
+	pushl	%ebx		FRAME_pushl()
+
+	movl	PARAM_DST, %edi
+	leal	-1(%eax), %ebx		C size-1
+
+	leal	(%esi,%eax,4), %esi
+	xorl	$-1, %ebx		C -size, and clear carry
+
+	leal	(%edi,%eax,4), %edi
+
+L(top):
+	C eax
+	C ebx	counter, negative
+	C ecx	carry
+	C edx
+	C esi	src end
+	C edi	dst end
+	C ebp
+
+	adcl	$0, %ecx
+	movl	(%esi,%ebx,4), %eax
+
+	mull	PARAM_MULTIPLIER
+
+	addl	%ecx, %eax
+	movl	(%edi,%ebx,4), %ecx
+
+	adcl	$0, %edx
+	M4_inst	%eax, %ecx
+
+	movl	%ecx, (%edi,%ebx,4)
+	incl	%ebx
+
+	movl	%edx, %ecx
+	jnz	L(top)
+
+
+	adcl	$0, %ecx
+	popl	%ebx
+
+	movl	%ecx, %eax
+	popl	%edi
+
+	popl	%esi
+
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/pentium/bdiv_q_1.asm b/third_party/gmp/mpn/x86/pentium/bdiv_q_1.asm
new file mode 100644
index 0000000..c2c4f58
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium/bdiv_q_1.asm
@@ -0,0 +1,266 @@
+dnl  Intel Pentium mpn_divexact_1 -- mpn by limb exact division.
+
+dnl  Rearranged from mpn/x86/pentium/dive_1.asm by Marco Bodrato.
+
+dnl  Copyright 2001, 2002, 2011, 2014 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C         divisor
+C       odd   even
+C P54:  24.5  30.5   cycles/limb
+C P55:  23.0  28.0
+
+MULFUNC_PROLOGUE(mpn_bdiv_q_1 mpn_pi1_bdiv_q_1)
+
+C The P55 speeds noted above, 23 cycles odd or 28 cycles even, are as
+C expected.  On P54 in the even case the shrdl pairing nonsense (see
+C mpn/x86/pentium/README) costs 1 cycle, but it's not clear why there's a
+C further 1.5 slowdown for both odd and even.
+
+defframe(PARAM_SHIFT,  24)
+defframe(PARAM_INVERSE,20)
+defframe(PARAM_DIVISOR,16)
+defframe(PARAM_SIZE,   12)
+defframe(PARAM_SRC,    8)
+defframe(PARAM_DST,    4)
+
+dnl  re-use parameter space
+define(VAR_INVERSE,`PARAM_DST')
+
+	TEXT
+
+	ALIGN(32)
+C mp_limb_t mpn_bdiv_q_1 (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                           mp_limb_t divisor);
+C
+PROLOGUE(mpn_bdiv_q_1)
+deflit(`FRAME',0)
+
+	movl	$-1, %ecx
+	movl	PARAM_DIVISOR, %eax
+
+L(strip_twos):
+	ASSERT(nz, `orl %eax, %eax')
+	shrl	%eax
+	incl	%ecx			C shift count
+
+	jnc	L(strip_twos)
+
+	leal	1(%eax,%eax), %edx	C d
+	andl	$127, %eax		C d/2, 7 bits
+
+	pushl	%ebx		FRAME_pushl()
+	pushl	%ebp		FRAME_pushl()
+
+ifdef(`PIC',`
+ifdef(`DARWIN',`
+	LEA(	binvert_limb_table, %ebp)
+	movzbl	(%eax,%ebp), %eax
+',`
+	call	L(here)
+L(here):
+	popl	%ebp			C eip
+
+	addl	$_GLOBAL_OFFSET_TABLE_+[.-L(here)], %ebp
+	C AGI
+	movl	binvert_limb_table@GOT(%ebp), %ebp
+	C AGI
+	movzbl	(%eax,%ebp), %eax
+')
+',`
+
+dnl non-PIC
+	movzbl	binvert_limb_table(%eax), %eax	C inv 8 bits
+')
+
+	movl	%eax, %ebp		C inv
+	addl	%eax, %eax		C 2*inv
+
+	imull	%ebp, %ebp		C inv*inv
+
+	imull	%edx, %ebp		C inv*inv*d
+
+	subl	%ebp, %eax		C inv = 2*inv - inv*inv*d
+	movl	PARAM_SIZE, %ebx
+
+	movl	%eax, %ebp
+	addl	%eax, %eax		C 2*inv
+
+	imull	%ebp, %ebp		C inv*inv
+
+	imull	%edx, %ebp		C inv*inv*d
+
+	subl	%ebp, %eax		C inv = 2*inv - inv*inv*d
+	movl	%edx, PARAM_DIVISOR	C d without twos
+
+	ASSERT(e,`	C expect d*inv == 1 mod 2^GMP_LIMB_BITS
+	pushl	%eax	FRAME_pushl()
+	imull	PARAM_DIVISOR, %eax
+	cmpl	$1, %eax
+	popl	%eax	FRAME_popl()')
+
+	jmp	L(common)
+EPILOGUE()
+
+C mp_limb_t
+C mpn_pi1_bdiv_q_1 (mp_ptr dst, mp_srcptr src, mp_size_t size, mp_limb_t divisor,
+C		    mp_limb_t inverse, int shift)
+	ALIGN(32)
+PROLOGUE(mpn_pi1_bdiv_q_1)
+deflit(`FRAME',0)
+
+	movl	PARAM_SHIFT, %ecx
+
+	pushl	%ebx		FRAME_pushl()
+	pushl	%ebp		FRAME_pushl()
+
+	movl	PARAM_SIZE, %ebx
+	movl	PARAM_INVERSE, %eax
+
+L(common):
+	pushl	%esi		FRAME_pushl()
+	push	%edi		FRAME_pushl()
+
+	movl	PARAM_SRC, %esi
+	movl	PARAM_DST, %edi
+	movl	%eax, VAR_INVERSE
+
+	leal	(%esi,%ebx,4), %esi	C src end
+	leal	(%edi,%ebx,4), %edi	C dst end
+
+	negl	%ebx			C -size
+
+	xorl	%ebp, %ebp		C initial carry bit
+
+	orl	%ecx, %ecx		C shift
+	movl	(%esi,%ebx,4), %eax	C src low limb
+	jz	L(odd_entry)
+
+	xorl	%edx, %edx		C initial carry limb (for even, if one)
+	incl	%ebx
+	jz	L(one)
+
+	movl	(%esi,%ebx,4), %edx	C src second limb (for even)
+	shrdl(	%cl, %edx, %eax)
+
+	jmp	L(even_entry)
+
+
+	ALIGN(8)
+L(odd_top):
+	C eax	scratch
+	C ebx	counter, limbs, negative
+	C ecx
+	C edx
+	C esi	src end
+	C edi	dst end
+	C ebp	carry bit, 0 or -1
+
+	mull	PARAM_DIVISOR
+
+	movl	(%esi,%ebx,4), %eax
+	subl	%ebp, %edx
+
+	subl	%edx, %eax
+
+	sbbl	%ebp, %ebp
+
+L(odd_entry):
+	imull	VAR_INVERSE, %eax
+
+	movl	%eax, (%edi,%ebx,4)
+
+	incl	%ebx
+	jnz	L(odd_top)
+
+	popl	%edi
+	popl	%esi
+
+	popl	%ebp
+	popl	%ebx
+
+	ret
+
+L(even_top):
+	C eax	scratch
+	C ebx	counter, limbs, negative
+	C ecx	twos
+	C edx
+	C esi	src end
+	C edi	dst end
+	C ebp	carry bit, 0 or -1
+
+	mull	PARAM_DIVISOR
+
+	subl	%ebp, %edx		C carry bit
+	movl	-4(%esi,%ebx,4), %eax	C src limb
+
+	movl	(%esi,%ebx,4), %ebp	C and one above it
+
+	shrdl(	%cl, %ebp, %eax)
+
+	subl	%edx, %eax		C carry limb
+
+	sbbl	%ebp, %ebp
+
+L(even_entry):
+	imull	VAR_INVERSE, %eax
+
+	movl	%eax, -4(%edi,%ebx,4)
+	incl	%ebx
+
+	jnz	L(even_top)
+
+	mull	PARAM_DIVISOR
+
+	movl	-4(%esi), %eax		C src high limb
+	subl	%ebp, %edx
+
+L(one):
+	shrl	%cl, %eax
+
+	subl	%edx, %eax		C no carry if division is exact
+
+	imull	VAR_INVERSE, %eax
+
+	movl	%eax, -4(%edi)		C dst high limb
+	nop				C protect against cache bank clash
+
+	popl	%edi
+	popl	%esi
+
+	popl	%ebp
+	popl	%ebx
+
+	ret
+
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86/pentium/com.asm b/third_party/gmp/mpn/x86/pentium/com.asm
new file mode 100644
index 0000000..b080545
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium/com.asm
@@ -0,0 +1,181 @@
+dnl  Intel Pentium mpn_com -- mpn ones complement.
+
+dnl  Copyright 1996, 2001, 2002, 2006 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C P5: 1.75 cycles/limb
+
+
+NAILS_SUPPORT(0-31)
+
+
+C void mpn_com (mp_ptr dst, mp_srcptr src, mp_size_t size);
+C
+C This code is similar to mpn_copyi, basically there's just some "xorl
+C $GMP_NUMB_MASK"s inserted.
+C
+C Alternatives:
+C
+C On P55 some MMX code could be 1.25 c/l (8 limb unrolled) if src and dst
+C are the same alignment mod 8, but it doesn't seem worth the trouble for
+C just that case (there'd need to be some plain integer available too for
+C the unaligned case).
+
+defframe(PARAM_SIZE,12)
+defframe(PARAM_SRC, 8)
+defframe(PARAM_DST, 4)
+
+	TEXT
+	ALIGN(8)
+PROLOGUE(mpn_com)
+deflit(`FRAME',0)
+
+	movl	PARAM_SRC, %eax
+	movl	PARAM_SIZE, %ecx
+
+	pushl	%esi	FRAME_pushl()
+	pushl	%edi	FRAME_pushl()
+
+	leal	(%eax,%ecx,4), %eax
+	xorl	$-1, %ecx		C -size-1
+
+	movl	PARAM_DST, %edx
+	addl	$8, %ecx		C -size+7
+
+	jns	L(end)
+
+	movl	(%edx), %esi		C fetch destination cache line
+	nop
+
+L(top):
+	C eax	&src[size]
+	C ebx
+	C ecx	counter, limbs, negative
+	C edx	dst, incrementing
+	C esi	scratch
+	C edi	scratch
+	C ebp
+
+	movl	28(%edx), %esi		C destination prefetch
+	addl	$32, %edx
+
+	movl	-28(%eax,%ecx,4), %esi
+	movl	-24(%eax,%ecx,4), %edi
+	xorl	$GMP_NUMB_MASK, %esi
+	xorl	$GMP_NUMB_MASK, %edi
+	movl	%esi, -32(%edx)
+	movl	%edi, -28(%edx)
+
+	movl	-20(%eax,%ecx,4), %esi
+	movl	-16(%eax,%ecx,4), %edi
+	xorl	$GMP_NUMB_MASK, %esi
+	xorl	$GMP_NUMB_MASK, %edi
+	movl	%esi, -24(%edx)
+	movl	%edi, -20(%edx)
+
+	movl	-12(%eax,%ecx,4), %esi
+	movl	-8(%eax,%ecx,4), %edi
+	xorl	$GMP_NUMB_MASK, %esi
+	xorl	$GMP_NUMB_MASK, %edi
+	movl	%esi, -16(%edx)
+	movl	%edi, -12(%edx)
+
+	movl	-4(%eax,%ecx,4), %esi
+	movl	(%eax,%ecx,4), %edi
+	xorl	$GMP_NUMB_MASK, %esi
+	xorl	$GMP_NUMB_MASK, %edi
+	movl	%esi, -8(%edx)
+	movl	%edi, -4(%edx)
+
+	addl	$8, %ecx
+	js	L(top)
+
+
+L(end):
+	C eax	&src[size]
+	C ecx	0 to 7, representing respectively 7 to 0 limbs remaining
+	C edx	dst, next location to store
+
+	subl	$4, %ecx
+	nop
+
+	jns	L(no4)
+
+	movl	-12(%eax,%ecx,4), %esi
+	movl	-8(%eax,%ecx,4), %edi
+	xorl	$GMP_NUMB_MASK, %esi
+	xorl	$GMP_NUMB_MASK, %edi
+	movl	%esi, (%edx)
+	movl	%edi, 4(%edx)
+
+	movl	-4(%eax,%ecx,4), %esi
+	movl	(%eax,%ecx,4), %edi
+	xorl	$GMP_NUMB_MASK, %esi
+	xorl	$GMP_NUMB_MASK, %edi
+	movl	%esi, 8(%edx)
+	movl	%edi, 12(%edx)
+
+	addl	$16, %edx
+	addl	$4, %ecx
+L(no4):
+
+	subl	$2, %ecx
+	nop
+
+	jns	L(no2)
+
+	movl	-4(%eax,%ecx,4), %esi
+	movl	(%eax,%ecx,4), %edi
+	xorl	$GMP_NUMB_MASK, %esi
+	xorl	$GMP_NUMB_MASK, %edi
+	movl	%esi, (%edx)
+	movl	%edi, 4(%edx)
+
+	addl	$8, %edx
+	addl	$2, %ecx
+L(no2):
+
+	popl	%edi
+	jnz	L(done)
+
+	movl	-4(%eax), %ecx
+
+	xorl	$GMP_NUMB_MASK, %ecx
+	popl	%esi
+
+	movl	%ecx, (%edx)
+	ret
+
+L(done):
+	popl	%esi
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/pentium/copyd.asm b/third_party/gmp/mpn/x86/pentium/copyd.asm
new file mode 100644
index 0000000..72a543b
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium/copyd.asm
@@ -0,0 +1,146 @@
+dnl  Intel Pentium mpn_copyd -- copy limb vector, decrementing.
+
+dnl  Copyright 1996, 2001, 2002, 2006 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C P5: 1.25 cycles/limb
+
+
+C void mpn_copyd (mp_ptr dst, mp_srcptr src, mp_size_t size);
+C
+C See comments in copyi.asm.
+
+defframe(PARAM_SIZE,12)
+defframe(PARAM_SRC, 8)
+defframe(PARAM_DST, 4)
+
+	TEXT
+	ALIGN(8)
+PROLOGUE(mpn_copyd)
+deflit(`FRAME',0)
+
+	movl	PARAM_SRC, %eax
+	movl	PARAM_SIZE, %ecx
+
+	pushl	%esi	FRAME_pushl()
+	pushl	%edi	FRAME_pushl()
+
+	leal	-4(%eax,%ecx,4), %eax		C &src[size-1]
+	movl	PARAM_DST, %edx
+
+	subl	$7, %ecx			C size-7
+	jle	L(end)
+
+	movl	28-4(%edx,%ecx,4), %esi		C prefetch cache, dst[size-1]
+	nop
+
+L(top):
+	C eax	src, decrementing
+	C ebx
+	C ecx	counter, limbs
+	C edx	dst
+	C esi	scratch
+	C edi	scratch
+	C ebp
+
+	movl	28-32(%edx,%ecx,4), %esi	C prefetch dst cache line
+	subl	$8, %ecx
+
+	movl	(%eax), %esi			C read words pairwise
+	movl	-4(%eax), %edi
+	movl	%esi, 56(%edx,%ecx,4)		C store words pairwise
+	movl	%edi, 52(%edx,%ecx,4)
+
+	movl	-8(%eax), %esi
+	movl	-12(%eax), %edi
+	movl	%esi, 48(%edx,%ecx,4)
+	movl	%edi, 44(%edx,%ecx,4)
+
+	movl	-16(%eax), %esi
+	movl	-20(%eax), %edi
+	movl	%esi, 40(%edx,%ecx,4)
+	movl	%edi, 36(%edx,%ecx,4)
+
+	movl	-24(%eax), %esi
+	movl	-28(%eax), %edi
+	movl	%esi, 32(%edx,%ecx,4)
+	movl	%edi, 28(%edx,%ecx,4)
+
+	leal	-32(%eax), %eax
+	jg	L(top)
+
+
+L(end):
+	C ecx	-7 to 0, representing respectively 0 to 7 limbs remaining
+	C eax	src end
+	C edx	dst, next location to store
+
+	addl	$4, %ecx
+	jle	L(no4)
+
+	movl	(%eax), %esi
+	movl	-4(%eax), %edi
+	movl	%esi, 8(%edx,%ecx,4)
+	movl	%edi, 4(%edx,%ecx,4)
+
+	movl	-8(%eax), %esi
+	movl	-12(%eax), %edi
+	movl	%esi, (%edx,%ecx,4)
+	movl	%edi, -4(%edx,%ecx,4)
+
+	subl	$16, %eax
+	subl	$4, %ecx
+L(no4):
+
+	addl	$2, %ecx
+	jle	L(no2)
+
+	movl	(%eax), %esi
+	movl	-4(%eax), %edi
+	movl	%esi, (%edx,%ecx,4)
+	movl	%edi, -4(%edx,%ecx,4)
+
+	subl	$8, %eax
+	subl	$2, %ecx
+L(no2):
+
+	jnz	L(done)
+
+	movl	(%eax), %ecx
+	movl	%ecx, (%edx)	C risk of cache bank clash here
+
+L(done):
+	popl	%edi
+	popl	%esi
+
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/pentium/copyi.asm b/third_party/gmp/mpn/x86/pentium/copyi.asm
new file mode 100644
index 0000000..d983d6b
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium/copyi.asm
@@ -0,0 +1,164 @@
+dnl  Intel Pentium mpn_copyi -- copy limb vector, incrementing.
+
+dnl  Copyright 1996, 2001, 2002, 2006 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C P5: 1.25 cycles/limb
+
+
+C void mpn_copyi (mp_ptr dst, mp_srcptr src, mp_size_t size);
+C
+C Destination prefetching is done to avoid repeated write-throughs on lines
+C not already in L1.
+C
+C At least one of the src or dst pointer needs to be incremented rather than
+C using indexing, so that there's somewhere to put the loop control without
+C an AGI.  Incrementing one and not two lets us keep loop overhead to 2
+C cycles.  Making it the src pointer incremented avoids an AGI on the %ecx
+C subtracts in the finishup code.
+C
+C The block of finishup code is almost as big as the main loop itself, which
+C is unfortunate, but it's faster that way than with say rep movsl, by about
+C 10 cycles for instance on P55.
+C
+C There's nothing to be gained from MMX on P55, since it can do only one
+C movq load (or store) per cycle, so the throughput would be the same as the
+C code here (and even then only if src and dst have the same alignment mod
+C 8).
+
+defframe(PARAM_SIZE,12)
+defframe(PARAM_SRC, 8)
+defframe(PARAM_DST, 4)
+
+	TEXT
+	ALIGN(8)
+PROLOGUE(mpn_copyi)
+deflit(`FRAME',0)
+
+	movl	PARAM_SIZE, %ecx
+	movl	PARAM_DST, %edx
+
+	pushl	%ebx	FRAME_pushl()
+	pushl	%esi	FRAME_pushl()
+
+	leal	(%edx,%ecx,4), %edx	C &dst[size-1]
+	xorl	$-1, %ecx		C -size-1
+
+	movl	PARAM_SRC, %esi
+	addl	$8, %ecx		C -size+7
+
+	jns	L(end)
+
+	movl	-28(%edx,%ecx,4), %eax	C fetch destination cache line, dst[0]
+	nop
+
+L(top):
+	C eax	scratch
+	C ebx	scratch
+	C ecx	counter, limbs, negative
+	C edx	&dst[size-1]
+	C esi	src, incrementing
+	C edi
+	C ebp
+
+	movl	(%edx,%ecx,4), %eax	C fetch destination cache line
+	addl	$8, %ecx
+
+	movl	(%esi), %eax		C read words pairwise
+	movl	4(%esi), %ebx
+	movl	%eax, -60(%edx,%ecx,4)	C store words pairwise
+	movl	%ebx, -56(%edx,%ecx,4)
+
+	movl	8(%esi), %eax
+	movl	12(%esi), %ebx
+	movl	%eax, -52(%edx,%ecx,4)
+	movl	%ebx, -48(%edx,%ecx,4)
+
+	movl	16(%esi), %eax
+	movl	20(%esi), %ebx
+	movl	%eax, -44(%edx,%ecx,4)
+	movl	%ebx, -40(%edx,%ecx,4)
+
+	movl	24(%esi), %eax
+	movl	28(%esi), %ebx
+	movl	%eax, -36(%edx,%ecx,4)
+	movl	%ebx, -32(%edx,%ecx,4)
+
+	leal	32(%esi), %esi
+	js	L(top)
+
+
+L(end):
+	C ecx	0 to 7, representing respectively 7 to 0 limbs remaining
+	C esi	src end
+	C edx	dst, next location to store
+
+	subl	$4, %ecx
+	jns	L(no4)
+
+	movl	(%esi), %eax
+	movl	4(%esi), %ebx
+	movl	%eax, -12(%edx,%ecx,4)
+	movl	%ebx, -8(%edx,%ecx,4)
+
+	movl	8(%esi), %eax
+	movl	12(%esi), %ebx
+	movl	%eax, -4(%edx,%ecx,4)
+	movl	%ebx, (%edx,%ecx,4)
+
+	addl	$16, %esi
+	addl	$4, %ecx
+L(no4):
+
+	subl	$2, %ecx
+	jns	L(no2)
+
+	movl	(%esi), %eax
+	movl	4(%esi), %ebx
+	movl	%eax, -4(%edx,%ecx,4)
+	movl	%ebx, (%edx,%ecx,4)
+
+	addl	$8, %esi
+	addl	$2, %ecx
+L(no2):
+
+	jnz	L(done)
+
+	movl	(%esi), %eax
+	movl	%eax, -4(%edx,%ecx,4)	C risk of cache bank clash here
+
+L(done):
+	popl	%esi
+	popl	%ebx
+
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/pentium/dive_1.asm b/third_party/gmp/mpn/x86/pentium/dive_1.asm
new file mode 100644
index 0000000..21b5287
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium/dive_1.asm
@@ -0,0 +1,264 @@
+dnl  Intel Pentium mpn_divexact_1 -- mpn by limb exact division.
+
+dnl  Copyright 2001, 2002, 2014 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C         divisor
+C       odd   even
+C P54:  24.5  30.5   cycles/limb
+C P55:  23.0  28.0
+
+
+C void mpn_divexact_1 (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                      mp_limb_t divisor);
+C
+C Plain divl is used for small sizes, since the inverse takes a while to
+C setup.  Multiplying works out faster for size>=3 when the divisor is odd,
+C or size>=4 when the divisor is even.  Actually on P55 size==2 for odd or
+C size==3 for even are about the same speed for both divl or mul, but the
+C former is used since it will use up less code cache.
+C
+C The P55 speeds noted above, 23 cycles odd or 28 cycles even, are as
+C expected.  On P54 in the even case the shrdl pairing nonsense (see
+C mpn/x86/pentium/README) costs 1 cycle, but it's not clear why there's a
+C further 1.5 slowdown for both odd and even.
+
+defframe(PARAM_DIVISOR,16)
+defframe(PARAM_SIZE,   12)
+defframe(PARAM_SRC,    8)
+defframe(PARAM_DST,    4)
+
+dnl  re-use parameter space
+define(VAR_INVERSE,`PARAM_DST')
+
+	TEXT
+
+	ALIGN(32)
+PROLOGUE(mpn_divexact_1)
+deflit(`FRAME',0)
+
+	movl	PARAM_DIVISOR, %eax
+	movl	PARAM_SIZE, %ecx
+
+	pushl	%esi		FRAME_pushl()
+	push	%edi		FRAME_pushl()
+
+	movl	PARAM_SRC, %esi
+	andl	$1, %eax
+
+	movl	PARAM_DST, %edi
+	addl	%ecx, %eax	C size if even, size+1 if odd
+
+	cmpl	$4, %eax
+	jae	L(mul_by_inverse)
+
+
+	xorl	%edx, %edx
+L(div_top):
+	movl	-4(%esi,%ecx,4), %eax
+
+	divl	PARAM_DIVISOR
+
+	movl	%eax, -4(%edi,%ecx,4)
+	decl	%ecx
+
+	jnz	L(div_top)
+
+	popl	%edi
+	popl	%esi
+
+	ret
+
+
+
+L(mul_by_inverse):
+	movl	PARAM_DIVISOR, %eax
+	movl	$-1, %ecx
+
+L(strip_twos):
+	ASSERT(nz, `orl %eax, %eax')
+	shrl	%eax
+	incl	%ecx			C shift count
+
+	jnc	L(strip_twos)
+
+	leal	1(%eax,%eax), %edx	C d
+	andl	$127, %eax		C d/2, 7 bits
+
+	pushl	%ebx		FRAME_pushl()
+	pushl	%ebp		FRAME_pushl()
+
+ifdef(`PIC',`dnl
+	LEA(	binvert_limb_table, %ebp)
+	movzbl	(%eax,%ebp), %eax		C inv 8 bits
+',`
+	movzbl	binvert_limb_table(%eax), %eax	C inv 8 bits
+')
+
+	movl	%eax, %ebp		C inv
+	addl	%eax, %eax		C 2*inv
+
+	imull	%ebp, %ebp		C inv*inv
+
+	imull	%edx, %ebp		C inv*inv*d
+
+	subl	%ebp, %eax		C inv = 2*inv - inv*inv*d
+	movl	PARAM_SIZE, %ebx
+
+	movl	%eax, %ebp
+	addl	%eax, %eax		C 2*inv
+
+	imull	%ebp, %ebp		C inv*inv
+
+	imull	%edx, %ebp		C inv*inv*d
+
+	subl	%ebp, %eax		C inv = 2*inv - inv*inv*d
+	movl	%edx, PARAM_DIVISOR	C d without twos
+
+	leal	(%esi,%ebx,4), %esi	C src end
+	leal	(%edi,%ebx,4), %edi	C dst end
+
+	negl	%ebx			C -size
+
+	ASSERT(e,`	C expect d*inv == 1 mod 2^GMP_LIMB_BITS
+	pushl	%eax	FRAME_pushl()
+	imull	PARAM_DIVISOR, %eax
+	cmpl	$1, %eax
+	popl	%eax	FRAME_popl()')
+
+	movl	%eax, VAR_INVERSE
+	xorl	%ebp, %ebp		C initial carry bit
+
+	movl	(%esi,%ebx,4), %eax	C src low limb
+	orl	%ecx, %ecx		C shift
+
+	movl	4(%esi,%ebx,4), %edx	C src second limb (for even)
+	jz	L(odd_entry)
+
+	shrdl(	%cl, %edx, %eax)
+
+	incl	%ebx
+	jmp	L(even_entry)
+
+
+	ALIGN(8)
+L(odd_top):
+	C eax	scratch
+	C ebx	counter, limbs, negative
+	C ecx
+	C edx
+	C esi	src end
+	C edi	dst end
+	C ebp	carry bit, 0 or -1
+
+	mull	PARAM_DIVISOR
+
+	movl	(%esi,%ebx,4), %eax
+	subl	%ebp, %edx
+
+	subl	%edx, %eax
+
+	sbbl	%ebp, %ebp
+
+L(odd_entry):
+	imull	VAR_INVERSE, %eax
+
+	movl	%eax, (%edi,%ebx,4)
+
+	incl	%ebx
+	jnz	L(odd_top)
+
+
+	popl	%ebp
+	popl	%ebx
+
+	popl	%edi
+	popl	%esi
+
+	ret
+
+
+L(even_top):
+	C eax	scratch
+	C ebx	counter, limbs, negative
+	C ecx	twos
+	C edx
+	C esi	src end
+	C edi	dst end
+	C ebp	carry bit, 0 or -1
+
+	mull	PARAM_DIVISOR
+
+	subl	%ebp, %edx		C carry bit
+	movl	-4(%esi,%ebx,4), %eax	C src limb
+
+	movl	(%esi,%ebx,4), %ebp	C and one above it
+
+	shrdl(	%cl, %ebp, %eax)
+
+	subl	%edx, %eax		C carry limb
+
+	sbbl	%ebp, %ebp
+
+L(even_entry):
+	imull	VAR_INVERSE, %eax
+
+	movl	%eax, -4(%edi,%ebx,4)
+	incl	%ebx
+
+	jnz	L(even_top)
+
+
+
+	mull	PARAM_DIVISOR
+
+	movl	-4(%esi), %eax		C src high limb
+	subl	%ebp, %edx
+
+	shrl	%cl, %eax
+
+	subl	%edx, %eax		C no carry if division is exact
+
+	imull	VAR_INVERSE, %eax
+
+	movl	%eax, -4(%edi)		C dst high limb
+	nop				C protect against cache bank clash
+
+	popl	%ebp
+	popl	%ebx
+
+	popl	%edi
+	popl	%esi
+
+	ret
+
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86/pentium/gmp-mparam.h b/third_party/gmp/mpn/x86/pentium/gmp-mparam.h
new file mode 100644
index 0000000..befa6e2
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium/gmp-mparam.h
@@ -0,0 +1,76 @@
+/* Intel P54 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 1999-2002, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+
+/* For mpn/x86/pentium/mod_1.asm */
+#define COUNT_LEADING_ZEROS_NEED_CLZ_TAB
+
+
+/* 166MHz P54 */
+
+/* Generated by tuneup.c, 2004-02-10, gcc 2.95 */
+
+#define MUL_TOOM22_THRESHOLD             16
+#define MUL_TOOM33_THRESHOLD             90
+
+#define SQR_BASECASE_THRESHOLD            0  /* always */
+#define SQR_TOOM2_THRESHOLD              22
+#define SQR_TOOM3_THRESHOLD             122
+
+#define DIV_SB_PREINV_THRESHOLD       MP_SIZE_T_MAX  /* never */
+#define DIV_DC_THRESHOLD                 52
+#define POWM_THRESHOLD                   77
+
+#define HGCD_THRESHOLD                  121
+#define GCD_ACCEL_THRESHOLD               3
+#define GCD_DC_THRESHOLD                615
+#define JACOBI_BASE_METHOD                2
+
+#define USE_PREINV_DIVREM_1               0
+#define USE_PREINV_MOD_1                  1  /* native */
+#define DIVREM_2_THRESHOLD            MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD              0  /* always (native) */
+#define MODEXACT_1_ODD_THRESHOLD          0  /* always (native) */
+
+#define GET_STR_DC_THRESHOLD             23
+#define GET_STR_PRECOMPUTE_THRESHOLD     33
+#define SET_STR_THRESHOLD              2788
+
+#define MUL_FFT_TABLE  { 432, 928, 1664, 3584, 10240, 40960, 0 }
+#define MUL_FFT_MODF_THRESHOLD          448
+#define MUL_FFT_THRESHOLD              3328
+
+#define SQR_FFT_TABLE  { 496, 928, 1920, 4608, 10240, 40960, 0 }
+#define SQR_FFT_MODF_THRESHOLD          512
+#define SQR_FFT_THRESHOLD              3328
diff --git a/third_party/gmp/mpn/x86/pentium/hamdist.asm b/third_party/gmp/mpn/x86/pentium/hamdist.asm
new file mode 100644
index 0000000..6c6c1a1
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium/hamdist.asm
@@ -0,0 +1,154 @@
+dnl  Intel P5 mpn_hamdist -- mpn hamming distance.
+
+dnl  Copyright 2001, 2002, 2014, 2015 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C P5: 14.0 cycles/limb
+
+
+C unsigned long mpn_hamdist (mp_srcptr src1, mp_srcptr src2, mp_size_t size);
+C
+C It might be possible to shave 1 cycle from the loop, and hence 2
+C cycles/limb.  The xorb is taking 2 cycles, but a separate load and xor
+C would be 1, if the right schedule could be found (not found so far).
+C Wanting to avoid potential cache bank clashes makes it tricky.
+
+C The slightly strange quoting here helps the renaming done by tune/many.pl.
+deflit(TABLE_NAME,
+m4_assert_defined(`GSYM_PREFIX')
+GSYM_PREFIX`'mpn_popcount``'_table')
+
+C FIXME: referencing popcount.asm's table is incorrect as it hurt incremental
+C linking.
+
+defframe(PARAM_SIZE,12)
+defframe(PARAM_SRC2, 8)
+defframe(PARAM_SRC1, 4)
+
+	TEXT
+	ALIGN(8)
+
+PROLOGUE(mpn_hamdist)
+deflit(`FRAME',0)
+
+	movl	PARAM_SIZE, %ecx
+	pushl	%esi	FRAME_pushl()
+
+	shll	%ecx		C size in byte pairs
+	pushl	%edi	FRAME_pushl()
+
+ifdef(`PIC',`
+	pushl	%ebx	FRAME_pushl()
+	pushl	%ebp	FRAME_pushl()
+ifdef(`DARWIN',`
+	movl	PARAM_SRC1, %esi
+	movl	PARAM_SRC2, %edi
+	LEA(	TABLE_NAME, %ebp)
+	xorl	%ebx, %ebx	C byte
+	xorl	%edx, %edx	C byte
+	xorl	%eax, %eax	C total
+',`
+	call	L(here)	FRAME_pushl()
+L(here):
+	movl	PARAM_SRC1, %esi
+	popl	%ebp	FRAME_popl()
+
+	movl	PARAM_SRC2, %edi
+	addl	$_GLOBAL_OFFSET_TABLE_+[.-L(here)], %ebp
+
+	xorl	%ebx, %ebx	C byte
+	xorl	%edx, %edx	C byte
+
+	movl	TABLE_NAME@GOT(%ebp), %ebp
+	xorl	%eax, %eax	C total
+')
+define(TABLE,`(%ebp,$1)')
+',`
+dnl non-PIC
+	movl	PARAM_SRC1, %esi
+	movl	PARAM_SRC2, %edi
+
+	xorl	%eax, %eax	C total
+	pushl	%ebx	FRAME_pushl()
+
+	xorl	%edx, %edx	C byte
+	xorl	%ebx, %ebx	C byte
+
+define(TABLE,`TABLE_NAME($1)')
+')
+
+
+	C The nop after the xorb seems necessary.  Although a movb might be
+	C expected to go down the V pipe in the second cycle of the xorb, it
+	C doesn't and costs an extra 2 cycles.
+L(top):
+	C eax	total
+	C ebx	byte
+	C ecx	counter, 2*size to 2
+	C edx	byte
+	C esi	src1
+	C edi	src2
+	C ebp	[PIC] table
+
+	addl	%ebx, %eax
+	movb	-1(%esi,%ecx,2), %bl
+
+	addl	%edx, %eax
+	movb	-1(%edi,%ecx,2), %dl
+
+	xorb	%dl, %bl
+	movb	-2(%esi,%ecx,2), %dl
+
+	xorb	-2(%edi,%ecx,2), %dl
+	nop
+
+	movb	TABLE(%ebx), %bl
+	decl	%ecx
+
+	movb	TABLE(%edx), %dl
+	jnz	L(top)
+
+
+ifdef(`PIC',`
+	popl	%ebp
+')
+	addl	%ebx, %eax
+	popl	%ebx
+
+	addl	%edx, %eax
+	popl	%edi
+
+	popl	%esi
+
+	ret
+
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86/pentium/logops_n.asm b/third_party/gmp/mpn/x86/pentium/logops_n.asm
new file mode 100644
index 0000000..1877317
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium/logops_n.asm
@@ -0,0 +1,176 @@
+dnl  Intel Pentium mpn_and_n,...,mpn_xnor_n -- bitwise logical operations.
+
+dnl  Copyright 2001, 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C P5: 3.0 c/l  and, ior, xor
+C     3.5 c/l  andn, iorn, nand, nior, xnor
+
+
+define(M4_choose_op,
+`ifdef(`OPERATION_$1',`
+define(`M4_function', `mpn_$1')
+define(`M4_want_pre', `$4')
+define(`M4op',        `$3')
+define(`M4_want_post',`$2')
+')')
+define(M4pre, `ifelse(M4_want_pre, yes,`$1')')
+define(M4post,`ifelse(M4_want_post,yes,`$1')')
+
+M4_choose_op( and_n,     , andl,    )
+M4_choose_op( andn_n,    , andl, yes)
+M4_choose_op( nand_n, yes, andl,    )
+M4_choose_op( ior_n,     ,  orl,    )
+M4_choose_op( iorn_n,    ,  orl, yes)
+M4_choose_op( nior_n, yes,  orl,    )
+M4_choose_op( xor_n,     , xorl,    )
+M4_choose_op( xnor_n, yes, xorl,    )
+
+ifdef(`M4_function',,
+`m4_error(`Unrecognised or undefined OPERATION symbol
+')')
+
+MULFUNC_PROLOGUE(mpn_and_n mpn_andn_n mpn_nand_n mpn_ior_n mpn_iorn_n mpn_nior_n mpn_xor_n mpn_xnor_n)
+
+NAILS_SUPPORT(0-31)
+
+
+C void M4_function (mp_ptr wp, mp_srcptr xp, mp_srcptr yp, mp_size_t size);
+C
+C Nothing complicated here, just some care to avoid data cache bank clashes
+C and AGIs.
+C
+C We're one register short of being able to do a simple 4 loads, 2 ops, 2
+C stores.  Instead %ebp is juggled a bit and nops are introduced to keep the
+C pairings as intended.  An in-place operation would free up a register, for
+C an 0.5 c/l speedup, if that's worth bothering with.
+C
+C This code seems best for P55 too.  Data alignment is a big problem for MMX
+C and the pairing restrictions on movq and integer instructions make life
+C difficult.
+
+defframe(PARAM_SIZE,16)
+defframe(PARAM_YP,  12)
+defframe(PARAM_XP,   8)
+defframe(PARAM_WP,   4)
+
+	TEXT
+	ALIGN(8)
+
+PROLOGUE(M4_function)
+deflit(`FRAME',0)
+
+	pushl	%ebx	FRAME_pushl()
+	pushl	%esi	FRAME_pushl()
+
+	pushl	%edi	FRAME_pushl()
+	pushl	%ebp	FRAME_pushl()
+
+	movl	PARAM_SIZE, %ecx
+	movl	PARAM_XP, %ebx
+
+	movl	PARAM_YP, %esi
+	movl	PARAM_WP, %edi
+
+	shrl	%ecx
+	jnc	L(entry)
+
+	movl	(%ebx,%ecx,8), %eax	C risk of data cache bank clash here
+	movl	(%esi,%ecx,8), %edx
+
+M4pre(`	notl_or_xorl_GMP_NUMB_MASK(%edx)')
+
+	M4op	%edx, %eax
+
+M4post(`xorl	$GMP_NUMB_MASK, %eax')
+	orl	%ecx, %ecx
+
+	movl	%eax, (%edi,%ecx,8)
+	jz	L(done)
+
+	jmp	L(entry)
+
+
+L(top):
+	C eax
+	C ebx	xp
+	C ecx	counter, limb pairs, decrementing
+	C edx
+	C esi	yp
+	C edi	wp
+	C ebp
+
+	M4op	%ebp, %edx
+	nop
+
+M4post(`xorl	$GMP_NUMB_MASK, %eax')
+M4post(`xorl	$GMP_NUMB_MASK, %edx')
+
+	movl	%eax, 4(%edi,%ecx,8)
+	movl	%edx, (%edi,%ecx,8)
+
+L(entry):
+	movl	-4(%ebx,%ecx,8), %ebp
+	nop
+
+	movl	-4(%esi,%ecx,8), %eax
+	movl	-8(%esi,%ecx,8), %edx
+
+M4pre(`	xorl	$GMP_NUMB_MASK, %eax')
+M4pre(`	xorl	$GMP_NUMB_MASK, %edx')
+
+	M4op	%ebp, %eax
+	movl	-8(%ebx,%ecx,8), %ebp
+
+	decl	%ecx
+	jnz	L(top)
+
+
+	M4op	%ebp, %edx
+	nop
+
+M4post(`xorl	$GMP_NUMB_MASK, %eax')
+M4post(`xorl	$GMP_NUMB_MASK, %edx')
+
+	movl	%eax, 4(%edi,%ecx,8)
+	movl	%edx, (%edi,%ecx,8)
+
+
+L(done):
+	popl	%ebp
+	popl	%edi
+
+	popl	%esi
+	popl	%ebx
+
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/pentium/lshift.asm b/third_party/gmp/mpn/x86/pentium/lshift.asm
new file mode 100644
index 0000000..2a31f36
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium/lshift.asm
@@ -0,0 +1,243 @@
+dnl  Intel Pentium mpn_lshift -- mpn left shift.
+
+dnl  Copyright 1992, 1994-1996, 1999, 2000, 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C         cycles/limb
+C P5,P54:    6.0
+C P55:       5.375
+
+
+C mp_limb_t mpn_lshift (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                       unsigned shift);
+C
+C The main shift-by-N loop should run at 5.375 c/l and that's what P55 does,
+C but P5 and P54 run only at 6.0 c/l, which is 4 cycles lost somewhere.
+
+defframe(PARAM_SHIFT,16)
+defframe(PARAM_SIZE, 12)
+defframe(PARAM_SRC,  8)
+defframe(PARAM_DST,  4)
+
+	TEXT
+	ALIGN(8)
+PROLOGUE(mpn_lshift)
+
+	pushl	%edi
+	pushl	%esi
+	pushl	%ebx
+	pushl	%ebp
+deflit(`FRAME',16)
+
+	movl	PARAM_DST,%edi
+	movl	PARAM_SRC,%esi
+	movl	PARAM_SIZE,%ebp
+	movl	PARAM_SHIFT,%ecx
+
+C We can use faster code for shift-by-1 under certain conditions.
+	cmp	$1,%ecx
+	jne	L(normal)
+	leal	4(%esi),%eax
+	cmpl	%edi,%eax
+	jnc	L(special)		C jump if s_ptr + 1 >= res_ptr
+	leal	(%esi,%ebp,4),%eax
+	cmpl	%eax,%edi
+	jnc	L(special)		C jump if res_ptr >= s_ptr + size
+
+L(normal):
+	leal	-4(%edi,%ebp,4),%edi
+	leal	-4(%esi,%ebp,4),%esi
+
+	movl	(%esi),%edx
+	subl	$4,%esi
+	xorl	%eax,%eax
+	shldl(	%cl, %edx, %eax)	C compute carry limb
+	pushl	%eax			C push carry limb onto stack
+
+	decl	%ebp
+	pushl	%ebp
+	shrl	$3,%ebp
+	jz	L(end)
+
+	movl	(%edi),%eax		C fetch destination cache line
+
+	ALIGN(4)
+L(oop):	movl	-28(%edi),%eax		C fetch destination cache line
+	movl	%edx,%ebx
+
+	movl	(%esi),%eax
+	movl	-4(%esi),%edx
+	shldl(	%cl, %eax, %ebx)
+	shldl(	%cl, %edx, %eax)
+	movl	%ebx,(%edi)
+	movl	%eax,-4(%edi)
+
+	movl	-8(%esi),%ebx
+	movl	-12(%esi),%eax
+	shldl(	%cl, %ebx, %edx)
+	shldl(	%cl, %eax, %ebx)
+	movl	%edx,-8(%edi)
+	movl	%ebx,-12(%edi)
+
+	movl	-16(%esi),%edx
+	movl	-20(%esi),%ebx
+	shldl(	%cl, %edx, %eax)
+	shldl(	%cl, %ebx, %edx)
+	movl	%eax,-16(%edi)
+	movl	%edx,-20(%edi)
+
+	movl	-24(%esi),%eax
+	movl	-28(%esi),%edx
+	shldl(	%cl, %eax, %ebx)
+	shldl(	%cl, %edx, %eax)
+	movl	%ebx,-24(%edi)
+	movl	%eax,-28(%edi)
+
+	subl	$32,%esi
+	subl	$32,%edi
+	decl	%ebp
+	jnz	L(oop)
+
+L(end):	popl	%ebp
+	andl	$7,%ebp
+	jz	L(end2)
+L(oop2):
+	movl	(%esi),%eax
+	shldl(	%cl,%eax,%edx)
+	movl	%edx,(%edi)
+	movl	%eax,%edx
+	subl	$4,%esi
+	subl	$4,%edi
+	decl	%ebp
+	jnz	L(oop2)
+
+L(end2):
+	shll	%cl,%edx		C compute least significant limb
+	movl	%edx,(%edi)		C store it
+
+	popl	%eax			C pop carry limb
+
+	popl	%ebp
+	popl	%ebx
+	popl	%esi
+	popl	%edi
+	ret
+
+
+C We loop from least significant end of the arrays, which is only
+C permissable if the source and destination don't overlap, since the
+C function is documented to work for overlapping source and destination.
+
+L(special):
+	movl	(%esi),%edx
+	addl	$4,%esi
+
+	decl	%ebp
+	pushl	%ebp
+	shrl	$3,%ebp
+
+	addl	%edx,%edx
+	incl	%ebp
+	decl	%ebp
+	jz	L(Lend)
+
+	movl	(%edi),%eax		C fetch destination cache line
+
+	ALIGN(4)
+L(Loop):
+	movl	28(%edi),%eax		C fetch destination cache line
+	movl	%edx,%ebx
+
+	movl	(%esi),%eax
+	movl	4(%esi),%edx
+	adcl	%eax,%eax
+	movl	%ebx,(%edi)
+	adcl	%edx,%edx
+	movl	%eax,4(%edi)
+
+	movl	8(%esi),%ebx
+	movl	12(%esi),%eax
+	adcl	%ebx,%ebx
+	movl	%edx,8(%edi)
+	adcl	%eax,%eax
+	movl	%ebx,12(%edi)
+
+	movl	16(%esi),%edx
+	movl	20(%esi),%ebx
+	adcl	%edx,%edx
+	movl	%eax,16(%edi)
+	adcl	%ebx,%ebx
+	movl	%edx,20(%edi)
+
+	movl	24(%esi),%eax
+	movl	28(%esi),%edx
+	adcl	%eax,%eax
+	movl	%ebx,24(%edi)
+	adcl	%edx,%edx
+	movl	%eax,28(%edi)
+
+	leal	32(%esi),%esi		C use leal not to clobber carry
+	leal	32(%edi),%edi
+	decl	%ebp
+	jnz	L(Loop)
+
+L(Lend):
+	popl	%ebp
+	sbbl	%eax,%eax		C save carry in %eax
+	andl	$7,%ebp
+	jz	L(Lend2)
+	addl	%eax,%eax		C restore carry from eax
+L(Loop2):
+	movl	%edx,%ebx
+	movl	(%esi),%edx
+	adcl	%edx,%edx
+	movl	%ebx,(%edi)
+
+	leal	4(%esi),%esi		C use leal not to clobber carry
+	leal	4(%edi),%edi
+	decl	%ebp
+	jnz	L(Loop2)
+
+	jmp	L(L1)
+L(Lend2):
+	addl	%eax,%eax		C restore carry from eax
+L(L1):	movl	%edx,(%edi)		C store last limb
+
+	sbbl	%eax,%eax
+	negl	%eax
+
+	popl	%ebp
+	popl	%ebx
+	popl	%esi
+	popl	%edi
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/pentium/mmx/gmp-mparam.h b/third_party/gmp/mpn/x86/pentium/mmx/gmp-mparam.h
new file mode 100644
index 0000000..02a0def
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium/mmx/gmp-mparam.h
@@ -0,0 +1,163 @@
+/* Intel P55 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 1999-2002, 2004, 2009, 2010 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+
+/* For mpn/x86/pentium/mod_1.asm */
+#define COUNT_LEADING_ZEROS_NEED_CLZ_TAB
+
+
+/* 233MHz P55 */
+
+#define MOD_1_NORM_THRESHOLD                 5
+#define MOD_1_UNNORM_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD      MP_SIZE_T_MAX  /* never */
+#define MOD_1U_TO_MOD_1_1_THRESHOLD         12
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD         0
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        11
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     63
+#define USE_PREINV_DIVREM_1                  0
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           51
+
+#define MUL_TOOM22_THRESHOLD                16
+#define MUL_TOOM33_THRESHOLD                53
+#define MUL_TOOM44_THRESHOLD               128
+#define MUL_TOOM6H_THRESHOLD               189
+#define MUL_TOOM8H_THRESHOLD               260
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      89
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD      91
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD      90
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD      88
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 20
+#define SQR_TOOM3_THRESHOLD                 73
+#define SQR_TOOM4_THRESHOLD                178
+#define SQR_TOOM6_THRESHOLD                210
+#define SQR_TOOM8_THRESHOLD                375
+
+#define MULMOD_BNM1_THRESHOLD               11
+#define SQRMOD_BNM1_THRESHOLD               12
+
+#define MUL_FFT_MODF_THRESHOLD             364  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    364, 5}, {     15, 6}, {      8, 5}, {     17, 6}, \
+    {      9, 5}, {     19, 6}, {     17, 7}, {      9, 6}, \
+    {     21, 7}, {     11, 6}, {     23, 7}, {     15, 6}, \
+    {     31, 7}, {     21, 8}, {     11, 7}, {     27, 8}, \
+    {     15, 7}, {     33, 8}, {     19, 7}, {     39, 8}, \
+    {     23, 7}, {     47, 8}, {     27, 9}, {     15, 8}, \
+    {     31, 7}, {     63, 8}, {     39, 9}, {     23, 8}, \
+    {     47,10}, {     15, 9}, {     31, 8}, {     67, 9}, \
+    {     39, 8}, {     79, 9}, {     47, 8}, {     95, 9}, \
+    {     55,10}, {     31, 9}, {     79,10}, {     47, 9}, \
+    {     95,11}, {     31,10}, {     63, 9}, {    135,10}, \
+    {     79, 9}, {    159, 8}, {    319, 9}, {    167,10}, \
+    {     95, 9}, {    191, 8}, {    383,11}, {     63,10}, \
+    {    127, 9}, {    255,10}, {    143, 9}, {    287,10}, \
+    {    159, 9}, {    319,11}, {     95,10}, {    191, 9}, \
+    {    383,12}, {     63,11}, {    127,10}, {    271, 9}, \
+    {    543,10}, {    287,11}, {    159,10}, {    351,11}, \
+    {    191,10}, {    415,11}, {    223,12}, {    127,11}, \
+    {    255,10}, {    511,11}, {    287,10}, {    575,11}, \
+    {    351,12}, {    191,11}, {    415,13}, {    127,12}, \
+    {    255,11}, {    575,12}, {    319,11}, {    703,12}, \
+    {    383,11}, {    831,12}, {    447,13}, {   8192,14}, \
+    {  16384,15}, {  32768,16} }
+#define MUL_FFT_TABLE3_SIZE 90
+#define MUL_FFT_THRESHOLD                 3520
+
+#define SQR_FFT_MODF_THRESHOLD             340  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    340, 5}, {     17, 6}, {      9, 5}, {     19, 6}, \
+    {     17, 7}, {      9, 6}, {     21, 7}, {     11, 6}, \
+    {     23, 7}, {     15, 6}, {     31, 7}, {     21, 8}, \
+    {     11, 7}, {     29, 8}, {     15, 7}, {     33, 8}, \
+    {     19, 7}, {     39, 8}, {     27, 7}, {     55, 9}, \
+    {     15, 8}, {     31, 7}, {     65, 8}, {     43, 9}, \
+    {     23, 8}, {     47,10}, {     15, 9}, {     31, 8}, \
+    {     67, 9}, {     39, 8}, {     83, 9}, {     47, 8}, \
+    {     95,10}, {     31, 9}, {     63, 8}, {    127, 9}, \
+    {     79,10}, {     47, 9}, {     95,11}, {     31,10}, \
+    {     63, 9}, {    127, 8}, {    255, 9}, {    135,10}, \
+    {     79, 9}, {    159, 8}, {    319,10}, {     95, 9}, \
+    {    191,11}, {     63,10}, {    127, 9}, {    255, 8}, \
+    {    511, 9}, {    271,10}, {    143, 9}, {    287, 8}, \
+    {    575, 9}, {    303,10}, {    159, 9}, {    319,11}, \
+    {     95,10}, {    191, 9}, {    383,10}, {    207,12}, \
+    {     63,11}, {    127,10}, {    271, 9}, {    543,10}, \
+    {    287, 9}, {    575,10}, {    303,11}, {    159,10}, \
+    {    351,11}, {    191,10}, {    415,11}, {    223,10}, \
+    {    447,12}, {    127,11}, {    255,10}, {    543,11}, \
+    {    287,10}, {    607,11}, {    351,12}, {    191,11}, \
+    {    479,13}, {    127,12}, {    255,11}, {    575,12}, \
+    {    319,11}, {    703,12}, {    383,11}, {    767,12}, \
+    {    447,13}, {   8192,14}, {  16384,15}, {  32768,16} }
+#define SQR_FFT_TABLE3_SIZE 96
+#define SQR_FFT_THRESHOLD                 5504
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  48
+#define MULLO_MUL_N_THRESHOLD             6633
+
+#define DC_DIV_QR_THRESHOLD                 43
+#define DC_DIVAPPR_Q_THRESHOLD             170
+#define DC_BDIV_QR_THRESHOLD                43
+#define DC_BDIV_Q_THRESHOLD                110
+
+#define INV_MULMOD_BNM1_THRESHOLD           30
+#define INV_NEWTON_THRESHOLD               177
+#define INV_APPR_THRESHOLD                 171
+
+#define BINV_NEWTON_THRESHOLD              194
+#define REDC_1_TO_REDC_N_THRESHOLD          50
+
+#define MU_DIV_QR_THRESHOLD               1142
+#define MU_DIVAPPR_Q_THRESHOLD            1142
+#define MUPI_DIV_QR_THRESHOLD               90
+#define MU_BDIV_QR_THRESHOLD               942
+#define MU_BDIV_Q_THRESHOLD               1017
+
+#define MATRIX22_STRASSEN_THRESHOLD         13
+#define HGCD_THRESHOLD                      92
+#define GCD_DC_THRESHOLD                   283
+#define GCDEXT_DC_THRESHOLD                221
+#define JACOBI_BASE_METHOD                   2
+
+#define GET_STR_DC_THRESHOLD                18
+#define GET_STR_PRECOMPUTE_THRESHOLD        31
+#define SET_STR_DC_THRESHOLD               490
+#define SET_STR_PRECOMPUTE_THRESHOLD       994
diff --git a/third_party/gmp/mpn/x86/pentium/mmx/hamdist.asm b/third_party/gmp/mpn/x86/pentium/mmx/hamdist.asm
new file mode 100644
index 0000000..72e3196
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium/mmx/hamdist.asm
@@ -0,0 +1,40 @@
+dnl  Intel P55 mpn_hamdist -- mpn hamming distance.
+
+dnl  Copyright 2000, 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C P55: hamdist 12.0 cycles/limb
+
+C For reference, this code runs at 11.5 cycles/limb for popcount, which is
+C slower than the plain integer mpn/x86/pentium/popcount.asm.
+
+MULFUNC_PROLOGUE(mpn_hamdist)
+include_mpn(`x86/k6/mmx/popham.asm')
diff --git a/third_party/gmp/mpn/x86/pentium/mmx/lshift.asm b/third_party/gmp/mpn/x86/pentium/mmx/lshift.asm
new file mode 100644
index 0000000..04b0ddc
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium/mmx/lshift.asm
@@ -0,0 +1,463 @@
+dnl  Intel P5 mpn_lshift -- mpn left shift.
+
+dnl  Copyright 2000-2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C P5: 1.75 cycles/limb.
+
+
+C mp_limb_t mpn_lshift (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                       unsigned shift);
+C
+C Shift src,size left by shift many bits and store the result in dst,size.
+C Zeros are shifted in at the right.  Return the bits shifted out at the
+C left.
+C
+C The comments in mpn_rshift apply here too.
+
+defframe(PARAM_SHIFT,16)
+defframe(PARAM_SIZE, 12)
+defframe(PARAM_SRC,  8)
+defframe(PARAM_DST,  4)
+deflit(`FRAME',0)
+
+dnl  minimum 5, because the unrolled loop can't handle less
+deflit(UNROLL_THRESHOLD, 5)
+
+	TEXT
+	ALIGN(8)
+
+PROLOGUE(mpn_lshift)
+
+	pushl	%ebx
+	pushl	%edi
+deflit(`FRAME',8)
+
+	movl	PARAM_SIZE, %eax
+	movl	PARAM_DST, %edx
+
+	movl	PARAM_SRC, %ebx
+	movl	PARAM_SHIFT, %ecx
+
+	cmp	$UNROLL_THRESHOLD, %eax
+	jae	L(unroll)
+
+	movl	-4(%ebx,%eax,4), %edi	C src high limb
+	decl	%eax
+
+	jnz	L(simple)
+
+	shldl(	%cl, %edi, %eax)	C eax was decremented to zero
+
+	shll	%cl, %edi
+
+	movl	%edi, (%edx)		C dst low limb
+	popl	%edi			C risk of data cache bank clash
+
+	popl	%ebx
+
+	ret
+
+
+C -----------------------------------------------------------------------------
+L(simple):
+	C eax	size-1
+	C ebx	src
+	C ecx	shift
+	C edx	dst
+	C esi
+	C edi
+	C ebp
+deflit(`FRAME',8)
+
+	movd	(%ebx,%eax,4), %mm5	C src high limb
+
+	movd	%ecx, %mm6		C lshift
+	negl	%ecx
+
+	psllq	%mm6, %mm5
+	addl	$32, %ecx
+
+	movd	%ecx, %mm7
+	psrlq	$32, %mm5		C retval
+
+
+L(simple_top):
+	C eax	counter, limbs, negative
+	C ebx	src
+	C ecx
+	C edx	dst
+	C esi
+	C edi
+	C
+	C mm0	scratch
+	C mm5	return value
+	C mm6	shift
+	C mm7	32-shift
+
+	movq	-4(%ebx,%eax,4), %mm0
+	decl	%eax
+
+	psrlq	%mm7, %mm0
+
+	C
+
+	movd	%mm0, 4(%edx,%eax,4)
+	jnz	L(simple_top)
+
+
+	movd	(%ebx), %mm0
+
+	movd	%mm5, %eax
+	psllq	%mm6, %mm0
+
+	popl	%edi
+	popl	%ebx
+
+	movd	%mm0, (%edx)
+
+	emms
+
+	ret
+
+
+C -----------------------------------------------------------------------------
+	ALIGN(8)
+L(unroll):
+	C eax	size
+	C ebx	src
+	C ecx	shift
+	C edx	dst
+	C esi
+	C edi
+	C ebp
+deflit(`FRAME',8)
+
+	movd	-4(%ebx,%eax,4), %mm5	C src high limb
+	leal	(%ebx,%eax,4), %edi
+
+	movd	%ecx, %mm6		C lshift
+	andl	$4, %edi
+
+	psllq	%mm6, %mm5
+	jz	L(start_src_aligned)
+
+
+	C src isn't aligned, process high limb separately (marked xxx) to
+	C make it so.
+	C
+	C  source     -8(ebx,%eax,4)
+	C                  |
+	C  +-------+-------+-------+--
+	C  |               |
+	C  +-------+-------+-------+--
+	C        0mod8   4mod8   0mod8
+	C
+	C  dest
+	C     -4(edx,%eax,4)
+	C          |
+	C  +-------+-------+--
+	C  |  xxx  |       |
+	C  +-------+-------+--
+
+	movq	-8(%ebx,%eax,4), %mm0	C unaligned load
+
+	psllq	%mm6, %mm0
+	decl	%eax
+
+	psrlq	$32, %mm0
+
+	C
+
+	movd	%mm0, (%edx,%eax,4)
+L(start_src_aligned):
+
+	movq	-8(%ebx,%eax,4), %mm1	C src high qword
+	leal	(%edx,%eax,4), %edi
+
+	andl	$4, %edi
+	psrlq	$32, %mm5		C return value
+
+	movq	-16(%ebx,%eax,4), %mm3	C src second highest qword
+	jz	L(start_dst_aligned)
+
+	C dst isn't aligned, subtract 4 to make it so, and pretend the shift
+	C is 32 bits extra.  High limb of dst (marked xxx) handled here
+	C separately.
+	C
+	C  source     -8(ebx,%eax,4)
+	C                  |
+	C  +-------+-------+--
+	C  |      mm1      |
+	C  +-------+-------+--
+	C                0mod8   4mod8
+	C
+	C  dest
+	C     -4(edx,%eax,4)
+	C          |
+	C  +-------+-------+-------+--
+	C  |  xxx  |               |
+	C  +-------+-------+-------+--
+	C        0mod8   4mod8   0mod8
+
+	movq	%mm1, %mm0
+	addl	$32, %ecx		C new shift
+
+	psllq	%mm6, %mm0
+
+	movd	%ecx, %mm6
+	psrlq	$32, %mm0
+
+	C wasted cycle here waiting for %mm0
+
+	movd	%mm0, -4(%edx,%eax,4)
+	subl	$4, %edx
+L(start_dst_aligned):
+
+
+	psllq	%mm6, %mm1
+	negl	%ecx			C -shift
+
+	addl	$64, %ecx		C 64-shift
+	movq	%mm3, %mm2
+
+	movd	%ecx, %mm7
+	subl	$8, %eax		C size-8
+
+	psrlq	%mm7, %mm3
+
+	por	%mm1, %mm3		C mm3 ready to store
+	jc	L(finish)
+
+
+	C The comments in mpn_rshift apply here too.
+
+	ALIGN(8)
+L(unroll_loop):
+	C eax	counter, limbs
+	C ebx	src
+	C ecx
+	C edx	dst
+	C esi
+	C edi
+	C
+	C mm0
+	C mm1
+	C mm2	src qword from 16(%ebx,%eax,4)
+	C mm3	dst qword ready to store to 24(%edx,%eax,4)
+	C
+	C mm5	return value
+	C mm6	lshift
+	C mm7	rshift
+
+	movq	8(%ebx,%eax,4), %mm0
+	psllq	%mm6, %mm2
+
+	movq	%mm0, %mm1
+	psrlq	%mm7, %mm0
+
+	movq	%mm3, 24(%edx,%eax,4)	C prev
+	por	%mm2, %mm0
+
+	movq	(%ebx,%eax,4), %mm3	C
+	psllq	%mm6, %mm1		C
+
+	movq	%mm0, 16(%edx,%eax,4)
+	movq	%mm3, %mm2		C
+
+	psrlq	%mm7, %mm3		C
+	subl	$4, %eax
+
+	por	%mm1, %mm3		C
+	jnc	L(unroll_loop)
+
+
+
+L(finish):
+	C eax	-4 to -1 representing respectively 0 to 3 limbs remaining
+
+	testb	$2, %al
+
+	jz	L(finish_no_two)
+
+	movq	8(%ebx,%eax,4), %mm0
+	psllq	%mm6, %mm2
+
+	movq	%mm0, %mm1
+	psrlq	%mm7, %mm0
+
+	movq	%mm3, 24(%edx,%eax,4)	C prev
+	por	%mm2, %mm0
+
+	movq	%mm1, %mm2
+	movq	%mm0, %mm3
+
+	subl	$2, %eax
+L(finish_no_two):
+
+
+	C eax	-4 or -3 representing respectively 0 or 1 limbs remaining
+	C
+	C mm2	src prev qword, from 16(%ebx,%eax,4)
+	C mm3	dst qword, for 24(%edx,%eax,4)
+
+	testb	$1, %al
+	movd	%mm5, %eax	C retval
+
+	popl	%edi
+	jz	L(finish_zero)
+
+
+	C One extra src limb, destination was aligned.
+	C
+	C                 source                  ebx
+	C                 --+---------------+-------+
+	C                   |      mm2      |       |
+	C                 --+---------------+-------+
+	C
+	C dest         edx+12           edx+4     edx
+	C --+---------------+---------------+-------+
+	C   |      mm3      |               |       |
+	C --+---------------+---------------+-------+
+	C
+	C mm6 = shift
+	C mm7 = ecx = 64-shift
+
+
+	C One extra src limb, destination was unaligned.
+	C
+	C                 source                  ebx
+	C                 --+---------------+-------+
+	C                   |      mm2      |       |
+	C                 --+---------------+-------+
+	C
+	C         dest         edx+12           edx+4
+	C         --+---------------+---------------+
+	C           |      mm3      |               |
+	C         --+---------------+---------------+
+	C
+	C mm6 = shift+32
+	C mm7 = ecx = 64-(shift+32)
+
+
+	C In both cases there's one extra limb of src to fetch and combine
+	C with mm2 to make a qword at 4(%edx), and in the aligned case
+	C there's an extra limb of dst to be formed from that extra src limb
+	C left shifted.
+
+
+	movd	(%ebx), %mm0
+	psllq	%mm6, %mm2
+
+	movq	%mm3, 12(%edx)
+	psllq	$32, %mm0
+
+	movq	%mm0, %mm1
+	psrlq	%mm7, %mm0
+
+	por	%mm2, %mm0
+	psllq	%mm6, %mm1
+
+	movq	%mm0, 4(%edx)
+	psrlq	$32, %mm1
+
+	andl	$32, %ecx
+	popl	%ebx
+
+	jz	L(finish_one_unaligned)
+
+	movd	%mm1, (%edx)
+L(finish_one_unaligned):
+
+	emms
+
+	ret
+
+
+L(finish_zero):
+
+	C No extra src limbs, destination was aligned.
+	C
+	C                 source          ebx
+	C                 --+---------------+
+	C                   |      mm2      |
+	C                 --+---------------+
+	C
+	C dest          edx+8             edx
+	C --+---------------+---------------+
+	C   |      mm3      |               |
+	C --+---------------+---------------+
+	C
+	C mm6 = shift
+	C mm7 = ecx = 64-shift
+
+
+	C No extra src limbs, destination was unaligned.
+	C
+	C               source            ebx
+	C                 --+---------------+
+	C                   |      mm2      |
+	C                 --+---------------+
+	C
+	C         dest          edx+8   edx+4
+	C         --+---------------+-------+
+	C           |      mm3      |       |
+	C         --+---------------+-------+
+	C
+	C mm6 = shift+32
+	C mm7 = ecx = 64-(shift+32)
+
+
+	C The movd for the unaligned case writes the same data to 4(%edx)
+	C that the movq does for the aligned case.
+
+
+	movq	%mm3, 8(%edx)
+	andl	$32, %ecx
+
+	psllq	%mm6, %mm2
+	jz	L(finish_zero_unaligned)
+
+	movq	%mm2, (%edx)
+L(finish_zero_unaligned):
+
+	psrlq	$32, %mm2
+	popl	%ebx
+
+	movd	%mm5, %eax	C retval
+
+	movd	%mm2, 4(%edx)
+
+	emms
+
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/pentium/mmx/mul_1.asm b/third_party/gmp/mpn/x86/pentium/mmx/mul_1.asm
new file mode 100644
index 0000000..4ced577
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium/mmx/mul_1.asm
@@ -0,0 +1,371 @@
+dnl  Intel Pentium MMX mpn_mul_1 -- mpn by limb multiplication.
+
+dnl  Copyright 2000-2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C    cycles/limb
+C P5:   12.0   for 32-bit multiplier
+C        7.0   for 16-bit multiplier
+
+
+C mp_limb_t mpn_mul_1 (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                      mp_limb_t multiplier);
+C
+C When the multiplier is 16 bits some special case MMX code is used.  Small
+C multipliers might arise reasonably often from mpz_mul_ui etc.  If the size
+C is odd there's roughly a 5 cycle penalty, so times for say size==7 and
+C size==8 end up being quite close.  If src isn't aligned to an 8 byte
+C boundary then one limb is processed separately with roughly a 5 cycle
+C penalty, so in that case it's say size==8 and size==9 which are close.
+C
+C Alternatives:
+C
+C MMX is not believed to be of any use for 32-bit multipliers, since for
+C instance the current method would just have to be more or less duplicated
+C for the high and low halves of the multiplier, and would probably
+C therefore run at about 14 cycles, which is slower than the plain integer
+C at 12.
+C
+C Adding the high and low MMX products using integer code seems best.  An
+C attempt at using paddd and carry bit propagation with pcmpgtd didn't give
+C any joy.  Perhaps something could be done keeping the values signed and
+C thereby avoiding adjustments to make pcmpgtd into an unsigned compare, or
+C perhaps not.
+C
+C Future:
+C
+C An mpn_mul_1c entrypoint would need a double carry out of the low result
+C limb in the 16-bit code, unless it could be assumed the carry fits in 16
+C bits, possibly as carry<multiplier, this being true of a big calculation
+C done piece by piece.  But let's worry about that if/when mul_1c is
+C actually used.
+
+defframe(PARAM_MULTIPLIER,16)
+defframe(PARAM_SIZE,      12)
+defframe(PARAM_SRC,       8)
+defframe(PARAM_DST,       4)
+
+	TEXT
+
+	ALIGN(8)
+PROLOGUE(mpn_mul_1)
+deflit(`FRAME',0)
+
+	movl	PARAM_SIZE, %ecx
+	movl	PARAM_SRC, %edx
+
+	cmpl	$1, %ecx
+	jne	L(two_or_more)
+
+	C one limb only
+
+	movl	PARAM_MULTIPLIER, %eax
+	movl	PARAM_DST, %ecx
+
+	mull	(%edx)
+
+	movl	%eax, (%ecx)
+	movl	%edx, %eax
+
+	ret
+
+
+L(two_or_more):
+	C eax	size
+	C ebx
+	C ecx	carry
+	C edx
+	C esi	src
+	C edi
+	C ebp
+
+	pushl	%esi		FRAME_pushl()
+	pushl	%edi		FRAME_pushl()
+
+	movl	%edx, %esi		C src
+	movl	PARAM_DST, %edi
+
+	movl	PARAM_MULTIPLIER, %eax
+	pushl	%ebx		FRAME_pushl()
+
+	leal	(%esi,%ecx,4), %esi	C src end
+	leal	(%edi,%ecx,4), %edi	C dst end
+
+	negl	%ecx			C -size
+
+	pushl	%ebp		FRAME_pushl()
+	cmpl	$65536, %eax
+
+	jb	L(small)
+
+
+L(big):
+	xorl	%ebx, %ebx		C carry limb
+	sarl	%ecx			C -size/2
+
+	jnc	L(top)			C with carry flag clear
+
+
+	C size was odd, process one limb separately
+
+	mull	4(%esi,%ecx,8)		C m * src[0]
+
+	movl	%eax, 4(%edi,%ecx,8)
+	incl	%ecx
+
+	orl	%edx, %ebx		C carry limb, and clear carry flag
+
+
+L(top):
+	C eax
+	C ebx	carry
+	C ecx	counter, negative
+	C edx
+	C esi	src end
+	C edi	dst end
+	C ebp	(scratch carry)
+
+	adcl	$0, %ebx
+	movl	(%esi,%ecx,8), %eax
+
+	mull	PARAM_MULTIPLIER
+
+	movl	%edx, %ebp
+	addl	%eax, %ebx
+
+	adcl	$0, %ebp
+	movl	4(%esi,%ecx,8), %eax
+
+	mull	PARAM_MULTIPLIER
+
+	movl	%ebx, (%edi,%ecx,8)
+	addl	%ebp, %eax
+
+	movl	%eax, 4(%edi,%ecx,8)
+	incl	%ecx
+
+	movl	%edx, %ebx
+	jnz	L(top)
+
+
+	adcl	$0, %ebx
+	popl	%ebp
+
+	movl	%ebx, %eax
+	popl	%ebx
+
+	popl	%edi
+	popl	%esi
+
+	ret
+
+
+L(small):
+	C Special case for 16-bit multiplier.
+	C
+	C eax	multiplier
+	C ebx
+	C ecx	-size
+	C edx	src
+	C esi	src end
+	C edi	dst end
+	C ebp	multiplier
+
+	C size<3 not supported here.  At size==3 we're already a couple of
+	C cycles faster, so there's no threshold as such, just use the MMX
+	C as soon as possible.
+
+	cmpl	$-3, %ecx
+	ja	L(big)
+
+	movd	%eax, %mm7		C m
+	pxor	%mm6, %mm6		C initial carry word
+
+	punpcklwd %mm7, %mm7		C m replicated 2 times
+	addl	$2, %ecx		C -size+2
+
+	punpckldq %mm7, %mm7		C m replicated 4 times
+	andl	$4, %edx		C test alignment, clear carry flag
+
+	movq	%mm7, %mm0		C m
+	jz	L(small_entry)
+
+
+	C Source is unaligned, process one limb separately.
+	C
+	C Plain integer code is used here, since it's smaller and is about
+	C the same 13 cycles as an mmx block would be.
+	C
+	C An "addl $1,%ecx" doesn't clear the carry flag when size==3, hence
+	C the use of separate incl and orl.
+
+	mull	-8(%esi,%ecx,4)		C m * src[0]
+
+	movl	%eax, -8(%edi,%ecx,4)	C dst[0]
+	incl	%ecx			C one limb processed
+
+	movd	%edx, %mm6		C initial carry
+
+	orl	%eax, %eax		C clear carry flag
+	jmp	L(small_entry)
+
+
+C The scheduling here is quite tricky, since so many instructions have
+C pairing restrictions.  In particular the js won't pair with a movd, and
+C can't be paired with an adc since it wants flags from the inc, so
+C instructions are rotated to the top of the loop to find somewhere useful
+C for it.
+C
+C Trouble has been taken to avoid overlapping successive loop iterations,
+C since that would greatly increase the size of the startup and finishup
+C code.  Actually there's probably not much advantage to be had from
+C overlapping anyway, since the difficulties are mostly with pairing, not
+C with latencies as such.
+C
+C In the comments x represents the src data and m the multiplier (16
+C bits, but replicated 4 times).
+C
+C The m signs calculated in %mm3 are a loop invariant and could be held in
+C say %mm5, but that would save only one instruction and hence be no faster.
+
+L(small_top):
+	C eax	l.low, then l.high
+	C ebx	(h.low)
+	C ecx	counter, -size+2 to 0 or 1
+	C edx	(h.high)
+	C esi	&src[size]
+	C edi	&dst[size]
+	C ebp
+	C
+	C %mm0	(high products)
+	C %mm1	(low products)
+	C %mm2	(adjust for m using x signs)
+	C %mm3	(adjust for x using m signs)
+	C %mm4
+	C %mm5
+	C %mm6	h.low, then carry
+	C %mm7	m replicated 4 times
+
+	movd	%mm6, %ebx		C h.low
+	psrlq	$32, %mm1		C l.high
+
+	movd	%mm0, %edx		C h.high
+	movq	%mm0, %mm6		C new c
+
+	adcl	%eax, %ebx
+	incl	%ecx
+
+	movd	%mm1, %eax		C l.high
+	movq	%mm7, %mm0
+
+	adcl	%eax, %edx
+	movl	%ebx, -16(%edi,%ecx,4)
+
+	movl	%edx, -12(%edi,%ecx,4)
+	psrlq	$32, %mm6		C c
+
+L(small_entry):
+	pmulhw	-8(%esi,%ecx,4), %mm0	C h = (x*m).high
+	movq	%mm7, %mm1
+
+	pmullw	-8(%esi,%ecx,4), %mm1	C l = (x*m).low
+	movq	%mm7, %mm3
+
+	movq	-8(%esi,%ecx,4), %mm2	C x
+	psraw	$15, %mm3		C m signs
+
+	pand	-8(%esi,%ecx,4), %mm3	C x selected by m signs
+	psraw	$15, %mm2		C x signs
+
+	paddw	%mm3, %mm0		C add x to h if m neg
+	pand	%mm7, %mm2		C m selected by x signs
+
+	paddw	%mm2, %mm0		C add m to h if x neg
+	incl	%ecx
+
+	movd	%mm1, %eax		C l.low
+	punpcklwd %mm0, %mm6		C c + h.low << 16
+
+	psrlq	$16, %mm0		C h.high
+	js	L(small_top)
+
+
+
+
+	movd	%mm6, %ebx		C h.low
+	psrlq	$32, %mm1		C l.high
+
+	adcl	%eax, %ebx
+	popl	%ebp		FRAME_popl()
+
+	movd	%mm0, %edx		C h.high
+	psrlq	$32, %mm0		C l.high
+
+	movd	%mm1, %eax		C l.high
+
+	adcl	%eax, %edx
+	movl	%ebx, -12(%edi,%ecx,4)
+
+	movd	%mm0, %eax		C c
+
+	adcl	$0, %eax
+	movl	%edx, -8(%edi,%ecx,4)
+
+	orl	%ecx, %ecx
+	jnz	L(small_done)		C final %ecx==1 means even, ==0 odd
+
+
+	C Size odd, one extra limb to process.
+	C Plain integer code is used here, since it's smaller and is about
+	C the same speed as another mmx block would be.
+
+	movl	%eax, %ecx
+	movl	PARAM_MULTIPLIER, %eax
+
+	mull	-4(%esi)
+
+	addl	%ecx, %eax
+
+	adcl	$0, %edx
+	movl	%eax, -4(%edi)
+
+	movl	%edx, %eax
+L(small_done):
+	popl	%ebx
+
+	popl	%edi
+	popl	%esi
+
+	emms
+
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/pentium/mmx/rshift.asm b/third_party/gmp/mpn/x86/pentium/mmx/rshift.asm
new file mode 100644
index 0000000..e3b274b
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium/mmx/rshift.asm
@@ -0,0 +1,468 @@
+dnl  Intel P5 mpn_rshift -- mpn right shift.
+
+dnl  Copyright 2000, 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C P5: 1.75 cycles/limb.
+
+
+C mp_limb_t mpn_rshift (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                       unsigned shift);
+C
+C Shift src,size right by shift many bits and store the result in dst,size.
+C Zeros are shifted in at the left.  Return the bits shifted out at the
+C right.
+C
+C It takes 6 mmx instructions to process 2 limbs, making 1.5 cycles/limb,
+C and with a 4 limb loop and 1 cycle of loop overhead the total is 1.75 c/l.
+C
+C Full speed depends on source and destination being aligned.  Unaligned mmx
+C loads and stores on P5 don't pair and have a 2 cycle penalty.  Some hairy
+C setups and finish-ups are done to ensure alignment for the loop.
+C
+C MMX shifts work out a bit faster even for the simple loop.
+
+defframe(PARAM_SHIFT,16)
+defframe(PARAM_SIZE, 12)
+defframe(PARAM_SRC,  8)
+defframe(PARAM_DST,  4)
+deflit(`FRAME',0)
+
+dnl  Minimum 5, because the unrolled loop can't handle less.
+deflit(UNROLL_THRESHOLD, 5)
+
+	TEXT
+	ALIGN(8)
+
+PROLOGUE(mpn_rshift)
+
+	pushl	%ebx
+	pushl	%edi
+deflit(`FRAME',8)
+
+	movl	PARAM_SIZE, %eax
+	movl	PARAM_DST, %edx
+
+	movl	PARAM_SRC, %ebx
+	movl	PARAM_SHIFT, %ecx
+
+	cmp	$UNROLL_THRESHOLD, %eax
+	jae	L(unroll)
+
+	decl	%eax
+	movl	(%ebx), %edi		C src low limb
+
+	jnz	L(simple)
+
+	shrdl(	%cl, %edi, %eax)	C eax was decremented to zero
+
+	shrl	%cl, %edi
+
+	movl	%edi, (%edx)		C dst low limb
+	popl	%edi			C risk of data cache bank clash
+
+	popl	%ebx
+
+	ret
+
+
+C -----------------------------------------------------------------------------
+	ALIGN(8)
+L(simple):
+	C eax	size-1
+	C ebx	src
+	C ecx	shift
+	C edx	dst
+	C esi
+	C edi
+	C ebp
+deflit(`FRAME',8)
+
+	movd	(%ebx), %mm5		C src[0]
+	leal	(%ebx,%eax,4), %ebx	C &src[size-1]
+
+	movd	%ecx, %mm6		C rshift
+	leal	-4(%edx,%eax,4), %edx	C &dst[size-2]
+
+	psllq	$32, %mm5
+	negl	%eax
+
+
+C This loop is 5 or 8 cycles, with every second load unaligned and a wasted
+C cycle waiting for the mm0 result to be ready.  For comparison a shrdl is 4
+C cycles and would be 8 in a simple loop.  Using mmx helps the return value
+C and last limb calculations too.
+
+L(simple_top):
+	C eax	counter, limbs, negative
+	C ebx	&src[size-1]
+	C ecx	return value
+	C edx	&dst[size-2]
+	C
+	C mm0	scratch
+	C mm5	return value
+	C mm6	shift
+
+	movq	(%ebx,%eax,4), %mm0
+	incl	%eax
+
+	psrlq	%mm6, %mm0
+
+	movd	%mm0, (%edx,%eax,4)
+	jnz	L(simple_top)
+
+
+	movd	(%ebx), %mm0
+	psrlq	%mm6, %mm5		C return value
+
+	psrlq	%mm6, %mm0
+	popl	%edi
+
+	movd	%mm5, %eax
+	popl	%ebx
+
+	movd	%mm0, 4(%edx)
+
+	emms
+
+	ret
+
+
+C -----------------------------------------------------------------------------
+	ALIGN(8)
+L(unroll):
+	C eax	size
+	C ebx	src
+	C ecx	shift
+	C edx	dst
+	C esi
+	C edi
+	C ebp
+deflit(`FRAME',8)
+
+	movd	(%ebx), %mm5		C src[0]
+	movl	$4, %edi
+
+	movd	%ecx, %mm6		C rshift
+	testl	%edi, %ebx
+
+	psllq	$32, %mm5
+	jz	L(start_src_aligned)
+
+
+	C src isn't aligned, process low limb separately (marked xxx) and
+	C step src and dst by one limb, making src aligned.
+	C
+	C source                  ebx
+	C --+-------+-------+-------+
+	C           |          xxx  |
+	C --+-------+-------+-------+
+	C         4mod8   0mod8   4mod8
+	C
+	C         dest            edx
+	C         --+-------+-------+
+	C           |       |  xxx  |
+	C         --+-------+-------+
+
+	movq	(%ebx), %mm0		C unaligned load
+
+	psrlq	%mm6, %mm0
+	addl	$4, %ebx
+
+	decl	%eax
+
+	movd	%mm0, (%edx)
+	addl	$4, %edx
+L(start_src_aligned):
+
+
+	movq	(%ebx), %mm1
+	testl	%edi, %edx
+
+	psrlq	%mm6, %mm5		C retval
+	jz	L(start_dst_aligned)
+
+	C dst isn't aligned, add 4 to make it so, and pretend the shift is
+	C 32 bits extra.  Low limb of dst (marked xxx) handled here
+	C separately.
+	C
+	C          source          ebx
+	C          --+-------+-------+
+	C            |      mm1      |
+	C          --+-------+-------+
+	C                  4mod8   0mod8
+	C
+	C  dest                    edx
+	C  --+-------+-------+-------+
+	C                    |  xxx  |
+	C  --+-------+-------+-------+
+	C          4mod8   0mod8   4mod8
+
+	movq	%mm1, %mm0
+	addl	$32, %ecx		C new shift
+
+	psrlq	%mm6, %mm0
+
+	movd	%ecx, %mm6
+
+	movd	%mm0, (%edx)
+	addl	$4, %edx
+L(start_dst_aligned):
+
+
+	movq	8(%ebx), %mm3
+	negl	%ecx
+
+	movq	%mm3, %mm2		C mm2 src qword
+	addl	$64, %ecx
+
+	movd	%ecx, %mm7
+	psrlq	%mm6, %mm1
+
+	leal	-12(%ebx,%eax,4), %ebx
+	leal	-20(%edx,%eax,4), %edx
+
+	psllq	%mm7, %mm3
+	subl	$7, %eax		C size-7
+
+	por	%mm1, %mm3		C mm3 ready to store
+	negl	%eax			C -(size-7)
+
+	jns	L(finish)
+
+
+	C This loop is the important bit, the rest is just support.  Careful
+	C instruction scheduling achieves the claimed 1.75 c/l.  The
+	C relevant parts of the pairing rules are:
+	C
+	C - mmx loads and stores execute only in the U pipe
+	C - only one mmx shift in a pair
+	C - wait one cycle before storing an mmx register result
+	C - the usual address generation interlock
+	C
+	C Two qword calculations are slightly interleaved.  The instructions
+	C marked "C" belong to the second qword, and the "C prev" one is for
+	C the second qword from the previous iteration.
+
+	ALIGN(8)
+L(unroll_loop):
+	C eax	counter, limbs, negative
+	C ebx	&src[size-12]
+	C ecx
+	C edx	&dst[size-12]
+	C esi
+	C edi
+	C
+	C mm0
+	C mm1
+	C mm2	src qword from -8(%ebx,%eax,4)
+	C mm3	dst qword ready to store to -8(%edx,%eax,4)
+	C
+	C mm5	return value
+	C mm6	rshift
+	C mm7	lshift
+
+	movq	(%ebx,%eax,4), %mm0
+	psrlq	%mm6, %mm2
+
+	movq	%mm0, %mm1
+	psllq	%mm7, %mm0
+
+	movq	%mm3, -8(%edx,%eax,4)	C prev
+	por	%mm2, %mm0
+
+	movq	8(%ebx,%eax,4), %mm3	C
+	psrlq	%mm6, %mm1		C
+
+	movq	%mm0, (%edx,%eax,4)
+	movq	%mm3, %mm2		C
+
+	psllq	%mm7, %mm3		C
+	addl	$4, %eax
+
+	por	%mm1, %mm3		C
+	js	L(unroll_loop)
+
+
+L(finish):
+	C eax	0 to 3 representing respectively 3 to 0 limbs remaining
+
+	testb	$2, %al
+
+	jnz	L(finish_no_two)
+
+	movq	(%ebx,%eax,4), %mm0
+	psrlq	%mm6, %mm2
+
+	movq	%mm0, %mm1
+	psllq	%mm7, %mm0
+
+	movq	%mm3, -8(%edx,%eax,4)	C prev
+	por	%mm2, %mm0
+
+	movq	%mm1, %mm2
+	movq	%mm0, %mm3
+
+	addl	$2, %eax
+L(finish_no_two):
+
+
+	C eax	2 or 3 representing respectively 1 or 0 limbs remaining
+	C
+	C mm2	src prev qword, from -8(%ebx,%eax,4)
+	C mm3	dst qword, for -8(%edx,%eax,4)
+
+	testb	$1, %al
+	popl	%edi
+
+	movd	%mm5, %eax	C retval
+	jnz	L(finish_zero)
+
+
+	C One extra limb, destination was aligned.
+	C
+	C source                ebx
+	C +-------+---------------+--
+	C |       |      mm2      |
+	C +-------+---------------+--
+	C
+	C dest                                  edx
+	C +-------+---------------+---------------+--
+	C |       |               |      mm3      |
+	C +-------+---------------+---------------+--
+	C
+	C mm6 = shift
+	C mm7 = ecx = 64-shift
+
+
+	C One extra limb, destination was unaligned.
+	C
+	C source                ebx
+	C +-------+---------------+--
+	C |       |      mm2      |
+	C +-------+---------------+--
+	C
+	C dest                          edx
+	C +---------------+---------------+--
+	C |               |      mm3      |
+	C +---------------+---------------+--
+	C
+	C mm6 = shift+32
+	C mm7 = ecx = 64-(shift+32)
+
+
+	C In both cases there's one extra limb of src to fetch and combine
+	C with mm2 to make a qword at 8(%edx), and in the aligned case
+	C there's a further extra limb of dst to be formed.
+
+
+	movd	8(%ebx), %mm0
+	psrlq	%mm6, %mm2
+
+	movq	%mm0, %mm1
+	psllq	%mm7, %mm0
+
+	movq	%mm3, (%edx)
+	por	%mm2, %mm0
+
+	psrlq	%mm6, %mm1
+	andl	$32, %ecx
+
+	popl	%ebx
+	jz	L(finish_one_unaligned)
+
+	C dst was aligned, must store one extra limb
+	movd	%mm1, 16(%edx)
+L(finish_one_unaligned):
+
+	movq	%mm0, 8(%edx)
+
+	emms
+
+	ret
+
+
+L(finish_zero):
+
+	C No extra limbs, destination was aligned.
+	C
+	C source        ebx
+	C +---------------+--
+	C |      mm2      |
+	C +---------------+--
+	C
+	C dest                        edx+4
+	C +---------------+---------------+--
+	C |               |      mm3      |
+	C +---------------+---------------+--
+	C
+	C mm6 = shift
+	C mm7 = ecx = 64-shift
+
+
+	C No extra limbs, destination was unaligned.
+	C
+	C source        ebx
+	C +---------------+--
+	C |      mm2      |
+	C +---------------+--
+	C
+	C dest                edx+4
+	C +-------+---------------+--
+	C |       |      mm3      |
+	C +-------+---------------+--
+	C
+	C mm6 = shift+32
+	C mm7 = 64-(shift+32)
+
+
+	C The movd for the unaligned case is clearly the same data as the
+	C movq for the aligned case, it's just a choice between whether one
+	C or two limbs should be written.
+
+
+	movq	%mm3, 4(%edx)
+	psrlq	%mm6, %mm2
+
+	movd	%mm2, 12(%edx)
+	andl	$32, %ecx
+
+	popl	%ebx
+	jz	L(finish_zero_unaligned)
+
+	movq	%mm2, 12(%edx)
+L(finish_zero_unaligned):
+
+	emms
+
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/pentium/mod_34lsub1.asm b/third_party/gmp/mpn/x86/pentium/mod_34lsub1.asm
new file mode 100644
index 0000000..2d88223
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium/mod_34lsub1.asm
@@ -0,0 +1,192 @@
+dnl  Intel P5 mpn_mod_34lsub1 -- mpn remainder modulo 2**24-1.
+
+dnl  Copyright 2000-2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C P5: 1.66 cycles/limb
+
+
+C mp_limb_t mpn_mod_34lsub1 (mp_srcptr src, mp_size_t size)
+C
+
+defframe(PARAM_SIZE, 8)
+defframe(PARAM_SRC,  4)
+
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_mod_34lsub1)
+deflit(`FRAME',0)
+
+	movl	PARAM_SIZE, %ecx
+	movl	PARAM_SRC, %edx
+
+	subl	$2, %ecx
+	ja	L(three_or_more)
+
+	movl	(%edx), %eax
+	jne	L(one)
+
+
+	movl	4(%edx), %ecx
+	movl	%eax, %edx
+
+	shrl	$24, %edx
+	andl	$0xFFFFFF, %eax
+
+	addl	%edx, %eax
+	movl	%ecx, %edx
+
+	shrl	$16, %ecx
+	andl	$0xFFFF, %edx
+
+	shll	$8, %edx
+	addl	%ecx, %eax
+
+	addl	%edx, %eax
+
+L(one):
+	ret
+
+
+L(three_or_more):
+	C eax
+	C ebx
+	C ecx	size-2
+	C edx	src
+	C esi
+	C edi
+	C ebp
+
+	pushl	%ebx	FRAME_pushl()
+	pushl	%esi	FRAME_pushl()
+
+	pushl	%edi	FRAME_pushl()
+	pushl	%ebp	FRAME_pushl()
+
+	xorl	%esi, %esi		C 0mod3
+	xorl	%edi, %edi		C 1mod3
+
+	xorl	%ebp, %ebp		C 2mod3, and clear carry
+
+L(top):
+	C eax	scratch
+	C ebx	scratch
+	C ecx	counter, limbs
+	C edx	src
+	C esi	0mod3
+	C edi	1mod3
+	C ebp	2mod3
+
+	movl	(%edx), %eax
+	movl	4(%edx), %ebx
+
+	adcl	%eax, %esi
+	movl	8(%edx), %eax
+
+	adcl	%ebx, %edi
+	leal	12(%edx), %edx
+
+	adcl	%eax, %ebp
+	leal	-2(%ecx), %ecx
+
+	decl	%ecx
+	jg	L(top)
+
+
+	C ecx is -2, -1 or 0, representing 0, 1 or 2 more limbs, respectively
+
+	movl	$0xFFFFFFFF, %ebx	C mask
+	incl	%ecx
+
+	js	L(combine)		C 0 more
+
+	movl	(%edx), %eax
+	movl	$0xFFFFFF00, %ebx
+
+	adcl	%eax, %esi
+	decl	%ecx
+
+	js	L(combine)		C 1 more
+
+	movl	4(%edx), %eax
+	movl	$0xFFFF0000, %ebx
+
+	adcl	%eax, %edi
+
+
+
+L(combine):
+	C eax
+	C ebx	mask
+	C ecx
+	C edx
+	C esi	0mod3
+	C edi	1mod3
+	C ebp	2mod3
+
+	sbbl	%ecx, %ecx		C carry
+	movl	%esi, %eax		C 0mod3
+
+	andl	%ebx, %ecx		C masked for position
+	andl	$0xFFFFFF, %eax		C 0mod3 low
+
+	shrl	$24, %esi		C 0mod3 high
+	subl	%ecx, %eax		C apply carry
+
+	addl	%esi, %eax		C apply 0mod3
+	movl	%edi, %ebx		C 1mod3
+
+	shrl	$16, %edi		C 1mod3 high
+	andl	$0x0000FFFF, %ebx
+
+	shll	$8, %ebx		C 1mod3 low
+	addl	%edi, %eax		C apply 1mod3 high
+
+	addl	%ebx, %eax		C apply 1mod3 low
+	movl	%ebp, %ebx		C 2mod3
+
+	shrl	$8, %ebp		C 2mod3 high
+	andl	$0xFF, %ebx
+
+	shll	$16, %ebx		C 2mod3 low
+	addl	%ebp, %eax		C apply 2mod3 high
+
+	addl	%ebx, %eax		C apply 2mod3 low
+
+	popl	%ebp
+	popl	%edi
+
+	popl	%esi
+	popl	%ebx
+
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/pentium/mode1o.asm b/third_party/gmp/mpn/x86/pentium/mode1o.asm
new file mode 100644
index 0000000..a90abca
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium/mode1o.asm
@@ -0,0 +1,279 @@
+dnl  Intel Pentium mpn_modexact_1_odd -- exact division style remainder.
+
+dnl  Copyright 2000-2002, 2014 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C P5: 23.0 cycles/limb
+
+
+C mp_limb_t mpn_modexact_1_odd (mp_srcptr src, mp_size_t size,
+C                               mp_limb_t divisor);
+C mp_limb_t mpn_modexact_1c_odd (mp_srcptr src, mp_size_t size,
+C                                mp_limb_t divisor, mp_limb_t carry);
+C
+C There seems no way to pair up the two lone instructions in the main loop.
+C
+C The special case for size==1 saves about 20 cycles (non-PIC), making it
+C the same as mpn_mod_1, and in fact making modexact faster than mod_1 at
+C all sizes.
+C
+C Alternatives:
+C
+C Using mmx for the multiplies might be possible, with pmullw and pmulhw
+C having just 3 cycle latencies, but carry bit handling would probably be
+C complicated.
+
+defframe(PARAM_CARRY,  16)
+defframe(PARAM_DIVISOR,12)
+defframe(PARAM_SIZE,   8)
+defframe(PARAM_SRC,    4)
+
+dnl  re-using parameter space
+define(VAR_INVERSE,`PARAM_SIZE')
+
+	TEXT
+
+	ALIGN(16)
+PROLOGUE(mpn_modexact_1c_odd)
+deflit(`FRAME',0)
+
+	movl	PARAM_DIVISOR, %eax
+	movl	PARAM_CARRY, %edx
+
+	jmp	L(start_1c)
+
+EPILOGUE()
+
+	ALIGN(16)
+PROLOGUE(mpn_modexact_1_odd)
+deflit(`FRAME',0)
+
+	movl	PARAM_DIVISOR, %eax
+	xorl	%edx, %edx		C carry
+
+L(start_1c):
+
+ifdef(`PIC',`
+ifdef(`DARWIN',`
+	shrl	%eax			C d/2
+	LEA(	binvert_limb_table, %ecx)
+	pushl	%ebx		FRAME_pushl()
+	movl	PARAM_SIZE, %ebx
+
+	andl	$127, %eax
+	subl	$2, %ebx
+
+	movb	(%eax,%ecx), %cl
+	jc	L(one_limb)
+',`
+	call	L(here)		FRAME_pushl()
+L(here):
+
+	shrl	%eax			C d/2
+	movl	(%esp), %ecx		C eip
+
+	addl	$_GLOBAL_OFFSET_TABLE_+[.-L(here)], %ecx
+	movl	%ebx, (%esp)		C push ebx
+
+	andl	$127, %eax
+	movl	PARAM_SIZE, %ebx
+
+	movl	binvert_limb_table@GOT(%ecx), %ecx
+	subl	$2, %ebx
+
+	movb	(%eax,%ecx), %cl			C inv 8 bits
+	jc	L(one_limb)
+')
+',`
+dnl non-PIC
+	shrl	%eax			C d/2
+	pushl	%ebx		FRAME_pushl()
+
+	movl	PARAM_SIZE, %ebx
+	andl	$127, %eax
+
+	subl	$2, %ebx
+	jc	L(one_limb)
+
+	movb	binvert_limb_table(%eax), %cl		C inv 8 bits
+')
+
+	movl	%ecx, %eax
+	addl	%ecx, %ecx		C 2*inv
+
+	imull	%eax, %eax		C inv*inv
+
+	imull	PARAM_DIVISOR, %eax	C inv*inv*d
+
+	subl	%eax, %ecx		C inv = 2*inv - inv*inv*d
+
+	movl	%ecx, %eax
+	addl	%ecx, %ecx		C 2*inv
+
+	imull	%eax, %eax		C inv*inv
+
+	imull	PARAM_DIVISOR, %eax	C inv*inv*d
+
+	subl	%eax, %ecx		C inv = 2*inv - inv*inv*d
+	pushl	%esi		FRAME_pushl()
+
+	ASSERT(e,`	C d*inv == 1 mod 2^GMP_LIMB_BITS
+	movl	%ecx, %eax
+	imull	PARAM_DIVISOR, %eax
+	cmpl	$1, %eax')
+
+	movl	PARAM_SRC, %esi
+	movl	%ecx, VAR_INVERSE
+
+	movl	(%esi), %eax		C src[0]
+	leal	4(%esi,%ebx,4), %esi	C &src[size-1]
+
+	xorl	$-1, %ebx		C -(size-1)
+	ASSERT(nz)
+	jmp	L(entry)
+
+
+C The use of VAR_INVERSE means only a store is needed for that value, rather
+C than a push and pop of say %edi.
+
+	ALIGN(16)
+L(top):
+	C eax	scratch, low product
+	C ebx	counter, limbs, negative
+	C ecx	carry bit
+	C edx	scratch, high product
+	C esi	&src[size-1]
+	C edi
+	C ebp
+
+	mull	PARAM_DIVISOR		C h:dummy = q*d
+
+	movl	(%esi,%ebx,4), %eax	C src[i]
+	subl	%ecx, %edx		C h -= -c
+
+L(entry):
+	subl	%edx, %eax		C s = src[i] - h
+
+	sbbl	%ecx, %ecx		C new -c (0 or -1)
+
+	imull	VAR_INVERSE, %eax	C q = s*i
+
+	incl	%ebx
+	jnz	L(top)
+
+
+	mull	PARAM_DIVISOR
+
+	movl	(%esi), %eax		C src high
+	subl	%ecx, %edx		C h -= -c
+
+	cmpl	PARAM_DIVISOR, %eax
+
+	jbe	L(skip_last)
+deflit(FRAME_LAST,FRAME)
+
+
+	subl	%edx, %eax		C s = src[i] - h
+	popl	%esi		FRAME_popl()
+
+	sbbl	%ecx, %ecx		C c (0 or -1)
+	popl	%ebx		FRAME_popl()
+
+	imull	VAR_INVERSE, %eax	C q = s*i
+
+	mull	PARAM_DIVISOR		C h:dummy = q*d
+
+	movl	%edx, %eax
+
+	subl	%ecx, %eax
+
+	ret
+
+
+C When high<divisor can skip last step.
+
+L(skip_last):
+deflit(`FRAME',FRAME_LAST)
+	C eax	src high
+	C ebx
+	C ecx
+	C edx	r
+	C esi
+
+	subl	%eax, %edx	C r-s
+	popl	%esi		FRAME_popl()
+
+	sbbl	%eax, %eax	C -1 if underflow
+	movl	PARAM_DIVISOR, %ebx
+
+	andl	%ebx, %eax	C divisor if underflow
+	popl	%ebx		FRAME_popl()
+
+	addl	%edx, %eax	C addback if underflow
+
+	ret
+
+
+C Special case for size==1 using a division for r = c-a mod d.
+C Could look for a-c<d and save a division sometimes, but that doesn't seem
+C worth bothering about.
+
+L(one_limb):
+deflit(`FRAME',4)
+	C eax
+	C ebx	size-2 (==-1)
+	C ecx
+	C edx	carry
+	C esi	src end
+	C edi
+	C ebp
+
+	movl	%edx, %eax
+	movl	PARAM_SRC, %edx
+
+	movl	PARAM_DIVISOR, %ecx
+	popl	%ebx		FRAME_popl()
+
+	subl	(%edx), %eax		C c-a
+
+	sbbl	%edx, %edx
+	decl	%ecx			C d-1
+
+	andl	%ecx, %edx		C b*d+c-a if c<a, or c-a if c>=a
+
+	divl	PARAM_DIVISOR
+
+	movl	%edx, %eax
+
+	ret
+
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86/pentium/mul_1.asm b/third_party/gmp/mpn/x86/pentium/mul_1.asm
new file mode 100644
index 0000000..a0858af
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium/mul_1.asm
@@ -0,0 +1,177 @@
+dnl  Intel Pentium mpn_mul_1 -- mpn by limb multiplication.
+
+dnl  Copyright 1992, 1994, 1996, 1999, 2000, 2002 Free Software Foundation,
+dnl  Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C P5: 12.0 cycles/limb
+
+
+C mp_limb_t mpn_mul_1 (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                      mp_limb_t multiplier);
+C mp_limb_t mpn_mul_1c (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                       mp_limb_t multiplier, mp_limb_t carry);
+C
+
+defframe(PARAM_CARRY,     20)
+defframe(PARAM_MULTIPLIER,16)
+defframe(PARAM_SIZE,      12)
+defframe(PARAM_SRC,       8)
+defframe(PARAM_DST,       4)
+
+	TEXT
+	ALIGN(8)
+PROLOGUE(mpn_mul_1c)
+deflit(`FRAME',0)
+
+	movl	PARAM_CARRY, %ecx
+	pushl	%esi		FRAME_pushl()
+
+	jmp	L(start_1c)
+
+EPILOGUE()
+
+
+	ALIGN(8)
+PROLOGUE(mpn_mul_1)
+deflit(`FRAME',0)
+
+	xorl	%ecx, %ecx
+	pushl	%esi		FRAME_pushl()
+
+L(start_1c):
+	movl	PARAM_SRC, %esi
+	movl	PARAM_SIZE, %eax
+
+	shrl	%eax
+	jnz	L(two_or_more)
+
+
+	C one limb only
+
+	movl	(%esi), %eax
+
+	mull	PARAM_MULTIPLIER
+
+	addl	%eax, %ecx
+	movl	PARAM_DST, %eax
+
+	adcl	$0, %edx
+	popl	%esi
+
+	movl	%ecx, (%eax)
+	movl	%edx, %eax
+
+	ret
+
+
+L(two_or_more):
+	C eax	size/2
+	C ebx
+	C ecx	carry
+	C edx
+	C esi	src
+	C edi
+	C ebp
+
+	pushl	%edi		FRAME_pushl()
+	pushl	%ebx		FRAME_pushl()
+
+	movl	PARAM_DST, %edi
+	leal	-1(%eax), %ebx		C size/2-1
+
+	notl	%ebx			C -size, preserve carry
+
+	leal	(%esi,%eax,8), %esi	C src end
+	leal	(%edi,%eax,8), %edi	C dst end
+
+	pushl	%ebp		FRAME_pushl()
+	jnc	L(top)
+
+
+	C size was odd, process one limb separately
+
+	movl	(%esi,%ebx,8), %eax
+	addl	$4, %esi
+
+	mull	PARAM_MULTIPLIER
+
+	addl	%ecx, %eax
+	movl	%edx, %ecx
+
+	movl	%eax, (%edi,%ebx,8)
+	leal	4(%edi), %edi
+
+
+L(top):
+	C eax
+	C ebx	counter, negative
+	C ecx	carry
+	C edx
+	C esi	src end
+	C edi	dst end
+	C ebp
+
+	adcl	$0, %ecx
+	movl	(%esi,%ebx,8), %eax
+
+	mull	PARAM_MULTIPLIER
+
+	movl	%edx, %ebp
+	addl	%eax, %ecx
+
+	adcl	$0, %ebp
+	movl	4(%esi,%ebx,8), %eax
+
+	mull	PARAM_MULTIPLIER
+
+	movl	%ecx, (%edi,%ebx,8)
+	addl	%ebp, %eax
+
+	movl	%eax, 4(%edi,%ebx,8)
+	incl	%ebx
+
+	movl	%edx, %ecx
+	jnz	L(top)
+
+
+	adcl	$0, %ecx
+	popl	%ebp
+
+	movl	%ecx, %eax
+	popl	%ebx
+
+	popl	%edi
+	popl	%esi
+
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/pentium/mul_2.asm b/third_party/gmp/mpn/x86/pentium/mul_2.asm
new file mode 100644
index 0000000..4c7beb5
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium/mul_2.asm
@@ -0,0 +1,150 @@
+dnl  Intel Pentium mpn_mul_2 -- mpn by 2-limb multiplication.
+
+dnl  Copyright 2001, 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C P5: 24.0 cycles/limb
+
+
+C mp_limb_t mpn_mul_2 (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                      mp_srcptr mult);
+C
+C At 24 c/l this is only 2 cycles faster than a separate mul_1 and addmul_1,
+C but has the advantage of making just one pass over the operands.
+C
+C There's not enough registers to use PARAM_MULT directly, so the multiplier
+C limbs are transferred to local variables on the stack.
+
+defframe(PARAM_MULT, 16)
+defframe(PARAM_SIZE, 12)
+defframe(PARAM_SRC,   8)
+defframe(PARAM_DST,   4)
+
+dnl  re-use parameter space
+define(VAR_MULT_LOW, `PARAM_SRC')
+define(VAR_MULT_HIGH,`PARAM_DST')
+
+	TEXT
+	ALIGN(8)
+PROLOGUE(mpn_mul_2)
+deflit(`FRAME',0)
+
+	pushl	%esi		FRAME_pushl()
+	pushl	%edi		FRAME_pushl()
+
+	movl	PARAM_SRC, %esi
+	movl	PARAM_DST, %edi
+
+	movl	PARAM_MULT, %eax
+	movl	PARAM_SIZE, %ecx
+
+	movl	4(%eax), %edx		C mult high
+	movl	(%eax), %eax		C mult low
+
+	movl	%eax, VAR_MULT_LOW
+	movl	%edx, VAR_MULT_HIGH
+
+	pushl	%ebx		FRAME_pushl()
+	pushl	%ebp		FRAME_pushl()
+
+	mull	(%esi)			C src[0] * mult[0]
+
+	movl	%eax, %ebp		C in case src==dst
+	movl	(%esi), %eax		C src[0]
+
+	movl	%ebp, (%edi)		C dst[0]
+	movl	%edx, %ebx		C initial low carry
+
+	xorl	%ebp, %ebp		C initial high carry
+	leal	(%edi,%ecx,4), %edi	C dst end
+
+	mull	VAR_MULT_HIGH		C src[0] * mult[1]
+
+	subl	$2, %ecx		C size-2
+	js	L(done)
+
+	leal	8(%esi,%ecx,4), %esi	C &src[size]
+	xorl	$-1, %ecx		C -(size-1)
+
+
+
+L(top):
+	C eax	low prod
+	C ebx	low carry
+	C ecx	counter, negative
+	C edx	high prod
+	C esi	src end
+	C edi	dst end
+	C ebp	high carry (0 or -1)
+
+	andl	$1, %ebp		C 1 or 0
+	addl	%eax, %ebx
+
+	adcl	%edx, %ebp
+	ASSERT(nc)
+	movl	(%esi,%ecx,4), %eax
+
+	mull	VAR_MULT_LOW
+
+	addl	%eax, %ebx		C low carry
+	movl	(%esi,%ecx,4), %eax
+
+	adcl	%ebp, %edx		C high carry
+	movl	%ebx, (%edi,%ecx,4)
+
+	sbbl	%ebp, %ebp		C new high carry, -1 or 0
+	movl	%edx, %ebx		C new low carry
+
+	mull	VAR_MULT_HIGH
+
+	incl	%ecx
+	jnz	L(top)
+
+
+L(done):
+	andl	$1, %ebp		C 1 or 0
+	addl	%ebx, %eax
+
+	adcl	%ebp, %edx
+	ASSERT(nc)
+	movl	%eax, (%edi)		C store carry low
+
+	movl	%edx, %eax		C return carry high
+
+	popl	%ebp
+	popl	%ebx
+
+	popl	%edi
+	popl	%esi
+
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/pentium/mul_basecase.asm b/third_party/gmp/mpn/x86/pentium/mul_basecase.asm
new file mode 100644
index 0000000..e1d0f05
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium/mul_basecase.asm
@@ -0,0 +1,142 @@
+dnl  Intel Pentium mpn_mul_basecase -- mpn by mpn multiplication.
+
+dnl  Copyright 1996, 1998-2000, 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C P5: 14.2 cycles/crossproduct (approx)
+
+
+C void mpn_mul_basecase (mp_ptr wp,
+C                        mp_srcptr xp, mp_size_t xsize,
+C                        mp_srcptr yp, mp_size_t ysize);
+
+defframe(PARAM_YSIZE, 20)
+defframe(PARAM_YP,    16)
+defframe(PARAM_XSIZE, 12)
+defframe(PARAM_XP,    8)
+defframe(PARAM_WP,    4)
+
+defframe(VAR_COUNTER, -4)
+
+	TEXT
+	ALIGN(8)
+PROLOGUE(mpn_mul_basecase)
+
+	pushl	%eax			C dummy push for allocating stack slot
+	pushl	%esi
+	pushl	%ebp
+	pushl	%edi
+deflit(`FRAME',16)
+
+	movl	PARAM_XP,%esi
+	movl	PARAM_WP,%edi
+	movl	PARAM_YP,%ebp
+
+	movl	(%esi),%eax		C load xp[0]
+	mull	(%ebp)			C multiply by yp[0]
+	movl	%eax,(%edi)		C store to wp[0]
+	movl	PARAM_XSIZE,%ecx	C xsize
+	decl	%ecx			C If xsize = 1, ysize = 1 too
+	jz	L(done)
+
+	movl	PARAM_XSIZE,%eax
+	pushl	%ebx
+FRAME_pushl()
+	movl	%edx,%ebx
+	leal	(%esi,%eax,4),%esi	C make xp point at end
+	leal	(%edi,%eax,4),%edi	C offset wp by xsize
+	negl	%ecx			C negate j size/index for inner loop
+	xorl	%eax,%eax		C clear carry
+
+	ALIGN(8)
+L(oop1):	adcl	$0,%ebx
+	movl	(%esi,%ecx,4),%eax	C load next limb at xp[j]
+	mull	(%ebp)
+	addl	%ebx,%eax
+	movl	%eax,(%edi,%ecx,4)
+	incl	%ecx
+	movl	%edx,%ebx
+	jnz	L(oop1)
+
+	adcl	$0,%ebx
+	movl	PARAM_YSIZE,%eax
+	movl	%ebx,(%edi)		C most significant limb of product
+	addl	$4,%edi			C increment wp
+	decl	%eax
+	jz	L(skip)
+	movl	%eax,VAR_COUNTER	C set index i to ysize
+
+L(outer):
+	addl	$4,%ebp			C make ebp point to next y limb
+	movl	PARAM_XSIZE,%ecx
+	negl	%ecx
+	xorl	%ebx,%ebx
+
+	C code at 0x61 here, close enough to aligned
+L(oop2):
+	adcl	$0,%ebx
+	movl	(%esi,%ecx,4),%eax
+	mull	(%ebp)
+	addl	%ebx,%eax
+	movl	(%edi,%ecx,4),%ebx
+	adcl	$0,%edx
+	addl	%eax,%ebx
+	movl	%ebx,(%edi,%ecx,4)
+	incl	%ecx
+	movl	%edx,%ebx
+	jnz	L(oop2)
+
+	adcl	$0,%ebx
+
+	movl	%ebx,(%edi)
+	addl	$4,%edi
+	movl	VAR_COUNTER,%eax
+	decl	%eax
+	movl	%eax,VAR_COUNTER
+	jnz	L(outer)
+
+L(skip):
+	popl	%ebx
+	popl	%edi
+	popl	%ebp
+	popl	%esi
+	addl	$4,%esp
+	ret
+
+L(done):
+	movl	%edx,4(%edi)	C store to wp[1]
+	popl	%edi
+	popl	%ebp
+	popl	%esi
+	popl	%eax		C dummy pop for deallocating stack slot
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/pentium/popcount.asm b/third_party/gmp/mpn/x86/pentium/popcount.asm
new file mode 100644
index 0000000..0e82144
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium/popcount.asm
@@ -0,0 +1,146 @@
+dnl  Intel P5 mpn_popcount -- mpn bit population count.
+
+dnl  Copyright 2001, 2002, 2014, 2015 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C P5: 8.0 cycles/limb
+
+
+C unsigned long mpn_popcount (mp_srcptr src, mp_size_t size);
+C
+C An arithmetic approach has been found to be slower than the table lookup,
+C due to needing too many instructions.
+
+C The slightly strange quoting here helps the renaming done by tune/many.pl.
+deflit(TABLE_NAME,
+m4_assert_defined(`GSYM_PREFIX')
+GSYM_PREFIX`'mpn_popcount``'_table')
+
+C FIXME: exporting the table to hamdist is incorrect as it hurt incremental
+C linking.
+
+	RODATA
+	ALIGN(8)
+	GLOBL	TABLE_NAME
+TABLE_NAME:
+forloop(i,0,255,
+`	.byte	m4_popcount(i)
+')
+
+defframe(PARAM_SIZE,8)
+defframe(PARAM_SRC, 4)
+
+	TEXT
+	ALIGN(8)
+
+PROLOGUE(mpn_popcount)
+deflit(`FRAME',0)
+
+	movl	PARAM_SIZE, %ecx
+	pushl	%esi	FRAME_pushl()
+
+ifdef(`PIC',`
+	pushl	%ebx	FRAME_pushl()
+	pushl	%ebp	FRAME_pushl()
+ifdef(`DARWIN',`
+	shll	%ecx		C size in byte pairs
+	LEA(	TABLE_NAME, %ebp)
+	movl	PARAM_SRC, %esi
+	xorl	%eax, %eax	C total
+	xorl	%ebx, %ebx	C byte
+	xorl	%edx, %edx	C byte
+',`
+	call	L(here)
+L(here):
+	popl	%ebp
+	shll	%ecx		C size in byte pairs
+
+	addl	$_GLOBAL_OFFSET_TABLE_+[.-L(here)], %ebp
+	movl	PARAM_SRC, %esi
+
+	xorl	%eax, %eax	C total
+	xorl	%ebx, %ebx	C byte
+
+	movl	TABLE_NAME@GOT(%ebp), %ebp
+	xorl	%edx, %edx	C byte
+')
+define(TABLE,`(%ebp,$1)')
+',`
+dnl non-PIC
+	shll	%ecx		C size in byte pairs
+	movl	PARAM_SRC, %esi
+
+	pushl	%ebx	FRAME_pushl()
+	xorl	%eax, %eax	C total
+
+	xorl	%ebx, %ebx	C byte
+	xorl	%edx, %edx	C byte
+
+define(TABLE,`TABLE_NAME`'($1)')
+')
+
+
+	ALIGN(8)	C necessary on P55 for claimed speed
+L(top):
+	C eax	total
+	C ebx	byte
+	C ecx	counter, 2*size to 2
+	C edx	byte
+	C esi	src
+	C edi
+	C ebp	[PIC] table
+
+	addl	%ebx, %eax
+	movb	-1(%esi,%ecx,2), %bl
+
+	addl	%edx, %eax
+	movb	-2(%esi,%ecx,2), %dl
+
+	movb	TABLE(%ebx), %bl
+	decl	%ecx
+
+	movb	TABLE(%edx), %dl
+	jnz	L(top)
+
+
+ifdef(`PIC',`
+	popl	%ebp
+')
+	addl	%ebx, %eax
+	popl	%ebx
+
+	addl	%edx, %eax
+	popl	%esi
+
+	ret
+
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86/pentium/rshift.asm b/third_party/gmp/mpn/x86/pentium/rshift.asm
new file mode 100644
index 0000000..2105c4c
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium/rshift.asm
@@ -0,0 +1,243 @@
+dnl  Intel Pentium mpn_rshift -- mpn right shift.
+
+dnl  Copyright 1992, 1994-1996, 1999, 2000, 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C         cycles/limb
+C P5,P54:    6.0
+C P55:       5.375
+
+
+C mp_limb_t mpn_rshift (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                       unsigned shift);
+C
+C The main shift-by-N loop should run at 5.375 c/l and that's what P55 does,
+C but P5 and P54 run only at 6.0 c/l, which is 4 cycles lost somewhere.
+
+defframe(PARAM_SHIFT,16)
+defframe(PARAM_SIZE, 12)
+defframe(PARAM_SRC,  8)
+defframe(PARAM_DST,  4)
+
+	TEXT
+	ALIGN(8)
+PROLOGUE(mpn_rshift)
+
+	pushl	%edi
+	pushl	%esi
+	pushl	%ebx
+	pushl	%ebp
+deflit(`FRAME',16)
+
+	movl	PARAM_DST,%edi
+	movl	PARAM_SRC,%esi
+	movl	PARAM_SIZE,%ebp
+	movl	PARAM_SHIFT,%ecx
+
+C We can use faster code for shift-by-1 under certain conditions.
+	cmp	$1,%ecx
+	jne	L(normal)
+	leal	4(%edi),%eax
+	cmpl	%esi,%eax
+	jnc	L(special)		C jump if res_ptr + 1 >= s_ptr
+	leal	(%edi,%ebp,4),%eax
+	cmpl	%eax,%esi
+	jnc	L(special)		C jump if s_ptr >= res_ptr + size
+
+L(normal):
+	movl	(%esi),%edx
+	addl	$4,%esi
+	xorl	%eax,%eax
+	shrdl(	%cl, %edx, %eax)	C compute carry limb
+	pushl	%eax			C push carry limb onto stack
+
+	decl	%ebp
+	pushl	%ebp
+	shrl	$3,%ebp
+	jz	L(end)
+
+	movl	(%edi),%eax		C fetch destination cache line
+
+	ALIGN(4)
+L(oop):	movl	28(%edi),%eax		C fetch destination cache line
+	movl	%edx,%ebx
+
+	movl	(%esi),%eax
+	movl	4(%esi),%edx
+	shrdl(	%cl, %eax, %ebx)
+	shrdl(	%cl, %edx, %eax)
+	movl	%ebx,(%edi)
+	movl	%eax,4(%edi)
+
+	movl	8(%esi),%ebx
+	movl	12(%esi),%eax
+	shrdl(	%cl, %ebx, %edx)
+	shrdl(	%cl, %eax, %ebx)
+	movl	%edx,8(%edi)
+	movl	%ebx,12(%edi)
+
+	movl	16(%esi),%edx
+	movl	20(%esi),%ebx
+	shrdl(	%cl, %edx, %eax)
+	shrdl(	%cl, %ebx, %edx)
+	movl	%eax,16(%edi)
+	movl	%edx,20(%edi)
+
+	movl	24(%esi),%eax
+	movl	28(%esi),%edx
+	shrdl(	%cl, %eax, %ebx)
+	shrdl(	%cl, %edx, %eax)
+	movl	%ebx,24(%edi)
+	movl	%eax,28(%edi)
+
+	addl	$32,%esi
+	addl	$32,%edi
+	decl	%ebp
+	jnz	L(oop)
+
+L(end):	popl	%ebp
+	andl	$7,%ebp
+	jz	L(end2)
+L(oop2):
+	movl	(%esi),%eax
+	shrdl(	%cl,%eax,%edx)		C compute result limb
+	movl	%edx,(%edi)
+	movl	%eax,%edx
+	addl	$4,%esi
+	addl	$4,%edi
+	decl	%ebp
+	jnz	L(oop2)
+
+L(end2):
+	shrl	%cl,%edx		C compute most significant limb
+	movl	%edx,(%edi)		C store it
+
+	popl	%eax			C pop carry limb
+
+	popl	%ebp
+	popl	%ebx
+	popl	%esi
+	popl	%edi
+	ret
+
+
+C We loop from least significant end of the arrays, which is only
+C permissable if the source and destination don't overlap, since the
+C function is documented to work for overlapping source and destination.
+
+L(special):
+	leal	-4(%edi,%ebp,4),%edi
+	leal	-4(%esi,%ebp,4),%esi
+
+	movl	(%esi),%edx
+	subl	$4,%esi
+
+	decl	%ebp
+	pushl	%ebp
+	shrl	$3,%ebp
+
+	shrl	%edx
+	incl	%ebp
+	decl	%ebp
+	jz	L(Lend)
+
+	movl	(%edi),%eax		C fetch destination cache line
+
+	ALIGN(4)
+L(Loop):
+	movl	-28(%edi),%eax		C fetch destination cache line
+	movl	%edx,%ebx
+
+	movl	(%esi),%eax
+	movl	-4(%esi),%edx
+	rcrl	%eax
+	movl	%ebx,(%edi)
+	rcrl	%edx
+	movl	%eax,-4(%edi)
+
+	movl	-8(%esi),%ebx
+	movl	-12(%esi),%eax
+	rcrl	%ebx
+	movl	%edx,-8(%edi)
+	rcrl	%eax
+	movl	%ebx,-12(%edi)
+
+	movl	-16(%esi),%edx
+	movl	-20(%esi),%ebx
+	rcrl	%edx
+	movl	%eax,-16(%edi)
+	rcrl	%ebx
+	movl	%edx,-20(%edi)
+
+	movl	-24(%esi),%eax
+	movl	-28(%esi),%edx
+	rcrl	%eax
+	movl	%ebx,-24(%edi)
+	rcrl	%edx
+	movl	%eax,-28(%edi)
+
+	leal	-32(%esi),%esi		C use leal not to clobber carry
+	leal	-32(%edi),%edi
+	decl	%ebp
+	jnz	L(Loop)
+
+L(Lend):
+	popl	%ebp
+	sbbl	%eax,%eax		C save carry in %eax
+	andl	$7,%ebp
+	jz	L(Lend2)
+	addl	%eax,%eax		C restore carry from eax
+L(Loop2):
+	movl	%edx,%ebx
+	movl	(%esi),%edx
+	rcrl	%edx
+	movl	%ebx,(%edi)
+
+	leal	-4(%esi),%esi		C use leal not to clobber carry
+	leal	-4(%edi),%edi
+	decl	%ebp
+	jnz	L(Loop2)
+
+	jmp	L(L1)
+L(Lend2):
+	addl	%eax,%eax		C restore carry from eax
+L(L1):	movl	%edx,(%edi)		C store last limb
+
+	movl	$0,%eax
+	rcrl	%eax
+
+	popl	%ebp
+	popl	%ebx
+	popl	%esi
+	popl	%edi
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/pentium/sqr_basecase.asm b/third_party/gmp/mpn/x86/pentium/sqr_basecase.asm
new file mode 100644
index 0000000..b11d767
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium/sqr_basecase.asm
@@ -0,0 +1,528 @@
+dnl  Intel P5 mpn_sqr_basecase -- square an mpn number.
+
+dnl  Copyright 1999-2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C P5: approx 8 cycles per crossproduct, or 15.5 cycles per triangular
+C product at around 20x20 limbs.
+
+
+C void mpn_sqr_basecase (mp_ptr dst, mp_srcptr src, mp_size_t size);
+C
+C Calculate src,size squared, storing the result in dst,2*size.
+C
+C The algorithm is basically the same as mpn/generic/sqr_basecase.c, but a
+C lot of function call overheads are avoided, especially when the size is
+C small.
+
+defframe(PARAM_SIZE,12)
+defframe(PARAM_SRC, 8)
+defframe(PARAM_DST, 4)
+
+	TEXT
+	ALIGN(8)
+PROLOGUE(mpn_sqr_basecase)
+deflit(`FRAME',0)
+
+	movl	PARAM_SIZE, %edx
+	movl	PARAM_SRC, %eax
+
+	cmpl	$2, %edx
+	movl	PARAM_DST, %ecx
+
+	je	L(two_limbs)
+
+	movl	(%eax), %eax
+	ja	L(three_or_more)
+
+C -----------------------------------------------------------------------------
+C one limb only
+	C eax	src
+	C ebx
+	C ecx	dst
+	C edx
+
+	mull	%eax
+
+	movl	%eax, (%ecx)
+	movl	%edx, 4(%ecx)
+
+	ret
+
+C -----------------------------------------------------------------------------
+	ALIGN(8)
+L(two_limbs):
+	C eax	src
+	C ebx
+	C ecx	dst
+	C edx	size
+
+	pushl	%ebp
+	pushl	%edi
+
+	pushl	%esi
+	pushl	%ebx
+
+	movl	%eax, %ebx
+	movl	(%eax), %eax
+
+	mull	%eax		C src[0]^2
+
+	movl	%eax, (%ecx)	C dst[0]
+	movl	%edx, %esi	C dst[1]
+
+	movl	4(%ebx), %eax
+
+	mull	%eax		C src[1]^2
+
+	movl	%eax, %edi	C dst[2]
+	movl	%edx, %ebp	C dst[3]
+
+	movl	(%ebx), %eax
+
+	mull	4(%ebx)		C src[0]*src[1]
+
+	addl	%eax, %esi
+	popl	%ebx
+
+	adcl	%edx, %edi
+
+	adcl	$0, %ebp
+	addl	%esi, %eax
+
+	adcl	%edi, %edx
+	movl	%eax, 4(%ecx)
+
+	adcl	$0, %ebp
+	popl	%esi
+
+	movl	%edx, 8(%ecx)
+	movl	%ebp, 12(%ecx)
+
+	popl	%edi
+	popl	%ebp
+
+	ret
+
+
+C -----------------------------------------------------------------------------
+	ALIGN(8)
+L(three_or_more):
+	C eax	src low limb
+	C ebx
+	C ecx	dst
+	C edx	size
+
+	cmpl	$4, %edx
+	pushl	%ebx
+deflit(`FRAME',4)
+
+	movl	PARAM_SRC, %ebx
+	jae	L(four_or_more)
+
+
+C -----------------------------------------------------------------------------
+C three limbs
+	C eax	src low limb
+	C ebx	src
+	C ecx	dst
+	C edx	size
+
+	pushl	%ebp
+	pushl	%edi
+
+	mull	%eax		C src[0] ^ 2
+
+	movl	%eax, (%ecx)
+	movl	%edx, 4(%ecx)
+
+	movl	4(%ebx), %eax
+	xorl	%ebp, %ebp
+
+	mull	%eax		C src[1] ^ 2
+
+	movl	%eax, 8(%ecx)
+	movl	%edx, 12(%ecx)
+
+	movl	8(%ebx), %eax
+	pushl	%esi		C risk of cache bank clash
+
+	mull	%eax		C src[2] ^ 2
+
+	movl	%eax, 16(%ecx)
+	movl	%edx, 20(%ecx)
+
+	movl	(%ebx), %eax
+
+	mull	4(%ebx)		C src[0] * src[1]
+
+	movl	%eax, %esi
+	movl	%edx, %edi
+
+	movl	(%ebx), %eax
+
+	mull	8(%ebx)		C src[0] * src[2]
+
+	addl	%eax, %edi
+	movl	%edx, %ebp
+
+	adcl	$0, %ebp
+	movl	4(%ebx), %eax
+
+	mull	8(%ebx)		C src[1] * src[2]
+
+	xorl	%ebx, %ebx
+	addl	%eax, %ebp
+
+	C eax
+	C ebx	zero, will be dst[5]
+	C ecx	dst
+	C edx	dst[4]
+	C esi	dst[1]
+	C edi	dst[2]
+	C ebp	dst[3]
+
+	adcl	$0, %edx
+	addl	%esi, %esi
+
+	adcl	%edi, %edi
+
+	adcl	%ebp, %ebp
+
+	adcl	%edx, %edx
+	movl	4(%ecx), %eax
+
+	adcl	$0, %ebx
+	addl	%esi, %eax
+
+	movl	%eax, 4(%ecx)
+	movl	8(%ecx), %eax
+
+	adcl	%edi, %eax
+	movl	12(%ecx), %esi
+
+	adcl	%ebp, %esi
+	movl	16(%ecx), %edi
+
+	movl	%eax, 8(%ecx)
+	movl	%esi, 12(%ecx)
+
+	adcl	%edx, %edi
+	popl	%esi
+
+	movl	20(%ecx), %eax
+	movl	%edi, 16(%ecx)
+
+	popl	%edi
+	popl	%ebp
+
+	adcl	%ebx, %eax	C no carry out of this
+	popl	%ebx
+
+	movl	%eax, 20(%ecx)
+
+	ret
+
+
+C -----------------------------------------------------------------------------
+	ALIGN(8)
+L(four_or_more):
+	C eax	src low limb
+	C ebx	src
+	C ecx	dst
+	C edx	size
+	C esi
+	C edi
+	C ebp
+	C
+	C First multiply src[0]*src[1..size-1] and store at dst[1..size].
+
+deflit(`FRAME',4)
+
+	pushl	%edi
+FRAME_pushl()
+	pushl	%esi
+FRAME_pushl()
+
+	pushl	%ebp
+FRAME_pushl()
+	leal	(%ecx,%edx,4), %edi	C dst end of this mul1
+
+	leal	(%ebx,%edx,4), %esi	C src end
+	movl	%ebx, %ebp		C src
+
+	negl	%edx			C -size
+	xorl	%ebx, %ebx		C clear carry limb and carry flag
+
+	leal	1(%edx), %ecx		C -(size-1)
+
+L(mul1):
+	C eax	scratch
+	C ebx	carry
+	C ecx	counter, negative
+	C edx	scratch
+	C esi	&src[size]
+	C edi	&dst[size]
+	C ebp	src
+
+	adcl	$0, %ebx
+	movl	(%esi,%ecx,4), %eax
+
+	mull	(%ebp)
+
+	addl	%eax, %ebx
+
+	movl	%ebx, (%edi,%ecx,4)
+	incl	%ecx
+
+	movl	%edx, %ebx
+	jnz	L(mul1)
+
+
+	C Add products src[n]*src[n+1..size-1] at dst[2*n-1...], for
+	C n=1..size-2.
+	C
+	C The last two products, which are the end corner of the product
+	C triangle, are handled separately to save looping overhead.  These
+	C are src[size-3]*src[size-2,size-1] and src[size-2]*src[size-1].
+	C If size is 4 then it's only these that need to be done.
+	C
+	C In the outer loop %esi is a constant, and %edi just advances by 1
+	C limb each time.  The size of the operation decreases by 1 limb
+	C each time.
+
+	C eax
+	C ebx	carry (needing carry flag added)
+	C ecx
+	C edx
+	C esi	&src[size]
+	C edi	&dst[size]
+	C ebp
+
+	adcl	$0, %ebx
+	movl	PARAM_SIZE, %edx
+
+	movl	%ebx, (%edi)
+	subl	$4, %edx
+
+	negl	%edx
+	jz	L(corner)
+
+
+L(outer):
+	C ebx	previous carry limb to store
+	C edx	outer loop counter (negative)
+	C esi	&src[size]
+	C edi	dst, pointing at stored carry limb of previous loop
+
+	pushl	%edx			C new outer loop counter
+	leal	-2(%edx), %ecx
+
+	movl	%ebx, (%edi)
+	addl	$4, %edi
+
+	addl	$4, %ebp
+	xorl	%ebx, %ebx		C initial carry limb, clear carry flag
+
+L(inner):
+	C eax	scratch
+	C ebx	carry (needing carry flag added)
+	C ecx	counter, negative
+	C edx	scratch
+	C esi	&src[size]
+	C edi	dst end of this addmul
+	C ebp	&src[j]
+
+	adcl	$0, %ebx
+	movl	(%esi,%ecx,4), %eax
+
+	mull	(%ebp)
+
+	addl	%ebx, %eax
+	movl	(%edi,%ecx,4), %ebx
+
+	adcl	$0, %edx
+	addl	%eax, %ebx
+
+	movl	%ebx, (%edi,%ecx,4)
+	incl	%ecx
+
+	movl	%edx, %ebx
+	jnz	L(inner)
+
+
+	adcl	$0, %ebx
+	popl	%edx		C outer loop counter
+
+	incl	%edx
+	jnz	L(outer)
+
+
+	movl	%ebx, (%edi)
+
+L(corner):
+	C esi	&src[size]
+	C edi	&dst[2*size-4]
+
+	movl	-8(%esi), %eax
+	movl	-4(%edi), %ebx		C risk of data cache bank clash here
+
+	mull	-12(%esi)		C src[size-2]*src[size-3]
+
+	addl	%eax, %ebx
+	movl	%edx, %ecx
+
+	adcl	$0, %ecx
+	movl	-4(%esi), %eax
+
+	mull	-12(%esi)		C src[size-1]*src[size-3]
+
+	addl	%ecx, %eax
+	movl	(%edi), %ecx
+
+	adcl	$0, %edx
+	movl	%ebx, -4(%edi)
+
+	addl	%eax, %ecx
+	movl	%edx, %ebx
+
+	adcl	$0, %ebx
+	movl	-4(%esi), %eax
+
+	mull	-8(%esi)		C src[size-1]*src[size-2]
+
+	movl	%ecx, (%edi)
+	addl	%eax, %ebx
+
+	adcl	$0, %edx
+	movl	PARAM_SIZE, %eax
+
+	negl	%eax
+	movl	%ebx, 4(%edi)
+
+	addl	$1, %eax		C -(size-1) and clear carry
+	movl	%edx, 8(%edi)
+
+
+C -----------------------------------------------------------------------------
+C Left shift of dst[1..2*size-2], high bit shifted out becomes dst[2*size-1].
+
+L(lshift):
+	C eax	counter, negative
+	C ebx	next limb
+	C ecx
+	C edx
+	C esi
+	C edi	&dst[2*size-4]
+	C ebp
+
+	movl	12(%edi,%eax,8), %ebx
+
+	rcll	%ebx
+	movl	16(%edi,%eax,8), %ecx
+
+	rcll	%ecx
+	movl	%ebx, 12(%edi,%eax,8)
+
+	movl	%ecx, 16(%edi,%eax,8)
+	incl	%eax
+
+	jnz	L(lshift)
+
+
+	adcl	%eax, %eax		C high bit out
+	movl	PARAM_SRC, %esi
+
+	movl	PARAM_SIZE, %ecx	C risk of cache bank clash
+	movl	%eax, 12(%edi)		C dst most significant limb
+
+
+C -----------------------------------------------------------------------------
+C Now add in the squares on the diagonal, namely src[0]^2, src[1]^2, ...,
+C src[size-1]^2.  dst[0] hasn't yet been set at all yet, and just gets the
+C low limb of src[0]^2.
+
+	movl	(%esi), %eax		C src[0]
+	leal	(%esi,%ecx,4), %esi	C src end
+
+	negl	%ecx
+
+	mull	%eax
+
+	movl	%eax, 16(%edi,%ecx,8)	C dst[0]
+	movl	%edx, %ebx
+
+	addl	$1, %ecx		C size-1 and clear carry
+
+L(diag):
+	C eax	scratch (low product)
+	C ebx	carry limb
+	C ecx	counter, negative
+	C edx	scratch (high product)
+	C esi	&src[size]
+	C edi	&dst[2*size-4]
+	C ebp	scratch (fetched dst limbs)
+
+	movl	(%esi,%ecx,4), %eax
+	adcl	$0, %ebx
+
+	mull	%eax
+
+	movl	16-4(%edi,%ecx,8), %ebp
+
+	addl	%ebp, %ebx
+	movl	16(%edi,%ecx,8), %ebp
+
+	adcl	%eax, %ebp
+	movl	%ebx, 16-4(%edi,%ecx,8)
+
+	movl	%ebp, 16(%edi,%ecx,8)
+	incl	%ecx
+
+	movl	%edx, %ebx
+	jnz	L(diag)
+
+
+	adcl	$0, %edx
+	movl	16-4(%edi), %eax	C dst most significant limb
+
+	addl	%eax, %edx
+	popl	%ebp
+
+	movl	%edx, 16-4(%edi)
+	popl	%esi		C risk of cache bank clash
+
+	popl	%edi
+	popl	%ebx
+
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/pentium4/README b/third_party/gmp/mpn/x86/pentium4/README
new file mode 100644
index 0000000..90f752e
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium4/README
@@ -0,0 +1,124 @@
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.
+
+
+
+
+                   INTEL PENTIUM-4 MPN SUBROUTINES
+
+
+This directory contains mpn functions optimized for Intel Pentium-4.
+
+The mmx subdirectory has routines using MMX instructions, the sse2
+subdirectory has routines using SSE2 instructions.  All P4s have these, the
+separate directories are just so configure can omit that code if the
+assembler doesn't support it.
+
+
+STATUS
+
+                                cycles/limb
+
+	mpn_add_n/sub_n            4 normal, 6 in-place
+
+	mpn_mul_1                  4 normal, 6 in-place
+	mpn_addmul_1               6
+	mpn_submul_1               7
+
+	mpn_mul_basecase           6 cycles/crossproduct (approx)
+
+	mpn_sqr_basecase           3.5 cycles/crossproduct (approx)
+                                   or 7.0 cycles/triangleproduct (approx)
+
+	mpn_l/rshift               1.75
+
+
+
+The shifts ought to be able to go at 1.5 c/l, but not much effort has been
+applied to them yet.
+
+In-place operations, and all addmul, submul, mul_basecase and sqr_basecase
+calls, suffer from pipeline anomalies associated with write combining and
+movd reads and writes to the same or nearby locations.  The movq
+instructions do not trigger the same hardware problems.  Unfortunately,
+using movq and splitting/combining seems to require too many extra
+instructions to help.  Perhaps future chip steppings will be better.
+
+
+
+NOTES
+
+The Pentium-4 pipeline "Netburst", provides for quite a number of surprises.
+Many traditional x86 instructions run very slowly, requiring use of
+alterative instructions for acceptable performance.
+
+adcl and sbbl are quite slow at 8 cycles for reg->reg.  paddq of 32-bits
+within a 64-bit mmx register seems better, though the combination
+paddq/psrlq when propagating a carry is still a 4 cycle latency.
+
+incl and decl should be avoided, instead use add $1 and sub $1.  Apparently
+the carry flag is not separately renamed, so incl and decl depend on all
+previous flags-setting instructions.
+
+shll and shrl have a 4 cycle latency, or 8 times the latency of the fastest
+integer instructions (addl, subl, orl, andl, and some more).  shldl and
+shrdl seem to have 13 and 15 cycles latency, respectively.  Bizarre.
+
+movq mmx -> mmx does have 6 cycle latency, as noted in the documentation.
+pxor/por or similar combination at 2 cycles latency can be used instead.
+The movq however executes in the float unit, thereby saving MMX execution
+resources.  With the right juggling, data moves shouldn't be on a dependent
+chain.
+
+L1 is write-through, but the write-combining sounds like it does enough to
+not require explicit destination prefetching.
+
+xmm registers so far haven't found a use, but not much effort has been
+expended.  A configure test for whether the operating system knows
+fxsave/fxrestor will be needed if they're used.
+
+
+
+REFERENCES
+
+Intel Pentium-4 processor manuals,
+
+	http://developer.intel.com/design/pentium4/manuals
+
+"Intel Pentium 4 Processor Optimization Reference Manual", Intel, 2001,
+order number 248966.  Available on-line:
+
+	http://developer.intel.com/design/pentium4/manuals/248966.htm
+
+
+
+----------------
+Local variables:
+mode: text
+fill-column: 76
+End:
diff --git a/third_party/gmp/mpn/x86/pentium4/copyd.asm b/third_party/gmp/mpn/x86/pentium4/copyd.asm
new file mode 100644
index 0000000..82af81c
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium4/copyd.asm
@@ -0,0 +1,71 @@
+dnl  Pentium-4 mpn_copyd -- copy limb vector, decrementing.
+
+dnl  Copyright 1999-2001 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+dnl  The std/rep/movsl/cld is very slow for small blocks on pentium4.  Its
+dnl  startup time seems to be about 165 cycles.  It then needs 2.6 c/l.
+dnl  We therefore use an open-coded 2 c/l copying loop.
+
+dnl  Ultimately, we may want to use 64-bit movq or 128-bit movdqu in some
+dnl  nifty unrolled arrangement.  Clearly, that could reach much higher
+dnl  speeds, at least for large blocks.
+
+include(`../config.m4')
+
+
+defframe(PARAM_SIZE, 12)
+defframe(PARAM_SRC, 8)
+defframe(PARAM_DST,  4)
+
+	TEXT
+	ALIGN(8)
+
+PROLOGUE(mpn_copyd)
+deflit(`FRAME',0)
+
+	movl	PARAM_SIZE, %ecx
+
+	movl	PARAM_SRC, %eax
+	movl	PARAM_DST, %edx
+	movl	%ebx, PARAM_SIZE
+	addl	$-1, %ecx
+	js	L(end)
+
+L(loop):
+	movl	(%eax,%ecx,4), %ebx
+	movl	%ebx, (%edx,%ecx,4)
+	addl	$-1, %ecx
+
+	jns	L(loop)
+L(end):
+	movl	PARAM_SIZE, %ebx
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/pentium4/copyi.asm b/third_party/gmp/mpn/x86/pentium4/copyi.asm
new file mode 100644
index 0000000..b614887
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium4/copyi.asm
@@ -0,0 +1,93 @@
+dnl  Pentium-4 mpn_copyi -- copy limb vector, incrementing.
+
+dnl  Copyright 1999-2001 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+dnl  The rep/movsl is very slow for small blocks on pentium4.  Its startup
+dnl  time seems to be about 110 cycles.  It then copies at a rate of one
+dnl  limb per cycle.  We therefore fall back to an open-coded 2 c/l copying
+dnl  loop for smaller sizes.
+
+dnl  Ultimately, we may want to use 64-bit movd or 128-bit movdqu in some
+dnl  nifty unrolled arrangement.  Clearly, that could reach much higher
+dnl  speeds, at least for large blocks.
+
+include(`../config.m4')
+
+
+defframe(PARAM_SIZE, 12)
+defframe(PARAM_SRC, 8)
+defframe(PARAM_DST,  4)
+
+	TEXT
+	ALIGN(8)
+
+PROLOGUE(mpn_copyi)
+deflit(`FRAME',0)
+
+	movl	PARAM_SIZE, %ecx
+	cmpl	$150, %ecx
+	jg	L(replmovs)
+
+	movl	PARAM_SRC, %eax
+	movl	PARAM_DST, %edx
+	movl	%ebx, PARAM_SIZE
+	testl	%ecx, %ecx
+	jz	L(end)
+
+L(loop):
+	movl	(%eax), %ebx
+	leal	4(%eax), %eax
+	addl	$-1, %ecx
+	movl	%ebx, (%edx)
+	leal	4(%edx), %edx
+
+	jnz	L(loop)
+
+L(end):
+	movl	PARAM_SIZE, %ebx
+	ret
+
+L(replmovs):
+	cld	C better safe than sorry, see mpn/x86/README
+
+	movl	%esi, %eax
+	movl	PARAM_SRC, %esi
+	movl	%edi, %edx
+	movl	PARAM_DST, %edi
+
+	rep
+	movsl
+
+	movl	%eax, %esi
+	movl	%edx, %edi
+
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/pentium4/mmx/lshift.asm b/third_party/gmp/mpn/x86/pentium4/mmx/lshift.asm
new file mode 100644
index 0000000..b5eca66
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium4/mmx/lshift.asm
@@ -0,0 +1,39 @@
+dnl  Intel Pentium-4 mpn_lshift -- left shift.
+
+dnl  Copyright 2001, 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C P4 Willamette, Northwood: 1.75 cycles/limb
+C P4 Prescott:		    2.0 cycles/limb
+
+
+MULFUNC_PROLOGUE(mpn_lshift)
+include_mpn(`x86/pentium/mmx/lshift.asm')
diff --git a/third_party/gmp/mpn/x86/pentium4/mmx/popham.asm b/third_party/gmp/mpn/x86/pentium4/mmx/popham.asm
new file mode 100644
index 0000000..9563cb5
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium4/mmx/popham.asm
@@ -0,0 +1,203 @@
+dnl  Intel Pentium 4 mpn_popcount, mpn_hamdist -- population count and
+dnl  hamming distance.
+
+dnl  Copyright 2000-2002, 2007 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C			     popcount	     hamdist
+C P3 model 9  (Banias)		?		?
+C P3 model 13 (Dothan)		6		6
+C P4 model 0  (Willamette)
+C P4 model 1  (?)
+C P4 model 2  (Northwood)	8		9
+C P4 model 3  (Prescott)	8		9
+C P4 model 4  (Nocona)
+
+C unsigned long mpn_popcount (mp_srcptr src, mp_size_t size);
+C unsigned long mpn_hamdist (mp_srcptr src, mp_srcptr src2, mp_size_t size);
+C
+C Loading with unaligned movq's costs an extra 1 c/l and hence is avoided.
+C Two movd's and a punpckldq seems to be the same speed as an aligned movq,
+C and using them saves fiddling about with alignment testing on entry.
+C
+C For popcount there's 13 mmx instructions in the loop, so perhaps 6.5 c/l
+C might be possible, but 8 c/l relying on out-of-order execution is already
+C quite reasonable.
+
+ifdef(`OPERATION_popcount',,
+`ifdef(`OPERATION_hamdist',,
+`m4_error(`Need OPERATION_popcount or OPERATION_hamdist defined
+')')')
+
+define(HAM,
+m4_assert_numargs(1)
+`ifdef(`OPERATION_hamdist',`$1')')
+
+define(POP,
+m4_assert_numargs(1)
+`ifdef(`OPERATION_popcount',`$1')')
+
+HAM(`
+defframe(PARAM_SIZE, 12)
+defframe(PARAM_SRC2,  8)
+defframe(PARAM_SRC,   4)
+define(M4_function,mpn_hamdist)
+')
+POP(`
+defframe(PARAM_SIZE,  8)
+defframe(PARAM_SRC,   4)
+define(M4_function,mpn_popcount)
+')
+
+MULFUNC_PROLOGUE(mpn_popcount mpn_hamdist)
+
+
+ifdef(`PIC',,`
+	dnl  non-PIC
+	RODATA
+	ALIGN(8)
+L(rodata_AAAAAAAAAAAAAAAA):
+	.long	0xAAAAAAAA
+	.long	0xAAAAAAAA
+L(rodata_3333333333333333):
+	.long	0x33333333
+	.long	0x33333333
+L(rodata_0F0F0F0F0F0F0F0F):
+	.long	0x0F0F0F0F
+	.long	0x0F0F0F0F
+')
+
+	TEXT
+	ALIGN(16)
+
+PROLOGUE(M4_function)
+deflit(`FRAME',0)
+
+	movl	PARAM_SIZE, %ecx
+	movl	PARAM_SRC, %eax
+
+ifdef(`PIC',`
+	movl	$0xAAAAAAAA, %edx
+	movd	%edx, %mm7
+	punpckldq %mm7, %mm7
+
+	movl	$0x33333333, %edx
+	movd	%edx, %mm6
+	punpckldq %mm6, %mm6
+
+	movl	$0x0F0F0F0F, %edx
+	movd	%edx, %mm5
+	punpckldq %mm5, %mm5
+
+HAM(`	movl	PARAM_SRC2, %edx')
+
+',`
+	dnl non-PIC
+HAM(`	movl	PARAM_SRC2, %edx')
+	movq	L(rodata_AAAAAAAAAAAAAAAA), %mm7
+	movq	L(rodata_3333333333333333), %mm6
+	movq	L(rodata_0F0F0F0F0F0F0F0F), %mm5
+')
+
+	pxor	%mm4, %mm4		C zero
+	pxor	%mm0, %mm0		C total
+
+	subl	$1, %ecx
+	ja	L(top)
+
+L(last):
+	movd	(%eax,%ecx,4), %mm1		C src high limb
+HAM(`	movd	(%edx,%ecx,4), %mm2
+	pxor	%mm2, %mm1
+')
+	jmp	L(loaded)
+
+
+L(top):
+	C eax	src
+	C ebx
+	C ecx	counter, size-1 to 2 or 1, inclusive
+	C edx	[hamdist] src2
+	C
+	C mm0	total (low dword)
+	C mm1	(scratch)
+	C mm2	(scratch)
+	C mm3
+	C mm4	0x0000000000000000
+	C mm5	0x0F0F0F0F0F0F0F0F
+	C mm6	0x3333333333333333
+	C mm7	0xAAAAAAAAAAAAAAAA
+
+	movd	(%eax), %mm1
+	movd	4(%eax), %mm2
+	punpckldq %mm2, %mm1
+	addl	$8, %eax
+
+HAM(`	movd	(%edx), %mm2
+	movd	4(%edx), %mm3
+	punpckldq %mm3, %mm2
+	pxor	%mm2, %mm1
+	addl	$8, %edx
+')
+
+L(loaded):
+	movq	%mm7, %mm2
+	pand	%mm1, %mm2
+	psrlq	$1, %mm2
+	psubd	%mm2, %mm1	C bit pairs
+
+	movq	%mm6, %mm2
+	pand	%mm1, %mm2
+	psrlq	$2, %mm1
+	pand	%mm6, %mm1
+	paddd	%mm2, %mm1	C nibbles
+
+	movq	%mm5, %mm2
+	pand	%mm1, %mm2
+	psrlq	$4, %mm1
+	pand	%mm5, %mm1
+	paddd	%mm2, %mm1	C bytes
+
+	psadbw(	%mm4, %mm1)
+	paddd	%mm1, %mm0	C to total
+
+	subl	$2, %ecx
+	jg	L(top)
+
+	C ecx is 0 or -1 representing respectively 1 or 0 further limbs
+	jz	L(last)
+
+
+	movd	%mm0, %eax
+	emms
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/pentium4/mmx/rshift.asm b/third_party/gmp/mpn/x86/pentium4/mmx/rshift.asm
new file mode 100644
index 0000000..3ac0094
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium4/mmx/rshift.asm
@@ -0,0 +1,39 @@
+dnl  Intel Pentium-4 mpn_rshift -- right shift.
+
+dnl  Copyright 2001, 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C P4 Willamette, Northwood: 1.75 cycles/limb
+C P4 Prescott:		    2.0 cycles/limb
+
+
+MULFUNC_PROLOGUE(mpn_rshift)
+include_mpn(`x86/pentium/mmx/rshift.asm')
diff --git a/third_party/gmp/mpn/x86/pentium4/sse2/add_n.asm b/third_party/gmp/mpn/x86/pentium4/sse2/add_n.asm
new file mode 100644
index 0000000..8e2380e
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium4/sse2/add_n.asm
@@ -0,0 +1,101 @@
+dnl  Intel Pentium-4 mpn_add_n -- mpn addition.
+
+dnl  Copyright 2001, 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C					cycles/limb
+C			     dst!=src1,2  dst==src1  dst==src2
+C P6 model 0-8,10-12		-
+C P6 model 9   (Banias)		?
+C P6 model 13  (Dothan)		?
+C P4 model 0-1 (Willamette)	?
+C P4 model 2   (Northwood)	4	     6		6
+C P4 model 3-4 (Prescott)	4.25	     7.5	7.5
+
+defframe(PARAM_CARRY,20)
+defframe(PARAM_SIZE, 16)
+defframe(PARAM_SRC2, 12)
+defframe(PARAM_SRC1, 8)
+defframe(PARAM_DST,  4)
+
+dnl  re-use parameter space
+define(SAVE_EBX,`PARAM_SRC1')
+
+	TEXT
+	ALIGN(8)
+
+PROLOGUE(mpn_add_nc)
+deflit(`FRAME',0)
+	movd	PARAM_CARRY, %mm0
+	jmp	L(start_nc)
+EPILOGUE()
+
+	ALIGN(8)
+PROLOGUE(mpn_add_n)
+deflit(`FRAME',0)
+	pxor	%mm0, %mm0
+L(start_nc):
+	mov	PARAM_SRC1, %eax
+	mov	%ebx, SAVE_EBX
+	mov	PARAM_SRC2, %ebx
+	mov	PARAM_DST, %edx
+	mov	PARAM_SIZE, %ecx
+
+	lea	(%eax,%ecx,4), %eax	C src1 end
+	lea	(%ebx,%ecx,4), %ebx	C src2 end
+	lea	(%edx,%ecx,4), %edx	C dst end
+	neg	%ecx			C -size
+
+L(top):
+	C eax	src1 end
+	C ebx	src2 end
+	C ecx	counter, limbs, negative
+	C edx	dst end
+	C mm0	carry bit
+
+	movd	(%eax,%ecx,4), %mm1
+	movd	(%ebx,%ecx,4), %mm2
+	paddq	%mm2, %mm1
+
+	paddq	%mm1, %mm0
+	movd	%mm0, (%edx,%ecx,4)
+
+	psrlq	$32, %mm0
+
+	add	$1, %ecx
+	jnz	L(top)
+
+	movd	%mm0, %eax
+	mov	SAVE_EBX, %ebx
+	emms
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/pentium4/sse2/addlsh1_n.asm b/third_party/gmp/mpn/x86/pentium4/sse2/addlsh1_n.asm
new file mode 100644
index 0000000..93b63b2
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium4/sse2/addlsh1_n.asm
@@ -0,0 +1,108 @@
+dnl  Intel Pentium-4 mpn_addlsh1_n -- mpn x+2*y.
+
+dnl  Copyright 2001-2004, 2006 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C					cycles/limb
+C			     dst!=src1,2  dst==src1  dst==src2
+C P6 model 0-8,10-12		-
+C P6 model 9   (Banias)		?
+C P6 model 13  (Dothan)		?
+C P4 model 0-1 (Willamette)	?
+C P4 model 2   (Northwood)	4.25	     6		6
+C P4 model 3-4 (Prescott)	5	     8.5	8.5
+
+C The slightly strange combination of indexing and pointer incrementing
+C that's used seems to work best.  Not sure why, but %ecx,4 with src1 and/or
+C src2 is a slowdown.
+C
+C The dependent chain is simply the paddq of x+2*y to the previous carry,
+C then psrlq to get the new carry.  That makes 4 c/l the target speed, which
+C is almost achieved for separate src/dst but when src==dst the write
+C combining anomalies slow it down.
+
+defframe(PARAM_SIZE, 16)
+defframe(PARAM_SRC2, 12)
+defframe(PARAM_SRC1, 8)
+defframe(PARAM_DST,  4)
+
+dnl  re-use parameter space
+define(SAVE_EBX,`PARAM_SRC1')
+
+	TEXT
+	ALIGN(8)
+
+PROLOGUE(mpn_addlsh1_n)
+deflit(`FRAME',0)
+
+	mov	PARAM_SRC1, %eax
+	mov	%ebx, SAVE_EBX
+
+	mov	PARAM_SRC2, %ebx
+	pxor	%mm0, %mm0		C initial carry
+
+	mov	PARAM_DST, %edx
+
+	mov	PARAM_SIZE, %ecx
+
+	lea	(%edx,%ecx,4), %edx	C dst end
+	neg	%ecx			C -size
+
+L(top):
+	C eax	src1 end
+	C ebx	src2 end
+	C ecx	counter, limbs, negative
+	C edx	dst end
+	C mm0	carry
+
+	movd	(%ebx), %mm2
+	movd	(%eax), %mm1
+	psrlq	$32, %mm0
+	lea	4(%eax), %eax
+	lea	4(%ebx), %ebx
+
+	psllq	$1, %mm2
+	paddq	%mm2, %mm1
+
+	paddq	%mm1, %mm0
+
+	movd	%mm0, (%edx,%ecx,4)
+	add	$1, %ecx
+	jnz	L(top)
+
+
+	psrlq	$32, %mm0
+	mov	SAVE_EBX, %ebx
+	movd	%mm0, %eax
+	emms
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/pentium4/sse2/addmul_1.asm b/third_party/gmp/mpn/x86/pentium4/sse2/addmul_1.asm
new file mode 100644
index 0000000..7810207
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium4/sse2/addmul_1.asm
@@ -0,0 +1,189 @@
+dnl  mpn_addmul_1 for Pentium 4 and P6 models with SSE2 (i.e., 9,D,E,F).
+
+dnl  Copyright 2005, 2007, 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+C			    cycles/limb
+C P6 model 0-8,10-12		-
+C P6 model 9   (Banias)		5.24
+C P6 model 13  (Dothan)		5.24
+C P4 model 0-1 (Willamette)	5
+C P4 model 2   (Northwood)	5
+C P4 model 3-4 (Prescott)	5
+
+C TODO:
+C  * Tweak eax/edx offsets in loop as to save some lea's
+C  * Perhaps software pipeline small-case code
+
+C INPUT PARAMETERS
+C rp		sp + 4
+C up		sp + 8
+C n		sp + 12
+C v0		sp + 16
+
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_addmul_1)
+	pxor	%mm6, %mm6
+L(ent):	mov	4(%esp), %edx
+	mov	8(%esp), %eax
+	mov	12(%esp), %ecx
+	movd	16(%esp), %mm7
+	cmp	$4, %ecx
+	jnc	L(big)
+
+L(lp0):	movd	(%eax), %mm0
+	lea	4(%eax), %eax
+	movd	(%edx), %mm4
+	lea	4(%edx), %edx
+	pmuludq	%mm7, %mm0
+	paddq	%mm0, %mm4
+	paddq	%mm4, %mm6
+	movd	%mm6, -4(%edx)
+	psrlq	$32, %mm6
+	dec	%ecx
+	jnz	L(lp0)
+	movd	%mm6, %eax
+	emms
+	ret
+
+L(big):	and	$3, %ecx
+	je	L(0)
+	cmp	$2, %ecx
+	jc	L(1)
+	je	L(2)
+	jmp	L(3)			C FIXME: one case should fall through
+
+L(0):	movd	(%eax), %mm3
+	sub	12(%esp), %ecx		C loop count
+	lea	-16(%eax), %eax
+	lea	-12(%edx), %edx
+	pmuludq	%mm7, %mm3
+	movd	20(%eax), %mm0
+	movd	12(%edx), %mm5
+	pmuludq	%mm7, %mm0
+	movd	24(%eax), %mm1
+	paddq	%mm3, %mm5
+	movd	16(%edx), %mm4
+	jmp	L(00)
+
+L(1):	movd	(%eax), %mm2
+	sub	12(%esp), %ecx
+	lea	-12(%eax), %eax
+	lea	-8(%edx), %edx
+	movd	8(%edx), %mm4
+	pmuludq	%mm7, %mm2
+	movd	16(%eax), %mm3
+	pmuludq	%mm7, %mm3
+	movd	20(%eax), %mm0
+	paddq	%mm2, %mm4
+	movd	12(%edx), %mm5
+	jmp	L(01)
+
+L(2):	movd	(%eax), %mm1
+	sub	12(%esp), %ecx
+	lea	-8(%eax), %eax
+	lea	-4(%edx), %edx
+	pmuludq	%mm7, %mm1
+	movd	12(%eax), %mm2
+	movd	4(%edx), %mm5
+	pmuludq	%mm7, %mm2
+	movd	16(%eax), %mm3
+	paddq	%mm1, %mm5
+	movd	8(%edx), %mm4
+	jmp	L(10)
+
+L(3):	movd	(%eax), %mm0
+	sub	12(%esp), %ecx
+	lea	-4(%eax), %eax
+	pmuludq	%mm7, %mm0
+	movd	8(%eax), %mm1
+	movd	(%edx), %mm4
+	pmuludq	%mm7, %mm1
+	movd	12(%eax), %mm2
+	paddq	%mm0, %mm4
+	movd	4(%edx), %mm5
+
+	ALIGN(16)
+L(top):	pmuludq	%mm7, %mm2
+	paddq	%mm4, %mm6
+	movd	16(%eax), %mm3
+	paddq	%mm1, %mm5
+	movd	8(%edx), %mm4
+	movd	%mm6, 0(%edx)
+	psrlq	$32, %mm6
+L(10):	pmuludq	%mm7, %mm3
+	paddq	%mm5, %mm6
+	movd	20(%eax), %mm0
+	paddq	%mm2, %mm4
+	movd	12(%edx), %mm5
+	movd	%mm6, 4(%edx)
+	psrlq	$32, %mm6
+L(01):	pmuludq	%mm7, %mm0
+	paddq	%mm4, %mm6
+	movd	24(%eax), %mm1
+	paddq	%mm3, %mm5
+	movd	16(%edx), %mm4
+	movd	%mm6, 8(%edx)
+	psrlq	$32, %mm6
+L(00):	pmuludq	%mm7, %mm1
+	paddq	%mm5, %mm6
+	movd	28(%eax), %mm2
+	paddq	%mm0, %mm4
+	movd	20(%edx), %mm5
+	movd	%mm6, 12(%edx)
+	psrlq	$32, %mm6
+	lea	16(%eax), %eax
+	lea	16(%edx), %edx
+	add	$4, %ecx
+	jnz	L(top)
+
+L(end):	pmuludq	%mm7, %mm2
+	paddq	%mm4, %mm6
+	paddq	%mm1, %mm5
+	movd	8(%edx), %mm4
+	movd	%mm6, 0(%edx)
+	psrlq	$32, %mm6
+	paddq	%mm5, %mm6
+	paddq	%mm2, %mm4
+	movd	%mm6, 4(%edx)
+	psrlq	$32, %mm6
+	paddq	%mm4, %mm6
+	movd	%mm6, 8(%edx)
+	psrlq	$32, %mm6
+	movd	%mm6, %eax
+	emms
+	ret
+EPILOGUE()
+PROLOGUE(mpn_addmul_1c)
+	movd	20(%esp), %mm6
+	jmp	L(ent)
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/pentium4/sse2/bdiv_dbm1c.asm b/third_party/gmp/mpn/x86/pentium4/sse2/bdiv_dbm1c.asm
new file mode 100644
index 0000000..354300e
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium4/sse2/bdiv_dbm1c.asm
@@ -0,0 +1,141 @@
+dnl  Intel Atom  mpn_bdiv_dbm1.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund and Marco Bodrato.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C			    cycles/limb
+C			    cycles/limb
+C P5				 -
+C P6 model 0-8,10-12		 -
+C P6 model 9  (Banias)		 9.75
+C P6 model 13 (Dothan)
+C P4 model 0  (Willamette)
+C P4 model 1  (?)
+C P4 model 2  (Northwood)	 8.25
+C P4 model 3  (Prescott)
+C P4 model 4  (Nocona)
+C Intel Atom			 8
+C AMD K6			 -
+C AMD K7			 -
+C AMD K8
+C AMD K10
+
+C TODO: This code was optimised for atom-32, consider moving it back to atom
+C	dir(atom currently grabs this code), and write a 4-way version(7c/l).
+
+defframe(PARAM_CARRY,20)
+defframe(PARAM_MUL,  16)
+defframe(PARAM_SIZE, 12)
+defframe(PARAM_SRC,  8)
+defframe(PARAM_DST,  4)
+
+dnl  re-use parameter space
+define(SAVE_RP,`PARAM_MUL')
+define(SAVE_UP,`PARAM_SIZE')
+
+define(`rp', `%edi')
+define(`up', `%esi')
+define(`n',  `%ecx')
+define(`reg', `%edx')
+define(`cy', `%eax')	C contains the return value
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+deflit(`FRAME',0)
+
+PROLOGUE(mpn_bdiv_dbm1c)
+	mov	PARAM_SIZE, n		C size
+	mov	up, SAVE_UP
+	mov	PARAM_SRC, up
+	movd	PARAM_MUL, %mm7
+	mov	rp, SAVE_RP
+	mov	PARAM_DST, rp
+
+	movd	(up), %mm0
+	pmuludq	%mm7, %mm0
+	shr	n
+	mov	PARAM_CARRY, cy
+	jz	L(eq1)
+
+	movd	4(up), %mm1
+	jc	L(odd)
+
+	lea	4(up), up
+	pmuludq	%mm7, %mm1
+	movd	%mm0, reg
+	psrlq	$32, %mm0
+	sub	reg, cy
+	movd	%mm0, reg
+	movq	%mm1, %mm0
+	dec	n
+	mov	cy, (rp)
+	lea	4(rp), rp
+	jz	L(end)
+
+C	ALIGN(16)
+L(top):	movd	4(up), %mm1
+	sbb	reg, cy
+L(odd):	movd	%mm0, reg
+	psrlq	$32, %mm0
+	pmuludq	%mm7, %mm1
+	sub	reg, cy
+	lea	8(up), up
+	movd	%mm0, reg
+	movd	(up), %mm0
+	mov	cy, (rp)
+	sbb	reg, cy
+	movd	%mm1, reg
+	psrlq	$32, %mm1
+	sub	reg, cy
+	movd	%mm1, reg
+	pmuludq	%mm7, %mm0
+	dec	n
+	mov	cy, 4(rp)
+	lea	8(rp), rp
+	jnz	L(top)
+
+L(end):	sbb	reg, cy
+
+L(eq1):	movd	%mm0, reg
+	psrlq	$32, %mm0
+	mov	SAVE_UP, up
+	sub	reg, cy
+	movd	%mm0, reg
+	emms
+	mov	cy, (rp)
+	sbb	reg, cy
+
+	mov	SAVE_RP, rp
+	ret
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86/pentium4/sse2/bdiv_q_1.asm b/third_party/gmp/mpn/x86/pentium4/sse2/bdiv_q_1.asm
new file mode 100644
index 0000000..d5008f4
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium4/sse2/bdiv_q_1.asm
@@ -0,0 +1,234 @@
+dnl  Intel Pentium-4 mpn_divexact_1 -- mpn by limb exact division.
+
+dnl  Rearranged from mpn/x86/pentium4/sse2/dive_1.asm by Marco Bodrato.
+
+dnl  Copyright 2001, 2002, 2007, 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C P4: 19.0 cycles/limb
+
+C Pairs of movd's are used to avoid unaligned loads.  Despite the loads not
+C being on the dependent chain and there being plenty of cycles available,
+C using an unaligned movq on every second iteration measured about 23 c/l.
+C
+
+defframe(PARAM_SHIFT,  24)
+defframe(PARAM_INVERSE,20)
+defframe(PARAM_DIVISOR,16)
+defframe(PARAM_SIZE,   12)
+defframe(PARAM_SRC,    8)
+defframe(PARAM_DST,    4)
+
+	TEXT
+
+C mp_limb_t
+C mpn_pi1_bdiv_q_1 (mp_ptr dst, mp_srcptr src, mp_size_t size, mp_limb_t divisor,
+C		    mp_limb_t inverse, int shift)
+	ALIGN(32)
+PROLOGUE(mpn_pi1_bdiv_q_1)
+deflit(`FRAME',0)
+
+	movl	PARAM_SIZE, %edx
+
+	movl	PARAM_SRC, %eax
+
+	movl	PARAM_DIVISOR, %ecx
+
+	movd	%ecx, %mm6
+	movl	PARAM_SHIFT, %ecx
+
+	movd	%ecx, %mm7		C shift
+
+	C
+
+	movl	PARAM_INVERSE, %ecx
+	movd	%ecx, %mm5		C inv
+
+	movl	PARAM_DST, %ecx
+	pxor	%mm1, %mm1		C initial carry limb
+	pxor	%mm0, %mm0		C initial carry bit
+
+	subl	$1, %edx
+	jz	L(done)
+
+	pcmpeqd	%mm4, %mm4
+	psrlq	$32, %mm4		C 0x00000000FFFFFFFF
+
+C The dependent chain here is as follows.
+C
+C					latency
+C	psubq	 s = (src-cbit) - climb	   2
+C	pmuludq	 q = s*inverse		   8
+C	pmuludq	 prod = q*divisor	   8
+C	psrlq	 climb = high(prod)	   2
+C					  --
+C					  20
+C
+C Yet the loop measures 19.0 c/l, so obviously there's something gained
+C there over a straight reading of the chip documentation.
+
+L(top):
+	C eax	src, incrementing
+	C ebx
+	C ecx	dst, incrementing
+	C edx	counter, size-1 iterations
+	C
+	C mm0	carry bit
+	C mm1	carry limb
+	C mm4	0x00000000FFFFFFFF
+	C mm5	inverse
+	C mm6	divisor
+	C mm7	shift
+
+	movd	(%eax), %mm2
+	movd	4(%eax), %mm3
+	addl	$4, %eax
+	punpckldq %mm3, %mm2
+
+	psrlq	%mm7, %mm2
+	pand	%mm4, %mm2		C src
+	psubq	%mm0, %mm2		C src - cbit
+
+	psubq	%mm1, %mm2		C src - cbit - climb
+	movq	%mm2, %mm0
+	psrlq	$63, %mm0		C new cbit
+
+	pmuludq	%mm5, %mm2		C s*inverse
+	movd	%mm2, (%ecx)		C q
+	addl	$4, %ecx
+
+	movq	%mm6, %mm1
+	pmuludq	%mm2, %mm1		C q*divisor
+	psrlq	$32, %mm1		C new climb
+
+L(entry):
+	subl	$1, %edx
+	jnz	L(top)
+
+L(done):
+	movd	(%eax), %mm2
+	psrlq	%mm7, %mm2		C src
+	psubq	%mm0, %mm2		C src - cbit
+
+	psubq	%mm1, %mm2		C src - cbit - climb
+
+	pmuludq	%mm5, %mm2		C s*inverse
+	movd	%mm2, (%ecx)		C q
+
+	emms
+	ret
+
+EPILOGUE()
+
+	ALIGN(16)
+C mp_limb_t mpn_bdiv_q_1 (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                           mp_limb_t divisor);
+C
+PROLOGUE(mpn_bdiv_q_1)
+deflit(`FRAME',0)
+
+	movl	PARAM_SIZE, %edx
+
+	movl	PARAM_DIVISOR, %ecx
+
+	C eax	src
+	C ebx
+	C ecx	divisor
+	C edx	size-1
+
+	movl	%ecx, %eax
+	bsfl	%ecx, %ecx		C trailing twos
+
+	shrl	%cl, %eax		C d = divisor without twos
+	movd	%eax, %mm6
+	movd	%ecx, %mm7		C shift
+
+	shrl	%eax			C d/2
+
+	andl	$127, %eax		C d/2, 7 bits
+
+ifdef(`PIC',`
+	LEA(	binvert_limb_table, %ecx)
+	movzbl	(%eax,%ecx), %eax		C inv 8 bits
+',`
+	movzbl	binvert_limb_table(%eax), %eax	C inv 8 bits
+')
+
+	C
+
+	movd	%eax, %mm5		C inv
+
+	movd	%eax, %mm0		C inv
+
+	pmuludq	%mm5, %mm5		C inv*inv
+
+	C
+
+	pmuludq	%mm6, %mm5		C inv*inv*d
+	paddd	%mm0, %mm0		C 2*inv
+
+	C
+
+	psubd	%mm5, %mm0		C inv = 2*inv - inv*inv*d
+	pxor	%mm5, %mm5
+
+	paddd	%mm0, %mm5
+	pmuludq	%mm0, %mm0		C inv*inv
+
+	pcmpeqd	%mm4, %mm4
+	psrlq	$32, %mm4		C 0x00000000FFFFFFFF
+
+	C
+
+	pmuludq	%mm6, %mm0		C inv*inv*d
+	paddd	%mm5, %mm5		C 2*inv
+
+	movl	PARAM_SRC, %eax
+	movl	PARAM_DST, %ecx
+	pxor	%mm1, %mm1		C initial carry limb
+
+	C
+
+	psubd	%mm0, %mm5		C inv = 2*inv - inv*inv*d
+
+	ASSERT(e,`	C expect d*inv == 1 mod 2^GMP_LIMB_BITS
+	pushl	%eax	FRAME_pushl()
+	movq	%mm6, %mm0
+	pmuludq	%mm5, %mm0
+	movd	%mm0, %eax
+	cmpl	$1, %eax
+	popl	%eax	FRAME_popl()')
+
+	pxor	%mm0, %mm0		C initial carry bit
+	jmp	L(entry)
+
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86/pentium4/sse2/cnd_add_n.asm b/third_party/gmp/mpn/x86/pentium4/sse2/cnd_add_n.asm
new file mode 100644
index 0000000..b3f3474
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium4/sse2/cnd_add_n.asm
@@ -0,0 +1,95 @@
+dnl  Intel Pentium-4 mpn_cnd_add_n -- mpn addition.
+
+dnl  Copyright 2001, 2002, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C			    cycles/limb
+C P6 model 0-8,10-12		 -
+C P6 model 9   (Banias)		 ?
+C P6 model 13  (Dothan)		 4.67
+C P4 model 0-1 (Willamette)	 ?
+C P4 model 2   (Northwood)	 5
+C P4 model 3-4 (Prescott)	 5.25
+
+defframe(PARAM_SIZE, 20)
+defframe(PARAM_SRC2, 16)
+defframe(PARAM_SRC1, 12)
+defframe(PARAM_DST,  8)
+defframe(PARAM_CND,  4)
+
+dnl  re-use parameter space
+define(SAVE_EBX,`PARAM_SRC1')
+
+define(`cnd', `%mm3')
+
+	TEXT
+	ALIGN(8)
+
+	ALIGN(8)
+PROLOGUE(mpn_cnd_add_n)
+deflit(`FRAME',0)
+	pxor	%mm0, %mm0
+
+	mov	PARAM_CND, %eax
+	neg	%eax
+	sbb	%eax, %eax
+	movd	%eax, cnd
+
+	mov	PARAM_SRC1, %eax
+	mov	%ebx, SAVE_EBX
+	mov	PARAM_SRC2, %ebx
+	mov	PARAM_DST, %edx
+	mov	PARAM_SIZE, %ecx
+
+	lea	(%eax,%ecx,4), %eax	C src1 end
+	lea	(%ebx,%ecx,4), %ebx	C src2 end
+	lea	(%edx,%ecx,4), %edx	C dst end
+	neg	%ecx			C -size
+
+L(top):	movd	(%ebx,%ecx,4), %mm2
+	movd	(%eax,%ecx,4), %mm1
+	pand	cnd, %mm2
+	paddq	%mm2, %mm1
+
+	paddq	%mm1, %mm0
+	movd	%mm0, (%edx,%ecx,4)
+
+	psrlq	$32, %mm0
+
+	add	$1, %ecx
+	jnz	L(top)
+
+	movd	%mm0, %eax
+	mov	SAVE_EBX, %ebx
+	emms
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/pentium4/sse2/cnd_sub_n.asm b/third_party/gmp/mpn/x86/pentium4/sse2/cnd_sub_n.asm
new file mode 100644
index 0000000..339a23e
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium4/sse2/cnd_sub_n.asm
@@ -0,0 +1,114 @@
+dnl  Intel Pentium-4 mpn_cnd_sub_n -- mpn subtraction.
+
+dnl  Copyright 2001, 2002, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C			    cycles/limb
+C P6 model 0-8,10-12		 -
+C P6 model 9   (Banias)		 ?
+C P6 model 13  (Dothan)		 4.67
+C P4 model 0-1 (Willamette)	 ?
+C P4 model 2   (Northwood)	 5
+C P4 model 3-4 (Prescott)	 5.25
+
+defframe(PARAM_SIZE, 20)
+defframe(PARAM_SRC2, 16)
+defframe(PARAM_SRC1, 12)
+defframe(PARAM_DST,  8)
+defframe(PARAM_CND,  4)
+
+dnl  re-use parameter space
+define(SAVE_EBX,`PARAM_SRC1')
+
+define(`cnd', `%mm3')
+
+	TEXT
+	ALIGN(8)
+
+	ALIGN(8)
+PROLOGUE(mpn_cnd_sub_n)
+deflit(`FRAME',0)
+	pxor	%mm0, %mm0
+
+	mov	PARAM_CND, %eax
+	neg	%eax
+	sbb	%eax, %eax
+	movd	%eax, cnd
+
+	mov	PARAM_SRC1, %eax
+	mov	%ebx, SAVE_EBX
+	mov	PARAM_SRC2, %ebx
+	mov	PARAM_DST, %edx
+	mov	PARAM_SIZE, %ecx
+
+	lea	(%eax,%ecx,4), %eax	C src1 end
+	lea	(%ebx,%ecx,4), %ebx	C src2 end
+	lea	(%edx,%ecx,4), %edx	C dst end
+	neg	%ecx			C -size
+
+L(top):	movd	(%ebx,%ecx,4), %mm2
+	movd	(%eax,%ecx,4), %mm1
+	pand	cnd, %mm2
+	psubq	%mm2, %mm1
+
+	psubq	%mm0, %mm1
+	movd	%mm1, (%edx,%ecx,4)
+
+	psrlq	$63, %mm1
+
+	add	$1, %ecx
+	jz	L(done_mm1)
+
+	movd	(%ebx,%ecx,4), %mm2
+	movd	(%eax,%ecx,4), %mm0
+	pand	cnd, %mm2
+	psubq	%mm2, %mm0
+
+	psubq	%mm1, %mm0
+	movd	%mm0, (%edx,%ecx,4)
+
+	psrlq	$63, %mm0
+
+	add	$1, %ecx
+	jnz	L(top)
+
+	movd	%mm0, %eax
+	mov	SAVE_EBX, %ebx
+	emms
+	ret
+
+L(done_mm1):
+	movd	%mm1, %eax
+	mov	SAVE_EBX, %ebx
+	emms
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/pentium4/sse2/dive_1.asm b/third_party/gmp/mpn/x86/pentium4/sse2/dive_1.asm
new file mode 100644
index 0000000..0ceef5b
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium4/sse2/dive_1.asm
@@ -0,0 +1,216 @@
+dnl  Intel Pentium-4 mpn_divexact_1 -- mpn by limb exact division.
+
+dnl  Copyright 2001, 2002, 2007 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C P4: 19.0 cycles/limb
+
+
+C void mpn_divexact_1 (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                      mp_limb_t divisor);
+C
+C Pairs of movd's are used to avoid unaligned loads.  Despite the loads not
+C being on the dependent chain and there being plenty of cycles available,
+C using an unaligned movq on every second iteration measured about 23 c/l.
+C
+C Using divl for size==1 seems a touch quicker than mul-by-inverse.  The mul
+C will be about 9+2*4+2*2+10*4+19+12 = 92 cycles latency, though some of
+C that might be hidden by out-of-order execution, whereas divl is around 60.
+C At size==2 an extra 19 for the mul versus 60 for the divl will see the mul
+C faster.
+
+defframe(PARAM_DIVISOR,16)
+defframe(PARAM_SIZE,   12)
+defframe(PARAM_SRC,    8)
+defframe(PARAM_DST,    4)
+
+	TEXT
+
+	ALIGN(16)
+PROLOGUE(mpn_divexact_1)
+deflit(`FRAME',0)
+
+	movl	PARAM_SIZE, %edx
+
+	movl	PARAM_SRC, %eax
+
+	movl	PARAM_DIVISOR, %ecx
+	subl	$1, %edx
+	jnz	L(two_or_more)
+
+	movl	(%eax), %eax
+	xorl	%edx, %edx
+
+	divl	%ecx
+	movl	PARAM_DST, %ecx
+
+	movl	%eax, (%ecx)
+	ret
+
+
+L(two_or_more):
+	C eax	src
+	C ebx
+	C ecx	divisor
+	C edx	size-1
+
+	movl	%ecx, %eax
+	bsfl	%ecx, %ecx		C trailing twos
+
+	shrl	%cl, %eax		C d = divisor without twos
+	movd	%eax, %mm6
+	movd	%ecx, %mm7		C shift
+
+	shrl	%eax			C d/2
+
+	andl	$127, %eax		C d/2, 7 bits
+
+ifdef(`PIC',`
+	LEA(	binvert_limb_table, %ecx)
+	movzbl	(%eax,%ecx), %eax		C inv 8 bits
+',`
+	movzbl	binvert_limb_table(%eax), %eax	C inv 8 bits
+')
+
+	C
+
+	movd	%eax, %mm5		C inv
+
+	movd	%eax, %mm0		C inv
+
+	pmuludq	%mm5, %mm5		C inv*inv
+
+	C
+
+	pmuludq	%mm6, %mm5		C inv*inv*d
+	paddd	%mm0, %mm0		C 2*inv
+
+	C
+
+	psubd	%mm5, %mm0		C inv = 2*inv - inv*inv*d
+	pxor	%mm5, %mm5
+
+	paddd	%mm0, %mm5
+	pmuludq	%mm0, %mm0		C inv*inv
+
+	pcmpeqd	%mm4, %mm4
+	psrlq	$32, %mm4		C 0x00000000FFFFFFFF
+
+	C
+
+	pmuludq	%mm6, %mm0		C inv*inv*d
+	paddd	%mm5, %mm5		C 2*inv
+
+	movl	PARAM_SRC, %eax
+	movl	PARAM_DST, %ecx
+	pxor	%mm1, %mm1		C initial carry limb
+
+	C
+
+	psubd	%mm0, %mm5		C inv = 2*inv - inv*inv*d
+
+	ASSERT(e,`	C expect d*inv == 1 mod 2^GMP_LIMB_BITS
+	pushl	%eax	FRAME_pushl()
+	movq	%mm6, %mm0
+	pmuludq	%mm5, %mm0
+	movd	%mm0, %eax
+	cmpl	$1, %eax
+	popl	%eax	FRAME_popl()')
+
+	pxor	%mm0, %mm0		C initial carry bit
+
+
+C The dependent chain here is as follows.
+C
+C					latency
+C	psubq	 s = (src-cbit) - climb	   2
+C	pmuludq	 q = s*inverse		   8
+C	pmuludq	 prod = q*divisor	   8
+C	psrlq	 climb = high(prod)	   2
+C					  --
+C					  20
+C
+C Yet the loop measures 19.0 c/l, so obviously there's something gained
+C there over a straight reading of the chip documentation.
+
+L(top):
+	C eax	src, incrementing
+	C ebx
+	C ecx	dst, incrementing
+	C edx	counter, size-1 iterations
+	C
+	C mm0	carry bit
+	C mm1	carry limb
+	C mm4	0x00000000FFFFFFFF
+	C mm5	inverse
+	C mm6	divisor
+	C mm7	shift
+
+	movd	(%eax), %mm2
+	movd	4(%eax), %mm3
+	addl	$4, %eax
+	punpckldq %mm3, %mm2
+
+	psrlq	%mm7, %mm2
+	pand	%mm4, %mm2		C src
+	psubq	%mm0, %mm2		C src - cbit
+
+	psubq	%mm1, %mm2		C src - cbit - climb
+	movq	%mm2, %mm0
+	psrlq	$63, %mm0		C new cbit
+
+	pmuludq	%mm5, %mm2		C s*inverse
+	movd	%mm2, (%ecx)		C q
+	addl	$4, %ecx
+
+	movq	%mm6, %mm1
+	pmuludq	%mm2, %mm1		C q*divisor
+	psrlq	$32, %mm1		C new climb
+
+	subl	$1, %edx
+	jnz	L(top)
+
+
+L(done):
+	movd	(%eax), %mm2
+	psrlq	%mm7, %mm2		C src
+	psubq	%mm0, %mm2		C src - cbit
+
+	psubq	%mm1, %mm2		C src - cbit - climb
+
+	pmuludq	%mm5, %mm2		C s*inverse
+	movd	%mm2, (%ecx)		C q
+
+	emms
+	ret
+
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86/pentium4/sse2/divrem_1.asm b/third_party/gmp/mpn/x86/pentium4/sse2/divrem_1.asm
new file mode 100644
index 0000000..0146fab
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium4/sse2/divrem_1.asm
@@ -0,0 +1,645 @@
+dnl  Intel Pentium-4 mpn_divrem_1 -- mpn by limb division.
+
+dnl  Copyright 1999-2004 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C P4: 32 cycles/limb integer part, 30 cycles/limb fraction part.
+
+
+C mp_limb_t mpn_divrem_1 (mp_ptr dst, mp_size_t xsize,
+C                         mp_srcptr src, mp_size_t size,
+C                         mp_limb_t divisor);
+C mp_limb_t mpn_divrem_1c (mp_ptr dst, mp_size_t xsize,
+C                          mp_srcptr src, mp_size_t size,
+C                          mp_limb_t divisor, mp_limb_t carry);
+C mp_limb_t mpn_preinv_divrem_1 (mp_ptr dst, mp_size_t xsize,
+C                                mp_srcptr src, mp_size_t size,
+C                                mp_limb_t divisor, mp_limb_t inverse,
+C                                unsigned shift);
+C
+C Algorithm:
+C
+C The method and nomenclature follow part 8 of "Division by Invariant
+C Integers using Multiplication" by Granlund and Montgomery, reference in
+C gmp.texi.
+C
+C "m" is written for what is m' in the paper, and "d" for d_norm, which
+C won't cause any confusion since it's only the normalized divisor that's of
+C any use in the code.  "b" is written for 2^N, the size of a limb, N being
+C 32 here.
+C
+C The step "sdword dr = n - 2^N*d + (2^N-1-q1) * d" is instead done as
+C "n-d - q1*d".  This rearrangement gives the same two-limb answer but lets
+C us have just a psubq on the dependent chain.
+C
+C For reference, the way the k7 code uses "n-(q1+1)*d" would not suit here,
+C detecting an overflow of q1+1 when q1=0xFFFFFFFF would cost too much.
+C
+C Notes:
+C
+C mpn_divrem_1 and mpn_preinv_divrem_1 avoid one division if the src high
+C limb is less than the divisor.  mpn_divrem_1c doesn't check for a zero
+C carry, since in normal circumstances that will be a very rare event.
+C
+C The test for skipping a division is branch free (once size>=1 is tested).
+C The store to the destination high limb is 0 when a divide is skipped, or
+C if it's not skipped then a copy of the src high limb is stored.  The
+C latter is in case src==dst.
+C
+C There's a small bias towards expecting xsize==0, by having code for
+C xsize==0 in a straight line and xsize!=0 under forward jumps.
+C
+C Enhancements:
+C
+C The loop measures 32 cycles, but the dependent chain would suggest it
+C could be done with 30.  Not sure where to start looking for the extras.
+C
+C Alternatives:
+C
+C If the divisor is normalized (high bit set) then a division step can
+C always be skipped, since the high destination limb is always 0 or 1 in
+C that case.  It doesn't seem worth checking for this though, since it
+C probably occurs infrequently.
+
+
+dnl  MUL_THRESHOLD is the value of xsize+size at which the multiply by
+dnl  inverse method is used, rather than plain "divl"s.  Minimum value 1.
+dnl
+dnl  The inverse takes about 80-90 cycles to calculate, but after that the
+dnl  multiply is 32 c/l versus division at about 58 c/l.
+dnl
+dnl  At 4 limbs the div is a touch faster than the mul (and of course
+dnl  simpler), so start the mul from 5 limbs.
+
+deflit(MUL_THRESHOLD, 5)
+
+
+defframe(PARAM_PREINV_SHIFT,   28)  dnl mpn_preinv_divrem_1
+defframe(PARAM_PREINV_INVERSE, 24)  dnl mpn_preinv_divrem_1
+defframe(PARAM_CARRY,  24)          dnl mpn_divrem_1c
+defframe(PARAM_DIVISOR,20)
+defframe(PARAM_SIZE,   16)
+defframe(PARAM_SRC,    12)
+defframe(PARAM_XSIZE,  8)
+defframe(PARAM_DST,    4)
+
+dnl  re-use parameter space
+define(SAVE_ESI,`PARAM_SIZE')
+define(SAVE_EBP,`PARAM_SRC')
+define(SAVE_EDI,`PARAM_DIVISOR')
+define(SAVE_EBX,`PARAM_DST')
+
+	TEXT
+
+	ALIGN(16)
+PROLOGUE(mpn_preinv_divrem_1)
+deflit(`FRAME',0)
+
+	movl	PARAM_SIZE, %ecx
+	xorl	%edx, %edx		C carry if can't skip a div
+
+	movl	%esi, SAVE_ESI
+	movl	PARAM_SRC, %esi
+
+	movl	%ebp, SAVE_EBP
+	movl	PARAM_DIVISOR, %ebp
+
+	movl	%edi, SAVE_EDI
+	movl	PARAM_DST, %edi
+
+	movl	-4(%esi,%ecx,4), %eax	C src high limb
+
+	movl	%ebx, SAVE_EBX
+	movl	PARAM_XSIZE, %ebx
+
+	movd	PARAM_PREINV_INVERSE, %mm4
+
+	movd	PARAM_PREINV_SHIFT, %mm7  C l
+	cmpl	%ebp, %eax		C high cmp divisor
+
+	cmovc(	%eax, %edx)		C high is carry if high<divisor
+	movd	%edx, %mm0		C carry
+
+	movd	%edx, %mm1		C carry
+	movl	$0, %edx
+
+	movd	%ebp, %mm5		C d
+	cmovnc(	%eax, %edx)		C 0 if skip div, src high if not
+					C (the latter in case src==dst)
+	leal	-4(%edi,%ebx,4), %edi	C &dst[xsize-1]
+
+	movl	%edx, (%edi,%ecx,4)	C dst high limb
+	sbbl	$0, %ecx		C skip one division if high<divisor
+	movl	$32, %eax
+
+	subl	PARAM_PREINV_SHIFT, %eax
+	psllq	%mm7, %mm5		C d normalized
+	leal	(%edi,%ecx,4), %edi	C &dst[xsize+size-1]
+	leal	-4(%esi,%ecx,4), %esi	C &src[size-1]
+
+	movd	%eax, %mm6		C 32-l
+	jmp	L(start_preinv)
+
+EPILOGUE()
+
+
+	ALIGN(16)
+PROLOGUE(mpn_divrem_1c)
+deflit(`FRAME',0)
+
+	movl	PARAM_CARRY, %edx
+
+	movl	PARAM_SIZE, %ecx
+
+	movl	%esi, SAVE_ESI
+	movl	PARAM_SRC, %esi
+
+	movl	%ebp, SAVE_EBP
+	movl	PARAM_DIVISOR, %ebp
+
+	movl	%edi, SAVE_EDI
+	movl	PARAM_DST, %edi
+
+	movl	%ebx, SAVE_EBX
+	movl	PARAM_XSIZE, %ebx
+
+	leal	-4(%edi,%ebx,4), %edi	C &dst[xsize-1]
+	jmp	L(start_1c)
+
+EPILOGUE()
+
+
+	ALIGN(16)
+PROLOGUE(mpn_divrem_1)
+deflit(`FRAME',0)
+
+	movl	PARAM_SIZE, %ecx
+	xorl	%edx, %edx		C initial carry (if can't skip a div)
+
+	movl	%esi, SAVE_ESI
+	movl	PARAM_SRC, %esi
+
+	movl	%ebp, SAVE_EBP
+	movl	PARAM_DIVISOR, %ebp
+
+	movl	%edi, SAVE_EDI
+	movl	PARAM_DST, %edi
+
+	movl	%ebx, SAVE_EBX
+	movl	PARAM_XSIZE, %ebx
+	leal	-4(%edi,%ebx,4), %edi	C &dst[xsize-1]
+
+	orl	%ecx, %ecx		C size
+	jz	L(no_skip_div)		C if size==0
+	movl	-4(%esi,%ecx,4), %eax	C src high limb
+
+	cmpl	%ebp, %eax		C high cmp divisor
+
+	cmovnc(	%eax, %edx)		C 0 if skip div, src high if not
+	movl	%edx, (%edi,%ecx,4)	C dst high limb
+
+	movl	$0, %edx
+	cmovc(	%eax, %edx)		C high is carry if high<divisor
+
+	sbbl	$0, %ecx		C size-1 if high<divisor
+L(no_skip_div):
+
+
+L(start_1c):
+	C eax
+	C ebx	xsize
+	C ecx	size
+	C edx	carry
+	C esi	src
+	C edi	&dst[xsize-1]
+	C ebp	divisor
+
+	leal	(%ebx,%ecx), %eax	C size+xsize
+	leal	-4(%esi,%ecx,4), %esi	C &src[size-1]
+	leal	(%edi,%ecx,4), %edi	C &dst[size+xsize-1]
+
+	cmpl	$MUL_THRESHOLD, %eax
+	jae	L(mul_by_inverse)
+
+
+	orl	%ecx, %ecx
+	jz	L(divide_no_integer)	C if size==0
+
+L(divide_integer):
+	C eax	scratch (quotient)
+	C ebx	xsize
+	C ecx	counter
+	C edx	carry
+	C esi	src, decrementing
+	C edi	dst, decrementing
+	C ebp	divisor
+
+	movl	(%esi), %eax
+	subl	$4, %esi
+
+	divl	%ebp
+
+	movl	%eax, (%edi)
+	subl	$4, %edi
+
+	subl	$1, %ecx
+	jnz	L(divide_integer)
+
+
+L(divide_no_integer):
+	orl	%ebx, %ebx
+	jnz	L(divide_fraction)	C if xsize!=0
+
+L(divide_done):
+	movl	SAVE_ESI, %esi
+	movl	SAVE_EDI, %edi
+	movl	SAVE_EBX, %ebx
+	movl	SAVE_EBP, %ebp
+	movl	%edx, %eax
+	ret
+
+
+L(divide_fraction):
+	C eax	scratch (quotient)
+	C ebx	counter
+	C ecx
+	C edx	carry
+	C esi
+	C edi	dst, decrementing
+	C ebp	divisor
+
+	movl	$0, %eax
+
+	divl	%ebp
+
+	movl	%eax, (%edi)
+	subl	$4, %edi
+
+	subl	$1, %ebx
+	jnz	L(divide_fraction)
+
+	jmp	L(divide_done)
+
+
+
+C -----------------------------------------------------------------------------
+
+L(mul_by_inverse):
+	C eax
+	C ebx	xsize
+	C ecx	size
+	C edx	carry
+	C esi	&src[size-1]
+	C edi	&dst[size+xsize-1]
+	C ebp	divisor
+
+	bsrl	%ebp, %eax		C 31-l
+	movd	%edx, %mm0		C carry
+	movd	%edx, %mm1		C carry
+	movl	%ecx, %edx		C size
+	movl	$31, %ecx
+
+	C
+
+	xorl	%eax, %ecx		C l = leading zeros on d
+	addl	$1, %eax
+
+	shll	%cl, %ebp		C d normalized
+	movd	%ecx, %mm7		C l
+	movl	%edx, %ecx		C size
+
+	movd	%eax, %mm6		C 32-l
+	movl	$-1, %edx
+	movl	$-1, %eax
+
+	C
+
+	subl	%ebp, %edx		C (b-d)-1 so  edx:eax = b*(b-d)-1
+
+	divl	%ebp			C floor (b*(b-d)-1 / d)
+	movd	%ebp, %mm5		C d
+
+	C
+
+	movd	%eax, %mm4		C m
+
+
+L(start_preinv):
+	C eax	inverse
+	C ebx	xsize
+	C ecx	size
+	C edx
+	C esi	&src[size-1]
+	C edi	&dst[size+xsize-1]
+	C ebp
+	C
+	C mm0	carry
+	C mm1	carry
+	C mm2
+	C mm4	m
+	C mm5	d
+	C mm6	31-l
+	C mm7	l
+
+	psllq	%mm7, %mm0		C n2 = carry << l, for size==0
+
+	subl	$1, %ecx
+	jb	L(integer_none)
+
+	movd	(%esi), %mm0		C src high limb
+	punpckldq %mm1, %mm0
+	psrlq	%mm6, %mm0		C n2 = high (carry:srchigh << l)
+	jz	L(integer_last)
+
+
+C The dependent chain here consists of
+C
+C	2   paddd    n1+n2
+C	8   pmuludq  m*(n1+n2)
+C	2   paddq    n2:nadj + m*(n1+n2)
+C	2   psrlq    q1
+C	8   pmuludq  d*q1
+C	2   psubq    (n-d)-q1*d
+C	2   psrlq    high n-(q1+1)*d mask
+C	2   pand     d masked
+C	2   paddd    n2+d addback
+C	--
+C	30
+C
+C But it seems to run at 32 cycles, so presumably there's something else
+C going on.
+
+	ALIGN(16)
+L(integer_top):
+	C eax
+	C ebx
+	C ecx	counter, size-1 to 0
+	C edx
+	C esi	src, decrementing
+	C edi	dst, decrementing
+	C
+	C mm0	n2
+	C mm4	m
+	C mm5	d
+	C mm6	32-l
+	C mm7	l
+
+	ASSERT(b,`C n2<d
+	 movd	%mm0, %eax
+	 movd	%mm5, %edx
+	 cmpl	%edx, %eax')
+
+	movd	-4(%esi), %mm1		C next src limbs
+	movd	(%esi), %mm2
+	leal	-4(%esi), %esi
+
+	punpckldq %mm2, %mm1
+	psrlq	%mm6, %mm1		C n10
+
+	movq	%mm1, %mm2		C n10
+	movq	%mm1, %mm3		C n10
+	psrad	$31, %mm1		C -n1
+	pand	%mm5, %mm1		C -n1 & d
+	paddd	%mm2, %mm1		C nadj = n10+(-n1&d), ignore overflow
+
+	psrld	$31, %mm2		C n1
+	paddd	%mm0, %mm2		C n2+n1
+	punpckldq %mm0, %mm1		C n2:nadj
+
+	pmuludq	%mm4, %mm2		C m*(n2+n1)
+
+	C
+
+	paddq	%mm2, %mm1		C n2:nadj + m*(n2+n1)
+	pxor	%mm2, %mm2		C break dependency, saves 4 cycles
+	pcmpeqd	%mm2, %mm2		C FF...FF
+	psrlq	$63, %mm2		C 1
+
+	psrlq	$32, %mm1		C q1 = high(n2:nadj + m*(n2+n1))
+
+	paddd	%mm1, %mm2		C q1+1
+	pmuludq	%mm5, %mm1		C q1*d
+
+	punpckldq %mm0, %mm3		C n = n2:n10
+	pxor	%mm0, %mm0
+
+	psubq	%mm5, %mm3		C n - d
+
+	C
+
+	psubq	%mm1, %mm3		C n - (q1+1)*d
+
+	por	%mm3, %mm0		C copy remainder -> new n2
+	psrlq	$32, %mm3		C high n - (q1+1)*d, 0 or -1
+
+	ASSERT(be,`C 0 or -1
+	 movd	%mm3, %eax
+	 addl	$1, %eax
+	 cmpl	$1, %eax')
+
+	paddd	%mm3, %mm2		C q
+	pand	%mm5, %mm3		C mask & d
+
+	paddd	%mm3, %mm0		C addback if necessary
+	movd	%mm2, (%edi)
+	leal	-4(%edi), %edi
+
+	subl	$1, %ecx
+	ja	L(integer_top)
+
+
+L(integer_last):
+	C eax
+	C ebx	xsize
+	C ecx
+	C edx
+	C esi	&src[0]
+	C edi	&dst[xsize]
+	C
+	C mm0	n2
+	C mm4	m
+	C mm5	d
+	C mm6
+	C mm7	l
+
+	ASSERT(b,`C n2<d
+	 movd	%mm0, %eax
+	 movd	%mm5, %edx
+	 cmpl	%edx, %eax')
+
+	movd	(%esi), %mm1		C src[0]
+	psllq	%mm7, %mm1		C n10
+
+	movq	%mm1, %mm2		C n10
+	movq	%mm1, %mm3		C n10
+	psrad	$31, %mm1		C -n1
+	pand	%mm5, %mm1		C -n1 & d
+	paddd	%mm2, %mm1		C nadj = n10+(-n1&d), ignore overflow
+
+	psrld	$31, %mm2		C n1
+	paddd	%mm0, %mm2		C n2+n1
+	punpckldq %mm0, %mm1		C n2:nadj
+
+	pmuludq	%mm4, %mm2		C m*(n2+n1)
+
+	C
+
+	paddq	%mm2, %mm1		C n2:nadj + m*(n2+n1)
+	pcmpeqd	%mm2, %mm2		C FF...FF
+	psrlq	$63, %mm2		C 1
+
+	psrlq	$32, %mm1		C q1 = high(n2:nadj + m*(n2+n1))
+	paddd	%mm1, %mm2		C q1
+
+	pmuludq	%mm5, %mm1		C q1*d
+	punpckldq %mm0, %mm3		C n
+	psubq	%mm5, %mm3		C n - d
+	pxor	%mm0, %mm0
+
+	C
+
+	psubq	%mm1, %mm3		C n - (q1+1)*d
+
+	por	%mm3, %mm0		C remainder -> n2
+	psrlq	$32, %mm3		C high n - (q1+1)*d, 0 or -1
+
+	ASSERT(be,`C 0 or -1
+	 movd	%mm3, %eax
+	 addl	$1, %eax
+	 cmpl	$1, %eax')
+
+	paddd	%mm3, %mm2		C q
+	pand	%mm5, %mm3		C mask & d
+
+	paddd	%mm3, %mm0		C addback if necessary
+	movd	%mm2, (%edi)
+	leal	-4(%edi), %edi
+
+
+L(integer_none):
+	C eax
+	C ebx	xsize
+
+	orl	%ebx, %ebx
+	jnz	L(fraction_some)	C if xsize!=0
+
+
+L(fraction_done):
+	movl	SAVE_EBP, %ebp
+	psrld	%mm7, %mm0		C remainder
+
+	movl	SAVE_EDI, %edi
+	movd	%mm0, %eax
+
+	movl	SAVE_ESI, %esi
+	movl	SAVE_EBX, %ebx
+	emms
+	ret
+
+
+
+C -----------------------------------------------------------------------------
+C
+
+L(fraction_some):
+	C eax
+	C ebx	xsize
+	C ecx
+	C edx
+	C esi
+	C edi	&dst[xsize-1]
+	C ebp
+
+
+L(fraction_top):
+	C eax
+	C ebx	counter, xsize iterations
+	C ecx
+	C edx
+	C esi	src, decrementing
+	C edi	dst, decrementing
+	C
+	C mm0	n2
+	C mm4	m
+	C mm5	d
+	C mm6	32-l
+	C mm7	l
+
+	ASSERT(b,`C n2<d
+	 movd	%mm0, %eax
+	 movd	%mm5, %edx
+	 cmpl	%edx, %eax')
+
+	movq	%mm0, %mm1		C n2
+	pmuludq	%mm4, %mm0		C m*n2
+
+	pcmpeqd	%mm2, %mm2
+	psrlq	$63, %mm2
+
+	C
+
+	psrlq	$32, %mm0		C high(m*n2)
+
+	paddd	%mm1, %mm0		C q1 = high(n2:0 + m*n2)
+
+	paddd	%mm0, %mm2		C q1+1
+	pmuludq	%mm5, %mm0		C q1*d
+
+	psllq	$32, %mm1		C n = n2:0
+	psubq	%mm5, %mm1		C n - d
+
+	C
+
+	psubq	%mm0, %mm1		C r = n - (q1+1)*d
+	pxor	%mm0, %mm0
+
+	por	%mm1, %mm0		C r -> n2
+	psrlq	$32, %mm1		C high n - (q1+1)*d, 0 or -1
+
+	ASSERT(be,`C 0 or -1
+	 movd	%mm1, %eax
+	 addl	$1, %eax
+	 cmpl	$1, %eax')
+
+	paddd	%mm1, %mm2		C q
+	pand	%mm5, %mm1		C mask & d
+
+	paddd	%mm1, %mm0		C addback if necessary
+	movd	%mm2, (%edi)
+	leal	-4(%edi), %edi
+
+	subl	$1, %ebx
+	jne	L(fraction_top)
+
+
+	jmp	L(fraction_done)
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/pentium4/sse2/gmp-mparam.h b/third_party/gmp/mpn/x86/pentium4/sse2/gmp-mparam.h
new file mode 100644
index 0000000..a047a51
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium4/sse2/gmp-mparam.h
@@ -0,0 +1,213 @@
+/* Intel Pentium-4 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+/* 2600 MHz P4 Northwood */
+/* FFT tuning limit = 23,700,309 */
+/* Generated by tuneup.c, 2019-11-09, gcc 8.2 */
+
+#define MOD_1_NORM_THRESHOLD                 5
+#define MOD_1_UNNORM_THRESHOLD              14
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          7
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          5
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        13
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD         0  /* never mpn_mod_1s_2p */
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD      7
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1N_PI1_METHOD                 2  /* 4.36% faster than 1 */
+#define DIV_QR_1_NORM_THRESHOLD             16
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           21
+
+#define DIV_1_VS_MUL_1_PERCENT             358
+
+#define MUL_TOOM22_THRESHOLD                26
+#define MUL_TOOM33_THRESHOLD               101
+#define MUL_TOOM44_THRESHOLD               284
+#define MUL_TOOM6H_THRESHOLD               406
+#define MUL_TOOM8H_THRESHOLD               592
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD     101
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     191
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     189
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     195
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     151
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 51
+#define SQR_TOOM3_THRESHOLD                163
+#define SQR_TOOM4_THRESHOLD                254
+#define SQR_TOOM6_THRESHOLD                614
+#define SQR_TOOM8_THRESHOLD                842
+
+#define MULMID_TOOM42_THRESHOLD             58
+
+#define MULMOD_BNM1_THRESHOLD               19
+#define SQRMOD_BNM1_THRESHOLD               23
+
+#define MUL_FFT_MODF_THRESHOLD             824  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    824, 5}, {     29, 6}, {     15, 5}, {     33, 6}, \
+    {     17, 5}, {     36, 6}, {     19, 5}, {     39, 6}, \
+    {     29, 7}, {     15, 6}, {     32, 7}, {     17, 6}, \
+    {     36, 7}, {     19, 6}, {     39, 7}, {     21, 6}, \
+    {     43, 7}, {     23, 6}, {     48, 7}, {     29, 8}, \
+    {     15, 7}, {     37, 8}, {     19, 7}, {     43, 8}, \
+    {     23, 7}, {     49, 8}, {     27, 7}, {     55, 8}, \
+    {     31, 7}, {     63, 8}, {     43, 9}, {     23, 8}, \
+    {     55, 9}, {     31, 8}, {     67, 9}, {     39, 8}, \
+    {     79, 9}, {     47, 8}, {     99, 9}, {     55,10}, \
+    {     31, 9}, {     79,10}, {     47, 9}, {    103,11}, \
+    {     31,10}, {     63, 9}, {    143,10}, {     79, 9}, \
+    {    167,10}, {     95, 9}, {    191,10}, {    111,11}, \
+    {     63,10}, {    127, 9}, {    255,10}, {    159,11}, \
+    {     95,10}, {    191,12}, {     63,11}, {    127,10}, \
+    {    271,11}, {    159,10}, {    319, 9}, {    639,10}, \
+    {    335,11}, {    191,10}, {    383, 9}, {    799,10}, \
+    {    415,11}, {    223,12}, {    127,11}, {    255,10}, \
+    {    527,11}, {    287,10}, {    607, 9}, {   1215,11}, \
+    {    319,10}, {    671,12}, {    191,11}, {    383,10}, \
+    {    799,11}, {    415,10}, {    863,13}, {    127,12}, \
+    {    255,11}, {    543,10}, {   1119, 9}, {   2239,11}, \
+    {    607,10}, {   1215,12}, {    319,11}, {    671,10}, \
+    {   1343,11}, {    735,10}, {   1471, 9}, {   2943,12}, \
+    {    383,11}, {    799,10}, {   1599,11}, {    863,12}, \
+    {    447,11}, {    927,10}, {   1855,11}, {    959,13}, \
+    {    255,12}, {    511,11}, {   1119,12}, {    575,11}, \
+    {   1215,10}, {   2431,11}, {   1247,12}, {    639,11}, \
+    {   1343,12}, {    703,11}, {   1471,10}, {   2943,13}, \
+    {    383,12}, {    767,11}, {   1599,12}, {    831,11}, \
+    {   1727,10}, {   3455,12}, {    895,14}, {    255,13}, \
+    {    511,12}, {   1087,11}, {   2239,10}, {   4479,12}, \
+    {   1215,11}, {   2431,13}, {    639,12}, {   1343,11}, \
+    {   2687,12}, {   1471,11}, {   2943,13}, {    767,12}, \
+    {   1727,11}, {   3455,13}, {    895,12}, {   1983,14}, \
+    {    511,13}, {   1023,12}, {   2239,13}, {   1151,12}, \
+    {   2495,11}, {   4991,13}, {   1407,12}, {   2943,14}, \
+    {    767,13}, {   1535,12}, {   3135,13}, {   1663,12}, \
+    {   3455,13}, {   1919,12}, {   3967,15}, {    511,14}, \
+    {   1023,13}, {   2175,12}, {   4479,13}, {   2431,12}, \
+    {   4991,14}, {   1279,13}, {   2687,12}, {   5503,13}, \
+    {   8192,14}, {  16384,15}, {  32768,16} }
+#define MUL_FFT_TABLE3_SIZE 167
+#define MUL_FFT_THRESHOLD                 7808
+
+#define SQR_FFT_MODF_THRESHOLD             560  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    560, 5}, {     33, 6}, {     17, 5}, {     35, 6}, \
+    {     33, 7}, {     17, 6}, {     36, 7}, {     19, 6}, \
+    {     39, 7}, {     35, 8}, {     19, 7}, {     43, 8}, \
+    {     23, 7}, {     47, 8}, {     27, 7}, {     55, 8}, \
+    {     31, 7}, {     63, 8}, {     43, 9}, {     23, 8}, \
+    {     55, 9}, {     31, 8}, {     67, 9}, {     39, 8}, \
+    {     79, 9}, {     47, 8}, {     95, 9}, {     55,10}, \
+    {     31, 9}, {     79,10}, {     47, 9}, {     95,11}, \
+    {     31,10}, {     63, 9}, {    135,10}, {     79, 9}, \
+    {    159,10}, {    111,11}, {     63,10}, {    143, 9}, \
+    {    287,10}, {    159,11}, {     95,10}, {    191,12}, \
+    {     63,11}, {    127, 9}, {    511, 8}, {   1023, 9}, \
+    {    527,11}, {    159,10}, {    319, 9}, {    639,10}, \
+    {    351,11}, {    191,10}, {    431,11}, {    223,12}, \
+    {    127,11}, {    255,10}, {    543,11}, {    287,10}, \
+    {    607, 9}, {   1215,11}, {    319,10}, {    639,11}, \
+    {    351,12}, {    191,11}, {    383,10}, {    767,11}, \
+    {    415,10}, {    831,13}, {    127,12}, {    255,11}, \
+    {    543,10}, {   1119,11}, {    607,12}, {    319,11}, \
+    {    671,10}, {   1343,11}, {    735,12}, {    383,11}, \
+    {    799,10}, {   1599,11}, {    863,12}, {    447,11}, \
+    {    927,10}, {   1855,11}, {    991,13}, {    255,12}, \
+    {    511,11}, {   1055,10}, {   2111,11}, {   1087,12}, \
+    {    575,11}, {   1215,10}, {   2431,12}, {    639,11}, \
+    {   1343,12}, {    703,11}, {   1407,13}, {    383,12}, \
+    {    767,11}, {   1599,12}, {    831,11}, {   1727,10}, \
+    {   3455,12}, {    895,11}, {   1855,12}, {    959,14}, \
+    {    255,13}, {    511,12}, {   1087,11}, {   2239,12}, \
+    {   1215,11}, {   2431,13}, {    639,12}, {   1471,11}, \
+    {   2943,13}, {    767,12}, {   1727,11}, {   3455,13}, \
+    {    895,12}, {   1983,14}, {    511,13}, {   1023,12}, \
+    {   2239,13}, {   1151,12}, {   2495,11}, {   4991,13}, \
+    {   1279,12}, {   2623,13}, {   1407,12}, {   2943,14}, \
+    {    767,13}, {   1663,12}, {   3455,13}, {   1919,12}, \
+    {   3839,15}, {    511,14}, {   1023,13}, {   2175,12}, \
+    {   4479,13}, {   2431,12}, {   4991,14}, {   1279,13}, \
+    {   2687,12}, {   5503,13}, {   8192,14}, {  16384,15}, \
+    {  32768,16} }
+#define SQR_FFT_TABLE3_SIZE 149
+#define SQR_FFT_THRESHOLD                 4800
+
+#define MULLO_BASECASE_THRESHOLD            12
+#define MULLO_DC_THRESHOLD                  44
+#define MULLO_MUL_N_THRESHOLD            14281
+#define SQRLO_BASECASE_THRESHOLD            13
+#define SQRLO_DC_THRESHOLD                  42
+#define SQRLO_SQR_THRESHOLD               9449
+
+#define DC_DIV_QR_THRESHOLD                 38
+#define DC_DIVAPPR_Q_THRESHOLD             105
+#define DC_BDIV_QR_THRESHOLD                52
+#define DC_BDIV_Q_THRESHOLD                 83
+
+#define INV_MULMOD_BNM1_THRESHOLD           50
+#define INV_NEWTON_THRESHOLD               158
+#define INV_APPR_THRESHOLD                 118
+
+#define BINV_NEWTON_THRESHOLD              342
+#define REDC_1_TO_REDC_N_THRESHOLD          67
+
+#define MU_DIV_QR_THRESHOLD               2130
+#define MU_DIVAPPR_Q_THRESHOLD            1895
+#define MUPI_DIV_QR_THRESHOLD               60
+#define MU_BDIV_QR_THRESHOLD              1652
+#define MU_BDIV_Q_THRESHOLD               2089
+
+#define POWM_SEC_TABLE  1,22,96,446,723,1378
+
+#define GET_STR_DC_THRESHOLD                13
+#define GET_STR_PRECOMPUTE_THRESHOLD        20
+#define SET_STR_DC_THRESHOLD               298
+#define SET_STR_PRECOMPUTE_THRESHOLD       960
+
+#define FAC_DSC_THRESHOLD                  212
+#define FAC_ODD_THRESHOLD                   71
+
+#define MATRIX22_STRASSEN_THRESHOLD         26
+#define HGCD2_DIV1_METHOD                    3  /* 0.68% faster than 1 */
+#define HGCD_THRESHOLD                      80
+#define HGCD_APPR_THRESHOLD                138
+#define HGCD_REDUCE_THRESHOLD             4455
+#define GCD_DC_THRESHOLD                   365
+#define GCDEXT_DC_THRESHOLD                245
+#define JACOBI_BASE_METHOD                   4  /* 23.41% faster than 1 */
+
+/* Tuneup completed successfully, took 63807 seconds */
diff --git a/third_party/gmp/mpn/x86/pentium4/sse2/mod_1_1.asm b/third_party/gmp/mpn/x86/pentium4/sse2/mod_1_1.asm
new file mode 100644
index 0000000..ee88bab
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium4/sse2/mod_1_1.asm
@@ -0,0 +1,166 @@
+dnl  x86-32 mpn_mod_1_1p for Pentium 4 and P6 models with SSE2 (i.e., 9,D,E,F).
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2009, 2010 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C TODO:
+C  * Optimize.  The present code was written quite straightforwardly.
+C  * Optimize post-loop reduction code; it is from mod_1s_4p, thus overkill.
+C  * Write a cps function that uses sse2 insns.
+
+C                           cycles/limb
+C P6 model 0-8,10-12		-
+C P6 model 9   (Banias)		?
+C P6 model 13  (Dothan)		?
+C P4 model 0-1 (Willamette)	?
+C P4 model 2   (Northwood)     16
+C P4 model 3-4 (Prescott)      18
+
+C INPUT PARAMETERS
+C ap		sp + 4
+C n		sp + 8
+C b		sp + 12
+C cps		sp + 16
+
+define(`B1modb', `%mm1')
+define(`B2modb', `%mm2')
+define(`ap',     `%edx')
+define(`n',      `%eax')
+
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_mod_1_1p)
+	push	%ebx
+	mov	8(%esp), ap
+	mov	12(%esp), n
+	mov	20(%esp), %ecx
+	movd	8(%ecx), B1modb
+	movd	12(%ecx), B2modb
+
+	lea	-4(ap,n,4), ap
+
+C FIXME: See comment in generic/mod_1_1.c.
+	movd	(ap), %mm7
+	movd	-4(ap), %mm4
+	pmuludq B1modb, %mm7
+	paddq	%mm4, %mm7
+	add	$-2, n
+	jz	L(end)
+
+	ALIGN(8)
+L(top):	movq	%mm7, %mm6
+	psrlq	$32, %mm7		C rh
+	movd	-8(ap), %mm0
+	add	$-4, ap
+	pmuludq	B2modb, %mm7
+	pmuludq	B1modb, %mm6
+	add	$-1, n
+	paddq	%mm0, %mm7
+	paddq	%mm6, %mm7
+	jnz	L(top)
+
+L(end):	pcmpeqd	%mm4, %mm4
+	psrlq	$32, %mm4		C 0x00000000FFFFFFFF
+	pand	%mm7, %mm4		C rl
+	psrlq	$32, %mm7		C rh
+	pmuludq	B1modb, %mm7		C rh,cl
+	paddq	%mm4, %mm7		C rh,rl
+	movd	4(%ecx), %mm4		C cnt
+	psllq	%mm4, %mm7		C rh,rl normalized
+	movq	%mm7, %mm2		C rl in low half
+	psrlq	$32, %mm7		C rh
+	movd	(%ecx), %mm1		C bi
+	pmuludq	%mm7, %mm1		C qh,ql
+	paddq	%mm2, %mm1		C qh-1,ql
+	movd	%mm1, %ecx		C ql
+	psrlq	$32, %mm1		C qh-1
+	movd	16(%esp), %mm3		C b
+	pmuludq	%mm1, %mm3		C (qh-1) * b
+	psubq	%mm3, %mm2		C r in low half (could use psubd)
+	movd	%mm2, %eax		C r
+	mov	16(%esp), %ebx
+	sub	%ebx, %eax		C r
+	cmp	%eax, %ecx
+	lea	(%eax,%ebx), %edx
+	cmovc(	%edx, %eax)
+	movd	%mm4, %ecx		C cnt
+	cmp	%ebx, %eax
+	jae	L(fix)
+	emms
+	pop	%ebx
+	shr	%cl, %eax
+	ret
+
+L(fix):	sub	%ebx, %eax
+	emms
+	pop	%ebx
+	shr	%cl, %eax
+	ret
+EPILOGUE()
+
+PROLOGUE(mpn_mod_1_1p_cps)
+C CAUTION: This is the same code as in k7/mod_1_1.asm
+	push	%ebp
+	mov	12(%esp), %ebp
+	push	%esi
+	bsr	%ebp, %ecx
+	push	%ebx
+	xor	$31, %ecx
+	mov	16(%esp), %esi
+	sal	%cl, %ebp
+	mov	%ebp, %edx
+	not	%edx
+	mov	$-1, %eax
+	div	%ebp
+	mov	%eax, (%esi)		C store bi
+	mov	%ecx, 4(%esi)		C store cnt
+	xor	%ebx, %ebx
+	sub	%ebp, %ebx
+	mov	$1, %edx
+	shld	%cl, %eax, %edx
+	imul	%edx, %ebx
+	mul	%ebx
+	add	%ebx, %edx
+	not	%edx
+	imul	%ebp, %edx
+	add	%edx, %ebp
+	cmp	%edx, %eax
+	cmovc(	%ebp, %edx)
+	shr	%cl, %ebx
+	mov	%ebx, 8(%esi)		C store B1modb
+	shr	%cl, %edx
+	mov	%edx, 12(%esi)		C store B2modb
+	pop	%ebx
+	pop	%esi
+	pop	%ebp
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/pentium4/sse2/mod_1_4.asm b/third_party/gmp/mpn/x86/pentium4/sse2/mod_1_4.asm
new file mode 100644
index 0000000..eb2edb6
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium4/sse2/mod_1_4.asm
@@ -0,0 +1,269 @@
+dnl  x86-32 mpn_mod_1s_4p for Pentium 4 and P6 models with SSE2 (i.e. 9,D,E,F).
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2009, 2010 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C TODO:
+C  * Optimize.  The present code was written quite straightforwardly.
+C  * Optimize post-loop reduction code.
+C  * Write a cps function that uses sse2 insns.
+
+C			    cycles/limb
+C P6 model 0-8,10-12		-
+C P6 model 9   (Banias)		?
+C P6 model 13  (Dothan)		3.4
+C P4 model 0-1 (Willamette)	?
+C P4 model 2   (Northwood)	4
+C P4 model 3-4 (Prescott)	4.5
+
+C INPUT PARAMETERS
+C ap		sp + 4
+C n		sp + 8
+C b		sp + 12
+C cps		sp + 16
+
+define(`B1modb', `%mm1')
+define(`B2modb', `%mm2')
+define(`B3modb', `%mm3')
+define(`B4modb', `%mm4')
+define(`B5modb', `%mm5')
+define(`ap',     `%edx')
+define(`n',      `%eax')
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_mod_1s_4p)
+	push	%ebx
+	mov	8(%esp), ap
+	mov	12(%esp), n
+	mov	20(%esp), %ecx
+
+	movd	8(%ecx), B1modb
+	movd	12(%ecx), B2modb
+	movd	16(%ecx), B3modb
+	movd	20(%ecx), B4modb
+	movd	24(%ecx), B5modb
+
+	mov	n, %ebx
+	lea	-4(ap,n,4), ap
+	and	$3, %ebx
+	je	L(b0)
+	cmp	$2, %ebx
+	jc	L(b1)
+	je	L(b2)
+
+L(b3):	movd	-4(ap), %mm7
+	pmuludq	B1modb, %mm7
+	movd	-8(ap), %mm6
+	paddq	%mm6, %mm7
+	movd	(ap), %mm6
+	pmuludq	B2modb, %mm6
+	paddq	%mm6, %mm7
+	lea	-24(ap), ap
+	add	$-3, n
+	jz	L(end)
+	jmp	L(top)
+
+L(b0):	movd	-8(ap), %mm7
+	pmuludq	B1modb, %mm7
+	movd	-12(ap), %mm6
+	paddq	%mm6, %mm7
+	movd	-4(ap), %mm6
+	pmuludq	B2modb, %mm6
+	paddq	%mm6, %mm7
+	movd	(ap), %mm6
+	pmuludq	B3modb, %mm6
+	paddq	%mm6, %mm7
+	lea	-28(ap), ap
+	add	$-4, n
+	jz	L(end)
+	jmp	L(top)
+
+L(b1):	movd	(ap), %mm7
+	lea	-16(ap), ap
+	dec	n
+	jz	L(x)
+	jmp	L(top)
+
+L(b2):	movd	-4(ap), %mm7		C rl
+	punpckldq (ap), %mm7		C rh
+	lea	-20(ap), ap
+	add	$-2, n
+	jz	L(end)
+
+	ALIGN(8)
+L(top):	movd	4(ap), %mm0
+	pmuludq	B1modb, %mm0
+	movd	0(ap), %mm6
+	paddq	%mm6, %mm0
+
+	movd	8(ap), %mm6
+	pmuludq	B2modb, %mm6
+	paddq	%mm6, %mm0
+
+	movd	12(ap), %mm6
+	pmuludq	B3modb, %mm6
+	paddq	%mm6, %mm0
+
+	movq	%mm7, %mm6
+	psrlq	$32, %mm7		C rh
+	pmuludq	B5modb, %mm7
+	pmuludq	B4modb, %mm6
+
+	paddq	%mm0, %mm7
+	paddq	%mm6, %mm7
+
+	add	$-16, ap
+	add	$-4, n
+	jnz	L(top)
+
+L(end):	pcmpeqd	%mm4, %mm4
+	psrlq	$32, %mm4		C 0x00000000FFFFFFFF
+	pand	%mm7, %mm4		C rl
+	psrlq	$32, %mm7		C rh
+	pmuludq	B1modb, %mm7		C rh,cl
+	paddq	%mm4, %mm7		C rh,rl
+L(x):	movd	4(%ecx), %mm4		C cnt
+	psllq	%mm4, %mm7		C rh,rl normalized
+	movq	%mm7, %mm2		C rl in low half
+	psrlq	$32, %mm7		C rh
+	movd	(%ecx), %mm1		C bi
+	pmuludq	%mm7, %mm1		C qh,ql
+	paddq	%mm2, %mm1		C qh-1,ql
+	movd	%mm1, %ecx		C ql
+	psrlq	$32, %mm1		C qh-1
+	movd	16(%esp), %mm3		C b
+	pmuludq	%mm1, %mm3		C (qh-1) * b
+	psubq	%mm3, %mm2		C r in low half (could use psubd)
+	movd	%mm2, %eax		C r
+	mov	16(%esp), %ebx
+	sub	%ebx, %eax		C r
+	cmp	%eax, %ecx
+	lea	(%eax,%ebx), %edx
+	cmovc(	%edx, %eax)
+	movd	%mm4, %ecx		C cnt
+	cmp	%ebx, %eax
+	jae	L(fix)
+	emms
+	pop	%ebx
+	shr	%cl, %eax
+	ret
+
+L(fix):	sub	%ebx, %eax
+	emms
+	pop	%ebx
+	shr	%cl, %eax
+	ret
+EPILOGUE()
+
+	ALIGN(16)
+PROLOGUE(mpn_mod_1s_4p_cps)
+C CAUTION: This is the same code as in k7/mod_1_4.asm
+	push	%ebp
+	push	%edi
+	push	%esi
+	push	%ebx
+	mov	20(%esp), %ebp		C FIXME: avoid bp for 0-idx
+	mov	24(%esp), %ebx
+	bsr	%ebx, %ecx
+	xor	$31, %ecx
+	sal	%cl, %ebx		C b << cnt
+	mov	%ebx, %edx
+	not	%edx
+	mov	$-1, %eax
+	div	%ebx
+	xor	%edi, %edi
+	sub	%ebx, %edi
+	mov	$1, %esi
+	mov	%eax, (%ebp)		C store bi
+	mov	%ecx, 4(%ebp)		C store cnt
+	shld	%cl, %eax, %esi
+	imul	%edi, %esi
+	mov	%eax, %edi
+	mul	%esi
+
+	add	%esi, %edx
+	shr	%cl, %esi
+	mov	%esi, 8(%ebp)		C store B1modb
+
+	not	%edx
+	imul	%ebx, %edx
+	lea	(%edx,%ebx), %esi
+	cmp	%edx, %eax
+	cmovnc(	%edx, %esi)
+	mov	%edi, %eax
+	mul	%esi
+
+	add	%esi, %edx
+	shr	%cl, %esi
+	mov	%esi, 12(%ebp)		C store B2modb
+
+	not	%edx
+	imul	%ebx, %edx
+	lea	(%edx,%ebx), %esi
+	cmp	%edx, %eax
+	cmovnc(	%edx, %esi)
+	mov	%edi, %eax
+	mul	%esi
+
+	add	%esi, %edx
+	shr	%cl, %esi
+	mov	%esi, 16(%ebp)		C store B3modb
+
+	not	%edx
+	imul	%ebx, %edx
+	lea	(%edx,%ebx), %esi
+	cmp	%edx, %eax
+	cmovnc(	%edx, %esi)
+	mov	%edi, %eax
+	mul	%esi
+
+	add	%esi, %edx
+	shr	%cl, %esi
+	mov	%esi, 20(%ebp)		C store B4modb
+
+	not	%edx
+	imul	%ebx, %edx
+	add	%edx, %ebx
+	cmp	%edx, %eax
+	cmovnc(	%edx, %ebx)
+
+	shr	%cl, %ebx
+	mov	%ebx, 24(%ebp)		C store B5modb
+
+	pop	%ebx
+	pop	%esi
+	pop	%edi
+	pop	%ebp
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/pentium4/sse2/mod_34lsub1.asm b/third_party/gmp/mpn/x86/pentium4/sse2/mod_34lsub1.asm
new file mode 100644
index 0000000..31e25b7
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium4/sse2/mod_34lsub1.asm
@@ -0,0 +1,175 @@
+dnl  Intel Pentium 4 mpn_mod_34lsub1 -- remainder modulo 2^24-1.
+
+dnl  Copyright 2000-2003 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C Pentium4: 1.0 cycles/limb
+
+
+C mp_limb_t mpn_mod_34lsub1 (mp_srcptr src, mp_size_t size)
+C
+C Enhancements:
+C
+C There might a couple of cycles to save by using plain integer code for
+C more small sizes.  2 limbs measures about 20 cycles, but 3 limbs jumps to
+C about 46 (inclusive of some function call overheads).
+
+defframe(PARAM_SIZE, 8)
+defframe(PARAM_SRC,  4)
+
+dnl  re-use parameter space
+define(SAVE_EBX, `PARAM_SRC')
+define(SAVE_ESI, `PARAM_SIZE')
+
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_mod_34lsub1)
+deflit(`FRAME',0)
+
+	movl	PARAM_SIZE, %ecx
+	movl	PARAM_SRC, %edx
+	movl	(%edx), %eax
+
+	subl	$2, %ecx
+	ja	L(three_or_more)
+	jne	L(one)
+
+	movl	4(%edx), %edx
+	movl	%eax, %ecx
+	shrl	$24, %eax		C src[0] high
+
+	andl	$0x00FFFFFF, %ecx	C src[0] low
+	addl	%ecx, %eax
+
+	movl	%edx, %ecx
+	shll	$8, %edx
+
+	shrl	$16, %ecx		C src[1] low
+	addl	%ecx, %eax
+
+	andl	$0x00FFFF00, %edx	C src[1] high
+	addl	%edx, %eax
+
+L(one):
+	ret
+
+
+L(three_or_more):
+	pxor	%mm0, %mm0
+	pxor	%mm1, %mm1
+	pxor	%mm2, %mm2
+
+	pcmpeqd	%mm7, %mm7
+	psrlq	$32, %mm7	C 0x00000000FFFFFFFF, low 32 bits
+
+	pcmpeqd	%mm6, %mm6
+	psrlq	$40, %mm6	C 0x0000000000FFFFFF, low 24 bits
+
+L(top):
+	C eax
+	C ebx
+	C ecx	counter, size-2 to 0, -1 or -2
+	C edx	src, incrementing
+	C
+	C mm0	sum 0mod3
+	C mm1	sum 1mod3
+	C mm2	sum 2mod3
+	C mm3
+	C mm4
+	C mm5
+	C mm6	0x0000000000FFFFFF
+	C mm7	0x00000000FFFFFFFF
+
+	movd	(%edx), %mm3
+	paddq	%mm3, %mm0
+
+	movd	4(%edx), %mm3
+	paddq	%mm3, %mm1
+
+	movd	8(%edx), %mm3
+	paddq	%mm3, %mm2
+
+	addl	$12, %edx
+	subl	$3, %ecx
+	ja	L(top)
+
+
+	C ecx is -2, -1 or 0 representing 0, 1 or 2 more limbs, respectively
+
+	addl	$1, %ecx
+	js	L(combine)		C 0 more
+
+	movd	(%edx), %mm3
+	paddq	%mm3, %mm0
+
+	jz	L(combine)		C 1 more
+
+	movd	4(%edx), %mm3
+	paddq	%mm3, %mm1
+
+L(combine):
+	movq	%mm7, %mm3		C low halves
+	pand	%mm0, %mm3
+
+	movq	%mm7, %mm4
+	pand	%mm1, %mm4
+
+	movq	%mm7, %mm5
+	pand	%mm2, %mm5
+
+	psrlq	$32, %mm0		C high halves
+	psrlq	$32, %mm1
+	psrlq	$32, %mm2
+
+	paddq	%mm0, %mm4		C fold high halves to give 33 bits each
+	paddq	%mm1, %mm5
+	paddq	%mm2, %mm3
+
+	psllq	$8, %mm4		C combine at respective offsets
+	psllq	$16, %mm5
+	paddq	%mm4, %mm3
+	paddq	%mm5, %mm3		C 0x000cxxxxxxxxxxxx, 50 bits
+
+	pand	%mm3, %mm6		C fold at 24 bits
+	psrlq	$24, %mm3
+
+	paddq	%mm6, %mm3
+	movd	%mm3, %eax
+
+	ASSERT(z,	C nothing left in high dword
+	`psrlq	$32, %mm3
+	movd	%mm3, %ecx
+	orl	%ecx, %ecx')
+
+	emms
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/pentium4/sse2/mode1o.asm b/third_party/gmp/mpn/x86/pentium4/sse2/mode1o.asm
new file mode 100644
index 0000000..aa9ef31
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium4/sse2/mode1o.asm
@@ -0,0 +1,175 @@
+dnl  Intel Pentium-4 mpn_modexact_1_odd -- mpn by limb exact remainder.
+
+dnl  Copyright 2001, 2002, 2007 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C P4: 19.0 cycles/limb
+
+
+C mp_limb_t mpn_modexact_1_odd (mp_srcptr src, mp_size_t size,
+C                               mp_limb_t divisor);
+C mp_limb_t mpn_modexact_1c_odd (mp_srcptr src, mp_size_t size,
+C                                mp_limb_t divisor, mp_limb_t carry);
+C
+
+defframe(PARAM_CARRY,  16)
+defframe(PARAM_DIVISOR,12)
+defframe(PARAM_SIZE,   8)
+defframe(PARAM_SRC,    4)
+
+	TEXT
+
+	ALIGN(16)
+PROLOGUE(mpn_modexact_1c_odd)
+deflit(`FRAME',0)
+
+	movd	PARAM_CARRY, %mm1
+	jmp	L(start_1c)
+
+EPILOGUE()
+
+
+	ALIGN(16)
+PROLOGUE(mpn_modexact_1_odd)
+deflit(`FRAME',0)
+
+	pxor	%mm1, %mm1		C carry limb
+L(start_1c):
+	movl	PARAM_DIVISOR, %eax
+
+	movd	PARAM_DIVISOR, %mm7
+
+	shrl	%eax
+
+	andl	$127, %eax		C d/2, 7 bits
+
+ifdef(`PIC',`
+	LEA(	binvert_limb_table, %edx)
+	movzbl	(%eax,%edx), %eax		C inv 8 bits
+',`
+	movzbl	binvert_limb_table(%eax), %eax	C inv 8 bits
+')
+
+	C
+
+	movd	%eax, %mm6		C inv
+
+	movd	%eax, %mm0		C inv
+
+	pmuludq	%mm6, %mm6		C inv*inv
+
+	C
+
+	pmuludq	%mm7, %mm6		C inv*inv*d
+	paddd	%mm0, %mm0		C 2*inv
+
+	C
+
+	psubd	%mm6, %mm0		C inv = 2*inv - inv*inv*d
+	pxor	%mm6, %mm6
+
+	paddd	%mm0, %mm6
+	pmuludq	%mm0, %mm0		C inv*inv
+
+	C
+
+	pmuludq	%mm7, %mm0		C inv*inv*d
+	paddd	%mm6, %mm6		C 2*inv
+
+
+	movl	PARAM_SRC, %eax
+	movl	PARAM_SIZE, %ecx
+
+	C
+
+	psubd	%mm0, %mm6		C inv = 2*inv - inv*inv*d
+
+	ASSERT(e,`	C expect d*inv == 1 mod 2^GMP_LIMB_BITS
+	pushl	%eax	FRAME_pushl()
+	movd	%mm6, %eax
+	imul	PARAM_DIVISOR, %eax
+	cmpl	$1, %eax
+	popl	%eax	FRAME_popl()')
+
+	pxor	%mm0, %mm0		C carry bit
+
+
+C The dependent chain here is as follows.
+C
+C					latency
+C	psubq	 s = (src-cbit) - climb	   2
+C	pmuludq	 q = s*inverse		   8
+C	pmuludq	 prod = q*divisor	   8
+C	psrlq	 climb = high(prod)	   2
+C					  --
+C					  20
+C
+C Yet the loop measures 19.0 c/l, so obviously there's something gained
+C there over a straight reading of the chip documentation.
+
+L(top):
+	C eax	src, incrementing
+	C ebx
+	C ecx	counter, limbs
+	C edx
+	C
+	C mm0	carry bit
+	C mm1	carry limb
+	C mm6	inverse
+	C mm7	divisor
+
+	movd	(%eax), %mm2
+	addl	$4, %eax
+
+	psubq	%mm0, %mm2		C src - cbit
+
+	psubq	%mm1, %mm2		C src - cbit - climb
+	movq	%mm2, %mm0
+	psrlq	$63, %mm0		C new cbit
+
+	pmuludq	%mm6, %mm2		C s*inverse
+
+	movq	%mm7, %mm1
+	pmuludq	%mm2, %mm1		C q*divisor
+	psrlq	$32, %mm1		C new climb
+
+	subl	$1, %ecx
+	jnz	L(top)
+
+
+L(done):
+	paddq	%mm1, %mm0
+	movd	%mm0, %eax
+	emms
+	ret
+
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86/pentium4/sse2/mul_1.asm b/third_party/gmp/mpn/x86/pentium4/sse2/mul_1.asm
new file mode 100644
index 0000000..6347b8b
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium4/sse2/mul_1.asm
@@ -0,0 +1,164 @@
+dnl  mpn_mul_1 for Pentium 4 and P6 models with SSE2 (i.e., 9,D,E,F).
+
+dnl  Copyright 2005, 2007, 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+C                           cycles/limb
+C P6 model 0-8,10-12		-
+C P6 model 9   (Banias)		4.17
+C P6 model 13  (Dothan)		4.17
+C P4 model 0-1 (Willamette)	4
+C P4 model 2   (Northwood)	4
+C P4 model 3-4 (Prescott)	4.55
+
+C TODO:
+C  * Tweak eax/edx offsets in loop as to save some lea's
+C  * Perhaps software pipeline small-case code
+
+C INPUT PARAMETERS
+C rp		sp + 4
+C up		sp + 8
+C n		sp + 12
+C v0		sp + 16
+
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_mul_1)
+	pxor	%mm6, %mm6
+L(ent):	mov	4(%esp), %edx
+	mov	8(%esp), %eax
+	mov	12(%esp), %ecx
+	movd	16(%esp), %mm7
+	cmp	$4, %ecx
+	jnc	L(big)
+
+L(lp0):	movd	(%eax), %mm0
+	lea	4(%eax), %eax
+	lea	4(%edx), %edx
+	pmuludq	%mm7, %mm0
+	paddq	%mm0, %mm6
+	movd	%mm6, -4(%edx)
+	psrlq	$32, %mm6
+	dec	%ecx
+	jnz	L(lp0)
+	movd	%mm6, %eax
+	emms
+	ret
+
+L(big):	and	$3, %ecx
+	je	L(0)
+	cmp	$2, %ecx
+	jc	L(1)
+	je	L(2)
+	jmp	L(3)			C FIXME: one case should fall through
+
+L(0):	movd	(%eax), %mm3
+	sub	12(%esp), %ecx		C loop count
+	lea	-16(%eax), %eax
+	lea	-12(%edx), %edx
+	pmuludq	%mm7, %mm3
+	movd	20(%eax), %mm0
+	pmuludq	%mm7, %mm0
+	movd	24(%eax), %mm1
+	jmp	L(00)
+
+L(1):	movd	(%eax), %mm2
+	sub	12(%esp), %ecx
+	lea	-12(%eax), %eax
+	lea	-8(%edx), %edx
+	pmuludq	%mm7, %mm2
+	movd	16(%eax), %mm3
+	pmuludq	%mm7, %mm3
+	movd	20(%eax), %mm0
+	jmp	L(01)
+
+L(2):	movd	(%eax), %mm1
+	sub	12(%esp), %ecx
+	lea	-8(%eax), %eax
+	lea	-4(%edx), %edx
+	pmuludq	%mm7, %mm1
+	movd	12(%eax), %mm2
+	pmuludq	%mm7, %mm2
+	movd	16(%eax), %mm3
+	jmp	L(10)
+
+L(3):	movd	(%eax), %mm0
+	sub	12(%esp), %ecx
+	lea	-4(%eax), %eax
+	pmuludq	%mm7, %mm0
+	movd	8(%eax), %mm1
+	pmuludq	%mm7, %mm1
+	movd	12(%eax), %mm2
+
+	ALIGN(16)
+L(top):	pmuludq	%mm7, %mm2
+	paddq	%mm0, %mm6
+	movd	16(%eax), %mm3
+	movd	%mm6, 0(%edx)
+	psrlq	$32, %mm6
+L(10):	pmuludq	%mm7, %mm3
+	paddq	%mm1, %mm6
+	movd	20(%eax), %mm0
+	movd	%mm6, 4(%edx)
+	psrlq	$32, %mm6
+L(01):	pmuludq	%mm7, %mm0
+	paddq	%mm2, %mm6
+	movd	24(%eax), %mm1
+	movd	%mm6, 8(%edx)
+	psrlq	$32, %mm6
+L(00):	pmuludq	%mm7, %mm1
+	paddq	%mm3, %mm6
+	movd	28(%eax), %mm2
+	movd	%mm6, 12(%edx)
+	psrlq	$32, %mm6
+	lea	16(%eax), %eax
+	lea	16(%edx), %edx
+	add	$4, %ecx
+	ja	L(top)
+
+L(end):	pmuludq	%mm7, %mm2
+	paddq	%mm0, %mm6
+	movd	%mm6, 0(%edx)
+	psrlq	$32, %mm6
+	paddq	%mm1, %mm6
+	movd	%mm6, 4(%edx)
+	psrlq	$32, %mm6
+	paddq	%mm2, %mm6
+	movd	%mm6, 8(%edx)
+	psrlq	$32, %mm6
+	movd	%mm6, %eax
+	emms
+	ret
+EPILOGUE()
+PROLOGUE(mpn_mul_1c)
+	movd	20(%esp), %mm6
+	jmp	L(ent)
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/pentium4/sse2/mul_basecase.asm b/third_party/gmp/mpn/x86/pentium4/sse2/mul_basecase.asm
new file mode 100644
index 0000000..6e3775a
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium4/sse2/mul_basecase.asm
@@ -0,0 +1,662 @@
+dnl  mpn_mul_basecase for Pentium 4 and P6 models with SSE2 (i.e., 9,D,E,F).
+
+dnl  Copyright 2001, 2002, 2005, 2007 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C TODO:
+C  * Improve ad-hoc outer loop code and register handling.  Some feed-in
+C    scheduling could improve things by several cycles per outer iteration.
+C  * In code for un <= 3, try keeping accumulation operands in registers,
+C    without storing intermediates to rp.
+C  * We might want to keep 32 in a free mm register, since the register form is
+C    3 bytes and the immediate form is 4 bytes.  About 70 bytes to save.
+C  * Look into different loop alignment, we now expand the code about 50 bytes
+C    with possibly needless alignment.
+C  * Perhaps rewrap loops 00,01,02 (6 loops) to allow fall-through entry.
+C  * Use OSP, should solve feed-in latency problems.
+C  * Save a few tens of bytes by doing cross-jumping for Loel0, etc.
+C  * Save around 120 bytes by remapping "m 0", "m 1", "m 2" and "m 3" registers
+C    so that they can share feed-in code, and changing the branch targets from
+C    L<n> to Lm<nn>.
+
+C                           cycles/limb
+C P6 model 9   (Banias)         ?
+C P6 model 13  (Dothan)         5.24
+C P6 model 14  (Yonah)          ?
+C P4 model 0-1 (Willamette):    5
+C P4 model 2   (Northwood):     4.60 at 32 limbs
+C P4 model 3-4 (Prescott):      4.94 at 32 limbs
+
+C INPUT PARAMETERS
+C rp		sp + 4
+C up		sp + 8
+C un		sp + 12
+C vp		sp + 16
+C vn		sp + 20
+
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_mul_basecase)
+	push	%esi
+	push	%ebx
+	mov	12(%esp), %edx		C rp
+	mov	16(%esp), %eax		C up
+	mov	20(%esp), %ecx		C un
+	mov	24(%esp), %esi		C vp
+	mov	28(%esp), %ebx		C vn
+	movd	(%esi), %mm7		C
+L(ent):	cmp	$3, %ecx
+	ja	L(big)
+	movd	(%eax), %mm6
+	pmuludq	%mm7, %mm6
+	jz	L(un3)
+	cmp	$2, %ecx
+	jz	L(un2)
+
+L(un1):	movd	%mm6, (%edx)		C				un=1
+	psrlq	$32, %mm6		C				un=1
+	movd	%mm6, 4(%edx)		C				un=1
+	jmp	L(rtr)			C				un=1
+
+L(un2):	movd	4(%eax), %mm1		C				un=2
+	pmuludq	%mm7, %mm1		C				un=2
+	movd	%mm6, (%edx)		C				un=2
+	psrlq	$32, %mm6		C				un=2
+	paddq	%mm1, %mm6		C				un=2
+	movd	%mm6, 4(%edx)		C				un=2
+	psrlq	$32, %mm6		C				un=2
+	movd	%mm6, 8(%edx)		C				un=2
+      dec	%ebx			C				un=2
+      jz	L(rtr)			C				un=2
+	movd	4(%esi), %mm7		C				un=2
+	movd	(%eax), %mm6		C				un=2
+	pmuludq	%mm7, %mm6		C				un=2
+	movd	4(%eax), %mm1		C				un=2
+	movd	4(%edx), %mm4		C				un=2
+	pmuludq	%mm7, %mm1		C				un=2
+	movd	8(%edx), %mm5		C				un=2
+	paddq	%mm4, %mm6		C				un=2
+	paddq	%mm1, %mm5		C				un=2
+	movd	%mm6, 4(%edx)		C				un=2
+	psrlq	$32, %mm6		C				un=2
+	paddq	%mm5, %mm6		C				un=2
+	movd	%mm6, 8(%edx)		C				un=2
+	psrlq	$32, %mm6		C				un=2
+	movd	%mm6, 12(%edx)		C				un=2
+L(rtr):	emms
+	pop	%ebx
+	pop	%esi
+	ret
+
+L(un3):	movd	4(%eax), %mm1		C				un=3
+	pmuludq	%mm7, %mm1		C				un=3
+	movd	8(%eax), %mm2		C				un=3
+	pmuludq	%mm7, %mm2		C				un=3
+	movd	%mm6, (%edx)		C				un=3
+	psrlq	$32, %mm6		C				un=3
+	paddq	%mm1, %mm6		C				un=3
+	movd	%mm6, 4(%edx)		C				un=3
+	psrlq	$32, %mm6		C				un=3
+	paddq	%mm2, %mm6		C				un=3
+	movd	%mm6, 8(%edx)		C				un=3
+	psrlq	$32, %mm6		C				un=3
+	movd	%mm6, 12(%edx)		C				un=3
+      dec	%ebx			C				un=3
+      jz	L(rtr)			C				un=3
+	movd	4(%esi), %mm7		C				un=3
+	movd	(%eax), %mm6		C				un=3
+	pmuludq	%mm7, %mm6		C				un=3
+	movd	4(%eax), %mm1		C				un=3
+	movd	4(%edx), %mm4		C				un=3
+	pmuludq	%mm7, %mm1		C				un=3
+	movd	8(%eax), %mm2		C				un=3
+	movd	8(%edx), %mm5		C				un=3
+	pmuludq	%mm7, %mm2		C				un=3
+	paddq	%mm4, %mm6		C				un=3
+	paddq	%mm1, %mm5		C				un=3
+	movd	12(%edx), %mm4		C				un=3
+	movd	%mm6, 4(%edx)		C				un=3
+	psrlq	$32, %mm6		C				un=3
+	paddq	%mm5, %mm6		C				un=3
+	paddq	%mm2, %mm4		C				un=3
+	movd	%mm6, 8(%edx)		C				un=3
+	psrlq	$32, %mm6		C				un=3
+	paddq	%mm4, %mm6		C				un=3
+	movd	%mm6, 12(%edx)		C				un=3
+	psrlq	$32, %mm6		C				un=3
+	movd	%mm6, 16(%edx)		C				un=3
+      dec	%ebx			C				un=3
+      jz	L(rtr)			C				un=3
+	movd	8(%esi), %mm7		C				un=3
+	movd	(%eax), %mm6		C				un=3
+	pmuludq	%mm7, %mm6		C				un=3
+	movd	4(%eax), %mm1		C				un=3
+	movd	8(%edx), %mm4		C				un=3
+	pmuludq	%mm7, %mm1		C				un=3
+	movd	8(%eax), %mm2		C				un=3
+	movd	12(%edx), %mm5		C				un=3
+	pmuludq	%mm7, %mm2		C				un=3
+	paddq	%mm4, %mm6		C				un=3
+	paddq	%mm1, %mm5		C				un=3
+	movd	16(%edx), %mm4		C				un=3
+	movd	%mm6, 8(%edx)		C				un=3
+	psrlq	$32, %mm6		C				un=3
+	paddq	%mm5, %mm6		C				un=3
+	paddq	%mm2, %mm4		C				un=3
+	movd	%mm6, 12(%edx)		C				un=3
+	psrlq	$32, %mm6		C				un=3
+	paddq	%mm4, %mm6		C				un=3
+	movd	%mm6, 16(%edx)		C				un=3
+	psrlq	$32, %mm6		C				un=3
+	movd	%mm6, 20(%edx)		C				un=3
+	jmp	L(rtr)
+
+
+L(big):	push	%edi
+	pxor	%mm6, %mm6
+	lea	4(%esi), %esi
+	and	$3, %ecx
+	jz	L(0)
+	cmp	$2, %ecx
+	jc	L(1)
+	jz	L(2)
+	jmp	L(3)			C FIXME: one case should fall through
+
+
+L(0):	movd	(%eax), %mm3		C				m 0
+	sub	24(%esp), %ecx		C inner loop count		m 0
+	mov	%ecx, 24(%esp)		C update loop count for later	m 0
+	pmuludq	%mm7, %mm3		C				m 0
+	movd	4(%eax), %mm0		C				m 0
+	pmuludq	%mm7, %mm0		C				m 0
+	movd	8(%eax), %mm1		C				m 0
+	jmp	L(m00)			C				m 0
+	ALIGN(16)			C				m 0
+L(lpm0):
+	pmuludq	%mm7, %mm4		C				m 0
+	paddq	%mm0, %mm6		C				m 0
+	movd	(%eax), %mm3		C				m 0
+	movd	%mm6, -12(%edx)		C				m 0
+	psrlq	$32, %mm6		C				m 0
+	pmuludq	%mm7, %mm3		C				m 0
+	paddq	%mm1, %mm6		C				m 0
+	movd	4(%eax), %mm0		C				m 0
+	movd	%mm6, -8(%edx)		C				m 0
+	psrlq	$32, %mm6		C				m 0
+	pmuludq	%mm7, %mm0		C				m 0
+	paddq	%mm4, %mm6		C				m 0
+	movd	8(%eax), %mm1		C				m 0
+	movd	%mm6, -4(%edx)		C				m 0
+	psrlq	$32, %mm6		C				m 0
+L(m00):	pmuludq	%mm7, %mm1		C				m 0
+	paddq	%mm3, %mm6		C				m 0
+	movd	12(%eax), %mm4		C				m 0
+	movd	%mm6, (%edx)		C				m 0
+	psrlq	$32, %mm6		C				m 0
+	lea	16(%eax), %eax		C				m 0
+	lea	16(%edx), %edx		C				m 0
+	add	$4, %ecx		C				m 0
+	ja	L(lpm0)			C				m 0
+	pmuludq	%mm7, %mm4		C				m 0
+	paddq	%mm0, %mm6		C				m 0
+	movd	%mm6, -12(%edx)		C				m 0
+	psrlq	$32, %mm6		C				m 0
+	paddq	%mm1, %mm6		C				m 0
+	mov	16(%esp), %edi		C rp				  0
+	jmp	L(x0)
+
+L(olp0):
+	lea	4(%edi), %edi		C				am 0
+	movd	(%esi), %mm7		C				am 0
+	lea	4(%esi), %esi		C				am 0
+	mov	%edi, %edx		C rp				am 0
+	mov	20(%esp), %eax		C up				am 0
+	movd	(%eax), %mm3		C				am 0
+	mov	24(%esp), %ecx		C inner loop count		am 0
+	pxor	%mm6, %mm6		C				am 0
+	pmuludq	%mm7, %mm3		C				am 0
+	movd	4(%eax), %mm0		C				am 0
+	movd	(%edx), %mm5		C				am 0
+	pmuludq	%mm7, %mm0		C				am 0
+	movd	8(%eax), %mm1		C				am 0
+	paddq	%mm3, %mm5		C				am 0
+	movd	4(%edx), %mm4		C				am 0
+	jmp	L(am00)			C				am 0
+	ALIGN(16)			C				mm 0
+L(lam0):
+	pmuludq	%mm7, %mm2		C				am 0
+	paddq	%mm4, %mm6		C				am 0
+	movd	(%eax), %mm3		C				am 0
+	paddq	%mm1, %mm5		C				am 0
+	movd	-4(%edx), %mm4		C				am 0
+	movd	%mm6, -12(%edx)		C				am 0
+	psrlq	$32, %mm6		C				am 0
+	pmuludq	%mm7, %mm3		C				am 0
+	paddq	%mm5, %mm6		C				am 0
+	movd	4(%eax), %mm0		C				am 0
+	paddq	%mm2, %mm4		C				am 0
+	movd	(%edx), %mm5		C				am 0
+	movd	%mm6, -8(%edx)		C				am 0
+	psrlq	$32, %mm6		C				am 0
+	pmuludq	%mm7, %mm0		C				am 0
+	paddq	%mm4, %mm6		C				am 0
+	movd	8(%eax), %mm1		C				am 0
+	paddq	%mm3, %mm5		C				am 0
+	movd	4(%edx), %mm4		C				am 0
+	movd	%mm6, -4(%edx)		C				am 0
+	psrlq	$32, %mm6		C				am 0
+L(am00):
+	pmuludq	%mm7, %mm1		C				am 0
+	paddq	%mm5, %mm6		C				am 0
+	movd	12(%eax), %mm2		C				am 0
+	paddq	%mm0, %mm4		C				am 0
+	movd	8(%edx), %mm5		C				am 0
+	movd	%mm6, (%edx)		C				am 0
+	psrlq	$32, %mm6		C				am 0
+	lea	16(%eax), %eax		C				am 0
+	lea	16(%edx), %edx		C				am 0
+	add	$4, %ecx		C				am 0
+	jnz	L(lam0)			C				am 0
+	pmuludq	%mm7, %mm2		C				am 0
+	paddq	%mm4, %mm6		C				am 0
+	paddq	%mm1, %mm5		C				am 0
+	movd	-4(%edx), %mm4		C				am 0
+	movd	%mm6, -12(%edx)		C				am 0
+	psrlq	$32, %mm6		C				am 0
+	paddq	%mm5, %mm6		C				am 0
+	paddq	%mm2, %mm4		C				am 0
+L(x0):	movd	%mm6, -8(%edx)		C				am 0
+	psrlq	$32, %mm6		C				am 0
+	paddq	%mm4, %mm6		C				am 0
+	movd	%mm6, -4(%edx)		C				am 0
+	psrlq	$32, %mm6		C				am 0
+	movd	%mm6, (%edx)		C				am 0
+	dec	%ebx			C				am 0
+	jnz	L(olp0)			C				am 0
+L(oel0):
+	emms				C				   0
+	pop	%edi			C				   0
+	pop	%ebx			C				   0
+	pop	%esi			C				   0
+	ret				C				   0
+
+
+L(1):	movd	(%eax), %mm4		C				m 1
+	sub	24(%esp), %ecx		C				m 1
+	mov	%ecx, 24(%esp)		C update loop count for later	m 1
+	pmuludq	%mm7, %mm4		C				m 1
+	movd	4(%eax), %mm3		C				m 1
+	pmuludq	%mm7, %mm3		C				m 1
+	movd	8(%eax), %mm0		C				m 1
+	jmp	L(m01)			C				m 1
+	ALIGN(16)			C				m 1
+L(lpm1):
+	pmuludq	%mm7, %mm4		C				m 1
+	paddq	%mm0, %mm6		C				m 1
+	movd	4(%eax), %mm3		C				m 1
+	movd	%mm6, -8(%edx)		C				m 1
+	psrlq	$32, %mm6		C				m 1
+	pmuludq	%mm7, %mm3		C				m 1
+	paddq	%mm1, %mm6		C				m 1
+	movd	8(%eax), %mm0		C				m 1
+	movd	%mm6, -4(%edx)		C				m 1
+	psrlq	$32, %mm6		C				m 1
+L(m01):	pmuludq	%mm7, %mm0		C				m 1
+	paddq	%mm4, %mm6		C				m 1
+	movd	12(%eax), %mm1		C				m 1
+	movd	%mm6, (%edx)		C				m 1
+	psrlq	$32, %mm6		C				m 1
+	pmuludq	%mm7, %mm1		C				m 1
+	paddq	%mm3, %mm6		C				m 1
+	movd	16(%eax), %mm4		C				m 1
+	movd	%mm6, 4(%edx)		C				m 1
+	psrlq	$32, %mm6		C				m 1
+	lea	16(%eax), %eax		C				m 1
+	lea	16(%edx), %edx		C				m 1
+	add	$4, %ecx		C				m 1
+	ja	L(lpm1)			C				m 1
+	pmuludq	%mm7, %mm4		C				m 1
+	paddq	%mm0, %mm6		C				m 1
+	movd	%mm6, -8(%edx)		C				m 1
+	psrlq	$32, %mm6		C				m 1
+	paddq	%mm1, %mm6		C				m 1
+	mov	16(%esp), %edi		C rp				  1
+	jmp	L(x1)
+
+L(olp1):
+	lea	4(%edi), %edi		C				am 1
+	movd	(%esi), %mm7		C				am 1
+	lea	4(%esi), %esi		C				am 1
+	mov	%edi, %edx		C rp				am 1
+	mov	20(%esp), %eax		C up				am 1
+	movd	(%eax), %mm2		C				am 1
+	mov	24(%esp), %ecx		C inner loop count		am 1
+	pxor	%mm6, %mm6		C				am 1
+	pmuludq	%mm7, %mm2		C				am 1
+	movd	4(%eax), %mm3		C				am 1
+	movd	(%edx), %mm4		C				am 1
+	pmuludq	%mm7, %mm3		C				am 1
+	movd	8(%eax), %mm0		C				am 1
+	paddq	%mm2, %mm4		C				am 1
+	movd	4(%edx), %mm5		C				am 1
+	jmp	L(am01)			C				am 1
+	ALIGN(16)			C				am 1
+L(lam1):
+	pmuludq	%mm7, %mm2		C				am 1
+	paddq	%mm4, %mm6		C				am 1
+	movd	4(%eax), %mm3		C				am 1
+	paddq	%mm1, %mm5		C				am 1
+	movd	(%edx), %mm4		C				am 1
+	movd	%mm6, -8(%edx)		C				am 1
+	psrlq	$32, %mm6		C				am 1
+	pmuludq	%mm7, %mm3		C				am 1
+	paddq	%mm5, %mm6		C				am 1
+	movd	8(%eax), %mm0		C				am 1
+	paddq	%mm2, %mm4		C				am 1
+	movd	4(%edx), %mm5		C				am 1
+	movd	%mm6, -4(%edx)		C				am 1
+	psrlq	$32, %mm6		C				am 1
+L(am01):
+	pmuludq	%mm7, %mm0		C				am 1
+	paddq	%mm4, %mm6		C				am 1
+	movd	12(%eax), %mm1		C				am 1
+	paddq	%mm3, %mm5		C				am 1
+	movd	8(%edx), %mm4		C				am 1
+	movd	%mm6, (%edx)		C				am 1
+	psrlq	$32, %mm6		C				am 1
+	pmuludq	%mm7, %mm1		C				am 1
+	paddq	%mm5, %mm6		C				am 1
+	movd	16(%eax), %mm2		C				am 1
+	paddq	%mm0, %mm4		C				am 1
+	movd	12(%edx), %mm5		C				am 1
+	movd	%mm6, 4(%edx)		C				am 1
+	psrlq	$32, %mm6		C				am 1
+	lea	16(%eax), %eax		C				am 1
+	lea	16(%edx), %edx		C				am 1
+	add	$4, %ecx		C				am 1
+	jnz	L(lam1)			C				am 1
+	pmuludq	%mm7, %mm2		C				am 1
+	paddq	%mm4, %mm6		C				am 1
+	paddq	%mm1, %mm5		C				am 1
+	movd	(%edx), %mm4		C				am 1
+	movd	%mm6, -8(%edx)		C				am 1
+	psrlq	$32, %mm6		C				am 1
+	paddq	%mm5, %mm6		C				am 1
+	paddq	%mm2, %mm4		C				am 1
+L(x1):	movd	%mm6, -4(%edx)		C				am 1
+	psrlq	$32, %mm6		C				am 1
+	paddq	%mm4, %mm6		C				am 1
+	movd	%mm6, (%edx)		C				am 1
+	psrlq	$32, %mm6		C				am 1
+	movd	%mm6, 4(%edx)		C				am 1
+	dec	%ebx			C				am 1
+	jnz	L(olp1)			C				am 1
+L(oel1):
+	emms				C				   1
+	pop	%edi			C				   1
+	pop	%ebx			C				   1
+	pop	%esi			C				   1
+	ret				C				   1
+
+
+L(2):	movd	(%eax), %mm1		C				m 2
+	sub	24(%esp), %ecx		C				m 2
+	mov	%ecx, 24(%esp)		C update loop count for later	m 2
+	pmuludq	%mm7, %mm1		C				m 2
+	movd	4(%eax), %mm4		C				m 2
+	pmuludq	%mm7, %mm4		C				m 2
+	movd	8(%eax), %mm3		C				m 2
+	jmp	L(m10)			C				m 2
+	ALIGN(16)			C				m 2
+L(lpm2):
+	pmuludq	%mm7, %mm4		C				m 2
+	paddq	%mm0, %mm6		C				m 2
+	movd	8(%eax), %mm3		C				m 2
+	movd	%mm6, -4(%edx)		C				m 2
+	psrlq	$32, %mm6		C				m 2
+L(m10):	pmuludq	%mm7, %mm3		C				m 2
+	paddq	%mm1, %mm6		C				m 2
+	movd	12(%eax), %mm0		C				m 2
+	movd	%mm6, (%edx)		C				m 2
+	psrlq	$32, %mm6		C				m 2
+	pmuludq	%mm7, %mm0		C				m 2
+	paddq	%mm4, %mm6		C				m 2
+	movd	16(%eax), %mm1		C				m 2
+	movd	%mm6, 4(%edx)		C				m 2
+	psrlq	$32, %mm6		C				m 2
+	pmuludq	%mm7, %mm1		C				m 2
+	paddq	%mm3, %mm6		C				m 2
+	movd	20(%eax), %mm4		C				m 2
+	movd	%mm6, 8(%edx)		C				m 2
+	psrlq	$32, %mm6		C				m 2
+	lea	16(%eax), %eax		C				m 2
+	lea	16(%edx), %edx		C				m 2
+	add	$4, %ecx		C				m 2
+	ja	L(lpm2)			C				m 2
+	pmuludq	%mm7, %mm4		C				m 2
+	paddq	%mm0, %mm6		C				m 2
+	movd	%mm6, -4(%edx)		C				m 2
+	psrlq	$32, %mm6		C				m 2
+	paddq	%mm1, %mm6		C				m 2
+	mov	16(%esp), %edi		C rp				  2
+	jmp	L(x2)
+
+L(olp2):
+	lea	4(%edi), %edi		C				am 2
+	movd	(%esi), %mm7		C				am 2
+	lea	4(%esi), %esi		C				am 2
+	mov	%edi, %edx		C rp				am 2
+	mov	20(%esp), %eax		C up				am 2
+	movd	(%eax), %mm1		C				am 2
+	mov	24(%esp), %ecx		C inner loop count		am 2
+	pxor	%mm6, %mm6		C				am 2
+	pmuludq	%mm7, %mm1		C				am 2
+	movd	4(%eax), %mm2		C				am 2
+	movd	(%edx), %mm5		C				am 2
+	pmuludq	%mm7, %mm2		C				am 2
+	movd	8(%eax), %mm3		C				am 2
+	paddq	%mm1, %mm5		C				am 2
+	movd	4(%edx), %mm4		C				am 2
+	jmp	L(am10)			C				am 2
+	ALIGN(16)			C				am 2
+L(lam2):
+	pmuludq	%mm7, %mm2		C				am 2
+	paddq	%mm4, %mm6		C				am 2
+	movd	8(%eax), %mm3		C				am 2
+	paddq	%mm1, %mm5		C				am 2
+	movd	4(%edx), %mm4		C				am 2
+	movd	%mm6, -4(%edx)		C				am 2
+	psrlq	$32, %mm6		C				am 2
+L(am10):
+	pmuludq	%mm7, %mm3		C				am 2
+	paddq	%mm5, %mm6		C				am 2
+	movd	12(%eax), %mm0		C				am 2
+	paddq	%mm2, %mm4		C				am 2
+	movd	8(%edx), %mm5		C				am 2
+	movd	%mm6, (%edx)		C				am 2
+	psrlq	$32, %mm6		C				am 2
+	pmuludq	%mm7, %mm0		C				am 2
+	paddq	%mm4, %mm6		C				am 2
+	movd	16(%eax), %mm1		C				am 2
+	paddq	%mm3, %mm5		C				am 2
+	movd	12(%edx), %mm4		C				am 2
+	movd	%mm6, 4(%edx)		C				am 2
+	psrlq	$32, %mm6		C				am 2
+	pmuludq	%mm7, %mm1		C				am 2
+	paddq	%mm5, %mm6		C				am 2
+	movd	20(%eax), %mm2		C				am 2
+	paddq	%mm0, %mm4		C				am 2
+	movd	16(%edx), %mm5		C				am 2
+	movd	%mm6, 8(%edx)		C				am 2
+	psrlq	$32, %mm6		C				am 2
+	lea	16(%eax), %eax		C				am 2
+	lea	16(%edx), %edx		C				am 2
+	add	$4, %ecx		C				am 2
+	jnz	L(lam2)			C				am 2
+	pmuludq	%mm7, %mm2		C				am 2
+	paddq	%mm4, %mm6		C				am 2
+	paddq	%mm1, %mm5		C				am 2
+	movd	4(%edx), %mm4		C				am 2
+	movd	%mm6, -4(%edx)		C				am 2
+	psrlq	$32, %mm6		C				am 2
+	paddq	%mm5, %mm6		C				am 2
+	paddq	%mm2, %mm4		C				am 2
+L(x2):	movd	%mm6, (%edx)		C				am 2
+	psrlq	$32, %mm6		C				am 2
+	paddq	%mm4, %mm6		C				am 2
+	movd	%mm6, 4(%edx)		C				am 2
+	psrlq	$32, %mm6		C				am 2
+	movd	%mm6, 8(%edx)		C				am 2
+	dec	%ebx			C				am 2
+	jnz	L(olp2)			C				am 2
+L(oel2):
+	emms				C				   2
+	pop	%edi			C				   2
+	pop	%ebx			C				   2
+	pop	%esi			C				   2
+	ret				C				   2
+
+
+L(3):	movd	(%eax), %mm0		C				m 3
+	sub	24(%esp), %ecx		C				m 3
+	mov	%ecx, 24(%esp)		C update loop count for later	m 3
+	pmuludq	%mm7, %mm0		C				m 3
+	movd	4(%eax), %mm1		C				m 3
+	pmuludq	%mm7, %mm1		C				m 3
+	movd	8(%eax), %mm4		C				m 3
+	jmp	L(lpm3)			C				m 3
+	ALIGN(16)			C				m 3
+L(lpm3):
+	pmuludq	%mm7, %mm4		C				m 3
+	paddq	%mm0, %mm6		C				m 3
+	movd	12(%eax), %mm3		C				m 3
+	movd	%mm6, (%edx)		C				m 3
+	psrlq	$32, %mm6		C				m 3
+	pmuludq	%mm7, %mm3		C				m 3
+	paddq	%mm1, %mm6		C				m 3
+	movd	16(%eax), %mm0		C				m 3
+	movd	%mm6, 4(%edx)		C				m 3
+	psrlq	$32, %mm6		C				m 3
+	pmuludq	%mm7, %mm0		C				m 3
+	paddq	%mm4, %mm6		C				m 3
+	movd	20(%eax), %mm1		C				m 3
+	movd	%mm6, 8(%edx)		C				m 3
+	psrlq	$32, %mm6		C				m 3
+	pmuludq	%mm7, %mm1		C				m 3
+	paddq	%mm3, %mm6		C				m 3
+	movd	24(%eax), %mm4		C				m 3
+	movd	%mm6, 12(%edx)		C				m 3
+	psrlq	$32, %mm6		C				m 3
+	lea	16(%eax), %eax		C				m 3
+	lea	16(%edx), %edx		C				m 3
+	add	$4, %ecx		C				m 3
+	ja	L(lpm3)			C				m 3
+	pmuludq	%mm7, %mm4		C				m 3
+	paddq	%mm0, %mm6		C				m 3
+	movd	%mm6, (%edx)		C				m 3
+	psrlq	$32, %mm6		C				m 3
+	paddq	%mm1, %mm6		C				m 3
+	mov	16(%esp), %edi		C rp				  3
+	jmp	L(x3)
+
+L(olp3):
+	lea	4(%edi), %edi		C				am 3
+	movd	(%esi), %mm7		C				am 3
+	lea	4(%esi), %esi		C				am 3
+	mov	%edi, %edx		C rp				am 3
+	mov	20(%esp), %eax		C up				am 3
+	movd	(%eax), %mm0		C				am 3
+	mov	24(%esp), %ecx		C inner loop count		am 3
+	pxor	%mm6, %mm6		C				am 3
+	pmuludq	%mm7, %mm0		C				am 3
+	movd	4(%eax), %mm1		C				am 3
+	movd	(%edx), %mm4		C				am 3
+	pmuludq	%mm7, %mm1		C				am 3
+	movd	8(%eax), %mm2		C				am 3
+	paddq	%mm0, %mm4		C				am 3
+	movd	4(%edx), %mm5		C				am 3
+	jmp	L(lam3)			C				am 3
+	ALIGN(16)			C				am 3
+L(lam3):
+	pmuludq	%mm7, %mm2		C				am 3
+	paddq	%mm4, %mm6		C				am 3
+	movd	12(%eax), %mm3		C				am 3
+	paddq	%mm1, %mm5		C				am 3
+	movd	8(%edx), %mm4		C				am 3
+	movd	%mm6, (%edx)		C				am 3
+	psrlq	$32, %mm6		C				am 3
+	pmuludq	%mm7, %mm3		C				am 3
+	paddq	%mm5, %mm6		C				am 3
+	movd	16(%eax), %mm0		C				am 3
+	paddq	%mm2, %mm4		C				am 3
+	movd	12(%edx), %mm5		C				am 3
+	movd	%mm6, 4(%edx)		C				am 3
+	psrlq	$32, %mm6		C				am 3
+	pmuludq	%mm7, %mm0		C				am 3
+	paddq	%mm4, %mm6		C				am 3
+	movd	20(%eax), %mm1		C				am 3
+	paddq	%mm3, %mm5		C				am 3
+	movd	16(%edx), %mm4		C				am 3
+	movd	%mm6, 8(%edx)		C				am 3
+	psrlq	$32, %mm6		C				am 3
+	pmuludq	%mm7, %mm1		C				am 3
+	paddq	%mm5, %mm6		C				am 3
+	movd	24(%eax), %mm2		C				am 3
+	paddq	%mm0, %mm4		C				am 3
+	movd	20(%edx), %mm5		C				am 3
+	movd	%mm6, 12(%edx)		C				am 3
+	psrlq	$32, %mm6		C				am 3
+	lea	16(%eax), %eax		C				am 3
+	lea	16(%edx), %edx		C				am 3
+	add	$4, %ecx		C				am 3
+	jnz	L(lam3)			C				am 3
+	pmuludq	%mm7, %mm2		C				am 3
+	paddq	%mm4, %mm6		C				am 3
+	paddq	%mm1, %mm5		C				am 3
+	movd	8(%edx), %mm4		C				am 3
+	movd	%mm6, (%edx)		C				am 3
+	psrlq	$32, %mm6		C				am 3
+	paddq	%mm5, %mm6		C				am 3
+	paddq	%mm2, %mm4		C				am 3
+L(x3):	movd	%mm6, 4(%edx)		C				am 3
+	psrlq	$32, %mm6		C				am 3
+	paddq	%mm4, %mm6		C				am 3
+	movd	%mm6, 8(%edx)		C				am 3
+	psrlq	$32, %mm6		C				am 3
+	movd	%mm6, 12(%edx)		C				am 3
+	dec	%ebx			C				am 3
+	jnz	L(olp3)			C				am 3
+L(oel3):
+	emms				C				   3
+	pop	%edi			C				   3
+	pop	%ebx			C				   3
+	pop	%esi			C				   3
+	ret				C				   3
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/pentium4/sse2/popcount.asm b/third_party/gmp/mpn/x86/pentium4/sse2/popcount.asm
new file mode 100644
index 0000000..c7f4426
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium4/sse2/popcount.asm
@@ -0,0 +1,281 @@
+dnl  X86-32 and X86-64 mpn_popcount using SSE2.
+
+dnl  Copyright 2006, 2007, 2011, 2015, 2020 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+
+C 32-bit		     popcount	     hamdist
+C			    cycles/limb	    cycles/limb
+C P5				-
+C P6 model 0-8,10-12		-
+C P6 model 9  (Banias)		?
+C P6 model 13 (Dothan)		4
+C P4 model 0  (Willamette)	?
+C P4 model 1  (?)		?
+C P4 model 2  (Northwood)	3.9
+C P4 model 3  (Prescott)	?
+C P4 model 4  (Nocona)		?
+C AMD K6			-
+C AMD K7			-
+C AMD K8			?
+
+C 64-bit		     popcount	     hamdist
+C			    cycles/limb	    cycles/limb
+C P4 model 4 (Nocona):		8
+C AMD K8,K9			7.5
+C AMD K10			3.5
+C Intel core2			3.68
+C Intel corei			3.15
+C Intel atom		       10.8
+C VIA nano			6.5
+
+C TODO
+C  * Make an mpn_hamdist based on this.  Alignment could either be handled by
+C    using movdqu for one operand and movdqa for the other, or by painfully
+C    shifting as we go.  Unfortunately, there seem to be no usable shift
+C    instruction, except for one that takes an immediate count.
+C  * It would probably be possible to cut a few cycles/limb using software
+C    pipelining.
+C  * There are 35 decode slots unused by the SSE2 instructions.  Loop control
+C    needs just 2 or 3 slots, leaving around 32 slots.  This allows a parallel
+C    integer based popcount.  Such a combined loop would handle 6 limbs in
+C    about 30 cycles on K8.
+C  * We could save a byte or two by using 32-bit operations on areg.
+C  * Check if using movdqa to a temp of and then register-based pand is faster.
+
+ifelse(GMP_LIMB_BITS,`32',
+`	define(`up',  `%edx')
+	define(`n',   `%ecx')
+	define(`areg',`%eax')
+	define(`breg',`%ebx')
+	define(`zero',`%xmm4')
+	define(`LIMB32',`	$1')
+	define(`LIMB64',`dnl')
+',`
+	define(`up',  `%rdi')
+	define(`n',   `%rsi')
+	define(`areg',`%rax')
+	define(`breg',`%rdx')
+	define(`zero',`%xmm8')
+	define(`LIMB32',`dnl')
+	define(`LIMB64',`	$1')
+')
+
+define(`mm01010101',`%xmm6')
+define(`mm00110011',`%xmm7')
+define(`mm00001111',`%xmm2')
+
+define(`GMP_LIMB_BYTES', eval(GMP_LIMB_BITS/8))
+define(`LIMBS_PER_XMM',  eval(16/GMP_LIMB_BYTES))
+define(`LIMBS_PER_2XMM', eval(32/GMP_LIMB_BYTES))
+
+undefine(`psadbw')			C override inherited m4 version
+
+C This file is shared between 32-bit and 64-bit builds.  Only the former has
+C LEAL.  Default LEAL as an alias of LEA.
+ifdef(`LEAL',,`define(`LEAL', `LEA($1,$2)')')
+
+ASM_START()
+
+C Make cnsts global to work around Apple relocation bug.
+ifdef(`DARWIN',`
+	define(`cnsts', MPN(popccnsts))
+	GLOBL	cnsts')
+
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_popcount)
+
+LIMB32(`mov	4(%esp), up	')
+LIMB32(`mov	8(%esp), n	')
+LIMB32(`push	%ebx		')
+
+	pxor	%xmm3, %xmm3		C zero grand total count
+LIMB64(`pxor	zero, zero	')
+
+	LEAL(	cnsts, breg)
+
+	movdqa	-48(breg), mm01010101
+	movdqa	-32(breg), mm00110011
+	movdqa	-16(breg), mm00001111
+
+	mov	up, areg
+	and	$-16, up		C round `up' down to 128-bit boundary
+	and	$12, areg		C 32:areg = 0, 4, 8, 12
+					C 64:areg = 0, 8
+	movdqa	(up), %xmm0
+	pand	64(breg,areg,4), %xmm0
+	shr	$m4_log2(GMP_LIMB_BYTES), %eax
+	add	areg, n			C compensate n for rounded down `up'
+
+	pxor	%xmm4, %xmm4
+	sub	$LIMBS_PER_XMM, n
+	jbe	L(sum)
+
+	sub	$LIMBS_PER_XMM, n
+	ja	L(ent)
+	jmp	L(lsum)
+
+	ALIGN(16)
+L(top):	movdqa	(up), %xmm0
+L(ent):	movdqa	16(up), %xmm4
+
+	movdqa	%xmm0, %xmm1
+	movdqa	%xmm4, %xmm5
+	psrld	$1, %xmm0
+	psrld	$1, %xmm4
+	pand	mm01010101, %xmm0
+	pand	mm01010101, %xmm4
+	psubd	%xmm0, %xmm1
+	psubd	%xmm4, %xmm5
+
+	movdqa	%xmm1, %xmm0
+	movdqa	%xmm5, %xmm4
+	psrlq	$2, %xmm1
+	psrlq	$2, %xmm5
+	pand	mm00110011, %xmm0
+	pand	mm00110011, %xmm4
+	pand	mm00110011, %xmm1
+	pand	mm00110011, %xmm5
+	paddq	%xmm0, %xmm1
+	paddq	%xmm4, %xmm5
+
+LIMB32(`pxor	zero, zero	')
+
+	add	$32, up
+	sub	$LIMBS_PER_2XMM, n
+
+	paddq	%xmm5, %xmm1
+	movdqa	%xmm1, %xmm0
+	psrlq	$4, %xmm1
+	pand	mm00001111, %xmm0
+	pand	mm00001111, %xmm1
+	paddq	%xmm0, %xmm1
+
+	psadbw	zero, %xmm1
+	paddq	%xmm1, %xmm3		C add to grand total
+
+	jnc	L(top)
+L(end):
+	add	$LIMBS_PER_2XMM, n
+	jz	L(rt)
+	movdqa	(up), %xmm0
+	pxor	%xmm4, %xmm4
+	sub	$LIMBS_PER_XMM, n
+	jbe	L(sum)
+L(lsum):
+	movdqa	%xmm0, %xmm4
+	movdqa	16(up), %xmm0
+L(sum):
+	shl	$m4_log2(GMP_LIMB_BYTES), n
+	and	$12, n
+	pand	(breg,n,4), %xmm0
+
+	movdqa	%xmm0, %xmm1
+	movdqa	%xmm4, %xmm5
+	psrld	$1, %xmm0
+	psrld	$1, %xmm4
+	pand	mm01010101, %xmm0
+	pand	mm01010101, %xmm4
+	psubd	%xmm0, %xmm1
+	psubd	%xmm4, %xmm5
+
+	movdqa	%xmm1, %xmm0
+	movdqa	%xmm5, %xmm4
+	psrlq	$2, %xmm1
+	psrlq	$2, %xmm5
+	pand	mm00110011, %xmm0
+	pand	mm00110011, %xmm4
+	pand	mm00110011, %xmm1
+	pand	mm00110011, %xmm5
+	paddq	%xmm0, %xmm1
+	paddq	%xmm4, %xmm5
+
+LIMB32(`pxor	zero, zero	')
+
+	paddq	%xmm5, %xmm1
+	movdqa	%xmm1, %xmm0
+	psrlq	$4, %xmm1
+	pand	mm00001111, %xmm0
+	pand	mm00001111, %xmm1
+	paddq	%xmm0, %xmm1
+
+	psadbw	zero, %xmm1
+	paddq	%xmm1, %xmm3		C add to grand total
+
+
+C Add the two 64-bit halves of the grand total counter
+L(rt):	movdqa	%xmm3, %xmm0
+	psrldq	$8, %xmm3
+	paddq	%xmm3, %xmm0
+	movd	%xmm0, areg		C movq avoided due to gas bug
+
+LIMB32(`pop	%ebx		')
+	ret
+
+EPILOGUE()
+DEF_OBJECT(dummy,16)
+C Three magic constants used for masking out bits
+	.byte	0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55
+	.byte	0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55
+
+	.byte	0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33
+	.byte	0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33
+
+	.byte	0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f
+	.byte	0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f
+cnsts:
+C Masks for high end of number
+	.byte	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
+	.byte	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
+
+	.byte	0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00
+	.byte	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+
+	.byte	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
+	.byte	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+
+	.byte	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
+	.byte	0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00
+C Masks for low end of number
+	.byte	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
+	.byte	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
+
+	.byte	0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff
+	.byte	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
+
+	.byte	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+	.byte	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
+
+	.byte	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+	.byte	0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff
+END_OBJECT(dummy)
+ASM_END()
diff --git a/third_party/gmp/mpn/x86/pentium4/sse2/rsh1add_n.asm b/third_party/gmp/mpn/x86/pentium4/sse2/rsh1add_n.asm
new file mode 100644
index 0000000..f421d13
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium4/sse2/rsh1add_n.asm
@@ -0,0 +1,126 @@
+dnl  Intel Pentium-4 mpn_rsh1add_n -- mpn (x+y)/2
+
+dnl  Copyright 2001-2004 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C        cycles/limb (approx)
+C      dst!=src1,2  dst==src1  dst==src2
+C P4:      4.5         6.5        6.5
+
+
+C mp_limb_t mpn_rsh1add_n (mp_ptr wp, mp_srcptr xp, mp_srcptr yp,
+C                          mp_size_t size);
+C
+C The slightly strange combination of indexing and pointer incrementing
+C that's used seems to work best.  Not sure why, but for instance leal
+C incrementing on %esi is a 1 or 2 cycle slowdown.
+C
+C The dependent chain is paddq combining the carry and next (shifted) part,
+C plus psrlq to move the new carry down.  That, and just 4 mmx instructions
+C in total, makes 4 c/l the target speed, which is almost achieved for
+C separate src/dst but when src==dst the write combining anomalies slow it
+C down.
+
+defframe(PARAM_SIZE, 16)
+defframe(PARAM_YP,   12)
+defframe(PARAM_XP,   8)
+defframe(PARAM_WP,   4)
+
+dnl  re-use parameter space
+define(SAVE_EBX,`PARAM_XP')
+define(SAVE_ESI,`PARAM_YP')
+
+	TEXT
+	ALIGN(8)
+
+PROLOGUE(mpn_rsh1add_n)
+deflit(`FRAME',0)
+
+	movl	PARAM_XP, %edx
+	movl	%ebx, SAVE_EBX
+
+	movl	PARAM_YP, %ebx
+	movl	%esi, SAVE_ESI
+
+	movl	PARAM_WP, %esi
+
+	movd	(%edx), %mm0		C xp[0]
+
+	movd	(%ebx), %mm1		C yp[0]
+	movl	PARAM_SIZE, %ecx
+
+	movl	(%edx), %eax		C xp[0]
+
+	addl	(%ebx), %eax		C xp[0]+yp[0]
+
+	paddq	%mm1, %mm0		C xp[0]+yp[0]
+	leal	(%esi,%ecx,4), %esi	C wp end
+	negl	%ecx			C -size
+
+	psrlq	$1, %mm0		C (xp[0]+yp[0])/2
+	and	$1, %eax		C return value, rsh1 bit of xp[0]+yp[0]
+	addl	$1, %ecx		C -(size-1)
+	jz	L(done)
+
+
+L(top):
+	C eax	return value
+	C ebx	yp end
+	C ecx	counter, limbs, -(size-1) to -1 inclusive
+	C edx	xp end
+	C esi	wp end
+	C mm0	carry (32 bits)
+
+	movd	4(%edx), %mm1	C xp[i+1]
+	movd	4(%ebx), %mm2	C yp[i+1]
+	leal	4(%edx), %edx
+	leal	4(%ebx), %ebx
+	paddq	%mm2, %mm1		C xp[i+1]+yp[i+1]
+	psllq	$31, %mm1		C low bit at 31, further 32 above
+
+	paddq	%mm1, %mm0		C 31 and carry from prev add
+	movd	%mm0, -4(%esi,%ecx,4)	C low ready to store dst[i]
+
+	psrlq	$32, %mm0		C high becomes new carry
+
+	addl	$1, %ecx
+	jnz	L(top)
+
+
+L(done):
+	movd	%mm0, -4(%esi)		C dst[size-1]
+	movl	SAVE_EBX, %ebx
+
+	movl	SAVE_ESI, %esi
+	emms
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/pentium4/sse2/sqr_basecase.asm b/third_party/gmp/mpn/x86/pentium4/sse2/sqr_basecase.asm
new file mode 100644
index 0000000..2dd57d2
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium4/sse2/sqr_basecase.asm
@@ -0,0 +1,705 @@
+dnl  mpn_sqr_basecase for Pentium 4 and P6 models with SSE2 (i.e., 9,D,E,F).
+
+dnl  Copyright 2001, 2002, 2007 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C TODO:
+C  * Improve ad-hoc outer loop code and register handling.  Some feed-in
+C    scheduling could improve things by several cycles per outer iteration.
+C  * In Lam3...Lam1 code for, keep accumulation operands in registers, without
+C    storing intermediates to rp.
+C  * We might want to keep 32 in a free mm register, since the register form is
+C    3 bytes and the immediate form is 4 bytes.  About 80 bytes to save.
+C  * Look into different loop alignment, we now expand the code about 50 bytes
+C    with possibly needless alignment.
+C  * Use OSP, should solve feed-in latency problems.
+C  * Address relative slowness for un<=3 for Pentium M.  The old code is there
+C    considerably faster.  (1:20/14, 2:34:32, 3:66/57)
+
+C INPUT PARAMETERS
+C rp		sp + 4
+C up		sp + 8
+C un		sp + 12
+
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_sqr_basecase)
+	mov	4(%esp), %edx		C rp
+	mov	8(%esp), %eax		C up
+	mov	12(%esp), %ecx		C un
+
+	cmp	$2, %ecx
+	jc	L(un1)
+	jz	L(un2)
+	cmp	$4, %ecx
+	jc	L(un3)
+	jz	L(un4)
+	jmp	L(big)
+
+L(un1):	mov	(%eax), %eax
+	mov	%edx, %ecx
+	mul	%eax
+	mov	%eax, (%ecx)
+	mov	%edx, 4(%ecx)
+	ret
+L(un2):	movd	(%eax), %mm0		C				un=2
+	movd	(%eax), %mm2		C				un=2
+	movd	4(%eax), %mm1		C				un=2
+	pmuludq	%mm0, %mm0		C 64b weight 0			un=2
+	pmuludq	%mm1, %mm2		C 64b weight 32			un=2
+	pmuludq	%mm1, %mm1		C 64b weight 64			un=2
+	movd	%mm0, (%edx)		C				un=2
+	psrlq	$32, %mm0		C 32b weight 32			un=2
+	pcmpeqd	%mm7, %mm7		C				un=2
+	psrlq	$33, %mm7		C 0x000000007FFFFFFF		un=2
+	pand	%mm2, %mm7		C 31b weight 32			un=2
+	psrlq	$31, %mm2		C 33b weight 65			un=2
+	psllq	$1, %mm7		C 31b weight 33			un=2
+	paddq	%mm7, %mm0		C				un=2
+	movd	%mm0, 4(%edx)		C				un=2
+	psrlq	$32, %mm0		C				un=2
+	paddq	%mm2, %mm1		C				un=2
+	paddq	%mm0, %mm1		C				un=2
+	movd	%mm1, 8(%edx)		C				un=2
+	psrlq	$32, %mm1		C				un=2
+	movd	%mm1, 12(%edx)		C				un=2
+	emms
+	ret
+L(un3):	movd	(%eax), %mm7		C				un=3
+	movd	4(%eax), %mm6		C				un=3
+	pmuludq	%mm7, %mm6		C				un=3
+	movd	8(%eax), %mm2		C				un=3
+	pmuludq	%mm7, %mm2		C				un=3
+	movd	%mm6, 4(%edx)		C				un=3
+	psrlq	$32, %mm6		C				un=3
+	paddq	%mm2, %mm6		C				un=3
+	movd	%mm6, 8(%edx)		C				un=3
+	psrlq	$32, %mm6		C				un=3
+	movd	%mm6, 12(%edx)		C				un=3
+	lea	4(%edx), %edx		C				un=3
+	lea	4(%eax), %eax		C				un=3
+	jmp	L(am1)
+L(un4):	movd	(%eax), %mm7		C				un=4
+	movd	4(%eax), %mm6		C				un=4
+	pmuludq	%mm7, %mm6		C				un=4
+	movd	8(%eax), %mm0		C				un=4
+	pmuludq	%mm7, %mm0		C				un=4
+	movd	12(%eax), %mm1		C				un=4
+	pmuludq	%mm7, %mm1		C				un=4
+	movd	%mm6, 4(%edx)		C				un=4
+	psrlq	$32, %mm6		C				un=4
+	paddq	%mm0, %mm6		C				un=4
+	movd	%mm6, 8(%edx)		C				un=4
+	psrlq	$32, %mm6		C				un=4
+	paddq	%mm1, %mm6		C				un=4
+	movd	%mm6, 12(%edx)		C				un=4
+	psrlq	$32, %mm6		C				un=4
+	movd	%mm6, 16(%edx)		C				un=4
+	lea	4(%edx), %edx		C				un=4
+	lea	4(%eax), %eax		C				un=4
+	jmp	L(am2)
+
+L(big):	push	%esi
+	push	%ebx
+	push	%edi
+	pxor	%mm6, %mm6
+	movd	(%eax), %mm7		C
+	lea	4(%eax), %esi		C init up, up++
+	lea	4(%eax), %eax		C up2++  FIXME: should fix offsets
+	lea	4(%edx), %edi		C init rp, rp++
+	lea	4(%edx), %edx		C rp2++
+	lea	-4(%ecx), %ebx		C loop count
+	and	$3, %ecx
+	jz	L(3m)
+	cmp	$2, %ecx
+	ja	L(2m)
+	jb	L(0m)
+
+L(1m):
+	movd	(%eax), %mm4		C				m 1
+	lea	(%ebx), %ecx		C inner loop count		m 1
+	pmuludq	%mm7, %mm4		C				m 1
+	movd	4(%eax), %mm3		C				m 1
+	pmuludq	%mm7, %mm3		C				m 1
+	movd	8(%eax), %mm0		C				m 1
+	jmp	L(m01)			C				m 1
+	ALIGN(16)			C				m 1
+L(lpm1):
+	pmuludq	%mm7, %mm4		C				m 1
+	paddq	%mm0, %mm6		C				m 1
+	movd	4(%eax), %mm3		C				m 1
+	movd	%mm6, -8(%edx)		C				m 1
+	psrlq	$32, %mm6		C				m 1
+	pmuludq	%mm7, %mm3		C				m 1
+	paddq	%mm1, %mm6		C				m 1
+	movd	8(%eax), %mm0		C				m 1
+	movd	%mm6, -4(%edx)		C				m 1
+	psrlq	$32, %mm6		C				m 1
+L(m01):	pmuludq	%mm7, %mm0		C				m 1
+	paddq	%mm4, %mm6		C				m 1
+	movd	12(%eax), %mm1		C				m 1
+	movd	%mm6, (%edx)		C				m 1
+	psrlq	$32, %mm6		C				m 1
+	pmuludq	%mm7, %mm1		C				m 1
+	paddq	%mm3, %mm6		C				m 1
+	movd	16(%eax), %mm4		C				m 1
+	movd	%mm6, 4(%edx)		C				m 1
+	psrlq	$32, %mm6		C				m 1
+	lea	16(%eax), %eax		C				m 1
+	lea	16(%edx), %edx		C				m 1
+	sub	$4, %ecx		C				m 1
+	ja	L(lpm1)			C				m 1
+	pmuludq	%mm7, %mm4		C				m 1
+	paddq	%mm0, %mm6		C				m 1
+	movd	%mm6, -8(%edx)		C				m 1
+	psrlq	$32, %mm6		C				m 1
+	paddq	%mm1, %mm6		C				m 1
+	jmp	L(0)
+
+L(2m):
+	movd	(%eax), %mm1		C				m 2
+	lea	(%ebx), %ecx		C inner loop count		m 2
+	pmuludq	%mm7, %mm1		C				m 2
+	movd	4(%eax), %mm4		C				m 2
+	pmuludq	%mm7, %mm4		C				m 2
+	movd	8(%eax), %mm3		C				m 2
+	jmp	L(m10)			C				m 2
+	ALIGN(16)			C				m 2
+L(lpm2):
+	pmuludq	%mm7, %mm4		C				m 2
+	paddq	%mm0, %mm6		C				m 2
+	movd	8(%eax), %mm3		C				m 2
+	movd	%mm6, -4(%edx)		C				m 2
+	psrlq	$32, %mm6		C				m 2
+L(m10):	pmuludq	%mm7, %mm3		C				m 2
+	paddq	%mm1, %mm6		C				m 2
+	movd	12(%eax), %mm0		C				m 2
+	movd	%mm6, (%edx)		C				m 2
+	psrlq	$32, %mm6		C				m 2
+	pmuludq	%mm7, %mm0		C				m 2
+	paddq	%mm4, %mm6		C				m 2
+	movd	16(%eax), %mm1		C				m 2
+	movd	%mm6, 4(%edx)		C				m 2
+	psrlq	$32, %mm6		C				m 2
+	pmuludq	%mm7, %mm1		C				m 2
+	paddq	%mm3, %mm6		C				m 2
+	movd	20(%eax), %mm4		C				m 2
+	movd	%mm6, 8(%edx)		C				m 2
+	psrlq	$32, %mm6		C				m 2
+	lea	16(%eax), %eax		C				m 2
+	lea	16(%edx), %edx		C				m 2
+	sub	$4, %ecx		C				m 2
+	ja	L(lpm2)			C				m 2
+	pmuludq	%mm7, %mm4		C				m 2
+	paddq	%mm0, %mm6		C				m 2
+	movd	%mm6, -4(%edx)		C				m 2
+	psrlq	$32, %mm6		C				m 2
+	paddq	%mm1, %mm6		C				m 2
+	jmp	L(1)
+
+L(3m):
+	movd	(%eax), %mm0		C				m 3
+	lea	(%ebx), %ecx		C inner loop count		m 3
+	pmuludq	%mm7, %mm0		C				m 3
+	movd	4(%eax), %mm1		C				m 3
+	pmuludq	%mm7, %mm1		C				m 3
+	movd	8(%eax), %mm4		C				m 3
+	jmp	L(lpm3)			C				m 3
+	ALIGN(16)			C				m 3
+L(lpm3):
+	pmuludq	%mm7, %mm4		C				m 3
+	paddq	%mm0, %mm6		C				m 3
+	movd	12(%eax), %mm3		C				m 3
+	movd	%mm6, (%edx)		C				m 3
+	psrlq	$32, %mm6		C				m 3
+	pmuludq	%mm7, %mm3		C				m 3
+	paddq	%mm1, %mm6		C				m 3
+	movd	16(%eax), %mm0		C				m 3
+	movd	%mm6, 4(%edx)		C				m 3
+	psrlq	$32, %mm6		C				m 3
+	pmuludq	%mm7, %mm0		C				m 3
+	paddq	%mm4, %mm6		C				m 3
+	movd	20(%eax), %mm1		C				m 3
+	movd	%mm6, 8(%edx)		C				m 3
+	psrlq	$32, %mm6		C				m 3
+	pmuludq	%mm7, %mm1		C				m 3
+	paddq	%mm3, %mm6		C				m 3
+	movd	24(%eax), %mm4		C				m 3
+	movd	%mm6, 12(%edx)		C				m 3
+	psrlq	$32, %mm6		C				m 3
+	lea	16(%eax), %eax		C				m 3
+	lea	16(%edx), %edx		C				m 3
+	sub	$4, %ecx		C				m 3
+	ja	L(lpm3)			C				m 3
+	pmuludq	%mm7, %mm4		C				m 3
+	paddq	%mm0, %mm6		C				m 3
+	movd	%mm6, (%edx)		C				m 3
+	psrlq	$32, %mm6		C				m 3
+	paddq	%mm1, %mm6		C				m 3
+	jmp	L(2)
+
+L(0m):
+	movd	(%eax), %mm3		C				m 0
+	lea	(%ebx), %ecx		C inner loop count		m 0
+	pmuludq	%mm7, %mm3		C				m 0
+	movd	4(%eax), %mm0		C				m 0
+	pmuludq	%mm7, %mm0		C				m 0
+	movd	8(%eax), %mm1		C				m 0
+	jmp	L(m00)			C				m 0
+	ALIGN(16)			C				m 0
+L(lpm0):
+	pmuludq	%mm7, %mm4		C				m 0
+	paddq	%mm0, %mm6		C				m 0
+	movd	(%eax), %mm3		C				m 0
+	movd	%mm6, -12(%edx)		C				m 0
+	psrlq	$32, %mm6		C				m 0
+	pmuludq	%mm7, %mm3		C				m 0
+	paddq	%mm1, %mm6		C				m 0
+	movd	4(%eax), %mm0		C				m 0
+	movd	%mm6, -8(%edx)		C				m 0
+	psrlq	$32, %mm6		C				m 0
+	pmuludq	%mm7, %mm0		C				m 0
+	paddq	%mm4, %mm6		C				m 0
+	movd	8(%eax), %mm1		C				m 0
+	movd	%mm6, -4(%edx)		C				m 0
+	psrlq	$32, %mm6		C				m 0
+L(m00):	pmuludq	%mm7, %mm1		C				m 0
+	paddq	%mm3, %mm6		C				m 0
+	movd	12(%eax), %mm4		C				m 0
+	movd	%mm6, (%edx)		C				m 0
+	psrlq	$32, %mm6		C				m 0
+	lea	16(%eax), %eax		C				m 0
+	lea	16(%edx), %edx		C				m 0
+	sub	$4, %ecx		C				m 0
+	ja	L(lpm0)			C				m 0
+	pmuludq	%mm7, %mm4		C				m 0
+	paddq	%mm0, %mm6		C				m 0
+	movd	%mm6, -12(%edx)		C				m 0
+	psrlq	$32, %mm6		C				m 0
+	paddq	%mm1, %mm6		C				m 0
+	jmp	L(3)
+
+L(outer):
+	lea	8(%edi), %edi		C rp += 2
+	movd	(%esi), %mm7		C				am 3
+	mov	%edi, %edx		C rp2 = rp			am 3
+	lea	4(%esi), %esi		C up++				am 3
+	lea	(%esi), %eax		C up2 = up			am 3
+	movd	(%eax), %mm0		C				am 3
+	lea	(%ebx), %ecx		C inner loop count		am 3
+	pxor	%mm6, %mm6		C				am 3
+	pmuludq	%mm7, %mm0		C				am 3
+	movd	4(%eax), %mm1		C				am 3
+	movd	(%edx), %mm4		C				am 3
+	pmuludq	%mm7, %mm1		C				am 3
+	movd	8(%eax), %mm2		C				am 3
+	paddq	%mm0, %mm4		C				am 3
+	movd	4(%edx), %mm5		C				am 3
+	jmp	L(lam3)			C				am 3
+	ALIGN(16)			C				am 3
+L(lam3):
+	pmuludq	%mm7, %mm2		C				am 3
+	paddq	%mm4, %mm6		C				am 3
+	movd	12(%eax), %mm3		C				am 3
+	paddq	%mm1, %mm5		C				am 3
+	movd	8(%edx), %mm4		C				am 3
+	movd	%mm6, (%edx)		C				am 3
+	psrlq	$32, %mm6		C				am 3
+	pmuludq	%mm7, %mm3		C				am 3
+	paddq	%mm5, %mm6		C				am 3
+	movd	16(%eax), %mm0		C				am 3
+	paddq	%mm2, %mm4		C				am 3
+	movd	12(%edx), %mm5		C				am 3
+	movd	%mm6, 4(%edx)		C				am 3
+	psrlq	$32, %mm6		C				am 3
+	pmuludq	%mm7, %mm0		C				am 3
+	paddq	%mm4, %mm6		C				am 3
+	movd	20(%eax), %mm1		C				am 3
+	paddq	%mm3, %mm5		C				am 3
+	movd	16(%edx), %mm4		C				am 3
+	movd	%mm6, 8(%edx)		C				am 3
+	psrlq	$32, %mm6		C				am 3
+	pmuludq	%mm7, %mm1		C				am 3
+	paddq	%mm5, %mm6		C				am 3
+	movd	24(%eax), %mm2		C				am 3
+	paddq	%mm0, %mm4		C				am 3
+	movd	20(%edx), %mm5		C				am 3
+	movd	%mm6, 12(%edx)		C				am 3
+	psrlq	$32, %mm6		C				am 3
+	lea	16(%eax), %eax		C				am 3
+	lea	16(%edx), %edx		C				am 3
+	sub	$4, %ecx		C				am 3
+	ja	L(lam3)			C				am 3
+	pmuludq	%mm7, %mm2		C				am 3
+	paddq	%mm4, %mm6		C				am 3
+	paddq	%mm1, %mm5		C				am 3
+	movd	8(%edx), %mm4		C				am 3
+	movd	%mm6, (%edx)		C				am 3
+	psrlq	$32, %mm6		C				am 3
+	paddq	%mm5, %mm6		C				am 3
+	paddq	%mm2, %mm4		C				am 3
+L(2):	movd	%mm6, 4(%edx)		C				am 3
+	psrlq	$32, %mm6		C				am 3
+	paddq	%mm4, %mm6		C				am 3
+	movd	%mm6, 8(%edx)		C				am 3
+	psrlq	$32, %mm6		C				am 3
+	movd	%mm6, 12(%edx)		C				am 3
+
+	lea	8(%edi), %edi		C rp += 2
+	movd	(%esi), %mm7		C				am 2
+	mov	%edi, %edx		C rp2 = rp			am 2
+	lea	4(%esi), %esi		C up++				am 2
+	lea	(%esi), %eax		C up2 = up			am 2
+	movd	(%eax), %mm1		C				am 2
+	lea	(%ebx), %ecx		C inner loop count		am 2
+	pxor	%mm6, %mm6		C				am 2
+	pmuludq	%mm7, %mm1		C				am 2
+	movd	4(%eax), %mm2		C				am 2
+	movd	(%edx), %mm5		C				am 2
+	pmuludq	%mm7, %mm2		C				am 2
+	movd	8(%eax), %mm3		C				am 2
+	paddq	%mm1, %mm5		C				am 2
+	movd	4(%edx), %mm4		C				am 2
+	jmp	L(am10)			C				am 2
+	ALIGN(16)			C				am 2
+L(lam2):
+	pmuludq	%mm7, %mm2		C				am 2
+	paddq	%mm4, %mm6		C				am 2
+	movd	8(%eax), %mm3		C				am 2
+	paddq	%mm1, %mm5		C				am 2
+	movd	4(%edx), %mm4		C				am 2
+	movd	%mm6, -4(%edx)		C				am 2
+	psrlq	$32, %mm6		C				am 2
+L(am10):
+	pmuludq	%mm7, %mm3		C				am 2
+	paddq	%mm5, %mm6		C				am 2
+	movd	12(%eax), %mm0		C				am 2
+	paddq	%mm2, %mm4		C				am 2
+	movd	8(%edx), %mm5		C				am 2
+	movd	%mm6, (%edx)		C				am 2
+	psrlq	$32, %mm6		C				am 2
+	pmuludq	%mm7, %mm0		C				am 2
+	paddq	%mm4, %mm6		C				am 2
+	movd	16(%eax), %mm1		C				am 2
+	paddq	%mm3, %mm5		C				am 2
+	movd	12(%edx), %mm4		C				am 2
+	movd	%mm6, 4(%edx)		C				am 2
+	psrlq	$32, %mm6		C				am 2
+	pmuludq	%mm7, %mm1		C				am 2
+	paddq	%mm5, %mm6		C				am 2
+	movd	20(%eax), %mm2		C				am 2
+	paddq	%mm0, %mm4		C				am 2
+	movd	16(%edx), %mm5		C				am 2
+	movd	%mm6, 8(%edx)		C				am 2
+	psrlq	$32, %mm6		C				am 2
+	lea	16(%eax), %eax		C				am 2
+	lea	16(%edx), %edx		C				am 2
+	sub	$4, %ecx		C				am 2
+	ja	L(lam2)			C				am 2
+	pmuludq	%mm7, %mm2		C				am 2
+	paddq	%mm4, %mm6		C				am 2
+	paddq	%mm1, %mm5		C				am 2
+	movd	4(%edx), %mm4		C				am 2
+	movd	%mm6, -4(%edx)		C				am 2
+	psrlq	$32, %mm6		C				am 2
+	paddq	%mm5, %mm6		C				am 2
+	paddq	%mm2, %mm4		C				am 2
+L(1):	movd	%mm6, (%edx)		C				am 2
+	psrlq	$32, %mm6		C				am 2
+	paddq	%mm4, %mm6		C				am 2
+	movd	%mm6, 4(%edx)		C				am 2
+	psrlq	$32, %mm6		C				am 2
+	movd	%mm6, 8(%edx)		C				am 2
+
+	lea	8(%edi), %edi		C rp += 2
+	movd	(%esi), %mm7		C				am 1
+	mov	%edi, %edx		C rp2 = rp			am 1
+	lea	4(%esi), %esi		C up++				am 1
+	lea	(%esi), %eax		C up2 = up			am 1
+	movd	(%eax), %mm2		C				am 1
+	lea	(%ebx), %ecx		C inner loop count		am 1
+	pxor	%mm6, %mm6		C				am 1
+	pmuludq	%mm7, %mm2		C				am 1
+	movd	4(%eax), %mm3		C				am 1
+	movd	(%edx), %mm4		C				am 1
+	pmuludq	%mm7, %mm3		C				am 1
+	movd	8(%eax), %mm0		C				am 1
+	paddq	%mm2, %mm4		C				am 1
+	movd	4(%edx), %mm5		C				am 1
+	jmp	L(am01)			C				am 1
+	ALIGN(16)			C				am 1
+L(lam1):
+	pmuludq	%mm7, %mm2		C				am 1
+	paddq	%mm4, %mm6		C				am 1
+	movd	4(%eax), %mm3		C				am 1
+	paddq	%mm1, %mm5		C				am 1
+	movd	(%edx), %mm4		C				am 1
+	movd	%mm6, -8(%edx)		C				am 1
+	psrlq	$32, %mm6		C				am 1
+	pmuludq	%mm7, %mm3		C				am 1
+	paddq	%mm5, %mm6		C				am 1
+	movd	8(%eax), %mm0		C				am 1
+	paddq	%mm2, %mm4		C				am 1
+	movd	4(%edx), %mm5		C				am 1
+	movd	%mm6, -4(%edx)		C				am 1
+	psrlq	$32, %mm6		C				am 1
+L(am01):
+	pmuludq	%mm7, %mm0		C				am 1
+	paddq	%mm4, %mm6		C				am 1
+	movd	12(%eax), %mm1		C				am 1
+	paddq	%mm3, %mm5		C				am 1
+	movd	8(%edx), %mm4		C				am 1
+	movd	%mm6, (%edx)		C				am 1
+	psrlq	$32, %mm6		C				am 1
+	pmuludq	%mm7, %mm1		C				am 1
+	paddq	%mm5, %mm6		C				am 1
+	movd	16(%eax), %mm2		C				am 1
+	paddq	%mm0, %mm4		C				am 1
+	movd	12(%edx), %mm5		C				am 1
+	movd	%mm6, 4(%edx)		C				am 1
+	psrlq	$32, %mm6		C				am 1
+	lea	16(%eax), %eax		C				am 1
+	lea	16(%edx), %edx		C				am 1
+	sub	$4, %ecx		C				am 1
+	ja	L(lam1)			C				am 1
+	pmuludq	%mm7, %mm2		C				am 1
+	paddq	%mm4, %mm6		C				am 1
+	paddq	%mm1, %mm5		C				am 1
+	movd	(%edx), %mm4		C				am 1
+	movd	%mm6, -8(%edx)		C				am 1
+	psrlq	$32, %mm6		C				am 1
+	paddq	%mm5, %mm6		C				am 1
+	paddq	%mm2, %mm4		C				am 1
+L(0):	movd	%mm6, -4(%edx)		C				am 1
+	psrlq	$32, %mm6		C				am 1
+	paddq	%mm4, %mm6		C				am 1
+	movd	%mm6, (%edx)		C				am 1
+	psrlq	$32, %mm6		C				am 1
+	movd	%mm6, 4(%edx)		C				am 1
+
+	lea	8(%edi), %edi		C rp += 2
+	movd	(%esi), %mm7		C				am 0
+	mov	%edi, %edx		C rp2 = rp			am 0
+	lea	4(%esi), %esi		C up++				am 0
+	lea	(%esi), %eax		C up2 = up			am 0
+	movd	(%eax), %mm3		C				am 0
+	lea	(%ebx), %ecx		C inner loop count		am 0
+	pxor	%mm6, %mm6		C				am 0
+	pmuludq	%mm7, %mm3		C				am 0
+	movd	4(%eax), %mm0		C				am 0
+	movd	(%edx), %mm5		C				am 0
+	pmuludq	%mm7, %mm0		C				am 0
+	movd	8(%eax), %mm1		C				am 0
+	paddq	%mm3, %mm5		C				am 0
+	movd	4(%edx), %mm4		C				am 0
+	jmp	L(am00)			C				am 0
+	ALIGN(16)			C				am 0
+L(lam0):
+	pmuludq	%mm7, %mm2		C				am 0
+	paddq	%mm4, %mm6		C				am 0
+	movd	(%eax), %mm3		C				am 0
+	paddq	%mm1, %mm5		C				am 0
+	movd	-4(%edx), %mm4		C				am 0
+	movd	%mm6, -12(%edx)		C				am 0
+	psrlq	$32, %mm6		C				am 0
+	pmuludq	%mm7, %mm3		C				am 0
+	paddq	%mm5, %mm6		C				am 0
+	movd	4(%eax), %mm0		C				am 0
+	paddq	%mm2, %mm4		C				am 0
+	movd	(%edx), %mm5		C				am 0
+	movd	%mm6, -8(%edx)		C				am 0
+	psrlq	$32, %mm6		C				am 0
+	pmuludq	%mm7, %mm0		C				am 0
+	paddq	%mm4, %mm6		C				am 0
+	movd	8(%eax), %mm1		C				am 0
+	paddq	%mm3, %mm5		C				am 0
+	movd	4(%edx), %mm4		C				am 0
+	movd	%mm6, -4(%edx)		C				am 0
+	psrlq	$32, %mm6		C				am 0
+L(am00):
+	pmuludq	%mm7, %mm1		C				am 0
+	paddq	%mm5, %mm6		C				am 0
+	movd	12(%eax), %mm2		C				am 0
+	paddq	%mm0, %mm4		C				am 0
+	movd	8(%edx), %mm5		C				am 0
+	movd	%mm6, (%edx)		C				am 0
+	psrlq	$32, %mm6		C				am 0
+	lea	16(%eax), %eax		C				am 0
+	lea	16(%edx), %edx		C				am 0
+	sub	$4, %ecx		C				am 0
+	ja	L(lam0)			C				am 0
+	pmuludq	%mm7, %mm2		C				am 0
+	paddq	%mm4, %mm6		C				am 0
+	paddq	%mm1, %mm5		C				am 0
+	movd	-4(%edx), %mm4		C				am 0
+	movd	%mm6, -12(%edx)		C				am 0
+	psrlq	$32, %mm6		C				am 0
+	paddq	%mm5, %mm6		C				am 0
+	paddq	%mm2, %mm4		C				am 0
+L(3):	movd	%mm6, -8(%edx)		C				am 0
+	psrlq	$32, %mm6		C				am 0
+	paddq	%mm4, %mm6		C				am 0
+	movd	%mm6, -4(%edx)		C				am 0
+	psrlq	$32, %mm6		C				am 0
+	movd	%mm6, (%edx)		C				am 0
+	sub	$4, %ebx		C				am 0
+	ja	L(outer)			C				am 0
+
+	mov	%edi, %edx
+	mov	%esi, %eax
+	pop	%edi
+	pop	%ebx
+	pop	%esi
+
+L(am3):	C up[un-1..un-3] x up[un-4]
+	lea	8(%edx), %edx		C rp2 += 2
+	movd	(%eax), %mm7
+	movd	4(%eax), %mm1
+	movd	8(%eax), %mm2
+	movd	12(%eax), %mm3
+	movd	(%edx), %mm4
+	pmuludq	%mm7, %mm1
+	movd	4(%edx), %mm5
+	pmuludq	%mm7, %mm2
+	movd	8(%edx), %mm6
+	pmuludq	%mm7, %mm3
+	paddq	%mm1, %mm4
+	paddq	%mm2, %mm5
+	paddq	%mm3, %mm6
+	movd	%mm4, (%edx)
+	psrlq	$32, %mm4
+	paddq	%mm5, %mm4
+	movd	%mm4, 4(%edx)
+	psrlq	$32, %mm4
+	paddq	%mm6, %mm4
+	movd	%mm4, 8(%edx)
+	psrlq	$32, %mm4
+	movd	%mm4, 12(%edx)		C FIXME feed through!
+	lea	4(%eax), %eax
+
+L(am2):	C up[un-1..un-2] x up[un-3]
+	lea	8(%edx), %edx		C rp2 += 2
+	movd	(%eax), %mm7
+	movd	4(%eax), %mm1
+	movd	8(%eax), %mm2
+	movd	(%edx), %mm4
+	movd	4(%edx), %mm5
+	pmuludq	%mm7, %mm1
+	pmuludq	%mm7, %mm2
+	paddq	%mm1, %mm4
+	paddq	%mm2, %mm5
+	movd	%mm4, (%edx)
+	psrlq	$32, %mm4
+	paddq	%mm5, %mm4
+	movd	%mm4, 4(%edx)
+	psrlq	$32, %mm4
+	movd	%mm4, 8(%edx)		C FIXME feed through!
+	lea	4(%eax), %eax
+
+L(am1):	C up[un-1] x up[un-2]
+	lea	8(%edx), %edx		C rp2 += 2
+	movd	(%eax), %mm7
+	movd	4(%eax), %mm2
+	movd	(%edx), %mm4
+	pmuludq	%mm7, %mm2
+	paddq	%mm2, %mm4
+	movd	%mm4, (%edx)
+	psrlq	$32, %mm4
+	movd	%mm4, 4(%edx)
+
+C *** diag stuff, use elementary code for now
+
+	mov	4(%esp), %edx		C rp
+	mov	8(%esp), %eax		C up
+	mov	12(%esp), %ecx		C un
+
+	movd	(%eax), %mm2
+	pmuludq	%mm2, %mm2		C src[0]^2
+
+	pcmpeqd	%mm7, %mm7
+	psrlq	$32, %mm7
+
+	movd	4(%edx), %mm3		C dst[1]
+
+	movd	%mm2, (%edx)
+	psrlq	$32, %mm2
+
+	psllq	$1, %mm3		C 2*dst[1]
+	paddq	%mm3, %mm2
+	movd	%mm2, 4(%edx)
+	psrlq	$32, %mm2
+
+	sub	$2, %ecx
+
+L(diag):
+	movd	4(%eax), %mm0		C src limb
+	add	$4, %eax
+	pmuludq	%mm0, %mm0
+	movq	%mm7, %mm1
+	pand	%mm0, %mm1		C diagonal low
+	psrlq	$32, %mm0		C diagonal high
+
+	movd	8(%edx), %mm3
+	psllq	$1, %mm3		C 2*dst[i]
+	paddq	%mm3, %mm1
+	paddq	%mm1, %mm2
+	movd	%mm2, 8(%edx)
+	psrlq	$32, %mm2
+
+	movd	12(%edx), %mm3
+	psllq	$1, %mm3		C 2*dst[i+1]
+	paddq	%mm3, %mm0
+	paddq	%mm0, %mm2
+	movd	%mm2, 12(%edx)
+	add	$8, %edx
+	psrlq	$32, %mm2
+
+	sub	$1, %ecx
+	jnz	L(diag)
+
+	movd	4(%eax), %mm0		C src[size-1]
+	pmuludq	%mm0, %mm0
+	pand	%mm0, %mm7		C diagonal low
+	psrlq	$32, %mm0		C diagonal high
+
+	movd	8(%edx), %mm3		C dst[2*size-2]
+	psllq	$1, %mm3
+	paddq	%mm3, %mm7
+	paddq	%mm7, %mm2
+	movd	%mm2, 8(%edx)
+	psrlq	$32, %mm2
+
+	paddq	%mm0, %mm2
+	movd	%mm2, 12(%edx)		C dst[2*size-1]
+
+	emms
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/pentium4/sse2/sub_n.asm b/third_party/gmp/mpn/x86/pentium4/sse2/sub_n.asm
new file mode 100644
index 0000000..5ba1c01
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium4/sse2/sub_n.asm
@@ -0,0 +1,119 @@
+dnl  Intel Pentium-4 mpn_sub_n -- mpn subtraction.
+
+dnl  Copyright 2001, 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C					cycles/limb
+C			     dst!=src1,2  dst==src1  dst==src2
+C P6 model 0-8,10-12		-
+C P6 model 9   (Banias)		?
+C P6 model 13  (Dothan)		?
+C P4 model 0-1 (Willamette)	?
+C P4 model 2   (Northwood)	4	     6		6
+C P4 model 3-4 (Prescott)	4.25	     7.5	7.5
+
+defframe(PARAM_CARRY,20)
+defframe(PARAM_SIZE, 16)
+defframe(PARAM_SRC2, 12)
+defframe(PARAM_SRC1, 8)
+defframe(PARAM_DST,  4)
+
+dnl  re-use parameter space
+define(SAVE_EBX,`PARAM_SRC1')
+
+	TEXT
+	ALIGN(8)
+
+PROLOGUE(mpn_sub_nc)
+deflit(`FRAME',0)
+	movd	PARAM_CARRY, %mm0
+	jmp	L(start_nc)
+EPILOGUE()
+
+	ALIGN(8)
+PROLOGUE(mpn_sub_n)
+deflit(`FRAME',0)
+	pxor	%mm0, %mm0
+L(start_nc):
+	mov	PARAM_SRC1, %eax
+	mov	%ebx, SAVE_EBX
+	mov	PARAM_SRC2, %ebx
+	mov	PARAM_DST, %edx
+	mov	PARAM_SIZE, %ecx
+
+	lea	(%eax,%ecx,4), %eax	C src1 end
+	lea	(%ebx,%ecx,4), %ebx	C src2 end
+	lea	(%edx,%ecx,4), %edx	C dst end
+	neg	%ecx			C -size
+
+L(top):
+	C eax	src1 end
+	C ebx	src2 end
+	C ecx	counter, limbs, negative
+	C edx	dst end
+	C mm0	carry bit
+
+	movd	(%eax,%ecx,4), %mm1
+	movd	(%ebx,%ecx,4), %mm2
+	psubq	%mm2, %mm1
+
+	psubq	%mm0, %mm1
+	movd	%mm1, (%edx,%ecx,4)
+
+	psrlq	$63, %mm1
+
+	add	$1, %ecx
+	jz	L(done_mm1)
+
+	movd	(%eax,%ecx,4), %mm0
+	movd	(%ebx,%ecx,4), %mm2
+	psubq	%mm2, %mm0
+
+	psubq	%mm1, %mm0
+	movd	%mm0, (%edx,%ecx,4)
+
+	psrlq	$63, %mm0
+
+	add	$1, %ecx
+	jnz	L(top)
+
+	movd	%mm0, %eax
+	mov	SAVE_EBX, %ebx
+	emms
+	ret
+
+L(done_mm1):
+	movd	%mm1, %eax
+	mov	SAVE_EBX, %ebx
+	emms
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/pentium4/sse2/submul_1.asm b/third_party/gmp/mpn/x86/pentium4/sse2/submul_1.asm
new file mode 100644
index 0000000..020675b
--- /dev/null
+++ b/third_party/gmp/mpn/x86/pentium4/sse2/submul_1.asm
@@ -0,0 +1,182 @@
+dnl  Intel Pentium-4 mpn_submul_1 -- Multiply a limb vector with a limb and
+dnl  subtract the result from a second limb vector.
+
+dnl  Copyright 2001, 2002, 2008, 2010 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C			    cycles/limb
+C P6 model 0-8,10-12		-
+C P6 model 9   (Banias)		6.8
+C P6 model 13  (Dothan)		6.9
+C P4 model 0-1 (Willamette)	?
+C P4 model 2   (Northwood)	5.87
+C P4 model 3-4 (Prescott)	6.5
+
+C This code represents a step forwards compared to the code available before
+C GMP 5.1, but it is not carefully tuned for either P6 or P4.  In fact, it is
+C not good for P6.  For P4 it saved a bit over 1 c/l for both Northwood and
+C Prescott compared to the old code.
+C
+C The arrangements made here to get a two instruction dependent chain are
+C slightly subtle.  In the loop the carry (or borrow rather) is a negative so
+C that a paddq can be used to give a low limb ready to store, and a high limb
+C ready to become the new carry after a psrlq.
+C
+C If the carry was a simple twos complement negative then the psrlq shift would
+C need to bring in 0 bits or 1 bits according to whether the high was zero or
+C non-zero, since a non-zero value would represent a negative needing sign
+C extension.  That wouldn't be particularly easy to arrange and certainly would
+C add an instruction to the dependent chain, so instead an offset is applied so
+C that the high limb will be 0xFFFFFFFF+c.  With c in the range -0xFFFFFFFF to
+C 0, the value 0xFFFFFFFF+c is in the range 0 to 0xFFFFFFFF and is therefore
+C always positive and can always have 0 bits shifted in, which is what psrlq
+C does.
+C
+C The extra 0xFFFFFFFF must be subtracted before c is used, but that can be
+C done off the dependent chain.  The total adjustment then is to add
+C 0xFFFFFFFF00000000 to offset the new carry, and subtract 0x00000000FFFFFFFF
+C to remove the offset from the current carry, for a net add of
+C 0xFFFFFFFE00000001.  In the code this is applied to the destination limb when
+C fetched.
+C
+C It's also possible to view the 0xFFFFFFFF adjustment as a ones-complement
+C negative, which is how it's undone for the return value, but that doesn't
+C seem as clear.
+
+defframe(PARAM_CARRY,     20)
+defframe(PARAM_MULTIPLIER,16)
+defframe(PARAM_SIZE,      12)
+defframe(PARAM_SRC,       8)
+defframe(PARAM_DST,       4)
+
+	TEXT
+	ALIGN(16)
+
+PROLOGUE(mpn_submul_1c)
+deflit(`FRAME',0)
+	movd	PARAM_CARRY, %mm1
+	jmp	L(start_1c)
+EPILOGUE()
+
+PROLOGUE(mpn_submul_1)
+deflit(`FRAME',0)
+	pxor	%mm1, %mm1		C initial borrow
+
+L(start_1c):
+	mov	PARAM_SRC, %eax
+	pcmpeqd	%mm0, %mm0
+
+	movd	PARAM_MULTIPLIER, %mm7
+	pcmpeqd	%mm6, %mm6
+
+	mov	PARAM_DST, %edx
+	psrlq	$32, %mm0		C 0x00000000FFFFFFFF
+
+	mov	PARAM_SIZE, %ecx
+	psllq	$32, %mm6		C 0xFFFFFFFF00000000
+
+	psubq	%mm0, %mm6		C 0xFFFFFFFE00000001
+
+	psubq	%mm1, %mm0		C 0xFFFFFFFF - borrow
+
+
+	movd	(%eax), %mm3		C up
+	movd	(%edx), %mm4		C rp
+
+	add	$-1, %ecx
+	paddq	%mm6, %mm4		C add 0xFFFFFFFE00000001
+	pmuludq	%mm7, %mm3
+	jnz	L(gt1)
+	psubq	%mm3, %mm4		C prod
+	paddq	%mm4, %mm0		C borrow
+	movd	%mm0, (%edx)		C result
+	jmp	L(rt)
+
+L(gt1):	movd	4(%eax), %mm1		C up
+	movd	4(%edx), %mm2		C rp
+
+	add	$-1, %ecx
+	jz	L(eev)
+
+	ALIGN(16)
+L(top):	paddq	%mm6, %mm2		C add 0xFFFFFFFE00000001
+	pmuludq	%mm7, %mm1
+	psubq	%mm3, %mm4		C prod
+	movd	8(%eax), %mm3		C up
+	paddq	%mm4, %mm0		C borrow
+	movd	8(%edx), %mm4		C rp
+	movd	%mm0, (%edx)		C result
+	psrlq	$32, %mm0
+
+	add	$-1, %ecx
+	jz	L(eod)
+
+	paddq	%mm6, %mm4		C add 0xFFFFFFFE00000001
+	pmuludq	%mm7, %mm3
+	psubq	%mm1, %mm2		C prod
+	movd	12(%eax), %mm1		C up
+	paddq	%mm2, %mm0		C borrow
+	movd	12(%edx), %mm2		C rp
+	movd	%mm0, 4(%edx)		C result
+	psrlq	$32, %mm0
+
+	lea	8(%eax), %eax
+	lea	8(%edx), %edx
+	add	$-1, %ecx
+	jnz	L(top)
+
+
+L(eev):	paddq	%mm6, %mm2		C add 0xFFFFFFFE00000001
+	pmuludq	%mm7, %mm1
+	psubq	%mm3, %mm4		C prod
+	paddq	%mm4, %mm0		C borrow
+	movd	%mm0, (%edx)		C result
+	psrlq	$32, %mm0
+	psubq	%mm1, %mm2		C prod
+	paddq	%mm2, %mm0		C borrow
+	movd	%mm0, 4(%edx)		C result
+L(rt):	psrlq	$32, %mm0
+	movd	%mm0, %eax
+	not	%eax
+	emms
+	ret
+
+L(eod):	paddq	%mm6, %mm4		C add 0xFFFFFFFE00000001
+	pmuludq	%mm7, %mm3
+	psubq	%mm1, %mm2		C prod
+	paddq	%mm2, %mm0		C borrow
+	movd	%mm0, 4(%edx)		C result
+	psrlq	$32, %mm0
+	psubq	%mm3, %mm4		C prod
+	paddq	%mm4, %mm0		C borrow
+	movd	%mm0, 8(%edx)		C result
+	jmp	L(rt)
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/rshift.asm b/third_party/gmp/mpn/x86/rshift.asm
new file mode 100644
index 0000000..a60dcaa
--- /dev/null
+++ b/third_party/gmp/mpn/x86/rshift.asm
@@ -0,0 +1,108 @@
+dnl  x86 mpn_rshift -- mpn right shift.
+
+dnl  Copyright 1992, 1994, 1996, 1999-2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C     cycles/limb
+C P54	 7.5
+C P55	 7.0
+C P6	 2.5
+C K6	 4.5
+C K7	 5.0
+C P4	16.5
+
+
+C mp_limb_t mpn_rshift (mp_ptr dst, mp_srcptr src, mp_size_t size,
+C                       unsigned shift);
+
+defframe(PARAM_SHIFT,16)
+defframe(PARAM_SIZE, 12)
+defframe(PARAM_SRC,  8)
+defframe(PARAM_DST,  4)
+
+	TEXT
+	ALIGN(8)
+PROLOGUE(mpn_rshift)
+
+	pushl	%edi
+	pushl	%esi
+	pushl	%ebx
+deflit(`FRAME',12)
+
+	movl	PARAM_DST,%edi
+	movl	PARAM_SRC,%esi
+	movl	PARAM_SIZE,%edx
+	movl	PARAM_SHIFT,%ecx
+
+	leal	-4(%edi,%edx,4),%edi
+	leal	(%esi,%edx,4),%esi
+	negl	%edx
+
+	movl	(%esi,%edx,4),%ebx	C read least significant limb
+	xorl	%eax,%eax
+	shrdl(	%cl, %ebx, %eax)	C compute carry limb
+	incl	%edx
+	jz	L(end)
+	pushl	%eax			C push carry limb onto stack
+	testb	$1,%dl
+	jnz	L(1)			C enter loop in the middle
+	movl	%ebx,%eax
+
+	ALIGN(8)
+L(oop):	movl	(%esi,%edx,4),%ebx	C load next higher limb
+	shrdl(	%cl, %ebx, %eax)	C compute result limb
+	movl	%eax,(%edi,%edx,4)	C store it
+	incl	%edx
+L(1):	movl	(%esi,%edx,4),%eax
+	shrdl(	%cl, %eax, %ebx)
+	movl	%ebx,(%edi,%edx,4)
+	incl	%edx
+	jnz	L(oop)
+
+	shrl	%cl,%eax		C compute most significant limb
+	movl	%eax,(%edi)		C store it
+
+	popl	%eax			C pop carry limb
+
+	popl	%ebx
+	popl	%esi
+	popl	%edi
+	ret
+
+L(end):	shrl	%cl,%ebx		C compute most significant limb
+	movl	%ebx,(%edi)		C store it
+
+	popl	%ebx
+	popl	%esi
+	popl	%edi
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/sec_tabselect.asm b/third_party/gmp/mpn/x86/sec_tabselect.asm
new file mode 100644
index 0000000..c7c2e05
--- /dev/null
+++ b/third_party/gmp/mpn/x86/sec_tabselect.asm
@@ -0,0 +1,115 @@
+dnl  x86 mpn_sec_tabselect.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C			    cycles/limb
+C P5				 ?
+C P6 model 0-8,10-12		 ?
+C P6 model 9  (Banias)		 ?
+C P6 model 13 (Dothan)		 ?
+C P4 model 0  (Willamette)	 ?
+C P4 model 1  (?)		 ?
+C P4 model 2  (Northwood)	 4.5
+C P4 model 3  (Prescott)	 ?
+C P4 model 4  (Nocona)		 ?
+C Intel Atom			 ?
+C AMD K6			 ?
+C AMD K7			 3.4
+C AMD K8			 ?
+C AMD K10			 ?
+
+C NOTES
+C  * This has not been tuned for any specific processor.  Its speed should not
+C    be too bad, though.
+C  * Using SSE2 could result in many-fold speedup.
+
+C mpn_sec_tabselect (mp_limb_t *rp, mp_limb_t *tp, mp_size_t n, mp_size_t nents, mp_size_t which)
+define(`rp',     `%edi')
+define(`tp',     `%esi')
+define(`n',      `%ebx')
+define(`nents',  `%ecx')
+define(`which',  `36(%esp)')
+
+define(`i',      `%ebp')
+define(`maskp',  `20(%esp)')
+define(`maskn',  `32(%esp)')
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_sec_tabselect)
+	push	%edi
+	push	%esi
+	push	%ebx
+	push	%ebp
+	mov	20(%esp), rp
+	mov	24(%esp), tp
+	mov	28(%esp), n
+	mov	32(%esp), nents
+
+	lea	(rp,n,4), rp
+	lea	(tp,n,4), tp
+	sub	nents, which
+L(outer):
+	mov	which, %eax
+	add	nents, %eax
+	neg	%eax			C set CF iff 'which' != k
+	sbb	%eax, %eax
+	mov	%eax, maskn
+	not	%eax
+	mov	%eax, maskp
+
+	mov	n, i
+	neg	i
+
+	ALIGN(16)
+L(top):	mov	(tp,i,4), %eax
+	and	maskp, %eax
+	mov	(rp,i,4), %edx
+	and	maskn, %edx
+	or	%edx, %eax
+	mov	%eax, (rp,i,4)
+	inc	i
+	js	L(top)
+
+L(end):	mov	n, %eax
+	lea	(tp,%eax,4), tp
+	dec	nents
+	jne	L(outer)
+
+L(outer_end):
+	pop	%ebp
+	pop	%ebx
+	pop	%esi
+	pop	%edi
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/silvermont/gmp-mparam.h b/third_party/gmp/mpn/x86/silvermont/gmp-mparam.h
new file mode 100644
index 0000000..e9f1d8f
--- /dev/null
+++ b/third_party/gmp/mpn/x86/silvermont/gmp-mparam.h
@@ -0,0 +1,222 @@
+/* Intel Silvermont/32 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+/* 2400 MHz Intel Atom C2758 Silvermont/Rangeley */
+/* FFT tuning limit = 67,000,000 */
+/* Generated by tuneup.c, 2019-10-30, gcc 8.3 */
+
+#define MOD_1_NORM_THRESHOLD                 3
+#define MOD_1_UNNORM_THRESHOLD               5
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          9
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          5
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        11
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD         0  /* never mpn_mod_1s_2p */
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     16
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1N_PI1_METHOD                 1  /* 64.62% faster than 2 */
+#define DIV_QR_1_NORM_THRESHOLD          MP_SIZE_T_MAX  /* never */
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           32
+
+#define DIV_1_VS_MUL_1_PERCENT             204
+
+#define MUL_TOOM22_THRESHOLD                26
+#define MUL_TOOM33_THRESHOLD               105
+#define MUL_TOOM44_THRESHOLD               236
+#define MUL_TOOM6H_THRESHOLD               351
+#define MUL_TOOM8H_THRESHOLD               502
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD     105
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     163
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     137
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     174
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     215
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 36
+#define SQR_TOOM3_THRESHOLD                138
+#define SQR_TOOM4_THRESHOLD                360
+#define SQR_TOOM6_THRESHOLD                494
+#define SQR_TOOM8_THRESHOLD                620
+
+#define MULMID_TOOM42_THRESHOLD             58
+
+#define MULMOD_BNM1_THRESHOLD               15
+#define SQRMOD_BNM1_THRESHOLD               19
+
+#define MUL_FFT_MODF_THRESHOLD             460  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    460, 5}, {     21, 6}, {     11, 5}, {     23, 6}, \
+    {     12, 5}, {     25, 6}, {     13, 5}, {     27, 6}, \
+    {     21, 7}, {     11, 6}, {     25, 7}, {     13, 6}, \
+    {     27, 7}, {     15, 6}, {     31, 7}, {     17, 6}, \
+    {     35, 7}, {     19, 6}, {     39, 7}, {     21, 8}, \
+    {     11, 7}, {     27, 8}, {     15, 7}, {     35, 8}, \
+    {     19, 7}, {     41, 8}, {     23, 7}, {     47, 8}, \
+    {     27, 9}, {     15, 8}, {     31, 7}, {     63, 8}, \
+    {     39, 9}, {     23, 8}, {     51,10}, {     15, 9}, \
+    {     31, 8}, {     67, 9}, {     39, 8}, {     79, 9}, \
+    {     47, 8}, {     95,10}, {     31, 9}, {     79,10}, \
+    {     47, 9}, {     95,11}, {     31,10}, {     63, 9}, \
+    {    135,10}, {     79, 9}, {    159,10}, {     95,11}, \
+    {     63,10}, {    127, 9}, {    255,10}, {    143, 9}, \
+    {    287,10}, {    159,11}, {     95,10}, {    191,12}, \
+    {     63,11}, {    127,10}, {    255, 9}, {    511,10}, \
+    {    271, 9}, {    543,10}, {    287, 9}, {    575,11}, \
+    {    159,10}, {    319, 9}, {    639,10}, {    335, 9}, \
+    {    671,10}, {    351, 9}, {    703,11}, {    191,10}, \
+    {    383, 9}, {    767,10}, {    415, 9}, {    831,12}, \
+    {    127,11}, {    255,10}, {    543, 9}, {   1087,11}, \
+    {    287,10}, {    607, 9}, {   1215,11}, {    319,10}, \
+    {    671,11}, {    351,10}, {    735,12}, {    191,11}, \
+    {    383,10}, {    767,11}, {    415,10}, {    831,13}, \
+    {    127,12}, {    255,11}, {    543,10}, {   1087,11}, \
+    {    607,10}, {   1215,12}, {    319,11}, {    671,10}, \
+    {   1343,11}, {    735,10}, {   1471,12}, {    383,11}, \
+    {    863,10}, {   1727,12}, {    447,11}, {    959,13}, \
+    {    255,12}, {    511,11}, {   1087,12}, {    575,11}, \
+    {   1215,10}, {   2431,12}, {    639,11}, {   1343,12}, \
+    {    703,11}, {   1471,13}, {    383,12}, {    767,11}, \
+    {   1535,12}, {    831,11}, {   1727,10}, {   3455,12}, \
+    {    959,11}, {   1919,14}, {    255,13}, {    511,12}, \
+    {   1215,11}, {   2431,13}, {    639,12}, {   1471,11}, \
+    {   2943,13}, {    767,12}, {   1727,11}, {   3455,13}, \
+    {    895,12}, {   1919,14}, {    511,13}, {   1023,12}, \
+    {   2111,13}, {   1151,12}, {   2431,13}, {   1407,12}, \
+    {   2943,14}, {    767,13}, {   1663,12}, {   3455,13}, \
+    {   1919,15}, {    511,14}, {   1023,13}, {   2175,12}, \
+    {   4479,13}, {   2431,14}, {   1279,13}, {   2943,12}, \
+    {   5887,14}, {   1535,13}, {   3455,14}, {   1791,13}, \
+    {   3967,12}, {   7935,15}, {   1023,14}, {   2047,13}, \
+    {   4479,14}, {   2303,13}, {   4991,12}, {   9983,14}, \
+    {   2815,13}, {   5887,15}, {   1535,14}, {   3839,13}, \
+    {   7935,16} }
+#define MUL_FFT_TABLE3_SIZE 177
+#define MUL_FFT_THRESHOLD                 4544
+
+#define SQR_FFT_MODF_THRESHOLD             400  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    400, 5}, {     21, 6}, {     11, 5}, {     23, 6}, \
+    {     12, 5}, {     25, 6}, {     13, 5}, {     28, 6}, \
+    {     21, 7}, {     11, 6}, {     25, 7}, {     13, 6}, \
+    {     28, 7}, {     15, 6}, {     32, 7}, {     17, 6}, \
+    {     35, 7}, {     19, 6}, {     39, 7}, {     21, 8}, \
+    {     11, 7}, {     27, 8}, {     15, 7}, {     35, 8}, \
+    {     19, 7}, {     41, 8}, {     23, 7}, {     47, 8}, \
+    {     27, 9}, {     15, 8}, {     31, 7}, {     63, 8}, \
+    {     39, 9}, {     23, 8}, {     51,10}, {     15, 9}, \
+    {     31, 8}, {     67, 9}, {     39, 8}, {     79, 9}, \
+    {     55,10}, {     31, 9}, {     79,10}, {     47, 9}, \
+    {     95,11}, {     31,10}, {     63, 9}, {    127,10}, \
+    {     79, 9}, {    159,10}, {     95,11}, {     63,10}, \
+    {    127, 9}, {    255,10}, {    143, 9}, {    287, 8}, \
+    {    575,10}, {    159,11}, {     95,12}, {     63,11}, \
+    {    127,10}, {    255, 9}, {    511,10}, {    271, 9}, \
+    {    543,10}, {    287, 9}, {    575,11}, {    159,10}, \
+    {    319, 9}, {    639,10}, {    335, 9}, {    671,10}, \
+    {    351, 9}, {    735,11}, {    191,10}, {    383, 9}, \
+    {    799,10}, {    415, 9}, {    831,11}, {    223,12}, \
+    {    127,11}, {    255,10}, {    543, 9}, {   1087,11}, \
+    {    287,10}, {    607, 9}, {   1215,11}, {    319,10}, \
+    {    671,11}, {    351,10}, {    735, 9}, {   1471,12}, \
+    {    191,11}, {    383,10}, {    799,11}, {    415,10}, \
+    {    863,13}, {    127,12}, {    255,11}, {    543,10}, \
+    {   1087,11}, {    607,10}, {   1215,12}, {    319,11}, \
+    {    671,10}, {   1343,11}, {    735,10}, {   1471,12}, \
+    {    383,11}, {    863,10}, {   1727,12}, {    447,11}, \
+    {    959,13}, {    255,12}, {    511,11}, {   1087,12}, \
+    {    575,11}, {   1215,10}, {   2431,12}, {    639,11}, \
+    {   1343,12}, {    703,11}, {   1471,13}, {    383,12}, \
+    {    767,11}, {   1535,12}, {    831,11}, {   1727,12}, \
+    {    959,14}, {    255,13}, {    511,12}, {   1215,11}, \
+    {   2431,13}, {    639,12}, {   1471,11}, {   2943,13}, \
+    {    767,12}, {   1727,11}, {   3455,13}, {    895,12}, \
+    {   1919,14}, {    511,13}, {   1023,12}, {   2111,13}, \
+    {   1151,12}, {   2431,13}, {   1407,12}, {   2943,14}, \
+    {    767,13}, {   1663,12}, {   3455,13}, {   1919,15}, \
+    {    511,14}, {   1023,13}, {   2175,12}, {   4479,13}, \
+    {   2431,14}, {   1279,13}, {   2943,12}, {   5887,14}, \
+    {   1535,13}, {   3455,14}, {   1791,13}, {   3967,15}, \
+    {   1023,14}, {   2047,13}, {   4479,14}, {   2303,13}, \
+    {   4991,12}, {   9983,14}, {   2815,13}, {   5887,15}, \
+    {   1535,14}, {   3839,13}, {   7679,16} }
+#define SQR_FFT_TABLE3_SIZE 175
+#define SQR_FFT_THRESHOLD                 3712
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  56
+#define MULLO_MUL_N_THRESHOLD             8907
+#define SQRLO_BASECASE_THRESHOLD             0  /* always */
+#define SQRLO_DC_THRESHOLD                 137
+#define SQRLO_SQR_THRESHOLD               7373
+
+#define DC_DIV_QR_THRESHOLD                 76
+#define DC_DIVAPPR_Q_THRESHOLD             336
+#define DC_BDIV_QR_THRESHOLD                66
+#define DC_BDIV_Q_THRESHOLD                218
+
+#define INV_MULMOD_BNM1_THRESHOLD           50
+#define INV_NEWTON_THRESHOLD               345
+#define INV_APPR_THRESHOLD                 342
+
+#define BINV_NEWTON_THRESHOLD              366
+#define REDC_1_TO_REDC_N_THRESHOLD          91
+
+#define MU_DIV_QR_THRESHOLD               1652
+#define MU_DIVAPPR_Q_THRESHOLD            1858
+#define MUPI_DIV_QR_THRESHOLD              171
+#define MU_BDIV_QR_THRESHOLD              1442
+#define MU_BDIV_Q_THRESHOLD               1830
+
+#define POWM_SEC_TABLE  3,17,102,404,1185
+
+#define GET_STR_DC_THRESHOLD                14
+#define GET_STR_PRECOMPUTE_THRESHOLD        21
+#define SET_STR_DC_THRESHOLD               272
+#define SET_STR_PRECOMPUTE_THRESHOLD       788
+
+#define FAC_DSC_THRESHOLD                  132
+#define FAC_ODD_THRESHOLD                   34
+
+#define MATRIX22_STRASSEN_THRESHOLD         19
+#define HGCD2_DIV1_METHOD                    1  /* 0.59% faster than 3 */
+#define HGCD_THRESHOLD                     142
+#define HGCD_APPR_THRESHOLD                181
+#define HGCD_REDUCE_THRESHOLD             2681
+#define GCD_DC_THRESHOLD                   492
+#define GCDEXT_DC_THRESHOLD                365
+#define JACOBI_BASE_METHOD                   1  /* 0.41% faster than 2 */
+
+/* Tuneup completed successfully, took 147027 seconds */
diff --git a/third_party/gmp/mpn/x86/skylake/gmp-mparam.h b/third_party/gmp/mpn/x86/skylake/gmp-mparam.h
new file mode 100644
index 0000000..fb87957
--- /dev/null
+++ b/third_party/gmp/mpn/x86/skylake/gmp-mparam.h
@@ -0,0 +1,211 @@
+/* x86/skylake gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+/* 3600-4000 MHz Intel Xeon E3-1270v5 Skylake */
+/* FFT tuning limit = 67,000,000 */
+/* Generated by tuneup.c, 2019-10-21, gcc 8.3 */
+
+#define MOD_1_NORM_THRESHOLD                15
+#define MOD_1_UNNORM_THRESHOLD              16
+#define MOD_1N_TO_MOD_1_1_THRESHOLD         10
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          8
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD         0  /* never mpn_mod_1_1p */
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        10
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD      9
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1N_PI1_METHOD                 1  /* 5.63% faster than 2 */
+#define DIV_QR_1_NORM_THRESHOLD             12
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD              17
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           18
+
+#define DIV_1_VS_MUL_1_PERCENT             348
+
+#define MUL_TOOM22_THRESHOLD                24
+#define MUL_TOOM33_THRESHOLD                81
+#define MUL_TOOM44_THRESHOLD               208
+#define MUL_TOOM6H_THRESHOLD               303
+#define MUL_TOOM8H_THRESHOLD               454
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      81
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     149
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     137
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     145
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     196
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 40
+#define SQR_TOOM3_THRESHOLD                129
+#define SQR_TOOM4_THRESHOLD                220
+#define SQR_TOOM6_THRESHOLD                354
+#define SQR_TOOM8_THRESHOLD                608
+
+#define MULMID_TOOM42_THRESHOLD             72
+
+#define MULMOD_BNM1_THRESHOLD               17
+#define SQRMOD_BNM1_THRESHOLD               21
+
+#define MUL_FFT_MODF_THRESHOLD             530  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    530, 5}, {     29, 6}, {     15, 5}, {     31, 6}, \
+    {     29, 7}, {     15, 6}, {     33, 7}, {     17, 6}, \
+    {     36, 7}, {     19, 6}, {     39, 7}, {     21, 6}, \
+    {     43, 7}, {     23, 6}, {     47, 7}, {     29, 8}, \
+    {     15, 7}, {     35, 8}, {     19, 7}, {     43, 8}, \
+    {     23, 7}, {     49, 8}, {     27, 7}, {     55, 9}, \
+    {     15, 8}, {     31, 7}, {     63, 8}, {     43, 9}, \
+    {     23, 8}, {     51, 9}, {     31, 8}, {     67, 9}, \
+    {     39, 8}, {     83, 9}, {     47, 8}, {     95, 9}, \
+    {     55,10}, {     31, 9}, {     79,10}, {     47, 9}, \
+    {     95,11}, {     31,10}, {     63, 9}, {    135,10}, \
+    {     79, 9}, {    159,10}, {     95, 9}, {    191,10}, \
+    {    111,11}, {     63,10}, {    143, 9}, {    287,10}, \
+    {    159,11}, {     95,10}, {    191,12}, {     63,11}, \
+    {    127,10}, {    255, 9}, {    511,10}, {    271, 9}, \
+    {    543,10}, {    287,11}, {    159,10}, {    351,11}, \
+    {    191,10}, {    415,12}, {    127,11}, {    255,10}, \
+    {    543,11}, {    287,10}, {    607,11}, {    319,10}, \
+    {    671,11}, {    351,12}, {    191,11}, {    383,10}, \
+    {    799,11}, {    415,13}, {    127,12}, {    255,11}, \
+    {    543,10}, {   1087,11}, {    607,12}, {    319,11}, \
+    {    671,10}, {   1343,11}, {    735,12}, {    383,11}, \
+    {    799,10}, {   1599,11}, {    863,12}, {    447,11}, \
+    {    959,13}, {    255,12}, {    511,11}, {   1087,12}, \
+    {    575,11}, {   1215,12}, {    639,11}, {   1343,12}, \
+    {    703,13}, {    383,12}, {    767,11}, {   1599,12}, \
+    {    831,11}, {   1727,12}, {    959,14}, {    255,13}, \
+    {    511,12}, {   1087,11}, {   2239,12}, {   1215,11}, \
+    {   2431,13}, {    639,12}, {   1471,13}, {    767,12}, \
+    {   1727,13}, {    895,12}, {   1919,14}, {    511,13}, \
+    {   1023,12}, {   2239,13}, {   1151,12}, {   2431,13}, \
+    {   1279,12}, {   2623,13}, {   1407,12}, {   2815,14}, \
+    {    767,13}, {   1663,12}, {   3455,13}, {   1919,15}, \
+    {    511,14}, {   1023,13}, {   2175,12}, {   4479,13}, \
+    {   2431,14}, {   1279,13}, {   2943,12}, {   5887,14}, \
+    {   1535,13}, {   3455,14}, {   1791,13}, {   3967,15}, \
+    {   1023,14}, {   2047,13}, {   4479,14}, {   2303,13}, \
+    {   4991,12}, {   9983,14}, {   2815,13}, {   5887,15}, \
+    {   1535,14}, {   3839,16} }
+#define MUL_FFT_TABLE3_SIZE 154
+#define MUL_FFT_THRESHOLD                 6784
+
+#define SQR_FFT_MODF_THRESHOLD             460  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    460, 5}, {     29, 6}, {     15, 5}, {     31, 6}, \
+    {     29, 7}, {     15, 6}, {     33, 7}, {     17, 6}, \
+    {     36, 7}, {     19, 6}, {     39, 7}, {     29, 8}, \
+    {     15, 7}, {     35, 8}, {     19, 7}, {     41, 8}, \
+    {     23, 7}, {     49, 8}, {     27, 7}, {     55, 9}, \
+    {     15, 8}, {     31, 7}, {     63, 8}, {     43, 9}, \
+    {     23, 8}, {     55,10}, {     15, 9}, {     31, 8}, \
+    {     67, 9}, {     39, 8}, {     79, 9}, {     47, 8}, \
+    {     95, 9}, {     55,10}, {     31, 9}, {     79,10}, \
+    {     47, 9}, {     95,11}, {     31,10}, {     63, 9}, \
+    {    135,10}, {     79, 9}, {    159,10}, {     95,11}, \
+    {     63,10}, {    127, 9}, {    255,10}, {    143, 9}, \
+    {    287,10}, {    159,11}, {     95,12}, {     63,11}, \
+    {    127,10}, {    271, 9}, {    543,10}, {    287,11}, \
+    {    159,10}, {    319, 9}, {    639,10}, {    351,11}, \
+    {    191,10}, {    415,12}, {    127,11}, {    255,10}, \
+    {    543,11}, {    287,10}, {    575,11}, {    319,10}, \
+    {    671,11}, {    351,10}, {    703,12}, {    191,11}, \
+    {    383,10}, {    799,11}, {    415,10}, {    831,13}, \
+    {    127,12}, {    255,11}, {    511,10}, {   1023,11}, \
+    {    543,10}, {   1087,11}, {    607,12}, {    319,11}, \
+    {    671,10}, {   1343,11}, {    735,12}, {    383,11}, \
+    {    799,10}, {   1599,11}, {    863,12}, {    447,11}, \
+    {    927,13}, {    255,12}, {    511,11}, {   1087,12}, \
+    {    575,11}, {   1215,12}, {    639,11}, {   1343,12}, \
+    {    703,11}, {   1407,13}, {    383,12}, {    767,11}, \
+    {   1599,12}, {    831,11}, {   1727,12}, {    895,11}, \
+    {   1791,14}, {    255,13}, {    511,12}, {   1087,11}, \
+    {   2239,12}, {   1215,13}, {    639,12}, {   1471,13}, \
+    {    767,12}, {   1727,13}, {    895,12}, {   1919,14}, \
+    {    511,13}, {   1023,12}, {   2239,13}, {   1151,12}, \
+    {   2431,13}, {   1279,12}, {   2623,13}, {   1407,12}, \
+    {   2815,14}, {    767,13}, {   1663,12}, {   3455,13}, \
+    {   1919,15}, {    511,14}, {   1023,13}, {   2175,12}, \
+    {   4479,13}, {   2431,14}, {   1279,13}, {   2943,12}, \
+    {   5887,14}, {   1535,13}, {   3455,14}, {   1791,13}, \
+    {   3967,15}, {   1023,14}, {   2047,13}, {   4479,14}, \
+    {   2303,13}, {   4991,12}, {   9983,14}, {   2815,13}, \
+    {   5887,15}, {   1535,14}, {   3839,16} }
+#define SQR_FFT_TABLE3_SIZE 155
+#define SQR_FFT_THRESHOLD                 5568
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  68
+#define MULLO_MUL_N_THRESHOLD            13555
+#define SQRLO_BASECASE_THRESHOLD             0  /* always */
+#define SQRLO_DC_THRESHOLD                 117
+#define SQRLO_SQR_THRESHOLD              10988
+
+#define DC_DIV_QR_THRESHOLD                 42
+#define DC_DIVAPPR_Q_THRESHOLD             163
+#define DC_BDIV_QR_THRESHOLD                66
+#define DC_BDIV_Q_THRESHOLD                160
+
+#define INV_MULMOD_BNM1_THRESHOLD           46
+#define INV_NEWTON_THRESHOLD               165
+#define INV_APPR_THRESHOLD                 157
+
+#define BINV_NEWTON_THRESHOLD              300
+#define REDC_1_TO_REDC_N_THRESHOLD          68
+
+#define MU_DIV_QR_THRESHOLD               1718
+#define MU_DIVAPPR_Q_THRESHOLD            1685
+#define MUPI_DIV_QR_THRESHOLD               62
+#define MU_BDIV_QR_THRESHOLD              1589
+#define MU_BDIV_Q_THRESHOLD               1830
+
+#define POWM_SEC_TABLE  1,17,129,547,1317
+
+#define GET_STR_DC_THRESHOLD                10
+#define GET_STR_PRECOMPUTE_THRESHOLD        16
+#define SET_STR_DC_THRESHOLD               354
+#define SET_STR_PRECOMPUTE_THRESHOLD       860
+
+#define FAC_DSC_THRESHOLD                  141
+#define FAC_ODD_THRESHOLD                   34
+
+#define MATRIX22_STRASSEN_THRESHOLD         20
+#define HGCD2_DIV1_METHOD                    5  /* 1.04% faster than 3 */
+#define HGCD_THRESHOLD                     114
+#define HGCD_APPR_THRESHOLD                132
+#define HGCD_REDUCE_THRESHOLD             3524
+#define GCD_DC_THRESHOLD                   474
+#define GCDEXT_DC_THRESHOLD                379
+#define JACOBI_BASE_METHOD                   1  /* 27.39% faster than 4 */
+
+/* Tuneup completed successfully, took 31721 seconds */
diff --git a/third_party/gmp/mpn/x86/sqr_basecase.asm b/third_party/gmp/mpn/x86/sqr_basecase.asm
new file mode 100644
index 0000000..39f8a89
--- /dev/null
+++ b/third_party/gmp/mpn/x86/sqr_basecase.asm
@@ -0,0 +1,359 @@
+dnl  x86 generic mpn_sqr_basecase -- square an mpn number.
+
+dnl  Copyright 1999, 2000, 2002, 2003 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+
+C     cycles/crossproduct  cycles/triangleproduct
+C P5
+C P6
+C K6
+C K7
+C P4
+
+
+C void mpn_sqr_basecase (mp_ptr dst, mp_srcptr src, mp_size_t size);
+C
+C The algorithm is basically the same as mpn/generic/sqr_basecase.c, but a
+C lot of function call overheads are avoided, especially when the size is
+C small.
+C
+C The mul1 loop is not unrolled like mul_1.asm, it doesn't seem worth the
+C code size to do so here.
+C
+C Enhancements:
+C
+C The addmul loop here is also not unrolled like aorsmul_1.asm and
+C mul_basecase.asm are.  Perhaps it should be done.  It'd add to the
+C complexity, but if it's worth doing in the other places then it should be
+C worthwhile here.
+C
+C A fully-unrolled style like other sqr_basecase.asm versions (k6, k7, p6)
+C might be worth considering.  That'd add quite a bit to the code size, but
+C only as much as is used would be dragged into L1 cache.
+
+defframe(PARAM_SIZE,12)
+defframe(PARAM_SRC, 8)
+defframe(PARAM_DST, 4)
+
+	TEXT
+	ALIGN(8)
+PROLOGUE(mpn_sqr_basecase)
+deflit(`FRAME',0)
+
+	movl	PARAM_SIZE, %edx
+
+	movl	PARAM_SRC, %eax
+
+	cmpl	$2, %edx
+	movl	PARAM_DST, %ecx
+
+	je	L(two_limbs)
+	ja	L(three_or_more)
+
+
+C -----------------------------------------------------------------------------
+C one limb only
+	C eax	src
+	C ebx
+	C ecx	dst
+	C edx
+
+	movl	(%eax), %eax
+	mull	%eax
+	movl	%eax, (%ecx)
+	movl	%edx, 4(%ecx)
+	ret
+
+
+C -----------------------------------------------------------------------------
+	ALIGN(8)
+L(two_limbs):
+	C eax	src
+	C ebx
+	C ecx	dst
+	C edx
+
+	pushl	%ebx
+	pushl	%ebp
+
+	movl	%eax, %ebx
+	movl	(%eax), %eax
+
+	mull	%eax		C src[0]^2
+
+	pushl	%esi
+	pushl	%edi
+
+	movl	%edx, %esi	C dst[1]
+	movl	%eax, (%ecx)	C dst[0]
+
+	movl	4(%ebx), %eax
+	mull	%eax		C src[1]^2
+
+	movl	%eax, %edi	C dst[2]
+	movl	%edx, %ebp	C dst[3]
+
+	movl	(%ebx), %eax
+	mull	4(%ebx)		C src[0]*src[1]
+
+	addl	%eax, %esi
+
+	adcl	%edx, %edi
+
+	adcl	$0, %ebp
+	addl	%esi, %eax
+
+	adcl	%edi, %edx
+	movl	%eax, 4(%ecx)
+
+	adcl	$0, %ebp
+
+	movl	%edx, 8(%ecx)
+	movl	%ebp, 12(%ecx)
+
+	popl	%edi
+	popl	%esi
+
+	popl	%ebp
+	popl	%ebx
+
+	ret
+
+
+C -----------------------------------------------------------------------------
+	ALIGN(8)
+L(three_or_more):
+deflit(`FRAME',0)
+	C eax	src
+	C ebx
+	C ecx	dst
+	C edx	size
+
+	pushl	%ebx	FRAME_pushl()
+	pushl	%edi	FRAME_pushl()
+
+	pushl	%esi	FRAME_pushl()
+	pushl	%ebp	FRAME_pushl()
+
+	leal	(%ecx,%edx,4), %edi	C &dst[size], end of this mul1
+	leal	(%eax,%edx,4), %esi	C &src[size]
+
+C First multiply src[0]*src[1..size-1] and store at dst[1..size].
+
+	movl	(%eax), %ebp		C src[0], multiplier
+	movl	%edx, %ecx
+
+	negl	%ecx			C -size
+	xorl	%ebx, %ebx		C clear carry limb
+
+	incl	%ecx			C -(size-1)
+
+L(mul1):
+	C eax	scratch
+	C ebx	carry
+	C ecx	counter, limbs, negative
+	C edx	scratch
+	C esi	&src[size]
+	C edi	&dst[size]
+	C ebp	multiplier
+
+	movl	(%esi,%ecx,4), %eax
+	mull	%ebp
+	addl	%eax, %ebx
+	adcl	$0, %edx
+	movl	%ebx, (%edi,%ecx,4)
+	movl	%edx, %ebx
+	incl	%ecx
+	jnz	L(mul1)
+
+	movl	%ebx, (%edi)
+
+
+	C Add products src[n]*src[n+1..size-1] at dst[2*n-1...], for
+	C n=1..size-2.
+	C
+	C The last products src[size-2]*src[size-1], which is the end corner
+	C of the product triangle, is handled separately at the end to save
+	C looping overhead.  If size is 3 then it's only this that needs to
+	C be done.
+	C
+	C In the outer loop %esi is a constant, and %edi just advances by 1
+	C limb each time.  The size of the operation decreases by 1 limb
+	C each time.
+
+	C eax
+	C ebx	carry (needing carry flag added)
+	C ecx
+	C edx
+	C esi	&src[size]
+	C edi	&dst[size]
+	C ebp
+
+	movl	PARAM_SIZE, %ecx
+	subl	$3, %ecx
+	jz	L(corner)
+
+	negl	%ecx
+
+dnl  re-use parameter space
+define(VAR_OUTER,`PARAM_DST')
+
+L(outer):
+	C eax
+	C ebx
+	C ecx
+	C edx	outer loop counter, -(size-3) to -1
+	C esi	&src[size]
+	C edi	dst, pointing at stored carry limb of previous loop
+	C ebp
+
+	movl	%ecx, VAR_OUTER
+	addl	$4, %edi		C advance dst end
+
+	movl	-8(%esi,%ecx,4), %ebp	C next multiplier
+	subl	$1, %ecx
+
+	xorl	%ebx, %ebx		C initial carry limb
+
+L(inner):
+	C eax	scratch
+	C ebx	carry (needing carry flag added)
+	C ecx	counter, -n-1 to -1
+	C edx	scratch
+	C esi	&src[size]
+	C edi	dst end of this addmul
+	C ebp	multiplier
+
+	movl	(%esi,%ecx,4), %eax
+	mull	%ebp
+	addl	%ebx, %eax
+	adcl	$0, %edx
+	addl	%eax, (%edi,%ecx,4)
+	adcl	$0, %edx
+	movl	%edx, %ebx
+	addl	$1, %ecx
+	jl	L(inner)
+
+
+	movl	%ebx, (%edi)
+	movl	VAR_OUTER, %ecx
+	incl	%ecx
+	jnz	L(outer)
+
+
+L(corner):
+	C esi	&src[size]
+	C edi	&dst[2*size-3]
+
+	movl	-4(%esi), %eax
+	mull	-8(%esi)		C src[size-1]*src[size-2]
+	addl	%eax, 0(%edi)
+	adcl	$0, %edx
+	movl	%edx, 4(%edi)		C dst high limb
+
+
+C -----------------------------------------------------------------------------
+C Left shift of dst[1..2*size-2], high bit shifted out becomes dst[2*size-1].
+
+	movl	PARAM_SIZE, %eax
+	negl	%eax
+	addl	$1, %eax		C -(size-1) and clear carry
+
+L(lshift):
+	C eax	counter, negative
+	C ebx	next limb
+	C ecx
+	C edx
+	C esi
+	C edi	&dst[2*size-4]
+	C ebp
+
+	rcll	8(%edi,%eax,8)
+	rcll	12(%edi,%eax,8)
+	incl	%eax
+	jnz	L(lshift)
+
+
+	adcl	%eax, %eax		C high bit out
+	movl	%eax, 8(%edi)		C dst most significant limb
+
+
+C Now add in the squares on the diagonal, namely src[0]^2, src[1]^2, ...,
+C src[size-1]^2.  dst[0] hasn't yet been set at all yet, and just gets the
+C low limb of src[0]^2.
+
+	movl	PARAM_SRC, %esi
+	movl	(%esi), %eax		C src[0]
+	mull	%eax			C src[0]^2
+
+	movl	PARAM_SIZE, %ecx
+	leal	(%esi,%ecx,4), %esi	C src end
+
+	negl	%ecx			C -size
+	movl	%edx, %ebx		C initial carry
+
+	movl	%eax, 12(%edi,%ecx,8)	C dst[0]
+	incl	%ecx			C -(size-1)
+
+L(diag):
+	C eax	scratch (low product)
+	C ebx	carry limb
+	C ecx	counter, -(size-1) to -1
+	C edx	scratch (high product)
+	C esi	&src[size]
+	C edi	&dst[2*size-3]
+	C ebp	scratch (fetched dst limbs)
+
+	movl	(%esi,%ecx,4), %eax
+	mull	%eax
+
+	addl	%ebx, 8(%edi,%ecx,8)
+	movl	%edx, %ebx
+
+	adcl	%eax, 12(%edi,%ecx,8)
+	adcl	$0, %ebx
+
+	incl	%ecx
+	jnz	L(diag)
+
+
+	addl	%ebx, 8(%edi)		C dst most significant limb
+
+	popl	%ebp
+	popl	%esi
+
+	popl	%edi
+	popl	%ebx
+
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/t-zdisp.sh b/third_party/gmp/mpn/x86/t-zdisp.sh
new file mode 100755
index 0000000..61efdd6
--- /dev/null
+++ b/third_party/gmp/mpn/x86/t-zdisp.sh
@@ -0,0 +1,71 @@
+#! /bin/sh
+#
+# Copyright 2000 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+
+# Usage: cd $(builddir)/mpn
+#        $(srcdir)/x86/t-zdisp.sh
+#
+# Run the Zdisp() macro instructions through the assembler to check
+# the encodings used.  Mismatches are printed, no output means all ok.
+#
+# This program is only meant for use during development.  It can be
+# run in the mpn build directory of any x86 configuration.
+#
+# For this test the assembler needs to generate byte sized 0
+# displacements when given something like 0(%eax).  Recent versions of
+# gas are suitable (eg. 2.9.x or 2.10.x).
+
+set -e
+
+cat >tmp-zdisptest.asm <<\EOF
+
+include(`../config.m4')
+
+dnl  Redefine Zdisp_match to output its pattern and encoding.
+define(`Zdisp_match',
+`define(`Zdisp_found',1)dnl
+ifelse(`$2',0,`	$1	$2$3, $4')`'dnl
+ifelse(`$3',0,`	$1	$2, $3$4')`'dnl
+
+	.byte	$5
+')
+	.text
+	Zdisp()
+EOF
+
+m4 tmp-zdisptest.asm >tmp-zdisptest.s
+as -o tmp-zdisptest.o tmp-zdisptest.s
+
+# Demand duplicates from the instruction patterns and byte encodings.
+objdump -d tmp-zdisptest.o | awk '
+/^ *[a-z0-9]+:/ {
+	sub(/^ *[a-z0-9]+:/,"")
+        print
+}' | sort | uniq -u
diff --git a/third_party/gmp/mpn/x86/t-zdisp2.pl b/third_party/gmp/mpn/x86/t-zdisp2.pl
new file mode 100755
index 0000000..b441b65
--- /dev/null
+++ b/third_party/gmp/mpn/x86/t-zdisp2.pl
@@ -0,0 +1,147 @@
+#!/usr/bin/perl -w
+#
+# Copyright 2001, 2002 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+
+# Usage: cd $(builddir)/mpn
+#        $(srcdir)/x86/t-zdisp2.pl
+#
+# Grep for any "0(reg...)" addressing modes coming out of the x86 .asm
+# files.  Additive expressions like "12+4-16" are recognised too.
+#
+# Old gas doesn't preserve the "0" displacement, so if it's wanted then
+# Zdisp ought to be used to give explicit .byte sequences.  See
+# mpn/x86/README.
+#
+# No output means everything is ok.  All the asm files are put through m4 in
+# PIC and non-PIC modes, and in each multi-function form, all of which can
+# take a while to run.
+#
+# This program is only meant for use during development.
+
+use strict;
+use File::Find;
+use File::Basename;
+use Getopt::Std;
+
+my %opt;
+getopts('t', \%opt);
+
+
+my $srcdir;
+open IN, '<Makefile' or die;
+while (<IN>) {
+  if (/^srcdir[ \t]*=[ \t]*(.*)/) {
+    $srcdir = $1;
+    last;
+  }
+}
+close IN or die;
+defined $srcdir or die "Cannot find \$srcdir in Makefile\n";
+
+my $filecount = 0;
+
+my $tempfile = 't-zdisp2.tmp';
+open KARA, ">$tempfile" or die;
+close KARA or die;
+
+find({ wanted => \&process, preprocess => \&process_mparam, no_chdir => 1 },
+     "$srcdir/x86");
+
+sub process {
+  if (/gmp-mparam.h$/) {
+    process_mparam($_);
+  } elsif (/\.asm$/) {
+    process_asm($_);
+  }
+}
+
+# Ensure we're using the right SQR_TOOM2_THRESHOLD for the part of the
+# tree being processed.
+sub process_mparam {
+  my $file = "$File::Find::dir/gmp-mparam.h";
+  if (-f $file) {
+    print "$file\n" if $opt{'t'};
+    open MPARAM, "<$file" or die;
+    while (<MPARAM>) {
+      if (/^#define SQR_TOOM2_THRESHOLD[ \t]*([0-9][0-9]*)/) {
+        open KARA, ">$tempfile" or die;
+        print KARA "define(\`SQR_TOOM2_THRESHOLD',$1)\n\n";
+        print "define(\`SQR_TOOM2_THRESHOLD',$1)\n" if $opt{'t'};
+        close KARA or die;
+        last;
+      }
+    }
+    close MPARAM or die;
+  }
+  return @_;
+}
+
+sub process_asm {
+  my ($file) = @_;
+  my $base = basename ($file, '.asm');
+
+  my @funs;
+  if    ($base eq 'aors_n')    { @funs = qw(add_n sub_n); }
+  elsif ($base eq 'aorsmul_1') { @funs = qw(addmul_1 submul_1); }
+  elsif ($base eq 'popham')    { @funs = qw(popcount hamdist); }
+  elsif ($base eq 'logops_n')  { @funs = qw(and_n andn_n nand_n ior_n iorn_n nior_n xor_n xnor_n); }
+  elsif ($base eq 'lorrshift') { @funs = qw(lshift rshift); }
+  else                         { @funs = ($base); }
+
+  foreach my $fun (@funs) {
+    foreach my $pic ('', ' -DPIC') {
+      my $header = "$file: 0: $pic\n";
+      $filecount++;
+
+      my $m4 = "m4 -DHAVE_HOST_CPU_athlon -DOPERATION_$fun $pic ../config.m4 $tempfile $file";
+      print "$m4\n" if $opt{'t'};
+
+      open IN, "$m4 |" or die;
+      while (<IN>) {
+        next unless /([0-9+-][0-9 \t+-]*)\(%/;
+        my $pat=$1;
+        $pat = eval($pat);
+        next if ($pat != 0);
+        print "$header$_";
+        $header='';
+      }
+      close IN or die;
+    }
+  }
+}
+
+unlink($tempfile);
+print "total $filecount processed\n";
+exit 0;
+
+
+# Local variables:
+# perl-indent-level: 2
+# End:
diff --git a/third_party/gmp/mpn/x86/udiv.asm b/third_party/gmp/mpn/x86/udiv.asm
new file mode 100644
index 0000000..a3ee088
--- /dev/null
+++ b/third_party/gmp/mpn/x86/udiv.asm
@@ -0,0 +1,52 @@
+dnl  x86 mpn_udiv_qrnnd -- 2 by 1 limb division
+
+dnl  Copyright 1999, 2000, 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C mp_limb_t mpn_udiv_qrnnd (mp_limb_t *remptr, mp_limb_t high, mp_limb_t low,
+C                           mp_limb_t divisor);
+
+defframe(PARAM_DIVISOR, 16)
+defframe(PARAM_LOW,     12)
+defframe(PARAM_HIGH,    8)
+defframe(PARAM_REMPTR,  4)
+
+	TEXT
+	ALIGN(8)
+PROLOGUE(mpn_udiv_qrnnd)
+deflit(`FRAME',0)
+	movl	PARAM_LOW, %eax
+	movl	PARAM_HIGH, %edx
+	divl	PARAM_DIVISOR
+	movl	PARAM_REMPTR, %ecx
+	movl	%edx, (%ecx)
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/umul.asm b/third_party/gmp/mpn/x86/umul.asm
new file mode 100644
index 0000000..34fe434
--- /dev/null
+++ b/third_party/gmp/mpn/x86/umul.asm
@@ -0,0 +1,51 @@
+dnl  mpn_umul_ppmm -- 1x1->2 limb multiplication
+
+dnl  Copyright 1999, 2000, 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C mp_limb_t mpn_umul_ppmm (mp_limb_t *lowptr, mp_limb_t m1, mp_limb_t m2);
+C
+
+defframe(PARAM_M2,    12)
+defframe(PARAM_M1,     8)
+defframe(PARAM_LOWPTR, 4)
+
+	TEXT
+	ALIGN(8)
+PROLOGUE(mpn_umul_ppmm)
+deflit(`FRAME',0)
+	movl	PARAM_LOWPTR, %ecx
+	movl	PARAM_M1, %eax
+	mull	PARAM_M2
+	movl	%eax, (%ecx)
+	movl	%edx, %eax
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86/x86-defs.m4 b/third_party/gmp/mpn/x86/x86-defs.m4
new file mode 100644
index 0000000..81309b2
--- /dev/null
+++ b/third_party/gmp/mpn/x86/x86-defs.m4
@@ -0,0 +1,1024 @@
+divert(-1)
+
+dnl  m4 macros for x86 assembler.
+
+dnl  Copyright 1999-2003, 2007, 2010, 2012, 2014 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+dnl  Notes:
+dnl
+dnl  m4 isn't perfect for processing BSD style x86 assembler code, the main
+dnl  problems are,
+dnl
+dnl  1. Doing define(foo,123) and then using foo in an addressing mode like
+dnl     foo(%ebx) expands as a macro rather than a constant.  This is worked
+dnl     around by using deflit() from asm-defs.m4, instead of define().
+dnl
+dnl  2. Immediates in macro definitions need a space or `' to stop the $
+dnl     looking like a macro parameter.  For example,
+dnl
+dnl	        define(foo, `mov $ 123, %eax')
+dnl
+dnl     This is only a problem in macro definitions, not in ordinary text,
+dnl     and not in macro parameters like text passed to forloop() or ifdef().
+
+
+deflit(GMP_LIMB_BYTES, 4)
+
+
+dnl  Libtool gives -DPIC -DDLL_EXPORT to indicate a cygwin or mingw DLL.  We
+dnl  undefine PIC since we don't need to be position independent in this
+dnl  case and definitely don't want the ELF style _GLOBAL_OFFSET_TABLE_ etc.
+
+ifdef(`DLL_EXPORT',`undefine(`PIC')')
+
+
+dnl  Usage: CPUVEC_FUNCS_LIST
+dnl
+dnl  A list of the functions from gmp-impl.h x86 struct cpuvec_t, in the
+dnl  order they appear in that structure.
+
+define(CPUVEC_FUNCS_LIST,
+``add_n',
+`addlsh1_n',
+`addlsh2_n',
+`addmul_1',
+`addmul_2',
+`bdiv_dbm1c',
+`cnd_add_n',
+`cnd_sub_n',
+`com',
+`copyd',
+`copyi',
+`divexact_1',
+`divrem_1',
+`gcd_11',
+`lshift',
+`lshiftc',
+`mod_1',
+`mod_1_1p',
+`mod_1_1p_cps',
+`mod_1s_2p',
+`mod_1s_2p_cps',
+`mod_1s_4p',
+`mod_1s_4p_cps',
+`mod_34lsub1',
+`modexact_1c_odd',
+`mul_1',
+`mul_basecase',
+`mullo_basecase',
+`preinv_divrem_1',
+`preinv_mod_1',
+`redc_1',
+`redc_2',
+`rshift',
+`sqr_basecase',
+`sub_n',
+`sublsh1_n',
+`submul_1'')
+
+
+dnl  Called: PROLOGUE_cpu(GSYM_PREFIX`'foo)
+dnl
+dnl  In the x86 code we use explicit TEXT and ALIGN() calls in the code,
+dnl  since different alignments are wanted in various circumstances.  So for
+dnl  instance,
+dnl
+dnl                  TEXT
+dnl                  ALIGN(16)
+dnl          PROLOGUE(mpn_add_n)
+dnl          ...
+dnl          EPILOGUE()
+
+define(`PROLOGUE_cpu',
+m4_assert_numargs(1)
+m4_assert_defined(`WANT_PROFILING')
+	`GLOBL	$1
+	TYPE($1,`function')
+	COFF_TYPE($1)
+$1:
+ifelse(WANT_PROFILING,`prof',      `	call_mcount')
+ifelse(WANT_PROFILING,`gprof',     `	call_mcount')
+ifelse(WANT_PROFILING,`instrument',`	call_instrument(enter)')
+')
+
+
+dnl  Usage: COFF_TYPE(GSYM_PREFIX`'foo)
+dnl
+dnl  Emit COFF style ".def ... .endef" type information for a function, when
+dnl  supported.  The argument should include any GSYM_PREFIX.
+dnl
+dnl  See autoconf macro GMP_ASM_COFF_TYPE for HAVE_COFF_TYPE.
+
+define(COFF_TYPE,
+m4_assert_numargs(1)
+m4_assert_defined(`HAVE_COFF_TYPE')
+`ifelse(HAVE_COFF_TYPE,yes,
+	`.def	$1
+	.scl	2
+	.type	32
+	.endef')')
+
+
+dnl  Usage: call_mcount
+dnl
+dnl  For `gprof' style profiling, %ebp is setup as a frame pointer.  None of
+dnl  the assembler routines use %ebp this way, so it's done only for the
+dnl  benefit of mcount.  glibc sysdeps/i386/i386-mcount.S shows how mcount
+dnl  gets the current function from (%esp) and the parent from 4(%ebp).
+dnl
+dnl  For `prof' style profiling gcc generates mcount calls without setting
+dnl  up %ebp, and the same is done here.
+
+define(`call_mcount',
+m4_assert_numargs(-1)
+m4_assert_defined(`WANT_PROFILING')
+m4_assert_defined(`MCOUNT_PIC_REG')
+m4_assert_defined(`MCOUNT_NONPIC_REG')
+m4_assert_defined(`MCOUNT_PIC_CALL')
+m4_assert_defined(`MCOUNT_NONPIC_CALL')
+`ifelse(ifdef(`PIC',`MCOUNT_PIC_REG',`MCOUNT_NONPIC_REG'),,,
+`	DATA
+	ALIGN(4)
+L(mcount_data_`'mcount_counter):
+	W32	0
+	TEXT
+')dnl
+ifelse(WANT_PROFILING,`gprof',
+`	pushl	%ebp
+	movl	%esp, %ebp
+')dnl
+ifdef(`PIC',
+`	pushl	%ebx
+	call_movl_eip_to_ebx
+L(mcount_here_`'mcount_counter):
+	addl	$_GLOBAL_OFFSET_TABLE_+[.-L(mcount_here_`'mcount_counter)], %ebx
+ifelse(MCOUNT_PIC_REG,,,
+`	leal	L(mcount_data_`'mcount_counter)@GOTOFF(%ebx), MCOUNT_PIC_REG')
+MCOUNT_PIC_CALL
+	popl	%ebx
+',`dnl non-PIC
+ifelse(MCOUNT_NONPIC_REG,,,
+`	movl	`$'L(mcount_data_`'mcount_counter), MCOUNT_NONPIC_REG
+')dnl
+MCOUNT_NONPIC_CALL
+')dnl
+ifelse(WANT_PROFILING,`gprof',
+`	popl	%ebp
+')
+define(`mcount_counter',incr(mcount_counter))
+')
+
+define(mcount_counter,1)
+
+
+dnl  Usage: call_instrument(enter|exit)
+dnl
+dnl  Call __cyg_profile_func_enter or __cyg_profile_func_exit.
+dnl
+dnl  For PIC, most routines don't require _GLOBAL_OFFSET_TABLE_ themselves
+dnl  so %ebx is just setup for these calls.  It's a bit wasteful to repeat
+dnl  the setup for the exit call having done it earlier for the enter, but
+dnl  there's nowhere very convenient to hold %ebx through the length of a
+dnl  routine, in general.
+dnl
+dnl  For PIC, because instrument_current_function will be within the current
+dnl  object file we can get it just as an offset from %eip, there's no need
+dnl  to use the GOT.
+dnl
+dnl  No attempt is made to maintain the stack alignment gcc generates with
+dnl  -mpreferred-stack-boundary.  This wouldn't be hard, but it seems highly
+dnl  unlikely the instrumenting functions would be doing anything that'd
+dnl  benefit from alignment, in particular they're unlikely to be using
+dnl  doubles or long doubles on the stack.
+dnl
+dnl  The FRAME scheme is used to conveniently account for the register saves
+dnl  before accessing the return address.  Any previous value is saved and
+dnl  restored, since plenty of code keeps a value across a "ret" in the
+dnl  middle of a routine.
+
+define(call_instrument,
+m4_assert_numargs(1)
+`	pushdef(`FRAME',0)
+ifelse($1,exit,
+`	pushl	%eax	FRAME_pushl()	C return value
+')
+ifdef(`PIC',
+`	pushl	%ebx	FRAME_pushl()
+	call_movl_eip_to_ebx
+L(instrument_here_`'instrument_count):
+	movl	%ebx, %ecx
+	addl	$_GLOBAL_OFFSET_TABLE_+[.-L(instrument_here_`'instrument_count)], %ebx
+	C use addl rather than leal to avoid old gas bugs, see mpn/x86/README
+	addl	$instrument_current_function-L(instrument_here_`'instrument_count), %ecx
+	pushl	m4_empty_if_zero(FRAME)(%esp)	FRAME_pushl()	C return addr
+	pushl	%ecx				FRAME_pushl()	C this function
+	call	GSYM_PREFIX`'__cyg_profile_func_$1@PLT
+	addl	$`'8, %esp
+	popl	%ebx
+',
+`	C non-PIC
+	pushl	m4_empty_if_zero(FRAME)(%esp)	FRAME_pushl()	C return addr
+	pushl	$instrument_current_function	FRAME_pushl()	C this function
+	call	GSYM_PREFIX`'__cyg_profile_func_$1
+	addl	$`'8, %esp
+')
+ifelse($1,exit,
+`	popl	%eax			C return value
+')
+	popdef(`FRAME')
+define(`instrument_count',incr(instrument_count))
+')
+define(instrument_count,1)
+
+
+dnl  Usage: instrument_current_function
+dnl
+dnl  Return the current function name for instrumenting purposes.  This is
+dnl  PROLOGUE_current_function, but it sticks at the first such name seen.
+dnl
+dnl  Sticking to the first name seen ensures that multiple-entrypoint
+dnl  functions like mpn_add_nc and mpn_add_n will make enter and exit calls
+dnl  giving the same function address.
+
+define(instrument_current_function,
+m4_assert_numargs(-1)
+`ifdef(`instrument_current_function_seen',
+`instrument_current_function_seen',
+`define(`instrument_current_function_seen',PROLOGUE_current_function)dnl
+PROLOGUE_current_function')')
+
+
+dnl  Usage: call_movl_eip_to_ebx
+dnl
+dnl  Generate a call to L(movl_eip_to_ebx), and record the need for that
+dnl  routine.
+
+define(call_movl_eip_to_ebx,
+m4_assert_numargs(-1)
+`call	L(movl_eip_to_ebx)
+define(`movl_eip_to_ebx_needed',1)')
+
+dnl  Usage: generate_movl_eip_to_ebx
+dnl
+dnl  Emit a L(movl_eip_to_ebx) routine, if needed and not already generated.
+
+define(generate_movl_eip_to_ebx,
+m4_assert_numargs(-1)
+`ifelse(movl_eip_to_ebx_needed,1,
+`ifelse(movl_eip_to_ebx_done,1,,
+`L(movl_eip_to_ebx):
+	movl	(%esp), %ebx
+	ret_internal
+define(`movl_eip_to_ebx_done',1)
+')')')
+
+
+dnl  Usage: ret
+dnl
+dnl  Generate a "ret", but if doing instrumented profiling then call
+dnl  __cyg_profile_func_exit first.
+
+define(ret,
+m4_assert_numargs(-1)
+m4_assert_defined(`WANT_PROFILING')
+`ifelse(WANT_PROFILING,instrument,
+`ret_instrument',
+`ret_internal')
+generate_movl_eip_to_ebx
+')
+
+
+dnl  Usage: ret_internal
+dnl
+dnl  A plain "ret", without any __cyg_profile_func_exit call.  This can be
+dnl  used for a return which is internal to some function, such as when
+dnl  getting %eip for PIC.
+
+define(ret_internal,
+m4_assert_numargs(-1)
+``ret'')
+
+
+dnl  Usage: ret_instrument
+dnl
+dnl  Generate call to __cyg_profile_func_exit and then a ret.  If a ret has
+dnl  already been seen from this function then jump to that chunk of code,
+dnl  rather than emitting it again.
+
+define(ret_instrument,
+m4_assert_numargs(-1)
+`ifelse(m4_unquote(ret_instrument_seen_`'instrument_current_function),1,
+`jmp	L(instrument_exit_`'instrument_current_function)',
+`define(ret_instrument_seen_`'instrument_current_function,1)
+L(instrument_exit_`'instrument_current_function):
+call_instrument(exit)
+	ret_internal')')
+
+
+dnl  Usage: _GLOBAL_OFFSET_TABLE_
+dnl
+dnl  Expand to _GLOBAL_OFFSET_TABLE_ plus any necessary underscore prefix.
+dnl  This lets us write plain _GLOBAL_OFFSET_TABLE_ in SVR4 style, but still
+dnl  work with systems requiring an extra underscore such as OpenBSD.
+dnl
+dnl  deflit is used so "leal _GLOBAL_OFFSET_TABLE_(%eax), %ebx" will come
+dnl  out right, though that form doesn't work properly in gas (see
+dnl  mpn/x86/README).
+
+deflit(_GLOBAL_OFFSET_TABLE_,
+m4_assert_defined(`GOT_GSYM_PREFIX')
+`GOT_GSYM_PREFIX`_GLOBAL_OFFSET_TABLE_'')
+
+
+dnl  --------------------------------------------------------------------------
+dnl  Various x86 macros.
+dnl
+
+
+dnl  Usage: ALIGN_OFFSET(bytes,offset)
+dnl
+dnl  Align to `offset' away from a multiple of `bytes'.
+dnl
+dnl  This is useful for testing, for example align to something very strict
+dnl  and see what effect offsets from it have, "ALIGN_OFFSET(256,32)".
+dnl
+dnl  Generally you wouldn't execute across the padding, but it's done with
+dnl  nop's so it'll work.
+
+define(ALIGN_OFFSET,
+m4_assert_numargs(2)
+`ALIGN($1)
+forloop(`i',1,$2,`	nop
+')')
+
+
+dnl  Usage: defframe(name,offset)
+dnl
+dnl  Make a definition like the following with which to access a parameter
+dnl  or variable on the stack.
+dnl
+dnl         define(name,`FRAME+offset(%esp)')
+dnl
+dnl  Actually m4_empty_if_zero(FRAME+offset) is used, which will save one
+dnl  byte if FRAME+offset is zero, by putting (%esp) rather than 0(%esp).
+dnl  Use define(`defframe_empty_if_zero_disabled',1) if for some reason the
+dnl  zero offset is wanted.
+dnl
+dnl  The new macro also gets a check that when it's used FRAME is actually
+dnl  defined, and that the final %esp offset isn't negative, which would
+dnl  mean an attempt to access something below the current %esp.
+dnl
+dnl  deflit() is used rather than a plain define(), so the new macro won't
+dnl  delete any following parenthesized expression.  name(%edi) will come
+dnl  out say as 16(%esp)(%edi).  This isn't valid assembler and should
+dnl  provoke an error, which is better than silently giving just 16(%esp).
+dnl
+dnl  See README for more on the suggested way to access the stack frame.
+
+define(defframe,
+m4_assert_numargs(2)
+`deflit(`$1',
+m4_assert_defined(`FRAME')
+`defframe_check_notbelow(`$1',$2,FRAME)dnl
+defframe_empty_if_zero(FRAME+($2))(%esp)')')
+
+dnl  Called: defframe_empty_if_zero(expression)
+define(defframe_empty_if_zero,
+m4_assert_numargs(1)
+`ifelse(defframe_empty_if_zero_disabled,1,
+`eval($1)',
+`m4_empty_if_zero($1)')')
+
+dnl  Called: defframe_check_notbelow(`name',offset,FRAME)
+define(defframe_check_notbelow,
+m4_assert_numargs(3)
+`ifelse(eval(($3)+($2)<0),1,
+`m4_error(`$1 at frame offset $2 used when FRAME is only $3 bytes
+')')')
+
+
+dnl  Usage: FRAME_pushl()
+dnl         FRAME_popl()
+dnl         FRAME_addl_esp(n)
+dnl         FRAME_subl_esp(n)
+dnl
+dnl  Adjust FRAME appropriately for a pushl or popl, or for an addl or subl
+dnl  %esp of n bytes.
+dnl
+dnl  Using these macros is completely optional.  Sometimes it makes more
+dnl  sense to put explicit deflit(`FRAME',N) forms, especially when there's
+dnl  jumps and different sequences of FRAME values need to be used in
+dnl  different places.
+
+define(FRAME_pushl,
+m4_assert_numargs(0)
+m4_assert_defined(`FRAME')
+`deflit(`FRAME',eval(FRAME+4))')
+
+define(FRAME_popl,
+m4_assert_numargs(0)
+m4_assert_defined(`FRAME')
+`deflit(`FRAME',eval(FRAME-4))')
+
+define(FRAME_addl_esp,
+m4_assert_numargs(1)
+m4_assert_defined(`FRAME')
+`deflit(`FRAME',eval(FRAME-($1)))')
+
+define(FRAME_subl_esp,
+m4_assert_numargs(1)
+m4_assert_defined(`FRAME')
+`deflit(`FRAME',eval(FRAME+($1)))')
+
+
+dnl  Usage: defframe_pushl(name)
+dnl
+dnl  Do a combination FRAME_pushl() and a defframe() to name the stack
+dnl  location just pushed.  This should come after a pushl instruction.
+dnl  Putting it on the same line works and avoids lengthening the code.  For
+dnl  example,
+dnl
+dnl         pushl   %eax     defframe_pushl(VAR_COUNTER)
+dnl
+dnl  Notice the defframe() is done with an unquoted -FRAME thus giving its
+dnl  current value without tracking future changes.
+
+define(defframe_pushl,
+m4_assert_numargs(1)
+`FRAME_pushl()defframe(`$1',-FRAME)')
+
+
+dnl  --------------------------------------------------------------------------
+dnl  Assembler instruction macros.
+dnl
+
+
+dnl  Usage: emms_or_femms
+dnl         femms_available_p
+dnl
+dnl  femms_available_p expands to 1 or 0 according to whether the AMD 3DNow
+dnl  femms instruction is available.  emms_or_femms expands to femms if
+dnl  available, or emms if not.
+dnl
+dnl  emms_or_femms is meant for use in the K6 directory where plain K6
+dnl  (without femms) and K6-2 and K6-3 (with a slightly faster femms) are
+dnl  supported together.
+dnl
+dnl  On K7 femms is no longer faster and is just an alias for emms, so plain
+dnl  emms may as well be used.
+
+define(femms_available_p,
+m4_assert_numargs(-1)
+`m4_ifdef_anyof_p(
+	`HAVE_HOST_CPU_k62',
+	`HAVE_HOST_CPU_k63',
+	`HAVE_HOST_CPU_athlon')')
+
+define(emms_or_femms,
+m4_assert_numargs(-1)
+`ifelse(femms_available_p,1,`femms',`emms')')
+
+
+dnl  Usage: femms
+dnl
+dnl  Gas 2.9.1 which comes with FreeBSD 3.4 doesn't support femms, so the
+dnl  following is a replacement using .byte.
+
+define(femms,
+m4_assert_numargs(-1)
+`.byte	15,14	C AMD 3DNow femms')
+
+
+dnl  Usage: jadcl0(op)
+dnl
+dnl  Generate a jnc/incl as a substitute for adcl $0,op.  Note this isn't an
+dnl  exact replacement, since it doesn't set the flags like adcl does.
+dnl
+dnl  This finds a use in K6 mpn_addmul_1, mpn_submul_1, mpn_mul_basecase and
+dnl  mpn_sqr_basecase because on K6 an adcl is slow, the branch
+dnl  misprediction penalty is small, and the multiply algorithm used leads
+dnl  to a carry bit on average only 1/4 of the time.
+dnl
+dnl  jadcl0_disabled can be set to 1 to instead generate an ordinary adcl
+dnl  for comparison.  For example,
+dnl
+dnl		define(`jadcl0_disabled',1)
+dnl
+dnl  When using a register operand, eg. "jadcl0(%edx)", the jnc/incl code is
+dnl  the same size as an adcl.  This makes it possible to use the exact same
+dnl  computed jump code when testing the relative speed of the two.
+
+define(jadcl0,
+m4_assert_numargs(1)
+`ifelse(jadcl0_disabled,1,
+	`adcl	$`'0, $1',
+	`jnc	L(jadcl0_`'jadcl0_counter)
+	incl	$1
+L(jadcl0_`'jadcl0_counter):
+define(`jadcl0_counter',incr(jadcl0_counter))')')
+
+define(jadcl0_counter,1)
+
+
+dnl  Usage: x86_lookup(target, key,value, key,value, ...)
+dnl         x86_lookup_p(target, key,value, key,value, ...)
+dnl
+dnl  Look for `target' among the `key' parameters.
+dnl
+dnl  x86_lookup expands to the corresponding `value', or generates an error
+dnl  if `target' isn't found.
+dnl
+dnl  x86_lookup_p expands to 1 if `target' is found, or 0 if not.
+
+define(x86_lookup,
+m4_assert_numargs_range(1,999)
+`ifelse(eval($#<3),1,
+`m4_error(`unrecognised part of x86 instruction: $1
+')',
+`ifelse(`$1',`$2', `$3',
+`x86_lookup(`$1',shift(shift(shift($@))))')')')
+
+define(x86_lookup_p,
+m4_assert_numargs_range(1,999)
+`ifelse(eval($#<3),1, `0',
+`ifelse(`$1',`$2',    `1',
+`x86_lookup_p(`$1',shift(shift(shift($@))))')')')
+
+
+dnl  Usage: x86_opcode_reg32(reg)
+dnl         x86_opcode_reg32_p(reg)
+dnl
+dnl  x86_opcode_reg32 expands to the standard 3 bit encoding for the given
+dnl  32-bit register, eg. `%ebp' turns into 5.
+dnl
+dnl  x86_opcode_reg32_p expands to 1 if reg is a valid 32-bit register, or 0
+dnl  if not.
+
+define(x86_opcode_reg32,
+m4_assert_numargs(1)
+`x86_lookup(`$1',x86_opcode_reg32_list)')
+
+define(x86_opcode_reg32_p,
+m4_assert_onearg()
+`x86_lookup_p(`$1',x86_opcode_reg32_list)')
+
+define(x86_opcode_reg32_list,
+``%eax',0,
+`%ecx',1,
+`%edx',2,
+`%ebx',3,
+`%esp',4,
+`%ebp',5,
+`%esi',6,
+`%edi',7')
+
+
+dnl  Usage: x86_opcode_tttn(cond)
+dnl
+dnl  Expand to the 4-bit "tttn" field value for the given x86 branch
+dnl  condition (like `c', `ae', etc).
+
+define(x86_opcode_tttn,
+m4_assert_numargs(1)
+`x86_lookup(`$1',x86_opcode_ttn_list)')
+
+define(x86_opcode_tttn_list,
+``o',  0,
+`no',  1,
+`b',   2, `c',  2, `nae',2,
+`nb',  3, `nc', 3, `ae', 3,
+`e',   4, `z',  4,
+`ne',  5, `nz', 5,
+`be',  6, `na', 6,
+`nbe', 7, `a',  7,
+`s',   8,
+`ns',  9,
+`p',  10, `pe', 10, `npo',10,
+`np', 11, `npe',11, `po', 11,
+`l',  12, `nge',12,
+`nl', 13, `ge', 13,
+`le', 14, `ng', 14,
+`nle',15, `g',  15')
+
+
+dnl  Usage: cmovCC(%srcreg,%dstreg)
+dnl
+dnl  Emit a cmov instruction, using a .byte sequence, since various past
+dnl  versions of gas don't know cmov.  For example,
+dnl
+dnl         cmovz(  %eax, %ebx)
+dnl
+dnl  The source operand can only be a plain register.  (m4 code implementing
+dnl  full memory addressing modes exists, believe it or not, but isn't
+dnl  currently needed and isn't included.)
+dnl
+dnl  All the standard conditions are defined.  Attempting to use one without
+dnl  the macro parentheses, such as just "cmovbe %eax, %ebx", will provoke
+dnl  an error.  This protects against writing something old gas wouldn't
+dnl  understand.
+
+dnl  Called: define_cmov_many(cond,tttn,cond,tttn,...)
+define(define_cmov_many,
+`ifelse(m4_length(`$1'),0,,
+`define_cmov(`$1',`$2')define_cmov_many(shift(shift($@)))')')
+
+dnl  Called: define_cmov(cond,tttn)
+dnl  Emit basically define(cmov<cond>,`cmov_internal(<cond>,<ttn>,`$1',`$2')')
+define(define_cmov,
+m4_assert_numargs(2)
+`define(`cmov$1',
+m4_instruction_wrapper()
+m4_assert_numargs(2)
+`cmov_internal'(m4_doublequote($`'0),``$2'',dnl
+m4_doublequote($`'1),m4_doublequote($`'2)))')
+
+define_cmov_many(x86_opcode_tttn_list)
+
+dnl  Called: cmov_internal(name,tttn,src,dst)
+define(cmov_internal,
+m4_assert_numargs(4)
+`.byte	dnl
+15, dnl
+eval(64+$2), dnl
+eval(192+8*x86_opcode_reg32(`$4')+x86_opcode_reg32(`$3')) dnl
+	C `$1 $3, $4'')
+
+
+dnl  Usage: x86_opcode_regmmx(reg)
+dnl
+dnl  Validate the given mmx register, and return its number, 0 to 7.
+
+define(x86_opcode_regmmx,
+m4_assert_numargs(1)
+`x86_lookup(`$1',x86_opcode_regmmx_list)')
+
+define(x86_opcode_regmmx_list,
+``%mm0',0,
+`%mm1',1,
+`%mm2',2,
+`%mm3',3,
+`%mm4',4,
+`%mm5',5,
+`%mm6',6,
+`%mm7',7')
+
+
+dnl  Usage: psadbw(%srcreg,%dstreg)
+dnl
+dnl  Oldish versions of gas don't know psadbw, in particular gas 2.9.1 on
+dnl  FreeBSD 3.3 and 3.4 doesn't, so instead emit .byte sequences.  For
+dnl  example,
+dnl
+dnl         psadbw( %mm1, %mm2)
+dnl
+dnl  Only register->register forms are supported here, which suffices for
+dnl  the current code.
+
+define(psadbw,
+m4_instruction_wrapper()
+m4_assert_numargs(2)
+`.byte 0x0f,0xf6,dnl
+eval(192+x86_opcode_regmmx(`$2')*8+x86_opcode_regmmx(`$1')) dnl
+	C `psadbw $1, $2'')
+
+
+dnl  Usage: Zdisp(inst,op,op,op)
+dnl
+dnl  Generate explicit .byte sequences if necessary to force a byte-sized
+dnl  zero displacement on an instruction.  For example,
+dnl
+dnl         Zdisp(  movl,   0,(%esi), %eax)
+dnl
+dnl  expands to
+dnl
+dnl                 .byte   139,70,0  C movl 0(%esi), %eax
+dnl
+dnl  If the displacement given isn't 0, then normal assembler code is
+dnl  generated.  For example,
+dnl
+dnl         Zdisp(  movl,   4,(%esi), %eax)
+dnl
+dnl  expands to
+dnl
+dnl                 movl    4(%esi), %eax
+dnl
+dnl  This means a single Zdisp() form can be used with an expression for the
+dnl  displacement, and .byte will be used only if necessary.  The
+dnl  displacement argument is eval()ed.
+dnl
+dnl  Because there aren't many places a 0(reg) form is wanted, Zdisp is
+dnl  implemented with a table of instructions and encodings.  A new entry is
+dnl  needed for any different operation or registers.  The table is split
+dnl  into separate macros to avoid overflowing BSD m4 macro expansion space.
+
+define(Zdisp,
+m4_assert_numargs(4)
+`define(`Zdisp_found',0)dnl
+Zdisp_1($@)dnl
+Zdisp_2($@)dnl
+Zdisp_3($@)dnl
+Zdisp_4($@)dnl
+ifelse(Zdisp_found,0,
+`m4_error(`unrecognised instruction in Zdisp: $1 $2 $3 $4
+')')')
+
+define(Zdisp_1,`dnl
+Zdisp_match( adcl, 0,(%edx), %eax,        `0x13,0x42,0x00',           $@)`'dnl
+Zdisp_match( adcl, 0,(%edx), %ebx,        `0x13,0x5a,0x00',           $@)`'dnl
+Zdisp_match( adcl, 0,(%edx), %esi,        `0x13,0x72,0x00',           $@)`'dnl
+Zdisp_match( addl, %ebx, 0,(%edi),        `0x01,0x5f,0x00',           $@)`'dnl
+Zdisp_match( addl, %ecx, 0,(%edi),        `0x01,0x4f,0x00',           $@)`'dnl
+Zdisp_match( addl, %esi, 0,(%edi),        `0x01,0x77,0x00',           $@)`'dnl
+Zdisp_match( sbbl, 0,(%edx), %eax,        `0x1b,0x42,0x00',           $@)`'dnl
+Zdisp_match( sbbl, 0,(%edx), %esi,        `0x1b,0x72,0x00',           $@)`'dnl
+Zdisp_match( subl, %ecx, 0,(%edi),        `0x29,0x4f,0x00',           $@)`'dnl
+Zdisp_match( movzbl, 0,(%eax,%ebp), %eax, `0x0f,0xb6,0x44,0x28,0x00', $@)`'dnl
+Zdisp_match( movzbl, 0,(%ecx,%edi), %edi, `0x0f,0xb6,0x7c,0x39,0x00', $@)`'dnl
+Zdisp_match( adc, 0,(%ebx,%ecx,4), %eax,  `0x13,0x44,0x8b,0x00',      $@)`'dnl
+Zdisp_match( sbb, 0,(%ebx,%ecx,4), %eax,  `0x1b,0x44,0x8b,0x00',      $@)`'dnl
+')
+define(Zdisp_2,`dnl
+Zdisp_match( movl, %eax, 0,(%edi),        `0x89,0x47,0x00',           $@)`'dnl
+Zdisp_match( movl, %ebx, 0,(%edi),        `0x89,0x5f,0x00',           $@)`'dnl
+Zdisp_match( movl, %esi, 0,(%edi),        `0x89,0x77,0x00',           $@)`'dnl
+Zdisp_match( movl, 0,(%ebx), %eax,        `0x8b,0x43,0x00',           $@)`'dnl
+Zdisp_match( movl, 0,(%ebx), %esi,        `0x8b,0x73,0x00',           $@)`'dnl
+Zdisp_match( movl, 0,(%edx), %eax,        `0x8b,0x42,0x00',           $@)`'dnl
+Zdisp_match( movl, 0,(%esi), %eax,        `0x8b,0x46,0x00',           $@)`'dnl
+Zdisp_match( movl, 0,(%esi,%ecx,4), %eax, `0x8b,0x44,0x8e,0x00',      $@)`'dnl
+Zdisp_match( mov, 0,(%esi,%ecx,4), %eax,  `0x8b,0x44,0x8e,0x00',      $@)`'dnl
+Zdisp_match( mov, %eax, 0,(%edi,%ecx,4),  `0x89,0x44,0x8f,0x00',      $@)`'dnl
+')
+define(Zdisp_3,`dnl
+Zdisp_match( movq, 0,(%eax,%ecx,8), %mm0, `0x0f,0x6f,0x44,0xc8,0x00', $@)`'dnl
+Zdisp_match( movq, 0,(%ebx,%eax,4), %mm0, `0x0f,0x6f,0x44,0x83,0x00', $@)`'dnl
+Zdisp_match( movq, 0,(%ebx,%eax,4), %mm2, `0x0f,0x6f,0x54,0x83,0x00', $@)`'dnl
+Zdisp_match( movq, 0,(%ebx,%ecx,4), %mm0, `0x0f,0x6f,0x44,0x8b,0x00', $@)`'dnl
+Zdisp_match( movq, 0,(%edx), %mm0,        `0x0f,0x6f,0x42,0x00',      $@)`'dnl
+Zdisp_match( movq, 0,(%esi), %mm0,        `0x0f,0x6f,0x46,0x00',      $@)`'dnl
+Zdisp_match( movq, %mm0, 0,(%edi),        `0x0f,0x7f,0x47,0x00',      $@)`'dnl
+Zdisp_match( movq, %mm2, 0,(%ecx,%eax,4), `0x0f,0x7f,0x54,0x81,0x00', $@)`'dnl
+Zdisp_match( movq, %mm2, 0,(%edx,%eax,4), `0x0f,0x7f,0x54,0x82,0x00', $@)`'dnl
+Zdisp_match( movq, %mm0, 0,(%edx,%ecx,8), `0x0f,0x7f,0x44,0xca,0x00', $@)`'dnl
+')
+define(Zdisp_4,`dnl
+Zdisp_match( movd, 0,(%eax,%ecx,4), %mm0, `0x0f,0x6e,0x44,0x88,0x00', $@)`'dnl
+Zdisp_match( movd, 0,(%eax,%ecx,8), %mm1, `0x0f,0x6e,0x4c,0xc8,0x00', $@)`'dnl
+Zdisp_match( movd, 0,(%edx,%ecx,8), %mm0, `0x0f,0x6e,0x44,0xca,0x00', $@)`'dnl
+Zdisp_match( movd, %mm0, 0,(%eax,%ecx,4), `0x0f,0x7e,0x44,0x88,0x00', $@)`'dnl
+Zdisp_match( movd, %mm0, 0,(%ecx,%eax,4), `0x0f,0x7e,0x44,0x81,0x00', $@)`'dnl
+Zdisp_match( movd, %mm2, 0,(%ecx,%eax,4), `0x0f,0x7e,0x54,0x81,0x00', $@)`'dnl
+Zdisp_match( movd, %mm0, 0,(%edx,%ecx,4), `0x0f,0x7e,0x44,0x8a,0x00', $@)`'dnl
+')
+
+define(Zdisp_match,
+m4_assert_numargs(9)
+`ifelse(eval(m4_stringequal_p(`$1',`$6')
+	&& m4_stringequal_p(`$2',0)
+	&& m4_stringequal_p(`$3',`$8')
+	&& m4_stringequal_p(`$4',`$9')),1,
+`define(`Zdisp_found',1)dnl
+ifelse(eval(`$7'),0,
+`	.byte	$5  C `$1 0$3, $4'',
+`	$6	$7$8, $9')',
+
+`ifelse(eval(m4_stringequal_p(`$1',`$6')
+	&& m4_stringequal_p(`$2',`$7')
+	&& m4_stringequal_p(`$3',0)
+	&& m4_stringequal_p(`$4',`$9')),1,
+`define(`Zdisp_found',1)dnl
+ifelse(eval(`$8'),0,
+`	.byte	$5  C `$1 $2, 0$4'',
+`	$6	$7, $8$9')')')')
+
+
+dnl  Usage: shldl(count,src,dst)
+dnl         shrdl(count,src,dst)
+dnl         shldw(count,src,dst)
+dnl         shrdw(count,src,dst)
+dnl
+dnl  Generate a double-shift instruction, possibly omitting a %cl count
+dnl  parameter if that's what the assembler requires, as indicated by
+dnl  WANT_SHLDL_CL in config.m4.  For example,
+dnl
+dnl         shldl(  %cl, %eax, %ebx)
+dnl
+dnl  turns into either
+dnl
+dnl         shldl   %cl, %eax, %ebx
+dnl  or
+dnl         shldl   %eax, %ebx
+dnl
+dnl  Immediate counts are always passed through unchanged.  For example,
+dnl
+dnl         shrdl(  $2, %esi, %edi)
+dnl  becomes
+dnl         shrdl   $2, %esi, %edi
+dnl
+dnl
+dnl  If you forget to use the macro form "shldl( ...)" and instead write
+dnl  just a plain "shldl ...", an error results.  This ensures the necessary
+dnl  variant treatment of %cl isn't accidentally bypassed.
+
+define(define_shd_instruction,
+m4_assert_numargs(1)
+`define($1,
+m4_instruction_wrapper()
+m4_assert_numargs(3)
+`shd_instruction'(m4_doublequote($`'0),m4_doublequote($`'1),dnl
+m4_doublequote($`'2),m4_doublequote($`'3)))')
+
+dnl  Effectively: define(shldl,`shd_instruction(`$0',`$1',`$2',`$3')') etc
+define_shd_instruction(shldl)
+define_shd_instruction(shrdl)
+define_shd_instruction(shldw)
+define_shd_instruction(shrdw)
+
+dnl  Called: shd_instruction(op,count,src,dst)
+define(shd_instruction,
+m4_assert_numargs(4)
+m4_assert_defined(`WANT_SHLDL_CL')
+`ifelse(eval(m4_stringequal_p(`$2',`%cl') && !WANT_SHLDL_CL),1,
+``$1'	`$3', `$4'',
+``$1'	`$2', `$3', `$4'')')
+
+
+dnl  Usage: ASSERT([cond][,instructions])
+dnl
+dnl  If WANT_ASSERT is 1, output the given instructions and expect the given
+dnl  flags condition to then be satisfied.  For example,
+dnl
+dnl         ASSERT(ne, `cmpl %eax, %ebx')
+dnl
+dnl  The instructions can be omitted to just assert a flags condition with
+dnl  no extra calculation.  For example,
+dnl
+dnl         ASSERT(nc)
+dnl
+dnl  When `instructions' is not empty, a pushf/popf is added to preserve the
+dnl  flags, but the instructions themselves must preserve any registers that
+dnl  matter.  FRAME is adjusted for the push and pop, so the instructions
+dnl  given can use defframe() stack variables.
+dnl
+dnl  The condition can be omitted to just output the given instructions when
+dnl  assertion checking is wanted.  In this case the pushf/popf is omitted.
+dnl  For example,
+dnl
+dnl         ASSERT(, `movl %eax, VAR_KEEPVAL')
+
+define(ASSERT,
+m4_assert_numargs_range(1,2)
+m4_assert_defined(`WANT_ASSERT')
+`ifelse(WANT_ASSERT,1,
+`ifelse(`$1',,
+	`$2',
+	`C ASSERT
+ifelse(`$2',,,`	pushf	ifdef(`FRAME',`FRAME_pushl()')')
+	$2
+	j`$1'	L(ASSERT_ok`'ASSERT_counter)
+	ud2	C assertion failed
+L(ASSERT_ok`'ASSERT_counter):
+ifelse(`$2',,,`	popf	ifdef(`FRAME',`FRAME_popl()')')
+define(`ASSERT_counter',incr(ASSERT_counter))')')')
+
+define(ASSERT_counter,1)
+
+
+dnl  Usage: movl_text_address(label,register)
+dnl
+dnl  Get the address of a text segment label, using either a plain movl or a
+dnl  position-independent calculation, as necessary.  For example,
+dnl
+dnl         movl_code_address(L(foo),%eax)
+dnl
+dnl  This macro is only meant for use in ASSERT()s or when testing, since
+dnl  the PIC sequence it generates will want to be done with a ret balancing
+dnl  the call on CPUs with return address branch prediction.
+dnl
+dnl  The addl generated here has a backward reference to the label, and so
+dnl  won't suffer from the two forwards references bug in old gas (described
+dnl  in mpn/x86/README).
+
+define(movl_text_address,
+m4_assert_numargs(2)
+`ifdef(`PIC',
+	`call	L(movl_text_address_`'movl_text_address_counter)
+L(movl_text_address_`'movl_text_address_counter):
+	popl	$2	C %eip
+	addl	`$'$1-L(movl_text_address_`'movl_text_address_counter), $2
+define(`movl_text_address_counter',incr(movl_text_address_counter))',
+	`movl	`$'$1, $2')')
+
+define(movl_text_address_counter,1)
+
+
+dnl  Usage: notl_or_xorl_GMP_NUMB_MASK(reg)
+dnl
+dnl  Expand to either "notl `reg'" or "xorl $GMP_NUMB_BITS,`reg'" as
+dnl  appropriate for nails in use or not.
+
+define(notl_or_xorl_GMP_NUMB_MASK,
+m4_assert_numargs(1)
+`ifelse(GMP_NAIL_BITS,0,
+`notl	`$1'',
+`xorl	$GMP_NUMB_MASK, `$1'')')
+
+
+dnl  Usage LEA(symbol,reg)
+dnl  Usage LEAL(symbol_local_to_file,reg)
+
+define(`LEA',
+m4_assert_numargs(2)
+`ifdef(`PIC',`dnl
+ifelse(index(defn(`load_eip'), `$2'),-1,
+`m4append(`load_eip',
+`	TEXT
+	ALIGN(16)
+L(movl_eip_`'substr($2,1)):
+	movl	(%esp), $2
+	ret_internal
+')')dnl
+	call	L(movl_eip_`'substr($2,1))
+	addl	$_GLOBAL_OFFSET_TABLE_, $2
+	movl	$1@GOT($2), $2
+',`
+	movl	`$'$1, $2
+')')
+
+define(`LEAL',
+m4_assert_numargs(2)
+`ifdef(`PIC',`dnl
+ifelse(index(defn(`load_eip'), `$2'),-1,
+`m4append(`load_eip',
+`	TEXT
+	ALIGN(16)
+L(movl_eip_`'substr($2,1)):
+	movl	(%esp), $2
+	ret_internal
+')')dnl
+	call	L(movl_eip_`'substr($2,1))
+	addl	$_GLOBAL_OFFSET_TABLE_, $2
+	leal	$1@GOTOFF($2), $2
+',`
+	movl	`$'$1, $2
+')')
+
+dnl ASM_END
+
+define(`ASM_END',`load_eip')
+
+define(`load_eip', `')		dnl updated in LEA/LEAL
+
+
+define(`DEF_OBJECT',
+m4_assert_numargs_range(1,2)
+	`RODATA
+	ALIGN(ifelse($#,1,2,$2))
+$1:
+')
+
+define(`END_OBJECT',
+m4_assert_numargs(1)
+`	SIZE(`$1',.-`$1')')
+
+dnl  Usage: CALL(funcname)
+dnl
+
+define(`CALL',
+m4_assert_numargs(1)
+`ifdef(`PIC',
+  `call	GSYM_PREFIX`'$1@PLT',
+  `call	GSYM_PREFIX`'$1')')
+
+ifdef(`PIC',
+`define(`PIC_WITH_EBX')',
+`undefine(`PIC_WITH_EBX')')
+
+divert`'dnl
diff --git a/third_party/gmp/mpn/x86/zn1/gmp-mparam.h b/third_party/gmp/mpn/x86/zn1/gmp-mparam.h
new file mode 100644
index 0000000..8e6c052
--- /dev/null
+++ b/third_party/gmp/mpn/x86/zn1/gmp-mparam.h
@@ -0,0 +1,220 @@
+/* AMD zn1/32 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+/* 3700-4300 MHz Pinnacle Ridge */
+/* FFT tuning limit = 67,000,000 */
+/* Generated by tuneup.c, 2019-10-21, gcc 8.3 */
+
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               3
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          4
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          3
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        10
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD         0  /* never mpn_mod_1s_2p */
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD      9
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1N_PI1_METHOD                 1  /* 14.00% faster than 2 */
+#define DIV_QR_1_NORM_THRESHOLD              4
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           22
+
+#define DIV_1_VS_MUL_1_PERCENT             248
+
+#define MUL_TOOM22_THRESHOLD                28
+#define MUL_TOOM33_THRESHOLD                91
+#define MUL_TOOM44_THRESHOLD               137
+#define MUL_TOOM6H_THRESHOLD               222
+#define MUL_TOOM8H_THRESHOLD               454
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      85
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     103
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD      88
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     105
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     130
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 63
+#define SQR_TOOM3_THRESHOLD                 98
+#define SQR_TOOM4_THRESHOLD                172
+#define SQR_TOOM6_THRESHOLD                286
+#define SQR_TOOM8_THRESHOLD                478
+
+#define MULMID_TOOM42_THRESHOLD             64
+
+#define MULMOD_BNM1_THRESHOLD               21
+#define SQRMOD_BNM1_THRESHOLD               17
+
+#define MUL_FFT_MODF_THRESHOLD             606  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    606, 5}, {     25, 6}, {     13, 5}, {     27, 6}, \
+    {     15, 5}, {     31, 6}, {     27, 7}, {     15, 6}, \
+    {     33, 7}, {     17, 6}, {     35, 7}, {     19, 6}, \
+    {     39, 7}, {     29, 8}, {     15, 7}, {     35, 8}, \
+    {     19, 7}, {     41, 8}, {     23, 7}, {     47, 8}, \
+    {     27, 9}, {     15, 8}, {     31, 7}, {     63, 8}, \
+    {     43, 9}, {     23, 8}, {     51, 9}, {     31, 8}, \
+    {     67, 9}, {     39, 8}, {     79, 9}, {     47, 8}, \
+    {     95,10}, {     31, 9}, {     79,10}, {     47, 9}, \
+    {     95,11}, {     31,10}, {     63, 9}, {    127,10}, \
+    {     79, 9}, {    159,10}, {     95,11}, {     63,10}, \
+    {    159,11}, {     95,10}, {    191,12}, {     63,11}, \
+    {    127,10}, {    255, 9}, {    511,10}, {    271, 9}, \
+    {    543, 8}, {   1087,11}, {    159,10}, {    319, 9}, \
+    {    639,10}, {    335, 9}, {    671,11}, {    191,10}, \
+    {    383, 9}, {    767,10}, {    399,11}, {    223,12}, \
+    {    127,11}, {    255,10}, {    543, 9}, {   1087,11}, \
+    {    287,10}, {    607, 9}, {   1215,11}, {    319,10}, \
+    {    671, 9}, {   1343,11}, {    351,12}, {    191,11}, \
+    {    383,10}, {    799,11}, {    415,13}, {    127,12}, \
+    {    255,11}, {    543,10}, {   1087,11}, {    607,10}, \
+    {   1215,12}, {    319,11}, {    671,10}, {   1343,11}, \
+    {    735,10}, {   1471,12}, {    383,11}, {    799,10}, \
+    {   1599,11}, {    863,10}, {   1727,12}, {    447,11}, \
+    {    959,10}, {   1919,11}, {    991,13}, {    255,12}, \
+    {    511,11}, {   1087,12}, {    575,11}, {   1215,10}, \
+    {   2431,12}, {    639,11}, {   1343,12}, {    703,11}, \
+    {   1471,10}, {   2943,13}, {    383,12}, {    767,11}, \
+    {   1599,12}, {    831,11}, {   1727,10}, {   3455,12}, \
+    {    959,11}, {   1919,14}, {    255,13}, {    511,12}, \
+    {   1087,11}, {   2239,12}, {   1215,11}, {   2431,13}, \
+    {    639,12}, {   1471,11}, {   2943,13}, {    767,12}, \
+    {   1727,11}, {   3455,13}, {    895,12}, {   1983,14}, \
+    {    511,13}, {   1023,12}, {   2239,13}, {   1151,12}, \
+    {   2495,13}, {   1279,12}, {   2623,13}, {   1407,12}, \
+    {   2943,14}, {    767,13}, {   1663,12}, {   3455,13}, \
+    {   1919,12}, {   3839,15}, {    511,14}, {   1023,13}, \
+    {   2175,12}, {   4479,13}, {   2431,14}, {   1279,13}, \
+    {   2943,12}, {   5887,14}, {   1535,13}, {   3455,14}, \
+    {   1791,13}, {   3967,12}, {   7935,11}, {  15871,15}, \
+    {   1023,14}, {   2047,13}, {   4479,14}, {   2303,13}, \
+    {   4991,12}, {   9983,14}, {   2815,13}, {   5887,15}, \
+    {   1535,14}, {   3839,13}, {   7935,12}, {  15871,16} }
+#define MUL_FFT_TABLE3_SIZE 172
+#define MUL_FFT_THRESHOLD                 5760
+
+#define SQR_FFT_MODF_THRESHOLD             464  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    464, 5}, {     25, 6}, {     13, 5}, {     27, 6}, \
+    {     25, 7}, {     13, 6}, {     28, 7}, {     15, 6}, \
+    {     31, 7}, {     17, 6}, {     35, 7}, {     19, 6}, \
+    {     39, 7}, {     27, 8}, {     15, 7}, {     35, 8}, \
+    {     19, 7}, {     41, 8}, {     23, 7}, {     47, 8}, \
+    {     27, 9}, {     15, 8}, {     39, 9}, {     23, 8}, \
+    {     51,10}, {     15, 9}, {     31, 8}, {     67, 9}, \
+    {     39, 8}, {     79, 9}, {     47, 8}, {     95, 9}, \
+    {     55,10}, {     31, 9}, {     79,10}, {     47, 9}, \
+    {     95,11}, {     31,10}, {     63, 9}, {    135,10}, \
+    {     79, 9}, {    159,10}, {     95,11}, {     63,10}, \
+    {    127, 9}, {    255,10}, {    143, 9}, {    287,10}, \
+    {    159,11}, {     95,12}, {     63,11}, {    127,10}, \
+    {    255, 9}, {    511,10}, {    271, 9}, {    543,10}, \
+    {    287, 9}, {    575,11}, {    159, 9}, {    639,10}, \
+    {    335, 9}, {    671,10}, {    351, 9}, {    703,11}, \
+    {    191,10}, {    383, 9}, {    767,10}, {    399, 9}, \
+    {    799,10}, {    415,12}, {    127,11}, {    255,10}, \
+    {    543,11}, {    287,10}, {    607,11}, {    319,10}, \
+    {    671,11}, {    351,10}, {    703,12}, {    191,11}, \
+    {    383,10}, {    799,11}, {    415,10}, {    831,13}, \
+    {    127,12}, {    255,11}, {    543,10}, {   1087,11}, \
+    {    607,10}, {   1215,12}, {    319,11}, {    671,10}, \
+    {   1343,11}, {    735,10}, {   1471,12}, {    383,11}, \
+    {    799,10}, {   1599,11}, {    863,12}, {    447,11}, \
+    {    959,13}, {    255,12}, {    511,11}, {   1087,12}, \
+    {    575,11}, {   1215,10}, {   2431,12}, {    639,11}, \
+    {   1343,12}, {    703,11}, {   1471,13}, {    383,12}, \
+    {    767,11}, {   1599,12}, {    831,11}, {   1727,10}, \
+    {   3455,12}, {    959,11}, {   1919,14}, {    255,13}, \
+    {    511,12}, {   1087,11}, {   2239,12}, {   1215,11}, \
+    {   2431,13}, {    639,12}, {   1471,11}, {   2943,13}, \
+    {    767,12}, {   1727,11}, {   3455,13}, {    895,12}, \
+    {   1919,14}, {    511,13}, {   1023,12}, {   2239,13}, \
+    {   1151,12}, {   2431,13}, {   1279,12}, {   2623,13}, \
+    {   1407,12}, {   2943,14}, {    767,13}, {   1663,12}, \
+    {   3455,13}, {   1919,12}, {   3839,15}, {    511,14}, \
+    {   1023,13}, {   2175,12}, {   4479,13}, {   2431,14}, \
+    {   1279,13}, {   2943,12}, {   5887,14}, {   1535,13}, \
+    {   3455,14}, {   1791,13}, {   3839,12}, {   7679,13}, \
+    {   3967,12}, {   7935,15}, {   1023,14}, {   2047,13}, \
+    {   4479,14}, {   2303,13}, {   4991,12}, {   9983,14}, \
+    {   2815,13}, {   5887,15}, {   1535,14}, {   3839,13}, \
+    {   7935,16} }
+#define SQR_FFT_TABLE3_SIZE 173
+#define SQR_FFT_THRESHOLD                 4736
+
+#define MULLO_BASECASE_THRESHOLD             3
+#define MULLO_DC_THRESHOLD                  60
+#define MULLO_MUL_N_THRESHOLD            11278
+#define SQRLO_BASECASE_THRESHOLD             8
+#define SQRLO_DC_THRESHOLD                 161
+#define SQRLO_SQR_THRESHOLD               9335
+
+#define DC_DIV_QR_THRESHOLD                 71
+#define DC_DIVAPPR_Q_THRESHOLD             206
+#define DC_BDIV_QR_THRESHOLD                63
+#define DC_BDIV_Q_THRESHOLD                126
+
+#define INV_MULMOD_BNM1_THRESHOLD           78
+#define INV_NEWTON_THRESHOLD               274
+#define INV_APPR_THRESHOLD                 228
+
+#define BINV_NEWTON_THRESHOLD              274
+#define REDC_1_TO_REDC_N_THRESHOLD          71
+
+#define MU_DIV_QR_THRESHOLD               1652
+#define MU_DIVAPPR_Q_THRESHOLD            1718
+#define MUPI_DIV_QR_THRESHOLD              122
+#define MU_BDIV_QR_THRESHOLD              1470
+#define MU_BDIV_Q_THRESHOLD               1589
+
+#define POWM_SEC_TABLE  3,28,54,386,1337
+
+#define GET_STR_DC_THRESHOLD                13
+#define GET_STR_PRECOMPUTE_THRESHOLD        19
+#define SET_STR_DC_THRESHOLD               262
+#define SET_STR_PRECOMPUTE_THRESHOLD       558
+
+#define FAC_DSC_THRESHOLD                  109
+#define FAC_ODD_THRESHOLD                   39
+
+#define MATRIX22_STRASSEN_THRESHOLD         21
+#define HGCD2_DIV1_METHOD                    1  /* 7.49% faster than 3 */
+#define HGCD_THRESHOLD                      74
+#define HGCD_APPR_THRESHOLD                 70
+#define HGCD_REDUCE_THRESHOLD             3389
+#define GCD_DC_THRESHOLD                   440
+#define GCDEXT_DC_THRESHOLD                327
+#define JACOBI_BASE_METHOD                   1  /* 11.98% faster than 3 */
+
+/* Tuneup completed successfully, took 36916 seconds */
diff --git a/third_party/gmp/mpn/x86/zn2/gmp-mparam.h b/third_party/gmp/mpn/x86/zn2/gmp-mparam.h
new file mode 100644
index 0000000..152e6b7
--- /dev/null
+++ b/third_party/gmp/mpn/x86/zn2/gmp-mparam.h
@@ -0,0 +1,226 @@
+/* AMD zn2/32 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 32
+#define GMP_LIMB_BYTES 4
+
+/* 3600-4400 MHz Matisse */
+/* FFT tuning limit = 67,000,000 */
+/* Generated by tuneup.c, 2019-10-23, gcc 8.3 */
+
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          3
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          3
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        15
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD         0  /* never mpn_mod_1s_2p */
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD      9
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1N_PI1_METHOD                 1  /* 4.78% faster than 2 */
+#define DIV_QR_1_NORM_THRESHOLD              3
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD               7
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           23
+
+#define DIV_1_VS_MUL_1_PERCENT             274
+
+#define MUL_TOOM22_THRESHOLD                24
+#define MUL_TOOM33_THRESHOLD                85
+#define MUL_TOOM44_THRESHOLD               166
+#define MUL_TOOM6H_THRESHOLD               290
+#define MUL_TOOM8H_THRESHOLD               430
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      97
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     114
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD      97
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     113
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     130
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 26
+#define SQR_TOOM3_THRESHOLD                153
+#define SQR_TOOM4_THRESHOLD                214
+#define SQR_TOOM6_THRESHOLD                318
+#define SQR_TOOM8_THRESHOLD                478
+
+#define MULMID_TOOM42_THRESHOLD             48
+
+#define MULMOD_BNM1_THRESHOLD               18
+#define SQRMOD_BNM1_THRESHOLD               24
+
+#define MUL_FFT_MODF_THRESHOLD             444  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    444, 5}, {     21, 6}, {     11, 5}, {     23, 6}, \
+    {     12, 5}, {     25, 6}, {     13, 5}, {     27, 6}, \
+    {     25, 7}, {     13, 6}, {     27, 7}, {     15, 6}, \
+    {     31, 7}, {     17, 6}, {     35, 7}, {     19, 6}, \
+    {     39, 7}, {     27, 8}, {     15, 7}, {     35, 8}, \
+    {     19, 7}, {     41, 8}, {     23, 7}, {     47, 8}, \
+    {     27, 9}, {     15, 8}, {     31, 7}, {     63, 8}, \
+    {     39, 9}, {     23, 8}, {     51,10}, {     15, 9}, \
+    {     31, 8}, {     67, 9}, {     39, 8}, {     79, 9}, \
+    {     47,10}, {     31, 9}, {     79,10}, {     47, 9}, \
+    {     95,11}, {     31,10}, {     63, 9}, {    127,10}, \
+    {     79, 9}, {    159,10}, {     95,11}, {     63,10}, \
+    {    127, 9}, {    255, 8}, {    511,10}, {    143, 9}, \
+    {    287, 8}, {    575,10}, {    159,11}, {     95,12}, \
+    {     63,11}, {    127,10}, {    255, 9}, {    511,10}, \
+    {    271, 9}, {    543,10}, {    287, 9}, {    575,11}, \
+    {    159,10}, {    319, 9}, {    639,10}, {    335, 9}, \
+    {    671, 8}, {   1343,10}, {    351, 9}, {    703,10}, \
+    {    367, 9}, {    735,11}, {    191,10}, {    383, 9}, \
+    {    767,10}, {    415,11}, {    223,10}, {    447,12}, \
+    {    127,11}, {    255,10}, {    543, 9}, {   1087,11}, \
+    {    287,10}, {    607,11}, {    319,10}, {    671, 9}, \
+    {   1343,11}, {    351,10}, {    735,12}, {    191,11}, \
+    {    383,10}, {    767,11}, {    415,10}, {    831,11}, \
+    {    447,13}, {    127,12}, {    255,11}, {    543,10}, \
+    {   1087,11}, {    607,10}, {   1215,12}, {    319,11}, \
+    {    671,10}, {   1343,11}, {    735,10}, {   1471, 9}, \
+    {   2943,12}, {    383,11}, {    799,10}, {   1599,11}, \
+    {    863,12}, {    447,11}, {    959,10}, {   1919,13}, \
+    {    255,12}, {    511,11}, {   1087,12}, {    575,11}, \
+    {   1215,10}, {   2431,12}, {    639,11}, {   1343,12}, \
+    {    703,11}, {   1471,10}, {   2943,13}, {    383,12}, \
+    {    767,11}, {   1599,12}, {    831,11}, {   1727,10}, \
+    {   3455,12}, {    959,11}, {   1919,10}, {   3839,14}, \
+    {    255,13}, {    511,12}, {   1215,11}, {   2431,13}, \
+    {    639,12}, {   1471,11}, {   2943,10}, {   5887,13}, \
+    {    767,12}, {   1727,11}, {   3455,13}, {    895,12}, \
+    {   1919,11}, {   3839,14}, {    511,13}, {   1023,12}, \
+    {   2111,13}, {   1151,12}, {   2431,13}, {   1407,12}, \
+    {   2943,11}, {   5887,14}, {    767,13}, {   1663,12}, \
+    {   3455,13}, {   1919,12}, {   3839,15}, {    511,14}, \
+    {   1023,13}, {   2431,14}, {   1279,13}, {   2943,12}, \
+    {   5887,14}, {   1535,13}, {   3455,14}, {   1791,13}, \
+    {   3839,12}, {   7679,13}, {   3967,12}, {   7935,11}, \
+    {  15871,15}, {   1023,14}, {   2047,13}, {   4351,14}, \
+    {   2303,13}, {   4991,12}, {   9983,14}, {   2815,13}, \
+    {   5887,15}, {   1535,14}, {   3839,13}, {   7935,12}, \
+    {  15871,16} }
+#define MUL_FFT_TABLE3_SIZE 189
+#define MUL_FFT_THRESHOLD                 4736
+
+#define SQR_FFT_MODF_THRESHOLD             404  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    404, 5}, {     21, 6}, {     11, 5}, {     23, 6}, \
+    {     12, 5}, {     25, 6}, {     13, 5}, {     27, 6}, \
+    {     25, 7}, {     13, 6}, {     27, 7}, {     15, 6}, \
+    {     31, 7}, {     19, 6}, {     39, 7}, {     23, 6}, \
+    {     47, 7}, {     27, 8}, {     15, 7}, {     35, 8}, \
+    {     19, 7}, {     41, 8}, {     23, 7}, {     47, 8}, \
+    {     27, 9}, {     15, 8}, {     39, 9}, {     23, 8}, \
+    {     47,10}, {     15, 9}, {     31, 8}, {     63, 9}, \
+    {     39, 8}, {     79, 9}, {     47,10}, {     31, 9}, \
+    {     79,10}, {     47,11}, {     31,10}, {     63, 9}, \
+    {    127,10}, {     95,11}, {     63,10}, {    127, 9}, \
+    {    255, 8}, {    511, 9}, {    271,10}, {    143, 9}, \
+    {    287, 8}, {    607, 7}, {   1215,11}, {     95,12}, \
+    {     63,11}, {    127,10}, {    255, 9}, {    511,10}, \
+    {    271, 9}, {    543, 8}, {   1087, 9}, {    607, 8}, \
+    {   1215,11}, {    159, 9}, {    671, 8}, {   1343,10}, \
+    {    351, 9}, {    735, 8}, {   1471,11}, {    191,10}, \
+    {    383, 9}, {    767,10}, {    415,11}, {    223,12}, \
+    {    127,11}, {    255,10}, {    543, 9}, {   1087,10}, \
+    {    607, 9}, {   1215, 8}, {   2431,10}, {    671, 9}, \
+    {   1343,10}, {    735, 9}, {   1471,12}, {    191,11}, \
+    {    383,10}, {    767,11}, {    415,10}, {    831,13}, \
+    {    127,12}, {    255,11}, {    543,10}, {   1087,11}, \
+    {    607,10}, {   1215, 9}, {   2431,11}, {    671,10}, \
+    {   1343,11}, {    735,10}, {   1471, 9}, {   2943,12}, \
+    {    383,11}, {    863,12}, {    447,11}, {    959,10}, \
+    {   1919,13}, {    255,12}, {    511,11}, {   1087,12}, \
+    {    575,11}, {   1215,10}, {   2431,12}, {    639,11}, \
+    {   1343,12}, {    703,11}, {   1471,10}, {   2943, 9}, \
+    {   5887,12}, {    767,11}, {   1599,12}, {    831,11}, \
+    {   1727,12}, {    959,11}, {   1919,10}, {   3839,14}, \
+    {    255,13}, {    511,12}, {   1215,11}, {   2431,13}, \
+    {    639,12}, {   1471,11}, {   2943,10}, {   5887,13}, \
+    {    767,12}, {   1727,13}, {    895,12}, {   1919,11}, \
+    {   3839,14}, {    511,13}, {   1023,12}, {   2111,13}, \
+    {   1151,12}, {   2431,13}, {   1279,12}, {   2623,13}, \
+    {   1407,12}, {   2943,11}, {   5887,14}, {    767,13}, \
+    {   1663,12}, {   3455,13}, {   1919,12}, {   3839,15}, \
+    {    511,14}, {   1023,13}, {   2431,14}, {   1279,13}, \
+    {   2943,12}, {   5887,14}, {   1535,13}, {   3455,14}, \
+    {   1791,13}, {   3839,12}, {   7679,13}, {   3967,12}, \
+    {   7935,11}, {  15871,15}, {   1023,14}, {   2047,13}, \
+    {   4223,14}, {   2303,13}, {   4991,12}, {   9983,14}, \
+    {   2815,13}, {   5887,15}, {   1535,14}, {   3839,13}, \
+    {   7935,12}, {  15871,16} }
+#define SQR_FFT_TABLE3_SIZE 178
+#define SQR_FFT_THRESHOLD                 3712
+
+#define MULLO_BASECASE_THRESHOLD             4
+#define MULLO_DC_THRESHOLD                  62
+#define MULLO_MUL_N_THRESHOLD             8907
+#define SQRLO_BASECASE_THRESHOLD             8
+#define SQRLO_DC_THRESHOLD                 107
+#define SQRLO_SQR_THRESHOLD               6633
+
+#define DC_DIV_QR_THRESHOLD                 54
+#define DC_DIVAPPR_Q_THRESHOLD             206
+#define DC_BDIV_QR_THRESHOLD                55
+#define DC_BDIV_Q_THRESHOLD                136
+
+#define INV_MULMOD_BNM1_THRESHOLD           74
+#define INV_NEWTON_THRESHOLD               212
+#define INV_APPR_THRESHOLD                 204
+
+#define BINV_NEWTON_THRESHOLD              292
+#define REDC_1_TO_REDC_N_THRESHOLD          67
+
+#define MU_DIV_QR_THRESHOLD               1442
+#define MU_DIVAPPR_Q_THRESHOLD            1528
+#define MUPI_DIV_QR_THRESHOLD               97
+#define MU_BDIV_QR_THRESHOLD              1142
+#define MU_BDIV_Q_THRESHOLD               1470
+
+#define POWM_SEC_TABLE  1,16,96,386,1555
+
+#define GET_STR_DC_THRESHOLD                10
+#define GET_STR_PRECOMPUTE_THRESHOLD        16
+#define SET_STR_DC_THRESHOLD               303
+#define SET_STR_PRECOMPUTE_THRESHOLD       748
+
+#define FAC_DSC_THRESHOLD                  141
+#define FAC_ODD_THRESHOLD                   55
+
+#define MATRIX22_STRASSEN_THRESHOLD         20
+#define HGCD2_DIV1_METHOD                    1  /* 14.03% faster than 3 */
+#define HGCD_THRESHOLD                     103
+#define HGCD_APPR_THRESHOLD                127
+#define HGCD_REDUCE_THRESHOLD             3014
+#define GCD_DC_THRESHOLD                   396
+#define GCDEXT_DC_THRESHOLD                265
+#define JACOBI_BASE_METHOD                   1  /* 47.88% faster than 4 */
+
+/* Tuneup completed successfully, took 29014 seconds */
diff --git a/third_party/gmp/mpn/x86_64/README b/third_party/gmp/mpn/x86_64/README
new file mode 100644
index 0000000..9c8a586
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/README
@@ -0,0 +1,74 @@
+Copyright 2003, 2004, 2006, 2008 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.
+
+
+
+
+
+			AMD64 MPN SUBROUTINES
+
+
+This directory contains mpn functions for AMD64 chips.  It is also useful
+for 64-bit Pentiums, and "Core 2".
+
+
+		     RELEVANT OPTIMIZATION ISSUES
+
+The Opteron and Athlon64 can sustain up to 3 instructions per cycle, but in
+practice that is only possible for integer instructions.  But almost any
+three integer instructions can issue simultaneously, including any 3 ALU
+operations, including shifts.  Up to two memory operations can issue each
+cycle.
+
+Scheduling typically requires that load-use instructions are split into
+separate load and use instructions.  That requires more decode resources,
+and it is rarely a win.  Opteron/Athlon64 have deep out-of-order core.
+
+
+Optimizing for 64-bit Pentium4 is probably a waste of time, as the most
+critical instructions are very poorly implemented here.  Perhaps we could
+save a cycle or two, but the most common loops now run at between 10 and 22
+cycles, so a saved cycle isn't too exciting.
+
+
+The new spin of the venerable P6 core, the "Core 2" is much better than the
+Pentium4 for the GMP loops.  Its integer pipeline is somewhat similar to to
+the Opteron/Athlon64 pipeline, except that the GMP favourites ADC/SBB and
+MUL are slower.  Furthermore, an INC/DEC followed by ADC/SBB incur a
+pipeline stall of around 10 cycles.  The default mpn_add_n and mpn_sub_n
+code suffers badly from the stall.  The code in the core2 subdirectory uses
+the almost forgotten instruction JRCXZ for loop control, and updates the
+induction variable using LEA.
+
+
+
+REFERENCES
+
+"System V Application Binary Interface AMD64 Architecture Processor
+Supplement", draft version 0.99, December 2007.
+http://www.x86-64.org/documentation/abi.pdf
diff --git a/third_party/gmp/mpn/x86_64/addaddmul_1msb0.asm b/third_party/gmp/mpn/x86_64/addaddmul_1msb0.asm
new file mode 100644
index 0000000..87c21b4
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/addaddmul_1msb0.asm
@@ -0,0 +1,170 @@
+dnl  AMD64 mpn_addaddmul_1msb0, R = Au + Bv, u,v < 2^63.
+
+dnl  Copyright 2008 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 2.167
+C AMD K10	 2.167
+C Intel P4	12.0
+C Intel core2	 4.0
+C Intel corei	 ?
+C Intel atom	 ?
+C VIA nano	 ?
+
+C TODO
+C  * Perhaps handle various n mod 3 sizes better.  The code now is too large.
+
+C INPUT PARAMETERS
+define(`rp',	`%rdi')
+define(`ap',	`%rsi')
+define(`bp_param', `%rdx')
+define(`n',	`%rcx')
+define(`u0',	`%r8')
+define(`v0',	`%r9')
+
+
+define(`bp', `%rbp')
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_addaddmul_1msb0)
+	push	%r12
+	push	%rbp
+
+	lea	(ap,n,8), ap
+	lea	(bp_param,n,8), bp
+	lea	(rp,n,8), rp
+	neg	n
+
+	mov	(ap,n,8), %rax
+	mul	%r8
+	mov	%rax, %r12
+	mov	(bp,n,8), %rax
+	mov	%rdx, %r10
+	add	$3, n
+	jns	L(end)
+
+	ALIGN(16)
+L(top):	mul	%r9
+	add	%rax, %r12
+	mov	-16(ap,n,8), %rax
+	adc	%rdx, %r10
+	mov	%r12, -24(rp,n,8)
+	mul	%r8
+	add	%rax, %r10
+	mov	-16(bp,n,8), %rax
+	mov	$0, R32(%r11)
+	adc	%rdx, %r11
+	mul	%r9
+	add	%rax, %r10
+	mov	-8(ap,n,8), %rax
+	adc	%rdx, %r11
+	mov	%r10, -16(rp,n,8)
+	mul	%r8
+	add	%rax, %r11
+	mov	-8(bp,n,8), %rax
+	mov	$0, R32(%r12)
+	adc	%rdx, %r12
+	mul	%r9
+	add	%rax, %r11
+	adc	%rdx, %r12
+	mov	(ap,n,8), %rax
+	mul	%r8
+	add	%rax, %r12
+	mov	%r11, -8(rp,n,8)
+	mov	(bp,n,8), %rax
+	mov	$0, R32(%r10)
+	adc	%rdx, %r10
+	add	$3, n
+	js	L(top)
+
+L(end):	cmp	$1, R32(n)
+	ja	2f
+	jz	1f
+
+	mul	%r9
+	add	%rax, %r12
+	mov	-16(ap), %rax
+	adc	%rdx, %r10
+	mov	%r12, -24(rp)
+	mul	%r8
+	add	%rax, %r10
+	mov	-16(bp), %rax
+	mov	$0, R32(%r11)
+	adc	%rdx, %r11
+	mul	%r9
+	add	%rax, %r10
+	mov	-8(ap), %rax
+	adc	%rdx, %r11
+	mov	%r10, -16(rp)
+	mul	%r8
+	add	%rax, %r11
+	mov	-8(bp), %rax
+	mov	$0, R32(%r12)
+	adc	%rdx, %r12
+	mul	%r9
+	add	%rax, %r11
+	adc	%rdx, %r12
+	mov	%r11, -8(rp)
+	mov	%r12, %rax
+	pop	%rbp
+	pop	%r12
+	ret
+
+1:	mul	%r9
+	add	%rax, %r12
+	mov	-8(ap), %rax
+	adc	%rdx, %r10
+	mov	%r12, -16(rp)
+	mul	%r8
+	add	%rax, %r10
+	mov	-8(bp), %rax
+	mov	$0, R32(%r11)
+	adc	%rdx, %r11
+	mul	%r9
+	add	%rax, %r10
+	adc	%rdx, %r11
+	mov	%r10, -8(rp)
+	mov	%r11, %rax
+	pop	%rbp
+	pop	%r12
+	ret
+
+2:	mul	%r9
+	add	%rax, %r12
+	mov	%r12, -8(rp)
+	adc	%rdx, %r10
+	mov	%r10, %rax
+	pop	%rbp
+	pop	%r12
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/aorrlsh1_n.asm b/third_party/gmp/mpn/x86_64/aorrlsh1_n.asm
new file mode 100644
index 0000000..6ee0872
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/aorrlsh1_n.asm
@@ -0,0 +1,170 @@
+dnl  AMD64 mpn_addlsh1_n -- rp[] = up[] + (vp[] << 1)
+dnl  AMD64 mpn_rsblsh1_n -- rp[] = (vp[] << 1) - up[]
+
+dnl  Copyright 2003, 2005-2009, 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C	     cycles/limb
+C AMD K8,K9	 2
+C AMD K10	 2
+C AMD bd1	 ?
+C AMD bobcat	 ?
+C Intel P4	 13
+C Intel core2	 3.45
+C Intel NHM	 ?
+C Intel SBR	 ?
+C Intel atom	 ?
+C VIA nano	 ?
+
+
+C Sometimes speed degenerates, supposedly related to that some operand
+C alignments cause cache conflicts.
+
+C The speed is limited by decoding/issue bandwidth.  There are 22 instructions
+C in the loop, which corresponds to ceil(22/3)/4 = 1.83 c/l.
+
+C INPUT PARAMETERS
+define(`rp',`%rdi')
+define(`up',`%rsi')
+define(`vp',`%rdx')
+define(`n', `%rcx')
+
+ifdef(`OPERATION_addlsh1_n', `
+  define(ADDSUB,	add)
+  define(ADCSBB,	adc)
+  define(func,		mpn_addlsh1_n)')
+ifdef(`OPERATION_rsblsh1_n', `
+  define(ADDSUB,	sub)
+  define(ADCSBB,	sbb)
+  define(func,		mpn_rsblsh1_n)')
+
+MULFUNC_PROLOGUE(mpn_addlsh1_n mpn_rsblsh1_n)
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(func)
+	FUNC_ENTRY(4)
+	push	%rbp
+
+	mov	(vp), %r8
+	mov	R32(n), R32(%rax)
+	lea	(rp,n,8), rp
+	lea	(up,n,8), up
+	lea	(vp,n,8), vp
+	neg	n
+	xor	R32(%rbp), R32(%rbp)
+	and	$3, R32(%rax)
+	je	L(b00)
+	cmp	$2, R32(%rax)
+	jc	L(b01)
+	je	L(b10)
+
+L(b11):	add	%r8, %r8
+	mov	8(vp,n,8), %r9
+	adc	%r9, %r9
+	mov	16(vp,n,8), %r10
+	adc	%r10, %r10
+	sbb	R32(%rax), R32(%rax)	C save scy
+	ADDSUB	(up,n,8), %r8
+	ADCSBB	8(up,n,8), %r9
+	mov	%r8, (rp,n,8)
+	mov	%r9, 8(rp,n,8)
+	ADCSBB	16(up,n,8), %r10
+	mov	%r10, 16(rp,n,8)
+	sbb	R32(%rbp), R32(%rbp)	C save acy
+	add	$3, n
+	jmp	L(ent)
+
+L(b10):	add	%r8, %r8
+	mov	8(vp,n,8), %r9
+	adc	%r9, %r9
+	sbb	R32(%rax), R32(%rax)	C save scy
+	ADDSUB	(up,n,8), %r8
+	ADCSBB	8(up,n,8), %r9
+	mov	%r8, (rp,n,8)
+	mov	%r9, 8(rp,n,8)
+	sbb	R32(%rbp), R32(%rbp)	C save acy
+	add	$2, n
+	jmp	L(ent)
+
+L(b01):	add	%r8, %r8
+	sbb	R32(%rax), R32(%rax)	C save scy
+	ADDSUB	(up,n,8), %r8
+	mov	%r8, (rp,n,8)
+	sbb	R32(%rbp), R32(%rbp)	C save acy
+	inc	n
+L(ent):	jns	L(end)
+
+	ALIGN(16)
+L(top):	add	R32(%rax), R32(%rax)	C restore scy
+
+	mov	(vp,n,8), %r8
+L(b00):	adc	%r8, %r8
+	mov	8(vp,n,8), %r9
+	adc	%r9, %r9
+	mov	16(vp,n,8), %r10
+	adc	%r10, %r10
+	mov	24(vp,n,8), %r11
+	adc	%r11, %r11
+
+	sbb	R32(%rax), R32(%rax)	C save scy
+	add	R32(%rbp), R32(%rbp)	C restore acy
+
+	ADCSBB	(up,n,8), %r8
+	nop				C Hammer speedup!
+	ADCSBB	8(up,n,8), %r9
+	mov	%r8, (rp,n,8)
+	mov	%r9, 8(rp,n,8)
+	ADCSBB	16(up,n,8), %r10
+	ADCSBB	24(up,n,8), %r11
+	mov	%r10, 16(rp,n,8)
+	mov	%r11, 24(rp,n,8)
+
+	sbb	R32(%rbp), R32(%rbp)	C save acy
+	add	$4, n
+	js	L(top)
+
+L(end):
+ifdef(`OPERATION_addlsh1_n',`
+	add	R32(%rbp), R32(%rax)
+	neg	R32(%rax)')
+ifdef(`OPERATION_rsblsh1_n',`
+	sub	R32(%rax), R32(%rbp)
+	movslq	R32(%rbp), %rax')
+
+	pop	%rbp
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/aorrlsh2_n.asm b/third_party/gmp/mpn/x86_64/aorrlsh2_n.asm
new file mode 100644
index 0000000..999e972
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/aorrlsh2_n.asm
@@ -0,0 +1,53 @@
+dnl  AMD64 mpn_addlsh2_n -- rp[] = up[] + (vp[] << 2)
+dnl  AMD64 mpn_rsblsh2_n -- rp[] = (vp[] << 2) - up[]
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2009-2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+define(LSH, 2)
+define(RSH, 62)
+
+ifdef(`OPERATION_addlsh2_n',`
+  define(ADDSUB,	add)
+  define(ADCSBB,	adc)
+  define(func,		mpn_addlsh2_n)')
+ifdef(`OPERATION_rsblsh2_n',`
+  define(ADDSUB,	sub)
+  define(ADCSBB,	sbb)
+  define(func,		mpn_rsblsh2_n)')
+
+MULFUNC_PROLOGUE(mpn_addlsh2_n mpn_rsblsh2_n)
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+include_mpn(`x86_64/aorrlshC_n.asm')
diff --git a/third_party/gmp/mpn/x86_64/aorrlshC_n.asm b/third_party/gmp/mpn/x86_64/aorrlshC_n.asm
new file mode 100644
index 0000000..de00154
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/aorrlshC_n.asm
@@ -0,0 +1,172 @@
+dnl  AMD64 mpn_addlshC_n -- rp[] = up[] + (vp[] << C)
+dnl  AMD64 mpn_rsblshC_n -- rp[] = (vp[] << C) - up[]
+
+dnl  Copyright 2009-2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+C	     cycles/limb
+C AMD K8,K9	 2.1
+C AMD K10	 2.0
+C AMD bd1	~2.7
+C AMD bd2	~2.7
+C AMD bd3	 ?
+C AMD bd4	 ?
+C AMD zen	 2.0
+C AMD bt1	 3.3
+C AMD bt2	 3.0
+C Intel P4	 ?
+C Intel PNR	 3.0
+C Intel NHM	 2.75
+C Intel SBR	 2.55
+C Intel IBR	 2.49
+C Intel HWL	 2.25
+C Intel BWL	 1.89
+C Intel SKL	 1.90
+C Intel atom	 8.4
+C Intel SLM	 4.0
+C VIA nano	 ?
+
+C INPUT PARAMETERS
+define(`rp',	`%rdi')
+define(`up',	`%rsi')
+define(`vp',	`%rdx')
+define(`n',	`%rcx')
+
+define(M, eval(m4_lshift(1,LSH)))
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(func)
+	FUNC_ENTRY(4)
+	push	%r12
+	push	%r13
+	push	%r14
+	push	%r15
+
+	mov	(vp), %r8
+	lea	(,%r8,M), %r12
+	shr	$RSH, %r8
+
+	mov	R32(n), R32(%rax)
+	lea	(rp,n,8), rp
+	lea	(up,n,8), up
+	lea	(vp,n,8), vp
+	neg	n
+	and	$3, R8(%rax)
+	je	L(b00)
+	cmp	$2, R8(%rax)
+	jc	L(b01)
+	je	L(b10)
+
+L(b11):	mov	8(vp,n,8), %r10
+	lea	(%r8,%r10,M), %r14
+	shr	$RSH, %r10
+	mov	16(vp,n,8), %r11
+	lea	(%r10,%r11,M), %r15
+	shr	$RSH, %r11
+	ADDSUB	(up,n,8), %r12
+	ADCSBB	8(up,n,8), %r14
+	ADCSBB	16(up,n,8), %r15
+	sbb	R32(%rax), R32(%rax)		  C save carry for next
+	mov	%r12, (rp,n,8)
+	mov	%r14, 8(rp,n,8)
+	mov	%r15, 16(rp,n,8)
+	add	$3, n
+	js	L(top)
+	jmp	L(end)
+
+L(b01):	mov	%r8, %r11
+	ADDSUB	(up,n,8), %r12
+	sbb	R32(%rax), R32(%rax)		  C save carry for next
+	mov	%r12, (rp,n,8)
+	add	$1, n
+	js	L(top)
+	jmp	L(end)
+
+L(b10):	mov	8(vp,n,8), %r11
+	lea	(%r8,%r11,M), %r15
+	shr	$RSH, %r11
+	ADDSUB	(up,n,8), %r12
+	ADCSBB	8(up,n,8), %r15
+	sbb	R32(%rax), R32(%rax)		  C save carry for next
+	mov	%r12, (rp,n,8)
+	mov	%r15, 8(rp,n,8)
+	add	$2, n
+	js	L(top)
+	jmp	L(end)
+
+L(b00):	mov	8(vp,n,8), %r9
+	mov	16(vp,n,8), %r10
+	jmp	L(e00)
+
+	ALIGN(16)
+L(top):	mov	16(vp,n,8), %r10
+	mov	(vp,n,8), %r8
+	mov	8(vp,n,8), %r9
+	lea	(%r11,%r8,M), %r12
+	shr	$RSH, %r8
+L(e00):	lea	(%r8,%r9,M), %r13
+	shr	$RSH, %r9
+	mov	24(vp,n,8), %r11
+	lea	(%r9,%r10,M), %r14
+	shr	$RSH, %r10
+	lea	(%r10,%r11,M), %r15
+	shr	$RSH, %r11
+	add	R32(%rax), R32(%rax)		  C restore carry
+	ADCSBB	(up,n,8), %r12
+	ADCSBB	8(up,n,8), %r13
+	ADCSBB	16(up,n,8), %r14
+	ADCSBB	24(up,n,8), %r15
+	mov	%r12, (rp,n,8)
+	mov	%r13, 8(rp,n,8)
+	mov	%r14, 16(rp,n,8)
+	sbb	R32(%rax), R32(%rax)		  C save carry for next
+	mov	%r15, 24(rp,n,8)
+	add	$4, n
+	js	L(top)
+L(end):
+
+ifelse(ADDSUB,add,`
+	sub	R32(%r11), R32(%rax)
+	neg	R32(%rax)
+',`
+	add	R32(%r11), R32(%rax)
+	movslq	R32(%rax), %rax
+')
+	pop	%r15
+	pop	%r14
+	pop	%r13
+	pop	%r12
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/aorrlsh_n.asm b/third_party/gmp/mpn/x86_64/aorrlsh_n.asm
new file mode 100644
index 0000000..5ca128f
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/aorrlsh_n.asm
@@ -0,0 +1,176 @@
+dnl  AMD64 mpn_addlsh_n and mpn_rsblsh_n.  R = V2^k +- U.
+
+dnl  Copyright 2006, 2010-2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C	     cycles/limb
+C AMD K8,K9	 3.1	< 3.85 for lshift + add_n
+C AMD K10	 3.1	< 3.85 for lshift + add_n
+C Intel P4	14.6	> 7.33 for lshift + add_n
+C Intel core2	 3.87	> 3.27 for lshift + add_n
+C Intel NHM	 4	> 3.75 for lshift + add_n
+C Intel SBR	(5.8)	> 3.46 for lshift + add_n
+C Intel atom	(7.75)	< 8.75 for lshift + add_n
+C VIA nano	 4.7	< 6.25 for lshift + add_n
+
+C This was written quickly and not optimized at all.  Surely one could get
+C closer to 3 c/l or perhaps even under 3 c/l.  Ideas:
+C   1) Use indexing to save the 3 LEA
+C   2) Write reasonable feed-in code
+C   3) Be more clever about register usage
+C   4) Unroll more, handling CL negation, carry save/restore cost much now
+C   5) Reschedule
+
+C INPUT PARAMETERS
+define(`rp',	`%rdi')
+define(`up',	`%rsi')
+define(`vp',	`%rdx')
+define(`n',	`%rcx')
+define(`cnt',	`%r8')
+
+ifdef(`OPERATION_addlsh_n',`
+  define(ADCSBB,       `adc')
+  define(func, mpn_addlsh_n)
+')
+ifdef(`OPERATION_rsblsh_n',`
+  define(ADCSBB,       `sbb')
+  define(func, mpn_rsblsh_n)
+')
+
+MULFUNC_PROLOGUE(mpn_addlsh_n mpn_rsblsh_n)
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(func)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8d	')
+	push	%r12
+	push	%r13
+	push	%r14
+	push	%rbp
+	push	%rbx
+
+	mov	n, %rax
+	xor	R32(%rbx), R32(%rbx)	C clear carry save register
+	mov	R32(%r8), R32(%rcx)	C shift count
+	xor	R32(%rbp), R32(%rbp)	C limb carry
+
+	mov	R32(%rax), R32(%r11)
+	and	$3, R32(%r11)
+	je	L(4)
+	sub	$1, R32(%r11)
+
+L(012):	mov	(vp), %r8
+	mov	%r8, %r12
+	shl	R8(%rcx), %r8
+	or	%rbp, %r8
+	neg	R8(%rcx)
+	mov	%r12, %rbp
+	shr	R8(%rcx), %rbp
+	neg	R8(%rcx)
+	add	R32(%rbx), R32(%rbx)
+	ADCSBB	(up), %r8
+	mov	%r8, (rp)
+	sbb	R32(%rbx), R32(%rbx)
+	lea	8(up), up
+	lea	8(vp), vp
+	lea	8(rp), rp
+	sub	$1, R32(%r11)
+	jnc	L(012)
+
+L(4):	sub	$4, %rax
+	jc	L(end)
+
+	ALIGN(16)
+L(top):	mov	(vp), %r8
+	mov	%r8, %r12
+	mov	8(vp), %r9
+	mov	%r9, %r13
+	mov	16(vp), %r10
+	mov	%r10, %r14
+	mov	24(vp), %r11
+
+	shl	R8(%rcx), %r8
+	shl	R8(%rcx), %r9
+	shl	R8(%rcx), %r10
+	or	%rbp, %r8
+	mov	%r11, %rbp
+	shl	R8(%rcx), %r11
+
+	neg	R8(%rcx)
+
+	shr	R8(%rcx), %r12
+	shr	R8(%rcx), %r13
+	shr	R8(%rcx), %r14
+	shr	R8(%rcx), %rbp		C used next iteration
+
+	or	%r12, %r9
+	or	%r13, %r10
+	or	%r14, %r11
+
+	neg	R8(%rcx)
+
+	add	R32(%rbx), R32(%rbx)	C restore carry flag
+
+	ADCSBB	(up), %r8
+	ADCSBB	8(up), %r9
+	ADCSBB	16(up), %r10
+	ADCSBB	24(up), %r11
+
+	mov	%r8, (rp)
+	mov	%r9, 8(rp)
+	mov	%r10, 16(rp)
+	mov	%r11, 24(rp)
+
+	sbb	R32(%rbx), R32(%rbx)	C save carry flag
+
+	lea	32(up), up
+	lea	32(vp), vp
+	lea	32(rp), rp
+
+	sub	$4, %rax
+	jnc	L(top)
+
+L(end):	add	R32(%rbx), R32(%rbx)
+	ADCSBB	$0, %rbp
+	mov	%rbp, %rax
+	pop	%rbx
+	pop	%rbp
+	pop	%r14
+	pop	%r13
+	pop	%r12
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/aors_err1_n.asm b/third_party/gmp/mpn/x86_64/aors_err1_n.asm
new file mode 100644
index 0000000..54d0b3f
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/aors_err1_n.asm
@@ -0,0 +1,225 @@
+dnl  AMD64 mpn_add_err1_n, mpn_sub_err1_n
+
+dnl  Contributed by David Harvey.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 2.75 (degenerates to 3 c/l for some alignments)
+C AMD K10	 ?
+C Intel P4	 ?
+C Intel core2	 ?
+C Intel corei	 ?
+C Intel atom	 ?
+C VIA nano	 ?
+
+
+C INPUT PARAMETERS
+define(`rp',	`%rdi')
+define(`up',	`%rsi')
+define(`vp',	`%rdx')
+define(`ep',	`%rcx')
+define(`yp',	`%r8')
+define(`n',	`%r9')
+define(`cy_param',	`8(%rsp)')
+
+define(`el',	`%rbx')
+define(`eh',	`%rbp')
+define(`t0',	`%r10')
+define(`t1',	`%r11')
+define(`t2',	`%r12')
+define(`t3',	`%r13')
+define(`w0',	`%r14')
+define(`w1',	`%r15')
+
+ifdef(`OPERATION_add_err1_n', `
+	define(ADCSBB,	      adc)
+	define(func,	      mpn_add_err1_n)')
+ifdef(`OPERATION_sub_err1_n', `
+	define(ADCSBB,	      sbb)
+	define(func,	      mpn_sub_err1_n)')
+
+MULFUNC_PROLOGUE(mpn_add_err1_n mpn_sub_err1_n)
+
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(func)
+	mov	cy_param, %rax
+
+	push	%rbx
+	push	%rbp
+	push	%r12
+	push	%r13
+	push	%r14
+	push	%r15
+
+	lea	(up,n,8), up
+	lea	(vp,n,8), vp
+	lea	(rp,n,8), rp
+
+	mov	R32(n), R32(%r10)
+	and	$3, R32(%r10)
+	jz	L(0mod4)
+	cmp	$2, R32(%r10)
+	jc	L(1mod4)
+	jz	L(2mod4)
+L(3mod4):
+	xor	R32(el), R32(el)
+	xor	R32(eh), R32(eh)
+	xor	R32(t0), R32(t0)
+	xor	R32(t1), R32(t1)
+	lea	-24(yp,n,8), yp
+	neg	n
+
+	shr	$1, %al		   C restore carry
+	mov	(up,n,8), w0
+	mov	8(up,n,8), w1
+	ADCSBB	(vp,n,8), w0
+	mov	w0, (rp,n,8)
+	cmovc	16(yp), el
+	ADCSBB	8(vp,n,8), w1
+	mov	w1, 8(rp,n,8)
+	cmovc	8(yp), t0
+	mov	16(up,n,8), w0
+	ADCSBB	16(vp,n,8), w0
+	mov	w0, 16(rp,n,8)
+	cmovc	(yp), t1
+	setc	%al		   C save carry
+	add	t0, el
+	adc	$0, eh
+	add	t1, el
+	adc	$0, eh
+
+	add	$3, n
+	jnz	L(loop)
+	jmp	L(end)
+
+	ALIGN(16)
+L(0mod4):
+	xor	R32(el), R32(el)
+	xor	R32(eh), R32(eh)
+	lea	(yp,n,8), yp
+	neg	n
+	jmp	L(loop)
+
+	ALIGN(16)
+L(1mod4):
+	xor	R32(el), R32(el)
+	xor	R32(eh), R32(eh)
+	lea	-8(yp,n,8), yp
+	neg	n
+
+	shr	$1, %al		   C restore carry
+	mov	(up,n,8), w0
+	ADCSBB	(vp,n,8), w0
+	mov	w0, (rp,n,8)
+	cmovc	(yp), el
+	setc	%al		   C save carry
+
+	add	$1, n
+	jnz	L(loop)
+	jmp	L(end)
+
+	ALIGN(16)
+L(2mod4):
+	xor	R32(el), R32(el)
+	xor	R32(eh), R32(eh)
+	xor	R32(t0), R32(t0)
+	lea	-16(yp,n,8), yp
+	neg	n
+
+	shr	$1, %al		   C restore carry
+	mov	(up,n,8), w0
+	mov	8(up,n,8), w1
+	ADCSBB	(vp,n,8), w0
+	mov	w0, (rp,n,8)
+	cmovc	8(yp), el
+	ADCSBB	8(vp,n,8), w1
+	mov	w1, 8(rp,n,8)
+	cmovc	(yp), t0
+	setc	%al		   C save carry
+	add	t0, el
+	adc	$0, eh
+
+	add	$2, n
+	jnz	L(loop)
+	jmp	L(end)
+
+	ALIGN(32)
+L(loop):
+	shr	$1, %al		   C restore carry
+	mov	-8(yp), t0
+	mov	$0, R32(t3)
+	mov	(up,n,8), w0
+	mov	8(up,n,8), w1
+	ADCSBB	(vp,n,8), w0
+	cmovnc	t3, t0
+	ADCSBB	8(vp,n,8), w1
+	mov	-16(yp), t1
+	mov	w0, (rp,n,8)
+	mov	16(up,n,8), w0
+	mov	w1, 8(rp,n,8)
+	cmovnc	t3, t1
+	mov	-24(yp), t2
+	ADCSBB	16(vp,n,8), w0
+	cmovnc	t3, t2
+	mov	24(up,n,8), w1
+	ADCSBB	24(vp,n,8), w1
+	cmovc	-32(yp), t3
+	setc	%al		   C save carry
+	add	t0, el
+	adc	$0, eh
+	add	t1, el
+	adc	$0, eh
+	add	t2, el
+	adc	$0, eh
+	mov	w0, 16(rp,n,8)
+	add	t3, el
+	lea	-32(yp), yp
+	adc	$0, eh
+	mov	w1, 24(rp,n,8)
+	add	$4, n
+	jnz	L(loop)
+
+L(end):
+	mov	el, (ep)
+	mov	eh, 8(ep)
+
+	pop	%r15
+	pop	%r14
+	pop	%r13
+	pop	%r12
+	pop	%rbp
+	pop	%rbx
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/aors_err2_n.asm b/third_party/gmp/mpn/x86_64/aors_err2_n.asm
new file mode 100644
index 0000000..ce5c2a4
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/aors_err2_n.asm
@@ -0,0 +1,172 @@
+dnl  AMD64 mpn_add_err2_n, mpn_sub_err2_n
+
+dnl  Contributed by David Harvey.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 4.5
+C AMD K10	 ?
+C Intel P4	 ?
+C Intel core2	 6.9
+C Intel corei	 ?
+C Intel atom	 ?
+C VIA nano	 ?
+
+
+C INPUT PARAMETERS
+define(`rp',	`%rdi')
+define(`up',	`%rsi')
+define(`vp',	`%rdx')
+define(`ep',	`%rcx')
+define(`yp1',	`%r8')
+define(`yp2',   `%r9')
+define(`n_param',     `8(%rsp)')
+define(`cy_param',    `16(%rsp)')
+
+define(`cy1',   `%r14')
+define(`cy2',   `%rax')
+
+define(`n',     `%r10')
+
+define(`w',     `%rbx')
+define(`e1l',	`%rbp')
+define(`e1h',	`%r11')
+define(`e2l',	`%r12')
+define(`e2h',	`%r13')
+
+
+ifdef(`OPERATION_add_err2_n', `
+	define(ADCSBB,	      adc)
+	define(func,	      mpn_add_err2_n)')
+ifdef(`OPERATION_sub_err2_n', `
+	define(ADCSBB,	      sbb)
+	define(func,	      mpn_sub_err2_n)')
+
+MULFUNC_PROLOGUE(mpn_add_err2_n mpn_sub_err2_n)
+
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(func)
+	mov	cy_param, cy2
+	mov	n_param, n
+
+	push	%rbx
+	push	%rbp
+	push	%r12
+	push	%r13
+	push	%r14
+
+	xor	R32(e1l), R32(e1l)
+	xor	R32(e1h), R32(e1h)
+	xor	R32(e2l), R32(e2l)
+	xor	R32(e2h), R32(e2h)
+
+	sub	yp1, yp2
+
+	lea	(rp,n,8), rp
+	lea	(up,n,8), up
+	lea	(vp,n,8), vp
+
+	test	$1, n
+	jnz	L(odd)
+
+	lea	-8(yp1,n,8), yp1
+	neg	n
+	jmp	L(top)
+
+	ALIGN(16)
+L(odd):
+	lea	-16(yp1,n,8), yp1
+	neg	n
+	shr	$1, cy2
+	mov	(up,n,8), w
+	ADCSBB	(vp,n,8), w
+	cmovc	8(yp1), e1l
+	cmovc	8(yp1,yp2), e2l
+	mov	w, (rp,n,8)
+	sbb	cy2, cy2
+	inc	n
+	jz	L(end)
+
+	ALIGN(16)
+L(top):
+	mov	(up,n,8), w
+	shr	$1, cy2		C restore carry
+	ADCSBB	(vp,n,8), w
+	mov	w, (rp,n,8)
+	sbb	cy1, cy1	C generate mask, preserve CF
+
+	mov	8(up,n,8), w
+	ADCSBB	8(vp,n,8), w
+	mov	w, 8(rp,n,8)
+	sbb	cy2, cy2	C generate mask, preserve CF
+
+	mov	(yp1), w	C (e1h:e1l) += cy1 * yp1 limb
+	and	cy1, w
+	add	w, e1l
+	adc	$0, e1h
+
+	and	(yp1,yp2), cy1	C (e2h:e2l) += cy1 * yp2 limb
+	add	cy1, e2l
+	adc	$0, e2h
+
+	mov	-8(yp1), w	C (e1h:e1l) += cy2 * next yp1 limb
+	and	cy2, w
+	add	w, e1l
+	adc	$0, e1h
+
+	mov	-8(yp1,yp2), w	C (e2h:e2l) += cy2 * next yp2 limb
+	and	cy2, w
+	add	w, e2l
+	adc	$0, e2h
+
+	add	$2, n
+	lea	-16(yp1), yp1
+	jnz	L(top)
+L(end):
+
+	mov	e1l, (ep)
+	mov	e1h, 8(ep)
+	mov	e2l, 16(ep)
+	mov	e2h, 24(ep)
+
+	and	$1, %eax	C return carry
+
+	pop	%r14
+	pop	%r13
+	pop	%r12
+	pop	%rbp
+	pop	%rbx
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/aors_err3_n.asm b/third_party/gmp/mpn/x86_64/aors_err3_n.asm
new file mode 100644
index 0000000..bb6d0c5
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/aors_err3_n.asm
@@ -0,0 +1,156 @@
+dnl  AMD64 mpn_add_err3_n, mpn_sub_err3_n
+
+dnl  Contributed by David Harvey.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 7.0
+C AMD K10	 ?
+C Intel P4	 ?
+C Intel core2	 ?
+C Intel corei	 ?
+C Intel atom	 ?
+C VIA nano	 ?
+
+C INPUT PARAMETERS
+define(`rp',	`%rdi')
+define(`up',	`%rsi')
+define(`vp',	`%rdx')
+define(`ep',	`%rcx')
+define(`yp1',	`%r8')
+define(`yp2',   `%r9')
+define(`yp3_param',   `8(%rsp)')
+define(`n_param',     `16(%rsp)')
+define(`cy_param',    `24(%rsp)')
+
+define(`n',     `%r10')
+define(`yp3',   `%rcx')
+define(`t',     `%rbx')
+
+define(`e1l',	`%rbp')
+define(`e1h',	`%r11')
+define(`e2l',	`%r12')
+define(`e2h',	`%r13')
+define(`e3l',   `%r14')
+define(`e3h',   `%r15')
+
+
+
+ifdef(`OPERATION_add_err3_n', `
+	define(ADCSBB,	      adc)
+	define(func,	      mpn_add_err3_n)')
+ifdef(`OPERATION_sub_err3_n', `
+	define(ADCSBB,	      sbb)
+	define(func,	      mpn_sub_err3_n)')
+
+MULFUNC_PROLOGUE(mpn_add_err3_n mpn_sub_err3_n)
+
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(func)
+	mov	cy_param, %rax
+	mov	n_param, n
+
+	push	%rbx
+	push	%rbp
+	push	%r12
+	push	%r13
+	push	%r14
+	push	%r15
+
+	push	ep
+	mov	64(%rsp), yp3       C load from yp3_param
+
+	xor	R32(e1l), R32(e1l)
+	xor	R32(e1h), R32(e1h)
+	xor	R32(e2l), R32(e2l)
+	xor	R32(e2h), R32(e2h)
+	xor	R32(e3l), R32(e3l)
+	xor	R32(e3h), R32(e3h)
+
+	sub	yp1, yp2
+	sub	yp1, yp3
+
+	lea	-8(yp1,n,8), yp1
+	lea	(rp,n,8), rp
+	lea	(up,n,8), up
+	lea	(vp,n,8), vp
+	neg	n
+
+	ALIGN(16)
+L(top):
+	shr	$1, %rax		C restore carry
+	mov	(up,n,8), %rax
+	ADCSBB	(vp,n,8), %rax
+	mov	%rax, (rp,n,8)
+	sbb	%rax, %rax		C save carry and generate mask
+
+	mov	(yp1), t
+	and	%rax, t
+	add	t, e1l
+	adc	$0, e1h
+
+	mov	(yp1,yp2), t
+	and	%rax, t
+	add	t, e2l
+	adc	$0, e2h
+
+	mov	(yp1,yp3), t
+	and	%rax, t
+	add	t, e3l
+	adc	$0, e3h
+
+	lea	-8(yp1), yp1
+	inc	n
+	jnz     L(top)
+
+L(end):
+	and	$1, %eax
+	pop	ep
+
+	mov	e1l, (ep)
+	mov	e1h, 8(ep)
+	mov	e2l, 16(ep)
+	mov	e2h, 24(ep)
+	mov	e3l, 32(ep)
+	mov	e3h, 40(ep)
+
+	pop	%r15
+	pop	%r14
+	pop	%r13
+	pop	%r12
+	pop	%rbp
+	pop	%rbx
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/aors_n.asm b/third_party/gmp/mpn/x86_64/aors_n.asm
new file mode 100644
index 0000000..d5a314a
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/aors_n.asm
@@ -0,0 +1,178 @@
+dnl  AMD64 mpn_add_n, mpn_sub_n
+
+dnl  Copyright 2003-2005, 2007, 2008, 2010-2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 1.5
+C AMD K10	 1.5
+C AMD bd1	 1.8
+C AMD bd2	 1.74
+C AMD bd3	 ?
+C AMD bd4	 1.78
+C AMD zen	 1.5
+C AMD bt1	 2.54
+C AMD bt2	 2.15
+C Intel P4	11.5
+C Intel core2	 4.9
+C Intel NHM	 5.53
+C Intel SBR	 1.59
+C Intel IBR	 1.55
+C Intel HWL	 1.44
+C Intel BWL	 1.14
+C Intel SKL	 1.21
+C Intel atom	 4
+C Intel SLM	 3
+C VIA nano	 3.25
+
+C The loop of this code is the result of running a code generation and
+C optimization tool suite written by David Harvey and Torbjorn Granlund.
+
+C INPUT PARAMETERS
+define(`rp',	`%rdi')	C rcx
+define(`up',	`%rsi')	C rdx
+define(`vp',	`%rdx')	C r8
+define(`n',	`%rcx')	C r9
+define(`cy',	`%r8')	C rsp+40    (mpn_add_nc and mpn_sub_nc)
+
+ifdef(`OPERATION_add_n', `
+	define(ADCSBB,	      adc)
+	define(func,	      mpn_add_n)
+	define(func_nc,	      mpn_add_nc)')
+ifdef(`OPERATION_sub_n', `
+	define(ADCSBB,	      sbb)
+	define(func,	      mpn_sub_n)
+	define(func_nc,	      mpn_sub_nc)')
+
+MULFUNC_PROLOGUE(mpn_add_n mpn_add_nc mpn_sub_n mpn_sub_nc)
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(func_nc)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8	')
+	mov	R32(n), R32(%rax)
+	shr	$2, n
+	and	$3, R32(%rax)
+	bt	$0, %r8			C cy flag <- carry parameter
+	jrcxz	L(lt4)
+
+	mov	(up), %r8
+	mov	8(up), %r9
+	dec	n
+	jmp	L(mid)
+
+EPILOGUE()
+	ALIGN(16)
+PROLOGUE(func)
+	FUNC_ENTRY(4)
+	mov	R32(n), R32(%rax)
+	shr	$2, n
+	and	$3, R32(%rax)
+	jrcxz	L(lt4)
+
+	mov	(up), %r8
+	mov	8(up), %r9
+	dec	n
+	jmp	L(mid)
+
+L(lt4):	dec	R32(%rax)
+	mov	(up), %r8
+	jnz	L(2)
+	ADCSBB	(vp), %r8
+	mov	%r8, (rp)
+	adc	R32(%rax), R32(%rax)
+	FUNC_EXIT()
+	ret
+
+L(2):	dec	R32(%rax)
+	mov	8(up), %r9
+	jnz	L(3)
+	ADCSBB	(vp), %r8
+	ADCSBB	8(vp), %r9
+	mov	%r8, (rp)
+	mov	%r9, 8(rp)
+	adc	R32(%rax), R32(%rax)
+	FUNC_EXIT()
+	ret
+
+L(3):	mov	16(up), %r10
+	ADCSBB	(vp), %r8
+	ADCSBB	8(vp), %r9
+	ADCSBB	16(vp), %r10
+	mov	%r8, (rp)
+	mov	%r9, 8(rp)
+	mov	%r10, 16(rp)
+	setc	R8(%rax)
+	FUNC_EXIT()
+	ret
+
+	ALIGN(16)
+L(top):	ADCSBB	(vp), %r8
+	ADCSBB	8(vp), %r9
+	ADCSBB	16(vp), %r10
+	ADCSBB	24(vp), %r11
+	mov	%r8, (rp)
+	lea	32(up), up
+	mov	%r9, 8(rp)
+	mov	%r10, 16(rp)
+	dec	n
+	mov	%r11, 24(rp)
+	lea	32(vp), vp
+	mov	(up), %r8
+	mov	8(up), %r9
+	lea	32(rp), rp
+L(mid):	mov	16(up), %r10
+	mov	24(up), %r11
+	jnz	L(top)
+
+L(end):	lea	32(up), up
+	ADCSBB	(vp), %r8
+	ADCSBB	8(vp), %r9
+	ADCSBB	16(vp), %r10
+	ADCSBB	24(vp), %r11
+	lea	32(vp), vp
+	mov	%r8, (rp)
+	mov	%r9, 8(rp)
+	mov	%r10, 16(rp)
+	mov	%r11, 24(rp)
+	lea	32(rp), rp
+
+	inc	R32(%rax)
+	dec	R32(%rax)
+	jnz	L(lt4)
+	adc	R32(%rax), R32(%rax)
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/aorsmul_1.asm b/third_party/gmp/mpn/x86_64/aorsmul_1.asm
new file mode 100644
index 0000000..dfe4dc4
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/aorsmul_1.asm
@@ -0,0 +1,190 @@
+dnl  AMD64 mpn_addmul_1 and mpn_submul_1.
+
+dnl  Copyright 2003-2005, 2007, 2008, 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 2.52
+C AMD K10	 2.51
+C AMD bd1	 4.43
+C AMD bd2	 5.03	 5.63
+C AMD bd3	 ?
+C AMD bd4	 ?
+C AMD zen	 ?
+C AMD bobcat	 6.20
+C AMD jaguar	 5.57	 6.56
+C Intel P4	14.9	17.1
+C Intel core2	 5.15
+C Intel NHM	 4.93
+C Intel SBR	 3.95
+C Intel IBR	 3.75
+C Intel HWL	 3.62
+C Intel BWL	 2.53
+C Intel SKL	 2.53
+C Intel atom	21.3
+C Intel SLM	 9.0
+C VIA nano	 5.0
+
+C The loop of this code is the result of running a code generation and
+C optimization tool suite written by David Harvey and Torbjorn Granlund.
+
+C TODO
+C  * The loop is great, but the prologue and epilogue code was quickly written.
+C    Tune it!
+
+define(`rp',      `%rdi')   C rcx
+define(`up',      `%rsi')   C rdx
+define(`n_param', `%rdx')   C r8
+define(`vl',      `%rcx')   C r9
+
+define(`n',       `%r11')
+
+ifdef(`OPERATION_addmul_1',`
+      define(`ADDSUB',        `add')
+      define(`func',  `mpn_addmul_1')
+')
+ifdef(`OPERATION_submul_1',`
+      define(`ADDSUB',        `sub')
+      define(`func',  `mpn_submul_1')
+')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_addmul_1 mpn_submul_1)
+
+IFDOS(`	define(`up', ``%rsi'')	') dnl
+IFDOS(`	define(`rp', ``%rcx'')	') dnl
+IFDOS(`	define(`vl', ``%r9'')	') dnl
+IFDOS(`	define(`r9', ``rdi'')	') dnl
+IFDOS(`	define(`n',  ``%r8'')	') dnl
+IFDOS(`	define(`r8', ``r11'')	') dnl
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(func)
+
+IFDOS(``push	%rsi		'')
+IFDOS(``push	%rdi		'')
+IFDOS(``mov	%rdx, %rsi	'')
+
+	mov	(up), %rax		C read first u limb early
+	push	%rbx
+IFSTD(`	mov	n_param, %rbx   ')	C move away n from rdx, mul uses it
+IFDOS(`	mov	n, %rbx         ')
+	mul	vl
+IFSTD(`	mov	%rbx, n         ')
+
+	and	$3, R32(%rbx)
+	jz	L(b0)
+	cmp	$2, R32(%rbx)
+	jz	L(b2)
+	jg	L(b3)
+
+L(b1):	dec	n
+	jne	L(gt1)
+	ADDSUB	%rax, (rp)
+	jmp	L(ret)
+L(gt1):	lea	8(up,n,8), up
+	lea	-8(rp,n,8), rp
+	neg	n
+	xor	%r10, %r10
+	xor	R32(%rbx), R32(%rbx)
+	mov	%rax, %r9
+	mov	(up,n,8), %rax
+	mov	%rdx, %r8
+	jmp	L(L1)
+
+L(b0):	lea	(up,n,8), up
+	lea	-16(rp,n,8), rp
+	neg	n
+	xor	%r10, %r10
+	mov	%rax, %r8
+	mov	%rdx, %rbx
+	jmp	 L(L0)
+
+L(b3):	lea	-8(up,n,8), up
+	lea	-24(rp,n,8), rp
+	neg	n
+	mov	%rax, %rbx
+	mov	%rdx, %r10
+	jmp	L(L3)
+
+L(b2):	lea	-16(up,n,8), up
+	lea	-32(rp,n,8), rp
+	neg	n
+	xor	%r8, %r8
+	xor	R32(%rbx), R32(%rbx)
+	mov	%rax, %r10
+	mov	24(up,n,8), %rax
+	mov	%rdx, %r9
+	jmp	L(L2)
+
+	ALIGN(16)
+L(top):	ADDSUB	%r10, (rp,n,8)
+	adc	%rax, %r9
+	mov	(up,n,8), %rax
+	adc	%rdx, %r8
+	mov	$0, R32(%r10)
+L(L1):	mul	vl
+	ADDSUB	%r9, 8(rp,n,8)
+	adc	%rax, %r8
+	adc	%rdx, %rbx
+L(L0):	mov	8(up,n,8), %rax
+	mul	vl
+	ADDSUB	%r8, 16(rp,n,8)
+	adc	%rax, %rbx
+	adc	%rdx, %r10
+L(L3):	mov	16(up,n,8), %rax
+	mul	vl
+	ADDSUB	%rbx, 24(rp,n,8)
+	mov	$0, R32(%r8)		C zero
+	mov	%r8, %rbx		C zero
+	adc	%rax, %r10
+	mov	24(up,n,8), %rax
+	mov	%r8, %r9		C zero
+	adc	%rdx, %r9
+L(L2):	mul	vl
+	add	$4, n
+	js	 L(top)
+
+	ADDSUB	%r10, (rp,n,8)
+	adc	%rax, %r9
+	adc	%r8, %rdx
+	ADDSUB	%r9, 8(rp,n,8)
+L(ret):	adc	$0, %rdx
+	mov	%rdx, %rax
+
+	pop	%rbx
+IFDOS(``pop	%rdi		'')
+IFDOS(``pop	%rsi		'')
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/atom/addmul_2.asm b/third_party/gmp/mpn/x86_64/atom/addmul_2.asm
new file mode 100644
index 0000000..c1dcdc4
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/atom/addmul_2.asm
@@ -0,0 +1,186 @@
+dnl  AMD64 mpn_addmul_2 optimised for Intel Atom.
+
+dnl  Copyright 2008, 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb	best
+C AMD K8,K9
+C AMD K10
+C AMD bd1
+C AMD bd2
+C AMD bobcat
+C AMD jaguar
+C Intel P4
+C Intel PNR
+C Intel NHM
+C Intel SBR
+C Intel IBR
+C Intel HWL
+C Intel BWL
+C Intel atom	18.8		this
+C VIA nano
+
+C The loop of this code is the result of running a code generation and
+C optimisation tool suite written by David Harvey and Torbjorn Granlund.
+
+define(`rp',      `%rdi')   C rcx
+define(`up',      `%rsi')   C rdx
+define(`n_param', `%rdx')   C r8
+define(`vp',      `%rcx')   C r9
+
+define(`v0', `%r8')
+define(`v1', `%r9')
+define(`w0', `%rbx')
+define(`w1', `%rcx')
+define(`w2', `%rbp')
+define(`w3', `%r10')
+define(`n',  `%r11')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_addmul_2)
+	FUNC_ENTRY(4)
+	push	%rbx
+	push	%rbp
+
+	mov	(up), %rax
+
+	mov	(vp), v0
+	mov	8(vp), v1
+
+	mov	n_param, n
+	mul	v0
+
+	test	$1, R8(n)
+	jnz	L(bx1)
+
+L(bx0):	test	$2, R8(n)
+	jnz	L(b10)
+
+L(b00):	mov	%rax, w0
+	mov	(up), %rax
+	mov	%rdx, w1
+	xor	R32(w2), R32(w2)
+	lea	-8(rp), rp
+	jmp	L(lo0)
+
+L(b10):	mov	%rax, w2
+	mov	(up), %rax
+	mov	%rdx, w3
+	xor	R32(w0), R32(w0)
+	lea	-16(up), up
+	lea	-24(rp), rp
+	jmp	L(lo2)
+
+L(bx1):	test	$2, R8(n)
+	jnz	L(b11)
+
+L(b01):	mov	%rax, w3
+	mov	%rdx, w0
+	mov	(up), %rax
+	xor	R32(w1), R32(w1)
+	lea	8(up), up
+	dec	n
+	jmp	L(lo1)
+
+L(b11):	mov	%rax, w1
+	mov	(up), %rax
+	mov	%rdx, w2
+	xor	R32(w3), R32(w3)
+	lea	-8(up), up
+	lea	-16(rp), rp
+	jmp	L(lo3)
+
+	ALIGN(16)
+L(top):
+L(lo1):	mul	v1
+	add	w3, (rp)
+	mov	$0, R32(w2)
+	adc	%rax, w0
+	mov	(up), %rax
+	adc	%rdx, w1
+	mul	v0
+	add	%rax, w0
+	mov	(up), %rax
+	adc	%rdx, w1
+	adc	$0, R32(w2)
+L(lo0):	mul	v1
+	add	w0, 8(rp)
+	adc	%rax, w1
+	mov	8(up), %rax
+	mov	$0, R32(w3)
+	adc	%rdx, w2
+	mul	v0
+	add	%rax, w1
+	mov	8(up), %rax
+	adc	%rdx, w2
+	adc	$0, R32(w3)
+L(lo3):	mul	v1
+	add	w1, 16(rp)
+	adc	%rax, w2
+	mov	16(up), %rax
+	mov	$0, R32(w0)
+	adc	%rdx, w3
+	mul	v0
+	add	%rax, w2
+	mov	16(up), %rax
+	adc	%rdx, w3
+	adc	$0, R32(w0)
+L(lo2):	mul	v1
+	add	w2, 24(rp)
+	adc	%rax, w3
+	mov	24(up), %rax
+	adc	%rdx, w0
+	mov	$0, R32(w1)
+	lea	32(rp), rp
+	mul	v0
+	lea	32(up), up
+	add	%rax, w3
+	adc	%rdx, w0
+	mov	-8(up), %rax
+	adc	$0, R32(w1)
+	sub	$4, n
+	ja	L(top)
+
+L(end):	mul	v1
+	add	w3, (rp)
+	adc	%rax, w0
+	adc	%rdx, w1
+	mov	w0, 8(rp)
+	mov	w1, %rax
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/atom/aorrlsh1_n.asm b/third_party/gmp/mpn/x86_64/atom/aorrlsh1_n.asm
new file mode 100644
index 0000000..f44de19
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/atom/aorrlsh1_n.asm
@@ -0,0 +1,238 @@
+dnl  AMD64 mpn_addlsh1_n, mpn_rsblsh1_n optimised for Intel Atom.
+dnl  Used also for AMD bd1.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C TODO
+C  * This code is slightly large at 433 bytes.
+C  * sublsh1_n.asm and this file use the same basic pattern.
+
+C	     cycles/limb
+C AMD K8,K9	 ?
+C AMD K10	 ?
+C AMD bd1	 2.3
+C AMD bobcat	 ?
+C Intel P4	 ?
+C Intel core2	 ?
+C Intel NHM	 ?
+C Intel SBR	 ?
+C Intel atom	 4.875	(4.75 is probably possible)
+C VIA nano	 ?
+
+C INPUT PARAMETERS
+define(`rp',       `%rdi')
+define(`up',       `%rsi')
+define(`vp',       `%rdx')
+define(`n',        `%rcx')
+define(`cy',       `%r8')
+
+ifdef(`OPERATION_addlsh1_n', `
+  define(ADDSUB,	add)
+  define(ADCSBB,	adc)
+  define(func_n,	mpn_addlsh1_n)
+  define(func_nc,	mpn_addlsh1_nc)')
+ifdef(`OPERATION_rsblsh1_n', `
+  define(ADDSUB,	sub)
+  define(ADCSBB,	sbb)
+  define(func_n,	mpn_rsblsh1_n)
+  define(func_nc,	mpn_rsblsh1_nc)')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_addlsh1_n mpn_addlsh1_nc mpn_rsblsh1_n mpn_rsblsh1_nc)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(func_n)
+	FUNC_ENTRY(4)
+	push	%rbp
+	xor	R32(%rbp), R32(%rbp)
+L(ent):	mov	R32(n), R32(%rax)
+	and	$3, R32(%rax)
+	jz	L(b0)
+	cmp	$2, R32(%rax)
+	jz	L(b2)
+	jg	L(b3)
+
+L(b1):	mov	(vp), %r8
+	add	%r8, %r8
+	lea	8(vp), vp
+	sbb	R32(%rax), R32(%rax)	C save scy
+	add	R32(%rbp), R32(%rbp)	C restore acy
+	ADCSBB	(up), %r8
+	mov	%r8, (rp)
+	sbb	R32(%rbp), R32(%rbp)	C save acy
+	lea	8(up), up
+	lea	8(rp), rp
+	jmp	L(b0)
+
+L(b2):	mov	(vp), %r8
+	add	%r8, %r8
+	mov	8(vp), %r9
+	adc	%r9, %r9
+	lea	16(vp), vp
+	sbb	R32(%rax), R32(%rax)	C save scy
+	add	R32(%rbp), R32(%rbp)	C restore acy
+	ADCSBB	(up), %r8
+	mov	%r8, (rp)
+	ADCSBB	8(up), %r9
+	mov	%r9, 8(rp)
+	sbb	R32(%rbp), R32(%rbp)	C save acy
+	lea	16(up), up
+	lea	16(rp), rp
+	jmp	L(b0)
+
+L(b3):	mov	(vp), %r8
+	add	%r8, %r8
+	mov	8(vp), %r9
+	adc	%r9, %r9
+	mov	16(vp), %r10
+	adc	%r10, %r10
+	lea	24(vp), vp
+	sbb	R32(%rax), R32(%rax)	C save scy
+	add	R32(%rbp), R32(%rbp)	C restore acy
+	ADCSBB	(up), %r8
+	mov	%r8, (rp)
+	ADCSBB	8(up), %r9
+	mov	%r9, 8(rp)
+	ADCSBB	16(up), %r10
+	mov	%r10, 16(rp)
+	sbb	R32(%rbp), R32(%rbp)	C save acy
+	lea	24(up), up
+	lea	24(rp), rp
+
+L(b0):	test	$4, R8(n)
+	jz	L(skp)
+	add	R32(%rax), R32(%rax)	C restore scy
+	mov	(vp), %r8
+	adc	%r8, %r8
+	mov	8(vp), %r9
+	adc	%r9, %r9
+	mov	16(vp), %r10
+	adc	%r10, %r10
+	mov	24(vp), %r11
+	adc	%r11, %r11
+	lea	32(vp), vp
+	sbb	R32(%rax), R32(%rax)	C save scy
+	add	R32(%rbp), R32(%rbp)	C restore acy
+	ADCSBB	(up), %r8
+	mov	%r8, (rp)
+	ADCSBB	8(up), %r9
+	mov	%r9, 8(rp)
+	ADCSBB	16(up), %r10
+	mov	%r10, 16(rp)
+	ADCSBB	24(up), %r11
+	mov	%r11, 24(rp)
+	lea	32(up), up
+	lea	32(rp), rp
+	sbb	R32(%rbp), R32(%rbp)	C save acy
+
+L(skp):	cmp	$8, n
+	jl	L(rtn)
+
+	push	%r12
+	push	%r13
+	push	%r14
+	push	%rbx
+	lea	-64(rp), rp
+	jmp	L(x)
+
+	ALIGN(16)
+L(top):	add	R32(%rax), R32(%rax)	C restore scy
+	lea	64(rp), rp
+	mov	(vp), %r8
+	adc	%r8, %r8
+	mov	8(vp), %r9
+	adc	%r9, %r9
+	mov	16(vp), %r10
+	adc	%r10, %r10
+	mov	24(vp), %r11
+	adc	%r11, %r11
+	mov	32(vp), %r12
+	adc	%r12, %r12
+	mov	40(vp), %r13
+	adc	%r13, %r13
+	mov	48(vp), %r14
+	adc	%r14, %r14
+	mov	56(vp), %rbx
+	adc	%rbx, %rbx
+	lea	64(vp), vp
+	sbb	R32(%rax), R32(%rax)	C save scy
+	add	R32(%rbp), R32(%rbp)	C restore acy
+	ADCSBB	(up), %r8
+	mov	%r8, (rp)
+	ADCSBB	8(up), %r9
+	mov	%r9, 8(rp)
+	ADCSBB	16(up), %r10
+	mov	%r10, 16(rp)
+	ADCSBB	24(up), %r11
+	mov	%r11, 24(rp)
+	ADCSBB	32(up), %r12
+	mov	%r12, 32(rp)
+	ADCSBB	40(up), %r13
+	mov	%r13, 40(rp)
+	ADCSBB	48(up), %r14
+	mov	%r14, 48(rp)
+	ADCSBB	56(up), %rbx
+	mov	%rbx, 56(rp)
+	sbb	R32(%rbp), R32(%rbp)	C save acy
+	lea	64(up), up
+L(x):	sub	$8, n
+	jge	L(top)
+
+L(end):	pop	%rbx
+	pop	%r14
+	pop	%r13
+	pop	%r12
+L(rtn):
+ifdef(`OPERATION_addlsh1_n',`
+	add	R32(%rbp), R32(%rax)
+	neg	R32(%rax)')
+ifdef(`OPERATION_rsblsh1_n',`
+	sub	R32(%rax), R32(%rbp)
+	movslq	R32(%rbp), %rax')
+
+	pop	%rbp
+	FUNC_EXIT()
+	ret
+EPILOGUE()
+PROLOGUE(func_nc)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8	')
+	push	%rbp
+	neg	%r8			C set CF
+	sbb	R32(%rbp), R32(%rbp)	C save acy
+	jmp	L(ent)
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/atom/aorrlsh2_n.asm b/third_party/gmp/mpn/x86_64/atom/aorrlsh2_n.asm
new file mode 100644
index 0000000..02fb29d
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/atom/aorrlsh2_n.asm
@@ -0,0 +1,191 @@
+dnl  AMD64 mpn_addlsh2_n -- rp[] = up[] + (vp[] << 2)
+dnl  AMD64 mpn_rsblsh2_n -- rp[] = (vp[] << 2) - up[]
+dnl  Optimised for Intel Atom.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 ?
+C AMD K10	 ?
+C Intel P4	 ?
+C Intel core2	 ?
+C Intel NHM	 ?
+C Intel SBR	 ?
+C Intel atom	 5.75
+C VIA nano	 ?
+
+C INPUT PARAMETERS
+define(`rp',       `%rdi')
+define(`up',       `%rsi')
+define(`vp',       `%rdx')
+define(`n',        `%rcx')
+
+define(`LSH', 2)
+define(`RSH', 62)
+define(M, eval(m4_lshift(1,LSH)))
+
+ifdef(`OPERATION_addlsh2_n', `
+  define(ADDSUB,	add)
+  define(ADCSBB,	adc)
+  define(func_n,	mpn_addlsh2_n)
+  define(func_nc,	mpn_addlsh2_nc)')
+ifdef(`OPERATION_rsblsh2_n', `
+  define(ADDSUB,	sub)
+  define(ADCSBB,	sbb)
+  define(func_n,	mpn_rsblsh2_n)
+  define(func_nc,	mpn_rsblsh2_nc)')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_addlsh2_n mpn_rsblsh2_n)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(func_n)
+	FUNC_ENTRY(4)
+	push	%rbx
+	push	%rbp
+
+	mov	R32(n), R32(%rax)
+	and	$3, R32(%rax)
+	jz	L(b0)			C we rely on rax = 0 at target
+	cmp	$2, R32(%rax)
+	mov	$0, R32(%rax)
+	jz	L(b2)
+	jg	L(b3)
+
+L(b1):	mov	(vp), %r9
+	lea	(%rax,%r9,M), %rbp
+	shr	$RSH, %r9
+	sub	$1, n
+	lea	-8(up), up
+	lea	-8(rp), rp
+	jz	L(cj1)
+	mov	8(vp), %r10
+	lea	(%r9,%r10,M), %r9
+	shr	$RSH, %r10
+	mov	16(vp), %r11
+	lea	24(vp), vp
+	mov	(vp), %r8
+	lea	(%r10,%r11,M), %r10
+	shr	$RSH, %r11
+	add	R32(%rax), R32(%rax)
+	jmp	L(L1)
+
+L(b2):	lea	-32(rp), rp
+	mov	(vp), %r8
+	lea	-32(up), up
+	lea	(%rax,%r8,M), %rbx
+	shr	$RSH, %r8
+	mov	8(vp), %r9
+	sub	$2, n
+	jle	L(end)
+	jmp	L(top)
+
+L(b3):	lea	-24(up), up
+	mov	(vp), %r11
+	lea	-24(rp), rp
+	mov	8(vp), %r8
+	lea	(%rax,%r11,M), %r10
+	shr	$RSH, %r11
+	lea	8(vp), vp
+	lea	(%r11,%r8,M), %rbx
+	add	$1, n
+	jmp	L(L3)
+
+L(b0):	lea	-16(up), up
+	mov	(vp), %r10
+	lea	(%rax,%r10,M), %r9
+	shr	$RSH, %r10
+	mov	8(vp), %r11
+	lea	-16(rp), rp
+	mov	16(vp), %r8
+	lea	(%r10,%r11,M), %r10
+	shr	$RSH, %r11
+	add	R32(%rax), R32(%rax)
+	lea	16(vp), vp
+	jmp	L(L0)
+
+	ALIGN(16)
+L(top):	lea	(%r8,%r9,M), %rbp
+	shr	$RSH, %r9
+	lea	32(up), up
+	mov	16(vp), %r10
+	lea	(%r9,%r10,M), %r9
+	shr	$RSH, %r10
+	mov	24(vp), %r11
+	lea	32(rp), rp
+	lea	32(vp), vp
+	mov	(vp), %r8
+	lea	(%r10,%r11,M), %r10
+	shr	$RSH, %r11
+	add	R32(%rax), R32(%rax)
+	ADCSBB	(up), %rbx
+	mov	%rbx, (rp)
+L(L1):	ADCSBB	8(up), %rbp
+	mov	%rbp, 8(rp)
+L(L0):	ADCSBB	16(up), %r9
+	lea	(%r11,%r8,M), %rbx
+	mov	%r9, 16(rp)
+L(L3):	ADCSBB	24(up), %r10
+	sbb	R32(%rax), R32(%rax)
+L(L2):	shr	$RSH, %r8
+	mov	8(vp), %r9
+	mov	%r10, 24(rp)
+	sub	$4, n
+	jg	L(top)
+
+L(end):	lea	(%r8,%r9,M), %rbp
+	shr	$RSH, %r9
+	lea	32(up), up
+	lea	32(rp), rp
+	add	R32(%rax), R32(%rax)
+	ADCSBB	(up), %rbx
+	mov	%rbx, (rp)
+L(cj1):	ADCSBB	8(up), %rbp
+	mov	%rbp, 8(rp)
+
+ifdef(`OPERATION_addlsh2_n',`
+	mov	R32(n), R32(%rax)	C zero rax
+	adc	%r9, %rax')
+ifdef(`OPERATION_rsblsh2_n',`
+	sbb	n, %r9			C subtract 0
+	mov	%r9, %rax')
+
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/atom/aors_n.asm b/third_party/gmp/mpn/x86_64/atom/aors_n.asm
new file mode 100644
index 0000000..83b8df9
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/atom/aors_n.asm
@@ -0,0 +1,128 @@
+dnl  X86-64 mpn_add_n, mpn_sub_n, optimised for Intel Atom.
+
+dnl  Copyright 2011, 2017 Free Software Foundation, Inc.
+
+dnl  Contributed to the GNU project by Marco Bodrato.  Ported to 64-bit by
+dnl  Torbjörn Granlund.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	    cycles/limb
+C AMD K8,K9	 2
+C AMD K10	 2
+C AMD bull	 2.34\2.63
+C AMD pile	 2.27\2.52
+C AMD steam
+C AMD excavator
+C AMD bobcat	 2.79
+C AMD jaguar	 2.78
+C Intel P4	11
+C Intel core2	 7.5
+C Intel NHM	 8.5
+C Intel SBR	 2.11
+C Intel IBR	 2.07
+C Intel HWL	 1.75
+C Intel BWL	 1.51
+C Intel SKL	 1.52
+C Intel atom	 3
+C Intel SLM	 4
+C VIA nano
+
+define(`rp',	`%rdi')	C rcx
+define(`up',	`%rsi')	C rdx
+define(`vp',	`%rdx')	C r8
+define(`n',	`%rcx')	C r9
+define(`cy',	`%r8')	C rsp+40    (mpn_add_nc and mpn_sub_nc)
+
+ifdef(`OPERATION_add_n', `
+  define(ADCSBB,    adc)
+  define(func_n,    mpn_add_n)
+  define(func_nc,   mpn_add_nc)')
+ifdef(`OPERATION_sub_n', `
+  define(ADCSBB,    sbb)
+  define(func_n,    mpn_sub_n)
+  define(func_nc,   mpn_sub_nc)')
+
+MULFUNC_PROLOGUE(mpn_add_n mpn_add_nc mpn_sub_n mpn_sub_nc)
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(func_n)
+	FUNC_ENTRY(4)
+	xor	cy, cy			C carry
+
+L(com):	shr	n			C n >> 1
+	jz	L(1)			C n == 1
+	jc	L(1m2)			C n % 2 == 1
+
+L(0m2):	shr	cy
+	mov	(up), %r10
+	lea	8(up), up
+	lea	8(vp), vp
+	lea	-8(rp), rp
+	jmp	L(mid)
+
+L(1):	shr	cy
+	mov	(up), %r9
+	jmp	L(end)
+
+L(1m2):	shr	cy
+	mov	(up), %r9
+
+	ALIGN(16)
+L(top):	ADCSBB	(vp), %r9
+	lea	16(up), up
+	mov	-8(up), %r10
+	lea	16(vp), vp
+	mov	%r9, (rp)
+L(mid):	ADCSBB	-8(vp), %r10
+	lea	16(rp), rp
+	dec	n
+	mov	(up), %r9
+	mov	%r10, -8(rp)
+	jnz	L(top)
+
+L(end):	ADCSBB	(vp), %r9
+	mov	$0, R32(%rax)
+	mov	%r9, (rp)
+	adc	R32(%rax), R32(%rax)
+	FUNC_EXIT()
+	ret
+EPILOGUE()
+
+PROLOGUE(func_nc)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), cy	')
+	jmp	L(com)
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86_64/atom/aorsmul_1.asm b/third_party/gmp/mpn/x86_64/atom/aorsmul_1.asm
new file mode 100644
index 0000000..7cbc085
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/atom/aorsmul_1.asm
@@ -0,0 +1,194 @@
+dnl  AMD64 mpn_addmul_1/mpn_submul_1 optimised for Intel Atom.
+
+dnl  Copyright 2003-2005, 2007, 2008, 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 4.5
+C AMD K10	 4.5
+C AMD bull	 4.73
+C AMD pile	 4.60	 4.80
+C AMD steam
+C AMD excavator
+C AMD bobcat	 5.48
+C AMD jaguar	 5.61
+C Intel P4	16.6
+C Intel core2	 5.09
+C Intel NHM	 4.79
+C Intel SBR	 3.88
+C Intel IBR	 3.65
+C Intel HWL	 3.53
+C Intel BWL	 2.75
+C Intel SKL	 2.76
+C Intel atom	19.4
+C Intel SLM	 8
+C VIA nano
+
+C The loop of this code is the result of running a code generation and
+C optimisation tool suite written by David Harvey and Torbjorn Granlund.
+
+define(`rp',      `%rdi')   C rcx
+define(`up',      `%rsi')   C rdx
+define(`n_param', `%rdx')   C r8
+define(`v0',      `%rcx')   C r9
+
+define(`n',       `%rbx')
+
+ifdef(`OPERATION_addmul_1',`
+  define(`ADDSUB', `add')
+  define(`func',   `mpn_addmul_1')
+')
+ifdef(`OPERATION_submul_1',`
+  define(`ADDSUB', `sub')
+  define(`func',   `mpn_submul_1')
+')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_addmul_1 mpn_submul_1)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(func)
+	FUNC_ENTRY(4)
+	push	%rbx
+
+	mov	(up), %rax
+	lea	-8(up,n_param,8), up
+	lea	-16(rp,n_param,8), rp
+
+	test	$1, R8(n_param)
+	jnz	L(bx1)
+
+L(bx0):	test	$2, R8(n_param)
+	jnz	L(b10)
+
+L(b00):	mov	$1, R32(n)
+	sub	n_param, n
+	mul	v0
+	mov	%rax, %r11
+	mov	8(up,n,8), %rax
+	mov	%rdx, %r10
+	mul	v0
+	mov	%rax, %r8
+	mov	16(up,n,8), %rax
+	jmp	L(lo0)
+
+L(b10):	mov	$3, R32(n)
+	sub	n_param, n
+	mul	v0
+	mov	%rax, %r11
+	mov	-8(up,n,8), %rax
+	mov	%rdx, %r10
+	mul	v0
+	test	n, n
+	jns	L(cj2)
+	mov	%rax, %r8
+	mov	(up,n,8), %rax
+	mov	%rdx, %r9
+	jmp	L(lo2)
+
+L(bx1):	test	$2, R8(n_param)
+	jnz	L(b11)
+
+L(b01):	mov	$2, R32(n)
+	sub	n_param, n
+	mul	v0
+	test	n, n
+	jns	L(cj1)
+	mov	%rax, %r8
+	mov	(up,n,8), %rax
+	mov	%rdx, %r9
+	mul	v0
+	mov	%rax, %r11
+	mov	8(up,n,8), %rax
+	mov	%rdx, %r10
+	jmp	L(lo1)
+
+L(b11):	xor	R32(n), R32(n)
+	sub	n_param, n
+	mul	v0
+	mov	%rax, %r8
+	mov	16(up,n,8), %rax
+	mov	%rdx, %r9
+	mul	v0
+	mov	%rax, %r11
+	mov	24(up,n,8), %rax
+	jmp	L(lo3)
+
+	ALIGN(16)
+L(top):	mul	v0
+	ADDSUB	%r8, -16(rp,n,8)
+	mov	%rax, %r8
+	mov	(up,n,8), %rax
+	adc	%r9, %r11
+	mov	%rdx, %r9
+	adc	$0, %r10
+L(lo2):	mul	v0
+	ADDSUB	%r11, -8(rp,n,8)
+	mov	%rax, %r11
+	mov	8(up,n,8), %rax
+	adc	%r10, %r8
+	mov	%rdx, %r10
+	adc	$0, %r9
+L(lo1):	mul	v0
+	ADDSUB	%r8, (rp,n,8)
+	mov	%rax, %r8
+	adc	%r9, %r11
+	mov	16(up,n,8), %rax
+	adc	$0, %r10
+L(lo0):	mov	%rdx, %r9
+	mul	v0
+	ADDSUB	%r11, 8(rp,n,8)
+	mov	%rax, %r11
+	adc	%r10, %r8
+	mov	24(up,n,8), %rax
+	adc	$0, %r9
+L(lo3):	add	$4, n
+	mov	%rdx, %r10
+	js	L(top)
+
+L(end):	mul	v0
+	ADDSUB	%r8, -16(rp,n,8)
+	adc	%r9, %r11
+	adc	$0, %r10
+L(cj2):	ADDSUB	%r11, -8(rp,n,8)
+	adc	%r10, %rax
+	adc	$0, %rdx
+L(cj1):	ADDSUB	%rax, (rp,n,8)
+	mov	$0, R32(%rax)
+	adc	%rdx, %rax
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86_64/atom/cnd_add_n.asm b/third_party/gmp/mpn/x86_64/atom/cnd_add_n.asm
new file mode 100644
index 0000000..fcb9a0f
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/atom/cnd_add_n.asm
@@ -0,0 +1,38 @@
+dnl  X86-64 mpn_cnd_add_n.
+
+dnl  Copyright 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_cnd_add_n)
+include_mpn(`x86_64/coreisbr/cnd_add_n.asm')
diff --git a/third_party/gmp/mpn/x86_64/atom/cnd_sub_n.asm b/third_party/gmp/mpn/x86_64/atom/cnd_sub_n.asm
new file mode 100644
index 0000000..9eee1c1
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/atom/cnd_sub_n.asm
@@ -0,0 +1,38 @@
+dnl  X86-64 mpn_cnd_sub_n.
+
+dnl  Copyright 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_cnd_sub_n)
+include_mpn(`x86_64/coreisbr/cnd_sub_n.asm')
diff --git a/third_party/gmp/mpn/x86_64/atom/com.asm b/third_party/gmp/mpn/x86_64/atom/com.asm
new file mode 100644
index 0000000..6b6460f
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/atom/com.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_com optimised for Intel Atom.
+
+dnl  Copyright 2012, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_com)
+include_mpn(`x86_64/fastsse/com-palignr.asm')
diff --git a/third_party/gmp/mpn/x86_64/atom/copyd.asm b/third_party/gmp/mpn/x86_64/atom/copyd.asm
new file mode 100644
index 0000000..e309279
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/atom/copyd.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_copyd optimised for Intel Atom.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_copyd)
+include_mpn(`x86_64/fastsse/copyd-palignr.asm')
diff --git a/third_party/gmp/mpn/x86_64/atom/copyi.asm b/third_party/gmp/mpn/x86_64/atom/copyi.asm
new file mode 100644
index 0000000..00ec3c2
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/atom/copyi.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_copyi optimised for Intel Atom.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_copyi)
+include_mpn(`x86_64/fastsse/copyi-palignr.asm')
diff --git a/third_party/gmp/mpn/x86_64/atom/dive_1.asm b/third_party/gmp/mpn/x86_64/atom/dive_1.asm
new file mode 100644
index 0000000..d9ba5fe
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/atom/dive_1.asm
@@ -0,0 +1,37 @@
+dnl  AMD64 mpn_divexact_1 -- mpn by limb exact division.
+
+dnl  Copyright 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_divexact_1)
+include_mpn(`x86_64/nano/dive_1.asm')
diff --git a/third_party/gmp/mpn/x86_64/atom/gmp-mparam.h b/third_party/gmp/mpn/x86_64/atom/gmp-mparam.h
new file mode 100644
index 0000000..2cd90f6
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/atom/gmp-mparam.h
@@ -0,0 +1,222 @@
+/* Intel Atom/64 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+#define SHLD_SLOW 1
+#define SHRD_SLOW 1
+
+/* 1600 MHz Diamondville (Atom 330) */
+/* FFT tuning limit = 50,646,641 */
+/* Generated by tuneup.c, 2019-10-16, gcc 8.3 */
+
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          5
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          3
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD     MP_SIZE_T_MAX
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD         0  /* never mpn_mod_1s_2p */
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     12
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1_NORM_THRESHOLD              1
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           16
+
+#define DIV_1_VS_MUL_1_PERCENT             201
+
+#define MUL_TOOM22_THRESHOLD                12
+#define MUL_TOOM33_THRESHOLD                74
+#define MUL_TOOM44_THRESHOLD               106
+#define MUL_TOOM6H_THRESHOLD               155
+#define MUL_TOOM8H_THRESHOLD               212
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      73
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD      77
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD      73
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD      72
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD      58
+
+#define SQR_BASECASE_THRESHOLD               5
+#define SQR_TOOM2_THRESHOLD                 22
+#define SQR_TOOM3_THRESHOLD                 73
+#define SQR_TOOM4_THRESHOLD                130
+#define SQR_TOOM6_THRESHOLD                159
+#define SQR_TOOM8_THRESHOLD                236
+
+#define MULMID_TOOM42_THRESHOLD             16
+
+#define MULMOD_BNM1_THRESHOLD                9
+#define SQRMOD_BNM1_THRESHOLD                9
+
+#define MUL_FFT_MODF_THRESHOLD             220  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    220, 5}, {     11, 6}, {      6, 5}, {     13, 6}, \
+    {     13, 7}, {      7, 6}, {     15, 7}, {      8, 6}, \
+    {     17, 7}, {     13, 8}, {      7, 7}, {     17, 8}, \
+    {      9, 7}, {     19, 8}, {     11, 7}, {     23, 8}, \
+    {     13, 9}, {      7, 8}, {     19, 9}, {     11, 8}, \
+    {     25,10}, {      7, 9}, {     15, 8}, {     33, 9}, \
+    {     19, 8}, {     39, 9}, {     23, 8}, {     47, 9}, \
+    {     27,10}, {     15, 9}, {     39,10}, {     23, 9}, \
+    {     47,11}, {     15,10}, {     31, 9}, {     67,10}, \
+    {     39, 9}, {     79,10}, {     47, 9}, {     95,11}, \
+    {     31,10}, {     63, 9}, {    127, 8}, {    255,10}, \
+    {     71, 9}, {    143, 8}, {    287,10}, {     79,11}, \
+    {     47,10}, {     95, 9}, {    191,12}, {     31,11}, \
+    {     63,10}, {    127, 9}, {    255, 8}, {    511,10}, \
+    {    143, 9}, {    287,11}, {     79,10}, {    159, 9}, \
+    {    319,10}, {    175, 9}, {    351,11}, {     95,10}, \
+    {    191, 9}, {    383,10}, {    207,11}, {    111,10}, \
+    {    223,12}, {     63,11}, {    127,10}, {    255, 9}, \
+    {    511,11}, {    143,10}, {    287, 9}, {    575,11}, \
+    {    159,10}, {    319,11}, {    175,10}, {    351,12}, \
+    {     95,11}, {    191,10}, {    383,11}, {    207,10}, \
+    {    415,11}, {    223,13}, {     63,12}, {    127,11}, \
+    {    255,10}, {    511,11}, {    287,10}, {    575,12}, \
+    {    159,11}, {    319,10}, {    639,11}, {    351,12}, \
+    {    191,11}, {    383,10}, {    767,12}, {    223,11}, \
+    {    447,13}, {    127,12}, {    255,11}, {    511,12}, \
+    {    287,11}, {    575,12}, {    319,11}, {    639,12}, \
+    {    351,13}, {    191,12}, {    383,11}, {    767,12}, \
+    {    447,14}, {    127,13}, {    255,12}, {    575,13}, \
+    {    319,12}, {    703,13}, {    383,12}, {    767,13}, \
+    {    447,14}, {    255,13}, {    511,12}, {   1023,13}, \
+    {    575,12}, {   1151,13}, {    703,14}, {    383,13}, \
+    {    831,12}, {   1663,15}, {    255,14}, {    511,13}, \
+    {   1087,12}, {   2175,13}, {   1151,14}, {    639,13}, \
+    {   1407,12}, {   2815,14}, {    767,13}, {   1663,14}, \
+    {    895,13}, {   1791,15}, {    511,14}, {   1023,13}, \
+    {   2175,14}, {   1151,13}, {   2431,12}, {   4863,14}, \
+    {   1407,13}, {   2815,15}, {    767,14}, {   1791,16}, \
+    {    511,15}, {   1023,14}, {   2431,13}, {   4863,15}, \
+    {   1279,14}, {   2943,15}, {   1535,14}, {  16384,15}, \
+    {  32768,16}, {  65536,17}, { 131072,18}, { 262144,19}, \
+    { 524288,20}, {1048576,21}, {2097152,22}, {4194304,23}, \
+    {8388608,24} }
+#define MUL_FFT_TABLE3_SIZE 169
+#define MUL_FFT_THRESHOLD                 2240
+
+#define SQR_FFT_MODF_THRESHOLD             184  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    184, 5}, {     11, 6}, {     13, 7}, {      7, 6}, \
+    {     15, 7}, {      8, 6}, {     17, 7}, {     13, 8}, \
+    {      7, 7}, {     17, 8}, {      9, 7}, {     19, 8}, \
+    {     11, 7}, {     23, 8}, {     13, 9}, {      7, 8}, \
+    {     19, 9}, {     11, 8}, {     25,10}, {      7, 9}, \
+    {     15, 8}, {     33, 9}, {     19, 8}, {     39, 9}, \
+    {     23,10}, {     15, 9}, {     39,10}, {     23, 9}, \
+    {     47,11}, {     15,10}, {     31, 9}, {     63, 8}, \
+    {    127, 7}, {    255,10}, {     39, 8}, {    159,10}, \
+    {     47, 9}, {     95, 8}, {    191,11}, {     31,10}, \
+    {     63, 9}, {    127, 8}, {    255, 7}, {    511,10}, \
+    {     71, 9}, {    143, 8}, {    287, 7}, {    575, 9}, \
+    {    159, 8}, {    319,11}, {     47,10}, {     95, 9}, \
+    {    191, 8}, {    383,12}, {     31,11}, {     63,10}, \
+    {    127, 9}, {    255, 8}, {    511,10}, {    143, 9}, \
+    {    287, 8}, {    575,10}, {    159, 9}, {    319, 8}, \
+    {    639,10}, {    175, 9}, {    351,11}, {     95,10}, \
+    {    191, 9}, {    383,11}, {    111,10}, {    223, 9}, \
+    {    447,12}, {     63,11}, {    127,10}, {    255, 9}, \
+    {    511,11}, {    143,10}, {    287, 9}, {    575,11}, \
+    {    159,10}, {    319, 9}, {    639,11}, {    175,10}, \
+    {    351,12}, {     95,11}, {    191,10}, {    383, 9}, \
+    {    767,11}, {    223,10}, {    447,13}, {     63,12}, \
+    {    127,11}, {    255,10}, {    511,11}, {    287,10}, \
+    {    575,12}, {    159,11}, {    319,10}, {    639,11}, \
+    {    351,12}, {    191,11}, {    383,10}, {    767,12}, \
+    {    223,11}, {    447,13}, {    127,12}, {    255,11}, \
+    {    511,12}, {    287,11}, {    575,12}, {    319,11}, \
+    {    639,12}, {    351,13}, {    191,12}, {    383,11}, \
+    {    767,12}, {    447,14}, {    127,13}, {    255,12}, \
+    {    575,13}, {    319,12}, {    703,13}, {    383,12}, \
+    {    767,13}, {    447,14}, {    255,13}, {    511,12}, \
+    {   1023,13}, {    575,12}, {   1151,13}, {    703,14}, \
+    {    383,13}, {    831,12}, {   1663,15}, {    255,14}, \
+    {    511,13}, {   1151,14}, {    639,13}, {   1407,12}, \
+    {   2815,14}, {    767,13}, {   1663,14}, {    895,13}, \
+    {   1791,15}, {    511,14}, {   1023,13}, {   2047,14}, \
+    {   1151,13}, {   2431,12}, {   4863,14}, {   1407,13}, \
+    {   2815,15}, {    767,14}, {   1791,16}, {    511,15}, \
+    {   1023,14}, {   2431,13}, {   4863,15}, {   1279,14}, \
+    {   2943,15}, {   1535,14}, {  16384,15}, {  32768,16}, \
+    {  65536,17}, { 131072,18}, { 262144,19}, { 524288,20}, \
+    {1048576,21}, {2097152,22}, {4194304,23}, {8388608,24} }
+#define SQR_FFT_TABLE3_SIZE 172
+#define SQR_FFT_THRESHOLD                 1728
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  33
+#define MULLO_MUL_N_THRESHOLD             4392
+#define SQRLO_BASECASE_THRESHOLD             0  /* always */
+#define SQRLO_DC_THRESHOLD                  85
+#define SQRLO_SQR_THRESHOLD               3176
+
+#define DC_DIV_QR_THRESHOLD                 34
+#define DC_DIVAPPR_Q_THRESHOLD             119
+#define DC_BDIV_QR_THRESHOLD                31
+#define DC_BDIV_Q_THRESHOLD                 76
+
+#define INV_MULMOD_BNM1_THRESHOLD           22
+#define INV_NEWTON_THRESHOLD               149
+#define INV_APPR_THRESHOLD                 123
+
+#define BINV_NEWTON_THRESHOLD              179
+#define REDC_1_TO_REDC_2_THRESHOLD          24
+#define REDC_2_TO_REDC_N_THRESHOLD          39
+
+#define MU_DIV_QR_THRESHOLD                807
+#define MU_DIVAPPR_Q_THRESHOLD             807
+#define MUPI_DIV_QR_THRESHOLD               77
+#define MU_BDIV_QR_THRESHOLD               748
+#define MU_BDIV_Q_THRESHOLD                807
+
+#define POWM_SEC_TABLE  1,22,114,326,1486
+
+#define GET_STR_DC_THRESHOLD                16
+#define GET_STR_PRECOMPUTE_THRESHOLD        30
+#define SET_STR_DC_THRESHOLD               381
+#define SET_STR_PRECOMPUTE_THRESHOLD      1565
+
+#define FAC_DSC_THRESHOLD                  960
+#define FAC_ODD_THRESHOLD                    0  /* always */
+
+#define MATRIX22_STRASSEN_THRESHOLD         13
+#define HGCD2_DIV1_METHOD                    3  /* 5.86% faster than 4 */
+#define HGCD_THRESHOLD                      88
+#define HGCD_APPR_THRESHOLD                 88
+#define HGCD_REDUCE_THRESHOLD             1182
+#define GCD_DC_THRESHOLD                   241
+#define GCDEXT_DC_THRESHOLD                192
+#define JACOBI_BASE_METHOD                   3  /* 9.43% faster than 2 */
+
+/* Tuneup completed successfully, took 193098 seconds */
diff --git a/third_party/gmp/mpn/x86_64/atom/lshift.asm b/third_party/gmp/mpn/x86_64/atom/lshift.asm
new file mode 100644
index 0000000..1b37d5d
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/atom/lshift.asm
@@ -0,0 +1,123 @@
+dnl  AMD64 mpn_lshift -- mpn left shift, optimised for Atom.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 ?
+C AMD K10	 ?
+C Intel P4	 ?
+C Intel core2	 ?
+C Intel NHM	 ?
+C Intel SBR	 ?
+C Intel atom	 4.5
+C VIA nano	 ?
+
+C TODO
+C  * Consider using 4-way unrolling.  We reach 4 c/l, but the code is 2.5 times
+C    larger.
+
+C INPUT PARAMETERS
+define(`rp',	`%rdi')
+define(`up',	`%rsi')
+define(`n',	`%rdx')
+define(`cnt',	`%rcx')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_lshift)
+	FUNC_ENTRY(4)
+	lea	-8(up,n,8), up
+	lea	-8(rp,n,8), rp
+	shr	R32(n)
+	mov	(up), %rax
+	jnc	L(evn)
+
+	mov	%rax, %r11
+	shl	R8(%rcx), %r11
+	neg	R8(%rcx)
+	shr	R8(%rcx), %rax
+	test	n, n
+	jnz	L(gt1)
+	mov	%r11, (rp)
+	FUNC_EXIT()
+	ret
+
+L(gt1):	mov	-8(up), %r8
+	mov	%r8, %r10
+	shr	R8(%rcx), %r8
+	jmp	L(lo1)
+
+L(evn):	mov	%rax, %r10
+	neg	R8(%rcx)
+	shr	R8(%rcx), %rax
+	mov	-8(up), %r9
+	mov	%r9, %r11
+	shr	R8(%rcx), %r9
+	neg	R8(%rcx)
+	dec	n
+	lea	8(rp), rp
+	lea	-8(up), up
+	jz	L(end)
+
+	ALIGN(8)
+L(top):	shl	R8(%rcx), %r10
+	or	%r10, %r9
+	shl	R8(%rcx), %r11
+	neg	R8(%rcx)
+	mov	-8(up), %r8
+	mov	%r8, %r10
+	mov	%r9, -8(rp)
+	shr	R8(%rcx), %r8
+	lea	-16(rp), rp
+L(lo1):	mov	-16(up), %r9
+	or	%r11, %r8
+	mov	%r9, %r11
+	shr	R8(%rcx), %r9
+	lea	-16(up), up
+	neg	R8(%rcx)
+	mov	%r8, (rp)
+	dec	n
+	jg	L(top)
+
+L(end):	shl	R8(%rcx), %r10
+	or	%r10, %r9
+	shl	R8(%rcx), %r11
+	mov	%r9, -8(rp)
+	mov	%r11, -16(rp)
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/atom/lshiftc.asm b/third_party/gmp/mpn/x86_64/atom/lshiftc.asm
new file mode 100644
index 0000000..7385f8f
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/atom/lshiftc.asm
@@ -0,0 +1,127 @@
+dnl  AMD64 mpn_lshiftc -- mpn left shift with complement, optimised for Atom.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 ?
+C AMD K10	 ?
+C Intel P4	 ?
+C Intel core2	 ?
+C Intel NHM	 ?
+C Intel SBR	 ?
+C Intel atom	 5
+C VIA nano	 ?
+
+C TODO
+C  * Consider using 4-way unrolling.  We reach 4.5 c/l, but the code is 2.5
+C    times larger.
+
+C INPUT PARAMETERS
+define(`rp',	`%rdi')
+define(`up',	`%rsi')
+define(`n',	`%rdx')
+define(`cnt',	`%rcx')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_lshiftc)
+	FUNC_ENTRY(4)
+	lea	-8(up,n,8), up
+	lea	-8(rp,n,8), rp
+	shr	R32(n)
+	mov	(up), %rax
+	jnc	L(evn)
+
+	mov	%rax, %r11
+	shl	R8(%rcx), %r11
+	neg	R8(%rcx)
+	shr	R8(%rcx), %rax
+	test	n, n
+	jnz	L(gt1)
+	not	%r11
+	mov	%r11, (rp)
+	FUNC_EXIT()
+	ret
+
+L(gt1):	mov	-8(up), %r8
+	mov	%r8, %r10
+	shr	R8(%rcx), %r8
+	jmp	L(lo1)
+
+L(evn):	mov	%rax, %r10
+	neg	R8(%rcx)
+	shr	R8(%rcx), %rax
+	mov	-8(up), %r9
+	mov	%r9, %r11
+	shr	R8(%rcx), %r9
+	neg	R8(%rcx)
+	lea	8(rp), rp
+	lea	-8(up), up
+	jmp	L(lo0)
+
+C	ALIGN(16)
+L(top):	shl	R8(%rcx), %r10
+	or	%r10, %r9
+	shl	R8(%rcx), %r11
+	not	%r9
+	neg	R8(%rcx)
+	mov	-8(up), %r8
+	lea	-16(rp), rp
+	mov	%r8, %r10
+	shr	R8(%rcx), %r8
+	mov	%r9, 8(rp)
+L(lo1):	or	%r11, %r8
+	mov	-16(up), %r9
+	mov	%r9, %r11
+	shr	R8(%rcx), %r9
+	lea	-16(up), up
+	neg	R8(%rcx)
+	not	%r8
+	mov	%r8, (rp)
+L(lo0):	dec	n
+	jg	L(top)
+
+L(end):	shl	R8(%rcx), %r10
+	or	%r10, %r9
+	not	%r9
+	shl	R8(%rcx), %r11
+	not	%r11
+	mov	%r9, -8(rp)
+	mov	%r11, -16(rp)
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/atom/mul_1.asm b/third_party/gmp/mpn/x86_64/atom/mul_1.asm
new file mode 100644
index 0000000..a0dcf1e
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/atom/mul_1.asm
@@ -0,0 +1,147 @@
+dnl  AMD64 mpn_mul_1 optimised for Intel Atom.
+
+dnl  Copyright 2003-2005, 2007, 2008, 2012, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9      3.03
+C AMD K10        3.03
+C AMD bull       4.74
+C AMD pile       4.56
+C AMD steam
+C AMD excavator
+C AMD bobcat     5.56    6.04
+C AMD jaguar     5.55    5.84
+C Intel P4      13.05
+C Intel core2    4.03
+C Intel NHM      3.80
+C Intel SBR      2.75
+C Intel IBR      2.69
+C Intel HWL      2.50
+C Intel BWL      2.55
+C Intel SKL      2.57
+C Intel atom    17.3
+C Intel SLM     14.7
+C VIA nano
+
+C The loop of this code is the result of running a code generation and
+C optimisation tool suite written by David Harvey and Torbjorn Granlund.
+
+define(`rp',      `%rdi')   C rcx
+define(`up',      `%rsi')   C rdx
+define(`n_param', `%rdx')   C r8
+define(`v0',      `%rcx')   C r9
+
+define(`n',       `%r11')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_mul_1)
+	FUNC_ENTRY(4)
+	xor	%r8, %r8
+L(com):	mov	(up), %rax
+	lea	-16(up,n_param,8), up
+	lea	-8(rp,n_param,8), rp
+	test	$1, R8(n_param)
+	jnz	L(bx1)
+
+L(bx0):	mov	%r8, %r9
+	test	$2, R8(n_param)
+	jnz	L(b10)
+
+L(b00):	mov	$2, R32(n)
+	sub	n_param, n
+	jmp	L(lo0)
+
+L(bx1):	test	$2, R8(n_param)
+	jnz	L(b11)
+
+L(b01):	mov	$3, R32(n)
+	sub	n_param, n
+	mul	v0
+	cmp	$2, n
+	jnz	L(lo1)
+	jmp	L(cj1)
+
+L(b11):	mov	$1, R32(n)
+	sub	n_param, n
+	jmp	L(lo3)
+
+L(b10):	xor	R32(n), R32(n)
+	sub	n_param, n
+	jmp	L(lo2)
+
+L(top):	mul	v0
+	mov	%r9, -24(rp,n,8)
+L(lo1):	xor	%r9d, %r9d
+	add	%rax, %r8
+	mov	(up,n,8), %rax
+	adc	%rdx, %r9
+	mov	%r8, -16(rp,n,8)
+L(lo0):	xor	%r8d, %r8d
+	mul	v0
+	add	%rax, %r9
+	mov	8(up,n,8), %rax
+	adc	%rdx, %r8
+	mov	%r9, -8(rp,n,8)
+L(lo3):	xor	%r9d, %r9d
+	mul	v0
+	add	%rax, %r8
+	mov	16(up,n,8), %rax
+	adc	%rdx, %r9
+	mov	%r8, (rp,n,8)
+L(lo2):	xor	%r8d, %r8d
+	mul	v0
+	add	%rax, %r9
+	mov	24(up,n,8), %rax
+	adc	%rdx, %r8
+	add	$4, n
+	js	L(top)
+
+L(end):	mul	v0
+	mov	%r9, -8(rp)
+L(cj1):	add	%rax, %r8
+	mov	$0, R32(%rax)
+	adc	%rdx, %rax
+	mov	%r8, (rp)
+	FUNC_EXIT()
+	ret
+EPILOGUE()
+
+PROLOGUE(mpn_mul_1c)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8	')
+	jmp	L(com)
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86_64/atom/mul_2.asm b/third_party/gmp/mpn/x86_64/atom/mul_2.asm
new file mode 100644
index 0000000..4bc22cd
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/atom/mul_2.asm
@@ -0,0 +1,190 @@
+dnl  AMD64 mpn_mul_2 optimised for Intel Atom.
+
+dnl  Copyright 2008, 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb	best
+C AMD K8,K9      5.78
+C AMD K10        5.78
+C AMD bull       9.10
+C AMD pile       9.17
+C AMD steam
+C AMD excavator
+C AMD bobcat    11.3
+C AMD jaguar    10.9
+C Intel P4      24.6
+C Intel core2    8.06
+C Intel NHM      7.65
+C Intel SBR      6.28
+C Intel IBR      6.10
+C Intel HWL      6.09
+C Intel BWL      4.73
+C Intel SKL      4.77
+C Intel atom    35.3
+C Intel SLM     25.6
+C VIA nano
+
+C The loop of this code is the result of running a code generation and
+C optimisation tool suite written by David Harvey and Torbjorn Granlund.
+
+define(`rp',      `%rdi')   C rcx
+define(`up',      `%rsi')   C rdx
+define(`n_param', `%rdx')   C r8
+define(`vp',      `%rcx')   C r9
+
+define(`v0', `%r8')
+define(`v1', `%r9')
+define(`w0', `%rbx')
+define(`w1', `%rcx')
+define(`w2', `%rbp')
+define(`w3', `%r10')
+define(`n',  `%r11')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_mul_2)
+	FUNC_ENTRY(4)
+	push	%rbx
+	push	%rbp
+
+	mov	(up), %rax
+
+	mov	(vp), v0
+	mov	8(vp), v1
+
+	mov	n_param, n
+	mul	v0
+
+	test	$1, R8(n)
+	jnz	L(bx1)
+
+L(bx0):	test	$2, R8(n)
+	jnz	L(b10)
+
+L(b00):	mov	%rax, w0
+	mov	(up), %rax
+	mov	%rdx, w1
+	xor	R32(w2), R32(w2)
+	lea	-8(rp), rp
+	jmp	L(lo0)
+
+L(b10):	mov	%rax, w2
+	mov	(up), %rax
+	mov	%rdx, w3
+	xor	R32(w0), R32(w0)
+	lea	-16(up), up
+	lea	-24(rp), rp
+	jmp	L(lo2)
+
+L(bx1):	test	$2, R8(n)
+	jnz	L(b11)
+
+L(b01):	mov	%rax, w3
+	mov	%rdx, w0
+	mov	(up), %rax
+	xor	R32(w1), R32(w1)
+	lea	8(up), up
+	dec	n
+	jmp	L(lo1)
+
+L(b11):	mov	%rax, w1
+	mov	(up), %rax
+	mov	%rdx, w2
+	xor	R32(w3), R32(w3)
+	lea	-8(up), up
+	lea	-16(rp), rp
+	jmp	L(lo3)
+
+	ALIGN(16)
+L(top):
+L(lo1):	mul	v1
+	add	%rax, w0
+	mov	(up), %rax
+	mov	$0, R32(w2)
+	mov	w3, (rp)
+	adc	%rdx, w1
+	mul	v0
+	add	%rax, w0
+	mov	(up), %rax
+	adc	%rdx, w1
+	adc	$0, R32(w2)
+L(lo0):	mul	v1
+	add	%rax, w1
+	mov	8(up), %rax
+	mov	w0, 8(rp)
+	adc	%rdx, w2
+	mul	v0
+	add	%rax, w1
+	mov	8(up), %rax
+	adc	%rdx, w2
+	mov	$0, R32(w3)
+	adc	$0, R32(w3)
+L(lo3):	mul	v1
+	add	%rax, w2
+	mov	16(up), %rax
+	mov	w1, 16(rp)
+	mov	$0, R32(w0)
+	adc	%rdx, w3
+	mul	v0
+	add	%rax, w2
+	mov	16(up), %rax
+	adc	%rdx, w3
+L(lo2):	mov	$0, R32(w1)
+	mov	w2, 24(rp)
+	adc	$0, R32(w0)
+	mul	v1
+	add	%rax, w3
+	mov	24(up), %rax
+	lea	32(up), up
+	adc	%rdx, w0
+	mul	v0
+	lea	32(rp), rp
+	add	%rax, w3
+	adc	%rdx, w0
+	mov	-8(up), %rax
+	adc	$0, R32(w1)
+	sub	$4, n
+	ja	L(top)
+
+L(end):	mul	v1
+	mov	w3, (rp)
+	add	%rax, w0
+	adc	%rdx, w1
+	mov	w0, 8(rp)
+	mov	w1, %rax
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/atom/popcount.asm b/third_party/gmp/mpn/x86_64/atom/popcount.asm
new file mode 100644
index 0000000..fb14dd3
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/atom/popcount.asm
@@ -0,0 +1,35 @@
+dnl  x86-64 mpn_popcount.
+
+dnl  Copyright 2007, 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+MULFUNC_PROLOGUE(mpn_popcount)
+include_mpn(`x86/pentium4/sse2/popcount.asm')
diff --git a/third_party/gmp/mpn/x86_64/atom/redc_1.asm b/third_party/gmp/mpn/x86_64/atom/redc_1.asm
new file mode 100644
index 0000000..62b9a84
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/atom/redc_1.asm
@@ -0,0 +1,579 @@
+dnl  X86-64 mpn_redc_1 optimised for Intel Atom.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2003-2005, 2007, 2008, 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 ?
+C AMD K10	 ?
+C AMD bull	 ?
+C AMD pile	 ?
+C AMD steam	 ?
+C AMD bobcat	 5.0
+C AMD jaguar	 ?
+C Intel P4	 ?
+C Intel core	 ?
+C Intel NHM	 ?
+C Intel SBR	 ?
+C Intel IBR	 ?
+C Intel HWL	 ?
+C Intel BWL	 ?
+C Intel atom	 ?
+C VIA nano	 ?
+
+C TODO
+C  * Micro-optimise, none performed thus far.
+C  * Consider inlining mpn_add_n.
+C  * Single basecases out before the pushes.
+C  * Make lead-in code for the inner loops be more similar.
+
+C When playing with pointers, set this to $2 to fall back to conservative
+C indexing in wind-down code.
+define(`I',`$1')
+
+define(`rp',          `%rdi')   C rcx
+define(`up',          `%rsi')   C rdx
+define(`mp_param',    `%rdx')   C r8
+define(`n',           `%rcx')   C r9
+define(`u0inv',       `%r8')    C stack
+
+define(`i',           `%r14')
+define(`j',           `%r15')
+define(`mp',          `%r12')
+define(`q0',          `%r13')
+define(`w0',          `%rbp')
+define(`w1',          `%r9')
+define(`w2',          `%r10')
+define(`w3',          `%r11')
+
+C rax rbx rcx rdx rdi rsi rbp r8 r9 r10 r11 r12 r13 r14 r15
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+define(`ALIGNx', `ALIGN(16)')
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_redc_1)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8	')
+	push	%rbx
+	push	%rbp
+	push	%r12
+	push	%r13
+	push	%r14
+	push	%r15
+
+	mov	(up), q0
+	mov	n, j			C outer loop induction var
+	lea	(mp_param,n,8), mp
+	lea	(up,n,8), up
+	neg	n
+	imul	u0inv, q0		C first iteration q0
+
+	test	$1, R8(n)
+	jz	L(bx0)
+
+L(bx1):	test	$2, R8(n)
+	jz	L(b3)
+
+L(b1):	cmp	$-1, R32(n)
+	jz	L(n1)
+
+L(otp1):lea	1(n), i
+	mov	(mp,n,8), %rax
+	mul	q0
+	mov	%rax, %rbp
+	mov	8(mp,n,8), %rax
+	mov	%rdx, %r9
+	mul	q0
+	mov	%rax, %rbx
+	mov	16(mp,n,8), %rax
+	mov	%rdx, %r10
+	mul	q0
+	add	(up,n,8), %rbp
+	mov	%rax, %rbp
+	adc	%r9, %rbx
+	mov	24(mp,n,8), %rax
+	adc	$0, %r10
+	mov	%rdx, %r9
+	mul	q0
+	add	8(up,n,8), %rbx
+	mov	%rbx, 8(up,n,8)
+	mov	%rax, %r11
+	adc	%r10, %rbp
+	mov	32(mp,n,8), %rax
+	adc	$0, %r9
+	imul	u0inv, %rbx		C next q limb
+	jmp	L(e1)
+
+	ALIGNx
+L(tp1):	mul	q0
+	add	%rbp, -24(up,i,8)
+	mov	%rax, %rbp
+	mov	(mp,i,8), %rax
+	adc	%r9, %r11
+	mov	%rdx, %r9
+	adc	$0, %r10
+	mul	q0
+	add	%r11, -16(up,i,8)
+	mov	%rax, %r11
+	mov	8(mp,i,8), %rax
+	adc	%r10, %rbp
+	mov	%rdx, %r10
+	adc	$0, %r9
+	mul	q0
+	add	%rbp, -8(up,i,8)
+	mov	%rax, %rbp
+	adc	%r9, %r11
+	mov	16(mp,i,8), %rax
+	adc	$0, %r10
+	mov	%rdx, %r9
+	mul	q0
+	add	%r11, (up,i,8)
+	mov	%rax, %r11
+	adc	%r10, %rbp
+	mov	24(mp,i,8), %rax
+	adc	$0, %r9
+L(e1):	add	$4, i
+	mov	%rdx, %r10
+	js	L(tp1)
+
+L(ed1):	mul	q0
+	add	%rbp, I(-24(up),-24(up,i,8))
+	adc	%r9, %r11
+	adc	$0, %r10
+	add	%r11, I(-16(up),-16(up,i,8))
+	adc	%r10, %rax
+	adc	$0, %rdx
+	add	%rax, I(-8(up),-8(up,i,8))
+	adc	$0, %rdx
+	mov	%rdx, (up,n,8)		C up[0]
+	mov	%rbx, q0		C previously computed q limb -> q0
+	lea	8(up), up		C up++
+	dec	j
+	jnz	L(otp1)
+	jmp	L(cj)
+
+L(b3):	cmp	$-3, R32(n)
+	jz	L(n3)
+
+L(otp3):lea	3(n), i
+	mov	(mp,n,8), %rax
+	mul	q0
+	mov	%rax, %rbp
+	mov	8(mp,n,8), %rax
+	mov	%rdx, %r9
+	mul	q0
+	mov	%rax, %rbx
+	mov	16(mp,n,8), %rax
+	mov	%rdx, %r10
+	mul	q0
+	add	(up,n,8), %rbp
+	mov	%rax, %rbp
+	mov	24(mp,n,8), %rax
+	adc	%r9, %rbx
+	mov	%rdx, %r9
+	adc	$0, %r10
+	mul	q0
+	add	8(up,n,8), %rbx
+	mov	%rbx, 8(up,n,8)
+	mov	%rax, %r11
+	mov	32(mp,n,8), %rax
+	adc	%r10, %rbp
+	mov	%rdx, %r10
+	adc	$0, %r9
+	imul	u0inv, %rbx		C next q limb
+	jmp	L(e3)
+
+	ALIGNx
+L(tp3):	mul	q0
+	add	%rbp, -24(up,i,8)
+	mov	%rax, %rbp
+	mov	(mp,i,8), %rax
+	adc	%r9, %r11
+	mov	%rdx, %r9
+	adc	$0, %r10
+	mul	q0
+	add	%r11, -16(up,i,8)
+	mov	%rax, %r11
+	mov	8(mp,i,8), %rax
+	adc	%r10, %rbp
+	mov	%rdx, %r10
+	adc	$0, %r9
+L(e3):	mul	q0
+	add	%rbp, -8(up,i,8)
+	mov	%rax, %rbp
+	adc	%r9, %r11
+	mov	16(mp,i,8), %rax
+	adc	$0, %r10
+	mov	%rdx, %r9
+	mul	q0
+	add	%r11, (up,i,8)
+	mov	%rax, %r11
+	adc	%r10, %rbp
+	mov	24(mp,i,8), %rax
+	adc	$0, %r9
+	add	$4, i
+	mov	%rdx, %r10
+	js	L(tp3)
+
+L(ed3):	mul	q0
+	add	%rbp, I(-24(up),-24(up,i,8))
+	adc	%r9, %r11
+	adc	$0, %r10
+	add	%r11, I(-16(up),-16(up,i,8))
+	adc	%r10, %rax
+	adc	$0, %rdx
+	add	%rax, I(-8(up),-8(up,i,8))
+	adc	$0, %rdx
+	mov	%rdx, (up,n,8)		C up[0]
+	mov	%rbx, q0		C previously computed q limb -> q0
+	lea	8(up), up		C up++
+	dec	j
+	jnz	L(otp3)
+C	jmp	L(cj)
+
+L(cj):
+IFSTD(`	lea	(up,n,8), up		C param 2: up
+	lea	(up,n,8), %rdx		C param 3: up - n
+	neg	R32(n)		')	C param 4: n
+
+IFDOS(`	lea	(up,n,8), %rdx		C param 2: up
+	lea	(%rdx,n,8), %r8		C param 3: up - n
+	neg	R32(n)
+	mov	n, %r9			C param 4: n
+	mov	rp, %rcx	')	C param 1: rp
+
+IFSTD(`	sub	$8, %rsp	')
+IFDOS(`	sub	$40, %rsp	')
+	ASSERT(nz, `test $15, %rsp')
+	CALL(	mpn_add_n)
+IFSTD(`	add	$8, %rsp	')
+IFDOS(`	add	$40, %rsp	')
+
+L(ret):	pop	%r15
+	pop	%r14
+	pop	%r13
+	pop	%r12
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+
+L(bx0):	test	$2, R8(n)
+	jnz	L(b2)
+
+L(b0):	cmp	$-4, R32(n)
+	jz	L(n4)
+
+L(otp0):lea	4(n), i
+	mov	(mp,n,8), %rax
+	mul	q0
+	mov	%rax, %r11
+	mov	8(mp,n,8), %rax
+	mov	%rdx, %r10
+	mul	q0
+	mov	%rax, %rbx
+	mov	16(mp,n,8), %rax
+	mov	%rdx, %r9
+	mul	q0
+	add	(up,n,8), %r11
+	mov	%rax, %r11
+	adc	%r10, %rbx
+	mov	24(mp,n,8), %rax
+	adc	$0, %r9
+	mov	%rdx, %r10
+	mul	q0
+	add	8(up,n,8), %rbx
+	mov	%rbx, 8(up,n,8)
+	mov	%rax, %rbp
+	mov	32(mp,n,8), %rax
+	adc	%r9, %r11
+	mov	%rdx, %r9
+	adc	$0, %r10
+	imul	u0inv, %rbx		C next q limb
+	jmp	L(e0)
+
+	ALIGNx
+L(tp0):	mul	q0
+	add	%rbp, -24(up,i,8)
+	mov	%rax, %rbp
+	mov	(mp,i,8), %rax
+	adc	%r9, %r11
+	mov	%rdx, %r9
+	adc	$0, %r10
+L(e0):	mul	q0
+	add	%r11, -16(up,i,8)
+	mov	%rax, %r11
+	mov	8(mp,i,8), %rax
+	adc	%r10, %rbp
+	mov	%rdx, %r10
+	adc	$0, %r9
+	mul	q0
+	add	%rbp, -8(up,i,8)
+	mov	%rax, %rbp
+	adc	%r9, %r11
+	mov	16(mp,i,8), %rax
+	adc	$0, %r10
+	mov	%rdx, %r9
+	mul	q0
+	add	%r11, (up,i,8)
+	mov	%rax, %r11
+	adc	%r10, %rbp
+	mov	24(mp,i,8), %rax
+	adc	$0, %r9
+	add	$4, i
+	mov	%rdx, %r10
+	js	L(tp0)
+
+L(ed0):	mul	q0
+	add	%rbp, I(-24(up),-24(up,i,8))
+	adc	%r9, %r11
+	adc	$0, %r10
+	add	%r11, I(-16(up),-16(up,i,8))
+	adc	%r10, %rax
+	adc	$0, %rdx
+	add	%rax, I(-8(up),-8(up,i,8))
+	adc	$0, %rdx
+	mov	%rdx, (up,n,8)		C up[0]
+	mov	%rbx, q0		C previously computed q limb -> q0
+	lea	8(up), up		C up++
+	dec	j
+	jnz	L(otp0)
+	jmp	L(cj)
+
+L(b2):	cmp	$-2, R32(n)
+	jz	L(n2)
+
+L(otp2):lea	2(n), i
+	mov	(mp,n,8), %rax
+	mul	q0
+	mov	%rax, %r11
+	mov	8(mp,n,8), %rax
+	mov	%rdx, %r10
+	mul	q0
+	mov	%rax, %rbx
+	mov	16(mp,n,8), %rax
+	mov	%rdx, %r9
+	mul	q0
+	add	(up,n,8), %r11
+	mov	%rax, %r11
+	adc	%r10, %rbx
+	mov	24(mp,n,8), %rax
+	adc	$0, %r9
+	mov	%rdx, %r10
+	mul	q0
+	add	8(up,n,8), %rbx
+	mov	%rbx, 8(up,n,8)
+	mov	%rax, %rbp
+	mov	32(mp,n,8), %rax
+	adc	%r9, %r11
+	mov	%rdx, %r9
+	adc	$0, %r10
+	imul	u0inv, %rbx		C next q limb
+	jmp	L(e2)
+
+	ALIGNx
+L(tp2):	mul	q0
+	add	%rbp, -24(up,i,8)
+	mov	%rax, %rbp
+	mov	(mp,i,8), %rax
+	adc	%r9, %r11
+	mov	%rdx, %r9
+	adc	$0, %r10
+	mul	q0
+	add	%r11, -16(up,i,8)
+	mov	%rax, %r11
+	mov	8(mp,i,8), %rax
+	adc	%r10, %rbp
+	mov	%rdx, %r10
+	adc	$0, %r9
+	mul	q0
+	add	%rbp, -8(up,i,8)
+	mov	%rax, %rbp
+	adc	%r9, %r11
+	mov	16(mp,i,8), %rax
+	adc	$0, %r10
+	mov	%rdx, %r9
+L(e2):	mul	q0
+	add	%r11, (up,i,8)
+	mov	%rax, %r11
+	adc	%r10, %rbp
+	mov	24(mp,i,8), %rax
+	adc	$0, %r9
+	add	$4, i
+	mov	%rdx, %r10
+	js	L(tp2)
+
+L(ed2):	mul	q0
+	add	%rbp, I(-24(up),-24(up,i,8))
+	adc	%r9, %r11
+	adc	$0, %r10
+	add	%r11, I(-16(up),-16(up,i,8))
+	adc	%r10, %rax
+	adc	$0, %rdx
+	add	%rax, I(-8(up),-8(up,i,8))
+	adc	$0, %rdx
+	mov	%rdx, (up,n,8)		C up[0]
+	mov	%rbx, q0		C previously computed q limb -> q0
+	lea	8(up), up		C up++
+	dec	j
+	jnz	L(otp2)
+	jmp	L(cj)
+
+L(n1):	mov	(mp_param), %rax
+	mul	q0
+	add	-8(up), %rax
+	adc	(up), %rdx
+	mov	%rdx, (rp)
+	mov	$0, R32(%rax)
+	adc	R32(%rax), R32(%rax)
+	jmp	L(ret)
+
+L(n2):	mov	(mp_param), %rax
+	mov	-16(up), %rbp
+	mul	q0
+	add	%rax, %rbp
+	mov	%rdx, %r9
+	adc	$0, %r9
+	mov	-8(mp), %rax
+	mov	-8(up), %r10
+	mul	q0
+	add	%rax, %r10
+	mov	%rdx, %r11
+	adc	$0, %r11
+	add	%r9, %r10
+	adc	$0, %r11
+	mov	%r10, q0
+	imul	u0inv, q0		C next q0
+	mov	-16(mp), %rax
+	mul	q0
+	add	%rax, %r10
+	mov	%rdx, %r9
+	adc	$0, %r9
+	mov	-8(mp), %rax
+	mov	(up), %r14
+	mul	q0
+	add	%rax, %r14
+	adc	$0, %rdx
+	add	%r9, %r14
+	adc	$0, %rdx
+	xor	R32(%rax), R32(%rax)
+	add	%r11, %r14
+	adc	8(up), %rdx
+	mov	%r14, (rp)
+	mov	%rdx, 8(rp)
+	adc	R32(%rax), R32(%rax)
+	jmp	L(ret)
+
+	ALIGNx
+L(n3):	mov	-24(mp), %rax
+	mov	-24(up), %r10
+	mul	q0
+	add	%rax, %r10
+	mov	-16(mp), %rax
+	mov	%rdx, %r11
+	adc	$0, %r11
+	mov	-16(up), %rbp
+	mul	q0
+	add	%rax, %rbp
+	mov	%rdx, %r9
+	adc	$0, %r9
+	mov	-8(mp), %rax
+	add	%r11, %rbp
+	mov	-8(up), %r10
+	adc	$0, %r9
+	mul	q0
+	mov	%rbp, q0
+	imul	u0inv, q0		C next q0
+	add	%rax, %r10
+	mov	%rdx, %r11
+	adc	$0, %r11
+	mov	%rbp, -16(up)
+	add	%r9, %r10
+	adc	$0, %r11
+	mov	%r10, -8(up)
+	mov	%r11, -24(up)		C up[0]
+	lea	8(up), up		C up++
+	dec	j
+	jnz	L(n3)
+
+	mov	-48(up), %rdx
+	mov	-40(up), %rbx
+	xor	R32(%rax), R32(%rax)
+	add	%rbp, %rdx
+	adc	%r10, %rbx
+	adc	-8(up), %r11
+	mov	%rdx, (rp)
+	mov	%rbx, 8(rp)
+	mov	%r11, 16(rp)
+	adc	R32(%rax), R32(%rax)
+	jmp	L(ret)
+
+L(n4):	mov	-32(mp), %rax
+	mul	q0
+	mov	%rax, %r11
+	mov	-24(mp), %rax
+	mov	%rdx, %r10
+	mul	q0
+	mov	%rax, %rbx
+	mov	-16(mp), %rax
+	mov	%rdx, %r9
+	mul	q0
+	add	-32(up), %r11
+	mov	%rax, %r11
+	adc	%r10, %rbx
+	mov	-8(mp), %rax
+	adc	$0, %r9
+	mov	%rdx, %r10
+	mul	q0
+	add	-24(up), %rbx
+	mov	%rbx, -24(up)
+	adc	%r9, %r11
+	adc	$0, %r10
+	imul	u0inv, %rbx		C next q limb
+	add	%r11, -16(up)
+	adc	%r10, %rax
+	adc	$0, %rdx
+	add	%rax, -8(up)
+	adc	$0, %rdx
+	mov	%rdx, -32(up)		C up[0]
+	mov	%rbx, q0		C previously computed q limb -> q0
+	dec	j
+	lea	8(up), up		C up++
+	jnz	L(n4)
+	jmp	L(cj)
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86_64/atom/rsh1aors_n.asm b/third_party/gmp/mpn/x86_64/atom/rsh1aors_n.asm
new file mode 100644
index 0000000..6f5f638
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/atom/rsh1aors_n.asm
@@ -0,0 +1,287 @@
+dnl  x86-64 mpn_rsh1add_n/mpn_rsh1sub_n.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C TODO
+C  * Schedule loop less.  It is now almost surely overscheduled, resulting in
+C    large feed-in and wind-down code.
+
+C	     cycles/limb
+C AMD K8,K9	 ?
+C AMD K10	 ?
+C Intel P4	 ?
+C Intel core2	 ?
+C Intel NMH	 ?
+C Intel SBR	 ?
+C Intel atom	 5.25
+C VIA nano	 ?
+
+C INPUT PARAMETERS
+define(`rp',`%rdi')
+define(`up',`%rsi')
+define(`vp',`%rdx')
+define(`n',`%rcx')
+
+ifdef(`OPERATION_rsh1add_n', `
+	define(ADDSUB,	      add)
+	define(ADCSBB,	      adc)
+	define(func_n,	      mpn_rsh1add_n)
+	define(func_nc,	      mpn_rsh1add_nc)')
+ifdef(`OPERATION_rsh1sub_n', `
+	define(ADDSUB,	      sub)
+	define(ADCSBB,	      sbb)
+	define(func_n,	      mpn_rsh1sub_n)
+	define(func_nc,	      mpn_rsh1sub_nc)')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_rsh1add_n mpn_rsh1sub_n)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(func_n)
+	FUNC_ENTRY(4)
+	push	%rbx
+	push	%rbp
+	push	%r12
+	push	%r13
+	push	%r14
+	push	%r15
+
+	mov	(up), %r15
+	ADDSUB	(vp), %r15
+	sbb	R32(%rbx), R32(%rbx)
+	xor	R32(%rax), R32(%rax)
+	shr	%r15
+	adc	R32(%rax), R32(%rax)	C return value
+
+	mov	R32(n), R32(%rbp)
+	and	$3, R32(%rbp)
+	jz	L(b0)
+	cmp	$2, R32(%rbp)
+	jae	L(b23)
+
+L(b1):	dec	n
+	jnz	L(gt1)
+	shl	$63, %rbx
+	add	%rbx, %r15
+	mov	%r15, (rp)
+	jmp	L(cj1)
+L(gt1):	lea	24(up), up
+	lea	24(vp), vp
+	mov	-16(up), %r9
+	add	R32(%rbx), R32(%rbx)
+	mov	-8(up), %r10
+	lea	24(rp), rp
+	mov	(up), %r11
+	ADCSBB	-16(vp), %r9
+	ADCSBB	-8(vp), %r10
+	mov	%r15, %r12
+	ADCSBB	(vp), %r11
+	mov	%r9, %r13
+	sbb	R32(%rbx), R32(%rbx)
+	mov	%r11, %r15
+	mov	%r10, %r14
+	shl	$63, %r11
+	shl	$63, %r10
+	shl	$63, %r9
+	or	%r9, %r12
+	shr	%r13
+	mov	8(up), %r8
+	shr	%r14
+	or	%r10, %r13
+	shr	%r15
+	or	%r11, %r14
+	sub	$4, n
+	jz	L(cj5)
+L(gt5):	mov	16(up), %r9
+	add	R32(%rbx), R32(%rbx)
+	mov	24(up), %r10
+	ADCSBB	8(vp), %r8
+	mov	%r15, %rbp
+	mov	32(up), %r11
+	jmp	L(lo1)
+
+L(b23):	jnz	L(b3)
+	mov	8(up), %r8
+	sub	$2, n
+	jnz	L(gt2)
+	add	R32(%rbx), R32(%rbx)
+	ADCSBB	8(vp), %r8
+	mov	%r8, %r12
+	jmp	L(cj2)
+L(gt2):	mov	16(up), %r9
+	add	R32(%rbx), R32(%rbx)
+	mov	24(up), %r10
+	ADCSBB	8(vp), %r8
+	mov	%r15, %rbp
+	mov	32(up), %r11
+	ADCSBB	16(vp), %r9
+	lea	32(up), up
+	ADCSBB	24(vp), %r10
+	mov	%r9, %r13
+	ADCSBB	32(vp), %r11
+	mov	%r8, %r12
+	jmp	L(lo2)
+
+L(b3):	lea	40(up), up
+	lea	8(vp), vp
+	mov	%r15, %r14
+	add	R32(%rbx), R32(%rbx)
+	mov	-32(up), %r11
+	ADCSBB	0(vp), %r11
+	lea	8(rp), rp
+	sbb	R32(%rbx), R32(%rbx)
+	mov	%r11, %r15
+	shl	$63, %r11
+	mov	-24(up), %r8
+	shr	%r15
+	or	%r11, %r14
+	sub	$3, n
+	jnz	L(gt3)
+	add	R32(%rbx), R32(%rbx)
+	ADCSBB	8(vp), %r8
+	jmp	L(cj3)
+L(gt3):	mov	-16(up), %r9
+	add	R32(%rbx), R32(%rbx)
+	mov	-8(up), %r10
+	ADCSBB	8(vp), %r8
+	mov	%r15, %rbp
+	mov	(up), %r11
+	ADCSBB	16(vp), %r9
+	ADCSBB	24(vp), %r10
+	mov	%r8, %r12
+	jmp	L(lo3)
+
+L(b0):	lea	48(up), up
+	lea	16(vp), vp
+	add	R32(%rbx), R32(%rbx)
+	mov	-40(up), %r10
+	lea	16(rp), rp
+	mov	-32(up), %r11
+	ADCSBB	-8(vp), %r10
+	mov	%r15, %r13
+	ADCSBB	(vp), %r11
+	sbb	R32(%rbx), R32(%rbx)
+	mov	%r11, %r15
+	mov	%r10, %r14
+	shl	$63, %r11
+	shl	$63, %r10
+	mov	-24(up), %r8
+	shr	%r14
+	or	%r10, %r13
+	shr	%r15
+	or	%r11, %r14
+	sub	$4, n
+	jnz	L(gt4)
+	add	R32(%rbx), R32(%rbx)
+	ADCSBB	8(vp), %r8
+	jmp	L(cj4)
+L(gt4):	mov	-16(up), %r9
+	add	R32(%rbx), R32(%rbx)
+	mov	-8(up), %r10
+	ADCSBB	8(vp), %r8
+	mov	%r15, %rbp
+	mov	(up), %r11
+	ADCSBB	16(vp), %r9
+	jmp	L(lo0)
+
+	ALIGN(8)
+L(top):	mov	16(up), %r9
+	shr	%r14
+	or	%r10, %r13
+	shr	%r15
+	or	%r11, %r14
+	add	R32(%rbx), R32(%rbx)
+	mov	24(up), %r10
+	mov	%rbp, (rp)
+	ADCSBB	8(vp), %r8
+	mov	%r15, %rbp
+	lea	32(rp), rp
+	mov	32(up), %r11
+L(lo1):	ADCSBB	16(vp), %r9
+	lea	32(up), up
+	mov	%r12, -24(rp)
+L(lo0):	ADCSBB	24(vp), %r10
+	mov	%r8, %r12
+	mov	%r13, -16(rp)
+L(lo3):	ADCSBB	32(vp), %r11
+	mov	%r9, %r13
+	mov	%r14, -8(rp)
+L(lo2):	sbb	R32(%rbx), R32(%rbx)
+	shl	$63, %r8
+	mov	%r11, %r15
+	shr	%r12
+	mov	%r10, %r14
+	shl	$63, %r9
+	lea	32(vp), vp
+	shl	$63, %r10
+	or	%r8, %rbp
+	shl	$63, %r11
+	or	%r9, %r12
+	shr	%r13
+	mov	8(up), %r8
+	sub	$4, n
+	jg	L(top)
+
+L(end):	shr	%r14
+	or	%r10, %r13
+	shr	%r15
+	or	%r11, %r14
+	mov	%rbp, (rp)
+	lea	32(rp), rp
+L(cj5):	add	R32(%rbx), R32(%rbx)
+	ADCSBB	8(vp), %r8
+	mov	%r12, -24(rp)
+L(cj4):	mov	%r13, -16(rp)
+L(cj3):	mov	%r8, %r12
+	mov	%r14, -8(rp)
+L(cj2):	sbb	R32(%rbx), R32(%rbx)
+	shl	$63, %r8
+	shr	%r12
+	or	%r8, %r15
+	shl	$63, %rbx
+	add	%rbx, %r12
+	mov	%r15, (rp)
+	mov	%r12, 8(rp)
+L(cj1):	pop	%r15
+	pop	%r14
+	pop	%r13
+	pop	%r12
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/atom/rshift.asm b/third_party/gmp/mpn/x86_64/atom/rshift.asm
new file mode 100644
index 0000000..29c027d
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/atom/rshift.asm
@@ -0,0 +1,121 @@
+dnl  AMD64 mpn_rshift -- mpn right shift, optimised for Atom.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 ?
+C AMD K10	 ?
+C Intel P4	 ?
+C Intel core2	 ?
+C Intel NHM	 ?
+C Intel SBR	 ?
+C Intel atom	 4.5
+C VIA nano	 ?
+
+C TODO
+C  * Consider using 4-way unrolling.  We reach 4 c/l, but the code is 2.5 times
+C    larger.
+
+C INPUT PARAMETERS
+define(`rp',	`%rdi')
+define(`up',	`%rsi')
+define(`n',	`%rdx')
+define(`cnt',	`%rcx')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_rshift)
+	FUNC_ENTRY(4)
+	shr	R32(n)
+	mov	(up), %rax
+	jnc	L(evn)
+
+	mov	%rax, %r11
+	shr	R8(cnt), %r11
+	neg	R8(cnt)
+	shl	R8(cnt), %rax
+	test	n, n
+	jnz	L(gt1)
+	mov	%r11, (rp)
+	FUNC_EXIT()
+	ret
+
+L(gt1):	mov	8(up), %r8
+	mov	%r8, %r10
+	shl	R8(cnt), %r8
+	jmp	L(lo1)
+
+L(evn):	mov	%rax, %r10
+	neg	R8(cnt)
+	shl	R8(cnt), %rax
+	mov	8(up), %r9
+	mov	%r9, %r11
+	shl	R8(cnt), %r9
+	neg	R8(cnt)
+	dec	n
+	lea	-8(rp), rp
+	lea	8(up), up
+	jz	L(end)
+
+	ALIGN(8)
+L(top):	shr	R8(cnt), %r10
+	or	%r10, %r9
+	shr	R8(cnt), %r11
+	neg	R8(cnt)
+	mov	8(up), %r8
+	mov	%r8, %r10
+	mov	%r9, 8(rp)
+	shl	R8(cnt), %r8
+	lea	16(rp), rp
+L(lo1):	mov	16(up), %r9
+	or	%r11, %r8
+	mov	%r9, %r11
+	shl	R8(cnt), %r9
+	lea	16(up), up
+	neg	R8(cnt)
+	mov	%r8, (rp)
+	dec	n
+	jg	L(top)
+
+L(end):	shr	R8(cnt), %r10
+	or	%r10, %r9
+	shr	R8(cnt), %r11
+	mov	%r9, 8(rp)
+	mov	%r11, 16(rp)
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/atom/sublsh1_n.asm b/third_party/gmp/mpn/x86_64/atom/sublsh1_n.asm
new file mode 100644
index 0000000..1306acd
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/atom/sublsh1_n.asm
@@ -0,0 +1,242 @@
+dnl  AMD64 mpn_sublsh1_n optimised for Intel Atom.
+dnl  Used also for AMD bd1.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C TODO
+C  * This code is slightly large at 501 bytes.
+C  * aorrlsh1_n.asm and this file use the same basic pattern.
+
+C	     cycles/limb
+C AMD K8,K9	 ?
+C AMD K10	 ?
+C AMD bd1	 2.3
+C AMD bobcat	 ?
+C Intel P4	 ?
+C Intel core2	 ?
+C Intel NHM	 ?
+C Intel SBR	 ?
+C Intel atom	 5	(4.875 is probably possible)
+C VIA nano	 ?
+
+C INPUT PARAMETERS
+define(`rp',       `%rdi')
+define(`up',       `%rsi')
+define(`vp',       `%rdx')
+define(`n',        `%rcx')
+define(`cy',       `%r8')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_sublsh1_n)
+	FUNC_ENTRY(4)
+	push	%rbp
+	push	%r15
+	xor	R32(%rbp), R32(%rbp)
+L(ent):	mov	R32(n), R32(%rax)
+	and	$3, R32(%rax)
+	jz	L(b0)
+	cmp	$2, R32(%rax)
+	jz	L(b2)
+	jg	L(b3)
+
+L(b1):	mov	(vp), %r8
+	add	%r8, %r8
+	lea	8(vp), vp
+	sbb	R32(%rax), R32(%rax)	C save scy
+	add	R32(%rbp), R32(%rbp)	C restore acy
+	mov	(up), %r15
+	sbb	%r8, %r15
+	mov	%r15, (rp)
+	sbb	R32(%rbp), R32(%rbp)	C save acy
+	lea	8(up), up
+	lea	8(rp), rp
+	jmp	L(b0)
+
+L(b2):	mov	(vp), %r8
+	add	%r8, %r8
+	mov	8(vp), %r9
+	adc	%r9, %r9
+	lea	16(vp), vp
+	sbb	R32(%rax), R32(%rax)	C save scy
+	add	R32(%rbp), R32(%rbp)	C restore acy
+	mov	(up), %r15
+	sbb	%r8, %r15
+	mov	%r15, (rp)
+	mov	8(up), %r15
+	sbb	%r9, %r15
+	mov	%r15, 8(rp)
+	sbb	R32(%rbp), R32(%rbp)	C save acy
+	lea	16(up), up
+	lea	16(rp), rp
+	jmp	L(b0)
+
+L(b3):	mov	(vp), %r8
+	add	%r8, %r8
+	mov	8(vp), %r9
+	adc	%r9, %r9
+	mov	16(vp), %r10
+	adc	%r10, %r10
+	lea	24(vp), vp
+	sbb	R32(%rax), R32(%rax)	C save scy
+	add	R32(%rbp), R32(%rbp)	C restore acy
+	mov	(up), %r15
+	sbb	%r8, %r15
+	mov	%r15, (rp)
+	mov	8(up), %r15
+	sbb	%r9, %r15
+	mov	%r15, 8(rp)
+	mov	16(up), %r15
+	sbb	%r10, %r15
+	mov	%r15, 16(rp)
+	sbb	R32(%rbp), R32(%rbp)	C save acy
+	lea	24(up), up
+	lea	24(rp), rp
+
+L(b0):	test	$4, R8(n)
+	jz	L(skp)
+	add	R32(%rax), R32(%rax)	C restore scy
+	mov	(vp), %r8
+	adc	%r8, %r8
+	mov	8(vp), %r9
+	adc	%r9, %r9
+	mov	16(vp), %r10
+	adc	%r10, %r10
+	mov	24(vp), %r11
+	adc	%r11, %r11
+	lea	32(vp), vp
+	sbb	R32(%rax), R32(%rax)	C save scy
+	add	R32(%rbp), R32(%rbp)	C restore acy
+	mov	(up), %r15
+	sbb	%r8, %r15
+	mov	%r15, (rp)
+	mov	8(up), %r15
+	sbb	%r9, %r15
+	mov	%r15, 8(rp)
+	mov	16(up), %r15
+	sbb	%r10, %r15
+	mov	%r15, 16(rp)
+	mov	24(up), %r15
+	sbb	%r11, %r15
+	mov	%r15, 24(rp)
+	lea	32(up), up
+	lea	32(rp), rp
+	sbb	R32(%rbp), R32(%rbp)	C save acy
+
+L(skp):	cmp	$8, n
+	jl	L(rtn)
+
+	push	%r12
+	push	%r13
+	push	%r14
+	push	%rbx
+	lea	-64(rp), rp
+	jmp	L(x)
+
+	ALIGN(16)
+L(top):	mov	(vp), %r8
+	add	R32(%rax), R32(%rax)
+	lea	64(vp), vp
+	adc	%r8, %r8
+	mov	-56(vp), %r9
+	adc	%r9, %r9
+	mov	-48(vp), %r10
+	adc	%r10, %r10
+	mov	-40(vp), %r11
+	adc	%r11, %r11
+	mov	-32(vp), %r12
+	adc	%r12, %r12
+	mov	-24(vp), %r13
+	adc	%r13, %r13
+	mov	-16(vp), %r14
+	adc	%r14, %r14
+	mov	-8(vp), %r15
+	adc	%r15, %r15
+	sbb	R32(%rax), R32(%rax)
+	add	R32(%rbp), R32(%rbp)
+	mov	(up), %rbp
+	lea	64(rp), rp
+	mov	8(up), %rbx
+	sbb	%r8, %rbp
+	mov	32(up), %r8
+	mov	%rbp, (rp)
+	sbb	%r9, %rbx
+	mov	16(up), %rbp
+	mov	%rbx, 8(rp)
+	sbb	%r10, %rbp
+	mov	24(up), %rbx
+	mov	%rbp, 16(rp)
+	sbb	%r11, %rbx
+	mov	%rbx, 24(rp)
+	sbb	%r12, %r8
+	mov	40(up), %r9
+	mov	%r8, 32(rp)
+	sbb	%r13, %r9
+	mov	48(up), %rbp
+	mov	%r9, 40(rp)
+	sbb	%r14, %rbp
+	mov	56(up), %rbx
+	mov	%rbp, 48(rp)
+	sbb	%r15, %rbx
+	lea	64(up), up
+	mov	%rbx, 56(rp)
+	sbb	R32(%rbp), R32(%rbp)
+L(x):	sub	$8, n
+	jge	L(top)
+
+L(end):	pop	%rbx
+	pop	%r14
+	pop	%r13
+	pop	%r12
+L(rtn):
+	add	R32(%rbp), R32(%rax)
+	neg	R32(%rax)
+
+	pop	%r15
+	pop	%rbp
+	FUNC_EXIT()
+	ret
+EPILOGUE()
+PROLOGUE(mpn_sublsh1_nc)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8	')
+	push	%rbp
+	push	%r15
+	neg	%r8			C set CF
+	sbb	R32(%rbp), R32(%rbp)	C save acy
+	jmp	L(ent)
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/bd1/README b/third_party/gmp/mpn/x86_64/bd1/README
new file mode 100644
index 0000000..ccd210e
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/bd1/README
@@ -0,0 +1,11 @@
+This directory contains code for AMD bulldozer including its piledriver update.
+
+We currently make limited use of SIMD instructions, both via the MPN_PATH and
+via inclusion of x86_64/fastsse files.
+
+The bd1 cores share one SIMD/FPU pipeline for two integer units.  This probably
+means that an all-core GMP load (such as a HPC load) might run slower if there
+is significant SIMD dependency.
+
+We should perhaps allow a special 'bd1nosimd' pseudo cpu-name excluding any
+SIMD code.
diff --git a/third_party/gmp/mpn/x86_64/bd1/addmul_2.asm b/third_party/gmp/mpn/x86_64/bd1/addmul_2.asm
new file mode 100644
index 0000000..b54e91a
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/bd1/addmul_2.asm
@@ -0,0 +1,235 @@
+dnl  AMD64 mpn_addmul_2 optimised for AMD Bulldozer.
+
+dnl  Copyright 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9
+C AMD K10
+C AMD bd1	 4.2
+C AMD bd2	 4.4
+C AMD bd3
+C AMD bd4
+C AMD zen
+C AMD bt1
+C AMD bt2
+C Intel P4
+C Intel PNR
+C Intel NHM
+C Intel SBR
+C Intel IBR
+C Intel HWL
+C Intel BWL
+C Intel SKL
+C Intel atom
+C Intel SLM
+C VIA nano
+
+C The loop of this code is the result of running a code generation and
+C optimisation tool suite written by David Harvey and Torbjorn Granlund.
+
+define(`rp',      `%rdi')   C rcx
+define(`up',      `%rsi')   C rdx
+define(`n_param', `%rdx')   C r8
+define(`vp',      `%rcx')   C r9
+
+define(`n',       `%rcx')
+define(`v0',      `%rbx')
+define(`v1',      `%rbp')
+define(`X0',      `%r12')
+define(`X1',      `%r13')
+
+define(`w0',    `%r8')
+define(`w1',    `%r9')
+define(`w2',    `%r10')
+define(`w3',    `%r11')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_addmul_2)
+	FUNC_ENTRY(4)
+	push	%rbx
+	push	%rbp
+	push	%r12
+	push	%r13
+
+	mov	(vp), v0
+	mov	8(vp), v1
+
+	mov	(up), %rax
+	mov	$0, R32(w2)		C abuse w2
+
+	lea	(up,n_param,8), up
+	lea	(rp,n_param,8), rp
+	sub	n_param, w2
+	mul	v0
+
+	test	$1, R8(w2)
+	jnz	L(bx1)
+
+L(bx0):	mov	%rdx, X0
+	mov	%rax, X1
+	test	$2, R8(w2)
+	jnz	L(b10)
+
+L(b00):	lea	(w2), n			C un = 4, 8, 12, ...
+	mov	(up,w2,8), %rax
+	mov	(rp,w2,8), w3
+	mul	v1
+	mov	%rax, w0
+	mov	8(up,w2,8), %rax
+	mov	%rdx, w1
+	jmp	L(lo0)
+
+L(b10):	lea	2(w2), n		C un = 2, 6, 10, ...
+	mov	(up,w2,8), %rax
+	mov	(rp,w2,8), w1
+	mul	v1
+	mov	%rdx, w3
+	mov	%rax, w2
+	mov	-8(up,n,8), %rax
+	test	n, n
+	jz	L(end)
+	jmp	L(top)
+
+L(bx1):	mov	%rax, X0
+	mov	%rdx, X1
+	test	$2, R8(w2)
+	jz	L(b11)
+
+L(b01):	lea	1(w2), n		C un = 1, 5, 9, ...
+	mov	(up,w2,8), %rax
+	mul	v1
+	mov	(rp,w2,8), w2
+	mov	%rdx, w0
+	mov	%rax, w3
+	jmp	L(lo1)
+
+L(b11):	lea	-1(w2), n		C un = 3, 7, 11, ...
+	mov	(up,w2,8), %rax
+	mul	v1
+	mov	(rp,w2,8), w0
+	mov	%rax, w1
+	mov	8(up,w2,8), %rax
+	mov	%rdx, w2
+	jmp	L(lo3)
+
+	ALIGN(32)
+L(top):
+L(lo2):	mul	v0
+	add	w1, X1
+	mov	X1, -16(rp,n,8)
+	mov	%rdx, X1
+	adc	%rax, X0
+	adc	$0, X1
+	mov	-8(up,n,8), %rax
+	mul	v1
+	mov	-8(rp,n,8), w1
+	mov	%rdx, w0
+	add	w1, w2
+	adc	%rax, w3
+	adc	$0, w0
+L(lo1):	mov	(up,n,8), %rax
+	mul	v0
+	add	w2, X0
+	mov	X0, -8(rp,n,8)
+	mov	%rdx, X0
+	adc	%rax, X1
+	mov	(up,n,8), %rax
+	adc	$0, X0
+	mov	(rp,n,8), w2
+	mul	v1
+	add	w2, w3
+	adc	%rax, w0
+	mov	8(up,n,8), %rax
+	mov	%rdx, w1
+	adc	$0, w1
+L(lo0):	mul	v0
+	add	w3, X1
+	mov	X1, (rp,n,8)
+	adc	%rax, X0
+	mov	8(up,n,8), %rax
+	mov	%rdx, X1
+	adc	$0, X1
+	mov	8(rp,n,8), w3
+	mul	v1
+	add	w3, w0
+	adc	%rax, w1
+	mov	16(up,n,8), %rax
+	mov	%rdx, w2
+	adc	$0, w2
+L(lo3):	mul	v0
+	add	w0, X0
+	mov	X0, 8(rp,n,8)
+	mov	%rdx, X0
+	adc	%rax, X1
+	adc	$0, X0
+	mov	16(up,n,8), %rax
+	mov	16(rp,n,8), w0
+	mul	v1
+	mov	%rdx, w3
+	add	w0, w1
+	adc	%rax, w2
+	adc	$0, w3
+	mov	24(up,n,8), %rax
+	add	$4, n
+	jnc	L(top)
+
+L(end):	mul	v0
+	add	w1, X1
+	mov	X1, -16(rp)
+	mov	%rdx, X1
+	adc	%rax, X0
+	adc	$0, X1
+	mov	-8(up), %rax
+	mul	v1
+	mov	-8(rp), w1
+	add	w1, w2
+	adc	%rax, w3
+	adc	$0, %rdx
+	add	w2, X0
+	adc	$0, X1
+	mov	X0, -8(rp)
+	add	w3, X1
+	mov	X1, (rp)
+	adc	$0, %rdx
+	mov	%rdx, %rax
+
+	pop	%r13
+	pop	%r12
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/bd1/aorrlsh1_n.asm b/third_party/gmp/mpn/x86_64/bd1/aorrlsh1_n.asm
new file mode 100644
index 0000000..c34a5fa
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/bd1/aorrlsh1_n.asm
@@ -0,0 +1,37 @@
+dnl  AMD64 mpn_addlsh1_n and mpn_rsblsh1_n
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_addlsh1_n mpn_addlsh1_nc mpn_rsblsh1_n mpn_rsblsh1_nc)
+include_mpn(`x86_64/atom/aorrlsh1_n.asm')
diff --git a/third_party/gmp/mpn/x86_64/bd1/aorrlsh_n.asm b/third_party/gmp/mpn/x86_64/bd1/aorrlsh_n.asm
new file mode 100644
index 0000000..5516c9d
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/bd1/aorrlsh_n.asm
@@ -0,0 +1,38 @@
+dnl  X86-64 mpn_addlsh_n and mpn_rsblsh_n.
+
+dnl  Copyright 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_addlsh_n mpn_rsblsh_n)
+include_mpn(`x86_64/aorrlsh_n.asm')
diff --git a/third_party/gmp/mpn/x86_64/bd1/aors_n.asm b/third_party/gmp/mpn/x86_64/bd1/aors_n.asm
new file mode 100644
index 0000000..143c42e
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/bd1/aors_n.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_add_n, mpn_sub_n, optimised for Intel Silvermont.
+
+dnl  Copyright 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_add_n mpn_add_nc mpn_sub_n mpn_sub_nc)
+include_mpn(`x86_64/coreihwl/aors_n.asm')
diff --git a/third_party/gmp/mpn/x86_64/bd1/aorsmul_1.asm b/third_party/gmp/mpn/x86_64/bd1/aorsmul_1.asm
new file mode 100644
index 0000000..fc0d2fe
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/bd1/aorsmul_1.asm
@@ -0,0 +1,190 @@
+dnl  AMD64 mpn_addmul_1 and mpn_submul_1 optimised for AMD Bulldozer.
+
+dnl  Copyright 2003-2005, 2007, 2008, 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9      3.30    3.58
+C AMD K10        3.09
+C AMD bull       4.47    4.72
+C AMD pile       4.66
+C AMD steam
+C AMD excavator
+C AMD bobcat     6.30
+C AMD jaguar     6.29
+C Intel P4      17.3    17.8
+C Intel core2    5.13
+C Intel NHM      4.85
+C Intel SBR      3.83
+C Intel IBR      3.75
+C Intel HWL      3.45
+C Intel BWL      2.56
+C Intel SKL      2.53
+C Intel atom    20.3
+C Intel SLM      9
+C VIA nano
+
+C The loop of this code is the result of running a code generation and
+C optimisation tool suite written by David Harvey and Torbjorn Granlund.
+
+C TODO
+C  * Try to make loop run closer to 4 c/l in Bulldozer and Piledriver.
+
+define(`rp',      `%rdi')   C rcx
+define(`up',      `%rsi')   C rdx
+define(`n_param', `%rdx')   C r8
+define(`v0',      `%rcx')   C r9
+
+define(`n',       `%r11')
+
+ifdef(`OPERATION_addmul_1',`
+      define(`ADDSUB',        `add')
+      define(`func',  `mpn_addmul_1')
+')
+ifdef(`OPERATION_submul_1',`
+      define(`ADDSUB',        `sub')
+      define(`func',  `mpn_submul_1')
+')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_addmul_1 mpn_submul_1)
+
+IFDOS(`	define(`up', ``%rsi'')	') dnl
+IFDOS(`	define(`rp', ``%rcx'')	') dnl
+IFDOS(`	define(`v0', ``%r9'')	') dnl
+IFDOS(`	define(`r9', ``rdi'')	') dnl
+IFDOS(`	define(`n',  ``%r8'')	') dnl
+IFDOS(`	define(`r8', ``r11'')	') dnl
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(func)
+IFDOS(``push	%rsi		'')
+IFDOS(``push	%rdi		'')
+IFDOS(``mov	%rdx, %rsi	'')
+
+	mov	(up), %rax		C read first u limb early
+	push	%rbx
+IFSTD(`	mov	n_param, %rbx	')	C move away n from rdx, mul uses it
+IFDOS(`	mov	n, %rbx		')
+	mul	v0
+
+IFSTD(`	mov	%rbx, n		')
+
+	and	$3, R32(%rbx)
+	lea	-16(rp,n,8), rp
+	jz	L(b0)
+	cmp	$2, R32(%rbx)
+	jb	L(b1)
+	jz	L(b2)
+
+L(b3):	mov	$0, R32(%r8)
+	mov	%rax, %rbx
+	mov	$0, R32(%r9)
+	mov	8(up), %rax
+	mov	%rdx, %r10
+	lea	(up,n,8), up
+	not	n
+	jmp	L(L3)
+
+L(b0):	mov	$0, R32(%r10)
+	mov	%rax, %r8
+	mov	%rdx, %rbx
+	mov	8(up), %rax
+	lea	(up,n,8), up
+	neg	n
+	jmp	L(L0)
+
+L(b1):	cmp	$1, n
+	jz	L(n1)
+	mov	%rax, %r9
+	mov	8(up), %rax
+	mov	%rdx, %r8
+	mov	$0, R32(%rbx)
+	lea	(up,n,8), up
+	neg	n
+	inc	n
+	jmp	L(L1)
+
+L(b2):	mov	$0, R32(%rbx)
+	mov	%rax, %r10
+	mov	%rdx, %r9
+	mov	8(up), %rax
+	mov	$0, R32(%r8)
+	lea	(up,n,8), up
+	neg	n
+	add	$2, n
+	jns	L(end)
+
+	ALIGN(32)
+L(top):	mul	v0
+	ADDSUB	%r10, (rp,n,8)
+	adc	%rax, %r9
+	mov	(up,n,8), %rax
+	adc	%rdx, %r8
+L(L1):	mul	v0
+	mov	$0, R32(%r10)
+	ADDSUB	%r9, 8(rp,n,8)
+	adc	%rax, %r8
+	adc	%rdx, %rbx
+	mov	8(up,n,8), %rax
+L(L0):	mul	v0
+	ADDSUB	%r8, 16(rp,n,8)
+	mov	$0, R32(%r8)
+	adc	%rax, %rbx
+	mov	$0, R32(%r9)
+	mov	16(up,n,8), %rax
+	adc	%rdx, %r10
+L(L3):	mul	v0
+	ADDSUB	%rbx, 24(rp,n,8)
+	mov	$0, R32(%rbx)
+	adc	%rax, %r10
+	adc	%rdx, %r9
+	mov	24(up,n,8), %rax
+	add	$4, n
+	js	L(top)
+
+L(end):	mul	v0
+	ADDSUB	%r10, (rp)
+	adc	%r9, %rax
+	adc	%r8, %rdx
+L(n1):	ADDSUB	%rax, 8(rp)
+	adc	$0, %rdx
+	mov	%rdx, %rax
+
+	pop	%rbx
+IFDOS(``pop	%rdi		'')
+IFDOS(``pop	%rsi		'')
+	ret
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86_64/bd1/com.asm b/third_party/gmp/mpn/x86_64/bd1/com.asm
new file mode 100644
index 0000000..43f3561
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/bd1/com.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_com optimised for AMD bd1.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_com)
+include_mpn(`x86_64/fastsse/com-palignr.asm')
diff --git a/third_party/gmp/mpn/x86_64/bd1/copyd.asm b/third_party/gmp/mpn/x86_64/bd1/copyd.asm
new file mode 100644
index 0000000..675cdc3
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/bd1/copyd.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_copyd optimised for AMD bd1.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_copyd)
+include_mpn(`x86_64/fastsse/copyd-palignr.asm')
diff --git a/third_party/gmp/mpn/x86_64/bd1/copyi.asm b/third_party/gmp/mpn/x86_64/bd1/copyi.asm
new file mode 100644
index 0000000..ceef036
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/bd1/copyi.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_copyi optimised for AMD bd1.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_copyi)
+include_mpn(`x86_64/fastsse/copyi-palignr.asm')
diff --git a/third_party/gmp/mpn/x86_64/bd1/gcd_11.asm b/third_party/gmp/mpn/x86_64/bd1/gcd_11.asm
new file mode 100644
index 0000000..4723093
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/bd1/gcd_11.asm
@@ -0,0 +1,37 @@
+dnl  AMD64 mpn_gcd_11.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_gcd_11)
+include_mpn(`x86_64/core2/gcd_11.asm')
diff --git a/third_party/gmp/mpn/x86_64/bd1/gmp-mparam.h b/third_party/gmp/mpn/x86_64/bd1/gmp-mparam.h
new file mode 100644
index 0000000..210f382
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/bd1/gmp-mparam.h
@@ -0,0 +1,265 @@
+/* AMD bd1 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+/* 3600-3800 MHz Bulldozer Zambezi */
+/* FFT tuning limit = 464,627,200 */
+/* Generated by tuneup.c, 2019-10-20, gcc 8.3 */
+
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          5
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          3
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        31
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD         0  /* never mpn_mod_1s_2p */
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     12
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1_NORM_THRESHOLD              2
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           27
+
+#define DIV_1_VS_MUL_1_PERCENT             275
+
+#define MUL_TOOM22_THRESHOLD                20
+#define MUL_TOOM33_THRESHOLD                57
+#define MUL_TOOM44_THRESHOLD               161
+#define MUL_TOOM6H_THRESHOLD               226
+#define MUL_TOOM8H_THRESHOLD               339
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      61
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     108
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     105
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     113
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD      91
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 24
+#define SQR_TOOM3_THRESHOLD                 85
+#define SQR_TOOM4_THRESHOLD                234
+#define SQR_TOOM6_THRESHOLD                286
+#define SQR_TOOM8_THRESHOLD                466
+
+#define MULMID_TOOM42_THRESHOLD             20
+
+#define MULMOD_BNM1_THRESHOLD               12
+#define SQRMOD_BNM1_THRESHOLD               15
+
+#define MUL_FFT_MODF_THRESHOLD             412  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    412, 5}, {     19, 6}, {     10, 5}, {     21, 6}, \
+    {     11, 5}, {     23, 6}, {     25, 7}, {     13, 6}, \
+    {     28, 7}, {     25, 8}, {     13, 7}, {     28, 8}, \
+    {     15, 7}, {     32, 8}, {     17, 7}, {     35, 8}, \
+    {     19, 7}, {     39, 8}, {     27, 9}, {     15, 8}, \
+    {     35, 9}, {     19, 8}, {     41, 9}, {     23, 8}, \
+    {     47, 9}, {     27,10}, {     15, 9}, {     39,10}, \
+    {     23, 9}, {     55,11}, {     15,10}, {     31, 9}, \
+    {     71,10}, {     39, 9}, {     83,10}, {     47, 9}, \
+    {     99,10}, {     55,11}, {     31,10}, {     79,11}, \
+    {     47,10}, {    103,12}, {     31,11}, {     63, 7}, \
+    {   1023, 8}, {    543, 9}, {    303,10}, {    167,11}, \
+    {     95,10}, {    191,12}, {     63,11}, {    127,10}, \
+    {    255,11}, {    143,10}, {    287,11}, {    159,12}, \
+    {     95,11}, {    191,13}, {     63,12}, {    127,11}, \
+    {    255,10}, {    511,11}, {    271,10}, {    543,11}, \
+    {    287,12}, {    159,11}, {    319,10}, {    639,11}, \
+    {    351,12}, {    191,11}, {    383,10}, {    767,12}, \
+    {    223,11}, {    447,13}, {    127,12}, {    255,11}, \
+    {    511,10}, {   1023,11}, {    543,12}, {    287,11}, \
+    {    575,10}, {   1151,11}, {    607,12}, {    319,11}, \
+    {    639,10}, {   1279,11}, {    671,12}, {    351,13}, \
+    {    191,12}, {    383,11}, {    767,12}, {    415,11}, \
+    {    831,12}, {    447,14}, {    127,13}, {    255,12}, \
+    {    511,11}, {   1023,12}, {    543,11}, {   1087,10}, \
+    {   2175,12}, {    575,11}, {   1151,12}, {    607,13}, \
+    {    319,12}, {    639,11}, {   1279,12}, {    671,11}, \
+    {   1343,10}, {   2687,12}, {    703,11}, {   1407,13}, \
+    {    383,12}, {    767,11}, {   1535,12}, {    799,11}, \
+    {   1599,12}, {    831,13}, {    447,12}, {    895,14}, \
+    {    255,13}, {    511,12}, {   1023,11}, {   2047,12}, \
+    {   1087,11}, {   2175,13}, {    575,12}, {   1215,11}, \
+    {   2431,13}, {    639,12}, {   1343,11}, {   2687,13}, \
+    {    703,12}, {   1407,14}, {    383,13}, {    767,12}, \
+    {   1599,13}, {    831,12}, {   1727,11}, {   3455,13}, \
+    {    895,15}, {    255,14}, {    511,13}, {   1023,12}, \
+    {   2047,13}, {   1087,12}, {   2175,13}, {   1215,12}, \
+    {   2431,11}, {   4863,14}, {    639,13}, {   1343,12}, \
+    {   2687,13}, {   1471,12}, {   2943,11}, {   5887,14}, \
+    {    767,13}, {   1599,12}, {   3199,13}, {   1727,12}, \
+    {   3455,14}, {    895,13}, {   1919,15}, {    511,14}, \
+    {   1023,13}, {   2175,14}, {   1151,13}, {   2431,12}, \
+    {   4863,14}, {   1279,13}, {   2687,14}, {   1407,13}, \
+    {   2815,12}, {   5631,13}, {   2943,12}, {   5887,15}, \
+    {    767,14}, {   1535,13}, {   3199,14}, {   1663,13}, \
+    {   3455,12}, {   6911,14}, {   1791,13}, {   3583,14}, \
+    {   1919,13}, {   3839,16}, {    511,15}, {   1023,14}, \
+    {   2175,13}, {   4479,14}, {   2431,13}, {   4863,15}, \
+    {   1279,14}, {   2943,13}, {   5887,12}, {  11775,15}, \
+    {   1535,14}, {   3455,13}, {   6911,15}, {   1791,14}, \
+    {   3839,13}, {   7679,16}, {   1023,15}, {   2047,14}, \
+    {   4479,15}, {   2303,14}, {   4863,15}, {   2559,14}, \
+    {   5247,15}, {   2815,14}, {   5887,13}, {  11775,16}, \
+    {   1535,15}, {   3327,14}, {   6911,15}, {   3839,14}, \
+    {   7679,13}, {  15359,17}, {   1023,16}, {   2047,15}, \
+    {   4351,14}, {   8959,15}, {   4863,16}, {   2559,15}, \
+    {   5887,14}, {  11775,16}, {   3071,15}, {   6911,16}, \
+    {   3583,15}, {   7679,14}, {  15359,15}, {   7935,17}, \
+    {   2047,16}, {   4095,15}, {   8959,16}, {   4607,15}, \
+    {   9983,14}, {  19967,16}, {   5119,15}, {  10239,16}, \
+    {   5631,15}, {  11775,17}, {   3071,16}, {  65536,17}, \
+    { 131072,18}, { 262144,19}, { 524288,20}, {1048576,21}, \
+    {2097152,22}, {4194304,23}, {8388608,24} }
+#define MUL_FFT_TABLE3_SIZE 251
+#define MUL_FFT_THRESHOLD                 4544
+
+#define SQR_FFT_MODF_THRESHOLD             364  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    364, 5}, {     19, 6}, {     10, 5}, {     21, 6}, \
+    {     11, 5}, {     23, 6}, {     12, 5}, {     25, 6}, \
+    {     25, 7}, {     13, 6}, {     27, 7}, {     25, 8}, \
+    {     13, 7}, {     28, 8}, {     15, 7}, {     31, 8}, \
+    {     17, 7}, {     35, 8}, {     19, 7}, {     39, 8}, \
+    {     27, 9}, {     15, 8}, {     35, 9}, {     19, 8}, \
+    {     41, 9}, {     23, 8}, {     47, 9}, {     27,10}, \
+    {     15, 9}, {     39,10}, {     23, 9}, {     51,11}, \
+    {     15,10}, {     31, 9}, {     67,10}, {     39, 9}, \
+    {     79,10}, {     47,11}, {     31,10}, {     79,11}, \
+    {     47,10}, {     95,12}, {     31,11}, {     63,10}, \
+    {    135,11}, {     79,10}, {    159,11}, {     95, 7}, \
+    {   1535, 8}, {    799, 7}, {   1599, 8}, {    831, 9}, \
+    {    447,10}, {    239,11}, {    127,10}, {    255,11}, \
+    {    143,10}, {    303,11}, {    159,12}, {     95,11}, \
+    {    191,10}, {    383,13}, {     63,12}, {    127,11}, \
+    {    255,10}, {    511,11}, {    303,12}, {    159,11}, \
+    {    351,12}, {    191,11}, {    383,10}, {    767,11}, \
+    {    415,12}, {    223,11}, {    447,13}, {    127,12}, \
+    {    255,11}, {    511,10}, {   1023,12}, {    287,11}, \
+    {    575,10}, {   1151,11}, {    607,12}, {    319,11}, \
+    {    639,10}, {   1279,11}, {    671,12}, {    351,13}, \
+    {    191,12}, {    383,11}, {    767,10}, {   1535,12}, \
+    {    415,11}, {    831,12}, {    447,14}, {    127,13}, \
+    {    255,12}, {    511,11}, {   1023,12}, {    543,11}, \
+    {   1087,10}, {   2175,12}, {    575,11}, {   1151,12}, \
+    {    607,13}, {    319,12}, {    639,11}, {   1279,12}, \
+    {    671,11}, {   1343,12}, {    703,11}, {   1407,12}, \
+    {    735,13}, {    383,12}, {    767,11}, {   1535,12}, \
+    {    799,11}, {   1599,12}, {    831,13}, {    447,12}, \
+    {    895,14}, {    255,13}, {    511,12}, {   1023,11}, \
+    {   2047,12}, {   1087,11}, {   2175,13}, {    575,12}, \
+    {   1151,11}, {   2303,12}, {   1215,11}, {   2431,13}, \
+    {    639,12}, {   1343,13}, {    703,12}, {   1407,14}, \
+    {    383,13}, {    767,12}, {   1599,11}, {   3199,13}, \
+    {    831,12}, {   1727,11}, {   3455,13}, {    895,15}, \
+    {    255,14}, {    511,13}, {   1023,12}, {   2047,13}, \
+    {   1087,12}, {   2175,13}, {   1151,12}, {   2303,13}, \
+    {   1215,12}, {   2431,14}, {    639,13}, {   1343,12}, \
+    {   2687,13}, {   1471,12}, {   2943,11}, {   5887,14}, \
+    {    767,13}, {   1599,12}, {   3199,13}, {   1727,12}, \
+    {   3455,11}, {   6911,14}, {    895,13}, {   1791,12}, \
+    {   3583,13}, {   1919,12}, {   3839,15}, {    511,14}, \
+    {   1023,13}, {   2175,14}, {   1151,13}, {   2431,12}, \
+    {   4863,14}, {   1279,13}, {   2687,14}, {   1407,13}, \
+    {   2943,12}, {   5887,11}, {  11775,15}, {    767,14}, \
+    {   1535,13}, {   3199,14}, {   1663,13}, {   3455,12}, \
+    {   6911,14}, {   1791,13}, {   3583,14}, {   1919,13}, \
+    {   3839,16}, {    511,15}, {   1023,14}, {   2175,13}, \
+    {   4351,12}, {   8703,13}, {   4479,12}, {   8959,14}, \
+    {   2303,13}, {   4607,14}, {   2431,13}, {   4863,15}, \
+    {   1279,14}, {   2815,13}, {   5631,14}, {   2943,13}, \
+    {   5887,12}, {  11775,15}, {   1535,14}, {   3455,13}, \
+    {   6911,15}, {   1791,14}, {   3839,13}, {   7679,16}, \
+    {   1023,15}, {   2047,14}, {   4351,13}, {   8703,14}, \
+    {   4479,13}, {   8959,15}, {   2303,14}, {   4991,13}, \
+    {   9983,15}, {   2559,14}, {   5119,15}, {   2815,14}, \
+    {   5887,13}, {  11775,16}, {   1535,15}, {   3071,14}, \
+    {   6143,15}, {   3327,14}, {   6911,15}, {   3839,14}, \
+    {   7679,13}, {  15359,17}, {   1023,16}, {   2047,15}, \
+    {   4095,14}, {   8191,15}, {   4351,14}, {   8959,15}, \
+    {   4863,14}, {   9983,16}, {   2559,15}, {   5887,14}, \
+    {  11775,16}, {   3071,15}, {   6911,16}, {   3583,15}, \
+    {   7679,14}, {  15359,15}, {   7935,14}, {  15871,17}, \
+    {   2047,16}, {   4095,15}, {   8959,16}, {   4607,15}, \
+    {   9983,14}, {  19967,16}, {   5119,15}, {  10239,16}, \
+    {   5631,15}, {  11775,17}, {   3071,16}, {  65536,17}, \
+    { 131072,18}, { 262144,19}, { 524288,20}, {1048576,21}, \
+    {2097152,22}, {4194304,23}, {8388608,24} }
+#define SQR_FFT_TABLE3_SIZE 275
+#define SQR_FFT_THRESHOLD                 3264
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  23
+#define MULLO_MUL_N_THRESHOLD             8907
+#define SQRLO_BASECASE_THRESHOLD             9
+#define SQRLO_DC_THRESHOLD                   0  /* never mpn_sqrlo_basecase */
+#define SQRLO_SQR_THRESHOLD               6440
+
+#define DC_DIV_QR_THRESHOLD                 52
+#define DC_DIVAPPR_Q_THRESHOLD             167
+#define DC_BDIV_QR_THRESHOLD                48
+#define DC_BDIV_Q_THRESHOLD                 93
+
+#define INV_MULMOD_BNM1_THRESHOLD           38
+#define INV_NEWTON_THRESHOLD               197
+#define INV_APPR_THRESHOLD                 179
+
+#define BINV_NEWTON_THRESHOLD              230
+#define REDC_1_TO_REDC_2_THRESHOLD          32
+#define REDC_2_TO_REDC_N_THRESHOLD          55
+
+#define MU_DIV_QR_THRESHOLD               1387
+#define MU_DIVAPPR_Q_THRESHOLD            1387
+#define MUPI_DIV_QR_THRESHOLD               92
+#define MU_BDIV_QR_THRESHOLD              1142
+#define MU_BDIV_Q_THRESHOLD               1334
+
+#define POWM_SEC_TABLE  1,22,194,434,452
+
+#define GET_STR_DC_THRESHOLD                13
+#define GET_STR_PRECOMPUTE_THRESHOLD        20
+#define SET_STR_DC_THRESHOLD               438
+#define SET_STR_PRECOMPUTE_THRESHOLD      1254
+
+#define FAC_DSC_THRESHOLD                  189
+#define FAC_ODD_THRESHOLD                   26
+
+#define MATRIX22_STRASSEN_THRESHOLD         14
+#define HGCD2_DIV1_METHOD                    3  /* 2.31% faster than 4 */
+#define HGCD_THRESHOLD                     104
+#define HGCD_APPR_THRESHOLD                 52
+#define HGCD_REDUCE_THRESHOLD             2681
+#define GCD_DC_THRESHOLD                   465
+#define GCDEXT_DC_THRESHOLD                283
+#define JACOBI_BASE_METHOD                   4  /* 5.81% faster than 1 */
+
+/* Tuneup completed successfully, took 554602 seconds */
diff --git a/third_party/gmp/mpn/x86_64/bd1/hamdist.asm b/third_party/gmp/mpn/x86_64/bd1/hamdist.asm
new file mode 100644
index 0000000..29e78a3
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/bd1/hamdist.asm
@@ -0,0 +1,206 @@
+dnl  AMD64 SSSE3/XOP mpn_hamdist -- hamming distance.
+
+dnl  Copyright 2010-2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+C		    cycles/limb	  good for cpu?
+C AMD K8,K9		n/a
+C AMD K10		n/a
+C AMD bd1	     1.51-2.0		y
+C AMD bd2	     1.50-1.9		y
+C AMD bd3		 ?
+C AMD bd4		 ?
+C AMD zen		n/a
+C AMD bobcat		n/a
+C AMD jaguar		n/a
+C Intel P4		n/a
+C Intel PNR		n/a
+C Intel NHM		n/a
+C Intel SBR		n/a
+C Intel IBR		n/a
+C Intel HWL		n/a
+C Intel BWL		n/a
+C Intel SKL		n/a
+C Intel atom		n/a
+C Intel SLM		n/a
+C VIA nano		n/a
+
+C TODO
+C  * We need to use .byte for vpshlb, vpperm, vphaddubq, and all popcnt if we
+C    intend to support old systems.
+
+C We use vpshlb and vpperm below, which are XOP extensions to AVX.  Some
+C systems, e.g., NetBSD, set OSXSAVE but nevertheless trigger SIGILL for AVX.
+C We fall back to the core2 code.
+ifdef(`GMP_AVX_NOT_REALLY_AVAILABLE',`
+MULFUNC_PROLOGUE(mpn_hamdist)
+include_mpn(`x86_64/core2/hamdist.asm')
+',`
+
+define(`up',		`%rdi')
+define(`vp',		`%rsi')
+define(`n',		`%rdx')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_hamdist)
+	FUNC_ENTRY(3)
+	cmp	$5, n
+	jl	L(sma)
+
+	lea	L(cnsts)(%rip), %r9
+
+	xor	R32(%r10), R32(%r10)
+	test	$8, R8(vp)
+	jz	L(ali)
+	mov	(up), %r8
+	xor	(vp), %r8
+	add	$8, up
+	add	$8, vp
+	dec	n
+	popcnt	%r8, %r10
+L(ali):
+
+ifdef(`PIC', `define(`OFF1',16) define(`OFF2',32) define(`OFF3',48)',
+	     `define(`OFF1',32) define(`OFF2',48) define(`OFF3',64)')
+	movdqa	OFF1`'(%r9), %xmm7	C nibble counts table
+	movdqa	OFF2`'(%r9), %xmm6	C splat shift counts
+	movdqa	OFF3`'(%r9), %xmm5	C masks
+	pxor	%xmm4, %xmm4
+	pxor	%xmm8, %xmm8		C grand total count
+
+	mov	R32(n), R32(%rax)
+	and	$6, R32(%rax)
+	lea	-64(up,%rax,8), up
+	lea	-64(vp,%rax,8), vp
+ifdef(`PIC',`
+	movslq	(%r9,%rax,2), %r11
+	add	%r9, %r11
+	jmp	*%r11
+',`
+	jmp	*(%r9,%rax,4)
+')
+
+L(0):	add	$64, up
+	add	$64, vp
+	sub	$2, n
+
+	ALIGN(32)
+L(top):	lddqu	(up), %xmm0
+	pxor	(vp), %xmm0
+	.byte	0x8f,0xe9,0x48,0x94,0xc8	C vpshlb %xmm6, %xmm0, %xmm1
+	pand	%xmm5, %xmm0
+	pand	%xmm5, %xmm1
+	.byte	0x8f,0xe8,0x40,0xa3,0xd7,0x00	C vpperm %xmm0,%xmm7,%xmm7,%xmm2
+	.byte	0x8f,0xe8,0x40,0xa3,0xdf,0x10	C vpperm %xmm1,%xmm7,%xmm7,%xmm3
+	paddb	%xmm2, %xmm3
+	paddb	%xmm3, %xmm4
+L(6):	lddqu	16(up), %xmm0
+	pxor	16(vp), %xmm0
+	.byte	0x8f,0xe9,0x48,0x94,0xc8	C vpshlb %xmm6, %xmm0, %xmm1
+	pand	%xmm5, %xmm0
+	pand	%xmm5, %xmm1
+	.byte	0x8f,0xe8,0x40,0xa3,0xd7,0x00	C vpperm %xmm0,%xmm7,%xmm7,%xmm2
+	.byte	0x8f,0xe8,0x40,0xa3,0xdf,0x10	C vpperm %xmm1,%xmm7,%xmm7,%xmm3
+	paddb	%xmm2, %xmm3
+	paddb	%xmm3, %xmm4
+L(4):	lddqu	32(up), %xmm0
+	pxor	32(vp), %xmm0
+	.byte	0x8f,0xe9,0x48,0x94,0xc8	C vpshlb %xmm6, %xmm0, %xmm1
+	pand	%xmm5, %xmm0
+	pand	%xmm5, %xmm1
+	.byte	0x8f,0xe8,0x40,0xa3,0xd7,0x00	C vpperm %xmm0,%xmm7,%xmm7,%xmm2
+	.byte	0x8f,0xe9,0x78,0xd3,0xc4	C vphaddubq %xmm4, %xmm0
+	.byte	0x8f,0xe8,0x40,0xa3,0xe7,0x10	C vpperm %xmm1,%xmm7,%xmm7,%xmm4
+	paddb	%xmm2, %xmm3
+	paddb	%xmm2, %xmm4
+	paddq	%xmm0, %xmm8		C sum to 2 x 64-bit counts
+L(2):	mov	48(up), %r8
+	mov	56(up), %r9
+	add	$64, up
+	xor	48(vp), %r8
+	xor	56(vp), %r9
+	add	$64, vp
+	popcnt	%r8, %r8
+	popcnt	%r9, %r9
+	add	%r8, %r10
+	add	%r9, %r10
+	sub	$8, n
+	jg	L(top)
+
+	test	$1, R8(n)
+	jz	L(x)
+	mov	(up), %r8
+	xor	(vp), %r8
+	popcnt	%r8, %r8
+	add	%r8, %r10
+L(x):	.byte	0x8f,0xe9,0x78,0xd3,0xc4	C vphaddubq %xmm4, %xmm0
+	paddq	%xmm0, %xmm8
+	pshufd	$14, %xmm8, %xmm0
+	paddq	%xmm8, %xmm0
+	movq	%xmm0, %rax
+	add	%r10, %rax
+	FUNC_EXIT()
+	ret
+
+L(sma):	mov	(up), %r8
+	xor	(vp), %r8
+	popcnt	%r8, %rax
+	dec	n
+	jz	L(ed)
+L(tp):	mov	8(up), %r8
+	add	$8, up
+	xor	8(vp), %r8
+	add	$8, vp
+	popcnt	%r8, %r8
+	add	%r8, %rax
+	dec	n
+	jnz	L(tp)
+L(ed):	FUNC_EXIT()
+	ret
+EPILOGUE()
+DEF_OBJECT(L(cnsts),16,`JUMPTABSECT')
+	JMPENT(	L(0), L(cnsts))
+	JMPENT(	L(2), L(cnsts))
+	JMPENT(	L(4), L(cnsts))
+	JMPENT(	L(6), L(cnsts))
+	.byte	0x00,0x01,0x01,0x02,0x01,0x02,0x02,0x03
+	.byte	0x01,0x02,0x02,0x03,0x02,0x03,0x03,0x04
+	.byte	-4,-4,-4,-4,-4,-4,-4,-4
+	.byte	-4,-4,-4,-4,-4,-4,-4,-4
+	.byte	0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f
+	.byte	0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f
+END_OBJECT(L(cnsts))
+')
diff --git a/third_party/gmp/mpn/x86_64/bd1/mul_1.asm b/third_party/gmp/mpn/x86_64/bd1/mul_1.asm
new file mode 100644
index 0000000..2fb097f
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/bd1/mul_1.asm
@@ -0,0 +1,193 @@
+dnl  AMD64 mpn_mul_1 optimised for AMD Bulldozer.
+
+dnl  Copyright 2003-2005, 2007, 2008, 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9      3.65
+C AMD K10        3.30    3.68
+C AMD bull       4.04    4.29
+C AMD pile       4.33
+C AMD steam
+C AMD excavator
+C AMD bobcat     5.73
+C AMD jaguar     5.87
+C Intel P4      12.5
+C Intel core2    4.38
+C Intel NHM      4.28
+C Intel SBR      2.69
+C Intel IBR      2.55
+C Intel HWL      2.41
+C Intel BWL      2.49
+C Intel SKL      2.50
+C Intel atom    20.3
+C Intel SLM      7.8
+C VIA nano       4.25
+
+C The loop of this code is the result of running a code generation and
+C optimisation tool suite written by David Harvey and Torbjorn Granlund.
+
+C TODO
+C  * Move loop code into feed-in blocks, to save insn for zeroing regs.
+
+define(`rp',      `%rdi')   C rcx
+define(`up',      `%rsi')   C rdx
+define(`n_param', `%rdx')   C r8
+define(`v0',      `%rcx')   C r9
+
+define(`n',       `%rbx')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+IFDOS(`	define(`up', ``%rsi'')	') dnl
+IFDOS(`	define(`rp', ``%rcx'')	') dnl
+IFDOS(`	define(`v0', ``%r9'')	') dnl
+IFDOS(`	define(`r9', ``rdi'')	') dnl
+IFDOS(`	define(`n',  ``%r8'')	') dnl
+IFDOS(`	define(`r8', ``rbx'')	') dnl
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_mul_1c)
+IFDOS(``push	%rsi		'')
+IFDOS(``push	%rdi		'')
+IFDOS(``mov	%rdx, %rsi	'')
+
+	mov	(up), %rax		C read first u limb early
+	push	%rbx
+IFSTD(`	mov	n_param, %r11	')	C move away n from rdx, mul uses it
+IFDOS(`	mov	n, %r11		')
+	mul	v0
+
+IFSTD(` add	%r8, %rax	')
+IFDOS(` add	64(%rsp), %rax	')	C 40 + 3*8  (3 push insns)
+	adc	$0, %rdx
+	jmp	L(common)
+
+EPILOGUE()
+
+	ALIGN(16)
+PROLOGUE(mpn_mul_1)
+IFDOS(``push	%rsi		'')
+IFDOS(``push	%rdi		'')
+IFDOS(``mov	%rdx, %rsi	'')
+
+	mov	(up), %rax		C read first u limb early
+	push	%rbx
+IFSTD(`	mov	n_param, %r11	')	C move away n from rdx, mul uses it
+IFDOS(`	mov	n, %r11		')
+	mul	v0
+
+L(common):
+IFSTD(`	mov	%r11, n		')
+
+	and	$3, R32(%r11)
+	lea	-16(rp,n,8), rp
+	jz	L(b0)
+	cmp	$2, R32(%r11)
+	jb	L(b1)
+	jz	L(b2)
+
+L(b3):	mov	%rax, %r10
+	mov	%rdx, %r11
+	mov	8(up), %rax
+	mul	v0
+	lea	(up,n,8), up
+	not	n
+	jmp	L(L3)
+
+L(b0):	mov	%rax, %r9
+	mov	%rdx, %r10
+	mov	8(up), %rax
+	lea	(up,n,8), up
+	neg	n
+	jmp	L(L0)
+
+L(b1):	mov	%rax, %r8
+	cmp	$1, n
+	jz	L(n1)
+	mov	%rdx, %r9
+	lea	(up,n,8), up
+	neg	n
+	mov	%r8, 16(rp,n,8)
+	inc	n
+	jmp	L(L1)
+
+L(b2):	mov	%rax, %r11
+	mov	%rdx, %r8
+	mov	8(up), %rax
+	lea	(up,n,8), up
+	neg	n
+	add	$2, n
+	jns	L(end)
+
+	ALIGN(16)
+L(top):	mul	v0
+	mov	%rdx, %r9
+	add	%rax, %r8
+	adc	$0, %r9
+	mov	%r8, 8(rp,n,8)
+	mov	%r11, (rp,n,8)
+L(L1):	mov	(up,n,8), %rax
+	mul	v0
+	add	%rax, %r9
+	mov	%rdx, %r10
+	mov	8(up,n,8), %rax
+	adc	$0, %r10
+L(L0):	mul	v0
+	add	%rax, %r10
+	mov	%rdx, %r11
+	mov	16(up,n,8), %rax
+	adc	$0, %r11
+	mul	v0
+	mov	%r9, 16(rp,n,8)
+L(L3):	add	%rax, %r11
+	mov	%r10, 24(rp,n,8)
+	mov	%rdx, %r8
+	adc	$0, %r8
+	add	$4, n
+	mov	-8(up,n,8), %rax
+	js	L(top)
+
+L(end):	mul	v0
+	add	%rax, %r8
+	adc	$0, %rdx
+	mov	%r11, (rp)
+L(n1):	mov	%r8, 8(rp)
+	mov	%rdx, %rax
+
+	pop	%rbx
+IFDOS(``pop	%rdi		'')
+IFDOS(``pop	%rsi		'')
+	ret
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86_64/bd1/mul_2.asm b/third_party/gmp/mpn/x86_64/bd1/mul_2.asm
new file mode 100644
index 0000000..85fa7aa
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/bd1/mul_2.asm
@@ -0,0 +1,195 @@
+dnl  AMD64 mpn_mul_2 optimised for AMD Bulldozer.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2008, 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 6.78
+C AMD K10	 6.78
+C AMD bd1	 8.39	 8.65
+C AMD bd2	 8.47
+C AMD bd3
+C AMD bd4
+C AMD zen
+C AMD bt1	12.1
+C AMD bt2	11.5
+C Intel P4	24.0
+C Intel PNR	 8.14
+C Intel NHM	 7.78
+C Intel SBR	 6.34
+C Intel IBR	 6.15
+C Intel HWL	 6.04
+C Intel BWL	 4.33
+C Intel SKL	 4.41
+C Intel atom	39.5
+C Intel SLM	27.8
+C VIA nano
+
+C The loop of this code is the result of running a code generation and
+C optimisation tool suite written by David Harvey and Torbjorn Granlund.
+
+define(`rp',      `%rdi')   C rcx
+define(`up',      `%rsi')   C rdx
+define(`n_param', `%rdx')   C r8
+define(`vp',      `%rcx')   C r9
+
+define(`v0', `%r8')
+define(`v1', `%r9')
+define(`w0', `%rbx')
+define(`w1', `%rcx')
+define(`w2', `%rbp')
+define(`w3', `%r10')
+define(`n',  `%r11')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_mul_2)
+	FUNC_ENTRY(4)
+	push	%rbx
+	push	%rbp
+
+	mov	(up), %rax
+
+	mov	(vp), v0
+	mov	8(vp), v1
+
+	lea	(up,n_param,8), up
+	lea	(rp,n_param,8), rp
+
+	mov	n_param, n
+	mul	v0
+	neg	n
+
+	test	$1, R8(n)
+	jnz	L(bx1)
+
+L(bx0):	test	$2, R8(n)
+	jnz	L(b10)
+
+L(b00):	mov	%rax, w0
+	mov	%rdx, w1
+	xor	R32(w2), R32(w2)
+	mov	(up,n,8), %rax
+	jmp	L(lo0)
+
+L(b10):	mov	%rax, w2
+	mov	%rdx, w3
+	mov	(up,n,8), %rax
+	xor	R32(w0), R32(w0)
+	mul	v1
+	add	$-2, n
+	jmp	L(lo2)
+
+L(bx1):	test	$2, R8(n)
+	jz	L(b11)
+
+L(b01):	mov	%rax, w3
+	mov	%rdx, w0
+	mov	(up,n,8), %rax
+	mul	v1
+	xor	R32(w1), R32(w1)
+	inc	n
+	jmp	L(lo1)
+
+L(b11):	mov	%rax, w1
+	mov	%rdx, w2
+	mov	(up,n,8), %rax
+	xor	R32(w3), R32(w3)
+	dec	n
+	jmp	L(lo3)
+
+	ALIGN(32)
+L(top):	mov	-8(up,n,8), %rax
+	mul	v1
+	mov	w2, -16(rp,n,8)
+L(lo1):	add	%rax, w0
+	mov	w3, -8(rp,n,8)
+	adc	%rdx, w1
+	mov	(up,n,8), %rax
+	mul	v0
+	mov	$0, R32(w2)
+	add	%rax, w0
+	adc	%rdx, w1
+	adc	$0, R32(w2)
+	mov	(up,n,8), %rax
+L(lo0):	mul	v1
+	add	%rax, w1
+	adc	%rdx, w2
+	mov	8(up,n,8), %rax
+	mul	v0
+	add	%rax, w1
+	mov	w0, (rp,n,8)
+	mov	$0, R32(w3)
+	mov	8(up,n,8), %rax
+	adc	%rdx, w2
+	adc	$0, R32(w3)
+L(lo3):	mul	v1
+	add	%rax, w2
+	mov	16(up,n,8), %rax
+	adc	%rdx, w3
+	mul	v0
+	add	%rax, w2
+	mov	16(up,n,8), %rax
+	mov	$0, R32(w0)
+	adc	%rdx, w3
+	adc	$0, R32(w0)
+	mul	v1
+	mov	w1, 8(rp,n,8)
+L(lo2):	add	%rax, w3
+	adc	%rdx, w0
+	mov	24(up,n,8), %rax
+	mul	v0
+	add	%rax, w3
+	adc	%rdx, w0
+	mov	$0, R32(w1)
+	adc	$0, R32(w1)
+	add	$4, n
+	jnc	L(top)
+
+L(end):	mov	-8(up), %rax
+	mul	v1
+	mov	w2, -16(rp)
+	add	%rax, w0
+	mov	w3, -8(rp)
+	adc	%rdx, w1
+	mov	w0, (rp)
+	mov	w1, %rax
+
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/bd1/mul_basecase.asm b/third_party/gmp/mpn/x86_64/bd1/mul_basecase.asm
new file mode 100644
index 0000000..e47ba58
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/bd1/mul_basecase.asm
@@ -0,0 +1,416 @@
+dnl  AMD64 mpn_mul_basecase optimised for AMD Bulldozer and Piledriver.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2003-2005, 2007, 2008, 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C cycles/limb	mul_1		mul_2		mul_3		addmul_2
+C AMD K8,K9
+C AMD K10
+C AMD bull	~4.8		~4.55		-		~4.3
+C AMD pile	~4.6		~4.55		-		~4.55
+C AMD bobcat
+C AMD jaguar
+C Intel P4
+C Intel core
+C Intel NHM
+C Intel SBR
+C Intel IBR
+C Intel HWL
+C Intel BWL
+C Intel atom
+C VIA nano
+
+C The inner loops of this code are the result of running a code generation and
+C optimisation tool suite written by David Harvey and Torbjorn Granlund.
+
+C TODO
+C  * Merge bull-specific mul_1, if it is not slower the TOOM22 range.
+C    Alternatively, we could tweak the present code (which was loopmixed for a
+C    different CPU).
+C  * Merge faster mul_2, such as the one in the same directory as this file.
+C  * Further micro-optimise.
+
+C When playing with pointers, set this to $2 to fall back to conservative
+C indexing in wind-down code.
+define(`I',`$1')
+
+
+define(`rp',      `%rdi')
+define(`up',      `%rsi')
+define(`un_param',`%rdx')
+define(`vp',      `%rcx')
+define(`vn',      `%r8')
+
+define(`un',      `%rbx')
+
+define(`w0',	`%r10')
+define(`w1',	`%r11')
+define(`w2',	`%r12')
+define(`w3',	`%r13')
+define(`n',	`%rbp')
+define(`v0',	`%r9')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_mul_basecase)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8d	')
+	push	%rbx
+	push	%rbp
+	mov	un_param, un		C free up rdx
+	neg	un
+
+	mov	(up), %rax		C shared for mul_1 and mul_2
+	lea	(up,un_param,8), up	C point at operand end
+	lea	(rp,un_param,8), rp	C point at rp[un-1]
+
+	mov	(vp), v0		C shared for mul_1 and mul_2
+	mul	v0			C shared for mul_1 and mul_2
+
+	test	$1, R8(vn)
+	jz	L(do_mul_2)
+
+L(do_mul_1):
+	test	$1, R8(un)
+	jnz	L(m1x1)
+
+L(m1x0):mov	%rax, w0		C un = 2, 4, 6, 8, ...
+	mov	%rdx, w1
+	mov	8(up,un,8), %rax
+	test	$2, R8(un)
+	jnz	L(m110)
+
+L(m100):lea	2(un), n		C un = 4, 8, 12, ...
+	jmp	L(m1l0)
+
+L(m110):lea	(un), n			C un = 2, 6, 10, ...
+	jmp	L(m1l2)
+
+L(m1x1):mov	%rax, w1		C un = 1, 3, 5, 7, ...
+	mov	%rdx, w0
+	test	$2, R8(un)
+	jz	L(m111)
+
+L(m101):lea	3(un), n		C un = 1, 5, 9, ...
+	test	n, n
+	js	L(m1l1)
+	mov	%rax, -8(rp)
+	mov	%rdx, (rp)
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+
+L(m111):lea	1(un), n		C un = 3, 7, 11, ...
+	mov	8(up,un,8), %rax
+	jmp	L(m1l3)
+
+	ALIGN(16)
+L(m1tp):mov	%rdx, w0
+	add	%rax, w1
+L(m1l1):mov	-16(up,n,8), %rax
+	adc	$0, w0
+	mul	v0
+	add	%rax, w0
+	mov	w1, -24(rp,n,8)
+	mov	-8(up,n,8), %rax
+	mov	%rdx, w1
+	adc	$0, w1
+L(m1l0):mul	v0
+	mov	w0, -16(rp,n,8)
+	add	%rax, w1
+	mov	%rdx, w0
+	mov	(up,n,8), %rax
+	adc	$0, w0
+L(m1l3):mul	v0
+	mov	w1, -8(rp,n,8)
+	mov	%rdx, w1
+	add	%rax, w0
+	mov	8(up,n,8), %rax
+	adc	$0, w1
+L(m1l2):mul	v0
+	mov	w0, (rp,n,8)
+	add	$4, n
+	jnc	L(m1tp)
+
+L(m1ed):add	%rax, w1
+	adc	$0, %rdx
+	mov	w1, I(-8(rp),-24(rp,n,8))
+	mov	%rdx, I((rp),-16(rp,n,8))
+
+	dec	R32(vn)
+	jz	L(ret2)
+
+	lea	8(vp), vp
+	lea	8(rp), rp
+	push	%r12
+	push	%r13
+	push	%r14
+	jmp	L(do_addmul)
+
+L(do_mul_2):
+define(`v1',	`%r14')
+	push	%r12
+	push	%r13
+	push	%r14
+
+	mov	8(vp), v1
+
+	test	$1, R8(un)
+	jnz	L(m2b1)
+
+L(m2b0):lea	(un), n
+	mov	%rax, w2		C 0
+	mov	(up,un,8), %rax
+	mov	%rdx, w1		C 1
+	mul	v1
+	mov	%rax, w0		C 1
+	mov	w2, (rp,un,8)		C 0
+	mov	8(up,un,8), %rax
+	mov	%rdx, w2		C 2
+	jmp	L(m2l0)
+
+L(m2b1):lea	1(un), n
+	mov	%rax, w0		C 1
+	mov	%rdx, w3		C 2
+	mov	(up,un,8), %rax
+	mul	v1
+	mov	w0, (rp,un,8)		C 1
+	mov	%rdx, w0		C 3
+	mov	%rax, w2		C 0
+	mov	8(up,un,8), %rax
+	jmp	L(m2l1)
+
+	ALIGN(32)
+L(m2tp):add	%rax, w2		C 0
+	mov	(up,n,8), %rax
+	adc	$0, w0			C 1
+L(m2l1):mul	v0
+	add	%rax, w2		C 0
+	mov	(up,n,8), %rax
+	mov	%rdx, w1		C 1
+	adc	$0, w1			C 1
+	mul	v1
+	add	w3, w2			C 0
+	adc	$0, w1			C 1
+	add	%rax, w0		C 1
+	mov	w2, (rp,n,8)		C 0
+	mov	8(up,n,8), %rax
+	mov	%rdx, w2		C 2
+	adc	$0, w2			C 2
+L(m2l0):mul	v0
+	add	%rax, w0		C 1
+	mov	%rdx, w3		C 2
+	adc	$0, w3			C 2
+	add	w1, w0			C 1
+	adc	$0, w3			C 2
+	mov	8(up,n,8), %rax
+	mul	v1
+	add	$2, n
+	mov	w0, -8(rp,n,8)		C 1
+	mov	%rdx, w0		C 3
+	jnc	L(m2tp)
+
+L(m2ed):add	%rax, w2
+	adc	$0, %rdx
+	add	w3, w2
+	adc	$0, %rdx
+	mov	w2, I((rp),(rp,n,8))
+	mov	%rdx, I(8(rp),8(rp,n,8))
+
+	add	$-2, R32(vn)
+	jz	L(ret5)
+
+	lea	16(vp), vp
+	lea	16(rp), rp
+
+
+L(do_addmul):
+	push	%r15
+	push	vn			C save vn in new stack slot
+define(`vn',	`(%rsp)')
+define(`X0',	`%r14')
+define(`X1',	`%r15')
+define(`v1',	`%r8')
+
+L(outer):
+	mov	(vp), v0
+	mov	8(vp), v1
+
+	mov	(up,un,8), %rax
+	mul	v0
+
+	test	$1, R8(un)
+	jnz	L(bx1)
+
+L(bx0):	mov	%rax, X1
+	mov	(up,un,8), %rax
+	mov	%rdx, X0
+	mul	v1
+	test	$2, R8(un)
+	jnz	L(b10)
+
+L(b00):	lea	(un), n			C un = 4, 8, 12, ...
+	mov	(rp,un,8), w3
+	mov	%rax, w0
+	mov	8(up,un,8), %rax
+	mov	%rdx, w1
+	jmp	L(lo0)
+
+L(b10):	lea	2(un), n		C un = 2, 6, 10, ...
+	mov	(rp,un,8), w1
+	mov	%rdx, w3
+	mov	%rax, w2
+	mov	8(up,un,8), %rax
+	jmp	L(lo2)
+
+L(bx1):	mov	%rax, X0
+	mov	(up,un,8), %rax
+	mov	%rdx, X1
+	mul	v1
+	test	$2, R8(un)
+	jz	L(b11)
+
+L(b01):	lea	1(un), n		C un = 1, 5, 9, ...
+	mov	(rp,un,8), w2
+	mov	%rdx, w0
+	mov	%rax, w3
+	jmp	L(lo1)
+
+L(b11):	lea	-1(un), n		C un = 3, 7, 11, ...
+	mov	(rp,un,8), w0
+	mov	%rax, w1
+	mov	8(up,un,8), %rax
+	mov	%rdx, w2
+	jmp	L(lo3)
+
+	ALIGN(32)
+L(top):
+L(lo2):	mul	v0
+	add	w1, X1
+	mov	X1, -16(rp,n,8)
+	mov	%rdx, X1
+	adc	%rax, X0
+	adc	$0, X1
+	mov	-8(up,n,8), %rax
+	mul	v1
+	mov	-8(rp,n,8), w1
+	mov	%rdx, w0
+	add	w1, w2
+	adc	%rax, w3
+	adc	$0, w0
+L(lo1):	mov	(up,n,8), %rax
+	mul	v0
+	add	w2, X0
+	mov	X0, -8(rp,n,8)
+	mov	%rdx, X0
+	adc	%rax, X1
+	mov	(up,n,8), %rax
+	adc	$0, X0
+	mov	(rp,n,8), w2
+	mul	v1
+	add	w2, w3
+	adc	%rax, w0
+	mov	8(up,n,8), %rax
+	mov	%rdx, w1
+	adc	$0, w1
+L(lo0):	mul	v0
+	add	w3, X1
+	mov	X1, (rp,n,8)
+	adc	%rax, X0
+	mov	8(up,n,8), %rax
+	mov	%rdx, X1
+	adc	$0, X1
+	mov	8(rp,n,8), w3
+	mul	v1
+	add	w3, w0
+	adc	%rax, w1
+	mov	16(up,n,8), %rax
+	mov	%rdx, w2
+	adc	$0, w2
+L(lo3):	mul	v0
+	add	w0, X0
+	mov	X0, 8(rp,n,8)
+	mov	%rdx, X0
+	adc	%rax, X1
+	adc	$0, X0
+	mov	16(up,n,8), %rax
+	mov	16(rp,n,8), w0
+	mul	v1
+	mov	%rdx, w3
+	add	w0, w1
+	adc	%rax, w2
+	adc	$0, w3
+	mov	24(up,n,8), %rax
+	add	$4, n
+	jnc	L(top)
+
+L(end):	mul	v0
+	add	w1, X1
+	mov	X1, I(-16(rp),-16(rp,n,8))
+	mov	%rdx, X1
+	adc	%rax, X0
+	adc	$0, X1
+	mov	I(-8(up),-8(up,n,8)), %rax
+	mul	v1
+	mov	I(-8(rp),-8(rp,n,8)), w1
+	add	w1, w2
+	adc	%rax, w3
+	adc	$0, %rdx
+	add	w2, X0
+	adc	$0, X1
+	mov	X0, I(-8(rp),-8(rp,n,8))
+	add	w3, X1
+	mov	X1, I((rp),(rp,n,8))
+	adc	$0, %rdx
+	mov	%rdx, I(8(rp),8(rp,n,8))
+
+
+	addl	$-2, vn
+	lea	16(vp), vp
+	lea	16(rp), rp
+	jnz	L(outer)
+
+	pop	%rax		C deallocate vn slot
+	pop	%r15
+L(ret5):pop	%r14
+	pop	%r13
+	pop	%r12
+L(ret2):pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/bd1/popcount.asm b/third_party/gmp/mpn/x86_64/bd1/popcount.asm
new file mode 100644
index 0000000..28ce461
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/bd1/popcount.asm
@@ -0,0 +1,191 @@
+dnl  AMD64 SSSE3/XOP mpn_popcount -- population count.
+
+dnl  Copyright 2010-2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+C		    cycles/limb	  good for cpu?
+C AMD K8,K9		n/a
+C AMD K10		n/a
+C AMD bd1		 1.27		y
+C AMD bd2		 1.24		y
+C AMD bd3		 ?
+C AMD bd4		 1.22
+C AMD zen		n/a
+C AMD bobcat		n/a
+C AMD jaguar		n/a
+C Intel P4		n/a
+C Intel CNR		n/a
+C Intel PNR		n/a
+C Intel NHM		n/a
+C Intel SBR		n/a
+C Intel IBR		n/a
+C Intel HWL		n/a
+C Intel BWL		n/a
+C Intel SKL		n/a
+C Intel atom		n/a
+C Intel SLM		n/a
+C VIA nano		n/a
+
+C TODO
+C  * We need to use .byte for vpshlb, vpperm, vphaddubq, and all popcnt if we
+C    intend to support old systems.
+
+C We use vpshlb and vpperm below, which are XOP extensions to AVX.  Some
+C systems, e.g., NetBSD, set OSXSAVE but nevertheless trigger SIGILL for AVX.
+C We fall back to the core2 code.
+ifdef(`GMP_AVX_NOT_REALLY_AVAILABLE',`
+MULFUNC_PROLOGUE(mpn_popcount)
+include_mpn(`x86_64/core2/popcount.asm')
+',`
+
+define(`up',		`%rdi')
+define(`n',		`%rsi')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_popcount)
+	FUNC_ENTRY(3)
+	lea	L(cnsts)(%rip), %r9
+
+ifdef(`PIC', `define(`OFF1',32) define(`OFF2',48) define(`OFF3',64)',
+	     `define(`OFF1',64) define(`OFF2',80) define(`OFF3',96)')
+	movdqa	OFF1`'(%r9), %xmm7	C nibble counts table
+	movdqa	OFF2`'(%r9), %xmm6	C splat shift counts
+	movdqa	OFF3`'(%r9), %xmm9	C masks
+	pxor	%xmm4, %xmm4
+	pxor	%xmm5, %xmm5		C 0-reg
+	pxor	%xmm8, %xmm8		C grand total count
+
+	xor	R32(%rdx), R32(%rdx)
+
+	mov	R32(n), R32(%rax)
+	and	$7, R32(%rax)
+ifdef(`PIC',`
+	movslq	(%r9,%rax,4), %rax
+	add	%r9, %rax
+	jmp	*%rax
+',`
+	jmp	*(%r9,%rax,8)
+')
+
+L(1):	.byte	0xf3,0x48,0x0f,0xb8,0x17	C popcnt (up),%rdx
+	add	$8, up
+	dec	n
+	jnz	L(top)
+	mov	%rdx, %rax
+	FUNC_EXIT()
+	ret
+
+L(2):	add	$-48, up
+	jmp	L(e2)
+
+L(3):	.byte	0xf3,0x48,0x0f,0xb8,0x17	C popcnt (up), %rdx
+	add	$-40, up
+	jmp	L(e2)
+
+L(4):	add	$-32, up
+	jmp	L(e4)
+
+L(5):	.byte	0xf3,0x48,0x0f,0xb8,0x17	C popcnt (up), %rdx
+	add	$-24, up
+	jmp	L(e4)
+
+L(6):	add	$-16, up
+	jmp	L(e6)
+
+L(7):	.byte	0xf3,0x48,0x0f,0xb8,0x17	C popcnt (up), %rdx
+	add	$-8, up
+	jmp	L(e6)
+
+	ALIGN(32)
+L(top):	lddqu	(up), %xmm0
+	.byte	0x8f,0xe9,0x48,0x94,0xc8	C vpshlb %xmm6, %xmm0, %xmm1
+	pand	%xmm9, %xmm0
+	pand	%xmm9, %xmm1
+	.byte	0x8f,0xe8,0x40,0xa3,0xd7,0x00	C vpperm %xmm0,%xmm7,%xmm7,%xmm2
+	.byte	0x8f,0xe8,0x40,0xa3,0xdf,0x10	C vpperm %xmm1, %xmm7, %xmm7, %xmm3
+	paddb	%xmm2, %xmm3
+	paddb	%xmm3, %xmm4
+L(e6):	lddqu	16(up), %xmm0
+	.byte	0x8f,0xe9,0x48,0x94,0xc8	C vpshlb %xmm6, %xmm0, %xmm1
+	pand	%xmm9, %xmm0
+	pand	%xmm9, %xmm1
+	.byte	0x8f,0xe8,0x40,0xa3,0xd7,0x00	C vpperm %xmm0,%xmm7,%xmm7,%xmm2
+	.byte	0x8f,0xe8,0x40,0xa3,0xdf,0x10	C vpperm %xmm1,%xmm7,%xmm7,%xmm3
+	paddb	%xmm2, %xmm3
+	paddb	%xmm3, %xmm4
+L(e4):	lddqu	32(up), %xmm0
+	.byte	0x8f,0xe9,0x48,0x94,0xc8	C vpshlb %xmm6, %xmm0, %xmm1
+	pand	%xmm9, %xmm0
+	pand	%xmm9, %xmm1
+	.byte	0x8f,0xe8,0x40,0xa3,0xd7,0x00	C vpperm %xmm0, %xmm7, %xmm7, %xmm2
+	.byte	0x8f,0xe9,0x78,0xd3,0xec	C vphaddubq %xmm4, %xmm5
+	.byte	0x8f,0xe8,0x40,0xa3,0xe7,0x10	C vpperm %xmm1,%xmm7,%xmm7,%xmm4
+	paddb	%xmm2, %xmm4
+L(e2):	popcnt	48(up), %r8
+	popcnt	56(up), %r9
+	add	$64, up
+	paddq	%xmm5, %xmm8			C sum to 2 x 64-bit counts
+	add	%r8, %rdx
+	add	%r9, %rdx
+	sub	$8, n
+	jg	L(top)
+
+	.byte	0x8f,0xe9,0x78,0xd3,0xec	C vphaddubq %xmm4, %xmm5
+	paddq	%xmm5, %xmm8
+	pshufd	$14, %xmm8, %xmm0
+	paddq	%xmm8, %xmm0
+	movq	%xmm0, %rax
+	add	%rdx, %rax
+	FUNC_EXIT()
+	ret
+EPILOGUE()
+DEF_OBJECT(L(cnsts),16,`JUMPTABSECT')
+	JMPENT(	L(top), L(cnsts))
+	JMPENT(	L(1), L(cnsts))
+	JMPENT(	L(2), L(cnsts))
+	JMPENT(	L(3), L(cnsts))
+	JMPENT(	L(4), L(cnsts))
+	JMPENT(	L(5), L(cnsts))
+	JMPENT(	L(6), L(cnsts))
+	JMPENT(	L(7), L(cnsts))
+	.byte	0x00,0x01,0x01,0x02,0x01,0x02,0x02,0x03
+	.byte	0x01,0x02,0x02,0x03,0x02,0x03,0x03,0x04
+	.byte	-4,-4,-4,-4,-4,-4,-4,-4
+	.byte	-4,-4,-4,-4,-4,-4,-4,-4
+	.byte	0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f
+	.byte	0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f
+END_OBJECT(L(cnsts))
+')
diff --git a/third_party/gmp/mpn/x86_64/bd1/sec_tabselect.asm b/third_party/gmp/mpn/x86_64/bd1/sec_tabselect.asm
new file mode 100644
index 0000000..e436034
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/bd1/sec_tabselect.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_sec_tabselect.
+
+dnl  Copyright 2012, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_sec_tabselect)
+include_mpn(`x86_64/fastsse/sec_tabselect.asm')
diff --git a/third_party/gmp/mpn/x86_64/bd1/sublsh1_n.asm b/third_party/gmp/mpn/x86_64/bd1/sublsh1_n.asm
new file mode 100644
index 0000000..4ba673d
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/bd1/sublsh1_n.asm
@@ -0,0 +1,37 @@
+dnl  AMD64 mpn_sublsh1_n
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_sublsh1_n mpn_sublsh1_nc)
+include_mpn(`x86_64/atom/sublsh1_n.asm')
diff --git a/third_party/gmp/mpn/x86_64/bd2/gcd_11.asm b/third_party/gmp/mpn/x86_64/bd2/gcd_11.asm
new file mode 100644
index 0000000..b167077
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/bd2/gcd_11.asm
@@ -0,0 +1,96 @@
+dnl  AMD64 mpn_gcd_11 optimised for AMD BD2, BD3, BT2.
+
+dnl  Based on the K7 gcd_1.asm, by Kevin Ryde.  Rehacked for AMD64 by Torbjorn
+dnl  Granlund.
+
+dnl  Copyright 2000-2002, 2005, 2009, 2011, 2012, 2017, 2019 Free Software
+dnl  Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C	     cycles/bit (approx)
+C AMD K8,K9	 ?
+C AMD K10	 ?
+C AMD bd1	 5.4
+C AMD bd2	 3.72
+C AMD bd3	 ?
+C AMD bd4	 4.12
+C AMD bt1	 9.0
+C AMD bt2	 3.97
+C AMD zn1	 3.36
+C AMD zn2	 3.33
+C Intel P4	 ?
+C Intel CNR	 ?
+C Intel PNR	 ?
+C Intel NHM	 ?
+C Intel WSM	 ?
+C Intel SBR	 ?
+C Intel IBR	 ?
+C Intel HWL	 ?
+C Intel BWL	 ?
+C Intel SKL	 ?
+C Intel atom	 ?
+C Intel SLM	 ?
+C Intel GLM	 ?
+C Intel GLM+	 ?
+C VIA nano	 ?
+
+define(`u0',    `%rdi')
+define(`v0',    `%rsi')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(64)
+PROLOGUE(mpn_gcd_11)
+	FUNC_ENTRY(2)
+	mov	v0, %rdx
+	sub	u0, %rdx
+	jz	L(end)
+
+	ALIGN(16)
+L(top):	rep;bsf	%rdx, %rcx		C tzcnt!
+	mov	u0, %rax
+	sub	v0, u0			C u - v
+	cmovc	%rdx, u0		C u = |u - v|
+	cmovc	%rax, v0		C v = min(u,v)
+	shr	R8(%rcx), u0
+	mov	v0, %rdx
+	sub	u0, %rdx		C v - u
+	jnz	L(top)
+
+L(end):	mov	v0, %rax
+	C rax = result
+	C rdx = 0 for the benefit of internal gcd_22 call
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/bd2/gcd_22.asm b/third_party/gmp/mpn/x86_64/bd2/gcd_22.asm
new file mode 100644
index 0000000..a4f30ea
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/bd2/gcd_22.asm
@@ -0,0 +1,142 @@
+dnl  AMD64 mpn_gcd_22.  Assumes useless bsf, useless shrd, tzcnt, no shlx.
+
+dnl  Copyright 2019 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C	     cycles/bit
+C AMD K8,K9	12.3
+C AMD K10	 8.0
+C AMD bd1	10.0
+C AMD bd2	 7.2 
+C AMD bd3	 ?
+C AMD bd4	 6.7
+C AMD bt1	13.6
+C AMD bt2	 8.9
+C AMD zn1	 5.7
+C AMD zn2	 5.6
+C Intel P4	 ?
+C Intel CNR	 9.7
+C Intel PNR	 9.7
+C Intel NHM	 9.4
+C Intel WSM	 9.5
+C Intel SBR	10.3
+C Intel IBR	 ?
+C Intel HWL	 8.2
+C Intel BWL	 7.4
+C Intel SKL	 7.3
+C Intel atom	26.5
+C Intel SLM	17.4
+C Intel GLM	13.4
+C Intel GLM+	12.4
+C VIA nano	 ?
+
+
+define(`u1',    `%rdi')
+define(`u0',    `%rsi')
+define(`v1',    `%rdx')
+define(`v0_param', `%rcx')
+
+define(`v0',    `%rax')
+define(`cnt',   `%rcx')
+
+define(`s0',    `%r8')
+define(`s1',    `%r9')
+define(`t0',    `%r10')
+define(`t1',    `%r11')
+
+dnl ABI_SUPPORT(DOS64)	C returns mp_double_limb_t in memory
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(64)
+PROLOGUE(mpn_gcd_22)
+	FUNC_ENTRY(4)
+	mov	v0_param, v0
+
+	ALIGN(16)
+L(top):	mov	v0, t0
+	sub	u0, t0
+	jz	L(lowz)		C	jump when low limb result = 0
+	mov	v1, t1
+	sbb	u1, t1
+
+	rep;bsf	t0, cnt		C tzcnt!
+	mov	u0, s0
+	mov	u1, s1
+
+	sub	v0, u0
+	sbb	v1, u1
+
+L(bck):	cmovc	t0, u0		C u = |u - v|
+	cmovc	t1, u1		C u = |u - v|
+	cmovc	s0, v0		C v = min(u,v)
+	cmovc	s1, v1		C v = min(u,v)
+
+C Rightshift (u1,,u0) into (u1,,u0)
+L(shr):	shr	R8(cnt), u0
+	mov	u1, t1
+	shr	R8(cnt), u1
+	neg	cnt
+	shl	R8(cnt), t1
+	or	t1, u0
+
+	test	v1, v1
+	jnz	L(top)
+	test	u1, u1
+	jnz	L(top)
+
+L(gcd_11):
+	mov	v0, %rdi
+C	mov	u0, %rsi
+	TCALL(	mpn_gcd_11)
+
+L(lowz):C We come here when v0 - u0 = 0
+	C 1. If v1 - u1 = 0, then gcd is u = v.
+	C 2. Else compute gcd_21({v1,v0}, |u1-v1|)
+	mov	v1, t0
+	sub	u1, t0
+	je	L(end)
+
+	xor	t1, t1
+	rep;bsf	t0, cnt		C tzcnt!
+	mov	u0, s0
+	mov	u1, s1
+	mov	u1, u0
+	xor	u1, u1
+	sub	v1, u0
+	jmp	L(bck)
+
+L(end):	C mov	v0, %rax
+	C mov	v1, %rdx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/bd2/gmp-mparam.h b/third_party/gmp/mpn/x86_64/bd2/gmp-mparam.h
new file mode 100644
index 0000000..61573ea
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/bd2/gmp-mparam.h
@@ -0,0 +1,263 @@
+/* AMD bd2 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+/* 4000-4200 MHz Piledriver Vishera  */
+/* FFT tuning limit = 464,626,631 */
+/* Generated by tuneup.c, 2019-10-18, gcc 8.3 */
+
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          6
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          3
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        23
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        34
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     12
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1_NORM_THRESHOLD              2
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           22
+
+#define DIV_1_VS_MUL_1_PERCENT             293
+
+#define MUL_TOOM22_THRESHOLD                16
+#define MUL_TOOM33_THRESHOLD                57
+#define MUL_TOOM44_THRESHOLD               152
+#define MUL_TOOM6H_THRESHOLD               230
+#define MUL_TOOM8H_THRESHOLD               309
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      97
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     107
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     105
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     103
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     142
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 20
+#define SQR_TOOM3_THRESHOLD                 73
+#define SQR_TOOM4_THRESHOLD                200
+#define SQR_TOOM6_THRESHOLD                286
+#define SQR_TOOM8_THRESHOLD                430
+
+#define MULMID_TOOM42_THRESHOLD             20
+
+#define MULMOD_BNM1_THRESHOLD               11
+#define SQRMOD_BNM1_THRESHOLD               13
+
+#define MUL_FFT_MODF_THRESHOLD             372  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    372, 5}, {     17, 6}, {      9, 5}, {     19, 6}, \
+    {     10, 5}, {     21, 6}, {     11, 5}, {     23, 6}, \
+    {     25, 7}, {     13, 6}, {     27, 7}, {     21, 8}, \
+    {     11, 7}, {     25, 8}, {     13, 7}, {     27, 8}, \
+    {     15, 7}, {     32, 8}, {     17, 7}, {     35, 8}, \
+    {     21, 9}, {     11, 8}, {     27, 9}, {     15, 8}, \
+    {     35, 9}, {     19, 8}, {     41, 9}, {     23, 8}, \
+    {     47, 9}, {     27,10}, {     15, 9}, {     31, 8}, \
+    {     63, 9}, {     39,10}, {     23, 9}, {     55,11}, \
+    {     15,10}, {     31, 9}, {     71,10}, {     39, 9}, \
+    {     83,10}, {     47, 9}, {     95,10}, {     55,11}, \
+    {     31,10}, {     79,11}, {     47,10}, {     95,12}, \
+    {     31,11}, {     63,10}, {    135,11}, {     79, 8}, \
+    {    639, 9}, {    335,10}, {    175, 9}, {    351,10}, \
+    {    191,12}, {     63,11}, {    127,10}, {    255,11}, \
+    {    143,10}, {    287,11}, {    159,12}, {     95,11}, \
+    {    191,13}, {     63,12}, {    127,11}, {    271,10}, \
+    {    543,11}, {    287,12}, {    159,11}, {    351,12}, \
+    {    191,11}, {    383,10}, {    767,11}, {    415,12}, \
+    {    223,11}, {    447,13}, {    127,12}, {    255,11}, \
+    {    511,10}, {   1023,11}, {    543,12}, {    287,11}, \
+    {    575,12}, {    319,11}, {    639,10}, {   1279,12}, \
+    {    351,13}, {    191,12}, {    383,11}, {    767,12}, \
+    {    415,11}, {    831,10}, {   1663,12}, {    447,14}, \
+    {    127,13}, {    255,12}, {    511,11}, {   1023,12}, \
+    {    543,11}, {   1087,10}, {   2175,12}, {    575,11}, \
+    {   1151,13}, {    319,12}, {    639,11}, {   1279,12}, \
+    {    671,11}, {   1343,10}, {   2687,12}, {    703,11}, \
+    {   1407,13}, {    383,12}, {    767,11}, {   1535,12}, \
+    {    799,11}, {   1599,12}, {    831,11}, {   1663,13}, \
+    {    447,12}, {    895,14}, {    255,13}, {    511,12}, \
+    {   1087,11}, {   2175,13}, {    575,12}, {   1215,11}, \
+    {   2431,10}, {   4863,13}, {    639,12}, {   1343,11}, \
+    {   2687,13}, {    703,12}, {   1407,11}, {   2815,14}, \
+    {    383,13}, {    767,12}, {   1599,13}, {    831,12}, \
+    {   1727,11}, {   3455,13}, {    895,15}, {    255,14}, \
+    {    511,13}, {   1087,12}, {   2175,13}, {   1215,12}, \
+    {   2431,11}, {   4863,14}, {    639,13}, {   1343,12}, \
+    {   2687,13}, {   1407,12}, {   2815,13}, {   1471,12}, \
+    {   2943,11}, {   5887,14}, {    767,13}, {   1599,12}, \
+    {   3199,13}, {   1727,12}, {   3455,14}, {    895,13}, \
+    {   1791,12}, {   3583,13}, {   1919,12}, {   3839,11}, \
+    {   7679,15}, {    511,14}, {   1023,13}, {   2175,14}, \
+    {   1151,13}, {   2303,12}, {   4607,13}, {   2431,12}, \
+    {   4863,14}, {   1279,13}, {   2687,14}, {   1407,13}, \
+    {   2815,12}, {   5631,13}, {   2943,12}, {   5887,15}, \
+    {    767,14}, {   1535,13}, {   3199,14}, {   1663,13}, \
+    {   3455,12}, {   6911,14}, {   1791,13}, {   3583,14}, \
+    {   1919,13}, {   3839,12}, {   7679,16}, {    511,15}, \
+    {   1023,14}, {   2175,13}, {   4479,14}, {   2303,13}, \
+    {   4607,14}, {   2431,13}, {   4863,15}, {   1279,14}, \
+    {   2815,13}, {   5631,14}, {   2943,13}, {   5887,12}, \
+    {  11775,15}, {   1535,14}, {   3455,13}, {   6911,15}, \
+    {   1791,14}, {   3839,13}, {   7679,16}, {   1023,15}, \
+    {   2047,14}, {   4479,13}, {   8959,15}, {   2303,14}, \
+    {   4863,15}, {   2815,14}, {   5887,13}, {  11775,16}, \
+    {   1535,15}, {   3327,14}, {   6911,15}, {   3839,14}, \
+    {   7679,13}, {  15359,17}, {   1023,16}, {   2047,15}, \
+    {   4351,14}, {   8959,15}, {   4863,16}, {   2559,15}, \
+    {   5887,14}, {  11775,16}, {   3071,15}, {   6911,16}, \
+    {   3583,15}, {   7679,14}, {  15359,15}, {   7935,14}, \
+    {  15871,17}, {   2047,16}, {   4095,15}, {   8959,16}, \
+    {   4607,15}, {   9983,14}, {  19967,16}, {   5631,15}, \
+    {  11775,17}, {   3071,16}, {  65536,17}, { 131072,18}, \
+    { 262144,19}, { 524288,20}, {1048576,21}, {2097152,22}, \
+    {4194304,23}, {8388608,24} }
+#define MUL_FFT_TABLE3_SIZE 262
+#define MUL_FFT_THRESHOLD                 4544
+
+#define SQR_FFT_MODF_THRESHOLD             344  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    344, 5}, {     19, 6}, {     10, 5}, {     21, 6}, \
+    {     11, 5}, {     23, 6}, {     25, 7}, {     13, 6}, \
+    {     27, 7}, {     25, 8}, {     13, 7}, {     28, 8}, \
+    {     15, 7}, {     31, 8}, {     17, 7}, {     35, 8}, \
+    {     19, 7}, {     39, 8}, {     21, 9}, {     11, 8}, \
+    {     27, 9}, {     15, 8}, {     35, 9}, {     19, 8}, \
+    {     39, 9}, {     23, 8}, {     47, 9}, {     27,10}, \
+    {     15, 9}, {     39,10}, {     23, 9}, {     51,11}, \
+    {     15,10}, {     31, 9}, {     67,10}, {     39, 9}, \
+    {     79,10}, {     47,11}, {     31,10}, {     79,11}, \
+    {     47,10}, {     95,12}, {     31,11}, {     63,10}, \
+    {    127, 9}, {    255,10}, {    135,11}, {     79,10}, \
+    {    159,11}, {     95,10}, {    191,12}, {     63, 9}, \
+    {    511,10}, {    271,11}, {    143,10}, {    303,11}, \
+    {    159,12}, {     95,11}, {    191,13}, {     63,12}, \
+    {    127,11}, {    287,10}, {    575,11}, {    303,12}, \
+    {    159,11}, {    351,12}, {    191,11}, {    383,12}, \
+    {    223,11}, {    447,13}, {    127,12}, {    255,11}, \
+    {    511,10}, {   1023,12}, {    287,11}, {    575,10}, \
+    {   1151,11}, {    607,12}, {    319,11}, {    639,10}, \
+    {   1279,12}, {    351,13}, {    191,12}, {    383,11}, \
+    {    767,12}, {    415,11}, {    831,10}, {   1663,12}, \
+    {    447,14}, {    127,13}, {    255,12}, {    511,11}, \
+    {   1023,12}, {    543,11}, {   1087,10}, {   2175,12}, \
+    {    575,11}, {   1151,12}, {    607,13}, {    319,12}, \
+    {    639,11}, {   1279,12}, {    671,11}, {   1343,10}, \
+    {   2687,12}, {    703,11}, {   1407,13}, {    383,12}, \
+    {    767,11}, {   1535,12}, {    799,11}, {   1599,12}, \
+    {    831,11}, {   1663,13}, {    447,12}, {    895,14}, \
+    {    255,13}, {    511,12}, {   1087,11}, {   2175,13}, \
+    {    575,12}, {   1215,11}, {   2431,10}, {   4863,13}, \
+    {    639,12}, {   1343,11}, {   2687,13}, {    703,12}, \
+    {   1407,14}, {    383,13}, {    767,12}, {   1599,13}, \
+    {    831,12}, {   1727,13}, {    895,15}, {    255,14}, \
+    {    511,13}, {   1087,12}, {   2175,13}, {   1151,12}, \
+    {   2303,13}, {   1215,12}, {   2431,11}, {   4863,14}, \
+    {    639,13}, {   1343,12}, {   2687,13}, {   1407,12}, \
+    {   2815,13}, {   1471,12}, {   2943,11}, {   5887,14}, \
+    {    767,13}, {   1599,12}, {   3199,13}, {   1727,12}, \
+    {   3455,14}, {    895,13}, {   1791,12}, {   3583,13}, \
+    {   1919,12}, {   3839,15}, {    511,14}, {   1023,13}, \
+    {   2175,14}, {   1151,13}, {   2303,12}, {   4607,13}, \
+    {   2431,12}, {   4863,14}, {   1279,13}, {   2687,14}, \
+    {   1407,13}, {   2943,12}, {   5887,11}, {  11775,15}, \
+    {    767,14}, {   1535,13}, {   3199,14}, {   1663,13}, \
+    {   3455,12}, {   6911,14}, {   1791,13}, {   3583,14}, \
+    {   1919,13}, {   3839,16}, {    511,15}, {   1023,14}, \
+    {   2175,13}, {   4479,14}, {   2303,13}, {   4607,14}, \
+    {   2431,13}, {   4863,15}, {   1279,14}, {   2815,13}, \
+    {   5631,14}, {   2943,13}, {   5887,12}, {  11775,15}, \
+    {   1535,14}, {   3455,13}, {   6911,15}, {   1791,14}, \
+    {   3839,13}, {   7679,16}, {   1023,15}, {   2047,14}, \
+    {   4479,13}, {   8959,15}, {   2303,14}, {   4863,15}, \
+    {   2815,14}, {   5887,13}, {  11775,16}, {   1535,15}, \
+    {   3327,14}, {   6911,15}, {   3839,14}, {   7679,17}, \
+    {   1023,16}, {   2047,15}, {   4351,14}, {   8959,15}, \
+    {   4863,16}, {   2559,15}, {   5887,14}, {  11775,16}, \
+    {   3071,15}, {   6911,16}, {   3583,15}, {   7679,14}, \
+    {  15359,15}, {   7935,14}, {  15871,17}, {   2047,16}, \
+    {   4095,15}, {   8959,16}, {   4607,15}, {   9983,14}, \
+    {  19967,16}, {   5119,15}, {  10239,16}, {   5631,15}, \
+    {  11775,17}, {   3071,16}, {  65536,17}, { 131072,18}, \
+    { 262144,19}, { 524288,20}, {1048576,21}, {2097152,22}, \
+    {4194304,23}, {8388608,24} }
+#define SQR_FFT_TABLE3_SIZE 254
+#define SQR_FFT_THRESHOLD                 2880
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  30
+#define MULLO_MUL_N_THRESHOLD             8907
+#define SQRLO_BASECASE_THRESHOLD             8
+#define SQRLO_DC_THRESHOLD                  53
+#define SQRLO_SQR_THRESHOLD               5724
+
+#define DC_DIV_QR_THRESHOLD                 52
+#define DC_DIVAPPR_Q_THRESHOLD             159
+#define DC_BDIV_QR_THRESHOLD                44
+#define DC_BDIV_Q_THRESHOLD                 79
+
+#define INV_MULMOD_BNM1_THRESHOLD           30
+#define INV_NEWTON_THRESHOLD               172
+#define INV_APPR_THRESHOLD                 172
+
+#define BINV_NEWTON_THRESHOLD              226
+#define REDC_1_TO_REDC_2_THRESHOLD          40
+#define REDC_2_TO_REDC_N_THRESHOLD          51
+
+#define MU_DIV_QR_THRESHOLD               1308
+#define MU_DIVAPPR_Q_THRESHOLD            1258
+#define MUPI_DIV_QR_THRESHOLD               85
+#define MU_BDIV_QR_THRESHOLD              1142
+#define MU_BDIV_Q_THRESHOLD               1210
+
+#define POWM_SEC_TABLE  3,16,129,523,1297
+
+#define GET_STR_DC_THRESHOLD                13
+#define GET_STR_PRECOMPUTE_THRESHOLD        20
+#define SET_STR_DC_THRESHOLD               228
+#define SET_STR_PRECOMPUTE_THRESHOLD      1033
+
+#define FAC_DSC_THRESHOLD                  172
+#define FAC_ODD_THRESHOLD                   28
+
+#define MATRIX22_STRASSEN_THRESHOLD         19
+#define HGCD2_DIV1_METHOD                    1  /* 8.54% faster than 3 */
+#define HGCD_THRESHOLD                     108
+#define HGCD_APPR_THRESHOLD                 50
+#define HGCD_REDUCE_THRESHOLD             2681
+#define GCD_DC_THRESHOLD                   393
+#define GCDEXT_DC_THRESHOLD                278
+#define JACOBI_BASE_METHOD                   4  /* 13.69% faster than 1 */
+
+/* Tuneup completed successfully, took 463931 seconds */
diff --git a/third_party/gmp/mpn/x86_64/bd4/aorrlsh_n.asm b/third_party/gmp/mpn/x86_64/bd4/aorrlsh_n.asm
new file mode 100644
index 0000000..ff0d27b
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/bd4/aorrlsh_n.asm
@@ -0,0 +1,38 @@
+dnl  X86-64 mpn_addlsh_n and mpn_rsblsh_n.
+
+dnl  Copyright 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_addlsh_n mpn_rsblsh_n)
+include_mpn(`x86_64/zen/aorrlsh_n.asm')
diff --git a/third_party/gmp/mpn/x86_64/bd4/gcd_11.asm b/third_party/gmp/mpn/x86_64/bd4/gcd_11.asm
new file mode 100644
index 0000000..4176b85
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/bd4/gcd_11.asm
@@ -0,0 +1,96 @@
+dnl  AMD64 mpn_gcd_11 optimised for AMD BD4, ZN1.
+
+dnl  Based on the K7 gcd_1.asm, by Kevin Ryde.  Rehacked for AMD64 by Torbjorn
+dnl  Granlund.
+
+dnl  Copyright 2000-2002, 2005, 2009, 2011, 2012, 2017, 2019 Free Software
+dnl  Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C	     cycles/bit (approx)
+C AMD K8,K9	 -
+C AMD K10	 -
+C AMD bd1	 -
+C AMD bd2	 -
+C AMD bd3	 -
+C AMD bd4	 3.73
+C AMD bt1	 -
+C AMD bt2	 -
+C AMD zn1	 3.33
+C AMD zn2	 3.48
+C Intel P4	 -
+C Intel CNR	 -
+C Intel PNR	 -
+C Intel NHM	 -
+C Intel WSM	 -
+C Intel SBR	 -
+C Intel IBR	 -
+C Intel HWL	 ?
+C Intel BWL	 ?
+C Intel SKL	 ?
+C Intel atom	 -
+C Intel SLM	 -
+C Intel GLM	 -
+C Intel GLM+	 -
+C VIA nano	 -
+
+define(`u0',    `%rdi')
+define(`v0',    `%rsi')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(64)
+PROLOGUE(mpn_gcd_11)
+	FUNC_ENTRY(2)
+	mov	u0, %rax
+	mov	v0, %rdx
+	sub	u0, %rdx		C v - u
+	jz	L(end)
+
+	ALIGN(16)
+L(top):	rep;bsf	%rdx, %rcx		C tzcnt!
+	sub	v0, u0			C u - v
+	cmovc	%rdx, u0		C u = |u - v|
+	cmovc	%rax, v0		C v = min(u,v)
+	shrx(	%rcx, u0, %rax)
+	shrx(	%rcx, u0, u0)
+	mov	v0, %rdx
+	sub	%rax, %rdx		C v - u
+	jnz	L(top)
+
+L(end):	C rax = result
+	C rdx = 0 for the benefit of internal gcd_22 call
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/bd4/gcd_22.asm b/third_party/gmp/mpn/x86_64/bd4/gcd_22.asm
new file mode 100644
index 0000000..5dfd9e3
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/bd4/gcd_22.asm
@@ -0,0 +1,37 @@
+dnl  AMD64 mpn_gcd_22.
+
+dnl  Copyright 2019 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+dnl ABI_SUPPORT(DOS64)	C returns mp_double_limb_t in memory
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_gcd_22)
+include_mpn(`x86_64/coreihwl/gcd_22.asm')
diff --git a/third_party/gmp/mpn/x86_64/bd4/gmp-mparam.h b/third_party/gmp/mpn/x86_64/bd4/gmp-mparam.h
new file mode 100644
index 0000000..9d2038c
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/bd4/gmp-mparam.h
@@ -0,0 +1,266 @@
+/* AMD bd4 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+/* 3800-4200 MHz Excavator/Bristol Ridge  */
+/* FFT tuning limit = 461,179,335 */
+/* Generated by tuneup.c, 2019-10-18, gcc 8.3 */
+
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          6
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          5
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        17
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        52
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     13
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1_NORM_THRESHOLD              1
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           25
+
+#define DIV_1_VS_MUL_1_PERCENT             298
+
+#define MUL_TOOM22_THRESHOLD                16
+#define MUL_TOOM33_THRESHOLD                53
+#define MUL_TOOM44_THRESHOLD               142
+#define MUL_TOOM6H_THRESHOLD               206
+#define MUL_TOOM8H_THRESHOLD               292
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      83
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     102
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD      97
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD      98
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD      82
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 20
+#define SQR_TOOM3_THRESHOLD                 71
+#define SQR_TOOM4_THRESHOLD                202
+#define SQR_TOOM6_THRESHOLD                298
+#define SQR_TOOM8_THRESHOLD                466
+
+#define MULMID_TOOM42_THRESHOLD             20
+
+#define MULMOD_BNM1_THRESHOLD               11
+#define SQRMOD_BNM1_THRESHOLD               14
+
+#define MUL_FFT_MODF_THRESHOLD             316  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    316, 5}, {     19, 6}, {     10, 5}, {     21, 6}, \
+    {     21, 7}, {     11, 6}, {     23, 7}, {     12, 6}, \
+    {     25, 7}, {     21, 8}, {     11, 7}, {     24, 8}, \
+    {     13, 7}, {     28, 8}, {     15, 7}, {     31, 8}, \
+    {     21, 9}, {     11, 8}, {     27, 9}, {     15, 8}, \
+    {     33, 9}, {     19, 8}, {     41, 9}, {     23, 8}, \
+    {     47, 9}, {     27,10}, {     15, 9}, {     39,10}, \
+    {     23, 9}, {     51,11}, {     15,10}, {     31, 9}, \
+    {     67,10}, {     39, 9}, {     83,10}, {     47, 9}, \
+    {     99,10}, {     55,11}, {     31,10}, {     87,11}, \
+    {     47,10}, {     95, 9}, {    191,10}, {    103,12}, \
+    {     31,11}, {     63,10}, {    127, 9}, {    255,10}, \
+    {    135, 9}, {    271, 5}, {   4351, 6}, {   2303, 7}, \
+    {   1215, 8}, {    639,10}, {    175,11}, {     95,10}, \
+    {    191, 9}, {    383,10}, {    207, 9}, {    415,11}, \
+    {    111,12}, {     63,11}, {    127,10}, {    255, 9}, \
+    {    511,10}, {    271, 9}, {    543,11}, {    143,10}, \
+    {    287, 9}, {    575,10}, {    303,11}, {    159,10}, \
+    {    319, 9}, {    639,11}, {    175,12}, {     95,11}, \
+    {    191,10}, {    383,11}, {    207,10}, {    415, 9}, \
+    {    831,13}, {     63,12}, {    127,11}, {    255,10}, \
+    {    511,11}, {    271,10}, {    543,11}, {    287,10}, \
+    {    575,11}, {    303,12}, {    159,11}, {    319,10}, \
+    {    639,11}, {    351,12}, {    191,11}, {    383,10}, \
+    {    767,11}, {    415,10}, {    831,12}, {    223,11}, \
+    {    447,10}, {    895,11}, {    479,13}, {    127,12}, \
+    {    255,11}, {    543,12}, {    287,11}, {    607,12}, \
+    {    319,11}, {    639,12}, {    351,13}, {    191,12}, \
+    {    383,11}, {    767,12}, {    415,11}, {    831,12}, \
+    {    447,11}, {    895,12}, {    479,14}, {    127,13}, \
+    {    255,12}, {    543,11}, {   1087,12}, {    607,13}, \
+    {    319,12}, {    671,11}, {   1343,10}, {   2687,12}, \
+    {    703,13}, {    383,12}, {    767,11}, {   1535,12}, \
+    {    831,13}, {    447,12}, {    895,11}, {   1791,12}, \
+    {    959,14}, {    255,13}, {    511,12}, {   1087,13}, \
+    {    575,12}, {   1151,11}, {   2303,12}, {   1215,11}, \
+    {   2431,13}, {    639,12}, {   1343,11}, {   2687,13}, \
+    {    703,14}, {    383,13}, {    767,12}, {   1535,13}, \
+    {    831,12}, {   1663,13}, {    959,15}, {    255,14}, \
+    {    511,13}, {   1087,12}, {   2175,13}, {   1151,12}, \
+    {   2303,13}, {   1215,12}, {   2431,14}, {    639,13}, \
+    {   1343,12}, {   2687,13}, {   1407,12}, {   2815,13}, \
+    {   1471,14}, {    767,13}, {   1535,12}, {   3071,13}, \
+    {   1663,14}, {    895,13}, {   1791,12}, {   3583,13}, \
+    {   1919,15}, {    511,14}, {   1023,13}, {   2175,14}, \
+    {   1151,13}, {   2303,12}, {   4607,13}, {   2431,12}, \
+    {   4863,14}, {   1279,13}, {   2687,14}, {   1407,13}, \
+    {   2815,15}, {    767,14}, {   1535,13}, {   3071,14}, \
+    {   1663,13}, {   3455,12}, {   6911,14}, {   1791,13}, \
+    {   3583,14}, {   1919,16}, {    511,15}, {   1023,14}, \
+    {   2303,13}, {   4607,14}, {   2431,13}, {   4863,15}, \
+    {   1279,14}, {   2943,13}, {   5887,15}, {   1535,14}, \
+    {   3455,13}, {   6911,15}, {   1791,14}, {   3839,13}, \
+    {   7679,16}, {   1023,15}, {   2047,14}, {   4351,15}, \
+    {   2303,14}, {   4863,15}, {   2815,14}, {   5887,16}, \
+    {   1535,15}, {   3071,14}, {   6143,15}, {   3327,14}, \
+    {   6911,15}, {   3839,14}, {   7679,17}, {   1023,16}, \
+    {   2047,15}, {   4863,16}, {   2559,15}, {   5887,14}, \
+    {  11775,16}, {   3071,15}, {   6911,16}, {   3583,15}, \
+    {   7679,17}, {   2047,16}, {   4095,15}, {   8191,16}, \
+    {   4607,15}, {   9983,16}, {   5631,15}, {  11775,17}, \
+    {   3071,16}, {  65536,17}, { 131072,18}, { 262144,19}, \
+    { 524288,20}, {1048576,21}, {2097152,22}, {4194304,23}, \
+    {8388608,24} }
+#define MUL_FFT_TABLE3_SIZE 253
+#define MUL_FFT_THRESHOLD                 4224
+
+#define SQR_FFT_MODF_THRESHOLD             300  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    300, 5}, {     19, 6}, {     10, 5}, {     21, 6}, \
+    {     23, 7}, {     12, 6}, {     25, 7}, {     21, 8}, \
+    {     11, 7}, {     25, 8}, {     13, 7}, {     27, 8}, \
+    {     15, 7}, {     31, 8}, {     21, 9}, {     11, 8}, \
+    {     27, 9}, {     15, 8}, {     35, 9}, {     19, 8}, \
+    {     39, 9}, {     23, 8}, {     47, 9}, {     27,10}, \
+    {     15, 9}, {     39,10}, {     23, 9}, {     51,11}, \
+    {     15,10}, {     31, 9}, {     63,10}, {     39, 9}, \
+    {     79,10}, {     47, 9}, {     95,10}, {     55,11}, \
+    {     31,10}, {     79,11}, {     47,10}, {     95, 9}, \
+    {    191, 8}, {    383,10}, {    103,12}, {     31,11}, \
+    {     63,10}, {    127, 9}, {    255, 8}, {    511, 9}, \
+    {    271, 8}, {    543,11}, {     79,10}, {    159, 9}, \
+    {    319, 8}, {    639,10}, {    175,11}, {     95,10}, \
+    {    191, 9}, {    383, 5}, {   6399, 6}, {   3327, 7}, \
+    {   1727, 6}, {   3455, 7}, {   1791,11}, {    127,10}, \
+    {    255, 9}, {    511,10}, {    271, 9}, {    543,10}, \
+    {    287, 9}, {    575,10}, {    303,11}, {    159,10}, \
+    {    319, 9}, {    639,11}, {    175,10}, {    351,12}, \
+    {     95,11}, {    191,10}, {    383,11}, {    207,10}, \
+    {    415, 9}, {    831,13}, {     63,11}, {    255,10}, \
+    {    511,11}, {    271,10}, {    543,11}, {    287,10}, \
+    {    575,11}, {    303,10}, {    607,12}, {    159,11}, \
+    {    319,10}, {    639,11}, {    351,10}, {    703,12}, \
+    {    191,11}, {    383,10}, {    767,11}, {    415,10}, \
+    {    831,12}, {    223,11}, {    447,10}, {    895,11}, \
+    {    479,12}, {    255,11}, {    511,10}, {   1023,11}, \
+    {    543,12}, {    287,11}, {    575,10}, {   1151,11}, \
+    {    607,12}, {    319,11}, {    639,12}, {    351,11}, \
+    {    703,13}, {    191,12}, {    383,11}, {    767,12}, \
+    {    415,11}, {    831,12}, {    447,11}, {    895,12}, \
+    {    479,13}, {    255,12}, {    511,11}, {   1023,12}, \
+    {    543,11}, {   1087,12}, {    575,11}, {   1151,12}, \
+    {    607,13}, {    319,12}, {    639,11}, {   1279,12}, \
+    {    671,11}, {   1343,12}, {    703,13}, {    383,12}, \
+    {    767,11}, {   1535,12}, {    831,11}, {   1663,13}, \
+    {    447,12}, {    959,14}, {    255,13}, {    511,12}, \
+    {   1087,13}, {    575,12}, {   1151,11}, {   2303,12}, \
+    {   1215,11}, {   2431,13}, {    639,12}, {   1343,13}, \
+    {    703,14}, {    383,13}, {    767,12}, {   1535,13}, \
+    {    831,12}, {   1663,13}, {    895,12}, {   1791,13}, \
+    {    959,15}, {    255,14}, {    511,13}, {   1023,12}, \
+    {   2047,13}, {   1087,12}, {   2175,13}, {   1151,12}, \
+    {   2303,13}, {   1215,12}, {   2431,14}, {    639,13}, \
+    {   1343,12}, {   2687,13}, {   1407,12}, {   2815,13}, \
+    {   1471,14}, {    767,13}, {   1599,12}, {   3199,13}, \
+    {   1663,14}, {    895,13}, {   1791,12}, {   3583,15}, \
+    {    511,14}, {   1023,13}, {   2175,14}, {   1151,13}, \
+    {   2303,12}, {   4607,13}, {   2431,12}, {   4863,14}, \
+    {   1279,13}, {   2687,14}, {   1407,13}, {   2815,15}, \
+    {    767,14}, {   1535,13}, {   3199,14}, {   1663,13}, \
+    {   3455,14}, {   1791,13}, {   3583,14}, {   1919,16}, \
+    {    511,15}, {   1023,14}, {   2303,13}, {   4607,14}, \
+    {   2431,13}, {   4863,15}, {   1279,14}, {   2815,13}, \
+    {   5631,14}, {   2943,13}, {   5887,15}, {   1535,14}, \
+    {   3455,15}, {   1791,14}, {   3583,13}, {   7167,14}, \
+    {   3839,13}, {   7679,16}, {   1023,15}, {   2047,14}, \
+    {   4223,15}, {   2303,14}, {   4863,15}, {   2815,14}, \
+    {   5887,16}, {   1535,15}, {   3071,14}, {   6143,15}, \
+    {   3327,14}, {   6911,15}, {   3583,14}, {   7167,15}, \
+    {   3839,14}, {   7679,17}, {   1023,16}, {   2047,15}, \
+    {   4095,14}, {   8191,15}, {   4863,16}, {   2559,15}, \
+    {   5887,14}, {  11775,16}, {   3071,15}, {   6911,16}, \
+    {   3583,15}, {   7679,14}, {  15359,17}, {   2047,16}, \
+    {   4095,15}, {   8447,16}, {   4607,15}, {   9983,16}, \
+    {   5119,15}, {  10239,16}, {   5631,15}, {  11775,17}, \
+    {   3071,16}, {  65536,17}, { 131072,18}, { 262144,19}, \
+    { 524288,20}, {1048576,21}, {2097152,22}, {4194304,23}, \
+    {8388608,24} }
+#define SQR_FFT_TABLE3_SIZE 273
+#define SQR_FFT_THRESHOLD                 2752
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  43
+#define MULLO_MUL_N_THRESHOLD             8397
+#define SQRLO_BASECASE_THRESHOLD             6
+#define SQRLO_DC_THRESHOLD                  54
+#define SQRLO_SQR_THRESHOLD               5397
+
+#define DC_DIV_QR_THRESHOLD                 39
+#define DC_DIVAPPR_Q_THRESHOLD             165
+#define DC_BDIV_QR_THRESHOLD                39
+#define DC_BDIV_Q_THRESHOLD                 76
+
+#define INV_MULMOD_BNM1_THRESHOLD           30
+#define INV_NEWTON_THRESHOLD               177
+#define INV_APPR_THRESHOLD                 155
+
+#define BINV_NEWTON_THRESHOLD              230
+#define REDC_1_TO_REDC_2_THRESHOLD          28
+#define REDC_2_TO_REDC_N_THRESHOLD          43
+
+#define MU_DIV_QR_THRESHOLD               1142
+#define MU_DIVAPPR_Q_THRESHOLD            1142
+#define MUPI_DIV_QR_THRESHOLD               66
+#define MU_BDIV_QR_THRESHOLD               998
+#define MU_BDIV_Q_THRESHOLD               1142
+
+#define POWM_SEC_TABLE  1,16,175,269,839,1420
+
+#define GET_STR_DC_THRESHOLD                12
+#define GET_STR_PRECOMPUTE_THRESHOLD        19
+#define SET_STR_DC_THRESHOLD               552
+#define SET_STR_PRECOMPUTE_THRESHOLD      1038
+
+#define FAC_DSC_THRESHOLD                  151
+#define FAC_ODD_THRESHOLD                   23
+
+#define MATRIX22_STRASSEN_THRESHOLD         17
+#define HGCD2_DIV1_METHOD                    1  /* 8.11% faster than 3 */
+#define HGCD_THRESHOLD                      87
+#define HGCD_APPR_THRESHOLD                 96
+#define HGCD_REDUCE_THRESHOLD             2121
+#define GCD_DC_THRESHOLD                   327
+#define GCDEXT_DC_THRESHOLD                241
+#define JACOBI_BASE_METHOD                   4  /* 21.40% faster than 1 */
+
+/* Tuneup completed successfully, took 431056 seconds */
diff --git a/third_party/gmp/mpn/x86_64/bdiv_dbm1c.asm b/third_party/gmp/mpn/x86_64/bdiv_dbm1c.asm
new file mode 100644
index 0000000..a53bd52
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/bdiv_dbm1c.asm
@@ -0,0 +1,106 @@
+dnl  x86_64 mpn_bdiv_dbm1.
+
+dnl  Copyright 2008, 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 2.25
+C AMD K10	 2.25
+C Intel P4	12.5
+C Intel core2	 4
+C Intel NHM	 3.75
+C Intel SBR	 3.6
+C Intel atom	20
+C VIA nano	 4
+
+C TODO
+C  * Optimise feed-in code.
+
+C INPUT PARAMETERS
+define(`qp',	  `%rdi')
+define(`up',	  `%rsi')
+define(`n_param', `%rdx')
+define(`bd',	  `%rcx')
+define(`cy',	  `%r8')
+
+define(`n',       `%r9')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_bdiv_dbm1c)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8	')
+	mov	(up), %rax
+	mov	n_param, n
+	mov	R32(n_param), R32(%r11)
+	mul	bd
+	lea	(up,n,8), up
+	lea	(qp,n,8), qp
+	neg	n
+	and	$3, R32(%r11)
+	jz	L(lo0)
+	lea	-4(n,%r11), n
+	cmp	$2, R32(%r11)
+	jc	L(lo1)
+	jz	L(lo2)
+	jmp	L(lo3)
+
+	ALIGN(16)
+L(top):	mov	(up,n,8), %rax
+	mul	bd
+L(lo0):	sub	%rax, %r8
+	mov	%r8, (qp,n,8)
+	sbb	%rdx, %r8
+	mov	8(up,n,8), %rax
+	mul	bd
+L(lo3):	sub	%rax, %r8
+	mov	%r8, 8(qp,n,8)
+	sbb	%rdx, %r8
+	mov	16(up,n,8), %rax
+	mul	bd
+L(lo2):	sub	%rax, %r8
+	mov	%r8, 16(qp,n,8)
+	sbb	%rdx, %r8
+	mov	24(up,n,8), %rax
+	mul	bd
+L(lo1):	sub	%rax, %r8
+	mov	%r8, 24(qp,n,8)
+	sbb	%rdx, %r8
+	add	$4, n
+	jnz	L(top)
+
+	mov	%r8, %rax
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/bdiv_q_1.asm b/third_party/gmp/mpn/x86_64/bdiv_q_1.asm
new file mode 100644
index 0000000..85538c9
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/bdiv_q_1.asm
@@ -0,0 +1,195 @@
+dnl  AMD64 mpn_bdiv_q_1, mpn_pi1_bdiv_q_1 -- Hensel division by 1-limb divisor.
+
+dnl  Copyright 2001, 2002, 2004-2006, 2010-2012, 2017 Free Software Foundation,
+dnl  Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	    cycles/limb    cycles/limb
+C	       norm	       unorm
+C AMD K8,K9	11		11
+C AMD K10	11		11
+C AMD bull	13.5		14
+C AMD pile	14		15
+C AMD steam
+C AMD excavator
+C AMD bobcat	14		14
+C AMD jaguar	14.5		15
+C Intel P4	33		33
+C Intel core2	13.5		13.25
+C Intel NHM	14		14
+C Intel SBR	8		8.25
+C Intel IBR	7.75		7.85
+C Intel HWL	8		8
+C Intel BWL	8		8
+C Intel SKL	8		8
+C Intel atom	34		36
+C Intel SLM	13.7		13.5
+C VIA nano	19.25		19.25	needs re-measuring
+
+C INPUT PARAMETERS
+define(`rp',		`%rdi')
+define(`up',		`%rsi')
+define(`n',		`%rdx')
+define(`d',		`%rcx')
+define(`di',		`%r8')		C	just mpn_pi1_bdiv_q_1
+define(`ncnt',		`%r9')		C	just mpn_pi1_bdiv_q_1
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_bdiv_q_1)
+	FUNC_ENTRY(4)
+	push	%rbx
+
+	mov	%rcx, %rax
+	xor	R32(%rcx), R32(%rcx)	C ncnt count
+	mov	%rdx, %r10
+
+	bt	$0, R32(%rax)
+	jnc	L(evn)			C skip bsf unless divisor is even
+
+L(odd):	mov	%rax, %rbx
+	shr	R32(%rax)
+	and	$127, R32(%rax)		C d/2, 7 bits
+
+	LEA(	binvert_limb_table, %rdx)
+
+	movzbl	(%rdx,%rax), R32(%rax)	C inv 8 bits
+
+	mov	%rbx, %r11		C d without twos
+
+	lea	(%rax,%rax), R32(%rdx)	C 2*inv
+	imul	R32(%rax), R32(%rax)	C inv*inv
+	imul	R32(%rbx), R32(%rax)	C inv*inv*d
+	sub	R32(%rax), R32(%rdx)	C inv = 2*inv - inv*inv*d, 16 bits
+
+	lea	(%rdx,%rdx), R32(%rax)	C 2*inv
+	imul	R32(%rdx), R32(%rdx)	C inv*inv
+	imul	R32(%rbx), R32(%rdx)	C inv*inv*d
+	sub	R32(%rdx), R32(%rax)	C inv = 2*inv - inv*inv*d, 32 bits
+
+	lea	(%rax,%rax), %r8	C 2*inv
+	imul	%rax, %rax		C inv*inv
+	imul	%rbx, %rax		C inv*inv*d
+	sub	%rax, %r8		C inv = 2*inv - inv*inv*d, 64 bits
+
+	jmp	L(pi1)
+
+L(evn):	bsf	%rax, %rcx
+	shr	R8(%rcx), %rax
+	jmp	L(odd)
+EPILOGUE()
+
+PROLOGUE(mpn_pi1_bdiv_q_1)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8	')
+IFDOS(`	mov	64(%rsp), %r9	')
+	push	%rbx
+
+	mov	%rcx, %r11		C d
+	mov	%rdx, %r10		C n
+	mov	%r9, %rcx		C ncnt
+
+L(pi1):	mov	(up), %rax		C up[0]
+
+	dec	%r10
+	jz	L(one)
+
+	lea	8(up,%r10,8), up	C up end
+	lea	(rp,%r10,8), rp		C rp end
+	neg	%r10			C -n
+
+	test	R32(%rcx), R32(%rcx)
+	jnz	L(unorm)		C branch if count != 0
+	xor	R32(%rbx), R32(%rbx)
+	jmp	L(nent)
+
+	ALIGN(8)
+L(ntop):mul	%r11			C carry limb in rdx	0 10
+	mov	-8(up,%r10,8), %rax	C
+	sub	%rbx, %rax		C apply carry bit
+	setc	R8(%rbx)		C
+	sub	%rdx, %rax		C apply carry limb	5
+	adc	$0, R32(%rbx)		C			6
+L(nent):imul	%r8, %rax		C			6
+	mov	%rax, (rp,%r10,8)	C
+	inc	%r10			C
+	jnz	L(ntop)
+
+	mov	-8(up), %r9		C up high limb
+	jmp	L(com)
+
+L(unorm):
+	mov	(up,%r10,8), %r9	C up[1]
+	shr	R8(%rcx), %rax		C
+	neg	R32(%rcx)
+	shl	R8(%rcx), %r9		C
+	neg	R32(%rcx)
+	or	%r9, %rax
+	xor	R32(%rbx), R32(%rbx)
+	jmp	L(uent)
+
+	ALIGN(8)
+L(utop):mul	%r11			C carry limb in rdx	0 10
+	mov	(up,%r10,8), %rax	C
+	shl	R8(%rcx), %rax		C
+	neg	R32(%rcx)
+	or	%r9, %rax
+	sub	%rbx, %rax		C apply carry bit
+	setc	R8(%rbx)		C
+	sub	%rdx, %rax		C apply carry limb	5
+	adc	$0, R32(%rbx)		C			6
+L(uent):imul	%r8, %rax		C			6
+	mov	(up,%r10,8), %r9	C
+	shr	R8(%rcx), %r9		C
+	neg	R32(%rcx)
+	mov	%rax, (rp,%r10,8)	C
+	inc	%r10			C
+	jnz	L(utop)
+
+L(com):	mul	%r11			C carry limb in rdx
+	sub	%rbx, %r9		C apply carry bit
+	sub	%rdx, %r9		C apply carry limb
+	imul	%r8, %r9
+	mov	%r9, (rp)
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+
+L(one):	shr	R8(%rcx), %rax
+	imul	%r8, %rax
+	mov	%rax, (rp)
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/bt1/aors_n.asm b/third_party/gmp/mpn/x86_64/bt1/aors_n.asm
new file mode 100644
index 0000000..9b6b5c7
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/bt1/aors_n.asm
@@ -0,0 +1,159 @@
+dnl  AMD64 mpn_add_n, mpn_sub_n optimised for bobcat.
+
+dnl  Copyright 2003-2005, 2007, 2008, 2010-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	    cycles/limb
+C AMD K8,K9	 1.77
+C AMD K10	 1.76\1.82
+C AMD bd1	 1.67\2.12
+C AMD bd2	 1.62\1.82
+C AMD bd3
+C AMD bd4	 1.55\2.2
+C AMD zen
+C AMD bt1	 2.54
+C AMD bt2	 2
+C Intel P4	11
+C Intel PNR	 4.76
+C Intel NHM	 5.27
+C Intel SBR	 2
+C Intel IBR	 1.94
+C Intel HWL	 1.63
+C Intel BWL	 1.51
+C Intel SKL	 1.51
+C Intel atom	 3.56
+C Intel SLM	 4
+C VIA nano
+
+C The loop of this code is the result of running a code generation and
+C optimization tool suite written by David Harvey and Torbjorn Granlund.
+
+C INPUT PARAMETERS
+define(`rp',	`%rdi')	C rcx
+define(`up',	`%rsi')	C rdx
+define(`vp',	`%rdx')	C r8
+define(`n',	`%rcx')	C r9
+define(`cy',	`%r8')	C rsp+40    (mpn_add_nc and mpn_sub_nc)
+
+ifdef(`OPERATION_add_n', `
+	define(ADCSBB,	      adc)
+	define(func,	      mpn_add_n)
+	define(func_nc,	      mpn_add_nc)')
+ifdef(`OPERATION_sub_n', `
+	define(ADCSBB,	      sbb)
+	define(func,	      mpn_sub_n)
+	define(func_nc,	      mpn_sub_nc)')
+
+MULFUNC_PROLOGUE(mpn_add_n mpn_add_nc mpn_sub_n mpn_sub_nc)
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(func)
+	FUNC_ENTRY(4)
+	xor	%r8, %r8
+L(ent):	test	$1, R8(n)
+	jnz	L(bx1)
+
+L(bx0):	test	$2, R8(n)
+	jnz	L(b10)
+
+L(b00):	shr	$2, n
+	neg	%r8
+	mov	$3, R32(%rax)
+	mov	(up), %r10
+	mov	8(up), %r11
+	jmp	L(lo0)
+
+L(b10):	shr	$2, n
+	neg	%r8
+	mov	$1, R32(%rax)
+	mov	(up), %r8
+	mov	8(up), %r9
+	jrcxz	L(cj2)
+	jmp	L(top)
+
+L(bx1):	test	$2, R8(n)
+	jnz	L(b11)
+
+L(b01):	shr	$2, n
+	neg	%r8
+	mov	$0, R32(%rax)
+	mov	(up), %r9
+	jrcxz	L(cj1)
+	mov	8(up), %r10
+	jmp	L(lo1)
+
+	ALIGN(8)
+L(b11):	inc	n
+	shr	$2, n
+	neg	%r8
+	mov	$2, R32(%rax)
+	mov	(up), %r11
+	jmp	L(lo3)
+
+	ALIGN(4)
+L(top):	mov	8(up,%rax,8), %r10
+	ADCSBB	-8(vp,%rax,8), %r8
+	mov	%r8, -8(rp,%rax,8)
+L(lo1):	mov	16(up,%rax,8), %r11
+	ADCSBB	(vp,%rax,8), %r9
+	lea	4(%rax), %rax
+	mov	%r9, -32(rp,%rax,8)
+L(lo0):	ADCSBB	-24(vp,%rax,8), %r10
+	mov	%r10, -24(rp,%rax,8)
+L(lo3):	ADCSBB	-16(vp,%rax,8), %r11
+	dec	n
+	mov	-8(up,%rax,8), %r8
+	mov	%r11, -16(rp,%rax,8)
+L(lo2):	mov	(up,%rax,8), %r9
+	jnz	L(top)
+
+L(cj2):	ADCSBB	-8(vp,%rax,8), %r8
+	mov	%r8, -8(rp,%rax,8)
+L(cj1):	ADCSBB	(vp,%rax,8), %r9
+	mov	%r9, (rp,%rax,8)
+
+	mov	$0, R32(%rax)
+	adc	$0, R32(%rax)
+
+	FUNC_EXIT()
+	ret
+EPILOGUE()
+
+	ALIGN(16)
+PROLOGUE(func_nc)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8	')
+	jmp	L(ent)
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/bt1/aorsmul_1.asm b/third_party/gmp/mpn/x86_64/bt1/aorsmul_1.asm
new file mode 100644
index 0000000..41e1d8a
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/bt1/aorsmul_1.asm
@@ -0,0 +1,191 @@
+dnl  AMD64 mpn_addmul_1 and mpn_submul_1 optimised for AMD bt1/bt2.
+
+dnl  Copyright 2003-2005, 2007, 2008, 2011, 2012, 2018-2019 Free Software
+dnl  Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 4.52		old measurement
+C AMD K10	 4.51		old measurement
+C AMD bd1	 4.66		old measurement
+C AMD bd2	 4.57		old measurement
+C AMD bd3	 ?
+C AMD bd4	 ?
+C AMD zen	 ?
+C AMD bt1	 5.04
+C AMD bt2	 5.07
+C Intel P4	16.8	18.6	old measurement
+C Intel PNR	 5.59		old measurement
+C Intel NHM	 5.39		old measurement
+C Intel SBR	 3.93		old measurement
+C Intel IBR	 3.59		old measurement
+C Intel HWL	 3.61		old measurement
+C Intel BWL	 2.76		old measurement
+C Intel SKL	 2.77		old measurement
+C Intel atom	23		old measurement
+C Intel SLM	 8		old measurement
+C Intel GLM	 ?
+C VIA nano	 5.63		old measurement
+
+C The ALIGNment here might look completely ad-hoc.  They are not.
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ifdef(`OPERATION_addmul_1',`
+      define(`ADDSUB',        `add')
+      define(`func',  `mpn_addmul_1')
+')
+ifdef(`OPERATION_submul_1',`
+      define(`ADDSUB',        `sub')
+      define(`func',  `mpn_submul_1')
+')
+
+MULFUNC_PROLOGUE(mpn_addmul_1 mpn_submul_1)
+
+C Standard parameters
+define(`rp',              `%rdi')
+define(`up',              `%rsi')
+define(`n_param',         `%rdx')
+define(`v0',              `%rcx')
+C Standard allocations
+define(`n',               `%rbx')
+define(`w0',              `%r8')
+define(`w1',              `%r9')
+define(`w2',              `%r10')
+define(`w3',              `%r11')
+
+C DOS64 parameters
+IFDOS(` define(`rp',      `%rcx')    ') dnl
+IFDOS(` define(`up',      `%rsi')    ') dnl
+IFDOS(` define(`n_param', `%r8')     ') dnl
+IFDOS(` define(`v0',      `%r9')     ') dnl
+C DOS64 allocations
+IFDOS(` define(`n',       `%rbx')    ') dnl
+IFDOS(` define(`w0',      `%r8')     ') dnl
+IFDOS(` define(`w1',      `%rdi')    ') dnl
+IFDOS(` define(`w2',      `%r10')    ') dnl
+IFDOS(` define(`w3',      `%r11')    ') dnl
+
+ASM_START()
+	TEXT
+	ALIGN(64)
+PROLOGUE(func)
+IFDOS(`	push	%rsi		')
+IFDOS(`	push	%rdi		')
+IFDOS(`	mov	%rdx, %rsi	')
+
+	push	%rbx
+	mov	(up), %rax
+
+	lea	(rp,n_param,8), rp
+	lea	(up,n_param,8), up
+	mov	n_param, n
+
+	test	$1, R8(n_param)
+	jne	L(bx1)
+
+L(bx0):	mul	v0
+	neg	n
+	mov	%rax, w0
+	mov	%rdx, w1
+	test	$2, R8(n)
+	jne	L(L2)
+
+L(b00):	add	$2, n
+	jmp	L(L0)
+
+	ALIGN(16)
+L(bx1):	mul	v0
+	test	$2, R8(n)
+	je	L(b01)
+
+L(b11):	mov	%rax, w2
+	mov	%rdx, w3
+	neg	n
+	inc	n
+	jmp	L(L3)
+
+	ALIGN(16)
+L(b01):	sub	$3, n
+	jc	L(n1)
+	mov	%rax, w2
+	mov	%rdx, w3
+	neg	n
+
+	ALIGN(16)
+L(top):	mov	-16(up,n,8), %rax
+	mul	v0
+	mov	%rax, w0
+	mov	%rdx, w1
+	ADDSUB	w2, -24(rp,n,8)
+	adc	w3, w0
+	adc	$0, w1
+L(L0):	mov	-8(up,n,8), %rax
+	mul	v0
+	mov	%rax, w2
+	mov	%rdx, w3
+	ADDSUB	w0, -16(rp,n,8)
+	adc	w1, w2
+	adc	$0, w3
+L(L3):	mov	(up,n,8), %rax
+	mul	v0
+	mov	%rax, w0
+	mov	%rdx, w1
+	ADDSUB	w2, -8(rp,n,8)
+	adc	w3, w0
+	adc	$0, w1
+L(L2):	mov	8(up,n,8), %rax
+	mul	v0
+	mov	%rax, w2
+	mov	%rdx, w3
+	ADDSUB	w0, (rp,n,8)
+	adc	w1, w2
+	adc	$0, w3
+	add	$4, n
+	js	L(top)
+
+L(end):	xor	R32(%rax), R32(%rax)
+	ADDSUB	w2, -8(rp)
+	adc	w3, %rax
+	pop	%rbx
+IFDOS(`	pop	%rdi		')
+IFDOS(`	pop	%rsi		')
+	ret
+
+	ALIGN(32)
+L(n1):	ADDSUB	%rax, -8(rp)
+	mov	$0, R32(%rax)
+	adc	%rdx, %rax
+	pop	%rbx
+IFDOS(`	pop	%rdi		')
+IFDOS(`	pop	%rsi		')
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/bt1/copyd.asm b/third_party/gmp/mpn/x86_64/bt1/copyd.asm
new file mode 100644
index 0000000..877714e
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/bt1/copyd.asm
@@ -0,0 +1,91 @@
+dnl  AMD64 mpn_copyd optimised for AMD bobcat.
+
+dnl  Copyright 2003, 2005, 2007, 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 1
+C AMD K10	 1-2  (alignment fluctuations)
+C AMD bd1	 ?
+C AMD bobcat	 1.5
+C Intel P4	 2.8
+C Intel core2	 1
+C Intel NHM	 1-1.25
+C Intel SBR	 1
+C Intel atom	 2.87
+C VIA nano	 2
+
+C INPUT PARAMETERS
+C rp	rdi
+C up	rsi
+C n	rdx
+
+define(`rp',`%rdi')
+define(`up',`%rsi')
+define(`n',`%rdx')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_copyd)
+	FUNC_ENTRY(3)
+	sub	$4, n
+	jl	L(end)
+	ALIGN(16)
+L(top):	mov	24(up,n,8), %r8
+	mov	%r8, 24(rp,n,8)
+	mov	16(up,n,8), %r8
+	mov	%r8, 16(rp,n,8)
+	mov	8(up,n,8), %r8
+	mov	%r8, 8(rp,n,8)
+	mov	(up,n,8), %r8
+	mov	%r8, (rp,n,8)
+L(ent):	sub	$4, n
+	jge	L(top)
+
+L(end):	cmp	$-4, R32(n)
+	jz	L(ret)
+	mov	24(up,n,8), %r8
+	mov	%r8, 24(rp,n,8)
+	cmp	$-3, R32(n)
+	jz	L(ret)
+	mov	16(up,n,8), %r8
+	mov	%r8, 16(rp,n,8)
+	cmp	$-2, R32(n)
+	jz	L(ret)
+	mov	8(up,n,8), %r8
+	mov	%r8, 8(rp,n,8)
+
+L(ret):	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/bt1/copyi.asm b/third_party/gmp/mpn/x86_64/bt1/copyi.asm
new file mode 100644
index 0000000..ee0f578
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/bt1/copyi.asm
@@ -0,0 +1,94 @@
+dnl  AMD64 mpn_copyi optimised for AMD bobcat.
+
+dnl  Copyright 2003, 2005, 2007, 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 1
+C AMD K10	 1-2  (alignment fluctuations)
+C AMD bd1	 ?
+C AMD bobcat	 1.5
+C Intel P4	 2.8
+C Intel core2	 1
+C Intel NHM	 1-1.25
+C Intel SBR	 1
+C Intel atom	 2.87
+C VIA nano	 2
+
+C INPUT PARAMETERS
+C rp	rdi
+C up	rsi
+C n	rdx
+
+define(`rp',`%rdi')
+define(`up',`%rsi')
+define(`n',`%rdx')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_copyi)
+	FUNC_ENTRY(3)
+	lea	-32(up,n,8), up
+	lea	-32(rp,n,8), rp
+	neg	n
+	add	$4, n
+	jg	L(end)
+	ALIGN(16)
+L(top):	mov	(up,n,8), %r8
+	mov	%r8, (rp,n,8)
+	mov	8(up,n,8), %r8
+	mov	%r8, 8(rp,n,8)
+	mov	16(up,n,8), %r8
+	mov	%r8, 16(rp,n,8)
+	mov	24(up,n,8), %r8
+	mov	%r8, 24(rp,n,8)
+L(ent):	add	$4, n
+	jle	L(top)
+
+L(end):	cmp	$4, R32(n)
+	jz	L(ret)
+	mov	(up,n,8), %r8
+	mov	%r8, (rp,n,8)
+	cmp	$3, R32(n)
+	jz	L(ret)
+	mov	8(up,n,8), %r8
+	mov	%r8, 8(rp,n,8)
+	cmp	$2, R32(n)
+	jz	L(ret)
+	mov	16(up,n,8), %r8
+	mov	%r8, 16(rp,n,8)
+
+L(ret):	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/bt1/gcd_11.asm b/third_party/gmp/mpn/x86_64/bt1/gcd_11.asm
new file mode 100644
index 0000000..ef53392
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/bt1/gcd_11.asm
@@ -0,0 +1,119 @@
+dnl  AMD64 mpn_gcd_11 -- 1 x 1 gcd.
+
+dnl  Based on the K7 gcd_1.asm, by Kevin Ryde.  Rehacked for AMD64 by Torbjorn
+dnl  Granlund.
+
+dnl  Copyright 2000-2002, 2005, 2009, 2011, 2012, 2017 Free Software
+dnl  Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C	     cycles/bit
+C AMD K8,K9	 ?
+C AMD K10	 ?
+C AMD bd1	 ?
+C AMD bd2	 ?
+C AMD bd3	 ?
+C AMD bd4	 ?
+C AMD bt1	 5.4
+C AMD bt2	 ?
+C AMD zn1	 ?
+C AMD zn2	 ?
+C Intel P4	 ?
+C Intel CNR	 ?
+C Intel PNR	 ?
+C Intel NHM	 ?
+C Intel WSM	 ?
+C Intel SBR	 ?
+C Intel IBR	 ?
+C Intel HWL	 ?
+C Intel BWL	 ?
+C Intel SKL	 ?
+C Intel atom	 ?
+C Intel SLM	 ?
+C Intel GLM	 ?
+C Intel GLM+	 ?
+C VIA nano	 ?
+
+
+C ctz_table[n] is the number of trailing zeros on n, or MAXSHIFT if n==0.
+
+deflit(MAXSHIFT, 8)
+deflit(MASK, eval((m4_lshift(1,MAXSHIFT))-1))
+
+DEF_OBJECT(ctz_table,64)
+	.byte	MAXSHIFT
+forloop(i,1,MASK,
+`	.byte	m4_count_trailing_zeros(i)
+')
+END_OBJECT(ctz_table)
+
+define(`u0',    `%rdi')
+define(`v0',    `%rsi')
+
+define(`cnt',   `%rcx')
+define(`s0',    `%rax')
+define(`t0',    `%rdx')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(64)
+PROLOGUE(mpn_gcd_11)
+	FUNC_ENTRY(2)
+	LEA(	ctz_table, %r10)
+	mov	v0, t0
+	sub	u0, t0
+	jz	L(end)
+
+	ALIGN(16)
+L(top):	mov	u0, s0
+	sub	v0, u0
+	cmovc	t0, u0		C u = |u - v|
+	cmovc	s0, v0		C v = min(u,v)
+	and	$MASK, R32(t0)
+	movzbl	(%r10,t0), R32(cnt)
+	jz	L(count_better)
+L(shr):	shr	R8(cnt), u0
+	mov	v0, t0
+	sub	u0, t0
+	jnz	L(top)
+
+L(end):	mov	v0, %rax
+	C rdx = 0 for the benefit of internal gcd_22 call
+	FUNC_EXIT()
+	ret
+
+L(count_better):
+	bsf	u0, cnt
+	jmp	L(shr)
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/bt1/gcd_22.asm b/third_party/gmp/mpn/x86_64/bt1/gcd_22.asm
new file mode 100644
index 0000000..c9f221e
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/bt1/gcd_22.asm
@@ -0,0 +1,37 @@
+dnl  AMD64 mpn_gcd_22.
+
+dnl  Copyright 2019 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+dnl ABI_SUPPORT(DOS64)	C returns mp_double_limb_t in memory
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_gcd_22)
+include_mpn(`x86_64/gcd_22.asm')
diff --git a/third_party/gmp/mpn/x86_64/bt1/gmp-mparam.h b/third_party/gmp/mpn/x86_64/bt1/gmp-mparam.h
new file mode 100644
index 0000000..977a209
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/bt1/gmp-mparam.h
@@ -0,0 +1,230 @@
+/* AMD Bobcat gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+/* Disable use of slow functions.  FIXME: We should disable lib inclusion.  */
+#undef HAVE_NATIVE_mpn_mul_2
+#undef HAVE_NATIVE_mpn_addmul_2
+
+/* 1600 MHz AMD Bobcat/Zacate */
+/* FFT tuning limit = 110,472,704 */
+/* Generated by tuneup.c, 2019-10-12, gcc 8.3 */
+
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          7
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          3
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        31
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        71
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     14
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1_NORM_THRESHOLD              1
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           20
+
+#define DIV_1_VS_MUL_1_PERCENT             270
+
+#define MUL_TOOM22_THRESHOLD                24
+#define MUL_TOOM33_THRESHOLD                66
+#define MUL_TOOM44_THRESHOLD               190
+#define MUL_TOOM6H_THRESHOLD               274
+#define MUL_TOOM8H_THRESHOLD               381
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD     129
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     138
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     127
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     131
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     100
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 30
+#define SQR_TOOM3_THRESHOLD                101
+#define SQR_TOOM4_THRESHOLD                278
+#define SQR_TOOM6_THRESHOLD                372
+#define SQR_TOOM8_THRESHOLD                478
+
+#define MULMID_TOOM42_THRESHOLD             22
+
+#define MULMOD_BNM1_THRESHOLD               11
+#define SQRMOD_BNM1_THRESHOLD               13
+
+#define MUL_FFT_MODF_THRESHOLD             444  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    444, 5}, {     19, 6}, {     10, 5}, {     21, 6}, \
+    {     11, 5}, {     23, 6}, {     21, 7}, {     11, 6}, \
+    {     25, 7}, {     13, 6}, {     27, 7}, {     21, 8}, \
+    {     11, 7}, {     25, 8}, {     13, 7}, {     28, 8}, \
+    {     15, 7}, {     31, 8}, {     17, 7}, {     35, 8}, \
+    {     19, 7}, {     39, 8}, {     27, 9}, {     15, 8}, \
+    {     35, 9}, {     19, 8}, {     41, 9}, {     23, 8}, \
+    {     49, 9}, {     27,10}, {     15, 9}, {     39,10}, \
+    {     23, 9}, {     55,11}, {     15,10}, {     31, 9}, \
+    {     71,10}, {     39, 9}, {     83, 5}, {   1343, 4}, \
+    {   2687, 5}, {   1407, 6}, {    735, 7}, {    415, 8}, \
+    {    223,10}, {     79,11}, {     47,10}, {    103,12}, \
+    {     31,11}, {     63,10}, {    135,11}, {     79,10}, \
+    {    167,11}, {     95,10}, {    191,11}, {    111,12}, \
+    {     63,11}, {    127,10}, {    255,11}, {    143,10}, \
+    {    287, 9}, {    575,11}, {    159,12}, {     95,11}, \
+    {    191,10}, {    383,11}, {    207,10}, {    415,13}, \
+    {     63,12}, {    127,11}, {    255,10}, {    511,11}, \
+    {    271,10}, {    543,11}, {    287,10}, {    575,12}, \
+    {    159,11}, {    319,10}, {    639,11}, {    351,10}, \
+    {    703,12}, {    191,11}, {    383,10}, {    767,11}, \
+    {    415,12}, {    223,13}, {    127,12}, {    255,11}, \
+    {    543,12}, {    287,11}, {    607,12}, {    319,11}, \
+    {    671,12}, {    351,11}, {    703,13}, {    191,12}, \
+    {    383,11}, {    767,12}, {    415,11}, {    831,12}, \
+    {    447,14}, {    127,13}, {    255,12}, {    607,13}, \
+    {    319,12}, {    703,13}, {    383,12}, {    831,13}, \
+    {    447,12}, {    959,14}, {    255,13}, {    511,12}, \
+    {   1023,13}, {    575,12}, {   1151,13}, {    703,14}, \
+    {    383,13}, {    831,12}, {   1663,13}, {    959,15}, \
+    {    255,14}, {    511,13}, {   1087,12}, {   2175,13}, \
+    {   1151,14}, {    639,13}, {   1343,12}, {   2687,13}, \
+    {   1407,14}, {    767,13}, {   1599,12}, {   3199,13}, \
+    {   1663,14}, {    895,15}, {    511,14}, {   1023,13}, \
+    {   2175,14}, {   1151,13}, {   2431,12}, {   4863,14}, \
+    {   1279,13}, {   2687,14}, {   1407,15}, {    767,14}, \
+    {   1535,13}, {   3199,14}, {   1663,13}, {   3455,16}, \
+    {    511,15}, {   1023,14}, {   2175,13}, {   4479,14}, \
+    {   2431,13}, {   4863,15}, {   1279,14}, {   2943,13}, \
+    {   5887,15}, {   1535,14}, {   3455,13}, {   6911,15}, \
+    {   1791,14}, {   3839,16}, {   1023,15}, {   2047,14}, \
+    {   4479,15}, {   2303,14}, {   4991,15}, {   2559,14}, \
+    {   5247,15}, {   2815,14}, {   5887,16}, {   1535,15}, \
+    {   3327,14}, {  16384,15}, {  32768,16}, {  65536,17}, \
+    { 131072,18}, { 262144,19}, { 524288,20}, {1048576,21}, \
+    {2097152,22}, {4194304,23}, {8388608,24} }
+#define MUL_FFT_TABLE3_SIZE 183
+#define MUL_FFT_THRESHOLD                 5760
+
+#define SQR_FFT_MODF_THRESHOLD             380  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    380, 5}, {     21, 6}, {     11, 5}, {     23, 6}, \
+    {     25, 7}, {     25, 8}, {     13, 7}, {     27, 8}, \
+    {     15, 7}, {     31, 8}, {     17, 7}, {     35, 8}, \
+    {     19, 7}, {     39, 8}, {     27, 9}, {     15, 8}, \
+    {     35, 9}, {     19, 8}, {     41, 9}, {     23, 8}, \
+    {     47, 9}, {     27,10}, {     15, 9}, {     31, 8}, \
+    {     63, 9}, {     39,10}, {     23, 9}, {     51,11}, \
+    {     15,10}, {     31, 9}, {     67,10}, {     39, 9}, \
+    {     79,10}, {     47, 9}, {     95,10}, {     55,11}, \
+    {     31,10}, {     63, 6}, {   1087, 7}, {    575, 8}, \
+    {    303, 9}, {    159,10}, {    103,12}, {     31,11}, \
+    {     63,10}, {    127, 9}, {    255,10}, {    135,11}, \
+    {     79,10}, {    159, 9}, {    319,11}, {     95,10}, \
+    {    191, 9}, {    383,11}, {    111,12}, {     63,11}, \
+    {    127,10}, {    255, 9}, {    511,10}, {    271,11}, \
+    {    143,10}, {    287, 9}, {    575,10}, {    303,11}, \
+    {    159,10}, {    319,12}, {     95,11}, {    191,10}, \
+    {    383,11}, {    207,13}, {     63,12}, {    127,11}, \
+    {    255,10}, {    511,11}, {    271,10}, {    543,11}, \
+    {    287,10}, {    575,11}, {    303,12}, {    159,11}, \
+    {    319,10}, {    639,11}, {    335,10}, {    671,11}, \
+    {    351,10}, {    703,12}, {    191,11}, {    383,10}, \
+    {    767,11}, {    415,12}, {    223,11}, {    447,13}, \
+    {    127,12}, {    255,11}, {    543,12}, {    287,11}, \
+    {    607,12}, {    319,11}, {    671,12}, {    351,11}, \
+    {    703,13}, {    191,12}, {    383,11}, {    767,12}, \
+    {    415,11}, {    831,12}, {    479,14}, {    127,13}, \
+    {    255,12}, {    607,13}, {    319,12}, {    703,13}, \
+    {    383,12}, {    831,13}, {    447,12}, {    895,14}, \
+    {    255,13}, {    511,12}, {   1023,13}, {    703,14}, \
+    {    383,13}, {    831,12}, {   1663,13}, {    895,15}, \
+    {    255,14}, {    511,13}, {   1087,12}, {   2175,13}, \
+    {   1151,14}, {    639,13}, {   1343,12}, {   2687,13}, \
+    {   1407,14}, {    767,13}, {   1599,12}, {   3199,13}, \
+    {   1663,14}, {    895,15}, {    511,14}, {   1023,13}, \
+    {   2175,14}, {   1151,13}, {   2431,12}, {   4863,14}, \
+    {   1279,13}, {   2687,14}, {   1407,15}, {    767,14}, \
+    {   1535,13}, {   3199,14}, {   1663,13}, {   3455,16}, \
+    {    511,15}, {   1023,14}, {   2175,13}, {   4351,14}, \
+    {   2431,13}, {   4863,15}, {   1279,14}, {   2943,13}, \
+    {   5887,15}, {   1535,14}, {   3455,15}, {   1791,14}, \
+    {   3839,16}, {   1023,15}, {   2047,14}, {   4479,15}, \
+    {   2303,14}, {   4863,15}, {   2559,14}, {   5247,15}, \
+    {   2815,14}, {   5887,16}, {   1535,15}, {   3327,14}, \
+    {  16384,15}, {  32768,16}, {  65536,17}, { 131072,18}, \
+    { 262144,19}, { 524288,20}, {1048576,21}, {2097152,22}, \
+    {4194304,23}, {8388608,24} }
+#define SQR_FFT_TABLE3_SIZE 186
+#define SQR_FFT_THRESHOLD                 3712
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  42
+#define MULLO_MUL_N_THRESHOLD            10950
+#define SQRLO_BASECASE_THRESHOLD             7
+#define SQRLO_DC_THRESHOLD                 100
+#define SQRLO_SQR_THRESHOLD               7293
+
+#define DC_DIV_QR_THRESHOLD                 70
+#define DC_DIVAPPR_Q_THRESHOLD             204
+#define DC_BDIV_QR_THRESHOLD                59
+#define DC_BDIV_Q_THRESHOLD                148
+
+#define INV_MULMOD_BNM1_THRESHOLD           46
+#define INV_NEWTON_THRESHOLD               246
+#define INV_APPR_THRESHOLD                 236
+
+#define BINV_NEWTON_THRESHOLD              252
+#define REDC_1_TO_REDC_2_THRESHOLD          67
+#define REDC_2_TO_REDC_N_THRESHOLD           0  /* always */
+
+#define MU_DIV_QR_THRESHOLD               1589
+#define MU_DIVAPPR_Q_THRESHOLD            1589
+#define MUPI_DIV_QR_THRESHOLD              108
+#define MU_BDIV_QR_THRESHOLD              1442
+#define MU_BDIV_Q_THRESHOLD               1470
+
+#define POWM_SEC_TABLE  1,16,194,960,1603,1811,2499
+
+#define GET_STR_DC_THRESHOLD                20
+#define GET_STR_PRECOMPUTE_THRESHOLD        34
+#define SET_STR_DC_THRESHOLD               345
+#define SET_STR_PRECOMPUTE_THRESHOLD      1787
+
+#define FAC_DSC_THRESHOLD                  781
+#define FAC_ODD_THRESHOLD                  104
+
+#define MATRIX22_STRASSEN_THRESHOLD         17
+#define HGCD2_DIV1_METHOD                    3  /* 3.20% faster than 5 */
+#define HGCD_THRESHOLD                     110
+#define HGCD_APPR_THRESHOLD                 50
+#define HGCD_REDUCE_THRESHOLD             2681
+#define GCD_DC_THRESHOLD                   474
+#define GCDEXT_DC_THRESHOLD                293
+#define JACOBI_BASE_METHOD                   2  /* 9.38% faster than 1 */
+
+/* Tuneup completed successfully, took 358881 seconds */
diff --git a/third_party/gmp/mpn/x86_64/bt1/mul_1.asm b/third_party/gmp/mpn/x86_64/bt1/mul_1.asm
new file mode 100644
index 0000000..4394d6e
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/bt1/mul_1.asm
@@ -0,0 +1,241 @@
+dnl  AMD64 mpn_mul_1 optimised for AMD bt1/bt2.
+
+dnl  Copyright 2003-2005, 2007, 2008, 2011, 2012, 2019 Free Software
+dnl  Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 4.53		old measurement
+C AMD K10	 4.53		old measurement
+C AMD bd1	 4.56		old measurement
+C AMD bd2	 4.47		old measurement
+C AMD bd3	 ?
+C AMD bd4	 ?
+C AMD zen	 ?
+C AMD bt1	 5.12
+C AMD bt2	 5.17
+C Intel P4	12.6		old measurement
+C Intel PNR	 4.53		old measurement
+C Intel NHM	 4.36		old measurement
+C Intel SBR	 3.0		old measurement
+C Intel IBR	 2.55		old measurement
+C Intel HWL	 2.28		old measurement
+C Intel BWL	 2.36		old measurement
+C Intel SKL	 2.39		old measurement
+C Intel atom	21.0		old measurement
+C Intel SLM	 9		old measurement
+C Intel GLM	 ?
+C VIA nano	 ?
+
+C The loop of this code is the result of running a code generation and
+C optimisation tool suite written by David Harvey and Torbjorn Granlund.
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+C Standard parameters
+define(`rp',              `%rdi')
+define(`up',              `%rsi')
+define(`n_param',         `%rdx')
+define(`v0',              `%rcx')
+define(`cy',              `%r8')
+C Standard allocations
+define(`n',               `%rbx')
+define(`w0',              `%r8')
+define(`w1',              `%r9')
+define(`w2',              `%r10')
+define(`w3',              `%r11')
+
+C DOS64 parameters
+IFDOS(` define(`rp',      `%rcx')    ') dnl
+IFDOS(` define(`up',      `%rsi')    ') dnl
+IFDOS(` define(`n_param', `%r8')     ') dnl
+IFDOS(` define(`v0',      `%r9')     ') dnl
+IFDOS(` define(`cy',      `56(%rsp)')') dnl
+C DOS64 allocations
+IFDOS(` define(`n',       `%rbx')    ') dnl
+IFDOS(` define(`w0',      `%r8')     ') dnl
+IFDOS(` define(`w1',      `%rdi')    ') dnl
+IFDOS(` define(`w2',      `%r10')    ') dnl
+IFDOS(` define(`w3',      `%r11')    ') dnl
+
+	ALIGN(64)
+PROLOGUE(mpn_mul_1)
+IFDOS(`	push	%rsi		')
+IFDOS(`	push	%rdi		')
+IFDOS(`	mov	%rdx, %rsi	')
+
+	push	%rbx
+	mov	(up), %rax
+
+	lea	(rp,n_param,8), rp
+	lea	(up,n_param,8), up
+	mov	n_param, n
+
+	test	$1, R8(n_param)
+	jne	L(bx1)
+
+L(bx0):	mul	v0
+	neg	n
+	mov	%rax, w0
+	mov	%rdx, w1
+	test	$2, R8(n)
+	jne	L(L2)
+
+L(b00):	add	$2, n
+	jmp	L(L0)
+
+	ALIGN(16)
+L(b11):	mov	%rax, w2
+	mov	%rdx, w3
+	neg	n
+	inc	n
+	jmp	L(L3)
+
+	ALIGN(16)
+L(bx1):	mul	v0
+	test	$2, R8(n)
+	jne	L(b11)
+
+L(b01):	sub	$3, n
+	jc	L(n1)
+	mov	%rax, w2
+	mov	%rdx, w3
+	neg	n
+
+	ALIGN(16)
+L(top):	mov	-16(up,n,8), %rax
+	mul	v0
+	mov	%rax, w0
+	mov	%rdx, w1
+	mov	w2, -24(rp,n,8)
+	add	w3, w0
+	adc	$0, w1
+L(L0):	mov	-8(up,n,8), %rax
+	mul	v0
+	mov	%rax, w2
+	mov	%rdx, w3
+	mov	w0, -16(rp,n,8)
+	add	w1, w2
+	adc	$0, w3
+L(L3):	mov	(up,n,8), %rax
+	mul	v0
+	mov	%rax, w0
+	mov	%rdx, w1
+	mov	w2, -8(rp,n,8)
+	add	w3, w0
+	adc	$0, w1
+L(L2):	mov	8(up,n,8), %rax
+	mul	v0
+	mov	%rax, w2
+	mov	%rdx, w3
+	mov	w0, (rp,n,8)
+	add	w1, w2
+	adc	$0, w3
+	add	$4, n
+	js	L(top)
+
+L(end):	mov	w2, -8(rp)
+	mov	w3, %rax
+	pop	%rbx
+IFDOS(`	pop	%rdi		')
+IFDOS(`	pop	%rsi		')
+	ret
+
+	ALIGN(32)
+L(n1):	mov	%rax, -8(rp)
+	mov	%rdx, %rax
+	pop	%rbx
+IFDOS(`	pop	%rdi		')
+IFDOS(`	pop	%rsi		')
+	ret
+EPILOGUE()
+
+ASM_START()
+	TEXT
+	ALIGN(64)
+PROLOGUE(mpn_mul_1c)
+IFDOS(`	push	%rsi		')
+IFDOS(`	push	%rdi		')
+IFDOS(`	mov	%rdx, %rsi	')
+	mov	cy, w2
+	push	%rbx
+	mov	(up), %rax
+
+	lea	(rp,n_param,8), rp
+	lea	(up,n_param,8), up
+	mov	n_param, n
+
+	test	$1, R8(n_param)
+	jne	L(cx1)
+
+L(cx0):	mul	v0
+	neg	n
+	mov	%rax, w0
+	mov	%rdx, w1
+	add	w2, w0
+	adc	$0, w1
+	test	$2, R8(n)
+	jne	L(L2)
+
+L(c00):	add	$2, n
+	jmp	L(L0)
+
+	ALIGN(16)
+L(cx1):	mul	v0
+	test	$2, R8(n)
+	je	L(c01)
+
+L(c11):	neg	n
+	inc	n
+	add	%rax, w2
+	mov	%rdx, w3
+	adc	$0, w3
+	jmp	L(L3)
+
+L(c01):	cmp	$1, n
+	jz	L(m1)
+	neg	n
+	add	$3, n
+	add	%rax, w2
+	mov	%rdx, w3
+	adc	$0, w3
+	jmp	L(top)
+
+	ALIGN(32)
+L(m1):	add	%rax, w2
+	mov	%rdx, %rax
+	mov	w2, -8(rp)
+	adc	$0, %rax
+	pop	%rbx
+IFDOS(`	pop	%rdi		')
+IFDOS(`	pop	%rsi		')
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/bt1/mul_basecase.asm b/third_party/gmp/mpn/x86_64/bt1/mul_basecase.asm
new file mode 100644
index 0000000..e7d46bf
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/bt1/mul_basecase.asm
@@ -0,0 +1,486 @@
+dnl  AMD64 mpn_mul_basecase optimised for AMD bobcat.
+
+dnl  Copyright 2003-2005, 2007, 2008, 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 4.5
+C AMD K10	 4.5
+C AMD bd1	 4.75
+C AMD bobcat	 5
+C Intel P4	17.7
+C Intel core2	 5.5
+C Intel NHM	 5.43
+C Intel SBR	 3.92
+C Intel atom	23
+C VIA nano	 5.63
+
+C This mul_basecase is based on mul_1 and addmul_1, since these both run at the
+C multiply insn bandwidth, without any apparent loop branch exit pipeline
+C replays experienced on K8.  The structure is unusual: it falls into mul_1 in
+C the same way for all n, then it splits into 4 different wind-down blocks and
+C 4 separate addmul_1 loops.
+C
+C We have not tried using the same addmul_1 loops with a switch into feed-in
+C code, as we do in other basecase implementations.  Doing that could save
+C substantial code volume, but would also probably add some overhead.
+
+C TODO
+C  * Tune un < 3 code.
+C  * Fix slowdown for un=vn=3 (67->71) compared to default code.
+C  * This is 1263 bytes, compared to 1099 bytes for default code.  Consider
+C    combining addmul loops like that code.  Tolerable slowdown?
+C  * Lots of space could be saved by replacing the "switch" code by gradual
+C    jumps out from mul_1 winddown code, perhaps with no added overhead.
+C  * Are the ALIGN(16) really necessary?  They add about 25 bytes of padding.
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+C Standard parameters
+define(`rp',              `%rdi')
+define(`up',              `%rsi')
+define(`un_param',        `%rdx')
+define(`vp',              `%rcx')
+define(`vn',              `%r8')
+C Standard allocations
+define(`un',              `%rbx')
+define(`w0',              `%r10')
+define(`w1',              `%r11')
+define(`w2',              `%r12')
+define(`w3',              `%r13')
+define(`n',               `%rbp')
+define(`v0',              `%r9')
+
+C Temp macro for allowing control over indexing.
+C Define to return $1 for more conservative ptr handling.
+define(`X',`$2')
+
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_mul_basecase)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8d	')
+
+	mov	(up), %rax
+	mov	(vp), v0
+
+	cmp	$2, un_param
+	ja	L(ge3)
+	jz	L(u2)
+
+	mul	v0			C u0 x v0
+	mov	%rax, (rp)
+	mov	%rdx, 8(rp)
+	FUNC_EXIT()
+	ret
+
+L(u2):	mul	v0			C u0 x v0
+	mov	%rax, (rp)
+	mov	8(up), %rax
+	mov	%rdx, w0
+	mul	v0
+	add	%rax, w0
+	mov	%rdx, w1
+	adc	$0, w1
+	cmp	$1, R32(vn)
+	jnz	L(u2v2)
+	mov	w0, 8(rp)
+	mov	w1, 16(rp)
+	FUNC_EXIT()
+	ret
+
+L(u2v2):mov	8(vp), v0
+	mov	(up), %rax
+	mul	v0
+	add	%rax, w0
+	mov	w0, 8(rp)
+	mov	%rdx, %r8		C CAUTION: r8 realloc
+	adc	$0, %r8
+	mov	8(up), %rax
+	mul	v0
+	add	w1, %r8
+	adc	$0, %rdx
+	add	%r8, %rax
+	adc	$0, %rdx
+	mov	%rax, 16(rp)
+	mov	%rdx, 24(rp)
+	FUNC_EXIT()
+	ret
+
+
+L(ge3):	push	%rbx
+	push	%rbp
+	push	%r12
+	push	%r13
+
+	lea	8(vp), vp
+
+	lea	-24(rp,un_param,8), rp
+	lea	-24(up,un_param,8), up
+	xor	R32(un), R32(un)
+	mov	$2, R32(n)
+	sub	un_param, un
+	sub	un_param, n
+
+	mul	v0
+	mov	%rax, w2
+	mov	%rdx, w3
+	jmp	L(L3)
+
+	ALIGN(16)
+L(top):	mov	w0, -16(rp,n,8)
+	add	w1, w2
+	adc	$0, w3
+	mov	(up,n,8), %rax
+	mul	v0
+	mov	%rax, w0
+	mov	%rdx, w1
+	mov	w2, -8(rp,n,8)
+	add	w3, w0
+	adc	$0, w1
+	mov	8(up,n,8), %rax
+	mul	v0
+	mov	%rax, w2
+	mov	%rdx, w3
+	mov	w0, (rp,n,8)
+	add	w1, w2
+	adc	$0, w3
+L(L3):	mov	16(up,n,8), %rax
+	mul	v0
+	mov	%rax, w0
+	mov	%rdx, w1
+	mov	w2, 8(rp,n,8)
+	add	w3, w0
+	adc	$0, w1
+	mov	24(up,n,8), %rax
+	mul	v0
+	mov	%rax, w2
+	mov	%rdx, w3
+	add	$4, n
+	js	L(top)
+
+	mov	w0, -16(rp,n,8)
+	add	w1, w2
+	adc	$0, w3
+
+C Switch on n into right addmul_l loop
+	test	n, n
+	jz	L(r2)
+	cmp	$2, R32(n)
+	ja	L(r3)
+	jz	L(r0)
+	jmp	L(r1)
+
+
+L(r3):	mov	w2, X(-8(rp,n,8),16(rp))
+	mov	w3, X((rp,n,8),24(rp))
+	add	$2, un
+
+C outer loop(3)
+L(to3):	dec	vn
+	jz	L(ret)
+	mov	(vp), v0
+	mov	8(up,un,8), %rax
+	lea	8(vp), vp
+	lea	8(rp), rp
+	mov	un, n
+	mul	v0
+	mov	%rax, w2
+	mov	%rdx, w3
+	jmp	L(al3)
+
+	ALIGN(16)
+L(ta3):	add	w0, -16(rp,n,8)
+	adc	w1, w2
+	adc	$0, w3
+	mov	(up,n,8), %rax
+	mul	v0
+	mov	%rax, w0
+	mov	%rdx, w1
+	add	w2, -8(rp,n,8)
+	adc	w3, w0
+	adc	$0, w1
+	mov	8(up,n,8), %rax
+	mul	v0
+	mov	%rax, w2
+	mov	%rdx, w3
+	add	w0, (rp,n,8)
+	adc	w1, w2
+	adc	$0, w3
+L(al3):	mov	16(up,n,8), %rax
+	mul	v0
+	mov	%rax, w0
+	mov	%rdx, w1
+	add	w2, 8(rp,n,8)
+	adc	w3, w0
+	adc	$0, w1
+	mov	24(up,n,8), %rax
+	mul	v0
+	mov	%rax, w2
+	mov	%rdx, w3
+	add	$4, n
+	js	L(ta3)
+
+	add	w0, X(-16(rp,n,8),8(rp))
+	adc	w1, w2
+	adc	$0, w3
+	add	w2, X(-8(rp,n,8),16(rp))
+	adc	$0, w3
+	mov	w3, X((rp,n,8),24(rp))
+	jmp	L(to3)
+
+
+L(r2):	mov	X(0(up,n,8),(up)), %rax
+	mul	v0
+	mov	%rax, w0
+	mov	%rdx, w1
+	mov	w2, X(-8(rp,n,8),-8(rp))
+	add	w3, w0
+	adc	$0, w1
+	mov	X(8(up,n,8),8(up)), %rax
+	mul	v0
+	mov	%rax, w2
+	mov	%rdx, w3
+	mov	w0, X((rp,n,8),(rp))
+	add	w1, w2
+	adc	$0, w3
+	mov	X(16(up,n,8),16(up)), %rax
+	mul	v0
+	mov	%rax, w0
+	mov	%rdx, w1
+	mov	w2, X(8(rp,n,8),8(rp))
+	add	w3, w0
+	adc	$0, w1
+	mov	w0, X(16(rp,n,8),16(rp))
+	adc	$0, w3
+	mov	w1, X(24(rp,n,8),24(rp))
+	inc	un
+
+C outer loop(2)
+L(to2):	dec	vn
+	jz	L(ret)
+	mov	(vp), v0
+	mov	16(up,un,8), %rax
+	lea	8(vp), vp
+	lea	8(rp), rp
+	mov	un, n
+	mul	v0
+	mov	%rax, w0
+	mov	%rdx, w1
+	jmp	L(al2)
+
+	ALIGN(16)
+L(ta2):	add	w0, -16(rp,n,8)
+	adc	w1, w2
+	adc	$0, w3
+	mov	(up,n,8), %rax
+	mul	v0
+	mov	%rax, w0
+	mov	%rdx, w1
+	add	w2, -8(rp,n,8)
+	adc	w3, w0
+	adc	$0, w1
+	mov	8(up,n,8), %rax
+	mul	v0
+	mov	%rax, w2
+	mov	%rdx, w3
+	add	w0, (rp,n,8)
+	adc	w1, w2
+	adc	$0, w3
+	mov	16(up,n,8), %rax
+	mul	v0
+	mov	%rax, w0
+	mov	%rdx, w1
+	add	w2, 8(rp,n,8)
+	adc	w3, w0
+	adc	$0, w1
+L(al2):	mov	24(up,n,8), %rax
+	mul	v0
+	mov	%rax, w2
+	mov	%rdx, w3
+	add	$4, n
+	js	L(ta2)
+
+	add	w0, X(-16(rp,n,8),8(rp))
+	adc	w1, w2
+	adc	$0, w3
+	add	w2, X(-8(rp,n,8),16(rp))
+	adc	$0, w3
+	mov	w3, X((rp,n,8),24(rp))
+	jmp	L(to2)
+
+
+L(r1):	mov	X(0(up,n,8),8(up)), %rax
+	mul	v0
+	mov	%rax, w0
+	mov	%rdx, w1
+	mov	w2, X(-8(rp,n,8),(rp))
+	add	w3, w0
+	adc	$0, w1
+	mov	X(8(up,n,8),16(up)), %rax
+	mul	v0
+	mov	%rax, w2
+	mov	%rdx, w3
+	mov	w0, X((rp,n,8),8(rp))
+	add	w1, w2
+	adc	$0, w3
+	mov	w2, X(8(rp,n,8),16(rp))
+	mov	w3, X(16(rp,n,8),24(rp))
+	add	$4, un
+
+C outer loop(1)
+L(to1):	dec	vn
+	jz	L(ret)
+	mov	(vp), v0
+	mov	-8(up,un,8), %rax
+	lea	8(vp), vp
+	lea	8(rp), rp
+	mov	un, n
+	mul	v0
+	mov	%rax, w2
+	mov	%rdx, w3
+	jmp	L(al1)
+
+	ALIGN(16)
+L(ta1):	add	w0, -16(rp,n,8)
+	adc	w1, w2
+	adc	$0, w3
+L(al1):	mov	(up,n,8), %rax
+	mul	v0
+	mov	%rax, w0
+	mov	%rdx, w1
+	add	w2, -8(rp,n,8)
+	adc	w3, w0
+	adc	$0, w1
+	mov	8(up,n,8), %rax
+	mul	v0
+	mov	%rax, w2
+	mov	%rdx, w3
+	add	w0, (rp,n,8)
+	adc	w1, w2
+	adc	$0, w3
+	mov	16(up,n,8), %rax
+	mul	v0
+	mov	%rax, w0
+	mov	%rdx, w1
+	add	w2, 8(rp,n,8)
+	adc	w3, w0
+	adc	$0, w1
+	mov	24(up,n,8), %rax
+	mul	v0
+	mov	%rax, w2
+	mov	%rdx, w3
+	add	$4, n
+	js	L(ta1)
+
+	add	w0, X(-16(rp,n,8),8(rp))
+	adc	w1, w2
+	adc	$0, w3
+	add	w2, X(-8(rp,n,8),16(rp))
+	adc	$0, w3
+	mov	w3, X((rp,n,8),24(rp))
+	jmp	L(to1)
+
+
+L(r0):	mov	X((up,n,8),16(up)), %rax
+	mul	v0
+	mov	%rax, w0
+	mov	%rdx, w1
+	mov	w2, X(-8(rp,n,8),8(rp))
+	add	w3, w0
+	adc	$0, w1
+	mov	w0, X((rp,n,8),16(rp))
+	mov	w1, X(8(rp,n,8),24(rp))
+	add	$3, un
+
+C outer loop(0)
+L(to0):	dec	vn
+	jz	L(ret)
+	mov	(vp), v0
+	mov	(up,un,8), %rax
+	lea	8(vp), vp
+	lea	8(rp), rp
+	mov	un, n
+	mul	v0
+	mov	%rax, w0
+	mov	%rdx, w1
+	jmp	L(al0)
+
+	ALIGN(16)
+L(ta0):	add	w0, -16(rp,n,8)
+	adc	w1, w2
+	adc	$0, w3
+	mov	(up,n,8), %rax
+	mul	v0
+	mov	%rax, w0
+	mov	%rdx, w1
+	add	w2, -8(rp,n,8)
+	adc	w3, w0
+	adc	$0, w1
+L(al0):	mov	8(up,n,8), %rax
+	mul	v0
+	mov	%rax, w2
+	mov	%rdx, w3
+	add	w0, (rp,n,8)
+	adc	w1, w2
+	adc	$0, w3
+	mov	16(up,n,8), %rax
+	mul	v0
+	mov	%rax, w0
+	mov	%rdx, w1
+	add	w2, 8(rp,n,8)
+	adc	w3, w0
+	adc	$0, w1
+	mov	24(up,n,8), %rax
+	mul	v0
+	mov	%rax, w2
+	mov	%rdx, w3
+	add	$4, n
+	js	L(ta0)
+
+	add	w0, X(-16(rp,n,8),8(rp))
+	adc	w1, w2
+	adc	$0, w3
+	add	w2, X(-8(rp,n,8),16(rp))
+	adc	$0, w3
+	mov	w3, X((rp,n,8),24(rp))
+	jmp	L(to0)
+
+
+L(ret):	pop	%r13
+	pop	%r12
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/bt1/redc_1.asm b/third_party/gmp/mpn/x86_64/bt1/redc_1.asm
new file mode 100644
index 0000000..d55b1e5
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/bt1/redc_1.asm
@@ -0,0 +1,507 @@
+dnl  X86-64 mpn_redc_1 optimised for AMD bobcat.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2003-2005, 2007, 2008, 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 ?
+C AMD K10	 ?
+C AMD bull	 ?
+C AMD pile	 ?
+C AMD steam	 ?
+C AMD bobcat	 5.0
+C AMD jaguar	 ?
+C Intel P4	 ?
+C Intel core	 ?
+C Intel NHM	 ?
+C Intel SBR	 ?
+C Intel IBR	 ?
+C Intel HWL	 ?
+C Intel BWL	 ?
+C Intel atom	 ?
+C VIA nano	 ?
+
+C TODO
+C  * Micro-optimise, none performed thus far.
+C  * Consider inlining mpn_add_n.
+C  * Single basecases out before the pushes.
+
+C When playing with pointers, set this to $2 to fall back to conservative
+C indexing in wind-down code.
+define(`I',`$1')
+
+define(`rp',          `%rdi')   C rcx
+define(`up',          `%rsi')   C rdx
+define(`mp_param',    `%rdx')   C r8
+define(`n',           `%rcx')   C r9
+define(`u0inv',       `%r8')    C stack
+
+define(`i',           `%r14')
+define(`j',           `%r15')
+define(`mp',          `%r12')
+define(`q0',          `%r13')
+define(`w0',          `%rbp')
+define(`w1',          `%r9')
+define(`w2',          `%r10')
+define(`w3',          `%r11')
+
+C rax rbx rcx rdx rdi rsi rbp r8 r9 r10 r11 r12 r13 r14 r15
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+define(`ALIGNx', `ALIGN(16)')
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_redc_1)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8	')
+	push	%rbx
+	push	%rbp
+	push	%r12
+	push	%r13
+	push	%r14
+	push	%r15
+
+	mov	(up), q0
+	mov	n, j			C outer loop induction var
+	lea	(mp_param,n,8), mp
+	lea	(up,n,8), up
+	neg	n
+	imul	u0inv, q0		C first iteration q0
+
+	test	$1, R8(n)
+	jz	L(bx0)
+
+L(bx1):	test	$2, R8(n)
+	jz	L(b3)
+
+L(b1):	cmp	$-1, R32(n)
+	jz	L(n1)
+
+L(otp1):lea	1(n), i
+	mov	(mp,n,8), %rax
+	mul	q0
+	mov	%rax, w2
+	mov	%rdx, w3
+	mov	8(mp,n,8), %rax
+	mul	q0
+	mov	%rax, %rbx
+	mov	%rdx, w1
+	add	(up,n,8), w2
+	adc	w3, %rbx
+	adc	$0, w1
+	mov	16(mp,n,8), %rax
+	mul	q0
+	mov	%rax, w2
+	mov	%rdx, w3
+	add	8(up,n,8), %rbx
+	mov	%rbx, 8(up,n,8)
+	adc	w1, w2
+	adc	$0, w3
+	imul	u0inv, %rbx		C next q limb
+	jmp	L(e1)
+
+	ALIGNx
+L(tp1):	add	w0, -16(up,i,8)
+	adc	w1, w2
+	adc	$0, w3
+	mov	(mp,i,8), %rax
+	mul	q0
+	mov	%rax, w0
+	mov	%rdx, w1
+	add	w2, -8(up,i,8)
+	adc	w3, w0
+	adc	$0, w1
+	mov	8(mp,i,8), %rax
+	mul	q0
+	mov	%rax, w2
+	mov	%rdx, w3
+	add	w0, (up,i,8)
+	adc	w1, w2
+	adc	$0, w3
+L(e1):	mov	16(mp,i,8), %rax
+	mul	q0
+	mov	%rax, w0
+	mov	%rdx, w1
+	add	w2, 8(up,i,8)
+	adc	w3, w0
+	adc	$0, w1
+	mov	24(mp,i,8), %rax
+	mul	q0
+	mov	%rax, w2
+	mov	%rdx, w3
+	add	$4, i
+	js	L(tp1)
+
+L(ed1):	add	w0, I(-16(up),-16(up,i,8))
+	adc	w1, w2
+	adc	$0, w3
+	add	w2, I(-8(up),-8(up,i,8))
+	adc	$0, w3
+	mov	w3, (up,n,8)		C up[0]
+	mov	%rbx, q0		C previously computed q limb -> q0
+	lea	8(up), up		C up++
+	dec	j
+	jnz	L(otp1)
+	jmp	L(cj)
+
+L(b3):	cmp	$-3, R32(n)
+	jz	L(n3)
+
+L(otp3):lea	3(n), i
+	mov	(mp,n,8), %rax
+	mul	q0
+	mov	%rax, w2
+	mov	%rdx, w3
+	mov	8(mp,n,8), %rax
+	mul	q0
+	mov	%rax, %rbx
+	mov	%rdx, w1
+	add	(up,n,8), w2
+	adc	w3, %rbx
+	adc	$0, w1
+	mov	16(mp,n,8), %rax
+	mul	q0
+	mov	%rax, w2
+	mov	%rdx, w3
+	add	8(up,n,8), %rbx
+	mov	%rbx, 8(up,n,8)
+	adc	w1, w2
+	adc	$0, w3
+	imul	u0inv, %rbx		C next q limb
+	jmp	L(e3)
+
+	ALIGNx
+L(tp3):	add	w0, -16(up,i,8)
+	adc	w1, w2
+	adc	$0, w3
+L(e3):	mov	(mp,i,8), %rax
+	mul	q0
+	mov	%rax, w0
+	mov	%rdx, w1
+	add	w2, -8(up,i,8)
+	adc	w3, w0
+	adc	$0, w1
+	mov	8(mp,i,8), %rax
+	mul	q0
+	mov	%rax, w2
+	mov	%rdx, w3
+	add	w0, (up,i,8)
+	adc	w1, w2
+	adc	$0, w3
+	mov	16(mp,i,8), %rax
+	mul	q0
+	mov	%rax, w0
+	mov	%rdx, w1
+	add	w2, 8(up,i,8)
+	adc	w3, w0
+	adc	$0, w1
+	mov	24(mp,i,8), %rax
+	mul	q0
+	mov	%rax, w2
+	mov	%rdx, w3
+	add	$4, i
+	js	L(tp3)
+
+L(ed3):	add	w0, I(-16(up),-16(up,i,8))
+	adc	w1, w2
+	adc	$0, w3
+	add	w2, I(-8(up),-8(up,i,8))
+	adc	$0, w3
+	mov	w3, (up,n,8)		C up[0]
+	mov	%rbx, q0		C previously computed q limb -> q0
+	lea	8(up), up		C up++
+	dec	j
+	jnz	L(otp3)
+C	jmp	L(cj)
+
+L(cj):
+IFSTD(`	lea	(up,n,8), up		C param 2: up
+	lea	(up,n,8), %rdx		C param 3: up - n
+	neg	R32(n)		')	C param 4: n
+
+IFDOS(`	lea	(up,n,8), %rdx		C param 2: up
+	lea	(%rdx,n,8), %r8		C param 3: up - n
+	neg	R32(n)
+	mov	n, %r9			C param 4: n
+	mov	rp, %rcx	')	C param 1: rp
+
+IFSTD(`	sub	$8, %rsp	')
+IFDOS(`	sub	$40, %rsp	')
+	ASSERT(nz, `test $15, %rsp')
+	CALL(	mpn_add_n)
+IFSTD(`	add	$8, %rsp	')
+IFDOS(`	add	$40, %rsp	')
+
+L(ret):	pop	%r15
+	pop	%r14
+	pop	%r13
+	pop	%r12
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+
+L(bx0):	test	$2, R8(n)
+	jnz	L(b2)
+
+L(b0):
+L(otp0):lea	(n), i
+	mov	(mp,n,8), %rax
+	mul	q0
+	mov	%rax, w0
+	mov	%rdx, w1
+	mov	8(mp,n,8), %rax
+	mul	q0
+	mov	%rax, %rbx
+	mov	%rdx, w3
+	add	(up,n,8), w0
+	adc	w1, %rbx
+	adc	$0, w3
+	mov	16(mp,n,8), %rax
+	mul	q0
+	mov	%rax, w0
+	mov	%rdx, w1
+	add	8(up,n,8), %rbx
+	mov	%rbx, 8(up,n,8)
+	adc	w3, w0
+	adc	$0, w1
+	imul	u0inv, %rbx		C next q limb
+	jmp	L(e0)
+
+	ALIGNx
+L(tp0):	add	w0, -16(up,i,8)
+	adc	w1, w2
+	adc	$0, w3
+	mov	(mp,i,8), %rax
+	mul	q0
+	mov	%rax, w0
+	mov	%rdx, w1
+	add	w2, -8(up,i,8)
+	adc	w3, w0
+	adc	$0, w1
+	mov	8(mp,i,8), %rax
+	mul	q0
+	mov	%rax, w2
+	mov	%rdx, w3
+	add	w0, (up,i,8)
+	adc	w1, w2
+	adc	$0, w3
+	mov	16(mp,i,8), %rax
+	mul	q0
+	mov	%rax, w0
+	mov	%rdx, w1
+	add	w2, 8(up,i,8)
+	adc	w3, w0
+	adc	$0, w1
+L(e0):	mov	24(mp,i,8), %rax
+	mul	q0
+	mov	%rax, w2
+	mov	%rdx, w3
+	add	$4, i
+	js	L(tp0)
+
+L(ed0):	add	w0, I(-16(up),-16(up,i,8))
+	adc	w1, w2
+	adc	$0, w3
+	add	w2, I(-8(up),-8(up,i,8))
+	adc	$0, w3
+	mov	w3, (up,n,8)		C up[0]
+	mov	%rbx, q0		C previously computed q limb -> q0
+	lea	8(up), up		C up++
+	dec	j
+	jnz	L(otp0)
+	jmp	L(cj)
+
+L(b2):	cmp	$-2, R32(n)
+	jz	L(n2)
+
+L(otp2):lea	2(n), i
+	mov	(mp,n,8), %rax
+	mul	q0
+	mov	%rax, w0
+	mov	%rdx, w1
+	mov	8(mp,n,8), %rax
+	mul	q0
+	mov	%rax, %rbx
+	mov	%rdx, w3
+	add	(up,n,8), w0
+	adc	w1, %rbx
+	adc	$0, w3
+	mov	16(mp,n,8), %rax
+	mul	q0
+	mov	%rax, w0
+	mov	%rdx, w1
+	add	8(up,n,8), %rbx
+	mov	%rbx, 8(up,n,8)
+	adc	w3, w0
+	adc	$0, w1
+	imul	u0inv, %rbx		C next q limb
+	jmp	L(e2)
+
+	ALIGNx
+L(tp2):	add	w0, -16(up,i,8)
+	adc	w1, w2
+	adc	$0, w3
+	mov	(mp,i,8), %rax
+	mul	q0
+	mov	%rax, w0
+	mov	%rdx, w1
+	add	w2, -8(up,i,8)
+	adc	w3, w0
+	adc	$0, w1
+L(e2):	mov	8(mp,i,8), %rax
+	mul	q0
+	mov	%rax, w2
+	mov	%rdx, w3
+	add	w0, (up,i,8)
+	adc	w1, w2
+	adc	$0, w3
+	mov	16(mp,i,8), %rax
+	mul	q0
+	mov	%rax, w0
+	mov	%rdx, w1
+	add	w2, 8(up,i,8)
+	adc	w3, w0
+	adc	$0, w1
+	mov	24(mp,i,8), %rax
+	mul	q0
+	mov	%rax, w2
+	mov	%rdx, w3
+	add	$4, i
+	js	L(tp2)
+
+L(ed2):	add	w0, I(-16(up),-16(up,i,8))
+	adc	w1, w2
+	adc	$0, w3
+	add	w2, I(-8(up),-8(up,i,8))
+	adc	$0, w3
+	mov	w3, (up,n,8)		C up[0]
+	mov	%rbx, q0		C previously computed q limb -> q0
+	lea	8(up), up		C up++
+	dec	j
+	jnz	L(otp2)
+	jmp	L(cj)
+
+L(n1):	mov	(mp_param), %rax
+	mul	q0
+	add	-8(up), %rax
+	adc	(up), %rdx
+	mov	%rdx, (rp)
+	mov	$0, R32(%rax)
+	adc	R32(%rax), R32(%rax)
+	jmp	L(ret)
+
+L(n2):	mov	(mp_param), %rax
+	mov	-16(up), %rbp
+	mul	q0
+	add	%rax, %rbp
+	mov	%rdx, %r9
+	adc	$0, %r9
+	mov	-8(mp), %rax
+	mov	-8(up), %r10
+	mul	q0
+	add	%rax, %r10
+	mov	%rdx, %r11
+	adc	$0, %r11
+	add	%r9, %r10
+	adc	$0, %r11
+	mov	%r10, q0
+	imul	u0inv, q0		C next q0
+	mov	-16(mp), %rax
+	mul	q0
+	add	%rax, %r10
+	mov	%rdx, %r9
+	adc	$0, %r9
+	mov	-8(mp), %rax
+	mov	(up), %r14
+	mul	q0
+	add	%rax, %r14
+	adc	$0, %rdx
+	add	%r9, %r14
+	adc	$0, %rdx
+	xor	R32(%rax), R32(%rax)
+	add	%r11, %r14
+	adc	8(up), %rdx
+	mov	%r14, (rp)
+	mov	%rdx, 8(rp)
+	adc	R32(%rax), R32(%rax)
+	jmp	L(ret)
+
+	ALIGNx
+L(n3):	mov	-24(mp), %rax
+	mov	-24(up), %r10
+	mul	q0
+	add	%rax, %r10
+	mov	-16(mp), %rax
+	mov	%rdx, %r11
+	adc	$0, %r11
+	mov	-16(up), %rbp
+	mul	q0
+	add	%rax, %rbp
+	mov	%rdx, %r9
+	adc	$0, %r9
+	mov	-8(mp), %rax
+	add	%r11, %rbp
+	mov	-8(up), %r10
+	adc	$0, %r9
+	mul	q0
+	mov	%rbp, q0
+	imul	u0inv, q0		C next q0
+	add	%rax, %r10
+	mov	%rdx, %r11
+	adc	$0, %r11
+	mov	%rbp, -16(up)
+	add	%r9, %r10
+	adc	$0, %r11
+	mov	%r10, -8(up)
+	mov	%r11, -24(up)		C up[0]
+	lea	8(up), up		C up++
+	dec	j
+	jnz	L(n3)
+
+	mov	-48(up), %rdx
+	mov	-40(up), %rbx
+	xor	R32(%rax), R32(%rax)
+	add	%rbp, %rdx
+	adc	%r10, %rbx
+	adc	-8(up), %r11
+	mov	%rdx, (rp)
+	mov	%rbx, 8(rp)
+	mov	%r11, 16(rp)
+	adc	R32(%rax), R32(%rax)
+	jmp	L(ret)
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86_64/bt1/sqr_basecase.asm b/third_party/gmp/mpn/x86_64/bt1/sqr_basecase.asm
new file mode 100644
index 0000000..0e417a1
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/bt1/sqr_basecase.asm
@@ -0,0 +1,565 @@
+dnl  AMD64 mpn_sqr_basecase optimised for AMD bobcat.
+
+dnl  Copyright 2003-2005, 2007, 2008, 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 4.5
+C AMD K10	 4.5
+C AMD bd1	 4.75
+C AMD bobcat	 5
+C Intel P4	17.7
+C Intel core2	 5.5
+C Intel NHM	 5.43
+C Intel SBR	 3.92
+C Intel atom	23
+C VIA nano	 5.63
+
+C This sqr_basecase is based on mul_1 and addmul_1, since these both run at the
+C multiply insn bandwidth, without any apparent loop branch exit pipeline
+C replays experienced on K8.  The structure is unusual: it falls into mul_1 in
+C the same way for all n, then it splits into 4 different wind-down blocks and
+C 4 separate addmul_1 loops.
+C
+C We have not tried using the same addmul_1 loops with a switch into feed-in
+C code, as we do in other basecase implementations.  Doing that could save
+C substantial code volume, but would also probably add some overhead.
+
+C TODO
+C  * Tune un < 4 code.
+C  * Perhaps implement a larger final corner (it is now 2 x 1).
+C  * Lots of space could be saved by replacing the "switch" code by gradual
+C    jumps out from mul_1 winddown code, perhaps with no added overhead.
+C  * Are the ALIGN(16) really necessary?  They add about 25 bytes of padding.
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+C Standard parameters
+define(`rp',              `%rdi')
+define(`up',              `%rsi')
+define(`un_param',        `%rdx')
+C Standard allocations
+define(`un',              `%rbx')
+define(`w0',              `%r8')
+define(`w1',              `%r9')
+define(`w2',              `%r10')
+define(`w3',              `%r11')
+define(`n',               `%rbp')
+define(`v0',              `%rcx')
+
+C Temp macro for allowing control over indexing.
+C Define to return $1 for more conservative ptr handling.
+define(`X',`$2')
+dnl define(`X',`$1')
+
+
+ASM_START()
+	TEXT
+	ALIGN(64)
+PROLOGUE(mpn_sqr_basecase)
+	FUNC_ENTRY(3)
+
+	mov	(up), %rax
+
+	cmp	$2, R32(un_param)
+	jae	L(ge2)
+
+	mul	%rax
+	mov	%rax, (rp)
+	mov	%rdx, 8(rp)
+	FUNC_EXIT()
+	ret
+
+L(ge2):	mov	(up), v0
+	jnz	L(g2)
+
+	mul	%rax
+	mov	%rax, (rp)
+	mov	8(up), %rax
+	mov	%rdx, w0
+	mul	v0
+	add	%rax, w0
+	mov	%rdx, w1
+	adc	$0, w1
+	mov	8(up), v0
+	mov	(up), %rax
+	mul	v0
+	add	%rax, w0
+	mov	w0, 8(rp)
+	mov	%rdx, w0		C CAUTION: r8 realloc
+	adc	$0, w0
+	mov	8(up), %rax
+	mul	v0
+	add	w1, w0
+	adc	$0, %rdx
+	add	w0, %rax
+	adc	$0, %rdx
+	mov	%rax, 16(rp)
+	mov	%rdx, 24(rp)
+	FUNC_EXIT()
+	ret
+
+L(g2):	cmp	$3, R32(un_param)
+	ja	L(g3)
+	mul	%rax
+	mov	%rax, (rp)
+	mov	%rdx, 8(rp)
+	mov	8(up), %rax
+	mul	%rax
+	mov	%rax, 16(rp)
+	mov	%rdx, 24(rp)
+	mov	16(up), %rax
+	mul	%rax
+	mov	%rax, 32(rp)
+	mov	%rdx, 40(rp)
+
+	mov	(up), v0
+	mov	8(up), %rax
+	mul	v0
+	mov	%rax, w0
+	mov	%rdx, w1
+	mov	16(up), %rax
+	mul	v0
+	xor	R32(w2), R32(w2)
+	add	%rax, w1
+	adc	%rdx, w2
+
+	mov	8(up), v0
+	mov	16(up), %rax
+	mul	v0
+	xor	R32(w3), R32(w3)
+	add	%rax, w2
+	adc	%rdx, w3
+	add	w0, w0
+	adc	w1, w1
+	adc	w2, w2
+	adc	w3, w3
+	mov	$0, R32(v0)
+	adc	v0, v0
+	add	w0, 8(rp)
+	adc	w1, 16(rp)
+	adc	w2, 24(rp)
+	adc	w3, 32(rp)
+	adc	v0, 40(rp)
+	FUNC_EXIT()
+	ret
+
+L(g3):	push	%rbx
+	push	%rbp
+
+	mov	8(up), %rax
+	lea	-24(rp,un_param,8), rp
+	lea	-24(up,un_param,8), up
+	neg	un_param
+	push	un_param		C for sqr_diag_addlsh1
+	lea	(un_param), un
+	lea	3(un_param), n
+
+	mul	v0
+	mov	%rax, w2
+	mov	%rdx, w3
+	jmp	L(L3)
+
+	ALIGN(16)
+L(top):	mov	w0, -16(rp,n,8)
+	add	w1, w2
+	adc	$0, w3
+	mov	(up,n,8), %rax
+	mul	v0
+	mov	%rax, w0
+	mov	%rdx, w1
+	mov	w2, -8(rp,n,8)
+	add	w3, w0
+	adc	$0, w1
+	mov	8(up,n,8), %rax
+	mul	v0
+	mov	%rax, w2
+	mov	%rdx, w3
+	mov	w0, (rp,n,8)
+	add	w1, w2
+	adc	$0, w3
+L(L3):	mov	16(up,n,8), %rax
+	mul	v0
+	mov	%rax, w0
+	mov	%rdx, w1
+	mov	w2, 8(rp,n,8)
+	add	w3, w0
+	adc	$0, w1
+	mov	24(up,n,8), %rax
+	mul	v0
+	mov	%rax, w2
+	mov	%rdx, w3
+	add	$4, n
+	js	L(top)
+
+	mov	w0, -16(rp,n,8)
+	add	w1, w2
+	adc	$0, w3
+
+	test	n, n
+	jz	L(r2)
+	cmp	$2, R32(n)
+	ja	L(r3)
+	jz	L(r0)
+
+
+L(r1):	mov	X((up,n,8),8(up)), %rax
+	mul	v0
+	mov	%rax, w0
+	mov	%rdx, w1
+	mov	w2, X(-8(rp,n,8),(rp))
+	add	w3, w0
+	adc	$0, w1
+	mov	X(8(up,n,8),16(up)), %rax
+	mul	v0
+	mov	%rax, w2
+	mov	%rdx, w3
+	mov	w0, X((rp,n,8),8(rp))
+	add	w1, w2
+	adc	$0, w3
+	mov	w2, X(8(rp,n,8),16(rp))
+	mov	w3, X(16(rp,n,8),24(rp))
+	add	$5, un
+	jmp	L(to0)
+
+L(r2):	mov	X((up,n,8),(up)), %rax
+	mul	v0
+	mov	%rax, w0
+	mov	%rdx, w1
+	mov	w2, X(-8(rp,n,8),-8(rp))
+	add	w3, w0
+	adc	$0, w1
+	mov	X(8(up,n,8),8(up)), %rax
+	mul	v0
+	mov	%rax, w2
+	mov	%rdx, w3
+	mov	w0, X((rp,n,8),(rp))
+	add	w1, w2
+	adc	$0, w3
+	mov	X(16(up,n,8),16(up)), %rax
+	mul	v0
+	mov	%rax, w0
+	mov	%rdx, w1
+	mov	w2, X(8(rp,n,8),8(rp))
+	add	w3, w0
+	adc	$0, w1
+	mov	w0, X(16(rp,n,8),16(rp))
+	adc	$0, w3
+	mov	w1, X(24(rp,n,8),24(rp))
+	add	$6, un
+	jmp	L(to1)
+
+L(r3):	mov	w2, X(-8(rp,n,8),16(rp))
+	mov	w3, X((rp,n,8),24(rp))
+	add	$3, un
+	jmp	L(to2)
+
+L(r0):	mov	X((up,n,8),16(up)), %rax
+	mul	v0
+	mov	%rax, w0
+	mov	%rdx, w1
+	mov	w2, X(-8(rp,n,8),8(rp))
+	add	w3, w0
+	adc	$0, w1
+	mov	w0, X((rp,n,8),16(rp))
+	mov	w1, X(8(rp,n,8),24(rp))
+	add	$4, un
+C	jmp	L(to3)
+C fall through into main loop
+
+
+L(outer):
+	mov	un, n
+	mov	(up,un,8), v0
+	mov	8(up,un,8), %rax
+	lea	8(rp), rp
+	mul	v0
+	mov	%rax, w2
+	mov	%rdx, w3
+	jmp	L(al3)
+
+	ALIGN(16)
+L(ta3):	add	w0, -16(rp,n,8)
+	adc	w1, w2
+	adc	$0, w3
+	mov	(up,n,8), %rax
+	mul	v0
+	mov	%rax, w0
+	mov	%rdx, w1
+	add	w2, -8(rp,n,8)
+	adc	w3, w0
+	adc	$0, w1
+	mov	8(up,n,8), %rax
+	mul	v0
+	mov	%rax, w2
+	mov	%rdx, w3
+	add	w0, (rp,n,8)
+	adc	w1, w2
+	adc	$0, w3
+L(al3):	mov	16(up,n,8), %rax
+	mul	v0
+	mov	%rax, w0
+	mov	%rdx, w1
+	add	w2, 8(rp,n,8)
+	adc	w3, w0
+	adc	$0, w1
+	mov	24(up,n,8), %rax
+	mul	v0
+	mov	%rax, w2
+	mov	%rdx, w3
+	add	$4, n
+	js	L(ta3)
+
+	add	w0, X(-16(rp,n,8),8(rp))
+	adc	w1, w2
+	adc	$0, w3
+	add	w2, X(-8(rp,n,8),16(rp))
+	adc	$0, w3
+	mov	w3, X((rp,n,8),24(rp))
+
+
+L(to2):	mov	un, n
+	cmp	$-4, R32(un)
+	jnc	L(end)
+	add	$4, un
+	mov	8(up,n,8), v0
+	mov	16(up,n,8), %rax
+	lea	8(rp), rp
+	mul	v0
+	mov	%rax, w0
+	mov	%rdx, w1
+	jmp	L(al2)
+
+	ALIGN(16)
+L(ta2):	add	w0, -16(rp,n,8)
+	adc	w1, w2
+	adc	$0, w3
+	mov	(up,n,8), %rax
+	mul	v0
+	mov	%rax, w0
+	mov	%rdx, w1
+	add	w2, -8(rp,n,8)
+	adc	w3, w0
+	adc	$0, w1
+	mov	8(up,n,8), %rax
+	mul	v0
+	mov	%rax, w2
+	mov	%rdx, w3
+	add	w0, (rp,n,8)
+	adc	w1, w2
+	adc	$0, w3
+	mov	16(up,n,8), %rax
+	mul	v0
+	mov	%rax, w0
+	mov	%rdx, w1
+	add	w2, 8(rp,n,8)
+	adc	w3, w0
+	adc	$0, w1
+L(al2):	mov	24(up,n,8), %rax
+	mul	v0
+	mov	%rax, w2
+	mov	%rdx, w3
+	add	$4, n
+	js	L(ta2)
+
+	add	w0, X(-16(rp,n,8),8(rp))
+	adc	w1, w2
+	adc	$0, w3
+	add	w2, X(-8(rp,n,8),16(rp))
+	adc	$0, w3
+	mov	w3, X((rp,n,8),24(rp))
+
+
+L(to1):	mov	un, n
+	mov	-16(up,un,8), v0
+	mov	-8(up,un,8), %rax
+	lea	8(rp), rp
+	mul	v0
+	mov	%rax, w2
+	mov	%rdx, w3
+	jmp	L(al1)
+
+	ALIGN(16)
+L(ta1):	add	w0, -16(rp,n,8)
+	adc	w1, w2
+	adc	$0, w3
+L(al1):	mov	(up,n,8), %rax
+	mul	v0
+	mov	%rax, w0
+	mov	%rdx, w1
+	add	w2, -8(rp,n,8)
+	adc	w3, w0
+	adc	$0, w1
+	mov	8(up,n,8), %rax
+	mul	v0
+	mov	%rax, w2
+	mov	%rdx, w3
+	add	w0, (rp,n,8)
+	adc	w1, w2
+	adc	$0, w3
+	mov	16(up,n,8), %rax
+	mul	v0
+	mov	%rax, w0
+	mov	%rdx, w1
+	add	w2, 8(rp,n,8)
+	adc	w3, w0
+	adc	$0, w1
+	mov	24(up,n,8), %rax
+	mul	v0
+	mov	%rax, w2
+	mov	%rdx, w3
+	add	$4, n
+	js	L(ta1)
+
+	add	w0, X(-16(rp,n,8),8(rp))
+	adc	w1, w2
+	adc	$0, w3
+	add	w2, X(-8(rp,n,8),16(rp))
+	adc	$0, w3
+	mov	w3, X((rp,n,8),24(rp))
+
+
+L(to0):	mov	un, n
+	mov	-8(up,un,8), v0
+	mov	(up,un,8), %rax
+	lea	8(rp), rp
+	mul	v0
+	mov	%rax, w0
+	mov	%rdx, w1
+	jmp	L(al0)
+
+	ALIGN(16)
+L(ta0):	add	w0, -16(rp,n,8)
+	adc	w1, w2
+	adc	$0, w3
+	mov	(up,n,8), %rax
+	mul	v0
+	mov	%rax, w0
+	mov	%rdx, w1
+	add	w2, -8(rp,n,8)
+	adc	w3, w0
+	adc	$0, w1
+L(al0):	mov	8(up,n,8), %rax
+	mul	v0
+	mov	%rax, w2
+	mov	%rdx, w3
+	add	w0, (rp,n,8)
+	adc	w1, w2
+	adc	$0, w3
+	mov	16(up,n,8), %rax
+	mul	v0
+	mov	%rax, w0
+	mov	%rdx, w1
+	add	w2, 8(rp,n,8)
+	adc	w3, w0
+	adc	$0, w1
+	mov	24(up,n,8), %rax
+	mul	v0
+	mov	%rax, w2
+	mov	%rdx, w3
+	add	$4, n
+	js	L(ta0)
+
+	add	w0, X(-16(rp,n,8),8(rp))
+	adc	w1, w2
+	adc	$0, w3
+	add	w2, X(-8(rp,n,8),16(rp))
+	adc	$0, w3
+	mov	w3, X((rp,n,8),24(rp))
+	jmp	L(outer)
+
+
+L(end):	mov	X(8(up,un,8),(up)), v0
+	mov	X(16(up,un,8),8(up)), %rax
+	mul	v0
+	mov	%rax, w0
+	mov	%rdx, w1
+	mov	X(24(up,un,8),16(up)), %rax
+	mul	v0
+	mov	%rax, w2
+	mov	%rdx, w3
+	add	w0, X(24(rp,un,8),16(rp))
+	adc	w1, w2
+	adc	$0, w3
+	add	w2, X(32(rp,un,8),24(rp))
+	adc	$0, w3
+	mov	X(16(up,un,8),8(up)), v0
+	mov	X(24(up,un,8),16(up)), %rax
+	mul	v0
+	add	%rax, w3
+	mov	w3, X(40(rp,un,8),32(rp))
+	adc	$0, %rdx
+	mov	%rdx, X(48(rp,un,8),40(rp))
+
+
+C sqr_diag_addlsh1
+
+	lea	16(up), up
+	lea	40(rp), rp
+	pop	n
+	lea	2(n,n), n
+
+	mov	(up,n,4), %rax
+	mul	%rax
+	xor	R32(w2), R32(w2)
+
+	mov	8(rp,n,8), w0
+	mov	%rax, (rp,n,8)
+	jmp	L(lm)
+
+	ALIGN(8)
+L(tsd):	add	%rbx, w0
+	adc	%rax, w1
+	mov	w0, -8(rp,n,8)
+	mov	8(rp,n,8), w0
+	mov	w1, (rp,n,8)
+L(lm):	mov	16(rp,n,8), w1
+	adc	w0, w0
+	adc	w1, w1
+	lea	(%rdx,w2), %rbx
+	mov	8(up,n,4), %rax
+	setc	R8(w2)
+	mul	%rax
+	add	$2, n
+	js	L(tsd)
+
+L(esd):	add	%rbx, w0
+	adc	%rax, w1
+	mov	w0, X(-8(rp,n,8),-8(rp))
+	mov	w1, X((rp,n,8),(rp))
+	adc	w2, %rdx
+	mov	%rdx, X(8(rp,n,8),8(rp))
+
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/bt2/com.asm b/third_party/gmp/mpn/x86_64/bt2/com.asm
new file mode 100644
index 0000000..87085ea
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/bt2/com.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_com.
+
+dnl  Copyright 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_com)
+include_mpn(`x86_64/fastsse/com.asm')
diff --git a/third_party/gmp/mpn/x86_64/bt2/copyd.asm b/third_party/gmp/mpn/x86_64/bt2/copyd.asm
new file mode 100644
index 0000000..83c0618
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/bt2/copyd.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_copyd.
+
+dnl  Copyright 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_copyd)
+include_mpn(`x86_64/fastsse/copyd.asm')
diff --git a/third_party/gmp/mpn/x86_64/bt2/copyi.asm b/third_party/gmp/mpn/x86_64/bt2/copyi.asm
new file mode 100644
index 0000000..148d0e5
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/bt2/copyi.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_copyi.
+
+dnl  Copyright 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_copyi)
+include_mpn(`x86_64/fastsse/copyi.asm')
diff --git a/third_party/gmp/mpn/x86_64/bt2/gcd_11.asm b/third_party/gmp/mpn/x86_64/bt2/gcd_11.asm
new file mode 100644
index 0000000..0ffb6ca
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/bt2/gcd_11.asm
@@ -0,0 +1,37 @@
+dnl  AMD64 mpn_gcd_11.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_gcd_11)
+include_mpn(`x86_64/bd2/gcd_11.asm')
diff --git a/third_party/gmp/mpn/x86_64/bt2/gcd_22.asm b/third_party/gmp/mpn/x86_64/bt2/gcd_22.asm
new file mode 100644
index 0000000..d693628
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/bt2/gcd_22.asm
@@ -0,0 +1,37 @@
+dnl  AMD64 mpn_gcd_22.
+
+dnl  Copyright 2019 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+dnl ABI_SUPPORT(DOS64)	C returns mp_double_limb_t in memory
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_gcd_22)
+include_mpn(`x86_64/bd2/gcd_22.asm')
diff --git a/third_party/gmp/mpn/x86_64/bt2/gmp-mparam.h b/third_party/gmp/mpn/x86_64/bt2/gmp-mparam.h
new file mode 100644
index 0000000..3e26726
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/bt2/gmp-mparam.h
@@ -0,0 +1,240 @@
+/* AMD Jaguar gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+/* Disable use of slow functions.  FIXME: We should disable lib inclusion.  */
+#undef HAVE_NATIVE_mpn_mul_2
+#undef HAVE_NATIVE_mpn_addmul_2
+
+/* 2050 MHz AMD Jaguar/Kabini */
+/* FFT tuning limit = 225,381,546 */
+/* Generated by tuneup.c, 2019-10-18, gcc 8.3 */
+
+#define MOD_1_NORM_THRESHOLD                 3
+#define MOD_1_UNNORM_THRESHOLD               4
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          4
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          4
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        65
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD         0  /* never mpn_mod_1s_2p */
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     10
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1_NORM_THRESHOLD              4
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           15
+
+#define DIV_1_VS_MUL_1_PERCENT             267
+
+#define MUL_TOOM22_THRESHOLD                25
+#define MUL_TOOM33_THRESHOLD                32
+#define MUL_TOOM44_THRESHOLD                93
+#define MUL_TOOM6H_THRESHOLD               366
+#define MUL_TOOM8H_THRESHOLD               537
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      63
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     172
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD      63
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD      67
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD      91
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 20
+#define SQR_TOOM3_THRESHOLD                 97
+#define SQR_TOOM4_THRESHOLD                220
+#define SQR_TOOM6_THRESHOLD                318
+#define SQR_TOOM8_THRESHOLD                434
+
+#define MULMID_TOOM42_THRESHOLD             20
+
+#define MULMOD_BNM1_THRESHOLD               11
+#define SQRMOD_BNM1_THRESHOLD               13
+
+#define MUL_FFT_MODF_THRESHOLD             348  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    348, 5}, {     17, 6}, {      9, 5}, {     19, 6}, \
+    {     23, 7}, {     21, 8}, {     11, 7}, {     24, 8}, \
+    {     13, 7}, {     28, 8}, {     15, 7}, {     31, 8}, \
+    {     17, 7}, {     35, 8}, {     19, 7}, {     39, 8}, \
+    {     21, 9}, {     11, 8}, {     29, 9}, {     15, 8}, \
+    {     35, 9}, {     19, 8}, {     41, 9}, {     23, 8}, \
+    {     49, 9}, {     27,10}, {     15, 9}, {     39,10}, \
+    {     23, 9}, {     55,11}, {     15,10}, {     31, 9}, \
+    {     67,10}, {     39, 9}, {     79,10}, {     55,11}, \
+    {     31,10}, {     63, 6}, {   1087, 8}, {    303, 9}, \
+    {    159,10}, {     95,12}, {     31,11}, {     63,10}, \
+    {    127, 9}, {    255,11}, {     79,10}, {    159, 9}, \
+    {    319,10}, {    167,11}, {     95,10}, {    191, 9}, \
+    {    383,10}, {    207, 9}, {    415,11}, {    111,12}, \
+    {     63,11}, {    127,10}, {    255, 9}, {    511,10}, \
+    {    271,11}, {    143,10}, {    287, 9}, {    575,10}, \
+    {    303,11}, {    159,10}, {    319,12}, {     95,11}, \
+    {    191,10}, {    383,11}, {    207,10}, {    415,11}, \
+    {    223,13}, {     63,12}, {    127,11}, {    255,10}, \
+    {    511,11}, {    271,10}, {    543,11}, {    287,10}, \
+    {    575,11}, {    303,12}, {    159,11}, {    319,10}, \
+    {    639,11}, {    351,12}, {    191,11}, {    415,12}, \
+    {    223,11}, {    479,13}, {    127,12}, {    255,11}, \
+    {    543,12}, {    287,11}, {    607,12}, {    319,11}, \
+    {    639,12}, {    351,13}, {    191,12}, {    383,11}, \
+    {    767,12}, {    415,11}, {    831,12}, {    479,14}, \
+    {    127,13}, {    255,12}, {    543,11}, {   1087,12}, \
+    {    607,13}, {    319,12}, {    703,13}, {    383,12}, \
+    {    831,13}, {    447,12}, {    895,14}, {    255,13}, \
+    {    511,12}, {   1023,13}, {    575,12}, {   1151,13}, \
+    {    639,12}, {   1279,13}, {    703,14}, {    383,13}, \
+    {    831,12}, {   1663,13}, {    895,15}, {    255,14}, \
+    {    511,13}, {   1087,12}, {   2175,13}, {   1151,14}, \
+    {    639,13}, {   1343,12}, {   2687,14}, {    767,13}, \
+    {   1663,14}, {    895,15}, {    511,14}, {   1023,13}, \
+    {   2175,14}, {   1151,13}, {   2431,14}, {   1279,13}, \
+    {   2687,15}, {    767,14}, {   1663,13}, {   3327,16}, \
+    {    511,15}, {   1023,14}, {   2175,13}, {   4351,14}, \
+    {   2431,13}, {   4863,15}, {   1279,14}, {   2943,13}, \
+    {   5887,15}, {   1535,14}, {   3455,13}, {   6911,15}, \
+    {   1791,14}, {   3839,13}, {   7679,16}, {   1023,15}, \
+    {   2047,14}, {   4223,13}, {   8447,14}, {   4479,15}, \
+    {   2303,14}, {   4863,15}, {   2559,14}, {   5247,15}, \
+    {   2815,14}, {   5887,16}, {   1535,15}, {   3071,14}, \
+    {   6271,15}, {   3327,14}, {   6911,15}, {   3839,14}, \
+    {   7679,17}, {   1023,16}, {   2047,15}, {   4095,14}, \
+    {   8447,15}, {   4351,14}, {   8959,15}, {   4863,16}, \
+    {   2559,15}, {   5887,14}, {  11775,16}, {   3071,15}, \
+    {  32768,16}, {  65536,17}, { 131072,18}, { 262144,19}, \
+    { 524288,20}, {1048576,21}, {2097152,22}, {4194304,23}, \
+    {8388608,24} }
+#define MUL_FFT_TABLE3_SIZE 201
+#define MUL_FFT_THRESHOLD                 3200
+
+#define SQR_FFT_MODF_THRESHOLD             340  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    340, 5}, {     19, 6}, {     10, 5}, {     21, 6}, \
+    {     11, 5}, {     23, 6}, {     21, 7}, {     11, 6}, \
+    {     23, 7}, {     12, 6}, {     25, 7}, {     13, 6}, \
+    {     27, 7}, {     21, 8}, {     11, 7}, {     25, 8}, \
+    {     13, 7}, {     27, 8}, {     15, 7}, {     31, 8}, \
+    {     21, 9}, {     11, 8}, {     27, 9}, {     15, 8}, \
+    {     35, 9}, {     19, 8}, {     41, 9}, {     23, 8}, \
+    {     47, 9}, {     27,10}, {     15, 9}, {     39,10}, \
+    {     23, 9}, {     51,11}, {     15,10}, {     31, 9}, \
+    {     63,10}, {     39, 9}, {     79,10}, {     47,11}, \
+    {     31,10}, {     79,11}, {     47,10}, {     95, 6}, \
+    {   1663, 7}, {    895, 9}, {    239, 8}, {    479,10}, \
+    {    127, 9}, {    255, 8}, {    511,10}, {    135, 9}, \
+    {    271,11}, {     79, 9}, {    319,11}, {     95,10}, \
+    {    191, 9}, {    383,10}, {    207,11}, {    111,12}, \
+    {     63,11}, {    127,10}, {    255, 9}, {    511,10}, \
+    {    271, 9}, {    543,10}, {    287, 9}, {    575,10}, \
+    {    303, 9}, {    607,10}, {    319, 9}, {    639,12}, \
+    {     95,11}, {    191,10}, {    383,11}, {    207,10}, \
+    {    415,13}, {     63,12}, {    127,11}, {    255,10}, \
+    {    511,11}, {    271,10}, {    543,11}, {    287,10}, \
+    {    575,11}, {    303,10}, {    607,11}, {    319,10}, \
+    {    639,11}, {    351,10}, {    703,11}, {    367,12}, \
+    {    191,11}, {    383,10}, {    767,11}, {    415,12}, \
+    {    223,11}, {    479,13}, {    127,12}, {    255,11}, \
+    {    543,12}, {    287,11}, {    607,12}, {    319,11}, \
+    {    639,12}, {    351,11}, {    703,13}, {    191,12}, \
+    {    383,11}, {    767,12}, {    415,11}, {    831,12}, \
+    {    479,14}, {    127,13}, {    255,12}, {    607,13}, \
+    {    319,12}, {    735,13}, {    383,12}, {    831,13}, \
+    {    447,12}, {    895,14}, {    255,13}, {    511,12}, \
+    {   1023,13}, {    575,12}, {   1151,13}, {    703,14}, \
+    {    383,13}, {    831,12}, {   1663,13}, {    895,15}, \
+    {    255,14}, {    511,13}, {   1087,12}, {   2175,13}, \
+    {   1151,14}, {    639,13}, {   1343,12}, {   2687,13}, \
+    {   1407,14}, {    767,13}, {   1599,12}, {   3199,13}, \
+    {   1663,14}, {    895,15}, {    511,14}, {   1023,13}, \
+    {   2175,14}, {   1151,13}, {   2431,14}, {   1279,13}, \
+    {   2687,14}, {   1407,15}, {    767,14}, {   1535,13}, \
+    {   3199,14}, {   1663,13}, {   3455,16}, {    511,15}, \
+    {   1023,14}, {   2175,13}, {   4479,14}, {   2431,13}, \
+    {   4863,15}, {   1279,14}, {   2943,13}, {   5887,15}, \
+    {   1535,14}, {   3455,13}, {   6911,15}, {   1791,14}, \
+    {   3839,13}, {   7679,16}, {   1023,15}, {   2047,14}, \
+    {   4479,15}, {   2303,14}, {   4991,15}, {   2815,14}, \
+    {   5887,16}, {   1535,15}, {   3071,14}, {   6143,15}, \
+    {   3327,14}, {   6911,15}, {   3839,14}, {   7679,17}, \
+    {   1023,16}, {   2047,15}, {   4095,14}, {   8191,15}, \
+    {   4351,14}, {   8959,15}, {   4863,16}, {   2559,15}, \
+    {   5887,14}, {  11775,16}, {   3071,15}, {  32768,16}, \
+    {  65536,17}, { 131072,18}, { 262144,19}, { 524288,20}, \
+    {1048576,21}, {2097152,22}, {4194304,23}, {8388608,24} }
+#define SQR_FFT_TABLE3_SIZE 208
+#define SQR_FFT_THRESHOLD                 2880
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  63
+#define MULLO_MUL_N_THRESHOLD             6253
+#define SQRLO_BASECASE_THRESHOLD             8
+#define SQRLO_DC_THRESHOLD                  54
+#define SQRLO_SQR_THRESHOLD               5558
+
+#define DC_DIV_QR_THRESHOLD                 72
+#define DC_DIVAPPR_Q_THRESHOLD             195
+#define DC_BDIV_QR_THRESHOLD                50
+#define DC_BDIV_Q_THRESHOLD                 90
+
+#define INV_MULMOD_BNM1_THRESHOLD           46
+#define INV_NEWTON_THRESHOLD               195
+#define INV_APPR_THRESHOLD                 197
+
+#define BINV_NEWTON_THRESHOLD              230
+#define REDC_1_TO_REDC_2_THRESHOLD          67
+#define REDC_2_TO_REDC_N_THRESHOLD           0  /* always */
+
+#define MU_DIV_QR_THRESHOLD               1334
+#define MU_DIVAPPR_Q_THRESHOLD            1334
+#define MUPI_DIV_QR_THRESHOLD              104
+#define MU_BDIV_QR_THRESHOLD              1017
+#define MU_BDIV_Q_THRESHOLD               1187
+
+#define POWM_SEC_TABLE  1,16,194,712,779,2387
+
+#define GET_STR_DC_THRESHOLD                15
+#define GET_STR_PRECOMPUTE_THRESHOLD        29
+#define SET_STR_DC_THRESHOLD               216
+#define SET_STR_PRECOMPUTE_THRESHOLD       994
+
+#define FAC_DSC_THRESHOLD                  153
+#define FAC_ODD_THRESHOLD                    0  /* always */
+
+#define MATRIX22_STRASSEN_THRESHOLD         17
+#define HGCD2_DIV1_METHOD                    1  /* 9.38% faster than 3 */
+#define HGCD_THRESHOLD                      77
+#define HGCD_APPR_THRESHOLD                 50
+#define HGCD_REDUCE_THRESHOLD             2121
+#define GCD_DC_THRESHOLD                   440
+#define GCDEXT_DC_THRESHOLD                273
+#define JACOBI_BASE_METHOD                   1  /* 7.74% faster than 4 */
+
+/* Tuneup completed successfully, took 495910 seconds */
diff --git a/third_party/gmp/mpn/x86_64/cnd_aors_n.asm b/third_party/gmp/mpn/x86_64/cnd_aors_n.asm
new file mode 100644
index 0000000..13a2ab3
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/cnd_aors_n.asm
@@ -0,0 +1,183 @@
+dnl  AMD64 mpn_cnd_add_n, mpn_cnd_sub_n
+
+dnl  Copyright 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 2
+C AMD K10	 2
+C AMD bd1	 2.32
+C AMD bobcat	 3
+C Intel P4	13
+C Intel core2	 2.9
+C Intel NHM	 2.8
+C Intel SBR	 2.4
+C Intel atom	 5.33
+C VIA nano	 3
+
+C NOTES
+C  * It might seem natural to use the cmov insn here, but since this function
+C    is supposed to have the exact same execution pattern for cnd true and
+C    false, and since cmov's documentation is not clear about whether it
+C    actually reads both source operands and writes the register for a false
+C    condition, we cannot use it.
+C  * Two cases could be optimised: (1) cnd_add_n could use ADCSBB-from-memory
+C    to save one insn/limb, and (2) when up=rp cnd_add_n and cnd_sub_n could use
+C    ADCSBB-to-memory, again saving 1 insn/limb.
+C  * This runs optimally at decoder bandwidth on K10.  It has not been tuned
+C    for any other processor.
+
+C INPUT PARAMETERS
+define(`cnd',	`%rdi')	dnl rcx
+define(`rp',	`%rsi')	dnl rdx
+define(`up',	`%rdx')	dnl r8
+define(`vp',	`%rcx')	dnl r9
+define(`n',	`%r8')	dnl rsp+40
+
+ifdef(`OPERATION_cnd_add_n', `
+	define(ADDSUB,	      add)
+	define(ADCSBB,	      adc)
+	define(func,	      mpn_cnd_add_n)')
+ifdef(`OPERATION_cnd_sub_n', `
+	define(ADDSUB,	      sub)
+	define(ADCSBB,	      sbb)
+	define(func,	      mpn_cnd_sub_n)')
+
+MULFUNC_PROLOGUE(mpn_cnd_add_n mpn_cnd_sub_n)
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(func)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), R32(%r8)')
+	push	%rbx
+	push	%rbp
+	push	%r12
+	push	%r13
+	push	%r14
+
+	neg	cnd
+	sbb	cnd, cnd		C make cnd mask
+
+	lea	(vp,n,8), vp
+	lea	(up,n,8), up
+	lea	(rp,n,8), rp
+
+	mov	R32(n), R32(%rax)
+	neg	n
+	and	$3, R32(%rax)
+	jz	L(top)			C carry-save reg rax = 0 in this arc
+	cmp	$2, R32(%rax)
+	jc	L(b1)
+	jz	L(b2)
+
+L(b3):	mov	(vp,n,8), %r12
+	mov	8(vp,n,8), %r13
+	mov	16(vp,n,8), %r14
+	and	cnd, %r12
+	mov	(up,n,8), %r10
+	and	cnd, %r13
+	mov	8(up,n,8), %rbx
+	and	cnd, %r14
+	mov	16(up,n,8), %rbp
+	ADDSUB	%r12, %r10
+	mov	%r10, (rp,n,8)
+	ADCSBB	%r13, %rbx
+	mov	%rbx, 8(rp,n,8)
+	ADCSBB	%r14, %rbp
+	mov	%rbp, 16(rp,n,8)
+	sbb	R32(%rax), R32(%rax)	C save carry
+	add	$3, n
+	js	L(top)
+	jmp	L(end)
+
+L(b2):	mov	(vp,n,8), %r12
+	mov	8(vp,n,8), %r13
+	mov	(up,n,8), %r10
+	and	cnd, %r12
+	mov	8(up,n,8), %rbx
+	and	cnd, %r13
+	ADDSUB	%r12, %r10
+	mov	%r10, (rp,n,8)
+	ADCSBB	%r13, %rbx
+	mov	%rbx, 8(rp,n,8)
+	sbb	R32(%rax), R32(%rax)	C save carry
+	add	$2, n
+	js	L(top)
+	jmp	L(end)
+
+L(b1):	mov	(vp,n,8), %r12
+	mov	(up,n,8), %r10
+	and	cnd, %r12
+	ADDSUB	%r12, %r10
+	mov	%r10, (rp,n,8)
+	sbb	R32(%rax), R32(%rax)	C save carry
+	add	$1, n
+	jns	L(end)
+
+	ALIGN(16)
+L(top):	mov	(vp,n,8), %r12
+	mov	8(vp,n,8), %r13
+	mov	16(vp,n,8), %r14
+	mov	24(vp,n,8), %r11
+	and	cnd, %r12
+	mov	(up,n,8), %r10
+	and	cnd, %r13
+	mov	8(up,n,8), %rbx
+	and	cnd, %r14
+	mov	16(up,n,8), %rbp
+	and	cnd, %r11
+	mov	24(up,n,8), %r9
+	add	R32(%rax), R32(%rax)	C restore carry
+	ADCSBB	%r12, %r10
+	mov	%r10, (rp,n,8)
+	ADCSBB	%r13, %rbx
+	mov	%rbx, 8(rp,n,8)
+	ADCSBB	%r14, %rbp
+	mov	%rbp, 16(rp,n,8)
+	ADCSBB	%r11, %r9
+	mov	%r9, 24(rp,n,8)
+	sbb	R32(%rax), R32(%rax)	C save carry
+	add	$4, n
+	js	L(top)
+
+L(end):	neg	R32(%rax)
+	pop	%r14
+	pop	%r13
+	pop	%r12
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/com.asm b/third_party/gmp/mpn/x86_64/com.asm
new file mode 100644
index 0000000..006acaf
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/com.asm
@@ -0,0 +1,95 @@
+dnl  AMD64 mpn_com.
+
+dnl  Copyright 2004-2006, 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C	    cycles/limb
+C AMD K8,K9	 1.25
+C AMD K10	 1.25
+C Intel P4	 2.78
+C Intel core2	 1.1
+C Intel corei	 1.5
+C Intel atom	 ?
+C VIA nano	 2
+
+C INPUT PARAMETERS
+define(`rp',`%rdi')
+define(`up',`%rsi')
+define(`n',`%rdx')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_com)
+	FUNC_ENTRY(3)
+	movq	(up), %r8
+	movl	R32(%rdx), R32(%rax)
+	leaq	(up,n,8), up
+	leaq	(rp,n,8), rp
+	negq	n
+	andl	$3, R32(%rax)
+	je	L(b00)
+	cmpl	$2, R32(%rax)
+	jc	L(b01)
+	je	L(b10)
+
+L(b11):	notq	%r8
+	movq	%r8, (rp,n,8)
+	decq	n
+	jmp	L(e11)
+L(b10):	addq	$-2, n
+	jmp	L(e10)
+	.byte	0x90,0x90,0x90,0x90,0x90,0x90
+L(b01):	notq	%r8
+	movq	%r8, (rp,n,8)
+	incq	n
+	jz	L(ret)
+
+L(oop):	movq	(up,n,8), %r8
+L(b00):	movq	8(up,n,8), %r9
+	notq	%r8
+	notq	%r9
+	movq	%r8, (rp,n,8)
+	movq	%r9, 8(rp,n,8)
+L(e11):	movq	16(up,n,8), %r8
+L(e10):	movq	24(up,n,8), %r9
+	notq	%r8
+	notq	%r9
+	movq	%r8, 16(rp,n,8)
+	movq	%r9, 24(rp,n,8)
+	addq	$4, n
+	jnc	L(oop)
+L(ret):	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/copyd.asm b/third_party/gmp/mpn/x86_64/copyd.asm
new file mode 100644
index 0000000..a5e6e59
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/copyd.asm
@@ -0,0 +1,93 @@
+dnl  AMD64 mpn_copyd -- copy limb vector, decrementing.
+
+dnl  Copyright 2003, 2005, 2007, 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 1
+C AMD K10	 1
+C AMD bd1	 1.36
+C AMD bobcat	 1.71
+C Intel P4	 2-3
+C Intel core2	 1
+C Intel NHM	 1
+C Intel SBR	 1
+C Intel atom	 2
+C VIA nano	 2
+
+
+IFSTD(`define(`rp',`%rdi')')
+IFSTD(`define(`up',`%rsi')')
+IFSTD(`define(`n', `%rdx')')
+
+IFDOS(`define(`rp',`%rcx')')
+IFDOS(`define(`up',`%rdx')')
+IFDOS(`define(`n', `%r8')')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(64)
+PROLOGUE(mpn_copyd)
+	lea	-8(up,n,8), up
+	lea	(rp,n,8), rp
+	sub	$4, n
+	jc	L(end)
+	nop
+
+L(top):	mov	(up), %rax
+	mov	-8(up), %r9
+	lea	-32(rp), rp
+	mov	-16(up), %r10
+	mov	-24(up), %r11
+	lea	-32(up), up
+	mov	%rax, 24(rp)
+	mov	%r9, 16(rp)
+	sub	$4, n
+	mov	%r10, 8(rp)
+	mov	%r11, (rp)
+	jnc	L(top)
+
+L(end):	shr	R32(n)
+	jnc	1f
+	mov	(up), %rax
+	mov	%rax, -8(rp)
+	lea	-8(rp), rp
+	lea	-8(up), up
+1:	shr	R32(n)
+	jnc	1f
+	mov	(up), %rax
+	mov	-8(up), %r9
+	mov	%rax, -8(rp)
+	mov	%r9, -16(rp)
+1:	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/copyi.asm b/third_party/gmp/mpn/x86_64/copyi.asm
new file mode 100644
index 0000000..bafce7a
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/copyi.asm
@@ -0,0 +1,92 @@
+dnl  AMD64 mpn_copyi -- copy limb vector, incrementing.
+
+dnl  Copyright 2003, 2005, 2007, 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 1
+C AMD K10	 1
+C AMD bd1	 1.36
+C AMD bobcat	 1.71
+C Intel P4	 2-3
+C Intel core2	 1
+C Intel NHM	 1
+C Intel SBR	 1
+C Intel atom	 2
+C VIA nano	 2
+
+
+IFSTD(`define(`rp',`%rdi')')
+IFSTD(`define(`up',`%rsi')')
+IFSTD(`define(`n', `%rdx')')
+
+IFDOS(`define(`rp',`%rcx')')
+IFDOS(`define(`up',`%rdx')')
+IFDOS(`define(`n', `%r8')')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(64)
+	.byte	0,0,0,0,0,0
+PROLOGUE(mpn_copyi)
+	lea	-8(rp), rp
+	sub	$4, n
+	jc	L(end)
+
+L(top):	mov	(up), %rax
+	mov	8(up), %r9
+	lea	32(rp), rp
+	mov	16(up), %r10
+	mov	24(up), %r11
+	lea	32(up), up
+	mov	%rax, -24(rp)
+	mov	%r9, -16(rp)
+	sub	$4, n
+	mov	%r10, -8(rp)
+	mov	%r11, (rp)
+	jnc	L(top)
+
+L(end):	shr	R32(n)
+	jnc	1f
+	mov	(up), %rax
+	mov	%rax, 8(rp)
+	lea	8(rp), rp
+	lea	8(up), up
+1:	shr	R32(n)
+	jnc	1f
+	mov	(up), %rax
+	mov	8(up), %r9
+	mov	%rax, 8(rp)
+	mov	%r9, 16(rp)
+1:	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/core2/aorrlsh1_n.asm b/third_party/gmp/mpn/x86_64/core2/aorrlsh1_n.asm
new file mode 100644
index 0000000..7066bb4
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/core2/aorrlsh1_n.asm
@@ -0,0 +1,53 @@
+dnl  AMD64 mpn_addlsh1_n -- rp[] = up[] + (vp[] << 1)
+dnl  AMD64 mpn_rsblsh1_n -- rp[] = (vp[] << 1) - up[]
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2008, 2010-2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+define(LSH, 1)
+define(RSH, 63)
+
+ifdef(`OPERATION_addlsh1_n', `
+	define(ADDSUB,	add)
+	define(ADCSBB,	adc)
+	define(func,	mpn_addlsh1_n)')
+ifdef(`OPERATION_rsblsh1_n', `
+	define(ADDSUB,	sub)
+	define(ADCSBB,	sbb)
+	define(func,	mpn_rsblsh1_n)')
+
+MULFUNC_PROLOGUE(mpn_addlsh1_n mpn_rsblsh1_n)
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+include_mpn(`x86_64/aorrlshC_n.asm')
diff --git a/third_party/gmp/mpn/x86_64/core2/aorrlsh2_n.asm b/third_party/gmp/mpn/x86_64/core2/aorrlsh2_n.asm
new file mode 100644
index 0000000..5065120
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/core2/aorrlsh2_n.asm
@@ -0,0 +1,53 @@
+dnl  AMD64 mpn_addlsh2_n -- rp[] = up[] + (vp[] << 2)
+dnl  AMD64 mpn_rsblsh2_n -- rp[] = (vp[] << 2) - up[]
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2008, 2010-2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+define(LSH, 2)
+define(RSH, 62)
+
+ifdef(`OPERATION_addlsh2_n', `
+	define(ADDSUB,	add)
+	define(ADCSBB,	adc)
+	define(func,	mpn_addlsh2_n)')
+ifdef(`OPERATION_rsblsh2_n', `
+	define(ADDSUB,	sub)
+	define(ADCSBB,	sbb)
+	define(func,	mpn_rsblsh2_n)')
+
+MULFUNC_PROLOGUE(mpn_addlsh2_n mpn_rsblsh2_n)
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+include_mpn(`x86_64/aorrlshC_n.asm')
diff --git a/third_party/gmp/mpn/x86_64/core2/aorrlsh_n.asm b/third_party/gmp/mpn/x86_64/core2/aorrlsh_n.asm
new file mode 100644
index 0000000..57abf31
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/core2/aorrlsh_n.asm
@@ -0,0 +1,38 @@
+dnl  AMD64 mpn_addlsh_n and mpn_rsblsh_n.  R = V2^k +- U.
+
+dnl  Copyright 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+MULFUNC_PROLOGUE(mpn_addlsh_n mpn_addlsh_nc mpn_rsblsh_n)
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+include_mpn(`x86_64/coreinhm/aorrlsh_n.asm')
diff --git a/third_party/gmp/mpn/x86_64/core2/aors_err1_n.asm b/third_party/gmp/mpn/x86_64/core2/aors_err1_n.asm
new file mode 100644
index 0000000..3f875ae
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/core2/aors_err1_n.asm
@@ -0,0 +1,225 @@
+dnl  Core 2 mpn_add_err1_n, mpn_sub_err1_n
+
+dnl  Contributed by David Harvey.
+
+dnl  Copyright 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 ?
+C AMD K10	 ?
+C Intel P4	 ?
+C Intel core2	 4.14
+C Intel corei	 ?
+C Intel atom	 ?
+C VIA nano	 ?
+
+
+C INPUT PARAMETERS
+define(`rp',	`%rdi')
+define(`up',	`%rsi')
+define(`vp',	`%rdx')
+define(`ep',	`%rcx')
+define(`yp',	`%r8')
+define(`n',	`%r9')
+define(`cy_param',	`8(%rsp)')
+
+define(`el',	`%rbx')
+define(`eh',	`%rbp')
+define(`t0',	`%r10')
+define(`t1',	`%r11')
+define(`t2',	`%r12')
+define(`t3',	`%r13')
+define(`w0',	`%r14')
+define(`w1',	`%r15')
+
+ifdef(`OPERATION_add_err1_n', `
+	define(ADCSBB,	      adc)
+	define(func,	      mpn_add_err1_n)')
+ifdef(`OPERATION_sub_err1_n', `
+	define(ADCSBB,	      sbb)
+	define(func,	      mpn_sub_err1_n)')
+
+MULFUNC_PROLOGUE(mpn_add_err1_n mpn_sub_err1_n)
+
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(func)
+	mov	cy_param, %rax
+
+	push	%rbx
+	push	%rbp
+	push	%r12
+	push	%r13
+	push	%r14
+	push	%r15
+
+	lea	(up,n,8), up
+	lea	(vp,n,8), vp
+	lea	(rp,n,8), rp
+
+	mov	R32(n), R32(%r10)
+	and	$3, R32(%r10)
+	jz	L(0mod4)
+	cmp	$2, R32(%r10)
+	jc	L(1mod4)
+	jz	L(2mod4)
+L(3mod4):
+	xor	R32(el), R32(el)
+	xor	R32(eh), R32(eh)
+	xor	R32(t0), R32(t0)
+	xor	R32(t1), R32(t1)
+	lea	-24(yp,n,8), yp
+	neg	n
+
+	shr	$1, %al		   C restore carry
+	mov	(up,n,8), w0
+	mov	8(up,n,8), w1
+	ADCSBB	(vp,n,8), w0
+	mov	w0, (rp,n,8)
+	cmovc	16(yp), el
+	ADCSBB	8(vp,n,8), w1
+	mov	w1, 8(rp,n,8)
+	cmovc	8(yp), t0
+	mov	16(up,n,8), w0
+	ADCSBB	16(vp,n,8), w0
+	mov	w0, 16(rp,n,8)
+	cmovc	(yp), t1
+	setc	%al		   C save carry
+	add	t0, el
+	adc	$0, eh
+	add	t1, el
+	adc	$0, eh
+
+	add	$3, n
+	jnz	L(loop)
+	jmp	L(end)
+
+	ALIGN(16)
+L(0mod4):
+	xor	R32(el), R32(el)
+	xor	R32(eh), R32(eh)
+	lea	(yp,n,8), yp
+	neg	n
+	jmp	L(loop)
+
+	ALIGN(16)
+L(1mod4):
+	xor	R32(el), R32(el)
+	xor	R32(eh), R32(eh)
+	lea	-8(yp,n,8), yp
+	neg	n
+
+	shr	$1, %al		   C restore carry
+	mov	(up,n,8), w0
+	ADCSBB	(vp,n,8), w0
+	mov	w0, (rp,n,8)
+	cmovc	(yp), el
+	setc	%al		   C save carry
+
+	add	$1, n
+	jnz	L(loop)
+	jmp	L(end)
+
+	ALIGN(16)
+L(2mod4):
+	xor	R32(el), R32(el)
+	xor	R32(eh), R32(eh)
+	xor	R32(t0), R32(t0)
+	lea	-16(yp,n,8), yp
+	neg	n
+
+	shr	$1, %al		   C restore carry
+	mov	(up,n,8), w0
+	mov	8(up,n,8), w1
+	ADCSBB	(vp,n,8), w0
+	mov	w0, (rp,n,8)
+	cmovc	8(yp), el
+	ADCSBB	8(vp,n,8), w1
+	mov	w1, 8(rp,n,8)
+	cmovc	(yp), t0
+	setc	%al		   C save carry
+	add	t0, el
+	adc	$0, eh
+
+	add	$2, n
+	jnz	L(loop)
+	jmp	L(end)
+
+	ALIGN(32)
+L(loop):
+	mov	(up,n,8), w0
+	shr	$1, %al		   C restore carry
+	mov	-8(yp), t0
+	mov	$0, R32(t3)
+	ADCSBB	(vp,n,8), w0
+	cmovnc	t3, t0
+	mov	w0, (rp,n,8)
+	mov	8(up,n,8), w1
+	mov	16(up,n,8), w0
+	ADCSBB	8(vp,n,8), w1
+	mov	-16(yp), t1
+	cmovnc	t3, t1
+	mov	-24(yp), t2
+	mov	w1, 8(rp,n,8)
+	ADCSBB	16(vp,n,8), w0
+	cmovnc	t3, t2
+	mov	24(up,n,8), w1
+	ADCSBB	24(vp,n,8), w1
+	cmovc	-32(yp), t3
+	setc	%al		   C save carry
+	add	t0, el
+	adc	$0, eh
+	add	t1, el
+	adc	$0, eh
+	add	t2, el
+	adc	$0, eh
+	lea	-32(yp), yp
+	mov	w0, 16(rp,n,8)
+	add	t3, el
+	adc	$0, eh
+	add	$4, n
+	mov	w1, -8(rp,n,8)
+	jnz	L(loop)
+
+L(end):
+	mov	el, (ep)
+	mov	eh, 8(ep)
+
+	pop	%r15
+	pop	%r14
+	pop	%r13
+	pop	%r12
+	pop	%rbp
+	pop	%rbx
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/core2/aors_n.asm b/third_party/gmp/mpn/x86_64/core2/aors_n.asm
new file mode 100644
index 0000000..f9e0039
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/core2/aors_n.asm
@@ -0,0 +1,150 @@
+dnl  Intel mpn_add_n/mpn_sub_n optimised for Conroe, Nehalem.
+
+dnl  Copyright 2006, 2007, 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	    cycles/limb
+C AMD K8,K9	 2
+C AMD K10	 1.93\2
+C AMD bull	 1.62\2.1
+C AMD pile	 1.6\1.7
+C AMD steam
+C AMD excavator
+C AMD bobcat	 2.79
+C AMD jaguar	 2.54
+C Intel P4	10
+C Intel core2	 2
+C Intel NHM	 2
+C Intel SBR	 2
+C Intel IBR	 1.95
+C Intel HWL	 1.72
+C Intel BWL	 1.54
+C Intel SKL	 1.52
+C Intel atom	 9
+C Intel SLM	 6.5
+C VIA nano	 3
+
+C INPUT PARAMETERS
+define(`rp',	`%rdi')
+define(`up',	`%rsi')
+define(`vp',	`%rdx')
+define(`n',	`%rcx')
+define(`cy',	`%r8')
+
+ifdef(`OPERATION_add_n', `
+	define(ADCSBB,	      adc)
+	define(func,	      mpn_add_n)
+	define(func_nc,	      mpn_add_nc)')
+ifdef(`OPERATION_sub_n', `
+	define(ADCSBB,	      sbb)
+	define(func,	      mpn_sub_n)
+	define(func_nc,	      mpn_sub_nc)')
+
+MULFUNC_PROLOGUE(mpn_add_n mpn_add_nc mpn_sub_n mpn_sub_nc)
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(func)
+	FUNC_ENTRY(4)
+	xor	%r8, %r8
+L(start):
+	mov	(up), %r10
+	mov	(vp), %r11
+
+	lea	(up,n,8), up
+	lea	(vp,n,8), vp
+	lea	(rp,n,8), rp
+	mov	R32(n), R32(%rax)
+	neg	n
+	and	$3, R32(%rax)
+	je	L(b00)
+	add	%rax, n			C clear low rcx bits for jrcxz
+	cmp	$2, R32(%rax)
+	jl	L(b01)
+	je	L(b10)
+
+L(b11):	neg	%r8			C set cy
+	jmp	L(e11)
+
+L(b00):	neg	%r8			C set cy
+	mov	%r10, %r8
+	mov	%r11, %r9
+	lea	4(n), n
+	jmp	L(e00)
+
+	nop
+	nop
+	nop
+L(b01):	neg	%r8			C set cy
+	jmp	L(top)
+
+L(b10):	neg	%r8			C set cy
+	mov	%r10, %r8
+	mov	%r11, %r9
+	jmp	L(e10)
+
+L(end):	ADCSBB	%r11, %r10
+	mov	%r10, -8(rp)
+	mov	R32(%rcx), R32(%rax)	C clear eax, ecx contains 0
+	adc	R32(%rax), R32(%rax)
+	FUNC_EXIT()
+	ret
+
+	ALIGN(16)
+L(top):	jrcxz	L(end)
+	mov	(up,n,8), %r8
+	mov	(vp,n,8), %r9
+	lea	4(n), n
+	ADCSBB	%r11, %r10
+	mov	%r10, -40(rp,n,8)
+L(e00):	mov	-24(up,n,8), %r10
+	mov	-24(vp,n,8), %r11
+	ADCSBB	%r9, %r8
+	mov	%r8, -32(rp,n,8)
+L(e11):	mov	-16(up,n,8), %r8
+	mov	-16(vp,n,8), %r9
+	ADCSBB	%r11, %r10
+	mov	%r10, -24(rp,n,8)
+L(e10):	mov	-8(up,n,8), %r10
+	mov	-8(vp,n,8), %r11
+	ADCSBB	%r9, %r8
+	mov	%r8, -16(rp,n,8)
+	jmp	L(top)
+EPILOGUE()
+
+PROLOGUE(func_nc)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8	')
+	jmp	L(start)
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/core2/aorsmul_1.asm b/third_party/gmp/mpn/x86_64/core2/aorsmul_1.asm
new file mode 100644
index 0000000..a7a5d6e
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/core2/aorsmul_1.asm
@@ -0,0 +1,188 @@
+dnl  x86-64 mpn_addmul_1 and mpn_submul_1, optimized for "Core 2".
+
+dnl  Copyright 2003-2005, 2007-2009, 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9      4.52
+C AMD K10        4.01
+C AMD bull       4.98
+C AMD pile       4.83
+C AMD steam
+C AMD excavator
+C AMD bobcat     5.56
+C AMD jaguar     5.54
+C Intel P4      16.3    17.3
+C Intel core2    4.32    4.61
+C Intel NHM      5.08
+C Intel SBR      4.04
+C Intel IBR      3.95
+C Intel HWL      3.66
+C Intel BWL      2.87
+C Intel SKL      2.79
+C Intel atom    20.6
+C Intel SLM      7.6
+C VIA nano       5.25
+
+C INPUT PARAMETERS
+define(`rp',	`%rdi')
+define(`up',	`%rsi')
+define(`n',	`%rdx')
+define(`v0',	`%rcx')
+
+ifdef(`OPERATION_addmul_1',`
+      define(`ADDSUB',        `add')
+      define(`func',     `mpn_addmul_1')
+      define(`func_1c',  `mpn_addmul_1c')
+')
+ifdef(`OPERATION_submul_1',`
+      define(`ADDSUB',        `sub')
+      define(`func',     `mpn_submul_1')
+      define(`func_1c',  `mpn_submul_1c')
+')
+
+MULFUNC_PROLOGUE(mpn_addmul_1 mpn_addmul_1c mpn_submul_1 mpn_submul_1c)
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+	C For DOS, on the stack we have four saved registers, return address,
+	C space for four register arguments, and finally the carry input.
+
+IFDOS(` define(`carry_in', `72(%rsp)')') dnl
+IFSTD(` define(`carry_in', `%r8')') dnl
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(func_1c)
+	FUNC_ENTRY(4)
+	push	%rbx
+	push	%rbp
+	lea	(%rdx), %rbx
+	neg	%rbx
+
+	mov	(up), %rax
+	mov	(rp), %r10
+
+	lea	-16(rp,%rdx,8), rp
+	lea	(up,%rdx,8), up
+	mul	%rcx
+	add	carry_in, %rax
+	adc	$0, %rdx
+	jmp	L(start_nc)
+EPILOGUE()
+
+	ALIGN(16)
+PROLOGUE(func)
+	FUNC_ENTRY(4)
+	push	%rbx
+	push	%rbp
+	lea	(%rdx), %rbx
+	neg	%rbx
+
+	mov	(up), %rax
+	mov	(rp), %r10
+
+	lea	-16(rp,%rdx,8), rp
+	lea	(up,%rdx,8), up
+	mul	%rcx
+
+L(start_nc):
+	test	$1, R8(%rbx)
+	jnz	L(odd)
+
+	lea	(%rax), %r11
+	mov	8(up,%rbx,8), %rax
+	lea	(%rdx), %rbp
+	mul	%rcx
+	add	$2, %rbx
+	jz	L(n2)
+
+	lea	(%rax), %r8
+	mov	(up,%rbx,8), %rax
+	lea	(%rdx), %r9
+	jmp	L(mid)
+
+	ALIGN(8)
+L(odd):	inc	%rbx
+	jz	L(n1)
+
+	lea	(%rax), %r8
+	mov	(up,%rbx,8), %rax
+	lea	(%rdx), %r9
+	mul	%rcx
+	lea	(%rax), %r11
+	mov	8(up,%rbx,8), %rax
+	lea	(%rdx), %rbp
+	jmp	L(e)
+
+	ALIGN(16)
+L(top):	mul	%rcx
+	ADDSUB	%r8, %r10
+	lea	(%rax), %r8
+	mov	(up,%rbx,8), %rax
+	adc	%r9, %r11
+	mov	%r10, -8(rp,%rbx,8)
+	mov	(rp,%rbx,8), %r10
+	lea	(%rdx), %r9
+	adc	$0, %rbp
+L(mid):	mul	%rcx
+	ADDSUB	%r11, %r10
+	lea	(%rax), %r11
+	mov	8(up,%rbx,8), %rax
+	adc	%rbp, %r8
+	mov	%r10, (rp,%rbx,8)
+	mov	8(rp,%rbx,8), %r10
+	lea	(%rdx), %rbp
+	adc	$0, %r9
+L(e):	add	$2, %rbx
+	js	L(top)
+
+	mul	%rcx
+	ADDSUB	%r8, %r10
+	adc	%r9, %r11
+	mov	%r10, -8(rp)
+	adc	%rbx, %rbp		C rbx = 0
+L(n2):	mov	(rp), %r10
+	ADDSUB	%r11, %r10
+	adc	%rbp, %rax
+	mov	%r10, (rp)
+	adc	%rbx, %rdx		C rbx = 0
+L(n1):	mov	8(rp), %r10
+	ADDSUB	%rax, %r10
+	mov	%r10, 8(rp)
+	mov	R32(%rbx), R32(%rax)	C rbx = 0
+	adc	%rdx, %rax
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/core2/com.asm b/third_party/gmp/mpn/x86_64/core2/com.asm
new file mode 100644
index 0000000..d7d9f79
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/core2/com.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_com.
+
+dnl  Copyright 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_com)
+include_mpn(`x86_64/fastsse/com-palignr.asm')
diff --git a/third_party/gmp/mpn/x86_64/core2/copyd.asm b/third_party/gmp/mpn/x86_64/core2/copyd.asm
new file mode 100644
index 0000000..57ea0e5
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/core2/copyd.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_copyd.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_copyd)
+include_mpn(`x86_64/fastsse/copyd-palignr.asm')
diff --git a/third_party/gmp/mpn/x86_64/core2/copyi.asm b/third_party/gmp/mpn/x86_64/core2/copyi.asm
new file mode 100644
index 0000000..f0c7607
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/core2/copyi.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_copyi.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_copyi)
+include_mpn(`x86_64/fastsse/copyi-palignr.asm')
diff --git a/third_party/gmp/mpn/x86_64/core2/divrem_1.asm b/third_party/gmp/mpn/x86_64/core2/divrem_1.asm
new file mode 100644
index 0000000..1b3f139
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/core2/divrem_1.asm
@@ -0,0 +1,243 @@
+dnl  x86-64 mpn_divrem_1 -- mpn by limb division.
+
+dnl  Copyright 2004, 2005, 2007-2010, 2012, 2014 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C		norm	unorm	frac
+C AMD K8,K9	15	15	12
+C AMD K10	15	15	12
+C Intel P4	44	44	43
+C Intel core2	24	24	19.5
+C Intel corei	19	19	18
+C Intel atom	51	51	36
+C VIA nano	46	44	22.5
+
+C mp_limb_t
+C mpn_divrem_1 (mp_ptr qp, mp_size_t fn,
+C               mp_srcptr np, mp_size_t nn, mp_limb_t d)
+
+C mp_limb_t
+C mpn_preinv_divrem_1 (mp_ptr qp, mp_size_t fn,
+C                      mp_srcptr np, mp_size_t nn, mp_limb_t d,
+C                      mp_limb_t dinv, int cnt)
+
+C INPUT PARAMETERS
+define(`qp',		`%rdi')
+define(`fn_param',	`%rsi')
+define(`up_param',	`%rdx')
+define(`un_param',	`%rcx')
+define(`d',		`%r8')
+define(`dinv',		`%r9')		C only for mpn_preinv_divrem_1
+C       shift passed on stack		C only for mpn_preinv_divrem_1
+
+define(`cnt',		`%rcx')
+define(`up',		`%rsi')
+define(`fn',		`%r12')
+define(`un',		`%rbx')
+
+
+C rax rbx rcx rdx rsi rdi rbp r8  r9  r10 r11 r12 r13 r14 r15
+C         cnt         qp      d  dinv
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+IFSTD(`define(`CNTOFF',		`40($1)')')
+IFDOS(`define(`CNTOFF',		`104($1)')')
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_preinv_divrem_1)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8	')
+IFDOS(`	mov	64(%rsp), %r9	')
+	xor	R32(%rax), R32(%rax)
+	push	%r13
+	push	%r12
+	push	%rbp
+	push	%rbx
+
+	mov	fn_param, fn
+	mov	un_param, un
+	add	fn_param, un_param
+	mov	up_param, up
+
+	lea	-8(qp,un_param,8), qp
+
+	mov	CNTOFF(%rsp), R8(cnt)
+	shl	R8(cnt), d
+	jmp	L(ent)
+EPILOGUE()
+
+	ALIGN(16)
+PROLOGUE(mpn_divrem_1)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8	')
+	xor	R32(%rax), R32(%rax)
+	push	%r13
+	push	%r12
+	push	%rbp
+	push	%rbx
+
+	mov	fn_param, fn
+	mov	un_param, un
+	add	fn_param, un_param
+	mov	up_param, up
+	je	L(ret)
+
+	lea	-8(qp,un_param,8), qp
+	xor	R32(%rbp), R32(%rbp)
+
+L(unnormalized):
+	test	un, un
+	je	L(44)
+	mov	-8(up,un,8), %rax
+	cmp	d, %rax
+	jae	L(44)
+	mov	%rbp, (qp)
+	mov	%rax, %rbp
+	lea	-8(qp), qp
+	je	L(ret)
+	dec	un
+L(44):
+	bsr	d, %rcx
+	not	R32(%rcx)
+	sal	R8(%rcx), d
+	sal	R8(%rcx), %rbp
+
+	push	%rcx
+IFSTD(`	push	%rdi		')
+IFSTD(`	push	%rsi		')
+	push	%r8
+IFSTD(`	sub	$8, %rsp	')
+IFSTD(`	mov	d, %rdi		')
+IFDOS(`	sub	$40, %rsp	')
+IFDOS(`	mov	d, %rcx		')
+	ASSERT(nz, `test $15, %rsp')
+	CALL(	mpn_invert_limb)
+IFSTD(`	add	$8, %rsp	')
+IFDOS(`	add	$40, %rsp	')
+	pop	%r8
+IFSTD(`	pop	%rsi		')
+IFSTD(`	pop	%rdi		')
+	pop	%rcx
+
+	mov	%rax, dinv
+	mov	%rbp, %rax
+	test	un, un
+	je	L(frac)
+
+L(ent):	mov	-8(up,un,8), %rbp
+	shr	R8(%rcx), %rax
+	shld	R8(%rcx), %rbp, %rax
+	sub	$2, un
+	js	L(end)
+
+	ALIGN(16)
+L(top):	lea	1(%rax), %r11
+	mul	dinv
+	mov	(up,un,8), %r10
+	shld	R8(%rcx), %r10, %rbp
+	mov	%rbp, %r13
+	add	%rax, %r13
+	adc	%r11, %rdx
+	mov	%rdx, %r11
+	imul	d, %rdx
+	sub	%rdx, %rbp
+	lea	(d,%rbp), %rax
+	sub	$8, qp
+	cmp	%r13, %rbp
+	cmovc	%rbp, %rax
+	adc	$-1, %r11
+	cmp	d, %rax
+	jae	L(ufx)
+L(uok):	dec	un
+	mov	%r11, 8(qp)
+	mov	%r10, %rbp
+	jns	L(top)
+
+L(end):	lea	1(%rax), %r11
+	sal	R8(%rcx), %rbp
+	mul	dinv
+	add	%rbp, %rax
+	adc	%r11, %rdx
+	mov	%rax, %r11
+	mov	%rdx, %r13
+	imul	d, %rdx
+	sub	%rdx, %rbp
+	mov	d, %rax
+	add	%rbp, %rax
+	cmp	%r11, %rbp
+	cmovc	%rbp, %rax
+	adc	$-1, %r13
+	cmp	d, %rax
+	jae	L(efx)
+L(eok):	mov	%r13, (qp)
+	sub	$8, qp
+	jmp	L(frac)
+
+L(ufx):	sub	d, %rax
+	inc	%r11
+	jmp	L(uok)
+L(efx):	sub	d, %rax
+	inc	%r13
+	jmp	L(eok)
+
+L(frac):mov	d, %rbp
+	neg	%rbp
+	jmp	L(fent)
+
+	ALIGN(16)			C	    K8-K10  P6-CNR P6-NHM  P4
+L(ftop):mul	dinv			C	      0,12   0,17   0,17
+	add	%r11, %rdx		C	      5      8     10
+	mov	%rax, %r11		C	      4      8      3
+	mov	%rdx, %r13		C	      6      9     11
+	imul	%rbp, %rdx		C	      6      9     11
+	mov	d, %rax			C
+	add	%rdx, %rax		C	     10     14     14
+	cmp	%r11, %rdx		C	     10     14     14
+	cmovc	%rdx, %rax		C	     11     15     15
+	adc	$-1, %r13		C
+	mov	%r13, (qp)		C
+	sub	$8, qp			C
+L(fent):lea	1(%rax), %r11		C
+	dec	fn			C
+	jns	L(ftop)			C
+
+	shr	R8(%rcx), %rax
+L(ret):	pop	%rbx
+	pop	%rbp
+	pop	%r12
+	pop	%r13
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/core2/gcd_11.asm b/third_party/gmp/mpn/x86_64/core2/gcd_11.asm
new file mode 100644
index 0000000..b00451f
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/core2/gcd_11.asm
@@ -0,0 +1,93 @@
+dnl  AMD64 mpn_gcd_11 optimised for Intel CNR, PNR, SBR, IBR.
+
+dnl  Based on the K7 gcd_1.asm, by Kevin Ryde.  Rehacked for AMD64 by Torbjorn
+dnl  Granlund.
+
+dnl  Copyright 2000-2002, 2005, 2009, 2011, 2012, 2017, 2019 Free Software
+dnl  Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C	     cycles/bit (approx)
+C AMD K8,K9	 ?
+C AMD K10	 ?
+C AMD bd1	 ?
+C AMD bd2	 ?
+C AMD bd3	 ?
+C AMD bd4	 ?
+C AMD bt1	 ?
+C AMD bt2	 ?
+C AMD zn1	 ?
+C AMD zn2	 ?
+C Intel P4	 ?
+C Intel CNR	 4.22  *
+C Intel PNR	 4.22  *
+C Intel NHM	 4.97
+C Intel WSM	 5.17
+C Intel SBR	 4.83  *
+C Intel IBR	 4.16  *
+C Intel HWL	 3.84
+C Intel BWL	 3.76
+C Intel SKL	 3.83
+C Intel atom	 ?
+C Intel SLM	 ?
+C Intel GLM	 ?
+C Intel GLM+	 ?
+C VIA nano	 ?
+
+define(`u0',    `%rdi')
+define(`v0',    `%rsi')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(64)
+PROLOGUE(mpn_gcd_11)
+	FUNC_ENTRY(2)
+	jmp	L(odd)
+
+	ALIGN(16)
+L(top):	cmovc	%rdx, u0		C u = |u - v|
+	cmovc	%rax, v0		C v = min(u,v)
+	shr	R8(%rcx), u0
+L(odd):	mov	v0, %rdx
+	sub	u0, %rdx		C v - u
+	bsf	%rdx, %rcx
+	mov	u0, %rax
+	sub	v0, u0			C u - v
+	jnz	L(top)
+
+L(end):	C rax = result
+	C rdx = 0 for the benefit of internal gcd_22 call
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/core2/gcd_22.asm b/third_party/gmp/mpn/x86_64/core2/gcd_22.asm
new file mode 100644
index 0000000..b5aa73b
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/core2/gcd_22.asm
@@ -0,0 +1,137 @@
+dnl  AMD64 mpn_gcd_22.  Assumes useful bsf, useful shrd, no tzcnt, no shlx.
+
+dnl  Copyright 2019 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C	     cycles/bit
+C AMD K8,K9	 ?
+C AMD K10	 ?
+C AMD bd1	 ?
+C AMD bd2	 ?
+C AMD bd3	 ?
+C AMD bd4	 ?
+C AMD bt1	 ?
+C AMD bt2	 ?
+C AMD zn1	 ?
+C AMD zn2	 ?
+C Intel P4	 ?
+C Intel CNR	 8.7
+C Intel PNR	 8.7
+C Intel NHM	 9.2
+C Intel WSM	 9.2
+C Intel SBR	 9.1
+C Intel IBR	 ?
+C Intel HWL	 ?
+C Intel BWL	 ?
+C Intel SKL	 ?
+C Intel atom	 ?
+C Intel SLM	 ?
+C Intel GLM	 ?
+C Intel GLM+	 ?
+C VIA nano	 ?
+
+
+define(`u1',    `%rdi')
+define(`u0',    `%rsi')
+define(`v1',    `%rdx')
+define(`v0_param', `%rcx')
+
+define(`v0',    `%rax')
+define(`cnt',   `%rcx')
+
+define(`s0',    `%r8')
+define(`s1',    `%r9')
+define(`t0',    `%r10')
+define(`t1',    `%r11')
+
+dnl ABI_SUPPORT(DOS64)	C returns mp_double_limb_t in memory
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(64)
+PROLOGUE(mpn_gcd_22)
+	FUNC_ENTRY(4)
+	mov	v0_param, v0
+
+	ALIGN(16)
+L(top):	mov	v0, t0
+	sub	u0, t0
+	jz	L(lowz)		C	jump when low limb result = 0
+	mov	v1, t1
+	sbb	u1, t1
+
+	mov	u0, s0
+	mov	u1, s1
+
+	bsf	t0, cnt
+
+	sub	v0, u0
+	sbb	v1, u1
+
+L(bck):	cmovc	t0, u0		C u = |u - v|
+	cmovc	t1, u1		C u = |u - v|
+	cmovc	s0, v0		C v = min(u,v)
+	cmovc	s1, v1		C v = min(u,v)
+
+	shrd	R8(cnt), u1, u0
+	shr	R8(cnt), u1
+
+	mov	v1, t1
+	or	u1, t1
+	jnz	L(top)
+
+L(gcd_11):
+	mov	v0, %rdi
+C	mov	u0, %rsi
+	TCALL(	mpn_gcd_11)
+
+L(lowz):C We come here when v0 - u0 = 0
+	C 1. If v1 - u1 = 0, then gcd is u = v.
+	C 2. Else compute gcd_21({v1,v0}, |u1-v1|)
+	mov	v1, t0
+	sub	u1, t0
+	je	L(end)
+
+	xor	t1, t1
+	mov	u0, s0
+	mov	u1, s1
+	bsf	t0, cnt
+	mov	u1, u0
+	xor	u1, u1
+	sub	v1, u0
+	jmp	L(bck)
+
+L(end):	C mov	v0, %rax
+	C mov	v1, %rdx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/core2/gmp-mparam.h b/third_party/gmp/mpn/x86_64/core2/gmp-mparam.h
new file mode 100644
index 0000000..44f1494
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/core2/gmp-mparam.h
@@ -0,0 +1,222 @@
+/* Core 2 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+/* 3000 MHz Penryn */
+/* FFT tuning limit = 116,220,984 */
+/* Generated by tuneup.c, 2019-10-18, gcc 8.3 */
+
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          3
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          2
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        11
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        18
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD      8
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1_NORM_THRESHOLD              3
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD              16
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           26
+
+#define DIV_1_VS_MUL_1_PERCENT             284
+
+#define MUL_TOOM22_THRESHOLD                24
+#define MUL_TOOM33_THRESHOLD                65
+#define MUL_TOOM44_THRESHOLD               184
+#define MUL_TOOM6H_THRESHOLD               256
+#define MUL_TOOM8H_THRESHOLD               381
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      73
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     122
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD      73
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD      79
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     106
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 28
+#define SQR_TOOM3_THRESHOLD                102
+#define SQR_TOOM4_THRESHOLD                160
+#define SQR_TOOM6_THRESHOLD                366
+#define SQR_TOOM8_THRESHOLD                478
+
+#define MULMID_TOOM42_THRESHOLD             32
+
+#define MULMOD_BNM1_THRESHOLD               11
+#define SQRMOD_BNM1_THRESHOLD               17
+
+#define MUL_FFT_MODF_THRESHOLD             368  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    368, 5}, {     17, 6}, {      9, 5}, {     19, 6}, \
+    {     10, 5}, {     21, 6}, {     11, 5}, {     23, 6}, \
+    {     21, 7}, {     11, 6}, {     23, 7}, {     12, 6}, \
+    {     25, 7}, {     21, 8}, {     11, 7}, {     24, 8}, \
+    {     13, 7}, {     27, 8}, {     15, 7}, {     31, 8}, \
+    {     19, 7}, {     39, 8}, {     21, 9}, {     11, 8}, \
+    {     27, 9}, {     15, 8}, {     35, 9}, {     19, 8}, \
+    {     41, 9}, {     23, 8}, {     47, 9}, {     27,10}, \
+    {     15, 9}, {     39,10}, {     23, 9}, {     51,11}, \
+    {     15,10}, {     31, 9}, {     67,10}, {     39, 9}, \
+    {     83,10}, {     47, 9}, {     95,11}, {     31,10}, \
+    {     79,11}, {     47,10}, {     95,12}, {     31, 9}, \
+    {    255,10}, {    135,11}, {     79,10}, {    159, 9}, \
+    {    319,11}, {     95,10}, {    191, 9}, {    383,11}, \
+    {    111,12}, {     63,11}, {    127,10}, {    271,11}, \
+    {    143,10}, {    287, 9}, {    575,10}, {    303,11}, \
+    {    159,10}, {    319,12}, {     95,11}, {    191,10}, \
+    {    383,11}, {    207,10}, {    415,13}, {     63,12}, \
+    {    127,11}, {    271,10}, {    543,11}, {    287,10}, \
+    {    575,11}, {    319,10}, {    639,11}, {    351,12}, \
+    {    191,11}, {    415,12}, {    223,11}, {    479,13}, \
+    {    127,12}, {    255,11}, {    543,12}, {    287,11}, \
+    {    607,12}, {    319,11}, {    639,12}, {    351,11}, \
+    {    703,13}, {    191,12}, {    479,14}, {    127,13}, \
+    {    255,12}, {    575,13}, {    319,12}, {    703,13}, \
+    {    383,12}, {    799,13}, {    447,12}, {    959,14}, \
+    {    255,13}, {    511,12}, {   1023,13}, {    575,12}, \
+    {   1151,13}, {    703,14}, {    383,13}, {    831,12}, \
+    {   1663,13}, {    959,15}, {    255,14}, {    511,13}, \
+    {   1087,12}, {   2175,13}, {   1215,14}, {    639,13}, \
+    {   1343,12}, {   2687,13}, {   1471,14}, {    767,13}, \
+    {   1663,14}, {    895,13}, {   1791,15}, {    511,14}, \
+    {   1023,13}, {   2175,14}, {   1151,13}, {   2431,12}, \
+    {   4863,14}, {   1279,13}, {   2559,14}, {   1407,13}, \
+    {   2815,15}, {    767,14}, {   1663,13}, {   3455,12}, \
+    {   6911,14}, {   1791,16}, {    511,15}, {   1023,14}, \
+    {   2431,13}, {   4863,15}, {   1279,14}, {   2943,13}, \
+    {   5887,12}, {  11775,15}, {   1535,14}, {   3455,13}, \
+    {   6911,15}, {   1791,14}, {   3839,13}, {   7679,16}, \
+    {   1023,15}, {   2047,14}, {   4223,15}, {   2303,14}, \
+    {   4991,15}, {   2815,14}, {   5887,13}, {  11775,16}, \
+    {   1535,15}, {   3327,14}, {   6911,15}, {  32768,16}, \
+    {  65536,17}, { 131072,18}, { 262144,19}, { 524288,20}, \
+    {1048576,21}, {2097152,22}, {4194304,23}, {8388608,24} }
+#define MUL_FFT_TABLE3_SIZE 176
+#define MUL_FFT_THRESHOLD                 4736
+
+#define SQR_FFT_MODF_THRESHOLD             308  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    308, 5}, {     17, 6}, {     23, 7}, {     12, 6}, \
+    {     25, 7}, {     21, 8}, {     11, 7}, {     25, 8}, \
+    {     13, 7}, {     27, 8}, {     15, 7}, {     31, 8}, \
+    {     21, 9}, {     11, 8}, {     27, 9}, {     15, 8}, \
+    {     33, 9}, {     19, 8}, {     41, 9}, {     23, 8}, \
+    {     47, 9}, {     27,10}, {     15, 9}, {     39,10}, \
+    {     23, 9}, {     51,11}, {     15,10}, {     31, 9}, \
+    {     63,10}, {     39, 9}, {     79,10}, {     47,11}, \
+    {     31,10}, {     79,11}, {     47,12}, {     31,11}, \
+    {     63,10}, {    127, 9}, {    255,11}, {     79,10}, \
+    {    159, 6}, {   2559, 7}, {   1343, 6}, {   2687, 7}, \
+    {   1407, 9}, {    383,12}, {     63,11}, {    127,10}, \
+    {    255, 9}, {    511,10}, {    271, 9}, {    543,11}, \
+    {    143,10}, {    287, 9}, {    575,11}, {    159,10}, \
+    {    319,11}, {    175,12}, {     95,11}, {    191,10}, \
+    {    383,11}, {    207,10}, {    415,13}, {     63,12}, \
+    {    127,11}, {    255,10}, {    511,11}, {    271,10}, \
+    {    543,11}, {    287,10}, {    575,12}, {    159,11}, \
+    {    319,10}, {    639,11}, {    351,12}, {    191,11}, \
+    {    383,10}, {    767,11}, {    415,12}, {    223,11}, \
+    {    479,13}, {    127,12}, {    255,11}, {    543,12}, \
+    {    287,11}, {    575,12}, {    319,11}, {    639,12}, \
+    {    351,13}, {    191,12}, {    383,11}, {    767,12}, \
+    {    479,14}, {    127,13}, {    255,12}, {    575,13}, \
+    {    319,12}, {    703,13}, {    383,12}, {    799,13}, \
+    {    447,12}, {    895,14}, {    255,13}, {    511,12}, \
+    {   1023,13}, {    575,12}, {   1151,13}, {    639,12}, \
+    {   1279,13}, {    703,14}, {    383,13}, {    767,12}, \
+    {   1535,13}, {    959,15}, {    255,14}, {    511,13}, \
+    {   1087,12}, {   2175,13}, {   1215,14}, {    639,13}, \
+    {   1343,12}, {   2687,13}, {   1407,14}, {    767,13}, \
+    {   1599,12}, {   3199,13}, {   1663,14}, {    895,15}, \
+    {    511,14}, {   1023,13}, {   2175,14}, {   1151,13}, \
+    {   2303,12}, {   4607,13}, {   2431,12}, {   4863,14}, \
+    {   1279,13}, {   2687,14}, {   1407,15}, {    767,14}, \
+    {   1535,13}, {   3199,14}, {   1663,13}, {   3455,12}, \
+    {   6911,16}, {    511,15}, {   1023,14}, {   2303,13}, \
+    {   4607,14}, {   2431,13}, {   4863,15}, {   1279,14}, \
+    {   2943,13}, {   5887,12}, {  11775,15}, {   1535,14}, \
+    {   3455,15}, {   1791,14}, {   3583,13}, {   7167,14}, \
+    {   3839,16}, {   1023,15}, {   2047,14}, {   4223,15}, \
+    {   2303,14}, {   4863,15}, {   2815,14}, {   5887,13}, \
+    {  11775,16}, {   1535,15}, {   3071,14}, {   6143,15}, \
+    {   3327,14}, {   6911,15}, {  32768,16}, {  65536,17}, \
+    { 131072,18}, { 262144,19}, { 524288,20}, {1048576,21}, \
+    {2097152,22}, {4194304,23}, {8388608,24} }
+#define SQR_FFT_TABLE3_SIZE 183
+#define SQR_FFT_THRESHOLD                 3520
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  67
+#define MULLO_MUL_N_THRESHOLD             9174
+#define SQRLO_BASECASE_THRESHOLD            10
+#define SQRLO_DC_THRESHOLD                  11
+#define SQRLO_SQR_THRESHOLD               7035
+
+#define DC_DIV_QR_THRESHOLD                 53
+#define DC_DIVAPPR_Q_THRESHOLD             163
+#define DC_BDIV_QR_THRESHOLD                46
+#define DC_BDIV_Q_THRESHOLD                 76
+
+#define INV_MULMOD_BNM1_THRESHOLD           46
+#define INV_NEWTON_THRESHOLD               158
+#define INV_APPR_THRESHOLD                 167
+
+#define BINV_NEWTON_THRESHOLD              248
+#define REDC_1_TO_REDC_N_THRESHOLD          44
+
+#define MU_DIV_QR_THRESHOLD               1187
+#define MU_DIVAPPR_Q_THRESHOLD            1210
+#define MUPI_DIV_QR_THRESHOLD               73
+#define MU_BDIV_QR_THRESHOLD              1017
+#define MU_BDIV_Q_THRESHOLD               1187
+
+#define POWM_SEC_TABLE  1,64,105,579,1486
+
+#define GET_STR_DC_THRESHOLD                12
+#define GET_STR_PRECOMPUTE_THRESHOLD        17
+#define SET_STR_DC_THRESHOLD               134
+#define SET_STR_PRECOMPUTE_THRESHOLD      1752
+
+#define FAC_DSC_THRESHOLD                  351
+#define FAC_ODD_THRESHOLD                   27
+
+#define MATRIX22_STRASSEN_THRESHOLD         18
+#define HGCD2_DIV1_METHOD                    3  /* 2.14% faster than 5 */
+#define HGCD_THRESHOLD                     118
+#define HGCD_APPR_THRESHOLD                161
+#define HGCD_REDUCE_THRESHOLD             2121
+#define GCD_DC_THRESHOLD                   416
+#define GCDEXT_DC_THRESHOLD                351
+#define JACOBI_BASE_METHOD                   4  /* 3.56% faster than 1 */
+
+/* Tuneup completed successfully, took 132491 seconds */
diff --git a/third_party/gmp/mpn/x86_64/core2/hamdist.asm b/third_party/gmp/mpn/x86_64/core2/hamdist.asm
new file mode 100644
index 0000000..a78753d
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/core2/hamdist.asm
@@ -0,0 +1,210 @@
+dnl  AMD64 SSSE3 mpn_hamdist -- hamming distance.
+
+dnl  Copyright 2010-2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+C		    cycles/limb	  good for cpu?
+C AMD K8,K9		n/a
+C AMD K10		n/a
+C AMD bd1		 ?
+C AMD bd2		 ?
+C AMD bd3		 ?
+C AMD bd4		 ?
+C AMD zen		 ?
+C AMD bobcat		 ?
+C AMD jaguar		 ?
+C Intel P4		n/a
+C Intel CNR		 4.50		y
+C Intel PNR		 3.28		y
+C Intel NHM		 ?
+C Intel SBR		 ?
+C Intel IBR		 ?
+C Intel HWL		 ?
+C Intel BWL		 ?
+C Intel SKL		 ?
+C Intel atom		 ?
+C Intel SLM		 ?
+C VIA nano		 ?
+
+C TODO
+C  * This was hand-written without too much thought about optimal insn
+C    selection; check to see of it can be improved.
+C  * Consider doing some instruction scheduling.
+
+define(`up',		`%rdi')
+define(`vp',		`%rsi')
+define(`n',		`%rdx')
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_hamdist)
+	lea	L(cnsts)(%rip), %r9
+
+ifdef(`PIC', `define(`OFF1',32) define(`OFF2',48)',
+	     `define(`OFF1',64) define(`OFF2',80)')
+	movdqa	OFF1`'(%r9), %xmm7
+	movdqa	OFF2`'(%r9), %xmm6
+	pxor	%xmm4, %xmm4
+	pxor	%xmm5, %xmm5
+	pxor	%xmm8, %xmm8
+
+	mov	R32(n), R32(%rax)
+	and	$7, R32(%rax)
+ifdef(`PIC',`
+	movslq	(%r9,%rax,4), %rax
+	add	%r9, %rax
+	jmp	*%rax
+',`
+	jmp	*(%r9,%rax,8)
+')
+
+L(1):	movq	(up), %xmm1
+	add	$8, up
+	movq	(vp), %xmm10
+	add	$8, vp
+	pxor	%xmm10, %xmm1
+	jmp	L(e1)
+
+L(2):	add	$-48, up
+	add	$-48, vp
+	jmp	L(e2)
+
+L(3):	movq	(up), %xmm1
+	add	$-40, up
+	movq	(vp), %xmm10
+	add	$-40, vp
+	pxor	%xmm10, %xmm1
+	jmp	L(e3)
+
+L(4):	add	$-32, up
+	add	$-32, vp
+	jmp	L(e4)
+
+L(5):	movq	(up), %xmm1
+	add	$-24, up
+	movq	(vp), %xmm10
+	add	$-24, vp
+	pxor	%xmm10, %xmm1
+	jmp	L(e5)
+
+L(6):	add	$-16, up
+	add	$-16, vp
+	jmp	L(e6)
+
+L(7):	movq	(up), %xmm1
+	add	$-8, up
+	movq	(vp), %xmm10
+	add	$-8, vp
+	pxor	%xmm10, %xmm1
+	jmp	L(e7)
+
+	ALIGN(32)
+L(top):	lddqu	(up), %xmm1
+	lddqu	(vp), %xmm10
+	pxor	%xmm10, %xmm1
+L(e7):	movdqa	%xmm6, %xmm0		C copy mask register
+	movdqa	%xmm7, %xmm2		C copy count register
+	movdqa	%xmm7, %xmm3		C copy count register
+	pand	%xmm1, %xmm0
+	psrlw	$4, %xmm1
+	pand	%xmm6, %xmm1
+	pshufb	%xmm0, %xmm2
+	pshufb	%xmm1, %xmm3
+	paddb	%xmm2, %xmm3
+	paddb	%xmm3, %xmm4
+L(e6):	lddqu	16(up), %xmm1
+	lddqu	16(vp), %xmm10
+	pxor	%xmm10, %xmm1
+L(e5):	movdqa	%xmm6, %xmm0
+	movdqa	%xmm7, %xmm2
+	movdqa	%xmm7, %xmm3
+	pand	%xmm1, %xmm0
+	psrlw	$4, %xmm1
+	pand	%xmm6, %xmm1
+	pshufb	%xmm0, %xmm2
+	pshufb	%xmm1, %xmm3
+	paddb	%xmm2, %xmm3
+	paddb	%xmm3, %xmm4
+L(e4):	lddqu	32(up), %xmm1
+	lddqu	32(vp), %xmm10
+	pxor	%xmm10, %xmm1
+L(e3):	movdqa	%xmm6, %xmm0
+	movdqa	%xmm7, %xmm2
+	movdqa	%xmm7, %xmm3
+	pand	%xmm1, %xmm0
+	psrlw	$4, %xmm1
+	pand	%xmm6, %xmm1
+	pshufb	%xmm0, %xmm2
+	pshufb	%xmm1, %xmm3
+	paddb	%xmm2, %xmm3
+	paddb	%xmm3, %xmm4
+L(e2):	lddqu	48(up), %xmm1
+	add	$64, up
+	lddqu	48(vp), %xmm10
+	add	$64, vp
+	pxor	%xmm10, %xmm1
+L(e1):	movdqa	%xmm6, %xmm0
+	movdqa	%xmm7, %xmm2
+	movdqa	%xmm7, %xmm3
+	pand	%xmm1, %xmm0
+	psrlw	$4, %xmm1
+	pand	%xmm6, %xmm1
+	pshufb	%xmm0, %xmm2
+	pshufb	%xmm1, %xmm3
+	psadbw	%xmm5, %xmm4		C sum to 8 x 16-bit counts
+	paddb	%xmm2, %xmm3
+	paddq	%xmm4, %xmm8		C sum to 2 x 64-bit counts
+	movdqa	%xmm3, %xmm4
+	sub	$8, n
+	jg	L(top)
+
+	psadbw	%xmm5, %xmm4
+	paddq	%xmm4, %xmm8
+	pshufd	$14, %xmm8, %xmm0
+	paddq	%xmm8, %xmm0
+	movq	%xmm0, %rax
+	ret
+EPILOGUE()
+DEF_OBJECT(L(cnsts),16,`JUMPTABSECT')
+	JMPENT(	L(top), L(cnsts))
+	JMPENT(	L(1), L(cnsts))
+	JMPENT(	L(2), L(cnsts))
+	JMPENT(	L(3), L(cnsts))
+	JMPENT(	L(4), L(cnsts))
+	JMPENT(	L(5), L(cnsts))
+	JMPENT(	L(6), L(cnsts))
+	JMPENT(	L(7), L(cnsts))
+	.byte	0x00,0x01,0x01,0x02,0x01,0x02,0x02,0x03
+	.byte	0x01,0x02,0x02,0x03,0x02,0x03,0x03,0x04
+	.byte	0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f
+	.byte	0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f
+END_OBJECT(L(cnsts))
diff --git a/third_party/gmp/mpn/x86_64/core2/logops_n.asm b/third_party/gmp/mpn/x86_64/core2/logops_n.asm
new file mode 100644
index 0000000..5ff174c
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/core2/logops_n.asm
@@ -0,0 +1,285 @@
+dnl  AMD64 logops.
+
+dnl  Copyright 2004-2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C		c/l	c/l	c/l	good
+C	       var-1   var-2   var-3  for cpu?
+C AMD K8,K9
+C AMD K10	 1.52	 1.75	 1.75	 n
+C AMD bd1
+C AMD bd2
+C AMD bd3
+C AMD bd4
+C AMD bt1	 2.67	~2.79	~2.79	 =
+C AMD bt2	 2.15	 2.65	 2.65	 n
+C AMD zen	 1.5	 1.5	 1.5	 =
+C Intel P4
+C Intel PNR	 2.0	 2.0	 2.0	 =
+C Intel NHM	 2.0	 2.0	 2.0	 =
+C Intel SBR	 1.5	 1.5	 1.5	 y
+C Intel IBR	 1.47	 1.48	 1.48	 y
+C Intel HWL	 1.11	 1.35	 1.35	 y
+C Intel BWL	 1.09	 1.30	 1.30	 y
+C Intel SKL	 1.21	 1.27	 1.27	 y
+C Intel atom	 3.31	 3.57	 3.57	 y
+C Intel SLM	 3.0	 3.0	 3.0	 =
+C VIA nano
+
+ifdef(`OPERATION_and_n',`
+  define(`func',`mpn_and_n')
+  define(`VARIANT_1')
+  define(`LOGOP',`and')')
+ifdef(`OPERATION_andn_n',`
+  define(`func',`mpn_andn_n')
+  define(`VARIANT_2')
+  define(`LOGOP',`and')')
+ifdef(`OPERATION_nand_n',`
+  define(`func',`mpn_nand_n')
+  define(`VARIANT_3')
+  define(`LOGOP',`and')')
+ifdef(`OPERATION_ior_n',`
+  define(`func',`mpn_ior_n')
+  define(`VARIANT_1')
+  define(`LOGOP',`or')')
+ifdef(`OPERATION_iorn_n',`
+  define(`func',`mpn_iorn_n')
+  define(`VARIANT_2')
+  define(`LOGOP',`or')')
+ifdef(`OPERATION_nior_n',`
+  define(`func',`mpn_nior_n')
+  define(`VARIANT_3')
+  define(`LOGOP',`or')')
+ifdef(`OPERATION_xor_n',`
+  define(`func',`mpn_xor_n')
+  define(`VARIANT_1')
+  define(`LOGOP',`xor')')
+ifdef(`OPERATION_xnor_n',`
+  define(`func',`mpn_xnor_n')
+  define(`VARIANT_2')
+  define(`LOGOP',`xor')')
+
+define(`addptr', `lea	$1($2), $2')
+
+MULFUNC_PROLOGUE(mpn_and_n mpn_andn_n mpn_nand_n mpn_ior_n mpn_iorn_n mpn_nior_n mpn_xor_n mpn_xnor_n)
+
+C INPUT PARAMETERS
+define(`rp',`%rdi')
+define(`up',`%rsi')
+define(`vp',`%rdx')
+define(`n',`%rcx')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+
+ifdef(`VARIANT_1',`
+	TEXT
+	ALIGN(32)
+PROLOGUE(func)
+	FUNC_ENTRY(4)
+	mov	(vp), %r8
+	mov	R32(%rcx), R32(%rax)
+	and	$3, R32(%rax)
+	je	L(b00)
+	cmp	$2, R32(%rax)
+	jc	L(b01)
+	je	L(b10)
+
+L(b11):	LOGOP	(up), %r8
+	mov	%r8, (rp)
+	inc	n
+	addptr(	-8, up)
+	addptr(	-8, vp)
+	addptr(	-8, rp)
+	jmp	L(e11)
+L(b10):	add	$2, n
+	addptr(	-16, up)
+	addptr(	-16, vp)
+	addptr(	-16, rp)
+	jmp	L(e10)
+L(b01):	LOGOP	(up), %r8
+	mov	%r8, (rp)
+	dec	n
+	jz	L(ret)
+	addptr(	8, up)
+	addptr(	8, vp)
+	addptr(	8, rp)
+
+	ALIGN(16)
+L(top):	mov	(vp), %r8
+L(b00):	mov	8(vp), %r9
+	LOGOP	(up), %r8
+	LOGOP	8(up), %r9
+	mov	%r8, (rp)
+	mov	%r9, 8(rp)
+L(e11):	mov	16(vp), %r8
+L(e10):	mov	24(vp), %r9
+	addptr(	32, vp)
+	LOGOP	16(up), %r8
+	LOGOP	24(up), %r9
+	addptr(	32, up)
+	mov	%r8, 16(rp)
+	mov	%r9, 24(rp)
+	addptr(	32, rp)
+	sub	$4, n
+	jnz	L(top)
+
+L(ret):	FUNC_EXIT()
+	ret
+EPILOGUE()
+')
+
+ifdef(`VARIANT_2',`
+	TEXT
+	ALIGN(32)
+PROLOGUE(func)
+	FUNC_ENTRY(4)
+	mov	(vp), %r8
+	not	%r8
+	mov	R32(%rcx), R32(%rax)
+	and	$3, R32(%rax)
+	je	L(b00)
+	cmp	$2, R32(%rax)
+	jc	L(b01)
+	je	L(b10)
+
+L(b11):	LOGOP	(up), %r8
+	mov	%r8, (rp)
+	inc	n
+	addptr(	-8, up)
+	addptr(	-8, vp)
+	addptr(	-8, rp)
+	jmp	L(e11)
+L(b10):	add	$2, n
+	addptr(	-16, up)
+	addptr(	-16, vp)
+	addptr(	-16, rp)
+	jmp	L(e10)
+L(b01):	LOGOP	(up), %r8
+	mov	%r8, (rp)
+	dec	n
+	jz	L(ret)
+	addptr(	8, up)
+	addptr(	8, vp)
+	addptr(	8, rp)
+
+	ALIGN(16)
+L(top):	mov	(vp), %r8
+	not	%r8
+L(b00):	mov	8(vp), %r9
+	not	%r9
+	LOGOP	(up), %r8
+	LOGOP	8(up), %r9
+	mov	%r8, (rp)
+	mov	%r9, 8(rp)
+L(e11):	mov	16(vp), %r8
+	not	%r8
+L(e10):	mov	24(vp), %r9
+	not	%r9
+	addptr(	32, vp)
+	LOGOP	16(up), %r8
+	LOGOP	24(up), %r9
+	addptr(	32, up)
+	mov	%r8, 16(rp)
+	mov	%r9, 24(rp)
+	addptr(	32, rp)
+	sub	$4, n
+	jnz	L(top)
+
+L(ret):	FUNC_EXIT()
+	ret
+EPILOGUE()
+')
+
+ifdef(`VARIANT_3',`
+	TEXT
+	ALIGN(32)
+PROLOGUE(func)
+	FUNC_ENTRY(4)
+	mov	(vp), %r8
+	mov	R32(%rcx), R32(%rax)
+	and	$3, R32(%rax)
+	je	L(b00)
+	cmp	$2, R32(%rax)
+	jc	L(b01)
+	je	L(b10)
+
+L(b11):	LOGOP	(up), %r8
+	not	%r8
+	mov	%r8, (rp)
+	inc	n
+	addptr(	-8, up)
+	addptr(	-8, vp)
+	addptr(	-8, rp)
+	jmp	L(e11)
+L(b10):	add	$2, n
+	addptr(	-16, up)
+	addptr(	-16, vp)
+	addptr(	-16, rp)
+	jmp	L(e10)
+L(b01):	LOGOP	(up), %r8
+	not	%r8
+	mov	%r8, (rp)
+	dec	n
+	jz	L(ret)
+	addptr(	8, up)
+	addptr(	8, vp)
+	addptr(	8, rp)
+
+	ALIGN(16)
+L(top):	mov	(vp), %r8
+L(b00):	mov	8(vp), %r9
+	LOGOP	(up), %r8
+	not	%r8
+	LOGOP	8(up), %r9
+	not	%r9
+	mov	%r8, (rp)
+	mov	%r9, 8(rp)
+L(e11):	mov	16(vp), %r8
+L(e10):	mov	24(vp), %r9
+	addptr(	32, vp)
+	LOGOP	16(up), %r8
+	not	%r8
+	LOGOP	24(up), %r9
+	addptr(	32, up)
+	not	%r9
+	mov	%r8, 16(rp)
+	mov	%r9, 24(rp)
+	addptr(	32, rp)
+	sub	$4, n
+	jnz	L(top)
+
+L(ret):	FUNC_EXIT()
+	ret
+EPILOGUE()
+')
diff --git a/third_party/gmp/mpn/x86_64/core2/lshift.asm b/third_party/gmp/mpn/x86_64/core2/lshift.asm
new file mode 100644
index 0000000..9016a71
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/core2/lshift.asm
@@ -0,0 +1,145 @@
+dnl  x86-64 mpn_lshift optimised for Conroe/Penryn and Nehalem.
+
+dnl  Copyright 2007, 2009, 2011, 2012, 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9
+C AMD K10
+C AMD bd1
+C AMD bd2
+C AMD bd3
+C AMD bd4
+C AMD zen
+C AMD bobcat
+C AMD jaguar
+C Intel P4
+C Intel core2	 1.32
+C Intel NHM	 1.30	(drops to 2.5 for n > 256)
+C Intel SBR
+C Intel IBR
+C Intel HWL
+C Intel BWL
+C Intel SKL
+C Intel atom
+C Intel SLM
+C VIA nano
+
+C INPUT PARAMETERS
+define(`rp',	`%rdi')
+define(`up',	`%rsi')
+define(`n',	`%rdx')
+define(`cnt',	`%rcx')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_lshift)
+	FUNC_ENTRY(4)
+
+	xor	R32(%rax), R32(%rax)
+
+	test	$1, R8(n)
+	jnz	L(bx1)
+L(bx0):	test	$2, R8(n)
+	jnz	L(b10)
+
+L(b00):	lea	-8(up,n,8), up
+	lea	16(rp,n,8), rp
+	mov	(up), %r10
+	mov	-8(up), %r11
+	shld	R8(cnt), %r10, %rax
+	mov	-16(up), %r8
+	shr	$2, n
+	jmp	L(00)
+
+L(bx1):	test	$2, R8(n)
+	jnz	L(b11)
+
+L(b01):	lea	-16(up,n,8), up
+	lea	8(rp,n,8), rp
+	mov	8(up), %r9
+	shld	R8(cnt), %r9, %rax
+	shr	$2, n
+	jz	L(1)
+	mov	(up), %r10
+	mov	-8(up), %r11
+	jmp	L(01)
+
+L(b10):	lea	-24(up,n,8), up
+	lea	(rp,n,8), rp
+	mov	16(up), %r8
+	mov	8(up), %r9
+	shld	R8(cnt), %r8, %rax
+	shr	$2, n
+	jz	L(2)
+	mov	(up), %r10
+	jmp	L(10)
+
+	ALIGN(16)
+L(b11):	lea	-32(up,n,8), up
+	lea	-8(rp,n,8), rp
+	mov	24(up), %r11
+	mov	16(up), %r8
+	mov	8(up), %r9
+	shld	R8(cnt), %r11, %rax
+	shr	$2, n
+	jz	L(end)
+
+	ALIGN(16)
+L(top):	shld	R8(cnt), %r8, %r11
+	mov	(up), %r10
+	mov	%r11, (rp)
+L(10):	shld	R8(cnt), %r9, %r8
+	mov	-8(up), %r11
+	mov	%r8, -8(rp)
+L(01):	shld	R8(cnt), %r10, %r9
+	mov	-16(up), %r8
+	mov	%r9, -16(rp)
+L(00):	shld	R8(cnt), %r11, %r10
+	mov	-24(up), %r9
+	add	$-32, up
+	mov	%r10, -24(rp)
+	add	$-32, rp
+	dec	n
+	jnz	L(top)
+
+L(end):	shld	R8(cnt), %r8, %r11
+	mov	%r11, (rp)
+L(2):	shld	R8(cnt), %r9, %r8
+	mov	%r8, -8(rp)
+L(1):	shl	R8(cnt), %r9
+	mov	%r9, -16(rp)
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/core2/lshiftc.asm b/third_party/gmp/mpn/x86_64/core2/lshiftc.asm
new file mode 100644
index 0000000..c428f13
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/core2/lshiftc.asm
@@ -0,0 +1,159 @@
+dnl  x86-64 mpn_lshiftc optimised for Conroe/Penryn and Nehalem.
+
+dnl  Copyright 2007, 2009, 2011, 2012, 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9
+C AMD K10
+C AMD bd1
+C AMD bd2
+C AMD bd3
+C AMD bd4
+C AMD zen
+C AMD bobcat
+C AMD jaguar
+C Intel P4
+C Intel core2	 1.52
+C Intel NHM	 1.78	(just 2.15 for n < 256)
+C Intel SBR
+C Intel IBR
+C Intel HWL
+C Intel BWL
+C Intel SKL
+C Intel atom
+C Intel SLM
+C VIA nano
+
+C INPUT PARAMETERS
+define(`rp',	`%rdi')
+define(`up',	`%rsi')
+define(`n',	`%rdx')
+define(`cnt',	`%rcx')
+
+C TODO
+C  * This runs poorly on Nehalem compared to plain lshift, in particular for
+C    n < 256.
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_lshiftc)
+	FUNC_ENTRY(4)
+
+	xor	R32(%rax), R32(%rax)
+
+	test	$1, R8(n)
+	jnz	L(bx1)
+L(bx0):	test	$2, R8(n)
+	jnz	L(b10)
+
+L(b00):	lea	-8(up,n,8), up
+	lea	16(rp,n,8), rp
+	mov	(up), %r10
+	mov	-8(up), %r11
+	shld	R8(cnt), %r10, %rax
+	mov	-16(up), %r8
+	shr	$2, n
+	shld	R8(cnt), %r11, %r10
+	jmp	L(00)
+
+L(bx1):	test	$2, R8(n)
+	jnz	L(b11)
+
+L(b01):	lea	-16(up,n,8), up
+	lea	8(rp,n,8), rp
+	mov	8(up), %r9
+	shld	R8(cnt), %r9, %rax
+	shr	$2, n
+	jz	L(1)
+	mov	(up), %r10
+	mov	-8(up), %r11
+	shld	R8(cnt), %r10, %r9
+	jmp	L(01)
+
+L(b10):	lea	-24(up,n,8), up
+	lea	(rp,n,8), rp
+	mov	16(up), %r8
+	mov	8(up), %r9
+	shld	R8(cnt), %r8, %rax
+	shr	$2, n
+	jz	L(2)
+	mov	(up), %r10
+	shld	R8(cnt), %r9, %r8
+	jmp	L(10)
+
+	ALIGN(16)
+L(b11):	lea	-32(up,n,8), up
+	lea	-8(rp,n,8), rp
+	mov	24(up), %r11
+	mov	16(up), %r8
+	mov	8(up), %r9
+	shld	R8(cnt), %r11, %rax
+	shr	$2, n
+	jz	L(end)
+
+	ALIGN(16)
+L(top):	shld	R8(cnt), %r8, %r11
+	mov	(up), %r10
+	not	%r11
+	shld	R8(cnt), %r9, %r8
+	mov	%r11, (rp)
+L(10):	mov	-8(up), %r11
+	not	%r8
+	shld	R8(cnt), %r10, %r9
+	mov	%r8, -8(rp)
+L(01):	mov	-16(up), %r8
+	not	%r9
+	shld	R8(cnt), %r11, %r10
+	mov	%r9, -16(rp)
+L(00):	mov	-24(up), %r9
+	not	%r10
+	add	$-32, up
+	mov	%r10, -24(rp)
+	add	$-32, rp
+	dec	n
+	jnz	L(top)
+
+L(end):	shld	R8(cnt), %r8, %r11
+	not	%r11
+	mov	%r11, (rp)
+L(2):	shld	R8(cnt), %r9, %r8
+	not	%r8
+	mov	%r8, -8(rp)
+L(1):	shl	R8(cnt), %r9
+	not	%r9
+	mov	%r9, -16(rp)
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/core2/mul_basecase.asm b/third_party/gmp/mpn/x86_64/core2/mul_basecase.asm
new file mode 100644
index 0000000..d16be85
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/core2/mul_basecase.asm
@@ -0,0 +1,975 @@
+dnl  X86-64 mpn_mul_basecase optimised for Intel Nehalem/Westmere.
+dnl  It also seems good for Conroe/Wolfdale.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2008, 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C cycles/limb	mul_1		mul_2		mul_3		addmul_2
+C AMD K8,K9
+C AMD K10
+C AMD bull
+C AMD pile
+C AMD steam
+C AMD bobcat
+C AMD jaguar
+C Intel P4
+C Intel core	 4.0		 4.0		 -		4.18-4.25
+C Intel NHM	 3.75		 3.8		 -		4.06-4.2
+C Intel SBR
+C Intel IBR
+C Intel HWL
+C Intel BWL
+C Intel atom
+C VIA nano
+
+C The inner loops of this code are the result of running a code generation and
+C optimisation tool suite written by David Harvey and Torbjörn Granlund.
+
+C Code structure:
+C
+C
+C               m_1(0m4)        m_1(1m4)        m_1(2m4)        m_1(3m4)
+C                  |               |               |               |
+C        m_2(0m4)  |     m_2(1m4)  |     m_2(2m4)  |     m_2(3m4)  |
+C           |      /        |      /        |      /        |      /
+C           |     /         |     /         |     /         |     /
+C           |    /          |    /          |    /          |    /
+C          \|/ |/_         \|/ |/_         \|/ |/_         \|/ |/_
+C             _____           _____           _____           _____
+C            /     \         /     \         /     \         /     \
+C          \|/      |      \|/      |      \|/      |      \|/      |
+C        am_2(0m4)  |    am_2(1m4)  |    am_2(2m4)  |    am_2(3m4)  |
+C           \      /|\      \      /|\      \      /|\      \      /|\
+C            \_____/         \_____/         \_____/         \_____/
+
+C TODO
+C  * Tune.  None done so far.
+C  * Currently 2687 bytes, making it smaller would be nice.
+C  * Implement some basecases, say for un < 4.
+C  * Try zeroing with xor in m2 loops.
+C  * Try re-rolling the m2 loops to avoid the current 9 insn code duplication
+C    between loop header and wind-down code.
+C  * Consider adc reg,reg instead of adc $0,reg in m2 loops.  This save a byte.
+
+C When playing with pointers, set this to $2 to fall back to conservative
+C indexing in wind-down code.
+define(`I',`$1')
+
+C Define this to $1 to use late loop index variable as zero, $2 to use an
+C explicit $0.
+define(`Z',`$1')
+
+define(`rp',       `%rdi')
+define(`up',       `%rsi')
+define(`un_param', `%rdx')
+define(`vp_param', `%rcx')	C FIXME reallocate vp to rcx but watch performance!
+define(`vn_param', `%r8')
+
+define(`un',       `%r9')
+define(`vn',       `(%rsp)')
+
+define(`v0',       `%r10')
+define(`v1',       `%r11')
+define(`w0',       `%rbx')
+define(`w1',       `%rcx')
+define(`w2',       `%rbp')
+define(`w3',       `%r12')
+define(`i',        `%r13')
+define(`vp',       `%r14')
+
+define(`X0',       `%r8')
+define(`X1',       `%r15')
+
+C rax rbx rcx rdx rdi rsi rbp r8 r9 r10 r11 r12 r13 r14 r15
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+define(`ALIGNx', `ALIGN(16)')
+
+define(`N', 85)
+ifdef(`N',,`define(`N',0)')
+define(`MOV', `ifelse(eval(N & $3),0,`mov	$1, $2',`lea	($1), $2')')
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_mul_basecase)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8d	')
+	mov	(up), %rax		C shared for mul_1 and mul_2
+	push	%rbx
+	push	%rbp
+	push	%r12
+	push	%r13
+	push	%r14
+
+	mov	(vp_param), v0		C shared for mul_1 and mul_2
+
+	xor	un, un
+	sub	un_param, un		C un = -un_param
+
+	lea	(up,un_param,8), up
+	lea	(rp,un_param,8), rp
+
+	mul	v0			C shared for mul_1 and mul_2
+
+	test	$1, R8(vn_param)
+	jz	L(m2)
+
+	lea	8(vp_param), vp		C FIXME: delay until known needed
+
+	test	$1, R8(un)
+	jnz	L(m1x1)
+
+L(m1x0):test	$2, R8(un)
+	jnz	L(m1s2)
+
+L(m1s0):
+	lea	(un), i
+	mov	%rax, (rp,un,8)
+	mov	8(up,un,8), %rax
+	mov	%rdx, w0		C FIXME: Use lea?
+	lea	L(do_am0)(%rip), %rbp
+	jmp	L(m1e0)
+
+L(m1s2):
+	lea	2(un), i
+	mov	%rax, (rp,un,8)
+	mov	8(up,un,8), %rax
+	mov	%rdx, w0		C FIXME: Use lea?
+	mul	v0
+	lea	L(do_am2)(%rip), %rbp
+	test	i, i
+	jnz	L(m1e2)
+	add	%rax, w0
+	adc	$0, %rdx
+	mov	w0, I(-8(rp),8(rp,un,8))
+	mov	%rdx, I((rp),16(rp,un,8))
+	jmp	L(ret2)
+
+L(m1x1):test	$2, R8(un)
+	jz	L(m1s3)
+
+L(m1s1):
+	lea	1(un), i
+	mov	%rax, (rp,un,8)
+	test	i, i
+	jz	L(1)
+	mov	8(up,un,8), %rax
+	mov	%rdx, w1		C FIXME: Use lea?
+	lea	L(do_am1)(%rip), %rbp
+	jmp	L(m1e1)
+L(1):	mov	%rdx, I((rp),8(rp,un,8))
+	jmp	L(ret2)
+
+L(m1s3):
+	lea	-1(un), i
+	mov	%rax, (rp,un,8)
+	mov	8(up,un,8), %rax
+	mov	%rdx, w1		C FIXME: Use lea?
+	lea	L(do_am3)(%rip), %rbp
+	jmp	L(m1e3)
+
+	ALIGNx
+L(m1top):
+	mul	v0
+	mov	w1, -16(rp,i,8)
+L(m1e2):xor	R32(w1), R32(w1)
+	add	%rax, w0
+	mov	(up,i,8), %rax
+	adc	%rdx, w1
+	mov	w0, -8(rp,i,8)
+L(m1e1):xor	R32(w0), R32(w0)
+	mul	v0
+	add	%rax, w1
+	mov	8(up,i,8), %rax
+	adc	%rdx, w0
+	mov	w1, (rp,i,8)
+L(m1e0):xor	R32(w1), R32(w1)
+	mul	v0
+	add	%rax, w0
+	mov	16(up,i,8), %rax
+	adc	%rdx, w1
+	mov	w0, 8(rp,i,8)
+L(m1e3):xor	R32(w0), R32(w0)
+	mul	v0
+	add	%rax, w1
+	mov	24(up,i,8), %rax
+	adc	%rdx, w0
+	add	$4, i
+	js	L(m1top)
+
+	mul	v0
+	mov	w1, I(-16(rp),-16(rp,i,8))
+	add	%rax, w0
+	adc	$0, %rdx
+	mov	w0, I(-8(rp),-8(rp,i,8))
+	mov	%rdx, I((rp),(rp,i,8))
+
+	dec	vn_param
+	jz	L(ret2)
+	lea	-8(rp), rp
+	jmp	*%rbp
+
+L(m2):
+	mov	8(vp_param), v1
+	lea	16(vp_param), vp	C FIXME: delay until known needed
+
+	test	$1, R8(un)
+	jnz	L(bx1)
+
+L(bx0):	test	$2, R8(un)
+	jnz	L(b10)
+
+L(b00):	lea	(un), i
+	mov	%rax, (rp,un,8)
+	mov	%rdx, w1		C FIXME: Use lea?
+	mov	(up,un,8), %rax
+	mov	$0, R32(w2)
+	jmp	L(m2e0)
+
+L(b10):	lea	-2(un), i
+	mov	%rax, w2		C FIXME: Use lea?
+	mov	(up,un,8), %rax
+	mov	%rdx, w3		C FIXME: Use lea?
+	mov	$0, R32(w0)
+	jmp	L(m2e2)
+
+L(bx1):	test	$2, R8(un)
+	jz	L(b11)
+
+L(b01):	lea	1(un), i
+	mov	%rax, (rp,un,8)
+	mov	(up,un,8), %rax
+	mov	%rdx, w0		C FIXME: Use lea?
+	mov	$0, R32(w1)
+	jmp	L(m2e1)
+
+L(b11):	lea	-1(un), i
+	mov	%rax, w1		C FIXME: Use lea?
+	mov	(up,un,8), %rax
+	mov	%rdx, w2		C FIXME: Use lea?
+	mov	$0, R32(w3)
+	jmp	L(m2e3)
+
+	ALIGNx
+L(m2top0):
+	mul	v0
+	add	%rax, w3
+	mov	-8(up,i,8), %rax
+	mov	w3, -8(rp,i,8)
+	adc	%rdx, w0
+	adc	$0, R32(w1)
+	mul	v1
+	add	%rax, w0
+	adc	%rdx, w1
+	mov	$0, R32(w2)
+	mov	(up,i,8), %rax
+	mul	v0
+	add	%rax, w0
+	mov	w0, (rp,i,8)
+	adc	%rdx, w1
+	mov	(up,i,8), %rax
+	adc	$0, R32(w2)
+L(m2e0):mul	v1
+	add	%rax, w1
+	adc	%rdx, w2
+	mov	8(up,i,8), %rax
+	mul	v0
+	mov	$0, R32(w3)
+	add	%rax, w1
+	adc	%rdx, w2
+	adc	$0, R32(w3)
+	mov	8(up,i,8), %rax
+	mul	v1
+	add	%rax, w2
+	mov	w1, 8(rp,i,8)
+	adc	%rdx, w3
+	mov	$0, R32(w0)
+	mov	16(up,i,8), %rax
+	mul	v0
+	add	%rax, w2
+	mov	16(up,i,8), %rax
+	adc	%rdx, w3
+	adc	$0, R32(w0)
+	mul	v1
+	mov	$0, R32(w1)
+	add	%rax, w3
+	mov	24(up,i,8), %rax
+	mov	w2, 16(rp,i,8)
+	adc	%rdx, w0
+	add	$4, i
+	js	L(m2top0)
+
+	mul	v0
+	add	%rax, w3
+	mov	I(-8(up),-8(up,i,8)), %rax
+	mov	w3, I(-8(rp),-8(rp,i,8))
+	adc	%rdx, w0
+	adc	R32(w1), R32(w1)
+	mul	v1
+	add	%rax, w0
+	adc	%rdx, w1
+	mov	w0, I((rp),(rp,i,8))
+	mov	w1, I(8(rp),8(rp,i,8))
+
+	add	$-2, vn_param
+	jz	L(ret2)
+
+L(do_am0):
+	push	%r15
+	push	vn_param
+
+L(olo0):
+	mov	(vp), v0
+	mov	8(vp), v1
+	lea	16(vp), vp
+	lea	16(rp), rp
+	mov	(up,un,8), %rax
+C	lea	0(un), i
+	mov	un, i
+	mul	v0
+	mov	%rax, X0
+	mov	(up,un,8), %rax
+	MOV(	%rdx, X1, 2)
+	mul	v1
+	MOV(	%rdx, w0, 4)
+	mov	(rp,un,8), w2
+	mov	%rax, w3
+	jmp	L(lo0)
+
+	ALIGNx
+L(am2top0):
+	mul	v1
+	add	w0, w1
+	adc	%rax, w2
+	mov	(up,i,8), %rax
+	MOV(	%rdx, w3, 1)
+	adc	$0, w3
+	mul	v0
+	add	w1, X1
+	mov	X1, -8(rp,i,8)
+	adc	%rax, X0
+	MOV(	%rdx, X1, 2)
+	adc	$0, X1
+	mov	(up,i,8), %rax
+	mul	v1
+	MOV(	%rdx, w0, 4)
+	mov	(rp,i,8), w1
+	add	w1, w2
+	adc	%rax, w3
+	adc	$0, w0
+L(lo0):	mov	8(up,i,8), %rax
+	mul	v0
+	add	w2, X0
+	adc	%rax, X1
+	mov	X0, (rp,i,8)
+	MOV(	%rdx, X0, 8)
+	adc	$0, X0
+	mov	8(up,i,8), %rax
+	mov	8(rp,i,8), w2
+	mul	v1
+	add	w2, w3
+	adc	%rax, w0
+	MOV(	%rdx, w1, 16)
+	adc	$0, w1
+	mov	16(up,i,8), %rax
+	mul	v0
+	add	w3, X1
+	mov	X1, 8(rp,i,8)
+	adc	%rax, X0
+	MOV(	%rdx, X1, 32)
+	mov	16(rp,i,8), w3
+	adc	$0, X1
+	mov	16(up,i,8), %rax
+	mul	v1
+	add	w3, w0
+	MOV(	%rdx, w2, 64)
+	adc	%rax, w1
+	mov	24(up,i,8), %rax
+	adc	$0, w2
+	mul	v0
+	add	w0, X0
+	mov	X0, 16(rp,i,8)
+	MOV(	%rdx, X0, 128)
+	adc	%rax, X1
+	mov	24(up,i,8), %rax
+	mov	24(rp,i,8), w0
+	adc	$0, X0
+	add	$4, i
+	jnc	L(am2top0)
+
+	mul	v1
+	add	w0, w1
+	adc	%rax, w2
+	adc	Z(i,$0), %rdx
+	add	w1, X1
+	adc	Z(i,$0), X0
+	mov	X1, I(-8(rp),-8(rp,i,8))
+	add	w2, X0
+	mov	X0, I((rp),(rp,i,8))
+	adc	Z(i,$0), %rdx
+	mov	%rdx, I(8(rp),8(rp,i,8))
+
+	addl	$-2, vn
+	jnz	L(olo0)
+
+L(ret):	pop	%rax
+	pop	%r15
+L(ret2):pop	%r14
+	pop	%r13
+	pop	%r12
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+
+
+	ALIGNx
+L(m2top1):
+	mul	v0
+	add	%rax, w3
+	mov	-8(up,i,8), %rax
+	mov	w3, -8(rp,i,8)
+	adc	%rdx, w0
+	adc	$0, R32(w1)
+L(m2e1):mul	v1
+	add	%rax, w0
+	adc	%rdx, w1
+	mov	$0, R32(w2)
+	mov	(up,i,8), %rax
+	mul	v0
+	add	%rax, w0
+	mov	w0, (rp,i,8)
+	adc	%rdx, w1
+	mov	(up,i,8), %rax
+	adc	$0, R32(w2)
+	mul	v1
+	add	%rax, w1
+	adc	%rdx, w2
+	mov	8(up,i,8), %rax
+	mul	v0
+	mov	$0, R32(w3)
+	add	%rax, w1
+	adc	%rdx, w2
+	adc	$0, R32(w3)
+	mov	8(up,i,8), %rax
+	mul	v1
+	add	%rax, w2
+	mov	w1, 8(rp,i,8)
+	adc	%rdx, w3
+	mov	$0, R32(w0)
+	mov	16(up,i,8), %rax
+	mul	v0
+	add	%rax, w2
+	mov	16(up,i,8), %rax
+	adc	%rdx, w3
+	adc	$0, R32(w0)
+	mul	v1
+	mov	$0, R32(w1)
+	add	%rax, w3
+	mov	24(up,i,8), %rax
+	mov	w2, 16(rp,i,8)
+	adc	%rdx, w0
+	add	$4, i
+	js	L(m2top1)
+
+	mul	v0
+	add	%rax, w3
+	mov	I(-8(up),-8(up,i,8)), %rax
+	mov	w3, I(-8(rp),-8(rp,i,8))
+	adc	%rdx, w0
+	adc	R32(w1), R32(w1)
+	mul	v1
+	add	%rax, w0
+	adc	%rdx, w1
+	mov	w0, I((rp),(rp,i,8))
+	mov	w1, I(8(rp),8(rp,i,8))
+
+	add	$-2, vn_param
+	jz	L(ret2)
+
+L(do_am1):
+	push	%r15
+	push	vn_param
+
+L(olo1):
+	mov	(vp), v0
+	mov	8(vp), v1
+	lea	16(vp), vp
+	lea	16(rp), rp
+	mov	(up,un,8), %rax
+	lea	1(un), i
+	mul	v0
+	mov	%rax, X1
+	MOV(	%rdx, X0, 128)
+	mov	(up,un,8), %rax
+	mov	(rp,un,8), w1
+	mul	v1
+	mov	%rax, w2
+	mov	8(up,un,8), %rax
+	MOV(	%rdx, w3, 1)
+	jmp	L(lo1)
+
+	ALIGNx
+L(am2top1):
+	mul	v1
+	add	w0, w1
+	adc	%rax, w2
+	mov	(up,i,8), %rax
+	MOV(	%rdx, w3, 1)
+	adc	$0, w3
+L(lo1):	mul	v0
+	add	w1, X1
+	mov	X1, -8(rp,i,8)
+	adc	%rax, X0
+	MOV(	%rdx, X1, 2)
+	adc	$0, X1
+	mov	(up,i,8), %rax
+	mul	v1
+	MOV(	%rdx, w0, 4)
+	mov	(rp,i,8), w1
+	add	w1, w2
+	adc	%rax, w3
+	adc	$0, w0
+	mov	8(up,i,8), %rax
+	mul	v0
+	add	w2, X0
+	adc	%rax, X1
+	mov	X0, (rp,i,8)
+	MOV(	%rdx, X0, 8)
+	adc	$0, X0
+	mov	8(up,i,8), %rax
+	mov	8(rp,i,8), w2
+	mul	v1
+	add	w2, w3
+	adc	%rax, w0
+	MOV(	%rdx, w1, 16)
+	adc	$0, w1
+	mov	16(up,i,8), %rax
+	mul	v0
+	add	w3, X1
+	mov	X1, 8(rp,i,8)
+	adc	%rax, X0
+	MOV(	%rdx, X1, 32)
+	mov	16(rp,i,8), w3
+	adc	$0, X1
+	mov	16(up,i,8), %rax
+	mul	v1
+	add	w3, w0
+	MOV(	%rdx, w2, 64)
+	adc	%rax, w1
+	mov	24(up,i,8), %rax
+	adc	$0, w2
+	mul	v0
+	add	w0, X0
+	mov	X0, 16(rp,i,8)
+	MOV(	%rdx, X0, 128)
+	adc	%rax, X1
+	mov	24(up,i,8), %rax
+	mov	24(rp,i,8), w0
+	adc	$0, X0
+	add	$4, i
+	jnc	L(am2top1)
+
+	mul	v1
+	add	w0, w1
+	adc	%rax, w2
+	adc	Z(i,$0), %rdx
+	add	w1, X1
+	adc	Z(i,$0), X0
+	mov	X1, I(-8(rp),-8(rp,i,8))
+	add	w2, X0
+	mov	X0, I((rp),(rp,i,8))
+	adc	Z(i,$0), %rdx
+	mov	%rdx, I(8(rp),8(rp,i,8))
+
+	addl	$-2, vn
+	jnz	L(olo1)
+
+	pop	%rax
+	pop	%r15
+	pop	%r14
+	pop	%r13
+	pop	%r12
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+
+
+	ALIGNx
+L(m2top2):
+	mul	v0
+	add	%rax, w3
+	mov	-8(up,i,8), %rax
+	mov	w3, -8(rp,i,8)
+	adc	%rdx, w0
+	adc	$0, R32(w1)
+	mul	v1
+	add	%rax, w0
+	adc	%rdx, w1
+	mov	$0, R32(w2)
+	mov	(up,i,8), %rax
+	mul	v0
+	add	%rax, w0
+	mov	w0, (rp,i,8)
+	adc	%rdx, w1
+	mov	(up,i,8), %rax
+	adc	$0, R32(w2)
+	mul	v1
+	add	%rax, w1
+	adc	%rdx, w2
+	mov	8(up,i,8), %rax
+	mul	v0
+	mov	$0, R32(w3)
+	add	%rax, w1
+	adc	%rdx, w2
+	adc	$0, R32(w3)
+	mov	8(up,i,8), %rax
+	mul	v1
+	add	%rax, w2
+	mov	w1, 8(rp,i,8)
+	adc	%rdx, w3
+	mov	$0, R32(w0)
+	mov	16(up,i,8), %rax
+	mul	v0
+	add	%rax, w2
+	mov	16(up,i,8), %rax
+	adc	%rdx, w3
+	adc	$0, R32(w0)
+L(m2e2):mul	v1
+	mov	$0, R32(w1)
+	add	%rax, w3
+	mov	24(up,i,8), %rax
+	mov	w2, 16(rp,i,8)
+	adc	%rdx, w0
+	add	$4, i
+	js	L(m2top2)
+
+	mul	v0
+	add	%rax, w3
+	mov	I(-8(up),-8(up,i,8)), %rax
+	mov	w3, I(-8(rp),-8(rp,i,8))
+	adc	%rdx, w0
+	adc	R32(w1), R32(w1)
+	mul	v1
+	add	%rax, w0
+	adc	%rdx, w1
+	mov	w0, I((rp),(rp,i,8))
+	mov	w1, I(8(rp),8(rp,i,8))
+
+	add	$-2, vn_param
+	jz	L(ret2)
+
+L(do_am2):
+	push	%r15
+	push	vn_param
+
+L(olo2):
+	mov	(vp), v0
+	mov	8(vp), v1
+	lea	16(vp), vp
+	lea	16(rp), rp
+	mov	(up,un,8), %rax
+	lea	-2(un), i
+	mul	v0
+	mov	%rax, X0
+	MOV(	%rdx, X1, 32)
+	mov	(up,un,8), %rax
+	mov	(rp,un,8), w0
+	mul	v1
+	mov	%rax, w1
+	lea	(%rdx), w2
+	mov	8(up,un,8), %rax
+	jmp	L(lo2)
+
+	ALIGNx
+L(am2top2):
+	mul	v1
+	add	w0, w1
+	adc	%rax, w2
+	mov	(up,i,8), %rax
+	MOV(	%rdx, w3, 1)
+	adc	$0, w3
+	mul	v0
+	add	w1, X1
+	mov	X1, -8(rp,i,8)
+	adc	%rax, X0
+	MOV(	%rdx, X1, 2)
+	adc	$0, X1
+	mov	(up,i,8), %rax
+	mul	v1
+	MOV(	%rdx, w0, 4)
+	mov	(rp,i,8), w1
+	add	w1, w2
+	adc	%rax, w3
+	adc	$0, w0
+	mov	8(up,i,8), %rax
+	mul	v0
+	add	w2, X0
+	adc	%rax, X1
+	mov	X0, (rp,i,8)
+	MOV(	%rdx, X0, 8)
+	adc	$0, X0
+	mov	8(up,i,8), %rax
+	mov	8(rp,i,8), w2
+	mul	v1
+	add	w2, w3
+	adc	%rax, w0
+	MOV(	%rdx, w1, 16)
+	adc	$0, w1
+	mov	16(up,i,8), %rax
+	mul	v0
+	add	w3, X1
+	mov	X1, 8(rp,i,8)
+	adc	%rax, X0
+	MOV(	%rdx, X1, 32)
+	mov	16(rp,i,8), w3
+	adc	$0, X1
+	mov	16(up,i,8), %rax
+	mul	v1
+	add	w3, w0
+	MOV(	%rdx, w2, 64)
+	adc	%rax, w1
+	mov	24(up,i,8), %rax
+	adc	$0, w2
+L(lo2):	mul	v0
+	add	w0, X0
+	mov	X0, 16(rp,i,8)
+	MOV(	%rdx, X0, 128)
+	adc	%rax, X1
+	mov	24(up,i,8), %rax
+	mov	24(rp,i,8), w0
+	adc	$0, X0
+	add	$4, i
+	jnc	L(am2top2)
+
+	mul	v1
+	add	w0, w1
+	adc	%rax, w2
+	adc	Z(i,$0), %rdx
+	add	w1, X1
+	adc	Z(i,$0), X0
+	mov	X1, I(-8(rp),-8(rp,i,8))
+	add	w2, X0
+	mov	X0, I((rp),(rp,i,8))
+	adc	Z(i,$0), %rdx
+	mov	%rdx, I(8(rp),8(rp,i,8))
+
+	addl	$-2, vn
+	jnz	L(olo2)
+
+	pop	%rax
+	pop	%r15
+	pop	%r14
+	pop	%r13
+	pop	%r12
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+
+
+	ALIGNx
+L(m2top3):
+	mul	v0
+	add	%rax, w3
+	mov	-8(up,i,8), %rax
+	mov	w3, -8(rp,i,8)
+	adc	%rdx, w0
+	adc	$0, R32(w1)
+	mul	v1
+	add	%rax, w0
+	adc	%rdx, w1
+	mov	$0, R32(w2)
+	mov	(up,i,8), %rax
+	mul	v0
+	add	%rax, w0
+	mov	w0, (rp,i,8)
+	adc	%rdx, w1
+	mov	(up,i,8), %rax
+	adc	$0, R32(w2)
+	mul	v1
+	add	%rax, w1
+	adc	%rdx, w2
+	mov	8(up,i,8), %rax
+	mul	v0
+	mov	$0, R32(w3)
+	add	%rax, w1
+	adc	%rdx, w2
+	adc	$0, R32(w3)
+	mov	8(up,i,8), %rax
+L(m2e3):mul	v1
+	add	%rax, w2
+	mov	w1, 8(rp,i,8)
+	adc	%rdx, w3
+	mov	$0, R32(w0)
+	mov	16(up,i,8), %rax
+	mul	v0
+	add	%rax, w2
+	mov	16(up,i,8), %rax
+	adc	%rdx, w3
+	adc	$0, R32(w0)
+	mul	v1
+	mov	$0, R32(w1)
+	add	%rax, w3
+	mov	24(up,i,8), %rax
+	mov	w2, 16(rp,i,8)
+	adc	%rdx, w0
+	add	$4, i
+	js	L(m2top3)
+
+	mul	v0
+	add	%rax, w3
+	mov	I(-8(up),-8(up,i,8)), %rax
+	mov	w3, I(-8(rp),-8(rp,i,8))
+	adc	%rdx, w0
+	adc	$0, R32(w1)
+	mul	v1
+	add	%rax, w0
+	adc	%rdx, w1
+	mov	w0, I((rp),(rp,i,8))
+	mov	w1, I(8(rp),8(rp,i,8))
+
+	add	$-2, vn_param
+	jz	L(ret2)
+
+L(do_am3):
+	push	%r15
+	push	vn_param
+
+L(olo3):
+	mov	(vp), v0
+	mov	8(vp), v1
+	lea	16(vp), vp
+	lea	16(rp), rp
+	mov	(up,un,8), %rax
+	lea	-1(un), i
+	mul	v0
+	mov	%rax, X1
+	MOV(	%rdx, X0, 8)
+	mov	(up,un,8), %rax
+	mov	(rp,un,8), w3
+	mul	v1
+	mov	%rax, w0
+	MOV(	%rdx, w1, 16)
+	mov	8(up,un,8), %rax
+	jmp	L(lo3)
+
+	ALIGNx
+L(am2top3):
+	mul	v1
+	add	w0, w1
+	adc	%rax, w2
+	mov	(up,i,8), %rax
+	MOV(	%rdx, w3, 1)
+	adc	$0, w3
+	mul	v0
+	add	w1, X1
+	mov	X1, -8(rp,i,8)
+	adc	%rax, X0
+	MOV(	%rdx, X1, 2)
+	adc	$0, X1
+	mov	(up,i,8), %rax
+	mul	v1
+	MOV(	%rdx, w0, 4)
+	mov	(rp,i,8), w1
+	add	w1, w2
+	adc	%rax, w3
+	adc	$0, w0
+	mov	8(up,i,8), %rax
+	mul	v0
+	add	w2, X0
+	adc	%rax, X1
+	mov	X0, (rp,i,8)
+	MOV(	%rdx, X0, 8)
+	adc	$0, X0
+	mov	8(up,i,8), %rax
+	mov	8(rp,i,8), w2
+	mul	v1
+	add	w2, w3
+	adc	%rax, w0
+	MOV(	%rdx, w1, 16)
+	adc	$0, w1
+	mov	16(up,i,8), %rax
+L(lo3):	mul	v0
+	add	w3, X1
+	mov	X1, 8(rp,i,8)
+	adc	%rax, X0
+	MOV(	%rdx, X1, 32)
+	mov	16(rp,i,8), w3
+	adc	$0, X1
+	mov	16(up,i,8), %rax
+	mul	v1
+	add	w3, w0
+	MOV(	%rdx, w2, 64)
+	adc	%rax, w1
+	mov	24(up,i,8), %rax
+	adc	$0, w2
+	mul	v0
+	add	w0, X0
+	mov	X0, 16(rp,i,8)
+	MOV(	%rdx, X0, 128)
+	adc	%rax, X1
+	mov	24(up,i,8), %rax
+	mov	24(rp,i,8), w0
+	adc	$0, X0
+	add	$4, i
+	jnc	L(am2top3)
+
+	mul	v1
+	add	w0, w1
+	adc	%rax, w2
+	adc	Z(i,$0), %rdx
+	add	w1, X1
+	adc	Z(i,$0), X0
+	mov	X1, I(-8(rp),-8(rp,i,8))
+	add	w2, X0
+	mov	X0, I((rp),(rp,i,8))
+	adc	Z(i,$0), %rdx
+	mov	%rdx, I(8(rp),8(rp,i,8))
+
+	addl	$-2, vn
+	jnz	L(olo3)
+
+	pop	%rax
+	pop	%r15
+	pop	%r14
+	pop	%r13
+	pop	%r12
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/core2/mullo_basecase.asm b/third_party/gmp/mpn/x86_64/core2/mullo_basecase.asm
new file mode 100644
index 0000000..0f03d86
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/core2/mullo_basecase.asm
@@ -0,0 +1,427 @@
+dnl  AMD64 mpn_mullo_basecase optimised for Conroe/Wolfdale/Nehalem/Westmere.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2008, 2009, 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C cycles/limb	mul_2		addmul_2
+C AMD K8,K9
+C AMD K10
+C AMD bull
+C AMD pile
+C AMD steam
+C AMD bobcat
+C AMD jaguar
+C Intel P4
+C Intel core	 4.0		4.18-4.25
+C Intel NHM	 3.75		4.06-4.2
+C Intel SBR
+C Intel IBR
+C Intel HWL
+C Intel BWL
+C Intel atom
+C VIA nano
+
+C The inner loops of this code are the result of running a code generation and
+C optimisation tool suite written by David Harvey and Torbjörn Granlund.
+
+C TODO
+C   * Implement proper cor2, replacing current cor0.
+C   * Offset n by 2 in order to avoid the outer loop cmp.  (And sqr_basecase?)
+C   * Micro-optimise.
+
+C When playing with pointers, set this to $2 to fall back to conservative
+C indexing in wind-down code.
+define(`I',`$1')
+
+define(`rp',       `%rdi')
+define(`up',       `%rsi')
+define(`vp_param', `%rdx')
+define(`n_param',  `%rcx')
+
+define(`v0',       `%r10')
+define(`v1',       `%r11')
+define(`w0',       `%rbx')
+define(`w1',       `%rcx')
+define(`w2',       `%rbp')
+define(`w3',       `%r12')
+define(`n',        `%r9')
+define(`i',        `%r13')
+define(`vp',       `%r8')
+
+define(`X0',       `%r14')
+define(`X1',       `%r15')
+
+C rax rbx rcx rdx rdi rsi rbp r8 r9 r10 r11 r12 r13 r14 r15
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+define(`ALIGNx', `ALIGN(16)')
+
+define(`N', 85)
+ifdef(`N',,`define(`N',0)')
+define(`MOV', `ifelse(eval(N & $3),0,`mov	$1, $2',`lea	($1), $2')')
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_mullo_basecase)
+	FUNC_ENTRY(4)
+
+	mov	(up), %rax
+	mov	vp_param, vp
+
+	cmp	$4, n_param
+	jb	L(small)
+
+	mov	(vp_param), v0
+	push	%rbx
+	lea	(rp,n_param,8), rp	C point rp at R[un]
+	push	%rbp
+	lea	(up,n_param,8), up	C point up right after U's end
+	push	%r12
+	mov	$0, R32(n)		C FIXME
+	sub	n_param, n
+	push	%r13
+	mul	v0
+	mov	8(vp), v1
+
+	test	$1, R8(n_param)
+	jnz	L(m2x1)
+
+L(m2x0):test	$2, R8(n_param)
+	jnz	L(m2b2)
+
+L(m2b0):lea	(n), i
+	mov	%rax, (rp,n,8)
+	mov	%rdx, w1
+	mov	(up,n,8), %rax
+	xor	R32(w2), R32(w2)
+	jmp	L(m2e0)
+
+L(m2b2):lea	-2(n), i
+	mov	%rax, w2
+	mov	(up,n,8), %rax
+	mov	%rdx, w3
+	xor	R32(w0), R32(w0)
+	jmp	L(m2e2)
+
+L(m2x1):test	$2, R8(n_param)
+	jnz	L(m2b3)
+
+L(m2b1):lea	1(n), i
+	mov	%rax, (rp,n,8)
+	mov	(up,n,8), %rax
+	mov	%rdx, w0
+	xor	R32(w1), R32(w1)
+	jmp	L(m2e1)
+
+L(m2b3):lea	-1(n), i
+	xor	R32(w3), R32(w3)
+	mov	%rax, w1
+	mov	%rdx, w2
+	mov	(up,n,8), %rax
+	jmp	L(m2e3)
+
+	ALIGNx
+L(m2tp):mul	v0
+	add	%rax, w3
+	mov	-8(up,i,8), %rax
+	mov	w3, -8(rp,i,8)
+	adc	%rdx, w0
+	adc	$0, R32(w1)
+L(m2e1):mul	v1
+	add	%rax, w0
+	adc	%rdx, w1
+	mov	$0, R32(w2)
+	mov	(up,i,8), %rax
+	mul	v0
+	add	%rax, w0
+	mov	w0, (rp,i,8)
+	adc	%rdx, w1
+	mov	(up,i,8), %rax
+	adc	$0, R32(w2)
+L(m2e0):mul	v1
+	add	%rax, w1
+	adc	%rdx, w2
+	mov	8(up,i,8), %rax
+	mul	v0
+	mov	$0, R32(w3)
+	add	%rax, w1
+	adc	%rdx, w2
+	adc	$0, R32(w3)
+	mov	8(up,i,8), %rax
+L(m2e3):mul	v1
+	add	%rax, w2
+	mov	w1, 8(rp,i,8)
+	adc	%rdx, w3
+	mov	$0, R32(w0)
+	mov	16(up,i,8), %rax
+	mul	v0
+	add	%rax, w2
+	mov	16(up,i,8), %rax
+	adc	%rdx, w3
+	adc	$0, R32(w0)
+L(m2e2):mul	v1
+	mov	$0, R32(w1)		C FIXME: dead in last iteration
+	add	%rax, w3
+	mov	24(up,i,8), %rax
+	mov	w2, 16(rp,i,8)
+	adc	%rdx, w0		C FIXME: dead in last iteration
+	add	$4, i
+	js	L(m2tp)
+
+L(m2ed):imul	v0, %rax
+	add	w3, %rax
+	mov	%rax, I(-8(rp),-8(rp,i,8))
+
+	add	$2, n
+	lea	16(vp), vp
+	lea	-16(up), up
+	cmp	$-2, n
+	jge	L(cor1)
+
+	push	%r14
+	push	%r15
+
+L(outer):
+	mov	(vp), v0
+	mov	8(vp), v1
+	mov	(up,n,8), %rax
+	mul	v0
+	test	$1, R8(n)
+	jnz	L(a1x1)
+
+L(a1x0):mov	%rax, X1
+	MOV(	%rdx, X0, 8)
+	mov	(up,n,8), %rax
+	mul	v1
+	test	$2, R8(n)
+	jnz	L(a110)
+
+L(a100):lea	(n), i
+	mov	(rp,n,8), w3
+	mov	%rax, w0
+	MOV(	%rdx, w1, 16)
+	jmp	L(lo0)
+
+L(a110):lea	2(n), i
+	mov	(rp,n,8), w1
+	mov	%rax, w2
+	mov	8(up,n,8), %rax
+	MOV(	%rdx, w3, 1)
+	jmp	L(lo2)
+
+L(a1x1):mov	%rax, X0
+	MOV(	%rdx, X1, 2)
+	mov	(up,n,8), %rax
+	mul	v1
+	test	$2, R8(n)
+	jz	L(a111)
+
+L(a101):lea	1(n), i
+	MOV(	%rdx, w0, 4)
+	mov	(rp,n,8), w2
+	mov	%rax, w3
+	jmp	L(lo1)
+
+L(a111):lea	-1(n), i
+	MOV(	%rdx, w2, 64)
+	mov	%rax, w1
+	mov	(rp,n,8), w0
+	mov	8(up,n,8), %rax
+	jmp	L(lo3)
+
+	ALIGNx
+L(top):	mul	v1
+	add	w0, w1
+	adc	%rax, w2
+	mov	-8(up,i,8), %rax
+	MOV(	%rdx, w3, 1)
+	adc	$0, w3
+L(lo2):	mul	v0
+	add	w1, X1
+	mov	X1, -16(rp,i,8)
+	adc	%rax, X0
+	MOV(	%rdx, X1, 2)
+	adc	$0, X1
+	mov	-8(up,i,8), %rax
+	mul	v1
+	MOV(	%rdx, w0, 4)
+	mov	-8(rp,i,8), w1
+	add	w1, w2
+	adc	%rax, w3
+	adc	$0, w0
+L(lo1):	mov	(up,i,8), %rax
+	mul	v0
+	add	w2, X0
+	adc	%rax, X1
+	mov	X0, -8(rp,i,8)
+	MOV(	%rdx, X0, 8)
+	adc	$0, X0
+	mov	(up,i,8), %rax
+	mov	(rp,i,8), w2
+	mul	v1
+	add	w2, w3
+	adc	%rax, w0
+	MOV(	%rdx, w1, 16)
+	adc	$0, w1
+L(lo0):	mov	8(up,i,8), %rax
+	mul	v0
+	add	w3, X1
+	mov	X1, (rp,i,8)
+	adc	%rax, X0
+	MOV(	%rdx, X1, 32)
+	mov	8(rp,i,8), w3
+	adc	$0, X1
+	mov	8(up,i,8), %rax
+	mul	v1
+	add	w3, w0
+	MOV(	%rdx, w2, 64)
+	adc	%rax, w1
+	mov	16(up,i,8), %rax
+	adc	$0, w2
+L(lo3):	mul	v0
+	add	w0, X0
+	mov	X0, 8(rp,i,8)
+	MOV(	%rdx, X0, 128)
+	adc	%rax, X1
+	mov	16(up,i,8), %rax
+	mov	16(rp,i,8), w0
+	adc	$0, X0
+	add	$4, i
+	jnc	L(top)
+
+L(end):	imul	v1, %rax
+	add	w0, w1
+	adc	%rax, w2
+	mov	I(-8(up),-8(up,i,8)), %rax
+	imul	v0, %rax
+	add	w1, X1
+	mov	X1, I(-16(rp),-16(rp,i,8))
+	adc	X0, %rax
+	mov	I(-8(rp),-8(rp,i,8)), w1
+	add	w1, w2
+	add	w2, %rax
+	mov	%rax, I(-8(rp),-8(rp,i,8))
+
+	add	$2, n
+	lea	16(vp), vp
+	lea	-16(up), up
+	cmp	$-2, n
+	jl	L(outer)
+
+	pop	%r15
+	pop	%r14
+
+	jnz	L(cor0)
+
+L(cor1):mov	(vp), v0
+	mov	8(vp), v1
+	mov	-16(up), %rax
+	mul	v0			C u0 x v2
+	add	-16(rp), %rax		C FIXME: rp[0] still available in reg?
+	adc	-8(rp), %rdx		C FIXME: rp[1] still available in reg?
+	mov	-8(up), %rbx
+	imul	v0, %rbx
+	mov	-16(up), %rcx
+	imul	v1, %rcx
+	mov	%rax, -16(rp)
+	add	%rbx, %rcx
+	add	%rdx, %rcx
+	mov	%rcx, -8(rp)
+	pop	%r13
+	pop	%r12
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+
+L(cor0):mov	(vp), %r11
+	imul	-8(up), %r11
+	add	%rax, %r11
+	mov	%r11, -8(rp)
+	pop	%r13
+	pop	%r12
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+
+	ALIGN(16)
+L(small):
+	cmp	$2, n_param
+	jae	L(gt1)
+L(n1):	imul	(vp_param), %rax
+	mov	%rax, (rp)
+	FUNC_EXIT()
+	ret
+L(gt1):	ja	L(gt2)
+L(n2):	mov	(vp_param), %r9
+	mul	%r9
+	mov	%rax, (rp)
+	mov	8(up), %rax
+	imul	%r9, %rax
+	add	%rax, %rdx
+	mov	8(vp), %r9
+	mov	(up), %rcx
+	imul	%r9, %rcx
+	add	%rcx, %rdx
+	mov	%rdx, 8(rp)
+	FUNC_EXIT()
+	ret
+L(gt2):
+L(n3):	mov	(vp_param), %r9
+	mul	%r9		C u0 x v0
+	mov	%rax, (rp)
+	mov	%rdx, %r10
+	mov	8(up), %rax
+	mul	%r9		C u1 x v0
+	imul	16(up), %r9	C u2 x v0
+	add	%rax, %r10
+	adc	%rdx, %r9
+	mov	8(vp), %r11
+	mov	(up), %rax
+	mul	%r11		C u0 x v1
+	add	%rax, %r10
+	adc	%rdx, %r9
+	imul	8(up), %r11	C u1 x v1
+	add	%r11, %r9
+	mov	%r10, 8(rp)
+	mov	16(vp), %r10
+	mov	(up), %rax
+	imul	%rax, %r10	C u0 x v2
+	add	%r10, %r9
+	mov	%r9, 16(rp)
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/core2/popcount.asm b/third_party/gmp/mpn/x86_64/core2/popcount.asm
new file mode 100644
index 0000000..39d8c5d
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/core2/popcount.asm
@@ -0,0 +1,185 @@
+dnl  AMD64 SSSE3 mpn_popcount -- population count.
+
+dnl  Copyright 2010-2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+C		    cycles/limb	  good for cpu?
+C AMD K8,K9		n/a
+C AMD K10		n/a
+C AMD bd1	     1.79-1.91		n
+C AMD bd2	     1.73-1.85		n
+C AMD bd3		 ?
+C AMD bd4	     1.73-1.85		n
+C AMD zen		 1.47		n
+C AMD bobcat		 8.0		n
+C AMD jaguar		 4.78		n
+C Intel P4		n/a
+C Intel CNR		 3.75
+C Intel PNR		 2.61		y
+C Intel NHM		 2.03		n
+C Intel SBR		 1.87		n
+C Intel IBR	     1.52-1.58		n
+C Intel HWL	     1.52-1.58		n
+C Intel BWL	     1.52-1.58		n
+C Intel SKL		 1.51		n
+C Intel atom		12.3		n
+C Intel SLM		 9.1		n
+C VIA nano		 ?
+
+C TODO
+C  * This was hand-written without too much thought about optimal insn
+C    selection; check to see of it can be improved.
+C  * Consider doing some instruction scheduling.
+
+define(`up',		`%rdi')
+define(`n',		`%rsi')
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_popcount)
+	lea	L(cnsts)(%rip), %r9
+
+ifdef(`PIC', `define(`OFF1',32) define(`OFF2',48)',
+	     `define(`OFF1',64) define(`OFF2',80)')
+	movdqa	OFF1`'(%r9), %xmm7
+	movdqa	OFF2`'(%r9), %xmm6
+	pxor	%xmm4, %xmm4
+	pxor	%xmm5, %xmm5
+	pxor	%xmm8, %xmm8
+
+	mov	R32(n), R32(%rax)
+	and	$7, R32(%rax)
+ifdef(`PIC',`
+	movslq	(%r9,%rax,4), %rax
+	add	%r9, %rax
+	jmp	*%rax
+',`
+	jmp	*(%r9,%rax,8)
+')
+
+L(1):	movq	(up), %xmm1
+	add	$8, up
+	jmp	L(e1)
+
+L(2):	add	$-48, up
+	jmp	L(e2)
+
+L(3):	movq	(up), %xmm1
+	add	$-40, up
+	jmp	L(e3)
+
+L(4):	add	$-32, up
+	jmp	L(e4)
+
+L(5):	movq	(up), %xmm1
+	add	$-24, up
+	jmp	L(e5)
+
+L(6):	add	$-16, up
+	jmp	L(e6)
+
+L(7):	movq	(up), %xmm1
+	add	$-8, up
+	jmp	L(e7)
+
+	ALIGN(32)
+L(top):	lddqu	(up), %xmm1
+L(e7):	movdqa	%xmm6, %xmm0		C copy mask register
+	movdqa	%xmm7, %xmm2		C copy count register
+	movdqa	%xmm7, %xmm3		C copy count register
+	pand	%xmm1, %xmm0
+	psrlw	$4, %xmm1
+	pand	%xmm6, %xmm1
+	pshufb	%xmm0, %xmm2
+	pshufb	%xmm1, %xmm3
+	paddb	%xmm2, %xmm3
+	paddb	%xmm3, %xmm4
+L(e6):	lddqu	16(up), %xmm1
+L(e5):	movdqa	%xmm6, %xmm0
+	movdqa	%xmm7, %xmm2
+	movdqa	%xmm7, %xmm3
+	pand	%xmm1, %xmm0
+	psrlw	$4, %xmm1
+	pand	%xmm6, %xmm1
+	pshufb	%xmm0, %xmm2
+	pshufb	%xmm1, %xmm3
+	paddb	%xmm2, %xmm3
+	paddb	%xmm3, %xmm4
+L(e4):	lddqu	32(up), %xmm1
+L(e3):	movdqa	%xmm6, %xmm0
+	movdqa	%xmm7, %xmm2
+	movdqa	%xmm7, %xmm3
+	pand	%xmm1, %xmm0
+	psrlw	$4, %xmm1
+	pand	%xmm6, %xmm1
+	pshufb	%xmm0, %xmm2
+	pshufb	%xmm1, %xmm3
+	paddb	%xmm2, %xmm3
+	paddb	%xmm3, %xmm4
+L(e2):	lddqu	48(up), %xmm1
+	add	$64, up
+L(e1):	movdqa	%xmm6, %xmm0
+	movdqa	%xmm7, %xmm2
+	movdqa	%xmm7, %xmm3
+	pand	%xmm1, %xmm0
+	psrlw	$4, %xmm1
+	pand	%xmm6, %xmm1
+	pshufb	%xmm0, %xmm2
+	pshufb	%xmm1, %xmm3
+	psadbw	%xmm5, %xmm4		C sum to 8 x 16-bit counts
+	paddb	%xmm2, %xmm3
+	paddq	%xmm4, %xmm8		C sum to 2 x 64-bit counts
+	movdqa	%xmm3, %xmm4
+	sub	$8, n
+	jg	L(top)
+
+	psadbw	%xmm5, %xmm4
+	paddq	%xmm4, %xmm8
+	pshufd	$14, %xmm8, %xmm0
+	paddq	%xmm8, %xmm0
+	movq	%xmm0, %rax
+	ret
+EPILOGUE()
+DEF_OBJECT(L(cnsts),16,`JUMPTABSECT')
+	JMPENT(	L(top), L(cnsts))
+	JMPENT(	L(1), L(cnsts))
+	JMPENT(	L(2), L(cnsts))
+	JMPENT(	L(3), L(cnsts))
+	JMPENT(	L(4), L(cnsts))
+	JMPENT(	L(5), L(cnsts))
+	JMPENT(	L(6), L(cnsts))
+	JMPENT(	L(7), L(cnsts))
+	.byte	0x00,0x01,0x01,0x02,0x01,0x02,0x02,0x03
+	.byte	0x01,0x02,0x02,0x03,0x02,0x03,0x03,0x04
+	.byte	0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f
+	.byte	0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f
+END_OBJECT(L(cnsts))
diff --git a/third_party/gmp/mpn/x86_64/core2/redc_1.asm b/third_party/gmp/mpn/x86_64/core2/redc_1.asm
new file mode 100644
index 0000000..8c296fd
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/core2/redc_1.asm
@@ -0,0 +1,430 @@
+dnl  X86-64 mpn_redc_1 optimised for Intel Conroe and Wolfdale.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2003-2005, 2007, 2008, 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 ?
+C AMD K10	 ?
+C AMD bull	 ?
+C AMD pile	 ?
+C AMD steam	 ?
+C AMD bobcat	 ?
+C AMD jaguar	 ?
+C Intel P4	 ?
+C Intel core	 4.5  (fluctuating)
+C Intel NHM	 ?
+C Intel SBR	 ?
+C Intel IBR	 ?
+C Intel HWL	 ?
+C Intel BWL	 ?
+C Intel atom	 ?
+C VIA nano	 ?
+
+C The inner loops of this code are the result of running a code generation and
+C optimisation tool suite written by David Harvey and Torbjörn Granlund.
+
+C TODO
+C  * Micro-optimise, none performed thus far.
+C  * Consider inlining mpn_add_n.
+C  * Single basecases out before the pushes.
+C  * Keep up[i] in registers for basecases (might require pushes).
+
+C When playing with pointers, set this to $2 to fall back to conservative
+C indexing in wind-down code.
+define(`I',`$1')
+
+define(`rp',          `%rdi')   C rcx
+define(`up',          `%rsi')   C rdx
+define(`mp_param',    `%rdx')   C r8
+define(`n',           `%rcx')   C r9
+define(`u0inv',       `%r8')    C stack
+
+define(`i',           `%r14')
+define(`j',           `%r15')
+define(`mp',          `%r12')
+define(`q0',          `%r13')
+
+C rax rbx rcx rdx rdi rsi rbp r8 r9 r10 r11 r12 r13 r14 r15
+C  X  q0'  n   X  rp  up      u0i           mp   q0 i   j
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+define(`ALIGNx', `ALIGN(16)')
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_redc_1)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8	')
+	push	%rbx
+	push	%rbp
+	push	%r12
+	push	%r13
+	push	%r14
+	push	%r15
+
+	mov	(up), q0
+	mov	n, j			C outer loop induction var
+	lea	(mp_param,n,8), mp
+	lea	-16(up,n,8), up
+	neg	n
+	imul	u0inv, q0		C first iteration q0
+
+	test	$1, R8(n)
+	jz	L(b0)
+
+L(b1):	cmp	$-1, R32(n)
+	jz	L(n1)
+	cmp	$-3, R32(n)
+	jz	L(n3)
+
+	push	rp
+
+L(otp1):lea	3(n), i
+	mov	(mp,n,8), %rax
+	mul	q0
+	lea	(%rax), %rbp
+	mov	8(mp,n,8), %rax
+	lea	(%rdx), %r9
+	mul	q0
+	lea	(%rax), %r11
+	mov	16(mp,n,8), %rax
+	mov	16(up,n,8), %r10
+	lea	(%rdx), %rdi
+	mul	q0
+	add	%rbp, %r10
+	lea	(%rax), %rbp
+	mov	24(mp,n,8), %rax
+	adc	%r9, %r11
+	mov	24(up,n,8), %rbx
+	lea	(%rdx), %r9
+	adc	$0, %rdi
+	mul	q0
+	add	%r11, %rbx
+	lea	(%rax), %r11
+	mov	32(mp,n,8), %rax
+	adc	%rdi, %rbp
+	mov	%rbx, 24(up,n,8)
+	mov	32(up,n,8), %r10
+	lea	(%rdx), %rdi
+	adc	$0, %r9
+	imul	u0inv, %rbx		C next q limb
+	add	$2, i
+	jns	L(ed1)
+
+	ALIGNx
+L(tp1):	mul	q0
+	add	%rbp, %r10
+	lea	(%rax), %rbp
+	mov	(mp,i,8), %rax
+	adc	%r9, %r11
+	mov	%r10, -8(up,i,8)
+	mov	(up,i,8), %r10
+	lea	(%rdx), %r9
+	adc	$0, %rdi
+	mul	q0
+	add	%r11, %r10
+	lea	(%rax), %r11
+	mov	8(mp,i,8), %rax
+	adc	%rdi, %rbp
+	mov	%r10, (up,i,8)
+	mov	8(up,i,8), %r10
+	lea	(%rdx), %rdi
+	adc	$0, %r9
+	add	$2, i
+	js	L(tp1)
+
+L(ed1):	mul	q0
+	add	%rbp, %r10
+	adc	%r9, %r11
+	mov	%r10, I(-8(up),-8(up,i,8))
+	mov	I((up),(up,i,8)), %r10
+	adc	$0, %rdi
+	add	%r11, %r10
+	adc	%rdi, %rax
+	mov	%r10, I((up),(up,i,8))
+	mov	I(8(up),8(up,i,8)), %r10
+	adc	$0, %rdx
+	add	%rax, %r10
+	mov	%r10, I(8(up),8(up,i,8))
+	adc	$0, %rdx
+	mov	%rdx, 16(up,n,8)	C up[0]
+	mov	%rbx, q0		C previously computed q limb -> q0
+	lea	8(up), up		C up++
+	dec	j
+	jnz	L(otp1)
+	jmp	L(cj)
+
+L(b0):	cmp	$-2, R32(n)
+	jz	L(n2)
+	cmp	$-4, R32(n)
+	jz	L(n4)
+
+	push	rp
+
+L(otp0):lea	4(n), i
+	mov	(mp,n,8), %rax
+	mul	q0
+	lea	(%rax), %r11
+	mov	8(mp,n,8), %rax
+	lea	(%rdx), %rdi
+	mul	q0
+	lea	(%rax), %rbp
+	mov	16(mp,n,8), %rax
+	mov	16(up,n,8), %r10
+	lea	(%rdx), %r9
+	mul	q0
+	add	%r11, %r10
+	lea	(%rax), %r11
+	mov	24(mp,n,8), %rax
+	adc	%rdi, %rbp
+	mov	24(up,n,8), %rbx
+	lea	(%rdx), %rdi
+	adc	$0, %r9
+	mul	q0
+	add	%rbp, %rbx
+	lea	(%rax), %rbp
+	mov	32(mp,n,8), %rax
+	adc	%r9, %r11
+	mov	%rbx, 24(up,n,8)
+	mov	32(up,n,8), %r10
+	lea	(%rdx), %r9
+	adc	$0, %rdi
+	imul	u0inv, %rbx		C next q limb
+	jmp	L(e0)
+
+	ALIGNx
+L(tp0):	mul	q0
+	add	%rbp, %r10
+	lea	(%rax), %rbp
+	mov	(mp,i,8), %rax
+	adc	%r9, %r11
+	mov	%r10, -8(up,i,8)
+	mov	(up,i,8), %r10
+	lea	(%rdx), %r9
+	adc	$0, %rdi
+L(e0):	mul	q0
+	add	%r11, %r10
+	lea	(%rax), %r11
+	mov	8(mp,i,8), %rax
+	adc	%rdi, %rbp
+	mov	%r10, (up,i,8)
+	mov	8(up,i,8), %r10
+	lea	(%rdx), %rdi
+	adc	$0, %r9
+	add	$2, i
+	js	L(tp0)
+
+L(ed0):	mul	q0
+	add	%rbp, %r10
+	adc	%r9, %r11
+	mov	%r10, I(-8(up),-8(up,i,8))
+	mov	I((up),(up,i,8)), %r10
+	adc	$0, %rdi
+	add	%r11, %r10
+	adc	%rdi, %rax
+	mov	%r10, I((up),(up,i,8))
+	mov	I(8(up),8(up,i,8)), %r10
+	adc	$0, %rdx
+	add	%rax, %r10
+	mov	%r10, I(8(up),8(up,i,8))
+	adc	$0, %rdx
+	mov	%rdx, 16(up,n,8)	C up[0]
+	mov	%rbx, q0		C previously computed q limb -> q0
+	lea	8(up), up		C up++
+	dec	j
+	jnz	L(otp0)
+
+L(cj):	lea	16(up), up		C FIXME
+	pop	rp
+L(add_n):
+IFSTD(`	lea	(up,n,8), up		C param 2: up
+	lea	(up,n,8), %rdx		C param 3: up - n
+	neg	R32(n)		')	C param 4: n
+
+IFDOS(`	lea	(up,n,8), %rdx		C param 2: up
+	lea	(%rdx,n,8), %r8		C param 3: up - n
+	neg	R32(n)
+	mov	n, %r9			C param 4: n
+	mov	rp, %rcx	')	C param 1: rp
+
+IFSTD(`	sub	$8, %rsp	')
+IFDOS(`	sub	$40, %rsp	')
+	ASSERT(nz, `test $15, %rsp')
+	CALL(	mpn_add_n)
+IFSTD(`	add	$8, %rsp	')
+IFDOS(`	add	$40, %rsp	')
+
+L(ret):	pop	%r15
+	pop	%r14
+	pop	%r13
+	pop	%r12
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+
+L(n1):	mov	(mp_param), %rax
+	mul	q0
+	add	8(up), %rax
+	adc	16(up), %rdx
+	mov	%rdx, (rp)
+	mov	$0, R32(%rax)
+	adc	R32(%rax), R32(%rax)
+	jmp	L(ret)
+
+L(n2):	mov	(mp_param), %rax
+	mov	(up), %rbp
+	mul	q0
+	add	%rax, %rbp
+	mov	%rdx, %r9
+	adc	$0, %r9
+	mov	-8(mp), %rax
+	mov	8(up), %r10
+	mul	q0
+	add	%rax, %r10
+	mov	%rdx, %r11
+	adc	$0, %r11
+	add	%r9, %r10
+	adc	$0, %r11
+	mov	%r10, q0
+	imul	u0inv, q0		C next q0
+	mov	-16(mp), %rax
+	mul	q0
+	add	%rax, %r10
+	mov	%rdx, %r9
+	adc	$0, %r9
+	mov	-8(mp), %rax
+	mov	16(up), %r14
+	mul	q0
+	add	%rax, %r14
+	adc	$0, %rdx
+	add	%r9, %r14
+	adc	$0, %rdx
+	xor	R32(%rax), R32(%rax)
+	add	%r11, %r14
+	adc	24(up), %rdx
+	mov	%r14, (rp)
+	mov	%rdx, 8(rp)
+	adc	R32(%rax), R32(%rax)
+	jmp	L(ret)
+
+	ALIGNx
+L(n3):	mov	-24(mp), %rax
+	mov	-8(up), %r10
+	mul	q0
+	add	%rax, %r10
+	mov	-16(mp), %rax
+	mov	%rdx, %r11
+	adc	$0, %r11
+	mov	(up), %rbp
+	mul	q0
+	add	%rax, %rbp
+	mov	%rdx, %r9
+	adc	$0, %r9
+	mov	-8(mp), %rax
+	add	%r11, %rbp
+	mov	8(up), %r10
+	adc	$0, %r9
+	mul	q0
+	mov	%rbp, q0
+	imul	u0inv, q0		C next q0
+	add	%rax, %r10
+	mov	%rdx, %r11
+	adc	$0, %r11
+	mov	%rbp, (up)
+	add	%r9, %r10
+	adc	$0, %r11
+	mov	%r10, 8(up)
+	mov	%r11, -8(up)		C up[0]
+	lea	8(up), up		C up++
+	dec	j
+	jnz	L(n3)
+
+	mov	-32(up), %rdx
+	mov	-24(up), %rbx
+	xor	R32(%rax), R32(%rax)
+	add	%rbp, %rdx
+	adc	%r10, %rbx
+	adc	8(up), %r11
+	mov	%rdx, (rp)
+	mov	%rbx, 8(rp)
+	mov	%r11, 16(rp)
+	adc	R32(%rax), R32(%rax)
+	jmp	L(ret)
+
+	ALIGNx
+L(n4):	mov	-32(mp), %rax
+	mul	q0
+	lea	(%rax), %r11
+	mov	-24(mp), %rax
+	lea	(%rdx), %r14
+	mul	q0
+	lea	(%rax), %rbp
+	mov	-16(mp), %rax
+	mov	-16(up), %r10
+	lea	(%rdx), %r9
+	mul	q0
+	add	%r11, %r10
+	lea	(%rax), %r11
+	mov	-8(mp), %rax
+	adc	%r14, %rbp
+	mov	-8(up), %rbx
+	lea	(%rdx), %r14
+	adc	$0, %r9
+	mul	q0
+	add	%rbp, %rbx
+	adc	%r9, %r11
+	mov	%rbx, -8(up)
+	mov	(up), %r10
+	adc	$0, %r14
+	imul	u0inv, %rbx		C next q limb
+	add	%r11, %r10
+	adc	%r14, %rax
+	mov	%r10, (up)
+	mov	8(up), %r10
+	adc	$0, %rdx
+	add	%rax, %r10
+	mov	%r10, 8(up)
+	adc	$0, %rdx
+	mov	%rdx, -16(up)		C up[0]
+	mov	%rbx, q0		C previously computed q limb -> q0
+	lea	8(up), up		C up++
+	dec	j
+	jnz	L(n4)
+	lea	16(up), up
+	jmp	L(add_n)
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86_64/core2/rsh1aors_n.asm b/third_party/gmp/mpn/x86_64/core2/rsh1aors_n.asm
new file mode 100644
index 0000000..27eed37
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/core2/rsh1aors_n.asm
@@ -0,0 +1,169 @@
+dnl  X86-64 mpn_rsh1add_n, mpn_rsh1sub_n optimised for Intel Conroe/Penryn.
+
+dnl  Copyright 2003, 2005, 2009, 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 ?
+C AMD K10	 ?
+C Intel P4	 ?
+C Intel core2	 3.05
+C Intel NHM	 3.3
+C Intel SBR	 2.5
+C Intel atom	 ?
+C VIA nano	 ?
+
+C TODO
+C  * Loopmix to approach 2.5 c/l on NHM.
+
+C INPUT PARAMETERS
+define(`rp', `%rdi')
+define(`up', `%rsi')
+define(`vp', `%rdx')
+define(`n',  `%rcx')
+
+ifdef(`OPERATION_rsh1add_n', `
+	define(ADDSUB,	      add)
+	define(ADCSBB,	      adc)
+	define(func_n,	      mpn_rsh1add_n)
+	define(func_nc,	      mpn_rsh1add_nc)')
+ifdef(`OPERATION_rsh1sub_n', `
+	define(ADDSUB,	      sub)
+	define(ADCSBB,	      sbb)
+	define(func_n,	      mpn_rsh1sub_n)
+	define(func_nc,	      mpn_rsh1sub_nc)')
+
+MULFUNC_PROLOGUE(mpn_rsh1add_n mpn_rsh1add_nc mpn_rsh1sub_n mpn_rsh1sub_nc)
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(func_nc)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8	')
+	push	%rbx
+	push	%rbp
+
+	neg	%r8			C set C flag from parameter
+	mov	(up), %r8
+	ADCSBB	(vp), %r8
+	jmp	L(ent)
+EPILOGUE()
+
+	ALIGN(16)
+PROLOGUE(func_n)
+	FUNC_ENTRY(4)
+	push	%rbx
+	push	%rbp
+
+	mov	(up), %r8
+	ADDSUB	(vp), %r8
+L(ent):	sbb	R32(%rbx), R32(%rbx)	C save cy
+	mov	%r8, %rax
+	and	$1, R32(%rax)		C return value
+
+	lea	(up,n,8), up
+	lea	(vp,n,8), vp
+	lea	(rp,n,8), rp
+	mov	R32(n), R32(%rbp)
+	neg	n
+	and	$3, R32(%rbp)
+	jz	L(b0)
+	cmp	$2, R32(%rbp)
+	jae	L(n1)
+
+L(b1):	mov	%r8, %rbp
+	inc	n
+	js	L(top)
+	jmp	L(end)
+
+L(n1):	jnz	L(b3)
+	add	R32(%rbx), R32(%rbx)	C restore cy
+	mov	8(up,n,8), %r11
+	ADCSBB	8(vp,n,8), %r11
+	sbb	R32(%rbx), R32(%rbx)	C save cy
+	mov	%r8, %r10
+	add	$-2, n
+	jmp	L(2)
+
+L(b3):	add	R32(%rbx), R32(%rbx)	C restore cy
+	mov	8(up,n,8), %r10
+	mov	16(up,n,8), %r11
+	ADCSBB	8(vp,n,8), %r10
+	ADCSBB	16(vp,n,8), %r11
+	sbb	R32(%rbx), R32(%rbx)	C save cy
+	mov	%r8, %r9
+	dec	n
+	jmp	L(3)
+
+L(b0):	add	R32(%rbx), R32(%rbx)	C restore cy
+	mov	8(up,n,8), %r9
+	mov	16(up,n,8), %r10
+	mov	24(up,n,8), %r11
+	ADCSBB	8(vp,n,8), %r9
+	ADCSBB	16(vp,n,8), %r10
+	ADCSBB	24(vp,n,8), %r11
+	sbb	R32(%rbx), R32(%rbx)	C save cy
+	jmp	L(4)
+
+	ALIGN(16)
+
+L(top):	add	R32(%rbx), R32(%rbx)	C restore cy
+	mov	(up,n,8), %r8
+	mov	8(up,n,8), %r9
+	mov	16(up,n,8), %r10
+	mov	24(up,n,8), %r11
+	ADCSBB	(vp,n,8), %r8
+	ADCSBB	8(vp,n,8), %r9
+	ADCSBB	16(vp,n,8), %r10
+	ADCSBB	24(vp,n,8), %r11
+	sbb	R32(%rbx), R32(%rbx)	C save cy
+	shrd	$1, %r8, %rbp
+	mov	%rbp, -8(rp,n,8)
+L(4):	shrd	$1, %r9, %r8
+	mov	%r8, (rp,n,8)
+L(3):	shrd	$1, %r10, %r9
+	mov	%r9, 8(rp,n,8)
+L(2):	shrd	$1, %r11, %r10
+	mov	%r10, 16(rp,n,8)
+L(1):	add	$4, n
+	mov	%r11, %rbp
+	js	L(top)
+
+L(end):	shrd	$1, %rbx, %rbp
+	mov	%rbp, -8(rp)
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/core2/rshift.asm b/third_party/gmp/mpn/x86_64/core2/rshift.asm
new file mode 100644
index 0000000..7578a53
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/core2/rshift.asm
@@ -0,0 +1,143 @@
+dnl  x86-64 mpn_rshift optimised for Conroe/Penryn and Nehalem.
+
+dnl  Copyright 2007, 2009, 2011, 2012, 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9
+C AMD K10
+C AMD bd1
+C AMD bd2
+C AMD bd3
+C AMD bd4
+C AMD zen
+C AMD bobcat
+C AMD jaguar
+C Intel P4
+C Intel core2	 1.32
+C Intel NHM	 1.30	(drops to 2.5 for n > 256)
+C Intel SBR
+C Intel IBR
+C Intel HWL
+C Intel BWL
+C Intel SKL
+C Intel atom
+C Intel SLM
+C VIA nano
+
+C INPUT PARAMETERS
+define(`rp',	`%rdi')
+define(`up',	`%rsi')
+define(`n',	`%rdx')
+define(`cnt',	`%rcx')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_rshift)
+	FUNC_ENTRY(4)
+
+	xor	R32(%rax), R32(%rax)
+
+	test	$1, R8(n)
+	jnz	L(bx1)
+L(bx0):	test	$2, R8(n)
+	jnz	L(b10)
+
+L(b00):	lea	8(up), up
+	lea	-24(rp), rp
+	mov	-8(up), %r10
+	mov	(up), %r11
+	shrd	R8(cnt), %r10, %rax
+	mov	8(up), %r8
+	shr	$2, n
+	jmp	L(00)
+
+L(bx1):	test	$2, R8(n)
+	jnz	L(b11)
+
+L(b01):	lea	16(up), up
+	lea	-16(rp), rp
+	mov	-16(up), %r9
+	shrd	R8(cnt), %r9, %rax
+	shr	$2, n
+	jz	L(1)
+	mov	-8(up), %r10
+	mov	(up), %r11
+	jmp	L(01)
+
+L(b10):	lea	24(up), up
+	lea	-8(rp), rp
+	mov	-24(up), %r8
+	mov	-16(up), %r9
+	shrd	R8(cnt), %r8, %rax
+	shr	$2, n
+	jz	L(2)
+	mov	-8(up), %r10
+	jmp	L(10)
+
+L(b11):	lea	32(up), up
+	mov	-32(up), %r11
+	mov	-24(up), %r8
+	mov	-16(up), %r9
+	shrd	R8(cnt), %r11, %rax
+	shr	$2, n
+	jz	L(end)
+
+	ALIGN(16)
+L(top):	shrd	R8(cnt), %r8, %r11
+	mov	-8(up), %r10
+	mov	%r11, (rp)
+L(10):	shrd	R8(cnt), %r9, %r8
+	mov	(up), %r11
+	mov	%r8, 8(rp)
+L(01):	shrd	R8(cnt), %r10, %r9
+	mov	8(up), %r8
+	mov	%r9, 16(rp)
+L(00):	shrd	R8(cnt), %r11, %r10
+	mov	16(up), %r9
+	add	$32, up
+	mov	%r10, 24(rp)
+	add	$32, rp
+	dec	n
+	jnz	L(top)
+
+L(end):	shrd	R8(cnt), %r8, %r11
+	mov	%r11, (rp)
+L(2):	shrd	R8(cnt), %r9, %r8
+	mov	%r8, 8(rp)
+L(1):	shr	R8(cnt), %r9
+	mov	%r9, 16(rp)
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/core2/sec_tabselect.asm b/third_party/gmp/mpn/x86_64/core2/sec_tabselect.asm
new file mode 100644
index 0000000..e436034
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/core2/sec_tabselect.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_sec_tabselect.
+
+dnl  Copyright 2012, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_sec_tabselect)
+include_mpn(`x86_64/fastsse/sec_tabselect.asm')
diff --git a/third_party/gmp/mpn/x86_64/core2/sqr_basecase.asm b/third_party/gmp/mpn/x86_64/core2/sqr_basecase.asm
new file mode 100644
index 0000000..a112c1b
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/core2/sqr_basecase.asm
@@ -0,0 +1,984 @@
+dnl  X86-64 mpn_sqr_basecase optimised for Intel Nehalem/Westmere.
+dnl  It also seems good for Conroe/Wolfdale.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2008, 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C cycles/limb	mul_2		addmul_2	sqr_diag_addlsh1
+C AMD K8,K9
+C AMD K10
+C AMD bull
+C AMD pile
+C AMD steam
+C AMD bobcat
+C AMD jaguar
+C Intel P4
+C Intel core	 4.9		4.18-4.25		 3.87
+C Intel NHM	 3.8		4.06-4.2		 3.5
+C Intel SBR
+C Intel IBR
+C Intel HWL
+C Intel BWL
+C Intel atom
+C VIA nano
+
+C The inner loops of this code are the result of running a code generation and
+C optimisation tool suite written by David Harvey and Torbjörn Granlund.
+
+C Code structure:
+C
+C
+C        m_2(0m4)        m_2(2m4)        m_2(1m4)        m_2(3m4)
+C           |               |               |               |
+C           |               |               |               |
+C           |               |               |               |
+C          \|/             \|/             \|/             \|/
+C              ____________                   ____________
+C             /            \                 /            \
+C            \|/            \               \|/            \
+C         am_2(3m4)       am_2(1m4)       am_2(0m4)       am_2(2m4)
+C            \            /|\                \            /|\
+C             \____________/                  \____________/
+C                       \                        /
+C                        \                      /
+C                         \                    /
+C                       tail(0m2)          tail(1m2)
+C                            \              /
+C                             \            /
+C                            sqr_diag_addlsh1
+
+C TODO
+C  * Tune.  None done so far.
+C  * Currently 2761 bytes, making it smaller would be nice.
+C  * Consider using a jumptab-based entry sequence.  One might even use a mask-
+C    less sequence, if the table is large enough to support tuneup's needs.
+C    The code would be, using non-PIC code,
+C        lea tab(%rip),%rax; jmp *(n,%rax)
+C    or,
+C        lea tab(%rip),%rax; lea (%rip),%rbx; add (n,%rax),%rbx; jmp *%rbx
+C    using PIC code.  The table entries would be Ln1,Ln2,Ln3,Lm0,Lm1,Lm2,Lm3,..
+C    with the last four entries repeated a safe number of times.
+C  * Consider expanding feed-in code in order to avoid zeroing registers.
+C  * Zero consistently with xor.
+C  * Check if using "lea (reg),reg" should be done in more places; we have some
+C    explicit "mov %rax,reg" now.
+C  * Try zeroing with xor in m2 loops.
+C  * Try re-rolling the m2 loops to avoid the current 9 insn code duplication
+C    between loop header and wind-down code.
+C  * Consider adc reg,reg instead of adc $0,reg in m2 loops.  This save a byte.
+
+C When playing with pointers, set this to $2 to fall back to conservative
+C indexing in wind-down code.
+define(`I',`$1')
+
+C Define this to $1 to use late loop index variable as zero, $2 to use an
+C explicit $0.
+define(`Z',`$1')
+
+define(`rp',       `%rdi')
+define(`up',       `%rsi')
+define(`n_param',  `%rdx')
+
+define(`n',        `%r8')
+
+define(`v0',       `%r10')
+define(`v1',       `%r11')
+define(`w0',       `%rbx')
+define(`w1',       `%rcx')
+define(`w2',       `%rbp')
+define(`w3',       `%r9')
+define(`i',        `%r13')
+
+define(`X0',       `%r12')
+define(`X1',       `%r14')
+
+C rax rbx rcx rdx rdi rsi rbp r8 r9 r10 r11 r12 r13 r14 r15
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+define(`ALIGNx', `ALIGN(16)')
+
+define(`N', 85)
+ifdef(`N',,`define(`N',0)')
+define(`MOV', `ifelse(eval(N & $3),0,`mov	$1, $2',`lea	($1), $2')')
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_sqr_basecase)
+	FUNC_ENTRY(3)
+
+	cmp	$4, n_param
+	jl	L(small)
+
+	push	%rbx
+	push	%rbp
+	push	%r12
+	push	%r13
+	push	%r14
+
+	mov	(up), v0
+	mov	8(up), %rax
+	mov	%rax, v1
+
+	mov	$1, R32(n)
+	sub	n_param, n		C n = -n_param+1
+	push	n
+
+	lea	(up,n_param,8), up
+	lea	(rp,n_param,8), rp
+
+	mul	v0
+
+	test	$1, R8(n)
+	jnz	L(bx1)
+
+L(bx0):	test	$2, R8(n)
+	mov	%rax, (rp,n,8)
+	jnz	L(b10)
+
+L(b00):	lea	(n), i			C n = 5, 9, ...
+	mov	%rdx, w1		C FIXME: Use lea?
+	xor	R32(w2), R32(w2)
+	jmp	L(m2e0)
+
+L(b10):	lea	2(n), i			C n = 7, 11, ...
+	mov	8(up,n,8), %rax
+	mov	%rdx, w3		C FIXME: Use lea?
+	xor	R32(w0), R32(w0)
+	xor	R32(w1), R32(w1)
+	jmp	L(m2e2)
+
+L(bx1):	test	$2, R8(n)
+	mov	%rax, (rp,n,8)
+	jz	L(b11)
+
+L(b01):	lea	1(n), i			C n = 6, 10, ...
+	mov	%rdx, w0		C FIXME: Use lea?
+	xor	R32(w1), R32(w1)
+	jmp	L(m2e1)
+
+L(b11):	lea	-1(n), i		C n = 4, 8, 12, ...
+	mov	%rdx, w2		C FIXME: Use lea?
+	xor	R32(w3), R32(w3)
+	jmp	L(m2e3)
+
+
+	ALIGNx
+L(m2top1):
+	mul	v0
+	add	%rax, w3
+	mov	-8(up,i,8), %rax
+	mov	w3, -8(rp,i,8)
+	adc	%rdx, w0
+	adc	$0, R32(w1)
+	mul	v1
+	add	%rax, w0
+	adc	%rdx, w1
+L(m2e1):mov	$0, R32(w2)
+	mov	(up,i,8), %rax
+	mul	v0
+	add	%rax, w0
+	mov	w0, (rp,i,8)
+	adc	%rdx, w1
+	mov	(up,i,8), %rax
+	adc	$0, R32(w2)
+	mul	v1
+	add	%rax, w1
+	adc	%rdx, w2
+	mov	8(up,i,8), %rax
+	mul	v0
+	mov	$0, R32(w3)
+	add	%rax, w1
+	adc	%rdx, w2
+	adc	$0, R32(w3)
+	mov	8(up,i,8), %rax
+	mul	v1
+	add	%rax, w2
+	mov	w1, 8(rp,i,8)
+	adc	%rdx, w3
+	mov	$0, R32(w0)
+	mov	16(up,i,8), %rax
+	mul	v0
+	add	%rax, w2
+	mov	16(up,i,8), %rax
+	adc	%rdx, w3
+	adc	$0, R32(w0)
+	mul	v1
+	mov	$0, R32(w1)
+	add	%rax, w3
+	mov	24(up,i,8), %rax
+	mov	w2, 16(rp,i,8)
+	adc	%rdx, w0
+	add	$4, i
+	js	L(m2top1)
+
+	mul	v0
+	add	%rax, w3
+	mov	I(-8(up),-8(up,i,8)), %rax
+	mov	w3, I(-8(rp),-8(rp,i,8))
+	adc	%rdx, w0
+	adc	R32(w1), R32(w1)
+	mul	v1
+	add	w0, %rax
+	adc	w1, %rdx
+	mov	%rax, I((rp),(rp,i,8))
+	mov	%rdx, I(8(rp),8(rp,i,8))
+
+	lea	16(rp), rp
+	add	$2, n			C decrease |n|
+	jmp	L(am2o3)
+
+	ALIGNx
+L(m2top3):
+	mul	v0
+	add	%rax, w3
+	mov	-8(up,i,8), %rax
+	mov	w3, -8(rp,i,8)
+	adc	%rdx, w0
+	adc	$0, R32(w1)
+	mul	v1
+	add	%rax, w0
+	adc	%rdx, w1
+	mov	$0, R32(w2)
+	mov	(up,i,8), %rax
+	mul	v0
+	add	%rax, w0
+	mov	w0, (rp,i,8)
+	adc	%rdx, w1
+	mov	(up,i,8), %rax
+	adc	$0, R32(w2)
+	mul	v1
+	add	%rax, w1
+	adc	%rdx, w2
+	mov	8(up,i,8), %rax
+	mul	v0
+	mov	$0, R32(w3)
+	add	%rax, w1
+	adc	%rdx, w2
+	adc	$0, R32(w3)
+	mov	8(up,i,8), %rax
+	mul	v1
+	add	%rax, w2
+	mov	w1, 8(rp,i,8)
+	adc	%rdx, w3
+L(m2e3):mov	$0, R32(w0)
+	mov	16(up,i,8), %rax
+	mul	v0
+	add	%rax, w2
+	mov	16(up,i,8), %rax
+	adc	%rdx, w3
+	adc	$0, R32(w0)
+	mul	v1
+	mov	$0, R32(w1)
+	add	%rax, w3
+	mov	24(up,i,8), %rax
+	mov	w2, 16(rp,i,8)
+	adc	%rdx, w0
+	add	$4, i
+	js	L(m2top3)
+
+	mul	v0
+	add	%rax, w3
+	mov	I(-8(up),-8(up,i,8)), %rax
+	mov	w3, I(-8(rp),-8(rp,i,8))
+	adc	%rdx, w0
+	adc	R32(w1), R32(w1)
+	mul	v1
+	add	w0, %rax
+	adc	w1, %rdx
+	mov	%rax, I((rp),(rp,i,8))
+	mov	%rdx, I(8(rp),8(rp,i,8))
+
+	lea	16(rp), rp
+	add	$2, n			C decrease |n|
+	cmp	$-1, n
+	jz	L(cor1)			C jumps iff entry n = 4
+
+L(am2o1):
+	mov	-8(up,n,8), v0
+	mov	(up,n,8), %rax
+	mov	%rax, v1
+	lea	1(n), i
+	mul	v0
+	mov	%rax, X1
+	MOV(	%rdx, X0, 128)
+	mov	(rp,n,8), w1
+	xor	R32(w2), R32(w2)
+	mov	8(up,n,8), %rax
+	xor	R32(w3), R32(w3)
+	jmp	L(lo1)
+
+	ALIGNx
+L(am2top1):
+	mul	v1
+	add	w0, w1
+	adc	%rax, w2
+	mov	(up,i,8), %rax
+	MOV(	%rdx, w3, 1)
+	adc	$0, w3
+L(lo1):	mul	v0
+	add	w1, X1
+	mov	X1, -8(rp,i,8)
+	adc	%rax, X0
+	MOV(	%rdx, X1, 2)
+	adc	$0, X1
+	mov	(up,i,8), %rax
+	mul	v1
+	MOV(	%rdx, w0, 4)
+	mov	(rp,i,8), w1
+	add	w1, w2
+	adc	%rax, w3
+	adc	$0, w0
+	mov	8(up,i,8), %rax
+	mul	v0
+	add	w2, X0
+	adc	%rax, X1
+	mov	X0, (rp,i,8)
+	MOV(	%rdx, X0, 8)
+	adc	$0, X0
+	mov	8(up,i,8), %rax
+	mov	8(rp,i,8), w2
+	mul	v1
+	add	w2, w3
+	adc	%rax, w0
+	MOV(	%rdx, w1, 16)
+	adc	$0, w1
+	mov	16(up,i,8), %rax
+	mul	v0
+	add	w3, X1
+	mov	X1, 8(rp,i,8)
+	adc	%rax, X0
+	MOV(	%rdx, X1, 32)
+	mov	16(rp,i,8), w3
+	adc	$0, X1
+	mov	16(up,i,8), %rax
+	mul	v1
+	add	w3, w0
+	MOV(	%rdx, w2, 64)
+	adc	%rax, w1
+	mov	24(up,i,8), %rax
+	adc	$0, w2
+	mul	v0
+	add	w0, X0
+	mov	X0, 16(rp,i,8)
+	MOV(	%rdx, X0, 128)
+	adc	%rax, X1
+	mov	24(up,i,8), %rax
+	mov	24(rp,i,8), w0
+	adc	$0, X0
+	add	$4, i
+	jnc	L(am2top1)
+
+	mul	v1
+	add	w0, w1
+	adc	w2, %rax
+	adc	Z(i,$0), %rdx
+	add	w1, X1
+	adc	Z(i,$0), X0
+	mov	X1, I(-8(rp),-8(rp,i,8))
+	add	X0, %rax
+	mov	%rax, I((rp),(rp,i,8))
+	adc	Z(i,$0), %rdx
+	mov	%rdx, I(8(rp),8(rp,i,8))
+
+	lea	16(rp), rp
+	add	$2, n
+
+L(am2o3):
+	mov	-8(up,n,8), v0
+	mov	(up,n,8), %rax
+	mov	%rax, v1
+	lea	-1(n), i
+	mul	v0
+	mov	%rax, X1
+	MOV(	%rdx, X0, 8)
+	mov	(rp,n,8), w3
+	xor	R32(w0), R32(w0)
+	xor	R32(w1), R32(w1)
+	mov	8(up,n,8), %rax
+	jmp	L(lo3)
+
+	ALIGNx
+L(am2top3):
+	mul	v1
+	add	w0, w1
+	adc	%rax, w2
+	mov	(up,i,8), %rax
+	MOV(	%rdx, w3, 1)
+	adc	$0, w3
+	mul	v0
+	add	w1, X1
+	mov	X1, -8(rp,i,8)
+	adc	%rax, X0
+	MOV(	%rdx, X1, 2)
+	adc	$0, X1
+	mov	(up,i,8), %rax
+	mul	v1
+	MOV(	%rdx, w0, 4)
+	mov	(rp,i,8), w1
+	add	w1, w2
+	adc	%rax, w3
+	adc	$0, w0
+	mov	8(up,i,8), %rax
+	mul	v0
+	add	w2, X0
+	adc	%rax, X1
+	mov	X0, (rp,i,8)
+	MOV(	%rdx, X0, 8)
+	adc	$0, X0
+	mov	8(up,i,8), %rax
+	mov	8(rp,i,8), w2
+	mul	v1
+	add	w2, w3
+	adc	%rax, w0
+	MOV(	%rdx, w1, 16)
+	adc	$0, w1
+	mov	16(up,i,8), %rax
+L(lo3):	mul	v0
+	add	w3, X1
+	mov	X1, 8(rp,i,8)
+	adc	%rax, X0
+	MOV(	%rdx, X1, 32)
+	mov	16(rp,i,8), w3
+	adc	$0, X1
+	mov	16(up,i,8), %rax
+	mul	v1
+	add	w3, w0
+	MOV(	%rdx, w2, 64)
+	adc	%rax, w1
+	mov	24(up,i,8), %rax
+	adc	$0, w2
+	mul	v0
+	add	w0, X0
+	mov	X0, 16(rp,i,8)
+	MOV(	%rdx, X0, 128)
+	adc	%rax, X1
+	mov	24(up,i,8), %rax
+	mov	24(rp,i,8), w0
+	adc	$0, X0
+	add	$4, i
+	jnc	L(am2top3)
+
+	mul	v1
+	add	w0, w1
+	adc	w2, %rax
+	adc	Z(i,$0), %rdx
+	add	w1, X1
+	adc	Z(i,$0), X0
+	mov	X1, I(-8(rp),-8(rp,i,8))
+	add	X0, %rax
+	mov	%rax, I((rp),(rp,i,8))
+	adc	Z(i,$0), %rdx
+	mov	%rdx, I(8(rp),8(rp,i,8))
+
+	lea	16(rp), rp
+	add	$2, n
+	cmp	$-1, n
+	jnz	L(am2o1)
+
+L(cor1):pop	n
+	mov	%rdx, w3
+	mov	-16(up), v0
+	mov	-8(up), %rax
+	mul	v0
+	add	w3, %rax
+	adc	$0, %rdx
+	mov	%rax, -8(rp)
+	mov	%rdx, (rp)
+	jmp	L(sqr_diag_addlsh1)
+
+	ALIGNx
+L(m2top2):
+L(m2e2):mul	v0
+	add	%rax, w3
+	mov	-8(up,i,8), %rax
+	mov	w3, -8(rp,i,8)
+	adc	%rdx, w0
+	adc	$0, R32(w1)
+	mul	v1
+	add	%rax, w0
+	adc	%rdx, w1
+	mov	$0, R32(w2)
+	mov	(up,i,8), %rax
+	mul	v0
+	add	%rax, w0
+	mov	w0, (rp,i,8)
+	adc	%rdx, w1
+	mov	(up,i,8), %rax
+	adc	$0, R32(w2)
+	mul	v1
+	add	%rax, w1
+	adc	%rdx, w2
+	mov	8(up,i,8), %rax
+	mul	v0
+	mov	$0, R32(w3)
+	add	%rax, w1
+	adc	%rdx, w2
+	adc	$0, R32(w3)
+	mov	8(up,i,8), %rax
+	mul	v1
+	add	%rax, w2
+	mov	w1, 8(rp,i,8)
+	adc	%rdx, w3
+	mov	$0, R32(w0)
+	mov	16(up,i,8), %rax
+	mul	v0
+	add	%rax, w2
+	mov	16(up,i,8), %rax
+	adc	%rdx, w3
+	adc	$0, R32(w0)
+	mul	v1
+	mov	$0, R32(w1)
+	add	%rax, w3
+	mov	24(up,i,8), %rax
+	mov	w2, 16(rp,i,8)
+	adc	%rdx, w0
+	add	$4, i
+	js	L(m2top2)
+
+	mul	v0
+	add	%rax, w3
+	mov	I(-8(up),-8(up,i,8)), %rax
+	mov	w3, I(-8(rp),-8(rp,i,8))
+	adc	%rdx, w0
+	adc	R32(w1), R32(w1)
+	mul	v1
+	add	w0, %rax
+	adc	w1, %rdx
+	mov	%rax, I((rp),(rp,i,8))
+	mov	%rdx, I(8(rp),8(rp,i,8))
+
+	lea	16(rp), rp
+	add	$2, n			C decrease |n|
+	jmp	L(am2o0)
+
+	ALIGNx
+L(m2top0):
+	mul	v0
+	add	%rax, w3
+	mov	-8(up,i,8), %rax
+	mov	w3, -8(rp,i,8)
+	adc	%rdx, w0
+	adc	$0, R32(w1)
+	mul	v1
+	add	%rax, w0
+	adc	%rdx, w1
+	mov	$0, R32(w2)
+	mov	(up,i,8), %rax
+	mul	v0
+	add	%rax, w0
+	mov	w0, (rp,i,8)
+	adc	%rdx, w1
+	mov	(up,i,8), %rax
+	adc	$0, R32(w2)
+	mul	v1
+	add	%rax, w1
+	adc	%rdx, w2
+L(m2e0):mov	8(up,i,8), %rax
+	mul	v0
+	mov	$0, R32(w3)
+	add	%rax, w1
+	adc	%rdx, w2
+	adc	$0, R32(w3)
+	mov	8(up,i,8), %rax
+	mul	v1
+	add	%rax, w2
+	mov	w1, 8(rp,i,8)
+	adc	%rdx, w3
+	mov	$0, R32(w0)
+	mov	16(up,i,8), %rax
+	mul	v0
+	add	%rax, w2
+	mov	16(up,i,8), %rax
+	adc	%rdx, w3
+	adc	$0, R32(w0)
+	mul	v1
+	mov	$0, R32(w1)
+	add	%rax, w3
+	mov	24(up,i,8), %rax
+	mov	w2, 16(rp,i,8)
+	adc	%rdx, w0
+	add	$4, i
+	js	L(m2top0)
+
+	mul	v0
+	add	%rax, w3
+	mov	I(-8(up),-8(up,i,8)), %rax
+	mov	w3, I(-8(rp),-8(rp,i,8))
+	adc	%rdx, w0
+	adc	R32(w1), R32(w1)
+	mul	v1
+	add	w0, %rax
+	adc	w1, %rdx
+	mov	%rax, I((rp),(rp,i,8))
+	mov	%rdx, I(8(rp),8(rp,i,8))
+
+	lea	16(rp), rp
+	add	$2, n			C decrease |n|
+	cmp	$-2, n
+	jz	L(cor2)			C jumps iff entry n = 5
+
+L(am2o2):
+	mov	-8(up,n,8), v0
+	mov	(up,n,8), %rax
+	mov	%rax, v1
+	lea	-2(n), i
+	mul	v0
+	mov	%rax, X0
+	MOV(	%rdx, X1, 32)
+	mov	(rp,n,8), w0
+	xor	R32(w1), R32(w1)
+	xor	R32(w2), R32(w2)
+	mov	8(up,n,8), %rax
+	jmp	L(lo2)
+
+	ALIGNx
+L(am2top2):
+	mul	v1
+	add	w0, w1
+	adc	%rax, w2
+	mov	(up,i,8), %rax
+	MOV(	%rdx, w3, 1)
+	adc	$0, w3
+	mul	v0
+	add	w1, X1
+	mov	X1, -8(rp,i,8)
+	adc	%rax, X0
+	MOV(	%rdx, X1, 2)
+	adc	$0, X1
+	mov	(up,i,8), %rax
+	mul	v1
+	MOV(	%rdx, w0, 4)
+	mov	(rp,i,8), w1
+	add	w1, w2
+	adc	%rax, w3
+	adc	$0, w0
+	mov	8(up,i,8), %rax
+	mul	v0
+	add	w2, X0
+	adc	%rax, X1
+	mov	X0, (rp,i,8)
+	MOV(	%rdx, X0, 8)
+	adc	$0, X0
+	mov	8(up,i,8), %rax
+	mov	8(rp,i,8), w2
+	mul	v1
+	add	w2, w3
+	adc	%rax, w0
+	MOV(	%rdx, w1, 16)
+	adc	$0, w1
+	mov	16(up,i,8), %rax
+	mul	v0
+	add	w3, X1
+	mov	X1, 8(rp,i,8)
+	adc	%rax, X0
+	MOV(	%rdx, X1, 32)
+	mov	16(rp,i,8), w3
+	adc	$0, X1
+	mov	16(up,i,8), %rax
+	mul	v1
+	add	w3, w0
+	MOV(	%rdx, w2, 64)
+	adc	%rax, w1
+	mov	24(up,i,8), %rax
+	adc	$0, w2
+L(lo2):	mul	v0
+	add	w0, X0
+	mov	X0, 16(rp,i,8)
+	MOV(	%rdx, X0, 128)
+	adc	%rax, X1
+	mov	24(up,i,8), %rax
+	mov	24(rp,i,8), w0
+	adc	$0, X0
+	add	$4, i
+	jnc	L(am2top2)
+
+	mul	v1
+	add	w0, w1
+	adc	w2, %rax
+	adc	Z(i,$0), %rdx
+	add	w1, X1
+	adc	Z(i,$0), X0
+	mov	X1, I(-8(rp),-8(rp,i,8))
+	add	X0, %rax
+	mov	%rax, I((rp),(rp,i,8))
+	adc	Z(i,$0), %rdx
+	mov	%rdx, I(8(rp),8(rp,i,8))
+
+	lea	16(rp), rp
+	add	$2, n
+
+L(am2o0):
+	mov	-8(up,n,8), v0
+	mov	(up,n,8), %rax
+	mov	%rax, v1
+	lea	0(n), i
+	mul	v0
+	mov	%rax, X0
+	MOV(	%rdx, X1, 2)
+	xor	R32(w0), R32(w0)
+	mov	(rp,n,8), w2
+	xor	R32(w3), R32(w3)
+	jmp	L(lo0)
+
+	ALIGNx
+L(am2top0):
+	mul	v1
+	add	w0, w1
+	adc	%rax, w2
+	mov	(up,i,8), %rax
+	MOV(	%rdx, w3, 1)
+	adc	$0, w3
+	mul	v0
+	add	w1, X1
+	mov	X1, -8(rp,i,8)
+	adc	%rax, X0
+	MOV(	%rdx, X1, 2)
+	adc	$0, X1
+	mov	(up,i,8), %rax
+	mul	v1
+	MOV(	%rdx, w0, 4)
+	mov	(rp,i,8), w1
+	add	w1, w2
+	adc	%rax, w3
+	adc	$0, w0
+L(lo0):	mov	8(up,i,8), %rax
+	mul	v0
+	add	w2, X0
+	adc	%rax, X1
+	mov	X0, (rp,i,8)
+	MOV(	%rdx, X0, 8)
+	adc	$0, X0
+	mov	8(up,i,8), %rax
+	mov	8(rp,i,8), w2
+	mul	v1
+	add	w2, w3
+	adc	%rax, w0
+	MOV(	%rdx, w1, 16)
+	adc	$0, w1
+	mov	16(up,i,8), %rax
+	mul	v0
+	add	w3, X1
+	mov	X1, 8(rp,i,8)
+	adc	%rax, X0
+	MOV(	%rdx, X1, 32)
+	mov	16(rp,i,8), w3
+	adc	$0, X1
+	mov	16(up,i,8), %rax
+	mul	v1
+	add	w3, w0
+	MOV(	%rdx, w2, 64)
+	adc	%rax, w1
+	mov	24(up,i,8), %rax
+	adc	$0, w2
+	mul	v0
+	add	w0, X0
+	mov	X0, 16(rp,i,8)
+	MOV(	%rdx, X0, 128)
+	adc	%rax, X1
+	mov	24(up,i,8), %rax
+	mov	24(rp,i,8), w0
+	adc	$0, X0
+	add	$4, i
+	jnc	L(am2top0)
+
+	mul	v1
+	add	w0, w1
+	adc	w2, %rax
+	adc	Z(i,$0), %rdx
+	add	w1, X1
+	adc	Z(i,$0), X0
+	mov	X1, I(-8(rp),-8(rp,i,8))
+	add	X0, %rax
+	mov	%rax, I((rp),(rp,i,8))
+	adc	Z(i,$0), %rdx
+	mov	%rdx, I(8(rp),8(rp,i,8))
+
+	lea	16(rp), rp
+	add	$2, n
+	cmp	$-2, n
+	jnz	L(am2o2)
+
+L(cor2):pop	n
+	mov	-24(up), v0
+	mov	%rax, w2
+	mov	%rdx, w0
+	mov	-16(up), %rax
+	mov	%rax, v1
+	mul	v0
+	mov	%rax, X0
+	MOV(	%rdx, X1, 32)
+	mov	-8(up), %rax
+	mul	v0
+	add	w2, X0
+	mov	X0, -16(rp)
+	MOV(	%rdx, X0, 128)
+	adc	%rax, X1
+	mov	-8(up), %rax
+	adc	$0, X0
+	mul	v1
+	add	w0, X1
+	adc	$0, X0
+	mov	X1, -8(rp)
+	add	X0, %rax
+	mov	%rax, (rp)
+	adc	$0, %rdx
+	mov	%rdx, 8(rp)
+	lea	8(rp), rp
+
+L(sqr_diag_addlsh1):
+	mov	-8(up,n,8), %rax
+	shl	n
+	xor	R32(%rbx), R32(%rbx)
+	mul	%rax
+	mov	8(rp,n,8), %r11
+	lea	(%rdx), %r10
+	mov	16(rp,n,8), %r9
+	add	%r11, %r11
+	jmp	L(dm)
+
+	ALIGNx
+L(dtop):mul	%rax
+	add	%r11, %r10
+	mov	8(rp,n,8), %r11
+	mov	%r10, -8(rp,n,8)
+	adc	%r9, %rax
+	lea	(%rdx,%rbx), %r10
+	mov	16(rp,n,8), %r9
+	adc	%r11, %r11
+L(dm):	mov	%rax, (rp,n,8)
+	mov	(up,n,4), %rax
+	adc	%r9, %r9
+	setc	R8(%rbx)
+	add	$2, n
+	js	L(dtop)
+
+	mul	%rax
+	add	%r11, %r10
+	mov	%r10, -8(rp)
+	adc	%r9, %rax
+	lea	(%rdx,%rbx), %r10
+	mov	%rax, (rp)
+	adc	$0, %r10
+	mov	%r10, 8(rp)
+
+	pop	%r14
+	pop	%r13
+	pop	%r12
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+
+	ALIGN(16)
+L(small):
+	mov	(up), %rax
+	cmp	$2, n_param
+	jae	L(gt1)
+L(n1):
+	mul	%rax
+	mov	%rax, (rp)
+	mov	%rdx, 8(rp)
+	FUNC_EXIT()
+	ret
+
+L(gt1):	jne	L(gt2)
+L(n2):	mov	%rax, %r8
+	mul	%rax
+	mov	8(up), %r11
+	mov	%rax, (rp)
+	mov	%r11, %rax
+	mov	%rdx, %r9
+	mul	%rax
+	mov	%rax, %r10
+	mov	%r11, %rax
+	mov	%rdx, %r11
+	mul	%r8
+	xor	%r8, %r8
+	add	%rax, %r9
+	adc	%rdx, %r10
+	adc	%r8, %r11
+	add	%rax, %r9
+	mov	%r9, 8(rp)
+	adc	%rdx, %r10
+	mov	%r10, 16(rp)
+	adc	%r8, %r11
+	mov	%r11, 24(rp)
+	FUNC_EXIT()
+	ret
+
+L(gt2):
+L(n3):	mov	%rax, %r10
+	mul	%rax
+	mov	8(up), %r11
+	mov	%rax, (rp)
+	mov	%r11, %rax
+	mov	%rdx, 8(rp)
+	mul	%rax
+	mov	16(up), %rcx
+	mov	%rax, 16(rp)
+	mov	%rcx, %rax
+	mov	%rdx, 24(rp)
+	mul	%rax
+	mov	%rax, 32(rp)
+	mov	%rdx, 40(rp)
+
+	mov	%r11, %rax
+	mul	%r10
+	mov	%rax, %r8
+	mov	%rcx, %rax
+	mov	%rdx, %r9
+	mul	%r10
+	xor	%r10, %r10
+	add	%rax, %r9
+	mov	%r11, %rax
+	mov	%r10, %r11
+	adc	%rdx, %r10
+
+	mul	%rcx
+	add	%rax, %r10
+	adc	%r11, %rdx
+	add	%r8, %r8
+	adc	%r9, %r9
+	adc	%r10, %r10
+	adc	%rdx, %rdx
+	adc	%r11, %r11
+	add	%r8, 8(rp)
+	adc	%r9, 16(rp)
+	adc	%r10, 24(rp)
+	adc	%rdx, 32(rp)
+	adc	%r11, 40(rp)
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/core2/sublsh1_n.asm b/third_party/gmp/mpn/x86_64/core2/sublsh1_n.asm
new file mode 100644
index 0000000..46488fc
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/core2/sublsh1_n.asm
@@ -0,0 +1,47 @@
+dnl  AMD64 mpn_sublsh1_n optimised for Core 2 and Core iN.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2008, 2010-2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+define(LSH, 1)
+define(RSH, 63)
+
+define(ADDSUB,	sub)
+define(ADCSBB,	sbb)
+define(func,	mpn_sublsh1_n)
+
+MULFUNC_PROLOGUE(mpn_sublsh1_n)
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+include_mpn(`x86_64/core2/sublshC_n.asm')
diff --git a/third_party/gmp/mpn/x86_64/core2/sublsh2_n.asm b/third_party/gmp/mpn/x86_64/core2/sublsh2_n.asm
new file mode 100644
index 0000000..f3b1e28
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/core2/sublsh2_n.asm
@@ -0,0 +1,47 @@
+dnl  AMD64 mpn_sublsh2_n optimised for Core 2 and Core iN.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2008, 2010-2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+define(LSH, 2)
+define(RSH, 62)
+
+define(ADDSUB,	sub)
+define(ADCSBB,	sbb)
+define(func,	mpn_sublsh2_n)
+
+MULFUNC_PROLOGUE(mpn_sublsh2_n)
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+include_mpn(`x86_64/core2/sublshC_n.asm')
diff --git a/third_party/gmp/mpn/x86_64/core2/sublshC_n.asm b/third_party/gmp/mpn/x86_64/core2/sublshC_n.asm
new file mode 100644
index 0000000..272700d
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/core2/sublshC_n.asm
@@ -0,0 +1,158 @@
+dnl  AMD64 mpn_sublshC_n -- rp[] = up[] - (vp[] << C), optimised for Core 2 and
+dnl  Core iN.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2008, 2010-2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+C	     cycles/limb
+C AMD K8,K9	 4.25
+C AMD K10	 ?
+C Intel P4	 ?
+C Intel core2	 3
+C Intel NHM	 3.1
+C Intel SBR	 2.47
+C Intel atom	 ?
+C VIA nano	 ?
+
+C INPUT PARAMETERS
+define(`rp',`%rdi')
+define(`up',`%rsi')
+define(`vp',`%rdx')
+define(`n', `%rcx')
+
+ASM_START()
+	TEXT
+	ALIGN(8)
+PROLOGUE(func)
+	FUNC_ENTRY(4)
+	push	%rbx
+	push	%r12
+
+	mov	R32(%rcx), R32(%rax)
+	lea	24(up,n,8), up
+	lea	24(vp,n,8), vp
+	lea	24(rp,n,8), rp
+	neg	n
+
+	xor	R32(%r11), R32(%r11)
+
+	mov	-24(vp,n,8), %r8	C do first limb early
+	shrd	$RSH, %r8, %r11
+
+	and	$3, R32(%rax)
+	je	L(b0)
+	cmp	$2, R32(%rax)
+	jc	L(b1)
+	je	L(b2)
+
+L(b3):	mov	-16(vp,n,8), %r9
+	shrd	$RSH, %r9, %r8
+	mov	-8(vp,n,8), %r10
+	shrd	$RSH, %r10, %r9
+	mov	-24(up,n,8), %r12
+	ADDSUB	%r11, %r12
+	mov	%r12, -24(rp,n,8)
+	mov	-16(up,n,8), %r12
+	ADCSBB	%r8, %r12
+	mov	%r12, -16(rp,n,8)
+	mov	-8(up,n,8), %r12
+	ADCSBB	%r9, %r12
+	mov	%r12, -8(rp,n,8)
+	mov	%r10, %r11
+	sbb	R32(%rax), R32(%rax)	C save cy
+	add	$3, n
+	js	L(top)
+	jmp	L(end)
+
+L(b1):	mov	-24(up,n,8), %r12
+	ADDSUB	%r11, %r12
+	mov	%r12, -24(rp,n,8)
+	mov	%r8, %r11
+	sbb	R32(%rax), R32(%rax)	C save cy
+	inc	n
+	js	L(top)
+	jmp	L(end)
+
+L(b2):	mov	-16(vp,n,8), %r9
+	shrd	$RSH, %r9, %r8
+	mov	-24(up,n,8), %r12
+	ADDSUB	%r11, %r12
+	mov	%r12, -24(rp,n,8)
+	mov	-16(up,n,8), %r12
+	ADCSBB	%r8, %r12
+	mov	%r12, -16(rp,n,8)
+	mov	%r9, %r11
+	sbb	R32(%rax), R32(%rax)	C save cy
+	add	$2, n
+	js	L(top)
+	jmp	L(end)
+
+	ALIGN(16)
+L(top):	mov	-24(vp,n,8), %r8
+	shrd	$RSH, %r8, %r11
+L(b0):	mov	-16(vp,n,8), %r9
+	shrd	$RSH, %r9, %r8
+	mov	-8(vp,n,8), %r10
+	shrd	$RSH, %r10, %r9
+	mov	(vp,n,8), %rbx
+	shrd	$RSH, %rbx, %r10
+
+	add	R32(%rax), R32(%rax)	C restore cy
+
+	mov	-24(up,n,8), %r12
+	ADCSBB	%r11, %r12
+	mov	%r12, -24(rp,n,8)
+
+	mov	-16(up,n,8), %r12
+	ADCSBB	%r8, %r12
+	mov	%r12, -16(rp,n,8)
+
+	mov	-8(up,n,8), %r12
+	ADCSBB	%r9, %r12
+	mov	%r12, -8(rp,n,8)
+
+	mov	(up,n,8), %r12
+	ADCSBB	%r10, %r12
+	mov	%r12, (rp,n,8)
+
+	mov	%rbx, %r11
+	sbb	R32(%rax), R32(%rax)	C save cy
+
+	add	$4, n
+	js	L(top)
+
+L(end):	shr	$RSH, %r11
+	pop	%r12
+	pop	%rbx
+	sub	R32(%r11), R32(%rax)
+	neg	R32(%rax)
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/coreibwl/addmul_1.asm b/third_party/gmp/mpn/x86_64/coreibwl/addmul_1.asm
new file mode 100644
index 0000000..ee7e4ee
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreibwl/addmul_1.asm
@@ -0,0 +1,208 @@
+dnl  AMD64 mpn_addmul_1 optimised for Intel Broadwell.
+
+dnl  Copyright 2015, 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	n/a
+C AMD K10	n/a
+C AMD bd1	n/a
+C AMD bd2	n/a
+C AMD bd3	n/a
+C AMD bd4	 ?
+C AMD zen	 ?
+C AMD bt1	n/a
+C AMD bt2	n/a
+C Intel P4	n/a
+C Intel PNR	n/a
+C Intel NHM	n/a
+C Intel SBR	n/a
+C Intel IBR	n/a
+C Intel HWL	n/a
+C Intel BWL	 1.67	 1.74
+C Intel SKL	 1.63	 1.71
+C Intel atom	n/a
+C Intel SLM	n/a
+C VIA nano	n/a
+
+C The loop of this code is the result of running a code generation and
+C optimisation tool suite written by David Harvey and Torbjorn Granlund.
+
+C TODO
+C  * Put an initial mulx before switching, targeting some free registers.
+C  * Tune feed-in code.
+C  * Trim nop execution after L(f2).
+C  * For DOS64, fix nop execution.
+
+define(`rp',      `%rdi')   C rcx
+define(`up',      `%rsi')   C rdx
+define(`n_param', `%rdx')   C r8
+define(`v0_param',`%rcx')   C r9
+
+define(`n',       `%rcx')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+dnl IFDOS(`	define(`up', ``%rsi'')	') dnl
+dnl IFDOS(`	define(`rp', ``%rcx'')	') dnl
+dnl IFDOS(`	define(`vl', ``%r9'')	') dnl
+dnl IFDOS(`	define(`r9', ``rdi'')	') dnl
+dnl IFDOS(`	define(`n',  ``%r8'')	') dnl
+dnl IFDOS(`	define(`r8', ``r11'')	') dnl
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_addmul_1)
+	FUNC_ENTRY(4)
+
+	mov	v0_param, %r10
+	mov	n_param, n
+	mov	R32(n_param), R32(%r8)
+	shr	$3, n
+	and	$7, R32(%r8)		C clear OF, CF as side-effect
+	mov	%r10, %rdx
+	lea	L(tab)(%rip), %r10
+ifdef(`PIC',
+`	movslq	(%r10,%r8,4), %r8
+	lea	(%r8, %r10), %r10
+	jmp	*%r10
+',`
+	jmp	*(%r10,%r8,8)
+')
+	JUMPTABSECT
+	ALIGN(8)
+L(tab):	JMPENT(	L(f0), L(tab))
+	JMPENT(	L(f1), L(tab))
+	JMPENT(	L(f2), L(tab))
+	JMPENT(	L(f3), L(tab))
+	JMPENT(	L(f4), L(tab))
+	JMPENT(	L(f5), L(tab))
+	JMPENT(	L(f6), L(tab))
+	JMPENT(	L(f7), L(tab))
+	TEXT
+
+L(f0):	mulx(	(up), %r10, %r8)
+	lea	-8(up), up
+	lea	-8(rp), rp
+	lea	-1(n), n
+	jmp	L(b0)
+
+L(f3):	mulx(	(up), %r9, %rax)
+	lea	16(up), up
+	lea	-48(rp), rp
+	jmp	L(b3)
+
+L(f4):	mulx(	(up), %r10, %r8)
+	lea	24(up), up
+	lea	-40(rp), rp
+	jmp	L(b4)
+
+L(f5):	mulx(	(up), %r9, %rax)
+	lea	32(up), up
+	lea	-32(rp), rp
+	jmp	L(b5)
+
+L(f6):	mulx(	(up), %r10, %r8)
+	lea	40(up), up
+	lea	-24(rp), rp
+	jmp	L(b6)
+
+L(f1):	mulx(	(up), %r9, %rax)
+	jrcxz	L(1)
+	jmp	L(b1)
+L(1):	add	(rp), %r9
+	mov	%r9, (rp)
+	adc	%rcx, %rax		C relies on rcx = 0
+	FUNC_EXIT()
+	ret
+
+L(end):	adox(	(rp), %r9)
+	mov	%r9, (rp)
+	adox(	%rcx, %rax)		C relies on rcx = 0
+	adc	%rcx, %rax		C relies on rcx = 0
+	FUNC_EXIT()
+	ret
+
+ifdef(`PIC',
+`	nop;nop;nop;nop',
+`	nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop')
+
+L(f2):	mulx(	(up), %r10, %r8)
+	lea	8(up), up
+	lea	8(rp), rp
+	mulx(	(up), %r9, %rax)
+
+	ALIGN(32)
+L(top):	adox(	-8,(rp), %r10)
+	adcx(	%r8, %r9)
+	mov	%r10, -8(rp)
+	jrcxz	L(end)
+L(b1):	mulx(	8,(up), %r10, %r8)
+	adox(	(rp), %r9)
+	lea	-1(n), n
+	mov	%r9, (rp)
+	adcx(	%rax, %r10)
+L(b0):	mulx(	16,(up), %r9, %rax)
+	adcx(	%r8, %r9)
+	adox(	8,(rp), %r10)
+	mov	%r10, 8(rp)
+L(b7):	mulx(	24,(up), %r10, %r8)
+	lea	64(up), up
+	adcx(	%rax, %r10)
+	adox(	16,(rp), %r9)
+	mov	%r9, 16(rp)
+L(b6):	mulx(	-32,(up), %r9, %rax)
+	adox(	24,(rp), %r10)
+	adcx(	%r8, %r9)
+	mov	%r10, 24(rp)
+L(b5):	mulx(	-24,(up), %r10, %r8)
+	adcx(	%rax, %r10)
+	adox(	32,(rp), %r9)
+	mov	%r9, 32(rp)
+L(b4):	mulx(	-16,(up), %r9, %rax)
+	adox(	40,(rp), %r10)
+	adcx(	%r8, %r9)
+	mov	%r10, 40(rp)
+L(b3):	adox(	48,(rp), %r9)
+	mulx(	-8,(up), %r10, %r8)
+	mov	%r9, 48(rp)
+	lea	64(rp), rp
+	adcx(	%rax, %r10)
+	mulx(	(up), %r9, %rax)
+	jmp	L(top)
+
+L(f7):	mulx(	(up), %r9, %rax)
+	lea	-16(up), up
+	lea	-16(rp), rp
+	jmp	L(b7)
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86_64/coreibwl/gmp-mparam.h b/third_party/gmp/mpn/x86_64/coreibwl/gmp-mparam.h
new file mode 100644
index 0000000..91c91b5
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreibwl/gmp-mparam.h
@@ -0,0 +1,246 @@
+/* Broadwell gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+/* Disable use of slow functions.  FIXME: We should disable lib inclusion.  */
+#undef HAVE_NATIVE_mpn_mul_2
+#undef HAVE_NATIVE_mpn_addmul_2
+
+/* 3400-3800 MHz Intel Xeon E3-1285Lv4 Broadwell */
+/* FFT tuning limit = 467,964,472 */
+/* Generated by tuneup.c, 2019-10-17, gcc 8.3 */
+
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          4
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          3
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        14
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        24
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD      9
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1_NORM_THRESHOLD              1
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD              24
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           22
+
+#define DIV_1_VS_MUL_1_PERCENT             455
+
+#define MUL_TOOM22_THRESHOLD                26
+#define MUL_TOOM33_THRESHOLD                73
+#define MUL_TOOM44_THRESHOLD               202
+#define MUL_TOOM6H_THRESHOLD               303
+#define MUL_TOOM8H_THRESHOLD               406
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD     141
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     152
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     137
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     151
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     198
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 34
+#define SQR_TOOM3_THRESHOLD                117
+#define SQR_TOOM4_THRESHOLD                336
+#define SQR_TOOM6_THRESHOLD                426
+#define SQR_TOOM8_THRESHOLD                547
+
+#define MULMID_TOOM42_THRESHOLD             46
+
+#define MULMOD_BNM1_THRESHOLD               16
+#define SQRMOD_BNM1_THRESHOLD               18
+
+#define MUL_FFT_MODF_THRESHOLD             460  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    460, 5}, {     21, 6}, {     11, 5}, {     23, 6}, \
+    {     12, 5}, {     25, 6}, {     25, 7}, {     13, 6}, \
+    {     28, 7}, {     15, 6}, {     31, 7}, {     25, 8}, \
+    {     13, 7}, {     28, 8}, {     15, 7}, {     31, 8}, \
+    {     17, 7}, {     35, 8}, {     19, 7}, {     39, 8}, \
+    {     21, 9}, {     11, 8}, {     27, 9}, {     15, 8}, \
+    {     35, 9}, {     19, 8}, {     41, 9}, {     23, 8}, \
+    {     49, 9}, {     27,10}, {     15, 9}, {     39, 8}, \
+    {     79,10}, {     23, 9}, {     55,11}, {     15,10}, \
+    {     31, 9}, {     71,10}, {     39, 9}, {     83,10}, \
+    {     47, 9}, {     99,10}, {     55,11}, {     31,10}, \
+    {     87,11}, {     47,10}, {    103,12}, {     31,11}, \
+    {     63,10}, {    135,11}, {     79,10}, {    167,11}, \
+    {     95,10}, {    199,11}, {    111,12}, {     63, 8}, \
+    {   1087,10}, {    287, 9}, {    575,10}, {    303,11}, \
+    {    159,12}, {     95,11}, {    191,10}, {    383,13}, \
+    {     63,12}, {    127,11}, {    255,10}, {    511,11}, \
+    {    271,10}, {    543,11}, {    287,10}, {    575,11}, \
+    {    303,10}, {    607,12}, {    159,11}, {    319,10}, \
+    {    639,11}, {    335,10}, {    671,11}, {    351,10}, \
+    {    703,11}, {    367,12}, {    191,11}, {    383,10}, \
+    {    767,11}, {    415,10}, {    831,11}, {    447,13}, \
+    {    127,12}, {    255,11}, {    543,12}, {    287,11}, \
+    {    607,12}, {    319,11}, {    671,12}, {    351,11}, \
+    {    703,13}, {    191,12}, {    383,11}, {    767,12}, \
+    {    415,11}, {    831,12}, {    447,14}, {    127,13}, \
+    {    255,12}, {    607,13}, {    319,12}, {    735,13}, \
+    {    383,12}, {    831,13}, {    447,12}, {    959,14}, \
+    {    255,13}, {    511,12}, {   1023,13}, {    575,12}, \
+    {   1151,13}, {    639,12}, {   1279,13}, {    703,14}, \
+    {    383,13}, {    831,12}, {   1663,13}, {    959,14}, \
+    {    511,13}, {   1087,12}, {   2175,13}, {   1151,14}, \
+    {    639,13}, {   1279,12}, {   2559,13}, {   1343,12}, \
+    {   2687,13}, {   1407,14}, {    767,13}, {   1535,12}, \
+    {   3071,13}, {   1599,12}, {   3199,13}, {   1663,14}, \
+    {    895,15}, {    511,14}, {   1023,13}, {   2175,14}, \
+    {   1151,13}, {   2431,12}, {   4863,14}, {   1279,13}, \
+    {   2687,14}, {   1407,15}, {    767,14}, {   1535,13}, \
+    {   3199,14}, {   1663,13}, {   3455,12}, {   6911,16}, \
+    {    511,15}, {   1023,14}, {   2175,13}, {   4479,14}, \
+    {   2303,13}, {   4607,14}, {   2431,13}, {   4863,15}, \
+    {   1279,14}, {   2815,13}, {   5631,14}, {   2943,13}, \
+    {   5887,15}, {   1535,14}, {   3455,13}, {   6911,15}, \
+    {   1791,14}, {   3839,13}, {   7679,16}, {   1023,15}, \
+    {   2047,14}, {   4479,15}, {   2303,14}, {   4863,15}, \
+    {   2559,14}, {   5247,15}, {   2815,14}, {   5887,16}, \
+    {   1535,15}, {   3327,14}, {   6911,15}, {   3839,14}, \
+    {   7679,17}, {   1023,16}, {   2047,15}, {   4351,14}, \
+    {   8703,15}, {   4863,16}, {   2559,15}, {   5887,14}, \
+    {  11775,16}, {   3071,15}, {   6911,16}, {   3583,15}, \
+    {   7679,14}, {  15359,17}, {   2047,16}, {   4095,15}, \
+    {   8703,16}, {   4607,15}, {   9983,14}, {  19967,16}, \
+    {   5631,15}, {  11775,17}, {   3071,16}, {  65536,17}, \
+    { 131072,18}, { 262144,19}, { 524288,20}, {1048576,21}, \
+    {2097152,22}, {4194304,23}, {8388608,24} }
+#define MUL_FFT_TABLE3_SIZE 219
+#define MUL_FFT_THRESHOLD                 5760
+
+#define SQR_FFT_MODF_THRESHOLD             400  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    400, 5}, {     23, 6}, {     12, 5}, {     25, 6}, \
+    {     28, 7}, {     15, 6}, {     31, 7}, {     25, 8}, \
+    {     13, 7}, {     27, 8}, {     15, 7}, {     31, 8}, \
+    {     17, 7}, {     35, 8}, {     19, 7}, {     39, 8}, \
+    {     27, 9}, {     15, 8}, {     35, 9}, {     19, 8}, \
+    {     41, 9}, {     23, 8}, {     47, 9}, {     27,10}, \
+    {     15, 9}, {     39,10}, {     23, 9}, {     51,11}, \
+    {     15,10}, {     31, 9}, {     67,10}, {     39, 9}, \
+    {     79,10}, {     47, 9}, {     95,10}, {     55,11}, \
+    {     31,10}, {     79,11}, {     47,10}, {     95,12}, \
+    {     31,11}, {     63,10}, {    127,11}, {     79,10}, \
+    {    159,11}, {     95,12}, {     63,11}, {    127,10}, \
+    {    255, 9}, {    511,11}, {    143,10}, {    287, 9}, \
+    {    575,10}, {    303,11}, {    159,10}, {    319,12}, \
+    {     95, 8}, {   1599, 9}, {    831,11}, {    223,10}, \
+    {    447,12}, {    127,11}, {    255,10}, {    511,11}, \
+    {    271,10}, {    543,11}, {    287,10}, {    575,11}, \
+    {    303,10}, {    607,12}, {    159,11}, {    319,10}, \
+    {    639,11}, {    335,10}, {    671,11}, {    351,10}, \
+    {    703,11}, {    367,10}, {    735,11}, {    415,10}, \
+    {    831,12}, {    223,11}, {    447,13}, {    127,12}, \
+    {    255,11}, {    543,12}, {    287,11}, {    607,12}, \
+    {    319,11}, {    671,12}, {    351,11}, {    735,12}, \
+    {    383,11}, {    767,12}, {    415,11}, {    831,12}, \
+    {    447,14}, {    127,13}, {    255,12}, {    607,13}, \
+    {    319,12}, {    735,13}, {    383,12}, {    799,13}, \
+    {    447,12}, {    959,13}, {    511,12}, {   1023,13}, \
+    {    575,12}, {   1151,13}, {    639,12}, {   1279,13}, \
+    {    703,14}, {    383,13}, {    767,12}, {   1535,13}, \
+    {    831,12}, {   1663,13}, {    959,14}, {    511,13}, \
+    {   1087,12}, {   2175,13}, {   1151,14}, {    639,13}, \
+    {   1343,12}, {   2687,13}, {   1407,12}, {   2815,13}, \
+    {   1471,14}, {    767,13}, {   1599,12}, {   3199,13}, \
+    {   1663,14}, {    895,15}, {    511,14}, {   1023,13}, \
+    {   2175,14}, {   1151,13}, {   2431,12}, {   4863,14}, \
+    {   1279,13}, {   2687,14}, {   1407,13}, {   2815,15}, \
+    {    767,14}, {   1535,13}, {   3199,14}, {   1663,13}, \
+    {   3455,12}, {   6911,14}, {   1791,16}, {    511,15}, \
+    {   1023,14}, {   2047,13}, {   4095,14}, {   2175,13}, \
+    {   4351,14}, {   2303,13}, {   4607,14}, {   2431,13}, \
+    {   4863,15}, {   1279,14}, {   2943,13}, {   5887,15}, \
+    {   1535,14}, {   3455,13}, {   6911,15}, {   1791,14}, \
+    {   3839,13}, {   7679,16}, {   1023,15}, {   2047,14}, \
+    {   4351,15}, {   2303,14}, {   4863,15}, {   2559,14}, \
+    {   5247,15}, {   2815,14}, {   5887,16}, {   1535,15}, \
+    {   3327,14}, {   6911,15}, {   3839,14}, {   7679,17}, \
+    {   1023,16}, {   2047,15}, {   4863,16}, {   2559,15}, \
+    {   5887,14}, {  11775,16}, {   3071,15}, {   6911,16}, \
+    {   3583,15}, {   7679,14}, {  15359,15}, {   7935,17}, \
+    {   2047,16}, {   4095,15}, {   8447,16}, {   4607,15}, \
+    {   9471,14}, {  18943,15}, {   9983,14}, {  19967,16}, \
+    {   5631,15}, {  11775,17}, {   3071,16}, {  65536,17}, \
+    { 131072,18}, { 262144,19}, { 524288,20}, {1048576,21}, \
+    {2097152,22}, {4194304,23}, {8388608,24} }
+#define SQR_FFT_TABLE3_SIZE 215
+#define SQR_FFT_THRESHOLD                 3712
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  80
+#define MULLO_MUL_N_THRESHOLD            11025
+#define SQRLO_BASECASE_THRESHOLD             9
+#define SQRLO_DC_THRESHOLD                 109
+#define SQRLO_SQR_THRESHOLD               7293
+
+#define DC_DIV_QR_THRESHOLD                 54
+#define DC_DIVAPPR_Q_THRESHOLD             183
+#define DC_BDIV_QR_THRESHOLD                86
+#define DC_BDIV_Q_THRESHOLD                160
+
+#define INV_MULMOD_BNM1_THRESHOLD           58
+#define INV_NEWTON_THRESHOLD               171
+#define INV_APPR_THRESHOLD                 171
+
+#define BINV_NEWTON_THRESHOLD              292
+#define REDC_1_TO_REDC_2_THRESHOLD          33
+#define REDC_2_TO_REDC_N_THRESHOLD          63
+
+#define MU_DIV_QR_THRESHOLD               1589
+#define MU_DIVAPPR_Q_THRESHOLD            1589
+#define MUPI_DIV_QR_THRESHOLD               67
+#define MU_BDIV_QR_THRESHOLD              1470
+#define MU_BDIV_Q_THRESHOLD               1866
+
+#define POWM_SEC_TABLE  2,10,191,494,712,1378
+
+#define GET_STR_DC_THRESHOLD                12
+#define GET_STR_PRECOMPUTE_THRESHOLD        20
+#define SET_STR_DC_THRESHOLD               644
+#define SET_STR_PRECOMPUTE_THRESHOLD      1658
+
+#define FAC_DSC_THRESHOLD                  562
+#define FAC_ODD_THRESHOLD                   48
+
+#define MATRIX22_STRASSEN_THRESHOLD         16
+#define HGCD2_DIV1_METHOD                    5  /* 0.38% faster than 3 */
+#define HGCD_THRESHOLD                      73
+#define HGCD_APPR_THRESHOLD                 67
+#define HGCD_REDUCE_THRESHOLD             3014
+#define GCD_DC_THRESHOLD                   630
+#define GCDEXT_DC_THRESHOLD                365
+#define JACOBI_BASE_METHOD                   1  /* 29.65% faster than 4 */
+
+/* Tuneup completed successfully, took 239050 seconds */
diff --git a/third_party/gmp/mpn/x86_64/coreibwl/mul_1.asm b/third_party/gmp/mpn/x86_64/coreibwl/mul_1.asm
new file mode 100644
index 0000000..b7fae2f
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreibwl/mul_1.asm
@@ -0,0 +1,195 @@
+dnl  AMD64 mpn_mul_1 optimised for Intel Broadwell.
+
+dnl  Copyright 2015 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9      -
+C AMD K10        -
+C AMD bull       -
+C AMD pile       -
+C AMD steam      -
+C AMD excavator  -
+C AMD bobcat     -
+C AMD jaguar     -
+C Intel P4       -
+C Intel core2    -
+C Intel NHM      -
+C Intel SBR      -
+C Intel IBR      -
+C Intel HWL      1.70
+C Intel BWL      1.51
+C Intel SKL      1.52
+C Intel atom     -
+C Intel SLM      -
+C VIA nano       -
+
+C The loop of this code is the result of running a code generation and
+C optimisation tool suite written by David Harvey and Torbjorn Granlund.
+
+C TODO
+C  * Put an initial mulx before switching, targeting some free registers.
+C  * Tune feed-in code.
+C  * Trim nop execution after L(f2).
+C  * Port to DOS64, not forgetting nop execution.
+
+define(`rp',      `%rdi')   C rcx
+define(`up',      `%rsi')   C rdx
+define(`n_param', `%rdx')   C r8
+define(`v0_param',`%rcx')   C r9
+
+define(`n',       `%rcx')
+
+dnl ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+dnl IFDOS(`	define(`up', ``%rsi'')	') dnl
+dnl IFDOS(`	define(`rp', ``%rcx'')	') dnl
+dnl IFDOS(`	define(`vl', ``%r9'')	') dnl
+dnl IFDOS(`	define(`r9', ``rdi'')	') dnl
+dnl IFDOS(`	define(`n',  ``%r8'')	') dnl
+dnl IFDOS(`	define(`r8', ``r11'')	') dnl
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_mul_1)
+
+	mov	v0_param, %r10
+	mov	n_param, n
+	mov	R32(n_param), R32(%r8)
+	shr	$3, n
+	and	$7, R32(%r8)		C clear OF, CF as side-effect
+	mov	%r10, %rdx
+	lea	L(tab)(%rip), %r10
+ifdef(`PIC',
+`	movslq	(%r10,%r8,4), %r8
+	lea	(%r8, %r10), %r10
+	jmp	*%r10
+',`
+	jmp	*(%r10,%r8,8)
+')
+	JUMPTABSECT
+	ALIGN(8)
+L(tab):	JMPENT(	L(f0), L(tab))
+	JMPENT(	L(f1), L(tab))
+	JMPENT(	L(f2), L(tab))
+	JMPENT(	L(f3), L(tab))
+	JMPENT(	L(f4), L(tab))
+	JMPENT(	L(f5), L(tab))
+	JMPENT(	L(f6), L(tab))
+	JMPENT(	L(f7), L(tab))
+	TEXT
+
+L(f0):	mulx(	(up), %r10, %r8)
+	lea	56(up), up
+	lea	-8(rp), rp
+	jmp	L(b0)
+
+L(f3):	mulx(	(up), %r9, %rax)
+	lea	16(up), up
+	lea	16(rp), rp
+	inc	n
+	jmp	L(b3)
+
+L(f4):	mulx(	(up), %r10, %r8)
+	lea	24(up), up
+	lea	24(rp), rp
+	inc	n
+	jmp	L(b4)
+
+L(f5):	mulx(	(up), %r9, %rax)
+	lea	32(up), up
+	lea	32(rp), rp
+	inc	n
+	jmp	L(b5)
+
+L(f6):	mulx(	(up), %r10, %r8)
+	lea	40(up), up
+	lea	40(rp), rp
+	inc	n
+	jmp	L(b6)
+
+L(f7):	mulx(	(up), %r9, %rax)
+	lea	48(up), up
+	lea	48(rp), rp
+	inc	n
+	jmp	L(b7)
+
+L(f1):	mulx(	(up), %r9, %rax)
+	test	n, n
+	jnz	L(b1)
+L(1):	mov	%r9, (rp)
+	ret
+
+L(f2):	mulx(	(up), %r10, %r8)
+	lea	8(up), up
+	lea	8(rp), rp
+	mulx(	(up), %r9, %rax)
+	test	n, n
+	jz	L(end)
+
+	ALIGN(32)
+L(top):	mov	%r10, -8(rp)
+	adc	%r8, %r9
+L(b1):	mulx(	8,(up), %r10, %r8)
+	adc	%rax, %r10
+	lea	64(up), up
+	mov	%r9, (rp)
+L(b0):	mov	%r10, 8(rp)
+	mulx(	-48,(up), %r9, %rax)
+	lea	64(rp), rp
+	adc	%r8, %r9
+L(b7):	mulx(	-40,(up), %r10, %r8)
+	mov	%r9, -48(rp)
+	adc	%rax, %r10
+L(b6):	mov	%r10, -40(rp)
+	mulx(	-32,(up), %r9, %rax)
+	adc	%r8, %r9
+L(b5):	mulx(	-24,(up), %r10, %r8)
+	mov	%r9, -32(rp)
+	adc	%rax, %r10
+L(b4):	mulx(	-16,(up), %r9, %rax)
+	mov	%r10, -24(rp)
+	adc	%r8, %r9
+L(b3):	mulx(	-8,(up), %r10, %r8)
+	adc	%rax, %r10
+	mov	%r9, -16(rp)
+	dec	n
+	mulx(	(up), %r9, %rax)
+	jnz	L(top)
+
+L(end):	mov	%r10, -8(rp)
+	adc	%r8, %r9
+	mov	%r9, (rp)
+	adc	%rcx, %rax
+	ret
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86_64/coreibwl/mul_basecase.asm b/third_party/gmp/mpn/x86_64/coreibwl/mul_basecase.asm
new file mode 100644
index 0000000..42ca976
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreibwl/mul_basecase.asm
@@ -0,0 +1,369 @@
+dnl  AMD64 mpn_mul_basecase optimised for Intel Broadwell.
+
+dnl  Copyright 2015 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C cycles/limb	mul_1		addmul_1
+C AMD K8,K9	n/a		n/a
+C AMD K10	n/a		n/a
+C AMD bd1	n/a		n/a
+C AMD bd2	n/a		n/a
+C AMD bd3	n/a		n/a
+C AMD bd4	 ?		 ?
+C AMD zen	 ?		 ?
+C AMD bt1	n/a		n/a
+C AMD bt2	n/a		n/a
+C Intel P4	n/a		n/a
+C Intel PNR	n/a		n/a
+C Intel NHM	n/a		n/a
+C Intel SBR	n/a		n/a
+C Intel IBR	n/a		n/a
+C Intel HWL	 1.68		n/a
+C Intel BWL	 1.51	      1.67-1.74
+C Intel SKL	 1.52	      1.63-1.71
+C Intel atom	n/a		n/a
+C Intel SLM	n/a		n/a
+C VIA nano	n/a		n/a
+
+C The inner loops of this code are the result of running a code generation and
+C optimisation tool suite written by David Harvey and Torbjorn Granlund.
+
+C TODO
+C  * Do overlapped software pipelining.
+C  * When changing this, make sure the code which falls into the inner loops
+C    does not execute too many no-ops (for both PIC and non-PIC).
+
+define(`rp',      `%rdi')
+define(`up',      `%rsi')
+define(`un_param',`%rdx')
+define(`vp_param',`%rcx')
+define(`vn',      `%r8')
+
+define(`n',       `%rcx')
+define(`n_save',  `%rbp')
+define(`vp',      `%r14')
+define(`unneg',   `%rbx')
+define(`v0',      `%rdx')
+define(`jaddr',   `%rax')
+
+define(`w0',	`%r12')
+define(`w1',	`%r9')
+define(`w2',	`%r10')
+define(`w3',	`%r11')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_mul_basecase)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8d	')
+
+	cmp	$2, un_param
+	ja	L(gen)
+	mov	(vp_param), %rdx
+	mulx(	(up), %rax, %r9)	C 0 1
+	je	L(s2x)
+
+L(s11):	mov	%rax, (rp)
+	mov	%r9, 8(rp)
+	FUNC_EXIT()
+	ret
+
+L(s2x):	cmp	$2, vn
+	mulx(	8,(up), %r8, %r10)	C 1 2
+	je	L(s22)
+
+L(s21):	add	%r8, %r9
+	adc	$0, %r10
+	mov	%rax, (rp)
+	mov	%r9, 8(rp)
+	mov	%r10, 16(rp)
+	FUNC_EXIT()
+	ret
+
+L(s22):	add	%r8, %r9		C 1
+	adc	$0, %r10		C 2
+	mov	8(vp_param), %rdx
+	mov	%rax, (rp)
+	mulx(	(up), %r8, %r11)	C 1 2
+	mulx(	8,(up), %rax, %rdx)	C 2 3
+	add	%r11, %rax		C 2
+	adc	$0, %rdx		C 3
+	add	%r8, %r9		C 1
+	adc	%rax, %r10		C 2
+	adc	$0, %rdx		C 3
+	mov	%r9, 8(rp)
+	mov	%r10, 16(rp)
+	mov	%rdx, 24(rp)
+	FUNC_EXIT()
+	ret
+
+	ALIGN(16)
+L(gen):
+	push	%rbx
+	push	%rbp
+	push	%r12
+	push	%r14
+
+	mov	vp_param, vp
+	lea	1(un_param), unneg
+	mov	un_param, n_save
+	mov	R32(un_param), R32(%rax)
+	and	$-8, unneg
+	shr	$3, n_save		C loop count
+	neg	unneg
+	and	$7, R32(%rax)		C clear CF for adc as side-effect
+					C note that rax lives very long
+	mov	n_save, n
+	mov	(vp), v0
+	lea	8(vp), vp
+
+	lea	L(mtab)(%rip), %r10
+ifdef(`PIC',
+`	movslq	(%r10,%rax,4), %r11
+	lea	(%r11, %r10), %r10
+	jmp	*%r10
+',`
+	jmp	*(%r10,%rax,8)
+')
+
+L(mf0):	mulx(	(up), w2, w3)
+	lea	56(up), up
+	lea	-8(rp), rp
+	jmp	L(mb0)
+
+L(mf3):	mulx(	(up), w0, w1)
+	lea	16(up), up
+	lea	16(rp), rp
+	inc	n
+	jmp	L(mb3)
+
+L(mf4):	mulx(	(up), w2, w3)
+	lea	24(up), up
+	lea	24(rp), rp
+	inc	n
+	jmp	L(mb4)
+
+L(mf5):	mulx(	(up), w0, w1)
+	lea	32(up), up
+	lea	32(rp), rp
+	inc	n
+	jmp	L(mb5)
+
+L(mf6):	mulx(	(up), w2, w3)
+	lea	40(up), up
+	lea	40(rp), rp
+	inc	n
+	jmp	L(mb6)
+
+L(mf7):	mulx(	(up), w0, w1)
+	lea	48(up), up
+	lea	48(rp), rp
+	inc	n
+	jmp	L(mb7)
+
+L(mf1):	mulx(	(up), w0, w1)
+	jmp	L(mb1)
+
+L(mf2):	mulx(	(up), w2, w3)
+	lea	8(up), up
+	lea	8(rp), rp
+	mulx(	(up), w0, w1)
+
+	ALIGN(16)
+L(m1top):
+	mov	w2, -8(rp)
+	adc	w3, w0
+L(mb1):	mulx(	8,(up), w2, w3)
+	adc	w1, w2
+	lea	64(up), up
+	mov	w0, (rp)
+L(mb0):	mov	w2, 8(rp)
+	mulx(	-48,(up), w0, w1)
+	lea	64(rp), rp
+	adc	w3, w0
+L(mb7):	mulx(	-40,(up), w2, w3)
+	mov	w0, -48(rp)
+	adc	w1, w2
+L(mb6):	mov	w2, -40(rp)
+	mulx(	-32,(up), w0, w1)
+	adc	w3, w0
+L(mb5):	mulx(	-24,(up), w2, w3)
+	mov	w0, -32(rp)
+	adc	w1, w2
+L(mb4):	mulx(	-16,(up), w0, w1)
+	mov	w2, -24(rp)
+	adc	w3, w0
+L(mb3):	mulx(	-8,(up), w2, w3)
+	adc	w1, w2
+	mov	w0, -16(rp)
+	dec	n
+	mulx(	(up), w0, w1)
+	jnz	L(m1top)
+
+L(m1end):
+	mov	w2, -8(rp)
+	adc	w3, w0
+	mov	w0, (rp)
+	adc	%rcx, w1		C relies on rcx = 0
+	mov	w1, 8(rp)
+
+	dec	vn
+	jz	L(done)
+
+	lea	L(atab)(%rip), %r10
+ifdef(`PIC',
+`	movslq	(%r10,%rax,4), %rax
+	lea	(%rax, %r10), jaddr
+',`
+	mov	(%r10,%rax,8), jaddr
+')
+
+L(outer):
+	lea	(up,unneg,8), up
+	mov	n_save, n
+	mov	(vp), v0
+	lea	8(vp), vp
+	jmp	*jaddr
+
+L(f0):	mulx(	8,(up), w2, w3)
+	lea	8(rp,unneg,8), rp
+	lea	-1(n), n
+	jmp	L(b0)
+
+L(f3):	mulx(	-16,(up), w0, w1)
+	lea	-56(rp,unneg,8), rp
+	jmp	L(b3)
+
+L(f4):	mulx(	-24,(up), w2, w3)
+	lea	-56(rp,unneg,8), rp
+	jmp	L(b4)
+
+L(f5):	mulx(	-32,(up), w0, w1)
+	lea	-56(rp,unneg,8), rp
+	jmp	L(b5)
+
+L(f6):	mulx(	-40,(up), w2, w3)
+	lea	-56(rp,unneg,8), rp
+	jmp	L(b6)
+
+L(f7):	mulx(	16,(up), w0, w1)
+	lea	8(rp,unneg,8), rp
+	jmp	L(b7)
+
+L(f1):	mulx(	(up), w0, w1)
+	lea	8(rp,unneg,8), rp
+	jmp	L(b1)
+
+L(am1end):
+	adox(	(rp), w0)
+	adox(	%rcx, w1)		C relies on rcx = 0
+	mov	w0, (rp)
+	adc	%rcx, w1		C relies on rcx = 0
+	mov	w1, 8(rp)
+
+	dec	vn			C clear CF and OF as side-effect
+	jnz	L(outer)
+L(done):
+	pop	%r14
+	pop	%r12
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+
+L(f2):
+	mulx(	-8,(up), w2, w3)
+	lea	8(rp,unneg,8), rp
+	mulx(	(up), w0, w1)
+
+	ALIGN(16)
+L(am1top):
+	adox(	-8,(rp), w2)
+	adcx(	w3, w0)
+	mov	w2, -8(rp)
+	jrcxz	L(am1end)
+L(b1):	mulx(	8,(up), w2, w3)
+	adox(	(rp), w0)
+	lea	-1(n), n
+	mov	w0, (rp)
+	adcx(	w1, w2)
+L(b0):	mulx(	16,(up), w0, w1)
+	adcx(	w3, w0)
+	adox(	8,(rp), w2)
+	mov	w2, 8(rp)
+L(b7):	mulx(	24,(up), w2, w3)
+	lea	64(up), up
+	adcx(	w1, w2)
+	adox(	16,(rp), w0)
+	mov	w0, 16(rp)
+L(b6):	mulx(	-32,(up), w0, w1)
+	adox(	24,(rp), w2)
+	adcx(	w3, w0)
+	mov	w2, 24(rp)
+L(b5):	mulx(	-24,(up), w2, w3)
+	adcx(	w1, w2)
+	adox(	32,(rp), w0)
+	mov	w0, 32(rp)
+L(b4):	mulx(	-16,(up), w0, w1)
+	adox(	40,(rp), w2)
+	adcx(	w3, w0)
+	mov	w2, 40(rp)
+L(b3):	adox(	48,(rp), w0)
+	mulx(	-8,(up), w2, w3)
+	mov	w0, 48(rp)
+	lea	64(rp), rp
+	adcx(	w1, w2)
+	mulx(	(up), w0, w1)
+	jmp	L(am1top)
+
+	JUMPTABSECT
+	ALIGN(8)
+L(mtab):JMPENT(	L(mf0), L(mtab))
+	JMPENT(	L(mf1), L(mtab))
+	JMPENT(	L(mf2), L(mtab))
+	JMPENT(	L(mf3), L(mtab))
+	JMPENT(	L(mf4), L(mtab))
+	JMPENT(	L(mf5), L(mtab))
+	JMPENT(	L(mf6), L(mtab))
+	JMPENT(	L(mf7), L(mtab))
+L(atab):JMPENT(	L(f0), L(atab))
+	JMPENT(	L(f1), L(atab))
+	JMPENT(	L(f2), L(atab))
+	JMPENT(	L(f3), L(atab))
+	JMPENT(	L(f4), L(atab))
+	JMPENT(	L(f5), L(atab))
+	JMPENT(	L(f6), L(atab))
+	JMPENT(	L(f7), L(atab))
+	TEXT
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/coreibwl/mullo_basecase.asm b/third_party/gmp/mpn/x86_64/coreibwl/mullo_basecase.asm
new file mode 100644
index 0000000..5cdb209
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreibwl/mullo_basecase.asm
@@ -0,0 +1,395 @@
+dnl  X64-64 mpn_mullo_basecase optimised for Intel Broadwell.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C The inner loops of this code are the result of running a code generation and
+C optimisation tool suite written by David Harvey and Torbjorn Granlund.
+
+define(`rp',	   `%rdi')
+define(`up',	   `%rsi')
+define(`vp_param', `%rdx')
+define(`n',	   `%rcx')
+
+define(`vp',	`%r11')
+define(`jmpreg',`%rbx')
+define(`nn',    `%rbp')
+
+C TODO
+C  * Suppress more rp[] rewrites in corner.
+C  * Rearrange feed-in jumps for short branch forms.
+C  * Perhaps roll out the heavy artillery and 8-way unroll outer loop.  Since
+C    feed-in code implodes, the blow-up will not be more than perhaps 4x.
+C  * Micro-optimise critical lead-in code block around L(ent).
+C  * Write n < 4 code specifically for Broadwell (current code is for Haswell).
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_mullo_basecase)
+	FUNC_ENTRY(4)
+	cmp	$4, R32(n)
+	jae	L(big)
+
+	mov	vp_param, vp
+	mov	(up), %rdx
+
+	cmp	$2, R32(n)
+	jae	L(gt1)
+L(n1):	imul	(vp), %rdx
+	mov	%rdx, (rp)
+	FUNC_EXIT()
+	ret
+L(gt1):	ja	L(gt2)
+L(n2):	mov	(vp), %r9
+	mulx(	%r9, %rax, %rdx)
+	mov	%rax, (rp)
+	mov	8(up), %rax
+	imul	%r9, %rax
+	add	%rax, %rdx
+	mov	8(vp), %r9
+	mov	(up), %rcx
+	imul	%r9, %rcx
+	add	%rcx, %rdx
+	mov	%rdx, 8(rp)
+	FUNC_EXIT()
+	ret
+L(gt2):
+L(n3):	mov	(vp), %r9
+	mulx(	%r9, %rax, %r10)	C u0 x v0
+	mov	%rax, (rp)
+	mov	8(up), %rdx
+	mulx(	%r9, %rax, %rdx)	C u1 x v0
+	imul	16(up), %r9		C u2 x v0
+	add	%rax, %r10
+	adc	%rdx, %r9
+	mov	8(vp), %r8
+	mov	(up), %rdx
+	mulx(	%r8, %rax, %rdx)	C u0 x v1
+	add	%rax, %r10
+	adc	%rdx, %r9
+	imul	8(up), %r8		C u1 x v1
+	add	%r8, %r9
+	mov	%r10, 8(rp)
+	mov	16(vp), %r10
+	mov	(up), %rax
+	imul	%rax, %r10		C u0 x v2
+	add	%r10, %r9
+	mov	%r9, 16(rp)
+	FUNC_EXIT()
+	ret
+
+	ALIGN(16)
+L(big):	push	%r14
+	push	%r12
+	push	%rbx
+	push	%rbp
+	mov	-8(vp_param,n,8), %r14	C FIXME Put at absolute end
+	imul	(up), %r14		C FIXME Put at absolute end
+	lea	-3(n), R32(nn)
+	lea	8(vp_param), vp
+	mov	(vp_param), %rdx
+
+	mov	R32(n), R32(%rax)
+	shr	$3, R32(n)
+	and	$7, R32(%rax)		C clear OF, CF as side-effect
+	lea	L(mtab)(%rip), %r10
+ifdef(`PIC',
+`	movslq	(%r10,%rax,4), %rax
+	lea	(%rax, %r10), %r10
+	jmp	*%r10
+',`
+	jmp	*(%r10,%rax,8)
+')
+
+L(mf0):	mulx(	(up), %r10, %r8)
+	lea	56(up), up
+	lea	-8(rp), rp
+	lea	L(f7)(%rip), jmpreg
+	jmp	L(mb0)
+
+L(mf3):	mulx(	(up), %r9, %rax)
+	lea	16(up), up
+	lea	16(rp), rp
+	jrcxz	L(mc)
+	inc	R32(n)
+	lea	L(f2)(%rip), jmpreg
+	jmp	L(mb3)
+
+L(mc):	mulx(	-8,(up), %r10, %r8)
+	add	%rax, %r10
+	mov	%r9, -16(rp)
+	mulx(	(up), %r9, %rax)
+	mov	%r10, -8(rp)
+	adc	%r8, %r9
+	mov	%r9, (rp)
+	jmp	L(c2)
+
+L(mf4):	mulx(	(up), %r10, %r8)
+	lea	24(up), up
+	lea	24(rp), rp
+	inc	R32(n)
+	lea	L(f3)(%rip), jmpreg
+	jmp	L(mb4)
+
+L(mf5):	mulx(	(up), %r9, %rax)
+	lea	32(up), up
+	lea	32(rp), rp
+	inc	R32(n)
+	lea	L(f4)(%rip), jmpreg
+	jmp	L(mb5)
+
+L(mf6):	mulx(	(up), %r10, %r8)
+	lea	40(up), up
+	lea	40(rp), rp
+	inc	R32(n)
+	lea	L(f5)(%rip), jmpreg
+	jmp	L(mb6)
+
+L(mf7):	mulx(	(up), %r9, %rax)
+	lea	48(up), up
+	lea	48(rp), rp
+	lea	L(f6)(%rip), jmpreg
+	jmp	L(mb7)
+
+L(mf1):	mulx(	(up), %r9, %rax)
+	lea	L(f0)(%rip), jmpreg
+	jmp	L(mb1)
+
+L(mf2):	mulx(	(up), %r10, %r8)
+	lea	8(up), up
+	lea	8(rp), rp
+	lea	L(f1)(%rip), jmpreg
+	mulx(	(up), %r9, %rax)
+
+C FIXME ugly fallthrough FIXME
+	ALIGN(32)
+L(mtop):mov	%r10, -8(rp)
+	adc	%r8, %r9
+L(mb1):	mulx(	8,(up), %r10, %r8)
+	adc	%rax, %r10
+	lea	64(up), up
+	mov	%r9, (rp)
+L(mb0):	mov	%r10, 8(rp)
+	mulx(	-48,(up), %r9, %rax)
+	lea	64(rp), rp
+	adc	%r8, %r9
+L(mb7):	mulx(	-40,(up), %r10, %r8)
+	mov	%r9, -48(rp)
+	adc	%rax, %r10
+L(mb6):	mov	%r10, -40(rp)
+	mulx(	-32,(up), %r9, %rax)
+	adc	%r8, %r9
+L(mb5):	mulx(	-24,(up), %r10, %r8)
+	mov	%r9, -32(rp)
+	adc	%rax, %r10
+L(mb4):	mulx(	-16,(up), %r9, %rax)
+	mov	%r10, -24(rp)
+	adc	%r8, %r9
+L(mb3):	mulx(	-8,(up), %r10, %r8)
+	adc	%rax, %r10
+	mov	%r9, -16(rp)
+	dec	R32(n)
+	mulx(	(up), %r9, %rax)
+	jnz	L(mtop)
+
+L(mend):mov	%r10, -8(rp)
+	adc	%r8, %r9
+	mov	%r9, (rp)
+	adc	%rcx, %rax
+
+	lea	8(,nn,8), %r12
+	neg	%r12
+	shr	$3, R32(nn)
+	jmp	L(ent)
+
+L(f0):	mulx(	(up), %r10, %r8)
+	lea	-8(up), up
+	lea	-8(rp), rp
+	lea	L(f7)(%rip), jmpreg
+	jmp	L(b0)
+
+L(f1):	mulx(	(up), %r9, %rax)
+	lea	-1(nn), R32(nn)
+	lea	L(f0)(%rip), jmpreg
+	jmp	L(b1)
+
+L(end):	adox(	(rp), %r9)
+	mov	%r9, (rp)
+	adox(	%rcx, %rax)		C relies on rcx = 0
+	adc	%rcx, %rax		C FIXME suppress, use adc below; reqs ent path edits
+	lea	8(%r12), %r12
+L(ent):	mulx(	8,(up), %r10, %r8)	C r8 unused (use imul?)
+	add	%rax, %r14
+	add	%r10, %r14		C h
+	lea	(up,%r12), up		C reset up
+	lea	8(rp,%r12), rp		C reset rp
+	mov	(vp), %rdx
+	lea	8(vp), vp
+	or	R32(nn), R32(n)		C copy count, clear CF,OF (n = 0 prior)
+	jmp	*jmpreg
+
+L(f7):	mulx(	(up), %r9, %rax)
+	lea	-16(up), up
+	lea	-16(rp), rp
+	lea	L(f6)(%rip), jmpreg
+	jmp	L(b7)
+
+L(f2):	mulx(	(up), %r10, %r8)
+	lea	8(up), up
+	lea	8(rp), rp
+	mulx(	(up), %r9, %rax)
+	lea	L(f1)(%rip), jmpreg
+
+C FIXME ugly fallthrough FIXME
+	ALIGN(32)
+L(top):	adox(	-8,(rp), %r10)
+	adcx(	%r8, %r9)
+	mov	%r10, -8(rp)
+	jrcxz	L(end)
+L(b1):	mulx(	8,(up), %r10, %r8)
+	adox(	(rp), %r9)
+	lea	-1(n), R32(n)
+	mov	%r9, (rp)
+	adcx(	%rax, %r10)
+L(b0):	mulx(	16,(up), %r9, %rax)
+	adcx(	%r8, %r9)
+	adox(	8,(rp), %r10)
+	mov	%r10, 8(rp)
+L(b7):	mulx(	24,(up), %r10, %r8)
+	lea	64(up), up
+	adcx(	%rax, %r10)
+	adox(	16,(rp), %r9)
+	mov	%r9, 16(rp)
+L(b6):	mulx(	-32,(up), %r9, %rax)
+	adox(	24,(rp), %r10)
+	adcx(	%r8, %r9)
+	mov	%r10, 24(rp)
+L(b5):	mulx(	-24,(up), %r10, %r8)
+	adcx(	%rax, %r10)
+	adox(	32,(rp), %r9)
+	mov	%r9, 32(rp)
+L(b4):	mulx(	-16,(up), %r9, %rax)
+	adox(	40,(rp), %r10)
+	adcx(	%r8, %r9)
+	mov	%r10, 40(rp)
+L(b3):	adox(	48,(rp), %r9)
+	mulx(	-8,(up), %r10, %r8)
+	mov	%r9, 48(rp)
+	lea	64(rp), rp
+	adcx(	%rax, %r10)
+	mulx(	(up), %r9, %rax)
+	jmp	L(top)
+
+L(f6):	mulx(	(up), %r10, %r8)
+	lea	40(up), up
+	lea	-24(rp), rp
+	lea	L(f5)(%rip), jmpreg
+	jmp	L(b6)
+
+L(f5):	mulx(	(up), %r9, %rax)
+	lea	32(up), up
+	lea	-32(rp), rp
+	lea	L(f4)(%rip), jmpreg
+	jmp	L(b5)
+
+L(f4):	mulx(	(up), %r10, %r8)
+	lea	24(up), up
+	lea	-40(rp), rp
+	lea	L(f3)(%rip), jmpreg
+	jmp	L(b4)
+
+L(f3):	mulx(	(up), %r9, %rax)
+	lea	16(up), up
+	lea	-48(rp), rp
+	jrcxz	L(cor)
+	lea	L(f2)(%rip), jmpreg
+	jmp	L(b3)
+
+L(cor):	adox(	48,(rp), %r9)
+	mulx(	-8,(up), %r10, %r8)
+	mov	%r9, 48(rp)
+	lea	64(rp), rp
+	adcx(	%rax, %r10)
+	mulx(	(up), %r9, %rax)
+	adox(	-8,(rp), %r10)
+	adcx(	%r8, %r9)
+	mov	%r10, -8(rp)		C FIXME suppress
+	adox(	(rp), %r9)
+	mov	%r9, (rp)		C FIXME suppress
+	adox(	%rcx, %rax)
+L(c2):
+	mulx(	8,(up), %r10, %r8)
+	adc	%rax, %r14
+	add	%r10, %r14
+	mov	(vp), %rdx
+	test	R32(%rcx), R32(%rcx)
+	mulx(	-16,(up), %r10, %r8)
+	mulx(	-8,(up), %r9, %rax)
+	adox(	-8,(rp), %r10)
+	adcx(	%r8, %r9)
+	mov	%r10, -8(rp)
+	adox(	(rp), %r9)
+	adox(	%rcx, %rax)
+	adc	%rcx, %rax
+	mulx(	(up), %r10, %r8)
+	add	%rax, %r14
+	add	%r10, %r14
+	mov	8(vp), %rdx
+	mulx(	-16,(up), %rcx, %rax)
+	add	%r9, %rcx
+	mov	%rcx, (rp)
+	adc	$0, %rax
+	mulx(	-8,(up), %r10, %r8)
+	add	%rax, %r14
+	add	%r10, %r14
+	mov	%r14, 8(rp)
+	pop	%rbp
+	pop	%rbx
+	pop	%r12
+	pop	%r14
+	FUNC_EXIT()
+	ret
+EPILOGUE()
+	JUMPTABSECT
+	ALIGN(8)
+L(mtab):JMPENT(	L(mf7), L(mtab))
+	JMPENT(	L(mf0), L(mtab))
+	JMPENT(	L(mf1), L(mtab))
+	JMPENT(	L(mf2), L(mtab))
+	JMPENT(	L(mf3), L(mtab))
+	JMPENT(	L(mf4), L(mtab))
+	JMPENT(	L(mf5), L(mtab))
+	JMPENT(	L(mf6), L(mtab))
diff --git a/third_party/gmp/mpn/x86_64/coreibwl/sqr_basecase.asm b/third_party/gmp/mpn/x86_64/coreibwl/sqr_basecase.asm
new file mode 100644
index 0000000..e81b01b
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreibwl/sqr_basecase.asm
@@ -0,0 +1,839 @@
+dnl  AMD64 mpn_sqr_basecase optimised for Intel Broadwell.
+
+dnl  Copyright 2015, 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C cycles/limb	mul_1		addmul_1
+C AMD K8,K9	n/a		n/a
+C AMD K10	n/a		n/a
+C AMD bd1	n/a		n/a
+C AMD bd2	n/a		n/a
+C AMD bd3	n/a		n/a
+C AMD bd4	 ?		 ?
+C AMD zen	 ?		 ?
+C AMD bt1	n/a		n/a
+C AMD bt2	n/a		n/a
+C Intel P4	n/a		n/a
+C Intel PNR	n/a		n/a
+C Intel NHM	n/a		n/a
+C Intel SBR	n/a		n/a
+C Intel IBR	n/a		n/a
+C Intel HWL	 1.68		n/a
+C Intel BWL	 1.51	      1.67-1.74
+C Intel SKL	 1.52	      1.63-1.71
+C Intel atom	n/a		n/a
+C Intel SLM	n/a		n/a
+C VIA nano	n/a		n/a
+
+C The inner loops of this code are the result of running a code generation and
+C optimisation tool suite written by David Harvey and Torbjorn Granlund.
+
+C TODO
+C  * We have 8 addmul_1 loops which fall into each other.  The idea is to save
+C    on switching code, since a circularly updated computed goto target will
+C    hardly allow correct branch prediction.  On 2nd thought, we now might make
+C    each of the 8 loop branches be poorly predicted since they will be
+C    executed fewer times for each time.  With just one addmul_1 loop, the loop
+C    count will change only once each 8th time.
+C  * Do overlapped software pipelining.
+C  * Perhaps load in shrx/sarx, eliminating separate load insn.
+C  * Schedule add+stored in small n code.
+C  * Try swapping adox and adcx insn, making mulx have more time to run.
+
+define(`rp',      `%rdi')
+define(`up',      `%rsi')
+define(`un_param',`%rdx')
+
+define(`n',       `%rcx')
+define(`un_save', `%rbx')
+define(`u0',      `%rdx')
+
+define(`w0',	`%r8')
+define(`w1',	`%r9')
+define(`w2',	`%r10')
+define(`w3',	`%r11')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_sqr_basecase)
+	FUNC_ENTRY(3)
+
+	cmp	$2, un_param
+	jae	L(gt1)
+
+	mov	(up), %rdx
+	mulx(	%rdx, %rax, %rdx)
+	mov	%rax, (rp)
+	mov	%rdx, 8(rp)
+	FUNC_EXIT()
+	ret
+
+L(gt1):	jne	L(gt2)
+
+	mov	(up), %rdx
+	mov	8(up), %rcx
+	mulx(	%rcx, %r9, %r10)	C v0 * v1	W 1 2
+	mulx(	%rdx, %rax, %r8)	C v0 * v0	W 0 1
+	mov	%rcx, %rdx
+	mulx(	%rdx, %r11, %rdx)	C v1 * v1	W 2 3
+	add	%r9, %r9		C		W 1
+	adc	%r10, %r10		C		W 2
+	adc	$0, %rdx		C		W 3
+	add	%r9, %r8		C W 1
+	adc	%r11, %r10		C W 2
+	adc	$0, %rdx		C W 3
+	mov	%rax, (rp)
+	mov	%r8, 8(rp)
+	mov	%r10, 16(rp)
+	mov	%rdx, 24(rp)
+	FUNC_EXIT()
+	ret
+
+L(gt2):	cmp	$4, un_param
+	jae	L(gt3)
+
+	push	%rbx
+	mov	(up), %rdx
+	mulx(	8,(up), w2, w3)
+	mulx(	16,(up), w0, w1)
+	add	w3, w0
+	mov	8(up), %rdx
+	mulx(	16,(up), %rax, w3)
+	adc	%rax, w1
+	adc	$0, w3
+	test	R32(%rbx), R32(%rbx)
+	mov	(up), %rdx
+	mulx(	%rdx, %rbx, %rcx)
+	mov	%rbx, (rp)
+	mov	8(up), %rdx
+	mulx(	%rdx, %rax, %rbx)
+	mov	16(up), %rdx
+	mulx(	%rdx, %rsi, %rdx)
+	adcx(	w2, w2)
+	adcx(	w0, w0)
+	adcx(	w1, w1)
+	adcx(	w3, w3)
+	adox(	w2, %rcx)
+	adox(	w0, %rax)
+	adox(	w1, %rbx)
+	adox(	w3, %rsi)
+	mov	$0, R32(%r8)
+	adox(	%r8, %rdx)
+	adcx(	%r8, %rdx)
+	mov	%rcx, 8(rp)
+	mov	%rax, 16(rp)
+	mov	%rbx, 24(rp)
+	mov	%rsi, 32(rp)
+	mov	%rdx, 40(rp)
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+
+L(gt3):	push	%rbx
+
+	lea	-3(un_param), R32(un_save)
+	lea	5(un_param), R32(n)
+	mov	R32(un_param), R32(%rax)
+	and	$-8, R32(un_save)
+	shr	$3, R32(n)		C count for mul_1 loop
+	neg	un_save			C 8*count and offert for addmul_1 loops
+	and	$7, R32(%rax)		C clear CF for adc as side-effect
+
+	mov	(up), u0
+
+	lea	L(mtab)(%rip), %r10
+ifdef(`PIC',
+`	movslq	(%r10,%rax,4), %r8
+	lea	(%r8, %r10), %r10
+	jmp	*%r10
+',`
+	jmp	*(%r10,%rax,8)
+')
+
+L(mf0):	mulx(	u0, w0, w1)		C up[0]^2
+	add	u0, u0
+	mulx(	8,(up), w2, w3)
+	lea	64(up), up
+	add	w1, w2
+	jmp	L(mb0)
+
+L(mf3):	mulx(	u0, w2, w3)		C up[0]^2
+	add	u0, u0
+	mov	w2, (rp)
+	mulx(	8,(up), w0, w1)
+	lea	24(up), up
+	lea	24(rp), rp
+	add	w3, w0
+	jmp	L(mb3)
+
+L(mf4):	mulx(	u0, w0, w1)		C up[0]^2
+	add	u0, u0
+	mulx(	8,(up), w2, w3)
+	mov	w0, (rp)
+	lea	32(up), up
+	lea	32(rp), rp
+	add	w1, w2
+	jmp	L(mb4)
+
+L(mf5):	mulx(	u0, w2, w3)		C up[0]^2
+	add	u0, u0
+	mulx(	8,(up), w0, w1)
+	mov	w2, (rp)
+	lea	40(up), up
+	lea	40(rp), rp
+	add	w3, w0
+	jmp	L(mb5)
+
+L(mf6):	mulx(	u0, w0, w1)		C up[0]^2
+	add	u0, u0
+	mulx(	8,(up), w2, w3)
+	mov	w0, (rp)
+	lea	48(up), up
+	lea	48(rp), rp
+	add	w1, w2
+	jmp	L(mb6)
+
+L(mf7):	mulx(	u0, w2, w3)		C up[0]^2
+	add	u0, u0
+	mulx(	8,(up), w0, w1)
+	mov	w2, (rp)
+	lea	56(up), up
+	lea	56(rp), rp
+	add	w3, w0
+	jmp	L(mb7)
+
+L(mf1):	mulx(	u0, w2, w3)		C up[0]^2
+	add	u0, u0
+	mulx(	8,(up), w0, w1)
+	mov	w2, (rp)
+	lea	8(up), up
+	lea	8(rp), rp
+	add	w3, w0
+	jmp	L(mb1)
+
+L(mf2):	mulx(	u0, w0, w1)		C up[0]^2
+	add	u0, u0
+	mulx(	8,(up), w2, w3)
+	mov	w0, (rp)
+	lea	16(up), up
+	lea	16(rp), rp
+	dec	R32(n)
+	add	w1, w2
+	mulx(	(up), w0, w1)
+
+	ALIGN(16)
+L(top):	mov	w2, -8(rp)
+	adc	w3, w0
+L(mb1):	mulx(	8,(up), w2, w3)
+	adc	w1, w2
+	lea	64(up), up
+L(mb0):	mov	w0, (rp)
+	mov	w2, 8(rp)
+	mulx(	-48,(up), w0, w1)
+	lea	64(rp), rp
+	adc	w3, w0
+L(mb7):	mulx(	-40,(up), w2, w3)
+	mov	w0, -48(rp)
+	adc	w1, w2
+L(mb6):	mov	w2, -40(rp)
+	mulx(	-32,(up), w0, w1)
+	adc	w3, w0
+L(mb5):	mulx(	-24,(up), w2, w3)
+	mov	w0, -32(rp)
+	adc	w1, w2
+L(mb4):	mulx(	-16,(up), w0, w1)
+	mov	w2, -24(rp)
+	adc	w3, w0
+L(mb3):	mulx(	-8,(up), w2, w3)
+	adc	w1, w2
+	mov	w0, -16(rp)
+	dec	R32(n)
+	mulx(	(up), w0, w1)
+	jnz	L(top)
+
+L(end):	mov	w2, -8(rp)
+	adc	w3, w0
+C	mov	w0, (rp)
+C	adc	%rcx, w1
+C	mov	w1, 8(rp)
+
+	lea	L(atab)(%rip), %r10
+ifdef(`PIC',
+`	movslq	(%r10,%rax,4), %r11
+	lea	(%r11, %r10), %r11
+',`
+	mov	(%r10,%rax,8), %r11
+')
+	mov	$63, R32(%rax)
+	jmp	*%r11
+
+L(ed0):	adox(	(rp), w0)
+	adox(	%rcx, w1)		C relies on rcx = 0
+L(f7):	mov	w0, (rp)
+	adc	%rcx, w1		C relies on rcx = 0
+	mov	w1, 8(rp)
+	lea	-64(up,un_save,8), up
+	mov	R32(un_save), R32(n)
+	lea	-56(rp,un_save,8), rp
+	mov	(up), w1		C up[-1]
+	mov	8(up), u0		C up[0]
+	shrx(	%rax, w1, w0)
+	sarx(	%rax, w1, w1)
+	and	u0, w1			C "ci" in C code
+	mulx(	u0, w2, w3)		C up[0]^2
+	lea	(w0,u0,2), u0		C "u0" arg in C code
+	jmp	L(b7)
+
+	ALIGN(16)
+L(tp0):	adox(	-8,(rp), w2)
+	adcx(	w3, w0)
+	mov	w2, -8(rp)
+	jrcxz	L(ed0)
+	mulx(	8,(up), w2, w3)
+	adox(	(rp), w0)
+	lea	8(n), R32(n)
+L(b0):	mov	w0, (rp)
+	adcx(	w1, w2)
+	mulx(	16,(up), w0, w1)
+	adcx(	w3, w0)
+	adox(	8,(rp), w2)
+	mov	w2, 8(rp)
+	mulx(	24,(up), w2, w3)
+	lea	64(up), up
+	adcx(	w1, w2)
+	adox(	16,(rp), w0)
+	mov	w0, 16(rp)
+	mulx(	-32,(up), w0, w1)
+	adox(	24,(rp), w2)
+	adcx(	w3, w0)
+	mov	w2, 24(rp)
+	mulx(	-24,(up), w2, w3)
+	adcx(	w1, w2)
+	adox(	32,(rp), w0)
+	mov	w0, 32(rp)
+	mulx(	-16,(up), w0, w1)
+	adox(	40,(rp), w2)
+	adcx(	w3, w0)
+	mov	w2, 40(rp)
+	adox(	48,(rp), w0)
+	mulx(	-8,(up), w2, w3)
+	mov	w0, 48(rp)
+	lea	64(rp), rp
+	adcx(	w1, w2)
+	mulx(	(up), w0, w1)
+	jmp	L(tp0)
+
+L(ed1):	adox(	(rp), w0)
+	adox(	%rcx, w1)		C relies on rcx = 0
+L(f0):	mov	w0, (rp)
+	adc	%rcx, w1		C relies on rcx = 0
+	mov	w1, 8(rp)
+	lea	-64(up,un_save,8), up
+	mov	R32(un_save), R32(n)
+	lea	-56(rp,un_save,8), rp
+	mov	-8(up), w3		C up[-1]
+	mov	(up), u0		C up[0]
+	shrx(	%rax, w3, w2)
+	sarx(	%rax, w3, w3)
+	and	u0, w3			C "ci" in C code
+	mulx(	u0, w0, w1)		C up[0]^2
+	lea	(w2,u0,2), u0		C "u0" arg in C code
+	adcx(	w3, w0)
+	mulx(	8,(up), w2, w3)
+	adox(	(rp), w0)
+	jmp	L(b0)
+
+	ALIGN(16)
+L(tp1):	adox(	-8,(rp), w2)
+	adcx(	w3, w0)
+	mov	w2, -8(rp)
+	jrcxz	L(ed1)
+L(b1):	mulx(	8,(up), w2, w3)
+	adox(	(rp), w0)
+	lea	8(n), R32(n)
+	mov	w0, (rp)
+	adcx(	w1, w2)
+	mulx(	16,(up), w0, w1)
+	adcx(	w3, w0)
+	adox(	8,(rp), w2)
+	mov	w2, 8(rp)
+	mulx(	24,(up), w2, w3)
+	lea	64(up), up
+	adcx(	w1, w2)
+	adox(	16,(rp), w0)
+	mov	w0, 16(rp)
+	mulx(	-32,(up), w0, w1)
+	adox(	24,(rp), w2)
+	adcx(	w3, w0)
+	mov	w2, 24(rp)
+	mulx(	-24,(up), w2, w3)
+	adcx(	w1, w2)
+	adox(	32,(rp), w0)
+	mov	w0, 32(rp)
+	mulx(	-16,(up), w0, w1)
+	adox(	40,(rp), w2)
+	adcx(	w3, w0)
+	mov	w2, 40(rp)
+	adox(	48,(rp), w0)
+	mulx(	-8,(up), w2, w3)
+	mov	w0, 48(rp)
+	lea	64(rp), rp
+	adcx(	w1, w2)
+	mulx(	(up), w0, w1)
+	jmp	L(tp1)
+
+L(ed2):	adox(	(rp), w0)
+	adox(	%rcx, w1)		C relies on rcx = 0
+L(f1):	mov	w0, (rp)
+	adc	%rcx, w1		C relies on rcx = 0
+	mov	w1, 8(rp)
+	lea	(up,un_save,8), up
+	mov	R32(un_save), R32(n)
+	lea	8(un_save), un_save
+	lea	-56(rp,un_save,8), rp
+	mov	-16(up), w1		C up[-1]
+	mov	-8(up), u0		C up[0]
+	shrx(	%rax, w1, w0)
+	sarx(	%rax, w1, w1)
+	and	u0, w1			C "ci" in C code
+	mulx(	u0, w2, w3)		C up[0]^2
+	lea	(w0,u0,2), u0		C "u0" arg in C code
+	adcx(	w1, w2)			C FIXME: crossjump?
+	mulx(	(up), w0, w1)
+	adox(	-8,(rp), w2)
+	adcx(	w3, w0)
+	mov	w2, -8(rp)
+	jmp	L(b1)
+
+	ALIGN(16)
+L(tp2):	adox(	-8,(rp), w2)
+	adcx(	w3, w0)
+	mov	w2, -8(rp)
+	jrcxz	L(ed2)
+	mulx(	8,(up), w2, w3)
+	adox(	(rp), w0)
+	lea	8(n), R32(n)
+	mov	w0, (rp)
+	adcx(	w1, w2)
+	mulx(	16,(up), w0, w1)
+	adcx(	w3, w0)
+	adox(	8,(rp), w2)
+	mov	w2, 8(rp)
+	mulx(	24,(up), w2, w3)
+	lea	64(up), up
+	adcx(	w1, w2)
+	adox(	16,(rp), w0)
+	mov	w0, 16(rp)
+	mulx(	-32,(up), w0, w1)
+	adox(	24,(rp), w2)
+	adcx(	w3, w0)
+	mov	w2, 24(rp)
+	mulx(	-24,(up), w2, w3)
+	adcx(	w1, w2)
+	adox(	32,(rp), w0)
+	mov	w0, 32(rp)
+	mulx(	-16,(up), w0, w1)
+	adox(	40,(rp), w2)
+	adcx(	w3, w0)
+	mov	w2, 40(rp)
+L(b2):	adox(	48,(rp), w0)
+	mulx(	-8,(up), w2, w3)
+	mov	w0, 48(rp)
+	lea	64(rp), rp
+	adcx(	w1, w2)
+	mulx(	(up), w0, w1)
+	jmp	L(tp2)
+
+L(ed3):	adox(	(rp), w0)
+	adox(	%rcx, w1)		C relies on rcx = 0
+L(f2):	mov	w0, (rp)
+	adc	%rcx, w1		C relies on rcx = 0
+	mov	w1, 8(rp)
+	lea	(up,un_save,8), up
+	or	R32(un_save), R32(n)
+	jz	L(cor3)
+	lea	-56(rp,un_save,8), rp
+	mov	-24(up), w3		C up[-1]
+	mov	-16(up), u0		C up[0]
+	shrx(	%rax, w3, w2)
+	sarx(	%rax, w3, w3)
+	and	u0, w3			C "ci" in C code
+	mulx(	u0, w0, w1)		C up[0]^2
+	lea	(w2,u0,2), u0		C "u0" arg in C code
+	adcx(	w3, w0)
+	jmp	L(b2)
+
+	ALIGN(16)
+L(tp3):	adox(	-8,(rp), w2)
+	adcx(	w3, w0)
+	mov	w2, -8(rp)
+	jrcxz	L(ed3)
+	mulx(	8,(up), w2, w3)
+	adox(	(rp), w0)
+	lea	8(n), R32(n)
+	mov	w0, (rp)
+	adcx(	w1, w2)
+	mulx(	16,(up), w0, w1)
+	adcx(	w3, w0)
+	adox(	8,(rp), w2)
+	mov	w2, 8(rp)
+	mulx(	24,(up), w2, w3)
+	lea	64(up), up
+	adcx(	w1, w2)
+	adox(	16,(rp), w0)
+	mov	w0, 16(rp)
+	mulx(	-32,(up), w0, w1)
+	adox(	24,(rp), w2)
+	adcx(	w3, w0)
+	mov	w2, 24(rp)
+	mulx(	-24,(up), w2, w3)
+	adcx(	w1, w2)
+	adox(	32,(rp), w0)
+	mov	w0, 32(rp)
+L(b3):	mulx(	-16,(up), w0, w1)
+	adox(	40,(rp), w2)
+	adcx(	w3, w0)
+	mov	w2, 40(rp)
+	adox(	48,(rp), w0)
+	mulx(	-8,(up), w2, w3)
+	mov	w0, 48(rp)
+	lea	64(rp), rp
+	adcx(	w1, w2)
+	mulx(	(up), w0, w1)
+	jmp	L(tp3)
+
+L(ed4):	adox(	(rp), w0)
+	adox(	%rcx, w1)		C relies on rcx = 0
+L(f3):	mov	w0, (rp)
+	adc	%rcx, w1		C relies on rcx = 0
+	mov	w1, 8(rp)
+	lea	(up,un_save,8), up
+	mov	R32(un_save), R32(n)
+	lea	-56(rp,un_save,8), rp
+	mov	-32(up), w1		C up[-1]
+	mov	-24(up), u0		C up[0]
+	shrx(	%rax, w1, w0)
+	sarx(	%rax, w1, w1)
+	and	u0, w1			C "ci" in C code
+	mulx(	u0, w2, w3)		C up[0]^2
+	lea	(w0,u0,2), u0		C "u0" arg in C code
+	adcx(	w1, w2)
+	jmp	L(b3)
+
+	ALIGN(16)
+L(tp4):	adox(	-8,(rp), w2)
+	adcx(	w3, w0)
+	mov	w2, -8(rp)
+	jrcxz	L(ed4)
+	mulx(	8,(up), w2, w3)
+	adox(	(rp), w0)
+	lea	8(n), R32(n)
+	mov	w0, (rp)
+	adcx(	w1, w2)
+	mulx(	16,(up), w0, w1)
+	adcx(	w3, w0)
+	adox(	8,(rp), w2)
+	mov	w2, 8(rp)
+	mulx(	24,(up), w2, w3)
+	lea	64(up), up
+	adcx(	w1, w2)
+	adox(	16,(rp), w0)
+	mov	w0, 16(rp)
+	mulx(	-32,(up), w0, w1)
+	adox(	24,(rp), w2)
+	adcx(	w3, w0)
+	mov	w2, 24(rp)
+L(b4):	mulx(	-24,(up), w2, w3)
+	adcx(	w1, w2)
+	adox(	32,(rp), w0)
+	mov	w0, 32(rp)
+	mulx(	-16,(up), w0, w1)
+	adox(	40,(rp), w2)
+	adcx(	w3, w0)
+	mov	w2, 40(rp)
+	adox(	48,(rp), w0)
+	mulx(	-8,(up), w2, w3)
+	mov	w0, 48(rp)
+	lea	64(rp), rp
+	adcx(	w1, w2)
+	mulx(	(up), w0, w1)
+	jmp	L(tp4)
+
+L(ed5):	adox(	(rp), w0)
+	adox(	%rcx, w1)		C relies on rcx = 0
+L(f4):	mov	w0, (rp)
+	adc	%rcx, w1		C relies on rcx = 0
+	mov	w1, 8(rp)
+	lea	(up,un_save,8), up
+	mov	R32(un_save), R32(n)
+	lea	-56(rp,un_save,8), rp
+	mov	-40(up), w3		C up[-1]
+	mov	-32(up), u0		C up[0]
+	shrx(	%rax, w3, w2)
+	sarx(	%rax, w3, w3)
+	and	u0, w3			C "ci" in C code
+	mulx(	u0, w0, w1)		C up[0]^2
+	lea	(w2,u0,2), u0		C "u0" arg in C code
+	adcx(	w3, w0)
+	jmp	L(b4)
+
+	ALIGN(16)
+L(tp5):	adox(	-8,(rp), w2)
+	adcx(	w3, w0)
+	mov	w2, -8(rp)
+	jrcxz	L(ed5)
+	mulx(	8,(up), w2, w3)
+	adox(	(rp), w0)
+	lea	8(n), R32(n)
+	mov	w0, (rp)
+	adcx(	w1, w2)
+	mulx(	16,(up), w0, w1)
+	adcx(	w3, w0)
+	adox(	8,(rp), w2)
+	mov	w2, 8(rp)
+	mulx(	24,(up), w2, w3)
+	lea	64(up), up
+	adcx(	w1, w2)
+	adox(	16,(rp), w0)
+	mov	w0, 16(rp)
+L(b5):	mulx(	-32,(up), w0, w1)
+	adox(	24,(rp), w2)
+	adcx(	w3, w0)
+	mov	w2, 24(rp)
+	mulx(	-24,(up), w2, w3)
+	adcx(	w1, w2)
+	adox(	32,(rp), w0)
+	mov	w0, 32(rp)
+	mulx(	-16,(up), w0, w1)
+	adox(	40,(rp), w2)
+	adcx(	w3, w0)
+	mov	w2, 40(rp)
+	adox(	48,(rp), w0)
+	mulx(	-8,(up), w2, w3)
+	mov	w0, 48(rp)
+	lea	64(rp), rp
+	adcx(	w1, w2)
+	mulx(	(up), w0, w1)
+	jmp	L(tp5)
+
+L(ed6):	adox(	(rp), w0)
+	adox(	%rcx, w1)		C relies on rcx = 0
+L(f5):	mov	w0, (rp)
+	adc	%rcx, w1		C relies on rcx = 0
+	mov	w1, 8(rp)
+	lea	(up,un_save,8), up
+	mov	R32(un_save), R32(n)
+	lea	-56(rp,un_save,8), rp
+	mov	-48(up), w1		C up[-1]
+	mov	-40(up), u0		C up[0]
+	shrx(	%rax, w1, w0)
+	sarx(	%rax, w1, w1)
+	and	u0, w1			C "ci" in C code
+	mulx(	u0, w2, w3)		C up[0]^2
+	lea	(w0,u0,2), u0		C "u0" arg in C code
+	adcx(	w1, w2)
+	jmp	L(b5)
+
+	ALIGN(16)
+L(tp6):	adox(	-8,(rp), w2)
+	adcx(	w3, w0)
+	mov	w2, -8(rp)
+	jrcxz	L(ed6)
+	mulx(	8,(up), w2, w3)
+	adox(	(rp), w0)
+	lea	8(n), R32(n)
+	mov	w0, (rp)
+	adcx(	w1, w2)
+	mulx(	16,(up), w0, w1)
+	adcx(	w3, w0)
+	adox(	8,(rp), w2)
+	mov	w2, 8(rp)
+	mulx(	24,(up), w2, w3)
+	lea	64(up), up
+L(b6):	adcx(	w1, w2)
+	adox(	16,(rp), w0)
+	mov	w0, 16(rp)
+	mulx(	-32,(up), w0, w1)
+	adox(	24,(rp), w2)
+	adcx(	w3, w0)
+	mov	w2, 24(rp)
+	mulx(	-24,(up), w2, w3)
+	adcx(	w1, w2)
+	adox(	32,(rp), w0)
+	mov	w0, 32(rp)
+	mulx(	-16,(up), w0, w1)
+	adox(	40,(rp), w2)
+	adcx(	w3, w0)
+	mov	w2, 40(rp)
+	adox(	48,(rp), w0)
+	mulx(	-8,(up), w2, w3)
+	mov	w0, 48(rp)
+	lea	64(rp), rp
+	adcx(	w1, w2)
+	mulx(	(up), w0, w1)
+	jmp	L(tp6)
+
+L(ed7):	adox(	(rp), w0)
+	adox(	%rcx, w1)		C relies on rcx = 0
+L(f6):	mov	w0, (rp)
+	adc	%rcx, w1		C relies on rcx = 0
+	mov	w1, 8(rp)
+	lea	(up,un_save,8), up
+	mov	R32(un_save), R32(n)
+	lea	-56(rp,un_save,8), rp
+	mov	-56(up), w3		C up[-1]
+	mov	-48(up), u0		C up[0]
+	shrx(	%rax, w3, w2)
+	sarx(	%rax, w3, w3)
+	and	u0, w3			C "ci" in C code
+	mulx(	u0, w0, w1)		C up[0]^2
+	lea	(w2,u0,2), u0		C "u0" arg in C code
+	adcx(	w3, w0)
+	mulx(	-40,(up), w2, w3)
+	jmp	L(b6)
+
+	ALIGN(16)
+L(tp7):	adox(	-8,(rp), w2)
+	adcx(	w3, w0)
+	mov	w2, -8(rp)
+	jrcxz	L(ed7)
+	mulx(	8,(up), w2, w3)
+	adox(	(rp), w0)
+	lea	8(n), R32(n)
+	mov	w0, (rp)
+L(b7):	adcx(	w1, w2)
+	mulx(	16,(up), w0, w1)
+	adcx(	w3, w0)
+	adox(	8,(rp), w2)
+	mov	w2, 8(rp)
+	mulx(	24,(up), w2, w3)
+	lea	64(up), up
+	adcx(	w1, w2)
+	adox(	16,(rp), w0)
+	mov	w0, 16(rp)
+	mulx(	-32,(up), w0, w1)
+	adox(	24,(rp), w2)
+	adcx(	w3, w0)
+	mov	w2, 24(rp)
+	mulx(	-24,(up), w2, w3)
+	adcx(	w1, w2)
+	adox(	32,(rp), w0)
+	mov	w0, 32(rp)
+	mulx(	-16,(up), w0, w1)
+	adox(	40,(rp), w2)
+	adcx(	w3, w0)
+	mov	w2, 40(rp)
+	adox(	48,(rp), w0)
+	mulx(	-8,(up), w2, w3)
+	mov	w0, 48(rp)
+	lea	64(rp), rp
+	adcx(	w1, w2)
+	mulx(	(up), w0, w1)
+	jmp	L(tp7)
+
+L(cor3):lea	-64(rp), rp
+	mov	-24(up), w3		C up[-1]
+	mov	-16(up), u0		C up[0]
+	shrx(	%rax, w3, w2)
+	sarx(	%rax, w3, w3)
+	and	u0, w3			C "ci" in C code
+	mulx(	u0, w0, w1)		C up[0]^2
+	lea	(w2,u0,2), u0		C "u0" arg in C code
+	adcx(	w3, w0)
+	adox(	56,(rp), w0)
+	mulx(	-8,(up), w2, w3)
+	mov	w0, 56(rp)
+	adcx(	w1, w2)
+	mulx(	(up), %rbx, w1)
+	adox(	64,(rp), w2)
+	adcx(	w3, %rbx)
+	mov	w2, 64(rp)
+	adox(	72,(rp), %rbx)
+	adox(	%rcx, w1)		C relies on rcx = 0
+	adc	%rcx, w1		C relies on rcx = 0
+	mov	w1, 80(rp)	C FIXME
+C wd2
+	mov	-16(up), w1		C up[-1]
+	mov	-8(up), u0		C up[0]
+	shrx(	%rax, w1, w0)
+	sarx(	%rax, w1, w1)
+	and	u0, w1			C "ci" in C code
+	mulx(	u0, w2, w3)		C up[0]^2
+	lea	(w0,u0,2), u0		C "u0" arg in C code
+	adcx(	w1, w2)
+	mulx(	(up), w0, %rax)
+	adox(	%rbx, w2)
+	adcx(	w3, w0)
+	mov	w2, 72(rp)
+	adox(	80,(rp), w0)
+	adox(	%rcx, %rax)		C relies on rcx = 0
+	mov	w0, 80(rp)
+	adc	%rcx, %rax		C relies on rcx = 0
+C wd1
+	mov	-8(up), w3		C up[-1]
+	mov	(up), u0		C up[0]
+	sar	$63, w3
+	and	u0, w3			C "ci" in C code
+	mulx(	u0, w0, w1)		C up[0]^2
+	adcx(	w3, w0)
+	adox(	%rax, w0)
+	mov	w0, 88(rp)
+	adcx(	%rcx, w1)
+	adox(	%rcx, w1)
+	mov	w1, 96(rp)
+
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+
+	JUMPTABSECT
+	ALIGN(8)
+L(mtab):JMPENT(	L(mf7), L(mtab))
+	JMPENT(	L(mf0), L(mtab))
+	JMPENT(	L(mf1), L(mtab))
+	JMPENT(	L(mf2), L(mtab))
+	JMPENT(	L(mf3), L(mtab))
+	JMPENT(	L(mf4), L(mtab))
+	JMPENT(	L(mf5), L(mtab))
+	JMPENT(	L(mf6), L(mtab))
+L(atab):JMPENT(	L(f6), L(atab))
+	JMPENT(	L(f7), L(atab))
+	JMPENT(	L(f0), L(atab))
+	JMPENT(	L(f1), L(atab))
+	JMPENT(	L(f2), L(atab))
+	JMPENT(	L(f3), L(atab))
+	JMPENT(	L(f4), L(atab))
+	JMPENT(	L(f5), L(atab))
+	TEXT
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/coreihwl/addmul_2.asm b/third_party/gmp/mpn/x86_64/coreihwl/addmul_2.asm
new file mode 100644
index 0000000..9d1c405
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreihwl/addmul_2.asm
@@ -0,0 +1,241 @@
+dnl  AMD64 mpn_addmul_2 optimised for Intel Haswell.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	n/a
+C AMD K10	n/a
+C AMD bull	n/a
+C AMD pile	n/a
+C AMD steam	n/a
+C AMD excavator	 ?
+C AMD bobcat	n/a
+C AMD jaguar	n/a
+C Intel P4	n/a
+C Intel core	n/a
+C Intel NHM	n/a
+C Intel SBR	n/a
+C Intel IBR	n/a
+C Intel HWL	 2.15
+C Intel BWL	 2.33
+C Intel SKL	 2.22
+C Intel atom	n/a
+C Intel SLM	n/a
+C VIA nano	n/a
+
+C The loop of this code is the result of running a code generation and
+C optimisation tool suite written by David Harvey and Torbjörn Granlund.
+
+define(`rp',     `%rdi')
+define(`up',     `%rsi')
+define(`n_param',`%rdx')
+define(`vp',     `%rcx')
+
+define(`v0', `%r8')
+define(`v1', `%r9')
+define(`w0', `%rbx')
+define(`w1', `%rcx')
+define(`w2', `%rbp')
+define(`w3', `%r10')
+define(`n',  `%r11')
+define(`X0', `%r12')
+define(`X1', `%r13')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_addmul_2)
+	FUNC_ENTRY(4)
+	push	%rbx
+	push	%rbp
+	push	%r12
+	push	%r13
+
+	mov	(vp), v0
+	mov	8(vp), v1
+
+	mov	n_param, n
+	shr	$2, n
+
+	test	$1, R8(n_param)
+	jnz	L(bx1)
+
+L(bx0):	mov	(rp), X0
+	mov	8(rp), X1
+	test	$2, R8(n_param)
+	jnz	L(b10)
+
+L(b00):	mov	(up), %rdx
+	lea	16(up), up
+	mulx(	v0, %rax, w1)
+	add	%rax, X0
+	mulx(	v1, %rax, w2)
+	adc	$0, w1
+	mov	X0, (rp)
+	add	%rax, X1
+	adc	$0, w2
+	mov	-8(up), %rdx
+	lea	16(rp), rp
+	jmp	L(lo0)
+
+L(b10):	mov	(up), %rdx
+	inc	n
+	mulx(	v0, %rax, w1)
+	add	%rax, X0
+	adc	$0, w1
+	mulx(	v1, %rax, w2)
+	mov	X0, (rp)
+	mov	16(rp), X0
+	add	%rax, X1
+	adc	$0, w2
+	xor	w0, w0
+	jmp	L(lo2)
+
+L(bx1):	mov	(rp), X1
+	mov	8(rp), X0
+	test	$2, R8(n_param)
+	jnz	L(b11)
+
+L(b01):	mov	(up), %rdx
+	mulx(	v0, %rax, w3)
+	add	%rax, X1
+	adc	$0, w3
+	mulx(	v1, %rax, w0)
+	add	%rax, X0
+	adc	$0, w0
+	mov	8(up), %rdx
+	mov	X1, (rp)
+	mov	16(rp), X1
+	mulx(	v0, %rax, w1)
+	lea	24(rp), rp
+	lea	24(up), up
+	jmp	L(lo1)
+
+L(b11):	mov	(up), %rdx
+	inc	n
+	mulx(	v0, %rax, w3)
+	add	%rax, X1
+	adc	$0, w3
+	mulx(	v1, %rax, w0)
+	add	%rax, X0
+	adc	$0, w0
+	mov	X1, (rp)
+	mov	8(up), %rdx
+	mulx(	v0, %rax, w1)
+	lea	8(rp), rp
+	lea	8(up), up
+	jmp	L(lo3)
+
+	ALIGN(16)
+L(top):	mulx(	v0, %rax, w3)
+	add	w0, X1
+	adc	$0, w2
+	add	%rax, X1
+	adc	$0, w3
+	mulx(	v1, %rax, w0)
+	add	%rax, X0
+	adc	$0, w0
+	lea	32(rp), rp
+	add	w1, X1
+	mov	-16(up), %rdx
+	mov	X1, -24(rp)
+	adc	$0, w3
+	add	w2, X0
+	mov	-8(rp), X1
+	mulx(	v0, %rax, w1)
+	adc	$0, w0
+L(lo1):	add	%rax, X0
+	mulx(	v1, %rax, w2)
+	adc	$0, w1
+	add	w3, X0
+	mov	X0, -16(rp)
+	adc	$0, w1
+	add	%rax, X1
+	adc	$0, w2
+	add	w0, X1
+	mov	-8(up), %rdx
+	adc	$0, w2
+L(lo0):	mulx(	v0, %rax, w3)
+	add	%rax, X1
+	adc	$0, w3
+	mov	(rp), X0
+	mulx(	v1, %rax, w0)
+	add	%rax, X0
+	adc	$0, w0
+	add	w1, X1
+	mov	X1, -8(rp)
+	adc	$0, w3
+	mov	(up), %rdx
+	add	w2, X0
+	mulx(	v0, %rax, w1)
+	adc	$0, w0
+L(lo3):	add	%rax, X0
+	adc	$0, w1
+	mulx(	v1, %rax, w2)
+	add	w3, X0
+	mov	8(rp), X1
+	mov	X0, (rp)
+	mov	16(rp), X0
+	adc	$0, w1
+	add	%rax, X1
+	adc	$0, w2
+L(lo2):	mov	8(up), %rdx
+	lea	32(up), up
+	dec	n
+	jnz	L(top)
+
+L(end):	mulx(	v0, %rax, w3)
+	add	w0, X1
+	adc	$0, w2
+	add	%rax, X1
+	adc	$0, w3
+	mulx(	v1, %rdx, %rax)
+	add	w1, X1
+	mov	X1, 8(rp)
+	adc	$0, w3
+	add	w2, %rdx
+	adc	$0, %rax
+	add	w3, %rdx
+	mov	%rdx, 16(rp)
+	adc	$0, %rax
+
+	pop	%r13
+	pop	%r12
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/coreihwl/aorrlsh_n.asm b/third_party/gmp/mpn/x86_64/coreihwl/aorrlsh_n.asm
new file mode 100644
index 0000000..ff0d27b
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreihwl/aorrlsh_n.asm
@@ -0,0 +1,38 @@
+dnl  X86-64 mpn_addlsh_n and mpn_rsblsh_n.
+
+dnl  Copyright 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_addlsh_n mpn_rsblsh_n)
+include_mpn(`x86_64/zen/aorrlsh_n.asm')
diff --git a/third_party/gmp/mpn/x86_64/coreihwl/aors_n.asm b/third_party/gmp/mpn/x86_64/coreihwl/aors_n.asm
new file mode 100644
index 0000000..fc99627
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreihwl/aors_n.asm
@@ -0,0 +1,261 @@
+dnl  AMD64 mpn_add_n, mpn_sub_n
+
+dnl  Copyright 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9
+C AMD K10
+C AMD bd1	 1.5  with fluctuations
+C AMD bd2	 1.5  with fluctuations
+C AMD bd3
+C AMD bd4	 1.6
+C AMD zen
+C AMD bt1
+C AMD bt2
+C Intel P4
+C Intel PNR
+C Intel NHM
+C Intel SBR
+C Intel IBR
+C Intel HWL	 1.21
+C Intel BWL	 1.04
+C Intel SKL
+C Intel atom
+C Intel SLM
+C VIA nano
+
+C The loop of this code is the result of running a code generation and
+C optimization tool suite written by David Harvey and Torbjorn Granlund.
+
+C INPUT PARAMETERS
+define(`rp',	`%rdi')	C rcx
+define(`up',	`%rsi')	C rdx
+define(`vp',	`%rdx')	C r8
+define(`n',	`%rcx')	C r9
+define(`cy',	`%r8')	C rsp+40    (mpn_add_nc and mpn_sub_nc)
+
+ifdef(`OPERATION_add_n', `
+	define(ADCSBB,	      adc)
+	define(func,	      mpn_add_n)
+	define(func_nc,	      mpn_add_nc)')
+ifdef(`OPERATION_sub_n', `
+	define(ADCSBB,	      sbb)
+	define(func,	      mpn_sub_n)
+	define(func_nc,	      mpn_sub_nc)')
+
+MULFUNC_PROLOGUE(mpn_add_n mpn_add_nc mpn_sub_n mpn_sub_nc)
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(func_nc)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8	')
+
+	mov	R32(n), R32(%rax)
+	shr	$3, n
+	and	$7, R32(%rax)
+
+	lea	L(tab)(%rip), %r9
+	neg	%r8			C set carry
+ifdef(`PIC',`
+	movslq	(%r9,%rax,4), %rax
+	lea	(%r9,%rax), %rax	C lea not add to preserve carry
+	jmp	*%rax
+',`
+	jmp	*(%r9,%rax,8)
+')
+EPILOGUE()
+
+	ALIGN(16)
+PROLOGUE(func)
+	FUNC_ENTRY(4)
+
+	mov	R32(n), R32(%rax)
+	shr	$3, n
+	and	$7, R32(%rax)		C clear cy as side-effect
+
+	lea	L(tab)(%rip), %r9
+ifdef(`PIC',`
+	movslq	(%r9,%rax,4), %rax
+	lea	(%r9,%rax), %rax	C lea not add to preserve carry
+	jmp	*%rax
+',`
+	jmp	*(%r9,%rax,8)
+')
+
+L(0):	mov	(up), %r8
+	mov	8(up), %r9
+	ADCSBB	(vp), %r8
+	jmp	L(e0)
+
+L(4):	mov	(up), %r8
+	mov	8(up), %r9
+	ADCSBB	(vp), %r8
+	lea	-32(up), up
+	lea	-32(vp), vp
+	lea	-32(rp), rp
+	inc	n
+	jmp	L(e4)
+
+L(5):	mov	(up), %r11
+	mov	8(up), %r8
+	mov	16(up), %r9
+	ADCSBB	(vp), %r11
+	lea	-24(up), up
+	lea	-24(vp), vp
+	lea	-24(rp), rp
+	inc	n
+	jmp	L(e5)
+
+L(6):	mov	(up), %r10
+	ADCSBB	(vp), %r10
+	mov	8(up), %r11
+	lea	-16(up), up
+	lea	-16(vp), vp
+	lea	-16(rp), rp
+	inc	n
+	jmp	L(e6)
+
+L(7):	mov	(up), %r9
+	mov	8(up), %r10
+	ADCSBB	(vp), %r9
+	ADCSBB	8(vp), %r10
+	lea	-8(up), up
+	lea	-8(vp), vp
+	lea	-8(rp), rp
+	inc	n
+	jmp	L(e7)
+
+	ALIGN(16)
+L(top):
+L(e3):	mov	%r9, 40(rp)
+L(e2):	mov	%r10, 48(rp)
+L(e1):	mov	(up), %r8
+	mov	8(up), %r9
+	ADCSBB	(vp), %r8
+	mov	%r11, 56(rp)
+	lea	64(rp), rp
+L(e0):	mov	16(up), %r10
+	ADCSBB	8(vp), %r9
+	ADCSBB	16(vp), %r10
+	mov	%r8, (rp)
+L(e7):	mov	24(up), %r11
+	mov	%r9, 8(rp)
+L(e6):	mov	32(up), %r8
+	mov	40(up), %r9
+	ADCSBB	24(vp), %r11
+	mov	%r10, 16(rp)
+L(e5):	ADCSBB	32(vp), %r8
+	mov	%r11, 24(rp)
+L(e4):	mov	48(up), %r10
+	mov	56(up), %r11
+	mov	%r8, 32(rp)
+	lea	64(up), up
+	ADCSBB	40(vp), %r9
+	ADCSBB	48(vp), %r10
+	ADCSBB	56(vp), %r11
+	lea	64(vp), vp
+	dec	n
+	jnz	L(top)
+
+L(end):	mov	%r9, 40(rp)
+	mov	%r10, 48(rp)
+	mov	%r11, 56(rp)
+	mov	R32(n), R32(%rax)
+	adc	R32(n), R32(%rax)
+	FUNC_EXIT()
+	ret
+
+	ALIGN(16)
+L(3):	mov	(up), %r9
+	mov	8(up), %r10
+	mov	16(up), %r11
+	ADCSBB	(vp), %r9
+	ADCSBB	8(vp), %r10
+	ADCSBB	16(vp), %r11
+	jrcxz	L(x3)
+	lea	24(up), up
+	lea	24(vp), vp
+	lea	-40(rp), rp
+	jmp	L(e3)
+L(x3):	mov	%r9, (rp)
+	mov	%r10, 8(rp)
+	mov	%r11, 16(rp)
+	mov	R32(n), R32(%rax)
+	adc	R32(n), R32(%rax)
+	FUNC_EXIT()
+	ret
+
+	ALIGN(16)
+L(1):	mov	(up), %r11
+	ADCSBB	(vp), %r11
+	jrcxz	L(x1)
+	lea	8(up), up
+	lea	8(vp), vp
+	lea	-56(rp), rp
+	jmp	L(e1)
+L(x1):	mov	%r11, (rp)
+	mov	R32(n), R32(%rax)
+	adc	R32(n), R32(%rax)
+	FUNC_EXIT()
+	ret
+
+	ALIGN(16)
+L(2):	mov	(up), %r10
+	mov	8(up), %r11
+	ADCSBB	(vp), %r10
+	ADCSBB	8(vp), %r11
+	jrcxz	L(x2)
+	lea	16(up), up
+	lea	16(vp), vp
+	lea	-48(rp), rp
+	jmp	L(e2)
+L(x2):	mov	%r10, (rp)
+	mov	%r11, 8(rp)
+	mov	R32(n), R32(%rax)
+	adc	R32(n), R32(%rax)
+	FUNC_EXIT()
+	ret
+EPILOGUE()
+	JUMPTABSECT
+	ALIGN(8)
+L(tab):	JMPENT(	L(0), L(tab))
+	JMPENT(	L(1), L(tab))
+	JMPENT(	L(2), L(tab))
+	JMPENT(	L(3), L(tab))
+	JMPENT(	L(4), L(tab))
+	JMPENT(	L(5), L(tab))
+	JMPENT(	L(6), L(tab))
+	JMPENT(	L(7), L(tab))
diff --git a/third_party/gmp/mpn/x86_64/coreihwl/aorsmul_1.asm b/third_party/gmp/mpn/x86_64/coreihwl/aorsmul_1.asm
new file mode 100644
index 0000000..3f43afa
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreihwl/aorsmul_1.asm
@@ -0,0 +1,201 @@
+dnl  AMD64 mpn_addmul_1 and mpn_submul_1 optimised for Intel Haswell.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 -
+C AMD K10	 -
+C AMD bull	 -
+C AMD pile	 -
+C AMD steam	 -
+C AMD excavator	 -
+C AMD bobcat	 -
+C AMD jaguar	 -
+C Intel P4	 -
+C Intel core2	 -
+C Intel NHM	 -
+C Intel SBR	 -
+C Intel IBR	 -
+C Intel HWL	 2.32
+C Intel BWL	 2.04
+C Intel SKL	 1.95
+C Intel atom	 -
+C Intel SLM	 -
+C VIA nano	 -
+
+C The loop of this code is the result of running a code generation and
+C optimisation tool suite written by David Harvey and Torbjörn Granlund.
+
+C TODO
+C  * Handle small n separately, for lower overhead.
+
+define(`rp',      `%rdi')   C rcx
+define(`up',      `%rsi')   C rdx
+define(`n_param', `%rdx')   C r8
+define(`v0_param',`%rcx')   C r9
+
+define(`n',       `%rbp')
+define(`v0',      `%rdx')
+
+ifdef(`OPERATION_addmul_1',`
+  define(`ADDSUB',        `add')
+  define(`ADCSBB',        `adc')
+  define(`func',  `mpn_addmul_1')
+')
+ifdef(`OPERATION_submul_1',`
+  define(`ADDSUB',        `sub')
+  define(`ADCSBB',        `sbb')
+  define(`func',  `mpn_submul_1')
+')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_addmul_1 mpn_submul_1)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(func)
+	FUNC_ENTRY(4)
+	push	%rbx
+	push	%rbp
+	push	%r12
+	push	%r13
+
+	mov	n_param, n
+	mov	v0_param, v0
+
+	test	$1, R8(n)
+	jnz	L(bx1)
+
+L(bx0):	shr	$2, n
+	jc	L(b10)
+
+L(b00):	mulx(	(up), %r13, %r12)
+	mulx(	8,(up), %rbx, %rax)
+	add	%r12, %rbx
+	adc	$0, %rax
+	mov	(rp), %r12
+	mov	8(rp), %rcx
+	mulx(	16,(up), %r9, %r8)
+	lea	-16(rp), rp
+	lea	16(up), up
+	ADDSUB	%r13, %r12
+	jmp	L(lo0)
+
+L(bx1):	shr	$2, n
+	jc	L(b11)
+
+L(b01):	mulx(	(up), %r11, %r10)
+	jnz	L(gt1)
+L(n1):	ADDSUB	%r11, (rp)
+	mov	$0, R32(%rax)
+	adc	%r10, %rax
+	jmp	L(ret)
+
+L(gt1):	mulx(	8,(up), %r13, %r12)
+	mulx(	16,(up), %rbx, %rax)
+	lea	24(up), up
+	add	%r10, %r13
+	adc	%r12, %rbx
+	adc	$0, %rax
+	mov	(rp), %r10
+	mov	8(rp), %r12
+	mov	16(rp), %rcx
+	lea	-8(rp), rp
+	ADDSUB	%r11, %r10
+	jmp	L(lo1)
+
+L(b11):	mulx(	(up), %rbx, %rax)
+	mov	(rp), %rcx
+	mulx(	8,(up), %r9, %r8)
+	lea	8(up), up
+	lea	-24(rp), rp
+	inc	n			C adjust n
+	ADDSUB	%rbx, %rcx
+	jmp	L(lo3)
+
+L(b10):	mulx(	(up), %r9, %r8)
+	mulx(	8,(up), %r11, %r10)
+	lea	-32(rp), rp
+	mov	$0, R32(%rax)
+	clc				C clear cf
+	jz	L(end)			C depends on old shift
+
+	ALIGN(16)
+L(top):	adc	%rax, %r9
+	lea	32(rp), rp
+	adc	%r8, %r11
+	mulx(	16,(up), %r13, %r12)
+	mov	(rp), %r8
+	mulx(	24,(up), %rbx, %rax)
+	lea	32(up), up
+	adc	%r10, %r13
+	adc	%r12, %rbx
+	adc	$0, %rax
+	mov	8(rp), %r10
+	mov	16(rp), %r12
+	ADDSUB	%r9, %r8
+	mov	24(rp), %rcx
+	mov	%r8, (rp)
+	ADCSBB	%r11, %r10
+L(lo1):	mulx(	(up), %r9, %r8)
+	mov	%r10, 8(rp)
+	ADCSBB	%r13, %r12
+L(lo0):	mov	%r12, 16(rp)
+	ADCSBB	%rbx, %rcx
+L(lo3):	mulx(	8,(up), %r11, %r10)
+	mov	%rcx, 24(rp)
+	dec	n
+	jnz	L(top)
+
+L(end):	adc	%rax, %r9
+	adc	%r8, %r11
+	mov	32(rp), %r8
+	mov	%r10, %rax
+	adc	$0, %rax
+	mov	40(rp), %r10
+	ADDSUB	%r9, %r8
+	mov	%r8, 32(rp)
+	ADCSBB	%r11, %r10
+	mov	%r10, 40(rp)
+	adc	$0, %rax
+
+L(ret):	pop	%r13
+	pop	%r12
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/coreihwl/gcd_22.asm b/third_party/gmp/mpn/x86_64/coreihwl/gcd_22.asm
new file mode 100644
index 0000000..b5863b6
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreihwl/gcd_22.asm
@@ -0,0 +1,138 @@
+dnl  AMD64 mpn_gcd_22.  Assumes useless bsf, useless shrd, useful tzcnt, shlx.
+
+dnl  Copyright 2019 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C	     cycles/bit
+C AMD K8,K9	 -
+C AMD K10	 -
+C AMD bd1	 -
+C AMD bd2	 -
+C AMD bd3	 -
+C AMD bd4	 6.7
+C AMD bt1	 -
+C AMD bt2	 -
+C AMD zn1	 5.4
+C AMD zn2	 5.5
+C Intel P4	 -
+C Intel CNR	 -
+C Intel PNR	 -
+C Intel NHM	 -
+C Intel WSM	 -
+C Intel SBR	 -
+C Intel IBR	 -
+C Intel HWL	 7.1
+C Intel BWL	 5.5
+C Intel SKL	 5.6
+C Intel atom	 -
+C Intel SLM	 -
+C Intel GLM	 -
+C Intel GLM+	 -
+C VIA nano	 -
+
+
+define(`u1',    `%rdi')
+define(`u0',    `%rsi')
+define(`v1',    `%rdx')
+define(`v0',    `%rcx')
+
+define(`s0',    `%r8')
+define(`s1',    `%r9')
+define(`t0',    `%r10')
+define(`t1',    `%r11')
+define(`cnt',   `%rax')
+
+dnl ABI_SUPPORT(DOS64)	C returns mp_double_limb_t in memory
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(64)
+PROLOGUE(mpn_gcd_22)
+	FUNC_ENTRY(4)
+
+	ALIGN(16)
+L(top):	mov	v0, t0
+	sub	u0, t0
+	jz	L(lowz)		C	jump when low limb result = 0
+	mov	v1, t1
+	sbb	u1, t1
+
+	rep;bsf	t0, cnt		C tzcnt!
+
+	mov	u0, s0
+	sub	v0, u0
+	mov	u1, s1
+	sbb	v1, u1
+
+L(bck):	cmovc	t0, u0		C u = |u - v|
+	cmovc	t1, u1		C u = |u - v|
+	cmovc	s0, v0		C v = min(u,v)
+	cmovc	s1, v1		C v = min(u,v)
+
+	xor	R32(t0), R32(t0)
+	sub	cnt, t0
+	shlx(	t0, u1, s1)
+	shrx(	cnt, u0, u0)
+	shrx(	cnt, u1, u1)
+	or	s1, u0
+
+	test	v1, v1
+	jnz	L(top)
+	test	u1, u1
+	jnz	L(top)
+
+L(gcd_11):
+	mov	v0, %rdi
+C	mov	u0, %rsi
+	TCALL(	mpn_gcd_11)
+
+L(lowz):C We come here when v0 - u0 = 0
+	C 1. If v1 - u1 = 0, then gcd is u = v.
+	C 2. Else compute gcd_21({v1,v0}, |u1-v1|)
+	mov	v1, t0
+	sub	u1, t0
+	je	L(end)
+
+	xor	t1, t1
+	mov	u0, s0
+	mov	u1, s1
+	rep;bsf	t0, cnt		C tzcnt!
+	mov	u1, u0
+	xor	u1, u1
+	sub	v1, u0
+	jmp	L(bck)
+
+L(end):	mov	v0, %rax
+	C mov	v1, %rdx
+L(ret):	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/coreihwl/gmp-mparam.h b/third_party/gmp/mpn/x86_64/coreihwl/gmp-mparam.h
new file mode 100644
index 0000000..c11aeec
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreihwl/gmp-mparam.h
@@ -0,0 +1,253 @@
+/* Haswell gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+/* 3600-4000 MHz Intel Xeon E3-1271v3 Haswell */
+/* FFT tuning limit = 467,964,359 */
+/* Generated by tuneup.c, 2019-10-18, gcc 8.3 */
+
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          4
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          3
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD         9
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        26
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD      9
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1_NORM_THRESHOLD              1
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD               9
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           25
+
+#define DIV_1_VS_MUL_1_PERCENT             427
+
+#define MUL_TOOM22_THRESHOLD                20
+#define MUL_TOOM33_THRESHOLD                74
+#define MUL_TOOM44_THRESHOLD               195
+#define MUL_TOOM6H_THRESHOLD               276
+#define MUL_TOOM8H_THRESHOLD               381
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD     120
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     139
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     128
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     129
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     170
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 32
+#define SQR_TOOM3_THRESHOLD                117
+#define SQR_TOOM4_THRESHOLD                315
+#define SQR_TOOM6_THRESHOLD                414
+#define SQR_TOOM8_THRESHOLD                  0  /* always */
+
+#define MULMID_TOOM42_THRESHOLD             42
+
+#define MULMOD_BNM1_THRESHOLD               13
+#define SQRMOD_BNM1_THRESHOLD               17
+
+#define MUL_FFT_MODF_THRESHOLD             376  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    376, 5}, {     21, 6}, {     11, 5}, {     23, 6}, \
+    {     21, 7}, {     11, 6}, {     25, 7}, {     13, 6}, \
+    {     27, 7}, {     21, 8}, {     11, 7}, {     25, 8}, \
+    {     13, 7}, {     28, 8}, {     15, 7}, {     31, 8}, \
+    {     17, 7}, {     35, 8}, {     21, 9}, {     11, 8}, \
+    {     27, 9}, {     15, 8}, {     35, 9}, {     19, 8}, \
+    {     41, 9}, {     23, 8}, {     49, 9}, {     27,10}, \
+    {     15, 9}, {     39,10}, {     23, 9}, {     51,11}, \
+    {     15,10}, {     31, 9}, {     71,10}, {     39, 9}, \
+    {     83,10}, {     47, 9}, {     95,11}, {     31,10}, \
+    {     79,11}, {     47,10}, {     95,12}, {     31,11}, \
+    {     63,10}, {    127, 9}, {    255,10}, {    135,11}, \
+    {     79,10}, {    167,11}, {     95,10}, {    191, 9}, \
+    {    383,11}, {    111,12}, {     63, 8}, {   1023,11}, \
+    {    143,10}, {    287, 9}, {    575,10}, {    303,11}, \
+    {    159,10}, {    319,12}, {     95,11}, {    191,10}, \
+    {    383,11}, {    207,13}, {     63,12}, {    127,11}, \
+    {    255,10}, {    543,11}, {    287,10}, {    575,11}, \
+    {    303,10}, {    607,12}, {    159,11}, {    319,10}, \
+    {    639,11}, {    335,10}, {    671,11}, {    351,10}, \
+    {    703,11}, {    367,10}, {    735,11}, {    383,10}, \
+    {    767,11}, {    415,10}, {    831,11}, {    447,10}, \
+    {    895,11}, {    479,13}, {    127,11}, {    543,10}, \
+    {   1087,12}, {    287,11}, {    607,10}, {   1215,12}, \
+    {    319,11}, {    671,12}, {    351,11}, {    735,13}, \
+    {    191,12}, {    383,11}, {    767,12}, {    415,11}, \
+    {    831,12}, {    447,11}, {    895,12}, {    479,11}, \
+    {    959,14}, {    127,12}, {    543,11}, {   1087,12}, \
+    {    607,11}, {   1215,10}, {   2431,12}, {    671,11}, \
+    {   1343,12}, {    703,11}, {   1407,12}, {    735,13}, \
+    {    383,12}, {    831,13}, {    447,12}, {    959,13}, \
+    {    511,12}, {   1087,11}, {   2175,13}, {    575,12}, \
+    {   1215,11}, {   2431,13}, {    639,12}, {   1343,13}, \
+    {    703,12}, {   1407,14}, {    383,13}, {    767,12}, \
+    {   1535,13}, {    831,12}, {   1727,13}, {    959,12}, \
+    {   1919,14}, {    511,13}, {   1023,12}, {   2047,13}, \
+    {   1087,12}, {   2175,13}, {   1215,14}, {    639,13}, \
+    {   1343,12}, {   2687,13}, {   1407,12}, {   2815,13}, \
+    {   1471,14}, {    767,13}, {   1599,12}, {   3199,13}, \
+    {   1727,14}, {    895,13}, {   1791,12}, {   3583,13}, \
+    {   1919,15}, {    511,14}, {   1023,13}, {   2175,14}, \
+    {   1151,13}, {   2431,12}, {   4863,14}, {   1279,13}, \
+    {   2687,14}, {   1407,13}, {   2815,15}, {    767,14}, \
+    {   1535,13}, {   3199,14}, {   1663,13}, {   3455,12}, \
+    {   6911,14}, {   1791,13}, {   3583,14}, {   1919,16}, \
+    {    511,15}, {   1023,14}, {   2175,13}, {   4351,14}, \
+    {   2431,13}, {   4863,15}, {   1279,14}, {   2943,13}, \
+    {   5887,12}, {  11775,15}, {   1535,14}, {   3455,13}, \
+    {   6911,15}, {   1791,14}, {   3839,13}, {   7679,16}, \
+    {   1023,15}, {   2047,14}, {   4351,15}, {   2303,14}, \
+    {   4863,15}, {   2815,14}, {   5887,13}, {  11775,16}, \
+    {   1535,15}, {   3327,14}, {   6911,15}, {   3839,14}, \
+    {   7679,17}, {   1023,16}, {   2047,15}, {   4863,16}, \
+    {   2559,15}, {   5887,14}, {  11775,16}, {   3071,15}, \
+    {   6911,16}, {   3583,15}, {   7679,14}, {  15359,15}, \
+    {   7935,17}, {   2047,16}, {   4095,15}, {   8447,16}, \
+    {   4607,15}, {   9983,14}, {  19967,16}, {   5631,15}, \
+    {  11775,17}, {   3071,16}, {  65536,17}, { 131072,18}, \
+    { 262144,19}, { 524288,20}, {1048576,21}, {2097152,22}, \
+    {4194304,23}, {8388608,24} }
+#define MUL_FFT_TABLE3_SIZE 238
+#define MUL_FFT_THRESHOLD                 4736
+
+#define SQR_FFT_MODF_THRESHOLD             368  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    368, 5}, {     21, 6}, {     11, 5}, {     23, 6}, \
+    {     25, 7}, {     13, 6}, {     27, 7}, {     21, 8}, \
+    {     11, 7}, {     25, 8}, {     13, 7}, {     28, 8}, \
+    {     15, 7}, {     31, 8}, {     21, 9}, {     11, 8}, \
+    {     27, 9}, {     15, 8}, {     33, 9}, {     19, 8}, \
+    {     41, 9}, {     23, 8}, {     47, 9}, {     27,10}, \
+    {     15, 9}, {     39,10}, {     23, 9}, {     51,11}, \
+    {     15,10}, {     31, 9}, {     67,10}, {     39, 9}, \
+    {     79,10}, {     55,11}, {     31,10}, {     79,11}, \
+    {     47,10}, {     95,12}, {     31,11}, {     63,10}, \
+    {    127, 9}, {    255,11}, {     79,10}, {    159, 9}, \
+    {    319,11}, {     95,10}, {    191,12}, {     63,11}, \
+    {    127,10}, {    255, 9}, {    511,10}, {    271,11}, \
+    {    143,10}, {    287, 9}, {    575,10}, {    303, 9}, \
+    {    607,11}, {    159,10}, {    319, 6}, {   5631, 7}, \
+    {   2943, 6}, {   5887, 8}, {   1535,11}, {    207,10}, \
+    {    415,11}, {    223,10}, {    447,11}, {    239,10}, \
+    {    479,12}, {    127,11}, {    255,10}, {    511,11}, \
+    {    271,10}, {    543,11}, {    287,10}, {    575,11}, \
+    {    303,10}, {    607,11}, {    319,10}, {    639,11}, \
+    {    335,10}, {    671,11}, {    351,10}, {    703,11}, \
+    {    367,10}, {    735,11}, {    383,10}, {    767,11}, \
+    {    415,10}, {    831,11}, {    447,10}, {    895,11}, \
+    {    479,13}, {    127,11}, {    511,10}, {   1023,11}, \
+    {    543,10}, {   1087,12}, {    287,11}, {    607,10}, \
+    {   1215,11}, {    671,12}, {    351,11}, {    735,12}, \
+    {    383,11}, {    767,12}, {    415,11}, {    831,12}, \
+    {    447,11}, {    895,12}, {    479,11}, {    959,14}, \
+    {    127,12}, {    511,11}, {   1023,12}, {    543,11}, \
+    {   1087,12}, {    607,11}, {   1215,12}, {    735,13}, \
+    {    383,12}, {    831,13}, {    447,12}, {    959,13}, \
+    {    511,12}, {   1087,13}, {    575,12}, {   1151,13}, \
+    {    639,12}, {   1279,13}, {    703,12}, {   1407,11}, \
+    {   2815,14}, {    383,13}, {    767,12}, {   1535,13}, \
+    {    831,12}, {   1727,11}, {   3455,13}, {    959,14}, \
+    {    511,13}, {   1087,12}, {   2175,13}, {   1215,14}, \
+    {    639,13}, {   1279,12}, {   2559,13}, {   1343,12}, \
+    {   2687,13}, {   1407,12}, {   2815,13}, {   1471,14}, \
+    {    767,13}, {   1599,12}, {   3199,13}, {   1727,14}, \
+    {    895,13}, {   1791,12}, {   3583,13}, {   1919,15}, \
+    {    511,14}, {   1023,13}, {   2175,14}, {   1151,13}, \
+    {   2303,12}, {   4607,13}, {   2431,12}, {   4863,14}, \
+    {   1279,13}, {   2687,14}, {   1407,13}, {   2815,15}, \
+    {    767,14}, {   1535,13}, {   3199,14}, {   1663,13}, \
+    {   3455,12}, {   6911,14}, {   1791,13}, {   3583,14}, \
+    {   1919,16}, {    511,15}, {   1023,14}, {   2431,13}, \
+    {   4863,15}, {   1279,14}, {   2943,13}, {   5887,15}, \
+    {   1535,14}, {   3455,13}, {   6911,15}, {   1791,14}, \
+    {   3839,13}, {   7679,16}, {   1023,15}, {   2047,14}, \
+    {   4351,15}, {   2303,14}, {   4863,15}, {   2815,14}, \
+    {   5887,16}, {   1535,15}, {   3071,14}, {   6143,15}, \
+    {   3327,14}, {   6911,15}, {   3839,14}, {   7679,17}, \
+    {   1023,16}, {   2047,15}, {   4863,16}, {   2559,15}, \
+    {   5887,14}, {  11775,16}, {   3071,15}, {   6911,16}, \
+    {   3583,15}, {   7679,14}, {  15359,15}, {   7935,17}, \
+    {   2047,16}, {   4095,15}, {   8191,16}, {   4607,15}, \
+    {   9983,14}, {  19967,16}, {   5631,15}, {  11775,17}, \
+    {   3071,16}, {  65536,17}, { 131072,18}, { 262144,19}, \
+    { 524288,20}, {1048576,21}, {2097152,22}, {4194304,23}, \
+    {8388608,24} }
+#define SQR_FFT_TABLE3_SIZE 237
+#define SQR_FFT_THRESHOLD                 3264
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  68
+#define MULLO_MUL_N_THRESHOLD             8967
+#define SQRLO_BASECASE_THRESHOLD            11
+#define SQRLO_DC_THRESHOLD                  80
+#define SQRLO_SQR_THRESHOLD               6481
+
+#define DC_DIV_QR_THRESHOLD                 58
+#define DC_DIVAPPR_Q_THRESHOLD             182
+#define DC_BDIV_QR_THRESHOLD                60
+#define DC_BDIV_Q_THRESHOLD                123
+
+#define INV_MULMOD_BNM1_THRESHOLD           38
+#define INV_NEWTON_THRESHOLD               179
+#define INV_APPR_THRESHOLD                 182
+
+#define BINV_NEWTON_THRESHOLD              230
+#define REDC_1_TO_REDC_2_THRESHOLD          48
+#define REDC_2_TO_REDC_N_THRESHOLD          63
+
+#define MU_DIV_QR_THRESHOLD               1470
+#define MU_DIVAPPR_Q_THRESHOLD            1528
+#define MUPI_DIV_QR_THRESHOLD               82
+#define MU_BDIV_QR_THRESHOLD              1334
+#define MU_BDIV_Q_THRESHOLD               1506
+
+#define POWM_SEC_TABLE  1,22,194,473,1297,2698
+
+#define GET_STR_DC_THRESHOLD                12
+#define GET_STR_PRECOMPUTE_THRESHOLD        19
+#define SET_STR_DC_THRESHOLD              1391
+#define SET_STR_PRECOMPUTE_THRESHOLD      2654
+
+#define FAC_DSC_THRESHOLD                  562
+#define FAC_ODD_THRESHOLD                    0  /* always */
+
+#define MATRIX22_STRASSEN_THRESHOLD         15
+#define HGCD2_DIV1_METHOD                    5  /* 3.49% faster than 3 */
+#define HGCD_THRESHOLD                      96
+#define HGCD_APPR_THRESHOLD                 92
+#define HGCD_REDUCE_THRESHOLD             2681
+#define GCD_DC_THRESHOLD                   501
+#define GCDEXT_DC_THRESHOLD                365
+#define JACOBI_BASE_METHOD                   1  /* 23.87% faster than 4 */
+
+/* Tuneup completed successfully, took 238360 seconds */
diff --git a/third_party/gmp/mpn/x86_64/coreihwl/mul_1.asm b/third_party/gmp/mpn/x86_64/coreihwl/mul_1.asm
new file mode 100644
index 0000000..5e649e8
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreihwl/mul_1.asm
@@ -0,0 +1,159 @@
+dnl  AMD64 mpn_mul_1 using mulx optimised for Intel Haswell.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2012, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9      -
+C AMD K10        -
+C AMD bull       -
+C AMD pile       -
+C AMD steam      -
+C AMD excavator  -
+C AMD bobcat     -
+C AMD jaguar     -
+C Intel P4       -
+C Intel core2    -
+C Intel NHM      -
+C Intel SBR      -
+C Intel IBR      -
+C Intel HWL      1.59
+C Intel BWL      1.76
+C Intel SKL      1.54
+C Intel atom     -
+C Intel SLM      -
+C VIA nano       -
+
+C The loop of this code is the result of running a code generation and
+C optimisation tool suite written by David Harvey and Torbjorn Granlund.
+
+define(`rp',      `%rdi')   C rcx
+define(`up',      `%rsi')   C rdx
+define(`n_param', `%rdx')   C r8
+define(`v0_param',`%rcx')   C r9
+
+define(`n',       `%rbp')
+define(`v0',      `%rdx')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_mul_1)
+	FUNC_ENTRY(4)
+	push	%rbx
+	push	%rbp
+	push	%r12
+
+	mov	n_param, n
+	shr	$2, n
+
+	test	$1, R8(n_param)
+	jnz	L(bx1)
+
+L(bx0):	test	$2, R8(n_param)
+	mov	v0_param, v0
+	jnz	L(b10)
+
+L(b00):	mulx(	(up), %r9, %r8)
+	mulx(	8,(up), %r11, %r10)
+	mulx(	16,(up), %rcx, %r12)
+	lea	-32(rp), rp
+	jmp	L(lo0)
+
+L(b10):	mulx(	(up), %rcx, %r12)
+	mulx(	8,(up), %rbx, %rax)
+	lea	-16(rp), rp
+	test	n, n
+	jz	L(cj2)
+	mulx(	16,(up), %r9, %r8)
+	lea	16(up), up
+	jmp	L(lo2)
+
+L(bx1):	test	$2, R8(n_param)
+	mov	v0_param, v0
+	jnz	L(b11)
+
+L(b01):	mulx(	(up), %rbx, %rax)
+	lea	-24(rp), rp
+	test	n, n
+	jz	L(cj1)
+	mulx(	8,(up), %r9, %r8)
+	lea	8(up), up
+	jmp	L(lo1)
+
+L(b11):	mulx(	(up), %r11, %r10)
+	mulx(	8,(up), %rcx, %r12)
+	mulx(	16,(up), %rbx, %rax)
+	lea	-8(rp), rp
+	test	n, n
+	jz	L(cj3)
+	lea	24(up), up
+	jmp	L(lo3)
+
+	ALIGN(32)
+L(top):	lea	32(rp), rp
+	mov	%r9, (rp)
+	adc	%r8, %r11
+L(lo3):	mulx(	(up), %r9, %r8)
+	mov	%r11, 8(rp)
+	adc	%r10, %rcx
+L(lo2):	mov	%rcx, 16(rp)
+	adc	%r12, %rbx
+L(lo1):	mulx(	8,(up), %r11, %r10)
+	adc	%rax, %r9
+	mulx(	16,(up), %rcx, %r12)
+	mov	%rbx, 24(rp)
+L(lo0):	mulx(	24,(up), %rbx, %rax)
+	lea	32(up), up
+	dec	n
+	jnz	L(top)
+
+L(end):	lea	32(rp), rp
+	mov	%r9, (rp)
+	adc	%r8, %r11
+L(cj3):	mov	%r11, 8(rp)
+	adc	%r10, %rcx
+L(cj2):	mov	%rcx, 16(rp)
+	adc	%r12, %rbx
+L(cj1):	mov	%rbx, 24(rp)
+	adc	$0, %rax
+
+	pop	%r12
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86_64/coreihwl/mul_2.asm b/third_party/gmp/mpn/x86_64/coreihwl/mul_2.asm
new file mode 100644
index 0000000..f1f044f
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreihwl/mul_2.asm
@@ -0,0 +1,176 @@
+dnl  AMD64 mpn_mul_2 optimised for Intel Haswell.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 -
+C AMD K10	 -
+C AMD bull	 -
+C AMD pile	 -
+C AMD steam	 -
+C AMD excavator	 -
+C AMD bobcat	 -
+C AMD jaguar	 -
+C Intel P4	 -
+C Intel core	 -
+C Intel NHM	 -
+C Intel SBR	 -
+C Intel IBR	 -
+C Intel HWL      3.74
+C Intel BWL      4.21
+C Intel SKL      4.20
+C Intel atom	 -
+C Intel SLM	 -
+C VIA nano	 -
+
+C The loop of this code is the result of running a code generation and
+C optimisation tool suite written by David Harvey and Torbjörn Granlund.
+
+C TODO
+C  * Move test and jcc together, for insn fusion.
+
+define(`rp',     `%rdi')
+define(`up',     `%rsi')
+define(`n_param',`%rdx')
+define(`vp',     `%rcx')
+
+define(`v0', `%r8')
+define(`v1', `%r9')
+define(`w0', `%rbx')
+define(`w1', `%rcx')
+define(`w2', `%rbp')
+define(`w3', `%r10')
+define(`n',  `%r11')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_mul_2)
+	FUNC_ENTRY(4)
+	push	%rbx
+	push	%rbp
+
+	mov	(vp), v0
+	mov	8(vp), v1
+
+	lea	3(n_param), n
+	shr	$2, n
+
+	test	$1, R8(n_param)
+	jnz	L(bx1)
+
+L(bx0):	xor	w0, w0
+	test	$2, R8(n_param)
+	mov	(up), %rdx
+	mulx(	v0, w2, w1)
+	jz	L(lo0)
+
+L(b10):	lea	-16(rp), rp
+	lea	-16(up), up
+	jmp	L(lo2)
+
+L(bx1):	xor	w2, w2
+	test	$2, R8(n_param)
+	mov	(up), %rdx
+	mulx(	v0, w0, w3)
+	jnz	L(b11)
+
+L(b01):	lea	-24(rp), rp
+	lea	8(up), up
+	jmp	L(lo1)
+
+L(b11):	lea	-8(rp), rp
+	lea	-8(up), up
+	jmp	L(lo3)
+
+	ALIGN(16)
+L(top):	mulx(	v1, %rax, w0)
+	add	%rax, w2		C 0
+	mov	(up), %rdx
+	mulx(	v0, %rax, w1)
+	adc	$0, w0			C 1
+	add	%rax, w2		C 0
+	adc	$0, w1			C 1
+	add	w3, w2			C 0
+L(lo0):	mov	w2, (rp)		C 0
+	adc	$0, w1			C 1
+	mulx(	v1, %rax, w2)
+	add	%rax, w0		C 1
+	mov	8(up), %rdx
+	adc	$0, w2			C 2
+	mulx(	v0, %rax, w3)
+	add	%rax, w0		C 1
+	adc	$0, w3			C 2
+	add	w1, w0			C 1
+L(lo3):	mov	w0, 8(rp)		C 1
+	adc	$0, w3			C 2
+	mulx(	v1, %rax, w0)
+	add	%rax, w2		C 2
+	mov	16(up), %rdx
+	mulx(	v0, %rax, w1)
+	adc	$0, w0			C 3
+	add	%rax, w2		C 2
+	adc	$0, w1			C 3
+	add	w3, w2			C 2
+L(lo2):	mov	w2, 16(rp)		C 2
+	adc	$0, w1			C 3
+	mulx(	v1, %rax, w2)
+	add	%rax, w0		C 3
+	mov	24(up), %rdx
+	adc	$0, w2			C 4
+	mulx(	v0, %rax, w3)
+	add	%rax, w0		C 3
+	adc	$0, w3			C 4
+	add	w1, w0			C 3
+	lea	32(up), up
+L(lo1):	mov	w0, 24(rp)		C 3
+	adc	$0, w3			C 4
+	dec	n
+	lea	32(rp), rp
+	jnz	L(top)
+
+L(end):	mulx(	v1, %rdx, %rax)
+	add	%rdx, w2
+	adc	$0, %rax
+	add	w3, w2
+	mov	w2, (rp)
+	adc	$0, %rax
+
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/coreihwl/mul_basecase.asm b/third_party/gmp/mpn/x86_64/coreihwl/mul_basecase.asm
new file mode 100644
index 0000000..b2656c8
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreihwl/mul_basecase.asm
@@ -0,0 +1,441 @@
+dnl  AMD64 mpn_mul_basecase optimised for Intel Haswell.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2003-2005, 2007, 2008, 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C cycles/limb	mul_1		mul_2		mul_3		addmul_2
+C AMD K8,K9	n/a		n/a		 -		n/a
+C AMD K10	n/a		n/a		 -		n/a
+C AMD bull	n/a		n/a		 -		n/a
+C AMD pile	n/a		n/a		 -		n/a
+C AMD steam	 ?		 ?		 -		 ?
+C AMD bobcat	n/a		n/a		 -		n/a
+C AMD jaguar	 ?		 ?		 -		 ?
+C Intel P4	n/a		n/a		 -		n/a
+C Intel core	n/a		n/a		 -		n/a
+C Intel NHM	n/a		n/a		 -		n/a
+C Intel SBR	n/a		n/a		 -		n/a
+C Intel IBR	n/a		n/a		 -		n/a
+C Intel HWL	 1.77		 1.86		 -		 2.15
+C Intel BWL	 ?		 ?		 -		 ?
+C Intel atom	n/a		n/a		 -		n/a
+C VIA nano	n/a		n/a		 -		n/a
+
+C The inner loops of this code are the result of running a code generation and
+C optimisation tool suite written by David Harvey and Torbjörn Granlund.
+
+C TODO
+C  * Adjoin a mul_3.
+C  * Further micro-optimise.
+
+define(`rp',      `%rdi')
+define(`up',      `%rsi')
+define(`un_param',`%rdx')
+define(`vp',      `%rcx')
+define(`vn',      `%r8')
+
+define(`un',      `%rbx')
+
+define(`w0',	`%r10')
+define(`w1',	`%r11')
+define(`w2',	`%r12')
+define(`w3',	`%r13')
+define(`n',	`%rbp')
+define(`v0',	`%r9')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_mul_basecase)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8d	')
+	push	%rbx
+	push	%rbp
+	push	%r12
+	push	%r13
+	push	%r14
+	mov	un_param, un		C free up rdx
+	neg	un
+
+	mov	un_param, n		C FIXME: share
+	sar	$2, n			C FIXME: share
+
+	test	$1, R8(vn)
+	jz	L(do_mul_2)
+
+define(`w4',	`%r9')
+define(`w5',	`%r14')
+
+	mov	(vp), %rdx
+
+L(do_mul_1):
+	test	$1, R8(un)
+	jnz	L(m1x1)
+
+L(m1x0):test	$2, R8(un)
+	jnz	L(m110)
+
+L(m100):
+	mulx(	(up), w5, w2)
+	mulx(	8,(up), w1, w3)
+	lea	-24(rp), rp
+	jmp	L(m1l0)
+
+L(m110):
+	mulx(	(up), w3, w4)
+	mulx(	8,(up), w1, w5)
+	lea	-8(rp), rp
+	test	n, n
+	jz	L(cj2)
+	mulx(	16,(up), w0, w2)
+	lea	16(up), up
+	jmp	L(m1l2)
+
+L(m1x1):test	$2, R8(un)
+	jz	L(m111)
+
+L(m101):
+	mulx(	(up), w4, w5)
+	lea	-16(rp), rp
+	test	n, n
+	jz	L(cj1)
+	mulx(	8,(up), w0, w2)
+	lea	8(up), up
+	jmp	L(m1l1)
+
+L(m111):
+	mulx(	(up), w2, w3)
+	mulx(	8,(up), w0, w4)
+	mulx(	16,(up), w1, w5)
+	lea	24(up), up
+	test	n, n
+	jnz	L(gt3)
+	add	w0, w3
+	jmp	L(cj3)
+L(gt3):	add	w0, w3
+	jmp	L(m1l3)
+
+	ALIGN(32)
+L(m1tp):lea	32(rp), rp
+L(m1l3):mov	w2, (rp)
+	mulx(	(up), w0, w2)
+L(m1l2):mov	w3, 8(rp)
+	adc	w1, w4
+L(m1l1):adc	w0, w5
+	mov	w4, 16(rp)
+	mulx(	8,(up), w1, w3)
+L(m1l0):mov	w5, 24(rp)
+	mulx(	16,(up), w0, w4)
+	adc	w1, w2
+	mulx(	24,(up), w1, w5)
+	adc	w0, w3
+	lea	32(up), up
+	dec	n
+	jnz	L(m1tp)
+
+L(m1ed):lea	32(rp), rp
+L(cj3):	mov	w2, (rp)
+L(cj2):	mov	w3, 8(rp)
+	adc	w1, w4
+L(cj1):	mov	w4, 16(rp)
+	adc	$0, w5
+	mov	w5, 24(rp)
+
+	dec	R32(vn)
+	jz	L(ret5)
+
+	lea	8(vp), vp
+	lea	32(rp), rp
+C	push	%r12
+C	push	%r13
+C	push	%r14
+	jmp	L(do_addmul)
+
+L(do_mul_2):
+define(`v1',	`%r14')
+C	push	%r12
+C	push	%r13
+C	push	%r14
+
+	mov	(vp), v0
+	mov	8(vp), v1
+
+	lea	(un), n
+	sar	$2, n
+
+	test	$1, R8(un)
+	jnz	L(m2x1)
+
+L(m2x0):xor	w0, w0
+	test	$2, R8(un)
+	mov	(up), %rdx
+	mulx(	v0, w2, w1)
+	jz	L(m2l0)
+
+L(m210):lea	-16(rp), rp
+	lea	-16(up), up
+	jmp	L(m2l2)
+
+L(m2x1):xor	w2, w2
+	test	$2, R8(un)
+	mov	(up), %rdx
+	mulx(	v0, w0, w3)
+	jz	L(m211)
+
+L(m201):lea	-24(rp), rp
+	lea	8(up), up
+	jmp	L(m2l1)
+
+L(m211):lea	-8(rp), rp
+	lea	-8(up), up
+	jmp	L(m2l3)
+
+	ALIGN(16)
+L(m2tp):mulx(	v1, %rax, w0)
+	add	%rax, w2
+	mov	(up), %rdx
+	mulx(	v0, %rax, w1)
+	adc	$0, w0
+	add	%rax, w2
+	adc	$0, w1
+	add	w3, w2
+L(m2l0):mov	w2, (rp)
+	adc	$0, w1
+	mulx(	v1, %rax, w2)
+	add	%rax, w0
+	mov	8(up), %rdx
+	adc	$0, w2
+	mulx(	v0, %rax, w3)
+	add	%rax, w0
+	adc	$0, w3
+	add	w1, w0
+L(m2l3):mov	w0, 8(rp)
+	adc	$0, w3
+	mulx(	v1, %rax, w0)
+	add	%rax, w2
+	mov	16(up), %rdx
+	mulx(	v0, %rax, w1)
+	adc	$0, w0
+	add	%rax, w2
+	adc	$0, w1
+	add	w3, w2
+L(m2l2):mov	w2, 16(rp)
+	adc	$0, w1
+	mulx(	v1, %rax, w2)
+	add	%rax, w0
+	mov	24(up), %rdx
+	adc	$0, w2
+	mulx(	v0, %rax, w3)
+	add	%rax, w0
+	adc	$0, w3
+	add	w1, w0
+	lea	32(up), up
+L(m2l1):mov	w0, 24(rp)
+	adc	$0, w3
+	inc	n
+	lea	32(rp), rp
+	jnz	L(m2tp)
+
+L(m2ed):mulx(	v1, %rdx, %rax)
+	add	%rdx, w2
+	adc	$0, %rax
+	add	w3, w2
+	mov	w2, (rp)
+	adc	$0, %rax
+	mov	%rax, 8(rp)
+
+	add	$-2, R32(vn)
+	jz	L(ret5)
+	lea	16(vp), vp
+	lea	16(rp), rp
+
+
+L(do_addmul):
+	push	%r15
+	push	vn			C save vn in new stack slot
+define(`vn',	`(%rsp)')
+define(`X0',	`%r14')
+define(`X1',	`%r15')
+define(`v1',	`%r8')
+
+	lea	(rp,un,8), rp
+	lea	(up,un,8), up
+
+L(outer):
+	mov	(vp), v0
+	mov	8(vp), v1
+
+	lea	2(un), n
+	sar	$2, n
+
+	mov	(up), %rdx
+	test	$1, R8(un)
+	jnz	L(bx1)
+
+L(bx0):	mov	(rp), X0
+	mov	8(rp), X1
+	mulx(	v0, %rax, w1)
+	add	%rax, X0
+	mulx(	v1, %rax, w2)
+	adc	$0, w1
+	mov	X0, (rp)
+	add	%rax, X1
+	adc	$0, w2
+	mov	8(up), %rdx
+	test	$2, R8(un)
+	jnz	L(b10)
+
+L(b00):	lea	16(up), up
+	lea	16(rp), rp
+	jmp	L(lo0)
+
+L(b10):	mov	16(rp), X0
+	lea	32(up), up
+	mulx(	v0, %rax, w3)
+	jmp	L(lo2)
+
+L(bx1):	mov	(rp), X1
+	mov	8(rp), X0
+	mulx(	v0, %rax, w3)
+	add	%rax, X1
+	adc	$0, w3
+	mulx(	v1, %rax, w0)
+	add	%rax, X0
+	adc	$0, w0
+	mov	8(up), %rdx
+	mov	X1, (rp)
+	mulx(	v0, %rax, w1)
+	test	$2, R8(un)
+	jz	L(b11)
+
+L(b01):	mov	16(rp), X1
+	lea	24(rp), rp
+	lea	24(up), up
+	jmp	L(lo1)
+
+L(b11):	lea	8(rp), rp
+	lea	8(up), up
+	jmp	L(lo3)
+
+	ALIGN(16)
+L(top):	mulx(	v0, %rax, w3)
+	add	w0, X1
+	adc	$0, w2
+L(lo2):	add	%rax, X1
+	adc	$0, w3
+	mulx(	v1, %rax, w0)
+	add	%rax, X0
+	adc	$0, w0
+	lea	32(rp), rp
+	add	w1, X1
+	mov	-16(up), %rdx
+	mov	X1, -24(rp)
+	adc	$0, w3
+	add	w2, X0
+	mov	-8(rp), X1
+	mulx(	v0, %rax, w1)
+	adc	$0, w0
+L(lo1):	add	%rax, X0
+	mulx(	v1, %rax, w2)
+	adc	$0, w1
+	add	w3, X0
+	mov	X0, -16(rp)
+	adc	$0, w1
+	add	%rax, X1
+	adc	$0, w2
+	add	w0, X1
+	mov	-8(up), %rdx
+	adc	$0, w2
+L(lo0):	mulx(	v0, %rax, w3)
+	add	%rax, X1
+	adc	$0, w3
+	mov	(rp), X0
+	mulx(	v1, %rax, w0)
+	add	%rax, X0
+	adc	$0, w0
+	add	w1, X1
+	mov	X1, -8(rp)
+	adc	$0, w3
+	mov	(up), %rdx
+	add	w2, X0
+	mulx(	v0, %rax, w1)
+	adc	$0, w0
+L(lo3):	add	%rax, X0
+	adc	$0, w1
+	mulx(	v1, %rax, w2)
+	add	w3, X0
+	mov	8(rp), X1
+	mov	X0, (rp)
+	mov	16(rp), X0
+	adc	$0, w1
+	add	%rax, X1
+	adc	$0, w2
+	mov	8(up), %rdx
+	lea	32(up), up
+	inc	n
+	jnz	L(top)
+
+L(end):	mulx(	v0, %rax, w3)
+	add	w0, X1
+	adc	$0, w2
+	add	%rax, X1
+	adc	$0, w3
+	mulx(	v1, %rdx, %rax)
+	add	w1, X1
+	mov	X1, 8(rp)
+	adc	$0, w3
+	add	w2, %rdx
+	adc	$0, %rax
+	add	w3, %rdx
+	mov	%rdx, 16(rp)
+	adc	$0, %rax
+	mov	%rax, 24(rp)
+
+	addl	$-2, vn
+	lea	16(vp), vp
+	lea	-16(up,un,8), up
+	lea	32(rp,un,8), rp
+	jnz	L(outer)
+
+	pop	%rax		C deallocate vn slot
+	pop	%r15
+L(ret5):pop	%r14
+L(ret4):pop	%r13
+L(ret3):pop	%r12
+L(ret2):pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/coreihwl/mullo_basecase.asm b/third_party/gmp/mpn/x86_64/coreihwl/mullo_basecase.asm
new file mode 100644
index 0000000..e65559b
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreihwl/mullo_basecase.asm
@@ -0,0 +1,422 @@
+dnl  AMD64 mpn_mullo_basecase optimised for Intel Haswell.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2008, 2009, 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C cycles/limb	mul_2		addmul_2
+C AMD K8,K9	n/a		n/a
+C AMD K10	n/a		n/a
+C AMD bull	n/a		n/a
+C AMD pile	n/a		n/a
+C AMD steam	 ?		 ?
+C AMD bobcat	n/a		n/a
+C AMD jaguar	 ?		 ?
+C Intel P4	n/a		n/a
+C Intel core	n/a		n/a
+C Intel NHM	n/a		n/a
+C Intel SBR	n/a		n/a
+C Intel IBR	n/a		n/a
+C Intel HWL	 1.86		 2.15
+C Intel BWL	 ?		 ?
+C Intel atom	n/a		n/a
+C VIA nano	n/a		n/a
+
+C The inner loops of this code are the result of running a code generation and
+C optimisation tool suite written by David Harvey and Torbjörn Granlund.
+
+C TODO
+C   * Implement proper cor2, replacing current cor0.
+C   * Micro-optimise.
+
+define(`rp',       `%rdi')
+define(`up',       `%rsi')
+define(`vp_param', `%rdx')
+define(`n',        `%rcx')
+
+define(`vp',       `%r8')
+define(`X0',       `%r14')
+define(`X1',       `%r15')
+
+define(`w0',       `%r10')
+define(`w1',       `%r11')
+define(`w2',       `%r12')
+define(`w3',       `%r13')
+define(`i',        `%rbp')
+define(`v0',       `%r9')
+define(`v1',       `%rbx')
+
+C rax rbx rcx rdx rdi rsi rbp r8 r9 r10 r11 r12 r13 r14 r15
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_mullo_basecase)
+	FUNC_ENTRY(4)
+
+	mov	vp_param, vp
+	mov	(up), %rdx
+
+	cmp	$4, n
+	jb	L(small)
+
+	push	%rbx
+	push	%rbp
+	push	%r12
+	push	%r13
+
+	mov	(vp), v0
+	mov	8(vp), v1
+
+	lea	2(n), i
+	shr	$2, i
+	neg	n
+	add	$2, n
+
+	push	up			C put entry `up' on stack
+
+	test	$1, R8(n)
+	jnz	L(m2x1)
+
+L(m2x0):mulx(	v0, w0, w3)
+	xor	R32(w2), R32(w2)
+	test	$2, R8(n)
+	jz	L(m2b2)
+
+L(m2b0):lea	-8(rp), rp
+	lea	-8(up), up
+	jmp	L(m2e0)
+
+L(m2b2):lea	-24(rp), rp
+	lea	8(up), up
+	jmp	L(m2e2)
+
+L(m2x1):mulx(	v0, w2, w1)
+	xor	R32(w0), R32(w0)
+	test	$2, R8(n)
+	jnz	L(m2b3)
+
+L(m2b1):jmp	L(m2e1)
+
+L(m2b3):lea	-16(rp), rp
+	lea	-16(up), up
+	jmp	L(m2e3)
+
+	ALIGN(16)
+L(m2tp):mulx(	v1, %rax, w0)
+	add	%rax, w2
+	mov	(up), %rdx
+	mulx(	v0, %rax, w1)
+	adc	$0, w0
+	add	%rax, w2
+	adc	$0, w1
+	add	w3, w2
+L(m2e1):mov	w2, (rp)
+	adc	$0, w1
+	mulx(	v1, %rax, w2)
+	add	%rax, w0
+	mov	8(up), %rdx
+	adc	$0, w2
+	mulx(	v0, %rax, w3)
+	add	%rax, w0
+	adc	$0, w3
+	add	w1, w0
+L(m2e0):mov	w0, 8(rp)
+	adc	$0, w3
+	mulx(	v1, %rax, w0)
+	add	%rax, w2
+	mov	16(up), %rdx
+	mulx(	v0, %rax, w1)
+	adc	$0, w0
+	add	%rax, w2
+	adc	$0, w1
+	add	w3, w2
+L(m2e3):mov	w2, 16(rp)
+	adc	$0, w1
+	mulx(	v1, %rax, w2)
+	add	%rax, w0
+	mov	24(up), %rdx
+	adc	$0, w2
+	mulx(	v0, %rax, w3)
+	add	%rax, w0
+	adc	$0, w3
+	add	w1, w0
+	lea	32(up), up
+L(m2e2):mov	w0, 24(rp)
+	adc	$0, w3
+	dec	i
+	lea	32(rp), rp
+	jnz	L(m2tp)
+
+L(m2ed):mulx(	v1, %rax, w0)
+	add	%rax, w2
+	mov	(up), %rdx
+	mulx(	v0, %rax, w1)
+	add	w2, %rax
+	add	w3, %rax
+	mov	%rax, (rp)
+
+	mov	(%rsp), up		C restore `up' to beginning
+	lea	16(vp), vp
+	lea	8(rp,n,8), rp		C put back rp to old rp + 2
+	add	$2, n
+	jge	L(cor1)
+
+	push	%r14
+	push	%r15
+
+L(outer):
+	mov	(vp), v0
+	mov	8(vp), v1
+
+	lea	(n), i
+	sar	$2, i
+
+	mov	(up), %rdx
+	test	$1, R8(n)
+	jnz	L(bx1)
+
+L(bx0):	mov	(rp), X1
+	mov	8(rp), X0
+	mulx(	v0, %rax, w3)
+	add	%rax, X1
+	adc	$0, w3
+	mulx(	v1, %rax, w0)
+	add	%rax, X0
+	adc	$0, w0
+	mov	8(up), %rdx
+	mov	X1, (rp)
+	mulx(	v0, %rax, w1)
+	test	$2, R8(n)
+	jz	L(b2)
+
+L(b0):	lea	8(rp), rp
+	lea	8(up), up
+	jmp	L(lo0)
+
+L(b2):	mov	16(rp), X1
+	lea	24(rp), rp
+	lea	24(up), up
+	jmp	L(lo2)
+
+L(bx1):	mov	(rp), X0
+	mov	8(rp), X1
+	mulx(	v0, %rax, w1)
+	add	%rax, X0
+	mulx(	v1, %rax, w2)
+	adc	$0, w1
+	mov	X0, (rp)
+	add	%rax, X1
+	adc	$0, w2
+	mov	8(up), %rdx
+	test	$2, R8(n)
+	jnz	L(b3)
+
+L(b1):	lea	16(up), up
+	lea	16(rp), rp
+	jmp	L(lo1)
+
+L(b3):	mov	16(rp), X0
+	lea	32(up), up
+	mulx(	v0, %rax, w3)
+	inc	i
+	jz	L(cj3)
+	jmp	L(lo3)
+
+	ALIGN(16)
+L(top):	mulx(	v0, %rax, w3)
+	add	w0, X1
+	adc	$0, w2
+L(lo3):	add	%rax, X1
+	adc	$0, w3
+	mulx(	v1, %rax, w0)
+	add	%rax, X0
+	adc	$0, w0
+	lea	32(rp), rp
+	add	w1, X1
+	mov	-16(up), %rdx
+	mov	X1, -24(rp)
+	adc	$0, w3
+	add	w2, X0
+	mov	-8(rp), X1
+	mulx(	v0, %rax, w1)
+	adc	$0, w0
+L(lo2):	add	%rax, X0
+	mulx(	v1, %rax, w2)
+	adc	$0, w1
+	add	w3, X0
+	mov	X0, -16(rp)
+	adc	$0, w1
+	add	%rax, X1
+	adc	$0, w2
+	add	w0, X1
+	mov	-8(up), %rdx
+	adc	$0, w2
+L(lo1):	mulx(	v0, %rax, w3)
+	add	%rax, X1
+	adc	$0, w3
+	mov	(rp), X0
+	mulx(	v1, %rax, w0)
+	add	%rax, X0
+	adc	$0, w0
+	add	w1, X1
+	mov	X1, -8(rp)
+	adc	$0, w3
+	mov	(up), %rdx
+	add	w2, X0
+	mulx(	v0, %rax, w1)
+	adc	$0, w0
+L(lo0):	add	%rax, X0
+	adc	$0, w1
+	mulx(	v1, %rax, w2)
+	add	w3, X0
+	mov	8(rp), X1
+	mov	X0, (rp)
+	mov	16(rp), X0
+	adc	$0, w1
+	add	%rax, X1
+	adc	$0, w2
+	mov	8(up), %rdx
+	lea	32(up), up
+	inc	i
+	jnz	L(top)
+
+L(end):	mulx(	v0, %rax, w3)
+	add	w0, X1
+	adc	$0, w2
+L(cj3):	add	%rax, X1
+	adc	$0, w3
+	mulx(	v1, %rax, w0)
+	add	%rax, X0
+	add	w1, X1
+	mov	-16(up), %rdx
+	mov	X1, 8(rp)
+	adc	$0, w3
+	add	w2, X0
+	mulx(	v0, %rax, w1)
+	add	X0, %rax
+	add	w3, %rax
+	mov	%rax, 16(rp)
+
+	mov	16(%rsp), up		C restore `up' to beginning
+	lea	16(vp), vp
+	lea	24(rp,n,8), rp		C put back rp to old rp + 2
+	add	$2, n
+	jl	L(outer)
+
+	pop	%r15
+	pop	%r14
+
+	jnz	L(cor0)
+
+L(cor1):mov	(vp), v0
+	mov	8(vp), v1
+	mov	(up), %rdx
+	mulx(	v0, %r12, %rbp)		C u0 x v2
+	add	(rp), %r12		C FIXME: rp[0] still available in reg?
+	adc	%rax, %rbp
+	mov	8(up), %r10
+	imul	v0, %r10
+	imul	v1, %rdx
+	mov	%r12, (rp)
+	add	%r10, %rdx
+	add	%rbp, %rdx
+	mov	%rdx, 8(rp)
+	pop	%rax			C deallocate `up' copy
+	pop	%r13
+	pop	%r12
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+
+L(cor0):mov	(vp), %r11
+	imul	(up), %r11
+	add	%rax, %r11
+	mov	%r11, (rp)
+	pop	%rax			C deallocate `up' copy
+	pop	%r13
+	pop	%r12
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+
+	ALIGN(16)
+L(small):
+	cmp	$2, n
+	jae	L(gt1)
+L(n1):	imul	(vp), %rdx
+	mov	%rdx, (rp)
+	FUNC_EXIT()
+	ret
+L(gt1):	ja	L(gt2)
+L(n2):	mov	(vp), %r9
+	mulx(	%r9, %rax, %rdx)
+	mov	%rax, (rp)
+	mov	8(up), %rax
+	imul	%r9, %rax
+	add	%rax, %rdx
+	mov	8(vp), %r9
+	mov	(up), %rcx
+	imul	%r9, %rcx
+	add	%rcx, %rdx
+	mov	%rdx, 8(rp)
+	FUNC_EXIT()
+	ret
+L(gt2):
+L(n3):	mov	(vp), %r9
+	mulx(	%r9, %rax, %r10)	C u0 x v0
+	mov	%rax, (rp)
+	mov	8(up), %rdx
+	mulx(	%r9, %rax, %rdx)	C u1 x v0
+	imul	16(up), %r9		C u2 x v0
+	add	%rax, %r10
+	adc	%rdx, %r9
+	mov	8(vp), %r11
+	mov	(up), %rdx
+	mulx(	%r11, %rax, %rdx)	C u0 x v1
+	add	%rax, %r10
+	adc	%rdx, %r9
+	imul	8(up), %r11		C u1 x v1
+	add	%r11, %r9
+	mov	%r10, 8(rp)
+	mov	16(vp), %r10
+	mov	(up), %rax
+	imul	%rax, %r10		C u0 x v2
+	add	%r10, %r9
+	mov	%r9, 16(rp)
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/coreihwl/redc_1.asm b/third_party/gmp/mpn/x86_64/coreihwl/redc_1.asm
new file mode 100644
index 0000000..b1d6c0a
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreihwl/redc_1.asm
@@ -0,0 +1,437 @@
+dnl  AMD64 mpn_redc_1 optimised for Intel Haswell.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	n/a
+C AMD K10	n/a
+C AMD bull	n/a
+C AMD pile	n/a
+C AMD steam	 ?
+C AMD bobcat	n/a
+C AMD jaguar	 ?
+C Intel P4	n/a
+C Intel core	n/a
+C Intel NHM	n/a
+C Intel SBR	n/a
+C Intel IBR	n/a
+C Intel HWL	 2.32
+C Intel BWL	 ?
+C Intel atom	n/a
+C VIA nano	n/a
+
+C The inner loops of this code are the result of running a code generation and
+C optimisation tool suite written by David Harvey and Torbjörn Granlund.
+
+C TODO
+C  * Micro-optimise.
+C  * Consider inlining mpn_add_n.  Tests indicate that this saves just 1-2
+C    cycles, though.
+
+define(`rp',          `%rdi')   C rcx
+define(`up',          `%rsi')   C rdx
+define(`mp_param',    `%rdx')   C r8
+define(`n',           `%rcx')   C r9
+define(`u0inv_param', `%r8')    C stack
+
+define(`i',           `%r14')
+define(`j',           `%r15')
+define(`mp',          `%rdi')
+define(`u0inv',       `(%rsp)')  C stack
+
+ABI_SUPPORT(DOS64)    C FIXME: needs verification
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_redc_1)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8	')
+	push	%rbx
+	push	%rbp
+	push	%r12
+	push	%r13
+	push	%r14
+	push	%r15
+	push	rp
+	mov	mp_param, mp		C note that rp and mp shares register
+	mov	(up), %rdx
+
+	neg	n
+	push	%r8			C put u0inv on stack
+	imul	u0inv_param, %rdx	C first iteration q0
+	mov	n, j			C outer loop induction var
+
+	test	$1, R8(n)
+	jnz	L(bx1)
+
+L(bx0):	test	$2, R8(n)
+	jz	L(o0b)
+
+	cmp	$-2, R32(n)
+	jnz	L(o2)
+
+C Special code for n = 2 since general code cannot handle it
+	mov	8(%rsp), %rbx		C rp
+	lea	16(%rsp), %rsp		C deallocate two slots
+	mulx(	(mp), %r9, %r12)
+	mulx(	8,(mp), %r11, %r10)
+	add	%r12, %r11
+	adc	$0, %r10
+	add	(up), %r9		C = 0
+	adc	8(up), %r11		C r11 = up[1]
+	adc	$0, %r10		C -> up[0]
+	mov	%r11, %rdx
+	imul	u0inv_param, %rdx
+	mulx(	(mp), %r13, %r12)
+	mulx(	8,(mp), %r14, %r15)
+	xor	R32(%rax), R32(%rax)
+	add	%r12, %r14
+	adc	$0, %r15
+	add	%r11, %r13		C = 0
+	adc	16(up), %r14		C rp[2]
+	adc	$0, %r15		C -> up[1]
+	add	%r14, %r10
+	adc	24(up), %r15
+	mov	%r10, (%rbx)
+	mov	%r15, 8(%rbx)
+	setc	R8(%rax)
+	jmp	L(ret)
+
+L(o2):	lea	2(n), i			C inner loop induction var
+	mulx(	(mp), %r9, %r8)
+	mulx(	8,(mp), %r11, %r10)
+	sar	$2, i
+	add	%r8, %r11
+	jmp	L(lo2)
+
+	ALIGN(16)
+L(tp2):	adc	%rax, %r9
+	lea	32(up), up
+	adc	%r8, %r11
+L(lo2):	mulx(	16,(mp), %r13, %r12)
+	mov	(up), %r8
+	mulx(	24,(mp), %rbx, %rax)
+	lea	32(mp), mp
+	adc	%r10, %r13
+	adc	%r12, %rbx
+	adc	$0, %rax
+	mov	8(up), %r10
+	mov	16(up), %r12
+	add	%r9, %r8
+	mov	24(up), %rbp
+	mov	%r8, (up)
+	adc	%r11, %r10
+	mulx(	(mp), %r9, %r8)
+	mov	%r10, 8(up)
+	adc	%r13, %r12
+	mov	%r12, 16(up)
+	adc	%rbx, %rbp
+	mulx(	8,(mp), %r11, %r10)
+	mov	%rbp, 24(up)
+	inc	i
+	jnz	L(tp2)
+
+L(ed2):	mov	56(up,n,8), %rdx	C next iteration up[0]
+	lea	16(mp,n,8), mp		C mp = (last starting mp)
+	adc	%rax, %r9
+	adc	%r8, %r11
+	mov	32(up), %r8
+	adc	$0, %r10
+	imul	u0inv, %rdx		C next iteration q0
+	mov	40(up), %rax
+	add	%r9, %r8
+	mov	%r8, 32(up)
+	adc	%r11, %rax
+	mov	%rax, 40(up)
+	lea	56(up,n,8), up		C up = (last starting up) + 1
+	adc	$0, %r10
+	mov	%r10, -8(up)
+	inc	j
+	jnz	L(o2)
+
+	jmp	L(cj)
+
+
+L(bx1):	test	$2, R8(n)
+	jz	L(o3a)
+
+L(o1a):	cmp	$-1, R32(n)
+	jnz	L(o1b)
+
+C Special code for n = 1 since general code cannot handle it
+	mov	8(%rsp), %rbx		C rp
+	lea	16(%rsp), %rsp		C deallocate two slots
+	mulx(	(mp), %r11, %r10)
+	add	(up), %r11
+	adc	8(up), %r10
+	mov	%r10, (%rbx)
+	mov	$0, R32(%rax)
+	setc	R8(%rax)
+	jmp	L(ret)
+
+L(o1b):	lea	24(mp), mp
+L(o1):	lea	1(n), i			C inner loop induction var
+	mulx(	-24,(mp), %r11, %r10)
+	mulx(	-16,(mp), %r13, %r12)
+	mulx(	-8,(mp), %rbx, %rax)
+	sar	$2, i
+	add	%r10, %r13
+	adc	%r12, %rbx
+	adc	$0, %rax
+	mov	(up), %r10
+	mov	8(up), %r12
+	mov	16(up), %rbp
+	add	%r11, %r10
+	jmp	L(lo1)
+
+	ALIGN(16)
+L(tp1):	adc	%rax, %r9
+	lea	32(up), up
+	adc	%r8, %r11
+	mulx(	16,(mp), %r13, %r12)
+	mov	-8(up), %r8
+	mulx(	24,(mp), %rbx, %rax)
+	lea	32(mp), mp
+	adc	%r10, %r13
+	adc	%r12, %rbx
+	adc	$0, %rax
+	mov	(up), %r10
+	mov	8(up), %r12
+	add	%r9, %r8
+	mov	16(up), %rbp
+	mov	%r8, -8(up)
+	adc	%r11, %r10
+L(lo1):	mulx(	(mp), %r9, %r8)
+	mov	%r10, (up)
+	adc	%r13, %r12
+	mov	%r12, 8(up)
+	adc	%rbx, %rbp
+	mulx(	8,(mp), %r11, %r10)
+	mov	%rbp, 16(up)
+	inc	i
+	jnz	L(tp1)
+
+L(ed1):	mov	48(up,n,8), %rdx	C next iteration up[0]
+	lea	40(mp,n,8), mp		C mp = (last starting mp)
+	adc	%rax, %r9
+	adc	%r8, %r11
+	mov	24(up), %r8
+	adc	$0, %r10
+	imul	u0inv, %rdx		C next iteration q0
+	mov	32(up), %rax
+	add	%r9, %r8
+	mov	%r8, 24(up)
+	adc	%r11, %rax
+	mov	%rax, 32(up)
+	lea	48(up,n,8), up		C up = (last starting up) + 1
+	adc	$0, %r10
+	mov	%r10, -8(up)
+	inc	j
+	jnz	L(o1)
+
+	jmp	L(cj)
+
+L(o3a):	cmp	$-3, R32(n)
+	jnz	L(o3b)
+
+C Special code for n = 3 since general code cannot handle it
+L(n3):	mulx(	(mp), %rbx, %rax)
+	mulx(	8,(mp), %r9, %r14)
+	add	(up), %rbx
+	mulx(	16,(mp), %r11, %r10)
+	adc	%rax, %r9		C W 1
+	adc	%r14, %r11		C W 2
+	mov	8(up), %r14
+	mov	u0inv_param, %rdx
+	adc	$0, %r10		C W 3
+	mov	16(up), %rax
+	add	%r9, %r14		C W 1
+	mov	%r14, 8(up)
+	mulx(	%r14, %rdx, %r13)	C next iteration q0
+	adc	%r11, %rax		C W 2
+	mov	%rax, 16(up)
+	adc	$0, %r10		C W 3
+	mov	%r10, (up)
+	lea	8(up), up		C up = (last starting up) + 1
+	inc	j
+	jnz	L(n3)
+
+	jmp	L(cj)
+
+L(o3b):	lea	8(mp), mp
+L(o3):	lea	4(n), i			C inner loop induction var
+	mulx(	-8,(mp), %rbx, %rax)
+	mulx(	(mp), %r9, %r8)
+	mov	(up), %rbp
+	mulx(	8,(mp), %r11, %r10)
+	sar	$2, i
+	add	%rbx, %rbp
+	nop
+	adc	%rax, %r9
+	jmp	L(lo3)
+
+	ALIGN(16)
+L(tp3):	adc	%rax, %r9
+	lea	32(up), up
+L(lo3):	adc	%r8, %r11
+	mulx(	16,(mp), %r13, %r12)
+	mov	8(up), %r8
+	mulx(	24,(mp), %rbx, %rax)
+	lea	32(mp), mp
+	adc	%r10, %r13
+	adc	%r12, %rbx
+	adc	$0, %rax
+	mov	16(up), %r10
+	mov	24(up), %r12
+	add	%r9, %r8
+	mov	32(up), %rbp
+	mov	%r8, 8(up)
+	adc	%r11, %r10
+	mulx(	(mp), %r9, %r8)
+	mov	%r10, 16(up)
+	adc	%r13, %r12
+	mov	%r12, 24(up)
+	adc	%rbx, %rbp
+	mulx(	8,(mp), %r11, %r10)
+	mov	%rbp, 32(up)
+	inc	i
+	jnz	L(tp3)
+
+L(ed3):	mov	64(up,n,8), %rdx	C next iteration up[0]
+	lea	24(mp,n,8), mp		C mp = (last starting mp)
+	adc	%rax, %r9
+	adc	%r8, %r11
+	mov	40(up), %r8
+	adc	$0, %r10
+	imul	u0inv, %rdx		C next iteration q0
+	mov	48(up), %rax
+	add	%r9, %r8
+	mov	%r8, 40(up)
+	adc	%r11, %rax
+	mov	%rax, 48(up)
+	lea	64(up,n,8), up		C up = (last starting up) + 1
+	adc	$0, %r10
+	mov	%r10, -8(up)
+	inc	j
+	jnz	L(o3)
+
+	jmp	L(cj)
+
+L(o0b):	lea	16(mp), mp
+L(o0):	mov	n, i			C inner loop induction var
+	mulx(	-16,(mp), %r13, %r12)
+	mulx(	-8,(mp), %rbx, %rax)
+	sar	$2, i
+	add	%r12, %rbx
+	adc	$0, %rax
+	mov	(up), %r12
+	mov	8(up), %rbp
+	mulx(	(mp), %r9, %r8)
+	add	%r13, %r12
+	jmp	L(lo0)
+
+	ALIGN(16)
+L(tp0):	adc	%rax, %r9
+	lea	32(up), up
+	adc	%r8, %r11
+	mulx(	16,(mp), %r13, %r12)
+	mov	-16(up), %r8
+	mulx(	24,(mp), %rbx, %rax)
+	lea	32(mp), mp
+	adc	%r10, %r13
+	adc	%r12, %rbx
+	adc	$0, %rax
+	mov	-8(up), %r10
+	mov	(up), %r12
+	add	%r9, %r8
+	mov	8(up), %rbp
+	mov	%r8, -16(up)
+	adc	%r11, %r10
+	mulx(	(mp), %r9, %r8)
+	mov	%r10, -8(up)
+	adc	%r13, %r12
+	mov	%r12, (up)
+L(lo0):	adc	%rbx, %rbp
+	mulx(	8,(mp), %r11, %r10)
+	mov	%rbp, 8(up)
+	inc	i
+	jnz	L(tp0)
+
+L(ed0):	mov	40(up,n,8), %rdx	C next iteration up[0]
+	lea	32(mp,n,8), mp		C mp = (last starting mp)
+	adc	%rax, %r9
+	adc	%r8, %r11
+	mov	16(up), %r8
+	adc	$0, %r10
+	imul	u0inv, %rdx		C next iteration q0
+	mov	24(up), %rax
+	add	%r9, %r8
+	mov	%r8, 16(up)
+	adc	%r11, %rax
+	mov	%rax, 24(up)
+	lea	40(up,n,8), up		C up = (last starting up) + 1
+	adc	$0, %r10
+	mov	%r10, -8(up)
+	inc	j
+	jnz	L(o0)
+
+L(cj):
+IFSTD(`	mov	8(%rsp), %rdi		C param 1: rp
+	lea	16-8(%rsp), %rsp	C deallocate 2, add back for alignment
+	lea	(up,n,8), %rdx		C param 3: up - n
+	neg	R32(n)		')	C param 4: n
+
+IFDOS(`	mov	up, %rdx		C param 2: up
+	lea	(up,n,8), %r8		C param 3: up - n
+	neg	R32(n)
+	mov	n, %r9			C param 4: n
+	mov	8(%rsp), %rcx		C param 1: rp
+	lea	16-32-8(%rsp), %rsp')	C deallocate 2, allocate shadow, align
+
+	ASSERT(nz, `test $15, %rsp')
+	CALL(	mpn_add_n)
+
+IFSTD(`	lea	8(%rsp), %rsp	')
+IFDOS(`	lea	32+8(%rsp), %rsp')
+
+L(ret):	pop	%r15
+	pop	%r14
+	pop	%r13
+	pop	%r12
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/coreihwl/sqr_basecase.asm b/third_party/gmp/mpn/x86_64/coreihwl/sqr_basecase.asm
new file mode 100644
index 0000000..641cdf3
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreihwl/sqr_basecase.asm
@@ -0,0 +1,506 @@
+dnl  AMD64 mpn_sqr_basecase optimised for Intel Haswell.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2008, 2009, 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C cycles/limb	mul_2		addmul_2	sqr_diag_addlsh1
+C AMD K8,K9	n/a		n/a			n/a
+C AMD K10	n/a		n/a			n/a
+C AMD bull	n/a		n/a			n/a
+C AMD pile	n/a		n/a			n/a
+C AMD steam	 ?		 ?			 ?
+C AMD bobcat	n/a		n/a			n/a
+C AMD jaguar	 ?		 ?			 ?
+C Intel P4	n/a		n/a			n/a
+C Intel core	n/a		n/a			n/a
+C Intel NHM	n/a		n/a			n/a
+C Intel SBR	n/a		n/a			n/a
+C Intel IBR	n/a		n/a			n/a
+C Intel HWL	 1.86		 2.15			~2.5
+C Intel BWL	 ?		 ?			 ?
+C Intel atom	n/a		n/a			n/a
+C VIA nano	n/a		n/a			n/a
+
+C The inner loops of this code are the result of running a code generation and
+C optimisation tool suite written by David Harvey and Torbjörn Granlund, except
+C that the sqr_diag_addlsh1 loop was manually written.
+
+C TODO
+C  * Replace current unoptimised sqr_diag_addlsh1 loop; 1.75 c/l might be
+C    possible.
+C  * Consider splitting outer loop into 2, one for n = 1 (mod 2) and one for
+C    n = 0 (mod 2).  These loops could fall into specific "corner" code.
+C  * Consider splitting outer loop into 4.
+C  * Streamline pointer updates.
+C  * Perhaps suppress a few more xor insns in feed-in code.
+C  * Make sure we write no dead registers in feed-in code.
+C  * We might use 32-bit size ops, since n >= 2^32 is non-terminating.  Watch
+C    out for negative sizes being zero-extended, though.
+C  * Provide straight-line code for n = 4; then look for simplifications in
+C    main code.
+
+define(`rp',	  `%rdi')
+define(`up',	  `%rsi')
+define(`un_param',`%rdx')
+
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_sqr_basecase)
+	FUNC_ENTRY(3)
+
+	cmp	$2, un_param
+	jae	L(gt1)
+
+	mov	(up), %rdx
+	mulx(	%rdx, %rax, %rdx)
+	mov	%rax, (rp)
+	mov	%rdx, 8(rp)
+	FUNC_EXIT()
+	ret
+
+L(gt1):	jne	L(gt2)
+
+	mov	(up), %rdx
+	mov	8(up), %rcx
+	mulx(	%rcx, %r9, %r10)	C v0 * v1	W 1 2
+	mulx(	%rdx, %rax, %r8)	C v0 * v0	W 0 1
+	mov	%rcx, %rdx
+	mulx(	%rdx, %r11, %rdx)	C v1 * v1	W 2 3
+	add	%r9, %r9		C		W 1
+	adc	%r10, %r10		C		W 2
+	adc	$0, %rdx		C		W 3
+	add	%r9, %r8		C W 1
+	adc	%r11, %r10		C W 2
+	adc	$0, %rdx		C W 3
+	mov	%rax, (rp)
+	mov	%r8, 8(rp)
+	mov	%r10, 16(rp)
+	mov	%rdx, 24(rp)
+	FUNC_EXIT()
+	ret
+
+L(gt2):	cmp	$4, un_param
+	jae	L(gt3)
+define(`v0', `%r8')
+define(`v1', `%r9')
+define(`w0', `%r10')
+define(`w2', `%r11')
+
+	mov	(up), v0
+	mov	8(up), %rdx
+	mov	%rdx, v1
+	mulx(	v0, w2, %rax)
+	mov	16(up), %rdx
+	mulx(	v0, w0, %rcx)
+	mov	w2, %r8
+	add	%rax, w0
+	adc	$0, %rcx
+	mulx(	v1, %rdx, %rax)
+	add	%rcx, %rdx
+	mov	%rdx, 24(rp)
+	adc	$0, %rax
+	mov	%rax, 32(rp)
+	xor	R32(%rcx), R32(%rcx)
+	mov	(up), %rdx
+	mulx(	%rdx, %rax, w2)
+	mov	%rax, (rp)
+	add	%r8, %r8
+	adc	w0, w0
+	setc	R8(%rcx)
+	mov	8(up), %rdx
+	mulx(	%rdx, %rax, %rdx)
+	add	w2, %r8
+	adc	%rax, w0
+	mov	%r8, 8(rp)
+	mov	w0, 16(rp)
+	mov	24(rp), %r8
+	mov	32(rp), w0
+	lea	(%rdx,%rcx), w2
+	adc	%r8, %r8
+	adc	w0, w0
+	setc	R8(%rcx)
+	mov	16(up), %rdx
+	mulx(	%rdx, %rax, %rdx)
+	add	w2, %r8
+	adc	%rax, w0
+	mov	%r8, 24(rp)
+	mov	w0, 32(rp)
+	adc	%rcx, %rdx
+	mov	%rdx, 40(rp)
+	FUNC_EXIT()
+	ret
+
+L(gt3):
+
+define(`v0', `%r8')
+define(`v1', `%r9')
+define(`w0', `%r10')
+define(`w1', `%r11')
+define(`w2', `%rbx')
+define(`w3', `%rbp')
+define(`un', `%r12')
+define(`n',  `%rcx')
+
+define(`X0', `%r13')
+define(`X1', `%r14')
+
+L(do_mul_2):
+	push	%rbx
+	push	%rbp
+	push	%r12
+	push	%r13
+	push	%r14
+	mov	$0, R32(un)
+	sub	un_param, un		C free up rdx
+	push	un
+	mov	(up), v0
+	mov	8(up), %rdx
+	lea	2(un), n
+	sar	$2, n			C FIXME: suppress, change loop?
+	inc	un			C decrement |un|
+	mov	%rdx, v1
+
+	test	$1, R8(un)
+	jnz	L(mx1)
+
+L(mx0):	mulx(	v0, w2, w1)
+	mov	16(up), %rdx
+	mov	w2, 8(rp)
+	xor	w2, w2
+	mulx(	v0, w0, w3)
+	test	$2, R8(un)
+	jz	L(m00)
+
+L(m10):	lea	-8(rp), rp
+	lea	-8(up), up
+	jmp	L(mlo2)
+
+L(m00):	lea	8(up), up
+	lea	8(rp), rp
+	jmp	L(mlo0)
+
+L(mx1):	mulx(	v0, w0, w3)
+	mov	16(up), %rdx
+	mov	w0, 8(rp)
+	xor	w0, w0
+	mulx(	v0, w2, w1)
+	test	$2, R8(un)
+	jz	L(mlo3)
+
+L(m01):	lea	16(rp), rp
+	lea	16(up), up
+	jmp	L(mlo1)
+
+	ALIGN(32)
+L(mtop):mulx(	v1, %rax, w0)
+	add	%rax, w2		C 0
+	mov	(up), %rdx
+	mulx(	v0, %rax, w1)
+	adc	$0, w0			C 1
+	add	%rax, w2		C 0
+L(mlo1):adc	$0, w1			C 1
+	add	w3, w2			C 0
+	mov	w2, (rp)		C 0
+	adc	$0, w1			C 1
+	mulx(	v1, %rax, w2)
+	add	%rax, w0		C 1
+	mov	8(up), %rdx
+	adc	$0, w2			C 2
+	mulx(	v0, %rax, w3)
+	add	%rax, w0		C 1
+	adc	$0, w3			C 2
+L(mlo0):add	w1, w0			C 1
+	mov	w0, 8(rp)		C 1
+	adc	$0, w3			C 2
+	mulx(	v1, %rax, w0)
+	add	%rax, w2		C 2
+	mov	16(up), %rdx
+	mulx(	v0, %rax, w1)
+	adc	$0, w0			C 3
+	add	%rax, w2		C 2
+	adc	$0, w1			C 3
+L(mlo3):add	w3, w2			C 2
+	mov	w2, 16(rp)		C 2
+	adc	$0, w1			C 3
+	mulx(	v1, %rax, w2)
+	add	%rax, w0		C 3
+	mov	24(up), %rdx
+	adc	$0, w2			C 4
+	mulx(	v0, %rax, w3)
+	add	%rax, w0		C 3
+	adc	$0, w3			C 4
+L(mlo2):add	w1, w0			C 3
+	lea	32(up), up
+	mov	w0, 24(rp)		C 3
+	adc	$0, w3			C 4
+	inc	n
+	lea	32(rp), rp
+	jnz	L(mtop)
+
+L(mend):mulx(	v1, %rdx, %rax)
+	add	%rdx, w2
+	adc	$0, %rax
+	add	w3, w2
+	mov	w2, (rp)
+	adc	$0, %rax
+	mov	%rax, 8(rp)
+
+	lea	16(up), up
+	lea	-16(rp), rp
+
+L(do_addmul_2):
+L(outer):
+	lea	(up,un,8), up		C put back up to 2 positions above last time
+	lea	48(rp,un,8), rp		C put back rp to 4 positions above last time
+
+	mov	-8(up), v0		C shared between addmul_2 and corner
+
+	add	$2, un			C decrease |un|
+	cmp	$-2, un
+	jge	L(corner)
+
+	mov	(up), v1
+
+	lea	1(un), n
+	sar	$2, n			C FIXME: suppress, change loop?
+
+	mov	v1, %rdx
+	test	$1, R8(un)
+	jnz	L(bx1)
+
+L(bx0):	mov	(rp), X0
+	mov	8(rp), X1
+	mulx(	v0, %rax, w1)
+	add	%rax, X0
+	adc	$0, w1
+	mov	X0, (rp)
+	xor	w2, w2
+	test	$2, R8(un)
+	jnz	L(b10)
+
+L(b00):	mov	8(up), %rdx
+	lea	16(rp), rp
+	lea	16(up), up
+	jmp	L(lo0)
+
+L(b10):	mov	8(up), %rdx
+	mov	16(rp), X0
+	lea	32(up), up
+	inc	n
+	mulx(	v0, %rax, w3)
+	jz	L(ex)
+	jmp	L(lo2)
+
+L(bx1):	mov	(rp), X1
+	mov	8(rp), X0
+	mulx(	v0, %rax, w3)
+	mov	8(up), %rdx
+	add	%rax, X1
+	adc	$0, w3
+	xor	w0, w0
+	mov	X1, (rp)
+	mulx(	v0, %rax, w1)
+	test	$2, R8(un)
+	jz	L(b11)
+
+L(b01):	mov	16(rp), X1
+	lea	24(rp), rp
+	lea	24(up), up
+	jmp	L(lo1)
+
+L(b11):	lea	8(rp), rp
+	lea	8(up), up
+	jmp	L(lo3)
+
+	ALIGN(32)
+L(top):	mulx(	v0, %rax, w3)
+	add	w0, X1
+	adc	$0, w2
+L(lo2):	add	%rax, X1
+	adc	$0, w3
+	mulx(	v1, %rax, w0)
+	add	%rax, X0
+	adc	$0, w0
+	lea	32(rp), rp
+	add	w1, X1
+	mov	-16(up), %rdx
+	mov	X1, -24(rp)
+	adc	$0, w3
+	add	w2, X0
+	mov	-8(rp), X1
+	mulx(	v0, %rax, w1)
+	adc	$0, w0
+L(lo1):	add	%rax, X0
+	mulx(	v1, %rax, w2)
+	adc	$0, w1
+	add	w3, X0
+	mov	X0, -16(rp)
+	adc	$0, w1
+	add	%rax, X1
+	adc	$0, w2
+	add	w0, X1
+	mov	-8(up), %rdx
+	adc	$0, w2
+L(lo0):	mulx(	v0, %rax, w3)
+	add	%rax, X1
+	adc	$0, w3
+	mov	(rp), X0
+	mulx(	v1, %rax, w0)
+	add	%rax, X0
+	adc	$0, w0
+	add	w1, X1
+	mov	X1, -8(rp)
+	adc	$0, w3
+	mov	(up), %rdx
+	add	w2, X0
+	mulx(	v0, %rax, w1)
+	adc	$0, w0
+L(lo3):	add	%rax, X0
+	adc	$0, w1
+	mulx(	v1, %rax, w2)
+	add	w3, X0
+	mov	8(rp), X1
+	mov	X0, (rp)
+	mov	16(rp), X0
+	adc	$0, w1
+	add	%rax, X1
+	adc	$0, w2
+	mov	8(up), %rdx
+	lea	32(up), up
+	inc	n
+	jnz	L(top)
+
+L(end):	mulx(	v0, %rax, w3)
+	add	w0, X1
+	adc	$0, w2
+L(ex):	add	%rax, X1
+	adc	$0, w3
+	mulx(	v1, %rdx, %rax)
+	add	w1, X1
+	mov	X1, 8(rp)
+	adc	$0, w3
+	add	w2, %rdx
+	adc	$0, %rax
+	add	%rdx, w3
+	mov	w3, 16(rp)
+	adc	$0, %rax
+	mov	%rax, 24(rp)
+
+	jmp	L(outer)		C loop until a small corner remains
+
+L(corner):
+	pop	un
+	mov	(up), %rdx
+	jg	L(small_corner)
+
+	mov	%rdx, v1
+	mov	(rp), X0
+	mov	%rax, X1		C Tricky rax reuse of last iteration
+	mulx(	v0, %rax, w1)
+	add	%rax, X0
+	adc	$0, w1
+	mov	X0, (rp)
+	mov	8(up), %rdx
+	mulx(	v0, %rax, w3)
+	add	%rax, X1
+	adc	$0, w3
+	mulx(	v1, %rdx, %rax)
+	add	w1, X1
+	mov	X1, 8(rp)
+	adc	$0, w3
+	add	w3, %rdx
+	mov	%rdx, 16(rp)
+	adc	$0, %rax
+	mov	%rax, 24(rp)
+	lea	32(rp), rp
+	lea	16(up), up
+	jmp	L(com)
+
+L(small_corner):
+	mulx(	v0, X1, w3)
+	add	%rax, X1		C Tricky rax reuse of last iteration
+	adc	$0, w3
+	mov	X1, (rp)
+	mov	w3, 8(rp)
+	lea	16(rp), rp
+	lea	8(up), up
+
+L(com):
+
+L(sqr_diag_addlsh1):
+	lea	8(up,un,8), up		C put back up at its very beginning
+	lea	(rp,un,8), rp
+	lea	(rp,un,8), rp		C put back rp at its very beginning
+	inc	un
+
+	mov	-8(up), %rdx
+	xor	R32(%rbx), R32(%rbx)	C clear CF as side effect
+	mulx(	%rdx, %rax, %r10)
+	mov	%rax, 8(rp)
+	mov	16(rp), %r8
+	mov	24(rp), %r9
+	jmp	L(dm)
+
+	ALIGN(16)
+L(dtop):mov	32(rp), %r8
+	mov	40(rp), %r9
+	lea	16(rp), rp
+	lea	(%rdx,%rbx), %r10
+L(dm):	adc	%r8, %r8
+	adc	%r9, %r9
+	setc	R8(%rbx)
+	mov	(up), %rdx
+	lea	8(up), up
+	mulx(	%rdx, %rax, %rdx)
+	add	%r10, %r8
+	adc	%rax, %r9
+	mov	%r8, 16(rp)
+	mov	%r9, 24(rp)
+	inc	un
+	jnz	L(dtop)
+
+L(dend):adc	%rbx, %rdx
+	mov	%rdx, 32(rp)
+
+	pop	%r14
+	pop	%r13
+	pop	%r12
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/coreinhm/aorrlsh_n.asm b/third_party/gmp/mpn/x86_64/coreinhm/aorrlsh_n.asm
new file mode 100644
index 0000000..eed64e7
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreinhm/aorrlsh_n.asm
@@ -0,0 +1,200 @@
+dnl  AMD64 mpn_addlsh_n -- rp[] = up[] + (vp[] << k)
+dnl  AMD64 mpn_rsblsh_n -- rp[] = (vp[] << k) - up[]
+dnl  Optimised for Nehalem.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 ?
+C AMD K10	 4.75
+C Intel P4	 ?
+C Intel core2	 2.8-3
+C Intel NHM	 2.8
+C Intel SBR	 3.55
+C Intel atom	 ?
+C VIA nano	 ?
+
+C The inner-loop probably runs close to optimally on Nehalem (using 4-way
+C unrolling).  The rest of the code is quite crude, and could perhaps be made
+C both smaller and faster.
+
+C INPUT PARAMETERS
+define(`rp',	`%rdi')
+define(`up',	`%rsi')
+define(`vp',	`%rdx')
+define(`n',	`%rcx')
+define(`cnt',	`%r8')
+define(`cy',	`%r9')			C for _nc variant
+
+ifdef(`OPERATION_addlsh_n', `
+	define(ADDSUB,	add)
+	define(ADCSBB,	adc)
+	define(IFRSB,	)
+	define(func_n,	mpn_addlsh_n)
+	define(func_nc,	mpn_addlsh_nc)')
+ifdef(`OPERATION_rsblsh_n', `
+	define(ADDSUB,	sub)
+	define(ADCSBB,	sbb)
+	define(IFRSB,	`$1')
+	define(func_n,	mpn_rsblsh_n)
+	define(func_nc,	mpn_rsblsh_nc)')
+
+C mpn_rsblsh_nc removed below, its idea of carry-in is inconsistent with
+C refmpn_rsblsh_nc
+MULFUNC_PROLOGUE(mpn_addlsh_n mpn_addlsh_nc mpn_rsblsh_n)
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(func_n)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8d	')	C cnt
+	push	%rbx
+	xor	R32(%rbx), R32(%rbx)	C clear CF save register
+L(ent):	push	%rbp
+	mov	R32(n), R32(%rbp)
+	mov	n, %rax
+
+	mov	R32(cnt), R32(%rcx)
+	neg	R32(%rcx)
+
+	lea	-8(up,%rax,8), up
+	lea	-8(vp,%rax,8), vp
+	lea	-40(rp,%rax,8), rp
+	neg	%rax
+
+	and	$3, R32(%rbp)
+	jz	L(b0)
+	cmp	$2, R32(%rbp)
+	jc	L(b1)
+	jz	L(b2)
+
+L(b3):	xor	R32(%r9), R32(%r9)
+	mov	8(vp,%rax,8), %r10
+	mov	16(vp,%rax,8), %r11
+	shrd	%cl, %r10, %r9
+	shrd	%cl, %r11, %r10
+	add	R32(%rbx), R32(%rbx)
+	ADCSBB	8(up,%rax,8), %r9
+	mov	24(vp,%rax,8), %r8
+	ADCSBB	16(up,%rax,8), %r10
+	sbb	R32(%rbx), R32(%rbx)
+	add	$3, %rax
+	jmp	L(lo3)
+
+L(b0):	mov	8(vp,%rax,8), %r9
+	xor	R32(%r8), R32(%r8)
+	shrd	%cl, %r9, %r8
+	mov	16(vp,%rax,8), %r10
+	mov	24(vp,%rax,8), %r11
+	shrd	%cl, %r10, %r9
+	shrd	%cl, %r11, %r10
+	add	R32(%rbx), R32(%rbx)
+	ADCSBB	8(up,%rax,8), %r8
+	mov	%r8, 40(rp,%rax,8)	C offset 40
+	ADCSBB	16(up,%rax,8), %r9
+	mov	32(vp,%rax,8), %r8
+	ADCSBB	24(up,%rax,8), %r10
+	sbb	R32(%rbx), R32(%rbx)
+	add	$4, %rax
+	jmp	L(lo0)
+
+L(b1):	mov	8(vp,%rax,8), %r8
+	add	$1, %rax
+	jz	L(1)
+	mov	8(vp,%rax,8), %r9
+	xor	R32(%rbp), R32(%rbp)
+	jmp	L(lo1)
+L(1):	xor	R32(%r11), R32(%r11)
+	jmp	L(wd1)
+
+L(b2):	xor	%r10, %r10
+	mov	8(vp,%rax,8), %r11
+	shrd	%cl, %r11, %r10
+	add	R32(%rbx), R32(%rbx)
+	mov	16(vp,%rax,8), %r8
+	ADCSBB	8(up,%rax,8), %r10
+	sbb	R32(%rbx), R32(%rbx)
+	add	$2, %rax
+	jz	L(end)
+
+	ALIGN(16)
+L(top):	mov	8(vp,%rax,8), %r9
+	mov	%r11, %rbp
+L(lo2):	mov	%r10, 24(rp,%rax,8)	C offset 24
+L(lo1):	shrd	%cl, %r8, %rbp
+	shrd	%cl, %r9, %r8
+	mov	16(vp,%rax,8), %r10
+	mov	24(vp,%rax,8), %r11
+	shrd	%cl, %r10, %r9
+	shrd	%cl, %r11, %r10
+	add	R32(%rbx), R32(%rbx)
+	ADCSBB	(up,%rax,8), %rbp
+	ADCSBB	8(up,%rax,8), %r8
+	mov	%r8, 40(rp,%rax,8)	C offset 40
+	ADCSBB	16(up,%rax,8), %r9
+	mov	32(vp,%rax,8), %r8
+	ADCSBB	24(up,%rax,8), %r10
+	sbb	R32(%rbx), R32(%rbx)
+	add	$4, %rax
+	mov	%rbp, (rp,%rax,8)	C offset 32
+L(lo0):
+L(lo3):	mov	%r9, 16(rp,%rax,8)	C offset 48
+	jnz	L(top)
+
+L(end):	mov	%r10, 24(rp,%rax,8)
+L(wd1):	shrd	%cl, %r8, %r11
+	add	R32(%rbx), R32(%rbx)
+	ADCSBB	(up,%rax,8), %r11
+	mov	%r11, 32(rp,%rax,8)	C offset 32
+	adc	R32(%rax), R32(%rax)	C rax is zero after loop
+	shr	R8(%rcx), %r8
+	ADDSUB	%r8, %rax
+IFRSB(	neg	%rax)
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
+PROLOGUE(func_nc)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8d	')	C cnt
+IFDOS(`	mov	64(%rsp), %r9	')	C cy
+	push	%rbx
+	neg	cy
+	sbb	R32(%rbx), R32(%rbx)	C initialise CF save register
+	jmp	L(ent)
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/coreinhm/aorsmul_1.asm b/third_party/gmp/mpn/x86_64/coreinhm/aorsmul_1.asm
new file mode 100644
index 0000000..1be829f
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreinhm/aorsmul_1.asm
@@ -0,0 +1,190 @@
+dnl  AMD64 mpn_addmul_1 and mpn_submul_1 optimised for Intel Nehalem.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2003-2005, 2007, 2008, 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C            cycles/limb
+C AMD K8,K9      4.0
+C AMD K10        4.0
+C AMD bull       5.0
+C AMD pile       4.84    5.39
+C AMD steam
+C AMD excavator
+C AMD bobcat     5.56
+C AMD jaguar     5.30
+C Intel P4      15.7    17.2
+C Intel core2    5.15
+C Intel NHM      4.56
+C Intel SBR      3.44
+C Intel HWL      3.03
+C Intel BWL      2.77
+C Intel SKL      2.76
+C Intel atom    21
+C Intel SLM     11
+C VIA nano
+
+C The loop of this code is the result of running a code generation and
+C optimization tool suite written by David Harvey and Torbjorn Granlund.
+
+C N.B.: Be careful if editing, making sure the loop alignment padding does not
+C become large, as we currently fall into it.
+
+define(`rp',      `%rdi')   C rcx
+define(`up',      `%rsi')   C rdx
+define(`n_param', `%rdx')   C r8
+define(`v0',      `%rcx')   C r9
+
+define(`n',       `%rbx')
+
+ifdef(`OPERATION_addmul_1',`
+  define(`ADDSUB', `add')
+  define(`func',   `mpn_addmul_1')
+')
+ifdef(`OPERATION_submul_1',`
+  define(`ADDSUB', `sub')
+  define(`func',   `mpn_submul_1')
+')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_addmul_1 mpn_submul_1)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(func)
+	FUNC_ENTRY(4)
+	push	%rbx
+
+	mov	(up), %rax
+	lea	-8(up,n_param,8), up
+	mov	(rp), %r8
+	lea	-8(rp,n_param,8), rp
+
+	test	$1, R8(n_param)
+	jnz	L(bx1)
+
+L(bx0):	test	$2, R8(n_param)
+	jnz	L(b10)
+
+L(b00):	mov	$3, R32(n)
+	sub	n_param, n
+	mul	v0
+	mov	$0, R32(%r11)
+	mov	%r8, %r10
+	ADDSUB	%rax, %r10
+	mov	-8(up,n,8), %rax
+	adc	%rdx, %r11
+	jmp	L(lo0)
+
+L(b10):	mov	$1, R32(n)
+	sub	n_param, n
+	mul	v0
+	mov	%r8, %r10
+	mov	$0, R32(%r11)
+	ADDSUB	%rax, %r10
+	mov	8(up,n,8), %rax
+	adc	%rdx, %r11
+	jmp	L(lo2)
+
+L(bx1):	test	$2, R8(n_param)
+	jz	L(b01)
+
+L(b11):	mov	$2, R32(n)
+	sub	n_param, n
+	mul	v0
+	ADDSUB	%rax, %r8
+	mov	$0, R32(%r9)
+	mov	(up,n,8), %rax
+	adc	%rdx, %r9
+	jmp	L(lo3)
+
+L(b01):	mov	$0, R32(n)
+	sub	n_param, n
+	xor	%r11, %r11
+	add	$4, n
+	jc	L(end)
+
+	ALIGN(32)
+L(top):	mul	v0
+	ADDSUB	%rax, %r8
+	mov	$0, R32(%r9)
+	mov	-16(up,n,8), %rax
+	adc	%rdx, %r9
+L(lo1):	mul	v0
+	ADDSUB	%r11, %r8
+	mov	$0, R32(%r11)
+	mov	-16(rp,n,8), %r10
+	adc	$0, %r9
+	ADDSUB	%rax, %r10
+	mov	-8(up,n,8), %rax
+	adc	%rdx, %r11
+	mov	%r8, -24(rp,n,8)
+	ADDSUB	%r9, %r10
+	adc	$0, %r11
+L(lo0):	mov	-8(rp,n,8), %r8
+	mul	v0
+	ADDSUB	%rax, %r8
+	mov	$0, R32(%r9)
+	mov	(up,n,8), %rax
+	adc	%rdx, %r9
+	mov	%r10, -16(rp,n,8)
+	ADDSUB	%r11, %r8
+	adc	$0, %r9
+L(lo3):	mul	v0
+	mov	(rp,n,8), %r10
+	mov	$0, R32(%r11)
+	ADDSUB	%rax, %r10
+	mov	8(up,n,8), %rax
+	adc	%rdx, %r11
+	mov	%r8, -8(rp,n,8)
+	ADDSUB	%r9, %r10
+	adc	$0, %r11
+L(lo2):	mov	8(rp,n,8), %r8
+	mov	%r10, (rp,n,8)
+	add	$4, n
+	jnc	L(top)
+
+L(end):	mul	v0
+	ADDSUB	%rax, %r8
+	mov	$0, R32(%rax)
+	adc	%rdx, %rax
+	ADDSUB	%r11, %r8
+	adc	$0, %rax
+	mov	%r8, (rp)
+
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86_64/coreinhm/gmp-mparam.h b/third_party/gmp/mpn/x86_64/coreinhm/gmp-mparam.h
new file mode 100644
index 0000000..f56c128
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreinhm/gmp-mparam.h
@@ -0,0 +1,238 @@
+/* Nehalem gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+/* 2933-3200 MHz Intel Xeon X3470 Nehalem */
+/* FFT tuning limit = 468,424,931 */
+/* Generated by tuneup.c, 2019-10-18, gcc 8.3 */
+
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          3
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          2
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        11
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        16
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD      7
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1_NORM_THRESHOLD              1
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD              10
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           17
+
+#define DIV_1_VS_MUL_1_PERCENT             301
+
+#define MUL_TOOM22_THRESHOLD                18
+#define MUL_TOOM33_THRESHOLD                59
+#define MUL_TOOM44_THRESHOLD               169
+#define MUL_TOOM6H_THRESHOLD               230
+#define MUL_TOOM8H_THRESHOLD               333
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      97
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     110
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     104
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     101
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     147
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 28
+#define SQR_TOOM3_THRESHOLD                 98
+#define SQR_TOOM4_THRESHOLD                250
+#define SQR_TOOM6_THRESHOLD                351
+#define SQR_TOOM8_THRESHOLD                478
+
+#define MULMID_TOOM42_THRESHOLD             28
+
+#define MULMOD_BNM1_THRESHOLD               13
+#define SQRMOD_BNM1_THRESHOLD               13
+
+#define MUL_FFT_MODF_THRESHOLD             372  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    372, 5}, {     17, 6}, {      9, 5}, {     19, 6}, \
+    {     10, 5}, {     21, 6}, {     21, 7}, {     11, 6}, \
+    {     23, 7}, {     21, 8}, {     11, 7}, {     24, 8}, \
+    {     13, 7}, {     27, 8}, {     15, 7}, {     31, 8}, \
+    {     21, 9}, {     11, 8}, {     27, 9}, {     15, 8}, \
+    {     33, 9}, {     19, 8}, {     39, 9}, {     23, 8}, \
+    {     47, 9}, {     27,10}, {     15, 9}, {     39,10}, \
+    {     23, 9}, {     51,11}, {     15,10}, {     31, 9}, \
+    {     67,10}, {     39, 9}, {     83,10}, {     47, 9}, \
+    {     95,10}, {     55,11}, {     31,10}, {     79,11}, \
+    {     47,10}, {     95,12}, {     31, 8}, {    511,10}, \
+    {    135,11}, {     79,10}, {    159, 9}, {    319,11}, \
+    {     95,10}, {    191, 9}, {    383,12}, {     63,11}, \
+    {    127,10}, {    255, 9}, {    511,11}, {    143,10}, \
+    {    287, 9}, {    575,10}, {    303,11}, {    159,10}, \
+    {    319,12}, {     95,11}, {    191,10}, {    383,13}, \
+    {     63,12}, {    127,11}, {    255,10}, {    511,11}, \
+    {    271,10}, {    543,11}, {    287,10}, {    575,11}, \
+    {    303,10}, {    607,11}, {    319,10}, {    639,11}, \
+    {    351,10}, {    703,12}, {    191,11}, {    383,10}, \
+    {    767,11}, {    415,10}, {    831,12}, {    223,11}, \
+    {    447,10}, {    895,13}, {    127,12}, {    255,11}, \
+    {    543,12}, {    287,11}, {    607,12}, {    319,11}, \
+    {    639,12}, {    351,11}, {    703,13}, {    191,12}, \
+    {    383,11}, {    767,12}, {    415,11}, {    831,12}, \
+    {    447,11}, {    895,12}, {    479,14}, {    127,13}, \
+    {    255,12}, {    543,11}, {   1087,12}, {    607,13}, \
+    {    319,12}, {    703,13}, {    383,12}, {    831,13}, \
+    {    447,12}, {    959,14}, {    255,13}, {    511,12}, \
+    {   1087,13}, {    575,12}, {   1215,11}, {   2431,13}, \
+    {    639,12}, {   1279,13}, {    703,12}, {   1407,14}, \
+    {    383,13}, {    831,12}, {   1663,13}, {    959,14}, \
+    {    511,13}, {   1087,12}, {   2175,13}, {   1215,12}, \
+    {   2431,14}, {    639,13}, {   1343,12}, {   2687,13}, \
+    {   1407,12}, {   2815,13}, {   1471,14}, {    767,13}, \
+    {   1663,14}, {    895,13}, {   1791,15}, {    511,14}, \
+    {   1023,13}, {   2175,14}, {   1151,13}, {   2431,12}, \
+    {   4863,14}, {   1279,13}, {   2687,14}, {   1407,13}, \
+    {   2815,15}, {    767,14}, {   1663,13}, {   3455,14}, \
+    {   1919,16}, {    511,15}, {   1023,14}, {   2431,13}, \
+    {   4863,15}, {   1279,14}, {   2943,13}, {   5887,15}, \
+    {   1535,14}, {   3455,15}, {   1791,14}, {   3839,16}, \
+    {   1023,15}, {   2047,14}, {   4223,15}, {   2303,14}, \
+    {   4863,15}, {   2815,14}, {   5887,16}, {   1535,15}, \
+    {   3327,14}, {   6911,15}, {   3839,17}, {   1023,16}, \
+    {   2047,15}, {   4863,16}, {   2559,15}, {   5887,14}, \
+    {  11775,16}, {   3071,15}, {   6911,16}, {   3583,15}, \
+    {   7679,14}, {  15359,17}, {   2047,16}, {   4607,15}, \
+    {   9983,16}, {   5631,15}, {  11775,17}, {   3071,16}, \
+    {  65536,17}, { 131072,18}, { 262144,19}, { 524288,20}, \
+    {1048576,21}, {2097152,22}, {4194304,23}, {8388608,24} }
+#define MUL_FFT_TABLE3_SIZE 204
+#define MUL_FFT_THRESHOLD                 4224
+
+#define SQR_FFT_MODF_THRESHOLD             336  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    336, 5}, {     19, 6}, {     10, 5}, {     21, 6}, \
+    {     21, 7}, {     11, 6}, {     23, 7}, {     21, 8}, \
+    {     11, 7}, {     25, 8}, {     13, 7}, {     27, 8}, \
+    {     15, 7}, {     31, 8}, {     21, 9}, {     11, 8}, \
+    {     27, 9}, {     15, 8}, {     33, 9}, {     19, 8}, \
+    {     39, 9}, {     23, 8}, {     47, 9}, {     27,10}, \
+    {     15, 9}, {     39,10}, {     23, 9}, {     47,11}, \
+    {     15,10}, {     31, 9}, {     67,10}, {     39, 9}, \
+    {     79,10}, {     47,11}, {     31,10}, {     79,11}, \
+    {     47,10}, {     95,12}, {     31,11}, {     63,10}, \
+    {    127, 9}, {    255, 8}, {    511,10}, {    135,11}, \
+    {     79, 9}, {    319, 6}, {   2687, 7}, {   1407, 9}, \
+    {    383,12}, {     63,11}, {    127,10}, {    255, 9}, \
+    {    511,10}, {    271, 9}, {    543,11}, {    143,10}, \
+    {    287, 9}, {    575,10}, {    303, 9}, {    607,10}, \
+    {    319,12}, {     95,11}, {    191,10}, {    383,13}, \
+    {     63,12}, {    127,11}, {    255,10}, {    511,11}, \
+    {    271,10}, {    543,11}, {    287,10}, {    575,11}, \
+    {    303,10}, {    607,11}, {    319,10}, {    639,11}, \
+    {    351,10}, {    703,12}, {    191,11}, {    383,10}, \
+    {    767,11}, {    415,10}, {    831,12}, {    223,11}, \
+    {    447,10}, {    895,11}, {    479,13}, {    127,12}, \
+    {    255,11}, {    511,10}, {   1023,11}, {    543,12}, \
+    {    287,11}, {    607,12}, {    319,11}, {    671,12}, \
+    {    351,11}, {    703,13}, {    191,12}, {    383,11}, \
+    {    767,12}, {    415,11}, {    831,12}, {    447,11}, \
+    {    895,12}, {    479,14}, {    127,13}, {    255,12}, \
+    {    511,11}, {   1023,12}, {    543,11}, {   1087,12}, \
+    {    575,11}, {   1151,12}, {    607,13}, {    319,12}, \
+    {    671,11}, {   1343,12}, {    703,13}, {    383,12}, \
+    {    767,11}, {   1535,12}, {    831,13}, {    447,12}, \
+    {    959,13}, {    511,12}, {   1087,13}, {    575,12}, \
+    {   1215,11}, {   2431,13}, {    639,12}, {   1343,13}, \
+    {    703,14}, {    383,13}, {    767,12}, {   1535,13}, \
+    {    831,12}, {   1663,13}, {    959,14}, {    511,13}, \
+    {   1087,12}, {   2175,13}, {   1215,12}, {   2431,14}, \
+    {    639,13}, {   1343,12}, {   2687,13}, {   1407,12}, \
+    {   2815,13}, {   1471,14}, {    767,13}, {   1663,14}, \
+    {    895,13}, {   1791,15}, {    511,14}, {   1023,13}, \
+    {   2175,14}, {   1151,13}, {   2431,12}, {   4863,14}, \
+    {   1279,13}, {   2687,14}, {   1407,13}, {   2815,15}, \
+    {    767,14}, {   1535,13}, {   3071,14}, {   1663,13}, \
+    {   3455,14}, {   1919,16}, {    511,15}, {   1023,14}, \
+    {   2431,13}, {   4863,15}, {   1279,14}, {   2943,13}, \
+    {   5887,15}, {   1535,14}, {   3455,15}, {   1791,14}, \
+    {   3839,16}, {   1023,15}, {   2047,14}, {   4223,15}, \
+    {   2303,14}, {   4863,15}, {   2815,14}, {   5887,16}, \
+    {   1535,15}, {   3327,14}, {   6911,15}, {   3839,17}, \
+    {   1023,16}, {   2047,15}, {   4863,16}, {   2559,15}, \
+    {   5887,14}, {  11775,16}, {   3071,15}, {   6655,16}, \
+    {   3583,15}, {   7679,14}, {  15359,17}, {   2047,16}, \
+    {   4607,15}, {   9983,14}, {  19967,16}, {   5631,15}, \
+    {  11775,17}, {   3071,16}, {  65536,17}, { 131072,18}, \
+    { 262144,19}, { 524288,20}, {1048576,21}, {2097152,22}, \
+    {4194304,23}, {8388608,24} }
+#define SQR_FFT_TABLE3_SIZE 218
+#define SQR_FFT_THRESHOLD                 3520
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  49
+#define MULLO_MUL_N_THRESHOLD             8397
+#define SQRLO_BASECASE_THRESHOLD            10
+#define SQRLO_DC_THRESHOLD                  11
+#define SQRLO_SQR_THRESHOLD               7035
+
+#define DC_DIV_QR_THRESHOLD                 47
+#define DC_DIVAPPR_Q_THRESHOLD             151
+#define DC_BDIV_QR_THRESHOLD                40
+#define DC_BDIV_Q_THRESHOLD                 30
+
+#define INV_MULMOD_BNM1_THRESHOLD           34
+#define INV_NEWTON_THRESHOLD               199
+#define INV_APPR_THRESHOLD                 157
+
+#define BINV_NEWTON_THRESHOLD              254
+#define REDC_1_TO_REDC_N_THRESHOLD          48
+
+#define MU_DIV_QR_THRESHOLD               1334
+#define MU_DIVAPPR_Q_THRESHOLD            1334
+#define MUPI_DIV_QR_THRESHOLD               83
+#define MU_BDIV_QR_THRESHOLD              1142
+#define MU_BDIV_Q_THRESHOLD               1308
+
+#define POWM_SEC_TABLE  1,64,66,452,1486
+
+#define GET_STR_DC_THRESHOLD                11
+#define GET_STR_PRECOMPUTE_THRESHOLD        18
+#define SET_STR_DC_THRESHOLD               141
+#define SET_STR_PRECOMPUTE_THRESHOLD      1023
+
+#define FAC_DSC_THRESHOLD                  182
+#define FAC_ODD_THRESHOLD                    0  /* always */
+
+#define MATRIX22_STRASSEN_THRESHOLD         19
+#define HGCD2_DIV1_METHOD                    5  /* 2.91% faster than 3 */
+#define HGCD_THRESHOLD                     116
+#define HGCD_APPR_THRESHOLD                164
+#define HGCD_REDUCE_THRESHOLD             2205
+#define GCD_DC_THRESHOLD                   321
+#define GCDEXT_DC_THRESHOLD                358
+#define JACOBI_BASE_METHOD                   4  /* 0.12% faster than 1 */
+
+/* Tuneup completed successfully, took 452116 seconds */
diff --git a/third_party/gmp/mpn/x86_64/coreinhm/hamdist.asm b/third_party/gmp/mpn/x86_64/coreinhm/hamdist.asm
new file mode 100644
index 0000000..a5a63e4
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreinhm/hamdist.asm
@@ -0,0 +1,196 @@
+dnl  AMD64 mpn_hamdist -- hamming distance.
+
+dnl  Copyright 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+C		    cycles/limb
+C AMD K8,K9		 n/a
+C AMD K10		 3.26
+C AMD bd1		 4.2
+C AMD bd2		 4.2
+C AMD bd3		 ?
+C AMD bd4		 ?
+C AMD zen		 1.15
+C AMD bobcat		 7.29
+C AMD jaguar		 2.53
+C Intel P4		 n/a
+C Intel core2		 n/a
+C Intel NHM		 2.03
+C Intel SBR		 1.66
+C Intel IBR		 1.62
+C Intel HWL		 1.50
+C Intel BWL		 1.50
+C Intel SKL		 1.50
+C Intel atom		 n/a
+C Intel SLM		 2.55
+C VIA nano		 n/a
+
+C TODO
+C  * An AVX pshufb based variant should approach 0.5 c/l on Haswell and later
+C    Intel hardware.  Perhaps mix such a loop with popcnt instructions.
+C  * The random placement of the L0, L1, L2, etc blocks are due to branch
+C    shortening.  More work could be done there.
+C  * Combine the accumulators rax and rcx into one register to save some
+C    bookkeeping and a push/pop pair.  Unfortunately this cause a slight
+C    slowdown for at leat NHM and SBR.
+
+define(`up',		`%rdi')
+define(`vp',		`%rsi')
+define(`n',		`%rdx')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+define(`sum', `lea	($1,$2), $2')
+define(`sum', `add	$1, $2')
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_hamdist)
+	FUNC_ENTRY(3)
+	push	%rbx
+	push	%rbp
+
+	mov	(up), %r10
+	xor	(vp), %r10
+
+	mov	R32(n), R32(%r8)
+	and	$3, R32(%r8)
+
+	xor	R32(%rcx), R32(%rcx)
+	.byte	0xf3,0x49,0x0f,0xb8,0xc2	C popcnt %r10,%rax
+
+	lea	L(tab)(%rip), %r9
+ifdef(`PIC',`
+	movslq	(%r9,%r8,4), %r8
+	add	%r9, %r8
+	jmp	*%r8
+',`
+	jmp	*(%r9,%r8,8)
+')
+
+L(3):	mov	8(up), %r10
+	mov	16(up), %r11
+	xor	8(vp), %r10
+	xor	16(vp), %r11
+	xor	R32(%rbp), R32(%rbp)
+	sub	$4, n
+	jle	L(x3)
+	mov	24(up), %r8
+	mov	32(up), %r9
+	add	$24, up
+	add	$24, vp
+	jmp	L(e3)
+
+L(0):	mov	8(up), %r9
+	xor	8(vp), %r9
+	mov	16(up), %r10
+	mov	24(up), %r11
+	xor	R32(%rbx), R32(%rbx)
+	xor	16(vp), %r10
+	xor	24(vp), %r11
+	add	$32, up
+	add	$32, vp
+	sub	$4, n
+	jle	L(x4)
+
+	ALIGN(16)
+L(top):
+L(e0):	.byte	0xf3,0x49,0x0f,0xb8,0xe9	C popcnt %r9,%rbp
+	mov	(up), %r8
+	mov	8(up), %r9
+	sum(	%rbx, %rax)
+L(e3):	.byte	0xf3,0x49,0x0f,0xb8,0xda	C popcnt %r10,%rbx
+	xor	(vp), %r8
+	xor	8(vp), %r9
+	sum(	%rbp, %rcx)
+L(e2):	.byte	0xf3,0x49,0x0f,0xb8,0xeb	C popcnt %r11,%rbp
+	mov	16(up), %r10
+	mov	24(up), %r11
+	add	$32, up
+	sum(	%rbx, %rax)
+L(e1):	.byte	0xf3,0x49,0x0f,0xb8,0xd8	C popcnt %r8,%rbx
+	xor	16(vp), %r10
+	xor	24(vp), %r11
+	add	$32, vp
+	sum(	%rbp, %rcx)
+	sub	$4, n
+	jg	L(top)
+
+L(x4):	.byte	0xf3,0x49,0x0f,0xb8,0xe9	C popcnt %r9,%rbp
+	sum(	%rbx, %rax)
+L(x3):	.byte	0xf3,0x49,0x0f,0xb8,0xda	C popcnt %r10,%rbx
+	sum(	%rbp, %rcx)
+	.byte	0xf3,0x49,0x0f,0xb8,0xeb	C popcnt %r11,%rbp
+	sum(	%rbx, %rax)
+	sum(	%rbp, %rcx)
+L(x2):	add	%rcx, %rax
+L(x1):	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+
+L(2):	mov	8(up), %r11
+	xor	8(vp), %r11
+	sub	$2, n
+	jle	L(n2)
+	mov	16(up), %r8
+	mov	24(up), %r9
+	xor	R32(%rbx), R32(%rbx)
+	xor	16(vp), %r8
+	xor	24(vp), %r9
+	add	$16, up
+	add	$16, vp
+	jmp	L(e2)
+L(n2):	.byte	0xf3,0x49,0x0f,0xb8,0xcb	C popcnt %r11,%rcx
+	jmp	L(x2)
+
+L(1):	dec	n
+	jle	L(x1)
+	mov	8(up), %r8
+	mov	16(up), %r9
+	xor	8(vp), %r8
+	xor	16(vp), %r9
+	xor	R32(%rbp), R32(%rbp)
+	mov	24(up), %r10
+	mov	32(up), %r11
+	add	$40, up
+	add	$8, vp
+	jmp	L(e1)
+
+EPILOGUE()
+	JUMPTABSECT
+	ALIGN(8)
+L(tab):	JMPENT(	L(0), L(tab))
+	JMPENT(	L(1), L(tab))
+	JMPENT(	L(2), L(tab))
+	JMPENT(	L(3), L(tab))
diff --git a/third_party/gmp/mpn/x86_64/coreinhm/popcount.asm b/third_party/gmp/mpn/x86_64/coreinhm/popcount.asm
new file mode 100644
index 0000000..0a3c867
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreinhm/popcount.asm
@@ -0,0 +1,182 @@
+dnl  AMD64 mpn_popcount -- population count.
+
+dnl  Copyright 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+C		    cycles/limb
+C AMD K8,K9		 n/a
+C AMD K10		 1.39
+C AMD bd1		 4
+C AMD bd2		 4
+C AMD bd3		 ?
+C AMD bd4		 ?
+C AMD zen		 0.72
+C AMD bobcat		 5.78
+C AMD jaguar		 1.27
+C Intel P4		 n/a
+C Intel core2		 n/a
+C Intel NHM		 1.04
+C Intel SBR		 1.02
+C Intel IBR		 1.0
+C Intel HWL		 1.0
+C Intel BWL		 1.0
+C Intel SKL		 1.0
+C Intel atom		 n/a
+C Intel SLM		 1.34
+C VIA nano		 n/a
+
+C TODO
+C  * We could approach 0.5 c/l for AMD Zen with more unrolling.  That would
+C    not cause any additional feed-in overhead as we already use a jump table.
+C  * An AVX pshufb based variant should approach 0.5 c/l on Haswell and later
+C    Intel hardware.  Perhaps mix such a loop with popcnt instructions.
+C  * The random placement of the L0, L1, L2, etc blocks are due to branch
+C    shortening.
+
+define(`up',		`%rdi')
+define(`n',		`%rsi')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_popcount)
+	FUNC_ENTRY(2)
+
+	mov	R32(n), R32(%r8)
+	and	$7, R32(%r8)
+
+	.byte	0xf3,0x48,0x0f,0xb8,0x07	C popcnt (up), %rax
+	xor	R32(%rcx), R32(%rcx)
+
+	lea	L(tab)(%rip), %r9
+ifdef(`PIC',`
+	movslq	(%r9,%r8,4), %r8
+	add	%r9, %r8
+	jmp	*%r8
+',`
+	jmp	*(%r9,%r8,8)
+')
+
+L(3):	.byte	0xf3,0x4c,0x0f,0xb8,0x57,0x08	C popcnt 8(up), %r10
+	.byte	0xf3,0x4c,0x0f,0xb8,0x5f,0x10	C popcnt 16(up), %r11
+	add	$24, up
+	sub	$8, n
+	jg	L(e34)
+	add	%r10, %rax
+	add	%r11, %rax
+L(s1):	FUNC_EXIT()
+	ret
+
+L(1):	sub	$8, n
+	jle	L(s1)
+	.byte	0xf3,0x4c,0x0f,0xb8,0x47,0x08	C popcnt 8(up), %r8
+	.byte	0xf3,0x4c,0x0f,0xb8,0x4f,0x10	C popcnt 16(up), %r9
+	add	$8, up
+	jmp	L(e12)
+
+L(7):	.byte	0xf3,0x4c,0x0f,0xb8,0x57,0x08	C popcnt 0x8(%rdi),%r10
+	.byte	0xf3,0x4c,0x0f,0xb8,0x5f,0x10	C popcnt 0x10(%rdi),%r11
+	add	$-8, up
+	jmp	L(e07)
+
+L(0):	.byte	0xf3,0x48,0x0f,0xb8,0x4f,0x08	C popcnt 0x8(%rdi),%rcx
+	.byte	0xf3,0x4c,0x0f,0xb8,0x57,0x10	C popcnt 0x10(%rdi),%r10
+	.byte	0xf3,0x4c,0x0f,0xb8,0x5f,0x18	C popcnt 0x18(%rdi),%r11
+	jmp	L(e07)
+
+L(4):	.byte	0xf3,0x48,0x0f,0xb8,0x4f,0x08	C popcnt 0x8(%rdi),%rcx
+	.byte	0xf3,0x4c,0x0f,0xb8,0x57,0x10	C popcnt 0x10(%rdi),%r10
+	.byte	0xf3,0x4c,0x0f,0xb8,0x5f,0x18	C popcnt 0x18(%rdi),%r11
+	add	$32, up
+	sub	$8, n
+	jle	L(x4)
+
+	ALIGN(16)
+L(top):
+L(e34):	.byte	0xf3,0x4c,0x0f,0xb8,0x07	C popcnt (%rdi),%r8
+	.byte	0xf3,0x4c,0x0f,0xb8,0x4f,0x08	C popcnt 0x8(%rdi),%r9
+	add	%r10, %rcx
+	add	%r11, %rax
+L(e12):	.byte	0xf3,0x4c,0x0f,0xb8,0x57,0x10	C popcnt 0x10(%rdi),%r10
+	.byte	0xf3,0x4c,0x0f,0xb8,0x5f,0x18	C popcnt 0x18(%rdi),%r11
+	add	%r8, %rcx
+	add	%r9, %rax
+L(e07):	.byte	0xf3,0x4c,0x0f,0xb8,0x47,0x20	C popcnt 0x20(%rdi),%r8
+	.byte	0xf3,0x4c,0x0f,0xb8,0x4f,0x28	C popcnt 0x28(%rdi),%r9
+	add	%r10, %rcx
+	add	%r11, %rax
+L(e56):	.byte	0xf3,0x4c,0x0f,0xb8,0x57,0x30	C popcnt 0x30(%rdi),%r10
+	.byte	0xf3,0x4c,0x0f,0xb8,0x5f,0x38	C popcnt 0x38(%rdi),%r11
+	add	$64, up
+	add	%r8, %rcx
+	add	%r9, %rax
+	sub	$8, n
+	jg	L(top)
+
+L(x4):	add	%r10, %rcx
+	add	%r11, %rax
+L(x2):	add	%rcx, %rax
+
+	FUNC_EXIT()
+	ret
+
+L(2):	.byte	0xf3,0x48,0x0f,0xb8,0x4f,0x08	C popcnt 0x8(%rdi),%rcx
+	sub	$8, n
+	jle	L(x2)
+	.byte	0xf3,0x4c,0x0f,0xb8,0x47,0x10	C popcnt 0x10(%rdi),%r8
+	.byte	0xf3,0x4c,0x0f,0xb8,0x4f,0x18	C popcnt 0x18(%rdi),%r9
+	add	$16, up
+	jmp	L(e12)
+
+L(5):	.byte	0xf3,0x4c,0x0f,0xb8,0x47,0x08	C popcnt 0x8(%rdi),%r8
+	.byte	0xf3,0x4c,0x0f,0xb8,0x4f,0x10	C popcnt 0x10(%rdi),%r9
+	add	$-24, up
+	jmp	L(e56)
+
+L(6):	.byte	0xf3,0x48,0x0f,0xb8,0x4f,0x08	C popcnt 0x8(%rdi),%rcx
+	.byte	0xf3,0x4c,0x0f,0xb8,0x47,0x10	C popcnt 0x10(%rdi),%r8
+	.byte	0xf3,0x4c,0x0f,0xb8,0x4f,0x18	C popcnt 0x18(%rdi),%r9
+	add	$-16, up
+	jmp	L(e56)
+EPILOGUE()
+	JUMPTABSECT
+	ALIGN(8)
+L(tab):	JMPENT(	L(0), L(tab))
+	JMPENT(	L(1), L(tab))
+	JMPENT(	L(2), L(tab))
+	JMPENT(	L(3), L(tab))
+	JMPENT(	L(4), L(tab))
+	JMPENT(	L(5), L(tab))
+	JMPENT(	L(6), L(tab))
+	JMPENT(	L(7), L(tab))
diff --git a/third_party/gmp/mpn/x86_64/coreinhm/redc_1.asm b/third_party/gmp/mpn/x86_64/coreinhm/redc_1.asm
new file mode 100644
index 0000000..fc71c1b
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreinhm/redc_1.asm
@@ -0,0 +1,549 @@
+dnl  X86-64 mpn_redc_1 optimised for Intel Nehalem and Westmere.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2003-2005, 2007, 2008, 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 ?
+C AMD K10	 ?
+C AMD bull	 ?
+C AMD pile	 ?
+C AMD steam	 ?
+C AMD bobcat	 ?
+C AMD jaguar	 ?
+C Intel P4	 ?
+C Intel core	 ?
+C Intel NHM	 ?
+C Intel SBR	 ?
+C Intel IBR	 ?
+C Intel HWL	 ?
+C Intel BWL	 ?
+C Intel atom	 ?
+C VIA nano	 ?
+
+C The inner loops of this code are the result of running a code generation and
+C optimisation tool suite written by David Harvey and Torbjörn Granlund.
+
+C TODO
+C  * Micro-optimise, none performed thus far.
+C  * Consider inlining mpn_add_n.
+C  * Single basecases out before the pushes.
+
+C When playing with pointers, set this to $2 to fall back to conservative
+C indexing in wind-down code.
+define(`I',`$1')
+
+define(`rp',          `%rdi')   C rcx
+define(`up',          `%rsi')   C rdx
+define(`mp_param',    `%rdx')   C r8
+define(`n',           `%rcx')   C r9
+define(`u0inv',       `%r8')    C stack
+
+define(`i',           `%r14')
+define(`j',           `%r15')
+define(`mp',          `%r12')
+define(`q0',          `%r13')
+
+C rax rbx rcx rdx rdi rsi rbp r8 r9 r10 r11 r12 r13 r14 r15
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+define(`ALIGNx', `ALIGN(16)')
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_redc_1)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8	')
+	push	%rbx
+	push	%rbp
+	push	%r12
+	push	%r13
+	push	%r14
+	push	%r15
+
+	mov	(up), q0
+	mov	n, j			C outer loop induction var
+	lea	(mp_param,n,8), mp
+	lea	(up,n,8), up
+	neg	n
+	imul	u0inv, q0		C first iteration q0
+
+	test	$1, R8(n)
+	jz	L(bx0)
+
+L(bx1):	test	$2, R8(n)
+	jz	L(b3)
+
+L(b1):	cmp	$-1, R32(n)
+	jz	L(n1)
+
+L(otp1):lea	3(n), i
+	mov	(mp,n,8), %rax
+	mov	(up,n,8), %rbp
+	mul	q0
+	add	%rax, %rbp
+	mov	$0, R32(%r9)
+	mov	8(mp,n,8), %rax
+	adc	%rdx, %r9
+	mul	q0
+	mov	$0, R32(%r11)
+	mov	8(up,n,8), %rbx
+	add	%rax, %rbx
+	mov	16(mp,n,8), %rax
+	adc	%rdx, %r11
+	add	%r9, %rbx
+	adc	$0, %r11
+	mov	16(up,n,8), %rbp
+	mul	q0
+	add	%rax, %rbp
+	mov	$0, R32(%r9)
+	mov	24(mp,n,8), %rax
+	adc	%rdx, %r9
+	mov	%rbx, 8(up,n,8)
+	imul	u0inv, %rbx		C next q limb
+	jmp	L(e1)
+
+	ALIGNx
+L(tp1):	mul	q0
+	add	%rax, %rbp
+	mov	$0, R32(%r9)
+	mov	-16(mp,i,8), %rax
+	adc	%rdx, %r9
+	mul	q0
+	add	%r11, %rbp
+	mov	$0, R32(%r11)
+	mov	-16(up,i,8), %r10
+	adc	$0, %r9
+	add	%rax, %r10
+	mov	-8(mp,i,8), %rax
+	adc	%rdx, %r11
+	mov	%rbp, -24(up,i,8)
+	add	%r9, %r10
+	adc	$0, %r11
+	mov	-8(up,i,8), %rbp
+	mul	q0
+	add	%rax, %rbp
+	mov	$0, R32(%r9)
+	mov	(mp,i,8), %rax
+	adc	%rdx, %r9
+	mov	%r10, -16(up,i,8)
+L(e1):	add	%r11, %rbp
+	adc	$0, %r9
+	mul	q0
+	mov	(up,i,8), %r10
+	mov	$0, R32(%r11)
+	add	%rax, %r10
+	mov	8(mp,i,8), %rax
+	adc	%rdx, %r11
+	mov	%rbp, -8(up,i,8)
+	add	%r9, %r10
+	adc	$0, %r11
+	mov	8(up,i,8), %rbp
+	mov	%r10, (up,i,8)
+	add	$4, i
+	jnc	L(tp1)
+
+L(ed1):	mul	q0
+	add	%rax, %rbp
+	adc	$0, %rdx
+	add	%r11, %rbp
+	adc	$0, %rdx
+	mov	%rbp, I(-8(up),-24(up,i,8))
+	mov	%rdx, (up,n,8)		C up[0]
+	mov	%rbx, q0		C previously computed q limb -> q0
+	lea	8(up), up		C up++
+	dec	j
+	jnz	L(otp1)
+	jmp	L(cj)
+
+L(b3):	cmp	$-3, R32(n)
+	jz	L(n3)
+
+L(otp3):lea	5(n), i
+	mov	(mp,n,8), %rax
+	mov	(up,n,8), %rbp
+	mul	q0
+	add	%rax, %rbp
+	mov	$0, R32(%r9)
+	mov	8(mp,n,8), %rax
+	adc	%rdx, %r9
+	mul	q0
+	mov	8(up,n,8), %rbx
+	mov	$0, R32(%r11)
+	add	%rax, %rbx
+	mov	16(mp,n,8), %rax
+	adc	%rdx, %r11
+	add	%r9, %rbx
+	adc	$0, %r11
+	mov	16(up,n,8), %rbp
+	mov	%rbx, 8(up,n,8)
+	imul	u0inv, %rbx		C next q limb
+C	jmp	L(tp3)
+
+	ALIGNx
+L(tp3):	mul	q0
+	add	%rax, %rbp
+	mov	$0, R32(%r9)
+	mov	-16(mp,i,8), %rax
+	adc	%rdx, %r9
+	mul	q0
+	add	%r11, %rbp
+	mov	$0, R32(%r11)
+	mov	-16(up,i,8), %r10
+	adc	$0, %r9
+	add	%rax, %r10
+	mov	-8(mp,i,8), %rax
+	adc	%rdx, %r11
+	mov	%rbp, -24(up,i,8)
+	add	%r9, %r10
+	adc	$0, %r11
+	mov	-8(up,i,8), %rbp
+	mul	q0
+	add	%rax, %rbp
+	mov	$0, R32(%r9)
+	mov	(mp,i,8), %rax
+	adc	%rdx, %r9
+	mov	%r10, -16(up,i,8)
+	add	%r11, %rbp
+	adc	$0, %r9
+	mul	q0
+	mov	(up,i,8), %r10
+	mov	$0, R32(%r11)
+	add	%rax, %r10
+	mov	8(mp,i,8), %rax
+	adc	%rdx, %r11
+	mov	%rbp, -8(up,i,8)
+	add	%r9, %r10
+	adc	$0, %r11
+	mov	8(up,i,8), %rbp
+	mov	%r10, (up,i,8)
+	add	$4, i
+	jnc	L(tp3)
+
+L(ed3):	mul	q0
+	add	%rax, %rbp
+	adc	$0, %rdx
+	add	%r11, %rbp
+	adc	$0, %rdx
+	mov	%rbp, I(-8(up),-24(up,i,8))
+	mov	%rdx, (up,n,8)		C up[0]
+	mov	%rbx, q0		C previously computed q limb -> q0
+	lea	8(up), up		C up++
+	dec	j
+	jnz	L(otp3)
+C	jmp	L(cj)
+
+L(cj):
+IFSTD(`	lea	(up,n,8), up		C param 2: up
+	lea	(up,n,8), %rdx		C param 3: up - n
+	neg	R32(n)		')	C param 4: n
+
+IFDOS(`	lea	(up,n,8), %rdx		C param 2: up
+	lea	(%rdx,n,8), %r8		C param 3: up - n
+	neg	R32(n)
+	mov	n, %r9			C param 4: n
+	mov	rp, %rcx	')	C param 1: rp
+
+IFSTD(`	sub	$8, %rsp	')
+IFDOS(`	sub	$40, %rsp	')
+	ASSERT(nz, `test $15, %rsp')
+	CALL(	mpn_add_n)
+IFSTD(`	add	$8, %rsp	')
+IFDOS(`	add	$40, %rsp	')
+
+L(ret):	pop	%r15
+	pop	%r14
+	pop	%r13
+	pop	%r12
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+
+L(bx0):	test	$2, R8(n)
+	jnz	L(b2)
+
+L(b0):
+L(otp0):lea	2(n), i
+	mov	(mp,n,8), %rax
+	mul	q0
+	mov	$0, R32(%r11)
+	mov	(up,n,8), %r10
+	add	%rax, %r10
+	mov	8(mp,n,8), %rax
+	adc	%rdx, %r11
+	mov	8(up,n,8), %rbx
+	mul	q0
+	add	%rax, %rbx
+	mov	$0, R32(%r9)
+	mov	16(mp,n,8), %rax
+	adc	%rdx, %r9
+	add	%r11, %rbx
+	adc	$0, %r9
+	mul	q0
+	mov	16(up,n,8), %r10
+	mov	$0, R32(%r11)
+	add	%rax, %r10
+	mov	24(mp,n,8), %rax
+	adc	%rdx, %r11
+	mov	%rbx, 8(up,n,8)
+	imul	u0inv, %rbx		C next q limb
+	jmp	L(e0)
+
+	ALIGNx
+L(tp0):	mul	q0
+	add	%rax, %rbp
+	mov	$0, R32(%r9)
+	mov	-16(mp,i,8), %rax
+	adc	%rdx, %r9
+	mul	q0
+	add	%r11, %rbp
+	mov	$0, R32(%r11)
+	mov	-16(up,i,8), %r10
+	adc	$0, %r9
+	add	%rax, %r10
+	mov	-8(mp,i,8), %rax
+	adc	%rdx, %r11
+	mov	%rbp, -24(up,i,8)
+	add	%r9, %r10
+	adc	$0, %r11
+	mov	-8(up,i,8), %rbp
+	mul	q0
+	add	%rax, %rbp
+	mov	$0, R32(%r9)
+	mov	(mp,i,8), %rax
+	adc	%rdx, %r9
+	mov	%r10, -16(up,i,8)
+	add	%r11, %rbp
+	adc	$0, %r9
+	mul	q0
+	mov	(up,i,8), %r10
+	mov	$0, R32(%r11)
+	add	%rax, %r10
+	mov	8(mp,i,8), %rax
+	adc	%rdx, %r11
+	mov	%rbp, -8(up,i,8)
+L(e0):	add	%r9, %r10
+	adc	$0, %r11
+	mov	8(up,i,8), %rbp
+	mov	%r10, (up,i,8)
+	add	$4, i
+	jnc	L(tp0)
+
+L(ed0):	mul	q0
+	add	%rax, %rbp
+	adc	$0, %rdx
+	add	%r11, %rbp
+	adc	$0, %rdx
+	mov	%rbp, I(-8(up),-24(up,i,8))
+	mov	%rdx, (up,n,8)		C up[0]
+	mov	%rbx, q0		C previously computed q limb -> q0
+	lea	8(up), up		C up++
+	dec	j
+	jnz	L(otp0)
+	jmp	L(cj)
+
+L(b2):	cmp	$-2, R32(n)
+	jz	L(n2)
+
+L(otp2):lea	4(n), i
+	mov	(mp,n,8), %rax
+	mul	q0
+	mov	(up,n,8), %r10
+	mov	$0, R32(%r11)
+	add	%rax, %r10
+	mov	8(mp,n,8), %rax
+	adc	%rdx, %r11
+	mov	8(up,n,8), %rbx
+	mul	q0
+	add	%rax, %rbx
+	mov	$0, R32(%r9)
+	mov	16(mp,n,8), %rax
+	adc	%rdx, %r9
+	mul	q0
+	add	%r11, %rbx
+	mov	$0, R32(%r11)
+	mov	16(up,n,8), %r10
+	adc	$0, %r9
+	add	%rax, %r10
+	mov	24(mp,n,8), %rax
+	adc	%rdx, %r11
+	mov	%rbx, 8(up,n,8)
+	imul	u0inv, %rbx		C next q limb
+	jmp	L(e2)
+
+	ALIGNx
+L(tp2):	mul	q0
+	add	%rax, %rbp
+	mov	$0, R32(%r9)
+	mov	-16(mp,i,8), %rax
+	adc	%rdx, %r9
+	mul	q0
+	add	%r11, %rbp
+	mov	$0, R32(%r11)
+	mov	-16(up,i,8), %r10
+	adc	$0, %r9
+	add	%rax, %r10
+	mov	-8(mp,i,8), %rax
+	adc	%rdx, %r11
+	mov	%rbp, -24(up,i,8)
+L(e2):	add	%r9, %r10
+	adc	$0, %r11
+	mov	-8(up,i,8), %rbp
+	mul	q0
+	add	%rax, %rbp
+	mov	$0, R32(%r9)
+	mov	(mp,i,8), %rax
+	adc	%rdx, %r9
+	mov	%r10, -16(up,i,8)
+	add	%r11, %rbp
+	adc	$0, %r9
+	mul	q0
+	mov	(up,i,8), %r10
+	mov	$0, R32(%r11)
+	add	%rax, %r10
+	mov	8(mp,i,8), %rax
+	adc	%rdx, %r11
+	mov	%rbp, -8(up,i,8)
+	add	%r9, %r10
+	adc	$0, %r11
+	mov	8(up,i,8), %rbp
+	mov	%r10, (up,i,8)
+	add	$4, i
+	jnc	L(tp2)
+
+L(ed2):	mul	q0
+	add	%rax, %rbp
+	adc	$0, %rdx
+	add	%r11, %rbp
+	adc	$0, %rdx
+	mov	%rbp, I(-8(up),-24(up,i,8))
+	mov	%rdx, (up,n,8)		C up[0]
+	mov	%rbx, q0		C previously computed q limb -> q0
+	lea	8(up), up		C up++
+	dec	j
+	jnz	L(otp2)
+	jmp	L(cj)
+
+L(n1):	mov	(mp_param), %rax
+	mul	q0
+	add	-8(up), %rax
+	adc	(up), %rdx
+	mov	%rdx, (rp)
+	mov	$0, R32(%rax)
+	adc	R32(%rax), R32(%rax)
+	jmp	L(ret)
+
+L(n2):	mov	(mp_param), %rax
+	mov	-16(up), %rbp
+	mul	q0
+	add	%rax, %rbp
+	mov	%rdx, %r9
+	adc	$0, %r9
+	mov	-8(mp), %rax
+	mov	-8(up), %r10
+	mul	q0
+	add	%rax, %r10
+	mov	%rdx, %r11
+	adc	$0, %r11
+	add	%r9, %r10
+	adc	$0, %r11
+	mov	%r10, q0
+	imul	u0inv, q0		C next q0
+	mov	-16(mp), %rax
+	mul	q0
+	add	%rax, %r10
+	mov	%rdx, %r9
+	adc	$0, %r9
+	mov	-8(mp), %rax
+	mov	(up), %r14
+	mul	q0
+	add	%rax, %r14
+	adc	$0, %rdx
+	add	%r9, %r14
+	adc	$0, %rdx
+	xor	R32(%rax), R32(%rax)
+	add	%r11, %r14
+	adc	8(up), %rdx
+	mov	%r14, (rp)
+	mov	%rdx, 8(rp)
+	adc	R32(%rax), R32(%rax)
+	jmp	L(ret)
+
+	ALIGNx
+L(n3):	mov	-24(mp), %rax
+	mov	-24(up), %r10
+	mul	q0
+	add	%rax, %r10
+	mov	-16(mp), %rax
+	mov	%rdx, %r11
+	adc	$0, %r11
+	mov	-16(up), %rbp
+	mul	q0
+	add	%rax, %rbp
+	mov	%rdx, %r9
+	adc	$0, %r9
+	mov	-8(mp), %rax
+	add	%r11, %rbp
+	mov	-8(up), %r10
+	adc	$0, %r9
+	mul	q0
+	mov	%rbp, q0
+	imul	u0inv, q0		C next q0
+	add	%rax, %r10
+	mov	%rdx, %r11
+	adc	$0, %r11
+	mov	%rbp, -16(up)
+	add	%r9, %r10
+	adc	$0, %r11
+	mov	%r10, -8(up)
+	mov	%r11, -24(up)		C up[0]
+	lea	8(up), up		C up++
+	dec	j
+	jnz	L(n3)
+
+	mov	-48(up), %rdx
+	mov	-40(up), %rbx
+	xor	R32(%rax), R32(%rax)
+	add	%rbp, %rdx
+	adc	%r10, %rbx
+	adc	-8(up), %r11
+	mov	%rdx, (rp)
+	mov	%rbx, 8(rp)
+	mov	%r11, 16(rp)
+	adc	R32(%rax), R32(%rax)
+	jmp	L(ret)
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86_64/coreinhm/sec_tabselect.asm b/third_party/gmp/mpn/x86_64/coreinhm/sec_tabselect.asm
new file mode 100644
index 0000000..e436034
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreinhm/sec_tabselect.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_sec_tabselect.
+
+dnl  Copyright 2012, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_sec_tabselect)
+include_mpn(`x86_64/fastsse/sec_tabselect.asm')
diff --git a/third_party/gmp/mpn/x86_64/coreisbr/addmul_2.asm b/third_party/gmp/mpn/x86_64/coreisbr/addmul_2.asm
new file mode 100644
index 0000000..21f0bf4
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreisbr/addmul_2.asm
@@ -0,0 +1,224 @@
+dnl  AMD64 mpn_addmul_2 optimised for Intel Sandy Bridge.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2003-2005, 2007, 2008, 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb	best
+C AMD K8,K9
+C AMD K10
+C AMD bull
+C AMD pile
+C AMD bobcat
+C AMD jaguar
+C Intel P4
+C Intel core
+C Intel NHM
+C Intel SBR	 2.93		this
+C Intel IBR	 2.66		this
+C Intel HWL	 2.5		 2.15
+C Intel BWL
+C Intel atom
+C VIA nano
+
+C This code is the result of running a code generation and optimisation tool
+C suite written by David Harvey and Torbjorn Granlund.
+
+C When playing with pointers, set this to $2 to fall back to conservative
+C indexing in wind-down code.
+define(`I',`$1')
+
+
+define(`rp',      `%rdi')   C rcx
+define(`up',      `%rsi')   C rdx
+define(`n_param', `%rdx')   C r8
+define(`vp',      `%rcx')   C r9
+
+define(`n',	  `%rcx')
+define(`v0',      `%rbx')
+define(`v1',      `%rbp')
+define(`w0',      `%r8')
+define(`w1',      `%r9')
+define(`w2',      `%r10')
+define(`w3',      `%r11')
+define(`X0',      `%r12')
+define(`X1',      `%r13')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_addmul_2)
+	FUNC_ENTRY(4)
+	push	%rbx
+	push	%rbp
+	push	%r12
+	push	%r13
+
+	mov	(vp), v0
+	mov	8(vp), v1
+
+	mov	(up), %rax
+
+	mov	n_param, n
+	neg	n
+
+	lea	(up,n_param,8), up
+	lea	8(rp,n_param,8), rp
+	mul	v0
+
+	test	$1, R8(n)
+	jnz	L(bx1)
+
+L(bx0):	mov	-8(rp,n,8), X0
+	mov	%rdx, w1
+	add	%rax, X0
+	adc	$0, w1
+	mov	(up,n,8), %rax
+	xor	w0, w0
+	xor	w3, w3
+	test	$2, R8(n)
+	jnz	L(b10)
+
+L(b00):	nop				C this nop make loop go faster on SBR!
+	mul	v1
+	mov	(rp,n,8), X1
+	jmp	L(lo0)
+
+L(b10):	lea	-2(n), n
+	jmp	L(lo2)
+
+L(bx1):	mov	-8(rp,n,8), X1
+	mov	%rdx, w3
+	add	%rax, X1
+	adc	$0, w3
+	mov	(up,n,8), %rax
+	xor	w1, w1
+	xor	w2, w2
+	test	$2, R8(n)
+	jz	L(b11)
+
+L(b01):	mov	(rp,n,8), X0
+	inc	n
+	jmp	L(lo1)
+
+L(b11):	dec	n
+	jmp	L(lo3)
+
+	ALIGN(32)
+L(top):
+L(lo1):	mul	v1
+	mov	%rdx, w0		C 1
+	add	%rax, X0		C 0
+	adc	$0, w0			C 1
+	add	w1, X1			C 3
+	adc	$0, w3			C 0
+	add	w2, X0			C 0
+	adc	$0, w0			C 1
+	mov	(up,n,8), %rax
+	mul	v0
+	add	%rax, X0		C 0
+	mov	%rdx, w1		C 1
+	adc	$0, w1			C 1
+	mov	(up,n,8), %rax
+	mul	v1
+	mov	X1, -16(rp,n,8)		C 3
+	mov	(rp,n,8), X1		C 1
+	add	w3, X0			C 0
+	adc	$0, w1			C 1
+L(lo0):	mov	%rdx, w2		C 2
+	mov	X0, -8(rp,n,8)		C 0
+	add	%rax, X1		C 1
+	adc	$0, w2			C 2
+	mov	8(up,n,8), %rax
+	add	w0, X1			C 1
+	adc	$0, w2			C 2
+	mul	v0
+	add	%rax, X1		C 1
+	mov	%rdx, w3		C 2
+	adc	$0, w3			C 2
+	mov	8(up,n,8), %rax
+L(lo3):	mul	v1
+	add	w1, X1			C 1
+	mov	8(rp,n,8), X0		C 2
+	adc	$0, w3			C 2
+	mov	%rdx, w0		C 3
+	add	%rax, X0		C 2
+	adc	$0, w0			C 3
+	mov	16(up,n,8), %rax
+	mul	v0
+	add	w2, X0			C 2
+	mov	X1, (rp,n,8)		C 1
+	mov	%rdx, w1		C 3
+	adc	$0, w0			C 3
+	add	%rax, X0		C 2
+	adc	$0, w1			C 3
+	mov	16(up,n,8), %rax
+	add	w3, X0			C 2
+	adc	$0, w1			C 3
+L(lo2):	mul	v1
+	mov	16(rp,n,8), X1		C 3
+	add	%rax, X1		C 3
+	mov	%rdx, w2		C 4
+	adc	$0, w2			C 4
+	mov	24(up,n,8), %rax
+	mov	X0, 8(rp,n,8)		C 2
+	mul	v0
+	add	w0, X1			C 3
+	mov	%rdx, w3		C 4
+	adc	$0, w2			C 4
+	add	%rax, X1		C 3
+	mov	24(up,n,8), %rax
+	mov	24(rp,n,8), X0		C 0	useless but harmless final read
+	adc	$0, w3			C 4
+	add	$4, n
+	jnc	L(top)
+
+L(end):	mul	v1
+	add	w1, X1
+	adc	$0, w3
+	add	w2, %rax
+	adc	$0, %rdx
+	mov	X1, I(-16(rp),-16(rp,n,8))
+	add	w3, %rax
+	adc	$0, %rdx
+	mov	%rax, I(-8(rp),-8(rp,n,8))
+	mov	%rdx, %rax
+
+	pop	%r13
+	pop	%r12
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/coreisbr/aorrlsh1_n.asm b/third_party/gmp/mpn/x86_64/coreisbr/aorrlsh1_n.asm
new file mode 100644
index 0000000..2319a80
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreisbr/aorrlsh1_n.asm
@@ -0,0 +1,54 @@
+dnl  AMD64 mpn_addlsh1_n -- rp[] = up[] + (vp[] << 1)
+dnl  AMD64 mpn_rsblsh1_n -- rp[] = (vp[] << 1) - up[]
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2008, 2010-2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+define(LSH, 1)
+define(RSH, 63)
+
+ifdef(`OPERATION_addlsh1_n', `
+	define(ADDSUB,	add)
+	define(ADCSBB,	adc)
+	define(func_n,	mpn_addlsh1_n)
+	define(func_nc,	mpn_addlsh1_nc)')
+ifdef(`OPERATION_rsblsh1_n', `
+	define(ADDSUB,	sub)
+	define(ADCSBB,	sbb)
+	define(func_n,	mpn_rsblsh1_n)
+	define(func_nc,	mpn_rsblsh1_nc)')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_addlsh1_n mpn_addlsh1_nc mpn_rsblsh1_n mpn_rsblsh1_nc)
+include_mpn(`x86_64/coreisbr/aorrlshC_n.asm')
diff --git a/third_party/gmp/mpn/x86_64/coreisbr/aorrlsh2_n.asm b/third_party/gmp/mpn/x86_64/coreisbr/aorrlsh2_n.asm
new file mode 100644
index 0000000..3b7bb22
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreisbr/aorrlsh2_n.asm
@@ -0,0 +1,56 @@
+dnl  AMD64 mpn_addlsh2_n -- rp[] = up[] + (vp[] << 2)
+dnl  AMD64 mpn_rsblsh2_n -- rp[] = (vp[] << 2) - up[]
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2008, 2010-2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+define(LSH, 2)
+define(RSH, 62)
+
+ifdef(`OPERATION_addlsh2_n', `
+	define(ADDSUB,	add)
+	define(ADCSBB,	adc)
+	define(func_n,	mpn_addlsh2_n)
+	define(func_nc,	mpn_addlsh2_nc)')
+ifdef(`OPERATION_rsblsh2_n', `
+	define(ADDSUB,	sub)
+	define(ADCSBB,	sbb)
+	define(func_n,	mpn_rsblsh2_n)
+	define(func_nc,	mpn_rsblsh2_nc)')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+C mpn_rsblsh2_nc removed below, its idea of carry-in is inconsistent with
+C refmpn_rsblsh2_nc
+MULFUNC_PROLOGUE(mpn_addlsh2_n mpn_addlsh2_nc mpn_rsblsh2_n)
+include_mpn(`x86_64/coreisbr/aorrlshC_n.asm')
diff --git a/third_party/gmp/mpn/x86_64/coreisbr/aorrlshC_n.asm b/third_party/gmp/mpn/x86_64/coreisbr/aorrlshC_n.asm
new file mode 100644
index 0000000..23ace41
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreisbr/aorrlshC_n.asm
@@ -0,0 +1,173 @@
+dnl  AMD64 mpn_addlshC_n -- rp[] = up[] + (vp[] << C)
+dnl  AMD64 mpn_rsblshC_n -- rp[] = (vp[] << C) - up[]
+
+dnl  Copyright 2009-2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+C	     cycles/limb
+C AMD K8,K9	 ?
+C AMD K10	 ?
+C Intel P4	 ?
+C Intel core2	 3.25
+C Intel NHM	 4
+C Intel SBR	 2  C (or 1.95 when L(top)'s alignment = 16 (mod 32))
+C Intel atom	 ?
+C VIA nano	 ?
+
+C This code probably runs close to optimally on Sandy Bridge (using 4-way
+C unrolling).  It also runs reasonably well on Core 2, but it runs poorly on
+C all other processors, including Nehalem.
+
+C INPUT PARAMETERS
+define(`rp',	`%rdi')
+define(`up',	`%rsi')
+define(`vp',	`%rdx')
+define(`n',	`%rcx')
+define(`cy',	`%r8')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(func_nc)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8	')
+	push	%rbp
+	mov	cy, %rax
+	neg	%rax			C set msb on carry
+	xor	R32(%rbp), R32(%rbp)	C limb carry
+	mov	(vp), %r8
+	shrd	$RSH, %r8, %rbp
+	mov	R32(n), R32(%r9)
+	and	$3, R32(%r9)
+	je	L(b00)
+	cmp	$2, R32(%r9)
+	jc	L(b01)
+	je	L(b10)
+	jmp	L(b11)
+EPILOGUE()
+
+	ALIGN(16)
+PROLOGUE(func_n)
+	FUNC_ENTRY(4)
+	push	%rbp
+	xor	R32(%rbp), R32(%rbp)	C limb carry
+	mov	(vp), %r8
+	shrd	$RSH, %r8, %rbp
+	mov	R32(n), R32(%rax)
+	and	$3, R32(%rax)
+	je	L(b00)
+	cmp	$2, R32(%rax)
+	jc	L(b01)
+	je	L(b10)
+
+L(b11):	mov	8(vp), %r9
+	shrd	$RSH, %r9, %r8
+	mov	16(vp), %r10
+	shrd	$RSH, %r10, %r9
+	add	R32(%rax), R32(%rax)	C init carry flag
+	ADCSBB	(up), %rbp
+	ADCSBB	8(up), %r8
+	ADCSBB	16(up), %r9
+	mov	%rbp, (rp)
+	mov	%r8, 8(rp)
+	mov	%r9, 16(rp)
+	mov	%r10, %rbp
+	lea	24(up), up
+	lea	24(vp), vp
+	lea	24(rp), rp
+	sbb	R32(%rax), R32(%rax)	C save carry flag
+	sub	$3, n
+	ja	L(top)
+	jmp	L(end)
+
+L(b01):	add	R32(%rax), R32(%rax)	C init carry flag
+	ADCSBB	(up), %rbp
+	mov	%rbp, (rp)
+	mov	%r8, %rbp
+	lea	8(up), up
+	lea	8(vp), vp
+	lea	8(rp), rp
+	sbb	R32(%rax), R32(%rax)	C save carry flag
+	sub	$1, n
+	ja	L(top)
+	jmp	L(end)
+
+L(b10):	mov	8(vp), %r9
+	shrd	$RSH, %r9, %r8
+	add	R32(%rax), R32(%rax)	C init carry flag
+	ADCSBB	(up), %rbp
+	ADCSBB	8(up), %r8
+	mov	%rbp, (rp)
+	mov	%r8, 8(rp)
+	mov	%r9, %rbp
+	lea	16(up), up
+	lea	16(vp), vp
+	lea	16(rp), rp
+	sbb	R32(%rax), R32(%rax)	C save carry flag
+	sub	$2, n
+	ja	L(top)
+	jmp	L(end)
+
+	ALIGN(16)
+L(top):	mov	(vp), %r8
+	shrd	$RSH, %r8, %rbp
+L(b00):	mov	8(vp), %r9
+	shrd	$RSH, %r9, %r8
+	mov	16(vp), %r10
+	shrd	$RSH, %r10, %r9
+	mov	24(vp), %r11
+	shrd	$RSH, %r11, %r10
+	lea	32(vp), vp
+	add	R32(%rax), R32(%rax)	C restore carry flag
+	ADCSBB	(up), %rbp
+	ADCSBB	8(up), %r8
+	ADCSBB	16(up), %r9
+	ADCSBB	24(up), %r10
+	lea	32(up), up
+	mov	%rbp, (rp)
+	mov	%r8, 8(rp)
+	mov	%r9, 16(rp)
+	mov	%r10, 24(rp)
+	mov	%r11, %rbp
+	lea	32(rp), rp
+	sbb	R32(%rax), R32(%rax)	C save carry flag
+	sub	$4, n
+	jnz	L(top)
+
+L(end):	shr	$RSH, %rbp
+	add	R32(%rax), R32(%rax)	C restore carry flag
+	ADCSBB	$0, %rbp
+	mov	%rbp, %rax
+	pop	%rbp
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/coreisbr/aorrlsh_n.asm b/third_party/gmp/mpn/x86_64/coreisbr/aorrlsh_n.asm
new file mode 100644
index 0000000..db8ee68
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreisbr/aorrlsh_n.asm
@@ -0,0 +1,215 @@
+dnl  AMD64 mpn_addlsh_n -- rp[] = up[] + (vp[] << k)
+dnl  AMD64 mpn_rsblsh_n -- rp[] = (vp[] << k) - up[]
+dnl  Optimised for Sandy Bridge.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 ?
+C AMD K10	 5.25
+C Intel P4	 ?
+C Intel core2	 3.1
+C Intel NHM	 3.95
+C Intel SBR	 2.75
+C Intel atom	 ?
+C VIA nano	 ?
+
+C The inner-loop probably runs close to optimally on Sandy Bridge (using 4-way
+C unrolling).  The rest of the code is quite crude, and could perhaps be made
+C both smaller and faster.
+
+C INPUT PARAMETERS
+define(`rp',	`%rdi')
+define(`up',	`%rsi')
+define(`vp',	`%rdx')
+define(`n',	`%rcx')
+define(`cnt',	`%r8')
+define(`cy',	`%r9')			C for _nc variant
+
+ifdef(`OPERATION_addlsh_n', `
+	define(ADDSUB,	add)
+	define(ADCSBB,	adc)
+	define(IFRSB,	)
+	define(func_n,	mpn_addlsh_n)
+	define(func_nc,	mpn_addlsh_nc)')
+ifdef(`OPERATION_rsblsh_n', `
+	define(ADDSUB,	sub)
+	define(ADCSBB,	sbb)
+	define(IFRSB,	`$1')
+	define(func_n,	mpn_rsblsh_n)
+	define(func_nc,	mpn_rsblsh_nc)')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+C mpn_rsblsh_nc removed below, its idea of carry-in is inconsistent with
+C refmpn_rsblsh_nc
+MULFUNC_PROLOGUE(mpn_addlsh_n mpn_addlsh_nc mpn_rsblsh_n)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(func_n)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8d	')	C cnt
+	push	%rbx
+	xor	R32(%rbx), R32(%rbx)	C clear CF save register
+L(ent):	push	%rbp
+	mov	R32(n), R32(%rbp)
+	mov	n, %rax
+	mov	R32(cnt), R32(%rcx)
+	neg	R32(%rcx)
+	and	$3, R32(%rbp)
+	jz	L(b0)
+	lea	-32(vp,%rbp,8), vp
+	lea	-32(up,%rbp,8), up
+	lea	-32(rp,%rbp,8), rp
+	cmp	$2, R32(%rbp)
+	jc	L(b1)
+	jz	L(b2)
+
+L(b3):	xor	%r8, %r8
+	mov	8(vp), %r9
+	mov	16(vp), %r10
+	shrd	R8(%rcx), %r9, %r8
+	shrd	R8(%rcx), %r10, %r9
+	mov	24(vp), %r11
+	shrd	R8(%rcx), %r11, %r10
+	sub	$3, %rax
+	jz	L(3)
+	add	R32(%rbx), R32(%rbx)
+	lea	32(vp), vp
+	ADCSBB	8(up), %r8
+	ADCSBB	16(up), %r9
+	ADCSBB	24(up), %r10
+	lea	32(up), up
+	jmp	L(lo3)
+L(3):	add	R32(%rbx), R32(%rbx)
+	lea	32(vp), vp
+	ADCSBB	8(up), %r8
+	ADCSBB	16(up), %r9
+	ADCSBB	24(up), %r10
+	jmp	L(wd3)
+
+L(b0):	mov	(vp), %r8
+	mov	8(vp), %r9
+	xor	R32(%rbp), R32(%rbp)
+	jmp	L(lo0)
+
+L(b1):	xor	%r10, %r10
+	mov	24(vp), %r11
+	shrd	R8(%rcx), %r11, %r10
+	sub	$1, %rax
+	jz	L(1)
+	add	R32(%rbx), R32(%rbx)
+	lea	32(vp), vp
+	ADCSBB	24(up), %r10
+	lea	32(up), up
+	mov	(vp), %r8
+	jmp	L(lo1)
+L(1):	add	R32(%rbx), R32(%rbx)
+	ADCSBB	24(up), %r10
+	jmp	L(wd1)
+
+L(b2):	xor	%r9, %r9
+	mov	16(vp), %r10
+	shrd	R8(%rcx), %r10, %r9
+	mov	24(vp), %r11
+	shrd	R8(%rcx), %r11, %r10
+	sub	$2, %rax
+	jz	L(2)
+	add	R32(%rbx), R32(%rbx)
+	lea	32(vp), vp
+	ADCSBB	16(up), %r9
+	ADCSBB	24(up), %r10
+	lea	32(up), up
+	jmp	L(lo2)
+L(2):	add	R32(%rbx), R32(%rbx)
+	ADCSBB	16(up), %r9
+	ADCSBB	24(up), %r10
+	jmp	L(wd2)
+
+	ALIGN(32)			C 16-byte alignment is not enough!
+L(top):	shrd	R8(%rcx), %r11, %r10
+	add	R32(%rbx), R32(%rbx)
+	lea	32(vp), vp
+	ADCSBB	(up), %rbp
+	ADCSBB	8(up), %r8
+	ADCSBB	16(up), %r9
+	ADCSBB	24(up), %r10
+	mov	%rbp, (rp)
+	lea	32(up), up
+L(lo3):	mov	%r8, 8(rp)
+L(lo2):	mov	%r9, 16(rp)
+	mov	(vp), %r8
+L(lo1):	mov	%r10, 24(rp)
+	mov	8(vp), %r9
+	mov	%r11, %rbp
+	lea	32(rp), rp
+	sbb	R32(%rbx), R32(%rbx)
+L(lo0):	shrd	R8(%rcx), %r8, %rbp
+	mov	16(vp), %r10
+	shrd	R8(%rcx), %r9, %r8
+	shrd	R8(%rcx), %r10, %r9
+	mov	24(vp), %r11
+	sub	$4, %rax
+	jg	L(top)
+
+	shrd	R8(%rcx), %r11, %r10
+	add	R32(%rbx), R32(%rbx)
+	ADCSBB	(up), %rbp
+	ADCSBB	8(up), %r8
+	ADCSBB	16(up), %r9
+	ADCSBB	24(up), %r10
+	mov	%rbp, (rp)
+L(wd3):	mov	%r8, 8(rp)
+L(wd2):	mov	%r9, 16(rp)
+L(wd1):	mov	%r10, 24(rp)
+	adc	R32(%rax), R32(%rax)	C rax is zero after loop
+	shr	R8(%rcx), %r11
+	ADDSUB	%r11, %rax
+IFRSB(	neg	%rax)
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
+PROLOGUE(func_nc)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8d	')	C cnt
+IFDOS(`	mov	64(%rsp), %r9	')	C cy
+	push	%rbx
+	neg	cy
+	sbb	R32(%rbx), R32(%rbx)	C initialise CF save register
+	jmp	L(ent)
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/coreisbr/aors_n.asm b/third_party/gmp/mpn/x86_64/coreisbr/aors_n.asm
new file mode 100644
index 0000000..61fee3e
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreisbr/aors_n.asm
@@ -0,0 +1,203 @@
+dnl  AMD64 mpn_add_n, mpn_sub_n optimised for Sandy bridge, Ivy bridge, and
+dnl  Haswell.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2003-2005, 2007, 2008, 2010-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	    cycles/limb
+C AMD K8,K9	 1.75\2.52
+C AMD K10	 1.5
+C AMD bd1	 1.69\2.25
+C AMD bd2	 1.65
+C AMD bd3	 ?
+C AMD bd4	 ?
+C AMD zen	 1.5
+C AMD bt1	 2.67
+C AMD bt2	 2.16
+C Intel P4	11.54
+C Intel PNR	 5
+C Intel NHM	 5.5
+C Intel SBR	 1.54
+C Intel IBR	 1.5
+C Intel HWL	 1.32
+C Intel BWL	 1.07
+C Intel SKL	 1.21
+C Intel atom	 4.3
+C Intel SLM	 3
+C VIA nano	 ?
+
+C The loop of this code was manually written.  It runs close to optimally on
+C Intel SBR, IBR, and HWL far as we know, except for the fluctuation problems.
+C It also runs slightly faster on average on AMD bd1 and bd2.
+C
+C No micro-optimisation has been done.
+C
+C N.B.!  The loop alignment padding insns are executed.  If editing the code,
+C make sure the padding does not become excessive.  It is now a 4-byte nop.
+
+define(`rp',	`%rdi')	C rcx
+define(`up',	`%rsi')	C rdx
+define(`vp',	`%rdx')	C r8
+define(`n',	`%rcx')	C r9
+define(`cy',	`%r8')	C rsp+40    (mpn_add_nc and mpn_sub_nc)
+
+ifdef(`OPERATION_add_n', `
+  define(ADCSBB,    adc)
+  define(func,      mpn_add_n)
+  define(func_nc,   mpn_add_nc)')
+ifdef(`OPERATION_sub_n', `
+  define(ADCSBB,    sbb)
+  define(func,      mpn_sub_n)
+  define(func_nc,   mpn_sub_nc)')
+
+MULFUNC_PROLOGUE(mpn_add_n mpn_add_nc mpn_sub_n mpn_sub_nc)
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(func)
+	FUNC_ENTRY(4)
+	xor	%r8, %r8
+
+L(ent):	mov	R32(n), R32(%rax)
+	shr	$2, n
+
+	test	$1, R8(%rax)
+	jnz	L(bx1)
+
+L(bx0):	test	$2, R8(%rax)
+	jnz	L(b10)
+
+L(b00):	neg	%r8
+	mov	(up), %r8
+	mov	8(up), %r9
+	ADCSBB	(vp), %r8
+	ADCSBB	8(vp), %r9
+	mov	16(up), %r10
+	mov	24(up), %r11
+	lea	32(up), up
+	ADCSBB	16(vp), %r10
+	ADCSBB	24(vp), %r11
+	lea	32(vp), vp
+	lea	-16(rp), rp
+	jmp	L(lo0)
+
+L(b10):	neg	%r8
+	mov	(up), %r10
+	mov	8(up), %r11
+	ADCSBB	0(vp), %r10
+	ADCSBB	8(vp), %r11
+	jrcxz	L(e2)
+	mov	16(up), %r8
+	mov	24(up), %r9
+	lea	16(up), up
+	ADCSBB	16(vp), %r8
+	ADCSBB	24(vp), %r9
+	lea	16(vp), vp
+C	lea	(rp), rp
+	jmp	L(lo2)
+
+L(e2):	mov	%r10, (rp)
+	mov	%r11, 8(rp)
+	setc	R8(%rax)
+	FUNC_EXIT()
+	ret
+
+L(bx1):	test	$2, R8(%rax)
+	jnz	L(b11)
+
+L(b01):	neg	%r8
+	mov	(up), %r11
+	ADCSBB	(vp), %r11
+	jrcxz	L(e1)
+	mov	8(up), %r8
+	mov	16(up), %r9
+	lea	8(up), up
+	lea	-8(rp), rp
+	ADCSBB	8(vp), %r8
+	ADCSBB	16(vp), %r9
+	lea	8(vp), vp
+	jmp	L(lo1)
+
+L(e1):	mov	%r11, (rp)
+	setc	R8(%rax)
+	FUNC_EXIT()
+	ret
+
+L(b11):	neg	%r8
+	mov	(up), %r9
+	ADCSBB	(vp), %r9
+	mov	8(up), %r10
+	mov	16(up), %r11
+	lea	24(up), up
+	ADCSBB	8(vp), %r10
+	ADCSBB	16(vp), %r11
+	lea	24(vp), vp
+	mov	%r9, (rp)
+	lea	8(rp), rp
+	jrcxz	L(end)
+
+	ALIGN(32)
+L(top):	mov	(up), %r8
+	mov	8(up), %r9
+	ADCSBB	(vp), %r8
+	ADCSBB	8(vp), %r9
+L(lo2):	mov	%r10, (rp)
+L(lo1):	mov	%r11, 8(rp)
+	mov	16(up), %r10
+	mov	24(up), %r11
+	lea	32(up), up
+	ADCSBB	16(vp), %r10
+	ADCSBB	24(vp), %r11
+	lea	32(vp), vp
+L(lo0):	mov	%r8, 16(rp)
+L(lo3):	mov	%r9, 24(rp)
+	lea	32(rp), rp
+	dec	n
+	jnz	L(top)
+
+L(end):	mov	R32(n), R32(%rax)	C zero rax
+	mov	%r10, (rp)
+	mov	%r11, 8(rp)
+	setc	R8(%rax)
+	FUNC_EXIT()
+	ret
+EPILOGUE()
+	ALIGN(16)
+PROLOGUE(func_nc)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8	')
+	jmp	L(ent)
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/coreisbr/aorsmul_1.asm b/third_party/gmp/mpn/x86_64/coreisbr/aorsmul_1.asm
new file mode 100644
index 0000000..b4c1572
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreisbr/aorsmul_1.asm
@@ -0,0 +1,212 @@
+dnl  X86-64 mpn_addmul_1 and mpn_submul_1 optimised for Intel Sandy Bridge.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2003-2005, 2007, 2008, 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C            cycles/limb
+C AMD K8,K9      4.27
+C AMD K10        4.27    4.54
+C AMD bull       4.76
+C AMD pile       4.55
+C AMD steam
+C AMD excavator
+C AMD bobcat     5.30
+C AMD jaguar     5.28
+C Intel P4      16.2    17.1
+C Intel core2    5.26
+C Intel NHM      5.09
+C Intel SBR      3.21
+C Intel IBR      2.96
+C Intel HWL      2.81
+C Intel BWL      2.76
+C Intel SKL      2.76
+C Intel atom    21.5
+C Intel SLM      9.5
+C VIA nano
+
+C The loop of this code is the result of running a code generation and
+C optimization tool suite written by David Harvey and Torbjörn Granlund.
+
+define(`rp',      `%rdi')   C rcx
+define(`up',      `%rsi')   C rdx
+define(`n_param', `%rdx')   C r8
+define(`v0',      `%rcx')   C r9
+
+define(`n',       `%rbx')
+
+define(`I',`$1')
+
+ifdef(`OPERATION_addmul_1',`
+      define(`ADDSUB',        `add')
+      define(`func',  `mpn_addmul_1')
+')
+ifdef(`OPERATION_submul_1',`
+      define(`ADDSUB',        `sub')
+      define(`func',  `mpn_submul_1')
+')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_addmul_1 mpn_submul_1)
+
+IFDOS(`	define(`up',     ``%rsi'')') dnl
+IFDOS(`	define(`rp',     ``%rcx'')') dnl
+IFDOS(`	define(`v0',     ``%r9'')') dnl
+IFDOS(`	define(`r9',     ``rdi'')') dnl
+IFDOS(`	define(`n_param',``%r8'')') dnl
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(func)
+
+IFDOS(``push	%rsi		'')
+IFDOS(``push	%rdi		'')
+IFDOS(``mov	%rdx, %rsi	'')
+
+	mov	(up), %rax
+	push	%rbx
+	lea	(up,n_param,8), up
+	lea	(rp,n_param,8), rp
+
+	test	$1, R8(n_param)
+	jnz	L(b13)
+
+L(b02):	xor	R32(%r11), R32(%r11)
+	test	$2, R8(n_param)
+	jnz	L(b2)
+
+L(b0):	mov	$1, R32(n)
+	sub	n_param, n
+	mul	v0
+	mov	%rdx, %r9
+	mov	-8(rp,n,8), %r8
+	jmp	L(e0)
+
+	ALIGN(16)
+L(b2):	mov	$-1, n
+	sub	n_param, n
+	mul	v0
+	mov	8(rp,n,8), %r8
+	mov	%rdx, %r9
+	jmp	L(e2)
+
+	ALIGN(16)
+L(b13):	xor	R32(%r9), R32(%r9)
+	test	$2, R8(n_param)
+	jnz	L(b3)
+
+L(b1):	mov	$2, R32(n)
+	sub	n_param, n
+	jns	L(1)
+	mul	v0
+	mov	-16(rp,n,8), %r10
+	mov	%rdx, %r11
+	jmp	L(e1)
+
+	ALIGN(16)
+L(b3):	xor	R32(n), R32(n)
+	sub	n_param, n
+	mul	v0
+	mov	(rp,n,8), %r10
+	jmp	L(e3)
+
+	ALIGN(32)
+L(top):	mul	v0
+	mov	-16(rp,n,8), %r10
+	ADDSUB	%r11, %r8
+	mov	%rdx, %r11
+	adc	$0, %r9
+	mov	%r8, -24(rp,n,8)
+L(e1):	ADDSUB	%rax, %r10
+	mov	-8(up,n,8), %rax
+	adc	$0, %r11
+	mul	v0
+	ADDSUB	%r9, %r10
+	mov	%rdx, %r9
+	mov	-8(rp,n,8), %r8
+	adc	$0, %r11
+	mov	%r10, -16(rp,n,8)
+L(e0):	ADDSUB	%rax, %r8
+	adc	$0, %r9
+	mov	(up,n,8), %rax
+	mul	v0
+	mov	(rp,n,8), %r10
+	ADDSUB	%r11, %r8
+	mov	%r8, -8(rp,n,8)
+	adc	$0, %r9
+L(e3):	mov	%rdx, %r11
+	ADDSUB	%rax, %r10
+	mov	8(up,n,8), %rax
+	adc	$0, %r11
+	mul	v0
+	mov	8(rp,n,8), %r8
+	ADDSUB	%r9, %r10
+	mov	%rdx, %r9
+	mov	%r10, (rp,n,8)
+	adc	$0, %r11
+L(e2):	ADDSUB	%rax, %r8
+	adc	$0, %r9
+	mov	16(up,n,8), %rax
+	add	$4, n
+	jnc	L(top)
+
+L(end):	mul	v0
+	mov	I(-8(rp),-16(rp,n,8)), %r10
+	ADDSUB	%r11, %r8
+	mov	%rdx, %r11
+	adc	$0, %r9
+	mov	%r8, I(-16(rp),-24(rp,n,8))
+	ADDSUB	%rax, %r10
+	adc	$0, %r11
+	ADDSUB	%r9, %r10
+	adc	$0, %r11
+	mov	%r10, I(-8(rp),-16(rp,n,8))
+	mov	%r11, %rax
+
+	pop	%rbx
+IFDOS(``pop	%rdi		'')
+IFDOS(``pop	%rsi		'')
+	ret
+
+	ALIGN(16)
+L(1):	mul	v0
+	ADDSUB	%rax, -8(rp)
+	mov	%rdx, %rax
+	adc	$0, %rax
+	pop	%rbx
+IFDOS(``pop	%rdi		'')
+IFDOS(``pop	%rsi		'')
+	ret
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86_64/coreisbr/cnd_add_n.asm b/third_party/gmp/mpn/x86_64/coreisbr/cnd_add_n.asm
new file mode 100644
index 0000000..43abcc8
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreisbr/cnd_add_n.asm
@@ -0,0 +1,174 @@
+dnl  AMD64 mpn_cnd_add_n.
+
+dnl  Copyright 2011-2013, 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9
+C AMD K10
+C AMD bd1
+C AMD bd2
+C AMD bd3
+C AMD bd4
+C AMD zen
+C AMD bobcat
+C AMD jaguar
+C Intel P4
+C Intel PNR	 3.0
+C Intel NHM	 3.75
+C Intel SBR	 1.93
+C Intel IBR	 1.89
+C Intel HWL	 1.78
+C Intel BWL	 1.50
+C Intel SKL	 1.50
+C Intel atom
+C Intel SLM	 4.0
+C VIA nano
+
+C NOTES
+C  * It might seem natural to use the cmov insn here, but since this function
+C    is supposed to have the exact same execution pattern for cnd true and
+C    false, and since cmov's documentation is not clear about whether it
+C    actually reads both source operands and writes the register for a false
+C    condition, we cannot use it.
+
+C INPUT PARAMETERS
+define(`cnd_arg', `%rdi')	dnl rcx
+define(`rp',	  `%rsi')	dnl rdx
+define(`up',	  `%rdx')	dnl r8
+define(`vp',	  `%rcx')	dnl r9
+define(`n',	  `%r8')	dnl rsp+40
+
+define(`cnd',     `%rbx')
+
+define(ADDSUB,	add)
+define(ADCSBB,	adc)
+define(func,	mpn_cnd_add_n)
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_cnd_add_n)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), R32(%r8)')
+	push	%rbx
+
+	neg	cnd_arg
+	sbb	cnd, cnd		C make cnd mask
+
+	test	$1, R8(n)
+	jz	L(x0)
+L(x1):	test	$2, R8(n)
+	jz	L(b1)
+
+L(b3):	mov	(vp), %rdi
+	mov	8(vp), %r9
+	mov	16(vp), %r10
+	and	cnd, %rdi
+	and	cnd, %r9
+	and	cnd, %r10
+	ADDSUB	(up), %rdi
+	mov	%rdi, (rp)
+	ADCSBB	8(up), %r9
+	mov	%r9, 8(rp)
+	ADCSBB	16(up), %r10
+	mov	%r10, 16(rp)
+	sbb	R32(%rax), R32(%rax)	C save carry
+	lea	24(up), up
+	lea	24(vp), vp
+	lea	24(rp), rp
+	sub	$3, n
+	jnz	L(top)
+	jmp	L(end)
+
+L(x0):	xor	R32(%rax), R32(%rax)
+	test	$2, R8(n)
+	jz	L(top)
+
+L(b2):	mov	(vp), %rdi
+	mov	8(vp), %r9
+	and	cnd, %rdi
+	and	cnd, %r9
+	ADDSUB	(up), %rdi
+	mov	%rdi, (rp)
+	ADCSBB	8(up), %r9
+	mov	%r9, 8(rp)
+	sbb	R32(%rax), R32(%rax)	C save carry
+	lea	16(up), up
+	lea	16(vp), vp
+	lea	16(rp), rp
+	sub	$2, n
+	jnz	L(top)
+	jmp	L(end)
+
+L(b1):	mov	(vp), %rdi
+	and	cnd, %rdi
+	ADDSUB	(up), %rdi
+	mov	%rdi, (rp)
+	sbb	R32(%rax), R32(%rax)	C save carry
+	lea	8(up), up
+	lea	8(vp), vp
+	lea	8(rp), rp
+	dec	n
+	jz	L(end)
+
+	ALIGN(16)
+L(top):	mov	(vp), %rdi
+	mov	8(vp), %r9
+	mov	16(vp), %r10
+	mov	24(vp), %r11
+	lea	32(vp), vp
+	and	cnd, %rdi
+	and	cnd, %r9
+	and	cnd, %r10
+	and	cnd, %r11
+	add	R32(%rax), R32(%rax)	C restore carry
+	ADCSBB	(up), %rdi
+	mov	%rdi, (rp)
+	ADCSBB	8(up), %r9
+	mov	%r9, 8(rp)
+	ADCSBB	16(up), %r10
+	mov	%r10, 16(rp)
+	ADCSBB	24(up), %r11
+	lea	32(up), up
+	mov	%r11, 24(rp)
+	lea	32(rp), rp
+	sbb	R32(%rax), R32(%rax)	C save carry
+	sub	$4, n
+	jnz	L(top)
+
+L(end):	neg	R32(%rax)
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/coreisbr/cnd_sub_n.asm b/third_party/gmp/mpn/x86_64/coreisbr/cnd_sub_n.asm
new file mode 100644
index 0000000..f55492b
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreisbr/cnd_sub_n.asm
@@ -0,0 +1,200 @@
+dnl  AMD64 mpn_cnd_add_n, mpn_cnd_sub_n
+
+dnl  Copyright 2011-2013, 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9
+C AMD K10
+C AMD bd1
+C AMD bd2
+C AMD bd3
+C AMD bd4
+C AMD zen
+C AMD bobcat
+C AMD jaguar
+C Intel P4
+C Intel PNR	 3.0
+C Intel NHM	 2.75
+C Intel SBR	 2.15
+C Intel IBR	 1.96
+C Intel HWL	 2.0
+C Intel BWL	 1.65
+C Intel SKL	 1.65
+C Intel atom
+C Intel SLM	 4.5
+C VIA nano
+
+C NOTES
+C  * It might seem natural to use the cmov insn here, but since this function
+C    is supposed to have the exact same execution pattern for cnd true and
+C    false, and since cmov's documentation is not clear about whether it
+C    actually reads both source operands and writes the register for a false
+C    condition, we cannot use it.
+C  * Given that we have a dedicated cnd_add_n, it might look strange that this
+C    file provides cnd_add_n and not just cnd_sub_n.  But that's harmless, and
+C    this file's generality might come in handy for some pipeline.
+
+C INPUT PARAMETERS
+define(`cnd_arg', `%rdi')	dnl rcx
+define(`rp',	  `%rsi')	dnl rdx
+define(`up',	  `%rdx')	dnl r8
+define(`vp',	  `%rcx')	dnl r9
+define(`n',	  `%r8')	dnl rsp+40
+
+define(`cnd',     `%rbx')
+
+ifdef(`OPERATION_cnd_add_n',`
+	define(ADDSUB,	add)
+	define(ADCSBB,	adc)
+	define(func,	mpn_cnd_add_n)')
+ifdef(`OPERATION_cnd_sub_n',`
+	define(ADDSUB,	sub)
+	define(ADCSBB,	sbb)
+	define(func,	mpn_cnd_sub_n)')
+
+MULFUNC_PROLOGUE(mpn_cnd_add_n mpn_cnd_sub_n)
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(func)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), R32(%r8)')
+	push	%rbx
+	push	%rbp
+	push	%r12
+	push	%r13
+
+	neg	cnd_arg
+	sbb	cnd, cnd		C make cnd mask
+
+	test	$1, R8(n)
+	jz	L(x0)
+L(x1):	test	$2, R8(n)
+	jz	L(b1)
+
+L(b3):	mov	(vp), %rdi
+	mov	8(vp), %r9
+	mov	16(vp), %r10
+	and	cnd, %rdi
+	mov	(up), %r12
+	and	cnd, %r9
+	mov	8(up), %r13
+	and	cnd, %r10
+	mov	16(up), %rbp
+	ADDSUB	%rdi, %r12
+	mov	%r12, (rp)
+	ADCSBB	%r9, %r13
+	mov	%r13, 8(rp)
+	ADCSBB	%r10, %rbp
+	mov	%rbp, 16(rp)
+	sbb	R32(%rax), R32(%rax)	C save carry
+	lea	24(up), up
+	lea	24(vp), vp
+	lea	24(rp), rp
+	sub	$3, n
+	jnz	L(top)
+	jmp	L(end)
+
+L(x0):	xor	R32(%rax), R32(%rax)
+	test	$2, R8(n)
+	jz	L(top)
+
+L(b2):	mov	(vp), %rdi
+	mov	8(vp), %r9
+	mov	(up), %r12
+	and	cnd, %rdi
+	mov	8(up), %r13
+	and	cnd, %r9
+	ADDSUB	%rdi, %r12
+	mov	%r12, (rp)
+	ADCSBB	%r9, %r13
+	mov	%r13, 8(rp)
+	sbb	R32(%rax), R32(%rax)	C save carry
+	lea	16(up), up
+	lea	16(vp), vp
+	lea	16(rp), rp
+	sub	$2, n
+	jnz	L(top)
+	jmp	L(end)
+
+L(b1):	mov	(vp), %rdi
+	mov	(up), %r12
+	and	cnd, %rdi
+	ADDSUB	%rdi, %r12
+	mov	%r12, (rp)
+	sbb	R32(%rax), R32(%rax)	C save carry
+	lea	8(up), up
+	lea	8(vp), vp
+	lea	8(rp), rp
+	dec	n
+	jz	L(end)
+
+	ALIGN(16)
+L(top):	mov	(vp), %rdi
+	mov	8(vp), %r9
+	mov	16(vp), %r10
+	mov	24(vp), %r11
+	lea	32(vp), vp
+	and	cnd, %rdi
+	mov	(up), %r12
+	and	cnd, %r9
+	mov	8(up), %r13
+	and	cnd, %r10
+	mov	16(up), %rbp
+	and	cnd, %r11
+	add	R32(%rax), R32(%rax)	C restore carry
+	mov	24(up), %rax
+	lea	32(up), up
+	ADCSBB	%rdi, %r12
+	mov	%r12, (rp)
+	ADCSBB	%r9, %r13
+	mov	%r13, 8(rp)
+	ADCSBB	%r10, %rbp
+	mov	%rbp, 16(rp)
+	ADCSBB	%r11, %rax
+	mov	%rax, 24(rp)
+	lea	32(rp), rp
+	sbb	R32(%rax), R32(%rax)	C save carry
+	sub	$4, n
+	jnz	L(top)
+
+L(end):	neg	R32(%rax)
+	pop	%r13
+	pop	%r12
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/coreisbr/divrem_1.asm b/third_party/gmp/mpn/x86_64/coreisbr/divrem_1.asm
new file mode 100644
index 0000000..d9f371f
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreisbr/divrem_1.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_divrem_1
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_divrem_1 mpn_preinv_divrem_1)
+include_mpn(`x86_64/divrem_1.asm')
diff --git a/third_party/gmp/mpn/x86_64/coreisbr/gcd_11.asm b/third_party/gmp/mpn/x86_64/coreisbr/gcd_11.asm
new file mode 100644
index 0000000..4723093
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreisbr/gcd_11.asm
@@ -0,0 +1,37 @@
+dnl  AMD64 mpn_gcd_11.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_gcd_11)
+include_mpn(`x86_64/core2/gcd_11.asm')
diff --git a/third_party/gmp/mpn/x86_64/coreisbr/gmp-mparam.h b/third_party/gmp/mpn/x86_64/coreisbr/gmp-mparam.h
new file mode 100644
index 0000000..36f4512
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreisbr/gmp-mparam.h
@@ -0,0 +1,241 @@
+/* Sandy Bridge gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+/* 3400-3800 MHz Intel Xeon E3-1270 Sandy Bridge */
+/* FFT tuning limit = 468,152,320 */
+/* Generated by tuneup.c, 2019-10-20, gcc 8.3 */
+
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          4
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          2
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD         9
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        24
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD      8
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1_NORM_THRESHOLD              1
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           30
+
+#define DIV_1_VS_MUL_1_PERCENT             298
+
+#define MUL_TOOM22_THRESHOLD                20
+#define MUL_TOOM33_THRESHOLD                65
+#define MUL_TOOM44_THRESHOLD               154
+#define MUL_TOOM6H_THRESHOLD               254
+#define MUL_TOOM8H_THRESHOLD               333
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD     105
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     122
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     105
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     113
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     148
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 28
+#define SQR_TOOM3_THRESHOLD                 93
+#define SQR_TOOM4_THRESHOLD                248
+#define SQR_TOOM6_THRESHOLD                342
+#define SQR_TOOM8_THRESHOLD                462
+
+#define MULMID_TOOM42_THRESHOLD             36
+
+#define MULMOD_BNM1_THRESHOLD               13
+#define SQRMOD_BNM1_THRESHOLD               15
+
+#define MUL_FFT_MODF_THRESHOLD             396  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    396, 5}, {     19, 6}, {     10, 5}, {     21, 6}, \
+    {     11, 5}, {     23, 6}, {     21, 7}, {     11, 6}, \
+    {     25, 7}, {     13, 6}, {     27, 7}, {     21, 8}, \
+    {     11, 7}, {     25, 8}, {     13, 7}, {     28, 8}, \
+    {     15, 7}, {     31, 8}, {     17, 7}, {     35, 8}, \
+    {     21, 9}, {     11, 8}, {     27, 9}, {     15, 8}, \
+    {     35, 9}, {     19, 8}, {     39, 9}, {     23, 8}, \
+    {     49, 9}, {     27,10}, {     15, 9}, {     39,10}, \
+    {     23, 9}, {     51,11}, {     15,10}, {     31, 9}, \
+    {     67,10}, {     39, 9}, {     83,10}, {     47, 9}, \
+    {     95,11}, {     31,10}, {     79,11}, {     47,10}, \
+    {     95,12}, {     31,11}, {     63,10}, {    135,11}, \
+    {     79,10}, {    159, 9}, {    319,10}, {    167,11}, \
+    {     95, 7}, {   1535, 8}, {    831,10}, {    223, 9}, \
+    {    447,11}, {    127,10}, {    255, 9}, {    511,11}, \
+    {    143,10}, {    287, 9}, {    575,10}, {    303,11}, \
+    {    159,10}, {    319,12}, {     95,11}, {    191,10}, \
+    {    383,13}, {     63,12}, {    127,11}, {    255,10}, \
+    {    511,11}, {    271,10}, {    543,11}, {    287,10}, \
+    {    575,11}, {    303,12}, {    159,11}, {    319,10}, \
+    {    639,11}, {    351,10}, {    703,11}, {    367,12}, \
+    {    191,11}, {    383,10}, {    767,11}, {    415,10}, \
+    {    831,12}, {    223,11}, {    447,10}, {    895,11}, \
+    {    479,13}, {    127,12}, {    255,11}, {    543,12}, \
+    {    287,11}, {    607,12}, {    319,11}, {    639,12}, \
+    {    351,11}, {    703,12}, {    383,11}, {    767,12}, \
+    {    415,11}, {    831,12}, {    447,11}, {    895,12}, \
+    {    479,14}, {    127,13}, {    255,12}, {    543,11}, \
+    {   1087,12}, {    607,13}, {    319,12}, {    735,13}, \
+    {    383,12}, {    831,13}, {    447,12}, {    959,14}, \
+    {    255,13}, {    511,12}, {   1087,13}, {    575,12}, \
+    {   1215,13}, {    639,12}, {   1279,13}, {    703,12}, \
+    {   1407,14}, {    383,13}, {    767,12}, {   1535,13}, \
+    {    831,12}, {   1663,13}, {    959,15}, {    255,14}, \
+    {    511,13}, {   1087,12}, {   2175,13}, {   1215,14}, \
+    {    639,13}, {   1343,12}, {   2687,13}, {   1407,12}, \
+    {   2815,13}, {   1471,14}, {    767,13}, {   1663,14}, \
+    {    895,13}, {   1919,15}, {    511,14}, {   1023,13}, \
+    {   2175,14}, {   1151,13}, {   2431,12}, {   4863,14}, \
+    {   1279,13}, {   2687,14}, {   1407,13}, {   2815,15}, \
+    {    767,14}, {   1535,13}, {   3071,14}, {   1663,13}, \
+    {   3455,12}, {   6911,14}, {   1919,16}, {    511,15}, \
+    {   1023,14}, {   2431,13}, {   4863,15}, {   1279,14}, \
+    {   2943,13}, {   5887,15}, {   1535,14}, {   3455,13}, \
+    {   6911,15}, {   1791,14}, {   3839,13}, {   7679,16}, \
+    {   1023,15}, {   2047,14}, {   4223,15}, {   2303,14}, \
+    {   4863,15}, {   2815,14}, {   5887,16}, {   1535,15}, \
+    {   3327,14}, {   6911,15}, {   3839,14}, {   7679,17}, \
+    {   1023,16}, {   2047,15}, {   4863,16}, {   2559,15}, \
+    {   5887,14}, {  11775,16}, {   3071,15}, {   6911,16}, \
+    {   3583,15}, {   7679,14}, {  15359,17}, {   2047,16}, \
+    {   4095,15}, {   8191,16}, {   4607,15}, {   9983,16}, \
+    {   5631,15}, {  11775,17}, {   3071,16}, {  65536,17}, \
+    { 131072,18}, { 262144,19}, { 524288,20}, {1048576,21}, \
+    {2097152,22}, {4194304,23}, {8388608,24} }
+#define MUL_FFT_TABLE3_SIZE 219
+#define MUL_FFT_THRESHOLD                 4736
+
+#define SQR_FFT_MODF_THRESHOLD             336  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    336, 5}, {     19, 6}, {     10, 5}, {     21, 6}, \
+    {     11, 5}, {     23, 6}, {     25, 7}, {     13, 6}, \
+    {     27, 7}, {     25, 8}, {     13, 7}, {     28, 8}, \
+    {     15, 7}, {     31, 8}, {     21, 9}, {     11, 8}, \
+    {     27, 9}, {     15, 8}, {     35, 9}, {     19, 8}, \
+    {     41, 9}, {     23, 8}, {     47, 9}, {     27,10}, \
+    {     15, 9}, {     39,10}, {     23, 9}, {     51,11}, \
+    {     15,10}, {     31, 9}, {     67,10}, {     39, 9}, \
+    {     79,10}, {     47,11}, {     31,10}, {     79,11}, \
+    {     47,10}, {     95,12}, {     31,11}, {     63,10}, \
+    {    127, 9}, {    255,10}, {    135,11}, {     79,10}, \
+    {    159, 9}, {    319,11}, {     95,10}, {    191, 9}, \
+    {    383,12}, {     63,11}, {    127,10}, {    255, 6}, \
+    {   4351, 7}, {   2303, 8}, {   1215,12}, {     95,11}, \
+    {    191,10}, {    383,13}, {     63,12}, {    127,11}, \
+    {    255,10}, {    511,11}, {    271,10}, {    543,11}, \
+    {    287,10}, {    575,11}, {    303,10}, {    607,12}, \
+    {    159,11}, {    319,10}, {    639,11}, {    335,10}, \
+    {    671,11}, {    351,10}, {    703,12}, {    191,11}, \
+    {    383,10}, {    767,11}, {    415,10}, {    831,12}, \
+    {    223,11}, {    447,10}, {    895,11}, {    479,13}, \
+    {    127,12}, {    255,11}, {    543,12}, {    287,11}, \
+    {    607,12}, {    319,11}, {    671,12}, {    351,11}, \
+    {    703,13}, {    191,12}, {    383,11}, {    767,12}, \
+    {    415,11}, {    831,12}, {    447,11}, {    895,12}, \
+    {    479,14}, {    127,13}, {    255,12}, {    511,11}, \
+    {   1023,12}, {    543,11}, {   1087,12}, {    607,13}, \
+    {    319,12}, {    703,13}, {    383,12}, {    831,13}, \
+    {    447,12}, {    959,14}, {    255,13}, {    511,12}, \
+    {   1087,13}, {    575,12}, {   1215,13}, {    639,12}, \
+    {   1279,13}, {    703,14}, {    383,13}, {    767,12}, \
+    {   1535,13}, {    831,12}, {   1663,13}, {    959,14}, \
+    {    511,13}, {   1087,12}, {   2175,13}, {   1215,14}, \
+    {    639,13}, {   1343,12}, {   2687,13}, {   1407,12}, \
+    {   2815,13}, {   1471,14}, {    767,13}, {   1599,12}, \
+    {   3199,13}, {   1663,14}, {    895,13}, {   1791,15}, \
+    {    511,14}, {   1023,13}, {   2175,14}, {   1151,13}, \
+    {   2431,12}, {   4863,14}, {   1279,13}, {   2687,14}, \
+    {   1407,13}, {   2815,15}, {    767,14}, {   1535,13}, \
+    {   3199,14}, {   1663,13}, {   3455,12}, {   6911,14}, \
+    {   1791,16}, {    511,15}, {   1023,14}, {   2431,13}, \
+    {   4863,15}, {   1279,14}, {   2943,13}, {   5887,15}, \
+    {   1535,14}, {   3455,13}, {   6911,15}, {   1791,14}, \
+    {   3839,16}, {   1023,15}, {   2047,14}, {   4223,15}, \
+    {   2303,14}, {   4863,15}, {   2815,14}, {   5887,16}, \
+    {   1535,15}, {   3327,14}, {   6911,15}, {   3839,17}, \
+    {   1023,16}, {   2047,15}, {   4863,16}, {   2559,15}, \
+    {   5887,14}, {  11775,16}, {   3071,15}, {   6911,16}, \
+    {   3583,15}, {   7679,14}, {  15359,17}, {   2047,16}, \
+    {   4607,15}, {   9983,14}, {  19967,16}, {   5631,15}, \
+    {  11775,17}, {   3071,16}, {  65536,17}, { 131072,18}, \
+    { 262144,19}, { 524288,20}, {1048576,21}, {2097152,22}, \
+    {4194304,23}, {8388608,24} }
+#define SQR_FFT_TABLE3_SIZE 210
+#define SQR_FFT_THRESHOLD                 3264
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  62
+#define MULLO_MUL_N_THRESHOLD             8907
+#define SQRLO_BASECASE_THRESHOLD             9
+#define SQRLO_DC_THRESHOLD                  66
+#define SQRLO_SQR_THRESHOLD               6440
+
+#define DC_DIV_QR_THRESHOLD                 52
+#define DC_DIVAPPR_Q_THRESHOLD             172
+#define DC_BDIV_QR_THRESHOLD                46
+#define DC_BDIV_Q_THRESHOLD                 92
+
+#define INV_MULMOD_BNM1_THRESHOLD           46
+#define INV_NEWTON_THRESHOLD               170
+#define INV_APPR_THRESHOLD                 167
+
+#define BINV_NEWTON_THRESHOLD              228
+#define REDC_1_TO_REDC_2_THRESHOLD          36
+#define REDC_2_TO_REDC_N_THRESHOLD          55
+
+#define MU_DIV_QR_THRESHOLD               1387
+#define MU_DIVAPPR_Q_THRESHOLD            1387
+#define MUPI_DIV_QR_THRESHOLD               77
+#define MU_BDIV_QR_THRESHOLD              1187
+#define MU_BDIV_Q_THRESHOLD               1442
+
+#define POWM_SEC_TABLE  1,16,191,452,1297
+
+#define GET_STR_DC_THRESHOLD                14
+#define GET_STR_PRECOMPUTE_THRESHOLD        21
+#define SET_STR_DC_THRESHOLD              1160
+#define SET_STR_PRECOMPUTE_THRESHOLD      2043
+
+#define FAC_DSC_THRESHOLD                  426
+#define FAC_ODD_THRESHOLD                   24
+
+#define MATRIX22_STRASSEN_THRESHOLD         14
+#define HGCD2_DIV1_METHOD                    5  /* 0.74% faster than 3 */
+#define HGCD_THRESHOLD                      96
+#define HGCD_APPR_THRESHOLD                 60
+#define HGCD_REDUCE_THRESHOLD             2681
+#define GCD_DC_THRESHOLD                   465
+#define GCDEXT_DC_THRESHOLD                345
+#define JACOBI_BASE_METHOD                   1  /* 32.22% faster than 4 */
+
+/* Tuneup completed successfully, took 276198 seconds */
diff --git a/third_party/gmp/mpn/x86_64/coreisbr/lshift.asm b/third_party/gmp/mpn/x86_64/coreisbr/lshift.asm
new file mode 100644
index 0000000..a1cbc31
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreisbr/lshift.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_lshift optimised for Intel Sandy Bridge.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_lshift)
+include_mpn(`x86_64/fastsse/lshift-movdqu2.asm')
diff --git a/third_party/gmp/mpn/x86_64/coreisbr/lshiftc.asm b/third_party/gmp/mpn/x86_64/coreisbr/lshiftc.asm
new file mode 100644
index 0000000..ac90edb
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreisbr/lshiftc.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_lshiftc optimised for Intel Sandy Bridge.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_lshiftc)
+include_mpn(`x86_64/fastsse/lshiftc-movdqu2.asm')
diff --git a/third_party/gmp/mpn/x86_64/coreisbr/mul_1.asm b/third_party/gmp/mpn/x86_64/coreisbr/mul_1.asm
new file mode 100644
index 0000000..a43a117
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreisbr/mul_1.asm
@@ -0,0 +1,199 @@
+dnl  X86-64 mpn_mul_1 optimised for Intel Sandy Bridge.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2003-2005, 2007, 2008, 2011-2013, 2017 Free Software Foundation,
+dnl  Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9
+C AMD K10
+C AMD bull
+C AMD pile
+C AMD steam
+C AMD excavator
+C AMD bobcat
+C AMD jaguar
+C Intel P4
+C Intel core2
+C Intel NHM
+C Intel SBR      2.49
+C Intel IBR      2.32
+C Intel HWL      2.44
+C Intel BWL      2.43
+C Intel SKL      2.47
+C Intel atom
+C Intel SLM
+C VIA nano
+
+C The loop of this code is the result of running a code generation and
+C optimisation tool suite written by David Harvey and Torbjorn Granlund.
+
+define(`rp',      `%rdi')   C rcx
+define(`up_param',`%rsi')   C rdx
+define(`n_param', `%rdx')   C r8
+define(`v0',      `%rcx')   C r9
+define(`cin',     `%r8')    C stack
+
+define(`up',      `%rsi')   C same as rp_param
+define(`n',	  `%r9')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+IFDOS(`	define(`rp',      `%rcx')')
+IFDOS(`	define(`up_param',`%rdx')')
+IFDOS(`	define(`n_param', `%r8')')
+IFDOS(`	define(`v0',      `%r9')')
+IFDOS(`	define(`cin',     `48(%rsp)')')
+
+IFDOS(`	define(`up',      `%rsi')')
+IFDOS(`	define(`n',       `%r8')')
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_mul_1)
+IFDOS(`	push	%rsi		')
+	mov	(up_param), %rax
+IFSTD(`	mov	n_param, n	')
+	lea	(up_param,n_param,8), up
+	lea	-8(rp,n_param,8), rp
+	neg	n
+	mul	v0
+
+	test	$1, R8(n)
+	jz	L(x0)
+L(x1):	mov	%rax, %r11
+	mov	%rdx, %r10
+	test	$2, R8(n)
+	jnz	L(01)
+
+L(11):	mov	8(up,n,8), %rax
+	dec	n
+	jmp	L(L3)
+
+L(01):	inc	n
+	jnz	L(L1)
+	mov	%rax, (rp)
+	mov	%rdx, %rax
+IFDOS(`	pop	%rsi		')
+	ret
+
+L(x0):	mov	%rax, %r10
+	mov	%rdx, %r11
+	mov	8(up,n,8), %rax
+	test	$2, R8(n)
+	jz	L(L0)
+
+L(10):	add	$-2, n
+	jmp	L(L2)
+
+	ALIGN(8)
+L(top):	mov	%rdx, %r10
+	add	%rax, %r11
+L(L1):	mov	0(up,n,8), %rax
+	adc	$0, %r10
+	mul	v0
+	add	%rax, %r10
+	mov	%r11, 0(rp,n,8)
+	mov	8(up,n,8), %rax
+	mov	%rdx, %r11
+L(L0c):	adc	$0, %r11
+L(L0):	mul	v0
+	mov	%r10, 8(rp,n,8)
+	add	%rax, %r11
+	mov	%rdx, %r10
+L(L3c):	mov	16(up,n,8), %rax
+	adc	$0, %r10
+L(L3):	mul	v0
+	mov	%r11, 16(rp,n,8)
+	mov	%rdx, %r11
+	add	%rax, %r10
+L(L2c):	mov	24(up,n,8), %rax
+	adc	$0, %r11
+L(L2):	mul	v0
+	mov	%r10, 24(rp,n,8)
+	add	$4, n
+	jnc	L(top)
+
+L(end):	add	%rax, %r11
+	mov	%rdx, %rax
+	adc	$0, %rax
+	mov	%r11, (rp)
+
+IFDOS(`	pop	%rsi		')
+	ret
+EPILOGUE()
+
+	ALIGN(16)
+PROLOGUE(mpn_mul_1c)
+IFDOS(`	push	%rsi		')
+	mov	(up_param), %rax
+IFSTD(`	mov	n_param, n	')
+	lea	(up_param,n_param,8), up
+	lea	-8(rp,n_param,8), rp
+	neg	n
+	mul	v0
+
+	test	$1, R8(n)
+	jz	L(x0c)
+L(x1c):	mov	%rax, %r11
+	mov	%rdx, %r10
+	test	$2, R8(n)
+	jnz	L(01c)
+
+L(11c):	add	cin, %r11
+	dec	n
+	jmp	L(L3c)
+
+L(01c):	add	cin, %r11
+	inc	n
+	jnz	L(L1)
+	mov	%r11, (rp)
+	mov	%rdx, %rax
+	adc	$0, %rax
+IFDOS(`	pop	%rsi		')
+	ret
+
+L(x0c):	mov	%rax, %r10
+	mov	%rdx, %r11
+	test	$2, R8(n)
+	jz	L(00c)
+
+L(10c):	add	$-2, n
+	add	cin, %r10
+	jmp	L(L2c)
+
+L(00c):	add	cin, %r10
+	mov	8(up,n,8), %rax
+	jmp	L(L0c)
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/coreisbr/mul_2.asm b/third_party/gmp/mpn/x86_64/coreisbr/mul_2.asm
new file mode 100644
index 0000000..781534d
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreisbr/mul_2.asm
@@ -0,0 +1,167 @@
+dnl  AMD64 mpn_mul_2 optimised for Intel Sandy Bridge.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2003-2005, 2007, 2008, 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb	best
+C AMD K8,K9      8.03
+C AMD K10        8.03
+C AMD bull       9.19
+C AMD pile       9.16
+C AMD steam
+C AMD excavator
+C AMD bobcat    10.6
+C AMD jaguar    11.0
+C Intel P4      26.0
+C Intel core2    8.73
+C Intel NHM      8.55
+C Intel SBR      5.15
+C Intel IBR      4.57
+C Intel HWL      4.08
+C Intel BWL      4.10
+C Intel SKL      4.14
+C Intel atom    39.5
+C Intel SLM     26.3
+C VIA nano
+
+C This code is the result of running a code generation and optimisation tool
+C suite written by David Harvey and Torbjorn Granlund.
+
+C When playing with pointers, set this to $2 to fall back to conservative
+C indexing in wind-down code.
+define(`I',`$1')
+
+define(`rp',      `%rdi')   C rcx
+define(`up',      `%rsi')   C rdx
+define(`n_param', `%rdx')   C r8
+define(`vp',      `%rcx')   C r9
+
+define(`n',	  `%rcx')
+define(`v0',      `%rbx')
+define(`v1',      `%rbp')
+
+define(`w0',	`%r8')
+define(`w1',	`%r9')
+define(`w2',	`%r10')
+define(`w3',	`%r11')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_mul_2)
+	FUNC_ENTRY(4)
+	push	%rbx
+	push	%rbp
+
+	mov	(vp), v0
+	mov	8(vp), v1
+
+	mov	(up), %rax
+	lea	(up,n_param,8), up
+	lea	(rp,n_param,8), rp
+
+	test	$1, R8(n_param)
+	jnz	L(b1)
+
+L(b0):	mov	$0, R32(n)
+	sub	n_param, n
+	xor	w0, w0
+	mul	v0
+	mov	%rax, w2
+	mov	%rdx, w1
+	mov	(up,n,8), %rax
+	jmp	L(lo0)
+
+L(b1):	mov	$1, R32(n)
+	sub	n_param, n
+	xor	w2, w2
+	mul	v0
+	mov	%rax, w0
+	mov	%rdx, w3
+	mov	-8(up,n,8), %rax
+	mul	v1
+	jmp	L(lo1)
+
+	ALIGN(32)
+L(top):	mul	v0
+	add	%rax, w0		C 1
+	mov	%rdx, w3		C 2
+	adc	$0, w3			C 2
+	mov	-8(up,n,8), %rax
+	mul	v1
+	add	w1, w0			C 1
+	adc	$0, w3			C 2
+L(lo1):	add	%rax, w2		C 2
+	mov	w0, -8(rp,n,8)		C 1
+	mov	%rdx, w0		C 3
+	adc	$0, w0			C 3
+	mov	(up,n,8), %rax
+	mul	v0
+	add	%rax, w2		C 2
+	mov	%rdx, w1		C 3
+	adc	$0, w1			C 3
+	add	w3, w2			C 2
+	mov	(up,n,8), %rax
+	adc	$0, w1			C 1
+L(lo0):	mul	v1
+	mov	w2, (rp,n,8)		C 2
+	add	%rax, w0		C 3
+	mov	%rdx, w2		C 4
+	mov	8(up,n,8), %rax
+	adc	$0, w2			C 4
+	add	$2, n
+	jnc	L(top)
+
+L(end):	mul	v0
+	add	%rax, w0
+	mov	%rdx, w3
+	adc	$0, w3
+	mov	I(-8(up),-8(up,n,8)), %rax
+	mul	v1
+	add	w1, w0
+	adc	$0, w3
+	add	%rax, w2
+	mov	w0, I(-8(rp),-8(rp,n,8))
+	adc	$0, %rdx
+	add	w3, w2
+	mov	w2, I((rp),(rp,n,8))
+	adc	$0, %rdx
+	mov	%rdx, %rax
+
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/coreisbr/mul_basecase.asm b/third_party/gmp/mpn/x86_64/coreisbr/mul_basecase.asm
new file mode 100644
index 0000000..35fd1cc
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreisbr/mul_basecase.asm
@@ -0,0 +1,407 @@
+dnl  AMD64 mpn_mul_basecase optimised for Intel Sandy bridge and Ivy bridge.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2003-2005, 2007, 2008, 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C cycles/limb	mul_1		mul_2		mul_3		addmul_2
+C AMD K8,K9
+C AMD K10
+C AMD bull
+C AMD pile
+C AMD steam
+C AMD bobcat
+C AMD jaguar
+C Intel P4
+C Intel core
+C Intel NHM
+C Intel SBR	 2.5		 2.5		 -		 2.95
+C Intel IBR	 2.4		 2.3		 -		 2.68
+C Intel HWL	 2.35		 2.0		 -		 2.5
+C Intel BWL
+C Intel atom
+C VIA nano
+
+C The inner loops of this code are the result of running a code generation and
+C optimisation tool suite written by David Harvey and Torbjorn Granlund.
+
+C TODO
+C  * Fix the addmul_2 fluctuation affecting SBR.
+C  * Improve feed-in code, avoiding zeroing of many registers and dummy adds in
+C    the loops at the expense of code size.
+C  * Adjoin a mul_3, avoiding slow mul_1 for odd vn.
+C  * Consider replacing the 2-way mul_2 code with 4-way code, for a very slight
+C    speedup.
+C  * Further micro-optimise.
+
+C When playing with pointers, set this to $2 to fall back to conservative
+C indexing in wind-down code.
+define(`I',`$1')
+
+
+define(`rp',      `%rdi')
+define(`up',      `%rsi')
+define(`un_param',`%rdx')
+define(`vp',      `%rcx')
+define(`vn',      `%r8')
+
+define(`un',      `%rbx')
+
+define(`w0',	`%r10')
+define(`w1',	`%r11')
+define(`w2',	`%r12')
+define(`w3',	`%r13')
+define(`n',	`%rbp')
+define(`v0',	`%r9')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_mul_basecase)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8d	')
+	push	%rbx
+	push	%rbp
+	mov	un_param, un		C free up rdx
+	neg	un
+
+	mov	(up), %rax		C shared for mul_1 and mul_2
+	lea	(up,un_param,8), up	C point at operand end
+	lea	(rp,un_param,8), rp	C point at rp[un-1]
+
+	mov	(vp), v0		C shared for mul_1 and mul_2
+	mul	v0			C shared for mul_1 and mul_2
+
+	test	$1, R8(vn)
+	jz	L(do_mul_2)
+
+L(do_mul_1):
+	test	$1, R8(un)
+	jnz	L(m1x1)
+
+L(m1x0):mov	%rax, w0		C un = 2, 4, 6, 8, ...
+	mov	%rdx, w1
+	mov	8(up,un,8), %rax
+	test	$2, R8(un)
+	jnz	L(m110)
+
+L(m100):lea	2(un), n		C un = 4, 8, 12, ...
+	jmp	L(m1l0)
+
+L(m110):lea	(un), n			C un = 2, 6, 10, ...
+	jmp	L(m1l2)
+
+L(m1x1):mov	%rax, w1		C un = 1, 3, 5, 7, ...
+	mov	%rdx, w0
+	test	$2, R8(un)
+	jz	L(m111)
+
+L(m101):lea	3(un), n		C un = 1, 5, 9, ...
+	test	n, n
+	js	L(m1l1)
+	mov	%rax, -8(rp)
+	mov	%rdx, (rp)
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+
+L(m111):lea	1(un), n		C un = 3, 7, 11, ...
+	mov	8(up,un,8), %rax
+	jmp	L(m1l3)
+
+	ALIGN(16)		C FIXME
+L(m1tp):mov	%rdx, w0
+	add	%rax, w1
+L(m1l1):mov	-16(up,n,8), %rax
+	adc	$0, w0
+	mul	v0
+	add	%rax, w0
+	mov	w1, -24(rp,n,8)
+	mov	-8(up,n,8), %rax
+	mov	%rdx, w1
+	adc	$0, w1
+L(m1l0):mul	v0
+	mov	w0, -16(rp,n,8)
+	add	%rax, w1
+	mov	%rdx, w0
+	mov	(up,n,8), %rax
+	adc	$0, w0
+L(m1l3):mul	v0
+	mov	w1, -8(rp,n,8)
+	mov	%rdx, w1
+	add	%rax, w0
+	mov	8(up,n,8), %rax
+	adc	$0, w1
+L(m1l2):mul	v0
+	mov	w0, (rp,n,8)
+	add	$4, n
+	jnc	L(m1tp)
+
+L(m1ed):add	%rax, w1
+	adc	$0, %rdx
+	mov	w1, I(-8(rp),-24(rp,n,8))
+	mov	%rdx, I((rp),-16(rp,n,8))
+
+	dec	R32(vn)
+	jz	L(ret2)
+
+	lea	8(vp), vp
+	lea	8(rp), rp
+	push	%r12
+	push	%r13
+	push	%r14
+	jmp	L(do_addmul)
+
+L(do_mul_2):
+define(`v1',	`%r14')
+	push	%r12
+	push	%r13
+	push	%r14
+
+	mov	8(vp), v1
+
+	test	$1, R8(un)
+	jnz	L(m2b1)
+
+L(m2b0):lea	(un), n
+	xor	w0, w0
+	mov	%rax, w2
+	mov	%rdx, w1
+	jmp	L(m2l0)
+
+L(m2b1):lea	1(un), n
+	xor	w1, w1
+	xor	w2, w2
+	mov	%rax, w0
+	mov	%rdx, w3
+	jmp	L(m2l1)
+
+	ALIGN(32)
+L(m2tp):mul	v0
+	add	%rax, w0
+	mov	%rdx, w3
+	adc	$0, w3
+L(m2l1):mov	-8(up,n,8), %rax
+	mul	v1
+	add	w1, w0
+	adc	$0, w3
+	add	%rax, w2
+	mov	w0, -8(rp,n,8)
+	mov	%rdx, w0
+	adc	$0, w0
+	mov	(up,n,8), %rax
+	mul	v0
+	add	%rax, w2
+	mov	%rdx, w1
+	adc	$0, w1
+	add	w3, w2
+L(m2l0):mov	(up,n,8), %rax
+	adc	$0, w1
+	mul	v1
+	mov	w2, (rp,n,8)
+	add	%rax, w0
+	mov	%rdx, w2
+	mov	8(up,n,8), %rax
+	adc	$0, w2
+	add	$2, n
+	jnc	L(m2tp)
+
+L(m2ed):mul	v0
+	add	%rax, w0
+	mov	%rdx, w3
+	adc	$0, w3
+	mov	I(-8(up),-8(up,n,8)), %rax
+	mul	v1
+	add	w1, w0
+	adc	$0, w3
+	add	%rax, w2
+	mov	w0, I(-8(rp),-8(rp,n,8))
+	adc	$0, %rdx
+	add	w3, w2
+	mov	w2, I((rp),(rp,n,8))
+	adc	$0, %rdx
+	mov	%rdx, I(8(rp),8(rp,n,8))
+
+	add	$-2, R32(vn)
+	jz	L(ret5)
+	lea	16(vp), vp
+	lea	16(rp), rp
+
+
+L(do_addmul):
+	push	%r15
+	push	vn			C save vn in new stack slot
+define(`vn',	`(%rsp)')
+define(`X0',	`%r14')
+define(`X1',	`%r15')
+define(`v1',	`%r8')
+
+L(outer):
+	mov	(vp), v0
+	mov	8(vp), v1
+	mov	(up,un,8), %rax
+	mul	v0
+	test	$1, R8(un)
+	jnz	L(a1x1)
+
+L(a1x0):mov	(rp,un,8), X0
+	xor	w0, w0
+	mov	%rdx, w1
+	test	$2, R8(un)
+	jnz	L(a110)
+
+L(a100):lea	2(un), n		C un = 4, 8, 12, ...
+	add	%rax, X0
+	adc	$0, w1
+	mov	(up,un,8), %rax
+	mul	v1
+	mov	8(rp,un,8), X1
+	jmp	L(lo0)
+
+L(a110):lea	(un), n			C un = 2, 6, 10, ...
+	xor	w3, w3
+	jmp	L(lo2)
+
+L(a1x1):mov	(rp,un,8), X1
+	xor	w2, w2
+	xor	w1, w1
+	test	$2, R8(un)
+	jz	L(a111)
+
+L(a101):lea	3(un), n		C un = 1, 5, 9, ...
+	mov	%rdx, w3
+	add	%rax, X1
+	mov	(up,un,8), %rax
+	mov	8(rp,un,8), X0
+	adc	$0, w3
+	jmp	L(top)
+
+L(a111):lea	1(un), n		C un = 3, 7, 11, ...
+	jmp	L(lo3)
+
+	ALIGN(32)
+L(top):	mul	v1
+	mov	%rdx, w0
+	add	%rax, X0
+	adc	$0, w0
+	add	w1, X1
+	adc	$0, w3
+	add	w2, X0
+	adc	$0, w0
+	mov	-16(up,n,8), %rax
+	mul	v0
+	add	%rax, X0
+	mov	%rdx, w1
+	adc	$0, w1
+	mov	-16(up,n,8), %rax
+	mul	v1
+	mov	X1, -24(rp,n,8)
+	mov	-8(rp,n,8), X1
+	add	w3, X0
+	adc	$0, w1
+L(lo0):	mov	%rdx, w2
+	mov	X0, -16(rp,n,8)
+	add	%rax, X1
+	adc	$0, w2
+	mov	-8(up,n,8), %rax
+	add	w0, X1
+	adc	$0, w2
+	mul	v0
+L(lo3):	add	%rax, X1
+	mov	%rdx, w3
+	adc	$0, w3
+	mov	-8(up,n,8), %rax
+	mul	v1
+	add	w1, X1
+	mov	(rp,n,8), X0
+	adc	$0, w3
+	mov	%rdx, w0
+	add	%rax, X0
+	adc	$0, w0
+	mov	(up,n,8), %rax
+	mul	v0
+	add	w2, X0
+	mov	X1, -8(rp,n,8)
+	mov	%rdx, w1
+	adc	$0, w0
+L(lo2):	add	%rax, X0
+	adc	$0, w1
+	mov	(up,n,8), %rax
+	add	w3, X0
+	adc	$0, w1
+	mul	v1
+	mov	8(rp,n,8), X1
+	add	%rax, X1
+	mov	%rdx, w2
+	adc	$0, w2
+	mov	8(up,n,8), %rax
+	mov	X0, (rp,n,8)
+	mul	v0
+	add	w0, X1
+	mov	%rdx, w3
+	adc	$0, w2
+	add	%rax, X1
+	mov	8(up,n,8), %rax
+	mov	16(rp,n,8), X0		C useless but harmless in final iter
+	adc	$0, w3
+	add	$4, n
+	jnc	L(top)
+
+L(end):	mul	v1
+	add	w1, X1
+	adc	$0, w3
+	add	w2, %rax
+	adc	$0, %rdx
+	mov	X1, I(-8(rp),-24(rp,n,8))
+	add	w3, %rax
+	adc	$0, %rdx
+	mov	%rax, I((rp),-16(rp,n,8))
+	mov	%rdx, I(8(rp),-8(rp,n,8))
+
+	addl	$-2, vn
+	lea	16(vp), vp
+	lea	16(rp), rp
+	jnz	L(outer)
+
+	pop	%rax		C deallocate vn slot
+	pop	%r15
+L(ret5):pop	%r14
+	pop	%r13
+	pop	%r12
+L(ret2):pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/coreisbr/mullo_basecase.asm b/third_party/gmp/mpn/x86_64/coreisbr/mullo_basecase.asm
new file mode 100644
index 0000000..a41a8ac
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreisbr/mullo_basecase.asm
@@ -0,0 +1,384 @@
+dnl  AMD64 mpn_mullo_basecase optimised for Intel Sandy bridge and Ivy bridge.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2008, 2009, 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C cycles/limb	mul_2		addmul_2
+C AMD K8,K9
+C AMD K10
+C AMD bull
+C AMD pile
+C AMD steam
+C AMD bobcat
+C AMD jaguar
+C Intel P4
+C Intel core
+C Intel NHM
+C Intel SBR	 2.5		 2.95
+C Intel IBR	 2.3		 2.68
+C Intel HWL	 2.0		 2.5
+C Intel BWL
+C Intel atom
+C VIA nano
+
+C The inner loops of this code are the result of running a code generation and
+C optimisation tool suite written by David Harvey and Torbjörn Granlund.
+
+C TODO
+C   * Implement proper cor2, replacing current cor0.
+C   * Offset n by 2 in order to avoid the outer loop cmp.  (And sqr_basecase?)
+C   * Micro-optimise.
+
+C When playing with pointers, set this to $2 to fall back to conservative
+C indexing in wind-down code.
+define(`I',`$1')
+
+define(`rp',       `%rdi')
+define(`up',       `%rsi')
+define(`vp_param', `%rdx')
+define(`n',        `%rcx')
+
+define(`vp',       `%r8')
+define(`X0',       `%r14')
+define(`X1',       `%r15')
+
+define(`w0',       `%r10')
+define(`w1',       `%r11')
+define(`w2',       `%r12')
+define(`w3',       `%r13')
+define(`i',        `%rbp')
+define(`v0',       `%r9')
+define(`v1',       `%rbx')
+
+C rax rbx rcx rdx rdi rsi rbp r8 r9 r10 r11 r12 r13 r14 r15
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_mullo_basecase)
+	FUNC_ENTRY(4)
+
+	mov	(up), %rax
+	mov	vp_param, vp
+
+	cmp	$4, n
+	jb	L(small)
+
+	mov	(vp_param), v0
+	push	%rbx
+	lea	(rp,n,8), rp		C point rp at R[un]
+	push	%rbp
+	lea	(up,n,8), up		C point up right after U's end
+	push	%r12
+	neg	n
+	push	%r13
+	mul	v0
+	mov	8(vp), v1
+
+	test	$1, R8(n)
+	jnz	L(m2b1)
+
+L(m2b0):lea	(n), i
+	xor	w0, w0
+	mov	%rax, w2
+	mov	%rdx, w1
+	jmp	L(m2l0)
+
+L(m2b1):lea	1(n), i
+	xor	w1, w1
+	xor	w2, w2
+	mov	%rax, w0
+	mov	%rdx, w3
+	jmp	L(m2l1)
+
+	ALIGN(32)
+L(m2tp):mul	v0
+	add	%rax, w0
+	mov	%rdx, w3
+	adc	$0, w3
+L(m2l1):mov	-8(up,i,8), %rax
+	mul	v1
+	add	w1, w0
+	adc	$0, w3
+	add	%rax, w2
+	mov	w0, -8(rp,i,8)
+	mov	%rdx, w0
+	adc	$0, w0
+	mov	(up,i,8), %rax
+	mul	v0
+	add	%rax, w2
+	mov	%rdx, w1
+	adc	$0, w1
+	add	w3, w2
+L(m2l0):mov	(up,i,8), %rax
+	adc	$0, w1
+	mul	v1
+	mov	w2, (rp,i,8)
+	add	%rax, w0
+	mov	%rdx, w2		C FIXME: dead in last iteration
+	mov	8(up,i,8), %rax
+	adc	$0, w2			C FIXME: dead in last iteration
+	add	$2, i
+	jnc	L(m2tp)
+
+L(m2ed):imul	v0, %rax
+	add	w0, %rax
+	add	w1, %rax
+	mov	%rax, I(-8(rp),-8(rp,i,8))
+
+	add	$2, n
+	lea	16(vp), vp
+	lea	-16(up), up
+	cmp	$-2, n
+	jge	L(cor1)
+
+	push	%r14
+	push	%r15
+
+L(outer):
+	mov	(vp), v0
+	mov	8(vp), v1
+	mov	(up,n,8), %rax
+	mul	v0
+	test	$1, R8(n)
+	jnz	L(a1x1)
+
+L(a1x0):mov	(rp,n,8), X1
+	xor	w2, w2
+	xor	w1, w1
+	test	$2, R8(n)
+	jnz	L(a110)
+
+L(a100):lea	1(n), i
+	jmp	L(lo0)
+
+L(a110):lea	3(n), i
+	mov	%rdx, w3
+	add	%rax, X1
+	mov	(up,n,8), %rax
+	mov	8(rp,n,8), X0
+	adc	$0, w3
+	jmp	L(lo2)
+
+L(a1x1):mov	(rp,n,8), X0
+	xor	w0, w0
+	mov	%rdx, w1
+	test	$2, R8(n)
+	jz	L(a111)
+
+L(a101):lea	2(n), i
+	add	%rax, X0
+	adc	$0, w1
+	mov	(up,n,8), %rax
+	mul	v1
+	mov	8(rp,n,8), X1
+	jmp	L(lo1)
+
+L(a111):lea	(n), i
+	xor	w3, w3
+	jmp	L(lo3)
+
+	ALIGN(32)
+L(top):
+L(lo2):	mul	v1
+	mov	%rdx, w0
+	add	%rax, X0
+	adc	$0, w0
+	add	w1, X1
+	adc	$0, w3
+	add	w2, X0
+	adc	$0, w0
+	mov	-16(up,i,8), %rax
+	mul	v0
+	add	%rax, X0
+	mov	%rdx, w1
+	adc	$0, w1
+	mov	-16(up,i,8), %rax
+	mul	v1
+	mov	X1, -24(rp,i,8)
+	mov	-8(rp,i,8), X1
+	add	w3, X0
+	adc	$0, w1
+L(lo1):	mov	%rdx, w2
+	mov	X0, -16(rp,i,8)
+	add	%rax, X1
+	adc	$0, w2
+	mov	-8(up,i,8), %rax
+	add	w0, X1
+	adc	$0, w2
+	mul	v0
+L(lo0):	add	%rax, X1
+	mov	%rdx, w3
+	adc	$0, w3
+	mov	-8(up,i,8), %rax
+	mul	v1
+	add	w1, X1
+	mov	(rp,i,8), X0
+	adc	$0, w3
+	mov	%rdx, w0
+	add	%rax, X0
+	adc	$0, w0
+	mov	(up,i,8), %rax
+	mul	v0
+	add	w2, X0
+	mov	X1, -8(rp,i,8)
+	mov	%rdx, w1
+	adc	$0, w0
+L(lo3):	add	%rax, X0
+	adc	$0, w1
+	mov	(up,i,8), %rax
+	add	w3, X0
+	adc	$0, w1
+	mul	v1
+	mov	8(rp,i,8), X1
+	add	%rax, X1
+	mov	%rdx, w2
+	adc	$0, w2
+	mov	8(up,i,8), %rax
+	mov	X0, (rp,i,8)
+	mul	v0
+	add	w0, X1
+	mov	%rdx, w3
+	adc	$0, w2
+	add	%rax, X1
+	mov	8(up,i,8), %rax
+	mov	16(rp,i,8), X0
+	adc	$0, w3
+	add	$4, i
+	jnc	L(top)
+
+L(end):	imul	v1, %rax
+	add	%rax, X0
+	add	w1, X1
+	adc	$0, w3
+	add	w2, X0
+	mov	I(-8(up),-16(up,i,8)), %rax
+	imul	v0, %rax
+	add	X0, %rax
+	mov	X1, I(-16(rp),-24(rp,i,8))
+	add	w3, %rax
+	mov	%rax, I(-8(rp),-16(rp,i,8))
+
+	add	$2, n
+	lea	16(vp), vp
+	lea	-16(up), up
+	cmp	$-2, n
+	jl	L(outer)
+
+	pop	%r15
+	pop	%r14
+
+	jnz	L(cor0)
+
+L(cor1):mov	(vp), v0
+	mov	8(vp), v1
+	mov	-16(up), %rax
+	mul	v0			C u0 x v2
+	add	-16(rp), %rax		C FIXME: rp[0] still available in reg?
+	adc	-8(rp), %rdx		C FIXME: rp[1] still available in reg?
+	mov	-8(up), %r10
+	imul	v0, %r10
+	mov	-16(up), %r11
+	imul	v1, %r11
+	mov	%rax, -16(rp)
+	add	%r10, %r11
+	add	%rdx, %r11
+	mov	%r11, -8(rp)
+	pop	%r13
+	pop	%r12
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+
+L(cor0):mov	(vp), %r11
+	imul	-8(up), %r11
+	add	%rax, %r11
+	mov	%r11, -8(rp)
+	pop	%r13
+	pop	%r12
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+
+	ALIGN(16)
+L(small):
+	cmp	$2, n
+	jae	L(gt1)
+L(n1):	imul	(vp_param), %rax
+	mov	%rax, (rp)
+	FUNC_EXIT()
+	ret
+L(gt1):	ja	L(gt2)
+L(n2):	mov	(vp_param), %r9
+	mul	%r9
+	mov	%rax, (rp)
+	mov	8(up), %rax
+	imul	%r9, %rax
+	add	%rax, %rdx
+	mov	8(vp), %r9
+	mov	(up), %rcx
+	imul	%r9, %rcx
+	add	%rcx, %rdx
+	mov	%rdx, 8(rp)
+	FUNC_EXIT()
+	ret
+L(gt2):
+L(n3):	mov	(vp_param), %r9
+	mul	%r9		C u0 x v0
+	mov	%rax, (rp)
+	mov	%rdx, %r10
+	mov	8(up), %rax
+	mul	%r9		C u1 x v0
+	imul	16(up), %r9	C u2 x v0
+	add	%rax, %r10
+	adc	%rdx, %r9
+	mov	8(vp), %r11
+	mov	(up), %rax
+	mul	%r11		C u0 x v1
+	add	%rax, %r10
+	adc	%rdx, %r9
+	imul	8(up), %r11	C u1 x v1
+	add	%r11, %r9
+	mov	%r10, 8(rp)
+	mov	16(vp), %r10
+	mov	(up), %rax
+	imul	%rax, %r10	C u0 x v2
+	add	%r10, %r9
+	mov	%r9, 16(rp)
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/coreisbr/redc_1.asm b/third_party/gmp/mpn/x86_64/coreisbr/redc_1.asm
new file mode 100644
index 0000000..f0dbe07
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreisbr/redc_1.asm
@@ -0,0 +1,546 @@
+dnl  X86-64 mpn_redc_1 optimised for Intel Sandy Bridge and Ivy Bridge.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2003-2005, 2007, 2008, 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 ?
+C AMD K10	 ?
+C AMD bull	 ?
+C AMD pile	 ?
+C AMD steam	 ?
+C AMD bobcat	 ?
+C AMD jaguar	 ?
+C Intel P4	 ?
+C Intel core	 ?
+C Intel NHM	 ?
+C Intel SBR	 3.24
+C Intel IBR	 3.04
+C Intel HWL	 ?
+C Intel BWL	 ?
+C Intel atom	 ?
+C VIA nano	 ?
+
+C The inner loops of this code are the result of running a code generation and
+C optimisation tool suite written by David Harvey and Torbjörn Granlund.
+
+C TODO
+C  * Micro-optimise, none performed thus far.
+C  * Consider inlining mpn_add_n.
+C  * Single basecases out before the pushes.
+
+C When playing with pointers, set this to $2 to fall back to conservative
+C indexing in wind-down code.
+define(`I',`$1')
+
+define(`rp',          `%rdi')   C rcx
+define(`up',          `%rsi')   C rdx
+define(`mp_param',    `%rdx')   C r8
+define(`n',           `%rcx')   C r9
+define(`u0inv',       `%r8')    C stack
+
+define(`i',           `%r14')
+define(`j',           `%r15')
+define(`mp',          `%r12')
+define(`q0',          `%r13')
+
+C rax rbx rcx rdx rdi rsi rbp r8 r9 r10 r11 r12 r13 r14 r15
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+define(`ALIGNx', `ALIGN(16)')
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_redc_1)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8	')
+	push	%rbx
+	push	%rbp
+	push	%r12
+	push	%r13
+	push	%r14
+	push	%r15
+
+	mov	(up), q0
+	mov	n, j			C outer loop induction var
+	lea	8(mp_param,n,8), mp
+	lea	8(up,n,8), up
+	neg	n
+	imul	u0inv, q0		C first iteration q0
+
+	test	$1, R8(n)
+	jz	L(bx0)
+
+L(bx1):	test	$2, R8(n)
+	jz	L(b3)
+
+L(b1):	cmp	$-1, R32(n)
+	jz	L(n1)
+
+L(otp1):lea	1(n), i
+	mov	-8(mp,n,8), %rax
+	mul	q0
+	mov	-8(up,n,8), %r10
+	mov	%rdx, %r11
+	add	%rax, %r10
+	mov	(mp,n,8), %rax
+	adc	$0, %r11
+	mul	q0
+	mov	%rdx, %r9
+	mov	(up,n,8), %rbx
+	add	%rax, %rbx
+	adc	$0, %r9
+	mov	(mp,i,8), %rax
+	mul	q0
+	mov	(up,i,8), %r10
+	add	%r11, %rbx
+	mov	%rbx, -8(up,i,8)	C next low remainder limb
+	adc	$0, %r9
+	imul	u0inv, %rbx		C next q limb
+	jmp	L(e1)
+
+	ALIGNx
+L(tp1):	mul	q0
+	mov	-16(up,i,8), %r10
+	add	%r11, %rbp
+	mov	%rdx, %r11
+	adc	$0, %r9
+	mov	%rbp, -24(up,i,8)
+	add	%rax, %r10
+	mov	-8(mp,i,8), %rax
+	adc	$0, %r11
+	mul	q0
+	add	%r9, %r10
+	mov	%rdx, %r9
+	mov	-8(up,i,8), %rbp
+	adc	$0, %r11
+	mov	%r10, -16(up,i,8)
+	add	%rax, %rbp
+	adc	$0, %r9
+	mov	(mp,i,8), %rax
+	mul	q0
+	mov	(up,i,8), %r10
+	add	%r11, %rbp
+	mov	%rbp, -8(up,i,8)
+	adc	$0, %r9
+L(e1):	mov	%rdx, %r11
+	add	%rax, %r10
+	mov	8(mp,i,8), %rax
+	adc	$0, %r11
+	mul	q0
+	mov	8(up,i,8), %rbp
+	add	%r9, %r10
+	mov	%rdx, %r9
+	mov	%r10, (up,i,8)
+	adc	$0, %r11
+	add	%rax, %rbp
+	adc	$0, %r9
+	mov	16(mp,i,8), %rax
+	add	$4, i
+	jnc	L(tp1)
+
+L(ed1):	mul	q0
+	mov	I(-16(up),-16(up,i,8)), %r10
+	add	%r11, %rbp
+	adc	$0, %r9
+	mov	%rbp, I(-24(up),-24(up,i,8))
+	add	%rax, %r10
+	adc	$0, %rdx
+	add	%r9, %r10
+	adc	$0, %rdx
+	mov	%r10, I(-16(up),-16(up,i,8))
+	mov	%rdx, -8(up,n,8)	C up[0]
+	mov	%rbx, q0		C previously computed q limb -> q0
+	lea	8(up), up		C up++
+	dec	j
+	jnz	L(otp1)
+	jmp	L(cj)
+
+L(b3):	cmp	$-3, R32(n)
+	jz	L(n3)
+
+L(otp3):lea	3(n), i
+	mov	-8(mp,n,8), %rax
+	mul	q0
+	mov	-8(up,n,8), %r10
+	mov	%rdx, %r11
+	add	%rax, %r10
+	mov	(mp,n,8), %rax
+	adc	$0, %r11
+	mul	q0
+	mov	(up,n,8), %rbx
+	mov	%rdx, %r9
+	add	%rax, %rbx
+	adc	$0, %r9
+	mov	8(mp,n,8), %rax
+	mul	q0
+	mov	8(up,n,8), %r10
+	add	%r11, %rbx
+	mov	%rdx, %r11
+	adc	$0, %r9
+	mov	%rbx, (up,n,8)
+	imul	u0inv, %rbx		C next q limb
+	jmp	L(e3)
+
+	ALIGNx
+L(tp3):	mul	q0
+	mov	-16(up,i,8), %r10
+	add	%r11, %rbp
+	mov	%rdx, %r11
+	adc	$0, %r9
+	mov	%rbp, -24(up,i,8)
+L(e3):	add	%rax, %r10
+	mov	-8(mp,i,8), %rax
+	adc	$0, %r11
+	mul	q0
+	add	%r9, %r10
+	mov	%rdx, %r9
+	mov	-8(up,i,8), %rbp
+	adc	$0, %r11
+	mov	%r10, -16(up,i,8)
+	add	%rax, %rbp
+	adc	$0, %r9
+	mov	(mp,i,8), %rax
+	mul	q0
+	mov	(up,i,8), %r10
+	add	%r11, %rbp
+	mov	%rbp, -8(up,i,8)
+	adc	$0, %r9
+	mov	%rdx, %r11
+	add	%rax, %r10
+	mov	8(mp,i,8), %rax
+	adc	$0, %r11
+	mul	q0
+	mov	8(up,i,8), %rbp
+	add	%r9, %r10
+	mov	%rdx, %r9
+	mov	%r10, (up,i,8)
+	adc	$0, %r11
+	add	%rax, %rbp
+	adc	$0, %r9
+	mov	16(mp,i,8), %rax
+	add	$4, i
+	jnc	L(tp3)
+
+L(ed3):	mul	q0
+	mov	I(-16(up),-16(up,i,8)), %r10
+	add	%r11, %rbp
+	adc	$0, %r9
+	mov	%rbp, I(-24(up),-24(up,i,8))
+	add	%rax, %r10
+	adc	$0, %rdx
+	add	%r9, %r10
+	adc	$0, %rdx
+	mov	%r10, I(-16(up),-16(up,i,8))
+	mov	%rdx, -8(up,n,8)	C up[0]
+	mov	%rbx, q0		C previously computed q limb -> q0
+	lea	8(up), up		C up++
+	dec	j
+	jnz	L(otp3)
+C	jmp	L(cj)
+
+L(cj):
+IFSTD(`	lea	-8(up,n,8), up		C param 2: up
+	lea	(up,n,8), %rdx		C param 3: up - n
+	neg	R32(n)		')	C param 4: n
+
+IFDOS(`	lea	-8(up,n,8), %rdx	C param 2: up
+	lea	(%rdx,n,8), %r8		C param 3: up - n
+	neg	R32(n)
+	mov	n, %r9			C param 4: n
+	mov	rp, %rcx	')	C param 1: rp
+
+IFSTD(`	sub	$8, %rsp	')
+IFDOS(`	sub	$40, %rsp	')
+	ASSERT(nz, `test $15, %rsp')
+	CALL(	mpn_add_n)
+IFSTD(`	add	$8, %rsp	')
+IFDOS(`	add	$40, %rsp	')
+
+L(ret):	pop	%r15
+	pop	%r14
+	pop	%r13
+	pop	%r12
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+
+L(bx0):	test	$2, R8(n)
+	jnz	L(b2)
+
+L(b0):
+L(otp0):lea	(n), i
+	mov	-8(mp,n,8), %rax
+	mul	q0
+	mov	%rdx, %r9
+	mov	-8(up,n,8), %rbp
+	add	%rax, %rbp
+	adc	$0, %r9
+	mov	(mp,n,8), %rax
+	mul	q0
+	mov	(up,n,8), %rbx
+	mov	%rdx, %r11
+	add	%rax, %rbx
+	mov	8(mp,n,8), %rax
+	adc	$0, %r11
+	mul	q0
+	mov	8(up,n,8), %rbp
+	add	%r9, %rbx
+	mov	%rdx, %r9
+	mov	%rbx, (up,n,8)
+	adc	$0, %r11
+	imul	u0inv, %rbx		C next q limb
+	jmp	L(e0)
+
+	ALIGNx
+L(tp0):	mul	q0
+	mov	-16(up,i,8), %r10
+	add	%r11, %rbp
+	mov	%rdx, %r11
+	adc	$0, %r9
+	mov	%rbp, -24(up,i,8)
+	add	%rax, %r10
+	mov	-8(mp,i,8), %rax
+	adc	$0, %r11
+	mul	q0
+	add	%r9, %r10
+	mov	%rdx, %r9
+	mov	-8(up,i,8), %rbp
+	adc	$0, %r11
+	mov	%r10, -16(up,i,8)
+	add	%rax, %rbp
+	adc	$0, %r9
+	mov	(mp,i,8), %rax
+	mul	q0
+	mov	(up,i,8), %r10
+	add	%r11, %rbp
+	mov	%rbp, -8(up,i,8)
+	adc	$0, %r9
+	mov	%rdx, %r11
+	add	%rax, %r10
+	mov	8(mp,i,8), %rax
+	adc	$0, %r11
+	mul	q0
+	mov	8(up,i,8), %rbp
+	add	%r9, %r10
+	mov	%rdx, %r9
+	mov	%r10, (up,i,8)
+	adc	$0, %r11
+L(e0):	add	%rax, %rbp
+	adc	$0, %r9
+	mov	16(mp,i,8), %rax
+	add	$4, i
+	jnc	L(tp0)
+
+L(ed0):	mul	q0
+	mov	I(-16(up),-16(up,i,8)), %r10
+	add	%r11, %rbp
+	adc	$0, %r9
+	mov	%rbp, I(-24(up),-24(up,i,8))
+	add	%rax, %r10
+	adc	$0, %rdx
+	add	%r9, %r10
+	adc	$0, %rdx
+	mov	%r10, I(-16(up),-16(up,i,8))
+	mov	%rdx, -8(up,n,8)	C up[0]
+	mov	%rbx, q0		C previously computed q limb -> q0
+	lea	8(up), up		C up++
+	dec	j
+	jnz	L(otp0)
+	jmp	L(cj)
+
+L(b2):	cmp	$-2, R32(n)
+	jz	L(n2)
+
+L(otp2):lea	2(n), i
+	mov	-8(mp,n,8), %rax
+	mul	q0
+	mov	-8(up,n,8), %rbp
+	mov	%rdx, %r9
+	add	%rax, %rbp
+	adc	$0, %r9
+	mov	(mp,n,8), %rax
+	mul	q0
+	mov	(up,n,8), %rbx
+	mov	%rdx, %r11
+	add	%rax, %rbx
+	mov	8(mp,n,8), %rax
+	adc	$0, %r11
+	mul	q0
+	add	%r9, %rbx
+	mov	%rdx, %r9
+	mov	8(up,n,8), %rbp
+	adc	$0, %r11
+	mov	%rbx, (up,n,8)
+	imul	u0inv, %rbx		C next q limb
+	jmp	L(e2)
+
+	ALIGNx
+L(tp2):	mul	q0
+	mov	-16(up,i,8), %r10
+	add	%r11, %rbp
+	mov	%rdx, %r11
+	adc	$0, %r9
+	mov	%rbp, -24(up,i,8)
+	add	%rax, %r10
+	mov	-8(mp,i,8), %rax
+	adc	$0, %r11
+	mul	q0
+	add	%r9, %r10
+	mov	%rdx, %r9
+	mov	-8(up,i,8), %rbp
+	adc	$0, %r11
+	mov	%r10, -16(up,i,8)
+L(e2):	add	%rax, %rbp
+	adc	$0, %r9
+	mov	(mp,i,8), %rax
+	mul	q0
+	mov	(up,i,8), %r10
+	add	%r11, %rbp
+	mov	%rbp, -8(up,i,8)
+	adc	$0, %r9
+	mov	%rdx, %r11
+	add	%rax, %r10
+	mov	8(mp,i,8), %rax
+	adc	$0, %r11
+	mul	q0
+	mov	8(up,i,8), %rbp
+	add	%r9, %r10
+	mov	%rdx, %r9
+	mov	%r10, (up,i,8)
+	adc	$0, %r11
+	add	%rax, %rbp
+	adc	$0, %r9
+	mov	16(mp,i,8), %rax
+	add	$4, i
+	jnc	L(tp2)
+
+L(ed2):	mul	q0
+	mov	I(-16(up),-16(up,i,8)), %r10
+	add	%r11, %rbp
+	adc	$0, %r9
+	mov	%rbp, I(-24(up),-24(up,i,8))
+	add	%rax, %r10
+	adc	$0, %rdx
+	add	%r9, %r10
+	adc	$0, %rdx
+	mov	%r10, I(-16(up),-16(up,i,8))
+	mov	%rdx, -8(up,n,8)	C up[0]
+	mov	%rbx, q0		C previously computed q limb -> q0
+	lea	8(up), up		C up++
+	dec	j
+	jnz	L(otp2)
+	jmp	L(cj)
+
+L(n1):	mov	(mp_param), %rax
+	mul	q0
+	add	-16(up), %rax
+	adc	-8(up), %rdx
+	mov	%rdx, (rp)
+	mov	$0, R32(%rax)
+	adc	R32(%rax), R32(%rax)
+	jmp	L(ret)
+
+L(n2):	mov	(mp_param), %rax
+	mov	-24(up), %rbp
+	mul	q0
+	add	%rax, %rbp
+	mov	%rdx, %r9
+	adc	$0, %r9
+	mov	-16(mp), %rax
+	mov	-16(up), %r10
+	mul	q0
+	add	%rax, %r10
+	mov	%rdx, %r11
+	adc	$0, %r11
+	add	%r9, %r10
+	adc	$0, %r11
+	mov	%r10, q0
+	imul	u0inv, q0		C next q0
+	mov	-24(mp), %rax
+	mul	q0
+	add	%rax, %r10
+	mov	%rdx, %r9
+	adc	$0, %r9
+	mov	-16(mp), %rax
+	mov	-8(up), %r14
+	mul	q0
+	add	%rax, %r14
+	adc	$0, %rdx
+	add	%r9, %r14
+	adc	$0, %rdx
+	xor	R32(%rax), R32(%rax)
+	add	%r11, %r14
+	adc	(up), %rdx
+	mov	%r14, (rp)
+	mov	%rdx, 8(rp)
+	adc	R32(%rax), R32(%rax)
+	jmp	L(ret)
+
+	ALIGNx
+L(n3):	mov	-32(mp), %rax
+	mov	-32(up), %r10
+	mul	q0
+	add	%rax, %r10
+	mov	-24(mp), %rax
+	mov	%rdx, %r11
+	adc	$0, %r11
+	mov	-24(up), %rbp
+	mul	q0
+	add	%rax, %rbp
+	mov	%rdx, %r9
+	adc	$0, %r9
+	mov	-16(mp), %rax
+	add	%r11, %rbp
+	mov	-16(up), %r10
+	adc	$0, %r9
+	mul	q0
+	mov	%rbp, q0
+	imul	u0inv, q0		C next q0
+	add	%rax, %r10
+	mov	%rdx, %r11
+	adc	$0, %r11
+	mov	%rbp, -24(up)
+	add	%r9, %r10
+	adc	$0, %r11
+	mov	%r10, -16(up)
+	mov	%r11, -32(up)		C up[0]
+	lea	8(up), up		C up++
+	dec	j
+	jnz	L(n3)
+	jmp	L(cj)
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86_64/coreisbr/rsh1aors_n.asm b/third_party/gmp/mpn/x86_64/coreisbr/rsh1aors_n.asm
new file mode 100644
index 0000000..fd2eaea
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreisbr/rsh1aors_n.asm
@@ -0,0 +1,193 @@
+dnl  X86-64 mpn_rsh1add_n, mpn_rsh1sub_n optimised for Intel Sandy Bridge.
+
+dnl  Copyright 2003, 2005, 2009-2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C	     cycles/limb
+C AMD K8,K9	 ?
+C AMD K10	 4.25
+C Intel P4	 21.5
+C Intel core2	 3.2
+C Intel NHM	 3.87
+C Intel SBR	 2.05
+C Intel atom	 ?
+C VIA nano	 44.9
+
+C INPUT PARAMETERS
+define(`rp', `%rdi')
+define(`up', `%rsi')
+define(`vp', `%rdx')
+define(`n',  `%rcx')
+
+ifdef(`OPERATION_rsh1add_n', `
+	define(ADDSUB,	      add)
+	define(ADCSBB,	      adc)
+	define(func_n,	      mpn_rsh1add_n)
+	define(func_nc,	      mpn_rsh1add_nc)')
+ifdef(`OPERATION_rsh1sub_n', `
+	define(ADDSUB,	      sub)
+	define(ADCSBB,	      sbb)
+	define(func_n,	      mpn_rsh1sub_n)
+	define(func_nc,	      mpn_rsh1sub_nc)')
+
+MULFUNC_PROLOGUE(mpn_rsh1add_n mpn_rsh1add_nc mpn_rsh1sub_n mpn_rsh1sub_nc)
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+
+	ALIGN(16)
+PROLOGUE(func_nc)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8	')
+	push	%rbx
+	push	%rbp
+
+	neg	%r8			C set C flag from parameter
+	mov	(up), %rbp
+	ADCSBB	(vp), %rbp
+
+	jmp	L(ent)
+EPILOGUE()
+
+	ALIGN(16)
+PROLOGUE(func_n)
+	FUNC_ENTRY(4)
+	push	%rbx
+	push	%rbp
+
+	mov	(up), %rbp
+	ADDSUB	(vp), %rbp
+L(ent):
+	sbb	R32(%rbx), R32(%rbx)	C save cy
+	mov	R32(%rbp), R32(%rax)
+	and	$1, R32(%rax)		C return value
+
+	mov	R32(n), R32(%r11)
+	and	$3, R32(%r11)
+
+	cmp	$1, R32(%r11)
+	je	L(do)			C jump if n = 1 5 9 ...
+
+L(n1):	cmp	$2, R32(%r11)
+	jne	L(n2)			C jump unless n = 2 6 10 ...
+	add	R32(%rbx), R32(%rbx)	C restore cy
+	mov	8(up), %r10
+	ADCSBB	8(vp), %r10
+	lea	8(up), up
+	lea	8(vp), vp
+	lea	8(rp), rp
+	sbb	R32(%rbx), R32(%rbx)	C save cy
+
+	shrd	$1, %r10, %rbp
+	mov	%rbp, -8(rp)
+	jmp	L(cj1)
+
+L(n2):	cmp	$3, R32(%r11)
+	jne	L(n3)			C jump unless n = 3 7 11 ...
+	add	R32(%rbx), R32(%rbx)	C restore cy
+	mov	8(up), %r9
+	mov	16(up), %r10
+	ADCSBB	8(vp), %r9
+	ADCSBB	16(vp), %r10
+	lea	16(up), up
+	lea	16(vp), vp
+	lea	16(rp), rp
+	sbb	R32(%rbx), R32(%rbx)	C save cy
+
+	shrd	$1, %r9, %rbp
+	mov	%rbp, -16(rp)
+	jmp	L(cj2)
+
+L(n3):	dec	n			C come here for n = 4 8 12 ...
+	add	R32(%rbx), R32(%rbx)	C restore cy
+	mov	8(up), %r8
+	mov	16(up), %r9
+	ADCSBB	8(vp), %r8
+	ADCSBB	16(vp), %r9
+	mov	24(up), %r10
+	ADCSBB	24(vp), %r10
+	lea	24(up), up
+	lea	24(vp), vp
+	lea	24(rp), rp
+	sbb	R32(%rbx), R32(%rbx)	C save cy
+
+	shrd	$1, %r8, %rbp
+	mov	%rbp, -24(rp)
+	shrd	$1, %r9, %r8
+	mov	%r8, -16(rp)
+L(cj2):	shrd	$1, %r10, %r9
+	mov	%r9, -8(rp)
+L(cj1):	mov	%r10, %rbp
+
+L(do):
+	shr	$2, n			C				4
+	je	L(end)			C				2
+	ALIGN(16)
+L(top):	add	R32(%rbx), R32(%rbx)		C restore cy
+
+	mov	8(up), %r8
+	mov	16(up), %r9
+	ADCSBB	8(vp), %r8
+	ADCSBB	16(vp), %r9
+	mov	24(up), %r10
+	mov	32(up), %r11
+	ADCSBB	24(vp), %r10
+	ADCSBB	32(vp), %r11
+
+	lea	32(up), up
+	lea	32(vp), vp
+
+	sbb	R32(%rbx), R32(%rbx)	C save cy
+
+	shrd	$1, %r8, %rbp
+	mov	%rbp, (rp)
+	shrd	$1, %r9, %r8
+	mov	%r8, 8(rp)
+	shrd	$1, %r10, %r9
+	mov	%r9, 16(rp)
+	shrd	$1, %r11, %r10
+	mov	%r10, 24(rp)
+
+	dec	n
+	mov	%r11, %rbp
+	lea	32(rp), rp
+	jne	L(top)
+
+L(end):	shrd	$1, %rbx, %rbp
+	mov	%rbp, (rp)
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/coreisbr/rshift.asm b/third_party/gmp/mpn/x86_64/coreisbr/rshift.asm
new file mode 100644
index 0000000..4c1c0d4
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreisbr/rshift.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_rshift optimised for Intel Sandy Bridge.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_rshift)
+include_mpn(`x86_64/fastsse/rshift-movdqu2.asm')
diff --git a/third_party/gmp/mpn/x86_64/coreisbr/sec_tabselect.asm b/third_party/gmp/mpn/x86_64/coreisbr/sec_tabselect.asm
new file mode 100644
index 0000000..e436034
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreisbr/sec_tabselect.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_sec_tabselect.
+
+dnl  Copyright 2012, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_sec_tabselect)
+include_mpn(`x86_64/fastsse/sec_tabselect.asm')
diff --git a/third_party/gmp/mpn/x86_64/coreisbr/sqr_basecase.asm b/third_party/gmp/mpn/x86_64/coreisbr/sqr_basecase.asm
new file mode 100644
index 0000000..46a3612
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/coreisbr/sqr_basecase.asm
@@ -0,0 +1,484 @@
+dnl  AMD64 mpn_sqr_basecase optimised for Intel Sandy bridge and Ivy bridge.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2008, 2009, 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C cycles/limb	mul_2		addmul_2	sqr_diag_addlsh1
+C AMD K8,K9	 ?		 ?			 ?
+C AMD K10	 ?		 ?			 ?
+C AMD bull	 ?		 ?			 ?
+C AMD pile	 ?		 ?			 ?
+C AMD steam	 ?		 ?			 ?
+C AMD bobcat	 ?		 ?			 ?
+C AMD jaguar	 ?		 ?			 ?
+C Intel P4	 ?		 ?			 ?
+C Intel core	 ?		 ?			 ?
+C Intel NHM	 ?		 ?			 ?
+C Intel SBR	 2.57		 2.93			 3.0
+C Intel IBR	 2.35		 2.66			 3.0
+C Intel HWL	 2.02		 2.5			 2.5
+C Intel BWL	 ?		 ?			 ?
+C Intel atom	 ?		 ?			 ?
+C VIA nano	 ?		 ?			 ?
+
+C The inner loops of this code are the result of running a code generation and
+C optimisation tool suite written by David Harvey and Torbjörn Granlund, except
+C that the sqr_diag_addlsh1 loop was manually written.
+
+C TODO
+C  * Replace current unoptimised sqr_diag_addlsh1 loop, 2.5 c/l should be easy.
+C  * Streamline pointer updates.
+C  * Perhaps suppress a few more xor insns in feed-in code.
+C  * Make sure we write no dead registers in feed-in code.
+C  * We might use 32-bit size ops, since n >= 2^32 is non-terminating.  Watch
+C    out for negative sizes being zero-extended, though.
+C  * The straight-line code for n <= 3 comes from the K8 code, and might be
+C    quite sub-optimal here.  Write specific code, and add code for n = 4.
+C  * The mul_2 loop has a 10 insn common sequence in the loop start and the
+C    wind-down code.  Try re-rolling it.
+C  * This file has been the subject to just basic micro-optimisation.
+
+C When playing with pointers, set this to $2 to fall back to conservative
+C indexing in wind-down code.
+define(`I',`$1')
+
+define(`rp',	  `%rdi')
+define(`up',	  `%rsi')
+define(`un_param',`%rdx')
+
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_sqr_basecase)
+	FUNC_ENTRY(3)
+
+	cmp	$2, un_param
+	jae	L(gt1)
+
+	mov	(up), %rax
+	mul	%rax
+	mov	%rax, (rp)
+	mov	%rdx, 8(rp)
+	FUNC_EXIT()
+	ret
+
+L(gt1):	jne	L(gt2)
+
+	mov	(up), %rax
+	mov	%rax, %r8
+	mul	%rax
+	mov	8(up), %r11
+	mov	%rax, (rp)
+	mov	%r11, %rax
+	mov	%rdx, %r9
+	mul	%rax
+	mov	%rax, %r10
+	mov	%r11, %rax
+	mov	%rdx, %r11
+	mul	%r8
+	xor	%r8, %r8
+	add	%rax, %r9
+	adc	%rdx, %r10
+	adc	%r8, %r11
+	add	%rax, %r9
+	mov	%r9, 8(rp)
+	adc	%rdx, %r10
+	mov	%r10, 16(rp)
+	adc	%r8, %r11
+	mov	%r11, 24(rp)
+	FUNC_EXIT()
+	ret
+
+L(gt2):	cmp	$4, un_param
+	jae	L(gt3)
+define(`v0', `%r8')
+define(`v1', `%r9')
+define(`w0', `%r10')
+define(`w2', `%r11')
+
+	mov	(up), %rax
+	mov	%rax, %r10
+	mul	%rax
+	mov	8(up), %r11
+	mov	%rax, (rp)
+	mov	%r11, %rax
+	mov	%rdx, 8(rp)
+	mul	%rax
+	mov	16(up), %rcx
+	mov	%rax, 16(rp)
+	mov	%rcx, %rax
+	mov	%rdx, 24(rp)
+	mul	%rax
+	mov	%rax, 32(rp)
+	mov	%rdx, 40(rp)
+
+	mov	%r11, %rax
+	mul	%r10
+	mov	%rax, %r8
+	mov	%rcx, %rax
+	mov	%rdx, %r9
+	mul	%r10
+	xor	%r10, %r10
+	add	%rax, %r9
+	mov	%r11, %rax
+	mov	%r10, %r11
+	adc	%rdx, %r10
+
+	mul	%rcx
+	add	%rax, %r10
+	adc	%r11, %rdx
+	add	%r8, %r8
+	adc	%r9, %r9
+	adc	%r10, %r10
+	adc	%rdx, %rdx
+	adc	%r11, %r11
+	add	%r8, 8(rp)
+	adc	%r9, 16(rp)
+	adc	%r10, 24(rp)
+	adc	%rdx, 32(rp)
+	adc	%r11, 40(rp)
+	FUNC_EXIT()
+	ret
+
+L(gt3):
+
+define(`v0', `%r8')
+define(`v1', `%r9')
+define(`w0', `%r10')
+define(`w1', `%r11')
+define(`w2', `%rbx')
+define(`w3', `%rbp')
+define(`un', `%r12')
+define(`n',  `%rcx')
+
+define(`X0', `%r13')
+define(`X1', `%r14')
+
+L(do_mul_2):
+	mov	(up), v0
+	push	%rbx
+	lea	(rp,un_param,8), rp	C point rp at R[un]
+	mov	8(up), %rax
+	push	%rbp
+	lea	(up,un_param,8), up	C point up right after U's end
+	mov	%rax, v1
+	push	%r12
+	mov	$1, R32(un)		C free up rdx
+	push	%r13
+	sub	un_param, un
+	push	%r14
+	push	un
+	mul	v0
+	mov	%rax, (rp,un,8)
+	mov	8(up,un,8), %rax
+	test	$1, R8(un)
+	jnz	L(m2b1)
+
+L(m2b0):lea	2(un), n
+	xor	R32(w1), R32(w1)	C FIXME
+	xor	R32(w2), R32(w2)	C FIXME
+	mov	%rdx, w0
+	jmp	L(m2l0)
+
+L(m2b1):lea	1(un), n
+	xor	R32(w3), R32(w3)	C FIXME
+	xor	R32(w0), R32(w0)	C FIXME
+	mov	%rdx, w2
+	jmp	L(m2l1)
+
+	ALIGN(32)
+L(m2tp):
+L(m2l0):mul	v0
+	add	%rax, w0
+	mov	%rdx, w3
+	adc	$0, w3
+	mov	-8(up,n,8), %rax
+	mul	v1
+	add	w1, w0
+	adc	$0, w3
+	add	%rax, w2
+	mov	w0, -8(rp,n,8)
+	mov	%rdx, w0
+	adc	$0, w0
+	mov	(up,n,8), %rax
+L(m2l1):mul	v0
+	add	%rax, w2
+	mov	%rdx, w1
+	adc	$0, w1
+	add	w3, w2
+	mov	(up,n,8), %rax
+	adc	$0, w1
+	mul	v1
+	mov	w2, (rp,n,8)
+	add	%rax, w0
+	mov	%rdx, w2
+	mov	8(up,n,8), %rax
+	adc	$0, w2
+	add	$2, n
+	jnc	L(m2tp)
+
+L(m2ed):mul	v0
+	add	%rax, w0
+	mov	%rdx, w3
+	adc	$0, w3
+	mov	I(-8(up),-8(up,n,8)), %rax
+	mul	v1
+	add	w1, w0
+	adc	$0, w3
+	add	%rax, w2
+	mov	w0, I(-8(rp),-8(rp,n,8))
+	adc	$0, %rdx
+	add	w3, w2
+	mov	w2, I((rp),(rp,n,8))
+	adc	$0, %rdx
+	mov	%rdx, I(8(rp),8(rp,n,8))
+
+	add	$2, un			C decrease |un|
+
+L(do_addmul_2):
+L(outer):
+	lea	16(rp), rp
+	cmp	$-2, R32(un)		C jump if un C {-1,0}  FIXME jump if un C {-2,1}
+	jge	L(corner)		C FIXME: move to before the lea above
+
+	mov	-8(up,un,8), v0
+	mov	(up,un,8), %rax
+	mov	%rax, v1
+	mul	v0
+	test	$1, R8(un)
+	jnz	L(a1x1)
+
+L(a1x0):mov	(rp,un,8), X0
+	xor	w0, w0
+	mov	8(rp,un,8), X1
+	add	%rax, X0
+	mov	%rdx, w1
+	adc	$0, w1
+	xor	w2, w2
+	mov	X0, (rp,un,8)
+	mov	8(up,un,8), %rax
+	test	$2, R8(un)
+	jnz	L(a110)
+
+L(a100):lea	2(un), n		C un = 4, 8, 12, ...
+	jmp	L(lo0)
+
+L(a110):lea	(un), n			C un = 2, 6, 10, ...
+	jmp	L(lo2)
+
+L(a1x1):mov	(rp,un,8), X1
+	xor	w2, w2
+	mov	8(rp,un,8), X0
+	add	%rax, X1
+	mov	%rdx, w3
+	adc	$0, w3
+	xor	w0, w0
+	mov	8(up,un,8), %rax
+	test	$2, R8(un)
+	jz	L(a111)
+
+L(a101):lea	3(un), n		C un = 1, 5, 9, ...
+	jmp	L(lo1)
+
+L(a111):lea	1(un), n		C un = 3, 7, 11, ...
+	jmp	L(lo3)
+
+	ALIGN(32)
+L(top):	mul	v1
+	mov	%rdx, w0
+	add	%rax, X0
+	adc	$0, w0
+	add	w1, X1
+	adc	$0, w3
+	add	w2, X0
+	adc	$0, w0
+	mov	-16(up,n,8), %rax
+L(lo1):	mul	v0
+	add	%rax, X0
+	mov	%rdx, w1
+	adc	$0, w1
+	mov	-16(up,n,8), %rax
+	mul	v1
+	mov	X1, -24(rp,n,8)
+	mov	-8(rp,n,8), X1
+	add	w3, X0
+	adc	$0, w1
+	mov	%rdx, w2
+	mov	X0, -16(rp,n,8)
+	add	%rax, X1
+	adc	$0, w2
+	mov	-8(up,n,8), %rax
+	add	w0, X1
+	adc	$0, w2
+L(lo0):	mul	v0
+	add	%rax, X1
+	mov	%rdx, w3
+	adc	$0, w3
+	mov	-8(up,n,8), %rax
+	mul	v1
+	add	w1, X1
+	mov	(rp,n,8), X0
+	adc	$0, w3
+	mov	%rdx, w0
+	add	%rax, X0
+	adc	$0, w0
+	mov	(up,n,8), %rax
+L(lo3):	mul	v0
+	add	w2, X0
+	mov	X1, -8(rp,n,8)
+	mov	%rdx, w1
+	adc	$0, w0
+	add	%rax, X0
+	adc	$0, w1
+	mov	(up,n,8), %rax
+	add	w3, X0
+	adc	$0, w1
+	mul	v1
+	mov	8(rp,n,8), X1
+	add	%rax, X1
+	mov	%rdx, w2
+	adc	$0, w2
+	mov	8(up,n,8), %rax
+	mov	X0, (rp,n,8)
+L(lo2):	mul	v0
+	add	w0, X1
+	mov	%rdx, w3
+	adc	$0, w2
+	add	%rax, X1
+	mov	8(up,n,8), %rax
+	mov	16(rp,n,8), X0
+	adc	$0, w3
+	add	$4, n
+	jnc	L(top)
+
+L(end):	mul	v1
+	add	w1, X1
+	adc	$0, w3
+	add	w2, %rax
+	adc	$0, %rdx
+	mov	X1, I(-8(rp),-24(rp,n,8))
+	add	w3, %rax
+	adc	$0, %rdx
+	mov	%rax, I((rp),-16(rp,n,8))
+	mov	%rdx, I(8(rp),-8(rp,n,8))
+
+	add	$2, un			C decrease |un|
+	jmp	L(outer)		C loop until a small corner remains
+
+L(corner):
+	pop	n
+	jg	L(small_corner)
+
+	lea	8(rp), rp
+	mov	-24(up), v0
+	mov	-16(up), %rax
+	mov	%rax, v1
+	mul	v0
+	mov	-24(rp), X0
+	mov	-16(rp), X1
+	add	%rax, X0
+	mov	%rdx, w1
+	adc	$0, w1
+	xor	w2, w2
+	mov	X0, -24(rp)
+	mov	-8(up), %rax
+	mul	v0
+	add	$0, X1
+	mov	%rdx, w3
+	adc	$0, w2
+	add	%rax, X1
+	mov	-8(up), %rax
+	adc	$0, w3
+	mul	v1
+	add	w1, X1
+	adc	$0, w3
+	add	w2, %rax
+	adc	$0, %rdx
+	mov	X1, -16(rp)
+	jmp	L(com)
+
+L(small_corner):
+	mov	-8(rp), w3
+	mov	-16(up), v0
+	mov	-8(up), %rax
+	mul	v0
+L(com):	add	w3, %rax
+	adc	$0, %rdx
+	mov	%rax, -8(rp)
+	mov	%rdx, (rp)
+
+L(sqr_diag_addlsh1):
+	mov	-8(up,n,8), %rax
+	shl	n
+	mul	%rax
+	mov	%rax, (rp,n,8)
+
+	xor	R32(%rbx), R32(%rbx)
+	mov	8(rp,n,8), %r8
+	mov	16(rp,n,8), %r9
+	jmp	L(dm)
+
+	ALIGN(32)
+L(dtop):add	%r8, %r10
+	adc	%r9, %rax
+	mov	8(rp,n,8), %r8
+	mov	16(rp,n,8), %r9
+	mov	%r10, -8(rp,n,8)
+	mov	%rax, (rp,n,8)
+L(dm):	adc	%r8, %r8
+	adc	%r9, %r9
+	mov	(up,n,4), %rax
+	lea	(%rdx,%rbx), %r10
+	setc	R8(%rbx)
+	mul	%rax
+	add	$2, n
+	js	L(dtop)
+
+L(dend):add	%r8, %r10
+	adc	%r9, %rax
+	mov	%r10, I(-8(rp),-8(rp,n,8))
+	mov	%rax, I((rp),(rp,n,8))
+	adc	%rbx, %rdx
+	mov	%rdx, I(8(rp),8(rp,n,8))
+
+	pop	%r14
+	pop	%r13
+	pop	%r12
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/darwin.m4 b/third_party/gmp/mpn/x86_64/darwin.m4
new file mode 100644
index 0000000..7771476
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/darwin.m4
@@ -0,0 +1,82 @@
+divert(-1)
+dnl  Copyright 2008, 2011, 2012 Free Software Foundation, Inc.
+dnl
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+define(`DARWIN')
+
+define(`LEA',`dnl
+ifdef(`PIC',
+	`lea	$1(%rip), $2'
+,
+	`movabs	`$'$1, $2')
+')
+
+dnl  Usage: CALL(funcname)
+dnl
+dnl  Simply override the definition in x86_64-defs.m4.
+
+define(`CALL',`call	GSYM_PREFIX`'$1')
+define(`TCALL',`jmp	GSYM_PREFIX`'$1')
+
+
+dnl  Usage: JUMPTABSECT
+dnl
+dnl  CAUTION: Do not put anything sensible here, like RODATA.  That works with
+dnl  some Darwin tool chains, but silently breaks with other.  (Note that
+dnl  putting jump tables in the text segment is a really poor idea for many PC
+dnl  processors, since they cannot cache the same thing in both L1D and L2I.)
+
+define(`JUMPTABSECT', `.text')
+
+
+dnl  Usage: JMPENT(targlabel,tablabel)
+
+define(`JMPENT',`dnl
+ifdef(`PIC',
+	`.set	$1_tmp, $1-$2
+	.long	$1_tmp'
+,
+	`.quad	$1'
+)')
+
+dnl  Target ABI macros.  For Darwin we override IFELF (and leave default for
+dnl  IFDOS and IFSTD).
+
+define(`IFELF',   `')
+
+
+dnl  Usage: PROTECT(symbol)
+dnl
+dnl  Used for private GMP symbols that should never be overridden by users.
+dnl  This can save reloc entries and improve shlib sharing as well as
+dnl  application startup times
+
+define(`PROTECT',  `.private_extern $1')
+
+
+divert`'dnl
diff --git a/third_party/gmp/mpn/x86_64/div_qr_1n_pi1.asm b/third_party/gmp/mpn/x86_64/div_qr_1n_pi1.asm
new file mode 100644
index 0000000..b3d45e2
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/div_qr_1n_pi1.asm
@@ -0,0 +1,247 @@
+dnl  x86-64 mpn_div_qr_1n_pi1
+dnl  -- Divide an mpn number by a normalized single-limb number,
+dnl     using a single-limb inverse.
+
+dnl  Contributed to the GNU project by Niels Möller
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C		c/l
+C AMD K8,K9	13
+C AMD K10	13
+C AMD bull	16.5
+C AMD pile	15
+C AMD steam	 ?
+C AMD bobcat	16
+C AMD jaguar	 ?
+C Intel P4	47	poor
+C Intel core	19.25
+C Intel NHM	18
+C Intel SBR	15	poor
+C Intel IBR	13
+C Intel HWL	11.7
+C Intel BWL	 ?
+C Intel atom	52	very poor
+C VIA nano	19
+
+
+C INPUT Parameters
+define(`QP', `%rdi')
+define(`UP', `%rsi')
+define(`UN_INPUT', `%rdx')
+define(`U1', `%rcx')	C Also in %rax
+define(`D', `%r8')
+define(`DINV', `%r9')
+
+C Invariants
+define(`B2', `%rbp')
+define(`B2md', `%rbx')
+
+C Variables
+define(`UN', `%r8')	C Overlaps D input
+define(`T', `%r10')
+define(`U0', `%r11')
+define(`U2', `%r12')
+define(`Q0', `%r13')
+define(`Q1', `%r14')
+define(`Q2', `%r15')
+
+ABI_SUPPORT(STD64)
+
+	ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_div_qr_1n_pi1)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8	')
+IFDOS(`	mov	64(%rsp), %r9	')
+	dec	UN_INPUT
+	jnz	L(first)
+
+	C Just a single 2/1 division.
+	C T, U0 are allocated in scratch registers
+	lea	1(U1), T
+	mov	U1, %rax
+	mul	DINV
+	mov	(UP), U0
+	add	U0, %rax
+	adc	T, %rdx
+	mov	%rdx, T
+	imul	D, %rdx
+	sub	%rdx, U0
+	cmp	U0, %rax
+	lea	(U0, D), %rax
+	cmovnc	U0, %rax
+	sbb	$0, T
+	cmp	D, %rax
+	jc	L(single_div_done)
+	sub	D, %rax
+	add	$1, T
+L(single_div_done):
+	mov	T, (QP)
+	FUNC_EXIT()
+	ret
+L(first):
+	C FIXME: Could delay some of these until we enter the loop.
+	push	%r15
+	push	%r14
+	push	%r13
+	push	%r12
+	push	%rbx
+	push	%rbp
+
+	mov	D, B2
+	imul	DINV, B2
+	neg	B2
+	mov	B2, B2md
+	sub	D, B2md
+
+	C D not needed until final reduction
+	push	D
+	mov	UN_INPUT, UN	C Clobbers D
+
+	mov	DINV, %rax
+	mul	U1
+	mov	%rax, Q0
+	add	U1, %rdx
+	mov	%rdx, T
+
+	mov	B2, %rax
+	mul	U1
+	mov	-8(UP, UN, 8), U0
+	mov	(UP, UN, 8), U1
+	mov	T, (QP, UN, 8)
+	add	%rax, U0
+	adc	%rdx, U1
+	sbb	U2, U2
+	dec	UN
+	mov	U1, %rax
+	jz	L(final)
+
+	ALIGN(16)
+
+	C Loop is 28 instructions, 30 decoder slots, should run in 10 cycles.
+	C At entry, %rax holds an extra copy of U1
+L(loop):
+	C {Q2, Q1, Q0} <-- DINV * U1 + B (Q0 + U2 DINV) + B^2 U2
+	C Remains to add in B (U1 + c)
+	mov	DINV, Q1
+	mov	U2, Q2
+	and	U2, Q1
+	neg	Q2
+	mul	DINV
+	add	%rdx, Q1
+	adc	$0, Q2
+	add	Q0, Q1
+	mov	%rax, Q0
+	mov	B2, %rax
+	lea	(B2md, U0), T
+	adc	$0, Q2
+
+	C {U2, U1, U0} <-- (U0 + U2 B2 -c U) B + U1 B2 + u
+	mul	U1
+	and	B2, U2
+	add	U2, U0
+	cmovnc	U0, T
+
+	C {QP+UN, ...} <-- {QP+UN, ...} + {Q2, Q1} + U1 + c
+	adc	U1, Q1
+	mov	-8(UP, UN, 8), U0
+	adc	Q2, 8(QP, UN, 8)
+	jc	L(q_incr)
+L(q_incr_done):
+	add	%rax, U0
+	mov	T, %rax
+	adc	%rdx, %rax
+	mov	Q1, (QP, UN, 8)
+	sbb	U2, U2
+	dec	UN
+	mov	%rax, U1
+	jnz	L(loop)
+
+L(final):
+	pop	D
+
+	mov	U2, Q1
+	and	D, U2
+	sub	U2, %rax
+	neg	Q1
+
+	mov	%rax, U1
+	sub	D, %rax
+	cmovc	U1, %rax
+	sbb	$-1, Q1
+
+	lea	1(%rax), T
+	mul	DINV
+	add	U0, %rax
+	adc	T, %rdx
+	mov	%rdx, T
+	imul	D, %rdx
+	sub	%rdx, U0
+	cmp	U0, %rax
+	lea	(U0, D), %rax
+	cmovnc	U0, %rax
+	sbb	$0, T
+	cmp	D, %rax
+	jc	L(div_done)
+	sub	D, %rax
+	add	$1, T
+L(div_done):
+	add	T, Q0
+	mov	Q0, (QP)
+	adc	Q1, 8(QP)
+	jnc	L(done)
+L(final_q_incr):
+	addq	$1, 16(QP)
+	lea	8(QP), QP
+	jc	L(final_q_incr)
+
+L(done):
+	pop	%rbp
+	pop	%rbx
+	pop	%r12
+	pop	%r13
+	pop	%r14
+	pop	%r15
+	FUNC_EXIT()
+	ret
+
+L(q_incr):
+	C U1 is not live, so use it for indexing
+	lea	16(QP, UN, 8), U1
+L(q_incr_loop):
+	addq	$1, (U1)
+	jnc	L(q_incr_done)
+	lea	8(U1), U1
+	jmp	L(q_incr_loop)
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/div_qr_2n_pi1.asm b/third_party/gmp/mpn/x86_64/div_qr_2n_pi1.asm
new file mode 100644
index 0000000..5e59a0a
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/div_qr_2n_pi1.asm
@@ -0,0 +1,158 @@
+dnl  x86-64 mpn_div_qr_2n_pi1
+dnl  -- Divide an mpn number by a normalized 2-limb number,
+dnl     using a single-limb inverse.
+
+dnl  Copyright 2007, 2008, 2010-2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C		c/l
+C INPUT PARAMETERS
+define(`qp',		`%rdi')
+define(`rp',		`%rsi')
+define(`up_param',	`%rdx')
+define(`un',		`%rcx')
+define(`d1',		`%r8')
+define(`d0',		`%r9')
+define(`di_param',	`8(%rsp)')
+
+define(`di',		`%r10')
+define(`up',		`%r11')
+define(`u2',		`%rbx')
+define(`u1',		`%r12')
+define(`t1',		`%r13')
+define(`t0',		`%r14')
+define(`md1',		`%r15')
+
+C TODO
+C * Store qh in the same stack slot as di_param, instead of pushing
+C   it. (we could put it in register %rbp, but then we would need to
+C   save and restore that instead, which doesn't seem like a win).
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_div_qr_2n_pi1)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8	')
+IFDOS(`	mov	64(%rsp), %r9	')
+IFDOS(`define(`di_param', `72(%rsp)')')
+	mov	di_param, di
+	mov	up_param, up
+	push	%r15
+	push	%r14
+	push	%r13
+	push	%r12
+	push	%rbx
+
+	mov	-16(up, un, 8), u1
+	mov	-8(up, un, 8), u2
+
+	mov	u1, t0
+	mov	u2, t1
+	sub	d0, t0
+	sbb	d1, t1
+	cmovnc  t0, u1
+	cmovnc	t1, u2
+	C push qh which is !carry
+	sbb	%rax, %rax
+	inc	%rax
+	push	%rax
+	lea	-2(un), un
+	mov	d1, md1
+	neg	md1
+
+	jmp	L(next)
+
+	ALIGN(16)
+L(loop):
+	C udiv_qr_3by2 (q,u2,u1,u2,u1,n0, d1,d0,di)
+	C Based on the optimized divrem_2.asm code.
+
+	mov	di, %rax
+	mul	u2
+	mov	u1, t0
+	add	%rax, t0	C q0 in t0
+	adc	u2, %rdx
+	mov	%rdx, t1	C q in t1
+	imul	md1, %rdx
+	mov	d0, %rax
+	lea	(%rdx, u1), u2
+	mul	t1
+	mov	(up, un, 8), u1
+	sub	d0, u1
+	sbb	d1, u2
+	sub	%rax, u1
+	sbb	%rdx, u2
+	xor	R32(%rax), R32(%rax)
+	xor	R32(%rdx), R32(%rdx)
+	cmp	t0, u2
+	cmovnc	d0, %rax
+	cmovnc	d1, %rdx
+	adc	$0, t1
+	nop
+	add	%rax, u1
+	adc	%rdx, u2
+	cmp	d1, u2
+	jae	L(fix)
+L(bck):
+	mov	t1, (qp, un, 8)
+L(next):
+	sub	$1, un
+	jnc	L(loop)
+L(end):
+	mov	u2, 8(rp)
+	mov	u1, (rp)
+
+	C qh on stack
+	pop	%rax
+
+	pop	%rbx
+	pop	%r12
+	pop	%r13
+	pop	%r14
+	pop	%r15
+	FUNC_EXIT()
+	ret
+
+L(fix):	C Unlikely update. u2 >= d1
+	seta	%dl
+	cmp	d0, u1
+	setae	%al
+	orb	%dl, %al		C "orb" form to placate Sun tools
+	je	L(bck)
+	inc	t1
+	sub	d0, u1
+	sbb	d1, u2
+	jmp	L(bck)
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/div_qr_2u_pi1.asm b/third_party/gmp/mpn/x86_64/div_qr_2u_pi1.asm
new file mode 100644
index 0000000..85af96f
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/div_qr_2u_pi1.asm
@@ -0,0 +1,200 @@
+dnl  x86-64 mpn_div_qr_2u_pi1
+dnl  -- Divide an mpn number by an unnormalized 2-limb number,
+dnl     using a single-limb inverse and shifting the dividend on the fly.
+
+dnl  Copyright 2007, 2008, 2010, 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C		c/l
+C INPUT PARAMETERS
+define(`qp',		`%rdi')
+define(`rp',		`%rsi')
+define(`up_param',	`%rdx')
+define(`un_param',	`%rcx') dnl %rcx needed for shift count
+define(`d1',		`%r8')
+define(`d0',		`%r9')
+define(`shift_param',	`FRAME+8(%rsp)')
+define(`di_param',	`FRAME+16(%rsp)')
+
+define(`di',		`%r10')
+define(`up',		`%r11')
+define(`un',		`%rbp')
+define(`u2',		`%rbx')
+define(`u1',		`%r12')
+define(`u0',		`%rsi') dnl Same as rp, which is saved and restored.
+define(`t1',		`%r13')
+define(`t0',		`%r14')
+define(`md1',		`%r15')
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+deflit(`FRAME', 0)
+PROLOGUE(mpn_div_qr_2u_pi1)
+	mov	di_param, di
+	mov	up_param, up
+	push	%r15
+	push	%r14
+	push	%r13
+	push	%r12
+	push	%rbx
+	push	%rbp
+	push	rp
+deflit(`FRAME', 56)
+	lea	-2(un_param), un
+	mov	d1, md1
+	neg	md1
+
+	C int parameter, 32 bits only
+	movl	shift_param, R32(%rcx)
+
+	C FIXME: Different code for SHLD_SLOW
+
+	xor	R32(u2), R32(u2)
+	mov	8(up, un, 8), u1
+	shld	%cl, u1, u2
+	C Remains to read (up, un, 8) and shift u1, u0
+	C udiv_qr_3by2 (qh,u2,u1,u2,u1,n0, d1,d0,di)
+	mov	di, %rax
+	mul	u2
+	mov	(up, un, 8), u0
+	shld	%cl, u0, u1
+	mov	u1, t0
+	add	%rax, t0	C q0 in t0
+	adc	u2, %rdx
+	mov	%rdx, t1	C q in t1
+	imul	md1, %rdx
+	mov	d0, %rax
+	lea	(%rdx, u1), u2
+	mul	t1
+	mov	u0, u1
+	shl	%cl, u1
+	sub	d0, u1
+	sbb	d1, u2
+	sub	%rax, u1
+	sbb	%rdx, u2
+	xor	R32(%rax), R32(%rax)
+	xor	R32(%rdx), R32(%rdx)
+	cmp	t0, u2
+	cmovnc	d0, %rax
+	cmovnc	d1, %rdx
+	adc	$0, t1
+	nop
+	add	%rax, u1
+	adc	%rdx, u2
+	cmp	d1, u2
+	jae	L(fix_qh)
+L(bck_qh):
+	push	t1	C push qh on stack
+
+	jmp	L(next)
+
+	ALIGN(16)
+L(loop):
+	C udiv_qr_3by2 (q,u2,u1,u2,u1,n0, d1,d0,di)
+	C Based on the optimized divrem_2.asm code.
+
+	mov	di, %rax
+	mul	u2
+	mov	(up, un, 8), u0
+	xor	R32(t1), R32(t1)
+	shld	%cl, u0, t1
+	or	t1, u1
+	mov	u1, t0
+	add	%rax, t0	C q0 in t0
+	adc	u2, %rdx
+	mov	%rdx, t1	C q in t1
+	imul	md1, %rdx
+	mov	d0, %rax
+	lea	(%rdx, u1), u2
+	mul	t1
+	mov	u0, u1
+	shl	%cl, u1
+	sub	d0, u1
+	sbb	d1, u2
+	sub	%rax, u1
+	sbb	%rdx, u2
+	xor	R32(%rax), R32(%rax)
+	xor	R32(%rdx), R32(%rdx)
+	cmp	t0, u2
+	cmovnc	d0, %rax
+	cmovnc	d1, %rdx
+	adc	$0, t1
+	nop
+	add	%rax, u1
+	adc	%rdx, u2
+	cmp	d1, u2
+	jae	L(fix)
+L(bck):
+	mov	t1, (qp, un, 8)
+L(next):
+	sub	$1, un
+	jnc	L(loop)
+L(end):
+	C qh on stack
+	pop	%rax
+	pop	rp
+	shrd	%cl, u2, u1
+	shr	%cl, u2
+	mov	u2, 8(rp)
+	mov	u1, (rp)
+
+	pop	%rbp
+	pop	%rbx
+	pop	%r12
+	pop	%r13
+	pop	%r14
+	pop	%r15
+	ret
+
+L(fix):	C Unlikely update. u2 >= d1
+	seta	%dl
+	cmp	d0, u1
+	setae	%al
+	orb	%dl, %al		C "orb" form to placate Sun tools
+	je	L(bck)
+	inc	t1
+	sub	d0, u1
+	sbb	d1, u2
+	jmp	L(bck)
+
+C Duplicated, just jumping back to a different address.
+L(fix_qh):	C Unlikely update. u2 >= d1
+	seta	%dl
+	cmp	d0, u1
+	setae	%al
+	orb	%dl, %al		C "orb" form to placate Sun tools
+	je	L(bck_qh)
+	inc	t1
+	sub	d0, u1
+	sbb	d1, u2
+	jmp	L(bck_qh)
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/dive_1.asm b/third_party/gmp/mpn/x86_64/dive_1.asm
new file mode 100644
index 0000000..988bdab
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/dive_1.asm
@@ -0,0 +1,158 @@
+dnl  AMD64 mpn_divexact_1 -- mpn by limb exact division.
+
+dnl  Copyright 2001, 2002, 2004-2006, 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C	     cycles/limb
+C AMD K8,K9	10
+C AMD K10	10
+C Intel P4	33
+C Intel core2	13.25
+C Intel corei	14
+C Intel atom	42
+C VIA nano	43
+
+C A quick adoption of the 32-bit K7 code.
+
+
+C INPUT PARAMETERS
+C rp		rdi
+C up		rsi
+C n		rdx
+C divisor	rcx
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_divexact_1)
+	FUNC_ENTRY(4)
+	push	%rbx
+
+	mov	%rcx, %rax
+	xor	R32(%rcx), R32(%rcx)	C shift count
+	mov	%rdx, %r8
+
+	bt	$0, R32(%rax)
+	jnc	L(evn)			C skip bsfq unless divisor is even
+
+L(odd):	mov	%rax, %rbx
+	shr	R32(%rax)
+	and	$127, R32(%rax)		C d/2, 7 bits
+
+	LEA(	binvert_limb_table, %rdx)
+
+	movzbl	(%rdx,%rax), R32(%rax)	C inv 8 bits
+
+	mov	%rbx, %r11		C d without twos
+
+	lea	(%rax,%rax), R32(%rdx)	C 2*inv
+	imul	R32(%rax), R32(%rax)	C inv*inv
+	imul	R32(%rbx), R32(%rax)	C inv*inv*d
+	sub	R32(%rax), R32(%rdx)	C inv = 2*inv - inv*inv*d, 16 bits
+
+	lea	(%rdx,%rdx), R32(%rax)	C 2*inv
+	imul	R32(%rdx), R32(%rdx)	C inv*inv
+	imul	R32(%rbx), R32(%rdx)	C inv*inv*d
+	sub	R32(%rdx), R32(%rax)	C inv = 2*inv - inv*inv*d, 32 bits
+
+	lea	(%rax,%rax), %r10	C 2*inv
+	imul	%rax, %rax		C inv*inv
+	imul	%rbx, %rax		C inv*inv*d
+	sub	%rax, %r10		C inv = 2*inv - inv*inv*d, 64 bits
+
+	lea	(%rsi,%r8,8), %rsi	C up end
+	lea	-8(%rdi,%r8,8), %rdi	C rp end
+	neg	%r8			C -n
+
+	mov	(%rsi,%r8,8), %rax	C up[0]
+
+	inc	%r8
+	jz	L(one)
+
+	mov	(%rsi,%r8,8), %rdx	C up[1]
+
+	shrd	R8(%rcx), %rdx, %rax
+
+	xor	R32(%rbx), R32(%rbx)
+	jmp	L(ent)
+
+L(evn):	bsf	%rax, %rcx
+	shr	R8(%rcx), %rax
+	jmp	L(odd)
+
+	ALIGN(8)
+L(top):
+	C rax	q
+	C rbx	carry bit, 0 or 1
+	C rcx	shift
+	C rdx
+	C rsi	up end
+	C rdi	rp end
+	C r8	counter, limbs, negative
+	C r10	d^(-1) mod 2^64
+	C r11	d, shifted down
+
+	mul	%r11			C carry limb in rdx	0 10
+	mov	-8(%rsi,%r8,8), %rax	C
+	mov	(%rsi,%r8,8), %r9	C
+	shrd	R8(%rcx), %r9, %rax	C
+	nop				C
+	sub	%rbx, %rax		C apply carry bit
+	setc	%bl			C
+	sub	%rdx, %rax		C apply carry limb	5
+	adc	$0, %rbx		C			6
+L(ent):	imul	%r10, %rax		C			6
+	mov	%rax, (%rdi,%r8,8)	C
+	inc	%r8			C
+	jnz	L(top)
+
+	mul	%r11			C carry limb in rdx
+	mov	-8(%rsi), %rax		C up high limb
+	shr	R8(%rcx), %rax
+	sub	%rbx, %rax		C apply carry bit
+	sub	%rdx, %rax		C apply carry limb
+	imul	%r10, %rax
+	mov	%rax, (%rdi)
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+
+L(one):	shr	R8(%rcx), %rax
+	imul	%r10, %rax
+	mov	%rax, (%rdi)
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/divrem_1.asm b/third_party/gmp/mpn/x86_64/divrem_1.asm
new file mode 100644
index 0000000..d4d61ad
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/divrem_1.asm
@@ -0,0 +1,314 @@
+dnl  x86-64 mpn_divrem_1 -- mpn by limb division.
+
+dnl  Copyright 2004, 2005, 2007-2012, 2014 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C		norm	unorm	frac
+C AMD K8,K9	13	13	12
+C AMD K10	13	13	12
+C Intel P4	43	44	43
+C Intel core2	24.5	24.5	19.5
+C Intel corei	20.5	19.5	18
+C Intel atom	43	46	36
+C VIA nano	25.5	25.5	24
+
+C mp_limb_t
+C mpn_divrem_1 (mp_ptr qp, mp_size_t fn,
+C               mp_srcptr np, mp_size_t nn, mp_limb_t d)
+
+C mp_limb_t
+C mpn_preinv_divrem_1 (mp_ptr qp, mp_size_t fn,
+C                      mp_srcptr np, mp_size_t nn, mp_limb_t d,
+C                      mp_limb_t dinv, int cnt)
+
+C INPUT PARAMETERS
+define(`qp',		`%rdi')
+define(`fn_param',	`%rsi')
+define(`up_param',	`%rdx')
+define(`un_param',	`%rcx')
+define(`d',		`%r8')
+define(`dinv',		`%r9')		C only for mpn_preinv_divrem_1
+C       shift passed on stack		C only for mpn_preinv_divrem_1
+
+define(`cnt',		`%rcx')
+define(`up',		`%rsi')
+define(`fn',		`%r12')
+define(`un',		`%rbx')
+
+
+C rax rbx rcx rdx rsi rdi rbp r8  r9  r10 r11 r12 r13 r14 r15
+C         cnt         qp      d  dinv
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+IFSTD(`define(`CNTOFF',		`40($1)')')
+IFDOS(`define(`CNTOFF',		`104($1)')')
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_preinv_divrem_1)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8	')
+IFDOS(`	mov	64(%rsp), %r9	')
+	xor	R32(%rax), R32(%rax)
+	push	%r13
+	push	%r12
+	push	%rbp
+	push	%rbx
+
+	mov	fn_param, fn
+	mov	un_param, un
+	add	fn_param, un_param
+	mov	up_param, up
+
+	lea	-8(qp,un_param,8), qp
+
+	test	d, d
+	js	L(nent)
+
+	mov	CNTOFF(%rsp), R8(cnt)
+	shl	R8(cnt), d
+	jmp	L(uent)
+EPILOGUE()
+
+	ALIGN(16)
+PROLOGUE(mpn_divrem_1)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8	')
+	xor	R32(%rax), R32(%rax)
+	push	%r13
+	push	%r12
+	push	%rbp
+	push	%rbx
+
+	mov	fn_param, fn
+	mov	un_param, un
+	add	fn_param, un_param
+	mov	up_param, up
+	je	L(ret)
+
+	lea	-8(qp,un_param,8), qp
+	xor	R32(%rbp), R32(%rbp)
+
+	test	d, d
+	jns	L(unnormalized)
+
+L(normalized):
+	test	un, un
+	je	L(8)			C un == 0
+	mov	-8(up,un,8), %rbp
+	dec	un
+	mov	%rbp, %rax
+	sub	d, %rbp
+	cmovc	%rax, %rbp
+	sbb	R32(%rax), R32(%rax)
+	inc	R32(%rax)
+	mov	%rax, (qp)
+	lea	-8(qp), qp
+L(8):
+IFSTD(`	push	%rdi		')
+IFSTD(`	push	%rsi		')
+	push	%r8
+IFSTD(`	mov	d, %rdi		')
+IFDOS(`	sub	$32, %rsp	')
+IFDOS(`	mov	d, %rcx		')
+	ASSERT(nz, `test $15, %rsp')
+	CALL(	mpn_invert_limb)
+IFDOS(`	add	$32, %rsp	')
+	pop	%r8
+IFSTD(`	pop	%rsi		')
+IFSTD(`	pop	%rdi		')
+
+	mov	%rax, dinv
+	mov	%rbp, %rax
+	jmp	L(nent)
+
+	ALIGN(16)
+L(ntop):mov	(up,un,8), %r10		C	    K8-K10  P6-CNR P6-NHM  P4
+	mul	dinv			C	      0,13   0,20   0,18   0,45
+	add	%r10, %rax		C	      4      8      3     12
+	adc	%rbp, %rdx		C	      5      9     10     13
+	mov	%rax, %rbp		C	      5      9      4     13
+	mov	%rdx, %r13		C	      6     11     12     23
+	imul	d, %rdx			C	      6     11     11     23
+	sub	%rdx, %r10		C	     10     16     14     33
+	mov	d, %rax			C
+	add	%r10, %rax		C	     11     17     15     34
+	cmp	%rbp, %r10		C	     11     17     15     34
+	cmovc	%r10, %rax		C	     12     18     16     35
+	adc	$-1, %r13		C
+	cmp	d, %rax			C
+	jae	L(nfx)			C
+L(nok):	mov	%r13, (qp)		C
+	sub	$8, qp			C
+L(nent):lea	1(%rax), %rbp		C
+	dec	un			C
+	jns	L(ntop)			C
+
+	xor	R32(%rcx), R32(%rcx)
+	jmp	L(frac)
+
+L(nfx):	sub	d, %rax
+	inc	%r13
+	jmp	L(nok)
+
+L(unnormalized):
+	test	un, un
+	je	L(44)
+	mov	-8(up,un,8), %rax
+	cmp	d, %rax
+	jae	L(44)
+	mov	%rbp, (qp)
+	mov	%rax, %rbp
+	lea	-8(qp), qp
+	je	L(ret)
+	dec	un
+L(44):
+	bsr	d, %rcx
+	not	R32(%rcx)
+	shl	R8(%rcx), d
+	shl	R8(%rcx), %rbp
+
+	push	%rcx
+IFSTD(`	push	%rdi		')
+IFSTD(`	push	%rsi		')
+	push	%r8
+IFSTD(`	sub	$8, %rsp	')
+IFSTD(`	mov	d, %rdi		')
+IFDOS(`	sub	$40, %rsp	')
+IFDOS(`	mov	d, %rcx		')
+	ASSERT(nz, `test $15, %rsp')
+	CALL(	mpn_invert_limb)
+IFSTD(`	add	$8, %rsp	')
+IFDOS(`	add	$40, %rsp	')
+	pop	%r8
+IFSTD(`	pop	%rsi		')
+IFSTD(`	pop	%rdi		')
+	pop	%rcx
+
+	mov	%rax, dinv
+	mov	%rbp, %rax
+	test	un, un
+	je	L(frac)
+
+L(uent):dec	un
+	mov	(up,un,8), %rbp
+	neg	R32(%rcx)
+	shr	R8(%rcx), %rbp
+	neg	R32(%rcx)
+	or	%rbp, %rax
+	jmp	L(ent)
+
+	ALIGN(16)
+L(utop):mov	(up,un,8), %r10
+	shl	R8(%rcx), %rbp
+	neg	R32(%rcx)
+	shr	R8(%rcx), %r10
+	neg	R32(%rcx)
+	or	%r10, %rbp
+	mul	dinv
+	add	%rbp, %rax
+	adc	%r11, %rdx
+	mov	%rax, %r11
+	mov	%rdx, %r13
+	imul	d, %rdx
+	sub	%rdx, %rbp
+	mov	d, %rax
+	add	%rbp, %rax
+	cmp	%r11, %rbp
+	cmovc	%rbp, %rax
+	adc	$-1, %r13
+	cmp	d, %rax
+	jae	L(ufx)
+L(uok):	mov	%r13, (qp)
+	sub	$8, qp
+L(ent):	mov	(up,un,8), %rbp
+	dec	un
+	lea	1(%rax), %r11
+	jns	L(utop)
+
+L(uend):shl	R8(%rcx), %rbp
+	mul	dinv
+	add	%rbp, %rax
+	adc	%r11, %rdx
+	mov	%rax, %r11
+	mov	%rdx, %r13
+	imul	d, %rdx
+	sub	%rdx, %rbp
+	mov	d, %rax
+	add	%rbp, %rax
+	cmp	%r11, %rbp
+	cmovc	%rbp, %rax
+	adc	$-1, %r13
+	cmp	d, %rax
+	jae	L(efx)
+L(eok):	mov	%r13, (qp)
+	sub	$8, qp
+	jmp	L(frac)
+
+L(ufx):	sub	d, %rax
+	inc	%r13
+	jmp	L(uok)
+L(efx):	sub	d, %rax
+	inc	%r13
+	jmp	L(eok)
+
+L(frac):mov	d, %rbp
+	neg	%rbp
+	jmp	L(fent)
+
+	ALIGN(16)			C	    K8-K10  P6-CNR P6-NHM  P4
+L(ftop):mul	dinv			C	      0,12   0,17   0,17
+	add	%r11, %rdx		C	      5      8     10
+	mov	%rax, %r11		C	      4      8      3
+	mov	%rdx, %r13		C	      6      9     11
+	imul	%rbp, %rdx		C	      6      9     11
+	mov	d, %rax			C
+	add	%rdx, %rax		C	     10     14     14
+	cmp	%r11, %rdx		C	     10     14     14
+	cmovc	%rdx, %rax		C	     11     15     15
+	adc	$-1, %r13		C
+	mov	%r13, (qp)		C
+	sub	$8, qp			C
+L(fent):lea	1(%rax), %r11		C
+	dec	fn			C
+	jns	L(ftop)			C
+
+	shr	R8(%rcx), %rax
+L(ret):	pop	%rbx
+	pop	%rbp
+	pop	%r12
+	pop	%r13
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/divrem_2.asm b/third_party/gmp/mpn/x86_64/divrem_2.asm
new file mode 100644
index 0000000..20811cc
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/divrem_2.asm
@@ -0,0 +1,192 @@
+dnl  x86-64 mpn_divrem_2 -- Divide an mpn number by a normalized 2-limb number.
+
+dnl  Copyright 2007, 2008, 2010, 2014 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C	     cycles/limb	best
+C AMD K8,K9	18
+C AMD K10	18
+C AMD bull
+C AMD pile
+C AMD bobcat
+C AMD jaguar
+C Intel P4	68
+C Intel core	34
+C Intel NHM	30.25
+C Intel SBR	21.3
+C Intel IBR	21.4
+C Intel HWL	20.6
+C Intel BWL
+C Intel atom	73
+C VIA nano	33
+
+
+C INPUT PARAMETERS
+define(`qp',		`%rdi')
+define(`fn',		`%rsi')
+define(`up_param',	`%rdx')
+define(`un_param',	`%rcx')
+define(`dp',		`%r8')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_divrem_2)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8	')
+	push	%r15
+	push	%r14
+	push	%r13
+	push	%r12
+	lea	-24(%rdx,%rcx,8), %r12	C r12 = &up[un-1]
+	mov	%rsi, %r13
+	push	%rbp
+	mov	%rdi, %rbp
+	push	%rbx
+	mov	8(%r8), %r11		C d1
+	mov	16(%r12), %rbx
+	mov	(%r8), %r8		C d0
+	mov	8(%r12), %r10
+
+	xor	R32(%r15), R32(%r15)
+	cmp	%rbx, %r11
+	ja	L(2)
+	setb	%dl
+	cmp	%r10, %r8
+	setbe	%al
+	orb	%al, %dl		C "orb" form to placate Sun tools
+	je	L(2)
+	inc	R32(%r15)
+	sub	%r8, %r10
+	sbb	%r11, %rbx
+L(2):
+	lea	-3(%rcx,%r13), %r14	C un + fn - 3
+	test	%r14, %r14
+	js	L(end)
+
+	push	%r8
+	push	%r10
+	push	%r11
+IFSTD(`	mov	%r11, %rdi	')
+IFDOS(`	mov	%r11, %rcx	')
+IFDOS(`	sub	$32, %rsp	')
+	ASSERT(nz, `test $15, %rsp')
+	CALL(	mpn_invert_limb)
+IFDOS(`	add	$32, %rsp	')
+	pop	%r11
+	pop	%r10
+	pop	%r8
+
+	mov	%r11, %rdx
+	mov	%rax, %rdi
+	imul	%rax, %rdx
+	mov	%rdx, %r9
+	mul	%r8
+	xor	R32(%rcx), R32(%rcx)
+	add	%r8, %r9
+	adc	$-1, %rcx
+	add	%rdx, %r9
+	adc	$0, %rcx
+	js	2f
+1:	dec	%rdi
+	sub	%r11, %r9
+	sbb	$0, %rcx
+	jns	1b
+2:
+
+	lea	(%rbp,%r14,8), %rbp
+	mov	%r11, %rsi
+	neg	%rsi			C -d1
+
+C rax rbx rcx rdx rsi rdi  rbp r8 r9 r10 r11 r12 r13 r14 r15
+C     n2  un      -d1 dinv qp  d0 q0     d1  up  fn      msl
+
+	ALIGN(16)
+L(top):	mov	%rdi, %rax		C di		ncp
+	mul	%rbx			C		0, 17
+	mov	%r10, %rcx		C
+	add	%rax, %rcx		C		4
+	adc	%rbx, %rdx		C		5
+	mov	%rdx, %r9		C q		6
+	imul	%rsi, %rdx		C		6
+	mov	%r8, %rax		C		ncp
+	lea	(%rdx, %r10), %rbx	C n1 -= ...	10
+	xor	R32(%r10), R32(%r10)	C
+	mul	%r9			C		7
+	cmp	%r14, %r13		C
+	jg	L(19)			C
+	mov	(%r12), %r10		C
+	sub	$8, %r12		C
+L(19):	sub	%r8, %r10		C		ncp
+	sbb	%r11, %rbx		C		11
+	sub	%rax, %r10		C		11
+	sbb	%rdx, %rbx		C		12
+	xor	R32(%rax), R32(%rax)	C
+	xor	R32(%rdx), R32(%rdx)	C
+	cmp	%rcx, %rbx		C		13
+	cmovnc	%r8, %rax		C		14
+	cmovnc	%r11, %rdx		C		14
+	adc	$0, %r9			C adjust q	14
+	nop
+	add	%rax, %r10		C		15
+	adc	%rdx, %rbx		C		16
+	cmp	%r11, %rbx		C
+	jae	L(fix)			C
+L(bck):	mov	%r9, (%rbp)		C
+	sub	$8, %rbp		C
+	dec	%r14
+	jns	L(top)
+
+L(end):	mov	%r10, 8(%r12)
+	mov	%rbx, 16(%r12)
+	pop	%rbx
+	pop	%rbp
+	pop	%r12
+	pop	%r13
+	pop	%r14
+	mov	%r15, %rax
+	pop	%r15
+	FUNC_EXIT()
+	ret
+
+L(fix):	seta	%dl
+	cmp	%r8, %r10
+	setae	%al
+	orb	%dl, %al		C "orb" form to placate Sun tools
+	je	L(bck)
+	inc	%r9
+	sub	%r8, %r10
+	sbb	%r11, %rbx
+	jmp	L(bck)
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/dos64.m4 b/third_party/gmp/mpn/x86_64/dos64.m4
new file mode 100644
index 0000000..0da1b36
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/dos64.m4
@@ -0,0 +1,101 @@
+divert(-1)
+dnl  Copyright 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+define(`HOST_DOS64')
+
+
+dnl  On DOS64 we always generate position-independent-code
+dnl
+
+define(`PIC')
+
+
+define(`LEA',`
+	lea	$1(%rip), $2
+')
+
+
+dnl  Usage: CALL(funcname)
+dnl
+dnl  Simply override the definition in x86_64-defs.m4.
+
+define(`CALL',`call	GSYM_PREFIX`'$1')
+define(`TCALL',`jmp	GSYM_PREFIX`'$1')
+
+
+dnl  Usage: JUMPTABSECT
+
+define(`JUMPTABSECT', `RODATA')
+
+
+dnl  Usage: JMPENT(targlabel,tablabel)
+
+define(`JMPENT', `.long	$1-$2')
+
+
+dnl  Usage: FUNC_ENTRY(nregparmas)
+dnl  Usage: FUNC_EXIT()
+
+dnl  FUNC_ENTRY and FUNC_EXIT provide an easy path for adoption of standard
+dnl  ABI assembly to the DOS64 ABI.
+
+define(`FUNC_ENTRY',
+	`push	%rdi
+	push	%rsi
+	mov	%rcx, %rdi
+ifelse(eval($1>=2),1,`dnl
+	mov	%rdx, %rsi
+ifelse(eval($1>=3),1,`dnl
+	mov	%r8, %rdx
+ifelse(eval($1>=4),1,`dnl
+	mov	%r9, %rcx
+')')')')
+
+define(`FUNC_EXIT',
+	`pop	%rsi
+	pop	%rdi')
+
+
+dnl  Target ABI macros.  For DOS64 we override the defaults.
+
+define(`IFDOS',   `$1')
+define(`IFSTD',   `')
+define(`IFELF',   `')
+
+
+dnl  Usage: PROTECT(symbol)
+dnl
+dnl  Used for private GMP symbols that should never be overridden by users.
+dnl  This can save reloc entries and improve shlib sharing as well as
+dnl  application startup times
+
+define(`PROTECT',  `')
+
+
+divert`'dnl
diff --git a/third_party/gmp/mpn/x86_64/fastavx/copyd.asm b/third_party/gmp/mpn/x86_64/fastavx/copyd.asm
new file mode 100644
index 0000000..56d472f
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/fastavx/copyd.asm
@@ -0,0 +1,172 @@
+dnl  AMD64 mpn_copyd optimised for CPUs with fast AVX.
+
+dnl  Copyright 2003, 2005, 2007, 2011-2013, 2015 Free Software Foundation, Inc.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb     cycles/limb     cycles/limb      good
+C              aligned	      unaligned	      best seen	     for cpu?
+C AMD K8,K9	n/a
+C AMD K10	n/a
+C AMD bull	n/a
+C AMD pile	 4.87		 4.87				N
+C AMD steam	 ?		 ?
+C AMD bobcat	n/a
+C AMD jaguar	n/a
+C Intel P4	n/a
+C Intel core	n/a
+C Intel NHM	n/a
+C Intel SBR	 0.50		 0.91				N
+C Intel IBR	 0.50		 0.65				N
+C Intel HWL	 0.25		 0.30				Y
+C Intel BWL	 0.28		 0.37				Y
+C Intel atom	n/a
+C VIA nano	n/a
+
+C We try to do as many 32-byte operations as possible.  The top-most and
+C bottom-most writes might need 8-byte operations.  For the bulk copying, we
+C write using aligned 32-byte operations, but we read with both aligned and
+C unaligned 32-byte operations.
+
+define(`rp', `%rdi')
+define(`up', `%rsi')
+define(`n',  `%rdx')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+dnl define(`vmovdqu', vlddqu)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_copyd)
+	FUNC_ENTRY(3)
+
+	lea	-32(rp,n,8), rp
+	lea	-32(up,n,8), up
+
+	cmp	$7, n			C basecase needed for correctness
+	jbe	L(bc)
+
+	test	$8, R8(rp)		C is rp 16-byte aligned?
+	jz	L(a2)			C jump if rp aligned
+	mov	24(up), %rax
+	lea	-8(up), up
+	mov	%rax, 24(rp)
+	lea	-8(rp), rp
+	dec	n
+L(a2):	test	$16, R8(rp)		C is rp 32-byte aligned?
+	jz	L(a3)			C jump if rp aligned
+	vmovdqu	16(up), %xmm0
+	lea	-16(up), up
+	vmovdqa	%xmm0, 16(rp)
+	lea	-16(rp), rp
+	sub	$2, n
+L(a3):	sub	$16, n
+	jc	L(sma)
+
+	ALIGN(16)
+L(top):	vmovdqu	(up), %ymm0
+	vmovdqu	-32(up), %ymm1
+	vmovdqu	-64(up), %ymm2
+	vmovdqu	-96(up), %ymm3
+	lea	-128(up), up
+	vmovdqa	%ymm0, (rp)
+	vmovdqa	%ymm1, -32(rp)
+	vmovdqa	%ymm2, -64(rp)
+	vmovdqa	%ymm3, -96(rp)
+	lea	-128(rp), rp
+L(ali):	sub	$16, n
+	jnc	L(top)
+
+L(sma):	test	$8, R8(n)
+	jz	1f
+	vmovdqu	(up), %ymm0
+	vmovdqu	-32(up), %ymm1
+	lea	-64(up), up
+	vmovdqa	%ymm0, (rp)
+	vmovdqa	%ymm1, -32(rp)
+	lea	-64(rp), rp
+1:
+	test	$4, R8(n)
+	jz	1f
+	vmovdqu	(up), %ymm0
+	lea	-32(up), up
+	vmovdqa	%ymm0, (rp)
+	lea	-32(rp), rp
+1:
+	test	$2, R8(n)
+	jz	1f
+	vmovdqu	16(up), %xmm0
+	lea	-16(up), up
+	vmovdqa	%xmm0, 16(rp)
+	lea	-16(rp), rp
+1:
+	test	$1, R8(n)
+	jz	1f
+	mov	24(up), %r8
+	mov	%r8, 24(rp)
+1:
+	FUNC_EXIT()
+	ret
+
+	ALIGN(16)
+L(bc):	test	$4, R8(n)
+	jz	1f
+	mov	24(up), %rax
+	mov	16(up), %rcx
+	mov	8(up), %r8
+	mov	(up), %r9
+	lea	-32(up), up
+	mov	%rax, 24(rp)
+	mov	%rcx, 16(rp)
+	mov	%r8, 8(rp)
+	mov	%r9, (rp)
+	lea	-32(rp), rp
+1:
+	test	$2, R8(n)
+	jz	1f
+	mov	24(up), %rax
+	mov	16(up), %rcx
+	lea	-16(up), up
+	mov	%rax, 24(rp)
+	mov	%rcx, 16(rp)
+	lea	-16(rp), rp
+1:
+	test	$1, R8(n)
+	jz	1f
+	mov	24(up), %rax
+	mov	%rax, 24(rp)
+1:
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/fastavx/copyi.asm b/third_party/gmp/mpn/x86_64/fastavx/copyi.asm
new file mode 100644
index 0000000..7607747
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/fastavx/copyi.asm
@@ -0,0 +1,169 @@
+dnl  AMD64 mpn_copyi optimised for CPUs with fast AVX.
+
+dnl  Copyright 2003, 2005, 2007, 2011-2013, 2015 Free Software Foundation, Inc.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb     cycles/limb     cycles/limb      good
+C              aligned	      unaligned	      best seen	     for cpu?
+C AMD K8,K9	n/a
+C AMD K10	n/a
+C AMD bull	n/a
+C AMD pile	 4.87		 4.87				N
+C AMD steam	 ?		 ?
+C AMD bobcat	n/a
+C AMD jaguar	n/a
+C Intel P4	n/a
+C Intel core	n/a
+C Intel NHM	n/a
+C Intel SBR	 0.50		 0.91				N
+C Intel IBR	 0.50		 0.65				N
+C Intel HWL	 0.25		 0.30				Y
+C Intel BWL	 0.28		 0.37				Y
+C Intel atom	n/a
+C VIA nano	n/a
+
+C We try to do as many 32-byte operations as possible.  The top-most and
+C bottom-most writes might need 8-byte operations.  For the bulk copying, we
+C write using aligned 32-byte operations, but we read with both aligned and
+C unaligned 32-byte operations.
+
+define(`rp', `%rdi')
+define(`up', `%rsi')
+define(`n',  `%rdx')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+dnl define(`vmovdqu', vlddqu)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_copyi)
+	FUNC_ENTRY(3)
+
+	cmp	$7, n
+	jbe	L(bc)
+
+	test	$8, R8(rp)		C is rp 16-byte aligned?
+	jz	L(a2)			C jump if rp aligned
+	mov	(up), %rax
+	lea	8(up), up
+	mov	%rax, (rp)
+	lea	8(rp), rp
+	dec	n
+L(a2):	test	$16, R8(rp)		C is rp 32-byte aligned?
+	jz	L(a3)			C jump if rp aligned
+	vmovdqu	(up), %xmm0
+	lea	16(up), up
+	vmovdqa	%xmm0, (rp)
+	lea	16(rp), rp
+	sub	$2, n
+L(a3):	sub	$16, n
+	jc	L(sma)
+
+	ALIGN(16)
+L(top):	vmovdqu	(up), %ymm0
+	vmovdqu	32(up), %ymm1
+	vmovdqu	64(up), %ymm2
+	vmovdqu	96(up), %ymm3
+	lea	128(up), up
+	vmovdqa	%ymm0, (rp)
+	vmovdqa	%ymm1, 32(rp)
+	vmovdqa	%ymm2, 64(rp)
+	vmovdqa	%ymm3, 96(rp)
+	lea	128(rp), rp
+L(ali):	sub	$16, n
+	jnc	L(top)
+
+L(sma):	test	$8, R8(n)
+	jz	1f
+	vmovdqu	(up), %ymm0
+	vmovdqu	32(up), %ymm1
+	lea	64(up), up
+	vmovdqa	%ymm0, (rp)
+	vmovdqa	%ymm1, 32(rp)
+	lea	64(rp), rp
+1:
+	test	$4, R8(n)
+	jz	1f
+	vmovdqu	(up), %ymm0
+	lea	32(up), up
+	vmovdqa	%ymm0, (rp)
+	lea	32(rp), rp
+1:
+	test	$2, R8(n)
+	jz	1f
+	vmovdqu	(up), %xmm0
+	lea	16(up), up
+	vmovdqa	%xmm0, (rp)
+	lea	16(rp), rp
+1:
+L(end):	test	$1, R8(n)
+	jz	1f
+	mov	(up), %r8
+	mov	%r8, (rp)
+1:
+	FUNC_EXIT()
+	ret
+
+	ALIGN(16)
+L(bc):	test	$4, R8(n)
+	jz	1f
+	mov	(up), %rax
+	mov	8(up), %rcx
+	mov	16(up), %r8
+	mov	24(up), %r9
+	lea	32(up), up
+	mov	%rax, (rp)
+	mov	%rcx, 8(rp)
+	mov	%r8, 16(rp)
+	mov	%r9, 24(rp)
+	lea	32(rp), rp
+1:
+	test	$2, R8(n)
+	jz	1f
+	mov	(up), %rax
+	mov	8(up), %rcx
+	lea	16(up), up
+	mov	%rax, (rp)
+	mov	%rcx, 8(rp)
+	lea	16(rp), rp
+1:
+	test	$1, R8(n)
+	jz	1f
+	mov	(up), %rax
+	mov	%rax, (rp)
+1:
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/fastsse/README b/third_party/gmp/mpn/x86_64/fastsse/README
new file mode 100644
index 0000000..5538b2d
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/fastsse/README
@@ -0,0 +1,22 @@
+This directory contains code for x86-64 processors with fast
+implementations of SSE operations, hence the name "fastsse".
+
+Current processors that might benefit from this code are:
+
+  AMD K10
+  AMD Bulldozer/Piledriver/Steamroller/Excavator
+  Intel Nocona
+  Intel Nehalem/Westmere
+  Intel Sandybridge/Ivybridge
+  Intel Haswell/Broadwell
+  VIA Nano
+
+Current processors that do not benefit from this code are:
+
+  AMD K8
+  AMD Bobcat
+  Intel Atom
+
+Intel Conroe/Penryn is a border case; its handling of non-aligned
+128-bit memory operands is poor.  VIA Nano also have poor handling of
+non-aligned operands.
diff --git a/third_party/gmp/mpn/x86_64/fastsse/com-palignr.asm b/third_party/gmp/mpn/x86_64/fastsse/com-palignr.asm
new file mode 100644
index 0000000..69027bc
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/fastsse/com-palignr.asm
@@ -0,0 +1,311 @@
+dnl  AMD64 mpn_com optimised for CPUs with fast SSE copying and SSSE3.
+
+dnl  Copyright 2012, 2013, 2015 Free Software Foundation, Inc.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb     cycles/limb     cycles/limb      good
+C              aligned	      unaligned	      best seen	     for cpu?
+C AMD K8,K9	 2.0		 illop		1.0/1.0		N
+C AMD K10	 0.85		 illop				Y/N
+C AMD bd1	 1.39		 ? 1.45				Y/N
+C AMD bd2     0.8-1.4	       0.7-1.4				Y
+C AMD bd3
+C AMD bd4
+C AMD bobcat	 1.97		 ? 8.17		1.5/1.5		N
+C AMD jaguar	 1.02		 1.02		0.91/0.91	N
+C Intel P4	 2.26		 illop				Y/N
+C Intel core	 0.58		 0.87		opt/0.74	Y
+C Intel NHM	 0.64		 1.14		opt/bad		Y
+C Intel SBR	 0.51		 0.65		opt/opt		Y
+C Intel IBR	 0.50		 0.64		opt/0.57	Y
+C Intel HWL	 0.51		 0.58		opt/opt		Y
+C Intel BWL	 0.52		 0.64		opt/opt		Y
+C Intel SKL	 0.51		 0.63		opt/opt		Y
+C Intel atom	 1.16		 1.70		opt/opt		Y
+C Intel SLM	 1.02		 1.52				N
+C VIA nano	 1.09		 1.10		opt/opt		Y
+
+C We use only 16-byte operations, except for unaligned top-most and bottom-most
+C limbs.  We use the SSSE3 palignr instruction when rp - up = 8 (mod 16).  That
+C instruction is better adapted to mpn_copyd's needs, we need to contort the
+C code to use it here.
+C
+C For operands of < COM_SSE_THRESHOLD limbs, we use a plain 64-bit loop, taken
+C from the x86_64 default code.
+
+C INPUT PARAMETERS
+define(`rp', `%rdi')
+define(`up', `%rsi')
+define(`n',  `%rdx')
+
+C There are three instructions for loading an aligned 128-bit quantity.  We use
+C movaps, since it has the shortest coding.
+define(`movdqa', ``movaps'')
+
+ifdef(`COM_SSE_THRESHOLD',`',`define(`COM_SSE_THRESHOLD', 7)')
+
+ASM_START()
+	TEXT
+	ALIGN(64)
+PROLOGUE(mpn_com)
+	FUNC_ENTRY(3)
+
+	cmp	$COM_SSE_THRESHOLD, n
+	jbe	L(bc)
+
+	pcmpeqb	%xmm5, %xmm5		C set to 111...111
+
+	test	$8, R8(rp)		C is rp 16-byte aligned?
+	jz	L(rp_aligned)		C jump if rp aligned
+
+	mov	(up), %r8
+	lea	8(up), up
+	not	%r8
+	mov	%r8, (rp)
+	lea	8(rp), rp
+	dec	n
+
+L(rp_aligned):
+	test	$8, R8(up)
+	jnz	L(uent)
+
+ifelse(eval(COM_SSE_THRESHOLD >= 8),1,
+`	sub	$8, n',
+`	jmp	L(am)')
+
+	ALIGN(16)
+L(atop):movdqa	0(up), %xmm0
+	movdqa	16(up), %xmm1
+	movdqa	32(up), %xmm2
+	movdqa	48(up), %xmm3
+	lea	64(up), up
+	pxor	%xmm5, %xmm0
+	pxor	%xmm5, %xmm1
+	pxor	%xmm5, %xmm2
+	pxor	%xmm5, %xmm3
+	movdqa	%xmm0, (rp)
+	movdqa	%xmm1, 16(rp)
+	movdqa	%xmm2, 32(rp)
+	movdqa	%xmm3, 48(rp)
+	lea	64(rp), rp
+L(am):	sub	$8, n
+	jnc	L(atop)
+
+	test	$4, R8(n)
+	jz	1f
+	movdqa	(up), %xmm0
+	movdqa	16(up), %xmm1
+	lea	32(up), up
+	pxor	%xmm5, %xmm0
+	pxor	%xmm5, %xmm1
+	movdqa	%xmm0, (rp)
+	movdqa	%xmm1, 16(rp)
+	lea	32(rp), rp
+
+1:	test	$2, R8(n)
+	jz	1f
+	movdqa	(up), %xmm0
+	lea	16(up), up
+	pxor	%xmm5, %xmm0
+	movdqa	%xmm0, (rp)
+	lea	16(rp), rp
+
+1:	test	$1, R8(n)
+	jz	1f
+	mov	(up), %r8
+	not	%r8
+	mov	%r8, (rp)
+
+1:	FUNC_EXIT()
+	ret
+
+L(uent):
+C Code handling up - rp = 8 (mod 16)
+
+C FIXME: The code below only handles overlap if it is close to complete, or
+C quite separate: up-rp < 5 or up-up > 15 limbs
+	lea	-40(up), %rax		C 40 = 5 * GMP_LIMB_BYTES
+	sub	rp, %rax
+	cmp	$80, %rax		C 80 = (15-5) * GMP_LIMB_BYTES
+	jbe	L(bc)			C deflect to plain loop
+
+	sub	$16, n
+	jc	L(uend)
+
+	movdqa	120(up), %xmm3
+
+	sub	$16, n
+	jmp	L(um)
+
+	ALIGN(16)
+L(utop):movdqa	120(up), %xmm3
+	pxor	%xmm5, %xmm0
+	movdqa	%xmm0, -128(rp)
+	sub	$16, n
+L(um):	movdqa	104(up), %xmm2
+	palignr($8, %xmm2, %xmm3)
+	movdqa	88(up), %xmm1
+	pxor	%xmm5, %xmm3
+	movdqa	%xmm3, 112(rp)
+	palignr($8, %xmm1, %xmm2)
+	movdqa	72(up), %xmm0
+	pxor	%xmm5, %xmm2
+	movdqa	%xmm2, 96(rp)
+	palignr($8, %xmm0, %xmm1)
+	movdqa	56(up), %xmm3
+	pxor	%xmm5, %xmm1
+	movdqa	%xmm1, 80(rp)
+	palignr($8, %xmm3, %xmm0)
+	movdqa	40(up), %xmm2
+	pxor	%xmm5, %xmm0
+	movdqa	%xmm0, 64(rp)
+	palignr($8, %xmm2, %xmm3)
+	movdqa	24(up), %xmm1
+	pxor	%xmm5, %xmm3
+	movdqa	%xmm3, 48(rp)
+	palignr($8, %xmm1, %xmm2)
+	movdqa	8(up), %xmm0
+	pxor	%xmm5, %xmm2
+	movdqa	%xmm2, 32(rp)
+	palignr($8, %xmm0, %xmm1)
+	movdqa	-8(up), %xmm3
+	pxor	%xmm5, %xmm1
+	movdqa	%xmm1, 16(rp)
+	palignr($8, %xmm3, %xmm0)
+	lea	128(up), up
+	lea	128(rp), rp
+	jnc	L(utop)
+
+	pxor	%xmm5, %xmm0
+	movdqa	%xmm0, -128(rp)
+
+L(uend):test	$8, R8(n)
+	jz	1f
+	movdqa	56(up), %xmm3
+	movdqa	40(up), %xmm2
+	palignr($8, %xmm2, %xmm3)
+	movdqa	24(up), %xmm1
+	pxor	%xmm5, %xmm3
+	movdqa	%xmm3, 48(rp)
+	palignr($8, %xmm1, %xmm2)
+	movdqa	8(up), %xmm0
+	pxor	%xmm5, %xmm2
+	movdqa	%xmm2, 32(rp)
+	palignr($8, %xmm0, %xmm1)
+	movdqa	-8(up), %xmm3
+	pxor	%xmm5, %xmm1
+	movdqa	%xmm1, 16(rp)
+	palignr($8, %xmm3, %xmm0)
+	lea	64(up), up
+	pxor	%xmm5, %xmm0
+	movdqa	%xmm0, (rp)
+	lea	64(rp), rp
+
+1:	test	$4, R8(n)
+	jz	1f
+	movdqa	24(up), %xmm1
+	movdqa	8(up), %xmm0
+	palignr($8, %xmm0, %xmm1)
+	movdqa	-8(up), %xmm3
+	pxor	%xmm5, %xmm1
+	movdqa	%xmm1, 16(rp)
+	palignr($8, %xmm3, %xmm0)
+	lea	32(up), up
+	pxor	%xmm5, %xmm0
+	movdqa	%xmm0, (rp)
+	lea	32(rp), rp
+
+1:	test	$2, R8(n)
+	jz	1f
+	movdqa	8(up), %xmm0
+	movdqa	-8(up), %xmm3
+	palignr($8, %xmm3, %xmm0)
+	lea	16(up), up
+	pxor	%xmm5, %xmm0
+	movdqa	%xmm0, (rp)
+	lea	16(rp), rp
+
+1:	test	$1, R8(n)
+	jz	1f
+	mov	(up), %r8
+	not	%r8
+	mov	%r8, (rp)
+
+1:	FUNC_EXIT()
+	ret
+
+C Basecase code.  Needed for good small operands speed, not for
+C correctness as the above code is currently written.
+
+L(bc):	lea	-8(rp), rp
+	sub	$4, R32(n)
+	jc	L(end)
+
+ifelse(eval(1 || COM_SSE_THRESHOLD >= 8),1,
+`	ALIGN(16)')
+L(top):	mov	(up), %r8
+	mov	8(up), %r9
+	lea	32(rp), rp
+	mov	16(up), %r10
+	mov	24(up), %r11
+	lea	32(up), up
+	not	%r8
+	not	%r9
+	not	%r10
+	not	%r11
+	mov	%r8, -24(rp)
+	mov	%r9, -16(rp)
+ifelse(eval(1 || COM_SSE_THRESHOLD >= 8),1,
+`	sub	$4, R32(n)')
+	mov	%r10, -8(rp)
+	mov	%r11, (rp)
+ifelse(eval(1 || COM_SSE_THRESHOLD >= 8),1,
+`	jnc	L(top)')
+
+L(end):	test	$1, R8(n)
+	jz	1f
+	mov	(up), %r8
+	not	%r8
+	mov	%r8, 8(rp)
+	lea	8(rp), rp
+	lea	8(up), up
+1:	test	$2, R8(n)
+	jz	1f
+	mov	(up), %r8
+	mov	8(up), %r9
+	not	%r8
+	not	%r9
+	mov	%r8, 8(rp)
+	mov	%r9, 16(rp)
+1:	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/fastsse/com.asm b/third_party/gmp/mpn/x86_64/fastsse/com.asm
new file mode 100644
index 0000000..c867222
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/fastsse/com.asm
@@ -0,0 +1,175 @@
+dnl  AMD64 mpn_com optimised for CPUs with fast SSE.
+
+dnl  Copyright 2003, 2005, 2007, 2011, 2012, 2015 Free Software Foundation,
+dnl  Inc.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb     cycles/limb     cycles/limb      good
+C              aligned	      unaligned	      best seen	     for cpu?
+C AMD K8,K9	 2.0		 2.0				N
+C AMD K10	 0.85		 1.3				Y/N
+C AMD bull	 1.40		 1.40				Y
+C AMD pile     0.9-1.4	       0.9-1.4				Y
+C AMD steam
+C AMD excavator
+C AMD bobcat	 3.1		 3.1				N
+C AMD jaguar	 0.91		 0.91		opt/opt		Y
+C Intel P4	 2.28		 illop				Y
+C Intel core2	 1.02		 1.02				N
+C Intel NHM	 0.53		 0.68				Y
+C Intel SBR	 0.51		 0.75		opt/0.65	Y/N
+C Intel IBR	 0.50		 0.57		opt/opt		Y
+C Intel HWL	 0.51		 0.64		opt/0.58	Y
+C Intel BWL	 0.61		 0.65		0.57/opt	Y
+C Intel atom	 3.68		 3.68				N
+C Intel SLM	 1.09		 1.35				N
+C VIA nano	 1.17		 5.09				Y/N
+
+C We try to do as many 16-byte operations as possible.  The top-most and
+C bottom-most writes might need 8-byte operations.  We can always write using
+C aligned 16-byte operations, we read with both aligned and unaligned 16-byte
+C operations.
+
+C Instead of having separate loops for reading aligned and unaligned, we read
+C using MOVDQU.  This seems to work great except for core2; there performance
+C doubles when reading using MOVDQA (for aligned source).  It is unclear how to
+C best handle the unaligned case there.
+
+C INPUT PARAMETERS
+define(`rp', `%rdi')
+define(`up', `%rsi')
+define(`n',  `%rdx')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_com)
+	FUNC_ENTRY(3)
+
+IFDOS(`	add	$-56, %rsp	')
+IFDOS(`	movdqa	%xmm6, (%rsp)	')
+IFDOS(`	movdqa	%xmm7, 16(%rsp)	')
+
+	pcmpeqb	%xmm7, %xmm7		C set to 111...111
+
+	test	$8, R8(rp)		C is rp 16-byte aligned?
+	jz	L(ali)			C jump if rp aligned
+	mov	(up), %rax
+	lea	8(up), up
+	not	%rax
+	mov	%rax, (rp)
+	lea	8(rp), rp
+	dec	n
+
+	sub	$14, n
+	jc	L(sma)
+
+	ALIGN(16)
+L(top):	movdqu	(up), %xmm0
+	movdqu	16(up), %xmm1
+	movdqu	32(up), %xmm2
+	movdqu	48(up), %xmm3
+	movdqu	64(up), %xmm4
+	movdqu	80(up), %xmm5
+	movdqu	96(up), %xmm6
+	lea	112(up), up
+	pxor	%xmm7, %xmm0
+	pxor	%xmm7, %xmm1
+	pxor	%xmm7, %xmm2
+	pxor	%xmm7, %xmm3
+	pxor	%xmm7, %xmm4
+	pxor	%xmm7, %xmm5
+	pxor	%xmm7, %xmm6
+	movdqa	%xmm0, (rp)
+	movdqa	%xmm1, 16(rp)
+	movdqa	%xmm2, 32(rp)
+	movdqa	%xmm3, 48(rp)
+	movdqa	%xmm4, 64(rp)
+	movdqa	%xmm5, 80(rp)
+	movdqa	%xmm6, 96(rp)
+	lea	112(rp), rp
+L(ali):	sub	$14, n
+	jnc	L(top)
+
+L(sma):	add	$14, n
+	test	$8, R8(n)
+	jz	1f
+	movdqu	(up), %xmm0
+	movdqu	16(up), %xmm1
+	movdqu	32(up), %xmm2
+	movdqu	48(up), %xmm3
+	lea	64(up), up
+	pxor	%xmm7, %xmm0
+	pxor	%xmm7, %xmm1
+	pxor	%xmm7, %xmm2
+	pxor	%xmm7, %xmm3
+	movdqa	%xmm0, (rp)
+	movdqa	%xmm1, 16(rp)
+	movdqa	%xmm2, 32(rp)
+	movdqa	%xmm3, 48(rp)
+	lea	64(rp), rp
+1:
+	test	$4, R8(n)
+	jz	1f
+	movdqu	(up), %xmm0
+	movdqu	16(up), %xmm1
+	lea	32(up), up
+	pxor	%xmm7, %xmm0
+	pxor	%xmm7, %xmm1
+	movdqa	%xmm0, (rp)
+	movdqa	%xmm1, 16(rp)
+	lea	32(rp), rp
+1:
+	test	$2, R8(n)
+	jz	1f
+	movdqu	(up), %xmm0
+	lea	16(up), up
+	pxor	%xmm7, %xmm0
+	movdqa	%xmm0, (rp)
+	lea	16(rp), rp
+1:
+	test	$1, R8(n)
+	jz	1f
+	mov	(up), %rax
+	not	%rax
+	mov	%rax, (rp)
+1:
+L(don):
+IFDOS(`	movdqa	(%rsp), %xmm6	')
+IFDOS(`	movdqa	16(%rsp), %xmm7	')
+IFDOS(`	add	$56, %rsp	')
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/fastsse/copyd-palignr.asm b/third_party/gmp/mpn/x86_64/fastsse/copyd-palignr.asm
new file mode 100644
index 0000000..fac6f8a
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/fastsse/copyd-palignr.asm
@@ -0,0 +1,254 @@
+dnl  AMD64 mpn_copyd optimised for CPUs with fast SSE copying and SSSE3.
+
+dnl  Copyright 2012, 2015 Free Software Foundation, Inc.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb     cycles/limb     cycles/limb      good
+C              aligned	      unaligned	      best seen	     for cpu?
+C AMD K8,K9	 2.0		 illop		1.0/1.0		N
+C AMD K10	 0.85		 illop				Y/N
+C AMD bull	 0.70		 0.70				Y
+C AMD pile	 0.68		 0.68				Y
+C AMD steam
+C AMD excavator
+C AMD bobcat	 1.97		 8.24		1.5/1.5		N
+C AMD jaguar	 0.77		 0.89		0.65/opt	N/Y
+C Intel P4	 2.26		 illop				Y/N
+C Intel core	 0.52		 0.80		opt/opt		Y
+C Intel NHM	 0.52		 0.64		opt/opt		Y
+C Intel SBR	 0.51		 0.51		opt/opt		Y
+C Intel IBR	 0.50		 0.50		opt/opt		Y
+C Intel HWL	 0.50		 0.51		opt/opt		Y
+C Intel BWL	 0.55		 0.55		opt/opt		Y
+C Intel atom	 1.16		 1.66		opt/opt		Y
+C Intel SLM	 1.02		 1.04		opt/opt		Y
+C VIA nano	 1.08		 1.06		opt/opt		Y
+
+C We use only 16-byte operations, except for unaligned top-most and bottom-most
+C limbs.  We use the SSSE3 palignr instruction when rp - up = 8 (mod 16).
+C
+C For operands of < COPYD_SSE_THRESHOLD limbs, we use a plain 64-bit loop,
+C taken from the x86_64 default code.
+
+C INPUT PARAMETERS
+define(`rp', `%rdi')
+define(`up', `%rsi')
+define(`n',  `%rdx')
+
+C There are three instructions for loading an aligned 128-bit quantity.  We use
+C movaps, since it has the shortest coding.
+define(`movdqa', ``movaps'')
+
+ifdef(`COPYD_SSE_THRESHOLD',`',`define(`COPYD_SSE_THRESHOLD', 7)')
+
+ASM_START()
+	TEXT
+	ALIGN(64)
+PROLOGUE(mpn_copyd)
+	FUNC_ENTRY(3)
+
+	lea	-8(up,n,8), up
+	lea	-8(rp,n,8), rp
+
+	cmp	$COPYD_SSE_THRESHOLD, n
+	jbe	L(bc)
+
+	test	$8, R8(rp)		C is rp 16-byte aligned?
+	jnz	L(rp_aligned)		C jump if rp aligned
+
+	mov	(up), %rax		C copy one limb
+	mov	%rax, (rp)
+	lea	-8(up), up
+	lea	-8(rp), rp
+	dec	n
+
+L(rp_aligned):
+	test	$8, R8(up)
+	jz	L(uent)
+
+ifelse(eval(COPYD_SSE_THRESHOLD >= 8),1,
+`	sub	$8, n',
+`	jmp	L(am)')
+
+	ALIGN(16)
+L(atop):movdqa	-8(up), %xmm0
+	movdqa	-24(up), %xmm1
+	movdqa	-40(up), %xmm2
+	movdqa	-56(up), %xmm3
+	lea	-64(up), up
+	movdqa	%xmm0, -8(rp)
+	movdqa	%xmm1, -24(rp)
+	movdqa	%xmm2, -40(rp)
+	movdqa	%xmm3, -56(rp)
+	lea	-64(rp), rp
+L(am):	sub	$8, n
+	jnc	L(atop)
+
+	test	$4, R8(n)
+	jz	1f
+	movdqa	-8(up), %xmm0
+	movdqa	-24(up), %xmm1
+	lea	-32(up), up
+	movdqa	%xmm0, -8(rp)
+	movdqa	%xmm1, -24(rp)
+	lea	-32(rp), rp
+
+1:	test	$2, R8(n)
+	jz	1f
+	movdqa	-8(up), %xmm0
+	lea	-16(up), up
+	movdqa	%xmm0, -8(rp)
+	lea	-16(rp), rp
+
+1:	test	$1, R8(n)
+	jz	1f
+	mov	(up), %r8
+	mov	%r8, (rp)
+
+1:	FUNC_EXIT()
+	ret
+
+L(uent):sub	$16, n
+	movdqa	(up), %xmm0
+	jc	L(uend)
+
+	ALIGN(16)
+L(utop):sub	$16, n
+	movdqa	-16(up), %xmm1
+	palignr($8, %xmm1, %xmm0)
+	movdqa	%xmm0, -8(rp)
+	movdqa	-32(up), %xmm2
+	palignr($8, %xmm2, %xmm1)
+	movdqa	%xmm1, -24(rp)
+	movdqa	-48(up), %xmm3
+	palignr($8, %xmm3, %xmm2)
+	movdqa	%xmm2, -40(rp)
+	movdqa	-64(up), %xmm0
+	palignr($8, %xmm0, %xmm3)
+	movdqa	%xmm3, -56(rp)
+	movdqa	-80(up), %xmm1
+	palignr($8, %xmm1, %xmm0)
+	movdqa	%xmm0, -72(rp)
+	movdqa	-96(up), %xmm2
+	palignr($8, %xmm2, %xmm1)
+	movdqa	%xmm1, -88(rp)
+	movdqa	-112(up), %xmm3
+	palignr($8, %xmm3, %xmm2)
+	movdqa	%xmm2, -104(rp)
+	movdqa	-128(up), %xmm0
+	palignr($8, %xmm0, %xmm3)
+	movdqa	%xmm3, -120(rp)
+	lea	-128(up), up
+	lea	-128(rp), rp
+	jnc	L(utop)
+
+L(uend):test	$8, R8(n)
+	jz	1f
+	movdqa	-16(up), %xmm1
+	palignr($8, %xmm1, %xmm0)
+	movdqa	%xmm0, -8(rp)
+	movdqa	-32(up), %xmm0
+	palignr($8, %xmm0, %xmm1)
+	movdqa	%xmm1, -24(rp)
+	movdqa	-48(up), %xmm1
+	palignr($8, %xmm1, %xmm0)
+	movdqa	%xmm0, -40(rp)
+	movdqa	-64(up), %xmm0
+	palignr($8, %xmm0, %xmm1)
+	movdqa	%xmm1, -56(rp)
+	lea	-64(up), up
+	lea	-64(rp), rp
+
+1:	test	$4, R8(n)
+	jz	1f
+	movdqa	-16(up), %xmm1
+	palignr($8, %xmm1, %xmm0)
+	movdqa	%xmm0, -8(rp)
+	movdqa	-32(up), %xmm0
+	palignr($8, %xmm0, %xmm1)
+	movdqa	%xmm1, -24(rp)
+	lea	-32(up), up
+	lea	-32(rp), rp
+
+1:	test	$2, R8(n)
+	jz	1f
+	movdqa	-16(up), %xmm1
+	palignr($8, %xmm1, %xmm0)
+	movdqa	%xmm0, -8(rp)
+	lea	-16(up), up
+	lea	-16(rp), rp
+
+1:	test	$1, R8(n)
+	jz	1f
+	mov	(up), %r8
+	mov	%r8, (rp)
+
+1:	FUNC_EXIT()
+	ret
+
+C Basecase code.  Needed for good small operands speed, not for
+C correctness as the above code is currently written.
+
+L(bc):	sub	$4, R32(n)
+	jc	L(end)
+
+	ALIGN(16)
+L(top):	mov	(up), %r8
+	mov	-8(up), %r9
+	lea	-32(rp), rp
+	mov	-16(up), %r10
+	mov	-24(up), %r11
+	lea	-32(up), up
+	mov	%r8, 32(rp)
+	mov	%r9, 24(rp)
+ifelse(eval(COPYD_SSE_THRESHOLD >= 8),1,
+`	sub	$4, R32(n)')
+	mov	%r10, 16(rp)
+	mov	%r11, 8(rp)
+ifelse(eval(COPYD_SSE_THRESHOLD >= 8),1,
+`	jnc	L(top)')
+
+L(end):	test	$1, R8(n)
+	jz	1f
+	mov	(up), %r8
+	mov	%r8, (rp)
+	lea	-8(rp), rp
+	lea	-8(up), up
+1:	test	$2, R8(n)
+	jz	1f
+	mov	(up), %r8
+	mov	-8(up), %r9
+	mov	%r8, (rp)
+	mov	%r9, -8(rp)
+1:	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/fastsse/copyd.asm b/third_party/gmp/mpn/x86_64/fastsse/copyd.asm
new file mode 100644
index 0000000..b3c4706
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/fastsse/copyd.asm
@@ -0,0 +1,166 @@
+dnl  AMD64 mpn_copyd optimised for CPUs with fast SSE.
+
+dnl  Copyright 2003, 2005, 2007, 2011, 2012, 2015 Free Software Foundation,
+dnl  Inc.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb     cycles/limb     cycles/limb      good
+C              aligned	      unaligned	      best seen	     for cpu?
+C AMD K8,K9
+C AMD K10	 0.85		 1.64				Y/N
+C AMD bull	 1.4		 1.4				Y
+C AMD pile	 0.68		 0.98				Y/N
+C AMD steam
+C AMD excavator
+C AMD bobcat
+C AMD jaguar	 0.65		 1.02		opt/0.93	Y/N
+C Intel P4	 2.3		 2.3				Y
+C Intel core	 1.0		 1.0		0.52/0.80	N
+C Intel NHM	 0.5		 0.67				Y
+C Intel SBR	 0.51		 0.75		opt/0.54	Y/N
+C Intel IBR	 0.50		 0.57		opt/0.50	Y
+C Intel HWL	 0.50		 0.57		opt/0.51	Y
+C Intel BWL	 0.55		 0.62		opt/0.55	Y
+C Intel atom
+C Intel SLM	 1.02		 1.27		opt/1.04	Y/N
+C VIA nano	 1.16		 5.16				Y/N
+
+C We try to do as many 16-byte operations as possible.  The top-most and
+C bottom-most writes might need 8-byte operations.  We can always write using
+C aligned 16-byte operations, we read with both aligned and unaligned 16-byte
+C operations.
+
+C Instead of having separate loops for reading aligned and unaligned, we read
+C using MOVDQU.  This seems to work great except for core2; there performance
+C doubles when reading using MOVDQA (for aligned source).  It is unclear how to
+C best handle the unaligned case there.
+
+C INPUT PARAMETERS
+define(`rp', `%rdi')
+define(`up', `%rsi')
+define(`n',  `%rdx')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+dnl define(`movdqu', lddqu)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_copyd)
+	FUNC_ENTRY(3)
+
+	test	n, n
+	jz	L(don)
+
+	lea	-16(rp,n,8), rp
+	lea	-16(up,n,8), up
+
+	test	$8, R8(rp)		C is rp 16-byte aligned?
+	jz	L(ali)			C jump if rp aligned
+	mov	8(up), %rax
+	lea	-8(up), up
+	mov	%rax, 8(rp)
+	lea	-8(rp), rp
+	dec	n
+
+L(ali):	sub	$16, n
+	jc	L(sma)
+
+IFDOS(`	add	$-56, %rsp	')
+IFDOS(`	movdqa	%xmm6, (%rsp)	')
+IFDOS(`	movdqa	%xmm7, 16(%rsp)	')
+
+	ALIGN(16)
+L(top):	movdqu	(up), %xmm0
+	movdqu	-16(up), %xmm1
+	movdqu	-32(up), %xmm2
+	movdqu	-48(up), %xmm3
+	movdqu	-64(up), %xmm4
+	movdqu	-80(up), %xmm5
+	movdqu	-96(up), %xmm6
+	movdqu	-112(up), %xmm7
+	lea	-128(up), up
+	movdqa	%xmm0, (rp)
+	movdqa	%xmm1, -16(rp)
+	movdqa	%xmm2, -32(rp)
+	movdqa	%xmm3, -48(rp)
+	movdqa	%xmm4, -64(rp)
+	movdqa	%xmm5, -80(rp)
+	movdqa	%xmm6, -96(rp)
+	movdqa	%xmm7, -112(rp)
+	lea	-128(rp), rp
+	sub	$16, n
+	jnc	L(top)
+
+IFDOS(`	movdqa	(%rsp), %xmm6	')
+IFDOS(`	movdqa	16(%rsp), %xmm7	')
+IFDOS(`	add	$56, %rsp	')
+
+L(sma):	test	$8, R8(n)
+	jz	1f
+	movdqu	(up), %xmm0
+	movdqu	-16(up), %xmm1
+	movdqu	-32(up), %xmm2
+	movdqu	-48(up), %xmm3
+	lea	-64(up), up
+	movdqa	%xmm0, (rp)
+	movdqa	%xmm1, -16(rp)
+	movdqa	%xmm2, -32(rp)
+	movdqa	%xmm3, -48(rp)
+	lea	-64(rp), rp
+1:
+	test	$4, R8(n)
+	jz	1f
+	movdqu	(up), %xmm0
+	movdqu	-16(up), %xmm1
+	lea	-32(up), up
+	movdqa	%xmm0, (rp)
+	movdqa	%xmm1, -16(rp)
+	lea	-32(rp), rp
+1:
+	test	$2, R8(n)
+	jz	1f
+	movdqu	(up), %xmm0
+	lea	-16(up), up
+	movdqa	%xmm0, (rp)
+	lea	-16(rp), rp
+1:
+	test	$1, R8(n)
+	jz	1f
+	mov	8(up), %r8
+	mov	%r8, 8(rp)
+1:
+L(don):	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/fastsse/copyi-palignr.asm b/third_party/gmp/mpn/x86_64/fastsse/copyi-palignr.asm
new file mode 100644
index 0000000..9876a47
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/fastsse/copyi-palignr.asm
@@ -0,0 +1,300 @@
+dnl  AMD64 mpn_copyi optimised for CPUs with fast SSE copying and SSSE3.
+
+dnl  Copyright 2012, 2013, 2015 Free Software Foundation, Inc.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb     cycles/limb     cycles/limb      good
+C              aligned	      unaligned	      best seen	     for cpu?
+C AMD K8,K9	 2.0		 illop		1.0/1.0		N
+C AMD K10	 0.85		 illop				Y/N
+C AMD bd1	 0.70		 0.66				Y
+C AMD bd2	 0.68		 0.66				Y
+C AMD bd3	 ?		 ?
+C AMD bd4	 ?		 ?
+C AMD bt1	 1.97		 8.16		1.5/1.5		N
+C AMD bt2	 0.77		 0.93		0.65/opt	N/Y
+C AMD zn1	 ?		 ?
+C AMD zn2	 ?		 ?
+C Intel P4	 2.26		 illop				Y/N
+C Intel CNR	 0.52		 0.64		opt/opt		Y
+C Intel NHM	 0.52		 0.71		0.50/0.67	N
+C Intel SBR	 0.51		 0.54		opt/0.51	Y
+C Intel IBR	 0.50		 0.54		opt/opt		Y
+C Intel HWL	 0.50		 0.51		opt/opt		Y
+C Intel BWL	 0.55		 0.55		opt/opt		Y
+C Intel atom	 1.16		 1.61		opt/opt		Y
+C Intel SLM	 1.02		 1.07		opt/opt		Y
+C VIA nano	 1.09		 1.08		opt/opt		Y
+
+C We use only 16-byte operations, except for unaligned top-most and bottom-most
+C limbs.  We use the SSSE3 palignr instruction when rp - up = 8 (mod 16).  That
+C instruction is better adapted to mpn_copyd's needs, we need to contort the
+C code to use it here.
+C
+C For operands of < COPYI_SSE_THRESHOLD limbs, we use a plain 64-bit loop,
+C taken from the x86_64 default code.
+
+C INPUT PARAMETERS
+define(`rp', `%rdi')
+define(`up', `%rsi')
+define(`n',  `%rdx')
+
+C There are three instructions for loading an aligned 128-bit quantity.  We use
+C movaps, since it has the shortest coding.
+dnl define(`movdqa', ``movaps'')
+
+ifdef(`COPYI_SSE_THRESHOLD',`',`define(`COPYI_SSE_THRESHOLD', 7)')
+
+ASM_START()
+	TEXT
+	ALIGN(64)
+PROLOGUE(mpn_copyi)
+	FUNC_ENTRY(3)
+
+	cmp	$COPYI_SSE_THRESHOLD, n
+	jbe	L(bc)
+
+	test	$8, R8(rp)		C is rp 16-byte aligned?
+	jz	L(rp_aligned)		C jump if rp aligned
+
+	movsq				C copy one limb
+	dec	n
+
+L(rp_aligned):
+	test	$8, R8(up)
+	jnz	L(uent)
+
+ifelse(eval(COPYI_SSE_THRESHOLD >= 8),1,
+`	sub	$8, n',
+`	jmp	L(am)')
+
+	ALIGN(16)
+L(atop):movdqa	0(up), %xmm0
+	movdqa	16(up), %xmm1
+	movdqa	32(up), %xmm2
+	movdqa	48(up), %xmm3
+	lea	64(up), up
+	movdqa	%xmm0, (rp)
+	movdqa	%xmm1, 16(rp)
+	movdqa	%xmm2, 32(rp)
+	movdqa	%xmm3, 48(rp)
+	lea	64(rp), rp
+L(am):	sub	$8, n
+	jnc	L(atop)
+
+	test	$4, R8(n)
+	jz	1f
+	movdqa	(up), %xmm0
+	movdqa	16(up), %xmm1
+	lea	32(up), up
+	movdqa	%xmm0, (rp)
+	movdqa	%xmm1, 16(rp)
+	lea	32(rp), rp
+
+1:	test	$2, R8(n)
+	jz	1f
+	movdqa	(up), %xmm0
+	lea	16(up), up
+	movdqa	%xmm0, (rp)
+	lea	16(rp), rp
+
+1:	test	$1, R8(n)
+	jz	1f
+	mov	(up), %r8
+	mov	%r8, (rp)
+
+1:	FUNC_EXIT()
+	ret
+
+L(uent):
+C Code handling up - rp = 8 (mod 16)
+
+	cmp	$16, n
+	jc	L(ued0)
+
+IFDOS(`	add	$-56, %rsp	')
+IFDOS(`	movdqa	%xmm6, (%rsp)	')
+IFDOS(`	movdqa	%xmm7, 16(%rsp)	')
+IFDOS(`	movdqa	%xmm8, 32(%rsp)	')
+
+	movaps	120(up), %xmm7
+	movaps	104(up), %xmm6
+	movaps	88(up), %xmm5
+	movaps	72(up), %xmm4
+	movaps	56(up), %xmm3
+	movaps	40(up), %xmm2
+	lea	128(up), up
+	sub	$32, n
+	jc	L(ued1)
+
+	ALIGN(16)
+L(utop):movaps	-104(up), %xmm1
+	sub	$16, n
+	movaps	-120(up), %xmm0
+	palignr($8, %xmm6, %xmm7)
+	movaps	-136(up), %xmm8
+	movdqa	%xmm7, 112(rp)
+	palignr($8, %xmm5, %xmm6)
+	movaps	120(up), %xmm7
+	movdqa	%xmm6, 96(rp)
+	palignr($8, %xmm4, %xmm5)
+	movaps	104(up), %xmm6
+	movdqa	%xmm5, 80(rp)
+	palignr($8, %xmm3, %xmm4)
+	movaps	88(up), %xmm5
+	movdqa	%xmm4, 64(rp)
+	palignr($8, %xmm2, %xmm3)
+	movaps	72(up), %xmm4
+	movdqa	%xmm3, 48(rp)
+	palignr($8, %xmm1, %xmm2)
+	movaps	56(up), %xmm3
+	movdqa	%xmm2, 32(rp)
+	palignr($8, %xmm0, %xmm1)
+	movaps	40(up), %xmm2
+	movdqa	%xmm1, 16(rp)
+	palignr($8, %xmm8, %xmm0)
+	lea	128(up), up
+	movdqa	%xmm0, (rp)
+	lea	128(rp), rp
+	jnc	L(utop)
+
+L(ued1):movaps	-104(up), %xmm1
+	movaps	-120(up), %xmm0
+	movaps	-136(up), %xmm8
+	palignr($8, %xmm6, %xmm7)
+	movdqa	%xmm7, 112(rp)
+	palignr($8, %xmm5, %xmm6)
+	movdqa	%xmm6, 96(rp)
+	palignr($8, %xmm4, %xmm5)
+	movdqa	%xmm5, 80(rp)
+	palignr($8, %xmm3, %xmm4)
+	movdqa	%xmm4, 64(rp)
+	palignr($8, %xmm2, %xmm3)
+	movdqa	%xmm3, 48(rp)
+	palignr($8, %xmm1, %xmm2)
+	movdqa	%xmm2, 32(rp)
+	palignr($8, %xmm0, %xmm1)
+	movdqa	%xmm1, 16(rp)
+	palignr($8, %xmm8, %xmm0)
+	movdqa	%xmm0, (rp)
+	lea	128(rp), rp
+
+IFDOS(`	movdqa	(%rsp), %xmm6	')
+IFDOS(`	movdqa	16(%rsp), %xmm7	')
+IFDOS(`	movdqa	32(%rsp), %xmm8	')
+IFDOS(`	add	$56, %rsp	')
+
+L(ued0):test	$8, R8(n)
+	jz	1f
+	movaps	56(up), %xmm3
+	movaps	40(up), %xmm2
+	movaps	24(up), %xmm1
+	movaps	8(up), %xmm0
+	movaps	-8(up), %xmm4
+	palignr($8, %xmm2, %xmm3)
+	movdqa	%xmm3, 48(rp)
+	palignr($8, %xmm1, %xmm2)
+	movdqa	%xmm2, 32(rp)
+	palignr($8, %xmm0, %xmm1)
+	movdqa	%xmm1, 16(rp)
+	palignr($8, %xmm4, %xmm0)
+	lea	64(up), up
+	movdqa	%xmm0, (rp)
+	lea	64(rp), rp
+
+1:	test	$4, R8(n)
+	jz	1f
+	movaps	24(up), %xmm1
+	movaps	8(up), %xmm0
+	palignr($8, %xmm0, %xmm1)
+	movaps	-8(up), %xmm3
+	movdqa	%xmm1, 16(rp)
+	palignr($8, %xmm3, %xmm0)
+	lea	32(up), up
+	movdqa	%xmm0, (rp)
+	lea	32(rp), rp
+
+1:	test	$2, R8(n)
+	jz	1f
+	movdqa	8(up), %xmm0
+	movdqa	-8(up), %xmm3
+	palignr($8, %xmm3, %xmm0)
+	lea	16(up), up
+	movdqa	%xmm0, (rp)
+	lea	16(rp), rp
+
+1:	test	$1, R8(n)
+	jz	1f
+	mov	(up), %r8
+	mov	%r8, (rp)
+
+1:	FUNC_EXIT()
+	ret
+
+C Basecase code.  Needed for good small operands speed, not for
+C correctness as the above code is currently written.
+
+L(bc):	lea	-8(rp), rp
+	sub	$4, R32(n)
+	jc	L(end)
+
+	ALIGN(16)
+L(top):	mov	(up), %r8
+	mov	8(up), %r9
+	lea	32(rp), rp
+	mov	16(up), %r10
+	mov	24(up), %r11
+	lea	32(up), up
+	mov	%r8, -24(rp)
+	mov	%r9, -16(rp)
+ifelse(eval(COPYI_SSE_THRESHOLD >= 8),1,
+`	sub	$4, R32(n)')
+	mov	%r10, -8(rp)
+	mov	%r11, (rp)
+ifelse(eval(COPYI_SSE_THRESHOLD >= 8),1,
+`	jnc	L(top)')
+
+L(end):	test	$1, R8(n)
+	jz	1f
+	mov	(up), %r8
+	mov	%r8, 8(rp)
+	lea	8(rp), rp
+	lea	8(up), up
+1:	test	$2, R8(n)
+	jz	1f
+	mov	(up), %r8
+	mov	8(up), %r9
+	mov	%r8, 8(rp)
+	mov	%r9, 16(rp)
+1:	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/fastsse/copyi.asm b/third_party/gmp/mpn/x86_64/fastsse/copyi.asm
new file mode 100644
index 0000000..97f7865
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/fastsse/copyi.asm
@@ -0,0 +1,185 @@
+dnl  AMD64 mpn_copyi optimised for CPUs with fast SSE.
+
+dnl  Copyright 2003, 2005, 2007, 2011, 2012, 2015 Free Software Foundation,
+dnl  Inc.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb     cycles/limb     cycles/limb      good
+C              aligned	      unaligned	      best seen	     for cpu?
+C AMD K8,K9
+C AMD K10	 0.85		 1.64				Y/N
+C AMD bull	 1.4		 1.4				N
+C AMD pile	 0.77		 0.93				N
+C AMD steam	 ?		 ?
+C AMD excavator	 ?		 ?
+C AMD bobcat
+C AMD jaguar	 0.65		 1.02		opt/0.93	Y/N
+C Intel P4	 2.3		 2.3				Y
+C Intel core	 1.0		 1.0		0.52/0.64	N
+C Intel NHM	 0.5		 0.67				Y
+C Intel SBR	 0.51		 0.75		opt/0.54	Y/N
+C Intel IBR	 0.50		 0.57		opt/0.54	Y
+C Intel HWL	 0.50		 0.57		opt/0.51	Y
+C Intel BWL	 0.55		 0.62		opt/0.55	Y
+C Intel atom
+C Intel SLM	 1.02		 1.27		opt/1.07	Y/N
+C VIA nano	 1.16		 5.16				Y/N
+
+C We try to do as many 16-byte operations as possible.  The top-most and
+C bottom-most writes might need 8-byte operations.  We can always write using
+C aligned 16-byte operations, we read with both aligned and unaligned 16-byte
+C operations.
+
+C Instead of having separate loops for reading aligned and unaligned, we read
+C using MOVDQU.  This seems to work great except for core2; there performance
+C doubles when reading using MOVDQA (for aligned source).  It is unclear how to
+C best handle the unaligned case there.
+
+C INPUT PARAMETERS
+define(`rp', `%rdi')
+define(`up', `%rsi')
+define(`n',  `%rdx')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+dnl define(`movdqu', lddqu)
+
+ASM_START()
+	TEXT
+	ALIGN(64)
+PROLOGUE(mpn_copyi)
+	FUNC_ENTRY(3)
+
+	cmp	$3, n			C NB: bc code below assumes this limit
+	jc	L(bc)
+
+	test	$8, R8(rp)		C is rp 16-byte aligned?
+	jz	L(ali)			C jump if rp aligned
+	movsq				C copy single limb
+	dec	n
+
+L(ali):	sub	$16, n
+	jc	L(sma)
+
+IFDOS(`	add	$-56, %rsp	')
+IFDOS(`	movdqa	%xmm6, (%rsp)	')
+IFDOS(`	movdqa	%xmm7, 16(%rsp)	')
+
+	ALIGN(16)
+L(top):	movdqu	(up), %xmm0
+	movdqu	16(up), %xmm1
+	movdqu	32(up), %xmm2
+	movdqu	48(up), %xmm3
+	movdqu	64(up), %xmm4
+	movdqu	80(up), %xmm5
+	movdqu	96(up), %xmm6
+	movdqu	112(up), %xmm7
+	lea	128(up), up
+	movdqa	%xmm0, (rp)
+	movdqa	%xmm1, 16(rp)
+	movdqa	%xmm2, 32(rp)
+	movdqa	%xmm3, 48(rp)
+	movdqa	%xmm4, 64(rp)
+	movdqa	%xmm5, 80(rp)
+	movdqa	%xmm6, 96(rp)
+	movdqa	%xmm7, 112(rp)
+	lea	128(rp), rp
+	sub	$16, n
+	jnc	L(top)
+
+IFDOS(`	movdqa	(%rsp), %xmm6	')
+IFDOS(`	movdqa	16(%rsp), %xmm7	')
+IFDOS(`	add	$56, %rsp	')
+
+L(sma):	test	$8, R8(n)
+	jz	1f
+	movdqu	(up), %xmm0
+	movdqu	16(up), %xmm1
+	movdqu	32(up), %xmm2
+	movdqu	48(up), %xmm3
+	lea	64(up), up
+	movdqa	%xmm0, (rp)
+	movdqa	%xmm1, 16(rp)
+	movdqa	%xmm2, 32(rp)
+	movdqa	%xmm3, 48(rp)
+	lea	64(rp), rp
+1:
+	test	$4, R8(n)
+	jz	1f
+	movdqu	(up), %xmm0
+	movdqu	16(up), %xmm1
+	lea	32(up), up
+	movdqa	%xmm0, (rp)
+	movdqa	%xmm1, 16(rp)
+	lea	32(rp), rp
+1:
+	test	$2, R8(n)
+	jz	1f
+	movdqu	(up), %xmm0
+	lea	16(up), up
+	movdqa	%xmm0, (rp)
+	lea	16(rp), rp
+	ALIGN(16)
+1:
+L(end):	test	$1, R8(n)
+	jz	1f
+	mov	(up), %r8
+	mov	%r8, (rp)
+1:
+	FUNC_EXIT()
+	ret
+
+C Basecase code.  Needed for good small operands speed, not for correctness as
+C the above code is currently written.  The commented-out lines need to be
+C reinstated if this code is to be used for n > 3, and then the post loop
+C offsets need fixing.
+
+L(bc):	sub	$2, n
+	jc	L(end)
+	ALIGN(16)
+1:	mov	(up), %rax
+	mov	8(up), %rcx
+dnl	lea	16(up), up
+	mov	%rax, (rp)
+	mov	%rcx, 8(rp)
+dnl	lea	16(rp), rp
+dnl	sub	$2, n
+dnl	jnc	1b
+
+	test	$1, R8(n)
+	jz	L(ret)
+	mov	16(up), %rax
+	mov	%rax, 16(rp)
+L(ret):	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/fastsse/lshift-movdqu2.asm b/third_party/gmp/mpn/x86_64/fastsse/lshift-movdqu2.asm
new file mode 100644
index 0000000..a05e850
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/fastsse/lshift-movdqu2.asm
@@ -0,0 +1,182 @@
+dnl  AMD64 mpn_lshift optimised for CPUs with fast SSE including fast movdqu.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2010-2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C	     cycles/limb     cycles/limb     cycles/limb    good
+C              aligned	      unaligned	      best seen	   for cpu?
+C AMD K8,K9	 3		 3		 2.35	  no, use shl/shr
+C AMD K10	 1.5-1.8	 1.5-1.8	 1.33	  yes
+C AMD bd1	 1.7-1.9	 1.7-1.9	 1.33	  yes
+C AMD bobcat	 3.17		 3.17			  yes, bad for n < 20
+C Intel P4	 4.67		 4.67		 2.7	  no, slow movdqu
+C Intel core2	 2.15		 2.15		 1.25	  no, use shld/shrd
+C Intel NHM	 1.66		 1.66		 1.25	  no, use shld/shrd
+C Intel SBR	 1.3		 1.3		 1.25	  yes, bad for n = 4-6
+C Intel atom	11.7		11.7		 4.5	  no
+C VIA nano	 5.7		 5.95		 2.0	  no, slow movdqu
+
+C We try to do as many aligned 16-byte operations as possible.  The top-most
+C and bottom-most writes might need 8-byte operations.
+C
+C This variant rely on fast load movdqu, and uses it even for aligned operands,
+C in order to avoid the need for two separate loops.
+C
+C TODO
+C  * Could 2-limb wind-down code be simplified?
+C  * Improve basecase code, using shld/shrd for SBR, discrete integer shifts
+C    for other affected CPUs.
+
+C INPUT PARAMETERS
+define(`rp',  `%rdi')
+define(`ap',  `%rsi')
+define(`n',   `%rdx')
+define(`cnt', `%rcx')
+
+ASM_START()
+	TEXT
+	ALIGN(64)
+PROLOGUE(mpn_lshift)
+	FUNC_ENTRY(4)
+	movd	R32(%rcx), %xmm4
+	mov	$64, R32(%rax)
+	sub	R32(%rcx), R32(%rax)
+	movd	R32(%rax), %xmm5
+
+	neg	R32(%rcx)
+	mov	-8(ap,n,8), %rax
+	shr	R8(%rcx), %rax
+
+	cmp	$3, n
+	jle	L(bc)
+
+	lea	(rp,n,8), R32(%rcx)
+	test	$8, R8(%rcx)
+	jz	L(rp_aligned)
+
+C Do one initial limb in order to make rp aligned
+	movq	-8(ap,n,8), %xmm0
+	movq	-16(ap,n,8), %xmm1
+	psllq	%xmm4, %xmm0
+	psrlq	%xmm5, %xmm1
+	por	%xmm1, %xmm0
+	movq	%xmm0, -8(rp,n,8)
+	dec	n
+
+L(rp_aligned):
+	lea	1(n), %r8d
+
+	and	$6, R32(%r8)
+	jz	L(ba0)
+	cmp	$4, R32(%r8)
+	jz	L(ba4)
+	jc	L(ba2)
+L(ba6):	add	$-4, n
+	jmp	L(i56)
+L(ba0):	add	$-6, n
+	jmp	L(i70)
+L(ba4):	add	$-2, n
+	jmp	L(i34)
+L(ba2):	add	$-8, n
+	jle	L(end)
+
+	ALIGN(16)
+L(top):	movdqu	40(ap,n,8), %xmm1
+	movdqu	48(ap,n,8), %xmm0
+	psllq	%xmm4, %xmm0
+	psrlq	%xmm5, %xmm1
+	por	%xmm1, %xmm0
+	movdqa	%xmm0, 48(rp,n,8)
+L(i70):
+	movdqu	24(ap,n,8), %xmm1
+	movdqu	32(ap,n,8), %xmm0
+	psllq	%xmm4, %xmm0
+	psrlq	%xmm5, %xmm1
+	por	%xmm1, %xmm0
+	movdqa	%xmm0, 32(rp,n,8)
+L(i56):
+	movdqu	8(ap,n,8), %xmm1
+	movdqu	16(ap,n,8), %xmm0
+	psllq	%xmm4, %xmm0
+	psrlq	%xmm5, %xmm1
+	por	%xmm1, %xmm0
+	movdqa	%xmm0, 16(rp,n,8)
+L(i34):
+	movdqu	-8(ap,n,8), %xmm1
+	movdqu	(ap,n,8), %xmm0
+	psllq	%xmm4, %xmm0
+	psrlq	%xmm5, %xmm1
+	por	%xmm1, %xmm0
+	movdqa	%xmm0, (rp,n,8)
+	sub	$8, n
+	jg	L(top)
+
+L(end):	test	$1, R8(n)
+	jnz	L(end8)
+
+	movdqu	(ap), %xmm1
+	pxor	%xmm0, %xmm0
+	punpcklqdq  %xmm1, %xmm0
+	psllq	%xmm4, %xmm1
+	psrlq	%xmm5, %xmm0
+	por	%xmm1, %xmm0
+	movdqa	%xmm0, (rp)
+	FUNC_EXIT()
+	ret
+
+C Basecase
+	ALIGN(16)
+L(bc):	dec	R32(n)
+	jz	L(end8)
+
+	movq	(ap,n,8), %xmm1
+	movq	-8(ap,n,8), %xmm0
+	psllq	%xmm4, %xmm1
+	psrlq	%xmm5, %xmm0
+	por	%xmm1, %xmm0
+	movq	%xmm0, (rp,n,8)
+	sub	$2, R32(n)
+	jl	L(end8)
+	movq	8(ap), %xmm1
+	movq	(ap), %xmm0
+	psllq	%xmm4, %xmm1
+	psrlq	%xmm5, %xmm0
+	por	%xmm1, %xmm0
+	movq	%xmm0, 8(rp)
+
+L(end8):movq	(ap), %xmm0
+	psllq	%xmm4, %xmm0
+	movq	%xmm0, (rp)
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/fastsse/lshift.asm b/third_party/gmp/mpn/x86_64/fastsse/lshift.asm
new file mode 100644
index 0000000..6a17b93
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/fastsse/lshift.asm
@@ -0,0 +1,173 @@
+dnl  AMD64 mpn_lshift optimised for CPUs with fast SSE.
+
+dnl  Contributed to the GNU project by David Harvey and Torbjorn Granlund.
+
+dnl  Copyright 2010-2012, 2018 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C	     cycles/limb	     cycles/limb	      good
+C          16-byte aligned         16-byte unaligned	    for cpu?
+C AMD K8,K9	 ?			 ?
+C AMD K10	 1.68  (1.45)		 1.75  (1.49)		Y
+C AMD bd1	 1.82  (1.75)		 1.82  (1.75)		Y
+C AMD bobcat	 4			 4
+C Intel P4	 3     (2.7)		 3     (2.7)		Y
+C Intel core2	 2.05  (1.67)		 2.55  (1.75)
+C Intel NHM	 2.05  (1.75)		 2.09  (2)
+C Intel SBR	 1.5   (1.3125)		 1.5   (1.4375)		Y
+C Intel atom	 ?			 ?
+C VIA nano	 2.25  (2)		 2.5   (2)		Y
+
+C We try to do as many 16-byte operations as possible.  The top-most and
+C bottom-most writes might need 8-byte operations.
+
+C There are two inner-loops, one for when rp = ap (mod 16) and one when this is
+C not true.  The aligned case reads 16+8 bytes, the unaligned case reads
+C 16+8+X bytes, where X is 8 or 16 depending on how punpcklqdq is implemented.
+
+C This is not yet great code:
+C   (1) The unaligned case makes many reads.
+C   (2) We should do some unrolling, at least 2-way.
+C With 2-way unrolling but no scheduling we reach 1.5 c/l on K10 and 2 c/l on
+C Nano.
+
+C INPUT PARAMETERS
+define(`rp',  `%rdi')
+define(`ap',  `%rsi')
+define(`n',   `%rdx')
+define(`cnt', `%rcx')
+
+ASM_START()
+	TEXT
+	ALIGN(64)
+PROLOGUE(mpn_lshift)
+	FUNC_ENTRY(4)
+	movd	R32(%rcx), %xmm4
+	mov	$64, R32(%rax)
+	sub	R32(%rcx), R32(%rax)
+	movd	R32(%rax), %xmm5
+
+	neg	R32(%rcx)
+	mov	-8(ap,n,8), %rax
+	shr	R8(%rcx), %rax
+
+	cmp	$2, n
+	jle	L(le2)
+
+	lea	(rp,n,8), R32(%rcx)
+	test	$8, R8(%rcx)
+	je	L(rp_aligned)
+
+C Do one initial limb in order to make rp aligned
+	movq	-8(ap,n,8), %xmm0
+	movq	-16(ap,n,8), %xmm1
+	psllq	%xmm4, %xmm0
+	psrlq	%xmm5, %xmm1
+	por	%xmm1, %xmm0
+	movq	%xmm0, -8(rp,n,8)
+	dec	n
+
+L(rp_aligned):
+	lea	(ap,n,8), R32(%rcx)
+	test	$8, R8(%rcx)
+	je	L(aent)
+	jmp	L(uent)
+C *****************************************************************************
+
+C Handle the case when ap != rp (mod 16).
+
+	ALIGN(16)
+L(utop):movdqa	-8(ap,n,8), %xmm0
+	movq	(ap,n,8), %xmm1
+	punpcklqdq  8(ap,n,8), %xmm1
+	psllq	%xmm4, %xmm1
+	psrlq	%xmm5, %xmm0
+	por	%xmm1, %xmm0
+	movdqa	%xmm0, (rp,n,8)
+L(uent):sub	$2, n
+	ja	L(utop)
+
+	jne	L(end8)
+
+	movq	(ap), %xmm1
+	pxor	%xmm0, %xmm0
+	punpcklqdq  %xmm1, %xmm0
+	punpcklqdq  8(ap), %xmm1
+	psllq	%xmm4, %xmm1
+	psrlq	%xmm5, %xmm0
+	por	%xmm1, %xmm0
+	movdqa	%xmm0, (rp)
+	FUNC_EXIT()
+	ret
+C *****************************************************************************
+
+C Handle the case when ap = rp (mod 16).
+
+	ALIGN(16)
+L(atop):movdqa	(ap,n,8), %xmm0		C xmm0 = B*ap[n-1] + ap[n-2]
+	movq	-8(ap,n,8), %xmm1	C xmm1 = ap[n-3]
+	punpcklqdq  %xmm0, %xmm1	C xmm1 = B*ap[n-2] + ap[n-3]
+	psllq	%xmm4, %xmm0
+	psrlq	%xmm5, %xmm1
+	por	%xmm1, %xmm0
+	movdqa	%xmm0, (rp,n,8)
+L(aent):
+	sub	$2, n
+	ja	L(atop)
+	jne	L(end8)
+
+	movdqa	(ap), %xmm1
+	pxor	%xmm0, %xmm0
+	punpcklqdq  %xmm1, %xmm0
+	psllq	%xmm4, %xmm1
+	psrlq	%xmm5, %xmm0
+	por	%xmm1, %xmm0
+	movdqa	%xmm0, (rp)
+	FUNC_EXIT()
+	ret
+C *****************************************************************************
+
+	ALIGN(16)
+L(le2):	jne	L(end8)
+
+	movq	8(ap), %xmm0
+	movq	(ap), %xmm1
+	psllq	%xmm4, %xmm0
+	psrlq	%xmm5, %xmm1
+	por	%xmm1, %xmm0
+	movq	%xmm0, 8(rp)
+
+L(end8):movq	(ap), %xmm0
+	psllq	%xmm4, %xmm0
+	movq	%xmm0, (rp)
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/fastsse/lshiftc-movdqu2.asm b/third_party/gmp/mpn/x86_64/fastsse/lshiftc-movdqu2.asm
new file mode 100644
index 0000000..8250910
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/fastsse/lshiftc-movdqu2.asm
@@ -0,0 +1,193 @@
+dnl  AMD64 mpn_lshiftc optimised for CPUs with fast SSE including fast movdqu.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2010-2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C	     cycles/limb     cycles/limb     cycles/limb    good
+C              aligned	      unaligned	      best seen	   for cpu?
+C AMD K8,K9	 3		 3		 ?	  no, use shl/shr
+C AMD K10	 1.8-2.0	 1.8-2.0	 ?	  yes
+C AMD bd1	 1.9		 1.9		 ?	  yes
+C AMD bobcat	 3.67		 3.67			  yes, bad for n < 20
+C Intel P4	 4.75		 4.75		 ?	  no, slow movdqu
+C Intel core2	 2.27		 2.27		 ?	  no, use shld/shrd
+C Intel NHM	 2.15		 2.15		 ?	  no, use shld/shrd
+C Intel SBR	 1.45		 1.45		 ?	  yes, bad for n = 4-6
+C Intel atom	12.9		12.9		 ?	  no
+C VIA nano	 6.18		 6.44		 ?	  no, slow movdqu
+
+C We try to do as many aligned 16-byte operations as possible.  The top-most
+C and bottom-most writes might need 8-byte operations.
+C
+C This variant rely on fast load movdqu, and uses it even for aligned operands,
+C in order to avoid the need for two separate loops.
+C
+C TODO
+C  * Could 2-limb wind-down code be simplified?
+C  * Improve basecase code, using shld/shrd for SBR, discrete integer shifts
+C    for other affected CPUs.
+
+C INPUT PARAMETERS
+define(`rp',  `%rdi')
+define(`ap',  `%rsi')
+define(`n',   `%rdx')
+define(`cnt', `%rcx')
+
+ASM_START()
+	TEXT
+	ALIGN(64)
+PROLOGUE(mpn_lshiftc)
+	FUNC_ENTRY(4)
+	movd	R32(%rcx), %xmm4
+	mov	$64, R32(%rax)
+	sub	R32(%rcx), R32(%rax)
+	movd	R32(%rax), %xmm5
+
+	neg	R32(%rcx)
+	mov	-8(ap,n,8), %rax
+	shr	R8(%rcx), %rax
+
+	pcmpeqb	%xmm3, %xmm3		C set to 111...111
+
+	cmp	$3, n
+	jle	L(bc)
+
+	lea	(rp,n,8), R32(%rcx)
+	test	$8, R8(%rcx)
+	jz	L(rp_aligned)
+
+C Do one initial limb in order to make rp aligned
+	movq	-8(ap,n,8), %xmm0
+	movq	-16(ap,n,8), %xmm1
+	psllq	%xmm4, %xmm0
+	psrlq	%xmm5, %xmm1
+	por	%xmm1, %xmm0
+	pxor	%xmm3, %xmm0
+	movq	%xmm0, -8(rp,n,8)
+	dec	n
+
+L(rp_aligned):
+	lea	1(n), %r8d
+
+	and	$6, R32(%r8)
+	jz	L(ba0)
+	cmp	$4, R32(%r8)
+	jz	L(ba4)
+	jc	L(ba2)
+L(ba6):	add	$-4, n
+	jmp	L(i56)
+L(ba0):	add	$-6, n
+	jmp	L(i70)
+L(ba4):	add	$-2, n
+	jmp	L(i34)
+L(ba2):	add	$-8, n
+	jle	L(end)
+
+	ALIGN(16)
+L(top):	movdqu	40(ap,n,8), %xmm1
+	movdqu	48(ap,n,8), %xmm0
+	psllq	%xmm4, %xmm0
+	psrlq	%xmm5, %xmm1
+	por	%xmm1, %xmm0
+	pxor	%xmm3, %xmm0
+	movdqa	%xmm0, 48(rp,n,8)
+L(i70):
+	movdqu	24(ap,n,8), %xmm1
+	movdqu	32(ap,n,8), %xmm0
+	psllq	%xmm4, %xmm0
+	psrlq	%xmm5, %xmm1
+	por	%xmm1, %xmm0
+	pxor	%xmm3, %xmm0
+	movdqa	%xmm0, 32(rp,n,8)
+L(i56):
+	movdqu	8(ap,n,8), %xmm1
+	movdqu	16(ap,n,8), %xmm0
+	psllq	%xmm4, %xmm0
+	psrlq	%xmm5, %xmm1
+	por	%xmm1, %xmm0
+	pxor	%xmm3, %xmm0
+	movdqa	%xmm0, 16(rp,n,8)
+L(i34):
+	movdqu	-8(ap,n,8), %xmm1
+	movdqu	(ap,n,8), %xmm0
+	psllq	%xmm4, %xmm0
+	psrlq	%xmm5, %xmm1
+	por	%xmm1, %xmm0
+	pxor	%xmm3, %xmm0
+	movdqa	%xmm0, (rp,n,8)
+	sub	$8, n
+	jg	L(top)
+
+L(end):	test	$1, R8(n)
+	jnz	L(end8)
+
+	movdqu	(ap), %xmm1
+	pxor	%xmm0, %xmm0
+	punpcklqdq  %xmm1, %xmm0
+	psllq	%xmm4, %xmm1
+	psrlq	%xmm5, %xmm0
+	por	%xmm1, %xmm0
+	pxor	%xmm3, %xmm0
+	movdqa	%xmm0, (rp)
+	FUNC_EXIT()
+	ret
+
+C Basecase
+	ALIGN(16)
+L(bc):	dec	R32(n)
+	jz	L(end8)
+
+	movq	(ap,n,8), %xmm1
+	movq	-8(ap,n,8), %xmm0
+	psllq	%xmm4, %xmm1
+	psrlq	%xmm5, %xmm0
+	por	%xmm1, %xmm0
+	pxor	%xmm3, %xmm0
+	movq	%xmm0, (rp,n,8)
+	sub	$2, R32(n)
+	jl	L(end8)
+	movq	8(ap), %xmm1
+	movq	(ap), %xmm0
+	psllq	%xmm4, %xmm1
+	psrlq	%xmm5, %xmm0
+	por	%xmm1, %xmm0
+	pxor	%xmm3, %xmm0
+	movq	%xmm0, 8(rp)
+
+L(end8):movq	(ap), %xmm0
+	psllq	%xmm4, %xmm0
+	pxor	%xmm3, %xmm0
+	movq	%xmm0, (rp)
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/fastsse/lshiftc.asm b/third_party/gmp/mpn/x86_64/fastsse/lshiftc.asm
new file mode 100644
index 0000000..a616075
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/fastsse/lshiftc.asm
@@ -0,0 +1,183 @@
+dnl  AMD64 mpn_lshiftc optimised for CPUs with fast SSE.
+
+dnl  Contributed to the GNU project by David Harvey and Torbjorn Granlund.
+
+dnl  Copyright 2010-2012, 2018 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C	     cycles/limb	     cycles/limb	      good
+C          16-byte aligned         16-byte unaligned	    for cpu?
+C AMD K8,K9	 ?			 ?
+C AMD K10	 1.85  (1.635)		 1.9   (1.67)		Y
+C AMD bd1	 1.82  (1.75)		 1.82  (1.75)		Y
+C AMD bobcat	 4.5			 4.5
+C Intel P4	 3.6   (3.125)		 3.6   (3.125)		Y
+C Intel core2	 2.05  (1.67)		 2.55  (1.75)
+C Intel NHM	 2.05  (1.875)		 2.6   (2.25)
+C Intel SBR	 1.55  (1.44)		 2     (1.57)		Y
+C Intel atom	 ?			 ?
+C VIA nano	 2.5   (2.5)		 2.5   (2.5)		Y
+
+C We try to do as many 16-byte operations as possible.  The top-most and
+C bottom-most writes might need 8-byte operations.  We always write using
+C 16-byte operations, we read with both 8-byte and 16-byte operations.
+
+C There are two inner-loops, one for when rp = ap (mod 16) and one when this is
+C not true.  The aligned case reads 16+8 bytes, the unaligned case reads
+C 16+8+X bytes, where X is 8 or 16 depending on how punpcklqdq is implemented.
+
+C This is not yet great code:
+C   (1) The unaligned case makes too many reads.
+C   (2) We should do some unrolling, at least 2-way.
+C With 2-way unrolling but no scheduling we reach 1.5 c/l on K10 and 2 c/l on
+C Nano.
+
+C INPUT PARAMETERS
+define(`rp',  `%rdi')
+define(`ap',  `%rsi')
+define(`n',   `%rdx')
+define(`cnt', `%rcx')
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_lshiftc)
+	FUNC_ENTRY(4)
+	movd	R32(%rcx), %xmm4
+	mov	$64, R32(%rax)
+	sub	R32(%rcx), R32(%rax)
+	movd	R32(%rax), %xmm5
+
+	neg	R32(%rcx)
+	mov	-8(ap,n,8), %rax
+	shr	R8(%rcx), %rax
+
+	pcmpeqb	%xmm2, %xmm2		C set to 111...111
+
+	cmp	$2, n
+	jle	L(le2)
+
+	lea	(rp,n,8), R32(%rcx)
+	test	$8, R8(%rcx)
+	je	L(rp_aligned)
+
+C Do one initial limb in order to make rp aligned
+	movq	-8(ap,n,8), %xmm0
+	movq	-16(ap,n,8), %xmm1
+	psllq	%xmm4, %xmm0
+	psrlq	%xmm5, %xmm1
+	por	%xmm1, %xmm0
+	pxor	%xmm2, %xmm0
+	movq	%xmm0, -8(rp,n,8)
+	dec	n
+
+L(rp_aligned):
+	lea	(ap,n,8), R32(%rcx)
+	test	$8, R8(%rcx)
+	je	L(aent)
+	jmp	L(uent)
+C *****************************************************************************
+
+C Handle the case when ap != rp (mod 16).
+
+	ALIGN(16)
+L(utop):movq	(ap,n,8), %xmm1
+	punpcklqdq  8(ap,n,8), %xmm1
+	movdqa	-8(ap,n,8), %xmm0
+	psllq	%xmm4, %xmm1
+	psrlq	%xmm5, %xmm0
+	por	%xmm1, %xmm0
+	pxor	%xmm2, %xmm0
+	movdqa	%xmm0, (rp,n,8)
+L(uent):sub	$2, n
+	ja	L(utop)
+
+	jne	L(end8)
+
+	movq	(ap), %xmm1
+	pxor	%xmm0, %xmm0
+	punpcklqdq  %xmm1, %xmm0
+	punpcklqdq  8(ap), %xmm1
+	psllq	%xmm4, %xmm1
+	psrlq	%xmm5, %xmm0
+	por	%xmm1, %xmm0
+	pxor	%xmm2, %xmm0
+	movdqa	%xmm0, (rp)
+	FUNC_EXIT()
+	ret
+C *****************************************************************************
+
+C Handle the case when ap = rp (mod 16).
+
+	ALIGN(16)
+L(atop):movdqa	(ap,n,8), %xmm0		C xmm0 = B*ap[n-1] + ap[n-2]
+	movq	-8(ap,n,8), %xmm1	C xmm1 = ap[n-3]
+	punpcklqdq  %xmm0, %xmm1	C xmm1 = B*ap[n-2] + ap[n-3]
+	psllq	%xmm4, %xmm0
+	psrlq	%xmm5, %xmm1
+	por	%xmm1, %xmm0
+	pxor	%xmm2, %xmm0
+	movdqa	%xmm0, (rp,n,8)
+L(aent):sub	$2, n
+	ja	L(atop)
+
+	jne	L(end8)
+
+	movdqa	(ap), %xmm0
+	pxor	%xmm1, %xmm1
+	punpcklqdq  %xmm0, %xmm1
+	psllq	%xmm4, %xmm0
+	psrlq	%xmm5, %xmm1
+	por	%xmm1, %xmm0
+	pxor	%xmm2, %xmm0
+	movdqa	%xmm0, (rp)
+	FUNC_EXIT()
+	ret
+C *****************************************************************************
+
+	ALIGN(16)
+L(le2):	jne	L(end8)
+
+	movq	8(ap), %xmm0
+	movq	(ap), %xmm1
+	psllq	%xmm4, %xmm0
+	psrlq	%xmm5, %xmm1
+	por	%xmm1, %xmm0
+	pxor	%xmm2, %xmm0
+	movq	%xmm0, 8(rp)
+
+L(end8):movq	(ap), %xmm0
+	psllq	%xmm4, %xmm0
+	pxor	%xmm2, %xmm0
+	movq	%xmm0, (rp)
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/fastsse/rshift-movdqu2.asm b/third_party/gmp/mpn/x86_64/fastsse/rshift-movdqu2.asm
new file mode 100644
index 0000000..1e270b1
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/fastsse/rshift-movdqu2.asm
@@ -0,0 +1,201 @@
+dnl  AMD64 mpn_rshift optimised for CPUs with fast SSE including fast movdqu.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2010-2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C	     cycles/limb     cycles/limb     cycles/limb    good
+C              aligned	      unaligned	      best seen	   for cpu?
+C AMD K8,K9	 3		 3		 2.35	  no, use shl/shr
+C AMD K10	 1.5-1.8	 1.5-1.8	 1.33	  yes
+C AMD bd1	 1.7-1.9	 1.7-1.9	 1.33	  yes
+C AMD bobcat	 3.17		 3.17			  yes, bad for n < 20
+C Intel P4	 4.67		 4.67		 2.7	  no, slow movdqu
+C Intel core2	 2.15		 2.15		 1.25	  no, use shld/shrd
+C Intel NHM	 1.66		 1.66		 1.25	  no, use shld/shrd
+C Intel SBR	 1.3		 1.3		 1.25	  yes, bad for n = 4-6
+C Intel atom	11.7		11.7		 4.5	  no
+C VIA nano	 5.7		 5.95		 2.0	  no, slow movdqu
+
+C We try to do as many aligned 16-byte operations as possible.  The top-most
+C and bottom-most writes might need 8-byte operations.
+C
+C This variant rely on fast load movdqu, and uses it even for aligned operands,
+C in order to avoid the need for two separate loops.
+C
+C TODO
+C  * Could 2-limb wind-down code be simplified?
+C  * Improve basecase code, using shld/shrd for SBR, discrete integer shifts
+C    for other affected CPUs.
+
+C INPUT PARAMETERS
+define(`rp',  `%rdi')
+define(`ap',  `%rsi')
+define(`n',   `%rdx')
+define(`cnt', `%rcx')
+
+ASM_START()
+	TEXT
+	ALIGN(64)
+PROLOGUE(mpn_rshift)
+	FUNC_ENTRY(4)
+	movd	R32(%rcx), %xmm4
+	mov	$64, R32(%rax)
+	sub	R32(%rcx), R32(%rax)
+	movd	R32(%rax), %xmm5
+
+	neg	R32(%rcx)
+	mov	(ap), %rax
+	shl	R8(%rcx), %rax
+
+	cmp	$3, n
+	jle	L(bc)
+
+	test	$8, R8(rp)
+	jz	L(rp_aligned)
+
+C Do one initial limb in order to make rp aligned
+	movq	(ap), %xmm0
+	movq	8(ap), %xmm1
+	psrlq	%xmm4, %xmm0
+	psllq	%xmm5, %xmm1
+	por	%xmm1, %xmm0
+	movq	%xmm0, (rp)
+	lea	8(ap), ap
+	lea	8(rp), rp
+	dec	n
+
+L(rp_aligned):
+	lea	1(n), %r8d
+	lea	(ap,n,8), ap
+	lea	(rp,n,8), rp
+	neg	n
+
+	and	$6, R32(%r8)
+	jz	L(bu0)
+	cmp	$4, R32(%r8)
+	jz	L(bu4)
+	jc	L(bu2)
+L(bu6):	add	$4, n
+	jmp	L(i56)
+L(bu0):	add	$6, n
+	jmp	L(i70)
+L(bu4):	add	$2, n
+	jmp	L(i34)
+L(bu2):	add	$8, n
+	jge	L(end)
+
+	ALIGN(16)
+L(top):	movdqu	-64(ap,n,8), %xmm1
+	movdqu	-56(ap,n,8), %xmm0
+	psllq	%xmm5, %xmm0
+	psrlq	%xmm4, %xmm1
+	por	%xmm1, %xmm0
+	movdqa	%xmm0, -64(rp,n,8)
+L(i70):
+	movdqu	-48(ap,n,8), %xmm1
+	movdqu	-40(ap,n,8), %xmm0
+	psllq	%xmm5, %xmm0
+	psrlq	%xmm4, %xmm1
+	por	%xmm1, %xmm0
+	movdqa	%xmm0, -48(rp,n,8)
+L(i56):
+	movdqu	-32(ap,n,8), %xmm1
+	movdqu	-24(ap,n,8), %xmm0
+	psllq	%xmm5, %xmm0
+	psrlq	%xmm4, %xmm1
+	por	%xmm1, %xmm0
+	movdqa	%xmm0, -32(rp,n,8)
+L(i34):
+	movdqu	-16(ap,n,8), %xmm1
+	movdqu	-8(ap,n,8), %xmm0
+	psllq	%xmm5, %xmm0
+	psrlq	%xmm4, %xmm1
+	por	%xmm1, %xmm0
+	movdqa	%xmm0, -16(rp,n,8)
+	add	$8, n
+	jl	L(top)
+
+L(end):	test	$1, R8(n)
+	jnz	L(e1)
+
+	movdqu	-16(ap), %xmm1
+	movq	-8(ap), %xmm0
+	psrlq	%xmm4, %xmm1
+	psllq	%xmm5, %xmm0
+	por	%xmm1, %xmm0
+	movdqa	%xmm0, -16(rp)
+	FUNC_EXIT()
+	ret
+
+L(e1):	movq	-8(ap), %xmm0
+	psrlq	%xmm4, %xmm0
+	movq	%xmm0, -8(rp)
+	FUNC_EXIT()
+	ret
+
+C Basecase
+	ALIGN(16)
+L(bc):	dec	R32(n)
+	jnz	1f
+	movq	(ap), %xmm0
+	psrlq	%xmm4, %xmm0
+	movq	%xmm0, (rp)
+	FUNC_EXIT()
+	ret
+
+1:	movq	(ap), %xmm1
+	movq	8(ap), %xmm0
+	psrlq	%xmm4, %xmm1
+	psllq	%xmm5, %xmm0
+	por	%xmm1, %xmm0
+	movq	%xmm0, (rp)
+	dec	R32(n)
+	jnz	1f
+	movq	8(ap), %xmm0
+	psrlq	%xmm4, %xmm0
+	movq	%xmm0, 8(rp)
+	FUNC_EXIT()
+	ret
+
+1:	movq	8(ap), %xmm1
+	movq	16(ap), %xmm0
+	psrlq	%xmm4, %xmm1
+	psllq	%xmm5, %xmm0
+	por	%xmm1, %xmm0
+	movq	%xmm0,	8(rp)
+	movq	16(ap), %xmm0
+	psrlq	%xmm4, %xmm0
+	movq	%xmm0, 16(rp)
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/fastsse/sec_tabselect.asm b/third_party/gmp/mpn/x86_64/fastsse/sec_tabselect.asm
new file mode 100644
index 0000000..e7b7feb
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/fastsse/sec_tabselect.asm
@@ -0,0 +1,204 @@
+dnl  AMD64 SSE mpn_sec_tabselect.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C	     cycles/limb     cycles/limb     cycles/limb
+C	      ali,evn n	     unal,evn n	      other cases
+C AMD K8,K9	 1.65		1.65		 1.8
+C AMD K10	 0.78		0.78		 0.85
+C AMD bd1	 0.80		0.91		 1.25
+C AMD bobcat	 2.15		2.15		 2.37
+C Intel P4	 2.5		2.5		 2.95
+C Intel core2	 1.17		1.25		 1.25
+C Intel NHM	 0.87		0.90		 0.90
+C Intel SBR	 0.63		0.79		 0.77
+C Intel atom	 4.3		 4.3		 4.3	slower than plain code
+C VIA nano	 1.4		 5.1		 3.14	too alignment dependent
+
+C NOTES
+C  * We only honour the least significant 32 bits of the `which' and `nents'
+C    arguments to allow efficient code using just SSE2.  We would need to
+C    either use the SSE4_1 pcmpeqq, or find some other SSE2 sequence.
+C  * We use movd for copying between xmm and plain registers, since old gas
+C    rejects movq.  But gas assembles movd as movq when given a 64-bit greg.
+
+define(`rp',     `%rdi')
+define(`tp',     `%rsi')
+define(`n',      `%rdx')
+define(`nents',  `%rcx')
+define(`which',  `%r8')
+
+define(`i',      `%r10')
+define(`j',      `%r9')
+
+C rax  rbx  rcx  rdx  rdi  rsi  rbp   r8   r9  r10  r11  r12  r13  r14  r15
+C          nents  n   rp   tab       which j    i   temp  *    *    *    *
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_sec_tabselect)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8d	')
+
+IFDOS(`	add	$-88, %rsp	')
+IFDOS(`	movdqu	%xmm6, (%rsp)	')
+IFDOS(`	movdqu	%xmm7, 16(%rsp)	')
+IFDOS(`	movdqu	%xmm8, 32(%rsp)	')
+IFDOS(`	movdqu	%xmm9, 48(%rsp)	')
+
+	movd	which, %xmm8
+	pshufd	$0, %xmm8, %xmm8	C 4 `which' copies
+	mov	$1, R32(%rax)
+	movd	%rax, %xmm9
+	pshufd	$0, %xmm9, %xmm9	C 4 copies of 1
+
+	mov	n, j
+	add	$-8, j
+	js	L(outer_end)
+
+L(outer_top):
+	mov	nents, i
+	mov	tp, %r11
+	pxor	%xmm1, %xmm1
+	pxor	%xmm4, %xmm4
+	pxor	%xmm5, %xmm5
+	pxor	%xmm6, %xmm6
+	pxor	%xmm7, %xmm7
+	ALIGN(16)
+L(top):	movdqa	%xmm8, %xmm0
+	pcmpeqd	%xmm1, %xmm0
+	paddd	%xmm9, %xmm1
+	movdqu	0(tp), %xmm2
+	movdqu	16(tp), %xmm3
+	pand	%xmm0, %xmm2
+	pand	%xmm0, %xmm3
+	por	%xmm2, %xmm4
+	por	%xmm3, %xmm5
+	movdqu	32(tp), %xmm2
+	movdqu	48(tp), %xmm3
+	pand	%xmm0, %xmm2
+	pand	%xmm0, %xmm3
+	por	%xmm2, %xmm6
+	por	%xmm3, %xmm7
+	lea	(tp,n,8), tp
+	add	$-1, i
+	jne	L(top)
+
+	movdqu	%xmm4, 0(rp)
+	movdqu	%xmm5, 16(rp)
+	movdqu	%xmm6, 32(rp)
+	movdqu	%xmm7, 48(rp)
+
+	lea	64(%r11), tp
+	lea	64(rp), rp
+	add	$-8, j
+	jns	L(outer_top)
+L(outer_end):
+
+	test	$4, R8(n)
+	je	L(b0xx)
+L(b1xx):mov	nents, i
+	mov	tp, %r11
+	pxor	%xmm1, %xmm1
+	pxor	%xmm4, %xmm4
+	pxor	%xmm5, %xmm5
+	ALIGN(16)
+L(tp4):	movdqa	%xmm8, %xmm0
+	pcmpeqd	%xmm1, %xmm0
+	paddd	%xmm9, %xmm1
+	movdqu	0(tp), %xmm2
+	movdqu	16(tp), %xmm3
+	pand	%xmm0, %xmm2
+	pand	%xmm0, %xmm3
+	por	%xmm2, %xmm4
+	por	%xmm3, %xmm5
+	lea	(tp,n,8), tp
+	add	$-1, i
+	jne	L(tp4)
+	movdqu	%xmm4, 0(rp)
+	movdqu	%xmm5, 16(rp)
+	lea	32(%r11), tp
+	lea	32(rp), rp
+
+L(b0xx):test	$2, R8(n)
+	je	L(b00x)
+L(b01x):mov	nents, i
+	mov	tp, %r11
+	pxor	%xmm1, %xmm1
+	pxor	%xmm4, %xmm4
+	ALIGN(16)
+L(tp2):	movdqa	%xmm8, %xmm0
+	pcmpeqd	%xmm1, %xmm0
+	paddd	%xmm9, %xmm1
+	movdqu	0(tp), %xmm2
+	pand	%xmm0, %xmm2
+	por	%xmm2, %xmm4
+	lea	(tp,n,8), tp
+	add	$-1, i
+	jne	L(tp2)
+	movdqu	%xmm4, 0(rp)
+	lea	16(%r11), tp
+	lea	16(rp), rp
+
+L(b00x):test	$1, R8(n)
+	je	L(b000)
+L(b001):mov	nents, i
+	mov	tp, %r11
+	pxor	%xmm1, %xmm1
+	pxor	%xmm4, %xmm4
+	ALIGN(16)
+L(tp1):	movdqa	%xmm8, %xmm0
+	pcmpeqd	%xmm1, %xmm0
+	paddd	%xmm9, %xmm1
+	movq	0(tp), %xmm2
+	pand	%xmm0, %xmm2
+	por	%xmm2, %xmm4
+	lea	(tp,n,8), tp
+	add	$-1, i
+	jne	L(tp1)
+	movq	%xmm4, 0(rp)
+
+L(b000):
+IFDOS(`	movdqu	(%rsp), %xmm6	')
+IFDOS(`	movdqu	16(%rsp), %xmm7	')
+IFDOS(`	movdqu	32(%rsp), %xmm8	')
+IFDOS(`	movdqu	48(%rsp), %xmm9	')
+IFDOS(`	add	$88, %rsp	')
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/fat/addmul_2.c b/third_party/gmp/mpn/x86_64/fat/addmul_2.c
new file mode 100644
index 0000000..e0d7358
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/fat/addmul_2.c
@@ -0,0 +1,38 @@
+/* Fat binary fallback mpn_addmul_2.
+
+Copyright 2016 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+mp_limb_t
+mpn_addmul_2 (mp_ptr rp, mp_srcptr up, mp_size_t n, const mp_limb_t vp[2])
+{
+  rp[n] = mpn_addmul_1 (rp,     up, n, vp[0]);
+  return  mpn_addmul_1 (rp + 1, up, n, vp[1]);
+}
diff --git a/third_party/gmp/mpn/x86_64/fat/fat.c b/third_party/gmp/mpn/x86_64/fat/fat.c
new file mode 100644
index 0000000..b7446a3
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/fat/fat.c
@@ -0,0 +1,472 @@
+/* x86_64 fat binary initializers.
+
+   Contributed to the GNU project by Kevin Ryde (original x86_32 code) and
+   Torbjorn Granlund (port to x86_64)
+
+   THE FUNCTIONS AND VARIABLES IN THIS FILE ARE FOR INTERNAL USE ONLY.
+   THEY'RE ALMOST CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR
+   COMPLETELY IN FUTURE GNU MP RELEASES.
+
+Copyright 2003, 2004, 2009, 2011-2015, 2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>    /* for printf */
+#include <stdlib.h>   /* for getenv */
+#include <string.h>
+
+#include "gmp-impl.h"
+
+/* Change this to "#define TRACE(x) x" for some traces. */
+#define TRACE(x)
+
+
+/* fat_entry.asm */
+long __gmpn_cpuid (char [12], int);
+
+
+#if WANT_FAKE_CPUID
+/* The "name"s in the table are values for the GMP_CPU_TYPE environment
+   variable.  Anything can be used, but for now it's the canonical cpu types
+   as per config.guess/config.sub.  */
+
+#define __gmpn_cpuid            fake_cpuid
+
+#define MAKE_FMS(family, model)						\
+  ((((family) & 0xf) << 8) + (((family) & 0xff0) << 20)			\
+   + (((model) & 0xf) << 4) + (((model)  &  0xf0) << 12))
+
+static struct {
+  const char  *name;
+  const char  *vendor;
+  unsigned    fms;
+} fake_cpuid_table[] = {
+  { "core2",      "GenuineIntel", MAKE_FMS (6, 0xf) },
+  { "nehalem",    "GenuineIntel", MAKE_FMS (6, 0x1a) },
+  { "nhm",        "GenuineIntel", MAKE_FMS (6, 0x1a) },
+  { "atom",       "GenuineIntel", MAKE_FMS (6, 0x1c) },
+  { "westmere",   "GenuineIntel", MAKE_FMS (6, 0x25) },
+  { "wsm",        "GenuineIntel", MAKE_FMS (6, 0x25) },
+  { "sandybridge","GenuineIntel", MAKE_FMS (6, 0x2a) },
+  { "sbr",        "GenuineIntel", MAKE_FMS (6, 0x2a) },
+  { "silvermont", "GenuineIntel", MAKE_FMS (6, 0x37) },
+  { "slm",        "GenuineIntel", MAKE_FMS (6, 0x37) },
+  { "haswell",    "GenuineIntel", MAKE_FMS (6, 0x3c) },
+  { "hwl",        "GenuineIntel", MAKE_FMS (6, 0x3c) },
+  { "broadwell",  "GenuineIntel", MAKE_FMS (6, 0x3d) },
+  { "bwl",        "GenuineIntel", MAKE_FMS (6, 0x3d) },
+  { "skylake",    "GenuineIntel", MAKE_FMS (6, 0x5e) },
+  { "sky",        "GenuineIntel", MAKE_FMS (6, 0x5e) },
+  { "pentium4",   "GenuineIntel", MAKE_FMS (15, 3) },
+
+  { "k8",         "AuthenticAMD", MAKE_FMS (15, 0) },
+  { "k10",        "AuthenticAMD", MAKE_FMS (16, 0) },
+  { "bobcat",     "AuthenticAMD", MAKE_FMS (20, 1) },
+  { "bulldozer",  "AuthenticAMD", MAKE_FMS (21, 1) },
+  { "piledriver", "AuthenticAMD", MAKE_FMS (21, 2) },
+  { "steamroller","AuthenticAMD", MAKE_FMS (21, 0x30) },
+  { "excavator",  "AuthenticAMD", MAKE_FMS (21, 0x60) },
+  { "jaguar",     "AuthenticAMD", MAKE_FMS (22, 1) },
+  { "zen",        "AuthenticAMD", MAKE_FMS (23, 1) },
+
+  { "nano",       "CentaurHauls", MAKE_FMS (6, 15) },
+};
+
+static int
+fake_cpuid_lookup (void)
+{
+  char  *s;
+  int   i;
+
+  s = getenv ("GMP_CPU_TYPE");
+  if (s == NULL)
+    {
+      printf ("Need GMP_CPU_TYPE environment variable for fake cpuid\n");
+      abort ();
+    }
+
+  for (i = 0; i < numberof (fake_cpuid_table); i++)
+    if (strcmp (s, fake_cpuid_table[i].name) == 0)
+      return i;
+
+  printf ("GMP_CPU_TYPE=%s unknown\n", s);
+  abort ();
+}
+
+static long
+fake_cpuid (char dst[12], unsigned int id)
+{
+  int  i = fake_cpuid_lookup();
+
+  switch (id) {
+  case 0:
+    memcpy (dst, fake_cpuid_table[i].vendor, 12);
+    return 0;
+  case 1:
+    return fake_cpuid_table[i].fms;
+  case 7:
+    dst[0] = 0xff;				/* BMI1, AVX2, etc */
+    dst[1] = 0xff;				/* BMI2, etc */
+    return 0;
+  case 0x80000001:
+    dst[4 + 29 / 8] = (1 << (29 % 8));		/* "long" mode */
+    return 0;
+  default:
+    printf ("fake_cpuid(): oops, unknown id %d\n", id);
+    abort ();
+  }
+}
+#endif
+
+
+typedef DECL_preinv_divrem_1 ((*preinv_divrem_1_t));
+typedef DECL_preinv_mod_1    ((*preinv_mod_1_t));
+
+struct cpuvec_t __gmpn_cpuvec = {
+  __MPN(add_n_init),
+  __MPN(addlsh1_n_init),
+  __MPN(addlsh2_n_init),
+  __MPN(addmul_1_init),
+  __MPN(addmul_2_init),
+  __MPN(bdiv_dbm1c_init),
+  __MPN(cnd_add_n_init),
+  __MPN(cnd_sub_n_init),
+  __MPN(com_init),
+  __MPN(copyd_init),
+  __MPN(copyi_init),
+  __MPN(divexact_1_init),
+  __MPN(divrem_1_init),
+  __MPN(gcd_11_init),
+  __MPN(lshift_init),
+  __MPN(lshiftc_init),
+  __MPN(mod_1_init),
+  __MPN(mod_1_1p_init),
+  __MPN(mod_1_1p_cps_init),
+  __MPN(mod_1s_2p_init),
+  __MPN(mod_1s_2p_cps_init),
+  __MPN(mod_1s_4p_init),
+  __MPN(mod_1s_4p_cps_init),
+  __MPN(mod_34lsub1_init),
+  __MPN(modexact_1c_odd_init),
+  __MPN(mul_1_init),
+  __MPN(mul_basecase_init),
+  __MPN(mullo_basecase_init),
+  __MPN(preinv_divrem_1_init),
+  __MPN(preinv_mod_1_init),
+  __MPN(redc_1_init),
+  __MPN(redc_2_init),
+  __MPN(rshift_init),
+  __MPN(sqr_basecase_init),
+  __MPN(sub_n_init),
+  __MPN(sublsh1_n_init),
+  __MPN(submul_1_init),
+  0
+};
+
+int __gmpn_cpuvec_initialized = 0;
+
+/* The following setups start with generic x86, then overwrite with
+   specifics for a chip, and higher versions of that chip.
+
+   The arrangement of the setups here will normally be the same as the $path
+   selections in configure.in for the respective chips.
+
+   This code is reentrant and thread safe.  We always calculate the same
+   decided_cpuvec, so if two copies of the code are running it doesn't
+   matter which completes first, both write the same to __gmpn_cpuvec.
+
+   We need to go via decided_cpuvec because if one thread has completed
+   __gmpn_cpuvec then it may be making use of the threshold values in that
+   vector.  If another thread is still running __gmpn_cpuvec_init then we
+   don't want it to write different values to those fields since some of the
+   asm routines only operate correctly up to their own defined threshold,
+   not an arbitrary value.  */
+
+static int
+gmp_workaround_skylake_cpuid_bug ()
+{
+  char feature_string[49];
+  char processor_name_string[49];
+  static const char *bad_cpus[] = {" G44", " G45", " G39" /* , "6600" */ };
+  int i;
+
+  /* Example strings:                                   */
+  /* "Intel(R) Pentium(R) CPU G4400 @ 3.30GHz"          */
+  /* "Intel(R) Core(TM) i5-6600K CPU @ 3.50GHz"         */
+  /*                  ^               ^               ^ */
+  /*     0x80000002       0x80000003      0x80000004    */
+  /* We match out just the 0x80000003 part here. */
+
+  /* In their infinitive wisdom, Intel decided to use one register order for
+     the vendor string, and another for the processor name string.  We shuffle
+     things about here, rather than write a new variant of our assembly cpuid.
+  */
+
+  unsigned int eax, ebx, ecx, edx;
+  eax = __gmpn_cpuid (feature_string, 0x80000003);
+  ebx = ((unsigned int *)feature_string)[0];
+  edx = ((unsigned int *)feature_string)[1];
+  ecx = ((unsigned int *)feature_string)[2];
+
+  ((unsigned int *) (processor_name_string))[0] = eax;
+  ((unsigned int *) (processor_name_string))[1] = ebx;
+  ((unsigned int *) (processor_name_string))[2] = ecx;
+  ((unsigned int *) (processor_name_string))[3] = edx;
+
+  processor_name_string[16] = 0;
+
+  for (i = 0; i < sizeof (bad_cpus) / sizeof (char *); i++)
+    {
+      if (strstr (processor_name_string, bad_cpus[i]) != 0)
+	return 1;
+    }
+  return 0;
+}
+
+enum {BMI2_BIT = 8};
+
+void
+__gmpn_cpuvec_init (void)
+{
+  struct cpuvec_t  decided_cpuvec;
+  char vendor_string[13];
+  char dummy_string[12];
+  long fms;
+  int family, model;
+
+  TRACE (printf ("__gmpn_cpuvec_init:\n"));
+
+  memset (&decided_cpuvec, '\0', sizeof (decided_cpuvec));
+
+  CPUVEC_SETUP_x86_64;
+  CPUVEC_SETUP_fat;
+
+  __gmpn_cpuid (vendor_string, 0);
+  vendor_string[12] = 0;
+
+  fms = __gmpn_cpuid (dummy_string, 1);
+  family = ((fms >> 8) & 0xf) + ((fms >> 20) & 0xff);
+  model = ((fms >> 4) & 0xf) + ((fms >> 12) & 0xf0);
+
+  /* Check extended feature flags */
+  __gmpn_cpuid (dummy_string, 0x80000001);
+  if ((dummy_string[4 + 29 / 8] & (1 << (29 % 8))) == 0)
+    abort (); /* longmode-capable-bit turned off! */
+
+  /*********************************************************/
+  /*** WARNING: keep this list in sync with config.guess ***/
+  /*********************************************************/
+  if (strcmp (vendor_string, "GenuineIntel") == 0)
+    {
+      switch (family)
+	{
+	case 6:
+	  switch (model)
+	    {
+	    case 0x0f:		/* Conroe Merom Kentsfield Allendale */
+	    case 0x10:
+	    case 0x11:
+	    case 0x12:
+	    case 0x13:
+	    case 0x14:
+	    case 0x15:
+	    case 0x16:
+	    case 0x17:		/* PNR Wolfdale Yorkfield */
+	    case 0x18:
+	    case 0x19:
+	    case 0x1d:		/* PNR Dunnington */
+	      CPUVEC_SETUP_core2;
+	      break;
+
+	    case 0x1c:		/* Atom Silverthorne */
+	    case 0x26:		/* Atom Lincroft */
+	    case 0x27:		/* Atom Saltwell? */
+	    case 0x36:		/* Atom Cedarview/Saltwell */
+	      CPUVEC_SETUP_atom;
+	      break;
+
+	    case 0x1a:		/* NHM Gainestown */
+	    case 0x1b:
+	    case 0x1e:		/* NHM Lynnfield/Jasper */
+	    case 0x1f:
+	    case 0x20:
+	    case 0x21:
+	    case 0x22:
+	    case 0x23:
+	    case 0x24:
+	    case 0x25:		/* WSM Clarkdale/Arrandale */
+	    case 0x28:
+	    case 0x29:
+	    case 0x2b:
+	    case 0x2c:		/* WSM Gulftown */
+	    case 0x2e:		/* NHM Beckton */
+	    case 0x2f:		/* WSM Eagleton */
+	      CPUVEC_SETUP_core2;
+	      CPUVEC_SETUP_coreinhm;
+	      break;
+
+	    case 0x37:		/* Silvermont */
+	    case 0x4a:		/* Silvermont */
+	    case 0x4c:		/* Airmont */
+	    case 0x4d:		/* Silvermont/Avoton */
+	    case 0x5a:		/* Silvermont */
+	      CPUVEC_SETUP_atom;
+	      CPUVEC_SETUP_silvermont;
+	      break;
+
+	    case 0x5c:		/* Goldmont */
+	    case 0x5f:		/* Goldmont */
+	    case 0x7a:		/* Goldmont Plus */
+	      CPUVEC_SETUP_atom;
+	      CPUVEC_SETUP_silvermont;
+	      CPUVEC_SETUP_goldmont;
+	      break;
+
+	    case 0x2a:		/* SB */
+	    case 0x2d:		/* SBC-EP */
+	    case 0x3a:		/* IBR */
+	    case 0x3e:		/* IBR Ivytown */
+	      CPUVEC_SETUP_core2;
+	      CPUVEC_SETUP_coreinhm;
+	      CPUVEC_SETUP_coreisbr;
+	      break;
+	    case 0x3c:		/* Haswell client */
+	    case 0x3f:		/* Haswell server */
+	    case 0x45:		/* Haswell ULT */
+	    case 0x46:		/* Crystal Well */
+	      CPUVEC_SETUP_core2;
+	      CPUVEC_SETUP_coreinhm;
+	      CPUVEC_SETUP_coreisbr;
+	      /* Some Haswells lack BMI2.  Let them appear as Sandybridges for
+		 now.  */
+	      __gmpn_cpuid (dummy_string, 7);
+	      if ((dummy_string[0 + BMI2_BIT / 8] & (1 << (BMI2_BIT % 8))) == 0)
+		break;
+	      CPUVEC_SETUP_coreihwl;
+	      break;
+	    case 0x3d:		/* Broadwell */
+	    case 0x47:		/* Broadwell */
+	    case 0x4f:		/* Broadwell server */
+	    case 0x56:		/* Broadwell microserver */
+	      CPUVEC_SETUP_core2;
+	      CPUVEC_SETUP_coreinhm;
+	      CPUVEC_SETUP_coreisbr;
+	      if ((dummy_string[0 + BMI2_BIT / 8] & (1 << (BMI2_BIT % 8))) == 0)
+		break;
+	      CPUVEC_SETUP_coreihwl;
+	      CPUVEC_SETUP_coreibwl;
+	      break;
+	    case 0x4e:		/* Skylake client */
+	    case 0x55:		/* Skylake server */
+	    case 0x5e:		/* Skylake */
+	    case 0x8e:		/* Kabylake */
+	    case 0x9e:		/* Kabylake */
+	      CPUVEC_SETUP_core2;
+	      CPUVEC_SETUP_coreinhm;
+	      CPUVEC_SETUP_coreisbr;
+	      if ((dummy_string[0 + BMI2_BIT / 8] & (1 << (BMI2_BIT % 8))) == 0)
+		break;
+	      if (gmp_workaround_skylake_cpuid_bug ())
+		break;
+	      CPUVEC_SETUP_coreihwl;
+	      CPUVEC_SETUP_coreibwl;
+	      CPUVEC_SETUP_skylake;
+	      break;
+	    }
+	  break;
+
+	case 15:
+	  CPUVEC_SETUP_pentium4;
+	  break;
+	}
+    }
+  else if (strcmp (vendor_string, "AuthenticAMD") == 0)
+    {
+      switch (family)
+	{
+	case 0x0f:		/* k8 */
+	case 0x11:		/* "fam 11h", mix of k8 and k10 */
+	case 0x13:
+	  CPUVEC_SETUP_k8;
+	  break;
+
+	case 0x10:		/* k10 */
+	case 0x12:		/* k10 (llano) */
+	  CPUVEC_SETUP_k8;
+	  CPUVEC_SETUP_k10;
+	  break;
+
+	case 0x14:		/* bobcat */
+	  CPUVEC_SETUP_k8;
+	  CPUVEC_SETUP_k10;
+	  CPUVEC_SETUP_bt1;
+	  break;
+
+	case 0x16:		/* jaguar */
+	  CPUVEC_SETUP_k8;
+	  CPUVEC_SETUP_k10;
+	  CPUVEC_SETUP_bt1;
+	  CPUVEC_SETUP_bt2;
+	  break;
+
+	case 0x15:	    /* bulldozer, piledriver, steamroller, excavator */
+	  CPUVEC_SETUP_k8;
+	  CPUVEC_SETUP_k10;
+	  CPUVEC_SETUP_bd1;
+	  break;
+
+	case 0x17:	    /* zen */
+	  CPUVEC_SETUP_zen;
+	  break;
+	}
+    }
+  else if (strcmp (vendor_string, "CentaurHauls") == 0)
+    {
+      switch (family)
+	{
+	case 6:
+	  if (model >= 15)
+	    CPUVEC_SETUP_nano;
+	  break;
+	}
+    }
+
+  /* There's no x86 generic mpn_preinv_divrem_1 or mpn_preinv_mod_1.
+     Instead default to the plain versions from whichever CPU we detected.
+     The function arguments are compatible, no need for any glue code.  */
+  if (decided_cpuvec.preinv_divrem_1 == NULL)
+    decided_cpuvec.preinv_divrem_1 =(preinv_divrem_1_t)decided_cpuvec.divrem_1;
+  if (decided_cpuvec.preinv_mod_1 == NULL)
+    decided_cpuvec.preinv_mod_1    =(preinv_mod_1_t)   decided_cpuvec.mod_1;
+
+  ASSERT_CPUVEC (decided_cpuvec);
+  CPUVEC_INSTALL (decided_cpuvec);
+
+  /* Set this once the threshold fields are ready.
+     Use volatile to prevent it getting moved.  */
+  *((volatile int *) &__gmpn_cpuvec_initialized) = 1;
+}
diff --git a/third_party/gmp/mpn/x86_64/fat/fat_entry.asm b/third_party/gmp/mpn/x86_64/fat/fat_entry.asm
new file mode 100644
index 0000000..5f244ac
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/fat/fat_entry.asm
@@ -0,0 +1,209 @@
+dnl  x86 fat binary entrypoints.
+
+dnl  Contributed to the GNU project by Kevin Ryde (original x86_32 code) and
+dnl  Torbjorn Granlund (port to x86_64)
+
+dnl  Copyright 2003, 2009, 2011-2014, 2016 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+dnl  Forcibly disable profiling.
+dnl
+dnl  The entrypoints and inits are small enough not to worry about, the real
+dnl  routines arrived at will have any profiling.  Also, the way the code
+dnl  here ends with a jump means we won't work properly with the
+dnl  "instrument" profiling scheme anyway.
+
+define(`WANT_PROFILING',no)
+
+
+dnl  We define PRETEND_PIC as a helper symbol, the use it for suppressing
+dnl  normal, fast call code, since that triggers problems on Darwin, OpenBSD
+dnl  and some versions of GNU/Linux.  This will go away when symbol hiding is
+dnl  finished.
+
+ifdef(`DARWIN',
+`define(`PRETEND_PIC')')
+ifdef(`OPENBSD',
+`define(`PRETEND_PIC')')
+ifdef(`LINUX',
+`define(`PRETEND_PIC')')
+ifdef(`PIC',
+`define(`PRETEND_PIC')')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+	TEXT
+
+dnl  Usage: FAT_ENTRY(name, offset)
+dnl
+dnl  Emit a fat binary entrypoint function of the given name.  This is the
+dnl  normal entry for applications, eg. __gmpn_add_n.
+dnl
+dnl  The code simply jumps through the function pointer in __gmpn_cpuvec at
+dnl  the given "offset" (in bytes).
+dnl
+dnl  For non-PIC, the jumps are 5 bytes each, aligning them to 8 should be
+dnl  fine for all x86s.
+dnl
+dnl  For ELF/DARWIN PIC, the jumps are 20 bytes each, and are best aligned to
+dnl  16 to ensure at least the first two instructions don't cross a cache line
+dnl  boundary.
+dnl
+dnl  For DOS64, the jumps are 6 bytes.  The same form works also for GNU/Linux
+dnl  (at least with certain assembler/linkers) but FreeBSD 8.2 crashes.  Not
+dnl  tested on Darwin, Slowaris, NetBSD, etc.
+dnl
+dnl  Note the extra `' ahead of PROLOGUE obscures it from the HAVE_NATIVE
+dnl  grepping in configure, stopping that code trying to eval something with
+dnl  $1 in it.
+
+define(FAT_ENTRY,
+m4_assert_numargs(2)
+`ifdef(`HOST_DOS64',
+`	ALIGN(8)
+`'PROLOGUE($1)
+	jmp	*$2+GSYM_PREFIX`'__gmpn_cpuvec(%rip)
+EPILOGUE()
+',
+`	ALIGN(ifdef(`PIC',16,8))
+`'PROLOGUE($1)
+ifdef(`PRETEND_PIC',
+`	LEA(	GSYM_PREFIX`'__gmpn_cpuvec, %rax)
+	jmp	*$2(%rax)
+',`dnl non-PIC
+	jmp	*GSYM_PREFIX`'__gmpn_cpuvec+$2
+')
+EPILOGUE()
+')')
+
+
+dnl  FAT_ENTRY for each CPUVEC_FUNCS_LIST
+dnl
+
+define(`CPUVEC_offset',0)
+foreach(i,
+`FAT_ENTRY(MPN(i),CPUVEC_offset)
+define(`CPUVEC_offset',eval(CPUVEC_offset + 8))',
+CPUVEC_FUNCS_LIST)
+
+
+dnl  Usage: FAT_INIT(name, offset)
+dnl
+dnl  Emit a fat binary initializer function of the given name.  These
+dnl  functions are the initial values for the pointers in __gmpn_cpuvec.
+dnl
+dnl  The code simply calls __gmpn_cpuvec_init, and then jumps back through
+dnl  the __gmpn_cpuvec pointer, at the given "offset" (in bytes).
+dnl  __gmpn_cpuvec_init will have stored the address of the selected
+dnl  implementation there.
+dnl
+dnl  Only one of these routines will be executed, and only once, since after
+dnl  that all the __gmpn_cpuvec pointers go to real routines.  So there's no
+dnl  need for anything special here, just something small and simple.  To
+dnl  keep code size down, "fat_init" is a shared bit of code, arrived at
+dnl  with the offset in %al.  %al is used since the movb instruction is 2
+dnl  bytes where %eax would be 4.
+dnl
+dnl  Note having `PROLOGUE in FAT_INIT obscures that PROLOGUE from the
+dnl  HAVE_NATIVE grepping in configure, preventing that code trying to eval
+dnl  something with $1 in it.
+dnl
+dnl  We need to preserve parameter registers over the __gmpn_cpuvec_init call
+
+define(FAT_INIT,
+m4_assert_numargs(2)
+`PROLOGUE($1)
+	mov	$`'$2, %al
+	jmp	L(fat_init)
+EPILOGUE()
+')
+
+dnl  FAT_INIT for each CPUVEC_FUNCS_LIST
+dnl
+
+define(`CPUVEC_offset',0)
+foreach(i,
+`FAT_INIT(MPN(i`'_init),CPUVEC_offset)
+define(`CPUVEC_offset',eval(CPUVEC_offset + 1))',
+CPUVEC_FUNCS_LIST)
+
+L(fat_init):
+	C al	__gmpn_cpuvec byte offset
+
+	movzbl	%al, %eax
+IFSTD(`	push	%rdi	')
+IFSTD(`	push	%rsi	')
+	push	%rdx
+	push	%rcx
+	push	%r8
+	push	%r9
+	push	%rax
+IFDOS(`	sub	$32, %rsp	')
+	CALL(	__gmpn_cpuvec_init)
+IFDOS(`	add	$32, %rsp	')
+	pop	%rax
+	pop	%r9
+	pop	%r8
+	pop	%rcx
+	pop	%rdx
+IFSTD(`	pop	%rsi	')
+IFSTD(`	pop	%rdi	')
+ifdef(`PRETEND_PIC',`
+	LEA(	GSYM_PREFIX`'__gmpn_cpuvec, %r10)
+	jmp	*(%r10,%rax,8)
+',`dnl non-PIC
+	jmp	*GSYM_PREFIX`'__gmpn_cpuvec(,%rax,8)
+')
+
+
+C long __gmpn_cpuid (char dst[12], int id);
+C
+C This is called only 3 times, so just something simple and compact is fine.
+C
+C The rcx/ecx zeroing here is needed for the BMI2 check.
+
+define(`rp',  `%rdi')
+define(`idx', `%rsi')
+
+PROLOGUE(__gmpn_cpuid)
+	FUNC_ENTRY(2)
+	mov	%rbx, %r8
+	mov	R32(idx), R32(%rax)
+	xor	%ecx, %ecx
+	cpuid
+	mov	%ebx, (rp)
+	mov	%edx, 4(rp)
+	mov	%ecx, 8(rp)
+	mov	%r8, %rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/fat/gmp-mparam.h b/third_party/gmp/mpn/x86_64/fat/gmp-mparam.h
new file mode 100644
index 0000000..005c893
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/fat/gmp-mparam.h
@@ -0,0 +1,72 @@
+/* Fat binary x86_64 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 2000-2003, 2009, 2011 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+
+/* mpn_divexact_1 is faster than mpn_divrem_1 at all sizes.  The only time
+   this might not be true currently is for actual 80386 and 80486 chips,
+   where mpn/x86/dive_1.asm might be slower than mpn/x86/divrem_1.asm, but
+   that's not worth worrying about.  */
+#define DIVEXACT_1_THRESHOLD  0
+
+/* Only some of the x86s have an mpn_preinv_divrem_1, but we set
+   USE_PREINV_DIVREM_1 so that all callers use it, and then let the
+   __gmpn_cpuvec pointer go to plain mpn_divrem_1 if there's not an actual
+   preinv.  */
+#define USE_PREINV_DIVREM_1   1
+
+#define BMOD_1_TO_MOD_1_THRESHOLD           20
+
+/* mpn_sqr_basecase is faster than mpn_mul_basecase at all sizes, no need
+   for mpn_sqr to call the latter.  */
+#define SQR_BASECASE_THRESHOLD 0
+
+/* Sensible fallbacks for these, when not taken from a cpu-specific
+   gmp-mparam.h.  */
+#define MUL_TOOM22_THRESHOLD      20
+#define MUL_TOOM33_THRESHOLD     130
+#define SQR_TOOM2_THRESHOLD       30
+#define SQR_TOOM3_THRESHOLD      200
+
+/* These are values more or less in the middle of what the typical x86 chips
+   come out as.  For a fat binary it's necessary to have values for these,
+   since the defaults for MUL_FFT_TABLE and SQR_FFT_TABLE otherwise come out
+   as non-constant array initializers.  FIXME: Perhaps these should be done
+   in the cpuvec structure like other thresholds.  */
+#define MUL_FFT_TABLE  { 464, 928, 1920, 3584, 10240, 40960, 0 }
+#define MUL_FFT_MODF_THRESHOLD          400
+#define MUL_FFT_THRESHOLD              2000
+
+#define SQR_FFT_TABLE  { 528, 1184, 1920, 4608, 14336, 40960, 0 }
+#define SQR_FFT_MODF_THRESHOLD          500
+#define SQR_FFT_THRESHOLD              3000
diff --git a/third_party/gmp/mpn/x86_64/fat/mod_1.c b/third_party/gmp/mpn/x86_64/fat/mod_1.c
new file mode 100644
index 0000000..4f149cc
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/fat/mod_1.c
@@ -0,0 +1,32 @@
+/* Fat binary fallback mpn_mod_1.
+
+Copyright 2003, 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "mpn/generic/mod_1.c"
diff --git a/third_party/gmp/mpn/x86_64/fat/mul_basecase.c b/third_party/gmp/mpn/x86_64/fat/mul_basecase.c
new file mode 100644
index 0000000..d9eb471
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/fat/mul_basecase.c
@@ -0,0 +1,32 @@
+/* Fat binary fallback mpn_mul_basecase.
+
+Copyright 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "mpn/generic/mul_basecase.c"
diff --git a/third_party/gmp/mpn/x86_64/fat/mullo_basecase.c b/third_party/gmp/mpn/x86_64/fat/mullo_basecase.c
new file mode 100644
index 0000000..7f86be6
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/fat/mullo_basecase.c
@@ -0,0 +1,32 @@
+/* Fat binary fallback mpn_mullo_basecase.
+
+Copyright 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "mpn/generic/mullo_basecase.c"
diff --git a/third_party/gmp/mpn/x86_64/fat/redc_1.c b/third_party/gmp/mpn/x86_64/fat/redc_1.c
new file mode 100644
index 0000000..0025403
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/fat/redc_1.c
@@ -0,0 +1,32 @@
+/* Fat binary fallback mpn_redc_1.
+
+Copyright 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "mpn/generic/redc_1.c"
diff --git a/third_party/gmp/mpn/x86_64/fat/redc_2.c b/third_party/gmp/mpn/x86_64/fat/redc_2.c
new file mode 100644
index 0000000..1932d58
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/fat/redc_2.c
@@ -0,0 +1,32 @@
+/* Fat binary fallback mpn_redc_2.
+
+Copyright 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "mpn/generic/redc_2.c"
diff --git a/third_party/gmp/mpn/x86_64/fat/sqr_basecase.c b/third_party/gmp/mpn/x86_64/fat/sqr_basecase.c
new file mode 100644
index 0000000..d1c5dcd
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/fat/sqr_basecase.c
@@ -0,0 +1,32 @@
+/* Fat binary fallback mpn_sqr_basecase.
+
+Copyright 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "mpn/generic/sqr_basecase.c"
diff --git a/third_party/gmp/mpn/x86_64/gcd_11.asm b/third_party/gmp/mpn/x86_64/gcd_11.asm
new file mode 100644
index 0000000..f9b3bcc
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/gcd_11.asm
@@ -0,0 +1,114 @@
+dnl  AMD64 mpn_gcd_11 -- 1 x 1 gcd.
+
+dnl  Based on the K7 gcd_1.asm, by Kevin Ryde.  Rehacked for AMD64 by Torbjorn
+dnl  Granlund.
+
+dnl  Copyright 2000-2002, 2005, 2009, 2011, 2012, 2017 Free Software
+dnl  Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C	     cycles/bit
+C AMD K8,K9	 5.5
+C AMD K10	 ?
+C AMD bd1	 ?
+C AMD bd2	 ?
+C AMD bd3	 ?
+C AMD bd4	 ?
+C AMD bt1	 7.1
+C AMD bt2	 ?
+C AMD zn1	 ?
+C AMD zn2	 ?
+C Intel P4	 ?
+C Intel CNR	 ?
+C Intel PNR	 ?
+C Intel NHM	 ?
+C Intel WSM	 ?
+C Intel SBR	 ?
+C Intel IBR	 ?
+C Intel HWL	 ?
+C Intel BWL	 ?
+C Intel SKL	 ?
+C Intel atom	 9.1
+C Intel SLM	 6.9
+C Intel GLM	 6.0
+C Intel GLM+	 5.8
+C VIA nano	 ?
+
+
+C ctz_table[n] is the number of trailing zeros on n, or MAXSHIFT if n==0.
+
+deflit(MAXSHIFT, 7)
+deflit(MASK, eval((m4_lshift(1,MAXSHIFT))-1))
+
+DEF_OBJECT(ctz_table,64)
+	.byte	MAXSHIFT
+forloop(i,1,MASK,
+`	.byte	m4_count_trailing_zeros(i)
+')
+END_OBJECT(ctz_table)
+
+define(`u0',    `%rdi')
+define(`v0',    `%rsi')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(64)
+PROLOGUE(mpn_gcd_11)
+	FUNC_ENTRY(2)
+	LEA(	ctz_table, %r8)
+	jmp	L(ent)
+
+	ALIGN(16)
+L(top):	cmovc	%rdx, u0		C u = |u - v|
+	cmovc	%rax, v0		C v = min(u,v)
+L(mid):	and	$MASK, R32(%rdx)
+	movzbl	(%r8,%rdx), R32(%rcx)
+	jz	L(shift_alot)
+	shr	R8(%rcx), u0
+L(ent):	mov	u0, %rax
+	mov	v0, %rdx
+	sub	u0, %rdx
+	sub	v0, u0
+	jnz	L(top)
+
+L(end):	C rax = result
+	C rdx = 0 for the benefit of internal gcd_22 call
+	FUNC_EXIT()
+	ret
+
+L(shift_alot):
+	shr	$MAXSHIFT, u0
+	mov	u0, %rdx
+	jmp	L(mid)
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/gcd_22.asm b/third_party/gmp/mpn/x86_64/gcd_22.asm
new file mode 100644
index 0000000..78f985f
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/gcd_22.asm
@@ -0,0 +1,163 @@
+dnl  AMD64 mpn_gcd_22.  Assumes useless bsf, useless shrd, no tzcnt, no shlx.
+dnl  We actually use tzcnt here, when table cannot count bits, as tzcnt always
+dnl  works for our use, and helps a lot for certain CPUs.
+
+dnl  Copyright 2019 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C	     cycles/bit
+C AMD K8,K9	 8.9
+C AMD K10	 8.8
+C AMD bd1	 9.7
+C AMD bd2	 7.8
+C AMD bd3	 ?
+C AMD bd4	 7.4
+C AMD bt1	 9.2
+C AMD bt2	 9.1
+C AMD zn1	 7.5
+C AMD zn2	 7.5
+C Intel P4	 ?
+C Intel CNR	10.5
+C Intel PNR	10.5
+C Intel NHM	 9.7
+C Intel WSM	 9.7
+C Intel SBR	10.7
+C Intel IBR	 ?
+C Intel HWL	 9.5
+C Intel BWL	 8.7
+C Intel SKL	 8.6
+C Intel atom	18.9
+C Intel SLM	14.0
+C Intel GLM	 9.8
+C Intel GLM+	 8.8
+C VIA nano	 ?
+
+
+C ctz_table[n] is the number of trailing zeros on n, or MAXSHIFT if n==0.
+
+deflit(MAXSHIFT, 8)
+deflit(MASK, eval((m4_lshift(1,MAXSHIFT))-1))
+
+DEF_OBJECT(ctz_table,64)
+	.byte	MAXSHIFT
+forloop(i,1,MASK,
+`	.byte	m4_count_trailing_zeros(i)
+')
+END_OBJECT(ctz_table)
+
+define(`u1',    `%rdi')
+define(`u0',    `%rsi')
+define(`v1',    `%rdx')
+define(`v0_param', `%rcx')
+
+define(`v0',    `%rax')
+define(`cnt',   `%rcx')
+
+define(`s0',    `%r8')
+define(`s1',    `%r9')
+define(`t0',    `%rcx')
+define(`t1',    `%r11')
+
+dnl ABI_SUPPORT(DOS64)	C returns mp_double_limb_t in memory
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(64)
+PROLOGUE(mpn_gcd_22)
+	FUNC_ENTRY(4)
+	mov	v0_param, v0
+
+	LEA(	ctz_table, %r10)
+
+	ALIGN(16)
+L(top):	mov	v0, t0
+	sub	u0, t0
+	jz	L(lowz)		C	jump when low limb result = 0
+	mov	v1, t1
+	sbb	u1, t1
+
+	mov	u0, s0
+	mov	u1, s1
+
+	sub	v0, u0
+	sbb	v1, u1
+
+L(bck):	cmovc	t0, u0		C u = |u - v|
+	cmovc	t1, u1		C u = |u - v|
+	cmovc	s0, v0		C v = min(u,v)
+	cmovc	s1, v1		C v = min(u,v)
+
+	and	$MASK, R32(t0)
+	movzbl	(%r10,t0), R32(cnt)
+	jz	L(count_better)
+C Rightshift (u1,,u0) into (u1,,u0)
+L(shr):	shr	R8(cnt), u0
+	mov	u1, t1
+	shr	R8(cnt), u1
+	neg	cnt
+	shl	R8(cnt), t1
+	or	t1, u0
+
+	test	v1, v1
+	jnz	L(top)
+	test	u1, u1
+	jnz	L(top)
+
+L(gcd_11):
+	mov	v0, %rdi
+C	mov	u0, %rsi
+	TCALL(	mpn_gcd_11)
+
+L(count_better):
+	rep;bsf	u0, cnt		C tzcnt!
+	jmp	L(shr)
+
+L(lowz):C We come here when v0 - u0 = 0
+	C 1. If v1 - u1 = 0, then gcd is u = v.
+	C 2. Else compute gcd_21({v1,v0}, |u1-v1|)
+	mov	v1, t0
+	sub	u1, t0
+	je	L(end)
+
+	xor	t1, t1
+	mov	u0, s0
+	mov	u1, s1
+	mov	u1, u0
+	xor	u1, u1
+	sub	v1, u0
+	jmp	L(bck)
+
+L(end):	C mov	v0, %rax
+	C mov	v1, %rdx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/gmp-mparam.h b/third_party/gmp/mpn/x86_64/gmp-mparam.h
new file mode 100644
index 0000000..db94fb7
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/gmp-mparam.h
@@ -0,0 +1,217 @@
+/* AMD K8-K10 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 2000-2010, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          4
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          3
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        14
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        28
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD      7
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           15
+
+#define MUL_TOOM22_THRESHOLD                27
+#define MUL_TOOM33_THRESHOLD                81
+#define MUL_TOOM44_THRESHOLD               234
+#define MUL_TOOM6H_THRESHOLD               418
+#define MUL_TOOM8H_THRESHOLD               466
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      97
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     160
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     145
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     175
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 36
+#define SQR_TOOM3_THRESHOLD                117
+#define SQR_TOOM4_THRESHOLD                327
+#define SQR_TOOM6_THRESHOLD                446
+#define SQR_TOOM8_THRESHOLD                547
+
+#define MULMID_TOOM42_THRESHOLD             36
+
+#define MULMOD_BNM1_THRESHOLD               17
+#define SQRMOD_BNM1_THRESHOLD               17
+
+#define POWM_SEC_TABLE  2,67,322,991
+
+#define MUL_FFT_MODF_THRESHOLD             570  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    570, 5}, {     21, 6}, {     11, 5}, {     23, 6}, \
+    {     25, 7}, {     13, 6}, {     27, 7}, {     15, 6}, \
+    {     31, 7}, {     25, 8}, {     13, 7}, {     29, 8}, \
+    {     15, 7}, {     31, 8}, {     17, 7}, {     35, 8}, \
+    {     19, 7}, {     39, 8}, {     21, 7}, {     43, 8}, \
+    {     23, 7}, {     47, 8}, {     25, 7}, {     51, 8}, \
+    {     29, 9}, {     15, 8}, {     37, 9}, {     19, 8}, \
+    {     43, 9}, {     23, 8}, {     51, 9}, {     27, 8}, \
+    {     55,10}, {     15, 9}, {     43,10}, {     23, 9}, \
+    {     55,10}, {     31, 9}, {     63, 5}, {   1023, 4}, \
+    {   2431, 5}, {   1279, 6}, {    671, 7}, {    367, 8}, \
+    {    189, 9}, {     95, 8}, {    195, 9}, {    111,11}, \
+    {     31, 9}, {    131,10}, {     71, 9}, {    155,10}, \
+    {     79, 9}, {    159,10}, {     87,11}, {     47,10}, \
+    {    111,11}, {     63,10}, {    135,11}, {     79,10}, \
+    {    167,11}, {     95,10}, {    191,11}, {    111,12}, \
+    {     63,11}, {    143,10}, {    287,11}, {    159,10}, \
+    {    319,11}, {    175,12}, {     95,11}, {    207,13}, \
+    {     63,12}, {    127,11}, {    255,10}, {    543,11}, \
+    {    287,12}, {    159,11}, {    319,10}, {    639,11}, \
+    {    335,10}, {    671,11}, {    351,10}, {    703,12}, \
+    {    191,11}, {    383,10}, {    767,11}, {    415,12}, \
+    {    223,13}, {    127,12}, {    255,11}, {    543,12}, \
+    {    287,11}, {    575,10}, {   1151,11}, {    607,12}, \
+    {    319,11}, {    639,10}, {   1279,11}, {    671,12}, \
+    {    351,11}, {    703,13}, {    191,12}, {    383,11}, \
+    {    767,12}, {    415,11}, {    831,12}, {    447,14}, \
+    {    127,13}, {    255,12}, {    543,11}, {   1087,12}, \
+    {    607,11}, {   1215,13}, {    319,12}, {    671,11}, \
+    {   1343,12}, {    735,13}, {    383,12}, {    767,11}, \
+    {   1535,12}, {    799,11}, {   1599,12}, {    831,13}, \
+    {    447,12}, {    895,11}, {   1791,12}, {    959,14}, \
+    {    255,13}, {    511,12}, {   1087,13}, {    575,12}, \
+    {   1215,13}, {    639,12}, {   1343,13}, {    703,12}, \
+    {   1407,14}, {    383,13}, {    767,12}, {   1599,13}, \
+    {    831,12}, {   1663,13}, {    895,12}, {   1791,13}, \
+    {    959,15}, {    255,14}, {    511,13}, {   1087,12}, \
+    {   2175,13}, {   1215,14}, {    639,13}, {   1471,14}, \
+    {    767,13}, {   1663,14}, {    895,13}, {   1855,15}, \
+    {    511,14}, {   1023,13}, {   2175,14}, {   1151,13}, \
+    {   2431,14}, {   1279,13}, {   2687,14}, {   1407,15}, \
+    {    767,14}, {   1535,13}, {   3071,14}, {   1791,16}, \
+    {    511,15}, {   1023,14}, {   2431,15}, {   1279,14}, \
+    {   2815,15}, {   1535,14}, {   3199,15}, {   1791,14}, \
+    {   3583,16}, {  65536,17}, { 131072,18}, { 262144,19}, \
+    { 524288,20}, {1048576,21}, {2097152,22}, {4194304,23}, \
+    {8388608,24} }
+#define MUL_FFT_TABLE3_SIZE 185
+#define MUL_FFT_THRESHOLD                 7552
+
+#define SQR_FFT_MODF_THRESHOLD             460  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    460, 5}, {     21, 6}, {     11, 5}, {     23, 6}, \
+    {     12, 5}, {     25, 6}, {     27, 7}, {     14, 6}, \
+    {     29, 7}, {     15, 6}, {     31, 7}, {     29, 8}, \
+    {     15, 7}, {     32, 8}, {     17, 7}, {     35, 8}, \
+    {     19, 7}, {     39, 8}, {     21, 7}, {     43, 8}, \
+    {     25, 7}, {     51, 8}, {     29, 9}, {     15, 8}, \
+    {     35, 9}, {     19, 8}, {     43, 9}, {     23, 8}, \
+    {     51, 9}, {     27, 8}, {     55,10}, {     15, 9}, \
+    {     31, 8}, {     63, 9}, {     43,10}, {     23, 9}, \
+    {     55,11}, {     15,10}, {     31, 9}, {     71,10}, \
+    {     39, 9}, {     83,10}, {     47, 6}, {    767, 4}, \
+    {   3263, 5}, {   1727, 4}, {   3455, 5}, {   1791, 6}, \
+    {    927, 7}, {    479, 6}, {    959, 7}, {    511, 8}, \
+    {    271, 9}, {    147,10}, {     87,11}, {     47,10}, \
+    {     95,12}, {     31,11}, {     63,10}, {    135,11}, \
+    {     79,10}, {    167,11}, {     95,10}, {    191,11}, \
+    {    111,12}, {     63,11}, {    127,10}, {    255,11}, \
+    {    143,10}, {    287, 9}, {    575,10}, {    303,11}, \
+    {    159,12}, {     95,11}, {    191,10}, {    383, 9}, \
+    {    767,10}, {    399,11}, {    207,13}, {     63,12}, \
+    {    127,11}, {    255,10}, {    511,11}, {    271,10}, \
+    {    543,11}, {    287,10}, {    575,12}, {    159,11}, \
+    {    319,10}, {    639,11}, {    335,10}, {    671,11}, \
+    {    351,10}, {    703,12}, {    191,11}, {    383,10}, \
+    {    767,11}, {    415,10}, {    831,11}, {    447,13}, \
+    {    127,12}, {    255,11}, {    511,10}, {   1023,11}, \
+    {    543,12}, {    287,11}, {    575,10}, {   1151,11}, \
+    {    607,10}, {   1215,12}, {    319,11}, {    639,10}, \
+    {   1279,11}, {    671,12}, {    351,11}, {    703,13}, \
+    {    191,12}, {    383,11}, {    767,12}, {    415,11}, \
+    {    831,12}, {    447,14}, {    127,13}, {    255,12}, \
+    {    511,11}, {   1023,12}, {    543,11}, {   1087,12}, \
+    {    575,11}, {   1151,12}, {    607,13}, {    319,12}, \
+    {    639,11}, {   1279,12}, {    671,11}, {   1343,12}, \
+    {    703,11}, {   1407,12}, {    735,13}, {    383,12}, \
+    {    767,11}, {   1535,12}, {    799,11}, {   1599,12}, \
+    {    831,13}, {    447,12}, {    959,14}, {    255,13}, \
+    {    511,12}, {   1087,13}, {    575,12}, {   1215,13}, \
+    {    639,12}, {   1343,13}, {    703,12}, {   1407,14}, \
+    {    383,13}, {    767,12}, {   1599,13}, {    831,12}, \
+    {   1663,13}, {    895,12}, {   1791,13}, {    959,15}, \
+    {    255,14}, {    511,13}, {   1087,12}, {   2175,13}, \
+    {   1215,14}, {    639,13}, {   1471,14}, {    767,13}, \
+    {   1663,14}, {    895,13}, {   1855,15}, {    511,14}, \
+    {   1023,13}, {   2175,14}, {   1151,13}, {   2303,14}, \
+    {   1279,13}, {   2559,14}, {   1407,15}, {    767,14}, \
+    {   1535,13}, {   3071,14}, {   1791,16}, {    511,15}, \
+    {   1023,14}, {   2303,15}, {   1279,14}, {   2687,15}, \
+    {   1535,14}, {   3199,15}, {   1791,16}, {  65536,17}, \
+    { 131072,18}, { 262144,19}, { 524288,20}, {1048576,21}, \
+    {2097152,22}, {4194304,23}, {8388608,24} }
+#define SQR_FFT_TABLE3_SIZE 203
+#define SQR_FFT_THRESHOLD                 5248
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  35
+#define MULLO_MUL_N_THRESHOLD            15604
+
+#define DC_DIV_QR_THRESHOLD                 56
+#define DC_DIVAPPR_Q_THRESHOLD             220
+#define DC_BDIV_QR_THRESHOLD                52
+#define DC_BDIV_Q_THRESHOLD                152
+
+#define INV_MULMOD_BNM1_THRESHOLD           54
+#define INV_NEWTON_THRESHOLD               226
+#define INV_APPR_THRESHOLD                 214
+
+#define BINV_NEWTON_THRESHOLD              327
+#define REDC_1_TO_REDC_2_THRESHOLD           4
+#define REDC_2_TO_REDC_N_THRESHOLD          79
+
+#define MU_DIV_QR_THRESHOLD               1895
+#define MU_DIVAPPR_Q_THRESHOLD            1895
+#define MUPI_DIV_QR_THRESHOLD              106
+#define MU_BDIV_QR_THRESHOLD              1589
+#define MU_BDIV_Q_THRESHOLD               1718
+
+#define MATRIX22_STRASSEN_THRESHOLD         16
+#define HGCD_THRESHOLD                     125
+#define HGCD_APPR_THRESHOLD                173
+#define HGCD_REDUCE_THRESHOLD             3524
+#define GCD_DC_THRESHOLD                   555
+#define GCDEXT_DC_THRESHOLD                478
+#define JACOBI_BASE_METHOD                   4
+
+#define GET_STR_DC_THRESHOLD                12
+#define GET_STR_PRECOMPUTE_THRESHOLD        28
+#define SET_STR_DC_THRESHOLD               248
+#define SET_STR_PRECOMPUTE_THRESHOLD      1648
+
+#define FAC_DSC_THRESHOLD                 1075
+#define FAC_ODD_THRESHOLD                    0  /* always */
diff --git a/third_party/gmp/mpn/x86_64/goldmont/aorrlsh_n.asm b/third_party/gmp/mpn/x86_64/goldmont/aorrlsh_n.asm
new file mode 100644
index 0000000..06c5d5d
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/goldmont/aorrlsh_n.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_addlsh_n, mpn_rsblsh_n, optimised for Intel Goldmont.
+
+dnl  Copyright 2018 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_addlsh_n mpn_rsblsh_n)
+include_mpn(`x86_64/k8/aorrlsh_n.asm')
diff --git a/third_party/gmp/mpn/x86_64/goldmont/aors_n.asm b/third_party/gmp/mpn/x86_64/goldmont/aors_n.asm
new file mode 100644
index 0000000..1818f9f
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/goldmont/aors_n.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_add_n, mpn_sub_n, optimised for Intel Goldmont.
+
+dnl  Copyright 2018 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_add_n mpn_add_nc mpn_sub_n mpn_sub_nc)
+include_mpn(`x86_64/coreihwl/aors_n.asm')
diff --git a/third_party/gmp/mpn/x86_64/goldmont/aorsmul_1.asm b/third_party/gmp/mpn/x86_64/goldmont/aorsmul_1.asm
new file mode 100644
index 0000000..9c5f631
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/goldmont/aorsmul_1.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_addmul_1 and mpn_submul_1 optimised for Intel Goldmont.
+
+dnl  Copyright 2018 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_addmul_1 mpn_submul_1)
+include_mpn(`x86_64/bd1/aorsmul_1.asm')
diff --git a/third_party/gmp/mpn/x86_64/goldmont/gmp-mparam.h b/third_party/gmp/mpn/x86_64/goldmont/gmp-mparam.h
new file mode 100644
index 0000000..531521d
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/goldmont/gmp-mparam.h
@@ -0,0 +1,264 @@
+/* Intel Goldmont gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+/* 2200 MHz Intel Atom C3758 Goldmont/Denverton */
+/* FFT tuning limit = 468,030,122 */
+/* Generated by tuneup.c, 2019-10-12, gcc 8.3 */
+
+#define MOD_1_NORM_THRESHOLD                 3
+#define MOD_1_UNNORM_THRESHOLD               5
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          5
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          4
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        13
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        38
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD      9
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1_NORM_THRESHOLD              3
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD              17
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           19
+
+#define DIV_1_VS_MUL_1_PERCENT             301
+
+#define MUL_TOOM22_THRESHOLD                23
+#define MUL_TOOM33_THRESHOLD                65
+#define MUL_TOOM44_THRESHOLD               178
+#define MUL_TOOM6H_THRESHOLD               258
+#define MUL_TOOM8H_THRESHOLD               357
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD     121
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     131
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     121
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     129
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     178
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 30
+#define SQR_TOOM3_THRESHOLD                113
+#define SQR_TOOM4_THRESHOLD                290
+#define SQR_TOOM6_THRESHOLD                351
+#define SQR_TOOM8_THRESHOLD                  0  /* always */
+
+#define MULMID_TOOM42_THRESHOLD             36
+
+#define MULMOD_BNM1_THRESHOLD               14
+#define SQRMOD_BNM1_THRESHOLD               16
+
+#define MUL_FFT_MODF_THRESHOLD             440  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    440, 5}, {     19, 6}, {     10, 5}, {     21, 6}, \
+    {     11, 5}, {     23, 6}, {     21, 7}, {     11, 6}, \
+    {     24, 7}, {     13, 6}, {     27, 7}, {     15, 6}, \
+    {     31, 7}, {     21, 8}, {     11, 7}, {     24, 8}, \
+    {     13, 7}, {     28, 8}, {     15, 7}, {     31, 8}, \
+    {     17, 7}, {     35, 8}, {     19, 7}, {     39, 8}, \
+    {     21, 9}, {     11, 8}, {     27, 9}, {     15, 8}, \
+    {     35, 9}, {     19, 8}, {     41, 9}, {     23, 8}, \
+    {     47, 9}, {     27,10}, {     15, 9}, {     39,10}, \
+    {     23, 9}, {     51,11}, {     15,10}, {     31, 9}, \
+    {     71,10}, {     39, 9}, {     83,10}, {     47, 9}, \
+    {     95,10}, {     55,11}, {     31,10}, {     79,11}, \
+    {     47,10}, {    103,12}, {     31,11}, {     63,10}, \
+    {    135,11}, {     79,10}, {    159,11}, {     95,10}, \
+    {    191,11}, {    111,12}, {     63,11}, {    127,10}, \
+    {    255,11}, {    143,10}, {    287, 9}, {    575,11}, \
+    {    159,10}, {    319,12}, {     95,11}, {    191,10}, \
+    {    383, 9}, {    767,11}, {    207,10}, {    415,13}, \
+    {     63,12}, {    127,11}, {    255,10}, {    511,11}, \
+    {    271,10}, {    543,11}, {    287,10}, {    575,11}, \
+    {    303,12}, {    159,11}, {    319,10}, {    639,11}, \
+    {    367,12}, {    191,11}, {    383,10}, {    767,11}, \
+    {    415,12}, {    223,11}, {    479,13}, {    127,12}, \
+    {    255,11}, {    543,12}, {    287,11}, {    607,12}, \
+    {    319,11}, {    639,12}, {    351,11}, {    703,13}, \
+    {    191,12}, {    383,11}, {    767,12}, {    415,11}, \
+    {    831,12}, {    479,14}, {    127,13}, {    255,12}, \
+    {    543,11}, {   1087,12}, {    607,13}, {    319,12}, \
+    {    671,11}, {   1343,12}, {    703,11}, {   1407,12}, \
+    {    735,13}, {    383,12}, {    767,11}, {   1535,12}, \
+    {    831,13}, {    447,12}, {    959,14}, {    255,13}, \
+    {    511,12}, {   1023,11}, {   2047,12}, {   1087,13}, \
+    {    575,12}, {   1215,11}, {   2431,10}, {   4863,13}, \
+    {    639,12}, {   1279,11}, {   2559,12}, {   1343,13}, \
+    {    703,12}, {   1407,14}, {    383,13}, {    767,12}, \
+    {   1535,13}, {    831,12}, {   1727,13}, {    959,15}, \
+    {    255,14}, {    511,13}, {   1023,12}, {   2047,13}, \
+    {   1087,12}, {   2175,13}, {   1151,12}, {   2303,13}, \
+    {   1215,12}, {   2431,11}, {   4863,14}, {    639,13}, \
+    {   1279,12}, {   2559,13}, {   1343,12}, {   2687,13}, \
+    {   1407,12}, {   2815,13}, {   1471,12}, {   2943,11}, \
+    {   5887,14}, {    767,13}, {   1535,12}, {   3071,13}, \
+    {   1727,14}, {    895,13}, {   1791,12}, {   3583,13}, \
+    {   1919,15}, {    511,14}, {   1023,13}, {   2175,14}, \
+    {   1151,13}, {   2303,12}, {   4607,13}, {   2431,12}, \
+    {   4863,14}, {   1279,13}, {   2687,14}, {   1407,13}, \
+    {   2943,12}, {   5887,15}, {    767,14}, {   1535,13}, \
+    {   3071,14}, {   1663,13}, {   3455,12}, {   6911,14}, \
+    {   1791,13}, {   3583,14}, {   1919,13}, {   3839,16}, \
+    {    511,15}, {   1023,14}, {   2431,13}, {   4863,15}, \
+    {   1279,14}, {   2943,13}, {   5887,12}, {  11775,15}, \
+    {   1535,14}, {   3455,13}, {   6911,15}, {   1791,14}, \
+    {   3839,13}, {   7679,12}, {  15359,14}, {   3967,16}, \
+    {   1023,15}, {   2047,14}, {   4351,15}, {   2303,14}, \
+    {   4863,15}, {   2815,14}, {   5887,13}, {  11775,16}, \
+    {   1535,15}, {   3071,14}, {   6143,15}, {   3327,14}, \
+    {   6911,15}, {   3839,14}, {   7679,13}, {  15359,17}, \
+    {   1023,16}, {   2047,15}, {   4351,14}, {   8703,15}, \
+    {   4863,16}, {   2559,15}, {   5887,14}, {  11775,16}, \
+    {   3071,15}, {   6911,16}, {   3583,15}, {   7679,14}, \
+    {  15359,15}, {   7935,17}, {   2047,16}, {   4095,15}, \
+    {   8703,16}, {   4607,15}, {   9983,14}, {  19967,16}, \
+    {   5119,15}, {  10239,16}, {   5631,15}, {  11775,17}, \
+    {   3071,16}, {  65536,17}, { 131072,18}, { 262144,19}, \
+    { 524288,20}, {1048576,21}, {2097152,22}, {4194304,23}, \
+    {8388608,24} }
+#define MUL_FFT_TABLE3_SIZE 261
+#define MUL_FFT_THRESHOLD                 4544
+
+#define SQR_FFT_MODF_THRESHOLD             380  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    380, 5}, {     19, 6}, {     10, 5}, {     21, 6}, \
+    {     11, 5}, {     23, 6}, {     12, 5}, {     25, 6}, \
+    {     25, 7}, {     13, 6}, {     27, 7}, {     15, 6}, \
+    {     31, 7}, {     25, 8}, {     13, 7}, {     27, 8}, \
+    {     15, 7}, {     31, 8}, {     21, 9}, {     11, 8}, \
+    {     27, 9}, {     15, 8}, {     33, 9}, {     19, 8}, \
+    {     41, 9}, {     23, 8}, {     47, 9}, {     27,10}, \
+    {     15, 9}, {     39,10}, {     23, 9}, {     51,11}, \
+    {     15,10}, {     31, 9}, {     67,10}, {     39, 9}, \
+    {     79,10}, {     55,11}, {     31,10}, {     79,11}, \
+    {     47,10}, {     95,12}, {     31,11}, {     63,10}, \
+    {    127, 9}, {    255,10}, {    135,11}, {     79,10}, \
+    {    159, 9}, {    319,11}, {     95,10}, {    191, 9}, \
+    {    383,12}, {     63,11}, {    127,10}, {    255, 9}, \
+    {    511,10}, {    271, 9}, {    543,10}, {    287, 9}, \
+    {    575,10}, {    303, 9}, {    607,10}, {    319, 9}, \
+    {    639,12}, {     95,11}, {    191,10}, {    383,11}, \
+    {    207,13}, {     63,12}, {    127,11}, {    255,10}, \
+    {    511,11}, {    271,10}, {    543,11}, {    287,10}, \
+    {    575,11}, {    303,10}, {    607,11}, {    319,10}, \
+    {    639,11}, {    351,10}, {    703,11}, {    367,12}, \
+    {    191,11}, {    415,12}, {    223,11}, {    479,13}, \
+    {    127,12}, {    255,11}, {    543,12}, {    287,11}, \
+    {    607,12}, {    319,11}, {    639,12}, {    351,11}, \
+    {    703,10}, {   1407,13}, {    191,12}, {    383,11}, \
+    {    767,12}, {    479,14}, {    127,13}, {    255,12}, \
+    {    607,13}, {    319,12}, {    703,11}, {   1407,12}, \
+    {    735,13}, {    383,12}, {    767,11}, {   1535,12}, \
+    {    799,13}, {    447,12}, {    895,11}, {   1791,14}, \
+    {    255,13}, {    511,12}, {   1023,13}, {    575,12}, \
+    {   1151,11}, {   2303,12}, {   1215,13}, {    639,12}, \
+    {   1279,13}, {    703,12}, {   1407,14}, {    383,13}, \
+    {    767,12}, {   1535,13}, {    831,12}, {   1663,13}, \
+    {    895,12}, {   1791,13}, {    959,15}, {    255,14}, \
+    {    511,13}, {   1023,12}, {   2047,13}, {   1087,12}, \
+    {   2175,13}, {   1151,12}, {   2303,13}, {   1215,12}, \
+    {   2431,14}, {    639,13}, {   1279,12}, {   2559,13}, \
+    {   1343,12}, {   2687,13}, {   1407,12}, {   2815,13}, \
+    {   1471,12}, {   2943,11}, {   5887,14}, {    767,13}, \
+    {   1535,12}, {   3071,13}, {   1599,12}, {   3199,13}, \
+    {   1663,14}, {    895,13}, {   1791,12}, {   3583,15}, \
+    {    511,14}, {   1023,13}, {   2175,14}, {   1151,13}, \
+    {   2303,12}, {   4607,13}, {   2431,12}, {   4863,14}, \
+    {   1279,13}, {   2687,14}, {   1407,13}, {   2943,12}, \
+    {   5887,15}, {    767,14}, {   1535,13}, {   3199,14}, \
+    {   1663,13}, {   3455,12}, {   6911,14}, {   1791,13}, \
+    {   3583,14}, {   1919,16}, {    511,15}, {   1023,14}, \
+    {   2303,13}, {   4607,14}, {   2431,13}, {   4863,15}, \
+    {   1279,14}, {   2943,13}, {   5887,12}, {  11775,15}, \
+    {   1535,14}, {   3455,13}, {   6911,15}, {   1791,14}, \
+    {   3583,13}, {   7167,14}, {   3839,13}, {   7679,12}, \
+    {  15359,16}, {   1023,15}, {   2047,14}, {   4223,15}, \
+    {   2303,14}, {   4863,15}, {   2559,14}, {   5119,15}, \
+    {   2815,14}, {   5887,13}, {  11775,16}, {   1535,15}, \
+    {   3071,14}, {   6143,15}, {   3327,14}, {   6911,15}, \
+    {   3583,14}, {   7167,15}, {   3839,14}, {   7679,13}, \
+    {  15359,17}, {   1023,16}, {   2047,15}, {   4095,14}, \
+    {   8191,15}, {   4863,16}, {   2559,15}, {   5887,14}, \
+    {  11775,16}, {   3071,15}, {   6911,16}, {   3583,15}, \
+    {   7679,14}, {  15359,15}, {   7935,14}, {  15871,17}, \
+    {   2047,16}, {   4095,15}, {   8447,16}, {   4607,15}, \
+    {   9983,14}, {  19967,16}, {   5119,15}, {  10239,16}, \
+    {   5631,15}, {  11775,17}, {   3071,16}, {  65536,17}, \
+    { 131072,18}, { 262144,19}, { 524288,20}, {1048576,21}, \
+    {2097152,22}, {4194304,23}, {8388608,24} }
+#define SQR_FFT_TABLE3_SIZE 259
+#define SQR_FFT_THRESHOLD                 3520
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  62
+#define MULLO_MUL_N_THRESHOLD             8907
+#define SQRLO_BASECASE_THRESHOLD            10
+#define SQRLO_DC_THRESHOLD                  13
+#define SQRLO_SQR_THRESHOLD               7035
+
+#define DC_DIV_QR_THRESHOLD                 51
+#define DC_DIVAPPR_Q_THRESHOLD             183
+#define DC_BDIV_QR_THRESHOLD                47
+#define DC_BDIV_Q_THRESHOLD                 88
+
+#define INV_MULMOD_BNM1_THRESHOLD           46
+#define INV_NEWTON_THRESHOLD               226
+#define INV_APPR_THRESHOLD                 204
+
+#define BINV_NEWTON_THRESHOLD              264
+#define REDC_1_TO_REDC_2_THRESHOLD          28
+#define REDC_2_TO_REDC_N_THRESHOLD          54
+
+#define MU_DIV_QR_THRESHOLD               1589
+#define MU_DIVAPPR_Q_THRESHOLD            1620
+#define MUPI_DIV_QR_THRESHOLD               83
+#define MU_BDIV_QR_THRESHOLD              1334
+#define MU_BDIV_Q_THRESHOLD               1470
+
+#define POWM_SEC_TABLE  1,16,194,642
+
+#define GET_STR_DC_THRESHOLD                10
+#define GET_STR_PRECOMPUTE_THRESHOLD        17
+#define SET_STR_DC_THRESHOLD               381
+#define SET_STR_PRECOMPUTE_THRESHOLD      1042
+
+#define FAC_DSC_THRESHOLD                  218
+#define FAC_ODD_THRESHOLD                   25
+
+#define MATRIX22_STRASSEN_THRESHOLD         21
+#define HGCD2_DIV1_METHOD                    1  /* 6.58% faster than 3 */
+#define HGCD_THRESHOLD                     136
+#define HGCD_APPR_THRESHOLD                168
+#define HGCD_REDUCE_THRESHOLD             3014
+#define GCD_DC_THRESHOLD                   416
+#define GCDEXT_DC_THRESHOLD                393
+#define JACOBI_BASE_METHOD                   4  /* 1.17% faster than 3 */
+
+/* Tuneup completed successfully, took 800192 seconds */
diff --git a/third_party/gmp/mpn/x86_64/goldmont/mul_1.asm b/third_party/gmp/mpn/x86_64/goldmont/mul_1.asm
new file mode 100644
index 0000000..ed1ec54
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/goldmont/mul_1.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_mul_1 optimised for Intel Goldmont.
+
+dnl  Copyright 2018 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_mul_1 mpn_mul_1c)
+include_mpn(`x86_64/coreisbr/mul_1.asm')
diff --git a/third_party/gmp/mpn/x86_64/goldmont/redc_1.asm b/third_party/gmp/mpn/x86_64/goldmont/redc_1.asm
new file mode 100644
index 0000000..1192635
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/goldmont/redc_1.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_redc_1 optimised for Intel Goldmont.
+
+dnl  Copyright 2018 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_redc_1)
+include_mpn(`x86_64/k8/redc_1.asm')
diff --git a/third_party/gmp/mpn/x86_64/invert_limb.asm b/third_party/gmp/mpn/x86_64/invert_limb.asm
new file mode 100644
index 0000000..b375ad3
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/invert_limb.asm
@@ -0,0 +1,112 @@
+dnl  AMD64 mpn_invert_limb -- Invert a normalized limb.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund and Niels Möller.
+
+dnl  Copyright 2004, 2007-2009, 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C	     cycles/limb (approx)	div
+C AMD K8,K9	 48			 71
+C AMD K10	 48			 77
+C Intel P4	135			161
+C Intel core2	 69			116
+C Intel corei	 55			 89
+C Intel atom	129			191
+C VIA nano	 79			157
+
+C rax rcx rdx rdi rsi r8
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+PROTECT(`mpn_invert_limb_table')
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_invert_limb)		C			Kn	C2	Ci
+	FUNC_ENTRY(1)
+	mov	%rdi, %rax		C			 0	 0	 0
+	shr	$55, %rax		C			 1	 1	 1
+ifdef(`DARWIN',`
+	lea	mpn_invert_limb_table(%rip), %r8
+	add	$-512, %r8
+',`
+	lea	-512+mpn_invert_limb_table(%rip), %r8
+')
+	movzwl	(%r8,%rax,2), R32(%rcx)	C	%rcx = v0
+
+	C v1 = (v0 << 11) - (v0*v0*d40 >> 40) - 1
+	mov	%rdi, %rsi		C			 0	 0	 0
+	mov	R32(%rcx), R32(%rax)	C			 4	 5	 5
+	imul	R32(%rcx), R32(%rcx)	C			 4	 5	 5
+	shr	$24, %rsi		C			 1	 1	 1
+	inc	%rsi			C	%rsi = d40
+	imul	%rsi, %rcx		C			 8	10	 8
+	shr	$40, %rcx		C			12	15	11
+	sal	$11, R32(%rax)		C			 5	 6	 6
+	dec	R32(%rax)
+	sub	R32(%rcx), R32(%rax)	C	%rax = v1
+
+	C v2 = (v1 << 13) + (v1 * (2^60 - v1*d40) >> 47)
+	mov	$0x1000000000000000, %rcx
+	imul	%rax, %rsi		C			14	17	13
+	sub	%rsi, %rcx
+	imul	%rax, %rcx
+	sal	$13, %rax
+	shr	$47, %rcx
+	add	%rax, %rcx		C	%rcx = v2
+
+	C v3 = (v2 << 31) + (v2 * (2^96 - v2 * d63 + ((v2 >> 1) & mask)) >> 65)
+	mov	%rdi, %rsi		C			 0	 0	 0
+	shr	%rsi			C d/2
+	sbb	%rax, %rax		C -d0 = -(d mod 2)
+	sub	%rax, %rsi		C d63 = ceil(d/2)
+	imul	%rcx, %rsi		C v2 * d63
+	and	%rcx, %rax		C v2 * d0
+	shr	%rax			C (v2>>1) * d0
+	sub	%rsi, %rax		C (v2>>1) * d0 - v2 * d63
+	mul	%rcx
+	sal	$31, %rcx
+	shr	%rdx
+	add	%rdx, %rcx		C	%rcx = v3
+
+	mov	%rdi, %rax
+	mul	%rcx
+	add	%rdi, %rax
+	mov	%rcx, %rax
+	adc	%rdi, %rdx
+	sub	%rdx, %rax
+
+	FUNC_EXIT()
+	ret
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86_64/invert_limb_table.asm b/third_party/gmp/mpn/x86_64/invert_limb_table.asm
new file mode 100644
index 0000000..739d59e
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/invert_limb_table.asm
@@ -0,0 +1,50 @@
+dnl  Table used for mpn_invert_limb
+
+dnl  Contributed to the GNU project by Torbjorn Granlund and Niels Möller.
+
+dnl  Copyright 2004, 2007-2009, 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+PROTECT(`mpn_invert_limb_table')
+
+ASM_START()
+C Table entry X contains floor (0x7fd00 / (0x100 + X))
+
+	RODATA
+	ALIGN(2)
+	GLOBL mpn_invert_limb_table
+mpn_invert_limb_table:
+forloop(i,256,512-1,dnl
+`	.value	eval(0x7fd00/i)
+')dnl
+ASM_END()
diff --git a/third_party/gmp/mpn/x86_64/k10/gcd_11.asm b/third_party/gmp/mpn/x86_64/k10/gcd_11.asm
new file mode 100644
index 0000000..4723093
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/k10/gcd_11.asm
@@ -0,0 +1,37 @@
+dnl  AMD64 mpn_gcd_11.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_gcd_11)
+include_mpn(`x86_64/core2/gcd_11.asm')
diff --git a/third_party/gmp/mpn/x86_64/k10/gcd_22.asm b/third_party/gmp/mpn/x86_64/k10/gcd_22.asm
new file mode 100644
index 0000000..f58b4cc
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/k10/gcd_22.asm
@@ -0,0 +1,142 @@
+dnl  AMD64 mpn_gcd_22.  Assumes useful bsf, useless shrd, no tzcnt, no shlx.
+
+dnl  Copyright 2019 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C	     cycles/bit
+C AMD K8,K9	 ?
+C AMD K10	 7.4
+C AMD bd1	 9.9
+C AMD bd2	 ?
+C AMD bd3	 ?
+C AMD bd4	 ?
+C AMD bt1	 ?
+C AMD bt2	 ?
+C AMD zn1	 ?
+C AMD zn2	 ?
+C Intel P4	 ?
+C Intel CNR	 ?
+C Intel PNR	 ?
+C Intel NHM	 9.2
+C Intel WSM	 9.0
+C Intel SBR	 ?
+C Intel IBR	 ?
+C Intel HWL	 ?
+C Intel BWL	 ?
+C Intel SKL	 ?
+C Intel atom	 ?
+C Intel SLM	 ?
+C Intel GLM	 ?
+C Intel GLM+	 ?
+C VIA nano	 ?
+
+
+define(`u1',    `%rdi')
+define(`u0',    `%rsi')
+define(`v1',    `%rdx')
+define(`v0_param', `%rcx')
+
+define(`v0',    `%rax')
+define(`cnt',   `%rcx')
+
+define(`s0',    `%r8')
+define(`s1',    `%r9')
+define(`t0',    `%r10')
+define(`t1',    `%r11')
+
+dnl ABI_SUPPORT(DOS64)	C returns mp_double_limb_t in memory
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(64)
+PROLOGUE(mpn_gcd_22)
+	FUNC_ENTRY(4)
+	mov	v0_param, v0
+
+	ALIGN(16)
+L(top):	mov	v0, t0
+	sub	u0, t0
+	jz	L(lowz)		C	jump when low limb result = 0
+	mov	v1, t1
+	sbb	u1, t1
+
+	mov	u0, s0
+	mov	u1, s1
+
+	bsf	t0, cnt
+
+	sub	v0, u0
+	sbb	v1, u1
+
+L(bck):	cmovc	t0, u0		C u = |u - v|
+	cmovnc	u1, t1		C u = |u - v|
+	cmovc	s0, v0		C v = min(u,v)
+	cmovc	s1, v1		C v = min(u,v)
+
+	shr	R8(cnt), u0
+	mov	t1, u1
+	shr	R8(cnt), u1
+	neg	cnt
+	shl	R8(cnt), t1
+	or	t1, u0
+
+	test	u1, u1
+	jnz	L(top)
+	test	v1, v1
+	jnz	L(top)
+
+L(gcd_11):
+	mov	v0, %rdi
+C	mov	u0, %rsi
+	TCALL(	mpn_gcd_11)
+
+L(lowz):C We come here when v0 - u0 = 0
+	C 1. If v1 - u1 = 0, then gcd is u = v.
+	C 2. Else compute gcd_21({v1,v0}, |u1-v1|)
+	mov	v1, t0
+	sub	u1, t0
+	je	L(end)
+
+	xor	t1, t1
+	mov	u0, s0
+	mov	u1, s1
+	bsf	t0, cnt
+	mov	u1, u0
+	xor	u1, u1
+	sub	v1, u0
+	jmp	L(bck)
+
+L(end):	C mov	v0, %rax
+	C mov	v1, %rdx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/k10/gmp-mparam.h b/third_party/gmp/mpn/x86_64/k10/gmp-mparam.h
new file mode 100644
index 0000000..349bace
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/k10/gmp-mparam.h
@@ -0,0 +1,248 @@
+/* AMD K10 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+#if 0
+#undef mpn_sublsh_n
+#define mpn_sublsh_n(rp,up,vp,n,c)					\
+  (((rp) == (up)) ? mpn_submul_1 (rp, vp, n, CNST_LIMB(1) << (c))	\
+   : MPN(mpn_sublsh_n)(rp,up,vp,n,c))
+#endif
+
+/* 3200-3600 MHz K10 Thuban */
+/* FFT tuning limit = 427,161,280 */
+/* Generated by tuneup.c, 2019-10-22, gcc 8.3 */
+
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          5
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          3
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        17
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        28
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     11
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1_NORM_THRESHOLD              1
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           15
+
+#define DIV_1_VS_MUL_1_PERCENT             324
+
+#define MUL_TOOM22_THRESHOLD                27
+#define MUL_TOOM33_THRESHOLD                81
+#define MUL_TOOM44_THRESHOLD               232
+#define MUL_TOOM6H_THRESHOLD               363
+#define MUL_TOOM8H_THRESHOLD               478
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      97
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     155
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     145
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     160
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     142
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 30
+#define SQR_TOOM3_THRESHOLD                117
+#define SQR_TOOM4_THRESHOLD                280
+#define SQR_TOOM6_THRESHOLD                446
+#define SQR_TOOM8_THRESHOLD                547
+
+#define MULMID_TOOM42_THRESHOLD             34
+
+#define MULMOD_BNM1_THRESHOLD               15
+#define SQRMOD_BNM1_THRESHOLD               17
+
+#define MUL_FFT_MODF_THRESHOLD             530  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    530, 5}, {     24, 6}, {     13, 5}, {     27, 6}, \
+    {     27, 7}, {     14, 6}, {     29, 7}, {     15, 6}, \
+    {     31, 7}, {     29, 8}, {     15, 7}, {     32, 8}, \
+    {     17, 7}, {     36, 8}, {     19, 7}, {     39, 8}, \
+    {     21, 7}, {     43, 8}, {     23, 7}, {     47, 8}, \
+    {     25, 7}, {     51, 8}, {     29, 9}, {     15, 8}, \
+    {     35, 9}, {     19, 8}, {     43, 9}, {     23, 8}, \
+    {     51, 9}, {     27, 8}, {     55,10}, {     15, 9}, \
+    {     31, 8}, {     63, 9}, {     35, 8}, {     71, 9}, \
+    {     39, 8}, {     81, 9}, {     43,10}, {     23, 9}, \
+    {     55,11}, {     15,10}, {     31, 9}, {     71,10}, \
+    {     39, 9}, {     87,10}, {     47, 9}, {     99,10}, \
+    {     55,11}, {     31,10}, {     87,11}, {     47,10}, \
+    {    111,12}, {     31,11}, {     63,10}, {    143,11}, \
+    {     79,10}, {    167,11}, {     95,10}, {    191,11}, \
+    {    111,12}, {     63,11}, {    143,10}, {    287,11}, \
+    {    159,12}, {     95,11}, {    207,13}, {     63,12}, \
+    {    127,11}, {    255,10}, {    511,11}, {    271,10}, \
+    {    543,11}, {    287,12}, {    159,11}, {    319,10}, \
+    {    639,11}, {    335,10}, {    671,11}, {    351,10}, \
+    {    703,12}, {    191,11}, {    383,10}, {    767,11}, \
+    {    415,12}, {    223,11}, {    447,13}, {    127,12}, \
+    {    255,11}, {    543,12}, {    287,11}, {    575,10}, \
+    {   1151,11}, {    607,12}, {    319,11}, {    671,12}, \
+    {    351,11}, {    703,13}, {    191,12}, {    383,11}, \
+    {    767,12}, {    415,11}, {    831,12}, {    447,14}, \
+    {    127,13}, {    255,12}, {    543,11}, {   1087,12}, \
+    {    575,11}, {   1151,12}, {    607,13}, {    319,12}, \
+    {    703,11}, {   1407,12}, {    735,13}, {    383,12}, \
+    {    831,13}, {    447,12}, {    959,14}, {    255,13}, \
+    {    511,12}, {   1087,13}, {    575,12}, {   1215,13}, \
+    {    639,12}, {   1343,13}, {    703,12}, {   1471,14}, \
+    {    383,13}, {    767,12}, {   1535,13}, {    831,12}, \
+    {   1663,13}, {    959,14}, {    511,13}, {   1087,12}, \
+    {   2175,13}, {   1215,14}, {    639,13}, {   1471,14}, \
+    {    767,13}, {   1663,14}, {    895,13}, {   1855,15}, \
+    {    511,14}, {   1023,13}, {   2175,14}, {   1151,13}, \
+    {   2431,14}, {   1279,13}, {   2559,14}, {   1407,15}, \
+    {    767,14}, {   1791,16}, {    511,15}, {   1023,14}, \
+    {   2431,15}, {   1279,14}, {   2943,15}, {   1535,14}, \
+    {   3199,15}, {   1791,14}, {   3583,16}, {   1023,15}, \
+    {   2047,14}, {   4223,15}, {   2303,14}, {   4863,15}, \
+    {   2559,14}, {   5247,15}, {   2815,16}, {   1535,15}, \
+    {   3071,14}, {   6271,15}, {   3327,14}, {   6911,15}, \
+    {   3583,17}, {   1023,16}, {   2047,15}, {   4351,14}, \
+    {   8959,15}, {   4863,16}, {   2559,15}, {   5887,14}, \
+    {  11775,16}, {   3071,15}, {   6911,16}, {   3583,15}, \
+    {   7167,17}, {   2047,16}, {   4095,15}, {   8959,16}, \
+    {   4607,15}, {   9983,16}, {   5631,15}, {  11775,17}, \
+    {   3071,16}, {   6143,15}, {  12543,16}, {  65536,17}, \
+    { 131072,18}, { 262144,19}, { 524288,20}, {1048576,21}, \
+    {2097152,22}, {4194304,23}, {8388608,24} }
+#define MUL_FFT_TABLE3_SIZE 207
+#define MUL_FFT_THRESHOLD                 7552
+
+#define SQR_FFT_MODF_THRESHOLD             476  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    476, 5}, {     21, 6}, {     11, 5}, {     23, 6}, \
+    {     12, 5}, {     25, 6}, {     29, 7}, {     28, 8}, \
+    {     15, 7}, {     32, 8}, {     17, 7}, {     35, 8}, \
+    {     19, 7}, {     39, 8}, {     21, 7}, {     43, 8}, \
+    {     23, 7}, {     47, 8}, {     29, 9}, {     15, 8}, \
+    {     35, 9}, {     19, 8}, {     43, 9}, {     23, 8}, \
+    {     49, 9}, {     27, 8}, {     55,10}, {     15, 9}, \
+    {     31, 8}, {     63, 9}, {     43,10}, {     23, 9}, \
+    {     55,11}, {     15,10}, {     31, 9}, {     67,10}, \
+    {     39, 9}, {     83,10}, {     47, 9}, {     95,10}, \
+    {     55,11}, {     31,10}, {     79,11}, {     47,10}, \
+    {    103,12}, {     31,11}, {     63,10}, {    135,11}, \
+    {     79,10}, {    167,11}, {    111,12}, {     63,11}, \
+    {    127,10}, {    255,11}, {    143,10}, {    287, 9}, \
+    {    575,11}, {    159,10}, {    319,12}, {     95,11}, \
+    {    191,10}, {    383, 9}, {    767,10}, {    399,13}, \
+    {     63,12}, {    127,11}, {    255,10}, {    511,11}, \
+    {    271,10}, {    543,11}, {    287,10}, {    575,12}, \
+    {    159,11}, {    319,10}, {    639,11}, {    335,10}, \
+    {    671,11}, {    351,10}, {    703,11}, {    367,12}, \
+    {    191,11}, {    383,10}, {    767,11}, {    415,10}, \
+    {    831,12}, {    223,11}, {    447,13}, {    127,12}, \
+    {    255,11}, {    511,10}, {   1023,11}, {    543,12}, \
+    {    287,11}, {    575,10}, {   1151,11}, {    607,12}, \
+    {    319,11}, {    639,10}, {   1279,11}, {    671,12}, \
+    {    351,11}, {    703,10}, {   1407,13}, {    191,12}, \
+    {    383,11}, {    799,12}, {    415,11}, {    831,12}, \
+    {    447,14}, {    127,13}, {    255,12}, {    511,11}, \
+    {   1023,12}, {    543,11}, {   1087,12}, {    575,11}, \
+    {   1151,12}, {    607,13}, {    319,12}, {    639,11}, \
+    {   1279,12}, {    671,11}, {   1343,12}, {    703,11}, \
+    {   1407,12}, {    735,13}, {    383,12}, {    767,11}, \
+    {   1535,12}, {    831,11}, {   1663,13}, {    447,12}, \
+    {    959,14}, {    255,13}, {    511,12}, {   1087,13}, \
+    {    575,12}, {   1215,13}, {    639,12}, {   1343,13}, \
+    {    703,12}, {   1407,14}, {    383,13}, {    767,12}, \
+    {   1535,13}, {    831,12}, {   1727,13}, {    895,12}, \
+    {   1791,13}, {    959,15}, {    255,14}, {    511,13}, \
+    {   1087,12}, {   2175,13}, {   1215,14}, {    639,13}, \
+    {   1471,14}, {    767,13}, {   1727,14}, {    895,13}, \
+    {   1791,15}, {    511,14}, {   1023,13}, {   2175,14}, \
+    {   1151,13}, {   2303,14}, {   1279,13}, {   2559,14}, \
+    {   1407,15}, {    767,14}, {   1791,16}, {    511,15}, \
+    {   1023,14}, {   2303,15}, {   1279,14}, {   2815,15}, \
+    {   1535,14}, {   3199,15}, {   1791,16}, {   1023,15}, \
+    {   2047,14}, {   4223,15}, {   2303,14}, {   4863,15}, \
+    {   2559,14}, {   5247,15}, {   2815,16}, {   1535,15}, \
+    {   3071,14}, {   6271,15}, {   3327,14}, {   6911,17}, \
+    {   1023,16}, {   2047,15}, {   4351,14}, {   8959,15}, \
+    {   4863,16}, {   2559,15}, {   5887,14}, {  11775,16}, \
+    {   3071,15}, {   6911,16}, {   3583,15}, {   7679,17}, \
+    {   2047,16}, {   4095,15}, {   8959,16}, {   4607,15}, \
+    {   9983,16}, {   5119,15}, {  10495,16}, {   5631,15}, \
+    {  11775,17}, {   3071,16}, {   6143,15}, {  12287,16}, \
+    {  65536,17}, { 131072,18}, { 262144,19}, { 524288,20}, \
+    {1048576,21}, {2097152,22}, {4194304,23}, {8388608,24} }
+#define SQR_FFT_TABLE3_SIZE 224
+#define SQR_FFT_THRESHOLD                 5568
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  61
+#define MULLO_MUL_N_THRESHOLD            14281
+#define SQRLO_BASECASE_THRESHOLD             9
+#define SQRLO_DC_THRESHOLD                   0  /* never mpn_sqrlo_basecase */
+#define SQRLO_SQR_THRESHOLD              10950
+
+#define DC_DIV_QR_THRESHOLD                 54
+#define DC_DIVAPPR_Q_THRESHOLD             238
+#define DC_BDIV_QR_THRESHOLD                54
+#define DC_BDIV_Q_THRESHOLD                 42
+
+#define INV_MULMOD_BNM1_THRESHOLD           54
+#define INV_NEWTON_THRESHOLD               252
+#define INV_APPR_THRESHOLD                 230
+
+#define BINV_NEWTON_THRESHOLD              327
+#define REDC_1_TO_REDC_2_THRESHOLD          25
+#define REDC_2_TO_REDC_N_THRESHOLD          67
+
+#define MU_DIV_QR_THRESHOLD               1620
+#define MU_DIVAPPR_Q_THRESHOLD            1620
+#define MUPI_DIV_QR_THRESHOLD              104
+#define MU_BDIV_QR_THRESHOLD              1528
+#define MU_BDIV_Q_THRESHOLD               1652
+
+#define POWM_SEC_TABLE  1,22,321,473,2144
+
+#define GET_STR_DC_THRESHOLD                15
+#define GET_STR_PRECOMPUTE_THRESHOLD        24
+#define SET_STR_DC_THRESHOLD               248
+#define SET_STR_PRECOMPUTE_THRESHOLD      1304
+
+#define FAC_DSC_THRESHOLD                  470
+#define FAC_ODD_THRESHOLD                   25
+
+#define MATRIX22_STRASSEN_THRESHOLD         17
+#define HGCD2_DIV1_METHOD                    5  /* 8.38% faster than 4 */
+#define HGCD_THRESHOLD                     115
+#define HGCD_APPR_THRESHOLD                146
+#define HGCD_REDUCE_THRESHOLD             3524
+#define GCD_DC_THRESHOLD                   535
+#define GCDEXT_DC_THRESHOLD                460
+#define JACOBI_BASE_METHOD                   1  /* 0.90% faster than 4 */
+
+/* Tuneup completed successfully, took 448763 seconds */
diff --git a/third_party/gmp/mpn/x86_64/k10/hamdist.asm b/third_party/gmp/mpn/x86_64/k10/hamdist.asm
new file mode 100644
index 0000000..f70494a
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/k10/hamdist.asm
@@ -0,0 +1,109 @@
+dnl  AMD64 mpn_hamdist -- hamming distance.
+
+dnl  Copyright 2008, 2010-2012, 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 -
+C AMD K10	 2.0		=
+C AMD bd1	~4.4		=
+C AMD bd2	~4.4		=
+C AMD bd3
+C AMD bd4
+C AMD bobcat	 7.55		=
+C AMD jaguar	 2.52		-
+C Intel P4	 -
+C Intel core2	 -
+C Intel NHM	 2.03		+
+C Intel SBR	 2.01		+
+C Intel IBR	 1.96		+
+C Intel HWL	 1.64		=
+C Intel BWL	 1.56		-
+C Intel SKL	 1.52		=
+C Intel atom
+C Intel SLM	 3.0		-
+C VIA nano
+
+define(`ap',		`%rdi')
+define(`bp',		`%rsi')
+define(`n',		`%rdx')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_hamdist)
+	FUNC_ENTRY(3)
+	mov	(ap), %r8
+	xor	(bp), %r8
+
+	lea	(ap,n,8), ap			C point at A operand end
+	lea	(bp,n,8), bp			C point at B operand end
+	neg	n
+
+	test	$1, R8(n)
+	jz	L(2)
+
+L(1):	.byte	0xf3,0x49,0x0f,0xb8,0xc0	C popcnt %r8, %rax
+	xor	R32(%r10), R32(%r10)
+	inc	n
+	js	L(top)
+	FUNC_EXIT()
+	ret
+
+	ALIGN(16)
+L(2):	mov	8(ap,n,8), %r9
+	.byte	0xf3,0x49,0x0f,0xb8,0xc0	C popcnt %r8, %rax
+	xor	8(bp,n,8), %r9
+	.byte	0xf3,0x4d,0x0f,0xb8,0xd1	C popcnt %r9, %r10
+	add	$2, n
+	js	L(top)
+	lea	(%r10, %rax), %rax
+	FUNC_EXIT()
+	ret
+
+	ALIGN(16)
+L(top):	mov	(ap,n,8), %r8
+	lea	(%r10, %rax), %rax
+	mov	8(ap,n,8), %r9
+	xor	(bp,n,8), %r8
+	xor	8(bp,n,8), %r9
+	.byte	0xf3,0x49,0x0f,0xb8,0xc8	C popcnt %r8, %rcx
+	lea	(%rcx, %rax), %rax
+	.byte	0xf3,0x4d,0x0f,0xb8,0xd1	C popcnt %r9, %r10
+	add	$2, n
+	js	L(top)
+
+	lea	(%r10, %rax), %rax
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/k10/lshift.asm b/third_party/gmp/mpn/x86_64/k10/lshift.asm
new file mode 100644
index 0000000..cadf9b9
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/k10/lshift.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_lshift optimised for AMD K10.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_lshift)
+include_mpn(`x86_64/fastsse/lshift-movdqu2.asm')
diff --git a/third_party/gmp/mpn/x86_64/k10/lshiftc.asm b/third_party/gmp/mpn/x86_64/k10/lshiftc.asm
new file mode 100644
index 0000000..48a92e5
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/k10/lshiftc.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_lshiftc optimised for AMD K10.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_lshiftc)
+include_mpn(`x86_64/fastsse/lshiftc-movdqu2.asm')
diff --git a/third_party/gmp/mpn/x86_64/k10/popcount.asm b/third_party/gmp/mpn/x86_64/k10/popcount.asm
new file mode 100644
index 0000000..3814aea
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/k10/popcount.asm
@@ -0,0 +1,138 @@
+dnl  AMD64 mpn_popcount -- population count.
+
+dnl  Copyright 2008, 2010-2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		    cycles/limb
+C AMD K8,K9		 n/a
+C AMD K10		 1.125
+C Intel P4		 n/a
+C Intel core2		 n/a
+C Intel corei		 1.25
+C Intel atom		 n/a
+C VIA nano		 n/a
+
+C * The zero-offset of popcount is misassembled to the offset-less form, which
+C   is one byte shorter and therefore will mess up the switching code.
+C * The outdated gas used in FreeBSD and NetBSD cannot handle the POPCNT insn,
+C   which is the main reason for our usage of '.byte'.
+
+C TODO
+C  * Improve switching code, the current code sucks.
+
+define(`up',		`%rdi')
+define(`n',		`%rsi')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_popcount)
+	FUNC_ENTRY(2)
+
+ifelse(1,1,`
+	lea	(up,n,8), up
+
+C	mov	R32(n), R32(%rcx)
+C	neg	R32(%rcx)
+	imul	$-1, R32(n), R32(%rcx)
+	and	$8-1, R32(%rcx)
+
+	neg	n
+
+	mov	R32(%rcx), R32(%rax)
+	neg	%rax
+	lea	(up,%rax,8),up
+
+	xor	R32(%rax), R32(%rax)
+
+	lea	(%rcx,%rcx,4), %rcx
+
+	lea	L(top)(%rip), %rdx
+	lea	(%rdx,%rcx,2), %rdx
+	jmp	*%rdx
+',`
+	lea	(up,n,8), up
+
+	mov	R32(n), R32(%rcx)
+	neg	R32(%rcx)
+	and	$8-1, R32(%rcx)
+
+	neg	n
+
+	mov	R32(%rcx), R32(%rax)
+	shl	$3, R32(%rax)
+	sub	%rax, up
+
+	xor	R32(%rax), R32(%rax)
+
+C	add	R32(%rcx), R32(%rcx)	C 2x
+C	lea	(%rcx,%rcx,4), %rcx	C 10x
+	imul	$10, R32(%rcx)
+
+	lea	L(top)(%rip), %rdx
+	add	%rcx, %rdx
+	jmp	*%rdx
+')
+
+	ALIGN(32)
+L(top):
+C 0 = n mod 8
+	.byte	0xf3,0x4c,0x0f,0xb8,0x44,0xf7,0x00	C popcnt 0(up,n,8), %r8
+	add	%r8, %rax
+C 7 = n mod 8
+	.byte	0xf3,0x4c,0x0f,0xb8,0x4c,0xf7,0x08	C popcnt 8(up,n,8), %r9
+	add	%r9, %rax
+C 6 = n mod 8
+	.byte	0xf3,0x4c,0x0f,0xb8,0x44,0xf7,0x10	C popcnt 16(up,n,8), %r8
+	add	%r8, %rax
+C 5 = n mod 8
+	.byte	0xf3,0x4c,0x0f,0xb8,0x4c,0xf7,0x18	C popcnt 24(up,n,8), %r9
+	add	%r9, %rax
+C 4 = n mod 8
+	.byte	0xf3,0x4c,0x0f,0xb8,0x44,0xf7,0x20	C popcnt 32(up,n,8), %r8
+	add	%r8, %rax
+C 3 = n mod 8
+	.byte	0xf3,0x4c,0x0f,0xb8,0x4c,0xf7,0x28	C popcnt 40(up,n,8), %r9
+	add	%r9, %rax
+C 2 = n mod 8
+	.byte	0xf3,0x4c,0x0f,0xb8,0x44,0xf7,0x30	C popcnt 48(up,n,8), %r8
+	add	%r8, %rax
+C 1 = n mod 8
+	.byte	0xf3,0x4c,0x0f,0xb8,0x4c,0xf7,0x38	C popcnt 56(up,n,8), %r9
+	add	%r9, %rax
+
+	add	$8, n
+	js	L(top)
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/k10/rshift.asm b/third_party/gmp/mpn/x86_64/k10/rshift.asm
new file mode 100644
index 0000000..249051a
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/k10/rshift.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_rshift optimised for AMD K10.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_rshift)
+include_mpn(`x86_64/fastsse/rshift-movdqu2.asm')
diff --git a/third_party/gmp/mpn/x86_64/k10/sec_tabselect.asm b/third_party/gmp/mpn/x86_64/k10/sec_tabselect.asm
new file mode 100644
index 0000000..e436034
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/k10/sec_tabselect.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_sec_tabselect.
+
+dnl  Copyright 2012, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_sec_tabselect)
+include_mpn(`x86_64/fastsse/sec_tabselect.asm')
diff --git a/third_party/gmp/mpn/x86_64/k8/addmul_2.asm b/third_party/gmp/mpn/x86_64/k8/addmul_2.asm
new file mode 100644
index 0000000..78bcba1
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/k8/addmul_2.asm
@@ -0,0 +1,195 @@
+dnl  AMD64 mpn_addmul_2 -- Multiply an n-limb vector with a 2-limb vector and
+dnl  add the result to a third limb vector.
+
+dnl  Copyright 2008, 2011, 2012, 2016 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb     cycles/limb cfg	cycles/limb am1+am1
+C AMD K8,K9	 2.375
+C AMD K10	 2.375
+C AMD bull	 5.2		<-		4.6-4.75		bad
+C AMD pile	 4.96		<-		4.6-4.75		bad
+C AMD steam	 ?
+C AMD excavator	 ?
+C AMD bobcat	 5.75				5.0			bad
+C AMD jaguar	 5.9				5.2-5.4			bad
+C Intel P4	15-16
+C Intel core2	 4.5				4.25-4.5		bad
+C Intel NHM	 4.33				4.55			bad
+C Intel SBR	 3.4		 2.93		3.24			bad
+C Intel IBR	 3.35		 2.6		2.95			bad
+C Intel HWL	 3.3		 2.15		2.3			bad
+C Intel BWL	 2.33		 2.33		1.65			bad
+C Intel SKL	 2.37		 2.21		1.64			bad
+C Intel atom	20		18.7
+C Intel SLM	 8		 8.5
+C VIA nano	 4.4
+
+C This code is the result of running a code generation and optimization tool
+C suite written by David Harvey and Torbjorn Granlund.
+
+C TODO
+C  * Tune feed-in and wind-down code.
+
+C INPUT PARAMETERS
+define(`rp',     `%rdi')
+define(`up',     `%rsi')
+define(`n_param',`%rdx')
+define(`vp',     `%rcx')
+
+define(`v0', `%r8')
+define(`v1', `%r9')
+define(`w0', `%rbx')
+define(`w1', `%rcx')
+define(`w2', `%rbp')
+define(`w3', `%r10')
+define(`n',  `%r11')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_addmul_2)
+	FUNC_ENTRY(4)
+	mov	n_param, n
+	push	%rbx
+	push	%rbp
+
+	mov	0(vp), v0
+	mov	8(vp), v1
+
+	mov	R32(n_param), R32(%rbx)
+	mov	(up), %rax
+	lea	-8(up,n_param,8), up
+	lea	-8(rp,n_param,8), rp
+	mul	v0
+	neg	n
+	and	$3, R32(%rbx)
+	jz	L(b0)
+	cmp	$2, R32(%rbx)
+	jc	L(b1)
+	jz	L(b2)
+
+L(b3):	mov	%rax, w1
+	mov	%rdx, w2
+	xor	R32(w3), R32(w3)
+	mov	8(up,n,8), %rax
+	dec	n
+	jmp	L(lo3)
+
+L(b2):	mov	%rax, w2
+	mov	8(up,n,8), %rax
+	mov	%rdx, w3
+	xor	R32(w0), R32(w0)
+	add	$-2, n
+	jmp	L(lo2)
+
+L(b1):	mov	%rax, w3
+	mov	8(up,n,8), %rax
+	mov	%rdx, w0
+	xor	R32(w1), R32(w1)
+	inc	n
+	jmp	L(lo1)
+
+L(b0):	mov	$0, R32(w3)
+	mov	%rax, w0
+	mov	8(up,n,8), %rax
+	mov	%rdx, w1
+	xor	R32(w2), R32(w2)
+	jmp	L(lo0)
+
+	ALIGN(32)
+L(top):	mov	$0, R32(w1)
+	mul	v0
+	add	%rax, w3
+	mov	(up,n,8), %rax
+	adc	%rdx, w0
+	adc	$0, R32(w1)
+L(lo1):	mul	v1
+	add	w3, (rp,n,8)
+	mov	$0, R32(w3)
+	adc	%rax, w0
+	mov	$0, R32(w2)
+	mov	8(up,n,8), %rax
+	adc	%rdx, w1
+	mul	v0
+	add	%rax, w0
+	mov	8(up,n,8), %rax
+	adc	%rdx, w1
+	adc	$0, R32(w2)
+L(lo0):	mul	v1
+	add	w0, 8(rp,n,8)
+	adc	%rax, w1
+	adc	%rdx, w2
+	mov	16(up,n,8), %rax
+	mul	v0
+	add	%rax, w1
+	adc	%rdx, w2
+	adc	$0, R32(w3)
+	mov	16(up,n,8), %rax
+L(lo3):	mul	v1
+	add	w1, 16(rp,n,8)
+	adc	%rax, w2
+	adc	%rdx, w3
+	xor	R32(w0), R32(w0)
+	mov	24(up,n,8), %rax
+	mul	v0
+	add	%rax, w2
+	mov	24(up,n,8), %rax
+	adc	%rdx, w3
+	adc	$0, R32(w0)
+L(lo2):	mul	v1
+	add	w2, 24(rp,n,8)
+	adc	%rax, w3
+	adc	%rdx, w0
+	mov	32(up,n,8), %rax
+	add	$4, n
+	js	L(top)
+
+L(end):	xor	R32(w1), R32(w1)
+	mul	v0
+	add	%rax, w3
+	mov	(up), %rax
+	adc	%rdx, w0
+	adc	R32(w1), R32(w1)
+	mul	v1
+	add	w3, (rp)
+	adc	%rax, w0
+	adc	%rdx, w1
+	mov	w0, 8(rp)
+	mov	w1, %rax
+
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/k8/aorrlsh_n.asm b/third_party/gmp/mpn/x86_64/k8/aorrlsh_n.asm
new file mode 100644
index 0000000..ff3a184
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/k8/aorrlsh_n.asm
@@ -0,0 +1,217 @@
+dnl  AMD64 mpn_addlsh_n and mpn_rsblsh_n.  R = V2^k +- U.
+
+dnl  Copyright 2006, 2010-2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 2.87	< 3.85 for lshift + add_n
+C AMD K10	 2.75	< 3.85 for lshift + add_n
+C Intel P4	22	> 7.33 for lshift + add_n
+C Intel core2	 4.1	> 3.27 for lshift + add_n
+C Intel NHM	 4.4	> 3.75 for lshift + add_n
+C Intel SBR	 3.17	< 3.46 for lshift + add_n
+C Intel atom	 ?	? 8.75 for lshift + add_n
+C VIA nano	 4.7	< 6.25 for lshift + add_n
+
+C TODO
+C  * Can we propagate carry into rdx instead of using a special carry register?
+C    That could save enough insns to get to 10 cycles/iteration.
+
+define(`rp',       `%rdi')
+define(`up',       `%rsi')
+define(`vp_param', `%rdx')
+define(`n_param',  `%rcx')
+define(`cnt',      `%r8')
+
+define(`vp',    `%r12')
+define(`n',     `%rbp')
+
+ifdef(`OPERATION_addlsh_n',`
+  define(ADDSUB,       `add')
+  define(ADCSBB,       `adc')
+  define(func, mpn_addlsh_n)
+')
+ifdef(`OPERATION_rsblsh_n',`
+  define(ADDSUB,       `sub')
+  define(ADCSBB,       `sbb')
+  define(func, mpn_rsblsh_n)
+')
+
+MULFUNC_PROLOGUE(mpn_addlsh_n mpn_rsblsh_n)
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(func)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8d	')
+	push	%r12
+	push	%rbp
+	push	%rbx
+
+	mov	(vp_param), %rax	C load first V limb early
+
+	mov	$0, R32(n)
+	sub	n_param, n
+
+	lea	-16(up,n_param,8), up
+	lea	-16(rp,n_param,8), rp
+	lea	16(vp_param,n_param,8), vp
+
+	mov	n_param, %r9
+
+	mov	%r8, %rcx
+	mov	$1, R32(%r8)
+	shl	R8(%rcx), %r8
+
+	mul	%r8			C initial multiply
+
+	and	$3, R32(%r9)
+	jz	L(b0)
+	cmp	$2, R32(%r9)
+	jc	L(b1)
+	jz	L(b2)
+
+L(b3):	mov	%rax, %r11
+	ADDSUB	16(up,n,8), %r11
+	mov	-8(vp,n,8), %rax
+	sbb	R32(%rcx), R32(%rcx)
+	mov	%rdx, %rbx
+	mul	%r8
+	or	%rax, %rbx
+	mov	(vp,n,8), %rax
+	mov	%rdx, %r9
+	mul	%r8
+	or	%rax, %r9
+	add	$3, n
+	jnz	L(lo3)
+	jmp	L(cj3)
+
+L(b2):	mov	%rax, %rbx
+	mov	-8(vp,n,8), %rax
+	mov	%rdx, %r9
+	mul	%r8
+	or	%rax, %r9
+	add	$2, n
+	jz	L(cj2)
+	mov	%rdx, %r10
+	mov	-16(vp,n,8), %rax
+	mul	%r8
+	or	%rax, %r10
+	xor	R32(%rcx), R32(%rcx)	C clear carry register
+	jmp	L(lo2)
+
+L(b1):	mov	%rax, %r9
+	mov	%rdx, %r10
+	add	$1, n
+	jnz	L(gt1)
+	ADDSUB	8(up,n,8), %r9
+	jmp	L(cj1)
+L(gt1):	mov	-16(vp,n,8), %rax
+	mul	%r8
+	or	%rax, %r10
+	mov	%rdx, %r11
+	mov	-8(vp,n,8), %rax
+	mul	%r8
+	or	%rax, %r11
+	ADDSUB	8(up,n,8), %r9
+	ADCSBB	16(up,n,8), %r10
+	ADCSBB	24(up,n,8), %r11
+	mov	(vp,n,8), %rax
+	sbb	R32(%rcx), R32(%rcx)
+	jmp	L(lo1)
+
+L(b0):	mov	%rax, %r10
+	mov	%rdx, %r11
+	mov	-8(vp,n,8), %rax
+	mul	%r8
+	or	%rax, %r11
+	ADDSUB	16(up,n,8), %r10
+	ADCSBB	24(up,n,8), %r11
+	mov	(vp,n,8), %rax
+	sbb	R32(%rcx), R32(%rcx)
+	mov	%rdx, %rbx
+	mul	%r8
+	or	%rax, %rbx
+	mov	8(vp,n,8), %rax
+	add	$4, n
+	jz	L(end)
+
+	ALIGN(8)
+L(top):	mov	%rdx, %r9
+	mul	%r8
+	or	%rax, %r9
+	mov	%r10, -16(rp,n,8)
+L(lo3):	mov	%rdx, %r10
+	mov	-16(vp,n,8), %rax
+	mul	%r8
+	or	%rax, %r10
+	mov	%r11, -8(rp,n,8)
+L(lo2):	mov	%rdx, %r11
+	mov	-8(vp,n,8), %rax
+	mul	%r8
+	or	%rax, %r11
+	add	R32(%rcx), R32(%rcx)
+	ADCSBB	(up,n,8), %rbx
+	ADCSBB	8(up,n,8), %r9
+	ADCSBB	16(up,n,8), %r10
+	ADCSBB	24(up,n,8), %r11
+	mov	(vp,n,8), %rax
+	sbb	R32(%rcx), R32(%rcx)
+	mov	%rbx, (rp,n,8)
+L(lo1):	mov	%rdx, %rbx
+	mul	%r8
+	or	%rax, %rbx
+	mov	%r9, 8(rp,n,8)
+L(lo0):	mov	8(vp,n,8), %rax
+	add	$4, n
+	jnz	L(top)
+
+L(end):	mov	%rdx, %r9
+	mul	%r8
+	or	%rax, %r9
+	mov	%r10, -16(rp,n,8)
+L(cj3):	mov	%r11, -8(rp,n,8)
+L(cj2):	add	R32(%rcx), R32(%rcx)
+	ADCSBB	(up,n,8), %rbx
+	ADCSBB	8(up,n,8), %r9
+	mov	%rbx, (rp,n,8)
+L(cj1):	mov	%r9, 8(rp,n,8)
+	mov	%rdx, %rax
+	ADCSBB	$0, %rax
+	pop	%rbx
+	pop	%rbp
+	pop	%r12
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/k8/bdiv_q_1.asm b/third_party/gmp/mpn/x86_64/k8/bdiv_q_1.asm
new file mode 100644
index 0000000..1172b0d
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/k8/bdiv_q_1.asm
@@ -0,0 +1,179 @@
+dnl  AMD64 mpn_bdiv_q_1, mpn_pi1_bdiv_q_1 -- Hensel division by 1-limb divisor,
+dnl  returning quotient only.
+
+dnl  Copyright 2001, 2002, 2004-2006, 2009, 2011, 2012, 2017 Free Software
+dnl  Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	    cycles/limb
+C	     norm/unorm
+C AMD K8,K9	10	+
+C AMD K10	10	+
+C AMD bull	13.7	-
+C AMD pile	13.7	+
+C AMD steam
+C AMD excavator
+C AMD bobcat	15	-
+C AMD jaguar	16	-
+C Intel P4	33	=
+C Intel core2	13.25	=
+C Intel NHM	14	=
+C Intel SBR	8.5	-
+C Intel IBR	8.5	-
+C Intel HWL	8	=
+C Intel BWL	8	=
+C Intel SKL	8	=
+C Intel atom	42	--
+C Intel SLM	20.4	--
+C VIA nano
+
+C INPUT PARAMETERS
+define(`rp',		`%rdi')
+define(`up',		`%rsi')
+define(`n',		`%rdx')
+define(`d',		`%rcx')
+define(`di',		`%r8')		C	just mpn_pi1_bdiv_q_1
+define(`ncnt',		`%r9')		C	just mpn_pi1_bdiv_q_1
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_bdiv_q_1)
+	FUNC_ENTRY(4)
+	push	%rbx
+
+	mov	%rcx, %rax
+	xor	R32(%rcx), R32(%rcx)	C ncnt count
+	mov	%rdx, %r10
+
+	bt	$0, R32(%rax)
+	jnc	L(evn)			C skip bsf unless divisor is even
+
+L(odd):	mov	%rax, %rbx
+	shr	R32(%rax)
+	and	$127, R32(%rax)		C d/2, 7 bits
+
+	LEA(	binvert_limb_table, %rdx)
+
+	movzbl	(%rdx,%rax), R32(%rax)	C inv 8 bits
+
+	mov	%rbx, %r11		C d without twos
+
+	lea	(%rax,%rax), R32(%rdx)	C 2*inv
+	imul	R32(%rax), R32(%rax)	C inv*inv
+	imul	R32(%rbx), R32(%rax)	C inv*inv*d
+	sub	R32(%rax), R32(%rdx)	C inv = 2*inv - inv*inv*d, 16 bits
+
+	lea	(%rdx,%rdx), R32(%rax)	C 2*inv
+	imul	R32(%rdx), R32(%rdx)	C inv*inv
+	imul	R32(%rbx), R32(%rdx)	C inv*inv*d
+	sub	R32(%rdx), R32(%rax)	C inv = 2*inv - inv*inv*d, 32 bits
+
+	lea	(%rax,%rax), %r8	C 2*inv
+	imul	%rax, %rax		C inv*inv
+	imul	%rbx, %rax		C inv*inv*d
+	sub	%rax, %r8		C inv = 2*inv - inv*inv*d, 64 bits
+
+	jmp	L(pi1)
+
+L(evn):	bsf	%rax, %rcx
+	shr	R8(%rcx), %rax
+	jmp	L(odd)
+EPILOGUE()
+
+PROLOGUE(mpn_pi1_bdiv_q_1)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8	')
+IFDOS(`	mov	64(%rsp), %r9	')
+	push	%rbx
+
+	mov	%rcx, %r11		C d
+	mov	%rdx, %r10		C n
+	mov	%r9, %rcx		C ncnt
+
+L(pi1):	mov	(up), %rax		C up[0]
+
+	dec	%r10
+	jz	L(one)
+
+	mov	8(up), %rdx		C up[1]
+	lea	(up,%r10,8), up		C up end
+	lea	(rp,%r10,8), rp		C rp end
+	neg	%r10			C -n
+
+	shrd	R8(%rcx), %rdx, %rax
+
+	xor	R32(%rbx), R32(%rbx)
+	jmp	L(ent)
+
+	ALIGN(8)
+L(top):
+	C rax	q
+	C rbx	carry bit, 0 or 1
+	C rcx	ncnt
+	C rdx
+	C r10	counter, limbs, negative
+	C r11	d
+
+	mul	%r11			C carry limb in rdx
+	mov	(up,%r10,8), %rax
+	mov	8(up,%r10,8), %r9
+	shrd	R8(%rcx), %r9, %rax
+	nop
+	sub	%rbx, %rax		C apply carry bit
+	setc	R8(%rbx)
+	sub	%rdx, %rax		C apply carry limb
+	adc	$0, R32(%rbx)
+L(ent):	imul	%r8, %rax
+	mov	%rax, (rp,%r10,8)
+	inc	%r10
+	jnz	L(top)
+
+	mul	%r11			C carry limb in rdx
+	mov	(up), %rax		C up high limb
+	shr	R8(%rcx), %rax
+	sub	%rbx, %rax		C apply carry bit
+	sub	%rdx, %rax		C apply carry limb
+	imul	%r8, %rax
+	mov	%rax, (rp)
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+
+L(one):	shr	R8(%rcx), %rax
+	imul	%r8, %rax
+	mov	%rax, (rp)
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/k8/div_qr_1n_pi1.asm b/third_party/gmp/mpn/x86_64/k8/div_qr_1n_pi1.asm
new file mode 100644
index 0000000..86de08c
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/k8/div_qr_1n_pi1.asm
@@ -0,0 +1,249 @@
+dnl  x86-64 mpn_div_qr_1n_pi1
+dnl  -- Divide an mpn number by a normalized single-limb number,
+dnl     using a single-limb inverse.
+
+dnl  Contributed to the GNU project by Niels Möller
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C		c/l
+C AMD K8,K9	11
+C AMD K10	11
+C AMD bull	16
+C AMD pile	14.25
+C AMD steam	 ?
+C AMD bobcat	16
+C AMD jaguar	 ?
+C Intel P4	47.5	poor
+C Intel core	28.5	very poor
+C Intel NHM	29	very poor
+C Intel SBR	16	poor
+C Intel IBR	13.5
+C Intel HWL	12
+C Intel BWL	 ?
+C Intel atom	53	very poor
+C VIA nano	19
+
+
+C INPUT Parameters
+define(`QP', `%rdi')
+define(`UP', `%rsi')
+define(`UN_INPUT', `%rdx')
+define(`U1', `%rcx')	C Also in %rax
+define(`D', `%r8')
+define(`DINV', `%r9')
+
+C Invariants
+define(`B2', `%rbp')
+define(`B2md', `%rbx')
+
+C Variables
+define(`UN', `%r8')	C Overlaps D input
+define(`T', `%r10')
+define(`U0', `%r11')
+define(`U2', `%r12')
+define(`Q0', `%r13')
+define(`Q1', `%r14')
+define(`Q2', `%r15')
+
+ABI_SUPPORT(STD64)
+
+	ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_div_qr_1n_pi1)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8	')
+IFDOS(`	mov	64(%rsp), %r9	')
+	dec	UN_INPUT
+	jnz	L(first)
+
+	C Just a single 2/1 division.
+	C T, U0 are allocated in scratch registers
+	lea	1(U1), T
+	mov	U1, %rax
+	mul	DINV
+	mov	(UP), U0
+	add	U0, %rax
+	adc	T, %rdx
+	mov	%rdx, T
+	imul	D, %rdx
+	sub	%rdx, U0
+	cmp	U0, %rax
+	lea	(U0, D), %rax
+	cmovnc	U0, %rax
+	sbb	$0, T
+	cmp	D, %rax
+	jc	L(single_div_done)
+	sub	D, %rax
+	add	$1, T
+L(single_div_done):
+	mov	T, (QP)
+	FUNC_EXIT()
+	ret
+L(first):
+	C FIXME: Could delay some of these until we enter the loop.
+	push	%r15
+	push	%r14
+	push	%r13
+	push	%r12
+	push	%rbx
+	push	%rbp
+
+	mov	D, B2
+	imul	DINV, B2
+	neg	B2
+	mov	B2, B2md
+	sub	D, B2md
+
+	C D not needed until final reduction
+	push	D
+	mov	UN_INPUT, UN	C Clobbers D
+
+	mov	DINV, %rax
+	mul	U1
+	mov	%rax, Q0
+	add	U1, %rdx
+	mov	%rdx, T
+
+	mov	B2, %rax
+	mul	U1
+	mov	-8(UP, UN, 8), U0
+	mov	(UP, UN, 8), U1
+	mov	T, (QP, UN, 8)
+	add	%rax, U0
+	adc	%rdx, U1
+	sbb	U2, U2
+	dec	UN
+	mov	U1, %rax
+	jz	L(final)
+	mov	$0, R32(Q1)
+
+	ALIGN(16)
+
+	C Loop is 28 instructions, 30 K8/K10 decoder slots, should run
+	C in 10 cycles. At entry, %rax holds an extra copy of U1, Q1
+	C is zero, and carry holds an extra copy of U2.
+L(loop):
+	C {Q2, Q1, Q0} <-- DINV * U1 + B (Q0 + U2 DINV) + B^2 U2
+	C Remains to add in B (U1 + c)
+	cmovc	DINV, Q1
+	mov	U2, Q2
+	neg	Q2
+	mul	DINV
+	add	%rdx, Q1
+	adc	$0, Q2
+	add	Q0, Q1
+	mov	%rax, Q0
+	mov	B2, %rax
+	lea	(B2md, U0), T
+	adc	$0, Q2
+
+	C {U2, U1, U0} <-- (U0 + U2 B2 -c U) B + U1 B2 + u
+	mul	U1
+	and	B2, U2
+	add	U2, U0
+	cmovnc	U0, T
+
+	C {QP+UN, ...} <-- {QP+UN, ...} + {Q2, Q1} + U1 + c
+	adc	U1, Q1
+	mov	-8(UP, UN, 8), U0
+	adc	Q2, 8(QP, UN, 8)
+	jc	L(q_incr)
+L(q_incr_done):
+	add	%rax, U0
+	mov	T, %rax
+	adc	%rdx, %rax
+	mov	Q1, (QP, UN, 8)
+	mov	$0, R32(Q1)
+	sbb	U2, U2
+	dec	UN
+	mov	%rax, U1
+	jnz	L(loop)
+
+L(final):
+	pop	D
+
+	mov	U2, Q1
+	and	D, U2
+	sub	U2, %rax
+	neg	Q1
+
+	mov	%rax, U1
+	sub	D, %rax
+	cmovc	U1, %rax
+	sbb	$-1, Q1
+
+	lea	1(%rax), T
+	mul	DINV
+	add	U0, %rax
+	adc	T, %rdx
+	mov	%rdx, T
+	imul	D, %rdx
+	sub	%rdx, U0
+	cmp	U0, %rax
+	lea	(U0, D), %rax
+	cmovnc	U0, %rax
+	sbb	$0, T
+	cmp	D, %rax
+	jc	L(div_done)
+	sub	D, %rax
+	add	$1, T
+L(div_done):
+	add	T, Q0
+	mov	Q0, (QP)
+	adc	Q1, 8(QP)
+	jnc	L(done)
+L(final_q_incr):
+	addq	$1, 16(QP)
+	lea	8(QP), QP
+	jc	L(final_q_incr)
+
+L(done):
+	pop	%rbp
+	pop	%rbx
+	pop	%r12
+	pop	%r13
+	pop	%r14
+	pop	%r15
+	FUNC_EXIT()
+	ret
+
+L(q_incr):
+	C U1 is not live, so use it for indexing
+	lea	16(QP, UN, 8), U1
+L(q_incr_loop):
+	addq	$1, (U1)
+	jnc	L(q_incr_done)
+	lea	8(U1), U1
+	jmp	L(q_incr_loop)
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/k8/gmp-mparam.h b/third_party/gmp/mpn/x86_64/k8/gmp-mparam.h
new file mode 100644
index 0000000..d87cc3b
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/k8/gmp-mparam.h
@@ -0,0 +1,237 @@
+/* AMD K8 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+#if 0
+#undef mpn_sublsh_n
+#define mpn_sublsh_n(rp,up,vp,n,c)					\
+  (((rp) == (up)) ? mpn_submul_1 (rp, vp, n, CNST_LIMB(1) << (c))	\
+   : MPN(mpn_sublsh_n)(rp,up,vp,n,c))
+#endif
+
+/* 2500 MHz K8 Brisbane */
+/* FFT tuning limit = 115,768,433 */
+/* Generated by tuneup.c, 2019-10-18, gcc 8.3 */
+
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          5
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          2
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        14
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        35
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD      9
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1_NORM_THRESHOLD              1
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           16
+
+#define DIV_1_VS_MUL_1_PERCENT             309
+
+#define MUL_TOOM22_THRESHOLD                28
+#define MUL_TOOM33_THRESHOLD                81
+#define MUL_TOOM44_THRESHOLD               232
+#define MUL_TOOM6H_THRESHOLD               324
+#define MUL_TOOM8H_THRESHOLD               478
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      97
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     153
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     154
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     160
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     226
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 34
+#define SQR_TOOM3_THRESHOLD                114
+#define SQR_TOOM4_THRESHOLD                336
+#define SQR_TOOM6_THRESHOLD                430
+#define SQR_TOOM8_THRESHOLD                  0  /* always */
+
+#define MULMID_TOOM42_THRESHOLD             36
+
+#define MULMOD_BNM1_THRESHOLD               17
+#define SQRMOD_BNM1_THRESHOLD               19
+
+#define MUL_FFT_MODF_THRESHOLD             654  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    654, 5}, {     21, 6}, {     11, 5}, {     23, 6}, \
+    {     12, 5}, {     25, 6}, {     13, 5}, {     27, 6}, \
+    {     27, 7}, {     14, 6}, {     29, 7}, {     15, 6}, \
+    {     31, 7}, {     29, 8}, {     15, 7}, {     32, 8}, \
+    {     17, 7}, {     37, 8}, {     19, 7}, {     39, 8}, \
+    {     21, 7}, {     44, 8}, {     23, 7}, {     47, 8}, \
+    {     25, 7}, {     51, 8}, {     31, 7}, {     63, 8}, \
+    {     37, 9}, {     19, 8}, {     43, 9}, {     23, 8}, \
+    {     53, 9}, {     27, 8}, {     57, 9}, {     31, 8}, \
+    {     67, 9}, {     35, 8}, {     71, 9}, {     39, 8}, \
+    {     81, 9}, {     43,10}, {     23, 9}, {     55, 8}, \
+    {    111,10}, {     31, 9}, {     71,10}, {     39, 9}, \
+    {     87,10}, {     47, 9}, {     99,10}, {     55, 9}, \
+    {    111,11}, {     31,10}, {     63, 9}, {    131,10}, \
+    {     71, 9}, {    147,10}, {     87,11}, {     47,10}, \
+    {    111,11}, {     63,10}, {    143,11}, {     79,10}, \
+    {    167,11}, {     95,10}, {    199,11}, {    111,12}, \
+    {     63,11}, {    143,10}, {    287,11}, {    159,12}, \
+    {     95,11}, {    191,10}, {    383,11}, {    207,10}, \
+    {    415,13}, {     63,12}, {    127,11}, {    255,10}, \
+    {    511,11}, {    271,10}, {    543,11}, {    287,12}, \
+    {    159,11}, {    319,10}, {    639,11}, {    335,10}, \
+    {    671,11}, {    351,12}, {    191,11}, {    415,12}, \
+    {    223,11}, {    447,13}, {    127,12}, {    255,11}, \
+    {    543,12}, {    287,11}, {    575,10}, {   1151,11}, \
+    {    607,12}, {    319,11}, {    671,12}, {    351,11}, \
+    {    703,13}, {    191,12}, {    383,11}, {    767,12}, \
+    {    415,11}, {    831,12}, {    447,11}, {    895,12}, \
+    {    479,14}, {    127,13}, {    255,12}, {    543,11}, \
+    {   1087,12}, {    575,11}, {   1151,12}, {    607,13}, \
+    {    319,12}, {    735,13}, {    383,12}, {    831,13}, \
+    {    447,12}, {    959,14}, {    255,13}, {    511,12}, \
+    {   1087,13}, {    575,12}, {   1215,13}, {    639,12}, \
+    {   1279,13}, {    703,12}, {   1407,14}, {    383,13}, \
+    {    767,12}, {   1535,13}, {    831,12}, {   1663,13}, \
+    {    959,15}, {    255,14}, {    511,13}, {   1215,14}, \
+    {    639,13}, {   1471,14}, {    767,13}, {   1663,14}, \
+    {    895,13}, {   1855,15}, {    511,14}, {   1023,13}, \
+    {   2047,14}, {   1151,13}, {   2367,14}, {   1407,15}, \
+    {    767,14}, {   1791,16}, {    511,15}, {   1023,14}, \
+    {   2303,15}, {   1279,14}, {   2687,15}, {   1535,14}, \
+    {   3199,15}, {   1791,16}, {   1023,15}, {   2047,14}, \
+    {   4223,15}, {   2303,14}, {   4735,15}, {   2559,16}, \
+    {   1535,15}, {   3071,14}, {   6271,15}, {   3327,17}, \
+    { 131072,18}, { 262144,19}, { 524288,20}, {1048576,21}, \
+    {2097152,22}, {4194304,23}, {8388608,24} }
+#define MUL_FFT_TABLE3_SIZE 183
+#define MUL_FFT_THRESHOLD                11520
+
+#define SQR_FFT_MODF_THRESHOLD             540  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    540, 5}, {     21, 6}, {     11, 5}, {     23, 6}, \
+    {     12, 5}, {     25, 6}, {     13, 5}, {     27, 6}, \
+    {     16, 5}, {     33, 6}, {     29, 7}, {     15, 6}, \
+    {     31, 7}, {     16, 6}, {     33, 7}, {     33, 8}, \
+    {     17, 7}, {     37, 8}, {     19, 7}, {     39, 8}, \
+    {     21, 7}, {     43, 8}, {     23, 7}, {     47, 8}, \
+    {     25, 7}, {     51, 8}, {     29, 9}, {     15, 8}, \
+    {     37, 9}, {     19, 8}, {     43, 9}, {     23, 8}, \
+    {     51, 9}, {     27, 8}, {     55, 9}, {     31, 8}, \
+    {     65, 9}, {     35, 8}, {     71, 9}, {     43,10}, \
+    {     23, 9}, {     55,10}, {     31, 9}, {     71,10}, \
+    {     39, 9}, {     83,10}, {     47, 9}, {     99,10}, \
+    {     55, 9}, {    111,11}, {     31,10}, {     63, 9}, \
+    {    127,10}, {     87,11}, {     47,10}, {    111,12}, \
+    {     31,11}, {     63,10}, {    143,11}, {     79,10}, \
+    {    167,11}, {     95,10}, {    191,11}, {    111,12}, \
+    {     63,11}, {    127, 9}, {    511,11}, {    143,10}, \
+    {    287, 9}, {    575,11}, {    159,12}, {     95,11}, \
+    {    191,10}, {    383, 9}, {    767,11}, {    207,10}, \
+    {    415,13}, {     63,12}, {    127,10}, {    511, 9}, \
+    {   1023,11}, {    271,10}, {    543, 9}, {   1087,11}, \
+    {    287,10}, {    575,12}, {    159,11}, {    319,10}, \
+    {    639,11}, {    335,10}, {    671,11}, {    351,10}, \
+    {    703,12}, {    191,11}, {    383,10}, {    767,11}, \
+    {    415,10}, {    831,12}, {    223,11}, {    447,13}, \
+    {    127,11}, {    511,10}, {   1023,11}, {    543,10}, \
+    {   1087,12}, {    287,11}, {    575,10}, {   1151,11}, \
+    {    607,12}, {    319,11}, {    639,10}, {   1279,11}, \
+    {    671,12}, {    351,11}, {    703,13}, {    191,12}, \
+    {    383,11}, {    767,12}, {    415,11}, {    831,12}, \
+    {    447,11}, {    895,14}, {    127,12}, {    511,11}, \
+    {   1023,12}, {    543,11}, {   1087,12}, {    575,11}, \
+    {   1151,12}, {    607,11}, {   1215,13}, {    319,12}, \
+    {    639,11}, {   1279,12}, {    671,11}, {   1343,12}, \
+    {    703,11}, {   1407,12}, {    735,13}, {    383,12}, \
+    {    767,11}, {   1535,12}, {    831,13}, {    447,12}, \
+    {    959,13}, {    511,12}, {   1087,13}, {    575,12}, \
+    {   1215,13}, {    639,12}, {   1343,13}, {    703,12}, \
+    {   1407,14}, {    383,13}, {    767,12}, {   1535,13}, \
+    {    831,12}, {   1663,13}, {    895,12}, {   1791,13}, \
+    {    959,14}, {    511,13}, {   1215,14}, {    639,13}, \
+    {   1471,14}, {    767,13}, {   1663,14}, {    895,13}, \
+    {   1791,15}, {    511,14}, {   1023,13}, {   2111,14}, \
+    {   1151,13}, {   2303,14}, {   1407,15}, {    767,14}, \
+    {   1791,16}, {    511,15}, {   1023,14}, {   2303,15}, \
+    {   1279,14}, {   2687,15}, {   1535,14}, {   3199,15}, \
+    {   1791,16}, {   1023,15}, {   2047,14}, {   4223,15}, \
+    {   2303,14}, {   4863,15}, {   2559,16}, {   1535,15}, \
+    {   3071,14}, {   6271,15}, {   3327,17}, { 131072,18}, \
+    { 262144,19}, { 524288,20}, {1048576,21}, {2097152,22}, \
+    {4194304,23}, {8388608,24} }
+#define SQR_FFT_TABLE3_SIZE 202
+#define SQR_FFT_THRESHOLD                 7296
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  61
+#define MULLO_MUL_N_THRESHOLD            22239
+#define SQRLO_BASECASE_THRESHOLD             8
+#define SQRLO_DC_THRESHOLD                   0  /* never mpn_sqrlo_basecase */
+#define SQRLO_SQR_THRESHOLD              14281
+
+#define DC_DIV_QR_THRESHOLD                 47
+#define DC_DIVAPPR_Q_THRESHOLD             266
+#define DC_BDIV_QR_THRESHOLD                38
+#define DC_BDIV_Q_THRESHOLD                104
+
+#define INV_MULMOD_BNM1_THRESHOLD           54
+#define INV_NEWTON_THRESHOLD               252
+#define INV_APPR_THRESHOLD                 250
+
+#define BINV_NEWTON_THRESHOLD              258
+#define REDC_1_TO_REDC_2_THRESHOLD          35
+#define REDC_2_TO_REDC_N_THRESHOLD          79
+
+#define MU_DIV_QR_THRESHOLD               2089
+#define MU_DIVAPPR_Q_THRESHOLD            1895
+#define MUPI_DIV_QR_THRESHOLD               99
+#define MU_BDIV_QR_THRESHOLD              1787
+#define MU_BDIV_Q_THRESHOLD               1895
+
+#define POWM_SEC_TABLE  1,16,194,960,2825
+
+#define GET_STR_DC_THRESHOLD                16
+#define GET_STR_PRECOMPUTE_THRESHOLD        26
+#define SET_STR_DC_THRESHOLD               248
+#define SET_STR_PRECOMPUTE_THRESHOLD      1747
+
+#define FAC_DSC_THRESHOLD                 1240
+#define FAC_ODD_THRESHOLD                   27
+
+#define MATRIX22_STRASSEN_THRESHOLD         21
+#define HGCD2_DIV1_METHOD                    3  /* 4.10% faster than 5 */
+#define HGCD_THRESHOLD                     141
+#define HGCD_APPR_THRESHOLD                181
+#define HGCD_REDUCE_THRESHOLD             4633
+#define GCD_DC_THRESHOLD                   622
+#define GCDEXT_DC_THRESHOLD                496
+#define JACOBI_BASE_METHOD                   1  /* 0.97% faster than 3 */
+
+/* Tuneup completed successfully, took 131832 seconds */
diff --git a/third_party/gmp/mpn/x86_64/k8/mul_basecase.asm b/third_party/gmp/mpn/x86_64/k8/mul_basecase.asm
new file mode 100644
index 0000000..ca2efb9
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/k8/mul_basecase.asm
@@ -0,0 +1,469 @@
+dnl  AMD64 mpn_mul_basecase.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund and David Harvey.
+
+dnl  Copyright 2008, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 2.375
+C AMD K10	 2.375
+C Intel P4	15-16
+C Intel core2	 4.45
+C Intel corei	 4.35
+C Intel atom	 ?
+C VIA nano	 4.5
+
+C The inner loops of this code are the result of running a code generation and
+C optimization tool suite written by David Harvey and Torbjorn Granlund.
+
+C TODO
+C  * Use fewer registers.  (how??? I can't see it -- david)
+C  * Avoid some "mov $0,r" and instead use "xor r,r".
+C  * Can the top of each L(addmul_outer_n) prologue be folded into the
+C    mul_1/mul_2 prologues, saving a LEA (%rip)? It would slow down the
+C    case where vn = 1 or 2; is it worth it?
+
+C INPUT PARAMETERS
+define(`rp',      `%rdi')
+define(`up',      `%rsi')
+define(`un_param',`%rdx')
+define(`vp',      `%rcx')
+define(`vn',      `%r8')
+
+define(`v0', `%r12')
+define(`v1', `%r9')
+
+define(`w0', `%rbx')
+define(`w1', `%r15')
+define(`w2', `%rbp')
+define(`w3', `%r10')
+
+define(`n',  `%r11')
+define(`outer_addr', `%r14')
+define(`un',  `%r13')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_mul_basecase)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8d	')
+	push	%rbx
+	push	%rbp
+	push	%r12
+	push	%r13
+	push	%r14
+	push	%r15
+
+	xor	R32(un), R32(un)
+	mov	(up), %rax
+	mov	(vp), v0
+
+	sub	un_param, un		C rdx used by mul
+	mov	un, n
+	mov	R32(un_param), R32(w0)
+
+	lea	(rp,un_param,8), rp
+	lea	(up,un_param,8), up
+
+	mul	v0
+
+	test	$1, R8(vn)
+	jz	L(mul_2)
+
+C ===========================================================
+C     mul_1 for vp[0] if vn is odd
+
+L(mul_1):
+	and	$3, R32(w0)
+	jz	L(mul_1_prologue_0)
+	cmp	$2, R32(w0)
+	jc	L(mul_1_prologue_1)
+	jz	L(mul_1_prologue_2)
+
+L(mul_1_prologue_3):
+	add	$-1, n
+	lea	L(addmul_outer_3)(%rip), outer_addr
+	mov	%rax, w3
+	mov	%rdx, w0
+	jmp	L(mul_1_entry_3)
+
+L(mul_1_prologue_0):
+	mov	%rax, w2
+	mov	%rdx, w3		C note: already w0 == 0
+	lea	L(addmul_outer_0)(%rip), outer_addr
+	jmp	L(mul_1_entry_0)
+
+L(mul_1_prologue_1):
+	cmp	$-1, un
+	jne	2f
+	mov	%rax, -8(rp)
+	mov	%rdx, (rp)
+	jmp	L(ret)
+2:	add	$1, n
+	lea	L(addmul_outer_1)(%rip), outer_addr
+	mov	%rax, w1
+	mov	%rdx, w2
+	xor	R32(w3), R32(w3)
+	mov	(up,n,8), %rax
+	jmp	L(mul_1_entry_1)
+
+L(mul_1_prologue_2):
+	add	$-2, n
+	lea	L(addmul_outer_2)(%rip), outer_addr
+	mov	%rax, w0
+	mov	%rdx, w1
+	mov	24(up,n,8), %rax
+	xor	R32(w2), R32(w2)
+	xor	R32(w3), R32(w3)
+	jmp	L(mul_1_entry_2)
+
+
+	C this loop is 10 c/loop = 2.5 c/l on K8, for all up/rp alignments
+
+	ALIGN(16)
+L(mul_1_top):
+	mov	w0, -16(rp,n,8)
+	add	%rax, w1
+	mov	(up,n,8), %rax
+	adc	%rdx, w2
+L(mul_1_entry_1):
+	xor	R32(w0), R32(w0)
+	mul	v0
+	mov	w1, -8(rp,n,8)
+	add	%rax, w2
+	adc	%rdx, w3
+L(mul_1_entry_0):
+	mov	8(up,n,8), %rax
+	mul	v0
+	mov	w2, (rp,n,8)
+	add	%rax, w3
+	adc	%rdx, w0
+L(mul_1_entry_3):
+	mov	16(up,n,8), %rax
+	mul	v0
+	mov	w3, 8(rp,n,8)
+	xor	R32(w2), R32(w2)	C zero
+	mov	w2, w3			C zero
+	add	%rax, w0
+	mov	24(up,n,8), %rax
+	mov	w2, w1			C zero
+	adc	%rdx, w1
+L(mul_1_entry_2):
+	mul	v0
+	add	$4, n
+	js	L(mul_1_top)
+
+	mov	w0, -16(rp)
+	add	%rax, w1
+	mov	w1, -8(rp)
+	adc	%rdx, w2
+	mov	w2, (rp)
+
+	add	$-1, vn			C vn -= 1
+	jz	L(ret)
+
+	mov	8(vp), v0
+	mov	16(vp), v1
+
+	lea	8(vp), vp		C vp += 1
+	lea	8(rp), rp		C rp += 1
+
+	jmp	*outer_addr
+
+C ===========================================================
+C     mul_2 for vp[0], vp[1] if vn is even
+
+	ALIGN(16)
+L(mul_2):
+	mov	8(vp), v1
+
+	and	$3, R32(w0)
+	jz	L(mul_2_prologue_0)
+	cmp	$2, R32(w0)
+	jz	L(mul_2_prologue_2)
+	jc	L(mul_2_prologue_1)
+
+L(mul_2_prologue_3):
+	lea	L(addmul_outer_3)(%rip), outer_addr
+	add	$2, n
+	mov	%rax, -16(rp,n,8)
+	mov	%rdx, w2
+	xor	R32(w3), R32(w3)
+	xor	R32(w0), R32(w0)
+	mov	-16(up,n,8), %rax
+	jmp	L(mul_2_entry_3)
+
+	ALIGN(16)
+L(mul_2_prologue_0):
+	add	$3, n
+	mov	%rax, w0
+	mov	%rdx, w1
+	xor	R32(w2), R32(w2)
+	mov	-24(up,n,8), %rax
+	lea	L(addmul_outer_0)(%rip), outer_addr
+	jmp	L(mul_2_entry_0)
+
+	ALIGN(16)
+L(mul_2_prologue_1):
+	mov	%rax, w3
+	mov	%rdx, w0
+	xor	R32(w1), R32(w1)
+	lea	L(addmul_outer_1)(%rip), outer_addr
+	jmp	L(mul_2_entry_1)
+
+	ALIGN(16)
+L(mul_2_prologue_2):
+	add	$1, n
+	lea	L(addmul_outer_2)(%rip), outer_addr
+	mov	$0, R32(w0)
+	mov	$0, R32(w1)
+	mov	%rax, w2
+	mov	-8(up,n,8), %rax
+	mov	%rdx, w3
+	jmp	L(mul_2_entry_2)
+
+	C this loop is 18 c/loop = 2.25 c/l on K8, for all up/rp alignments
+
+	ALIGN(16)
+L(mul_2_top):
+	mov	-32(up,n,8), %rax
+	mul	v1
+	add	%rax, w0
+	adc	%rdx, w1
+	mov	-24(up,n,8), %rax
+	xor	R32(w2), R32(w2)
+	mul	v0
+	add	%rax, w0
+	mov	-24(up,n,8), %rax
+	adc	%rdx, w1
+	adc	$0, R32(w2)
+L(mul_2_entry_0):
+	mul	v1
+	add	%rax, w1
+	mov	w0, -24(rp,n,8)
+	adc	%rdx, w2
+	mov	-16(up,n,8), %rax
+	mul	v0
+	mov	$0, R32(w3)
+	add	%rax, w1
+	adc	%rdx, w2
+	mov	-16(up,n,8), %rax
+	adc	$0, R32(w3)
+	mov	$0, R32(w0)
+	mov	w1, -16(rp,n,8)
+L(mul_2_entry_3):
+	mul	v1
+	add	%rax, w2
+	mov	-8(up,n,8), %rax
+	adc	%rdx, w3
+	mov	$0, R32(w1)
+	mul	v0
+	add	%rax, w2
+	mov	-8(up,n,8), %rax
+	adc	%rdx, w3
+	adc	R32(w1), R32(w0)	C adc $0, w0
+L(mul_2_entry_2):
+	mul	v1
+	add	%rax, w3
+	mov	w2, -8(rp,n,8)
+	adc	%rdx, w0
+	mov	(up,n,8), %rax
+	mul	v0
+	add	%rax, w3
+	adc	%rdx, w0
+	adc	$0, R32(w1)
+L(mul_2_entry_1):
+	add	$4, n
+	mov	w3, -32(rp,n,8)
+	js	L(mul_2_top)
+
+	mov	-32(up,n,8), %rax	C FIXME: n is constant
+	mul	v1
+	add	%rax, w0
+	mov	w0, (rp)
+	adc	%rdx, w1
+	mov	w1, 8(rp)
+
+	add	$-2, vn			C vn -= 2
+	jz	L(ret)
+
+	mov	16(vp), v0
+	mov	24(vp), v1
+
+	lea	16(vp), vp		C vp += 2
+	lea	16(rp), rp		C rp += 2
+
+	jmp	*outer_addr
+
+
+C ===========================================================
+C     addmul_2 for remaining vp's
+
+	C in the following prologues, we reuse un to store the
+	C adjusted value of n that is reloaded on each iteration
+
+L(addmul_outer_0):
+	add	$3, un
+	lea	0(%rip), outer_addr
+
+	mov	un, n
+	mov	-24(up,un,8), %rax
+	mul	v0
+	mov	%rax, w0
+	mov	-24(up,un,8), %rax
+	mov	%rdx, w1
+	xor	R32(w2), R32(w2)
+	jmp	L(addmul_entry_0)
+
+L(addmul_outer_1):
+	mov	un, n
+	mov	(up,un,8), %rax
+	mul	v0
+	mov	%rax, w3
+	mov	(up,un,8), %rax
+	mov	%rdx, w0
+	xor	R32(w1), R32(w1)
+	jmp	L(addmul_entry_1)
+
+L(addmul_outer_2):
+	add	$1, un
+	lea	0(%rip), outer_addr
+
+	mov	un, n
+	mov	-8(up,un,8), %rax
+	mul	v0
+	xor	R32(w0), R32(w0)
+	mov	%rax, w2
+	xor	R32(w1), R32(w1)
+	mov	%rdx, w3
+	mov	-8(up,un,8), %rax
+	jmp	L(addmul_entry_2)
+
+L(addmul_outer_3):
+	add	$2, un
+	lea	0(%rip), outer_addr
+
+	mov	un, n
+	mov	-16(up,un,8), %rax
+	xor	R32(w3), R32(w3)
+	mul	v0
+	mov	%rax, w1
+	mov	-16(up,un,8), %rax
+	mov	%rdx, w2
+	jmp	L(addmul_entry_3)
+
+	C this loop is 19 c/loop = 2.375 c/l on K8, for all up/rp alignments
+
+	ALIGN(16)
+L(addmul_top):
+	add	w3, -32(rp,n,8)
+	adc	%rax, w0
+	mov	-24(up,n,8), %rax
+	adc	%rdx, w1
+	xor	R32(w2), R32(w2)
+	mul	v0
+	add	%rax, w0
+	mov	-24(up,n,8), %rax
+	adc	%rdx, w1
+	adc	R32(w2), R32(w2)	C adc $0, w2
+L(addmul_entry_0):
+	mul	v1
+	xor	R32(w3), R32(w3)
+	add	w0, -24(rp,n,8)
+	adc	%rax, w1
+	mov	-16(up,n,8), %rax
+	adc	%rdx, w2
+	mul	v0
+	add	%rax, w1
+	mov	-16(up,n,8), %rax
+	adc	%rdx, w2
+	adc	$0, R32(w3)
+L(addmul_entry_3):
+	mul	v1
+	add	w1, -16(rp,n,8)
+	adc	%rax, w2
+	mov	-8(up,n,8), %rax
+	adc	%rdx, w3
+	mul	v0
+	xor	R32(w0), R32(w0)
+	add	%rax, w2
+	adc	%rdx, w3
+	mov	$0, R32(w1)
+	mov	-8(up,n,8), %rax
+	adc	R32(w1), R32(w0)	C adc $0, w0
+L(addmul_entry_2):
+	mul	v1
+	add	w2, -8(rp,n,8)
+	adc	%rax, w3
+	adc	%rdx, w0
+	mov	(up,n,8), %rax
+	mul	v0
+	add	%rax, w3
+	mov	(up,n,8), %rax
+	adc	%rdx, w0
+	adc	$0, R32(w1)
+L(addmul_entry_1):
+	mul	v1
+	add	$4, n
+	js	L(addmul_top)
+
+	add	w3, -8(rp)
+	adc	%rax, w0
+	mov	w0, (rp)
+	adc	%rdx, w1
+	mov	w1, 8(rp)
+
+	add	$-2, vn			C vn -= 2
+	jz	L(ret)
+
+	lea	16(rp), rp		C rp += 2
+	lea	16(vp), vp		C vp += 2
+
+	mov	(vp), v0
+	mov	8(vp), v1
+
+	jmp	*outer_addr
+
+	ALIGN(16)
+L(ret):	pop	%r15
+	pop	%r14
+	pop	%r13
+	pop	%r12
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/k8/mullo_basecase.asm b/third_party/gmp/mpn/x86_64/k8/mullo_basecase.asm
new file mode 100644
index 0000000..fa00f42
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/k8/mullo_basecase.asm
@@ -0,0 +1,436 @@
+dnl  AMD64 mpn_mullo_basecase.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2008, 2009, 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C The inner loops of this code are the result of running a code generation and
+C optimisation tool suite written by David Harvey and Torbjorn Granlund.
+
+C NOTES
+C   * There is a major stupidity in that we call mpn_mul_1 initially, for a
+C     large trip count.  Instead, we should start with mul_2 for any operand
+C     size congruence class.
+C   * Stop iterating addmul_2 earlier, falling into straight-line triangle code
+C     for the last 2-3 iterations.
+C   * Perhaps implement n=4 special code.
+C   * The reload of the outer loop jump address hurts branch prediction.
+C   * The addmul_2 loop ends with an MUL whose high part is not used upon loop
+C     exit.
+
+C INPUT PARAMETERS
+define(`rp',	   `%rdi')
+define(`up',	   `%rsi')
+define(`vp_param', `%rdx')
+define(`n',	   `%rcx')
+
+define(`vp',	`%r11')
+define(`outer_addr', `%r8')
+define(`j',	`%r9')
+define(`v0',	`%r13')
+define(`v1',	`%r14')
+define(`w0',	`%rbx')
+define(`w1',	`%r15')
+define(`w2',	`%rbp')
+define(`w3',	`%r10')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_mullo_basecase)
+	FUNC_ENTRY(4)
+	cmp	$4, n
+	jge	L(gen)
+	mov	(up), %rax		C u0
+	mov	(vp_param), %r8		C v0
+
+	lea	L(tab)(%rip), %r9
+ifdef(`PIC',
+`	movslq	(%r9,%rcx,4), %r10
+	add	%r10, %r9
+	jmp	*%r9
+',`
+	jmp	*(%r9,n,8)
+')
+	JUMPTABSECT
+	ALIGN(8)
+L(tab):	JMPENT(	L(tab), L(tab))			C not allowed
+	JMPENT(	L(1), L(tab))			C 1
+	JMPENT(	L(2), L(tab))			C 2
+	JMPENT(	L(3), L(tab))			C 3
+dnl	JMPENT(	L(0m4), L(tab))			C 4
+dnl	JMPENT(	L(1m4), L(tab))			C 5
+dnl	JMPENT(	L(2m4), L(tab))			C 6
+dnl	JMPENT(	L(3m4), L(tab))			C 7
+dnl	JMPENT(	L(0m4), L(tab))			C 8
+dnl	JMPENT(	L(1m4), L(tab))			C 9
+dnl	JMPENT(	L(2m4), L(tab))			C 10
+dnl	JMPENT(	L(3m4), L(tab))			C 11
+	TEXT
+
+L(1):	imul	%r8, %rax
+	mov	%rax, (rp)
+	FUNC_EXIT()
+	ret
+
+L(2):	mov	8(vp_param), %r11
+	imul	%rax, %r11		C u0 x v1
+	mul	%r8			C u0 x v0
+	mov	%rax, (rp)
+	imul	8(up), %r8		C u1 x v0
+	lea	(%r11, %rdx), %rax
+	add	%r8, %rax
+	mov	%rax, 8(rp)
+	FUNC_EXIT()
+	ret
+
+L(3):	mov	8(vp_param), %r9	C v1
+	mov	16(vp_param), %r11
+	mul	%r8			C u0 x v0 -> <r1,r0>
+	mov	%rax, (rp)		C r0
+	mov	(up), %rax		C u0
+	mov	%rdx, %rcx		C r1
+	mul	%r9			C u0 x v1 -> <r2,r1>
+	imul	8(up), %r9		C u1 x v1 -> r2
+	mov	16(up), %r10
+	imul	%r8, %r10		C u2 x v0 -> r2
+	add	%rax, %rcx
+	adc	%rdx, %r9
+	add	%r10, %r9
+	mov	8(up), %rax		C u1
+	mul	%r8			C u1 x v0 -> <r2,r1>
+	add	%rax, %rcx
+	adc	%rdx, %r9
+	mov	%r11, %rax
+	imul	(up), %rax		C u0 x v2 -> r2
+	add	%rax, %r9
+	mov	%rcx, 8(rp)
+	mov	%r9, 16(rp)
+	FUNC_EXIT()
+	ret
+
+L(0m4):
+L(1m4):
+L(2m4):
+L(3m4):
+L(gen):	push	%rbx
+	push	%rbp
+	push	%r13
+	push	%r14
+	push	%r15
+
+	mov	(up), %rax
+	mov	(vp_param), v0
+	mov	vp_param, vp
+
+	lea	(rp,n,8), rp
+	lea	(up,n,8), up
+	neg	n
+
+	mul	v0
+
+	test	$1, R8(n)
+	jz	L(mul_2)
+
+L(mul_1):
+	lea	-8(rp), rp
+	lea	-8(up), up
+	test	$2, R8(n)
+	jnz	L(mul_1_prologue_3)
+
+L(mul_1_prologue_2):		C n = 7, 11, 15, ...
+	lea	-1(n), j
+	lea	L(addmul_outer_1)(%rip), outer_addr
+	mov	%rax, w0
+	mov	%rdx, w1
+	xor	R32(w2), R32(w2)
+	xor	R32(w3), R32(w3)
+	mov	16(up,n,8), %rax
+	jmp	L(mul_1_entry_2)
+
+L(mul_1_prologue_3):		C n = 5, 9, 13, ...
+	lea	1(n), j
+	lea	L(addmul_outer_3)(%rip), outer_addr
+	mov	%rax, w2
+	mov	%rdx, w3
+	xor	R32(w0), R32(w0)
+	jmp	L(mul_1_entry_0)
+
+	ALIGN(16)
+L(mul_1_top):
+	mov	w0, -16(rp,j,8)
+	add	%rax, w1
+	mov	(up,j,8), %rax
+	adc	%rdx, w2
+	xor	R32(w0), R32(w0)
+	mul	v0
+	mov	w1, -8(rp,j,8)
+	add	%rax, w2
+	adc	%rdx, w3
+L(mul_1_entry_0):
+	mov	8(up,j,8), %rax
+	mul	v0
+	mov	w2, (rp,j,8)
+	add	%rax, w3
+	adc	%rdx, w0
+	mov	16(up,j,8), %rax
+	mul	v0
+	mov	w3, 8(rp,j,8)
+	xor	R32(w2), R32(w2)	C zero
+	mov	w2, w3			C zero
+	add	%rax, w0
+	mov	24(up,j,8), %rax
+	mov	w2, w1			C zero
+	adc	%rdx, w1
+L(mul_1_entry_2):
+	mul	v0
+	add	$4, j
+	js	L(mul_1_top)
+
+	mov	w0, -16(rp)
+	add	%rax, w1
+	mov	w1, -8(rp)
+	adc	%rdx, w2
+
+	imul	(up), v0
+	add	v0, w2
+	mov	w2, (rp)
+
+	add	$1, n
+	jz	L(ret)
+
+	mov	8(vp), v0
+	mov	16(vp), v1
+
+	lea	16(up), up
+	lea	8(vp), vp
+	lea	24(rp), rp
+
+	jmp	*outer_addr
+
+
+L(mul_2):
+	mov	8(vp), v1
+	test	$2, R8(n)
+	jz	L(mul_2_prologue_3)
+
+	ALIGN(16)
+L(mul_2_prologue_1):
+	lea	0(n), j
+	mov	%rax, w3
+	mov	%rdx, w0
+	xor	R32(w1), R32(w1)
+	mov	(up,n,8), %rax
+	lea	L(addmul_outer_3)(%rip), outer_addr
+	jmp	L(mul_2_entry_1)
+
+	ALIGN(16)
+L(mul_2_prologue_3):
+	lea	2(n), j
+	mov	$0, R32(w3)
+	mov	%rax, w1
+	mov	(up,n,8), %rax
+	mov	%rdx, w2
+	lea	L(addmul_outer_1)(%rip), outer_addr
+	jmp	L(mul_2_entry_3)
+
+	ALIGN(16)
+L(mul_2_top):
+	mov	-32(up,j,8), %rax
+	mul	v1
+	add	%rax, w0
+	adc	%rdx, w1
+	mov	-24(up,j,8), %rax
+	xor	R32(w2), R32(w2)
+	mul	v0
+	add	%rax, w0
+	mov	-24(up,j,8), %rax
+	adc	%rdx, w1
+	adc	$0, R32(w2)
+	mul	v1
+	add	%rax, w1
+	mov	w0, -24(rp,j,8)
+	adc	%rdx, w2
+	mov	-16(up,j,8), %rax
+	mul	v0
+	mov	$0, R32(w3)
+	add	%rax, w1
+	adc	%rdx, w2
+	mov	-16(up,j,8), %rax
+	adc	$0, R32(w3)
+L(mul_2_entry_3):
+	mov	$0, R32(w0)
+	mov	w1, -16(rp,j,8)
+	mul	v1
+	add	%rax, w2
+	mov	-8(up,j,8), %rax
+	adc	%rdx, w3
+	mov	$0, R32(w1)
+	mul	v0
+	add	%rax, w2
+	mov	-8(up,j,8), %rax
+	adc	%rdx, w3
+	adc	R32(w1), R32(w0)
+	mul	v1
+	add	%rax, w3
+	mov	w2, -8(rp,j,8)
+	adc	%rdx, w0
+	mov	(up,j,8), %rax
+	mul	v0
+	add	%rax, w3
+	adc	%rdx, w0
+	adc	$0, R32(w1)
+L(mul_2_entry_1):
+	add	$4, j
+	mov	w3, -32(rp,j,8)
+	js	L(mul_2_top)
+
+	imul	-16(up), v1
+	add	v1, w0
+	imul	-8(up), v0
+	add	v0, w0
+	mov	w0, -8(rp)
+
+	add	$2, n
+	jz	L(ret)
+
+	mov	16(vp), v0
+	mov	24(vp), v1
+
+	lea	16(vp), vp
+	lea	16(rp), rp
+
+	jmp	*outer_addr
+
+
+L(addmul_outer_1):
+	lea	-2(n), j
+	mov	-16(up,n,8), %rax
+	mul	v0
+	mov	%rax, w3
+	mov	-16(up,n,8), %rax
+	mov	%rdx, w0
+	xor	R32(w1), R32(w1)
+	lea	L(addmul_outer_3)(%rip), outer_addr
+	jmp	L(addmul_entry_1)
+
+L(addmul_outer_3):
+	lea	0(n), j
+	mov	-16(up,n,8), %rax
+	xor	R32(w3), R32(w3)
+	mul	v0
+	mov	%rax, w1
+	mov	-16(up,n,8), %rax
+	mov	%rdx, w2
+	lea	L(addmul_outer_1)(%rip), outer_addr
+	jmp	L(addmul_entry_3)
+
+	ALIGN(16)
+L(addmul_top):
+	add	w3, -32(rp,j,8)
+	adc	%rax, w0
+	mov	-24(up,j,8), %rax
+	adc	%rdx, w1
+	xor	R32(w2), R32(w2)
+	mul	v0
+	add	%rax, w0
+	mov	-24(up,j,8), %rax
+	adc	%rdx, w1
+	adc	R32(w2), R32(w2)
+	mul	v1
+	xor	R32(w3), R32(w3)
+	add	w0, -24(rp,j,8)
+	adc	%rax, w1
+	mov	-16(up,j,8), %rax
+	adc	%rdx, w2
+	mul	v0
+	add	%rax, w1
+	mov	-16(up,j,8), %rax
+	adc	%rdx, w2
+	adc	$0, R32(w3)
+L(addmul_entry_3):
+	mul	v1
+	add	w1, -16(rp,j,8)
+	adc	%rax, w2
+	mov	-8(up,j,8), %rax
+	adc	%rdx, w3
+	mul	v0
+	xor	R32(w0), R32(w0)
+	add	%rax, w2
+	adc	%rdx, w3
+	mov	$0, R32(w1)
+	mov	-8(up,j,8), %rax
+	adc	R32(w1), R32(w0)
+	mul	v1
+	add	w2, -8(rp,j,8)
+	adc	%rax, w3
+	adc	%rdx, w0
+	mov	(up,j,8), %rax
+	mul	v0
+	add	%rax, w3
+	mov	(up,j,8), %rax
+	adc	%rdx, w0
+	adc	$0, R32(w1)
+L(addmul_entry_1):
+	mul	v1
+	add	$4, j
+	js	L(addmul_top)
+
+	add	w3, -32(rp)
+	adc	%rax, w0
+
+	imul	-24(up), v0
+	add	v0, w0
+	add	w0, -24(rp)
+
+	add	$2, n
+	jns	L(ret)
+
+	lea	16(vp), vp
+
+	mov	(vp), v0
+	mov	8(vp), v1
+
+	lea	-16(up), up
+
+	jmp	*outer_addr
+
+L(ret):	pop	%r15
+	pop	%r14
+	pop	%r13
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/k8/mulmid_basecase.asm b/third_party/gmp/mpn/x86_64/k8/mulmid_basecase.asm
new file mode 100644
index 0000000..86f1414
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/k8/mulmid_basecase.asm
@@ -0,0 +1,559 @@
+dnl  AMD64 mpn_mulmid_basecase
+
+dnl  Contributed by David Harvey.
+
+dnl  Copyright 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+C	     cycles/limb
+C K8,K9:	 2.375  (2.5 when un - vn is "small")
+C K10:		 ?
+C P4:		 ?
+C P6-15:	 ?
+
+C INPUT PARAMETERS
+define(`rp',      `%rdi')
+define(`up',      `%rsi')
+define(`un_param',`%rdx')
+define(`vp_param',`%rcx')
+define(`vn',      `%r8')
+
+define(`v0', `%r12')
+define(`v1', `%r9')
+
+define(`w0', `%rbx')
+define(`w1', `%rcx')
+define(`w2', `%rbp')
+define(`w3', `%r10')
+
+define(`n',  `%r11')
+define(`outer_addr', `%r14')
+define(`un',  `%r13')
+define(`vp',  `%r15')
+
+define(`vp_inner', `%r10')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_mulmid_basecase)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8d	')
+	push	%rbx
+	push	%rbp
+	push	%r12
+	push	%r13
+	push	%r14
+	push	%r15
+
+	mov	vp_param, vp
+
+	C use un for row length (= un_param - vn + 1)
+	lea	1(un_param), un
+	sub	vn, un
+
+	lea	(rp,un,8), rp
+
+	cmp	$4, un		C TODO: needs tuning
+	jc	L(diagonal)
+
+	lea	(up,un_param,8), up
+
+	test	$1, vn
+	jz	L(mul_2)
+
+C ===========================================================
+C     mul_1 for vp[0] if vn is odd
+
+L(mul_1):
+	mov	R32(un), R32(w0)
+
+	neg	un
+	mov	(up,un,8), %rax
+	mov	(vp), v0
+	mul	v0
+
+	and	$-4, un		C round down to multiple of 4
+	mov	un, n
+
+	and	$3, R32(w0)
+	jz	L(mul_1_prologue_0)
+	cmp	$2, R32(w0)
+	jc	L(mul_1_prologue_1)
+	jz	L(mul_1_prologue_2)
+
+L(mul_1_prologue_3):
+	mov	%rax, w3
+	mov	%rdx, w0
+	lea	L(addmul_prologue_3)(%rip), outer_addr
+	jmp	L(mul_1_entry_3)
+
+	ALIGN(16)
+L(mul_1_prologue_0):
+	mov	%rax, w2
+	mov	%rdx, w3		C note already w0 == 0
+	lea	L(addmul_prologue_0)(%rip), outer_addr
+	jmp	L(mul_1_entry_0)
+
+	ALIGN(16)
+L(mul_1_prologue_1):
+	add	$4, n
+	mov	%rax, w1
+	mov	%rdx, w2
+	mov	$0, R32(w3)
+	mov	(up,n,8), %rax
+	lea	L(addmul_prologue_1)(%rip), outer_addr
+	jmp	L(mul_1_entry_1)
+
+	ALIGN(16)
+L(mul_1_prologue_2):
+	mov	%rax, w0
+	mov	%rdx, w1
+	mov	24(up,n,8), %rax
+	mov	$0, R32(w2)
+	mov	$0, R32(w3)
+	lea	L(addmul_prologue_2)(%rip), outer_addr
+	jmp	L(mul_1_entry_2)
+
+
+	C this loop is 10 c/loop = 2.5 c/l on K8
+
+	ALIGN(16)
+L(mul_1_top):
+	mov	w0, -16(rp,n,8)
+	add	%rax, w1
+	mov	(up,n,8), %rax
+	adc	%rdx, w2
+L(mul_1_entry_1):
+	mov	$0, R32(w0)
+	mul	v0
+	mov	w1, -8(rp,n,8)
+	add	%rax, w2
+	adc	%rdx, w3
+L(mul_1_entry_0):
+	mov	8(up,n,8), %rax
+	mul	v0
+	mov	w2, (rp,n,8)
+	add	%rax, w3
+	adc	%rdx, w0
+L(mul_1_entry_3):
+	mov	16(up,n,8), %rax
+	mul	v0
+	mov	w3, 8(rp,n,8)
+	mov	$0, R32(w2)		C zero
+	mov	w2, w3			C zero
+	add	%rax, w0
+	mov	24(up,n,8), %rax
+	mov	w2, w1			C zero
+	adc	%rdx, w1
+L(mul_1_entry_2):
+	mul	v0
+	add	$4, n
+	js	L(mul_1_top)
+
+	mov	w0, -16(rp)
+	add	%rax, w1
+	mov	w1, -8(rp)
+	mov	w2, 8(rp)		C zero last limb of output
+	adc	%rdx, w2
+	mov	w2, (rp)
+
+	dec	vn
+	jz	L(ret)
+
+	lea	-8(up), up
+	lea	8(vp), vp
+
+	mov	un, n
+	mov	(vp), v0
+	mov	8(vp), v1
+
+	jmp	*outer_addr
+
+C ===========================================================
+C     mul_2 for vp[0], vp[1] if vn is even
+
+	ALIGN(16)
+L(mul_2):
+	mov	R32(un), R32(w0)
+
+	neg	un
+	mov	-8(up,un,8), %rax
+	mov	(vp), v0
+	mov	8(vp), v1
+	mul	v1
+
+	and	$-4, un		C round down to multiple of 4
+	mov	un, n
+
+	and	$3, R32(w0)
+	jz	L(mul_2_prologue_0)
+	cmp	$2, R32(w0)
+	jc	L(mul_2_prologue_1)
+	jz	L(mul_2_prologue_2)
+
+L(mul_2_prologue_3):
+	mov	%rax, w1
+	mov	%rdx, w2
+	lea	L(addmul_prologue_3)(%rip), outer_addr
+	jmp	L(mul_2_entry_3)
+
+	ALIGN(16)
+L(mul_2_prologue_0):
+	mov	%rax, w0
+	mov	%rdx, w1
+	lea	L(addmul_prologue_0)(%rip), outer_addr
+	jmp	L(mul_2_entry_0)
+
+	ALIGN(16)
+L(mul_2_prologue_1):
+	mov	%rax, w3
+	mov	%rdx, w0
+	mov	$0, R32(w1)
+	lea	L(addmul_prologue_1)(%rip), outer_addr
+	jmp	L(mul_2_entry_1)
+
+	ALIGN(16)
+L(mul_2_prologue_2):
+	mov	%rax, w2
+	mov	%rdx, w3
+	mov	$0, R32(w0)
+	mov	16(up,n,8), %rax
+	lea	L(addmul_prologue_2)(%rip), outer_addr
+	jmp	L(mul_2_entry_2)
+
+
+	C this loop is 18 c/loop = 2.25 c/l on K8
+
+	ALIGN(16)
+L(mul_2_top):
+	mov     -8(up,n,8), %rax
+	mul     v1
+	add     %rax, w0
+	adc     %rdx, w1
+L(mul_2_entry_0):
+	mov     $0, R32(w2)
+	mov     (up,n,8), %rax
+	mul     v0
+	add     %rax, w0
+	mov     (up,n,8), %rax
+	adc     %rdx, w1
+	adc     $0, R32(w2)
+	mul     v1
+	add     %rax, w1
+	mov     w0, (rp,n,8)
+	adc     %rdx, w2
+L(mul_2_entry_3):
+	mov     8(up,n,8), %rax
+	mul     v0
+	mov     $0, R32(w3)
+	add     %rax, w1
+	adc     %rdx, w2
+	mov     $0, R32(w0)
+	adc     $0, R32(w3)
+	mov     8(up,n,8), %rax
+	mov     w1, 8(rp,n,8)
+	mul     v1
+	add     %rax, w2
+	mov     16(up,n,8), %rax
+	adc     %rdx, w3
+L(mul_2_entry_2):
+	mov     $0, R32(w1)
+	mul     v0
+	add     %rax, w2
+	mov     16(up,n,8), %rax
+	adc     %rdx, w3
+	adc     $0, R32(w0)
+	mul     v1
+	add     %rax, w3
+	mov     w2, 16(rp,n,8)
+	adc     %rdx, w0
+L(mul_2_entry_1):
+	mov     24(up,n,8), %rax
+	mul     v0
+	add     %rax, w3
+	adc     %rdx, w0
+	adc     $0, R32(w1)
+	add     $4, n
+	mov     w3, -8(rp,n,8)
+	jnz     L(mul_2_top)
+
+	mov	w0, (rp)
+	mov	w1, 8(rp)
+
+	sub	$2, vn
+	jz	L(ret)
+
+	lea	16(vp), vp
+	lea	-16(up), up
+
+	mov	un, n
+	mov	(vp), v0
+	mov	8(vp), v1
+
+	jmp	*outer_addr
+
+C ===========================================================
+C     addmul_2 for remaining vp's
+
+	ALIGN(16)
+L(addmul_prologue_0):
+	mov	-8(up,n,8), %rax
+	mul	v1
+	mov	%rax, w1
+	mov	%rdx, w2
+	mov	$0, R32(w3)
+	jmp	L(addmul_entry_0)
+
+	ALIGN(16)
+L(addmul_prologue_1):
+	mov	16(up,n,8), %rax
+	mul	v1
+	mov	%rax, w0
+	mov	%rdx, w1
+	mov	$0, R32(w2)
+	mov	24(up,n,8), %rax
+	jmp	L(addmul_entry_1)
+
+	ALIGN(16)
+L(addmul_prologue_2):
+	mov	8(up,n,8), %rax
+	mul	v1
+	mov	%rax, w3
+	mov	%rdx, w0
+	mov	$0, R32(w1)
+	jmp	L(addmul_entry_2)
+
+	ALIGN(16)
+L(addmul_prologue_3):
+	mov	(up,n,8), %rax
+	mul	v1
+	mov	%rax, w2
+	mov	%rdx, w3
+	mov	$0, R32(w0)
+	mov	$0, R32(w1)
+	jmp	L(addmul_entry_3)
+
+	C this loop is 19 c/loop = 2.375 c/l on K8
+
+	ALIGN(16)
+L(addmul_top):
+	mov	$0, R32(w3)
+	add	%rax, w0
+	mov	-8(up,n,8), %rax
+	adc	%rdx, w1
+	adc	$0, R32(w2)
+	mul	v1
+	add	w0, -8(rp,n,8)
+	adc	%rax, w1
+	adc	%rdx, w2
+L(addmul_entry_0):
+	mov	(up,n,8), %rax
+	mul	v0
+	add	%rax, w1
+	mov	(up,n,8), %rax
+	adc	%rdx, w2
+	adc	$0, R32(w3)
+	mul	v1
+	add	w1, (rp,n,8)
+	mov	$0, R32(w1)
+	adc	%rax, w2
+	mov	$0, R32(w0)
+	adc	%rdx, w3
+L(addmul_entry_3):
+	mov	8(up,n,8), %rax
+	mul	v0
+	add	%rax, w2
+	mov	8(up,n,8), %rax
+	adc	%rdx, w3
+	adc	$0, R32(w0)
+	mul	v1
+	add	w2, 8(rp,n,8)
+	adc	%rax, w3
+	adc	%rdx, w0
+L(addmul_entry_2):
+	mov	16(up,n,8), %rax
+	mul	v0
+	add	%rax, w3
+	mov	16(up,n,8), %rax
+	adc	%rdx, w0
+	adc	$0, R32(w1)
+	mul	v1
+	add	w3, 16(rp,n,8)
+	nop			C don't ask...
+	adc	%rax, w0
+	mov	$0, R32(w2)
+	mov	24(up,n,8), %rax
+	adc	%rdx, w1
+L(addmul_entry_1):
+	mul	v0
+	add	$4, n
+	jnz	L(addmul_top)
+
+	add	%rax, w0
+	adc	%rdx, w1
+	adc	$0, R32(w2)
+
+	add	w0, -8(rp)
+	adc	w1, (rp)
+	adc	w2, 8(rp)
+
+	sub	$2, vn
+	jz	L(ret)
+
+	lea	16(vp), vp
+	lea	-16(up), up
+
+	mov	un, n
+	mov	(vp), v0
+	mov	8(vp), v1
+
+	jmp	*outer_addr
+
+C ===========================================================
+C     accumulate along diagonals if un - vn is small
+
+	ALIGN(16)
+L(diagonal):
+	xor	R32(w0), R32(w0)
+	xor	R32(w1), R32(w1)
+	xor	R32(w2), R32(w2)
+
+	neg	un
+
+	mov	R32(vn), %eax
+	and	$3, %eax
+	jz	L(diag_prologue_0)
+	cmp	$2, %eax
+	jc	L(diag_prologue_1)
+	jz	L(diag_prologue_2)
+
+L(diag_prologue_3):
+	lea	-8(vp), vp
+	mov	vp, vp_inner
+	add	$1, vn
+	mov	vn, n
+	lea	L(diag_entry_3)(%rip), outer_addr
+	jmp	L(diag_entry_3)
+
+L(diag_prologue_0):
+	mov	vp, vp_inner
+	mov	vn, n
+	lea	0(%rip), outer_addr
+	mov     -8(up,n,8), %rax
+	jmp	L(diag_entry_0)
+
+L(diag_prologue_1):
+	lea	8(vp), vp
+	mov	vp, vp_inner
+	add	$3, vn
+	mov	vn, n
+	lea	0(%rip), outer_addr
+	mov     -8(vp_inner), %rax
+	jmp	L(diag_entry_1)
+
+L(diag_prologue_2):
+	lea	-16(vp), vp
+	mov	vp, vp_inner
+	add	$2, vn
+	mov	vn, n
+	lea	0(%rip), outer_addr
+	mov	16(vp_inner), %rax
+	jmp	L(diag_entry_2)
+
+
+	C this loop is 10 c/loop = 2.5 c/l on K8
+
+	ALIGN(16)
+L(diag_top):
+	add     %rax, w0
+	adc     %rdx, w1
+	mov     -8(up,n,8), %rax
+	adc     $0, w2
+L(diag_entry_0):
+	mulq    (vp_inner)
+	add     %rax, w0
+	adc     %rdx, w1
+	adc     $0, w2
+L(diag_entry_3):
+	mov     -16(up,n,8), %rax
+	mulq    8(vp_inner)
+	add     %rax, w0
+	mov     16(vp_inner), %rax
+	adc     %rdx, w1
+	adc     $0, w2
+L(diag_entry_2):
+	mulq    -24(up,n,8)
+	add     %rax, w0
+	mov     24(vp_inner), %rax
+	adc     %rdx, w1
+	lea     32(vp_inner), vp_inner
+	adc     $0, w2
+L(diag_entry_1):
+	mulq    -32(up,n,8)
+	sub     $4, n
+	jnz	L(diag_top)
+
+	add	%rax, w0
+	adc	%rdx, w1
+	adc	$0, w2
+
+	mov	w0, (rp,un,8)
+
+	inc	un
+	jz	L(diag_end)
+
+	mov	vn, n
+	mov	vp, vp_inner
+
+	lea	8(up), up
+	mov	w1, w0
+	mov	w2, w1
+	xor	R32(w2), R32(w2)
+
+	jmp	*outer_addr
+
+L(diag_end):
+	mov	w1, (rp)
+	mov	w2, 8(rp)
+
+L(ret):	pop	%r15
+	pop	%r14
+	pop	%r13
+	pop	%r12
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/k8/redc_1.asm b/third_party/gmp/mpn/x86_64/k8/redc_1.asm
new file mode 100644
index 0000000..9327b21
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/k8/redc_1.asm
@@ -0,0 +1,591 @@
+dnl  X86-64 mpn_redc_1 optimised for AMD K8-K10.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2004, 2008, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 ?
+C AMD K10	 ?
+C AMD bull	 ?
+C AMD pile	 ?
+C AMD steam	 ?
+C AMD bobcat	 ?
+C AMD jaguar	 ?
+C Intel P4	 ?
+C Intel core	 ?
+C Intel NHM	 ?
+C Intel SBR	 ?
+C Intel IBR	 ?
+C Intel HWL	 ?
+C Intel BWL	 ?
+C Intel atom	 ?
+C VIA nano	 ?
+
+C The inner loops of this code are the result of running a code generation and
+C optimisation tool suite written by David Harvey and Torbjörn Granlund.
+
+C TODO
+C  * Micro-optimise, none performed thus far.
+C  * This looks different from other current redc_1.asm variants.  Consider
+C    adapting this to the mainstream style.
+C  * Is this code really faster than more approaches which compute q0 later?
+C    Is the use of a jump jump table faster?  Or is the edge of this due to the
+C    inlined add_n code?
+C  * Put initial m[0] x q0 computation in header.
+C  * Put basecases at the file's end, single them out before the pushes.
+
+define(`rp',          `%rdi')   C rcx
+define(`up',          `%rsi')   C rdx
+define(`mp_param',    `%rdx')   C r8
+define(`n',           `%rcx')   C r9
+define(`u0inv',       `%r8')    C stack
+
+define(`i',           `%r11')
+define(`nneg',        `%r12')
+define(`mp',          `%r13')
+define(`q0',          `%rbp')
+define(`vp',          `%rdx')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_redc_1)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8	')
+	push	%rbp
+	mov	(up), q0		C up[0]
+	push	%rbx
+	imul	u0inv, q0		C first q0, for all execution paths
+	push	%r12
+	push	%r13
+	push	%r14
+	push	%r15
+
+	mov	n, nneg
+	neg	nneg
+	lea	(mp_param,n,8), mp	C mp += n
+	lea	-16(up,n,8), up		C up += n
+
+	mov	R32(n), R32(%rax)
+	and	$3, R32(%rax)
+	lea	4(%rax), %r9
+	cmp	$4, R32(n)
+	cmovg	%r9, %rax
+	lea	L(tab)(%rip), %r9
+ifdef(`PIC',`
+	movslq	(%r9,%rax,4), %rax
+	add	%r9, %rax
+	jmp	*%rax
+',`
+	jmp	*(%r9,%rax,8)
+')
+
+	JUMPTABSECT
+	ALIGN(8)
+L(tab):	JMPENT(	L(0), L(tab))
+	JMPENT(	L(1), L(tab))
+	JMPENT(	L(2), L(tab))
+	JMPENT(	L(3), L(tab))
+	JMPENT(	L(0m4), L(tab))
+	JMPENT(	L(1m4), L(tab))
+	JMPENT(	L(2m4), L(tab))
+	JMPENT(	L(3m4), L(tab))
+	TEXT
+
+	ALIGN(16)
+L(1):	mov	(mp_param), %rax
+	mul	q0
+	add	8(up), %rax
+	adc	16(up), %rdx
+	mov	%rdx, (rp)
+	mov	$0, R32(%rax)
+	adc	R32(%rax), R32(%rax)
+	jmp	L(ret)
+
+
+	ALIGN(16)
+L(2):	mov	(mp_param), %rax
+	mul	q0
+	xor	R32(%r14), R32(%r14)
+	mov	%rax, %r10
+	mov	-8(mp), %rax
+	mov	%rdx, %r9
+	mul	q0
+	add	(up), %r10
+	adc	%rax, %r9
+	adc	%rdx, %r14
+	add	8(up), %r9
+	adc	$0, %r14
+	mov	%r9, q0
+	imul	u0inv, q0
+	mov	-16(mp), %rax
+	mul	q0
+	xor	R32(%rbx), R32(%rbx)
+	mov	%rax, %r10
+	mov	-8(mp), %rax
+	mov	%rdx, %r11
+	mul	q0
+	add	%r9, %r10
+	adc	%rax, %r11
+	adc	%rdx, %rbx
+	add	16(up), %r11
+	adc	$0, %rbx
+	xor	R32(%rax), R32(%rax)
+	add	%r11, %r14
+	adc	24(up), %rbx
+	mov	%r14, (rp)
+	mov	%rbx, 8(rp)
+	adc	R32(%rax), R32(%rax)
+	jmp	L(ret)
+
+
+L(3):	mov	(mp_param), %rax
+	mul	q0
+	mov	%rax, %rbx
+	mov	%rdx, %r10
+	mov	-16(mp), %rax
+	mul	q0
+	xor	R32(%r9), R32(%r9)
+	xor	R32(%r14), R32(%r14)
+	add	-8(up), %rbx
+	adc	%rax, %r10
+	mov	-8(mp), %rax
+	adc	%rdx, %r9
+	mul	q0
+	add	(up), %r10
+	mov	%r10, (up)
+	adc	%rax, %r9
+	adc	%rdx, %r14
+	mov	%r10, q0
+	imul	u0inv, q0
+	add	%r9, 8(up)
+	adc	$0, %r14
+	mov	%r14, -8(up)
+
+	mov	-24(mp), %rax
+	mul	q0
+	mov	%rax, %rbx
+	mov	%rdx, %r10
+	mov	-16(mp), %rax
+	mul	q0
+	xor	R32(%r9), R32(%r9)
+	xor	R32(%r14), R32(%r14)
+	add	(up), %rbx
+	adc	%rax, %r10
+	mov	-8(mp), %rax
+	adc	%rdx, %r9
+	mul	q0
+	add	8(up), %r10
+	mov	%r10, 8(up)
+	adc	%rax, %r9
+	adc	%rdx, %r14
+	mov	%r10, q0
+	imul	u0inv, q0
+	add	%r9, 16(up)
+	adc	$0, %r14
+	mov	%r14, (up)
+
+	mov	-24(mp), %rax
+	mul	q0
+	mov	%rax, %rbx
+	mov	%rdx, %r10
+	mov	-16(mp), %rax
+	mul	q0
+	xor	R32(%r9), R32(%r9)
+	xor	R32(%r14), R32(%r14)
+	add	8(up), %rbx
+	adc	%rax, %r10
+	mov	-8(mp), %rax
+	adc	%rdx, %r9
+	mul	q0
+	add	16(up), %r10
+	adc	%rax, %r9
+	adc	%rdx, %r14
+	add	24(up), %r9
+	adc	$0, %r14
+
+	xor	R32(%rax), R32(%rax)
+	add	-8(up), %r10
+	adc	(up), %r9
+	adc	32(up), %r14
+	mov	%r10, (rp)
+	mov	%r9, 8(rp)
+	mov	%r14, 16(rp)
+	adc	R32(%rax), R32(%rax)
+	jmp	L(ret)
+
+
+	ALIGN(16)
+L(2m4):
+L(lo2):	mov	(mp,nneg,8), %rax
+	mul	q0
+	xor	R32(%r14), R32(%r14)
+	xor	R32(%rbx), R32(%rbx)
+	mov	%rax, %r10
+	mov	8(mp,nneg,8), %rax
+	mov	24(up,nneg,8), %r15
+	mov	%rdx, %r9
+	mul	q0
+	add	16(up,nneg,8), %r10
+	adc	%rax, %r9
+	mov	16(mp,nneg,8), %rax
+	adc	%rdx, %r14
+	mul	q0
+	mov	$0, R32(%r10)		C xor?
+	lea	2(nneg), i
+	add	%r9, %r15
+	imul	u0inv, %r15
+	jmp	 L(e2)
+
+	ALIGN(16)
+L(li2):	add	%r10, (up,i,8)
+	adc	%rax, %r9
+	mov	(mp,i,8), %rax
+	adc	%rdx, %r14
+	xor	R32(%r10), R32(%r10)
+	mul	q0
+L(e2):	add	%r9, 8(up,i,8)
+	adc	%rax, %r14
+	adc	%rdx, %rbx
+	mov	8(mp,i,8), %rax
+	mul	q0
+	add	%r14, 16(up,i,8)
+	adc	%rax, %rbx
+	adc	%rdx, %r10
+	mov	16(mp,i,8), %rax
+	mul	q0
+	add	%rbx, 24(up,i,8)
+	mov	$0, R32(%r14)		C zero
+	mov	%r14, %rbx		C zero
+	adc	%rax, %r10
+	mov	24(mp,i,8), %rax
+	mov	%r14, %r9		C zero
+	adc	%rdx, %r9
+	mul	q0
+	add	$4, i
+	js	 L(li2)
+
+L(le2):	add	%r10, (up)
+	adc	%rax, %r9
+	adc	%r14, %rdx
+	add	%r9, 8(up)
+	adc	$0, %rdx
+	mov	%rdx, 16(up,nneg,8)	C up[0]
+	add	$8, up
+	mov	%r15, q0
+	dec	n
+	jnz	L(lo2)
+
+	mov	nneg, n
+	sar	$2, n
+	lea	32(up,nneg,8), up
+	lea	(up,nneg,8), vp
+
+	mov	-16(up), %r8
+	mov	-8(up), %r9
+	add	-16(vp), %r8
+	adc	-8(vp), %r9
+	mov	%r8, (rp)
+	mov	%r9, 8(rp)
+	lea	16(rp), rp
+	jmp	L(addx)
+
+
+	ALIGN(16)
+L(1m4):
+L(lo1):	mov	(mp,nneg,8), %rax
+	xor	%r9, %r9
+	xor	R32(%rbx), R32(%rbx)
+	mul	q0
+	mov	%rax, %r9
+	mov	8(mp,nneg,8), %rax
+	mov	24(up,nneg,8), %r15
+	mov	%rdx, %r14
+	mov	$0, R32(%r10)		C xor?
+	mul	q0
+	add	16(up,nneg,8), %r9
+	adc	%rax, %r14
+	adc	%rdx, %rbx
+	mov	16(mp,nneg,8), %rax
+	mul	q0
+	lea	1(nneg), i
+	add	%r14, %r15
+	imul	u0inv, %r15
+	jmp	 L(e1)
+
+	ALIGN(16)
+L(li1):	add	%r10, (up,i,8)
+	adc	%rax, %r9
+	mov	(mp,i,8), %rax
+	adc	%rdx, %r14
+	xor	R32(%r10), R32(%r10)
+	mul	q0
+	add	%r9, 8(up,i,8)
+	adc	%rax, %r14
+	adc	%rdx, %rbx
+	mov	8(mp,i,8), %rax
+	mul	q0
+L(e1):	add	%r14, 16(up,i,8)
+	adc	%rax, %rbx
+	adc	%rdx, %r10
+	mov	16(mp,i,8), %rax
+	mul	q0
+	add	%rbx, 24(up,i,8)
+	mov	$0, R32(%r14)		C zero
+	mov	%r14, %rbx		C zero
+	adc	%rax, %r10
+	mov	24(mp,i,8), %rax
+	mov	%r14, %r9		C zero
+	adc	%rdx, %r9
+	mul	q0
+	add	$4, i
+	js	 L(li1)
+
+L(le1):	add	%r10, (up)
+	adc	%rax, %r9
+	adc	%r14, %rdx
+	add	%r9, 8(up)
+	adc	$0, %rdx
+	mov	%rdx, 16(up,nneg,8)	C up[0]
+	add	$8, up
+	mov	%r15, q0
+	dec	n
+	jnz	L(lo1)
+
+	mov	nneg, n
+	sar	$2, n
+	lea	24(up,nneg,8), up
+	lea	(up,nneg,8), vp
+
+	mov	-8(up), %r8
+	add	-8(vp), %r8
+	mov	%r8, (rp)
+	lea	8(rp), rp
+	jmp	L(addx)
+
+
+	ALIGN(16)
+L(0):
+L(0m4):
+L(lo0):	mov	(mp,nneg,8), %rax
+	mov	nneg, i
+	mul	q0
+	xor	R32(%r10), R32(%r10)
+	mov	%rax, %r14
+	mov	%rdx, %rbx
+	mov	8(mp,nneg,8), %rax
+	mov	24(up,nneg,8), %r15
+	mul	q0
+	add	16(up,nneg,8), %r14
+	adc	%rax, %rbx
+	adc	%rdx, %r10
+	add	%rbx, %r15
+	imul	u0inv, %r15
+	jmp	L(e0)
+
+	ALIGN(16)
+L(li0):	add	%r10, (up,i,8)
+	adc	%rax, %r9
+	mov	(mp,i,8), %rax
+	adc	%rdx, %r14
+	xor	R32(%r10), R32(%r10)
+	mul	q0
+	add	%r9, 8(up,i,8)
+	adc	%rax, %r14
+	adc	%rdx, %rbx
+	mov	8(mp,i,8), %rax
+	mul	q0
+	add	%r14, 16(up,i,8)
+	adc	%rax, %rbx
+	adc	%rdx, %r10
+L(e0):	mov	16(mp,i,8), %rax
+	mul	q0
+	add	%rbx, 24(up,i,8)
+	mov	$0, R32(%r14)		C zero
+	mov	%r14, %rbx		C zero
+	adc	%rax, %r10
+	mov	24(mp,i,8), %rax
+	mov	%r14, %r9		C zero
+	adc	%rdx, %r9
+	mul	q0
+	add	$4, i
+	js	 L(li0)
+
+L(le0):	add	%r10, (up)
+	adc	%rax, %r9
+	adc	%r14, %rdx
+	add	%r9, 8(up)
+	adc	$0, %rdx
+	mov	%rdx, 16(up,nneg,8)	C up[0]
+	add	$8, up
+	mov	%r15, q0
+	dec	n
+	jnz	L(lo0)
+
+	mov	nneg, n
+	sar	$2, n
+	clc
+	lea	16(up,nneg,8), up
+	lea	(up,nneg,8), vp
+	jmp	L(addy)
+
+
+	ALIGN(16)
+L(3m4):
+L(lo3):	mov	(mp,nneg,8), %rax
+	mul	q0
+	mov	%rax, %rbx
+	mov	%rdx, %r10
+	mov	8(mp,nneg,8), %rax
+	mov	24(up,nneg,8), %r15
+	mul	q0
+	add	16(up,nneg,8), %rbx	C result is zero, might carry
+	mov	$0, R32(%rbx)		C zero
+	mov	%rbx, %r14		C zero
+	adc	%rax, %r10
+	mov	16(mp,nneg,8), %rax
+	mov	%r14, %r9		C zero
+	adc	%rdx, %r9
+	add	%r10, %r15
+	mul	q0
+	lea	3(nneg), i
+	imul	u0inv, %r15
+C	jmp	L(li3)
+
+	ALIGN(16)
+L(li3):	add	%r10, (up,i,8)
+	adc	%rax, %r9
+	mov	(mp,i,8), %rax
+	adc	%rdx, %r14
+	xor	R32(%r10), R32(%r10)
+	mul	q0
+	add	%r9, 8(up,i,8)
+	adc	%rax, %r14
+	adc	%rdx, %rbx
+	mov	8(mp,i,8), %rax
+	mul	q0
+	add	%r14, 16(up,i,8)
+	adc	%rax, %rbx
+	adc	%rdx, %r10
+	mov	16(mp,i,8), %rax
+	mul	q0
+	add	%rbx, 24(up,i,8)
+	mov	$0, R32(%r14)		C zero
+	mov	%r14, %rbx		C zero
+	adc	%rax, %r10
+	mov	24(mp,i,8), %rax
+	mov	%r14, %r9		C zero
+	adc	%rdx, %r9
+	mul	q0
+	add	$4, i
+	js	 L(li3)
+
+L(le3):	add	%r10, (up)
+	adc	%rax, %r9
+	adc	%r14, %rdx
+	add	%r9, 8(up)
+	adc	$0, %rdx
+	mov	%rdx, 16(up,nneg,8)	C up[0]
+	mov	%r15, q0
+	lea	8(up), up
+	dec	n
+	jnz	L(lo3)
+
+
+C ==== Addition code ====
+	mov	nneg, n
+	sar	$2, n
+	lea	40(up,nneg,8), up
+	lea	(up,nneg,8), vp
+
+	mov	-24(up), %r8
+	mov	-16(up), %r9
+	mov	-8(up), %r10
+	add	-24(vp), %r8
+	adc	-16(vp), %r9
+	adc	-8(vp), %r10
+	mov	%r8, (rp)
+	mov	%r9, 8(rp)
+	mov	%r10, 16(rp)
+	lea	24(rp), rp
+
+L(addx):inc	n
+	jz	L(ad3)
+
+L(addy):mov	(up), %r8
+	mov	8(up), %r9
+	inc	n
+	jmp	L(mid)
+
+C	ALIGN(16)
+L(al3):	adc	(vp), %r8
+	adc	8(vp), %r9
+	adc	16(vp), %r10
+	adc	24(vp), %r11
+	mov	%r8, (rp)
+	lea	32(up), up
+	mov	%r9, 8(rp)
+	mov	%r10, 16(rp)
+	inc	n
+	mov	%r11, 24(rp)
+	lea	32(vp), vp
+	mov	(up), %r8
+	mov	8(up), %r9
+	lea	32(rp), rp
+L(mid):	mov	16(up), %r10
+	mov	24(up), %r11
+	jnz	L(al3)
+
+L(ae3):	adc	(vp), %r8
+	adc	8(vp), %r9
+	adc	16(vp), %r10
+	adc	24(vp), %r11
+	mov	%r8, (rp)
+	mov	%r9, 8(rp)
+	mov	%r10, 16(rp)
+	mov	%r11, 24(rp)
+
+L(ad3):	mov	R32(n), R32(%rax)	C zero
+	adc	R32(%rax), R32(%rax)
+
+L(ret):	pop	%r15
+	pop	%r14
+	pop	%r13
+	pop	%r12
+	pop	%rbx
+	pop	%rbp
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/k8/sqr_basecase.asm b/third_party/gmp/mpn/x86_64/k8/sqr_basecase.asm
new file mode 100644
index 0000000..60cf945
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/k8/sqr_basecase.asm
@@ -0,0 +1,807 @@
+dnl  AMD64 mpn_sqr_basecase.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2008, 2009, 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C The inner loops of this code are the result of running a code generation and
+C optimization tool suite written by David Harvey and Torbjorn Granlund.
+
+C NOTES
+C   * There is a major stupidity in that we call mpn_mul_1 initially, for a
+C     large trip count.  Instead, we should follow the generic/sqr_basecase.c
+C     code which uses addmul_2s from the start, conditionally leaving a 1x1
+C     multiply to the end.  (In assembly code, one would stop invoking
+C     addmul_2s loops when perhaps 3x2s respectively a 2x2s remains.)
+C   * Another stupidity is in the sqr_diag_addlsh1 code.  It does not need to
+C     save/restore carry, instead it can propagate into the high product word.
+C   * Align more labels, should shave off a few cycles.
+C   * We can safely use 32-bit size operations, since operands with (2^32)
+C     limbs will lead to non-termination in practice.
+C   * The jump table could probably be optimized, at least for non-pic.
+C   * The special code for n <= 4 was quickly written.  It is probably too
+C     large and unnecessarily slow.
+C   * Consider combining small cases code so that the n=k-1 code jumps into the
+C     middle of the n=k code.
+C   * Avoid saving registers for small cases code.
+C   * Needed variables:
+C    n   r11  input size
+C    i   r8   work left, initially n
+C    j   r9   inner loop count
+C        r15  unused
+C    v0  r13
+C    v1  r14
+C    rp  rdi
+C    up  rsi
+C    w0  rbx
+C    w1  rcx
+C    w2  rbp
+C    w3  r10
+C    tp  r12
+C    lo  rax
+C    hi  rdx
+C        rsp
+
+C INPUT PARAMETERS
+define(`rp',	  `%rdi')
+define(`up',	  `%rsi')
+define(`n_param', `%rdx')
+
+define(`n',	`%r11')
+define(`tp',	`%r12')
+define(`i',	`%r8')
+define(`j',	`%r9')
+define(`v0',	`%r13')
+define(`v1',	`%r14')
+define(`w0',	`%rbx')
+define(`w1',	`%rcx')
+define(`w2',	`%rbp')
+define(`w3',	`%r10')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_sqr_basecase)
+	FUNC_ENTRY(3)
+	mov	R32(n_param), R32(%rcx)
+	mov	R32(n_param), R32(n)		C free original n register (rdx)
+
+	add	$-40, %rsp
+
+	and	$3, R32(%rcx)
+	cmp	$4, R32(n_param)
+	lea	4(%rcx), %r8
+
+	mov	%rbx, 32(%rsp)
+	mov	%rbp, 24(%rsp)
+	mov	%r12, 16(%rsp)
+	mov	%r13, 8(%rsp)
+	mov	%r14, (%rsp)
+
+	cmovg	%r8, %rcx
+
+	lea	L(tab)(%rip), %rax
+ifdef(`PIC',
+`	movslq	(%rax,%rcx,4), %r10
+	add	%r10, %rax
+	jmp	*%rax
+',`
+	jmp	*(%rax,%rcx,8)
+')
+	JUMPTABSECT
+	ALIGN(8)
+L(tab):	JMPENT(	L(4), L(tab))
+	JMPENT(	L(1), L(tab))
+	JMPENT(	L(2), L(tab))
+	JMPENT(	L(3), L(tab))
+	JMPENT(	L(0m4), L(tab))
+	JMPENT(	L(1m4), L(tab))
+	JMPENT(	L(2m4), L(tab))
+	JMPENT(	L(3m4), L(tab))
+	TEXT
+
+L(1):	mov	(up), %rax
+	mul	%rax
+	add	$40, %rsp
+	mov	%rax, (rp)
+	mov	%rdx, 8(rp)
+	FUNC_EXIT()
+	ret
+
+L(2):	mov	(up), %rax
+	mov	%rax, %r8
+	mul	%rax
+	mov	8(up), %r11
+	mov	%rax, (rp)
+	mov	%r11, %rax
+	mov	%rdx, %r9
+	mul	%rax
+	add	$40, %rsp
+	mov	%rax, %r10
+	mov	%r11, %rax
+	mov	%rdx, %r11
+	mul	%r8
+	xor	%r8, %r8
+	add	%rax, %r9
+	adc	%rdx, %r10
+	adc	%r8, %r11
+	add	%rax, %r9
+	mov	%r9, 8(rp)
+	adc	%rdx, %r10
+	mov	%r10, 16(rp)
+	adc	%r8, %r11
+	mov	%r11, 24(rp)
+	FUNC_EXIT()
+	ret
+
+L(3):	mov	(up), %rax
+	mov	%rax, %r10
+	mul	%rax
+	mov	8(up), %r11
+	mov	%rax, (rp)
+	mov	%r11, %rax
+	mov	%rdx, 8(rp)
+	mul	%rax
+	mov	16(up), %rcx
+	mov	%rax, 16(rp)
+	mov	%rcx, %rax
+	mov	%rdx, 24(rp)
+	mul	%rax
+	mov	%rax, 32(rp)
+	mov	%rdx, 40(rp)
+
+	mov	%r11, %rax
+	mul	%r10
+	mov	%rax, %r8
+	mov	%rcx, %rax
+	mov	%rdx, %r9
+	mul	%r10
+	xor	%r10, %r10
+	add	%rax, %r9
+	mov	%r11, %rax
+	mov	%r10, %r11
+	adc	%rdx, %r10
+
+	mul	%rcx
+	add	$40, %rsp
+	add	%rax, %r10
+	adc	%r11, %rdx
+	add	%r8, %r8
+	adc	%r9, %r9
+	adc	%r10, %r10
+	adc	%rdx, %rdx
+	adc	%r11, %r11
+	add	%r8, 8(rp)
+	adc	%r9, 16(rp)
+	adc	%r10, 24(rp)
+	adc	%rdx, 32(rp)
+	adc	%r11, 40(rp)
+	FUNC_EXIT()
+	ret
+
+L(4):	mov	(up), %rax
+	mov	%rax, %r11
+	mul	%rax
+	mov	8(up), %rbx
+	mov	%rax, (rp)
+	mov	%rbx, %rax
+	mov	%rdx, 8(rp)
+	mul	%rax
+	mov	%rax, 16(rp)
+	mov	%rdx, 24(rp)
+	mov	16(up), %rax
+	mul	%rax
+	mov	%rax, 32(rp)
+	mov	%rdx, 40(rp)
+	mov	24(up), %rax
+	mul	%rax
+	mov	%rax, 48(rp)
+	mov	%rbx, %rax
+	mov	%rdx, 56(rp)
+
+	mul	%r11
+	add	$32, %rsp
+	mov	%rax, %r8
+	mov	%rdx, %r9
+	mov	16(up), %rax
+	mul	%r11
+	xor	%r10, %r10
+	add	%rax, %r9
+	adc	%rdx, %r10
+	mov	24(up), %rax
+	mul	%r11
+	xor	%r11, %r11
+	add	%rax, %r10
+	adc	%rdx, %r11
+	mov	16(up), %rax
+	mul	%rbx
+	xor	%rcx, %rcx
+	add	%rax, %r10
+	adc	%rdx, %r11
+	adc	$0, %rcx
+	mov	24(up), %rax
+	mul	%rbx
+	pop	%rbx
+	add	%rax, %r11
+	adc	%rdx, %rcx
+	mov	16(up), %rdx
+	mov	24(up), %rax
+	mul	%rdx
+	add	%rax, %rcx
+	adc	$0, %rdx
+
+	add	%r8, %r8
+	adc	%r9, %r9
+	adc	%r10, %r10
+	adc	%r11, %r11
+	adc	%rcx, %rcx
+	mov	$0, R32(%rax)
+	adc	%rdx, %rdx
+
+	adc	%rax, %rax
+	add	%r8, 8(rp)
+	adc	%r9, 16(rp)
+	adc	%r10, 24(rp)
+	adc	%r11, 32(rp)
+	adc	%rcx, 40(rp)
+	adc	%rdx, 48(rp)
+	adc	%rax, 56(rp)
+	FUNC_EXIT()
+	ret
+
+
+L(0m4):
+	lea	-16(rp,n,8), tp		C point tp in middle of result operand
+	mov	(up), v0
+	mov	8(up), %rax
+	lea	(up,n,8), up		C point up at end of input operand
+
+	lea	-4(n), i
+C Function mpn_mul_1_m3(tp, up - i, i, up[-i - 1])
+	xor	R32(j), R32(j)
+	sub	n, j
+
+	mul	v0
+	xor	R32(w2), R32(w2)
+	mov	%rax, w0
+	mov	16(up,j,8), %rax
+	mov	%rdx, w3
+	jmp	L(L3)
+
+	ALIGN(16)
+L(mul_1_m3_top):
+	add	%rax, w2
+	mov	w3, (tp,j,8)
+	mov	(up,j,8), %rax
+	adc	%rdx, w1
+	xor	R32(w0), R32(w0)
+	mul	v0
+	xor	R32(w3), R32(w3)
+	mov	w2, 8(tp,j,8)
+	add	%rax, w1
+	adc	%rdx, w0
+	mov	8(up,j,8), %rax
+	mov	w1, 16(tp,j,8)
+	xor	R32(w2), R32(w2)
+	mul	v0
+	add	%rax, w0
+	mov	16(up,j,8), %rax
+	adc	%rdx, w3
+L(L3):	xor	R32(w1), R32(w1)
+	mul	v0
+	add	%rax, w3
+	mov	24(up,j,8), %rax
+	adc	%rdx, w2
+	mov	w0, 24(tp,j,8)
+	mul	v0
+	add	$4, j
+	js	L(mul_1_m3_top)
+
+	add	%rax, w2
+	mov	w3, (tp)
+	adc	%rdx, w1
+	mov	w2, 8(tp)
+	mov	w1, 16(tp)
+
+	lea	eval(2*8)(tp), tp	C tp += 2
+	lea	-8(up), up
+	jmp	L(dowhile)
+
+
+L(1m4):
+	lea	8(rp,n,8), tp		C point tp in middle of result operand
+	mov	(up), v0		C u0
+	mov	8(up), %rax		C u1
+	lea	8(up,n,8), up		C point up at end of input operand
+
+	lea	-3(n), i
+C Function mpn_mul_2s_m0(tp, up - i, i, up - i - 1)
+	lea	-3(n), j
+	neg	j
+
+	mov	%rax, v1		C u1
+	mul	v0			C u0 * u1
+	mov	%rdx, w1
+	xor	R32(w2), R32(w2)
+	mov	%rax, 8(rp)
+	jmp	L(m0)
+
+	ALIGN(16)
+L(mul_2_m0_top):
+	mul	v1
+	add	%rax, w0
+	adc	%rdx, w1
+	mov	-24(up,j,8), %rax
+	mov	$0, R32(w2)
+	mul	v0
+	add	%rax, w0
+	mov	-24(up,j,8), %rax
+	adc	%rdx, w1
+	adc	$0, R32(w2)
+	mul	v1			C v1 * u0
+	add	%rax, w1
+	mov	w0, -24(tp,j,8)
+	adc	%rdx, w2
+L(m0):	mov	-16(up,j,8), %rax	C u2, u6 ...
+	mul	v0			C u0 * u2
+	mov	$0, R32(w3)
+	add	%rax, w1
+	adc	%rdx, w2
+	mov	-16(up,j,8), %rax
+	adc	$0, R32(w3)
+	mov	$0, R32(w0)
+	mov	w1, -16(tp,j,8)
+	mul	v1
+	add	%rax, w2
+	mov	-8(up,j,8), %rax
+	adc	%rdx, w3
+	mov	$0, R32(w1)
+	mul	v0
+	add	%rax, w2
+	mov	-8(up,j,8), %rax
+	adc	%rdx, w3
+	adc	$0, R32(w0)
+	mul	v1
+	add	%rax, w3
+	mov	w2, -8(tp,j,8)
+	adc	%rdx, w0
+L(m2x):	mov	(up,j,8), %rax
+	mul	v0
+	add	%rax, w3
+	adc	%rdx, w0
+	adc	$0, R32(w1)
+	add	$4, j
+	mov	-32(up,j,8), %rax
+	mov	w3, -32(tp,j,8)
+	js	L(mul_2_m0_top)
+
+	mul	v1
+	add	%rax, w0
+	adc	%rdx, w1
+	mov	w0, -8(tp)
+	mov	w1, (tp)
+
+	lea	-16(up), up
+	lea	eval(3*8-24)(tp), tp	C tp += 3
+	jmp	L(dowhile_end)
+
+
+L(2m4):
+	lea	-16(rp,n,8), tp		C point tp in middle of result operand
+	mov	(up), v0
+	mov	8(up), %rax
+	lea	(up,n,8), up		C point up at end of input operand
+
+	lea	-4(n), i
+C Function mpn_mul_1_m1(tp, up - (i - 1), i - 1, up[-i])
+	lea	-2(n), j
+	neg	j
+
+	mul	v0
+	mov	%rax, w2
+	mov	(up,j,8), %rax
+	mov	%rdx, w1
+	jmp	L(L1)
+
+	ALIGN(16)
+L(mul_1_m1_top):
+	add	%rax, w2
+	mov	w3, (tp,j,8)
+	mov	(up,j,8), %rax
+	adc	%rdx, w1
+L(L1):	xor	R32(w0), R32(w0)
+	mul	v0
+	xor	R32(w3), R32(w3)
+	mov	w2, 8(tp,j,8)
+	add	%rax, w1
+	adc	%rdx, w0
+	mov	8(up,j,8), %rax
+	mov	w1, 16(tp,j,8)
+	xor	R32(w2), R32(w2)
+	mul	v0
+	add	%rax, w0
+	mov	16(up,j,8), %rax
+	adc	%rdx, w3
+	xor	R32(w1), R32(w1)
+	mul	v0
+	add	%rax, w3
+	mov	24(up,j,8), %rax
+	adc	%rdx, w2
+	mov	w0, 24(tp,j,8)
+	mul	v0
+	add	$4, j
+	js	L(mul_1_m1_top)
+
+	add	%rax, w2
+	mov	w3, (tp)
+	adc	%rdx, w1
+	mov	w2, 8(tp)
+	mov	w1, 16(tp)
+
+	lea	eval(2*8)(tp), tp	C tp += 2
+	lea	-8(up), up
+	jmp	L(dowhile_mid)
+
+
+L(3m4):
+	lea	8(rp,n,8), tp		C point tp in middle of result operand
+	mov	(up), v0		C u0
+	mov	8(up), %rax		C u1
+	lea	8(up,n,8), up		C point up at end of input operand
+
+	lea	-5(n), i
+C Function mpn_mul_2s_m2(tp, up - i + 1, i - 1, up - i)
+	lea	-1(n), j
+	neg	j
+
+	mov	%rax, v1		C u1
+	mul	v0			C u0 * u1
+	mov	%rdx, w3
+	xor	R32(w0), R32(w0)
+	xor	R32(w1), R32(w1)
+	mov	%rax, 8(rp)
+	jmp	L(m2)
+
+	ALIGN(16)
+L(mul_2_m2_top):
+	mul	v1
+	add	%rax, w0
+	adc	%rdx, w1
+	mov	-24(up,j,8), %rax
+	mov	$0, R32(w2)
+	mul	v0
+	add	%rax, w0
+	mov	-24(up,j,8), %rax
+	adc	%rdx, w1
+	adc	$0, R32(w2)
+	mul	v1			C v1 * u0
+	add	%rax, w1
+	mov	w0, -24(tp,j,8)
+	adc	%rdx, w2
+	mov	-16(up,j,8), %rax
+	mul	v0
+	mov	$0, R32(w3)
+	add	%rax, w1
+	adc	%rdx, w2
+	mov	-16(up,j,8), %rax
+	adc	$0, R32(w3)
+	mov	$0, R32(w0)
+	mov	w1, -16(tp,j,8)
+	mul	v1
+	add	%rax, w2
+	mov	-8(up,j,8), %rax
+	adc	%rdx, w3
+	mov	$0, R32(w1)
+	mul	v0
+	add	%rax, w2
+	mov	-8(up,j,8), %rax
+	adc	%rdx, w3
+	adc	$0, R32(w0)
+	mul	v1
+	add	%rax, w3
+	mov	w2, -8(tp,j,8)
+	adc	%rdx, w0
+L(m2):	mov	(up,j,8), %rax
+	mul	v0
+	add	%rax, w3
+	adc	%rdx, w0
+	adc	$0, R32(w1)
+	add	$4, j
+	mov	-32(up,j,8), %rax
+	mov	w3, -32(tp,j,8)
+	js	L(mul_2_m2_top)
+
+	mul	v1
+	add	%rax, w0
+	adc	%rdx, w1
+	mov	w0, -8(tp)
+	mov	w1, (tp)
+
+	lea	-16(up), up
+	jmp	L(dowhile_mid)
+
+L(dowhile):
+C Function mpn_addmul_2s_m2(tp, up - (i - 1), i - 1, up - i)
+	lea	4(i), j
+	neg	j
+
+	mov	16(up,j,8), v0
+	mov	24(up,j,8), v1
+	mov	24(up,j,8), %rax
+	mul	v0
+	xor	R32(w3), R32(w3)
+	add	%rax, 24(tp,j,8)
+	adc	%rdx, w3
+	xor	R32(w0), R32(w0)
+	xor	R32(w1), R32(w1)
+	jmp	L(am2)
+
+	ALIGN(16)
+L(addmul_2_m2_top):
+	add	w3, (tp,j,8)
+	adc	%rax, w0
+	mov	8(up,j,8), %rax
+	adc	%rdx, w1
+	mov	$0, R32(w2)
+	mul	v0
+	add	%rax, w0
+	mov	8(up,j,8), %rax
+	adc	%rdx, w1
+	adc	$0, R32(w2)
+	mul	v1				C v1 * u0
+	add	w0, 8(tp,j,8)
+	adc	%rax, w1
+	adc	%rdx, w2
+	mov	16(up,j,8), %rax
+	mov	$0, R32(w3)
+	mul	v0				C v0 * u1
+	add	%rax, w1
+	mov	16(up,j,8), %rax
+	adc	%rdx, w2
+	adc	$0, R32(w3)
+	mul	v1				C v1 * u1
+	add	w1, 16(tp,j,8)
+	adc	%rax, w2
+	mov	24(up,j,8), %rax
+	adc	%rdx, w3
+	mul	v0
+	mov	$0, R32(w0)
+	add	%rax, w2
+	adc	%rdx, w3
+	mov	$0, R32(w1)
+	mov	24(up,j,8), %rax
+	adc	$0, R32(w0)
+	mul	v1
+	add	w2, 24(tp,j,8)
+	adc	%rax, w3
+	adc	%rdx, w0
+L(am2):	mov	32(up,j,8), %rax
+	mul	v0
+	add	%rax, w3
+	mov	32(up,j,8), %rax
+	adc	%rdx, w0
+	adc	$0, R32(w1)
+	mul	v1
+	add	$4, j
+	js	L(addmul_2_m2_top)
+
+	add	w3, (tp)
+	adc	%rax, w0
+	adc	%rdx, w1
+	mov	w0, 8(tp)
+	mov	w1, 16(tp)
+
+	lea	eval(2*8)(tp), tp	C tp += 2
+
+	add	$-2, R32(i)		C i -= 2
+
+L(dowhile_mid):
+C Function mpn_addmul_2s_m0(tp, up - (i - 1), i - 1, up - i)
+	lea	2(i), j
+	neg	j
+
+	mov	(up,j,8), v0
+	mov	8(up,j,8), v1
+	mov	8(up,j,8), %rax
+	mul	v0
+	xor	R32(w1), R32(w1)
+	add	%rax, 8(tp,j,8)
+	adc	%rdx, w1
+	xor	R32(w2), R32(w2)
+	jmp	L(20)
+
+	ALIGN(16)
+L(addmul_2_m0_top):
+	add	w3, (tp,j,8)
+	adc	%rax, w0
+	mov	8(up,j,8), %rax
+	adc	%rdx, w1
+	mov	$0, R32(w2)
+	mul	v0
+	add	%rax, w0
+	mov	8(up,j,8), %rax
+	adc	%rdx, w1
+	adc	$0, R32(w2)
+	mul	v1				C v1 * u0
+	add	w0, 8(tp,j,8)
+	adc	%rax, w1
+	adc	%rdx, w2
+L(20):	mov	16(up,j,8), %rax
+	mov	$0, R32(w3)
+	mul	v0				C v0 * u1
+	add	%rax, w1
+	mov	16(up,j,8), %rax
+	adc	%rdx, w2
+	adc	$0, R32(w3)
+	mul	v1				C v1 * u1
+	add	w1, 16(tp,j,8)
+	adc	%rax, w2
+	mov	24(up,j,8), %rax
+	adc	%rdx, w3
+	mul	v0
+	mov	$0, R32(w0)
+	add	%rax, w2
+	adc	%rdx, w3
+	mov	$0, R32(w1)
+	mov	24(up,j,8), %rax
+	adc	$0, R32(w0)
+	mul	v1
+	add	w2, 24(tp,j,8)
+	adc	%rax, w3
+	adc	%rdx, w0
+	mov	32(up,j,8), %rax
+	mul	v0
+	add	%rax, w3
+	mov	32(up,j,8), %rax
+	adc	%rdx, w0
+	adc	$0, R32(w1)
+	mul	v1
+	add	$4, j
+	js	L(addmul_2_m0_top)
+
+	add	w3, (tp)
+	adc	%rax, w0
+	adc	%rdx, w1
+	mov	w0, 8(tp)
+	mov	w1, 16(tp)
+
+	lea	eval(2*8)(tp), tp	C tp += 2
+L(dowhile_end):
+
+	add	$-2, R32(i)		C i -= 2
+	jne	L(dowhile)
+
+C Function mpn_addmul_2s_2
+	mov	-16(up), v0
+	mov	-8(up), v1
+	mov	-8(up), %rax
+	mul	v0
+	xor	R32(w3), R32(w3)
+	add	%rax, -8(tp)
+	adc	%rdx, w3
+	xor	R32(w0), R32(w0)
+	xor	R32(w1), R32(w1)
+	mov	(up), %rax
+	mul	v0
+	add	%rax, w3
+	mov	(up), %rax
+	adc	%rdx, w0
+	mul	v1
+	add	w3, (tp)
+	adc	%rax, w0
+	adc	%rdx, w1
+	mov	w0, 8(tp)
+	mov	w1, 16(tp)
+
+C Function mpn_sqr_diag_addlsh1
+	lea	-4(n,n), j
+
+	mov	8(rp), %r11
+	lea	-8(up), up
+	lea	(rp,j,8), rp
+	neg	j
+	mov	(up,j,4), %rax
+	mul	%rax
+	test	$2, R8(j)
+	jnz	L(odd)
+
+L(evn):	add	%r11, %r11
+	sbb	R32(%rbx), R32(%rbx)		C save CF
+	add	%rdx, %r11
+	mov	%rax, (rp,j,8)
+	jmp	L(d0)
+
+L(odd):	add	%r11, %r11
+	sbb	R32(%rbp), R32(%rbp)		C save CF
+	add	%rdx, %r11
+	mov	%rax, (rp,j,8)
+	lea	-2(j), j
+	jmp	L(d1)
+
+	ALIGN(16)
+L(top):	mov	(up,j,4), %rax
+	mul	%rax
+	add	R32(%rbp), R32(%rbp)		C restore carry
+	adc	%rax, %r10
+	adc	%rdx, %r11
+	mov	%r10, (rp,j,8)
+L(d0):	mov	%r11, 8(rp,j,8)
+	mov	16(rp,j,8), %r10
+	adc	%r10, %r10
+	mov	24(rp,j,8), %r11
+	adc	%r11, %r11
+	nop
+	sbb	R32(%rbp), R32(%rbp)		C save CF
+	mov	8(up,j,4), %rax
+	mul	%rax
+	add	R32(%rbx), R32(%rbx)		C restore carry
+	adc	%rax, %r10
+	adc	%rdx, %r11
+	mov	%r10, 16(rp,j,8)
+L(d1):	mov	%r11, 24(rp,j,8)
+	mov	32(rp,j,8), %r10
+	adc	%r10, %r10
+	mov	40(rp,j,8), %r11
+	adc	%r11, %r11
+	sbb	R32(%rbx), R32(%rbx)		C save CF
+	add	$4, j
+	js	L(top)
+
+	mov	(up), %rax
+	mul	%rax
+	add	R32(%rbp), R32(%rbp)		C restore carry
+	adc	%rax, %r10
+	adc	%rdx, %r11
+	mov	%r10, (rp)
+	mov	%r11, 8(rp)
+	mov	16(rp), %r10
+	adc	%r10, %r10
+	sbb	R32(%rbp), R32(%rbp)		C save CF
+	neg	R32(%rbp)
+	mov	8(up), %rax
+	mul	%rax
+	add	R32(%rbx), R32(%rbx)		C restore carry
+	adc	%rax, %r10
+	adc	%rbp, %rdx
+	mov	%r10, 16(rp)
+	mov	%rdx, 24(rp)
+
+	pop	%r14
+	pop	%r13
+	pop	%r12
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/logops_n.asm b/third_party/gmp/mpn/x86_64/logops_n.asm
new file mode 100644
index 0000000..e25854d
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/logops_n.asm
@@ -0,0 +1,260 @@
+dnl  AMD64 logops.
+
+dnl  Copyright 2004-2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C		c/l	c/l	c/l	good
+C	       var-1   var-2   var-3  for cpu?
+C AMD K8,K9	 1.5	 1.5	 1.5	 y
+C AMD K10	 1.5	 1.5	 1.5	 y
+C AMD bd1
+C AMD bd2
+C AMD bd3
+C AMD bd4
+C AMD bt1	 2.67	~2.79	~2.67
+C AMD bt2	 2.0	 2.28	 2.28	 y
+C AMD zen	 1.5	 1.5	 1.5	 =
+C Intel P4	 2.8	 3.35	 3.6
+C Intel PNR	 2.0	 2.0	 2.0	 =
+C Intel NHM	 2.0	 2.0	 2.0	 =
+C Intel SBR	 1.5	 1.75	 1.75	 n
+C Intel IBR	 1.48	 1.71	 1.72	 n
+C Intel HWL	 1.5	 1.5	 1.5	 n
+C Intel BWL	 1.5	 1.5	 1.5	 n
+C Intel SKL	 1.5	 1.5	 1.5	 n
+C Intel atom	 3.82	 3.82	 3.82	 n
+C Intel SLM	 3.0	 3.0	 3.0	 =
+C VIA nano	 3.25
+
+ifdef(`OPERATION_and_n',`
+  define(`func',`mpn_and_n')
+  define(`VARIANT_1')
+  define(`LOGOP',`and')')
+ifdef(`OPERATION_andn_n',`
+  define(`func',`mpn_andn_n')
+  define(`VARIANT_2')
+  define(`LOGOP',`and')')
+ifdef(`OPERATION_nand_n',`
+  define(`func',`mpn_nand_n')
+  define(`VARIANT_3')
+  define(`LOGOP',`and')')
+ifdef(`OPERATION_ior_n',`
+  define(`func',`mpn_ior_n')
+  define(`VARIANT_1')
+  define(`LOGOP',`or')')
+ifdef(`OPERATION_iorn_n',`
+  define(`func',`mpn_iorn_n')
+  define(`VARIANT_2')
+  define(`LOGOP',`or')')
+ifdef(`OPERATION_nior_n',`
+  define(`func',`mpn_nior_n')
+  define(`VARIANT_3')
+  define(`LOGOP',`or')')
+ifdef(`OPERATION_xor_n',`
+  define(`func',`mpn_xor_n')
+  define(`VARIANT_1')
+  define(`LOGOP',`xor')')
+ifdef(`OPERATION_xnor_n',`
+  define(`func',`mpn_xnor_n')
+  define(`VARIANT_2')
+  define(`LOGOP',`xor')')
+
+
+MULFUNC_PROLOGUE(mpn_and_n mpn_andn_n mpn_nand_n mpn_ior_n mpn_iorn_n mpn_nior_n mpn_xor_n mpn_xnor_n)
+
+C INPUT PARAMETERS
+define(`rp',`%rdi')
+define(`up',`%rsi')
+define(`vp',`%rdx')
+define(`n',`%rcx')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+
+ifdef(`VARIANT_1',`
+	TEXT
+	ALIGN(32)
+PROLOGUE(func)
+	FUNC_ENTRY(4)
+	mov	(vp), %r8
+	mov	R32(%rcx), R32(%rax)
+	lea	(vp,n,8), vp
+	lea	(up,n,8), up
+	lea	(rp,n,8), rp
+	neg	n
+	and	$3, R32(%rax)
+	je	L(b00)
+	cmp	$2, R32(%rax)
+	jc	L(b01)
+	je	L(b10)
+
+L(b11):	LOGOP	(up,n,8), %r8
+	mov	%r8, (rp,n,8)
+	dec	n
+	jmp	L(e11)
+L(b10):	add	$-2, n
+	jmp	L(e10)
+L(b01):	LOGOP	(up,n,8), %r8
+	mov	%r8, (rp,n,8)
+	inc	n
+	jz	L(ret)
+
+L(top):	mov	(vp,n,8), %r8
+L(b00):	mov	8(vp,n,8), %r9
+	LOGOP	(up,n,8), %r8
+	LOGOP	8(up,n,8), %r9
+	nop				C K8/K9/K10 concession
+	mov	%r8, (rp,n,8)
+	mov	%r9, 8(rp,n,8)
+L(e11):	mov	16(vp,n,8), %r8
+L(e10):	mov	24(vp,n,8), %r9
+	LOGOP	16(up,n,8), %r8
+	LOGOP	24(up,n,8), %r9
+	mov	%r8, 16(rp,n,8)
+	mov	%r9, 24(rp,n,8)
+	add	$4, n
+	jnc	L(top)
+
+L(ret):	FUNC_EXIT()
+	ret
+EPILOGUE()
+')
+
+ifdef(`VARIANT_2',`
+	TEXT
+	ALIGN(32)
+PROLOGUE(func)
+	FUNC_ENTRY(4)
+	mov	(vp), %r8
+	not	%r8
+	mov	R32(%rcx), R32(%rax)
+	lea	(vp,n,8), vp
+	lea	(up,n,8), up
+	lea	(rp,n,8), rp
+	neg	n
+	and	$3, R32(%rax)
+	je	L(b00)
+	cmp	$2, R32(%rax)
+	jc	L(b01)
+	je	L(b10)
+
+L(b11):	LOGOP	(up,n,8), %r8
+	mov	%r8, (rp,n,8)
+	dec	n
+	jmp	L(e11)
+L(b10):	add	$-2, n
+	jmp	L(e10)
+	.byte	0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90
+L(b01):	LOGOP	(up,n,8), %r8
+	mov	%r8, (rp,n,8)
+	inc	n
+	jz	L(ret)
+
+L(top):	mov	(vp,n,8), %r8
+	not	%r8
+L(b00):	mov	8(vp,n,8), %r9
+	not	%r9
+	LOGOP	(up,n,8), %r8
+	LOGOP	8(up,n,8), %r9
+	mov	%r8, (rp,n,8)
+	mov	%r9, 8(rp,n,8)
+L(e11):	mov	16(vp,n,8), %r8
+	not	%r8
+L(e10):	mov	24(vp,n,8), %r9
+	not	%r9
+	LOGOP	16(up,n,8), %r8
+	LOGOP	24(up,n,8), %r9
+	mov	%r8, 16(rp,n,8)
+	mov	%r9, 24(rp,n,8)
+	add	$4, n
+	jnc	L(top)
+
+L(ret):	FUNC_EXIT()
+	ret
+EPILOGUE()
+')
+
+ifdef(`VARIANT_3',`
+	TEXT
+	ALIGN(32)
+PROLOGUE(func)
+	FUNC_ENTRY(4)
+	mov	(vp), %r8
+	mov	R32(%rcx), R32(%rax)
+	lea	(vp,n,8), vp
+	lea	(up,n,8), up
+	lea	(rp,n,8), rp
+	neg	n
+	and	$3, R32(%rax)
+	je	L(b00)
+	cmp	$2, R32(%rax)
+	jc	L(b01)
+	je	L(b10)
+
+L(b11):	LOGOP	(up,n,8), %r8
+	not	%r8
+	mov	%r8, (rp,n,8)
+	dec	n
+	jmp	L(e11)
+L(b10):	add	$-2, n
+	jmp	L(e10)
+	.byte	0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90
+L(b01):	LOGOP	(up,n,8), %r8
+	not	%r8
+	mov	%r8, (rp,n,8)
+	inc	n
+	jz	L(ret)
+
+L(top):	mov	(vp,n,8), %r8
+L(b00):	mov	8(vp,n,8), %r9
+	LOGOP	(up,n,8), %r8
+	not	%r8
+	LOGOP	8(up,n,8), %r9
+	not	%r9
+	mov	%r8, (rp,n,8)
+	mov	%r9, 8(rp,n,8)
+L(e11):	mov	16(vp,n,8), %r8
+L(e10):	mov	24(vp,n,8), %r9
+	LOGOP	16(up,n,8), %r8
+	not	%r8
+	LOGOP	24(up,n,8), %r9
+	not	%r9
+	mov	%r8, 16(rp,n,8)
+	mov	%r9, 24(rp,n,8)
+	add	$4, n
+	jnc	L(top)
+
+L(ret):	FUNC_EXIT()
+	ret
+EPILOGUE()
+')
diff --git a/third_party/gmp/mpn/x86_64/lshift.asm b/third_party/gmp/mpn/x86_64/lshift.asm
new file mode 100644
index 0000000..fff3152
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/lshift.asm
@@ -0,0 +1,172 @@
+dnl  AMD64 mpn_lshift -- mpn left shift.
+
+dnl  Copyright 2003, 2005, 2007, 2009, 2011, 2012, 2018 Free Software
+dnl  Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C	     cycles/limb   cycles/limb cnt=1
+C AMD K8,K9	 2.375		 1.375
+C AMD K10	 2.375		 1.375
+C Intel P4	 8		10.5
+C Intel core2	 2.11		 4.28
+C Intel corei	 ?		 ?
+C Intel atom	 5.75		 3.5
+C VIA nano	 3.5		 2.25
+
+
+C INPUT PARAMETERS
+define(`rp',	`%rdi')
+define(`up',	`%rsi')
+define(`n',	`%rdx')
+define(`cnt',	`%rcx')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_lshift)
+	FUNC_ENTRY(4)
+	neg	R32(%rcx)		C put rsh count in cl
+	mov	-8(up,n,8), %rax
+	shr	R8(%rcx), %rax		C function return value
+
+	neg	R32(%rcx)		C put lsh count in cl
+	lea	1(n), R32(%r8)
+	and	$3, R32(%r8)
+	je	L(rlx)			C jump for n = 3, 7, 11, ...
+
+	dec	R32(%r8)
+	jne	L(1)
+C	n = 4, 8, 12, ...
+	mov	-8(up,n,8), %r10
+	shl	R8(%rcx), %r10
+	neg	R32(%rcx)		C put rsh count in cl
+	mov	-16(up,n,8), %r8
+	shr	R8(%rcx), %r8
+	or	%r8, %r10
+	mov	%r10, -8(rp,n,8)
+	dec	n
+	jmp	L(rll)
+
+L(1):	dec	R32(%r8)
+	je	L(1x)			C jump for n = 1, 5, 9, 13, ...
+C	n = 2, 6, 10, 16, ...
+	mov	-8(up,n,8), %r10
+	shl	R8(%rcx), %r10
+	neg	R32(%rcx)		C put rsh count in cl
+	mov	-16(up,n,8), %r8
+	shr	R8(%rcx), %r8
+	or	%r8, %r10
+	mov	%r10, -8(rp,n,8)
+	dec	n
+	neg	R32(%rcx)		C put lsh count in cl
+L(1x):
+	cmp	$1, n
+	je	L(ast)
+	mov	-8(up,n,8), %r10
+	shl	R8(%rcx), %r10
+	mov	-16(up,n,8), %r11
+	shl	R8(%rcx), %r11
+	neg	R32(%rcx)		C put rsh count in cl
+	mov	-16(up,n,8), %r8
+	mov	-24(up,n,8), %r9
+	shr	R8(%rcx), %r8
+	or	%r8, %r10
+	shr	R8(%rcx), %r9
+	or	%r9, %r11
+	mov	%r10, -8(rp,n,8)
+	mov	%r11, -16(rp,n,8)
+	sub	$2, n
+
+L(rll):	neg	R32(%rcx)		C put lsh count in cl
+L(rlx):	mov	-8(up,n,8), %r10
+	shl	R8(%rcx), %r10
+	mov	-16(up,n,8), %r11
+	shl	R8(%rcx), %r11
+
+	sub	$4, n			C				      4
+	jb	L(end)			C				      2
+	ALIGN(16)
+L(top):
+	C finish stuff from lsh block
+	neg	R32(%rcx)		C put rsh count in cl
+	mov	16(up,n,8), %r8
+	mov	8(up,n,8), %r9
+	shr	R8(%rcx), %r8
+	or	%r8, %r10
+	shr	R8(%rcx), %r9
+	or	%r9, %r11
+	mov	%r10, 24(rp,n,8)
+	mov	%r11, 16(rp,n,8)
+	C start two new rsh
+	mov	0(up,n,8), %r8
+	mov	-8(up,n,8), %r9
+	shr	R8(%rcx), %r8
+	shr	R8(%rcx), %r9
+
+	C finish stuff from rsh block
+	neg	R32(%rcx)		C put lsh count in cl
+	mov	8(up,n,8), %r10
+	mov	0(up,n,8), %r11
+	shl	R8(%rcx), %r10
+	or	%r10, %r8
+	shl	R8(%rcx), %r11
+	or	%r11, %r9
+	mov	%r8, 8(rp,n,8)
+	mov	%r9, 0(rp,n,8)
+	C start two new lsh
+	mov	-8(up,n,8), %r10
+	mov	-16(up,n,8), %r11
+	shl	R8(%rcx), %r10
+	shl	R8(%rcx), %r11
+
+	sub	$4, n
+	jae	L(top)			C				      2
+L(end):
+	neg	R32(%rcx)		C put rsh count in cl
+	mov	8(up), %r8
+	shr	R8(%rcx), %r8
+	or	%r8, %r10
+	mov	(up), %r9
+	shr	R8(%rcx), %r9
+	or	%r9, %r11
+	mov	%r10, 16(rp)
+	mov	%r11, 8(rp)
+
+	neg	R32(%rcx)		C put lsh count in cl
+L(ast):	mov	(up), %r10
+	shl	R8(%rcx), %r10
+	mov	%r10, (rp)
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/lshiftc.asm b/third_party/gmp/mpn/x86_64/lshiftc.asm
new file mode 100644
index 0000000..c4ba04a
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/lshiftc.asm
@@ -0,0 +1,182 @@
+dnl  AMD64 mpn_lshiftc -- mpn left shift with complement.
+
+dnl  Copyright 2003, 2005, 2006, 2009, 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C	     cycles/limb
+C AMD K8,K9	 2.75
+C AMD K10	 2.75
+C Intel P4	 ?
+C Intel core2	 ?
+C Intel corei	 ?
+C Intel atom	 ?
+C VIA nano	 3.75
+
+
+C INPUT PARAMETERS
+define(`rp',	`%rdi')
+define(`up',	`%rsi')
+define(`n',	`%rdx')
+define(`cnt',	`%rcx')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_lshiftc)
+	FUNC_ENTRY(4)
+	neg	R32(%rcx)		C put rsh count in cl
+	mov	-8(up,n,8), %rax
+	shr	R8(%rcx), %rax		C function return value
+
+	neg	R32(%rcx)		C put lsh count in cl
+	lea	1(n), R32(%r8)
+	and	$3, R32(%r8)
+	je	L(rlx)			C jump for n = 3, 7, 11, ...
+
+	dec	R32(%r8)
+	jne	L(1)
+C	n = 4, 8, 12, ...
+	mov	-8(up,n,8), %r10
+	shl	R8(%rcx), %r10
+	neg	R32(%rcx)		C put rsh count in cl
+	mov	-16(up,n,8), %r8
+	shr	R8(%rcx), %r8
+	or	%r8, %r10
+	not	%r10
+	mov	%r10, -8(rp,n,8)
+	dec	n
+	jmp	L(rll)
+
+L(1):	dec	R32(%r8)
+	je	L(1x)			C jump for n = 1, 5, 9, 13, ...
+C	n = 2, 6, 10, 16, ...
+	mov	-8(up,n,8), %r10
+	shl	R8(%rcx), %r10
+	neg	R32(%rcx)		C put rsh count in cl
+	mov	-16(up,n,8), %r8
+	shr	R8(%rcx), %r8
+	or	%r8, %r10
+	not	%r10
+	mov	%r10, -8(rp,n,8)
+	dec	n
+	neg	R32(%rcx)		C put lsh count in cl
+L(1x):
+	cmp	$1, n
+	je	L(ast)
+	mov	-8(up,n,8), %r10
+	shl	R8(%rcx), %r10
+	mov	-16(up,n,8), %r11
+	shl	R8(%rcx), %r11
+	neg	R32(%rcx)		C put rsh count in cl
+	mov	-16(up,n,8), %r8
+	mov	-24(up,n,8), %r9
+	shr	R8(%rcx), %r8
+	or	%r8, %r10
+	shr	R8(%rcx), %r9
+	or	%r9, %r11
+	not	%r10
+	not	%r11
+	mov	%r10, -8(rp,n,8)
+	mov	%r11, -16(rp,n,8)
+	sub	$2, n
+
+L(rll):	neg	R32(%rcx)		C put lsh count in cl
+L(rlx):	mov	-8(up,n,8), %r10
+	shl	R8(%rcx), %r10
+	mov	-16(up,n,8), %r11
+	shl	R8(%rcx), %r11
+
+	sub	$4, n			C				      4
+	jb	L(end)			C				      2
+	ALIGN(16)
+L(top):
+	C finish stuff from lsh block
+	neg	R32(%rcx)		C put rsh count in cl
+	mov	16(up,n,8), %r8
+	mov	8(up,n,8), %r9
+	shr	R8(%rcx), %r8
+	or	%r8, %r10
+	shr	R8(%rcx), %r9
+	or	%r9, %r11
+	not	%r10
+	not	%r11
+	mov	%r10, 24(rp,n,8)
+	mov	%r11, 16(rp,n,8)
+	C start two new rsh
+	mov	0(up,n,8), %r8
+	mov	-8(up,n,8), %r9
+	shr	R8(%rcx), %r8
+	shr	R8(%rcx), %r9
+
+	C finish stuff from rsh block
+	neg	R32(%rcx)		C put lsh count in cl
+	mov	8(up,n,8), %r10
+	mov	0(up,n,8), %r11
+	shl	R8(%rcx), %r10
+	or	%r10, %r8
+	shl	R8(%rcx), %r11
+	or	%r11, %r9
+	not	%r8
+	not	%r9
+	mov	%r8, 8(rp,n,8)
+	mov	%r9, 0(rp,n,8)
+	C start two new lsh
+	mov	-8(up,n,8), %r10
+	mov	-16(up,n,8), %r11
+	shl	R8(%rcx), %r10
+	shl	R8(%rcx), %r11
+
+	sub	$4, n
+	jae	L(top)			C				      2
+L(end):
+	neg	R32(%rcx)		C put rsh count in cl
+	mov	8(up), %r8
+	shr	R8(%rcx), %r8
+	or	%r8, %r10
+	mov	(up), %r9
+	shr	R8(%rcx), %r9
+	or	%r9, %r11
+	not	%r10
+	not	%r11
+	mov	%r10, 16(rp)
+	mov	%r11, 8(rp)
+
+	neg	R32(%rcx)		C put lsh count in cl
+L(ast):	mov	(up), %r10
+	shl	R8(%rcx), %r10
+	not	%r10
+	mov	%r10, (rp)
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/lshsub_n.asm b/third_party/gmp/mpn/x86_64/lshsub_n.asm
new file mode 100644
index 0000000..4d428c0
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/lshsub_n.asm
@@ -0,0 +1,172 @@
+dnl  AMD64 mpn_lshsub_n.  R = 2^k(U - V).
+
+dnl  Copyright 2006, 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C	     cycles/limb
+C AMD K8,K9	 3.15	(mpn_sub_n + mpn_lshift costs about 4 c/l)
+C AMD K10	 3.15	(mpn_sub_n + mpn_lshift costs about 4 c/l)
+C Intel P4	16.5
+C Intel core2	 4.35
+C Intel corei	 ?
+C Intel atom	 ?
+C VIA nano	 ?
+
+C This was written quickly and not optimized at all, but it runs very well on
+C K8.  But perhaps one could get under 3 c/l.  Ideas:
+C   1) Use indexing to save the 3 LEA
+C   2) Write reasonable feed-in code
+C   3) Be more clever about register usage
+C   4) Unroll more, handling CL negation, carry save/restore cost much now
+C   5) Reschedule
+
+C INPUT PARAMETERS
+define(`rp',	`%rdi')
+define(`up',	`%rsi')
+define(`vp',	`%rdx')
+define(`n',	`%rcx')
+define(`cnt',	`%r8')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_lshsub_n)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8d	')
+
+	push	%r12
+	push	%r13
+	push	%r14
+	push	%r15
+	push	%rbx
+
+	mov	n, %rax
+	xor	R32(%rbx), R32(%rbx)	C clear carry save register
+	mov	R32(%r8), R32(%rcx)	C shift count
+	xor	R32(%r15), R32(%r15)	C limb carry
+
+	mov	R32(%rax), R32(%r11)
+	and	$3, R32(%r11)
+	je	L(4)
+	sub	$1, R32(%r11)
+
+L(oopette):
+	add	R32(%rbx), R32(%rbx)	C restore carry flag
+	mov	0(up), %r8
+	lea	8(up), up
+	sbb	0(vp), %r8
+	mov	%r8, %r12
+	sbb	R32(%rbx), R32(%rbx)	C save carry flag
+	shl	R8(%rcx), %r8
+	or	%r15, %r8
+	mov	%r12, %r15
+	lea	8(vp), vp
+	neg	R8(%rcx)
+	shr	R8(%rcx), %r15
+	neg	R8(%rcx)
+	mov	%r8, 0(rp)
+	lea	8(rp), rp
+	sub	$1, R32(%r11)
+	jnc	L(oopette)
+
+L(4):
+	sub	$4, %rax
+	jc	L(end)
+
+	ALIGN(16)
+L(oop):
+	add	R32(%rbx), R32(%rbx)	C restore carry flag
+
+	mov	0(up), %r8
+	mov	8(up), %r9
+	mov	16(up), %r10
+	mov	24(up), %r11
+
+	lea	32(up), up
+
+	sbb	0(vp), %r8
+	mov	%r8, %r12
+	sbb	8(vp), %r9
+	mov	%r9, %r13
+	sbb	16(vp), %r10
+	mov	%r10, %r14
+	sbb	24(vp), %r11
+
+	sbb	R32(%rbx), R32(%rbx)	C save carry flag
+
+	shl	R8(%rcx), %r8
+	shl	R8(%rcx), %r9
+	shl	R8(%rcx), %r10
+	or	%r15, %r8
+	mov	%r11, %r15
+	shl	R8(%rcx), %r11
+
+	lea	32(vp), vp
+
+	neg	R8(%rcx)
+
+	shr	R8(%rcx), %r12
+	shr	R8(%rcx), %r13
+	shr	R8(%rcx), %r14
+	shr	R8(%rcx), %r15		C used next loop
+
+	or	%r12, %r9
+	or	%r13, %r10
+	or	%r14, %r11
+
+	neg	R8(%rcx)
+
+	mov	%r8, 0(rp)
+	mov	%r9, 8(rp)
+	mov	%r10, 16(rp)
+	mov	%r11, 24(rp)
+
+	lea	32(rp), rp
+
+	sub	$4, %rax
+	jnc	L(oop)
+L(end):
+	neg	R32(%rbx)
+	shl	R8(%rcx), %rbx
+	adc	%r15, %rbx
+	mov	%rbx, %rax
+	pop	%rbx
+	pop	%r15
+	pop	%r14
+	pop	%r13
+	pop	%r12
+
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/missing-call.m4 b/third_party/gmp/mpn/x86_64/missing-call.m4
new file mode 100644
index 0000000..c024f0e
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/missing-call.m4
@@ -0,0 +1,53 @@
+dnl  AMD64 MULX/ADX simulation support, function call version.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+define(`adox',`
+	push	$1
+	push	$2
+	call	__gmp_adox
+	pop	$2
+')
+
+define(`adcx',`
+	push	$1
+	push	$2
+	call	__gmp_adcx
+	pop	$2
+')
+
+define(`mulx',`
+	push	$1
+	call	__gmp_mulx
+	pop	$2
+	pop	$3
+')
diff --git a/third_party/gmp/mpn/x86_64/missing-inline.m4 b/third_party/gmp/mpn/x86_64/missing-inline.m4
new file mode 100644
index 0000000..bd1df13
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/missing-inline.m4
@@ -0,0 +1,100 @@
+dnl  AMD64 MULX/ADX simulation support, inline version.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+define(`adox',`
+	push	$2
+	push	%rcx
+	push	%rbx
+	push	%rax
+	mov	$1, %rcx
+	pushfq
+	pushfq
+C copy 0(%rsp):11 to 0(%rsp):0
+	mov	(%rsp), %rbx
+	shr	%rbx
+	bt	$`'10, %rbx
+	adc	%rbx, %rbx
+	mov	%rbx, (%rsp)
+C put manipulated flags into eflags, execute a plain adc
+	popfq
+	adc	%rcx, 32(%rsp)
+C copy CF to 0(%rsp):11
+	mov	(%rsp), %rbx
+	sbb	R32(%rax), R32(%rax)
+	and	$`'0x800, R32(%rax)
+	and	$`'0xfffffffffffff7ff, %rbx
+	or	%rax, %rbx
+	mov	%rbx, (%rsp)
+C put manipulated flags into eflags
+	popfq
+	pop	%rax
+	pop	%rbx
+	pop	%rcx
+	pop	$2
+')
+
+define(`adcx',`
+	push	$2
+	push	%rcx
+	push	%rbx
+	push	%rax
+	mov	$1, %rcx
+	pushfq
+	adc	%rcx, 32(%rsp)
+	mov	(%rsp), %rbx
+	sbb	R32(%rax), R32(%rax)
+	and	$`'0xfffffffffffffffe, %rbx
+	sub	%rax, %rbx
+	mov	%rbx, (%rsp)
+	popfq
+	pop	%rax
+	pop	%rbx
+	pop	%rcx
+	pop	$2
+')
+
+define(`mulx',`
+	lea	-16(%rsp), %rsp
+	push	%rax
+	push	%rdx
+	pushfq			C preserve all flags
+	mov	$1, %rax
+	mul	%rdx
+	mov	%rax, 24(%rsp)
+	mov	%rdx, 32(%rsp)
+	popfq			C restore eflags
+	pop	%rdx
+	pop	%rax
+	pop	$2
+	pop	$3
+')
diff --git a/third_party/gmp/mpn/x86_64/missing.asm b/third_party/gmp/mpn/x86_64/missing.asm
new file mode 100644
index 0000000..9b65c89
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/missing.asm
@@ -0,0 +1,130 @@
+
+	dnl  AMD64 MULX/ADX simulation support.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+ASM_START()
+
+C Fake the MULX instruction
+C
+C Accept the single explicit parameter on the stack, return the two result
+C words on the stack.  This calling convention means that we need to move the
+C return address up.
+C
+PROLOGUE(__gmp_mulx)
+	lea	-8(%rsp), %rsp
+	push	%rax
+	push	%rdx
+	pushfq				C preserve all flags
+	mov	32(%rsp), %rax		C move retaddr...
+	mov	%rax, 24(%rsp)		C ...up the stack
+	mov	40(%rsp), %rax		C input parameter
+	mul	%rdx
+	mov	%rax, 32(%rsp)
+	mov	%rdx, 40(%rsp)
+	popfq				C restore eflags
+	pop	%rdx
+	pop	%rax
+	ret
+EPILOGUE()
+PROTECT(__gmp_mulx)
+
+
+C Fake the ADOX instruction
+C
+C Accept the two parameters on the stack, return the result word on the stack.
+C This calling convention means that we need to move the return address down.
+C
+PROLOGUE(__gmp_adox)
+	push	%rcx
+	push	%rbx
+	push	%rax
+	mov	32(%rsp), %rcx		C src2
+	mov	24(%rsp), %rax		C move retaddr...
+	mov	%rax, 32(%rsp)		C ...down the stack
+	pushfq
+C copy 0(%rsp):11 to 0(%rsp):0
+	mov	(%rsp), %rbx
+	shr	%rbx
+	bt	$10, %rbx
+	adc	%rbx, %rbx
+	push	%rbx
+C put manipulated flags into eflags, execute a plain adc
+	popfq
+	adc	%rcx, 48(%rsp)
+C copy CF to 0(%rsp):11
+	pop	%rbx
+	sbb	R32(%rax), R32(%rax)
+	and	$0x800, R32(%rax)
+	and	$0xfffffffffffff7ff, %rbx
+	or	%rax, %rbx
+	push	%rbx
+C put manipulated flags into eflags
+	popfq
+	pop	%rax
+	pop	%rbx
+	pop	%rcx
+	lea	8(%rsp), %rsp
+	ret
+EPILOGUE()
+PROTECT(__gmp_adox)
+
+
+C Fake the ADCX instruction
+C
+C Accept the two parameters on the stack, return the result word on the stack.
+C This calling convention means that we need to move the return address down.
+C
+PROLOGUE(__gmp_adcx)
+	push	%rcx
+	push	%rbx
+	push	%rax
+	mov	32(%rsp), %rcx		C src2
+	mov	24(%rsp), %rax		C move retaddr...
+	mov	%rax, 32(%rsp)		C ...down the stack
+	pushfq
+	adc	%rcx, 48(%rsp)
+	pop	%rbx
+	sbb	R32(%rax), R32(%rax)
+	and	$`'0xfffffffffffffffe, %rbx
+	sub	%rax, %rbx
+	push	%rbx
+	popfq
+	pop	%rax
+	pop	%rbx
+	pop	%rcx
+	lea	8(%rsp), %rsp
+	ret
+EPILOGUE()
+PROTECT(__gmp_adcx)
diff --git a/third_party/gmp/mpn/x86_64/mod_1_1.asm b/third_party/gmp/mpn/x86_64/mod_1_1.asm
new file mode 100644
index 0000000..255305f
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/mod_1_1.asm
@@ -0,0 +1,238 @@
+dnl  AMD64 mpn_mod_1_1p
+
+dnl  Contributed to the GNU project by Torbjörn Granlund and Niels Möller.
+
+dnl  Copyright 2009-2012, 2014 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 6
+C AMD K10	 6
+C Intel P4	26
+C Intel core2	12.5
+C Intel NHM	11.3
+C Intel SBR	 8.4	(slowdown, old code took 8.0)
+C Intel atom	26
+C VIA nano	13
+
+define(`B2mb',   `%r10')
+define(`B2modb', `%r11')
+define(`ap',     `%rdi')
+define(`n',      `%rsi')
+define(`pre',    `%r8')
+define(`b',      `%rbx')
+
+define(`r0',     `%rbp') C r1 kept in %rax
+define(`r2',	 `%rcx')  C kept negated. Also used as shift count
+define(`t0',     `%r9')
+
+C mp_limb_t
+C mpn_mod_1_1p (mp_srcptr ap, mp_size_t n, mp_limb_t b, mp_limb_t bmodb[4])
+C                       %rdi         %rsi         %rdx                %rcx
+C The pre array contains bi, cnt, B1modb, B2modb
+C Note: This implementation needs B1modb only when cnt > 0
+
+C The iteration is almost as follows,
+C
+C   r_2 B^3 + r_1 B^2 + r_0 B + u = r_1 B2modb + (r_0 + r_2 B2mod) B + u
+C
+C where r2 is a single bit represented as a mask. But to make sure that the
+C result fits in two limbs and a bit, carry from the addition
+C
+C   r_0 + r_2 B2mod
+C
+C is handled specially. On carry, we subtract b to cancel the carry,
+C and we use instead the value
+C
+C   r_0 + B2mb (mod B)
+C
+C This addition can be issued early since it doesn't depend on r2, and it is
+C the source of the cmov in the loop.
+C
+C We have the invariant that r_2 B^2 + r_1 B + r_0 < B^2 + B b
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_mod_1_1p)
+	FUNC_ENTRY(4)
+	push	%rbp
+	push	%rbx
+	mov	%rdx, b
+	mov	%rcx, pre
+
+	mov	-8(ap, n, 8), %rax
+	cmp	$3, n
+	jnc	L(first)
+	mov	-16(ap, n, 8), r0
+	jmp	L(reduce_two)
+
+L(first):
+	C First iteration, no r2
+	mov	24(pre), B2modb
+	mul	B2modb
+	mov	-24(ap, n, 8), r0
+	add	%rax, r0
+	mov	-16(ap, n, 8), %rax
+	adc	%rdx, %rax
+	sbb	r2, r2
+	sub	$4, n
+	jc	L(reduce_three)
+
+	mov	B2modb, B2mb
+	sub	b, B2mb
+
+	ALIGN(16)
+L(top):	and	B2modb, r2
+	lea	(B2mb, r0), t0
+	mul	B2modb
+	add	r0, r2
+	mov	(ap, n, 8), r0
+	cmovc	t0, r2
+	add	%rax, r0
+	mov	r2, %rax
+	adc	%rdx, %rax
+	sbb	r2, r2
+	sub	$1, n
+	jnc	L(top)
+
+L(reduce_three):
+	C Eliminate r2
+	and	b, r2
+	sub	r2, %rax
+
+L(reduce_two):
+	mov	8(pre), R32(%rcx)
+	test	R32(%rcx), R32(%rcx)
+	jz	L(normalized)
+
+	C Unnormalized, use B1modb to reduce to size < B (b+1)
+	mulq	16(pre)
+	xor	t0, t0
+	add	%rax, r0
+	adc	%rdx, t0
+	mov	t0, %rax
+
+	C Left-shift to normalize
+ifdef(`SHLD_SLOW',`
+	shl	R8(%rcx), %rax
+	mov	r0, t0
+	neg	R32(%rcx)
+	shr	R8(%rcx), t0
+	or	t0, %rax
+	neg	R32(%rcx)
+',`
+	shld	R8(%rcx), r0, %rax
+')
+	shl	R8(%rcx), r0
+	jmp	L(udiv)
+
+L(normalized):
+	mov	%rax, t0
+	sub	b, t0
+	cmovnc	t0, %rax
+
+L(udiv):
+	lea	1(%rax), t0
+	mulq	(pre)
+	add	r0, %rax
+	adc	t0, %rdx
+	imul	b, %rdx
+	sub	%rdx, r0
+	cmp	r0, %rax
+	lea	(b, r0), %rax
+	cmovnc	r0, %rax
+	cmp	b, %rax
+	jnc	L(fix)
+L(ok):	shr	R8(%rcx), %rax
+
+	pop	%rbx
+	pop	%rbp
+	FUNC_EXIT()
+	ret
+L(fix):	sub	b, %rax
+	jmp	L(ok)
+EPILOGUE()
+
+	ALIGN(16)
+PROLOGUE(mpn_mod_1_1p_cps)
+	FUNC_ENTRY(2)
+	push	%rbp
+	bsr	%rsi, %rcx
+	push	%rbx
+	mov	%rdi, %rbx
+	push	%r12
+	xor	$63, R32(%rcx)
+	mov	%rsi, %r12
+	mov	R32(%rcx), R32(%rbp)
+	sal	R8(%rcx), %r12
+IFSTD(`	mov	%r12, %rdi	')	C pass parameter
+IFDOS(`	mov	%r12, %rcx	')	C pass parameter
+IFDOS(`	sub	$32, %rsp	')
+	ASSERT(nz, `test $15, %rsp')
+	CALL(	mpn_invert_limb)
+IFDOS(`	add	$32, %rsp	')
+	neg	%r12
+	mov	%r12, %r8
+	mov	%rax, (%rbx)		C store bi
+	mov	%rbp, 8(%rbx)		C store cnt
+	imul	%rax, %r12
+	mov	%r12, 24(%rbx)		C store B2modb
+	mov	R32(%rbp), R32(%rcx)
+	test	R32(%rcx), R32(%rcx)
+	jz	L(z)
+
+	mov	$1, R32(%rdx)
+ifdef(`SHLD_SLOW',`
+	C Destroys %rax, unlike shld. Otherwise, we could do B1modb
+	C before B2modb, and get rid of the move %r12, %r8 above.
+
+	shl	R8(%rcx), %rdx
+	neg	R32(%rcx)
+	shr	R8(%rcx), %rax
+	or	%rax, %rdx
+	neg	R32(%rcx)
+',`
+	shld	R8(%rcx), %rax, %rdx
+')
+	imul	%rdx, %r8
+	shr	R8(%rcx), %r8
+	mov	%r8, 16(%rbx)		C store B1modb
+L(z):
+	pop	%r12
+	pop	%rbx
+	pop	%rbp
+	FUNC_EXIT()
+	ret
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86_64/mod_1_2.asm b/third_party/gmp/mpn/x86_64/mod_1_2.asm
new file mode 100644
index 0000000..40fcaeb
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/mod_1_2.asm
@@ -0,0 +1,241 @@
+dnl  AMD64 mpn_mod_1s_2p
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2009-2012, 2014 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 4
+C AMD K10	 4
+C Intel P4	19
+C Intel core2	 8
+C Intel NHM	 6.5
+C Intel SBR	 4.5
+C Intel atom	28
+C VIA nano	 8
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_mod_1s_2p)
+	FUNC_ENTRY(4)
+	push	%r14
+	test	$1, R8(%rsi)
+	mov	%rdx, %r14
+	push	%r13
+	mov	%rcx, %r13
+	push	%r12
+	push	%rbp
+	push	%rbx
+	mov	16(%rcx), %r10
+	mov	24(%rcx), %rbx
+	mov	32(%rcx), %rbp
+	je	L(b0)
+	dec	%rsi
+	je	L(one)
+	mov	-8(%rdi,%rsi,8), %rax
+	mul	%r10
+	mov	%rax, %r9
+	mov	%rdx, %r8
+	mov	(%rdi,%rsi,8), %rax
+	add	-16(%rdi,%rsi,8), %r9
+	adc	$0, %r8
+	mul	%rbx
+	add	%rax, %r9
+	adc	%rdx, %r8
+	jmp	L(11)
+
+L(b0):	mov	-8(%rdi,%rsi,8), %r8
+	mov	-16(%rdi,%rsi,8), %r9
+
+L(11):	sub	$4, %rsi
+	jb	L(ed2)
+	lea	40(%rdi,%rsi,8), %rdi
+	mov	-40(%rdi), %r11
+	mov	-32(%rdi), %rax
+	jmp	L(m0)
+
+	ALIGN(16)
+L(top):	mov	-24(%rdi), %r9
+	add	%rax, %r11
+	mov	-16(%rdi), %rax
+	adc	%rdx, %r12
+	mul	%r10
+	add	%rax, %r9
+	mov	%r11, %rax
+	mov	%rdx, %r8
+	adc	$0, %r8
+	mul	%rbx
+	add	%rax, %r9
+	mov	%r12, %rax
+	adc	%rdx, %r8
+	mul	%rbp
+	sub	$2, %rsi
+	jb	L(ed1)
+	mov	-40(%rdi), %r11
+	add	%rax, %r9
+	mov	-32(%rdi), %rax
+	adc	%rdx, %r8
+L(m0):	mul	%r10
+	add	%rax, %r11
+	mov	%r9, %rax
+	mov	%rdx, %r12
+	adc	$0, %r12
+	mul	%rbx
+	add	%rax, %r11
+	lea	-32(%rdi), %rdi		C ap -= 4
+	mov	%r8, %rax
+	adc	%rdx, %r12
+	mul	%rbp
+	sub	$2, %rsi
+	jae	L(top)
+
+L(ed0):	mov	%r11, %r9
+	mov	%r12, %r8
+L(ed1):	add	%rax, %r9
+	adc	%rdx, %r8
+L(ed2):	mov	8(%r13), R32(%rdi)		C cnt
+	mov	%r8, %rax
+	mov	%r9, %r8
+	mul	%r10
+	add	%rax, %r8
+	adc	$0, %rdx
+L(1):	xor	R32(%rcx), R32(%rcx)
+	mov	%r8, %r9
+	sub	R32(%rdi), R32(%rcx)
+	shr	R8(%rcx), %r9
+	mov	R32(%rdi), R32(%rcx)
+	sal	R8(%rcx), %rdx
+	or	%rdx, %r9
+	sal	R8(%rcx), %r8
+	mov	%r9, %rax
+	mulq	(%r13)
+	mov	%rax, %rsi
+	inc	%r9
+	add	%r8, %rsi
+	adc	%r9, %rdx
+	imul	%r14, %rdx
+	sub	%rdx, %r8
+	lea	(%r8,%r14), %rax
+	cmp	%r8, %rsi
+	cmovc	%rax, %r8
+	mov	%r8, %rax
+	sub	%r14, %rax
+	cmovc	%r8, %rax
+	mov	R32(%rdi), R32(%rcx)
+	shr	R8(%rcx), %rax
+	pop	%rbx
+	pop	%rbp
+	pop	%r12
+	pop	%r13
+	pop	%r14
+	FUNC_EXIT()
+	ret
+L(one):
+	mov	(%rdi), %r8
+	mov	8(%rcx), R32(%rdi)
+	xor	%rdx, %rdx
+	jmp	L(1)
+EPILOGUE()
+
+	ALIGN(16)
+PROLOGUE(mpn_mod_1s_2p_cps)
+	FUNC_ENTRY(2)
+	push	%rbp
+	bsr	%rsi, %rcx
+	push	%rbx
+	mov	%rdi, %rbx
+	push	%r12
+	xor	$63, R32(%rcx)
+	mov	%rsi, %r12
+	mov	R32(%rcx), R32(%rbp)	C preserve cnt over call
+	sal	R8(%rcx), %r12		C b << cnt
+IFSTD(`	mov	%r12, %rdi	')	C pass parameter
+IFDOS(`	mov	%r12, %rcx	')	C pass parameter
+IFDOS(`	sub	$32, %rsp	')
+	ASSERT(nz, `test $15, %rsp')
+	CALL(	mpn_invert_limb)
+IFDOS(`	add	$32, %rsp	')
+	mov	%r12, %r8
+	mov	%rax, %r11
+	mov	%rax, (%rbx)		C store bi
+	mov	%rbp, 8(%rbx)		C store cnt
+	neg	%r8
+	mov	R32(%rbp), R32(%rcx)
+	mov	$1, R32(%rsi)
+ifdef(`SHLD_SLOW',`
+	shl	R8(%rcx), %rsi
+	neg	R32(%rcx)
+	mov	%rax, %rbp
+	shr	R8(%rcx), %rax
+	or	%rax, %rsi
+	mov	%rbp, %rax
+	neg	R32(%rcx)
+',`
+	shld	R8(%rcx), %rax, %rsi	C FIXME: Slow on Atom and Nano
+')
+	imul	%r8, %rsi
+	mul	%rsi
+
+	add	%rsi, %rdx
+	shr	R8(%rcx), %rsi
+	mov	%rsi, 16(%rbx)		C store B1modb
+
+	not	%rdx
+	imul	%r12, %rdx
+	lea	(%rdx,%r12), %rsi
+	cmp	%rdx, %rax
+	cmovnc	%rdx, %rsi
+	mov	%r11, %rax
+	mul	%rsi
+
+	add	%rsi, %rdx
+	shr	R8(%rcx), %rsi
+	mov	%rsi, 24(%rbx)		C store B2modb
+
+	not	%rdx
+	imul	%r12, %rdx
+	add	%rdx, %r12
+	cmp	%rdx, %rax
+	cmovnc	%rdx, %r12
+
+	shr	R8(%rcx), %r12
+	mov	%r12, 32(%rbx)		C store B3modb
+
+	pop	%r12
+	pop	%rbx
+	pop	%rbp
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/mod_1_4.asm b/third_party/gmp/mpn/x86_64/mod_1_4.asm
new file mode 100644
index 0000000..6cf304c
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/mod_1_4.asm
@@ -0,0 +1,272 @@
+dnl  AMD64 mpn_mod_1s_4p
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2009-2012, 2014 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 3
+C AMD K10	 3
+C Intel P4	15.5
+C Intel core2	 5
+C Intel corei	 4
+C Intel atom	23
+C VIA nano	 4.75
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_mod_1s_4p)
+	FUNC_ENTRY(4)
+	push	%r15
+	push	%r14
+	push	%r13
+	push	%r12
+	push	%rbp
+	push	%rbx
+
+	mov	%rdx, %r15
+	mov	%rcx, %r14
+	mov	16(%rcx), %r11		C B1modb
+	mov	24(%rcx), %rbx		C B2modb
+	mov	32(%rcx), %rbp		C B3modb
+	mov	40(%rcx), %r13		C B4modb
+	mov	48(%rcx), %r12		C B5modb
+	xor	R32(%r8), R32(%r8)
+	mov	R32(%rsi), R32(%rdx)
+	and	$3, R32(%rdx)
+	je	L(b0)
+	cmp	$2, R32(%rdx)
+	jc	L(b1)
+	je	L(b2)
+
+L(b3):	lea	-24(%rdi,%rsi,8), %rdi
+	mov	8(%rdi), %rax
+	mul	%r11
+	mov	(%rdi), %r9
+	add	%rax, %r9
+	adc	%rdx, %r8
+	mov	16(%rdi), %rax
+	mul	%rbx
+	jmp	L(m0)
+
+	ALIGN(8)
+L(b0):	lea	-32(%rdi,%rsi,8), %rdi
+	mov	8(%rdi), %rax
+	mul	%r11
+	mov	(%rdi), %r9
+	add	%rax, %r9
+	adc	%rdx, %r8
+	mov	16(%rdi), %rax
+	mul	%rbx
+	add	%rax, %r9
+	adc	%rdx, %r8
+	mov	24(%rdi), %rax
+	mul	%rbp
+	jmp	L(m0)
+
+	ALIGN(8)
+L(b1):	lea	-8(%rdi,%rsi,8), %rdi
+	mov	(%rdi), %r9
+	jmp	L(m1)
+
+	ALIGN(8)
+L(b2):	lea	-16(%rdi,%rsi,8), %rdi
+	mov	8(%rdi), %r8
+	mov	(%rdi), %r9
+	jmp	L(m1)
+
+	ALIGN(16)
+L(top):	mov	-24(%rdi), %rax
+	mov	-32(%rdi), %r10
+	mul	%r11			C up[1] * B1modb
+	add	%rax, %r10
+	mov	-16(%rdi), %rax
+	mov	$0, R32(%rcx)
+	adc	%rdx, %rcx
+	mul	%rbx			C up[2] * B2modb
+	add	%rax, %r10
+	mov	-8(%rdi), %rax
+	adc	%rdx, %rcx
+	sub	$32, %rdi
+	mul	%rbp			C up[3] * B3modb
+	add	%rax, %r10
+	mov	%r13, %rax
+	adc	%rdx, %rcx
+	mul	%r9			C rl * B4modb
+	add	%rax, %r10
+	mov	%r12, %rax
+	adc	%rdx, %rcx
+	mul	%r8			C rh * B5modb
+	mov	%r10, %r9
+	mov	%rcx, %r8
+L(m0):	add	%rax, %r9
+	adc	%rdx, %r8
+L(m1):	sub	$4, %rsi
+	ja	L(top)
+
+L(end):	mov	8(%r14), R32(%rsi)
+	mov	%r8, %rax
+	mul	%r11
+	mov	%rax, %r8
+	add	%r9, %r8
+	adc	$0, %rdx
+	xor	R32(%rcx), R32(%rcx)
+	sub	R32(%rsi), R32(%rcx)
+	mov	%r8, %rdi
+	shr	R8(%rcx), %rdi
+	mov	R32(%rsi), R32(%rcx)
+	sal	R8(%rcx), %rdx
+	or	%rdx, %rdi
+	mov	%rdi, %rax
+	mulq	(%r14)
+	mov	%r15, %rbx
+	mov	%rax, %r9
+	sal	R8(%rcx), %r8
+	inc	%rdi
+	add	%r8, %r9
+	adc	%rdi, %rdx
+	imul	%rbx, %rdx
+	sub	%rdx, %r8
+	lea	(%r8,%rbx), %rax
+	cmp	%r8, %r9
+	cmovc	%rax, %r8
+	mov	%r8, %rax
+	sub	%rbx, %rax
+	cmovc	%r8, %rax
+	shr	R8(%rcx), %rax
+	pop	%rbx
+	pop	%rbp
+	pop	%r12
+	pop	%r13
+	pop	%r14
+	pop	%r15
+	FUNC_EXIT()
+	ret
+EPILOGUE()
+
+	ALIGN(16)
+PROLOGUE(mpn_mod_1s_4p_cps)
+	FUNC_ENTRY(2)
+	push	%rbp
+	bsr	%rsi, %rcx
+	push	%rbx
+	mov	%rdi, %rbx
+	push	%r12
+	xor	$63, R32(%rcx)
+	mov	%rsi, %r12
+	mov	R32(%rcx), R32(%rbp)	C preserve cnt over call
+	sal	R8(%rcx), %r12		C b << cnt
+IFSTD(`	mov	%r12, %rdi	')	C pass parameter
+IFDOS(`	mov	%r12, %rcx	')	C pass parameter
+IFDOS(`	sub	$32, %rsp	')
+	ASSERT(nz, `test $15, %rsp')
+	CALL(	mpn_invert_limb)
+IFDOS(`	add	$32, %rsp	')
+	mov	%r12, %r8
+	mov	%rax, %r11
+	mov	%rax, (%rbx)		C store bi
+	mov	%rbp, 8(%rbx)		C store cnt
+	neg	%r8
+	mov	R32(%rbp), R32(%rcx)
+	mov	$1, R32(%rsi)
+ifdef(`SHLD_SLOW',`
+	shl	R8(%rcx), %rsi
+	neg	R32(%rcx)
+	mov	%rax, %rbp
+	shr	R8(%rcx), %rax
+	or	%rax, %rsi
+	mov	%rbp, %rax
+	neg	R32(%rcx)
+',`
+	shld	R8(%rcx), %rax, %rsi	C FIXME: Slow on Atom and Nano
+')
+	imul	%r8, %rsi
+	mul	%rsi
+
+	add	%rsi, %rdx
+	shr	R8(%rcx), %rsi
+	mov	%rsi, 16(%rbx)		C store B1modb
+
+	not	%rdx
+	imul	%r12, %rdx
+	lea	(%rdx,%r12), %rsi
+	cmp	%rdx, %rax
+	cmovnc	%rdx, %rsi
+	mov	%r11, %rax
+	mul	%rsi
+
+	add	%rsi, %rdx
+	shr	R8(%rcx), %rsi
+	mov	%rsi, 24(%rbx)		C store B2modb
+
+	not	%rdx
+	imul	%r12, %rdx
+	lea	(%rdx,%r12), %rsi
+	cmp	%rdx, %rax
+	cmovnc	%rdx, %rsi
+	mov	%r11, %rax
+	mul	%rsi
+
+	add	%rsi, %rdx
+	shr	R8(%rcx), %rsi
+	mov	%rsi, 32(%rbx)		C store B3modb
+
+	not	%rdx
+	imul	%r12, %rdx
+	lea	(%rdx,%r12), %rsi
+	cmp	%rdx, %rax
+	cmovnc	%rdx, %rsi
+	mov	%r11, %rax
+	mul	%rsi
+
+	add	%rsi, %rdx
+	shr	R8(%rcx), %rsi
+	mov	%rsi, 40(%rbx)		C store B4modb
+
+	not	%rdx
+	imul	%r12, %rdx
+	add	%rdx, %r12
+	cmp	%rdx, %rax
+	cmovnc	%rdx, %r12
+
+	shr	R8(%rcx), %r12
+	mov	%r12, 48(%rbx)		C store B5modb
+
+	pop	%r12
+	pop	%rbx
+	pop	%rbp
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/mod_34lsub1.asm b/third_party/gmp/mpn/x86_64/mod_34lsub1.asm
new file mode 100644
index 0000000..75421a6
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/mod_34lsub1.asm
@@ -0,0 +1,215 @@
+dnl  AMD64 mpn_mod_34lsub1 -- remainder modulo 2^48-1.
+
+dnl  Copyright 2000-2002, 2004, 2005, 2007, 2009-2012 Free Software Foundation,
+dnl  Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C	    cycles/limb
+C AMD K8,K9	 0.67	   0.583 is possible with zero-reg instead of $0, 4-way
+C AMD K10	 0.67	   this seems hard to beat
+C AMD bd1	 1
+C AMD bd2	 1
+C AMD bd3	 ?
+C AMD bd4	 ?
+C AMD zen	 0.62
+C AMD bobcat	 1.07
+C AMD jaguar	 1
+C Intel P4	 7.35	   terrible, use old code
+C Intel core2	 1.25	   1+epsilon with huge unrolling
+C Intel NHM	 1.15	   this seems hard to beat
+C Intel SBR	 0.93
+C Intel IBR	 0.93
+C Intel HWL	 0.82
+C Intel BWL	 0.64
+C Intel SKY	 0.60
+C Intel atom	 2.5
+C Intel SLM      1.59
+C VIA nano	 1.25	   this seems hard to beat
+
+C INPUT PARAMETERS
+define(`ap',	%rdi)
+define(`n',	%rsi)
+
+C mp_limb_t mpn_mod_34lsub1 (mp_srcptr up, mp_size_t n)
+
+C TODO
+C  * Review feed-in and wind-down code.
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_mod_34lsub1)
+	FUNC_ENTRY(2)
+
+	mov	$0x0000FFFFFFFFFFFF, %r11
+
+	mov	(ap), %rax
+
+	cmp	$2, %rsi
+	ja	L(gt2)
+
+	jb	L(one)
+
+	mov	8(ap), %rsi
+	mov	%rax, %rdx
+	shr	$48, %rax		C src[0] low
+
+	and	%r11, %rdx		C src[0] high
+	add	%rdx, %rax
+	mov	R32(%rsi), R32(%rdx)
+
+	shr	$32, %rsi		C src[1] high
+	add	%rsi, %rax
+
+	shl	$16, %rdx		C src[1] low
+	add	%rdx, %rax
+L(one):	FUNC_EXIT()
+	ret
+
+
+C Don't change this, the wind-down code is not able to handle greater values
+define(UNROLL,3)
+
+L(gt2):	mov	8(ap), %rcx
+	mov	16(ap), %rdx
+	xor	%r9, %r9
+	add	$24, ap
+	sub	$eval(UNROLL*3+3), %rsi
+	jc	L(end)
+	ALIGN(16)
+L(top):
+	add	(ap), %rax
+	adc	8(ap), %rcx
+	adc	16(ap), %rdx
+	adc	$0, %r9
+forloop(i,1,UNROLL-1,`dnl
+	add	eval(i*24)(ap), %rax
+	adc	eval(i*24+8)(ap), %rcx
+	adc	eval(i*24+16)(ap), %rdx
+	adc	$0, %r9
+')dnl
+	add	$eval(UNROLL*24), ap
+	sub	$eval(UNROLL*3), %rsi
+	jnc	L(top)
+
+L(end):
+	lea	L(tab)(%rip), %r8
+ifdef(`PIC',
+`	movslq	36(%r8,%rsi,4), %r10
+	add	%r10, %r8
+	jmp	*%r8
+',`
+	jmp	*72(%r8,%rsi,8)
+')
+	JUMPTABSECT
+	ALIGN(8)
+L(tab):	JMPENT(	L(0), L(tab))
+	JMPENT(	L(1), L(tab))
+	JMPENT(	L(2), L(tab))
+	JMPENT(	L(3), L(tab))
+	JMPENT(	L(4), L(tab))
+	JMPENT(	L(5), L(tab))
+	JMPENT(	L(6), L(tab))
+	JMPENT(	L(7), L(tab))
+	JMPENT(	L(8), L(tab))
+	TEXT
+
+L(6):	add	(ap), %rax
+	adc	8(ap), %rcx
+	adc	16(ap), %rdx
+	adc	$0, %r9
+	add	$24, ap
+L(3):	add	(ap), %rax
+	adc	8(ap), %rcx
+	adc	16(ap), %rdx
+	jmp	L(cj1)
+
+L(7):	add	(ap), %rax
+	adc	8(ap), %rcx
+	adc	16(ap), %rdx
+	adc	$0, %r9
+	add	$24, ap
+L(4):	add	(ap), %rax
+	adc	8(ap), %rcx
+	adc	16(ap), %rdx
+	adc	$0, %r9
+	add	$24, ap
+L(1):	add	(ap), %rax
+	adc	$0, %rcx
+	jmp	L(cj2)
+
+L(8):	add	(ap), %rax
+	adc	8(ap), %rcx
+	adc	16(ap), %rdx
+	adc	$0, %r9
+	add	$24, ap
+L(5):	add	(ap), %rax
+	adc	8(ap), %rcx
+	adc	16(ap), %rdx
+	adc	$0, %r9
+	add	$24, ap
+L(2):	add	(ap), %rax
+	adc	8(ap), %rcx
+
+L(cj2):	adc	$0, %rdx
+L(cj1):	adc	$0, %r9
+L(0):	add	%r9, %rax
+	adc	$0, %rcx
+	adc	$0, %rdx
+	adc	$0, %rax
+
+	mov	%rax, %rdi		C 0mod3
+	shr	$48, %rax		C 0mod3 high
+
+	and	%r11, %rdi		C 0mod3 low
+	mov	R32(%rcx), R32(%r10)	C 1mod3
+
+	shr	$32, %rcx		C 1mod3 high
+
+	add	%rdi, %rax		C apply 0mod3 low
+	movzwl	%dx, R32(%rdi)		C 2mod3
+	shl	$16, %r10		C 1mod3 low
+
+	add	%rcx, %rax		C apply 1mod3 high
+	shr	$16, %rdx		C 2mod3 high
+
+	add	%r10, %rax		C apply 1mod3 low
+	shl	$32, %rdi		C 2mod3 low
+
+	add	%rdx, %rax		C apply 2mod3 high
+	add	%rdi, %rax		C apply 2mod3 low
+
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/mode1o.asm b/third_party/gmp/mpn/x86_64/mode1o.asm
new file mode 100644
index 0000000..2cd2b08
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/mode1o.asm
@@ -0,0 +1,171 @@
+dnl  AMD64 mpn_modexact_1_odd -- Hensel norm remainder.
+
+dnl  Copyright 2000-2006, 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C	     cycles/limb
+C AMD K8,K9	10
+C AMD K10	10
+C Intel P4	33
+C Intel core2	13
+C Intel corei	14.5
+C Intel atom	35
+C VIA nano	 ?
+
+
+C The dependent chain in the main loop is
+C
+C                            cycles
+C	sub	%rdx, %rax	1
+C	imul	%r9, %rax	4
+C	mul	%r8		5
+C			      ----
+C       total		       10
+C
+C The mov load from src seems to need to be scheduled back before the jz to
+C achieve this speed, out-of-order execution apparently can't completely hide
+C the latency otherwise.
+C
+C The l=src[i]-cbit step is rotated back too, since that allows us to avoid it
+C for the first iteration (where there's no cbit).
+C
+C The code alignment used (32-byte) for the loop also seems necessary.  Without
+C that the non-PIC case has adc crossing the 0x60 offset, apparently making it
+C run at 11 cycles instead of 10.
+
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_modexact_1_odd)
+	FUNC_ENTRY(3)
+	mov	$0, R32(%rcx)
+IFDOS(`	jmp	L(ent)		')
+
+PROLOGUE(mpn_modexact_1c_odd)
+	FUNC_ENTRY(4)
+L(ent):
+	C rdi	src
+	C rsi	size
+	C rdx	divisor
+	C rcx	carry
+
+	mov	%rdx, %r8		C d
+	shr	R32(%rdx)		C d/2
+
+	LEA(	binvert_limb_table, %r9)
+
+	and	$127, R32(%rdx)
+	mov	%rcx, %r10		C initial carry
+
+	movzbl	(%r9,%rdx), R32(%rdx)	C inv 8 bits
+
+	mov	(%rdi), %rax		C src[0]
+	lea	(%rdi,%rsi,8), %r11	C src end
+	mov	%r8, %rdi		C d, made available to imull
+
+	lea	(%rdx,%rdx), R32(%rcx)	C 2*inv
+	imul	R32(%rdx), R32(%rdx)	C inv*inv
+
+	neg	%rsi			C -size
+
+	imul	R32(%rdi), R32(%rdx)	C inv*inv*d
+
+	sub	R32(%rdx), R32(%rcx)	C inv = 2*inv - inv*inv*d, 16 bits
+
+	lea	(%rcx,%rcx), R32(%rdx)	C 2*inv
+	imul	R32(%rcx), R32(%rcx)	C inv*inv
+
+	imul	R32(%rdi), R32(%rcx)	C inv*inv*d
+
+	sub	R32(%rcx), R32(%rdx)	C inv = 2*inv - inv*inv*d, 32 bits
+	xor	R32(%rcx), R32(%rcx)	C initial cbit
+
+	lea	(%rdx,%rdx), %r9	C 2*inv
+	imul	%rdx, %rdx		C inv*inv
+
+	imul	%r8, %rdx		C inv*inv*d
+
+	sub	%rdx, %r9		C inv = 2*inv - inv*inv*d, 64 bits
+	mov	%r10, %rdx		C initial climb
+
+	ASSERT(e,`	C d*inv == 1 mod 2^64
+	mov	%r8, %r10
+	imul	%r9, %r10
+	cmp	$1, %r10')
+
+	inc	%rsi
+	jz	L(one)
+
+
+	ALIGN(16)
+L(top):
+	C rax	l = src[i]-cbit
+	C rcx	new cbit, 0 or 1
+	C rdx	climb, high of last product
+	C rsi	counter, limbs, negative
+	C rdi
+	C r8	divisor
+	C r9	inverse
+	C r11	src end ptr
+
+	sub	%rdx, %rax		C l = src[i]-cbit - climb
+
+	adc	$0, %rcx		C more cbit
+	imul	%r9, %rax		C q = l * inverse
+
+	mul	%r8			C climb = high (q * d)
+
+	mov	(%r11,%rsi,8), %rax	C src[i+1]
+	sub	%rcx, %rax		C next l = src[i+1] - cbit
+	setc	R8(%rcx)		C new cbit
+
+	inc	%rsi
+	jnz	L(top)
+
+
+L(one):
+	sub	%rdx, %rax		C l = src[i]-cbit - climb
+
+	adc	$0, %rcx		C more cbit
+	imul	%r9, %rax		C q = l * inverse
+
+	mul	%r8			C climb = high (q * d)
+
+	lea	(%rcx,%rdx), %rax	C climb+cbit
+	FUNC_EXIT()
+	ret
+
+EPILOGUE(mpn_modexact_1c_odd)
+EPILOGUE(mpn_modexact_1_odd)
diff --git a/third_party/gmp/mpn/x86_64/mul_1.asm b/third_party/gmp/mpn/x86_64/mul_1.asm
new file mode 100644
index 0000000..e1ba89b
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/mul_1.asm
@@ -0,0 +1,192 @@
+dnl  AMD64 mpn_mul_1.
+
+dnl  Copyright 2003-2005, 2007, 2008, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9      2.54
+C AMD K10        2.54
+C AMD bull       4.98
+C AMD pile       4.80
+C AMD steam
+C AMD excavator
+C AMD bobcat     5.37
+C AMD jaguar     6.16
+C Intel P4      12.6
+C Intel core2    4.05
+C Intel NHM      4.0
+C Intel SBR      2.91
+C Intel IBR      2.73
+C Intel HWL      2.44
+C Intel BWL      2.39
+C Intel SKL      2.44
+C Intel atom    19.8
+C Intel SLM      9.0
+C VIA nano       4.25
+
+C The loop of this code is the result of running a code generation and
+C optimization tool suite written by David Harvey and Torbjorn Granlund.
+
+C TODO
+C  * The loop is great, but the prologue and epilogue code was quickly written.
+C    Tune it!
+
+define(`rp',      `%rdi')   C rcx
+define(`up',      `%rsi')   C rdx
+define(`n_param', `%rdx')   C r8
+define(`vl',      `%rcx')   C r9
+
+define(`n',       `%r11')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+IFDOS(`	define(`up', ``%rsi'')	') dnl
+IFDOS(`	define(`rp', ``%rcx'')	') dnl
+IFDOS(`	define(`vl', ``%r9'')	') dnl
+IFDOS(`	define(`r9', ``rdi'')	') dnl
+IFDOS(`	define(`n',  ``%r8'')	') dnl
+IFDOS(`	define(`r8', ``r11'')	') dnl
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_mul_1c)
+IFDOS(``push	%rsi		'')
+IFDOS(``push	%rdi		'')
+IFDOS(``mov	%rdx, %rsi	'')
+	push	%rbx
+IFSTD(`	mov	%r8, %r10')
+IFDOS(`	mov	64(%rsp), %r10')	C 40 + 3*8  (3 push insns)
+	jmp	L(common)
+EPILOGUE()
+
+PROLOGUE(mpn_mul_1)
+IFDOS(``push	%rsi		'')
+IFDOS(``push	%rdi		'')
+IFDOS(``mov	%rdx, %rsi	'')
+
+	push	%rbx
+	xor	%r10, %r10
+L(common):
+	mov	(up), %rax		C read first u limb early
+IFSTD(`	mov	n_param, %rbx   ')	C move away n from rdx, mul uses it
+IFDOS(`	mov	n, %rbx         ')
+	mul	vl
+IFSTD(`	mov	%rbx, n         ')
+
+	add	%r10, %rax
+	adc	$0, %rdx
+
+	and	$3, R32(%rbx)
+	jz	L(b0)
+	cmp	$2, R32(%rbx)
+	jz	L(b2)
+	jg	L(b3)
+
+L(b1):	dec	n
+	jne	L(gt1)
+	mov	%rax, (rp)
+	jmp	L(ret)
+L(gt1):	lea	8(up,n,8), up
+	lea	-8(rp,n,8), rp
+	neg	n
+	xor	%r10, %r10
+	xor	R32(%rbx), R32(%rbx)
+	mov	%rax, %r9
+	mov	(up,n,8), %rax
+	mov	%rdx, %r8
+	jmp	L(L1)
+
+L(b0):	lea	(up,n,8), up
+	lea	-16(rp,n,8), rp
+	neg	n
+	xor	%r10, %r10
+	mov	%rax, %r8
+	mov	%rdx, %rbx
+	jmp	 L(L0)
+
+L(b3):	lea	-8(up,n,8), up
+	lea	-24(rp,n,8), rp
+	neg	n
+	mov	%rax, %rbx
+	mov	%rdx, %r10
+	jmp	L(L3)
+
+L(b2):	lea	-16(up,n,8), up
+	lea	-32(rp,n,8), rp
+	neg	n
+	xor	%r8, %r8
+	xor	R32(%rbx), R32(%rbx)
+	mov	%rax, %r10
+	mov	24(up,n,8), %rax
+	mov	%rdx, %r9
+	jmp	L(L2)
+
+	ALIGN(16)
+L(top):	mov	%r10, (rp,n,8)
+	add	%rax, %r9
+	mov	(up,n,8), %rax
+	adc	%rdx, %r8
+	mov	$0, R32(%r10)
+L(L1):	mul	vl
+	mov	%r9, 8(rp,n,8)
+	add	%rax, %r8
+	adc	%rdx, %rbx
+L(L0):	mov	8(up,n,8), %rax
+	mul	vl
+	mov	%r8, 16(rp,n,8)
+	add	%rax, %rbx
+	adc	%rdx, %r10
+L(L3):	mov	16(up,n,8), %rax
+	mul	vl
+	mov	%rbx, 24(rp,n,8)
+	mov	$0, R32(%r8)		C zero
+	mov	%r8, %rbx		C zero
+	add	%rax, %r10
+	mov	24(up,n,8), %rax
+	mov	%r8, %r9		C zero
+	adc	%rdx, %r9
+L(L2):	mul	vl
+	add	$4, n
+	js	 L(top)
+
+	mov	%r10, (rp,n,8)
+	add	%rax, %r9
+	adc	%r8, %rdx
+	mov	%r9, 8(rp,n,8)
+	add	%r8, %rdx
+L(ret):	mov	%rdx, %rax
+
+	pop	%rbx
+IFDOS(``pop	%rdi		'')
+IFDOS(``pop	%rsi		'')
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/mul_2.asm b/third_party/gmp/mpn/x86_64/mul_2.asm
new file mode 100644
index 0000000..d64313b
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/mul_2.asm
@@ -0,0 +1,204 @@
+dnl  AMD64 mpn_mul_2 -- Multiply an n-limb vector with a 2-limb vector and
+dnl  store the result in a third limb vector.
+
+dnl  Copyright 2008, 2011, 2012, 2016 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9      4.53
+C AMD K10        4.53
+C AMD bull       9.76   10.37
+C AMD pile       9.22
+C AMD steam
+C AMD excavator
+C AMD bobcat    11.3
+C AMD jaguar    11.9
+C Intel P4      25.0
+C Intel core2    8.05
+C Intel NHM      7.72
+C Intel SBR      6.33
+C Intel IBR      6.15
+C Intel HWL      6.00
+C Intel BWL      4.44
+C Intel SKL      4.54
+C Intel atom    39.0
+C Intel SLM     24.0
+C VIA nano
+
+C This code is the result of running a code generation and optimization tool
+C suite written by David Harvey and Torbjorn Granlund.
+
+C TODO
+C  * Work on feed-in and wind-down code.
+C  * Convert "mov $0" to "xor".
+C  * Adjust initial lea to save some bytes.
+C  * Perhaps adjust n from n_param&3 value?
+C  * Replace with 2.25 c/l sequence.
+
+C INPUT PARAMETERS
+define(`rp',	 `%rdi')
+define(`up',	 `%rsi')
+define(`n_param',`%rdx')
+define(`vp',	 `%rcx')
+
+define(`v0', `%r8')
+define(`v1', `%r9')
+define(`w0', `%rbx')
+define(`w1', `%rcx')
+define(`w2', `%rbp')
+define(`w3', `%r10')
+define(`n',  `%r11')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_mul_2)
+	FUNC_ENTRY(4)
+	push	%rbx
+	push	%rbp
+
+	mov	(vp), v0
+	mov	8(vp), v1
+
+	mov	(up), %rax
+
+	mov	n_param, n
+	neg	n
+	lea	-8(up,n_param,8), up
+	lea	-8(rp,n_param,8), rp
+
+	and	$3, R32(n_param)
+	jz	L(m2p0)
+	cmp	$2, R32(n_param)
+	jc	L(m2p1)
+	jz	L(m2p2)
+L(m2p3):
+	mul	v0
+	xor	R32(w3), R32(w3)
+	mov	%rax, w1
+	mov	%rdx, w2
+	mov	8(up,n,8), %rax
+	add	$-1, n
+	mul	v1
+	add	%rax, w2
+	jmp	L(m23)
+L(m2p0):
+	mul	v0
+	xor	R32(w2), R32(w2)
+	mov	%rax, w0
+	mov	%rdx, w1
+	jmp	L(m20)
+L(m2p1):
+	mul	v0
+	xor	R32(w3), R32(w3)
+	xor	R32(w0), R32(w0)
+	xor	R32(w1), R32(w1)
+	add	$1, n
+	jmp	L(m2top)
+L(m2p2):
+	mul	v0
+	xor	R32(w0), R32(w0)
+	xor	R32(w1), R32(w1)
+	mov	%rax, w2
+	mov	%rdx, w3
+	mov	8(up,n,8), %rax
+	add	$-2, n
+	jmp	L(m22)
+
+
+	ALIGN(32)
+L(m2top):
+	add	%rax, w3
+	adc	%rdx, w0
+	mov	0(up,n,8), %rax
+	adc	$0, R32(w1)
+	mov	$0, R32(w2)
+	mul	v1
+	add	%rax, w0
+	mov	w3, 0(rp,n,8)
+	adc	%rdx, w1
+	mov	8(up,n,8), %rax
+	mul	v0
+	add	%rax, w0
+	adc	%rdx, w1
+	adc	$0, R32(w2)
+L(m20):	mov	8(up,n,8), %rax
+	mul	v1
+	add	%rax, w1
+	adc	%rdx, w2
+	mov	16(up,n,8), %rax
+	mov	$0, R32(w3)
+	mul	v0
+	add	%rax, w1
+	mov	16(up,n,8), %rax
+	adc	%rdx, w2
+	adc	$0, R32(w3)
+	mul	v1
+	add	%rax, w2
+	mov	w0, 8(rp,n,8)
+L(m23):	adc	%rdx, w3
+	mov	24(up,n,8), %rax
+	mul	v0
+	mov	$0, R32(w0)
+	add	%rax, w2
+	adc	%rdx, w3
+	mov	w1, 16(rp,n,8)
+	mov	24(up,n,8), %rax
+	mov	$0, R32(w1)
+	adc	$0, R32(w0)
+L(m22):	mul	v1
+	add	%rax, w3
+	mov	w2, 24(rp,n,8)
+	adc	%rdx, w0
+	mov	32(up,n,8), %rax
+	mul	v0
+	add	$4, n
+	js	L(m2top)
+
+
+	add	%rax, w3
+	adc	%rdx, w0
+	adc	$0, R32(w1)
+	mov	(up), %rax
+	mul	v1
+	mov	w3, (rp)
+	add	%rax, w0
+	adc	%rdx, w1
+	mov	w0, 8(rp)
+	mov	w1, %rax
+
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/mulx/adx/addmul_1.asm b/third_party/gmp/mpn/x86_64/mulx/adx/addmul_1.asm
new file mode 100644
index 0000000..9ceb611
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/mulx/adx/addmul_1.asm
@@ -0,0 +1,157 @@
+dnl  AMD64 mpn_addmul_1 for CPUs with mulx and adx.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2012, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 -
+C AMD K10	 -
+C AMD bd1	 -
+C AMD bd2	 -
+C AMD bd3	 -
+C AMD bd4	 -
+C AMD zen	 ?
+C AMD bt1	 -
+C AMD bt2	 -
+C Intel P4	 -
+C Intel PNR	 -
+C Intel NHM	 -
+C Intel SBR	 -
+C Intel IBR	 -
+C Intel HWL	 -
+C Intel BWL	 ?
+C Intel SKL	 ?
+C Intel atom	 -
+C Intel SLM	 -
+C VIA nano	 -
+
+define(`rp',      `%rdi')	dnl rcx
+define(`up',      `%rsi')	dnl rdx
+define(`n_param', `%rdx')	dnl r8
+define(`v0_param',`%rcx')	dnl r9
+
+define(`n',       `%rcx')	dnl
+define(`v0',      `%rdx')	dnl
+
+C Testing mechanism for running this on older AMD64 processors
+ifelse(FAKE_MULXADX,1,`
+  include(CONFIG_TOP_SRCDIR`/mpn/x86_64/missing-call.m4')
+',`
+  define(`adox',	``adox'	$1, $2')
+  define(`adcx',	``adcx'	$1, $2')
+  define(`mulx',	``mulx'	$1, $2, $3')
+')
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_addmul_1)
+	mov	(up), %r8
+
+	push	%rbx
+	push	%r12
+	push	%r13
+
+	lea	(up,n_param,8), up
+	lea	-16(rp,n_param,8), rp
+	mov	R32(n_param), R32(%rax)
+	xchg	v0_param, v0		C FIXME: is this insn fast?
+
+	neg	n
+
+	and	$3, R8(%rax)
+	jz	L(b0)
+	cmp	$2, R8(%rax)
+	jl	L(b1)
+	jz	L(b2)
+
+L(b3):	mulx(	(up,n,8), %r11, %r10)
+	mulx(	8(up,n,8), %r13, %r12)
+	mulx(	16(up,n,8), %rbx, %rax)
+	dec	n
+	jmp	L(lo3)
+
+L(b0):	mulx(	(up,n,8), %r9, %r8)
+	mulx(	8(up,n,8), %r11, %r10)
+	mulx(	16(up,n,8), %r13, %r12)
+	jmp	L(lo0)
+
+L(b2):	mulx(	(up,n,8), %r13, %r12)
+	mulx(	8(up,n,8), %rbx, %rax)
+	lea	2(n), n
+	jrcxz	L(wd2)
+L(gt2):	mulx(	(up,n,8), %r9, %r8)
+	jmp	L(lo2)
+
+L(b1):	and	R8(%rax), R8(%rax)
+	mulx(	(up,n,8), %rbx, %rax)
+	lea	1(n), n
+	jrcxz	L(wd1)
+	mulx(	(up,n,8), %r9, %r8)
+	mulx(	8(up,n,8), %r11, %r10)
+	jmp	L(lo1)
+
+L(end):	adcx(	%r10, %r13)
+	mov	%r11, -8(rp)
+L(wd2):	adox(	(rp), %r13)
+	adcx(	%r12, %rbx)
+	mov	%r13, (rp)
+L(wd1):	adox(	8(rp), %rbx)
+	adcx(	%rcx, %rax)
+	adox(	%rcx, %rax)
+	mov	%rbx, 8(rp)
+	pop	%r13
+	pop	%r12
+	pop	%rbx
+	ret
+
+L(top):	jrcxz	L(end)
+	mulx(	(up,n,8), %r9, %r8)
+	adcx(	%r10, %r13)
+	mov	%r11, -8(rp,n,8)
+L(lo2):	adox(	(rp,n,8), %r13)
+	mulx(	8(up,n,8), %r11, %r10)
+	adcx(	%r12, %rbx)
+	mov	%r13, (rp,n,8)
+L(lo1):	adox(	8(rp,n,8), %rbx)
+	mulx(	16(up,n,8), %r13, %r12)
+	adcx(	%rax, %r9)
+	mov	%rbx, 8(rp,n,8)
+L(lo0):	adox(	16(rp,n,8), %r9)
+	mulx(	24(up,n,8), %rbx, %rax)
+	adcx(	%r8, %r11)
+	mov	%r9, 16(rp,n,8)
+L(lo3):	adox(	24(rp,n,8), %r11)
+	lea	4(n), n
+	jmp	L(top)
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86_64/nano/copyd.asm b/third_party/gmp/mpn/x86_64/nano/copyd.asm
new file mode 100644
index 0000000..f0dc54a
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/nano/copyd.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_copyd optimised for Intel Sandy Bridge.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_copyd)
+include_mpn(`x86_64/fastsse/copyd-palignr.asm')
diff --git a/third_party/gmp/mpn/x86_64/nano/copyi.asm b/third_party/gmp/mpn/x86_64/nano/copyi.asm
new file mode 100644
index 0000000..9c26e00
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/nano/copyi.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_copyi optimised for Intel Sandy Bridge.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_copyi)
+include_mpn(`x86_64/fastsse/copyi-palignr.asm')
diff --git a/third_party/gmp/mpn/x86_64/nano/dive_1.asm b/third_party/gmp/mpn/x86_64/nano/dive_1.asm
new file mode 100644
index 0000000..e9a0763
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/nano/dive_1.asm
@@ -0,0 +1,166 @@
+dnl  AMD64 mpn_divexact_1 -- mpn by limb exact division.
+
+dnl  Copyright 2001, 2002, 2004-2006, 2010-2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C	     cycles/limb
+C	       norm	       unorm
+C AMD K8,K9	11		11
+C AMD K10	11		11
+C Intel P4	 ?
+C Intel core2	13.5		13.25
+C Intel corei	14.25
+C Intel atom	34		36
+C VIA nano	19.25		19.25
+
+
+C INPUT PARAMETERS
+C rp		rdi
+C up		rsi
+C n		rdx
+C divisor	rcx
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_divexact_1)
+	FUNC_ENTRY(4)
+	push	%rbx
+
+	mov	%rcx, %rax
+	xor	R32(%rcx), R32(%rcx)	C shift count
+	mov	%rdx, %r8
+
+	bt	$0, R32(%rax)
+	jc	L(odd)			C skip bsfq unless divisor is even
+	bsf	%rax, %rcx
+	shr	R8(%rcx), %rax
+L(odd):	mov	%rax, %rbx
+	shr	R32(%rax)
+	and	$127, R32(%rax)		C d/2, 7 bits
+
+	LEA(	binvert_limb_table, %rdx)
+
+	movzbl	(%rdx,%rax), R32(%rax)	C inv 8 bits
+
+	mov	%rbx, %r11		C d without twos
+
+	lea	(%rax,%rax), R32(%rdx)	C 2*inv
+	imul	R32(%rax), R32(%rax)	C inv*inv
+	imul	R32(%rbx), R32(%rax)	C inv*inv*d
+	sub	R32(%rax), R32(%rdx)	C inv = 2*inv - inv*inv*d, 16 bits
+
+	lea	(%rdx,%rdx), R32(%rax)	C 2*inv
+	imul	R32(%rdx), R32(%rdx)	C inv*inv
+	imul	R32(%rbx), R32(%rdx)	C inv*inv*d
+	sub	R32(%rdx), R32(%rax)	C inv = 2*inv - inv*inv*d, 32 bits
+
+	lea	(%rax,%rax), %r10	C 2*inv
+	imul	%rax, %rax		C inv*inv
+	imul	%rbx, %rax		C inv*inv*d
+	sub	%rax, %r10		C inv = 2*inv - inv*inv*d, 64 bits
+
+	lea	(%rsi,%r8,8), %rsi	C up end
+	lea	-8(%rdi,%r8,8), %rdi	C rp end
+	neg	%r8			C -n
+
+	mov	(%rsi,%r8,8), %rax	C up[0]
+
+	inc	%r8
+	jz	L(one)
+
+	test	R32(%rcx), R32(%rcx)
+	jnz	L(unorm)		C branch if count != 0
+	xor	R32(%rbx), R32(%rbx)
+	jmp	L(nent)
+
+	ALIGN(8)
+L(ntop):mul	%r11			C carry limb in rdx	0 10
+	mov	-8(%rsi,%r8,8), %rax	C
+	sub	%rbx, %rax		C apply carry bit
+	setc	%bl			C
+	sub	%rdx, %rax		C apply carry limb	5
+	adc	$0, %rbx		C			6
+L(nent):imul	%r10, %rax		C			6
+	mov	%rax, (%rdi,%r8,8)	C
+	inc	%r8			C
+	jnz	L(ntop)
+
+	mov	-8(%rsi), %r9		C up high limb
+	jmp	L(com)
+
+L(unorm):
+	mov	(%rsi,%r8,8), %r9	C up[1]
+	shr	R8(%rcx), %rax		C
+	neg	R32(%rcx)
+	shl	R8(%rcx), %r9		C
+	neg	R32(%rcx)
+	or	%r9, %rax
+	xor	R32(%rbx), R32(%rbx)
+	jmp	L(uent)
+
+	ALIGN(8)
+L(utop):mul	%r11			C carry limb in rdx	0 10
+	mov	(%rsi,%r8,8), %rax	C
+	shl	R8(%rcx), %rax		C
+	neg	R32(%rcx)
+	or	%r9, %rax
+	sub	%rbx, %rax		C apply carry bit
+	setc	%bl			C
+	sub	%rdx, %rax		C apply carry limb	5
+	adc	$0, %rbx		C			6
+L(uent):imul	%r10, %rax		C			6
+	mov	(%rsi,%r8,8), %r9	C
+	shr	R8(%rcx), %r9		C
+	neg	R32(%rcx)
+	mov	%rax, (%rdi,%r8,8)	C
+	inc	%r8			C
+	jnz	L(utop)
+
+L(com):	mul	%r11			C carry limb in rdx
+	sub	%rbx, %r9		C apply carry bit
+	sub	%rdx, %r9		C apply carry limb
+	imul	%r10, %r9
+	mov	%r9, (%rdi)
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+
+L(one):	shr	R8(%rcx), %rax
+	imul	%r10, %rax
+	mov	%rax, (%rdi)
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/nano/gcd_11.asm b/third_party/gmp/mpn/x86_64/nano/gcd_11.asm
new file mode 100644
index 0000000..4723093
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/nano/gcd_11.asm
@@ -0,0 +1,37 @@
+dnl  AMD64 mpn_gcd_11.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_gcd_11)
+include_mpn(`x86_64/core2/gcd_11.asm')
diff --git a/third_party/gmp/mpn/x86_64/nano/gmp-mparam.h b/third_party/gmp/mpn/x86_64/nano/gmp-mparam.h
new file mode 100644
index 0000000..fde69db
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/nano/gmp-mparam.h
@@ -0,0 +1,243 @@
+/* VIA Nano gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 1991, 1993, 1994, 2000-2010, 2012, 2014 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+#define SHLD_SLOW 1
+#define SHRD_SLOW 1
+
+/* 1600 MHz Nano 2xxx */
+/* FFT tuning limit = 25000000 */
+/* Generated by tuneup.c, 2014-03-12, gcc 4.2 */
+
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          4
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          2
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        18
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        20
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD      8
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1_NORM_THRESHOLD              1
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           22
+
+#define MUL_TOOM22_THRESHOLD                27
+#define MUL_TOOM33_THRESHOLD                38
+#define MUL_TOOM44_THRESHOLD               324
+#define MUL_TOOM6H_THRESHOLD               450
+#define MUL_TOOM8H_THRESHOLD               632
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      73
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     207
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     211
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     219
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     315
+
+#define SQR_BASECASE_THRESHOLD              10
+#define SQR_TOOM2_THRESHOLD                 52
+#define SQR_TOOM3_THRESHOLD                 73
+#define SQR_TOOM4_THRESHOLD                387
+#define SQR_TOOM6_THRESHOLD                662
+#define SQR_TOOM8_THRESHOLD                781
+
+#define MULMID_TOOM42_THRESHOLD             32
+
+#define MULMOD_BNM1_THRESHOLD               14
+#define SQRMOD_BNM1_THRESHOLD               15
+
+#define MUL_FFT_MODF_THRESHOLD             376  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    376, 5}, {     19, 6}, {     10, 5}, {     21, 6}, \
+    {     23, 7}, {     12, 6}, {     25, 7}, {     21, 8}, \
+    {     11, 7}, {     24, 8}, {     13, 7}, {     27, 8}, \
+    {     15, 7}, {     31, 8}, {     19, 7}, {     39, 8}, \
+    {     21, 9}, {     11, 8}, {     27, 9}, {     15, 8}, \
+    {     35, 9}, {     19, 8}, {     41, 9}, {     23, 8}, \
+    {     49, 9}, {     27,10}, {     15, 9}, {     43,10}, \
+    {     23, 9}, {     55,11}, {     15,10}, {     31, 9}, \
+    {     67,10}, {     39, 9}, {     83,10}, {     47, 9}, \
+    {     95,10}, {     79,11}, {     47,10}, {    103,12}, \
+    {     31,11}, {     63,10}, {    143,11}, {     79,10}, \
+    {    159, 9}, {    319,10}, {    175,11}, {     95, 9}, \
+    {    383, 8}, {    767,10}, {    207,11}, {    111,12}, \
+    {     63,11}, {    127,10}, {    255,11}, {    143, 9}, \
+    {    575, 8}, {   1151,10}, {    303,11}, {    159,10}, \
+    {    319, 9}, {    639, 8}, {   1279,10}, {    335,12}, \
+    {     95,11}, {    191,10}, {    383, 9}, {    767,11}, \
+    {    207,10}, {    415, 9}, {    831, 8}, {   1663,10}, \
+    {    447,13}, {     63,12}, {    127,11}, {    255,10}, \
+    {    511, 9}, {   1023,11}, {    271,10}, {    543, 9}, \
+    {   1087,10}, {    575, 9}, {   1215,12}, {    159,11}, \
+    {    319,10}, {    639, 9}, {   1279,11}, {    335,10}, \
+    {    671, 9}, {   1343,11}, {    351,10}, {    703, 9}, \
+    {   1407,12}, {    191,11}, {    383,10}, {    767, 9}, \
+    {   1535,10}, {    831, 9}, {   1663,12}, {    223,11}, \
+    {    447,10}, {    895,13}, {    127,12}, {    255,11}, \
+    {    511,10}, {   1023,11}, {    543,10}, {   1087,12}, \
+    {    287,11}, {    575,10}, {   1151,11}, {    607,10}, \
+    {   1215,12}, {    319,11}, {    639,10}, {   1279,11}, \
+    {    671,10}, {   1343,12}, {    351,11}, {    703,10}, \
+    {   1407,13}, {    191,12}, {    383,11}, {    767,10}, \
+    {   1535,12}, {    415,11}, {    831,10}, {   1663,12}, \
+    {    447,11}, {    895,10}, {   1791,14}, {    127,13}, \
+    {    255,12}, {    511,11}, {   1023,12}, {    543,11}, \
+    {   1087,12}, {    575,11}, {   1151,12}, {    607,11}, \
+    {   1215,13}, {    319,12}, {    639,11}, {   1279,12}, \
+    {    671,11}, {   1343,12}, {    703,11}, {   1407,13}, \
+    {    383,12}, {    767,11}, {   1535,12}, {    831,11}, \
+    {   1663,13}, {    447,12}, {    895,11}, {   1791,13}, \
+    {    511,12}, {   1023,11}, {   2047,12}, {   1087,13}, \
+    {    575,12}, {   1151,11}, {   2303,12}, {   1215,13}, \
+    {    639,12}, {   1279,11}, {   2559,12}, {   1343,13}, \
+    {    703,12}, {   1407,14}, {    383,13}, {    767,12}, \
+    {   1535,13}, {    831,12}, {   1663,13}, {    895,12}, \
+    {   1791,13}, {    959,14}, {    511,13}, {   1023,12}, \
+    {   2047,13}, {   1087,12}, {   2175,13}, {   1151,12}, \
+    {   2303,13}, {   1215,14}, {    639,13}, {   1279,12}, \
+    {   2559,13}, {   1407,12}, {   2815,13}, {   1471,14}, \
+    {    767,13}, {   1535,12}, {   3071,13}, {   1663,14}, \
+    {    895,13}, {   1791,12}, {   3583,13}, {   1919,15}, \
+    {    511,14}, {   1023,13}, {   2047,12}, {   4095,13}, \
+    {   2175,14}, {   1151,13}, {   2303,12}, {   4607,13}, \
+    {   2431,14}, {   1279,13}, {   2559,12}, {   5119,14}, \
+    {   1407,13}, {   2815,12}, {   5631,15}, {  32768,16}, \
+    {  65536,17}, { 131072,18}, { 262144,19}, { 524288,20}, \
+    {1048576,21}, {2097152,22}, {4194304,23}, {8388608,24} }
+#define MUL_FFT_TABLE3_SIZE 224
+#define MUL_FFT_THRESHOLD                 3520
+
+#define SQR_FFT_MODF_THRESHOLD             340  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    340, 5}, {     19, 6}, {     10, 5}, {     21, 6}, \
+    {     21, 7}, {     11, 6}, {     23, 7}, {     21, 8}, \
+    {     11, 7}, {     24, 8}, {     13, 7}, {     27, 8}, \
+    {     15, 7}, {     31, 8}, {     21, 9}, {     11, 8}, \
+    {     27, 9}, {     15, 8}, {     33, 9}, {     19, 8}, \
+    {     41, 9}, {     23, 8}, {     47, 9}, {     27,10}, \
+    {     15, 9}, {     39,10}, {     23, 9}, {     51,11}, \
+    {     15,10}, {     31, 9}, {     67,10}, {     39, 9}, \
+    {     79,10}, {     47, 9}, {     95,10}, {     55,11}, \
+    {     31,10}, {     63, 9}, {    127,10}, {     71, 9}, \
+    {    143,10}, {     79,11}, {     47,10}, {     95, 9}, \
+    {    191,10}, {    103,12}, {     31,11}, {     63,10}, \
+    {    127, 9}, {    255,10}, {    135, 7}, {   1087, 9}, \
+    {    287,11}, {     79, 9}, {    319, 8}, {    639,10}, \
+    {    167,11}, {     95,10}, {    191, 9}, {    383, 8}, \
+    {    767,11}, {    111,12}, {     63,11}, {    127,10}, \
+    {    255, 9}, {    511, 8}, {   1023,10}, {    271, 9}, \
+    {    543, 8}, {   1087,11}, {    143, 9}, {    575, 8}, \
+    {   1151,10}, {    303, 9}, {    639, 8}, {   1279,10}, \
+    {    335, 9}, {    671,10}, {    351, 9}, {    703,12}, \
+    {     95,11}, {    191,10}, {    383, 9}, {    767,11}, \
+    {    207,10}, {    415, 9}, {    831,13}, {     63,12}, \
+    {    127,11}, {    255,10}, {    511, 9}, {   1023,11}, \
+    {    271,10}, {    543, 9}, {   1087,10}, {    575, 9}, \
+    {   1151,11}, {    303,10}, {    607, 9}, {   1215,12}, \
+    {    159,11}, {    319,10}, {    639, 9}, {   1279,10}, \
+    {    671, 9}, {   1343,11}, {    351,10}, {    703, 9}, \
+    {   1407,12}, {    191,11}, {    383,10}, {    767, 9}, \
+    {   1535,11}, {    415,10}, {    831, 9}, {   1663,12}, \
+    {    223,11}, {    447,10}, {    959,13}, {    127,12}, \
+    {    255,11}, {    511,10}, {   1023,11}, {    543,10}, \
+    {   1087,11}, {    575,10}, {   1215,12}, {    319,11}, \
+    {    639,10}, {   1279,11}, {    671,10}, {   1343,12}, \
+    {    351,11}, {    703,10}, {   1407,13}, {    191,12}, \
+    {    383,11}, {    767,10}, {   1535,12}, {    415,11}, \
+    {    831,10}, {   1663,12}, {    447,11}, {    895,10}, \
+    {   1791,12}, {    479,11}, {    959,14}, {    127,12}, \
+    {    511,11}, {   1023,12}, {    543,11}, {   1087,12}, \
+    {    575,11}, {   1151,12}, {    607,11}, {   1215,13}, \
+    {    319,12}, {    639,11}, {   1279,12}, {    671,11}, \
+    {   1343,12}, {    703,11}, {   1407,13}, {    383,12}, \
+    {    767,11}, {   1535,12}, {    831,11}, {   1663,13}, \
+    {    447,12}, {    895,11}, {   1791,12}, {    959,13}, \
+    {    511,12}, {   1023,11}, {   2047,12}, {   1087,13}, \
+    {    575,12}, {   1215,13}, {    639,12}, {   1343,13}, \
+    {    703,12}, {   1407,11}, {   2815,13}, {    767,12}, \
+    {   1535,13}, {    831,12}, {   1663,13}, {    895,12}, \
+    {   1791,13}, {    959,14}, {    511,13}, {   1023,12}, \
+    {   2047,13}, {   1087,12}, {   2175,13}, {   1215,14}, \
+    {    639,13}, {   1279,12}, {   2559,13}, {   1407,12}, \
+    {   2815,14}, {    767,13}, {   1535,12}, {   3071,13}, \
+    {   1663,14}, {    895,13}, {   1791,12}, {   3583,13}, \
+    {   1919,15}, {    511,14}, {   1023,13}, {   2047,12}, \
+    {   4095,13}, {   2175,14}, {   1151,13}, {   2303,12}, \
+    {   4607,14}, {   1279,13}, {   2559,14}, {   1407,13}, \
+    {   2815,15}, {  32768,16}, {  65536,17}, { 131072,18}, \
+    { 262144,19}, { 524288,20}, {1048576,21}, {2097152,22}, \
+    {4194304,23}, {8388608,24} }
+#define SQR_FFT_TABLE3_SIZE 230
+#define SQR_FFT_THRESHOLD                 2496
+
+#define MULLO_BASECASE_THRESHOLD            13
+#define MULLO_DC_THRESHOLD                  38
+#define MULLO_MUL_N_THRESHOLD             6633
+
+#define DC_DIV_QR_THRESHOLD                 56
+#define DC_DIVAPPR_Q_THRESHOLD             173
+#define DC_BDIV_QR_THRESHOLD                55
+#define DC_BDIV_Q_THRESHOLD                 96
+
+#define INV_MULMOD_BNM1_THRESHOLD           54
+#define INV_NEWTON_THRESHOLD               202
+#define INV_APPR_THRESHOLD                 166
+
+#define BINV_NEWTON_THRESHOLD              246
+#define REDC_1_TO_REDC_2_THRESHOLD           7
+#define REDC_2_TO_REDC_N_THRESHOLD          85
+
+#define MU_DIV_QR_THRESHOLD               1499
+#define MU_DIVAPPR_Q_THRESHOLD            1652
+#define MUPI_DIV_QR_THRESHOLD               83
+#define MU_BDIV_QR_THRESHOLD              1210
+#define MU_BDIV_Q_THRESHOLD               1499
+
+#define POWM_SEC_TABLE  1,28,129,642,2387
+
+#define MATRIX22_STRASSEN_THRESHOLD         15
+#define HGCD_THRESHOLD                     127
+#define HGCD_APPR_THRESHOLD                214
+#define HGCD_REDUCE_THRESHOLD             2479
+#define GCD_DC_THRESHOLD                   487
+#define GCDEXT_DC_THRESHOLD                505
+#define JACOBI_BASE_METHOD                   4
+
+#define GET_STR_DC_THRESHOLD                12
+#define GET_STR_PRECOMPUTE_THRESHOLD        24
+#define SET_STR_DC_THRESHOLD               802
+#define SET_STR_PRECOMPUTE_THRESHOLD      2042
+
+#define FAC_DSC_THRESHOLD                 1737
+#define FAC_ODD_THRESHOLD                   44
diff --git a/third_party/gmp/mpn/x86_64/nano/popcount.asm b/third_party/gmp/mpn/x86_64/nano/popcount.asm
new file mode 100644
index 0000000..fb14dd3
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/nano/popcount.asm
@@ -0,0 +1,35 @@
+dnl  x86-64 mpn_popcount.
+
+dnl  Copyright 2007, 2011 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+MULFUNC_PROLOGUE(mpn_popcount)
+include_mpn(`x86/pentium4/sse2/popcount.asm')
diff --git a/third_party/gmp/mpn/x86_64/pentium4/addmul_2.asm b/third_party/gmp/mpn/x86_64/pentium4/addmul_2.asm
new file mode 100644
index 0000000..7ae6a1a
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/pentium4/addmul_2.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_addmul_2 optimised for Intel Nocona.
+
+dnl  Copyright 2018 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_addmul_2)
+include_mpn(`x86_64/bd1/addmul_2.asm')
diff --git a/third_party/gmp/mpn/x86_64/pentium4/aors_n.asm b/third_party/gmp/mpn/x86_64/pentium4/aors_n.asm
new file mode 100644
index 0000000..8e6ee1b
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/pentium4/aors_n.asm
@@ -0,0 +1,196 @@
+dnl  x86-64 mpn_add_n/mpn_sub_n optimized for Pentium 4.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2007, 2008, 2010-2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C	     cycles/limb
+C AMD K8,K9	 2.8
+C AMD K10	 2.8
+C Intel P4	 4
+C Intel core2	 3.6-5	(fluctuating)
+C Intel corei	 ?
+C Intel atom	 ?
+C VIA nano	 ?
+
+
+C INPUT PARAMETERS
+define(`rp',	`%rdi')
+define(`up',	`%rsi')
+define(`vp',	`%rdx')
+define(`n',	`%rcx')
+define(`cy',	`%r8')
+
+ifdef(`OPERATION_add_n', `
+	define(ADDSUB,	      add)
+	define(func,	      mpn_add_n)
+	define(func_nc,	      mpn_add_nc)')
+ifdef(`OPERATION_sub_n', `
+	define(ADDSUB,	      sub)
+	define(func,	      mpn_sub_n)
+	define(func_nc,	      mpn_sub_nc)')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_add_n mpn_add_nc mpn_sub_n mpn_sub_nc)
+ASM_START()
+	TEXT
+PROLOGUE(func)
+	FUNC_ENTRY(4)
+	xor	%r8, %r8
+IFDOS(`	jmp	L(ent)		')
+EPILOGUE()
+PROLOGUE(func_nc)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8	')
+L(ent):	push	%rbx
+	push	%r12
+
+	mov	(vp), %r9
+
+	mov	R32(n), R32(%rax)
+	and	$3, R32(%rax)
+	jne	L(n00)		C n = 0, 4, 8, ...
+	mov	R32(%r8), R32(%rbx)
+	mov	(up), %r8
+	mov	8(up), %r10
+	ADDSUB	%r9, %r8
+	mov	8(vp), %r9
+	setc	R8(%rax)
+	lea	-16(rp), rp
+	jmp	L(L00)
+
+L(n00):	cmp	$2, R32(%rax)
+	jnc	L(n01)		C n = 1, 5, 9, ...
+	mov	(up), %r11
+	mov	R32(%r8), R32(%rax)
+	xor	R32(%rbx), R32(%rbx)
+	dec	n
+	jnz	L(gt1)
+	ADDSUB	%r9, %r11
+	setc	R8(%rbx)
+	ADDSUB	%rax, %r11
+	adc	$0, R32(%rbx)
+	mov	%r11, (rp)
+	jmp	L(ret)
+L(gt1):	mov	8(up), %r8
+	ADDSUB	%r9, %r11
+	mov	8(vp), %r9
+	setc	R8(%rbx)
+	lea	-8(rp), rp
+	lea	8(up), up
+	lea	8(vp), vp
+	jmp	L(L01)
+
+L(n01):	jne	L(n10)		C n = 2, 6, 10, ...
+	mov	(up), %r12
+	mov	R32(%r8), R32(%rbx)
+	mov	8(up), %r11
+	ADDSUB	%r9, %r12
+	mov	8(vp), %r9
+	setc	R8(%rax)
+	lea	-32(rp), rp
+	lea	16(up), up
+	lea	16(vp), vp
+	jmp	L(L10)
+
+L(n10):	mov	(up), %r10	C n = 3, 7, 11, ...
+	mov	R32(%r8), R32(%rax)
+	xor	R32(%rbx), R32(%rbx)
+	mov	8(up), %r12
+	ADDSUB	%r9, %r10
+	mov	8(vp), %r9
+	setc	R8(%rbx)
+	lea	-24(rp), rp
+	lea	-8(up), up
+	lea	-8(vp), vp
+	jmp	L(L11)
+
+L(c0):	mov	$1, R8(%rbx)
+	jmp	L(rc0)
+L(c1):	mov	$1, R8(%rax)
+	jmp	L(rc1)
+L(c2):	mov	$1, R8(%rbx)
+	jmp	L(rc2)
+L(c3):	mov	$1, R8(%rax)
+	jmp	L(rc3)
+
+	ALIGN(16)
+L(top):	mov	(up), %r8	C not on critical path
+	ADDSUB	%r9, %r11	C not on critical path
+	mov	(vp), %r9	C not on critical path
+	setc	R8(%rbx)	C save carry out
+	mov	%r12, (rp)
+L(L01):	ADDSUB	%rax, %r11	C apply previous carry out
+	jc	L(c0)		C jump if ripple
+L(rc0):	mov	8(up), %r10
+	ADDSUB	%r9, %r8
+	mov	8(vp), %r9
+	setc	R8(%rax)
+	mov	%r11, 8(rp)
+L(L00):	ADDSUB	%rbx, %r8
+	jc	L(c1)
+L(rc1):	mov	16(up), %r12
+	ADDSUB	%r9, %r10
+	mov	16(vp), %r9
+	setc	R8(%rbx)
+	mov	%r8, 16(rp)
+L(L11):	ADDSUB	%rax, %r10
+	jc	L(c2)
+L(rc2):	mov	24(up), %r11
+	ADDSUB	%r9, %r12
+	lea	32(up), up
+	mov	24(vp), %r9
+	lea	32(vp), vp
+	setc	R8(%rax)
+	mov	%r10, 24(rp)
+L(L10):	ADDSUB	%rbx, %r12
+	jc	L(c3)
+L(rc3):	lea	32(rp), rp
+	sub	$4, n
+	ja	L(top)
+
+L(end):	ADDSUB	%r9, %r11
+	setc	R8(%rbx)
+	mov	%r12, (rp)
+	ADDSUB	%rax, %r11
+	jnc	L(1)
+	mov	$1, R8(%rbx)
+L(1):	mov	%r11, 8(rp)
+
+L(ret):	mov	R32(%rbx), R32(%rax)
+	pop	%r12
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/pentium4/aorslsh1_n.asm b/third_party/gmp/mpn/x86_64/pentium4/aorslsh1_n.asm
new file mode 100644
index 0000000..66937d3
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/pentium4/aorslsh1_n.asm
@@ -0,0 +1,50 @@
+dnl  AMD64 mpn_addlsh1_n, mpn_sublsh1_n -- rp[] = up[] +- (vp[] << 1),
+dnl  optimised for Pentium 4.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2008, 2010-2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+define(LSH, 1)
+define(RSH, 31)			C 31, not 63, since we use 32-bit ops
+
+ifdef(`OPERATION_addlsh1_n', `
+  define(ADDSUB,	add)
+  define(func,		mpn_addlsh1_n)')
+ifdef(`OPERATION_sublsh1_n', `
+  define(ADDSUB,	sub)
+  define(func,		mpn_sublsh1_n)')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_addlsh1_n mpn_sublsh1_n)
+include_mpn(`x86_64/pentium4/aorslshC_n.asm')
diff --git a/third_party/gmp/mpn/x86_64/pentium4/aorslsh2_n.asm b/third_party/gmp/mpn/x86_64/pentium4/aorslsh2_n.asm
new file mode 100644
index 0000000..001f0ac
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/pentium4/aorslsh2_n.asm
@@ -0,0 +1,50 @@
+dnl  AMD64 mpn_addlsh2_n, mpn_sublsh2_n -- rp[] = up[] +- (vp[] << 2),
+dnl  optimised for Pentium 4.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2008, 2010-2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+define(LSH, 2)
+define(RSH, 30)			C 30, not 62, since we use 32-bit ops
+
+ifdef(`OPERATION_addlsh2_n', `
+  define(ADDSUB,	add)
+  define(func,		mpn_addlsh2_n)')
+ifdef(`OPERATION_sublsh2_n', `
+  define(ADDSUB,	sub)
+  define(func,		mpn_sublsh2_n)')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_addlsh2_n mpn_sublsh2_n)
+include_mpn(`x86_64/pentium4/aorslshC_n.asm')
diff --git a/third_party/gmp/mpn/x86_64/pentium4/aorslshC_n.asm b/third_party/gmp/mpn/x86_64/pentium4/aorslshC_n.asm
new file mode 100644
index 0000000..d03c6a3
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/pentium4/aorslshC_n.asm
@@ -0,0 +1,203 @@
+dnl  AMD64 mpn_addlshC_n, mpn_sublshC_n -- rp[] = up[] +- (vp[] << C), where
+dnl  C is 1, 2, 3.  Optimized for Pentium 4.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2008, 2010-2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+C	     cycles/limb
+C AMD K8,K9	 3.8
+C AMD K10	 3.8
+C Intel P4	 5.8
+C Intel core2	 4.75
+C Intel corei	 4.75
+C Intel atom	 ?
+C VIA nano	 4.75
+
+
+C INPUT PARAMETERS
+define(`rp',`%rdi')
+define(`up',`%rsi')
+define(`vp',`%rdx')
+define(`n', `%rcx')
+
+define(M, eval(m4_lshift(1,LSH)))
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(func)
+	FUNC_ENTRY(4)
+	push	%rbx
+	push	%r12
+	push	%rbp
+
+	mov	(vp), %r9
+	shl	$LSH, %r9
+	mov	4(vp), R32(%rbp)
+
+	xor	R32(%rbx), R32(%rbx)
+
+	mov	R32(n), R32(%rax)
+	and	$3, R32(%rax)
+	jne	L(n00)		C n = 0, 4, 8, ...
+
+	mov	(up), %r8
+	mov	8(up), %r10
+	shr	$RSH, R32(%rbp)
+	ADDSUB	%r9, %r8
+	mov	8(vp), %r9
+	lea	(%rbp,%r9,M), %r9
+	setc	R8(%rax)
+	mov	12(vp), R32(%rbp)
+	lea	-16(rp), rp
+	jmp	L(L00)
+
+L(n00):	cmp	$2, R32(%rax)
+	jnc	L(n01)		C n = 1, 5, 9, ...
+	mov	(up), %r11
+	lea	-8(rp), rp
+	shr	$RSH, R32(%rbp)
+	ADDSUB	%r9, %r11
+	setc	R8(%rbx)
+	dec	n
+	jz	L(1)		C jump for n = 1
+	mov	8(up), %r8
+	mov	8(vp), %r9
+	lea	(%rbp,%r9,M), %r9
+	mov	12(vp), R32(%rbp)
+	lea	8(up), up
+	lea	8(vp), vp
+	jmp	L(L01)
+
+L(n01):	jne	L(n10)		C n = 2, 6, 10, ...
+	mov	(up), %r12
+	mov	8(up), %r11
+	shr	$RSH, R32(%rbp)
+	ADDSUB	%r9, %r12
+	mov	8(vp), %r9
+	lea	(%rbp,%r9,M), %r9
+	setc	R8(%rax)
+	mov	12(vp), R32(%rbp)
+	lea	16(up), up
+	lea	16(vp), vp
+	jmp	L(L10)
+
+L(n10):	mov	(up), %r10
+	mov	8(up), %r12
+	shr	$RSH, R32(%rbp)
+	ADDSUB	%r9, %r10
+	mov	8(vp), %r9
+	lea	(%rbp,%r9,M), %r9
+	setc	R8(%rbx)
+	mov	12(vp), R32(%rbp)
+	lea	-24(rp), rp
+	lea	-8(up), up
+	lea	-8(vp), vp
+	jmp	L(L11)
+
+L(c0):	mov	$1, R8(%rbx)
+	jmp	L(rc0)
+L(c1):	mov	$1, R8(%rax)
+	jmp	L(rc1)
+L(c2):	mov	$1, R8(%rbx)
+	jmp	L(rc2)
+
+	ALIGN(16)
+L(top):	mov	(up), %r8	C not on critical path
+	shr	$RSH, R32(%rbp)
+	ADDSUB	%r9, %r11	C not on critical path
+	mov	(vp), %r9
+	lea	(%rbp,%r9,M), %r9
+	setc	R8(%rbx)	C save carry out
+	mov	4(vp), R32(%rbp)
+	mov	%r12, (rp)
+	ADDSUB	%rax, %r11	C apply previous carry out
+	jc	L(c0)		C jump if ripple
+L(rc0):
+L(L01):	mov	8(up), %r10
+	shr	$RSH, R32(%rbp)
+	ADDSUB	%r9, %r8
+	mov	8(vp), %r9
+	lea	(%rbp,%r9,M), %r9
+	setc	R8(%rax)
+	mov	12(vp), R32(%rbp)
+	mov	%r11, 8(rp)
+	ADDSUB	%rbx, %r8
+	jc	L(c1)
+L(rc1):
+L(L00):	mov	16(up), %r12
+	shr	$RSH, R32(%rbp)
+	ADDSUB	%r9, %r10
+	mov	16(vp), %r9
+	lea	(%rbp,%r9,M), %r9
+	setc	R8(%rbx)
+	mov	20(vp), R32(%rbp)
+	mov	%r8, 16(rp)
+	ADDSUB	%rax, %r10
+	jc	L(c2)
+L(rc2):
+L(L11):	mov	24(up), %r11
+	shr	$RSH, R32(%rbp)
+	ADDSUB	%r9, %r12
+	mov	24(vp), %r9
+	lea	(%rbp,%r9,M), %r9
+	lea	32(up), up
+	lea	32(vp), vp
+	setc	R8(%rax)
+	mov	-4(vp), R32(%rbp)
+	mov	%r10, 24(rp)
+	ADDSUB	%rbx, %r12
+	jc	L(c3)
+L(rc3):	lea	32(rp), rp
+L(L10):	sub	$4, n
+	ja	L(top)
+
+L(end):
+	shr	$RSH, R32(%rbp)
+	ADDSUB	%r9, %r11
+	setc	R8(%rbx)
+	mov	%r12, (rp)
+	ADDSUB	%rax, %r11
+	jnc	L(1)
+	mov	$1, R8(%rbx)
+L(1):	mov	%r11, 8(rp)
+	lea	(%rbx,%rbp), R32(%rax)
+	pop	%rbp
+	pop	%r12
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+L(c3):	mov	$1, R8(%rax)
+	jmp	L(rc3)
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86_64/pentium4/aorsmul_1.asm b/third_party/gmp/mpn/x86_64/pentium4/aorsmul_1.asm
new file mode 100644
index 0000000..e5dbb34
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/pentium4/aorsmul_1.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_addmul_1 and mpn_submul_1 optimised for Intel Nocona.
+
+dnl  Copyright 2018 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_addmul_1 mpn_submul_1)
+include_mpn(`x86_64/bd1/aorsmul_1.asm')
diff --git a/third_party/gmp/mpn/x86_64/pentium4/gmp-mparam.h b/third_party/gmp/mpn/x86_64/pentium4/gmp-mparam.h
new file mode 100644
index 0000000..9c79310
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/pentium4/gmp-mparam.h
@@ -0,0 +1,257 @@
+/* Pentium 4-64 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+/* These routines exists for all x86_64 chips, but they are slower on Pentium4
+   than separate add/sub and shift.  Make sure they are not really used.  */
+#undef HAVE_NATIVE_mpn_rsblsh1_n
+#undef HAVE_NATIVE_mpn_rsblsh2_n
+#undef HAVE_NATIVE_mpn_addlsh_n
+#undef HAVE_NATIVE_mpn_rsblsh_n
+
+/* 3400 MHz Pentium4 Nocona / 1024 Kibyte L2 cache */
+/* FFT tuning limit = 107,095,964 */
+/* Generated by tuneup.c, 2019-11-09, gcc 8.3 */
+
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          5
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          3
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        14
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        32
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD     11
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1_NORM_THRESHOLD              2
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD              12
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           20
+
+#define DIV_1_VS_MUL_1_PERCENT             228
+
+#define MUL_TOOM22_THRESHOLD                12
+#define MUL_TOOM33_THRESHOLD                81
+#define MUL_TOOM44_THRESHOLD               130
+#define MUL_TOOM6H_THRESHOLD               173
+#define MUL_TOOM8H_THRESHOLD               430
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      81
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD      91
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD      89
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD      88
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     112
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 18
+#define SQR_TOOM3_THRESHOLD                113
+#define SQR_TOOM4_THRESHOLD                202
+#define SQR_TOOM6_THRESHOLD                238
+#define SQR_TOOM8_THRESHOLD                430
+
+#define MULMID_TOOM42_THRESHOLD             20
+
+#define MULMOD_BNM1_THRESHOLD                9
+#define SQRMOD_BNM1_THRESHOLD               11
+
+#define MUL_FFT_MODF_THRESHOLD             236  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    236, 5}, {     11, 6}, {      6, 5}, {     13, 6}, \
+    {      9, 5}, {     19, 6}, {     17, 7}, {      9, 6}, \
+    {     19, 7}, {     10, 6}, {     21, 7}, {     11, 6}, \
+    {     23, 7}, {     13, 8}, {      7, 7}, {     17, 8}, \
+    {      9, 7}, {     21, 8}, {     11, 7}, {     23, 8}, \
+    {     13, 9}, {      7, 8}, {     15, 7}, {     31, 8}, \
+    {     21, 9}, {     11, 8}, {     27,10}, {      7, 9}, \
+    {     15, 8}, {     33, 9}, {     19, 8}, {     39, 9}, \
+    {     23, 8}, {     47, 9}, {     27,10}, {     15, 9}, \
+    {     39,10}, {     23, 9}, {     51,11}, {     15,10}, \
+    {     31, 9}, {     67,10}, {     39, 9}, {     83,10}, \
+    {     47, 9}, {     95,10}, {     55,11}, {     31,10}, \
+    {     63, 9}, {    127, 8}, {    255,10}, {     71, 9}, \
+    {    143, 8}, {    287,10}, {     79,11}, {     47,10}, \
+    {     95, 9}, {    191,12}, {     31,11}, {     63,10}, \
+    {    127, 9}, {    255,10}, {    143, 9}, {    287,11}, \
+    {     79,10}, {    159, 9}, {    319,10}, {    175,11}, \
+    {     95,10}, {    191, 9}, {    383,10}, {    223,12}, \
+    {     63,11}, {    127,10}, {    255,11}, {    143,10}, \
+    {    287,11}, {    159,10}, {    319,11}, {    175,12}, \
+    {     95,11}, {    191,10}, {    383,11}, {    223,13}, \
+    {     63,12}, {    127,11}, {    255,10}, {    511,11}, \
+    {    287,10}, {    575,12}, {    159,11}, {    351,12}, \
+    {    191,11}, {    383,12}, {    223,11}, {    447,13}, \
+    {    127,12}, {    255,11}, {    511,12}, {    287,11}, \
+    {    575,10}, {   1151,12}, {    351,13}, {    191,12}, \
+    {    415,11}, {    831,10}, {   1663,12}, {    447,14}, \
+    {    127,13}, {    255,12}, {    511,11}, {   1023,12}, \
+    {    543,11}, {   1087,10}, {   2175,12}, {    575,11}, \
+    {   1151,13}, {    319,12}, {    639,11}, {   1279,12}, \
+    {    671,11}, {   1343,12}, {    703,13}, {    383,12}, \
+    {    767,11}, {   1535,12}, {    831,11}, {   1663,13}, \
+    {    447,14}, {    255,13}, {    511,12}, {   1023,11}, \
+    {   2047,12}, {   1087,11}, {   2175,13}, {    575,12}, \
+    {   1151,11}, {   2303,12}, {   1215,11}, {   2431,10}, \
+    {   4863,13}, {    639,12}, {   1279,11}, {   2559,12}, \
+    {   1343,13}, {    703,14}, {    383,13}, {    767,12}, \
+    {   1535,13}, {    831,12}, {   1663,15}, {    255,14}, \
+    {    511,13}, {   1023,12}, {   2047,13}, {   1087,12}, \
+    {   2175,13}, {   1151,12}, {   2303,13}, {   1215,12}, \
+    {   2431,11}, {   4863,14}, {    639,13}, {   1279,12}, \
+    {   2559,13}, {   1343,12}, {   2687,13}, {   1407,12}, \
+    {   2815,13}, {   1471,14}, {    767,13}, {   1663,14}, \
+    {    895,13}, {   1791,12}, {   3583,13}, {   1919,12}, \
+    {   3839,15}, {    511,14}, {   1023,13}, {   2175,14}, \
+    {   1151,13}, {   2303,12}, {   4607,13}, {   2431,12}, \
+    {   4863,14}, {   1279,13}, {   2687,14}, {   1407,13}, \
+    {   2815,15}, {    767,14}, {   1791,13}, {   3583,14}, \
+    {   1919,13}, {   3839,16}, {    511,15}, {   1023,14}, \
+    {   2175,13}, {   4351,14}, {   2303,13}, {   4607,14}, \
+    {   2431,13}, {   4863,15}, {   1279,14}, {   2943,13}, \
+    {   5887,15}, {   1535,14}, {   3199,15}, {   1791,14}, \
+    {   3839,13}, {   7679,16}, {   1023,15}, {   2047,14}, \
+    {   4351,15}, {   2303,14}, {   4863,15}, {   2815,14}, \
+    {   5887,16}, {   1535,15}, {   3071,14}, {   6143,15}, \
+    {  32768,16}, {  65536,17}, { 131072,18}, { 262144,19}, \
+    { 524288,20}, {1048576,21}, {2097152,22}, {4194304,23}, \
+    {8388608,24} }
+#define MUL_FFT_TABLE3_SIZE 229
+#define MUL_FFT_THRESHOLD                 2752
+
+#define SQR_FFT_MODF_THRESHOLD             240  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    240, 5}, {     11, 6}, {      6, 5}, {     13, 6}, \
+    {      9, 5}, {     19, 6}, {     17, 7}, {      9, 6}, \
+    {     23, 7}, {     12, 6}, {     25, 7}, {     13, 8}, \
+    {      7, 7}, {     17, 8}, {      9, 7}, {     21, 8}, \
+    {     11, 7}, {     24, 8}, {     13, 9}, {      7, 8}, \
+    {     15, 7}, {     31, 8}, {     21, 9}, {     11, 8}, \
+    {     27,10}, {      7, 9}, {     15, 8}, {     33, 9}, \
+    {     19, 8}, {     39, 9}, {     27,10}, {     15, 9}, \
+    {     39,10}, {     23, 9}, {     47,11}, {     15,10}, \
+    {     31, 9}, {     63,10}, {     39, 9}, {     79,10}, \
+    {     55,11}, {     31,10}, {     63, 9}, {    127, 8}, \
+    {    255,10}, {     71, 9}, {    143, 8}, {    287,10}, \
+    {     79,11}, {     47,10}, {     95, 9}, {    191,12}, \
+    {     31,11}, {     63,10}, {    127, 9}, {    255,10}, \
+    {    143, 9}, {    287,11}, {     79,10}, {    159, 9}, \
+    {    319,10}, {    175, 9}, {    351,11}, {     95,10}, \
+    {    191, 9}, {    383,10}, {    207, 9}, {    415,10}, \
+    {    223,12}, {     63,11}, {    127,10}, {    255,11}, \
+    {    143,10}, {    287,11}, {    159,10}, {    319,11}, \
+    {    175,10}, {    351,12}, {     95,11}, {    191,10}, \
+    {    383,11}, {    207,10}, {    415,11}, {    223,13}, \
+    {     63,12}, {    127,11}, {    255,10}, {    511,11}, \
+    {    287,10}, {    575,12}, {    159,11}, {    319,10}, \
+    {    639,11}, {    351,12}, {    191,11}, {    383,10}, \
+    {    767,12}, {    223,11}, {    447,13}, {    127,12}, \
+    {    255,11}, {    511,12}, {    287,11}, {    575,10}, \
+    {   1151,12}, {    319,11}, {    639,12}, {    351,13}, \
+    {    191,12}, {    383,11}, {    767,12}, {    415,11}, \
+    {    831,12}, {    447,14}, {    127,13}, {    255,12}, \
+    {    511,11}, {   1023,12}, {    543,11}, {   1087,12}, \
+    {    575,11}, {   1151,13}, {    319,12}, {    639,11}, \
+    {   1279,12}, {    671,11}, {   1343,13}, {    383,12}, \
+    {    767,11}, {   1535,12}, {    831,13}, {    447,14}, \
+    {    255,13}, {    511,12}, {   1023,11}, {   2047,12}, \
+    {   1087,13}, {    575,12}, {   1151,11}, {   2303,12}, \
+    {   1215,11}, {   2431,10}, {   4863,13}, {    639,12}, \
+    {   1279,11}, {   2559,12}, {   1343,11}, {   2687,14}, \
+    {    383,13}, {    767,12}, {   1535,13}, {    831,12}, \
+    {   1663,15}, {    255,14}, {    511,13}, {   1023,12}, \
+    {   2047,13}, {   1087,12}, {   2175,13}, {   1151,12}, \
+    {   2303,13}, {   1215,12}, {   2431,11}, {   4863,14}, \
+    {    639,13}, {   1279,12}, {   2559,13}, {   1343,12}, \
+    {   2687,13}, {   1407,12}, {   2815,13}, {   1471,14}, \
+    {    767,13}, {   1663,14}, {    895,13}, {   1791,12}, \
+    {   3583,13}, {   1919,12}, {   3839,15}, {    511,14}, \
+    {   1023,13}, {   2175,14}, {   1151,13}, {   2303,12}, \
+    {   4607,13}, {   2431,12}, {   4863,14}, {   1279,13}, \
+    {   2687,14}, {   1407,13}, {   2943,15}, {    767,14}, \
+    {   1663,13}, {   3327,14}, {   1791,13}, {   3583,14}, \
+    {   1919,13}, {   3839,16}, {    511,15}, {   1023,14}, \
+    {   2175,13}, {   4351,14}, {   2303,13}, {   4607,14}, \
+    {   2431,13}, {   4863,15}, {   1279,14}, {   2815,13}, \
+    {   5631,14}, {   2943,13}, {   5887,15}, {   1535,14}, \
+    {   3327,15}, {   1791,14}, {   3839,13}, {   7679,16}, \
+    {   1023,15}, {   2047,14}, {   4351,15}, {   2303,14}, \
+    {   4863,15}, {   2815,14}, {   5887,16}, {   1535,15}, \
+    {   3071,14}, {   6143,15}, {  32768,16}, {  65536,17}, \
+    { 131072,18}, { 262144,19}, { 524288,20}, {1048576,21}, \
+    {2097152,22}, {4194304,23}, {8388608,24} }
+#define SQR_FFT_TABLE3_SIZE 235
+#define SQR_FFT_THRESHOLD                 2368
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  45
+#define MULLO_MUL_N_THRESHOLD             5397
+#define SQRLO_BASECASE_THRESHOLD             6
+#define SQRLO_DC_THRESHOLD                  46
+#define SQRLO_SQR_THRESHOLD               4658
+
+#define DC_DIV_QR_THRESHOLD                 36
+#define DC_DIVAPPR_Q_THRESHOLD              95
+#define DC_BDIV_QR_THRESHOLD                35
+#define DC_BDIV_Q_THRESHOLD                 47
+
+#define INV_MULMOD_BNM1_THRESHOLD           22
+#define INV_NEWTON_THRESHOLD               178
+#define INV_APPR_THRESHOLD                 116
+
+#define BINV_NEWTON_THRESHOLD              206
+#define REDC_1_TO_REDC_2_THRESHOLD          24
+#define REDC_2_TO_REDC_N_THRESHOLD          50
+
+#define MU_DIV_QR_THRESHOLD                979
+#define MU_DIVAPPR_Q_THRESHOLD             979
+#define MUPI_DIV_QR_THRESHOLD               97
+#define MU_BDIV_QR_THRESHOLD               762
+#define MU_BDIV_Q_THRESHOLD                942
+
+#define POWM_SEC_TABLE  7,34,114,523,1486
+
+#define GET_STR_DC_THRESHOLD                13
+#define GET_STR_PRECOMPUTE_THRESHOLD        25
+#define SET_STR_DC_THRESHOLD               381
+#define SET_STR_PRECOMPUTE_THRESHOLD      1659
+
+#define FAC_DSC_THRESHOLD                  969
+#define FAC_ODD_THRESHOLD                    0  /* always */
+
+#define MATRIX22_STRASSEN_THRESHOLD         29
+#define HGCD2_DIV1_METHOD                    3  /* 2.03% faster than 5 */
+#define HGCD_THRESHOLD                      92
+#define HGCD_APPR_THRESHOLD                 95
+#define HGCD_REDUCE_THRESHOLD             1815
+#define GCD_DC_THRESHOLD                   195
+#define GCDEXT_DC_THRESHOLD                233
+#define JACOBI_BASE_METHOD                   4  /* 17.06% faster than 1 */
+
+/* Tuneup completed successfully, took 297016 seconds */
diff --git a/third_party/gmp/mpn/x86_64/pentium4/lshift.asm b/third_party/gmp/mpn/x86_64/pentium4/lshift.asm
new file mode 100644
index 0000000..4037be4
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/pentium4/lshift.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_lshift optimised for Pentium 4.
+
+dnl  Copyright 2018 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_lshift)
+include_mpn(`x86_64/fastsse/lshift.asm')
diff --git a/third_party/gmp/mpn/x86_64/pentium4/lshiftc.asm b/third_party/gmp/mpn/x86_64/pentium4/lshiftc.asm
new file mode 100644
index 0000000..52856c1
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/pentium4/lshiftc.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_lshiftc optimised for Pentium 4.
+
+dnl  Copyright 2018 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_lshiftc)
+include_mpn(`x86_64/fastsse/lshiftc.asm')
diff --git a/third_party/gmp/mpn/x86_64/pentium4/mod_34lsub1.asm b/third_party/gmp/mpn/x86_64/pentium4/mod_34lsub1.asm
new file mode 100644
index 0000000..f34b3f0
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/pentium4/mod_34lsub1.asm
@@ -0,0 +1,167 @@
+dnl  AMD64 mpn_mod_34lsub1 -- remainder modulo 2^48-1.
+
+dnl  Copyright 2000-2002, 2004, 2005, 2007, 2010-2012 Free Software Foundation,
+dnl  Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C	     cycles/limb
+C AMD K8,K9	 1.0
+C AMD K10	 1.12
+C Intel P4	 3.25
+C Intel core2	 1.5
+C Intel corei	 1.5
+C Intel atom	 2.5
+C VIA nano	 1.75
+
+
+C INPUT PARAMETERS
+define(`ap',	%rdi)
+define(`n',	%rsi)
+
+C mp_limb_t mpn_mod_34lsub1 (mp_srcptr up, mp_size_t n)
+
+C TODO
+C  * Review feed-in and wind-down code.  In particular, try to avoid adc and
+C    sbb to placate Pentium4.
+C  * It seems possible to reach 2.67 c/l by using a cleaner 6-way unrolling,
+C    without the dual loop exits.
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_mod_34lsub1)
+	FUNC_ENTRY(2)
+
+	mov	$0x0000FFFFFFFFFFFF, %r11
+
+	sub	$2, %rsi
+	ja	L(gt2)
+
+	mov	(ap), %rax
+	nop
+	jb	L(1)
+
+	mov	8(ap), %rsi
+	mov	%rax, %rdx
+	shr	$48, %rax		C src[0] low
+
+	and	%r11, %rdx		C src[0] high
+	add	%rdx, %rax
+	mov	R32(%rsi), R32(%rdx)
+
+	shr	$32, %rsi		C src[1] high
+	add	%rsi, %rax
+
+	shl	$16, %rdx		C src[1] low
+	add	%rdx, %rax
+
+L(1):	FUNC_EXIT()
+	ret
+
+
+	ALIGN(16)
+L(gt2):	xor	R32(%rax), R32(%rax)
+	xor	R32(%rcx), R32(%rcx)
+	xor	R32(%rdx), R32(%rdx)
+	xor	%r8, %r8
+	xor	%r9, %r9
+	xor	%r10, %r10
+
+L(top):	add	(ap), %rax
+	adc	$0, %r10
+	add	8(ap), %rcx
+	adc	$0, %r8
+	add	16(ap), %rdx
+	adc	$0, %r9
+
+	sub	$3, %rsi
+	jng	L(end)
+
+	add	24(ap), %rax
+	adc	$0, %r10
+	add	32(ap), %rcx
+	adc	$0, %r8
+	add	40(ap), %rdx
+	lea	48(ap), ap
+	adc	$0, %r9
+
+	sub	$3, %rsi
+	jg	L(top)
+
+
+	add	$-24, ap
+L(end):	add	%r9, %rax
+	adc	%r10, %rcx
+	adc	%r8, %rdx
+
+	inc	%rsi
+	mov	$0x1, R32(%r10)
+	js	L(combine)
+
+	mov	$0x10000, R32(%r10)
+	adc	24(ap), %rax
+	dec	%rsi
+	js	L(combine)
+
+	adc	32(ap), %rcx
+	mov	$0x100000000, %r10
+
+L(combine):
+	sbb	%rsi, %rsi		C carry
+	mov	%rax, %rdi		C 0mod3
+	shr	$48, %rax		C 0mod3 high
+
+	and	%r10, %rsi		C carry masked
+	and	%r11, %rdi		C 0mod3 low
+	mov	R32(%rcx), R32(%r10)	C 1mod3
+
+	add	%rsi, %rax		C apply carry
+	shr	$32, %rcx		C 1mod3 high
+
+	add	%rdi, %rax		C apply 0mod3 low
+	movzwl	%dx, R32(%rdi)		C 2mod3
+	shl	$16, %r10		C 1mod3 low
+
+	add	%rcx, %rax		C apply 1mod3 high
+	shr	$16, %rdx		C 2mod3 high
+
+	add	%r10, %rax		C apply 1mod3 low
+	shl	$32, %rdi		C 2mod3 low
+
+	add	%rdx, %rax		C apply 2mod3 high
+	add	%rdi, %rax		C apply 2mod3 low
+
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/pentium4/mul_1.asm b/third_party/gmp/mpn/x86_64/pentium4/mul_1.asm
new file mode 100644
index 0000000..70de670
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/pentium4/mul_1.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_mul_1 optimised for Intel Nocona.
+
+dnl  Copyright 2018 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_mul_1 mpn_mul_1c)
+include_mpn(`x86_64/bd1/mul_1.asm')
diff --git a/third_party/gmp/mpn/x86_64/pentium4/mul_2.asm b/third_party/gmp/mpn/x86_64/pentium4/mul_2.asm
new file mode 100644
index 0000000..a0f7302
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/pentium4/mul_2.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_mul_2 optimised for Intel Nocona.
+
+dnl  Copyright 2018 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_mul_2)
+include_mpn(`x86_64/bd1/mul_2.asm')
diff --git a/third_party/gmp/mpn/x86_64/pentium4/mul_basecase.asm b/third_party/gmp/mpn/x86_64/pentium4/mul_basecase.asm
new file mode 100644
index 0000000..fb16029
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/pentium4/mul_basecase.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_mul_basecase optimised for Intel Nocona.
+
+dnl  Copyright 2018 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_mul_basecase)
+include_mpn(`x86_64/core2/mul_basecase.asm')
diff --git a/third_party/gmp/mpn/x86_64/pentium4/mullo_basecase.asm b/third_party/gmp/mpn/x86_64/pentium4/mullo_basecase.asm
new file mode 100644
index 0000000..b9e08a8
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/pentium4/mullo_basecase.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_mullo_basecase optimised for Intel Nocona.
+
+dnl  Copyright 2018 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_mullo_basecase)
+include_mpn(`x86_64/core2/mullo_basecase.asm')
diff --git a/third_party/gmp/mpn/x86_64/pentium4/popcount.asm b/third_party/gmp/mpn/x86_64/pentium4/popcount.asm
new file mode 100644
index 0000000..7014b39
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/pentium4/popcount.asm
@@ -0,0 +1,35 @@
+dnl  x86-64 mpn_popcount optimized for Pentium 4.
+
+dnl  Copyright 2007 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+MULFUNC_PROLOGUE(mpn_popcount)
+include_mpn(`x86/pentium4/sse2/popcount.asm')
diff --git a/third_party/gmp/mpn/x86_64/pentium4/redc_1.asm b/third_party/gmp/mpn/x86_64/pentium4/redc_1.asm
new file mode 100644
index 0000000..00e380d
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/pentium4/redc_1.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_redc_1 optimised for Intel Nocona.
+
+dnl  Copyright 2018 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_redc_1)
+include_mpn(`x86_64/bt1/redc_1.asm')
diff --git a/third_party/gmp/mpn/x86_64/pentium4/rsh1aors_n.asm b/third_party/gmp/mpn/x86_64/pentium4/rsh1aors_n.asm
new file mode 100644
index 0000000..5528ce4
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/pentium4/rsh1aors_n.asm
@@ -0,0 +1,334 @@
+dnl  x86-64 mpn_rsh1add_n/mpn_rsh1sub_n optimized for Pentium 4.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2007, 2008, 2010-2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C	     cycles/limb
+C AMD K8,K9	 4.13
+C AMD K10	 4.13
+C Intel P4	 5.70
+C Intel core2	 4.75
+C Intel corei	 5
+C Intel atom	 8.75
+C VIA nano	 5.25
+
+C TODO
+C  * Try to make this smaller, 746 bytes seem excessive for this 2nd class
+C    function.  Less sw pipelining would help, and since we now probably
+C    pipeline somewhat too deeply, it might not affect performance too much.
+C  * A separate small-n loop might speed things as well as make things smaller.
+C    That loop should be selected before pushing registers.
+
+C INPUT PARAMETERS
+define(`rp',	`%rdi')
+define(`up',	`%rsi')
+define(`vp',	`%rdx')
+define(`n',	`%rcx')
+define(`cy',	`%r8')
+
+ifdef(`OPERATION_rsh1add_n', `
+	define(ADDSUB,	      add)
+	define(func,	      mpn_rsh1add_n)
+	define(func_nc,	      mpn_rsh1add_nc)')
+ifdef(`OPERATION_rsh1sub_n', `
+	define(ADDSUB,	      sub)
+	define(func,	      mpn_rsh1sub_n)
+	define(func_nc,	      mpn_rsh1sub_nc)')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_rsh1add_n mpn_rsh1add_nc mpn_rsh1sub_n mpn_rsh1sub_nc)
+
+ASM_START()
+	TEXT
+PROLOGUE(func)
+	FUNC_ENTRY(4)
+	xor	%r8, %r8
+IFDOS(`	jmp	L(ent)		')
+EPILOGUE()
+PROLOGUE(func_nc)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8	')
+L(ent):	push	%rbx
+	push	%r12
+	push	%r13
+	push	%r14
+	push	%r15
+
+	mov	(vp), %r9
+	mov	(up), %r15
+
+	mov	R32(n), R32(%rax)
+	and	$3, R32(%rax)
+	jne	L(n00)
+
+	mov	R32(%r8), R32(%rbx)	C n = 0, 4, 8, ...
+	mov	8(up), %r10
+	ADDSUB	%r9, %r15
+	mov	8(vp), %r9
+	setc	R8(%rax)
+	ADDSUB	%rbx, %r15		C return bit
+	jnc	1f
+	mov	$1, R8(%rax)
+1:	mov	16(up), %r12
+	ADDSUB	%r9, %r10
+	mov	16(vp), %r9
+	setc	R8(%rbx)
+	mov	%r15, %r13
+	ADDSUB	%rax, %r10
+	jnc	1f
+	mov	$1, R8(%rbx)
+1:	mov	24(up), %r11
+	ADDSUB	%r9, %r12
+	lea	32(up), up
+	mov	24(vp), %r9
+	lea	32(vp), vp
+	setc	R8(%rax)
+	mov	%r10, %r14
+	shl	$63, %r10
+	shr	%r13
+	jmp	L(L00)
+
+L(n00):	cmp	$2, R32(%rax)
+	jnc	L(n01)
+	xor	R32(%rbx), R32(%rbx)	C n = 1, 5, 9, ...
+	lea	-24(rp), rp
+	mov	R32(%r8), R32(%rax)
+	dec	n
+	jnz	L(gt1)
+	ADDSUB	%r9, %r15
+	setc	R8(%rbx)
+	ADDSUB	%rax, %r15
+	jnc	1f
+	mov	$1, R8(%rbx)
+1:	mov	%r15, %r14
+	shl	$63, %rbx
+	shr	%r14
+	jmp	L(cj1)
+L(gt1):	mov	8(up), %r8
+	ADDSUB	%r9, %r15
+	mov	8(vp), %r9
+	setc	R8(%rbx)
+	ADDSUB	%rax, %r15
+	jnc	1f
+	mov	$1, R8(%rbx)
+1:	mov	16(up), %r10
+	ADDSUB	%r9, %r8
+	mov	16(vp), %r9
+	setc	R8(%rax)
+	mov	%r15, %r14
+	ADDSUB	%rbx, %r8
+	jnc	1f
+	mov	$1, R8(%rax)
+1:	mov	24(up), %r12
+	ADDSUB	%r9, %r10
+	mov	24(vp), %r9
+	setc	R8(%rbx)
+	mov	%r8, %r13
+	shl	$63, %r8
+	shr	%r14
+	lea	8(up), up
+	lea	8(vp), vp
+	jmp	L(L01)
+
+L(n01):	jne	L(n10)
+	lea	-16(rp), rp		C n = 2, 6, 10, ...
+	mov	R32(%r8), R32(%rbx)
+	mov	8(up), %r11
+	ADDSUB	%r9, %r15
+	mov	8(vp), %r9
+	setc	R8(%rax)
+	ADDSUB	%rbx, %r15
+	jnc	1f
+	mov	$1, R8(%rax)
+1:	sub	$2, n
+	jnz	L(gt2)
+	ADDSUB	%r9, %r11
+	setc	R8(%rbx)
+	mov	%r15, %r13
+	ADDSUB	%rax, %r11
+	jnc	1f
+	mov	$1, R8(%rbx)
+1:	mov	%r11, %r14
+	shl	$63, %r11
+	shr	%r13
+	jmp	L(cj2)
+L(gt2):	mov	16(up), %r8
+	ADDSUB	%r9, %r11
+	mov	16(vp), %r9
+	setc	R8(%rbx)
+	mov	%r15, %r13
+	ADDSUB	%rax, %r11
+	jnc	1f
+	mov	$1, R8(%rbx)
+1:	mov	24(up), %r10
+	ADDSUB	%r9, %r8
+	mov	24(vp), %r9
+	setc	R8(%rax)
+	mov	%r11, %r14
+	shl	$63, %r11
+	shr	%r13
+	lea	16(up), up
+	lea	16(vp), vp
+	jmp	L(L10)
+
+L(n10):	xor	R32(%rbx), R32(%rbx)	C n = 3, 7, 11, ...
+	lea	-8(rp), rp
+	mov	R32(%r8), R32(%rax)
+	mov	8(up), %r12
+	ADDSUB	%r9, %r15
+	mov	8(vp), %r9
+	setc	R8(%rbx)
+	ADDSUB	%rax, %r15
+	jnc	1f
+	mov	$1, R8(%rbx)
+1:	mov	16(up), %r11
+	ADDSUB	%r9, %r12
+	mov	16(vp), %r9
+	setc	R8(%rax)
+	mov	%r15, %r14
+	ADDSUB	%rbx, %r12
+	jnc	1f
+	mov	$1, R8(%rax)
+1:	sub	$3, n
+	jnz	L(gt3)
+	ADDSUB	%r9, %r11
+	setc	R8(%rbx)
+	mov	%r12, %r13
+	shl	$63, %r12
+	shr	%r14
+	jmp	L(cj3)
+L(gt3):	mov	24(up), %r8
+	ADDSUB	%r9, %r11
+	mov	24(vp), %r9
+	setc	R8(%rbx)
+	mov	%r12, %r13
+	shl	$63, %r12
+	shr	%r14
+	lea	24(up), up
+	lea	24(vp), vp
+	jmp	L(L11)
+
+L(c0):	mov	$1, R8(%rbx)
+	jmp	L(rc0)
+L(c1):	mov	$1, R8(%rax)
+	jmp	L(rc1)
+L(c2):	mov	$1, R8(%rbx)
+	jmp	L(rc2)
+
+	ALIGN(16)
+L(top):	mov	(up), %r8	C not on critical path
+	or	%r13, %r10
+	ADDSUB	%r9, %r11	C not on critical path
+	mov	(vp), %r9	C not on critical path
+	setc	R8(%rbx)	C save carry out
+	mov	%r12, %r13	C new for later
+	shl	$63, %r12	C shift new right
+	shr	%r14		C shift old left
+	mov	%r10, (rp)
+L(L11):	ADDSUB	%rax, %r11	C apply previous carry out
+	jc	L(c0)		C jump if ripple
+L(rc0):	mov	8(up), %r10
+	or	%r14, %r12
+	ADDSUB	%r9, %r8
+	mov	8(vp), %r9
+	setc	R8(%rax)
+	mov	%r11, %r14
+	shl	$63, %r11
+	shr	%r13
+	mov	%r12, 8(rp)
+L(L10):	ADDSUB	%rbx, %r8
+	jc	L(c1)
+L(rc1):	mov	16(up), %r12
+	or	%r13, %r11
+	ADDSUB	%r9, %r10
+	mov	16(vp), %r9
+	setc	R8(%rbx)
+	mov	%r8, %r13
+	shl	$63, %r8
+	shr	%r14
+	mov	%r11, 16(rp)
+L(L01):	ADDSUB	%rax, %r10
+	jc	L(c2)
+L(rc2):	mov	24(up), %r11
+	or	%r14, %r8
+	ADDSUB	%r9, %r12
+	lea	32(up), up
+	mov	24(vp), %r9
+	lea	32(vp), vp
+	setc	R8(%rax)
+	mov	%r10, %r14
+	shl	$63, %r10
+	shr	%r13
+	mov	%r8, 24(rp)
+	lea	32(rp), rp
+L(L00):	ADDSUB	%rbx, %r12
+	jc	L(c3)
+L(rc3):	sub	$4, n
+	ja	L(top)
+
+L(end):	or	%r13, %r10
+	ADDSUB	%r9, %r11
+	setc	R8(%rbx)
+	mov	%r12, %r13
+	shl	$63, %r12
+	shr	%r14
+	mov	%r10, (rp)
+L(cj3):	ADDSUB	%rax, %r11
+	jnc	1f
+	mov	$1, R8(%rbx)
+1:	or	%r14, %r12
+	mov	%r11, %r14
+	shl	$63, %r11
+	shr	%r13
+	mov	%r12, 8(rp)
+L(cj2):	or	%r13, %r11
+	shl	$63, %rbx
+	shr	%r14
+	mov	%r11, 16(rp)
+L(cj1):	or	%r14, %rbx
+	mov	%rbx, 24(rp)
+
+	mov	R32(%r15), R32(%rax)
+	and	$1, R32(%rax)
+	pop	%r15
+	pop	%r14
+	pop	%r13
+	pop	%r12
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+L(c3):	mov	$1, R8(%rax)
+	jmp	L(rc3)
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/pentium4/rshift.asm b/third_party/gmp/mpn/x86_64/pentium4/rshift.asm
new file mode 100644
index 0000000..b7c1ee2
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/pentium4/rshift.asm
@@ -0,0 +1,169 @@
+dnl  x86-64 mpn_rshift optimized for Pentium 4.
+
+dnl  Copyright 2003, 2005, 2007, 2008, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C	     cycles/limb
+C AMD K8,K9	 2.5
+C AMD K10	 ?
+C Intel P4	 3.29
+C Intel core2	 2.1 (fluctuates, presumably cache related)
+C Intel corei	 ?
+C Intel atom	14.3
+C VIA nano	 ?
+
+C INPUT PARAMETERS
+define(`rp',`%rdi')
+define(`up',`%rsi')
+define(`n',`%rdx')
+define(`cnt',`%cl')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_rshift)
+	FUNC_ENTRY(4)
+	mov	(up), %rax
+	movd	R32(%rcx), %mm4
+	neg	R32(%rcx)			C put lsh count in cl
+	and	$63, R32(%rcx)
+	movd	R32(%rcx), %mm5
+
+	lea	-8(up,n,8), up
+	lea	-8(rp,n,8), rp
+	lea	1(n), R32(%r8)
+	neg	n
+
+	shl	R8(%rcx), %rax		C function return value
+
+	and	$3, R32(%r8)
+	je	L(rol)			C jump for n = 3, 7, 11, ...
+
+	dec	R32(%r8)
+	jne	L(1)
+C	n = 4, 8, 12, ...
+	movq	8(up,n,8), %mm2
+	psrlq	%mm4, %mm2
+	movq	16(up,n,8), %mm0
+	psllq	%mm5, %mm0
+	por	%mm0, %mm2
+	movq	%mm2, 8(rp,n,8)
+	inc	n
+	jmp	L(rol)
+
+L(1):	dec	R32(%r8)
+	je	L(1x)			C jump for n = 1, 5, 9, 13, ...
+C	n = 2, 6, 10, 16, ...
+	movq	8(up,n,8), %mm2
+	psrlq	%mm4, %mm2
+	movq	16(up,n,8), %mm0
+	psllq	%mm5, %mm0
+	por	%mm0, %mm2
+	movq	%mm2, 8(rp,n,8)
+	inc	n
+L(1x):
+	cmp	$-1, n
+	je	L(ast)
+	movq	8(up,n,8), %mm2
+	psrlq	%mm4, %mm2
+	movq	16(up,n,8), %mm3
+	psrlq	%mm4, %mm3
+	movq	16(up,n,8), %mm0
+	movq	24(up,n,8), %mm1
+	psllq	%mm5, %mm0
+	por	%mm0, %mm2
+	psllq	%mm5, %mm1
+	por	%mm1, %mm3
+	movq	%mm2, 8(rp,n,8)
+	movq	%mm3, 16(rp,n,8)
+	add	$2, n
+
+L(rol):	movq	8(up,n,8), %mm2
+	psrlq	%mm4, %mm2
+	movq	16(up,n,8), %mm3
+	psrlq	%mm4, %mm3
+
+	add	$4, n			C				      4
+	jb	L(end)			C				      2
+	ALIGN(32)
+L(top):
+	C finish stuff from lsh block
+	movq	-16(up,n,8), %mm0
+	movq	-8(up,n,8), %mm1
+	psllq	%mm5, %mm0
+	por	%mm0, %mm2
+	psllq	%mm5, %mm1
+	movq	(up,n,8), %mm0
+	por	%mm1, %mm3
+	movq	8(up,n,8), %mm1
+	movq	%mm2, -24(rp,n,8)
+	movq	%mm3, -16(rp,n,8)
+	C start two new rsh
+	psllq	%mm5, %mm0
+	psllq	%mm5, %mm1
+
+	C finish stuff from rsh block
+	movq	-8(up,n,8), %mm2
+	movq	(up,n,8), %mm3
+	psrlq	%mm4, %mm2
+	por	%mm2, %mm0
+	psrlq	%mm4, %mm3
+	movq	8(up,n,8), %mm2
+	por	%mm3, %mm1
+	movq	16(up,n,8), %mm3
+	movq	%mm0, -8(rp,n,8)
+	movq	%mm1, (rp,n,8)
+	C start two new lsh
+	add	$4, n
+	psrlq	%mm4, %mm2
+	psrlq	%mm4, %mm3
+
+	jae	L(top)			C				      2
+L(end):
+	movq	-8(up), %mm0
+	psllq	%mm5, %mm0
+	por	%mm0, %mm2
+	movq	(up), %mm1
+	psllq	%mm5, %mm1
+	por	%mm1, %mm3
+	movq	%mm2, -16(rp)
+	movq	%mm3, -8(rp)
+
+L(ast):	movq	(up), %mm2
+	psrlq	%mm4, %mm2
+	movq	%mm2, (rp)
+	emms
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/pentium4/sec_tabselect.asm b/third_party/gmp/mpn/x86_64/pentium4/sec_tabselect.asm
new file mode 100644
index 0000000..e436034
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/pentium4/sec_tabselect.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_sec_tabselect.
+
+dnl  Copyright 2012, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_sec_tabselect)
+include_mpn(`x86_64/fastsse/sec_tabselect.asm')
diff --git a/third_party/gmp/mpn/x86_64/pentium4/sqr_basecase.asm b/third_party/gmp/mpn/x86_64/pentium4/sqr_basecase.asm
new file mode 100644
index 0000000..9725287
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/pentium4/sqr_basecase.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_sqr_basecase optimised for Intel Nocona.
+
+dnl  Copyright 2018 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_sqr_basecase)
+include_mpn(`x86_64/core2/sqr_basecase.asm')
diff --git a/third_party/gmp/mpn/x86_64/popham.asm b/third_party/gmp/mpn/x86_64/popham.asm
new file mode 100644
index 0000000..3a29b2e
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/popham.asm
@@ -0,0 +1,163 @@
+dnl  AMD64 mpn_popcount, mpn_hamdist -- population count and hamming distance.
+
+dnl  Copyright 2004, 2005, 2007, 2010-2012, 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+
+C		     popcount	      hamdist
+C		    cycles/limb	    cycles/limb
+C AMD K8,K9		 6		 7
+C AMD K10		 6		 7
+C Intel P4		12		14.3
+C Intel core2		 7		 8
+C Intel corei		 ?		 7.3
+C Intel atom		16.5		17.5
+C VIA nano		 8.75		10.4
+
+C TODO
+C  * Tune.  It should be possible to reach 5 c/l for popcount and 6 c/l for
+C    hamdist for K8/K9.
+
+
+ifdef(`OPERATION_popcount',`
+  define(`func',`mpn_popcount')
+  define(`up',		`%rdi')
+  define(`n',		`%rsi')
+  define(`h55555555',	`%r10')
+  define(`h33333333',	`%r11')
+  define(`h0f0f0f0f',	`%rcx')
+  define(`h01010101',	`%rdx')
+  define(`POP',		`$1')
+  define(`HAM',		`dnl')
+')
+ifdef(`OPERATION_hamdist',`
+  define(`func',`mpn_hamdist')
+  define(`up',		`%rdi')
+  define(`vp',		`%rsi')
+  define(`n',		`%rdx')
+  define(`h55555555',	`%r10')
+  define(`h33333333',	`%r11')
+  define(`h0f0f0f0f',	`%rcx')
+  define(`h01010101',	`%r12')
+  define(`POP',		`dnl')
+  define(`HAM',		`$1')
+')
+
+
+MULFUNC_PROLOGUE(mpn_popcount mpn_hamdist)
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(func)
+ POP(`	FUNC_ENTRY(2)		')
+ HAM(`	FUNC_ENTRY(3)		')
+	push	%rbx
+	mov	$0x5555555555555555, h55555555
+	push	%rbp
+	mov	$0x3333333333333333, h33333333
+ HAM(`	push	%r12		')
+	lea	(up,n,8), up
+	mov	$0x0f0f0f0f0f0f0f0f, h0f0f0f0f
+ HAM(`	lea	(vp,n,8), vp	')
+	neg	n
+	mov	$0x0101010101010101, h01010101
+	xor	R32(%rax), R32(%rax)
+	test	$1, R8(n)
+	jz	L(top)
+
+	mov	(up,n,8), %r8
+ HAM(`	xor	(vp,n,8), %r8	')
+
+	mov	%r8, %r9
+	shr	%r8
+	and	h55555555, %r8
+	sub	%r8, %r9
+
+	mov	%r9, %r8
+	shr	$2, %r9
+	and	h33333333, %r8
+	and	h33333333, %r9
+	add	%r8, %r9		C 16 4-bit fields (0..4)
+
+	dec	n
+	jmp	L(mid)
+
+	ALIGN(16)
+L(top):	mov	(up,n,8), %r8
+	mov	8(up,n,8), %rbx
+ HAM(`	xor	(vp,n,8), %r8	')
+ HAM(`	xor	8(vp,n,8), %rbx	')
+
+	mov	%r8, %r9
+	mov	%rbx, %rbp
+	shr	%r8
+	shr	%rbx
+	and	h55555555, %r8
+	and	h55555555, %rbx
+	sub	%r8, %r9
+	sub	%rbx, %rbp
+
+	mov	%r9, %r8
+	mov	%rbp, %rbx
+	shr	$2, %r9
+	shr	$2, %rbp
+	and	h33333333, %r8
+	and	h33333333, %r9
+	and	h33333333, %rbx
+	and	h33333333, %rbp
+	add	%r8, %r9		C 16 4-bit fields (0..4)
+	add	%rbx, %rbp		C 16 4-bit fields (0..4)
+
+	add	%rbp, %r9		C 16 4-bit fields (0..8)
+L(mid):	mov	%r9, %r8
+	shr	$4, %r9
+	and	h0f0f0f0f, %r8
+	and	h0f0f0f0f, %r9
+	add	%r8, %r9		C 8 8-bit fields (0..16)
+
+	imul	h01010101, %r9		C sum the 8 fields in high 8 bits
+	shr	$56, %r9
+
+	add	%r9, %rax		C add to total
+	add	$2, n
+	jnc	L(top)
+
+L(end):
+ HAM(`	pop	%r12		')
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/rsh1aors_n.asm b/third_party/gmp/mpn/x86_64/rsh1aors_n.asm
new file mode 100644
index 0000000..a3e9cc5
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/rsh1aors_n.asm
@@ -0,0 +1,189 @@
+dnl  AMD64 mpn_rsh1add_n -- rp[] = (up[] + vp[]) >> 1
+dnl  AMD64 mpn_rsh1sub_n -- rp[] = (up[] - vp[]) >> 1
+
+dnl  Copyright 2003, 2005, 2009, 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 2.14	(mpn_add_n + mpn_rshift need 4.125)
+C AMD K10	 2.14	(mpn_add_n + mpn_rshift need 4.125)
+C Intel P4	12.75
+C Intel core2	 3.75
+C Intel NMH	 4.4
+C Intel SBR	 ?
+C Intel atom	 ?
+C VIA nano	 3.25
+
+C TODO
+C  * Rewrite to use indexed addressing, like addlsh1.asm and sublsh1.asm.
+
+C INPUT PARAMETERS
+define(`rp', `%rdi')
+define(`up', `%rsi')
+define(`vp', `%rdx')
+define(`n',`  %rcx')
+
+ifdef(`OPERATION_rsh1add_n', `
+	define(ADDSUB,	      add)
+	define(ADCSBB,	      adc)
+	define(func_n,	      mpn_rsh1add_n)
+	define(func_nc,	      mpn_rsh1add_nc)')
+ifdef(`OPERATION_rsh1sub_n', `
+	define(ADDSUB,	      sub)
+	define(ADCSBB,	      sbb)
+	define(func_n,	      mpn_rsh1sub_n)
+	define(func_nc,	      mpn_rsh1sub_nc)')
+
+MULFUNC_PROLOGUE(mpn_rsh1add_n mpn_rsh1add_nc mpn_rsh1sub_n mpn_rsh1sub_nc)
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(func_nc)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8	')
+	push	%rbx
+
+	xor	R32(%rax), R32(%rax)
+	neg	%r8			C set C flag from parameter
+	mov	(up), %rbx
+	ADCSBB	(vp), %rbx
+	jmp	L(ent)
+EPILOGUE()
+
+	ALIGN(16)
+PROLOGUE(func_n)
+	FUNC_ENTRY(4)
+	push	%rbx
+
+	xor	R32(%rax), R32(%rax)
+	mov	(up), %rbx
+	ADDSUB	(vp), %rbx
+L(ent):
+	rcr	%rbx			C rotate, save acy
+	adc	R32(%rax), R32(%rax)	C return value
+
+	mov	R32(n), R32(%r11)
+	and	$3, R32(%r11)
+
+	cmp	$1, R32(%r11)
+	je	L(do)			C jump if n = 1 5 9 ...
+
+L(n1):	cmp	$2, R32(%r11)
+	jne	L(n2)			C jump unless n = 2 6 10 ...
+	add	%rbx, %rbx		C rotate carry limb, restore acy
+	mov	8(up), %r10
+	ADCSBB	8(vp), %r10
+	lea	8(up), up
+	lea	8(vp), vp
+	lea	8(rp), rp
+	rcr	%r10
+	rcr	%rbx
+	mov	%rbx, -8(rp)
+	jmp	L(cj1)
+
+L(n2):	cmp	$3, R32(%r11)
+	jne	L(n3)			C jump unless n = 3 7 11 ...
+	add	%rbx, %rbx		C rotate carry limb, restore acy
+	mov	8(up), %r9
+	mov	16(up), %r10
+	ADCSBB	8(vp), %r9
+	ADCSBB	16(vp), %r10
+	lea	16(up), up
+	lea	16(vp), vp
+	lea	16(rp), rp
+	rcr	%r10
+	rcr	%r9
+	rcr	%rbx
+	mov	%rbx, -16(rp)
+	jmp	L(cj2)
+
+L(n3):	dec	n			C come here for n = 4 8 12 ...
+	add	%rbx, %rbx		C rotate carry limb, restore acy
+	mov	8(up), %r8
+	mov	16(up), %r9
+	ADCSBB	8(vp), %r8
+	ADCSBB	16(vp), %r9
+	mov	24(up), %r10
+	ADCSBB	24(vp), %r10
+	lea	24(up), up
+	lea	24(vp), vp
+	lea	24(rp), rp
+	rcr	%r10
+	rcr	%r9
+	rcr	%r8
+	rcr	%rbx
+	mov	%rbx, -24(rp)
+	mov	%r8, -16(rp)
+L(cj2):	mov	%r9, -8(rp)
+L(cj1):	mov	%r10, %rbx
+
+L(do):
+	shr	$2, n			C				4
+	je	L(end)			C				2
+	ALIGN(16)
+L(top):	add	%rbx, %rbx		C rotate carry limb, restore acy
+
+	mov	8(up), %r8
+	mov	16(up), %r9
+	ADCSBB	8(vp), %r8
+	ADCSBB	16(vp), %r9
+	mov	24(up), %r10
+	mov	32(up), %r11
+	ADCSBB	24(vp), %r10
+	ADCSBB	32(vp), %r11
+
+	lea	32(up), up
+	lea	32(vp), vp
+
+	rcr	%r11			C rotate, save acy
+	rcr	%r10
+	rcr	%r9
+	rcr	%r8
+
+	rcr	%rbx
+	mov	%rbx, (rp)
+	mov	%r8, 8(rp)
+	mov	%r9, 16(rp)
+	mov	%r10, 24(rp)
+	mov	%r11, %rbx
+
+	lea	32(rp), rp
+	dec	n
+	jne	L(top)
+
+L(end):	mov	%rbx, (rp)
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/rshift.asm b/third_party/gmp/mpn/x86_64/rshift.asm
new file mode 100644
index 0000000..3f344f1
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/rshift.asm
@@ -0,0 +1,176 @@
+dnl  AMD64 mpn_rshift -- mpn right shift.
+
+dnl  Copyright 2003, 2005, 2009, 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C	     cycles/limb
+C AMD K8,K9	 2.375
+C AMD K10	 2.375
+C Intel P4	 8
+C Intel core2	 2.11
+C Intel corei	 ?
+C Intel atom	 5.75
+C VIA nano	 3.5
+
+
+C INPUT PARAMETERS
+define(`rp',	`%rdi')
+define(`up',	`%rsi')
+define(`n',	`%rdx')
+define(`cnt',	`%rcx')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_rshift)
+	FUNC_ENTRY(4)
+	neg	R32(%rcx)		C put rsh count in cl
+	mov	(up), %rax
+	shl	R8(%rcx), %rax		C function return value
+	neg	R32(%rcx)		C put lsh count in cl
+
+	lea	1(n), R32(%r8)
+
+	lea	-8(up,n,8), up
+	lea	-8(rp,n,8), rp
+	neg	n
+
+	and	$3, R32(%r8)
+	je	L(rlx)			C jump for n = 3, 7, 11, ...
+
+	dec	R32(%r8)
+	jne	L(1)
+C	n = 4, 8, 12, ...
+	mov	8(up,n,8), %r10
+	shr	R8(%rcx), %r10
+	neg	R32(%rcx)		C put rsh count in cl
+	mov	16(up,n,8), %r8
+	shl	R8(%rcx), %r8
+	or	%r8, %r10
+	mov	%r10, 8(rp,n,8)
+	inc	n
+	jmp	L(rll)
+
+L(1):	dec	R32(%r8)
+	je	L(1x)			C jump for n = 1, 5, 9, 13, ...
+C	n = 2, 6, 10, 16, ...
+	mov	8(up,n,8), %r10
+	shr	R8(%rcx), %r10
+	neg	R32(%rcx)		C put rsh count in cl
+	mov	16(up,n,8), %r8
+	shl	R8(%rcx), %r8
+	or	%r8, %r10
+	mov	%r10, 8(rp,n,8)
+	inc	n
+	neg	R32(%rcx)		C put lsh count in cl
+L(1x):
+	cmp	$-1, n
+	je	L(ast)
+	mov	8(up,n,8), %r10
+	shr	R8(%rcx), %r10
+	mov	16(up,n,8), %r11
+	shr	R8(%rcx), %r11
+	neg	R32(%rcx)		C put rsh count in cl
+	mov	16(up,n,8), %r8
+	mov	24(up,n,8), %r9
+	shl	R8(%rcx), %r8
+	or	%r8, %r10
+	shl	R8(%rcx), %r9
+	or	%r9, %r11
+	mov	%r10, 8(rp,n,8)
+	mov	%r11, 16(rp,n,8)
+	add	$2, n
+
+L(rll):	neg	R32(%rcx)		C put lsh count in cl
+L(rlx):	mov	8(up,n,8), %r10
+	shr	R8(%rcx), %r10
+	mov	16(up,n,8), %r11
+	shr	R8(%rcx), %r11
+
+	add	$4, n			C				      4
+	jb	L(end)			C				      2
+	ALIGN(16)
+L(top):
+	C finish stuff from lsh block
+	neg	R32(%rcx)		C put rsh count in cl
+	mov	-16(up,n,8), %r8
+	mov	-8(up,n,8), %r9
+	shl	R8(%rcx), %r8
+	or	%r8, %r10
+	shl	R8(%rcx), %r9
+	or	%r9, %r11
+	mov	%r10, -24(rp,n,8)
+	mov	%r11, -16(rp,n,8)
+	C start two new rsh
+	mov	(up,n,8), %r8
+	mov	8(up,n,8), %r9
+	shl	R8(%rcx), %r8
+	shl	R8(%rcx), %r9
+
+	C finish stuff from rsh block
+	neg	R32(%rcx)		C put lsh count in cl
+	mov	-8(up,n,8), %r10
+	mov	0(up,n,8), %r11
+	shr	R8(%rcx), %r10
+	or	%r10, %r8
+	shr	R8(%rcx), %r11
+	or	%r11, %r9
+	mov	%r8, -8(rp,n,8)
+	mov	%r9, 0(rp,n,8)
+	C start two new lsh
+	mov	8(up,n,8), %r10
+	mov	16(up,n,8), %r11
+	shr	R8(%rcx), %r10
+	shr	R8(%rcx), %r11
+
+	add	$4, n
+	jae	L(top)			C				      2
+L(end):
+	neg	R32(%rcx)		C put rsh count in cl
+	mov	-8(up), %r8
+	shl	R8(%rcx), %r8
+	or	%r8, %r10
+	mov	(up), %r9
+	shl	R8(%rcx), %r9
+	or	%r9, %r11
+	mov	%r10, -16(rp)
+	mov	%r11, -8(rp)
+
+	neg	R32(%rcx)		C put lsh count in cl
+L(ast):	mov	(up), %r10
+	shr	R8(%rcx), %r10
+	mov	%r10, (rp)
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/sec_tabselect.asm b/third_party/gmp/mpn/x86_64/sec_tabselect.asm
new file mode 100644
index 0000000..e8aed26
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/sec_tabselect.asm
@@ -0,0 +1,176 @@
+dnl  AMD64 mpn_sec_tabselect.
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C	     cycles/limb          good for cpu
+C AMD K8,K9	 1.5			Y
+C AMD K10	 1.4
+C AMD bd1	 2.64
+C AMD bobcat	 2.15			Y
+C Intel P4	 4
+C Intel core2	 1.38
+C Intel NHM	 1.75
+C Intel SBR	 1.25
+C Intel atom	 2.5			Y
+C VIA nano	 1.75			Y
+
+C NOTES
+C  * This has not been tuned for any specific processor.  Its speed should not
+C    be too bad, though.
+C  * Using SSE2/AVX2 could result in many-fold speedup.
+C  * WORKS FOR n mod 4 = 0 ONLY!
+
+C mpn_sec_tabselect (mp_limb_t *rp, mp_limb_t *tp, mp_size_t n, mp_size_t nents, mp_size_t which)
+define(`rp',     `%rdi')
+define(`tp',     `%rsi')
+define(`n',      `%rdx')
+define(`nents',  `%rcx')
+define(`which',  `%r8')
+
+define(`i',      `%rbp')
+define(`j',      `%r9')
+
+C rax  rbx  rcx  rdx  rdi  rsi  rbp   r8   r9  r10  r11  r12  r13  r14  r15
+C          nents  n   rp   tab   i   which j    *    *    *    *    *    *
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_sec_tabselect)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8d	')
+
+	push	%rbx
+	push	%rbp
+	push	%r12
+	push	%r13
+	push	%r14
+	push	%r15
+
+	mov	n, j
+	add	$-4, j
+	js	L(outer_end)
+
+L(outer_top):
+	mov	nents, i
+	push	tp
+	xor	R32(%r12), R32(%r12)
+	xor	R32(%r13), R32(%r13)
+	xor	R32(%r14), R32(%r14)
+	xor	R32(%r15), R32(%r15)
+	mov	which, %rbx
+
+	ALIGN(16)
+L(top):	sub	$1, %rbx
+	sbb	%rax, %rax
+	mov	0(tp), %r10
+	mov	8(tp), %r11
+	and	%rax, %r10
+	and	%rax, %r11
+	or	%r10, %r12
+	or	%r11, %r13
+	mov	16(tp), %r10
+	mov	24(tp), %r11
+	and	%rax, %r10
+	and	%rax, %r11
+	or	%r10, %r14
+	or	%r11, %r15
+	lea	(tp,n,8), tp
+	add	$-1, i
+	jne	L(top)
+
+	mov	%r12, 0(rp)
+	mov	%r13, 8(rp)
+	mov	%r14, 16(rp)
+	mov	%r15, 24(rp)
+	pop	tp
+	lea	32(tp), tp
+	lea	32(rp), rp
+	add	$-4, j
+	jns	L(outer_top)
+L(outer_end):
+
+	test	$2, R8(n)
+	jz	L(b0x)
+L(b1x):	mov	nents, i
+	push	tp
+	xor	R32(%r12), R32(%r12)
+	xor	R32(%r13), R32(%r13)
+	mov	which, %rbx
+	ALIGN(16)
+L(tp2):	sub	$1, %rbx
+	sbb	%rax, %rax
+	mov	0(tp), %r10
+	mov	8(tp), %r11
+	and	%rax, %r10
+	and	%rax, %r11
+	or	%r10, %r12
+	or	%r11, %r13
+	lea	(tp,n,8), tp
+	add	$-1, i
+	jne	L(tp2)
+	mov	%r12, 0(rp)
+	mov	%r13, 8(rp)
+	pop	tp
+	lea	16(tp), tp
+	lea	16(rp), rp
+
+L(b0x):	test	$1, R8(n)
+	jz	L(b00)
+L(b01):	mov	nents, i
+	xor	R32(%r12), R32(%r12)
+	mov	which, %rbx
+	ALIGN(16)
+L(tp1):	sub	$1, %rbx
+	sbb	%rax, %rax
+	mov	0(tp), %r10
+	and	%rax, %r10
+	or	%r10, %r12
+	lea	(tp,n,8), tp
+	add	$-1, i
+	jne	L(tp1)
+	mov	%r12, 0(rp)
+
+L(b00):	pop	%r15
+	pop	%r14
+	pop	%r13
+	pop	%r12
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/silvermont/aorrlsh1_n.asm b/third_party/gmp/mpn/x86_64/silvermont/aorrlsh1_n.asm
new file mode 100644
index 0000000..98c26cf
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/silvermont/aorrlsh1_n.asm
@@ -0,0 +1,50 @@
+dnl  X86-64 mpn_addlsh1_n/mpn_rsblsh1_n optimised for Intel Silvermont.
+
+dnl  Copyright 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+define(LSH, 1)
+define(RSH, 63)
+
+ifdef(`OPERATION_addlsh1_n', `
+	define(ADDSUB,	add)
+	define(ADCSBB,	adc)
+	define(func,	mpn_addlsh1_n)')
+ifdef(`OPERATION_rsblsh1_n', `
+	define(ADDSUB,	sub)
+	define(ADCSBB,	sbb)
+	define(func,	mpn_rsblsh1_n)')
+
+MULFUNC_PROLOGUE(mpn_addlsh1_n mpn_rsblsh1_n)
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+include_mpn(`x86_64/aorrlshC_n.asm')
diff --git a/third_party/gmp/mpn/x86_64/silvermont/aorrlsh2_n.asm b/third_party/gmp/mpn/x86_64/silvermont/aorrlsh2_n.asm
new file mode 100644
index 0000000..2a83217
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/silvermont/aorrlsh2_n.asm
@@ -0,0 +1,50 @@
+dnl  X86-64 mpn_addlsh2_n/mpn_rsblsh2_n optimised for Intel Silvermont.
+
+dnl  Copyright 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+define(LSH, 2)
+define(RSH, 62)
+
+ifdef(`OPERATION_addlsh2_n', `
+	define(ADDSUB,	add)
+	define(ADCSBB,	adc)
+	define(func,	mpn_addlsh2_n)')
+ifdef(`OPERATION_rsblsh2_n', `
+	define(ADDSUB,	sub)
+	define(ADCSBB,	sbb)
+	define(func,	mpn_rsblsh2_n)')
+
+MULFUNC_PROLOGUE(mpn_addlsh2_n mpn_rsblsh2_n)
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+include_mpn(`x86_64/aorrlshC_n.asm')
diff --git a/third_party/gmp/mpn/x86_64/silvermont/aors_n.asm b/third_party/gmp/mpn/x86_64/silvermont/aors_n.asm
new file mode 100644
index 0000000..dce3d75
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/silvermont/aors_n.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_add_n, mpn_sub_n, optimised for Intel Silvermont.
+
+dnl  Copyright 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_add_n mpn_add_nc mpn_sub_n mpn_sub_nc)
+include_mpn(`x86_64/coreisbr/aors_n.asm')
diff --git a/third_party/gmp/mpn/x86_64/silvermont/aorsmul_1.asm b/third_party/gmp/mpn/x86_64/silvermont/aorsmul_1.asm
new file mode 100644
index 0000000..ead0d76
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/silvermont/aorsmul_1.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_addmul_1/mpn_submul_1 optimised for Intel Silvermont.
+
+dnl  Copyright 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_addmul_1 mpn_addmul_1c mpn_submul_1 mpn_submul_1c)
+include_mpn(`x86_64/core2/aorsmul_1.asm')
diff --git a/third_party/gmp/mpn/x86_64/silvermont/gmp-mparam.h b/third_party/gmp/mpn/x86_64/silvermont/gmp-mparam.h
new file mode 100644
index 0000000..f8cb0f4
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/silvermont/gmp-mparam.h
@@ -0,0 +1,252 @@
+/* Intel Silvermont gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+/* Disable use of slow functions.  FIXME: We should disable lib inclusion.  */
+#undef HAVE_NATIVE_mpn_mul_2
+#undef HAVE_NATIVE_mpn_addmul_2
+
+/* 2400 MHz Intel Atom C2758 Silvermont/Rangeley */
+/* FFT tuning limit = 468153400 */
+/* Generated by tuneup.c, 2019-10-19, gcc 8.3 */
+
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          4
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          3
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        55
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD         0  /* never mpn_mod_1s_2p */
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD      9
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1_NORM_THRESHOLD              1
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD           MP_SIZE_T_MAX  /* never */
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD        MP_SIZE_T_MAX  /* never */
+
+#define DIV_1_VS_MUL_1_PERCENT             168
+
+#define MUL_TOOM22_THRESHOLD                19
+#define MUL_TOOM33_THRESHOLD                66
+#define MUL_TOOM44_THRESHOLD               152
+#define MUL_TOOM6H_THRESHOLD               222
+#define MUL_TOOM8H_THRESHOLD               333
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD     105
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     114
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     105
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     113
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD      88
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 24
+#define SQR_TOOM3_THRESHOLD                 97
+#define SQR_TOOM4_THRESHOLD                232
+#define SQR_TOOM6_THRESHOLD                286
+#define SQR_TOOM8_THRESHOLD                  0  /* always */
+
+#define MULMID_TOOM42_THRESHOLD             24
+
+#define MULMOD_BNM1_THRESHOLD               13
+#define SQRMOD_BNM1_THRESHOLD               15
+
+#define MUL_FFT_MODF_THRESHOLD             340  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    340, 5}, {     17, 6}, {      9, 5}, {     19, 6}, \
+    {     17, 7}, {      9, 6}, {     20, 7}, {     11, 6}, \
+    {     23, 7}, {     17, 8}, {      9, 7}, {     21, 8}, \
+    {     11, 7}, {     23, 8}, {     13, 7}, {     27, 8}, \
+    {     15, 7}, {     31, 8}, {     21, 9}, {     11, 8}, \
+    {     27, 9}, {     15, 8}, {     33, 9}, {     19, 8}, \
+    {     39, 9}, {     23, 8}, {     47, 9}, {     27,10}, \
+    {     15, 9}, {     39,10}, {     23, 9}, {     51,11}, \
+    {     15,10}, {     31, 9}, {     67,10}, {     39, 9}, \
+    {     79,10}, {     47, 9}, {     95,10}, {     55,11}, \
+    {     31,10}, {     79,11}, {     47,10}, {     95,12}, \
+    {     31,11}, {     63,10}, {    127, 9}, {    255,10}, \
+    {    135,11}, {     79, 9}, {    319,11}, {     95,10}, \
+    {    191, 9}, {    383,10}, {    207, 9}, {    415,11}, \
+    {    111,12}, {     63,11}, {    127,10}, {    255, 9}, \
+    {    511,10}, {    271,11}, {    143,10}, {    287, 9}, \
+    {    575,10}, {    303,11}, {    159,10}, {    319,12}, \
+    {     95,11}, {    191,10}, {    383,11}, {    207,10}, \
+    {    415,13}, {     63,12}, {    127,11}, {    255,10}, \
+    {    511,11}, {    271,10}, {    543,11}, {    287,10}, \
+    {    575,11}, {    319,10}, {    639,11}, {    351,10}, \
+    {    703, 9}, {   1407,12}, {    191,11}, {    415,10}, \
+    {    831,12}, {    223,11}, {    479,13}, {    127,12}, \
+    {    255,11}, {    543,12}, {    287,11}, {    575,10}, \
+    {   1151,12}, {    319,11}, {    639,12}, {    351,11}, \
+    {    703,10}, {   1407,13}, {    191,12}, {    415,11}, \
+    {    831,10}, {   1663,12}, {    479,14}, {    127,13}, \
+    {    255,12}, {    543,11}, {   1087,10}, {   2175,12}, \
+    {    575,11}, {   1151,13}, {    319,12}, {    639,11}, \
+    {   1279,12}, {    703,11}, {   1407,13}, {    383,12}, \
+    {    831,11}, {   1663,13}, {    447,12}, {    959,14}, \
+    {    255,13}, {    511,12}, {   1087,11}, {   2175,13}, \
+    {    575,12}, {   1215,11}, {   2431,10}, {   4863,13}, \
+    {    639,12}, {   1279,13}, {    703,12}, {   1407,14}, \
+    {    383,13}, {    831,12}, {   1663,13}, {    959,15}, \
+    {    255,14}, {    511,13}, {   1087,12}, {   2175,13}, \
+    {   1215,12}, {   2431,11}, {   4863,14}, {    639,13}, \
+    {   1407,12}, {   2815,13}, {   1471,12}, {   2943,11}, \
+    {   5887,14}, {    767,13}, {   1663,14}, {    895,13}, \
+    {   1919,15}, {    511,14}, {   1023,13}, {   2175,14}, \
+    {   1151,13}, {   2431,12}, {   4863,14}, {   1279,13}, \
+    {   2559,14}, {   1407,13}, {   2943,12}, {   5887,15}, \
+    {    767,14}, {   1663,13}, {   3455,12}, {   6911,14}, \
+    {   1919,16}, {    511,15}, {   1023,14}, {   2431,13}, \
+    {   4863,15}, {   1279,14}, {   2943,13}, {   5887,12}, \
+    {  11775,15}, {   1535,14}, {   3455,13}, {   6911,15}, \
+    {   1791,14}, {   3839,13}, {   7679,16}, {   1023,15}, \
+    {   2047,14}, {   4223,15}, {   2303,14}, {   4863,15}, \
+    {   2815,14}, {   5887,13}, {  11775,16}, {   1535,15}, \
+    {   3327,14}, {   6911,15}, {   3839,14}, {   7679,17}, \
+    {   1023,16}, {   2047,15}, {   4863,16}, {   2559,15}, \
+    {   5887,14}, {  11775,16}, {   3071,15}, {   6911,16}, \
+    {   3583,15}, {   7679,14}, {  15359,17}, {   2047,16}, \
+    {   4607,15}, {   9215,16}, {   5631,15}, {  11775,17}, \
+    {   3071,16}, {  65536,17}, { 131072,18}, { 262144,19}, \
+    { 524288,20}, {1048576,21}, {2097152,22}, {4194304,23}, \
+    {8388608,24} }
+#define MUL_FFT_TABLE3_SIZE 225
+#define MUL_FFT_THRESHOLD                 3712
+
+#define SQR_FFT_MODF_THRESHOLD             308  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    308, 5}, {     17, 6}, {      9, 5}, {     19, 6}, \
+    {     21, 7}, {     11, 6}, {     23, 7}, {     17, 8}, \
+    {      9, 7}, {     21, 8}, {     11, 7}, {     23, 8}, \
+    {     13, 7}, {     27, 8}, {     15, 7}, {     31, 8}, \
+    {     21, 9}, {     11, 8}, {     27, 9}, {     15, 8}, \
+    {     33, 9}, {     19, 8}, {     39, 9}, {     23, 8}, \
+    {     47, 9}, {     27,10}, {     15, 9}, {     39,10}, \
+    {     23, 9}, {     47,11}, {     15,10}, {     31, 9}, \
+    {     63,10}, {     39, 9}, {     79,10}, {     47, 9}, \
+    {     95,11}, {     31,10}, {     79,11}, {     47,10}, \
+    {     95,12}, {     31,11}, {     63,10}, {    127, 9}, \
+    {    255, 8}, {    511, 9}, {    271, 8}, {    543,11}, \
+    {     79,10}, {    159, 9}, {    319, 8}, {    639,10}, \
+    {    175,11}, {     95,10}, {    191, 9}, {    383,10}, \
+    {    207, 9}, {    415,12}, {     63,11}, {    127,10}, \
+    {    255, 9}, {    511,10}, {    271, 9}, {    543,10}, \
+    {    287, 9}, {    575,10}, {    303,11}, {    159,10}, \
+    {    319, 9}, {    639,11}, {    175,10}, {    351,12}, \
+    {     95,11}, {    191,10}, {    383,11}, {    207,10}, \
+    {    415,13}, {     63,12}, {    127,11}, {    255,10}, \
+    {    511,11}, {    271,10}, {    543,11}, {    287,10}, \
+    {    575,11}, {    303,12}, {    159,11}, {    319,10}, \
+    {    639,11}, {    351,10}, {    703,12}, {    191,11}, \
+    {    383,10}, {    767,11}, {    415,10}, {    831,12}, \
+    {    223,11}, {    479,12}, {    255,11}, {    543,12}, \
+    {    287,11}, {    575,12}, {    319,11}, {    639,12}, \
+    {    351,11}, {    703,10}, {   1407,13}, {    191,12}, \
+    {    383,11}, {    767,12}, {    415,11}, {    831,12}, \
+    {    479,13}, {    255,12}, {    543,11}, {   1087,10}, \
+    {   2175,12}, {    575,11}, {   1151,12}, {    607,13}, \
+    {    319,12}, {    639,11}, {   1279,12}, {    703,11}, \
+    {   1407,13}, {    383,12}, {    831,11}, {   1663,13}, \
+    {    447,12}, {    895,14}, {    255,13}, {    511,12}, \
+    {   1087,11}, {   2175,13}, {    575,12}, {   1215,11}, \
+    {   2431,13}, {    639,12}, {   1279,13}, {    703,12}, \
+    {   1407,14}, {    383,13}, {    831,12}, {   1663,13}, \
+    {    959,15}, {    255,14}, {    511,13}, {   1087,12}, \
+    {   2175,13}, {   1215,12}, {   2431,14}, {    639,13}, \
+    {   1343,12}, {   2687,13}, {   1407,12}, {   2815,13}, \
+    {   1471,12}, {   2943,14}, {    767,13}, {   1663,14}, \
+    {    895,13}, {   1791,15}, {    511,14}, {   1023,13}, \
+    {   2175,14}, {   1151,13}, {   2431,12}, {   4863,14}, \
+    {   1279,13}, {   2687,14}, {   1407,13}, {   2943,15}, \
+    {    767,14}, {   1663,13}, {   3455,12}, {   6911,14}, \
+    {   1791,13}, {   3583,16}, {    511,15}, {   1023,14}, \
+    {   2431,13}, {   4863,15}, {   1279,14}, {   2943,13}, \
+    {   5887,12}, {  11775,15}, {   1535,14}, {   3455,13}, \
+    {   6911,15}, {   1791,14}, {   3839,13}, {   7679,16}, \
+    {   1023,15}, {   2047,14}, {   4223,15}, {   2303,14}, \
+    {   4863,15}, {   2815,14}, {   5887,13}, {  11775,16}, \
+    {   1535,15}, {   3071,14}, {   6143,15}, {   3327,14}, \
+    {   6911,15}, {   3839,14}, {   7679,17}, {   1023,16}, \
+    {   2047,15}, {   4863,16}, {   2559,15}, {   5887,14}, \
+    {  11775,16}, {   3071,15}, {   6911,16}, {   3583,15}, \
+    {   7679,14}, {  15359,17}, {   2047,16}, {   4607,15}, \
+    {   9983,16}, {   5631,15}, {  11775,17}, {   3071,16}, \
+    {  65536,17}, { 131072,18}, { 262144,19}, { 524288,20}, \
+    {1048576,21}, {2097152,22}, {4194304,23}, {8388608,24} }
+#define SQR_FFT_TABLE3_SIZE 232
+#define SQR_FFT_THRESHOLD                 2752
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  55
+#define MULLO_MUL_N_THRESHOLD             6633
+#define SQRLO_BASECASE_THRESHOLD             9
+#define SQRLO_DC_THRESHOLD                   0  /* never mpn_sqrlo_basecase */
+#define SQRLO_SQR_THRESHOLD               5397
+
+#define DC_DIV_QR_THRESHOLD                 33
+#define DC_DIVAPPR_Q_THRESHOLD             222
+#define DC_BDIV_QR_THRESHOLD                31
+#define DC_BDIV_Q_THRESHOLD                147
+
+#define INV_MULMOD_BNM1_THRESHOLD           37
+#define INV_NEWTON_THRESHOLD               222
+#define INV_APPR_THRESHOLD                 222
+
+#define BINV_NEWTON_THRESHOLD              212
+#define REDC_1_TO_REDC_2_THRESHOLD          55
+#define REDC_2_TO_REDC_N_THRESHOLD           0  /* always */
+
+#define MU_DIV_QR_THRESHOLD               1142
+#define MU_DIVAPPR_Q_THRESHOLD            1142
+#define MUPI_DIV_QR_THRESHOLD               81
+#define MU_BDIV_QR_THRESHOLD               942
+#define MU_BDIV_Q_THRESHOLD               1043
+
+#define POWM_SEC_TABLE  1,34,102,588,1730
+
+#define GET_STR_DC_THRESHOLD                17
+#define GET_STR_PRECOMPUTE_THRESHOLD        30
+#define SET_STR_DC_THRESHOLD               381
+#define SET_STR_PRECOMPUTE_THRESHOLD      1659
+
+#define FAC_DSC_THRESHOLD                  351
+#define FAC_ODD_THRESHOLD                   27
+
+#define MATRIX22_STRASSEN_THRESHOLD         16
+#define HGCD2_DIV1_METHOD                    3  /* 3.06% faster than 1 */
+#define HGCD_THRESHOLD                     120
+#define HGCD_APPR_THRESHOLD                153
+#define HGCD_REDUCE_THRESHOLD             2121
+#define GCD_DC_THRESHOLD                   416
+#define GCDEXT_DC_THRESHOLD                309
+#define JACOBI_BASE_METHOD                   1  /* 2.28% faster than 3 */
+
+/* Tuneup completed successfully, took 938046 seconds */
diff --git a/third_party/gmp/mpn/x86_64/silvermont/hamdist.asm b/third_party/gmp/mpn/x86_64/silvermont/hamdist.asm
new file mode 100644
index 0000000..848ed01
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/silvermont/hamdist.asm
@@ -0,0 +1,38 @@
+dnl  x86-64 mpn_hamdist.
+
+dnl  Copyright 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_hamdist)
+include_mpn(`x86_64/coreinhm/hamdist.asm')
diff --git a/third_party/gmp/mpn/x86_64/silvermont/lshift.asm b/third_party/gmp/mpn/x86_64/silvermont/lshift.asm
new file mode 100644
index 0000000..acd3180
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/silvermont/lshift.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_lshift optimised for Intel Silvermont.
+
+dnl  Copyright 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_lshift)
+include_mpn(`x86_64/fastsse/lshift-movdqu2.asm')
diff --git a/third_party/gmp/mpn/x86_64/silvermont/lshiftc.asm b/third_party/gmp/mpn/x86_64/silvermont/lshiftc.asm
new file mode 100644
index 0000000..3a68bb5
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/silvermont/lshiftc.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_lshiftc optimised for Intel Silvermont.
+
+dnl  Copyright 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_lshiftc)
+include_mpn(`x86_64/fastsse/lshiftc-movdqu2.asm')
diff --git a/third_party/gmp/mpn/x86_64/silvermont/mul_1.asm b/third_party/gmp/mpn/x86_64/silvermont/mul_1.asm
new file mode 100644
index 0000000..c1e1c94
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/silvermont/mul_1.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_mul_1 optimised for Intel Silvermont.
+
+dnl  Copyright 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_mul_1 mpn_mul_1c)
+include_mpn(`x86_64/bd1/mul_1.asm')
diff --git a/third_party/gmp/mpn/x86_64/silvermont/mul_basecase.asm b/third_party/gmp/mpn/x86_64/silvermont/mul_basecase.asm
new file mode 100644
index 0000000..6228c48
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/silvermont/mul_basecase.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_mul_basecase optimised for Intel Silvermont.
+
+dnl  Copyright 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_mul_basecase)
+include_mpn(`x86_64/k8/mul_basecase.asm')
diff --git a/third_party/gmp/mpn/x86_64/silvermont/mullo_basecase.asm b/third_party/gmp/mpn/x86_64/silvermont/mullo_basecase.asm
new file mode 100644
index 0000000..0244f8a
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/silvermont/mullo_basecase.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_mullo_basecase optimised for Intel Silvermont.
+
+dnl  Copyright 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_mullo_basecase)
+include_mpn(`x86_64/k8/mullo_basecase.asm')
diff --git a/third_party/gmp/mpn/x86_64/silvermont/popcount.asm b/third_party/gmp/mpn/x86_64/silvermont/popcount.asm
new file mode 100644
index 0000000..73eb7b5
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/silvermont/popcount.asm
@@ -0,0 +1,38 @@
+dnl  x86-64 mpn_popcount.
+
+dnl  Copyright 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_popcount)
+include_mpn(`x86_64/coreinhm/popcount.asm')
diff --git a/third_party/gmp/mpn/x86_64/silvermont/rshift.asm b/third_party/gmp/mpn/x86_64/silvermont/rshift.asm
new file mode 100644
index 0000000..b84371c
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/silvermont/rshift.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_rshift optimised for Intel Silvermont.
+
+dnl  Copyright 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_rshift)
+include_mpn(`x86_64/fastsse/rshift-movdqu2.asm')
diff --git a/third_party/gmp/mpn/x86_64/silvermont/sqr_basecase.asm b/third_party/gmp/mpn/x86_64/silvermont/sqr_basecase.asm
new file mode 100644
index 0000000..afccf93
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/silvermont/sqr_basecase.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_sqr_basecase optimised for Intel Silvermont.
+
+dnl  Copyright 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_sqr_basecase)
+include_mpn(`x86_64/k8/sqr_basecase.asm')
diff --git a/third_party/gmp/mpn/x86_64/skylake/gmp-mparam.h b/third_party/gmp/mpn/x86_64/skylake/gmp-mparam.h
new file mode 100644
index 0000000..a899ea1
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/skylake/gmp-mparam.h
@@ -0,0 +1,246 @@
+/* Skylake gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+/* Disable use of slow functions.  FIXME: We should disable lib inclusion.  */
+#undef HAVE_NATIVE_mpn_mul_2
+#undef HAVE_NATIVE_mpn_addmul_2
+
+/* 3600-4000 MHz Intel Xeon E3-1270v5 Skylake */
+/* FFT tuning limit = 465,990,371 */
+/* Generated by tuneup.c, 2019-10-18, gcc 8.3 */
+
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          4
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          3
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        13
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        32
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD      9
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1_NORM_THRESHOLD              1
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD              41
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           20
+
+#define DIV_1_VS_MUL_1_PERCENT             473
+
+#define MUL_TOOM22_THRESHOLD                26
+#define MUL_TOOM33_THRESHOLD                73
+#define MUL_TOOM44_THRESHOLD               208
+#define MUL_TOOM6H_THRESHOLD               300
+#define MUL_TOOM8H_THRESHOLD               406
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      73
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     153
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     137
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     151
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     106
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 32
+#define SQR_TOOM3_THRESHOLD                117
+#define SQR_TOOM4_THRESHOLD                336
+#define SQR_TOOM6_THRESHOLD                426
+#define SQR_TOOM8_THRESHOLD                547
+
+#define MULMID_TOOM42_THRESHOLD             46
+
+#define MULMOD_BNM1_THRESHOLD               15
+#define SQRMOD_BNM1_THRESHOLD               17
+
+#define MUL_FFT_MODF_THRESHOLD             404  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    404, 5}, {     21, 6}, {     11, 5}, {     23, 6}, \
+    {     12, 5}, {     25, 6}, {     28, 7}, {     15, 6}, \
+    {     31, 7}, {     21, 8}, {     11, 7}, {     25, 8}, \
+    {     13, 7}, {     28, 8}, {     15, 7}, {     32, 8}, \
+    {     17, 7}, {     35, 8}, {     19, 7}, {     39, 8}, \
+    {     21, 9}, {     11, 8}, {     23, 7}, {     47, 8}, \
+    {     27, 9}, {     15, 8}, {     35, 9}, {     19, 8}, \
+    {     41, 9}, {     23, 8}, {     49, 9}, {     27,10}, \
+    {     15, 9}, {     39, 8}, {     79, 9}, {     43,10}, \
+    {     23, 9}, {     55,11}, {     15,10}, {     31, 9}, \
+    {     71,10}, {     39, 9}, {     83,10}, {     47, 9}, \
+    {     99,10}, {     55,11}, {     31,10}, {     79,11}, \
+    {     47,10}, {    103,12}, {     31,11}, {     63,10}, \
+    {    135,11}, {     79,10}, {    167,11}, {     95,10}, \
+    {    191, 9}, {    383,10}, {    199,11}, {    111,12}, \
+    {     63,11}, {    127,10}, {    255, 9}, {    511,10}, \
+    {    271, 9}, {    543,11}, {    143,10}, {    287, 9}, \
+    {    575,11}, {    159,12}, {     95,11}, {    191,10}, \
+    {    383,13}, {     63,12}, {    127,11}, {    255,10}, \
+    {    511,11}, {    271,10}, {    543,11}, {    287,10}, \
+    {    575,11}, {    303,12}, {    159,11}, {    319,10}, \
+    {    639,11}, {    335,10}, {    671,11}, {    351,10}, \
+    {    703,12}, {    191,11}, {    383,10}, {    767,11}, \
+    {    415,12}, {    223,11}, {    447,13}, {    127,12}, \
+    {    255,11}, {    543,12}, {    287,11}, {    607,12}, \
+    {    319,11}, {    671,12}, {    351,11}, {    703,13}, \
+    {    191,12}, {    383,11}, {    767,12}, {    415,11}, \
+    {    831,12}, {    479,14}, {    127,13}, {    255,12}, \
+    {    543,11}, {   1087,12}, {    607,13}, {    319,12}, \
+    {    671,11}, {   1343,12}, {    703,13}, {    383,12}, \
+    {    831,13}, {    447,12}, {    959,13}, {    511,12}, \
+    {   1087,13}, {    575,12}, {   1151,13}, {    639,12}, \
+    {   1343,13}, {    703,14}, {    383,13}, {    767,12}, \
+    {   1535,13}, {    831,12}, {   1727,13}, {    959,14}, \
+    {    511,13}, {   1087,12}, {   2175,13}, {   1151,14}, \
+    {    639,13}, {   1343,12}, {   2687,13}, {   1407,14}, \
+    {    767,13}, {   1599,12}, {   3199,13}, {   1663,14}, \
+    {    895,13}, {   1791,15}, {    511,14}, {   1023,13}, \
+    {   2175,14}, {   1151,13}, {   2431,12}, {   4863,14}, \
+    {   1279,13}, {   2687,14}, {   1407,13}, {   2815,15}, \
+    {    767,14}, {   1535,13}, {   3199,14}, {   1663,13}, \
+    {   3455,12}, {   6911,14}, {   1791,16}, {    511,15}, \
+    {   1023,14}, {   2175,13}, {   4351,14}, {   2431,13}, \
+    {   4863,15}, {   1279,14}, {   2943,13}, {   5887,15}, \
+    {   1535,14}, {   3455,13}, {   6911,15}, {   1791,14}, \
+    {   3839,13}, {   7679,16}, {   1023,15}, {   2047,14}, \
+    {   4223,15}, {   2303,14}, {   4863,15}, {   2559,14}, \
+    {   5247,15}, {   2815,14}, {   5887,16}, {   1535,15}, \
+    {   3327,14}, {   6911,15}, {   3839,14}, {   7679,17}, \
+    {   1023,16}, {   2047,15}, {   4351,14}, {   8703,15}, \
+    {   4863,16}, {   2559,15}, {   5887,14}, {  11775,16}, \
+    {   3071,15}, {   6911,16}, {   3583,15}, {   7679,14}, \
+    {  15359,15}, {   7935,17}, {   2047,16}, {   4095,15}, \
+    {   8703,16}, {   4607,15}, {   9983,14}, {  19967,16}, \
+    {   5631,15}, {  11775,17}, {   3071,16}, {  65536,17}, \
+    { 131072,18}, { 262144,19}, { 524288,20}, {1048576,21}, \
+    {2097152,22}, {4194304,23}, {8388608,24} }
+#define MUL_FFT_TABLE3_SIZE 227
+#define MUL_FFT_THRESHOLD                 6272
+
+#define SQR_FFT_MODF_THRESHOLD             400  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    400, 5}, {     25, 6}, {     13, 5}, {     27, 6}, \
+    {     29, 7}, {     15, 6}, {     31, 7}, {     28, 8}, \
+    {     15, 7}, {     32, 8}, {     17, 7}, {     35, 8}, \
+    {     19, 7}, {     39, 8}, {     27, 9}, {     15, 8}, \
+    {     33, 9}, {     19, 8}, {     39, 9}, {     23, 8}, \
+    {     47, 9}, {     27,10}, {     15, 9}, {     39,10}, \
+    {     23, 9}, {     51,11}, {     15,10}, {     31, 9}, \
+    {     67,10}, {     39, 9}, {     79,10}, {     55,11}, \
+    {     31,10}, {     79,11}, {     47,10}, {     95,12}, \
+    {     31,11}, {     63,10}, {    135,11}, {     79,10}, \
+    {    159, 9}, {    319,11}, {     95,12}, {     63,11}, \
+    {    127,10}, {    255, 9}, {    511,10}, {    271,11}, \
+    {    143,10}, {    287, 9}, {    575,10}, {    303,11}, \
+    {    159,10}, {    319,12}, {     95,10}, {    383,13}, \
+    {     63,12}, {    127,11}, {    255,10}, {    511,11}, \
+    {    271,10}, {    543,11}, {    287,10}, {    575,11}, \
+    {    303,10}, {    607,12}, {    159,11}, {    319,10}, \
+    {    639,11}, {    335,10}, {    671,11}, {    351,10}, \
+    {    703,11}, {    367,10}, {    735,11}, {    383,10}, \
+    {    767,11}, {    415,10}, {    831,12}, {    223,11}, \
+    {    479,13}, {    127,12}, {    255,11}, {    543,12}, \
+    {    287,11}, {    607,12}, {    319,11}, {    671,12}, \
+    {    351,11}, {    735,12}, {    383,11}, {    799,12}, \
+    {    415,11}, {    831,12}, {    479,14}, {    127,13}, \
+    {    255,12}, {    511,11}, {   1023,12}, {    607,13}, \
+    {    319,12}, {    735,13}, {    383,12}, {    831,13}, \
+    {    447,12}, {    959,13}, {    511,12}, {   1023,13}, \
+    {    575,12}, {   1151,13}, {    639,12}, {   1279,13}, \
+    {    703,12}, {   1407,14}, {    383,13}, {    767,12}, \
+    {   1535,13}, {    831,12}, {   1727,13}, {    895,12}, \
+    {   1791,13}, {    959,14}, {    511,13}, {   1087,12}, \
+    {   2175,13}, {   1151,14}, {    639,13}, {   1343,12}, \
+    {   2687,13}, {   1407,14}, {    767,13}, {   1599,12}, \
+    {   3199,13}, {   1663,14}, {    895,13}, {   1791,15}, \
+    {    511,14}, {   1023,13}, {   2175,14}, {   1151,13}, \
+    {   2431,12}, {   4863,14}, {   1279,13}, {   2687,14}, \
+    {   1407,15}, {    767,14}, {   1535,13}, {   3199,14}, \
+    {   1663,13}, {   3455,14}, {   1791,16}, {    511,15}, \
+    {   1023,14}, {   2431,13}, {   4863,15}, {   1279,14}, \
+    {   2943,13}, {   5887,15}, {   1535,14}, {   3455,15}, \
+    {   1791,14}, {   3839,16}, {   1023,15}, {   2047,14}, \
+    {   4223,15}, {   2303,14}, {   4863,15}, {   2559,14}, \
+    {   5119,15}, {   2815,14}, {   5887,16}, {   1535,15}, \
+    {   3071,14}, {   6143,15}, {   3327,14}, {   6911,15}, \
+    {   3839,17}, {   1023,16}, {   2047,15}, {   4863,16}, \
+    {   2559,15}, {   5887,14}, {  11775,16}, {   3071,15}, \
+    {   6911,16}, {   3583,15}, {   7679,14}, {  15359,17}, \
+    {   2047,16}, {   4095,15}, {   8191,16}, {   4607,15}, \
+    {   9983,14}, {  19967,16}, {   5631,15}, {  11775,17}, \
+    {   3071,16}, {  65536,17}, { 131072,18}, { 262144,19}, \
+    { 524288,20}, {1048576,21}, {2097152,22}, {4194304,23}, \
+    {8388608,24} }
+#define SQR_FFT_TABLE3_SIZE 205
+#define SQR_FFT_THRESHOLD                 4224
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  79
+#define MULLO_MUL_N_THRESHOLD            11278
+#define SQRLO_BASECASE_THRESHOLD            10
+#define SQRLO_DC_THRESHOLD                 109
+#define SQRLO_SQR_THRESHOLD               8207
+
+#define DC_DIV_QR_THRESHOLD                 55
+#define DC_DIVAPPR_Q_THRESHOLD             179
+#define DC_BDIV_QR_THRESHOLD                82
+#define DC_BDIV_Q_THRESHOLD                166
+
+#define INV_MULMOD_BNM1_THRESHOLD           50
+#define INV_NEWTON_THRESHOLD               170
+#define INV_APPR_THRESHOLD                 171
+
+#define BINV_NEWTON_THRESHOLD              294
+#define REDC_1_TO_REDC_2_THRESHOLD          33
+#define REDC_2_TO_REDC_N_THRESHOLD          59
+
+#define MU_DIV_QR_THRESHOLD               1528
+#define MU_DIVAPPR_Q_THRESHOLD            1589
+#define MUPI_DIV_QR_THRESHOLD               62
+#define MU_BDIV_QR_THRESHOLD              1470
+#define MU_BDIV_Q_THRESHOLD               1597
+
+#define POWM_SEC_TABLE  2,8,191,452,904
+
+#define GET_STR_DC_THRESHOLD                12
+#define GET_STR_PRECOMPUTE_THRESHOLD        19
+#define SET_STR_DC_THRESHOLD               898
+#define SET_STR_PRECOMPUTE_THRESHOLD      1670
+
+#define FAC_DSC_THRESHOLD                  474
+#define FAC_ODD_THRESHOLD                    0  /* always */
+
+#define MATRIX22_STRASSEN_THRESHOLD         16
+#define HGCD2_DIV1_METHOD                    5  /* 3.85% faster than 3 */
+#define HGCD_THRESHOLD                      64
+#define HGCD_APPR_THRESHOLD                 60
+#define HGCD_REDUCE_THRESHOLD             2681
+#define GCD_DC_THRESHOLD                   618
+#define GCDEXT_DC_THRESHOLD                321
+#define JACOBI_BASE_METHOD                   1  /* 12.01% faster than 4 */
+
+/* Tuneup completed successfully, took 213784 seconds */
diff --git a/third_party/gmp/mpn/x86_64/sqr_diag_addlsh1.asm b/third_party/gmp/mpn/x86_64/sqr_diag_addlsh1.asm
new file mode 100644
index 0000000..f486125
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/sqr_diag_addlsh1.asm
@@ -0,0 +1,116 @@
+dnl  AMD64 mpn_sqr_diag_addlsh1
+
+dnl  Contributed to the GNU project by Torbjörn Granlund.
+
+dnl  Copyright 2011-2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 2.5
+C AMD K10	 2.5
+C AMD bull	 3.6
+C AMD pile	 3.6
+C AMD steam	 ?
+C AMD bobcat	 4
+C AMD jaguar	 ?
+C Intel P4	 11.5
+C Intel core	 4
+C Intel NHM	 3.6
+C Intel SBR	 3.15
+C Intel IBR	 3.0
+C Intel HWL	 2.6
+C Intel BWL	 ?
+C Intel atom	14
+C VIA nano	 3.5
+
+C When playing with pointers, set this to $2 to fall back to conservative
+C indexing in wind-down code.
+define(`I',`$1')
+
+define(`rp',     `%rdi')
+define(`tp',     `%rsi')
+define(`up_arg', `%rdx')
+define(`n',      `%rcx')
+
+define(`up',     `%r11')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_sqr_diag_addlsh1)
+	FUNC_ENTRY(4)
+	push	%rbx
+
+	dec	n
+	shl	n
+
+	mov	(up_arg), %rax
+
+	lea	(rp,n,8), rp
+	lea	(tp,n,8), tp
+	lea	(up_arg,n,4), up
+	neg	n
+
+	mul	%rax
+	mov	%rax, (rp,n,8)
+
+	xor	R32(%rbx), R32(%rbx)
+	jmp	L(mid)
+
+	ALIGN(16)
+L(top):	add	%r10, %r8
+	adc	%rax, %r9
+	mov	%r8, -8(rp,n,8)
+	mov	%r9, (rp,n,8)
+L(mid):	mov	8(up,n,4), %rax
+	mov	(tp,n,8), %r8
+	mov	8(tp,n,8), %r9
+	adc	%r8, %r8
+	adc	%r9, %r9
+	lea	(%rdx,%rbx), %r10
+	setc	R8(%rbx)
+	mul	%rax
+	add	$2, n
+	js	L(top)
+
+L(end):	add	%r10, %r8
+	adc	%rax, %r9
+	mov	%r8, I(-8(rp),-8(rp,n,8))
+	mov	%r9, I((rp),(rp,n,8))
+	adc	%rbx, %rdx
+	mov	%rdx, I(8(rp),8(rp,n,8))
+
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/sublsh1_n.asm b/third_party/gmp/mpn/x86_64/sublsh1_n.asm
new file mode 100644
index 0000000..c6d829f
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/sublsh1_n.asm
@@ -0,0 +1,160 @@
+dnl  AMD64 mpn_sublsh1_n -- rp[] = up[] - (vp[] << 1)
+
+dnl  Copyright 2003, 2005-2007, 2011, 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C	     cycles/limb
+C AMD K8,K9	 2.2
+C AMD K10	 2.2
+C Intel P4	12.75
+C Intel core2	 3.45
+C Intel corei	 ?
+C Intel atom	 ?
+C VIA nano	 3.25
+
+C Sometimes speed degenerates, supposedly related to that some operand
+C alignments cause cache conflicts.
+
+C The speed is limited by decoding/issue bandwidth.  There are 26 instructions
+C in the loop, which corresponds to 26/3/4 = 2.167 c/l.
+
+C INPUT PARAMETERS
+define(`rp',`%rdi')
+define(`up',`%rsi')
+define(`vp',`%rdx')
+define(`n', `%rcx')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_sublsh1_n)
+	FUNC_ENTRY(4)
+	push	%rbx
+	push	%rbp
+
+	mov	(vp), %r8
+	mov	R32(n), R32(%rax)
+	lea	(rp,n,8), rp
+	lea	(up,n,8), up
+	lea	(vp,n,8), vp
+	neg	n
+	xor	R32(%rbp), R32(%rbp)
+	and	$3, R32(%rax)
+	je	L(b00)
+	cmp	$2, R32(%rax)
+	jc	L(b01)
+	je	L(b10)
+
+L(b11):	add	%r8, %r8
+	mov	8(vp,n,8), %r9
+	adc	%r9, %r9
+	mov	16(vp,n,8), %r10
+	adc	%r10, %r10
+	sbb	R32(%rax), R32(%rax)	C save scy
+	mov	(up,n,8), %rbp
+	mov	8(up,n,8), %rbx
+	sub	%r8, %rbp
+	sbb	%r9, %rbx
+	mov	%rbp, (rp,n,8)
+	mov	%rbx, 8(rp,n,8)
+	mov	16(up,n,8), %rbp
+	sbb	%r10, %rbp
+	mov	%rbp, 16(rp,n,8)
+	sbb	R32(%rbp), R32(%rbp)	C save acy
+	add	$3, n
+	jmp	L(ent)
+
+L(b10):	add	%r8, %r8
+	mov	8(vp,n,8), %r9
+	adc	%r9, %r9
+	sbb	R32(%rax), R32(%rax)	C save scy
+	mov	(up,n,8), %rbp
+	mov	8(up,n,8), %rbx
+	sub	%r8, %rbp
+	sbb	%r9, %rbx
+	mov	%rbp, (rp,n,8)
+	mov	%rbx, 8(rp,n,8)
+	sbb	R32(%rbp), R32(%rbp)	C save acy
+	add	$2, n
+	jmp	L(ent)
+
+L(b01):	add	%r8, %r8
+	sbb	R32(%rax), R32(%rax)	C save scy
+	mov	(up,n,8), %rbp
+	sub	%r8, %rbp
+	mov	%rbp, (rp,n,8)
+	sbb	R32(%rbp), R32(%rbp)	C save acy
+	inc	n
+L(ent):	jns	L(end)
+
+	ALIGN(16)
+L(top):	add	R32(%rax), R32(%rax)	C restore scy
+
+	mov	(vp,n,8), %r8
+L(b00):	adc	%r8, %r8
+	mov	8(vp,n,8), %r9
+	adc	%r9, %r9
+	mov	16(vp,n,8), %r10
+	adc	%r10, %r10
+	mov	24(vp,n,8), %r11
+	adc	%r11, %r11
+
+	sbb	R32(%rax), R32(%rax)	C save scy
+	add	R32(%rbp), R32(%rbp)	C restore acy
+
+	mov	(up,n,8), %rbp
+	mov	8(up,n,8), %rbx
+	sbb	%r8, %rbp
+	sbb	%r9, %rbx
+	mov	%rbp, (rp,n,8)
+	mov	%rbx, 8(rp,n,8)
+	mov	16(up,n,8), %rbp
+	mov	24(up,n,8), %rbx
+	sbb	%r10, %rbp
+	sbb	%r11, %rbx
+	mov	%rbp, 16(rp,n,8)
+	mov	%rbx, 24(rp,n,8)
+
+	sbb	R32(%rbp), R32(%rbp)	C save acy
+	add	$4, n
+	js	L(top)
+
+L(end):	add	R32(%rbp), R32(%rax)
+	neg	R32(%rax)
+
+	pop	%rbp
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/x86_64-defs.m4 b/third_party/gmp/mpn/x86_64/x86_64-defs.m4
new file mode 100644
index 0000000..64e3729
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/x86_64-defs.m4
@@ -0,0 +1,475 @@
+divert(-1)
+
+dnl  m4 macros for amd64 assembler.
+
+dnl  Copyright 1999-2005, 2008, 2009, 2011-2013, 2017 Free Software Foundation,
+dnl  Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+dnl  Usage: CPUVEC_FUNCS_LIST
+dnl
+dnl  A list of the functions from gmp-impl.h x86 struct cpuvec_t, in the
+dnl  order they appear in that structure.
+
+define(CPUVEC_FUNCS_LIST,
+``add_n',
+`addlsh1_n',
+`addlsh2_n',
+`addmul_1',
+`addmul_2',
+`bdiv_dbm1c',
+`cnd_add_n',
+`cnd_sub_n',
+`com',
+`copyd',
+`copyi',
+`divexact_1',
+`divrem_1',
+`gcd_11',
+`lshift',
+`lshiftc',
+`mod_1',
+`mod_1_1p',
+`mod_1_1p_cps',
+`mod_1s_2p',
+`mod_1s_2p_cps',
+`mod_1s_4p',
+`mod_1s_4p_cps',
+`mod_34lsub1',
+`modexact_1c_odd',
+`mul_1',
+`mul_basecase',
+`mullo_basecase',
+`preinv_divrem_1',
+`preinv_mod_1',
+`redc_1',
+`redc_2',
+`rshift',
+`sqr_basecase',
+`sub_n',
+`sublsh1_n',
+`submul_1'')
+
+
+dnl  Called: PROLOGUE_cpu(GSYM_PREFIX`'foo)
+dnl
+dnl  In the amd64 code we use explicit TEXT and ALIGN() calls in the code,
+dnl  since different alignments are wanted in various circumstances.  So for
+dnl  instance,
+dnl
+dnl                  TEXT
+dnl                  ALIGN(16)
+dnl          PROLOGUE(mpn_add_n)
+dnl                  ...
+dnl          EPILOGUE()
+
+define(`PROLOGUE_cpu',
+m4_assert_numargs(1)
+`	GLOBL	$1
+	TYPE($1,`function')
+$1:
+')
+
+
+dnl  Usage: ASSERT([cond][,instructions])
+dnl
+dnl  If WANT_ASSERT is 1, output the given instructions and expect the given
+dnl  flags condition to then be satisfied.  For example,
+dnl
+dnl         ASSERT(ne, `cmpq %rax, %rbx')
+dnl
+dnl  The instructions can be omitted to just assert a flags condition with
+dnl  no extra calculation.  For example,
+dnl
+dnl         ASSERT(nc)
+dnl
+dnl  When `instructions' is not empty, a pushfq/popfq is added for
+dnl  convenience to preserve the flags, but the instructions themselves must
+dnl  preserve any registers that matter.
+dnl
+dnl  The condition can be omitted to just output the given instructions when
+dnl  assertion checking is wanted.  In this case the pushf/popf is omitted.
+dnl  For example,
+dnl
+dnl         ASSERT(, `movq %rax, VAR_KEEPVAL')
+
+define(ASSERT,
+m4_assert_numargs_range(1,2)
+m4_assert_defined(`WANT_ASSERT')
+`ifelse(WANT_ASSERT,1,
+`ifelse(`$1',,
+`	$2',
+`ifelse(`$2',,,
+`	pushfq')
+	$2
+	`j$1'	L(ASSERT_ok`'ASSERT_counter)
+	ud2	C assertion failed
+L(ASSERT_ok`'ASSERT_counter):
+ifelse(`$2',,,`	popfq')
+define(`ASSERT_counter',incr(ASSERT_counter))')')')
+
+define(ASSERT_counter,1)
+
+dnl LEA - load effective address
+dnl
+dnl FIXME: We should never create a GOT entry and therefore use the simpler 2nd
+dnl variant always. We need to understand what happens for not-yet-hidden
+dnl symbols first.
+dnl
+define(`LEA',`dnl
+ifdef(`PIC',
+	`mov	$1@GOTPCREL(%rip), $2'
+,
+	`lea	$1(%rip), $2')
+')
+
+
+define(`DEF_OBJECT',
+m4_assert_numargs_range(2,3)
+`	ifelse($#,3,`$3',`RODATA')
+	ALIGN($2)
+$1:
+')
+
+define(`END_OBJECT',
+m4_assert_numargs(1)
+`	SIZE(`$1',.-`$1')')
+
+
+define(`R32',
+	`ifelse($1,`%rax',`%eax',
+		$1,`%rbx',`%ebx',
+		$1,`%rcx',`%ecx',
+		$1,`%rdx',`%edx',
+		$1,`%rsi',`%esi',
+		$1,`%rdi',`%edi',
+		$1,`%rbp',`%ebp',
+		$1,`%r8',`%r8d',
+		$1,`%r9',`%r9d',
+		$1,`%r10',`%r10d',
+		$1,`%r11',`%r11d',
+		$1,`%r12',`%r12d',
+		$1,`%r13',`%r13d',
+		$1,`%r14',`%r14d',
+		$1,`%r15',`%r15d')')
+define(`R8',
+	`ifelse($1,`%rax',`%al',
+		$1,`%rbx',`%bl',
+		$1,`%rcx',`%cl',
+		$1,`%rdx',`%dl',
+		$1,`%rsi',`%sil',
+		$1,`%rdi',`%dil',
+		$1,`%rbp',`%bpl',
+		$1,`%r8',`%r8b',
+		$1,`%r9',`%r9b',
+		$1,`%r10',`%r10b',
+		$1,`%r11',`%r11b',
+		$1,`%r12',`%r12b',
+		$1,`%r13',`%r13b',
+		$1,`%r14',`%r14b',
+		$1,`%r15',`%r15b')')
+
+
+dnl  Usage: CALL(funcname)
+dnl
+
+define(`CALL',`dnl
+ifdef(`PIC',
+	`call	GSYM_PREFIX`'$1@PLT'
+,
+	`call	GSYM_PREFIX`'$1'
+)')
+
+define(`TCALL',`dnl
+ifdef(`PIC',
+	`jmp	GSYM_PREFIX`'$1@PLT'
+,
+	`jmp	GSYM_PREFIX`'$1'
+)')
+
+
+define(`JUMPTABSECT', `.section	.data.rel.ro.local,"a",@progbits')
+
+
+dnl  Usage: JMPENT(targlabel,tablabel)
+
+define(`JMPENT',`dnl
+ifdef(`PIC',
+	`.long	$1-$2'dnl
+,
+	`.quad	$1'dnl
+)')
+
+
+dnl  These macros are defined just for DOS64, where they provide calling
+dnl  sequence glue code.
+
+define(`FUNC_ENTRY',`')
+define(`FUNC_EXIT',`')
+
+
+dnl  Target ABI macros.
+
+define(`IFDOS',   `')
+define(`IFSTD',   `$1')
+define(`IFELF',   `$1')
+
+
+dnl  Usage: PROTECT(symbol)
+dnl
+dnl  Used for private GMP symbols that should never be overridden by users.
+dnl  This can save reloc entries and improve shlib sharing as well as
+dnl  application startup times
+
+define(`PROTECT',  `.hidden $1')
+
+
+dnl  Usage: x86_lookup(target, key,value, key,value, ...)
+dnl
+dnl  Look for `target' among the `key' parameters.
+dnl
+dnl  x86_lookup expands to the corresponding `value', or generates an error
+dnl  if `target' isn't found.
+
+define(x86_lookup,
+m4_assert_numargs_range(1,999)
+`ifelse(eval($#<3),1,
+`m4_error(`unrecognised part of x86 instruction: $1
+')',
+`ifelse(`$1',`$2', `$3',
+`x86_lookup(`$1',shift(shift(shift($@))))')')')
+
+
+dnl  Usage: x86_opcode_regxmm(reg)
+dnl
+dnl  Validate the given xmm register, and return its number, 0 to 7.
+
+define(x86_opcode_regxmm,
+m4_assert_numargs(1)
+`x86_lookup(`$1',x86_opcode_regxmm_list)')
+
+define(x86_opcode_regxmm_list,
+``%xmm0',0,
+`%xmm1',1,
+`%xmm2',2,
+`%xmm3',3,
+`%xmm4',4,
+`%xmm5',5,
+`%xmm6',6,
+`%xmm7',7,
+`%xmm8',8,
+`%xmm9',9,
+`%xmm10',10,
+`%xmm11',11,
+`%xmm12',12,
+`%xmm13',13,
+`%xmm14',14,
+`%xmm15',15')
+
+dnl  Usage: palignr($imm,%srcreg,%dstreg)
+dnl
+dnl  Emit a palignr instruction, using a .byte sequence, since obsolete but
+dnl  still distributed versions of gas don't know SSSE3 instructions.
+
+define(`palignr',
+m4_assert_numargs(3)
+`.byte	0x66,dnl
+ifelse(eval(x86_opcode_regxmm($3) >= 8 || x86_opcode_regxmm($2) >= 8),1,
+       `eval(0x40+x86_opcode_regxmm($3)/8*4+x86_opcode_regxmm($2)/8),')dnl
+0x0f,0x3a,0x0f,dnl
+eval(0xc0+x86_opcode_regxmm($3)%8*8+x86_opcode_regxmm($2)%8),dnl
+substr($1,1)')
+
+
+dnl  Usage
+dnl
+dnl    regnum(op)   raw operand index (so slightly misnamed)
+dnl    regnumh(op)  high bit of register operand nimber
+dnl    ix(op)       0 for reg operand, 1 for plain pointer operand.
+dnl
+
+define(`regnum',`x86_lookup(`$1',oplist)')
+define(`regnumh',`eval(regnum($1)/8 & 1)')
+define(`ix',`eval(regnum($1)/16)')
+define(`oplist',
+``%rax',   0, `%rcx',   1, `%rdx',   2,  `%rbx',   3,
+ `%rsp',   4, `%rbp',   5, `%rsi',   6,  `%rdi',   7,
+ `%r8',    8, `%r9',    9, `%r10',  10,  `%r11',  11,
+ `%r12',  12, `%r13',  13, `%r14',  14,  `%r15',  15,
+ `(%rax)',16, `(%rcx)',17, `(%rdx)',18,  `(%rbx)',19,
+ `(%rsp)',20, `(%rbp)',21, `(%rsi)',22,  `(%rdi)',23,
+ `(%r8)', 24, `(%r9)', 25, `(%r10)',26,  `(%r11)',27,
+ `(%r12)',28, `(%r13)',29, `(%r14)',30,  `(%r15)',31')
+
+dnl  Usage (by mulx, shlx, shrx)
+dnl
+dnl     reg1,reg2,reg3,opc1,opc2
+dnl
+dnl  or
+dnl
+dnl     (reg1),reg2,reg3,opc1,opc2
+dnl
+dnl  where reg1 is any register but rsp,rbp,r12,r13, or
+dnl
+dnl  or
+dnl
+dnl     off,(reg1),reg2,reg3,opc1,opc2
+dnl
+dnl  where reg1 is any register but rsp,r12.
+dnl
+dnl  The exceptions are due to special coding needed for some registers; rsp
+dnl  and r12 need an extra byte 0x24 at the end while rbp and r13 lack the
+dnl  offset-less form.
+dnl
+dnl  Other addressing forms are not handled.  Invalid forms are not properly
+dnl  detected.  Offsets that don't fit one byte are not handled correctly.
+
+define(`c4_helper',`dnl
+.byte	0xc4`'dnl
+ifelse(`$#',5,`dnl
+,eval(0xe2^32*regnumh($1)^128*regnumh($3))`'dnl
+,eval(0x$4-8*regnum($2))`'dnl
+,0x$5`'dnl
+,eval(0xc0+(7 & regnum($1))+8*(7 & regnum($3))-0xc0*ix($1))`'dnl
+',`$#',6,`dnl
+,eval(0xe2^32*regnumh($2)^128*regnumh($4))`'dnl
+,eval(0x$5-8*regnum($3))`'dnl
+,0x$6`'dnl
+,eval(0x40+(7 & regnum($2))+8*(7 & regnum($4)))`'dnl
+,eval(($1 + 256) % 256)`'dnl
+')')
+
+
+dnl  Usage
+dnl
+dnl     mulx(reg1,reg2,reg3)
+dnl
+dnl  or
+dnl
+dnl     mulx((reg1),reg2,reg3)
+dnl
+dnl  where reg1 is any register but rsp,rbp,r12,r13, or
+dnl
+dnl     mulx(off,(reg1),reg2,reg3)
+dnl
+dnl  where reg1 is any register but rsp,r12.
+
+define(`mulx',`dnl
+ifelse(`$#',3,`dnl
+c4_helper($1,$2,$3,fb,f6)',`dnl         format 1,2
+c4_helper($1,$2,$3,$4,fb,f6)'dnl	format 3
+)')
+
+
+dnl  Usage
+dnl
+dnl     shlx(reg1,reg2,reg3)
+dnl     shrx(reg1,reg2,reg3)
+dnl
+dnl  or
+dnl
+dnl     shlx(reg1,(reg2),reg3)
+dnl     shrx(reg1,(reg2),reg3)
+dnl
+dnl  where reg2 is any register but rsp,rbp,r12,r13, or
+dnl
+dnl     shlx(reg1,off,(reg2),reg3)
+dnl     shrx(reg1,off,(reg2),reg3)
+dnl
+dnl  where reg2 is any register but rsp,r12.
+
+define(`shlx',`dnl
+ifelse(`$#',3,`dnl
+c4_helper($2,$1,$3,f9,f7)',`dnl         format 1,2
+c4_helper($1,$3,$2,$4,f9,f7)'dnl        format 3
+)')
+
+define(`shrx',`dnl
+ifelse(`$#',3,`dnl
+c4_helper($2,$1,$3,fb,f7)',`dnl         format 1,2
+c4_helper($1,$3,$2,$4,fb,f7)'dnl        format 3
+)')
+
+define(`sarx',`dnl
+ifelse(`$#',3,`dnl
+c4_helper($2,$1,$3,fa,f7)',`dnl         format 1,2
+c4_helper($1,$3,$2,$4,fa,f7)'dnl        format 3
+)')
+
+
+dnl  Usage
+dnl
+dnl     adcx(reg1,reg2)
+dnl     adox(reg1,reg2)
+dnl
+dnl  or
+dnl
+dnl     adcx((reg1),reg2)
+dnl     adox((reg1),reg2)
+dnl
+dnl  where reg1 is any register but rsp,rbp,r12,r13, or
+dnl
+dnl     adcx(off,(reg1),reg2)
+dnl     adox(off,(reg1),reg2)
+dnl
+dnl  where reg1 is any register but rsp,r12.
+dnl
+dnl  The exceptions are due to special coding needed for some registers; rsp
+dnl  and r12 need an extra byte 0x24 at the end while rbp and r13 lack the
+dnl  offset-less form.
+dnl
+dnl  Other addressing forms are not handled.  Invalid forms are not properly
+dnl  detected.  Offsets that don't fit one byte are not handled correctly.
+
+define(`adx_helper',`dnl
+,eval(0x48+regnumh($1)+4*regnumh($2))`'dnl
+,0x0f`'dnl
+,0x38`'dnl
+,0xf6`'dnl
+')
+
+define(`adx',`dnl
+ifelse(`$#',2,`dnl
+adx_helper($1,$2)dnl
+,eval(0xc0+(7 & regnum($1))+8*(7 & regnum($2))-0xc0*ix($1))`'dnl
+',`$#',3,`dnl
+adx_helper($2,$3)dnl
+,eval(0x40+(7 & regnum($2))+8*(7 & regnum($3)))`'dnl
+,eval(($1 + 256) % 256)`'dnl
+')')
+
+define(`adcx',`dnl
+.byte	0x66`'dnl
+adx($@)')
+
+define(`adox',`dnl
+.byte	0xf3`'dnl
+adx($@)')
+
+divert`'dnl
diff --git a/third_party/gmp/mpn/x86_64/zen/aorrlsh1_n.asm b/third_party/gmp/mpn/x86_64/zen/aorrlsh1_n.asm
new file mode 100644
index 0000000..803fa30
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/zen/aorrlsh1_n.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_addlsh1_n, mpn_addlsh1_nc, mpn_rsblsh1_n, mpn_rsblsh1_nc.
+
+dnl  Copyright 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_addlsh1_n mpn_addlsh1_nc mpn_rsblsh1_n mpn_rsblsh1_nc)
+include_mpn(`x86_64/atom/aorrlsh1_n.asm')
diff --git a/third_party/gmp/mpn/x86_64/zen/aorrlsh_n.asm b/third_party/gmp/mpn/x86_64/zen/aorrlsh_n.asm
new file mode 100644
index 0000000..e049b2f
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/zen/aorrlsh_n.asm
@@ -0,0 +1,226 @@
+dnl  AMD64 mpn_addlsh_n, mpn_rsblsh_n.
+
+dnl  Copyright 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C		     cycles/limb
+C AMD K8,K9		n/a
+C AMD K10		n/a
+C AMD bd1		n/a
+C AMD bd2		n/a
+C AMD bd3		n/a
+C AMD bd4		 2.31
+C AMD zen		 1.69
+C AMD bt1		n/a
+C AMD bt2		n/a
+C Intel P4		n/a
+C Intel PNR		n/a
+C Intel NHM		n/a
+C Intel SBR		n/a
+C Intel IBR		n/a
+C Intel HWL		 2.08
+C Intel BWL		 1.78
+C Intel SKL		 1.78
+C Intel atom		n/a
+C Intel SLM		n/a
+C VIA nano		n/a
+
+C TODO
+C  * The loop sustains 4 insns/cycle on zen.
+C  * Perhaps avoid using jrcxz by using dec n + jnz.
+
+define(`rp',	`%rdi')
+define(`up',	`%rsi')
+define(`vp',	`%rdx')
+define(`n',	`%rcx')
+define(`cnt',	`%r8')
+
+define(`tnc',	`%r9')
+
+ifdef(`OPERATION_addlsh_n',`
+  define(ADCSBB,       `adc')
+  define(func, mpn_addlsh_n)
+')
+ifdef(`OPERATION_rsblsh_n',`
+  define(ADCSBB,       `sbb')
+  define(func, mpn_rsblsh_n)
+')
+
+MULFUNC_PROLOGUE(mpn_addlsh_n mpn_rsblsh_n)
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(func)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8d	')
+
+	mov	(vp), %r10
+
+	mov	R32(n), R32(%rax)
+	shr	$3, n
+	xor	R32(tnc), R32(tnc)
+	sub	cnt, tnc
+	and	$7, R32(%rax)
+
+	lea	L(tab)(%rip), %r11
+ifdef(`PIC',`
+	movslq	(%r11,%rax,4), %rax
+	add	%r11, %rax
+	jmp	*%rax
+',`
+	jmp	*(%r11,%rax,8)
+')
+
+L(0):	lea	32(up), up
+	lea	32(vp), vp
+	lea	32(rp), rp
+	xor	R32(%r11), R32(%r11)
+	jmp	L(e0)
+
+L(7):	mov	%r10, %r11
+	lea	24(up), up
+	lea	24(vp), vp
+	lea	24(rp), rp
+	xor	R32(%r10), R32(%r10)
+	jmp	L(e7)
+
+L(6):	lea	16(up), up
+	lea	16(vp), vp
+	lea	16(rp), rp
+	xor	R32(%r11), R32(%r11)
+	jmp	L(e6)
+
+L(5):	mov	%r10, %r11
+	lea	8(up), up
+	lea	8(vp), vp
+	lea	8(rp), rp
+	xor	R32(%r10), R32(%r10)
+	jmp	L(e5)
+
+L(end):	ADCSBB	24(up), %rax
+	mov	%rax, -40(rp)
+	shrx(	tnc, %r11, %rax)
+	ADCSBB	n, %rax
+	FUNC_EXIT()
+	ret
+
+	ALIGN(32)
+L(top):	jrcxz	L(end)
+	mov	-32(vp), %r10
+	ADCSBB	24(up), %rax
+	lea	64(up), up
+	shrx(	tnc, %r11, %r11)
+	mov	%rax, -40(rp)
+L(e0):	dec	n
+	shlx(	cnt, %r10, %rax)
+	lea	(%r11,%rax), %rax
+	mov	-24(vp), %r11
+	ADCSBB	-32(up), %rax
+	shrx(	tnc, %r10, %r10)
+	mov	%rax, -32(rp)
+L(e7):	shlx(	cnt, %r11, %rax)
+	lea	(%r10,%rax), %rax
+	mov	-16(vp), %r10
+	ADCSBB	-24(up), %rax
+	shrx(	tnc, %r11, %r11)
+	mov	%rax, -24(rp)
+L(e6):	shlx(	cnt, %r10, %rax)
+	lea	(%r11,%rax), %rax
+	mov	-8(vp), %r11
+	ADCSBB	-16(up), %rax
+	shrx(	tnc, %r10, %r10)
+	mov	%rax, -16(rp)
+L(e5):	shlx(	cnt, %r11, %rax)
+	lea	(%r10,%rax), %rax
+	mov	(vp), %r10
+	ADCSBB	-8(up), %rax
+	shrx(	tnc, %r11, %r11)
+	mov	%rax, -8(rp)
+L(e4):	shlx(	cnt, %r10, %rax)
+	lea	(%r11,%rax), %rax
+	mov	8(vp), %r11
+	ADCSBB	(up), %rax
+	shrx(	tnc, %r10, %r10)
+	mov	%rax, (rp)
+L(e3):	shlx(	cnt, %r11, %rax)
+	lea	(%r10,%rax), %rax
+	mov	16(vp), %r10
+	ADCSBB	8(up), %rax
+	shrx(	tnc, %r11, %r11)
+	mov	%rax, 8(rp)
+L(e2):	shlx(	cnt, %r10, %rax)
+	lea	(%r11,%rax), %rax
+	mov	24(vp), %r11
+	ADCSBB	16(up), %rax
+	lea	64(vp), vp
+	shrx(	tnc, %r10, %r10)
+	mov	%rax, 16(rp)
+	lea	64(rp), rp
+L(e1):	shlx(	cnt, %r11, %rax)
+	lea	(%r10,%rax), %rax
+	jmp	L(top)
+
+L(4):	xor	R32(%r11), R32(%r11)
+	jmp	L(e4)
+
+L(3):	mov	%r10, %r11
+	lea	-8(up), up
+	lea	-8(vp), vp
+	lea	-8(rp), rp
+	xor	R32(%r10), R32(%r10)
+	jmp	L(e3)
+
+L(2):	lea	-16(up), up
+	lea	-16(vp), vp
+	lea	-16(rp), rp
+	xor	R32(%r11), R32(%r11)
+	jmp	L(e2)
+
+L(1):	mov	%r10, %r11
+	lea	-24(up), up
+	lea	40(vp), vp
+	lea	40(rp), rp
+	xor	R32(%r10), R32(%r10)
+	jmp	L(e1)
+EPILOGUE()
+	JUMPTABSECT
+	ALIGN(8)
+L(tab):	JMPENT(	L(0), L(tab))
+	JMPENT(	L(1), L(tab))
+	JMPENT(	L(2), L(tab))
+	JMPENT(	L(3), L(tab))
+	JMPENT(	L(4), L(tab))
+	JMPENT(	L(5), L(tab))
+	JMPENT(	L(6), L(tab))
+	JMPENT(	L(7), L(tab))
diff --git a/third_party/gmp/mpn/x86_64/zen/aorsmul_1.asm b/third_party/gmp/mpn/x86_64/zen/aorsmul_1.asm
new file mode 100644
index 0000000..89795e3
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/zen/aorsmul_1.asm
@@ -0,0 +1,165 @@
+dnl  AMD64 mpn_addmul_1 and mpn_submul_1 for CPUs with mulx.
+
+dnl  Copyright 2012, 2013, 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 -
+C AMD K10	 -
+C AMD bd1	 -
+C AMD bd2	 -
+C AMD bd3	 -
+C AMD bd4	 4.3
+C AMD zen	 2
+C AMD bt1	 -
+C AMD bt2	 -
+C Intel P4	 -
+C Intel PNR	 -
+C Intel NHM	 -
+C Intel SBR	 -
+C Intel IBR	 -
+C Intel HWL	 ?
+C Intel BWL	 ?
+C Intel SKL	 ?
+C Intel atom	 -
+C Intel SLM	 -
+C VIA nano	 -
+
+define(`rp',      `%rdi')   C rcx
+define(`up',      `%rsi')   C rdx
+define(`n_param', `%rdx')   C r8
+define(`v0_param',`%rcx')   C r9
+
+define(`n',       `%rcx')
+define(`v0',      `%rdx')
+
+ifdef(`OPERATION_addmul_1',`
+      define(`ADDSUB',        `add')
+      define(`ADCSBB',        `adc')
+      define(`func',  `mpn_addmul_1')
+')
+ifdef(`OPERATION_submul_1',`
+      define(`ADDSUB',        `sub')
+      define(`ADCSBB',        `sbb')
+      define(`func',  `mpn_submul_1')
+')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_addmul_1 mpn_submul_1)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(func)
+	FUNC_ENTRY(4)
+	mov	(up), %r8
+
+	push	%rbx
+	push	%r12
+	push	%r13
+
+	lea	(up,n_param,8), up
+	lea	-32(rp,n_param,8), rp
+	mov	R32(n_param), R32(%rax)
+	xchg	v0_param, v0		C FIXME: is this insn fast?
+
+	neg	n
+
+	and	$3, R8(%rax)
+	jz	L(b0)
+	cmp	$2, R8(%rax)
+	jz	L(b2)
+	jg	L(b3)
+
+L(b1):	mulx(	%r8, %rbx, %rax)
+	sub	$-1, n
+	jz	L(wd1)
+	.byte	0xc4,0x62,0xb3,0xf6,0x04,0xce		C mulx (up,n,8), %r9, %r8
+	.byte	0xc4,0x62,0xa3,0xf6,0x54,0xce,0x08	C mulx 8(up,n,8), %r11, %r10
+	test	R32(%rax), R32(%rax)		C clear cy
+	jmp	L(lo1)
+
+L(b0):	mulx(	%r8, %r9, %r8)
+	.byte	0xc4,0x62,0xa3,0xf6,0x54,0xce,0x08	C mulx 8(up,n,8), %r11, %r10
+	.byte	0xc4,0x62,0x93,0xf6,0x64,0xce,0x10	C mulx 16(up,n,8), %r13, %r12
+	xor	R32(%rax), R32(%rax)
+	jmp	L(lo0)
+
+L(b3):	mulx(	%r8, %r11, %r10)
+	.byte	0xc4,0x62,0x93,0xf6,0x64,0xce,0x08	C mulx 8(up,n,8), %r13, %r12
+	.byte	0xc4,0xe2,0xe3,0xf6,0x44,0xce,0x10	C mulx 16(up,n,8), %rbx, %rax
+	add	%r10, %r13
+	adc	%r12, %rbx
+	adc	$0, %rax
+	sub	$-3, n
+	jz	L(wd3)
+	test	R32(%rax), R32(%rax)		C clear cy
+	jmp	L(lo3)
+
+L(b2):	mulx(	%r8, %r13, %r12)
+	.byte	0xc4,0xe2,0xe3,0xf6,0x44,0xce,0x08	C mulx 8(up,n,8), %rbx, %rax
+	add	%r12, %rbx
+	adc	$0, %rax
+	sub	$-2, n
+	jz	L(wd2)
+	.byte	0xc4,0x62,0xb3,0xf6,0x04,0xce		C mulx (up,n,8), %r9, %r8
+	test	R32(%rax), R32(%rax)		C clear cy
+	jmp	L(lo2)
+
+L(top):	ADDSUB	%r9, (rp,n,8)
+L(lo3):	.byte	0xc4,0x62,0xb3,0xf6,0x04,0xce		C mulx (up,n,8), %r9, %r8
+	ADCSBB	%r11, 8(rp,n,8)
+L(lo2):	.byte	0xc4,0x62,0xa3,0xf6,0x54,0xce,0x08	C mulx 8(up,n,8), %r11, %r10
+	ADCSBB	%r13, 16(rp,n,8)
+L(lo1):	.byte	0xc4,0x62,0x93,0xf6,0x64,0xce,0x10	C mulx 16(up,n,8), %r13, %r12
+	ADCSBB	%rbx, 24(rp,n,8)
+	adc	%rax, %r9
+L(lo0):	.byte	0xc4,0xe2,0xe3,0xf6,0x44,0xce,0x18	C mulx 24(up,n,8), %rbx, %rax
+	adc	%r8, %r11
+	adc	%r10, %r13
+	adc	%r12, %rbx
+	adc	$0, %rax		C rax = carry limb
+	add	$4, n
+	js	L(top)
+
+L(end):	ADDSUB	%r9, (rp)
+L(wd3):	ADCSBB	%r11, 8(rp)
+L(wd2):	ADCSBB	%r13, 16(rp)
+L(wd1):	ADCSBB	%rbx, 24(rp)
+	adc	n, %rax
+	pop	%r13
+	pop	%r12
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86_64/zen/com.asm b/third_party/gmp/mpn/x86_64/zen/com.asm
new file mode 100644
index 0000000..b34f841
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/zen/com.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_com optimised for AMD Zen.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_com)
+include_mpn(`x86_64/fastsse/com.asm')
diff --git a/third_party/gmp/mpn/x86_64/zen/copyd.asm b/third_party/gmp/mpn/x86_64/zen/copyd.asm
new file mode 100644
index 0000000..63ed237
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/zen/copyd.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_copyd optimised for AMD Zen.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_copyd)
+include_mpn(`x86_64/fastsse/copyd.asm')
diff --git a/third_party/gmp/mpn/x86_64/zen/copyi.asm b/third_party/gmp/mpn/x86_64/zen/copyi.asm
new file mode 100644
index 0000000..1aafaaa
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/zen/copyi.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_copyi optimised for AMD Zen.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_copyi)
+include_mpn(`x86_64/fastsse/copyi.asm')
diff --git a/third_party/gmp/mpn/x86_64/zen/gcd_11.asm b/third_party/gmp/mpn/x86_64/zen/gcd_11.asm
new file mode 100644
index 0000000..0ffb6ca
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/zen/gcd_11.asm
@@ -0,0 +1,37 @@
+dnl  AMD64 mpn_gcd_11.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_gcd_11)
+include_mpn(`x86_64/bd2/gcd_11.asm')
diff --git a/third_party/gmp/mpn/x86_64/zen/gcd_22.asm b/third_party/gmp/mpn/x86_64/zen/gcd_22.asm
new file mode 100644
index 0000000..5dfd9e3
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/zen/gcd_22.asm
@@ -0,0 +1,37 @@
+dnl  AMD64 mpn_gcd_22.
+
+dnl  Copyright 2019 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+dnl ABI_SUPPORT(DOS64)	C returns mp_double_limb_t in memory
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_gcd_22)
+include_mpn(`x86_64/coreihwl/gcd_22.asm')
diff --git a/third_party/gmp/mpn/x86_64/zen/gmp-mparam.h b/third_party/gmp/mpn/x86_64/zen/gmp-mparam.h
new file mode 100644
index 0000000..05a12b3
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/zen/gmp-mparam.h
@@ -0,0 +1,280 @@
+/* AMD Zen gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+/* Disable use of slow functions.  FIXME: We should disable lib inclusion.  */
+#undef HAVE_NATIVE_mpn_mul_2
+#undef HAVE_NATIVE_mpn_addmul_2
+
+/* 3700-4300 MHz Pinnacle Ridge */
+/* FFT tuning limit = 468,514,360 */
+/* Generated by tuneup.c, 2019-10-18, gcc 8.3 */
+
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          4
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          3
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD        13
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        18
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD      9
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1_NORM_THRESHOLD              1
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD              32
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           22
+
+#define DIV_1_VS_MUL_1_PERCENT             338
+
+#define MUL_TOOM22_THRESHOLD                16
+#define MUL_TOOM33_THRESHOLD               107
+#define MUL_TOOM44_THRESHOLD               190
+#define MUL_TOOM6H_THRESHOLD               230
+#define MUL_TOOM8H_THRESHOLD               272
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD      97
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     110
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     106
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     117
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     136
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 32
+#define SQR_TOOM3_THRESHOLD                114
+#define SQR_TOOM4_THRESHOLD                422
+#define SQR_TOOM6_THRESHOLD                  0  /* always */
+#define SQR_TOOM8_THRESHOLD                  0  /* always */
+
+#define MULMID_TOOM42_THRESHOLD             40
+
+#define MULMOD_BNM1_THRESHOLD               12
+#define SQRMOD_BNM1_THRESHOLD               17
+
+#define MUL_FFT_MODF_THRESHOLD             540  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    540, 5}, {     22, 6}, {     12, 5}, {     25, 6}, \
+    {     25, 7}, {     13, 6}, {     29, 7}, {     15, 6}, \
+    {     31, 7}, {     21, 8}, {     11, 7}, {     25, 8}, \
+    {     13, 7}, {     29, 8}, {     15, 7}, {     32, 8}, \
+    {     17, 7}, {     35, 8}, {     19, 7}, {     39, 8}, \
+    {     21, 7}, {     43, 9}, {     11, 8}, {     29, 9}, \
+    {     15, 8}, {     35, 9}, {     19, 8}, {     43, 9}, \
+    {     23, 8}, {     49, 9}, {     27,10}, {     15, 9}, \
+    {     31, 8}, {     63, 9}, {     43,10}, {     23, 9}, \
+    {     55,11}, {     15,10}, {     31, 9}, {     67,10}, \
+    {     39, 9}, {     83,10}, {     47, 9}, {     99,10}, \
+    {     55,11}, {     31,10}, {     79,11}, {     47,10}, \
+    {    103,12}, {     31,11}, {     63,10}, {    135,11}, \
+    {     79,10}, {    167,11}, {     95,10}, {    191,12}, \
+    {     63,11}, {    159,12}, {     95,11}, {    191,13}, \
+    {     63,12}, {    127,11}, {    255,10}, {    511,11}, \
+    {    271,10}, {    543,11}, {    287,12}, {    159,11}, \
+    {    319,10}, {    639,11}, {    335,10}, {    671, 9}, \
+    {   1343,11}, {    351,12}, {    191,11}, {    383,10}, \
+    {    767,11}, {    415,10}, {    831,12}, {    223,11}, \
+    {    447,13}, {    127,12}, {    255,11}, {    543,10}, \
+    {   1087,12}, {    287,11}, {    575,10}, {   1151,11}, \
+    {    607,10}, {   1215,12}, {    319,11}, {    639,10}, \
+    {   1279,11}, {    671,10}, {   1343, 9}, {   2687,12}, \
+    {    351,11}, {    703,13}, {    191,12}, {    383,11}, \
+    {    767,12}, {    415,11}, {    831,10}, {   1663,12}, \
+    {    447,14}, {    127,13}, {    255,12}, {    511,11}, \
+    {   1023,12}, {    543,11}, {   1087,12}, {    575,11}, \
+    {   1151,12}, {    607,11}, {   1215,13}, {    319,12}, \
+    {    639,11}, {   1279,12}, {    671,11}, {   1343,10}, \
+    {   2687,12}, {    703,11}, {   1407,13}, {    383,12}, \
+    {    799,11}, {   1599,12}, {    831,11}, {   1663,13}, \
+    {    447,12}, {    895,11}, {   1791,12}, {    927,11}, \
+    {   1855,12}, {    959,11}, {   1919,10}, {   3839,13}, \
+    {    511,12}, {   1087,11}, {   2175,13}, {    575,12}, \
+    {   1215,11}, {   2431,13}, {    639,12}, {   1343,11}, \
+    {   2687,13}, {    703,12}, {   1407,14}, {    383,13}, \
+    {    767,12}, {   1599,13}, {    831,12}, {   1727,11}, \
+    {   3455,13}, {    895,12}, {   1855,13}, {    959,12}, \
+    {   1919,11}, {   3839,14}, {    511,13}, {   1087,12}, \
+    {   2175,13}, {   1215,12}, {   2431,14}, {    639,13}, \
+    {   1343,12}, {   2687,13}, {   1471,12}, {   2943,14}, \
+    {    767,13}, {   1599,12}, {   3199,13}, {   1727,12}, \
+    {   3455,14}, {    895,13}, {   1855,12}, {   3711,13}, \
+    {   1919,15}, {    511,14}, {   1023,13}, {   2175,14}, \
+    {   1151,13}, {   2431,12}, {   4863,14}, {   1279,13}, \
+    {   2687,14}, {   1407,13}, {   2815,15}, {    767,14}, \
+    {   1535,13}, {   3199,14}, {   1663,13}, {   3455,12}, \
+    {   6911,14}, {   1791,13}, {   3583,14}, {   1919,16}, \
+    {    511,15}, {   1023,14}, {   2175,13}, {   4479,14}, \
+    {   2431,13}, {   4863,15}, {   1279,14}, {   2687,13}, \
+    {   5375,14}, {   2943,13}, {   5887,15}, {   1535,14}, \
+    {   3455,13}, {   6911,15}, {   1791,14}, {   3839,13}, \
+    {   7679,16}, {   1023,15}, {   2047,14}, {   4479,15}, \
+    {   2303,14}, {   4991,15}, {   2559,14}, {   5247,15}, \
+    {   2815,14}, {   5887,16}, {   1535,15}, {   3327,14}, \
+    {   6911,15}, {   3839,14}, {   7679,17}, {   1023,16}, \
+    {   2047,15}, {   4095,14}, {   8191,15}, {   4351,14}, \
+    {   8959,15}, {   4863,16}, {   2559,15}, {   5375,14}, \
+    {  11007,15}, {   5887,14}, {  11775,16}, {   3071,15}, \
+    {   6911,16}, {   3583,15}, {   7167,14}, {  14335,15}, \
+    {   7679,14}, {  15359,15}, {   7935,14}, {  15871,17}, \
+    {   2047,16}, {   4095,15}, {   8959,16}, {   4607,15}, \
+    {   9215,14}, {  18431,15}, {   9727,14}, {  19455,15}, \
+    {   9983,14}, {  19967,16}, {   5119,15}, {  11007,16}, \
+    {   5631,15}, {  11775,17}, {   3071,16}, {  65536,17}, \
+    { 131072,18}, { 262144,19}, { 524288,20}, {1048576,21}, \
+    {2097152,22}, {4194304,23}, {8388608,24} }
+#define MUL_FFT_TABLE3_SIZE 271
+#define MUL_FFT_THRESHOLD                 6272
+
+#define SQR_FFT_MODF_THRESHOLD             404  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    404, 5}, {     13, 4}, {     27, 5}, {     21, 6}, \
+    {     11, 5}, {     25, 6}, {     13, 5}, {     27, 6}, \
+    {     14, 5}, {     29, 6}, {     29, 7}, {     15, 6}, \
+    {     31, 7}, {     17, 6}, {     35, 7}, {     25, 8}, \
+    {     13, 7}, {     29, 8}, {     15, 7}, {     33, 8}, \
+    {     17, 7}, {     35, 8}, {     19, 7}, {     39, 8}, \
+    {     29, 9}, {     15, 8}, {     35, 9}, {     19, 8}, \
+    {     41, 9}, {     23, 8}, {     49, 9}, {     27,10}, \
+    {     15, 9}, {     31, 8}, {     63, 9}, {     43,10}, \
+    {     23, 9}, {     51,11}, {     15,10}, {     31, 9}, \
+    {     67,10}, {     39, 9}, {     79,10}, {     47, 9}, \
+    {     95,10}, {     55,11}, {     31,10}, {     79,11}, \
+    {     47,10}, {     95,12}, {     31,11}, {     63,10}, \
+    {    135,11}, {     79,10}, {    159,11}, {     95,12}, \
+    {     63,11}, {    127,10}, {    255, 9}, {    511,11}, \
+    {    143,10}, {    287, 9}, {    575,11}, {    159,12}, \
+    {     95,11}, {    191,13}, {     63,12}, {    127,11}, \
+    {    255,10}, {    511,11}, {    271,10}, {    543,11}, \
+    {    287,10}, {    575,11}, {    303,12}, {    159,11}, \
+    {    319,10}, {    639,11}, {    335,10}, {    671, 9}, \
+    {   1343,11}, {    351,10}, {    703,11}, {    367,10}, \
+    {    735,12}, {    191,11}, {    383,10}, {    767,11}, \
+    {    399,10}, {    799,11}, {    415,10}, {    831,12}, \
+    {    223,11}, {    447,10}, {    895,13}, {    127,12}, \
+    {    255,11}, {    511,10}, {   1023,11}, {    543,10}, \
+    {   1087,12}, {    287,11}, {    575,10}, {   1151,11}, \
+    {    607,10}, {   1215,12}, {    319,11}, {    639,10}, \
+    {   1279,11}, {    671,10}, {   1343,12}, {    351,11}, \
+    {    703,10}, {   1407,11}, {    735,10}, {   1471,13}, \
+    {    191,12}, {    383,11}, {    767,10}, {   1535,11}, \
+    {    799,12}, {    415,11}, {    831,10}, {   1663,12}, \
+    {    447,11}, {    895,14}, {    127,13}, {    255,12}, \
+    {    511,11}, {   1023,12}, {    543,11}, {   1087,12}, \
+    {    575,11}, {   1151,12}, {    607,11}, {   1215,13}, \
+    {    319,12}, {    639,11}, {   1279,12}, {    671,11}, \
+    {   1343,12}, {    703,11}, {   1407,12}, {    735,11}, \
+    {   1471,13}, {    383,12}, {    767,11}, {   1535,12}, \
+    {    799,11}, {   1599,12}, {    831,11}, {   1663,13}, \
+    {    447,12}, {    895,11}, {   1791,12}, {    959,14}, \
+    {    255,13}, {    511,12}, {   1023,11}, {   2047,12}, \
+    {   1087,11}, {   2175,13}, {    575,12}, {   1215,11}, \
+    {   2431,13}, {    639,12}, {   1343,13}, {    703,12}, \
+    {   1471,11}, {   2943,14}, {    383,13}, {    767,12}, \
+    {   1599,13}, {    831,12}, {   1727,11}, {   3455,13}, \
+    {    895,12}, {   1855,13}, {    959,15}, {    255,14}, \
+    {    511,13}, {   1023,12}, {   2047,13}, {   1087,12}, \
+    {   2175,13}, {   1215,12}, {   2431,14}, {    639,13}, \
+    {   1343,12}, {   2687,13}, {   1471,12}, {   2943,14}, \
+    {    767,13}, {   1599,12}, {   3199,13}, {   1727,12}, \
+    {   3455,14}, {    895,13}, {   1855,12}, {   3711,13}, \
+    {   1919,15}, {    511,14}, {   1023,13}, {   2175,14}, \
+    {   1151,13}, {   2431,12}, {   4863,14}, {   1279,13}, \
+    {   2687,14}, {   1407,13}, {   2943,15}, {    767,14}, \
+    {   1535,13}, {   3199,14}, {   1663,13}, {   3455,12}, \
+    {   6911,14}, {   1791,13}, {   3583,14}, {   1919,16}, \
+    {    511,15}, {   1023,14}, {   2047,13}, {   4095,14}, \
+    {   2175,13}, {   4479,12}, {   8959,14}, {   2431,13}, \
+    {   4863,15}, {   1279,14}, {   2943,13}, {   5887,12}, \
+    {  11775,15}, {   1535,14}, {   3455,13}, {   6911,15}, \
+    {   1791,14}, {   3839,13}, {   7679,14}, {   3967,16}, \
+    {   1023,15}, {   2047,14}, {   4479,15}, {   2303,14}, \
+    {   4991,15}, {   2559,14}, {   5247,15}, {   2815,14}, \
+    {   5887,13}, {  11775,16}, {   1535,15}, {   3071,14}, \
+    {   6143,15}, {   3327,14}, {   6911,15}, {   3839,14}, \
+    {   7679,17}, {   1023,16}, {   2047,15}, {   4095,14}, \
+    {   8191,15}, {   4351,14}, {   8959,15}, {   4863,14}, \
+    {   9727,16}, {   2559,15}, {   5887,14}, {  11775,16}, \
+    {   3071,15}, {   6911,16}, {   3583,15}, {   7167,14}, \
+    {  14335,15}, {   7679,14}, {  15359,15}, {   7935,14}, \
+    {  15871,17}, {   2047,16}, {   4095,15}, {   8959,16}, \
+    {   4607,15}, {   9215,14}, {  18431,15}, {   9727,14}, \
+    {  19455,15}, {   9983,14}, {  19967,16}, {   5119,15}, \
+    {  10239,16}, {   5631,15}, {  11775,17}, {   3071,16}, \
+    {   6655,15}, {  13311,16}, {  65536,17}, { 131072,18}, \
+    { 262144,19}, { 524288,20}, {1048576,21}, {2097152,22}, \
+    {4194304,23}, {8388608,24} }
+#define SQR_FFT_TABLE3_SIZE 302
+#define SQR_FFT_THRESHOLD                 4224
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  69
+#define MULLO_MUL_N_THRESHOLD            11278
+#define SQRLO_BASECASE_THRESHOLD            12
+#define SQRLO_DC_THRESHOLD                  82
+#define SQRLO_SQR_THRESHOLD               8207
+
+#define DC_DIV_QR_THRESHOLD                 76
+#define DC_DIVAPPR_Q_THRESHOLD             232
+#define DC_BDIV_QR_THRESHOLD                76
+#define DC_BDIV_Q_THRESHOLD                104
+
+#define INV_MULMOD_BNM1_THRESHOLD           37
+#define INV_NEWTON_THRESHOLD               274
+#define INV_APPR_THRESHOLD                 230
+
+#define BINV_NEWTON_THRESHOLD              372
+#define REDC_1_TO_REDC_N_THRESHOLD          68
+
+#define MU_DIV_QR_THRESHOLD               1499
+#define MU_DIVAPPR_Q_THRESHOLD            1718
+#define MUPI_DIV_QR_THRESHOLD              108
+#define MU_BDIV_QR_THRESHOLD              1470
+#define MU_BDIV_Q_THRESHOLD               1787
+
+#define POWM_SEC_TABLE  3,22,81,494
+
+#define GET_STR_DC_THRESHOLD                12
+#define GET_STR_PRECOMPUTE_THRESHOLD        20
+#define SET_STR_DC_THRESHOLD               486
+#define SET_STR_PRECOMPUTE_THRESHOLD      1264
+
+#define FAC_DSC_THRESHOLD                  187
+#define FAC_ODD_THRESHOLD                    0  /* always */
+
+#define MATRIX22_STRASSEN_THRESHOLD         23
+#define HGCD2_DIV1_METHOD                    1  /* 9.20% faster than 3 */
+#define HGCD_THRESHOLD                     109
+#define HGCD_APPR_THRESHOLD                104
+#define HGCD_REDUCE_THRESHOLD             3014
+#define GCD_DC_THRESHOLD                   566
+#define GCDEXT_DC_THRESHOLD                382
+#define JACOBI_BASE_METHOD                   1  /* 15.55% faster than 3 */
+
+/* Tuneup completed successfully, took 281243 seconds */
diff --git a/third_party/gmp/mpn/x86_64/zen/hamdist.asm b/third_party/gmp/mpn/x86_64/zen/hamdist.asm
new file mode 100644
index 0000000..48dcf61
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/zen/hamdist.asm
@@ -0,0 +1,38 @@
+dnl  AMD64 mpn_hamdist -- hamming distance.
+
+dnl  Copyright 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_hamdist)
+include_mpn(`x86_64/coreinhm/hamdist.asm')
diff --git a/third_party/gmp/mpn/x86_64/zen/lshift.asm b/third_party/gmp/mpn/x86_64/zen/lshift.asm
new file mode 100644
index 0000000..4dce319
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/zen/lshift.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_lshift optimised for AMD Zen.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_lshift)
+include_mpn(`x86_64/fastsse/lshift-movdqu2.asm')
diff --git a/third_party/gmp/mpn/x86_64/zen/lshiftc.asm b/third_party/gmp/mpn/x86_64/zen/lshiftc.asm
new file mode 100644
index 0000000..d52b194
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/zen/lshiftc.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_lshiftc optimised for AMD Zen.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_lshiftc)
+include_mpn(`x86_64/fastsse/lshiftc-movdqu2.asm')
diff --git a/third_party/gmp/mpn/x86_64/zen/mul_1.asm b/third_party/gmp/mpn/x86_64/zen/mul_1.asm
new file mode 100644
index 0000000..6a083ac
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/zen/mul_1.asm
@@ -0,0 +1,161 @@
+dnl  AMD64 mpn_mul_1 for CPUs with mulx.
+
+dnl  Copyright 2012, 2013, 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C	     cycles/limb
+C AMD K8,K9	 -
+C AMD K10	 -
+C AMD bd1	 -
+C AMD bd2	 -
+C AMD bd3	 -
+C AMD bd4	 4.4
+C AMD zen	 2
+C AMD bobcat	 -
+C AMD jaguar	 -
+C Intel P4	 -
+C Intel PNR	 -
+C Intel NHM	 -
+C Intel SBR	 -
+C Intel IBR	 -
+C Intel HWL	 ?
+C Intel BWL	 ?
+C Intel SKL	 ?
+C Intel atom	 -
+C Intel SLM      -
+C VIA nano	 -
+
+define(`rp',      `%rdi')   C rcx
+define(`up',      `%rsi')   C rdx
+define(`n_param', `%rdx')   C r8
+define(`v0_param',`%rcx')   C r9
+
+define(`n',       `%rcx')
+define(`v0',      `%rdx')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_mul_1c)
+	FUNC_ENTRY(4)
+IFDOS(` mov	56(%rsp), %r8	')
+	jmp	L(ent)
+EPILOGUE()
+	ALIGN(16)
+PROLOGUE(mpn_mul_1)
+	FUNC_ENTRY(4)
+	xor	R32(%r8), R32(%r8)	C carry-in limb
+L(ent):	mov	(up), %r9
+
+	push	%rbx
+	push	%r12
+	push	%r13
+
+	lea	(up,n_param,8), up
+	lea	-32(rp,n_param,8), rp
+	mov	R32(n_param), R32(%rax)
+	xchg	v0_param, v0		C FIXME: is this insn fast?
+
+	neg	n
+
+	and	$3, R8(%rax)
+	jz	L(b0)
+	cmp	$2, R8(%rax)
+	jz	L(b2)
+	jg	L(b3)
+
+L(b1):	mov	%r8, %r12
+	mulx(	%r9, %rbx, %rax)
+	sub	$-1, n
+	jz	L(wd1)
+	.byte	0xc4,0x62,0xb3,0xf6,0x04,0xce		C mulx (up,n,8), %r9, %r8
+	.byte	0xc4,0x62,0xa3,0xf6,0x54,0xce,0x08	C mulx 8(up,n,8), %r11, %r10
+	add	%r12, %rbx
+	jmp	L(lo1)
+
+L(b3):	mulx(	%r9, %r11, %r10)
+	.byte	0xc4,0x62,0x93,0xf6,0x64,0xce,0x08	C mulx 8(up,n,8), %r13, %r12
+	.byte	0xc4,0xe2,0xe3,0xf6,0x44,0xce,0x10	C mulx 16(up,n,8), %rbx, %rax
+	sub	$-3, n
+	jz	L(wd3)
+	add	%r8, %r11
+	jmp	L(lo3)
+
+L(b2):	mov	%r8, %r10		C carry-in limb
+	mulx(	%r9, %r13, %r12)
+	.byte	0xc4,0xe2,0xe3,0xf6,0x44,0xce,0x08	C mulx 8(up,n,8), %rbx, %rax
+	sub	$-2, n
+	jz	L(wd2)
+	.byte	0xc4,0x62,0xb3,0xf6,0x04,0xce		C mulx (up,n,8), %r9, %r8
+	add	%r10, %r13
+	jmp	L(lo2)
+
+L(b0):	mov	%r8, %rax		C carry-in limb
+	mulx(	%r9, %r9, %r8)
+	.byte	0xc4,0x62,0xa3,0xf6,0x54,0xce,0x08	C mulx 8(up,n,8), %r11, %r10
+	.byte	0xc4,0x62,0x93,0xf6,0x64,0xce,0x10	C mulx 16(up,n,8), %r13, %r12
+	add	%rax, %r9
+	jmp	L(lo0)
+
+L(top):	jrcxz	L(end)
+	adc	%r8, %r11
+	mov	%r9, (rp,n,8)
+L(lo3):	.byte	0xc4,0x62,0xb3,0xf6,0x04,0xce		C mulx (up,n,8), %r9, %r8
+	adc	%r10, %r13
+	mov	%r11, 8(rp,n,8)
+L(lo2):	.byte	0xc4,0x62,0xa3,0xf6,0x54,0xce,0x08	C mulx 8(up,n,8), %r11, %r10
+	adc	%r12, %rbx
+	mov	%r13, 16(rp,n,8)
+L(lo1):	.byte	0xc4,0x62,0x93,0xf6,0x64,0xce,0x10	C mulx 16(up,n,8), %r13, %r12
+	adc	%rax, %r9
+	mov	%rbx, 24(rp,n,8)
+L(lo0):	.byte	0xc4,0xe2,0xe3,0xf6,0x44,0xce,0x18	C mulx 24(up,n,8), %rbx, %rax
+	lea	4(n), n
+	jmp	L(top)
+
+L(end):	mov	%r9, (rp)
+L(wd3):	adc	%r8, %r11
+	mov	%r11, 8(rp)
+L(wd2):	adc	%r10, %r13
+	mov	%r13, 16(rp)
+L(wd1):	adc	%r12, %rbx
+	adc	$0, %rax
+	mov	%rbx, 24(rp)
+
+	pop	%r13
+	pop	%r12
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/mpn/x86_64/zen/mul_basecase.asm b/third_party/gmp/mpn/x86_64/zen/mul_basecase.asm
new file mode 100644
index 0000000..affa3b6
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/zen/mul_basecase.asm
@@ -0,0 +1,455 @@
+dnl  AMD64 mpn_mul_basecase optimised for AMD Zen.
+
+dnl  Copyright 2012, 2013, 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C TODO
+C  * Try 2x unrolling instead of current 4x, at least for mul_1.  Else consider
+C    shallower sw pipelining of mul_1/addmul_1 loops, allowing 4 or 6 instead
+C    of 8 product registers.
+C  * Split up mul_1 into 4 loops in order to fall into the addmul_1 loops
+C    without branch tree.
+C  * Improve the overlapped software pipelining.  The mulx in the osp block now
+C    suffers from write/read conflicts, in particular the 1 mod 4 case.  Also,
+C    mul_1 could osp into addmul_1.
+C  * Let vn_param be vn to save a copy.
+C  * Re-allocate to benefit more from 32-bit encoding.
+C  * Poor performance for e.g. n = 12,16.
+
+define(`rp',       `%rdi')
+define(`up',       `%rsi')
+define(`un_param', `%rdx')
+define(`vp_param', `%rcx')
+define(`vn_param', `%r8')
+
+define(`un',       `%r14')
+define(`vp',       `%rbp')
+define(`v0',       `%rdx')
+define(`n',        `%rcx')
+define(`vn',       `%r15')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_mul_basecase)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), %r8d	')
+
+	cmp	$2, un_param
+	ja	L(gen)
+	mov	(vp_param), %rdx
+	mulx(	(up), %rax, %r9)	C 0 1
+	je	L(s2x)
+
+L(s11):	mov	%rax, (rp)
+	mov	%r9, 8(rp)
+	FUNC_EXIT()
+	ret
+
+L(s2x):	cmp	$2, vn_param
+	mulx(	8,(up), %r8, %r10)	C 1 2
+	je	L(s22)
+
+L(s21):	add	%r8, %r9
+	adc	$0, %r10
+	mov	%rax, (rp)
+	mov	%r9, 8(rp)
+	mov	%r10, 16(rp)
+	FUNC_EXIT()
+	ret
+
+L(s22):	add	%r8, %r9		C 1
+	adc	$0, %r10		C 2
+	mov	8(vp_param), %rdx
+	mov	%rax, (rp)
+	mulx(	(up), %r8, %r11)	C 1 2
+	mulx(	8,(up), %rax, %rdx)	C 2 3
+	add	%r11, %rax		C 2
+	adc	$0, %rdx		C 3
+	add	%r8, %r9		C 1
+	adc	%rax, %r10		C 2
+	adc	$0, %rdx		C 3
+	mov	%r9, 8(rp)
+	mov	%r10, 16(rp)
+	mov	%rdx, 24(rp)
+	FUNC_EXIT()
+	ret
+
+
+L(gen):	push	%r15
+	push	%r14
+	push	%r13
+	push	%r12
+	push	%rbp
+	push	%rbx
+
+	mov	un_param, un
+	mov	vp_param, vp
+	mov	vn_param, vn
+
+	mov	(up), %r9
+	mov	(vp), v0
+
+	lea	(up,un,8), up
+	lea	-32(rp,un,8), rp
+
+	neg	un
+	mov	un, n
+	test	$1, R8(un)
+	jz	L(mx0)
+L(mx1):	test	$2, R8(un)
+	jz	L(mb3)
+
+L(mb1):	mulx(	%r9, %rbx, %rax)
+	inc	n
+	.byte	0xc4,0x22,0xb3,0xf6,0x44,0xf6,0x08	C mulx 8(up,un,8), %r9, %r8
+	.byte	0xc4,0x22,0xa3,0xf6,0x54,0xf6,0x10	C mulx 16(up,un,8), %r11, %r10
+	jmp	L(mlo1)
+
+L(mb3):	mulx(	%r9, %r11, %r10)
+	.byte	0xc4,0x22,0x93,0xf6,0x64,0xf6,0x08	C mulx 8(up,un,8), %r13, %r12
+	.byte	0xc4,0xa2,0xe3,0xf6,0x44,0xf6,0x10	C mulx 16(up,un,8), %rbx, %rax
+	sub	$-3, n
+	jz	L(mwd3)
+	test	R32(%rdx), R32(%rdx)
+	jmp	L(mlo3)
+
+L(mx0):	test	$2, R8(un)
+	jz	L(mb0)
+
+L(mb2):	mulx(	%r9, %r13, %r12)
+	.byte	0xc4,0xa2,0xe3,0xf6,0x44,0xf6,0x08	C mulx 8(up,un,8), %rbx, %rax
+	lea	2(n), n
+	.byte	0xc4,0x22,0xb3,0xf6,0x44,0xf6,0x10	C mulx 16(up,un,8), %r9, %r8
+	jmp	L(mlo2)
+
+L(mb0):	mulx(	%r9, %r9, %r8)
+	.byte	0xc4,0x22,0xa3,0xf6,0x54,0xf6,0x08	C mulx 8(up,un,8), %r11, %r10
+	.byte	0xc4,0x22,0x93,0xf6,0x64,0xf6,0x10	C mulx 16(up,un,8), %r13, %r12
+	jmp	L(mlo0)
+
+L(mtop):jrcxz	L(mend)
+	adc	%r8, %r11
+	mov	%r9, (rp,n,8)
+L(mlo3):.byte	0xc4,0x62,0xb3,0xf6,0x04,0xce		C mulx (up,n,8), %r9, %r8
+	adc	%r10, %r13
+	mov	%r11, 8(rp,n,8)
+L(mlo2):.byte	0xc4,0x62,0xa3,0xf6,0x54,0xce,0x08	C mulx 8(up,n,8), %r11, %r10
+	adc	%r12, %rbx
+	mov	%r13, 16(rp,n,8)
+L(mlo1):.byte	0xc4,0x62,0x93,0xf6,0x64,0xce,0x10	C mulx 16(up,n,8), %r13, %r12
+	adc	%rax, %r9
+	mov	%rbx, 24(rp,n,8)
+L(mlo0):.byte	0xc4,0xe2,0xe3,0xf6,0x44,0xce,0x18	C mulx 24(up,n,8), %rbx, %rax
+	lea	4(n), n
+	jmp	L(mtop)
+
+L(mend):mov	%r9, (rp)
+	adc	%r8, %r11
+L(mwd3):mov	%r11, 8(rp)
+	adc	%r10, %r13
+	mov	%r13, 16(rp)
+	adc	%r12, %rbx
+	adc	$0, %rax
+	mov	%rbx, 24(rp)
+	mov	%rax, 32(rp)
+	add	$8, vp
+	dec	vn
+	jz	L(end)
+
+C The rest of the file are 4 osp loops around addmul_1
+
+	test	$1, R8(un)
+	jnz	L(0x1)
+
+L(0x0):	test	$2, R8(un)
+	jnz	L(oloop2_entry)
+
+L(oloop0_entry):
+	C initial feed-in block
+	mov	(vp), %rdx
+	add	$8, vp
+	mov	un, n
+	add	$8, rp
+	.byte	0xc4,0x22,0xb3,0xf6,0x04,0xf6		C mulx (up,un,8), %r9, %r8
+	.byte	0xc4,0x22,0xa3,0xf6,0x54,0xf6,0x08	C mulx 8(up,un,8), %r11, %r10
+	.byte	0xc4,0x22,0x93,0xf6,0x64,0xf6,0x10	C mulx 16(up,un,8), %r13, %r12
+	.byte	0xc4,0xa2,0xe3,0xf6,0x44,0xf6,0x18	C mulx 24(up,un,8), %rbx, %rax
+	add	%r8, %r11
+	jmp	L(lo0)
+
+L(oloop0):
+	C overlapped software pipelining block
+	mov	(vp), %rdx			C new
+	add	$8, vp
+	add	%r9, (rp)			C prev
+	.byte	0xc4,0x22,0xb3,0xf6,0x04,0xf6		C mulx (%rsi,%r14,8),%r9,%r8
+	adc	%r11, 8(rp)			C prev
+	.byte	0xc4,0x22,0xa3,0xf6,0x54,0xf6,0x08	C mulx 0x8(%rsi,%r14,8),%r11,%r10
+	adc	%r13, 16(rp)			C prev
+	.byte	0xc4,0x22,0x93,0xf6,0x64,0xf6,0x10	C mulx 0x10(%rsi,%r14,8),%r13,%r12
+	adc	%rbx, 24(rp)			C prev
+	mov	un, n
+	adc	$0, %rax			C prev
+	mov	%rax, 32(rp)			C prev
+	add	$8, rp
+	.byte	0xc4,0xa2,0xe3,0xf6,0x44,0xf6,0x18	C mulx 0x18(%rsi,%r14,8),%rbx,%rax
+	add	%r8, %r11			C new
+	jmp	L(lo0)
+
+	ALIGN(16)
+L(tp0):	add	%r9, (rp,n,8)
+	.byte	0xc4,0x62,0xb3,0xf6,0x04,0xce		C mulx (up,n,8), %r9, %r8
+	adc	%r11, 8(rp,n,8)
+	.byte	0xc4,0x62,0xa3,0xf6,0x54,0xce,0x08	C mulx 8(up,n,8), %r11, %r10
+	adc	%r13, 16(rp,n,8)
+	.byte	0xc4,0x62,0x93,0xf6,0x64,0xce,0x10	C mulx 16(up,n,8), %r13, %r12
+	adc	%rbx, 24(rp,n,8)
+	adc	%rax, %r9
+	.byte	0xc4,0xe2,0xe3,0xf6,0x44,0xce,0x18	C mulx 24(up,n,8), %rbx, %rax
+	adc	%r8, %r11
+L(lo0):	adc	%r10, %r13
+	adc	%r12, %rbx
+	adc	$0, %rax
+	add	$4, n
+	jnz	L(tp0)
+
+	dec	vn
+	jne	L(oloop0)
+
+	jmp	L(final_wind_down)
+
+L(oloop2_entry):
+	mov	(vp), %rdx
+	add	$8, vp
+	lea	2(un), n
+	add	$8, rp
+	.byte	0xc4,0x22,0x93,0xf6,0x24,0xf6		C mulx (up,un,8), %r13, %r12
+	.byte	0xc4,0xa2,0xe3,0xf6,0x44,0xf6,0x08	C mulx 8(up,un,8), %rbx, %rax
+	add	%r12, %rbx
+	adc	$0, %rax
+	.byte	0xc4,0x22,0xb3,0xf6,0x44,0xf6,0x10	C mulx 16(up,un,8), %r9, %r8
+	.byte	0xc4,0x62,0xa3,0xf6,0x54,0xce,0x08	C mulx 8(up,n,8), %r11, %r10
+	add	%r13, 16(rp,n,8)
+	jmp	L(lo2)
+
+L(oloop2):
+	mov	(vp), %rdx
+	add	$8, vp
+	add	%r9, (rp)
+	adc	%r11, 8(rp)
+	adc	%r13, 16(rp)
+	.byte	0xc4,0x22,0x93,0xf6,0x24,0xf6		C mulx (up,un,8), %r13, %r12
+	adc	%rbx, 24(rp)
+	adc	$0, %rax
+	mov	%rax, 32(rp)
+	.byte	0xc4,0xa2,0xe3,0xf6,0x44,0xf6,0x08	C mulx 8(up,un,8), %rbx, %rax
+	lea	2(un), n
+	add	$8, rp
+	.byte	0xc4,0x22,0xb3,0xf6,0x44,0xf6,0x10	C mulx 16(up,un,8), %r9, %r8
+	add	%r12, %rbx
+	adc	$0, %rax
+	.byte	0xc4,0x22,0xa3,0xf6,0x54,0xf6,0x18	C mulx 0x18(%rsi,%r14,8),%r11,%r10
+	add	%r13, 16(rp,n,8)
+	jmp	L(lo2)
+
+	ALIGN(16)
+L(tp2):	add	%r9, (rp,n,8)
+	.byte	0xc4,0x62,0xb3,0xf6,0x04,0xce		C mulx (up,n,8), %r9, %r8
+	adc	%r11, 8(rp,n,8)
+	.byte	0xc4,0x62,0xa3,0xf6,0x54,0xce,0x08	C mulx 8(up,n,8), %r11, %r10
+	adc	%r13, 16(rp,n,8)
+L(lo2):	.byte	0xc4,0x62,0x93,0xf6,0x64,0xce,0x10	C mulx 16(up,n,8), %r13, %r12
+	adc	%rbx, 24(rp,n,8)
+	adc	%rax, %r9
+	.byte	0xc4,0xe2,0xe3,0xf6,0x44,0xce,0x18	C mulx 24(up,n,8), %rbx, %rax
+	adc	%r8, %r11
+	adc	%r10, %r13
+	adc	%r12, %rbx
+	adc	$0, %rax
+	add	$4, n
+	jnz	L(tp2)
+
+	dec	vn
+	jne	L(oloop2)
+
+	jmp	L(final_wind_down)
+
+L(0x1):	test	$2, R8(un)
+	jz	L(oloop3_entry)
+
+L(oloop1_entry):
+	mov	(vp), %rdx
+	add	$8, vp
+	lea	1(un), n
+	add	$8, rp
+	.byte	0xc4,0xa2,0xe3,0xf6,0x04,0xf6		C mulx (up,un,8), %rbx, %rax
+	.byte	0xc4,0x22,0xb3,0xf6,0x44,0xf6,0x08	C mulx 8(up,un,8), %r9, %r8
+	.byte	0xc4,0x22,0xa3,0xf6,0x54,0xf6,0x10	C mulx 16(up,un,8), %r11, %r10
+	.byte	0xc4,0x62,0x93,0xf6,0x64,0xce,0x10	C mulx 16(up,n,8), %r13, %r12
+	add	%rbx, 24(rp,n,8)
+	jmp	L(lo1)
+
+L(oloop1):
+	mov	(vp), %rdx
+	add	$8, vp
+	add	%r9, (rp)
+	.byte	0xc4,0x22,0xb3,0xf6,0x44,0xf6,0x08	C mulx 8(up,un,8), %r9, %r8
+	adc	%r11, 8(rp)
+	.byte	0xc4,0x22,0xa3,0xf6,0x54,0xf6,0x10	C mulx 16(up,un,8), %r11, %r10
+	adc	%r13, 16(rp)
+	.byte	0xc4,0x22,0x93,0xf6,0x64,0xf6,0x18	C mulx 0x18(%rsi,%r14,8),%r13,%r12
+	adc	%rbx, 24(rp)
+	adc	$0, %rax
+	mov	%rax, 32(rp)
+	.byte	0xc4,0xa2,0xe3,0xf6,0x04,0xf6		C mulx (up,un,8), %rbx, %rax
+	lea	1(un), n
+	add	$8, rp
+	add	%rbx, 24(rp,n,8)
+	jmp	L(lo1)
+
+	ALIGN(16)
+L(tp1):	add	%r9, (rp,n,8)
+	.byte	0xc4,0x62,0xb3,0xf6,0x04,0xce		C mulx (up,n,8), %r9, %r8
+	adc	%r11, 8(rp,n,8)
+	.byte	0xc4,0x62,0xa3,0xf6,0x54,0xce,0x08	C mulx 8(up,n,8), %r11, %r10
+	adc	%r13, 16(rp,n,8)
+	.byte	0xc4,0x62,0x93,0xf6,0x64,0xce,0x10	C mulx 16(up,n,8), %r13, %r12
+	adc	%rbx, 24(rp,n,8)
+L(lo1):	adc	%rax, %r9
+	.byte	0xc4,0xe2,0xe3,0xf6,0x44,0xce,0x18	C mulx 24(up,n,8), %rbx, %rax
+	adc	%r8, %r11
+	adc	%r10, %r13
+	adc	%r12, %rbx
+	adc	$0, %rax
+	add	$4, n
+	jnz	L(tp1)
+
+	dec	vn
+	jne	L(oloop1)
+
+	jmp	L(final_wind_down)
+
+L(oloop3_entry):
+	mov	(vp), %rdx
+	add	$8, vp
+	lea	3(un), n
+	add	$8, rp
+	.byte	0xc4,0x22,0xa3,0xf6,0x14,0xf6		C mulx (up,un,8), %r11, %r10
+	.byte	0xc4,0x22,0x93,0xf6,0x64,0xf6,0x08	C mulx 8(up,un,8), %r13, %r12
+	.byte	0xc4,0xa2,0xe3,0xf6,0x44,0xf6,0x10	C mulx 16(up,un,8), %rbx, %rax
+	add	%r10, %r13
+	adc	%r12, %rbx
+	adc	$0, %rax
+	test	n, n
+	jz	L(wd3)
+	.byte	0xc4,0x62,0xb3,0xf6,0x04,0xce		C mulx (up,n,8), %r9, %r8
+	add	%r11, 8(rp,n,8)
+	jmp	L(lo3)
+
+L(oloop3):
+	mov	(vp), %rdx
+	add	$8, vp
+	add	%r9, (rp)
+	adc	%r11, 8(rp)
+	.byte	0xc4,0x22,0xa3,0xf6,0x14,0xf6		C mulx (up,un,8), %r11, %r10
+	adc	%r13, 16(rp)
+	.byte	0xc4,0x22,0x93,0xf6,0x64,0xf6,0x08	C mulx 8(up,un,8), %r13, %r12
+	adc	%rbx, 24(rp)
+	adc	$0, %rax
+	mov	%rax, 32(rp)
+	.byte	0xc4,0xa2,0xe3,0xf6,0x44,0xf6,0x10	C mulx 16(up,un,8), %rbx, %rax
+	lea	3(un), n
+	add	$8, rp
+	add	%r10, %r13
+	.byte	0xc4,0x62,0xb3,0xf6,0x04,0xce		C mulx (up,n,8), %r9, %r8
+	adc	%r12, %rbx
+	adc	$0, %rax
+	add	%r11, 8(rp,n,8)
+	jmp	L(lo3)
+
+	ALIGN(16)
+L(tp3):	add	%r9, (rp,n,8)
+	.byte	0xc4,0x62,0xb3,0xf6,0x04,0xce		C mulx (up,n,8), %r9, %r8
+	adc	%r11, 8(rp,n,8)
+L(lo3):	.byte	0xc4,0x62,0xa3,0xf6,0x54,0xce,0x08	C mulx 8(up,n,8), %r11, %r10
+	adc	%r13, 16(rp,n,8)
+	.byte	0xc4,0x62,0x93,0xf6,0x64,0xce,0x10	C mulx 16(up,n,8), %r13, %r12
+	adc	%rbx, 24(rp,n,8)
+	adc	%rax, %r9
+	.byte	0xc4,0xe2,0xe3,0xf6,0x44,0xce,0x18	C mulx 24(up,n,8), %rbx, %rax
+	adc	%r8, %r11
+	adc	%r10, %r13
+	adc	%r12, %rbx
+	adc	$0, %rax
+	add	$4, n
+	jnz	L(tp3)
+
+	dec	vn
+	jne	L(oloop3)
+
+L(final_wind_down):
+	add	%r9, (rp)
+	adc	%r11, 8(rp)
+	adc	%r13, 16(rp)
+	adc	%rbx, 24(rp)
+	adc	$0, %rax
+	mov	%rax, 32(rp)
+
+L(end):	pop	%rbx
+	pop	%rbp
+	pop	%r12
+	pop	%r13
+	pop	%r14
+	pop	%r15
+	FUNC_EXIT()
+	ret
+
+L(3):	mov	(vp), %rdx
+	add	$8, vp
+	add	$8, rp
+	.byte	0xc4,0x22,0xa3,0xf6,0x14,0xf6		C mulx (up,un,8), %r11, %r10
+	.byte	0xc4,0x22,0x93,0xf6,0x64,0xf6,0x08	C mulx 8(up,un,8), %r13, %r12
+	.byte	0xc4,0xa2,0xe3,0xf6,0x44,0xf6,0x10	C mulx 16(up,un,8), %rbx, %rax
+	add	%r10, %r13
+	adc	%r12, %rbx
+	adc	$0, %rax
+L(wd3):	adc	%r11, 8(rp)
+	adc	%r13, 16(rp)
+	adc	%rbx, 24(rp)
+	adc	$0, %rax
+	mov	%rax, 32(rp)
+	dec	vn
+	jne	L(3)
+	jmp	L(end)
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/zen/mullo_basecase.asm b/third_party/gmp/mpn/x86_64/zen/mullo_basecase.asm
new file mode 100644
index 0000000..2ae729a
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/zen/mullo_basecase.asm
@@ -0,0 +1,299 @@
+dnl  X64-64 mpn_mullo_basecase optimised for AMD Zen.
+
+dnl  Contributed to the GNU project by Torbjorn Granlund.
+
+dnl  Copyright 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C The inner loops of this code are the result of running a code generation and
+C optimisation tool suite written by David Harvey and Torbjorn Granlund.
+
+define(`rp',	   `%rdi')
+define(`up',	   `%rsi')
+define(`vp_param', `%rdx')
+define(`n',	   `%rcx')
+
+define(`vp',	`%r11')
+define(`nn',    `%rbp')
+
+C TODO
+C  * Rearrange feed-in jumps for short branch forms.
+C  * Roll out the heavy artillery and 4-way unroll outer loop.  Since feed-in
+C    code implodes, the blow-up will not be more than perhaps 2.5x.
+C  * Micro-optimise critical lead-in code blocks.
+C  * Clean up register use, e.g. r15 vs vp, disuse of nn, etc.
+C  * Write n < 4 code specifically for Zen (current code is for Haswell).
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(32)
+PROLOGUE(mpn_mullo_basecase)
+	FUNC_ENTRY(4)
+	cmp	$4, R32(n)
+	jae	L(big)
+
+	mov	vp_param, vp
+	mov	(up), %rdx
+
+	cmp	$2, R32(n)
+	jae	L(gt1)
+L(n1):	imul	(vp), %rdx
+	mov	%rdx, (rp)
+	FUNC_EXIT()
+	ret
+L(gt1):	ja	L(gt2)
+L(n2):	mov	(vp), %r9
+	mulx(	%r9, %rax, %rdx)
+	mov	%rax, (rp)
+	mov	8(up), %rax
+	imul	%r9, %rax
+	add	%rax, %rdx
+	mov	8(vp), %r9
+	mov	(up), %rcx
+	imul	%r9, %rcx
+	add	%rcx, %rdx
+	mov	%rdx, 8(rp)
+	FUNC_EXIT()
+	ret
+L(gt2):
+L(n3):	mov	(vp), %r9
+	mulx(	%r9, %rax, %r10)	C u0 x v0
+	mov	%rax, (rp)
+	mov	8(up), %rdx
+	mulx(	%r9, %rax, %rdx)	C u1 x v0
+	imul	16(up), %r9		C u2 x v0
+	add	%rax, %r10
+	adc	%rdx, %r9
+	mov	8(vp), %r8
+	mov	(up), %rdx
+	mulx(	%r8, %rax, %rdx)	C u0 x v1
+	add	%rax, %r10
+	adc	%rdx, %r9
+	imul	8(up), %r8		C u1 x v1
+	add	%r8, %r9
+	mov	%r10, 8(rp)
+	mov	16(vp), %r10
+	mov	(up), %rax
+	imul	%rax, %r10		C u0 x v2
+	add	%r10, %r9
+	mov	%r9, 16(rp)
+	FUNC_EXIT()
+	ret
+
+	ALIGN(16)
+L(big):	push	%r15
+	push	%r14
+	push	%r13
+	push	%r12
+	push	%rbp
+	push	%rbx
+
+	mov	(up), %r9
+	lea	-8(up,n,8), up
+	lea	-40(rp,n,8), rp
+
+	mov	$4, R32(%r14)
+	sub	n, %r14
+	mov	-8(vp_param,n,8), %rbp
+	imul	%r9, %rbp
+	lea	8(vp_param), %r15
+	mov	(vp_param), %rdx
+
+	test	$1, R8(%r14)
+	jnz	L(mx0)
+L(mx1):	test	$2, R8(%r14)
+	jz	L(mb3)
+
+L(mb1):	mulx(	%r9, %rbx, %rax)
+	lea	-2(%r14), n
+	.byte	0xc4,0x22,0xb3,0xf6,0x44,0xf6,0xf0	C mulx -0x10(%rsi,%r14,8),%r9,%r8
+	.byte	0xc4,0x22,0xa3,0xf6,0x54,0xf6,0xf8	C mulx -0x8(%rsi,%r14,8),%r11,%r10
+	jmp	L(mlo1)
+
+L(mb3):	mulx(	%r9, %r11, %r10)
+	.byte	0xc4,0x22,0x93,0xf6,0x64,0xf6,0xf0	C mulx -0x10(%rsi,%r14,8),%r13,%r12
+	.byte	0xc4,0xa2,0xe3,0xf6,0x44,0xf6,0xf8	C mulx -0x8(%rsi,%r14,8),%rbx,%rax
+	lea	(%r14), n
+	jrcxz	L(x)
+	jmp	L(mlo3)
+L(x):	jmp	L(mcor)
+
+L(mb2):	mulx(	%r9, %r13, %r12)
+	.byte	0xc4,0xa2,0xe3,0xf6,0x44,0xf6,0xf0	C mulx -0x10(%rsi,%r14,8),%rbx,%rax
+	lea	-1(%r14), n
+	.byte	0xc4,0x22,0xb3,0xf6,0x44,0xf6,0xf8	C mulx -0x8(%rsi,%r14,8),%r9,%r8
+	jmp	L(mlo2)
+
+L(mx0):	test	$2, R8(%r14)
+	jz	L(mb2)
+
+L(mb0):	mulx(	%r9, %r9, %r8)
+	.byte	0xc4,0x22,0xa3,0xf6,0x54,0xf6,0xf0	C mulx -0x10(%rsi,%r14,8),%r11,%r10
+	.byte	0xc4,0x22,0x93,0xf6,0x64,0xf6,0xf8	C mulx -0x8(%rsi,%r14,8),%r13,%r12
+	lea	-3(%r14), n
+	jmp	L(mlo0)
+
+	ALIGN(16)
+L(mtop):jrcxz	L(mend)
+	adc	%r8, %r11
+	mov	%r9, (rp,n,8)
+L(mlo3):.byte	0xc4,0x62,0xb3,0xf6,0x04,0xce		C mulx (up,n,8), %r9, %r8
+	adc	%r10, %r13
+	mov	%r11, 8(rp,n,8)
+L(mlo2):.byte	0xc4,0x62,0xa3,0xf6,0x54,0xce,0x08	C mulx 8(up,n,8), %r11, %r10
+	adc	%r12, %rbx
+	mov	%r13, 16(rp,n,8)
+L(mlo1):.byte	0xc4,0x62,0x93,0xf6,0x64,0xce,0x10	C mulx 16(up,n,8), %r13, %r12
+	adc	%rax, %r9
+	mov	%rbx, 24(rp,n,8)
+L(mlo0):.byte	0xc4,0xe2,0xe3,0xf6,0x44,0xce,0x18	C mulx 24(up,n,8), %rbx, %rax
+	lea	4(n), n
+	jmp	L(mtop)
+
+L(mend):mov	%r9, (rp)
+	adc	%r8, %r11
+	mov	%r11, 8(rp)
+	adc	%r10, %r13
+	mov	%r13, 16(rp)
+	adc	%r12, %rbx
+	mov	%rbx, 24(rp)
+
+L(outer):
+	mulx(	(up), %r10, %r8)	C FIXME r8 unused (use imul?)
+	adc	%rax, %rbp
+	add	%r10, %rbp
+	mov	(%r15), %rdx
+	add	$8, %r15
+	mov	-24(up,%r14,8), %r8
+	lea	-8(up), up
+
+	test	$1, R8(%r14)
+	jz	L(x0)
+L(x1):	test	$2, R8(%r14)
+	jnz	L(b3)
+
+L(b1):	mulx(	%r8, %rbx, %rax)
+	lea	-1(%r14), n
+	.byte	0xc4,0x62,0xb3,0xf6,0x04,0xce		C mulx (%rsi,%rcx,8),%r9,%r8
+	.byte	0xc4,0x62,0xa3,0xf6,0x54,0xce,0x08	C mulx 0x8(%rsi,%rcx,8),%r11,%r10
+	jmp	L(lo1)
+
+L(x0):	test	$2, R8(%r14)
+	jz	L(b2)
+
+L(b0):	mulx(	%r8, %r9, %r8)
+	lea	-2(%r14), n
+	.byte	0xc4,0x22,0xa3,0xf6,0x54,0xf6,0xf8	C mulx -0x8(%rsi,%r14,8),%r11,%r10
+	.byte	0xc4,0x22,0x93,0xf6,0x24,0xf6		C mulx (%rsi,%r14,8),%r13,%r12
+	jmp	L(lo0)
+
+L(b3):	mulx(	%r8, %r11, %r10)
+	lea	1(%r14), n
+	.byte	0xc4,0x22,0x93,0xf6,0x64,0xf6,0xf8	C mulx -0x8(%rsi,%r14,8),%r13,%r12
+	.byte	0xc4,0xa2,0xe3,0xf6,0x04,0xf6		C mulx (%rsi,%r14,8),%rbx,%rax
+	add	%r10, %r13
+	adc	%r12, %rbx
+	adc	$0, %rax
+	jrcxz	L(cor)
+	jmp	L(lo3)
+
+L(cor):	add	8(rp), %r11
+	mov	16(rp), %r10
+	mov	24(rp), %r12
+L(mcor):mov	%r11, 8(rp)
+	adc	%r10, %r13
+	adc	%r12, %rbx
+	mulx(	(up), %r10, %r8)	C FIXME r8 unused (use imul?)
+	adc	%rax, %rbp
+	add	%r10, %rbp
+	mov	(%r15), %rdx
+	mov	-24(up), %r8
+	mulx(	%r8, %r9, %r12)
+	mulx(	-16,(up), %r14, %rax)
+	add	%r12, %r14
+	adc	$0, %rax
+	adc	%r9, %r13
+	mov	%r13, 16(rp)
+	adc	%r14, %rbx
+	mulx(	-8,(up), %r10, %r8)	C FIXME r8 unused (use imul?)
+	adc	%rax, %rbp
+	add	%r10, %rbp
+	mov	8(%r15), %rdx
+	mulx(	-24,(up), %r14, %rax)
+	add	%r14, %rbx
+	mov	%rbx, 24(rp)
+	mulx(	-16,(up), %r10, %r8)	C FIXME r8 unused (use imul?)
+	adc	%rax, %rbp
+	add	%r10, %rbp
+	mov	%rbp, 32(rp)
+	pop	%rbx
+	pop	%rbp
+	pop	%r12
+	pop	%r13
+	pop	%r14
+	pop	%r15
+	FUNC_EXIT()
+	ret
+
+L(b2):	mulx(	%r8, %r13, %r12)
+	lea	(%r14), n
+	.byte	0xc4,0xa2,0xe3,0xf6,0x44,0xf6,0xf8	C mulx -0x8(%rsi,%r14,8),%rbx,%rax
+	add	%r12, %rbx
+	adc	$0, %rax
+	.byte	0xc4,0x22,0xb3,0xf6,0x04,0xf6		C mulx (%rsi,%r14,8),%r9,%r8
+	jmp	L(lo2)
+
+	ALIGN(16)
+L(top):	add	%r9, (rp,n,8)
+L(lo3):	.byte	0xc4,0x62,0xb3,0xf6,0x04,0xce		C mulx (up,n,8), %r9, %r8
+	adc	%r11, 8(rp,n,8)
+L(lo2):	.byte	0xc4,0x62,0xa3,0xf6,0x54,0xce,0x08	C mulx 8(up,n,8), %r11, %r10
+	adc	%r13, 16(rp,n,8)
+L(lo1):	.byte	0xc4,0x62,0x93,0xf6,0x64,0xce,0x10	C mulx 16(up,n,8), %r13, %r12
+	adc	%rbx, 24(rp,n,8)
+	adc	%rax, %r9
+L(lo0):	.byte	0xc4,0xe2,0xe3,0xf6,0x44,0xce,0x18	C mulx 24(up,n,8), %rbx, %rax
+	adc	%r8, %r11
+	adc	%r10, %r13
+	adc	%r12, %rbx
+	adc	$0, %rax
+	add	$4, n
+	js	L(top)
+
+	add	%r9, (rp)
+	adc	%r11, 8(rp)
+	adc	%r13, 16(rp)
+	adc	%rbx, 24(rp)
+	inc	%r14
+	jmp	L(outer)
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/zen/popcount.asm b/third_party/gmp/mpn/x86_64/zen/popcount.asm
new file mode 100644
index 0000000..be1613b
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/zen/popcount.asm
@@ -0,0 +1,38 @@
+dnl  AMD64 mpn_popcount -- population count.
+
+dnl  Copyright 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_popcount)
+include_mpn(`x86_64/coreinhm/popcount.asm')
diff --git a/third_party/gmp/mpn/x86_64/zen/rshift.asm b/third_party/gmp/mpn/x86_64/zen/rshift.asm
new file mode 100644
index 0000000..0196870
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/zen/rshift.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_rshift optimised for AMD Zen.
+
+dnl  Copyright 2012 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_rshift)
+include_mpn(`x86_64/fastsse/rshift-movdqu2.asm')
diff --git a/third_party/gmp/mpn/x86_64/zen/sbpi1_bdiv_r.asm b/third_party/gmp/mpn/x86_64/zen/sbpi1_bdiv_r.asm
new file mode 100644
index 0000000..f6e8f9c
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/zen/sbpi1_bdiv_r.asm
@@ -0,0 +1,507 @@
+dnl  AMD64 mpn_sbpi1_bdiv_r optimised for AMD Zen
+
+dnl  Copyright 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+define(`up',       `%rdi')
+define(`un_param', `%rsi')
+define(`dp_param', `%rdx')
+define(`dn_param', `%rcx')
+define(`dinv',     `%r8')
+
+define(`i',        `%rcx')
+define(`dn',       `%r14')
+
+define(`dp',       `%rsi')
+define(`un',       `%r15')
+
+C TODO
+C  * The o1...o8  loops for special dn counts were naively hand-optimised by
+C    folding the generic loops.  They can probably be tuned.  The speculative
+C    quotient limb generation might not be in the optimal spot.
+C  * Perhaps avoid late-in-loop jumps, e.g., lo0.
+C  * Improve regalloc wrt dn_param/dn and un_param/un to save some moves.
+
+C ABI_SUPPORT(DOS64)
+C ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_sbpi1_bdiv_r)
+	FUNC_ENTRY(4)
+IFDOS(`	mov	56(%rsp), dinv	')
+	push	%r15
+	push	%r14
+	push	%r13
+	push	%r12
+	push	%rbp
+	push	%rbx
+
+	sub	dn_param, un_param		C outer loop count
+	mov	dn_param, dn		C FIXME: Suppress by reg re-alloc
+	push	dinv				C keep dinv on stack
+	mov	un_param, un		C FIXME: Suppress by reg re-alloc
+	xor	R32(%rbp), R32(%rbp)
+
+	lea	(dp_param,dn_param,8), dp
+
+	mov	(up), %rdx
+	imul	dinv, %rdx			C first quotient limb
+
+	neg	dn
+	lea	-32(up,dn_param,8), up
+
+	test	$1, R8(dn_param)
+	jnz	L(cx1)
+
+L(cx0):	test	$2, R8(dn_param)
+	jnz	L(b2)
+
+
+C =============================================================================
+L(b0):	cmp	$-4, dn
+	jnz	L(gt4)
+
+L(o4):	mulx(	-32,(dp), %r9, %r14)
+	mulx(	-24,(dp), %r11, %r10)
+	mulx(	-16,(dp), %r13, %r12)
+	mulx(	-8,(dp), %rbx, %rax)
+	add	%r14, %r11
+	adc	%r10, %r13
+	adc	%r12, %rbx
+	adc	$0, %rax
+	add	(up), %r9
+	adc	8(up), %r11
+	mov	%r8, %rdx			C dinv
+	mov	%r11, 8(up)
+	mulx(	%r11, %rdx, %r12)		C next quotient
+	adc	%r13, 16(up)
+	adc	%rbx, 24(up)
+	adc	%rbp, %rax
+	setc	R8(%rbp)
+	add	%rax, 32(up)
+	adc	$0, R32(%rbp)
+	lea	8(up), up
+	dec	un
+	jne	L(o4)
+	jmp	L(ret)
+
+L(gt4):	cmp	$-8, dn
+	jnz	L(out0)
+
+L(o8):	mulx(	-64,(dp), %r9, %r14)
+	mulx(	-56,(dp), %rcx, %r10)
+	mulx(	-48,(dp), %r13, %r12)
+	mulx(	-40,(dp), %rbx, %rax)
+	add	%r14, %rcx
+	adc	%r10, %r13
+	adc	%r12, %rbx
+	adc	$0, %rax
+	add	-32(up), %r9
+	mulx(	-32,(dp), %r9, %r14)
+	adc	-24(up), %rcx
+	mov	%rcx, -24(up)
+	mulx(	-24,(dp), %r11, %r10)
+	adc	%r13, -16(up)
+	mulx(	-16,(dp), %r13, %r12)
+	adc	%rbx, -8(up)
+	adc	%rax, %r9
+	mulx(	-8,(dp), %rbx, %rax)
+	adc	%r14, %r11
+	adc	%r10, %r13
+	adc	%r12, %rbx
+	adc	$0, %rax
+	mov	%r8, %rdx			C dinv
+	mulx(	%rcx, %rdx, %r12)		C next quotient
+	add	%r9, (up)
+	adc	%r11, 8(up)
+	adc	%r13, 16(up)
+	adc	%rbx, 24(up)
+	adc	%rbp, %rax
+	setc	R8(%rbp)
+	add	%rax, 32(up)
+	adc	$0, R32(%rbp)
+	lea	8(up), up
+	dec	un
+	jne	L(o8)
+	jmp	L(ret)
+
+L(out0):mov	dn, i
+	.byte	0xc4,0x22,0xb3,0xf6,0x04,0xf6		C mulx (dp,dn,8),%r9,%r8
+	.byte	0xc4,0x22,0xa3,0xf6,0x54,0xf6,0x08	C mulx 8(dp,dn,8),%r11,%r10
+	.byte	0xc4,0x22,0x93,0xf6,0x64,0xf6,0x10	C mulx 16(dp,dn,8),%r13,%r12
+	clc
+	jmp	L(lo0)
+
+	ALIGN(16)
+L(top0):add	%r9, (up,i,8)
+	.byte	0xc4,0x62,0xb3,0xf6,0x04,0xce		C mulx (dp,i,8), %r9, %r8
+	adc	%r11, 8(up,i,8)
+	.byte	0xc4,0x62,0xa3,0xf6,0x54,0xce,0x08	C mulx 8(dp,i,8), %r11, %r10
+	adc	%r13, 16(up,i,8)
+	.byte	0xc4,0x62,0x93,0xf6,0x64,0xce,0x10	C mulx 16(dp,i,8), %r13, %r12
+	adc	%rbx, 24(up,i,8)
+	adc	%rax, %r9
+L(lo0):	.byte	0xc4,0xe2,0xe3,0xf6,0x44,0xce,0x18	C mulx 24(dp,i,8), %rbx, %rax
+	adc	%r8, %r11
+	adc	%r10, %r13
+	adc	%r12, %rbx
+	adc	$0, %rax
+	add	$4, i
+	js	L(top0)
+
+	mov	(%rsp), %rdx			C dinv
+	.byte	0xc4,0x22,0xeb,0xf6,0x64,0xf7,0x28	C mulx 40(%rdi,%r14,8),%rdx,%r12
+	add	%r9, (up)
+	adc	%r11, 8(up)
+	adc	%r13, 16(up)
+	adc	%rbx, 24(up)
+	adc	%rbp, %rax
+	setc	R8(%rbp)
+	add	%rax, 32(up)
+	adc	$0, R32(%rbp)
+	lea	8(up), up
+	dec	un
+	jne	L(out0)
+	jmp	L(ret)
+
+L(cx1):	test	$2, R8(dn_param)
+	jnz	L(b3)
+
+C =============================================================================
+L(b1):	cmp	$-1, dn
+	jnz	L(gt1)
+
+	mov	24(up), %r9
+L(o1):	mulx(	-8,(dp), %rbx, %rdx)
+	add	%r9, %rbx
+	adc	%rbp, %rdx
+	add	32(up), %rdx
+	setc	R8(%rbp)
+	mov	%rdx, %r9
+	mulx(	%r8, %rdx, %r12)		C next quotient
+	lea	8(up), up
+	dec	un
+	jne	L(o1)
+	mov	%r9, 24(up)
+	jmp	L(ret)
+
+L(gt1):	cmp	$-5, dn
+	jnz	L(out1)
+
+L(o5):	mulx(	-40,(dp), %rbx, %rax)
+	mulx(	-32,(dp), %r9, %r14)
+	mulx(	-24,(dp), %r11, %r10)
+	mulx(	-16,(dp), %r13, %r12)
+	add	-8(up), %rbx
+	adc	%rax, %r9
+	mulx(	-8,(dp), %rbx, %rax)
+	adc	%r14, %r11
+	adc	%r10, %r13
+	adc	%r12, %rbx
+	adc	$0, %rax
+	add	(up), %r9
+	mov	%r9, (up)
+	mov	%r8, %rdx			C dinv
+	mulx(	%r9, %rdx, %r12)		C next quotient
+	adc	%r11, 8(up)
+	adc	%r13, 16(up)
+	adc	%rbx, 24(up)
+	adc	%rbp, %rax
+	setc	R8(%rbp)
+	add	%rax, 32(up)
+	adc	$0, R32(%rbp)
+	lea	8(up), up
+	dec	un
+	jne	L(o5)
+	jmp	L(ret)
+
+L(out1):lea	1(dn), i
+	.byte	0xc4,0xa2,0xe3,0xf6,0x04,0xf6		C mulx (dp,dn,8),%rbx,%rax
+	.byte	0xc4,0x22,0xb3,0xf6,0x44,0xf6,0x08	C mulx 8(dp,dn,8),%r9,%r8
+	.byte	0xc4,0x22,0xa3,0xf6,0x54,0xf6,0x10	C mulx 16(dp,dn,8),%r11,%r10
+	clc
+	jmp	L(lo1)
+
+	ALIGN(16)
+L(top1):add	%r9, (up,i,8)
+	.byte	0xc4,0x62,0xb3,0xf6,0x04,0xce		C mulx (dp,i,8), %r9, %r8
+	adc	%r11, 8(up,i,8)
+	.byte	0xc4,0x62,0xa3,0xf6,0x54,0xce,0x08	C mulx 8(dp,i,8), %r11, %r10
+	adc	%r13, 16(up,i,8)
+L(lo1):	.byte	0xc4,0x62,0x93,0xf6,0x64,0xce,0x10	C mulx 16(dp,i,8), %r13, %r12
+	adc	%rbx, 24(up,i,8)
+	adc	%rax, %r9
+	.byte	0xc4,0xe2,0xe3,0xf6,0x44,0xce,0x18	C mulx 24(dp,i,8), %rbx, %rax
+	adc	%r8, %r11
+	adc	%r10, %r13
+	adc	%r12, %rbx
+	adc	$0, %rax
+	add	$4, i
+	js	L(top1)
+
+	mov	(%rsp), %rdx			C dinv
+	.byte	0xc4,0x22,0xeb,0xf6,0x64,0xf7,0x28	C mulx 40(up,dn,8), %rdx, %r12
+	add	%r9, (up)
+	adc	%r11, 8(up)
+	adc	%r13, 16(up)
+	adc	%rbx, 24(up)
+	adc	%rbp, %rax
+	setc	R8(%rbp)
+	add	%rax, 32(up)
+	adc	$0, R32(%rbp)
+	lea	8(up), up
+	dec	un
+	jne	L(out1)
+	jmp	L(ret)
+
+C =============================================================================
+L(b2):	cmp	$-2, dn
+	jnz	L(gt2)
+
+	mov	16(up), %r10
+	mov	24(up), %r9
+L(o2):	mulx(	-16,(dp), %r13, %r12)
+	mulx(	-8,(dp), %rbx, %rax)
+	add	%r12, %rbx
+	adc	$0, %rax
+	add	%r10, %r13			C add just to produce carry
+	mov	%r9, %r10
+	adc	%rbx, %r10
+	mov	%r8, %rdx
+	mulx(	%r10, %rdx, %r12)		C next quotient
+	adc	%rbp, %rax
+	setc	R8(%rbp)
+	mov	32(up), %r9
+	add	%rax, %r9
+	adc	$0, R32(%rbp)
+	lea	8(up), up
+	dec	un
+	jne	L(o2)
+	mov	%r10, 16(up)
+	mov	%r9, 24(up)
+	jmp	L(ret)
+
+L(gt2):	cmp	$-6, dn
+	jnz	L(out2)
+
+L(o6):	mulx(	-48,(dp), %r13, %r12)
+	mulx(	-40,(dp), %rcx, %rax)
+	add	%r12, %rcx
+	adc	$0, %rax
+	mulx(	-32,(dp), %r9, %r14)
+	mulx(	-24,(dp), %r11, %r10)
+	add	-16(up), %r13
+	mulx(	-16,(dp), %r13, %r12)
+	adc	-8(up), %rcx
+	mov	%rcx, -8(up)
+	adc	%rax, %r9
+	mulx(	-8,(dp), %rbx, %rax)
+	adc	%r14, %r11
+	adc	%r10, %r13
+	adc	%r12, %rbx
+	adc	$0, %rax
+	mov	%r8, %rdx			C dinv
+	mulx(	%rcx, %rdx, %r12)		C next quotient
+	add	%r9, (up)
+	adc	%r11, 8(up)
+	adc	%r13, 16(up)
+	adc	%rbx, 24(up)
+	adc	%rbp, %rax
+	setc	R8(%rbp)
+	add	%rax, 32(up)
+	adc	$0, R32(%rbp)
+	lea	8(up), up
+	dec	un
+	jne	L(o6)
+	jmp	L(ret)
+
+L(out2):lea	2(dn), i
+	.byte	0xc4,0x22,0x93,0xf6,0x24,0xf6		C mulx (dp,dn,8),%r13,%r12
+	.byte	0xc4,0xa2,0xe3,0xf6,0x44,0xf6,0x08	C mulx 8(dp,dn,8),%rbx,%rax
+	add	%r12, %rbx
+	adc	$0, %rax
+	.byte	0xc4,0x22,0xb3,0xf6,0x44,0xf6,0x10	C mulx 16(dp,dn,8),%r9,%r8
+	jmp	L(lo2)
+
+	ALIGN(16)
+L(top2):add	%r9, (up,i,8)
+	.byte	0xc4,0x62,0xb3,0xf6,0x04,0xce		C mulx (dp,i,8), %r9, %r8
+	adc	%r11, 8(up,i,8)
+L(lo2):	.byte	0xc4,0x62,0xa3,0xf6,0x54,0xce,0x08	C mulx 8(dp,i,8), %r11, %r10
+	adc	%r13, 16(up,i,8)
+	.byte	0xc4,0x62,0x93,0xf6,0x64,0xce,0x10	C mulx 16(dp,i,8), %r13, %r12
+	adc	%rbx, 24(up,i,8)
+	adc	%rax, %r9
+	.byte	0xc4,0xe2,0xe3,0xf6,0x44,0xce,0x18	C mulx 24(dp,i,8), %rbx, %rax
+	adc	%r8, %r11
+	adc	%r10, %r13
+	adc	%r12, %rbx
+	adc	$0, %rax
+	add	$4, i
+	js	L(top2)
+
+	mov	(%rsp), %rdx			C dinv
+	.byte	0xc4,0x22,0xeb,0xf6,0x64,0xf7,0x28	C mulx 40(up,dn,8), %rdx, %r12
+	add	%r9, (up)
+	adc	%r11, 8(up)
+	adc	%r13, 16(up)
+	adc	%rbx, 24(up)
+	adc	%rbp, %rax
+	setc	R8(%rbp)
+	add	%rax, 32(up)
+	adc	$0, R32(%rbp)
+	lea	8(up), up
+	dec	un
+	jne	L(out2)
+	jmp	L(ret)
+
+C =============================================================================
+L(b3):	cmp	$-3, dn
+	jnz	L(gt3)
+
+	mov	8(up), %r14
+	mov	16(up), %r9
+	mov	24(up), %rcx
+L(o3):	mulx(	-24,(dp), %r11, %r10)
+	mulx(	-16,(dp), %r13, %r12)
+	mulx(	-8,(dp), %rbx, %rax)
+	add	%r10, %r13
+	adc	%r12, %rbx
+	adc	$0, %rax
+	add	%r14, %r11
+	mov	%r9, %r14
+	adc	%r13, %r14
+	mov	%rcx, %r9
+	mov	%r8, %rdx			C dinv
+	mulx(	%r14, %rdx, %r12)		C next quotient
+	adc	%rbx, %r9
+	adc	%rbp, %rax
+	setc	R8(%rbp)
+	mov	32(up), %rcx
+	add	%rax, %rcx
+	adc	$0, R32(%rbp)
+	lea	8(up), up
+	dec	un
+	jne	L(o3)
+	mov	%r14, 8(up)
+	mov	%r9, 16(up)
+	mov	%rcx, 24(up)
+	jmp	L(ret)
+
+L(gt3):	cmp	$-7, dn
+	jnz	L(out3)
+
+L(o7):	mulx(	-56,(dp), %r11, %r10)
+	mulx(	-48,(dp), %rcx, %r12)
+	mulx(	-40,(dp), %rbx, %rax)
+	add	%r10, %rcx
+	adc	%r12, %rbx
+	adc	$0, %rax
+	mulx(	-32,(dp), %r9, %r14)
+	add	-24(up), %r11
+	mulx(	-24,(dp), %r11, %r10)
+	adc	-16(up), %rcx
+	mov	%rcx, -16(up)
+	mulx(	-16,(dp), %r13, %r12)
+	adc	%rbx, -8(up)
+	adc	%rax, %r9
+	mulx(	-8,(dp), %rbx, %rax)
+	adc	%r14, %r11
+	adc	%r10, %r13
+	adc	%r12, %rbx
+	adc	$0, %rax
+	mov	%r8, %rdx			C dinv
+	mulx(	%rcx, %rdx, %r12)		C next quotient
+	add	%r9, (up)
+	adc	%r11, 8(up)
+	adc	%r13, 16(up)
+	adc	%rbx, 24(up)
+	adc	%rbp, %rax
+	setc	R8(%rbp)
+	add	%rax, 32(up)
+	adc	$0, R32(%rbp)
+	lea	8(up), up
+	dec	un
+	jne	L(o7)
+	jmp	L(ret)
+
+L(out3):lea	3(dn), i
+	.byte	0xc4,0x22,0xa3,0xf6,0x14,0xf6		C mulx (dp,dn,8),%r11,%r10
+	.byte	0xc4,0x22,0x93,0xf6,0x64,0xf6,0x08	C mulx 8(dp,dn,8),%r13,%r12
+	.byte	0xc4,0xa2,0xe3,0xf6,0x44,0xf6,0x10	C mulx 16(dp,dn,8),%rbx,%rax
+	add	%r10, %r13
+	adc	%r12, %rbx
+	adc	$0, %rax
+	jmp	L(lo3)
+
+	ALIGN(16)
+L(top3):add	%r9, (up,i,8)
+L(lo3):	.byte	0xc4,0x62,0xb3,0xf6,0x04,0xce		C mulx (dp,i,8), %r9, %r8
+	adc	%r11, 8(up,i,8)
+	.byte	0xc4,0x62,0xa3,0xf6,0x54,0xce,0x08	C mulx 8(dp,i,8), %r11, %r10
+	adc	%r13, 16(up,i,8)
+	.byte	0xc4,0x62,0x93,0xf6,0x64,0xce,0x10	C mulx 16(dp,i,8), %r13, %r12
+	adc	%rbx, 24(up,i,8)
+	adc	%rax, %r9
+	.byte	0xc4,0xe2,0xe3,0xf6,0x44,0xce,0x18	C mulx 24(dp,i,8), %rbx, %rax
+	adc	%r8, %r11
+	adc	%r10, %r13
+	adc	%r12, %rbx
+	adc	$0, %rax
+	add	$4, i
+	js	L(top3)
+
+	mov	(%rsp), %rdx			C dinv
+	.byte	0xc4,0x22,0xeb,0xf6,0x64,0xf7,0x28	C mulx 40(up,dn,8), %rdx, %r12
+	add	%r9, (up)
+	adc	%r11, 8(up)
+	adc	%r13, 16(up)
+	adc	%rbx, 24(up)
+	adc	%rbp, %rax
+	setc	R8(%rbp)
+	add	%rax, 32(up)
+	adc	$0, R32(%rbp)
+	lea	8(up), up
+	dec	un
+	jne	L(out3)
+
+L(ret):	mov	%rbp, %rax
+	pop	%rsi			C dummy dealloc
+	pop	%rbx
+	pop	%rbp
+	pop	%r12
+	pop	%r13
+	pop	%r14
+	pop	%r15
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/zen/sqr_basecase.asm b/third_party/gmp/mpn/x86_64/zen/sqr_basecase.asm
new file mode 100644
index 0000000..a7c6127
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/zen/sqr_basecase.asm
@@ -0,0 +1,482 @@
+dnl  AMD64 mpn_sqr_basecase optimised for AMD Zen.
+
+dnl  Copyright 2012, 2013, 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+C TODO
+C  * Do overlapped software pipelining.  This should close the remaining gap to
+C    mul_basecase.
+C
+C  * Update un just once in the outer loop.
+C
+C  * Perhaps keep un and n pre-multiplied by 8, thus suppressing ",8" from
+C    loads and stores.  At least in some cases, the non-scaled form is faster.
+C
+C  * Optimise xit3 code, e.g., using shrx and sarx like in the main loop.
+C
+C  * The mul_1 feed-in code has gotten little attention and could probably be
+C    improved.  Perhaps even expand it to 4 separate loops to allow straight
+C    fall-through into the 4 addmul_1 loops.
+C
+C  * Clean up ad-hoc scratch register usage in the addmul_1 feed-in code blocks.
+
+define(`rp',      `%rdi')
+define(`up',      `%rsi')
+define(`un_param',`%rdx')
+
+define(`un',      `%rbp')
+define(`n',       `%rcx')
+
+C these are used just for the small op code
+define(`w0',	`%r8')
+define(`w1',	`%r9')
+define(`w2',	`%r10')
+define(`w3',	`%r11')
+
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+ASM_START()
+	TEXT
+	ALIGN(16)
+PROLOGUE(mpn_sqr_basecase)
+	FUNC_ENTRY(3)
+
+	cmp	$2, R32(un_param)
+	jae	L(gt1)
+
+	mov	(up), %rdx
+	mulx(	%rdx, %rax, %rdx)
+	mov	%rax, (rp)
+	mov	%rdx, 8(rp)
+	FUNC_EXIT()
+	ret
+
+L(gt1):	jne	L(gt2)
+
+	mov	(up), %rdx
+	mov	8(up), %rcx
+	mulx(	%rcx, %r9, %r10)	C v0 * v1	W 1 2
+	mulx(	%rdx, %rax, %r8)	C v0 * v0	W 0 1
+	mov	%rcx, %rdx
+	mulx(	%rdx, %r11, %rdx)	C v1 * v1	W 2 3
+	add	%r9, %r9		C		W 1
+	adc	%r10, %r10		C		W 2
+	adc	$0, %rdx		C		W 3
+	add	%r9, %r8		C W 1
+	adc	%r11, %r10		C W 2
+	adc	$0, %rdx		C W 3
+	mov	%rax, (rp)
+	mov	%r8, 8(rp)
+	mov	%r10, 16(rp)
+	mov	%rdx, 24(rp)
+	FUNC_EXIT()
+	ret
+
+L(gt2):	cmp	$4, R32(un_param)
+	jae	L(gt3)
+
+	push	%rbx
+	mov	(up), %rdx
+	mulx(	8,(up), w2, w3)
+	mulx(	16,(up), w0, w1)
+	add	w3, w0
+	mov	8(up), %rdx
+	mulx(	16,(up), %rax, w3)
+	adc	%rax, w1
+	adc	$0, w3
+	test	R32(%rbx), R32(%rbx)
+	mov	(up), %rdx
+	mulx(	%rdx, %rbx, %rcx)
+	mov	%rbx, (rp)
+	mov	8(up), %rdx
+	mulx(	%rdx, %rax, %rbx)
+	mov	16(up), %rdx
+	mulx(	%rdx, %rsi, %rdx)
+	adcx(	w2, w2)
+	adcx(	w0, w0)
+	adcx(	w1, w1)
+	adcx(	w3, w3)
+	adox(	w2, %rcx)
+	adox(	w0, %rax)
+	adox(	w1, %rbx)
+	adox(	w3, %rsi)
+	mov	$0, R32(%r8)
+	adox(	%r8, %rdx)
+	adcx(	%r8, %rdx)
+	mov	%rcx, 8(rp)
+	mov	%rax, 16(rp)
+	mov	%rbx, 24(rp)
+	mov	%rsi, 32(rp)
+	mov	%rdx, 40(rp)
+	pop	%rbx
+	FUNC_EXIT()
+	ret
+
+L(gt3):	push	%r15
+C	push	%r14
+	push	%r13
+	push	%r12
+	push	%rbp
+	push	%rbx
+	mov	R32(un_param), R32(un)
+
+	mov	(up), %rdx		C up[0]
+	mov	8(up), %r9		C up[1]
+
+	mulx(	%rdx, %rax, %r15)	C up[0]^2
+	mov	%rax, (rp)
+	shl	%rdx
+
+	lea	(up,un,8), up
+	lea	-32(rp,un,8), rp
+
+	neg	un
+	lea	4(un), n
+	and	$-4, n
+
+	test	$1, R8(un)
+	jnz	L(mx0)
+L(mx1):	test	$2, R8(un)
+	jz	L(mb3)
+
+L(mb1):	mulx(	%r9, %rbx, %rax)
+	.byte	0xc4,0x62,0xb3,0xf6,0x44,0xee,0x10	C mulx 16(up,un,8), %r9, %r8
+	.byte	0xc4,0x62,0xa3,0xf6,0x54,0xee,0x18	C mulx 24(up,un,8), %r11, %r10
+	add	%r15, %rbx
+	jmp	L(mlo1)
+
+L(mb3):	mulx(	%r9, %r11, %r10)
+	.byte	0xc4,0x62,0x93,0xf6,0x64,0xee,0x10	C mulx 16(up,un,8), %r13, %r12
+	.byte	0xc4,0xe2,0xe3,0xf6,0x44,0xee,0x18	C mulx 24(up,un,8), %rbx, %rax
+	add	%r15, %r11
+	jrcxz	L(n4)
+	jmp	L(mlo3)
+L(n4):	mov	%r11, 8(rp)
+	adc	%r10, %r13
+	adc	%r12, %rbx
+	jmp	L(m)
+
+L(mx0):	test	$2, R8(un)
+	jnz	L(mb0)
+
+L(mb2):	mulx(	%r9, %r13, %r12)
+	.byte	0xc4,0xe2,0xe3,0xf6,0x44,0xee,0x10	C mulx 16(up,un,8), %rbx, %rax
+	.byte	0xc4,0x62,0xb3,0xf6,0x44,0xee,0x18	C mulx 24(up,un,8), %r9, %r8
+	add	%r15, %r13
+	jmp	L(mlo2)
+
+L(mb0):	mulx(	%r9, %r9, %r8)
+	.byte	0xc4,0x62,0xa3,0xf6,0x54,0xee,0x10	C mulx 16(up,un,8), %r11, %r10
+	.byte	0xc4,0x62,0x93,0xf6,0x64,0xee,0x18	C mulx 24(up,un,8), %r13, %r12
+	add	%r15, %r9
+	jmp	L(mlo0)
+
+	ALIGN(16)
+L(mtop):jrcxz	L(mend)
+	adc	%r8, %r11
+	mov	%r9, (rp,n,8)
+L(mlo3):.byte	0xc4,0x62,0xb3,0xf6,0x04,0xce		C mulx (up,n,8), %r9, %r8
+	adc	%r10, %r13
+	mov	%r11, 8(rp,n,8)
+L(mlo2):.byte	0xc4,0x62,0xa3,0xf6,0x54,0xce,0x08	C mulx 8(up,n,8), %r11, %r10
+	adc	%r12, %rbx
+	mov	%r13, 16(rp,n,8)
+L(mlo1):.byte	0xc4,0x62,0x93,0xf6,0x64,0xce,0x10	C mulx 16(up,n,8), %r13, %r12
+	adc	%rax, %r9
+	mov	%rbx, 24(rp,n,8)
+L(mlo0):.byte	0xc4,0xe2,0xe3,0xf6,0x44,0xce,0x18	C mulx 24(up,n,8), %rbx, %rax
+	lea	4(n), n
+	jmp	L(mtop)
+
+L(mend):mov	%r9, (rp)
+	adc	%r8, %r11
+	mov	%r11, 8(rp)
+	adc	%r10, %r13
+	mov	%r13, 16(rp)
+	adc	%r12, %rbx
+	adc	$0, %rax
+	mov	%rbx, 24(rp)
+	mov	%rax, 32(rp)
+
+	lea	2(un), un
+
+	mov	$63, R32(%r15)			C keep at 63 for shrx/sarx.
+	test	$1, R8(un)
+	jz	L(x0)
+L(x1):	test	$2, R8(un)
+	jz	L(f3)
+	jmp	L(f1)
+L(x0):	test	$2, R8(un)
+	jz	L(f0)
+C	jmp	L(f2)
+
+L(f2):	mov	-8(up,un,8), %rdx		C up[0]
+	lea	2(un), n
+	lea	8(rp), rp
+	.byte	0xc4,0x62,0x82,0xf7,0x5c,0xee,0xf0	C sarx %r15, -16(up,un,8), %r11
+	.byte	0xc4,0x62,0x83,0xf7,0x6c,0xee,0xf0	C shrx %r15, -16(up,un,8), %r13
+	and	%rdx, %r11			C "ci" in C code
+	mulx(	%rdx, %rax, %r10)		C up[0]^2
+	lea	(%r13,%rdx,2), %rdx		C "u0" arg in C code
+	add	%rax, %r11
+
+	.byte	0xc4,0x62,0x93,0xf6,0x24,0xee		C mulx (up,un,8), %r13, %r12
+	.byte	0xc4,0xe2,0xe3,0xf6,0x44,0xee,0x08	C mulx 8(up,un,8), %rbx, %rax
+	adc	%r10, %r13
+	adc	%r12, %rbx
+	adc	$0, %rax
+	jmp	L(b2)
+
+	ALIGN(16)
+L(top2):add	%r9, (rp,n,8)
+L(b2):	.byte	0xc4,0x62,0xb3,0xf6,0x04,0xce		C mulx (up,n,8), %r9, %r8
+	adc	%r11, 8(rp,n,8)
+	.byte	0xc4,0x62,0xa3,0xf6,0x54,0xce,0x08	C mulx 8(up,n,8), %r11, %r10
+	adc	%r13, 16(rp,n,8)
+	.byte	0xc4,0x62,0x93,0xf6,0x64,0xce,0x10	C mulx 16(up,n,8), %r13, %r12
+	adc	%rbx, 24(rp,n,8)
+	adc	%rax, %r9
+	.byte	0xc4,0xe2,0xe3,0xf6,0x44,0xce,0x18	C mulx 24(up,n,8), %rbx, %rax
+	adc	%r8, %r11
+	adc	%r10, %r13
+	adc	%r12, %rbx
+	adc	$0, %rax
+	add	$4, n
+	jnz	L(top2)
+
+	inc	un
+	add	%r9, (rp)
+	adc	%r11, 8(rp)
+	adc	%r13, 16(rp)
+	adc	%rbx, 24(rp)
+	adc	$0, %rax
+	mov	%rax, 32(rp)
+
+L(f1):	mov	-8(up,un,8), %rdx		C up[0]
+	lea	1(un), n
+	lea	8(rp), rp
+	.byte	0xc4,0x62,0x82,0xf7,0x6c,0xee,0xf0	C sarx	%r15, -16(up,un,8), %r13
+	.byte	0xc4,0xe2,0x83,0xf7,0x5c,0xee,0xf0	C shrx	%r15, -16(up,un,8), %rbx
+	and	%rdx, %r13			C "ci" in C code
+	mulx(	%rdx, %rax, %r12)		C up[0]^2
+	lea	(%rbx,%rdx,2), %rdx		C "u0" arg in C code
+	add	%rax, %r13
+
+	.byte	0xc4,0xe2,0xe3,0xf6,0x04,0xee		C mulx (up,un,8), %rbx, %rax
+	adc	%r12, %rbx
+	adc	$0, %rax
+	.byte	0xc4,0x62,0xb3,0xf6,0x44,0xee,0x08	C mulx 8(up,un,8), %r9, %r8
+	jmp	L(b1)
+
+	ALIGN(16)
+L(top1):add	%r9, (rp,n,8)
+	.byte	0xc4,0x62,0xb3,0xf6,0x04,0xce		C mulx (up,n,8), %r9, %r8
+	adc	%r11, 8(rp,n,8)
+L(b1):	.byte	0xc4,0x62,0xa3,0xf6,0x54,0xce,0x08	C mulx 8(up,n,8), %r11, %r10
+	adc	%r13, 16(rp,n,8)
+	.byte	0xc4,0x62,0x93,0xf6,0x64,0xce,0x10	C mulx 16(up,n,8), %r13, %r12
+	adc	%rbx, 24(rp,n,8)
+	adc	%rax, %r9
+	.byte	0xc4,0xe2,0xe3,0xf6,0x44,0xce,0x18	C mulx 24(up,n,8), %rbx, %rax
+	adc	%r8, %r11
+	adc	%r10, %r13
+	adc	%r12, %rbx
+	adc	$0, %rax
+	add	$4, n
+	jnz	L(top1)
+
+	inc	un
+	add	%r9, (rp)
+	adc	%r11, 8(rp)
+	adc	%r13, 16(rp)
+	adc	%rbx, 24(rp)
+	adc	$0, %rax
+	mov	%rax, 32(rp)
+
+L(f0):	mov	-8(up,un,8), %rdx		C up[0]
+	lea	(un), n
+	lea	8(rp), rp
+	.byte	0xc4,0xe2,0x82,0xf7,0x5c,0xee,0xf0	C sarx	%r15, -16(up,un,8), %rbx
+	.byte	0xc4,0x62,0x83,0xf7,0x4c,0xee,0xf0	C shrx	%r15, -16(up,un,8), %r9
+	and	%rdx, %rbx			C "ci" in C code
+	mulx(	%rdx, %r10, %rax)		C up[0]^2
+	lea	(%r9,%rdx,2), %rdx		C "u0" arg in C code
+	add	%r10, %rbx
+	adc	$0, %rax			C "cin" in C code
+
+	.byte	0xc4,0x62,0xb3,0xf6,0x04,0xce		C mulx (up,un,8), %r9, %r8
+	.byte	0xc4,0x62,0xa3,0xf6,0x54,0xee,0x08	C mulx 8(up,un,8), %r11, %r10
+	jmp	L(b0)
+
+	ALIGN(16)
+L(top0):add	%r9, (rp,n,8)
+	.byte	0xc4,0x62,0xb3,0xf6,0x04,0xce		C mulx (up,n,8), %r9, %r8
+	adc	%r11, 8(rp,n,8)
+	.byte	0xc4,0x62,0xa3,0xf6,0x54,0xce,0x08	C mulx 8(up,n,8), %r11, %r10
+	adc	%r13, 16(rp,n,8)
+L(b0):	.byte	0xc4,0x62,0x93,0xf6,0x64,0xce,0x10	C mulx 16(up,n,8), %r13, %r12
+	adc	%rbx, 24(rp,n,8)
+	adc	%rax, %r9
+	.byte	0xc4,0xe2,0xe3,0xf6,0x44,0xce,0x18	C mulx 24(up,n,8), %rbx, %rax
+	adc	%r8, %r11
+	adc	%r10, %r13
+	adc	%r12, %rbx
+	adc	$0, %rax
+	add	$4, n
+	jnz	L(top0)
+
+	inc	un
+	add	%r9, (rp)
+	adc	%r11, 8(rp)
+	adc	%r13, 16(rp)
+	adc	%rbx, 24(rp)
+	adc	$0, %rax
+	mov	%rax, 32(rp)
+
+L(f3):	mov	-8(up,un,8), %rdx		C up[0]
+	lea	3(un), n
+	lea	8(rp), rp
+	.byte	0xc4,0x62,0x82,0xf7,0x4c,0xee,0xf0	C sarx %r15, -16(up,un,8), %r9
+	.byte	0xc4,0x62,0x83,0xf7,0x5c,0xee,0xf0	C shrx %r15, -16(up,un,8), %r11
+	and	%rdx, %r9			C "ci" in C code
+	mulx(	%rdx, %rax, %r8)		C up[0]^2
+	lea	(%r11,%rdx,2), %rdx		C "u0" arg in C code
+	add	%rax, %r9
+
+	.byte	0xc4,0x62,0xa3,0xf6,0x14,0xee		C mulx (%rsi,%rbp,8),%r11,%r10
+	.byte	0xc4,0x62,0x93,0xf6,0x64,0xee,0x08	C mulx 0x8(%rsi,%rbp,8),%r13,%r12
+	.byte	0xc4,0xe2,0xe3,0xf6,0x44,0xee,0x10	C mulx 0x10(%rsi,%rbp,8),%rbx,%rax
+	adc	%r8, %r11
+	adc	%r10, %r13
+	adc	%r12, %rbx
+	adc	$0, %rax
+	jrcxz	L(xit3)
+	jmp	L(top3)			C FIXME perhaps fall through
+
+	ALIGN(16)
+L(top3):add	%r9, (rp,n,8)
+	.byte	0xc4,0x62,0xb3,0xf6,0x04,0xce		C mulx (up,n,8), %r9, %r8
+	adc	%r11, 8(rp,n,8)
+	.byte	0xc4,0x62,0xa3,0xf6,0x54,0xce,0x08	C mulx 8(up,n,8), %r11, %r10
+	adc	%r13, 16(rp,n,8)
+	.byte	0xc4,0x62,0x93,0xf6,0x64,0xce,0x10	C mulx 16(up,n,8), %r13, %r12
+	adc	%rbx, 24(rp,n,8)
+	adc	%rax, %r9
+	.byte	0xc4,0xe2,0xe3,0xf6,0x44,0xce,0x18	C mulx 24(up,n,8), %rbx, %rax
+	adc	%r8, %r11
+	adc	%r10, %r13
+	adc	%r12, %rbx
+	adc	$0, %rax
+	add	$4, n
+	jnz	L(top3)
+
+	inc	un
+	add	%r9, (rp)
+	adc	%r11, 8(rp)
+	adc	%r13, 16(rp)
+	adc	%rbx, 24(rp)
+	adc	$0, %rax
+	mov	%rax, 32(rp)
+	jmp	L(f2)
+
+
+L(xit3):add	%r9, (rp)
+	adc	%r11, 8(rp)
+	adc	16(rp), %r13
+	adc	24(rp), %rbx
+L(m):	adc	$0, %rax
+	mov	%rax, 32(rp)
+	mov	-24(up), %rdx		C FIXME: CSE
+	mov	-32(up), %r9		C FIXME: CSE
+	sar	$63, %r9
+	and	%rdx, %r9
+	add	%r13, %r9
+	mulx(	%rdx, %rax, %r10)
+	mov	-16(up), %r8		C FIXME: CSE
+	adc	$0, %r10
+	add	%rax, %r9
+	adc	$0, %r10
+	mov	%r9, 16(rp)
+	mov	-32(up), %rax
+	shl	%rax
+	adc	%rdx, %rdx
+	mulx(	%r8, %r13, %r12)
+	mulx(	-8,(up), %r11, %rax)	C FIXME: CSE
+	add	%r10, %r13
+	adc	%r12, %r11
+	adc	$0, %rax
+	add	%rbx, %r13
+	mov	%r13, 24(rp)
+	adc	32(rp), %r11
+	adc	$0, %rax
+	mov	-16(up), %rdx		C FIXME: CSE
+	mov	-8(up), %r8		C FIXME: CSE
+	mov	-24(up), %r9
+	sar	$63, %r9
+	and	%rdx, %r9
+	add	%r11, %r9
+	mulx(	%rdx, %rbp, %r10)
+	adc	$0, %r10
+	add	%rbp, %r9
+	adc	$0, %r10
+	mov	%r9, 32(rp)
+	mov	-24(up), %rbp
+	shl	%rbp
+	adc	%rdx, %rdx
+	mulx(	%r8, %rbx, %rbp)
+	add	%r10, %rbx
+	adc	$0, %rbp
+	adc	%rbx, %rax
+	mov	%rax, 40(rp)
+	adc	$0, %rbp
+	mov	-8(up), %rdx		C FIXME: CSE
+	mov	-16(up), %r9		C FIXME: CSE
+	sar	$63, %r9
+	and	%rdx, %r9
+	add	%rbp, %r9
+	mulx(	%rdx, %rbp, %r10)
+	adc	$0, %r10
+	add	%rbp, %r9
+	adc	$0, %r10
+	mov	%r9, 48(rp)
+	mov	%r10, 56(rp)
+
+	pop	%rbx
+	pop	%rbp
+	pop	%r12
+	pop	%r13
+C	pop	%r14
+	pop	%r15
+
+	FUNC_EXIT()
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/mpn/x86_64/zen/sublsh1_n.asm b/third_party/gmp/mpn/x86_64/zen/sublsh1_n.asm
new file mode 100644
index 0000000..00f6dc9
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/zen/sublsh1_n.asm
@@ -0,0 +1,37 @@
+dnl  X86-64 mpn_sublsh1_n, mpn_sublsh1_nc.
+
+dnl  Copyright 2017 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+ABI_SUPPORT(DOS64)
+ABI_SUPPORT(STD64)
+
+MULFUNC_PROLOGUE(mpn_sublsh1_n mpn_sublsh1_nc)
+include_mpn(`x86_64/atom/sublsh1_n.asm')
diff --git a/third_party/gmp/mpn/x86_64/zen2/gmp-mparam.h b/third_party/gmp/mpn/x86_64/zen2/gmp-mparam.h
new file mode 100644
index 0000000..3748c5f
--- /dev/null
+++ b/third_party/gmp/mpn/x86_64/zen2/gmp-mparam.h
@@ -0,0 +1,276 @@
+/* AMD Zen2 gmp-mparam.h -- Compiler/machine parameter header file.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define GMP_LIMB_BITS 64
+#define GMP_LIMB_BYTES 8
+
+/* Disable use of slow functions.  FIXME: We should disable lib inclusion.  */
+#undef HAVE_NATIVE_mpn_mul_2
+#undef HAVE_NATIVE_mpn_addmul_2
+
+/* 3600-4400 MHz Matisse */
+/* FFT tuning limit = 703,392,483 */
+/* Generated by tuneup.c, 2019-10-19, gcc 8.3 */
+
+#define MOD_1_NORM_THRESHOLD                 0  /* always */
+#define MOD_1_UNNORM_THRESHOLD               0  /* always */
+#define MOD_1N_TO_MOD_1_1_THRESHOLD          4
+#define MOD_1U_TO_MOD_1_1_THRESHOLD          3
+#define MOD_1_1_TO_MOD_1_2_THRESHOLD         8
+#define MOD_1_2_TO_MOD_1_4_THRESHOLD        27
+#define PREINV_MOD_1_TO_MOD_1_THRESHOLD      1
+#define USE_PREINV_DIVREM_1                  1  /* native */
+#define DIV_QR_1_NORM_THRESHOLD              1
+#define DIV_QR_1_UNNORM_THRESHOLD        MP_SIZE_T_MAX  /* never */
+#define DIV_QR_2_PI2_THRESHOLD              13
+#define DIVEXACT_1_THRESHOLD                 0  /* always (native) */
+#define BMOD_1_TO_MOD_1_THRESHOLD           22
+
+#define DIV_1_VS_MUL_1_PERCENT             385
+
+#define MUL_TOOM22_THRESHOLD                19
+#define MUL_TOOM33_THRESHOLD               125
+#define MUL_TOOM44_THRESHOLD               196
+#define MUL_TOOM6H_THRESHOLD               276
+#define MUL_TOOM8H_THRESHOLD               369
+
+#define MUL_TOOM32_TO_TOOM43_THRESHOLD     121
+#define MUL_TOOM32_TO_TOOM53_THRESHOLD     138
+#define MUL_TOOM42_TO_TOOM53_THRESHOLD     129
+#define MUL_TOOM42_TO_TOOM63_THRESHOLD     132
+#define MUL_TOOM43_TO_TOOM54_THRESHOLD     185
+
+#define SQR_BASECASE_THRESHOLD               0  /* always (native) */
+#define SQR_TOOM2_THRESHOLD                 30
+#define SQR_TOOM3_THRESHOLD                117
+#define SQR_TOOM4_THRESHOLD                315
+#define SQR_TOOM6_THRESHOLD                446
+#define SQR_TOOM8_THRESHOLD                527
+
+#define MULMID_TOOM42_THRESHOLD             38
+
+#define MULMOD_BNM1_THRESHOLD               14
+#define SQRMOD_BNM1_THRESHOLD               20
+
+#define MUL_FFT_MODF_THRESHOLD             436  /* k = 5 */
+#define MUL_FFT_TABLE3                                      \
+  { {    436, 5}, {     25, 6}, {     25, 7}, {     13, 6}, \
+    {     27, 7}, {     15, 6}, {     31, 7}, {     25, 8}, \
+    {     13, 7}, {     28, 8}, {     15, 7}, {     32, 8}, \
+    {     17, 7}, {     35, 8}, {     19, 7}, {     39, 8}, \
+    {     27, 9}, {     15, 8}, {     35, 9}, {     19, 8}, \
+    {     41, 9}, {     23, 8}, {     49, 9}, {     27,10}, \
+    {     15, 9}, {     31, 8}, {     63, 9}, {     39,10}, \
+    {     23, 9}, {     51,11}, {     15,10}, {     31, 9}, \
+    {     71,10}, {     39, 9}, {     83,10}, {     47, 9}, \
+    {     95,10}, {     55,11}, {     31,10}, {     79,11}, \
+    {     47,10}, {     95,12}, {     31,11}, {     63,10}, \
+    {    135,11}, {     79,10}, {    159,11}, {     95,10}, \
+    {    191,12}, {     63,11}, {    127,10}, {    255, 9}, \
+    {    511,11}, {    143,10}, {    287, 9}, {    575,11}, \
+    {    159,12}, {     95,11}, {    191,13}, {     63,12}, \
+    {    127,11}, {    255,10}, {    511,11}, {    271,10}, \
+    {    543, 9}, {   1087,11}, {    287,10}, {    575,12}, \
+    {    159,11}, {    319,10}, {    639,11}, {    335,10}, \
+    {    671,11}, {    351,10}, {    703,11}, {    367,12}, \
+    {    191,11}, {    383,10}, {    767,11}, {    415,10}, \
+    {    831,12}, {    223,11}, {    447,13}, {    127,12}, \
+    {    255,11}, {    543,10}, {   1087,12}, {    287,11}, \
+    {    575,10}, {   1151,11}, {    607,10}, {   1215,12}, \
+    {    319,11}, {    639,10}, {   1279,11}, {    671,10}, \
+    {   1343,12}, {    351,11}, {    703,10}, {   1407,11}, \
+    {    735,13}, {    191,12}, {    383,11}, {    767,10}, \
+    {   1535,11}, {    799,12}, {    415,11}, {    831,10}, \
+    {   1663,12}, {    447,11}, {    895,12}, {    479,14}, \
+    {    127,13}, {    255,12}, {    543,11}, {   1087,10}, \
+    {   2175,12}, {    575,11}, {   1151,12}, {    607,11}, \
+    {   1215,10}, {   2431,13}, {    319,12}, {    639,11}, \
+    {   1279,12}, {    671,11}, {   1343,10}, {   2687,12}, \
+    {    703,11}, {   1471,10}, {   2943,13}, {    383,12}, \
+    {    767,11}, {   1535,12}, {    799,11}, {   1599,12}, \
+    {    831,11}, {   1663,13}, {    447,12}, {    959,11}, \
+    {   1919,10}, {   3839,14}, {    255,13}, {    511,12}, \
+    {   1087,11}, {   2175,13}, {    575,12}, {   1215,11}, \
+    {   2431,13}, {    639,12}, {   1343,11}, {   2687,13}, \
+    {    703,12}, {   1471,11}, {   2943,14}, {    383,13}, \
+    {    767,12}, {   1599,11}, {   3199,13}, {    831,12}, \
+    {   1727,13}, {    895,12}, {   1791,13}, {    959,12}, \
+    {   1919,11}, {   3839,14}, {    511,13}, {   1087,12}, \
+    {   2175,13}, {   1215,12}, {   2431,14}, {    639,13}, \
+    {   1343,12}, {   2687,13}, {   1471,12}, {   2943,11}, \
+    {   5887,14}, {    767,13}, {   1599,12}, {   3199,13}, \
+    {   1727,12}, {   3455,14}, {    895,13}, {   1919,12}, \
+    {   3839,11}, {   7679,15}, {    511,14}, {   1023,13}, \
+    {   2175,14}, {   1151,13}, {   2431,12}, {   4863,14}, \
+    {   1279,13}, {   2687,14}, {   1407,13}, {   2943,12}, \
+    {   5887,15}, {    767,14}, {   1535,13}, {   3199,14}, \
+    {   1663,13}, {   3455,12}, {   6911,14}, {   1919,13}, \
+    {   3839,16}, {    511,15}, {   1023,14}, {   2175,13}, \
+    {   4479,12}, {   8959,14}, {   2431,13}, {   4863,15}, \
+    {   1279,14}, {   2943,13}, {   5887,12}, {  11775,15}, \
+    {   1535,14}, {   3455,15}, {   1791,14}, {   3839,13}, \
+    {   7679,14}, {   3967,16}, {   1023,15}, {   2047,14}, \
+    {   4479,15}, {   2303,14}, {   4863,15}, {   2559,14}, \
+    {   5247,15}, {   2815,14}, {   5887,16}, {   1535,15}, \
+    {   3327,14}, {   6911,15}, {   3839,14}, {   7679,13}, \
+    {  15359,17}, {   1023,16}, {   2047,15}, {   4351,14}, \
+    {   8959,15}, {   4863,16}, {   2559,15}, {   5887,14}, \
+    {  11775,16}, {   3071,15}, {   6911,16}, {   3583,15}, \
+    {   7679,14}, {  15359,15}, {   7935,17}, {   2047,16}, \
+    {   4095,15}, {   8959,16}, {   4607,15}, {   9983,14}, \
+    {  19967,16}, {   5631,15}, {  11775,17}, {   3071,16}, \
+    {   7679,15}, {  15871,18}, {   2047,17}, {   4095,16}, \
+    {   9727,15}, {  19967,17}, {   5119,16}, {  65536,17}, \
+    { 131072,18}, { 262144,19}, { 524288,20}, {1048576,21}, \
+    {2097152,22}, {4194304,23}, {8388608,24} }
+#define MUL_FFT_TABLE3_SIZE 275
+#define MUL_FFT_THRESHOLD                 4736
+
+#define SQR_FFT_MODF_THRESHOLD             396  /* k = 5 */
+#define SQR_FFT_TABLE3                                      \
+  { {    396, 5}, {     25, 6}, {     25, 7}, {     13, 6}, \
+    {     27, 7}, {     15, 6}, {     31, 7}, {     25, 8}, \
+    {     13, 7}, {     28, 8}, {     15, 7}, {     32, 8}, \
+    {     17, 7}, {     35, 8}, {     19, 7}, {     39, 8}, \
+    {     27, 9}, {     15, 8}, {     35, 9}, {     19, 8}, \
+    {     41, 9}, {     23, 8}, {     47, 9}, {     27,10}, \
+    {     15, 9}, {     39,10}, {     23, 9}, {     51,11}, \
+    {     15,10}, {     31, 9}, {     67,10}, {     39, 9}, \
+    {     79,10}, {     55,11}, {     31,10}, {     79,11}, \
+    {     47,10}, {     95,12}, {     31,11}, {     63,10}, \
+    {    135,11}, {     79,10}, {    159,11}, {     95,12}, \
+    {     63,11}, {    127,10}, {    255, 9}, {    511,11}, \
+    {    143,10}, {    287, 9}, {    575,10}, {    303,11}, \
+    {    159,12}, {     95,13}, {     63,12}, {    127,11}, \
+    {    255,10}, {    511,11}, {    271,10}, {    543,11}, \
+    {    287,10}, {    575,11}, {    303,12}, {    159,11}, \
+    {    319,10}, {    639,11}, {    335,10}, {    671, 9}, \
+    {   1343,11}, {    351,10}, {    703,11}, {    367,10}, \
+    {    735,11}, {    383,10}, {    767,11}, {    415,10}, \
+    {    831,12}, {    223,11}, {    447,13}, {    127,12}, \
+    {    255,11}, {    511,10}, {   1023,11}, {    543,10}, \
+    {   1087,12}, {    287,11}, {    575,10}, {   1151,11}, \
+    {    607,10}, {   1215,12}, {    319,11}, {    639,10}, \
+    {   1279,11}, {    671,10}, {   1343,12}, {    351,11}, \
+    {    703,10}, {   1407,11}, {    735,10}, {   1471,12}, \
+    {    383,11}, {    767,10}, {   1535,11}, {    799,12}, \
+    {    415,11}, {    831,10}, {   1663,12}, {    447,11}, \
+    {    895,12}, {    479,11}, {    959,14}, {    127,12}, \
+    {    511,11}, {   1023,12}, {    543,11}, {   1087,10}, \
+    {   2175,12}, {    575,11}, {   1151,12}, {    607,11}, \
+    {   1215,10}, {   2431,12}, {    639,11}, {   1279,12}, \
+    {    671,11}, {   1343,10}, {   2687,12}, {    703,11}, \
+    {   1407,12}, {    735,11}, {   1471,10}, {   2943,13}, \
+    {    383,12}, {    767,11}, {   1535,12}, {    799,11}, \
+    {   1599,12}, {    831,11}, {   1663,13}, {    447,12}, \
+    {    959,11}, {   1919,10}, {   3839,13}, {    511,12}, \
+    {   1087,11}, {   2175,13}, {    575,12}, {   1215,11}, \
+    {   2431,13}, {    639,12}, {   1343,11}, {   2687,13}, \
+    {    703,12}, {   1471,11}, {   2943,14}, {    383,13}, \
+    {    767,12}, {   1599,13}, {    831,12}, {   1727,11}, \
+    {   3455,13}, {    959,12}, {   1919,11}, {   3839,14}, \
+    {    511,13}, {   1023,12}, {   2047,13}, {   1087,12}, \
+    {   2175,13}, {   1215,12}, {   2431,11}, {   4863,14}, \
+    {    639,13}, {   1343,12}, {   2687,13}, {   1471,12}, \
+    {   2943,11}, {   5887,14}, {    767,13}, {   1599,12}, \
+    {   3199,13}, {   1727,12}, {   3455,14}, {    895,13}, \
+    {   1919,12}, {   3839,15}, {    511,14}, {   1023,13}, \
+    {   2175,14}, {   1151,13}, {   2431,12}, {   4863,14}, \
+    {   1279,13}, {   2687,14}, {   1407,13}, {   2943,12}, \
+    {   5887,15}, {    767,14}, {   1535,13}, {   3199,14}, \
+    {   1663,13}, {   3455,12}, {   6911,14}, {   1919,13}, \
+    {   3839,12}, {   7679,16}, {    511,15}, {   1023,14}, \
+    {   2175,13}, {   4479,14}, {   2431,13}, {   4863,15}, \
+    {   1279,14}, {   2943,13}, {   5887,12}, {  11775,15}, \
+    {   1535,14}, {   3455,13}, {   6911,15}, {   1791,14}, \
+    {   3839,13}, {   7679,14}, {   3967,16}, {   1023,15}, \
+    {   2047,14}, {   4479,15}, {   2303,14}, {   4863,15}, \
+    {   2559,14}, {   5247,15}, {   2815,14}, {   5887,13}, \
+    {  11775,16}, {   1535,15}, {   3071,14}, {   6143,15}, \
+    {   3327,14}, {   6911,15}, {   3839,14}, {   7679,17}, \
+    {   1023,16}, {   2047,15}, {   4095,14}, {   8191,15}, \
+    {   4351,14}, {   8959,15}, {   4863,16}, {   2559,15}, \
+    {   5887,14}, {  11775,16}, {   3071,15}, {   6911,16}, \
+    {   3583,15}, {   7679,14}, {  15359,15}, {   7935,17}, \
+    {   2047,16}, {   4095,15}, {   8959,16}, {   4607,15}, \
+    {   9983,14}, {  19967,16}, {   5119,15}, {  10239,16}, \
+    {   5631,15}, {  11775,17}, {   3071,16}, {   7679,15}, \
+    {  15359,18}, {   2047,17}, {   4095,16}, {   9727,15}, \
+    {  19967,17}, {   5119,16}, {  65536,17}, { 131072,18}, \
+    { 262144,19}, { 524288,20}, {1048576,21}, {2097152,22}, \
+    {4194304,23}, {8388608,24} }
+#define SQR_FFT_TABLE3_SIZE 282
+#define SQR_FFT_THRESHOLD                 3264
+
+#define MULLO_BASECASE_THRESHOLD             0  /* always */
+#define MULLO_DC_THRESHOLD                  57
+#define MULLO_MUL_N_THRESHOLD             8907
+#define SQRLO_BASECASE_THRESHOLD             8
+#define SQRLO_DC_THRESHOLD                   0  /* never mpn_sqrlo_basecase */
+#define SQRLO_SQR_THRESHOLD               6440
+
+#define DC_DIV_QR_THRESHOLD                 43
+#define DC_DIVAPPR_Q_THRESHOLD             154
+#define DC_BDIV_QR_THRESHOLD                46
+#define DC_BDIV_Q_THRESHOLD                 93
+
+#define INV_MULMOD_BNM1_THRESHOLD           36
+#define INV_NEWTON_THRESHOLD               141
+#define INV_APPR_THRESHOLD                 149
+
+#define BINV_NEWTON_THRESHOLD              264
+#define REDC_1_TO_REDC_N_THRESHOLD          47
+
+#define MU_DIV_QR_THRESHOLD               1470
+#define MU_DIVAPPR_Q_THRESHOLD            1528
+#define MUPI_DIV_QR_THRESHOLD               47
+#define MU_BDIV_QR_THRESHOLD              1187
+#define MU_BDIV_Q_THRESHOLD               1589
+
+#define POWM_SEC_TABLE  3,22,194,579
+
+#define GET_STR_DC_THRESHOLD                12
+#define GET_STR_PRECOMPUTE_THRESHOLD        19
+#define SET_STR_DC_THRESHOLD               195
+#define SET_STR_PRECOMPUTE_THRESHOLD      1752
+
+#define FAC_DSC_THRESHOLD                  345
+#define FAC_ODD_THRESHOLD                    0  /* always */
+
+#define MATRIX22_STRASSEN_THRESHOLD         24
+#define HGCD2_DIV1_METHOD                    1  /* 11.29% faster than 3 */
+#define HGCD_THRESHOLD                      89
+#define HGCD_APPR_THRESHOLD                 96
+#define HGCD_REDUCE_THRESHOLD             2681
+#define GCD_DC_THRESHOLD                   465
+#define GCDEXT_DC_THRESHOLD                233
+#define JACOBI_BASE_METHOD                   1  /* 25.56% faster than 4 */
+
+/* Tuneup completed successfully, took 294200 seconds */
diff --git a/third_party/gmp/mpq/Makefile.am b/third_party/gmp/mpq/Makefile.am
new file mode 100644
index 0000000..6d65774
--- /dev/null
+++ b/third_party/gmp/mpq/Makefile.am
@@ -0,0 +1,41 @@
+## Process this file with automake to generate Makefile.in
+
+# Copyright 1996, 1998, 2000-2002 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+
+AM_CPPFLAGS = -D__GMP_WITHIN_GMP -I$(top_srcdir)
+
+noinst_LTLIBRARIES = libmpq.la
+libmpq_la_SOURCES =							\
+  abs.c aors.c canonicalize.c clear.c clears.c				\
+  cmp.c cmp_si.c cmp_ui.c div.c equal.c					\
+  get_d.c get_den.c get_num.c get_str.c					\
+  init.c inits.c inp_str.c inv.c md_2exp.c mul.c neg.c out_str.c	\
+  set.c set_den.c set_num.c set_si.c set_str.c set_ui.c set_z.c set_d.c	\
+  set_f.c swap.c
diff --git a/third_party/gmp/mpq/Makefile.in b/third_party/gmp/mpq/Makefile.in
new file mode 100644
index 0000000..0a74ca3
--- /dev/null
+++ b/third_party/gmp/mpq/Makefile.in
@@ -0,0 +1,650 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Copyright 1996, 1998, 2000-2002 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = mpq
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libmpq_la_LIBADD =
+am_libmpq_la_OBJECTS = abs.lo aors.lo canonicalize.lo clear.lo \
+	clears.lo cmp.lo cmp_si.lo cmp_ui.lo div.lo equal.lo get_d.lo \
+	get_den.lo get_num.lo get_str.lo init.lo inits.lo inp_str.lo \
+	inv.lo md_2exp.lo mul.lo neg.lo out_str.lo set.lo set_den.lo \
+	set_num.lo set_si.lo set_str.lo set_ui.lo set_z.lo set_d.lo \
+	set_f.lo swap.lo
+libmpq_la_OBJECTS = $(am_libmpq_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp =
+am__depfiles_maybe =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+SOURCES = $(libmpq_la_SOURCES)
+DIST_SOURCES = $(libmpq_la_SOURCES)
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ABI = @ABI@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+ASMFLAGS = @ASMFLAGS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CALLING_CONVENTIONS_OBJS = @CALLING_CONVENTIONS_OBJS@
+CC = @CC@
+CCAS = @CCAS@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPP_FOR_BUILD = @CPP_FOR_BUILD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFN_LONG_LONG_LIMB = @DEFN_LONG_LONG_LIMB@
+DEFS = @DEFS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@
+FGREP = @FGREP@
+GMP_LDFLAGS = @GMP_LDFLAGS@
+GMP_LIMB_BITS = @GMP_LIMB_BITS@
+GMP_NAIL_BITS = @GMP_NAIL_BITS@
+GREP = @GREP@
+HAVE_CLOCK_01 = @HAVE_CLOCK_01@
+HAVE_CPUTIME_01 = @HAVE_CPUTIME_01@
+HAVE_GETRUSAGE_01 = @HAVE_GETRUSAGE_01@
+HAVE_GETTIMEOFDAY_01 = @HAVE_GETTIMEOFDAY_01@
+HAVE_HOST_CPU_FAMILY_power = @HAVE_HOST_CPU_FAMILY_power@
+HAVE_HOST_CPU_FAMILY_powerpc = @HAVE_HOST_CPU_FAMILY_powerpc@
+HAVE_SIGACTION_01 = @HAVE_SIGACTION_01@
+HAVE_SIGALTSTACK_01 = @HAVE_SIGALTSTACK_01@
+HAVE_SIGSTACK_01 = @HAVE_SIGSTACK_01@
+HAVE_STACK_T_01 = @HAVE_STACK_T_01@
+HAVE_SYS_RESOURCE_H_01 = @HAVE_SYS_RESOURCE_H_01@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCURSES = @LIBCURSES@
+LIBGMPXX_LDFLAGS = @LIBGMPXX_LDFLAGS@
+LIBGMP_DLL = @LIBGMP_DLL@
+LIBGMP_LDFLAGS = @LIBGMP_LDFLAGS@
+LIBM = @LIBM@
+LIBM_FOR_BUILD = @LIBM_FOR_BUILD@
+LIBOBJS = @LIBOBJS@
+LIBREADLINE = @LIBREADLINE@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+M4 = @M4@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPEED_CYCLECOUNTER_OBJ = @SPEED_CYCLECOUNTER_OBJ@
+STRIP = @STRIP@
+TAL_OBJECT = @TAL_OBJECT@
+TUNE_LIBS = @TUNE_LIBS@
+TUNE_SQR_OBJ = @TUNE_SQR_OBJ@
+U_FOR_BUILD = @U_FOR_BUILD@
+VERSION = @VERSION@
+WITH_READLINE_01 = @WITH_READLINE_01@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__leading_dot = @am__leading_dot@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gmp_srclinks = @gmp_srclinks@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+mpn_objects = @mpn_objects@
+mpn_objs_in_libgmp = @mpn_objs_in_libgmp@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_CPPFLAGS = -D__GMP_WITHIN_GMP -I$(top_srcdir)
+noinst_LTLIBRARIES = libmpq.la
+libmpq_la_SOURCES = \
+  abs.c aors.c canonicalize.c clear.c clears.c				\
+  cmp.c cmp_si.c cmp_ui.c div.c equal.c					\
+  get_d.c get_den.c get_num.c get_str.c					\
+  init.c inits.c inp_str.c inv.c md_2exp.c mul.c neg.c out_str.c	\
+  set.c set_den.c set_num.c set_si.c set_str.c set_ui.c set_z.c set_d.c	\
+  set_f.c swap.c
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu --ignore-deps mpq/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu --ignore-deps mpq/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+	@list='$(noinst_LTLIBRARIES)'; \
+	locs=`for p in $$list; do echo $$p; done | \
+	      sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+	      sort -u`; \
+	test -z "$$locs" || { \
+	  echo rm -f $${locs}; \
+	  rm -f $${locs}; \
+	}
+
+libmpq.la: $(libmpq_la_OBJECTS) $(libmpq_la_DEPENDENCIES) $(EXTRA_libmpq_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(LINK)  $(libmpq_la_OBJECTS) $(libmpq_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+.c.o:
+	$(AM_V_CC)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+	$(AM_V_CC)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+	$(AM_V_CC)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+	clean-libtool clean-noinstLTLIBRARIES cscopelist-am ctags \
+	ctags-am distclean distclean-compile distclean-generic \
+	distclean-libtool distclean-tags distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-dvi install-dvi-am install-exec \
+	install-exec-am install-html install-html-am install-info \
+	install-info-am install-man install-pdf install-pdf-am \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/third_party/gmp/mpq/abs.c b/third_party/gmp/mpq/abs.c
new file mode 100644
index 0000000..1f0bf13
--- /dev/null
+++ b/third_party/gmp/mpq/abs.c
@@ -0,0 +1,55 @@
+/* mpq_abs -- absolute value of a rational.
+
+Copyright 2000, 2001, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define __GMP_FORCE_mpq_abs 1
+
+#include "gmp-impl.h"
+
+
+void
+mpq_abs (mpq_ptr dst, mpq_srcptr src)
+{
+  mp_size_t  num_abs_size = ABSIZ(NUM(src));
+
+  if (dst != src)
+    {
+      mp_size_t  den_size = SIZ(DEN(src));
+      mp_ptr dp;
+
+      dp = MPZ_NEWALLOC (NUM(dst), num_abs_size);
+      MPN_COPY (dp, PTR(NUM(src)), num_abs_size);
+
+      dp = MPZ_NEWALLOC (DEN(dst), den_size);
+      SIZ(DEN(dst)) = den_size;
+      MPN_COPY (dp, PTR(DEN(src)), den_size);
+    }
+
+  SIZ(NUM(dst)) = num_abs_size;
+}
diff --git a/third_party/gmp/mpq/aors.c b/third_party/gmp/mpq/aors.c
new file mode 100644
index 0000000..e86af94
--- /dev/null
+++ b/third_party/gmp/mpq/aors.c
@@ -0,0 +1,112 @@
+/* mpq_add, mpq_sub -- add or subtract rational numbers.
+
+Copyright 1991, 1994-1997, 2000, 2001, 2004, 2005 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+static void __gmpq_aors (REGPARM_3_1 (mpq_ptr, mpq_srcptr, mpq_srcptr, void (*) (mpz_ptr, mpz_srcptr, mpz_srcptr))) REGPARM_ATTR (1);
+#define mpq_aors(w,x,y,fun)  __gmpq_aors (REGPARM_3_1 (w, x, y, fun))
+
+REGPARM_ATTR (1) static void
+mpq_aors (mpq_ptr rop, mpq_srcptr op1, mpq_srcptr op2,
+          void (*fun) (mpz_ptr, mpz_srcptr, mpz_srcptr))
+{
+  mpz_t gcd;
+  mpz_t tmp1, tmp2;
+  mp_size_t op1_num_size = ABSIZ(NUM(op1));
+  mp_size_t op1_den_size =   SIZ(DEN(op1));
+  mp_size_t op2_num_size = ABSIZ(NUM(op2));
+  mp_size_t op2_den_size =   SIZ(DEN(op2));
+  TMP_DECL;
+
+  TMP_MARK;
+  MPZ_TMP_INIT (gcd, MIN (op1_den_size, op2_den_size));
+  MPZ_TMP_INIT (tmp1, op1_num_size + op2_den_size);
+  MPZ_TMP_INIT (tmp2, op2_num_size + op1_den_size);
+
+  /* ROP might be identical to either operand, so don't store the
+     result there until we are finished with the input operands.  We
+     dare to overwrite the numerator of ROP when we are finished
+     with the numerators of OP1 and OP2.  */
+
+  mpz_gcd (gcd, DEN(op1), DEN(op2));
+  if (! MPZ_EQUAL_1_P (gcd))
+    {
+      mpz_t t;
+
+      MPZ_TMP_INIT (t, MAX (op1_num_size + op2_den_size,
+	     op2_num_size + op1_den_size) + 2 - SIZ(gcd));
+
+      mpz_divexact_gcd (t, DEN(op2), gcd);
+      mpz_divexact_gcd (tmp2, DEN(op1), gcd);
+
+      mpz_mul (tmp1, NUM(op1), t);
+      mpz_mul (t, NUM(op2), tmp2);
+
+      (*fun) (t, tmp1, t);
+
+      mpz_gcd (gcd, t, gcd);
+      if (MPZ_EQUAL_1_P (gcd))
+        {
+          mpz_set (NUM(rop), t);
+          mpz_mul (DEN(rop), DEN(op2), tmp2);
+        }
+      else
+        {
+          mpz_divexact_gcd (NUM(rop), t, gcd);
+          mpz_divexact_gcd (tmp1, DEN(op2), gcd);
+          mpz_mul (DEN(rop), tmp1, tmp2);
+        }
+    }
+  else
+    {
+      /* The common divisor is 1.  This is the case (for random input) with
+	 probability 6/(pi**2), which is about 60.8%.  */
+      mpz_mul (tmp1, NUM(op1), DEN(op2));
+      mpz_mul (tmp2, NUM(op2), DEN(op1));
+      (*fun) (NUM(rop), tmp1, tmp2);
+      mpz_mul (DEN(rop), DEN(op1), DEN(op2));
+    }
+  TMP_FREE;
+}
+
+
+void
+mpq_add (mpq_ptr rop, mpq_srcptr op1, mpq_srcptr op2)
+{
+  mpq_aors (rop, op1, op2, mpz_add);
+}
+
+void
+mpq_sub (mpq_ptr rop, mpq_srcptr op1, mpq_srcptr op2)
+{
+  mpq_aors (rop, op1, op2, mpz_sub);
+}
diff --git a/third_party/gmp/mpq/canonicalize.c b/third_party/gmp/mpq/canonicalize.c
new file mode 100644
index 0000000..cbc0a22
--- /dev/null
+++ b/third_party/gmp/mpq/canonicalize.c
@@ -0,0 +1,61 @@
+/* mpq_canonicalize(op) -- Remove common factors of the denominator and
+   numerator in OP.
+
+Copyright 1991, 1994-1996, 2000, 2001, 2005, 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpq_canonicalize (mpq_t op)
+{
+  mpz_t gcd;
+  TMP_DECL;
+
+  if (SIZ(DEN(op)) < 0)
+    {
+      SIZ(NUM(op)) = -SIZ(NUM(op));
+      SIZ(DEN(op)) = -SIZ(DEN(op));
+    }
+  else if (UNLIKELY (SIZ(DEN(op)) == 0))
+    DIVIDE_BY_ZERO;
+
+  TMP_MARK;
+
+  /* ??? Dunno if the 1+ is needed.  */
+  MPZ_TMP_INIT (gcd, 1 + MAX (ABSIZ(NUM(op)),
+			      SIZ(DEN(op))));
+
+  mpz_gcd (gcd, NUM(op), DEN(op));
+  if (! MPZ_EQUAL_1_P (gcd))
+    {
+      mpz_divexact_gcd (NUM(op), NUM(op), gcd);
+      mpz_divexact_gcd (DEN(op), DEN(op), gcd);
+    }
+  TMP_FREE;
+}
diff --git a/third_party/gmp/mpq/clear.c b/third_party/gmp/mpq/clear.c
new file mode 100644
index 0000000..65e899f
--- /dev/null
+++ b/third_party/gmp/mpq/clear.c
@@ -0,0 +1,41 @@
+/* mpq_clear -- free the space occupied by an mpq_t.
+
+Copyright 1991, 1994, 1995, 2000, 2001, 2015, 2018 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpq_clear (mpq_t x)
+{
+  if (ALLOC (NUM(x)))
+    __GMP_FREE_FUNC_LIMBS (PTR(NUM(x)), ALLOC(NUM(x)));
+  if (ALLOC (DEN(x)))
+    __GMP_FREE_FUNC_LIMBS (PTR(DEN(x)), ALLOC(DEN(x)));
+}
diff --git a/third_party/gmp/mpq/clears.c b/third_party/gmp/mpq/clears.c
new file mode 100644
index 0000000..68c6ad3
--- /dev/null
+++ b/third_party/gmp/mpq/clears.c
@@ -0,0 +1,52 @@
+/* mpq_clears() -- Clear multiple mpq_t variables.
+
+Copyright 2009, 2014, 2015, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+#include "gmp-impl.h"
+
+void
+mpq_clears (mpq_ptr x, ...)
+{
+  va_list  ap;
+
+  va_start (ap, x);
+
+  do
+    {
+      if (ALLOC (NUM(x)))
+	__GMP_FREE_FUNC_LIMBS (PTR(NUM(x)), ALLOC(NUM(x)));
+      if (ALLOC (DEN(x)))
+	__GMP_FREE_FUNC_LIMBS (PTR(DEN(x)), ALLOC(DEN(x)));
+      x = va_arg (ap, mpq_ptr);
+    }
+  while (x != NULL);
+
+  va_end (ap);
+}
diff --git a/third_party/gmp/mpq/cmp.c b/third_party/gmp/mpq/cmp.c
new file mode 100644
index 0000000..d3eefe2
--- /dev/null
+++ b/third_party/gmp/mpq/cmp.c
@@ -0,0 +1,168 @@
+/* mpq_cmp(u,v) -- Compare U, V.  Return positive, zero, or negative
+   based on if U > V, U == V, or U < V.
+
+Copyright 1991, 1994, 1996, 2001, 2002, 2005, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+static int
+mpq_cmp_numden (mpq_srcptr op1, mpz_srcptr num_op2, mpz_srcptr den_op2)
+{
+  mp_size_t num1_size = SIZ(NUM(op1));
+  mp_size_t den1_size = SIZ(DEN(op1));
+  mp_size_t num2_size = SIZ(num_op2);
+  mp_size_t den2_size = SIZ(den_op2);
+  int op2_is_int;
+  mp_limb_t d1h, d2h;
+  mp_size_t tmp1_size, tmp2_size;
+  mp_ptr tmp1_ptr, tmp2_ptr;
+  mp_size_t num1_sign;
+  int cc;
+  TMP_DECL;
+
+  /* need canonical signs to get right result */
+  ASSERT (den1_size > 0);
+  ASSERT (den2_size > 0);
+
+  if (num1_size == 0)
+    return -num2_size;
+  if (num2_size == 0)
+    return num1_size;
+  if ((num1_size ^ num2_size) < 0) /* I.e. are the signs different? */
+    return num1_size;
+
+  num1_sign = num1_size;
+  num1_size = ABS (num1_size);
+
+  /* THINK: Does storing d1h and d2h make sense? */
+  d1h = PTR(DEN(op1))[den1_size - 1];
+  d2h = PTR(den_op2)[den2_size - 1];
+  op2_is_int = (den2_size | d2h) == 1;
+  if ((unsigned) op2_is_int == (den1_size | d1h)) /* Both ops are integers */
+    /* return mpz_cmp (NUM (op1), num_op2); */
+    {
+      int cmp;
+
+      if (num1_sign != num2_size)
+	return num1_sign - num2_size;
+
+      cmp = mpn_cmp (PTR(NUM(op1)), PTR(num_op2), num1_size);
+      return (num1_sign > 0 ? cmp : -cmp);
+    }
+
+  num2_size = ABS (num2_size);
+
+  tmp1_size = num1_size + den2_size;
+  tmp2_size = num2_size + den1_size;
+
+  /* 1. Check to see if we can tell which operand is larger by just looking at
+     the number of limbs.  */
+
+  /* NUM1 x DEN2 is either TMP1_SIZE limbs or TMP1_SIZE-1 limbs.
+     Same for NUM1 x DEN1 with respect to TMP2_SIZE.  */
+  if (tmp1_size > tmp2_size + 1)
+    /* NUM1 x DEN2 is surely larger in magnitude than NUM2 x DEN1.  */
+    return num1_sign;
+  if (tmp2_size + op2_is_int > tmp1_size + 1)
+    /* NUM1 x DEN2 is surely smaller in magnitude than NUM2 x DEN1.  */
+    return -num1_sign;
+
+  /* 2. Same, but compare the number of significant bits.  */
+  {
+    int cnt1, cnt2;
+    mp_bitcnt_t bits1, bits2;
+
+    count_leading_zeros (cnt1, PTR(NUM(op1))[num1_size - 1]);
+    count_leading_zeros (cnt2, d2h);
+    bits1 = (mp_bitcnt_t) tmp1_size * GMP_NUMB_BITS - cnt1 - cnt2 + 2 * GMP_NAIL_BITS;
+
+    count_leading_zeros (cnt1, PTR(num_op2)[num2_size - 1]);
+    count_leading_zeros (cnt2, d1h);
+    bits2 = (mp_bitcnt_t) tmp2_size * GMP_NUMB_BITS - cnt1 - cnt2 + 2 * GMP_NAIL_BITS;
+
+    if (bits1 > bits2 + 1)
+      return num1_sign;
+    if (bits2 + op2_is_int > bits1 + 1)
+      return -num1_sign;
+  }
+
+  /* 3. Finally, cross multiply and compare.  */
+
+  TMP_MARK;
+  if (op2_is_int)
+    {
+      tmp2_ptr = TMP_ALLOC_LIMBS (tmp2_size);
+      tmp1_ptr = PTR(NUM(op1));
+      --tmp1_size;
+    }
+  else
+    {
+  TMP_ALLOC_LIMBS_2 (tmp1_ptr,tmp1_size, tmp2_ptr,tmp2_size);
+
+  if (num1_size >= den2_size)
+    tmp1_size -= 0 == mpn_mul (tmp1_ptr,
+			       PTR(NUM(op1)), num1_size,
+			       PTR(den_op2), den2_size);
+  else
+    tmp1_size -= 0 == mpn_mul (tmp1_ptr,
+			       PTR(den_op2), den2_size,
+			       PTR(NUM(op1)), num1_size);
+    }
+
+   if (num2_size >= den1_size)
+     tmp2_size -= 0 == mpn_mul (tmp2_ptr,
+				PTR(num_op2), num2_size,
+				PTR(DEN(op1)), den1_size);
+   else
+     tmp2_size -= 0 == mpn_mul (tmp2_ptr,
+				PTR(DEN(op1)), den1_size,
+				PTR(num_op2), num2_size);
+
+
+  cc = tmp1_size - tmp2_size != 0
+    ? tmp1_size - tmp2_size : mpn_cmp (tmp1_ptr, tmp2_ptr, tmp1_size);
+  TMP_FREE;
+  return num1_sign < 0 ? -cc : cc;
+}
+
+int
+mpq_cmp (mpq_srcptr op1, mpq_srcptr op2)
+{
+  return mpq_cmp_numden (op1, NUM(op2), DEN(op2));
+}
+
+int
+mpq_cmp_z (mpq_srcptr op1, mpz_srcptr op2)
+{
+  const static mp_limb_t one = 1;
+  const static mpz_t den = MPZ_ROINIT_N ((mp_limb_t *) &one, 1);
+
+  return mpq_cmp_numden (op1, op2, den);
+}
diff --git a/third_party/gmp/mpq/cmp_si.c b/third_party/gmp/mpq/cmp_si.c
new file mode 100644
index 0000000..faf472c
--- /dev/null
+++ b/third_party/gmp/mpq/cmp_si.c
@@ -0,0 +1,60 @@
+/* _mpq_cmp_si -- compare mpq and long/ulong fraction.
+
+Copyright 2001, 2013, 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* Something like mpq_cmpabs_ui would be more useful for the neg/neg case,
+   and perhaps a version accepting a parameter to reverse the test, to make
+   it a tail call here.  */
+
+int
+_mpq_cmp_si (mpq_srcptr q, long n, unsigned long d)
+{
+  /* need canonical sign to get right result */
+  ASSERT (SIZ(DEN(q)) > 0);
+
+  if (n >= 0)
+    return _mpq_cmp_ui (q, n, d);
+  if (SIZ(NUM(q)) >= 0)
+    {
+      return 1;                                /* >=0 cmp <0 */
+    }
+  else
+    {
+      mpq_t  qabs;
+      SIZ(NUM(qabs)) = -SIZ(NUM(q));
+      PTR(NUM(qabs)) = PTR(NUM(q));
+      SIZ(DEN(qabs)) = SIZ(DEN(q));
+      PTR(DEN(qabs)) = PTR(DEN(q));
+
+      return - _mpq_cmp_ui (qabs, NEG_CAST (unsigned long, n), d);    /* <0 cmp <0 */
+    }
+}
diff --git a/third_party/gmp/mpq/cmp_ui.c b/third_party/gmp/mpq/cmp_ui.c
new file mode 100644
index 0000000..9d99a9a
--- /dev/null
+++ b/third_party/gmp/mpq/cmp_ui.c
@@ -0,0 +1,99 @@
+/* mpq_cmp_ui(u,vn,vd) -- Compare U with Vn/Vd.  Return positive, zero, or
+   negative based on if U > V, U == V, or U < V.  Vn and Vd may have
+   common factors.
+
+Copyright 1993, 1994, 1996, 2000-2003, 2005, 2014, 2018 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+int
+_mpq_cmp_ui (mpq_srcptr op1, unsigned long int num2, unsigned long int den2)
+{
+  mp_size_t num1_size = SIZ(NUM(op1));
+  mp_size_t den1_size = SIZ(DEN(op1));
+  mp_size_t tmp1_size, tmp2_size;
+  mp_ptr tmp1_ptr, tmp2_ptr;
+  mp_limb_t cy_limb;
+  int cc;
+  TMP_DECL;
+
+#if GMP_NAIL_BITS != 0
+  if ((num2 | den2) > GMP_NUMB_MAX)
+    {
+      mpq_t op2;
+      mpq_init (op2);
+      mpz_set_ui (mpq_numref (op2), num2);
+      mpz_set_ui (mpq_denref (op2), den2);
+      cc = mpq_cmp (op1, op2);
+      mpq_clear (op2);
+      return cc;
+    }
+#endif
+
+  /* need canonical sign to get right result */
+  ASSERT (den1_size > 0);
+
+  if (UNLIKELY (den2 == 0))
+    DIVIDE_BY_ZERO;
+
+  if (num2 == 0)
+    return num1_size;
+  if (num1_size <= 0)
+    return -1;
+
+  /* NUM1 x DEN2 is either TMP1_SIZE limbs or TMP1_SIZE-1 limbs.
+     Same for NUM2 x DEN1 with respect to TMP2_SIZE.  */
+  /* If frac2 <= 1 (i.e. num2 <= den2), shortcut with a simpler
+     condition: num1 > den1. Here we only test sizes. */
+  if (num1_size > den1_size + (num2 > den2))
+    /* NUM1 x DEN2 is surely larger in magnitude than NUM2 x DEN1.  */
+    return num1_size;
+  if (den1_size > num1_size + (den2 > num2))
+    /* NUM1 x DEN2 is surely smaller in magnitude than NUM2 x DEN1.  */
+    return -num1_size;
+
+  TMP_MARK;
+  TMP_ALLOC_LIMBS_2 (tmp1_ptr, num1_size + 1, tmp2_ptr, den1_size + 1);
+
+  cy_limb = mpn_mul_1 (tmp1_ptr, PTR(NUM(op1)), num1_size,
+                       (mp_limb_t) den2);
+  tmp1_ptr[num1_size] = cy_limb;
+  tmp1_size = num1_size + (cy_limb != 0);
+
+  cy_limb = mpn_mul_1 (tmp2_ptr, PTR(DEN(op1)), den1_size,
+                       (mp_limb_t) num2);
+  tmp2_ptr[den1_size] = cy_limb;
+  tmp2_size = den1_size + (cy_limb != 0);
+
+  cc = tmp1_size - tmp2_size;
+  cc = cc != 0 ? cc : mpn_cmp (tmp1_ptr, tmp2_ptr, tmp1_size);
+  TMP_FREE;
+  return cc;
+}
diff --git a/third_party/gmp/mpq/div.c b/third_party/gmp/mpq/div.c
new file mode 100644
index 0000000..3bd9726
--- /dev/null
+++ b/third_party/gmp/mpq/div.c
@@ -0,0 +1,133 @@
+/* mpq_div -- divide two rational numbers.
+
+Copyright 1991, 1994-1996, 2000, 2001, 2015, 2018 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+void
+mpq_div (mpq_ptr quot, mpq_srcptr op1, mpq_srcptr op2)
+{
+  mpz_t gcd1, gcd2;
+  mpz_t tmp1, tmp2;
+  mp_size_t op1_size;
+  mp_size_t op2_size;
+  mp_size_t alloc;
+  TMP_DECL;
+
+  op2_size = SIZ(NUM(op2));
+
+  if (UNLIKELY (op2_size == 0))
+    DIVIDE_BY_ZERO;
+
+  if (UNLIKELY (quot == op2))
+    {
+      if (UNLIKELY (op1 == op2))
+	{
+	  mpq_set_ui (quot, 1, 1);
+	  return;
+	}
+
+      /* We checked for op1 == op2: we are not in the x=x/x case.
+	 We compute x=y/x by computing x=inv(x)*y */
+      MPN_PTR_SWAP (PTR(NUM(quot)), ALLOC(NUM(quot)),
+		    PTR(DEN(quot)), ALLOC(DEN(quot)));
+      if (op2_size > 0)
+	{
+	  SIZ(NUM(quot)) = SIZ(DEN(quot));
+	  SIZ(DEN(quot)) = op2_size;
+	}
+      else
+	{
+	  SIZ(NUM(quot)) = - SIZ(DEN(quot));
+	  SIZ(DEN(quot)) = - op2_size;
+	}
+      mpq_mul (quot, quot, op1);
+      return;
+    }
+
+  op1_size = ABSIZ(NUM(op1));
+
+  if (op1_size == 0)
+    {
+      /* We special case this to simplify allocation logic; gcd(0,x) = x
+	 is a singular case for the allocations.  */
+      SIZ(NUM(quot)) = 0;
+      MPZ_NEWALLOC (DEN(quot), 1)[0] = 1;
+      SIZ(DEN(quot)) = 1;
+      return;
+    }
+
+  op2_size = ABS(op2_size);
+
+  TMP_MARK;
+
+  alloc = MIN (op1_size, op2_size);
+  MPZ_TMP_INIT (gcd1, alloc);
+
+  alloc = MAX (op1_size, op2_size);
+  MPZ_TMP_INIT (tmp1, alloc);
+
+  op2_size = SIZ(DEN(op2));
+  op1_size = SIZ(DEN(op1));
+
+  alloc = MIN (op1_size, op2_size);
+  MPZ_TMP_INIT (gcd2, alloc);
+
+  alloc = MAX (op1_size, op2_size);
+  MPZ_TMP_INIT (tmp2, alloc);
+
+  /* QUOT might be identical to OP1, so don't store the result there
+     until we are finished with the input operand.  We can overwrite
+     the numerator of QUOT when we are finished with the numerator of
+     OP1. */
+
+  mpz_gcd (gcd1, NUM(op1), NUM(op2));
+  mpz_gcd (gcd2, DEN(op2), DEN(op1));
+
+  mpz_divexact_gcd (tmp1, NUM(op1), gcd1);
+  mpz_divexact_gcd (tmp2, DEN(op2), gcd2);
+
+  mpz_mul (NUM(quot), tmp1, tmp2);
+
+  mpz_divexact_gcd (tmp1, NUM(op2), gcd1);
+  mpz_divexact_gcd (tmp2, DEN(op1), gcd2);
+
+  mpz_mul (DEN(quot), tmp1, tmp2);
+
+  /* Keep the denominator positive.  */
+  if (SIZ(DEN(quot)) < 0)
+    {
+      SIZ(DEN(quot)) = -SIZ(DEN(quot));
+      SIZ(NUM(quot)) = -SIZ(NUM(quot));
+    }
+
+  TMP_FREE;
+}
diff --git a/third_party/gmp/mpq/equal.c b/third_party/gmp/mpq/equal.c
new file mode 100644
index 0000000..9835e04
--- /dev/null
+++ b/third_party/gmp/mpq/equal.c
@@ -0,0 +1,68 @@
+/* mpq_equal(u,v) -- Compare U, V.  Return non-zero if they are equal, zero
+   if they are non-equal.
+
+Copyright 1996, 2001, 2002, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+int
+mpq_equal (mpq_srcptr op1, mpq_srcptr op2) __GMP_NOTHROW
+{
+  mp_size_t  num1_size, num2_size, den1_size, den2_size, i;
+  mp_srcptr  num1_ptr,  num2_ptr,  den1_ptr,  den2_ptr;
+
+  /* need fully canonical for correct results */
+  ASSERT_MPQ_CANONICAL (op1);
+  ASSERT_MPQ_CANONICAL (op2);
+
+  num1_size = SIZ(NUM(op1));
+  num2_size = SIZ(NUM(op2));
+  if (num1_size != num2_size)
+    return 0;
+
+  den1_size = SIZ(DEN(op1));
+  den2_size = SIZ(DEN(op2));
+  if (den1_size != den2_size)
+    return 0;
+
+  num1_ptr = PTR(NUM(op1));
+  num2_ptr = PTR(NUM(op2));
+  num1_size = ABS (num1_size);
+  for (i = 0; i < num1_size; i++)
+    if (num1_ptr[i] != num2_ptr[i])
+      return 0;
+
+  den1_ptr = PTR(DEN(op1));
+  den2_ptr = PTR(DEN(op2));
+  for (i = 0; i < den1_size; i++)
+    if (den1_ptr[i] != den2_ptr[i])
+      return 0;
+
+  return 1;
+}
diff --git a/third_party/gmp/mpq/get_d.c b/third_party/gmp/mpq/get_d.c
new file mode 100644
index 0000000..4d9779d
--- /dev/null
+++ b/third_party/gmp/mpq/get_d.c
@@ -0,0 +1,162 @@
+/* double mpq_get_d (mpq_t src) -- mpq to double, rounding towards zero.
+
+Copyright 1995, 1996, 2001-2005, 2018, 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>  /* for NULL */
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* All that's needed is to get the high 53 bits of the quotient num/den,
+   rounded towards zero.  More than 53 bits is fine, any excess is ignored
+   by mpn_get_d.
+
+   N_QLIMBS is how many quotient limbs we need to satisfy the mantissa of a
+   double, assuming the highest of those limbs is non-zero.  The target
+   qsize for mpn_tdiv_qr is then 1 more than this, since that function may
+   give a zero in the high limb (and non-zero in the second highest).
+
+   The use of 8*sizeof(double) in N_QLIMBS is an overestimate of the
+   mantissa bits, but it gets the same result as the true value (53 or 48 or
+   whatever) when rounded up to a multiple of GMP_NUMB_BITS, for non-nails.
+
+   Enhancements:
+
+   Use the true mantissa size in the N_QLIMBS formula, to save a divide step
+   in nails.
+
+   Examine the high limbs of num and den to see if the highest 1 bit of the
+   quotient will fall high enough that just N_QLIMBS-1 limbs is enough to
+   get the necessary bits, thereby saving a division step.
+
+   Bit shift either num or den to arrange for the above condition on the
+   high 1 bit of the quotient, to save a division step always.  A shift to
+   save a division step is definitely worthwhile with mpn_tdiv_qr, though we
+   may want to reassess this on big num/den when a quotient-only division
+   exists.
+
+   Maybe we could estimate the final exponent using nsize-dsize (and
+   possibly the high limbs of num and den), so as to detect overflow and
+   return infinity or zero quickly.  Overflow is never very helpful to an
+   application, and can therefore probably be regarded as abnormal, but we
+   may still like to optimize it if the conditions are easy.  (This would
+   only be for float formats we know, unknown formats are not important and
+   can be left to mpn_get_d.)
+
+   Future:
+
+   If/when mpn_tdiv_qr supports its qxn parameter we can use that instead of
+   padding n with zeros in temporary space.
+
+   Alternatives:
+
+   An alternative algorithm, that may be faster:
+   0. Let n be somewhat larger than the number of significant bits in a double.
+   1. Extract the most significant n bits of the denominator, and an equal
+      number of bits from the numerator.
+   2. Interpret the extracted numbers as integers, call them a and b
+      respectively, and develop n bits of the fractions ((a + 1) / b) and
+      (a / (b + 1)) using mpn_divrem.
+   3. If the computed values are identical UP TO THE POSITION WE CARE ABOUT,
+      we are done.  If they are different, repeat the algorithm from step 1,
+      but first let n = n * 2.
+   4. If we end up using all bits from the numerator and denominator, fall
+      back to a plain division.
+   5. Just to make life harder, The computation of a + 1 and b + 1 above
+      might give carry-out...  Needs special handling.  It might work to
+      subtract 1 in both cases instead.
+
+   Not certain if this approach would be faster than a quotient-only
+   division.  Presumably such optimizations are the sort of thing we would
+   like to have helping everywhere that uses a quotient-only division. */
+
+double
+mpq_get_d (mpq_srcptr src)
+{
+  double res;
+  mp_srcptr np, dp;
+  mp_ptr temp;
+  mp_size_t nsize = SIZ(NUM(src));
+  mp_size_t dsize = SIZ(DEN(src));
+  mp_size_t qsize, prospective_qsize, zeros;
+  mp_size_t sign_quotient = nsize;
+  long exp;
+#define N_QLIMBS (1 + (sizeof (double) + GMP_LIMB_BYTES-1) / GMP_LIMB_BYTES)
+  mp_limb_t qarr[N_QLIMBS + 1];
+  mp_ptr qp = qarr;
+  TMP_DECL;
+
+  ASSERT (dsize > 0);    /* canonical src */
+
+  /* mpn_get_d below requires a non-zero operand */
+  if (UNLIKELY (nsize == 0))
+    return 0.0;
+
+  TMP_MARK;
+  nsize = ABS (nsize);
+  dsize = ABS (dsize);
+  np = PTR(NUM(src));
+  dp = PTR(DEN(src));
+
+  prospective_qsize = nsize - dsize;       /* from using given n,d */
+  qsize = N_QLIMBS;                        /* desired qsize */
+
+  zeros = qsize - prospective_qsize;       /* padding n to get qsize */
+  exp = (long) -zeros * GMP_NUMB_BITS;     /* relative to low of qp */
+
+  /* zero extend n into temporary space, if necessary */
+  if (zeros > 0)
+    {
+      mp_size_t tsize;
+      tsize = nsize + zeros;               /* size for copy of n */
+
+      temp = TMP_ALLOC_LIMBS (tsize + 1);
+      MPN_FILL (temp, zeros, 0);
+      MPN_COPY (temp + zeros, np, nsize);
+      np = temp;
+      nsize = tsize;
+    }
+  else /* negative zeros means shorten n */
+    {
+      np -= zeros;
+      nsize += zeros;
+
+      temp = TMP_ALLOC_LIMBS (nsize + 1);
+    }
+
+  ASSERT (qsize == nsize - dsize);
+  mpn_div_q (qp, np, nsize, dp, dsize, temp);
+
+  /* strip possible zero high limb */
+  qsize += (qp[qsize] != 0);
+
+  res = mpn_get_d (qp, qsize, sign_quotient, exp);
+  TMP_FREE;
+  return res;
+}
diff --git a/third_party/gmp/mpq/get_den.c b/third_party/gmp/mpq/get_den.c
new file mode 100644
index 0000000..d4fd90b
--- /dev/null
+++ b/third_party/gmp/mpq/get_den.c
@@ -0,0 +1,42 @@
+/* mpq_get_den(den,rat_src) -- Set DEN to the denominator of RAT_SRC.
+
+Copyright 1991, 1994, 1995, 2001, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpq_get_den (mpz_ptr den, mpq_srcptr src)
+{
+  mp_size_t size = SIZ(DEN(src));
+  mp_ptr dp;
+
+  dp = MPZ_NEWALLOC (den, size);
+  SIZ(den) = size;
+  MPN_COPY (dp, PTR(DEN(src)), size);
+}
diff --git a/third_party/gmp/mpq/get_num.c b/third_party/gmp/mpq/get_num.c
new file mode 100644
index 0000000..079211c
--- /dev/null
+++ b/third_party/gmp/mpq/get_num.c
@@ -0,0 +1,44 @@
+ /* mpq_get_num(num,rat_src) -- Set NUM to the numerator of RAT_SRC.
+
+Copyright 1991, 1994, 1995, 2001, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpq_get_num (mpz_ptr num, mpq_srcptr src)
+{
+  mp_size_t size = SIZ(NUM(src));
+  mp_size_t abs_size = ABS (size);
+  mp_ptr dp;
+
+  dp = MPZ_NEWALLOC (num, abs_size);
+  SIZ(num) = size;
+
+  MPN_COPY (dp, PTR(NUM(src)), abs_size);
+}
diff --git a/third_party/gmp/mpq/get_str.c b/third_party/gmp/mpq/get_str.c
new file mode 100644
index 0000000..d0cfb58
--- /dev/null
+++ b/third_party/gmp/mpq/get_str.c
@@ -0,0 +1,80 @@
+/* mpq_get_str -- mpq to string conversion.
+
+Copyright 2001, 2002, 2006, 2011, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <string.h>
+#include "gmp-impl.h"
+#include "longlong.h"
+
+char *
+mpq_get_str (char *str, int base, mpq_srcptr q)
+{
+  size_t  str_alloc, len;
+
+  if (base > 62 || base < -36)
+    return NULL;
+
+  str_alloc = 0;
+  if (str == NULL)
+    {
+      /* This is an overestimate since we don't bother checking how much of
+	 the high limbs of num and den are used.  +2 for rounding up the
+	 chars per bit of num and den.  +3 for sign, slash and '\0'.  */
+      if (ABS(base) < 2)
+	base = 10;
+      DIGITS_IN_BASE_PER_LIMB (str_alloc, ABSIZ(NUM(q)) + SIZ(DEN(q)), ABS(base));
+      str_alloc += 6;
+
+      str = __GMP_ALLOCATE_FUNC_TYPE (str_alloc, char);
+    }
+
+  mpz_get_str (str, base, mpq_numref(q));
+  len = strlen (str);
+  if (! MPZ_EQUAL_1_P (mpq_denref (q)))
+    {
+      str[len++] = '/';
+      mpz_get_str (str+len, base, mpq_denref(q));
+      len += strlen (str+len);
+    }
+
+  ASSERT (len == strlen(str));
+  ASSERT (str_alloc == 0 || len+1 <= str_alloc);
+  ASSERT (len+1 <= 3 + /* size recommended to applications */
+	  (ABS(base) < 2 ?
+	   mpz_sizeinbase (mpq_numref(q), 10) +
+	   mpz_sizeinbase (mpq_denref(q), 10)
+	   : mpz_sizeinbase (mpq_numref(q), ABS(base)) +
+	   mpz_sizeinbase (mpq_denref(q), ABS(base))));
+
+  if (str_alloc != 0)
+    __GMP_REALLOCATE_FUNC_MAYBE_TYPE (str, str_alloc, len+1, char);
+
+  return str;
+}
diff --git a/third_party/gmp/mpq/init.c b/third_party/gmp/mpq/init.c
new file mode 100644
index 0000000..b006945
--- /dev/null
+++ b/third_party/gmp/mpq/init.c
@@ -0,0 +1,45 @@
+/* mpq_init -- Make a new rational number with value 0/1.
+
+Copyright 1991, 1994, 1995, 2000-2002, 2015, 2018 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpq_init (mpq_t x)
+{
+  static const mp_limb_t dummy_limb=0xc1a0;
+  ALLOC(NUM(x)) = 0;
+  PTR(NUM(x)) = (mp_ptr) &dummy_limb;
+  SIZ(NUM(x)) = 0;
+  ALLOC(DEN(x)) = 1;
+  PTR(DEN(x)) = __GMP_ALLOCATE_FUNC_LIMBS (1);
+  PTR(DEN(x))[0] = 1;
+  SIZ(DEN(x)) = 1;
+}
diff --git a/third_party/gmp/mpq/inits.c b/third_party/gmp/mpq/inits.c
new file mode 100644
index 0000000..fff4343
--- /dev/null
+++ b/third_party/gmp/mpq/inits.c
@@ -0,0 +1,49 @@
+/* mpq_inits() -- Initialize multiple mpq_t variables and set them to 0.
+
+Copyright 2009, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+#include "gmp-impl.h"
+
+void
+mpq_inits (mpq_ptr x, ...)
+{
+  va_list  ap;
+
+  va_start (ap, x);
+
+  do
+    {
+      mpq_init (x);
+      x = va_arg (ap, mpq_ptr);
+    }
+  while (x != NULL);
+
+  va_end (ap);
+}
diff --git a/third_party/gmp/mpq/inp_str.c b/third_party/gmp/mpq/inp_str.c
new file mode 100644
index 0000000..b7662bc
--- /dev/null
+++ b/third_party/gmp/mpq/inp_str.c
@@ -0,0 +1,75 @@
+/* mpq_inp_str -- read an mpq from a FILE.
+
+Copyright 2001, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <ctype.h>
+#include "gmp-impl.h"
+
+
+size_t
+mpq_inp_str (mpq_ptr q, FILE *fp, int base)
+{
+  size_t  nread;
+  int     c;
+
+  if (fp == NULL)
+    fp = stdin;
+
+  SIZ(DEN(q)) = 1;
+  MPZ_NEWALLOC (DEN(q), 1)[0] = 1;
+
+  nread = mpz_inp_str (mpq_numref(q), fp, base);
+  if (nread == 0)
+    return 0;
+
+  c = getc (fp);
+  nread++;
+
+  if (c == '/')
+    {
+      c = getc (fp);
+      nread++;
+
+      nread = mpz_inp_str_nowhite (mpq_denref(q), fp, base, c, nread);
+      if (nread == 0)
+	{
+	  SIZ(NUM(q)) = 0;
+	  SIZ(DEN(q)) = 1;
+	  PTR(DEN(q))[0] = 1;
+	}
+    }
+  else
+    {
+      ungetc (c, fp);
+      nread--;
+    }
+
+  return nread;
+}
diff --git a/third_party/gmp/mpq/inv.c b/third_party/gmp/mpq/inv.c
new file mode 100644
index 0000000..c395984
--- /dev/null
+++ b/third_party/gmp/mpq/inv.c
@@ -0,0 +1,70 @@
+/* mpq_inv(dest,src) -- invert a rational number, i.e. set DEST to SRC
+   with the numerator and denominator swapped.
+
+Copyright 1991, 1994, 1995, 2000, 2001, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpq_inv (mpq_ptr dest, mpq_srcptr src)
+{
+  mp_size_t num_size = SIZ(NUM(src));
+  mp_size_t den_size = SIZ(DEN(src));
+
+  if (num_size < 0)
+    {
+      num_size = -num_size;
+      den_size = -den_size;
+    }
+  else if (UNLIKELY (num_size == 0))
+    DIVIDE_BY_ZERO;
+
+  SIZ(DEN(dest)) = num_size;
+  SIZ(NUM(dest)) = den_size;
+
+  /* If dest == src we may just swap the numerator and denominator;
+     we ensured that the new denominator is positive.  */
+
+  if (dest == src)
+    {
+      MP_PTR_SWAP (PTR(NUM(dest)), PTR(DEN(dest)));
+      MP_SIZE_T_SWAP (ALLOC(NUM(dest)), ALLOC(DEN(dest)));
+    }
+  else
+    {
+      mp_ptr dp;
+
+      den_size = ABS (den_size);
+      dp = MPZ_NEWALLOC (NUM(dest), den_size);
+      MPN_COPY (dp, PTR(DEN(src)), den_size);
+
+      dp = MPZ_NEWALLOC (DEN(dest), num_size);
+      MPN_COPY (dp, PTR(NUM(src)), num_size);
+    }
+}
diff --git a/third_party/gmp/mpq/md_2exp.c b/third_party/gmp/mpq/md_2exp.c
new file mode 100644
index 0000000..b3378b3
--- /dev/null
+++ b/third_party/gmp/mpq/md_2exp.c
@@ -0,0 +1,110 @@
+/* mpq_mul_2exp, mpq_div_2exp - multiply or divide by 2^N */
+
+/*
+Copyright 2000, 2002, 2012, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* The multiplier/divisor "n", representing 2^n, is applied by right shifting
+   "r" until it's odd (if it isn't already), and left shifting "l" for the
+   rest. */
+
+static void
+mord_2exp (mpz_ptr ldst, mpz_ptr rdst, mpz_srcptr lsrc, mpz_srcptr rsrc,
+           mp_bitcnt_t n)
+{
+  mp_size_t  rsrc_size = SIZ(rsrc);
+  mp_size_t  len = ABS (rsrc_size);
+  mp_ptr     rsrc_ptr = PTR(rsrc);
+  mp_ptr     p, rdst_ptr;
+  mp_limb_t  plow;
+
+  p = rsrc_ptr;
+  plow = *p;
+  while (n >= GMP_NUMB_BITS && plow == 0)
+    {
+      n -= GMP_NUMB_BITS;
+      p++;
+      plow = *p;
+    }
+
+  /* no realloc here if rsrc==rdst, so p and rsrc_ptr remain valid */
+  len -= (p - rsrc_ptr);
+  rdst_ptr = MPZ_REALLOC (rdst, len);
+
+  if ((plow & 1) || n == 0)
+    {
+      /* need INCR when src==dst */
+      if (p != rdst_ptr)
+        MPN_COPY_INCR (rdst_ptr, p, len);
+    }
+  else
+    {
+      unsigned long  shift;
+      if (plow == 0)
+        shift = n;
+      else
+        {
+          count_trailing_zeros (shift, plow);
+          shift = MIN (shift, n);
+        }
+      mpn_rshift (rdst_ptr, p, len, shift);
+      len -= (rdst_ptr[len-1] == 0);
+      n -= shift;
+    }
+  SIZ(rdst) = (rsrc_size >= 0) ? len : -len;
+
+  if (n)
+    mpz_mul_2exp (ldst, lsrc, n);
+  else if (ldst != lsrc)
+    mpz_set (ldst, lsrc);
+}
+
+
+void
+mpq_mul_2exp (mpq_ptr dst, mpq_srcptr src, mp_bitcnt_t n)
+{
+  mord_2exp (NUM(dst), DEN(dst), NUM(src), DEN(src), n);
+}
+
+void
+mpq_div_2exp (mpq_ptr dst, mpq_srcptr src, mp_bitcnt_t n)
+{
+  if (SIZ(NUM(src)) == 0)
+    {
+      SIZ(NUM(dst)) = 0;
+      SIZ(DEN(dst)) = 1;
+      MPZ_NEWALLOC (DEN(dst), 1)[0] = 1;
+      return;
+    }
+
+  mord_2exp (DEN(dst), NUM(dst), DEN(src), NUM(src), n);
+}
diff --git a/third_party/gmp/mpq/mul.c b/third_party/gmp/mpq/mul.c
new file mode 100644
index 0000000..270dafc
--- /dev/null
+++ b/third_party/gmp/mpq/mul.c
@@ -0,0 +1,102 @@
+/* mpq_mul -- multiply two rational numbers.
+
+Copyright 1991, 1994-1996, 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+void
+mpq_mul (mpq_ptr prod, mpq_srcptr op1, mpq_srcptr op2)
+{
+  mpz_t gcd1, gcd2;
+  mpz_t tmp1, tmp2;
+  mp_size_t op1_num_size;
+  mp_size_t op1_den_size;
+  mp_size_t op2_num_size;
+  mp_size_t op2_den_size;
+  mp_size_t alloc;
+  TMP_DECL;
+
+  if (op1 == op2)
+    {
+      /* No need for any GCDs when squaring. */
+      mpz_mul (mpq_numref (prod), mpq_numref (op1), mpq_numref (op1));
+      mpz_mul (mpq_denref (prod), mpq_denref (op1), mpq_denref (op1));
+      return;
+    }
+
+  op1_num_size = ABSIZ(NUM(op1));
+  op1_den_size =   SIZ(DEN(op1));
+  op2_num_size = ABSIZ(NUM(op2));
+  op2_den_size =   SIZ(DEN(op2));
+
+  if (op1_num_size == 0 || op2_num_size == 0)
+    {
+      /* We special case this to simplify allocation logic; gcd(0,x) = x
+	 is a singular case for the allocations.  */
+      SIZ(NUM(prod)) = 0;
+      MPZ_NEWALLOC (DEN(prod), 1)[0] = 1;
+      SIZ(DEN(prod)) = 1;
+      return;
+    }
+
+  TMP_MARK;
+
+  alloc = MIN (op1_num_size, op2_den_size);
+  MPZ_TMP_INIT (gcd1, alloc);
+
+  alloc = MIN (op2_num_size, op1_den_size);
+  MPZ_TMP_INIT (gcd2, alloc);
+
+  alloc = MAX (op1_num_size, op2_den_size);
+  MPZ_TMP_INIT (tmp1, alloc);
+
+  alloc = MAX (op2_num_size, op1_den_size);
+  MPZ_TMP_INIT (tmp2, alloc);
+
+  /* PROD might be identical to either operand, so don't store the result there
+     until we are finished with the input operands.  We can overwrite the
+     numerator of PROD when we are finished with the numerators of OP1 and
+     OP2.  */
+
+  mpz_gcd (gcd1, NUM(op1), DEN(op2));
+  mpz_gcd (gcd2, NUM(op2), DEN(op1));
+
+  mpz_divexact_gcd (tmp1, NUM(op1), gcd1);
+  mpz_divexact_gcd (tmp2, NUM(op2), gcd2);
+
+  mpz_mul (NUM(prod), tmp1, tmp2);
+
+  mpz_divexact_gcd (tmp1, DEN(op2), gcd1);
+  mpz_divexact_gcd (tmp2, DEN(op1), gcd2);
+
+  mpz_mul (DEN(prod), tmp1, tmp2);
+
+  TMP_FREE;
+}
diff --git a/third_party/gmp/mpq/neg.c b/third_party/gmp/mpq/neg.c
new file mode 100644
index 0000000..8fda41c
--- /dev/null
+++ b/third_party/gmp/mpq/neg.c
@@ -0,0 +1,57 @@
+/* mpq_neg -- negate a rational.
+
+Copyright 2000, 2001, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define __GMP_FORCE_mpq_neg 1
+
+#include "gmp-impl.h"
+
+
+void
+mpq_neg (mpq_ptr dst, mpq_srcptr src)
+{
+  mp_size_t  num_size = SIZ(NUM(src));
+
+  if (src != dst)
+    {
+      mp_size_t  size;
+      mp_ptr dp;
+
+      size = ABS(num_size);
+      dp = MPZ_NEWALLOC (NUM(dst), size);
+      MPN_COPY (dp, PTR(NUM(src)), size);
+
+      size = SIZ(DEN(src));
+      dp = MPZ_NEWALLOC (DEN(dst), size);
+      SIZ(DEN(dst)) = size;
+      MPN_COPY (dp, PTR(DEN(src)), size);
+    }
+
+  SIZ(NUM(dst)) = -num_size;
+}
diff --git a/third_party/gmp/mpq/out_str.c b/third_party/gmp/mpq/out_str.c
new file mode 100644
index 0000000..5d2dd4e
--- /dev/null
+++ b/third_party/gmp/mpq/out_str.c
@@ -0,0 +1,53 @@
+/* mpq_out_str(stream,base,integer) */
+
+/*
+Copyright 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp-impl.h"
+
+
+size_t
+mpq_out_str (FILE *stream, int base, mpq_srcptr q)
+{
+  size_t  written;
+
+  if (stream == NULL)
+    stream = stdout;
+
+  written = mpz_out_str (stream, base, mpq_numref (q));
+
+  if (mpz_cmp_ui (mpq_denref (q), 1) != 0)
+    {
+      putc ('/', stream);
+      written += 1 + mpz_out_str (stream, base, mpq_denref (q));
+    }
+
+  return ferror (stream) ? 0 : written;
+}
diff --git a/third_party/gmp/mpq/set.c b/third_party/gmp/mpq/set.c
new file mode 100644
index 0000000..87c15e3
--- /dev/null
+++ b/third_party/gmp/mpq/set.c
@@ -0,0 +1,51 @@
+/* mpq_set(dest,src) -- Set DEST to SRC.
+
+Copyright 1991, 1994, 1995, 2001, 2012, 2015 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpq_set (mpq_ptr dest, mpq_srcptr src)
+{
+  mp_size_t num_size, den_size;
+  mp_size_t abs_num_size;
+  mp_ptr dp;
+
+  num_size = SIZ(NUM(src));
+  SIZ(NUM(dest)) = num_size;
+  abs_num_size = ABS (num_size);
+  dp = MPZ_NEWALLOC (NUM(dest), abs_num_size);
+  MPN_COPY (dp, PTR(NUM(src)), abs_num_size);
+
+  den_size = SIZ(DEN(src));
+  SIZ(DEN(dest)) = den_size;
+  dp = MPZ_NEWALLOC (DEN(dest), den_size);
+  MPN_COPY (dp, PTR(DEN(src)), den_size);
+}
diff --git a/third_party/gmp/mpq/set_d.c b/third_party/gmp/mpq/set_d.c
new file mode 100644
index 0000000..3f3fab0
--- /dev/null
+++ b/third_party/gmp/mpq/set_d.c
@@ -0,0 +1,165 @@
+/* mpq_set_d(mpq_t q, double d) -- Set q to d without rounding.
+
+Copyright 2000, 2002, 2003, 2012, 2014, 2018 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#if HAVE_FLOAT_H
+#include <float.h>  /* for DBL_MAX */
+#endif
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#if LIMBS_PER_DOUBLE > 4
+  choke me
+#endif
+
+void
+mpq_set_d (mpq_ptr dest, double d)
+{
+  int negative;
+  mp_exp_t exp;
+  mp_limb_t tp[LIMBS_PER_DOUBLE];
+  mp_ptr np, dp;
+  mp_size_t nn, dn;
+  int c;
+
+  DOUBLE_NAN_INF_ACTION (d,
+                         __gmp_invalid_operation (),
+                         __gmp_invalid_operation ());
+
+  negative = d < 0;
+  d = ABS (d);
+
+  exp = __gmp_extract_double (tp, d);
+
+  /* There are two main version of the conversion.  The `then' arm handles
+     numbers with a fractional part, while the `else' arm handles integers.  */
+#if LIMBS_PER_DOUBLE == 4
+  if (exp <= 1 || (exp == 2 && (tp[0] | tp[1]) != 0))
+#endif
+#if LIMBS_PER_DOUBLE == 3
+  if (exp <= 1 || (exp == 2 && tp[0] != 0))
+#endif
+#if LIMBS_PER_DOUBLE == 2
+  if (exp <= 1)
+#endif
+    {
+      if (d == 0.0)
+	{
+	  SIZ(NUM(dest)) = 0;
+	  SIZ(DEN(dest)) = 1;
+	  MPZ_NEWALLOC (DEN(dest), 1)[0] = 1;
+	  return;
+	}
+
+#if LIMBS_PER_DOUBLE == 4
+      np = MPZ_NEWALLOC (NUM(dest), 4);
+      if ((tp[0] | tp[1] | tp[2]) == 0)
+	np[0] = tp[3], nn = 1;
+      else if ((tp[0] | tp[1]) == 0)
+	np[1] = tp[3], np[0] = tp[2], nn = 2;
+      else if (tp[0] == 0)
+	np[2] = tp[3], np[1] = tp[2], np[0] = tp[1], nn = 3;
+      else
+	np[3] = tp[3], np[2] = tp[2], np[1] = tp[1], np[0] = tp[0], nn = 4;
+#endif
+#if LIMBS_PER_DOUBLE == 3
+      np = MPZ_NEWALLOC (NUM(dest), 3);
+      if ((tp[0] | tp[1]) == 0)
+	np[0] = tp[2], nn = 1;
+      else if (tp[0] == 0)
+	np[1] = tp[2], np[0] = tp[1], nn = 2;
+      else
+	np[2] = tp[2], np[1] = tp[1], np[0] = tp[0], nn = 3;
+#endif
+#if LIMBS_PER_DOUBLE == 2
+      np = MPZ_NEWALLOC (NUM(dest), 2);
+      if (tp[0] == 0)
+	np[0] = tp[1], nn = 1;
+      else
+	np[1] = tp[1], np[0] = tp[0], nn = 2;
+#endif
+      dn = nn + 1 - exp;
+      ASSERT (dn > 0); /* -exp >= -1; nn >= 1*/
+      dp = MPZ_NEWALLOC (DEN(dest), dn);
+      MPN_ZERO (dp, dn - 1);
+      dp[dn - 1] = 1;
+      count_trailing_zeros (c, np[0] | dp[0]);
+      if (c != 0)
+	{
+	  mpn_rshift (np, np, nn, c);
+	  nn -= np[nn - 1] == 0;
+	  --dn;
+	  dp[dn - 1] = CNST_LIMB(1) << (GMP_LIMB_BITS - c);
+	}
+      SIZ(DEN(dest)) = dn;
+    }
+  else
+    {
+      nn = exp;
+      np = MPZ_NEWALLOC (NUM(dest), nn);
+      switch (nn)
+        {
+	default:
+	  MPN_ZERO (np, nn - LIMBS_PER_DOUBLE);
+	  np += nn - LIMBS_PER_DOUBLE;
+	  /* fall through */
+#if LIMBS_PER_DOUBLE == 2
+	case 2:
+	  np[1] = tp[1], np[0] = tp[0];
+	  break;
+#endif
+#if LIMBS_PER_DOUBLE == 3
+	case 3:
+	  np[2] = tp[2], np[1] = tp[1], np[0] = tp[0];
+	  break;
+	case 2:
+	  np[1] = tp[2], np[0] = tp[1];
+	  break;
+#endif
+#if LIMBS_PER_DOUBLE == 4
+	case 4:
+	  np[3] = tp[3], np[2] = tp[2], np[1] = tp[1], np[0] = tp[0];
+	  break;
+	case 3:
+	  np[2] = tp[3], np[1] = tp[2], np[0] = tp[1];
+	  break;
+	case 2:
+	  np[1] = tp[3], np[0] = tp[2];
+	  break;
+#endif
+	}
+      MPZ_NEWALLOC (DEN(dest), 1)[0] = 1;
+      SIZ(DEN(dest)) = 1;
+    }
+  SIZ(NUM(dest)) = negative ? -nn : nn;
+}
diff --git a/third_party/gmp/mpq/set_den.c b/third_party/gmp/mpq/set_den.c
new file mode 100644
index 0000000..e249db7
--- /dev/null
+++ b/third_party/gmp/mpq/set_den.c
@@ -0,0 +1,45 @@
+/* mpq_set_den(dest,den) -- Set the denominator of DEST from DEN.
+
+Copyright 1991, 1994-1996, 2000, 2001, 2012, 2015 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpq_set_den (mpq_ptr dest, mpz_srcptr den)
+{
+  mp_size_t size = SIZ (den);
+  mp_size_t abs_size = ABS (size);
+  mp_ptr dp;
+
+  SIZ(DEN(dest)) = size;
+  dp = MPZ_NEWALLOC (DEN(dest), abs_size);
+
+  MPN_COPY (dp, PTR(den), abs_size);
+}
diff --git a/third_party/gmp/mpq/set_f.c b/third_party/gmp/mpq/set_f.c
new file mode 100644
index 0000000..581d4fc
--- /dev/null
+++ b/third_party/gmp/mpq/set_f.c
@@ -0,0 +1,106 @@
+/* mpq_set_f -- set an mpq from an mpf.
+
+Copyright 2000-2002, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+void
+mpq_set_f (mpq_ptr q, mpf_srcptr f)
+{
+  mp_size_t  fexp = EXP(f);
+  mp_ptr     fptr = PTR(f);
+  mp_size_t  fsize = SIZ(f);
+  mp_size_t  abs_fsize = ABS(fsize);
+  mp_limb_t  flow;
+
+  if (fsize == 0)
+    {
+      /* set q=0 */
+      SIZ(NUM(q)) = 0;
+      SIZ(DEN(q)) = 1;
+      MPZ_NEWALLOC (DEN(q), 1)[0] = 1;
+      return;
+    }
+
+  /* strip low zero limbs from f */
+  flow = *fptr;
+  MPN_STRIP_LOW_ZEROS_NOT_ZERO (fptr, abs_fsize, flow);
+
+  if (fexp >= abs_fsize)
+    {
+      /* radix point is to the right of the limbs, no denominator */
+      mp_ptr  num_ptr;
+
+      num_ptr = MPZ_NEWALLOC (mpq_numref (q), fexp);
+      MPN_ZERO (num_ptr, fexp - abs_fsize);
+      MPN_COPY (num_ptr + fexp - abs_fsize, fptr, abs_fsize);
+
+      SIZ(NUM(q)) = fsize >= 0 ? fexp : -fexp;
+      SIZ(DEN(q)) = 1;
+      MPZ_NEWALLOC (DEN(q), 1)[0] = 1;
+    }
+  else
+    {
+      /* radix point is within or to the left of the limbs, use denominator */
+      mp_ptr     num_ptr, den_ptr;
+      mp_size_t  den_size;
+
+      den_size = abs_fsize - fexp;
+      num_ptr = MPZ_NEWALLOC (mpq_numref (q), abs_fsize);
+      den_ptr = MPZ_NEWALLOC (mpq_denref (q), den_size+1);
+
+      if (flow & 1)
+        {
+          /* no powers of two to strip from numerator */
+
+          MPN_COPY (num_ptr, fptr, abs_fsize);
+          MPN_ZERO (den_ptr, den_size);
+          den_ptr[den_size] = 1;
+        }
+      else
+        {
+          /* right shift numerator, adjust denominator accordingly */
+          int  shift;
+
+          den_size--;
+          count_trailing_zeros (shift, flow);
+
+          mpn_rshift (num_ptr, fptr, abs_fsize, shift);
+          abs_fsize -= (num_ptr[abs_fsize-1] == 0);
+
+          MPN_ZERO (den_ptr, den_size);
+          den_ptr[den_size] = GMP_LIMB_HIGHBIT >> (shift-1);
+        }
+
+      SIZ(NUM(q)) = fsize >= 0 ? abs_fsize : -abs_fsize;
+      SIZ(DEN(q)) = den_size + 1;
+    }
+}
diff --git a/third_party/gmp/mpq/set_num.c b/third_party/gmp/mpq/set_num.c
new file mode 100644
index 0000000..1a099a2
--- /dev/null
+++ b/third_party/gmp/mpq/set_num.c
@@ -0,0 +1,45 @@
+/* mpq_set_num(dest,num) -- Set the numerator of DEST from NUM.
+
+Copyright 1991, 1994, 1995, 2001, 2012, 2015 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpq_set_num (mpq_ptr dest, mpz_srcptr num)
+{
+  mp_size_t size = SIZ (num);
+  mp_size_t abs_size = ABS (size);
+  mp_ptr dp;
+
+  SIZ(NUM(dest)) = size;
+  dp = MPZ_NEWALLOC (NUM(dest), abs_size);
+
+  MPN_COPY (dp, PTR(num), abs_size);
+}
diff --git a/third_party/gmp/mpq/set_si.c b/third_party/gmp/mpq/set_si.c
new file mode 100644
index 0000000..e51406b
--- /dev/null
+++ b/third_party/gmp/mpq/set_si.c
@@ -0,0 +1,60 @@
+/* mpq_set_si(dest,ulong_num,ulong_den) -- Set DEST to the rational number
+   ULONG_NUM/ULONG_DEN.
+
+Copyright 1991, 1994, 1995, 2001, 2003, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpq_set_si (mpq_t dest, signed long int num, unsigned long int den)
+{
+  if (GMP_NUMB_BITS < BITS_PER_ULONG)
+    {
+      if (num == 0)  /* Canonicalize 0/d to 0/1.  */
+        den = 1;
+      mpz_set_si (mpq_numref (dest), num);
+      mpz_set_ui (mpq_denref (dest), den);
+      return;
+    }
+
+  if (num == 0)
+    {
+      /* Canonicalize 0/d to 0/1.  */
+      den = 1;
+      SIZ(NUM(dest)) = 0;
+    }
+  else
+    {
+      MPZ_NEWALLOC (NUM(dest), 1)[0] = ABS_CAST (unsigned long, num);
+      SIZ(NUM(dest)) = num > 0 ? 1 : -1;
+    }
+
+  MPZ_NEWALLOC (DEN(dest), 1)[0] = den;
+  SIZ(DEN(dest)) = (den != 0);
+}
diff --git a/third_party/gmp/mpq/set_str.c b/third_party/gmp/mpq/set_str.c
new file mode 100644
index 0000000..664bb2d
--- /dev/null
+++ b/third_party/gmp/mpq/set_str.c
@@ -0,0 +1,68 @@
+/* mpq_set_str -- string to mpq conversion.
+
+Copyright 2001, 2002, 2015, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <string.h>
+#include "gmp-impl.h"
+
+
+/* FIXME: Would like an mpz_set_mem (or similar) accepting a pointer and
+   length so we wouldn't have to copy the numerator just to null-terminate
+   it.  */
+
+int
+mpq_set_str (mpq_ptr q, const char *str, int base)
+{
+  const char  *slash;
+  char        *num;
+  size_t      numlen;
+  int         ret;
+
+  slash = strchr (str, '/');
+  if (slash == NULL)
+    {
+      SIZ(DEN(q)) = 1;
+      MPZ_NEWALLOC (DEN(q), 1)[0] = 1;
+
+      return mpz_set_str (mpq_numref(q), str, base);
+    }
+
+  numlen = slash - str;
+  num = __GMP_ALLOCATE_FUNC_TYPE (numlen+1, char);
+  memcpy (num, str, numlen);
+  num[numlen] = '\0';
+  ret = mpz_set_str (mpq_numref(q), num, base);
+  __GMP_FREE_FUNC_TYPE (num, numlen+1, char);
+
+  if (ret != 0)
+    return ret;
+
+  return mpz_set_str (mpq_denref(q), slash+1, base);
+}
diff --git a/third_party/gmp/mpq/set_ui.c b/third_party/gmp/mpq/set_ui.c
new file mode 100644
index 0000000..db85d97
--- /dev/null
+++ b/third_party/gmp/mpq/set_ui.c
@@ -0,0 +1,60 @@
+/* mpq_set_ui(dest,ulong_num,ulong_den) -- Set DEST to the rational number
+   ULONG_NUM/ULONG_DEN.
+
+Copyright 1991, 1994, 1995, 2001-2003, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpq_set_ui (mpq_t dest, unsigned long int num, unsigned long int den)
+{
+  if (GMP_NUMB_BITS < BITS_PER_ULONG)
+    {
+      if (num == 0)  /* Canonicalize 0/d to 0/1.  */
+        den = 1;
+      mpz_set_ui (mpq_numref (dest), num);
+      mpz_set_ui (mpq_denref (dest), den);
+      return;
+    }
+
+  if (num == 0)
+    {
+      /* Canonicalize 0/d to 0/1.  */
+      den = 1;
+      SIZ(NUM(dest)) = 0;
+    }
+  else
+    {
+      MPZ_NEWALLOC (NUM(dest), 1)[0] = num;
+      SIZ(NUM(dest)) = 1;
+    }
+
+  MPZ_NEWALLOC (DEN(dest), 1)[0] = den;
+  SIZ(DEN(dest)) = (den != 0);
+}
diff --git a/third_party/gmp/mpq/set_z.c b/third_party/gmp/mpq/set_z.c
new file mode 100644
index 0000000..8309c93
--- /dev/null
+++ b/third_party/gmp/mpq/set_z.c
@@ -0,0 +1,48 @@
+/* mpq_set_z (dest,src) -- Set DEST to SRC.
+
+Copyright 1996, 2001, 2012, 2015, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpq_set_z (mpq_ptr dest, mpz_srcptr src)
+{
+  mp_size_t num_size;
+  mp_size_t abs_num_size;
+  mp_ptr dp;
+
+  num_size = SIZ (src);
+  SIZ(NUM(dest)) = num_size;
+  abs_num_size = ABS (num_size);
+  dp = MPZ_NEWALLOC (NUM(dest), abs_num_size);
+  MPN_COPY (dp, PTR(src), abs_num_size);
+
+  MPZ_NEWALLOC (DEN(dest), 1)[0] = 1;
+  SIZ(DEN(dest)) = 1;
+}
diff --git a/third_party/gmp/mpq/swap.c b/third_party/gmp/mpq/swap.c
new file mode 100644
index 0000000..e5152d4
--- /dev/null
+++ b/third_party/gmp/mpq/swap.c
@@ -0,0 +1,42 @@
+/* mpq_swap (U, V) -- Swap U and V.
+
+Copyright 1997, 1998, 2000, 2001, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpq_swap (mpq_ptr u, mpq_ptr v) __GMP_NOTHROW
+{
+  MP_SIZE_T_SWAP (ALLOC(NUM(u)), ALLOC(NUM(v)));
+  MP_SIZE_T_SWAP (ALLOC(DEN(u)), ALLOC(DEN(v)));
+  MP_SIZE_T_SWAP (SIZ(NUM(u)), SIZ(NUM(v)));
+  MP_SIZE_T_SWAP (SIZ(DEN(u)), SIZ(DEN(v)));
+  MP_PTR_SWAP (PTR(NUM(u)), PTR(NUM(v)));
+  MP_PTR_SWAP (PTR(DEN(u)), PTR(DEN(v)));
+}
diff --git a/third_party/gmp/mpz/2fac_ui.c b/third_party/gmp/mpz/2fac_ui.c
new file mode 100644
index 0000000..141a0a7
--- /dev/null
+++ b/third_party/gmp/mpz/2fac_ui.c
@@ -0,0 +1,100 @@
+/* mpz_2fac_ui(RESULT, N) -- Set RESULT to N!!.
+
+Contributed to the GNU project by Marco Bodrato.
+
+Copyright 2012, 2015, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#define FACTOR_LIST_STORE(P, PR, MAX_PR, VEC, I)		\
+  do {								\
+    if ((PR) > (MAX_PR)) {					\
+      (VEC)[(I)++] = (PR);					\
+      (PR) = (P);						\
+    } else							\
+      (PR) *= (P);						\
+  } while (0)
+
+#define FAC_2DSC_THRESHOLD ((FAC_DSC_THRESHOLD << 1) | (FAC_DSC_THRESHOLD & 1))
+#define FACTORS_PER_LIMB   (GMP_NUMB_BITS / (LOG2C(FAC_2DSC_THRESHOLD-1)+1))
+
+/* Computes n!!, the 2-multi-factorial of n. (aka double-factorial or semi-factorial)
+   WARNING: it assumes that n fits in a limb!
+ */
+void
+mpz_2fac_ui (mpz_ptr x, unsigned long n)
+{
+  ASSERT (n <= GMP_NUMB_MAX);
+
+  if ((n & 1) == 0) { /* n is even, n = 2k, (2k)!! = k! 2^k */
+    mp_limb_t count;
+
+    if ((n <= TABLE_LIMIT_2N_MINUS_POPC_2N) & (n != 0))
+      count = __gmp_fac2cnt_table[n / 2 - 1];
+    else
+      {
+	popc_limb (count, n);	/* popc(n) == popc(k) */
+	count = n - count;		/* n - popc(n) == k + k - popc(k) */
+      }
+    mpz_oddfac_1 (x, n >> 1, 0);
+    mpz_mul_2exp (x, x, count);
+  } else { /* n is odd */
+    if (n <= ODD_DOUBLEFACTORIAL_TABLE_LIMIT) {
+      MPZ_NEWALLOC (x, 1)[0] = __gmp_odd2fac_table[n >> 1];
+      SIZ (x) = 1;
+    } else if (BELOW_THRESHOLD (n, FAC_2DSC_THRESHOLD)) { /* odd basecase, */
+      mp_limb_t *factors, prod, max_prod;
+      mp_size_t j;
+      TMP_SDECL;
+
+      /* FIXME: we might alloc a fixed amount 1+FAC_2DSC_THRESHOLD/FACTORS_PER_LIMB */
+      TMP_SMARK;
+      factors = TMP_SALLOC_LIMBS (1 + n / (2 * FACTORS_PER_LIMB));
+
+      factors[0] = ODD_DOUBLEFACTORIAL_TABLE_MAX;
+      j = 1;
+      prod = n;
+
+      max_prod = GMP_NUMB_MAX / FAC_2DSC_THRESHOLD;
+      while ((n -= 2) > ODD_DOUBLEFACTORIAL_TABLE_LIMIT)
+	FACTOR_LIST_STORE (n, prod, max_prod, factors, j);
+
+      factors[j++] = prod;
+      mpz_prodlimbs (x, factors, j);
+
+      TMP_SFREE;
+    } else { /* for the asymptotically fast odd case, let oddfac do the job. */
+      mpz_oddfac_1 (x, n, 1);
+    }
+  }
+}
+
+#undef FACTORS_PER_LIMB
+#undef FACTOR_LIST_STORE
+#undef FAC_2DSC_THRESHOLD
diff --git a/third_party/gmp/mpz/Makefile.am b/third_party/gmp/mpz/Makefile.am
new file mode 100644
index 0000000..a5e1f57
--- /dev/null
+++ b/third_party/gmp/mpz/Makefile.am
@@ -0,0 +1,68 @@
+## Process this file with automake to generate Makefile.in
+
+# Copyright 1996, 1998-2003, 2012 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+
+AM_CPPFLAGS = -D__GMP_WITHIN_GMP -I$(top_srcdir)
+
+noinst_LTLIBRARIES = libmpz.la
+libmpz_la_SOURCES = aors.h aors_ui.h fits_s.h mul_i.h \
+  2fac_ui.c \
+  add.c add_ui.c abs.c aorsmul.c aorsmul_i.c and.c array_init.c \
+  bin_ui.c bin_uiui.c cdiv_q.c \
+  cdiv_q_ui.c cdiv_qr.c cdiv_qr_ui.c cdiv_r.c cdiv_r_ui.c cdiv_ui.c \
+  cfdiv_q_2exp.c cfdiv_r_2exp.c \
+  clear.c clears.c clrbit.c \
+  cmp.c cmp_d.c cmp_si.c cmp_ui.c cmpabs.c cmpabs_d.c cmpabs_ui.c \
+  com.c combit.c \
+  cong.c cong_2exp.c cong_ui.c \
+  divexact.c divegcd.c dive_ui.c divis.c divis_ui.c divis_2exp.c \
+  dump.c export.c fac_ui.c fdiv_q.c fdiv_q_ui.c \
+  fdiv_qr.c fdiv_qr_ui.c fdiv_r.c fdiv_r_ui.c fdiv_ui.c \
+  fib_ui.c fib2_ui.c \
+  fits_sint.c fits_slong.c fits_sshort.c \
+  fits_uint.c fits_ulong.c fits_ushort.c \
+  gcd.c gcd_ui.c gcdext.c get_d.c get_d_2exp.c get_si.c \
+  get_str.c get_ui.c getlimbn.c hamdist.c \
+  import.c init.c init2.c inits.c inp_raw.c inp_str.c \
+  invert.c ior.c iset.c iset_d.c iset_si.c iset_str.c iset_ui.c \
+  jacobi.c kronsz.c kronuz.c kronzs.c kronzu.c \
+  lcm.c lcm_ui.c limbs_read.c limbs_write.c limbs_modify.c limbs_finish.c \
+  lucnum_ui.c lucnum2_ui.c lucmod.c mfac_uiui.c millerrabin.c \
+  mod.c mul.c mul_2exp.c mul_si.c mul_ui.c n_pow_ui.c neg.c nextprime.c \
+  oddfac_1.c \
+  out_raw.c out_str.c perfpow.c perfsqr.c popcount.c pow_ui.c powm.c \
+  powm_sec.c powm_ui.c pprime_p.c prodlimbs.c primorial_ui.c random.c random2.c \
+  realloc.c realloc2.c remove.c roinit_n.c root.c rootrem.c rrandomb.c \
+  scan0.c scan1.c set.c set_d.c set_f.c set_q.c set_si.c set_str.c \
+  set_ui.c setbit.c size.c sizeinbase.c sqrt.c sqrtrem.c stronglucas.c \
+  sub.c sub_ui.c \
+  swap.c tdiv_ui.c tdiv_q.c tdiv_q_2exp.c tdiv_q_ui.c tdiv_qr.c \
+  tdiv_qr_ui.c tdiv_r.c tdiv_r_2exp.c tdiv_r_ui.c tstbit.c ui_pow_ui.c \
+  ui_sub.c urandomb.c urandomm.c xor.c
diff --git a/third_party/gmp/mpz/Makefile.in b/third_party/gmp/mpz/Makefile.in
new file mode 100644
index 0000000..6fd9c60
--- /dev/null
+++ b/third_party/gmp/mpz/Makefile.in
@@ -0,0 +1,702 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Copyright 1996, 1998-2003, 2012 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = mpz
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libmpz_la_LIBADD =
+am_libmpz_la_OBJECTS = 2fac_ui.lo add.lo add_ui.lo abs.lo aorsmul.lo \
+	aorsmul_i.lo and.lo array_init.lo bin_ui.lo bin_uiui.lo \
+	cdiv_q.lo cdiv_q_ui.lo cdiv_qr.lo cdiv_qr_ui.lo cdiv_r.lo \
+	cdiv_r_ui.lo cdiv_ui.lo cfdiv_q_2exp.lo cfdiv_r_2exp.lo \
+	clear.lo clears.lo clrbit.lo cmp.lo cmp_d.lo cmp_si.lo \
+	cmp_ui.lo cmpabs.lo cmpabs_d.lo cmpabs_ui.lo com.lo combit.lo \
+	cong.lo cong_2exp.lo cong_ui.lo divexact.lo divegcd.lo \
+	dive_ui.lo divis.lo divis_ui.lo divis_2exp.lo dump.lo \
+	export.lo fac_ui.lo fdiv_q.lo fdiv_q_ui.lo fdiv_qr.lo \
+	fdiv_qr_ui.lo fdiv_r.lo fdiv_r_ui.lo fdiv_ui.lo fib_ui.lo \
+	fib2_ui.lo fits_sint.lo fits_slong.lo fits_sshort.lo \
+	fits_uint.lo fits_ulong.lo fits_ushort.lo gcd.lo gcd_ui.lo \
+	gcdext.lo get_d.lo get_d_2exp.lo get_si.lo get_str.lo \
+	get_ui.lo getlimbn.lo hamdist.lo import.lo init.lo init2.lo \
+	inits.lo inp_raw.lo inp_str.lo invert.lo ior.lo iset.lo \
+	iset_d.lo iset_si.lo iset_str.lo iset_ui.lo jacobi.lo \
+	kronsz.lo kronuz.lo kronzs.lo kronzu.lo lcm.lo lcm_ui.lo \
+	limbs_read.lo limbs_write.lo limbs_modify.lo limbs_finish.lo \
+	lucnum_ui.lo lucnum2_ui.lo lucmod.lo mfac_uiui.lo \
+	millerrabin.lo mod.lo mul.lo mul_2exp.lo mul_si.lo mul_ui.lo \
+	n_pow_ui.lo neg.lo nextprime.lo oddfac_1.lo out_raw.lo \
+	out_str.lo perfpow.lo perfsqr.lo popcount.lo pow_ui.lo powm.lo \
+	powm_sec.lo powm_ui.lo pprime_p.lo prodlimbs.lo \
+	primorial_ui.lo random.lo random2.lo realloc.lo realloc2.lo \
+	remove.lo roinit_n.lo root.lo rootrem.lo rrandomb.lo scan0.lo \
+	scan1.lo set.lo set_d.lo set_f.lo set_q.lo set_si.lo \
+	set_str.lo set_ui.lo setbit.lo size.lo sizeinbase.lo sqrt.lo \
+	sqrtrem.lo stronglucas.lo sub.lo sub_ui.lo swap.lo tdiv_ui.lo \
+	tdiv_q.lo tdiv_q_2exp.lo tdiv_q_ui.lo tdiv_qr.lo tdiv_qr_ui.lo \
+	tdiv_r.lo tdiv_r_2exp.lo tdiv_r_ui.lo tstbit.lo ui_pow_ui.lo \
+	ui_sub.lo urandomb.lo urandomm.lo xor.lo
+libmpz_la_OBJECTS = $(am_libmpz_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp =
+am__depfiles_maybe =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+SOURCES = $(libmpz_la_SOURCES)
+DIST_SOURCES = $(libmpz_la_SOURCES)
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ABI = @ABI@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+ASMFLAGS = @ASMFLAGS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CALLING_CONVENTIONS_OBJS = @CALLING_CONVENTIONS_OBJS@
+CC = @CC@
+CCAS = @CCAS@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPP_FOR_BUILD = @CPP_FOR_BUILD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFN_LONG_LONG_LIMB = @DEFN_LONG_LONG_LIMB@
+DEFS = @DEFS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@
+FGREP = @FGREP@
+GMP_LDFLAGS = @GMP_LDFLAGS@
+GMP_LIMB_BITS = @GMP_LIMB_BITS@
+GMP_NAIL_BITS = @GMP_NAIL_BITS@
+GREP = @GREP@
+HAVE_CLOCK_01 = @HAVE_CLOCK_01@
+HAVE_CPUTIME_01 = @HAVE_CPUTIME_01@
+HAVE_GETRUSAGE_01 = @HAVE_GETRUSAGE_01@
+HAVE_GETTIMEOFDAY_01 = @HAVE_GETTIMEOFDAY_01@
+HAVE_HOST_CPU_FAMILY_power = @HAVE_HOST_CPU_FAMILY_power@
+HAVE_HOST_CPU_FAMILY_powerpc = @HAVE_HOST_CPU_FAMILY_powerpc@
+HAVE_SIGACTION_01 = @HAVE_SIGACTION_01@
+HAVE_SIGALTSTACK_01 = @HAVE_SIGALTSTACK_01@
+HAVE_SIGSTACK_01 = @HAVE_SIGSTACK_01@
+HAVE_STACK_T_01 = @HAVE_STACK_T_01@
+HAVE_SYS_RESOURCE_H_01 = @HAVE_SYS_RESOURCE_H_01@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCURSES = @LIBCURSES@
+LIBGMPXX_LDFLAGS = @LIBGMPXX_LDFLAGS@
+LIBGMP_DLL = @LIBGMP_DLL@
+LIBGMP_LDFLAGS = @LIBGMP_LDFLAGS@
+LIBM = @LIBM@
+LIBM_FOR_BUILD = @LIBM_FOR_BUILD@
+LIBOBJS = @LIBOBJS@
+LIBREADLINE = @LIBREADLINE@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+M4 = @M4@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPEED_CYCLECOUNTER_OBJ = @SPEED_CYCLECOUNTER_OBJ@
+STRIP = @STRIP@
+TAL_OBJECT = @TAL_OBJECT@
+TUNE_LIBS = @TUNE_LIBS@
+TUNE_SQR_OBJ = @TUNE_SQR_OBJ@
+U_FOR_BUILD = @U_FOR_BUILD@
+VERSION = @VERSION@
+WITH_READLINE_01 = @WITH_READLINE_01@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__leading_dot = @am__leading_dot@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gmp_srclinks = @gmp_srclinks@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+mpn_objects = @mpn_objects@
+mpn_objs_in_libgmp = @mpn_objs_in_libgmp@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_CPPFLAGS = -D__GMP_WITHIN_GMP -I$(top_srcdir)
+noinst_LTLIBRARIES = libmpz.la
+libmpz_la_SOURCES = aors.h aors_ui.h fits_s.h mul_i.h \
+  2fac_ui.c \
+  add.c add_ui.c abs.c aorsmul.c aorsmul_i.c and.c array_init.c \
+  bin_ui.c bin_uiui.c cdiv_q.c \
+  cdiv_q_ui.c cdiv_qr.c cdiv_qr_ui.c cdiv_r.c cdiv_r_ui.c cdiv_ui.c \
+  cfdiv_q_2exp.c cfdiv_r_2exp.c \
+  clear.c clears.c clrbit.c \
+  cmp.c cmp_d.c cmp_si.c cmp_ui.c cmpabs.c cmpabs_d.c cmpabs_ui.c \
+  com.c combit.c \
+  cong.c cong_2exp.c cong_ui.c \
+  divexact.c divegcd.c dive_ui.c divis.c divis_ui.c divis_2exp.c \
+  dump.c export.c fac_ui.c fdiv_q.c fdiv_q_ui.c \
+  fdiv_qr.c fdiv_qr_ui.c fdiv_r.c fdiv_r_ui.c fdiv_ui.c \
+  fib_ui.c fib2_ui.c \
+  fits_sint.c fits_slong.c fits_sshort.c \
+  fits_uint.c fits_ulong.c fits_ushort.c \
+  gcd.c gcd_ui.c gcdext.c get_d.c get_d_2exp.c get_si.c \
+  get_str.c get_ui.c getlimbn.c hamdist.c \
+  import.c init.c init2.c inits.c inp_raw.c inp_str.c \
+  invert.c ior.c iset.c iset_d.c iset_si.c iset_str.c iset_ui.c \
+  jacobi.c kronsz.c kronuz.c kronzs.c kronzu.c \
+  lcm.c lcm_ui.c limbs_read.c limbs_write.c limbs_modify.c limbs_finish.c \
+  lucnum_ui.c lucnum2_ui.c lucmod.c mfac_uiui.c millerrabin.c \
+  mod.c mul.c mul_2exp.c mul_si.c mul_ui.c n_pow_ui.c neg.c nextprime.c \
+  oddfac_1.c \
+  out_raw.c out_str.c perfpow.c perfsqr.c popcount.c pow_ui.c powm.c \
+  powm_sec.c powm_ui.c pprime_p.c prodlimbs.c primorial_ui.c random.c random2.c \
+  realloc.c realloc2.c remove.c roinit_n.c root.c rootrem.c rrandomb.c \
+  scan0.c scan1.c set.c set_d.c set_f.c set_q.c set_si.c set_str.c \
+  set_ui.c setbit.c size.c sizeinbase.c sqrt.c sqrtrem.c stronglucas.c \
+  sub.c sub_ui.c \
+  swap.c tdiv_ui.c tdiv_q.c tdiv_q_2exp.c tdiv_q_ui.c tdiv_qr.c \
+  tdiv_qr_ui.c tdiv_r.c tdiv_r_2exp.c tdiv_r_ui.c tstbit.c ui_pow_ui.c \
+  ui_sub.c urandomb.c urandomm.c xor.c
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu --ignore-deps mpz/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu --ignore-deps mpz/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+	@list='$(noinst_LTLIBRARIES)'; \
+	locs=`for p in $$list; do echo $$p; done | \
+	      sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+	      sort -u`; \
+	test -z "$$locs" || { \
+	  echo rm -f $${locs}; \
+	  rm -f $${locs}; \
+	}
+
+libmpz.la: $(libmpz_la_OBJECTS) $(libmpz_la_DEPENDENCIES) $(EXTRA_libmpz_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(LINK)  $(libmpz_la_OBJECTS) $(libmpz_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+.c.o:
+	$(AM_V_CC)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+	$(AM_V_CC)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+	$(AM_V_CC)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+	clean-libtool clean-noinstLTLIBRARIES cscopelist-am ctags \
+	ctags-am distclean distclean-compile distclean-generic \
+	distclean-libtool distclean-tags distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-dvi install-dvi-am install-exec \
+	install-exec-am install-html install-html-am install-info \
+	install-info-am install-man install-pdf install-pdf-am \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/third_party/gmp/mpz/abs.c b/third_party/gmp/mpz/abs.c
new file mode 100644
index 0000000..0cfbc49
--- /dev/null
+++ b/third_party/gmp/mpz/abs.c
@@ -0,0 +1,54 @@
+/* mpz_abs(dst, src) -- Assign the absolute value of SRC to DST.
+
+Copyright 1991, 1993-1995, 2001, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define __GMP_FORCE_mpz_abs 1
+
+#include "gmp-impl.h"
+
+void
+mpz_abs (mpz_ptr w, mpz_srcptr u)
+{
+  mp_ptr wp;
+  mp_srcptr up;
+  mp_size_t size;
+
+  size = ABSIZ (u);
+
+  if (u != w)
+    {
+      wp = MPZ_NEWALLOC (w, size);
+
+      up = PTR (u);
+
+      MPN_COPY (wp, up, size);
+    }
+
+  SIZ (w) = size;
+}
diff --git a/third_party/gmp/mpz/add.c b/third_party/gmp/mpz/add.c
new file mode 100644
index 0000000..f1f0ae8
--- /dev/null
+++ b/third_party/gmp/mpz/add.c
@@ -0,0 +1,33 @@
+/* mpz_add -- add integers.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#define OPERATION_add
+#include "aors.h"
diff --git a/third_party/gmp/mpz/add_ui.c b/third_party/gmp/mpz/add_ui.c
new file mode 100644
index 0000000..8fd15ad
--- /dev/null
+++ b/third_party/gmp/mpz/add_ui.c
@@ -0,0 +1,33 @@
+/* mpz_add_ui -- Add an mpz_t and an unsigned one-word integer.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#define OPERATION_add_ui
+#include "aors_ui.h"
diff --git a/third_party/gmp/mpz/and.c b/third_party/gmp/mpz/and.c
new file mode 100644
index 0000000..5d34547
--- /dev/null
+++ b/third_party/gmp/mpz/and.c
@@ -0,0 +1,222 @@
+/* mpz_and -- Logical and.
+
+Copyright 1991, 1993, 1994, 1996, 1997, 2000, 2001, 2003, 2005, 2012,
+2015-2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_and (mpz_ptr res, mpz_srcptr op1, mpz_srcptr op2)
+{
+  mp_srcptr op1_ptr, op2_ptr;
+  mp_size_t op1_size, op2_size;
+  mp_ptr res_ptr;
+  mp_size_t res_size;
+  mp_size_t i;
+
+  op1_size = SIZ(op1);
+  op2_size = SIZ(op2);
+
+  if (op1_size < op2_size)
+    {
+      MPZ_SRCPTR_SWAP (op1, op2);
+      MP_SIZE_T_SWAP (op1_size, op2_size);
+    }
+
+  op1_ptr = PTR(op1);
+  op2_ptr = PTR(op2);
+
+  if (op2_size >= 0)
+    {
+      /* First loop finds the size of the result.  */
+      for (i = op2_size; --i >= 0;)
+	if ((op1_ptr[i] & op2_ptr[i]) != 0)
+	  {
+	    res_size = i + 1;
+	    /* Handle allocation, now then we know exactly how much space is
+	       needed for the result.  */
+	    /* Don't re-read op1_ptr and op2_ptr.  Since res_size <=
+	       MIN(op1_size, op2_size), res is not changed when op1
+	       is identical to res or op2 is identical to res.  */
+	    SIZ (res) = res_size;
+	    mpn_and_n (MPZ_NEWALLOC (res, res_size), op1_ptr, op2_ptr, res_size);
+	    return;
+	  }
+
+      SIZ (res) = 0;
+    }
+  else
+    {
+      TMP_DECL;
+
+      op2_size = -op2_size;
+      TMP_MARK;
+      if (op1_size < 0)
+	{
+	  mp_ptr opx, opy;
+
+	  /* Both operands are negative, so will be the result.
+	     -((-OP1) & (-OP2)) = -(~(OP1 - 1) & ~(OP2 - 1)) =
+	     = ~(~(OP1 - 1) & ~(OP2 - 1)) + 1 =
+	     = ((OP1 - 1) | (OP2 - 1)) + 1      */
+
+	  /* It might seem as we could end up with an (invalid) result with
+	     a leading zero-limb here when one of the operands is of the
+	     type 1,,0,,..,,.0.  But some analysis shows that we surely
+	     would get carry into the zero-limb in this situation...  */
+
+	  op1_size = -op1_size;
+
+	  TMP_ALLOC_LIMBS_2 (opx, op1_size, opy, op2_size);
+	  mpn_sub_1 (opx, op1_ptr, op1_size, (mp_limb_t) 1);
+	  op1_ptr = opx;
+
+	  mpn_sub_1 (opy, op2_ptr, op2_size, (mp_limb_t) 1);
+	  op2_ptr = opy;
+
+	  res_ptr = MPZ_NEWALLOC (res, 1 + op2_size);
+	  /* Don't re-read OP1_PTR and OP2_PTR.  They point to temporary
+	     space--never to the space PTR(res) used to point to before
+	     reallocation.  */
+
+	  MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size,
+		    op2_size - op1_size);
+	  mpn_ior_n (res_ptr, op1_ptr, op2_ptr, op1_size);
+	  TMP_FREE;
+	  res_size = op2_size;
+
+	  res_ptr[res_size] = 0;
+	  MPN_INCR_U (res_ptr, res_size + 1, (mp_limb_t) 1);
+	  res_size += res_ptr[res_size];
+
+	  SIZ(res) = -res_size;
+	}
+      else
+	{
+#if ANDNEW
+	  mp_size_t op2_lim;
+	  mp_size_t count;
+
+	  /* OP2 must be negated as with infinite precision.
+
+	     Scan from the low end for a non-zero limb.  The first non-zero
+	     limb is simply negated (two's complement).  Any subsequent
+	     limbs are one's complemented.  Of course, we don't need to
+	     handle more limbs than there are limbs in the other, positive
+	     operand as the result for those limbs is going to become zero
+	     anyway.  */
+
+	  /* Scan for the least significant non-zero OP2 limb, and zero the
+	     result meanwhile for those limb positions.  (We will surely
+	     find a non-zero limb, so we can write the loop with one
+	     termination condition only.)  */
+	  for (i = 0; op2_ptr[i] == 0; i++)
+	    res_ptr[i] = 0;
+	  op2_lim = i;
+
+	  if (op1_size <= op2_size)
+	    {
+	      /* The ones-extended OP2 is >= than the zero-extended OP1.
+		 RES_SIZE <= OP1_SIZE.  Find the exact size.  */
+	      for (i = op1_size - 1; i > op2_lim; i--)
+		if ((op1_ptr[i] & ~op2_ptr[i]) != 0)
+		  break;
+	      res_size = i + 1;
+	      for (i = res_size - 1; i > op2_lim; i--)
+		res_ptr[i] = op1_ptr[i] & ~op2_ptr[i];
+	      res_ptr[op2_lim] = op1_ptr[op2_lim] & -op2_ptr[op2_lim];
+	      /* Yes, this *can* happen!  */
+	      MPN_NORMALIZE (res_ptr, res_size);
+	    }
+	  else
+	    {
+	      /* The ones-extended OP2 is < than the zero-extended OP1.
+		 RES_SIZE == OP1_SIZE, since OP1 is normalized.  */
+	      res_size = op1_size;
+	      MPN_COPY (res_ptr + op2_size, op1_ptr + op2_size, op1_size - op2_size);
+	      for (i = op2_size - 1; i > op2_lim; i--)
+		res_ptr[i] = op1_ptr[i] & ~op2_ptr[i];
+	      res_ptr[op2_lim] = op1_ptr[op2_lim] & -op2_ptr[op2_lim];
+	    }
+#else
+
+	  /* OP1 is positive and zero-extended,
+	     OP2 is negative and ones-extended.
+	     The result will be positive.
+	     OP1 & -OP2 = OP1 & ~(OP2 - 1).  */
+
+	  mp_ptr opx;
+
+	  opx = TMP_ALLOC_LIMBS (op2_size);
+	  mpn_sub_1 (opx, op2_ptr, op2_size, (mp_limb_t) 1);
+	  op2_ptr = opx;
+
+	  if (op1_size > op2_size)
+	    {
+	      /* The result has the same size as OP1, since OP1 is normalized
+		 and longer than the ones-extended OP2.  */
+	      res_size = op1_size;
+
+	      /* Handle allocation, now then we know exactly how much space is
+		 needed for the result.  */
+	      res_ptr = MPZ_NEWALLOC (res, res_size);
+	      /* Don't re-read OP1_PTR or OP2_PTR.  Since res_size = op1_size,
+		 op1 is not changed if it is identical to res.
+		 OP2_PTR points to temporary space.  */
+
+	      mpn_andn_n (res_ptr, op1_ptr, op2_ptr, op2_size);
+	      MPN_COPY (res_ptr + op2_size, op1_ptr + op2_size, res_size - op2_size);
+	    }
+	  else
+	    {
+	      /* Find out the exact result size.  Ignore the high limbs of OP2,
+		 OP1 is zero-extended and would make the result zero.  */
+	      res_size = 0;
+	      for (i = op1_size; --i >= 0;)
+		if ((op1_ptr[i] & ~op2_ptr[i]) != 0)
+		  {
+		    res_size = i + 1;
+		    /* Handle allocation, now then we know exactly how much
+		       space is needed for the result.  */
+		    /* Don't re-read OP1_PTR.  Since res_size <= op1_size,
+		       op1 is not changed if it is identical to res.  Don't
+		       re-read OP2_PTR.  It points to temporary space--never
+		       to the space PTR(res) used to point to before
+		       reallocation.  */
+		    mpn_andn_n (MPZ_NEWALLOC (res, res_size), op1_ptr, op2_ptr, res_size);
+
+		    break;
+		  }
+	    }
+#endif
+	  SIZ(res) = res_size;
+	  TMP_FREE;
+	}
+    }
+}
diff --git a/third_party/gmp/mpz/aors.h b/third_party/gmp/mpz/aors.h
new file mode 100644
index 0000000..722d480
--- /dev/null
+++ b/third_party/gmp/mpz/aors.h
@@ -0,0 +1,123 @@
+/* mpz_add, mpz_sub -- add or subtract integers.
+
+Copyright 1991, 1993, 1994, 1996, 2000, 2001, 2011, 2012 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+#ifdef OPERATION_add
+#define FUNCTION     mpz_add
+#define VARIATION
+#endif
+#ifdef OPERATION_sub
+#define FUNCTION     mpz_sub
+#define VARIATION    -
+#endif
+
+#ifndef FUNCTION
+Error, need OPERATION_add or OPERATION_sub
+#endif
+
+
+void
+FUNCTION (mpz_ptr w, mpz_srcptr u, mpz_srcptr v)
+{
+  mp_srcptr up, vp;
+  mp_ptr wp;
+  mp_size_t usize, vsize, wsize;
+  mp_size_t abs_usize;
+  mp_size_t abs_vsize;
+
+  usize = SIZ(u);
+  vsize = VARIATION SIZ(v);
+  abs_usize = ABS (usize);
+  abs_vsize = ABS (vsize);
+
+  if (abs_usize < abs_vsize)
+    {
+      /* Swap U and V. */
+      MPZ_SRCPTR_SWAP (u, v);
+      MP_SIZE_T_SWAP (usize, vsize);
+      MP_SIZE_T_SWAP (abs_usize, abs_vsize);
+    }
+
+  /* True: ABS_USIZE >= ABS_VSIZE.  */
+
+  /* If not space for w (and possible carry), increase space.  */
+  wsize = abs_usize + 1;
+  wp = MPZ_REALLOC (w, wsize);
+
+  /* These must be after realloc (u or v may be the same as w).  */
+  up = PTR(u);
+  vp = PTR(v);
+
+  if ((usize ^ vsize) < 0)
+    {
+      /* U and V have different sign.  Need to compare them to determine
+	 which operand to subtract from which.  */
+
+      /* This test is right since ABS_USIZE >= ABS_VSIZE.  */
+      if (abs_usize != abs_vsize)
+	{
+	  mpn_sub (wp, up, abs_usize, vp, abs_vsize);
+	  wsize = abs_usize;
+	  MPN_NORMALIZE (wp, wsize);
+	  if (usize < 0)
+	    wsize = -wsize;
+	}
+      else if (mpn_cmp (up, vp, abs_usize) < 0)
+	{
+	  mpn_sub_n (wp, vp, up, abs_usize);
+	  wsize = abs_usize;
+	  MPN_NORMALIZE (wp, wsize);
+	  if (usize >= 0)
+	    wsize = -wsize;
+	}
+      else
+	{
+	  mpn_sub_n (wp, up, vp, abs_usize);
+	  wsize = abs_usize;
+	  MPN_NORMALIZE (wp, wsize);
+	  if (usize < 0)
+	    wsize = -wsize;
+	}
+    }
+  else
+    {
+      /* U and V have same sign.  Add them.  */
+      mp_limb_t cy_limb = mpn_add (wp, up, abs_usize, vp, abs_vsize);
+      wp[abs_usize] = cy_limb;
+      wsize = abs_usize + cy_limb;
+      if (usize < 0)
+	wsize = -wsize;
+    }
+
+  SIZ(w) = wsize;
+}
diff --git a/third_party/gmp/mpz/aors_ui.h b/third_party/gmp/mpz/aors_ui.h
new file mode 100644
index 0000000..ba65af3
--- /dev/null
+++ b/third_party/gmp/mpz/aors_ui.h
@@ -0,0 +1,120 @@
+/* mpz_add_ui, mpz_sub_ui -- Add or subtract an mpz_t and an unsigned
+   one-word integer.
+
+Copyright 1991, 1993, 1994, 1996, 1999-2002, 2004, 2012, 2013, 2015
+Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+#ifdef OPERATION_add_ui
+#define FUNCTION          mpz_add_ui
+#define FUNCTION2         mpz_add
+#define VARIATION_CMP     >=
+#define VARIATION_NEG
+#define VARIATION_UNNEG   -
+#endif
+
+#ifdef OPERATION_sub_ui
+#define FUNCTION          mpz_sub_ui
+#define FUNCTION2         mpz_sub
+#define VARIATION_CMP     <
+#define VARIATION_NEG     -
+#define VARIATION_UNNEG
+#endif
+
+#ifndef FUNCTION
+Error, need OPERATION_add_ui or OPERATION_sub_ui
+#endif
+
+
+void
+FUNCTION (mpz_ptr w, mpz_srcptr u, unsigned long int vval)
+{
+  mp_srcptr up;
+  mp_ptr wp;
+  mp_size_t usize, wsize;
+  mp_size_t abs_usize;
+
+#if BITS_PER_ULONG > GMP_NUMB_BITS  /* avoid warnings about shift amount */
+  if (vval > GMP_NUMB_MAX)
+    {
+      mpz_t v;
+      mp_limb_t vl[2];
+      PTR(v) = vl;
+      vl[0] = vval & GMP_NUMB_MASK;
+      vl[1] = vval >> GMP_NUMB_BITS;
+      SIZ(v) = 2;
+      FUNCTION2 (w, u, v);
+      return;
+    }
+#endif
+
+  usize = SIZ (u);
+  if (usize == 0)
+    {
+      MPZ_NEWALLOC (w, 1)[0] = vval;
+      SIZ (w) = VARIATION_NEG (vval != 0);
+      return;
+    }
+
+  abs_usize = ABS (usize);
+
+  /* If not space for W (and possible carry), increase space.  */
+  wp = MPZ_REALLOC (w, abs_usize + 1);
+
+  /* These must be after realloc (U may be the same as W).  */
+  up = PTR (u);
+
+  if (usize VARIATION_CMP 0)
+    {
+      mp_limb_t cy;
+      cy = mpn_add_1 (wp, up, abs_usize, (mp_limb_t) vval);
+      wp[abs_usize] = cy;
+      wsize = VARIATION_NEG (abs_usize + cy);
+    }
+  else
+    {
+      /* The signs are different.  Need exact comparison to determine
+	 which operand to subtract from which.  */
+      if (abs_usize == 1 && up[0] < vval)
+	{
+	  wp[0] = vval - up[0];
+	  wsize = VARIATION_NEG 1;
+	}
+      else
+	{
+	  mpn_sub_1 (wp, up, abs_usize, (mp_limb_t) vval);
+	  /* Size can decrease with at most one limb.  */
+	  wsize = VARIATION_UNNEG (abs_usize - (wp[abs_usize - 1] == 0));
+	}
+    }
+
+  SIZ (w) = wsize;
+}
diff --git a/third_party/gmp/mpz/aorsmul.c b/third_party/gmp/mpz/aorsmul.c
new file mode 100644
index 0000000..57b06b3
--- /dev/null
+++ b/third_party/gmp/mpz/aorsmul.c
@@ -0,0 +1,163 @@
+/* mpz_addmul, mpz_submul -- add or subtract multiple.
+
+Copyright 2001, 2004, 2005, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* expecting x and y both with non-zero high limbs */
+#define mpn_cmp_twosizes_lt(xp,xsize, yp,ysize)                 \
+  ((xsize) < (ysize)                                            \
+   || ((xsize) == (ysize) && mpn_cmp (xp, yp, xsize) < 0))
+
+
+/* sub>=0 means an addmul w += x*y, sub<0 means a submul w -= x*y.
+
+   The signs of w, x and y are fully accounted for by each flipping "sub".
+
+   The sign of w is retained for the result, unless the absolute value
+   submul underflows, in which case it flips.  */
+
+static void __gmpz_aorsmul (REGPARM_3_1 (mpz_ptr w, mpz_srcptr x, mpz_srcptr y, mp_size_t sub)) REGPARM_ATTR (1);
+#define mpz_aorsmul(w,x,y,sub)  __gmpz_aorsmul (REGPARM_3_1 (w, x, y, sub))
+
+REGPARM_ATTR (1) static void
+mpz_aorsmul (mpz_ptr w, mpz_srcptr x, mpz_srcptr y, mp_size_t sub)
+{
+  mp_size_t  xsize, ysize, tsize, wsize, wsize_signed;
+  mp_ptr     wp, tp;
+  mp_limb_t  c, high;
+  TMP_DECL;
+
+  /* w unaffected if x==0 or y==0 */
+  xsize = SIZ(x);
+  ysize = SIZ(y);
+  if (xsize == 0 || ysize == 0)
+    return;
+
+  /* make x the bigger of the two */
+  if (ABS(ysize) > ABS(xsize))
+    {
+      MPZ_SRCPTR_SWAP (x, y);
+      MP_SIZE_T_SWAP (xsize, ysize);
+    }
+
+  sub ^= ysize;
+  ysize = ABS(ysize);
+
+  /* use mpn_addmul_1/mpn_submul_1 if possible */
+  if (ysize == 1)
+    {
+      mpz_aorsmul_1 (w, x, PTR(y)[0], sub);
+      return;
+    }
+
+  sub ^= xsize;
+  xsize = ABS(xsize);
+
+  wsize_signed = SIZ(w);
+  sub ^= wsize_signed;
+  wsize = ABS(wsize_signed);
+
+  tsize = xsize + ysize;
+  wp = MPZ_REALLOC (w, MAX (wsize, tsize) + 1);
+
+  if (wsize_signed == 0)
+    {
+      /* Nothing to add to, just set w=x*y.  No w==x or w==y overlap here,
+	 since we know x,y!=0 but w==0.  */
+      high = mpn_mul (wp, PTR(x),xsize, PTR(y),ysize);
+      tsize -= (high == 0);
+      SIZ(w) = (sub >= 0 ? tsize : -tsize);
+      return;
+    }
+
+  TMP_MARK;
+  tp = TMP_ALLOC_LIMBS (tsize);
+
+  high = mpn_mul (tp, PTR(x),xsize, PTR(y),ysize);
+  tsize -= (high == 0);
+  ASSERT (tp[tsize-1] != 0);
+  if (sub >= 0)
+    {
+      mp_srcptr up    = wp;
+      mp_size_t usize = wsize;
+
+      if (usize < tsize)
+	{
+	  up	= tp;
+	  usize = tsize;
+	  tp	= wp;
+	  tsize = wsize;
+
+	  wsize = usize;
+	}
+
+      c = mpn_add (wp, up,usize, tp,tsize);
+      wp[wsize] = c;
+      wsize += (c != 0);
+    }
+  else
+    {
+      mp_srcptr up    = wp;
+      mp_size_t usize = wsize;
+
+      if (mpn_cmp_twosizes_lt (up,usize, tp,tsize))
+	{
+	  up	= tp;
+	  usize = tsize;
+	  tp	= wp;
+	  tsize = wsize;
+
+	  wsize = usize;
+	  wsize_signed = -wsize_signed;
+	}
+
+      ASSERT_NOCARRY (mpn_sub (wp, up,usize, tp,tsize));
+      wsize = usize;
+      MPN_NORMALIZE (wp, wsize);
+    }
+
+  SIZ(w) = (wsize_signed >= 0 ? wsize : -wsize);
+
+  TMP_FREE;
+}
+
+
+void
+mpz_addmul (mpz_ptr w, mpz_srcptr u, mpz_srcptr v)
+{
+  mpz_aorsmul (w, u, v, (mp_size_t) 0);
+}
+
+void
+mpz_submul (mpz_ptr w, mpz_srcptr u, mpz_srcptr v)
+{
+  mpz_aorsmul (w, u, v, (mp_size_t) -1);
+}
diff --git a/third_party/gmp/mpz/aorsmul_i.c b/third_party/gmp/mpz/aorsmul_i.c
new file mode 100644
index 0000000..73f986e
--- /dev/null
+++ b/third_party/gmp/mpz/aorsmul_i.c
@@ -0,0 +1,256 @@
+/* mpz_addmul_ui, mpz_submul_ui - add or subtract small multiple.
+
+   THE mpz_aorsmul_1 FUNCTION IN THIS FILE IS FOR INTERNAL USE ONLY AND IS
+   ALMOST CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR
+   COMPLETELY IN FUTURE GNU MP RELEASES.
+
+Copyright 2001, 2002, 2004, 2005, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+#if HAVE_NATIVE_mpn_mul_1c
+#define MPN_MUL_1C(cout, dst, src, size, n, cin)        \
+  do {                                                  \
+    (cout) = mpn_mul_1c (dst, src, size, n, cin);       \
+  } while (0)
+#else
+#define MPN_MUL_1C(cout, dst, src, size, n, cin)        \
+  do {                                                  \
+    mp_limb_t __cy;                                     \
+    __cy = mpn_mul_1 (dst, src, size, n);               \
+    (cout) = __cy + mpn_add_1 (dst, dst, size, cin);    \
+  } while (0)
+#endif
+
+
+/* sub>=0 means an addmul w += x*y, sub<0 means a submul w -= x*y.
+
+   All that's needed to account for negative w or x is to flip "sub".
+
+   The final w will retain its sign, unless an underflow occurs in a submul
+   of absolute values, in which case it's flipped.
+
+   If x has more limbs than w, then mpn_submul_1 followed by mpn_com is
+   used.  The alternative would be mpn_mul_1 into temporary space followed
+   by mpn_sub_n.  Avoiding temporary space seem good, and submul+com stands
+   a chance of being faster since it involves only one set of carry
+   propagations, not two.  Note that doing an addmul_1 with a
+   twos-complement negative y doesn't work, because it effectively adds an
+   extra x * 2^GMP_LIMB_BITS.  */
+
+REGPARM_ATTR(1) void
+mpz_aorsmul_1 (mpz_ptr w, mpz_srcptr x, mp_limb_t y, mp_size_t sub)
+{
+  mp_size_t  xsize, wsize, wsize_signed, new_wsize, min_size, dsize;
+  mp_srcptr  xp;
+  mp_ptr     wp;
+  mp_limb_t  cy;
+
+  /* w unaffected if x==0 or y==0 */
+  xsize = SIZ (x);
+  if (xsize == 0 || y == 0)
+    return;
+
+  sub ^= xsize;
+  xsize = ABS (xsize);
+
+  wsize_signed = SIZ (w);
+  if (wsize_signed == 0)
+    {
+      /* nothing to add to, just set x*y, "sub" gives the sign */
+      wp = MPZ_REALLOC (w, xsize+1);
+      cy = mpn_mul_1 (wp, PTR(x), xsize, y);
+      wp[xsize] = cy;
+      xsize += (cy != 0);
+      SIZ (w) = (sub >= 0 ? xsize : -xsize);
+      return;
+    }
+
+  sub ^= wsize_signed;
+  wsize = ABS (wsize_signed);
+
+  new_wsize = MAX (wsize, xsize);
+  wp = MPZ_REALLOC (w, new_wsize+1);
+  xp = PTR (x);
+  min_size = MIN (wsize, xsize);
+
+  if (sub >= 0)
+    {
+      /* addmul of absolute values */
+
+      cy = mpn_addmul_1 (wp, xp, min_size, y);
+      wp += min_size;
+      xp += min_size;
+
+      dsize = xsize - wsize;
+#if HAVE_NATIVE_mpn_mul_1c
+      if (dsize > 0)
+	cy = mpn_mul_1c (wp, xp, dsize, y, cy);
+      else if (dsize < 0)
+	{
+	  dsize = -dsize;
+	  cy = mpn_add_1 (wp, wp, dsize, cy);
+	}
+#else
+      if (dsize != 0)
+	{
+	  mp_limb_t  cy2;
+	  if (dsize > 0)
+	    cy2 = mpn_mul_1 (wp, xp, dsize, y);
+	  else
+	    {
+	      dsize = -dsize;
+	      cy2 = 0;
+	    }
+	  cy = cy2 + mpn_add_1 (wp, wp, dsize, cy);
+	}
+#endif
+
+      wp[dsize] = cy;
+      new_wsize += (cy != 0);
+    }
+  else
+    {
+      /* submul of absolute values */
+
+      cy = mpn_submul_1 (wp, xp, min_size, y);
+      if (wsize >= xsize)
+	{
+	  /* if w bigger than x, then propagate borrow through it */
+	  if (wsize != xsize)
+	    cy = mpn_sub_1 (wp+xsize, wp+xsize, wsize-xsize, cy);
+
+	  if (cy != 0)
+	    {
+	      /* Borrow out of w, take twos complement negative to get
+		 absolute value, flip sign of w.  */
+	      wp[new_wsize] = ~-cy;  /* extra limb is 0-cy */
+	      mpn_com (wp, wp, new_wsize);
+	      new_wsize++;
+	      MPN_INCR_U (wp, new_wsize, CNST_LIMB(1));
+	      wsize_signed = -wsize_signed;
+	    }
+	}
+      else /* wsize < xsize */
+	{
+	  /* x bigger than w, so want x*y-w.  Submul has given w-x*y, so
+	     take twos complement and use an mpn_mul_1 for the rest.  */
+
+	  mp_limb_t  cy2;
+
+	  /* -(-cy*b^n + w-x*y) = (cy-1)*b^n + ~(w-x*y) + 1 */
+	  mpn_com (wp, wp, wsize);
+	  cy += mpn_add_1 (wp, wp, wsize, CNST_LIMB(1));
+	  cy -= 1;
+
+	  /* If cy-1 == -1 then hold that -1 for latter.  mpn_submul_1 never
+	     returns cy==MP_LIMB_T_MAX so that value always indicates a -1. */
+	  cy2 = (cy == MP_LIMB_T_MAX);
+	  cy += cy2;
+	  MPN_MUL_1C (cy, wp+wsize, xp+wsize, xsize-wsize, y, cy);
+	  wp[new_wsize] = cy;
+	  new_wsize += (cy != 0);
+
+	  /* Apply any -1 from above.  The value at wp+wsize is non-zero
+	     because y!=0 and the high limb of x will be non-zero.  */
+	  if (cy2)
+	    MPN_DECR_U (wp+wsize, new_wsize-wsize, CNST_LIMB(1));
+
+	  wsize_signed = -wsize_signed;
+	}
+
+      /* submul can produce high zero limbs due to cancellation, both when w
+	 has more limbs or x has more  */
+      MPN_NORMALIZE (wp, new_wsize);
+    }
+
+  SIZ (w) = (wsize_signed >= 0 ? new_wsize : -new_wsize);
+
+  ASSERT (new_wsize == 0 || PTR(w)[new_wsize-1] != 0);
+}
+
+
+void
+mpz_addmul_ui (mpz_ptr w, mpz_srcptr x, unsigned long y)
+{
+#if BITS_PER_ULONG > GMP_NUMB_BITS
+  if (UNLIKELY (y > GMP_NUMB_MAX))
+    {
+      mpz_t t;
+      mp_ptr tp;
+      mp_size_t xn;
+      TMP_DECL;
+      TMP_MARK;
+      xn = SIZ (x);
+      if (xn == 0) return;
+      MPZ_TMP_INIT (t, ABS (xn) + 1);
+      tp = PTR (t);
+      tp[0] = 0;
+      MPN_COPY (tp + 1, PTR(x), ABS (xn));
+      SIZ(t) = xn >= 0 ? xn + 1 : xn - 1;
+      mpz_aorsmul_1 (w, t, (mp_limb_t) y >> GMP_NUMB_BITS, (mp_size_t) 0);
+      PTR(t) = tp + 1;
+      SIZ(t) = xn;
+      mpz_aorsmul_1 (w, t, (mp_limb_t) y & GMP_NUMB_MASK, (mp_size_t) 0);
+      TMP_FREE;
+      return;
+    }
+#endif
+  mpz_aorsmul_1 (w, x, (mp_limb_t) y, (mp_size_t) 0);
+}
+
+void
+mpz_submul_ui (mpz_ptr w, mpz_srcptr x, unsigned long y)
+{
+#if BITS_PER_ULONG > GMP_NUMB_BITS
+  if (y > GMP_NUMB_MAX)
+    {
+      mpz_t t;
+      mp_ptr tp;
+      mp_size_t xn;
+      TMP_DECL;
+      TMP_MARK;
+      xn = SIZ (x);
+      if (xn == 0) return;
+      MPZ_TMP_INIT (t, ABS (xn) + 1);
+      tp = PTR (t);
+      tp[0] = 0;
+      MPN_COPY (tp + 1, PTR(x), ABS (xn));
+      SIZ(t) = xn >= 0 ? xn + 1 : xn - 1;
+      mpz_aorsmul_1 (w, t, (mp_limb_t) y >> GMP_NUMB_BITS, (mp_size_t) -1);
+      PTR(t) = tp + 1;
+      SIZ(t) = xn;
+      mpz_aorsmul_1 (w, t, (mp_limb_t) y & GMP_NUMB_MASK, (mp_size_t) -1);
+      TMP_FREE;
+      return;
+    }
+#endif
+  mpz_aorsmul_1 (w, x, (mp_limb_t) y & GMP_NUMB_MASK, (mp_size_t) -1);
+}
diff --git a/third_party/gmp/mpz/array_init.c b/third_party/gmp/mpz/array_init.c
new file mode 100644
index 0000000..df97f34
--- /dev/null
+++ b/third_party/gmp/mpz/array_init.c
@@ -0,0 +1,49 @@
+/* mpz_array_init (array, array_size, size_per_elem) --
+
+Copyright 1991, 1993-1995, 2000-2002, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_array_init (mpz_ptr arr, mp_size_t arr_size, mp_size_t nbits)
+{
+  mp_ptr p;
+  mp_size_t i;
+  mp_size_t nlimbs;
+
+  nlimbs = nbits / GMP_NUMB_BITS + 1;
+  p = __GMP_ALLOCATE_FUNC_LIMBS (arr_size * nlimbs);
+
+  for (i = 0; i < arr_size; i++)
+    {
+      ALLOC (&arr[i]) = nlimbs + 1; /* Yes, lie a little... */
+      SIZ (&arr[i]) = 0;
+      PTR (&arr[i]) = p + i * nlimbs;
+    }
+}
diff --git a/third_party/gmp/mpz/bin_ui.c b/third_party/gmp/mpz/bin_ui.c
new file mode 100644
index 0000000..bab3e07
--- /dev/null
+++ b/third_party/gmp/mpz/bin_ui.c
@@ -0,0 +1,459 @@
+/* mpz_bin_ui(RESULT, N, K) -- Set RESULT to N over K.
+
+Copyright 1998-2002, 2012, 2013, 2015, 2017-2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/* How many special cases? Minimum is 2: 0 and 1;
+ * also 3 {0,1,2} and 5 {0,1,2,3,4} are implemented.
+ */
+#define APARTAJ_KALKULOJ 2
+
+/* Whether to use (1) or not (0) the function mpz_bin_uiui whenever
+ * the operands fit.
+ */
+#define UZU_BIN_UIUI 0
+
+/* Whether to use a shortcut to precompute the product of four
+ * elements (1), or precompute only the product of a couple (0).
+ *
+ * In both cases the precomputed product is then updated with some
+ * linear operations to obtain the product of the next four (1)
+ * [or two (0)] operands.
+ */
+#define KVAROPE 1
+
+static void
+posmpz_init (mpz_ptr r)
+{
+  mp_ptr rp;
+  ASSERT (SIZ (r) > 0);
+  rp = SIZ (r) + MPZ_REALLOC (r, SIZ (r) + 2);
+  *rp = 0;
+  *++rp = 0;
+}
+
+/* Equivalent to mpz_add_ui (r, r, in), but faster when
+   0 < SIZ (r) < ALLOC (r) and limbs above SIZ (r) contain 0. */
+static void
+posmpz_inc_ui (mpz_ptr r, unsigned long in)
+{
+#if BITS_PER_ULONG > GMP_NUMB_BITS
+  mpz_add_ui (r, r, in);
+#else
+  ASSERT (SIZ (r) > 0);
+  MPN_INCR_U (PTR (r), SIZ (r) + 1, in);
+  SIZ (r) += (PTR (r)[SIZ (r)] != 0);
+#endif
+}
+
+/* Equivalent to mpz_sub_ui (r, r, in), but faster when
+   0 < SIZ (r) and we know in advance that the result is positive. */
+static void
+posmpz_dec_ui (mpz_ptr r, unsigned long in)
+{
+#if BITS_PER_ULONG > GMP_NUMB_BITS
+  mpz_sub_ui (r, r, in);
+#else
+  ASSERT (mpz_cmp_ui (r, in) >= 0);
+  MPN_DECR_U (PTR (r), SIZ (r), in);
+  SIZ (r) -= (PTR (r)[SIZ (r)-1] == 0);
+#endif
+}
+
+/* Equivalent to mpz_tdiv_q_2exp (r, r, 1), but faster when
+   0 < SIZ (r) and we know in advance that the result is positive. */
+static void
+posmpz_rsh1 (mpz_ptr r)
+{
+  mp_ptr rp;
+  mp_size_t rn;
+
+  rn = SIZ (r);
+  rp = PTR (r);
+  ASSERT (rn > 0);
+  mpn_rshift (rp, rp, rn, 1);
+  SIZ (r) -= rp[rn - 1] == 0;
+}
+
+/* Computes r = n(n+(2*k-1))/2
+   It uses a sqare instead of a product, computing
+   r = ((n+k-1)^2 + n - (k-1)^2)/2
+   As a side effect, sets t = n+k-1
+ */
+static void
+mpz_hmul_nbnpk (mpz_ptr r, mpz_srcptr n, unsigned long int k, mpz_ptr t)
+{
+  ASSERT (k > 0 && SIZ(n) > 0);
+  --k;
+  mpz_add_ui (t, n, k);
+  mpz_mul (r, t, t);
+  mpz_add (r, r, n);
+  posmpz_rsh1 (r);
+  if (LIKELY (k <= (1UL << (BITS_PER_ULONG / 2))))
+    posmpz_dec_ui (r, (k + (k & 1))*(k >> 1));
+  else
+    {
+      mpz_t tmp;
+      mpz_init_set_ui (tmp, (k + (k & 1)));
+      mpz_mul_ui (tmp, tmp, k >> 1);
+      mpz_sub (r, r, tmp);
+      mpz_clear (tmp);
+    }
+}
+
+#if KVAROPE
+static void
+rek_raising_fac4 (mpz_ptr r, mpz_ptr p, mpz_ptr P, unsigned long int k, unsigned long int lk, mpz_ptr t)
+{
+  if (k - lk < 5)
+    {
+      do {
+	posmpz_inc_ui (p, 4*k+2);
+	mpz_addmul_ui (P, p, 4*k);
+	posmpz_dec_ui (P, k);
+	mpz_mul (r, r, P);
+      } while (--k > lk);
+    }
+  else
+    {
+      mpz_t lt;
+      unsigned long int m;
+
+      m = ((k + lk) >> 1) + 1;
+      rek_raising_fac4 (r, p, P, k, m, t);
+
+      posmpz_inc_ui (p, 4*m+2);
+      mpz_addmul_ui (P, p, 4*m);
+      posmpz_dec_ui (P, m);
+      if (t == NULL)
+	{
+	  mpz_init_set (lt, P);
+	  t = lt;
+	}
+      else
+	{
+	  ALLOC (lt) = 0;
+	  mpz_set (t, P);
+	}
+      rek_raising_fac4 (t, p, P, m - 1, lk, NULL);
+
+      mpz_mul (r, r, t);
+      mpz_clear (lt);
+    }
+}
+
+/* Computes (n+1)(n+2)...(n+k)/2^(k/2 +k/4) using the helper function
+   rek_raising_fac4, and exploiting an idea inspired by a piece of
+   code that Fredrik Johansson wrote and by a comment by Niels Möller.
+
+   Assume k = 4i then compute:
+     p  = (n+1)(n+4i)/2 - i
+	  (n+1+1)(n+4i)/2 = p + i + (n+4i)/2
+	  (n+1+1)(n+4i-1)/2 = p + i + ((n+4i)-(n+1+1))/2 = p + i + (n-n+4i-2)/2 = p + 3i-1
+     P  = (p + i)*(p+3i-1)/2 = (n+1)(n+2)(n+4i-1)(n+4i)/8
+     n' = n + 2
+     i' = i - 1
+	  (n'-1)(n')(n'+4i'+1)(n'+4i'+2)/8 = P
+	  (n'-1)(n'+4i'+2)/2 - i' - 1 = p
+	  (n'-1+2)(n'+4i'+2)/2 - i' - 1 = p + (n'+4i'+2)
+	  (n'-1+2)(n'+4i'+2-2)/2 - i' - 1 = p + (n'+4i'+2) - (n'-1+2) =  p + 4i' + 1
+	  (n'-1+2)(n'+4i'+2-2)/2 - i' = p + 4i' + 2
+     p' = p + 4i' + 2 = (n'+1)(n'+4i')/2 - i'
+	  p' - 4i' - 2 = p
+	  (p' - 4i' - 2 + i)*(p' - 4i' - 2+3i-1)/2 = P
+	  (p' - 4i' - 2 + i' + 1)*(p' - 4i' - 2 + 3i' + 3 - 1)/2 = P
+	  (p' - 3i' - 1)*(p' - i')/2 = P
+	  (p' - 3i' - 1 + 4i' + 1)*(p' - i' + 4i' - 1)/2 = P + (4i' + 1)*(p' - i')/2 + (p' - 3i' - 1 + 4i' + 1)*(4i' - 1)/2
+	  (p' + i')*(p' + 3i' - 1)/2 = P + (4i')*(p' + p')/2 + (p' - i' - (p' + i'))/2
+	  (p' + i')*(p' + 3i' - 1)/2 = P + 4i'p' + (p' - i' - p' - i')/2
+	  (p' + i')*(p' + 3i' - 1)/2 = P + 4i'p' - i'
+     P' = P + 4i'p' - i'
+
+   And compute the product P * P' * P" ...
+ */
+
+static void
+mpz_raising_fac4 (mpz_ptr r, mpz_ptr n, unsigned long int k, mpz_ptr t, mpz_ptr p)
+{
+  ASSERT ((k >= APARTAJ_KALKULOJ) && (APARTAJ_KALKULOJ > 0));
+  posmpz_init (n);
+  posmpz_inc_ui (n, 1);
+  SIZ (r) = 0;
+  if (k & 1)
+    {
+      mpz_set (r, n);
+      posmpz_inc_ui (n, 1);
+    }
+  k >>= 1;
+  if (APARTAJ_KALKULOJ < 2 && k == 0)
+    return;
+
+  mpz_hmul_nbnpk (p, n, k, t);
+  posmpz_init (p);
+
+  if (k & 1)
+    {
+      if (SIZ (r))
+	mpz_mul (r, r, p);
+      else
+	mpz_set (r, p);
+      posmpz_inc_ui (p, k - 1);
+    }
+  k >>= 1;
+  if (APARTAJ_KALKULOJ < 4 && k == 0)
+    return;
+
+  mpz_hmul_nbnpk (t, p, k, n);
+  if (SIZ (r))
+    mpz_mul (r, r, t);
+  else
+    mpz_set (r, t);
+
+  if (APARTAJ_KALKULOJ > 8 || k > 1)
+    {
+      posmpz_dec_ui (p, k);
+      rek_raising_fac4 (r, p, t, k - 1, 0, n);
+    }
+}
+
+#else /* KVAROPE */
+
+static void
+rek_raising_fac (mpz_ptr r, mpz_ptr n, unsigned long int k, unsigned long int lk, mpz_ptr t1, mpz_ptr t2)
+{
+  /* Should the threshold depend on SIZ (n) ? */
+  if (k - lk < 10)
+    {
+      do {
+	posmpz_inc_ui (n, k);
+	mpz_mul (r, r, n);
+	--k;
+      } while (k > lk);
+    }
+  else
+    {
+      mpz_t t3;
+      unsigned long int m;
+
+      m = ((k + lk) >> 1) + 1;
+      rek_raising_fac (r, n, k, m, t1, t2);
+
+      posmpz_inc_ui (n, m);
+      if (t1 == NULL)
+	{
+	  mpz_init_set (t3, n);
+	  t1 = t3;
+	}
+      else
+	{
+	  ALLOC (t3) = 0;
+	  mpz_set (t1, n);
+	}
+      rek_raising_fac (t1, n, m - 1, lk, t2, NULL);
+
+      mpz_mul (r, r, t1);
+      mpz_clear (t3);
+    }
+}
+
+/* Computes (n+1)(n+2)...(n+k)/2^(k/2) using the helper function
+   rek_raising_fac, and exploiting an idea inspired by a piece of
+   code that Fredrik Johansson wrote.
+
+   Force an even k = 2i then compute:
+     p  = (n+1)(n+2i)/2
+     i' = i - 1
+     p == (n+1)(n+2i'+2)/2
+     p' = p + i' == (n+2)(n+2i'+1)/2
+     n' = n + 1
+     p'== (n'+1)(n'+2i')/2 == (n+1 +1)(n+2i -1)/2
+
+   And compute the product p * p' * p" ...
+*/
+
+static void
+mpz_raising_fac (mpz_ptr r, mpz_ptr n, unsigned long int k, mpz_ptr t, mpz_ptr p)
+{
+  unsigned long int hk;
+  ASSERT ((k >= APARTAJ_KALKULOJ) && (APARTAJ_KALKULOJ > 1));
+  mpz_add_ui (n, n, 1);
+  hk = k >> 1;
+  mpz_hmul_nbnpk (p, n, hk, t);
+
+  if ((k & 1) != 0)
+    {
+      mpz_add_ui (t, t, hk + 1);
+      mpz_mul (r, t, p);
+    }
+  else
+    {
+      mpz_set (r, p);
+    }
+
+  if ((APARTAJ_KALKULOJ > 3) || (hk > 1))
+    {
+      posmpz_init (p);
+      rek_raising_fac (r, p, hk - 1, 0, t, n);
+    }
+}
+#endif /* KVAROPE */
+
+/* This is a poor implementation.  Look at bin_uiui.c for improvement ideas.
+   In fact consider calling mpz_bin_uiui() when the arguments fit, leaving
+   the code here only for big n.
+
+   The identity bin(n,k) = (-1)^k * bin(-n+k-1,k) can be found in Knuth vol
+   1 section 1.2.6 part G. */
+
+void
+mpz_bin_ui (mpz_ptr r, mpz_srcptr n, unsigned long int k)
+{
+  mpz_t      ni;
+  mp_size_t  negate;
+
+  if (SIZ (n) < 0)
+    {
+      /* bin(n,k) = (-1)^k * bin(-n+k-1,k), and set ni = -n+k-1 - k = -n-1 */
+      mpz_init (ni);
+      mpz_add_ui (ni, n, 1L);
+      mpz_neg (ni, ni);
+      negate = (k & 1);   /* (-1)^k */
+    }
+  else
+    {
+      /* bin(n,k) == 0 if k>n
+	 (no test for this under the n<0 case, since -n+k-1 >= k there) */
+      if (mpz_cmp_ui (n, k) < 0)
+	{
+	  SIZ (r) = 0;
+	  return;
+	}
+
+      /* set ni = n-k */
+      mpz_init (ni);
+      mpz_sub_ui (ni, n, k);
+      negate = 0;
+    }
+
+  /* Now wanting bin(ni+k,k), with ni positive, and "negate" is the sign (0
+     for positive, 1 for negative). */
+
+  /* Rewrite bin(n,k) as bin(n,n-k) if that is smaller.  In this case it's
+     whether ni+k-k < k meaning ni<k, and if so change to denominator ni+k-k
+     = ni, and new ni of ni+k-ni = k.  */
+  if (mpz_cmp_ui (ni, k) < 0)
+    {
+      unsigned long  tmp;
+      tmp = k;
+      k = mpz_get_ui (ni);
+      mpz_set_ui (ni, tmp);
+    }
+
+  if (k < APARTAJ_KALKULOJ)
+    {
+      if (k == 0)
+	{
+	  SIZ (r) = 1;
+	  MPZ_NEWALLOC (r, 1)[0] = 1;
+	}
+#if APARTAJ_KALKULOJ > 2
+      else if (k == 2)
+	{
+	  mpz_add_ui (ni, ni, 1);
+	  mpz_mul (r, ni, ni);
+	  mpz_add (r, r, ni);
+	  posmpz_rsh1 (r);
+	}
+#endif
+#if APARTAJ_KALKULOJ > 3
+      else if (k > 2)
+	{ /* k = 3, 4 */
+	  mpz_add_ui (ni, ni, 2); /* n+1 */
+	  mpz_mul (r, ni, ni); /* (n+1)^2 */
+	  mpz_sub_ui (r, r, 1); /* (n+1)^2-1 */
+	  if (k == 3)
+	    {
+	      mpz_mul (r, r, ni); /* ((n+1)^2-1)(n+1) = n(n+1)(n+2) */
+	      /* mpz_divexact_ui (r, r, 6); /\* 6=3<<1; div_by3 ? *\/ */
+	      mpn_pi1_bdiv_q_1 (PTR(r), PTR(r), SIZ(r), 3, GMP_NUMB_MASK/3*2+1, 1);
+	      MPN_NORMALIZE_NOT_ZERO (PTR(r), SIZ(r));
+	    }
+	  else /* k = 4 */
+	    {
+	      mpz_add (ni, ni, r); /* (n+1)^2+n */
+	      mpz_mul (r, ni, ni); /* ((n+1)^2+n)^2 */
+	      mpz_sub_ui (r, r, 1); /* ((n+1)^2+n)^2-1 = n(n+1)(n+2)(n+3) */
+	      /* mpz_divexact_ui (r, r, 24); /\* 24=3<<3; div_by3 ? *\/ */
+	      mpn_pi1_bdiv_q_1 (PTR(r), PTR(r), SIZ(r), 3, GMP_NUMB_MASK/3*2+1, 3);
+	      MPN_NORMALIZE_NOT_ZERO (PTR(r), SIZ(r));
+	    }
+	}
+#endif
+      else
+	{ /* k = 1 */
+	  mpz_add_ui (r, ni, 1);
+	}
+    }
+#if UZU_BIN_UIUI
+  else if (mpz_cmp_ui (ni, ULONG_MAX - k) <= 0)
+    {
+      mpz_bin_uiui (r, mpz_get_ui (ni) + k, k);
+    }
+#endif
+  else
+    {
+      mp_limb_t count;
+      mpz_t num, den;
+
+      mpz_init (num);
+      mpz_init (den);
+
+#if KVAROPE
+      mpz_raising_fac4 (num, ni, k, den, r);
+      popc_limb (count, k);
+      ASSERT (k - (k >> 1) - (k >> 2) - count >= 0);
+      mpz_tdiv_q_2exp (num, num, k - (k >> 1) - (k >> 2) - count);
+#else
+      mpz_raising_fac (num, ni, k, den, r);
+      popc_limb (count, k);
+      ASSERT (k - (k >> 1) - count >= 0);
+      mpz_tdiv_q_2exp (num, num, k - (k >> 1) - count);
+#endif
+
+      mpz_oddfac_1(den, k, 0);
+
+      mpz_divexact(r, num, den);
+      mpz_clear (num);
+      mpz_clear (den);
+    }
+  mpz_clear (ni);
+
+  SIZ(r) = (SIZ(r) ^ -negate) + negate;
+}
diff --git a/third_party/gmp/mpz/bin_uiui.c b/third_party/gmp/mpz/bin_uiui.c
new file mode 100644
index 0000000..b77628f
--- /dev/null
+++ b/third_party/gmp/mpz/bin_uiui.c
@@ -0,0 +1,707 @@
+/* mpz_bin_uiui - compute n over k.
+
+Contributed to the GNU project by Torbjorn Granlund and Marco Bodrato.
+
+Copyright 2010-2012, 2015-2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#ifndef BIN_GOETGHELUCK_THRESHOLD
+#define BIN_GOETGHELUCK_THRESHOLD  512
+#endif
+#ifndef BIN_UIUI_ENABLE_SMALLDC
+#define BIN_UIUI_ENABLE_SMALLDC    1
+#endif
+#ifndef BIN_UIUI_RECURSIVE_SMALLDC
+#define BIN_UIUI_RECURSIVE_SMALLDC (GMP_NUMB_BITS > 32)
+#endif
+
+/* Algorithm:
+
+   Accumulate chunks of factors first limb-by-limb (using one of mul0-mul8)
+   which are then accumulated into mpn numbers.  The first inner loop
+   accumulates divisor factors, the 2nd inner loop accumulates exactly the same
+   number of dividend factors.  We avoid accumulating more for the divisor,
+   even with its smaller factors, since we else cannot guarantee divisibility.
+
+   Since we know each division will yield an integer, we compute the quotient
+   using Hensel norm: If the quotient is limited by 2^t, we compute A / B mod
+   2^t.
+
+   Improvements:
+
+   (1) An obvious improvement to this code would be to compute mod 2^t
+   everywhere.  Unfortunately, we cannot determine t beforehand, unless we
+   invoke some approximation, such as Stirling's formula.  Of course, we don't
+   need t to be tight.  However, it is not clear that this would help much,
+   our numbers are kept reasonably small already.
+
+   (2) Compute nmax/kmax semi-accurately, without scalar division or a loop.
+   Extracting the 3 msb, then doing a table lookup using cnt*8+msb as index,
+   would make it both reasonably accurate and fast.  (We could use a table
+   stored into a limb, perhaps.)  The table should take the removed factors of
+   2 into account (those done on-the-fly in mulN).
+
+   (3) The first time in the loop we compute the odd part of a
+   factorial in kp, we might use oddfac_1 for this task.
+ */
+
+/* This threshold determines how large divisor to accumulate before we call
+   bdiv.  Perhaps we should never call bdiv, and accumulate all we are told,
+   since we are just basecase code anyway?  Presumably, this depends on the
+   relative speed of the asymptotically fast code and this code.  */
+#define SOME_THRESHOLD 20
+
+/* Multiply-into-limb functions.  These remove factors of 2 on-the-fly.  FIXME:
+   All versions of MAXFACS don't take this 2 removal into account now, meaning
+   that then, shifting just adds some overhead.  (We remove factors from the
+   completed limb anyway.)  */
+
+static mp_limb_t
+mul1 (mp_limb_t m)
+{
+  return m;
+}
+
+static mp_limb_t
+mul2 (mp_limb_t m)
+{
+  /* We need to shift before multiplying, to avoid an overflow. */
+  mp_limb_t m01 = (m | 1) * ((m + 1) >> 1);
+  return m01;
+}
+
+static mp_limb_t
+mul3 (mp_limb_t m)
+{
+  mp_limb_t m01 = (m + 0) * (m + 1) >> 1;
+  mp_limb_t m2 = (m + 2);
+  return m01 * m2;
+}
+
+static mp_limb_t
+mul4 (mp_limb_t m)
+{
+  mp_limb_t m03 = (m + 0) * (m + 3) >> 1;
+  return m03 * (m03 + 1); /* mul2 (m03) ? */
+}
+
+static mp_limb_t
+mul5 (mp_limb_t m)
+{
+  mp_limb_t m03 = (m + 0) * (m + 3) >> 1;
+  mp_limb_t m034 = m03 * (m + 4);
+  return (m03 + 1) * m034;
+}
+
+static mp_limb_t
+mul6 (mp_limb_t m)
+{
+  mp_limb_t m05 = (m + 0) * (m + 5);
+  mp_limb_t m1234 = (m05 + 5) * (m05 + 5) >> 3;
+  return m1234 * (m05 >> 1);
+}
+
+static mp_limb_t
+mul7 (mp_limb_t m)
+{
+  mp_limb_t m05 = (m + 0) * (m + 5);
+  mp_limb_t m1234 = (m05 + 5) * (m05 + 5) >> 3;
+  mp_limb_t m056 = m05 * (m + 6) >> 1;
+  return m1234 * m056;
+}
+
+static mp_limb_t
+mul8 (mp_limb_t m)
+{
+  mp_limb_t m07 = (m + 0) * (m + 7);
+  mp_limb_t m0257 = m07 * (m07 + 10) >> 3;
+  mp_limb_t m1346 = m07 + 9 + m0257;
+  return m0257 * m1346;
+}
+
+/*
+static mp_limb_t
+mul9 (mp_limb_t m)
+{
+  return (m + 8) * mul8 (m) ;
+}
+
+static mp_limb_t
+mul10 (mp_limb_t m)
+{
+  mp_limb_t m09 = (m + 0) * (m + 9);
+  mp_limb_t m18 = (m09 >> 1) + 4;
+  mp_limb_t m0369 = m09 * (m09 + 18) >> 3;
+  mp_limb_t m2457 = m09 * 2 + 35 + m0369;
+  return ((m0369 * m2457) >> 1) * m18;
+}
+*/
+
+typedef mp_limb_t (* mulfunc_t) (mp_limb_t);
+
+static const mulfunc_t mulfunc[] = {mul1,mul2,mul3,mul4,mul5,mul6,mul7,mul8 /* ,mul9,mul10 */};
+#define M (numberof(mulfunc))
+
+/* Number of factors-of-2 removed by the corresponding mulN function.  */
+static const unsigned char tcnttab[] = {0, 1, 1, 2, 2, 4, 4, 6 /*,6,8*/};
+
+#if 1
+/* This variant is inaccurate but share the code with other functions.  */
+#define MAXFACS(max,l)							\
+  do {									\
+    (max) = log_n_max (l);						\
+  } while (0)
+#else
+
+/* This variant is exact(?) but uses a loop.  It takes the 2 removal
+ of mulN into account.  */
+static const unsigned long ftab[] =
+#if GMP_NUMB_BITS == 64
+  /* 1 to 8 factors per iteration */
+  {CNST_LIMB(0xffffffffffffffff),CNST_LIMB(0x16a09e667),0x32cbfc,0x16a08,0x24c0,0xa11,0x345,0x1ab /*,0xe9,0x8e */};
+#endif
+#if GMP_NUMB_BITS == 32
+  /* 1 to 7 factors per iteration */
+  {0xffffffff,0x16a09,0x7ff,0x168,0x6f,0x3d,0x20 /* ,0x17 */};
+#endif
+
+#define MAXFACS(max,l)							\
+  do {									\
+    int __i;								\
+    for (__i = numberof (ftab) - 1; l > ftab[__i]; __i--)		\
+      ;									\
+    (max) = __i + 1;							\
+  } while (0)
+#endif
+
+/* Entry i contains (i!/2^t)^(-1) where t is chosen such that the parenthesis
+   is an odd integer. */
+static const mp_limb_t facinv[] = { ONE_LIMB_ODD_FACTORIAL_INVERSES_TABLE };
+
+static void
+mpz_bdiv_bin_uiui (mpz_ptr r, unsigned long int n, unsigned long int k)
+{
+  unsigned nmax, kmax, nmaxnow, numfac;
+  mp_ptr np, kp;
+  mp_size_t nn, kn, alloc;
+  mp_limb_t i, j, t, iii, jjj, cy, dinv;
+  int cnt;
+  mp_size_t maxn;
+  TMP_DECL;
+
+  ASSERT (k > ODD_FACTORIAL_TABLE_LIMIT);
+  TMP_MARK;
+
+  maxn = 1 + n / GMP_NUMB_BITS;    /* absolutely largest result size (limbs) */
+
+  /* FIXME: This allocation might be insufficient, but is usually way too
+     large.  */
+  alloc = SOME_THRESHOLD - 1 + MAX (3 * maxn / 2, SOME_THRESHOLD);
+  alloc = MIN (alloc, (mp_size_t) k) + 1;
+  TMP_ALLOC_LIMBS_2 (np, alloc, kp, SOME_THRESHOLD + 1);
+
+  MAXFACS (nmax, n);
+  ASSERT (nmax <= M);
+  MAXFACS (kmax, k);
+  ASSERT (kmax <= M);
+  ASSERT (k >= M);
+
+  i = n - k + 1;
+
+  np[0] = 1; nn = 1;
+
+  numfac = 1;
+  j = ODD_FACTORIAL_TABLE_LIMIT + 1;
+  jjj = ODD_FACTORIAL_TABLE_MAX;
+  ASSERT (__gmp_oddfac_table[ODD_FACTORIAL_TABLE_LIMIT] == ODD_FACTORIAL_TABLE_MAX);
+
+  while (1)
+    {
+      kp[0] = jjj;				/* store new factors */
+      kn = 1;
+      t = k - j + 1;
+      kmax = MIN (kmax, t);
+
+      while (kmax != 0 && kn < SOME_THRESHOLD)
+	{
+	  jjj = mulfunc[kmax - 1] (j);
+	  j += kmax;				/* number of factors used */
+	  count_trailing_zeros (cnt, jjj);	/* count low zeros */
+	  jjj >>= cnt;				/* remove remaining low zeros */
+	  cy = mpn_mul_1 (kp, kp, kn, jjj);	/* accumulate new factors */
+	  kp[kn] = cy;
+	  kn += cy != 0;
+	  t = k - j + 1;
+	  kmax = MIN (kmax, t);
+	}
+      numfac = j - numfac;
+
+      while (numfac != 0)
+	{
+	  nmaxnow = MIN (nmax, numfac);
+	  iii = mulfunc[nmaxnow - 1] (i);
+	  i += nmaxnow;				/* number of factors used */
+	  count_trailing_zeros (cnt, iii);	/* count low zeros */
+	  iii >>= cnt;				/* remove remaining low zeros */
+	  cy = mpn_mul_1 (np, np, nn, iii);	/* accumulate new factors */
+	  np[nn] = cy;
+	  nn += cy != 0;
+	  numfac -= nmaxnow;
+	}
+
+      ASSERT (nn < alloc);
+
+      binvert_limb (dinv, kp[0]);
+      nn += (np[nn - 1] >= kp[kn - 1]);
+      nn -= kn;
+      mpn_sbpi1_bdiv_q (np, np, nn, kp, MIN(kn,nn), -dinv);
+      mpn_neg (np, np, nn);
+
+      if (kmax == 0)
+	break;
+      numfac = j;
+
+      jjj = mulfunc[kmax - 1] (j);
+      j += kmax;				/* number of factors used */
+      count_trailing_zeros (cnt, jjj);		/* count low zeros */
+      jjj >>= cnt;				/* remove remaining low zeros */
+    }
+
+  /* Put back the right number of factors of 2.  */
+  popc_limb (cnt, n - k);
+  popc_limb (j, k);
+  cnt += j;
+  popc_limb (j, n);
+  cnt -= j;
+  if (cnt != 0)
+    {
+      ASSERT (cnt < GMP_NUMB_BITS); /* can happen, but not for intended use */
+      cy = mpn_lshift (np, np, nn, cnt);
+      np[nn] = cy;
+      nn += cy != 0;
+    }
+
+  nn -= np[nn - 1] == 0;	/* normalisation */
+
+  kp = MPZ_NEWALLOC (r, nn);
+  SIZ(r) = nn;
+  MPN_COPY (kp, np, nn);
+  TMP_FREE;
+}
+
+static void
+mpz_smallk_bin_uiui (mpz_ptr r, unsigned long int n, unsigned long int k)
+{
+  unsigned nmax, numfac;
+  mp_ptr rp;
+  mp_size_t rn, alloc;
+  mp_limb_t i, iii, cy;
+  unsigned i2cnt, cnt;
+
+  MAXFACS (nmax, n);
+  nmax = MIN (nmax, M);
+
+  i = n - k + 1;
+
+  i2cnt = __gmp_fac2cnt_table[k / 2 - 1];		/* low zeros count */
+  if (nmax >= k)
+    {
+      MPZ_NEWALLOC (r, 1) [0] = mulfunc[k - 1] (i) * facinv[k - 2] >>
+	(i2cnt - tcnttab[k - 1]);
+      SIZ(r) = 1;
+      return;
+    }
+
+  count_leading_zeros (cnt, (mp_limb_t) n);
+  cnt = GMP_LIMB_BITS - cnt;
+  alloc = cnt * k / GMP_NUMB_BITS + 3;	/* FIXME: ensure rounding is enough. */
+  rp = MPZ_NEWALLOC (r, alloc);
+
+  rp[0] = mulfunc[nmax - 1] (i);
+  rn = 1;
+  i += nmax;				/* number of factors used */
+  i2cnt -= tcnttab[nmax - 1];		/* low zeros count */
+  numfac = k - nmax;
+  do
+    {
+      nmax = MIN (nmax, numfac);
+      iii = mulfunc[nmax - 1] (i);
+      i += nmax;			/* number of factors used */
+      i2cnt -= tcnttab[nmax - 1];	/* update low zeros count */
+      cy = mpn_mul_1 (rp, rp, rn, iii);	/* accumulate new factors */
+      rp[rn] = cy;
+      rn += cy != 0;
+      numfac -= nmax;
+    } while (numfac != 0);
+
+  ASSERT (rn < alloc);
+
+  mpn_pi1_bdiv_q_1 (rp, rp, rn, __gmp_oddfac_table[k], facinv[k - 2], i2cnt);
+  /* A two-fold, branch-free normalisation is possible :*/
+  /* rn -= rp[rn - 1] == 0; */
+  /* rn -= rp[rn - 1] == 0; */
+  MPN_NORMALIZE_NOT_ZERO (rp, rn);
+
+  SIZ(r) = rn;
+}
+
+/* Algorithm:
+
+   Plain and simply multiply things together.
+
+   We tabulate factorials (k!/2^t)^(-1) mod B (where t is chosen such
+   that k!/2^t is odd).
+
+*/
+
+static mp_limb_t
+bc_bin_uiui (unsigned int n, unsigned int k)
+{
+  return ((__gmp_oddfac_table[n] * facinv[k - 2] * facinv[n - k - 2])
+    << (__gmp_fac2cnt_table[n / 2 - 1] - __gmp_fac2cnt_table[k / 2 - 1] - __gmp_fac2cnt_table[(n-k) / 2 - 1]))
+    & GMP_NUMB_MASK;
+}
+
+/* Algorithm:
+
+   Recursively exploit the relation
+   bin(n,k) = bin(n,k>>1)*bin(n-k>>1,k-k>>1)/bin(k,k>>1) .
+
+   Values for binomial(k,k>>1) that fit in a limb are precomputed
+   (with inverses).
+*/
+
+/* bin2kk[i - ODD_CENTRAL_BINOMIAL_OFFSET] =
+   binomial(i*2,i)/2^t (where t is chosen so that it is odd). */
+static const mp_limb_t bin2kk[] = { ONE_LIMB_ODD_CENTRAL_BINOMIAL_TABLE };
+
+/* bin2kkinv[i] = bin2kk[i]^-1 mod B */
+static const mp_limb_t bin2kkinv[] = { ONE_LIMB_ODD_CENTRAL_BINOMIAL_INVERSE_TABLE };
+
+/* bin2kk[i] = binomial((i+MIN_S)*2,i+MIN_S)/2^t. This table contains the t values. */
+static const unsigned char fac2bin[] = { CENTRAL_BINOMIAL_2FAC_TABLE };
+
+static void
+mpz_smallkdc_bin_uiui (mpz_ptr r, unsigned long int n, unsigned long int k)
+{
+  mp_ptr rp;
+  mp_size_t rn;
+  unsigned long int hk;
+
+  hk = k >> 1;
+
+  if ((! BIN_UIUI_RECURSIVE_SMALLDC) || hk <= ODD_FACTORIAL_TABLE_LIMIT)
+    mpz_smallk_bin_uiui (r, n, hk);
+  else
+    mpz_smallkdc_bin_uiui (r, n, hk);
+  k -= hk;
+  n -= hk;
+  if (n <= ODD_FACTORIAL_EXTTABLE_LIMIT) {
+    mp_limb_t cy;
+    rn = SIZ (r);
+    rp = MPZ_REALLOC (r, rn + 1);
+    cy = mpn_mul_1 (rp, rp, rn, bc_bin_uiui (n, k));
+    rp [rn] = cy;
+    rn += cy != 0;
+  } else {
+    mp_limb_t buffer[ODD_CENTRAL_BINOMIAL_TABLE_LIMIT + 3];
+    mpz_t t;
+
+    ALLOC (t) = ODD_CENTRAL_BINOMIAL_TABLE_LIMIT + 3;
+    PTR (t) = buffer;
+    if ((! BIN_UIUI_RECURSIVE_SMALLDC) || k <= ODD_FACTORIAL_TABLE_LIMIT)
+      mpz_smallk_bin_uiui (t, n, k);
+    else
+      mpz_smallkdc_bin_uiui (t, n, k);
+    mpz_mul (r, r, t);
+    rp = PTR (r);
+    rn = SIZ (r);
+  }
+
+  mpn_pi1_bdiv_q_1 (rp, rp, rn, bin2kk[k - ODD_CENTRAL_BINOMIAL_OFFSET],
+		    bin2kkinv[k - ODD_CENTRAL_BINOMIAL_OFFSET],
+		    fac2bin[k - ODD_CENTRAL_BINOMIAL_OFFSET] - (k != hk));
+  /* A two-fold, branch-free normalisation is possible :*/
+  /* rn -= rp[rn - 1] == 0; */
+  /* rn -= rp[rn - 1] == 0; */
+  MPN_NORMALIZE_NOT_ZERO (rp, rn);
+
+  SIZ(r) = rn;
+}
+
+/* mpz_goetgheluck_bin_uiui(RESULT, N, K) -- Set RESULT to binomial(N,K).
+ *
+ * Contributed to the GNU project by Marco Bodrato.
+ *
+ * Implementation of the algorithm by P. Goetgheluck, "Computing
+ * Binomial Coefficients", The American Mathematical Monthly, Vol. 94,
+ * No. 4 (April 1987), pp. 360-365.
+ *
+ * Acknowledgment: Peter Luschny did spot the slowness of the previous
+ * code and suggested the reference.
+ */
+
+/* TODO: Remove duplicated constants / macros / static functions...
+ */
+
+/*************************************************************/
+/* Section macros: common macros, for swing/fac/bin (&sieve) */
+/*************************************************************/
+
+#define FACTOR_LIST_APPEND(PR, MAX_PR, VEC, I)			\
+  if ((PR) > (MAX_PR)) {					\
+    (VEC)[(I)++] = (PR);					\
+    (PR) = 1;							\
+  }
+
+#define FACTOR_LIST_STORE(P, PR, MAX_PR, VEC, I)		\
+  do {								\
+    if ((PR) > (MAX_PR)) {					\
+      (VEC)[(I)++] = (PR);					\
+      (PR) = (P);						\
+    } else							\
+      (PR) *= (P);						\
+  } while (0)
+
+#define LOOP_ON_SIEVE_CONTINUE(prime,end,sieve)			\
+    __max_i = (end);						\
+								\
+    do {							\
+      ++__i;							\
+      if (((sieve)[__index] & __mask) == 0)			\
+	{							\
+	  mp_limb_t prime;					\
+	  prime = id_to_n(__i)
+
+#define LOOP_ON_SIEVE_BEGIN(prime,start,end,off,sieve)		\
+  do {								\
+    mp_limb_t __mask, __index, __max_i, __i;			\
+								\
+    __i = (start)-(off);					\
+    __index = __i / GMP_LIMB_BITS;				\
+    __mask = CNST_LIMB(1) << (__i % GMP_LIMB_BITS);		\
+    __i += (off);						\
+								\
+    LOOP_ON_SIEVE_CONTINUE(prime,end,sieve)
+
+#define LOOP_ON_SIEVE_STOP					\
+	}							\
+      __mask = __mask << 1 | __mask >> (GMP_LIMB_BITS-1);	\
+      __index += __mask & 1;					\
+    }  while (__i <= __max_i)
+
+#define LOOP_ON_SIEVE_END					\
+    LOOP_ON_SIEVE_STOP;						\
+  } while (0)
+
+/*********************************************************/
+/* Section sieve: sieving functions and tools for primes */
+/*********************************************************/
+
+#if WANT_ASSERT
+static mp_limb_t
+bit_to_n (mp_limb_t bit) { return (bit*3+4)|1; }
+#endif
+
+/* id_to_n (x) = bit_to_n (x-1) = (id*3+1)|1*/
+static mp_limb_t
+id_to_n  (mp_limb_t id)  { return id*3+1+(id&1); }
+
+/* n_to_bit (n) = ((n-1)&(-CNST_LIMB(2)))/3U-1 */
+static mp_limb_t
+n_to_bit (mp_limb_t n) { return ((n-5)|1)/3U; }
+
+static mp_size_t
+primesieve_size (mp_limb_t n) { return n_to_bit(n) / GMP_LIMB_BITS + 1; }
+
+/*********************************************************/
+/* Section binomial: fast binomial implementation        */
+/*********************************************************/
+
+#define COUNT_A_PRIME(P, N, K, PR, MAX_PR, VEC, I)	\
+  do {							\
+    mp_limb_t __a, __b, __prime, __ma,__mb;		\
+    __prime = (P);					\
+    __a = (N); __b = (K); __mb = 0;			\
+    FACTOR_LIST_APPEND(PR, MAX_PR, VEC, I);		\
+    do {						\
+      __mb += __b % __prime; __b /= __prime;		\
+      __ma = __a % __prime; __a /= __prime;		\
+      if (__ma < __mb) {				\
+        __mb = 1; (PR) *= __prime;			\
+      } else  __mb = 0;					\
+    } while (__a >= __prime);				\
+  } while (0)
+
+#define SH_COUNT_A_PRIME(P, N, K, PR, MAX_PR, VEC, I)	\
+  do {							\
+    mp_limb_t __prime;					\
+    __prime = (P);					\
+    if (((N) % __prime) < ((K) % __prime)) {		\
+      FACTOR_LIST_STORE (__prime, PR, MAX_PR, VEC, I);	\
+    }							\
+  } while (0)
+
+/* Returns an approximation of the sqare root of x.
+ * It gives:
+ *   limb_apprsqrt (x) ^ 2 <= x < (limb_apprsqrt (x)+1) ^ 2
+ * or
+ *   x <= limb_apprsqrt (x) ^ 2 <= x * 9/8
+ */
+static mp_limb_t
+limb_apprsqrt (mp_limb_t x)
+{
+  int s;
+
+  ASSERT (x > 2);
+  count_leading_zeros (s, x);
+  s = (GMP_LIMB_BITS - s) >> 1;
+  return ((CNST_LIMB(1) << s) + (x >> s)) >> 1;
+}
+
+static void
+mpz_goetgheluck_bin_uiui (mpz_ptr r, unsigned long int n, unsigned long int k)
+{
+  mp_limb_t *sieve, *factors, count;
+  mp_limb_t prod, max_prod;
+  mp_size_t j;
+  TMP_DECL;
+
+  ASSERT (BIN_GOETGHELUCK_THRESHOLD >= 13);
+  ASSERT (n >= 25);
+
+  TMP_MARK;
+  sieve = TMP_ALLOC_LIMBS (primesieve_size (n));
+
+  count = gmp_primesieve (sieve, n) + 1;
+  factors = TMP_ALLOC_LIMBS (count / log_n_max (n) + 1);
+
+  max_prod = GMP_NUMB_MAX / n;
+
+  /* Handle primes = 2, 3 separately. */
+  popc_limb (count, n - k);
+  popc_limb (j, k);
+  count += j;
+  popc_limb (j, n);
+  count -= j;
+  prod = CNST_LIMB(1) << count;
+
+  j = 0;
+  COUNT_A_PRIME (3, n, k, prod, max_prod, factors, j);
+
+  /* Accumulate prime factors from 5 to n/2 */
+    {
+      mp_limb_t s;
+
+      s = limb_apprsqrt(n);
+      s = n_to_bit (s);
+      ASSERT (bit_to_n (s+1) * bit_to_n (s+1) > n);
+      ASSERT (s <= n_to_bit (n >> 1));
+      LOOP_ON_SIEVE_BEGIN (prime, n_to_bit (5), s, 0,sieve);
+      COUNT_A_PRIME (prime, n, k, prod, max_prod, factors, j);
+      LOOP_ON_SIEVE_STOP;
+
+      ASSERT (max_prod <= GMP_NUMB_MAX / 2);
+      max_prod <<= 1;
+
+      LOOP_ON_SIEVE_CONTINUE (prime, n_to_bit (n >> 1),sieve);
+      SH_COUNT_A_PRIME (prime, n, k, prod, max_prod, factors, j);
+      LOOP_ON_SIEVE_END;
+
+      max_prod >>= 1;
+    }
+
+  /* Store primes from (n-k)+1 to n */
+  ASSERT (n_to_bit (n - k) < n_to_bit (n));
+
+  LOOP_ON_SIEVE_BEGIN (prime, n_to_bit (n - k) + 1, n_to_bit (n), 0,sieve);
+  FACTOR_LIST_STORE (prime, prod, max_prod, factors, j);
+  LOOP_ON_SIEVE_END;
+
+  if (LIKELY (j != 0))
+    {
+      factors[j++] = prod;
+      mpz_prodlimbs (r, factors, j);
+    }
+  else
+    {
+      MPZ_NEWALLOC (r, 1)[0] = prod;
+      SIZ (r) = 1;
+    }
+  TMP_FREE;
+}
+
+#undef COUNT_A_PRIME
+#undef SH_COUNT_A_PRIME
+#undef LOOP_ON_SIEVE_END
+#undef LOOP_ON_SIEVE_STOP
+#undef LOOP_ON_SIEVE_BEGIN
+#undef LOOP_ON_SIEVE_CONTINUE
+
+/*********************************************************/
+/* End of implementation of Goetgheluck's algorithm      */
+/*********************************************************/
+
+void
+mpz_bin_uiui (mpz_ptr r, unsigned long int n, unsigned long int k)
+{
+  if (UNLIKELY (n < k)) {
+    SIZ (r) = 0;
+#if BITS_PER_ULONG > GMP_NUMB_BITS
+  } else if (UNLIKELY (n > GMP_NUMB_MAX)) {
+    mpz_t tmp;
+
+    mpz_init_set_ui (tmp, n);
+    mpz_bin_ui (r, tmp, k);
+    mpz_clear (tmp);
+#endif
+  } else {
+    ASSERT (n <= GMP_NUMB_MAX);
+    /* Rewrite bin(n,k) as bin(n,n-k) if that is smaller. */
+    k = MIN (k, n - k);
+    if (k < 2) {
+      MPZ_NEWALLOC (r, 1)[0] = k ? n : 1; /* 1 + ((-k) & (n-1)); */
+      SIZ(r) = 1;
+    } else if (n <= ODD_FACTORIAL_EXTTABLE_LIMIT) { /* k >= 2, n >= 4 */
+      MPZ_NEWALLOC (r, 1)[0] = bc_bin_uiui (n, k);
+      SIZ(r) = 1;
+    } else if (k <= ODD_FACTORIAL_TABLE_LIMIT)
+      mpz_smallk_bin_uiui (r, n, k);
+    else if (BIN_UIUI_ENABLE_SMALLDC &&
+	     k <= (BIN_UIUI_RECURSIVE_SMALLDC ? ODD_CENTRAL_BINOMIAL_TABLE_LIMIT : ODD_FACTORIAL_TABLE_LIMIT)* 2)
+      mpz_smallkdc_bin_uiui (r, n, k);
+    else if (ABOVE_THRESHOLD (k, BIN_GOETGHELUCK_THRESHOLD) &&
+	     k > (n >> 4)) /* k > ODD_FACTORIAL_TABLE_LIMIT */
+      mpz_goetgheluck_bin_uiui (r, n, k);
+    else
+      mpz_bdiv_bin_uiui (r, n, k);
+  }
+}
diff --git a/third_party/gmp/mpz/cdiv_q.c b/third_party/gmp/mpz/cdiv_q.c
new file mode 100644
index 0000000..f19eb74
--- /dev/null
+++ b/third_party/gmp/mpz/cdiv_q.c
@@ -0,0 +1,52 @@
+/* mpz_cdiv_q -- Division rounding the quotient towards +infinity.  The
+   remainder gets the opposite sign as the denominator.
+
+Copyright 1994-1996, 2000, 2001, 2005, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_cdiv_q (mpz_ptr quot, mpz_srcptr dividend, mpz_srcptr divisor)
+{
+  mp_size_t dividend_size = SIZ (dividend);
+  mp_size_t divisor_size = SIZ (divisor);
+  mpz_t rem;
+  TMP_DECL;
+
+  TMP_MARK;
+
+  MPZ_TMP_INIT (rem, ABS (divisor_size));
+
+  mpz_tdiv_qr (quot, rem, dividend, divisor);
+
+  if ((divisor_size ^ dividend_size) >= 0 && SIZ (rem) != 0)
+    mpz_add_ui (quot, quot, 1L);
+
+  TMP_FREE;
+}
diff --git a/third_party/gmp/mpz/cdiv_q_ui.c b/third_party/gmp/mpz/cdiv_q_ui.c
new file mode 100644
index 0000000..269d9a3
--- /dev/null
+++ b/third_party/gmp/mpz/cdiv_q_ui.c
@@ -0,0 +1,102 @@
+/* mpz_cdiv_q_ui -- Division rounding the quotient towards +infinity.  The
+   remainder gets the opposite sign as the denominator.  In order to make it
+   always fit into the return type, the negative of the true remainder is
+   returned.
+
+Copyright 1994, 1996, 1999, 2001, 2002, 2004, 2012 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+unsigned long int
+mpz_cdiv_q_ui (mpz_ptr quot, mpz_srcptr dividend, unsigned long int divisor)
+{
+  mp_size_t ns, nn, qn;
+  mp_ptr np, qp;
+  mp_limb_t rl;
+
+  if (UNLIKELY (divisor == 0))
+    DIVIDE_BY_ZERO;
+
+  ns = SIZ(dividend);
+  if (ns == 0)
+    {
+      SIZ(quot) = 0;
+      return 0;
+    }
+
+  nn = ABS(ns);
+  qp = MPZ_REALLOC (quot, nn);
+  np = PTR(dividend);
+
+#if BITS_PER_ULONG > GMP_NUMB_BITS  /* avoid warnings about shift amount */
+  if (divisor > GMP_NUMB_MAX)
+    {
+      mp_limb_t dp[2], rp[2];
+
+      if (nn == 1)		/* tdiv_qr requirements; tested above for 0 */
+	{
+	  qp[0] = 0;
+	  rl = np[0];
+	  qn = 1;		/* a white lie, fixed below */
+	}
+      else
+	{
+	  dp[0] = divisor & GMP_NUMB_MASK;
+	  dp[1] = divisor >> GMP_NUMB_BITS;
+	  mpn_tdiv_qr (qp, rp, (mp_size_t) 0, np, nn, dp, (mp_size_t) 2);
+	  rl = rp[0] + (rp[1] << GMP_NUMB_BITS);
+	  qn = nn - 2 + 1;
+	}
+
+      if (rl != 0 && ns >= 0)
+	{
+	  mpn_incr_u (qp, (mp_limb_t) 1);
+	  rl = divisor - rl;
+	}
+
+      qn -= qp[qn - 1] == 0; qn -= qn != 0 && qp[qn - 1] == 0;
+    }
+  else
+#endif
+    {
+      rl = mpn_divrem_1 (qp, (mp_size_t) 0, np, nn, (mp_limb_t) divisor);
+
+      if (rl != 0 && ns >= 0)
+	{
+	  mpn_incr_u (qp, (mp_limb_t) 1);
+	  rl = divisor - rl;
+	}
+
+      qn = nn - (qp[nn - 1] == 0);
+    }
+
+  SIZ(quot) = ns >= 0 ? qn : -qn;
+  return rl;
+}
diff --git a/third_party/gmp/mpz/cdiv_qr.c b/third_party/gmp/mpz/cdiv_qr.c
new file mode 100644
index 0000000..bc9b892
--- /dev/null
+++ b/third_party/gmp/mpz/cdiv_qr.c
@@ -0,0 +1,64 @@
+/* mpz_cdiv_qr -- Division rounding the quotient towards +infinity.  The
+   remainder gets the opposite sign as the denominator.
+
+Copyright 1994-1996, 2000, 2001, 2005, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_cdiv_qr (mpz_ptr quot, mpz_ptr rem, mpz_srcptr dividend, mpz_srcptr divisor)
+{
+  mp_size_t divisor_size = SIZ (divisor);
+  mp_size_t xsize;
+  mpz_t temp_divisor;		/* N.B.: lives until function returns! */
+  TMP_DECL;
+
+  TMP_MARK;
+
+  /* We need the original value of the divisor after the quotient and
+     remainder have been preliminary calculated.  We have to copy it to
+     temporary space if it's the same variable as either QUOT or REM.  */
+  if (quot == divisor || rem == divisor)
+    {
+      MPZ_TMP_INIT (temp_divisor, ABS (divisor_size));
+      mpz_set (temp_divisor, divisor);
+      divisor = temp_divisor;
+    }
+
+  xsize = SIZ (dividend) ^ divisor_size;;
+  mpz_tdiv_qr (quot, rem, dividend, divisor);
+
+  if (xsize >= 0 && SIZ (rem) != 0)
+    {
+      mpz_add_ui (quot, quot, 1L);
+      mpz_sub (rem, rem, divisor);
+    }
+
+  TMP_FREE;
+}
diff --git a/third_party/gmp/mpz/cdiv_qr_ui.c b/third_party/gmp/mpz/cdiv_qr_ui.c
new file mode 100644
index 0000000..0c11fb6
--- /dev/null
+++ b/third_party/gmp/mpz/cdiv_qr_ui.c
@@ -0,0 +1,118 @@
+/* mpz_cdiv_qr_ui -- Division rounding the quotient towards +infinity.  The
+   remainder gets the opposite sign as the denominator.  In order to make it
+   always fit into the return type, the negative of the true remainder is
+   returned.
+
+Copyright 1994-1996, 1999, 2001, 2002, 2004, 2012, 2015 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+unsigned long int
+mpz_cdiv_qr_ui (mpz_ptr quot, mpz_ptr rem, mpz_srcptr dividend, unsigned long int divisor)
+{
+  mp_size_t ns, nn, qn;
+  mp_ptr np, qp;
+  mp_limb_t rl;
+
+  if (UNLIKELY (divisor == 0))
+    DIVIDE_BY_ZERO;
+
+  ns = SIZ(dividend);
+  if (ns == 0)
+    {
+      SIZ(quot) = 0;
+      SIZ(rem) = 0;
+      return 0;
+    }
+
+  nn = ABS(ns);
+  qp = MPZ_REALLOC (quot, nn);
+  np = PTR(dividend);
+
+#if BITS_PER_ULONG > GMP_NUMB_BITS  /* avoid warnings about shift amount */
+  if (divisor > GMP_NUMB_MAX)
+    {
+      mp_limb_t dp[2];
+      mp_ptr rp;
+      mp_size_t rn;
+
+      rp = MPZ_REALLOC (rem, 2);
+
+      if (nn == 1)		/* tdiv_qr requirements; tested above for 0 */
+	{
+	  qp[0] = 0;
+	  qn = 1;		/* a white lie, fixed below */
+	  rl = np[0];
+	  rp[0] = rl;
+	}
+      else
+	{
+	  dp[0] = divisor & GMP_NUMB_MASK;
+	  dp[1] = divisor >> GMP_NUMB_BITS;
+	  mpn_tdiv_qr (qp, rp, (mp_size_t) 0, np, nn, dp, (mp_size_t) 2);
+	  rl = rp[0] + (rp[1] << GMP_NUMB_BITS);
+	  qn = nn - 2 + 1;
+	}
+
+      if (rl != 0 && ns >= 0)
+	{
+	  mpn_incr_u (qp, (mp_limb_t) 1);
+	  rl = divisor - rl;
+	  rp[0] = rl & GMP_NUMB_MASK;
+	  rp[1] = rl >> GMP_NUMB_BITS;
+	}
+
+      qn -= qp[qn - 1] == 0; qn -= qn != 0 && qp[qn - 1] == 0;
+      rn = 1 + (rl > GMP_NUMB_MAX);  rn -= (rp[rn - 1] == 0);
+      SIZ(rem) = -rn;
+    }
+  else
+#endif
+    {
+      rl = mpn_divrem_1 (qp, (mp_size_t) 0, np, nn, (mp_limb_t) divisor);
+      if (rl == 0)
+	SIZ(rem) = 0;
+      else
+	{
+	  if (ns >= 0)
+	    {
+	      mpn_incr_u (qp, (mp_limb_t) 1);
+	      rl = divisor - rl;
+	    }
+
+	  MPZ_NEWALLOC (rem, 1)[0] = rl;
+	  SIZ(rem) = -(rl != 0);
+	}
+      qn = nn - (qp[nn - 1] == 0);
+    }
+
+  SIZ(quot) = ns >= 0 ? qn : -qn;
+  return rl;
+}
diff --git a/third_party/gmp/mpz/cdiv_r.c b/third_party/gmp/mpz/cdiv_r.c
new file mode 100644
index 0000000..83c624a
--- /dev/null
+++ b/third_party/gmp/mpz/cdiv_r.c
@@ -0,0 +1,60 @@
+/* mpz_cdiv_r -- Division rounding the quotient towards +infinity.  The
+   remainder gets the opposite sign as the denominator.
+
+Copyright 1994-1996, 2001, 2005, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_cdiv_r (mpz_ptr rem, mpz_srcptr dividend, mpz_srcptr divisor)
+{
+  mp_size_t divisor_size = SIZ (divisor);
+  mpz_t temp_divisor;		/* N.B.: lives until function returns! */
+  TMP_DECL;
+
+  TMP_MARK;
+
+  /* We need the original value of the divisor after the remainder has been
+     preliminary calculated.  We have to copy it to temporary space if it's
+     the same variable as REM.  */
+  if (rem == divisor)
+    {
+
+      MPZ_TMP_INIT (temp_divisor, ABS (divisor_size));
+      mpz_set (temp_divisor, divisor);
+      divisor = temp_divisor;
+    }
+
+  mpz_tdiv_r (rem, dividend, divisor);
+
+  if ((divisor_size ^ SIZ (dividend)) >= 0 && SIZ (rem) != 0)
+    mpz_sub (rem, rem, divisor);
+
+  TMP_FREE;
+}
diff --git a/third_party/gmp/mpz/cdiv_r_ui.c b/third_party/gmp/mpz/cdiv_r_ui.c
new file mode 100644
index 0000000..84d51db
--- /dev/null
+++ b/third_party/gmp/mpz/cdiv_r_ui.c
@@ -0,0 +1,109 @@
+/* mpz_cdiv_r_ui -- Division rounding the quotient towards +infinity.  The
+   remainder gets the opposite sign as the denominator.  In order to make it
+   always fit into the return type, the negative of the true remainder is
+   returned.
+
+Copyright 1994-1996, 2001, 2002, 2004, 2005, 2012, 2015 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+unsigned long int
+mpz_cdiv_r_ui (mpz_ptr rem, mpz_srcptr dividend, unsigned long int divisor)
+{
+  mp_size_t ns, nn;
+  mp_ptr np;
+  mp_limb_t rl;
+
+  if (UNLIKELY (divisor == 0))
+    DIVIDE_BY_ZERO;
+
+  ns = SIZ(dividend);
+  if (ns == 0)
+    {
+      SIZ(rem) = 0;
+      return 0;
+    }
+
+  nn = ABS(ns);
+  np = PTR(dividend);
+#if BITS_PER_ULONG > GMP_NUMB_BITS  /* avoid warnings about shift amount */
+  if (divisor > GMP_NUMB_MAX)
+    {
+      mp_limb_t dp[2];
+      mp_ptr rp, qp;
+      mp_size_t rn;
+      TMP_DECL;
+
+      rp = MPZ_REALLOC (rem, 2);
+
+      if (nn == 1)		/* tdiv_qr requirements; tested above for 0 */
+	{
+	  rl = np[0];
+	  rp[0] = rl;
+	}
+      else
+	{
+	  TMP_MARK;
+	  dp[0] = divisor & GMP_NUMB_MASK;
+	  dp[1] = divisor >> GMP_NUMB_BITS;
+	  qp = TMP_ALLOC_LIMBS (nn - 2 + 1);
+	  mpn_tdiv_qr (qp, rp, (mp_size_t) 0, np, nn, dp, (mp_size_t) 2);
+	  TMP_FREE;
+	  rl = rp[0] + (rp[1] << GMP_NUMB_BITS);
+	}
+
+      if (rl != 0 && ns >= 0)
+	{
+	  rl = divisor - rl;
+	  rp[0] = rl & GMP_NUMB_MASK;
+	  rp[1] = rl >> GMP_NUMB_BITS;
+	}
+
+      rn = 1 + (rl > GMP_NUMB_MAX);  rn -= (rp[rn - 1] == 0);
+      SIZ(rem) = -rn;
+    }
+  else
+#endif
+    {
+      rl = mpn_mod_1 (np, nn, (mp_limb_t) divisor);
+      if (rl == 0)
+	SIZ(rem) = 0;
+      else
+	{
+	  if (ns >= 0)
+	    rl = divisor - rl;
+
+	  MPZ_NEWALLOC (rem, 1)[0] = rl;
+	  SIZ(rem) = -1;
+	}
+    }
+
+  return rl;
+}
diff --git a/third_party/gmp/mpz/cdiv_ui.c b/third_party/gmp/mpz/cdiv_ui.c
new file mode 100644
index 0000000..e1a1c49
--- /dev/null
+++ b/third_party/gmp/mpz/cdiv_ui.c
@@ -0,0 +1,102 @@
+/* mpz_cdiv_ui -- Division rounding the quotient towards +infinity.  The
+   remainder gets the opposite sign as the denominator.  In order to make it
+   always fit into the return type, the negative of the true remainder is
+   returned.
+
+Copyright 1994-1996, 2001, 2002, 2004, 2005, 2012 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+unsigned long int
+mpz_cdiv_ui (mpz_srcptr dividend, unsigned long int divisor)
+{
+  mp_size_t ns, nn;
+  mp_ptr np;
+  mp_limb_t rl;
+
+  if (UNLIKELY (divisor == 0))
+    DIVIDE_BY_ZERO;
+
+  ns = SIZ(dividend);
+  if (ns == 0)
+    {
+      return 0;
+    }
+
+  nn = ABS(ns);
+  np = PTR(dividend);
+#if BITS_PER_ULONG > GMP_NUMB_BITS  /* avoid warnings about shift amount */
+  if (divisor > GMP_NUMB_MAX)
+    {
+      mp_limb_t dp[2], rp[2];
+      mp_ptr qp;
+      mp_size_t rn;
+      TMP_DECL;
+
+      if (nn == 1)		/* tdiv_qr requirements; tested above for 0 */
+	{
+	  rl = np[0];
+	  rp[0] = rl;
+	}
+      else
+	{
+	  TMP_MARK;
+	  dp[0] = divisor & GMP_NUMB_MASK;
+	  dp[1] = divisor >> GMP_NUMB_BITS;
+	  qp = TMP_ALLOC_LIMBS (nn - 2 + 1);
+	  mpn_tdiv_qr (qp, rp, (mp_size_t) 0, np, nn, dp, (mp_size_t) 2);
+	  TMP_FREE;
+	  rl = rp[0] + (rp[1] << GMP_NUMB_BITS);
+	}
+
+      if (rl != 0 && ns >= 0)
+	{
+	  rl = divisor - rl;
+	  rp[0] = rl & GMP_NUMB_MASK;
+	  rp[1] = rl >> GMP_NUMB_BITS;
+	}
+
+      rn = 1 + (rl > GMP_NUMB_MAX);  rn -= (rp[rn - 1] == 0);
+    }
+  else
+#endif
+    {
+      rl = mpn_mod_1 (np, nn, (mp_limb_t) divisor);
+      if (rl == 0)
+	;
+      else
+	{
+	  if (ns >= 0)
+	    rl = divisor - rl;
+	}
+    }
+
+  return rl;
+}
diff --git a/third_party/gmp/mpz/cfdiv_q_2exp.c b/third_party/gmp/mpz/cfdiv_q_2exp.c
new file mode 100644
index 0000000..413ea36
--- /dev/null
+++ b/third_party/gmp/mpz/cfdiv_q_2exp.c
@@ -0,0 +1,111 @@
+/* mpz_cdiv_q_2exp, mpz_fdiv_q_2exp -- quotient from mpz divided by 2^n.
+
+Copyright 1991, 1993, 1994, 1996, 1998, 1999, 2001, 2002, 2004, 2012,
+2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* dir==1 for ceil, dir==-1 for floor */
+
+static void __gmpz_cfdiv_q_2exp (REGPARM_3_1 (mpz_ptr, mpz_srcptr, mp_bitcnt_t, int)) REGPARM_ATTR (1);
+#define cfdiv_q_2exp(w,u,cnt,dir)  __gmpz_cfdiv_q_2exp (REGPARM_3_1 (w,u,cnt,dir))
+
+REGPARM_ATTR (1) static void
+cfdiv_q_2exp (mpz_ptr w, mpz_srcptr u, mp_bitcnt_t cnt, int dir)
+{
+  mp_size_t  wsize, usize, abs_usize, limb_cnt, i;
+  mp_srcptr  up;
+  mp_ptr     wp;
+  mp_limb_t  round, rmask;
+
+  usize = SIZ (u);
+  abs_usize = ABS (usize);
+  limb_cnt = cnt / GMP_NUMB_BITS;
+  wsize = abs_usize - limb_cnt;
+  if (wsize <= 0)
+    {
+      /* u < 2**cnt, so result 1, 0 or -1 according to rounding */
+      MPZ_NEWALLOC (w, 1)[0] = 1;
+      SIZ(w) = (usize == 0 || (usize ^ dir) < 0 ? 0 : dir);
+      return;
+    }
+
+  /* +1 limb to allow for mpn_add_1 below */
+  wp = MPZ_REALLOC (w, wsize+1);
+
+  /* Check for rounding if direction matches u sign.
+     Set round if we're skipping non-zero limbs.  */
+  up = PTR(u);
+  round = 0;
+  rmask = ((usize ^ dir) >= 0 ? MP_LIMB_T_MAX : 0);
+  if (rmask != 0)
+    for (i = 0; i < limb_cnt && round == 0; i++)
+      round = up[i];
+
+  cnt %= GMP_NUMB_BITS;
+  if (cnt != 0)
+    {
+      round |= rmask & mpn_rshift (wp, up + limb_cnt, wsize, cnt);
+      wsize -= (wp[wsize - 1] == 0);
+    }
+  else
+    MPN_COPY_INCR (wp, up + limb_cnt, wsize);
+
+  if (round != 0)
+    {
+      if (wsize != 0)
+	{
+	  mp_limb_t cy;
+	  cy = mpn_add_1 (wp, wp, wsize, CNST_LIMB(1));
+	  wp[wsize] = cy;
+	  wsize += cy;
+	}
+      else
+	{
+	  /* We shifted something to zero.  */
+	  wp[0] = 1;
+	  wsize = 1;
+	}
+    }
+  SIZ(w) = (usize >= 0 ? wsize : -wsize);
+}
+
+
+void
+mpz_cdiv_q_2exp (mpz_ptr w, mpz_srcptr u, mp_bitcnt_t cnt)
+{
+  cfdiv_q_2exp (w, u, cnt, 1);
+}
+
+void
+mpz_fdiv_q_2exp (mpz_ptr w, mpz_srcptr u, mp_bitcnt_t cnt)
+{
+  cfdiv_q_2exp (w, u, cnt, -1);
+}
diff --git a/third_party/gmp/mpz/cfdiv_r_2exp.c b/third_party/gmp/mpz/cfdiv_r_2exp.c
new file mode 100644
index 0000000..fedb97d
--- /dev/null
+++ b/third_party/gmp/mpz/cfdiv_r_2exp.c
@@ -0,0 +1,159 @@
+/* mpz_cdiv_r_2exp, mpz_fdiv_r_2exp -- remainder from mpz divided by 2^n.
+
+Copyright 2001, 2002, 2004, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* Bit mask of "n" least significant bits of a limb. */
+#define LOW_MASK(n)   ((CNST_LIMB(1) << (n)) - 1)
+
+
+/* dir==1 for ceil, dir==-1 for floor */
+
+static void __gmpz_cfdiv_r_2exp (REGPARM_3_1 (mpz_ptr, mpz_srcptr, mp_bitcnt_t, int)) REGPARM_ATTR (1);
+#define cfdiv_r_2exp(w,u,cnt,dir)  __gmpz_cfdiv_r_2exp (REGPARM_3_1 (w, u, cnt, dir))
+
+REGPARM_ATTR (1) static void
+cfdiv_r_2exp (mpz_ptr w, mpz_srcptr u, mp_bitcnt_t cnt, int dir)
+{
+  mp_size_t  usize, abs_usize, limb_cnt, i;
+  mp_srcptr  up;
+  mp_ptr     wp;
+  mp_limb_t  high;
+
+  usize = SIZ(u);
+  if (usize == 0)
+    {
+      SIZ(w) = 0;
+      return;
+    }
+
+  limb_cnt = cnt / GMP_NUMB_BITS;
+  cnt %= GMP_NUMB_BITS;
+  abs_usize = ABS (usize);
+
+  /* MPZ_REALLOC(w) below is only when w!=u, so we can fetch PTR(u) here
+     nice and early */
+  up = PTR(u);
+
+  if ((usize ^ dir) < 0)
+    {
+      /* Round towards zero, means just truncate */
+
+      if (w == u)
+	{
+	  /* if already smaller than limb_cnt then do nothing */
+	  if (abs_usize <= limb_cnt)
+	    return;
+	  wp = (mp_ptr) up;
+	}
+      else
+	{
+	  i = MIN (abs_usize, limb_cnt+1);
+	  wp = MPZ_NEWALLOC (w, i);
+	  MPN_COPY (wp, up, i);
+
+	  /* if smaller than limb_cnt then only the copy is needed */
+	  if (abs_usize <= limb_cnt)
+	    {
+	      SIZ(w) = usize;
+	      return;
+	    }
+	}
+    }
+  else
+    {
+      /* Round away from zero, means twos complement if non-zero */
+
+      /* if u!=0 and smaller than divisor, then must negate */
+      if (abs_usize <= limb_cnt)
+	goto negate;
+
+      /* if non-zero low limb, then must negate */
+      for (i = 0; i < limb_cnt; i++)
+	if (up[i] != 0)
+	  goto negate;
+
+      /* if non-zero partial limb, then must negate */
+      if ((up[limb_cnt] & LOW_MASK (cnt)) != 0)
+	goto negate;
+
+      /* otherwise low bits of u are zero, so that's the result */
+      SIZ(w) = 0;
+      return;
+
+    negate:
+      /* twos complement negation to get 2**cnt-u */
+
+      wp = MPZ_REALLOC (w, limb_cnt+1);
+      up = PTR(u);
+
+      /* Ones complement */
+      i = MIN (abs_usize, limb_cnt+1);
+      ASSERT_CARRY (mpn_neg (wp, up, i));
+      for ( ; i <= limb_cnt; i++)
+	wp[i] = GMP_NUMB_MAX;
+
+      usize = -usize;
+    }
+
+  /* Mask the high limb */
+  high = wp[limb_cnt];
+  high &= LOW_MASK (cnt);
+  wp[limb_cnt] = high;
+
+  /* Strip any consequent high zeros */
+  while (high == 0)
+    {
+      limb_cnt--;
+      if (limb_cnt < 0)
+	{
+	  SIZ(w) = 0;
+	  return;
+	}
+      high = wp[limb_cnt];
+    }
+
+  limb_cnt++;
+  SIZ(w) = (usize >= 0 ? limb_cnt : -limb_cnt);
+}
+
+
+void
+mpz_cdiv_r_2exp (mpz_ptr w, mpz_srcptr u, mp_bitcnt_t cnt)
+{
+  cfdiv_r_2exp (w, u, cnt, 1);
+}
+
+void
+mpz_fdiv_r_2exp (mpz_ptr w, mpz_srcptr u, mp_bitcnt_t cnt)
+{
+  cfdiv_r_2exp (w, u, cnt, -1);
+}
diff --git a/third_party/gmp/mpz/clear.c b/third_party/gmp/mpz/clear.c
new file mode 100644
index 0000000..f8c38a2
--- /dev/null
+++ b/third_party/gmp/mpz/clear.c
@@ -0,0 +1,40 @@
+/* mpz_clear -- de-allocate the space occupied by the dynamic digit space of
+   an integer.
+
+Copyright 1991, 1993-1995, 2000, 2001, 2012, 2014, 2015 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_clear (mpz_ptr x)
+{
+  if (ALLOC (x))
+    __GMP_FREE_FUNC_LIMBS (PTR (x), ALLOC(x));
+}
diff --git a/third_party/gmp/mpz/clears.c b/third_party/gmp/mpz/clears.c
new file mode 100644
index 0000000..7ac257a
--- /dev/null
+++ b/third_party/gmp/mpz/clears.c
@@ -0,0 +1,50 @@
+/* mpz_clears() -- Clear multiple mpz_t variables.
+
+Copyright 2009, 2014, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+#include "gmp-impl.h"
+
+void
+mpz_clears (mpz_ptr x, ...)
+{
+  va_list  ap;
+
+  va_start (ap, x);
+
+  do
+    {
+      if (ALLOC (x))
+	__GMP_FREE_FUNC_LIMBS (PTR (x), ALLOC (x));
+      x = va_arg (ap, mpz_ptr);
+    }
+  while (x != NULL);
+
+  va_end (ap);
+}
diff --git a/third_party/gmp/mpz/clrbit.c b/third_party/gmp/mpz/clrbit.c
new file mode 100644
index 0000000..8b3c854
--- /dev/null
+++ b/third_party/gmp/mpz/clrbit.c
@@ -0,0 +1,115 @@
+/* mpz_clrbit -- clear a specified bit.
+
+Copyright 1991, 1993-1995, 2001, 2002, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_clrbit (mpz_ptr d, mp_bitcnt_t bit_idx)
+{
+  mp_size_t dsize = SIZ (d);
+  mp_ptr dp = PTR (d);
+  mp_size_t limb_idx;
+  mp_limb_t mask;
+
+  limb_idx = bit_idx / GMP_NUMB_BITS;
+  mask = CNST_LIMB(1) << (bit_idx % GMP_NUMB_BITS);
+  if (dsize >= 0)
+    {
+      if (limb_idx < dsize)
+	{
+	  mp_limb_t  dlimb;
+	  dlimb = dp[limb_idx] & ~mask;
+	  dp[limb_idx] = dlimb;
+
+	  if (UNLIKELY ((dlimb == 0) + limb_idx == dsize)) /* dsize == limb_idx + 1 */
+	    {
+	      /* high limb became zero, must normalize */
+	      MPN_NORMALIZE (dp, limb_idx);
+	      SIZ (d) = limb_idx;
+	    }
+	}
+      else
+	;
+    }
+  else
+    {
+      /* Simulate two's complement arithmetic, i.e. simulate
+	 1. Set OP = ~(OP - 1) [with infinitely many leading ones].
+	 2. clear the bit.
+	 3. Set OP = ~OP + 1.  */
+
+      dsize = -dsize;
+
+      if (limb_idx < dsize)
+	{
+	  mp_size_t zero_bound;
+
+	  /* No index upper bound on this loop, we're sure there's a non-zero limb
+	     sooner or later.  */
+	  zero_bound = 0;
+	  while (dp[zero_bound] == 0)
+	    zero_bound++;
+
+	  if (limb_idx > zero_bound)
+	    {
+	      dp[limb_idx] |= mask;
+	    }
+	  else if (limb_idx == zero_bound)
+	    {
+	      mp_limb_t  dlimb;
+	      dlimb = (((dp[limb_idx] - 1) | mask) + 1) & GMP_NUMB_MASK;
+	      dp[limb_idx] = dlimb;
+
+	      if (dlimb == 0)
+		{
+		  /* Increment at limb_idx + 1.  Extend the number with a zero limb
+		     for simplicity.  */
+		  dp = MPZ_REALLOC (d, dsize + 1);
+		  dp[dsize] = 0;
+		  MPN_INCR_U (dp + limb_idx + 1, dsize - limb_idx, 1);
+		  dsize += dp[dsize];
+
+		  SIZ (d) = -dsize;
+		}
+	    }
+	  else
+	    ;
+	}
+      else
+	{
+	  /* Ugh.  The bit should be cleared outside of the end of the
+	     number.  We have to increase the size of the number.  */
+	  dp = MPZ_REALLOC (d, limb_idx + 1);
+	  SIZ (d) = -(limb_idx + 1);
+	  MPN_ZERO (dp + dsize, limb_idx - dsize);
+	  dp[limb_idx] = mask;
+	}
+    }
+}
diff --git a/third_party/gmp/mpz/cmp.c b/third_party/gmp/mpz/cmp.c
new file mode 100644
index 0000000..a97b004
--- /dev/null
+++ b/third_party/gmp/mpz/cmp.c
@@ -0,0 +1,53 @@
+/* mpz_cmp(u,v) -- Compare U, V.  Return positive, zero, or negative
+   based on if U > V, U == V, or U < V.
+
+Copyright 1991, 1993, 1994, 1996, 2001, 2002, 2011 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+int
+mpz_cmp (mpz_srcptr u, mpz_srcptr v) __GMP_NOTHROW
+{
+  mp_size_t  usize, vsize, dsize, asize;
+  mp_srcptr  up, vp;
+  int        cmp;
+
+  usize = SIZ(u);
+  vsize = SIZ(v);
+  dsize = usize - vsize;
+  if (dsize != 0)
+    return dsize;
+
+  asize = ABS (usize);
+  up = PTR(u);
+  vp = PTR(v);
+  MPN_CMP (cmp, up, vp, asize);
+  return (usize >= 0 ? cmp : -cmp);
+}
diff --git a/third_party/gmp/mpz/cmp_d.c b/third_party/gmp/mpz/cmp_d.c
new file mode 100644
index 0000000..b5b5e8b
--- /dev/null
+++ b/third_party/gmp/mpz/cmp_d.c
@@ -0,0 +1,144 @@
+/* mpz_cmp_d -- compare absolute values of mpz and double.
+
+Copyright 2001-2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#if HAVE_FLOAT_H
+#include <float.h>  /* for DBL_MAX */
+#endif
+
+#include "gmp-impl.h"
+
+
+#define RETURN_CMP(zl, dl)                      \
+  do {                                          \
+    zlimb = (zl);                               \
+    dlimb = (dl);                               \
+    if (zlimb != dlimb)                         \
+      return (zlimb >= dlimb ? ret : -ret);     \
+  } while (0)
+
+#define RETURN_NONZERO(ptr, size, val)          \
+  do {                                          \
+    mp_size_t __i;                              \
+    for (__i = (size)-1; __i >= 0; __i--)       \
+      if ((ptr)[__i] != 0)                      \
+        return val;                             \
+    return 0;                                   \
+  } while (0)
+
+
+int
+mpz_cmp_d (mpz_srcptr z, double d)
+{
+  mp_limb_t  darray[LIMBS_PER_DOUBLE], zlimb, dlimb;
+  mp_srcptr  zp;
+  mp_size_t  zsize;
+  int        dexp, ret;
+
+  /* d=NaN is an invalid operation, there's no sensible return value.
+     d=Inf or -Inf is always bigger than z.  */
+  DOUBLE_NAN_INF_ACTION (d, __gmp_invalid_operation (), goto z_zero);
+
+  /* 1. Either operand zero. */
+  zsize = SIZ(z);
+  if (d == 0.0)
+    return zsize;
+  if (zsize == 0)
+    {
+    z_zero:
+      return (d < 0.0 ? 1 : -1);
+    }
+
+  /* 2. Opposite signs. */
+  if (zsize >= 0)
+    {
+      if (d < 0.0)
+	return 1;    /* >=0 cmp <0 */
+      ret = 1;
+    }
+  else
+    {
+      if (d >= 0.0)
+	return -1;   /* <0 cmp >=0 */
+      ret = -1;
+      d = -d;
+      zsize = -zsize;
+    }
+
+  /* 3. Small d, knowing abs(z) >= 1. */
+  if (d < 1.0)
+    return ret;
+
+  dexp = __gmp_extract_double (darray, d);
+  ASSERT (dexp >= 1);
+
+  /* 4. Check for different high limb positions. */
+  if (zsize != dexp)
+    return (zsize >= dexp ? ret : -ret);
+
+  /* 5. Limb data. */
+  zp = PTR(z);
+
+#if LIMBS_PER_DOUBLE == 2
+  RETURN_CMP (zp[zsize-1], darray[1]);
+  if (zsize == 1)
+    return (darray[0] != 0 ? -ret : 0);
+
+  RETURN_CMP (zp[zsize-2], darray[0]);
+  RETURN_NONZERO (zp, zsize-2, ret);
+#endif
+
+#if LIMBS_PER_DOUBLE == 3
+  RETURN_CMP (zp[zsize-1], darray[2]);
+  if (zsize == 1)
+    return ((darray[0] | darray[1]) != 0 ? -ret : 0);
+
+  RETURN_CMP (zp[zsize-2], darray[1]);
+  if (zsize == 2)
+    return (darray[0] != 0 ? -ret : 0);
+
+  RETURN_CMP (zp[zsize-3], darray[0]);
+  RETURN_NONZERO (zp, zsize-3, ret);
+#endif
+
+#if LIMBS_PER_DOUBLE >= 4
+  {
+    int i;
+    for (i = 1; i <= LIMBS_PER_DOUBLE; i++)
+      {
+	RETURN_CMP (zp[zsize-i], darray[LIMBS_PER_DOUBLE-i]);
+	if (i >= zsize)
+	  RETURN_NONZERO (darray, LIMBS_PER_DOUBLE-i, -ret);
+      }
+    RETURN_NONZERO (zp, zsize-LIMBS_PER_DOUBLE, ret);
+  }
+#endif
+}
diff --git a/third_party/gmp/mpz/cmp_si.c b/third_party/gmp/mpz/cmp_si.c
new file mode 100644
index 0000000..23296c8
--- /dev/null
+++ b/third_party/gmp/mpz/cmp_si.c
@@ -0,0 +1,69 @@
+/* mpz_cmp_si(u,v) -- Compare an integer U with a single-word int V.
+   Return positive, zero, or negative based on if U > V, U == V, or U < V.
+
+Copyright 1991, 1993-1996, 2000-2002, 2012, 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+int
+_mpz_cmp_si (mpz_srcptr u, signed long int v_digit) __GMP_NOTHROW
+{
+#if GMP_NAIL_BITS != 0
+  /* FIXME.  This isn't very pretty.  */
+  mpz_t tmp;
+  mp_limb_t tt[2];
+  PTR(tmp) = tt;
+  ALLOC(tmp) = 2;
+  mpz_set_si (tmp, v_digit);
+  return mpz_cmp (u, tmp);
+#else
+
+  mp_size_t vsize, usize;
+
+  usize = SIZ (u);
+  vsize = (v_digit > 0) - (v_digit < 0);
+
+  if ((usize == 0) | (usize != vsize))
+    return usize - vsize;
+  else {
+    mp_limb_t u_digit, absv_digit;
+
+    u_digit = PTR (u)[0];
+    absv_digit = ABS_CAST (unsigned long, v_digit);
+
+    if (u_digit == absv_digit)
+      return 0;
+
+    if (u_digit > absv_digit)
+      return usize;
+    else
+      return -usize;
+  }
+#endif
+}
diff --git a/third_party/gmp/mpz/cmp_ui.c b/third_party/gmp/mpz/cmp_ui.c
new file mode 100644
index 0000000..4b40ab7
--- /dev/null
+++ b/third_party/gmp/mpz/cmp_ui.c
@@ -0,0 +1,77 @@
+/* mpz_cmp_ui.c -- Compare an mpz_t a with an mp_limb_t b.  Return positive,
+  zero, or negative based on if a > b, a == b, or a < b.
+
+Copyright 1991, 1993-1996, 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+int
+_mpz_cmp_ui (mpz_srcptr u, unsigned long int v_digit) __GMP_NOTHROW
+{
+  mp_ptr up;
+  mp_size_t un;
+  mp_limb_t ul;
+
+  up = PTR(u);
+  un = SIZ(u);
+
+  if (un == 0)
+    return -(v_digit != 0);
+
+  if (un == 1)
+    {
+      ul = up[0];
+      if (ul > v_digit)
+	return 1;
+      if (ul < v_digit)
+	return -1;
+      return 0;
+    }
+
+#if GMP_NAIL_BITS != 0
+  if (v_digit > GMP_NUMB_MAX)
+    {
+      if (un == 2)
+	{
+	  ul = up[0] + (up[1] << GMP_NUMB_BITS);
+
+	  if ((up[1] >> GMP_NAIL_BITS) != 0)
+	    return 1;
+
+	  if (ul > v_digit)
+	    return 1;
+	  if (ul < v_digit)
+	    return -1;
+	  return 0;
+	}
+    }
+#endif
+
+  return un > 0 ? 1 : -1;
+}
diff --git a/third_party/gmp/mpz/cmpabs.c b/third_party/gmp/mpz/cmpabs.c
new file mode 100644
index 0000000..14f0dc9
--- /dev/null
+++ b/third_party/gmp/mpz/cmpabs.c
@@ -0,0 +1,53 @@
+/* mpz_cmpabs(u,v) -- Compare U, V.  Return positive, zero, or negative
+   based on if U > V, U == V, or U < V.
+
+Copyright 1991, 1993, 1994, 1996, 1997, 2000-2002 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+int
+mpz_cmpabs (mpz_srcptr u, mpz_srcptr v) __GMP_NOTHROW
+{
+  mp_size_t  usize, vsize, dsize;
+  mp_srcptr  up, vp;
+  int        cmp;
+
+  usize = ABSIZ (u);
+  vsize = ABSIZ (v);
+  dsize = usize - vsize;
+  if (dsize != 0)
+    return dsize;
+
+  up = PTR(u);
+  vp = PTR(v);
+  MPN_CMP (cmp, up, vp, usize);
+  return cmp;
+}
diff --git a/third_party/gmp/mpz/cmpabs_d.c b/third_party/gmp/mpz/cmpabs_d.c
new file mode 100644
index 0000000..d2431cc
--- /dev/null
+++ b/third_party/gmp/mpz/cmpabs_d.c
@@ -0,0 +1,129 @@
+/* mpz_cmpabs_d -- compare absolute values of mpz and double.
+
+Copyright 2001-2003, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#if HAVE_FLOAT_H
+#include <float.h>  /* for DBL_MAX */
+#endif
+
+#include "gmp-impl.h"
+
+
+#define RETURN_CMP(zl, dl)              \
+  do {                                  \
+    zlimb = (zl);                       \
+    dlimb = (dl);                       \
+    if (zlimb != dlimb)                 \
+      return (zlimb >= dlimb ? 1 : -1); \
+  } while (0)
+
+#define RETURN_NONZERO(ptr, size, val)          \
+  do {                                          \
+    mp_size_t __i;                              \
+    for (__i = (size)-1; __i >= 0; __i--)       \
+      if ((ptr)[__i] != 0)                      \
+        return val;                             \
+    return 0;                                   \
+  } while (0)
+
+
+int
+mpz_cmpabs_d (mpz_srcptr z, double d)
+{
+  mp_limb_t  darray[LIMBS_PER_DOUBLE], zlimb, dlimb;
+  mp_srcptr  zp;
+  mp_size_t  zsize;
+  int        dexp;
+
+  /* d=NaN is an invalid operation, there's no sensible return value.
+     d=Inf or -Inf is always bigger than z.  */
+  DOUBLE_NAN_INF_ACTION (d, __gmp_invalid_operation (), return -1);
+
+  /* 1. Check for either operand zero. */
+  zsize = SIZ(z);
+  if (d == 0.0)
+    return (zsize != 0);
+  if (zsize == 0)
+    return -1; /* d != 0 */
+
+  /* 2. Ignore signs. */
+  zsize = ABS(zsize);
+  d = ABS(d);
+
+  /* 3. Small d, knowing abs(z) >= 1. */
+  if (d < 1.0)
+    return 1;
+
+  dexp = __gmp_extract_double (darray, d);
+  ASSERT (dexp >= 1);
+
+  /* 4. Check for different high limb positions. */
+  if (zsize != dexp)
+    return (zsize >= dexp ? 1 : -1);
+
+  /* 5. Limb data. */
+  zp = PTR(z);
+
+#if LIMBS_PER_DOUBLE == 2
+  RETURN_CMP (zp[zsize-1], darray[1]);
+  if (zsize == 1)
+    return (darray[0] != 0 ? -1 : 0);
+
+  RETURN_CMP (zp[zsize-2], darray[0]);
+  RETURN_NONZERO (zp, zsize-2, 1);
+#endif
+
+#if LIMBS_PER_DOUBLE == 3
+  RETURN_CMP (zp[zsize-1], darray[2]);
+  if (zsize == 1)
+    return ((darray[0] | darray[1]) != 0 ? -1 : 0);
+
+  RETURN_CMP (zp[zsize-2], darray[1]);
+  if (zsize == 2)
+    return (darray[0] != 0 ? -1 : 0);
+
+  RETURN_CMP (zp[zsize-3], darray[0]);
+  RETURN_NONZERO (zp, zsize-3, 1);
+#endif
+
+#if LIMBS_PER_DOUBLE >= 4
+  {
+    int i;
+    for (i = 1; i <= LIMBS_PER_DOUBLE; i++)
+      {
+	RETURN_CMP (zp[zsize-i], darray[LIMBS_PER_DOUBLE-i]);
+	if (i >= zsize)
+	  RETURN_NONZERO (darray, LIMBS_PER_DOUBLE-i, -1);
+      }
+    RETURN_NONZERO (zp, zsize-LIMBS_PER_DOUBLE, 1);
+  }
+#endif
+}
diff --git a/third_party/gmp/mpz/cmpabs_ui.c b/third_party/gmp/mpz/cmpabs_ui.c
new file mode 100644
index 0000000..6deffb3
--- /dev/null
+++ b/third_party/gmp/mpz/cmpabs_ui.c
@@ -0,0 +1,76 @@
+/* mpz_cmpabs_ui.c -- Compare an mpz_t a with an mp_limb_t b.  Return positive,
+  zero, or negative based on if a > b, a == b, or a < b.
+
+Copyright 1991, 1993-1995, 1997, 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+int
+mpz_cmpabs_ui (mpz_srcptr u, unsigned long int v_digit) __GMP_NOTHROW
+{
+  mp_ptr up;
+  mp_size_t un;
+  mp_limb_t ul;
+
+  up = PTR(u);
+  un = SIZ(u);
+
+  if (un == 0)
+    return -(v_digit != 0);
+
+  un = ABS (un);
+
+  if (un == 1)
+    {
+      ul = up[0];
+      if (ul > v_digit)
+	return 1;
+      if (ul < v_digit)
+	return -1;
+      return 0;
+    }
+
+#if GMP_NAIL_BITS != 0
+  if (v_digit > GMP_NUMB_MAX)
+    {
+      if (un == 2)
+	{
+	  ul = up[0] + (up[1] << GMP_NUMB_BITS);
+
+	  if (ul > v_digit)
+	    return 1;
+	  if (ul < v_digit)
+	    return -1;
+	  return 0;
+	}
+    }
+#endif
+
+  return 1;
+}
diff --git a/third_party/gmp/mpz/com.c b/third_party/gmp/mpz/com.c
new file mode 100644
index 0000000..c5d22b0
--- /dev/null
+++ b/third_party/gmp/mpz/com.c
@@ -0,0 +1,87 @@
+/* mpz_com(mpz_ptr dst, mpz_ptr src) -- Assign the bit-complemented value of
+   SRC to DST.
+
+Copyright 1991, 1993, 1994, 1996, 2001, 2003, 2012, 2015 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_com (mpz_ptr dst, mpz_srcptr src)
+{
+  mp_size_t size = SIZ (src);
+  mp_srcptr src_ptr;
+  mp_ptr dst_ptr;
+
+  if (size >= 0)
+    {
+      /* As with infinite precision: one's complement, two's complement.
+	 But this can be simplified using the identity -x = ~x + 1.
+	 So we're going to compute (~~x) + 1 = x + 1!  */
+
+      if (UNLIKELY (size == 0))
+	{
+	  /* special case, as mpn_add_1 wants size!=0 */
+	  MPZ_NEWALLOC (dst, 1)[0] = 1;
+	  SIZ (dst) = -1;
+	}
+      else
+	{
+	  mp_limb_t cy;
+
+	  dst_ptr = MPZ_REALLOC (dst, size + 1);
+
+	  src_ptr = PTR (src);
+
+	  cy = mpn_add_1 (dst_ptr, src_ptr, size, (mp_limb_t) 1);
+	  dst_ptr[size] = cy;
+	  size += cy;
+
+	  /* Store a negative size, to indicate ones-extension.  */
+	  SIZ (dst) = -size;
+      }
+    }
+  else
+    {
+      /* As with infinite precision: two's complement, then one's complement.
+	 But that can be simplified using the identity -x = ~(x - 1).
+	 So we're going to compute ~~(x - 1) = x - 1!  */
+      size = -size;
+
+      dst_ptr = MPZ_REALLOC (dst, size);
+
+      src_ptr = PTR (src);
+
+      mpn_sub_1 (dst_ptr, src_ptr, size, (mp_limb_t) 1);
+      size -= dst_ptr[size - 1] == 0;
+
+      /* Store a positive size, to indicate zero-extension.  */
+      SIZ (dst) = size;
+    }
+}
diff --git a/third_party/gmp/mpz/combit.c b/third_party/gmp/mpz/combit.c
new file mode 100644
index 0000000..0a29875
--- /dev/null
+++ b/third_party/gmp/mpz/combit.c
@@ -0,0 +1,103 @@
+/* mpz_combit -- complement a specified bit.
+
+Copyright 2002, 2003, 2012, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_combit (mpz_ptr d, mp_bitcnt_t bit_index)
+{
+  mp_size_t dsize = SIZ(d);
+  mp_ptr dp = PTR(d);
+
+  mp_size_t limb_index = bit_index / GMP_NUMB_BITS;
+  mp_limb_t bit = (CNST_LIMB (1) << (bit_index % GMP_NUMB_BITS));
+
+  /* Check for the most common case: Positive input, no realloc or
+     normalization needed. */
+  if (limb_index + 1 < dsize)
+    dp[limb_index] ^= bit;
+
+  /* Check for the hairy case. d < 0, and we have all zero bits to the
+     right of the bit to toggle. */
+  else if (limb_index < -dsize
+	   && (limb_index == 0 || mpn_zero_p (dp, limb_index))
+	   && (dp[limb_index] & (bit - 1)) == 0)
+    {
+      ASSERT (dsize < 0);
+      dsize = -dsize;
+
+      if (dp[limb_index] & bit)
+	{
+	  /* We toggle the least significant one bit. Corresponds to
+	     an add, with potential carry propagation, on the absolute
+	     value. */
+	  dp = MPZ_REALLOC (d, 1 + dsize);
+	  dp[dsize] = 0;
+	  MPN_INCR_U (dp + limb_index, 1 + dsize - limb_index, bit);
+	  SIZ(d) = - dsize - dp[dsize];
+	}
+      else
+	{
+	  /* We toggle a zero bit, subtract from the absolute value. */
+	  MPN_DECR_U (dp + limb_index, dsize - limb_index, bit);
+	  /* The absolute value shrinked by at most one bit. */
+	  dsize -= dp[dsize - 1] == 0;
+	  ASSERT (dsize > 0 && dp[dsize - 1] != 0);
+	  SIZ (d) = -dsize;
+	}
+    }
+  else
+    {
+      /* Simple case: Toggle the bit in the absolute value. */
+      dsize = ABS(dsize);
+      if (limb_index < dsize)
+	{
+	  mp_limb_t	 dlimb;
+	  dlimb = dp[limb_index] ^ bit;
+	  dp[limb_index] = dlimb;
+
+	  /* Can happen only when limb_index = dsize - 1. Avoid SIZ(d)
+	     bookkeeping in the common case. */
+	  if (UNLIKELY ((dlimb == 0) + limb_index == dsize)) /* dsize == limb_index + 1 */
+	    {
+	      /* high limb became zero, must normalize */
+	      MPN_NORMALIZE (dp, limb_index);
+	      SIZ (d) = SIZ (d) >= 0 ? limb_index : -limb_index;
+	    }
+	}
+      else
+	{
+	  dp = MPZ_REALLOC (d, limb_index + 1);
+	  MPN_ZERO(dp + dsize, limb_index - dsize);
+	  dp[limb_index++] = bit;
+	  SIZ(d) = SIZ(d) >= 0 ? limb_index : -limb_index;
+	}
+    }
+}
diff --git a/third_party/gmp/mpz/cong.c b/third_party/gmp/mpz/cong.c
new file mode 100644
index 0000000..5d2d835
--- /dev/null
+++ b/third_party/gmp/mpz/cong.c
@@ -0,0 +1,182 @@
+/* mpz_congruent_p -- test congruence of two mpz's.
+
+Copyright 2001, 2002, 2005 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* For big divisors this code is only very slightly better than the user
+   doing a combination of mpz_sub and mpz_tdiv_r, but it's quite convenient,
+   and perhaps in the future can be improved, in similar ways to
+   mpn_divisible_p perhaps.
+
+   The csize==1 / dsize==1 special case makes mpz_congruent_p as good as
+   mpz_congruent_ui_p on relevant operands, though such a combination
+   probably doesn't occur often.
+
+   Alternatives:
+
+   If c<d then it'd work to just form a%d and compare a and c (either as
+   a==c or a+c==d depending on the signs), but the saving from avoiding the
+   abs(a-c) calculation would be small compared to the division.
+
+   Similarly if both a<d and c<d then it would work to just compare a and c
+   (a==c or a+c==d), but this isn't considered a particularly important case
+   and so isn't done for the moment.
+
+   Low zero limbs on d could be stripped and the corresponding limbs of a
+   and c tested and skipped, but doing so would introduce a borrow when a
+   and c differ in sign and have non-zero skipped limbs.  It doesn't seem
+   worth the complications to do this, since low zero limbs on d should
+   occur only rarely.  */
+
+int
+mpz_congruent_p (mpz_srcptr a, mpz_srcptr c, mpz_srcptr d)
+{
+  mp_size_t  asize, csize, dsize, sign;
+  mp_srcptr  ap, cp, dp;
+  mp_ptr     xp;
+  mp_limb_t  alow, clow, dlow, dmask, r;
+  int        result;
+  TMP_DECL;
+
+  dsize = SIZ(d);
+  if (UNLIKELY (dsize == 0))
+    return (mpz_cmp (a, c) == 0);
+
+  dsize = ABS(dsize);
+  dp = PTR(d);
+
+  if (ABSIZ(a) < ABSIZ(c))
+    MPZ_SRCPTR_SWAP (a, c);
+
+  asize = SIZ(a);
+  csize = SIZ(c);
+  sign = (asize ^ csize);
+
+  asize = ABS(asize);
+  ap = PTR(a);
+
+  if (csize == 0)
+    return mpn_divisible_p (ap, asize, dp, dsize);
+
+  csize = ABS(csize);
+  cp = PTR(c);
+
+  alow = ap[0];
+  clow = cp[0];
+  dlow = dp[0];
+
+  /* Check a==c mod low zero bits of dlow.  This might catch a few cases of
+     a!=c quickly, and it helps the csize==1 special cases below.  */
+  dmask = LOW_ZEROS_MASK (dlow) & GMP_NUMB_MASK;
+  alow = (sign >= 0 ? alow : -alow);
+  if (((alow-clow) & dmask) != 0)
+    return 0;
+
+  if (csize == 1)
+    {
+      if (dsize == 1)
+	{
+	cong_1:
+	  if (sign < 0)
+	    NEG_MOD (clow, clow, dlow);
+
+	  if (ABOVE_THRESHOLD (asize, BMOD_1_TO_MOD_1_THRESHOLD))
+	    {
+	      r = mpn_mod_1 (ap, asize, dlow);
+	      if (clow < dlow)
+		return r == clow;
+	      else
+		return r == (clow % dlow);
+	    }
+
+	  if ((dlow & 1) == 0)
+	    {
+	      /* Strip low zero bits to get odd d required by modexact.  If
+		 d==e*2^n then a==c mod d if and only if both a==c mod e and
+		 a==c mod 2^n, the latter having been done above.  */
+	      unsigned	twos;
+	      count_trailing_zeros (twos, dlow);
+	      dlow >>= twos;
+	    }
+
+	  r = mpn_modexact_1c_odd (ap, asize, dlow, clow);
+	  return r == 0 || r == dlow;
+	}
+
+      /* dlow==0 is avoided since we don't want to bother handling extra low
+	 zero bits if dsecond is even (would involve borrow if a,c differ in
+	 sign and alow,clow!=0).  */
+      if (dsize == 2 && dlow != 0)
+	{
+	  mp_limb_t  dsecond = dp[1];
+
+	  if (dsecond <= dmask)
+	    {
+	      unsigned	 twos;
+	      count_trailing_zeros (twos, dlow);
+	      dlow = (dlow >> twos) | (dsecond << (GMP_NUMB_BITS-twos));
+	      ASSERT_LIMB (dlow);
+
+	      /* dlow will be odd here, so the test for it even under cong_1
+		 is unnecessary, but the rest of that code is wanted. */
+	      goto cong_1;
+	    }
+	}
+    }
+
+  TMP_MARK;
+  xp = TMP_ALLOC_LIMBS (asize+1);
+
+  /* calculate abs(a-c) */
+  if (sign >= 0)
+    {
+      /* same signs, subtract */
+      if (asize > csize || mpn_cmp (ap, cp, asize) >= 0)
+	ASSERT_NOCARRY (mpn_sub (xp, ap, asize, cp, csize));
+      else
+	ASSERT_NOCARRY (mpn_sub_n (xp, cp, ap, asize));
+      MPN_NORMALIZE (xp, asize);
+    }
+  else
+    {
+      /* different signs, add */
+      mp_limb_t  carry;
+      carry = mpn_add (xp, ap, asize, cp, csize);
+      xp[asize] = carry;
+      asize += (carry != 0);
+    }
+
+  result = mpn_divisible_p (xp, asize, dp, dsize);
+
+  TMP_FREE;
+  return result;
+}
diff --git a/third_party/gmp/mpz/cong_2exp.c b/third_party/gmp/mpz/cong_2exp.c
new file mode 100644
index 0000000..9de9645
--- /dev/null
+++ b/third_party/gmp/mpz/cong_2exp.c
@@ -0,0 +1,149 @@
+/* mpz_congruent_2exp_p -- test congruence of mpz mod 2^n.
+
+Copyright 2001, 2002, 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+int
+mpz_congruent_2exp_p (mpz_srcptr a, mpz_srcptr c, mp_bitcnt_t d) __GMP_NOTHROW
+{
+  mp_size_t      i, dlimbs;
+  unsigned       dbits;
+  mp_ptr         ap, cp;
+  mp_limb_t      dmask, alimb, climb, sum;
+  mp_size_t      as, cs, asize, csize;
+
+  as = SIZ(a);
+  asize = ABS(as);
+
+  cs = SIZ(c);
+  csize = ABS(cs);
+
+  if (asize < csize)
+    {
+      MPZ_SRCPTR_SWAP (a, c);
+      MP_SIZE_T_SWAP (asize, csize);
+    }
+
+  dlimbs = d / GMP_NUMB_BITS;
+  dbits = d % GMP_NUMB_BITS;
+  dmask = (CNST_LIMB(1) << dbits) - 1;
+
+  ap = PTR(a);
+  cp = PTR(c);
+
+  if (csize == 0)
+    goto a_zeros;
+
+  if ((cs ^ as) >= 0)
+    {
+      /* same signs, direct comparison */
+
+      /* a==c for limbs in common */
+      if (mpn_cmp (ap, cp, MIN (csize, dlimbs)) != 0)
+	return 0;
+
+      /* if that's all of dlimbs, then a==c for remaining bits */
+      if (csize > dlimbs)
+	return ((ap[dlimbs]-cp[dlimbs]) & dmask) == 0;
+
+    a_zeros:
+      /* a remains, need all zero bits */
+
+      /* if d covers all of a and c, then must be exactly equal */
+      if (asize <= dlimbs)
+	return asize == csize;
+
+      /* whole limbs zero */
+      for (i = csize; i < dlimbs; i++)
+	if (ap[i] != 0)
+	  return 0;
+
+      /* partial limb zero */
+      return (ap[dlimbs] & dmask) == 0;
+    }
+  else
+    {
+      /* different signs, negated comparison */
+
+      /* common low zero limbs, stopping at first non-zeros, which must
+	 match twos complement */
+      i = 0;
+      do
+	{
+	  ASSERT (i < csize);  /* always have a non-zero limb on c */
+	  alimb = ap[i];
+	  climb = cp[i];
+	  sum = (alimb + climb) & GMP_NUMB_MASK;
+
+	  if (i >= dlimbs)
+	    return (sum & dmask) == 0;
+	  ++i;
+
+	  /* require both zero, or first non-zeros as twos-complements */
+	  if (sum != 0)
+	    return 0;
+	} while (alimb == 0);
+
+      /* further limbs matching as ones-complement */
+      for (; i < csize; ++i)
+	{
+	  alimb = ap[i];
+	  climb = cp[i];
+	  sum = alimb ^ climb ^ GMP_NUMB_MASK;
+
+	  if (i >= dlimbs)
+	    return (sum & dmask) == 0;
+
+	  if (sum != 0)
+	    return 0;
+	}
+
+      /* no more c, so require all 1 bits in a */
+
+      if (asize < dlimbs)
+	return 0;   /* not enough a */
+
+      /* whole limbs */
+      for ( ; i < dlimbs; i++)
+	if (ap[i] != GMP_NUMB_MAX)
+	  return 0;
+
+      /* if only whole limbs, no further fetches from a */
+      if (dbits == 0)
+	return 1;
+
+      /* need enough a */
+      if (asize == dlimbs)
+	return 0;
+
+      return ((ap[dlimbs]+1) & dmask) == 0;
+    }
+}
diff --git a/third_party/gmp/mpz/cong_ui.c b/third_party/gmp/mpz/cong_ui.c
new file mode 100644
index 0000000..6f86c23
--- /dev/null
+++ b/third_party/gmp/mpz/cong_ui.c
@@ -0,0 +1,115 @@
+/* mpz_congruent_ui_p -- test congruence of mpz and ulong.
+
+Copyright 2000-2002, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* There's some explicit checks for c<d since it seems reasonably likely an
+   application might use that in a test.
+
+   Hopefully the compiler can generate something good for r==(c%d), though
+   if modexact is being used exclusively then that's not reached.  */
+
+int
+mpz_congruent_ui_p (mpz_srcptr a, unsigned long cu, unsigned long du)
+{
+  mp_srcptr  ap;
+  mp_size_t  asize;
+  mp_limb_t  c, d, r;
+
+  if (UNLIKELY (du == 0))
+    return (mpz_cmp_ui (a, cu) == 0);
+
+  asize = SIZ(a);
+  if (asize == 0)
+    {
+      if (cu < du)
+	return cu == 0;
+      else
+	return (cu % du) == 0;
+    }
+
+  /* For nails don't try to be clever if c or d is bigger than a limb, just
+     fake up some mpz_t's and go to the main mpz_congruent_p.  */
+  if (du > GMP_NUMB_MAX || cu > GMP_NUMB_MAX)
+    {
+      mp_limb_t  climbs[2], dlimbs[2];
+      mpz_t      cz, dz;
+
+      ALLOC(cz) = 2;
+      PTR(cz) = climbs;
+      ALLOC(dz) = 2;
+      PTR(dz) = dlimbs;
+
+      mpz_set_ui (cz, cu);
+      mpz_set_ui (dz, du);
+      return mpz_congruent_p (a, cz, dz);
+    }
+
+  /* NEG_MOD works on limbs, so convert ulong to limb */
+  c = cu;
+  d = du;
+
+  if (asize < 0)
+    {
+      asize = -asize;
+      NEG_MOD (c, c, d);
+    }
+
+  ap = PTR (a);
+
+  if (ABOVE_THRESHOLD (asize, BMOD_1_TO_MOD_1_THRESHOLD))
+    {
+      r = mpn_mod_1 (ap, asize, d);
+      if (c < d)
+	return r == c;
+      else
+	return r == (c % d);
+    }
+
+  if ((d & 1) == 0)
+    {
+      /* Strip low zero bits to get odd d required by modexact.  If
+	 d==e*2^n then a==c mod d if and only if both a==c mod 2^n
+	 and a==c mod e.  */
+
+      unsigned	twos;
+
+      if ((ap[0]-c) & LOW_ZEROS_MASK (d))
+	return 0;
+
+      count_trailing_zeros (twos, d);
+      d >>= twos;
+    }
+
+  r = mpn_modexact_1c_odd (ap, asize, d, c);
+  return r == 0 || r == d;
+}
diff --git a/third_party/gmp/mpz/dive_ui.c b/third_party/gmp/mpz/dive_ui.c
new file mode 100644
index 0000000..c859b96
--- /dev/null
+++ b/third_party/gmp/mpz/dive_ui.c
@@ -0,0 +1,68 @@
+/* mpz_divexact_ui -- exact division mpz by ulong.
+
+Copyright 2001, 2002, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_divexact_ui (mpz_ptr dst, mpz_srcptr src, unsigned long divisor)
+{
+  mp_size_t  size, abs_size;
+  mp_ptr     dst_ptr;
+
+  if (UNLIKELY (divisor == 0))
+    DIVIDE_BY_ZERO;
+
+  /* For nails don't try to be clever if d is bigger than a limb, just fake
+     up an mpz_t and go to the main mpz_divexact.  */
+  if (divisor > GMP_NUMB_MAX)
+    {
+      mp_limb_t  dlimbs[2];
+      mpz_t      dz;
+      ALLOC(dz) = 2;
+      PTR(dz) = dlimbs;
+      mpz_set_ui (dz, divisor);
+      mpz_divexact (dst, src, dz);
+      return;
+    }
+
+  size = SIZ(src);
+  if (size == 0)
+    {
+      SIZ(dst) = 0;
+      return;
+    }
+  abs_size = ABS (size);
+
+  dst_ptr = MPZ_REALLOC (dst, abs_size);
+
+  MPN_DIVREM_OR_DIVEXACT_1 (dst_ptr, PTR(src), abs_size, (mp_limb_t) divisor);
+  abs_size -= (dst_ptr[abs_size-1] == 0);
+  SIZ(dst) = (size >= 0 ? abs_size : -abs_size);
+}
diff --git a/third_party/gmp/mpz/divegcd.c b/third_party/gmp/mpz/divegcd.c
new file mode 100644
index 0000000..dc236c3
--- /dev/null
+++ b/third_party/gmp/mpz/divegcd.c
@@ -0,0 +1,156 @@
+/* mpz_divexact_gcd -- exact division optimized for GCDs.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE AND ARE ALMOST CERTAIN TO
+   BE SUBJECT TO INCOMPATIBLE CHANGES IN FUTURE GNU MP RELEASES.
+
+Copyright 2000, 2005, 2011, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* Set q to a/d, expecting d to be from a GCD and therefore usually small.
+
+   The distribution of GCDs of random numbers can be found in Knuth volume 2
+   section 4.5.2 theorem D.
+
+            GCD     chance
+             1       60.8%
+            2^k      20.2%     (1<=k<32)
+           3*2^k      9.0%     (1<=k<32)
+           other     10.1%
+
+   Only the low limb is examined for optimizations, since GCDs bigger than
+   2^32 (or 2^64) will occur very infrequently.
+
+   Future: This could change to an mpn_divexact_gcd, possibly partly
+   inlined, if/when the relevant mpq functions change to an mpn based
+   implementation.  */
+
+
+#if GMP_NUMB_BITS % 2 == 0
+static void
+mpz_divexact_by3 (mpz_ptr q, mpz_srcptr a)
+{
+  mp_size_t  size = SIZ(a);
+  mp_size_t  abs_size = ABS(size);
+  mp_ptr     qp;
+
+  qp = MPZ_REALLOC (q, abs_size);
+
+  mpn_bdiv_dbm1 (qp, PTR(a), abs_size, GMP_NUMB_MASK / 3);
+
+  abs_size -= (qp[abs_size-1] == 0);
+  SIZ(q) = (size>0 ? abs_size : -abs_size);
+}
+#endif
+
+#if GMP_NUMB_BITS % 4 == 0
+static void
+mpz_divexact_by5 (mpz_ptr q, mpz_srcptr a)
+{
+  mp_size_t  size = SIZ(a);
+  mp_size_t  abs_size = ABS(size);
+  mp_ptr     qp;
+
+  qp = MPZ_REALLOC (q, abs_size);
+
+  mpn_bdiv_dbm1 (qp, PTR(a), abs_size, GMP_NUMB_MASK / 5);
+
+  abs_size -= (qp[abs_size-1] == 0);
+  SIZ(q) = (size>0 ? abs_size : -abs_size);
+}
+#endif
+
+static void
+mpz_divexact_limb (mpz_ptr q, mpz_srcptr a, mp_limb_t d)
+{
+  mp_size_t  size = SIZ(a);
+  mp_size_t  abs_size = ABS(size);
+  mp_ptr     qp;
+
+  qp = MPZ_REALLOC (q, abs_size);
+
+  MPN_DIVREM_OR_DIVEXACT_1 (qp, PTR(a), abs_size, d);
+
+  abs_size -= (qp[abs_size-1] == 0);
+  SIZ(q) = (size > 0 ? abs_size : -abs_size);
+}
+
+void
+mpz_divexact_gcd (mpz_ptr q, mpz_srcptr a, mpz_srcptr d)
+{
+  ASSERT (mpz_sgn (d) > 0);
+
+  if (SIZ(a) == 0)
+    {
+      SIZ(q) = 0;
+      return;
+    }
+
+  if (SIZ(d) == 1)
+    {
+      mp_limb_t  dl = PTR(d)[0];
+      int        twos;
+
+      if ((dl & 1) == 0)
+	{
+	  count_trailing_zeros (twos, dl);
+	  dl >>= twos;
+	  mpz_tdiv_q_2exp (q, a, twos);
+	  a = q;
+	}
+
+      if (dl == 1)
+	{
+	  if (q != a)
+	    mpz_set (q, a);
+	  return;
+	}
+#if GMP_NUMB_BITS % 2 == 0
+      if (dl == 3)
+	{
+	  mpz_divexact_by3 (q, a);
+	  return;
+	}
+#endif
+#if GMP_NUMB_BITS % 4 == 0
+      if (dl == 5)
+	{
+	  mpz_divexact_by5 (q, a);
+	  return;
+	}
+#endif
+
+      mpz_divexact_limb (q, a, dl);
+      return;
+    }
+
+  mpz_divexact (q, a, d);
+}
diff --git a/third_party/gmp/mpz/divexact.c b/third_party/gmp/mpz/divexact.c
new file mode 100644
index 0000000..8336819
--- /dev/null
+++ b/third_party/gmp/mpz/divexact.c
@@ -0,0 +1,89 @@
+/* mpz_divexact -- finds quotient when known that quot * den == num && den != 0.
+
+Contributed to the GNU project by Niels Möller.
+
+Copyright 1991, 1993-1998, 2000-2002, 2005-2007, 2009, 2012 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+void
+mpz_divexact (mpz_ptr quot, mpz_srcptr num, mpz_srcptr den)
+{
+  mp_ptr qp;
+  mp_size_t qn;
+  mp_srcptr np, dp;
+  mp_size_t nn, dn;
+  TMP_DECL;
+
+#if WANT_ASSERT
+  {
+    mpz_t  rem;
+    mpz_init (rem);
+    mpz_tdiv_r (rem, num, den);
+    ASSERT (SIZ(rem) == 0);
+    mpz_clear (rem);
+  }
+#endif
+
+  nn = ABSIZ (num);
+  dn = ABSIZ (den);
+
+  if (nn < dn)
+    {
+      /* This special case avoids segfaults below when the function is
+	 incorrectly called with |N| < |D|, N != 0.  It also handles the
+	 well-defined case N = 0.  */
+      SIZ(quot) = 0;
+      return;
+    }
+
+  qn = nn - dn + 1;
+
+  TMP_MARK;
+
+  if (quot == num || quot == den)
+    qp = TMP_ALLOC_LIMBS (qn);
+  else
+    qp = MPZ_NEWALLOC (quot, qn);
+
+  np = PTR(num);
+  dp = PTR(den);
+
+  mpn_divexact (qp, np, nn, dp, dn);
+  MPN_NORMALIZE (qp, qn);
+
+  if (qp != PTR(quot))
+    MPN_COPY (MPZ_NEWALLOC (quot, qn), qp, qn);
+
+  SIZ(quot) = (SIZ(num) ^ SIZ(den)) >= 0 ? qn : -qn;
+
+  TMP_FREE;
+}
diff --git a/third_party/gmp/mpz/divis.c b/third_party/gmp/mpz/divis.c
new file mode 100644
index 0000000..35429a7
--- /dev/null
+++ b/third_party/gmp/mpz/divis.c
@@ -0,0 +1,43 @@
+/* mpz_divisible_p -- mpz by mpz divisibility test
+
+Copyright 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+int
+mpz_divisible_p (mpz_srcptr a, mpz_srcptr d)
+{
+  mp_size_t dsize = SIZ(d);
+  mp_size_t asize = SIZ(a);
+
+  if (UNLIKELY (dsize == 0))
+    return (asize == 0);
+
+  return mpn_divisible_p (PTR(a), ABS(asize), PTR(d), ABS(dsize));
+}
diff --git a/third_party/gmp/mpz/divis_2exp.c b/third_party/gmp/mpz/divis_2exp.c
new file mode 100644
index 0000000..4ecb0c0
--- /dev/null
+++ b/third_party/gmp/mpz/divis_2exp.c
@@ -0,0 +1,60 @@
+/* mpz_divisible_2exp_p -- mpz by 2^n divisibility test
+
+Copyright 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+int
+mpz_divisible_2exp_p (mpz_srcptr a, mp_bitcnt_t d) __GMP_NOTHROW
+{
+  mp_size_t      i, dlimbs;
+  unsigned       dbits;
+  mp_ptr         ap;
+  mp_limb_t      dmask;
+  mp_size_t      asize;
+
+  asize = ABSIZ(a);
+  dlimbs = d / GMP_NUMB_BITS;
+
+  /* if d covers the whole of a, then only a==0 is divisible */
+  if (asize <= dlimbs)
+    return asize == 0;
+
+  /* whole limbs must be zero */
+  ap = PTR(a);
+  for (i = 0; i < dlimbs; i++)
+    if (ap[i] != 0)
+      return 0;
+
+  /* left over bits must be zero */
+  dbits = d % GMP_NUMB_BITS;
+  dmask = (CNST_LIMB(1) << dbits) - 1;
+  return (ap[dlimbs] & dmask) == 0;
+}
diff --git a/third_party/gmp/mpz/divis_ui.c b/third_party/gmp/mpz/divis_ui.c
new file mode 100644
index 0000000..b24c7dc
--- /dev/null
+++ b/third_party/gmp/mpz/divis_ui.c
@@ -0,0 +1,80 @@
+/* mpz_divisible_ui_p -- mpz by ulong divisibility test.
+
+Copyright 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+int
+mpz_divisible_ui_p (mpz_srcptr a, unsigned long d)
+{
+  mp_size_t  asize;
+  mp_ptr     ap;
+  unsigned   twos;
+
+  asize = SIZ(a);
+  if (UNLIKELY (d == 0))
+    return (asize == 0);
+
+  if (asize == 0)  /* 0 divisible by any d */
+    return 1;
+
+  /* For nails don't try to be clever if d is bigger than a limb, just fake
+     up an mpz_t and go to the main mpz_divisible_p.  */
+  if (d > GMP_NUMB_MAX)
+    {
+      mp_limb_t  dlimbs[2];
+      mpz_t      dz;
+      ALLOC(dz) = 2;
+      PTR(dz) = dlimbs;
+      mpz_set_ui (dz, d);
+      return mpz_divisible_p (a, dz);
+    }
+
+  ap = PTR(a);
+  asize = ABS(asize);  /* ignore sign of a */
+
+  if (ABOVE_THRESHOLD (asize, BMOD_1_TO_MOD_1_THRESHOLD))
+    return mpn_mod_1 (ap, asize, (mp_limb_t) d) == 0;
+
+  if (! (d & 1))
+    {
+      /* Strip low zero bits to get odd d required by modexact.  If d==e*2^n
+	 and a is divisible by 2^n and by e, then it's divisible by d. */
+
+      if ((ap[0] & LOW_ZEROS_MASK (d)) != 0)
+	return 0;
+
+      count_trailing_zeros (twos, (mp_limb_t) d);
+      d >>= twos;
+    }
+
+  return mpn_modexact_1_odd (ap, asize, (mp_limb_t) d) == 0;
+}
diff --git a/third_party/gmp/mpz/dump.c b/third_party/gmp/mpz/dump.c
new file mode 100644
index 0000000..6135ddd
--- /dev/null
+++ b/third_party/gmp/mpz/dump.c
@@ -0,0 +1,48 @@
+/* mpz_dump - Dump an integer to stdout.
+
+   THIS IS AN INTERNAL FUNCTION WITH A MUTABLE INTERFACE.  IT IS NOT SAFE TO
+   CALL THIS FUNCTION DIRECTLY.  IN FACT, IT IS ALMOST GUARANTEED THAT THIS
+   FUNCTION WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+
+Copyright 1999-2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <string.h> /* for strlen */
+#include "gmp-impl.h"
+
+void
+mpz_dump (mpz_srcptr u)
+{
+  char *str;
+
+  str = mpz_get_str (0, 10, u);
+  printf ("%s\n", str);
+  (*__gmp_free_func) (str, strlen (str) + 1);
+}
diff --git a/third_party/gmp/mpz/export.c b/third_party/gmp/mpz/export.c
new file mode 100644
index 0000000..2dacd69
--- /dev/null
+++ b/third_party/gmp/mpz/export.c
@@ -0,0 +1,189 @@
+/* mpz_export -- create word data from mpz.
+
+Copyright 2002, 2003, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>  /* for NULL */
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+#if HAVE_LIMB_BIG_ENDIAN
+#define HOST_ENDIAN     1
+#endif
+#if HAVE_LIMB_LITTLE_ENDIAN
+#define HOST_ENDIAN     (-1)
+#endif
+#ifndef HOST_ENDIAN
+static const mp_limb_t  endian_test = (CNST_LIMB(1) << (GMP_LIMB_BITS-7)) - 1;
+#define HOST_ENDIAN     (* (signed char *) &endian_test)
+#endif
+
+void *
+mpz_export (void *data, size_t *countp, int order,
+	    size_t size, int endian, size_t nail, mpz_srcptr z)
+{
+  mp_size_t      zsize;
+  mp_srcptr      zp;
+  size_t         count, dummy;
+  unsigned long  numb;
+  unsigned       align;
+
+  ASSERT (order == 1 || order == -1);
+  ASSERT (endian == 1 || endian == 0 || endian == -1);
+  ASSERT (nail <= 8*size);
+  ASSERT (nail <  8*size || SIZ(z) == 0); /* nail < 8*size+(SIZ(z)==0) */
+
+  if (countp == NULL)
+    countp = &dummy;
+
+  zsize = SIZ(z);
+  if (zsize == 0)
+    {
+      *countp = 0;
+      return data;
+    }
+
+  zsize = ABS (zsize);
+  zp = PTR(z);
+  numb = 8*size - nail;
+  MPN_SIZEINBASE_2EXP (count, zp, zsize, numb);
+  *countp = count;
+
+  if (data == NULL)
+    data = (*__gmp_allocate_func) (count*size);
+
+  if (endian == 0)
+    endian = HOST_ENDIAN;
+
+  align = ((char *) data - (char *) NULL) % sizeof (mp_limb_t);
+
+  if (nail == GMP_NAIL_BITS)
+    {
+      if (size == sizeof (mp_limb_t) && align == 0)
+	{
+	  if (order == -1 && endian == HOST_ENDIAN)
+	    {
+	      MPN_COPY ((mp_ptr) data, zp, (mp_size_t) count);
+	      return data;
+	    }
+	  if (order == 1 && endian == HOST_ENDIAN)
+	    {
+	      MPN_REVERSE ((mp_ptr) data, zp, (mp_size_t) count);
+	      return data;
+	    }
+
+	  if (order == -1 && endian == -HOST_ENDIAN)
+	    {
+	      MPN_BSWAP ((mp_ptr) data, zp, (mp_size_t) count);
+	      return data;
+	    }
+	  if (order == 1 && endian == -HOST_ENDIAN)
+	    {
+	      MPN_BSWAP_REVERSE ((mp_ptr) data, zp, (mp_size_t) count);
+	      return data;
+	    }
+	}
+    }
+
+  {
+    mp_limb_t      limb, wbitsmask;
+    size_t         i, numb;
+    mp_size_t      j, wbytes, woffset;
+    unsigned char  *dp;
+    int            lbits, wbits;
+    mp_srcptr      zend;
+
+    numb = size * 8 - nail;
+
+    /* whole bytes per word */
+    wbytes = numb / 8;
+
+    /* possible partial byte */
+    wbits = numb % 8;
+    wbitsmask = (CNST_LIMB(1) << wbits) - 1;
+
+    /* offset to get to the next word */
+    woffset = (endian >= 0 ? size : - (mp_size_t) size)
+      + (order < 0 ? size : - (mp_size_t) size);
+
+    /* least significant byte */
+    dp = (unsigned char *) data
+      + (order >= 0 ? (count-1)*size : 0) + (endian >= 0 ? size-1 : 0);
+
+#define EXTRACT(N, MASK)                                \
+    do {                                                \
+      if (lbits >= (N))                                 \
+        {                                               \
+          *dp = limb MASK;                              \
+          limb >>= (N);                                 \
+          lbits -= (N);                                 \
+        }                                               \
+      else                                              \
+        {                                               \
+          mp_limb_t  newlimb;                           \
+          newlimb = (zp == zend ? 0 : *zp++);           \
+          *dp = (limb | (newlimb << lbits)) MASK;       \
+          limb = newlimb >> ((N)-lbits);                \
+          lbits += GMP_NUMB_BITS - (N);                 \
+        }                                               \
+    } while (0)
+
+    zend = zp + zsize;
+    lbits = 0;
+    limb = 0;
+    for (i = 0; i < count; i++)
+      {
+	for (j = 0; j < wbytes; j++)
+	  {
+	    EXTRACT (8, + 0);
+	    dp -= endian;
+	  }
+	if (wbits != 0)
+	  {
+	    EXTRACT (wbits, & wbitsmask);
+	    dp -= endian;
+	    j++;
+	  }
+	for ( ; j < size; j++)
+	  {
+	    *dp = '\0';
+	    dp -= endian;
+	  }
+	dp += woffset;
+      }
+
+    ASSERT (zp == PTR(z) + ABSIZ(z));
+
+    /* low byte of word after most significant */
+    ASSERT (dp == (unsigned char *) data
+	    + (order < 0 ? count*size : - (mp_size_t) size)
+	    + (endian >= 0 ? (mp_size_t) size - 1 : 0));
+  }
+  return data;
+}
diff --git a/third_party/gmp/mpz/fac_ui.c b/third_party/gmp/mpz/fac_ui.c
new file mode 100644
index 0000000..db3cfee
--- /dev/null
+++ b/third_party/gmp/mpz/fac_ui.c
@@ -0,0 +1,108 @@
+/* mpz_fac_ui(RESULT, N) -- Set RESULT to N!.
+
+Contributed to the GNU project by Marco Bodrato.
+
+Copyright 1991, 1993-1995, 2000-2003, 2011, 2012, 2015 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#define FACTOR_LIST_STORE(P, PR, MAX_PR, VEC, I)		\
+  do {								\
+    if ((PR) > (MAX_PR)) {					\
+      (VEC)[(I)++] = (PR);					\
+      (PR) = (P);						\
+    } else							\
+      (PR) *= (P);						\
+  } while (0)
+
+#if TUNE_PROGRAM_BUILD
+#define FACTORS_PER_LIMB (GMP_NUMB_BITS / (LOG2C(FAC_DSC_THRESHOLD_LIMIT-1)+1))
+#else
+#define FACTORS_PER_LIMB (GMP_NUMB_BITS / (LOG2C(FAC_ODD_THRESHOLD)+1))
+#endif
+
+/* Computes n!, the factorial of n.
+   WARNING: it assumes that n fits in a limb!
+ */
+void
+mpz_fac_ui (mpz_ptr x, unsigned long n)
+{
+  static const mp_limb_t table[] = { ONE_LIMB_FACTORIAL_TABLE };
+
+  ASSERT (n <= GMP_NUMB_MAX);
+
+  if (n < numberof (table))
+    {
+      MPZ_NEWALLOC (x, 1)[0] = table[n];
+      SIZ (x) = 1;
+    }
+  else if (BELOW_THRESHOLD (n, FAC_ODD_THRESHOLD))
+    {
+      mp_limb_t prod, max_prod;
+      mp_size_t j;
+      mp_ptr    factors;
+      TMP_SDECL;
+
+      TMP_SMARK;
+      factors = TMP_SALLOC_LIMBS (2 + (n - numberof (table)) / FACTORS_PER_LIMB);
+
+      factors[0] = table[numberof (table)-1];
+      j = 1;
+      prod = n;
+#if TUNE_PROGRAM_BUILD
+      max_prod = GMP_NUMB_MAX / FAC_DSC_THRESHOLD_LIMIT;
+#else
+      max_prod = GMP_NUMB_MAX / (FAC_ODD_THRESHOLD | 1);
+#endif
+      while (--n >= numberof (table))
+	FACTOR_LIST_STORE (n, prod, max_prod, factors, j);
+
+      factors[j++] = prod;
+      mpz_prodlimbs (x, factors, j);
+
+      TMP_SFREE;
+    }
+  else
+    {
+      mp_limb_t count;
+      mpz_oddfac_1 (x, n, 0);
+      if (n <= TABLE_LIMIT_2N_MINUS_POPC_2N)
+	count = __gmp_fac2cnt_table[n / 2 - 1];
+      else
+	{
+	  popc_limb (count, n);
+	  count = n - count;
+	}
+      mpz_mul_2exp (x, x, count);
+    }
+}
+
+#undef FACTORS_PER_LIMB
+#undef FACTOR_LIST_STORE
diff --git a/third_party/gmp/mpz/fdiv_q.c b/third_party/gmp/mpz/fdiv_q.c
new file mode 100644
index 0000000..f17023e
--- /dev/null
+++ b/third_party/gmp/mpz/fdiv_q.c
@@ -0,0 +1,52 @@
+/* mpz_fdiv_q -- Division rounding the quotient towards -infinity.
+   The remainder gets the same sign as the denominator.
+
+Copyright 1994-1996, 2000, 2001, 2005, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_fdiv_q (mpz_ptr quot, mpz_srcptr dividend, mpz_srcptr divisor)
+{
+  mp_size_t dividend_size = SIZ (dividend);
+  mp_size_t divisor_size = SIZ (divisor);
+  mpz_t rem;
+  TMP_DECL;
+
+  TMP_MARK;
+
+  MPZ_TMP_INIT (rem, ABS (divisor_size));
+
+  mpz_tdiv_qr (quot, rem, dividend, divisor);
+
+  if ((divisor_size ^ dividend_size) < 0 && SIZ (rem) != 0)
+    mpz_sub_ui (quot, quot, 1L);
+
+  TMP_FREE;
+}
diff --git a/third_party/gmp/mpz/fdiv_q_ui.c b/third_party/gmp/mpz/fdiv_q_ui.c
new file mode 100644
index 0000000..539f951
--- /dev/null
+++ b/third_party/gmp/mpz/fdiv_q_ui.c
@@ -0,0 +1,100 @@
+/* mpz_fdiv_q_ui -- Division rounding the quotient towards -infinity.
+   The remainder gets the same sign as the denominator.
+
+Copyright 1994-1996, 1999, 2001, 2002, 2004, 2012 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+unsigned long int
+mpz_fdiv_q_ui (mpz_ptr quot, mpz_srcptr dividend, unsigned long int divisor)
+{
+  mp_size_t ns, nn, qn;
+  mp_ptr np, qp;
+  mp_limb_t rl;
+
+  if (UNLIKELY (divisor == 0))
+    DIVIDE_BY_ZERO;
+
+  ns = SIZ(dividend);
+  if (ns == 0)
+    {
+      SIZ(quot) = 0;
+      return 0;
+    }
+
+  nn = ABS(ns);
+  qp = MPZ_REALLOC (quot, nn);
+  np = PTR(dividend);
+
+#if BITS_PER_ULONG > GMP_NUMB_BITS  /* avoid warnings about shift amount */
+  if (divisor > GMP_NUMB_MAX)
+    {
+      mp_limb_t dp[2], rp[2];
+
+      if (nn == 1)		/* tdiv_qr requirements; tested above for 0 */
+	{
+	  qp[0] = 0;
+	  rl = np[0];
+	  qn = 1;		/* a white lie, fixed below */
+	}
+      else
+	{
+	  dp[0] = divisor & GMP_NUMB_MASK;
+	  dp[1] = divisor >> GMP_NUMB_BITS;
+	  mpn_tdiv_qr (qp, rp, (mp_size_t) 0, np, nn, dp, (mp_size_t) 2);
+	  rl = rp[0] + (rp[1] << GMP_NUMB_BITS);
+	  qn = nn - 2 + 1;
+	}
+
+      if (rl != 0 && ns < 0)
+	{
+	  mpn_incr_u (qp, (mp_limb_t) 1);
+	  rl = divisor - rl;
+	}
+
+      qn -= qp[qn - 1] == 0; qn -= qn != 0 && qp[qn - 1] == 0;
+    }
+  else
+#endif
+    {
+      rl = mpn_divrem_1 (qp, (mp_size_t) 0, np, nn, (mp_limb_t) divisor);
+
+      if (rl != 0 && ns < 0)
+	{
+	  mpn_incr_u (qp, (mp_limb_t) 1);
+	  rl = divisor - rl;
+	}
+
+      qn = nn - (qp[nn - 1] == 0);
+    }
+
+  SIZ(quot) = ns >= 0 ? qn : -qn;
+  return rl;
+}
diff --git a/third_party/gmp/mpz/fdiv_qr.c b/third_party/gmp/mpz/fdiv_qr.c
new file mode 100644
index 0000000..a0a6166
--- /dev/null
+++ b/third_party/gmp/mpz/fdiv_qr.c
@@ -0,0 +1,64 @@
+/* mpz_fdiv_qr -- Division rounding the quotient towards -infinity.
+   The remainder gets the same sign as the denominator.
+
+Copyright 1994-1996, 2000, 2001, 2005, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_fdiv_qr (mpz_ptr quot, mpz_ptr rem, mpz_srcptr dividend, mpz_srcptr divisor)
+{
+  mp_size_t divisor_size = SIZ (divisor);
+  mp_size_t xsize;
+  mpz_t temp_divisor;		/* N.B.: lives until function returns! */
+  TMP_DECL;
+
+  TMP_MARK;
+
+  /* We need the original value of the divisor after the quotient and
+     remainder have been preliminary calculated.  We have to copy it to
+     temporary space if it's the same variable as either QUOT or REM.  */
+  if (quot == divisor || rem == divisor)
+    {
+      MPZ_TMP_INIT (temp_divisor, ABS (divisor_size));
+      mpz_set (temp_divisor, divisor);
+      divisor = temp_divisor;
+    }
+
+  xsize = SIZ (dividend) ^ divisor_size;;
+  mpz_tdiv_qr (quot, rem, dividend, divisor);
+
+  if (xsize < 0 && SIZ (rem) != 0)
+    {
+      mpz_sub_ui (quot, quot, 1L);
+      mpz_add (rem, rem, divisor);
+    }
+
+  TMP_FREE;
+}
diff --git a/third_party/gmp/mpz/fdiv_qr_ui.c b/third_party/gmp/mpz/fdiv_qr_ui.c
new file mode 100644
index 0000000..984ca1c
--- /dev/null
+++ b/third_party/gmp/mpz/fdiv_qr_ui.c
@@ -0,0 +1,116 @@
+/* mpz_fdiv_qr_ui -- Division rounding the quotient towards -infinity.
+   The remainder gets the same sign as the denominator.
+
+Copyright 1994-1996, 1999, 2001, 2002, 2004, 2012, 2015 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+unsigned long int
+mpz_fdiv_qr_ui (mpz_ptr quot, mpz_ptr rem, mpz_srcptr dividend, unsigned long int divisor)
+{
+  mp_size_t ns, nn, qn;
+  mp_ptr np, qp;
+  mp_limb_t rl;
+
+  if (UNLIKELY (divisor == 0))
+    DIVIDE_BY_ZERO;
+
+  ns = SIZ(dividend);
+  if (ns == 0)
+    {
+      SIZ(quot) = 0;
+      SIZ(rem) = 0;
+      return 0;
+    }
+
+  nn = ABS(ns);
+  qp = MPZ_REALLOC (quot, nn);
+  np = PTR(dividend);
+
+#if BITS_PER_ULONG > GMP_NUMB_BITS  /* avoid warnings about shift amount */
+  if (divisor > GMP_NUMB_MAX)
+    {
+      mp_limb_t dp[2];
+      mp_ptr rp;
+      mp_size_t rn;
+
+      rp = MPZ_REALLOC (rem, 2);
+
+      if (nn == 1)		/* tdiv_qr requirements; tested above for 0 */
+	{
+	  qp[0] = 0;
+	  qn = 1;		/* a white lie, fixed below */
+	  rl = np[0];
+	  rp[0] = rl;
+	}
+      else
+	{
+	  dp[0] = divisor & GMP_NUMB_MASK;
+	  dp[1] = divisor >> GMP_NUMB_BITS;
+	  mpn_tdiv_qr (qp, rp, (mp_size_t) 0, np, nn, dp, (mp_size_t) 2);
+	  rl = rp[0] + (rp[1] << GMP_NUMB_BITS);
+	  qn = nn - 2 + 1;
+	}
+
+      if (rl != 0 && ns < 0)
+	{
+	  mpn_incr_u (qp, (mp_limb_t) 1);
+	  rl = divisor - rl;
+	  rp[0] = rl & GMP_NUMB_MASK;
+	  rp[1] = rl >> GMP_NUMB_BITS;
+	}
+
+      qn -= qp[qn - 1] == 0; qn -= qn != 0 && qp[qn - 1] == 0;
+      rn = 1 + (rl > GMP_NUMB_MAX);  rn -= (rp[rn - 1] == 0);
+      SIZ(rem) = rn;
+    }
+  else
+#endif
+    {
+      rl = mpn_divrem_1 (qp, (mp_size_t) 0, np, nn, (mp_limb_t) divisor);
+      if (rl == 0)
+	SIZ(rem) = 0;
+      else
+	{
+	  if (ns < 0)
+	    {
+	      mpn_incr_u (qp, (mp_limb_t) 1);
+	      rl = divisor - rl;
+	    }
+
+	  MPZ_NEWALLOC (rem, 1)[0] = rl;
+	  SIZ(rem) = rl != 0;
+	}
+      qn = nn - (qp[nn - 1] == 0);
+    }
+
+  SIZ(quot) = ns >= 0 ? qn : -qn;
+  return rl;
+}
diff --git a/third_party/gmp/mpz/fdiv_r.c b/third_party/gmp/mpz/fdiv_r.c
new file mode 100644
index 0000000..c7a3c8e
--- /dev/null
+++ b/third_party/gmp/mpz/fdiv_r.c
@@ -0,0 +1,59 @@
+/* mpz_fdiv_r -- Division rounding the quotient towards -infinity.
+   The remainder gets the same sign as the denominator.
+
+Copyright 1994-1996, 2001, 2005, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_fdiv_r (mpz_ptr rem, mpz_srcptr dividend, mpz_srcptr divisor)
+{
+  mp_size_t divisor_size = SIZ (divisor);
+  mpz_t temp_divisor;		/* N.B.: lives until function returns! */
+  TMP_DECL;
+
+  TMP_MARK;
+
+  /* We need the original value of the divisor after the remainder has been
+     preliminary calculated.  We have to copy it to temporary space if it's
+     the same variable as REM.  */
+  if (rem == divisor)
+    {
+      MPZ_TMP_INIT (temp_divisor, ABS (divisor_size));
+      mpz_set (temp_divisor, divisor);
+      divisor = temp_divisor;
+    }
+
+  mpz_tdiv_r (rem, dividend, divisor);
+
+  if ((divisor_size ^ SIZ (dividend)) < 0 && SIZ (rem) != 0)
+    mpz_add (rem, rem, divisor);
+
+  TMP_FREE;
+}
diff --git a/third_party/gmp/mpz/fdiv_r_ui.c b/third_party/gmp/mpz/fdiv_r_ui.c
new file mode 100644
index 0000000..f2df8a8
--- /dev/null
+++ b/third_party/gmp/mpz/fdiv_r_ui.c
@@ -0,0 +1,107 @@
+/* mpz_fdiv_r_ui -- Division rounding the quotient towards -infinity.
+   The remainder gets the same sign as the denominator.
+
+Copyright 1994-1996, 2001, 2002, 2004, 2005, 2012, 2015 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+unsigned long int
+mpz_fdiv_r_ui (mpz_ptr rem, mpz_srcptr dividend, unsigned long int divisor)
+{
+  mp_size_t ns, nn;
+  mp_ptr np;
+  mp_limb_t rl;
+
+  if (UNLIKELY (divisor == 0))
+    DIVIDE_BY_ZERO;
+
+  ns = SIZ(dividend);
+  if (ns == 0)
+    {
+      SIZ(rem) = 0;
+      return 0;
+    }
+
+  nn = ABS(ns);
+  np = PTR(dividend);
+#if BITS_PER_ULONG > GMP_NUMB_BITS  /* avoid warnings about shift amount */
+  if (divisor > GMP_NUMB_MAX)
+    {
+      mp_limb_t dp[2];
+      mp_ptr rp, qp;
+      mp_size_t rn;
+      TMP_DECL;
+
+      rp = MPZ_REALLOC (rem, 2);
+
+      if (nn == 1)		/* tdiv_qr requirements; tested above for 0 */
+	{
+	  rl = np[0];
+	  rp[0] = rl;
+	}
+      else
+	{
+	  TMP_MARK;
+	  dp[0] = divisor & GMP_NUMB_MASK;
+	  dp[1] = divisor >> GMP_NUMB_BITS;
+	  qp = TMP_ALLOC_LIMBS (nn - 2 + 1);
+	  mpn_tdiv_qr (qp, rp, (mp_size_t) 0, np, nn, dp, (mp_size_t) 2);
+	  TMP_FREE;
+	  rl = rp[0] + (rp[1] << GMP_NUMB_BITS);
+	}
+
+      if (rl != 0 && ns < 0)
+	{
+	  rl = divisor - rl;
+	  rp[0] = rl & GMP_NUMB_MASK;
+	  rp[1] = rl >> GMP_NUMB_BITS;
+	}
+
+      rn = 1 + (rl > GMP_NUMB_MAX);  rn -= (rp[rn - 1] == 0);
+      SIZ(rem) = rn;
+    }
+  else
+#endif
+    {
+      rl = mpn_mod_1 (np, nn, (mp_limb_t) divisor);
+      if (rl == 0)
+	SIZ(rem) = 0;
+      else
+	{
+	  if (ns < 0)
+	    rl = divisor - rl;
+
+	  MPZ_NEWALLOC (rem, 1)[0] = rl;
+	  SIZ(rem) = 1;
+	}
+    }
+
+  return rl;
+}
diff --git a/third_party/gmp/mpz/fdiv_ui.c b/third_party/gmp/mpz/fdiv_ui.c
new file mode 100644
index 0000000..f0aacdb
--- /dev/null
+++ b/third_party/gmp/mpz/fdiv_ui.c
@@ -0,0 +1,100 @@
+/* mpz_fdiv_ui -- Division rounding the quotient towards -infinity.
+   The remainder gets the same sign as the denominator.
+
+Copyright 1994-1996, 2001, 2002, 2004, 2005, 2012 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+unsigned long int
+mpz_fdiv_ui (mpz_srcptr dividend, unsigned long int divisor)
+{
+  mp_size_t ns, nn;
+  mp_ptr np;
+  mp_limb_t rl;
+
+  if (UNLIKELY (divisor == 0))
+    DIVIDE_BY_ZERO;
+
+  ns = SIZ(dividend);
+  if (ns == 0)
+    {
+      return 0;
+    }
+
+  nn = ABS(ns);
+  np = PTR(dividend);
+#if BITS_PER_ULONG > GMP_NUMB_BITS  /* avoid warnings about shift amount */
+  if (divisor > GMP_NUMB_MAX)
+    {
+      mp_limb_t dp[2], rp[2];
+      mp_ptr qp;
+      mp_size_t rn;
+      TMP_DECL;
+
+      if (nn == 1)		/* tdiv_qr requirements; tested above for 0 */
+	{
+	  rl = np[0];
+	  rp[0] = rl;
+	}
+      else
+	{
+	  TMP_MARK;
+	  dp[0] = divisor & GMP_NUMB_MASK;
+	  dp[1] = divisor >> GMP_NUMB_BITS;
+	  qp = TMP_ALLOC_LIMBS (nn - 2 + 1);
+	  mpn_tdiv_qr (qp, rp, (mp_size_t) 0, np, nn, dp, (mp_size_t) 2);
+	  TMP_FREE;
+	  rl = rp[0] + (rp[1] << GMP_NUMB_BITS);
+	}
+
+      if (rl != 0 && ns < 0)
+	{
+	  rl = divisor - rl;
+	  rp[0] = rl & GMP_NUMB_MASK;
+	  rp[1] = rl >> GMP_NUMB_BITS;
+	}
+
+      rn = 1 + (rl > GMP_NUMB_MAX);  rn -= (rp[rn - 1] == 0);
+    }
+  else
+#endif
+    {
+      rl = mpn_mod_1 (np, nn, (mp_limb_t) divisor);
+      if (rl == 0)
+	;
+      else
+	{
+	  if (ns < 0)
+	    rl = divisor - rl;
+	}
+    }
+
+  return rl;
+}
diff --git a/third_party/gmp/mpz/fib2_ui.c b/third_party/gmp/mpz/fib2_ui.c
new file mode 100644
index 0000000..ea26227
--- /dev/null
+++ b/third_party/gmp/mpz/fib2_ui.c
@@ -0,0 +1,58 @@
+/* mpz_fib2_ui -- calculate Fibonacci numbers.
+
+Copyright 2001, 2012, 2014, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp-impl.h"
+
+
+void
+mpz_fib2_ui (mpz_ptr fn, mpz_ptr fnsub1, unsigned long n)
+{
+  mp_ptr     fp, f1p;
+  mp_size_t  size;
+
+  if (n <= FIB_TABLE_LIMIT)
+    {
+      MPZ_NEWALLOC (fn, 1)[0] = FIB_TABLE (n);
+      SIZ(fn) = (n != 0);      /* F[0]==0, others are !=0 */
+      MPZ_NEWALLOC (fnsub1, 1)[0] = FIB_TABLE ((int) n - 1);
+      SIZ(fnsub1) = (n != 1);  /* F[1-1]==0, others are !=0 */
+      return;
+    }
+
+  size = MPN_FIB2_SIZE (n);
+  fp =  MPZ_NEWALLOC (fn,     size);
+  f1p = MPZ_NEWALLOC (fnsub1, size);
+
+  size = mpn_fib2_ui (fp, f1p, n);
+
+  SIZ(fn)     = size;
+  SIZ(fnsub1) = size - (f1p[size-1] == 0);
+}
diff --git a/third_party/gmp/mpz/fib_ui.c b/third_party/gmp/mpz/fib_ui.c
new file mode 100644
index 0000000..a65f3c9
--- /dev/null
+++ b/third_party/gmp/mpz/fib_ui.c
@@ -0,0 +1,158 @@
+/* mpz_fib_ui -- calculate Fibonacci numbers.
+
+Copyright 2000-2002, 2005, 2012, 2014, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* change to "#define TRACE(x) x" to get some traces */
+#define TRACE(x)
+
+
+/* In the F[2k+1] below for k odd, the -2 won't give a borrow from the low
+   limb because the result F[2k+1] is an F[4m+3] and such numbers are always
+   == 1, 2 or 5 mod 8, whereas an underflow would leave 6 or 7.  (This is
+   the same as in mpn_fib2_ui.)
+
+   In the F[2k+1] for k even, the +2 won't give a carry out of the low limb
+   in normal circumstances.  This is an F[4m+1] and we claim that F[3*2^b+1]
+   == 1 mod 2^b is the first F[4m+1] congruent to 0 or 1 mod 2^b, and hence
+   if n < 2^GMP_NUMB_BITS then F[n] cannot have a low limb of 0 or 1.  No
+   proof for this claim, but it's been verified up to b==32 and has such a
+   nice pattern it must be true :-).  Of interest is that F[3*2^b] == 0 mod
+   2^(b+1) seems to hold too.
+
+   When n >= 2^GMP_NUMB_BITS, which can arise in a nails build, then the low
+   limb of F[4m+1] can certainly be 1, and an mpn_add_1 must be used.  */
+
+void
+mpz_fib_ui (mpz_ptr fn, unsigned long n)
+{
+  mp_ptr         fp, xp, yp;
+  mp_size_t      size, xalloc;
+  unsigned long  n2;
+  mp_limb_t      c;
+  TMP_DECL;
+
+  if (n <= FIB_TABLE_LIMIT)
+    {
+      MPZ_NEWALLOC (fn, 1)[0] = FIB_TABLE (n);
+      SIZ(fn) = (n != 0);      /* F[0]==0, others are !=0 */
+      return;
+    }
+
+  n2 = n/2;
+  xalloc = MPN_FIB2_SIZE (n2) + 1;
+  fp = MPZ_NEWALLOC (fn, 2 * xalloc);
+
+  TMP_MARK;
+  TMP_ALLOC_LIMBS_2 (xp,xalloc, yp,xalloc);
+  size = mpn_fib2_ui (xp, yp, n2);
+
+  TRACE (printf ("mpz_fib_ui last step n=%lu size=%ld bit=%lu\n",
+		 n >> 1, size, n&1);
+	 mpn_trace ("xp", xp, size);
+	 mpn_trace ("yp", yp, size));
+
+  if (n & 1)
+    {
+      /* F[2k+1] = (2F[k]+F[k-1])*(2F[k]-F[k-1]) + 2*(-1)^k  */
+      mp_size_t  xsize, ysize;
+
+#if HAVE_NATIVE_mpn_add_n_sub_n
+      xp[size] = mpn_lshift (xp, xp, size, 1);
+      yp[size] = 0;
+      ASSERT_NOCARRY (mpn_add_n_sub_n (xp, yp, xp, yp, size+1));
+      xsize = size + (xp[size] != 0);
+      ASSERT (yp[size] <= 1);
+      ysize = size + yp[size];
+#else
+      mp_limb_t  c2;
+
+      c2 = mpn_lshift (fp, xp, size, 1);
+      c = c2 + mpn_add_n (xp, fp, yp, size);
+      xp[size] = c;
+      xsize = size + (c != 0);
+      c2 -= mpn_sub_n (yp, fp, yp, size);
+      yp[size] = c2;
+      ASSERT (c2 <= 1);
+      ysize = size + c2;
+#endif
+
+      size = xsize + ysize;
+      c = mpn_mul (fp, xp, xsize, yp, ysize);
+
+#if GMP_NUMB_BITS >= BITS_PER_ULONG
+      /* no overflow, see comments above */
+      ASSERT (n & 2 ? fp[0] >= 2 : fp[0] <= GMP_NUMB_MAX-2);
+      fp[0] += (n & 2 ? -CNST_LIMB(2) : CNST_LIMB(2));
+#else
+      if (n & 2)
+	{
+	  ASSERT (fp[0] >= 2);
+	  fp[0] -= 2;
+	}
+      else
+	{
+	  ASSERT (c != GMP_NUMB_MAX); /* because it's the high of a mul */
+	  c += mpn_add_1 (fp, fp, size-1, CNST_LIMB(2));
+	  fp[size-1] = c;
+	}
+#endif
+    }
+  else
+    {
+      /* F[2k] = F[k]*(F[k]+2F[k-1]) */
+
+      mp_size_t  xsize, ysize;
+#if HAVE_NATIVE_mpn_addlsh1_n
+      c = mpn_addlsh1_n (yp, xp, yp, size);
+#else
+      c = mpn_lshift (yp, yp, size, 1);
+      c += mpn_add_n (yp, yp, xp, size);
+#endif
+      yp[size] = c;
+      xsize = size;
+      ysize = size + (c != 0);
+      size += ysize;
+      c = mpn_mul (fp, yp, ysize, xp, xsize);
+    }
+
+  /* one or two high zeros */
+  size -= (c == 0);
+  size -= (fp[size-1] == 0);
+  SIZ(fn) = size;
+
+  TRACE (printf ("done special, size=%ld\n", size);
+	 mpn_trace ("fp ", fp, size));
+
+  TMP_FREE;
+}
diff --git a/third_party/gmp/mpz/fits_s.h b/third_party/gmp/mpz/fits_s.h
new file mode 100644
index 0000000..9fd6a0b
--- /dev/null
+++ b/third_party/gmp/mpz/fits_s.h
@@ -0,0 +1,60 @@
+/* int mpz_fits_X_p (mpz_t z) -- test whether z fits signed type X.
+
+Copyright 1997, 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+int
+FUNCTION (mpz_srcptr z) __GMP_NOTHROW
+{
+  mp_size_t n = SIZ(z);
+  mp_ptr p = PTR(z);
+  mp_limb_t limb = p[0];
+
+  if (n == 0)
+    return 1;
+  if (n == 1)
+    return limb <= MAXIMUM;
+  if (n == -1)
+    return limb <= NEG_CAST (mp_limb_t, MINIMUM);
+#if GMP_NAIL_BITS != 0
+  {
+    if ((p[1] >> GMP_NAIL_BITS) == 0)
+      {
+	limb += p[1] << GMP_NUMB_BITS;
+	if (n == 2)
+	  return limb <= MAXIMUM;
+	if (n == -2)
+	  return limb <= NEG_CAST (mp_limb_t, MINIMUM);
+      }
+  }
+#endif
+  return 0;
+}
diff --git a/third_party/gmp/mpz/fits_sint.c b/third_party/gmp/mpz/fits_sint.c
new file mode 100644
index 0000000..d548c45
--- /dev/null
+++ b/third_party/gmp/mpz/fits_sint.c
@@ -0,0 +1,36 @@
+/* int mpz_fits_sint_p (mpz_t z) -- test whether z fits an int.
+
+Copyright 1997, 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#define FUNCTION  mpz_fits_sint_p
+#define MAXIMUM   INT_MAX
+#define MINIMUM   INT_MIN
+
+#include "fits_s.h"
diff --git a/third_party/gmp/mpz/fits_slong.c b/third_party/gmp/mpz/fits_slong.c
new file mode 100644
index 0000000..9306a00
--- /dev/null
+++ b/third_party/gmp/mpz/fits_slong.c
@@ -0,0 +1,36 @@
+/* int mpz_fits_slong_p (mpz_t z) -- test whether z fits a long.
+
+Copyright 1997, 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#define FUNCTION  mpz_fits_slong_p
+#define MAXIMUM   LONG_MAX
+#define MINIMUM   LONG_MIN
+
+#include "fits_s.h"
diff --git a/third_party/gmp/mpz/fits_sshort.c b/third_party/gmp/mpz/fits_sshort.c
new file mode 100644
index 0000000..431d6b0
--- /dev/null
+++ b/third_party/gmp/mpz/fits_sshort.c
@@ -0,0 +1,36 @@
+/* int mpz_fits_sshort_p (mpz_t z) -- test whether z fits a short.
+
+Copyright 1997, 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#define FUNCTION  mpz_fits_sshort_p
+#define MAXIMUM   SHRT_MAX
+#define MINIMUM   SHRT_MIN
+
+#include "fits_s.h"
diff --git a/third_party/gmp/mpz/fits_uint.c b/third_party/gmp/mpz/fits_uint.c
new file mode 100644
index 0000000..6becc8b
--- /dev/null
+++ b/third_party/gmp/mpz/fits_uint.c
@@ -0,0 +1,33 @@
+/* mpz_fits_uint_p -- test whether z fits an unsigned int.
+
+Copyright 1997, 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define __GMP_FORCE_mpz_fits_uint_p 1
+
+#include "gmp-impl.h"
diff --git a/third_party/gmp/mpz/fits_ulong.c b/third_party/gmp/mpz/fits_ulong.c
new file mode 100644
index 0000000..c70886b
--- /dev/null
+++ b/third_party/gmp/mpz/fits_ulong.c
@@ -0,0 +1,33 @@
+/* mpz_fits_ulong_p -- test whether z fits an unsigned long.
+
+Copyright 1997, 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define __GMP_FORCE_mpz_fits_ulong_p 1
+
+#include "gmp-impl.h"
diff --git a/third_party/gmp/mpz/fits_ushort.c b/third_party/gmp/mpz/fits_ushort.c
new file mode 100644
index 0000000..16873d6
--- /dev/null
+++ b/third_party/gmp/mpz/fits_ushort.c
@@ -0,0 +1,33 @@
+/* mpz_fits_ushort_p -- test whether z fits an unsigned short.
+
+Copyright 1997, 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define __GMP_FORCE_mpz_fits_ushort_p 1
+
+#include "gmp-impl.h"
diff --git a/third_party/gmp/mpz/gcd.c b/third_party/gmp/mpz/gcd.c
new file mode 100644
index 0000000..9557155
--- /dev/null
+++ b/third_party/gmp/mpz/gcd.c
@@ -0,0 +1,164 @@
+/* mpz/gcd.c:   Calculate the greatest common divisor of two integers.
+
+Copyright 1991, 1993, 1994, 1996, 2000-2002, 2005, 2010, 2015, 2016
+Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+void
+mpz_gcd (mpz_ptr g, mpz_srcptr u, mpz_srcptr v)
+{
+  unsigned long int g_zero_bits, u_zero_bits, v_zero_bits;
+  mp_size_t g_zero_limbs, u_zero_limbs, v_zero_limbs;
+  mp_ptr tp;
+  mp_ptr up;
+  mp_size_t usize;
+  mp_ptr vp;
+  mp_size_t vsize;
+  mp_size_t gsize;
+  TMP_DECL;
+
+  up = PTR(u);
+  usize = ABSIZ (u);
+  vp = PTR(v);
+  vsize = ABSIZ (v);
+  /* GCD(0, V) == V.  */
+  if (usize == 0)
+    {
+      SIZ (g) = vsize;
+      if (g == v)
+	return;
+      tp = MPZ_NEWALLOC (g, vsize);
+      MPN_COPY (tp, vp, vsize);
+      return;
+    }
+
+  /* GCD(U, 0) == U.  */
+  if (vsize == 0)
+    {
+      SIZ (g) = usize;
+      if (g == u)
+	return;
+      tp = MPZ_NEWALLOC (g, usize);
+      MPN_COPY (tp, up, usize);
+      return;
+    }
+
+  if (usize == 1)
+    {
+      SIZ (g) = 1;
+      MPZ_NEWALLOC (g, 1)[0] = mpn_gcd_1 (vp, vsize, up[0]);
+      return;
+    }
+
+  if (vsize == 1)
+    {
+      SIZ(g) = 1;
+      MPZ_NEWALLOC (g, 1)[0] = mpn_gcd_1 (up, usize, vp[0]);
+      return;
+    }
+
+  TMP_MARK;
+
+  /*  Eliminate low zero bits from U and V and move to temporary storage.  */
+  tp = up;
+  while (*tp == 0)
+    tp++;
+  u_zero_limbs = tp - up;
+  usize -= u_zero_limbs;
+  count_trailing_zeros (u_zero_bits, *tp);
+  up = TMP_ALLOC_LIMBS (usize);
+  if (u_zero_bits != 0)
+    {
+      mpn_rshift (up, tp, usize, u_zero_bits);
+      usize -= up[usize - 1] == 0;
+    }
+  else
+    MPN_COPY (up, tp, usize);
+
+  tp = vp;
+  while (*tp == 0)
+    tp++;
+  v_zero_limbs = tp - vp;
+  vsize -= v_zero_limbs;
+  count_trailing_zeros (v_zero_bits, *tp);
+  vp = TMP_ALLOC_LIMBS (vsize);
+  if (v_zero_bits != 0)
+    {
+      mpn_rshift (vp, tp, vsize, v_zero_bits);
+      vsize -= vp[vsize - 1] == 0;
+    }
+  else
+    MPN_COPY (vp, tp, vsize);
+
+  if (u_zero_limbs > v_zero_limbs)
+    {
+      g_zero_limbs = v_zero_limbs;
+      g_zero_bits = v_zero_bits;
+    }
+  else
+    {
+      g_zero_limbs = u_zero_limbs;
+      if (u_zero_limbs < v_zero_limbs)
+	g_zero_bits = u_zero_bits;
+      else  /*  Equal.  */
+	g_zero_bits = MIN (u_zero_bits, v_zero_bits);
+    }
+
+  /*  Call mpn_gcd.  The 2nd argument must not have more bits than the 1st.  */
+  vsize = (usize < vsize || (usize == vsize && up[usize-1] < vp[vsize-1]))
+    ? mpn_gcd (vp, vp, vsize, up, usize)
+    : mpn_gcd (vp, up, usize, vp, vsize);
+
+  /*  Here G <-- V << (g_zero_limbs*GMP_LIMB_BITS + g_zero_bits).  */
+  gsize = vsize + g_zero_limbs;
+  if (g_zero_bits != 0)
+    {
+      mp_limb_t cy_limb;
+      gsize += (vp[vsize - 1] >> (GMP_NUMB_BITS - g_zero_bits)) != 0;
+      tp = MPZ_NEWALLOC (g, gsize);
+      MPN_ZERO (tp, g_zero_limbs);
+
+      tp = tp + g_zero_limbs;
+      cy_limb = mpn_lshift (tp, vp, vsize, g_zero_bits);
+      if (cy_limb != 0)
+	tp[vsize] = cy_limb;
+    }
+  else
+    {
+      tp = MPZ_NEWALLOC (g, gsize);
+      MPN_ZERO (tp, g_zero_limbs);
+      MPN_COPY (tp + g_zero_limbs, vp, vsize);
+    }
+
+  SIZ (g) = gsize;
+  TMP_FREE;
+}
diff --git a/third_party/gmp/mpz/gcd_ui.c b/third_party/gmp/mpz/gcd_ui.c
new file mode 100644
index 0000000..ee5bff8
--- /dev/null
+++ b/third_party/gmp/mpz/gcd_ui.c
@@ -0,0 +1,84 @@
+/* mpz_gcd_ui -- Calculate the greatest common divisor of two integers.
+
+Copyright 1994, 1996, 1999-2004, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h> /* for NULL */
+#include "gmp-impl.h"
+
+unsigned long int
+mpz_gcd_ui (mpz_ptr w, mpz_srcptr u, unsigned long int v)
+{
+  mp_size_t un;
+  mp_limb_t res;
+
+#if BITS_PER_ULONG > GMP_NUMB_BITS  /* avoid warnings about shift amount */
+  if (v > GMP_NUMB_MAX)
+    {
+      mpz_t vz;
+      mp_limb_t vlimbs[2];
+      vlimbs[0] = v & GMP_NUMB_MASK;
+      vlimbs[1] = v >> GMP_NUMB_BITS;
+      PTR(vz) = vlimbs;
+      SIZ(vz) = 2;
+      mpz_gcd (w, u, vz);
+      /* because v!=0 we will have w<=v hence fitting a ulong */
+      ASSERT (mpz_fits_ulong_p (w));
+      return mpz_get_ui (w);
+    }
+#endif
+
+  un = ABSIZ(u);
+
+  if (un == 0)
+    res = v;
+  else if (v == 0)
+    {
+      if (w != NULL)
+	{
+	  if (u != w)
+	    {
+	      MPZ_NEWALLOC (w, un);
+	      MPN_COPY (PTR(w), PTR(u), un);
+	    }
+	  SIZ(w) = un;
+	}
+      /* Return u if it fits a ulong, otherwise 0. */
+      res = PTR(u)[0];
+      return (un == 1 && res <= ULONG_MAX ? res : 0);
+    }
+  else
+    res = mpn_gcd_1 (PTR(u), un, (mp_limb_t) v);
+
+  if (w != NULL)
+    {
+      MPZ_NEWALLOC (w, 1)[0] = res;
+      SIZ(w) = res != 0;
+    }
+  return res;
+}
diff --git a/third_party/gmp/mpz/gcdext.c b/third_party/gmp/mpz/gcdext.c
new file mode 100644
index 0000000..b1f73c2
--- /dev/null
+++ b/third_party/gmp/mpz/gcdext.c
@@ -0,0 +1,135 @@
+/* mpz_gcdext(g, s, t, a, b) -- Set G to gcd(a, b), and S and T such that
+   g = as + bt.
+
+Copyright 1991, 1993-1997, 2000, 2001, 2005, 2011, 2012, 2015 Free
+Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h> /* for NULL */
+#include "gmp-impl.h"
+
+void
+mpz_gcdext (mpz_ptr g, mpz_ptr s, mpz_ptr t, mpz_srcptr a, mpz_srcptr b)
+{
+  mp_size_t asize, bsize;
+  mp_ptr tmp_ap, tmp_bp;
+  mp_size_t gsize, ssize, tmp_ssize;
+  mp_ptr gp, tmp_gp, tmp_sp;
+  TMP_DECL;
+
+  /* mpn_gcdext requires that Usize >= Vsize.  Therefore, we often
+     have to swap U and V.  The computed cofactor will be the
+     "smallest" one, which is faster to produce.  The wanted one will
+     be computed here; this is needed anyway when both are requested.  */
+
+  asize = ABSIZ (a);
+  bsize = ABSIZ (b);
+
+  ASSERT (s != NULL);
+
+  if (asize < bsize)
+    {
+      MPZ_SRCPTR_SWAP (a, b);
+      MP_SIZE_T_SWAP (asize, bsize);
+      MPZ_PTR_SWAP (s, t);
+    }
+
+  if (bsize == 0)
+    {
+      /* g = |a|, s = sgn(a), t = 0. */
+      ssize = SIZ (a) >= 0 ? (asize != 0) : -1;
+
+      if (g != NULL)
+	{
+	  /* If g == a, then ALLOC(g) == ALLOC(a) >= asize, i.e.
+	     the next MPZ_NEWALLOC returns the old PTR(a) .*/
+	  gp = MPZ_NEWALLOC (g, asize);
+	  MPN_COPY (gp, PTR (a), asize);
+	  SIZ (g) = asize;
+	}
+      if (t != NULL)
+	SIZ (t) = 0;
+      if (s != NULL)
+	{
+	  SIZ (s) = ssize;
+	  MPZ_NEWALLOC (s, 1)[0] = 1;
+	}
+      return;
+    }
+
+  TMP_MARK;
+
+  TMP_ALLOC_LIMBS_2 (tmp_gp, bsize, tmp_sp, asize + bsize + bsize + 1);
+  tmp_bp = tmp_sp + bsize + 1;
+  tmp_ap = tmp_bp + bsize;
+  MPN_COPY (tmp_ap, PTR (a), asize);
+  MPN_COPY (tmp_bp, PTR (b), bsize);
+
+  gsize = mpn_gcdext (tmp_gp, tmp_sp, &tmp_ssize, tmp_ap, asize, tmp_bp, bsize);
+
+  ssize = ABS (tmp_ssize);
+  tmp_ssize = SIZ (a) >= 0 ? tmp_ssize : -tmp_ssize;
+
+  if (t != NULL)
+    {
+      mpz_t x;
+      mpz_t gtmp, stmp;
+
+      PTR (gtmp) = tmp_gp;
+      SIZ (gtmp) = gsize;
+
+      PTR (stmp) = tmp_sp;
+      SIZ (stmp) = tmp_ssize;
+
+      ASSERT (ssize <= bsize); /* ssize*2 + asize + 1 <= asize + bsize*2 + 1 */
+      PTR (x) = tmp_sp + ssize;
+      ALLOC (x) = ssize + asize + 1;
+
+      mpz_mul (x, stmp, a);
+      mpz_sub (x, gtmp, x);
+      mpz_divexact (t, x, b);
+    }
+
+  if (s != NULL)
+    {
+      mp_ptr sp;
+
+      sp = MPZ_NEWALLOC (s, ssize);
+      MPN_COPY (sp, tmp_sp, ssize);
+      SIZ (s) = tmp_ssize;
+    }
+
+  if (g != NULL)
+    {
+      gp = MPZ_NEWALLOC (g, gsize);
+      MPN_COPY (gp, tmp_gp, gsize);
+      SIZ (g) = gsize;
+    }
+
+  TMP_FREE;
+}
diff --git a/third_party/gmp/mpz/get_d.c b/third_party/gmp/mpz/get_d.c
new file mode 100644
index 0000000..61d4e36
--- /dev/null
+++ b/third_party/gmp/mpz/get_d.c
@@ -0,0 +1,43 @@
+/* double mpz_get_d (mpz_t src) -- Return the double approximation to SRC.
+
+Copyright 1996, 1997, 2000-2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+double
+mpz_get_d (mpz_srcptr z)
+{
+  mp_size_t size;
+
+  size = SIZ (z);
+  if (UNLIKELY (size == 0))
+    return 0.0;
+
+  return mpn_get_d (PTR (z), ABS (size), size, 0L);
+}
diff --git a/third_party/gmp/mpz/get_d_2exp.c b/third_party/gmp/mpz/get_d_2exp.c
new file mode 100644
index 0000000..beb364a
--- /dev/null
+++ b/third_party/gmp/mpz/get_d_2exp.c
@@ -0,0 +1,53 @@
+/* double mpz_get_d_2exp (signed long int *exp, mpz_t src).
+
+Copyright 2001, 2003, 2004, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+double
+mpz_get_d_2exp (signed long int *exp2, mpz_srcptr src)
+{
+  mp_size_t size, abs_size;
+  mp_srcptr ptr;
+  long exp;
+
+  size = SIZ(src);
+  if (UNLIKELY (size == 0))
+    {
+      *exp2 = 0;
+      return 0.0;
+    }
+
+  ptr = PTR(src);
+  abs_size = ABS(size);
+  MPN_SIZEINBASE_2EXP(exp, ptr, abs_size, 1);
+  *exp2 = exp;
+  return mpn_get_d (ptr, abs_size, size, -exp);
+}
diff --git a/third_party/gmp/mpz/get_si.c b/third_party/gmp/mpz/get_si.c
new file mode 100644
index 0000000..c65be2e
--- /dev/null
+++ b/third_party/gmp/mpz/get_si.c
@@ -0,0 +1,52 @@
+/* mpz_get_si(integer) -- Return the least significant digit from INTEGER.
+
+Copyright 1991, 1993-1995, 2000-2002, 2006, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+signed long int
+mpz_get_si (mpz_srcptr z) __GMP_NOTHROW
+{
+  mp_ptr zp = PTR (z);
+  mp_size_t size = SIZ (z);
+  mp_limb_t zl = zp[0];
+
+#if GMP_NAIL_BITS != 0
+  if (ULONG_MAX > GMP_NUMB_MAX && ABS (size) >= 2)
+    zl |= zp[1] << GMP_NUMB_BITS;
+#endif
+
+  if (size > 0)
+    return zl & LONG_MAX;
+  else if (size < 0)
+    /* This expression is necessary to properly handle 0x80000000 */
+    return -1 - (long) ((zl - 1) & LONG_MAX);
+  else
+    return 0;
+}
diff --git a/third_party/gmp/mpz/get_str.c b/third_party/gmp/mpz/get_str.c
new file mode 100644
index 0000000..c00a9a3
--- /dev/null
+++ b/third_party/gmp/mpz/get_str.c
@@ -0,0 +1,115 @@
+/* mpz_get_str (string, base, mp_src) -- Convert the multiple precision
+   number MP_SRC to a string STRING of base BASE.  If STRING is NULL
+   allocate space for the result.  In any case, return a pointer to the
+   result.  If STRING is not NULL, the caller must ensure enough space is
+   available to store the result.
+
+Copyright 1991, 1993, 1994, 1996, 2000-2002, 2005, 2012, 2017 Free
+Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <string.h> /* for strlen */
+#include "gmp-impl.h"
+#include "longlong.h"
+
+char *
+mpz_get_str (char *res_str, int base, mpz_srcptr x)
+{
+  mp_ptr xp;
+  mp_size_t x_size = SIZ (x);
+  char *return_str;
+  size_t str_size;
+  size_t alloc_size = 0;
+  const char *num_to_text;
+  int i;
+  TMP_DECL;
+
+  num_to_text = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+  if (base > 1)
+    {
+      if (base <= 36)
+	num_to_text = "0123456789abcdefghijklmnopqrstuvwxyz";
+      else if (UNLIKELY (base > 62))
+	return NULL;
+    }
+  else if (base > -2)
+    {
+      base = 10;
+    }
+  else
+    {
+      base = -base;
+      if (UNLIKELY (base > 36))
+	return NULL;
+    }
+
+  /* allocate string for the user if necessary */
+  if (res_str == NULL)
+    {
+      /* digits, null terminator, possible minus sign */
+      MPN_SIZEINBASE (alloc_size, PTR(x), ABS(x_size), base);
+      alloc_size += 1 + (x_size<0);
+      res_str = __GMP_ALLOCATE_FUNC_TYPE (alloc_size, char);
+    }
+  return_str = res_str;
+
+  if (x_size < 0)
+    {
+      *res_str++ = '-';
+      x_size = -x_size;
+    }
+
+  /* mpn_get_str clobbers its input on non power-of-2 bases */
+  TMP_MARK;
+  xp = PTR (x);
+  if (! POW2_P (base))
+    {
+      xp = TMP_ALLOC_LIMBS (x_size | 1);  /* |1 in case x_size==0 */
+      MPN_COPY (xp, PTR (x), x_size);
+    }
+
+  str_size = mpn_get_str ((unsigned char *) res_str, base, xp, x_size);
+  ASSERT (alloc_size == 0 || str_size <= alloc_size - (SIZ(x) < 0));
+
+  /* Convert result to printable chars.  */
+  for (i = 0; i < str_size; i++)
+    res_str[i] = num_to_text[(int) res_str[i]];
+  res_str[str_size] = 0;
+
+  TMP_FREE;
+
+  /* if allocated then resize down to the actual space required */
+  if (alloc_size != 0)
+    {
+      size_t  actual_size = str_size + 1 + (res_str - return_str);
+      ASSERT (actual_size == strlen (return_str) + 1);
+      __GMP_REALLOCATE_FUNC_MAYBE_TYPE (return_str, alloc_size, actual_size,
+					char);
+    }
+  return return_str;
+}
diff --git a/third_party/gmp/mpz/get_ui.c b/third_party/gmp/mpz/get_ui.c
new file mode 100644
index 0000000..2d7ea4e
--- /dev/null
+++ b/third_party/gmp/mpz/get_ui.c
@@ -0,0 +1,33 @@
+/* mpz_get_ui(integer) -- Return the least significant digit from INTEGER.
+
+Copyright 1991, 1993-1995, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define __GMP_FORCE_mpz_get_ui 1
+
+#include "gmp-impl.h"
diff --git a/third_party/gmp/mpz/getlimbn.c b/third_party/gmp/mpz/getlimbn.c
new file mode 100644
index 0000000..d34d764
--- /dev/null
+++ b/third_party/gmp/mpz/getlimbn.c
@@ -0,0 +1,33 @@
+/* mpz_getlimbn(integer,n) -- Return the N:th limb from INTEGER.
+
+Copyright 1993-1996, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define __GMP_FORCE_mpz_getlimbn 1
+
+#include "gmp-impl.h"
diff --git a/third_party/gmp/mpz/hamdist.c b/third_party/gmp/mpz/hamdist.c
new file mode 100644
index 0000000..1dfb7b8
--- /dev/null
+++ b/third_party/gmp/mpz/hamdist.c
@@ -0,0 +1,174 @@
+/* mpz_hamdist -- calculate hamming distance.
+
+Copyright 1994, 1996, 2001, 2002, 2009-2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+mp_bitcnt_t
+mpz_hamdist (mpz_srcptr u, mpz_srcptr v) __GMP_NOTHROW
+{
+  mp_srcptr      up, vp;
+  mp_size_t      usize, vsize;
+  mp_bitcnt_t    count;
+
+  usize = SIZ(u);
+  vsize = SIZ(v);
+
+  up = PTR(u);
+  vp = PTR(v);
+
+  if (usize >= 0)
+    {
+      if (vsize < 0)
+	return ~ (mp_bitcnt_t) 0;
+
+      /* positive/positive */
+
+      if (usize < vsize)
+	MPN_SRCPTR_SWAP (up,usize, vp,vsize);
+
+      count = 0;
+      if (vsize != 0)
+	count = mpn_hamdist (up, vp, vsize);
+
+      usize -= vsize;
+      if (usize != 0)
+	count += mpn_popcount (up + vsize, usize);
+
+      return count;
+    }
+  else
+    {
+      mp_limb_t  ulimb, vlimb;
+      mp_size_t  old_vsize, step;
+
+      if (vsize >= 0)
+	return ~ (mp_bitcnt_t) 0;
+
+      /* negative/negative */
+
+      usize = -usize;
+      vsize = -vsize;
+
+      /* skip common low zeros */
+      for (;;)
+	{
+	  ASSERT (usize > 0);
+	  ASSERT (vsize > 0);
+
+	  usize--;
+	  vsize--;
+
+	  ulimb = *up++;
+	  vlimb = *vp++;
+
+	  if (ulimb != 0)
+	    break;
+
+	  if (vlimb != 0)
+	    {
+	      MPN_SRCPTR_SWAP (up,usize, vp,vsize);
+	      ulimb = vlimb;
+	      vlimb = 0;
+	      break;
+	    }
+	}
+
+      /* twos complement first non-zero limbs (ulimb is non-zero, but vlimb
+	 might be zero) */
+      ulimb = -ulimb;
+      vlimb = -vlimb;
+      popc_limb (count, (ulimb ^ vlimb) & GMP_NUMB_MASK);
+
+      if (vlimb == 0)
+	{
+	  mp_bitcnt_t  twoscount;
+
+	  /* first non-zero of v */
+	  old_vsize = vsize;
+	  do
+	    {
+	      ASSERT (vsize > 0);
+	      vsize--;
+	      vlimb = *vp++;
+	    }
+	  while (vlimb == 0);
+
+	  /* part of u corresponding to skipped v zeros */
+	  step = old_vsize - vsize - 1;
+	  count += step * GMP_NUMB_BITS;
+	  step = MIN (step, usize);
+	  if (step != 0)
+	    {
+	      count -= mpn_popcount (up, step);
+	      usize -= step;
+	      up += step;
+	    }
+
+	  /* First non-zero vlimb as twos complement, xor with ones
+	     complement ulimb.  Note -v^(~0^u) == (v-1)^u. */
+	  vlimb--;
+	  if (usize != 0)
+	    {
+	      usize--;
+	      vlimb ^= *up++;
+	    }
+	  popc_limb (twoscount, vlimb);
+	  count += twoscount;
+	}
+
+      /* Overlapping part of u and v, if any.  Ones complement both, so just
+	 plain hamdist. */
+      step = MIN (usize, vsize);
+      if (step != 0)
+	{
+	  count += mpn_hamdist (up, vp, step);
+	  usize -= step;
+	  vsize -= step;
+	  up += step;
+	  vp += step;
+	}
+
+      /* Remaining high part of u or v, if any, ones complement but xor
+	 against all ones in the other, so plain popcount. */
+      if (usize != 0)
+	{
+	remaining:
+	  count += mpn_popcount (up, usize);
+	}
+      else if (vsize != 0)
+	{
+	  up = vp;
+	  usize = vsize;
+	  goto remaining;
+	}
+      return count;
+    }
+}
diff --git a/third_party/gmp/mpz/import.c b/third_party/gmp/mpz/import.c
new file mode 100644
index 0000000..e40b5ed
--- /dev/null
+++ b/third_party/gmp/mpz/import.c
@@ -0,0 +1,179 @@
+/* mpz_import -- set mpz from word data.
+
+Copyright 2002, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp-impl.h"
+
+
+
+#if HAVE_LIMB_BIG_ENDIAN
+#define HOST_ENDIAN     1
+#endif
+#if HAVE_LIMB_LITTLE_ENDIAN
+#define HOST_ENDIAN     (-1)
+#endif
+#ifndef HOST_ENDIAN
+static const mp_limb_t  endian_test = (CNST_LIMB(1) << (GMP_LIMB_BITS-7)) - 1;
+#define HOST_ENDIAN     (* (signed char *) &endian_test)
+#endif
+
+
+void
+mpz_import (mpz_ptr z, size_t count, int order,
+	    size_t size, int endian, size_t nail, const void *data)
+{
+  mp_size_t  zsize;
+  mp_ptr     zp;
+
+  ASSERT (order == 1 || order == -1);
+  ASSERT (endian == 1 || endian == 0 || endian == -1);
+  ASSERT (nail <= 8*size);
+
+  zsize = BITS_TO_LIMBS (count * (8*size - nail));
+  zp = MPZ_NEWALLOC (z, zsize);
+
+  if (endian == 0)
+    endian = HOST_ENDIAN;
+
+  /* Can't use these special cases with nails currently, since they don't
+     mask out the nail bits in the input data.  */
+  if (nail == 0 && GMP_NAIL_BITS == 0)
+    {
+      unsigned  align = ((char *) data - (char *) NULL) % sizeof (mp_limb_t);
+
+      if (order == -1
+	  && size == sizeof (mp_limb_t)
+	  && endian == HOST_ENDIAN
+	  && align == 0)
+	{
+	  MPN_COPY (zp, (mp_srcptr) data, (mp_size_t) count);
+	  goto done;
+	}
+
+      if (order == -1
+	  && size == sizeof (mp_limb_t)
+	  && endian == - HOST_ENDIAN
+	  && align == 0)
+	{
+	  MPN_BSWAP (zp, (mp_srcptr) data, (mp_size_t) count);
+	  goto done;
+	}
+
+      if (order == 1
+	  && size == sizeof (mp_limb_t)
+	  && endian == HOST_ENDIAN
+	  && align == 0)
+	{
+	  MPN_REVERSE (zp, (mp_srcptr) data, (mp_size_t) count);
+	  goto done;
+	}
+    }
+
+  {
+    mp_limb_t      limb, byte, wbitsmask;
+    size_t         i, j, numb, wbytes;
+    mp_size_t      woffset;
+    unsigned char  *dp;
+    int            lbits, wbits;
+
+    numb = size * 8 - nail;
+
+    /* whole bytes to process */
+    wbytes = numb / 8;
+
+    /* partial byte to process */
+    wbits = numb % 8;
+    wbitsmask = (CNST_LIMB(1) << wbits) - 1;
+
+    /* offset to get to the next word after processing wbytes and wbits */
+    woffset = (numb + 7) / 8;
+    woffset = (endian >= 0 ? woffset : -woffset)
+      + (order < 0 ? size : - (mp_size_t) size);
+
+    /* least significant byte */
+    dp = (unsigned char *) data
+      + (order >= 0 ? (count-1)*size : 0) + (endian >= 0 ? size-1 : 0);
+
+#define ACCUMULATE(N)                                   \
+    do {                                                \
+      ASSERT (lbits < GMP_NUMB_BITS);                   \
+      ASSERT (limb <= (CNST_LIMB(1) << lbits) - 1);     \
+                                                        \
+      limb |= (mp_limb_t) byte << lbits;                \
+      lbits += (N);                                     \
+      if (lbits >= GMP_NUMB_BITS)                       \
+        {                                               \
+          *zp++ = limb & GMP_NUMB_MASK;                 \
+          lbits -= GMP_NUMB_BITS;                       \
+          ASSERT (lbits < (N));                         \
+          limb = byte >> ((N) - lbits);                 \
+        }                                               \
+    } while (0)
+
+    limb = 0;
+    lbits = 0;
+    for (i = 0; i < count; i++)
+      {
+	for (j = 0; j < wbytes; j++)
+	  {
+	    byte = *dp;
+	    dp -= endian;
+	    ACCUMULATE (8);
+	  }
+	if (wbits != 0)
+	  {
+	    byte = *dp & wbitsmask;
+	    dp -= endian;
+	    ACCUMULATE (wbits);
+	  }
+	dp += woffset;
+      }
+
+    if (lbits != 0)
+      {
+	ASSERT (lbits <= GMP_NUMB_BITS);
+	ASSERT_LIMB (limb);
+	*zp++ = limb;
+      }
+
+    ASSERT (zp == PTR(z) + zsize);
+
+    /* low byte of word after most significant */
+    ASSERT (dp == (unsigned char *) data
+	    + (order < 0 ? count*size : - (mp_size_t) size)
+	    + (endian >= 0 ? (mp_size_t) size - 1 : 0));
+
+  }
+
+ done:
+  zp = PTR(z);
+  MPN_NORMALIZE (zp, zsize);
+  SIZ(z) = zsize;
+}
diff --git a/third_party/gmp/mpz/init.c b/third_party/gmp/mpz/init.c
new file mode 100644
index 0000000..b85a2da
--- /dev/null
+++ b/third_party/gmp/mpz/init.c
@@ -0,0 +1,41 @@
+/* mpz_init() -- Make a new multiple precision number with value 0.
+
+Copyright 1991, 1993-1995, 2000-2002, 2012, 2015 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_init (mpz_ptr x) __GMP_NOTHROW
+{
+  static const mp_limb_t dummy_limb=0xc1a0;
+  ALLOC (x) = 0;
+  PTR (x) = (mp_ptr) &dummy_limb;
+  SIZ (x) = 0;
+}
diff --git a/third_party/gmp/mpz/init2.c b/third_party/gmp/mpz/init2.c
new file mode 100644
index 0000000..fcbaa66
--- /dev/null
+++ b/third_party/gmp/mpz/init2.c
@@ -0,0 +1,55 @@
+/* mpz_init2 -- initialize mpz, with requested size in bits.
+
+Copyright 2001, 2002, 2008 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "gmp-impl.h"
+
+void
+mpz_init2 (mpz_ptr x, mp_bitcnt_t bits)
+{
+  mp_size_t  new_alloc;
+
+  bits -= (bits != 0);		/* Round down, except if 0 */
+  new_alloc = 1 + bits / GMP_NUMB_BITS;
+
+  if (sizeof (unsigned long) > sizeof (int)) /* param vs _mp_size field */
+    {
+      if (UNLIKELY (new_alloc > INT_MAX))
+	{
+	  fprintf (stderr, "gmp: overflow in mpz type\n");
+	  abort ();
+	}
+    }
+
+  PTR(x) = __GMP_ALLOCATE_FUNC_LIMBS (new_alloc);
+  ALLOC(x) = new_alloc;
+  SIZ(x) = 0;
+}
diff --git a/third_party/gmp/mpz/inits.c b/third_party/gmp/mpz/inits.c
new file mode 100644
index 0000000..1660744
--- /dev/null
+++ b/third_party/gmp/mpz/inits.c
@@ -0,0 +1,53 @@
+/* mpz_inits() -- Initialize multiple mpz_t variables and set them to 0.
+
+Copyright 2009, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+#include "gmp-impl.h"
+
+void
+mpz_inits (mpz_ptr x, ...) __GMP_NOTHROW
+{
+  static const mp_limb_t dummy_limb=0xc1a0;
+  va_list  ap;
+
+  va_start (ap, x);
+
+  do
+    {
+      ALLOC (x) = 0;
+      PTR (x) = (mp_ptr) &dummy_limb;
+      SIZ (x) = 0;
+
+      x = va_arg (ap, mpz_ptr);
+    }
+  while (x != NULL);
+
+  va_end (ap);
+}
diff --git a/third_party/gmp/mpz/inp_raw.c b/third_party/gmp/mpz/inp_raw.c
new file mode 100644
index 0000000..378c42b
--- /dev/null
+++ b/third_party/gmp/mpz/inp_raw.c
@@ -0,0 +1,169 @@
+/* mpz_inp_raw -- read an mpz_t in raw format.
+
+Copyright 2001, 2002, 2005, 2012, 2016 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp-impl.h"
+
+
+/* NTOH_LIMB_FETCH fetches a limb which is in network byte order (ie. big
+   endian) and produces a normal host byte order result. */
+
+#if HAVE_LIMB_BIG_ENDIAN
+#define NTOH_LIMB_FETCH(limb, src)  do { (limb) = *(src); } while (0)
+#endif
+
+#if HAVE_LIMB_LITTLE_ENDIAN
+#define NTOH_LIMB_FETCH(limb, src)  BSWAP_LIMB_FETCH (limb, src)
+#endif
+
+#ifndef NTOH_LIMB_FETCH
+#define NTOH_LIMB_FETCH(limb, src)                              \
+  do {                                                          \
+    const unsigned char  *__p = (const unsigned char *) (src);  \
+    mp_limb_t  __limb;                                          \
+    int        __i;                                             \
+    __limb = 0;                                                 \
+    for (__i = 0; __i < GMP_LIMB_BYTES; __i++)               \
+      __limb = (__limb << 8) | __p[__i];                        \
+    (limb) = __limb;                                            \
+  } while (0)
+#endif
+
+
+/* Enhancement: The byte swap loop ought to be safe to vectorize on Cray
+   etc, but someone who knows what they're doing needs to check it.  */
+
+size_t
+mpz_inp_raw (mpz_ptr x, FILE *fp)
+{
+  unsigned char  csize_bytes[4];
+  mp_size_t      csize, abs_xsize, i;
+  size_t         size;
+  size_t         abs_csize;
+  char           *cp;
+  mp_ptr         xp, sp, ep;
+  mp_limb_t      slimb, elimb;
+
+  if (fp == 0)
+    fp = stdin;
+
+  /* 4 bytes for size */
+  if (fread (csize_bytes, sizeof (csize_bytes), 1, fp) != 1)
+    return 0;
+
+  size = (((size_t) csize_bytes[0] << 24) + ((size_t) csize_bytes[1] << 16) +
+	  ((size_t) csize_bytes[2] << 8)  + ((size_t) csize_bytes[3]));
+
+  if (size < 0x80000000u)
+    csize = size;
+  else
+    csize = size - 0x80000000u - 0x80000000u;
+
+  abs_csize = ABS (csize);
+
+  /* round up to a multiple of limbs */
+  abs_xsize = BITS_TO_LIMBS (abs_csize*8);
+
+  if (abs_xsize != 0)
+    {
+      xp = MPZ_NEWALLOC (x, abs_xsize);
+
+      /* Get limb boundaries right in the read, for the benefit of the
+	 non-nails case.  */
+      xp[0] = 0;
+      cp = (char *) (xp + abs_xsize) - abs_csize;
+      if (fread (cp, abs_csize, 1, fp) != 1)
+	return 0;
+
+      if (GMP_NAIL_BITS == 0)
+	{
+	  /* Reverse limbs to least significant first, and byte swap.  If
+	     abs_xsize is odd then on the last iteration elimb and slimb are
+	     the same.  It doesn't seem extra code to handle that case
+	     separately, to save an NTOH.  */
+	  sp = xp;
+	  ep = xp + abs_xsize-1;
+	  for (i = 0; i < (abs_xsize+1)/2; i++)
+	    {
+	      NTOH_LIMB_FETCH (elimb, ep);
+	      NTOH_LIMB_FETCH (slimb, sp);
+	      *sp++ = elimb;
+	      *ep-- = slimb;
+	    }
+	}
+      else
+	{
+	  /* It ought to be possible to do the transformation in-place, but
+	     for now it's easier to use an extra temporary area.  */
+	  mp_limb_t  byte, limb;
+	  int	     bits;
+	  mp_size_t  tpos;
+	  mp_ptr     tp;
+	  TMP_DECL;
+
+	  TMP_MARK;
+	  tp = TMP_ALLOC_LIMBS (abs_xsize);
+	  limb = 0;
+	  bits = 0;
+	  tpos = 0;
+	  for (i = abs_csize-1; i >= 0; i--)
+	    {
+	      byte = (unsigned char) cp[i];
+	      limb |= (byte << bits);
+	      bits += 8;
+	      if (bits >= GMP_NUMB_BITS)
+		{
+		  ASSERT (tpos < abs_xsize);
+		  tp[tpos++] = limb & GMP_NUMB_MASK;
+		  bits -= GMP_NUMB_BITS;
+		  ASSERT (bits < 8);
+		  limb = byte >> (8 - bits);
+		}
+	    }
+	  if (bits != 0)
+	    {
+	      ASSERT (tpos < abs_xsize);
+	      tp[tpos++] = limb;
+	    }
+	  ASSERT (tpos == abs_xsize);
+
+	  MPN_COPY (xp, tp, abs_xsize);
+	  TMP_FREE;
+	}
+
+      /* GMP 1.x mpz_out_raw wrote high zero bytes, strip any high zero
+	 limbs resulting from this.  Should be a non-zero value here, but
+	 for safety don't assume that. */
+      MPN_NORMALIZE (xp, abs_xsize);
+    }
+
+  SIZ(x) = (csize >= 0 ? abs_xsize : -abs_xsize);
+  return abs_csize + 4;
+}
diff --git a/third_party/gmp/mpz/inp_str.c b/third_party/gmp/mpz/inp_str.c
new file mode 100644
index 0000000..0756055
--- /dev/null
+++ b/third_party/gmp/mpz/inp_str.c
@@ -0,0 +1,173 @@
+/* mpz_inp_str(dest_integer, stream, base) -- Input a number in base
+   BASE from stdio stream STREAM and store the result in DEST_INTEGER.
+
+   OF THE FUNCTIONS IN THIS FILE, ONLY mpz_inp_str IS FOR EXTERNAL USE, THE
+   REST ARE INTERNALS AND ARE ALMOST CERTAIN TO BE SUBJECT TO INCOMPATIBLE
+   CHANGES OR DISAPPEAR COMPLETELY IN FUTURE GNU MP RELEASES.
+
+Copyright 1991, 1993, 1994, 1996, 1998, 2000-2003, 2011-2013 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <ctype.h>
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#define digit_value_tab __gmp_digit_value_tab
+
+size_t
+mpz_inp_str (mpz_ptr x, FILE *stream, int base)
+{
+  int c;
+  size_t nread;
+
+  if (stream == 0)
+    stream = stdin;
+
+  nread = 0;
+
+  /* Skip whitespace.  */
+  do
+    {
+      c = getc (stream);
+      nread++;
+    }
+  while (isspace (c));
+
+  return mpz_inp_str_nowhite (x, stream, base, c, nread);
+}
+
+/* shared by mpq_inp_str */
+size_t
+mpz_inp_str_nowhite (mpz_ptr x, FILE *stream, int base, int c, size_t nread)
+{
+  char *str;
+  size_t alloc_size, str_size;
+  int negative;
+  mp_size_t xsize;
+  const unsigned char *digit_value;
+
+  ASSERT_ALWAYS (EOF == -1);	/* FIXME: handle this by adding explicit */
+				/* comparisons of c and EOF before each  */
+				/* read of digit_value[].  */
+
+  digit_value = digit_value_tab;
+  if (base > 36)
+    {
+      /* For bases > 36, use the collating sequence
+	 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.  */
+      digit_value += 208;
+      if (UNLIKELY (base > 62))
+	return 0;		/* too large base */
+    }
+
+  negative = 0;
+  if (c == '-')
+    {
+      negative = 1;
+      c = getc (stream);
+      nread++;
+    }
+
+  if (c == EOF || digit_value[c] >= (base == 0 ? 10 : base))
+    return 0;			/* error if no digits */
+
+  /* If BASE is 0, try to find out the base by looking at the initial
+     characters.  */
+  if (base == 0)
+    {
+      base = 10;
+      if (c == '0')
+	{
+	  base = 8;
+	  c = getc (stream);
+	  nread++;
+	  if (c == 'x' || c == 'X')
+	    {
+	      base = 16;
+	      c = getc (stream);
+	      nread++;
+	    }
+	  else if (c == 'b' || c == 'B')
+	    {
+	      base = 2;
+	      c = getc (stream);
+	      nread++;
+	    }
+	}
+    }
+
+  /* Skip leading zeros.  */
+  while (c == '0')
+    {
+      c = getc (stream);
+      nread++;
+    }
+
+  alloc_size = 100;
+  str = __GMP_ALLOCATE_FUNC_TYPE (alloc_size, char);
+  str_size = 0;
+
+  while (c != EOF)
+    {
+      int dig;
+      dig = digit_value[c];
+      if (dig >= base)
+	break;
+      if (str_size >= alloc_size)
+	{
+	  size_t old_alloc_size = alloc_size;
+	  alloc_size = alloc_size * 3 / 2;
+	  str = __GMP_REALLOCATE_FUNC_TYPE (str, old_alloc_size, alloc_size, char);
+	}
+      str[str_size++] = dig;
+      c = getc (stream);
+    }
+  nread += str_size;
+
+  ungetc (c, stream);
+  nread--;
+
+  /* Make sure the string is not empty, mpn_set_str would fail.  */
+  if (str_size == 0)
+    {
+      SIZ (x) = 0;
+    }
+  else
+    {
+      LIMBS_PER_DIGIT_IN_BASE (xsize, str_size, base);
+      MPZ_NEWALLOC (x, xsize);
+
+      /* Convert the byte array in base BASE to our bignum format.  */
+      xsize = mpn_set_str (PTR (x), (unsigned char *) str, str_size, base);
+      SIZ (x) = negative ? -xsize : xsize;
+    }
+  (*__gmp_free_func) (str, alloc_size);
+  return nread;
+}
diff --git a/third_party/gmp/mpz/invert.c b/third_party/gmp/mpz/invert.c
new file mode 100644
index 0000000..5532d13
--- /dev/null
+++ b/third_party/gmp/mpz/invert.c
@@ -0,0 +1,72 @@
+/* mpz_invert (inv, x, n).  Find multiplicative inverse of X in Z(N).
+   If X has an inverse, return non-zero and store inverse in INVERSE,
+   otherwise, return 0 and put garbage in INVERSE.
+
+Copyright 1996-2001, 2005, 2012, 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+int
+mpz_invert (mpz_ptr inverse, mpz_srcptr x, mpz_srcptr n)
+{
+  mpz_t gcd, tmp;
+  mp_size_t xsize, nsize, size;
+  TMP_DECL;
+
+  xsize = ABSIZ (x);
+  nsize = ABSIZ (n);
+
+  size = MAX (xsize, nsize) + 1;
+  TMP_MARK;
+
+  MPZ_TMP_INIT (gcd, size);
+  MPZ_TMP_INIT (tmp, size);
+  mpz_gcdext (gcd, tmp, (mpz_ptr) 0, x, n);
+
+  /* If no inverse existed, return with an indication of that.  */
+  if (!MPZ_EQUAL_1_P (gcd))
+    {
+      TMP_FREE;
+      return 0;
+    }
+
+  /* Make sure we return a positive inverse.  */
+  if (SIZ (tmp) < 0)
+    {
+      if (SIZ (n) < 0)
+	mpz_sub (inverse, tmp, n);
+      else
+	mpz_add (inverse, tmp, n);
+    }
+  else
+    mpz_set (inverse, tmp);
+
+  TMP_FREE;
+  return 1;
+}
diff --git a/third_party/gmp/mpz/ior.c b/third_party/gmp/mpz/ior.c
new file mode 100644
index 0000000..32f3042
--- /dev/null
+++ b/third_party/gmp/mpz/ior.c
@@ -0,0 +1,184 @@
+/* mpz_ior -- Logical inclusive or.
+
+Copyright 1991, 1993, 1994, 1996, 1997, 2000, 2001, 2005, 2012, 2013,
+2015-2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_ior (mpz_ptr res, mpz_srcptr op1, mpz_srcptr op2)
+{
+  mp_srcptr op1_ptr, op2_ptr;
+  mp_size_t op1_size, op2_size;
+  mp_ptr res_ptr;
+  mp_size_t res_size;
+  mp_size_t i;
+
+  op1_size = SIZ(op1);
+  op2_size = SIZ(op2);
+
+  if (op1_size < op2_size)
+    {
+      MPZ_SRCPTR_SWAP (op1, op2);
+      MP_SIZE_T_SWAP (op1_size, op2_size);
+    }
+
+  op1_ptr = PTR(op1);
+  res_ptr = PTR(res);
+
+  if (op2_size >= 0)
+    {
+      if (res_ptr != op1_ptr)
+	{
+	  res_ptr = MPZ_REALLOC (res, op1_size);
+	  /* No overlapping possible: op1_ptr = PTR(op1); */
+	  MPN_COPY (res_ptr + op2_size, op1_ptr + op2_size,
+		    op1_size - op2_size);
+	}
+      if (LIKELY (op2_size != 0))
+	mpn_ior_n (res_ptr, op1_ptr, PTR(op2), op2_size);
+
+      SIZ(res) = op1_size;
+    }
+  else
+    {
+      mp_ptr opx;
+      TMP_DECL;
+
+      TMP_MARK;
+      if (op1_size < 0)
+	{
+	  mp_ptr opy;
+
+	  /* Both operands are negative, so will be the result.
+	     -((-OP1) | (-OP2)) = -(~(OP1 - 1) | ~(OP2 - 1)) =
+	     = ~(~(OP1 - 1) | ~(OP2 - 1)) + 1 =
+	     = ((OP1 - 1) & (OP2 - 1)) + 1      */
+
+	  res_size = -op1_size;
+
+	  /* Possible optimization: Decrease mpn_sub precision,
+	     as we won't use the entire res of both.  */
+	  TMP_ALLOC_LIMBS_2 (opx, res_size, opy, res_size);
+	  mpn_sub_1 (opx, op1_ptr, res_size, (mp_limb_t) 1);
+	  op1_ptr = opx;
+
+	  mpn_sub_1 (opy, PTR(op2), res_size, (mp_limb_t) 1);
+	  op2_ptr = opy;
+
+	  /* First loop finds the size of the result.  */
+	  for (i = res_size; --i >= 0;)
+	    if ((op1_ptr[i] & op2_ptr[i]) != 0)
+	      break;
+	  res_size = i + 1;
+
+	  res_ptr = MPZ_NEWALLOC (res, res_size + 1);
+
+	  if (res_size != 0)
+	    {
+	      /* Second loop computes the real result.  */
+	      mpn_and_n (res_ptr, op1_ptr, op2_ptr, res_size);
+
+	      res_ptr[res_size] = 0;
+	      MPN_INCR_U (res_ptr, res_size + 1, 1);
+	      res_size += res_ptr[res_size];
+	    }
+	  else
+	    {
+	      res_ptr[0] = 1;
+	      res_size = 1;
+	    }
+
+	  SIZ(res) = -res_size;
+	}
+      else
+	{
+	  mp_limb_t cy;
+	  mp_size_t count;
+
+	  /* Operand 2 negative, so will be the result.
+	     -(OP1 | (-OP2)) = -(OP1 | ~(OP2 - 1)) =
+	     = ~(OP1 | ~(OP2 - 1)) + 1 =
+	     = (~OP1 & (OP2 - 1)) + 1      */
+
+	  op2_size = -op2_size;
+
+	  res_ptr = MPZ_REALLOC (res, op2_size);
+	  op1_ptr = PTR(op1);
+
+	  opx = TMP_ALLOC_LIMBS (op2_size);
+	  mpn_sub_1 (opx, PTR(op2), op2_size, (mp_limb_t) 1);
+	  op2_ptr = opx;
+	  op2_size -= op2_ptr[op2_size - 1] == 0;
+
+	  if (op1_size >= op2_size)
+	    {
+	      /* We can just ignore the part of OP1 that stretches above OP2,
+		 because the result limbs are zero there.  */
+
+	      /* First loop finds the size of the result.  */
+	      for (i = op2_size; --i >= 0;)
+		if ((~op1_ptr[i] & op2_ptr[i]) != 0)
+		  break;
+	      res_size = i + 1;
+	      count = res_size;
+	    }
+	  else
+	    {
+	      res_size = op2_size;
+
+	      /* Copy the part of OP2 that stretches above OP1, to RES.  */
+	      MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size, op2_size - op1_size);
+	      count = op1_size;
+	    }
+
+	  if (res_size != 0)
+	    {
+	      /* Second loop computes the real result.  */
+	      if (LIKELY (count != 0))
+		mpn_andn_n (res_ptr, op2_ptr, op1_ptr, count);
+
+	      cy = mpn_add_1 (res_ptr, res_ptr, res_size, (mp_limb_t) 1);
+	      if (cy)
+		{
+		  res_ptr[res_size] = cy;
+		  ++res_size;
+		}
+	    }
+	  else
+	    {
+	      res_ptr[0] = 1;
+	      res_size = 1;
+	    }
+
+	  SIZ(res) = -res_size;
+	}
+      TMP_FREE;
+    }
+}
diff --git a/third_party/gmp/mpz/iset.c b/third_party/gmp/mpz/iset.c
new file mode 100644
index 0000000..252cada
--- /dev/null
+++ b/third_party/gmp/mpz/iset.c
@@ -0,0 +1,52 @@
+/* mpz_init_set (src_integer) -- Make a new multiple precision number with
+   a value copied from SRC_INTEGER.
+
+Copyright 1991, 1993, 1994, 1996, 2000-2002, 2012 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_init_set (mpz_ptr w, mpz_srcptr u)
+{
+  mp_ptr wp, up;
+  mp_size_t usize, size;
+
+  usize = SIZ (u);
+  size = ABS (usize);
+
+  ALLOC (w) = MAX (size, 1);
+  wp = __GMP_ALLOCATE_FUNC_LIMBS (ALLOC (w));
+
+  PTR (w) = wp;
+  up = PTR (u);
+
+  MPN_COPY (wp, up, size);
+  SIZ (w) = usize;
+}
diff --git a/third_party/gmp/mpz/iset_d.c b/third_party/gmp/mpz/iset_d.c
new file mode 100644
index 0000000..5d04a6f
--- /dev/null
+++ b/third_party/gmp/mpz/iset_d.c
@@ -0,0 +1,43 @@
+/* mpz_init_set_d(integer, val) -- Initialize and assign INTEGER with a double
+   value VAL.
+
+Copyright 1996, 2000, 2001, 2012, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_init_set_d (mpz_ptr dest, double val)
+{
+  static const mp_limb_t dummy_limb=0xc1a0;
+
+  ALLOC (dest) = 0;
+  SIZ (dest) = 0;
+  PTR (dest) = (mp_ptr) &dummy_limb;
+  mpz_set_d (dest, val);
+}
diff --git a/third_party/gmp/mpz/iset_si.c b/third_party/gmp/mpz/iset_si.c
new file mode 100644
index 0000000..7179cb0
--- /dev/null
+++ b/third_party/gmp/mpz/iset_si.c
@@ -0,0 +1,58 @@
+/* mpz_init_set_si(dest,val) -- Make a new multiple precision in DEST and
+   assign VAL to the new number.
+
+Copyright 1991, 1993-1995, 2000-2002, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_init_set_si (mpz_ptr dest, signed long int val)
+{
+  mp_size_t size;
+  mp_limb_t vl;
+
+  ALLOC (dest) = 1;
+  PTR (dest) = __GMP_ALLOCATE_FUNC_LIMBS (1);
+
+  vl = (mp_limb_t) ABS_CAST (unsigned long int, val);
+
+  PTR (dest)[0] = vl & GMP_NUMB_MASK;
+  size = vl != 0;
+
+#if GMP_NAIL_BITS != 0
+  if (vl > GMP_NUMB_MAX)
+    {
+      MPZ_REALLOC (dest, 2);
+      PTR (dest)[1] = vl >> GMP_NUMB_BITS;
+      size = 2;
+    }
+#endif
+
+  SIZ (dest) = val >= 0 ? size : -size;
+}
diff --git a/third_party/gmp/mpz/iset_str.c b/third_party/gmp/mpz/iset_str.c
new file mode 100644
index 0000000..2df12f9
--- /dev/null
+++ b/third_party/gmp/mpz/iset_str.c
@@ -0,0 +1,47 @@
+/* mpz_init_set_str(string, base) -- Convert the \0-terminated string STRING in
+   base BASE to a multiple precision integer.  Allow white space in the string.
+   If BASE == 0 determine the base in the C standard way, i.e.  0xhh...h means
+   base 16, 0oo...o means base 8, otherwise assume base 10.
+
+Copyright 1991, 1993-1995, 2000-2002, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+int
+mpz_init_set_str (mpz_ptr x, const char *str, int base)
+{
+  static const mp_limb_t dummy_limb=0xc1a0;
+  ALLOC (x) = 0;
+  PTR (x) = (mp_ptr) &dummy_limb;
+
+  /* if str has no digits mpz_set_str leaves x->_mp_size unset */
+  SIZ (x) = 0;
+
+  return mpz_set_str (x, str, base);
+}
diff --git a/third_party/gmp/mpz/iset_ui.c b/third_party/gmp/mpz/iset_ui.c
new file mode 100644
index 0000000..22a8e15
--- /dev/null
+++ b/third_party/gmp/mpz/iset_ui.c
@@ -0,0 +1,58 @@
+/* mpz_init_set_ui(dest,val) -- Make a new multiple precision in DEST and
+   assign VAL to the new number.
+
+Copyright 1991, 1993-1995, 2000-2002, 2004, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_init_set_ui (mpz_ptr dest, unsigned long int val)
+{
+  mp_size_t size;
+
+#if BITS_PER_ULONG > GMP_NUMB_BITS  /* avoid warnings about shift amount */
+  if (val > GMP_NUMB_MAX)
+    {
+      ALLOC (dest) = 2;
+      PTR (dest) = __GMP_ALLOCATE_FUNC_LIMBS (2);
+      PTR (dest)[1] = val >> GMP_NUMB_BITS;
+      size = 2;
+    }
+  else
+#endif
+    {
+      ALLOC (dest) = 1;
+      PTR (dest) = __GMP_ALLOCATE_FUNC_LIMBS (1);
+
+      size = val != 0;
+    }
+  PTR (dest)[0] = val & GMP_NUMB_MASK;
+
+  SIZ (dest) = size;
+}
diff --git a/third_party/gmp/mpz/jacobi.c b/third_party/gmp/mpz/jacobi.c
new file mode 100644
index 0000000..cd556d7
--- /dev/null
+++ b/third_party/gmp/mpz/jacobi.c
@@ -0,0 +1,210 @@
+/* mpz_jacobi, mpz_legendre, mpz_kronecker -- mpz/mpz Jacobi symbols.
+
+Copyright 2000-2002, 2005, 2010-2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* This code does triple duty as mpz_jacobi, mpz_legendre and
+   mpz_kronecker. For ABI compatibility, the link symbol is
+   __gmpz_jacobi, not __gmpz_kronecker, even though the latter would
+   be more logical.
+
+   mpz_jacobi could assume b is odd, but the improvements from that seem
+   small compared to other operations, and anything significant should be
+   checked at run-time since we'd like odd b to go fast in mpz_kronecker
+   too.
+
+   mpz_legendre could assume b is an odd prime, but knowing this doesn't
+   present any obvious benefits.  Result 0 wouldn't arise (unless "a" is a
+   multiple of b), but the checking for that takes little time compared to
+   other operations.
+
+   Enhancements:
+
+   mpn_bdiv_qr should be used instead of mpn_tdiv_qr.
+
+*/
+
+int
+mpz_jacobi (mpz_srcptr a, mpz_srcptr b)
+{
+  mp_srcptr  asrcp, bsrcp;
+  mp_size_t  asize, bsize;
+  mp_limb_t  alow, blow;
+  mp_ptr     ap, bp;
+  unsigned   btwos;
+  int        result_bit1;
+  int        res;
+  TMP_DECL;
+
+  asize = SIZ(a);
+  asrcp = PTR(a);
+  alow = asrcp[0];
+
+  bsize = SIZ(b);
+  bsrcp = PTR(b);
+  blow = bsrcp[0];
+
+  /* The MPN jacobi functions require positive a and b, and b odd. So
+     we must to handle the cases of a or b zero, then signs, and then
+     the case of even b.
+  */
+
+  if (bsize == 0)
+    /* (a/0) = [ a = 1 or a = -1 ] */
+    return JACOBI_LS0 (alow, asize);
+
+  if (asize == 0)
+    /* (0/b) = [ b = 1 or b = - 1 ] */
+    return JACOBI_0LS (blow, bsize);
+
+  if ( (((alow | blow) & 1) == 0))
+    /* Common factor of 2 ==> (a/b) = 0 */
+    return 0;
+
+  if (bsize < 0)
+    {
+      /* (a/-1) = -1 if a < 0, +1 if a >= 0 */
+      result_bit1 = (asize < 0) << 1;
+      bsize = -bsize;
+    }
+  else
+    result_bit1 = 0;
+
+  JACOBI_STRIP_LOW_ZEROS (result_bit1, alow, bsrcp, bsize, blow);
+
+  count_trailing_zeros (btwos, blow);
+  blow >>= btwos;
+
+  if (bsize > 1 && btwos > 0)
+    {
+      mp_limb_t b1 = bsrcp[1];
+      blow |= b1 << (GMP_NUMB_BITS - btwos);
+      if (bsize == 2 && (b1 >> btwos) == 0)
+	bsize = 1;
+    }
+
+  if (asize < 0)
+    {
+      /* (-1/b) = -1 iff b = 3 (mod 4) */
+      result_bit1 ^= JACOBI_N1B_BIT1(blow);
+      asize = -asize;
+    }
+
+  JACOBI_STRIP_LOW_ZEROS (result_bit1, blow, asrcp, asize, alow);
+
+  /* Ensure asize >= bsize. Take advantage of the generalized
+     reciprocity law (a/b*2^n) = (b*2^n / a) * RECIP(a,b) */
+
+  if (asize < bsize)
+    {
+      MPN_SRCPTR_SWAP (asrcp, asize, bsrcp, bsize);
+      MP_LIMB_T_SWAP (alow, blow);
+
+      /* NOTE: The value of alow (old blow) is a bit subtle. For this code
+	 path, we get alow as the low, always odd, limb of shifted A. Which is
+	 what we need for the reciprocity update below.
+
+	 However, all other uses of alow assumes that it is *not*
+	 shifted. Luckily, alow matters only when either
+
+	 + btwos > 0, in which case A is always odd
+
+	 + asize == bsize == 1, in which case this code path is never
+	   taken. */
+
+      count_trailing_zeros (btwos, blow);
+      blow >>= btwos;
+
+      if (bsize > 1 && btwos > 0)
+	{
+	  mp_limb_t b1 = bsrcp[1];
+	  blow |= b1 << (GMP_NUMB_BITS - btwos);
+	  if (bsize == 2 && (b1 >> btwos) == 0)
+	    bsize = 1;
+	}
+
+      result_bit1 ^= JACOBI_RECIP_UU_BIT1 (alow, blow);
+    }
+
+  if (bsize == 1)
+    {
+      result_bit1 ^= JACOBI_TWOS_U_BIT1(btwos, alow);
+
+      if (blow == 1)
+	return JACOBI_BIT1_TO_PN (result_bit1);
+
+      if (asize > 1)
+	JACOBI_MOD_OR_MODEXACT_1_ODD (result_bit1, alow, asrcp, asize, blow);
+
+      return mpn_jacobi_base (alow, blow, result_bit1);
+    }
+
+  /* Allocation strategy: For A, we allocate a working copy only for A % B, but
+     when A is much larger than B, we have to allocate space for the large
+     quotient. We use the same area, pointed to by bp, for both the quotient
+     A/B and the working copy of B. */
+
+  TMP_MARK;
+
+  if (asize >= 2*bsize)
+    TMP_ALLOC_LIMBS_2 (ap, bsize, bp, asize - bsize + 1);
+  else
+    TMP_ALLOC_LIMBS_2 (ap, bsize, bp, bsize);
+
+  /* In the case of even B, we conceptually shift out the powers of two first,
+     and then divide A mod B. Hence, when taking those powers of two into
+     account, we must use alow *before* the division. Doing the actual division
+     first is ok, because the point is to remove multiples of B from A, and
+     multiples of 2^k B are good enough. */
+  if (asize > bsize)
+    mpn_tdiv_qr (bp, ap, 0, asrcp, asize, bsrcp, bsize);
+  else
+    MPN_COPY (ap, asrcp, bsize);
+
+  if (btwos > 0)
+    {
+      result_bit1 ^= JACOBI_TWOS_U_BIT1(btwos, alow);
+
+      ASSERT_NOCARRY (mpn_rshift (bp, bsrcp, bsize, btwos));
+      bsize -= (ap[bsize-1] | bp[bsize-1]) == 0;
+    }
+  else
+    MPN_COPY (bp, bsrcp, bsize);
+
+  ASSERT (blow == bp[0]);
+  res = mpn_jacobi_n (ap, bp, bsize,
+		      mpn_jacobi_init (ap[0], blow, (result_bit1>>1) & 1));
+
+  TMP_FREE;
+  return res;
+}
diff --git a/third_party/gmp/mpz/kronsz.c b/third_party/gmp/mpz/kronsz.c
new file mode 100644
index 0000000..92cc971
--- /dev/null
+++ b/third_party/gmp/mpz/kronsz.c
@@ -0,0 +1,137 @@
+/* mpz_si_kronecker -- long+mpz Kronecker/Jacobi symbol.
+
+Copyright 1999-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+int
+mpz_si_kronecker (long a, mpz_srcptr b)
+{
+  mp_srcptr  b_ptr;
+  mp_limb_t  b_low;
+  mp_size_t  b_size;
+  mp_size_t  b_abs_size;
+  mp_limb_t  a_limb, b_rem;
+  unsigned   twos;
+  int        result_bit1;
+
+#if GMP_NUMB_BITS < BITS_PER_ULONG
+  if (a > GMP_NUMB_MAX || a < -GMP_NUMB_MAX)
+    {
+      mp_limb_t  alimbs[2];
+      mpz_t      az;
+      ALLOC(az) = numberof (alimbs);
+      PTR(az) = alimbs;
+      mpz_set_si (az, a);
+      return mpz_kronecker (az, b);
+    }
+#endif
+
+  b_size = SIZ (b);
+  if (b_size == 0)
+    return JACOBI_S0 (a);  /* (a/0) */
+
+  /* account for the effect of the sign of b, then ignore it */
+  result_bit1 = JACOBI_BSGN_SS_BIT1 (a, b_size);
+
+  b_ptr = PTR(b);
+  b_low = b_ptr[0];
+  b_abs_size = ABS (b_size);
+
+  if ((b_low & 1) != 0)
+    {
+      /* b odd */
+
+      result_bit1 ^= JACOBI_ASGN_SU_BIT1 (a, b_low);
+      a_limb = ABS_CAST(mp_limb_t, a);
+
+      if ((a_limb & 1) == 0)
+	{
+	  /* (0/b)=1 for b=+/-1, 0 otherwise */
+	  if (a_limb == 0)
+	    return (b_abs_size == 1 && b_low == 1);
+
+	  /* a even, b odd */
+	  count_trailing_zeros (twos, a_limb);
+	  a_limb >>= twos;
+	  /* (a*2^n/b) = (a/b) * twos(n,a) */
+	  result_bit1 ^= JACOBI_TWOS_U_BIT1 (twos, b_low);
+	}
+    }
+  else
+    {
+      /* (even/even)=0, and (0/b)=0 for b!=+/-1 */
+      if ((a & 1) == 0)
+	return 0;
+
+      /* a odd, b even
+
+	 Establish shifted b_low with valid bit1 for ASGN and RECIP below.
+	 Zero limbs stripped are accounted for, but zero bits on b_low are
+	 not because they remain in {b_ptr,b_abs_size} for the
+	 JACOBI_MOD_OR_MODEXACT_1_ODD. */
+
+      JACOBI_STRIP_LOW_ZEROS (result_bit1, a, b_ptr, b_abs_size, b_low);
+      if ((b_low & 1) == 0)
+	{
+	  if (UNLIKELY (b_low == GMP_NUMB_HIGHBIT))
+	    {
+	      /* need b_ptr[1] to get bit1 in b_low */
+	      if (b_abs_size == 1)
+		{
+		  /* (a/0x80000000) = (a/2)^(BPML-1) */
+		  if ((GMP_NUMB_BITS % 2) == 0)
+		    result_bit1 ^= JACOBI_TWO_U_BIT1 (a);
+		  return JACOBI_BIT1_TO_PN (result_bit1);
+		}
+
+	      /* b_abs_size > 1 */
+	      b_low = b_ptr[1] << 1;
+	    }
+	  else
+	    {
+	      count_trailing_zeros (twos, b_low);
+	      b_low >>= twos;
+	    }
+	}
+
+      result_bit1 ^= JACOBI_ASGN_SU_BIT1 (a, b_low);
+      a_limb = (unsigned long) ABS(a);
+    }
+
+  if (a_limb == 1)
+    return JACOBI_BIT1_TO_PN (result_bit1);  /* (1/b)=1 */
+
+  /* (a/b*2^n) = (b*2^n mod a / a) * recip(a,b) */
+  JACOBI_MOD_OR_MODEXACT_1_ODD (result_bit1, b_rem, b_ptr, b_abs_size, a_limb);
+  result_bit1 ^= JACOBI_RECIP_UU_BIT1 (a_limb, b_low);
+  return mpn_jacobi_base (b_rem, a_limb, result_bit1);
+}
diff --git a/third_party/gmp/mpz/kronuz.c b/third_party/gmp/mpz/kronuz.c
new file mode 100644
index 0000000..ba5c6dd
--- /dev/null
+++ b/third_party/gmp/mpz/kronuz.c
@@ -0,0 +1,129 @@
+/* mpz_ui_kronecker -- ulong+mpz Kronecker/Jacobi symbol.
+
+Copyright 1999-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+int
+mpz_ui_kronecker (unsigned long a, mpz_srcptr b)
+{
+  mp_srcptr  b_ptr;
+  mp_limb_t  b_low;
+  int        b_abs_size;
+  mp_limb_t  b_rem;
+  int        twos;
+  int        result_bit1;
+
+  /* (a/-1)=1 when a>=0, so the sign of b is ignored */
+  b_abs_size = ABSIZ (b);
+
+  if (b_abs_size == 0)
+    return JACOBI_U0 (a);  /* (a/0) */
+
+  if (a > GMP_NUMB_MAX)
+    {
+      mp_limb_t  alimbs[2];
+      mpz_t      az;
+      ALLOC(az) = numberof (alimbs);
+      PTR(az) = alimbs;
+      mpz_set_ui (az, a);
+      return mpz_kronecker (az, b);
+    }
+
+  b_ptr = PTR(b);
+  b_low = b_ptr[0];
+  result_bit1 = 0;
+
+  if (! (b_low & 1))
+    {
+      /* (0/b)=0 for b!=+/-1; and (even/even)=0 */
+      if (! (a & 1))
+	return 0;
+
+      /* a odd, b even
+
+	 Establish shifted b_low with valid bit1 for the RECIP below.  Zero
+	 limbs stripped are accounted for, but zero bits on b_low are not
+	 because they remain in {b_ptr,b_abs_size} for
+	 JACOBI_MOD_OR_MODEXACT_1_ODD. */
+
+      JACOBI_STRIP_LOW_ZEROS (result_bit1, a, b_ptr, b_abs_size, b_low);
+      if (! (b_low & 1))
+	{
+	  if (UNLIKELY (b_low == GMP_NUMB_HIGHBIT))
+	    {
+	      /* need b_ptr[1] to get bit1 in b_low */
+	      if (b_abs_size == 1)
+		{
+		  /* (a/0x80...00) == (a/2)^(NUMB-1) */
+		  if ((GMP_NUMB_BITS % 2) == 0)
+		    {
+		      /* JACOBI_STRIP_LOW_ZEROS does nothing to result_bit1
+			 when GMP_NUMB_BITS is even, so it's still 0. */
+		      ASSERT (result_bit1 == 0);
+		      result_bit1 = JACOBI_TWO_U_BIT1 (a);
+		    }
+		  return JACOBI_BIT1_TO_PN (result_bit1);
+		}
+
+	      /* b_abs_size > 1 */
+	      b_low = b_ptr[1] << 1;
+	    }
+	  else
+	    {
+	      count_trailing_zeros (twos, b_low);
+	      b_low >>= twos;
+	    }
+	}
+    }
+  else
+    {
+      if (a == 0)        /* (0/b)=1 for b=+/-1, 0 otherwise */
+	return (b_abs_size == 1 && b_low == 1);
+
+      if (! (a & 1))
+	{
+	  /* a even, b odd */
+	  count_trailing_zeros (twos, a);
+	  a >>= twos;
+	  /* (a*2^n/b) = (a/b) * (2/a)^n */
+	  result_bit1 = JACOBI_TWOS_U_BIT1 (twos, b_low);
+	}
+    }
+
+  if (a == 1)
+    return JACOBI_BIT1_TO_PN (result_bit1);  /* (1/b)=1 */
+
+  /* (a/b*2^n) = (b*2^n mod a / a) * RECIP(a,b) */
+  JACOBI_MOD_OR_MODEXACT_1_ODD (result_bit1, b_rem, b_ptr, b_abs_size, a);
+  result_bit1 ^= JACOBI_RECIP_UU_BIT1 (a, b_low);
+  return mpn_jacobi_base (b_rem, (mp_limb_t) a, result_bit1);
+}
diff --git a/third_party/gmp/mpz/kronzs.c b/third_party/gmp/mpz/kronzs.c
new file mode 100644
index 0000000..1f63f15
--- /dev/null
+++ b/third_party/gmp/mpz/kronzs.c
@@ -0,0 +1,92 @@
+/* mpz_kronecker_si -- mpz+long Kronecker/Jacobi symbol.
+
+Copyright 1999-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* After the absolute value of b is established it's treated as an unsigned
+   long, because 0x80..00 doesn't fit in a signed long. */
+
+int
+mpz_kronecker_si (mpz_srcptr a, long b)
+{
+  mp_srcptr  a_ptr;
+  mp_size_t  a_size;
+  mp_limb_t  a_rem, b_limb;
+  int        result_bit1;
+
+  a_size = SIZ(a);
+  if (a_size == 0)
+    return JACOBI_0S (b);
+
+#if GMP_NUMB_BITS < BITS_PER_ULONG
+  if (b > GMP_NUMB_MAX || b < -GMP_NUMB_MAX)
+    {
+      mp_limb_t  blimbs[2];
+      mpz_t      bz;
+      ALLOC(bz) = numberof (blimbs);
+      PTR(bz) = blimbs;
+      mpz_set_si (bz, b);
+      return mpz_kronecker (a, bz);
+    }
+#endif
+
+  result_bit1 = JACOBI_BSGN_SS_BIT1 (a_size, b);
+  b_limb = ABS_CAST (unsigned long, b);
+  a_ptr = PTR(a);
+
+  if ((b_limb & 1) == 0)
+    {
+      mp_limb_t  a_low = a_ptr[0];
+      int        twos;
+
+      if (b_limb == 0)
+	return JACOBI_LS0 (a_low, a_size);   /* (a/0) */
+
+      if (! (a_low & 1))
+	return 0;  /* (even/even)=0 */
+
+      /* (a/2)=(2/a) for a odd */
+      count_trailing_zeros (twos, b_limb);
+      b_limb >>= twos;
+      result_bit1 ^= JACOBI_TWOS_U_BIT1 (twos, a_low);
+    }
+
+  if (b_limb == 1)
+    return JACOBI_BIT1_TO_PN (result_bit1);  /* (a/1)=1 for any a */
+
+  result_bit1 ^= JACOBI_ASGN_SU_BIT1 (a_size, b_limb);
+  a_size = ABS(a_size);
+
+  /* (a/b) = (a mod b / b) */
+  JACOBI_MOD_OR_MODEXACT_1_ODD (result_bit1, a_rem, a_ptr, a_size, b_limb);
+  return mpn_jacobi_base (a_rem, b_limb, result_bit1);
+}
diff --git a/third_party/gmp/mpz/kronzu.c b/third_party/gmp/mpz/kronzu.c
new file mode 100644
index 0000000..b4fbf79
--- /dev/null
+++ b/third_party/gmp/mpz/kronzu.c
@@ -0,0 +1,88 @@
+/* mpz_kronecker_ui -- mpz+ulong Kronecker/Jacobi symbol.
+
+Copyright 1999-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+int
+mpz_kronecker_ui (mpz_srcptr a, unsigned long b)
+{
+  mp_srcptr  a_ptr;
+  mp_size_t  a_size;
+  mp_limb_t  a_rem;
+  int        result_bit1;
+
+  a_size = SIZ(a);
+  if (a_size == 0)
+    return JACOBI_0U (b);
+
+  if (b > GMP_NUMB_MAX)
+    {
+      mp_limb_t  blimbs[2];
+      mpz_t      bz;
+      ALLOC(bz) = numberof (blimbs);
+      PTR(bz) = blimbs;
+      mpz_set_ui (bz, b);
+      return mpz_kronecker (a, bz);
+    }
+
+  a_ptr = PTR(a);
+  if ((b & 1) != 0)
+    {
+      result_bit1 = JACOBI_ASGN_SU_BIT1 (a_size, b);
+    }
+  else
+    {
+      mp_limb_t  a_low = a_ptr[0];
+      int        twos;
+
+      if (b == 0)
+	return JACOBI_LS0 (a_low, a_size);   /* (a/0) */
+
+      if (! (a_low & 1))
+	return 0;  /* (even/even)=0 */
+
+      /* (a/2)=(2/a) for a odd */
+      count_trailing_zeros (twos, b);
+      b >>= twos;
+      result_bit1 = (JACOBI_TWOS_U_BIT1 (twos, a_low)
+		     ^ JACOBI_ASGN_SU_BIT1 (a_size, b));
+    }
+
+  if (b == 1)
+    return JACOBI_BIT1_TO_PN (result_bit1);  /* (a/1)=1 for any a */
+
+  a_size = ABS(a_size);
+
+  /* (a/b) = (a mod b / b) */
+  JACOBI_MOD_OR_MODEXACT_1_ODD (result_bit1, a_rem, a_ptr, a_size, b);
+  return mpn_jacobi_base (a_rem, (mp_limb_t) b, result_bit1);
+}
diff --git a/third_party/gmp/mpz/lcm.c b/third_party/gmp/mpz/lcm.c
new file mode 100644
index 0000000..2807ef7
--- /dev/null
+++ b/third_party/gmp/mpz/lcm.c
@@ -0,0 +1,87 @@
+/* mpz_lcm -- mpz/mpz least common multiple.
+
+Copyright 1996, 2000, 2001, 2005, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_lcm (mpz_ptr r, mpz_srcptr u, mpz_srcptr v)
+{
+  mpz_t g;
+  mp_size_t usize, vsize;
+  TMP_DECL;
+
+  usize = SIZ (u);
+  vsize = SIZ (v);
+  if (usize == 0 || vsize == 0)
+    {
+      SIZ (r) = 0;
+      return;
+    }
+  usize = ABS (usize);
+  vsize = ABS (vsize);
+
+  if (vsize == 1 || usize == 1)
+    {
+      mp_limb_t  vl, gl, c;
+      mp_srcptr  up;
+      mp_ptr     rp;
+
+      if (usize == 1)
+	{
+	  usize = vsize;
+	  MPZ_SRCPTR_SWAP (u, v);
+	}
+
+      MPZ_REALLOC (r, usize+1);
+
+      up = PTR(u);
+      vl = PTR(v)[0];
+      gl = mpn_gcd_1 (up, usize, vl);
+      vl /= gl;
+
+      rp = PTR(r);
+      c = mpn_mul_1 (rp, up, usize, vl);
+      rp[usize] = c;
+      usize += (c != 0);
+      SIZ(r) = usize;
+      return;
+    }
+
+  TMP_MARK;
+  MPZ_TMP_INIT (g, usize); /* v != 0 implies |gcd(u,v)| <= |u| */
+
+  mpz_gcd (g, u, v);
+  mpz_divexact (g, u, g);
+  mpz_mul (r, g, v);
+
+  SIZ (r) = ABS (SIZ (r));	/* result always positive */
+
+  TMP_FREE;
+}
diff --git a/third_party/gmp/mpz/lcm_ui.c b/third_party/gmp/mpz/lcm_ui.c
new file mode 100644
index 0000000..1f199b7
--- /dev/null
+++ b/third_party/gmp/mpz/lcm_ui.c
@@ -0,0 +1,78 @@
+/* mpz_lcm_ui -- least common multiple of mpz and ulong.
+
+Copyright 2001, 2002, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+void
+mpz_lcm_ui (mpz_ptr r, mpz_srcptr u, unsigned long v)
+{
+  mp_size_t      usize;
+  mp_srcptr      up;
+  mp_ptr         rp;
+  unsigned long  g;
+  mp_limb_t      c;
+
+#if BITS_PER_ULONG > GMP_NUMB_BITS  /* avoid warnings about shift amount */
+  if (v > GMP_NUMB_MAX)
+    {
+      mpz_t vz;
+      mp_limb_t vlimbs[2];
+      vlimbs[0] = v & GMP_NUMB_MASK;
+      vlimbs[1] = v >> GMP_NUMB_BITS;
+      PTR(vz) = vlimbs;
+      SIZ(vz) = 2;
+      mpz_lcm (r, u, vz);
+      return;
+    }
+#endif
+
+  /* result zero if either operand zero */
+  usize = SIZ(u);
+  if (usize == 0 || v == 0)
+    {
+      SIZ(r) = 0;
+      return;
+    }
+  usize = ABS(usize);
+
+  MPZ_REALLOC (r, usize+1);
+
+  up = PTR(u);
+  g = (unsigned long) mpn_gcd_1 (up, usize, (mp_limb_t) v);
+  v /= g;
+
+  rp = PTR(r);
+  c = mpn_mul_1 (rp, up, usize, (mp_limb_t) v);
+  rp[usize] = c;
+  usize += (c != 0);
+  SIZ(r) = usize;
+}
diff --git a/third_party/gmp/mpz/limbs_finish.c b/third_party/gmp/mpz/limbs_finish.c
new file mode 100644
index 0000000..a02839d
--- /dev/null
+++ b/third_party/gmp/mpz/limbs_finish.c
@@ -0,0 +1,39 @@
+/* mpz_finish_limbs -- Update mpz after writing to the limb array.
+
+Copyright 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_limbs_finish (mpz_ptr x, mp_size_t xs)
+{
+  mp_size_t xn = ABS(xs);
+  MPN_NORMALIZE (PTR (x), xn);
+  SIZ (x) = xs < 0 ? -xn : xn;
+}
diff --git a/third_party/gmp/mpz/limbs_modify.c b/third_party/gmp/mpz/limbs_modify.c
new file mode 100644
index 0000000..a778b6e
--- /dev/null
+++ b/third_party/gmp/mpz/limbs_modify.c
@@ -0,0 +1,38 @@
+/* mpz_limbs_modify -- Read-and-modify access to the mpn-style limb array.
+
+Copyright 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+mp_ptr
+mpz_limbs_modify (mpz_ptr x, mp_size_t n)
+{
+  ASSERT (n > 0);
+  return MPZ_REALLOC (x, n);
+}
diff --git a/third_party/gmp/mpz/limbs_read.c b/third_party/gmp/mpz/limbs_read.c
new file mode 100644
index 0000000..705f0c1
--- /dev/null
+++ b/third_party/gmp/mpz/limbs_read.c
@@ -0,0 +1,37 @@
+/* mpz_limbs_read -- Read access to the mpn-style limb array.
+
+Copyright 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+mp_srcptr
+mpz_limbs_read (mpz_srcptr x)
+{
+  return PTR(x);
+}
diff --git a/third_party/gmp/mpz/limbs_write.c b/third_party/gmp/mpz/limbs_write.c
new file mode 100644
index 0000000..b116ad0
--- /dev/null
+++ b/third_party/gmp/mpz/limbs_write.c
@@ -0,0 +1,38 @@
+/* mpz_limbs_write -- Write access to the mpn-style limb array.
+
+Copyright 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+mp_ptr
+mpz_limbs_write (mpz_ptr x, mp_size_t n)
+{
+  ASSERT (n > 0);
+  return MPZ_NEWALLOC (x, n);
+}
diff --git a/third_party/gmp/mpz/lucmod.c b/third_party/gmp/mpz/lucmod.c
new file mode 100644
index 0000000..0dad48c
--- /dev/null
+++ b/third_party/gmp/mpz/lucmod.c
@@ -0,0 +1,127 @@
+/* mpz_lucas_mod -- Helper function for the strong Lucas
+   primality test.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2018 Free Software Foundation, Inc.
+
+Contributed by Marco Bodrato.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/* Computes V_{k+1}, Q^{k+1} (mod n) for the Lucas' sequence	*/
+/* with P=1, Q=Q; k = n>>b0.	*/
+/* Requires n > 4; b0 > 0; -2*Q must not overflow a long.	*/
+/* If U_{k+1}==0 (mod n) or V_{k+1}==0 (mod n), it returns 1,	*/
+/* otherwise it returns 0 and sets V=V_{k+1} and Qk=Q^{k+1}.	*/
+/* V will never grow beyond SIZ(n), Qk not beyond 2*SIZ(n).	*/
+int
+mpz_lucas_mod (mpz_ptr V, mpz_ptr Qk, long Q,
+	       mp_bitcnt_t b0, mpz_srcptr n, mpz_ptr T1, mpz_ptr T2)
+{
+  mp_bitcnt_t bs;
+  int res;
+
+  ASSERT (b0 > 0);
+  ASSERT (SIZ (n) > 1 || SIZ (n) > 0 && PTR (n) [0] > 4);
+
+  mpz_set_ui (V, 1); /* U1 = 1 */
+  bs = mpz_sizeinbase (n, 2) - 2;
+  if (UNLIKELY (bs < b0))
+    {
+      /* n = 2^b0 - 1, should we use Lucas-Lehmer instead? */
+      ASSERT (bs == b0 - 2);
+      mpz_set_si (Qk, Q);
+      return 0;
+    }
+  mpz_set_ui (Qk, 1); /* U2 = 1 */
+
+  do
+    {
+      /* We use the iteration suggested in "Elementary Number Theory"	*/
+      /* by Peter Hackman (November 1, 2009), section "L.XVII Scalar	*/
+      /* Formulas", from http://hackmat.se/kurser/TATM54/booktot.pdf	*/
+      /* U_{2k} = 2*U_{k+1}*U_k - P*U_k^2	*/
+      /* U_{2k+1} = U_{k+1}^2  - Q*U_k^2	*/
+      /* U_{2k+2} = P*U_{k+1}^2 - 2*Q*U_{k+1}*U_k	*/
+      /* We note that U_{2k+2} = P*U_{2k+1} - Q*U_{2k}	*/
+      /* The formulas are specialized for P=1, and only squares:	*/
+      /* U_{2k}   = U_{k+1}^2 - |U_{k+1} - U_k|^2	*/
+      /* U_{2k+1} = U_{k+1}^2 - Q*U_k^2		*/
+      /* U_{2k+2} = U_{2k+1}  - Q*U_{2k}	*/
+      mpz_mul (T1, Qk, Qk);	/* U_{k+1}^2		*/
+      mpz_sub (Qk, V, Qk);	/* |U_{k+1} - U_k|	*/
+      mpz_mul (T2, Qk, Qk);	/* |U_{k+1} - U_k|^2	*/
+      mpz_mul (Qk, V, V);	/* U_k^2		*/
+      mpz_sub (T2, T1, T2);	/* U_{k+1}^2 - (U_{k+1} - U_k)^2	*/
+      if (Q > 0)		/* U_{k+1}^2 - Q U_k^2 = U_{2k+1}	*/
+	mpz_submul_ui (T1, Qk, Q);
+      else
+	mpz_addmul_ui (T1, Qk, NEG_CAST (unsigned long, Q));
+
+      /* A step k->k+1 is performed if the bit in $n$ is 1	*/
+      if (mpz_tstbit (n, bs))
+	{
+	  /* U_{2k+2} = U_{2k+1} - Q*U_{2k}	*/
+	  mpz_mul_si (T2, T2, Q);
+	  mpz_sub (T2, T1, T2);
+	  mpz_swap (T1, T2);
+	}
+      mpz_tdiv_r (Qk, T1, n);
+      mpz_tdiv_r (V, T2, n);
+    } while (--bs >= b0);
+
+  res = SIZ (Qk) == 0;
+  if (!res) {
+    mpz_mul_si (T1, V, -2*Q);
+    mpz_add (T1, Qk, T1);	/* V_k = U_k - 2Q*U_{k-1} */
+    mpz_tdiv_r (V, T1, n);
+    res = SIZ (V) == 0;
+    if (!res && b0 > 1) {
+      /* V_k and Q^k will be needed for further check, compute them.	*/
+      /* FIXME: Here we compute V_k^2 and store V_k, but the former	*/
+      /* will be recomputed by the calling function, shoul we store	*/
+      /* that instead?							*/
+      mpz_mul (T2, T1, T1);	/* V_k^2 */
+      mpz_mul (T1, Qk, Qk);	/* P^2 U_k^2 = U_k^2 */
+      mpz_sub (T2, T2, T1);
+      ASSERT (SIZ (T2) == 0 || PTR (T2) [0] % 4 == 0);
+      mpz_tdiv_q_2exp (T2, T2, 2);	/* (V_k^2 - P^2 U_k^2) / 4 */
+      if (Q > 0)		/* (V_k^2 - (P^2 -4Q) U_k^2) / 4 = Q^k */
+	mpz_addmul_ui (T2, T1, Q);
+      else
+	mpz_submul_ui (T2, T1, NEG_CAST (unsigned long, Q));
+      mpz_tdiv_r (Qk, T2, n);
+    }
+  }
+
+  return res;
+}
diff --git a/third_party/gmp/mpz/lucnum2_ui.c b/third_party/gmp/mpz/lucnum2_ui.c
new file mode 100644
index 0000000..3cc3d7b
--- /dev/null
+++ b/third_party/gmp/mpz/lucnum2_ui.c
@@ -0,0 +1,94 @@
+/* mpz_lucnum2_ui -- calculate Lucas numbers.
+
+Copyright 2001, 2003, 2005, 2012, 2015, 2016, 2018 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp-impl.h"
+
+
+void
+mpz_lucnum2_ui (mpz_ptr ln, mpz_ptr lnsub1, unsigned long n)
+{
+  mp_ptr     lp, l1p, f1p;
+  mp_size_t  size;
+  mp_limb_t  c;
+  TMP_DECL;
+
+  ASSERT (ln != lnsub1);
+
+  /* handle small n quickly, and hide the special case for L[-1]=-1 */
+  if (n <= FIB_TABLE_LUCNUM_LIMIT)
+    {
+      mp_limb_t  f  = FIB_TABLE (n);
+      mp_limb_t  f1 = FIB_TABLE ((int) n - 1);
+
+      /* L[n] = F[n] + 2F[n-1] */
+      MPZ_NEWALLOC (ln, 1)[0] = f + 2*f1;
+      SIZ(ln) = 1;
+
+      /* L[n-1] = 2F[n] - F[n-1], but allow for L[-1]=-1 */
+      MPZ_NEWALLOC (lnsub1, 1)[0] = (n == 0 ? 1 : 2*f - f1);
+      SIZ(lnsub1) = (n == 0 ? -1 : 1);
+
+      return;
+    }
+
+  TMP_MARK;
+  size = MPN_FIB2_SIZE (n);
+  f1p = TMP_ALLOC_LIMBS (size);
+
+  lp  = MPZ_NEWALLOC (ln,     size+1);
+  l1p = MPZ_NEWALLOC (lnsub1, size+1);
+
+  size = mpn_fib2_ui (l1p, f1p, n);
+
+  /* L[n] = F[n] + 2F[n-1] */
+#if HAVE_NATIVE_mpn_addlsh1_n
+  c = mpn_addlsh1_n (lp, l1p, f1p, size);
+#else
+  c = mpn_lshift (lp, f1p, size, 1);
+  c += mpn_add_n (lp, lp, l1p, size);
+#endif
+  lp[size] = c;
+  SIZ(ln) = size + (c != 0);
+
+  /* L[n-1] = 2F[n] - F[n-1] */
+#if HAVE_NATIVE_mpn_rsblsh1_n
+  c = mpn_rsblsh1_n (l1p, f1p, l1p, size);
+#else
+  c = mpn_lshift (l1p, l1p, size, 1);
+  c -= mpn_sub_n (l1p, l1p, f1p, size);
+#endif
+  ASSERT ((mp_limb_signed_t) c >= 0);
+  l1p[size] = c;
+  SIZ(lnsub1) = size + (c != 0);
+
+  TMP_FREE;
+}
diff --git a/third_party/gmp/mpz/lucnum_ui.c b/third_party/gmp/mpz/lucnum_ui.c
new file mode 100644
index 0000000..4213bb7
--- /dev/null
+++ b/third_party/gmp/mpz/lucnum_ui.c
@@ -0,0 +1,208 @@
+/* mpz_lucnum_ui -- calculate Lucas number.
+
+Copyright 2001, 2003, 2005, 2011, 2012, 2015, 2016 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp-impl.h"
+
+
+/* change this to "#define TRACE(x) x" for diagnostics */
+#define TRACE(x)
+
+
+/* Notes:
+
+   For the +4 in L[2k+1] when k is even, all L[4m+3] == 4, 5 or 7 mod 8, so
+   there can't be an overflow applying +4 to just the low limb (since that
+   would leave 0, 1, 2 or 3 mod 8).
+
+   For the -4 in L[2k+1] when k is even, it seems (no proof) that
+   L[3*2^(b-2)-3] == -4 mod 2^b, so for instance with a 32-bit limb
+   L[0xBFFFFFFD] == 0xFFFFFFFC mod 2^32, and this implies a borrow from the
+   low limb.  Obviously L[0xBFFFFFFD] is a huge number, but it's at least
+   conceivable to calculate it, so it probably should be handled.
+
+   For the -2 in L[2k] with k even, it seems (no proof) L[2^(b-1)] == -1 mod
+   2^b, so for instance in 32-bits L[0x80000000] has a low limb of
+   0xFFFFFFFF so there would have been a borrow.  Again L[0x80000000] is
+   obviously huge, but probably should be made to work.  */
+
+void
+mpz_lucnum_ui (mpz_ptr ln, unsigned long n)
+{
+  mp_size_t  lalloc, xalloc, lsize, xsize;
+  mp_ptr     lp, xp;
+  mp_limb_t  c;
+  int        zeros;
+  TMP_DECL;
+
+  TRACE (printf ("mpn_lucnum_ui n=%lu\n", n));
+
+  if (n <= FIB_TABLE_LUCNUM_LIMIT)
+    {
+      /* L[n] = F[n] + 2F[n-1] */
+      MPZ_NEWALLOC (ln, 1)[0] = FIB_TABLE(n) + 2 * FIB_TABLE ((int) n - 1);
+      SIZ(ln) = 1;
+      return;
+    }
+
+  /* +1 since L[n]=F[n]+2F[n-1] might be 1 limb bigger than F[n], further +1
+     since square or mul used below might need an extra limb over the true
+     size */
+  lalloc = MPN_FIB2_SIZE (n) + 2;
+  lp = MPZ_NEWALLOC (ln, lalloc);
+
+  TMP_MARK;
+  xalloc = lalloc;
+  xp = TMP_ALLOC_LIMBS (xalloc);
+
+  /* Strip trailing zeros from n, until either an odd number is reached
+     where the L[2k+1] formula can be used, or until n fits within the
+     FIB_TABLE data.  The table is preferred of course.  */
+  zeros = 0;
+  for (;;)
+    {
+      if (n & 1)
+	{
+	  /* L[2k+1] = 5*F[k-1]*(2*F[k]+F[k-1]) - 4*(-1)^k */
+
+	  mp_size_t  yalloc, ysize;
+	  mp_ptr     yp;
+
+	  TRACE (printf ("  initial odd n=%lu\n", n));
+
+	  yalloc = MPN_FIB2_SIZE (n/2);
+	  yp = TMP_ALLOC_LIMBS (yalloc);
+	  ASSERT (xalloc >= yalloc);
+
+	  xsize = mpn_fib2_ui (xp, yp, n/2);
+
+	  /* possible high zero on F[k-1] */
+	  ysize = xsize;
+	  ysize -= (yp[ysize-1] == 0);
+	  ASSERT (yp[ysize-1] != 0);
+
+	  /* xp = 2*F[k] + F[k-1] */
+#if HAVE_NATIVE_mpn_addlsh1_n
+	  c = mpn_addlsh1_n (xp, yp, xp, xsize);
+#else
+	  c = mpn_lshift (xp, xp, xsize, 1);
+	  c += mpn_add_n (xp, xp, yp, xsize);
+#endif
+	  ASSERT (xalloc >= xsize+1);
+	  xp[xsize] = c;
+	  xsize += (c != 0);
+	  ASSERT (xp[xsize-1] != 0);
+
+	  ASSERT (lalloc >= xsize + ysize);
+	  c = mpn_mul (lp, xp, xsize, yp, ysize);
+	  lsize = xsize + ysize;
+	  lsize -= (c == 0);
+
+	  /* lp = 5*lp */
+#if HAVE_NATIVE_mpn_addlsh2_n
+	  c = mpn_addlsh2_n (lp, lp, lp, lsize);
+#else
+	  /* FIXME: Is this faster than mpn_mul_1 ? */
+	  c = mpn_lshift (xp, lp, lsize, 2);
+	  c += mpn_add_n (lp, lp, xp, lsize);
+#endif
+	  ASSERT (lalloc >= lsize+1);
+	  lp[lsize] = c;
+	  lsize += (c != 0);
+
+	  /* lp = lp - 4*(-1)^k */
+	  if (n & 2)
+	    {
+	      /* no overflow, see comments above */
+	      ASSERT (lp[0] <= MP_LIMB_T_MAX-4);
+	      lp[0] += 4;
+	    }
+	  else
+	    {
+	      /* won't go negative */
+	      MPN_DECR_U (lp, lsize, CNST_LIMB(4));
+	    }
+
+	  TRACE (mpn_trace ("  l",lp, lsize));
+	  break;
+	}
+
+      MP_PTR_SWAP (xp, lp); /* balance the swaps wanted in the L[2k] below */
+      zeros++;
+      n /= 2;
+
+      if (n <= FIB_TABLE_LUCNUM_LIMIT)
+	{
+	  /* L[n] = F[n] + 2F[n-1] */
+	  lp[0] = FIB_TABLE (n) + 2 * FIB_TABLE ((int) n - 1);
+	  lsize = 1;
+
+	  TRACE (printf ("  initial small n=%lu\n", n);
+		 mpn_trace ("  l",lp, lsize));
+	  break;
+	}
+    }
+
+  for ( ; zeros != 0; zeros--)
+    {
+      /* L[2k] = L[k]^2 + 2*(-1)^k */
+
+      TRACE (printf ("  zeros=%d\n", zeros));
+
+      ASSERT (xalloc >= 2*lsize);
+      mpn_sqr (xp, lp, lsize);
+      lsize *= 2;
+      lsize -= (xp[lsize-1] == 0);
+
+      /* First time around the loop k==n determines (-1)^k, after that k is
+	 always even and we set n=0 to indicate that.  */
+      if (n & 1)
+	{
+	  /* L[n]^2 == 0 or 1 mod 4, like all squares, so +2 gives no carry */
+	  ASSERT (xp[0] <= MP_LIMB_T_MAX-2);
+	  xp[0] += 2;
+	  n = 0;
+	}
+      else
+	{
+	  /* won't go negative */
+	  MPN_DECR_U (xp, lsize, CNST_LIMB(2));
+	}
+
+      MP_PTR_SWAP (xp, lp);
+      ASSERT (lp[lsize-1] != 0);
+    }
+
+  /* should end up in the right spot after all the xp/lp swaps */
+  ASSERT (lp == PTR(ln));
+  SIZ(ln) = lsize;
+
+  TMP_FREE;
+}
diff --git a/third_party/gmp/mpz/mfac_uiui.c b/third_party/gmp/mpz/mfac_uiui.c
new file mode 100644
index 0000000..8595a9b
--- /dev/null
+++ b/third_party/gmp/mpz/mfac_uiui.c
@@ -0,0 +1,140 @@
+/* mpz_mfac_uiui(RESULT, N, M) -- Set RESULT to N!^(M) = N(N-M)(N-2M)...
+
+Contributed to the GNU project by Marco Bodrato.
+
+Copyright 2012, 2013, 2015, 2016 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/*************************************************************/
+/* Section macros: common macros, for swing/fac/bin (&sieve) */
+/*************************************************************/
+
+#define FACTOR_LIST_STORE(P, PR, MAX_PR, VEC, I)		\
+  do {								\
+    if ((PR) > (MAX_PR)) {					\
+      (VEC)[(I)++] = (PR);					\
+      (PR) = (P);						\
+    } else							\
+      (PR) *= (P);						\
+  } while (0)
+
+/*********************************************************/
+/* Section oder factorials:                              */
+/*********************************************************/
+
+/* mpz_mfac_uiui (x, n, m) computes x = n!^(m) = n*(n-m)*(n-2m)*...   */
+
+void
+mpz_mfac_uiui (mpz_ptr x, unsigned long n, unsigned long m)
+{
+  ASSERT (n <= GMP_NUMB_MAX);
+  ASSERT (m != 0);
+
+  if ((n < 3) | (n - 3 < m - 1)) { /* (n < 3 || n - 1 <= m || m == 0) */
+    MPZ_NEWALLOC (x, 1)[0] = n + (n == 0);
+    SIZ (x) = 1;
+  } else { /* 0 < m < n - 1 < GMP_NUMB_MAX */
+    mp_limb_t g, sn;
+    mpz_t     t;
+
+    sn = n;
+    g = mpn_gcd_1 (&sn, 1, m);
+    if (g > 1) { n/=g; m/=g; }
+
+    if (m <= 2) { /* fac or 2fac */
+      if (m == 1) {
+	if (g > 2) {
+	  mpz_init (t);
+	  mpz_fac_ui (t, n);
+	  sn = n;
+	} else {
+	  if (g == 2)
+	    mpz_2fac_ui (x, n << 1);
+	  else
+	    mpz_fac_ui (x, n);
+	  return;
+	}
+      } else { /* m == 2 */
+	if (g > 1) {
+	  mpz_init (t);
+	  mpz_2fac_ui (t, n);
+	  sn = n / 2 + 1;
+	} else {
+	  mpz_2fac_ui (x, n);
+	  return;
+	}
+      }
+    } else { /* m >= 3, gcd(n,m) = 1 */
+      mp_limb_t *factors;
+      mp_limb_t prod, max_prod;
+      mp_size_t j;
+      TMP_DECL;
+
+      sn = n / m + 1;
+
+      j = 0;
+      prod = n;
+      n -= m;
+      max_prod = GMP_NUMB_MAX / n;
+
+      if (g > 1)
+	factors = MPZ_NEWALLOC (x, sn / log_n_max (n) + 2);
+      else {
+	TMP_MARK;
+	factors = TMP_ALLOC_LIMBS (sn / log_n_max (n) + 2);
+      }
+
+      for (; n > m; n -= m)
+	FACTOR_LIST_STORE (n, prod, max_prod, factors, j);
+
+      factors[j++] = n;
+      factors[j++] = prod;
+
+      if (g > 1) {
+	mpz_init (t);
+	mpz_prodlimbs (t, factors, j);
+      } else {
+	mpz_prodlimbs (x, factors, j);
+	TMP_FREE;
+	return;
+      }
+    }
+
+    {
+      mpz_t p;
+
+      mpz_init (p);
+      mpz_ui_pow_ui (p, g, sn); /* g^sn */
+      mpz_mul (x, p, t);
+      mpz_clear (p);
+      mpz_clear (t);
+    }
+  }
+}
diff --git a/third_party/gmp/mpz/millerrabin.c b/third_party/gmp/mpz/millerrabin.c
new file mode 100644
index 0000000..1f5d482
--- /dev/null
+++ b/third_party/gmp/mpz/millerrabin.c
@@ -0,0 +1,222 @@
+/* mpz_millerrabin(n,reps) -- An implementation of the probabilistic primality
+   test found in Knuth's Seminumerical Algorithms book.  If the function
+   mpz_millerrabin() returns 0 then n is not prime.  If it returns 1, then n is
+   'probably' prime.  The probability of a false positive is (1/4)**reps, where
+   reps is the number of internal passes of the probabilistic algorithm.  Knuth
+   indicates that 25 passes are reasonable.
+
+   With the current implementation, the first 24 MR-tests are substituted by a
+   Baillie-PSW probable prime test.
+
+   This implementation the Baillie-PSW test was checked up to 19*2^46,
+   for smaller values no MR-test is performed, regardless of reps, and
+   2 ("surely prime") is returned if the number was not proved composite.
+
+   If GMP_BPSW_NOFALSEPOSITIVES_UPTO_64BITS is defined as non-zero,
+   the code assumes that the Baillie-PSW test was checked up to 2^64.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 1991, 1993, 1994, 1996-2002, 2005, 2014, 2018, 2019 Free
+Software Foundation, Inc.
+
+Contributed by John Amanatides.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#ifndef GMP_BPSW_NOFALSEPOSITIVES_UPTO_64BITS
+#define GMP_BPSW_NOFALSEPOSITIVES_UPTO_64BITS 0
+#endif
+
+static int millerrabin (mpz_srcptr,
+			mpz_ptr, mpz_ptr,
+			mpz_srcptr, unsigned long int);
+
+int
+mpz_millerrabin (mpz_srcptr n, int reps)
+{
+  mpz_t nm, x, y, q;
+  unsigned long int k;
+  gmp_randstate_t rstate;
+  int is_prime;
+  TMP_DECL;
+  TMP_MARK;
+
+  ASSERT (SIZ (n) > 0);
+  MPZ_TMP_INIT (nm, SIZ (n) + 1);
+  mpz_tdiv_q_2exp (nm, n, 1);
+
+  MPZ_TMP_INIT (x, SIZ (n) + 1);
+  MPZ_TMP_INIT (y, 2 * SIZ (n)); /* mpz_powm_ui needs excessive memory!!! */
+  MPZ_TMP_INIT (q, SIZ (n));
+
+  /* Find q and k, where q is odd and n = 1 + 2**k * q.  */
+  k = mpz_scan1 (nm, 0L);
+  mpz_tdiv_q_2exp (q, nm, k);
+  ++k;
+
+  /* BPSW test */
+  mpz_set_ui (x, 2);
+  is_prime = millerrabin (n, x, y, q, k) && mpz_stronglucas (n, x, y);
+
+  if (is_prime)
+    {
+      if (
+#if GMP_BPSW_NOFALSEPOSITIVES_UPTO_64BITS
+	  /* Consider numbers up to 2^64 that pass the BPSW test as primes. */
+#if GMP_NUMB_BITS <= 64
+	  SIZ (n) <= 64 / GMP_NUMB_BITS
+#else
+	  0
+#endif
+#if 64 % GMP_NUMB_BITS != 0
+	  || SIZ (n) - 64 / GMP_NUMB_BITS == (PTR (n) [64 / GMP_NUMB_BITS] < CNST_LIMB(1) << 64 % GMP_NUMB_BITS)
+#endif
+#else
+	  /* Consider numbers up to 19*2^46 that pass the BPSW test as primes.
+	     This implementation was tested up to 19*2^46 = 2^50+2^47+2^46 */
+	  /* 2^4 < 19 = 0b10011 < 2^5 */
+#define GMP_BPSW_LIMB_CONST CNST_LIMB(19)
+#define GMP_BPSW_BITS_CONST (LOG2C(19) - 1)
+#define GMP_BPSW_BITS_LIMIT (46 + GMP_BPSW_BITS_CONST)
+
+#define GMP_BPSW_LIMBS_LIMIT (GMP_BPSW_BITS_LIMIT / GMP_NUMB_BITS)
+#define GMP_BPSW_BITS_MOD (GMP_BPSW_BITS_LIMIT % GMP_NUMB_BITS)
+
+#if GMP_NUMB_BITS <=  GMP_BPSW_BITS_LIMIT
+	  SIZ (n) <= GMP_BPSW_LIMBS_LIMIT
+#else
+	  0
+#endif
+#if GMP_BPSW_BITS_MOD >=  GMP_BPSW_BITS_CONST
+	  || SIZ (n) - GMP_BPSW_LIMBS_LIMIT == (PTR (n) [GMP_BPSW_LIMBS_LIMIT] < GMP_BPSW_LIMB_CONST << (GMP_BPSW_BITS_MOD - GMP_BPSW_BITS_CONST))
+#else
+#if GMP_BPSW_BITS_MOD != 0
+	  || SIZ (n) - GMP_BPSW_LIMBS_LIMIT == (PTR (n) [GMP_BPSW_LIMBS_LIMIT] < GMP_BPSW_LIMB_CONST >> (GMP_BPSW_BITS_CONST -  GMP_BPSW_BITS_MOD))
+#else
+#if GMP_NUMB_BITS > GMP_BPSW_BITS_CONST
+	  || SIZ (nm) - GMP_BPSW_LIMBS_LIMIT + 1 == (PTR (nm) [GMP_BPSW_LIMBS_LIMIT - 1] < GMP_BPSW_LIMB_CONST << (GMP_NUMB_BITS - 1 - GMP_BPSW_BITS_CONST))
+#endif
+#endif
+#endif
+
+#undef GMP_BPSW_BITS_LIMIT
+#undef GMP_BPSW_LIMB_CONST
+#undef GMP_BPSW_BITS_CONST
+#undef GMP_BPSW_LIMBS_LIMIT
+#undef GMP_BPSW_BITS_MOD
+
+#endif
+	  )
+	is_prime = 2;
+      else
+	{
+	  reps -= 24;
+	  if (reps > 0)
+	    {
+	      /* (n-5)/2 */
+	      mpz_sub_ui (nm, nm, 2L);
+	      ASSERT (mpz_cmp_ui (nm, 1L) >= 0);
+
+	      gmp_randinit_default (rstate);
+
+	      do
+		{
+		  /* 3 to (n-1)/2 inclusive, don't want 1, 0 or 2 */
+		  mpz_urandomm (x, rstate, nm);
+		  mpz_add_ui (x, x, 3L);
+
+		  is_prime = millerrabin (n, x, y, q, k);
+		} while (--reps > 0 && is_prime);
+
+	      gmp_randclear (rstate);
+	    }
+	}
+    }
+  TMP_FREE;
+  return is_prime;
+}
+
+static int
+mod_eq_m1 (mpz_srcptr x, mpz_srcptr m)
+{
+  mp_size_t ms;
+  mp_srcptr mp, xp;
+
+  ms = SIZ (m);
+  if (SIZ (x) != ms)
+    return 0;
+  ASSERT (ms > 0);
+
+  mp = PTR (m);
+  xp = PTR (x);
+  ASSERT ((mp[0] - 1) == (mp[0] ^ 1)); /* n is odd */
+
+  if ((*xp ^ CNST_LIMB(1) ^ *mp) != CNST_LIMB(0)) /* xp[0] != mp[0] - 1 */
+    return 0;
+  else
+    {
+      int cmp;
+
+      --ms;
+      ++xp;
+      ++mp;
+
+      MPN_CMP (cmp, xp, mp, ms);
+
+      return cmp == 0;
+    }
+}
+
+static int
+millerrabin (mpz_srcptr n, mpz_ptr x, mpz_ptr y,
+	     mpz_srcptr q, unsigned long int k)
+{
+  unsigned long int i;
+
+  mpz_powm (y, x, q, n);
+
+  if (mpz_cmp_ui (y, 1L) == 0 || mod_eq_m1 (y, n))
+    return 1;
+
+  for (i = 1; i < k; i++)
+    {
+      mpz_powm_ui (y, y, 2L, n);
+      if (mod_eq_m1 (y, n))
+	return 1;
+      /* y == 1 means that the previous y was a non-trivial square root
+	 of 1 (mod n). y == 0 means that n is a power of the base.
+	 In either case, n is not prime. */
+      if (mpz_cmp_ui (y, 1L) <= 0)
+	return 0;
+    }
+  return 0;
+}
diff --git a/third_party/gmp/mpz/mod.c b/third_party/gmp/mpz/mod.c
new file mode 100644
index 0000000..ab5cdb1
--- /dev/null
+++ b/third_party/gmp/mpz/mod.c
@@ -0,0 +1,67 @@
+/* mpz_mod -- The mathematical mod function.
+
+Copyright 1991, 1993-1996, 2001, 2002, 2005, 2010, 2012 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_mod (mpz_ptr rem, mpz_srcptr dividend, mpz_srcptr divisor)
+{
+  mp_size_t rn, bn;
+  mpz_t temp_divisor;
+  TMP_DECL;
+
+  TMP_MARK;
+
+  bn = ABSIZ(divisor);
+
+  /* We need the original value of the divisor after the remainder has been
+     preliminary calculated.  We have to copy it to temporary space if it's
+     the same variable as REM.  */
+  if (rem == divisor)
+    {
+      PTR(temp_divisor) = TMP_ALLOC_LIMBS (bn);
+      MPN_COPY (PTR(temp_divisor), PTR(divisor), bn);
+    }
+  else
+    {
+      PTR(temp_divisor) = PTR(divisor);
+    }
+  SIZ(temp_divisor) = bn;
+  divisor = temp_divisor;
+
+  mpz_tdiv_r (rem, dividend, divisor);
+
+  rn = SIZ (rem);
+  if (rn < 0)
+    mpz_add (rem, rem, divisor);
+
+  TMP_FREE;
+}
diff --git a/third_party/gmp/mpz/mul.c b/third_party/gmp/mpz/mul.c
new file mode 100644
index 0000000..d72c93e
--- /dev/null
+++ b/third_party/gmp/mpz/mul.c
@@ -0,0 +1,157 @@
+/* mpz_mul -- Multiply two integers.
+
+Copyright 1991, 1993, 1994, 1996, 2000, 2001, 2005, 2009, 2011, 2012,
+2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h> /* for NULL */
+#include "gmp-impl.h"
+
+
+void
+mpz_mul (mpz_ptr w, mpz_srcptr u, mpz_srcptr v)
+{
+  mp_size_t usize;
+  mp_size_t vsize;
+  mp_size_t wsize;
+  mp_size_t sign_product;
+  mp_ptr up, vp;
+  mp_ptr wp;
+  mp_ptr free_me;
+  size_t free_me_size;
+  mp_limb_t cy_limb;
+  TMP_DECL;
+
+  usize = SIZ (u);
+  vsize = SIZ (v);
+  sign_product = usize ^ vsize;
+  usize = ABS (usize);
+  vsize = ABS (vsize);
+
+  if (usize < vsize)
+    {
+      MPZ_SRCPTR_SWAP (u, v);
+      MP_SIZE_T_SWAP (usize, vsize);
+    }
+
+  if (vsize == 0)
+    {
+      SIZ (w) = 0;
+      return;
+    }
+
+#if HAVE_NATIVE_mpn_mul_2
+  if (vsize <= 2)
+    {
+      wp = MPZ_REALLOC (w, usize+vsize);
+      if (vsize == 1)
+	cy_limb = mpn_mul_1 (wp, PTR (u), usize, PTR (v)[0]);
+      else
+	{
+	  cy_limb = mpn_mul_2 (wp, PTR (u), usize, PTR (v));
+	  usize++;
+	}
+      wp[usize] = cy_limb;
+      usize += (cy_limb != 0);
+      SIZ (w) = (sign_product >= 0 ? usize : -usize);
+      return;
+    }
+#else
+  if (vsize == 1)
+    {
+      wp = MPZ_REALLOC (w, usize+1);
+      cy_limb = mpn_mul_1 (wp, PTR (u), usize, PTR (v)[0]);
+      wp[usize] = cy_limb;
+      usize += (cy_limb != 0);
+      SIZ (w) = (sign_product >= 0 ? usize : -usize);
+      return;
+    }
+#endif
+
+  TMP_MARK;
+  free_me = NULL;
+  up = PTR (u);
+  vp = PTR (v);
+  wp = PTR (w);
+
+  /* Ensure W has space enough to store the result.  */
+  wsize = usize + vsize;
+  if (ALLOC (w) < wsize)
+    {
+      if (ALLOC (w) != 0)
+	if (wp == up || wp == vp)
+	  {
+	    free_me = wp;
+	    free_me_size = ALLOC (w);
+	  }
+	else
+	  (*__gmp_free_func) (wp, (size_t) ALLOC (w) * GMP_LIMB_BYTES);
+
+      ALLOC (w) = wsize;
+      wp = __GMP_ALLOCATE_FUNC_LIMBS (wsize);
+      PTR (w) = wp;
+    }
+  else
+    {
+      /* Make U and V not overlap with W.  */
+      if (wp == up)
+	{
+	  /* W and U are identical.  Allocate temporary space for U.  */
+	  up = TMP_ALLOC_LIMBS (usize);
+	  /* Is V identical too?  Keep it identical with U.  */
+	  if (wp == vp)
+	    vp = up;
+	  /* Copy to the temporary space.  */
+	  MPN_COPY (up, wp, usize);
+	}
+      else if (wp == vp)
+	{
+	  /* W and V are identical.  Allocate temporary space for V.  */
+	  vp = TMP_ALLOC_LIMBS (vsize);
+	  /* Copy to the temporary space.  */
+	  MPN_COPY (vp, wp, vsize);
+	}
+    }
+
+  if (up == vp)
+    {
+      mpn_sqr (wp, up, usize);
+      cy_limb = wp[wsize - 1];
+    }
+  else
+    {
+      cy_limb = mpn_mul (wp, up, usize, vp, vsize);
+    }
+
+  wsize -= cy_limb == 0;
+
+  SIZ (w) = sign_product < 0 ? -wsize : wsize;
+  if (free_me != NULL)
+    (*__gmp_free_func) (free_me, free_me_size * GMP_LIMB_BYTES);
+  TMP_FREE;
+}
diff --git a/third_party/gmp/mpz/mul_2exp.c b/third_party/gmp/mpz/mul_2exp.c
new file mode 100644
index 0000000..6144d0d
--- /dev/null
+++ b/third_party/gmp/mpz/mul_2exp.c
@@ -0,0 +1,72 @@
+/* mpz_mul_2exp -- Multiply a bignum by 2**CNT
+
+Copyright 1991, 1993, 1994, 1996, 2001, 2002, 2012 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_mul_2exp (mpz_ptr r, mpz_srcptr u, mp_bitcnt_t cnt)
+{
+  mp_size_t un, rn;
+  mp_size_t limb_cnt;
+  mp_ptr rp;
+  mp_srcptr up;
+  mp_limb_t rlimb;
+
+  un = ABSIZ (u);
+  limb_cnt = cnt / GMP_NUMB_BITS;
+  rn = un + limb_cnt;
+
+  if (un == 0)
+    rn = 0;
+  else
+    {
+      rp = MPZ_REALLOC (r, rn + 1);
+      up = PTR(u);
+
+      cnt %= GMP_NUMB_BITS;
+      if (cnt != 0)
+	{
+	  rlimb = mpn_lshift (rp + limb_cnt, up, un, cnt);
+	  rp[rn] = rlimb;
+	  rn += (rlimb != 0);
+	}
+      else
+	{
+	  MPN_COPY_DECR (rp + limb_cnt, up, un);
+	}
+
+      /* Zero all whole limbs at low end.  Do it here and not before calling
+	 mpn_lshift, not to lose for U == R.  */
+      MPN_ZERO (rp, limb_cnt);
+    }
+
+  SIZ(r) = SIZ(u) >= 0 ? rn : -rn;
+}
diff --git a/third_party/gmp/mpz/mul_i.h b/third_party/gmp/mpz/mul_i.h
new file mode 100644
index 0000000..65c9c2f
--- /dev/null
+++ b/third_party/gmp/mpz/mul_i.h
@@ -0,0 +1,106 @@
+/* mpz_mul_ui/si (product, multiplier, small_multiplicand) -- Set PRODUCT to
+   MULTIPLICATOR times SMALL_MULTIPLICAND.
+
+Copyright 1991, 1993, 1994, 1996, 2000-2002, 2005, 2008, 2012 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+#ifdef OPERATION_mul_si
+#define FUNCTION               mpz_mul_si
+#define MULTIPLICAND_UNSIGNED
+#define MULTIPLICAND_ABS(x)    ABS_CAST(unsigned long, (x))
+#endif
+
+#ifdef OPERATION_mul_ui
+#define FUNCTION               mpz_mul_ui
+#define MULTIPLICAND_UNSIGNED  unsigned
+#define MULTIPLICAND_ABS(x)    x
+#endif
+
+#ifndef FUNCTION
+Error, error, unrecognised OPERATION
+#endif
+
+
+void
+FUNCTION (mpz_ptr prod, mpz_srcptr mult,
+          MULTIPLICAND_UNSIGNED long int small_mult)
+{
+  mp_size_t size;
+  mp_size_t sign_product;
+  mp_limb_t sml;
+  mp_limb_t cy;
+  mp_ptr pp;
+
+  sign_product = SIZ(mult);
+  if (sign_product == 0 || small_mult == 0)
+    {
+      SIZ(prod) = 0;
+      return;
+    }
+
+  size = ABS (sign_product);
+
+  sml = MULTIPLICAND_ABS (small_mult);
+
+  if (sml <= GMP_NUMB_MAX)
+    {
+      pp = MPZ_REALLOC (prod, size + 1);
+      cy = mpn_mul_1 (pp, PTR(mult), size, sml);
+      pp[size] = cy;
+      size += cy != 0;
+    }
+#if GMP_NAIL_BITS != 0
+  else
+    {
+      /* Operand too large for the current nails size.  Use temporary for
+	 intermediate products, to allow prod and mult being identical.  */
+      mp_ptr tp;
+      TMP_DECL;
+      TMP_MARK;
+
+      tp = TMP_ALLOC_LIMBS (size + 2);
+
+      /* Use, maybe, mpn_mul_2? */
+      cy = mpn_mul_1 (tp, PTR(mult), size, sml & GMP_NUMB_MASK);
+      tp[size] = cy;
+      cy = mpn_addmul_1 (tp + 1, PTR(mult), size, sml >> GMP_NUMB_BITS);
+      tp[size + 1] = cy;
+      size += 2;
+      MPN_NORMALIZE_NOT_ZERO (tp, size); /* too general, need to trim one or two limb */
+      pp = MPZ_NEWALLOC (prod, size);
+      MPN_COPY (pp, tp, size);
+      TMP_FREE;
+    }
+#endif
+
+  SIZ(prod) = ((sign_product < 0) ^ (small_mult < 0)) ? -size : size;
+}
diff --git a/third_party/gmp/mpz/mul_si.c b/third_party/gmp/mpz/mul_si.c
new file mode 100644
index 0000000..9f29f60
--- /dev/null
+++ b/third_party/gmp/mpz/mul_si.c
@@ -0,0 +1,34 @@
+/* mpz_mul_si (product, multiplier, small_multiplicand) -- Set PRODUCT to
+   MULTIPLICATOR times SMALL_MULTIPLICAND.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#define OPERATION_mul_si
+#include "mul_i.h"
diff --git a/third_party/gmp/mpz/mul_ui.c b/third_party/gmp/mpz/mul_ui.c
new file mode 100644
index 0000000..d398c4f
--- /dev/null
+++ b/third_party/gmp/mpz/mul_ui.c
@@ -0,0 +1,34 @@
+/* mpz_mul_ui (product, multiplier, small_multiplicand) -- Set PRODUCT to
+   MULTIPLICATOR times SMALL_MULTIPLICAND.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#define OPERATION_mul_ui
+#include "mul_i.h"
diff --git a/third_party/gmp/mpz/n_pow_ui.c b/third_party/gmp/mpz/n_pow_ui.c
new file mode 100644
index 0000000..cf293f5
--- /dev/null
+++ b/third_party/gmp/mpz/n_pow_ui.c
@@ -0,0 +1,532 @@
+/* mpz_n_pow_ui -- mpn raised to ulong.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2001, 2002, 2005, 2012, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* Change this to "#define TRACE(x) x" for some traces. */
+#define TRACE(x)
+
+
+/* Use this to test the mul_2 code on a CPU without a native version of that
+   routine.  */
+#if 0
+#define mpn_mul_2  refmpn_mul_2
+#define HAVE_NATIVE_mpn_mul_2  1
+#endif
+
+
+/* mpz_pow_ui and mpz_ui_pow_ui want to share almost all of this code.
+   ui_pow_ui doesn't need the mpn_mul based powering loop or the tests on
+   bsize==2 or >2, but separating that isn't easy because there's shared
+   code both before and after (the size calculations and the powers of 2
+   handling).
+
+   Alternatives:
+
+   It would work to just use the mpn_mul powering loop for 1 and 2 limb
+   bases, but the current separate loop allows mul_1 and mul_2 to be done
+   in-place, which might help cache locality a bit.  If mpn_mul was relaxed
+   to allow source==dest when vn==1 or 2 then some pointer twiddling might
+   let us get the same effect in one loop.
+
+   The initial powering for bsize==1 into blimb or blimb:blimb_low doesn't
+   form the biggest possible power of b that fits, only the biggest power of
+   2 power, ie. b^(2^n).  It'd be possible to choose a bigger power, perhaps
+   using mp_bases[b].big_base for small b, and thereby get better value
+   from mpn_mul_1 or mpn_mul_2 in the bignum powering.  It's felt that doing
+   so would be more complicated than it's worth, and could well end up being
+   a slowdown for small e.  For big e on the other hand the algorithm is
+   dominated by mpn_sqr so there wouldn't much of a saving.  The current
+   code can be viewed as simply doing the first few steps of the powering in
+   a single or double limb where possible.
+
+   If r==b, and blow_twos==0, and r must be realloc'ed, then the temporary
+   copy made of b is unnecessary.  We could just use the old alloc'ed block
+   and free it at the end.  But arranging this seems like a lot more trouble
+   than it's worth.  */
+
+
+/* floor(sqrt(GMP_NUMB_MAX)), ie. the biggest value that can be squared in
+   a limb without overflowing.
+   FIXME: This formula is an underestimate when GMP_NUMB_BITS is odd. */
+
+#define GMP_NUMB_HALFMAX  (((mp_limb_t) 1 << GMP_NUMB_BITS/2) - 1)
+
+
+/* The following are for convenience, they update the size and check the
+   alloc.  */
+
+#define MPN_SQR(dst, alloc, src, size)          \
+  do {                                          \
+    ASSERT (2*(size) <= (alloc));               \
+    mpn_sqr (dst, src, size);                   \
+    (size) *= 2;                                \
+    (size) -= ((dst)[(size)-1] == 0);           \
+  } while (0)
+
+#define MPN_MUL(dst, alloc, src, size, src2, size2)     \
+  do {                                                  \
+    mp_limb_t  cy;                                      \
+    ASSERT ((size) + (size2) <= (alloc));               \
+    cy = mpn_mul (dst, src, size, src2, size2);         \
+    (size) += (size2) - (cy == 0);                      \
+  } while (0)
+
+#define MPN_MUL_2(ptr, size, alloc, mult)       \
+  do {                                          \
+    mp_limb_t  cy;                              \
+    ASSERT ((size)+2 <= (alloc));               \
+    cy = mpn_mul_2 (ptr, ptr, size, mult);      \
+    (size)++;                                   \
+    (ptr)[(size)] = cy;                         \
+    (size) += (cy != 0);                        \
+  } while (0)
+
+#define MPN_MUL_1(ptr, size, alloc, limb)       \
+  do {                                          \
+    mp_limb_t  cy;                              \
+    ASSERT ((size)+1 <= (alloc));               \
+    cy = mpn_mul_1 (ptr, ptr, size, limb);      \
+    (ptr)[size] = cy;                           \
+    (size) += (cy != 0);                        \
+  } while (0)
+
+#define MPN_LSHIFT(ptr, size, alloc, shift)     \
+  do {                                          \
+    mp_limb_t  cy;                              \
+    ASSERT ((size)+1 <= (alloc));               \
+    cy = mpn_lshift (ptr, ptr, size, shift);    \
+    (ptr)[size] = cy;                           \
+    (size) += (cy != 0);                        \
+  } while (0)
+
+#define MPN_RSHIFT_OR_COPY(dst, src, size, shift)       \
+  do {                                                  \
+    if ((shift) == 0)                                   \
+      MPN_COPY (dst, src, size);                        \
+    else                                                \
+      {                                                 \
+        mpn_rshift (dst, src, size, shift);             \
+        (size) -= ((dst)[(size)-1] == 0);               \
+      }                                                 \
+  } while (0)
+
+
+/* ralloc and talloc are only wanted for ASSERTs, after the initial space
+   allocations.  Avoid writing values to them in a normal build, to ensure
+   the compiler lets them go dead.  gcc already figures this out itself
+   actually.  */
+
+#define SWAP_RP_TP                                      \
+  do {                                                  \
+    MP_PTR_SWAP (rp, tp);                               \
+    ASSERT_CODE (MP_SIZE_T_SWAP (ralloc, talloc));      \
+  } while (0)
+
+
+void
+mpz_n_pow_ui (mpz_ptr r, mp_srcptr bp, mp_size_t bsize, unsigned long int e)
+{
+  mp_ptr         rp;
+  mp_size_t      rtwos_limbs, ralloc, rsize;
+  int            rneg, i, cnt, btwos, r_bp_overlap;
+  mp_limb_t      blimb, rl;
+  mp_bitcnt_t    rtwos_bits;
+#if HAVE_NATIVE_mpn_mul_2
+  mp_limb_t      blimb_low, rl_high;
+#else
+  mp_limb_t      b_twolimbs[2];
+#endif
+  TMP_DECL;
+
+  TRACE (printf ("mpz_n_pow_ui rp=0x%lX bp=0x%lX bsize=%ld e=%lu (0x%lX)\n",
+		 PTR(r), bp, bsize, e, e);
+	 mpn_trace ("b", bp, bsize));
+
+  ASSERT (bsize == 0 || bp[ABS(bsize)-1] != 0);
+  ASSERT (MPN_SAME_OR_SEPARATE2_P (PTR(r), ALLOC(r), bp, ABS(bsize)));
+
+  /* b^0 == 1, including 0^0 == 1 */
+  if (e == 0)
+    {
+      MPZ_NEWALLOC (r, 1)[0] = 1;
+      SIZ(r) = 1;
+      return;
+    }
+
+  /* 0^e == 0 apart from 0^0 above */
+  if (bsize == 0)
+    {
+      SIZ(r) = 0;
+      return;
+    }
+
+  /* Sign of the final result. */
+  rneg = (bsize < 0 && (e & 1) != 0);
+  bsize = ABS (bsize);
+  TRACE (printf ("rneg %d\n", rneg));
+
+  r_bp_overlap = (PTR(r) == bp);
+
+  /* Strip low zero limbs from b. */
+  rtwos_limbs = 0;
+  for (blimb = *bp; blimb == 0; blimb = *++bp)
+    {
+      rtwos_limbs += e;
+      bsize--; ASSERT (bsize >= 1);
+    }
+  TRACE (printf ("trailing zero rtwos_limbs=%ld\n", rtwos_limbs));
+
+  /* Strip low zero bits from b. */
+  count_trailing_zeros (btwos, blimb);
+  blimb >>= btwos;
+  rtwos_bits = e * btwos;
+  rtwos_limbs += rtwos_bits / GMP_NUMB_BITS;
+  rtwos_bits %= GMP_NUMB_BITS;
+  TRACE (printf ("trailing zero btwos=%d rtwos_limbs=%ld rtwos_bits=%lu\n",
+		 btwos, rtwos_limbs, rtwos_bits));
+
+  TMP_MARK;
+
+  rl = 1;
+#if HAVE_NATIVE_mpn_mul_2
+  rl_high = 0;
+#endif
+
+  if (bsize == 1)
+    {
+    bsize_1:
+      /* Power up as far as possible within blimb.  We start here with e!=0,
+	 but if e is small then we might reach e==0 and the whole b^e in rl.
+	 Notice this code works when blimb==1 too, reaching e==0.  */
+
+      while (blimb <= GMP_NUMB_HALFMAX)
+	{
+	  TRACE (printf ("small e=0x%lX blimb=0x%lX rl=0x%lX\n",
+			 e, blimb, rl));
+	  ASSERT (e != 0);
+	  if ((e & 1) != 0)
+	    rl *= blimb;
+	  e >>= 1;
+	  if (e == 0)
+	    goto got_rl;
+	  blimb *= blimb;
+	}
+
+#if HAVE_NATIVE_mpn_mul_2
+      TRACE (printf ("single power, e=0x%lX b=0x%lX rl=0x%lX\n",
+		     e, blimb, rl));
+
+      /* Can power b once more into blimb:blimb_low */
+      bsize = 2;
+      ASSERT (e != 0);
+      if ((e & 1) != 0)
+	{
+	  umul_ppmm (rl_high, rl, rl, blimb << GMP_NAIL_BITS);
+	  rl >>= GMP_NAIL_BITS;
+	}
+      e >>= 1;
+      umul_ppmm (blimb, blimb_low, blimb, blimb << GMP_NAIL_BITS);
+      blimb_low >>= GMP_NAIL_BITS;
+
+    got_rl:
+      TRACE (printf ("double power e=0x%lX blimb=0x%lX:0x%lX rl=0x%lX:%lX\n",
+		     e, blimb, blimb_low, rl_high, rl));
+
+      /* Combine left-over rtwos_bits into rl_high:rl to be handled by the
+	 final mul_1 or mul_2 rather than a separate lshift.
+	 - rl_high:rl mustn't be 1 (since then there's no final mul)
+	 - rl_high mustn't overflow
+	 - rl_high mustn't change to non-zero, since mul_1+lshift is
+	 probably faster than mul_2 (FIXME: is this true?)  */
+
+      if (rtwos_bits != 0
+	  && ! (rl_high == 0 && rl == 1)
+	  && (rl_high >> (GMP_NUMB_BITS-rtwos_bits)) == 0)
+	{
+	  mp_limb_t  new_rl_high = (rl_high << rtwos_bits)
+	    | (rl >> (GMP_NUMB_BITS-rtwos_bits));
+	  if (! (rl_high == 0 && new_rl_high != 0))
+	    {
+	      rl_high = new_rl_high;
+	      rl <<= rtwos_bits;
+	      rtwos_bits = 0;
+	      TRACE (printf ("merged rtwos_bits, rl=0x%lX:%lX\n",
+			     rl_high, rl));
+	    }
+	}
+#else
+    got_rl:
+      TRACE (printf ("small power e=0x%lX blimb=0x%lX rl=0x%lX\n",
+		     e, blimb, rl));
+
+      /* Combine left-over rtwos_bits into rl to be handled by the final
+	 mul_1 rather than a separate lshift.
+	 - rl mustn't be 1 (since then there's no final mul)
+	 - rl mustn't overflow	*/
+
+      if (rtwos_bits != 0
+	  && rl != 1
+	  && (rl >> (GMP_NUMB_BITS-rtwos_bits)) == 0)
+	{
+	  rl <<= rtwos_bits;
+	  rtwos_bits = 0;
+	  TRACE (printf ("merged rtwos_bits, rl=0x%lX\n", rl));
+	}
+#endif
+    }
+  else if (bsize == 2)
+    {
+      mp_limb_t  bsecond = bp[1];
+      if (btwos != 0)
+	blimb |= (bsecond << (GMP_NUMB_BITS - btwos)) & GMP_NUMB_MASK;
+      bsecond >>= btwos;
+      if (bsecond == 0)
+	{
+	  /* Two limbs became one after rshift. */
+	  bsize = 1;
+	  goto bsize_1;
+	}
+
+      TRACE (printf ("bsize==2 using b=0x%lX:%lX", bsecond, blimb));
+#if HAVE_NATIVE_mpn_mul_2
+      blimb_low = blimb;
+#else
+      bp = b_twolimbs;
+      b_twolimbs[0] = blimb;
+      b_twolimbs[1] = bsecond;
+#endif
+      blimb = bsecond;
+    }
+  else
+    {
+      if (r_bp_overlap || btwos != 0)
+	{
+	  mp_ptr tp = TMP_ALLOC_LIMBS (bsize);
+	  MPN_RSHIFT_OR_COPY (tp, bp, bsize, btwos);
+	  bp = tp;
+	  TRACE (printf ("rshift or copy bp,bsize, new bsize=%ld\n", bsize));
+	}
+#if HAVE_NATIVE_mpn_mul_2
+      /* in case 3 limbs rshift to 2 and hence use the mul_2 loop below */
+      blimb_low = bp[0];
+#endif
+      blimb = bp[bsize-1];
+
+      TRACE (printf ("big bsize=%ld  ", bsize);
+	     mpn_trace ("b", bp, bsize));
+    }
+
+  /* At this point blimb is the most significant limb of the base to use.
+
+     Each factor of b takes (bsize*BPML-cnt) bits and there's e of them; +1
+     limb to round up the division; +1 for multiplies all using an extra
+     limb over the true size; +2 for rl at the end; +1 for lshift at the
+     end.
+
+     The size calculation here is reasonably accurate.  The base is at least
+     half a limb, so in 32 bits the worst case is 2^16+1 treated as 17 bits
+     when it will power up as just over 16, an overestimate of 17/16 =
+     6.25%.  For a 64-bit limb it's half that.
+
+     If e==0 then blimb won't be anything useful (though it will be
+     non-zero), but that doesn't matter since we just end up with ralloc==5,
+     and that's fine for 2 limbs of rl and 1 of lshift.  */
+
+  ASSERT (blimb != 0);
+  count_leading_zeros (cnt, blimb);
+  ralloc = (bsize*GMP_NUMB_BITS - cnt + GMP_NAIL_BITS) * e / GMP_NUMB_BITS + 5;
+  TRACE (printf ("ralloc %ld, from bsize=%ld blimb=0x%lX cnt=%d\n",
+		 ralloc, bsize, blimb, cnt));
+  rp = MPZ_NEWALLOC (r, ralloc + rtwos_limbs);
+
+  /* Low zero limbs resulting from powers of 2. */
+  MPN_ZERO (rp, rtwos_limbs);
+  rp += rtwos_limbs;
+
+  if (e == 0)
+    {
+      /* Any e==0 other than via bsize==1 or bsize==2 is covered at the
+	 start. */
+      rp[0] = rl;
+      rsize = 1;
+#if HAVE_NATIVE_mpn_mul_2
+      rp[1] = rl_high;
+      rsize += (rl_high != 0);
+#endif
+      ASSERT (rp[rsize-1] != 0);
+    }
+  else
+    {
+      mp_ptr     tp;
+      mp_size_t  talloc;
+
+      /* In the mpn_mul_1 or mpn_mul_2 loops or in the mpn_mul loop when the
+	 low bit of e is zero, tp only has to hold the second last power
+	 step, which is half the size of the final result.  There's no need
+	 to round up the divide by 2, since ralloc includes a +2 for rl
+	 which not needed by tp.  In the mpn_mul loop when the low bit of e
+	 is 1, tp must hold nearly the full result, so just size it the same
+	 as rp.  */
+
+      talloc = ralloc;
+#if HAVE_NATIVE_mpn_mul_2
+      if (bsize <= 2 || (e & 1) == 0)
+	talloc /= 2;
+#else
+      if (bsize <= 1 || (e & 1) == 0)
+	talloc /= 2;
+#endif
+      TRACE (printf ("talloc %ld\n", talloc));
+      tp = TMP_ALLOC_LIMBS (talloc);
+
+      /* Go from high to low over the bits of e, starting with i pointing at
+	 the bit below the highest 1 (which will mean i==-1 if e==1).  */
+      count_leading_zeros (cnt, (mp_limb_t) e);
+      i = GMP_LIMB_BITS - cnt - 2;
+
+#if HAVE_NATIVE_mpn_mul_2
+      if (bsize <= 2)
+	{
+	  mp_limb_t  mult[2];
+
+	  /* Any bsize==1 will have been powered above to be two limbs. */
+	  ASSERT (bsize == 2);
+	  ASSERT (blimb != 0);
+
+	  /* Arrange the final result ends up in r, not in the temp space */
+	  if ((i & 1) == 0)
+	    SWAP_RP_TP;
+
+	  rp[0] = blimb_low;
+	  rp[1] = blimb;
+	  rsize = 2;
+
+	  mult[0] = blimb_low;
+	  mult[1] = blimb;
+
+	  for ( ; i >= 0; i--)
+	    {
+	      TRACE (printf ("mul_2 loop i=%d e=0x%lX, rsize=%ld ralloc=%ld talloc=%ld\n",
+			     i, e, rsize, ralloc, talloc);
+		     mpn_trace ("r", rp, rsize));
+
+	      MPN_SQR (tp, talloc, rp, rsize);
+	      SWAP_RP_TP;
+	      if ((e & (1L << i)) != 0)
+		MPN_MUL_2 (rp, rsize, ralloc, mult);
+	    }
+
+	  TRACE (mpn_trace ("mul_2 before rl, r", rp, rsize));
+	  if (rl_high != 0)
+	    {
+	      mult[0] = rl;
+	      mult[1] = rl_high;
+	      MPN_MUL_2 (rp, rsize, ralloc, mult);
+	    }
+	  else if (rl != 1)
+	    MPN_MUL_1 (rp, rsize, ralloc, rl);
+	}
+#else
+      if (bsize == 1)
+	{
+	  /* Arrange the final result ends up in r, not in the temp space */
+	  if ((i & 1) == 0)
+	    SWAP_RP_TP;
+
+	  rp[0] = blimb;
+	  rsize = 1;
+
+	  for ( ; i >= 0; i--)
+	    {
+	      TRACE (printf ("mul_1 loop i=%d e=0x%lX, rsize=%ld ralloc=%ld talloc=%ld\n",
+			     i, e, rsize, ralloc, talloc);
+		     mpn_trace ("r", rp, rsize));
+
+	      MPN_SQR (tp, talloc, rp, rsize);
+	      SWAP_RP_TP;
+	      if ((e & (1L << i)) != 0)
+		MPN_MUL_1 (rp, rsize, ralloc, blimb);
+	    }
+
+	  TRACE (mpn_trace ("mul_1 before rl, r", rp, rsize));
+	  if (rl != 1)
+	    MPN_MUL_1 (rp, rsize, ralloc, rl);
+	}
+#endif
+      else
+	{
+	  int  parity;
+
+	  /* Arrange the final result ends up in r, not in the temp space */
+	  ULONG_PARITY (parity, e);
+	  if (((parity ^ i) & 1) != 0)
+	    SWAP_RP_TP;
+
+	  MPN_COPY (rp, bp, bsize);
+	  rsize = bsize;
+
+	  for ( ; i >= 0; i--)
+	    {
+	      TRACE (printf ("mul loop i=%d e=0x%lX, rsize=%ld ralloc=%ld talloc=%ld\n",
+			     i, e, rsize, ralloc, talloc);
+		     mpn_trace ("r", rp, rsize));
+
+	      MPN_SQR (tp, talloc, rp, rsize);
+	      SWAP_RP_TP;
+	      if ((e & (1L << i)) != 0)
+		{
+		  MPN_MUL (tp, talloc, rp, rsize, bp, bsize);
+		  SWAP_RP_TP;
+		}
+	    }
+	}
+    }
+
+  ASSERT (rp == PTR(r) + rtwos_limbs);
+  TRACE (mpn_trace ("end loop r", rp, rsize));
+  TMP_FREE;
+
+  /* Apply any partial limb factors of 2. */
+  if (rtwos_bits != 0)
+    {
+      MPN_LSHIFT (rp, rsize, ralloc, (unsigned) rtwos_bits);
+      TRACE (mpn_trace ("lshift r", rp, rsize));
+    }
+
+  rsize += rtwos_limbs;
+  SIZ(r) = (rneg ? -rsize : rsize);
+}
diff --git a/third_party/gmp/mpz/neg.c b/third_party/gmp/mpz/neg.c
new file mode 100644
index 0000000..7f3fbcf
--- /dev/null
+++ b/third_party/gmp/mpz/neg.c
@@ -0,0 +1,56 @@
+/* mpz_neg(mpz_ptr dst, mpz_ptr src) -- Assign the negated value of SRC to DST.
+
+Copyright 1991, 1993-1995, 2001, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define __GMP_FORCE_mpz_neg 1
+
+#include "gmp-impl.h"
+
+void
+mpz_neg (mpz_ptr w, mpz_srcptr u)
+{
+  mp_ptr wp;
+  mp_srcptr up;
+  mp_size_t usize, size;
+
+  usize = SIZ (u);
+
+  if (u != w)
+    {
+      size = ABS (usize);
+
+      wp = MPZ_NEWALLOC (w, size);
+
+      up = PTR (u);
+
+      MPN_COPY (wp, up, size);
+    }
+
+  SIZ (w) = -usize;
+}
diff --git a/third_party/gmp/mpz/nextprime.c b/third_party/gmp/mpz/nextprime.c
new file mode 100644
index 0000000..1a0b5b6
--- /dev/null
+++ b/third_party/gmp/mpz/nextprime.c
@@ -0,0 +1,128 @@
+/* mpz_nextprime(p,t) - compute the next prime > t and store that in p.
+
+Copyright 1999-2001, 2008, 2009, 2012 Free Software Foundation, Inc.
+
+Contributed to the GNU project by Niels Möller and Torbjorn Granlund.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+static const unsigned char primegap[] =
+{
+  2,2,4,2,4,2,4,6,2,6,4,2,4,6,6,2,6,4,2,6,4,6,8,4,2,4,2,4,14,4,6,
+  2,10,2,6,6,4,6,6,2,10,2,4,2,12,12,4,2,4,6,2,10,6,6,6,2,6,4,2,10,14,4,2,
+  4,14,6,10,2,4,6,8,6,6,4,6,8,4,8,10,2,10,2,6,4,6,8,4,2,4,12,8,4,8,4,6,
+  12,2,18,6,10,6,6,2,6,10,6,6,2,6,6,4,2,12,10,2,4,6,6,2,12,4,6,8,10,8,10,8,
+  6,6,4,8,6,4,8,4,14,10,12,2,10,2,4,2,10,14,4,2,4,14,4,2,4,20,4,8,10,8,4,6,
+  6,14,4,6,6,8,6,12
+};
+
+#define NUMBER_OF_PRIMES 167
+
+void
+mpz_nextprime (mpz_ptr p, mpz_srcptr n)
+{
+  unsigned short *moduli;
+  unsigned long difference;
+  int i;
+  unsigned prime_limit;
+  unsigned long prime;
+  mp_size_t pn;
+  mp_bitcnt_t nbits;
+  unsigned incr;
+  TMP_SDECL;
+
+  /* First handle tiny numbers */
+  if (mpz_cmp_ui (n, 2) < 0)
+    {
+      mpz_set_ui (p, 2);
+      return;
+    }
+  mpz_add_ui (p, n, 1);
+  mpz_setbit (p, 0);
+
+  if (mpz_cmp_ui (p, 7) <= 0)
+    return;
+
+  pn = SIZ(p);
+  MPN_SIZEINBASE_2EXP(nbits, PTR(p), pn, 1);
+  if (nbits / 2 >= NUMBER_OF_PRIMES)
+    prime_limit = NUMBER_OF_PRIMES - 1;
+  else
+    prime_limit = nbits / 2;
+
+  TMP_SMARK;
+
+  /* Compute residues modulo small odd primes */
+  moduli = TMP_SALLOC_TYPE (prime_limit, unsigned short);
+
+  for (;;)
+    {
+      /* FIXME: Compute lazily? */
+      prime = 3;
+      for (i = 0; i < prime_limit; i++)
+	{
+	  moduli[i] = mpz_tdiv_ui (p, prime);
+	  prime += primegap[i];
+	}
+
+#define INCR_LIMIT 0x10000	/* deep science */
+
+      for (difference = incr = 0; incr < INCR_LIMIT; difference += 2)
+	{
+	  /* First check residues */
+	  prime = 3;
+	  for (i = 0; i < prime_limit; i++)
+	    {
+	      unsigned r;
+	      /* FIXME: Reduce moduli + incr and store back, to allow for
+		 division-free reductions.  Alternatively, table primes[]'s
+		 inverses (mod 2^16).  */
+	      r = (moduli[i] + incr) % prime;
+	      prime += primegap[i];
+
+	      if (r == 0)
+		goto next;
+	    }
+
+	  mpz_add_ui (p, p, difference);
+	  difference = 0;
+
+	  /* Miller-Rabin test */
+	  if (mpz_millerrabin (p, 25))
+	    goto done;
+	next:;
+	  incr += 2;
+	}
+      mpz_add_ui (p, p, difference);
+      difference = 0;
+    }
+ done:
+  TMP_SFREE;
+}
diff --git a/third_party/gmp/mpz/oddfac_1.c b/third_party/gmp/mpz/oddfac_1.c
new file mode 100644
index 0000000..9c99d1e
--- /dev/null
+++ b/third_party/gmp/mpz/oddfac_1.c
@@ -0,0 +1,422 @@
+/* mpz_oddfac_1(RESULT, N) -- Set RESULT to the odd factor of N!.
+
+Contributed to the GNU project by Marco Bodrato.
+
+THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.
+IT IS ONLY SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.
+IN FACT, IT IS ALMOST GUARANTEED THAT IT WILL CHANGE OR
+DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2010-2012, 2015-2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/* TODO:
+   - split this file in smaller parts with functions that can be recycled for different computations.
+ */
+
+/**************************************************************/
+/* Section macros: common macros, for mswing/fac/bin (&sieve) */
+/**************************************************************/
+
+#define FACTOR_LIST_APPEND(PR, MAX_PR, VEC, I)			\
+  if ((PR) > (MAX_PR)) {					\
+    (VEC)[(I)++] = (PR);					\
+    (PR) = 1;							\
+  }
+
+#define FACTOR_LIST_STORE(P, PR, MAX_PR, VEC, I)		\
+  do {								\
+    if ((PR) > (MAX_PR)) {					\
+      (VEC)[(I)++] = (PR);					\
+      (PR) = (P);						\
+    } else							\
+      (PR) *= (P);						\
+  } while (0)
+
+#define LOOP_ON_SIEVE_CONTINUE(prime,end,sieve)			\
+    __max_i = (end);						\
+								\
+    do {							\
+      ++__i;							\
+      if (((sieve)[__index] & __mask) == 0)			\
+	{							\
+	  mp_limb_t prime;					\
+	  prime = id_to_n(__i)
+
+#define LOOP_ON_SIEVE_BEGIN(prime,start,end,off,sieve)		\
+  do {								\
+    mp_limb_t __mask, __index, __max_i, __i;			\
+								\
+    __i = (start)-(off);					\
+    __index = __i / GMP_LIMB_BITS;				\
+    __mask = CNST_LIMB(1) << (__i % GMP_LIMB_BITS);		\
+    __i += (off);						\
+								\
+    LOOP_ON_SIEVE_CONTINUE(prime,end,sieve)
+
+#define LOOP_ON_SIEVE_STOP					\
+	}							\
+      __mask = __mask << 1 | __mask >> (GMP_LIMB_BITS-1);	\
+      __index += __mask & 1;					\
+    }  while (__i <= __max_i)
+
+#define LOOP_ON_SIEVE_END					\
+    LOOP_ON_SIEVE_STOP;						\
+  } while (0)
+
+/*********************************************************/
+/* Section sieve: sieving functions and tools for primes */
+/*********************************************************/
+
+#if WANT_ASSERT
+static mp_limb_t
+bit_to_n (mp_limb_t bit) { return (bit*3+4)|1; }
+#endif
+
+/* id_to_n (x) = bit_to_n (x-1) = (id*3+1)|1*/
+static mp_limb_t
+id_to_n  (mp_limb_t id)  { return id*3+1+(id&1); }
+
+/* n_to_bit (n) = ((n-1)&(-CNST_LIMB(2)))/3U-1 */
+static mp_limb_t
+n_to_bit (mp_limb_t n) { return ((n-5)|1)/3U; }
+
+#if WANT_ASSERT
+static mp_size_t
+primesieve_size (mp_limb_t n) { return n_to_bit(n) / GMP_LIMB_BITS + 1; }
+#endif
+
+/*********************************************************/
+/* Section mswing: 2-multiswing factorial                */
+/*********************************************************/
+
+/* Returns an approximation of the sqare root of x.
+ * It gives:
+ *   limb_apprsqrt (x) ^ 2 <= x < (limb_apprsqrt (x)+1) ^ 2
+ * or
+ *   x <= limb_apprsqrt (x) ^ 2 <= x * 9/8
+ */
+static mp_limb_t
+limb_apprsqrt (mp_limb_t x)
+{
+  int s;
+
+  ASSERT (x > 2);
+  count_leading_zeros (s, x);
+  s = (GMP_LIMB_BITS - s) >> 1;
+  return ((CNST_LIMB(1) << s) + (x >> s)) >> 1;
+}
+
+#if 0
+/* A count-then-exponentiate variant for SWING_A_PRIME */
+#define SWING_A_PRIME(P, N, PR, MAX_PR, VEC, I)		\
+  do {							\
+    mp_limb_t __q, __prime;				\
+    int __exp;						\
+    __prime = (P);					\
+    __exp = 0;						\
+    __q = (N);						\
+    do {						\
+      __q /= __prime;					\
+      __exp += __q & 1;					\
+    } while (__q >= __prime);				\
+    if (__exp) { /* Store $prime^{exp}$ */		\
+      for (__q = __prime; --__exp; __q *= __prime);	\
+      FACTOR_LIST_STORE(__q, PR, MAX_PR, VEC, I);	\
+    };							\
+  } while (0)
+#else
+#define SWING_A_PRIME(P, N, PR, MAX_PR, VEC, I)	\
+  do {						\
+    mp_limb_t __q, __prime;			\
+    __prime = (P);				\
+    FACTOR_LIST_APPEND(PR, MAX_PR, VEC, I);	\
+    __q = (N);					\
+    do {					\
+      __q /= __prime;				\
+      if ((__q & 1) != 0) (PR) *= __prime;	\
+    } while (__q >= __prime);			\
+  } while (0)
+#endif
+
+#define SH_SWING_A_PRIME(P, N, PR, MAX_PR, VEC, I)	\
+  do {							\
+    mp_limb_t __prime;					\
+    __prime = (P);					\
+    if ((((N) / __prime) & 1) != 0)			\
+      FACTOR_LIST_STORE(__prime, PR, MAX_PR, VEC, I);	\
+  } while (0)
+
+/* mpz_2multiswing_1 computes the odd part of the 2-multiswing
+   factorial of the parameter n.  The result x is an odd positive
+   integer so that multiswing(n,2) = x 2^a.
+
+   Uses the algorithm described by Peter Luschny in "Divide, Swing and
+   Conquer the Factorial!".
+
+   The pointer sieve points to primesieve_size(n) limbs containing a
+   bit-array where primes are marked as 0.
+   Enough (FIXME: explain :-) limbs must be pointed by factors.
+ */
+
+static void
+mpz_2multiswing_1 (mpz_ptr x, mp_limb_t n, mp_ptr sieve, mp_ptr factors)
+{
+  mp_limb_t prod, max_prod;
+  mp_size_t j;
+
+  ASSERT (n > 25);
+
+  j = 0;
+  prod  = -(n & 1);
+  n &= ~ CNST_LIMB(1); /* n-1, if n is odd */
+
+  prod = (prod & n) + 1; /* the original n, if it was odd, 1 otherwise */
+  max_prod = GMP_NUMB_MAX / (n-1);
+
+  /* Handle prime = 3 separately. */
+  SWING_A_PRIME (3, n, prod, max_prod, factors, j);
+
+  /* Swing primes from 5 to n/3 */
+  {
+    mp_limb_t s, l_max_prod;
+
+    s = limb_apprsqrt(n);
+    ASSERT (s >= 5);
+    s = n_to_bit (s);
+    ASSERT (bit_to_n (s+1) * bit_to_n (s+1) > n);
+    ASSERT (s < n_to_bit (n / 3));
+    LOOP_ON_SIEVE_BEGIN (prime, n_to_bit (5), s, 0,sieve);
+    SWING_A_PRIME (prime, n, prod, max_prod, factors, j);
+    LOOP_ON_SIEVE_STOP;
+
+    ASSERT (max_prod <= GMP_NUMB_MAX / 3);
+
+    l_max_prod = max_prod * 3;
+
+    LOOP_ON_SIEVE_CONTINUE (prime, n_to_bit (n/3), sieve);
+    SH_SWING_A_PRIME (prime, n, prod, l_max_prod, factors, j);
+    LOOP_ON_SIEVE_END;
+  }
+
+  /* Store primes from (n+1)/2 to n */
+  LOOP_ON_SIEVE_BEGIN (prime, n_to_bit (n >> 1) + 1, n_to_bit (n), 0,sieve);
+  FACTOR_LIST_STORE (prime, prod, max_prod, factors, j);
+  LOOP_ON_SIEVE_END;
+
+  if (LIKELY (j != 0))
+    {
+      factors[j++] = prod;
+      mpz_prodlimbs (x, factors, j);
+    }
+  else
+    {
+      ASSERT (ALLOC (x) > 0);
+      PTR (x)[0] = prod;
+      SIZ (x) = 1;
+    }
+}
+
+#undef SWING_A_PRIME
+#undef SH_SWING_A_PRIME
+#undef LOOP_ON_SIEVE_END
+#undef LOOP_ON_SIEVE_STOP
+#undef LOOP_ON_SIEVE_BEGIN
+#undef LOOP_ON_SIEVE_CONTINUE
+#undef FACTOR_LIST_APPEND
+
+/*********************************************************/
+/* Section oddfac: odd factorial, needed also by binomial*/
+/*********************************************************/
+
+#if TUNE_PROGRAM_BUILD
+#define FACTORS_PER_LIMB (GMP_NUMB_BITS / (LOG2C(FAC_DSC_THRESHOLD_LIMIT-1)+1))
+#else
+#define FACTORS_PER_LIMB (GMP_NUMB_BITS / (LOG2C(FAC_DSC_THRESHOLD-1)+1))
+#endif
+
+/* mpz_oddfac_1 computes the odd part of the factorial of the
+   parameter n.  I.e. n! = x 2^a, where x is the returned value: an
+   odd positive integer.
+
+   If flag != 0 a square is skipped in the DSC part, e.g.
+   if n is odd, n > FAC_DSC_THRESHOLD and flag = 1, x is set to n!!.
+
+   If n is too small, flag is ignored, and an ASSERT can be triggered.
+
+   TODO: FAC_DSC_THRESHOLD is used here with two different roles:
+    - to decide when prime factorisation is needed,
+    - to stop the recursion, once sieving is done.
+   Maybe two thresholds can do a better job.
+ */
+void
+mpz_oddfac_1 (mpz_ptr x, mp_limb_t n, unsigned flag)
+{
+  ASSERT (n <= GMP_NUMB_MAX);
+  ASSERT (flag == 0 || (flag == 1 && n > ODD_DOUBLEFACTORIAL_TABLE_LIMIT + 1 && ABOVE_THRESHOLD (n, FAC_DSC_THRESHOLD)));
+
+  if (n <= ODD_FACTORIAL_TABLE_LIMIT)
+    {
+      MPZ_NEWALLOC (x, 1)[0] = __gmp_oddfac_table[n];
+      SIZ (x) = 1;
+    }
+  else if (n <= ODD_DOUBLEFACTORIAL_TABLE_LIMIT + 1)
+    {
+      mp_ptr   px;
+
+      px = MPZ_NEWALLOC (x, 2);
+      umul_ppmm (px[1], px[0], __gmp_odd2fac_table[(n - 1) >> 1], __gmp_oddfac_table[n >> 1]);
+      SIZ (x) = 2;
+    }
+  else
+    {
+      unsigned s;
+      mp_ptr   factors;
+
+      s = 0;
+      {
+	mp_limb_t tn;
+	mp_limb_t prod, max_prod, i;
+	mp_size_t j;
+	TMP_SDECL;
+
+#if TUNE_PROGRAM_BUILD
+	ASSERT (FAC_DSC_THRESHOLD_LIMIT >= FAC_DSC_THRESHOLD);
+	ASSERT (FAC_DSC_THRESHOLD >= 2 * (ODD_DOUBLEFACTORIAL_TABLE_LIMIT + 2));
+#endif
+
+	/* Compute the number of recursive steps for the DSC algorithm. */
+	for (tn = n; ABOVE_THRESHOLD (tn, FAC_DSC_THRESHOLD); s++)
+	  tn >>= 1;
+
+	j = 0;
+
+	TMP_SMARK;
+	factors = TMP_SALLOC_LIMBS (1 + tn / FACTORS_PER_LIMB);
+	ASSERT (tn >= FACTORS_PER_LIMB);
+
+	prod = 1;
+#if TUNE_PROGRAM_BUILD
+	max_prod = GMP_NUMB_MAX / FAC_DSC_THRESHOLD_LIMIT;
+#else
+	max_prod = GMP_NUMB_MAX / FAC_DSC_THRESHOLD;
+#endif
+
+	ASSERT (tn > ODD_DOUBLEFACTORIAL_TABLE_LIMIT + 1);
+	do {
+	  i = ODD_DOUBLEFACTORIAL_TABLE_LIMIT + 2;
+	  factors[j++] = ODD_DOUBLEFACTORIAL_TABLE_MAX;
+	  do {
+	    FACTOR_LIST_STORE (i, prod, max_prod, factors, j);
+	    i += 2;
+	  } while (i <= tn);
+	  max_prod <<= 1;
+	  tn >>= 1;
+	} while (tn > ODD_DOUBLEFACTORIAL_TABLE_LIMIT + 1);
+
+	factors[j++] = prod;
+	factors[j++] = __gmp_odd2fac_table[(tn - 1) >> 1];
+	factors[j++] = __gmp_oddfac_table[tn >> 1];
+	mpz_prodlimbs (x, factors, j);
+
+	TMP_SFREE;
+      }
+
+      if (s != 0)
+	/* Use the algorithm described by Peter Luschny in "Divide,
+	   Swing and Conquer the Factorial!".
+
+	   Improvement: there are two temporary buffers, factors and
+	   square, that are never used together; with a good estimate
+	   of the maximal needed size, they could share a single
+	   allocation.
+	*/
+	{
+	  mpz_t mswing;
+	  mp_ptr sieve;
+	  mp_size_t size;
+	  TMP_DECL;
+
+	  TMP_MARK;
+
+	  flag--;
+	  size = n / GMP_NUMB_BITS + 4;
+	  ASSERT (primesieve_size (n - 1) <= size - (size / 2 + 1));
+	  /* 2-multiswing(n) < 2^(n-1)*sqrt(n/pi) < 2^(n+GMP_NUMB_BITS);
+	     one more can be overwritten by mul, another for the sieve */
+	  MPZ_TMP_INIT (mswing, size);
+	  /* Initialize size, so that ASSERT can check it correctly. */
+	  ASSERT_CODE (SIZ (mswing) = 0);
+
+	  /* Put the sieve on the second half, it will be overwritten by the last mswing. */
+	  sieve = PTR (mswing) + size / 2 + 1;
+
+	  size = (gmp_primesieve (sieve, n - 1) + 1) / log_n_max (n) + 1;
+
+	  factors = TMP_ALLOC_LIMBS (size);
+	  do {
+	    mp_ptr    square, px;
+	    mp_size_t nx, ns;
+	    mp_limb_t cy;
+	    TMP_DECL;
+
+	    s--;
+	    ASSERT (ABSIZ (mswing) < ALLOC (mswing) / 2); /* Check: sieve has not been overwritten */
+	    mpz_2multiswing_1 (mswing, n >> s, sieve, factors);
+
+	    TMP_MARK;
+	    nx = SIZ (x);
+	    if (s == flag) {
+	      size = nx;
+	      square = TMP_ALLOC_LIMBS (size);
+	      MPN_COPY (square, PTR (x), nx);
+	    } else {
+	      size = nx << 1;
+	      square = TMP_ALLOC_LIMBS (size);
+	      mpn_sqr (square, PTR (x), nx);
+	      size -= (square[size - 1] == 0);
+	    }
+	    ns = SIZ (mswing);
+	    nx = size + ns;
+	    px = MPZ_NEWALLOC (x, nx);
+	    ASSERT (ns <= size);
+	    cy = mpn_mul (px, square, size, PTR(mswing), ns); /* n!= n$ * floor(n/2)!^2 */
+
+	    SIZ(x) = nx - (cy == 0);
+	    TMP_FREE;
+	  } while (s != 0);
+	  TMP_FREE;
+	}
+    }
+}
+
+#undef FACTORS_PER_LIMB
+#undef FACTOR_LIST_STORE
diff --git a/third_party/gmp/mpz/out_raw.c b/third_party/gmp/mpz/out_raw.c
new file mode 100644
index 0000000..b9fd086
--- /dev/null
+++ b/third_party/gmp/mpz/out_raw.c
@@ -0,0 +1,172 @@
+/* mpz_out_raw -- write an mpz_t in raw format.
+
+Copyright 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* HTON_LIMB_STORE takes a normal host byte order limb and stores it as
+   network byte order (ie. big endian). */
+
+#if HAVE_LIMB_BIG_ENDIAN
+#define HTON_LIMB_STORE(dst, limb)  do { *(dst) = (limb); } while (0)
+#endif
+
+#if HAVE_LIMB_LITTLE_ENDIAN
+#define HTON_LIMB_STORE(dst, limb)  BSWAP_LIMB_STORE (dst, limb)
+#endif
+
+#ifndef HTON_LIMB_STORE
+#define HTON_LIMB_STORE(dst, limb)                                      \
+  do {                                                                  \
+    mp_limb_t  __limb = (limb);                                         \
+    char      *__p = (char *) (dst);                                    \
+    int        __i;                                                     \
+    for (__i = 0; __i < GMP_LIMB_BYTES; __i++)                       \
+      __p[__i] = (char) (__limb >> ((GMP_LIMB_BYTES-1 - __i) * 8));  \
+  } while (0)
+#endif
+
+
+size_t
+mpz_out_raw (FILE *fp, mpz_srcptr x)
+{
+  mp_size_t   xsize, abs_xsize, bytes, i;
+  mp_srcptr   xp;
+  char        *tp, *bp;
+  mp_limb_t   xlimb;
+  int         zeros;
+  size_t      tsize, ssize;
+
+  xsize = SIZ(x);
+  abs_xsize = ABS (xsize);
+  bytes = (abs_xsize * GMP_NUMB_BITS + 7) / 8;
+  tsize = ROUND_UP_MULTIPLE ((unsigned) 4, GMP_LIMB_BYTES) + bytes;
+
+  tp = __GMP_ALLOCATE_FUNC_TYPE (tsize, char);
+  bp = tp + ROUND_UP_MULTIPLE ((unsigned) 4, GMP_LIMB_BYTES);
+
+  if (bytes != 0)
+    {
+      bp += bytes;
+      xp = PTR (x);
+      i = abs_xsize;
+
+      if (GMP_NAIL_BITS == 0)
+	{
+	  /* reverse limb order, and byte swap if necessary */
+#ifdef _CRAY
+	  _Pragma ("_CRI ivdep");
+#endif
+	  do
+	    {
+	      bp -= GMP_LIMB_BYTES;
+	      xlimb = *xp;
+	      HTON_LIMB_STORE ((mp_ptr) bp, xlimb);
+	      xp++;
+	    }
+	  while (--i > 0);
+
+	  /* strip high zero bytes (without fetching from bp) */
+	  count_leading_zeros (zeros, xlimb);
+	  zeros /= 8;
+	  bp += zeros;
+	  bytes -= zeros;
+	}
+      else
+	{
+	  mp_limb_t  new_xlimb;
+	  int        bits;
+	  ASSERT_CODE (char *bp_orig = bp - bytes);
+
+	  ASSERT_ALWAYS (GMP_NUMB_BITS >= 8);
+
+	  bits = 0;
+	  xlimb = 0;
+	  for (;;)
+	    {
+	      while (bits >= 8)
+		{
+		  ASSERT (bp > bp_orig);
+		  *--bp = xlimb & 0xFF;
+		  xlimb >>= 8;
+		  bits -= 8;
+		}
+
+	      if (i == 0)
+		break;
+
+	      new_xlimb = *xp++;
+	      i--;
+	      ASSERT (bp > bp_orig);
+	      *--bp = (xlimb | (new_xlimb << bits)) & 0xFF;
+	      xlimb = new_xlimb >> (8 - bits);
+	      bits += GMP_NUMB_BITS - 8;
+	    }
+
+	  if (bits != 0)
+	    {
+	      ASSERT (bp > bp_orig);
+	      *--bp = xlimb;
+	    }
+
+	  ASSERT (bp == bp_orig);
+	  while (*bp == 0)
+	    {
+	      bp++;
+	      bytes--;
+	    }
+	}
+    }
+
+  /* total bytes to be written */
+  ssize = 4 + bytes;
+
+  /* twos complement negative for the size value */
+  bytes = (xsize >= 0 ? bytes : -bytes);
+
+  /* so we don't rely on sign extension in ">>" */
+  ASSERT_ALWAYS (sizeof (bytes) >= 4);
+
+  bp[-4] = bytes >> 24;
+  bp[-3] = bytes >> 16;
+  bp[-2] = bytes >> 8;
+  bp[-1] = bytes;
+  bp -= 4;
+
+  if (fp == 0)
+    fp = stdout;
+  if (fwrite (bp, ssize, 1, fp) != 1)
+    ssize = 0;
+
+  (*__gmp_free_func) (tp, tsize);
+  return ssize;
+}
diff --git a/third_party/gmp/mpz/out_str.c b/third_party/gmp/mpz/out_str.c
new file mode 100644
index 0000000..b1d8ae8
--- /dev/null
+++ b/third_party/gmp/mpz/out_str.c
@@ -0,0 +1,108 @@
+/* mpz_out_str(stream, base, integer) -- Output to STREAM the multi prec.
+   integer INTEGER in base BASE.
+
+Copyright 1991, 1993, 1994, 1996, 2001, 2005, 2011, 2012, 2017 Free
+Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp-impl.h"
+#include "longlong.h"
+
+size_t
+mpz_out_str (FILE *stream, int base, mpz_srcptr x)
+{
+  mp_ptr xp;
+  mp_size_t x_size = SIZ (x);
+  unsigned char *str;
+  size_t str_size;
+  size_t i;
+  size_t written;
+  const char *num_to_text;
+  TMP_DECL;
+
+  if (stream == 0)
+    stream = stdout;
+
+  num_to_text = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+  if (base > 1)
+    {
+      if (base <= 36)
+	num_to_text = "0123456789abcdefghijklmnopqrstuvwxyz";
+      else if (UNLIKELY (base > 62))
+	    return 0;
+    }
+  else if (base > -2)
+    {
+      base = 10;
+    }
+  else
+    {
+      base = -base;
+      if (UNLIKELY (base > 36))
+	return 0;
+    }
+
+  written = 0;
+
+  if (x_size < 0)
+    {
+      fputc ('-', stream);
+      x_size = -x_size;
+      written = 1;
+    }
+
+  TMP_MARK;
+
+  DIGITS_IN_BASE_PER_LIMB (str_size, x_size, base);
+  str_size += 3;
+  str = (unsigned char *) TMP_ALLOC (str_size);
+
+  xp = PTR (x);
+  if (! POW2_P (base))
+    {
+      xp = TMP_ALLOC_LIMBS (x_size | 1);  /* |1 in case x_size==0 */
+      MPN_COPY (xp, PTR (x), x_size);
+    }
+
+  str_size = mpn_get_str (str, base, xp, x_size);
+
+  /* Convert result to printable chars.  */
+  for (i = 0; i < str_size; i++)
+    str[i] = num_to_text[str[i]];
+  str[str_size] = 0;
+
+  {
+    size_t fwret;
+    fwret = fwrite ((char *) str, 1, str_size, stream);
+    written += fwret;
+  }
+
+  TMP_FREE;
+  return ferror (stream) ? 0 : written;
+}
diff --git a/third_party/gmp/mpz/perfpow.c b/third_party/gmp/mpz/perfpow.c
new file mode 100644
index 0000000..9bbb497
--- /dev/null
+++ b/third_party/gmp/mpz/perfpow.c
@@ -0,0 +1,38 @@
+/* mpz_perfect_power_p(arg) -- Return non-zero if ARG is a perfect power,
+   zero otherwise.
+
+Copyright 1998-2001, 2005, 2008, 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+int
+mpz_perfect_power_p (mpz_srcptr u)
+{
+  return mpn_perfect_power_p (PTR (u), SIZ (u));
+}
diff --git a/third_party/gmp/mpz/perfsqr.c b/third_party/gmp/mpz/perfsqr.c
new file mode 100644
index 0000000..c2ac924
--- /dev/null
+++ b/third_party/gmp/mpz/perfsqr.c
@@ -0,0 +1,34 @@
+/* mpz_perfect_square_p(arg) -- Return non-zero if ARG is a perfect square,
+   zero otherwise.
+
+Copyright 1991, 1993, 1994, 1996, 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define __GMP_FORCE_mpz_perfect_square_p 1
+
+#include "gmp-impl.h"
diff --git a/third_party/gmp/mpz/popcount.c b/third_party/gmp/mpz/popcount.c
new file mode 100644
index 0000000..e9a85bb
--- /dev/null
+++ b/third_party/gmp/mpz/popcount.c
@@ -0,0 +1,34 @@
+/* mpz_popcount(mpz_ptr op) -- Population count of OP.  If the operand is
+   negative, return ~0 (a novel representation of infinity).
+
+Copyright 1994, 1996, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define __GMP_FORCE_mpz_popcount 1
+
+#include "gmp-impl.h"
diff --git a/third_party/gmp/mpz/pow_ui.c b/third_party/gmp/mpz/pow_ui.c
new file mode 100644
index 0000000..8bafaa7
--- /dev/null
+++ b/third_party/gmp/mpz/pow_ui.c
@@ -0,0 +1,52 @@
+/* mpz_pow_ui -- mpz raised to ulong.
+
+Copyright 2001, 2008 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_pow_ui (mpz_ptr r, mpz_srcptr b, unsigned long int e)
+{
+  /* We test some small exponents here, mainly to avoid the overhead of
+     mpz_n_pow_ui for small bases and exponents.  */
+  switch (e)
+    {
+    case 0:
+      mpz_set_ui (r, 1);
+      break;
+    case 1:
+      mpz_set (r, b);
+      break;
+    case 2:
+      mpz_mul (r, b, b);
+      break;
+    default:
+      mpz_n_pow_ui (r, PTR(b), (mp_size_t) SIZ(b), e);
+    }
+}
diff --git a/third_party/gmp/mpz/powm.c b/third_party/gmp/mpz/powm.c
new file mode 100644
index 0000000..f1bf8e3
--- /dev/null
+++ b/third_party/gmp/mpz/powm.c
@@ -0,0 +1,282 @@
+/* mpz_powm(res,base,exp,mod) -- Set R to (U^E) mod M.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+Copyright 1991, 1993, 1994, 1996, 1997, 2000-2002, 2005, 2008, 2009,
+2011, 2012, 2015, 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* TODO
+
+ * Improve handling of buffers.  It is pretty ugly now.
+
+ * For even moduli, we compute a binvert of its odd part both here and in
+   mpn_powm.  How can we avoid this recomputation?
+*/
+
+/*
+  b ^ e mod m   res
+  0   0     0    ?
+  0   e     0    ?
+  0   0     m    ?
+  0   e     m    0
+  b   0     0    ?
+  b   e     0    ?
+  b   0     m    1 mod m
+  b   e     m    b^e mod m
+*/
+
+#define HANDLE_NEGATIVE_EXPONENT 1
+
+void
+mpz_powm (mpz_ptr r, mpz_srcptr b, mpz_srcptr e, mpz_srcptr m)
+{
+  mp_size_t n, nodd, ncnt;
+  int cnt;
+  mp_ptr rp, tp;
+  mp_srcptr bp, ep, mp;
+  mp_size_t rn, bn, es, en, itch;
+  mpz_t new_b;			/* note: value lives long via 'b' */
+  TMP_DECL;
+
+  n = ABSIZ(m);
+  if (UNLIKELY (n == 0))
+    DIVIDE_BY_ZERO;
+
+  mp = PTR(m);
+
+  TMP_MARK;
+
+  es = SIZ(e);
+  if (UNLIKELY (es <= 0))
+    {
+      if (es == 0)
+	{
+	  /* b^0 mod m,  b is anything and m is non-zero.
+	     Result is 1 mod m, i.e., 1 or 0 depending on if m = 1.  */
+	  SIZ(r) = n != 1 || mp[0] != 1;
+	  MPZ_NEWALLOC (r, 1)[0] = 1;
+	  TMP_FREE;	/* we haven't really allocated anything here */
+	  return;
+	}
+#if HANDLE_NEGATIVE_EXPONENT
+      MPZ_TMP_INIT (new_b, n + 1);
+
+      if (UNLIKELY (! mpz_invert (new_b, b, m)))
+	DIVIDE_BY_ZERO;
+      b = new_b;
+      es = -es;
+#else
+      DIVIDE_BY_ZERO;
+#endif
+    }
+  en = es;
+
+  bn = ABSIZ(b);
+
+  if (UNLIKELY (bn == 0))
+    {
+      SIZ(r) = 0;
+      TMP_FREE;
+      return;
+    }
+
+  ep = PTR(e);
+
+  /* Handle (b^1 mod m) early, since mpn_pow* do not handle that case.  */
+  if (UNLIKELY (en == 1 && ep[0] == 1))
+    {
+      rp = TMP_ALLOC_LIMBS (n);
+      bp = PTR(b);
+      if (bn >= n)
+	{
+	  mp_ptr qp = TMP_ALLOC_LIMBS (bn - n + 1);
+	  mpn_tdiv_qr (qp, rp, 0L, bp, bn, mp, n);
+	  rn = n;
+	  MPN_NORMALIZE (rp, rn);
+
+	  if (rn != 0 && SIZ(b) < 0)
+	    {
+	      mpn_sub (rp, mp, n, rp, rn);
+	      rn = n;
+	      MPN_NORMALIZE_NOT_ZERO (rp, rn);
+	    }
+	}
+      else
+	{
+	  if (SIZ(b) < 0)
+	    {
+	      mpn_sub (rp, mp, n, bp, bn);
+	      rn = n;
+	      MPN_NORMALIZE_NOT_ZERO (rp, rn);
+	    }
+	  else
+	    {
+	      MPN_COPY (rp, bp, bn);
+	      rn = bn;
+	    }
+	}
+      goto ret;
+    }
+
+  /* Remove low zero limbs from M.  This loop will terminate for correctly
+     represented mpz numbers.  */
+  ncnt = 0;
+  while (UNLIKELY (mp[0] == 0))
+    {
+      mp++;
+      ncnt++;
+    }
+  nodd = n - ncnt;
+  cnt = 0;
+  if (mp[0] % 2 == 0)
+    {
+      mp_ptr newmp = TMP_ALLOC_LIMBS (nodd);
+      count_trailing_zeros (cnt, mp[0]);
+      mpn_rshift (newmp, mp, nodd, cnt);
+      nodd -= newmp[nodd - 1] == 0;
+      mp = newmp;
+      ncnt++;
+    }
+
+  if (ncnt != 0)
+    {
+      /* We will call both mpn_powm and mpn_powlo.  */
+      /* rp needs n, mpn_powlo needs 4n, the 2 mpn_binvert might need more */
+      mp_size_t n_largest_binvert = MAX (ncnt, nodd);
+      mp_size_t itch_binvert = mpn_binvert_itch (n_largest_binvert);
+      itch = 3 * n + MAX (itch_binvert, 2 * n);
+    }
+  else
+    {
+      /* We will call just mpn_powm.  */
+      mp_size_t itch_binvert = mpn_binvert_itch (nodd);
+      itch = n + MAX (itch_binvert, 2 * n);
+    }
+  tp = TMP_ALLOC_LIMBS (itch);
+
+  rp = tp;  tp += n;
+
+  bp = PTR(b);
+  mpn_powm (rp, bp, bn, ep, en, mp, nodd, tp);
+
+  rn = n;
+
+  if (ncnt != 0)
+    {
+      mp_ptr r2, xp, yp, odd_inv_2exp;
+      unsigned long t;
+      int bcnt;
+
+      if (bn < ncnt)
+	{
+	  mp_ptr newbp = TMP_ALLOC_LIMBS (ncnt);
+	  MPN_COPY (newbp, bp, bn);
+	  MPN_ZERO (newbp + bn, ncnt - bn);
+	  bp = newbp;
+	}
+
+      r2 = tp;
+
+      if (bp[0] % 2 == 0)
+	{
+	  if (en > 1)
+	    {
+	      MPN_ZERO (r2, ncnt);
+	      goto zero;
+	    }
+
+	  ASSERT (en == 1);
+	  t = (ncnt - (cnt != 0)) * GMP_NUMB_BITS + cnt;
+
+	  /* Count number of low zero bits in B, up to 3.  */
+	  bcnt = (0x1213 >> ((bp[0] & 7) << 1)) & 0x3;
+	  /* Note that ep[0] * bcnt might overflow, but that just results
+	     in a missed optimization.  */
+	  if (ep[0] * bcnt >= t)
+	    {
+	      MPN_ZERO (r2, ncnt);
+	      goto zero;
+	    }
+	}
+
+      mpn_powlo (r2, bp, ep, en, ncnt, tp + ncnt);
+
+    zero:
+      if (nodd < ncnt)
+	{
+	  mp_ptr newmp = TMP_ALLOC_LIMBS (ncnt);
+	  MPN_COPY (newmp, mp, nodd);
+	  MPN_ZERO (newmp + nodd, ncnt - nodd);
+	  mp = newmp;
+	}
+
+      odd_inv_2exp = tp + n;
+      mpn_binvert (odd_inv_2exp, mp, ncnt, tp + 2 * n);
+
+      mpn_sub (r2, r2, ncnt, rp, nodd > ncnt ? ncnt : nodd);
+
+      xp = tp + 2 * n;
+      mpn_mullo_n (xp, odd_inv_2exp, r2, ncnt);
+
+      if (cnt != 0)
+	xp[ncnt - 1] &= (CNST_LIMB(1) << cnt) - 1;
+
+      yp = tp;
+      if (ncnt > nodd)
+	mpn_mul (yp, xp, ncnt, mp, nodd);
+      else
+	mpn_mul (yp, mp, nodd, xp, ncnt);
+
+      mpn_add (rp, yp, n, rp, nodd);
+
+      ASSERT (nodd + ncnt >= n);
+      ASSERT (nodd + ncnt <= n + 1);
+    }
+
+  MPN_NORMALIZE (rp, rn);
+
+  if ((ep[0] & 1) && SIZ(b) < 0 && rn != 0)
+    {
+      mpn_sub (rp, PTR(m), n, rp, rn);
+      rn = n;
+      MPN_NORMALIZE (rp, rn);
+    }
+
+ ret:
+  MPZ_NEWALLOC (r, rn);
+  SIZ(r) = rn;
+  MPN_COPY (PTR(r), rp, rn);
+
+  TMP_FREE;
+}
diff --git a/third_party/gmp/mpz/powm_sec.c b/third_party/gmp/mpz/powm_sec.c
new file mode 100644
index 0000000..a2581a8
--- /dev/null
+++ b/third_party/gmp/mpz/powm_sec.c
@@ -0,0 +1,102 @@
+/* mpz_powm_sec(res,base,exp,mod) -- Set R to (U^E) mod M.
+
+   Contributed to the GNU project by Torbjorn Granlund.
+
+Copyright 1991, 1993, 1994, 1996, 1997, 2000-2002, 2005, 2008, 2009,
+2012, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+
+
+void
+mpz_powm_sec (mpz_ptr r, mpz_srcptr b, mpz_srcptr e, mpz_srcptr m)
+{
+  mp_size_t n;
+  mp_ptr rp, tp;
+  mp_srcptr bp, ep, mp;
+  mp_size_t rn, bn, es, en;
+  TMP_DECL;
+
+  n = ABSIZ(m);
+
+  mp = PTR(m);
+
+  if (UNLIKELY ((n == 0) || (mp[0] % 2 == 0)))
+    DIVIDE_BY_ZERO;
+
+  es = SIZ(e);
+  if (UNLIKELY (es <= 0))
+    {
+      if (es == 0)
+	{
+	  /* b^0 mod m,  b is anything and m is non-zero.
+	     Result is 1 mod m, i.e., 1 or 0 depending on if m = 1.  */
+	  SIZ(r) = n != 1 || mp[0] != 1;
+	  MPZ_NEWALLOC (r, 1)[0] = 1;
+	  return;
+	}
+      DIVIDE_BY_ZERO;
+    }
+  en = es;
+
+  bn = ABSIZ(b);
+
+  if (UNLIKELY (bn == 0))
+    {
+      SIZ(r) = 0;
+      return;
+    }
+
+  TMP_MARK;
+  TMP_ALLOC_LIMBS_2 (rp, n,
+		     tp, mpn_sec_powm_itch (bn, en * GMP_NUMB_BITS, n));
+
+  bp = PTR(b);
+  ep = PTR(e);
+
+  mpn_sec_powm (rp, bp, bn, ep, en * GMP_NUMB_BITS, mp, n, tp);
+
+  rn = n;
+
+  MPN_NORMALIZE (rp, rn);
+
+  if ((ep[0] & 1) && SIZ(b) < 0 && rn != 0)
+    {
+      mpn_sub (rp, PTR(m), n, rp, rn);
+      rn = n;
+      MPN_NORMALIZE (rp, rn);
+    }
+
+  MPZ_NEWALLOC (r, rn);
+  SIZ(r) = rn;
+  MPN_COPY (PTR(r), rp, rn);
+
+  TMP_FREE;
+}
diff --git a/third_party/gmp/mpz/powm_ui.c b/third_party/gmp/mpz/powm_ui.c
new file mode 100644
index 0000000..23d3ed8
--- /dev/null
+++ b/third_party/gmp/mpz/powm_ui.c
@@ -0,0 +1,281 @@
+/* mpz_powm_ui(res,base,exp,mod) -- Set R to (B^E) mod M.
+
+   Contributed to the GNU project by Torbjörn Granlund.
+
+Copyright 1991, 1993, 1994, 1996, 1997, 2000-2002, 2005, 2008, 2009,
+2011-2013, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* This code is very old, and should be rewritten to current GMP standard.  It
+   is slower than mpz_powm for large exponents, but also for small exponents
+   when the mod argument is small.
+
+   As an intermediate solution, we now deflect to mpz_powm for exponents >= 20.
+*/
+
+/*
+  b ^ e mod m   res
+  0   0     0    ?
+  0   e     0    ?
+  0   0     m    ?
+  0   e     m    0
+  b   0     0    ?
+  b   e     0    ?
+  b   0     m    1 mod m
+  b   e     m    b^e mod m
+*/
+
+static void
+mod (mp_ptr np, mp_size_t nn, mp_srcptr dp, mp_size_t dn, gmp_pi1_t *dinv, mp_ptr tp)
+{
+  mp_ptr qp = tp;
+
+  if (dn == 1)
+    {
+      np[0] = mpn_divrem_1 (qp, (mp_size_t) 0, np, nn, dp[0]);
+    }
+  else if (dn == 2)
+    {
+      mpn_div_qr_2n_pi1 (qp, np, np, nn, dp[1], dp[0], dinv->inv32);
+    }
+  else if (BELOW_THRESHOLD (dn, DC_DIV_QR_THRESHOLD) ||
+	   BELOW_THRESHOLD (nn - dn, DC_DIV_QR_THRESHOLD))
+    {
+      mpn_sbpi1_div_qr (qp, np, nn, dp, dn, dinv->inv32);
+    }
+  else if (BELOW_THRESHOLD (dn, MUPI_DIV_QR_THRESHOLD) ||   /* fast condition */
+	   BELOW_THRESHOLD (nn, 2 * MU_DIV_QR_THRESHOLD) || /* fast condition */
+	   (double) (2 * (MU_DIV_QR_THRESHOLD - MUPI_DIV_QR_THRESHOLD)) * dn /* slow... */
+	   + (double) MUPI_DIV_QR_THRESHOLD * nn > (double) dn * nn)    /* ...condition */
+    {
+      mpn_dcpi1_div_qr (qp, np, nn, dp, dn, dinv);
+    }
+  else
+    {
+      /* We need to allocate separate remainder area, since mpn_mu_div_qr does
+	 not handle overlap between the numerator and remainder areas.
+	 FIXME: Make it handle such overlap.  */
+      mp_ptr rp, scratch;
+      mp_size_t itch;
+      TMP_DECL;
+      TMP_MARK;
+
+      itch = mpn_mu_div_qr_itch (nn, dn, 0);
+      rp = TMP_BALLOC_LIMBS (dn);
+      scratch = TMP_BALLOC_LIMBS (itch);
+
+      mpn_mu_div_qr (qp, rp, np, nn, dp, dn, scratch);
+      MPN_COPY (np, rp, dn);
+
+      TMP_FREE;
+    }
+}
+
+/* Compute t = a mod m, a is defined by (ap,an), m is defined by (mp,mn), and
+   t is defined by (tp,mn).  */
+static void
+reduce (mp_ptr tp, mp_srcptr ap, mp_size_t an, mp_srcptr mp, mp_size_t mn, gmp_pi1_t *dinv)
+{
+  mp_ptr rp, scratch;
+  TMP_DECL;
+  TMP_MARK;
+
+  TMP_ALLOC_LIMBS_2 (rp, an, scratch, an - mn + 1);
+  MPN_COPY (rp, ap, an);
+  mod (rp, an, mp, mn, dinv, scratch);
+  MPN_COPY (tp, rp, mn);
+
+  TMP_FREE;
+}
+
+void
+mpz_powm_ui (mpz_ptr r, mpz_srcptr b, unsigned long int el, mpz_srcptr m)
+{
+  if (el < 20)
+    {
+      mp_ptr xp, tp, mp, bp, scratch;
+      mp_size_t xn, tn, mn, bn;
+      int m_zero_cnt;
+      int c;
+      mp_limb_t e, m2;
+      gmp_pi1_t dinv;
+      TMP_DECL;
+
+      mp = PTR(m);
+      mn = ABSIZ(m);
+      if (UNLIKELY (mn == 0))
+	DIVIDE_BY_ZERO;
+
+      if (el <= 1)
+	{
+	  if (el == 1)
+	    {
+	      mpz_mod (r, b, m);
+	      return;
+	    }
+	  /* Exponent is zero, result is 1 mod M, i.e., 1 or 0 depending on if
+	     M equals 1.  */
+	  SIZ(r) = mn != 1 || mp[0] != 1;
+	  MPZ_NEWALLOC (r, 1)[0] = 1;
+	  return;
+	}
+
+      TMP_MARK;
+
+      /* Normalize m (i.e. make its most significant bit set) as required by
+	 division functions below.  */
+      count_leading_zeros (m_zero_cnt, mp[mn - 1]);
+      m_zero_cnt -= GMP_NAIL_BITS;
+      if (m_zero_cnt != 0)
+	{
+	  mp_ptr new_mp = TMP_ALLOC_LIMBS (mn);
+	  mpn_lshift (new_mp, mp, mn, m_zero_cnt);
+	  mp = new_mp;
+	}
+
+      m2 = mn == 1 ? 0 : mp[mn - 2];
+      invert_pi1 (dinv, mp[mn - 1], m2);
+
+      bn = ABSIZ(b);
+      bp = PTR(b);
+      if (bn > mn)
+	{
+	  /* Reduce possibly huge base.  Use a function call to reduce, since we
+	     don't want the quotient allocation to live until function return.  */
+	  mp_ptr new_bp = TMP_ALLOC_LIMBS (mn);
+	  reduce (new_bp, bp, bn, mp, mn, &dinv);
+	  bp = new_bp;
+	  bn = mn;
+	  /* Canonicalize the base, since we are potentially going to multiply with
+	     it quite a few times.  */
+	  MPN_NORMALIZE (bp, bn);
+	}
+
+      if (bn == 0)
+	{
+	  SIZ(r) = 0;
+	  TMP_FREE;
+	  return;
+	}
+
+      TMP_ALLOC_LIMBS_3 (xp, mn, scratch, mn + 1, tp, 2 * mn + 1);
+
+      MPN_COPY (xp, bp, bn);
+      xn = bn;
+
+      e = el;
+      count_leading_zeros (c, e);
+      e = (e << c) << 1;		/* shift the exp bits to the left, lose msb */
+      c = GMP_LIMB_BITS - 1 - c;
+
+      ASSERT (c != 0); /* el > 1 */
+	{
+	  /* Main loop. */
+	  do
+	    {
+	      mpn_sqr (tp, xp, xn);
+	      tn = 2 * xn; tn -= tp[tn - 1] == 0;
+	      if (tn < mn)
+		{
+		  MPN_COPY (xp, tp, tn);
+		  xn = tn;
+		}
+	      else
+		{
+		  mod (tp, tn, mp, mn, &dinv, scratch);
+		  MPN_COPY (xp, tp, mn);
+		  xn = mn;
+		}
+
+	      if ((mp_limb_signed_t) e < 0)
+		{
+		  mpn_mul (tp, xp, xn, bp, bn);
+		  tn = xn + bn; tn -= tp[tn - 1] == 0;
+		  if (tn < mn)
+		    {
+		      MPN_COPY (xp, tp, tn);
+		      xn = tn;
+		    }
+		  else
+		    {
+		      mod (tp, tn, mp, mn, &dinv, scratch);
+		      MPN_COPY (xp, tp, mn);
+		      xn = mn;
+		    }
+		}
+	      e <<= 1;
+	      c--;
+	    }
+	  while (c != 0);
+	}
+
+      /* We shifted m left m_zero_cnt steps.  Adjust the result by reducing it
+	 with the original M.  */
+      if (m_zero_cnt != 0)
+	{
+	  mp_limb_t cy;
+	  cy = mpn_lshift (tp, xp, xn, m_zero_cnt);
+	  tp[xn] = cy; xn += cy != 0;
+
+	  if (xn >= mn)
+	    {
+	      mod (tp, xn, mp, mn, &dinv, scratch);
+	      xn = mn;
+	    }
+	  mpn_rshift (xp, tp, xn, m_zero_cnt);
+	}
+      MPN_NORMALIZE (xp, xn);
+
+      if ((el & 1) != 0 && SIZ(b) < 0 && xn != 0)
+	{
+	  mp = PTR(m);			/* want original, unnormalized m */
+	  mpn_sub (xp, mp, mn, xp, xn);
+	  xn = mn;
+	  MPN_NORMALIZE (xp, xn);
+	}
+      MPZ_NEWALLOC (r, xn);
+      SIZ (r) = xn;
+      MPN_COPY (PTR(r), xp, xn);
+
+      TMP_FREE;
+    }
+  else
+    {
+      /* For large exponents, fake an mpz_t exponent and deflect to the more
+	 sophisticated mpz_powm.  */
+      mpz_t e;
+      mp_limb_t ep[LIMBS_PER_ULONG];
+      MPZ_FAKE_UI (e, ep, el);
+      mpz_powm (r, b, e, m);
+    }
+}
diff --git a/third_party/gmp/mpz/pprime_p.c b/third_party/gmp/mpz/pprime_p.c
new file mode 100644
index 0000000..b8a21c2
--- /dev/null
+++ b/third_party/gmp/mpz/pprime_p.c
@@ -0,0 +1,166 @@
+/* mpz_probab_prime_p --
+   An implementation of the probabilistic primality test found in Knuth's
+   Seminumerical Algorithms book.  If the function mpz_probab_prime_p()
+   returns 0 then n is not prime.  If it returns 1, then n is 'probably'
+   prime.  If it returns 2, n is surely prime.  The probability of a false
+   positive is (1/4)**reps, where reps is the number of internal passes of the
+   probabilistic algorithm.  Knuth indicates that 25 passes are reasonable.
+
+Copyright 1991, 1993, 1994, 1996-2002, 2005, 2015, 2016 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+static int isprime (unsigned long int);
+
+
+/* MPN_MOD_OR_MODEXACT_1_ODD can be used instead of mpn_mod_1 for the trial
+   division.  It gives a result which is not the actual remainder r but a
+   value congruent to r*2^n mod d.  Since all the primes being tested are
+   odd, r*2^n mod p will be 0 if and only if r mod p is 0.  */
+
+int
+mpz_probab_prime_p (mpz_srcptr n, int reps)
+{
+  mp_limb_t r;
+  mpz_t n2;
+
+  /* Handle small and negative n.  */
+  if (mpz_cmp_ui (n, 1000000L) <= 0)
+    {
+      if (mpz_cmpabs_ui (n, 1000000L) <= 0)
+	{
+	  int is_prime;
+	  unsigned long n0;
+	  n0 = mpz_get_ui (n);
+	  is_prime = n0 & (n0 > 1) ? isprime (n0) : n0 == 2;
+	  return is_prime ? 2 : 0;
+	}
+      /* Negative number.  Negate and fall out.  */
+      PTR(n2) = PTR(n);
+      SIZ(n2) = -SIZ(n);
+      n = n2;
+    }
+
+  /* If n is now even, it is not a prime.  */
+  if (mpz_even_p (n))
+    return 0;
+
+#if defined (PP)
+  /* Check if n has small factors.  */
+#if defined (PP_INVERTED)
+  r = MPN_MOD_OR_PREINV_MOD_1 (PTR(n), (mp_size_t) SIZ(n), (mp_limb_t) PP,
+			       (mp_limb_t) PP_INVERTED);
+#else
+  r = mpn_mod_1 (PTR(n), (mp_size_t) SIZ(n), (mp_limb_t) PP);
+#endif
+  if (r % 3 == 0
+#if GMP_LIMB_BITS >= 4
+      || r % 5 == 0
+#endif
+#if GMP_LIMB_BITS >= 8
+      || r % 7 == 0
+#endif
+#if GMP_LIMB_BITS >= 16
+      || r % 11 == 0 || r % 13 == 0
+#endif
+#if GMP_LIMB_BITS >= 32
+      || r % 17 == 0 || r % 19 == 0 || r % 23 == 0 || r % 29 == 0
+#endif
+#if GMP_LIMB_BITS >= 64
+      || r % 31 == 0 || r % 37 == 0 || r % 41 == 0 || r % 43 == 0
+      || r % 47 == 0 || r % 53 == 0
+#endif
+      )
+    {
+      return 0;
+    }
+#endif /* PP */
+
+  /* Do more dividing.  We collect small primes, using umul_ppmm, until we
+     overflow a single limb.  We divide our number by the small primes product,
+     and look for factors in the remainder.  */
+  {
+    unsigned long int ln2;
+    unsigned long int q;
+    mp_limb_t p1, p0, p;
+    unsigned int primes[15];
+    int nprimes;
+
+    nprimes = 0;
+    p = 1;
+    ln2 = mpz_sizeinbase (n, 2);	/* FIXME: tune this limit */
+    for (q = PP_FIRST_OMITTED; q < ln2; q += 2)
+      {
+	if (isprime (q))
+	  {
+	    umul_ppmm (p1, p0, p, q);
+	    if (p1 != 0)
+	      {
+		r = MPN_MOD_OR_MODEXACT_1_ODD (PTR(n), (mp_size_t) SIZ(n), p);
+		while (--nprimes >= 0)
+		  if (r % primes[nprimes] == 0)
+		    {
+		      ASSERT_ALWAYS (mpn_mod_1 (PTR(n), (mp_size_t) SIZ(n), (mp_limb_t) primes[nprimes]) == 0);
+		      return 0;
+		    }
+		p = q;
+		nprimes = 0;
+	      }
+	    else
+	      {
+		p = p0;
+	      }
+	    primes[nprimes++] = q;
+	  }
+      }
+  }
+
+  /* Perform a number of Miller-Rabin tests.  */
+  return mpz_millerrabin (n, reps);
+}
+
+static int
+isprime (unsigned long int t)
+{
+  unsigned long int q, r, d;
+
+  ASSERT (t >= 3 && (t & 1) != 0);
+
+  d = 3;
+  do {
+      q = t / d;
+      r = t - q * d;
+      if (q < d)
+	return 1;
+      d += 2;
+  } while (r != 0);
+  return 0;
+}
diff --git a/third_party/gmp/mpz/primorial_ui.c b/third_party/gmp/mpz/primorial_ui.c
new file mode 100644
index 0000000..2703919
--- /dev/null
+++ b/third_party/gmp/mpz/primorial_ui.c
@@ -0,0 +1,162 @@
+/* mpz_primorial_ui(RESULT, N) -- Set RESULT to N# the product of primes <= N.
+
+Contributed to the GNU project by Marco Bodrato.
+
+Copyright 2012, 2015, 2016 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/* TODO: Remove duplicated constants / macros / static functions...
+ */
+
+/*************************************************************/
+/* Section macros: common macros, for swing/fac/bin (&sieve) */
+/*************************************************************/
+
+#define FACTOR_LIST_STORE(P, PR, MAX_PR, VEC, I)		\
+  do {								\
+    if ((PR) > (MAX_PR)) {					\
+      (VEC)[(I)++] = (PR);					\
+      (PR) = (P);						\
+    } else							\
+      (PR) *= (P);						\
+  } while (0)
+
+#define LOOP_ON_SIEVE_CONTINUE(prime,end,sieve)			\
+    __max_i = (end);						\
+								\
+    do {							\
+      ++__i;							\
+      if (((sieve)[__index] & __mask) == 0)			\
+	{							\
+	  mp_limb_t prime;					\
+	  prime = id_to_n(__i)
+
+#define LOOP_ON_SIEVE_BEGIN(prime,start,end,off,sieve)		\
+  do {								\
+    mp_limb_t __mask, __index, __max_i, __i;			\
+								\
+    __i = (start)-(off);					\
+    __index = __i / GMP_LIMB_BITS;				\
+    __mask = CNST_LIMB(1) << (__i % GMP_LIMB_BITS);		\
+    __i += (off);						\
+								\
+    LOOP_ON_SIEVE_CONTINUE(prime,end,sieve)
+
+#define LOOP_ON_SIEVE_STOP					\
+	}							\
+      __mask = __mask << 1 | __mask >> (GMP_LIMB_BITS-1);	\
+      __index += __mask & 1;					\
+    }  while (__i <= __max_i)
+
+#define LOOP_ON_SIEVE_END					\
+    LOOP_ON_SIEVE_STOP;						\
+  } while (0)
+
+/*********************************************************/
+/* Section sieve: sieving functions and tools for primes */
+/*********************************************************/
+
+#if 0
+static mp_limb_t
+bit_to_n (mp_limb_t bit) { return (bit*3+4)|1; }
+#endif
+
+/* id_to_n (x) = bit_to_n (x-1) = (id*3+1)|1*/
+static mp_limb_t
+id_to_n  (mp_limb_t id)  { return id*3+1+(id&1); }
+
+/* n_to_bit (n) = ((n-1)&(-CNST_LIMB(2)))/3U-1 */
+static mp_limb_t
+n_to_bit (mp_limb_t n) { return ((n-5)|1)/3U; }
+
+#if WANT_ASSERT
+static mp_size_t
+primesieve_size (mp_limb_t n) { return n_to_bit(n) / GMP_LIMB_BITS + 1; }
+#endif
+
+/*********************************************************/
+/* Section primorial: implementation                     */
+/*********************************************************/
+
+void
+mpz_primorial_ui (mpz_ptr x, unsigned long n)
+{
+  ASSERT (n <= GMP_NUMB_MAX);
+
+  if (n < 5)
+    {
+      MPZ_NEWALLOC (x, 1)[0] = (066211 >> (n*3)) & 7;
+      SIZ (x) = 1;
+    }
+  else
+    {
+      mp_limb_t *sieve, *factors;
+      mp_size_t size, j;
+      mp_limb_t prod;
+      TMP_DECL;
+
+      size = n / GMP_NUMB_BITS;
+      size = size + (size >> 1) + 1;
+      ASSERT (size >= primesieve_size (n));
+      sieve = MPZ_NEWALLOC (x, size);
+      size = (gmp_primesieve (sieve, n) + 1) / log_n_max (n) + 1;
+
+      TMP_MARK;
+      factors = TMP_ALLOC_LIMBS (size);
+
+      j = 0;
+
+      prod = 6;
+
+      /* Store primes from 5 to n */
+      {
+	mp_limb_t max_prod;
+
+	max_prod = GMP_NUMB_MAX / n;
+
+	LOOP_ON_SIEVE_BEGIN (prime, n_to_bit(5), n_to_bit (n), 0, sieve);
+	FACTOR_LIST_STORE (prime, prod, max_prod, factors, j);
+	LOOP_ON_SIEVE_END;
+      }
+
+      if (j != 0)
+	{
+	  factors[j++] = prod;
+	  mpz_prodlimbs (x, factors, j);
+	}
+      else
+	{
+	  PTR (x)[0] = prod;
+	  SIZ (x) = 1;
+	}
+
+      TMP_FREE;
+    }
+}
diff --git a/third_party/gmp/mpz/prodlimbs.c b/third_party/gmp/mpz/prodlimbs.c
new file mode 100644
index 0000000..23f06a1
--- /dev/null
+++ b/third_party/gmp/mpz/prodlimbs.c
@@ -0,0 +1,108 @@
+/* mpz_prodlimbs(RESULT, V, LEN) -- Set RESULT to V[0]*V[1]*...*V[LEN-1].
+
+Contributed to the GNU project by Marco Bodrato.
+
+THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.
+IT IS ONLY SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.
+IN FACT, IT IS ALMOST GUARANTEED THAT IT WILL CHANGE OR
+DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2010-2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/*********************************************************/
+/* Section list-prod: product of a list -> mpz_t         */
+/*********************************************************/
+
+/* FIXME: should be tuned */
+#ifndef RECURSIVE_PROD_THRESHOLD
+#define RECURSIVE_PROD_THRESHOLD (MUL_TOOM22_THRESHOLD)
+#endif
+
+/* Computes the product of the j>1 limbs pointed by factors, puts the
+ * result in x. It assumes that all limbs are non-zero. Above
+ * Karatsuba's threshold it uses a binary splitting strategy, to gain
+ * speed by the asymptotically fast multiplication algorithms.
+ *
+ * The list in  {factors, j} is overwritten.
+ * Returns the size of the result
+ */
+
+mp_size_t
+mpz_prodlimbs (mpz_ptr x, mp_ptr factors, mp_size_t j)
+{
+  mp_limb_t cy;
+  mp_size_t size, i;
+  mp_ptr    prod;
+
+  ASSERT (j > 1);
+  ASSERT (RECURSIVE_PROD_THRESHOLD > 3);
+
+  if (BELOW_THRESHOLD (j, RECURSIVE_PROD_THRESHOLD)) {
+    j--;
+    size = 1;
+
+    for (i = 1; i < j; i++)
+      {
+	cy = mpn_mul_1 (factors, factors, size, factors[i]);
+	factors[size] = cy;
+	size += cy != 0;
+      };
+
+    prod = MPZ_NEWALLOC (x, size + 1);
+
+    cy = mpn_mul_1 (prod, factors, size, factors[i]);
+    prod[size] = cy;
+    return SIZ (x) = size + (cy != 0);
+  } else {
+    mpz_t x1, x2;
+    TMP_DECL;
+
+    i = j >> 1;
+    j -= i;
+    TMP_MARK;
+
+    MPZ_TMP_INIT (x2, j);
+
+    PTR (x1) = factors + i;
+    ALLOC (x1) = j;
+    j = mpz_prodlimbs (x2, factors + i, j);
+    i = mpz_prodlimbs (x1, factors, i);
+    size = i + j;
+    prod = MPZ_NEWALLOC (x, size);
+    if (i >= j)
+      cy = mpn_mul (prod, PTR(x1), i, PTR(x2), j);
+    else
+      cy = mpn_mul (prod, PTR(x2), j, PTR(x1), i);
+    TMP_FREE;
+
+    return SIZ (x) = size - (cy == 0);
+  }
+}
diff --git a/third_party/gmp/mpz/random.c b/third_party/gmp/mpz/random.c
new file mode 100644
index 0000000..1a1e515
--- /dev/null
+++ b/third_party/gmp/mpz/random.c
@@ -0,0 +1,39 @@
+/* mpz_random -- Generate a random mpz_t of specified size in limbs.
+
+Copyright 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_random (mpz_ptr x, mp_size_t size)
+{
+  mpz_urandomb (x, RANDS, (unsigned long) (ABS (size) * GMP_NUMB_BITS));
+  if (size < 0)
+    SIZ(x) = -SIZ(x);
+}
diff --git a/third_party/gmp/mpz/random2.c b/third_party/gmp/mpz/random2.c
new file mode 100644
index 0000000..2c72540
--- /dev/null
+++ b/third_party/gmp/mpz/random2.c
@@ -0,0 +1,51 @@
+/* mpz_random2 -- Generate a positive random mpz_t of specified size, with
+   long runs of consecutive ones and zeros in the binary representation.
+   Meant for testing of other MP routines.
+
+Copyright 1991, 1993, 1994, 1996, 2001, 2012, 2015 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_random2 (mpz_ptr x, mp_size_t size)
+{
+  mp_size_t abs_size;
+  mp_ptr xp;
+
+  abs_size = ABS (size);
+  if (abs_size != 0)
+    {
+      xp = MPZ_NEWALLOC (x, abs_size);
+
+      mpn_random2 (xp, abs_size);
+    }
+
+  SIZ (x) = size;
+}
diff --git a/third_party/gmp/mpz/realloc.c b/third_party/gmp/mpz/realloc.c
new file mode 100644
index 0000000..bb55bf6
--- /dev/null
+++ b/third_party/gmp/mpz/realloc.c
@@ -0,0 +1,78 @@
+/* _mpz_realloc -- make the mpz_t have NEW_ALLOC digits allocated.
+
+Copyright 1991, 1993-1995, 2000, 2001, 2008, 2015 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "gmp-impl.h"
+
+void *
+_mpz_realloc (mpz_ptr m, mp_size_t new_alloc)
+{
+  mp_ptr mp;
+
+  /* Never allocate zero space. */
+  new_alloc = MAX (new_alloc, 1);
+
+  if (sizeof (mp_size_t) == sizeof (int))
+    {
+      if (UNLIKELY (new_alloc > ULONG_MAX / GMP_NUMB_BITS))
+	{
+	  fprintf (stderr, "gmp: overflow in mpz type\n");
+	  abort ();
+	}
+    }
+  else
+    {
+      if (UNLIKELY (new_alloc > INT_MAX))
+	{
+	  fprintf (stderr, "gmp: overflow in mpz type\n");
+	  abort ();
+	}
+    }
+
+  if (ALLOC (m) == 0)
+    {
+      mp = __GMP_ALLOCATE_FUNC_LIMBS (new_alloc);
+    }
+  else
+    {
+      mp = __GMP_REALLOCATE_FUNC_LIMBS (PTR (m), ALLOC (m), new_alloc);
+
+      /* Don't create an invalid number; if the current value doesn't fit after
+	 reallocation, clear it to 0.  */
+      if (UNLIKELY (ABSIZ (m) > new_alloc))
+	SIZ (m) = 0;
+    }
+
+  PTR (m) = mp;
+  ALLOC(m) = new_alloc;
+  return (void *) mp;
+}
diff --git a/third_party/gmp/mpz/realloc2.c b/third_party/gmp/mpz/realloc2.c
new file mode 100644
index 0000000..5350339
--- /dev/null
+++ b/third_party/gmp/mpz/realloc2.c
@@ -0,0 +1,67 @@
+/* mpz_realloc2 -- change allocated data size.
+
+Copyright 2001, 2002, 2008, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "gmp-impl.h"
+
+void
+mpz_realloc2 (mpz_ptr m, mp_bitcnt_t bits)
+{
+  mp_size_t new_alloc;
+
+  bits -= (bits != 0);		/* Round down, except if 0 */
+  new_alloc = 1 + bits / GMP_NUMB_BITS;
+
+  if (sizeof (unsigned long) > sizeof (int)) /* param vs _mp_size field */
+    {
+      if (UNLIKELY (new_alloc > INT_MAX))
+	{
+	  fprintf (stderr, "gmp: overflow in mpz type\n");
+	  abort ();
+	}
+    }
+
+  if (ALLOC (m) == 0)
+    {
+      PTR (m) = __GMP_ALLOCATE_FUNC_LIMBS (new_alloc);
+    }
+  else
+    {
+      PTR (m) = __GMP_REALLOCATE_FUNC_LIMBS (PTR(m), ALLOC(m), new_alloc);
+
+      /* Don't create an invalid number; if the current value doesn't fit after
+	 reallocation, clear it to 0.  */
+      if (ABSIZ(m) > new_alloc)
+	SIZ(m) = 0;
+    }
+
+  ALLOC(m) = new_alloc;
+}
diff --git a/third_party/gmp/mpz/remove.c b/third_party/gmp/mpz/remove.c
new file mode 100644
index 0000000..a655121
--- /dev/null
+++ b/third_party/gmp/mpz/remove.c
@@ -0,0 +1,146 @@
+/* mpz_remove -- divide out a factor and return its multiplicity.
+
+Copyright 1998-2002, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+mp_bitcnt_t
+mpz_remove (mpz_ptr dest, mpz_srcptr src, mpz_srcptr f)
+{
+  mp_bitcnt_t pwr;
+  mp_srcptr fp;
+  mp_size_t sn, fn, afn;
+  mp_limb_t fp0;
+
+  sn = SIZ (src);
+  fn = SIZ (f);
+  fp = PTR (f);
+  afn = ABS (fn);
+  fp0 = fp[0];
+
+  if (UNLIKELY ((afn <= (fp0 == 1)) /* mpz_cmpabs_ui (f, 1) <= 0 */
+		| (sn == 0)))
+    {
+      /*  f = 0 or f = +- 1 or src = 0 */
+      if (afn == 0)
+	DIVIDE_BY_ZERO;
+      mpz_set (dest, src);
+      return 0;
+    }
+
+  if ((fp0 & 1) != 0)
+    { /* f is odd */
+      mp_ptr dp;
+      mp_size_t dn;
+
+      dn = ABS (sn);
+      dp = MPZ_REALLOC (dest, dn);
+
+      pwr = mpn_remove (dp, &dn, PTR(src), dn, PTR(f), afn, ~(mp_bitcnt_t) 0);
+
+      SIZ (dest) = ((pwr & (fn < 0)) ^ (sn < 0)) ? -dn : dn;
+    }
+  else if (afn == (fp0 == 2))
+    { /* mpz_cmpabs_ui (f, 2) == 0 */
+      pwr = mpz_scan1 (src, 0);
+      mpz_div_2exp (dest, src, pwr);
+      if (pwr & (fn < 0)) /*((pwr % 2 == 1) && (SIZ (f) < 0))*/
+	mpz_neg (dest, dest);
+    }
+  else
+    { /* f != +-2 */
+      mpz_t x, rem;
+
+      mpz_init (rem);
+      mpz_init (x);
+
+      pwr = 0;
+      mpz_tdiv_qr (x, rem, src, f);
+      if (SIZ (rem) == 0)
+	{
+	  mpz_t fpow[GMP_LIMB_BITS];		/* Really MP_SIZE_T_BITS */
+	  int p;
+
+#if WANT_ORIGINAL_DEST
+	  mp_ptr dp;
+	  dp = PTR (dest);
+#endif
+      /* We could perhaps compute mpz_scan1(src,0)/mpz_scan1(f,0).  It is an
+	 upper bound of the result we're seeking.  We could also shift down the
+	 operands so that they become odd, to make intermediate values
+	 smaller.  */
+	  mpz_init_set (fpow[0], f);
+	  mpz_swap (dest, x);
+
+	  p = 1;
+      /* Divide by f, f^2 ... f^(2^k) until we get a remainder for f^(2^k).  */
+	  while (ABSIZ (dest) >= 2 * ABSIZ (fpow[p - 1]) - 1)
+	    {
+	      mpz_init (fpow[p]);
+	      mpz_mul (fpow[p], fpow[p - 1], fpow[p - 1]);
+	      mpz_tdiv_qr (x, rem, dest, fpow[p]);
+	      if (SIZ (rem) != 0) {
+		mpz_clear (fpow[p]);
+		break;
+	      }
+	      mpz_swap (dest, x);
+	      p++;
+	    }
+
+	  pwr = ((mp_bitcnt_t)1 << p) - 1;
+
+      /* Divide by f^(2^(k-1)), f^(2^(k-2)), ..., f for all divisors that give
+	 a zero remainder.  */
+	  while (--p >= 0)
+	    {
+	      mpz_tdiv_qr (x, rem, dest, fpow[p]);
+	      if (SIZ (rem) == 0)
+		{
+		  pwr += (mp_bitcnt_t)1 << p;
+		  mpz_swap (dest, x);
+		}
+	      mpz_clear (fpow[p]);
+	    }
+
+#if WANT_ORIGINAL_DEST
+	  if (PTR (x) == dp) {
+	    mpz_swap (dest, x);
+	    mpz_set (dest, x);
+	  }
+#endif
+	}
+      else
+	mpz_set (dest, src);
+
+      mpz_clear (x);
+      mpz_clear (rem);
+    }
+
+  return pwr;
+}
diff --git a/third_party/gmp/mpz/roinit_n.c b/third_party/gmp/mpz/roinit_n.c
new file mode 100644
index 0000000..9125466
--- /dev/null
+++ b/third_party/gmp/mpz/roinit_n.c
@@ -0,0 +1,43 @@
+/* mpz_roinit_n -- Initialize mpz with read-only limb array.
+
+Copyright 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+mpz_srcptr
+mpz_roinit_n (mpz_ptr x, mp_srcptr xp, mp_size_t xs)
+{
+  mp_size_t xn = ABS(xs);
+  MPN_NORMALIZE (xp, xn);
+
+  ALLOC (x) = 0;
+  SIZ (x) = xs < 0 ? -xn : xn;
+  PTR (x) = (mp_ptr) xp;
+  return x;
+}
diff --git a/third_party/gmp/mpz/root.c b/third_party/gmp/mpz/root.c
new file mode 100644
index 0000000..7119bbc
--- /dev/null
+++ b/third_party/gmp/mpz/root.c
@@ -0,0 +1,92 @@
+/* mpz_root(root, u, nth) --  Set ROOT to floor(U^(1/nth)).
+   Return an indication if the result is exact.
+
+Copyright 1999-2003, 2005, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>		/* for NULL */
+#include "gmp-impl.h"
+
+int
+mpz_root (mpz_ptr root, mpz_srcptr u, unsigned long int nth)
+{
+  mp_ptr rootp, up;
+  mp_size_t us, un, rootn, remn;
+  TMP_DECL;
+
+  us = SIZ(u);
+
+  /* even roots of negatives provoke an exception */
+  if (UNLIKELY (us < 0 && (nth & 1) == 0))
+    SQRT_OF_NEGATIVE;
+
+  /* root extraction interpreted as c^(1/nth) means a zeroth root should
+     provoke a divide by zero, do this even if c==0 */
+  if (UNLIKELY (nth == 0))
+    DIVIDE_BY_ZERO;
+
+  if (us == 0)
+    {
+      if (root != NULL)
+	SIZ(root) = 0;
+      return 1;			/* exact result */
+    }
+
+  un = ABS (us);
+  rootn = (un - 1) / nth + 1;
+
+  TMP_MARK;
+
+  /* FIXME: Perhaps disallow root == NULL */
+  if (root != NULL && u != root)
+    rootp = MPZ_NEWALLOC (root, rootn);
+  else
+    rootp = TMP_ALLOC_LIMBS (rootn);
+
+  up = PTR(u);
+
+  if (nth == 1)
+    {
+      MPN_COPY (rootp, up, un);
+      remn = 0;
+    }
+  else
+    {
+      remn = mpn_rootrem (rootp, NULL, up, un, (mp_limb_t) nth);
+    }
+
+  if (root != NULL)
+    {
+      SIZ(root) = us >= 0 ? rootn : -rootn;
+      if (u == root)
+	MPN_COPY (up, rootp, rootn);
+    }
+
+  TMP_FREE;
+  return remn == 0;
+}
diff --git a/third_party/gmp/mpz/rootrem.c b/third_party/gmp/mpz/rootrem.c
new file mode 100644
index 0000000..67953db
--- /dev/null
+++ b/third_party/gmp/mpz/rootrem.c
@@ -0,0 +1,100 @@
+/* mpz_rootrem(root, rem, u, nth) --  Set ROOT to trunc(U^(1/nth)) and
+   set REM to the remainder.
+
+Copyright 1999-2003, 2005, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>		/* for NULL */
+#include "gmp-impl.h"
+
+void
+mpz_rootrem (mpz_ptr root, mpz_ptr rem, mpz_srcptr u, unsigned long int nth)
+{
+  mp_ptr rootp, up, remp;
+  mp_size_t us, un, rootn, remn;
+  TMP_DECL;
+
+  us = SIZ(u);
+
+  /* even roots of negatives provoke an exception */
+  if (UNLIKELY (us < 0 && (nth & 1) == 0))
+    SQRT_OF_NEGATIVE;
+
+  /* root extraction interpreted as c^(1/nth) means a zeroth root should
+     provoke a divide by zero, do this even if c==0 */
+  if (UNLIKELY (nth == 0))
+    DIVIDE_BY_ZERO;
+
+  if (us == 0)
+    {
+      if (root != NULL)
+	SIZ(root) = 0;
+      SIZ(rem) = 0;
+      return;
+    }
+
+  un = ABS (us);
+  rootn = (un - 1) / nth + 1;
+
+  TMP_MARK;
+
+  /* FIXME: Perhaps disallow root == NULL */
+  if (root != NULL && u != root)
+    rootp = MPZ_NEWALLOC (root, rootn);
+  else
+    rootp = TMP_ALLOC_LIMBS (rootn);
+
+  if (u != rem)
+    remp = MPZ_NEWALLOC (rem, un);
+  else
+    remp = TMP_ALLOC_LIMBS (un);
+
+  up = PTR(u);
+
+  if (nth == 1)
+    {
+      MPN_COPY (rootp, up, un);
+      remn = 0;
+    }
+  else
+    {
+      remn = mpn_rootrem (rootp, remp, up, un, (mp_limb_t) nth);
+    }
+
+  if (root != NULL)
+    {
+      SIZ(root) = us >= 0 ? rootn : -rootn;
+      if (u == root)
+	MPN_COPY (up, rootp, rootn);
+    }
+
+  if (u == rem)
+    MPN_COPY (up, remp, remn);
+  SIZ(rem) = us >= 0 ? remn : -remn;
+  TMP_FREE;
+}
diff --git a/third_party/gmp/mpz/rrandomb.c b/third_party/gmp/mpz/rrandomb.c
new file mode 100644
index 0000000..39546a6
--- /dev/null
+++ b/third_party/gmp/mpz/rrandomb.c
@@ -0,0 +1,102 @@
+/* mpz_rrandomb -- Generate a positive random mpz_t of specified bit size, with
+   long runs of consecutive ones and zeros in the binary representation.
+   Meant for testing of other MP routines.
+
+Copyright 2000-2002, 2004, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+static void gmp_rrandomb (mp_ptr, gmp_randstate_t, mp_bitcnt_t);
+
+void
+mpz_rrandomb (mpz_ptr x, gmp_randstate_t rstate, mp_bitcnt_t nbits)
+{
+  mp_size_t nl;
+  mp_ptr xp;
+
+  nl = BITS_TO_LIMBS (nbits);
+  if (nbits != 0)
+    {
+      xp = MPZ_NEWALLOC (x, nl);
+      gmp_rrandomb (xp, rstate, nbits);
+    }
+
+  SIZ(x) = nl;
+}
+
+/* Ask _gmp_rand for 32 bits per call unless that's more than a limb can hold.
+   Thus, we get the same random number sequence in the common cases.
+   FIXME: We should always generate the same random number sequence!  */
+#if GMP_NUMB_BITS < 32
+#define BITS_PER_RANDCALL GMP_NUMB_BITS
+#else
+#define BITS_PER_RANDCALL 32
+#endif
+
+static void
+gmp_rrandomb (mp_ptr rp, gmp_randstate_t rstate, mp_bitcnt_t nbits)
+{
+  mp_bitcnt_t bi;
+  mp_limb_t ranm;		/* buffer for random bits */
+  unsigned cap_chunksize, chunksize;
+  mp_size_t i;
+
+  /* Set entire result to 111..1  */
+  i = BITS_TO_LIMBS (nbits) - 1;
+  rp[i] = GMP_NUMB_MAX >> (GMP_NUMB_BITS - (nbits % GMP_NUMB_BITS)) % GMP_NUMB_BITS;
+  for (i = i - 1; i >= 0; i--)
+    rp[i] = GMP_NUMB_MAX;
+
+  _gmp_rand (&ranm, rstate, BITS_PER_RANDCALL);
+  cap_chunksize = nbits / (ranm % 4 + 1);
+  cap_chunksize += cap_chunksize == 0; /* make it at least 1 */
+
+  bi = nbits;
+
+  for (;;)
+    {
+      _gmp_rand (&ranm, rstate, BITS_PER_RANDCALL);
+      chunksize = 1 + ranm % cap_chunksize;
+      bi = (bi < chunksize) ? 0 : bi - chunksize;
+
+      if (bi == 0)
+	break;			/* low chunk is ...1 */
+
+      rp[bi / GMP_NUMB_BITS] ^= CNST_LIMB (1) << bi % GMP_NUMB_BITS;
+
+      _gmp_rand (&ranm, rstate, BITS_PER_RANDCALL);
+      chunksize = 1 + ranm % cap_chunksize;
+      bi = (bi < chunksize) ? 0 : bi - chunksize;
+
+      mpn_incr_u (rp + bi / GMP_NUMB_BITS, CNST_LIMB (1) << bi % GMP_NUMB_BITS);
+
+      if (bi == 0)
+	break;			/* low chunk is ...0 */
+    }
+}
diff --git a/third_party/gmp/mpz/scan0.c b/third_party/gmp/mpz/scan0.c
new file mode 100644
index 0000000..4b0f1ef
--- /dev/null
+++ b/third_party/gmp/mpz/scan0.c
@@ -0,0 +1,129 @@
+/* mpz_scan0 -- search for a 0 bit.
+
+Copyright 2000-2002, 2004, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* mpn_scan0 can't be used for the u>0 search since there might not be a 0
+   bit before the end of the data.  mpn_scan1 could be used for the inverted
+   search under u<0, but usually the search won't go very far so it seems
+   reasonable to inline that code.  */
+
+mp_bitcnt_t
+mpz_scan0 (mpz_srcptr u, mp_bitcnt_t starting_bit) __GMP_NOTHROW
+{
+  mp_srcptr      u_ptr = PTR(u);
+  mp_size_t      size = SIZ(u);
+  mp_size_t      abs_size = ABS(size);
+  mp_srcptr      u_end = u_ptr + abs_size;
+  mp_size_t      starting_limb = starting_bit / GMP_NUMB_BITS;
+  mp_srcptr      p = u_ptr + starting_limb;
+  mp_limb_t      limb;
+  int            cnt;
+
+  /* When past end, there's an immediate 0 bit for u>=0, or no 0 bits for
+     u<0.  Notice this test picks up all cases of u==0 too. */
+  if (starting_limb >= abs_size)
+    return (size >= 0 ? starting_bit : ~(mp_bitcnt_t) 0);
+
+  limb = *p;
+
+  if (size >= 0)
+    {
+      /* Mask to 1 all bits before starting_bit, thus ignoring them. */
+      limb |= (CNST_LIMB(1) << (starting_bit % GMP_NUMB_BITS)) - 1;
+
+      /* Search for a limb which isn't all ones.  If the end is reached then
+	 the zero bit immediately past the end is returned.  */
+      while (limb == GMP_NUMB_MAX)
+	{
+	  p++;
+	  if (p == u_end)
+	    return (mp_bitcnt_t) abs_size * GMP_NUMB_BITS;
+	  limb = *p;
+	}
+
+      /* Now seek low 1 bit. */
+      limb = ~limb;
+    }
+  else
+    {
+      mp_srcptr  q;
+
+      /* If there's a non-zero limb before ours then we're in the ones
+	 complement region.  Search from *(p-1) downwards since that might
+	 give better cache locality, and since a non-zero in the middle of a
+	 number is perhaps a touch more likely than at the end.  */
+      q = p;
+      while (q != u_ptr)
+	{
+	  q--;
+	  if (*q != 0)
+	    goto inverted;
+	}
+
+      /* Adjust so ~limb implied by searching for 1 bit below becomes -limb.
+	 If limb==0 here then this isn't the beginning of twos complement
+	 inversion, but that doesn't matter because limb==0 is a zero bit
+	 immediately (-1 is all ones for below).  */
+      limb--;
+
+    inverted:
+      /* Now seeking a 1 bit. */
+
+      /* Mask to 0 all bits before starting_bit, thus ignoring them. */
+      limb &= (MP_LIMB_T_MAX << (starting_bit % GMP_NUMB_BITS));
+
+      if (limb == 0)
+	{
+	  /* If the high limb is zero after masking, then no 1 bits past
+	     starting_bit.  */
+	  p++;
+	  if (p == u_end)
+	    return ~(mp_bitcnt_t) 0;
+
+	  /* Search further for a non-zero limb.  The high limb is non-zero,
+	     if nothing else.  */
+	  for (;;)
+	    {
+	      limb = *p;
+	      if (limb != 0)
+		break;
+	      p++;
+	      ASSERT (p < u_end);
+	    }
+	}
+    }
+
+  ASSERT (limb != 0);
+  count_trailing_zeros (cnt, limb);
+  return (mp_bitcnt_t) (p - u_ptr) * GMP_NUMB_BITS + cnt;
+}
diff --git a/third_party/gmp/mpz/scan1.c b/third_party/gmp/mpz/scan1.c
new file mode 100644
index 0000000..d096147
--- /dev/null
+++ b/third_party/gmp/mpz/scan1.c
@@ -0,0 +1,123 @@
+/* mpz_scan1 -- search for a 1 bit.
+
+Copyright 2000-2002, 2004, 2012, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* mpn_scan0 can't be used for the inverted u<0 search since there might not
+   be a 0 bit before the end of the data.  mpn_scan1 could be used under u>0
+   (except when in the high limb), but usually the search won't go very far
+   so it seems reasonable to inline that code.  */
+
+mp_bitcnt_t
+mpz_scan1 (mpz_srcptr u, mp_bitcnt_t starting_bit) __GMP_NOTHROW
+{
+  mp_srcptr      u_ptr = PTR(u);
+  mp_size_t      size = SIZ(u);
+  mp_size_t      abs_size = ABS(size);
+  mp_srcptr      u_end = u_ptr + abs_size - 1;
+  mp_size_t      starting_limb = starting_bit / GMP_NUMB_BITS;
+  mp_srcptr      p = u_ptr + starting_limb;
+  mp_limb_t      limb;
+  int            cnt;
+
+  /* Past the end there's no 1 bits for u>=0, or an immediate 1 bit for u<0.
+     Notice this test picks up any u==0 too. */
+  if (starting_limb >= abs_size)
+    return (size >= 0 ? ~(mp_bitcnt_t) 0 : starting_bit);
+
+  /* This is an important case, where sign is not relevant! */
+  if (starting_bit == 0)
+    goto short_cut;
+
+  limb = *p;
+
+  if (size >= 0)
+    {
+      /* Mask to 0 all bits before starting_bit, thus ignoring them. */
+      limb &= (MP_LIMB_T_MAX << (starting_bit % GMP_NUMB_BITS));
+
+      if (limb == 0)
+	{
+	  /* If it's the high limb which is zero after masking, then there's
+	     no 1 bits after starting_bit.  */
+	  if (p == u_end)
+	    return ~(mp_bitcnt_t) 0;
+
+	  /* Otherwise search further for a non-zero limb.  The high limb is
+	     non-zero, if nothing else.  */
+	search_nonzero:
+	  do
+	    {
+	      ASSERT (p != u_end);
+	      p++;
+	    short_cut:
+	      limb = *p;
+	    }
+	  while (limb == 0);
+	}
+    }
+  else
+    {
+      /* If there's a non-zero limb before ours then we're in the ones
+	 complement region.  */
+      if (starting_limb == 0 || mpn_zero_p (u_ptr, starting_limb)) {
+	if (limb == 0)
+	  /* Seeking for the first non-zero bit, it is the same for u and -u. */
+	  goto search_nonzero;
+
+	/* Adjust so ~limb implied by searching for 0 bit becomes -limb.  */
+	limb--;
+      }
+
+      /* Now seeking a 0 bit. */
+
+      /* Mask to 1 all bits before starting_bit, thus ignoring them. */
+      limb |= (CNST_LIMB(1) << (starting_bit % GMP_NUMB_BITS)) - 1;
+
+      /* Search for a limb which is not all ones.  If the end is reached
+	 then the zero immediately past the end is the result.  */
+      while (limb == GMP_NUMB_MAX)
+	{
+	  if (p == u_end)
+	    return (mp_bitcnt_t) abs_size * GMP_NUMB_BITS;
+	  p++;
+	  limb = *p;
+	}
+
+      /* Now seeking low 1 bit. */
+      limb = ~limb;
+    }
+
+  ASSERT (limb != 0);
+  count_trailing_zeros (cnt, limb);
+  return (mp_bitcnt_t) (p - u_ptr) * GMP_NUMB_BITS + cnt;
+}
diff --git a/third_party/gmp/mpz/set.c b/third_party/gmp/mpz/set.c
new file mode 100644
index 0000000..7789af3
--- /dev/null
+++ b/third_party/gmp/mpz/set.c
@@ -0,0 +1,49 @@
+/* mpz_set (dest_integer, src_integer) -- Assign DEST_INTEGER from SRC_INTEGER.
+
+Copyright 1991, 1993-1995, 2000, 2012, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+void
+mpz_set (mpz_ptr w, mpz_srcptr u)
+{
+  mp_ptr wp, up;
+  mp_size_t usize, size;
+
+  usize = SIZ(u);
+  size = ABS (usize);
+
+  wp = MPZ_NEWALLOC (w, size);
+
+  up = PTR(u);
+
+  MPN_COPY (wp, up, size);
+  SIZ(w) = usize;
+}
diff --git a/third_party/gmp/mpz/set_d.c b/third_party/gmp/mpz/set_d.c
new file mode 100644
index 0000000..8cbda11
--- /dev/null
+++ b/third_party/gmp/mpz/set_d.c
@@ -0,0 +1,113 @@
+/* mpz_set_d(integer, val) -- Assign INTEGER with a double value VAL.
+
+Copyright 1995, 1996, 2000-2003, 2006, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#if HAVE_FLOAT_H
+#include <float.h>  /* for DBL_MAX */
+#endif
+
+#include "gmp-impl.h"
+
+
+/* We used to have a special case for d < MP_BASE_AS_DOUBLE, just casting
+   double -> limb.  Unfortunately gcc 3.3 on powerpc970-apple-darwin6.8.5
+   got this wrong.  (It assumed __fixunsdfdi returned its result in a single
+   64-bit register, where instead that function followed the calling
+   conventions and gave the result in two parts r3 and r4.)  Hence the use
+   of __gmp_extract_double in all cases.  */
+
+void
+mpz_set_d (mpz_ptr r, double d)
+{
+  int negative;
+  mp_limb_t tp[LIMBS_PER_DOUBLE];
+  mp_ptr rp;
+  mp_size_t rn;
+
+  DOUBLE_NAN_INF_ACTION (d,
+			 __gmp_invalid_operation (),
+			 __gmp_invalid_operation ());
+
+  negative = d < 0;
+  d = ABS (d);
+
+  rn = __gmp_extract_double (tp, d);
+
+  if (rn <= 0)
+    rn = 0;
+
+  rp = MPZ_NEWALLOC (r, rn);
+
+  switch (rn)
+    {
+    default:
+      MPN_ZERO (rp, rn - LIMBS_PER_DOUBLE);
+      rp += rn - LIMBS_PER_DOUBLE;
+      /* fall through */
+#if LIMBS_PER_DOUBLE == 2
+    case 2:
+      rp[1] = tp[1], rp[0] = tp[0];
+      break;
+    case 1:
+      rp[0] = tp[1];
+      break;
+#endif
+#if LIMBS_PER_DOUBLE == 3
+    case 3:
+      rp[2] = tp[2], rp[1] = tp[1], rp[0] = tp[0];
+      break;
+    case 2:
+      rp[1] = tp[2], rp[0] = tp[1];
+      break;
+    case 1:
+      rp[0] = tp[2];
+      break;
+#endif
+#if LIMBS_PER_DOUBLE == 4
+    case 4:
+      rp[3] = tp[3], rp[2] = tp[2], rp[1] = tp[1], rp[0] = tp[0];
+      break;
+    case 3:
+      rp[2] = tp[3], rp[1] = tp[2], rp[0] = tp[1];
+      break;
+    case 2:
+      rp[1] = tp[3], rp[0] = tp[2];
+      break;
+    case 1:
+      rp[0] = tp[3];
+      break;
+#endif
+    case 0:
+      break;
+    }
+
+  SIZ(r) = negative ? -rn : rn;
+}
diff --git a/third_party/gmp/mpz/set_f.c b/third_party/gmp/mpz/set_f.c
new file mode 100644
index 0000000..b3ecc0b
--- /dev/null
+++ b/third_party/gmp/mpz/set_f.c
@@ -0,0 +1,71 @@
+/* mpz_set_f (dest_integer, src_float) -- Assign DEST_INTEGER from SRC_FLOAT.
+
+Copyright 1996, 2001, 2012, 2016 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+void
+mpz_set_f (mpz_ptr w, mpf_srcptr u)
+{
+  mp_ptr    wp, up;
+  mp_size_t size;
+  mp_exp_t  exp;
+
+  /* abs(u)<1 truncates to zero */
+  exp = EXP (u);
+  if (exp <= 0)
+    {
+      SIZ(w) = 0;
+      return;
+    }
+
+  wp = MPZ_NEWALLOC (w, exp);
+  up = PTR(u);
+
+  size = SIZ (u);
+  SIZ(w) = (size >= 0 ? exp : -exp);
+  size = ABS (size);
+
+  if (exp > size)
+    {
+      /* pad with low zeros to get a total "exp" many limbs */
+      mp_size_t  zeros = exp - size;
+      MPN_ZERO (wp, zeros);
+      wp += zeros;
+    }
+  else
+    {
+      /* exp<=size, truncate to the high "exp" many limbs */
+      up += (size - exp);
+      size = exp;
+    }
+
+  MPN_COPY (wp, up, size);
+}
diff --git a/third_party/gmp/mpz/set_q.c b/third_party/gmp/mpz/set_q.c
new file mode 100644
index 0000000..2280247
--- /dev/null
+++ b/third_party/gmp/mpz/set_q.c
@@ -0,0 +1,34 @@
+/* mpz_set_q (dest_integer, src_rational) -- Assign DEST_INTEGER from
+   SRC_rational.
+
+Copyright 1996, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define __GMP_FORCE_mpz_set_q 1
+
+#include "gmp-impl.h"
diff --git a/third_party/gmp/mpz/set_si.c b/third_party/gmp/mpz/set_si.c
new file mode 100644
index 0000000..973aef8
--- /dev/null
+++ b/third_party/gmp/mpz/set_si.c
@@ -0,0 +1,55 @@
+/* mpz_set_si(dest,val) -- Assign DEST with a small value VAL.
+
+Copyright 1991, 1993-1995, 2000-2002, 2012, 2015 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_set_si (mpz_ptr dest, signed long int val)
+{
+  mp_size_t size;
+  mp_limb_t vl;
+
+  vl = (mp_limb_t) ABS_CAST (unsigned long int, val);
+
+  MPZ_NEWALLOC (dest, 1)[0] = vl & GMP_NUMB_MASK;
+  size = vl != 0;
+
+#if GMP_NAIL_BITS != 0
+  if (vl > GMP_NUMB_MAX)
+    {
+      MPZ_REALLOC (dest, 2);
+      PTR (dest)[1] = vl >> GMP_NUMB_BITS;
+      size = 2;
+    }
+#endif
+
+  SIZ (dest) = val >= 0 ? size : -size;
+}
diff --git a/third_party/gmp/mpz/set_str.c b/third_party/gmp/mpz/set_str.c
new file mode 100644
index 0000000..26c102b
--- /dev/null
+++ b/third_party/gmp/mpz/set_str.c
@@ -0,0 +1,144 @@
+/* mpz_set_str(mp_dest, string, base) -- Convert the \0-terminated
+   string STRING in base BASE to multiple precision integer in
+   MP_DEST.  Allow white space in the string.  If BASE == 0 determine
+   the base in the C standard way, i.e.  0xhh...h means base 16,
+   0oo...o means base 8, otherwise assume base 10.
+
+Copyright 1991, 1993, 1994, 1996-1998, 2000-2003, 2005, 2011-2013 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <string.h>
+#include <ctype.h>
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#define digit_value_tab __gmp_digit_value_tab
+
+int
+mpz_set_str (mpz_ptr x, const char *str, int base)
+{
+  size_t str_size;
+  char *s, *begs;
+  size_t i;
+  mp_size_t xsize;
+  int c;
+  int negative;
+  const unsigned char *digit_value;
+  TMP_DECL;
+
+  digit_value = digit_value_tab;
+  if (base > 36)
+    {
+      /* For bases > 36, use the collating sequence
+	 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.  */
+      digit_value += 208;
+      if (UNLIKELY (base > 62))
+	return -1;		/* too large base */
+    }
+
+  /* Skip whitespace.  */
+  do
+    c = (unsigned char) *str++;
+  while (isspace (c));
+
+  negative = 0;
+  if (c == '-')
+    {
+      negative = 1;
+      c = (unsigned char) *str++;
+    }
+
+  if (digit_value[c] >= (base == 0 ? 10 : base))
+    return -1;			/* error if no valid digits */
+
+  /* If BASE is 0, try to find out the base by looking at the initial
+     characters.  */
+  if (base == 0)
+    {
+      base = 10;
+      if (c == '0')
+	{
+	  base = 8;
+	  c = (unsigned char) *str++;
+	  if (c == 'x' || c == 'X')
+	    {
+	      base = 16;
+	      c = (unsigned char) *str++;
+	    }
+	  else if (c == 'b' || c == 'B')
+	    {
+	      base = 2;
+	      c = (unsigned char) *str++;
+	    }
+	}
+    }
+
+  /* Skip leading zeros and white space.  */
+  while (c == '0' || isspace (c))
+    c = (unsigned char) *str++;
+  /* Make sure the string does not become empty, mpn_set_str would fail.  */
+  if (c == 0)
+    {
+      SIZ (x) = 0;
+      return 0;
+    }
+
+  TMP_MARK;
+  str_size = strlen (str - 1);
+  s = begs = (char *) TMP_ALLOC (str_size + 1);
+
+  /* Remove spaces from the string and convert the result from ASCII to a
+     byte array.  */
+  for (i = 0; i < str_size; i++)
+    {
+      if (!isspace (c))
+	{
+	  int dig = digit_value[c];
+	  if (UNLIKELY (dig >= base))
+	    {
+	      TMP_FREE;
+	      return -1;
+	    }
+	  *s++ = dig;
+	}
+      c = (unsigned char) *str++;
+    }
+
+  str_size = s - begs;
+
+  LIMBS_PER_DIGIT_IN_BASE (xsize, str_size, base);
+  MPZ_NEWALLOC (x, xsize);
+
+  /* Convert the byte array in base BASE to our bignum format.  */
+  xsize = mpn_set_str (PTR (x), (unsigned char *) begs, str_size, base);
+  SIZ (x) = negative ? -xsize : xsize;
+
+  TMP_FREE;
+  return 0;
+}
diff --git a/third_party/gmp/mpz/set_ui.c b/third_party/gmp/mpz/set_ui.c
new file mode 100644
index 0000000..12e95d1
--- /dev/null
+++ b/third_party/gmp/mpz/set_ui.c
@@ -0,0 +1,52 @@
+/* mpz_set_ui(integer, val) -- Assign INTEGER with a small value VAL.
+
+Copyright 1991, 1993-1995, 2001, 2002, 2004, 2012, 2015 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_set_ui (mpz_ptr dest, unsigned long int val)
+{
+  mp_size_t size;
+
+  MPZ_NEWALLOC (dest, 1)[0] = val & GMP_NUMB_MASK;
+  size = val != 0;
+
+#if BITS_PER_ULONG > GMP_NUMB_BITS  /* avoid warnings about shift amount */
+  if (val > GMP_NUMB_MAX)
+    {
+      MPZ_REALLOC (dest, 2);
+      PTR (dest)[1] = val >> GMP_NUMB_BITS;
+      size = 2;
+    }
+#endif
+
+  SIZ (dest) = size;
+}
diff --git a/third_party/gmp/mpz/setbit.c b/third_party/gmp/mpz/setbit.c
new file mode 100644
index 0000000..228a564
--- /dev/null
+++ b/third_party/gmp/mpz/setbit.c
@@ -0,0 +1,104 @@
+/* mpz_setbit -- set a specified bit.
+
+Copyright 1991, 1993-1995, 1997, 1999, 2001, 2002, 2012 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_setbit (mpz_ptr d, mp_bitcnt_t bit_idx)
+{
+  mp_size_t dsize = SIZ (d);
+  mp_ptr dp = PTR (d);
+  mp_size_t limb_idx;
+  mp_limb_t mask;
+
+  limb_idx = bit_idx / GMP_NUMB_BITS;
+  mask = CNST_LIMB(1) << (bit_idx % GMP_NUMB_BITS);
+  if (dsize >= 0)
+    {
+      if (limb_idx < dsize)
+	{
+	  dp[limb_idx] |= mask;
+	}
+      else
+	{
+	  /* Ugh.  The bit should be set outside of the end of the
+	     number.  We have to increase the size of the number.  */
+	  dp = MPZ_REALLOC (d, limb_idx + 1);
+	  SIZ (d) = limb_idx + 1;
+	  MPN_ZERO (dp + dsize, limb_idx - dsize);
+	  dp[limb_idx] = mask;
+	}
+    }
+  else
+    {
+      /* Simulate two's complement arithmetic, i.e. simulate
+	 1. Set OP = ~(OP - 1) [with infinitely many leading ones].
+	 2. Set the bit.
+	 3. Set OP = ~OP + 1.  */
+
+      dsize = -dsize;
+
+      if (limb_idx < dsize)
+	{
+	  mp_size_t zero_bound;
+	  /* No index upper bound on this loop, we're sure there's a non-zero limb
+	     sooner or later.  */
+	  zero_bound = 0;
+	  while (dp[zero_bound] == 0)
+	    zero_bound++;
+
+	  if (limb_idx > zero_bound)
+	    {
+	      mp_limb_t	 dlimb;
+	      dlimb = dp[limb_idx] & ~mask;
+	      dp[limb_idx] = dlimb;
+
+	      if (UNLIKELY ((dlimb == 0) + limb_idx == dsize)) /* dsize == limb_idx + 1 */
+		{
+		  /* high limb became zero, must normalize */
+		  MPN_NORMALIZE (dp, limb_idx);
+		  SIZ (d) = -limb_idx;
+		}
+	    }
+	  else if (limb_idx == zero_bound)
+	    {
+	      dp[limb_idx] = ((dp[limb_idx] - 1) & ~mask) + 1;
+	      ASSERT (dp[limb_idx] != 0);
+	    }
+	  else
+	    {
+	      MPN_DECR_U (dp + limb_idx, dsize - limb_idx, mask);
+	      dsize -= dp[dsize - 1] == 0;
+	      SIZ (d) = -dsize;
+	    }
+	}
+    }
+}
diff --git a/third_party/gmp/mpz/size.c b/third_party/gmp/mpz/size.c
new file mode 100644
index 0000000..b8aa59e
--- /dev/null
+++ b/third_party/gmp/mpz/size.c
@@ -0,0 +1,34 @@
+/* mpz_size(x) -- return the number of lims currently used by the
+   value of integer X.
+
+Copyright 1991, 1993-1995, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define __GMP_FORCE_mpz_size 1
+
+#include "gmp-impl.h"
diff --git a/third_party/gmp/mpz/sizeinbase.c b/third_party/gmp/mpz/sizeinbase.c
new file mode 100644
index 0000000..7a1bd01
--- /dev/null
+++ b/third_party/gmp/mpz/sizeinbase.c
@@ -0,0 +1,42 @@
+/* mpz_sizeinbase(x, base) -- return an approximation to the number of
+   character the integer X would have printed in base BASE.  The
+   approximation is never too small.
+
+Copyright 1991, 1993-1995, 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+size_t
+mpz_sizeinbase (mpz_srcptr x, int base) __GMP_NOTHROW
+{
+  size_t  result;
+  MPN_SIZEINBASE (result, PTR(x), ABSIZ(x), base);
+  return result;
+}
diff --git a/third_party/gmp/mpz/sqrt.c b/third_party/gmp/mpz/sqrt.c
new file mode 100644
index 0000000..74d2f75
--- /dev/null
+++ b/third_party/gmp/mpz/sqrt.c
@@ -0,0 +1,76 @@
+/* mpz_sqrt(root, u) --  Set ROOT to floor(sqrt(U)).
+
+Copyright 1991, 1993, 1994, 1996, 2000, 2001, 2005, 2012, 2015 Free
+Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h> /* for NULL */
+#include "gmp-impl.h"
+
+void
+mpz_sqrt (mpz_ptr root, mpz_srcptr op)
+{
+  mp_size_t op_size, root_size;
+  mp_ptr root_ptr, op_ptr;
+
+  op_size = SIZ (op);
+  if (UNLIKELY (op_size <= 0))
+    {
+      if (UNLIKELY (op_size < 0))
+	SQRT_OF_NEGATIVE;
+      SIZ(root) = 0;
+      return;
+    }
+
+  /* The size of the root is accurate after this simple calculation.  */
+  root_size = (op_size + 1) / 2;
+  SIZ (root) = root_size;
+
+  op_ptr = PTR (op);
+
+  if (root == op)
+    {
+      /* Allocate temp space for the root, which we then copy to the
+	 shared OP/ROOT variable.  */
+      TMP_DECL;
+      TMP_MARK;
+
+      root_ptr = TMP_ALLOC_LIMBS (root_size);
+      mpn_sqrtrem (root_ptr, NULL, op_ptr, op_size);
+
+      MPN_COPY (op_ptr, root_ptr, root_size);
+
+      TMP_FREE;
+    }
+  else
+    {
+      root_ptr = MPZ_NEWALLOC (root, root_size);
+
+      mpn_sqrtrem (root_ptr, NULL, op_ptr, op_size);
+    }
+}
diff --git a/third_party/gmp/mpz/sqrtrem.c b/third_party/gmp/mpz/sqrtrem.c
new file mode 100644
index 0000000..a580d95
--- /dev/null
+++ b/third_party/gmp/mpz/sqrtrem.c
@@ -0,0 +1,85 @@
+/* mpz_sqrtrem(root,rem,x) -- Set ROOT to floor(sqrt(X)) and REM
+   to the remainder, i.e. X - ROOT**2.
+
+Copyright 1991, 1993, 1994, 1996, 2000, 2001, 2005, 2011, 2012, 2015 Free
+Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_sqrtrem (mpz_ptr root, mpz_ptr rem, mpz_srcptr op)
+{
+  mp_size_t op_size, root_size, rem_size;
+  mp_ptr root_ptr, op_ptr, rem_ptr;
+
+  op_size = SIZ (op);
+  if (UNLIKELY (op_size <= 0))
+    {
+      if (UNLIKELY (op_size < 0))
+	SQRT_OF_NEGATIVE;
+      SIZ(root) = 0;
+      SIZ(rem) = 0;
+      return;
+    }
+
+  /* No-op if rem == op */
+  rem_ptr = MPZ_NEWALLOC (rem, op_size);
+
+  /* The size of the root is accurate after this simple calculation.  */
+  root_size = (op_size + 1) / 2;
+  SIZ (root) = root_size;
+
+  op_ptr = PTR (op);
+
+  if (root == op)
+    {
+      /* Allocate temp space for the root, which we then copy to the
+	 shared OP/ROOT variable.  */
+      TMP_DECL;
+      TMP_MARK;
+
+      root_ptr = TMP_ALLOC_LIMBS (root_size);
+      rem_size = mpn_sqrtrem (root_ptr, rem_ptr, op_ptr, op_size);
+
+      if (rem != root)	/* Don't overwrite remainder */
+	MPN_COPY (op_ptr, root_ptr, root_size);
+
+      TMP_FREE;
+    }
+  else
+    {
+      root_ptr = MPZ_NEWALLOC (root, root_size);
+
+      rem_size = mpn_sqrtrem (root_ptr, rem_ptr, op_ptr, op_size);
+    }
+
+  /* Write remainder size last, to make this function give only the square root
+     remainder, when passed ROOT == REM.  */
+  SIZ (rem) = rem_size;
+}
diff --git a/third_party/gmp/mpz/stronglucas.c b/third_party/gmp/mpz/stronglucas.c
new file mode 100644
index 0000000..350dd2a
--- /dev/null
+++ b/third_party/gmp/mpz/stronglucas.c
@@ -0,0 +1,178 @@
+/* mpz_stronglucas(n, t1, t2) -- An implementation of the strong Lucas
+   primality test on n, using parameters as suggested by the BPSW test.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2018 Free Software Foundation, Inc.
+
+Contributed by Marco Bodrato.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+/* Returns an approximation of the sqare root of x.
+ * It gives:
+ *   limb_apprsqrt (x) ^ 2 <= x < (limb_apprsqrt (x)+1) ^ 2
+ * or
+ *   x <= limb_apprsqrt (x) ^ 2 <= x * 9/8
+ */
+static mp_limb_t
+limb_apprsqrt (mp_limb_t x)
+{
+  int s;
+
+  ASSERT (x > 2);
+  count_leading_zeros (s, x);
+  s = (GMP_LIMB_BITS - s) >> 1;
+  return ((CNST_LIMB(1) << s) + (x >> s)) >> 1;
+}
+
+/* Performs strong Lucas' test on x, with parameters suggested */
+/* for the BPSW test. Qk and V are passed to recycle variables. */
+/* Requires GCD (x,6) = 1.*/
+int
+mpz_stronglucas (mpz_srcptr x, mpz_ptr V, mpz_ptr Qk)
+{
+  mp_bitcnt_t b0;
+  mpz_t n;
+  mp_limb_t D; /* The absolute value is stored. */
+  long Q;
+  mpz_t T1, T2;
+
+  /* Test on the absolute value. */
+  mpz_roinit_n (n, PTR (x), ABSIZ (x));
+
+  ASSERT (mpz_odd_p (n));
+  /* ASSERT (mpz_gcd_ui (NULL, n, 6) == 1);	*/
+#if GMP_NUMB_BITS % 16 == 0
+  /* (2^12 - 1) | (2^{GMP_NUMB_BITS*3/4} - 1)	*/
+  D = mpn_mod_34lsub1 (PTR (n), SIZ (n));
+  /* (2^12 - 1) = 3^2 * 5 * 7 * 13		*/
+  ASSERT (D % 3 != 0 && D % 5 != 0 && D % 7 != 0);
+  if ((D % 5 & 2) != 0)
+    /* (5/n) = -1, iff n = 2 or 3 (mod 5)	*/
+    /* D = 5; Q = -1 */
+    return mpn_strongfibo (PTR (n), SIZ (n), PTR (V));
+  else if (! POW2_P (D % 7))
+    /* (-7/n) = -1, iff n = 3,5 or 6 (mod 7)	*/
+    D = 7; /* Q = 2 */
+    /* (9/n) = -1, never: 9 = 3^2	*/
+  else if (mpz_kronecker_ui (n, 11) == -1)
+    /* (-11/n) = (n/11)	*/
+    D = 11; /* Q = 3 */
+  else if ((((D % 13 - (D % 13 >> 3)) & 7) > 4) ||
+	   (((D % 13 - (D % 13 >> 3)) & 7) == 2))
+    /* (13/n) = -1, iff n = 2,5,6,7,8 or 11 (mod 13)	*/
+    D = 13; /* Q = -3 */
+  else if (D % 3 == 2)
+    /* (-15/n) = (n/15) = (n/5)*(n/3)	*/
+    /* Here, (n/5) = 1, and		*/
+    /* (n/3) = -1, iff n = 2 (mod 3)	*/
+    D = 15; /* Q = 4 */
+#if GMP_NUMB_BITS % 32 == 0
+  /* (2^24 - 1) | (2^{GMP_NUMB_BITS*3/4} - 1)	*/
+  /* (2^24 - 1) = (2^12 - 1) * 17 * 241		*/
+  else if (! POW2_P (D % 17) && ! POW2_P (17 - D % 17))
+    D = 17; /* Q = -4 */
+#endif
+#else
+  if (mpz_kronecker_ui (n, 5) == -1)
+    return mpn_strongfibo (PTR (n), SIZ (n), PTR (V));
+#endif
+  else
+  {
+    mp_limb_t tl;
+    mp_limb_t maxD;
+    int jac_bit1;
+
+    if (UNLIKELY (mpz_perfect_square_p (n)))
+      return 0; /* A square is composite. */
+
+    /* Check Ds up to square root (in case, n is prime)
+       or avoid overflows */
+    if (SIZ (n) == 1)
+      maxD = limb_apprsqrt (* PTR (n));
+    else if (BITS_PER_ULONG >= GMP_NUMB_BITS && SIZ (n) == 2)
+      mpn_sqrtrem (&maxD, (mp_ptr) NULL, PTR (n), 2);
+    else
+      maxD = GMP_NUMB_MAX;
+    maxD = MIN (maxD, ULONG_MAX);
+
+    D = GMP_NUMB_BITS % 16 == 0 ? (GMP_NUMB_BITS % 32 == 0 ? 17 : 15) : 5;
+
+    /* Search a D such that (D/n) = -1 in the sequence 5,-7,9,-11,.. */
+    /* For those Ds we have (D/n) = (n/|D|) */
+    /* FIXME: Should we loop only on prime Ds?	*/
+    /* The only interesting composite D is 15.	*/
+    do
+      {
+	if (UNLIKELY (D >= maxD))
+	  return 1;
+	D += 2;
+	jac_bit1 = 0;
+	JACOBI_MOD_OR_MODEXACT_1_ODD (jac_bit1, tl, PTR (n), SIZ (n), D);
+	if (UNLIKELY (tl == 0))
+	  return 0;
+      }
+    while (mpn_jacobi_base (tl, D, jac_bit1) == 1);
+  }
+
+  /* D= P^2 - 4Q; P = 1; Q = (1-D)/4 */
+  Q = (D & 2) ? (D >> 2) + 1 : -(long) (D >> 2);
+  /* ASSERT (mpz_si_kronecker ((D & 2) ? NEG_CAST (long, D) : D, n) == -1); */
+
+  /* n-(D/n) = n+1 = d*2^{b0}, with d = (n>>b0) | 1 */
+  b0 = mpz_scan0 (n, 0);
+
+  mpz_init (T1);
+  mpz_init (T2);
+
+  /* If Ud != 0 && Vd != 0 */
+  if (mpz_lucas_mod (V, Qk, Q, b0, n, T1, T2) == 0)
+    if (LIKELY (--b0 != 0))
+      do
+	{
+	  /* V_{2k} <- V_k ^ 2 - 2Q^k */
+	  mpz_mul (T2, V, V);
+	  mpz_submul_ui (T2, Qk, 2);
+	  mpz_tdiv_r (V, T2, n);
+	  if (SIZ (V) == 0 || UNLIKELY (--b0 == 0))
+	    break;
+	  /* Q^{2k} = (Q^k)^2 */
+	  mpz_mul (T2, Qk, Qk);
+	  mpz_tdiv_r (Qk, T2, n);
+	} while (1);
+
+  mpz_clear (T1);
+  mpz_clear (T2);
+
+  return (b0 != 0);
+}
diff --git a/third_party/gmp/mpz/sub.c b/third_party/gmp/mpz/sub.c
new file mode 100644
index 0000000..7cb022e
--- /dev/null
+++ b/third_party/gmp/mpz/sub.c
@@ -0,0 +1,33 @@
+/* mpz_sub -- subtract integers.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#define OPERATION_sub
+#include "aors.h"
diff --git a/third_party/gmp/mpz/sub_ui.c b/third_party/gmp/mpz/sub_ui.c
new file mode 100644
index 0000000..3ce23d3
--- /dev/null
+++ b/third_party/gmp/mpz/sub_ui.c
@@ -0,0 +1,33 @@
+/* mpz_sub_ui -- Subtract an mpz_t and an unsigned one-word integer.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+#define OPERATION_sub_ui
+#include "aors_ui.h"
diff --git a/third_party/gmp/mpz/swap.c b/third_party/gmp/mpz/swap.c
new file mode 100644
index 0000000..255fac0
--- /dev/null
+++ b/third_party/gmp/mpz/swap.c
@@ -0,0 +1,39 @@
+/* mpz_swap (dest_integer, src_integer) -- Swap U and V.
+
+Copyright 1997, 1998, 2001, 2012, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_swap (mpz_ptr u, mpz_ptr v) __GMP_NOTHROW
+{
+  MP_SIZE_T_SWAP (ALLOC(u), ALLOC(v));
+  MP_SIZE_T_SWAP (SIZ(u), SIZ(v));
+  MP_PTR_SWAP (PTR(v), PTR(u));
+}
diff --git a/third_party/gmp/mpz/tdiv_q.c b/third_party/gmp/mpz/tdiv_q.c
new file mode 100644
index 0000000..8c5001d
--- /dev/null
+++ b/third_party/gmp/mpz/tdiv_q.c
@@ -0,0 +1,87 @@
+/* mpz_tdiv_q -- divide two integers and produce a quotient.
+
+Copyright 1991, 1993, 1994, 1996, 2000, 2001, 2005, 2010, 2012 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+void
+mpz_tdiv_q (mpz_ptr quot, mpz_srcptr num, mpz_srcptr den)
+{
+  mp_size_t ql;
+  mp_size_t ns, ds, nl, dl;
+  mp_ptr np, dp, qp, tp;
+  TMP_DECL;
+
+  ns = SIZ (num);
+  ds = SIZ (den);
+  nl = ABS (ns);
+  dl = ABS (ds);
+  ql = nl - dl + 1;
+
+  if (UNLIKELY (dl == 0))
+    DIVIDE_BY_ZERO;
+
+  if (ql <= 0)
+    {
+      SIZ (quot) = 0;
+      return;
+    }
+
+  qp = MPZ_REALLOC (quot, ql);
+
+  TMP_MARK;
+  dp = PTR (den);
+
+  /* Copy denominator to temporary space if it overlaps with the quotient.  */
+  if (dp == qp)
+    {
+      mp_ptr tp;
+      tp = TMP_ALLOC_LIMBS (dl);
+      MPN_COPY (tp, dp, dl);
+      dp = tp;
+    }
+
+  tp = TMP_ALLOC_LIMBS (nl + 1);
+  np = PTR (num);
+  /* Copy numerator to temporary space if it overlaps with the quotient.  */
+  if (np == qp)
+    {
+      MPN_COPY (tp, np, nl);
+      /* Overlap dividend and scratch.  */
+      np = tp;
+    }
+  mpn_div_q (qp, np, nl, dp, dl, tp);
+
+  ql -=  qp[ql - 1] == 0;
+
+  SIZ (quot) = (ns ^ ds) >= 0 ? ql : -ql;
+  TMP_FREE;
+}
diff --git a/third_party/gmp/mpz/tdiv_q_2exp.c b/third_party/gmp/mpz/tdiv_q_2exp.c
new file mode 100644
index 0000000..c6b9bd0
--- /dev/null
+++ b/third_party/gmp/mpz/tdiv_q_2exp.c
@@ -0,0 +1,67 @@
+/* mpz_tdiv_q_2exp -- Divide an integer by 2**CNT.  Round the quotient
+   towards -infinity.
+
+Copyright 1991, 1993, 1994, 1996, 2001, 2002, 2012 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_tdiv_q_2exp (mpz_ptr r, mpz_srcptr u, mp_bitcnt_t cnt)
+{
+  mp_size_t un, rn;
+  mp_size_t limb_cnt;
+  mp_ptr rp;
+  mp_srcptr up;
+
+  un = SIZ(u);
+  limb_cnt = cnt / GMP_NUMB_BITS;
+  rn = ABS (un) - limb_cnt;
+
+  if (rn <= 0)
+    rn = 0;
+  else
+    {
+      rp = MPZ_REALLOC (r, rn);
+      up = PTR(u) + limb_cnt;
+
+      cnt %= GMP_NUMB_BITS;
+      if (cnt != 0)
+	{
+	  mpn_rshift (rp, up, rn, cnt);
+	  rn -= rp[rn - 1] == 0;
+	}
+      else
+	{
+	  MPN_COPY_INCR (rp, up, rn);
+	}
+    }
+
+  SIZ(r) = un >= 0 ? rn : -rn;
+}
diff --git a/third_party/gmp/mpz/tdiv_q_ui.c b/third_party/gmp/mpz/tdiv_q_ui.c
new file mode 100644
index 0000000..a11c51e
--- /dev/null
+++ b/third_party/gmp/mpz/tdiv_q_ui.c
@@ -0,0 +1,83 @@
+/* mpz_tdiv_q_ui(quot, dividend, divisor_limb)
+   -- Divide DIVIDEND by DIVISOR_LIMB and store the result in QUOT.
+
+Copyright 1991, 1993, 1994, 1996, 1998, 2001, 2002, 2004, 2012 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+unsigned long int
+mpz_tdiv_q_ui (mpz_ptr quot, mpz_srcptr dividend, unsigned long int divisor)
+{
+  mp_size_t ns, nn, qn;
+  mp_ptr np, qp;
+  mp_limb_t rl;
+
+  if (UNLIKELY (divisor == 0))
+    DIVIDE_BY_ZERO;
+
+  ns = SIZ(dividend);
+  if (ns == 0)
+    {
+      SIZ(quot) = 0;
+      return 0;
+    }
+
+  nn = ABS(ns);
+  qp = MPZ_REALLOC (quot, nn);
+  np = PTR(dividend);
+
+#if BITS_PER_ULONG > GMP_NUMB_BITS  /* avoid warnings about shift amount */
+  if (divisor > GMP_NUMB_MAX)
+    {
+      mp_limb_t dp[2], rp[2];
+
+      if (nn == 1)		/* tdiv_qr requirements; tested above for 0 */
+	{
+	  SIZ(quot) = 0;
+	  rl = np[0];
+	  return rl;
+	}
+
+      dp[0] = divisor & GMP_NUMB_MASK;
+      dp[1] = divisor >> GMP_NUMB_BITS;
+      mpn_tdiv_qr (qp, rp, (mp_size_t) 0, np, nn, dp, (mp_size_t) 2);
+      rl = rp[0] + (rp[1] << GMP_NUMB_BITS);
+      qn = nn - 2 + 1; qn -= qp[qn - 1] == 0; qn -= qn != 0 && qp[qn - 1] == 0;
+    }
+  else
+#endif
+    {
+      rl = mpn_divrem_1 (qp, (mp_size_t) 0, np, nn, (mp_limb_t) divisor);
+      qn = nn - (qp[nn - 1] == 0);
+    }
+
+  SIZ(quot) = ns >= 0 ? qn : -qn;
+  return rl;
+}
diff --git a/third_party/gmp/mpz/tdiv_qr.c b/third_party/gmp/mpz/tdiv_qr.c
new file mode 100644
index 0000000..eda9501
--- /dev/null
+++ b/third_party/gmp/mpz/tdiv_qr.c
@@ -0,0 +1,106 @@
+/* mpz_tdiv_qr(quot,rem,dividend,divisor) -- Set QUOT to DIVIDEND/DIVISOR,
+   and REM to DIVIDEND mod DIVISOR.
+
+Copyright 1991, 1993, 1994, 2000, 2001, 2005, 2011, 2012 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+void
+mpz_tdiv_qr (mpz_ptr quot, mpz_ptr rem, mpz_srcptr num, mpz_srcptr den)
+{
+  mp_size_t ql;
+  mp_size_t ns, ds, nl, dl;
+  mp_ptr np, dp, qp, rp;
+  TMP_DECL;
+
+  ns = SIZ (num);
+  ds = SIZ (den);
+  nl = ABS (ns);
+  dl = ABS (ds);
+  ql = nl - dl + 1;
+
+  if (UNLIKELY (dl == 0))
+    DIVIDE_BY_ZERO;
+
+  rp = MPZ_REALLOC (rem, dl);
+
+  if (ql <= 0)
+    {
+      if (num != rem)
+	{
+	  np = PTR (num);
+	  MPN_COPY (rp, np, nl);
+	  SIZ (rem) = SIZ (num);
+	}
+      /* This needs to follow the assignment to rem, in case the
+	 numerator and quotient are the same.  */
+      SIZ (quot) = 0;
+      return;
+    }
+
+  qp = MPZ_REALLOC (quot, ql);
+
+  TMP_MARK;
+  np = PTR (num);
+  dp = PTR (den);
+
+  /* FIXME: We should think about how to handle the temporary allocation.
+     Perhaps mpn_tdiv_qr should handle it, since it anyway often needs to
+     allocate temp space.  */
+
+  /* Copy denominator to temporary space if it overlaps with the quotient
+     or remainder.  */
+  if (dp == rp || dp == qp)
+    {
+      mp_ptr tp;
+      tp = TMP_ALLOC_LIMBS (dl);
+      MPN_COPY (tp, dp, dl);
+      dp = tp;
+    }
+  /* Copy numerator to temporary space if it overlaps with the quotient or
+     remainder.  */
+  if (np == rp || np == qp)
+    {
+      mp_ptr tp;
+      tp = TMP_ALLOC_LIMBS (nl);
+      MPN_COPY (tp, np, nl);
+      np = tp;
+    }
+
+  mpn_tdiv_qr (qp, rp, 0L, np, nl, dp, dl);
+
+  ql -=  qp[ql - 1] == 0;
+  MPN_NORMALIZE (rp, dl);
+
+  SIZ (quot) = (ns ^ ds) >= 0 ? ql : -ql;
+  SIZ (rem) = ns >= 0 ? dl : -dl;
+  TMP_FREE;
+}
diff --git a/third_party/gmp/mpz/tdiv_qr_ui.c b/third_party/gmp/mpz/tdiv_qr_ui.c
new file mode 100644
index 0000000..4e1c9fa
--- /dev/null
+++ b/third_party/gmp/mpz/tdiv_qr_ui.c
@@ -0,0 +1,100 @@
+/* mpz_tdiv_qr_ui(quot,rem,dividend,short_divisor) --
+   Set QUOT to DIVIDEND / SHORT_DIVISOR
+   and REM to DIVIDEND mod SHORT_DIVISOR.
+
+Copyright 1991, 1993, 1994, 1996, 1998, 2001, 2002, 2004, 2012, 2015
+Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+unsigned long int
+mpz_tdiv_qr_ui (mpz_ptr quot, mpz_ptr rem, mpz_srcptr dividend, unsigned long int divisor)
+{
+  mp_size_t ns, nn, qn;
+  mp_ptr np, qp;
+  mp_limb_t rl;
+
+  if (UNLIKELY (divisor == 0))
+    DIVIDE_BY_ZERO;
+
+  ns = SIZ(dividend);
+  if (ns == 0)
+    {
+      SIZ(quot) = 0;
+      SIZ(rem) = 0;
+      return 0;
+    }
+
+  nn = ABS(ns);
+  qp = MPZ_REALLOC (quot, nn);
+  np = PTR(dividend);
+
+#if BITS_PER_ULONG > GMP_NUMB_BITS  /* avoid warnings about shift amount */
+  if (divisor > GMP_NUMB_MAX)
+    {
+      mp_limb_t dp[2];
+      mp_ptr rp;
+      mp_size_t rn;
+
+      if (nn == 1)		/* tdiv_qr requirements; tested above for 0 */
+	{
+	  SIZ(quot) = 0;
+	  rl = np[0];
+	  SIZ(rem) = ns >= 0 ? 1 : -1;
+	  MPZ_NEWALLOC (rem, 1)[0] = rl;
+	  return rl;
+	}
+
+      rp = MPZ_REALLOC (rem, 2);
+
+      dp[0] = divisor & GMP_NUMB_MASK;
+      dp[1] = divisor >> GMP_NUMB_BITS;
+      mpn_tdiv_qr (qp, rp, (mp_size_t) 0, np, nn, dp, (mp_size_t) 2);
+      rl = rp[0] + (rp[1] << GMP_NUMB_BITS);
+      qn = nn - 2 + 1; qn -= qp[qn - 1] == 0; qn -= qn != 0 && qp[qn - 1] == 0;
+      rn = 2 - (rp[1] == 0);  rn -= (rp[rn - 1] == 0);
+      SIZ(rem) = ns >= 0 ? rn : -rn;
+    }
+  else
+#endif
+    {
+      rl = mpn_divrem_1 (qp, (mp_size_t) 0, np, nn, (mp_limb_t) divisor);
+      if (rl == 0)
+	SIZ(rem) = 0;
+      else
+	{
+	  SIZ(rem) = ns >= 0 ? 1 : -1;
+	  MPZ_NEWALLOC (rem, 1)[0] = rl;
+	}
+      qn = nn - (qp[nn - 1] == 0);
+    }
+
+  SIZ(quot) = ns >= 0 ? qn : -qn;
+  return rl;
+}
diff --git a/third_party/gmp/mpz/tdiv_r.c b/third_party/gmp/mpz/tdiv_r.c
new file mode 100644
index 0000000..c76275e
--- /dev/null
+++ b/third_party/gmp/mpz/tdiv_r.c
@@ -0,0 +1,97 @@
+/* mpz_tdiv_r(rem, dividend, divisor) -- Set REM to DIVIDEND mod DIVISOR.
+
+Copyright 1991, 1993, 1994, 2000, 2001, 2005, 2012 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+void
+mpz_tdiv_r (mpz_ptr rem, mpz_srcptr num, mpz_srcptr den)
+{
+  mp_size_t ql;
+  mp_size_t ns, nl, dl;
+  mp_ptr np, dp, qp, rp;
+  TMP_DECL;
+
+  ns = SIZ (num);
+  nl = ABS (ns);
+  dl = ABSIZ (den);
+  ql = nl - dl + 1;
+
+  if (UNLIKELY (dl == 0))
+    DIVIDE_BY_ZERO;
+
+  if (ql <= 0)
+    {
+      if (num != rem)
+	{
+	  SIZ (rem) = ns;
+	  rp = MPZ_NEWALLOC (rem, nl);
+	  np = PTR (num);
+	  MPN_COPY (rp, np, nl);
+	}
+      return;
+    }
+
+  rp = MPZ_REALLOC (rem, dl);
+
+  TMP_MARK;
+  qp = TMP_ALLOC_LIMBS (ql);
+  np = PTR (num);
+  dp = PTR (den);
+
+  /* FIXME: We should think about how to handle the temporary allocation.
+     Perhaps mpn_tdiv_qr should handle it, since it anyway often needs to
+     allocate temp space.  */
+
+  /* Copy denominator to temporary space if it overlaps with the remainder.  */
+  if (dp == rp)
+    {
+      mp_ptr tp;
+      tp = TMP_ALLOC_LIMBS (dl);
+      MPN_COPY (tp, dp, dl);
+      dp = tp;
+    }
+  /* Copy numerator to temporary space if it overlaps with the remainder.  */
+  if (np == rp)
+    {
+      mp_ptr tp;
+      tp = TMP_ALLOC_LIMBS (nl);
+      MPN_COPY (tp, np, nl);
+      np = tp;
+    }
+
+  mpn_tdiv_qr (qp, rp, 0L, np, nl, dp, dl);
+
+  MPN_NORMALIZE (rp, dl);
+
+  SIZ (rem) = ns >= 0 ? dl : -dl;
+  TMP_FREE;
+}
diff --git a/third_party/gmp/mpz/tdiv_r_2exp.c b/third_party/gmp/mpz/tdiv_r_2exp.c
new file mode 100644
index 0000000..96a81f7
--- /dev/null
+++ b/third_party/gmp/mpz/tdiv_r_2exp.c
@@ -0,0 +1,76 @@
+/* mpz_tdiv_r_2exp -- Divide an integer by 2**CNT and produce a remainder.
+
+Copyright 1991, 1993-1995, 2001, 2002, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_tdiv_r_2exp (mpz_ptr res, mpz_srcptr in, mp_bitcnt_t cnt)
+{
+  mp_size_t in_size = ABSIZ (in);
+  mp_size_t res_size;
+  mp_size_t limb_cnt = cnt / GMP_NUMB_BITS;
+  mp_srcptr in_ptr = PTR (in);
+
+  if (in_size > limb_cnt)
+    {
+      /* The input operand is (probably) greater than 2**CNT.  */
+      mp_limb_t x;
+
+      x = in_ptr[limb_cnt] & (((mp_limb_t) 1 << cnt % GMP_NUMB_BITS) - 1);
+      if (x != 0)
+	{
+	  res_size = limb_cnt + 1;
+	  MPZ_REALLOC (res, res_size);
+
+	  PTR (res)[limb_cnt] = x;
+	}
+      else
+	{
+	  MPN_NORMALIZE (in_ptr, limb_cnt);
+
+	  MPZ_REALLOC (res, limb_cnt);
+
+	  res_size = limb_cnt;
+	}
+    }
+  else
+    {
+      /* The input operand is smaller than 2**CNT.  We perform a no-op,
+	 apart from that we might need to copy IN to RES.  */
+      limb_cnt = in_size;
+      MPZ_REALLOC (res, limb_cnt);
+
+      res_size = limb_cnt;
+    }
+
+  if (res != in)
+    MPN_COPY (PTR (res), PTR (in), limb_cnt);
+  SIZ (res) = SIZ (in) >= 0 ? res_size : -res_size;
+}
diff --git a/third_party/gmp/mpz/tdiv_r_ui.c b/third_party/gmp/mpz/tdiv_r_ui.c
new file mode 100644
index 0000000..f3da8ef
--- /dev/null
+++ b/third_party/gmp/mpz/tdiv_r_ui.c
@@ -0,0 +1,96 @@
+/* mpz_tdiv_r_ui(rem, dividend, divisor_limb)
+   -- Set REM to DIVDEND mod DIVISOR_LIMB.
+
+Copyright 1991, 1993, 1994, 1996, 1998, 2001, 2002, 2004, 2005, 2012,
+2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+unsigned long int
+mpz_tdiv_r_ui (mpz_ptr rem, mpz_srcptr dividend, unsigned long int divisor)
+{
+  mp_size_t ns, nn;
+  mp_ptr np;
+  mp_limb_t rl;
+
+  if (UNLIKELY (divisor == 0))
+    DIVIDE_BY_ZERO;
+
+  ns = SIZ(dividend);
+  if (ns == 0)
+    {
+      SIZ(rem) = 0;
+      return 0;
+    }
+
+  nn = ABS(ns);
+  np = PTR(dividend);
+#if BITS_PER_ULONG > GMP_NUMB_BITS  /* avoid warnings about shift amount */
+  if (divisor > GMP_NUMB_MAX)
+    {
+      mp_limb_t dp[2];
+      mp_ptr rp, qp;
+      mp_size_t rn;
+      TMP_DECL;
+
+      if (nn == 1)		/* tdiv_qr requirements; tested above for 0 */
+	{
+	  rl = np[0];
+	  SIZ(rem) = ns >= 0 ? 1 : -1;
+	  MPZ_NEWALLOC (rem, 1)[0] = rl;
+	  return rl;
+	}
+
+      rp = MPZ_NEWALLOC (rem, 2);
+
+      TMP_MARK;
+      dp[0] = divisor & GMP_NUMB_MASK;
+      dp[1] = divisor >> GMP_NUMB_BITS;
+      qp = TMP_ALLOC_LIMBS (nn - 2 + 1);
+      mpn_tdiv_qr (qp, rp, (mp_size_t) 0, np, nn, dp, (mp_size_t) 2);
+      TMP_FREE;
+      rl = rp[0] + (rp[1] << GMP_NUMB_BITS);
+      rn = 2 - (rp[1] == 0);  rn -= (rp[rn - 1] == 0);
+      SIZ(rem) = ns >= 0 ? rn : -rn;
+    }
+  else
+#endif
+    {
+      rl = mpn_mod_1 (np, nn, (mp_limb_t) divisor);
+      if (rl == 0)
+	SIZ(rem) = 0;
+      else
+	{
+	  SIZ(rem) = ns >= 0 ? 1 : -1;
+	  MPZ_NEWALLOC (rem, 1)[0] = rl;
+	}
+    }
+
+  return rl;
+}
diff --git a/third_party/gmp/mpz/tdiv_ui.c b/third_party/gmp/mpz/tdiv_ui.c
new file mode 100644
index 0000000..4618599
--- /dev/null
+++ b/third_party/gmp/mpz/tdiv_ui.c
@@ -0,0 +1,84 @@
+/* mpz_tdiv_ui(dividend, divisor_limb) -- Return DIVDEND mod DIVISOR_LIMB.
+
+Copyright 1991, 1993, 1994, 1996-1998, 2001, 2002, 2004, 2005, 2012 Free
+Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+unsigned long int
+mpz_tdiv_ui (mpz_srcptr dividend, unsigned long int divisor)
+{
+  mp_size_t ns, nn;
+  mp_ptr np;
+  mp_limb_t rl;
+
+  if (UNLIKELY (divisor == 0))
+    DIVIDE_BY_ZERO;
+
+  ns = SIZ(dividend);
+  if (ns == 0)
+    {
+      return 0;
+    }
+
+  nn = ABS(ns);
+  np = PTR(dividend);
+
+#if BITS_PER_ULONG > GMP_NUMB_BITS  /* avoid warnings about shift amount */
+  if (divisor > GMP_NUMB_MAX)
+    {
+      mp_limb_t dp[2], rp[2];
+      mp_ptr qp;
+      mp_size_t rn;
+      TMP_DECL;
+
+      if (nn == 1)		/* tdiv_qr requirements; tested above for 0 */
+	{
+	  rl = np[0];
+	  return rl;
+	}
+
+      TMP_MARK;
+      dp[0] = divisor & GMP_NUMB_MASK;
+      dp[1] = divisor >> GMP_NUMB_BITS;
+      qp = TMP_ALLOC_LIMBS (nn - 2 + 1);
+      mpn_tdiv_qr (qp, rp, (mp_size_t) 0, np, nn, dp, (mp_size_t) 2);
+      TMP_FREE;
+      rl = rp[0] + (rp[1] << GMP_NUMB_BITS);
+      rn = 2 - (rp[1] == 0);  rn -= (rp[rn - 1] == 0);
+    }
+  else
+#endif
+    {
+      rl = mpn_mod_1 (np, nn, (mp_limb_t) divisor);
+    }
+
+  return rl;
+}
diff --git a/third_party/gmp/mpz/tstbit.c b/third_party/gmp/mpz/tstbit.c
new file mode 100644
index 0000000..48725d4
--- /dev/null
+++ b/third_party/gmp/mpz/tstbit.c
@@ -0,0 +1,80 @@
+/* mpz_tstbit -- test a specified bit.
+
+Copyright 2000, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* For negatives the effective twos complement is achieved by negating the
+   limb tested, either with a ones or twos complement.  Twos complement
+   ("-") is used if there's only zero limbs below the one being tested.
+   Ones complement ("~") is used if there's a non-zero below.  Note that "-"
+   is correct even if the limb examined is 0 (and the true beginning of twos
+   complement is further up).
+
+   Testing the limbs below p is unavoidable on negatives, but will usually
+   need to examine only *(p-1).  The search is done from *(p-1) down to
+   *u_ptr, since that might give better cache locality, and because a
+   non-zero limb is perhaps a touch more likely in the middle of a number
+   than at the low end.
+
+   Bits past the end of available data simply follow sign of u.  Notice that
+   the limb_index >= abs_size test covers u=0 too.  */
+
+int
+mpz_tstbit (mpz_srcptr u, mp_bitcnt_t bit_index) __GMP_NOTHROW
+{
+  mp_srcptr      u_ptr      = PTR(u);
+  mp_size_t      size       = SIZ(u);
+  unsigned       abs_size   = ABS(size);
+  mp_size_t      limb_index = bit_index / GMP_NUMB_BITS;
+  mp_srcptr      p          = u_ptr + limb_index;
+  mp_limb_t      limb;
+
+  if (limb_index >= abs_size)
+    return (size < 0);
+
+  limb = *p;
+  if (size < 0)
+    {
+      limb = -limb;     /* twos complement */
+
+      while (p != u_ptr)
+	{
+	  p--;
+	  if (*p != 0)
+	    {
+	      limb--;	/* make it a ones complement instead */
+	      break;
+	    }
+	}
+    }
+
+  return (limb >> (bit_index % GMP_NUMB_BITS)) & 1;
+}
diff --git a/third_party/gmp/mpz/ui_pow_ui.c b/third_party/gmp/mpz/ui_pow_ui.c
new file mode 100644
index 0000000..87f2d3a
--- /dev/null
+++ b/third_party/gmp/mpz/ui_pow_ui.c
@@ -0,0 +1,58 @@
+/* mpz_ui_pow_ui -- ulong raised to ulong.
+
+Copyright 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+void
+mpz_ui_pow_ui (mpz_ptr r, unsigned long b, unsigned long e)
+{
+#if GMP_NAIL_BITS != 0
+  if (b > GMP_NUMB_MAX)
+    {
+      mp_limb_t bb[2];
+      bb[0] = b & GMP_NUMB_MASK;
+      bb[1] = b >> GMP_NUMB_BITS;
+      mpz_n_pow_ui (r, bb, (mp_size_t) 2, e);
+    }
+  else
+#endif
+    {
+#ifdef _LONG_LONG_LIMB
+      /* i386 gcc 2.95.3 doesn't recognise blimb can be eliminated when
+	 mp_limb_t is an unsigned long, so only use a separate blimb when
+	 necessary.  */
+      mp_limb_t  blimb = b;
+      mpz_n_pow_ui (r, &blimb, (mp_size_t) (b != 0), e);
+#else
+      mpz_n_pow_ui (r, &b,     (mp_size_t) (b != 0), e);
+#endif
+    }
+}
diff --git a/third_party/gmp/mpz/ui_sub.c b/third_party/gmp/mpz/ui_sub.c
new file mode 100644
index 0000000..1d0edb9
--- /dev/null
+++ b/third_party/gmp/mpz/ui_sub.c
@@ -0,0 +1,90 @@
+/* mpz_ui_sub -- Subtract an unsigned one-word integer and an mpz_t.
+
+Copyright 2002, 2004, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_ui_sub (mpz_ptr w, unsigned long int uval, mpz_srcptr v)
+{
+  mp_ptr vp, wp;
+  mp_size_t vn, wn;
+  mp_limb_t cy;
+
+#if BITS_PER_ULONG > GMP_NUMB_BITS  /* avoid warnings about shift amount */
+  if (uval > GMP_NUMB_MAX)
+    {
+      mpz_t u;
+      mp_limb_t ul[2];
+      PTR(u) = ul;
+      ul[0] = uval & GMP_NUMB_MASK;
+      ul[1] = uval >> GMP_NUMB_BITS;
+      SIZ(u) = 2;
+      mpz_sub (w, u, v);
+      return;
+    }
+#endif
+
+  vn = SIZ(v);
+
+  if (vn > 1)
+    {
+      wp = MPZ_REALLOC (w, vn);
+      vp = PTR(v);
+      mpn_sub_1 (wp, vp, vn, (mp_limb_t) uval);
+      wn = -(vn - (wp[vn - 1] == 0));
+    }
+  else if (vn >= 0)
+    {
+      mp_limb_t vp0;
+      vp0 = PTR (v)[0] & - (mp_limb_t) vn;
+      wp = MPZ_NEWALLOC (w, 1);
+      if (uval >= vp0)
+	{
+	  wp[0] = uval - vp0;
+	  wn = wp[0] != 0;
+	}
+      else
+	{
+	  wp[0] = vp0 - uval;
+	  wn = -1;
+	}
+    }
+  else /* (vn < 0) */
+    {
+      vn = -vn;
+      wp = MPZ_REALLOC (w, vn + 1);
+      vp = PTR(v);
+      cy = mpn_add_1 (wp, vp, vn, (mp_limb_t) uval);
+      wp[vn] = cy;
+      wn = vn + (cy != 0);
+    }
+
+  SIZ(w) = wn;
+}
diff --git a/third_party/gmp/mpz/urandomb.c b/third_party/gmp/mpz/urandomb.c
new file mode 100644
index 0000000..fcaea21
--- /dev/null
+++ b/third_party/gmp/mpz/urandomb.c
@@ -0,0 +1,47 @@
+/* mpz_urandomb (rop, state, n) -- Generate a uniform pseudorandom
+   integer in the range 0 to 2^N - 1, inclusive, using STATE as the
+   random state previously initialized by a call to gmp_randinit().
+
+Copyright 1999, 2000, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_urandomb (mpz_ptr rop, gmp_randstate_t rstate, mp_bitcnt_t nbits)
+{
+  mp_ptr rp;
+  mp_size_t size;
+
+  size = BITS_TO_LIMBS (nbits);
+  rp = MPZ_NEWALLOC (rop, size);
+
+  _gmp_rand (rp, rstate, nbits);
+  MPN_NORMALIZE (rp, size);
+  SIZ (rop) = size;
+}
diff --git a/third_party/gmp/mpz/urandomm.c b/third_party/gmp/mpz/urandomm.c
new file mode 100644
index 0000000..df73935
--- /dev/null
+++ b/third_party/gmp/mpz/urandomm.c
@@ -0,0 +1,98 @@
+/* mpz_urandomm (rop, state, n) -- Generate a uniform pseudorandom
+   integer in the range 0 to N-1, using STATE as the random state
+   previously initialized by a call to gmp_randinit().
+
+Copyright 2000, 2002, 2012, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h" /* for count_leading_zeros */
+
+
+#define MAX_URANDOMM_ITER  80
+
+void
+mpz_urandomm (mpz_ptr rop, gmp_randstate_t rstate, mpz_srcptr n)
+{
+  mp_ptr rp, np;
+  mp_size_t nbits, size;
+  mp_limb_t nh;
+  int count;
+  int pow2;
+  int cmp;
+  TMP_DECL;
+
+  size = ABSIZ (n);
+  if (UNLIKELY (size == 0))
+    DIVIDE_BY_ZERO;
+
+  np = PTR (n);
+  nh = np[size - 1];
+
+  /* Detect whether n is a power of 2.  */
+  pow2 = POW2_P (nh) && (size == 1 || mpn_zero_p (np, size - 1));
+
+  count_leading_zeros (count, nh);
+  nbits = size * GMP_NUMB_BITS - (count - GMP_NAIL_BITS) - pow2;
+  if (nbits == 0)		/* nbits == 0 means that n was == 1.  */
+    {
+      SIZ (rop) = 0;
+      return;
+    }
+
+  TMP_MARK;
+  if (rop == n)
+    {
+      mp_ptr tp;
+      tp = TMP_ALLOC_LIMBS (size);
+      MPN_COPY (tp, np, size);
+      np = tp;
+    }
+
+  /* Here the allocated size can be one too much if n is a power of
+     (2^GMP_NUMB_BITS) but it's convenient for using mpn_cmp below.  */
+  rp = MPZ_NEWALLOC (rop, size);
+  /* Clear last limb to prevent the case in which size is one too much.  */
+  rp[size - 1] = 0;
+
+  count = MAX_URANDOMM_ITER;	/* Set iteration count limit.  */
+  do
+    {
+      _gmp_rand (rp, rstate, nbits);
+      MPN_CMP (cmp, rp, np, size);
+    }
+  while (cmp >= 0 && --count != 0);
+
+  if (count == 0)
+    /* Too many iterations; return result mod n == result - n */
+    mpn_sub_n (rp, rp, np, size);
+
+  MPN_NORMALIZE (rp, size);
+  SIZ (rop) = size;
+  TMP_FREE;
+}
diff --git a/third_party/gmp/mpz/xor.c b/third_party/gmp/mpz/xor.c
new file mode 100644
index 0000000..5ec657a
--- /dev/null
+++ b/third_party/gmp/mpz/xor.c
@@ -0,0 +1,146 @@
+/* mpz_xor -- Logical xor.
+
+Copyright 1991, 1993, 1994, 1996, 1997, 2000, 2001, 2005, 2012,
+2015-2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+mpz_xor (mpz_ptr res, mpz_srcptr op1, mpz_srcptr op2)
+{
+  mp_srcptr op1_ptr, op2_ptr;
+  mp_size_t op1_size, op2_size;
+  mp_ptr res_ptr;
+  mp_size_t res_size;
+
+  op1_size = SIZ(op1);
+  op2_size = SIZ(op2);
+
+  if (op1_size < op2_size)
+    {
+      MPZ_SRCPTR_SWAP (op1, op2);
+      MP_SIZE_T_SWAP (op1_size, op2_size);
+    }
+
+  op1_ptr = PTR(op1);
+  res_ptr = PTR(res);
+
+  if (op2_size >= 0)
+    {
+      if (res_ptr != op1_ptr)
+	{
+	  res_ptr = MPZ_REALLOC (res, op1_size);
+	  MPN_COPY (res_ptr + op2_size, op1_ptr + op2_size,
+		    op1_size - op2_size);
+	}
+      if (LIKELY (op2_size != 0))
+	mpn_xor_n (res_ptr, op1_ptr, PTR(op2), op2_size);
+      res_size = op1_size;
+
+      MPN_NORMALIZE (res_ptr, res_size);
+      SIZ(res) = res_size;
+    }
+  else
+    {
+      mp_ptr opx;
+      TMP_DECL;
+
+      op2_size = -op2_size;
+      TMP_MARK;
+      if (op1_size < 0)
+	{
+	  mp_ptr opy;
+
+	  /* Both operands are negative, the result will be positive.
+	      (-OP1) ^ (-OP2) =
+	     = ~(OP1 - 1) ^ ~(OP2 - 1) =
+	     = (OP1 - 1) ^ (OP2 - 1)  */
+
+	  op1_size = -op1_size;
+
+	  /* Possible optimization: Decrease mpn_sub precision,
+	     as we won't use the entire res of both.  */
+	  TMP_ALLOC_LIMBS_2 (opx, op1_size, opy, op2_size);
+	  mpn_sub_1 (opx, op1_ptr, op1_size, (mp_limb_t) 1);
+	  op1_ptr = opx;
+
+	  mpn_sub_1 (opy, PTR(op2), op2_size, (mp_limb_t) 1);
+	  op2_ptr = opy;
+
+	  res_ptr = MPZ_NEWALLOC (res, op2_size);
+	  /* Don't re-read OP1_PTR and OP2_PTR.  They point to temporary
+	     space--never to the space PTR(res) used to point to before
+	     reallocation.  */
+
+	  MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size,
+		    op2_size - op1_size);
+	  mpn_xor_n (res_ptr, op1_ptr, op2_ptr, op1_size);
+	  TMP_FREE;
+	  res_size = op2_size;
+
+	  MPN_NORMALIZE (res_ptr, res_size);
+	  SIZ(res) = res_size;
+	}
+      else
+	{
+	  /* Operand 2 negative, so will be the result.
+	     -(OP1 ^ (-OP2)) = -(OP1 ^ ~(OP2 - 1)) =
+	     = ~(OP1 ^ ~(OP2 - 1)) + 1 =
+	     = (OP1 ^ (OP2 - 1)) + 1      */
+
+	  res_size = MAX (op1_size, op2_size);
+	  res_ptr = MPZ_REALLOC (res, res_size + 1);
+	  op1_ptr = PTR(op1);
+
+	  opx = TMP_ALLOC_LIMBS (op2_size);
+	  mpn_sub_1 (opx, PTR(op2), op2_size, (mp_limb_t) 1);
+	  op2_ptr = opx;
+
+	  if (res_size == op1_size)
+	    {
+	      MPN_COPY (res_ptr + op2_size, op1_ptr + op2_size, op1_size - op2_size);
+	      mpn_xor_n (res_ptr, op1_ptr, op2_ptr, op2_size);
+	    }
+	  else
+	    {
+	      MPN_COPY (res_ptr + op1_size, op2_ptr + op1_size, op2_size - op1_size);
+	      if (LIKELY (op1_size != 0))
+		mpn_xor_n (res_ptr, op1_ptr, op2_ptr, op1_size);
+	    }
+	  TMP_FREE;
+
+	  res_ptr[res_size] = 0;
+	  MPN_INCR_U (res_ptr, res_size + 1, (mp_limb_t) 1);
+	  res_size += res_ptr[res_size];
+
+	  MPN_NORMALIZE_NOT_ZERO (res_ptr, res_size);
+	  SIZ(res) = -res_size;
+	}
+    }
+}
diff --git a/third_party/gmp/nextprime.c b/third_party/gmp/nextprime.c
new file mode 100644
index 0000000..e8e60dd
--- /dev/null
+++ b/third_party/gmp/nextprime.c
@@ -0,0 +1,166 @@
+/* gmp_nextprime -- generate small primes reasonably efficiently for internal
+   GMP needs.
+
+   Contributed to the GNU project by Torbjorn Granlund.  Miscellaneous
+   improvements by Martin Boij.
+
+   THE FUNCTIONS IN THIS FILE ARE INTERNAL WITH MUTABLE INTERFACES.  IT IS ONLY
+   SAFE TO REACH THEM THROUGH DOCUMENTED INTERFACES.  IN FACT, IT IS ALMOST
+   GUARANTEED THAT THEY WILL CHANGE OR DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+/*
+  Optimisation ideas:
+
+  1. Unroll the sieving loops.  Should reach 1 write/cycle.  That would be a 2x
+     improvement.
+
+  2. Separate sieving with primes p < SIEVESIZE and p >= SIEVESIZE.  The latter
+     will need at most one write, and thus not need any inner loop.
+
+  3. For primes p >= SIEVESIZE, i.e., typically the majority of primes, we
+     perform more than one division per sieving write.  That might dominate the
+     entire run time for the nextprime function.  A incrementally initialised
+     remainder table of Pi(65536) = 6542 16-bit entries could replace that
+     division.
+*/
+
+#include "gmp-impl.h"
+#include <string.h>		/* for memset */
+
+
+unsigned long int
+gmp_nextprime (gmp_primesieve_t *ps)
+{
+  unsigned long p, d, pi;
+  unsigned char *sp;
+  static unsigned char addtab[] =
+    { 2,4,2,4,6,2,6,4,2,4,6,6,2,6,4,2,6,4,6,8,4,2,4,2,4,8,6,4,6,2,4,6,2,6,6,4,
+      2,4,6,2,6,4,2,4,2,10,2,10 };
+  unsigned char *addp = addtab;
+  unsigned long ai;
+
+  /* Look for already sieved primes.  A sentinel at the end of the sieving
+     area allows us to use a very simple loop here.  */
+  d = ps->d;
+  sp = ps->s + d;
+  while (*sp != 0)
+    sp++;
+  if (sp != ps->s + SIEVESIZE)
+    {
+      d = sp - ps->s;
+      ps->d = d + 1;
+      return ps->s0 + 2 * d;
+    }
+
+  /* Handle the number 2 separately.  */
+  if (ps->s0 < 3)
+    {
+      ps->s0 = 3 - 2 * SIEVESIZE; /* Tricky */
+      return 2;
+    }
+
+  /* Exhausted computed primes.  Resieve, then call ourselves recursively.  */
+
+#if 0
+  for (sp = ps->s; sp < ps->s + SIEVESIZE; sp++)
+    *sp = 0;
+#else
+  memset (ps->s, 0, SIEVESIZE);
+#endif
+
+  ps->s0 += 2 * SIEVESIZE;
+
+  /* Update sqrt_s0 as needed.  */
+  while ((ps->sqrt_s0 + 1) * (ps->sqrt_s0 + 1) <= ps->s0 + 2 * SIEVESIZE - 1)
+    ps->sqrt_s0++;
+
+  pi = ((ps->s0 + 3) / 2) % 3;
+  if (pi > 0)
+    pi = 3 - pi;
+  if (ps->s0 + 2 * pi <= 3)
+    pi += 3;
+  sp = ps->s + pi;
+  while (sp < ps->s + SIEVESIZE)
+    {
+      *sp = 1, sp += 3;
+    }
+
+  pi = ((ps->s0 + 5) / 2) % 5;
+  if (pi > 0)
+    pi = 5 - pi;
+  if (ps->s0 + 2 * pi <= 5)
+    pi += 5;
+  sp = ps->s + pi;
+  while (sp < ps->s + SIEVESIZE)
+    {
+      *sp = 1, sp += 5;
+    }
+
+  pi = ((ps->s0 + 7) / 2) % 7;
+  if (pi > 0)
+    pi = 7 - pi;
+  if (ps->s0 + 2 * pi <= 7)
+    pi += 7;
+  sp = ps->s + pi;
+  while (sp < ps->s + SIEVESIZE)
+    {
+      *sp = 1, sp += 7;
+    }
+
+  p = 11;
+  ai = 0;
+  while (p <= ps->sqrt_s0)
+    {
+      pi = ((ps->s0 + p) / 2) % p;
+      if (pi > 0)
+	pi = p - pi;
+      if (ps->s0 + 2 * pi <= p)
+	  pi += p;
+      sp = ps->s + pi;
+      while (sp < ps->s + SIEVESIZE)
+	{
+	  *sp = 1, sp += p;
+	}
+      p += addp[ai];
+      ai = (ai + 1) % 48;
+    }
+  ps->d = 0;
+  return gmp_nextprime (ps);
+}
+
+void
+gmp_init_primesieve (gmp_primesieve_t *ps)
+{
+  ps->s0 = 0;
+  ps->sqrt_s0 = 0;
+  ps->d = SIEVESIZE;
+  ps->s[SIEVESIZE] = 0;		/* sentinel */
+}
diff --git a/third_party/gmp/primesieve.c b/third_party/gmp/primesieve.c
new file mode 100644
index 0000000..f6cdf36
--- /dev/null
+++ b/third_party/gmp/primesieve.c
@@ -0,0 +1,436 @@
+/* primesieve (BIT_ARRAY, N) -- Fills the BIT_ARRAY with a mask for primes up to N.
+
+Contributed to the GNU project by Marco Bodrato.
+
+THE FUNCTION IN THIS FILE IS INTERNAL WITH A MUTABLE INTERFACE.
+IT IS ONLY SAFE TO REACH IT THROUGH DOCUMENTED INTERFACES.
+IN FACT, IT IS ALMOST GUARANTEED THAT IT WILL CHANGE OR
+DISAPPEAR IN A FUTURE GNU MP RELEASE.
+
+Copyright 2010-2012, 2015, 2016 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#if 0
+static mp_limb_t
+bit_to_n (mp_limb_t bit) { return (bit*3+4)|1; }
+#endif
+
+/* id_to_n (x) = bit_to_n (x-1) = (id*3+1)|1*/
+static mp_limb_t
+id_to_n  (mp_limb_t id)  { return id*3+1+(id&1); }
+
+/* n_to_bit (n) = ((n-1)&(-CNST_LIMB(2)))/3U-1 */
+static mp_limb_t
+n_to_bit (mp_limb_t n) { return ((n-5)|1)/3U; }
+
+#if 0
+static mp_size_t
+primesieve_size (mp_limb_t n) { return n_to_bit(n) / GMP_LIMB_BITS + 1; }
+#endif
+
+#if GMP_LIMB_BITS > 61
+#define SIEVE_SEED CNST_LIMB(0x3294C9E069128480)
+#if GMP_LIMB_BITS == 64
+/* 110bits pre-sieved mask for primes 5, 11*/
+#define SIEVE_MASK1 CNST_LIMB(0x81214a1204892058)
+#define SIEVE_MASKT CNST_LIMB(0xc8130681244)
+/* 182bits pre-sieved mask for primes 7, 13*/
+#define SIEVE_2MSK1 CNST_LIMB(0x9402180c40230184)
+#define SIEVE_2MSK2 CNST_LIMB(0x0285021088402120)
+#define SIEVE_2MSKT CNST_LIMB(0xa41210084421)
+#define SEED_LIMIT 210
+#else
+#define SEED_LIMIT 202
+#endif
+#else
+#if GMP_LIMB_BITS > 30
+#define SIEVE_SEED CNST_LIMB(0x69128480)
+#if GMP_LIMB_BITS == 32
+/* 70bits pre-sieved mask for primes 5, 7*/
+#define SIEVE_MASK1 CNST_LIMB(0x12148960)
+#define SIEVE_MASK2 CNST_LIMB(0x44a120cc)
+#define SIEVE_MASKT CNST_LIMB(0x1a)
+#define SEED_LIMIT 120
+#else
+#define SEED_LIMIT 114
+#endif
+#else
+#if GMP_LIMB_BITS > 15
+#define SIEVE_SEED CNST_LIMB(0x8480)
+#define SEED_LIMIT 54
+#else
+#if GMP_LIMB_BITS > 7
+#define SIEVE_SEED CNST_LIMB(0x80)
+#define SEED_LIMIT 34
+#else
+#define SIEVE_SEED CNST_LIMB(0x0)
+#define SEED_LIMIT 24
+#endif /* 7 */
+#endif /* 15 */
+#endif /* 30 */
+#endif /* 61 */
+
+#define SET_OFF1(m1, m2, M1, M2, off, BITS)		\
+  if (off) {						\
+    if (off < GMP_LIMB_BITS) {				\
+      m1 = (M1 >> off) | (M2 << (GMP_LIMB_BITS - off));	\
+      if (off <= BITS - GMP_LIMB_BITS) {		\
+	m2 = M1 << (BITS - GMP_LIMB_BITS - off)		\
+	  | M2 >> off;					\
+      } else {						\
+	m1 |= M1 << (BITS - off);			\
+	m2 = M1 >> (off + GMP_LIMB_BITS - BITS);	\
+      }							\
+    } else {						\
+      m1 = M1 << (BITS - off)				\
+	| M2 >> (off - GMP_LIMB_BITS);			\
+      m2 = M2 << (BITS - off)				\
+	| M1 >> (off + GMP_LIMB_BITS - BITS);		\
+    }							\
+  } else {						\
+    m1 = M1; m2 = M2;					\
+  }
+
+#define SET_OFF2(m1, m2, m3, M1, M2, M3, off, BITS)	\
+  if (off) {						\
+    if (off <= GMP_LIMB_BITS) {				\
+      m1 = M2 << (GMP_LIMB_BITS - off);			\
+      m2 = M3 << (GMP_LIMB_BITS - off);			\
+      if (off != GMP_LIMB_BITS) {			\
+	m1 |= (M1 >> off);				\
+	m2 |= (M2 >> off);				\
+      }							\
+      if (off <= BITS - 2 * GMP_LIMB_BITS) {		\
+	m3 = M1 << (BITS - 2 * GMP_LIMB_BITS - off)	\
+	  | M3 >> off;					\
+      } else {						\
+	m2 |= M1 << (BITS - GMP_LIMB_BITS - off);	\
+	m3 = M1 >> (off + 2 * GMP_LIMB_BITS - BITS);	\
+      }							\
+    } else if (off < 2 *GMP_LIMB_BITS) {		\
+      m1 = M2 >> (off - GMP_LIMB_BITS)			\
+	| M3 << (2 * GMP_LIMB_BITS - off);		\
+      if (off <= BITS - GMP_LIMB_BITS) {		\
+	m2 = M3 >> (off - GMP_LIMB_BITS)		\
+	  | M1 << (BITS - GMP_LIMB_BITS - off);		\
+	m3 = M2 << (BITS - GMP_LIMB_BITS - off);	\
+	if (off != BITS - GMP_LIMB_BITS) {		\
+	  m3 |= M1 >> (off + 2 * GMP_LIMB_BITS - BITS);	\
+	}						\
+      } else {						\
+	m1 |= M1 << (BITS - off);			\
+	m2 = M2 << (BITS - off)				\
+	  | M1 >> (GMP_LIMB_BITS - BITS + off);		\
+	m3 = M2 >> (GMP_LIMB_BITS - BITS + off);	\
+      }							\
+    } else {						\
+      m1 = M1 << (BITS - off)				\
+	| M3 >> (off - 2 * GMP_LIMB_BITS);		\
+      m2 = M2 << (BITS - off)				\
+	| M1 >> (off + GMP_LIMB_BITS - BITS);		\
+      m3 = M3 << (BITS - off)				\
+	| M2 >> (off + GMP_LIMB_BITS - BITS);		\
+    }							\
+  } else {						\
+    m1 = M1; m2 = M2; m3 = M3;				\
+  }
+
+#define ROTATE1(m1, m2, BITS)			\
+  do {						\
+    mp_limb_t __tmp;				\
+    __tmp = m1 >> (2 * GMP_LIMB_BITS - BITS);	\
+    m1 = (m1 << (BITS - GMP_LIMB_BITS)) | m2;	\
+    m2 = __tmp;					\
+  } while (0)
+
+#define ROTATE2(m1, m2, m3, BITS)		\
+  do {						\
+    mp_limb_t __tmp;				\
+    __tmp = m2 >> (3 * GMP_LIMB_BITS - BITS);	\
+    m2 = m2 << (BITS - GMP_LIMB_BITS * 2)	\
+      | m1 >> (3 * GMP_LIMB_BITS - BITS);	\
+    m1 = m1 << (BITS - GMP_LIMB_BITS * 2) | m3;	\
+    m3 = __tmp;					\
+  } while (0)
+
+static mp_limb_t
+fill_bitpattern (mp_ptr bit_array, mp_size_t limbs, mp_limb_t offset)
+{
+#ifdef SIEVE_2MSK2
+  mp_limb_t m11, m12, m21, m22, m23;
+
+  if (offset == 0) { /* This branch is not needed. */
+    m11 = SIEVE_MASK1;
+    m12 = SIEVE_MASKT;
+    m21 = SIEVE_2MSK1;
+    m22 = SIEVE_2MSK2;
+    m23 = SIEVE_2MSKT;
+  } else { /* correctly handle offset == 0... */
+    m21 = offset % 110;
+    SET_OFF1 (m11, m12, SIEVE_MASK1, SIEVE_MASKT, m21, 110);
+    offset %= 182;
+    SET_OFF2 (m21, m22, m23, SIEVE_2MSK1, SIEVE_2MSK2, SIEVE_2MSKT, offset, 182);
+  }
+  /* THINK: Consider handling odd values of 'limbs' outside the loop,
+     to have a single exit condition. */
+  do {
+    bit_array[0] = m11 | m21;
+    if (--limbs == 0)
+      break;
+    ROTATE1 (m11, m12, 110);
+    bit_array[1] = m11 | m22;
+    bit_array += 2;
+    ROTATE1 (m11, m12, 110);
+    ROTATE2 (m21, m22, m23, 182);
+  } while (--limbs != 0);
+  return 4;
+#else
+#ifdef SIEVE_MASK2
+  mp_limb_t mask, mask2, tail;
+
+  if (offset == 0) { /* This branch is not needed. */
+    mask = SIEVE_MASK1;
+    mask2 = SIEVE_MASK2;
+    tail = SIEVE_MASKT;
+  } else { /* correctly handle offset == 0... */
+    offset %= 70;
+    SET_OFF2 (mask, mask2, tail, SIEVE_MASK1, SIEVE_MASK2, SIEVE_MASKT, offset, 70);
+  }
+  /* THINK: Consider handling odd values of 'limbs' outside the loop,
+     to have a single exit condition. */
+  do {
+    bit_array[0] = mask;
+    if (--limbs == 0)
+      break;
+    bit_array[1] = mask2;
+    bit_array += 2;
+    ROTATE2 (mask, mask2, tail, 70);
+  } while (--limbs != 0);
+  return 2;
+#else
+  MPN_FILL (bit_array, limbs, CNST_LIMB(0));
+  return 0;
+#endif
+#endif
+}
+
+static void
+first_block_primesieve (mp_ptr bit_array, mp_limb_t n)
+{
+  mp_size_t bits, limbs;
+  mp_limb_t i;
+
+  ASSERT (n > 4);
+
+  bits  = n_to_bit(n);
+  limbs = bits / GMP_LIMB_BITS;
+
+  if (limbs != 0)
+    i = fill_bitpattern (bit_array + 1, limbs, 0);
+  bit_array[0] = SIEVE_SEED;
+
+  if ((bits + 1) % GMP_LIMB_BITS != 0)
+    bit_array[limbs] |= MP_LIMB_T_MAX << ((bits + 1) % GMP_LIMB_BITS);
+
+  if (n > SEED_LIMIT) {
+    mp_limb_t mask, index;
+
+    ASSERT (i < GMP_LIMB_BITS);
+
+    if (n_to_bit (SEED_LIMIT + 1) < GMP_LIMB_BITS)
+      i = 0;
+    mask = CNST_LIMB(1) << i;
+    index = 0;
+    do {
+      ++i;
+      if ((bit_array[index] & mask) == 0)
+	{
+	  mp_size_t step, lindex;
+	  mp_limb_t lmask;
+	  unsigned  maskrot;
+
+	  step = id_to_n(i);
+/*	  lindex = n_to_bit(id_to_n(i)*id_to_n(i)); */
+	  lindex = i*(step+1)-1+(-(i&1)&(i+1));
+/*	  lindex = i*(step+1+(i&1))-1+(i&1); */
+	  if (lindex > bits)
+	    break;
+
+	  step <<= 1;
+	  maskrot = step % GMP_LIMB_BITS;
+
+	  lmask = CNST_LIMB(1) << (lindex % GMP_LIMB_BITS);
+	  do {
+	    bit_array[lindex / GMP_LIMB_BITS] |= lmask;
+	    lmask = lmask << maskrot | lmask >> (GMP_LIMB_BITS - maskrot);
+	    lindex += step;
+	  } while (lindex <= bits);
+
+/*	  lindex = n_to_bit(id_to_n(i)*bit_to_n(i)); */
+	  lindex = i*(i*3+6)+(i&1);
+
+	  lmask = CNST_LIMB(1) << (lindex % GMP_LIMB_BITS);
+	  for ( ; lindex <= bits; lindex += step) {
+	    bit_array[lindex / GMP_LIMB_BITS] |= lmask;
+	    lmask = lmask << maskrot | lmask >> (GMP_LIMB_BITS - maskrot);
+	  };
+	}
+      mask = mask << 1 | mask >> (GMP_LIMB_BITS-1);
+      index += mask & 1;
+    } while (1);
+  }
+}
+
+static void
+block_resieve (mp_ptr bit_array, mp_size_t limbs, mp_limb_t offset,
+	       mp_srcptr sieve)
+{
+  mp_size_t bits, off = offset;
+  mp_limb_t mask, index, i;
+
+  ASSERT (limbs > 0);
+  ASSERT (offset >= GMP_LIMB_BITS);
+
+  bits = limbs * GMP_LIMB_BITS - 1;
+
+  i = fill_bitpattern (bit_array, limbs, offset - GMP_LIMB_BITS);
+
+  ASSERT (i < GMP_LIMB_BITS);
+
+  mask = CNST_LIMB(1) << i;
+  index = 0;
+  do {
+    ++i;
+    if ((sieve[index] & mask) == 0)
+      {
+	mp_size_t step, lindex;
+	mp_limb_t lmask;
+	unsigned  maskrot;
+
+	step = id_to_n(i);
+
+/*	lindex = n_to_bit(id_to_n(i)*id_to_n(i)); */
+	lindex = i*(step+1)-1+(-(i&1)&(i+1));
+/*	lindex = i*(step+1+(i&1))-1+(i&1); */
+	if (lindex > bits + off)
+	  break;
+
+	step <<= 1;
+	maskrot = step % GMP_LIMB_BITS;
+
+	if (lindex < off)
+	  lindex += step * ((off - lindex - 1) / step + 1);
+
+	lindex -= off;
+
+	lmask = CNST_LIMB(1) << (lindex % GMP_LIMB_BITS);
+	for ( ; lindex <= bits; lindex += step) {
+	  bit_array[lindex / GMP_LIMB_BITS] |= lmask;
+	  lmask = lmask << maskrot | lmask >> (GMP_LIMB_BITS - maskrot);
+	};
+
+/*	lindex = n_to_bit(id_to_n(i)*bit_to_n(i)); */
+	lindex = i*(i*3+6)+(i&1);
+
+	if (lindex < off)
+	  lindex += step * ((off - lindex - 1) / step + 1);
+
+	lindex -= off;
+
+	lmask = CNST_LIMB(1) << (lindex % GMP_LIMB_BITS);
+	for ( ; lindex <= bits; lindex += step) {
+	  bit_array[lindex / GMP_LIMB_BITS] |= lmask;
+	  lmask = lmask << maskrot | lmask >> (GMP_LIMB_BITS - maskrot);
+	};
+      }
+      mask = mask << 1 | mask >> (GMP_LIMB_BITS-1);
+      index += mask & 1;
+  } while (1);
+}
+
+#define BLOCK_SIZE 2048
+
+/* Fills bit_array with the characteristic function of composite
+   numbers up to the parameter n. I.e. a bit set to "1" represent a
+   composite, a "0" represent a prime.
+
+   The primesieve_size(n) limbs pointed to by bit_array are
+   overwritten. The returned value counts prime integers in the
+   interval [4, n]. Note that n > 4.
+
+   Even numbers and multiples of 3 are excluded "a priori", only
+   numbers equivalent to +/- 1 mod 6 have their bit in the array.
+
+   Once sieved, if the bit b is ZERO it represent a prime, the
+   represented prime is bit_to_n(b), if the LSbit is bit 0, or
+   id_to_n(b), if you call "1" the first bit.
+ */
+
+mp_limb_t
+gmp_primesieve (mp_ptr bit_array, mp_limb_t n)
+{
+  mp_size_t size;
+  mp_limb_t bits;
+
+  ASSERT (n > 4);
+
+  bits = n_to_bit(n);
+  size = bits / GMP_LIMB_BITS + 1;
+
+  if (size > BLOCK_SIZE * 2) {
+    mp_size_t off;
+    off = BLOCK_SIZE + (size % BLOCK_SIZE);
+    first_block_primesieve (bit_array, id_to_n (off * GMP_LIMB_BITS));
+    do {
+      block_resieve (bit_array + off, BLOCK_SIZE, off * GMP_LIMB_BITS, bit_array);
+    } while ((off += BLOCK_SIZE) < size);
+  } else {
+    first_block_primesieve (bit_array, n);
+  }
+
+  if ((bits + 1) % GMP_LIMB_BITS != 0)
+    bit_array[size-1] |= MP_LIMB_T_MAX << ((bits + 1) % GMP_LIMB_BITS);
+
+  return size * GMP_LIMB_BITS - mpn_popcount (bit_array, size);
+}
+
+#undef BLOCK_SIZE
+#undef SEED_LIMIT
+#undef SIEVE_SEED
+#undef SIEVE_MASK1
+#undef SIEVE_MASK2
+#undef SIEVE_MASKT
+#undef SIEVE_2MSK1
+#undef SIEVE_2MSK2
+#undef SIEVE_2MSKT
+#undef SET_OFF1
+#undef SET_OFF2
+#undef ROTATE1
+#undef ROTATE2
diff --git a/third_party/gmp/printf/Makefile.am b/third_party/gmp/printf/Makefile.am
new file mode 100644
index 0000000..bcbf55d
--- /dev/null
+++ b/third_party/gmp/printf/Makefile.am
@@ -0,0 +1,41 @@
+## Process this file with automake to generate Makefile.in
+
+# Copyright 2001, 2002 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+
+AM_CPPFLAGS = -D__GMP_WITHIN_GMP -I$(top_srcdir)
+
+noinst_LTLIBRARIES = libprintf.la
+
+libprintf_la_SOURCES =							 \
+  asprintf.c asprntffuns.c doprnt.c doprntf.c doprnti.c			 \
+  fprintf.c obprintf.c obvprintf.c obprntffuns.c			 \
+  printf.c printffuns.c snprintf.c snprntffuns.c sprintf.c sprintffuns.c \
+  vasprintf.c vfprintf.c vprintf.c vsnprintf.c vsprintf.c		 \
+  repl-vsnprintf.c
diff --git a/third_party/gmp/printf/Makefile.in b/third_party/gmp/printf/Makefile.in
new file mode 100644
index 0000000..6be1da7
--- /dev/null
+++ b/third_party/gmp/printf/Makefile.in
@@ -0,0 +1,649 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Copyright 2001, 2002 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = printf
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libprintf_la_LIBADD =
+am_libprintf_la_OBJECTS = asprintf.lo asprntffuns.lo doprnt.lo \
+	doprntf.lo doprnti.lo fprintf.lo obprintf.lo obvprintf.lo \
+	obprntffuns.lo printf.lo printffuns.lo snprintf.lo \
+	snprntffuns.lo sprintf.lo sprintffuns.lo vasprintf.lo \
+	vfprintf.lo vprintf.lo vsnprintf.lo vsprintf.lo \
+	repl-vsnprintf.lo
+libprintf_la_OBJECTS = $(am_libprintf_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp =
+am__depfiles_maybe =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+SOURCES = $(libprintf_la_SOURCES)
+DIST_SOURCES = $(libprintf_la_SOURCES)
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ABI = @ABI@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+ASMFLAGS = @ASMFLAGS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CALLING_CONVENTIONS_OBJS = @CALLING_CONVENTIONS_OBJS@
+CC = @CC@
+CCAS = @CCAS@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPP_FOR_BUILD = @CPP_FOR_BUILD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFN_LONG_LONG_LIMB = @DEFN_LONG_LONG_LIMB@
+DEFS = @DEFS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@
+FGREP = @FGREP@
+GMP_LDFLAGS = @GMP_LDFLAGS@
+GMP_LIMB_BITS = @GMP_LIMB_BITS@
+GMP_NAIL_BITS = @GMP_NAIL_BITS@
+GREP = @GREP@
+HAVE_CLOCK_01 = @HAVE_CLOCK_01@
+HAVE_CPUTIME_01 = @HAVE_CPUTIME_01@
+HAVE_GETRUSAGE_01 = @HAVE_GETRUSAGE_01@
+HAVE_GETTIMEOFDAY_01 = @HAVE_GETTIMEOFDAY_01@
+HAVE_HOST_CPU_FAMILY_power = @HAVE_HOST_CPU_FAMILY_power@
+HAVE_HOST_CPU_FAMILY_powerpc = @HAVE_HOST_CPU_FAMILY_powerpc@
+HAVE_SIGACTION_01 = @HAVE_SIGACTION_01@
+HAVE_SIGALTSTACK_01 = @HAVE_SIGALTSTACK_01@
+HAVE_SIGSTACK_01 = @HAVE_SIGSTACK_01@
+HAVE_STACK_T_01 = @HAVE_STACK_T_01@
+HAVE_SYS_RESOURCE_H_01 = @HAVE_SYS_RESOURCE_H_01@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCURSES = @LIBCURSES@
+LIBGMPXX_LDFLAGS = @LIBGMPXX_LDFLAGS@
+LIBGMP_DLL = @LIBGMP_DLL@
+LIBGMP_LDFLAGS = @LIBGMP_LDFLAGS@
+LIBM = @LIBM@
+LIBM_FOR_BUILD = @LIBM_FOR_BUILD@
+LIBOBJS = @LIBOBJS@
+LIBREADLINE = @LIBREADLINE@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+M4 = @M4@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPEED_CYCLECOUNTER_OBJ = @SPEED_CYCLECOUNTER_OBJ@
+STRIP = @STRIP@
+TAL_OBJECT = @TAL_OBJECT@
+TUNE_LIBS = @TUNE_LIBS@
+TUNE_SQR_OBJ = @TUNE_SQR_OBJ@
+U_FOR_BUILD = @U_FOR_BUILD@
+VERSION = @VERSION@
+WITH_READLINE_01 = @WITH_READLINE_01@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__leading_dot = @am__leading_dot@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gmp_srclinks = @gmp_srclinks@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+mpn_objects = @mpn_objects@
+mpn_objs_in_libgmp = @mpn_objs_in_libgmp@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_CPPFLAGS = -D__GMP_WITHIN_GMP -I$(top_srcdir)
+noinst_LTLIBRARIES = libprintf.la
+libprintf_la_SOURCES = \
+  asprintf.c asprntffuns.c doprnt.c doprntf.c doprnti.c			 \
+  fprintf.c obprintf.c obvprintf.c obprntffuns.c			 \
+  printf.c printffuns.c snprintf.c snprntffuns.c sprintf.c sprintffuns.c \
+  vasprintf.c vfprintf.c vprintf.c vsnprintf.c vsprintf.c		 \
+  repl-vsnprintf.c
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu --ignore-deps printf/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu --ignore-deps printf/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+	@list='$(noinst_LTLIBRARIES)'; \
+	locs=`for p in $$list; do echo $$p; done | \
+	      sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+	      sort -u`; \
+	test -z "$$locs" || { \
+	  echo rm -f $${locs}; \
+	  rm -f $${locs}; \
+	}
+
+libprintf.la: $(libprintf_la_OBJECTS) $(libprintf_la_DEPENDENCIES) $(EXTRA_libprintf_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(LINK)  $(libprintf_la_OBJECTS) $(libprintf_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+.c.o:
+	$(AM_V_CC)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+	$(AM_V_CC)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+	$(AM_V_CC)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+	clean-libtool clean-noinstLTLIBRARIES cscopelist-am ctags \
+	ctags-am distclean distclean-compile distclean-generic \
+	distclean-libtool distclean-tags distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-dvi install-dvi-am install-exec \
+	install-exec-am install-html install-html-am install-info \
+	install-info-am install-man install-pdf install-pdf-am \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/third_party/gmp/printf/asprintf.c b/third_party/gmp/printf/asprintf.c
new file mode 100644
index 0000000..da87b75
--- /dev/null
+++ b/third_party/gmp/printf/asprintf.c
@@ -0,0 +1,47 @@
+/* gmp_asprintf -- formatted output to an allocated space.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+
+#include "gmp-impl.h"
+
+
+int
+gmp_asprintf (char **result, const char *fmt, ...)
+{
+  va_list  ap;
+  int      ret;
+
+  va_start (ap, fmt);
+
+  ret = gmp_vasprintf (result, fmt, ap);
+  va_end (ap);
+  return ret;
+}
diff --git a/third_party/gmp/printf/asprntffuns.c b/third_party/gmp/printf/asprntffuns.c
new file mode 100644
index 0000000..022a80c
--- /dev/null
+++ b/third_party/gmp/printf/asprntffuns.c
@@ -0,0 +1,71 @@
+/* __gmp_asprintf_memory etc -- formatted output to allocated space.
+
+Copyright 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+/* These routines are in a separate file so that the mpz_t, mpq_t and mpf_t
+   operator<< routines can avoid dragging vsnprintf into the link (via
+   __gmp_asprintf_format).  */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gmp-impl.h"
+
+
+int
+__gmp_asprintf_memory (struct gmp_asprintf_t *d, const char *str, size_t len)
+{
+  GMP_ASPRINTF_T_NEED (d, len);
+  memcpy (d->buf + d->size, str, len);
+  d->size += len;
+  return len;
+}
+
+int
+__gmp_asprintf_reps (struct gmp_asprintf_t *d, int c, int reps)
+{
+  GMP_ASPRINTF_T_NEED (d, reps);
+  memset (d->buf + d->size, c, reps);
+  d->size += reps;
+  return reps;
+}
+
+int
+__gmp_asprintf_final (struct gmp_asprintf_t *d)
+{
+  char  *buf = d->buf;
+  ASSERT (d->alloc >= d->size + 1);
+  buf[d->size] = '\0';
+  __GMP_REALLOCATE_FUNC_MAYBE_TYPE (buf, d->alloc, d->size+1, char);
+  *d->result = buf;
+  return 0;
+}
diff --git a/third_party/gmp/printf/doprnt.c b/third_party/gmp/printf/doprnt.c
new file mode 100644
index 0000000..fa3f302
--- /dev/null
+++ b/third_party/gmp/printf/doprnt.c
@@ -0,0 +1,626 @@
+/* __gmp_doprnt -- printf style formatted output.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2001-2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define _GNU_SOURCE    /* for DECIMAL_POINT in glibc langinfo.h */
+
+#include "config.h"	/* needed for the HAVE_, could also move gmp incls */
+
+#include <stdarg.h>
+#include <ctype.h>     /* for isdigit */
+#include <stddef.h>    /* for ptrdiff_t */
+#include <string.h>
+#include <stdio.h>     /* for NULL */
+#include <stdlib.h>
+
+#if HAVE_INTTYPES_H
+# include <inttypes.h> /* for intmax_t */
+#else
+# if HAVE_STDINT_H
+#  include <stdint.h>
+# endif
+#endif
+
+#if HAVE_LANGINFO_H
+#include <langinfo.h>  /* for nl_langinfo */
+#endif
+
+#if HAVE_LOCALE_H
+#include <locale.h>    /* for localeconv */
+#endif
+
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h> /* for quad_t */
+#endif
+
+#include "gmp-impl.h"
+
+
+/* change this to "#define TRACE(x) x" for diagnostics */
+#define TRACE(x)
+
+
+/* Should be portable, but in any case this is only used under some ASSERTs. */
+#define va_equal(x, y)                           \
+  (memcmp (&(x), &(y), sizeof(va_list)) == 0)
+
+
+/* printf is convenient because it allows various types to be printed in one
+   fairly compact call, so having gmp_printf support the standard types as
+   well as the gmp ones is important.  This ends up meaning all the standard
+   parsing must be duplicated, to get a new routine recognising the gmp
+   extras.
+
+   With the currently favoured handling of mpz etc as Z, Q and F type
+   markers, it's not possible to use glibc register_printf_function since
+   that only accepts new conversion characters, not new types.  If Z was a
+   conversion there'd be no way to specify hex, decimal or octal, or
+   similarly with F no way to specify fixed point or scientific format.
+
+   It seems wisest to pass conversions %f, %e and %g of float, double and
+   long double over to the standard printf.  It'd be hard to be sure of
+   getting the right handling for NaNs, rounding, etc.  Integer conversions
+   %d etc and string conversions %s on the other hand could be easily enough
+   handled within gmp_doprnt, but if floats are going to libc then it's just
+   as easy to send all non-gmp types there.
+
+   "Z" was a type marker for size_t in old glibc, but there seems no need to
+   provide access to that now "z" is standard.
+
+   In GMP 4.1.1 we documented "ll" and "L" as being equivalent, but in C99
+   in fact "ll" is just for long long and "L" just for long double.
+   Apparently GLIBC allows "L" for long long though.  This doesn't affect
+   us as such, since both are passed through to the C library.  To be
+   consistent with what we said before, the two are treated equivalently
+   here, and it's left to the C library to do what it thinks with them.
+
+   Possibilities:
+
+   "b" might be nice for binary output, and could even be supported for the
+   standard C types too if desired.
+
+   POSIX style "%n$" parameter numbering would be possible, but would need
+   to be handled completely within gmp_doprnt, since the numbering will be
+   all different once the format string it cut into pieces.
+
+   Some options for mpq formatting would be good.  Perhaps a non-zero
+   precision field could give a width for the denominator and mean always
+   put a "/".  A form "n+p/q" might interesting too, though perhaps that's
+   better left to applications.
+
+   Right now there's no way for an application to know whether types like
+   intmax_t are supported here.  If configure is doing its job and the same
+   compiler is used for gmp as for the application then there shouldn't be
+   any problem, but perhaps gmp.h should have some preprocessor symbols to
+   say what libgmp can do.  */
+
+
+
+/* If a gmp format is the very first thing or there are two gmp formats with
+   nothing in between then we'll reach here with this_fmt == last_fmt and we
+   can do nothing in that case.
+
+   last_ap is always replaced after a FLUSH, so it doesn't matter if va_list
+   is a call-by-reference and the funs->format routine modifies it.  */
+
+#define FLUSH()                                         \
+  do {                                                  \
+    if (this_fmt == last_fmt)                           \
+      {                                                 \
+	TRACE (printf ("nothing to flush\n"));          \
+	ASSERT (va_equal (this_ap, last_ap));           \
+      }                                                 \
+    else                                                \
+      {                                                 \
+	ASSERT (*this_fmt == '%');                      \
+	*this_fmt = '\0';                               \
+	TRACE (printf ("flush \"%s\"\n", last_fmt));    \
+	DOPRNT_FORMAT (last_fmt, last_ap);              \
+      }                                                 \
+  } while (0)
+
+
+/* Parse up the given format string and do the appropriate output using the
+   given "funs" routines.  The data parameter is passed through to those
+   routines.  */
+
+int
+__gmp_doprnt (const struct doprnt_funs_t *funs, void *data,
+	      const char *orig_fmt, va_list orig_ap)
+{
+  va_list  ap, this_ap, last_ap;
+  size_t   alloc_fmt_size, orig_fmt_size;
+  char     *fmt, *alloc_fmt, *last_fmt, *this_fmt, *gmp_str;
+  int      retval = 0;
+  int      type, fchar, *value, seen_precision;
+  struct doprnt_params_t param;
+
+  TRACE (printf ("gmp_doprnt \"%s\"\n", orig_fmt));
+
+  /* Don't modify orig_ap, if va_list is actually an array and hence call by
+     reference.  It could be argued that it'd be more efficient to leave the
+     caller to make a copy if it cared, but doing so here is going to be a
+     very small part of the total work, and we may as well keep applications
+     out of trouble.  */
+  va_copy (ap, orig_ap);
+
+  /* The format string is chopped up into pieces to be passed to
+     funs->format.  Unfortunately that means it has to be copied so each
+     piece can be null-terminated.  We're not going to be very fast here, so
+     use __gmp_allocate_func rather than TMP_ALLOC, to avoid overflowing the
+     stack if a long output string is given.  */
+  alloc_fmt_size = orig_fmt_size = strlen (orig_fmt) + 1;
+#if _LONG_LONG_LIMB
+  /* for a long long limb we change %Mx to %llx, so could need an extra 1
+     char for every 3 existing */
+  alloc_fmt_size += alloc_fmt_size / 3;
+#endif
+  alloc_fmt = __GMP_ALLOCATE_FUNC_TYPE (alloc_fmt_size, char);
+  fmt = alloc_fmt;
+  memcpy (fmt, orig_fmt, orig_fmt_size);
+
+  /* last_fmt and last_ap are just after the last output, and hence where
+     the next output will begin, when that's done */
+  last_fmt = fmt;
+  va_copy (last_ap, ap);
+
+  for (;;)
+    {
+      TRACE (printf ("next: \"%s\"\n", fmt));
+
+      fmt = strchr (fmt, '%');
+      if (fmt == NULL)
+	break;
+
+      /* this_fmt and this_ap are the current '%' sequence being considered */
+      this_fmt = fmt;
+      va_copy (this_ap, ap);
+      fmt++; /* skip the '%' */
+
+      TRACE (printf ("considering\n");
+	     printf ("  last: \"%s\"\n", last_fmt);
+	     printf ("  this: \"%s\"\n", this_fmt));
+
+      type = '\0';
+      value = &param.width;
+
+      param.base = 10;
+      param.conv = 0;
+      param.expfmt = "e%c%02ld";
+      param.exptimes4 = 0;
+      param.fill = ' ';
+      param.justify = DOPRNT_JUSTIFY_RIGHT;
+      param.prec = 6;
+      param.showbase = DOPRNT_SHOWBASE_NO;
+      param.showpoint = 0;
+      param.showtrailing = 1;
+      param.sign = '\0';
+      param.width = 0;
+      seen_precision = 0;
+
+      /* This loop parses a single % sequence.  "break" from the switch
+	 means continue with this %, "goto next" means the conversion
+	 character has been seen and a new % should be sought.  */
+      for (;;)
+	{
+	  fchar = *fmt++;
+	  if (fchar == '\0')
+	    break;
+
+	  switch (fchar) {
+
+	  case 'a':
+	    /* %a behaves like %e, but defaults to all significant digits,
+	       and there's no leading zeros on the exponent (which is in
+	       fact bit-based) */
+	    param.base = 16;
+	    param.expfmt = "p%c%ld";
+	    goto conv_a;
+	  case 'A':
+	    param.base = -16;
+	    param.expfmt = "P%c%ld";
+	  conv_a:
+	    param.conv = DOPRNT_CONV_SCIENTIFIC;
+	    param.exptimes4 = 1;
+	    if (! seen_precision)
+	      param.prec = -1;  /* default to all digits */
+	    param.showbase = DOPRNT_SHOWBASE_YES;
+	    param.showtrailing = 1;
+	    goto floating_a;
+
+	  case 'c':
+	    /* Let's assume wchar_t will be promoted to "int" in the call,
+	       the same as char will be. */
+	    (void) va_arg (ap, int);
+	    goto next;
+
+	  case 'd':
+	  case 'i':
+	  case 'u':
+	  integer:
+	    TRACE (printf ("integer, base=%d\n", param.base));
+	    if (! seen_precision)
+	      param.prec = -1;
+	    switch (type) {
+	    case 'j':
+	      /* Let's assume uintmax_t is the same size as intmax_t. */
+#if HAVE_INTMAX_T
+	      (void) va_arg (ap, intmax_t);
+#else
+	      ASSERT_FAIL (intmax_t not available);
+#endif
+	      break;
+	    case 'l':
+	      (void) va_arg (ap, long);
+	      break;
+	    case 'L':
+#if HAVE_LONG_LONG
+	      (void) va_arg (ap, long long);
+#else
+	      ASSERT_FAIL (long long not available);
+#endif
+	      break;
+	    case 'N':
+	      {
+		mp_ptr     xp;
+		mp_size_t  xsize, abs_xsize;
+		mpz_t      z;
+		FLUSH ();
+		xp = va_arg (ap, mp_ptr);
+		PTR(z) = xp;
+		xsize = (int) va_arg (ap, mp_size_t);
+		abs_xsize = ABS (xsize);
+		MPN_NORMALIZE (xp, abs_xsize);
+		SIZ(z) = (xsize >= 0 ? abs_xsize : -abs_xsize);
+		ASSERT_CODE (ALLOC(z) = abs_xsize);
+		gmp_str = mpz_get_str (NULL, param.base, z);
+		goto gmp_integer;
+	      }
+	      /* break; */
+	    case 'q':
+	      /* quad_t is probably the same as long long, but let's treat
+		 it separately just to be sure.  Also let's assume u_quad_t
+		 will be the same size as quad_t.  */
+#if HAVE_QUAD_T
+	      (void) va_arg (ap, quad_t);
+#else
+	      ASSERT_FAIL (quad_t not available);
+#endif
+	      break;
+	    case 'Q':
+	      FLUSH ();
+	      gmp_str = mpq_get_str (NULL, param.base, va_arg(ap, mpq_srcptr));
+	      goto gmp_integer;
+	    case 't':
+#if HAVE_PTRDIFF_T
+	      (void) va_arg (ap, ptrdiff_t);
+#else
+	      ASSERT_FAIL (ptrdiff_t not available);
+#endif
+	      break;
+	    case 'z':
+	      (void) va_arg (ap, size_t);
+	      break;
+	    case 'Z':
+	      {
+		int   ret;
+		FLUSH ();
+		gmp_str = mpz_get_str (NULL, param.base,
+				       va_arg (ap, mpz_srcptr));
+	      gmp_integer:
+		ret = __gmp_doprnt_integer (funs, data, &param, gmp_str);
+		 __GMP_FREE_FUNC_TYPE (gmp_str, strlen(gmp_str)+1, char);
+		DOPRNT_ACCUMULATE (ret);
+		va_copy (last_ap, ap);
+		last_fmt = fmt;
+	      }
+	      break;
+	    default:
+	      /* default is an "int", and this includes h=short and hh=char
+		 since they're promoted to int in a function call */
+	      (void) va_arg (ap, int);
+	      break;
+	    }
+	    goto next;
+
+	  case 'E':
+	    param.base = -10;
+	    param.expfmt = "E%c%02ld";
+	    /*FALLTHRU*/
+	  case 'e':
+	    param.conv = DOPRNT_CONV_SCIENTIFIC;
+	  floating:
+	    if (param.showbase == DOPRNT_SHOWBASE_NONZERO)
+	      {
+		/* # in %e, %f and %g */
+		param.showpoint = 1;
+		param.showtrailing = 1;
+	      }
+	  floating_a:
+	    switch (type) {
+	    case 'F':
+	      FLUSH ();
+	      DOPRNT_ACCUMULATE (__gmp_doprnt_mpf (funs, data, &param,
+						   GMP_DECIMAL_POINT,
+						   va_arg (ap, mpf_srcptr)));
+	      va_copy (last_ap, ap);
+	      last_fmt = fmt;
+	      break;
+	    case 'L':
+#if HAVE_LONG_DOUBLE
+	      (void) va_arg (ap, long double);
+#else
+	      ASSERT_FAIL (long double not available);
+#endif
+	      break;
+	    default:
+	      (void) va_arg (ap, double);
+	      break;
+	    }
+	    goto next;
+
+	  case 'f':
+	    param.conv = DOPRNT_CONV_FIXED;
+	    goto floating;
+
+	  case 'F': /* mpf_t     */
+	  case 'j': /* intmax_t  */
+	  case 'L': /* long long */
+	  case 'N': /* mpn       */
+	  case 'q': /* quad_t    */
+	  case 'Q': /* mpq_t     */
+	  case 't': /* ptrdiff_t */
+	  case 'z': /* size_t    */
+	  case 'Z': /* mpz_t     */
+	  set_type:
+	    type = fchar;
+	    break;
+
+	  case 'G':
+	    param.base = -10;
+	    param.expfmt = "E%c%02ld";
+	    /*FALLTHRU*/
+	  case 'g':
+	    param.conv = DOPRNT_CONV_GENERAL;
+	    param.showtrailing = 0;
+	    goto floating;
+
+	  case 'h':
+	    if (type != 'h')
+	      goto set_type;
+	    type = 'H';   /* internal code for "hh" */
+	    break;
+
+	  case 'l':
+	    if (type != 'l')
+	      goto set_type;
+	    type = 'L';   /* "ll" means "L" */
+	    break;
+
+	  case 'm':
+	    /* glibc strerror(errno), no argument */
+	    goto next;
+
+	  case 'M': /* mp_limb_t */
+	    /* mung format string to l or ll and let plain printf handle it */
+#if _LONG_LONG_LIMB
+	    memmove (fmt+1, fmt, strlen (fmt)+1);
+	    fmt[-1] = 'l';
+	    fmt[0] = 'l';
+	    fmt++;
+	    type = 'L';
+#else
+	    fmt[-1] = 'l';
+	    type = 'l';
+#endif
+	    break;
+
+	  case 'n':
+	    {
+	      void  *p;
+	      FLUSH ();
+	      p = va_arg (ap, void *);
+	      switch (type) {
+	      case '\0': * (int       *) p = retval; break;
+	      case 'F':  mpf_set_si ((mpf_ptr) p, (long) retval); break;
+	      case 'H':  * (char      *) p = retval; break;
+	      case 'h':  * (short     *) p = retval; break;
+#if HAVE_INTMAX_T
+	      case 'j':  * (intmax_t  *) p = retval; break;
+#else
+	      case 'j':  ASSERT_FAIL (intmax_t not available); break;
+#endif
+	      case 'l':  * (long      *) p = retval; break;
+#if HAVE_QUAD_T && HAVE_LONG_LONG
+	      case 'q':
+		ASSERT_ALWAYS (sizeof (quad_t) == sizeof (long long));
+		/*FALLTHRU*/
+#else
+	      case 'q':  ASSERT_FAIL (quad_t not available); break;
+#endif
+#if HAVE_LONG_LONG
+	      case 'L':  * (long long *) p = retval; break;
+#else
+	      case 'L':  ASSERT_FAIL (long long not available); break;
+#endif
+	      case 'N':
+		{
+		  mp_size_t  n;
+		  n = va_arg (ap, mp_size_t);
+		  n = ABS (n);
+		  if (n != 0)
+		    {
+		      * (mp_ptr) p = retval;
+		      MPN_ZERO ((mp_ptr) p + 1, n - 1);
+		    }
+		}
+		break;
+	      case 'Q':  mpq_set_si ((mpq_ptr) p, (long) retval, 1L); break;
+#if HAVE_PTRDIFF_T
+	      case 't':  * (ptrdiff_t *) p = retval; break;
+#else
+	      case 't':  ASSERT_FAIL (ptrdiff_t not available); break;
+#endif
+	      case 'z':  * (size_t    *) p = retval; break;
+	      case 'Z':  mpz_set_si ((mpz_ptr) p, (long) retval); break;
+	      }
+	    }
+	    va_copy (last_ap, ap);
+	    last_fmt = fmt;
+	    goto next;
+
+	  case 'o':
+	    param.base = 8;
+	    goto integer;
+
+	  case 'p':
+	  case 's':
+	    /* "void *" will be good enough for "char *" or "wchar_t *", no
+	       need for separate code.  */
+	    (void) va_arg (ap, const void *);
+	    goto next;
+
+	  case 'x':
+	    param.base = 16;
+	    goto integer;
+	  case 'X':
+	    param.base = -16;
+	    goto integer;
+
+	  case '%':
+	    goto next;
+
+	  case '#':
+	    param.showbase = DOPRNT_SHOWBASE_NONZERO;
+	    break;
+
+	  case '\'':
+	    /* glibc digit grouping, just pass it through, no support for it
+	       on gmp types */
+	    break;
+
+	  case '+':
+	  case ' ':
+	    param.sign = fchar;
+	    break;
+
+	  case '-':
+	    param.justify = DOPRNT_JUSTIFY_LEFT;
+	    break;
+	  case '.':
+	    seen_precision = 1;
+	    param.prec = -1; /* "." alone means all necessary digits */
+	    value = &param.prec;
+	    break;
+
+	  case '*':
+	    {
+	      int n = va_arg (ap, int);
+
+	      if (value == &param.width)
+		{
+		  /* negative width means left justify */
+		  if (n < 0)
+		    {
+		      param.justify = DOPRNT_JUSTIFY_LEFT;
+		      n = -n;
+		    }
+		  param.width = n;
+		}
+	      else
+		{
+		  /* don't allow negative precision */
+		  param.prec = MAX (0, n);
+		}
+	    }
+	    break;
+
+	  case '0':
+	    if (value == &param.width)
+	      {
+		/* in width field, set fill */
+		param.fill = '0';
+
+		/* for right justify, put the fill after any minus sign */
+		if (param.justify == DOPRNT_JUSTIFY_RIGHT)
+		  param.justify = DOPRNT_JUSTIFY_INTERNAL;
+	      }
+	    else
+	      {
+		/* in precision field, set value */
+		*value = 0;
+	      }
+	    break;
+
+	  case '1': case '2': case '3': case '4': case '5':
+	  case '6': case '7': case '8': case '9':
+	    /* process all digits to form a value */
+	    {
+	      int  n = 0;
+	      do {
+		n = n * 10 + (fchar-'0');
+		fchar = *fmt++;
+	      } while (isascii (fchar) && isdigit (fchar));
+	      fmt--; /* unget the non-digit */
+	      *value = n;
+	    }
+	    break;
+
+	  default:
+	    /* something invalid */
+	    ASSERT (0);
+	    goto next;
+	  }
+	}
+
+    next:
+      /* Stop parsing the current "%" format, look for a new one. */
+      ;
+    }
+
+  TRACE (printf ("remainder: \"%s\"\n", last_fmt));
+  if (*last_fmt != '\0')
+    DOPRNT_FORMAT (last_fmt, last_ap);
+
+  if (funs->final != NULL)
+    if ((*funs->final) (data) == -1)
+      goto error;
+
+ done:
+  __GMP_FREE_FUNC_TYPE (alloc_fmt, alloc_fmt_size, char);
+  return retval;
+
+ error:
+  retval = -1;
+  goto done;
+}
diff --git a/third_party/gmp/printf/doprntf.c b/third_party/gmp/printf/doprntf.c
new file mode 100644
index 0000000..2a7e0d2
--- /dev/null
+++ b/third_party/gmp/printf/doprntf.c
@@ -0,0 +1,389 @@
+/* __gmp_doprnt_mpf -- mpf formatted output.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2001, 2002, 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>    /* for va_list and hence doprnt_funs_t */
+#include <ctype.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* change this to "#define TRACE(x) x" for diagnostics */
+#define TRACE(x)
+
+
+/* The separate of __gmp_doprnt_float_digits and __gmp_doprnt_float is so
+   some C++ can do the mpf_get_str and release it in case of an exception */
+
+#define DIGIT_VALUE(c)                  \
+  (isdigit (c)   ? (c) - '0'            \
+   : islower (c) ? (c) - 'a' + 10       \
+   :               (c) - 'A' + 10)
+
+int
+__gmp_doprnt_mpf (const struct doprnt_funs_t *funs,
+		  void *data,
+		  const struct doprnt_params_t *p,
+		  const char *point,
+		  mpf_srcptr f)
+{
+  int         prec, ndigits, free_size, len, newlen, justify, justlen, explen;
+  int         showbaselen, sign, signlen, intlen, intzeros, pointlen;
+  int         fraczeros, fraclen, preczeros;
+  char        *s, *free_ptr;
+  mp_exp_t    exp;
+  char        exponent[GMP_LIMB_BITS + 10];
+  const char  *showbase;
+  int         retval = 0;
+
+  TRACE (printf ("__gmp_doprnt_float\n");
+	 printf ("  conv=%d prec=%d\n", p->conv, p->prec));
+
+  prec = p->prec;
+  if (prec <= -1)
+    {
+      /* all digits */
+      ndigits = 0;
+
+      /* arrange the fixed/scientific decision on a "prec" implied by how
+	 many significant digits there are */
+      if (p->conv == DOPRNT_CONV_GENERAL)
+	MPF_SIGNIFICANT_DIGITS (prec, PREC(f), ABS(p->base));
+    }
+  else
+    {
+      switch (p->conv) {
+      case DOPRNT_CONV_FIXED:
+	/* Precision is digits after the radix point.  Try not to generate
+	   too many more than will actually be required.  If f>=1 then
+	   overestimate the integer part, and add prec.  If f<1 then
+	   underestimate the zeros between the radix point and the first
+	   digit and subtract that from prec.  In either case add 2 so the
+	   round to nearest can be applied accurately.  Finally, we add 1 to
+	   handle the case of 1-eps where EXP(f) = 0 but mpf_get_str returns
+	   exp as 1.  */
+	ndigits = prec + 2 + 1
+	  + EXP(f) * (mp_bases[ABS(p->base)].chars_per_limb + (EXP(f)>=0));
+	ndigits = MAX (ndigits, 1);
+	break;
+
+      case DOPRNT_CONV_SCIENTIFIC:
+	/* precision is digits after the radix point, and there's one digit
+	   before */
+	ndigits = prec + 1;
+	break;
+
+      default:
+	ASSERT (0);
+	/*FALLTHRU*/
+
+      case DOPRNT_CONV_GENERAL:
+	/* precision is total digits, but be sure to ask mpf_get_str for at
+	   least 1, not 0 */
+	ndigits = MAX (prec, 1);
+	break;
+      }
+    }
+  TRACE (printf ("  ndigits %d\n", ndigits));
+
+  s = mpf_get_str (NULL, &exp, p->base, ndigits, f);
+  len = strlen (s);
+  free_ptr = s;
+  free_size = len + 1;
+  TRACE (printf ("  s   %s\n", s);
+	 printf ("  exp %ld\n", exp);
+	 printf ("  len %d\n", len));
+
+  /* For fixed mode check the ndigits formed above was in fact enough for
+     the integer part plus p->prec after the radix point. */
+  ASSERT ((p->conv == DOPRNT_CONV_FIXED && p->prec > -1)
+	  ? ndigits >= MAX (1, exp + p->prec + 2) : 1);
+
+  sign = p->sign;
+  if (s[0] == '-')
+    {
+      sign = s[0];
+      s++, len--;
+    }
+  signlen = (sign != '\0');
+  TRACE (printf ("  sign %c  signlen %d\n", sign, signlen));
+
+  switch (p->conv) {
+  case DOPRNT_CONV_FIXED:
+    if (prec <= -1)
+      prec = MAX (0, len-exp);   /* retain all digits */
+
+    /* Truncate if necessary so fraction will be at most prec digits. */
+    ASSERT (prec >= 0);
+    newlen = exp + prec;
+    if (newlen < 0)
+      {
+	/* first non-zero digit is below target prec, and at least one zero
+	   digit in between, so print zero */
+	len = 0;
+	exp = 0;
+      }
+    else if (len <= newlen)
+      {
+	/* already got few enough digits */
+      }
+    else
+      {
+	/* discard excess digits and round to nearest */
+
+	const char  *num_to_text = (p->base >= 0
+				    ? "0123456789abcdefghijklmnopqrstuvwxyz"
+				    : "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ");
+	int  base = ABS(p->base);
+	int  n;
+
+	ASSERT (base <= 36);
+
+	len = newlen;
+	n = DIGIT_VALUE (s[len]);
+	TRACE (printf ("  rounding with %d\n", n));
+	if (n >= (base + 1) / 2)
+	  {
+	    /* propagate a carry */
+	    for (;;)
+	      {
+		if (len == 0)
+		  {
+		    s[0] = '1';
+		    len = 1;
+		    exp++;
+		    break;
+		  }
+		n = DIGIT_VALUE (s[len-1]);
+		ASSERT (n >= 0 && n < base);
+		n++;
+		if (n != base)
+		  {
+		    TRACE (printf ("  storing now %d\n", n));
+		    s[len-1] = num_to_text[n];
+		    break;
+		  }
+		len--;
+	      }
+	  }
+	else
+	  {
+	    /* truncate only, strip any trailing zeros now exposed */
+	    while (len > 0 && s[len-1] == '0')
+	      len--;
+	  }
+
+	/* Can have newlen==0, in which case the truncate was just to check
+	   for a carry turning it into "1".  If we're left with len==0 then
+	   adjust exp to match.  */
+	if (len == 0)
+	  exp = 0;
+      }
+
+  fixed:
+    ASSERT (len == 0 ? exp == 0 : 1);
+    if (exp <= 0)
+      {
+	TRACE (printf ("  fixed 0.000sss\n"));
+	intlen = 0;
+	intzeros = 1;
+	fraczeros = -exp;
+	fraclen = len;
+      }
+    else
+      {
+	TRACE (printf ("  fixed sss.sss or sss000\n"));
+	intlen = MIN (len, exp);
+	intzeros = exp - intlen;
+	fraczeros = 0;
+	fraclen = len - intlen;
+      }
+    explen = 0;
+    break;
+
+  case DOPRNT_CONV_SCIENTIFIC:
+    {
+      long int expval;
+      char  expsign;
+
+      if (prec <= -1)
+	prec = MAX (0, len-1);   /* retain all digits */
+
+    scientific:
+      TRACE (printf ("  scientific s.sss\n"));
+
+      intlen = MIN (1, len);
+      intzeros = (intlen == 0 ? 1 : 0);
+      fraczeros = 0;
+      fraclen = len - intlen;
+
+      expval = (exp-intlen);
+      if (p->exptimes4)
+	expval <<= 2;
+
+      /* Split out the sign since %o or %x in expfmt give negatives as twos
+	 complement, not with a sign. */
+      expsign = (expval >= 0 ? '+' : '-');
+      expval = ABS (expval);
+
+#if HAVE_VSNPRINTF
+      explen = snprintf (exponent, sizeof(exponent),
+			 p->expfmt, expsign, expval);
+      /* test for < sizeof-1 since a glibc 2.0.x return of sizeof-1 might
+	 mean truncation */
+      ASSERT (explen >= 0 && explen < sizeof(exponent)-1);
+#else
+      sprintf (exponent, p->expfmt, expsign, expval);
+      explen = strlen (exponent);
+      ASSERT (explen < sizeof(exponent));
+#endif
+      TRACE (printf ("  expfmt %s gives %s\n", p->expfmt, exponent));
+    }
+    break;
+
+  default:
+    ASSERT (0);
+    /*FALLTHRU*/  /* to stop variables looking uninitialized */
+
+  case DOPRNT_CONV_GENERAL:
+    /* The exponent for "scientific" will be exp-1, choose scientific if
+       this is < -4 or >= prec (and minimum 1 for prec).  For f==0 will have
+       exp==0 and get the desired "fixed".  This rule follows glibc.  For
+       fixed there's no need to truncate, the desired ndigits will already
+       be as required.  */
+    if (exp-1 < -4 || exp-1 >= MAX (1, prec))
+      goto scientific;
+    else
+      goto fixed;
+  }
+
+  TRACE (printf ("  intlen %d intzeros %d fraczeros %d fraclen %d\n",
+		 intlen, intzeros, fraczeros, fraclen));
+  ASSERT (p->prec <= -1
+	  ? intlen + fraclen == strlen (s)
+	  : intlen + fraclen <= strlen (s));
+
+  if (p->showtrailing)
+    {
+      /* Pad to requested precision with trailing zeros, for general this is
+	 all digits, for fixed and scientific just the fraction.  */
+      preczeros = prec - (fraczeros + fraclen
+			  + (p->conv == DOPRNT_CONV_GENERAL
+			     ? intlen + intzeros : 0));
+      preczeros = MAX (0, preczeros);
+    }
+  else
+    preczeros = 0;
+  TRACE (printf ("  prec=%d showtrailing=%d, pad with preczeros %d\n",
+		 prec, p->showtrailing, preczeros));
+
+  /* radix point if needed, or if forced */
+  pointlen = ((fraczeros + fraclen + preczeros) != 0 || p->showpoint != 0)
+    ? strlen (point) : 0;
+  TRACE (printf ("  point |%s|  pointlen %d\n", point, pointlen));
+
+  /* Notice the test for a non-zero value is done after any truncation for
+     DOPRNT_CONV_FIXED. */
+  showbase = NULL;
+  showbaselen = 0;
+  switch (p->showbase) {
+  default:
+    ASSERT (0);
+    /*FALLTHRU*/
+  case DOPRNT_SHOWBASE_NO:
+    break;
+  case DOPRNT_SHOWBASE_NONZERO:
+    if (intlen == 0 && fraclen == 0)
+      break;
+    /*FALLTHRU*/
+  case DOPRNT_SHOWBASE_YES:
+    switch (p->base) {
+    case 16:  showbase = "0x"; showbaselen = 2; break;
+    case -16: showbase = "0X"; showbaselen = 2; break;
+    case 8:   showbase = "0";  showbaselen = 1; break;
+    }
+    break;
+  }
+  TRACE (printf ("  showbase %s showbaselen %d\n",
+		 showbase == NULL ? "" : showbase, showbaselen));
+
+  /* left over field width */
+  justlen = p->width - (signlen + showbaselen + intlen + intzeros + pointlen
+			+ fraczeros + fraclen + preczeros + explen);
+  TRACE (printf ("  justlen %d fill 0x%X\n", justlen, p->fill));
+
+  justify = p->justify;
+  if (justlen <= 0) /* no justifying if exceed width */
+    justify = DOPRNT_JUSTIFY_NONE;
+
+  TRACE (printf ("  justify type %d  intlen %d pointlen %d fraclen %d\n",
+		 justify, intlen, pointlen, fraclen));
+
+  if (justify == DOPRNT_JUSTIFY_RIGHT)         /* pad for right */
+    DOPRNT_REPS (p->fill, justlen);
+
+  if (signlen)                                 /* sign */
+    DOPRNT_REPS (sign, 1);
+
+  DOPRNT_MEMORY_MAYBE (showbase, showbaselen); /* base */
+
+  if (justify == DOPRNT_JUSTIFY_INTERNAL)      /* pad for internal */
+    DOPRNT_REPS (p->fill, justlen);
+
+  DOPRNT_MEMORY (s, intlen);                   /* integer */
+  DOPRNT_REPS_MAYBE ('0', intzeros);
+
+  DOPRNT_MEMORY_MAYBE (point, pointlen);       /* point */
+
+  DOPRNT_REPS_MAYBE ('0', fraczeros);          /* frac */
+  DOPRNT_MEMORY_MAYBE (s+intlen, fraclen);
+
+  DOPRNT_REPS_MAYBE ('0', preczeros);          /* prec */
+
+  DOPRNT_MEMORY_MAYBE (exponent, explen);      /* exp */
+
+  if (justify == DOPRNT_JUSTIFY_LEFT)          /* pad for left */
+    DOPRNT_REPS (p->fill, justlen);
+
+ done:
+  __GMP_FREE_FUNC_TYPE (free_ptr, free_size, char);
+  return retval;
+
+ error:
+  retval = -1;
+  goto done;
+}
diff --git a/third_party/gmp/printf/doprnti.c b/third_party/gmp/printf/doprnti.c
new file mode 100644
index 0000000..61ff643
--- /dev/null
+++ b/third_party/gmp/printf/doprnti.c
@@ -0,0 +1,136 @@
+/* __gmp_doprnt_integer -- integer style formatted output.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>    /* for va_list and hence doprnt_funs_t */
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+
+
+int
+__gmp_doprnt_integer (const struct doprnt_funs_t *funs,
+		      void *data,
+		      const struct doprnt_params_t *p,
+		      const char *s)
+{
+  int         retval = 0;
+  int         slen, justlen, showbaselen, sign, signlen, slashlen, zeros;
+  int         justify, den_showbaselen;
+  const char  *slash, *showbase;
+
+  /* '+' or ' ' if wanted, and don't already have '-' */
+  sign = p->sign;
+  if (s[0] == '-')
+    {
+      sign = s[0];
+      s++;
+    }
+  signlen = (sign != '\0');
+
+  /* if the precision was explicitly 0, print nothing for a 0 value */
+  if (*s == '0' && p->prec == 0)
+    s++;
+
+  slen = strlen (s);
+  slash = strchr (s, '/');
+
+  showbase = NULL;
+  showbaselen = 0;
+
+  if (p->showbase != DOPRNT_SHOWBASE_NO)
+    {
+      switch (p->base) {
+      case 16:  showbase = "0x"; showbaselen = 2; break;
+      case -16: showbase = "0X"; showbaselen = 2; break;
+      case 8:   showbase = "0";  showbaselen = 1; break;
+      }
+    }
+
+  den_showbaselen = showbaselen;
+  if (slash == NULL
+      || (p->showbase == DOPRNT_SHOWBASE_NONZERO && slash[1] == '0'))
+    den_showbaselen = 0;
+
+  if (p->showbase == DOPRNT_SHOWBASE_NONZERO && s[0] == '0')
+    showbaselen = 0;
+
+  /* the influence of p->prec on mpq is currently undefined */
+  zeros = MAX (0, p->prec - slen);
+
+  /* space left over after actual output length */
+  justlen = p->width
+    - (strlen(s) + signlen + showbaselen + den_showbaselen + zeros);
+
+  justify = p->justify;
+  if (justlen <= 0) /* no justifying if exceed width */
+    justify = DOPRNT_JUSTIFY_NONE;
+
+  if (justify == DOPRNT_JUSTIFY_RIGHT)             /* pad right */
+    DOPRNT_REPS (p->fill, justlen);
+
+  DOPRNT_REPS_MAYBE (sign, signlen);               /* sign */
+
+  DOPRNT_MEMORY_MAYBE (showbase, showbaselen);     /* base */
+
+  DOPRNT_REPS_MAYBE ('0', zeros);                  /* zeros */
+
+  if (justify == DOPRNT_JUSTIFY_INTERNAL)          /* pad internal */
+    DOPRNT_REPS (p->fill, justlen);
+
+  /* if there's a showbase on the denominator, then print the numerator
+     separately so it can be inserted */
+  if (den_showbaselen != 0)
+    {
+      ASSERT (slash != NULL);
+      slashlen = slash+1 - s;
+      DOPRNT_MEMORY (s, slashlen);                 /* numerator and slash */
+      slen -= slashlen;
+      s += slashlen;
+      DOPRNT_MEMORY (showbase, den_showbaselen);
+    }
+
+  DOPRNT_MEMORY (s, slen);                         /* number, or denominator */
+
+  if (justify == DOPRNT_JUSTIFY_LEFT)              /* pad left */
+    DOPRNT_REPS (p->fill, justlen);
+
+ done:
+  return retval;
+
+ error:
+  retval = -1;
+  goto done;
+}
diff --git a/third_party/gmp/printf/fprintf.c b/third_party/gmp/printf/fprintf.c
new file mode 100644
index 0000000..0008b3b
--- /dev/null
+++ b/third_party/gmp/printf/fprintf.c
@@ -0,0 +1,48 @@
+/* gmp_fprintf -- formatted output.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "gmp-impl.h"
+
+
+int
+gmp_fprintf (FILE *fp, const char *fmt, ...)
+{
+  va_list  ap;
+  int      ret;
+
+  va_start (ap, fmt);
+
+  ret = __gmp_doprnt (&__gmp_fprintf_funs, fp, fmt, ap);
+  va_end (ap);
+  return ret;
+}
diff --git a/third_party/gmp/printf/obprintf.c b/third_party/gmp/printf/obprintf.c
new file mode 100644
index 0000000..c12d6de
--- /dev/null
+++ b/third_party/gmp/printf/obprintf.c
@@ -0,0 +1,60 @@
+/* gmp_obstack_printf -- formatted output to an obstack.
+
+Copyright 2001, 2002, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#if HAVE_OBSTACK_VPRINTF
+
+#include <stdarg.h>
+#include <obstack.h>
+#include <string.h>
+
+#include "gmp-impl.h"
+
+
+int
+gmp_obstack_printf (struct obstack *ob, const char *fmt, ...)
+{
+  va_list  ap;
+  int      ret;
+
+  va_start (ap, fmt);
+
+  ASSERT (! MEM_OVERLAP_P (obstack_base(ob), obstack_object_size(ob),
+                           fmt, strlen(fmt)+1));
+
+  ret = __gmp_doprnt (&__gmp_obstack_printf_funs, ob, fmt, ap);
+  va_end (ap);
+  return ret;
+}
+
+#else
+typedef int __gmp_dummy_typedef;
+#endif /* HAVE_OBSTACK_VPRINTF */
diff --git a/third_party/gmp/printf/obprntffuns.c b/third_party/gmp/printf/obprntffuns.c
new file mode 100644
index 0000000..a23e4e8
--- /dev/null
+++ b/third_party/gmp/printf/obprntffuns.c
@@ -0,0 +1,73 @@
+/* __gmp_obstack_printf_funs -- support for gmp_obstack_printf and
+   gmp_obstack_vprintf.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2001, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#if HAVE_OBSTACK_VPRINTF
+
+#define _GNU_SOURCE   /* ask glibc <stdio.h> for obstack_vprintf */
+
+#include <stdarg.h>
+#include <stdio.h>    /* for obstack_vprintf */
+#include <string.h>
+#include <obstack.h>
+
+#include "gmp-impl.h"
+
+
+static int
+gmp_obstack_memory (struct obstack *ob, const char *ptr, size_t len)
+{
+  obstack_grow (ob, ptr, len);
+  return len;
+}
+
+static int
+gmp_obstack_reps (struct obstack *ob, int c, int reps)
+{
+  obstack_blank (ob, reps);
+  memset ((char *) obstack_next_free(ob) - reps, c, reps);
+  return reps;
+}
+
+const struct doprnt_funs_t  __gmp_obstack_printf_funs = {
+  (doprnt_format_t) obstack_vprintf,
+  (doprnt_memory_t) gmp_obstack_memory,
+  (doprnt_reps_t)   gmp_obstack_reps
+};
+
+#else
+typedef int __gmp_dummy_typedef;
+#endif /* HAVE_OBSTACK_VPRINTF */
diff --git a/third_party/gmp/printf/obvprintf.c b/third_party/gmp/printf/obvprintf.c
new file mode 100644
index 0000000..7563c11
--- /dev/null
+++ b/third_party/gmp/printf/obvprintf.c
@@ -0,0 +1,53 @@
+/* gmp_obstack_vprintf -- formatted output to an obstack.
+
+Copyright 2001, 2002, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#if HAVE_OBSTACK_VPRINTF
+
+#include <stdarg.h>
+#include <obstack.h>
+#include <string.h>
+
+#include "gmp-impl.h"
+
+
+int
+gmp_obstack_vprintf (struct obstack *ob, const char *fmt, va_list ap)
+{
+  ASSERT (! MEM_OVERLAP_P (obstack_base(ob), obstack_object_size(ob),
+                           fmt, strlen(fmt)+1));
+
+  return __gmp_doprnt (&__gmp_obstack_printf_funs, ob, fmt, ap);
+}
+
+#else
+typedef int __gmp_dummy_typedef;
+#endif /* HAVE_OBSTACK_VPRINTF */
diff --git a/third_party/gmp/printf/printf.c b/third_party/gmp/printf/printf.c
new file mode 100644
index 0000000..4becb0b
--- /dev/null
+++ b/third_party/gmp/printf/printf.c
@@ -0,0 +1,48 @@
+/* gmp_printf -- formatted output.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "gmp-impl.h"
+
+
+int
+gmp_printf (const char *fmt, ...)
+{
+  va_list  ap;
+  int      ret;
+
+  va_start (ap, fmt);
+
+  ret = __gmp_doprnt (&__gmp_fprintf_funs, stdout, fmt, ap);
+  va_end (ap);
+  return ret;
+}
diff --git a/third_party/gmp/printf/printffuns.c b/third_party/gmp/printf/printffuns.c
new file mode 100644
index 0000000..957381d
--- /dev/null
+++ b/third_party/gmp/printf/printffuns.c
@@ -0,0 +1,79 @@
+/* __gmp_fprintf_funs -- support for formatted output to FILEs.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "gmp-impl.h"
+
+/* SunOS 4 stdio.h doesn't provide a prototype for this */
+#if ! HAVE_DECL_VFPRINTF
+int vfprintf (FILE *, const char *, va_list);
+#endif
+
+
+static int
+gmp_fprintf_memory (FILE *fp, const char *str, size_t len)
+{
+  return fwrite (str, 1, len, fp);
+}
+
+/* glibc putc is a function, at least when it's in multi-threaded mode or
+   some such, so fwrite chunks instead of making many calls. */
+static int
+gmp_fprintf_reps (FILE *fp, int c, int reps)
+{
+  char  buf[256];
+  int   i, piece, ret;
+  ASSERT (reps >= 0);
+
+  memset (buf, c, MIN (reps, sizeof (buf)));
+  for (i = reps; i > 0; i -= sizeof (buf))
+    {
+      piece = MIN (i, sizeof (buf));
+      ret = fwrite (buf, 1, piece, fp);
+      if (ret == -1)
+        return ret;
+      ASSERT (ret == piece);
+    }
+
+  return reps;
+}
+
+const struct doprnt_funs_t  __gmp_fprintf_funs = {
+  (doprnt_format_t) vfprintf,
+  (doprnt_memory_t) gmp_fprintf_memory,
+  (doprnt_reps_t)   gmp_fprintf_reps,
+};
diff --git a/third_party/gmp/printf/repl-vsnprintf.c b/third_party/gmp/printf/repl-vsnprintf.c
new file mode 100644
index 0000000..d228671
--- /dev/null
+++ b/third_party/gmp/printf/repl-vsnprintf.c
@@ -0,0 +1,394 @@
+/* __gmp_replacement_vsnprintf -- for systems which don't have vsnprintf, or
+   only have a broken one.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2001, 2002, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#define _GNU_SOURCE    /* for strnlen prototype */
+
+#include <stdarg.h>
+#include <ctype.h>     /* for isdigit */
+#include <stddef.h>    /* for ptrdiff_t */
+#include <string.h>
+#include <stdio.h>     /* for NULL */
+#include <stdlib.h>
+
+#if HAVE_FLOAT_H
+#include <float.h>     /* for DBL_MAX_10_EXP etc */
+#endif
+
+#if HAVE_INTTYPES_H
+# include <inttypes.h> /* for intmax_t */
+#else
+# if HAVE_STDINT_H
+#  include <stdint.h>
+# endif
+#endif
+
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h> /* for quad_t */
+#endif
+
+#include "gmp-impl.h"
+
+
+#if ! HAVE_VSNPRINTF   /* only need this file if we don't have vsnprintf */
+
+/* Autoconf notes that AIX 4.3 has a broken strnlen, but fortunately it
+   doesn't affect us since __gmp_replacement_vsnprintf is not required on
+   that system.  */
+#if ! HAVE_STRNLEN
+static size_t
+strnlen (const char *s, size_t n)
+{
+  size_t  i;
+  for (i = 0; i < n; i++)
+    if (s[i] == '\0')
+      break;
+  return i;
+}
+#endif
+
+
+/* The approach here is to parse the fmt string, and decide how much space
+   it requires, then use vsprintf into a big enough buffer.  The space
+   calculated isn't an exact amount, but it's certainly no less than
+   required.
+
+   This code was inspired by GNU libiberty/vasprintf.c but we support more
+   datatypes, when available.
+
+   mingw32 - doesn't have vsnprintf, it seems.  Because gcc is used a full
+       set of types are available, but "long double" is just a plain IEEE
+       64-bit "double" and LDBL_MAX_EXP_10 is correspondingly defined, so we
+       avoid the big 15-bit exponent estimate.  */
+
+int
+__gmp_replacement_vsnprintf (char *buf, size_t buf_size,
+			     const char *orig_fmt, va_list orig_ap)
+{
+  va_list     ap;
+  const char  *fmt;
+  size_t      total_width, integer_sizeof, floating_sizeof, len;
+  char        fchar, type;
+  int         width, prec, seen_prec, double_digits, long_double_digits;
+  int         *value;
+
+  /* preserve orig_ap for use after size estimation */
+  va_copy (ap, orig_ap);
+
+  fmt = orig_fmt;
+  total_width = strlen (fmt) + 1;   /* 1 extra for the '\0' */
+
+  integer_sizeof = sizeof (long);
+#if HAVE_LONG_LONG
+  integer_sizeof = MAX (integer_sizeof, sizeof (long long));
+#endif
+#if HAVE_QUAD_T
+  integer_sizeof = MAX (integer_sizeof, sizeof (quad_t));
+#endif
+
+  floating_sizeof = sizeof (double);
+#if HAVE_LONG_DOUBLE
+  floating_sizeof = MAX (floating_sizeof, sizeof (long double));
+#endif
+
+  /* IEEE double or VAX G floats have an 11 bit exponent, so the default is
+     a maximum 308 decimal digits.  VAX D floats have only an 8 bit
+     exponent, but we don't bother trying to detect that directly.  */
+  double_digits = 308;
+#ifdef DBL_MAX_10_EXP
+  /* but in any case prefer a value the compiler says */
+  double_digits = DBL_MAX_10_EXP;
+#endif
+
+  /* IEEE 128-bit quad, Intel 80-bit temporary, or VAX H floats all have 15
+     bit exponents, so the default is a maximum 4932 decimal digits.  */
+  long_double_digits = 4932;
+  /* but if double == long double, then go with that size */
+#if HAVE_LONG_DOUBLE
+  if (sizeof (double) == sizeof (long double))
+    long_double_digits = double_digits;
+#endif
+#ifdef LDBL_MAX_10_EXP
+  /* but in any case prefer a value the compiler says */
+  long_double_digits = LDBL_MAX_10_EXP;
+#endif
+
+  for (;;)
+    {
+      fmt = strchr (fmt, '%');
+      if (fmt == NULL)
+	break;
+      fmt++;
+
+      type = '\0';
+      width = 0;
+      prec = 6;
+      seen_prec = 0;
+      value = &width;
+
+      for (;;)
+	{
+	  fchar = *fmt++;
+	  switch (fchar) {
+
+	  case 'c':
+	    /* char, already accounted for by strlen(fmt) */
+	    goto next;
+
+	  case 'd':
+	  case 'i':
+	  case 'o':
+	  case 'x':
+	  case 'X':
+	  case 'u':
+	    /* at most 3 digits per byte in hex, dec or octal, plus a sign */
+	    total_width += 3 * integer_sizeof + 1;
+
+	    switch (type) {
+	    case 'j':
+	      /* Let's assume uintmax_t is the same size as intmax_t. */
+#if HAVE_INTMAX_T
+	      (void) va_arg (ap, intmax_t);
+#else
+	      ASSERT_FAIL (intmax_t not available);
+#endif
+	      break;
+	    case 'l':
+	      (void) va_arg (ap, long);
+	      break;
+	    case 'L':
+#if HAVE_LONG_LONG
+	      (void) va_arg (ap, long long);
+#else
+	      ASSERT_FAIL (long long not available);
+#endif
+	      break;
+	    case 'q':
+	      /* quad_t is probably the same as long long, but let's treat
+		 it separately just to be sure.  Also let's assume u_quad_t
+		 will be the same size as quad_t.  */
+#if HAVE_QUAD_T
+	      (void) va_arg (ap, quad_t);
+#else
+	      ASSERT_FAIL (quad_t not available);
+#endif
+	      break;
+	    case 't':
+#if HAVE_PTRDIFF_T
+	      (void) va_arg (ap, ptrdiff_t);
+#else
+	      ASSERT_FAIL (ptrdiff_t not available);
+#endif
+	      break;
+	    case 'z':
+	      (void) va_arg (ap, size_t);
+	      break;
+	    default:
+	      /* default is an "int", and this includes h=short and hh=char
+		 since they're promoted to int in a function call */
+	      (void) va_arg (ap, int);
+	      break;
+	    }
+	    goto next;
+
+	  case 'E':
+	  case 'e':
+	  case 'G':
+	  case 'g':
+	    /* Requested decimals, sign, point and e, plus an overestimate
+	       of exponent digits (the assumption is all the float is
+	       exponent!).  */
+	    total_width += prec + 3 + floating_sizeof * 3;
+	    if (type == 'L')
+	      {
+#if HAVE_LONG_DOUBLE
+		(void) va_arg (ap, long double);
+#else
+		ASSERT_FAIL (long double not available);
+#endif
+	      }
+	    else
+	      (void) va_arg (ap, double);
+	    goto next;
+
+	  case 'f':
+	    /* Requested decimals, sign and point, and a margin for error,
+	       then add the maximum digits that can be in the integer part,
+	       based on the maximum exponent value. */
+	    total_width += prec + 2 + 10;
+	    if (type == 'L')
+	      {
+#if HAVE_LONG_DOUBLE
+		(void) va_arg (ap, long double);
+		total_width += long_double_digits;
+#else
+		ASSERT_FAIL (long double not available);
+#endif
+	      }
+	    else
+	      {
+		(void) va_arg (ap, double);
+		total_width += double_digits;
+	      }
+	    goto next;
+
+	  case 'h':  /* short or char */
+	  case 'j':  /* intmax_t */
+	  case 'L':  /* long long or long double */
+	  case 'q':  /* quad_t */
+	  case 't':  /* ptrdiff_t */
+	  case 'z':  /* size_t */
+	  set_type:
+	    type = fchar;
+	    break;
+
+	  case 'l':
+	    /* long or long long */
+	    if (type != 'l')
+	      goto set_type;
+	    type = 'L';   /* "ll" means "L" */
+	    break;
+
+	  case 'n':
+	    /* bytes written, no output as such */
+	    (void) va_arg (ap, void *);
+	    goto next;
+
+	  case 's':
+	    /* If no precision was given, then determine the string length
+	       and put it there, to be added to the total under "next".  If
+	       a precision was given then that's already the maximum from
+	       this field, but see whether the string is shorter than that,
+	       in case the limit was very big.  */
+	    {
+	      const char  *s = va_arg (ap, const char *);
+	      prec = (seen_prec ? strnlen (s, prec) : strlen (s));
+	    }
+	    goto next;
+
+	  case 'p':
+	    /* pointer, let's assume at worst it's octal with some padding */
+	    (void) va_arg (ap, const void *);
+	    total_width += 3 * sizeof (void *) + 16;
+	    goto next;
+
+	  case '%':
+	    /* literal %, already accounted for by strlen(fmt) */
+	    goto next;
+
+	  case '#':
+	    /* showbase, at most 2 for "0x" */
+	    total_width += 2;
+	    break;
+
+	  case '+':
+	  case ' ':
+	    /* sign, already accounted for under numerics */
+	    break;
+
+	  case '-':
+	    /* left justify, no effect on total width */
+	    break;
+
+	  case '.':
+	    seen_prec = 1;
+	    value = &prec;
+	    break;
+
+	  case '*':
+	    {
+	      /* negative width means left justify which can be ignored,
+		 negative prec would be invalid, just use absolute value */
+	      int n = va_arg (ap, int);
+	      *value = ABS (n);
+	    }
+	    break;
+
+	  case '0': case '1': case '2': case '3': case '4':
+	  case '5': case '6': case '7': case '8': case '9':
+	    /* process all digits to form a value */
+	    {
+	      int  n = 0;
+	      do {
+		n = n * 10 + (fchar-'0');
+		fchar = *fmt++;
+	      } while (isascii (fchar) && isdigit (fchar));
+	      fmt--; /* unget the non-digit */
+	      *value = n;
+	    }
+	    break;
+
+	  default:
+	    /* incomplete or invalid % sequence */
+	    ASSERT (0);
+	    goto next;
+	  }
+	}
+
+    next:
+      total_width += width;
+      total_width += prec;
+    }
+
+  if (total_width <= buf_size)
+    {
+      vsprintf (buf, orig_fmt, orig_ap);
+      len = strlen (buf);
+    }
+  else
+    {
+      char  *s;
+
+      s = __GMP_ALLOCATE_FUNC_TYPE (total_width, char);
+      vsprintf (s, orig_fmt, orig_ap);
+      len = strlen (s);
+      if (buf_size != 0)
+	{
+	  size_t  copylen = MIN (len, buf_size-1);
+	  memcpy (buf, s, copylen);
+	  buf[copylen] = '\0';
+	}
+      __GMP_FREE_FUNC_TYPE (s, total_width, char);
+    }
+
+  /* If total_width was somehow wrong then chances are we've already
+     clobbered memory, but maybe this check will still work.  */
+  ASSERT_ALWAYS (len < total_width);
+
+  return len;
+}
+
+#endif /* ! HAVE_VSNPRINTF */
diff --git a/third_party/gmp/printf/snprintf.c b/third_party/gmp/printf/snprintf.c
new file mode 100644
index 0000000..8da33f8
--- /dev/null
+++ b/third_party/gmp/printf/snprintf.c
@@ -0,0 +1,53 @@
+/* gmp_snprintf -- formatted output to an fixed size buffer.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+#include <string.h>    /* for strlen */
+
+#include "gmp-impl.h"
+
+
+int
+gmp_snprintf (char *buf, size_t size, const char *fmt, ...)
+{
+  struct gmp_snprintf_t d;
+  va_list  ap;
+  int      ret;
+
+  va_start (ap, fmt);
+  d.buf = buf;
+  d.size = size;
+
+  ASSERT (! MEM_OVERLAP_P (buf, size, fmt, strlen(fmt)+1));
+
+  ret = __gmp_doprnt (&__gmp_snprintf_funs, &d, fmt, ap);
+  va_end (ap);
+  return ret;
+}
diff --git a/third_party/gmp/printf/snprntffuns.c b/third_party/gmp/printf/snprntffuns.c
new file mode 100644
index 0000000..885c7ab
--- /dev/null
+++ b/third_party/gmp/printf/snprntffuns.c
@@ -0,0 +1,157 @@
+/* __gmp_snprintf_funs -- support for gmp_snprintf and gmp_vsnprintf.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2001, 2002, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "gmp-impl.h"
+
+
+#if ! HAVE_VSNPRINTF
+#define vsnprintf  __gmp_replacement_vsnprintf
+#endif
+
+
+/* glibc 2.0.x vsnprintf returns either -1 or size-1 for an overflow, with
+   no indication how big the output would have been.  It's necessary to
+   re-run to determine that size.
+
+   "size-1" would mean success from a C99 vsnprintf, and the re-run is
+   unnecessary in this case, but we don't bother to try to detect what sort
+   of vsnprintf we've got.  size-1 should occur rarely in normal
+   circumstances.
+
+   vsnprintf might trash it's given ap (it does for instance in glibc 2.1.3
+   on powerpc), so copy it in case we need to use it to probe for the size
+   output that would have been produced.  Note there's no need to preserve
+   it for our callers, just for ourselves.  */
+
+static int
+gmp_snprintf_format (struct gmp_snprintf_t *d, const char *fmt,
+                     va_list orig_ap)
+{
+  int      ret;
+  size_t   step, alloc, avail;
+  va_list  ap;
+  char     *p;
+
+  ASSERT (d->size >= 0);
+
+  avail = d->size;
+  if (avail > 1)
+    {
+      va_copy (ap, orig_ap);
+      ret = vsnprintf (d->buf, avail, fmt, ap);
+      if (ret == -1)
+        return ret;
+
+      step = MIN (ret, avail-1);
+      d->size -= step;
+      d->buf += step;
+
+      if (ret != avail-1)
+        return ret;
+
+      /* probably glibc 2.0.x truncated output, probe for actual size */
+      alloc = MAX (128, ret);
+    }
+  else
+    {
+      /* no space to write anything, just probe for size */
+      alloc = 128;
+    }
+
+  do
+    {
+      alloc *= 2;
+      p = __GMP_ALLOCATE_FUNC_TYPE (alloc, char);
+      va_copy (ap, orig_ap);
+      ret = vsnprintf (p, alloc, fmt, ap);
+      __GMP_FREE_FUNC_TYPE (p, alloc, char);
+    }
+  while (ret == alloc-1);
+
+  return ret;
+}
+
+static int
+gmp_snprintf_memory (struct gmp_snprintf_t *d, const char *str, size_t len)
+{
+  size_t n;
+
+  ASSERT (d->size >= 0);
+
+  if (d->size > 1)
+    {
+      n = MIN (d->size-1, len);
+      memcpy (d->buf, str, n);
+      d->buf += n;
+      d->size -= n;
+    }
+  return len;
+}
+
+static int
+gmp_snprintf_reps (struct gmp_snprintf_t *d, int c, int reps)
+{
+  size_t n;
+
+  ASSERT (reps >= 0);
+  ASSERT (d->size >= 0);
+
+  if (d->size > 1)
+    {
+      n = MIN (d->size-1, reps);
+      memset (d->buf, c, n);
+      d->buf += n;
+      d->size -= n;
+    }
+  return reps;
+}
+
+static int
+gmp_snprintf_final (struct gmp_snprintf_t *d)
+{
+  if (d->size >= 1)
+    d->buf[0] = '\0';
+  return 0;
+}
+
+const struct doprnt_funs_t  __gmp_snprintf_funs = {
+  (doprnt_format_t) gmp_snprintf_format,
+  (doprnt_memory_t) gmp_snprintf_memory,
+  (doprnt_reps_t)   gmp_snprintf_reps,
+  (doprnt_final_t)  gmp_snprintf_final
+};
diff --git a/third_party/gmp/printf/sprintf.c b/third_party/gmp/printf/sprintf.c
new file mode 100644
index 0000000..0952a53
--- /dev/null
+++ b/third_party/gmp/printf/sprintf.c
@@ -0,0 +1,54 @@
+/* gmp_sprintf -- formatted output to an unrestricted string.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+#include <string.h>    /* for strlen */
+
+#include "gmp-impl.h"
+
+
+int
+gmp_sprintf (char *buf, const char *fmt, ...)
+{
+#if WANT_ASSERT
+  int      fmtlen = strlen(fmt);
+#endif
+  va_list  ap;
+  int      ret;
+
+  va_start (ap, fmt);
+
+  ret = __gmp_doprnt (&__gmp_sprintf_funs, &buf, fmt, ap);
+  va_end (ap);
+
+  ASSERT (! MEM_OVERLAP_P (buf, strlen(buf)+1, fmt, fmtlen+1));
+
+  return ret;
+}
diff --git a/third_party/gmp/printf/sprintffuns.c b/third_party/gmp/printf/sprintffuns.c
new file mode 100644
index 0000000..6781f25
--- /dev/null
+++ b/third_party/gmp/printf/sprintffuns.c
@@ -0,0 +1,94 @@
+/* __gmp_sprintf_funs -- support for gmp_sprintf and gmp_vsprintf.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gmp-impl.h"
+
+
+/* The data parameter "bufp" points to a "char *buf" which is the next
+   character to be written, having started as the destination from the
+   application.  This is then increased each time output is produced.  */
+
+
+/* If vsprintf returns -1 then pass it upwards.  It doesn't matter that
+   "*bufp" is ruined in this case, since gmp_doprint will bail out
+   immediately anyway.  */
+static int
+gmp_sprintf_format (char **bufp, const char *fmt, va_list ap)
+{
+  char  *buf = *bufp;
+  int   ret;
+  vsprintf (buf, fmt, ap);
+  ret = strlen (buf);
+  *bufp = buf + ret;
+  return ret;
+}
+
+static int
+gmp_sprintf_memory (char **bufp, const char *str, size_t len)
+{
+  char  *buf = *bufp;
+  *bufp = buf + len;
+  memcpy (buf, str, len);
+  return len;
+}
+
+static int
+gmp_sprintf_reps (char **bufp, int c, int reps)
+{
+  char  *buf = *bufp;
+  ASSERT (reps >= 0);
+  *bufp = buf + reps;
+  memset (buf, c, reps);
+  return reps;
+}
+
+static int
+gmp_sprintf_final (char **bufp)
+{
+  char  *buf = *bufp;
+  *buf = '\0';
+  return 0;
+}
+
+const struct doprnt_funs_t  __gmp_sprintf_funs = {
+  (doprnt_format_t) gmp_sprintf_format,
+  (doprnt_memory_t) gmp_sprintf_memory,
+  (doprnt_reps_t)   gmp_sprintf_reps,
+  (doprnt_final_t)  gmp_sprintf_final
+};
diff --git a/third_party/gmp/printf/vasprintf.c b/third_party/gmp/printf/vasprintf.c
new file mode 100644
index 0000000..8a29a12
--- /dev/null
+++ b/third_party/gmp/printf/vasprintf.c
@@ -0,0 +1,116 @@
+/* gmp_vasprintf -- formatted output to an allocated space.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gmp-impl.h"
+
+#if ! HAVE_VSNPRINTF
+#define vsnprintf  __gmp_replacement_vsnprintf
+#endif
+
+
+/* vasprintf isn't used since we prefer all GMP allocs to go through
+   __gmp_allocate_func, and in particular we don't want the -1 return from
+   vasprintf for out-of-memory, instead __gmp_allocate_func should handle
+   that.  Using vsnprintf unfortunately means we might have to re-run it if
+   our current space is insufficient.
+
+   The initial guess for the needed space is an arbitrary 256 bytes.  If
+   that (and any extra GMP_ASPRINTF_T_NEED might give) isn't enough then an
+   ISO C99 standard vsnprintf will tell us what we really need.
+
+   GLIBC 2.0.x vsnprintf returns either -1 or space-1 to indicate overflow,
+   without giving any indication how much is really needed.  In this case
+   keep trying with double the space each time.
+
+   A return of space-1 is success on a C99 vsnprintf, but we're not
+   bothering to identify which style vsnprintf we've got, so just take the
+   pessimistic option and assume it's glibc 2.0.x.
+
+   Notice the use of ret+2 for the new space in the C99 case.  This ensures
+   the next vsnprintf return value will be space-2, which is unambiguously
+   successful.  But actually GMP_ASPRINTF_T_NEED() will realloc to even
+   bigger than that ret+2.
+
+   vsnprintf might trash it's given ap, so copy it in case we need to use it
+   more than once.  See comments with gmp_snprintf_format.  */
+
+static int
+gmp_asprintf_format (struct gmp_asprintf_t *d, const char *fmt,
+                     va_list orig_ap)
+{
+  int      ret;
+  va_list  ap;
+  size_t   space = 256;
+
+  for (;;)
+    {
+      GMP_ASPRINTF_T_NEED (d, space);
+      space = d->alloc - d->size;
+      va_copy (ap, orig_ap);
+      ret = vsnprintf (d->buf + d->size, space, fmt, ap);
+      if (ret == -1)
+        {
+          ASSERT (strlen (d->buf + d->size) == space-1);
+          ret = space-1;
+        }
+
+      /* done if output fits in our space */
+      if (ret < space-1)
+        break;
+
+      if (ret == space-1)
+        space *= 2;     /* possible glibc 2.0.x, so double */
+      else
+        space = ret+2;  /* C99, so now know space required */
+    }
+
+  d->size += ret;
+  return ret;
+}
+
+const struct doprnt_funs_t  __gmp_asprintf_funs = {
+  (doprnt_format_t) gmp_asprintf_format,
+  (doprnt_memory_t) __gmp_asprintf_memory,
+  (doprnt_reps_t)   __gmp_asprintf_reps,
+  (doprnt_final_t)  __gmp_asprintf_final
+};
+
+int
+gmp_vasprintf (char **result, const char *fmt, va_list ap)
+{
+  struct gmp_asprintf_t  d;
+  GMP_ASPRINTF_T_INIT (d, result);
+  return __gmp_doprnt (&__gmp_asprintf_funs, &d, fmt, ap);
+}
diff --git a/third_party/gmp/printf/vfprintf.c b/third_party/gmp/printf/vfprintf.c
new file mode 100644
index 0000000..b2d1906
--- /dev/null
+++ b/third_party/gmp/printf/vfprintf.c
@@ -0,0 +1,41 @@
+/* gmp_vfprintf -- formatted output.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "gmp-impl.h"
+
+
+int
+gmp_vfprintf (FILE *fp, const char *fmt, va_list ap)
+{
+  return __gmp_doprnt (&__gmp_fprintf_funs, fp, fmt, ap);
+}
diff --git a/third_party/gmp/printf/vprintf.c b/third_party/gmp/printf/vprintf.c
new file mode 100644
index 0000000..60a2233
--- /dev/null
+++ b/third_party/gmp/printf/vprintf.c
@@ -0,0 +1,41 @@
+/* gmp_vprintf -- formatted output.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "gmp-impl.h"
+
+
+int
+gmp_vprintf (const char *fmt, va_list ap)
+{
+  return __gmp_doprnt (&__gmp_fprintf_funs, stdout, fmt, ap);
+}
diff --git a/third_party/gmp/printf/vsnprintf.c b/third_party/gmp/printf/vsnprintf.c
new file mode 100644
index 0000000..2432f5d
--- /dev/null
+++ b/third_party/gmp/printf/vsnprintf.c
@@ -0,0 +1,47 @@
+/* gmp_vsnprintf -- formatted output to an fixed size buffer.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+#include <string.h>    /* for strlen */
+
+#include "gmp-impl.h"
+
+
+int
+gmp_vsnprintf (char *buf, size_t size, const char *fmt, va_list ap)
+{
+  struct gmp_snprintf_t d;
+
+  ASSERT (! MEM_OVERLAP_P (buf, size, fmt, strlen(fmt)+1));
+
+  d.buf = buf;
+  d.size = size;
+  return __gmp_doprnt (&__gmp_snprintf_funs, &d, fmt, ap);
+}
diff --git a/third_party/gmp/printf/vsprintf.c b/third_party/gmp/printf/vsprintf.c
new file mode 100644
index 0000000..26de193
--- /dev/null
+++ b/third_party/gmp/printf/vsprintf.c
@@ -0,0 +1,50 @@
+/* gmp_vsprintf -- formatted output to an unrestricted string.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+#include <string.h>    /* for strlen */
+
+#include "gmp-impl.h"
+
+
+int
+gmp_vsprintf (char *buf, const char *fmt, va_list ap)
+{
+#if WANT_ASSERT
+  int  fmtlen = strlen(fmt);
+#endif
+  int  ret;
+
+  ret = __gmp_doprnt (&__gmp_sprintf_funs, &buf, fmt, ap);
+
+  ASSERT (! MEM_OVERLAP_P (buf, strlen(buf)+1, fmt, fmtlen+1));
+
+  return ret;
+}
diff --git a/third_party/gmp/rand/Makefile.am b/third_party/gmp/rand/Makefile.am
new file mode 100644
index 0000000..b3b98c0
--- /dev/null
+++ b/third_party/gmp/rand/Makefile.am
@@ -0,0 +1,38 @@
+## Process this file with automake to generate Makefile.in
+
+# Copyright 2001, 2002, 2010 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+
+AM_CPPFLAGS = -D__GMP_WITHIN_GMP -I$(top_srcdir)
+
+noinst_LTLIBRARIES = librandom.la
+
+librandom_la_SOURCES = randmt.h						\
+  rand.c randclr.c randdef.c randiset.c randlc2s.c randlc2x.c randmt.c	\
+  randmts.c rands.c randsd.c randsdui.c randbui.c randmui.c
diff --git a/third_party/gmp/rand/Makefile.in b/third_party/gmp/rand/Makefile.in
new file mode 100644
index 0000000..52cb75a
--- /dev/null
+++ b/third_party/gmp/rand/Makefile.in
@@ -0,0 +1,643 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Copyright 2001, 2002, 2010 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = rand
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+librandom_la_LIBADD =
+am_librandom_la_OBJECTS = rand.lo randclr.lo randdef.lo randiset.lo \
+	randlc2s.lo randlc2x.lo randmt.lo randmts.lo rands.lo \
+	randsd.lo randsdui.lo randbui.lo randmui.lo
+librandom_la_OBJECTS = $(am_librandom_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp =
+am__depfiles_maybe =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+SOURCES = $(librandom_la_SOURCES)
+DIST_SOURCES = $(librandom_la_SOURCES)
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ABI = @ABI@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+ASMFLAGS = @ASMFLAGS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CALLING_CONVENTIONS_OBJS = @CALLING_CONVENTIONS_OBJS@
+CC = @CC@
+CCAS = @CCAS@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPP_FOR_BUILD = @CPP_FOR_BUILD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFN_LONG_LONG_LIMB = @DEFN_LONG_LONG_LIMB@
+DEFS = @DEFS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@
+FGREP = @FGREP@
+GMP_LDFLAGS = @GMP_LDFLAGS@
+GMP_LIMB_BITS = @GMP_LIMB_BITS@
+GMP_NAIL_BITS = @GMP_NAIL_BITS@
+GREP = @GREP@
+HAVE_CLOCK_01 = @HAVE_CLOCK_01@
+HAVE_CPUTIME_01 = @HAVE_CPUTIME_01@
+HAVE_GETRUSAGE_01 = @HAVE_GETRUSAGE_01@
+HAVE_GETTIMEOFDAY_01 = @HAVE_GETTIMEOFDAY_01@
+HAVE_HOST_CPU_FAMILY_power = @HAVE_HOST_CPU_FAMILY_power@
+HAVE_HOST_CPU_FAMILY_powerpc = @HAVE_HOST_CPU_FAMILY_powerpc@
+HAVE_SIGACTION_01 = @HAVE_SIGACTION_01@
+HAVE_SIGALTSTACK_01 = @HAVE_SIGALTSTACK_01@
+HAVE_SIGSTACK_01 = @HAVE_SIGSTACK_01@
+HAVE_STACK_T_01 = @HAVE_STACK_T_01@
+HAVE_SYS_RESOURCE_H_01 = @HAVE_SYS_RESOURCE_H_01@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCURSES = @LIBCURSES@
+LIBGMPXX_LDFLAGS = @LIBGMPXX_LDFLAGS@
+LIBGMP_DLL = @LIBGMP_DLL@
+LIBGMP_LDFLAGS = @LIBGMP_LDFLAGS@
+LIBM = @LIBM@
+LIBM_FOR_BUILD = @LIBM_FOR_BUILD@
+LIBOBJS = @LIBOBJS@
+LIBREADLINE = @LIBREADLINE@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+M4 = @M4@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPEED_CYCLECOUNTER_OBJ = @SPEED_CYCLECOUNTER_OBJ@
+STRIP = @STRIP@
+TAL_OBJECT = @TAL_OBJECT@
+TUNE_LIBS = @TUNE_LIBS@
+TUNE_SQR_OBJ = @TUNE_SQR_OBJ@
+U_FOR_BUILD = @U_FOR_BUILD@
+VERSION = @VERSION@
+WITH_READLINE_01 = @WITH_READLINE_01@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__leading_dot = @am__leading_dot@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gmp_srclinks = @gmp_srclinks@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+mpn_objects = @mpn_objects@
+mpn_objs_in_libgmp = @mpn_objs_in_libgmp@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_CPPFLAGS = -D__GMP_WITHIN_GMP -I$(top_srcdir)
+noinst_LTLIBRARIES = librandom.la
+librandom_la_SOURCES = randmt.h						\
+  rand.c randclr.c randdef.c randiset.c randlc2s.c randlc2x.c randmt.c	\
+  randmts.c rands.c randsd.c randsdui.c randbui.c randmui.c
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu --ignore-deps rand/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu --ignore-deps rand/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+	@list='$(noinst_LTLIBRARIES)'; \
+	locs=`for p in $$list; do echo $$p; done | \
+	      sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+	      sort -u`; \
+	test -z "$$locs" || { \
+	  echo rm -f $${locs}; \
+	  rm -f $${locs}; \
+	}
+
+librandom.la: $(librandom_la_OBJECTS) $(librandom_la_DEPENDENCIES) $(EXTRA_librandom_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(LINK)  $(librandom_la_OBJECTS) $(librandom_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+.c.o:
+	$(AM_V_CC)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+	$(AM_V_CC)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+	$(AM_V_CC)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+	clean-libtool clean-noinstLTLIBRARIES cscopelist-am ctags \
+	ctags-am distclean distclean-compile distclean-generic \
+	distclean-libtool distclean-tags distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-dvi install-dvi-am install-exec \
+	install-exec-am install-html install-html-am install-info \
+	install-info-am install-man install-pdf install-pdf-am \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/third_party/gmp/rand/rand.c b/third_party/gmp/rand/rand.c
new file mode 100644
index 0000000..418b3de
--- /dev/null
+++ b/third_party/gmp/rand/rand.c
@@ -0,0 +1,51 @@
+/* gmp_randinit (state, algorithm, ...) -- Initialize a random state.
+
+Copyright 1999-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+
+#include "gmp-impl.h"
+
+void
+gmp_randinit (gmp_randstate_t rstate, gmp_randalg_t alg, ...)
+{
+  va_list ap;
+  va_start (ap, alg);
+
+  switch (alg) {
+  case GMP_RAND_ALG_LC:
+    if (! gmp_randinit_lc_2exp_size (rstate, va_arg (ap, unsigned long)))
+      gmp_errno |= GMP_ERROR_INVALID_ARGUMENT;
+    break;
+  default:
+    gmp_errno |= GMP_ERROR_UNSUPPORTED_ARGUMENT;
+    break;
+  }
+  va_end (ap);
+}
diff --git a/third_party/gmp/rand/randbui.c b/third_party/gmp/rand/randbui.c
new file mode 100644
index 0000000..de9e95b
--- /dev/null
+++ b/third_party/gmp/rand/randbui.c
@@ -0,0 +1,56 @@
+/* gmp_urandomb_ui -- random bits returned in a ulong.
+
+Copyright 2003, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* Currently bits>=BITS_PER_ULONG is quietly truncated to BITS_PER_ULONG,
+   maybe this should raise an exception or something.  */
+
+unsigned long
+gmp_urandomb_ui (gmp_randstate_ptr rstate, unsigned long bits)
+{
+  mp_limb_t  a[LIMBS_PER_ULONG];
+
+  /* start with zeros, since if bits==0 then _gmp_rand will store nothing at
+     all, or if bits <= GMP_NUMB_BITS then it will store only a[0] */
+  a[0] = 0;
+#if LIMBS_PER_ULONG > 1
+  a[1] = 0;
+#endif
+
+  _gmp_rand (a, rstate, MIN (bits, BITS_PER_ULONG));
+
+#if LIMBS_PER_ULONG == 1
+  return a[0];
+#else
+  return a[0] | (a[1] << GMP_NUMB_BITS);
+#endif
+}
diff --git a/third_party/gmp/rand/randclr.c b/third_party/gmp/rand/randclr.c
new file mode 100644
index 0000000..5603ed7
--- /dev/null
+++ b/third_party/gmp/rand/randclr.c
@@ -0,0 +1,37 @@
+/* gmp_randclear (state) -- Clear and deallocate random state STATE.
+
+Copyright 1999-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+gmp_randclear (gmp_randstate_t rstate)
+{
+  (*((gmp_randfnptr_t *) RNG_FNPTR (rstate))->randclear_fn) (rstate);
+}
diff --git a/third_party/gmp/rand/randdef.c b/third_party/gmp/rand/randdef.c
new file mode 100644
index 0000000..a8a1792
--- /dev/null
+++ b/third_party/gmp/rand/randdef.c
@@ -0,0 +1,37 @@
+/* gmp_randinit_default -- initialize a random state with a default algorithm.
+
+Copyright 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+gmp_randinit_default (gmp_randstate_t rstate)
+{
+  gmp_randinit_mt (rstate);
+}
diff --git a/third_party/gmp/rand/randiset.c b/third_party/gmp/rand/randiset.c
new file mode 100644
index 0000000..11b5b97
--- /dev/null
+++ b/third_party/gmp/rand/randiset.c
@@ -0,0 +1,38 @@
+/* gmp_randinit_set -- initialize with a copy of another gmp_randstate_t.
+
+Copyright 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+void
+gmp_randinit_set (gmp_randstate_ptr dst, gmp_randstate_srcptr src)
+{
+  (*((gmp_randfnptr_t *) RNG_FNPTR (src))->randiset_fn) (dst, src);
+}
diff --git a/third_party/gmp/rand/randlc2s.c b/third_party/gmp/rand/randlc2s.c
new file mode 100644
index 0000000..42ed8c4
--- /dev/null
+++ b/third_party/gmp/rand/randlc2s.c
@@ -0,0 +1,92 @@
+/* gmp_randinit_lc_2exp_size -- initialize a random state with a linear
+   congruential generator of a requested size.
+
+Copyright 1999-2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h> /* for NULL */
+#include "gmp-impl.h"
+
+
+/* Array of LC-schemes, ordered in increasing order of the first
+   member (the 'm2exp' value).  The end of the array is indicated with
+   an entry containing all zeros.  */
+
+/* All multipliers are in the range 0.01*m and 0.99*m, and are
+congruent to 5 (mod 8).
+They all pass the spectral test with Vt >= 2^(30/t) and merit >= 1.
+(Up to and including 196 bits, merit is >= 3.)  */
+
+struct __gmp_rand_lc_scheme_struct
+{
+  unsigned long int m2exp;	/* Modulus is 2 ^ m2exp. */
+  const char *astr;		/* Multiplier in string form. */
+  unsigned long int c;		/* Addend. */
+};
+
+static const struct __gmp_rand_lc_scheme_struct __gmp_rand_lc_scheme[] =
+{
+  {32, "29CF535",	     1},
+  {33, "51F666D",	     1},
+  {34, "A3D73AD",	     1},
+  {35, "147E5B85",	     1},
+  {36, "28F725C5",	     1},
+  {37, "51EE3105",	     1},
+  {38, "A3DD5CDD",	     1},
+  {39, "147AF833D",	     1},
+  {40, "28F5DA175",	     1},
+  {56, "AA7D735234C0DD",  1},
+  {64, "BAECD515DAF0B49D", 1},
+  {100, "292787EBD3329AD7E7575E2FD", 1},
+  {128, "48A74F367FA7B5C8ACBB36901308FA85", 1},
+  {156, "78A7FDDDC43611B527C3F1D760F36E5D7FC7C45", 1},
+  {196, "41BA2E104EE34C66B3520CE706A56498DE6D44721E5E24F5", 1},
+  {200, "4E5A24C38B981EAFE84CD9D0BEC48E83911362C114F30072C5", 1},
+  {256, "AF66BA932AAF58A071FD8F0742A99A0C76982D648509973DB802303128A14CB5", 1},
+  {0, NULL, 0}			/* End of array. */
+};
+
+int
+gmp_randinit_lc_2exp_size (gmp_randstate_t rstate, mp_bitcnt_t size)
+{
+  const struct __gmp_rand_lc_scheme_struct *sp;
+  mpz_t a;
+
+  /* Pick a scheme.  */
+  for (sp = __gmp_rand_lc_scheme; sp->m2exp != 0; sp++)
+    if (sp->m2exp / 2 >= size)
+      goto found;
+  return 0;
+
+ found:
+  /* Install scheme.  */
+  mpz_init_set_str (a, sp->astr, 16);
+  gmp_randinit_lc_2exp (rstate, a, sp->c, sp->m2exp);
+  mpz_clear (a);
+  return 1;
+}
diff --git a/third_party/gmp/rand/randlc2x.c b/third_party/gmp/rand/randlc2x.c
new file mode 100644
index 0000000..4c03eb4
--- /dev/null
+++ b/third_party/gmp/rand/randlc2x.c
@@ -0,0 +1,332 @@
+/* Linear Congruential pseudo-random number generator functions.
+
+Copyright 1999-2003, 2005, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* State structure for LC, the RNG_STATE() pointer in a gmp_randstate_t.
+
+   _mp_seed holds the current seed value, in the range 0 to 2^m2exp-1.
+   SIZ(_mp_seed) is fixed at BITS_TO_LIMBS(_mp_m2exp) and the value is
+   padded with high zero limbs if necessary.  ALLOC(_mp_seed) is the current
+   size of PTR(_mp_seed) in the usual way.  There only needs to be
+   BITS_TO_LIMBS(_mp_m2exp) allocated, but the mpz functions in the
+   initialization and seeding end up making it a bit more than this.
+
+   _mp_a is the "a" multiplier, in the range 0 to 2^m2exp-1.  SIZ(_mp_a) is
+   the size of the value in the normal way for an mpz_t, except that a value
+   of zero is held with SIZ(_mp_a)==1 and PTR(_mp_a)[0]==0.  This makes it
+   easy to call mpn_mul, and the case of a==0 is highly un-random and not
+   worth any trouble to optimize.
+
+   {_cp,_cn} is the "c" addend.  Normally _cn is 1, but when nails are in
+   use a ulong can be bigger than one limb, and in this case _cn is 2 if
+   necessary.  c==0 is stored as _cp[0]==0 and _cn==1, which makes it easy
+   to call __GMPN_ADD.  c==0 is fairly un-random so isn't worth optimizing.
+
+   _mp_m2exp gives the modulus, namely 2^m2exp.  We demand m2exp>=1, since
+   m2exp==0 would mean no bits at all out of each iteration, which makes no
+   sense.  */
+
+typedef struct {
+  mpz_t          _mp_seed;
+  mpz_t          _mp_a;
+  mp_size_t      _cn;
+  mp_limb_t      _cp[LIMBS_PER_ULONG];
+  unsigned long  _mp_m2exp;
+} gmp_rand_lc_struct;
+
+
+/* lc (rp, state) -- Generate next number in LC sequence.  Return the
+   number of valid bits in the result.  Discards the lower half of the
+   result.  */
+
+static unsigned long int
+lc (mp_ptr rp, gmp_randstate_t rstate)
+{
+  mp_ptr tp, seedp, ap;
+  mp_size_t ta;
+  mp_size_t tn, seedn, an;
+  unsigned long int m2exp;
+  unsigned long int bits;
+  int cy;
+  mp_size_t xn;
+  gmp_rand_lc_struct *p;
+  TMP_DECL;
+
+  p = (gmp_rand_lc_struct *) RNG_STATE (rstate);
+
+  m2exp = p->_mp_m2exp;
+
+  seedp = PTR (p->_mp_seed);
+  seedn = SIZ (p->_mp_seed);
+
+  ap = PTR (p->_mp_a);
+  an = SIZ (p->_mp_a);
+
+  /* Allocate temporary storage.  Let there be room for calculation of
+     (A * seed + C) % M, or M if bigger than that.  */
+
+  TMP_MARK;
+
+  ta = an + seedn + 1;
+  tn = BITS_TO_LIMBS (m2exp);
+  if (ta <= tn) /* that is, if (ta < tn + 1) */
+    {
+      mp_size_t tmp = an + seedn;
+      ta = tn + 1;
+      tp = TMP_ALLOC_LIMBS (ta);
+      MPN_ZERO (&tp[tmp], ta - tmp); /* mpn_mul won't zero it out.  */
+    }
+  else
+    tp = TMP_ALLOC_LIMBS (ta);
+
+  /* t = a * seed.  NOTE: an is always > 0; see initialization.  */
+  ASSERT (seedn >= an && an > 0);
+  mpn_mul (tp, seedp, seedn, ap, an);
+
+  /* t = t + c.  NOTE: tn is always >= p->_cn (precondition for __GMPN_ADD);
+     see initialization.  */
+  ASSERT (tn >= p->_cn);
+  __GMPN_ADD (cy, tp, tp, tn, p->_cp, p->_cn);
+
+  /* t = t % m */
+  tp[m2exp / GMP_NUMB_BITS] &= (CNST_LIMB (1) << m2exp % GMP_NUMB_BITS) - 1;
+
+  /* Save result as next seed.  */
+  MPN_COPY (PTR (p->_mp_seed), tp, tn);
+
+  /* Discard the lower m2exp/2 of the result.  */
+  bits = m2exp / 2;
+  xn = bits / GMP_NUMB_BITS;
+
+  tn -= xn;
+  if (tn > 0)
+    {
+      unsigned int cnt = bits % GMP_NUMB_BITS;
+      if (cnt != 0)
+	{
+	  mpn_rshift (tp, tp + xn, tn, cnt);
+	  MPN_COPY_INCR (rp, tp, xn + 1);
+	}
+      else			/* Even limb boundary.  */
+	MPN_COPY_INCR (rp, tp + xn, tn);
+    }
+
+  TMP_FREE;
+
+  /* Return number of valid bits in the result.  */
+  return (m2exp + 1) / 2;
+}
+
+
+/* Obtain a sequence of random numbers.  */
+static void
+randget_lc (gmp_randstate_t rstate, mp_ptr rp, unsigned long int nbits)
+{
+  unsigned long int rbitpos;
+  int chunk_nbits;
+  mp_ptr tp;
+  mp_size_t tn;
+  gmp_rand_lc_struct *p;
+  TMP_DECL;
+
+  p = (gmp_rand_lc_struct *) RNG_STATE (rstate);
+
+  TMP_MARK;
+
+  chunk_nbits = p->_mp_m2exp / 2;
+  tn = BITS_TO_LIMBS (chunk_nbits);
+
+  tp = TMP_ALLOC_LIMBS (tn);
+
+  rbitpos = 0;
+  while (rbitpos + chunk_nbits <= nbits)
+    {
+      mp_ptr r2p = rp + rbitpos / GMP_NUMB_BITS;
+
+      if (rbitpos % GMP_NUMB_BITS != 0)
+	{
+	  mp_limb_t savelimb, rcy;
+	  /* Target of new chunk is not bit aligned.  Use temp space
+	     and align things by shifting it up.  */
+	  lc (tp, rstate);
+	  savelimb = r2p[0];
+	  rcy = mpn_lshift (r2p, tp, tn, rbitpos % GMP_NUMB_BITS);
+	  r2p[0] |= savelimb;
+	  /* bogus */
+	  if ((chunk_nbits % GMP_NUMB_BITS + rbitpos % GMP_NUMB_BITS)
+	      > GMP_NUMB_BITS)
+	    r2p[tn] = rcy;
+	}
+      else
+	{
+	  /* Target of new chunk is bit aligned.  Let `lc' put bits
+	     directly into our target variable.  */
+	  lc (r2p, rstate);
+	}
+      rbitpos += chunk_nbits;
+    }
+
+  /* Handle last [0..chunk_nbits) bits.  */
+  if (rbitpos != nbits)
+    {
+      mp_ptr r2p = rp + rbitpos / GMP_NUMB_BITS;
+      int last_nbits = nbits - rbitpos;
+      tn = BITS_TO_LIMBS (last_nbits);
+      lc (tp, rstate);
+      if (rbitpos % GMP_NUMB_BITS != 0)
+	{
+	  mp_limb_t savelimb, rcy;
+	  /* Target of new chunk is not bit aligned.  Use temp space
+	     and align things by shifting it up.  */
+	  savelimb = r2p[0];
+	  rcy = mpn_lshift (r2p, tp, tn, rbitpos % GMP_NUMB_BITS);
+	  r2p[0] |= savelimb;
+	  if (rbitpos + tn * GMP_NUMB_BITS - rbitpos % GMP_NUMB_BITS < nbits)
+	    r2p[tn] = rcy;
+	}
+      else
+	{
+	  MPN_COPY (r2p, tp, tn);
+	}
+      /* Mask off top bits if needed.  */
+      if (nbits % GMP_NUMB_BITS != 0)
+	rp[nbits / GMP_NUMB_BITS]
+	  &= ~(~CNST_LIMB (0) << nbits % GMP_NUMB_BITS);
+    }
+
+  TMP_FREE;
+}
+
+
+static void
+randseed_lc (gmp_randstate_t rstate, mpz_srcptr seed)
+{
+  gmp_rand_lc_struct *p = (gmp_rand_lc_struct *) RNG_STATE (rstate);
+  mpz_ptr seedz = p->_mp_seed;
+  mp_size_t seedn = BITS_TO_LIMBS (p->_mp_m2exp);
+
+  /* Store p->_mp_seed as an unnormalized integer with size enough
+     for numbers up to 2^m2exp-1.  That size can't be zero.  */
+  mpz_fdiv_r_2exp (seedz, seed, p->_mp_m2exp);
+  MPN_ZERO (&PTR (seedz)[SIZ (seedz)], seedn - SIZ (seedz));
+  SIZ (seedz) = seedn;
+}
+
+
+static void
+randclear_lc (gmp_randstate_t rstate)
+{
+  gmp_rand_lc_struct *p = (gmp_rand_lc_struct *) RNG_STATE (rstate);
+
+  mpz_clear (p->_mp_seed);
+  mpz_clear (p->_mp_a);
+  (*__gmp_free_func) (p, sizeof (gmp_rand_lc_struct));
+}
+
+static void randiset_lc (gmp_randstate_ptr, gmp_randstate_srcptr);
+
+static const gmp_randfnptr_t Linear_Congruential_Generator = {
+  randseed_lc,
+  randget_lc,
+  randclear_lc,
+  randiset_lc
+};
+
+static void
+randiset_lc (gmp_randstate_ptr dst, gmp_randstate_srcptr src)
+{
+  gmp_rand_lc_struct *dstp, *srcp;
+
+  srcp = (gmp_rand_lc_struct *) RNG_STATE (src);
+  dstp = (gmp_rand_lc_struct *) (*__gmp_allocate_func) (sizeof (gmp_rand_lc_struct));
+
+  RNG_STATE (dst) = (mp_limb_t *) (void *) dstp;
+  RNG_FNPTR (dst) = (void *) &Linear_Congruential_Generator;
+
+  /* _mp_seed and _mp_a might be unnormalized (high zero limbs), but
+     mpz_init_set won't worry about that */
+  mpz_init_set (dstp->_mp_seed, srcp->_mp_seed);
+  mpz_init_set (dstp->_mp_a,    srcp->_mp_a);
+
+  dstp->_cn = srcp->_cn;
+
+  dstp->_cp[0] = srcp->_cp[0];
+  if (LIMBS_PER_ULONG > 1)
+    dstp->_cp[1] = srcp->_cp[1];
+  if (LIMBS_PER_ULONG > 2)  /* usually there's only 1 or 2 */
+    MPN_COPY (dstp->_cp + 2, srcp->_cp + 2, LIMBS_PER_ULONG - 2);
+
+  dstp->_mp_m2exp = srcp->_mp_m2exp;
+}
+
+
+void
+gmp_randinit_lc_2exp (gmp_randstate_t rstate,
+		      mpz_srcptr a,
+		      unsigned long int c,
+		      mp_bitcnt_t m2exp)
+{
+  gmp_rand_lc_struct *p;
+  mp_size_t seedn = BITS_TO_LIMBS (m2exp);
+
+  ASSERT_ALWAYS (m2exp != 0);
+
+  p = __GMP_ALLOCATE_FUNC_TYPE (1, gmp_rand_lc_struct);
+  RNG_STATE (rstate) = (mp_limb_t *) (void *) p;
+  RNG_FNPTR (rstate) = (void *) &Linear_Congruential_Generator;
+
+  /* allocate m2exp bits of space for p->_mp_seed, and initial seed "1" */
+  mpz_init2 (p->_mp_seed, m2exp);
+  MPN_ZERO (PTR (p->_mp_seed), seedn);
+  SIZ (p->_mp_seed) = seedn;
+  PTR (p->_mp_seed)[0] = 1;
+
+  /* "a", forced to 0 to 2^m2exp-1 */
+  mpz_init (p->_mp_a);
+  mpz_fdiv_r_2exp (p->_mp_a, a, m2exp);
+
+  /* Avoid SIZ(a) == 0 to avoid checking for special case in lc().  */
+  if (SIZ (p->_mp_a) == 0)
+    {
+      SIZ (p->_mp_a) = 1;
+      MPZ_NEWALLOC (p->_mp_a, 1)[0] = CNST_LIMB (0);
+    }
+
+  MPN_SET_UI (p->_cp, p->_cn, c);
+
+  /* Internally we may discard any bits of c above m2exp.  The following
+     code ensures that __GMPN_ADD in lc() will always work.  */
+  if (seedn < p->_cn)
+    p->_cn = (p->_cp[0] != 0);
+
+  p->_mp_m2exp = m2exp;
+}
diff --git a/third_party/gmp/rand/randmt.c b/third_party/gmp/rand/randmt.c
new file mode 100644
index 0000000..a05e76a
--- /dev/null
+++ b/third_party/gmp/rand/randmt.c
@@ -0,0 +1,415 @@
+/* Mersenne Twister pseudo-random number generator functions.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2002, 2003, 2006 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>   /* for NULL */
+
+#include "gmp-impl.h"
+#include "randmt.h"
+
+
+/* This code implements the Mersenne Twister pseudorandom number generator
+   by Takuji Nishimura and Makoto Matsumoto.  The buffer initialization
+   function is different in order to permit seeds greater than 2^32-1.
+
+   This file contains a special __gmp_randinit_mt_noseed which excludes the
+   seeding function from the gmp_randfnptr_t routines.  This is for use by
+   mpn_random and mpn_random2 on the global random generator.  MT seeding
+   uses mpz functions, and we don't want mpn routines dragging mpz functions
+   into the link.  */
+
+
+/* Default seed to use when the generator is not initialized.  */
+#define DEFAULT_SEED 5489 /* was 4357 */
+
+/* Tempering masks.  */
+#define MASK_1 0x9D2C5680
+#define MASK_2 0xEFC60000
+
+/* Initial state of buffer when initialized with default seed.  */
+static const gmp_uint_least32_t default_state[N] =
+{
+  0xD247B233,0x9E5AA8F1,0x0FFA981B,0x9DCB0980,0x74200F2B,0xA576D044,
+  0xE9F05ADF,0x1538BFF5,0x59818BBF,0xCF9E58D8,0x09FCE032,0x6A1C663F,
+  0x5116E78A,0x69B3E0FA,0x6D92D665,0xD0A8BE98,0xF669B734,0x41AC1B68,
+  0x630423F1,0x4B8D6B8A,0xC2C46DD7,0x5680747D,0x43703E8F,0x3B6103D2,
+  0x49E5EB3F,0xCBDAB4C1,0x9C988E23,0x747BEE0B,0x9111E329,0x9F031B5A,
+  0xECCA71B9,0x2AFE4EF8,0x8421C7ED,0xAC89AFF1,0xAED90DF3,0x2DD74F01,
+  0x14906A13,0x75873FA9,0xFF83F877,0x5028A0C9,0x11B4C41D,0x7CAEDBC4,
+  0x8672D0A7,0x48A7C109,0x8320E59F,0xBC0B3D5F,0x75A30886,0xF9E0D128,
+  0x41AF7580,0x239BB94D,0xC67A3C81,0x74EEBD6E,0xBC02B53C,0x727EA449,
+  0x6B8A2806,0x5853B0DA,0xBDE032F4,0xCE234885,0x320D6145,0x48CC053F,
+  0x00DBC4D2,0xD55A2397,0xE1059B6F,0x1C3E05D1,0x09657C64,0xD07CB661,
+  0x6E982E34,0x6DD1D777,0xEDED1071,0xD79DFD65,0xF816DDCE,0xB6FAF1E4,
+  0x1C771074,0x311835BD,0x18F952F7,0xF8F40350,0x4ECED354,0x7C8AC12B,
+  0x31A9994D,0x4FD47747,0xDC227A23,0x6DFAFDDF,0x6796E748,0x0C6F634F,
+  0xF992FA1D,0x4CF670C9,0x067DFD31,0xA7A3E1A5,0x8CD7D9DF,0x972CCB34,
+  0x67C82156,0xD548F6A8,0x045CEC21,0xF3240BFB,0xDEF656A7,0x43DE08C5,
+  0xDAD1F92F,0x3726C56B,0x1409F19A,0x942FD147,0xB926749C,0xADDC31B8,
+  0x53D0D869,0xD1BA52FE,0x6722DF8C,0x22D95A74,0x7DC1B52A,0x1DEC6FD5,
+  0x7262874D,0x0A725DC9,0xE6A8193D,0xA052835A,0xDC9AD928,0xE59EBB90,
+  0x70DBA9FF,0xD612749D,0x5A5A638C,0x6086EC37,0x2A579709,0x1449EA3A,
+  0xBC8E3C06,0x2F900666,0xFBE74FD1,0x6B35B911,0xF8335008,0xEF1E979D,
+  0x738AB29D,0xA2DC0FDC,0x7696305D,0xF5429DAC,0x8C41813B,0x8073E02E,
+  0xBEF83CCD,0x7B50A95A,0x05EE5862,0x00829ECE,0x8CA1958C,0xBE4EA2E2,
+  0x4293BB73,0x656F7B23,0x417316D8,0x4467D7CF,0x2200E63B,0x109050C8,
+  0x814CBE47,0x36B1D4A8,0x36AF9305,0x308327B3,0xEBCD7344,0xA738DE27,
+  0x5A10C399,0x4142371D,0x64A18528,0x0B31E8B2,0x641057B9,0x6AFC363B,
+  0x108AD953,0x9D4DA234,0x0C2D9159,0x1C8A1A1F,0x310C66BA,0x87AA1070,
+  0xDAC832FF,0x0A433422,0x7AF15812,0x2D8D9BD0,0x995A25E9,0x25326CAC,
+  0xA34384DB,0x4C8421CC,0x4F0315EC,0x29E8649E,0xA7732D6F,0x2E94D3E3,
+  0x7D98A340,0x397C4D74,0x659DB4DE,0x747D4E9A,0xD9DB8435,0x4659DBE9,
+  0x313E6DC5,0x29D104DC,0x9F226CBA,0x452F18B0,0xD0BC5068,0x844CA299,
+  0x782B294E,0x4AE2EB7B,0xA4C475F8,0x70A81311,0x4B3E8BCC,0x7E20D4BA,
+  0xABCA33C9,0x57BE2960,0x44F9B419,0x2E567746,0x72EB757A,0x102CC0E8,
+  0xB07F32B9,0xD0DABD59,0xBA85AD6B,0xF3E20667,0x98D77D81,0x197AFA47,
+  0x518EE9AC,0xE10CE5A2,0x01CF2C2A,0xD3A3AF3D,0x16DDFD65,0x669232F8,
+  0x1C50A301,0xB93D9151,0x9354D3F4,0x847D79D0,0xD5FE2EC6,0x1F7B0610,
+  0xFA6B90A5,0xC5879041,0x2E7DC05E,0x423F1F32,0xEF623DDB,0x49C13280,
+  0x98714E92,0xC7B6E4AD,0xC4318466,0x0737F312,0x4D3C003F,0x9ACC1F1F,
+  0x5F1C926D,0x085FA771,0x185A83A2,0xF9AA159D,0x0B0B0132,0xF98E7A43,
+  0xCD9EBDBE,0x0190CB29,0x10D93FB6,0x3B8A4D97,0x66A65A41,0xE43E766F,
+  0x77BE3C41,0xB9686364,0xCB36994D,0x6846A287,0x567E77F7,0x36178DD8,
+  0xBDE6B1F2,0xB6EFDC64,0x82950324,0x42053F47,0xC09BE51C,0x0942D762,
+  0x35F92C7F,0x367DEC61,0x6EE3D983,0xDBAAF78A,0x265D2C47,0x8EB4BF5C,
+  0x33B232D7,0xB0137E77,0x373C39A7,0x8D2B2E76,0xC7510F01,0x50F9E032,
+  0x7B1FDDDB,0x724C2AAE,0xB10ECB31,0xCCA3D1B8,0x7F0BCF10,0x4254BBBD,
+  0xE3F93B97,0x2305039B,0x53120E22,0x1A2F3B9A,0x0FDDBD97,0x0118561E,
+  0x0A798E13,0x9E0B3ACD,0xDB6C9F15,0xF512D0A2,0x9E8C3A28,0xEE2184AE,
+  0x0051EC2F,0x2432F74F,0xB0AA66EA,0x55128D88,0xF7D83A38,0x4DAE8E82,
+  0x3FDC98D6,0x5F0BD341,0x7244BE1D,0xC7B48E78,0x2D473053,0x43892E20,
+  0xBA0F1F2A,0x524D4895,0x2E10BCB1,0x4C372D81,0x5C3E50CD,0xCF61CC2E,
+  0x931709AB,0x81B3AEFC,0x39E9405E,0x7FFE108C,0x4FBB3FF8,0x06ABE450,
+  0x7F5BF51E,0xA4E3CDFD,0xDB0F6C6F,0x159A1227,0x3B9FED55,0xD20B6F7F,
+  0xFBE9CC83,0x64856619,0xBF52B8AF,0x9D7006B0,0x71165BC6,0xAE324AEE,
+  0x29D27F2C,0x794C2086,0x74445CE2,0x782915CC,0xD4CE6886,0x3289AE7C,
+  0x53DEF297,0x4185F7ED,0x88B72400,0x3C09DC11,0xBCE3AAB6,0x6A75934A,
+  0xB267E399,0x000DF1BF,0x193BA5E2,0xFA3E1977,0x179E14F6,0x1EEDE298,
+  0x691F0B06,0xB84F78AC,0xC1C15316,0xFFFF3AD6,0x0B457383,0x518CD612,
+  0x05A00F3E,0xD5B7D275,0x4C5ECCD7,0xE02CD0BE,0x5558E9F2,0x0C89BBF0,
+  0xA3D96227,0x2832D2B2,0xF667B897,0xD4556554,0xF9D2F01F,0xFA1E3FAE,
+  0x52C2E1EE,0xE5451F31,0x7E849729,0xDABDB67A,0x54BF5E7E,0xF831C271,
+  0x5F1A17E3,0x9D140AFE,0x92741C47,0x48CFABCE,0x9CBBE477,0x9C3EE57F,
+  0xB07D4C39,0xCC21BCE2,0x697708B1,0x58DA2A6B,0x2370DB16,0x6E641948,
+  0xACC5BD52,0x868F24CC,0xCA1DB0F5,0x4CADA492,0x3F443E54,0xC4A4D5E9,
+  0xF00AD670,0xE93C86E0,0xFE90651A,0xDDE532A3,0xA66458DF,0xAB7D7151,
+  0x0E2E775F,0xC9109F99,0x8D96D59F,0x73CEF14C,0xC74E88E9,0x02712DC0,
+  0x04F41735,0x2E5914A2,0x59F4B2FB,0x0287FC83,0x80BC0343,0xF6B32559,
+  0xC74178D4,0xF1D99123,0x383CCC07,0xACC0637D,0x0863A548,0xA6FCAC85,
+  0x2A13EFF0,0xAF2EEDB1,0x41E72750,0xE0C6B342,0x5DA22B46,0x635559E0,
+  0xD2EA40AC,0x10AA98C0,0x19096497,0x112C542B,0x2C85040C,0xA868E7D0,
+  0x6E260188,0xF596D390,0xC3BB5D7A,0x7A2AA937,0xDFD15032,0x6780AE3B,
+  0xDB5F9CD8,0x8BD266B0,0x7744AF12,0xB463B1B0,0x589629C9,0xE30DBC6E,
+  0x880F5569,0x209E6E16,0x9DECA50C,0x02987A57,0xBED3EA57,0xD3A678AA,
+  0x70DD030D,0x0CFD9C5D,0x92A18E99,0xF5740619,0x7F6F0A7D,0x134CAF9A,
+  0x70F5BAE4,0x23DCA7B5,0x4D788FCD,0xC7F07847,0xBCF77DA1,0x9071D568,
+  0xFC627EA1,0xAE004B77,0x66B54BCB,0x7EF2DAAC,0xDCD5AC30,0xB9BDF730,
+  0x505A97A7,0x9D881FD3,0xADB796CC,0x94A1D202,0x97535D7F,0x31EC20C0,
+  0xB1887A98,0xC1475069,0xA6F73AF3,0x71E4E067,0x46A569DE,0xD2ADE430,
+  0x6F0762C7,0xF50876F4,0x53510542,0x03741C3E,0x53502224,0xD8E54D60,
+  0x3C44AB1A,0x34972B46,0x74BFA89D,0xD7D768E0,0x37E605DC,0xE13D1BDF,
+  0x5051C421,0xB9E057BE,0xB717A14C,0xA1730C43,0xB99638BE,0xB5D5F36D,
+  0xE960D9EA,0x6B1388D3,0xECB6D3B6,0xBDBE8B83,0x2E29AFC5,0x764D71EC,
+  0x4B8F4F43,0xC21DDC00,0xA63F657F,0x82678130,0xDBF535AC,0xA594FC58,
+  0x942686BC,0xBD9B657B,0x4A0F9B61,0x44FF184F,0x38E10A2F,0x61910626,
+  0x5E247636,0x7106D137,0xC62802F0,0xBD1D1F00,0x7CC0DCB2,0xED634909,
+  0xDC13B24E,0x9799C499,0xD77E3D6A,0x14773B68,0x967A4FB7,0x35EECFB1,
+  0x2A5110B8,0xE2F0AF94,0x9D09DEA5,0x20255D27,0x5771D34B,0xE1089EE4,
+  0x246F330B,0x8F7CAEE5,0xD3064712,0x75CAFBEE,0xB94F7028,0xED953666,
+  0x5D1975B4,0x5AF81271,0x13BE2025,0x85194659,0x30805331,0xEC9D46C0,
+  0xBC027C36,0x2AF84188,0xC2141B80,0xC02B1E4A,0x04D36177,0xFC50E9D7,
+  0x39CE79DA,0x917E0A00,0xEF7A0BF4,0xA98BD8D1,0x19424DD2,0x9439DF1F,
+  0xC42AF746,0xADDBE83E,0x85221F0D,0x45563E90,0x9095EC52,0x77887B25,
+  0x8AE46064,0xBD43B71A,0xBB541956,0x7366CF9D,0xEE8E1737,0xB5A727C9,
+  0x5076B3E7,0xFC70BACA,0xCE135B75,0xC4E91AA3,0xF0341911,0x53430C3F,
+  0x886B0824,0x6BB5B8B7,0x33E21254,0xF193B456,0x5B09617F,0x215FFF50,
+  0x48D97EF1,0x356479AB,0x6EA9DDC4,0x0D352746,0xA2F5CE43,0xB226A1B3,
+  0x1329EA3C,0x7A337CC2,0xB5CCE13D,0x563E3B5B,0x534E8E8F,0x561399C9,
+  0xE1596392,0xB0F03125,0x4586645B,0x1F371847,0x94EAABD1,0x41F97EDD,
+  0xE3E5A39B,0x71C774E2,0x507296F4,0x5960133B,0x7852C494,0x3F5B2691,
+  0xA3F87774,0x5A7AF89E,0x17DA3F28,0xE9D9516D,0xFCC1C1D5,0xE4618628,
+  0x04081047,0xD8E4DB5F,0xDC380416,0x8C4933E2,0x95074D53,0xB1B0032D,
+  0xCC8102EA,0x71641243,0x98D6EB6A,0x90FEC945,0xA0914345,0x6FAB037D,
+  0x70F49C4D,0x05BF5B0E,0x927AAF7F,0xA1940F61,0xFEE0756F,0xF815369F,
+  0x5C00253B,0xF2B9762F,0x4AEB3CCC,0x1069F386,0xFBA4E7B9,0x70332665,
+  0x6BCA810E,0x85AB8058,0xAE4B2B2F,0x9D120712,0xBEE8EACB,0x776A1112
+};
+
+void
+__gmp_mt_recalc_buffer (gmp_uint_least32_t mt[])
+{
+  gmp_uint_least32_t y;
+  int kk;
+
+  for (kk = 0; kk < N - M; kk++)
+    {
+      y = (mt[kk] & 0x80000000) | (mt[kk + 1] & 0x7FFFFFFF);
+      mt[kk] = mt[kk + M] ^ (y >> 1) ^ ((y & 0x01) != 0 ? MATRIX_A : 0);
+    }
+  for (; kk < N - 1; kk++)
+    {
+      y = (mt[kk] & 0x80000000) | (mt[kk + 1] & 0x7FFFFFFF);
+      mt[kk] = mt[kk - (N - M)] ^ (y >> 1) ^ ((y & 0x01) != 0 ? MATRIX_A : 0);
+    }
+
+  y = (mt[N - 1] & 0x80000000) | (mt[0] & 0x7FFFFFFF);
+  mt[N - 1] = mt[M - 1] ^ (y >> 1) ^ ((y & 0x01) != 0 ? MATRIX_A : 0);
+}
+
+
+/* Get nbits bits of output from the generator into dest.
+   Note that Mersenne Twister is designed to produce outputs in
+   32-bit words.  */
+void
+__gmp_randget_mt (gmp_randstate_t rstate, mp_ptr dest, unsigned long int nbits)
+{
+  gmp_uint_least32_t y;
+  int rbits;
+  mp_size_t i;
+  mp_size_t nlimbs;
+  int *pmti;
+  gmp_uint_least32_t *mt;
+
+  pmti = &((gmp_rand_mt_struct *) RNG_STATE (rstate))->mti;
+  mt = ((gmp_rand_mt_struct *) RNG_STATE (rstate))->mt;
+
+  nlimbs = nbits / GMP_NUMB_BITS;
+  rbits = nbits % GMP_NUMB_BITS;
+
+#define NEXT_RANDOM			\
+  do					\
+    {					\
+      if (*pmti >= N)			\
+	{				\
+	  __gmp_mt_recalc_buffer (mt);  \
+	  *pmti = 0;			\
+	}				\
+      y = mt[(*pmti)++];		\
+      y ^= (y >> 11);			\
+      y ^= (y << 7) & MASK_1;		\
+      y ^= (y << 15) & MASK_2;		\
+      y ^= (y >> 18);			\
+    }					\
+  while (0)
+
+
+  /* Handle the common cases of 32- or 64-bit limbs with fast,
+     optimized routines, and the rest of cases with a general
+     routine.  In all cases, no more than 31 bits are rejected
+     for the last limb so that every version of the code is
+     consistent with the others.  */
+
+#if (GMP_NUMB_BITS == 32)
+
+  for (i = 0; i < nlimbs; i++)
+    {
+      NEXT_RANDOM;
+      dest[i] = (mp_limb_t) y;
+    }
+  if (rbits)
+    {
+      NEXT_RANDOM;
+      dest[nlimbs] = (mp_limb_t) (y & ~(ULONG_MAX << rbits));
+    }
+
+#else /* GMP_NUMB_BITS != 32 */
+#if (GMP_NUMB_BITS == 64)
+
+  for (i = 0; i < nlimbs; i++)
+    {
+      NEXT_RANDOM;
+      dest[i] = (mp_limb_t) y;
+      NEXT_RANDOM;
+      dest[i] |= (mp_limb_t) y << 32;
+    }
+  if (rbits)
+    {
+      if (rbits < 32)
+	{
+	  NEXT_RANDOM;
+	  dest[nlimbs] = (mp_limb_t) (y & ~(ULONG_MAX << rbits));
+	}
+      else
+	{
+	  NEXT_RANDOM;
+	  dest[nlimbs] = (mp_limb_t) y;
+	  if (rbits > 32)
+	    {
+	      NEXT_RANDOM;
+	      dest[nlimbs] |=
+		((mp_limb_t) (y & ~(ULONG_MAX << (rbits-32)))) << 32;
+	    }
+	}
+    }
+
+#else /* GMP_NUMB_BITS != 64 */
+
+  {
+    /* Fall back to a general algorithm.  This algorithm works by
+       keeping a pool of up to 64 bits (2 outputs from MT) acting
+       as a shift register from which bits are consumed as needed.
+       Bits are consumed using the LSB bits of bitpool_l, and
+       inserted via bitpool_h and shifted to the right place.  */
+
+    gmp_uint_least32_t bitpool_h = 0;
+    gmp_uint_least32_t bitpool_l = 0;
+    int bits_in_pool = 0;	/* Holds number of valid bits in the pool.  */
+    int bits_to_fill;		/* Holds total number of bits to put in
+				   destination.  */
+    int bitidx;			/* Holds the destination bit position.  */
+    mp_size_t nlimbs2;		/* Number of whole+partial limbs to fill.  */
+
+    nlimbs2 = nlimbs + (rbits != 0);
+
+    for (i = 0; i < nlimbs2; i++)
+      {
+	bitidx = 0;
+	if (i < nlimbs)
+	  bits_to_fill = GMP_NUMB_BITS;
+	else
+	  bits_to_fill = rbits;
+
+	dest[i] = CNST_LIMB (0);
+	while (bits_to_fill >= 32) /* Process whole 32-bit blocks first.  */
+	  {
+	    if (bits_in_pool < 32)	/* Need more bits.  */
+	      {
+		/* 64-bit right shift.  */
+		NEXT_RANDOM;
+		bitpool_h = y;
+		bitpool_l |= (bitpool_h << bits_in_pool) & 0xFFFFFFFF;
+		if (bits_in_pool == 0)
+		  bitpool_h = 0;
+		else
+		  bitpool_h >>= 32 - bits_in_pool;
+		bits_in_pool += 32;	/* We've got 32 more bits.  */
+	      }
+
+	    /* Fill a 32-bit chunk.  */
+	    dest[i] |= ((mp_limb_t) bitpool_l) << bitidx;
+	    bitpool_l = bitpool_h;
+	    bits_in_pool -= 32;
+	    bits_to_fill -= 32;
+	    bitidx += 32;
+	  }
+
+	/* Cover the case where GMP_NUMB_BITS is not a multiple of 32.  */
+	if (bits_to_fill != 0)
+	  {
+	    if (bits_in_pool < bits_to_fill)
+	      {
+		NEXT_RANDOM;
+		bitpool_h = y;
+		bitpool_l |= (bitpool_h << bits_in_pool) & 0xFFFFFFFF;
+		if (bits_in_pool == 0)
+		  bitpool_h = 0;
+		else
+		  bitpool_h >>= 32 - bits_in_pool;
+		bits_in_pool += 32;
+	      }
+
+	    dest[i] |= (((mp_limb_t) bitpool_l
+			 & ~(~CNST_LIMB (0) << bits_to_fill))
+			<< bitidx);
+	    bitpool_l = ((bitpool_l >> bits_to_fill)
+			 | (bitpool_h << (32 - bits_to_fill))) & 0xFFFFFFFF;
+	    bitpool_h >>= bits_to_fill;
+	    bits_in_pool -= bits_to_fill;
+	  }
+      }
+  }
+
+#endif /* GMP_NUMB_BITS != 64 */
+#endif /* GMP_NUMB_BITS != 32 */
+}
+
+void
+__gmp_randclear_mt (gmp_randstate_t rstate)
+{
+  (*__gmp_free_func) ((void *) RNG_STATE (rstate),
+		      ALLOC (rstate->_mp_seed) * GMP_LIMB_BYTES);
+}
+
+void __gmp_randiset_mt (gmp_randstate_ptr, gmp_randstate_srcptr);
+
+static const gmp_randfnptr_t Mersenne_Twister_Generator_Noseed = {
+  NULL,
+  __gmp_randget_mt,
+  __gmp_randclear_mt,
+  __gmp_randiset_mt
+};
+
+void
+__gmp_randiset_mt (gmp_randstate_ptr dst, gmp_randstate_srcptr src)
+{
+  const mp_size_t sz = ((sizeof (gmp_rand_mt_struct) - 1) / GMP_LIMB_BYTES) + 1;
+  gmp_rand_mt_struct *dstp, *srcp;
+  mp_size_t i;
+
+  /* Set the generator functions.  */
+  RNG_FNPTR (dst) = RNG_FNPTR(src);
+
+  /* Allocate the MT-specific state.  */
+  dstp = (gmp_rand_mt_struct *) __GMP_ALLOCATE_FUNC_LIMBS (sz);
+  RNG_STATE (dst) = (mp_ptr) dstp;
+  ALLOC (dst->_mp_seed) = sz;     /* Initialize alloc field to placate Camm.  */
+
+  /* Copy state.  */
+  srcp = (gmp_rand_mt_struct *) RNG_STATE (src);
+  for (i = 0; i < N; i++)
+    dstp->mt[i] = srcp->mt[i];
+
+  dstp->mti = srcp->mti;
+}
+
+void
+__gmp_randinit_mt_noseed (gmp_randstate_ptr dst)
+{
+  const mp_size_t sz = ((sizeof (gmp_rand_mt_struct) - 1) / GMP_LIMB_BYTES) + 1;
+  gmp_rand_mt_struct *dstp;
+  mp_size_t i;
+
+  /* Set the generator functions.  */
+  RNG_FNPTR (dst) = (void *) &Mersenne_Twister_Generator_Noseed;
+
+  /* Allocate the MT-specific state.  */
+  dstp = (gmp_rand_mt_struct *) __GMP_ALLOCATE_FUNC_LIMBS (sz);
+  RNG_STATE (dst) = (mp_ptr) dstp;
+  ALLOC (dst->_mp_seed) = sz;     /* Initialize alloc field to placate Camm.  */
+
+  /* Set state for default seed.  */
+  for (i = 0; i < N; i++)
+    dstp->mt[i] = default_state[i];
+
+  dstp->mti = WARM_UP % N;
+}
diff --git a/third_party/gmp/rand/randmt.h b/third_party/gmp/rand/randmt.h
new file mode 100644
index 0000000..d64ff59
--- /dev/null
+++ b/third_party/gmp/rand/randmt.h
@@ -0,0 +1,51 @@
+/* Mersenne Twister pseudo-random number generator defines.
+
+Copyright 2002, 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+/* Number of extractions used to warm the buffer up.  */
+#define WARM_UP 2000
+
+/* Period parameters.  */
+#define N 624
+#define M 397
+#define MATRIX_A 0x9908B0DF   /* Constant vector a.  */
+
+/* State structure for MT.  */
+typedef struct
+{
+  gmp_uint_least32_t mt[N];    /* State array.  */
+  int mti;                     /* Index of current value.  */
+} gmp_rand_mt_struct;
+
+
+void __gmp_mt_recalc_buffer (gmp_uint_least32_t *);
+void __gmp_randget_mt (gmp_randstate_t, mp_ptr, unsigned long int);
+void __gmp_randclear_mt (gmp_randstate_t);
+void __gmp_randiset_mt (gmp_randstate_ptr, gmp_randstate_srcptr);
diff --git a/third_party/gmp/rand/randmts.c b/third_party/gmp/rand/randmts.c
new file mode 100644
index 0000000..2c3fc09
--- /dev/null
+++ b/third_party/gmp/rand/randmts.c
@@ -0,0 +1,164 @@
+/* Mersenne Twister pseudo-random number generator functions.
+
+Copyright 2002, 2003, 2013, 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "randmt.h"
+
+
+/* Calculate (b^e) mod (2^n-k) for e=1074888996, n=19937 and k=20023,
+   needed by the seeding function below.  */
+static void
+mangle_seed (mpz_ptr r)
+{
+  mpz_t          t, b;
+  unsigned long  e = 0x40118124;
+  unsigned long  bit = 0x20000000;
+
+  mpz_init2 (t, 19937L);
+  mpz_init_set (b, r);
+
+  do
+    {
+      mpz_mul (r, r, r);
+
+    reduce:
+      for (;;)
+        {
+          mpz_tdiv_q_2exp (t, r, 19937L);
+          if (SIZ (t) == 0)
+            break;
+          mpz_tdiv_r_2exp (r, r, 19937L);
+          mpz_addmul_ui (r, t, 20023L);
+        }
+
+      if ((e & bit) != 0)
+        {
+          e ^= bit;
+          mpz_mul (r, r, b);
+          goto reduce;
+        }
+
+      bit >>= 1;
+    }
+  while (bit != 0);
+
+  mpz_clear (t);
+  mpz_clear (b);
+}
+
+
+/* Seeding function.  Uses powering modulo a non-Mersenne prime to obtain
+   a permutation of the input seed space.  The modulus is 2^19937-20023,
+   which is probably prime.  The power is 1074888996.  In order to avoid
+   seeds 0 and 1 generating invalid or strange output, the input seed is
+   first manipulated as follows:
+
+     seed1 = seed mod (2^19937-20027) + 2
+
+   so that seed1 lies between 2 and 2^19937-20026 inclusive. Then the
+   powering is performed as follows:
+
+     seed2 = (seed1^1074888996) mod (2^19937-20023)
+
+   and then seed2 is used to bootstrap the buffer.
+
+   This method aims to give guarantees that:
+     a) seed2 will never be zero,
+     b) seed2 will very seldom have a very low population of ones in its
+	binary representation, and
+     c) every seed between 0 and 2^19937-20028 (inclusive) will yield a
+	different sequence.
+
+   CAVEATS:
+
+   The period of the seeding function is 2^19937-20027.  This means that
+   with seeds 2^19937-20027, 2^19937-20026, ... the exact same sequences
+   are obtained as with seeds 0, 1, etc.; it also means that seed -1
+   produces the same sequence as seed 2^19937-20028, etc.
+ */
+
+static void
+randseed_mt (gmp_randstate_t rstate, mpz_srcptr seed)
+{
+  int i;
+  size_t cnt;
+
+  gmp_rand_mt_struct *p;
+  mpz_t mod;    /* Modulus.  */
+  mpz_t seed1;  /* Intermediate result.  */
+
+  p = (gmp_rand_mt_struct *) RNG_STATE (rstate);
+
+  mpz_init2 (mod, 19938L);
+  mpz_init2 (seed1, 19937L);
+
+  mpz_setbit (mod, 19937L);
+  mpz_sub_ui (mod, mod, 20027L);
+  mpz_mod (seed1, seed, mod);	/* Reduce `seed' modulo `mod'.  */
+  mpz_clear (mod);
+  mpz_add_ui (seed1, seed1, 2L);	/* seed1 is now ready.  */
+  mangle_seed (seed1);	/* Perform the mangling by powering.  */
+
+  /* Copy the last bit into bit 31 of mt[0] and clear it.  */
+  p->mt[0] = (mpz_tstbit (seed1, 19936L) != 0) ? 0x80000000 : 0;
+  mpz_clrbit (seed1, 19936L);
+
+  /* Split seed1 into N-1 32-bit chunks.  */
+  mpz_export (&p->mt[1], &cnt, -1, sizeof (p->mt[1]), 0,
+              8 * sizeof (p->mt[1]) - 32, seed1);
+  mpz_clear (seed1);
+  cnt++;
+  ASSERT (cnt <= N);
+  while (cnt < N)
+    p->mt[cnt++] = 0;
+
+  /* Warm the generator up if necessary.  */
+  if (WARM_UP != 0)
+    for (i = 0; i < WARM_UP / N; i++)
+      __gmp_mt_recalc_buffer (p->mt);
+
+  p->mti = WARM_UP % N;
+}
+
+
+static const gmp_randfnptr_t Mersenne_Twister_Generator = {
+  randseed_mt,
+  __gmp_randget_mt,
+  __gmp_randclear_mt,
+  __gmp_randiset_mt
+};
+
+/* Initialize MT-specific data.  */
+void
+gmp_randinit_mt (gmp_randstate_t rstate)
+{
+  __gmp_randinit_mt_noseed (rstate);
+  RNG_FNPTR (rstate) = (void *) &Mersenne_Twister_Generator;
+}
diff --git a/third_party/gmp/rand/randmui.c b/third_party/gmp/rand/randmui.c
new file mode 100644
index 0000000..d3292db
--- /dev/null
+++ b/third_party/gmp/rand/randmui.c
@@ -0,0 +1,85 @@
+/* gmp_urandomm_ui -- uniform random number 0 to N-1 for ulong N.
+
+Copyright 2003, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+/* If n is a power of 2 then the test ret<n is always true and the loop is
+   unnecessary, but there's no need to add special code for this.  Just get
+   the "bits" calculation correct and let it go through normally.
+
+   If n is 1 then will have bits==0 and _gmp_rand will produce no output and
+   we always return 0.  Again there seems no need for a special case, just
+   initialize a[0]=0 and let it go through normally.  */
+
+#define MAX_URANDOMM_ITER  80
+
+unsigned long
+gmp_urandomm_ui (gmp_randstate_ptr rstate, unsigned long n)
+{
+  mp_limb_t      a[LIMBS_PER_ULONG];
+  unsigned long  ret, bits, leading;
+  int            i;
+
+  if (UNLIKELY (n == 0))
+    DIVIDE_BY_ZERO;
+
+  /* start with zeros, since if bits==0 then _gmp_rand will store nothing at
+     all (bits==0 arises when n==1), or if bits <= GMP_NUMB_BITS then it
+     will store only a[0].  */
+  a[0] = 0;
+#if LIMBS_PER_ULONG > 1
+  a[1] = 0;
+#endif
+
+  count_leading_zeros (leading, (mp_limb_t) n);
+  bits = GMP_LIMB_BITS - leading - (POW2_P(n) != 0);
+
+  for (i = 0; i < MAX_URANDOMM_ITER; i++)
+    {
+      _gmp_rand (a, rstate, bits);
+#if LIMBS_PER_ULONG == 1
+      ret = a[0];
+#else
+      ret = a[0] | (a[1] << GMP_NUMB_BITS);
+#endif
+      if (LIKELY (ret < n))   /* usually one iteration suffices */
+        goto done;
+    }
+
+  /* Too many iterations, there must be something degenerate about the
+     rstate algorithm.  Return r%n.  */
+  ret -= n;
+  ASSERT (ret < n);
+
+ done:
+  return ret;
+}
diff --git a/third_party/gmp/rand/rands.c b/third_party/gmp/rand/rands.c
new file mode 100644
index 0000000..af436a4
--- /dev/null
+++ b/third_party/gmp/rand/rands.c
@@ -0,0 +1,41 @@
+/* __gmp_rands -- global random state for old-style random functions.
+
+   EVERYTHING IN THIS FILE IS FOR INTERNAL USE ONLY.  IT'S ALMOST CERTAIN TO
+   BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN FUTURE GNU
+   MP RELEASES.  */
+
+/*
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+/* Use this via the RANDS macro in gmp-impl.h */
+char             __gmp_rands_initialized = 0;
+gmp_randstate_t  __gmp_rands;
diff --git a/third_party/gmp/rand/randsd.c b/third_party/gmp/rand/randsd.c
new file mode 100644
index 0000000..b0e3dd6
--- /dev/null
+++ b/third_party/gmp/rand/randsd.c
@@ -0,0 +1,38 @@
+/* gmp_randseed (state, seed) -- Set initial seed SEED in random state STATE.
+
+Copyright 2000, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+gmp_randseed (gmp_randstate_t rstate,
+	      mpz_srcptr seed)
+{
+  (*((gmp_randfnptr_t *) RNG_FNPTR (rstate))->randseed_fn) (rstate, seed);
+}
diff --git a/third_party/gmp/rand/randsdui.c b/third_party/gmp/rand/randsdui.c
new file mode 100644
index 0000000..46d80ad
--- /dev/null
+++ b/third_party/gmp/rand/randsdui.c
@@ -0,0 +1,43 @@
+/* gmp_randseed_ui (state, seed) -- Set initial seed SEED in random
+   state STATE.
+
+Copyright 2000, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+void
+gmp_randseed_ui (gmp_randstate_t rstate,
+                 unsigned long int seed)
+{
+  mpz_t zseed;
+  mp_limb_t zlimbs[LIMBS_PER_ULONG];
+
+  MPZ_FAKE_UI (zseed, zlimbs, seed);
+  gmp_randseed (rstate, zseed);
+}
diff --git a/third_party/gmp/scanf/Makefile.am b/third_party/gmp/scanf/Makefile.am
new file mode 100644
index 0000000..4f0f6c1
--- /dev/null
+++ b/third_party/gmp/scanf/Makefile.am
@@ -0,0 +1,38 @@
+## Process this file with automake to generate Makefile.in
+
+# Copyright 2001, 2002 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+
+AM_CPPFLAGS = -D__GMP_WITHIN_GMP -I$(top_srcdir)
+
+noinst_LTLIBRARIES = libscanf.la
+
+libscanf_la_SOURCES = \
+  doscan.c fscanf.c fscanffuns.c scanf.c sscanf.c sscanffuns.c \
+  vfscanf.c vscanf.c vsscanf.c
diff --git a/third_party/gmp/scanf/Makefile.in b/third_party/gmp/scanf/Makefile.in
new file mode 100644
index 0000000..8f57055
--- /dev/null
+++ b/third_party/gmp/scanf/Makefile.in
@@ -0,0 +1,642 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Copyright 2001, 2002 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = scanf
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libscanf_la_LIBADD =
+am_libscanf_la_OBJECTS = doscan.lo fscanf.lo fscanffuns.lo scanf.lo \
+	sscanf.lo sscanffuns.lo vfscanf.lo vscanf.lo vsscanf.lo
+libscanf_la_OBJECTS = $(am_libscanf_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp =
+am__depfiles_maybe =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+SOURCES = $(libscanf_la_SOURCES)
+DIST_SOURCES = $(libscanf_la_SOURCES)
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ABI = @ABI@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+ASMFLAGS = @ASMFLAGS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CALLING_CONVENTIONS_OBJS = @CALLING_CONVENTIONS_OBJS@
+CC = @CC@
+CCAS = @CCAS@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPP_FOR_BUILD = @CPP_FOR_BUILD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFN_LONG_LONG_LIMB = @DEFN_LONG_LONG_LIMB@
+DEFS = @DEFS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@
+FGREP = @FGREP@
+GMP_LDFLAGS = @GMP_LDFLAGS@
+GMP_LIMB_BITS = @GMP_LIMB_BITS@
+GMP_NAIL_BITS = @GMP_NAIL_BITS@
+GREP = @GREP@
+HAVE_CLOCK_01 = @HAVE_CLOCK_01@
+HAVE_CPUTIME_01 = @HAVE_CPUTIME_01@
+HAVE_GETRUSAGE_01 = @HAVE_GETRUSAGE_01@
+HAVE_GETTIMEOFDAY_01 = @HAVE_GETTIMEOFDAY_01@
+HAVE_HOST_CPU_FAMILY_power = @HAVE_HOST_CPU_FAMILY_power@
+HAVE_HOST_CPU_FAMILY_powerpc = @HAVE_HOST_CPU_FAMILY_powerpc@
+HAVE_SIGACTION_01 = @HAVE_SIGACTION_01@
+HAVE_SIGALTSTACK_01 = @HAVE_SIGALTSTACK_01@
+HAVE_SIGSTACK_01 = @HAVE_SIGSTACK_01@
+HAVE_STACK_T_01 = @HAVE_STACK_T_01@
+HAVE_SYS_RESOURCE_H_01 = @HAVE_SYS_RESOURCE_H_01@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCURSES = @LIBCURSES@
+LIBGMPXX_LDFLAGS = @LIBGMPXX_LDFLAGS@
+LIBGMP_DLL = @LIBGMP_DLL@
+LIBGMP_LDFLAGS = @LIBGMP_LDFLAGS@
+LIBM = @LIBM@
+LIBM_FOR_BUILD = @LIBM_FOR_BUILD@
+LIBOBJS = @LIBOBJS@
+LIBREADLINE = @LIBREADLINE@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+M4 = @M4@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPEED_CYCLECOUNTER_OBJ = @SPEED_CYCLECOUNTER_OBJ@
+STRIP = @STRIP@
+TAL_OBJECT = @TAL_OBJECT@
+TUNE_LIBS = @TUNE_LIBS@
+TUNE_SQR_OBJ = @TUNE_SQR_OBJ@
+U_FOR_BUILD = @U_FOR_BUILD@
+VERSION = @VERSION@
+WITH_READLINE_01 = @WITH_READLINE_01@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__leading_dot = @am__leading_dot@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gmp_srclinks = @gmp_srclinks@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+mpn_objects = @mpn_objects@
+mpn_objs_in_libgmp = @mpn_objs_in_libgmp@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_CPPFLAGS = -D__GMP_WITHIN_GMP -I$(top_srcdir)
+noinst_LTLIBRARIES = libscanf.la
+libscanf_la_SOURCES = \
+  doscan.c fscanf.c fscanffuns.c scanf.c sscanf.c sscanffuns.c \
+  vfscanf.c vscanf.c vsscanf.c
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu --ignore-deps scanf/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu --ignore-deps scanf/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+	@list='$(noinst_LTLIBRARIES)'; \
+	locs=`for p in $$list; do echo $$p; done | \
+	      sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+	      sort -u`; \
+	test -z "$$locs" || { \
+	  echo rm -f $${locs}; \
+	  rm -f $${locs}; \
+	}
+
+libscanf.la: $(libscanf_la_OBJECTS) $(libscanf_la_DEPENDENCIES) $(EXTRA_libscanf_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(LINK)  $(libscanf_la_OBJECTS) $(libscanf_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+.c.o:
+	$(AM_V_CC)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+	$(AM_V_CC)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+	$(AM_V_CC)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+	clean-libtool clean-noinstLTLIBRARIES cscopelist-am ctags \
+	ctags-am distclean distclean-compile distclean-generic \
+	distclean-libtool distclean-tags distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-dvi install-dvi-am install-exec \
+	install-exec-am install-html install-html-am install-info \
+	install-info-am install-man install-pdf install-pdf-am \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/third_party/gmp/scanf/doscan.c b/third_party/gmp/scanf/doscan.c
new file mode 100644
index 0000000..8d9c1bb
--- /dev/null
+++ b/third_party/gmp/scanf/doscan.c
@@ -0,0 +1,767 @@
+/* __gmp_doscan -- formatted input internals.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2001-2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define _GNU_SOURCE    /* for DECIMAL_POINT in langinfo.h */
+
+#include "config.h"	/* needed for the HAVE_, could also move gmp incls */
+
+#include <stdarg.h>
+#include <ctype.h>
+#include <stddef.h>    /* for ptrdiff_t */
+#include <stdio.h>
+#include <stdlib.h>    /* for strtol */
+#include <string.h>
+
+#if HAVE_LANGINFO_H
+#include <langinfo.h>  /* for nl_langinfo */
+#endif
+
+#if HAVE_LOCALE_H
+#include <locale.h>    /* for localeconv */
+#endif
+
+#if HAVE_INTTYPES_H
+# include <inttypes.h> /* for intmax_t */
+#else
+# if HAVE_STDINT_H
+#  include <stdint.h>
+# endif
+#endif
+
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h> /* for quad_t */
+#endif
+
+#include "gmp-impl.h"
+
+
+/* Change this to "#define TRACE(x) x" for some traces. */
+#define TRACE(x)
+
+
+/* General:
+
+       It's necessary to parse up the format string to recognise the GMP
+       extra types F, Q and Z.  Other types and conversions are passed
+       across to the standard sscanf or fscanf via funs->scan, for ease of
+       implementation.  This is essential in the case of something like glibc
+       %p where the pointer format isn't actually documented.
+
+       Because funs->scan doesn't get the whole input it can't put the right
+       values in for %n, so that's handled in __gmp_doscan.  Neither sscanf
+       nor fscanf directly indicate how many characters were read, so an
+       extra %n is appended to each run for that.  For fscanf this merely
+       supports our %n output, but for sscanf it lets funs->step move us
+       along the input string.
+
+       Whitespace and literal matches in the format string, including %%,
+       are handled directly within __gmp_doscan.  This is reasonably
+       efficient, and avoids some suspicious behaviour observed in various
+       system libc's.  GLIBC 2.2.4 for instance returns 0 on
+
+	   sscanf(" ", " x")
+       or
+	   sscanf(" ", " x%d",&n)
+
+       whereas we think they should return EOF, since end-of-string is
+       reached when a match of "x" is required.
+
+       For standard % conversions, funs->scan is called once for each
+       conversion.  If we had vfscanf and vsscanf and could rely on their
+       fixed text matching behaviour then we could call them with multiple
+       consecutive standard conversions.  But plain fscanf and sscanf work
+       fine, and parsing one field at a time shouldn't be too much of a
+       slowdown.
+
+   gmpscan:
+
+       gmpscan reads a gmp type.  It's only used from one place, but is a
+       separate subroutine to avoid a big chunk of complicated code in the
+       middle of __gmp_doscan.  Within gmpscan a couple of loopbacks make it
+       possible to share code for parsing integers, rationals and floats.
+
+       In gmpscan normally one char of lookahead is maintained, but when width
+       is reached that stops, on the principle that an fgetc/ungetc of a char
+       past where we're told to stop would be undesirable.  "chars" is how many
+       characters have been read so far, including the current c.  When
+       chars==width and another character is desired then a jump is done to the
+       "convert" stage.  c is invalid and mustn't be unget'ed in this case;
+       chars is set to width+1 to indicate that.
+
+       gmpscan normally returns the number of characters read.  -1 means an
+       invalid field, -2 means EOF reached before any matching characters
+       were read.
+
+       For hex floats, the mantissa part is passed to mpf_set_str, then the
+       exponent is applied with mpf_mul_exp or mpf_div_2exp.  This is easier
+       than teaching mpf_set_str about an exponent factor (ie. 2) differing
+       from the mantissa radix point factor (ie. 16).  mpf_mul_exp and
+       mpf_div_2exp will preserve the application requested precision, so
+       nothing in that respect is lost by making this a two-step process.
+
+   Matching and errors:
+
+       C99 7.19.6.2 paras 9 and 10 say an input item is read as the longest
+       string which is a match for the appropriate type, or a prefix of a
+       match.  With that done, if it's only a prefix then the result is a
+       matching failure, ie. invalid input.
+
+       This rule seems fairly clear, but doesn't seem to be universally
+       applied in system C libraries.  Even GLIBC doesn't seem to get it
+       right, insofar as it seems to accept some apparently invalid forms.
+       Eg. glibc 2.3.1 accepts "0x" for a "%i", where a reading of the
+       standard would suggest a non-empty sequence of digits should be
+       required after an "0x".
+
+       A footnote to 7.19.6.2 para 17 notes how this input item reading can
+       mean inputs acceptable to strtol are not acceptable to fscanf.  We
+       think this confirms our reading of "0x" as invalid.
+
+       Clearly gmp_sscanf could backtrack to a longest input which was a
+       valid match for a given item, but this is not done, since C99 says
+       sscanf is identical to fscanf, so we make gmp_sscanf identical to
+       gmp_fscanf.
+
+   Types:
+
+       C99 says "ll" is for long long, and "L" is for long double floats.
+       Unfortunately in GMP 4.1.1 we documented the two as equivalent.  This
+       doesn't affect us directly, since both are passed through to plain
+       scanf.  It seems wisest not to try to enforce the C99 rule.  This is
+       consistent with what we said before, though whether it actually
+       worked was always up to the C library.
+
+   Alternatives:
+
+       Consideration was given to using separate code for gmp_fscanf and
+       gmp_sscanf.  The sscanf case could zip across a string doing literal
+       matches or recognising digits in gmpscan, rather than making a
+       function call fun->get per character.  The fscanf could use getc
+       rather than fgetc too, which might help those systems where getc is a
+       macro or otherwise inlined.  But none of this scanning and converting
+       will be particularly fast, so the two are done together to keep it a
+       little simpler for now.
+
+       Various multibyte string issues are not addressed, for a start C99
+       scanf says the format string is multibyte.  Since we pass %c, %s and
+       %[ to the system scanf, they might do multibyte reads already, but
+       it's another matter whether or not that can be used, since our digit
+       and whitespace parsing is only unibyte.  The plan is to quietly
+       ignore multibyte locales for now.  This is not as bad as it sounds,
+       since GMP is presumably used mostly on numbers, which can be
+       perfectly adequately treated in plain ASCII.
+
+*/
+
+
+struct gmp_doscan_params_t {
+  int	base;
+  int	ignore;
+  char	type;
+  int	width;
+};
+
+
+#define GET(c)			\
+  do {				\
+    ASSERT (chars <= width);	\
+    chars++;			\
+    if (chars > width)		\
+      goto convert;		\
+    (c) = (*funs->get) (data);	\
+  } while (0)
+
+/* store into "s", extending if necessary */
+#define STORE(c)							\
+  do {									\
+    ASSERT (s_upto <= s_alloc);						\
+    if (s_upto >= s_alloc)						\
+      {									\
+	size_t	s_alloc_new = s_alloc + S_ALLOC_STEP;			\
+	s = __GMP_REALLOCATE_FUNC_TYPE (s, s_alloc, s_alloc_new, char); \
+	s_alloc = s_alloc_new;						\
+      }									\
+    s[s_upto++] = c;							\
+  } while (0)
+
+#define S_ALLOC_STEP  512
+
+static int
+gmpscan (const struct gmp_doscan_funs_t *funs, void *data,
+	 const struct gmp_doscan_params_t *p, void *dst)
+{
+  int	  chars, c, base, first, width, seen_point, seen_digit, hexfloat;
+  size_t  s_upto, s_alloc, hexexp;
+  char	  *s;
+  int	  invalid = 0;
+
+  TRACE (printf ("gmpscan\n"));
+
+  ASSERT (p->type == 'F' || p->type == 'Q' || p->type == 'Z');
+
+  c = (*funs->get) (data);
+  if (c == EOF)
+    return -2;
+
+  chars = 1;
+  first = 1;
+  seen_point = 0;
+  width = (p->width == 0 ? INT_MAX-1 : p->width);
+  base = p->base;
+  s_alloc = S_ALLOC_STEP;
+  s = __GMP_ALLOCATE_FUNC_TYPE (s_alloc, char);
+  s_upto = 0;
+  hexfloat = 0;
+  hexexp = 0;
+
+ another:
+  seen_digit = 0;
+  if (c == '-')
+    {
+      STORE (c);
+      goto get_for_sign;
+    }
+  else if (c == '+')
+    {
+      /* don't store '+', it's not accepted by mpz_set_str etc */
+    get_for_sign:
+      GET (c);
+    }
+
+  if (base == 0)
+    {
+      base = 10;		  /* decimal if no base indicator */
+      if (c == '0')
+	{
+	  seen_digit = 1;	  /* 0 alone is a valid number */
+	  if (p->type != 'F')
+	    base = 8;		  /* leading 0 is octal, for non-floats */
+	  STORE (c);
+	  GET (c);
+	  if (c == 'x' || c == 'X')
+	    {
+	      base = 16;
+	      seen_digit = 0;	  /* must have digits after an 0x */
+	      if (p->type == 'F') /* don't pass 'x' to mpf_set_str_point */
+		hexfloat = 1;
+	      else
+		STORE (c);
+	      GET (c);
+	    }
+	}
+    }
+
+ digits:
+  for (;;)
+    {
+      if (base == 16)
+	{
+	  if (! isxdigit (c))
+	    break;
+	}
+      else
+	{
+	  if (! isdigit (c))
+	    break;
+	  if (base == 8 && (c == '8' || c == '9'))
+	    break;
+	}
+
+      seen_digit = 1;
+      STORE (c);
+      GET (c);
+    }
+
+  if (first)
+    {
+      /* decimal point */
+      if (p->type == 'F' && ! seen_point)
+	{
+	  /* For a multi-character decimal point, if the first character is
+	     present then all of it must be, otherwise the input is
+	     considered invalid.  */
+	  const char  *point = GMP_DECIMAL_POINT;
+	  int	      pc = (unsigned char) *point++;
+	  if (c == pc)
+	    {
+	      for (;;)
+		{
+		  STORE (c);
+		  GET (c);
+		  pc = (unsigned char) *point++;
+		  if (pc == '\0')
+		    break;
+		  if (c != pc)
+		    goto set_invalid;
+		}
+	      seen_point = 1;
+	      goto digits;
+	    }
+	}
+
+      /* exponent */
+      if (p->type == 'F')
+	{
+	  if (hexfloat && (c == 'p' || c == 'P'))
+	    {
+	      hexexp = s_upto; /* exponent location */
+	      base = 10;       /* exponent in decimal */
+	      goto exponent;
+	    }
+	  else if (! hexfloat && (c == 'e' || c == 'E'))
+	    {
+	    exponent:
+	      /* must have at least one digit in the mantissa, just an exponent
+		 is not good enough */
+	      if (! seen_digit)
+		goto set_invalid;
+
+	    do_second:
+	      first = 0;
+	      STORE (c);
+	      GET (c);
+	      goto another;
+	    }
+	}
+
+      /* denominator */
+      if (p->type == 'Q' && c == '/')
+	{
+	  /* must have at least one digit in the numerator */
+	  if (! seen_digit)
+	    goto set_invalid;
+
+	  /* now look for at least one digit in the denominator */
+	  seen_digit = 0;
+
+	  /* allow the base to be redetermined for "%i" */
+	  base = p->base;
+	  goto do_second;
+	}
+    }
+
+ convert:
+  if (! seen_digit)
+    {
+    set_invalid:
+      invalid = 1;
+      goto done;
+    }
+
+  if (! p->ignore)
+    {
+      STORE ('\0');
+      TRACE (printf ("	convert \"%s\"\n", s));
+
+      /* We ought to have parsed out a valid string above, so just test
+	 mpz_set_str etc with an ASSERT.  */
+      switch (p->type) {
+      case 'F':
+	{
+	  mpf_ptr  f = (mpf_ptr) dst;
+	  if (hexexp != 0)
+	    s[hexexp] = '\0';
+	  ASSERT_NOCARRY (mpf_set_str (f, s, hexfloat ? 16 : 10));
+	  if (hexexp != 0)
+	    {
+	      char *dummy;
+	      long  exp;
+	      exp = strtol (s + hexexp + 1, &dummy, 10);
+	      if (exp >= 0)
+		mpf_mul_2exp (f, f, (unsigned long) exp);
+	      else
+		mpf_div_2exp (f, f, NEG_CAST (unsigned long, exp));
+	    }
+	}
+	break;
+      case 'Q':
+	ASSERT_NOCARRY (mpq_set_str ((mpq_ptr) dst, s, p->base));
+	break;
+      case 'Z':
+	ASSERT_NOCARRY (mpz_set_str ((mpz_ptr) dst, s, p->base));
+	break;
+      default:
+	ASSERT (0);
+	/*FALLTHRU*/
+	break;
+      }
+    }
+
+ done:
+  ASSERT (chars <= width+1);
+  if (chars != width+1)
+    {
+      (*funs->unget) (c, data);
+      TRACE (printf ("	ungetc %d, to give %d chars\n", c, chars-1));
+    }
+  chars--;
+
+  (*__gmp_free_func) (s, s_alloc);
+
+  if (invalid)
+    {
+      TRACE (printf ("	invalid\n"));
+      return -1;
+    }
+
+  TRACE (printf ("  return %d chars (cf width %d)\n", chars, width));
+  return chars;
+}
+
+
+/* Read and discard whitespace, if any.  Return number of chars skipped.
+   Whitespace skipping never provokes the EOF return from __gmp_doscan, so
+   it's not necessary to watch for EOF from funs->get, */
+static int
+skip_white (const struct gmp_doscan_funs_t *funs, void *data)
+{
+  int  c;
+  int  ret = 0;
+
+  do
+    {
+      c = (funs->get) (data);
+      ret++;
+    }
+  while (isspace (c));
+
+  (funs->unget) (c, data);
+  ret--;
+
+  TRACE (printf ("  skip white %d\n", ret));
+  return ret;
+}
+
+
+int
+__gmp_doscan (const struct gmp_doscan_funs_t *funs, void *data,
+	      const char *orig_fmt, va_list orig_ap)
+{
+  struct gmp_doscan_params_t  param;
+  va_list     ap;
+  char	      *alloc_fmt;
+  const char  *fmt, *this_fmt, *end_fmt;
+  size_t      orig_fmt_len, alloc_fmt_size, len;
+  int	      new_fields, new_chars;
+  char	      fchar;
+  int	      fields = 0;
+  int	      chars = 0;
+
+  TRACE (printf ("__gmp_doscan \"%s\"\n", orig_fmt);
+	 if (funs->scan == (gmp_doscan_scan_t) sscanf)
+	   printf ("  s=\"%s\"\n", * (const char **) data));
+
+  /* Don't modify orig_ap, if va_list is actually an array and hence call by
+     reference.  It could be argued that it'd be more efficient to leave
+     callers to make a copy if they care, but doing so here is going to be a
+     very small part of the total work, and we may as well keep applications
+     out of trouble.  */
+  va_copy (ap, orig_ap);
+
+  /* Parts of the format string are going to be copied so that a " %n" can
+     be appended.  alloc_fmt is some space for that.  orig_fmt_len+4 will be
+     needed if fmt consists of a single "%" specifier, but otherwise is an
+     overestimate.  We're not going to be very fast here, so use
+     __gmp_allocate_func rather than TMP_ALLOC.  */
+  orig_fmt_len = strlen (orig_fmt);
+  alloc_fmt_size = orig_fmt_len + 4;
+  alloc_fmt = __GMP_ALLOCATE_FUNC_TYPE (alloc_fmt_size, char);
+
+  fmt = orig_fmt;
+  end_fmt = orig_fmt + orig_fmt_len;
+
+  for (;;)
+    {
+    next:
+      fchar = *fmt++;
+
+      if (fchar == '\0')
+	break;
+
+      if (isspace (fchar))
+	{
+	  chars += skip_white (funs, data);
+	  continue;
+	}
+
+      if (fchar != '%')
+	{
+	  int  c;
+	literal:
+	  c = (funs->get) (data);
+	  if (c != fchar)
+	    {
+	      (funs->unget) (c, data);
+	      if (c == EOF)
+		{
+		eof_no_match:
+		  if (fields == 0)
+		    fields = EOF;
+		}
+	      goto done;
+	    }
+	  chars++;
+	  continue;
+	}
+
+      param.type = '\0';
+      param.base = 0;	 /* for e,f,g,i */
+      param.ignore = 0;
+      param.width = 0;
+
+      this_fmt = fmt-1;
+      TRACE (printf ("	this_fmt \"%s\"\n", this_fmt));
+
+      for (;;)
+	{
+	  ASSERT (fmt <= end_fmt);
+
+	  fchar = *fmt++;
+	  switch (fchar) {
+
+	  case '\0':  /* unterminated % sequence */
+	    ASSERT (0);
+	    goto done;
+
+	  case '%':   /* literal % */
+	    goto literal;
+
+	  case '[':   /* character range */
+	    fchar = *fmt++;
+	    if (fchar == '^')
+	      fchar = *fmt++;
+	    /* ']' allowed as the first char (possibly after '^') */
+	    if (fchar == ']')
+	      fchar = *fmt++;
+	    for (;;)
+	      {
+		ASSERT (fmt <= end_fmt);
+		if (fchar == '\0')
+		  {
+		    /* unterminated % sequence */
+		    ASSERT (0);
+		    goto done;
+		  }
+		if (fchar == ']')
+		  break;
+		fchar = *fmt++;
+	      }
+	    /*FALLTHRU*/
+	  case 'c':   /* characters */
+	  case 's':   /* string of non-whitespace */
+	  case 'p':   /* pointer */
+	  libc_type:
+	    len = fmt - this_fmt;
+	    memcpy (alloc_fmt, this_fmt, len);
+	    alloc_fmt[len++] = '%';
+	    alloc_fmt[len++] = 'n';
+	    alloc_fmt[len] = '\0';
+
+	    TRACE (printf ("  scan \"%s\"\n", alloc_fmt);
+		   if (funs->scan == (gmp_doscan_scan_t) sscanf)
+		     printf ("	s=\"%s\"\n", * (const char **) data));
+
+	    new_chars = -1;
+	    if (param.ignore)
+	      {
+		new_fields = (*funs->scan) (data, alloc_fmt, &new_chars, NULL);
+		ASSERT (new_fields == 0 || new_fields == EOF);
+	      }
+	    else
+	      {
+		void *arg = va_arg (ap, void *);
+		new_fields = (*funs->scan) (data, alloc_fmt, arg, &new_chars);
+		ASSERT (new_fields==0 || new_fields==1 || new_fields==EOF);
+
+		if (new_fields == 0)
+		  goto done;  /* invalid input */
+
+		if (new_fields == 1)
+		  ASSERT (new_chars != -1);
+	      }
+	    TRACE (printf ("  new_fields %d   new_chars %d\n",
+			   new_fields, new_chars));
+
+	    if (new_fields == -1)
+	      goto eof_no_match;  /* EOF before anything matched */
+
+	    /* Under param.ignore, when new_fields==0 we don't know if
+	       it's a successful match or an invalid field.  new_chars
+	       won't have been assigned if it was an invalid field.  */
+	    if (new_chars == -1)
+	      goto done;  /* invalid input */
+
+	    chars += new_chars;
+	    (*funs->step) (data, new_chars);
+
+	  increment_fields:
+	    if (! param.ignore)
+	      fields++;
+	    goto next;
+
+	  case 'd':   /* decimal */
+	  case 'u':   /* decimal */
+	    param.base = 10;
+	    goto numeric;
+
+	  case 'e':   /* float */
+	  case 'E':   /* float */
+	  case 'f':   /* float */
+	  case 'g':   /* float */
+	  case 'G':   /* float */
+	  case 'i':   /* integer with base marker */
+	  numeric:
+	    if (param.type != 'F' && param.type != 'Q' && param.type != 'Z')
+	      goto libc_type;
+
+	    chars += skip_white (funs, data);
+
+	    new_chars = gmpscan (funs, data, &param,
+				 param.ignore ? NULL : va_arg (ap, void*));
+	    if (new_chars == -2)
+	      goto eof_no_match;
+	    if (new_chars == -1)
+	      goto done;
+
+	    ASSERT (new_chars >= 0);
+	    chars += new_chars;
+	    goto increment_fields;
+
+	  case 'a':   /* glibc allocate string */
+	  case '\'':  /* glibc digit groupings */
+	    break;
+
+	  case 'F':   /* mpf_t */
+	  case 'j':   /* intmax_t */
+	  case 'L':   /* long long */
+	  case 'q':   /* quad_t */
+	  case 'Q':   /* mpq_t */
+	  case 't':   /* ptrdiff_t */
+	  case 'z':   /* size_t */
+	  case 'Z':   /* mpz_t */
+	  set_type:
+	    param.type = fchar;
+	    break;
+
+	  case 'h':   /* short or char */
+	    if (param.type != 'h')
+	      goto set_type;
+	    param.type = 'H';	/* internal code for "hh" */
+	    break;
+
+	    goto numeric;
+
+	  case 'l':   /* long, long long, double or long double */
+	    if (param.type != 'l')
+	      goto set_type;
+	    param.type = 'L';	/* "ll" means "L" */
+	    break;
+
+	  case 'n':
+	    if (! param.ignore)
+	      {
+		void  *p;
+		p = va_arg (ap, void *);
+		TRACE (printf ("  store %%n to %p\n", p));
+		switch (param.type) {
+		case '\0': * (int	*) p = chars; break;
+		case 'F':  mpf_set_si ((mpf_ptr) p, (long) chars); break;
+		case 'H':  * (char	*) p = chars; break;
+		case 'h':  * (short	*) p = chars; break;
+#if HAVE_INTMAX_T
+		case 'j':  * (intmax_t	*) p = chars; break;
+#else
+		case 'j':  ASSERT_FAIL (intmax_t not available); break;
+#endif
+		case 'l':  * (long	*) p = chars; break;
+#if HAVE_QUAD_T && HAVE_LONG_LONG
+		case 'q':
+		  ASSERT_ALWAYS (sizeof (quad_t) == sizeof (long long));
+		  /*FALLTHRU*/
+#else
+		case 'q':  ASSERT_FAIL (quad_t not available); break;
+#endif
+#if HAVE_LONG_LONG
+		case 'L':  * (long long *) p = chars; break;
+#else
+		case 'L':  ASSERT_FAIL (long long not available); break;
+#endif
+		case 'Q':  mpq_set_si ((mpq_ptr) p, (long) chars, 1L); break;
+#if HAVE_PTRDIFF_T
+		case 't':  * (ptrdiff_t *) p = chars; break;
+#else
+		case 't':  ASSERT_FAIL (ptrdiff_t not available); break;
+#endif
+		case 'z':  * (size_t	*) p = chars; break;
+		case 'Z':  mpz_set_si ((mpz_ptr) p, (long) chars); break;
+		default: ASSERT (0); break;
+		}
+	      }
+	    goto next;
+
+	  case 'o':
+	    param.base = 8;
+	    goto numeric;
+
+	  case 'x':
+	  case 'X':
+	    param.base = 16;
+	    goto numeric;
+
+	  case '0': case '1': case '2': case '3': case '4':
+	  case '5': case '6': case '7': case '8': case '9':
+	    param.width = 0;
+	    do {
+	      param.width = param.width * 10 + (fchar-'0');
+	      fchar = *fmt++;
+	    } while (isdigit (fchar));
+	    fmt--; /* unget the non-digit */
+	    break;
+
+	  case '*':
+	    param.ignore = 1;
+	    break;
+
+	  default:
+	    /* something invalid in a % sequence */
+	    ASSERT (0);
+	    goto next;
+	  }
+	}
+    }
+
+ done:
+  (*__gmp_free_func) (alloc_fmt, alloc_fmt_size);
+  return fields;
+}
diff --git a/third_party/gmp/scanf/fscanf.c b/third_party/gmp/scanf/fscanf.c
new file mode 100644
index 0000000..ce74aa4
--- /dev/null
+++ b/third_party/gmp/scanf/fscanf.c
@@ -0,0 +1,47 @@
+/* gmp_fscanf -- formatted input from a FILE.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "gmp-impl.h"
+
+
+int
+gmp_fscanf (FILE *fp, const char *fmt, ...)
+{
+  va_list  ap;
+  int      ret;
+  va_start (ap, fmt);
+
+  ret = __gmp_doscan (&__gmp_fscanf_funs, fp, fmt, ap);
+  va_end (ap);
+  return ret;
+}
diff --git a/third_party/gmp/scanf/fscanffuns.c b/third_party/gmp/scanf/fscanffuns.c
new file mode 100644
index 0000000..f2d2939
--- /dev/null
+++ b/third_party/gmp/scanf/fscanffuns.c
@@ -0,0 +1,61 @@
+/* __gmp_fscanf_funs -- support for formatted input from a FILE.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp-impl.h"
+
+
+/* SunOS 4 stdio.h doesn't provide prototypes for these */
+#if ! HAVE_DECL_FGETC
+int fgetc (FILE *);
+#endif
+#if ! HAVE_DECL_FSCANF
+int fscanf (FILE *, const char *, ...);
+#endif
+#if ! HAVE_DECL_UNGETC
+int ungetc (int, FILE *);
+#endif
+
+
+static void
+step (FILE *fp, int n)
+{
+}
+
+const struct gmp_doscan_funs_t  __gmp_fscanf_funs = {
+  (gmp_doscan_scan_t)  fscanf,
+  (gmp_doscan_step_t)  step,
+  (gmp_doscan_get_t)   fgetc,
+  (gmp_doscan_unget_t) ungetc,
+};
diff --git a/third_party/gmp/scanf/scanf.c b/third_party/gmp/scanf/scanf.c
new file mode 100644
index 0000000..645188c
--- /dev/null
+++ b/third_party/gmp/scanf/scanf.c
@@ -0,0 +1,47 @@
+/* gmp_scanf -- formatted input from stdin.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "gmp-impl.h"
+
+
+int
+gmp_scanf (const char *fmt, ...)
+{
+  va_list  ap;
+  int      ret;
+  va_start (ap, fmt);
+
+  ret = __gmp_doscan (&__gmp_fscanf_funs, stdin, fmt, ap);
+  va_end (ap);
+  return ret;
+}
diff --git a/third_party/gmp/scanf/sscanf.c b/third_party/gmp/scanf/sscanf.c
new file mode 100644
index 0000000..4486b83
--- /dev/null
+++ b/third_party/gmp/scanf/sscanf.c
@@ -0,0 +1,52 @@
+/* gmp_sscanf -- formatted input from a string.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "gmp-impl.h"
+
+
+int
+gmp_sscanf (const char *s, const char *fmt, ...)
+{
+  va_list  ap;
+  int      ret;
+  va_start (ap, fmt);
+
+#if SSCANF_WRITABLE_INPUT
+  /* let gmp_vsscanf handle the copying */
+  ret = gmp_vsscanf (s, fmt, ap);
+#else
+  ret = __gmp_doscan (&__gmp_sscanf_funs, (void *) &s, fmt, ap);
+#endif
+  va_end (ap);
+  return ret;
+}
diff --git a/third_party/gmp/scanf/sscanffuns.c b/third_party/gmp/scanf/sscanffuns.c
new file mode 100644
index 0000000..3ee6b63
--- /dev/null
+++ b/third_party/gmp/scanf/sscanffuns.c
@@ -0,0 +1,123 @@
+/* __gmp_sscanf_funs -- support for formatted input from a string.
+
+   THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
+   CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
+   FUTURE GNU MP RELEASES.
+
+Copyright 2001-2003, 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include "gmp-impl.h"
+
+
+#if 0
+static int
+scan (const char **sp, const char *fmt, ...)
+{
+    va_list ap;
+    int ret;
+
+    va_start(ap, fmt);
+    ret = vsscanf(*sp, fmt, ap);
+    va_end(ap);
+
+    return ret;
+}
+#else
+static int
+scan (const char **sp, const char *fmt, ...)
+{
+  va_list ap;
+  void *p1, *p2;
+  int ret;
+
+  va_start (ap, fmt);
+  p1 = va_arg (ap, void *);
+  p2 = va_arg (ap, void *);
+
+  ret = sscanf (*sp, fmt, p1, p2);
+
+  va_end (ap);
+
+  return ret;
+}
+#endif
+
+static void
+step (const char **sp, int n)
+{
+  ASSERT (n >= 0);
+
+  /* shouldn't push us past the end of the string */
+#if WANT_ASSERT
+  {
+    int  i;
+    for (i = 0; i < n; i++)
+      ASSERT ((*sp)[i] != '\0');
+  }
+#endif
+
+  (*sp) += n;
+}
+
+static int
+get (const char **sp)
+{
+  const char  *s;
+  int  c;
+  s = *sp;
+  c = (unsigned char) *s++;
+  if (c == '\0')
+    return EOF;
+  *sp = s;
+  return c;
+}
+
+static void
+unget (int c, const char **sp)
+{
+  const char  *s;
+  s = *sp;
+  if (c == EOF)
+    {
+      ASSERT (*s == '\0');
+      return;
+    }
+  s--;
+  ASSERT ((unsigned char) *s == c);
+  *sp = s;
+}
+
+const struct gmp_doscan_funs_t  __gmp_sscanf_funs = {
+  (gmp_doscan_scan_t)  scan,
+  (gmp_doscan_step_t)  step,
+  (gmp_doscan_get_t)   get,
+  (gmp_doscan_unget_t) unget,
+};
diff --git a/third_party/gmp/scanf/vfscanf.c b/third_party/gmp/scanf/vfscanf.c
new file mode 100644
index 0000000..98b810a
--- /dev/null
+++ b/third_party/gmp/scanf/vfscanf.c
@@ -0,0 +1,41 @@
+/* gmp_vfscanf -- formatted input from a FILE.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "gmp-impl.h"
+
+
+int
+gmp_vfscanf (FILE *fp, const char *fmt, va_list ap)
+{
+  return __gmp_doscan (&__gmp_fscanf_funs, fp, fmt, ap);
+}
diff --git a/third_party/gmp/scanf/vscanf.c b/third_party/gmp/scanf/vscanf.c
new file mode 100644
index 0000000..2a8cfc1
--- /dev/null
+++ b/third_party/gmp/scanf/vscanf.c
@@ -0,0 +1,42 @@
+/* gmp_vscanf -- formatted input from stdin.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+
+#include <stdio.h>
+
+#include "gmp-impl.h"
+
+
+int
+gmp_vscanf (const char *fmt, va_list ap)
+{
+  return __gmp_doscan (&__gmp_fscanf_funs, stdin, fmt, ap);
+}
diff --git a/third_party/gmp/scanf/vsscanf.c b/third_party/gmp/scanf/vsscanf.c
new file mode 100644
index 0000000..7c7b98a
--- /dev/null
+++ b/third_party/gmp/scanf/vsscanf.c
@@ -0,0 +1,60 @@
+/* gmp_vsscanf -- formatted input from a string.
+
+Copyright 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdarg.h>
+
+#include <string.h>
+
+#include "gmp-impl.h"
+
+
+int
+gmp_vsscanf (const char *s, const char *fmt, va_list ap)
+{
+#if SSCANF_WRITABLE_INPUT
+  /* We only actually need this if there's standard C types in fmt, and if
+     "s" is not already writable, but it's too much trouble to check that,
+     and in any case this writable sscanf input business is only for a few
+     old systems. */
+  size_t size;
+  char   *alloc;
+  int    ret;
+  size = strlen (s) + 1;
+  alloc = __GMP_ALLOCATE_FUNC_TYPE (size, char);
+  memcpy (alloc, s, size);
+  s = alloc;
+  ret = __gmp_doscan (&__gmp_sscanf_funs, (void *) &s, fmt, ap);
+  (*__gmp_free_func) (alloc, size);
+  return ret;
+
+#else
+  return __gmp_doscan (&__gmp_sscanf_funs, (void *) &s, fmt, ap);
+#endif
+}
diff --git a/third_party/gmp/tal-debug.c b/third_party/gmp/tal-debug.c
new file mode 100644
index 0000000..38c27aa
--- /dev/null
+++ b/third_party/gmp/tal-debug.c
@@ -0,0 +1,150 @@
+/* TMP_ALLOC routines for debugging.
+
+Copyright 2000, 2001, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "gmp-impl.h"
+
+
+/* This method aims to help a malloc debugger find problems.  A linked list
+   of allocated block is kept for TMP_FREE to release.  This is reentrant
+   and thread safe.
+
+   Each TMP_ALLOC is a separate malloced block, so redzones or sentinels
+   applied by a malloc debugger either above or below can guard against
+   accesses outside the allocated area.
+
+   A marker is a "struct tmp_debug_t *" so that TMP_DECL can initialize it
+   to NULL and we can detect TMP_ALLOC without TMP_MARK.
+
+   It will work to realloc an MPZ_TMP_INIT variable, but when TMP_FREE comes
+   to release the memory it will have the old size, thereby triggering an
+   error from tests/memory.c.
+
+   Possibilities:
+
+   It'd be possible to keep a global list of active "struct tmp_debug_t"
+   records, so at the end of a program any TMP leaks could be printed.  But
+   if only a couple of routines are under test at any one time then the
+   likely culprit should be easy enough to spot.  */
+
+
+void
+__gmp_tmp_debug_mark (const char *file, int line,
+                      struct tmp_debug_t **markp, struct tmp_debug_t *mark,
+                      const char *decl_name, const char *mark_name)
+{
+  if (strcmp (mark_name, decl_name) != 0)
+    {
+      __gmp_assert_header (file, line);
+      fprintf (stderr, "GNU MP: TMP_MARK(%s) but TMP_DECL(%s) is in scope\n",
+               mark_name, decl_name);
+      abort ();
+    }
+
+  if (*markp != NULL)
+    {
+      __gmp_assert_header (file, line);
+      fprintf (stderr, "GNU MP: Repeat of TMP_MARK(%s)\n", mark_name);
+      if (mark->file != NULL && mark->file[0] != '\0' && mark->line != -1)
+        {
+          __gmp_assert_header (mark->file, mark->line);
+          fprintf (stderr, "previous was here\n");
+        }
+      abort ();
+    }
+
+  *markp = mark;
+  mark->file = file;
+  mark->line = line;
+  mark->list = NULL;
+}
+
+void *
+__gmp_tmp_debug_alloc (const char *file, int line, int dummy,
+                       struct tmp_debug_t **markp,
+                       const char *decl_name, size_t size)
+{
+  struct tmp_debug_t        *mark = *markp;
+  struct tmp_debug_entry_t  *p;
+
+  ASSERT_ALWAYS (size >= 1);
+
+  if (mark == NULL)
+    {
+      __gmp_assert_header (file, line);
+      fprintf (stderr, "GNU MP: TMP_ALLOC without TMP_MARK(%s)\n", decl_name);
+      abort ();
+    }
+
+  p = __GMP_ALLOCATE_FUNC_TYPE (1, struct tmp_debug_entry_t);
+  p->size = size;
+  p->block = (*__gmp_allocate_func) (size);
+  p->next = mark->list;
+  mark->list = p;
+  return p->block;
+}
+
+void
+__gmp_tmp_debug_free (const char *file, int line, int dummy,
+                      struct tmp_debug_t **markp,
+                      const char *decl_name, const char *free_name)
+{
+  struct tmp_debug_t        *mark = *markp;
+  struct tmp_debug_entry_t  *p, *next;
+
+  if (mark == NULL)
+    {
+      __gmp_assert_header (file, line);
+      fprintf (stderr, "GNU MP: TMP_FREE(%s) without TMP_MARK(%s)\n",
+               free_name, decl_name);
+      abort ();
+    }
+
+  if (strcmp (free_name, decl_name) != 0)
+    {
+      __gmp_assert_header (file, line);
+      fprintf (stderr, "GNU MP: TMP_FREE(%s) when TMP_DECL(%s) is in scope\n",
+               free_name, decl_name);
+      abort ();
+    }
+
+  p = mark->list;
+  while (p != NULL)
+    {
+      next = p->next;
+      (*__gmp_free_func) (p->block, p->size);
+      __GMP_FREE_FUNC_TYPE (p, 1, struct tmp_debug_entry_t);
+      p = next;
+    }
+
+  *markp = NULL;
+}
diff --git a/third_party/gmp/tal-notreent.c b/third_party/gmp/tal-notreent.c
new file mode 100644
index 0000000..083fa84
--- /dev/null
+++ b/third_party/gmp/tal-notreent.c
@@ -0,0 +1,129 @@
+/* Stack allocation routines.  This is intended for machines without support
+   for the `alloca' function.
+
+Copyright 1996, 1997, 1999-2001, 2006 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+
+struct tmp_stack
+{
+  void *end;
+  void *alloc_point;
+  struct tmp_stack *prev;
+};
+typedef struct tmp_stack tmp_stack;
+
+
+static unsigned long max_total_allocation = 0;
+static unsigned long current_total_allocation = 0;
+
+static tmp_stack xxx = {&xxx, &xxx, 0};
+static tmp_stack *current = &xxx;
+
+/* The rounded size of the header of each allocation block.  */
+#define HSIZ   ROUND_UP_MULTIPLE (sizeof (tmp_stack), __TMP_ALIGN)
+
+
+/* Allocate a block of exactly <size> bytes.  This should only be called
+   through the TMP_ALLOC macro, which takes care of rounding/alignment.  */
+void *
+__gmp_tmp_alloc (unsigned long size)
+{
+  void *that;
+
+  ASSERT ((size % __TMP_ALIGN) == 0);
+  ASSERT (((unsigned) current->alloc_point % __TMP_ALIGN) == 0);
+
+  if (size > (char *) current->end - (char *) current->alloc_point)
+    {
+      void *chunk;
+      tmp_stack *header;
+      unsigned long chunk_size;
+      unsigned long now;
+
+      /* Allocate a chunk that makes the total current allocation somewhat
+	 larger than the maximum allocation ever.  If size is very large, we
+	 allocate that much.  */
+
+      now = current_total_allocation + size;
+      if (now > max_total_allocation)
+	{
+	  /* We need more temporary memory than ever before.  Increase
+	     for future needs.  */
+	  now = (now * 3 / 2 + __TMP_ALIGN - 1) & -__TMP_ALIGN;
+	  chunk_size = now - current_total_allocation + HSIZ;
+	  current_total_allocation = now;
+	  max_total_allocation = current_total_allocation;
+	}
+      else
+	{
+	  chunk_size = max_total_allocation - current_total_allocation + HSIZ;
+	  current_total_allocation = max_total_allocation;
+	}
+
+      chunk = (*__gmp_allocate_func) (chunk_size);
+      header = (tmp_stack *) chunk;
+      header->end = (char *) chunk + chunk_size;
+      header->alloc_point = (char *) chunk + HSIZ;
+      header->prev = current;
+      current = header;
+    }
+
+  that = current->alloc_point;
+  current->alloc_point = (char *) that + size;
+  ASSERT (((unsigned) that % __TMP_ALIGN) == 0);
+  return that;
+}
+
+/* Typically called at function entry.  <mark> is assigned so that
+   __gmp_tmp_free can later be used to reclaim all subsequently allocated
+   storage.  */
+void
+__gmp_tmp_mark (struct tmp_marker *mark)
+{
+  mark->which_chunk = current;
+  mark->alloc_point = current->alloc_point;
+}
+
+/* Free everything allocated since <mark> was assigned by __gmp_tmp_mark */
+void
+__gmp_tmp_free (struct tmp_marker *mark)
+{
+  while (mark->which_chunk != current)
+    {
+      tmp_stack *tmp;
+
+      tmp = current;
+      current = tmp->prev;
+      current_total_allocation -= (((char *) (tmp->end) - (char *) tmp) - HSIZ);
+      (*__gmp_free_func) (tmp, (char *) tmp->end - (char *) tmp);
+    }
+  current->alloc_point = mark->alloc_point;
+}
diff --git a/third_party/gmp/tal-reent.c b/third_party/gmp/tal-reent.c
new file mode 100644
index 0000000..fb43e06
--- /dev/null
+++ b/third_party/gmp/tal-reent.c
@@ -0,0 +1,81 @@
+/* TMP_ALLOC routines using malloc in a reentrant fashion.
+
+Copyright 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp-impl.h"
+
+
+/* Each TMP_ALLOC uses __gmp_allocate_func to get a block of memory of the
+   size requested, plus a header at the start which is used to hold the
+   blocks on a linked list in the marker variable, ready for TMP_FREE to
+   release.
+
+   Callers should try to do multiple allocs with one call, in the style of
+   TMP_ALLOC_LIMBS_2 if it's easy to arrange, since that will keep down the
+   number of separate malloc calls.
+
+   Enhancements:
+
+   Could inline both TMP_ALLOC and TMP_FREE, though TMP_ALLOC would need the
+   compiler to have "inline" since it returns a value.  The calls to malloc
+   will be slow though, so it hardly seems worth worrying about one extra
+   level of function call.  */
+
+
+#define HSIZ   ROUND_UP_MULTIPLE (sizeof (struct tmp_reentrant_t), __TMP_ALIGN)
+
+void *
+__gmp_tmp_reentrant_alloc (struct tmp_reentrant_t **markp, size_t size)
+{
+  char    *p;
+  size_t  total_size;
+
+#define P   ((struct tmp_reentrant_t *) p)
+
+  total_size = size + HSIZ;
+  p = __GMP_ALLOCATE_FUNC_TYPE (total_size, char);
+  P->size = total_size;
+  P->next = *markp;
+  *markp = P;
+  return p + HSIZ;
+}
+
+void
+__gmp_tmp_reentrant_free (struct tmp_reentrant_t *mark)
+{
+  struct tmp_reentrant_t  *next;
+
+  while (mark != NULL)
+    {
+      next = mark->next;
+      (*__gmp_free_func) ((char *) mark, mark->size);
+      mark = next;
+    }
+}
diff --git a/third_party/gmp/test-driver b/third_party/gmp/test-driver
new file mode 100755
index 0000000..8e575b0
--- /dev/null
+++ b/third_party/gmp/test-driver
@@ -0,0 +1,148 @@
+#! /bin/sh
+# test-driver - basic testsuite driver script.
+
+scriptversion=2013-07-13.22; # UTC
+
+# Copyright (C) 2011-2014 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+# Make unconditional expansion of undefined variables an error.  This
+# helps a lot in preventing typo-related bugs.
+set -u
+
+usage_error ()
+{
+  echo "$0: $*" >&2
+  print_usage >&2
+  exit 2
+}
+
+print_usage ()
+{
+  cat <<END
+Usage:
+  test-driver --test-name=NAME --log-file=PATH --trs-file=PATH
+              [--expect-failure={yes|no}] [--color-tests={yes|no}]
+              [--enable-hard-errors={yes|no}] [--]
+              TEST-SCRIPT [TEST-SCRIPT-ARGUMENTS]
+The '--test-name', '--log-file' and '--trs-file' options are mandatory.
+END
+}
+
+test_name= # Used for reporting.
+log_file=  # Where to save the output of the test script.
+trs_file=  # Where to save the metadata of the test run.
+expect_failure=no
+color_tests=no
+enable_hard_errors=yes
+while test $# -gt 0; do
+  case $1 in
+  --help) print_usage; exit $?;;
+  --version) echo "test-driver $scriptversion"; exit $?;;
+  --test-name) test_name=$2; shift;;
+  --log-file) log_file=$2; shift;;
+  --trs-file) trs_file=$2; shift;;
+  --color-tests) color_tests=$2; shift;;
+  --expect-failure) expect_failure=$2; shift;;
+  --enable-hard-errors) enable_hard_errors=$2; shift;;
+  --) shift; break;;
+  -*) usage_error "invalid option: '$1'";;
+   *) break;;
+  esac
+  shift
+done
+
+missing_opts=
+test x"$test_name" = x && missing_opts="$missing_opts --test-name"
+test x"$log_file"  = x && missing_opts="$missing_opts --log-file"
+test x"$trs_file"  = x && missing_opts="$missing_opts --trs-file"
+if test x"$missing_opts" != x; then
+  usage_error "the following mandatory options are missing:$missing_opts"
+fi
+
+if test $# -eq 0; then
+  usage_error "missing argument"
+fi
+
+if test $color_tests = yes; then
+  # Keep this in sync with 'lib/am/check.am:$(am__tty_colors)'.
+  red='' # Red.
+  grn='' # Green.
+  lgn='' # Light green.
+  blu='' # Blue.
+  mgn='' # Magenta.
+  std=''     # No color.
+else
+  red= grn= lgn= blu= mgn= std=
+fi
+
+do_exit='rm -f $log_file $trs_file; (exit $st); exit $st'
+trap "st=129; $do_exit" 1
+trap "st=130; $do_exit" 2
+trap "st=141; $do_exit" 13
+trap "st=143; $do_exit" 15
+
+# Test script is run here.
+"$@" >$log_file 2>&1
+estatus=$?
+
+if test $enable_hard_errors = no && test $estatus -eq 99; then
+  tweaked_estatus=1
+else
+  tweaked_estatus=$estatus
+fi
+
+case $tweaked_estatus:$expect_failure in
+  0:yes) col=$red res=XPASS recheck=yes gcopy=yes;;
+  0:*)   col=$grn res=PASS  recheck=no  gcopy=no;;
+  77:*)  col=$blu res=SKIP  recheck=no  gcopy=yes;;
+  99:*)  col=$mgn res=ERROR recheck=yes gcopy=yes;;
+  *:yes) col=$lgn res=XFAIL recheck=no  gcopy=yes;;
+  *:*)   col=$red res=FAIL  recheck=yes gcopy=yes;;
+esac
+
+# Report the test outcome and exit status in the logs, so that one can
+# know whether the test passed or failed simply by looking at the '.log'
+# file, without the need of also peaking into the corresponding '.trs'
+# file (automake bug#11814).
+echo "$res $test_name (exit status: $estatus)" >>$log_file
+
+# Report outcome to console.
+echo "${col}${res}${std}: $test_name"
+
+# Register the test result, and other relevant metadata.
+echo ":test-result: $res" > $trs_file
+echo ":global-test-result: $res" >> $trs_file
+echo ":recheck: $recheck" >> $trs_file
+echo ":copy-in-global-log: $gcopy" >> $trs_file
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/third_party/gmp/tests/Makefile.am b/third_party/gmp/tests/Makefile.am
new file mode 100644
index 0000000..ff42b66
--- /dev/null
+++ b/third_party/gmp/tests/Makefile.am
@@ -0,0 +1,40 @@
+## Process this file with automake to generate Makefile.in
+
+# Copyright 2000-2004, 2013 Free Software Foundation, Inc.
+#
+# This file is part of the GNU MP Library test suite.
+#
+# The GNU MP Library test suite is free software; you can redistribute it
+# and/or modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 3 of the License,
+# or (at your option) any later version.
+#
+# The GNU MP Library test suite is distributed in the hope that it will be
+# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.
+
+
+SUBDIRS = . devel mpn mpz mpq mpf rand misc cxx
+
+include ../mpn/Makeasm.am
+
+AM_CPPFLAGS = -I$(top_srcdir)
+AM_LDFLAGS = -no-install
+LDADD = libtests.la $(top_builddir)/libgmp.la
+
+check_LTLIBRARIES = libtests.la
+
+EXTRA_libtests_la_SOURCES = amd64call.asm amd64check.c x86call.asm x86check.c \
+    arm32call.asm arm32check.c
+libtests_la_SOURCES = tests.h \
+  memory.c misc.c refmpf.c refmpn.c refmpq.c refmpz.c spinner.c trace.c
+libtests_la_DEPENDENCIES = @CALLING_CONVENTIONS_OBJS@
+libtests_la_LIBADD = $(libtests_la_DEPENDENCIES) $(top_builddir)/libgmp.la
+
+check_PROGRAMS = t-bswap t-constants t-count_zeros t-hightomask \
+  t-modlinv t-popc t-parity t-sub
+TESTS = $(check_PROGRAMS)
diff --git a/third_party/gmp/tests/Makefile.in b/third_party/gmp/tests/Makefile.in
new file mode 100644
index 0000000..073c9f3
--- /dev/null
+++ b/third_party/gmp/tests/Makefile.in
@@ -0,0 +1,1369 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Copyright 2000-2004, 2013 Free Software Foundation, Inc.
+#
+# This file is part of the GNU MP Library test suite.
+#
+# The GNU MP Library test suite is free software; you can redistribute it
+# and/or modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 3 of the License,
+# or (at your option) any later version.
+#
+# The GNU MP Library test suite is distributed in the hope that it will be
+# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.
+
+# Copyright 1996, 1998-2002 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+check_PROGRAMS = t-bswap$(EXEEXT) t-constants$(EXEEXT) \
+	t-count_zeros$(EXEEXT) t-hightomask$(EXEEXT) \
+	t-modlinv$(EXEEXT) t-popc$(EXEEXT) t-parity$(EXEEXT) \
+	t-sub$(EXEEXT)
+subdir = tests
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__DEPENDENCIES_1 =
+am_libtests_la_OBJECTS = memory.lo misc.lo refmpf.lo refmpn.lo \
+	refmpq.lo refmpz.lo spinner.lo trace.lo
+libtests_la_OBJECTS = $(am_libtests_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+t_bswap_SOURCES = t-bswap.c
+t_bswap_OBJECTS = t-bswap.$(OBJEXT)
+t_bswap_LDADD = $(LDADD)
+t_bswap_DEPENDENCIES = libtests.la $(top_builddir)/libgmp.la
+t_constants_SOURCES = t-constants.c
+t_constants_OBJECTS = t-constants.$(OBJEXT)
+t_constants_LDADD = $(LDADD)
+t_constants_DEPENDENCIES = libtests.la $(top_builddir)/libgmp.la
+t_count_zeros_SOURCES = t-count_zeros.c
+t_count_zeros_OBJECTS = t-count_zeros.$(OBJEXT)
+t_count_zeros_LDADD = $(LDADD)
+t_count_zeros_DEPENDENCIES = libtests.la $(top_builddir)/libgmp.la
+t_hightomask_SOURCES = t-hightomask.c
+t_hightomask_OBJECTS = t-hightomask.$(OBJEXT)
+t_hightomask_LDADD = $(LDADD)
+t_hightomask_DEPENDENCIES = libtests.la $(top_builddir)/libgmp.la
+t_modlinv_SOURCES = t-modlinv.c
+t_modlinv_OBJECTS = t-modlinv.$(OBJEXT)
+t_modlinv_LDADD = $(LDADD)
+t_modlinv_DEPENDENCIES = libtests.la $(top_builddir)/libgmp.la
+t_parity_SOURCES = t-parity.c
+t_parity_OBJECTS = t-parity.$(OBJEXT)
+t_parity_LDADD = $(LDADD)
+t_parity_DEPENDENCIES = libtests.la $(top_builddir)/libgmp.la
+t_popc_SOURCES = t-popc.c
+t_popc_OBJECTS = t-popc.$(OBJEXT)
+t_popc_LDADD = $(LDADD)
+t_popc_DEPENDENCIES = libtests.la $(top_builddir)/libgmp.la
+t_sub_SOURCES = t-sub.c
+t_sub_OBJECTS = t-sub.$(OBJEXT)
+t_sub_LDADD = $(LDADD)
+t_sub_DEPENDENCIES = libtests.la $(top_builddir)/libgmp.la
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp =
+am__depfiles_maybe =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+SOURCES = $(libtests_la_SOURCES) $(EXTRA_libtests_la_SOURCES) \
+	t-bswap.c t-constants.c t-count_zeros.c t-hightomask.c \
+	t-modlinv.c t-parity.c t-popc.c t-sub.c
+DIST_SOURCES = $(libtests_la_SOURCES) $(EXTRA_libtests_la_SOURCES) \
+	t-bswap.c t-constants.c t-count_zeros.c t-hightomask.c \
+	t-modlinv.c t-parity.c t-popc.c t-sub.c
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+	ctags-recursive dvi-recursive html-recursive info-recursive \
+	install-data-recursive install-dvi-recursive \
+	install-exec-recursive install-html-recursive \
+	install-info-recursive install-pdf-recursive \
+	install-ps-recursive install-recursive installcheck-recursive \
+	installdirs-recursive pdf-recursive ps-recursive \
+	tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive	\
+  distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+  $(RECURSIVE_TARGETS) \
+  $(RECURSIVE_CLEAN_TARGETS) \
+  $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+	check recheck distdir
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__tty_colors_dummy = \
+  mgn= red= grn= lgn= blu= brg= std=; \
+  am__color_tests=no
+am__tty_colors = { \
+  $(am__tty_colors_dummy); \
+  if test "X$(AM_COLOR_TESTS)" = Xno; then \
+    am__color_tests=no; \
+  elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+    am__color_tests=yes; \
+  elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+    am__color_tests=yes; \
+  fi; \
+  if test $$am__color_tests = yes; then \
+    red=''; \
+    grn=''; \
+    lgn=''; \
+    blu=''; \
+    mgn=''; \
+    brg=''; \
+    std=''; \
+  fi; \
+}
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+  test -z "$$files" \
+    || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+    || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+         $(am__cd) "$$dir" && rm -f $$files; }; \
+  }
+am__recheck_rx = ^[ 	]*:recheck:[ 	]*
+am__global_test_result_rx = ^[ 	]*:global-test-result:[ 	]*
+am__copy_in_global_log_rx = ^[ 	]*:copy-in-global-log:[ 	]*
+# A command that, given a newline-separated list of test names on the
+# standard input, print the name of the tests that are to be re-run
+# upon "make recheck".
+am__list_recheck_tests = $(AWK) '{ \
+  recheck = 1; \
+  while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+    { \
+      if (rc < 0) \
+        { \
+          if ((getline line2 < ($$0 ".log")) < 0) \
+	    recheck = 0; \
+          break; \
+        } \
+      else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \
+        { \
+          recheck = 0; \
+          break; \
+        } \
+      else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \
+        { \
+          break; \
+        } \
+    }; \
+  if (recheck) \
+    print $$0; \
+  close ($$0 ".trs"); \
+  close ($$0 ".log"); \
+}'
+# A command that, given a newline-separated list of test names on the
+# standard input, create the global log from their .trs and .log files.
+am__create_global_log = $(AWK) ' \
+function fatal(msg) \
+{ \
+  print "fatal: making $@: " msg | "cat >&2"; \
+  exit 1; \
+} \
+function rst_section(header) \
+{ \
+  print header; \
+  len = length(header); \
+  for (i = 1; i <= len; i = i + 1) \
+    printf "="; \
+  printf "\n\n"; \
+} \
+{ \
+  copy_in_global_log = 1; \
+  global_test_result = "RUN"; \
+  while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+    { \
+      if (rc < 0) \
+         fatal("failed to read from " $$0 ".trs"); \
+      if (line ~ /$(am__global_test_result_rx)/) \
+        { \
+          sub("$(am__global_test_result_rx)", "", line); \
+          sub("[ 	]*$$", "", line); \
+          global_test_result = line; \
+        } \
+      else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \
+        copy_in_global_log = 0; \
+    }; \
+  if (copy_in_global_log) \
+    { \
+      rst_section(global_test_result ": " $$0); \
+      while ((rc = (getline line < ($$0 ".log"))) != 0) \
+      { \
+        if (rc < 0) \
+          fatal("failed to read from " $$0 ".log"); \
+        print line; \
+      }; \
+      printf "\n"; \
+    }; \
+  close ($$0 ".trs"); \
+  close ($$0 ".log"); \
+}'
+# Restructured Text title.
+am__rst_title = { sed 's/.*/   &   /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; }
+# Solaris 10 'make', and several other traditional 'make' implementations,
+# pass "-e" to $(SHELL), and POSIX 2008 even requires this.  Work around it
+# by disabling -e (using the XSI extension "set +e") if it's set.
+am__sh_e_setup = case $$- in *e*) set +e;; esac
+# Default flags passed to test drivers.
+am__common_driver_flags = \
+  --color-tests "$$am__color_tests" \
+  --enable-hard-errors "$$am__enable_hard_errors" \
+  --expect-failure "$$am__expect_failure"
+# To be inserted before the command running the test.  Creates the
+# directory for the log if needed.  Stores in $dir the directory
+# containing $f, in $tst the test, in $log the log.  Executes the
+# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and
+# passes TESTS_ENVIRONMENT.  Set up options for the wrapper that
+# will run the test scripts (or their associated LOG_COMPILER, if
+# thy have one).
+am__check_pre = \
+$(am__sh_e_setup);					\
+$(am__vpath_adj_setup) $(am__vpath_adj)			\
+$(am__tty_colors);					\
+srcdir=$(srcdir); export srcdir;			\
+case "$@" in						\
+  */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;;	\
+    *) am__odir=.;; 					\
+esac;							\
+test "x$$am__odir" = x"." || test -d "$$am__odir" 	\
+  || $(MKDIR_P) "$$am__odir" || exit $$?;		\
+if test -f "./$$f"; then dir=./;			\
+elif test -f "$$f"; then dir=;				\
+else dir="$(srcdir)/"; fi;				\
+tst=$$dir$$f; log='$@'; 				\
+if test -n '$(DISABLE_HARD_ERRORS)'; then		\
+  am__enable_hard_errors=no; 				\
+else							\
+  am__enable_hard_errors=yes; 				\
+fi; 							\
+case " $(XFAIL_TESTS) " in				\
+  *[\ \	]$$f[\ \	]* | *[\ \	]$$dir$$f[\ \	]*) \
+    am__expect_failure=yes;;				\
+  *)							\
+    am__expect_failure=no;;				\
+esac; 							\
+$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT)
+# A shell command to get the names of the tests scripts with any registered
+# extension removed (i.e., equivalently, the names of the test logs, with
+# the '.log' extension removed).  The result is saved in the shell variable
+# '$bases'.  This honors runtime overriding of TESTS and TEST_LOGS.  Sadly,
+# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)",
+# since that might cause problem with VPATH rewrites for suffix-less tests.
+# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'.
+am__set_TESTS_bases = \
+  bases='$(TEST_LOGS)'; \
+  bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \
+  bases=`echo $$bases`
+RECHECK_LOGS = $(TEST_LOGS)
+TEST_SUITE_LOG = test-suite.log
+TEST_EXTENSIONS = @EXEEXT@ .test
+LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS)
+am__set_b = \
+  case '$@' in \
+    */*) \
+      case '$*' in \
+        */*) b='$*';; \
+          *) b=`echo '$@' | sed 's/\.log$$//'`; \
+       esac;; \
+    *) \
+      b='$*';; \
+  esac
+am__test_logs1 = $(TESTS:=.log)
+am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log)
+TEST_LOGS = $(am__test_logs2:.test.log=.log)
+TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \
+	$(TEST_LOG_FLAGS)
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/../mpn/Makeasm.am $(srcdir)/Makefile.in \
+	$(top_srcdir)/test-driver
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+  dir0=`pwd`; \
+  sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+  sed_rest='s,^[^/]*/*,,'; \
+  sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+  sed_butlast='s,/*[^/]*$$,,'; \
+  while test -n "$$dir1"; do \
+    first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+    if test "$$first" != "."; then \
+      if test "$$first" = ".."; then \
+        dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+        dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+      else \
+        first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+        if test "$$first2" = "$$first"; then \
+          dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+        else \
+          dir2="../$$dir2"; \
+        fi; \
+        dir0="$$dir0"/"$$first"; \
+      fi; \
+    fi; \
+    dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+  done; \
+  reldir="$$dir2"
+ABI = @ABI@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+ASMFLAGS = @ASMFLAGS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CALLING_CONVENTIONS_OBJS = @CALLING_CONVENTIONS_OBJS@
+CC = @CC@
+CCAS = @CCAS@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPP_FOR_BUILD = @CPP_FOR_BUILD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFN_LONG_LONG_LIMB = @DEFN_LONG_LONG_LIMB@
+DEFS = @DEFS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@
+FGREP = @FGREP@
+GMP_LDFLAGS = @GMP_LDFLAGS@
+GMP_LIMB_BITS = @GMP_LIMB_BITS@
+GMP_NAIL_BITS = @GMP_NAIL_BITS@
+GREP = @GREP@
+HAVE_CLOCK_01 = @HAVE_CLOCK_01@
+HAVE_CPUTIME_01 = @HAVE_CPUTIME_01@
+HAVE_GETRUSAGE_01 = @HAVE_GETRUSAGE_01@
+HAVE_GETTIMEOFDAY_01 = @HAVE_GETTIMEOFDAY_01@
+HAVE_HOST_CPU_FAMILY_power = @HAVE_HOST_CPU_FAMILY_power@
+HAVE_HOST_CPU_FAMILY_powerpc = @HAVE_HOST_CPU_FAMILY_powerpc@
+HAVE_SIGACTION_01 = @HAVE_SIGACTION_01@
+HAVE_SIGALTSTACK_01 = @HAVE_SIGALTSTACK_01@
+HAVE_SIGSTACK_01 = @HAVE_SIGSTACK_01@
+HAVE_STACK_T_01 = @HAVE_STACK_T_01@
+HAVE_SYS_RESOURCE_H_01 = @HAVE_SYS_RESOURCE_H_01@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCURSES = @LIBCURSES@
+LIBGMPXX_LDFLAGS = @LIBGMPXX_LDFLAGS@
+LIBGMP_DLL = @LIBGMP_DLL@
+LIBGMP_LDFLAGS = @LIBGMP_LDFLAGS@
+LIBM = @LIBM@
+LIBM_FOR_BUILD = @LIBM_FOR_BUILD@
+LIBOBJS = @LIBOBJS@
+LIBREADLINE = @LIBREADLINE@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+M4 = @M4@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPEED_CYCLECOUNTER_OBJ = @SPEED_CYCLECOUNTER_OBJ@
+STRIP = @STRIP@
+TAL_OBJECT = @TAL_OBJECT@
+TUNE_LIBS = @TUNE_LIBS@
+TUNE_SQR_OBJ = @TUNE_SQR_OBJ@
+U_FOR_BUILD = @U_FOR_BUILD@
+VERSION = @VERSION@
+WITH_READLINE_01 = @WITH_READLINE_01@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__leading_dot = @am__leading_dot@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gmp_srclinks = @gmp_srclinks@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+mpn_objects = @mpn_objects@
+mpn_objs_in_libgmp = @mpn_objs_in_libgmp@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = . devel mpn mpz mpq mpf rand misc cxx
+
+# COMPILE minus CC.
+#
+COMPILE_FLAGS = $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) $(ASMFLAGS)
+
+
+# Flags used for preprocessing (in ansi2knr rules).
+#
+PREPROCESS_FLAGS = $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS)
+
+
+# Recent versions of automake (1.5 and up for instance) append automake
+# generated suffixes to this $(SUFFIXES) list.  This is essential for us,
+# since .c must come after .s, .S and .asm.  If .c is before .s, for
+# instance, then in the mpn directory "make" will see add_n.c mentioned in
+# an explicit rule (the ansi2knr stuff) and decide it must have add_n.c,
+# even if add_n.c doesn't exist but add_n.s does.  See GNU make
+# documentation "(make)Implicit Rule Search", part 5c.
+#
+# On IRIX 6 native make this doesn't work properly though.  Somehow .c
+# remains ahead of .s, perhaps because .c.s is a builtin rule.  .asm works
+# fine though, and mpn/mips3 uses this.
+#
+SUFFIXES = .s .S .asm
+
+# can be overridden during development, eg. "make RM_TMP=: mul_1.lo"
+RM_TMP = rm -f
+AM_CPPFLAGS = -I$(top_srcdir)
+AM_LDFLAGS = -no-install
+LDADD = libtests.la $(top_builddir)/libgmp.la
+check_LTLIBRARIES = libtests.la
+EXTRA_libtests_la_SOURCES = amd64call.asm amd64check.c x86call.asm x86check.c \
+    arm32call.asm arm32check.c
+
+libtests_la_SOURCES = tests.h \
+  memory.c misc.c refmpf.c refmpn.c refmpq.c refmpz.c spinner.c trace.c
+
+libtests_la_DEPENDENCIES = @CALLING_CONVENTIONS_OBJS@
+libtests_la_LIBADD = $(libtests_la_DEPENDENCIES) $(top_builddir)/libgmp.la
+TESTS = $(check_PROGRAMS)
+all: all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .s .S .asm .c .lo .log .o .obj .test .test$(EXEEXT) .trs
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/../mpn/Makeasm.am $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu --ignore-deps tests/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu --ignore-deps tests/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+$(srcdir)/../mpn/Makeasm.am $(am__empty):
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-checkLTLIBRARIES:
+	-test -z "$(check_LTLIBRARIES)" || rm -f $(check_LTLIBRARIES)
+	@list='$(check_LTLIBRARIES)'; \
+	locs=`for p in $$list; do echo $$p; done | \
+	      sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+	      sort -u`; \
+	test -z "$$locs" || { \
+	  echo rm -f $${locs}; \
+	  rm -f $${locs}; \
+	}
+
+libtests.la: $(libtests_la_OBJECTS) $(libtests_la_DEPENDENCIES) $(EXTRA_libtests_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(LINK)  $(libtests_la_OBJECTS) $(libtests_la_LIBADD) $(LIBS)
+
+clean-checkPROGRAMS:
+	@list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
+	echo " rm -f" $$list; \
+	rm -f $$list || exit $$?; \
+	test -n "$(EXEEXT)" || exit 0; \
+	list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+	echo " rm -f" $$list; \
+	rm -f $$list
+
+t-bswap$(EXEEXT): $(t_bswap_OBJECTS) $(t_bswap_DEPENDENCIES) $(EXTRA_t_bswap_DEPENDENCIES) 
+	@rm -f t-bswap$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_bswap_OBJECTS) $(t_bswap_LDADD) $(LIBS)
+
+t-constants$(EXEEXT): $(t_constants_OBJECTS) $(t_constants_DEPENDENCIES) $(EXTRA_t_constants_DEPENDENCIES) 
+	@rm -f t-constants$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_constants_OBJECTS) $(t_constants_LDADD) $(LIBS)
+
+t-count_zeros$(EXEEXT): $(t_count_zeros_OBJECTS) $(t_count_zeros_DEPENDENCIES) $(EXTRA_t_count_zeros_DEPENDENCIES) 
+	@rm -f t-count_zeros$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_count_zeros_OBJECTS) $(t_count_zeros_LDADD) $(LIBS)
+
+t-hightomask$(EXEEXT): $(t_hightomask_OBJECTS) $(t_hightomask_DEPENDENCIES) $(EXTRA_t_hightomask_DEPENDENCIES) 
+	@rm -f t-hightomask$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_hightomask_OBJECTS) $(t_hightomask_LDADD) $(LIBS)
+
+t-modlinv$(EXEEXT): $(t_modlinv_OBJECTS) $(t_modlinv_DEPENDENCIES) $(EXTRA_t_modlinv_DEPENDENCIES) 
+	@rm -f t-modlinv$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_modlinv_OBJECTS) $(t_modlinv_LDADD) $(LIBS)
+
+t-parity$(EXEEXT): $(t_parity_OBJECTS) $(t_parity_DEPENDENCIES) $(EXTRA_t_parity_DEPENDENCIES) 
+	@rm -f t-parity$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_parity_OBJECTS) $(t_parity_LDADD) $(LIBS)
+
+t-popc$(EXEEXT): $(t_popc_OBJECTS) $(t_popc_DEPENDENCIES) $(EXTRA_t_popc_DEPENDENCIES) 
+	@rm -f t-popc$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_popc_OBJECTS) $(t_popc_LDADD) $(LIBS)
+
+t-sub$(EXEEXT): $(t_sub_OBJECTS) $(t_sub_DEPENDENCIES) $(EXTRA_t_sub_DEPENDENCIES) 
+	@rm -f t-sub$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_sub_OBJECTS) $(t_sub_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+.c.o:
+	$(AM_V_CC)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+	$(AM_V_CC)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+	$(AM_V_CC)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+#     (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+	@fail=; \
+	if $(am__make_keepgoing); then \
+	  failcom='fail=yes'; \
+	else \
+	  failcom='exit 1'; \
+	fi; \
+	dot_seen=no; \
+	target=`echo $@ | sed s/-recursive//`; \
+	case "$@" in \
+	  distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+	  *) list='$(SUBDIRS)' ;; \
+	esac; \
+	for subdir in $$list; do \
+	  echo "Making $$target in $$subdir"; \
+	  if test "$$subdir" = "."; then \
+	    dot_seen=yes; \
+	    local_target="$$target-am"; \
+	  else \
+	    local_target="$$target"; \
+	  fi; \
+	  ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+	  || eval $$failcom; \
+	done; \
+	if test "$$dot_seen" = "no"; then \
+	  $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+	fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+	  include_option=--etags-include; \
+	  empty_fix=.; \
+	else \
+	  include_option=--include; \
+	  empty_fix=; \
+	fi; \
+	list='$(SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    test ! -f $$subdir/TAGS || \
+	      set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+	  fi; \
+	done; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+# Recover from deleted '.trs' file; this should ensure that
+# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create
+# both 'foo.log' and 'foo.trs'.  Break the recipe in two subshells
+# to avoid problems with "make -n".
+.log.trs:
+	rm -f $< $@
+	$(MAKE) $(AM_MAKEFLAGS) $<
+
+# Leading 'am--fnord' is there to ensure the list of targets does not
+# expand to empty, as could happen e.g. with make check TESTS=''.
+am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck)
+am--force-recheck:
+	@:
+
+$(TEST_SUITE_LOG): $(TEST_LOGS)
+	@$(am__set_TESTS_bases); \
+	am__f_ok () { test -f "$$1" && test -r "$$1"; }; \
+	redo_bases=`for i in $$bases; do \
+	              am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \
+	            done`; \
+	if test -n "$$redo_bases"; then \
+	  redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \
+	  redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \
+	  if $(am__make_dryrun); then :; else \
+	    rm -f $$redo_logs && rm -f $$redo_results || exit 1; \
+	  fi; \
+	fi; \
+	if test -n "$$am__remaking_logs"; then \
+	  echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \
+	       "recursion detected" >&2; \
+	elif test -n "$$redo_logs"; then \
+	  am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \
+	fi; \
+	if $(am__make_dryrun); then :; else \
+	  st=0;  \
+	  errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \
+	  for i in $$redo_bases; do \
+	    test -f $$i.trs && test -r $$i.trs \
+	      || { echo "$$errmsg $$i.trs" >&2; st=1; }; \
+	    test -f $$i.log && test -r $$i.log \
+	      || { echo "$$errmsg $$i.log" >&2; st=1; }; \
+	  done; \
+	  test $$st -eq 0 || exit 1; \
+	fi
+	@$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \
+	ws='[ 	]'; \
+	results=`for b in $$bases; do echo $$b.trs; done`; \
+	test -n "$$results" || results=/dev/null; \
+	all=`  grep "^$$ws*:test-result:"           $$results | wc -l`; \
+	pass=` grep "^$$ws*:test-result:$$ws*PASS"  $$results | wc -l`; \
+	fail=` grep "^$$ws*:test-result:$$ws*FAIL"  $$results | wc -l`; \
+	skip=` grep "^$$ws*:test-result:$$ws*SKIP"  $$results | wc -l`; \
+	xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \
+	xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \
+	error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \
+	if test `expr $$fail + $$xpass + $$error` -eq 0; then \
+	  success=true; \
+	else \
+	  success=false; \
+	fi; \
+	br='==================='; br=$$br$$br$$br$$br; \
+	result_count () \
+	{ \
+	    if test x"$$1" = x"--maybe-color"; then \
+	      maybe_colorize=yes; \
+	    elif test x"$$1" = x"--no-color"; then \
+	      maybe_colorize=no; \
+	    else \
+	      echo "$@: invalid 'result_count' usage" >&2; exit 4; \
+	    fi; \
+	    shift; \
+	    desc=$$1 count=$$2; \
+	    if test $$maybe_colorize = yes && test $$count -gt 0; then \
+	      color_start=$$3 color_end=$$std; \
+	    else \
+	      color_start= color_end=; \
+	    fi; \
+	    echo "$${color_start}# $$desc $$count$${color_end}"; \
+	}; \
+	create_testsuite_report () \
+	{ \
+	  result_count $$1 "TOTAL:" $$all   "$$brg"; \
+	  result_count $$1 "PASS: " $$pass  "$$grn"; \
+	  result_count $$1 "SKIP: " $$skip  "$$blu"; \
+	  result_count $$1 "XFAIL:" $$xfail "$$lgn"; \
+	  result_count $$1 "FAIL: " $$fail  "$$red"; \
+	  result_count $$1 "XPASS:" $$xpass "$$red"; \
+	  result_count $$1 "ERROR:" $$error "$$mgn"; \
+	}; \
+	{								\
+	  echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" |	\
+	    $(am__rst_title);						\
+	  create_testsuite_report --no-color;				\
+	  echo;								\
+	  echo ".. contents:: :depth: 2";				\
+	  echo;								\
+	  for b in $$bases; do echo $$b; done				\
+	    | $(am__create_global_log);					\
+	} >$(TEST_SUITE_LOG).tmp || exit 1;				\
+	mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG);			\
+	if $$success; then						\
+	  col="$$grn";							\
+	 else								\
+	  col="$$red";							\
+	  test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG);		\
+	fi;								\
+	echo "$${col}$$br$${std}"; 					\
+	echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}";	\
+	echo "$${col}$$br$${std}"; 					\
+	create_testsuite_report --maybe-color;				\
+	echo "$$col$$br$$std";						\
+	if $$success; then :; else					\
+	  echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}";		\
+	  if test -n "$(PACKAGE_BUGREPORT)"; then			\
+	    echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}";	\
+	  fi;								\
+	  echo "$$col$$br$$std";					\
+	fi;								\
+	$$success || exit 1
+
+check-TESTS:
+	@list='$(RECHECK_LOGS)';           test -z "$$list" || rm -f $$list
+	@list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list
+	@test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+	@set +e; $(am__set_TESTS_bases); \
+	log_list=`for i in $$bases; do echo $$i.log; done`; \
+	trs_list=`for i in $$bases; do echo $$i.trs; done`; \
+	log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \
+	$(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \
+	exit $$?;
+recheck: all $(check_LTLIBRARIES) $(check_PROGRAMS)
+	@test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+	@set +e; $(am__set_TESTS_bases); \
+	bases=`for i in $$bases; do echo $$i; done \
+	         | $(am__list_recheck_tests)` || exit 1; \
+	log_list=`for i in $$bases; do echo $$i.log; done`; \
+	log_list=`echo $$log_list`; \
+	$(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \
+	        am__force_recheck=am--force-recheck \
+	        TEST_LOGS="$$log_list"; \
+	exit $$?
+t-bswap.log: t-bswap$(EXEEXT)
+	@p='t-bswap$(EXEEXT)'; \
+	b='t-bswap'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-constants.log: t-constants$(EXEEXT)
+	@p='t-constants$(EXEEXT)'; \
+	b='t-constants'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-count_zeros.log: t-count_zeros$(EXEEXT)
+	@p='t-count_zeros$(EXEEXT)'; \
+	b='t-count_zeros'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-hightomask.log: t-hightomask$(EXEEXT)
+	@p='t-hightomask$(EXEEXT)'; \
+	b='t-hightomask'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-modlinv.log: t-modlinv$(EXEEXT)
+	@p='t-modlinv$(EXEEXT)'; \
+	b='t-modlinv'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-popc.log: t-popc$(EXEEXT)
+	@p='t-popc$(EXEEXT)'; \
+	b='t-popc'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-parity.log: t-parity$(EXEEXT)
+	@p='t-parity$(EXEEXT)'; \
+	b='t-parity'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-sub.log: t-sub$(EXEEXT)
+	@p='t-sub$(EXEEXT)'; \
+	b='t-sub'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+.test.log:
+	@p='$<'; \
+	$(am__set_b); \
+	$(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+@am__EXEEXT_TRUE@.test$(EXEEXT).log:
+@am__EXEEXT_TRUE@	@p='$<'; \
+@am__EXEEXT_TRUE@	$(am__set_b); \
+@am__EXEEXT_TRUE@	$(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+@am__EXEEXT_TRUE@	--log-file $$b.log --trs-file $$b.trs \
+@am__EXEEXT_TRUE@	$(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+@am__EXEEXT_TRUE@	"$$tst" $(AM_TESTS_FD_REDIRECT)
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+	@list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+	  if test "$$subdir" = .; then :; else \
+	    $(am__make_dryrun) \
+	      || test -d "$(distdir)/$$subdir" \
+	      || $(MKDIR_P) "$(distdir)/$$subdir" \
+	      || exit 1; \
+	    dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+	    $(am__relativize); \
+	    new_distdir=$$reldir; \
+	    dir1=$$subdir; dir2="$(top_distdir)"; \
+	    $(am__relativize); \
+	    new_top_distdir=$$reldir; \
+	    echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+	    echo "     am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+	    ($(am__cd) $$subdir && \
+	      $(MAKE) $(AM_MAKEFLAGS) \
+	        top_distdir="$$new_top_distdir" \
+	        distdir="$$new_distdir" \
+		am__remove_distdir=: \
+		am__skip_length_check=: \
+		am__skip_mode_fix=: \
+	        distdir) \
+	      || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) $(check_LTLIBRARIES) $(check_PROGRAMS)
+	$(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-recursive
+all-am: Makefile
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+	-test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS)
+	-test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs)
+	-test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-checkLTLIBRARIES clean-checkPROGRAMS clean-generic \
+	clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(am__recursive_targets) check-am install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
+	check-TESTS check-am clean clean-checkLTLIBRARIES \
+	clean-checkPROGRAMS clean-generic clean-libtool cscopelist-am \
+	ctags ctags-am distclean distclean-compile distclean-generic \
+	distclean-libtool distclean-tags distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-dvi install-dvi-am install-exec \
+	install-exec-am install-html install-html-am install-info \
+	install-info-am install-man install-pdf install-pdf-am \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs installdirs-am maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	recheck tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# .s assembler, no preprocessing.
+#
+.s.o:
+	$(CCAS) $(COMPILE_FLAGS) `test -f '$<' || echo '$(srcdir)/'`$<
+.s.obj:
+	$(CCAS) $(COMPILE_FLAGS) `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi`
+.s.lo:
+	$(LIBTOOL) --mode=compile --tag=CC $(CCAS) $(COMPILE_FLAGS) `test -f '$<' || echo '$(srcdir)/'`$<
+
+# .S assembler, preprocessed with cpp.
+#
+# It's necessary to run $(CPP) separately, since it seems not all compilers
+# recognise .S files, in particular "cc" on HP-UX 10 and 11 doesn't (and
+# will silently do nothing if given a .S).
+#
+# For .lo we need a helper script, as described below for .asm.lo.
+#
+.S.o:
+	$(CPP) $(PREPROCESS_FLAGS) `test -f '$<' || echo '$(srcdir)/'`$< | grep -v '^#' >tmp-$*.s
+	$(CCAS) $(COMPILE_FLAGS) tmp-$*.s -o $@
+	$(RM_TMP) tmp-$*.s
+.S.obj:
+	$(CPP) $(PREPROCESS_FLAGS) `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi` | grep -v '^#' >tmp-$*.s
+	$(CCAS) $(COMPILE_FLAGS) tmp-$*.s -o $@
+	$(RM_TMP) tmp-$*.s
+.S.lo:
+	$(LIBTOOL) --mode=compile --tag=CC $(top_srcdir)/mpn/cpp-ccas --cpp="$(CPP) $(PREPROCESS_FLAGS)" $(CCAS) $(COMPILE_FLAGS) `test -f '$<' || echo '$(srcdir)/'`$<
+
+# .asm assembler, preprocessed with m4.
+#
+# .o and .obj are non-PIC and just need m4 followed by a compile.
+#
+# .lo is a bit tricky.  Libtool (as of version 1.5) has foo.lo as a little
+# text file, and .libs/foo.o and foo.o as the PIC and non-PIC objects,
+# respectively.  It'd be asking for lots of trouble to try to create foo.lo
+# ourselves, so instead arrange to invoke libtool like a --mode=compile, but
+# with a special m4-ccas script which first m4 preprocesses, then compiles.
+# --tag=CC is necessary since foo.asm is otherwise unknown to libtool.
+#
+# Libtool adds -DPIC when building a shared object and the .asm files look
+# for that.  But it should be noted that the other PIC flags are on occasion
+# important too, in particular FreeBSD 2.2.8 gas 1.92.3 requires -k before
+# it accepts PIC constructs like @GOT, and gcc adds that flag only under
+# -fPIC.  (Later versions of gas are happy to accept PIC stuff any time.)
+#
+.asm.o:
+	$(M4) -DOPERATION_$* `test -f '$<' || echo '$(srcdir)/'`$< >tmp-$*.s
+	$(CCAS) $(COMPILE_FLAGS) tmp-$*.s -o $@
+	$(RM_TMP) tmp-$*.s
+.asm.obj:
+	$(M4) -DOPERATION_$* `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi` >tmp-$*.s
+	$(CCAS) $(COMPILE_FLAGS) tmp-$*.s -o $@
+	$(RM_TMP) tmp-$*.s
+.asm.lo:
+	$(LIBTOOL) --mode=compile --tag=CC $(top_srcdir)/mpn/m4-ccas --m4="$(M4)" $(CCAS) $(COMPILE_FLAGS) `test -f '$<' || echo '$(srcdir)/'`$<
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/third_party/gmp/tests/amd64call.asm b/third_party/gmp/tests/amd64call.asm
new file mode 100644
index 0000000..dad7763
--- /dev/null
+++ b/third_party/gmp/tests/amd64call.asm
@@ -0,0 +1,167 @@
+dnl  AMD64 calling conventions checking.
+
+dnl  Copyright 2000, 2003, 2004, 2006, 2007, 2010 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library test suite.
+
+dnl  The GNU MP Library test suite is free software; you can redistribute it
+dnl  and/or modify it under the terms of the GNU General Public License as
+dnl  published by the Free Software Foundation; either version 3 of the
+dnl  License, or (at your option) any later version.
+
+dnl  The GNU MP Library test suite is distributed in the hope that it will be
+dnl  useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+dnl  Public License for more details.
+
+dnl  You should have received a copy of the GNU General Public License along
+dnl  with the GNU MP Library test suite.  If not, see
+dnl  https://www.gnu.org/licenses/.
+
+
+dnl  The current version of the code attempts to keep the call/return
+dnl  prediction stack valid, but matching calls and returns.
+
+include(`../config.m4')
+
+
+C void x86_fldcw (unsigned short cw);
+C
+C Execute an fldcw, setting the x87 control word to cw.
+
+PROLOGUE(x86_fldcw)
+	mov	%rdi, -8(%rsp)
+	fldcw	-8(%rsp)
+	ret
+EPILOGUE()
+
+
+C unsigned short x86_fstcw (void);
+C
+C Execute an fstcw, returning the current x87 control word.
+
+PROLOGUE(x86_fstcw)
+	movq	$0, -8(%rsp)
+	fstcw	-8(%rsp)
+	mov	-8(%rsp), %rax
+	ret
+EPILOGUE()
+
+
+dnl  Instrumented profiling won't come out quite right below, since we don't do
+dnl  an actual "ret".  There's only a few instructions here, so there's no
+dnl  great need to get them separately accounted, just let them get attributed
+dnl  to the caller.  FIXME this comment might no longer be true.
+
+ifelse(WANT_PROFILING,instrument,
+`define(`WANT_PROFILING',no)')
+
+
+C int calling_conventions (...);
+C
+C The global variable "calling_conventions_function" is the function to
+C call, with the arguments as passed here.
+C
+C Perhaps the finit should be done only if the tags word isn't clear, but
+C nothing uses the rounding mode or anything at the moment.
+
+define(`WANT_RBX', eval(8*0)($1))
+define(`WANT_RBP', eval(8*1)($1))
+define(`WANT_R12', eval(8*2)($1))
+define(`WANT_R13', eval(8*3)($1))
+define(`WANT_R14', eval(8*4)($1))
+define(`WANT_R15', eval(8*5)($1))
+
+define(`JUNK_RAX', eval(8*6)($1))
+define(`JUNK_R10', eval(8*7)($1))
+define(`JUNK_R11', eval(8*8)($1))
+
+define(`SAVE_RBX', eval(8*9)($1))
+define(`SAVE_RBP', eval(8*10)($1))
+define(`SAVE_R12', eval(8*11)($1))
+define(`SAVE_R13', eval(8*12)($1))
+define(`SAVE_R14', eval(8*13)($1))
+define(`SAVE_R15', eval(8*14)($1))
+
+define(`RETADDR',  eval(8*15)($1))
+
+define(`RBX',	   eval(8*16)($1))
+define(`RBP',	   eval(8*17)($1))
+define(`R12',	   eval(8*18)($1))
+define(`R13',	   eval(8*19)($1))
+define(`R14',	   eval(8*20)($1))
+define(`R15',	   eval(8*21)($1))
+define(`RFLAGS',   eval(8*22)($1))
+
+
+define(G,
+m4_assert_numargs(1)
+`GSYM_PREFIX`'$1')
+
+	TEXT
+	ALIGN(32)
+PROLOGUE(calling_conventions)
+	mov	G(calling_conventions_values)@GOTPCREL(%rip), %rax
+	pop	RETADDR(%rax)
+
+	mov	%rbx, SAVE_RBX(%rax)
+	mov	%rbp, SAVE_RBP(%rax)
+	mov	%r12, SAVE_R12(%rax)
+	mov	%r13, SAVE_R13(%rax)
+	mov	%r14, SAVE_R14(%rax)
+	mov	%r15, SAVE_R15(%rax)
+
+	C Values we expect to see unchanged, as per amd64check.c
+	mov	WANT_RBX(%rax), %rbx
+	mov	WANT_RBP(%rax), %rbp
+	mov	WANT_R12(%rax), %r12
+	mov	WANT_R13(%rax), %r13
+	mov	WANT_R14(%rax), %r14
+	mov	WANT_R15(%rax), %r15
+
+	C Try to provoke a problem by starting with junk in the caller-saves
+	C registers, especially %rax which will be the return value.
+C	mov	JUNK_RAX(%rax), %rax		C overwritten below anyway
+	mov	JUNK_R10(%rax), %r10
+	mov	JUNK_R11(%rax), %r11
+
+	mov	G(calling_conventions_function)@GOTPCREL(%rip), %rax
+	call	*(%rax)
+
+	mov	G(calling_conventions_values)@GOTPCREL(%rip), %rcx
+
+	mov	%rbx, RBX(%rcx)
+	mov	%rbp, RBP(%rcx)
+	mov	%r12, R12(%rcx)
+	mov	%r13, R13(%rcx)
+	mov	%r14, R14(%rcx)
+	mov	%r15, R15(%rcx)
+
+	pushf
+	pop	%rbx
+	mov	%rbx, RFLAGS(%rcx)
+
+	mov	SAVE_RBX(%rcx), %rbx
+	mov	SAVE_RBP(%rcx), %rbp
+	mov	SAVE_R12(%rcx), %r12
+	mov	SAVE_R13(%rcx), %r13
+	mov	SAVE_R14(%rcx), %r14
+	mov	SAVE_R15(%rcx), %r15
+
+	C Overwrite parameter registers
+C	mov	JUNK_R9(%rcx), %r9
+C	mov	JUNK_R8(%rcx), %r8
+C	mov	JUNK_RCX(%rcx), %rcx
+C	mov	JUNK_RDX(%rcx), %rdx
+C	mov	JUNK_RSI(%rcx), %rsi
+C	mov	JUNK_RDI(%rcx), %rdi
+
+	push	RETADDR(%rcx)
+
+	mov	G(calling_conventions_fenv)@GOTPCREL(%rip), %rcx
+	fstenv	(%rcx)
+	finit
+
+	ret
+
+EPILOGUE()
diff --git a/third_party/gmp/tests/amd64check.c b/third_party/gmp/tests/amd64check.c
new file mode 100644
index 0000000..a8cdbe2
--- /dev/null
+++ b/third_party/gmp/tests/amd64check.c
@@ -0,0 +1,111 @@
+/* AMD64 calling conventions checking.
+
+Copyright 2000, 2001, 2004, 2007 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+/* Vector if constants and register values.  We use one vector to allow access
+   via a base pointer, very beneficial for the PIC-enabled amd64call.asm.  */
+mp_limb_t calling_conventions_values[23] =
+{
+  CNST_LIMB(0x1234567887654321),	/* want_rbx */
+  CNST_LIMB(0x89ABCDEFFEDCBA98),	/* want_rbp */
+  CNST_LIMB(0xDEADBEEFBADECAFE),	/* want_r12 */
+  CNST_LIMB(0xFFEEDDCCBBAA9988),	/* want_r13 */
+  CNST_LIMB(0x0011223344556677),	/* want_r14 */
+  CNST_LIMB(0x1234432156788765),	/* want_r15 */
+
+  CNST_LIMB(0xFEEDABBACAAFBEED),	/* JUNK_RAX */
+  CNST_LIMB(0xAB78DE89FF5125BB),	/* JUNK_R10 */
+  CNST_LIMB(0x1238901890189031)		/* JUNK_R11 */
+
+  /* rest of array used for dynamic values.  */
+};
+
+/* Index starts for various regions in above vector.  */
+#define WANT	0
+#define JUNK	6
+#define SAVE	9
+#define RETADDR	15
+#define VAL	16
+#define RFLAGS	22
+
+/* values to check */
+#ifdef __cplusplus
+extern "C" {
+#endif
+struct {
+  int  control;
+  int  status;
+  int  tag;
+  int  other[4];
+} calling_conventions_fenv;
+#ifdef __cplusplus
+}
+#endif
+
+
+const char *regname[6] = {"rbx", "rbp", "r12", "r13", "r14", "r15"};
+
+#define DIR_BIT(rflags)   (((rflags) & (1<<10)) != 0)
+
+
+/* Return 1 if ok, 0 if not */
+
+int
+calling_conventions_check (void)
+{
+  const char  *header = "Violated calling conventions:\n";
+  int  ret = 1;
+  int i;
+
+#define CHECK(callreg, regstr, value)			\
+  if (callreg != value)					\
+    {							\
+      printf ("%s   %s	got 0x%016lX want 0x%016lX\n",	\
+	      header, regstr, callreg, value);		\
+      header = "";					\
+      ret = 0;						\
+    }
+
+  for (i = 0; i < 6; i++)
+    {
+      CHECK (calling_conventions_values[VAL+i], regname[i], calling_conventions_values[WANT+i]);
+    }
+
+  if (DIR_BIT (calling_conventions_values[RFLAGS]) != 0)
+    {
+      printf ("%s   rflags dir bit  got %d want 0\n",
+	      header, DIR_BIT (calling_conventions_values[RFLAGS]));
+      header = "";
+      ret = 0;
+    }
+
+  if ((calling_conventions_fenv.tag & 0xFFFF) != 0xFFFF)
+    {
+      printf ("%s   fpu tags  got 0x%X want 0xFFFF\n",
+	      header, calling_conventions_fenv.tag & 0xFFFF);
+      header = "";
+      ret = 0;
+    }
+
+  return ret;
+}
diff --git a/third_party/gmp/tests/arm32call.asm b/third_party/gmp/tests/arm32call.asm
new file mode 100644
index 0000000..24d0739
--- /dev/null
+++ b/third_party/gmp/tests/arm32call.asm
@@ -0,0 +1,83 @@
+dnl  ARM32 calling conventions checking.
+
+dnl  Copyright 2000, 2003, 2004, 2006, 2007, 2010, 2013, 2016 Free Software
+dnl  Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library test suite.
+
+dnl  The GNU MP Library test suite is free software; you can redistribute it
+dnl  and/or modify it under the terms of the GNU General Public License as
+dnl  published by the Free Software Foundation; either version 3 of the
+dnl  License, or (at your option) any later version.
+
+dnl  The GNU MP Library test suite is distributed in the hope that it will be
+dnl  useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+dnl  Public License for more details.
+
+dnl  You should have received a copy of the GNU General Public License along
+dnl  with the GNU MP Library test suite.  If not, see
+dnl  https://www.gnu.org/licenses/.
+
+
+dnl  The current version of the code attempts to keep the call/return
+dnl  prediction stack valid, but matching calls and returns.
+
+include(`../config.m4')
+
+
+C int calling_conventions (...);
+C
+C The global variable "calling_conventions_function" is the function to
+C call, with the arguments as passed here.
+
+define(`WANT_CALLEE_SAVES',	eval(4*0))
+define(`SAVE_CALLEE_SAVES',	eval(4*8))
+define(`RETADDR',		eval(4*16))
+define(`GOT_CALLEE_SAVES',	eval(4*17))
+define(`JUNK_PARAMS',		eval(4*25))
+
+	TEXT
+	ALIGN(32)
+PROLOGUE(calling_conventions)
+	LEA(	r12, calling_conventions_values)
+
+	C Preserve callee-saves registers, including the link register r14
+	add	r12, r12, #SAVE_CALLEE_SAVES
+	stm	r12, {r4-r11,r14}
+	sub	r12, r12, #SAVE_CALLEE_SAVES
+
+	C Put chosen junk into callee-saves registers
+	add	r12, r12, #WANT_CALLEE_SAVES
+	ldm	r12, {r4-r11}
+	sub	r12, r12, #WANT_CALLEE_SAVES
+
+	C No callee-saves registers on arm except r12 and parameter registers
+	C
+
+	C Make the actual call
+	LEA(	r12, calling_conventions_function)
+	ldr	r12, [r12]
+	mov	r14, pc
+	return	r12
+
+	LEA(	r12, calling_conventions_values)
+
+	C Save callee-saves registers after call
+	add	r12, r12, #GOT_CALLEE_SAVES
+	stm	r12, {r4-r11}
+	sub	r12, r12, #GOT_CALLEE_SAVES
+
+	C Restore callee-saves registers, including the link register r14
+	add	r12, r12, #SAVE_CALLEE_SAVES
+	ldm	r12, {r4-r11,r14}
+	sub	r12, r12, #SAVE_CALLEE_SAVES
+
+	C Overwrite parameter registers.  Note that we overwrite r1, which
+	C could hold one half of a 64-bit return value, since we don't use that
+	C in GMP.
+	add	r12, r12, #JUNK_PARAMS
+	ldm	r12, {r1-r3}
+
+	return	r14
+EPILOGUE()
diff --git a/third_party/gmp/tests/arm32check.c b/third_party/gmp/tests/arm32check.c
new file mode 100644
index 0000000..0a9f86d
--- /dev/null
+++ b/third_party/gmp/tests/arm32check.c
@@ -0,0 +1,95 @@
+/* ARM32 calling conventions checking.
+
+Copyright 2000, 2001, 2004, 2007 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+/* Vector if constants and register values.  */
+mp_limb_t calling_conventions_values[29] =
+{
+  0x12345678,	/*  0 want_r4 */
+  0x87654321,	/*  1 want_r5 */
+  0x89ABCDEF,	/*  2 want_r6 */
+  0xFEDCBA98,	/*  3 want_r7 */
+  0xDEADBEEF,	/*  4 want_r8 */
+  0xBADECAFE,	/*  5 want_r9 */
+  0xFFEEDDCC,	/*  6 want_r10 */
+  0xBBAA9988,	/*  7 want_r11 */
+
+  0x00000000,	/*  8 save_r4 */
+  0x00000000,	/*  9 save_r5 */
+  0x00000000,	/* 10 save_r6 */
+  0x00000000,	/* 11 save_r7 */
+  0x00000000,	/* 12 save_r8 */
+  0x00000000,	/* 13 save_r9 */
+  0x00000000,	/* 14 save_r10 */
+  0x00000000,	/* 15 save_r11 */
+  0x00000000,	/* 16 save_r14 */
+
+  0x00000000,	/* 17 got_r4 */
+  0x00000000,	/* 18 got_r5 */
+  0x00000000,	/* 19 got_r6 */
+  0x00000000,	/* 20 got_r7 */
+  0x00000000,	/* 21 got_r8 */
+  0x00000000,	/* 22 got_r9 */
+  0x00000000,	/* 23 got_r10 */
+  0x00000000,	/* 24 got_r11 */
+
+  0x00112233,	/* 25 junk_r0 */
+  0x44556677,	/* 26 junk_r1 */
+  0x12344321,	/* 27 junk_r2 */
+  0x56788765,	/* 28 junk_r3 */
+};
+
+/* Index starts for various regions in above vector.  */
+#define WANT_CALLEE_SAVES	0
+#define SAVE_CALLEE_SAVES	8
+#define RETADDR			16
+#define GOT_CALLEE_SAVES	17
+#define JUNK_PARAMS		25
+
+/* Return 1 if ok, 0 if not */
+
+int
+calling_conventions_check (void)
+{
+  const char  *header = "Violated calling conventions:\n";
+  int  ret = 1;
+  int i;
+
+#define CHECK(callreg, regnum, value)					\
+  if (callreg != value)							\
+    {									\
+      printf ("%s   r%d	got 0x%08lX want 0x%08lX\n",			\
+	      header, regnum, callreg, value);				\
+      header = "";							\
+      ret = 0;								\
+    }
+
+  for (i = 0; i < 8; i++)
+    {
+      CHECK (calling_conventions_values[GOT_CALLEE_SAVES + i],
+	     i + 4,
+	     calling_conventions_values[WANT_CALLEE_SAVES + i]);
+    }
+
+  return ret;
+}
diff --git a/third_party/gmp/tests/cxx/Makefile.am b/third_party/gmp/tests/cxx/Makefile.am
new file mode 100644
index 0000000..041bf59
--- /dev/null
+++ b/third_party/gmp/tests/cxx/Makefile.am
@@ -0,0 +1,87 @@
+## Process this file with automake to generate Makefile.in
+
+# Copyright 2001-2004 Free Software Foundation, Inc.
+#
+# This file is part of the GNU MP Library test suite.
+#
+# The GNU MP Library test suite is free software; you can redistribute it
+# and/or modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 3 of the License,
+# or (at your option) any later version.
+#
+# The GNU MP Library test suite is distributed in the hope that it will be
+# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.
+
+
+# LDADD has an explicit -L of $(top_builddir)/.libs for the benefit of gcc
+# 3.2 on itanium2-hp-hpux11.22.  Without this option, the libgmp.sl.6
+# required by libgmpxx.sl (ie. in its NEEDED records) is not found by the
+# linker.  FIXME: Presumably libtool should do something about this itself.
+# -lm is needed for t-ops2 which compares the results of trunc and mpf_trunc.
+#
+AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/tests
+AM_LDFLAGS = -no-install
+LDADD = -L$(top_builddir)/.libs \
+  $(top_builddir)/tests/libtests.la \
+  $(top_builddir)/libgmpxx.la \
+  $(top_builddir)/libgmp.la \
+  -lm
+
+if WANT_CXX
+check_PROGRAMS = t-binary t-cast t-cxx11 \
+  t-headers t-iostream t-istream t-locale t-misc t-mix \
+  t-ops t-ops2qf t-ops2f t-ops3 t-ostream t-prec \
+  t-ternary t-unary \
+  t-do-exceptions-work-at-all-with-this-compiler \
+  t-ops2z t-assign t-constr t-rand
+
+TESTS = $(check_PROGRAMS)
+endif
+
+EXTRA_DIST = t-ops2.h
+
+t_assign_SOURCES  = t-assign.cc
+t_binary_SOURCES  = t-binary.cc
+t_cast_SOURCES    = t-cast.cc
+t_constr_SOURCES  = t-constr.cc
+t_cxx11_SOURCES   = t-cxx11.cc
+t_headers_SOURCES = t-headers.cc
+t_iostream_SOURCES= t-iostream.cc
+t_istream_SOURCES = t-istream.cc
+t_locale_SOURCES  = t-locale.cc clocale.c
+t_misc_SOURCES    = t-misc.cc
+t_mix_SOURCES     = t-mix.cc
+t_ops_SOURCES     = t-ops.cc
+t_ops2z_SOURCES   = t-ops2z.cc
+t_ops2qf_SOURCES  = t-ops2qf.cc
+t_ops2f_SOURCES   = t-ops2f.cc
+t_ops3_SOURCES    = t-ops3.cc
+t_ostream_SOURCES = t-ostream.cc
+t_prec_SOURCES    = t-prec.cc
+t_rand_SOURCES    = t-rand.cc
+t_ternary_SOURCES = t-ternary.cc
+t_unary_SOURCES   = t-unary.cc
+t_do_exceptions_work_at_all_with_this_compiler_SOURCES = \
+  t-do-exceptions-work-at-all-with-this-compiler.cc
+
+$(top_builddir)/tests/libtests.la:
+	cd $(top_builddir)/tests; $(MAKE) $(AM_MAKEFLAGS) libtests.la
+
+
+# Libtool (1.5) somehow botches its uninstalled shared library setups on
+# OpenBSD 3.2, making the C++ test programs here fail.  libgmpxx.so ends up
+# with a NEEDED record asking for ./.libs/libgmp.so.N, but the loader can't
+# find that unless it exists in the current directory.
+#
+# FIXME: Clearly libtool ought to handle this itself, in which case the hack
+# here can be removed.
+#
+# Note this fix applies only when running "make check".  The cp here should
+# be done manually if just one program is to be built and run.
+#
+TESTS_ENVIRONMENT = cp $(top_builddir)/.libs/libgmp.so.* .libs 2>/dev/null || true;
diff --git a/third_party/gmp/tests/cxx/Makefile.in b/third_party/gmp/tests/cxx/Makefile.in
new file mode 100644
index 0000000..94ce352
--- /dev/null
+++ b/third_party/gmp/tests/cxx/Makefile.in
@@ -0,0 +1,1445 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Copyright 2001-2004 Free Software Foundation, Inc.
+#
+# This file is part of the GNU MP Library test suite.
+#
+# The GNU MP Library test suite is free software; you can redistribute it
+# and/or modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 3 of the License,
+# or (at your option) any later version.
+#
+# The GNU MP Library test suite is distributed in the hope that it will be
+# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@WANT_CXX_TRUE@check_PROGRAMS = t-binary$(EXEEXT) t-cast$(EXEEXT) \
+@WANT_CXX_TRUE@	t-cxx11$(EXEEXT) t-headers$(EXEEXT) \
+@WANT_CXX_TRUE@	t-iostream$(EXEEXT) t-istream$(EXEEXT) \
+@WANT_CXX_TRUE@	t-locale$(EXEEXT) t-misc$(EXEEXT) \
+@WANT_CXX_TRUE@	t-mix$(EXEEXT) t-ops$(EXEEXT) t-ops2qf$(EXEEXT) \
+@WANT_CXX_TRUE@	t-ops2f$(EXEEXT) t-ops3$(EXEEXT) \
+@WANT_CXX_TRUE@	t-ostream$(EXEEXT) t-prec$(EXEEXT) \
+@WANT_CXX_TRUE@	t-ternary$(EXEEXT) t-unary$(EXEEXT) \
+@WANT_CXX_TRUE@	t-do-exceptions-work-at-all-with-this-compiler$(EXEEXT) \
+@WANT_CXX_TRUE@	t-ops2z$(EXEEXT) t-assign$(EXEEXT) \
+@WANT_CXX_TRUE@	t-constr$(EXEEXT) t-rand$(EXEEXT)
+subdir = tests/cxx
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am_t_assign_OBJECTS = t-assign.$(OBJEXT)
+t_assign_OBJECTS = $(am_t_assign_OBJECTS)
+t_assign_LDADD = $(LDADD)
+t_assign_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmpxx.la $(top_builddir)/libgmp.la
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+am_t_binary_OBJECTS = t-binary.$(OBJEXT)
+t_binary_OBJECTS = $(am_t_binary_OBJECTS)
+t_binary_LDADD = $(LDADD)
+t_binary_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmpxx.la $(top_builddir)/libgmp.la
+am_t_cast_OBJECTS = t-cast.$(OBJEXT)
+t_cast_OBJECTS = $(am_t_cast_OBJECTS)
+t_cast_LDADD = $(LDADD)
+t_cast_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmpxx.la $(top_builddir)/libgmp.la
+am_t_constr_OBJECTS = t-constr.$(OBJEXT)
+t_constr_OBJECTS = $(am_t_constr_OBJECTS)
+t_constr_LDADD = $(LDADD)
+t_constr_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmpxx.la $(top_builddir)/libgmp.la
+am_t_cxx11_OBJECTS = t-cxx11.$(OBJEXT)
+t_cxx11_OBJECTS = $(am_t_cxx11_OBJECTS)
+t_cxx11_LDADD = $(LDADD)
+t_cxx11_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmpxx.la $(top_builddir)/libgmp.la
+am_t_do_exceptions_work_at_all_with_this_compiler_OBJECTS =  \
+	t-do-exceptions-work-at-all-with-this-compiler.$(OBJEXT)
+t_do_exceptions_work_at_all_with_this_compiler_OBJECTS =  \
+	$(am_t_do_exceptions_work_at_all_with_this_compiler_OBJECTS)
+t_do_exceptions_work_at_all_with_this_compiler_LDADD = $(LDADD)
+t_do_exceptions_work_at_all_with_this_compiler_DEPENDENCIES =  \
+	$(top_builddir)/tests/libtests.la $(top_builddir)/libgmpxx.la \
+	$(top_builddir)/libgmp.la
+am_t_headers_OBJECTS = t-headers.$(OBJEXT)
+t_headers_OBJECTS = $(am_t_headers_OBJECTS)
+t_headers_LDADD = $(LDADD)
+t_headers_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmpxx.la $(top_builddir)/libgmp.la
+am_t_iostream_OBJECTS = t-iostream.$(OBJEXT)
+t_iostream_OBJECTS = $(am_t_iostream_OBJECTS)
+t_iostream_LDADD = $(LDADD)
+t_iostream_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmpxx.la $(top_builddir)/libgmp.la
+am_t_istream_OBJECTS = t-istream.$(OBJEXT)
+t_istream_OBJECTS = $(am_t_istream_OBJECTS)
+t_istream_LDADD = $(LDADD)
+t_istream_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmpxx.la $(top_builddir)/libgmp.la
+am_t_locale_OBJECTS = t-locale.$(OBJEXT) clocale.$(OBJEXT)
+t_locale_OBJECTS = $(am_t_locale_OBJECTS)
+t_locale_LDADD = $(LDADD)
+t_locale_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmpxx.la $(top_builddir)/libgmp.la
+am_t_misc_OBJECTS = t-misc.$(OBJEXT)
+t_misc_OBJECTS = $(am_t_misc_OBJECTS)
+t_misc_LDADD = $(LDADD)
+t_misc_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmpxx.la $(top_builddir)/libgmp.la
+am_t_mix_OBJECTS = t-mix.$(OBJEXT)
+t_mix_OBJECTS = $(am_t_mix_OBJECTS)
+t_mix_LDADD = $(LDADD)
+t_mix_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmpxx.la $(top_builddir)/libgmp.la
+am_t_ops_OBJECTS = t-ops.$(OBJEXT)
+t_ops_OBJECTS = $(am_t_ops_OBJECTS)
+t_ops_LDADD = $(LDADD)
+t_ops_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmpxx.la $(top_builddir)/libgmp.la
+am_t_ops2f_OBJECTS = t-ops2f.$(OBJEXT)
+t_ops2f_OBJECTS = $(am_t_ops2f_OBJECTS)
+t_ops2f_LDADD = $(LDADD)
+t_ops2f_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmpxx.la $(top_builddir)/libgmp.la
+am_t_ops2qf_OBJECTS = t-ops2qf.$(OBJEXT)
+t_ops2qf_OBJECTS = $(am_t_ops2qf_OBJECTS)
+t_ops2qf_LDADD = $(LDADD)
+t_ops2qf_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmpxx.la $(top_builddir)/libgmp.la
+am_t_ops2z_OBJECTS = t-ops2z.$(OBJEXT)
+t_ops2z_OBJECTS = $(am_t_ops2z_OBJECTS)
+t_ops2z_LDADD = $(LDADD)
+t_ops2z_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmpxx.la $(top_builddir)/libgmp.la
+am_t_ops3_OBJECTS = t-ops3.$(OBJEXT)
+t_ops3_OBJECTS = $(am_t_ops3_OBJECTS)
+t_ops3_LDADD = $(LDADD)
+t_ops3_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmpxx.la $(top_builddir)/libgmp.la
+am_t_ostream_OBJECTS = t-ostream.$(OBJEXT)
+t_ostream_OBJECTS = $(am_t_ostream_OBJECTS)
+t_ostream_LDADD = $(LDADD)
+t_ostream_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmpxx.la $(top_builddir)/libgmp.la
+am_t_prec_OBJECTS = t-prec.$(OBJEXT)
+t_prec_OBJECTS = $(am_t_prec_OBJECTS)
+t_prec_LDADD = $(LDADD)
+t_prec_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmpxx.la $(top_builddir)/libgmp.la
+am_t_rand_OBJECTS = t-rand.$(OBJEXT)
+t_rand_OBJECTS = $(am_t_rand_OBJECTS)
+t_rand_LDADD = $(LDADD)
+t_rand_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmpxx.la $(top_builddir)/libgmp.la
+am_t_ternary_OBJECTS = t-ternary.$(OBJEXT)
+t_ternary_OBJECTS = $(am_t_ternary_OBJECTS)
+t_ternary_LDADD = $(LDADD)
+t_ternary_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmpxx.la $(top_builddir)/libgmp.la
+am_t_unary_OBJECTS = t-unary.$(OBJEXT)
+t_unary_OBJECTS = $(am_t_unary_OBJECTS)
+t_unary_LDADD = $(LDADD)
+t_unary_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmpxx.la $(top_builddir)/libgmp.la
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp =
+am__depfiles_maybe =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo "  CXX     " $@;
+am__v_CXX_1 = 
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+	$(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo "  CXXLD   " $@;
+am__v_CXXLD_1 = 
+SOURCES = $(t_assign_SOURCES) $(t_binary_SOURCES) $(t_cast_SOURCES) \
+	$(t_constr_SOURCES) $(t_cxx11_SOURCES) \
+	$(t_do_exceptions_work_at_all_with_this_compiler_SOURCES) \
+	$(t_headers_SOURCES) $(t_iostream_SOURCES) \
+	$(t_istream_SOURCES) $(t_locale_SOURCES) $(t_misc_SOURCES) \
+	$(t_mix_SOURCES) $(t_ops_SOURCES) $(t_ops2f_SOURCES) \
+	$(t_ops2qf_SOURCES) $(t_ops2z_SOURCES) $(t_ops3_SOURCES) \
+	$(t_ostream_SOURCES) $(t_prec_SOURCES) $(t_rand_SOURCES) \
+	$(t_ternary_SOURCES) $(t_unary_SOURCES)
+DIST_SOURCES = $(t_assign_SOURCES) $(t_binary_SOURCES) \
+	$(t_cast_SOURCES) $(t_constr_SOURCES) $(t_cxx11_SOURCES) \
+	$(t_do_exceptions_work_at_all_with_this_compiler_SOURCES) \
+	$(t_headers_SOURCES) $(t_iostream_SOURCES) \
+	$(t_istream_SOURCES) $(t_locale_SOURCES) $(t_misc_SOURCES) \
+	$(t_mix_SOURCES) $(t_ops_SOURCES) $(t_ops2f_SOURCES) \
+	$(t_ops2qf_SOURCES) $(t_ops2z_SOURCES) $(t_ops3_SOURCES) \
+	$(t_ostream_SOURCES) $(t_prec_SOURCES) $(t_rand_SOURCES) \
+	$(t_ternary_SOURCES) $(t_unary_SOURCES)
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__tty_colors_dummy = \
+  mgn= red= grn= lgn= blu= brg= std=; \
+  am__color_tests=no
+am__tty_colors = { \
+  $(am__tty_colors_dummy); \
+  if test "X$(AM_COLOR_TESTS)" = Xno; then \
+    am__color_tests=no; \
+  elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+    am__color_tests=yes; \
+  elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+    am__color_tests=yes; \
+  fi; \
+  if test $$am__color_tests = yes; then \
+    red=''; \
+    grn=''; \
+    lgn=''; \
+    blu=''; \
+    mgn=''; \
+    brg=''; \
+    std=''; \
+  fi; \
+}
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+  test -z "$$files" \
+    || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+    || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+         $(am__cd) "$$dir" && rm -f $$files; }; \
+  }
+am__recheck_rx = ^[ 	]*:recheck:[ 	]*
+am__global_test_result_rx = ^[ 	]*:global-test-result:[ 	]*
+am__copy_in_global_log_rx = ^[ 	]*:copy-in-global-log:[ 	]*
+# A command that, given a newline-separated list of test names on the
+# standard input, print the name of the tests that are to be re-run
+# upon "make recheck".
+am__list_recheck_tests = $(AWK) '{ \
+  recheck = 1; \
+  while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+    { \
+      if (rc < 0) \
+        { \
+          if ((getline line2 < ($$0 ".log")) < 0) \
+	    recheck = 0; \
+          break; \
+        } \
+      else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \
+        { \
+          recheck = 0; \
+          break; \
+        } \
+      else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \
+        { \
+          break; \
+        } \
+    }; \
+  if (recheck) \
+    print $$0; \
+  close ($$0 ".trs"); \
+  close ($$0 ".log"); \
+}'
+# A command that, given a newline-separated list of test names on the
+# standard input, create the global log from their .trs and .log files.
+am__create_global_log = $(AWK) ' \
+function fatal(msg) \
+{ \
+  print "fatal: making $@: " msg | "cat >&2"; \
+  exit 1; \
+} \
+function rst_section(header) \
+{ \
+  print header; \
+  len = length(header); \
+  for (i = 1; i <= len; i = i + 1) \
+    printf "="; \
+  printf "\n\n"; \
+} \
+{ \
+  copy_in_global_log = 1; \
+  global_test_result = "RUN"; \
+  while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+    { \
+      if (rc < 0) \
+         fatal("failed to read from " $$0 ".trs"); \
+      if (line ~ /$(am__global_test_result_rx)/) \
+        { \
+          sub("$(am__global_test_result_rx)", "", line); \
+          sub("[ 	]*$$", "", line); \
+          global_test_result = line; \
+        } \
+      else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \
+        copy_in_global_log = 0; \
+    }; \
+  if (copy_in_global_log) \
+    { \
+      rst_section(global_test_result ": " $$0); \
+      while ((rc = (getline line < ($$0 ".log"))) != 0) \
+      { \
+        if (rc < 0) \
+          fatal("failed to read from " $$0 ".log"); \
+        print line; \
+      }; \
+      printf "\n"; \
+    }; \
+  close ($$0 ".trs"); \
+  close ($$0 ".log"); \
+}'
+# Restructured Text title.
+am__rst_title = { sed 's/.*/   &   /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; }
+# Solaris 10 'make', and several other traditional 'make' implementations,
+# pass "-e" to $(SHELL), and POSIX 2008 even requires this.  Work around it
+# by disabling -e (using the XSI extension "set +e") if it's set.
+am__sh_e_setup = case $$- in *e*) set +e;; esac
+# Default flags passed to test drivers.
+am__common_driver_flags = \
+  --color-tests "$$am__color_tests" \
+  --enable-hard-errors "$$am__enable_hard_errors" \
+  --expect-failure "$$am__expect_failure"
+# To be inserted before the command running the test.  Creates the
+# directory for the log if needed.  Stores in $dir the directory
+# containing $f, in $tst the test, in $log the log.  Executes the
+# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and
+# passes TESTS_ENVIRONMENT.  Set up options for the wrapper that
+# will run the test scripts (or their associated LOG_COMPILER, if
+# thy have one).
+am__check_pre = \
+$(am__sh_e_setup);					\
+$(am__vpath_adj_setup) $(am__vpath_adj)			\
+$(am__tty_colors);					\
+srcdir=$(srcdir); export srcdir;			\
+case "$@" in						\
+  */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;;	\
+    *) am__odir=.;; 					\
+esac;							\
+test "x$$am__odir" = x"." || test -d "$$am__odir" 	\
+  || $(MKDIR_P) "$$am__odir" || exit $$?;		\
+if test -f "./$$f"; then dir=./;			\
+elif test -f "$$f"; then dir=;				\
+else dir="$(srcdir)/"; fi;				\
+tst=$$dir$$f; log='$@'; 				\
+if test -n '$(DISABLE_HARD_ERRORS)'; then		\
+  am__enable_hard_errors=no; 				\
+else							\
+  am__enable_hard_errors=yes; 				\
+fi; 							\
+case " $(XFAIL_TESTS) " in				\
+  *[\ \	]$$f[\ \	]* | *[\ \	]$$dir$$f[\ \	]*) \
+    am__expect_failure=yes;;				\
+  *)							\
+    am__expect_failure=no;;				\
+esac; 							\
+$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT)
+# A shell command to get the names of the tests scripts with any registered
+# extension removed (i.e., equivalently, the names of the test logs, with
+# the '.log' extension removed).  The result is saved in the shell variable
+# '$bases'.  This honors runtime overriding of TESTS and TEST_LOGS.  Sadly,
+# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)",
+# since that might cause problem with VPATH rewrites for suffix-less tests.
+# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'.
+am__set_TESTS_bases = \
+  bases='$(TEST_LOGS)'; \
+  bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \
+  bases=`echo $$bases`
+RECHECK_LOGS = $(TEST_LOGS)
+AM_RECURSIVE_TARGETS = check recheck
+TEST_SUITE_LOG = test-suite.log
+TEST_EXTENSIONS = @EXEEXT@ .test
+LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS)
+am__set_b = \
+  case '$@' in \
+    */*) \
+      case '$*' in \
+        */*) b='$*';; \
+          *) b=`echo '$@' | sed 's/\.log$$//'`; \
+       esac;; \
+    *) \
+      b='$*';; \
+  esac
+am__test_logs1 = $(TESTS:=.log)
+am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log)
+TEST_LOGS = $(am__test_logs2:.test.log=.log)
+TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \
+	$(TEST_LOG_FLAGS)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/test-driver
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ABI = @ABI@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+ASMFLAGS = @ASMFLAGS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CALLING_CONVENTIONS_OBJS = @CALLING_CONVENTIONS_OBJS@
+CC = @CC@
+CCAS = @CCAS@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPP_FOR_BUILD = @CPP_FOR_BUILD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFN_LONG_LONG_LIMB = @DEFN_LONG_LONG_LIMB@
+DEFS = @DEFS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@
+FGREP = @FGREP@
+GMP_LDFLAGS = @GMP_LDFLAGS@
+GMP_LIMB_BITS = @GMP_LIMB_BITS@
+GMP_NAIL_BITS = @GMP_NAIL_BITS@
+GREP = @GREP@
+HAVE_CLOCK_01 = @HAVE_CLOCK_01@
+HAVE_CPUTIME_01 = @HAVE_CPUTIME_01@
+HAVE_GETRUSAGE_01 = @HAVE_GETRUSAGE_01@
+HAVE_GETTIMEOFDAY_01 = @HAVE_GETTIMEOFDAY_01@
+HAVE_HOST_CPU_FAMILY_power = @HAVE_HOST_CPU_FAMILY_power@
+HAVE_HOST_CPU_FAMILY_powerpc = @HAVE_HOST_CPU_FAMILY_powerpc@
+HAVE_SIGACTION_01 = @HAVE_SIGACTION_01@
+HAVE_SIGALTSTACK_01 = @HAVE_SIGALTSTACK_01@
+HAVE_SIGSTACK_01 = @HAVE_SIGSTACK_01@
+HAVE_STACK_T_01 = @HAVE_STACK_T_01@
+HAVE_SYS_RESOURCE_H_01 = @HAVE_SYS_RESOURCE_H_01@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCURSES = @LIBCURSES@
+LIBGMPXX_LDFLAGS = @LIBGMPXX_LDFLAGS@
+LIBGMP_DLL = @LIBGMP_DLL@
+LIBGMP_LDFLAGS = @LIBGMP_LDFLAGS@
+LIBM = @LIBM@
+LIBM_FOR_BUILD = @LIBM_FOR_BUILD@
+LIBOBJS = @LIBOBJS@
+LIBREADLINE = @LIBREADLINE@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+M4 = @M4@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPEED_CYCLECOUNTER_OBJ = @SPEED_CYCLECOUNTER_OBJ@
+STRIP = @STRIP@
+TAL_OBJECT = @TAL_OBJECT@
+TUNE_LIBS = @TUNE_LIBS@
+TUNE_SQR_OBJ = @TUNE_SQR_OBJ@
+U_FOR_BUILD = @U_FOR_BUILD@
+VERSION = @VERSION@
+WITH_READLINE_01 = @WITH_READLINE_01@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__leading_dot = @am__leading_dot@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gmp_srclinks = @gmp_srclinks@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+mpn_objects = @mpn_objects@
+mpn_objs_in_libgmp = @mpn_objs_in_libgmp@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+
+# LDADD has an explicit -L of $(top_builddir)/.libs for the benefit of gcc
+# 3.2 on itanium2-hp-hpux11.22.  Without this option, the libgmp.sl.6
+# required by libgmpxx.sl (ie. in its NEEDED records) is not found by the
+# linker.  FIXME: Presumably libtool should do something about this itself.
+# -lm is needed for t-ops2 which compares the results of trunc and mpf_trunc.
+#
+AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/tests
+AM_LDFLAGS = -no-install
+LDADD = -L$(top_builddir)/.libs \
+  $(top_builddir)/tests/libtests.la \
+  $(top_builddir)/libgmpxx.la \
+  $(top_builddir)/libgmp.la \
+  -lm
+
+@WANT_CXX_TRUE@TESTS = $(check_PROGRAMS)
+EXTRA_DIST = t-ops2.h
+t_assign_SOURCES = t-assign.cc
+t_binary_SOURCES = t-binary.cc
+t_cast_SOURCES = t-cast.cc
+t_constr_SOURCES = t-constr.cc
+t_cxx11_SOURCES = t-cxx11.cc
+t_headers_SOURCES = t-headers.cc
+t_iostream_SOURCES = t-iostream.cc
+t_istream_SOURCES = t-istream.cc
+t_locale_SOURCES = t-locale.cc clocale.c
+t_misc_SOURCES = t-misc.cc
+t_mix_SOURCES = t-mix.cc
+t_ops_SOURCES = t-ops.cc
+t_ops2z_SOURCES = t-ops2z.cc
+t_ops2qf_SOURCES = t-ops2qf.cc
+t_ops2f_SOURCES = t-ops2f.cc
+t_ops3_SOURCES = t-ops3.cc
+t_ostream_SOURCES = t-ostream.cc
+t_prec_SOURCES = t-prec.cc
+t_rand_SOURCES = t-rand.cc
+t_ternary_SOURCES = t-ternary.cc
+t_unary_SOURCES = t-unary.cc
+t_do_exceptions_work_at_all_with_this_compiler_SOURCES = \
+  t-do-exceptions-work-at-all-with-this-compiler.cc
+
+
+# Libtool (1.5) somehow botches its uninstalled shared library setups on
+# OpenBSD 3.2, making the C++ test programs here fail.  libgmpxx.so ends up
+# with a NEEDED record asking for ./.libs/libgmp.so.N, but the loader can't
+# find that unless it exists in the current directory.
+#
+# FIXME: Clearly libtool ought to handle this itself, in which case the hack
+# here can be removed.
+#
+# Note this fix applies only when running "make check".  The cp here should
+# be done manually if just one program is to be built and run.
+#
+TESTS_ENVIRONMENT = cp $(top_builddir)/.libs/libgmp.so.* .libs 2>/dev/null || true;
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .cc .lo .log .o .obj .test .test$(EXEEXT) .trs
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu --ignore-deps tests/cxx/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu --ignore-deps tests/cxx/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-checkPROGRAMS:
+	@list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
+	echo " rm -f" $$list; \
+	rm -f $$list || exit $$?; \
+	test -n "$(EXEEXT)" || exit 0; \
+	list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+	echo " rm -f" $$list; \
+	rm -f $$list
+
+t-assign$(EXEEXT): $(t_assign_OBJECTS) $(t_assign_DEPENDENCIES) $(EXTRA_t_assign_DEPENDENCIES) 
+	@rm -f t-assign$(EXEEXT)
+	$(AM_V_CXXLD)$(CXXLINK) $(t_assign_OBJECTS) $(t_assign_LDADD) $(LIBS)
+
+t-binary$(EXEEXT): $(t_binary_OBJECTS) $(t_binary_DEPENDENCIES) $(EXTRA_t_binary_DEPENDENCIES) 
+	@rm -f t-binary$(EXEEXT)
+	$(AM_V_CXXLD)$(CXXLINK) $(t_binary_OBJECTS) $(t_binary_LDADD) $(LIBS)
+
+t-cast$(EXEEXT): $(t_cast_OBJECTS) $(t_cast_DEPENDENCIES) $(EXTRA_t_cast_DEPENDENCIES) 
+	@rm -f t-cast$(EXEEXT)
+	$(AM_V_CXXLD)$(CXXLINK) $(t_cast_OBJECTS) $(t_cast_LDADD) $(LIBS)
+
+t-constr$(EXEEXT): $(t_constr_OBJECTS) $(t_constr_DEPENDENCIES) $(EXTRA_t_constr_DEPENDENCIES) 
+	@rm -f t-constr$(EXEEXT)
+	$(AM_V_CXXLD)$(CXXLINK) $(t_constr_OBJECTS) $(t_constr_LDADD) $(LIBS)
+
+t-cxx11$(EXEEXT): $(t_cxx11_OBJECTS) $(t_cxx11_DEPENDENCIES) $(EXTRA_t_cxx11_DEPENDENCIES) 
+	@rm -f t-cxx11$(EXEEXT)
+	$(AM_V_CXXLD)$(CXXLINK) $(t_cxx11_OBJECTS) $(t_cxx11_LDADD) $(LIBS)
+
+t-do-exceptions-work-at-all-with-this-compiler$(EXEEXT): $(t_do_exceptions_work_at_all_with_this_compiler_OBJECTS) $(t_do_exceptions_work_at_all_with_this_compiler_DEPENDENCIES) $(EXTRA_t_do_exceptions_work_at_all_with_this_compiler_DEPENDENCIES) 
+	@rm -f t-do-exceptions-work-at-all-with-this-compiler$(EXEEXT)
+	$(AM_V_CXXLD)$(CXXLINK) $(t_do_exceptions_work_at_all_with_this_compiler_OBJECTS) $(t_do_exceptions_work_at_all_with_this_compiler_LDADD) $(LIBS)
+
+t-headers$(EXEEXT): $(t_headers_OBJECTS) $(t_headers_DEPENDENCIES) $(EXTRA_t_headers_DEPENDENCIES) 
+	@rm -f t-headers$(EXEEXT)
+	$(AM_V_CXXLD)$(CXXLINK) $(t_headers_OBJECTS) $(t_headers_LDADD) $(LIBS)
+
+t-iostream$(EXEEXT): $(t_iostream_OBJECTS) $(t_iostream_DEPENDENCIES) $(EXTRA_t_iostream_DEPENDENCIES) 
+	@rm -f t-iostream$(EXEEXT)
+	$(AM_V_CXXLD)$(CXXLINK) $(t_iostream_OBJECTS) $(t_iostream_LDADD) $(LIBS)
+
+t-istream$(EXEEXT): $(t_istream_OBJECTS) $(t_istream_DEPENDENCIES) $(EXTRA_t_istream_DEPENDENCIES) 
+	@rm -f t-istream$(EXEEXT)
+	$(AM_V_CXXLD)$(CXXLINK) $(t_istream_OBJECTS) $(t_istream_LDADD) $(LIBS)
+
+t-locale$(EXEEXT): $(t_locale_OBJECTS) $(t_locale_DEPENDENCIES) $(EXTRA_t_locale_DEPENDENCIES) 
+	@rm -f t-locale$(EXEEXT)
+	$(AM_V_CXXLD)$(CXXLINK) $(t_locale_OBJECTS) $(t_locale_LDADD) $(LIBS)
+
+t-misc$(EXEEXT): $(t_misc_OBJECTS) $(t_misc_DEPENDENCIES) $(EXTRA_t_misc_DEPENDENCIES) 
+	@rm -f t-misc$(EXEEXT)
+	$(AM_V_CXXLD)$(CXXLINK) $(t_misc_OBJECTS) $(t_misc_LDADD) $(LIBS)
+
+t-mix$(EXEEXT): $(t_mix_OBJECTS) $(t_mix_DEPENDENCIES) $(EXTRA_t_mix_DEPENDENCIES) 
+	@rm -f t-mix$(EXEEXT)
+	$(AM_V_CXXLD)$(CXXLINK) $(t_mix_OBJECTS) $(t_mix_LDADD) $(LIBS)
+
+t-ops$(EXEEXT): $(t_ops_OBJECTS) $(t_ops_DEPENDENCIES) $(EXTRA_t_ops_DEPENDENCIES) 
+	@rm -f t-ops$(EXEEXT)
+	$(AM_V_CXXLD)$(CXXLINK) $(t_ops_OBJECTS) $(t_ops_LDADD) $(LIBS)
+
+t-ops2f$(EXEEXT): $(t_ops2f_OBJECTS) $(t_ops2f_DEPENDENCIES) $(EXTRA_t_ops2f_DEPENDENCIES) 
+	@rm -f t-ops2f$(EXEEXT)
+	$(AM_V_CXXLD)$(CXXLINK) $(t_ops2f_OBJECTS) $(t_ops2f_LDADD) $(LIBS)
+
+t-ops2qf$(EXEEXT): $(t_ops2qf_OBJECTS) $(t_ops2qf_DEPENDENCIES) $(EXTRA_t_ops2qf_DEPENDENCIES) 
+	@rm -f t-ops2qf$(EXEEXT)
+	$(AM_V_CXXLD)$(CXXLINK) $(t_ops2qf_OBJECTS) $(t_ops2qf_LDADD) $(LIBS)
+
+t-ops2z$(EXEEXT): $(t_ops2z_OBJECTS) $(t_ops2z_DEPENDENCIES) $(EXTRA_t_ops2z_DEPENDENCIES) 
+	@rm -f t-ops2z$(EXEEXT)
+	$(AM_V_CXXLD)$(CXXLINK) $(t_ops2z_OBJECTS) $(t_ops2z_LDADD) $(LIBS)
+
+t-ops3$(EXEEXT): $(t_ops3_OBJECTS) $(t_ops3_DEPENDENCIES) $(EXTRA_t_ops3_DEPENDENCIES) 
+	@rm -f t-ops3$(EXEEXT)
+	$(AM_V_CXXLD)$(CXXLINK) $(t_ops3_OBJECTS) $(t_ops3_LDADD) $(LIBS)
+
+t-ostream$(EXEEXT): $(t_ostream_OBJECTS) $(t_ostream_DEPENDENCIES) $(EXTRA_t_ostream_DEPENDENCIES) 
+	@rm -f t-ostream$(EXEEXT)
+	$(AM_V_CXXLD)$(CXXLINK) $(t_ostream_OBJECTS) $(t_ostream_LDADD) $(LIBS)
+
+t-prec$(EXEEXT): $(t_prec_OBJECTS) $(t_prec_DEPENDENCIES) $(EXTRA_t_prec_DEPENDENCIES) 
+	@rm -f t-prec$(EXEEXT)
+	$(AM_V_CXXLD)$(CXXLINK) $(t_prec_OBJECTS) $(t_prec_LDADD) $(LIBS)
+
+t-rand$(EXEEXT): $(t_rand_OBJECTS) $(t_rand_DEPENDENCIES) $(EXTRA_t_rand_DEPENDENCIES) 
+	@rm -f t-rand$(EXEEXT)
+	$(AM_V_CXXLD)$(CXXLINK) $(t_rand_OBJECTS) $(t_rand_LDADD) $(LIBS)
+
+t-ternary$(EXEEXT): $(t_ternary_OBJECTS) $(t_ternary_DEPENDENCIES) $(EXTRA_t_ternary_DEPENDENCIES) 
+	@rm -f t-ternary$(EXEEXT)
+	$(AM_V_CXXLD)$(CXXLINK) $(t_ternary_OBJECTS) $(t_ternary_LDADD) $(LIBS)
+
+t-unary$(EXEEXT): $(t_unary_OBJECTS) $(t_unary_DEPENDENCIES) $(EXTRA_t_unary_DEPENDENCIES) 
+	@rm -f t-unary$(EXEEXT)
+	$(AM_V_CXXLD)$(CXXLINK) $(t_unary_OBJECTS) $(t_unary_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+.c.o:
+	$(AM_V_CC)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+	$(AM_V_CC)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+	$(AM_V_CC)$(LTCOMPILE) -c -o $@ $<
+
+.cc.o:
+	$(AM_V_CXX)$(CXXCOMPILE) -c -o $@ $<
+
+.cc.obj:
+	$(AM_V_CXX)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cc.lo:
+	$(AM_V_CXX)$(LTCXXCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+# Recover from deleted '.trs' file; this should ensure that
+# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create
+# both 'foo.log' and 'foo.trs'.  Break the recipe in two subshells
+# to avoid problems with "make -n".
+.log.trs:
+	rm -f $< $@
+	$(MAKE) $(AM_MAKEFLAGS) $<
+
+# Leading 'am--fnord' is there to ensure the list of targets does not
+# expand to empty, as could happen e.g. with make check TESTS=''.
+am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck)
+am--force-recheck:
+	@:
+
+$(TEST_SUITE_LOG): $(TEST_LOGS)
+	@$(am__set_TESTS_bases); \
+	am__f_ok () { test -f "$$1" && test -r "$$1"; }; \
+	redo_bases=`for i in $$bases; do \
+	              am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \
+	            done`; \
+	if test -n "$$redo_bases"; then \
+	  redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \
+	  redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \
+	  if $(am__make_dryrun); then :; else \
+	    rm -f $$redo_logs && rm -f $$redo_results || exit 1; \
+	  fi; \
+	fi; \
+	if test -n "$$am__remaking_logs"; then \
+	  echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \
+	       "recursion detected" >&2; \
+	elif test -n "$$redo_logs"; then \
+	  am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \
+	fi; \
+	if $(am__make_dryrun); then :; else \
+	  st=0;  \
+	  errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \
+	  for i in $$redo_bases; do \
+	    test -f $$i.trs && test -r $$i.trs \
+	      || { echo "$$errmsg $$i.trs" >&2; st=1; }; \
+	    test -f $$i.log && test -r $$i.log \
+	      || { echo "$$errmsg $$i.log" >&2; st=1; }; \
+	  done; \
+	  test $$st -eq 0 || exit 1; \
+	fi
+	@$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \
+	ws='[ 	]'; \
+	results=`for b in $$bases; do echo $$b.trs; done`; \
+	test -n "$$results" || results=/dev/null; \
+	all=`  grep "^$$ws*:test-result:"           $$results | wc -l`; \
+	pass=` grep "^$$ws*:test-result:$$ws*PASS"  $$results | wc -l`; \
+	fail=` grep "^$$ws*:test-result:$$ws*FAIL"  $$results | wc -l`; \
+	skip=` grep "^$$ws*:test-result:$$ws*SKIP"  $$results | wc -l`; \
+	xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \
+	xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \
+	error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \
+	if test `expr $$fail + $$xpass + $$error` -eq 0; then \
+	  success=true; \
+	else \
+	  success=false; \
+	fi; \
+	br='==================='; br=$$br$$br$$br$$br; \
+	result_count () \
+	{ \
+	    if test x"$$1" = x"--maybe-color"; then \
+	      maybe_colorize=yes; \
+	    elif test x"$$1" = x"--no-color"; then \
+	      maybe_colorize=no; \
+	    else \
+	      echo "$@: invalid 'result_count' usage" >&2; exit 4; \
+	    fi; \
+	    shift; \
+	    desc=$$1 count=$$2; \
+	    if test $$maybe_colorize = yes && test $$count -gt 0; then \
+	      color_start=$$3 color_end=$$std; \
+	    else \
+	      color_start= color_end=; \
+	    fi; \
+	    echo "$${color_start}# $$desc $$count$${color_end}"; \
+	}; \
+	create_testsuite_report () \
+	{ \
+	  result_count $$1 "TOTAL:" $$all   "$$brg"; \
+	  result_count $$1 "PASS: " $$pass  "$$grn"; \
+	  result_count $$1 "SKIP: " $$skip  "$$blu"; \
+	  result_count $$1 "XFAIL:" $$xfail "$$lgn"; \
+	  result_count $$1 "FAIL: " $$fail  "$$red"; \
+	  result_count $$1 "XPASS:" $$xpass "$$red"; \
+	  result_count $$1 "ERROR:" $$error "$$mgn"; \
+	}; \
+	{								\
+	  echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" |	\
+	    $(am__rst_title);						\
+	  create_testsuite_report --no-color;				\
+	  echo;								\
+	  echo ".. contents:: :depth: 2";				\
+	  echo;								\
+	  for b in $$bases; do echo $$b; done				\
+	    | $(am__create_global_log);					\
+	} >$(TEST_SUITE_LOG).tmp || exit 1;				\
+	mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG);			\
+	if $$success; then						\
+	  col="$$grn";							\
+	 else								\
+	  col="$$red";							\
+	  test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG);		\
+	fi;								\
+	echo "$${col}$$br$${std}"; 					\
+	echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}";	\
+	echo "$${col}$$br$${std}"; 					\
+	create_testsuite_report --maybe-color;				\
+	echo "$$col$$br$$std";						\
+	if $$success; then :; else					\
+	  echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}";		\
+	  if test -n "$(PACKAGE_BUGREPORT)"; then			\
+	    echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}";	\
+	  fi;								\
+	  echo "$$col$$br$$std";					\
+	fi;								\
+	$$success || exit 1
+
+check-TESTS:
+	@list='$(RECHECK_LOGS)';           test -z "$$list" || rm -f $$list
+	@list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list
+	@test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+	@set +e; $(am__set_TESTS_bases); \
+	log_list=`for i in $$bases; do echo $$i.log; done`; \
+	trs_list=`for i in $$bases; do echo $$i.trs; done`; \
+	log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \
+	$(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \
+	exit $$?;
+recheck: all $(check_PROGRAMS)
+	@test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+	@set +e; $(am__set_TESTS_bases); \
+	bases=`for i in $$bases; do echo $$i; done \
+	         | $(am__list_recheck_tests)` || exit 1; \
+	log_list=`for i in $$bases; do echo $$i.log; done`; \
+	log_list=`echo $$log_list`; \
+	$(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \
+	        am__force_recheck=am--force-recheck \
+	        TEST_LOGS="$$log_list"; \
+	exit $$?
+t-binary.log: t-binary$(EXEEXT)
+	@p='t-binary$(EXEEXT)'; \
+	b='t-binary'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-cast.log: t-cast$(EXEEXT)
+	@p='t-cast$(EXEEXT)'; \
+	b='t-cast'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-cxx11.log: t-cxx11$(EXEEXT)
+	@p='t-cxx11$(EXEEXT)'; \
+	b='t-cxx11'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-headers.log: t-headers$(EXEEXT)
+	@p='t-headers$(EXEEXT)'; \
+	b='t-headers'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-iostream.log: t-iostream$(EXEEXT)
+	@p='t-iostream$(EXEEXT)'; \
+	b='t-iostream'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-istream.log: t-istream$(EXEEXT)
+	@p='t-istream$(EXEEXT)'; \
+	b='t-istream'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-locale.log: t-locale$(EXEEXT)
+	@p='t-locale$(EXEEXT)'; \
+	b='t-locale'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-misc.log: t-misc$(EXEEXT)
+	@p='t-misc$(EXEEXT)'; \
+	b='t-misc'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-mix.log: t-mix$(EXEEXT)
+	@p='t-mix$(EXEEXT)'; \
+	b='t-mix'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-ops.log: t-ops$(EXEEXT)
+	@p='t-ops$(EXEEXT)'; \
+	b='t-ops'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-ops2qf.log: t-ops2qf$(EXEEXT)
+	@p='t-ops2qf$(EXEEXT)'; \
+	b='t-ops2qf'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-ops2f.log: t-ops2f$(EXEEXT)
+	@p='t-ops2f$(EXEEXT)'; \
+	b='t-ops2f'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-ops3.log: t-ops3$(EXEEXT)
+	@p='t-ops3$(EXEEXT)'; \
+	b='t-ops3'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-ostream.log: t-ostream$(EXEEXT)
+	@p='t-ostream$(EXEEXT)'; \
+	b='t-ostream'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-prec.log: t-prec$(EXEEXT)
+	@p='t-prec$(EXEEXT)'; \
+	b='t-prec'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-ternary.log: t-ternary$(EXEEXT)
+	@p='t-ternary$(EXEEXT)'; \
+	b='t-ternary'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-unary.log: t-unary$(EXEEXT)
+	@p='t-unary$(EXEEXT)'; \
+	b='t-unary'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-do-exceptions-work-at-all-with-this-compiler.log: t-do-exceptions-work-at-all-with-this-compiler$(EXEEXT)
+	@p='t-do-exceptions-work-at-all-with-this-compiler$(EXEEXT)'; \
+	b='t-do-exceptions-work-at-all-with-this-compiler'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-ops2z.log: t-ops2z$(EXEEXT)
+	@p='t-ops2z$(EXEEXT)'; \
+	b='t-ops2z'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-assign.log: t-assign$(EXEEXT)
+	@p='t-assign$(EXEEXT)'; \
+	b='t-assign'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-constr.log: t-constr$(EXEEXT)
+	@p='t-constr$(EXEEXT)'; \
+	b='t-constr'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-rand.log: t-rand$(EXEEXT)
+	@p='t-rand$(EXEEXT)'; \
+	b='t-rand'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+.test.log:
+	@p='$<'; \
+	$(am__set_b); \
+	$(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+@am__EXEEXT_TRUE@.test$(EXEEXT).log:
+@am__EXEEXT_TRUE@	@p='$<'; \
+@am__EXEEXT_TRUE@	$(am__set_b); \
+@am__EXEEXT_TRUE@	$(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+@am__EXEEXT_TRUE@	--log-file $$b.log --trs-file $$b.trs \
+@am__EXEEXT_TRUE@	$(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+@am__EXEEXT_TRUE@	"$$tst" $(AM_TESTS_FD_REDIRECT)
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+	$(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+	-test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS)
+	-test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs)
+	-test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-TESTS check-am clean \
+	clean-checkPROGRAMS clean-generic clean-libtool cscopelist-am \
+	ctags ctags-am distclean distclean-compile distclean-generic \
+	distclean-libtool distclean-tags distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-dvi install-dvi-am install-exec \
+	install-exec-am install-html install-html-am install-info \
+	install-info-am install-man install-pdf install-pdf-am \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	recheck tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+$(top_builddir)/tests/libtests.la:
+	cd $(top_builddir)/tests; $(MAKE) $(AM_MAKEFLAGS) libtests.la
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/third_party/gmp/tests/cxx/clocale.c b/third_party/gmp/tests/cxx/clocale.c
new file mode 100644
index 0000000..7f7c36e
--- /dev/null
+++ b/third_party/gmp/tests/cxx/clocale.c
@@ -0,0 +1,66 @@
+/* Manipulable localeconv and nl_langinfo.
+
+Copyright 2001, 2002, 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#if HAVE_NL_TYPES_H
+#include <nl_types.h>  /* for nl_item */
+#endif
+
+#if HAVE_LANGINFO_H
+#include <langinfo.h>  /* for nl_langinfo */
+#endif
+
+#if HAVE_LOCALE_H
+#include <locale.h>    /* for lconv */
+#endif
+
+
+/* Replace the libc localeconv and nl_langinfo with ones we can manipulate.
+
+   This is done in a C file since if it was in a C++ file then we'd have to
+   match the "throw" or lack thereof declared for localeconv in <locale.h>.
+   g++ 3.2 gives an error about mismatched throws under "-pedantic", other
+   C++ compilers may very possibly do so too.  */
+
+extern char point_string[];
+
+#if HAVE_LOCALECONV && ! defined __MINGW32__
+struct lconv *
+localeconv (void)
+#if defined __cplusplus && defined __GLIBC__
+  throw()
+#endif
+{
+  static struct lconv  l;
+  l.decimal_point = point_string;
+  return &l;
+}
+#endif
+
+#if HAVE_NL_LANGINFO
+char *
+nl_langinfo (nl_item n)
+#if defined __cplusplus && defined __GLIBC__
+  throw()
+#endif
+{
+  return point_string;
+}
+#endif
diff --git a/third_party/gmp/tests/cxx/t-assign.cc b/third_party/gmp/tests/cxx/t-assign.cc
new file mode 100644
index 0000000..bd2e41a
--- /dev/null
+++ b/third_party/gmp/tests/cxx/t-assign.cc
@@ -0,0 +1,603 @@
+/* Test mp*_class assignment operators.
+
+Copyright 2001-2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#include <iostream>
+#include <string>
+
+#include "gmpxx.h"
+#include "gmp-impl.h"
+#include "tests.h"
+
+using std::string;
+using std::invalid_argument;
+
+
+void
+check_mpz (void)
+{
+  // operator=(const mpz_class &)
+  {
+    mpz_class a(123), b;
+    b = a; ASSERT_ALWAYS(b == 123);
+  }
+
+  // template <class T, class U> operator=(const __gmp_expr<T, U> &)
+  // not tested here, see t-unary.cc, t-binary.cc
+
+  // operator=(signed char)
+  {
+    signed char a = -127;
+    mpz_class b;
+    b = a; ASSERT_ALWAYS(b == -127);
+  }
+
+  // operator=(unsigned char)
+  {
+    unsigned char a = 255;
+    mpz_class b;
+    b = a; ASSERT_ALWAYS(b == 255);
+  }
+
+  // either signed or unsigned char, machine dependent
+  {
+    mpz_class a;
+    a = 'A'; ASSERT_ALWAYS(a == 65);
+  }
+  {
+    mpz_class a;
+    a = 'z'; ASSERT_ALWAYS(a == 122);
+  }
+
+  // operator=(signed int)
+  {
+    signed int a = 0;
+    mpz_class b;
+    b = a; ASSERT_ALWAYS(b == 0);
+  }
+  {
+    signed int a = -123;
+    mpz_class b;
+    b = a; ASSERT_ALWAYS(b == -123);
+  }
+  {
+    signed int a = 32767;
+    mpz_class b;
+    b = a; ASSERT_ALWAYS(b == 32767);
+  }
+
+  // operator=(unsigned int)
+  {
+    unsigned int a = 65535u;
+    mpz_class b;
+    b = a; ASSERT_ALWAYS(b == 65535u);
+  }
+
+  // operator=(signed short int)
+  {
+    signed short int a = -12345;
+    mpz_class b;
+    b = a; ASSERT_ALWAYS(b == -12345);
+  }
+
+  // operator=(unsigned short int)
+  {
+    unsigned short int a = 54321u;
+    mpz_class b;
+    b = a; ASSERT_ALWAYS(b == 54321u);
+  }
+
+  // operator=(signed long int)
+  {
+    signed long int a = -1234567890L;
+    mpz_class b;
+    b = a; ASSERT_ALWAYS(b == -1234567890L);
+  }
+
+  // operator=(unsigned long int)
+  {
+    unsigned long int a = 3456789012UL;
+    mpz_class b;
+    b = a; ASSERT_ALWAYS(b == 3456789012UL);
+  }
+
+  // operator=(float)
+  {
+    float a = 123.0;
+    mpz_class b;
+    b = a; ASSERT_ALWAYS(b == 123);
+  }
+
+  // operator=(double)
+  {
+    double a = 0.0;
+    mpz_class b;
+    b = a; ASSERT_ALWAYS(b == 0);
+  }
+  {
+    double a = -12.375;
+    mpz_class b;
+    b = a; ASSERT_ALWAYS(b == -12);
+  }
+  {
+    double a = 6.789e+3;
+    mpz_class b;
+    b = a; ASSERT_ALWAYS(b == 6789);
+  }
+  {
+    double a = 9.375e-1;
+    mpz_class b;
+    b = a; ASSERT_ALWAYS(b == 0);
+  }
+
+  // operator=(long double)
+  // currently not implemented
+
+  // operator=(const char *)
+  {
+    const char *a = "1234567890";
+    mpz_class b;
+    b = a; ASSERT_ALWAYS(b == 1234567890L);
+  }
+
+  // operator=(const std::string &)
+  {
+    string a("1234567890");
+    mpz_class b;
+    b = a; ASSERT_ALWAYS(b == 1234567890L);
+  }
+
+  // operator=(const char *) with invalid
+  {
+    try {
+      const char *a = "abc";
+      mpz_class b;
+      b = a;
+      ASSERT_ALWAYS (0);  /* should not be reached */
+    } catch (invalid_argument) {
+    }
+  }
+
+  // operator=(const std::string &) with invalid
+  {
+    try {
+      string a("def");
+      mpz_class b;
+      b = a;
+      ASSERT_ALWAYS (0);  /* should not be reached */
+    } catch (invalid_argument) {
+    }
+  }
+
+  // swap(mpz_class &)
+  {
+    mpz_class a(123);
+    mpz_class b(456);
+    a.swap(b);
+    a.swap(a);
+    ASSERT_ALWAYS(a == 456);
+    ASSERT_ALWAYS(b == 123);
+  }
+
+  // swap(mpz_class &, mpz_class &)
+  {
+    mpz_class a(123);
+    mpz_class b(456);
+    ::swap(a, b);
+    ::swap(a, a);
+    ASSERT_ALWAYS(a == 456);
+    ASSERT_ALWAYS(b == 123);
+  }
+  {
+    using std::swap;
+    mpz_class a(123);
+    mpz_class b(456);
+    swap(a, b);
+    swap(a, a);
+    ASSERT_ALWAYS(a == 456);
+    ASSERT_ALWAYS(b == 123);
+  }
+}
+
+void
+check_mpq (void)
+{
+  // operator=(const mpq_class &)
+  {
+    mpq_class a(1, 2), b;
+    b = a; ASSERT_ALWAYS(b == 0.5);
+  }
+
+  // template <class T, class U> operator=(const __gmp_expr<T, U> &)
+  // not tested here, see t-unary.cc, t-binary.cc
+
+  // operator=(signed char)
+  {
+    signed char a = -127;
+    mpq_class b;
+    b = a; ASSERT_ALWAYS(b == -127);
+  }
+
+  // operator=(unsigned char)
+  {
+    unsigned char a = 255;
+    mpq_class b;
+    b = a; ASSERT_ALWAYS(b == 255);
+  }
+
+  // either signed or unsigned char, machine dependent
+  {
+    mpq_class a;
+    a = 'A'; ASSERT_ALWAYS(a == 65);
+  }
+  {
+    mpq_class a;
+    a = 'z'; ASSERT_ALWAYS(a == 122);
+  }
+
+  // operator=(signed int)
+  {
+    signed int a = 0;
+    mpq_class b;
+    b = a; ASSERT_ALWAYS(b == 0);
+  }
+  {
+    signed int a = -123;
+    mpq_class b;
+    b = a; ASSERT_ALWAYS(b == -123);
+  }
+  {
+    signed int a = 32767;
+    mpq_class b;
+    b = a; ASSERT_ALWAYS(b == 32767);
+  }
+
+  // operator=(unsigned int)
+  {
+    unsigned int a = 65535u;
+    mpq_class b;
+    b = a; ASSERT_ALWAYS(b == 65535u);
+  }
+
+  // operator=(signed short int)
+  {
+    signed short int a = -12345;
+    mpq_class b;
+    b = a; ASSERT_ALWAYS(b == -12345);
+  }
+
+  // operator=(unsigned short int)
+  {
+    unsigned short int a = 54321u;
+    mpq_class b;
+    b = a; ASSERT_ALWAYS(b == 54321u);
+  }
+
+  // operator=(signed long int)
+  {
+    signed long int a = -1234567890L;
+    mpq_class b;
+    b = a; ASSERT_ALWAYS(b == -1234567890L);
+  }
+
+  // operator=(unsigned long int)
+  {
+    unsigned long int a = 3456789012UL;
+    mpq_class b;
+    b = a; ASSERT_ALWAYS(b == 3456789012UL);
+  }
+
+  // operator=(float)
+  {
+    float a = 123.0;
+    mpq_class b;
+    b = a; ASSERT_ALWAYS(b == 123);
+  }
+
+  // operator=(double)
+  {
+    double a = 0.0;
+    mpq_class b;
+    b = a; ASSERT_ALWAYS(b == 0);
+  }
+  {
+    double a = -12.375;
+    mpq_class b;
+    b = a; ASSERT_ALWAYS(b == -12.375);
+  }
+  {
+    double a = 6.789e+3;
+    mpq_class b;
+    b = a; ASSERT_ALWAYS(b == 6789);
+  }
+  {
+    double a = 9.375e-1;
+    mpq_class b;
+    b = a; ASSERT_ALWAYS(b == 0.9375);
+  }
+
+  // operator=(long double)
+  // currently not implemented
+
+  // operator=(const char *)
+  {
+    const char *a = "1234567890";
+    mpq_class b;
+    b = a; ASSERT_ALWAYS(b == 1234567890L);
+  }
+
+  // operator=(const std::string &)
+  {
+    string a("1234567890");
+    mpq_class b;
+    b = a; ASSERT_ALWAYS(b == 1234567890L);
+  }
+
+  // operator=(const char *) with invalid
+  {
+    try {
+      const char *a = "abc";
+      mpq_class b;
+      b = a;
+      ASSERT_ALWAYS (0);  /* should not be reached */
+    } catch (invalid_argument) {
+    }
+  }
+
+  // operator=(const std::string &) with invalid
+  {
+    try {
+      string a("def");
+      mpq_class b;
+      b = a;
+      ASSERT_ALWAYS (0);  /* should not be reached */
+    } catch (invalid_argument) {
+    }
+  }
+
+  // swap(mpq_class &)
+  {
+    mpq_class a(3, 2);
+    mpq_class b(-1, 4);
+    a.swap(b);
+    a.swap(a);
+    ASSERT_ALWAYS(a == -.25);
+    ASSERT_ALWAYS(b == 1.5);
+  }
+
+  // swap(mpq_class &, mpq_class &)
+  {
+    mpq_class a(3, 2);
+    mpq_class b(-1, 4);
+    ::swap(a, b);
+    ::swap(a, a);
+    ASSERT_ALWAYS(a == -.25);
+    ASSERT_ALWAYS(b == 1.5);
+  }
+  {
+    using std::swap;
+    mpq_class a(3, 2);
+    mpq_class b(-1, 4);
+    swap(a, b);
+    swap(a, a);
+    ASSERT_ALWAYS(a == -.25);
+    ASSERT_ALWAYS(b == 1.5);
+  }
+}
+
+void
+check_mpf (void)
+{
+  // operator=(const mpf_class &)
+  {
+    mpf_class a(123), b;
+    b = a; ASSERT_ALWAYS(b == 123);
+  }
+
+  // template <class T, class U> operator=(const __gmp_expr<T, U> &)
+  // not tested here, see t-unary.cc, t-binary.cc
+
+  // operator=(signed char)
+  {
+    signed char a = -127;
+    mpf_class b;
+    b = a; ASSERT_ALWAYS(b == -127);
+  }
+
+  // operator=(unsigned char)
+  {
+    unsigned char a = 255;
+    mpf_class b;
+    b = a; ASSERT_ALWAYS(b == 255);
+  }
+
+  // either signed or unsigned char, machine dependent
+  {
+    mpf_class a;
+    a = 'A'; ASSERT_ALWAYS(a == 65);
+  }
+  {
+    mpf_class a;
+    a = 'z'; ASSERT_ALWAYS(a == 122);
+  }
+
+  // operator=(signed int)
+  {
+    signed int a = 0;
+    mpf_class b;
+    b = a; ASSERT_ALWAYS(b == 0);
+  }
+  {
+    signed int a = -123;
+    mpf_class b;
+    b = a; ASSERT_ALWAYS(b == -123);
+  }
+  {
+    signed int a = 32767;
+    mpf_class b;
+    b = a; ASSERT_ALWAYS(b == 32767);
+  }
+
+  // operator=(unsigned int)
+  {
+    unsigned int a = 65535u;
+    mpf_class b;
+    b = a; ASSERT_ALWAYS(b == 65535u);
+  }
+
+  // operator=(signed short int)
+  {
+    signed short int a = -12345;
+    mpf_class b;
+    b = a; ASSERT_ALWAYS(b == -12345);
+  }
+
+  // operator=(unsigned short int)
+  {
+    unsigned short int a = 54321u;
+    mpf_class b;
+    b = a; ASSERT_ALWAYS(b == 54321u);
+  }
+
+  // operator=(signed long int)
+  {
+    signed long int a = -1234567890L;
+    mpf_class b;
+    b = a; ASSERT_ALWAYS(b == -1234567890L);
+  }
+
+  // operator=(unsigned long int)
+  {
+    unsigned long int a = 3456789012UL;
+    mpf_class b;
+    b = a; ASSERT_ALWAYS(b == 3456789012UL);
+  }
+
+  // operator=(float)
+  {
+    float a = 123.0;
+    mpf_class b;
+    b = a; ASSERT_ALWAYS(b == 123);
+  }
+
+  // operator=(double)
+  {
+    double a = 0.0;
+    mpf_class b;
+    b = a; ASSERT_ALWAYS(b == 0);
+  }
+  {
+    double a = -12.375;
+    mpf_class b;
+    b = a; ASSERT_ALWAYS(b == -12.375);
+  }
+  {
+    double a = 6.789e+3;
+    mpf_class b;
+    b = a; ASSERT_ALWAYS(b == 6789);
+  }
+  {
+    double a = 9.375e-1;
+    mpf_class b;
+    b = a; ASSERT_ALWAYS(b == 0.9375);
+  }
+
+  // operator=(long double)
+  // currently not implemented
+
+  // operator=(const char *)
+  {
+    const char *a = "1234567890";
+    mpf_class b;
+    b = a; ASSERT_ALWAYS(b == 1234567890L);
+  }
+
+  // operator=(const std::string &)
+  {
+    string a("1234567890");
+    mpf_class b;
+    b = a; ASSERT_ALWAYS(b == 1234567890L);
+  }
+
+  // operator=(const char *) with invalid
+  {
+    try {
+      const char *a = "abc";
+      mpf_class b;
+      b = a;
+      ASSERT_ALWAYS (0);  /* should not be reached */
+    } catch (invalid_argument) {
+    }
+  }
+
+  // operator=(const std::string &) with invalid
+  {
+    try {
+      string a("def");
+      mpf_class b;
+      b = a;
+      ASSERT_ALWAYS (0);  /* should not be reached */
+    } catch (invalid_argument) {
+    }
+  }
+
+  // swap(mpf_class &)
+  {
+    mpf_class a(123);
+    mpf_class b(456);
+    a.swap(b);
+    a.swap(a);
+    ASSERT_ALWAYS(a == 456);
+    ASSERT_ALWAYS(b == 123);
+  }
+
+  // swap(mpf_class &, mpf_class &)
+  {
+    mpf_class a(123);
+    mpf_class b(456);
+    ::swap(a, b);
+    ::swap(a, a);
+    ASSERT_ALWAYS(a == 456);
+    ASSERT_ALWAYS(b == 123);
+  }
+  {
+    using std::swap;
+    mpf_class a(123);
+    mpf_class b(456);
+    swap(a, b);
+    swap(a, a);
+    ASSERT_ALWAYS(a == 456);
+    ASSERT_ALWAYS(b == 123);
+  }
+}
+
+
+int
+main (void)
+{
+  tests_start();
+
+  check_mpz();
+  check_mpq();
+  check_mpf();
+
+  tests_end();
+  return 0;
+}
diff --git a/third_party/gmp/tests/cxx/t-binary.cc b/third_party/gmp/tests/cxx/t-binary.cc
new file mode 100644
index 0000000..697adfa
--- /dev/null
+++ b/third_party/gmp/tests/cxx/t-binary.cc
@@ -0,0 +1,465 @@
+/* Test mp*_class binary expressions.
+
+Copyright 2001-2003, 2008, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#include <iostream>
+
+#include "gmpxx.h"
+#include "gmp-impl.h"
+#include "tests.h"
+
+using namespace std;
+
+
+void
+check_mpz (void)
+{
+  // template <class T, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, T>, __gmp_expr<T, T>, Op> >
+  {
+    mpz_class a(1), b(2);
+    mpz_class c(a + b); ASSERT_ALWAYS(c == 3);
+  }
+  {
+    mpz_class a(3), b(4);
+    mpz_class c;
+    c = a * b; ASSERT_ALWAYS(c == 12);
+  }
+  {
+    mpz_class a(5), b(3);
+    mpz_class c;
+    c = a % b; ASSERT_ALWAYS(c == 2);
+  }
+
+  // template <class T, class U, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, T>, U, Op> >
+  {
+    mpz_class a(1);
+    signed int b = 3;
+    mpz_class c(a - b); ASSERT_ALWAYS(c == -2);
+  }
+  {
+    mpz_class a(-8);
+    unsigned int b = 2;
+    mpz_class c;
+    c = a / b; ASSERT_ALWAYS(c == -4);
+  }
+  {
+    mpz_class a(2);
+    double b = 3.0;
+    mpz_class c(a + b); ASSERT_ALWAYS(c == 5);
+  }
+  {
+    mpz_class a(4);
+    mpz_class b;
+    b = a + 0; ASSERT_ALWAYS(b == 4);
+  }
+
+  // template <class T, class U, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<U, __gmp_expr<T, T>, Op> >
+  {
+    mpz_class a(3);
+    signed int b = 9;
+    mpz_class c(b / a); ASSERT_ALWAYS(c == 3);
+  }
+
+  // template <class T, class U, class V, class W, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, U>, __gmp_expr<V, W>, Op> >
+  // type of result can't be mpz
+
+  // template <class T, class U, class V, class W, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<U, V>, __gmp_expr<T, W>, Op> >
+  // type of result can't be mpz
+
+  // template <class T, class U, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, T>, __gmp_expr<T, U>, Op> >
+  {
+    mpz_class a(3), b(4);
+    mpz_class c(a * (-b)); ASSERT_ALWAYS(c == -12);
+    c = c * (-b); ASSERT_ALWAYS(c == 48);
+  }
+
+  // template <class T, class U, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, U>, __gmp_expr<T, T>, Op> >
+  {
+    mpz_class a(3), b(2), c(1);
+    mpz_class d;
+    d = (a % b) + c; ASSERT_ALWAYS(d == 2);
+    d = (a % b) + d; ASSERT_ALWAYS(d == 3);
+  }
+
+  // template <class T, class U, class V, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, U>, V, Op> >
+  {
+    mpz_class a(-5);
+    unsigned int b = 2;
+    mpz_class c((-a) << b); ASSERT_ALWAYS(c == 20);
+  }
+  {
+    mpz_class a(5), b(-4);
+    signed int c = 3;
+    mpz_class d;
+    d = (a * b) >> c; ASSERT_ALWAYS(d == -3);
+  }
+
+  // template <class T, class U, class V, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<U, __gmp_expr<T, V>, Op> >
+  {
+    mpz_class a(2), b(4);
+    double c = 6;
+    mpz_class d(c / (a - b)); ASSERT_ALWAYS(d == -3);
+  }
+  {
+    mpz_class a(3), b(2);
+    double c = 1;
+    mpz_class d;
+    d = c + (a + b); ASSERT_ALWAYS(d == 6);
+  }
+
+  // template <class T, class U, class V, class W, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, U>, __gmp_expr<V, W>, Op> >
+  // type of result can't be mpz
+
+  // template <class T, class U, class V, class W, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<U, V>, __gmp_expr<T, W>, Op> >
+  // type of result can't be mpz
+
+  // template <class T, class U, class V, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, U>, __gmp_expr<T, V>, Op> >
+  {
+    mpz_class a(3), b(5), c(7);
+    mpz_class d;
+    d = (a - b) * (-c); ASSERT_ALWAYS(d == 14);
+    d = (b - d) * (-a); ASSERT_ALWAYS(d == 27);
+    d = (a - b) * (-d); ASSERT_ALWAYS(d == 54);
+  }
+
+  {
+    mpz_class a(0xcafe), b(0xbeef), c, want;
+    c = a & b; ASSERT_ALWAYS (c == 0x8aee);
+    c = a | b; ASSERT_ALWAYS (c == 0xfeff);
+    c = a ^ b; ASSERT_ALWAYS (c == 0x7411);
+    c = a & 0xbeef; ASSERT_ALWAYS (c == 0x8aee);
+    c = a | 0xbeef; ASSERT_ALWAYS (c == 0xfeff);
+    c = a ^ 0xbeef; ASSERT_ALWAYS (c == 0x7411);
+    c = a & -0xbeef; ASSERT_ALWAYS (c == 0x4010);
+    c = a | -0xbeef; ASSERT_ALWAYS (c == -0x3401);
+    c = a ^ -0xbeef; ASSERT_ALWAYS (c == -0x7411);
+    c = a & 48879.0; ASSERT_ALWAYS (c == 0x8aee);
+    c = a | 48879.0; ASSERT_ALWAYS (c == 0xfeff);
+    c = a ^ 48879.0; ASSERT_ALWAYS (c == 0x7411);
+
+    c = a | 1267650600228229401496703205376.0; // 2^100
+    want = "0x1000000000000000000000cafe";
+    ASSERT_ALWAYS (c == want);
+  }
+
+}
+
+void
+check_mpq (void)
+{
+  // template <class T, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, T>, __gmp_expr<T, T>, Op> >
+  {
+    mpq_class a(1, 2), b(3, 4);
+    mpq_class c(a + b); ASSERT_ALWAYS(c == 1.25);
+  }
+
+  // template <class T, class U, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, T>, U, Op> >
+  {
+    mpq_class a(1, 2);
+    signed int b = 3;
+    mpq_class c(a - b); ASSERT_ALWAYS(c == -2.5);
+  }
+  {
+    mpq_class a(1, 2);
+    mpq_class b;
+    b = a + 0; ASSERT_ALWAYS(b == 0.5);
+  }
+
+  // template <class T, class U, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<U, __gmp_expr<T, T>, Op> >
+  {
+    mpq_class a(2, 3);
+    signed int b = 4;
+    mpq_class c;
+    c = b / a; ASSERT_ALWAYS(c == 6);
+  }
+
+  // template <class T, class U, class V, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, T>, __gmp_expr<U, V>, Op> >
+  {
+    mpq_class a(1, 2);
+    mpz_class b(1);
+    mpq_class c(a + b); ASSERT_ALWAYS(c == 1.5);
+  }
+  {
+    mpq_class a(2, 3);
+    mpz_class b(1);
+    double c = 2.0;
+    mpq_class d;
+    d = a * (b + c); ASSERT_ALWAYS(d == 2);
+    d = d * (b + c); ASSERT_ALWAYS(d == 6);
+  }
+
+  // template <class T, class U, class V, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<U, V>, __gmp_expr<T, T>, Op> >
+  {
+    mpq_class a(2, 3);
+    mpz_class b(4);
+    mpq_class c(b / a); ASSERT_ALWAYS(c == 6);
+  }
+  {
+    mpq_class a(2, 3);
+    mpz_class b(1), c(4);
+    mpq_class d;
+    d = (b - c) * a; ASSERT_ALWAYS(d == -2);
+    d = (b - c) * d; ASSERT_ALWAYS(d == 6);
+  }
+
+  // template <class T, class U, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, T>, __gmp_expr<T, U>, Op> >
+  {
+    mpq_class a(1, 3), b(3, 4);
+    mpq_class c;
+    c = a * (-b); ASSERT_ALWAYS(c == -0.25);
+    a = a * (-b); ASSERT_ALWAYS(a == -0.25);
+  }
+
+  // template <class T, class U, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, U>, __gmp_expr<T, T>, Op> >
+  {
+    mpq_class a(1, 3), b(2, 3), c(1, 4);
+    mpq_class d((a / b) + c); ASSERT_ALWAYS(d == 0.75);
+    c = (a / b) + c; ASSERT_ALWAYS(c == 0.75);
+  }
+
+  // template <class T, class U, class V, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, U>, V, Op> >
+  {
+    mpq_class a(3, 8);
+    unsigned int b = 4;
+    mpq_class c((-a) << b); ASSERT_ALWAYS(c == -6);
+  }
+
+  // template <class T, class U, class V, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<U, __gmp_expr<T, V>, Op> >
+  {
+    mpq_class a(1, 2), b(1, 4);
+    double c = 6.0;
+    mpq_class d;
+    d = c / (a + b); ASSERT_ALWAYS(d == 8);
+  }
+
+  // template <class T, class U, class V, class W, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, U>, __gmp_expr<V, W>, Op> >
+  {
+    mpq_class a(1, 2), b(1, 4);
+    mpz_class c(1);
+    mpq_class d((a + b) - c); ASSERT_ALWAYS(d == -0.25);
+    d = (a + d) - c; ASSERT_ALWAYS(d == -0.75);
+    d = (a + d) - d.get_num(); ASSERT_ALWAYS(d == 2.75);
+    d = (2 * d) * d.get_den(); ASSERT_ALWAYS(d == 22);
+    d = (b * d) / -d.get_num(); ASSERT_ALWAYS(d == -0.25);
+  }
+  {
+    mpq_class a(1, 3), b(3, 2);
+    mpz_class c(2), d(4);
+    mpq_class e;
+    e = (a * b) / (c - d); ASSERT_ALWAYS(e == -0.25);
+    e = (2 * e) / (c - d); ASSERT_ALWAYS(e ==  0.25);
+  }
+
+  // template <class T, class U, class V, class W, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<U, V>, __gmp_expr<T, W>, Op> >
+  {
+    mpq_class a(1, 3), b(3, 4);
+    mpz_class c(-3);
+    mpq_class d(c * (a * b)); ASSERT_ALWAYS(d == -0.75);
+  }
+  {
+    mpq_class a(1, 3), b(3, 5);
+    mpz_class c(6);
+    signed int d = 4;
+    mpq_class e;
+    e = (c % d) / (a * b); ASSERT_ALWAYS(e == 10);
+    e = (e.get_num() % d) / (2 / e); ASSERT_ALWAYS(e == 10);
+  }
+
+  // template <class T, class U, class V, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, U>, __gmp_expr<T, V>, Op> >
+  {
+    mpq_class a(1, 3), b(3, 4), c(2, 5);
+    mpq_class d;
+    d = (a * b) / (-c); ASSERT_ALWAYS(d == -0.625);
+    d = (c * d) / (-b); ASSERT_ALWAYS(3 * d == 1);
+    d = (a * c) / (-d); ASSERT_ALWAYS(5 * d == -2);
+  }
+}
+
+void
+check_mpf (void)
+{
+  // template <class T, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, T>, __gmp_expr<T, T>, Op> >
+  {
+    mpf_class a(1), b(2);
+    mpf_class c(a + b); ASSERT_ALWAYS(c == 3);
+  }
+  {
+    mpf_class a(1.5), b(6);
+    mpf_class c;
+    c = a / b; ASSERT_ALWAYS(c == 0.25);
+  }
+
+  // template <class T, class U, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, T>, U, Op> >
+  {
+    mpf_class a(1);
+    signed int b = -2;
+    mpf_class c(a - b); ASSERT_ALWAYS(c == 3);
+  }
+  {
+    mpf_class a(2);
+    mpf_class b;
+    b = a + 0; ASSERT_ALWAYS(b == 2);
+  }
+
+  // template <class T, class U, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<U, __gmp_expr<T, T>, Op> >
+  {
+    mpf_class a(2);
+    unsigned int b = 3;
+    mpf_class c;
+    c = b / a; ASSERT_ALWAYS(c == 1.5);
+  }
+
+  // template <class T, class U, class V, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, T>, __gmp_expr<U, V>, Op> >
+  {
+    mpf_class a(2);
+    mpz_class b(3);
+    mpf_class c(a - b); ASSERT_ALWAYS(c == -1);
+  }
+  {
+    mpf_class a(3);
+    mpz_class b(2), c(1);
+    mpf_class d;
+    d = a * (b + c); ASSERT_ALWAYS(d == 9);
+    a = a * (b + c); ASSERT_ALWAYS(a == 9);
+  }
+
+  // template <class T, class U, class V, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<U, V>, __gmp_expr<T, T>, Op> >
+  {
+    mpf_class a(6);
+    mpq_class b(3, 4);
+    mpf_class c(a * b); ASSERT_ALWAYS(c == 4.5);
+  }
+
+  // template <class T, class U, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, T>, __gmp_expr<T, U>, Op> >
+  {
+    mpf_class a(2), b(-3);
+    mpf_class c;
+    c = a * (-b); ASSERT_ALWAYS(c == 6);
+    c = c * (-b); ASSERT_ALWAYS(c == 18);
+  }
+
+  // template <class T, class U, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, U>, __gmp_expr<T, T>, Op> >
+  {
+    mpf_class a(3), b(4), c(5);
+    mpf_class d;
+    d = (a / b) - c; ASSERT_ALWAYS(d == -4.25);
+    c = (a / b) - c; ASSERT_ALWAYS(c == -4.25);
+  }
+
+  // template <class T, class U, class V, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, U>, V, Op> >
+  {
+    mpf_class a(3);
+    unsigned int b = 2;
+    mpf_class c((-a) >> b); ASSERT_ALWAYS(c == -0.75);
+  }
+
+  // template <class T, class U, class V, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<U, __gmp_expr<T, V>, Op> >
+  {
+    mpf_class a(2), b(3);
+    double c = 5.0;
+    mpf_class d;
+    d = c / (a + b); ASSERT_ALWAYS(d == 1);
+  }
+
+  // template <class T, class U, class V, class W, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, U>, __gmp_expr<V, W>, Op> >
+  {
+    mpf_class a(2), b(3);
+    mpz_class c(4);
+    mpf_class d;
+    d = (a + b) * c; ASSERT_ALWAYS(d == 20);
+  }
+  {
+    mpf_class a(2), b(3);
+    mpq_class c(1, 2), d(1, 4);
+    mpf_class e;
+    e = (a * b) / (c + d); ASSERT_ALWAYS(e == 8);
+  }
+
+  // template <class T, class U, class V, class W, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<U, V>, __gmp_expr<T, W>, Op> >
+  {
+    mpf_class a(1), b(2);
+    mpq_class c(3);
+    mpf_class d(c / (a + b)); ASSERT_ALWAYS(d == 1);
+  }
+  {
+    mpf_class a(1);
+    mpz_class b(2);
+    mpq_class c(3, 4);
+    mpf_class d;
+    d = (-c) + (a + b); ASSERT_ALWAYS(d == 2.25);
+  }
+
+  // template <class T, class U, class V, class Op>
+  // __gmp_expr<T, __gmp_binary_expr<__gmp_expr<T, U>, __gmp_expr<T, V>, Op> >
+  {
+    mpf_class a(1), b(2), c(3);
+    mpf_class d;
+    d = (a + b) * (-c); ASSERT_ALWAYS(d == -9);
+  }
+}
+
+
+int
+main (void)
+{
+  tests_start();
+
+  check_mpz();
+  check_mpq();
+  check_mpf();
+
+  tests_end();
+  return 0;
+}
diff --git a/third_party/gmp/tests/cxx/t-cast.cc b/third_party/gmp/tests/cxx/t-cast.cc
new file mode 100644
index 0000000..983b3b8
--- /dev/null
+++ b/third_party/gmp/tests/cxx/t-cast.cc
@@ -0,0 +1,56 @@
+/* Test g++ -Wold-style-cast cleanliness.
+
+Copyright 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "gmpxx.h"
+
+
+/* This code doesn't do anything when run, it just expands various C macros
+   to see that they don't trigger compile-time warnings from g++
+   -Wold-style-cast.  This option isn't used in a normal build, it has to be
+   added manually to make this test worthwhile.  */
+
+void
+check_macros (void)
+{
+  mpz_t          z;
+  long           l = 123;
+  unsigned long  u = 456;
+  int            i;
+  mp_limb_t      limb;
+
+  mpz_init_set_ui (z, 0L);
+  i = mpz_odd_p (z);
+  i = mpz_even_p (z);
+  i = mpz_cmp_si (z, l);
+  i = mpz_cmp_ui (z, u);
+  mpz_clear (z);
+
+  limb = GMP_NUMB_MASK;
+  limb = GMP_NUMB_MAX;
+  limb = GMP_NAIL_MASK;
+
+  mpn_divmod (&limb, &limb, 1, &limb, 1);
+  mpn_divexact_by3 (&limb, &limb, 1);
+}
+
+int
+main (void)
+{
+  return 0;
+}
diff --git a/third_party/gmp/tests/cxx/t-constr.cc b/third_party/gmp/tests/cxx/t-constr.cc
new file mode 100644
index 0000000..0b2ac97
--- /dev/null
+++ b/third_party/gmp/tests/cxx/t-constr.cc
@@ -0,0 +1,755 @@
+/* Test mp*_class constructors.
+
+Copyright 2001-2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#include <iostream>
+#include <string>
+
+#include "gmpxx.h"
+#include "gmp-impl.h"
+#include "tests.h"
+
+using namespace std;
+
+
+void
+check_mpz (void)
+{
+  // mpz_class()
+  {
+    mpz_class a; ASSERT_ALWAYS(a == 0);
+  }
+
+  // mpz_class(const mpz_class &)
+  // see below
+
+  // template <class T, class U> mpz_class(const __gmp_expr<T, U> &)
+  // not tested here, see t-unary.cc, t-binary.cc
+
+  // mpz_class(signed char)
+  {
+    signed char a = -127;
+    mpz_class b(a); ASSERT_ALWAYS(b == -127);
+  }
+
+  // mpz_class(unsigned char)
+  {
+    unsigned char a = 255;
+    mpz_class b(a); ASSERT_ALWAYS(b == 255);
+  }
+
+  // either signed or unsigned char, machine dependent
+  {
+    mpz_class a('A'); ASSERT_ALWAYS(a == 65);
+  }
+  {
+    mpz_class a('z'); ASSERT_ALWAYS(a == 122);
+  }
+
+  // mpz_class(signed int)
+  {
+    signed int a = 0;
+    mpz_class b(a); ASSERT_ALWAYS(b == 0);
+  }
+  {
+    signed int a = -123;
+    mpz_class b(a); ASSERT_ALWAYS(b == -123);
+  }
+  {
+    signed int a = 4567;
+    mpz_class b(a); ASSERT_ALWAYS(b == 4567);
+  }
+
+  // mpz_class(unsigned int)
+  {
+    unsigned int a = 890;
+    mpz_class b(a); ASSERT_ALWAYS(b == 890);
+  }
+
+  // mpz_class(signed short int)
+  {
+    signed short int a = -12345;
+    mpz_class b(a); ASSERT_ALWAYS(b == -12345);
+  }
+
+  // mpz_class(unsigned short int)
+  {
+    unsigned short int a = 54321u;
+    mpz_class b(a); ASSERT_ALWAYS(b == 54321u);
+  }
+
+  // mpz_class(signed long int)
+  {
+    signed long int a = -1234567890L;
+    mpz_class b(a); ASSERT_ALWAYS(b == -1234567890L);
+  }
+
+  // mpz_class(unsigned long int)
+  {
+    unsigned long int a = 1UL << 30;
+    mpz_class b(a); ASSERT_ALWAYS(b == 1073741824L);
+  }
+
+  // mpz_class(float)
+  {
+    float a = 123.45;
+    mpz_class b(a); ASSERT_ALWAYS(b == 123);
+  }
+
+  // mpz_class(double)
+  {
+    double a = 3.141592653589793238;
+    mpz_class b(a); ASSERT_ALWAYS(b == 3);
+  }
+
+  // mpz_class(long double)
+  // currently not implemented
+
+  // mpz_class(const char *)
+  {
+    const char *a = "1234567890";
+    mpz_class b(a); ASSERT_ALWAYS(b == 1234567890L);
+  }
+
+  // mpz_class(const char *, int)
+  {
+    const char *a = "FFFF";
+    int base = 16;
+    mpz_class b(a, base); ASSERT_ALWAYS(b == 65535u);
+  }
+
+  // mpz_class(const std::string &)
+  {
+    string a("1234567890");
+    mpz_class b(a); ASSERT_ALWAYS(b == 1234567890L);
+  }
+
+  // mpz_class(const std::string &, int)
+  {
+    string a("7777");
+    int base = 8;
+    mpz_class b(a, base); ASSERT_ALWAYS(b == 4095);
+  }
+
+  // mpz_class(const char *) with invalid
+  {
+    try {
+      const char *a = "ABC";
+      mpz_class b(a);
+      ASSERT_ALWAYS (0);  /* should not be reached */
+    } catch (invalid_argument) {
+    }
+  }
+
+  // mpz_class(const char *, int) with invalid
+  {
+    try {
+      const char *a = "GHI";
+      int base = 16;
+      mpz_class b(a, base);
+      ASSERT_ALWAYS (0);  /* should not be reached */
+    } catch (invalid_argument) {
+    }
+  }
+
+  // mpz_class(const std::string &) with invalid
+  {
+    try {
+      string a("abc");
+      mpz_class b(a);
+      ASSERT_ALWAYS (0);  /* should not be reached */
+    } catch (invalid_argument) {
+    }
+  }
+
+  // mpz_class(const std::string &, int) with invalid
+  {
+    try {
+      string a("ZZZ");
+      int base = 8;
+      mpz_class b(a, base);
+      ASSERT_ALWAYS (0);  /* should not be reached */
+    } catch (invalid_argument) {
+    }
+  }
+
+  // mpz_class(mpz_srcptr)
+  {
+    mpz_t a;
+    mpz_init_set_ui(a, 100);
+    mpz_class b(a); ASSERT_ALWAYS(b == 100);
+    mpz_clear(a);
+  }
+
+  // mpz_class(const mpz_class &)
+  {
+    mpz_class a(12345); // tested above, assume it works
+    mpz_class b(a); ASSERT_ALWAYS(b == 12345);
+  }
+
+  // no constructor for bool, but it gets casted to int
+  {
+    bool a = true;
+    mpz_class b(a); ASSERT_ALWAYS(b == 1);
+  }
+  {
+    bool a = false;
+    mpz_class b(a); ASSERT_ALWAYS(b == 0);
+  }
+}
+
+void
+check_mpq (void)
+{
+  // mpq_class()
+  {
+    mpq_class a; ASSERT_ALWAYS(a == 0);
+  }
+
+  // mpq_class(const mpq_class &)
+  // see below
+
+  // template <class T, class U> mpq_class(const __gmp_expr<T, U> &)
+  // not tested here, see t-unary.cc, t-binary.cc
+
+  // mpq_class(signed char)
+  {
+    signed char a = -127;
+    mpq_class b(a); ASSERT_ALWAYS(b == -127);
+  }
+
+  // mpq_class(unsigned char)
+  {
+    unsigned char a = 255;
+    mpq_class b(a); ASSERT_ALWAYS(b == 255);
+  }
+
+  // either signed or unsigned char, machine dependent
+  {
+    mpq_class a('A'); ASSERT_ALWAYS(a == 65);
+  }
+  {
+    mpq_class a('z'); ASSERT_ALWAYS(a == 122);
+  }
+
+  // mpq_class(signed int)
+  {
+    signed int a = 0;
+    mpq_class b(a); ASSERT_ALWAYS(b == 0);
+  }
+  {
+    signed int a = -123;
+    mpq_class b(a); ASSERT_ALWAYS(b == -123);
+  }
+  {
+    signed int a = 4567;
+    mpq_class b(a); ASSERT_ALWAYS(b == 4567);
+  }
+
+  // mpq_class(unsigned int)
+  {
+    unsigned int a = 890;
+    mpq_class b(a); ASSERT_ALWAYS(b == 890);
+  }
+
+  // mpq_class(signed short int)
+  {
+    signed short int a = -12345;
+    mpq_class b(a); ASSERT_ALWAYS(b == -12345);
+  }
+
+  // mpq_class(unsigned short int)
+  {
+    unsigned short int a = 54321u;
+    mpq_class b(a); ASSERT_ALWAYS(b == 54321u);
+  }
+
+  // mpq_class(signed long int)
+  {
+    signed long int a = -1234567890L;
+    mpq_class b(a); ASSERT_ALWAYS(b == -1234567890L);
+  }
+
+  // mpq_class(unsigned long int)
+  {
+    unsigned long int a = 1UL << 30;
+    mpq_class b(a); ASSERT_ALWAYS(b == 1073741824L);
+  }
+
+  // mpq_class(float)
+  {
+    float a = 0.625;
+    mpq_class b(a); ASSERT_ALWAYS(b == 0.625);
+  }
+
+  // mpq_class(double)
+  {
+    double a = 1.25;
+    mpq_class b(a); ASSERT_ALWAYS(b == 1.25);
+  }
+
+  // mpq_class(long double)
+  // currently not implemented
+
+  // mpq_class(const char *)
+  {
+    const char *a = "1234567890";
+    mpq_class b(a); ASSERT_ALWAYS(b == 1234567890L);
+  }
+
+  // mpq_class(const char *, int)
+  {
+    const char *a = "FFFF";
+    int base = 16;
+    mpq_class b(a, base); ASSERT_ALWAYS(b == 65535u);
+    mpq_class c(0, 1); ASSERT_ALWAYS(c == 0);
+  }
+
+  // mpq_class(const std::string &)
+  {
+    string a("1234567890");
+    mpq_class b(a); ASSERT_ALWAYS(b == 1234567890L);
+  }
+
+  // mpq_class(const std::string &, int)
+  {
+    string a("7777");
+    int base = 8;
+    mpq_class b(a, base); ASSERT_ALWAYS(b == 4095);
+  }
+
+  // mpq_class(const char *) with invalid
+  {
+    try {
+      const char *a = "abc";
+      mpq_class b(a);
+      ASSERT_ALWAYS (0);  /* should not be reached */
+    } catch (invalid_argument) {
+    }
+  }
+
+  // mpq_class(const char *, int) with invalid
+  {
+    try {
+      const char *a = "ZZZ";
+      int base = 16;
+      mpq_class b (a, base);
+      ASSERT_ALWAYS (0);  /* should not be reached */
+    } catch (invalid_argument) {
+    }
+  }
+
+  // mpq_class(const std::string &) with invalid
+  {
+    try {
+      string a("abc");
+      mpq_class b(a);
+      ASSERT_ALWAYS (0);  /* should not be reached */
+    } catch (invalid_argument) {
+    }
+  }
+
+  // mpq_class(const std::string &, int) with invalid
+  {
+    try {
+      string a("ZZZ");
+      int base = 8;
+      mpq_class b (a, base);
+      ASSERT_ALWAYS (0);  /* should not be reached */
+    } catch (invalid_argument) {
+    }
+  }
+
+  // mpq_class(mpq_srcptr)
+  {
+    mpq_t a;
+    mpq_init(a);
+    mpq_set_ui(a, 100, 1);
+    mpq_class b(a); ASSERT_ALWAYS(b == 100);
+    mpq_clear(a);
+  }
+
+  // mpq_class(const mpz_class &, const mpz_class &)
+  {
+    mpz_class a(123), b(4); // tested above, assume it works
+    mpq_class c(a, b); ASSERT_ALWAYS(c == 30.75);
+  }
+  {
+    mpz_class a(-1), b(2);  // tested above, assume it works
+    mpq_class c(a, b); ASSERT_ALWAYS(c == -0.5);
+  }
+  {
+    mpz_class a(5), b(4); // tested above, assume it works
+    mpq_class c(a, b); ASSERT_ALWAYS(c == 1.25);
+  }
+
+  // mpq_class(const mpz_class &)
+  {
+    mpq_class a(12345); // tested above, assume it works
+    mpq_class b(a); ASSERT_ALWAYS(b == 12345);
+  }
+
+  // no constructor for bool, but it gets casted to int
+  {
+    bool a = true;
+    mpq_class b(a); ASSERT_ALWAYS(b == 1);
+  }
+  {
+    bool a = false;
+    mpq_class b(a); ASSERT_ALWAYS(b == 0);
+  }
+}
+
+void
+check_mpf (void)
+{
+  // mpf_class()
+  {
+    mpf_class a; ASSERT_ALWAYS(a == 0);
+  }
+
+  // mpf_class(const mpf_class &)
+  // mpf_class(const mpf_class &, unsigned long int)
+  // see below
+
+  // template <class T, class U> mpf_class(const __gmp_expr<T, U> &)
+  // template <class T, class U> mpf_class(const __gmp_expr<T, U> &,
+  //                                       unsigned long int)
+  // not tested here, see t-unary.cc, t-binary.cc
+
+  // mpf_class(signed char)
+  {
+    signed char a = -127;
+    mpf_class b(a); ASSERT_ALWAYS(b == -127);
+  }
+
+  // mpf_class(signed char, unsigned long int)
+  {
+    signed char a = -1;
+    int prec = 64;
+    mpf_class b(a, prec); ASSERT_ALWAYS(b == -1);
+  }
+
+  // mpf_class(unsigned char)
+  {
+    unsigned char a = 255;
+    mpf_class b(a); ASSERT_ALWAYS(b == 255);
+  }
+
+  // mpf_class(unsigned char, unsigned long int)
+  {
+    unsigned char a = 128;
+    int prec = 128;
+    mpf_class b(a, prec); ASSERT_ALWAYS(b == 128);
+  }
+
+  // either signed or unsigned char, machine dependent
+  {
+    mpf_class a('A'); ASSERT_ALWAYS(a == 65);
+  }
+  {
+    int prec = 256;
+    mpf_class a('z', prec); ASSERT_ALWAYS(a == 122);
+  }
+
+  // mpf_class(signed int)
+  {
+    signed int a = 0;
+    mpf_class b(a); ASSERT_ALWAYS(b == 0);
+  }
+  {
+    signed int a = -123;
+    mpf_class b(a); ASSERT_ALWAYS(b == -123);
+  }
+  {
+    signed int a = 4567;
+    mpf_class b(a); ASSERT_ALWAYS(b == 4567);
+  }
+
+  // mpf_class(signed int, unsigned long int)
+  {
+    signed int a = -123;
+    int prec = 64;
+    mpf_class b(a, prec); ASSERT_ALWAYS(b == -123);
+  }
+
+  // mpf_class(unsigned int)
+  {
+    unsigned int a = 890;
+    mpf_class b(a); ASSERT_ALWAYS(b == 890);
+  }
+
+  // mpf_class(unsigned int, unsigned long int)
+  {
+    unsigned int a = 890;
+    int prec = 128;
+    mpf_class b(a, prec); ASSERT_ALWAYS(b == 890);
+  }
+
+  // mpf_class(signed short int)
+  {
+    signed short int a = -12345;
+    mpf_class b(a); ASSERT_ALWAYS(b == -12345);
+  }
+
+  // mpf_class(signed short int, unsigned long int)
+  {
+    signed short int a = 6789;
+    int prec = 256;
+    mpf_class b(a, prec); ASSERT_ALWAYS(b == 6789);
+  }
+
+  // mpf_class(unsigned short int)
+  {
+    unsigned short int a = 54321u;
+    mpf_class b(a); ASSERT_ALWAYS(b == 54321u);
+  }
+
+  // mpf_class(unsigned short int, unsigned long int)
+  {
+    unsigned short int a = 54321u;
+    int prec = 64;
+    mpf_class b(a, prec); ASSERT_ALWAYS(b == 54321u);
+  }
+
+  // mpf_class(signed long int)
+  {
+    signed long int a = -1234567890L;
+    mpf_class b(a); ASSERT_ALWAYS(b == -1234567890L);
+  }
+
+  // mpf_class(signed long int, unsigned long int)
+  {
+    signed long int a = -1234567890L;
+    int prec = 128;
+    mpf_class b(a, prec); ASSERT_ALWAYS(b == -1234567890L);
+  }
+
+  // mpf_class(unsigned long int)
+  {
+    unsigned long int a = 3456789012UL;
+    mpf_class b(a); ASSERT_ALWAYS(b == 3456789012UL);
+  }
+
+  // mpf_class(unsigned long int, unsigned long int)
+  {
+    unsigned long int a = 3456789012UL;
+    int prec = 256;
+    mpf_class b(a, prec); ASSERT_ALWAYS(b == 3456789012UL);
+  }
+
+  // mpf_class(float)
+  {
+    float a = 1234.5;
+    mpf_class b(a); ASSERT_ALWAYS(b == 1234.5);
+  }
+
+  // mpf_class(float, unsigned long int)
+  {
+    float a = 1234.5;
+    int prec = 64;
+    mpf_class b(a, prec); ASSERT_ALWAYS(b == 1234.5);
+  }
+
+  // mpf_class(double)
+  {
+    double a = 12345.0;
+    mpf_class b(a); ASSERT_ALWAYS(b == 12345);
+  }
+  {
+    double a = 1.2345e+4;
+    mpf_class b(a); ASSERT_ALWAYS(b == 12345);
+  }
+  {
+    double a = 312.5e-2;
+    mpf_class b(a); ASSERT_ALWAYS(b == 3.125);
+  }
+
+  // mpf_class(double, unsigned long int)
+  {
+    double a = 5.4321e+4;
+    int prec = 128;
+    mpf_class b(a, prec); ASSERT_ALWAYS(b == 54321L);
+  }
+
+  // mpf_class(long double)
+  // mpf_class(long double, unsigned long int)
+  // currently not implemented
+
+  // mpf_class(const char *)
+  {
+    const char *a = "1234567890";
+    mpf_class b(a); ASSERT_ALWAYS(b == 1234567890L);
+  }
+
+  // mpf_class(const char *, unsigned long int, int = 0)
+  {
+    const char *a = "1234567890";
+    int prec = 256;
+    mpf_class b(a, prec); ASSERT_ALWAYS(b == 1234567890L);
+  }
+  {
+    const char *a = "777777";
+    int prec = 64, base = 8;
+    mpf_class b(a, prec, base); ASSERT_ALWAYS(b == 262143L);
+  }
+
+  // mpf_class(const std::string &)
+  {
+    string a("1234567890");
+    mpf_class b(a); ASSERT_ALWAYS(b == 1234567890L);
+  }
+
+  // mpf_class(const std::string &, unsigned long int, int = 0)
+  {
+    string a("1234567890");
+    int prec = 128;
+    mpf_class b(a, prec); ASSERT_ALWAYS(b == 1234567890L);
+  }
+  {
+    string a("FFFF");
+    int prec = 256, base = 16;
+    mpf_class b(a, prec, base); ASSERT_ALWAYS(b == 65535u);
+  }
+
+  // mpf_class(const char *) with invalid
+  {
+    try {
+      const char *a = "abc";
+      mpf_class b(a);
+      ASSERT_ALWAYS (0);  /* should not be reached */
+    } catch (invalid_argument) {
+    }
+  }
+
+  // mpf_class(const char *, unsigned long int, int = 0) with invalid
+  {
+    try {
+      const char *a = "def";
+      int prec = 256;
+      mpf_class b(a, prec); ASSERT_ALWAYS(b == 1234567890L);
+      ASSERT_ALWAYS (0);  /* should not be reached */
+    } catch (invalid_argument) {
+    }
+  }
+  {
+    try {
+      const char *a = "ghi";
+      int prec = 64, base = 8;
+      mpf_class b(a, prec, base); ASSERT_ALWAYS(b == 262143L);
+      ASSERT_ALWAYS (0);  /* should not be reached */
+    } catch (invalid_argument) {
+    }
+  }
+
+  // mpf_class(const std::string &) with invalid
+  {
+    try {
+      string a("abc");
+      mpf_class b(a); ASSERT_ALWAYS(b == 1234567890L);
+      ASSERT_ALWAYS (0);  /* should not be reached */
+    } catch (invalid_argument) {
+    }
+  }
+
+  // mpf_class(const std::string &, unsigned long int, int = 0) with invalid
+  {
+    try {
+      string a("def");
+      int prec = 128;
+      mpf_class b(a, prec); ASSERT_ALWAYS(b == 1234567890L);
+      ASSERT_ALWAYS (0);  /* should not be reached */
+    } catch (invalid_argument) {
+    }
+  }
+  {
+    try {
+      string a("ghi");
+      int prec = 256, base = 16;
+      mpf_class b(a, prec, base); ASSERT_ALWAYS(b == 65535u);
+      ASSERT_ALWAYS (0);  /* should not be reached */
+    } catch (invalid_argument) {
+    }
+  }
+
+  // mpf_class(mpf_srcptr)
+  {
+    mpf_t a;
+    mpf_init_set_ui(a, 100);
+    mpf_class b(a); ASSERT_ALWAYS(b == 100);
+    mpf_clear(a);
+  }
+
+  // mpf_class(mpf_srcptr, unsigned long int)
+  {
+    mpf_t a;
+    int prec = 64;
+    mpf_init_set_ui(a, 100);
+    mpf_class b(a, prec); ASSERT_ALWAYS(b == 100);
+    mpf_clear(a);
+  }
+
+  // mpf_class(const mpf_class &)
+  {
+    mpf_class a(12345); // tested above, assume it works
+    mpf_class b(a); ASSERT_ALWAYS(b == 12345);
+  }
+
+  // mpf_class(const mpf_class &, unsigned long int)
+  {
+    mpf_class a(12345); // tested above, assume it works
+    int prec = 64;
+    mpf_class b(a, prec); ASSERT_ALWAYS(b == 12345);
+  }
+
+  // no constructors for bool, but it gets casted to int
+  {
+    bool a = true;
+    mpf_class b(a); ASSERT_ALWAYS(b == 1);
+  }
+  {
+    bool a = false;
+    mpf_class b(a); ASSERT_ALWAYS(b == 0);
+  }
+  {
+    bool a = true;
+    int prec = 128;
+    mpf_class b(a, prec); ASSERT_ALWAYS(b == 1);
+  }
+  {
+    bool a = false;
+    int prec = 256;
+    mpf_class b(a, prec); ASSERT_ALWAYS(b == 0);
+  }
+}
+
+
+int
+main (void)
+{
+  tests_start();
+
+  check_mpz();
+  check_mpq();
+  check_mpf();
+
+  tests_end();
+  return 0;
+}
diff --git a/third_party/gmp/tests/cxx/t-cxx11.cc b/third_party/gmp/tests/cxx/t-cxx11.cc
new file mode 100644
index 0000000..8d6fccb
--- /dev/null
+++ b/third_party/gmp/tests/cxx/t-cxx11.cc
@@ -0,0 +1,232 @@
+/* Test C++11 features
+
+Copyright 2011, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#include "gmpxx.h"
+#include "gmp-impl.h"
+#include "tests.h"
+
+#if __GMPXX_USE_CXX11
+
+#include <utility>
+#include <type_traits>
+
+void check_noexcept ()
+{
+  mpz_class z1, z2;
+  mpq_class q1, q2;
+  mpf_class f1, f2;
+  static_assert(noexcept(z1 = std::move(z2)), "sorry");
+  static_assert(noexcept(q1 = std::move(q2)), "sorry");
+  static_assert(noexcept(f1 = std::move(f2)), "sorry");
+  static_assert(noexcept(q1 = std::move(z1)), "sorry");
+
+  // Only mpz has lazy allocation for now
+  static_assert(std::is_nothrow_default_constructible<mpz_class>::value, "sorry");
+  static_assert(std::is_nothrow_move_constructible<mpz_class>::value, "sorry");
+  static_assert(!std::is_nothrow_default_constructible<mpq_class>::value, "sorry");
+  static_assert(!std::is_nothrow_move_constructible<mpq_class>::value, "sorry");
+  static_assert(!std::is_nothrow_default_constructible<mpf_class>::value, "sorry");
+  static_assert(!std::is_nothrow_move_constructible<mpf_class>::value, "sorry");
+}
+
+void check_common_type ()
+{
+#define CHECK_COMMON_TYPE1(T, Res) \
+  static_assert(std::is_same<std::common_type<T>::type, Res>::value, "sorry")
+#define CHECK_COMMON_TYPE(T, U, Res) \
+  static_assert(std::is_same<std::common_type<T, U>::type, Res>::value, "sorry")
+#define CHECK_COMMON_TYPE_BUILTIN1(T, Res) \
+  CHECK_COMMON_TYPE(  signed char , T, Res); \
+  CHECK_COMMON_TYPE(unsigned char , T, Res); \
+  CHECK_COMMON_TYPE(  signed short, T, Res); \
+  CHECK_COMMON_TYPE(unsigned short, T, Res); \
+  CHECK_COMMON_TYPE(  signed int  , T, Res); \
+  CHECK_COMMON_TYPE(unsigned int  , T, Res); \
+  CHECK_COMMON_TYPE(  signed long , T, Res); \
+  CHECK_COMMON_TYPE(unsigned long , T, Res); \
+  CHECK_COMMON_TYPE(float , T, Res); \
+  CHECK_COMMON_TYPE(double, T, Res)
+#define CHECK_COMMON_TYPE_BUILTIN2(T, Res) \
+  CHECK_COMMON_TYPE(T,   signed char , Res); \
+  CHECK_COMMON_TYPE(T, unsigned char , Res); \
+  CHECK_COMMON_TYPE(T,   signed short, Res); \
+  CHECK_COMMON_TYPE(T, unsigned short, Res); \
+  CHECK_COMMON_TYPE(T,   signed int  , Res); \
+  CHECK_COMMON_TYPE(T, unsigned int  , Res); \
+  CHECK_COMMON_TYPE(T,   signed long , Res); \
+  CHECK_COMMON_TYPE(T, unsigned long , Res); \
+  CHECK_COMMON_TYPE(T, float , Res); \
+  CHECK_COMMON_TYPE(T, double, Res)
+#define CHECK_COMMON_TYPE_BUILTIN(T, Res) \
+  CHECK_COMMON_TYPE_BUILTIN1(T, Res); \
+  CHECK_COMMON_TYPE_BUILTIN2(T, Res)
+  /* These would just work with implicit conversions */
+  CHECK_COMMON_TYPE (mpz_class, mpq_class, mpq_class);
+  CHECK_COMMON_TYPE (mpz_class, mpf_class, mpf_class);
+  CHECK_COMMON_TYPE (mpf_class, mpq_class, mpf_class);
+
+  CHECK_COMMON_TYPE_BUILTIN (mpz_class, mpz_class);
+  CHECK_COMMON_TYPE_BUILTIN (mpq_class, mpq_class);
+  CHECK_COMMON_TYPE_BUILTIN (mpf_class, mpf_class);
+
+  mpz_class z; mpq_class q; mpf_class f;
+
+  CHECK_COMMON_TYPE (decltype(-z), mpz_class, mpz_class);
+  CHECK_COMMON_TYPE (decltype(-q), mpq_class, mpq_class);
+  CHECK_COMMON_TYPE (decltype(-f), mpf_class, mpf_class);
+
+  CHECK_COMMON_TYPE (decltype(-z), mpq_class, mpq_class);
+  CHECK_COMMON_TYPE (decltype(-z), mpf_class, mpf_class);
+  CHECK_COMMON_TYPE (decltype(-q), mpf_class, mpf_class);
+
+  /* These require a common_type specialization */
+  CHECK_COMMON_TYPE (decltype(-z), decltype(z+z), mpz_class);
+  CHECK_COMMON_TYPE (decltype(-q), decltype(q+q), mpq_class);
+  CHECK_COMMON_TYPE (decltype(-f), decltype(f+f), mpf_class);
+
+  CHECK_COMMON_TYPE (decltype(-q), mpz_class, mpq_class);
+  CHECK_COMMON_TYPE (decltype(-f), mpz_class, mpf_class);
+  CHECK_COMMON_TYPE (decltype(-f), mpq_class, mpf_class);
+
+  CHECK_COMMON_TYPE (decltype(-z), decltype(-q), mpq_class);
+  CHECK_COMMON_TYPE (decltype(-z), decltype(-f), mpf_class);
+  CHECK_COMMON_TYPE (decltype(-q), decltype(-f), mpf_class);
+
+  /* common_type now decays */
+  CHECK_COMMON_TYPE (decltype(-z), decltype(-z), mpz_class);
+  CHECK_COMMON_TYPE (decltype(-q), decltype(-q), mpq_class);
+  CHECK_COMMON_TYPE (decltype(-f), decltype(-f), mpf_class);
+  CHECK_COMMON_TYPE1 (decltype(-z), mpz_class);
+  CHECK_COMMON_TYPE1 (decltype(-q), mpq_class);
+  CHECK_COMMON_TYPE1 (decltype(-f), mpf_class);
+
+  /* Painful */
+  CHECK_COMMON_TYPE_BUILTIN (decltype(-z), mpz_class);
+  CHECK_COMMON_TYPE_BUILTIN (decltype(-q), mpq_class);
+  CHECK_COMMON_TYPE_BUILTIN (decltype(-f), mpf_class);
+}
+
+template<class T, class U = T>
+void check_move_init ()
+{
+  {
+    // Delete moved-from x1
+    T x1 = 3;
+    U x2 = std::move(x1);
+    ASSERT_ALWAYS (x2 == 3);
+  }
+  {
+    // Assign to moved-from x1
+    T x1 = 2;
+    U x2 = std::move(x1);
+    x1 = -7;
+    ASSERT_ALWAYS (x1 == -7);
+    ASSERT_ALWAYS (x2 == 2);
+  }
+}
+
+template<class T, class U = T>
+void check_move_assign ()
+{
+  {
+    // Delete moved-from x1
+    T x1 = 3; U x2;
+    x2 = std::move(x1);
+    ASSERT_ALWAYS (x2 == 3);
+  }
+  {
+    // Assign to moved-from x1
+    T x1 = 2; U x2;
+    x2 = std::move(x1);
+    x1 = -7;
+    ASSERT_ALWAYS (x1 == -7);
+    ASSERT_ALWAYS (x2 == 2);
+  }
+  {
+    // Self move-assign (not necessary, but it happens to work...)
+    T x = 4;
+    x = std::move(x);
+    ASSERT_ALWAYS (x == 4);
+  }
+}
+
+void check_user_defined_literal ()
+{
+  ASSERT_ALWAYS (123_mpz % 5 == 3);
+  ASSERT_ALWAYS (-11_mpq / 22 == -.5);
+  ASSERT_ALWAYS (112.5e-1_mpf * 4 == 45);
+  {
+    mpz_class ref ( "123456789abcdef0123456789abcdef0123", 16);
+    ASSERT_ALWAYS (0x123456789abcdef0123456789abcdef0123_mpz == ref);
+  }
+}
+
+// Check for explicit conversion to bool
+void implicit_bool(bool);
+int implicit_bool(...);
+
+void check_bool_conversion ()
+{
+  const mpz_class zn = -2;
+  const mpq_class qn = -2;
+  const mpf_class fn = -2;
+  const mpz_class z0 =  0;
+  const mpq_class q0 =  0;
+  const mpf_class f0 =  0;
+  const mpz_class zp = +2;
+  const mpq_class qp = +2;
+  const mpf_class fp = +2;
+  if (zn && qn && fn && zp && qp && fp && !z0 && !q0 && !f0)
+    {
+      if (z0 || q0 || f0) ASSERT_ALWAYS(false);
+    }
+  else ASSERT_ALWAYS(false);
+  decltype(implicit_bool(zn)) zi = 1;
+  decltype(implicit_bool(qn)) qi = 1;
+  decltype(implicit_bool(fn)) fi = 1;
+  (void)(zi+qi+fi);
+}
+
+int
+main (void)
+{
+  tests_start();
+
+  check_noexcept();
+  check_common_type();
+  check_move_init<mpz_class>();
+  check_move_init<mpq_class>();
+  check_move_init<mpf_class>();
+  check_move_assign<mpz_class>();
+  check_move_assign<mpq_class>();
+  check_move_assign<mpf_class>();
+  check_move_init<mpz_class,mpq_class>();
+  check_move_assign<mpz_class,mpq_class>();
+  check_user_defined_literal();
+  check_bool_conversion();
+
+  tests_end();
+  return 0;
+}
+
+#else
+int main () { return 0; }
+#endif
diff --git a/third_party/gmp/tests/cxx/t-do-exceptions-work-at-all-with-this-compiler.cc b/third_party/gmp/tests/cxx/t-do-exceptions-work-at-all-with-this-compiler.cc
new file mode 100644
index 0000000..341a818
--- /dev/null
+++ b/third_party/gmp/tests/cxx/t-do-exceptions-work-at-all-with-this-compiler.cc
@@ -0,0 +1,38 @@
+/* Test if the compiler has working try / throw / catch.
+
+Copyright 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdexcept>
+
+inline void
+throw_expr ()
+{
+  throw std::invalid_argument ("Test");
+}
+
+using namespace std;
+
+int
+main ()
+{
+  try
+  {
+    throw_expr();
+  }
+  catch (invalid_argument) { }
+}
diff --git a/third_party/gmp/tests/cxx/t-headers.cc b/third_party/gmp/tests/cxx/t-headers.cc
new file mode 100644
index 0000000..35f7a25
--- /dev/null
+++ b/third_party/gmp/tests/cxx/t-headers.cc
@@ -0,0 +1,26 @@
+/* Test that gmpxx.h compiles correctly.
+
+Copyright 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "gmpxx.h"
+
+int
+main (void)
+{
+  return 0;
+}
diff --git a/third_party/gmp/tests/cxx/t-iostream.cc b/third_party/gmp/tests/cxx/t-iostream.cc
new file mode 100644
index 0000000..76e280b
--- /dev/null
+++ b/third_party/gmp/tests/cxx/t-iostream.cc
@@ -0,0 +1,106 @@
+/* Test stream formatted input and output on mp*_class
+
+Copyright 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <sstream>
+
+#include "gmpxx.h"
+#include "gmp-impl.h"
+#include "tests.h"
+
+using namespace std;
+
+// The tests are extremely basic. These functions just forward to the
+// ones tested in t-istream.cc and t-ostream.cc; we rely on those for
+// advanced tests and only check the syntax here.
+
+void
+checki ()
+{
+  {
+    istringstream i("123");
+    mpz_class x;
+    i >> x;
+    ASSERT_ALWAYS (x == 123);
+  }
+  {
+    istringstream i("3/4");
+    mpq_class x;
+    i >> x;
+    ASSERT_ALWAYS (x == .75);
+  }
+  {
+    istringstream i("1.5");
+    mpf_class x;
+    i >> x;
+    ASSERT_ALWAYS (x == 1.5);
+  }
+}
+
+void
+checko ()
+{
+  {
+    ostringstream o;
+    mpz_class x=123;
+    o << x;
+    ASSERT_ALWAYS (o.str() == "123");
+  }
+  {
+    ostringstream o;
+    mpz_class x=123;
+    o << (x+1);
+    ASSERT_ALWAYS (o.str() == "124");
+  }
+  {
+    ostringstream o;
+    mpq_class x(3,4);
+    o << x;
+    ASSERT_ALWAYS (o.str() == "3/4");
+  }
+  {
+    ostringstream o;
+    mpq_class x(3,4);
+    o << (x+1);
+    ASSERT_ALWAYS (o.str() == "7/4");
+  }
+  {
+    ostringstream o;
+    mpf_class x=1.5;
+    o << x;
+    ASSERT_ALWAYS (o.str() == "1.5");
+  }
+  {
+    ostringstream o;
+    mpf_class x=1.5;
+    o << (x+1);
+    ASSERT_ALWAYS (o.str() == "2.5");
+  }
+}
+
+int
+main (int argc, char *argv[])
+{
+  tests_start ();
+
+  checki ();
+  checko ();
+
+  tests_end ();
+  return 0;
+}
diff --git a/third_party/gmp/tests/cxx/t-istream.cc b/third_party/gmp/tests/cxx/t-istream.cc
new file mode 100644
index 0000000..76bcbab
--- /dev/null
+++ b/third_party/gmp/tests/cxx/t-istream.cc
@@ -0,0 +1,598 @@
+/* Test istream formatted input.
+
+Copyright 2001-2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <iostream>
+#include <cstdlib>
+#include <cstring>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+using namespace std;
+
+
+// Under option_check_standard, the various test cases for mpz operator>>
+// are put through the standard operator>> for long, and likewise mpf
+// operator>> is put through double.
+//
+// In g++ 3.3 this results in some printouts about the final position
+// indicated for something like ".e123".  Our mpf code stops at the "e"
+// since there's no mantissa digits, but g++ reads the whole thing and only
+// then decides it's bad.
+
+bool option_check_standard = false;
+
+
+// On some versions of g++ 2.96 it's been observed that putback() may leave
+// tellg() unchanged.  We believe this is incorrect and presumably the
+// result of a bug, since for instance it's ok in g++ 2.95 and g++ 3.3.  We
+// detect the problem at runtime and disable affected checks.
+
+bool putback_tellg_works = true;
+
+void
+check_putback_tellg (void)
+{
+  istringstream input ("hello");
+  streampos  old_pos, new_pos;
+  char  c;
+
+  input.get(c);
+  old_pos = input.tellg();
+  input.putback(c);
+  new_pos = input.tellg();
+
+  if (old_pos == new_pos)
+    {
+      cout << "Warning, istringstream has a bug: putback() doesn't update tellg().\n";;
+      cout << "Tests on tellg() will be skipped.\n";
+      putback_tellg_works = false;
+    }
+}
+
+
+#define WRONG(str)                                              \
+  do {                                                          \
+    cout << str ", data[" << i << "]\n";                        \
+    cout << "  input: \"" << data[i].input << "\"\n";           \
+    cout << "  flags: " << hex << input.flags() << dec << "\n"; \
+  } while (0)
+
+void
+check_mpz (void)
+{
+  static const struct {
+    const char     *input;
+    int            want_pos;
+    const char     *want;
+    ios::fmtflags  flags;
+
+  } data[] = {
+
+    { "0",      -1, "0",    (ios::fmtflags) 0 },
+    { "123",    -1, "123",  (ios::fmtflags) 0 },
+    { "0123",   -1, "83",   (ios::fmtflags) 0 },
+    { "0x123",  -1, "291",  (ios::fmtflags) 0 },
+    { "-123",   -1, "-123", (ios::fmtflags) 0 },
+    { "-0123",  -1, "-83",  (ios::fmtflags) 0 },
+    { "-0x123", -1, "-291", (ios::fmtflags) 0 },
+    { "+123",   -1, "123", (ios::fmtflags) 0 },
+    { "+0123",  -1, "83",  (ios::fmtflags) 0 },
+    { "+0x123", -1, "291", (ios::fmtflags) 0 },
+
+    { "0",     -1, "0",    ios::dec },
+    { "1f",     1, "1",    ios::dec },
+    { "011f",   3, "11",   ios::dec },
+    { "123",   -1, "123",  ios::dec },
+    { "-1f",    2, "-1",   ios::dec },
+    { "-011f",  4, "-11",  ios::dec },
+    { "-123",  -1, "-123", ios::dec },
+    { "+1f",    2, "1",    ios::dec },
+    { "+011f",  4, "11",   ios::dec },
+    { "+123",  -1, "123",  ios::dec },
+
+    { "0",    -1, "0",   ios::oct },
+    { "123",  -1, "83",  ios::oct },
+    { "-123", -1, "-83", ios::oct },
+    { "+123", -1, "83",  ios::oct },
+
+    { "0",    -1, "0",    ios::hex },
+    { "123",  -1, "291",  ios::hex },
+    { "ff",   -1, "255",  ios::hex },
+    { "FF",   -1, "255",  ios::hex },
+    { "-123", -1, "-291", ios::hex },
+    { "-ff",  -1, "-255", ios::hex },
+    { "-FF",  -1, "-255", ios::hex },
+    { "+123", -1, "291",  ios::hex },
+    { "+ff",  -1, "255",  ios::hex },
+    { "+FF",  -1, "255",  ios::hex },
+    { "ab",   -1, "171",  ios::hex },
+    { "cd",   -1, "205",  ios::hex },
+    { "ef",   -1, "239",  ios::hex },
+
+    { " 123",  0, NULL,  (ios::fmtflags) 0 },   // not without skipws
+    { " 123", -1, "123", ios::skipws },
+  };
+
+  mpz_t      got, want;
+  bool       got_ok, want_ok;
+  bool       got_eof, want_eof;
+  long       got_si, want_si;
+  streampos  init_tellg, got_pos, want_pos;
+
+  mpz_init (got);
+  mpz_init (want);
+
+  for (size_t i = 0; i < numberof (data); i++)
+    {
+      size_t input_length = strlen (data[i].input);
+      want_pos = (data[i].want_pos == -1
+                  ? input_length : data[i].want_pos);
+      want_eof = (want_pos == streampos(input_length));
+
+      want_ok = (data[i].want != NULL);
+
+      if (data[i].want != NULL)
+        mpz_set_str_or_abort (want, data[i].want, 0);
+      else
+        mpz_set_ui (want, 0L);
+
+      if (option_check_standard && mpz_fits_slong_p (want))
+        {
+          istringstream  input (data[i].input);
+          input.flags (data[i].flags);
+          init_tellg = input.tellg();
+          want_si = mpz_get_si (want);
+
+          input >> got_si;
+          got_ok = !input.fail();
+          got_eof = input.eof();
+          input.clear();
+          got_pos = input.tellg() - init_tellg;
+
+          if (got_ok != want_ok)
+            {
+              WRONG ("stdc++ operator>> wrong status, check_mpz");
+              cout << "  want_ok: " << want_ok << "\n";
+              cout << "  got_ok:  " << got_ok << "\n";
+            }
+          if (want_ok && got_si != want_si)
+            {
+              WRONG ("stdc++ operator>> wrong result, check_mpz");
+              cout << "  got_si:  " << got_si << "\n";
+              cout << "  want_si: " << want_si << "\n";
+            }
+          if (want_ok && got_eof != want_eof)
+            {
+              WRONG ("stdc++ operator>> wrong EOF state, check_mpz");
+              cout << "  got_eof:  " << got_eof << "\n";
+              cout << "  want_eof: " << want_eof << "\n";
+            }
+          if (putback_tellg_works && got_pos != want_pos)
+            {
+              WRONG ("stdc++ operator>> wrong position, check_mpz");
+              cout << "  want_pos: " << want_pos << "\n";
+              cout << "  got_pos:  " << got_pos << "\n";
+            }
+        }
+
+      {
+        istringstream  input (data[i].input);
+        input.flags (data[i].flags);
+        init_tellg = input.tellg();
+
+        mpz_set_ui (got, 0xDEAD);
+        input >> got;
+        got_ok = !input.fail();
+	got_eof = input.eof();
+        input.clear();
+        got_pos = input.tellg() - init_tellg;
+
+        if (got_ok != want_ok)
+          {
+            WRONG ("mpz operator>> wrong status");
+            cout << "  want_ok: " << want_ok << "\n";
+            cout << "  got_ok:  " << got_ok << "\n";
+            abort ();
+          }
+        if (want_ok && mpz_cmp (got, want) != 0)
+          {
+            WRONG ("mpz operator>> wrong result");
+            mpz_trace ("  got ", got);
+            mpz_trace ("  want", want);
+            abort ();
+          }
+        if (want_ok && got_eof != want_eof)
+          {
+            WRONG ("mpz operator>> wrong EOF state");
+            cout << "  want_eof: " << want_eof << "\n";
+            cout << "  got_eof:  " << got_eof << "\n";
+            abort ();
+          }
+        if (putback_tellg_works && got_pos != want_pos)
+          {
+            WRONG ("mpz operator>> wrong position");
+            cout << "  want_pos: " << want_pos << "\n";
+            cout << "  got_pos:  " << got_pos << "\n";
+            abort ();
+          }
+      }
+    }
+
+  mpz_clear (got);
+  mpz_clear (want);
+}
+
+void
+check_mpq (void)
+{
+  static const struct {
+    const char     *input;
+    int            want_pos;
+    const char     *want;
+    ios::fmtflags  flags;
+
+  } data[] = {
+
+    { "0",   -1, "0", (ios::fmtflags) 0 },
+    { "00",  -1, "0", (ios::fmtflags) 0 },
+    { "0x0", -1, "0", (ios::fmtflags) 0 },
+
+    { "123/456",   -1, "123/456", ios::dec },
+    { "0123/456",  -1, "123/456", ios::dec },
+    { "123/0456",  -1, "123/456", ios::dec },
+    { "0123/0456", -1, "123/456", ios::dec },
+
+    { "123/456",   -1, "83/302", ios::oct },
+    { "0123/456",  -1, "83/302", ios::oct },
+    { "123/0456",  -1, "83/302", ios::oct },
+    { "0123/0456", -1, "83/302", ios::oct },
+
+    { "ab",   -1, "171",  ios::hex },
+    { "cd",   -1, "205",  ios::hex },
+    { "ef",   -1, "239",  ios::hex },
+
+    { "0/0",     -1, "0/0", (ios::fmtflags) 0 },
+    { "5/8",     -1, "5/8", (ios::fmtflags) 0 },
+    { "0x5/0x8", -1, "5/8", (ios::fmtflags) 0 },
+
+    { "123/456",   -1, "123/456",  (ios::fmtflags) 0 },
+    { "123/0456",  -1, "123/302",  (ios::fmtflags) 0 },
+    { "123/0x456", -1, "123/1110", (ios::fmtflags) 0 },
+    { "123/0X456", -1, "123/1110", (ios::fmtflags) 0 },
+
+    { "0123/123",   -1, "83/123", (ios::fmtflags) 0 },
+    { "0123/0123",  -1, "83/83",  (ios::fmtflags) 0 },
+    { "0123/0x123", -1, "83/291", (ios::fmtflags) 0 },
+    { "0123/0X123", -1, "83/291", (ios::fmtflags) 0 },
+
+    { "0x123/123",   -1, "291/123", (ios::fmtflags) 0 },
+    { "0X123/0123",  -1, "291/83",  (ios::fmtflags) 0 },
+    { "0x123/0x123", -1, "291/291", (ios::fmtflags) 0 },
+
+    { " 123",  0, NULL,  (ios::fmtflags) 0 },   // not without skipws
+    { " 123", -1, "123", ios::skipws },
+
+    { "123 /456",    3, "123",  (ios::fmtflags) 0 },
+    { "123/ 456",    4,  NULL,  (ios::fmtflags) 0 },
+    { "123/"    ,   -1,  NULL,  (ios::fmtflags) 0 },
+    { "123 /456",    3, "123",  ios::skipws },
+    { "123/ 456",    4,  NULL,  ios::skipws },
+  };
+
+  mpq_t      got, want;
+  bool       got_ok, want_ok;
+  bool       got_eof, want_eof;
+  long       got_si, want_si;
+  streampos  init_tellg, got_pos, want_pos;
+
+  mpq_init (got);
+  mpq_init (want);
+
+  for (size_t i = 0; i < numberof (data); i++)
+    {
+      size_t input_length = strlen (data[i].input);
+      want_pos = (data[i].want_pos == -1
+                  ? input_length : data[i].want_pos);
+      want_eof = (want_pos == streampos(input_length));
+
+      want_ok = (data[i].want != NULL);
+
+      if (data[i].want != NULL)
+        mpq_set_str_or_abort (want, data[i].want, 0);
+      else
+        mpq_set_ui (want, 0L, 1L);
+
+      if (option_check_standard
+          && mpz_fits_slong_p (mpq_numref(want))
+          && mpz_cmp_ui (mpq_denref(want), 1L) == 0
+          && strchr (data[i].input, '/') == NULL)
+        {
+          istringstream  input (data[i].input);
+          input.flags (data[i].flags);
+          init_tellg = input.tellg();
+          want_si = mpz_get_si (mpq_numref(want));
+
+          input >> got_si;
+          got_ok = !input.fail();
+          got_eof = input.eof();
+          input.clear();
+          got_pos = input.tellg() - init_tellg;
+
+          if (got_ok != want_ok)
+            {
+              WRONG ("stdc++ operator>> wrong status, check_mpq");
+              cout << "  want_ok: " << want_ok << "\n";
+              cout << "  got_ok:  " << got_ok << "\n";
+            }
+          if (want_ok && want_si != got_si)
+            {
+              WRONG ("stdc++ operator>> wrong result, check_mpq");
+              cout << "  got_si:  " << got_si << "\n";
+              cout << "  want_si: " << want_si << "\n";
+            }
+          if (want_ok && got_eof != want_eof)
+            {
+              WRONG ("stdc++ operator>> wrong EOF state, check_mpq");
+              cout << "  got_eof:  " << got_eof << "\n";
+              cout << "  want_eof: " << want_eof << "\n";
+            }
+          if (putback_tellg_works && got_pos != want_pos)
+            {
+              WRONG ("stdc++ operator>> wrong position, check_mpq");
+              cout << "  want_pos: " << want_pos << "\n";
+              cout << "  got_pos:  " << got_pos << "\n";
+            }
+        }
+
+      {
+        istringstream  input (data[i].input);
+        input.flags (data[i].flags);
+        init_tellg = input.tellg();
+        mpq_set_si (got, 0xDEAD, 0xBEEF);
+
+        input >> got;
+        got_ok = !input.fail();
+	got_eof = input.eof();
+        input.clear();
+        got_pos = input.tellg() - init_tellg;
+
+        if (got_ok != want_ok)
+          {
+            WRONG ("mpq operator>> wrong status");
+            cout << "  want_ok: " << want_ok << "\n";
+            cout << "  got_ok:  " << got_ok << "\n";
+            abort ();
+          }
+        // don't use mpq_equal, since we allow non-normalized values to be
+        // read, which can trigger ASSERTs in mpq_equal
+        if (want_ok && (mpz_cmp (mpq_numref (got), mpq_numref(want)) != 0
+                        || mpz_cmp (mpq_denref (got), mpq_denref(want)) != 0))
+          {
+            WRONG ("mpq operator>> wrong result");
+            mpq_trace ("  got ", got);
+            mpq_trace ("  want", want);
+            abort ();
+          }
+        if (want_ok && got_eof != want_eof)
+          {
+            WRONG ("mpq operator>> wrong EOF state");
+            cout << "  want_eof: " << want_eof << "\n";
+            cout << "  got_eof:  " << got_eof << "\n";
+            abort ();
+          }
+        if (putback_tellg_works && got_pos != want_pos)
+          {
+            WRONG ("mpq operator>> wrong position");
+            cout << "  want_pos: " << want_pos << "\n";
+            cout << "  got_pos:  " << got_pos << "\n";
+            abort ();
+          }
+      }
+    }
+
+  mpq_clear (got);
+  mpq_clear (want);
+}
+
+
+void
+check_mpf (void)
+{
+  static const struct {
+    const char     *input;
+    int            want_pos;
+    const char     *want;
+    ios::fmtflags  flags;
+
+  } data[] = {
+
+    { "0",      -1, "0", (ios::fmtflags) 0 },
+    { "+0",     -1, "0", (ios::fmtflags) 0 },
+    { "-0",     -1, "0", (ios::fmtflags) 0 },
+    { "0.0",    -1, "0", (ios::fmtflags) 0 },
+    { "0.",     -1, "0", (ios::fmtflags) 0 },
+    { ".0",     -1, "0", (ios::fmtflags) 0 },
+    { "+.0",    -1, "0", (ios::fmtflags) 0 },
+    { "-.0",    -1, "0", (ios::fmtflags) 0 },
+    { "+0.00",  -1, "0", (ios::fmtflags) 0 },
+    { "-0.000", -1, "0", (ios::fmtflags) 0 },
+    { "+0.00",  -1, "0", (ios::fmtflags) 0 },
+    { "-0.000", -1, "0", (ios::fmtflags) 0 },
+    { "0.0e0",  -1, "0", (ios::fmtflags) 0 },
+    { "0.e0",   -1, "0", (ios::fmtflags) 0 },
+    { ".0e0",   -1, "0", (ios::fmtflags) 0 },
+    { "0.0e-0", -1, "0", (ios::fmtflags) 0 },
+    { "0.e-0",  -1, "0", (ios::fmtflags) 0 },
+    { ".0e-0",  -1, "0", (ios::fmtflags) 0 },
+    { "0.0e+0", -1, "0", (ios::fmtflags) 0 },
+    { "0.e+0",  -1, "0", (ios::fmtflags) 0 },
+    { ".0e+0",  -1, "0", (ios::fmtflags) 0 },
+
+    { "1",  -1,  "1", (ios::fmtflags) 0 },
+    { "+1", -1,  "1", (ios::fmtflags) 0 },
+    { "-1", -1, "-1", (ios::fmtflags) 0 },
+
+    { " 0",  0,  NULL, (ios::fmtflags) 0 },  // not without skipws
+    { " 0",  -1, "0", ios::skipws },
+    { " +0", -1, "0", ios::skipws },
+    { " -0", -1, "0", ios::skipws },
+
+    { "+-123", 1, NULL, (ios::fmtflags) 0 },
+    { "-+123", 1, NULL, (ios::fmtflags) 0 },
+    { "1e+-123", 3, NULL, (ios::fmtflags) 0 },
+    { "1e-+123", 3, NULL, (ios::fmtflags) 0 },
+
+    { "e123",   0, NULL, (ios::fmtflags) 0 }, // at least one mantissa digit
+    { ".e123",  1, NULL, (ios::fmtflags) 0 },
+    { "+.e123", 2, NULL, (ios::fmtflags) 0 },
+    { "-.e123", 2, NULL, (ios::fmtflags) 0 },
+
+    { "123e",   4, NULL, (ios::fmtflags) 0 }, // at least one exponent digit
+    { "123e-",  5, NULL, (ios::fmtflags) 0 },
+    { "123e+",  5, NULL, (ios::fmtflags) 0 },
+  };
+
+  mpf_t      got, want;
+  bool       got_ok, want_ok;
+  bool       got_eof, want_eof;
+  double     got_d, want_d;
+  streampos  init_tellg, got_pos, want_pos;
+
+  mpf_init (got);
+  mpf_init (want);
+
+  for (size_t i = 0; i < numberof (data); i++)
+    {
+      size_t input_length = strlen (data[i].input);
+      want_pos = (data[i].want_pos == -1
+                  ? input_length : data[i].want_pos);
+      want_eof = (want_pos == streampos(input_length));
+
+      want_ok = (data[i].want != NULL);
+
+      if (data[i].want != NULL)
+        mpf_set_str_or_abort (want, data[i].want, 0);
+      else
+        mpf_set_ui (want, 0L);
+
+      want_d = mpf_get_d (want);
+      if (option_check_standard && mpf_cmp_d (want, want_d) == 0)
+        {
+          istringstream  input (data[i].input);
+          input.flags (data[i].flags);
+          init_tellg = input.tellg();
+
+          input >> got_d;
+          got_ok = !input.fail();
+          got_eof = input.eof();
+          input.clear();
+          got_pos = input.tellg() - init_tellg;
+
+          if (got_ok != want_ok)
+            {
+              WRONG ("stdc++ operator>> wrong status, check_mpf");
+              cout << "  want_ok: " << want_ok << "\n";
+              cout << "  got_ok:  " << got_ok << "\n";
+            }
+          if (want_ok && want_d != got_d)
+            {
+              WRONG ("stdc++ operator>> wrong result, check_mpf");
+              cout << "  got:   " << got_d << "\n";
+              cout << "  want:  " << want_d << "\n";
+            }
+          if (want_ok && got_eof != want_eof)
+            {
+              WRONG ("stdc++ operator>> wrong EOF state, check_mpf");
+              cout << "  got_eof:  " << got_eof << "\n";
+              cout << "  want_eof: " << want_eof << "\n";
+            }
+          if (putback_tellg_works && got_pos != want_pos)
+            {
+              WRONG ("stdc++ operator>> wrong position, check_mpf");
+              cout << "  want_pos: " << want_pos << "\n";
+              cout << "  got_pos:  " << got_pos << "\n";
+            }
+        }
+
+      {
+        istringstream  input (data[i].input);
+        input.flags (data[i].flags);
+        init_tellg = input.tellg();
+
+        mpf_set_ui (got, 0xDEAD);
+        input >> got;
+        got_ok = !input.fail();
+	got_eof = input.eof();
+        input.clear();
+        got_pos = input.tellg() - init_tellg;
+
+        if (got_ok != want_ok)
+          {
+            WRONG ("mpf operator>> wrong status");
+            cout << "  want_ok: " << want_ok << "\n";
+            cout << "  got_ok:  " << got_ok << "\n";
+            abort ();
+          }
+        if (want_ok && mpf_cmp (got, want) != 0)
+          {
+            WRONG ("mpf operator>> wrong result");
+            mpf_trace ("  got ", got);
+            mpf_trace ("  want", want);
+            abort ();
+          }
+        if (want_ok && got_eof != want_eof)
+          {
+            WRONG ("mpf operator>> wrong EOF state");
+            cout << "  want_eof: " << want_eof << "\n";
+            cout << "  got_eof:  " << got_eof << "\n";
+            abort ();
+          }
+        if (putback_tellg_works && got_pos != want_pos)
+          {
+            WRONG ("mpf operator>> wrong position");
+            cout << "  want_pos: " << want_pos << "\n";
+            cout << "  got_pos:  " << got_pos << "\n";
+            abort ();
+          }
+      }
+    }
+
+  mpf_clear (got);
+  mpf_clear (want);
+}
+
+
+
+int
+main (int argc, char *argv[])
+{
+  if (argc > 1 && strcmp (argv[1], "-s") == 0)
+    option_check_standard = true;
+
+  tests_start ();
+
+  check_putback_tellg ();
+  check_mpz ();
+  check_mpq ();
+  check_mpf ();
+
+  tests_end ();
+  return 0;
+}
diff --git a/third_party/gmp/tests/cxx/t-locale.cc b/third_party/gmp/tests/cxx/t-locale.cc
new file mode 100644
index 0000000..14e95e0
--- /dev/null
+++ b/third_party/gmp/tests/cxx/t-locale.cc
@@ -0,0 +1,194 @@
+/* Test locale support in C++ functions.
+
+Copyright 2001-2003, 2007 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <clocale>
+#include <iostream>
+#include <cstdlib>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+using namespace std;
+
+
+extern "C" {
+  char point_string[2];
+}
+
+#if HAVE_STD__LOCALE
+// Like std::numpunct, but with decimal_point coming from point_string[].
+class my_numpunct : public numpunct<char> {
+ public:
+  explicit my_numpunct (size_t r = 0) : numpunct<char>(r) { }
+ protected:
+  char do_decimal_point() const { return point_string[0]; }
+};
+#endif
+
+void
+set_point (char c)
+{
+  point_string[0] = c;
+
+#if HAVE_STD__LOCALE
+  locale loc (locale::classic(), new my_numpunct ());
+  locale::global (loc);
+#endif
+}
+
+
+void
+check_input (void)
+{
+  static const struct {
+    const char  *str1;
+    const char  *str2;
+    double      want;
+  } data[] = {
+
+    { "1","",   1.0 },
+    { "1","0",  1.0 },
+    { "1","00", 1.0 },
+
+    { "","5",    0.5 },
+    { "0","5",   0.5 },
+    { "00","5",  0.5 },
+    { "00","50", 0.5 },
+
+    { "1","5",    1.5 },
+    { "1","5e1", 15.0 },
+  };
+
+  static char point[] = {
+    '.', ',', 'x', '\xFF'
+  };
+
+  mpf_t  got;
+  mpf_init (got);
+
+  for (size_t i = 0; i < numberof (point); i++)
+    {
+      set_point (point[i]);
+
+      for (int neg = 0; neg <= 1; neg++)
+        {
+          for (size_t j = 0; j < numberof (data); j++)
+            {
+              string str = string(data[j].str1)+point[i]+string(data[j].str2);
+              if (neg)
+                str = "-" + str;
+
+              istringstream is (str.c_str());
+
+              mpf_set_ui (got, 123);   // dummy initial value
+
+              if (! (is >> got))
+                {
+                  cout << "istream mpf_t operator>> error\n";
+                  cout << "  point " << point[i] << "\n";
+                  cout << "  str   \"" << str << "\"\n";
+                  cout << "  localeconv point \""
+                       << GMP_DECIMAL_POINT << "\"\n";
+                  abort ();
+                }
+
+              double want = data[j].want;
+              if (neg)
+                want = -want;
+              if (mpf_cmp_d (got, want) != 0)
+                {
+                  cout << "istream mpf_t operator>> wrong\n";
+                  cout << "  point " << point[i] << "\n";
+                  cout << "  str   \"" << str << "\"\n";
+                  cout << "  got   " << got << "\n";
+                  cout << "  want  " << want << "\n";
+                  cout << "  localeconv point \""
+                       << GMP_DECIMAL_POINT << "\"\n";
+                  abort ();
+                }
+            }
+        }
+    }
+
+  mpf_clear (got);
+}
+
+void
+check_output (void)
+{
+  static char point[] = {
+    '.', ',', 'x', '\xFF'
+  };
+
+  for (size_t i = 0; i < numberof (point); i++)
+    {
+      set_point (point[i]);
+      ostringstream  got;
+
+      mpf_t  f;
+      mpf_init (f);
+      mpf_set_d (f, 1.5);
+      got << f;
+      mpf_clear (f);
+
+      string  want = string("1") + point[i] + string("5");
+
+      if (want.compare (got.str()) != 0)
+        {
+          cout << "ostream mpf_t operator<< doesn't respect locale\n";
+          cout << "  point " << point[i] << "\n";
+          cout << "  got   \"" << got.str() << "\"\n";
+          cout << "  want  \"" << want      << "\"\n";
+          abort ();
+        }
+    }
+}
+
+int
+replacement_works (void)
+{
+  set_point ('x');
+  mpf_t  f;
+  mpf_init (f);
+  mpf_set_d (f, 1.5);
+  ostringstream s;
+  s << f;
+  mpf_clear (f);
+
+  return (s.str().compare("1x5") == 0);
+}
+
+int
+main (void)
+{
+  tests_start ();
+
+  if (replacement_works())
+    {
+      check_input ();
+      check_output ();
+    }
+  else
+    {
+      cout << "Replacing decimal point didn't work, tests skipped\n";
+    }
+
+  tests_end ();
+  return 0;
+}
diff --git a/third_party/gmp/tests/cxx/t-misc.cc b/third_party/gmp/tests/cxx/t-misc.cc
new file mode 100644
index 0000000..1143e84
--- /dev/null
+++ b/third_party/gmp/tests/cxx/t-misc.cc
@@ -0,0 +1,397 @@
+/* Test mp*_class functions.
+
+Copyright 2002, 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+/* Note that we don't use <climits> for LONG_MIN, but instead our own
+   definitions in gmp-impl.h.  In g++ 2.95.4 (debian 3.0) under
+   -mcpu=ultrasparc, limits.h sees __sparc_v9__ defined and assumes that
+   means long is 64-bit long, but it's only 32-bits, causing fatal compile
+   errors.  */
+
+#include "config.h"
+
+#include <string>
+
+#include "gmpxx.h"
+#include "gmp-impl.h"
+#include "tests.h"
+
+using namespace std;
+
+
+void
+check_mpz (void)
+{
+  // mpz_class::fits_sint_p
+  {
+    bool       fits;
+    mpz_class  z;
+    z = INT_MIN; fits = z.fits_sint_p(); ASSERT_ALWAYS (fits);
+    z--;         fits = z.fits_sint_p(); ASSERT_ALWAYS (! fits);
+    z = INT_MAX; fits = z.fits_sint_p(); ASSERT_ALWAYS (fits);
+    z++;         fits = z.fits_sint_p(); ASSERT_ALWAYS (! fits);
+  }
+
+  // mpz_class::fits_uint_p
+  {
+    bool       fits;
+    mpz_class  z;
+    z = 0;        fits = z.fits_uint_p(); ASSERT_ALWAYS (fits);
+    z--;          fits = z.fits_uint_p(); ASSERT_ALWAYS (! fits);
+    z = UINT_MAX; fits = z.fits_uint_p(); ASSERT_ALWAYS (fits);
+    z++;          fits = z.fits_uint_p(); ASSERT_ALWAYS (! fits);
+  }
+
+  // mpz_class::fits_slong_p
+  {
+    bool       fits;
+    mpz_class  z;
+    z = LONG_MIN; fits = z.fits_slong_p(); ASSERT_ALWAYS (fits);
+    z--;          fits = z.fits_slong_p(); ASSERT_ALWAYS (! fits);
+    z = LONG_MAX; fits = z.fits_slong_p(); ASSERT_ALWAYS (fits);
+    z++;          fits = z.fits_slong_p(); ASSERT_ALWAYS (! fits);
+  }
+
+  // mpz_class::fits_ulong_p
+  {
+    bool       fits;
+    mpz_class  z;
+    z = 0;         fits = z.fits_ulong_p(); ASSERT_ALWAYS (fits);
+    z--;           fits = z.fits_ulong_p(); ASSERT_ALWAYS (! fits);
+    z = ULONG_MAX; fits = z.fits_ulong_p(); ASSERT_ALWAYS (fits);
+    z++;           fits = z.fits_ulong_p(); ASSERT_ALWAYS (! fits);
+  }
+
+  // mpz_class::fits_sshort_p
+  {
+    bool       fits;
+    mpz_class  z;
+    z = SHRT_MIN; fits = z.fits_sshort_p(); ASSERT_ALWAYS (fits);
+    z--;          fits = z.fits_sshort_p(); ASSERT_ALWAYS (! fits);
+    z = SHRT_MAX; fits = z.fits_sshort_p(); ASSERT_ALWAYS (fits);
+    z++;          fits = z.fits_sshort_p(); ASSERT_ALWAYS (! fits);
+  }
+
+  // mpz_class::fits_ushort_p
+  {
+    bool       fits;
+    mpz_class  z;
+    z = 0;         fits = z.fits_ushort_p(); ASSERT_ALWAYS (fits);
+    z--;           fits = z.fits_ushort_p(); ASSERT_ALWAYS (! fits);
+    z = USHRT_MAX; fits = z.fits_ushort_p(); ASSERT_ALWAYS (fits);
+    z++;           fits = z.fits_ushort_p(); ASSERT_ALWAYS (! fits);
+  }
+
+  // mpz_class::get_mpz_t
+  {
+    mpz_class  z(0);
+    mpz_ptr    p = z.get_mpz_t();
+    ASSERT_ALWAYS (mpz_cmp_ui (p, 0) == 0);
+  }
+  {
+    mpz_class  z(0);
+    mpz_srcptr p = z.get_mpz_t();
+    ASSERT_ALWAYS (mpz_cmp_ui (p, 0) == 0);
+  }
+
+  // mpz_class::get_d
+  // mpz_class::get_si
+  // mpz_class::get_ui
+  {
+    mpz_class  z(123);
+    { double d = z.get_d();  ASSERT_ALWAYS (d == 123.0); }
+    { long   l = z.get_si(); ASSERT_ALWAYS (l == 123L); }
+    { long   u = z.get_ui(); ASSERT_ALWAYS (u == 123L); }
+  }
+  {
+    mpz_class  z(-123);
+    { double d = z.get_d();  ASSERT_ALWAYS (d == -123.0); }
+    { long   l = z.get_si(); ASSERT_ALWAYS (l == -123L); }
+  }
+
+  // mpz_class::get_str
+  {
+    mpz_class  z(123);
+    string     s;
+    s = z.get_str(); ASSERT_ALWAYS (s == "123");
+    s = z.get_str(16); ASSERT_ALWAYS (s == "7b");
+    s = z.get_str(-16); ASSERT_ALWAYS (s == "7B");
+  }
+
+  // mpz_class::set_str
+  {
+    mpz_class  z;
+    int        ret;
+    ret = z.set_str ("123", 10);  ASSERT_ALWAYS (ret == 0 && z == 123);
+    ret = z.set_str ("7b",  16);  ASSERT_ALWAYS (ret == 0 && z == 123);
+    ret = z.set_str ("7B",  16);  ASSERT_ALWAYS (ret == 0 && z == 123);
+    ret = z.set_str ("0x7B", 0);  ASSERT_ALWAYS (ret == 0 && z == 123);
+
+    ret = z.set_str (string("123"), 10);  ASSERT_ALWAYS (ret == 0 && z == 123);
+    ret = z.set_str (string("7b"),  16);  ASSERT_ALWAYS (ret == 0 && z == 123);
+    ret = z.set_str (string("7B"),  16);  ASSERT_ALWAYS (ret == 0 && z == 123);
+    ret = z.set_str (string("0x7B"), 0);  ASSERT_ALWAYS (ret == 0 && z == 123);
+  }
+}
+
+void
+check_mpq (void)
+{
+  // mpq_class::canonicalize
+  {
+    mpq_class  q(12,9);
+    q.canonicalize();
+    ASSERT_ALWAYS (q.get_num() == 4);
+    ASSERT_ALWAYS (q.get_den() == 3);
+  }
+
+  // mpq_class::get_d
+  {
+    mpq_class  q(123);
+    { double d = q.get_d();  ASSERT_ALWAYS (d == 123.0); }
+  }
+  {
+    mpq_class  q(-123);
+    { double d = q.get_d();  ASSERT_ALWAYS (d == -123.0); }
+  }
+
+  // mpq_class::get_mpq_t
+  {
+    mpq_class  q(0);
+    mpq_ptr    p = q.get_mpq_t();
+    ASSERT_ALWAYS (mpq_cmp_ui (p, 0, 1) == 0);
+  }
+  {
+    mpq_class  q(0);
+    mpq_srcptr p = q.get_mpq_t();
+    ASSERT_ALWAYS (mpq_cmp_ui (p, 0, 1) == 0);
+  }
+
+  // mpq_class::get_num, mpq_class::get_den
+  {
+    const mpq_class  q(4,5);
+    mpz_class  z;
+    z = q.get_num(); ASSERT_ALWAYS (z == 4);
+    z = q.get_den(); ASSERT_ALWAYS (z == 5);
+  }
+
+  // mpq_class::get_num_mpz_t, mpq_class::get_den_mpz_t
+  {
+    mpq_class  q(4,5);
+    mpz_ptr    p;
+    p = q.get_num_mpz_t(); ASSERT_ALWAYS (mpz_cmp_ui (p, 4) == 0);
+    p = q.get_den_mpz_t(); ASSERT_ALWAYS (mpz_cmp_ui (p, 5) == 0);
+  }
+  {
+    const mpq_class  q(4,5);
+    mpz_srcptr p;
+    p = q.get_num_mpz_t(); ASSERT_ALWAYS (mpz_cmp_ui (p, 4) == 0);
+    p = q.get_den_mpz_t(); ASSERT_ALWAYS (mpz_cmp_ui (p, 5) == 0);
+  }
+
+  // mpq_class::get_str
+  {
+    mpq_class  q(17,11);
+    string     s;
+    s = q.get_str();    ASSERT_ALWAYS (s == "17/11");
+    s = q.get_str(10);  ASSERT_ALWAYS (s == "17/11");
+    s = q.get_str(16);  ASSERT_ALWAYS (s == "11/b");
+    s = q.get_str(-16); ASSERT_ALWAYS (s == "11/B");
+  }
+
+  // mpq_class::set_str
+  {
+    mpq_class  q;
+    int        ret;
+    ret = q.set_str ("123", 10);     ASSERT_ALWAYS (ret == 0 && q == 123);
+    ret = q.set_str ("4/5", 10);     ASSERT_ALWAYS (ret == 0 && q == mpq_class(4,5));
+    ret = q.set_str ("7b",  16);     ASSERT_ALWAYS (ret == 0 && q == 123);
+    ret = q.set_str ("7B",  16);     ASSERT_ALWAYS (ret == 0 && q == 123);
+    ret = q.set_str ("0x7B", 0);     ASSERT_ALWAYS (ret == 0 && q == 123);
+    ret = q.set_str ("0x10/17", 0);  ASSERT_ALWAYS (ret == 0 && q == mpq_class(16,17));
+
+    ret = q.set_str (string("4/5"), 10);  ASSERT_ALWAYS (ret == 0 && q == mpq_class(4,5));
+    ret = q.set_str (string("123"), 10);  ASSERT_ALWAYS (ret == 0 && q == 123);
+    ret = q.set_str (string("7b"),  16);  ASSERT_ALWAYS (ret == 0 && q == 123);
+    ret = q.set_str (string("7B"),  16);  ASSERT_ALWAYS (ret == 0 && q == 123);
+    ret = q.set_str (string("0x7B"), 0);  ASSERT_ALWAYS (ret == 0 && q == 123);
+    ret = q.set_str (string("0x10/17"), 0);  ASSERT_ALWAYS (ret == 0 && q == mpq_class(16,17));
+  }
+}
+
+void
+check_mpf (void)
+{
+  // mpf_class::fits_sint_p
+  {
+    bool       fits;
+    mpf_class  f (0, 2*8*sizeof(int));
+    f = INT_MIN; fits = f.fits_sint_p(); ASSERT_ALWAYS (fits);
+    f--;         fits = f.fits_sint_p(); ASSERT_ALWAYS (! fits);
+    f = INT_MAX; fits = f.fits_sint_p(); ASSERT_ALWAYS (fits);
+    f++;         fits = f.fits_sint_p(); ASSERT_ALWAYS (! fits);
+  }
+
+  // mpf_class::fits_uint_p
+  {
+    bool       fits;
+    mpf_class  f (0, 2*8*sizeof(int));
+    f = 0;        fits = f.fits_uint_p(); ASSERT_ALWAYS (fits);
+    f--;          fits = f.fits_uint_p(); ASSERT_ALWAYS (! fits);
+    f = UINT_MAX; fits = f.fits_uint_p(); ASSERT_ALWAYS (fits);
+    f++;          fits = f.fits_uint_p(); ASSERT_ALWAYS (! fits);
+  }
+
+  // mpf_class::fits_slong_p
+  {
+    bool       fits;
+    mpf_class  f (0, 2*8*sizeof(long));
+    f = LONG_MIN; fits = f.fits_slong_p(); ASSERT_ALWAYS (fits);
+    f--;          fits = f.fits_slong_p(); ASSERT_ALWAYS (! fits);
+    f = LONG_MAX; fits = f.fits_slong_p(); ASSERT_ALWAYS (fits);
+    f++;          fits = f.fits_slong_p(); ASSERT_ALWAYS (! fits);
+  }
+
+  // mpf_class::fits_ulong_p
+  {
+    bool       fits;
+    mpf_class  f (0, 2*8*sizeof(long));
+    f = 0;         fits = f.fits_ulong_p(); ASSERT_ALWAYS (fits);
+    f--;           fits = f.fits_ulong_p(); ASSERT_ALWAYS (! fits);
+    f = ULONG_MAX; fits = f.fits_ulong_p(); ASSERT_ALWAYS (fits);
+    f++;           fits = f.fits_ulong_p(); ASSERT_ALWAYS (! fits);
+  }
+
+  // mpf_class::fits_sshort_p
+  {
+    bool       fits;
+    mpf_class  f (0, 2*8*sizeof(short));
+    f = SHRT_MIN; fits = f.fits_sshort_p(); ASSERT_ALWAYS (fits);
+    f--;          fits = f.fits_sshort_p(); ASSERT_ALWAYS (! fits);
+    f = SHRT_MAX; fits = f.fits_sshort_p(); ASSERT_ALWAYS (fits);
+    f++;          fits = f.fits_sshort_p(); ASSERT_ALWAYS (! fits);
+  }
+
+  // mpf_class::fits_ushort_p
+  {
+    bool       fits;
+    mpf_class  f (0, 2*8*sizeof(short));
+    f = 0;         fits = f.fits_ushort_p(); ASSERT_ALWAYS (fits);
+    f--;           fits = f.fits_ushort_p(); ASSERT_ALWAYS (! fits);
+    f = USHRT_MAX; fits = f.fits_ushort_p(); ASSERT_ALWAYS (fits);
+    f++;           fits = f.fits_ushort_p(); ASSERT_ALWAYS (! fits);
+  }
+
+  // mpf_class::get_d
+  // mpf_class::get_si
+  // mpf_class::get_ui
+  {
+    mpf_class  f(123);
+    { double d = f.get_d();  ASSERT_ALWAYS (d == 123.0); }
+    { long   l = f.get_si(); ASSERT_ALWAYS (l == 123L); }
+    { long   u = f.get_ui(); ASSERT_ALWAYS (u == 123L); }
+  }
+  {
+    mpf_class  f(-123);
+    { double d = f.get_d();  ASSERT_ALWAYS (d == -123.0); }
+    { long   l = f.get_si(); ASSERT_ALWAYS (l == -123L); }
+  }
+
+  // mpf_class::get_prec
+  {
+    mpf_class  f;
+    ASSERT_ALWAYS (f.get_prec() == mpf_get_default_prec());
+  }
+
+  // mpf_class::get_str
+  {
+    mpf_class  f(123);
+    string     s;
+    mp_exp_t   e;
+    s = f.get_str(e);        ASSERT_ALWAYS (s == "123" && e == 3);
+    s = f.get_str(e,  16);   ASSERT_ALWAYS (s == "7b"  && e == 2);
+    s = f.get_str(e, -16);   ASSERT_ALWAYS (s == "7B"  && e == 2);
+    s = f.get_str(e, 10, 2); ASSERT_ALWAYS (s == "12"  && e == 3);
+    s = f.get_str(e, 10, 1); ASSERT_ALWAYS (s == "1"   && e == 3);
+  }
+
+  // mpf_class::set_str
+  {
+    mpf_class  f;
+    int        ret;
+    ret = f.set_str ("123",     10);  ASSERT_ALWAYS (ret == 0 && f == 123);
+    ret = f.set_str ("123e1",   10);  ASSERT_ALWAYS (ret == 0 && f == 1230);
+    ret = f.set_str ("1230e-1", 10);  ASSERT_ALWAYS (ret == 0 && f == 123);
+    ret = f.set_str ("7b",      16);  ASSERT_ALWAYS (ret == 0 && f == 123);
+    ret = f.set_str ("7B",      16);  ASSERT_ALWAYS (ret == 0 && f == 123);
+    ret = f.set_str ("7B@1",    16);  ASSERT_ALWAYS (ret == 0 && f == 1968);
+    ret = f.set_str ("7B0@-1",  16);  ASSERT_ALWAYS (ret == 0 && f == 123);
+
+    ret = f.set_str (string("123"),     10);  ASSERT_ALWAYS (ret == 0 && f == 123);
+    ret = f.set_str (string("123e1"),   10);  ASSERT_ALWAYS (ret == 0 && f == 1230);
+    ret = f.set_str (string("1230e-1"), 10);  ASSERT_ALWAYS (ret == 0 && f == 123);
+    ret = f.set_str (string("7b"),      16);  ASSERT_ALWAYS (ret == 0 && f == 123);
+    ret = f.set_str (string("7B"),      16);  ASSERT_ALWAYS (ret == 0 && f == 123);
+    ret = f.set_str (string("7B@1"),    16);  ASSERT_ALWAYS (ret == 0 && f == 1968);
+    ret = f.set_str (string("7B0@-1"),  16);  ASSERT_ALWAYS (ret == 0 && f == 123);
+  }
+
+  // mpf_class::set_prec
+  {
+    mpf_class  f;
+    f.set_prec (256);
+    ASSERT_ALWAYS (f.get_prec () >= 256);
+  }
+
+  // mpf_class::set_prec_raw
+  {
+    mpf_class  f (0, 100 * GMP_NUMB_BITS);
+    f.set_prec_raw (5 * GMP_NUMB_BITS);
+    ASSERT_ALWAYS (f.get_prec () >= 5 * GMP_NUMB_BITS);
+    ASSERT_ALWAYS (f.get_prec () < 100 * GMP_NUMB_BITS);
+    f.set_prec_raw (100 * GMP_NUMB_BITS);
+  }
+}
+
+// std::numeric_limits
+void
+check_limits (void)
+{
+  // Check that the content is not private.
+  ASSERT_ALWAYS ( std::numeric_limits<mpz_class>::is_integer);
+  ASSERT_ALWAYS (!std::numeric_limits<mpf_class>::is_integer);
+
+  // Check that symbols are emitted.
+  ASSERT_ALWAYS (&std::numeric_limits<mpz_class>::is_integer
+	      != &std::numeric_limits<mpq_class>::is_integer);
+}
+
+int
+main (void)
+{
+  tests_start();
+
+  check_mpz();
+  check_mpq();
+  check_mpf();
+  check_limits();
+
+  tests_end();
+  return 0;
+}
diff --git a/third_party/gmp/tests/cxx/t-mix.cc b/third_party/gmp/tests/cxx/t-mix.cc
new file mode 100644
index 0000000..cb6733b
--- /dev/null
+++ b/third_party/gmp/tests/cxx/t-mix.cc
@@ -0,0 +1,82 @@
+/* Test legality of conversion between the different mp*_class
+
+Copyright 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#include "gmpxx.h"
+#include "gmp-impl.h"
+#include "tests.h"
+
+int f_z  (mpz_class){return 0;}
+int f_q  (mpq_class){return 1;}
+int f_f  (mpf_class){return 2;}
+int f_zq (mpz_class){return 0;}
+int f_zq (mpq_class){return 1;}
+int f_zf (mpz_class){return 0;}
+int f_zf (mpf_class){return 2;}
+int f_qf (mpq_class){return 1;}
+int f_qf (mpf_class){return 2;}
+int f_zqf(mpz_class){return 0;}
+int f_zqf(mpq_class){return 1;}
+int f_zqf(mpf_class){return 2;}
+
+void
+check (void)
+{
+  mpz_class z=42;
+  mpq_class q=33;
+  mpf_class f=18;
+
+  ASSERT_ALWAYS(f_z  (z)==0); ASSERT_ALWAYS(f_z  (-z)==0);
+  ASSERT_ALWAYS(f_q  (z)==1); ASSERT_ALWAYS(f_q  (-z)==1);
+  ASSERT_ALWAYS(f_q  (q)==1); ASSERT_ALWAYS(f_q  (-q)==1);
+  ASSERT_ALWAYS(f_f  (z)==2); ASSERT_ALWAYS(f_f  (-z)==2);
+  ASSERT_ALWAYS(f_f  (q)==2); ASSERT_ALWAYS(f_f  (-q)==2);
+  ASSERT_ALWAYS(f_f  (f)==2); ASSERT_ALWAYS(f_f  (-f)==2);
+  ASSERT_ALWAYS(f_zq (z)==0);
+  ASSERT_ALWAYS(f_zq (q)==1); ASSERT_ALWAYS(f_zq (-q)==1);
+  ASSERT_ALWAYS(f_zf (z)==0);
+  ASSERT_ALWAYS(f_zf (f)==2); ASSERT_ALWAYS(f_zf (-f)==2);
+  ASSERT_ALWAYS(f_qf (q)==1);
+  ASSERT_ALWAYS(f_qf (f)==2); ASSERT_ALWAYS(f_qf (-f)==2);
+  ASSERT_ALWAYS(f_zqf(z)==0);
+  ASSERT_ALWAYS(f_zqf(q)==1);
+  ASSERT_ALWAYS(f_zqf(f)==2); ASSERT_ALWAYS(f_zqf(-f)==2);
+
+  ASSERT_ALWAYS(f_zqf(mpz_class(z))==0); ASSERT_ALWAYS(f_zqf(mpz_class(-z))==0);
+  ASSERT_ALWAYS(f_zqf(mpz_class(q))==0); ASSERT_ALWAYS(f_zqf(mpz_class(-q))==0);
+  ASSERT_ALWAYS(f_zqf(mpz_class(f))==0); ASSERT_ALWAYS(f_zqf(mpz_class(-f))==0);
+  ASSERT_ALWAYS(f_zqf(mpq_class(z))==1); ASSERT_ALWAYS(f_zqf(mpq_class(-z))==1);
+  ASSERT_ALWAYS(f_zqf(mpq_class(q))==1); ASSERT_ALWAYS(f_zqf(mpq_class(-q))==1);
+  ASSERT_ALWAYS(f_zqf(mpq_class(f))==1); ASSERT_ALWAYS(f_zqf(mpq_class(-f))==1);
+  ASSERT_ALWAYS(f_zqf(mpf_class(z))==2); ASSERT_ALWAYS(f_zqf(mpf_class(-z))==2);
+  ASSERT_ALWAYS(f_zqf(mpf_class(q))==2); ASSERT_ALWAYS(f_zqf(mpf_class(-q))==2);
+  ASSERT_ALWAYS(f_zqf(mpf_class(f))==2); ASSERT_ALWAYS(f_zqf(mpf_class(-f))==2);
+}
+
+int
+main (void)
+{
+  tests_start();
+
+  check();
+
+  tests_end();
+  return 0;
+}
diff --git a/third_party/gmp/tests/cxx/t-ops.cc b/third_party/gmp/tests/cxx/t-ops.cc
new file mode 100644
index 0000000..ecc6bd0
--- /dev/null
+++ b/third_party/gmp/tests/cxx/t-ops.cc
@@ -0,0 +1,753 @@
+/* Test mp*_class operators and functions.
+
+Copyright 2001-2003, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#include <iostream>
+
+#include "gmpxx.h"
+#include "gmp-impl.h"
+#include "tests.h"
+
+using namespace std;
+
+
+void
+check_mpz (void)
+{
+  // unary operators and functions
+
+  // operator+
+  {
+    mpz_class a(1);
+    mpz_class b;
+    b = +a; ASSERT_ALWAYS(b == 1);
+  }
+
+  // operator-
+  {
+    mpz_class a(2);
+    mpz_class b;
+    b = -a; ASSERT_ALWAYS(b == -2);
+  }
+
+  // operator~
+  {
+    mpz_class a(3);
+    mpz_class b;
+    b = ~a; ASSERT_ALWAYS(b == -4);
+  }
+
+  // abs
+  {
+    mpz_class a(-123);
+    mpz_class b;
+    b = abs(a); ASSERT_ALWAYS(b == 123);
+    a <<= 300;
+    b = abs(a); ASSERT_ALWAYS(a + b == 0);
+  }
+
+  // sqrt
+  {
+    mpz_class a(25);
+    mpz_class b;
+    b = sqrt(a); ASSERT_ALWAYS(b == 5);
+  }
+  {
+    mpz_class a(125);
+    mpz_class b;
+    b = sqrt(a); ASSERT_ALWAYS(b == 11); // round toward zero
+  }
+
+  // sgn
+  {
+    mpz_class a(123);
+    int b = sgn(a); ASSERT_ALWAYS(b == 1);
+  }
+  {
+    mpz_class a(0);
+    int b = sgn(a); ASSERT_ALWAYS(b == 0);
+  }
+  {
+    mpz_class a(-123);
+    int b = sgn(a); ASSERT_ALWAYS(b == -1);
+  }
+
+
+  // binary operators and functions
+
+  // operator+
+  {
+    mpz_class a(1), b(2);
+    mpz_class c;
+    c = a + b; ASSERT_ALWAYS(c == 3);
+  }
+  {
+    mpz_class a(3);
+    signed int b = 4;
+    mpz_class c;
+    c = a + b; ASSERT_ALWAYS(c == 7);
+  }
+  {
+    mpz_class a(5);
+    double b = 6.0;
+    mpz_class c;
+    c = b + a; ASSERT_ALWAYS(c == 11);
+  }
+
+  // operator-
+  {
+    mpz_class a(3), b(6);
+    mpz_class c;
+    c = a - b; ASSERT_ALWAYS(c == -3);
+  }
+
+  // operator*
+  {
+    mpz_class a(-2), b(4);
+    mpz_class c;
+    c = a * b; ASSERT_ALWAYS(c == -8);
+  }
+  {
+    mpz_class a(2);
+    long b = -4;
+    mpz_class c;
+    c = a * b; ASSERT_ALWAYS(c == -8);
+    c = b * a; ASSERT_ALWAYS(c == -8);
+  }
+  {
+    mpz_class a(-2);
+    unsigned long b = 4;
+    mpz_class c;
+    c = a * b; ASSERT_ALWAYS(c == -8);
+    c = b * a; ASSERT_ALWAYS(c == -8);
+  }
+
+  // operator/ and operator%
+  {
+    mpz_class a(12), b(4);
+    mpz_class c;
+    c = a / b; ASSERT_ALWAYS(c == 3);
+    c = a % b; ASSERT_ALWAYS(c == 0);
+  }
+  {
+    mpz_class a(7), b(5);
+    mpz_class c;
+    c = a / b; ASSERT_ALWAYS(c == 1);
+    c = a % b; ASSERT_ALWAYS(c == 2);
+  }
+  {
+    mpz_class a(-10);
+    signed int ai = -10;
+    mpz_class b(3);
+    signed int bi = 3;
+    mpz_class c;
+    c = a / b;  ASSERT_ALWAYS(c == -3);
+    c = a % b;  ASSERT_ALWAYS(c == -1);
+    c = a / bi; ASSERT_ALWAYS(c == -3);
+    c = a % bi; ASSERT_ALWAYS(c == -1);
+    c = ai / b; ASSERT_ALWAYS(c == -3);
+    c = ai % b; ASSERT_ALWAYS(c == -1);
+  }
+  {
+    mpz_class a(-10);
+    signed int ai = -10;
+    mpz_class b(-3);
+    signed int bi = -3;
+    mpz_class c;
+    c = a / b;  ASSERT_ALWAYS(c == 3);
+    c = a % b;  ASSERT_ALWAYS(c == -1);
+    c = a / bi; ASSERT_ALWAYS(c == 3);
+    c = a % bi; ASSERT_ALWAYS(c == -1);
+    c = ai / b; ASSERT_ALWAYS(c == 3);
+    c = ai % b; ASSERT_ALWAYS(c == -1);
+  }
+  {
+    mpz_class a (LONG_MIN);
+    signed long ai = LONG_MIN;
+    mpz_class b = - mpz_class (LONG_MIN);
+    mpz_class c;
+    c = a / b;  ASSERT_ALWAYS(c == -1);
+    c = a % b;  ASSERT_ALWAYS(c == 0);
+    c = ai / b; ASSERT_ALWAYS(c == -1);
+    c = ai % b; ASSERT_ALWAYS(c == 0);
+  }
+
+  // operator&
+  // operator|
+  // operator^
+
+  // operator<<
+  {
+    mpz_class a(3);
+    unsigned int b = 4;
+    mpz_class c;
+    c = a << b; ASSERT_ALWAYS(c == 48);
+  }
+
+  // operator>>
+  {
+    mpz_class a(127);
+    unsigned int b = 4;
+    mpz_class c;
+    c = a >> b; ASSERT_ALWAYS(c == 7);
+  }
+
+  // operator==
+  // operator!=
+  // operator<
+  // operator<=
+  // operator>
+  // operator>=
+
+  // cmp
+  {
+    mpz_class a(123), b(45);
+    int c;
+    c = cmp(a, b); ASSERT_ALWAYS(c > 0);
+    c = cmp(b, a); ASSERT_ALWAYS(c < 0);
+  }
+  {
+    mpz_class a(123);
+    unsigned long b = 45;
+    int c;
+    c = cmp(a, b); ASSERT_ALWAYS(c > 0);
+    c = cmp(b, a); ASSERT_ALWAYS(c < 0);
+  }
+  {
+    mpz_class a(123);
+    long b = 45;
+    int c;
+    c = cmp(a, b); ASSERT_ALWAYS(c > 0);
+    c = cmp(b, a); ASSERT_ALWAYS(c < 0);
+  }
+  {
+    mpz_class a(123);
+    double b = 45;
+    int c;
+    c = cmp(a, b); ASSERT_ALWAYS(c > 0);
+    c = cmp(b, a); ASSERT_ALWAYS(c < 0);
+  }
+
+
+  // ternary operators
+
+  // mpz_addmul
+  {
+    mpz_class a(1), b(2), c(3);
+    mpz_class d;
+    d = a + b * c; ASSERT_ALWAYS(d == 7);
+  }
+  {
+    mpz_class a(1), b(2);
+    unsigned int c = 3;
+    mpz_class d;
+    d = a + b * c; ASSERT_ALWAYS(d == 7);
+  }
+  {
+    mpz_class a(1), b(3);
+    unsigned int c = 2;
+    mpz_class d;
+    d = a + c * b; ASSERT_ALWAYS(d == 7);
+  }
+  {
+    mpz_class a(1), b(2);
+    signed int c = 3;
+    mpz_class d;
+    d = a + b * c; ASSERT_ALWAYS(d == 7);
+  }
+  {
+    mpz_class a(1), b(3);
+    signed int c = 2;
+    mpz_class d;
+    d = a + c * b; ASSERT_ALWAYS(d == 7);
+  }
+  {
+    mpz_class a(1), b(2);
+    double c = 3.0;
+    mpz_class d;
+    d = a + b * c; ASSERT_ALWAYS(d == 7);
+  }
+  {
+    mpz_class a(1), b(3);
+    double c = 2.0;
+    mpz_class d;
+    d = a + c * b; ASSERT_ALWAYS(d == 7);
+  }
+
+  {
+    mpz_class a(2), b(3), c(4);
+    mpz_class d;
+    d = a * b + c; ASSERT_ALWAYS(d == 10);
+  }
+  {
+    mpz_class a(2), b(4);
+    unsigned int c = 3;
+    mpz_class d;
+    d = a * c + b; ASSERT_ALWAYS(d == 10);
+  }
+  {
+    mpz_class a(3), b(4);
+    unsigned int c = 2;
+    mpz_class d;
+    d = c * a + b; ASSERT_ALWAYS(d == 10);
+  }
+  {
+    mpz_class a(2), b(4);
+    signed int c = 3;
+    mpz_class d;
+    d = a * c + b; ASSERT_ALWAYS(d == 10);
+  }
+  {
+    mpz_class a(3), b(4);
+    signed int c = 2;
+    mpz_class d;
+    d = c * a + b; ASSERT_ALWAYS(d == 10);
+  }
+  {
+    mpz_class a(2), b(4);
+    double c = 3.0;
+    mpz_class d;
+    d = a * c + b; ASSERT_ALWAYS(d == 10);
+  }
+  {
+    mpz_class a(3), b(4);
+    double c = 2.0;
+    mpz_class d;
+    d = c * a + b; ASSERT_ALWAYS(d == 10);
+  }
+
+  // mpz_submul
+  {
+    mpz_class a(1), b(2), c(3);
+    mpz_class d;
+    d = a - b * c; ASSERT_ALWAYS(d == -5);
+  }
+  {
+    mpz_class a(1), b(2);
+    unsigned int c = 3;
+    mpz_class d;
+    d = a - b * c; ASSERT_ALWAYS(d == -5);
+  }
+  {
+    mpz_class a(1), b(3);
+    unsigned int c = 2;
+    mpz_class d;
+    d = a - c * b; ASSERT_ALWAYS(d == -5);
+  }
+  {
+    mpz_class a(1), b(2);
+    signed int c = 3;
+    mpz_class d;
+    d = a - b * c; ASSERT_ALWAYS(d == -5);
+  }
+  {
+    mpz_class a(1), b(3);
+    signed int c = 2;
+    mpz_class d;
+    d = a - c * b; ASSERT_ALWAYS(d == -5);
+  }
+  {
+    mpz_class a(1), b(2);
+    double c = 3.0;
+    mpz_class d;
+    d = a - b * c; ASSERT_ALWAYS(d == -5);
+  }
+  {
+    mpz_class a(1), b(3);
+    double c = 2.0;
+    mpz_class d;
+    d = a - c * b; ASSERT_ALWAYS(d == -5);
+  }
+
+  {
+    mpz_class a(2), b(3), c(4);
+    mpz_class d;
+    d = a * b - c; ASSERT_ALWAYS(d == 2);
+  }
+  {
+    mpz_class a(2), b(4);
+    unsigned int c = 3;
+    mpz_class d;
+    d = a * c - b; ASSERT_ALWAYS(d == 2);
+  }
+  {
+    mpz_class a(3), b(4);
+    unsigned int c = 2;
+    mpz_class d;
+    d = c * a - b; ASSERT_ALWAYS(d == 2);
+  }
+  {
+    mpz_class a(2), b(4);
+    signed int c = 3;
+    mpz_class d;
+    d = a * c - b; ASSERT_ALWAYS(d == 2);
+  }
+  {
+    mpz_class a(3), b(4);
+    signed int c = 2;
+    mpz_class d;
+    d = c * a - b; ASSERT_ALWAYS(d == 2);
+  }
+  {
+    mpz_class a(2), b(4);
+    double c = 3.0;
+    mpz_class d;
+    d = a * c - b; ASSERT_ALWAYS(d == 2);
+  }
+  {
+    mpz_class a(3), b(4);
+    double c = 2.0;
+    mpz_class d;
+    d = c * a - b; ASSERT_ALWAYS(d == 2);
+  }
+}
+
+void
+check_mpq (void)
+{
+  // unary operators and functions
+
+  // operator+
+  {
+    mpq_class a(1, 2);
+    mpq_class b;
+    b = +a; ASSERT_ALWAYS(b == 0.5);
+  }
+
+  // operator-
+  {
+    mpq_class a(3, 4);
+    mpq_class b;
+    b = -a; ASSERT_ALWAYS(b == -0.75);
+  }
+
+  // abs
+  {
+    mpq_class a(-123);
+    mpq_class b;
+    b = abs(a); ASSERT_ALWAYS(b == 123);
+  }
+
+  // sgn
+  {
+    mpq_class a(123);
+    int b = sgn(a); ASSERT_ALWAYS(b == 1);
+  }
+  {
+    mpq_class a(0);
+    int b = sgn(a); ASSERT_ALWAYS(b == 0);
+  }
+  {
+    mpq_class a(-123);
+    int b = sgn(a); ASSERT_ALWAYS(b == -1);
+  }
+
+
+  // binary operators and functions
+
+  // operator+
+  {
+    mpq_class a(1, 2), b(3, 4);
+    mpq_class c;
+    c = a + b; ASSERT_ALWAYS(c == 1.25);
+  }
+  {
+    mpq_class a(1, 2);
+    signed int b = 2;
+    mpq_class c;
+    c = a + b; ASSERT_ALWAYS(c == 2.5);
+  }
+  {
+    mpq_class a(1, 2);
+    double b = 1.5;
+    mpq_class c;
+    c = b + a; ASSERT_ALWAYS(c == 2);
+  }
+
+  // operator-
+  {
+    mpq_class a(1, 2), b(3, 4);
+    mpq_class c;
+    c = a - b; ASSERT_ALWAYS(c == -0.25);
+  }
+
+  // operator*
+  {
+    mpq_class a(1, 3), b(3, 4);
+    mpq_class c;
+    c = a * b; ASSERT_ALWAYS(c == 0.25);
+    c = b * b; ASSERT_ALWAYS(c == 0.5625);
+  }
+
+  // operator/
+  {
+    mpq_class a(1, 2), b(2, 3);
+    mpq_class c;
+    c = a / b; ASSERT_ALWAYS(c == 0.75);
+  }
+  {
+    mpq_class one = 1;
+    mpq_class x(2, 5);
+    ASSERT_ALWAYS(1 / x == one / x);
+    ASSERT_ALWAYS(1u / x == one / x);
+    x = (-1) / x;
+    ASSERT_ALWAYS(x == -2.5);
+    ASSERT_ALWAYS(0 / x == 0);
+    ASSERT_ALWAYS(0u / x == 0);
+  }
+
+  // operator<<
+  // operator>>
+  // operator==
+  // operator!=
+  // operator<
+  // operator<=
+  // operator>
+  // operator>=
+
+  // cmp
+  {
+    mpq_class a(123), b(45);
+    int c;
+    c = cmp(a, b); ASSERT_ALWAYS(c > 0);
+    c = cmp(b, a); ASSERT_ALWAYS(c < 0);
+  }
+  {
+    mpq_class a(123);
+    unsigned long b = 45;
+    int c;
+    c = cmp(a, b); ASSERT_ALWAYS(c > 0);
+    c = cmp(b, a); ASSERT_ALWAYS(c < 0);
+  }
+  {
+    mpq_class a(123);
+    long b = 45;
+    int c;
+    c = cmp(a, b); ASSERT_ALWAYS(c > 0);
+    c = cmp(b, a); ASSERT_ALWAYS(c < 0);
+  }
+  {
+    mpq_class a(123);
+    double b = 45;
+    int c;
+    c = cmp(a, b); ASSERT_ALWAYS(c > 0);
+    c = cmp(b, a); ASSERT_ALWAYS(c < 0);
+  }
+  {
+    mpq_class a(123);
+    mpz_class b(45);
+    int c;
+    c = cmp(a, b); ASSERT_ALWAYS(c > 0);
+    c = cmp(b, a); ASSERT_ALWAYS(c < 0);
+  }
+}
+
+void
+check_mpf (void)
+{
+  // unary operators and functions
+
+  // operator+
+  {
+    mpf_class a(1);
+    mpf_class b;
+    b = +a; ASSERT_ALWAYS(b == 1);
+  }
+
+  // operator-
+  {
+    mpf_class a(2);
+    mpf_class b;
+    b = -a; ASSERT_ALWAYS(b == -2);
+  }
+
+  // abs
+  {
+    mpf_class a(-123);
+    mpf_class b;
+    b = abs(a); ASSERT_ALWAYS(b == 123);
+  }
+
+  // trunc
+  {
+    mpf_class a(1.5);
+    mpf_class b;
+    b = trunc(a); ASSERT_ALWAYS(b == 1);
+  }
+  {
+    mpf_class a(-1.5);
+    mpf_class b;
+    b = trunc(a); ASSERT_ALWAYS(b == -1);
+  }
+
+  // floor
+  {
+    mpf_class a(1.9);
+    mpf_class b;
+    b = floor(a); ASSERT_ALWAYS(b == 1);
+  }
+  {
+    mpf_class a(-1.1);
+    mpf_class b;
+    b = floor(a); ASSERT_ALWAYS(b == -2);
+  }
+
+  // ceil
+  {
+    mpf_class a(1.1);
+    mpf_class b;
+    b = ceil(a); ASSERT_ALWAYS(b == 2);
+  }
+  {
+    mpf_class a(-1.9);
+    mpf_class b;
+    b = ceil(a); ASSERT_ALWAYS(b == -1);
+  }
+
+  // sqrt
+  {
+    mpf_class a(25);
+    mpf_class b;
+    b = sqrt(a); ASSERT_ALWAYS(b == 5);
+  }
+  {
+    mpf_class a(2.25);
+    mpf_class b;
+    b = sqrt(a); ASSERT_ALWAYS(b == 1.5);
+  }
+
+  // sgn
+  {
+    mpf_class a(123);
+    int b = sgn(a); ASSERT_ALWAYS(b == 1);
+  }
+  {
+    mpf_class a(0);
+    int b = sgn(a); ASSERT_ALWAYS(b == 0);
+  }
+  {
+    mpf_class a(-123);
+    int b = sgn(a); ASSERT_ALWAYS(b == -1);
+  }
+
+
+  // binary operators and functions
+
+  // operator+
+  {
+    mpf_class a(1), b(2);
+    mpf_class c;
+    c = a + b; ASSERT_ALWAYS(c == 3);
+  }
+
+  // operator-
+  {
+    mpf_class a(3), b(4);
+    mpf_class c;
+    c = a - b; ASSERT_ALWAYS(c == -1);
+  }
+
+  // operator*
+  {
+    mpf_class a(2), b(5);
+    mpf_class c;
+    c = a * b; ASSERT_ALWAYS(c == 10);
+  }
+
+  // operator/
+  {
+    mpf_class a(7), b(4);
+    mpf_class c;
+    c = a / b; ASSERT_ALWAYS(c == 1.75);
+  }
+
+  // operator<<
+  // operator>>
+  // operator==
+  // operator!=
+  // operator<
+  // operator<=
+  // operator>
+  // operator>=
+
+  // hypot
+  {
+    mpf_class a(3), b(4);
+    mpf_class c;
+    c = hypot(a, b); ASSERT_ALWAYS(c == 5);
+  }
+
+  // cmp
+  {
+    mpf_class a(123), b(45);
+    int c;
+    c = cmp(a, b); ASSERT_ALWAYS(c > 0);
+    c = cmp(b, a); ASSERT_ALWAYS(c < 0);
+  }
+  {
+    mpf_class a(123);
+    unsigned long b = 45;
+    int c;
+    c = cmp(a, b); ASSERT_ALWAYS(c > 0);
+    c = cmp(b, a); ASSERT_ALWAYS(c < 0);
+  }
+  {
+    mpf_class a(123);
+    long b = 45;
+    int c;
+    c = cmp(a, b); ASSERT_ALWAYS(c > 0);
+    c = cmp(b, a); ASSERT_ALWAYS(c < 0);
+  }
+  {
+    mpf_class a(123);
+    double b = 45;
+    int c;
+    c = cmp(a, b); ASSERT_ALWAYS(c > 0);
+    c = cmp(b, a); ASSERT_ALWAYS(c < 0);
+  }
+  {
+    mpf_class a(123);
+    mpz_class b(45);
+    int c;
+    c = cmp(a, b); ASSERT_ALWAYS(c > 0);
+    c = cmp(b, a); ASSERT_ALWAYS(c < 0);
+  }
+  {
+    mpf_class a(123);
+    mpq_class b(45);
+    int c;
+    c = cmp(a, b); ASSERT_ALWAYS(c > 0);
+    c = cmp(b, a); ASSERT_ALWAYS(c < 0);
+  }
+}
+
+
+int
+main (void)
+{
+  tests_start();
+
+  check_mpz();
+  check_mpq();
+  check_mpf();
+
+  tests_end();
+  return 0;
+}
diff --git a/third_party/gmp/tests/cxx/t-ops2.h b/third_party/gmp/tests/cxx/t-ops2.h
new file mode 100644
index 0000000..f8898ee
--- /dev/null
+++ b/third_party/gmp/tests/cxx/t-ops2.h
@@ -0,0 +1,82 @@
+/* Test mp*_class operators and functions.
+
+Copyright 2011, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#include <math.h>
+
+#include "gmpxx.h"
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+#define CHECK1(Type,a,fun) \
+  ASSERT_ALWAYS(fun((Type)(a))==fun(a))
+#define CHECK(Type1,Type2,a,b,op) \
+  ASSERT_ALWAYS(((Type1)(a) op (Type2)(b))==((a) op (b)))
+#define CHECK_G(Type,a,b,op) \
+  CHECK(Type,Type,a,b,op)
+#define CHECK_UI(Type,a,b,op) \
+  CHECK(Type,unsigned long,a,b,op); \
+  CHECK(unsigned long,Type,a,b,op)
+#define CHECK_SI(Type,a,b,op) \
+  CHECK(Type,long,a,b,op); \
+  CHECK(long,Type,a,b,op)
+#define CHECK_D(Type,a,b,op) \
+  CHECK(Type,double,a,b,op); \
+  CHECK(double,Type,a,b,op)
+#define CHECK_MPZ(Type,a,b,op) \
+  CHECK(Type,mpz_class,a,b,op); \
+  CHECK(mpz_class,Type,a,b,op)
+#define CHECK_MPQ(Type,a,b,op) \
+  CHECK(Type,mpq_class,a,b,op); \
+  CHECK(mpq_class,Type,a,b,op)
+#define CHECK_ALL_SIGNED(Type,a,b,op) \
+  CHECK_G(Type,a,b,op); \
+  CHECK_SI(Type,a,b,op); \
+  CHECK_D(Type,a,b,op)
+#define CHECK_ALL_SIGNS(Type,a,b,op) \
+  CHECK_ALL_SIGNED(Type,a,b,op); \
+  CHECK_ALL_SIGNED(Type,-(a),b,op); \
+  CHECK_ALL_SIGNED(Type,a,-(b),op); \
+  CHECK_ALL_SIGNED(Type,-(a),-(b),op)
+#define CHECK_ALL(Type,a,b,op) \
+  CHECK_ALL_SIGNED(Type,a,b,op); \
+  CHECK_UI(Type,a,b,op)
+#define CHECK_ALL_SIGNED_COMPARISONS(Type,a,b) \
+  CHECK_ALL_SIGNED(Type,a,b,<); \
+  CHECK_ALL_SIGNED(Type,a,b,>); \
+  CHECK_ALL_SIGNED(Type,a,b,<=); \
+  CHECK_ALL_SIGNED(Type,a,b,>=); \
+  CHECK_ALL_SIGNED(Type,a,b,==); \
+  CHECK_ALL_SIGNED(Type,a,b,!=)
+#define CHECK_ALL_SIGNS_COMPARISONS(Type,a,b) \
+  CHECK_ALL_SIGNS(Type,a,b,<); \
+  CHECK_ALL_SIGNS(Type,a,b,>); \
+  CHECK_ALL_SIGNS(Type,a,b,<=); \
+  CHECK_ALL_SIGNS(Type,a,b,>=); \
+  CHECK_ALL_SIGNS(Type,a,b,==); \
+  CHECK_ALL_SIGNS(Type,a,b,!=)
+#define CHECK_ALL_COMPARISONS(Type,a,b) \
+  CHECK_ALL(Type,a,b,<); \
+  CHECK_ALL(Type,a,b,>); \
+  CHECK_ALL(Type,a,b,<=); \
+  CHECK_ALL(Type,a,b,>=); \
+  CHECK_ALL(Type,a,b,==); \
+  CHECK_ALL(Type,a,b,!=)
diff --git a/third_party/gmp/tests/cxx/t-ops2f.cc b/third_party/gmp/tests/cxx/t-ops2f.cc
new file mode 100644
index 0000000..71c9e10
--- /dev/null
+++ b/third_party/gmp/tests/cxx/t-ops2f.cc
@@ -0,0 +1,87 @@
+/* Test mp*_class operators and functions.
+
+Copyright 2011, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "t-ops2.h"
+
+void checkf (){
+  ASSERT_ALWAYS(sqrt(mpf_class(7))>2.64);
+  ASSERT_ALWAYS(sqrt(mpf_class(7))<2.65);
+  ASSERT_ALWAYS(sqrt(mpf_class(0))==0);
+  // TODO: add some consistency checks, as described in
+  // https://gmplib.org/list-archives/gmp-bugs/2013-February/002940.html
+  CHECK1(mpf_class,1.9,trunc);
+  CHECK1(mpf_class,1.9,floor);
+  CHECK1(mpf_class,1.9,ceil);
+  CHECK1(mpf_class,4.3,trunc);
+  CHECK1(mpf_class,4.3,floor);
+  CHECK1(mpf_class,4.3,ceil);
+  CHECK1(mpf_class,-7.1,trunc);
+  CHECK1(mpf_class,-7.1,floor);
+  CHECK1(mpf_class,-7.1,ceil);
+  CHECK1(mpf_class,-2.8,trunc);
+  CHECK1(mpf_class,-2.8,floor);
+  CHECK1(mpf_class,-2.8,ceil);
+  CHECK1(mpf_class,-1.5,trunc);
+  CHECK1(mpf_class,-1.5,floor);
+  CHECK1(mpf_class,-1.5,ceil);
+  CHECK1(mpf_class,2.5,trunc);
+  CHECK1(mpf_class,2.5,floor);
+  CHECK1(mpf_class,2.5,ceil);
+  ASSERT_ALWAYS(hypot(mpf_class(-3),mpf_class(4))>4.9);
+  ASSERT_ALWAYS(hypot(mpf_class(-3),mpf_class(4))<5.1);
+  ASSERT_ALWAYS(hypot(mpf_class(-3),4.)>4.9);
+  ASSERT_ALWAYS(hypot(-3.,mpf_class(4))<5.1);
+  ASSERT_ALWAYS(hypot(mpf_class(-3),4l)>4.9);
+  ASSERT_ALWAYS(hypot(-3l,mpf_class(4))<5.1);
+  ASSERT_ALWAYS(hypot(mpf_class(-3),4ul)>4.9);
+  ASSERT_ALWAYS(hypot(3ul,mpf_class(4))<5.1);
+  CHECK(mpf_class,mpq_class,1.5,2.25,+);
+  CHECK(mpf_class,mpq_class,1.5,2.25,-);
+  CHECK(mpf_class,mpq_class,1.5,-2.25,*);
+  CHECK(mpf_class,mpq_class,1.5,-2,/);
+  CHECK_MPQ(mpf_class,-5.5,-2.25,+);
+  CHECK_MPQ(mpf_class,-5.5,-2.25,-);
+  CHECK_MPQ(mpf_class,-5.5,-2.25,*);
+  CHECK_MPQ(mpf_class,-5.25,-0.5,/);
+  CHECK_MPQ(mpf_class,5,-2,<);
+  CHECK_MPQ(mpf_class,5,-2,>);
+  CHECK_MPQ(mpf_class,5,-2,<=);
+  CHECK_MPQ(mpf_class,5,-2,>=);
+  CHECK_MPQ(mpf_class,5,-2,==);
+  CHECK_MPQ(mpf_class,5,-2,!=);
+  CHECK_MPQ(mpf_class,0,0,<);
+  CHECK_MPQ(mpf_class,0,0,>);
+  CHECK_MPQ(mpf_class,0,0,<=);
+  CHECK_MPQ(mpf_class,0,0,>=);
+  CHECK_MPQ(mpf_class,0,0,==);
+  CHECK_MPQ(mpf_class,0,0,!=);
+}
+
+int
+main (void)
+{
+  tests_start();
+
+  // Enough precision for 1 + denorm_min
+  mpf_set_default_prec(DBL_MANT_DIG-DBL_MIN_EXP+42);
+  checkf();
+
+  tests_end();
+  return 0;
+}
diff --git a/third_party/gmp/tests/cxx/t-ops2qf.cc b/third_party/gmp/tests/cxx/t-ops2qf.cc
new file mode 100644
index 0000000..bd96f61
--- /dev/null
+++ b/third_party/gmp/tests/cxx/t-ops2qf.cc
@@ -0,0 +1,89 @@
+/* Test mp*_class operators and functions.
+
+Copyright 2011, 2012, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "t-ops2.h"
+
+template<class T>
+void checkqf (){
+  CHECK_ALL(T,5.,0,+);
+  CHECK_ALL(T,5.,0,-);
+  CHECK_ALL(T,5.,2,+); CHECK_MPZ(T,5.,2,+);
+  CHECK_ALL(T,5.,2,-); CHECK_MPZ(T,5.,2,-);
+  CHECK_ALL(T,5.,2,*); CHECK_MPZ(T,5.,2,*);
+  CHECK_ALL(T,5.,2,/); CHECK_MPZ(T,5.,2,/);
+  CHECK_ALL(T,0.,2,/);
+  CHECK_ALL_SIGNS(T,11.,3,+);
+  CHECK_ALL_SIGNS(T,11.,3,-);
+  CHECK_ALL_SIGNS(T,13.,1,+);
+  CHECK_ALL_SIGNS(T,13.,1,-);
+  CHECK_ALL_SIGNS(T,11.,3,*);
+  CHECK_ALL_SIGNS(T,11.,4,/);
+  CHECK_SI(T,LONG_MIN,1,*);
+  CHECK_SI(T,0,3,*);
+  CHECK_ALL_COMPARISONS(T,5.,2);
+  CHECK_ALL_SIGNS_COMPARISONS(T,11.,3);
+  CHECK_MPZ(T,5,-2,<);
+  CHECK_MPZ(T,5,-2,>);
+  CHECK_MPZ(T,5,-2,<=);
+  CHECK_MPZ(T,5,-2,>=);
+  CHECK_MPZ(T,5,-2,==);
+  CHECK_MPZ(T,5,-2,!=);
+  CHECK_MPZ(T,0,0,<);
+  CHECK_MPZ(T,0,0,>);
+  CHECK_MPZ(T,0,0,<=);
+  CHECK_MPZ(T,0,0,>=);
+  CHECK_MPZ(T,0,0,==);
+  CHECK_MPZ(T,0,0,!=);
+  ASSERT_ALWAYS(T(6)<<2==6.*4);
+  ASSERT_ALWAYS(T(6)>>2==6./4);
+  ASSERT_ALWAYS(T(-13)<<2==-13.*4);
+  ASSERT_ALWAYS(T(-13)>>2==-13./4);
+  ASSERT_ALWAYS(++T(7)==8);
+  ASSERT_ALWAYS(++T(-8)==-7);
+  ASSERT_ALWAYS(--T(8)==7);
+  ASSERT_ALWAYS(--T(-7)==-8);
+  ASSERT_ALWAYS(+T(7)==7);
+  ASSERT_ALWAYS(+T(-8)==-8);
+  ASSERT_ALWAYS(-T(7)==-7);
+  ASSERT_ALWAYS(-T(-8)==8);
+  ASSERT_ALWAYS(abs(T(7))==7);
+  ASSERT_ALWAYS(abs(T(-8))==8);
+  ASSERT_ALWAYS(sgn(T(0))==0);
+  ASSERT_ALWAYS(sgn(T(9))==1);
+  ASSERT_ALWAYS(sgn(T(-17))==-1);
+  ASSERT_ALWAYS(T(1)+DBL_MAX>2);
+  ASSERT_ALWAYS(T(1)+DBL_MIN>1);
+  ASSERT_ALWAYS(T(1)+DBL_MIN<1.001);
+  ASSERT_ALWAYS(T(1)+std::numeric_limits<double>::denorm_min()>1);
+  ASSERT_ALWAYS(T(1)+std::numeric_limits<double>::denorm_min()<1.001);
+}
+
+int
+main (void)
+{
+  tests_start();
+
+  // Enough precision for 1 + denorm_min
+  mpf_set_default_prec(DBL_MANT_DIG-DBL_MIN_EXP+42);
+  checkqf<mpq_class>();
+  checkqf<mpf_class>();
+
+  tests_end();
+  return 0;
+}
diff --git a/third_party/gmp/tests/cxx/t-ops2z.cc b/third_party/gmp/tests/cxx/t-ops2z.cc
new file mode 100644
index 0000000..6d0e4ad
--- /dev/null
+++ b/third_party/gmp/tests/cxx/t-ops2z.cc
@@ -0,0 +1,126 @@
+/* Test mp*_class operators and functions.
+
+Copyright 2011, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "t-ops2.h"
+
+void checkz (){
+  CHECK_ALL(mpz_class,5,2,+);
+  CHECK_ALL(mpz_class,5,2,-);
+  CHECK_ALL(mpz_class,5,2,*);
+  CHECK_ALL(mpz_class,5,2,/);
+  CHECK_ALL(mpz_class,5,2,%);
+  CHECK_ALL_COMPARISONS(mpz_class,5,2);
+  CHECK_ALL_SIGNS(mpz_class,11,3,+);
+  CHECK_ALL_SIGNS(mpz_class,11,3,-);
+  CHECK_ALL_SIGNS(mpz_class,11,3,*);
+  CHECK_ALL_SIGNS(mpz_class,11,3,/);
+  CHECK_ALL_SIGNS(mpz_class,11,3,%);
+  CHECK_ALL_SIGNS(mpz_class,17,2,*);
+  CHECK_ALL_SIGNS(mpz_class,17,2,/);
+  CHECK_ALL_SIGNS(mpz_class,17,2,%);
+  CHECK(unsigned long,mpz_class,5,-2,/);
+  CHECK(unsigned long,mpz_class,5,-2,%);
+  ASSERT_ALWAYS(7ul/mpz_class(1e35)==0);
+  ASSERT_ALWAYS(7ul%mpz_class(1e35)==7);
+  ASSERT_ALWAYS(7ul/mpz_class(-1e35)==0);
+  ASSERT_ALWAYS(7ul%mpz_class(-1e35)==7);
+  CHECK_ALL_SIGNS_COMPARISONS(mpz_class,11,3);
+  CHECK_ALL(mpz_class,6,3,&);
+  CHECK_ALL(mpz_class,6,3,|);
+  CHECK_ALL(mpz_class,6,3,^);
+  CHECK(mpz_class,unsigned long,6,2,<<);
+  CHECK(mpz_class,unsigned long,6,2,>>);
+  ASSERT_ALWAYS((mpz_class(-13)<<(unsigned long)2) == (-13)*4);
+  CHECK(mpz_class,unsigned long,-13,2,>>);
+  ASSERT_ALWAYS(++mpz_class(7)==8);
+  ASSERT_ALWAYS(++mpz_class(-8)==-7);
+  ASSERT_ALWAYS(--mpz_class(8)==7);
+  ASSERT_ALWAYS(--mpz_class(-7)==-8);
+  ASSERT_ALWAYS(~mpz_class(7)==-8);
+  ASSERT_ALWAYS(~mpz_class(-8)==7);
+  ASSERT_ALWAYS(+mpz_class(7)==7);
+  ASSERT_ALWAYS(+mpz_class(-8)==-8);
+  ASSERT_ALWAYS(-mpz_class(7)==-7);
+  ASSERT_ALWAYS(-mpz_class(-8)==8);
+  ASSERT_ALWAYS(abs(mpz_class(7))==7);
+  ASSERT_ALWAYS(abs(mpz_class(-8))==8);
+  ASSERT_ALWAYS(sqrt(mpz_class(7))==2);
+  ASSERT_ALWAYS(sqrt(mpz_class(0))==0);
+  ASSERT_ALWAYS(sgn(mpz_class(0))==0);
+  ASSERT_ALWAYS(sgn(mpz_class(9))==1);
+  ASSERT_ALWAYS(sgn(mpz_class(-17))==-1);
+  ASSERT_ALWAYS(mpz_class(1)+DBL_MAX>2);
+  ASSERT_ALWAYS(mpz_class(1)+DBL_MIN<2);
+  ASSERT_ALWAYS(mpz_class(1)+std::numeric_limits<double>::denorm_min()<2);
+  ASSERT_ALWAYS(gcd(mpz_class(6),mpz_class(8))==2);
+  ASSERT_ALWAYS(gcd(-mpz_class(6),mpz_class(8))==2);
+  ASSERT_ALWAYS(gcd(-mpz_class(6),-mpz_class(8))==2);
+  ASSERT_ALWAYS(gcd(mpz_class(6),8.f)==2);
+  ASSERT_ALWAYS(gcd(-mpz_class(6),static_cast<unsigned char>(8))==2);
+  ASSERT_ALWAYS(gcd(static_cast<long>(-6),mpz_class(5)+3)==2);
+  ASSERT_ALWAYS(lcm(mpz_class(6),mpz_class(8))==24);
+  ASSERT_ALWAYS(lcm(-mpz_class(6),mpz_class(8))==24);
+  ASSERT_ALWAYS(lcm(-mpz_class(6),-mpz_class(8))==24);
+  ASSERT_ALWAYS(lcm(mpz_class(6),static_cast<short>(8))==24);
+  ASSERT_ALWAYS(lcm(-mpz_class(6),static_cast<unsigned char>(8))==24);
+  ASSERT_ALWAYS(lcm(-6.,mpz_class(5)+3)==24);
+  ASSERT_ALWAYS(factorial(mpz_class(3))==6);
+  ASSERT_ALWAYS(factorial(mpz_class(5)-1)==24);
+  ASSERT_ALWAYS(mpz_class::factorial(mpz_class(3))==6);
+  ASSERT_ALWAYS(mpz_class::factorial(mpz_class(2)*2)==24);
+  ASSERT_ALWAYS(mpz_class::factorial(3)==6);
+  ASSERT_ALWAYS(mpz_class::factorial(3ul)==6);
+  ASSERT_ALWAYS(mpz_class::factorial(3.f)==6);
+  mpz_class ret;
+  try { ret=factorial(-mpz_class(3)); ASSERT_ALWAYS(0); }
+  catch (std::domain_error) {}
+  try { ret=mpz_class::factorial(-2); ASSERT_ALWAYS(0); }
+  catch (std::domain_error) {}
+  try { ret=factorial(mpz_class(1)<<300); ASSERT_ALWAYS(0); }
+  catch (std::bad_alloc) {}
+  ASSERT_ALWAYS(mpz_class::primorial(mpz_class(3))==6);
+  ASSERT_ALWAYS(mpz_class::primorial(mpz_class(2)*2)==6);
+  ASSERT_ALWAYS(mpz_class::primorial(3)==6);
+  ASSERT_ALWAYS(mpz_class::primorial(3ul)==6);
+  ASSERT_ALWAYS(mpz_class::primorial(3.f)==6);
+  try { ret=primorial(-mpz_class(3)); ASSERT_ALWAYS(0); }
+  catch (std::domain_error) {}
+  try { ret=mpz_class::primorial(-5); ASSERT_ALWAYS(0); }
+  catch (std::domain_error) {}
+  try { ret=primorial(mpz_class(1)<<300); ASSERT_ALWAYS(0); }
+  catch (std::bad_alloc) {}
+  ASSERT_ALWAYS(mpz_class::fibonacci(mpz_class(6))==8);
+  ASSERT_ALWAYS(mpz_class::fibonacci(mpz_class(2)*2)==3);
+  ASSERT_ALWAYS(mpz_class::fibonacci(3)==2);
+  ASSERT_ALWAYS(mpz_class::fibonacci(3ul)==2);
+  ASSERT_ALWAYS(mpz_class::fibonacci(3.f)==2);
+  ASSERT_ALWAYS(fibonacci(-mpz_class(6))==-8);
+  ASSERT_ALWAYS(mpz_class::fibonacci(-3)==2);
+  try { ret=fibonacci(mpz_class(1)<<300); ASSERT_ALWAYS(0); }
+  catch (std::bad_alloc) {}
+}
+
+int
+main (void)
+{
+  tests_start();
+  checkz();
+  tests_end();
+  return 0;
+}
diff --git a/third_party/gmp/tests/cxx/t-ops3.cc b/third_party/gmp/tests/cxx/t-ops3.cc
new file mode 100644
index 0000000..baf49e1
--- /dev/null
+++ b/third_party/gmp/tests/cxx/t-ops3.cc
@@ -0,0 +1,132 @@
+/* Test mp*_class assignment operators (+=, -=, etc)
+
+Copyright 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#include "gmpxx.h"
+#include "gmp-impl.h"
+#include "tests.h"
+
+using namespace std;
+
+#define FOR_ALL_SIGNED_BUILTIN(F) \
+	F(signed char) \
+	F(signed short) \
+	F(signed int) \
+	F(signed long) \
+	F(float) \
+	F(double)
+
+#define FOR_ALL_BUILTIN(F) \
+	FOR_ALL_SIGNED_BUILTIN(F) \
+	F(char) \
+	F(unsigned char) \
+	F(unsigned short) \
+	F(unsigned int) \
+	F(unsigned long)
+
+#define FOR_ALL_GMPXX(F) \
+	F(mpz_class) \
+	F(mpq_class) \
+	F(mpf_class)
+
+template<class T,class U> void f(T t, U u){
+  T a=t;
+  ASSERT_ALWAYS((a+=u)==(t+u)); ASSERT_ALWAYS(a==(t+u));
+  ASSERT_ALWAYS((a-=u)==t); ASSERT_ALWAYS(a==t);
+  ASSERT_ALWAYS((a*=u)==(t*u)); ASSERT_ALWAYS(a==(t*u));
+  ASSERT_ALWAYS((a/=u)==t); ASSERT_ALWAYS(a==t);
+  ASSERT_ALWAYS((a<<=5)==(t<<5)); ASSERT_ALWAYS(a==(t<<5));
+  ASSERT_ALWAYS((a>>=5)==t); ASSERT_ALWAYS(a==t);
+}
+
+template<class T,class U> void g(T t, U u){
+  T a=t;
+  ASSERT_ALWAYS((a%=u)==(t%u)); ASSERT_ALWAYS(a==(t%u));
+  a=t;
+  ASSERT_ALWAYS((a&=u)==(t&u)); ASSERT_ALWAYS(a==(t&u));
+  a=t;
+  ASSERT_ALWAYS((a|=u)==(t|u)); ASSERT_ALWAYS(a==(t|u));
+  a=t;
+  ASSERT_ALWAYS((a^=u)==(t^u)); ASSERT_ALWAYS(a==(t^u));
+}
+
+template<class T> void h(T t){
+  T a=t;
+  ASSERT_ALWAYS((a<<=5)==(t<<5)); ASSERT_ALWAYS(a==(t<<5));
+  ASSERT_ALWAYS((a>>=5)==t); ASSERT_ALWAYS(a==t);
+}
+
+template<class T, class U> void ffs(T t, U u){
+#define F(V) f(t,(V)u);
+	FOR_ALL_SIGNED_BUILTIN(F)
+	FOR_ALL_GMPXX(F)
+#undef F
+#define F(V) f(t,-(V)u);
+	FOR_ALL_GMPXX(F)
+#undef F
+}
+
+template<class T, class U> void ff(T t, U u){
+#define F(V) f(t,(V)u);
+	FOR_ALL_BUILTIN(F)
+	FOR_ALL_GMPXX(F)
+#undef F
+#define F(V) f(t,-(V)u);
+	FOR_ALL_GMPXX(F)
+#undef F
+}
+
+template<class U> void ggs(mpz_class t, U u){
+#define F(V) g(t,(V)u);
+	FOR_ALL_SIGNED_BUILTIN(F)
+#undef F
+	g(t,(mpz_class)u);
+	g(t,-(mpz_class)u);
+}
+
+template<class U> void gg(mpz_class t, U u){
+#define F(V) g(t,(V)u);
+	FOR_ALL_BUILTIN(F)
+#undef F
+	g(t,(mpz_class)u);
+	g(t,-(mpz_class)u);
+}
+
+void check(){
+	mpz_class z=18;
+	mpq_class q(7,2);
+	mpf_class d=3.375;
+	h(z); h(q); h(d);
+	ff(z,13); ff(q,13); ff(d,13);
+	ffs(z,-42); ffs(q,-42); ffs(d,-42);
+	gg(z,33); ggs(z,-22);
+}
+
+
+int
+main (void)
+{
+  tests_start();
+
+  check();
+
+  tests_end();
+  return 0;
+}
diff --git a/third_party/gmp/tests/cxx/t-ostream.cc b/third_party/gmp/tests/cxx/t-ostream.cc
new file mode 100644
index 0000000..8550f67
--- /dev/null
+++ b/third_party/gmp/tests/cxx/t-ostream.cc
@@ -0,0 +1,449 @@
+/* Test ostream formatted output.
+
+Copyright 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <iostream>
+#include <cstdlib>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+using namespace std;
+
+
+bool option_check_standard = false;
+
+
+#define CALL(expr)							\
+  do {									\
+    got.flags (data[i].flags);						\
+    got.width (data[i].width);						\
+    got.precision (data[i].precision);					\
+    if (data[i].fill == '\0')						\
+      got.fill (' ');							\
+    else								\
+      got.fill (data[i].fill);						\
+									\
+    if (! (expr))							\
+      {									\
+	cout << "\"got\" output error\n";				\
+	abort ();							\
+      }									\
+    if (got.width() != 0)						\
+      {									\
+	cout << "\"got\" width not reset to 0\n";			\
+	abort ();							\
+      }									\
+									\
+  } while (0)
+
+
+#define DUMP()								\
+  do {									\
+    cout << "  want:  |" << data[i].want << "|\n";			\
+    cout << "  got:   |" << got.str() << "|\n";				\
+    cout << "  width: " << data[i].width << "\n";			\
+    cout << "  prec:  " << got.precision() << "\n";			\
+    cout << "  flags: " << hex << (unsigned long) got.flags() << "\n";	\
+  } while (0)
+
+#define ABORT() \
+  do {          \
+    DUMP ();    \
+    abort ();   \
+  } while (0)
+
+void
+check_mpz (void)
+{
+  static const struct {
+    const char     *z;
+    const char     *want;
+    ios::fmtflags  flags;
+    int            width;
+    int            precision;
+    char           fill;
+
+  } data[] = {
+
+    { "0", "0", ios::dec },
+
+    { "0", "0", ios::oct },
+    { "0", "0", ios::oct | ios::showbase },
+
+    { "0", "0", ios::hex },
+    { "0", "0x0", ios::hex | ios::showbase },
+    { "0", "0X0", ios::hex | ios::showbase | ios::uppercase },
+
+    { "1", "****1", ios::dec, 5, 0, '*' },
+
+    { "-1", "   -1",  ios::dec | ios::right,    5 },
+    { "-1", "-   1",  ios::dec | ios::internal, 5 },
+    { "-1", "-1   ",  ios::dec | ios::left,     5 },
+
+    { "1", "   0x1", ios::hex | ios::showbase | ios::right,    6 },
+    { "1", "0x   1", ios::hex | ios::showbase | ios::internal, 6 },
+    { "1", "0x1   ", ios::hex | ios::showbase | ios::left,     6 },
+
+    { "1", "   +0x1", ios::hex | ios::showbase | ios::showpos | ios::right,
+      7 },
+    { "1", "+0x   1", ios::hex | ios::showbase | ios::showpos | ios::internal,
+      7 },
+    { "1", "+0x1   ", ios::hex | ios::showbase | ios::showpos | ios::left,
+      7 },
+
+    {  "123",    "7b", ios::hex },
+    {  "123",    "7B", ios::hex | ios::uppercase },
+    {  "123",  "0x7b", ios::hex | ios::showbase },
+    {  "123",  "0X7B", ios::hex | ios::showbase | ios::uppercase },
+    { "-123", "-0x7b", ios::hex | ios::showbase },
+    { "-123", "-0X7B", ios::hex | ios::showbase | ios::uppercase },
+
+    {  "123",   "173", ios::oct },
+    {  "123",   "173", ios::oct | ios::uppercase },
+    {  "123",  "0173", ios::oct | ios::showbase },
+    {  "123",  "0173", ios::oct | ios::showbase | ios::uppercase },
+    { "-123", "-0173", ios::oct | ios::showbase },
+    { "-123", "-0173", ios::oct | ios::showbase | ios::uppercase },
+
+  };
+
+  size_t  i;
+  mpz_t   z;
+
+  mpz_init (z);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_set_str_or_abort (z, data[i].z, 0);
+
+      if (option_check_standard
+	  && mpz_fits_slong_p (z)
+
+	  // no negatives or showpos in hex or oct
+	  && (((data[i].flags & ios::basefield) == ios::hex
+	       || (data[i].flags & ios::basefield) == ios::oct)
+	      ? (mpz_sgn (z) >= 0
+		 && ! (data[i].flags & ios::showpos))
+	      : 1)
+	  )
+	{
+	  ostringstream  got;
+	  long  n = mpz_get_si (z);
+	  CALL (got << n);
+	  if (got.str().compare (data[i].want) != 0)
+	    {
+	      cout << "check_mpz data[" << i
+		   << "] doesn't match standard ostream output\n";
+	      cout << "  z:     " << data[i].z << "\n";
+	      cout << "  n:     " << n << "\n";
+	      DUMP ();
+	    }
+	}
+
+      {
+	ostringstream  got;
+	CALL (got << z);
+	if (got.str().compare (data[i].want) != 0)
+	  {
+	    cout << "mpz operator<< wrong, data[" << i << "]\n";
+	    cout << "  z:     " << data[i].z << "\n";
+	    ABORT ();
+	  }
+      }
+    }
+
+  mpz_clear (z);
+}
+
+void
+check_mpq (void)
+{
+  static const struct {
+    const char     *q;
+    const char     *want;
+    ios::fmtflags  flags;
+    int            width;
+    int            precision;
+    char           fill;
+
+  } data[] = {
+
+    { "0", "0", ios::dec },
+    { "0", "0", ios::hex },
+    { "0", "0x0", ios::hex | ios::showbase },
+    { "0", "0X0", ios::hex | ios::showbase | ios::uppercase },
+
+    { "5/8", "5/8", ios::dec },
+    { "5/8", "0X5/0X8", ios::hex | ios::showbase | ios::uppercase },
+
+    // zero denominator with showbase
+    { "0/0",   "       0/0", ios::oct | ios::showbase, 10 },
+    { "0/0",   "       0/0", ios::dec | ios::showbase, 10 },
+    { "0/0",   "   0x0/0x0", ios::hex | ios::showbase, 10 },
+    { "123/0", "    0173/0", ios::oct | ios::showbase, 10 },
+    { "123/0", "     123/0", ios::dec | ios::showbase, 10 },
+    { "123/0", "  0x7b/0x0", ios::hex | ios::showbase, 10 },
+    { "123/0", "  0X7B/0X0", ios::hex | ios::showbase | ios::uppercase, 10 },
+    { "0/123", "    0/0173", ios::oct | ios::showbase, 10 },
+    { "0/123", "     0/123", ios::dec | ios::showbase, 10 },
+    { "0/123", "  0x0/0x7b", ios::hex | ios::showbase, 10 },
+    { "0/123", "  0X0/0X7B", ios::hex | ios::showbase | ios::uppercase, 10 },
+  };
+
+  size_t  i;
+  mpq_t   q;
+
+  mpq_init (q);
+
+#define mpq_integer_p(q)  (mpz_cmp_ui (mpq_denref(q), 1L) == 0)
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpq_set_str_or_abort (q, data[i].q, 0);
+      MPZ_CHECK_FORMAT (mpq_numref (q));
+      MPZ_CHECK_FORMAT (mpq_denref (q));
+
+      if (option_check_standard
+	  && mpz_fits_slong_p (mpq_numref(q))
+	  && mpq_integer_p (q))
+	{
+	  ostringstream  got;
+	  long  n = mpz_get_si (mpq_numref(q));
+	  CALL (got << n);
+	  if (got.str().compare (data[i].want) != 0)
+	    {
+	      cout << "check_mpq data[" << i
+		   << "] doesn't match standard ostream output\n";
+	      cout << "  q:     " << data[i].q << "\n";
+	      cout << "  n:     " << n << "\n";
+	      DUMP ();
+	    }
+	}
+
+      {
+	ostringstream  got;
+	CALL (got << q);
+	if (got.str().compare (data[i].want) != 0)
+	  {
+	    cout << "mpq operator<< wrong, data[" << i << "]\n";
+	    cout << "  q:     " << data[i].q << "\n";
+	    ABORT ();
+	  }
+      }
+    }
+
+  mpq_clear (q);
+}
+
+
+void
+check_mpf (void)
+{
+  static const struct {
+    const char     *f;
+    const char     *want;
+    ios::fmtflags  flags;
+    int            width;
+    int            precision;
+    char           fill;
+
+  } data[] = {
+
+    { "0", "0",            ios::dec },
+    { "0", "+0",           ios::dec | ios::showpos },
+    { "0", "0.00000",      ios::dec | ios::showpoint },
+    { "0", "0",            ios::dec | ios::fixed },
+    { "0", "0.",           ios::dec | ios::fixed | ios::showpoint },
+    { "0", "0.000000e+00", ios::dec | ios::scientific },
+    { "0", "0.000000e+00", ios::dec | ios::scientific | ios::showpoint },
+
+    { "0", "0",          ios::dec, 0, 4 },
+    { "0", "0.000",      ios::dec | ios::showpoint, 0, 4 },
+    { "0", "0.0000",     ios::dec | ios::fixed, 0, 4 },
+    { "0", "0.0000",     ios::dec | ios::fixed | ios::showpoint, 0, 4 },
+    { "0", "0.0000e+00", ios::dec | ios::scientific, 0, 4 },
+    { "0", "0.0000e+00", ios::dec | ios::scientific | ios::showpoint, 0, 4 },
+
+    { "1", "1",       ios::dec },
+    { "1", "+1",      ios::dec | ios::showpos },
+    { "1", "1.00000", ios::dec | ios::showpoint },
+    { "1", "1",       ios::dec | ios::fixed },
+    { "1", "1.",      ios::dec | ios::fixed | ios::showpoint },
+    { "1", "1.000000e+00",   ios::dec | ios::scientific },
+    { "1", "1.000000e+00",  ios::dec | ios::scientific | ios::showpoint },
+
+    { "1", "1",          ios::dec,                   0, 4 },
+    { "1", "1.000",      ios::dec | ios::showpoint,  0, 4 },
+    { "1", "1.0000",     ios::dec | ios::fixed,      0, 4 },
+    { "1", "1.0000",     ios::dec | ios::fixed | ios::showpoint, 0, 4 },
+    { "1", "1.0000e+00", ios::dec | ios::scientific, 0, 4 },
+    { "1", "1.0000e+00", ios::dec | ios::scientific | ios::showpoint, 0, 4 },
+
+    { "-1", "-1",        ios::dec | ios::showpos },
+
+    { "-1", "  -1",      ios::dec, 4 },
+    { "-1", "-  1",      ios::dec | ios::internal, 4 },
+    { "-1", "-1  ",      ios::dec | ios::left, 4 },
+
+    { "-1", "  -0x1",    ios::hex | ios::showbase, 6 },
+    { "-1", "-0x  1",    ios::hex | ios::showbase | ios::internal, 6 },
+    { "-1", "-0x1  ",    ios::hex | ios::showbase | ios::left, 6 },
+
+    {    "1", "*********1", ios::dec, 10, 4, '*' },
+    { "1234", "******1234", ios::dec, 10, 4, '*' },
+    { "1234", "*****1234.", ios::dec | ios::showpoint, 10, 4, '*' },
+
+    { "12345", "1.23e+04", ios::dec, 0, 3 },
+
+    { "12345", "12345.", ios::dec | ios::fixed | ios::showpoint },
+
+    { "1.9999999",    "2",     ios::dec, 0, 1 },
+    { "1.0009999999", "1.001", ios::dec, 0, 4 },
+    { "1.0001",       "1",     ios::dec, 0, 4 },
+    { "1.0004",       "1",     ios::dec, 0, 4 },
+    { "1.000555",     "1.001", ios::dec, 0, 4 },
+
+    { "1.0002",       "1.000", ios::dec | ios::fixed, 0, 3 },
+    { "1.0008",       "1.001", ios::dec | ios::fixed, 0, 3 },
+
+    { "0", "0", ios::hex },
+    { "0", "0x0", ios::hex | ios::showbase },
+    { "0", "0X0", ios::hex | ios::showbase | ios::uppercase },
+    { "123",   "7b", ios::hex },
+    { "123", "0x7b", ios::hex | ios::showbase },
+    { "123", "0X7B", ios::hex | ios::showbase | ios::uppercase },
+
+    { "0", "0.000@+00", ios::hex | ios::scientific, 0, 3 },
+    { "256", "1.000@+02", ios::hex | ios::scientific, 0, 3 },
+
+    { "123",   "7.b@+01", ios::hex | ios::scientific, 0, 1 },
+    { "123",   "7.B@+01", ios::hex | ios::scientific | ios::uppercase, 0, 1 },
+    { "123", "0x7.b@+01", ios::hex | ios::scientific | ios::showbase, 0, 1 },
+    { "123", "0X7.B@+01",
+      ios::hex | ios::scientific | ios::showbase | ios::uppercase, 0, 1 },
+
+    { "1099511627776", "1.0@+10", ios::hex | ios::scientific, 0, 1 },
+    { "1099511627776", "1.0@+10",
+      ios::hex | ios::scientific | ios::uppercase, 0, 1 },
+
+    { "0.0625", "1.00@-01", ios::hex | ios::scientific, 0, 2 },
+
+    { "0", "0", ios::oct },
+    { "123",  "173", ios::oct },
+    { "123", "0173", ios::oct | ios::showbase },
+
+    // octal showbase suppressed for 0
+    { "0", "0", ios::oct | ios::showbase },
+    { ".125",    "00.1",  ios::oct | ios::showbase, 0, 1 },
+    { ".015625", "00.01", ios::oct | ios::showbase, 0, 2 },
+    { ".125",    "00.1",  ios::fixed | ios::oct | ios::showbase, 0, 1 },
+    { ".015625", "0.0",   ios::fixed | ios::oct | ios::showbase, 0, 1 },
+    { ".015625", "00.01", ios::fixed | ios::oct | ios::showbase, 0, 2 },
+
+    {  "0.125",  "1.000000e-01", ios::oct | ios::scientific },
+    {  "0.125", "+1.000000e-01", ios::oct | ios::scientific | ios::showpos },
+    { "-0.125", "-1.000000e-01", ios::oct | ios::scientific },
+    { "-0.125", "-1.000000e-01", ios::oct | ios::scientific | ios::showpos },
+
+    { "0", "0.000e+00", ios::oct | ios::scientific, 0, 3 },
+    { "256",  "4.000e+02", ios::oct | ios::scientific, 0, 3 },
+    { "256", "04.000e+02", ios::oct | ios::scientific | ios::showbase, 0, 3 },
+    { "256",  "4.000E+02", ios::oct | ios::scientific | ios::uppercase, 0, 3 },
+    { "256", "04.000E+02",
+      ios::oct | ios::scientific | ios::showbase | ios::uppercase, 0, 3 },
+
+    { "16777216",    "1.000000e+08", ios::oct | ios::scientific },
+    { "16777216",    "1.000000E+08",
+      ios::oct | ios::scientific | ios::uppercase },
+    { "16777216",   "01.000000e+08",
+      ios::oct | ios::scientific | ios::showbase },
+    { "16777216",   "01.000000E+08",
+      ios::oct | ios::scientific | ios::showbase | ios::uppercase },
+    { "16777216",  "+01.000000e+08",
+      ios::oct | ios::scientific | ios::showbase | ios::showpos },
+    { "16777216",  "+01.000000E+08", ios::oct | ios::scientific
+      | ios::showbase | ios::showpos | ios::uppercase },
+    { "-16777216", "-01.000000e+08",
+      ios::oct | ios::scientific | ios::showbase | ios::showpos },
+    { "-16777216", "-01.000000E+08", ios::oct | ios::scientific
+      | ios::showbase | ios::showpos | ios::uppercase },
+
+  };
+
+  size_t  i;
+  mpf_t   f, f2;
+  double  d;
+
+  mpf_init (f);
+  mpf_init (f2);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpf_set_str_or_abort (f, data[i].f, 0);
+
+      d = mpf_get_d (f);
+      mpf_set_d (f2, d);
+      if (option_check_standard && mpf_cmp (f, f2) == 0
+	  && ! (data[i].flags & (ios::hex | ios::oct | ios::showbase)))
+	{
+	  ostringstream  got;
+	  CALL (got << d);
+	  if (got.str().compare (data[i].want) != 0)
+	    {
+	      cout << "check_mpf data[" << i
+		   << "] doesn't match standard ostream output\n";
+	      cout << "  f:     " << data[i].f << "\n";
+	      cout << "  d:     " << d << "\n";
+	      DUMP ();
+	    }
+	}
+
+      {
+	ostringstream  got;
+	CALL (got << f);
+	if (got.str().compare (data[i].want) != 0)
+	  {
+	    cout << "mpf operator<< wrong, data[" << i << "]\n";
+	    cout << "  f:     " << data[i].f << "\n";
+	    ABORT ();
+	  }
+      }
+    }
+
+  mpf_clear (f);
+  mpf_clear (f2);
+}
+
+
+
+int
+main (int argc, char *argv[])
+{
+  if (argc > 1 && strcmp (argv[1], "-s") == 0)
+    option_check_standard = true;
+
+  tests_start ();
+
+  check_mpz ();
+  check_mpq ();
+  check_mpf ();
+
+  tests_end ();
+  return 0;
+}
diff --git a/third_party/gmp/tests/cxx/t-prec.cc b/third_party/gmp/tests/cxx/t-prec.cc
new file mode 100644
index 0000000..72fca72
--- /dev/null
+++ b/third_party/gmp/tests/cxx/t-prec.cc
@@ -0,0 +1,216 @@
+/* Test precision of mpf_class expressions.
+
+Copyright 2001-2003, 2008 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#include <iostream>
+
+#include "gmpxx.h"
+#include "gmp-impl.h"
+#include "tests.h"
+
+using namespace std;
+
+
+const int
+small_prec = 64, medium_prec = 128, large_prec = 192, very_large_prec = 256;
+
+#define ASSERT_ALWAYS_PREC(a, s, prec) \
+{                                      \
+  mpf_srcptr _a = a.get_mpf_t();       \
+  mpf_class _b(s, prec);               \
+  mpf_srcptr _c = _b.get_mpf_t();      \
+  ASSERT_ALWAYS(mpf_eq(_a, _c, prec)); \
+}
+
+
+
+void
+check_mpf (void)
+{
+  mpf_set_default_prec(medium_prec);
+
+  // simple expressions
+  {
+    mpf_class f(3.0, small_prec);
+    mpf_class g(1 / f, very_large_prec);
+    ASSERT_ALWAYS_PREC
+      (g, "0.33333 33333 33333 33333 33333 33333 33333 33333 33333 33333"
+       "     33333 33333 33333 33333 33333 333", very_large_prec);
+  }
+  {
+    mpf_class f(9.0, medium_prec);
+    mpf_class g(0.0, very_large_prec);
+    g = 1 / f;
+    ASSERT_ALWAYS_PREC
+      (g, "0.11111 11111 11111 11111 11111 11111 11111 11111 11111 11111"
+       "     11111 11111 11111 11111 11111 111", very_large_prec);
+  }
+  {
+    mpf_class f(15.0, large_prec);
+    mpf_class g(0.0, very_large_prec);
+    g = 1 / f;
+    ASSERT_ALWAYS_PREC
+      (g, "0.06666 66666 66666 66666 66666 66666 66666 66666 66666 66666"
+       "     66666 66666 66666 66666 66666 667", very_large_prec);
+  }
+
+  // compound expressions
+  {
+    mpf_class f(3.0, small_prec);
+    mpf_class g(-(-(-1 / f)), very_large_prec);
+    ASSERT_ALWAYS_PREC
+      (g, "-0.33333 33333 33333 33333 33333 33333 33333 33333 33333 33333"
+       "      33333 33333 33333 33333 33333 333", very_large_prec);
+  }
+  {
+    mpf_class f(3.0, small_prec), g(9.0, medium_prec);
+    mpf_class h(0.0, very_large_prec);
+    h = 1/f + 1/g;
+    ASSERT_ALWAYS_PREC
+      (h, "0.44444 44444 44444 44444 44444 44444 44444 44444 44444 44444"
+       "     44444 44444 44444 44444 44444 444", very_large_prec);
+  }
+  {
+    mpf_class f(3.0, small_prec), g(9.0, medium_prec), h(15.0, large_prec);
+    mpf_class i(0.0, very_large_prec);
+    i = f / g + h;
+    ASSERT_ALWAYS_PREC
+      (i, "15.33333 33333 33333 33333 33333 33333 33333 33333 33333 33333"
+       "      33333 33333 33333 33333 33333 3", very_large_prec);
+  }
+  {
+    mpf_class f(3.0, small_prec);
+    mpf_class g(-(1 + f) / 3, very_large_prec);
+    ASSERT_ALWAYS_PREC
+      (g, "-1.33333 33333 33333 33333 33333 33333 33333 33333 33333 33333"
+       "      33333 33333 33333 33333 33333 33", very_large_prec);
+  }
+  {
+    mpf_class f(9.0, medium_prec);
+    mpf_class g(0.0, very_large_prec);
+    g = sqrt(1 / f);
+    ASSERT_ALWAYS_PREC
+      (g, "0.33333 33333 33333 33333 33333 33333 33333 33333 33333 33333"
+       "     33333 33333 33333 33333 33333 333", very_large_prec);
+  }
+  {
+    mpf_class f(15.0, large_prec);
+    mpf_class g(0.0, very_large_prec);
+    g = hypot(1 + 5 / f, 1.0);
+    ASSERT_ALWAYS_PREC
+      (g, "1.66666 66666 66666 66666 66666 66666 66666 66666 66666 66666"
+       "     66666 66666 66666 66666 66666 67", very_large_prec);
+  }
+
+  // compound assignments
+  {
+    mpf_class f(3.0, small_prec), g(9.0, medium_prec);
+    mpf_class h(1.0, very_large_prec);
+    h -= f / g;
+    ASSERT_ALWAYS_PREC
+      (h, "0.66666 66666 66666 66666 66666 66666 66666 66666 66666 66666"
+       "     66666 66666 66666 66666 66666 667", very_large_prec);
+  }
+
+  // construction from expressions
+  {
+    mpf_class f(3.0, small_prec);
+    mpf_class g(0.0, very_large_prec);
+    g = mpf_class(1 / f);
+    ASSERT_ALWAYS_PREC(g, "0.33333 33333 33333 33333", small_prec);
+  }
+  {
+    mpf_class f(9.0, medium_prec);
+    mpf_class g(0.0, very_large_prec);
+    g = mpf_class(1 / f);
+    ASSERT_ALWAYS_PREC
+      (g, "0.11111 11111 11111 11111 11111 11111 11111 1111", medium_prec);
+  }
+  {
+    mpf_class f(15.0, large_prec);
+    mpf_class g(0.0, very_large_prec);
+    g = mpf_class(1 / f);
+    ASSERT_ALWAYS_PREC
+      (g, "0.06666 66666 66666 66666 66666 66666 66666 66666 66666 66666"
+       "     66666 6667", large_prec);
+  }
+
+  {
+    mpf_class f(3.0, small_prec), g(9.0, medium_prec);
+    mpf_class h(0.0, very_large_prec);
+    h = mpf_class(f / g + 1, large_prec);
+    ASSERT_ALWAYS_PREC
+      (h, "1.33333 33333 33333 33333 33333 33333 33333 33333 33333 33333"
+       "     33333 333",
+       large_prec);
+  }
+
+  // mixed mpf/mpq expressions
+  {
+    mpf_class f(3.0, small_prec);
+    mpq_class q(1, 3);
+    mpf_class g(0.0, very_large_prec);
+    g = f - q;
+    ASSERT_ALWAYS_PREC
+      (g, "2.66666 66666 66666 66666 66666 66666 66666 66666 66666 66666"
+       "     66666 66666 66666 66666 66666 67", very_large_prec);
+  }
+
+  {
+    mpf_class f(3.0, small_prec);
+    mpq_class q(1, 3);
+    mpf_class g(0.0, very_large_prec);
+    g = mpf_class(f - q, large_prec);
+    ASSERT_ALWAYS_PREC
+      (g, "2.66666 66666 66666 66666 66666 66666 66666 66666 66666 66666"
+       "     66666 667",
+       large_prec);
+  }
+  {
+    mpf_class f(3.0, small_prec);
+    mpq_class q(1, 3);
+    mpf_class g(0.0, very_large_prec);
+    g = mpf_class(f - q);
+    ASSERT_ALWAYS_PREC
+      (g, "2.66666 66666 66666 66666 66666 66666 66666 667", medium_prec);
+  }
+  {
+    mpf_class f(15.0, large_prec);
+    mpq_class q(1, 3);
+    mpf_class g(0.0, very_large_prec);
+    g = mpf_class(f + q);
+    ASSERT_ALWAYS_PREC
+      (g, "15.33333 33333 33333 33333 33333 33333 33333 33333 33333 33333"
+       "      33333 33",
+       large_prec);
+  }
+}
+
+
+int
+main (void)
+{
+  tests_start();
+
+  check_mpf();
+
+  tests_end();
+  return 0;
+}
diff --git a/third_party/gmp/tests/cxx/t-rand.cc b/third_party/gmp/tests/cxx/t-rand.cc
new file mode 100644
index 0000000..1f011eb
--- /dev/null
+++ b/third_party/gmp/tests/cxx/t-rand.cc
@@ -0,0 +1,148 @@
+/* Test gmp_randclass.
+
+Copyright 2002, 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "gmpxx.h"
+#include "gmp-impl.h"
+#include "tests.h"
+
+using namespace std;
+
+
+/* all flavours of initialization */
+void
+check_randinit (void)
+{
+  {
+    gmp_randclass r(gmp_randinit_default);
+  }
+
+  {
+    mpz_class a(0);
+    unsigned long c = 0, m2exp = 8;
+    gmp_randclass r(gmp_randinit_lc_2exp, a, c, m2exp);
+  }
+
+  {
+    unsigned long m2exp = 64;
+    gmp_randclass r(gmp_randinit_lc_2exp_size, m2exp);
+  }
+
+  /* gmp_randinit_lc_2exp_size, with excessive size */
+  {
+    try {
+      unsigned long m2exp = ULONG_MAX;
+      gmp_randclass r(gmp_randinit_lc_2exp_size, m2exp);
+      ASSERT_ALWAYS (0);  /* should not be reached */
+    } catch (length_error) {
+    }
+  }
+
+  {
+    gmp_randclass r(gmp_randinit_mt);
+  }
+
+  /* obsolete, but still available */
+  {
+    gmp_randalg_t alg = GMP_RAND_ALG_LC;
+    unsigned long m2exp = 64;
+    gmp_randclass r(alg, m2exp);
+  }
+  {
+    gmp_randalg_t alg = GMP_RAND_ALG_DEFAULT;
+    unsigned long m2exp = 64;
+    gmp_randclass r(alg, m2exp);
+  }
+  {
+    gmp_randalg_t alg = (gmp_randalg_t) 0;
+    unsigned long m2exp = 64;
+    gmp_randclass r(alg, m2exp);
+  }
+}
+
+void
+check_mpz (void)
+{
+  {
+    gmp_randclass r(gmp_randinit_default);
+    mpz_class a(123);
+    unsigned int b = 256;
+    mpz_class c;
+    r.seed(a);
+    c = r.get_z_bits(b);
+  }
+  {
+    gmp_randclass r(gmp_randinit_default);
+    mpz_class a(256);
+    unsigned long b = 123;
+    mpz_class c;
+    r.seed(b);
+    c = r.get_z_bits(a);
+  }
+  {
+    gmp_randclass r(gmp_randinit_default);
+    mpz_class a(123), b(256);
+    mpz_class c;
+    r.seed(a);
+    c = r.get_z_range(b);
+  }
+}
+
+void
+check_mpf (void)
+{
+  {
+    gmp_randclass r(gmp_randinit_default);
+    mpz_class a(123);
+    r.seed(a);
+    mpf_class b;
+    b = r.get_f();
+    mpf_class c(r.get_f());
+    ASSERT_ALWAYS (c.get_prec() == mpf_get_default_prec());
+    mpf_class d(r.get_f(),212);
+    ASSERT_ALWAYS (d.get_prec() >= 212);
+  }
+  {
+    gmp_randclass r(gmp_randinit_default);
+    int a = 123, b = 198;
+    r.seed(a);
+    mpf_class c;
+    c = r.get_f(b);
+    ASSERT_ALWAYS (c.get_prec() == mpf_get_default_prec());
+    mpf_class d(r.get_f(b));
+    ASSERT_ALWAYS (d.get_prec() >= 198);
+    mpf_class e(r.get_f(b)-r.get_f());
+    ASSERT_ALWAYS (e.get_prec() >= 198);
+    mpf_class f(r.get_f(60),300);
+    ASSERT_ALWAYS (f.get_prec() >= 300);
+  }
+}
+
+
+int
+main (void)
+{
+  tests_start();
+
+  check_randinit();
+  check_mpz();
+  check_mpf();
+
+  tests_end();
+  return 0;
+}
diff --git a/third_party/gmp/tests/cxx/t-ternary.cc b/third_party/gmp/tests/cxx/t-ternary.cc
new file mode 100644
index 0000000..8d087fb
--- /dev/null
+++ b/third_party/gmp/tests/cxx/t-ternary.cc
@@ -0,0 +1,734 @@
+/* Test mp*_class ternary expressions.
+
+Copyright 2001-2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#include <iostream>
+
+#include "gmpxx.h"
+#include "gmp-impl.h"
+#include "tests.h"
+
+using namespace std;
+
+
+/* The various test cases are broken up into separate functions to keep down
+   compiler memory use.  They're static so that any mistakenly omitted from
+   main() will provoke warnings (under gcc -Wall at least).  */
+
+static void
+check_mpz_1 (void)
+{
+  // template<class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<mpz_class, __gmp_expr
+  // <mpz_t, __gmp_binary_expr<mpz_class, mpz_class, Op1> >, Op2> >
+  {
+    mpz_class a(1), b(2), c(3);
+    mpz_class d;
+    d = a + b * c; ASSERT_ALWAYS(d == 7);
+  }
+  {
+    mpz_class a(1), b(2), c(3);
+    mpz_class d;
+    d = a - b * c; ASSERT_ALWAYS(d == -5);
+  }
+}
+
+static void
+check_mpz_2 (void)
+{
+  // template <class T, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<mpz_class, __gmp_expr
+  // <mpz_t, __gmp_binary_expr<mpz_class, T, Op1> >, Op2> >
+  {
+    mpz_class a(1), b(2);
+    signed int c = 3;
+    mpz_class d;
+    d = a + b * c; ASSERT_ALWAYS(d == 7);
+  }
+  {
+    mpz_class a(1), b(2);
+    signed int c = 3;
+    mpz_class d;
+    d = a - b * c; ASSERT_ALWAYS(d == -5);
+  }
+}
+
+static void
+check_mpz_3 (void)
+{
+  // template <class T, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<mpz_class, __gmp_expr
+  // <mpz_t, __gmp_binary_expr<T, mpz_class, Op1> >, Op2> >
+  {
+    mpz_class a(1), b(2);
+    unsigned int c = 3;
+    mpz_class d;
+    d = a + c * b; ASSERT_ALWAYS(d == 7);
+  }
+  {
+    mpz_class a(1), b(2);
+    unsigned int c = 3;
+    mpz_class d;
+    d = a - c * b; ASSERT_ALWAYS(d == -5);
+  }
+}
+
+static void
+check_mpz_4 (void)
+{
+  // template <class T, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<mpz_class, __gmp_expr
+  // <mpz_t, __gmp_binary_expr<mpz_class, __gmp_expr<mpz_t, T>, Op1> >, Op2> >
+  {
+    mpz_class a(1), b(2), c(3);
+    double d = 4.0;
+    mpz_class e;
+    e = a + b * (c + d); ASSERT_ALWAYS(e == 15);
+  }
+  {
+    mpz_class a(1), b(2), c(3);
+    double d = 4.0;
+    mpz_class e;
+    e = a - b * (c + d); ASSERT_ALWAYS(e == -13);
+  }
+}
+
+static void
+check_mpz_5 (void)
+{
+  // template <class T, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<mpz_class, __gmp_expr
+  // <mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, T>, mpz_class, Op1> >, Op2> >
+  {
+    mpz_class a(1), b(2), c(3);
+    signed int d = 4;
+    mpz_class e;
+    e = a + (b - d) * c; ASSERT_ALWAYS(e == -5);
+  }
+  {
+    mpz_class a(1), b(2), c(3);
+    signed int d = 4;
+    mpz_class e;
+    e = a - (b - d) * c; ASSERT_ALWAYS(e == 7);
+  }
+}
+
+static void
+check_mpz_6 (void)
+{
+  // template <class T, class U, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<mpz_class, __gmp_expr
+  // <mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, T>, U, Op1> >, Op2> >
+  {
+    mpz_class a(1), b(2);
+    unsigned int c = 3, d = 4;
+    mpz_class e;
+    e = a + (b + c) * d; ASSERT_ALWAYS(e == 21);
+  }
+  {
+    mpz_class a(1), b(2);
+    unsigned int c = 3, d = 4;
+    mpz_class e;
+    e = a - (b + c) * d; ASSERT_ALWAYS(e == -19);
+  }
+}
+
+static void
+check_mpz_7 (void)
+{
+  // template <class T, class U, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<mpz_class, __gmp_expr
+  // <mpz_t, __gmp_binary_expr<T, __gmp_expr<mpz_t, U>, Op1> >, Op2> >
+  {
+    mpz_class a(1), b(2);
+    double c = 3.0, d = 4.0;
+    mpz_class e;
+    e = a + c * (b + d); ASSERT_ALWAYS(e == 19);
+  }
+  {
+    mpz_class a(1), b(2);
+    double c = 3.0, d = 4.0;
+    mpz_class e;
+    e = a - c * (b + d); ASSERT_ALWAYS(e == -17);
+  }
+}
+
+static void
+check_mpz_8 (void)
+{
+  // template <class T, class U, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<mpz_class, __gmp_expr
+  // <mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, T>, __gmp_expr<mpz_t, U>,
+  // Op1> >, Op2> >
+  {
+    mpz_class a(1), b(2), c(3);
+    signed int d = 4, e = 5;
+    mpz_class f;
+    f = a + (b - d) * (c + e); ASSERT_ALWAYS(f == -15);
+  }
+  {
+    mpz_class a(1), b(2), c(3);
+    signed int d = 4, e = 5;
+    mpz_class f;
+    f = a - (b - d) * (c + e); ASSERT_ALWAYS(f == 17);
+  }
+}
+
+static void
+check_mpz_9 (void)
+{
+  // template <class T, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, T>,
+  // __gmp_expr<mpz_t, __gmp_binary_expr<mpz_class, mpz_class, Op1> >, Op2> >
+  {
+    mpz_class a(1), b(2), c(3);
+    unsigned int d = 4;
+    mpz_class e;
+    e = (a + d) + b * c; ASSERT_ALWAYS(e == 11);
+  }
+  {
+    mpz_class a(1), b(2), c(3);
+    unsigned int d = 4;
+    mpz_class e;
+    e = (a + d) - b * c; ASSERT_ALWAYS(e == -1);
+  }
+}
+
+static void
+check_mpz_10 (void)
+{
+  // template <class T, class U, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, T>,
+  // __gmp_expr<mpz_t, __gmp_binary_expr<mpz_class, U, Op1> >, Op2> >
+  {
+    mpz_class a(1), b(2);
+    double c = 3.0, d = 4.0;
+    mpz_class e;
+    e = (a - c) + b * d; ASSERT_ALWAYS(e == 6);
+  }
+  {
+    mpz_class a(1), b(2);
+    double c = 3.0, d = 4.0;
+    mpz_class e;
+    e = (a - c) - b * d; ASSERT_ALWAYS(e == -10);
+  }
+}
+
+static void
+check_mpz_11 (void)
+{
+  // template <class T, class U, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, T>,
+  // __gmp_expr<mpz_t, __gmp_binary_expr<U, mpz_class, Op1> >, Op2> >
+  {
+    mpz_class a(1), b(2);
+    signed int c = 3, d = 4;
+    mpz_class e;
+    e = (a - c) + d * b; ASSERT_ALWAYS(e == 6);
+  }
+  {
+    mpz_class a(1), b(2);
+    signed int c = 3, d = 4;
+    mpz_class e;
+    e = (a - c) - d * b; ASSERT_ALWAYS(e == -10);
+  }
+}
+
+static void
+check_mpz_12 (void)
+{
+  // template <class T, class U, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, T>, __gmp_expr
+  // <mpz_t, __gmp_binary_expr<mpz_class, __gmp_expr<mpz_t, U>, Op1> >, Op2> >
+  {
+    mpz_class a(1), b(2), c(3);
+    unsigned int d = 4, e = 5;
+    mpz_class f;
+    f = (a + d) + b * (c - e); ASSERT_ALWAYS(f == 1);
+  }
+  {
+    mpz_class a(1), b(2), c(3);
+    unsigned int d = 4, e = 5;
+    mpz_class f;
+    f = (a + d) - b * (c - e); ASSERT_ALWAYS(f == 9);
+  }
+}
+
+static void
+check_mpz_13 (void)
+{
+  // template <class T, class U, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, T>, __gmp_expr
+  // <mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, U>, mpz_class, Op1> >, Op2> >
+  {
+    mpz_class a(1), b(2), c(3);
+    double d = 4.0, e = 5.0;
+    mpz_class f;
+    f = (a - d) + (b + e) * c; ASSERT_ALWAYS(f == 18);
+  }
+  {
+    mpz_class a(1), b(2), c(3);
+    double d = 4.0, e = 5.0;
+    mpz_class f;
+    f = (a - d) - (b + e) * c; ASSERT_ALWAYS(f == -24);
+  }
+
+}
+
+static void
+check_mpz_14 (void)
+{
+  // template <class T, class U, class V, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, T>, __gmp_expr
+  // <mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, U>, V, Op1> >, Op2> >
+  {
+    mpz_class a(1), b(2);
+    signed int c = 3, d = 4, e = 5;
+    mpz_class f;
+    f = (a + c) + (b + d) * e; ASSERT_ALWAYS(f == 34);
+  }
+  {
+    mpz_class a(1), b(2);
+    signed int c = 3, d = 4, e = 5;
+    mpz_class f;
+    f = (a + c) - (b + d) * e; ASSERT_ALWAYS(f == -26);
+  }
+}
+
+static void
+check_mpz_15 (void)
+{
+  // template <class T, class U, class V, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, T>, __gmp_expr
+  // <mpz_t, __gmp_binary_expr<U, __gmp_expr<mpz_t, V>, Op1> >, Op2> >
+  {
+    mpz_class a(1), b(2);
+    unsigned int c = 3, d = 4, e = 5;
+    mpz_class f;
+    f = (a - c) + d * (b - e); ASSERT_ALWAYS(f == -14);
+  }
+  {
+    mpz_class a(1), b(2);
+    unsigned int c = 3, d = 4, e = 5;
+    mpz_class f;
+    f = (a - c) - d * (b - e); ASSERT_ALWAYS(f == 10);
+  }
+
+}
+
+static void
+check_mpz_16 (void)
+{
+  // template <class T, class U, class V, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, T>, __gmp_expr
+  // <mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, U>, __gmp_expr<mpz_t, V>,
+  // Op1> >, Op2> >
+  {
+    mpz_class a(1), b(2), c(3);
+    double d = 4.0, e = 5.0, f = 6.0;
+    mpz_class g;
+    g = (a + d) + (b - e) * (c + f); ASSERT_ALWAYS(g == -22);
+  }
+  {
+    mpz_class a(1), b(2), c(3);
+    double d = 4.0, e = 5.0, f = 6.0;
+    mpz_class g;
+    g = (a + d) - (b - e) * (c + f); ASSERT_ALWAYS(g == 32);
+  }
+}
+
+static void
+check_mpz_17 (void)
+{
+  // template <class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr
+  // <mpz_t, __gmp_binary_expr<mpz_class, mpz_class, Op1> >, mpz_class, Op2> >
+  {
+    mpz_class a(2), b(3), c(4);
+    mpz_class d;
+    d = a * b + c; ASSERT_ALWAYS(d == 10);
+  }
+  {
+    mpz_class a(2), b(3), c(4);
+    mpz_class d;
+    d = a * b - c; ASSERT_ALWAYS(d == 2);
+  }
+}
+
+static void
+check_mpz_18 (void)
+{
+  // template <class T, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr
+  // <mpz_t, __gmp_binary_expr<mpz_class, T, Op1> >, mpz_class, Op2> >
+  {
+    mpz_class a(2), b(3);
+    signed int c = 4;
+    mpz_class d;
+    d = a * c + b; ASSERT_ALWAYS(d == 11);
+  }
+  {
+    mpz_class a(2), b(3);
+    signed int c = 4;
+    mpz_class d;
+    d = a * c - b; ASSERT_ALWAYS(d == 5);
+  }
+
+}
+
+static void
+check_mpz_19 (void)
+{
+  // template <class T, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr
+  // <mpz_t, __gmp_binary_expr<T, mpz_class, Op1> >, mpz_class, Op2> >
+  {
+    mpz_class a(2), b(3);
+    unsigned int c = 4;
+    mpz_class d;
+    d = c * a + b; ASSERT_ALWAYS(d == 11);
+  }
+  {
+    mpz_class a(2), b(3);
+    unsigned int c = 4;
+    mpz_class d;
+    d = c * a - b; ASSERT_ALWAYS(d == 5);
+  }
+}
+
+static void
+check_mpz_20 (void)
+{
+  // template <class T, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, __gmp_binary_expr
+  // <mpz_class, __gmp_expr<mpz_t, T>, Op1> >, mpz_class, Op2> >
+  {
+    mpz_class a(2), b(3), c(4);
+    double d = 5.0;
+    mpz_class e;
+    e = a * (b + d) + c; ASSERT_ALWAYS(e == 20);
+  }
+  {
+    mpz_class a(2), b(3), c(4);
+    double d = 5.0;
+    mpz_class e;
+    e = a * (b + d) - c; ASSERT_ALWAYS(e == 12);
+  }
+}
+
+static void
+check_mpz_21 (void)
+{
+  // template <class T, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, __gmp_binary_expr
+  // <__gmp_expr<mpz_t, T>, mpz_class, Op1> >, mpz_class, Op2> >
+  {
+    mpz_class a(2), b(3), c(4);
+    signed int d = 5;
+    mpz_class e;
+    e = (a - d) * b + c; ASSERT_ALWAYS(e == -5);
+  }
+  {
+    mpz_class a(2), b(3), c(4);
+    signed int d = 5;
+    mpz_class e;
+    e = (a - d) * b - c; ASSERT_ALWAYS(e == -13);
+  }
+}
+
+static void
+check_mpz_22 (void)
+{
+  // template <class T, class U, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, __gmp_binary_expr
+  // <__gmp_expr<mpz_t, T>, U, Op1> >, mpz_class, Op2> >
+  {
+    mpz_class a(2), b(3);
+    unsigned int c = 4, d = 5;
+    mpz_class e;
+    e = (a + c) * d + b; ASSERT_ALWAYS(e == 33);
+  }
+  {
+    mpz_class a(2), b(3);
+    unsigned int c = 4, d = 5;
+    mpz_class e;
+    e = (a + c) * d - b; ASSERT_ALWAYS(e == 27);
+  }
+}
+
+static void
+check_mpz_23 (void)
+{
+  // template <class T, class U, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, __gmp_binary_expr
+  // <T, __gmp_expr<mpz_t, U>, Op1> >, mpz_class, Op2> >
+  {
+    mpz_class a(2), b(3);
+    double c = 4.0, d = 5.0;
+    mpz_class e;
+    e = c * (a + d) + b; ASSERT_ALWAYS(e == 31);
+  }
+  {
+    mpz_class a(2), b(3);
+    double c = 4.0, d = 5.0;
+    mpz_class e;
+    e = c * (a + d) - b; ASSERT_ALWAYS(e == 25);
+  }
+
+}
+
+static void
+check_mpz_24 (void)
+{
+  // template <class T, class U, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, __gmp_binary_expr
+  // <__gmp_expr<mpz_t, T>, __gmp_expr<mpz_t, U>, Op1> >, mpz_class, Op2> >
+  {
+    mpz_class a(2), b(3), c(4);
+    signed int d = 5, e = 6;
+    mpz_class f;
+    f = (a - d) * (b + e) + c; ASSERT_ALWAYS(f == -23);
+  }
+  {
+    mpz_class a(2), b(3), c(4);
+    signed int d = 5, e = 6;
+    mpz_class f;
+    f = (a - d) * (b + e) - c; ASSERT_ALWAYS(f == -31);
+  }
+}
+
+static void
+check_mpz_25 (void)
+{
+  // template <class T, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, __gmp_binary_expr
+  // <mpz_class, mpz_class, Op1> >, __gmp_expr<mpz_t, T>, Op2> >
+  {
+    mpz_class a(2), b(3), c(4);
+    unsigned int d = 5;
+    mpz_class e;
+    e = a * b + (c - d); ASSERT_ALWAYS(e == 5);
+  }
+  {
+    mpz_class a(2), b(3), c(4);
+    unsigned int d = 5;
+    mpz_class e;
+    e = a * b - (c - d); ASSERT_ALWAYS(e == 7);
+  }
+}
+
+static void
+check_mpz_26 (void)
+{
+  // template <class T, class U, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, __gmp_binary_expr
+  // <mpz_class, T, Op1> >, __gmp_expr<mpz_t, U>, Op2> >
+  {
+    mpz_class a(2), b(3);
+    double c = 4.0, d = 5.0;
+    mpz_class e;
+    e = a * c + (b + d); ASSERT_ALWAYS(e == 16);
+  }
+  {
+    mpz_class a(2), b(3);
+    double c = 4.0, d = 5.0;
+    mpz_class e;
+    e = a * c - (b + d); ASSERT_ALWAYS(e == 0);
+  }
+}
+
+static void
+check_mpz_27 (void)
+{
+  // template <class T, class U, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, __gmp_binary_expr
+  // <T, mpz_class, Op1> >, __gmp_expr<mpz_t, U>, Op2> >
+  {
+    mpz_class a(2), b(3);
+    signed int c = 4, d = 5;
+    mpz_class e;
+    e = c * a + (b - d); ASSERT_ALWAYS(e == 6);
+  }
+  {
+    mpz_class a(2), b(3);
+    signed int c = 4, d = 5;
+    mpz_class e;
+    e = c * a - (b - d); ASSERT_ALWAYS(e == 10);
+  }
+}
+
+static void
+check_mpz_28 (void)
+{
+  // template <class T, class U, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, __gmp_binary_expr
+  // <mpz_class, __gmp_expr<mpz_t, T>, Op1> >, __gmp_expr<mpz_t, U>, Op2> >
+  {
+    mpz_class a(2), b(3), c(4);
+    unsigned int d = 5, e = 6;
+    mpz_class f;
+    f = a * (b - d) + (c + e); ASSERT_ALWAYS(f == 6);
+  }
+  {
+    mpz_class a(2), b(3), c(4);
+    unsigned int d = 5, e = 6;
+    mpz_class f;
+    f = a * (b - d) - (c + e); ASSERT_ALWAYS(f == -14);
+  }
+}
+
+static void
+check_mpz_29 (void)
+{
+  // template <class T, class U, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, __gmp_binary_expr
+  // <__gmp_expr<mpz_t, T>, mpz_class, Op1> >, __gmp_expr<mpz_t, U>, Op2> >
+  {
+    mpz_class a(2), b(3), c(4);
+    double d = 5.0, e = 6.0;
+    mpz_class f;
+    f = (a + d) * b + (c - e); ASSERT_ALWAYS(f == 19);
+  }
+  {
+    mpz_class a(2), b(3), c(4);
+    double d = 5.0, e = 6.0;
+    mpz_class f;
+    f = (a + d) * b - (c - e); ASSERT_ALWAYS(f == 23);
+  }
+}
+
+static void
+check_mpz_30 (void)
+{
+  // template <class T, class U, class V, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, __gmp_binary_expr
+  // <__gmp_expr<mpz_t, T>, U, Op1> >, __gmp_expr<mpz_t, V>, Op2> >
+  {
+    mpz_class a(2), b(3);
+    signed int c = 4, d = 5, e = 6;
+    mpz_class f;
+    f = (a + c) * d + (b + e); ASSERT_ALWAYS(f == 39);
+  }
+  {
+    mpz_class a(2), b(3);
+    signed int c = 4, d = 5, e = 6;
+    mpz_class f;
+    f = (a + c) * d - (b + e); ASSERT_ALWAYS(f == 21);
+  }
+}
+
+static void
+check_mpz_31 (void)
+{
+  // template <class T, class U, class V, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, __gmp_binary_expr
+  // <T, __gmp_expr<mpz_t, U>, Op1> >, __gmp_expr<mpz_t, V>, Op2> >
+  {
+    mpz_class a(2), b(3);
+    unsigned int c = 4, d = 5, e = 6;
+    mpz_class f;
+    f = c * (a + d) + (b - e); ASSERT_ALWAYS(f == 25);
+  }
+  {
+    mpz_class a(2), b(3);
+    unsigned int c = 4, d = 5, e = 6;
+    mpz_class f;
+    f = c * (a + d) - (b - e); ASSERT_ALWAYS(f == 31);
+  }
+}
+
+static void
+check_mpz_32 (void)
+{
+  // template <class T, class U, class V, class Op1, class Op2>
+  // __gmp_expr<mpz_t, __gmp_binary_expr<__gmp_expr<mpz_t, __gmp_binary_expr
+  // <__gmp_expr<mpz_t, T>, __gmp_expr<mpz_t, U>, Op1> >,
+  // __gmp_expr<mpz_t, V>, Op2> >
+  {
+    mpz_class a(2), b(3), c(4);
+    double d = 5.0, e = 6.0, f = 7.0;
+    mpz_class g;
+    g = (a + d) * (b - e) + (c + f); ASSERT_ALWAYS(g == -10);
+  }
+  {
+    mpz_class a(2), b(3), c(4);
+    double d = 5.0, e = 6.0, f = 7.0;
+    mpz_class g;
+    g = (a + d) * (b - e) - (c + f); ASSERT_ALWAYS(g == -32);
+  }
+}
+
+void
+check_mpq (void)
+{
+  // currently there's no ternary mpq operation
+}
+
+void
+check_mpf (void)
+{
+  // currently there's no ternary mpf operation
+}
+
+
+int
+main (void)
+{
+  tests_start();
+
+  check_mpz_1 ();
+  check_mpz_2 ();
+  check_mpz_3 ();
+  check_mpz_4 ();
+  check_mpz_5 ();
+  check_mpz_6 ();
+  check_mpz_7 ();
+  check_mpz_8 ();
+  check_mpz_9 ();
+  check_mpz_10 ();
+  check_mpz_11 ();
+  check_mpz_12 ();
+  check_mpz_13 ();
+  check_mpz_14 ();
+  check_mpz_15 ();
+  check_mpz_16 ();
+  check_mpz_17 ();
+  check_mpz_18 ();
+  check_mpz_19 ();
+  check_mpz_20 ();
+  check_mpz_21 ();
+  check_mpz_22 ();
+  check_mpz_23 ();
+  check_mpz_24 ();
+  check_mpz_25 ();
+  check_mpz_26 ();
+  check_mpz_27 ();
+  check_mpz_28 ();
+  check_mpz_29 ();
+  check_mpz_30 ();
+  check_mpz_31 ();
+  check_mpz_32 ();
+
+  check_mpq();
+  check_mpf();
+
+  tests_end();
+  return 0;
+}
diff --git a/third_party/gmp/tests/cxx/t-unary.cc b/third_party/gmp/tests/cxx/t-unary.cc
new file mode 100644
index 0000000..c7d8bf6
--- /dev/null
+++ b/third_party/gmp/tests/cxx/t-unary.cc
@@ -0,0 +1,132 @@
+/* Test mp*_class unary expressions.
+
+Copyright 2001-2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#include <iostream>
+
+#include "gmpxx.h"
+#include "gmp-impl.h"
+#include "tests.h"
+
+using namespace std;
+
+
+void
+check_mpz (void)
+{
+  // template <class T, class Op>
+  // __gmp_expr<T, __gmp_unary_expr<__gmp_expr<T, T>, Op> >
+  {
+    mpz_class a(1);
+    mpz_class b(+a); ASSERT_ALWAYS(b == 1);
+  }
+  {
+    mpz_class a(2);
+    mpz_class b;
+    b = -a; ASSERT_ALWAYS(b == -2);
+  }
+  {
+    mpz_class a(3);
+    mpz_class b;
+    b = ~a; ASSERT_ALWAYS(b == -4);
+  }
+
+  // template <class T, class U, class Op>
+  // __gmp_expr<T, __gmp_unary_expr<__gmp_expr<T, U>, Op> >
+  {
+    mpz_class a(1);
+    mpz_class b(-(-a)); ASSERT_ALWAYS(b == 1);
+  }
+  {
+    mpz_class a(2);
+    mpz_class b;
+    b = -(-(-a)); ASSERT_ALWAYS(b == -2);
+  }
+}
+
+void
+check_mpq (void)
+{
+  // template <class T, class Op>
+  // __gmp_expr<T, __gmp_unary_expr<__gmp_expr<T, T>, Op> >
+  {
+    mpq_class a(1);
+    mpq_class b(+a); ASSERT_ALWAYS(b == 1);
+  }
+  {
+    mpq_class a(2);
+    mpq_class b;
+    b = -a; ASSERT_ALWAYS(b == -2);
+  }
+
+  // template <class T, class U, class Op>
+  // __gmp_expr<T, __gmp_unary_expr<__gmp_expr<T, U>, Op> >
+  {
+    mpq_class a(1);
+    mpq_class b(-(-a)); ASSERT_ALWAYS(b == 1);
+  }
+  {
+    mpq_class a(2);
+    mpq_class b;
+    b = -(-(-a)); ASSERT_ALWAYS(b == -2);
+  }
+}
+
+void
+check_mpf (void)
+{
+  // template <class T, class Op>
+  // __gmp_expr<T, __gmp_unary_expr<__gmp_expr<T, T>, Op> >
+  {
+    mpf_class a(1);
+    mpf_class b(+a); ASSERT_ALWAYS(b == 1);
+  }
+  {
+    mpf_class a(2);
+    mpf_class b;
+    b = -a; ASSERT_ALWAYS(b == -2);
+  }
+
+  // template <class T, class U, class Op>
+  // __gmp_expr<T, __gmp_unary_expr<__gmp_expr<T, U>, Op> >
+  {
+    mpf_class a(1);
+    mpf_class b(-(-a)); ASSERT_ALWAYS(b == 1);
+  }
+  {
+    mpf_class a(2);
+    mpf_class b;
+    b = -(-(-a)); ASSERT_ALWAYS(b == -2);
+  }
+}
+
+
+int
+main (void)
+{
+  tests_start();
+
+  check_mpz();
+  check_mpq();
+  check_mpf();
+
+  tests_end();
+  return 0;
+}
diff --git a/third_party/gmp/tests/devel/Makefile.am b/third_party/gmp/tests/devel/Makefile.am
new file mode 100644
index 0000000..6b384f0
--- /dev/null
+++ b/third_party/gmp/tests/devel/Makefile.am
@@ -0,0 +1,35 @@
+## Process this file with automake to generate Makefile.in
+
+# Copyright 2000-2002, 2018 Free Software Foundation, Inc.
+#
+# This file is part of the GNU MP Library test suite.
+#
+# The GNU MP Library test suite is free software; you can redistribute it
+# and/or modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 3 of the License,
+# or (at your option) any later version.
+#
+# The GNU MP Library test suite is distributed in the hope that it will be
+# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.
+
+
+AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/tests
+AM_LDFLAGS = -no-install
+LDADD = $(top_builddir)/tests/libtests.la $(top_builddir)/libgmp.la
+
+# add_n_sub_n add_n_sub_n_2 not yet built since mpn_add_n_sub_n doesn't yet exist
+#
+EXTRA_PROGRAMS = \
+  aors_n anymul_1 copy divmod_1 divrem shift logops_n sqrtrem_1_2 primes tst-addsub try addmul_N mul_N cnd_aors_n
+
+allprogs: $(EXTRA_PROGRAMS)
+
+CLEANFILES = $(EXTRA_PROGRAMS)
+
+$(top_builddir)/tests/libtests.la:
+	cd $(top_builddir)/tests; $(MAKE) $(AM_MAKEFLAGS) libtests.la
diff --git a/third_party/gmp/tests/devel/Makefile.in b/third_party/gmp/tests/devel/Makefile.in
new file mode 100644
index 0000000..796371d
--- /dev/null
+++ b/third_party/gmp/tests/devel/Makefile.in
@@ -0,0 +1,748 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Copyright 2000-2002, 2018 Free Software Foundation, Inc.
+#
+# This file is part of the GNU MP Library test suite.
+#
+# The GNU MP Library test suite is free software; you can redistribute it
+# and/or modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 3 of the License,
+# or (at your option) any later version.
+#
+# The GNU MP Library test suite is distributed in the hope that it will be
+# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+EXTRA_PROGRAMS = aors_n$(EXEEXT) anymul_1$(EXEEXT) copy$(EXEEXT) \
+	divmod_1$(EXEEXT) divrem$(EXEEXT) shift$(EXEEXT) \
+	logops_n$(EXEEXT) sqrtrem_1_2$(EXEEXT) primes$(EXEEXT) \
+	tst-addsub$(EXEEXT) try$(EXEEXT) addmul_N$(EXEEXT) \
+	mul_N$(EXEEXT) cnd_aors_n$(EXEEXT)
+subdir = tests/devel
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+addmul_N_SOURCES = addmul_N.c
+addmul_N_OBJECTS = addmul_N.$(OBJEXT)
+addmul_N_LDADD = $(LDADD)
+addmul_N_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+anymul_1_SOURCES = anymul_1.c
+anymul_1_OBJECTS = anymul_1.$(OBJEXT)
+anymul_1_LDADD = $(LDADD)
+anymul_1_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+aors_n_SOURCES = aors_n.c
+aors_n_OBJECTS = aors_n.$(OBJEXT)
+aors_n_LDADD = $(LDADD)
+aors_n_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+cnd_aors_n_SOURCES = cnd_aors_n.c
+cnd_aors_n_OBJECTS = cnd_aors_n.$(OBJEXT)
+cnd_aors_n_LDADD = $(LDADD)
+cnd_aors_n_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+copy_SOURCES = copy.c
+copy_OBJECTS = copy.$(OBJEXT)
+copy_LDADD = $(LDADD)
+copy_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+divmod_1_SOURCES = divmod_1.c
+divmod_1_OBJECTS = divmod_1.$(OBJEXT)
+divmod_1_LDADD = $(LDADD)
+divmod_1_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+divrem_SOURCES = divrem.c
+divrem_OBJECTS = divrem.$(OBJEXT)
+divrem_LDADD = $(LDADD)
+divrem_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+logops_n_SOURCES = logops_n.c
+logops_n_OBJECTS = logops_n.$(OBJEXT)
+logops_n_LDADD = $(LDADD)
+logops_n_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+mul_N_SOURCES = mul_N.c
+mul_N_OBJECTS = mul_N.$(OBJEXT)
+mul_N_LDADD = $(LDADD)
+mul_N_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+primes_SOURCES = primes.c
+primes_OBJECTS = primes.$(OBJEXT)
+primes_LDADD = $(LDADD)
+primes_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+shift_SOURCES = shift.c
+shift_OBJECTS = shift.$(OBJEXT)
+shift_LDADD = $(LDADD)
+shift_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+sqrtrem_1_2_SOURCES = sqrtrem_1_2.c
+sqrtrem_1_2_OBJECTS = sqrtrem_1_2.$(OBJEXT)
+sqrtrem_1_2_LDADD = $(LDADD)
+sqrtrem_1_2_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+try_SOURCES = try.c
+try_OBJECTS = try.$(OBJEXT)
+try_LDADD = $(LDADD)
+try_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+tst_addsub_SOURCES = tst-addsub.c
+tst_addsub_OBJECTS = tst-addsub.$(OBJEXT)
+tst_addsub_LDADD = $(LDADD)
+tst_addsub_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp =
+am__depfiles_maybe =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+SOURCES = addmul_N.c anymul_1.c aors_n.c cnd_aors_n.c copy.c \
+	divmod_1.c divrem.c logops_n.c mul_N.c primes.c shift.c \
+	sqrtrem_1_2.c try.c tst-addsub.c
+DIST_SOURCES = addmul_N.c anymul_1.c aors_n.c cnd_aors_n.c copy.c \
+	divmod_1.c divrem.c logops_n.c mul_N.c primes.c shift.c \
+	sqrtrem_1_2.c try.c tst-addsub.c
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in README
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ABI = @ABI@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+ASMFLAGS = @ASMFLAGS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CALLING_CONVENTIONS_OBJS = @CALLING_CONVENTIONS_OBJS@
+CC = @CC@
+CCAS = @CCAS@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPP_FOR_BUILD = @CPP_FOR_BUILD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFN_LONG_LONG_LIMB = @DEFN_LONG_LONG_LIMB@
+DEFS = @DEFS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@
+FGREP = @FGREP@
+GMP_LDFLAGS = @GMP_LDFLAGS@
+GMP_LIMB_BITS = @GMP_LIMB_BITS@
+GMP_NAIL_BITS = @GMP_NAIL_BITS@
+GREP = @GREP@
+HAVE_CLOCK_01 = @HAVE_CLOCK_01@
+HAVE_CPUTIME_01 = @HAVE_CPUTIME_01@
+HAVE_GETRUSAGE_01 = @HAVE_GETRUSAGE_01@
+HAVE_GETTIMEOFDAY_01 = @HAVE_GETTIMEOFDAY_01@
+HAVE_HOST_CPU_FAMILY_power = @HAVE_HOST_CPU_FAMILY_power@
+HAVE_HOST_CPU_FAMILY_powerpc = @HAVE_HOST_CPU_FAMILY_powerpc@
+HAVE_SIGACTION_01 = @HAVE_SIGACTION_01@
+HAVE_SIGALTSTACK_01 = @HAVE_SIGALTSTACK_01@
+HAVE_SIGSTACK_01 = @HAVE_SIGSTACK_01@
+HAVE_STACK_T_01 = @HAVE_STACK_T_01@
+HAVE_SYS_RESOURCE_H_01 = @HAVE_SYS_RESOURCE_H_01@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCURSES = @LIBCURSES@
+LIBGMPXX_LDFLAGS = @LIBGMPXX_LDFLAGS@
+LIBGMP_DLL = @LIBGMP_DLL@
+LIBGMP_LDFLAGS = @LIBGMP_LDFLAGS@
+LIBM = @LIBM@
+LIBM_FOR_BUILD = @LIBM_FOR_BUILD@
+LIBOBJS = @LIBOBJS@
+LIBREADLINE = @LIBREADLINE@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+M4 = @M4@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPEED_CYCLECOUNTER_OBJ = @SPEED_CYCLECOUNTER_OBJ@
+STRIP = @STRIP@
+TAL_OBJECT = @TAL_OBJECT@
+TUNE_LIBS = @TUNE_LIBS@
+TUNE_SQR_OBJ = @TUNE_SQR_OBJ@
+U_FOR_BUILD = @U_FOR_BUILD@
+VERSION = @VERSION@
+WITH_READLINE_01 = @WITH_READLINE_01@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__leading_dot = @am__leading_dot@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gmp_srclinks = @gmp_srclinks@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+mpn_objects = @mpn_objects@
+mpn_objs_in_libgmp = @mpn_objs_in_libgmp@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/tests
+AM_LDFLAGS = -no-install
+LDADD = $(top_builddir)/tests/libtests.la $(top_builddir)/libgmp.la
+CLEANFILES = $(EXTRA_PROGRAMS)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu --ignore-deps tests/devel/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu --ignore-deps tests/devel/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+addmul_N$(EXEEXT): $(addmul_N_OBJECTS) $(addmul_N_DEPENDENCIES) $(EXTRA_addmul_N_DEPENDENCIES) 
+	@rm -f addmul_N$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(addmul_N_OBJECTS) $(addmul_N_LDADD) $(LIBS)
+
+anymul_1$(EXEEXT): $(anymul_1_OBJECTS) $(anymul_1_DEPENDENCIES) $(EXTRA_anymul_1_DEPENDENCIES) 
+	@rm -f anymul_1$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(anymul_1_OBJECTS) $(anymul_1_LDADD) $(LIBS)
+
+aors_n$(EXEEXT): $(aors_n_OBJECTS) $(aors_n_DEPENDENCIES) $(EXTRA_aors_n_DEPENDENCIES) 
+	@rm -f aors_n$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(aors_n_OBJECTS) $(aors_n_LDADD) $(LIBS)
+
+cnd_aors_n$(EXEEXT): $(cnd_aors_n_OBJECTS) $(cnd_aors_n_DEPENDENCIES) $(EXTRA_cnd_aors_n_DEPENDENCIES) 
+	@rm -f cnd_aors_n$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(cnd_aors_n_OBJECTS) $(cnd_aors_n_LDADD) $(LIBS)
+
+copy$(EXEEXT): $(copy_OBJECTS) $(copy_DEPENDENCIES) $(EXTRA_copy_DEPENDENCIES) 
+	@rm -f copy$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(copy_OBJECTS) $(copy_LDADD) $(LIBS)
+
+divmod_1$(EXEEXT): $(divmod_1_OBJECTS) $(divmod_1_DEPENDENCIES) $(EXTRA_divmod_1_DEPENDENCIES) 
+	@rm -f divmod_1$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(divmod_1_OBJECTS) $(divmod_1_LDADD) $(LIBS)
+
+divrem$(EXEEXT): $(divrem_OBJECTS) $(divrem_DEPENDENCIES) $(EXTRA_divrem_DEPENDENCIES) 
+	@rm -f divrem$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(divrem_OBJECTS) $(divrem_LDADD) $(LIBS)
+
+logops_n$(EXEEXT): $(logops_n_OBJECTS) $(logops_n_DEPENDENCIES) $(EXTRA_logops_n_DEPENDENCIES) 
+	@rm -f logops_n$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(logops_n_OBJECTS) $(logops_n_LDADD) $(LIBS)
+
+mul_N$(EXEEXT): $(mul_N_OBJECTS) $(mul_N_DEPENDENCIES) $(EXTRA_mul_N_DEPENDENCIES) 
+	@rm -f mul_N$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(mul_N_OBJECTS) $(mul_N_LDADD) $(LIBS)
+
+primes$(EXEEXT): $(primes_OBJECTS) $(primes_DEPENDENCIES) $(EXTRA_primes_DEPENDENCIES) 
+	@rm -f primes$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(primes_OBJECTS) $(primes_LDADD) $(LIBS)
+
+shift$(EXEEXT): $(shift_OBJECTS) $(shift_DEPENDENCIES) $(EXTRA_shift_DEPENDENCIES) 
+	@rm -f shift$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(shift_OBJECTS) $(shift_LDADD) $(LIBS)
+
+sqrtrem_1_2$(EXEEXT): $(sqrtrem_1_2_OBJECTS) $(sqrtrem_1_2_DEPENDENCIES) $(EXTRA_sqrtrem_1_2_DEPENDENCIES) 
+	@rm -f sqrtrem_1_2$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(sqrtrem_1_2_OBJECTS) $(sqrtrem_1_2_LDADD) $(LIBS)
+
+try$(EXEEXT): $(try_OBJECTS) $(try_DEPENDENCIES) $(EXTRA_try_DEPENDENCIES) 
+	@rm -f try$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(try_OBJECTS) $(try_LDADD) $(LIBS)
+
+tst-addsub$(EXEEXT): $(tst_addsub_OBJECTS) $(tst_addsub_DEPENDENCIES) $(EXTRA_tst_addsub_DEPENDENCIES) 
+	@rm -f tst-addsub$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(tst_addsub_OBJECTS) $(tst_addsub_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+.c.o:
+	$(AM_V_CC)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+	$(AM_V_CC)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+	$(AM_V_CC)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+	-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+	clean-libtool cscopelist-am ctags ctags-am distclean \
+	distclean-compile distclean-generic distclean-libtool \
+	distclean-tags distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-ps install-ps-am \
+	install-strip installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+	pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+allprogs: $(EXTRA_PROGRAMS)
+
+$(top_builddir)/tests/libtests.la:
+	cd $(top_builddir)/tests; $(MAKE) $(AM_MAKEFLAGS) libtests.la
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/third_party/gmp/tests/devel/README b/third_party/gmp/tests/devel/README
new file mode 100644
index 0000000..77fa65d
--- /dev/null
+++ b/third_party/gmp/tests/devel/README
@@ -0,0 +1,37 @@
+Copyright 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.
+
+
+
+
+                       DEVELOPMENT TEST PROGRAMS
+
+
+This directory contains various programs used during development.  Casual
+GMP users are unlikely to find anything of interest.
+
+Nothing here is built or installed, nor even run in a "make check", but
+there's Makefile rules to build each program, or "allprogs" to build
+everything.
+
+
+
+----------------
+Local variables:
+mode: text
+fill-column: 76
+End:
diff --git a/third_party/gmp/tests/devel/addmul_N.c b/third_party/gmp/tests/devel/addmul_N.c
new file mode 100644
index 0000000..410e291
--- /dev/null
+++ b/third_party/gmp/tests/devel/addmul_N.c
@@ -0,0 +1,272 @@
+/*
+Copyright 1996-2002, 2004, 2007 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#if defined (USG) || defined (__SVR4) || defined (_UNICOS) || defined (__hpux)
+#include <time.h>
+
+int
+cputime ()
+{
+  if (CLOCKS_PER_SEC < 100000)
+    return clock () * 1000 / CLOCKS_PER_SEC;
+  return clock () / (CLOCKS_PER_SEC / 1000);
+}
+#else
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+int
+cputime ()
+{
+  struct rusage rus;
+
+  getrusage (0, &rus);
+  return rus.ru_utime.tv_sec * 1000 + rus.ru_utime.tv_usec / 1000;
+}
+#endif
+
+#ifndef NOCHECK
+static void print_posneg (mp_limb_t);
+#endif
+#ifdef PRINT
+static void mpn_print (mp_ptr, mp_size_t);
+#endif
+
+#define LXW ((int) (2 * sizeof (mp_limb_t)))
+#define M * 1000000
+
+#ifndef CLOCK
+#error "Don't know CLOCK of your machine"
+#endif
+
+#ifndef OPS
+#define OPS (CLOCK/5)
+#endif
+#ifndef SIZE
+#define SIZE 496
+#endif
+#ifndef TIMES
+#define TIMES OPS/(SIZE+1)
+#endif
+
+#if N == 2
+#define mpn_addmul_N mpn_addmul_2
+#elif N == 3
+#define mpn_addmul_N mpn_addmul_3
+#elif N == 4
+#define mpn_addmul_N mpn_addmul_4
+#elif N == 5
+#define mpn_addmul_N mpn_addmul_5
+#elif N == 6
+#define mpn_addmul_N mpn_addmul_6
+#elif N == 7
+#define mpn_addmul_N mpn_addmul_7
+#elif N == 8
+#define mpn_addmul_N mpn_addmul_8
+#endif
+
+mp_limb_t
+refmpn_addmul_N (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_srcptr vp)
+{
+  int i;
+  for (i = 1; i < N; i++)
+    {
+      rp[n] = mpn_addmul_1 (rp, up, n, *vp);
+      rp++;
+      vp++;
+    }
+  return mpn_addmul_1 (rp, up, n, *vp);
+}
+
+int
+main (int argc, char **argv)
+{
+  mp_limb_t up[SIZE];
+  mp_limb_t ref[SIZE + N - 1];
+  mp_limb_t mem[SIZE + N + 1];
+  mp_ptr rp = mem + 1;
+  mp_limb_t vp[N];
+  mp_limb_t cy_ref, cy_try;
+  int i;
+#if TIMES != 1
+  long t0, t;
+  double cyc;
+#endif
+  unsigned test;
+  mp_size_t size;
+  unsigned ntests;
+
+  ntests = ~(unsigned) 0;
+  if (argc == 2)
+    ntests = strtol (argv[1], 0, 0);
+
+  for (test = 1; test <= ntests; test++)
+    {
+#if TIMES == 1 && ! defined (PRINT)
+      if (test % (CLOCK / SIZE / 1000) == 0)
+	{
+	  printf ("\r%u", test);
+	  fflush (stdout);
+	}
+#endif
+
+#ifdef RANDOM
+      size = random () % (SIZE - N + 1) + N;
+#else
+      size = SIZE;
+#endif
+
+      rp[size + N - 1] = 0x12345678;
+      rp[-1] = 0x87654321;
+
+      mpn_random (vp, N);
+
+#if TIMES != 1			/* run timing tests unless asked not to */
+      mpn_random (up, size);
+      mpn_random (rp, size + N - 1);
+
+      MPN_COPY (ref, rp, size + N - 1);
+      t0 = cputime();
+      for (i = 0; i < TIMES; i++)
+	mpn_addmul_N (ref, up, size, vp);
+      t = cputime() - t0;
+      cyc = ((double) t * CLOCK) / (TIMES * size * 1000.0) / N;
+      printf ("mpn_addmul_%d:    %5ldms (%.3f cycles/limb) [%.2f Gb/s]\n",
+	      N, t, cyc, CLOCK/cyc*GMP_LIMB_BITS*GMP_LIMB_BITS/1e9);
+#endif
+
+#ifdef PLAIN_RANDOM
+#define MPN_RANDOM mpn_random
+#else
+#define MPN_RANDOM mpn_random2
+#endif
+
+#ifdef ZEROu
+      MPN_ZERO (up, size);
+#else
+      MPN_RANDOM (up, size);
+#endif
+      MPN_RANDOM (vp, N);
+#ifdef ZERO
+      MPN_ZERO (rp, size + N - 1);
+#else
+      MPN_RANDOM (rp, size + N - 1);
+#endif
+
+#if defined (PRINT) || defined (PRINTV)
+      printf ("vp=");
+      mpn_print (vp, N);
+#endif
+#ifdef PRINT
+      printf ("%*s ", 3 + N * LXW, "");
+      mpn_print (rp, size);
+      printf ("%*s ", 3 + N * LXW, "");
+      mpn_print (up, size);
+#endif
+
+      MPN_COPY (ref, rp, size + N - 1);
+      cy_ref = refmpn_addmul_N (ref, up, size, vp);
+      cy_try = mpn_addmul_N (rp, up, size, vp);
+
+#ifdef PRINT
+      printf ("%*lX ", LXW, cy_ref);
+      mpn_print (ref, size + N - 1);
+      printf ("%*lX ", LXW, cy_try);
+      mpn_print (rp, size + N - 1);
+#endif
+
+#ifndef NOCHECK
+      if (cy_ref != cy_try || mpn_cmp (ref, rp, size + N - 1) != 0
+	  || rp[size + N - 1] != 0x12345678 || rp[-1] != 0x87654321)
+	{
+	  printf ("\n        ref%*s try%*s diff\n", LXW - 3, "", 2 * LXW - 6, "");
+	  for (i = 0; i < size + N - 1; i++)
+	    {
+	      printf ("%6d: ", i);
+	      printf ("%0*llX ", LXW, (unsigned long long) ref[i]);
+	      printf ("%0*llX ", LXW, (unsigned long long) rp[i]);
+	      print_posneg (rp[i] - ref[i]);
+	      printf ("\n");
+	    }
+	  printf ("retval: ");
+	  printf ("%0*llX ", LXW, (unsigned long long) cy_ref);
+	  printf ("%0*llX ", LXW, (unsigned long long) cy_try);
+	  print_posneg (cy_try - cy_ref);
+	  printf ("\n");
+	  if (rp[-1] != 0x87654321)
+	    printf ("clobbered at low end\n");
+	  if (rp[size + N - 1] != 0x12345678)
+	    printf ("clobbered at high end\n");
+	  printf ("TEST NUMBER %u\n", test);
+	  abort();
+	}
+#endif
+    }
+  exit (0);
+}
+
+#ifndef NOCHECK
+static void
+print_posneg (mp_limb_t d)
+{
+  char buf[LXW + 2];
+  if (d == 0)
+    printf (" %*X", LXW, 0);
+  else if (-d < d)
+    {
+      sprintf (buf, "%llX", (unsigned long long) -d);
+      printf ("%*s-%s", LXW - (int) strlen (buf), "", buf);
+    }
+  else
+    {
+      sprintf (buf, "%llX", (unsigned long long) d);
+      printf ("%*s+%s", LXW - (int) strlen (buf), "", buf);
+    }
+}
+#endif
+
+#ifdef PRINT
+static void
+mpn_print (mp_ptr p, mp_size_t size)
+{
+  mp_size_t i;
+
+  for (i = size - 1; i >= 0; i--)
+    {
+#ifdef _LONG_LONG_LIMB
+      printf ("%0*lX%0*lX", (int) (sizeof(mp_limb_t)),
+	      (unsigned long) (p[i] >> (GMP_LIMB_BITS/2)),
+              (int) (sizeof(mp_limb_t)), (unsigned long) (p[i]));
+#else
+      printf ("%0*lX", LXW, p[i]);
+#endif
+#ifdef SPACE
+      if (i != 0)
+	printf (" ");
+#endif
+    }
+  puts ("");
+}
+#endif
diff --git a/third_party/gmp/tests/devel/anymul_1.c b/third_party/gmp/tests/devel/anymul_1.c
new file mode 100644
index 0000000..84f2781
--- /dev/null
+++ b/third_party/gmp/tests/devel/anymul_1.c
@@ -0,0 +1,255 @@
+/*
+Copyright 1996-2002, 2004, 2006-2008 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "gmp-impl.h"
+#include "longlong.h"
+#include "tests/tests.h"
+
+#ifdef OPERATION_mul_1
+#define func __gmpn_mul_1
+#define reffunc refmpn_mul_1
+#define funcname "mpn_mul_1"
+#endif
+
+#ifdef OPERATION_addmul_1
+#define func __gmpn_addmul_1
+#define reffunc refmpn_addmul_1
+#define funcname "mpn_addmul_1"
+#endif
+
+#ifdef OPERATION_submul_1
+#define func __gmpn_submul_1
+#define reffunc refmpn_submul_1
+#define funcname "mpn_submul_1"
+#endif
+
+#if defined (USG) || defined (__SVR4) || defined (_UNICOS) || defined (__hpux)
+#include <time.h>
+
+int
+cputime ()
+{
+  if (CLOCKS_PER_SEC < 100000)
+    return clock () * 1000 / CLOCKS_PER_SEC;
+  return clock () / (CLOCKS_PER_SEC / 1000);
+}
+#else
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+int
+cputime ()
+{
+  struct rusage rus;
+
+  getrusage (0, &rus);
+  return rus.ru_utime.tv_sec * 1000 + rus.ru_utime.tv_usec / 1000;
+}
+#endif
+
+static void print_posneg (mp_limb_t);
+static void mpn_print (mp_ptr, mp_size_t);
+
+#define LXW ((int) (2 * sizeof (mp_limb_t)))
+#define M * 1000000
+
+#ifndef CLOCK
+#error "Don't know CLOCK of your machine"
+#endif
+
+#ifndef OPS
+#define OPS (CLOCK/5)
+#endif
+#ifndef SIZE
+#define SIZE 496
+#endif
+#ifndef TIMES
+#define TIMES OPS/(SIZE+1)
+#endif
+
+int
+main (int argc, char **argv)
+{
+  mp_ptr s1, ref, rp;
+  mp_limb_t cy_ref, cy_try;
+  int i;
+  long t0, t;
+  unsigned int test;
+  mp_limb_t xlimb;
+  mp_size_t size;
+  double cyc;
+  unsigned int ntests;
+
+  s1 = malloc (SIZE * sizeof (mp_limb_t));
+  ref = malloc (SIZE * sizeof (mp_limb_t));
+  rp = malloc ((SIZE + 2) * sizeof (mp_limb_t));
+  rp++;
+
+  ntests = ~(unsigned) 0;
+  if (argc == 2)
+    ntests = strtol (argv[1], 0, 0);
+
+  for (test = 1; test <= ntests; test++)
+    {
+#if TIMES == 1 && ! defined (PRINT)
+      if (test % (1 + 0x80000 / (SIZE + 20)) == 0)
+	{
+	  printf ("\r%u", test);
+	  fflush (stdout);
+	}
+#endif
+
+#ifdef PLAIN_RANDOM
+#define MPN_RANDOM mpn_random
+#else
+#define MPN_RANDOM mpn_random2
+#endif
+
+#ifdef RANDOM
+      size = random () % SIZE + 1;
+#else
+      size = SIZE;
+#endif
+
+      rp[-1] = 0x87654321;
+      rp[size] = 0x12345678;
+
+#ifdef FIXED_XLIMB
+      xlimb = FIXED_XLIMB;
+#else
+      MPN_RANDOM (&xlimb, 1);
+#endif
+
+#if TIMES != 1
+      mpn_random (s1, size);
+      mpn_random (rp, size);
+
+      MPN_COPY (ref, rp, size);
+      t0 = cputime();
+      for (i = 0; i < TIMES; i++)
+	func (ref, s1, size, xlimb);
+      t = cputime() - t0;
+      cyc = ((double) t * CLOCK) / (TIMES * size * 1000.0);
+      printf (funcname ":    %5ldms (%.3f cycles/limb) [%.2f Gb/s]\n",
+	      t, cyc,
+	      CLOCK/cyc*GMP_LIMB_BITS*GMP_LIMB_BITS/1e9);
+#endif
+
+#ifndef NOCHECK
+      MPN_RANDOM (s1, size);
+#ifdef ZERO
+      memset (rp, 0, size * sizeof *rp);
+#else
+      MPN_RANDOM (rp, size);
+#endif
+#if defined (PRINT) || defined (XPRINT)
+      printf ("xlimb=");
+      mpn_print (&xlimb, 1);
+#endif
+#ifdef PRINT
+#ifndef OPERATION_mul_1
+      printf ("%*s ", (int) (2 * sizeof(mp_limb_t)), "");
+      mpn_print (rp, size);
+#endif
+      printf ("%*s ", (int) (2 * sizeof(mp_limb_t)), "");
+      mpn_print (s1, size);
+#endif
+
+      MPN_COPY (ref, rp, size);
+      cy_ref = reffunc (ref, s1, size, xlimb);
+      cy_try = func (rp, s1, size, xlimb);
+
+#ifdef PRINT
+      mpn_print (&cy_ref, 1);
+      mpn_print (ref, size);
+      mpn_print (&cy_try, 1);
+      mpn_print (rp, size);
+#endif
+
+      if (cy_ref != cy_try || mpn_cmp (ref, rp, size) != 0
+	  || rp[-1] != 0x87654321 || rp[size] != 0x12345678)
+	{
+	  printf ("\n        ref%*s try%*s diff\n", LXW - 3, "", 2 * LXW - 6, "");
+	  for (i = 0; i < size; i++)
+	    {
+	      printf ("%6d: ", i);
+	      printf ("%0*llX ", LXW, (unsigned long long) ref[i]);
+	      printf ("%0*llX ", LXW, (unsigned long long) rp[i]);
+	      print_posneg (rp[i] - ref[i]);
+	      printf ("\n");
+	    }
+	  printf ("retval: ");
+	  printf ("%0*llX ", LXW, (unsigned long long) cy_ref);
+	  printf ("%0*llX ", LXW, (unsigned long long) cy_try);
+	  print_posneg (cy_try - cy_ref);
+	  printf ("\n");
+	  if (rp[-1] != 0x87654321)
+	    printf ("clobbered at low end\n");
+	  if (rp[size] != 0x12345678)
+	    printf ("clobbered at high end\n");
+	  printf ("TEST NUMBER %u\n", test);
+	  abort();
+	}
+#endif
+    }
+  exit (0);
+}
+
+static void
+print_posneg (mp_limb_t d)
+{
+  char buf[LXW + 2];
+  if (d == 0)
+    printf (" %*X", LXW, 0);
+  else if (-d < d)
+    {
+      sprintf (buf, "%llX", (unsigned long long) -d);
+      printf ("%*s-%s", LXW - (int) strlen (buf), "", buf);
+    }
+  else
+    {
+      sprintf (buf, "%llX", (unsigned long long) d);
+      printf ("%*s+%s", LXW - (int) strlen (buf), "", buf);
+    }
+}
+
+static void
+mpn_print (mp_ptr p, mp_size_t size)
+{
+  mp_size_t i;
+
+  for (i = size - 1; i >= 0; i--)
+    {
+#ifdef _LONG_LONG_LIMB
+      printf ("%0*lX%0*lX", (int) (sizeof(mp_limb_t)),
+	      (unsigned long) (p[i] >> (GMP_LIMB_BITS/2)),
+              (int) (sizeof(mp_limb_t)), (unsigned long) (p[i]));
+#else
+      printf ("%0*lX", (int) (2 * sizeof(mp_limb_t)), p[i]);
+#endif
+#ifdef SPACE
+      if (i != 0)
+	printf (" ");
+#endif
+    }
+  puts ("");
+}
diff --git a/third_party/gmp/tests/devel/aors_n.c b/third_party/gmp/tests/devel/aors_n.c
new file mode 100644
index 0000000..d15cb58
--- /dev/null
+++ b/third_party/gmp/tests/devel/aors_n.c
@@ -0,0 +1,262 @@
+/*
+Copyright 1996-2004, 2009, 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+#ifdef OPERATION_add_n
+#define func __gmpn_add_n
+#define reffunc refmpn_add_n
+#define funcname "mpn_add_n"
+#endif
+
+#ifdef OPERATION_sub_n
+#define func __gmpn_sub_n
+#define reffunc refmpn_sub_n
+#define funcname "mpn_sub_n"
+#endif
+
+#ifdef OPERATION_addlsh1_n
+#define func __gmpn_addlsh1_n
+#define reffunc refmpn_addlsh1_n
+#define funcname "mpn_addlsh1_n"
+#endif
+
+#ifdef OPERATION_sublsh1_n
+#define func __gmpn_sublsh1_n
+#define reffunc refmpn_sublsh1_n
+#define funcname "mpn_sublsh1_n"
+#endif
+
+#ifdef OPERATION_rsh1add_n
+#define func __gmpn_rsh1add_n
+#define reffunc refmpn_rsh1add_n
+#define funcname "mpn_rsh1add_n"
+#endif
+
+#ifdef OPERATION_rsh1sub_n
+#define func __gmpn_rsh1sub_n
+#define reffunc refmpn_rsh1sub_n
+#define funcname "mpn_rsh1sub_n"
+#endif
+
+#if defined (USG) || defined (__SVR4) || defined (_UNICOS) || defined (__hpux)
+#include <time.h>
+
+int
+cputime ()
+{
+  if (CLOCKS_PER_SEC < 100000)
+    return clock () * 1000 / CLOCKS_PER_SEC;
+  return clock () / (CLOCKS_PER_SEC / 1000);
+}
+#else
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+int
+cputime ()
+{
+  struct rusage rus;
+
+  getrusage (0, &rus);
+  return rus.ru_utime.tv_sec * 1000 + rus.ru_utime.tv_usec / 1000;
+}
+#endif
+
+static void print_posneg (mp_limb_t);
+static void mpn_print (mp_ptr, mp_size_t);
+
+#define LXW ((int) (2 * sizeof (mp_limb_t)))
+#define M * 1000000
+
+#ifndef CLOCK
+#error "Don't know CLOCK of your machine"
+#endif
+
+#ifndef OPS
+#define OPS (CLOCK/5)
+#endif
+#ifndef SIZE
+#define SIZE 328
+#endif
+#ifndef TIMES
+#define TIMES OPS/(SIZE+1)
+#endif
+
+int
+main (int argc, char **argv)
+{
+  mp_ptr s1, s2, dx, dy;
+  mp_limb_t cyx, cyy;
+  int i;
+#if TIMES != 1
+  long t0, t;
+#endif
+  unsigned int test;
+  mp_size_t size;
+  unsigned int ntests;
+
+  s1 = malloc (SIZE * sizeof (mp_limb_t));
+  s2 = malloc (SIZE * sizeof (mp_limb_t));
+  dx = malloc ((SIZE + 2) * sizeof (mp_limb_t));
+  dy = malloc ((SIZE + 2) * sizeof (mp_limb_t));
+
+  ntests = ~(unsigned) 0;
+  if (argc == 2)
+    ntests = strtol (argv[1], 0, 0);
+
+  for (test = 1; test <= ntests; test++)
+    {
+#if TIMES == 1 && ! defined (PRINT)
+      if (test % (SIZE > 100000 ? 1 : 100000 / SIZE) == 0)
+	{
+	  printf ("\r%u", test);
+	  fflush (stdout);
+	}
+#endif
+
+#ifdef RANDOM
+      size = random () % SIZE + 1;
+#else
+      size = SIZE;
+#endif
+
+      dx[0] = 0x87654321;
+      dy[0] = 0x87654321;
+      dx[size+1] = 0x12345678;
+      dy[size+1] = 0x12345678;
+
+#if TIMES != 1
+      mpn_random (s1, size);
+      mpn_random (s2, size);
+
+      t0 = cputime();
+      for (i = 0; i < TIMES; i++)
+	func (dx+1, s1, s2, size);
+      t = cputime() - t0;
+      printf (funcname ":    %5ldms (%.3f cycles/limb)\n",
+	      t, ((double) t * CLOCK) / (TIMES * size * 1000.0));
+#endif
+
+#ifndef NOCHECK
+      mpn_random2 (s1, size);
+      mpn_random2 (s2, size);
+
+#ifdef PRINT
+      mpn_print (s1, size);
+      mpn_print (s2, size);
+#endif
+
+      /* Put garbage in the destination.  */
+      for (i = 0; i < size; i++)
+	{
+	  dx[i+1] = 0xdead;
+	  dy[i+1] = 0xbeef;
+	}
+
+      cyx = reffunc (dx+1, s1, s2, size);
+      cyy = func (dy+1, s1, s2, size);
+
+#ifdef PRINT
+      mpn_print (&cyx, 1);
+      mpn_print (dx+1, size);
+      mpn_print (&cyy, 1);
+      mpn_print (dy+1, size);
+#endif
+
+      if (cyx != cyy || mpn_cmp (dx, dy, size+2) != 0
+	  || dx[0] != 0x87654321 || dx[size+1] != 0x12345678)
+	{
+	  mp_size_t s, e;
+	  for (s = 0;; s++)
+	    if ((unsigned long long) (dx+1)[s] != (unsigned long long) (dy+1)[s])
+	      break;
+	  for (e = size - 1;; e--)
+	    if ((unsigned long long) (dx+1)[e] != (unsigned long long) (dy+1)[e])
+	      break;
+#ifndef PRINT
+	  for (i = s; i <= e; i++)
+	    {
+	      printf ("%6d: ", i);
+	      printf ("%0*llX ", LXW, (unsigned long long) (dx+1)[i]);
+	      printf ("%0*llX ", LXW, (unsigned long long) (dy+1)[i]);
+	      print_posneg ((dy+1)[i] - (dx+1)[i]);
+	      printf ("\n");
+	    }
+	  printf ("%6s: ", "retval");
+	  printf ("%0*llX ", LXW, (unsigned long long) cyx);
+	  printf ("%0*llX ", LXW, (unsigned long long) cyy);
+	  print_posneg (cyx - cyy);
+#endif
+	  printf ("\n");
+	  if (dy[0] != 0x87654321)
+	    printf ("clobbered at low end\n");
+	  if (dy[size+1] != 0x12345678)
+	    printf ("clobbered at high end\n");
+	  printf ("TEST NUMBER %u\n", test);
+	  abort();
+	}
+#endif
+    }
+  exit (0);
+}
+
+static void
+print_posneg (mp_limb_t d)
+{
+  char buf[LXW + 2];
+  if (d == 0)
+    printf (" %*X", LXW, 0);
+  else if (-d < d)
+    {
+      sprintf (buf, "%llX", (unsigned long long) -d);
+      printf ("%*s-%s", LXW - (int) strlen (buf), "", buf);
+    }
+  else
+    {
+      sprintf (buf, "%llX", (unsigned long long) d);
+      printf ("%*s+%s", LXW - (int) strlen (buf), "", buf);
+    }
+}
+
+static void
+mpn_print (mp_ptr p, mp_size_t size)
+{
+  mp_size_t i;
+
+  for (i = size - 1; i >= 0; i--)
+    {
+#ifdef _LONG_LONG_LIMB
+      printf ("%0*lX%0*lX", (int) (sizeof(mp_limb_t)),
+	      (unsigned long) (p[i] >> (GMP_LIMB_BITS/2)),
+	      (int) (sizeof(mp_limb_t)), (unsigned long) (p[i]));
+#else
+      printf ("%0*lX", (int) (2 * sizeof(mp_limb_t)), p[i]);
+#endif
+#ifdef SPACE
+      if (i != 0)
+	printf (" ");
+#endif
+    }
+  puts ("");
+}
diff --git a/third_party/gmp/tests/devel/cnd_aors_n.c b/third_party/gmp/tests/devel/cnd_aors_n.c
new file mode 100644
index 0000000..00d6db1
--- /dev/null
+++ b/third_party/gmp/tests/devel/cnd_aors_n.c
@@ -0,0 +1,257 @@
+/*
+Copyright 1996-2004, 2009, 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "gmp-impl.h"
+#include "tests/tests.h"
+
+#ifdef OPERATION_cnd_add_n
+#define func __gmpn_cnd_add_n
+#define reffunc refmpn_cnd_add_n
+#define funcname "mpn_cnd_add_n"
+#endif
+
+#ifdef OPERATION_cnd_sub_n
+#define func __gmpn_cnd_sub_n
+#define reffunc refmpn_cnd_sub_n
+#define funcname "mpn_cnd_sub_n"
+#endif
+
+#if defined (USG) || defined (__SVR4) || defined (_UNICOS) || defined (__hpux)
+#include <time.h>
+
+int
+cputime ()
+{
+  if (CLOCKS_PER_SEC < 100000)
+    return clock () * 1000 / CLOCKS_PER_SEC;
+  return clock () / (CLOCKS_PER_SEC / 1000);
+}
+#else
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+int
+cputime ()
+{
+  struct rusage rus;
+
+  getrusage (0, &rus);
+  return rus.ru_utime.tv_sec * 1000 + rus.ru_utime.tv_usec / 1000;
+}
+#endif
+
+static void print_posneg (mp_limb_t);
+static void mpn_print (mp_ptr, mp_size_t);
+
+#define LXW ((int) (2 * sizeof (mp_limb_t)))
+#define M * 1000000
+
+#ifndef CLOCK
+#error "Don't know CLOCK of your machine"
+#endif
+
+#ifndef OPS
+#define OPS (CLOCK/5)
+#endif
+#ifndef SIZE
+#define SIZE 328
+#endif
+#ifndef TIMES
+#define TIMES OPS/(SIZE+1)
+#endif
+
+int
+main (int argc, char **argv)
+{
+  mp_ptr s1, s2, dx, dy;
+  mp_limb_t cyx, cyy;
+  int i;
+#if TIMES != 1
+  long t0, t;
+#endif
+  unsigned int test;
+  mp_size_t size;
+  unsigned int ntests;
+
+  s1 = malloc ((SIZE + 2) * sizeof (mp_limb_t));
+  s2 = malloc ((SIZE + 2) * sizeof (mp_limb_t));
+  dx = malloc ((SIZE + 2) * sizeof (mp_limb_t));
+  dy = malloc ((SIZE + 2) * sizeof (mp_limb_t));
+
+  s1 += 1;
+  s2 += 1;
+
+  ntests = ~(unsigned) 0;
+  if (argc == 2)
+    ntests = strtol (argv[1], 0, 0);
+
+  for (test = 1; test <= ntests; test++)
+    {
+#if TIMES == 1 && ! defined (PRINT)
+      if (test % (SIZE > 100000 ? 1 : 100000 / SIZE) == 0)
+	{
+	  printf ("\r%u", test);
+	  fflush (stdout);
+	}
+#endif
+
+#ifdef PLAIN_RANDOM
+#define MPN_RANDOM mpn_random
+#else
+#define MPN_RANDOM mpn_random2
+#endif
+
+#ifdef RANDOM
+      size = random () % SIZE + 1;
+#else
+      size = SIZE;
+#endif
+
+      dx[0] = 0x87654321;
+      dy[0] = 0x87654321;
+      dx[size+1] = 0x12345678;
+      dy[size+1] = 0x12345678;
+
+#if TIMES != 1
+      mpn_random (s1 - 1, size + 2);
+      mpn_random (s2 - 1, size + 2);
+
+      t0 = cputime();
+      for (i = 0; i < TIMES; i++)
+	func (i & 1, dx+1, s1, s2, size);
+      t = cputime() - t0;
+      printf (funcname ":    %5ldms (%.3f cycles/limb)\n",
+	      t, ((double) t * CLOCK) / (TIMES * size * 1000.0));
+#endif
+
+#ifndef NOCHECK
+#ifndef ZEROup
+      MPN_RANDOM (s1 - 1, size + 2);
+#else
+      MPN_ZERO (s1, size);
+#endif
+#ifndef ZEROvp
+      MPN_RANDOM (s2 - 1, size + 2);
+#else
+      MPN_ZERO (s2, size);
+#endif
+
+#ifdef PRINT
+      mpn_print (s1, size);
+      mpn_print (s2, size);
+#endif
+
+      /* Put garbage in the destination.  */
+      for (i = 0; i < size; i++)
+	{
+	  dx[i+1] = 0xdead;
+	  dy[i+1] = 0xbeef;
+	}
+
+      int cond = random() & 1;
+
+      cyx = reffunc (cond, dx+1, s1, s2, size);
+      cyy = func (cond, dy+1, s1, s2, size);
+
+#ifdef PRINT
+      mpn_print (&cyx, 1);
+      mpn_print (dx+1, size);
+      mpn_print (&cyy, 1);
+      mpn_print (dy+1, size);
+#endif
+
+      if (cyx != cyy || mpn_cmp (dx, dy, size+2) != 0
+	  || dx[0] != 0x87654321 || dx[size+1] != 0x12345678)
+	{
+	  mp_size_t s, e;
+	  for (s = 0;; s++)
+	    if ((unsigned long long) (dx+1)[s] != (unsigned long long) (dy+1)[s])
+	      break;
+	  for (e = size - 1;; e--)
+	    if ((unsigned long long) (dx+1)[e] != (unsigned long long) (dy+1)[e])
+	      break;
+#ifndef PRINT
+	  for (i = s; i <= e; i++)
+	    {
+	      printf ("%6d: ", i);
+	      printf ("%0*llX ", LXW, (unsigned long long) (dx+1)[i]);
+	      printf ("%0*llX ", LXW, (unsigned long long) (dy+1)[i]);
+	      print_posneg ((dy+1)[i] - (dx+1)[i]);
+	      printf ("\n");
+	    }
+	  printf ("%6s: ", "retval");
+	  printf ("%0*llX ", LXW, (unsigned long long) cyx);
+	  printf ("%0*llX ", LXW, (unsigned long long) cyy);
+	  print_posneg (cyx - cyy);
+#endif
+	  printf ("\n");
+	  if (dy[0] != 0x87654321)
+	    printf ("clobbered at low end\n");
+	  if (dy[size+1] != 0x12345678)
+	    printf ("clobbered at high end\n");
+	  printf ("TEST NUMBER %u\n", test);
+	  abort();
+	}
+#endif
+    }
+  exit (0);
+}
+
+static void
+print_posneg (mp_limb_t d)
+{
+  char buf[LXW + 2];
+  if (d == 0)
+    printf (" %*X", LXW, 0);
+  else if (-d < d)
+    {
+      sprintf (buf, "%llX", (unsigned long long) -d);
+      printf ("%*s-%s", LXW - (int) strlen (buf), "", buf);
+    }
+  else
+    {
+      sprintf (buf, "%llX", (unsigned long long) d);
+      printf ("%*s+%s", LXW - (int) strlen (buf), "", buf);
+    }
+}
+
+static void
+mpn_print (mp_ptr p, mp_size_t size)
+{
+  mp_size_t i;
+
+  for (i = size - 1; i >= 0; i--)
+    {
+#ifdef _LONG_LONG_LIMB
+      printf ("%0*lX%0*lX", (int) (sizeof(mp_limb_t)),
+	      (unsigned long) (p[i] >> (GMP_LIMB_BITS/2)),
+	      (int) (sizeof(mp_limb_t)), (unsigned long) (p[i]));
+#else
+      printf ("%0*lX", (int) (2 * sizeof(mp_limb_t)), p[i]);
+#endif
+#ifdef SPACE
+      if (i != 0)
+	printf (" ");
+#endif
+    }
+  puts ("");
+}
diff --git a/third_party/gmp/tests/devel/copy.c b/third_party/gmp/tests/devel/copy.c
new file mode 100644
index 0000000..65dbd9b
--- /dev/null
+++ b/third_party/gmp/tests/devel/copy.c
@@ -0,0 +1,225 @@
+/*
+Copyright 1999-2001, 2004, 2009, 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+#ifdef OPERATION_copyi
+#define func MPN_COPY_INCR
+#define reffunc refmpn_copyi
+#define funcname "MPN_COPY_INCR"
+#endif
+
+#ifdef OPERATION_copyd
+#define func MPN_COPY_DECR
+#define reffunc refmpn_copyd
+#define funcname "MPN_COPY_DECR"
+#endif
+
+#if defined (USG) || defined (__SVR4) || defined (_UNICOS) || defined (__hpux)
+#include <time.h>
+
+int
+cputime ()
+{
+  if (CLOCKS_PER_SEC < 100000)
+    return clock () * 1000 / CLOCKS_PER_SEC;
+  return clock () / (CLOCKS_PER_SEC / 1000);
+}
+#else
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+int
+cputime ()
+{
+  struct rusage rus;
+
+  getrusage (0, &rus);
+  return rus.ru_utime.tv_sec * 1000 + rus.ru_utime.tv_usec / 1000;
+}
+#endif
+
+static void print_posneg (mp_limb_t);
+static void mpn_print (mp_ptr, mp_size_t);
+
+#define LXW ((int) (2 * sizeof (mp_limb_t)))
+#define M * 1000000
+
+#ifndef CLOCK
+#error "Don't know CLOCK of your machine"
+#endif
+
+#ifndef OPS
+#define OPS (CLOCK/5)
+#endif
+#ifndef SIZE
+#define SIZE 496
+#endif
+#ifndef TIMES
+#define TIMES OPS/(SIZE+1)
+#endif
+
+int
+main (int argc, char **argv)
+{
+  mp_ptr s1, dx, dy;
+  int i;
+  long t0, t;
+  unsigned int test;
+  mp_size_t size;
+  unsigned int ntests;
+
+  s1 = malloc (SIZE * sizeof (mp_limb_t));
+  dx = malloc ((SIZE + 2) * sizeof (mp_limb_t));
+  dy = malloc ((SIZE + 2) * sizeof (mp_limb_t));
+
+  ntests = ~(unsigned) 0;
+  if (argc == 2)
+    ntests = strtol (argv[1], 0, 0);
+
+  for (test = 1; test <= ntests; test++)
+    {
+#if TIMES == 1 && ! defined (PRINT)
+      if (test % (SIZE > 100000 ? 1 : 100000 / SIZE) == 0)
+	{
+	  printf ("\r%u", test);
+	  fflush (stdout);
+	}
+#endif
+
+#ifdef RANDOM
+      size = random () % SIZE + 1;
+#else
+      size = SIZE;
+#endif
+
+      dx[0] = 0x87654321;
+      dy[0] = 0x87654321;
+      dx[size+1] = 0x12345678;
+      dy[size+1] = 0x12345678;
+
+#if TIMES != 1
+      mpn_random (s1, size);
+
+      t0 = cputime();
+      for (i = 0; i < TIMES; i++)
+	func (dx+1, s1, size);
+      t = cputime() - t0;
+      printf (funcname ":    %5ldms (%.3f cycles/limb)\n",
+	      t, ((double) t * CLOCK) / (TIMES * size * 1000.0));
+#endif
+
+#ifndef NOCHECK
+      mpn_random2 (s1, size);
+
+#ifdef PRINT
+      mpn_print (s1, size);
+#endif
+
+      /* Put garbage in the destination.  */
+      for (i = 0; i < size; i++)
+	{
+	  dx[i+1] = 0xdead;
+	  dy[i+1] = 0xbeef;
+	}
+
+      reffunc (dx+1, s1, size);
+      func (dy+1, s1, size);
+
+#ifdef PRINT
+      mpn_print (dx+1, size);
+      mpn_print (dy+1, size);
+#endif
+
+      if (mpn_cmp (dx, dy, size+2) != 0
+	  || dx[0] != 0x87654321 || dx[size+1] != 0x12345678)
+	{
+	  mp_size_t s, e;
+	  for (s = 0;; s++)
+	    if ((unsigned long long) (dx+1)[s] != (unsigned long long) (dy+1)[s])
+	      break;
+	  for (e = size - 1;; e--)
+	    if ((unsigned long long) (dx+1)[e] != (unsigned long long) (dy+1)[e])
+	      break;
+#ifndef PRINT
+	  for (i = s; i <= e; i++)
+	    {
+	      printf ("%6d: ", i);
+	      printf ("%0*llX ", LXW, (unsigned long long) (dx+1)[i]);
+	      printf ("%0*llX ", LXW, (unsigned long long) (dy+1)[i]);
+	      print_posneg ((dy+1)[i] - (dx+1)[i]);
+	      printf ("\n");
+	    }
+#endif
+	  printf ("\n");
+	  if (dy[0] != 0x87654321)
+	    printf ("clobbered at low end\n");
+	  if (dy[size+1] != 0x12345678)
+	    printf ("clobbered at high end\n");
+	  printf ("TEST NUMBER %u\n", test);
+	  abort();
+	}
+#endif
+    }
+  exit (0);
+}
+
+static void
+print_posneg (mp_limb_t d)
+{
+  char buf[LXW + 2];
+  if (d == 0)
+    printf (" %*X", LXW, 0);
+  else if (-d < d)
+    {
+      sprintf (buf, "%llX", (unsigned long long) -d);
+      printf ("%*s-%s", LXW - (int) strlen (buf), "", buf);
+    }
+  else
+    {
+      sprintf (buf, "%llX", (unsigned long long) d);
+      printf ("%*s+%s", LXW - (int) strlen (buf), "", buf);
+    }
+}
+
+static void
+mpn_print (mp_ptr p, mp_size_t size)
+{
+  mp_size_t i;
+
+  for (i = size - 1; i >= 0; i--)
+    {
+#ifdef _LONG_LONG_LIMB
+      printf ("%0*lX%0*lX", (int) (sizeof(mp_limb_t)),
+	      (unsigned long) (p[i] >> (GMP_LIMB_BITS/2)),
+	      (int) (sizeof(mp_limb_t)), (unsigned long) (p[i]));
+#else
+      printf ("%0*lX", (int) (2 * sizeof(mp_limb_t)), p[i]);
+#endif
+#ifdef SPACE
+      if (i != 0)
+	printf (" ");
+#endif
+    }
+  puts ("");
+}
diff --git a/third_party/gmp/tests/devel/divmod_1.c b/third_party/gmp/tests/devel/divmod_1.c
new file mode 100644
index 0000000..2757375
--- /dev/null
+++ b/third_party/gmp/tests/devel/divmod_1.c
@@ -0,0 +1,199 @@
+/*
+Copyright 1996, 1998, 2000, 2001, 2007 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+#if defined (USG) || defined (__SVR4) || defined (_UNICOS) || defined (__hpux)
+#include <time.h>
+
+int
+cputime ()
+{
+  if (CLOCKS_PER_SEC < 100000)
+    return clock () * 1000 / CLOCKS_PER_SEC;
+  return clock () / (CLOCKS_PER_SEC / 1000);
+}
+#else
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+int
+cputime ()
+{
+  struct rusage rus;
+
+  getrusage (0, &rus);
+  return rus.ru_utime.tv_sec * 1000 + rus.ru_utime.tv_usec / 1000;
+}
+#endif
+
+static void mpn_print (mp_ptr, mp_size_t);
+
+#define M * 1000000
+
+#ifndef CLOCK
+#error "Don't know CLOCK of your machine"
+#endif
+
+#ifndef OPS
+#define OPS 20000000
+#endif
+#ifndef SIZE
+#define SIZE 1000
+#endif
+#ifndef TIMES
+#define TIMES OPS/SIZE
+#endif
+
+#ifndef FSIZE
+#define FSIZE SIZE
+#endif
+
+int
+main ()
+{
+  mp_limb_t np[SIZE];
+  mp_limb_t dx[SIZE + FSIZE + 2];
+  mp_limb_t dy[SIZE + FSIZE + 2];
+  mp_limb_t dlimb;
+  mp_size_t nn, fn;
+  mp_limb_t retx, rety;
+  int test;
+#if TIMES != 1
+  int i;
+  long t0, t;
+  double cyc;
+#endif
+
+  for (test = 0; ; test++)
+    {
+#if TIMES == 1 && ! defined (PRINT)
+      if (test % (SIZE > 100000 ? 1 : 100000 / SIZE) == 0)
+	{
+	  printf ("\r%u", test);
+	  fflush (stdout);
+	}
+#endif
+
+#ifdef RANDOM
+      nn = random () % (SIZE + 1);
+      fn = random () % (FSIZE + 1);
+#else
+      nn = SIZE;
+      fn = FSIZE;
+#endif
+
+      dx[0] = 0x87654321;
+      dx[nn + fn + 1] = 0x12345678;
+      dy[0] = 0x87654321;
+      dy[nn + fn + 1] = 0x12345678;
+      mpn_random2 (np, nn);
+
+#ifdef FIXED_DLIMB
+      dlimb = FIXED_DLIMB;
+#else
+      do
+	{
+	  mpn_random2 (&dlimb, 1);
+#ifdef FORCE_NORM
+	  dlimb |= GMP_NUMB_HIGHBIT;
+#endif
+#ifdef FORCE_UNNORM
+	  dlimb &= GMP_NUMB_MAX >> 1;
+#endif
+	}
+      while (dlimb == 0);
+#endif
+
+#if defined (PRINT) || defined (XPRINT)
+      printf ("N=");
+      mpn_print (np, nn);
+      printf ("D=");
+      mpn_print (&dlimb, 1);
+      printf ("nn=%ld\n", (long) nn);
+#endif
+
+#if TIMES != 1
+      t0 = cputime();
+      for (i = 0; i < TIMES; i++)
+	mpn_divrem_1 (dx + 1, 0L, np, nn, dlimb);
+      t = cputime() - t0;
+      cyc = ((double) t * CLOCK) / (TIMES * nn * 1000.0);
+      printf ("mpn_divrem_1 int:    %5ldms (%.3f cycles/limb) [%.2f Gb/s]\n",
+	      t, cyc,
+	      CLOCK/cyc*GMP_LIMB_BITS*GMP_LIMB_BITS/1e9);
+      t0 = cputime();
+      for (i = 0; i < TIMES; i++)
+	mpn_divrem_1 (dx + 1, fn, np, 0, dlimb);
+      t = cputime() - t0;
+      cyc = ((double) t * CLOCK) / (TIMES * fn * 1000.0);
+      printf ("mpn_divrem_1 frac:   %5ldms (%.3f cycles/limb) [%.2f Gb/s]\n",
+	      t, cyc,
+	      CLOCK/cyc*GMP_LIMB_BITS*GMP_LIMB_BITS/1e9);
+#endif
+
+      retx = refmpn_divrem_1 (dx + 1, fn, np, nn, dlimb);
+      rety = mpn_divrem_1 (dy + 1, fn, np, nn, dlimb);
+
+#ifndef NOCHECK
+      if (retx != rety || mpn_cmp (dx, dy, fn + nn + 2) != 0)
+	{
+	  printf ("ERROR in test %d, nn=%ld, fn=%ld\n", test, nn, fn);
+	  mpn_print (np, nn);
+	  mpn_print (&dlimb, 1);
+	  printf ("rq: ");
+	  mpn_print (dx + 1, nn + fn);
+	  printf ("rr: %*lX\n", (int) (2 * sizeof(mp_limb_t)), retx);
+	  printf (" q: ");
+	  mpn_print (dy + 1, nn + fn);
+	  printf (" r: %*lX\n", (int) (2 * sizeof(mp_limb_t)), rety);
+	  if (dy[0] != 0x87654321)
+	    printf ("clobbered at low end %*lX\n", (int) (2 * sizeof(mp_limb_t)), dy[0]);
+	  if (dy[nn + fn + 1] != 0x12345678)
+	    printf ("clobbered at high end\n");
+	  abort ();
+	}
+#endif
+    }
+}
+
+static void
+mpn_print (mp_ptr p, mp_size_t size)
+{
+  mp_size_t i;
+
+  for (i = size - 1; i >= 0; i--)
+    {
+#ifdef _LONG_LONG_LIMB
+      printf ("%0*lX%0*lX", (int) (sizeof(mp_limb_t)),
+	      (unsigned long) (p[i] >> (GMP_LIMB_BITS/2)),
+              (int) (sizeof(mp_limb_t)), (unsigned long) (p[i]));
+#else
+      printf ("%0*lX", (int) (2 * sizeof(mp_limb_t)), p[i]);
+#endif
+#ifdef SPACE
+      if (i != 0)
+	printf (" ");
+#endif
+    }
+  puts ("");
+}
diff --git a/third_party/gmp/tests/devel/divrem.c b/third_party/gmp/tests/devel/divrem.c
new file mode 100644
index 0000000..e6c38c6
--- /dev/null
+++ b/third_party/gmp/tests/devel/divrem.c
@@ -0,0 +1,118 @@
+/*
+Copyright 1996-1998, 2000, 2001, 2007, 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+
+#if defined (USG) || defined (__SVR4) || defined (_UNICOS) || defined (__hpux)
+#include <time.h>
+
+int
+cputime ()
+{
+  if (CLOCKS_PER_SEC < 100000)
+    return clock () * 1000 / CLOCKS_PER_SEC;
+  return clock () / (CLOCKS_PER_SEC / 1000);
+}
+#else
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+int
+cputime ()
+{
+  struct rusage rus;
+
+  getrusage (0, &rus);
+  return rus.ru_utime.tv_sec * 1000 + rus.ru_utime.tv_usec / 1000;
+}
+#endif
+
+#define M * 1000000
+
+#ifndef CLOCK
+#error "Don't know CLOCK of your machine"
+#endif
+
+#ifndef OPS
+#define OPS 20000000
+#endif
+#ifndef SIZE
+#define SIZE 100
+#endif
+#ifndef TIMES
+#define TIMES OPS/(SIZE+1)
+#endif
+
+int
+main ()
+{
+  mp_limb_t nptr[2 * SIZE];
+  mp_limb_t dptr[2 * SIZE];
+  mp_limb_t qptr[2 * SIZE];
+  mp_limb_t pptr[2 * SIZE + 1];
+  mp_limb_t rptr[2 * SIZE];
+  mp_size_t nsize, dsize, qsize, rsize, psize;
+  int test;
+  mp_limb_t qlimb;
+
+  for (test = 0; ; test++)
+    {
+      printf ("%d\n", test);
+#ifdef RANDOM
+      nsize = random () % (2 * SIZE) + 1;
+      dsize = random () % nsize + 1;
+#else
+      nsize = 2 * SIZE;
+      dsize = SIZE;
+#endif
+
+      mpn_random2 (nptr, nsize);
+      mpn_random2 (dptr, dsize);
+      dptr[dsize - 1] |= (mp_limb_t) 1 << (GMP_LIMB_BITS - 1);
+
+      MPN_COPY (rptr, nptr, nsize);
+      qlimb = mpn_divrem (qptr, (mp_size_t) 0, rptr, nsize, dptr, dsize);
+      rsize = dsize;
+      qsize = nsize - dsize;
+      qptr[qsize] = qlimb;
+      qsize += qlimb;
+      if (qsize == 0 || qsize > 2 * SIZE)
+	{
+	  continue;		/* bogus */
+	}
+      else
+	{
+	  mp_limb_t cy;
+	  if (qsize > dsize)
+	    mpn_mul (pptr, qptr, qsize, dptr, dsize);
+	  else
+	    mpn_mul (pptr, dptr, dsize, qptr, qsize);
+	  psize = qsize + dsize;
+	  psize -= pptr[psize - 1] == 0;
+	  cy = mpn_add (pptr, pptr, psize, rptr, rsize);
+	  pptr[psize] = cy;
+	  psize += cy;
+	}
+
+      if (nsize != psize || mpn_cmp (nptr, pptr, nsize) != 0)
+	abort ();
+    }
+}
diff --git a/third_party/gmp/tests/devel/logops_n.c b/third_party/gmp/tests/devel/logops_n.c
new file mode 100644
index 0000000..349c637
--- /dev/null
+++ b/third_party/gmp/tests/devel/logops_n.c
@@ -0,0 +1,229 @@
+/*
+Copyright 1996-2004, 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+#ifdef OPERATION_and_n
+#define func __gmpn_and_n
+#define reffunc refmpn_and_n
+#define funcname "mpn_and_n"
+#endif
+
+#ifdef OPERATION_andn_n
+#define func __gmpn_andn_n
+#define reffunc refmpn_andn_n
+#define funcname "mpn_andn_n"
+#endif
+
+#ifdef OPERATION_nand_n
+#define func __gmpn_nand_n
+#define reffunc refmpn_nand_n
+#define funcname "mpn_nand_n"
+#endif
+
+#ifdef OPERATION_ior_n
+#define func __gmpn_ior_n
+#define reffunc refmpn_ior_n
+#define funcname "mpn_ior_n"
+#endif
+
+#ifdef OPERATION_iorn_n
+#define func __gmpn_iorn_n
+#define reffunc refmpn_iorn_n
+#define funcname "mpn_iorn_n"
+#endif
+
+#ifdef OPERATION_nior_n
+#define func __gmpn_nior_n
+#define reffunc refmpn_nior_n
+#define funcname "mpn_nior_n"
+#endif
+
+#ifdef OPERATION_xor_n
+#define func __gmpn_xor_n
+#define reffunc refmpn_xor_n
+#define funcname "mpn_xor_n"
+#endif
+
+#ifdef OPERATION_xnor_n
+#define func __gmpn_xnor_n
+#define reffunc refmpn_xnor_n
+#define funcname "mpn_xnor_n"
+#endif
+
+#if defined (USG) || defined (__SVR4) || defined (_UNICOS) || defined (__hpux)
+#include <time.h>
+
+int
+cputime ()
+{
+  if (CLOCKS_PER_SEC < 100000)
+    return clock () * 1000 / CLOCKS_PER_SEC;
+  return clock () / (CLOCKS_PER_SEC / 1000);
+}
+#else
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+int
+cputime ()
+{
+  struct rusage rus;
+
+  getrusage (0, &rus);
+  return rus.ru_utime.tv_sec * 1000 + rus.ru_utime.tv_usec / 1000;
+}
+#endif
+
+static void mpn_print (mp_ptr, mp_size_t);
+
+#define M * 1000000
+
+#ifndef CLOCK
+#error "Don't know CLOCK of your machine"
+#endif
+
+#ifndef OPS
+#define OPS (CLOCK/5)
+#endif
+#ifndef SIZE
+#define SIZE 328
+#endif
+#ifndef TIMES
+#define TIMES OPS/(SIZE+1)
+#endif
+
+int
+main (int argc, char **argv)
+{
+  mp_ptr s1, s2, dx, dy;
+  int i;
+  long t0, t;
+  unsigned int test;
+  mp_size_t size;
+  unsigned int ntests;
+
+  s1 = malloc (SIZE * sizeof (mp_limb_t));
+  s2 = malloc (SIZE * sizeof (mp_limb_t));
+  dx = malloc ((SIZE + 2) * sizeof (mp_limb_t));
+  dy = malloc ((SIZE + 2) * sizeof (mp_limb_t));
+
+  ntests = ~(unsigned) 0;
+  if (argc == 2)
+    ntests = strtol (argv[1], 0, 0);
+
+  for (test = 1; test <= ntests; test++)
+    {
+#if TIMES == 1 && ! defined (PRINT)
+      if (test % (SIZE > 100000 ? 1 : 100000 / SIZE) == 0)
+	{
+	  printf ("\r%d", test);
+	  fflush (stdout);
+	}
+#endif
+
+#ifdef RANDOM
+      size = random () % SIZE + 1;
+#else
+      size = SIZE;
+#endif
+
+      dx[0] = 0x87654321;
+      dy[0] = 0x87654321;
+      dx[size+1] = 0x12345678;
+      dy[size+1] = 0x12345678;
+
+#if TIMES != 1
+      mpn_random (s1, size);
+      mpn_random (s2, size);
+
+      t0 = cputime();
+      for (i = 0; i < TIMES; i++)
+	func (dx+1, s1, s2, size);
+      t = cputime() - t0;
+      printf (funcname ":    %5ldms (%.3f cycles/limb)\n",
+	      t, ((double) t * CLOCK) / (TIMES * size * 1000.0));
+#endif
+
+#ifndef NOCHECK
+      mpn_random2 (s1, size);
+      mpn_random2 (s2, size);
+
+#ifdef PRINT
+      mpn_print (s1, size);
+      mpn_print (s2, size);
+#endif
+
+      /* Put garbage in the destination.  */
+      for (i = 0; i < size; i++)
+	{
+	  dx[i+1] = 0xdead;
+	  dy[i+1] = 0xbeef;
+	}
+
+      reffunc (dx+1, s1, s2, size);
+      func (dy+1, s1, s2, size);
+#ifdef PRINT
+      mpn_print (dx+1, size);
+      mpn_print (dy+1, size);
+#endif
+      if (mpn_cmp (dx, dy, size+2) != 0
+	  || dx[0] != 0x87654321 || dx[size+1] != 0x12345678)
+	{
+#ifndef PRINT
+	  mpn_print (dx+1, size);
+	  mpn_print (dy+1, size);
+#endif
+	  printf ("\n");
+	  if (dy[0] != 0x87654321)
+	    printf ("clobbered at low end\n");
+	  if (dy[size+1] != 0x12345678)
+	    printf ("clobbered at high end\n");
+	  printf ("TEST NUMBER %u\n", test);
+	  abort();
+	}
+#endif
+    }
+  exit (0);
+}
+
+static void
+mpn_print (mp_ptr p, mp_size_t size)
+{
+  mp_size_t i;
+
+  for (i = size - 1; i >= 0; i--)
+    {
+#ifdef _LONG_LONG_LIMB
+      printf ("%0*lX%0*lX", (int) (sizeof(mp_limb_t)),
+	      (unsigned long) (p[i] >> (GMP_LIMB_BITS/2)),
+              (int) (sizeof(mp_limb_t)), (unsigned long) (p[i]));
+#else
+      printf ("%0*lX", (int) (2 * sizeof(mp_limb_t)), p[i]);
+#endif
+#ifdef SPACE
+      if (i != 0)
+	printf (" ");
+#endif
+    }
+  puts ("");
+}
diff --git a/third_party/gmp/tests/devel/mul_N.c b/third_party/gmp/tests/devel/mul_N.c
new file mode 100644
index 0000000..c9de5ec
--- /dev/null
+++ b/third_party/gmp/tests/devel/mul_N.c
@@ -0,0 +1,270 @@
+/*
+Copyright 1996-2002, 2004, 2007 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#if defined (USG) || defined (__SVR4) || defined (_UNICOS) || defined (__hpux)
+#include <time.h>
+
+int
+cputime ()
+{
+  if (CLOCKS_PER_SEC < 100000)
+    return clock () * 1000 / CLOCKS_PER_SEC;
+  return clock () / (CLOCKS_PER_SEC / 1000);
+}
+#else
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+int
+cputime ()
+{
+  struct rusage rus;
+
+  getrusage (0, &rus);
+  return rus.ru_utime.tv_sec * 1000 + rus.ru_utime.tv_usec / 1000;
+}
+#endif
+
+#ifndef NOCHECK
+static void print_posneg (mp_limb_t);
+#endif
+#ifdef PRINT
+static void mpn_print (mp_ptr, mp_size_t);
+#endif
+
+#define LXW ((int) (2 * sizeof (mp_limb_t)))
+#define M * 1000000
+
+#ifndef CLOCK
+#error "Don't know CLOCK of your machine"
+#endif
+
+#ifndef OPS
+#define OPS (CLOCK/5)
+#endif
+#ifndef SIZE
+#define SIZE 496
+#endif
+#ifndef TIMES
+#define TIMES OPS/(SIZE+1)
+#endif
+
+#if N == 2
+#define mpn_mul_N mpn_mul_2
+#elif N == 3
+#define mpn_mul_N mpn_mul_3
+#elif N == 4
+#define mpn_mul_N mpn_mul_4
+#elif N == 5
+#define mpn_mul_N mpn_mul_5
+#elif N == 6
+#define mpn_mul_N mpn_mul_6
+#elif N == 7
+#define mpn_mul_N mpn_mul_7
+#elif N == 8
+#define mpn_mul_N mpn_mul_8
+#endif
+
+mp_limb_t
+refmpn_mul_N (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_srcptr vp)
+{
+  int i;
+  rp[n] = mpn_mul_1 (rp, up, n, *vp);
+  rp++;
+  vp++;
+  for (i = 2; i < N; i++)
+    {
+      rp[n] = mpn_addmul_1 (rp, up, n, *vp);
+      rp++;
+      vp++;
+    }
+  return mpn_addmul_1 (rp, up, n, *vp);
+}
+
+int
+main (int argc, char **argv)
+{
+  mp_limb_t up[SIZE];
+  mp_limb_t ref[SIZE + N - 1];
+  mp_limb_t mem[SIZE + N + 1];
+  mp_ptr rp = mem + 1;
+  mp_limb_t vp[N];
+  mp_limb_t cy_ref, cy_try;
+  int i;
+#if TIMES != 1
+  long t0, t;
+  double cyc;
+#endif
+  unsigned test;
+  mp_size_t size;
+  unsigned ntests;
+
+  ntests = ~(unsigned) 0;
+  if (argc == 2)
+    ntests = strtol (argv[1], 0, 0);
+
+  for (test = 1; test <= ntests; test++)
+    {
+#if TIMES == 1 && ! defined (PRINT)
+      if (test % (CLOCK / SIZE / 1000) == 0)
+	{
+	  printf ("\r%u", test);
+	  fflush (stdout);
+	}
+#endif
+
+#ifdef RANDOM
+      size = random () % (SIZE - N + 1) + N;
+#else
+      size = SIZE;
+#endif
+
+      rp[size + N - 1] = 0x12345678;
+      rp[-1] = 0x87654321;
+
+      mpn_random (vp, N);
+
+#if TIMES != 1			/* run timing tests unless asked not to */
+      mpn_random (up, size);
+
+      MPN_COPY (ref, rp, size + N - 1);
+      t0 = cputime();
+      for (i = 0; i < TIMES; i++)
+	mpn_mul_N (ref, up, size, vp);
+      t = cputime() - t0;
+      cyc = ((double) t * CLOCK) / (TIMES * size * 1000.0) / N;
+      printf ("mpn_mul_%d:    %5ldms (%.3f cycles/limb) [%.2f Gb/s]\n",
+	      N, t, cyc, CLOCK/cyc*GMP_LIMB_BITS*GMP_LIMB_BITS/1e9);
+#endif
+
+#ifdef PLAIN_RANDOM
+#define MPN_RANDOM mpn_random
+#else
+#define MPN_RANDOM mpn_random2
+#endif
+
+#ifdef ZEROu
+      MPN_ZERO (up, size);
+#else
+      MPN_RANDOM (up, size);
+#endif
+      MPN_RANDOM (vp, N);
+      /* vp[0] = vp[1] = vp[2] = vp[3] = vp[4] =  vp[5] = 0; */
+      MPN_RANDOM (rp, size + N - 1);
+
+#if defined (PRINT) || defined (PRINTV)
+      printf ("vp=");
+      mpn_print (vp, N);
+#endif
+#ifdef PRINT
+      printf ("%*s ", 3 + N * LXW, "");
+      mpn_print (up, size);
+#endif
+
+      MPN_COPY (ref, rp, size + N - 1);
+      cy_ref = refmpn_mul_N (ref, up, size, vp);
+      cy_try = mpn_mul_N (rp, up, size, vp);
+
+#ifdef PRINT
+      printf ("%*lX ", LXW, cy_ref);
+      mpn_print (ref, size + N - 1);
+      printf ("%*lX ", LXW, cy_try);
+      mpn_print (rp, size + N - 1);
+#endif
+
+#ifndef NOCHECK
+      if (cy_ref != cy_try || mpn_cmp (ref, rp, size + N - 1) != 0
+//      if (cy_ref != cy_try || mpn_cmp (ref + 5, rp + 5, size + N - 1 - 6) != 0
+	  || rp[size + N - 1] != 0x12345678 || rp[-1] != 0x87654321)
+	{
+	  printf ("\n        ref%*s try%*s diff\n", LXW - 3, "", 2 * LXW - 6, "");
+	  for (i = 0; i < size + N - 1; i++)
+	    {
+	      printf ("%6d: ", i);
+	      printf ("%0*llX ", LXW, (unsigned long long) ref[i]);
+	      printf ("%0*llX ", LXW, (unsigned long long) rp[i]);
+	      print_posneg (rp[i] - ref[i]);
+	      printf ("\n");
+	    }
+	  printf ("retval: ");
+	  printf ("%0*llX ", LXW, (unsigned long long) cy_ref);
+	  printf ("%0*llX ", LXW, (unsigned long long) cy_try);
+	  print_posneg (cy_try - cy_ref);
+	  printf ("\n");
+	  if (rp[-1] != 0x87654321)
+	    printf ("clobbered at low end\n");
+	  if (rp[size + N - 1] != 0x12345678)
+	    printf ("clobbered at high end\n");
+	  printf ("TEST NUMBER %u\n", test);
+	  abort();
+	}
+#endif
+    }
+  exit (0);
+}
+
+#ifndef NOCHECK
+static void
+print_posneg (mp_limb_t d)
+{
+  char buf[LXW + 2];
+  if (d == 0)
+    printf (" %*X", LXW, 0);
+  else if (-d < d)
+    {
+      sprintf (buf, "%llX", (unsigned long long) -d);
+      printf ("%*s-%s", LXW - (int) strlen (buf), "", buf);
+    }
+  else
+    {
+      sprintf (buf, "%llX", (unsigned long long) d);
+      printf ("%*s+%s", LXW - (int) strlen (buf), "", buf);
+    }
+}
+#endif
+
+#ifdef PRINT
+static void
+mpn_print (mp_ptr p, mp_size_t size)
+{
+  mp_size_t i;
+
+  for (i = size - 1; i >= 0; i--)
+    {
+#ifdef _LONG_LONG_LIMB
+      printf ("%0*lX%0*lX", (int) (sizeof(mp_limb_t)),
+	      (unsigned long) (p[i] >> (GMP_LIMB_BITS/2)),
+              (int) (sizeof(mp_limb_t)), (unsigned long) (p[i]));
+#else
+      printf ("%0*lX", LXW, p[i]);
+#endif
+#ifdef SPACE
+      if (i != 0)
+	printf (" ");
+#endif
+    }
+  puts ("");
+}
+#endif
diff --git a/third_party/gmp/tests/devel/primes.c b/third_party/gmp/tests/devel/primes.c
new file mode 100644
index 0000000..84b3b51
--- /dev/null
+++ b/third_party/gmp/tests/devel/primes.c
@@ -0,0 +1,341 @@
+/*
+Copyright 2018-2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+/* Usage:
+
+   ./primes [p|c] [n0] <nMax>
+
+     Checks mpz_probab_prime_p(n, r) exhaustively, starting from n=n0
+     up to nMax.
+     If n0 * n0 > nMax, the intervall is sieved piecewise, else the
+     full intervall [0..nMax] is sieved at once.
+     With the parameter "p" (or nothing), tests all numbers. With "c"
+     only composites are tested.
+
+   ./primes n [n0] <nMax>
+
+     Checks mpz_nextprime() exhaustively, starting from n=n0 up to
+     nMax.
+
+     WARNING: The full intervall [0..nMax] is sieved at once, even if
+     only a piece is needed. This may require a lot of memory!
+
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "gmp-impl.h"
+#include "longlong.h"
+#include "tests.h"
+#define STOP(x) return (x)
+/* #define STOP(x) x */
+#define REPS 10
+/* #define TRACE(x,n) if ((n)>1) {x;} */
+#define TRACE(x,n)
+
+/* The full primesieve.c is included, just for block_resieve, that
+   is not exported ... */
+#undef gmp_primesieve
+#include "../../primesieve.c"
+
+#ifndef BLOCK_SIZE
+#define BLOCK_SIZE 2048
+#endif
+
+/*********************************************************/
+/* Section sieve: sieving functions and tools for primes */
+/*********************************************************/
+
+static mp_size_t
+primesieve_size (mp_limb_t n) { return n_to_bit(n) / GMP_LIMB_BITS + 1; }
+
+/*************************************************************/
+/* Section macros: common macros, for swing/fac/bin (&sieve) */
+/*************************************************************/
+
+#define LOOP_ON_SIEVE_CONTINUE(prime,end,sieve)			\
+    __max_i = (end);						\
+								\
+    do {							\
+      ++__i;							\
+      if (((sieve)[__index] & __mask) == 0)			\
+	{							\
+          mp_limb_t prime;					\
+	  prime = id_to_n(__i)
+
+#define LOOP_ON_SIEVE_BEGIN(prime,start,end,off,sieve)		\
+  do {								\
+    mp_limb_t __mask, __index, __max_i, __i;			\
+								\
+    __i = (start)-(off);					\
+    __index = __i / GMP_LIMB_BITS;				\
+    __mask = CNST_LIMB(1) << (__i % GMP_LIMB_BITS);		\
+    __i += (off);						\
+								\
+    LOOP_ON_SIEVE_CONTINUE(prime,end,sieve)
+
+#define LOOP_ON_SIEVE_STOP					\
+	}							\
+      __mask = __mask << 1 | __mask >> (GMP_LIMB_BITS-1);	\
+      __index += __mask & 1;					\
+    }  while (__i <= __max_i)
+
+#define LOOP_ON_SIEVE_END					\
+    LOOP_ON_SIEVE_STOP;						\
+  } while (0)
+
+mpz_t g;
+
+int something_wrong (mpz_t er, int exp)
+{
+  fprintf (stderr, "value = %lu , expected = %i\n", mpz_get_ui (er), exp);
+  return -1;
+}
+
+int
+check_pprime (unsigned long begin, unsigned long end, int composites)
+{
+  begin = (begin / 6U) * 6U;
+  for (;(begin < 2) & (begin <= end); ++begin)
+    {
+      *(g->_mp_d) = begin;
+      TRACE(printf ("-%li ", begin),1);
+      if (mpz_probab_prime_p (g, REPS))
+	STOP (something_wrong (g, 0));
+    }
+  for (;(begin < 4) & (begin <= end); ++begin)
+    {
+      *(g->_mp_d) = begin;
+      TRACE(printf ("+%li ", begin),2);
+      if (!composites && !mpz_probab_prime_p (g, REPS))
+	STOP (something_wrong (g, 1));
+    }
+  if (end > 4) {
+    if ((end > 10000) && (begin > end / begin))
+      {
+	mp_limb_t *sieve, *primes;
+	mp_size_t size_s, size_p, off;
+	unsigned long start;
+
+	mpz_set_ui (g, end);
+	mpz_sqrt (g, g);
+	start = mpz_get_ui (g) + GMP_LIMB_BITS;
+	size_p = primesieve_size (start);
+
+	primes = __GMP_ALLOCATE_FUNC_LIMBS (size_p);
+	gmp_primesieve (primes, start);
+
+	size_s = BLOCK_SIZE * 2;
+	sieve = __GMP_ALLOCATE_FUNC_LIMBS (size_s);
+	off = n_to_bit(begin) + (begin % 3 == 0);
+
+	do {
+	  TRACE (printf ("off =%li\n", off),3);
+	  block_resieve (sieve, BLOCK_SIZE, off, primes);
+	  TRACE (printf ("LOOP =%li - %li\n", id_to_n (off+1), id_to_n (off + BLOCK_SIZE * GMP_LIMB_BITS)),3);
+	  LOOP_ON_SIEVE_BEGIN (prime, off, off + BLOCK_SIZE * GMP_LIMB_BITS - 1,
+			       off, sieve);
+
+	  do {
+	    *(g->_mp_d) = begin;
+	    TRACE(printf ("-%li ", begin),1);
+	    if (mpz_probab_prime_p (g, REPS))
+	      STOP (something_wrong (g, 0));
+	    if ((begin & 0xff) == 0)
+	      {
+		spinner();
+		if ((begin & 0xfffffff) == 0)
+		  printf ("%li (0x%lx)\n", begin, begin);
+	      }
+	  } while (++begin < prime);
+
+	  *(g->_mp_d) = begin;
+	  TRACE(printf ("+%li ", begin),2);
+	  if (!composites && ! mpz_probab_prime_p (g, REPS))
+	    STOP (something_wrong (g, 1));
+	  ++begin;
+
+	  LOOP_ON_SIEVE_END;
+	  off += BLOCK_SIZE * GMP_LIMB_BITS;
+	} while (begin < end);
+
+	__GMP_FREE_FUNC_LIMBS (sieve, size_s);
+	__GMP_FREE_FUNC_LIMBS (primes, size_p);
+      }
+    else
+      {
+	mp_limb_t *sieve;
+	mp_size_t size;
+	unsigned long start;
+
+	size = primesieve_size (end);
+
+	sieve = __GMP_ALLOCATE_FUNC_LIMBS (size);
+	gmp_primesieve (sieve, end);
+	start = MAX (begin, 5) | 1;
+	LOOP_ON_SIEVE_BEGIN (prime, n_to_bit(start) + (start % 3 == 0),
+			     n_to_bit (end), 0, sieve);
+
+	do {
+	  *(g->_mp_d) = begin;
+	  TRACE(printf ("-%li ", begin),1);
+	  if (mpz_probab_prime_p (g, REPS))
+	    STOP (something_wrong (g, 0));
+	  if ((begin & 0xff) == 0)
+	    {
+	      spinner();
+	      if ((begin & 0xfffffff) == 0)
+		printf ("%li (0x%lx)\n", begin, begin);
+	    }
+	} while (++begin < prime);
+
+	*(g->_mp_d) = begin;
+	TRACE(printf ("+%li ", begin),2);
+	if (!composites && ! mpz_probab_prime_p (g, REPS))
+	  STOP (something_wrong (g, 1));
+	++begin;
+
+	LOOP_ON_SIEVE_END;
+
+	__GMP_FREE_FUNC_LIMBS (sieve, size);
+      }
+  }
+
+  for (;begin < end; ++begin)
+    {
+      *(g->_mp_d) = begin;
+      TRACE(printf ("-%li ", begin),1);
+      if (mpz_probab_prime_p (g, REPS))
+	STOP (something_wrong (g, 0));
+    }
+
+  gmp_printf ("%Zd\n", g);
+  return 0;
+}
+
+int
+check_nprime (unsigned long begin, unsigned long end)
+{
+  if (begin < 2)
+    {
+      *(g->_mp_d) = begin;
+      TRACE(printf ("%li ", begin),1);
+      mpz_nextprime (g, g);
+      if (mpz_cmp_ui (g, 2) != 0)
+	STOP (something_wrong (g, -1));
+      begin = mpz_get_ui (g);
+    }
+  if (begin < 3)
+    {
+      *(g->_mp_d) = begin;
+      TRACE(printf ("%li ", begin),1);
+      mpz_nextprime (g, g);
+      if (mpz_cmp_ui (g, 3) != 0)
+	STOP (something_wrong (g, -1));
+      begin = mpz_get_ui (g);
+    }
+  if (end > 4)
+      {
+	mp_limb_t *sieve;
+	mp_size_t size;
+	unsigned long start;
+
+	size = primesieve_size (end);
+
+	sieve = __GMP_ALLOCATE_FUNC_LIMBS (size);
+	gmp_primesieve (sieve, end);
+	start = MAX (begin, 5) | 1;
+	*(g->_mp_d) = begin;
+	LOOP_ON_SIEVE_BEGIN (prime, n_to_bit(start) + (start % 3 == 0),
+			     n_to_bit (end), 0, sieve);
+
+	mpz_nextprime (g, g);
+	if (mpz_cmp_ui (g, prime) != 0)
+	  STOP (something_wrong (g, -1));
+
+	if (prime - start > 200)
+	  {
+	    start = prime;
+	    spinner();
+	    if (prime - begin > 0xfffffff)
+	      {
+		begin = prime;
+		printf ("%li (0x%lx)\n", begin, begin);
+	      }
+	  }
+
+	LOOP_ON_SIEVE_END;
+
+	__GMP_FREE_FUNC_LIMBS (sieve, size);
+      }
+
+  if (mpz_cmp_ui (g, end) < 0)
+    {
+      mpz_nextprime (g, g);
+      if (mpz_cmp_ui (g, end) <= 0)
+	STOP (something_wrong (g, -1));
+    }
+
+  gmp_printf ("%Zd\n", g);
+  return 0;
+}
+
+int
+main (int argc, char **argv)
+{
+  int ret, mode = 0;
+  unsigned long begin = 0, end = 0;
+
+  for (;argc > 1;--argc,++argv)
+    switch (*argv[1]) {
+    case 'p':
+      mode = 0;
+      break;
+    case 'c':
+      mode = 2;
+      break;
+    case 'n':
+      mode = 1;
+      break;
+    default:
+      begin = end;
+      end = atol (argv[1]);
+    }
+
+  if (begin >= end)
+    {
+      fprintf (stderr, "usage: primes [n|p|c] [n0] <nMax>\n");
+      exit (1);
+    }
+
+  mpz_init_set_ui (g, ULONG_MAX);
+
+  switch (mode) {
+  case 1:
+    ret = check_nprime (begin, end);
+    break;
+  default:
+    ret = check_pprime (begin, end, mode);
+  }
+
+  mpz_clear (g);
+
+  if (ret == 0)
+    printf ("Prime tests checked in [%lu - %lu] [0x%lx - 0x%lx].\n", begin, end, begin, end);
+  return ret;
+}
diff --git a/third_party/gmp/tests/devel/shift.c b/third_party/gmp/tests/devel/shift.c
new file mode 100644
index 0000000..ad5125b
--- /dev/null
+++ b/third_party/gmp/tests/devel/shift.c
@@ -0,0 +1,244 @@
+/*
+Copyright 1996, 1998-2001, 2004, 2007, 2009, 2011 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+#ifdef OPERATION_lshift
+#define func __gmpn_lshift
+#define reffunc refmpn_lshift
+#define funcname "mpn_lshift"
+#endif
+
+#ifdef OPERATION_rshift
+#define func __gmpn_rshift
+#define reffunc refmpn_rshift
+#define funcname "mpn_rshift"
+#endif
+
+#if defined (USG) || defined (__SVR4) || defined (_UNICOS) || defined (__hpux)
+#include <time.h>
+
+int
+cputime ()
+{
+  if (CLOCKS_PER_SEC < 100000)
+    return clock () * 1000 / CLOCKS_PER_SEC;
+  return clock () / (CLOCKS_PER_SEC / 1000);
+}
+#else
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+int
+cputime ()
+{
+  struct rusage rus;
+
+  getrusage (0, &rus);
+  return rus.ru_utime.tv_sec * 1000 + rus.ru_utime.tv_usec / 1000;
+}
+#endif
+
+static void print_posneg (mp_limb_t);
+static void mpn_print (mp_ptr, mp_size_t);
+
+#define LXW ((int) (2 * sizeof (mp_limb_t)))
+#define M * 1000000
+
+#ifndef CLOCK
+#error "Don't know CLOCK of your machine"
+#endif
+
+#ifndef OPS
+#define OPS (CLOCK/5)
+#endif
+#ifndef SIZE
+#define SIZE 496
+#endif
+#ifndef TIMES
+#define TIMES OPS/(SIZE+1)
+#endif
+
+#ifndef CNT
+int CNT = 4;
+#endif
+
+int
+main (int argc, char **argv)
+{
+  mp_ptr s1, dx, dy;
+  mp_limb_t cyx, cyy;
+  int i;
+  long t0, t;
+  unsigned int test;
+  int cnt = CNT;
+  mp_size_t size;
+  unsigned int ntests;
+
+  s1 = malloc (SIZE * sizeof (mp_limb_t));
+  dx = malloc ((SIZE + 2) * sizeof (mp_limb_t));
+  dy = malloc ((SIZE + 2) * sizeof (mp_limb_t));
+
+  ntests = ~(unsigned) 0;
+  if (argc == 2)
+    ntests = strtol (argv[1], 0, 0);
+
+  for (test = 1; test <= ntests; test++)
+    {
+#if TIMES == 1 && ! defined (PRINT)
+      if (test % (SIZE > 100000 ? 1 : 100000 / SIZE) == 0)
+	{
+	  printf ("\r%u", test);
+	  fflush (stdout);
+	}
+#endif
+
+#if TIMES == 1
+      cnt = random () % (GMP_NUMB_BITS - 1) + 1;
+#endif
+
+#ifdef RANDOM
+      size = random () % SIZE + 1;
+#else
+      size = SIZE;
+#endif
+
+      dx[0] = 0x87654321;
+      dy[0] = 0x87654321;
+      dx[size+1] = 0x12345678;
+      dy[size+1] = 0x12345678;
+
+#if TIMES != 1
+      mpn_random (s1, size);
+
+      t0 = cputime();
+      for (i = 0; i < TIMES; i++)
+	func (dx+1, s1, size, cnt);
+      t = cputime() - t0;
+      printf (funcname ":    %5ldms (%.3f cycles/limb)\n",
+	      t, ((double) t * CLOCK) / (TIMES * size * 1000.0));
+#endif
+
+#ifndef NOCHECK
+      mpn_random (s1, size);
+
+#ifdef PRINT
+      printf ("cnt=%-*d ", (int) (2 * sizeof(mp_limb_t)) - 4, cnt);
+      mpn_print (s1, size);
+#endif
+
+      /* Put garbage in the destination.  */
+      for (i = 0; i < size; i++)
+	{
+	  dx[i+1] = 0xdead;
+	  dy[i+1] = 0xbeef;
+	}
+
+      cyx = reffunc (dx+1, s1, size, cnt);
+      cyy = func (dy+1, s1, size, cnt);
+
+#ifdef PRINT
+      mpn_print (&cyx, 1);
+      mpn_print (dx+1, size);
+      mpn_print (&cyy, 1);
+      mpn_print (dy+1, size);
+#endif
+
+      if (cyx != cyy || mpn_cmp (dx, dy, size+2) != 0
+	  || dx[0] != 0x87654321 || dx[size+1] != 0x12345678)
+	{
+	  mp_size_t s, e;
+	  for (s = 0;; s++)
+	    if ((unsigned long long) (dx+1)[s] != (unsigned long long) (dy+1)[s])
+	      break;
+	  for (e = size - 1;; e--)
+	    if ((unsigned long long) (dx+1)[e] != (unsigned long long) (dy+1)[e])
+	      break;
+#ifndef PRINT
+	  printf ("cnt=%-*d\n", (int) (2 * sizeof(mp_limb_t)) - 4, cnt);
+	  for (i = s; i <= e; i++)
+	    {
+	      printf ("%6d: ", i);
+	      printf ("%0*llX ", LXW, (unsigned long long) (dx+1)[i]);
+	      printf ("%0*llX ", LXW, (unsigned long long) (dy+1)[i]);
+	      print_posneg ((dy+1)[i] - (dx+1)[i]);
+	      printf ("\n");
+	    }
+	  printf ("%6s: ", "retval");
+	  printf ("%0*llX ", LXW, (unsigned long long) cyx);
+	  printf ("%0*llX ", LXW, (unsigned long long) cyy);
+	  print_posneg (cyx - cyy);
+#endif
+	  printf ("\n");
+	  if (dy[0] != 0x87654321)
+	    printf ("clobbered at low end\n");
+	  if (dy[size+1] != 0x12345678)
+	    printf ("clobbered at high end\n");
+	  printf ("TEST NUMBER %u\n", test);
+	  abort();
+	}
+#endif
+    }
+  exit (0);
+}
+
+static void
+print_posneg (mp_limb_t d)
+{
+  char buf[LXW + 2];
+  if (d == 0)
+    printf (" %*X", LXW, 0);
+  else if (-d < d)
+    {
+      sprintf (buf, "%llX", (unsigned long long) -d);
+      printf ("%*s-%s", LXW - (int) strlen (buf), "", buf);
+    }
+  else
+    {
+      sprintf (buf, "%llX", (unsigned long long) d);
+      printf ("%*s+%s", LXW - (int) strlen (buf), "", buf);
+    }
+}
+
+static void
+mpn_print (mp_ptr p, mp_size_t size)
+{
+  mp_size_t i;
+
+  for (i = size - 1; i >= 0; i--)
+    {
+#ifdef _LONG_LONG_LIMB
+      printf ("%0*lX%0*lX", (int) (sizeof(mp_limb_t)),
+	      (unsigned long) (p[i] >> (GMP_LIMB_BITS/2)),
+	      (int) (sizeof(mp_limb_t)), (unsigned long) (p[i]));
+#else
+      printf ("%0*lX", (int) (2 * sizeof(mp_limb_t)), p[i]);
+#endif
+#ifdef SPACE
+      if (i != 0)
+	printf (" ");
+#endif
+    }
+  puts ("");
+}
diff --git a/third_party/gmp/tests/devel/sqrtrem_1_2.c b/third_party/gmp/tests/devel/sqrtrem_1_2.c
new file mode 100644
index 0000000..3951191
--- /dev/null
+++ b/third_party/gmp/tests/devel/sqrtrem_1_2.c
@@ -0,0 +1,401 @@
+/*
+Copyright 2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+/* Usage:
+
+   ./sqrtrem_1_2 x
+
+     Checks mpn_sqrtrem() exhaustively, starting from 0, incrementing
+     the operand by a single unit, until all values handled by
+     mpn_sqrtrem{1,2} are tested. SLOW.
+
+   ./sqrtrem_1_2 s 1
+
+     Checks some special cases for mpn_sqrtrem(). I.e. values of the form
+     2^k*i and 2^k*(i+1)-1, with k=2^n and 0<i<2^k, until all such values,
+     handled by mpn_sqrtrem{1,2}, are tested.
+     Currently supports only the test of values that fits in one limb.
+     Less slow than the exhaustive test.
+
+   ./sqrtrem_1_2 c
+
+     Checks all corner cases for mpn_sqrtrem(). I.e. values of the form
+     i*i and (i+1)*(i+1)-1, for each value of i, until all such values,
+     handled by mpn_sqrtrem{1,2}, are tested.
+     Slightly faster than the special cases test.
+
+   For larger values, use
+   ./try mpn_sqrtrem
+
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "gmp-impl.h"
+#include "longlong.h"
+#include "tests.h"
+#define STOP(x) return (x)
+/* #define STOP(x) x */
+#define SPINNER(v)					\
+  do {							\
+    MPN_SIZEINBASE_2EXP (spinner_count, q, v, 1);	\
+    --spinner_count;					\
+    spinner();						\
+  } while (0)
+
+int something_wrong (mp_limb_t er, mp_limb_t ec, mp_limb_t es)
+{
+  fprintf (stderr, "root = %lu , rem = {%lu , %lu}\n", (long unsigned) es,(long unsigned) ec,(long unsigned) er);
+  return -1;
+}
+
+int
+check_all_values (int justone, int quick)
+{
+  mp_limb_t es, mer, er, s[1], r[2], q[2];
+  mp_size_t x;
+  unsigned bits;
+
+  es=1;
+  if (quick) {
+    printf ("Quick, skipping some... (%u)\n", GMP_NUMB_BITS - 2);
+    es <<= GMP_NUMB_BITS / 2 - 1;
+  }
+  er=0;
+  mer= es << 1;
+  *q = es * es;
+  printf ("All values tested, up to bits:\n");
+  do {
+    x = mpn_sqrtrem (s, r, q, 1);
+    if (UNLIKELY (x != (er != 0)) || UNLIKELY (*s != es)
+	|| UNLIKELY ((x == 1) && (er != *r)))
+      STOP (something_wrong (er, 0, es));
+
+    if (UNLIKELY (er == mer)) {
+      ++es;
+      if (UNLIKELY ((es & 0xff) == 0))
+	SPINNER(1);
+      mer +=2; /* mer = es * 2 */
+      er = 0;
+    } else
+      ++er;
+    ++*q;
+  } while (*q != 0);
+  q[1] = 1;
+  SPINNER(2);
+  printf ("\nValues of a single limb, tested.\n");
+  if (justone) return 0;
+  printf ("All values tested, up to bits:\n");
+  do {
+    x = mpn_sqrtrem (s, r, q, 2);
+    if (UNLIKELY (x != (er != 0)) || UNLIKELY (*s != es)
+	|| UNLIKELY ((x == 1) && (er != *r)))
+      STOP (something_wrong (er, 0, es));
+
+    if (UNLIKELY (er == mer)) {
+      ++es;
+      if (UNLIKELY ((es & 0x7f) == 0))
+	SPINNER(2);
+      mer +=2; /* mer = es * 2 */
+      if (UNLIKELY (mer == 0))
+	break;
+      er = 0;
+    } else
+      ++er;
+    q[1] += (++*q == 0);
+  } while (1);
+  SPINNER(2);
+  printf ("\nValues with at most a limb for reminder, tested.\n");
+  printf ("Testing more values not supported, jet.\n");
+  return 0;
+}
+
+mp_limb_t
+upd (mp_limb_t *s, mp_limb_t k)
+{
+  mp_limb_t _s = *s;
+
+  while (k > _s * 2)
+    {
+      k -= _s * 2 + 1;
+      ++_s;
+    }
+  *s = _s;
+  return k;
+}
+
+mp_limb_t
+upd1 (mp_limb_t *s, mp_limb_t k)
+{
+  mp_limb_t _s = *s;
+
+  if (LIKELY (k < _s * 2)) return k + 1;
+  *s = _s + 1;
+  return k - _s * 2;
+}
+
+int
+check_some_values (int justone, int quick)
+{
+  mp_limb_t es, her, er, k, s[1], r[2], q[2];
+  mp_size_t x;
+  unsigned bits;
+
+  es = 1 << 1;
+  if (quick) {
+    es <<= GMP_NUMB_BITS / 4 - 1;
+    printf ("Quick, skipping some... (%u)\n", GMP_NUMB_BITS / 2);
+  }
+  er = 0;
+  *q = es * es;
+  printf ("High-half values tested, up to bits:\n");
+  do {
+    k  = *q - 1;
+    do {
+      x = mpn_sqrtrem (s, r, q, 1);
+      if (UNLIKELY (x != (er != 0)) || UNLIKELY (*s != es)
+	  || UNLIKELY ((x == 1) && (er != *r)))
+	STOP (something_wrong (er, 0, es));
+
+      if (UNLIKELY ((es & 0xffff) == 0))
+	SPINNER(1);
+      if ((*q & k) == 0) {
+	*q |= k;
+	er = upd (&es, k + er);
+      } else {
+	++*q;
+	er = upd1 (&es, er);
+      }
+    } while (es & k);
+  } while (*q != 0);
+  q[1] = 1;
+  SPINNER(2);
+  printf ("\nValues of a single limb, tested.\n");
+  if (justone) return 0;
+  if (quick) {
+    es <<= GMP_NUMB_BITS / 2 - 1;
+    q[1] <<= GMP_NUMB_BITS - 2;
+    printf ("Quick, skipping some... (%u)\n", GMP_NUMB_BITS - 2);
+  }
+  printf ("High-half values tested, up to bits:\n");
+  do {
+    x = mpn_sqrtrem (s, r, q, 2);
+    if (UNLIKELY (x != (er != 0)) || UNLIKELY (*s != es)
+	|| UNLIKELY ((x == 1) && (er != *r)))
+      STOP (something_wrong (er, 0, es));
+
+    if (*q == 0) {
+      *q = GMP_NUMB_MAX;
+      if (UNLIKELY ((es & 0xffff) == 0)) {
+	if (UNLIKELY (es == GMP_NUMB_HIGHBIT))
+	  break;
+	SPINNER(2);
+      }
+      /* er = er + GMP_NUMB_MAX - 1 - es*2 // postponed */
+      ++es;
+      /* er = er + GMP_NUMB_MAX - 1 - 2*(es-1) =
+            = er +(GMP_NUMB_MAX + 1)- 2* es = er - 2*es */
+      er = upd (&es, er - 2 * es);
+    } else {
+      *q = 0;
+      ++q[1];
+      er = upd1 (&es, er);
+    }
+  } while (1);
+  SPINNER(2);
+  printf ("\nValues with at most a limb for reminder, tested.\n");
+  er = GMP_NUMB_MAX; her = 0;
+
+  printf ("High-half values tested, up to bits:\n");
+  do {
+    x = mpn_sqrtrem (s, r, q, 2);
+    if (UNLIKELY (x != (her?2:(er != 0))) || UNLIKELY (*s != es)
+	|| UNLIKELY ((x != 0) && ((er != *r) || ((x == 2) && (r[1] != 1)))))
+      STOP (something_wrong (er, her, es));
+
+    if (*q == 0) {
+      *q = GMP_NUMB_MAX;
+      if (UNLIKELY ((es & 0xffff) == 0)) {
+	SPINNER(2);
+      }
+      if (her) {
+	++es;
+	her = 0;
+	er = er - 2 * es;
+      } else {
+	her = --er != GMP_NUMB_MAX;
+	if (her & (er > es * 2)) {
+	  er -= es * 2 + 1;
+	  her = 0;
+	  ++es;
+	}
+      }
+    } else {
+      *q = 0;
+      if (++q[1] == 0) break;
+      if ((her == 0) | (er < es * 2)) {
+	her += ++er == 0;
+      }	else {
+	  er -= es * 2;
+	  her = 0;
+	  ++es;
+      }
+    }
+  } while (1);
+  printf ("| %u\nValues of at most two limbs, tested.\n", GMP_NUMB_BITS*2);
+  return 0;
+}
+
+int
+check_corner_cases (int justone, int quick)
+{
+  mp_limb_t es, er, s[1], r[2], q[2];
+  mp_size_t x;
+  unsigned bits;
+
+  es = 1;
+  if (quick) {
+    es <<= GMP_NUMB_BITS / 2 - 1;
+    printf ("Quick, skipping some... (%u)\n", GMP_NUMB_BITS - 2);
+  }
+  er = 0;
+  *q = es*es;
+  printf ("Corner cases tested, up to bits:\n");
+  do {
+    x = mpn_sqrtrem (s, r, q, 1);
+    if (UNLIKELY (x != (er != 0)) || UNLIKELY (*s != es)
+	|| UNLIKELY ((x == 1) && (er != *r)))
+      STOP (something_wrong (er, 0, es));
+
+    if (er != 0) {
+      ++es;
+      if (UNLIKELY ((es & 0xffff) == 0))
+	SPINNER(1);
+      er = 0;
+      ++*q;
+    } else {
+      er = es * 2;
+      *q += er;
+    }
+  } while (*q != 0);
+  q[1] = 1;
+  SPINNER(2);
+  printf ("\nValues of a single limb, tested.\n");
+  if (justone) return 0;
+  if (quick) {
+    es <<= GMP_NUMB_BITS / 2 - 1;
+    q[1] <<= GMP_NUMB_BITS - 2;
+    printf ("Quick, skipping some... (%u)\n", GMP_NUMB_BITS - 2);
+    --es;
+    --q[1];
+    q[0] -= es*2+1;
+  }
+  printf ("Corner cases tested, up to bits:\n");
+  do {
+    x = mpn_sqrtrem (s, r, q, 2);
+    if (UNLIKELY (x != (er != 0)) || UNLIKELY (*s != es)
+	|| UNLIKELY ((x == 1) && (er != *r)))
+      STOP (something_wrong (er, 0, es));
+
+    if (er != 0) {
+      ++es;
+      if (UNLIKELY ((es & 0xff) == 0))
+	SPINNER(2);
+      er = 0;
+      q[1] += (++*q == 0);
+      if (UNLIKELY (es == GMP_NUMB_HIGHBIT))
+	break;
+    } else {
+      er = es * 2;
+      add_ssaaaa (q[1], *q, q[1], *q, 0, er);
+    }
+  } while (1);
+  SPINNER(2);
+  printf ("\nValues with at most a limb for reminder, tested.\nCorner cases tested, up to bits:\n");
+  x = mpn_sqrtrem (s, r, q, 2);
+  if ((*s != es) || (x != 0))
+    STOP (something_wrong (0, 0, es));
+  q[1] += 1;
+  x = mpn_sqrtrem (s, r, q, 2);
+  if ((*s != es) || (x != 2) || (*r != 0) || (r[1] != 1))
+    STOP (something_wrong (0, 1, es));
+  ++es;
+  q[1] += (++*q == 0);
+  do {
+    x = mpn_sqrtrem (s, r, q, 2);
+    if (UNLIKELY (x != (er != 0) * 2) || UNLIKELY (*s != es)
+	|| UNLIKELY ((x == 2) && ((er != *r) || (r[1] != 1))))
+      STOP (something_wrong (er, er != 0, es));
+
+    if (er != 0) {
+      ++es;
+      if (UNLIKELY (es == 0))
+	break;
+      if (UNLIKELY ((es & 0xff) == 0))
+	SPINNER(2);
+      er = 0;
+      q[1] += (++*q == 0);
+    } else {
+      er = es * 2;
+      add_ssaaaa (q[1], *q, q[1], *q, 1, er);
+    }
+  } while (1);
+  printf ("| %u\nValues of at most two limbs, tested.\n", GMP_NUMB_BITS*2);
+  return 0;
+}
+
+int
+main (int argc, char **argv)
+{
+  int mode = 0;
+  int justone = 0;
+  int quick = 0;
+
+  for (;argc > 1;--argc,++argv)
+    switch (*argv[1]) {
+    default:
+      fprintf (stderr, "usage: sqrtrem_1_2 [x|c|s] [1|2] [q]\n");
+      exit (1);
+    case 'x':
+      mode = 0;
+      break;
+    case 'c':
+      mode = 1;
+      break;
+    case 's':
+      mode = 2;
+      break;
+    case 'q':
+      quick = 1;
+      break;
+    case '1':
+      justone = 1;
+      break;
+    case '2':
+      justone = 0;
+    }
+
+  switch (mode) {
+  default:
+    return check_all_values (justone, quick);
+  case 1:
+    return check_corner_cases (justone, quick);
+  case 2:
+    return check_some_values (justone, quick);
+  }
+}
diff --git a/third_party/gmp/tests/devel/try.c b/third_party/gmp/tests/devel/try.c
new file mode 100644
index 0000000..f8f4a1c
--- /dev/null
+++ b/third_party/gmp/tests/devel/try.c
@@ -0,0 +1,3658 @@
+/* Run some tests on various mpn routines.
+
+   THIS IS A TEST PROGRAM USED ONLY FOR DEVELOPMENT.  IT'S ALMOST CERTAIN TO
+   BE SUBJECT TO INCOMPATIBLE CHANGES IN FUTURE VERSIONS OF GMP.
+
+Copyright 2000-2006, 2008, 2009, 2011, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+/* Usage: try [options] <function>...
+
+   For example, "./try mpn_add_n" to run tests of that function.
+
+   Combinations of alignments and overlaps are tested, with redzones above
+   or below the destinations, and with the sources write-protected.
+
+   The number of tests performed becomes ridiculously large with all the
+   combinations, and for that reason this can't be a part of a "make check",
+   it's meant only for development.  The code isn't very pretty either.
+
+   During development it can help to disable the redzones, since seeing the
+   rest of the destination written can show where the wrong part is, or if
+   the dst pointers are off by 1 or whatever.  The magic DEADVAL initial
+   fill (see below) will show locations never written.
+
+   The -s option can be used to test only certain size operands, which is
+   useful if some new code doesn't yet support say sizes less than the
+   unrolling, or whatever.
+
+   When a problem occurs it'll of course be necessary to run the program
+   under gdb to find out quite where, how and why it's going wrong.  Disable
+   the spinner with the -W option when doing this, or single stepping won't
+   work.  Using the "-1" option to run with simple data can be useful.
+
+   New functions to test can be added in try_array[].  If a new TYPE is
+   required then add it to the existing constants, set up its parameters in
+   param_init(), and add it to the call() function.  Extra parameter fields
+   can be added if necessary, or further interpretations given to existing
+   fields.
+
+
+   Portability:
+
+   This program is not designed for use on Cray vector systems under Unicos,
+   it will fail to compile due to missing _SC_PAGE_SIZE.  Those systems
+   don't really have pages or mprotect.  We could arrange to run the tests
+   without the redzones, but we haven't bothered currently.
+
+
+   Enhancements:
+
+   umul_ppmm support is not very good, lots of source data is generated
+   whereas only two limbs are needed.
+
+   Make a little scheme for interpreting the "SIZE" selections uniformly.
+
+   Make tr->size==SIZE_2 work, for the benefit of find_a which wants just 2
+   source limbs.  Possibly increase the default repetitions in that case.
+
+   Automatically detect gdb and disable the spinner (use -W for now).
+
+   Make a way to re-run a failing case in the debugger.  Have an option to
+   snapshot each test case before it's run so the data is available if a
+   segv occurs.  (This should be more reliable than the current print_all()
+   in the signal handler.)
+
+   When alignment means a dst isn't hard against the redzone, check the
+   space in between remains unchanged.
+
+   When a source overlaps a destination, don't run both s[i].high 0 and 1,
+   as s[i].high has no effect.  Maybe encode s[i].high into overlap->s[i].
+
+   When partial overlaps aren't done, don't loop over source alignments
+   during overlaps.
+
+   Try to make the looping code a bit less horrible.  Right now it's pretty
+   hard to see what iterations are actually done.
+
+   Perhaps specific setups and loops for each style of function under test
+   would be clearer than a parameterized general loop.  There's lots of
+   stuff common to all functions, but the exceptions get messy.
+
+   When there's no overlap, run with both src>dst and src<dst.  A subtle
+   calling-conventions violation occurred in a P6 copy which depended on the
+   relative location of src and dst.
+
+   multiplier_N is more or less a third source region for the addmul_N
+   routines, and could be done with the redzoned region scheme.
+
+*/
+
+
+/* always do assertion checking */
+#define WANT_ASSERT 1
+
+#include "config.h"
+
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#if HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+
+#include "gmp-impl.h"
+#include "longlong.h"
+#include "tests.h"
+
+
+#if !HAVE_DECL_OPTARG
+extern char *optarg;
+extern int optind, opterr;
+#endif
+
+#if ! HAVE_DECL_SYS_NERR
+extern int sys_nerr;
+#endif
+
+#if ! HAVE_DECL_SYS_ERRLIST
+extern char *sys_errlist[];
+#endif
+
+#if ! HAVE_STRERROR
+char *
+strerror (int n)
+{
+  if (n < 0 || n >= sys_nerr)
+    return "errno out of range";
+  else
+    return sys_errlist[n];
+}
+#endif
+
+/* Rumour has it some systems lack a define of PROT_NONE. */
+#ifndef PROT_NONE
+#define PROT_NONE   0
+#endif
+
+/* Dummy defines for when mprotect doesn't exist. */
+#ifndef PROT_READ
+#define PROT_READ   0
+#endif
+#ifndef PROT_WRITE
+#define PROT_WRITE  0
+#endif
+
+/* _SC_PAGESIZE is standard, but hpux 9 and possibly other systems have
+   _SC_PAGE_SIZE instead. */
+#if defined (_SC_PAGE_SIZE) && ! defined (_SC_PAGESIZE)
+#define _SC_PAGESIZE  _SC_PAGE_SIZE
+#endif
+
+
+#ifdef EXTRA_PROTOS
+EXTRA_PROTOS
+#endif
+#ifdef EXTRA_PROTOS2
+EXTRA_PROTOS2
+#endif
+
+
+#define DEFAULT_REPETITIONS  10
+
+int  option_repetitions = DEFAULT_REPETITIONS;
+int  option_spinner = 1;
+int  option_redzones = 1;
+int  option_firstsize = 0;
+int  option_lastsize = 500;
+int  option_firstsize2 = 0;
+
+#define ALIGNMENTS          4
+#define OVERLAPS            4
+#define CARRY_RANDOMS       5
+#define MULTIPLIER_RANDOMS  5
+#define DIVISOR_RANDOMS     5
+#define FRACTION_COUNT      4
+
+int  option_print = 0;
+
+#define DATA_TRAND  0
+#define DATA_ZEROS  1
+#define DATA_SEQ    2
+#define DATA_FFS    3
+#define DATA_2FD    4
+int  option_data = DATA_TRAND;
+
+
+mp_size_t  pagesize;
+#define PAGESIZE_LIMBS  (pagesize / GMP_LIMB_BYTES)
+
+/* must be a multiple of the page size */
+#define REDZONE_BYTES   (pagesize * 16)
+#define REDZONE_LIMBS   (REDZONE_BYTES / GMP_LIMB_BYTES)
+
+
+#define MAX3(x,y,z)   (MAX (x, MAX (y, z)))
+
+#if GMP_LIMB_BITS == 32
+#define DEADVAL  CNST_LIMB(0xDEADBEEF)
+#else
+#define DEADVAL  CNST_LIMB(0xDEADBEEFBADDCAFE)
+#endif
+
+
+struct region_t {
+  mp_ptr     ptr;
+  mp_size_t  size;
+};
+
+
+#define TRAP_NOWHERE 0
+#define TRAP_REF     1
+#define TRAP_FUN     2
+#define TRAP_SETUPS  3
+int trap_location = TRAP_NOWHERE;
+
+
+#define NUM_SOURCES  5
+#define NUM_DESTS    2
+
+struct source_t {
+  struct region_t  region;
+  int        high;
+  mp_size_t  align;
+  mp_ptr     p;
+};
+
+struct source_t  s[NUM_SOURCES];
+
+struct dest_t {
+  int        high;
+  mp_size_t  align;
+  mp_size_t  size;
+};
+
+struct dest_t  d[NUM_DESTS];
+
+struct source_each_t {
+  mp_ptr     p;
+};
+
+struct dest_each_t {
+  struct region_t  region;
+  mp_ptr     p;
+};
+
+mp_size_t       size;
+mp_size_t       size2;
+unsigned long   shift;
+mp_limb_t       carry;
+mp_limb_t       divisor;
+mp_limb_t       multiplier;
+mp_limb_t       multiplier_N[8];
+
+struct each_t {
+  const char  *name;
+  struct dest_each_t    d[NUM_DESTS];
+  struct source_each_t  s[NUM_SOURCES];
+  mp_limb_t  retval;
+};
+
+struct each_t  ref = { "Ref" };
+struct each_t  fun = { "Fun" };
+
+#define SRC_SIZE(n)  ((n) == 1 && tr->size2 ? size2 : size)
+
+void validate_fail (void);
+
+
+#if HAVE_TRY_NEW_C
+#include "try-new.c"
+#endif
+
+
+typedef mp_limb_t (*tryfun_t) (ANYARGS);
+
+struct try_t {
+  char  retval;
+
+  char  src[NUM_SOURCES];
+  char  dst[NUM_DESTS];
+
+#define SIZE_YES          1
+#define SIZE_ALLOW_ZERO   2
+#define SIZE_1            3  /* 1 limb  */
+#define SIZE_2            4  /* 2 limbs */
+#define SIZE_3            5  /* 3 limbs */
+#define SIZE_4            6  /* 4 limbs */
+#define SIZE_6            7  /* 6 limbs */
+#define SIZE_FRACTION     8  /* size2 is fraction for divrem etc */
+#define SIZE_SIZE2        9
+#define SIZE_PLUS_1      10
+#define SIZE_SUM         11
+#define SIZE_DIFF        12
+#define SIZE_DIFF_PLUS_1 13
+#define SIZE_DIFF_PLUS_3 14
+#define SIZE_RETVAL      15
+#define SIZE_CEIL_HALF   16
+#define SIZE_GET_STR     17
+#define SIZE_PLUS_MSIZE_SUB_1 18  /* size+msize-1 */
+#define SIZE_ODD         19
+  char  size;
+  char  size2;
+  char  dst_size[NUM_DESTS];
+
+  /* multiplier_N size in limbs */
+  mp_size_t  msize;
+
+  char  dst_bytes[NUM_DESTS];
+
+  char  dst0_from_src1;
+
+#define CARRY_BIT     1  /* single bit 0 or 1 */
+#define CARRY_3       2  /* 0, 1, 2 */
+#define CARRY_4       3  /* 0 to 3 */
+#define CARRY_LIMB    4  /* any limb value */
+#define CARRY_DIVISOR 5  /* carry<divisor */
+  char  carry;
+
+  /* a fudge to tell the output when to print negatives */
+  char  carry_sign;
+
+  char  multiplier;
+  char  shift;
+
+#define DIVISOR_LIMB  1
+#define DIVISOR_NORM  2
+#define DIVISOR_ODD   3
+  char  divisor;
+
+#define DATA_NON_ZERO         1
+#define DATA_GCD              2
+#define DATA_SRC0_ODD         3
+#define DATA_SRC0_HIGHBIT     4
+#define DATA_SRC1_ODD         5
+#define DATA_SRC1_ODD_PRIME   6
+#define DATA_SRC1_HIGHBIT     7
+#define DATA_MULTIPLE_DIVISOR 8
+#define DATA_UDIV_QRNND       9
+#define DATA_DIV_QR_1        10
+  char  data;
+
+/* Default is allow full overlap. */
+#define OVERLAP_NONE         1
+#define OVERLAP_LOW_TO_HIGH  2
+#define OVERLAP_HIGH_TO_LOW  3
+#define OVERLAP_NOT_SRCS     4
+#define OVERLAP_NOT_SRC2     8
+#define OVERLAP_NOT_DST2     16
+  char  overlap;
+
+  tryfun_t    reference;
+  const char  *reference_name;
+
+  void        (*validate) (void);
+  const char  *validate_name;
+};
+
+struct try_t  *tr;
+
+
+void
+validate_mod_34lsub1 (void)
+{
+#define CNST_34LSUB1   ((CNST_LIMB(1) << (3 * (GMP_NUMB_BITS / 4))) - 1)
+
+  mp_srcptr  ptr = s[0].p;
+  int        error = 0;
+  mp_limb_t  got, got_mod, want, want_mod;
+
+  ASSERT (size >= 1);
+
+  got = fun.retval;
+  got_mod = got % CNST_34LSUB1;
+
+  want = refmpn_mod_34lsub1 (ptr, size);
+  want_mod = want % CNST_34LSUB1;
+
+  if (got_mod != want_mod)
+    {
+      gmp_printf ("got   0x%MX reduced from 0x%MX\n", got_mod, got);
+      gmp_printf ("want  0x%MX reduced from 0x%MX\n", want_mod, want);
+      error = 1;
+    }
+
+  if (error)
+    validate_fail ();
+}
+
+void
+validate_divexact_1 (void)
+{
+  mp_srcptr  src = s[0].p;
+  mp_srcptr  dst = fun.d[0].p;
+  int  error = 0;
+
+  ASSERT (size >= 1);
+
+  {
+    mp_ptr     tp = refmpn_malloc_limbs (size);
+    mp_limb_t  rem;
+
+    rem = refmpn_divrem_1 (tp, 0, src, size, divisor);
+    if (rem != 0)
+      {
+	gmp_printf ("Remainder a%%d == 0x%MX, mpn_divexact_1 undefined\n", rem);
+	error = 1;
+      }
+    if (! refmpn_equal_anynail (tp, dst, size))
+      {
+	printf ("Quotient a/d wrong\n");
+	mpn_trace ("fun ", dst, size);
+	mpn_trace ("want", tp, size);
+	error = 1;
+      }
+    free (tp);
+  }
+
+  if (error)
+    validate_fail ();
+}
+
+void
+validate_bdiv_q_1
+ (void)
+{
+  mp_srcptr  src = s[0].p;
+  mp_srcptr  dst = fun.d[0].p;
+  int  error = 0;
+
+  ASSERT (size >= 1);
+
+  {
+    mp_ptr     tp = refmpn_malloc_limbs (size + 1);
+
+    refmpn_mul_1 (tp, dst, size, divisor);
+    /* Set ignored low bits */
+    tp[0] |= (src[0] & LOW_ZEROS_MASK (divisor));
+    if (! refmpn_equal_anynail (tp, src, size))
+      {
+	printf ("Bdiv wrong: res * divisor != src (mod B^size)\n");
+	mpn_trace ("res ", dst, size);
+	mpn_trace ("src ", src, size);
+	error = 1;
+      }
+    free (tp);
+  }
+
+  if (error)
+    validate_fail ();
+}
+
+
+void
+validate_modexact_1c_odd (void)
+{
+  mp_srcptr  ptr = s[0].p;
+  mp_limb_t  r = fun.retval;
+  int  error = 0;
+
+  ASSERT (size >= 1);
+  ASSERT (divisor & 1);
+
+  if ((r & GMP_NAIL_MASK) != 0)
+    printf ("r has non-zero nail\n");
+
+  if (carry < divisor)
+    {
+      if (! (r < divisor))
+	{
+	  printf ("Don't have r < divisor\n");
+	  error = 1;
+	}
+    }
+  else /* carry >= divisor */
+    {
+      if (! (r <= divisor))
+	{
+	  printf ("Don't have r <= divisor\n");
+	  error = 1;
+	}
+    }
+
+  {
+    mp_limb_t  c = carry % divisor;
+    mp_ptr     tp = refmpn_malloc_limbs (size+1);
+    mp_size_t  k;
+
+    for (k = size-1; k <= size; k++)
+      {
+	/* set {tp,size+1} to r*b^k + a - c */
+	refmpn_copyi (tp, ptr, size);
+	tp[size] = 0;
+	ASSERT_NOCARRY (refmpn_add_1 (tp+k, tp+k, size+1-k, r));
+	if (refmpn_sub_1 (tp, tp, size+1, c))
+	  ASSERT_CARRY (mpn_add_1 (tp, tp, size+1, divisor));
+
+	if (refmpn_mod_1 (tp, size+1, divisor) == 0)
+	  goto good_remainder;
+      }
+    printf ("Remainder matches neither r*b^(size-1) nor r*b^size\n");
+    error = 1;
+
+  good_remainder:
+    free (tp);
+  }
+
+  if (error)
+    validate_fail ();
+}
+
+void
+validate_modexact_1_odd (void)
+{
+  carry = 0;
+  validate_modexact_1c_odd ();
+}
+
+void
+validate_div_qr_1_pi1 (void)
+{
+  mp_srcptr up = ref.s[0].p;
+  mp_size_t un = size;
+  mp_size_t uh = ref.s[1].p[0];
+  mp_srcptr qp = fun.d[0].p;
+  mp_limb_t r = fun.retval;
+  mp_limb_t cy;
+  int cmp;
+  mp_ptr tp;
+  if (r >= divisor)
+    {
+      gmp_printf ("Bad remainder %Md, d = %Md\n", r, divisor);
+      validate_fail ();
+    }
+  tp = refmpn_malloc_limbs (un);
+  cy = refmpn_mul_1 (tp, qp, un, divisor);
+  cy += refmpn_add_1 (tp, tp, un, r);
+  if (cy != uh || refmpn_cmp (tp, up, un) != 0)
+    {
+      gmp_printf ("Incorrect result, size %ld.\n"
+		  "d = %Mx, u = %Mx, %Nx\n"
+		  "got: r = %Mx, q = %Nx\n"
+		  "q d + r = %Mx, %Nx",
+		  (long) un,
+		  divisor, uh, up, un,
+		  r, qp, un,
+		  cy, tp, un);
+      validate_fail ();
+    }
+  free (tp);
+}
+
+
+void
+validate_sqrtrem (void)
+{
+  mp_srcptr  orig_ptr = s[0].p;
+  mp_size_t  orig_size = size;
+  mp_size_t  root_size = (size+1)/2;
+  mp_srcptr  root_ptr = fun.d[0].p;
+  mp_size_t  rem_size = fun.retval;
+  mp_srcptr  rem_ptr = fun.d[1].p;
+  mp_size_t  prod_size = 2*root_size;
+  mp_ptr     p;
+  int  error = 0;
+
+  if (rem_size < 0 || rem_size > size)
+    {
+      printf ("Bad remainder size retval %ld\n", (long) rem_size);
+      validate_fail ();
+    }
+
+  p = refmpn_malloc_limbs (prod_size);
+
+  p[root_size] = refmpn_lshift (p, root_ptr, root_size, 1);
+  if (refmpn_cmp_twosizes (p,root_size+1, rem_ptr,rem_size) < 0)
+    {
+      printf ("Remainder bigger than 2*root\n");
+      error = 1;
+    }
+
+  refmpn_sqr (p, root_ptr, root_size);
+  if (rem_size != 0)
+    refmpn_add (p, p, prod_size, rem_ptr, rem_size);
+  if (refmpn_cmp_twosizes (p,prod_size, orig_ptr,orig_size) != 0)
+    {
+      printf ("root^2+rem != original\n");
+      mpn_trace ("prod", p, prod_size);
+      error = 1;
+    }
+  free (p);
+
+  if (error)
+    validate_fail ();
+}
+
+void
+validate_sqrt (void)
+{
+  mp_srcptr  orig_ptr = s[0].p;
+  mp_size_t  orig_size = size;
+  mp_size_t  root_size = (size+1)/2;
+  mp_srcptr  root_ptr = fun.d[0].p;
+  int        perf_pow = (fun.retval == 0);
+  mp_size_t  prod_size = 2*root_size;
+  mp_ptr     p;
+  int  error = 0;
+
+  p = refmpn_malloc_limbs (prod_size);
+
+  refmpn_sqr (p, root_ptr, root_size);
+  MPN_NORMALIZE (p, prod_size);
+  if (refmpn_cmp_twosizes (p,prod_size, orig_ptr,orig_size) != - !perf_pow)
+    {
+      printf ("root^2 bigger than original, or wrong return value.\n");
+      mpn_trace ("prod...", p, prod_size);
+      error = 1;
+    }
+
+  refmpn_sub (p, orig_ptr,orig_size, p,prod_size);
+  MPN_NORMALIZE (p, prod_size);
+  if (prod_size >= root_size &&
+      refmpn_sub (p, p,prod_size, root_ptr, root_size) == 0 &&
+      refmpn_cmp_twosizes (p, prod_size, root_ptr, root_size) > 0)
+    {
+      printf ("(root+1)^2 smaller than original.\n");
+      mpn_trace ("prod", p, prod_size);
+      error = 1;
+    }
+  free (p);
+
+  if (error)
+    validate_fail ();
+}
+
+
+/* These types are indexes into the param[] array and are arbitrary so long
+   as they're all distinct and within the size of param[].  Renumber
+   whenever necessary or desired.  */
+
+enum {
+  TYPE_ADD = 1, TYPE_ADD_N, TYPE_ADD_NC, TYPE_SUB, TYPE_SUB_N, TYPE_SUB_NC,
+
+  TYPE_ADD_ERR1_N, TYPE_ADD_ERR2_N, TYPE_ADD_ERR3_N,
+  TYPE_SUB_ERR1_N, TYPE_SUB_ERR2_N, TYPE_SUB_ERR3_N,
+
+  TYPE_MUL_1, TYPE_MUL_1C,
+
+  TYPE_MUL_2, TYPE_MUL_3, TYPE_MUL_4, TYPE_MUL_5, TYPE_MUL_6,
+
+  TYPE_ADDMUL_1, TYPE_ADDMUL_1C, TYPE_SUBMUL_1, TYPE_SUBMUL_1C,
+
+  TYPE_ADDMUL_2, TYPE_ADDMUL_3, TYPE_ADDMUL_4, TYPE_ADDMUL_5, TYPE_ADDMUL_6,
+  TYPE_ADDMUL_7, TYPE_ADDMUL_8,
+
+  TYPE_ADDSUB_N, TYPE_ADDSUB_NC,
+
+  TYPE_RSHIFT, TYPE_LSHIFT, TYPE_LSHIFTC,
+
+  TYPE_COPY, TYPE_COPYI, TYPE_COPYD, TYPE_COM,
+
+  TYPE_ADDLSH1_N, TYPE_ADDLSH2_N, TYPE_ADDLSH_N,
+  TYPE_ADDLSH1_N_IP1, TYPE_ADDLSH2_N_IP1, TYPE_ADDLSH_N_IP1,
+  TYPE_ADDLSH1_N_IP2, TYPE_ADDLSH2_N_IP2, TYPE_ADDLSH_N_IP2,
+  TYPE_SUBLSH1_N, TYPE_SUBLSH2_N, TYPE_SUBLSH_N,
+  TYPE_SUBLSH1_N_IP1, TYPE_SUBLSH2_N_IP1, TYPE_SUBLSH_N_IP1,
+  TYPE_RSBLSH1_N, TYPE_RSBLSH2_N, TYPE_RSBLSH_N,
+  TYPE_RSH1ADD_N, TYPE_RSH1SUB_N,
+
+  TYPE_ADDLSH1_NC, TYPE_ADDLSH2_NC, TYPE_ADDLSH_NC,
+  TYPE_SUBLSH1_NC, TYPE_SUBLSH2_NC, TYPE_SUBLSH_NC,
+  TYPE_RSBLSH1_NC, TYPE_RSBLSH2_NC, TYPE_RSBLSH_NC,
+
+  TYPE_ADDCND_N, TYPE_SUBCND_N,
+
+  TYPE_MOD_1, TYPE_MOD_1C, TYPE_DIVMOD_1, TYPE_DIVMOD_1C, TYPE_DIVREM_1,
+  TYPE_DIVREM_1C, TYPE_PREINV_DIVREM_1, TYPE_DIVREM_2, TYPE_PREINV_MOD_1,
+  TYPE_DIV_QR_1N_PI1,
+  TYPE_MOD_34LSUB1, TYPE_UDIV_QRNND, TYPE_UDIV_QRNND_R,
+
+  TYPE_DIVEXACT_1, TYPE_BDIV_Q_1, TYPE_DIVEXACT_BY3, TYPE_DIVEXACT_BY3C,
+  TYPE_MODEXACT_1_ODD, TYPE_MODEXACT_1C_ODD,
+
+  TYPE_INVERT, TYPE_BINVERT,
+
+  TYPE_GCD, TYPE_GCD_1, TYPE_GCD_FINDA, TYPE_MPZ_JACOBI, TYPE_MPZ_KRONECKER,
+  TYPE_MPZ_KRONECKER_UI, TYPE_MPZ_KRONECKER_SI, TYPE_MPZ_UI_KRONECKER,
+  TYPE_MPZ_SI_KRONECKER, TYPE_MPZ_LEGENDRE,
+
+  TYPE_AND_N, TYPE_NAND_N, TYPE_ANDN_N, TYPE_IOR_N, TYPE_IORN_N, TYPE_NIOR_N,
+  TYPE_XOR_N, TYPE_XNOR_N,
+
+  TYPE_MUL_MN, TYPE_MUL_N, TYPE_SQR, TYPE_UMUL_PPMM, TYPE_UMUL_PPMM_R,
+  TYPE_MULLO_N, TYPE_SQRLO, TYPE_MULMID_MN, TYPE_MULMID_N,
+
+  TYPE_SBPI1_DIV_QR, TYPE_TDIV_QR,
+
+  TYPE_SQRTREM, TYPE_SQRT, TYPE_ZERO, TYPE_GET_STR, TYPE_POPCOUNT, TYPE_HAMDIST,
+
+  TYPE_EXTRA
+};
+
+struct try_t  param[TYPE_EXTRA];
+
+
+void
+param_init (void)
+{
+  struct try_t  *p;
+
+#define COPY(index)  memcpy (p, &param[index], sizeof (*p))
+
+#define REFERENCE(fun)                  \
+  p->reference = (tryfun_t) fun;        \
+  p->reference_name = #fun
+#define VALIDATE(fun)           \
+  p->validate = fun;            \
+  p->validate_name = #fun
+
+
+  p = &param[TYPE_ADD_N];
+  p->retval = 1;
+  p->dst[0] = 1;
+  p->src[0] = 1;
+  p->src[1] = 1;
+  REFERENCE (refmpn_add_n);
+
+  p = &param[TYPE_ADD_NC];
+  COPY (TYPE_ADD_N);
+  p->carry = CARRY_BIT;
+  REFERENCE (refmpn_add_nc);
+
+  p = &param[TYPE_SUB_N];
+  COPY (TYPE_ADD_N);
+  REFERENCE (refmpn_sub_n);
+
+  p = &param[TYPE_SUB_NC];
+  COPY (TYPE_ADD_NC);
+  REFERENCE (refmpn_sub_nc);
+
+  p = &param[TYPE_ADD];
+  COPY (TYPE_ADD_N);
+  p->size = SIZE_ALLOW_ZERO;
+  p->size2 = 1;
+  REFERENCE (refmpn_add);
+
+  p = &param[TYPE_SUB];
+  COPY (TYPE_ADD);
+  REFERENCE (refmpn_sub);
+
+
+  p = &param[TYPE_ADD_ERR1_N];
+  p->retval = 1;
+  p->dst[0] = 1;
+  p->dst[1] = 1;
+  p->src[0] = 1;
+  p->src[1] = 1;
+  p->src[2] = 1;
+  p->dst_size[1] = SIZE_2;
+  p->carry = CARRY_BIT;
+  p->overlap = OVERLAP_NOT_DST2;
+  REFERENCE (refmpn_add_err1_n);
+
+  p = &param[TYPE_SUB_ERR1_N];
+  COPY (TYPE_ADD_ERR1_N);
+  REFERENCE (refmpn_sub_err1_n);
+
+  p = &param[TYPE_ADD_ERR2_N];
+  COPY (TYPE_ADD_ERR1_N);
+  p->src[3] = 1;
+  p->dst_size[1] = SIZE_4;
+  REFERENCE (refmpn_add_err2_n);
+
+  p = &param[TYPE_SUB_ERR2_N];
+  COPY (TYPE_ADD_ERR2_N);
+  REFERENCE (refmpn_sub_err2_n);
+
+  p = &param[TYPE_ADD_ERR3_N];
+  COPY (TYPE_ADD_ERR2_N);
+  p->src[4] = 1;
+  p->dst_size[1] = SIZE_6;
+  REFERENCE (refmpn_add_err3_n);
+
+  p = &param[TYPE_SUB_ERR3_N];
+  COPY (TYPE_ADD_ERR3_N);
+  REFERENCE (refmpn_sub_err3_n);
+
+  p = &param[TYPE_ADDCND_N];
+  COPY (TYPE_ADD_N);
+  p->carry = CARRY_BIT;
+  REFERENCE (refmpn_cnd_add_n);
+
+  p = &param[TYPE_SUBCND_N];
+  COPY (TYPE_ADD_N);
+  p->carry = CARRY_BIT;
+  REFERENCE (refmpn_cnd_sub_n);
+
+
+  p = &param[TYPE_MUL_1];
+  p->retval = 1;
+  p->dst[0] = 1;
+  p->src[0] = 1;
+  p->multiplier = 1;
+  p->overlap = OVERLAP_LOW_TO_HIGH;
+  REFERENCE (refmpn_mul_1);
+
+  p = &param[TYPE_MUL_1C];
+  COPY (TYPE_MUL_1);
+  p->carry = CARRY_LIMB;
+  REFERENCE (refmpn_mul_1c);
+
+
+  p = &param[TYPE_MUL_2];
+  p->retval = 1;
+  p->dst[0] = 1;
+  p->dst_size[0] = SIZE_PLUS_MSIZE_SUB_1;
+  p->src[0] = 1;
+  p->src[1] = 1;
+  p->msize = 2;
+  p->overlap = OVERLAP_NOT_SRC2;
+  REFERENCE (refmpn_mul_2);
+
+  p = &param[TYPE_MUL_3];
+  COPY (TYPE_MUL_2);
+  p->msize = 3;
+  REFERENCE (refmpn_mul_3);
+
+  p = &param[TYPE_MUL_4];
+  COPY (TYPE_MUL_2);
+  p->msize = 4;
+  REFERENCE (refmpn_mul_4);
+
+  p = &param[TYPE_MUL_5];
+  COPY (TYPE_MUL_2);
+  p->msize = 5;
+  REFERENCE (refmpn_mul_5);
+
+  p = &param[TYPE_MUL_6];
+  COPY (TYPE_MUL_2);
+  p->msize = 6;
+  REFERENCE (refmpn_mul_6);
+
+
+  p = &param[TYPE_ADDMUL_1];
+  p->retval = 1;
+  p->dst[0] = 1;
+  p->src[0] = 1;
+  p->multiplier = 1;
+  p->dst0_from_src1 = 1;
+  REFERENCE (refmpn_addmul_1);
+
+  p = &param[TYPE_ADDMUL_1C];
+  COPY (TYPE_ADDMUL_1);
+  p->carry = CARRY_LIMB;
+  REFERENCE (refmpn_addmul_1c);
+
+  p = &param[TYPE_SUBMUL_1];
+  COPY (TYPE_ADDMUL_1);
+  REFERENCE (refmpn_submul_1);
+
+  p = &param[TYPE_SUBMUL_1C];
+  COPY (TYPE_ADDMUL_1C);
+  REFERENCE (refmpn_submul_1c);
+
+
+  p = &param[TYPE_ADDMUL_2];
+  p->retval = 1;
+  p->dst[0] = 1;
+  p->dst_size[0] = SIZE_PLUS_MSIZE_SUB_1;
+  p->src[0] = 1;
+  p->src[1] = 1;
+  p->msize = 2;
+  p->dst0_from_src1 = 1;
+  p->overlap = OVERLAP_NONE;
+  REFERENCE (refmpn_addmul_2);
+
+  p = &param[TYPE_ADDMUL_3];
+  COPY (TYPE_ADDMUL_2);
+  p->msize = 3;
+  REFERENCE (refmpn_addmul_3);
+
+  p = &param[TYPE_ADDMUL_4];
+  COPY (TYPE_ADDMUL_2);
+  p->msize = 4;
+  REFERENCE (refmpn_addmul_4);
+
+  p = &param[TYPE_ADDMUL_5];
+  COPY (TYPE_ADDMUL_2);
+  p->msize = 5;
+  REFERENCE (refmpn_addmul_5);
+
+  p = &param[TYPE_ADDMUL_6];
+  COPY (TYPE_ADDMUL_2);
+  p->msize = 6;
+  REFERENCE (refmpn_addmul_6);
+
+  p = &param[TYPE_ADDMUL_7];
+  COPY (TYPE_ADDMUL_2);
+  p->msize = 7;
+  REFERENCE (refmpn_addmul_7);
+
+  p = &param[TYPE_ADDMUL_8];
+  COPY (TYPE_ADDMUL_2);
+  p->msize = 8;
+  REFERENCE (refmpn_addmul_8);
+
+
+  p = &param[TYPE_AND_N];
+  p->dst[0] = 1;
+  p->src[0] = 1;
+  p->src[1] = 1;
+  REFERENCE (refmpn_and_n);
+
+  p = &param[TYPE_ANDN_N];
+  COPY (TYPE_AND_N);
+  REFERENCE (refmpn_andn_n);
+
+  p = &param[TYPE_NAND_N];
+  COPY (TYPE_AND_N);
+  REFERENCE (refmpn_nand_n);
+
+  p = &param[TYPE_IOR_N];
+  COPY (TYPE_AND_N);
+  REFERENCE (refmpn_ior_n);
+
+  p = &param[TYPE_IORN_N];
+  COPY (TYPE_AND_N);
+  REFERENCE (refmpn_iorn_n);
+
+  p = &param[TYPE_NIOR_N];
+  COPY (TYPE_AND_N);
+  REFERENCE (refmpn_nior_n);
+
+  p = &param[TYPE_XOR_N];
+  COPY (TYPE_AND_N);
+  REFERENCE (refmpn_xor_n);
+
+  p = &param[TYPE_XNOR_N];
+  COPY (TYPE_AND_N);
+  REFERENCE (refmpn_xnor_n);
+
+
+  p = &param[TYPE_ADDSUB_N];
+  p->retval = 1;
+  p->dst[0] = 1;
+  p->dst[1] = 1;
+  p->src[0] = 1;
+  p->src[1] = 1;
+  REFERENCE (refmpn_add_n_sub_n);
+
+  p = &param[TYPE_ADDSUB_NC];
+  COPY (TYPE_ADDSUB_N);
+  p->carry = CARRY_4;
+  REFERENCE (refmpn_add_n_sub_nc);
+
+
+  p = &param[TYPE_COPY];
+  p->dst[0] = 1;
+  p->src[0] = 1;
+  p->overlap = OVERLAP_NONE;
+  p->size = SIZE_ALLOW_ZERO;
+  REFERENCE (refmpn_copy);
+
+  p = &param[TYPE_COPYI];
+  p->dst[0] = 1;
+  p->src[0] = 1;
+  p->overlap = OVERLAP_LOW_TO_HIGH;
+  p->size = SIZE_ALLOW_ZERO;
+  REFERENCE (refmpn_copyi);
+
+  p = &param[TYPE_COPYD];
+  p->dst[0] = 1;
+  p->src[0] = 1;
+  p->overlap = OVERLAP_HIGH_TO_LOW;
+  p->size = SIZE_ALLOW_ZERO;
+  REFERENCE (refmpn_copyd);
+
+  p = &param[TYPE_COM];
+  p->dst[0] = 1;
+  p->src[0] = 1;
+  REFERENCE (refmpn_com);
+
+
+  p = &param[TYPE_ADDLSH1_N];
+  COPY (TYPE_ADD_N);
+  REFERENCE (refmpn_addlsh1_n);
+
+  p = &param[TYPE_ADDLSH2_N];
+  COPY (TYPE_ADD_N);
+  REFERENCE (refmpn_addlsh2_n);
+
+  p = &param[TYPE_ADDLSH_N];
+  COPY (TYPE_ADD_N);
+  p->shift = 1;
+  REFERENCE (refmpn_addlsh_n);
+
+  p = &param[TYPE_ADDLSH1_N_IP1];
+  p->retval = 1;
+  p->dst[0] = 1;
+  p->src[0] = 1;
+  p->dst0_from_src1 = 1;
+  REFERENCE (refmpn_addlsh1_n_ip1);
+
+  p = &param[TYPE_ADDLSH2_N_IP1];
+  COPY (TYPE_ADDLSH1_N_IP1);
+  REFERENCE (refmpn_addlsh2_n_ip1);
+
+  p = &param[TYPE_ADDLSH_N_IP1];
+  COPY (TYPE_ADDLSH1_N_IP1);
+  p->shift = 1;
+  REFERENCE (refmpn_addlsh_n_ip1);
+
+  p = &param[TYPE_ADDLSH1_N_IP2];
+  COPY (TYPE_ADDLSH1_N_IP1);
+  REFERENCE (refmpn_addlsh1_n_ip2);
+
+  p = &param[TYPE_ADDLSH2_N_IP2];
+  COPY (TYPE_ADDLSH1_N_IP1);
+  REFERENCE (refmpn_addlsh2_n_ip2);
+
+  p = &param[TYPE_ADDLSH_N_IP2];
+  COPY (TYPE_ADDLSH_N_IP1);
+  REFERENCE (refmpn_addlsh_n_ip2);
+
+  p = &param[TYPE_SUBLSH1_N];
+  COPY (TYPE_ADD_N);
+  REFERENCE (refmpn_sublsh1_n);
+
+  p = &param[TYPE_SUBLSH2_N];
+  COPY (TYPE_ADD_N);
+  REFERENCE (refmpn_sublsh2_n);
+
+  p = &param[TYPE_SUBLSH_N];
+  COPY (TYPE_ADDLSH_N);
+  REFERENCE (refmpn_sublsh_n);
+
+  p = &param[TYPE_SUBLSH1_N_IP1];
+  COPY (TYPE_ADDLSH1_N_IP1);
+  REFERENCE (refmpn_sublsh1_n_ip1);
+
+  p = &param[TYPE_SUBLSH2_N_IP1];
+  COPY (TYPE_ADDLSH1_N_IP1);
+  REFERENCE (refmpn_sublsh2_n_ip1);
+
+  p = &param[TYPE_SUBLSH_N_IP1];
+  COPY (TYPE_ADDLSH_N_IP1);
+  REFERENCE (refmpn_sublsh_n_ip1);
+
+  p = &param[TYPE_RSBLSH1_N];
+  COPY (TYPE_ADD_N);
+  REFERENCE (refmpn_rsblsh1_n);
+
+  p = &param[TYPE_RSBLSH2_N];
+  COPY (TYPE_ADD_N);
+  REFERENCE (refmpn_rsblsh2_n);
+
+  p = &param[TYPE_RSBLSH_N];
+  COPY (TYPE_ADDLSH_N);
+  REFERENCE (refmpn_rsblsh_n);
+
+  p = &param[TYPE_RSH1ADD_N];
+  COPY (TYPE_ADD_N);
+  REFERENCE (refmpn_rsh1add_n);
+
+  p = &param[TYPE_RSH1SUB_N];
+  COPY (TYPE_ADD_N);
+  REFERENCE (refmpn_rsh1sub_n);
+
+
+  p = &param[TYPE_ADDLSH1_NC];
+  COPY (TYPE_ADDLSH1_N);
+  p->carry = CARRY_3;
+  REFERENCE (refmpn_addlsh1_nc);
+
+  p = &param[TYPE_ADDLSH2_NC];
+  COPY (TYPE_ADDLSH2_N);
+  p->carry = CARRY_4; /* FIXME */
+  REFERENCE (refmpn_addlsh2_nc);
+
+  p = &param[TYPE_ADDLSH_NC];
+  COPY (TYPE_ADDLSH_N);
+  p->carry = CARRY_BIT; /* FIXME */
+  REFERENCE (refmpn_addlsh_nc);
+
+  p = &param[TYPE_SUBLSH1_NC];
+  COPY (TYPE_ADDLSH1_NC);
+  REFERENCE (refmpn_sublsh1_nc);
+
+  p = &param[TYPE_SUBLSH2_NC];
+  COPY (TYPE_ADDLSH2_NC);
+  REFERENCE (refmpn_sublsh2_nc);
+
+  p = &param[TYPE_SUBLSH_NC];
+  COPY (TYPE_ADDLSH_NC);
+  REFERENCE (refmpn_sublsh_nc);
+
+  p = &param[TYPE_RSBLSH1_NC];
+  COPY (TYPE_RSBLSH1_N);
+  p->carry = CARRY_BIT; /* FIXME */
+  REFERENCE (refmpn_rsblsh1_nc);
+
+  p = &param[TYPE_RSBLSH2_NC];
+  COPY (TYPE_RSBLSH2_N);
+  p->carry = CARRY_4; /* FIXME */
+  REFERENCE (refmpn_rsblsh2_nc);
+
+  p = &param[TYPE_RSBLSH_NC];
+  COPY (TYPE_RSBLSH_N);
+  p->carry = CARRY_BIT; /* FIXME */
+  REFERENCE (refmpn_rsblsh_nc);
+
+
+  p = &param[TYPE_MOD_1];
+  p->retval = 1;
+  p->src[0] = 1;
+  p->size = SIZE_ALLOW_ZERO;
+  p->divisor = DIVISOR_LIMB;
+  REFERENCE (refmpn_mod_1);
+
+  p = &param[TYPE_MOD_1C];
+  COPY (TYPE_MOD_1);
+  p->carry = CARRY_DIVISOR;
+  REFERENCE (refmpn_mod_1c);
+
+  p = &param[TYPE_DIVMOD_1];
+  COPY (TYPE_MOD_1);
+  p->dst[0] = 1;
+  REFERENCE (refmpn_divmod_1);
+
+  p = &param[TYPE_DIVMOD_1C];
+  COPY (TYPE_DIVMOD_1);
+  p->carry = CARRY_DIVISOR;
+  REFERENCE (refmpn_divmod_1c);
+
+  p = &param[TYPE_DIVREM_1];
+  COPY (TYPE_DIVMOD_1);
+  p->size2 = SIZE_FRACTION;
+  p->dst_size[0] = SIZE_SUM;
+  REFERENCE (refmpn_divrem_1);
+
+  p = &param[TYPE_DIVREM_1C];
+  COPY (TYPE_DIVREM_1);
+  p->carry = CARRY_DIVISOR;
+  REFERENCE (refmpn_divrem_1c);
+
+  p = &param[TYPE_PREINV_DIVREM_1];
+  COPY (TYPE_DIVREM_1);
+  p->size = SIZE_YES; /* ie. no size==0 */
+  REFERENCE (refmpn_preinv_divrem_1);
+
+  p = &param[TYPE_DIV_QR_1N_PI1];
+  p->retval = 1;
+  p->src[0] = 1;
+  p->src[1] = 1;
+  /* SIZE_1 not supported. Always uses low limb only. */
+  p->size2 = 1;
+  p->dst[0] = 1;
+  p->divisor = DIVISOR_NORM;
+  p->data = DATA_DIV_QR_1;
+  VALIDATE (validate_div_qr_1_pi1);
+
+  p = &param[TYPE_PREINV_MOD_1];
+  p->retval = 1;
+  p->src[0] = 1;
+  p->divisor = DIVISOR_NORM;
+  REFERENCE (refmpn_preinv_mod_1);
+
+  p = &param[TYPE_MOD_34LSUB1];
+  p->retval = 1;
+  p->src[0] = 1;
+  VALIDATE (validate_mod_34lsub1);
+
+  p = &param[TYPE_UDIV_QRNND];
+  p->retval = 1;
+  p->src[0] = 1;
+  p->dst[0] = 1;
+  p->dst_size[0] = SIZE_1;
+  p->divisor = UDIV_NEEDS_NORMALIZATION ? DIVISOR_NORM : DIVISOR_LIMB;
+  p->data = DATA_UDIV_QRNND;
+  p->overlap = OVERLAP_NONE;
+  REFERENCE (refmpn_udiv_qrnnd);
+
+  p = &param[TYPE_UDIV_QRNND_R];
+  COPY (TYPE_UDIV_QRNND);
+  REFERENCE (refmpn_udiv_qrnnd_r);
+
+
+  p = &param[TYPE_DIVEXACT_1];
+  p->dst[0] = 1;
+  p->src[0] = 1;
+  p->divisor = DIVISOR_LIMB;
+  p->data = DATA_MULTIPLE_DIVISOR;
+  VALIDATE (validate_divexact_1);
+  REFERENCE (refmpn_divmod_1);
+
+  p = &param[TYPE_BDIV_Q_1];
+  p->dst[0] = 1;
+  p->src[0] = 1;
+  p->divisor = DIVISOR_LIMB;
+  VALIDATE (validate_bdiv_q_1);
+
+  p = &param[TYPE_DIVEXACT_BY3];
+  p->retval = 1;
+  p->dst[0] = 1;
+  p->src[0] = 1;
+  REFERENCE (refmpn_divexact_by3);
+
+  p = &param[TYPE_DIVEXACT_BY3C];
+  COPY (TYPE_DIVEXACT_BY3);
+  p->carry = CARRY_3;
+  REFERENCE (refmpn_divexact_by3c);
+
+
+  p = &param[TYPE_MODEXACT_1_ODD];
+  p->retval = 1;
+  p->src[0] = 1;
+  p->divisor = DIVISOR_ODD;
+  VALIDATE (validate_modexact_1_odd);
+
+  p = &param[TYPE_MODEXACT_1C_ODD];
+  COPY (TYPE_MODEXACT_1_ODD);
+  p->carry = CARRY_LIMB;
+  VALIDATE (validate_modexact_1c_odd);
+
+
+  p = &param[TYPE_GCD_1];
+  p->retval = 1;
+  p->src[0] = 1;
+  p->data = DATA_NON_ZERO;
+  p->divisor = DIVISOR_LIMB;
+  REFERENCE (refmpn_gcd_1);
+
+  p = &param[TYPE_GCD];
+  p->retval = 1;
+  p->dst[0] = 1;
+  p->src[0] = 1;
+  p->src[1] = 1;
+  p->size2 = 1;
+  p->dst_size[0] = SIZE_RETVAL;
+  p->overlap = OVERLAP_NOT_SRCS;
+  p->data = DATA_GCD;
+  REFERENCE (refmpn_gcd);
+
+
+  p = &param[TYPE_MPZ_LEGENDRE];
+  p->retval = 1;
+  p->src[0] = 1;
+  p->size = SIZE_ALLOW_ZERO;
+  p->src[1] = 1;
+  p->data = DATA_SRC1_ODD_PRIME;
+  p->size2 = 1;
+  p->carry = CARRY_BIT;
+  p->carry_sign = 1;
+  REFERENCE (refmpz_legendre);
+
+  p = &param[TYPE_MPZ_JACOBI];
+  p->retval = 1;
+  p->src[0] = 1;
+  p->size = SIZE_ALLOW_ZERO;
+  p->src[1] = 1;
+  p->data = DATA_SRC1_ODD;
+  p->size2 = 1;
+  p->carry = CARRY_BIT;
+  p->carry_sign = 1;
+  REFERENCE (refmpz_jacobi);
+
+  p = &param[TYPE_MPZ_KRONECKER];
+  p->retval = 1;
+  p->src[0] = 1;
+  p->size = SIZE_ALLOW_ZERO;
+  p->src[1] = 1;
+  p->data = 0;
+  p->size2 = 1;
+  p->carry = CARRY_4;
+  p->carry_sign = 1;
+  REFERENCE (refmpz_kronecker);
+
+
+  p = &param[TYPE_MPZ_KRONECKER_UI];
+  p->retval = 1;
+  p->src[0] = 1;
+  p->size = SIZE_ALLOW_ZERO;
+  p->multiplier = 1;
+  p->carry = CARRY_BIT;
+  REFERENCE (refmpz_kronecker_ui);
+
+  p = &param[TYPE_MPZ_KRONECKER_SI];
+  COPY (TYPE_MPZ_KRONECKER_UI);
+  REFERENCE (refmpz_kronecker_si);
+
+  p = &param[TYPE_MPZ_UI_KRONECKER];
+  COPY (TYPE_MPZ_KRONECKER_UI);
+  REFERENCE (refmpz_ui_kronecker);
+
+  p = &param[TYPE_MPZ_SI_KRONECKER];
+  COPY (TYPE_MPZ_KRONECKER_UI);
+  REFERENCE (refmpz_si_kronecker);
+
+
+  p = &param[TYPE_SQR];
+  p->dst[0] = 1;
+  p->src[0] = 1;
+  p->dst_size[0] = SIZE_SUM;
+  p->overlap = OVERLAP_NONE;
+  REFERENCE (refmpn_sqr);
+
+  p = &param[TYPE_MUL_N];
+  COPY (TYPE_SQR);
+  p->src[1] = 1;
+  REFERENCE (refmpn_mul_n);
+
+  p = &param[TYPE_MULLO_N];
+  COPY (TYPE_MUL_N);
+  p->dst_size[0] = 0;
+  REFERENCE (refmpn_mullo_n);
+
+  p = &param[TYPE_SQRLO];
+  COPY (TYPE_SQR);
+  p->dst_size[0] = 0;
+  REFERENCE (refmpn_sqrlo);
+
+  p = &param[TYPE_MUL_MN];
+  COPY (TYPE_MUL_N);
+  p->size2 = 1;
+  REFERENCE (refmpn_mul_basecase);
+
+  p = &param[TYPE_MULMID_MN];
+  COPY (TYPE_MUL_MN);
+  p->dst_size[0] = SIZE_DIFF_PLUS_3;
+  REFERENCE (refmpn_mulmid_basecase);
+
+  p = &param[TYPE_MULMID_N];
+  COPY (TYPE_MUL_N);
+  p->size = SIZE_ODD;
+  p->size2 = SIZE_CEIL_HALF;
+  p->dst_size[0] = SIZE_DIFF_PLUS_3;
+  REFERENCE (refmpn_mulmid_n);
+
+  p = &param[TYPE_UMUL_PPMM];
+  p->retval = 1;
+  p->src[0] = 1;
+  p->dst[0] = 1;
+  p->dst_size[0] = SIZE_1;
+  p->overlap = OVERLAP_NONE;
+  REFERENCE (refmpn_umul_ppmm);
+
+  p = &param[TYPE_UMUL_PPMM_R];
+  COPY (TYPE_UMUL_PPMM);
+  REFERENCE (refmpn_umul_ppmm_r);
+
+
+  p = &param[TYPE_RSHIFT];
+  p->retval = 1;
+  p->dst[0] = 1;
+  p->src[0] = 1;
+  p->shift = 1;
+  p->overlap = OVERLAP_LOW_TO_HIGH;
+  REFERENCE (refmpn_rshift);
+
+  p = &param[TYPE_LSHIFT];
+  COPY (TYPE_RSHIFT);
+  p->overlap = OVERLAP_HIGH_TO_LOW;
+  REFERENCE (refmpn_lshift);
+
+  p = &param[TYPE_LSHIFTC];
+  COPY (TYPE_RSHIFT);
+  p->overlap = OVERLAP_HIGH_TO_LOW;
+  REFERENCE (refmpn_lshiftc);
+
+
+  p = &param[TYPE_POPCOUNT];
+  p->retval = 1;
+  p->src[0] = 1;
+  REFERENCE (refmpn_popcount);
+
+  p = &param[TYPE_HAMDIST];
+  COPY (TYPE_POPCOUNT);
+  p->src[1] = 1;
+  REFERENCE (refmpn_hamdist);
+
+
+  p = &param[TYPE_SBPI1_DIV_QR];
+  p->retval = 1;
+  p->dst[0] = 1;
+  p->dst[1] = 1;
+  p->src[0] = 1;
+  p->src[1] = 1;
+  p->data = DATA_SRC1_HIGHBIT;
+  p->size2 = 1;
+  p->dst_size[0] = SIZE_DIFF;
+  p->overlap = OVERLAP_NONE;
+  REFERENCE (refmpn_sb_div_qr);
+
+  p = &param[TYPE_TDIV_QR];
+  p->dst[0] = 1;
+  p->dst[1] = 1;
+  p->src[0] = 1;
+  p->src[1] = 1;
+  p->size2 = 1;
+  p->dst_size[0] = SIZE_DIFF_PLUS_1;
+  p->dst_size[1] = SIZE_SIZE2;
+  p->overlap = OVERLAP_NONE;
+  REFERENCE (refmpn_tdiv_qr);
+
+  p = &param[TYPE_SQRTREM];
+  p->retval = 1;
+  p->dst[0] = 1;
+  p->dst[1] = 1;
+  p->src[0] = 1;
+  p->dst_size[0] = SIZE_CEIL_HALF;
+  p->dst_size[1] = SIZE_RETVAL;
+  p->overlap = OVERLAP_NONE;
+  VALIDATE (validate_sqrtrem);
+  REFERENCE (refmpn_sqrtrem);
+
+  p = &param[TYPE_SQRT];
+  p->retval = 1;
+  p->dst[0] = 1;
+  p->dst[1] = 0;
+  p->src[0] = 1;
+  p->dst_size[0] = SIZE_CEIL_HALF;
+  p->overlap = OVERLAP_NONE;
+  VALIDATE (validate_sqrt);
+
+  p = &param[TYPE_ZERO];
+  p->dst[0] = 1;
+  p->size = SIZE_ALLOW_ZERO;
+  REFERENCE (refmpn_zero);
+
+  p = &param[TYPE_GET_STR];
+  p->retval = 1;
+  p->src[0] = 1;
+  p->size = SIZE_ALLOW_ZERO;
+  p->dst[0] = 1;
+  p->dst[1] = 1;
+  p->dst_size[0] = SIZE_GET_STR;
+  p->dst_bytes[0] = 1;
+  p->overlap = OVERLAP_NONE;
+  REFERENCE (refmpn_get_str);
+
+  p = &param[TYPE_BINVERT];
+  p->dst[0] = 1;
+  p->src[0] = 1;
+  p->data = DATA_SRC0_ODD;
+  p->overlap = OVERLAP_NONE;
+  REFERENCE (refmpn_binvert);
+
+  p = &param[TYPE_INVERT];
+  p->dst[0] = 1;
+  p->src[0] = 1;
+  p->data = DATA_SRC0_HIGHBIT;
+  p->overlap = OVERLAP_NONE;
+  REFERENCE (refmpn_invert);
+
+#ifdef EXTRA_PARAM_INIT
+  EXTRA_PARAM_INIT
+#endif
+}
+
+
+/* The following are macros if there's no native versions, so wrap them in
+   functions that can be in try_array[]. */
+
+void
+MPN_COPY_fun (mp_ptr rp, mp_srcptr sp, mp_size_t size)
+{ MPN_COPY (rp, sp, size); }
+
+void
+MPN_COPY_INCR_fun (mp_ptr rp, mp_srcptr sp, mp_size_t size)
+{ MPN_COPY_INCR (rp, sp, size); }
+
+void
+MPN_COPY_DECR_fun (mp_ptr rp, mp_srcptr sp, mp_size_t size)
+{ MPN_COPY_DECR (rp, sp, size); }
+
+void
+__GMPN_COPY_fun (mp_ptr rp, mp_srcptr sp, mp_size_t size)
+{ __GMPN_COPY (rp, sp, size); }
+
+#ifdef __GMPN_COPY_INCR
+void
+__GMPN_COPY_INCR_fun (mp_ptr rp, mp_srcptr sp, mp_size_t size)
+{ __GMPN_COPY_INCR (rp, sp, size); }
+#endif
+
+void
+mpn_com_fun (mp_ptr rp, mp_srcptr sp, mp_size_t size)
+{ mpn_com (rp, sp, size); }
+
+void
+mpn_and_n_fun (mp_ptr rp, mp_srcptr s1, mp_srcptr s2, mp_size_t size)
+{ mpn_and_n (rp, s1, s2, size); }
+
+void
+mpn_andn_n_fun (mp_ptr rp, mp_srcptr s1, mp_srcptr s2, mp_size_t size)
+{ mpn_andn_n (rp, s1, s2, size); }
+
+void
+mpn_nand_n_fun (mp_ptr rp, mp_srcptr s1, mp_srcptr s2, mp_size_t size)
+{ mpn_nand_n (rp, s1, s2, size); }
+
+void
+mpn_ior_n_fun (mp_ptr rp, mp_srcptr s1, mp_srcptr s2, mp_size_t size)
+{ mpn_ior_n (rp, s1, s2, size); }
+
+void
+mpn_iorn_n_fun (mp_ptr rp, mp_srcptr s1, mp_srcptr s2, mp_size_t size)
+{ mpn_iorn_n (rp, s1, s2, size); }
+
+void
+mpn_nior_n_fun (mp_ptr rp, mp_srcptr s1, mp_srcptr s2, mp_size_t size)
+{ mpn_nior_n (rp, s1, s2, size); }
+
+void
+mpn_xor_n_fun (mp_ptr rp, mp_srcptr s1, mp_srcptr s2, mp_size_t size)
+{ mpn_xor_n (rp, s1, s2, size); }
+
+void
+mpn_xnor_n_fun (mp_ptr rp, mp_srcptr s1, mp_srcptr s2, mp_size_t size)
+{ mpn_xnor_n (rp, s1, s2, size); }
+
+mp_limb_t
+udiv_qrnnd_fun (mp_limb_t *remptr, mp_limb_t n1, mp_limb_t n0, mp_limb_t d)
+{
+  mp_limb_t  q;
+  udiv_qrnnd (q, *remptr, n1, n0, d);
+  return q;
+}
+
+mp_limb_t
+mpn_divexact_by3_fun (mp_ptr rp, mp_srcptr sp, mp_size_t size)
+{
+  return mpn_divexact_by3 (rp, sp, size);
+}
+
+#if HAVE_NATIVE_mpn_addlsh1_n_ip1
+mp_limb_t
+mpn_addlsh1_n_ip1_fun (mp_ptr rp, mp_srcptr sp, mp_size_t size)
+{
+  return mpn_addlsh1_n_ip1 (rp, sp, size);
+}
+#endif
+#if HAVE_NATIVE_mpn_addlsh2_n_ip1
+mp_limb_t
+mpn_addlsh2_n_ip1_fun (mp_ptr rp, mp_srcptr sp, mp_size_t size)
+{
+  return mpn_addlsh2_n_ip1 (rp, sp, size);
+}
+#endif
+#if HAVE_NATIVE_mpn_addlsh_n_ip1
+mp_limb_t
+mpn_addlsh_n_ip1_fun (mp_ptr rp, mp_srcptr sp, mp_size_t size, unsigned int sh)
+{
+  return mpn_addlsh_n_ip1 (rp, sp, size, sh);
+}
+#endif
+#if HAVE_NATIVE_mpn_addlsh1_n_ip2
+mp_limb_t
+mpn_addlsh1_n_ip2_fun (mp_ptr rp, mp_srcptr sp, mp_size_t size)
+{
+  return mpn_addlsh1_n_ip2 (rp, sp, size);
+}
+#endif
+#if HAVE_NATIVE_mpn_addlsh2_n_ip2
+mp_limb_t
+mpn_addlsh2_n_ip2_fun (mp_ptr rp, mp_srcptr sp, mp_size_t size)
+{
+  return mpn_addlsh2_n_ip2 (rp, sp, size);
+}
+#endif
+#if HAVE_NATIVE_mpn_addlsh_n_ip2
+mp_limb_t
+mpn_addlsh_n_ip2_fun (mp_ptr rp, mp_srcptr sp, mp_size_t size, unsigned int sh)
+{
+  return mpn_addlsh_n_ip2 (rp, sp, size, sh);
+}
+#endif
+#if HAVE_NATIVE_mpn_sublsh1_n_ip1
+mp_limb_t
+mpn_sublsh1_n_ip1_fun (mp_ptr rp, mp_srcptr sp, mp_size_t size)
+{
+  return mpn_sublsh1_n_ip1 (rp, sp, size);
+}
+#endif
+#if HAVE_NATIVE_mpn_sublsh2_n_ip1
+mp_limb_t
+mpn_sublsh2_n_ip1_fun (mp_ptr rp, mp_srcptr sp, mp_size_t size)
+{
+  return mpn_sublsh2_n_ip1 (rp, sp, size);
+}
+#endif
+#if HAVE_NATIVE_mpn_sublsh_n_ip1
+mp_limb_t
+mpn_sublsh_n_ip1_fun (mp_ptr rp, mp_srcptr sp, mp_size_t size, unsigned int sh)
+{
+  return mpn_sublsh_n_ip1 (rp, sp, size, sh);
+}
+#endif
+
+mp_limb_t
+mpn_modexact_1_odd_fun (mp_srcptr ptr, mp_size_t size, mp_limb_t divisor)
+{
+  return mpn_modexact_1_odd (ptr, size, divisor);
+}
+
+void
+mpn_toom22_mul_fun (mp_ptr dst, mp_srcptr src1, mp_srcptr src2, mp_size_t size)
+{
+  mp_ptr  tspace;
+  TMP_DECL;
+  TMP_MARK;
+  tspace = TMP_ALLOC_LIMBS (mpn_toom22_mul_itch (size, size));
+  mpn_toom22_mul (dst, src1, size, src2, size, tspace);
+  TMP_FREE;
+}
+void
+mpn_toom2_sqr_fun (mp_ptr dst, mp_srcptr src, mp_size_t size)
+{
+  mp_ptr tspace;
+  TMP_DECL;
+  TMP_MARK;
+  tspace = TMP_ALLOC_LIMBS (mpn_toom2_sqr_itch (size));
+  mpn_toom2_sqr (dst, src, size, tspace);
+  TMP_FREE;
+}
+void
+mpn_toom33_mul_fun (mp_ptr dst, mp_srcptr src1, mp_srcptr src2, mp_size_t size)
+{
+  mp_ptr  tspace;
+  TMP_DECL;
+  TMP_MARK;
+  tspace = TMP_ALLOC_LIMBS (mpn_toom33_mul_itch (size, size));
+  mpn_toom33_mul (dst, src1, size, src2, size, tspace);
+  TMP_FREE;
+}
+void
+mpn_toom3_sqr_fun (mp_ptr dst, mp_srcptr src, mp_size_t size)
+{
+  mp_ptr tspace;
+  TMP_DECL;
+  TMP_MARK;
+  tspace = TMP_ALLOC_LIMBS (mpn_toom3_sqr_itch (size));
+  mpn_toom3_sqr (dst, src, size, tspace);
+  TMP_FREE;
+}
+void
+mpn_toom44_mul_fun (mp_ptr dst, mp_srcptr src1, mp_srcptr src2, mp_size_t size)
+{
+  mp_ptr  tspace;
+  TMP_DECL;
+  TMP_MARK;
+  tspace = TMP_ALLOC_LIMBS (mpn_toom44_mul_itch (size, size));
+  mpn_toom44_mul (dst, src1, size, src2, size, tspace);
+  TMP_FREE;
+}
+void
+mpn_toom4_sqr_fun (mp_ptr dst, mp_srcptr src, mp_size_t size)
+{
+  mp_ptr tspace;
+  TMP_DECL;
+  TMP_MARK;
+  tspace = TMP_ALLOC_LIMBS (mpn_toom4_sqr_itch (size));
+  mpn_toom4_sqr (dst, src, size, tspace);
+  TMP_FREE;
+}
+
+void
+mpn_toom42_mulmid_fun (mp_ptr dst, mp_srcptr src1, mp_srcptr src2,
+		       mp_size_t size)
+{
+  mp_ptr  tspace;
+  mp_size_t n;
+  TMP_DECL;
+  TMP_MARK;
+  tspace = TMP_ALLOC_LIMBS (mpn_toom42_mulmid_itch (size));
+  mpn_toom42_mulmid (dst, src1, src2, size, tspace);
+  TMP_FREE;
+}
+
+mp_limb_t
+umul_ppmm_fun (mp_limb_t *lowptr, mp_limb_t m1, mp_limb_t m2)
+{
+  mp_limb_t  high;
+  umul_ppmm (high, *lowptr, m1, m2);
+  return high;
+}
+
+void
+MPN_ZERO_fun (mp_ptr ptr, mp_size_t size)
+{ MPN_ZERO (ptr, size); }
+
+mp_size_t
+mpn_sqrt_fun (mp_ptr dst, mp_srcptr src, mp_size_t size)
+{ return mpn_sqrtrem (dst, NULL, src, size); }
+
+struct choice_t {
+  const char  *name;
+  tryfun_t    function;
+  int         type;
+  mp_size_t   minsize;
+};
+
+#define TRY(fun)        #fun, (tryfun_t) fun
+#define TRY_FUNFUN(fun) #fun, (tryfun_t) fun##_fun
+
+const struct choice_t choice_array[] = {
+  { TRY(mpn_add),       TYPE_ADD    },
+  { TRY(mpn_sub),       TYPE_SUB    },
+
+  { TRY(mpn_add_n),     TYPE_ADD_N  },
+  { TRY(mpn_sub_n),     TYPE_SUB_N  },
+
+#if HAVE_NATIVE_mpn_add_nc
+  { TRY(mpn_add_nc),    TYPE_ADD_NC },
+#endif
+#if HAVE_NATIVE_mpn_sub_nc
+  { TRY(mpn_sub_nc),    TYPE_SUB_NC },
+#endif
+
+#if HAVE_NATIVE_mpn_add_n_sub_n
+  { TRY(mpn_add_n_sub_n),  TYPE_ADDSUB_N  },
+#endif
+#if HAVE_NATIVE_mpn_add_n_sub_nc
+  { TRY(mpn_add_n_sub_nc), TYPE_ADDSUB_NC },
+#endif
+
+  { TRY(mpn_add_err1_n),  TYPE_ADD_ERR1_N  },
+  { TRY(mpn_sub_err1_n),  TYPE_SUB_ERR1_N  },
+  { TRY(mpn_add_err2_n),  TYPE_ADD_ERR2_N  },
+  { TRY(mpn_sub_err2_n),  TYPE_SUB_ERR2_N  },
+  { TRY(mpn_add_err3_n),  TYPE_ADD_ERR3_N  },
+  { TRY(mpn_sub_err3_n),  TYPE_SUB_ERR3_N  },
+
+  { TRY(mpn_addmul_1),  TYPE_ADDMUL_1  },
+  { TRY(mpn_submul_1),  TYPE_SUBMUL_1  },
+#if HAVE_NATIVE_mpn_addmul_1c
+  { TRY(mpn_addmul_1c), TYPE_ADDMUL_1C },
+#endif
+#if HAVE_NATIVE_mpn_submul_1c
+  { TRY(mpn_submul_1c), TYPE_SUBMUL_1C },
+#endif
+
+#if HAVE_NATIVE_mpn_addmul_2
+  { TRY(mpn_addmul_2), TYPE_ADDMUL_2, 2 },
+#endif
+#if HAVE_NATIVE_mpn_addmul_3
+  { TRY(mpn_addmul_3), TYPE_ADDMUL_3, 3 },
+#endif
+#if HAVE_NATIVE_mpn_addmul_4
+  { TRY(mpn_addmul_4), TYPE_ADDMUL_4, 4 },
+#endif
+#if HAVE_NATIVE_mpn_addmul_5
+  { TRY(mpn_addmul_5), TYPE_ADDMUL_5, 5 },
+#endif
+#if HAVE_NATIVE_mpn_addmul_6
+  { TRY(mpn_addmul_6), TYPE_ADDMUL_6, 6 },
+#endif
+#if HAVE_NATIVE_mpn_addmul_7
+  { TRY(mpn_addmul_7), TYPE_ADDMUL_7, 7 },
+#endif
+#if HAVE_NATIVE_mpn_addmul_8
+  { TRY(mpn_addmul_8), TYPE_ADDMUL_8, 8 },
+#endif
+
+  { TRY_FUNFUN(mpn_com),  TYPE_COM },
+
+  { TRY_FUNFUN(MPN_COPY),      TYPE_COPY },
+  { TRY_FUNFUN(MPN_COPY_INCR), TYPE_COPYI },
+  { TRY_FUNFUN(MPN_COPY_DECR), TYPE_COPYD },
+
+  { TRY_FUNFUN(__GMPN_COPY),      TYPE_COPY },
+#ifdef __GMPN_COPY_INCR
+  { TRY_FUNFUN(__GMPN_COPY_INCR), TYPE_COPYI },
+#endif
+
+#if HAVE_NATIVE_mpn_copyi
+  { TRY(mpn_copyi), TYPE_COPYI },
+#endif
+#if HAVE_NATIVE_mpn_copyd
+  { TRY(mpn_copyd), TYPE_COPYD },
+#endif
+
+  { TRY(mpn_cnd_add_n), TYPE_ADDCND_N },
+  { TRY(mpn_cnd_sub_n), TYPE_SUBCND_N },
+#if HAVE_NATIVE_mpn_addlsh1_n == 1
+  { TRY(mpn_addlsh1_n), TYPE_ADDLSH1_N },
+#endif
+#if HAVE_NATIVE_mpn_addlsh2_n == 1
+  { TRY(mpn_addlsh2_n), TYPE_ADDLSH2_N },
+#endif
+#if HAVE_NATIVE_mpn_addlsh_n
+  { TRY(mpn_addlsh_n), TYPE_ADDLSH_N },
+#endif
+#if HAVE_NATIVE_mpn_addlsh1_n_ip1
+  { TRY_FUNFUN(mpn_addlsh1_n_ip1), TYPE_ADDLSH1_N_IP1 },
+#endif
+#if HAVE_NATIVE_mpn_addlsh2_n_ip1
+  { TRY_FUNFUN(mpn_addlsh2_n_ip1), TYPE_ADDLSH2_N_IP1 },
+#endif
+#if HAVE_NATIVE_mpn_addlsh_n_ip1
+  { TRY_FUNFUN(mpn_addlsh_n_ip1), TYPE_ADDLSH_N_IP1 },
+#endif
+#if HAVE_NATIVE_mpn_addlsh1_n_ip2
+  { TRY_FUNFUN(mpn_addlsh1_n_ip2), TYPE_ADDLSH1_N_IP2 },
+#endif
+#if HAVE_NATIVE_mpn_addlsh2_n_ip2
+  { TRY_FUNFUN(mpn_addlsh2_n_ip2), TYPE_ADDLSH2_N_IP2 },
+#endif
+#if HAVE_NATIVE_mpn_addlsh_n_ip2
+  { TRY_FUNFUN(mpn_addlsh_n_ip2), TYPE_ADDLSH_N_IP2 },
+#endif
+#if HAVE_NATIVE_mpn_sublsh1_n == 1
+  { TRY(mpn_sublsh1_n), TYPE_SUBLSH1_N },
+#endif
+#if HAVE_NATIVE_mpn_sublsh2_n == 1
+  { TRY(mpn_sublsh2_n), TYPE_SUBLSH2_N },
+#endif
+#if HAVE_NATIVE_mpn_sublsh_n
+  { TRY(mpn_sublsh_n), TYPE_SUBLSH_N },
+#endif
+#if HAVE_NATIVE_mpn_sublsh1_n_ip1
+  { TRY_FUNFUN(mpn_sublsh1_n_ip1), TYPE_SUBLSH1_N_IP1 },
+#endif
+#if HAVE_NATIVE_mpn_sublsh2_n_ip1
+  { TRY_FUNFUN(mpn_sublsh2_n_ip1), TYPE_SUBLSH2_N_IP1 },
+#endif
+#if HAVE_NATIVE_mpn_sublsh_n_ip1
+  { TRY_FUNFUN(mpn_sublsh_n_ip1), TYPE_SUBLSH_N_IP1 },
+#endif
+#if HAVE_NATIVE_mpn_rsblsh1_n == 1
+  { TRY(mpn_rsblsh1_n), TYPE_RSBLSH1_N },
+#endif
+#if HAVE_NATIVE_mpn_rsblsh2_n == 1
+  { TRY(mpn_rsblsh2_n), TYPE_RSBLSH2_N },
+#endif
+#if HAVE_NATIVE_mpn_rsblsh_n
+  { TRY(mpn_rsblsh_n), TYPE_RSBLSH_N },
+#endif
+#if HAVE_NATIVE_mpn_rsh1add_n
+  { TRY(mpn_rsh1add_n), TYPE_RSH1ADD_N },
+#endif
+#if HAVE_NATIVE_mpn_rsh1sub_n
+  { TRY(mpn_rsh1sub_n), TYPE_RSH1SUB_N },
+#endif
+
+#if HAVE_NATIVE_mpn_addlsh1_nc == 1
+  { TRY(mpn_addlsh1_nc), TYPE_ADDLSH1_NC },
+#endif
+#if HAVE_NATIVE_mpn_addlsh2_nc == 1
+  { TRY(mpn_addlsh2_nc), TYPE_ADDLSH2_NC },
+#endif
+#if HAVE_NATIVE_mpn_addlsh_nc
+  { TRY(mpn_addlsh_nc), TYPE_ADDLSH_NC },
+#endif
+#if HAVE_NATIVE_mpn_sublsh1_nc == 1
+  { TRY(mpn_sublsh1_nc), TYPE_SUBLSH1_NC },
+#endif
+#if HAVE_NATIVE_mpn_sublsh2_nc == 1
+  { TRY(mpn_sublsh2_nc), TYPE_SUBLSH2_NC },
+#endif
+#if HAVE_NATIVE_mpn_sublsh_nc
+  { TRY(mpn_sublsh_nc), TYPE_SUBLSH_NC },
+#endif
+#if HAVE_NATIVE_mpn_rsblsh1_nc
+  { TRY(mpn_rsblsh1_nc), TYPE_RSBLSH1_NC },
+#endif
+#if HAVE_NATIVE_mpn_rsblsh2_nc
+  { TRY(mpn_rsblsh2_nc), TYPE_RSBLSH2_NC },
+#endif
+#if HAVE_NATIVE_mpn_rsblsh_nc
+  { TRY(mpn_rsblsh_nc), TYPE_RSBLSH_NC },
+#endif
+
+  { TRY_FUNFUN(mpn_and_n),  TYPE_AND_N  },
+  { TRY_FUNFUN(mpn_andn_n), TYPE_ANDN_N },
+  { TRY_FUNFUN(mpn_nand_n), TYPE_NAND_N },
+  { TRY_FUNFUN(mpn_ior_n),  TYPE_IOR_N  },
+  { TRY_FUNFUN(mpn_iorn_n), TYPE_IORN_N },
+  { TRY_FUNFUN(mpn_nior_n), TYPE_NIOR_N },
+  { TRY_FUNFUN(mpn_xor_n),  TYPE_XOR_N  },
+  { TRY_FUNFUN(mpn_xnor_n), TYPE_XNOR_N },
+
+  { TRY(mpn_divrem_1),     TYPE_DIVREM_1 },
+#if USE_PREINV_DIVREM_1
+  { TRY(mpn_preinv_divrem_1), TYPE_PREINV_DIVREM_1 },
+#endif
+  { TRY(mpn_mod_1),        TYPE_MOD_1 },
+#if USE_PREINV_MOD_1
+  { TRY(mpn_preinv_mod_1), TYPE_PREINV_MOD_1 },
+#endif
+#if HAVE_NATIVE_mpn_divrem_1c
+  { TRY(mpn_divrem_1c),    TYPE_DIVREM_1C },
+#endif
+#if HAVE_NATIVE_mpn_mod_1c
+  { TRY(mpn_mod_1c),       TYPE_MOD_1C },
+#endif
+  { TRY(mpn_div_qr_1n_pi1), TYPE_DIV_QR_1N_PI1 },
+#if GMP_NUMB_BITS % 4 == 0
+  { TRY(mpn_mod_34lsub1),  TYPE_MOD_34LSUB1 },
+#endif
+
+  { TRY_FUNFUN(udiv_qrnnd), TYPE_UDIV_QRNND, 2 },
+#if HAVE_NATIVE_mpn_udiv_qrnnd
+  { TRY(mpn_udiv_qrnnd),    TYPE_UDIV_QRNND, 2 },
+#endif
+#if HAVE_NATIVE_mpn_udiv_qrnnd_r
+  { TRY(mpn_udiv_qrnnd_r),  TYPE_UDIV_QRNND_R, 2 },
+#endif
+
+  { TRY(mpn_divexact_1),          TYPE_DIVEXACT_1 },
+  { TRY(mpn_bdiv_q_1),            TYPE_BDIV_Q_1 },
+  { TRY_FUNFUN(mpn_divexact_by3), TYPE_DIVEXACT_BY3 },
+  { TRY(mpn_divexact_by3c),       TYPE_DIVEXACT_BY3C },
+
+  { TRY_FUNFUN(mpn_modexact_1_odd), TYPE_MODEXACT_1_ODD },
+  { TRY(mpn_modexact_1c_odd),       TYPE_MODEXACT_1C_ODD },
+
+
+  { TRY(mpn_sbpi1_div_qr), TYPE_SBPI1_DIV_QR, 3},
+  { TRY(mpn_tdiv_qr),      TYPE_TDIV_QR },
+
+  { TRY(mpn_mul_1),      TYPE_MUL_1 },
+#if HAVE_NATIVE_mpn_mul_1c
+  { TRY(mpn_mul_1c),     TYPE_MUL_1C },
+#endif
+#if HAVE_NATIVE_mpn_mul_2
+  { TRY(mpn_mul_2),      TYPE_MUL_2, 2 },
+#endif
+#if HAVE_NATIVE_mpn_mul_3
+  { TRY(mpn_mul_3),      TYPE_MUL_3, 3 },
+#endif
+#if HAVE_NATIVE_mpn_mul_4
+  { TRY(mpn_mul_4),      TYPE_MUL_4, 4 },
+#endif
+#if HAVE_NATIVE_mpn_mul_5
+  { TRY(mpn_mul_5),      TYPE_MUL_5, 5 },
+#endif
+#if HAVE_NATIVE_mpn_mul_6
+  { TRY(mpn_mul_6),      TYPE_MUL_6, 6 },
+#endif
+
+  { TRY(mpn_rshift),     TYPE_RSHIFT },
+  { TRY(mpn_lshift),     TYPE_LSHIFT },
+  { TRY(mpn_lshiftc),    TYPE_LSHIFTC },
+
+
+  { TRY(mpn_mul_basecase), TYPE_MUL_MN },
+  { TRY(mpn_mulmid_basecase), TYPE_MULMID_MN },
+  { TRY(mpn_mullo_basecase), TYPE_MULLO_N },
+  { TRY(mpn_sqrlo_basecase), TYPE_SQRLO },
+  { TRY(mpn_sqrlo), TYPE_SQRLO },
+#if SQR_TOOM2_THRESHOLD > 0
+  { TRY(mpn_sqr_basecase), TYPE_SQR },
+#endif
+
+  { TRY(mpn_mul),    TYPE_MUL_MN },
+  { TRY(mpn_mul_n),  TYPE_MUL_N },
+  { TRY(mpn_sqr),    TYPE_SQR },
+
+  { TRY_FUNFUN(umul_ppmm), TYPE_UMUL_PPMM, 2 },
+#if HAVE_NATIVE_mpn_umul_ppmm
+  { TRY(mpn_umul_ppmm),    TYPE_UMUL_PPMM, 2 },
+#endif
+#if HAVE_NATIVE_mpn_umul_ppmm_r
+  { TRY(mpn_umul_ppmm_r),  TYPE_UMUL_PPMM_R, 2 },
+#endif
+
+  { TRY_FUNFUN(mpn_toom22_mul),  TYPE_MUL_N,  MPN_TOOM22_MUL_MINSIZE },
+  { TRY_FUNFUN(mpn_toom2_sqr),   TYPE_SQR,    MPN_TOOM2_SQR_MINSIZE },
+  { TRY_FUNFUN(mpn_toom33_mul),  TYPE_MUL_N,  MPN_TOOM33_MUL_MINSIZE },
+  { TRY_FUNFUN(mpn_toom3_sqr),   TYPE_SQR,    MPN_TOOM3_SQR_MINSIZE },
+  { TRY_FUNFUN(mpn_toom44_mul),  TYPE_MUL_N,  MPN_TOOM44_MUL_MINSIZE },
+  { TRY_FUNFUN(mpn_toom4_sqr),   TYPE_SQR,    MPN_TOOM4_SQR_MINSIZE },
+
+  { TRY(mpn_mulmid_n),  TYPE_MULMID_N, 1 },
+  { TRY(mpn_mulmid),  TYPE_MULMID_MN, 1 },
+  { TRY_FUNFUN(mpn_toom42_mulmid),  TYPE_MULMID_N,
+    (2 * MPN_TOOM42_MULMID_MINSIZE - 1) },
+
+  { TRY(mpn_gcd_1),        TYPE_GCD_1            },
+  { TRY(mpn_gcd),          TYPE_GCD              },
+  { TRY(mpz_legendre),     TYPE_MPZ_LEGENDRE     },
+  { TRY(mpz_jacobi),       TYPE_MPZ_JACOBI       },
+  { TRY(mpz_kronecker),    TYPE_MPZ_KRONECKER    },
+  { TRY(mpz_kronecker_ui), TYPE_MPZ_KRONECKER_UI },
+  { TRY(mpz_kronecker_si), TYPE_MPZ_KRONECKER_SI },
+  { TRY(mpz_ui_kronecker), TYPE_MPZ_UI_KRONECKER },
+  { TRY(mpz_si_kronecker), TYPE_MPZ_SI_KRONECKER },
+
+  { TRY(mpn_popcount),   TYPE_POPCOUNT },
+  { TRY(mpn_hamdist),    TYPE_HAMDIST },
+
+  { TRY(mpn_sqrtrem),     TYPE_SQRTREM },
+  { TRY_FUNFUN(mpn_sqrt), TYPE_SQRT },
+
+  { TRY_FUNFUN(MPN_ZERO), TYPE_ZERO },
+
+  { TRY(mpn_get_str),    TYPE_GET_STR },
+
+  { TRY(mpn_binvert),    TYPE_BINVERT },
+  { TRY(mpn_invert),     TYPE_INVERT  },
+
+#ifdef EXTRA_ROUTINES
+  EXTRA_ROUTINES
+#endif
+};
+
+const struct choice_t *choice = NULL;
+
+
+void
+mprotect_maybe (void *addr, size_t len, int prot)
+{
+  if (!option_redzones)
+    return;
+
+#if HAVE_MPROTECT
+  if (mprotect (addr, len, prot) != 0)
+    {
+      fprintf (stderr, "Cannot mprotect %p 0x%X 0x%X: %s\n",
+	       addr, (unsigned) len, prot, strerror (errno));
+      exit (1);
+    }
+#else
+  {
+    static int  warned = 0;
+    if (!warned)
+      {
+	fprintf (stderr,
+		 "mprotect not available, bounds testing not performed\n");
+	warned = 1;
+      }
+  }
+#endif
+}
+
+/* round "a" up to a multiple of "m" */
+size_t
+round_up_multiple (size_t a, size_t m)
+{
+  unsigned long  r;
+
+  r = a % m;
+  if (r == 0)
+    return a;
+  else
+    return a + (m - r);
+}
+
+
+/* On some systems it seems that only an mmap'ed region can be mprotect'ed,
+   for instance HP-UX 10.
+
+   mmap will almost certainly return a pointer already aligned to a page
+   boundary, but it's easy enough to share the alignment handling with the
+   malloc case. */
+
+void
+malloc_region (struct region_t *r, mp_size_t n)
+{
+  mp_ptr  p;
+  size_t  nbytes;
+
+  ASSERT ((pagesize % GMP_LIMB_BYTES) == 0);
+
+  n = round_up_multiple (n, PAGESIZE_LIMBS);
+  r->size = n;
+
+  nbytes = n*GMP_LIMB_BYTES + 2*REDZONE_BYTES + pagesize;
+
+#if defined (MAP_ANONYMOUS) && ! defined (MAP_ANON)
+#define MAP_ANON  MAP_ANONYMOUS
+#endif
+
+#if HAVE_MMAP && defined (MAP_ANON)
+  /* note must pass fd=-1 for MAP_ANON on BSD */
+  p = (mp_ptr) mmap (NULL, nbytes, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
+  if (p == (void *) -1)
+    {
+      fprintf (stderr, "Cannot mmap %#x anon bytes: %s\n",
+	       (unsigned) nbytes, strerror (errno));
+      exit (1);
+    }
+#else
+  p = (mp_ptr) malloc (nbytes);
+  ASSERT_ALWAYS (p != NULL);
+#endif
+
+  p = (mp_ptr) align_pointer (p, pagesize);
+
+  mprotect_maybe (p, REDZONE_BYTES, PROT_NONE);
+  p += REDZONE_LIMBS;
+  r->ptr = p;
+
+  mprotect_maybe (p + n, REDZONE_BYTES, PROT_NONE);
+}
+
+void
+mprotect_region (const struct region_t *r, int prot)
+{
+  mprotect_maybe (r->ptr, r->size, prot);
+}
+
+
+/* First four entries must be 0,1,2,3 for the benefit of CARRY_BIT, CARRY_3,
+   and CARRY_4 */
+mp_limb_t  carry_array[] = {
+  0, 1, 2, 3,
+  4,
+  CNST_LIMB(1) << 8,
+  CNST_LIMB(1) << 16,
+  GMP_NUMB_MAX
+};
+int        carry_index;
+
+#define CARRY_COUNT                                             \
+  ((tr->carry == CARRY_BIT) ? 2                                 \
+   : tr->carry == CARRY_3   ? 3                                 \
+   : tr->carry == CARRY_4   ? 4                                 \
+   : (tr->carry == CARRY_LIMB || tr->carry == CARRY_DIVISOR)    \
+     ? numberof(carry_array) + CARRY_RANDOMS                    \
+   : 1)
+
+#define MPN_RANDOM_ALT(index,dst,size) \
+  (((index) & 1) ? refmpn_random (dst, size) : refmpn_random2 (dst, size))
+
+/* The dummy value after MPN_RANDOM_ALT ensures both sides of the ":" have
+   the same type */
+#define CARRY_ITERATION                                                 \
+  for (carry_index = 0;                                                 \
+       (carry_index < numberof (carry_array)                            \
+	? (carry = carry_array[carry_index])                            \
+	: (MPN_RANDOM_ALT (carry_index, &carry, 1), (mp_limb_t) 0)),    \
+	 (tr->carry == CARRY_DIVISOR ? carry %= divisor : 0),           \
+	 carry_index < CARRY_COUNT;                                     \
+       carry_index++)
+
+
+mp_limb_t  multiplier_array[] = {
+  0, 1, 2, 3,
+  CNST_LIMB(1) << 8,
+  CNST_LIMB(1) << 16,
+  GMP_NUMB_MAX - 2,
+  GMP_NUMB_MAX - 1,
+  GMP_NUMB_MAX
+};
+int        multiplier_index;
+
+mp_limb_t  divisor_array[] = {
+  1, 2, 3,
+  CNST_LIMB(1) << 8,
+  CNST_LIMB(1) << 16,
+  CNST_LIMB(1) << (GMP_NUMB_BITS/2 - 1),
+  GMP_NUMB_MAX >> (GMP_NUMB_BITS/2),
+  GMP_NUMB_HIGHBIT,
+  GMP_NUMB_HIGHBIT + 1,
+  GMP_NUMB_MAX - 2,
+  GMP_NUMB_MAX - 1,
+  GMP_NUMB_MAX
+};
+
+int        divisor_index;
+
+/* The dummy value after MPN_RANDOM_ALT ensures both sides of the ":" have
+   the same type */
+#define ARRAY_ITERATION(var, index, limit, array, randoms, cond)        \
+  for (index = 0;                                                       \
+       (index < numberof (array)                                        \
+	? (var = array[index])                                          \
+	: (MPN_RANDOM_ALT (index, &var, 1), (mp_limb_t) 0)),            \
+       index < limit;                                                   \
+       index++)
+
+#define MULTIPLIER_COUNT                                \
+  (tr->multiplier                                       \
+    ? numberof (multiplier_array) + MULTIPLIER_RANDOMS  \
+    : 1)
+
+#define MULTIPLIER_ITERATION                                            \
+  ARRAY_ITERATION(multiplier, multiplier_index, MULTIPLIER_COUNT,       \
+		  multiplier_array, MULTIPLIER_RANDOMS, TRY_MULTIPLIER)
+
+#define DIVISOR_COUNT                           \
+  (tr->divisor                                  \
+   ? numberof (divisor_array) + DIVISOR_RANDOMS \
+   : 1)
+
+#define DIVISOR_ITERATION                                               \
+  ARRAY_ITERATION(divisor, divisor_index, DIVISOR_COUNT, divisor_array, \
+		  DIVISOR_RANDOMS, TRY_DIVISOR)
+
+
+/* overlap_array[].s[i] is where s[i] should be, 0 or 1 means overlapping
+   d[0] or d[1] respectively, -1 means a separate (write-protected)
+   location. */
+
+struct overlap_t {
+  int  s[NUM_SOURCES];
+} overlap_array[] = {
+  { { -1, -1, -1, -1, -1 } },
+  { {  0, -1, -1, -1, -1 } },
+  { { -1,  0, -1, -1, -1 } },
+  { {  0,  0, -1, -1, -1 } },
+  { {  1, -1, -1, -1, -1 } },
+  { { -1,  1, -1, -1, -1 } },
+  { {  1,  1, -1, -1, -1 } },
+  { {  0,  1, -1, -1, -1 } },
+  { {  1,  0, -1, -1, -1 } },
+};
+
+struct overlap_t  *overlap, *overlap_limit;
+
+#define OVERLAP_COUNT                   \
+  (tr->overlap & OVERLAP_NONE       ? 1 \
+   : tr->overlap & OVERLAP_NOT_SRCS ? 3 \
+   : tr->overlap & OVERLAP_NOT_SRC2 ? 2 \
+   : tr->overlap & OVERLAP_NOT_DST2 ? 4	\
+   : tr->dst[1]                     ? 9 \
+   : tr->src[1]                     ? 4 \
+   : tr->dst[0]                     ? 2 \
+   : 1)
+
+#define OVERLAP_ITERATION                               \
+  for (overlap = &overlap_array[0],                     \
+    overlap_limit = &overlap_array[OVERLAP_COUNT];      \
+    overlap < overlap_limit;                            \
+    overlap++)
+
+
+int  base = 10;
+
+#define T_RAND_COUNT  2
+int  t_rand;
+
+void
+t_random (mp_ptr ptr, mp_size_t n)
+{
+  if (n == 0)
+    return;
+
+  switch (option_data) {
+  case DATA_TRAND:
+    switch (t_rand) {
+    case 0: refmpn_random (ptr, n); break;
+    case 1: refmpn_random2 (ptr, n); break;
+    default: abort();
+    }
+    break;
+  case DATA_SEQ:
+    {
+      static mp_limb_t  counter = 0;
+      mp_size_t  i;
+      for (i = 0; i < n; i++)
+	ptr[i] = ++counter;
+    }
+    break;
+  case DATA_ZEROS:
+    refmpn_zero (ptr, n);
+    break;
+  case DATA_FFS:
+    refmpn_fill (ptr, n, GMP_NUMB_MAX);
+    break;
+  case DATA_2FD:
+    /* Special value 0x2FFF...FFFD, which divided by 3 gives 0xFFF...FFF,
+       inducing the q1_ff special case in the mul-by-inverse part of some
+       versions of divrem_1 and mod_1. */
+    refmpn_fill (ptr, n, (mp_limb_t) -1);
+    ptr[n-1] = 2;
+    ptr[0] -= 2;
+    break;
+
+  default:
+    abort();
+  }
+}
+#define T_RAND_ITERATION \
+  for (t_rand = 0; t_rand < T_RAND_COUNT; t_rand++)
+
+
+void
+print_each (const struct each_t *e)
+{
+  int  i;
+
+  printf ("%s %s\n", e->name, e == &ref ? tr->reference_name : choice->name);
+  if (tr->retval)
+    mpn_trace ("   retval", &e->retval, 1);
+
+  for (i = 0; i < NUM_DESTS; i++)
+    {
+      if (tr->dst[i])
+	{
+	  if (tr->dst_bytes[i])
+	    byte_tracen ("   d[%d]", i, e->d[i].p, d[i].size);
+	  else
+	    mpn_tracen ("   d[%d]", i, e->d[i].p, d[i].size);
+	  printf ("        located %p\n", (void *) (e->d[i].p));
+	}
+    }
+
+  for (i = 0; i < NUM_SOURCES; i++)
+    if (tr->src[i])
+      printf ("   s[%d] located %p\n", i, (void *)  (e->s[i].p));
+}
+
+
+void
+print_all (void)
+{
+  int  i;
+
+  printf ("\n");
+  printf ("size  %ld\n", (long) size);
+  if (tr->size2)
+    printf ("size2 %ld\n", (long) size2);
+
+  for (i = 0; i < NUM_DESTS; i++)
+    if (d[i].size != size)
+      printf ("d[%d].size %ld\n", i, (long) d[i].size);
+
+  if (tr->multiplier)
+    mpn_trace ("   multiplier", &multiplier, 1);
+  if (tr->divisor)
+    mpn_trace ("   divisor", &divisor, 1);
+  if (tr->shift)
+    printf ("   shift %lu\n", shift);
+  if (tr->carry)
+    mpn_trace ("   carry", &carry, 1);
+  if (tr->msize)
+    mpn_trace ("   multiplier_N", multiplier_N, tr->msize);
+
+  for (i = 0; i < NUM_DESTS; i++)
+    if (tr->dst[i])
+      printf ("   d[%d] %s, align %ld, size %ld\n",
+	      i, d[i].high ? "high" : "low",
+	      (long) d[i].align, (long) d[i].size);
+
+  for (i = 0; i < NUM_SOURCES; i++)
+    {
+      if (tr->src[i])
+	{
+	  printf ("   s[%d] %s, align %ld, ",
+		  i, s[i].high ? "high" : "low", (long) s[i].align);
+	  switch (overlap->s[i]) {
+	  case -1:
+	    printf ("no overlap\n");
+	    break;
+	  default:
+	    printf ("==d[%d]%s\n",
+		    overlap->s[i],
+		    tr->overlap == OVERLAP_LOW_TO_HIGH ? "+a"
+		    : tr->overlap == OVERLAP_HIGH_TO_LOW ? "-a"
+		    : "");
+	    break;
+	  }
+	  printf ("   s[%d]=", i);
+	  if (tr->carry_sign && (carry & (1 << i)))
+	    printf ("-");
+	  mpn_trace (NULL, s[i].p, SRC_SIZE(i));
+	}
+    }
+
+  if (tr->dst0_from_src1)
+    mpn_trace ("   d[0]", s[1].region.ptr, size);
+
+  if (tr->reference)
+    print_each (&ref);
+  print_each (&fun);
+}
+
+void
+compare (void)
+{
+  int  error = 0;
+  int  i;
+
+  if (tr->retval && ref.retval != fun.retval)
+    {
+      gmp_printf ("Different return values (%Mu, %Mu)\n",
+		  ref.retval, fun.retval);
+      error = 1;
+    }
+
+  for (i = 0; i < NUM_DESTS; i++)
+    {
+      switch (tr->dst_size[i]) {
+      case SIZE_RETVAL:
+      case SIZE_GET_STR:
+	d[i].size = ref.retval;
+	break;
+      }
+    }
+
+  for (i = 0; i < NUM_DESTS; i++)
+    {
+      if (! tr->dst[i])
+	continue;
+
+      if (tr->dst_bytes[i])
+	{
+	  if (memcmp (ref.d[i].p, fun.d[i].p, d[i].size) != 0)
+	    {
+	      printf ("Different d[%d] data results, low diff at %ld, high diff at %ld\n",
+		      i,
+		      (long) byte_diff_lowest (ref.d[i].p, fun.d[i].p, d[i].size),
+		      (long) byte_diff_highest (ref.d[i].p, fun.d[i].p, d[i].size));
+	      error = 1;
+	    }
+	}
+      else
+	{
+	  if (d[i].size != 0
+	      && ! refmpn_equal_anynail (ref.d[i].p, fun.d[i].p, d[i].size))
+	    {
+	      printf ("Different d[%d] data results, low diff at %ld, high diff at %ld\n",
+		      i,
+		      (long) mpn_diff_lowest (ref.d[i].p, fun.d[i].p, d[i].size),
+		      (long) mpn_diff_highest (ref.d[i].p, fun.d[i].p, d[i].size));
+	      error = 1;
+	    }
+	}
+    }
+
+  if (error)
+    {
+      print_all();
+      abort();
+    }
+}
+
+
+/* The functions are cast if the return value should be a long rather than
+   the default mp_limb_t.  This is necessary under _LONG_LONG_LIMB.  This
+   might not be enough if some actual calling conventions checking is
+   implemented on a long long limb system.  */
+
+void
+call (struct each_t *e, tryfun_t function)
+{
+  switch (choice->type) {
+  case TYPE_ADD:
+  case TYPE_SUB:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->d[0].p, e->s[0].p, size, e->s[1].p, size2);
+    break;
+
+  case TYPE_ADD_N:
+  case TYPE_SUB_N:
+  case TYPE_ADDLSH1_N:
+  case TYPE_ADDLSH2_N:
+  case TYPE_SUBLSH1_N:
+  case TYPE_SUBLSH2_N:
+  case TYPE_RSBLSH1_N:
+  case TYPE_RSBLSH2_N:
+  case TYPE_RSH1ADD_N:
+  case TYPE_RSH1SUB_N:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->d[0].p, e->s[0].p, e->s[1].p, size);
+    break;
+  case TYPE_ADDLSH_N:
+  case TYPE_SUBLSH_N:
+  case TYPE_RSBLSH_N:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->d[0].p, e->s[0].p, e->s[1].p, size, shift);
+    break;
+  case TYPE_ADDLSH_NC:
+  case TYPE_SUBLSH_NC:
+  case TYPE_RSBLSH_NC:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->d[0].p, e->s[0].p, e->s[1].p, size, shift, carry);
+    break;
+  case TYPE_ADDLSH1_NC:
+  case TYPE_ADDLSH2_NC:
+  case TYPE_SUBLSH1_NC:
+  case TYPE_SUBLSH2_NC:
+  case TYPE_RSBLSH1_NC:
+  case TYPE_RSBLSH2_NC:
+  case TYPE_ADD_NC:
+  case TYPE_SUB_NC:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->d[0].p, e->s[0].p, e->s[1].p, size, carry);
+    break;
+  case TYPE_ADDCND_N:
+  case TYPE_SUBCND_N:
+    e->retval = CALLING_CONVENTIONS (function)
+      (carry, e->d[0].p, e->s[0].p, e->s[1].p, size);
+    break;
+  case TYPE_ADD_ERR1_N:
+  case TYPE_SUB_ERR1_N:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->d[0].p, e->s[0].p, e->s[1].p, e->d[1].p, e->s[2].p, size, carry);
+    break;
+  case TYPE_ADD_ERR2_N:
+  case TYPE_SUB_ERR2_N:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->d[0].p, e->s[0].p, e->s[1].p, e->d[1].p, e->s[2].p, e->s[3].p, size, carry);
+    break;
+  case TYPE_ADD_ERR3_N:
+  case TYPE_SUB_ERR3_N:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->d[0].p, e->s[0].p, e->s[1].p, e->d[1].p, e->s[2].p, e->s[3].p, e->s[4].p, size, carry);
+    break;
+
+  case TYPE_MUL_1:
+  case TYPE_ADDMUL_1:
+  case TYPE_SUBMUL_1:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->d[0].p, e->s[0].p, size, multiplier);
+    break;
+  case TYPE_MUL_1C:
+  case TYPE_ADDMUL_1C:
+  case TYPE_SUBMUL_1C:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->d[0].p, e->s[0].p, size, multiplier, carry);
+    break;
+
+  case TYPE_MUL_2:
+  case TYPE_MUL_3:
+  case TYPE_MUL_4:
+  case TYPE_MUL_5:
+  case TYPE_MUL_6:
+    if (size == 1)
+      abort ();
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->d[0].p, e->s[0].p, size, multiplier_N);
+    break;
+
+  case TYPE_ADDMUL_2:
+  case TYPE_ADDMUL_3:
+  case TYPE_ADDMUL_4:
+  case TYPE_ADDMUL_5:
+  case TYPE_ADDMUL_6:
+  case TYPE_ADDMUL_7:
+  case TYPE_ADDMUL_8:
+    if (size == 1)
+      abort ();
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->d[0].p, e->s[0].p, size, multiplier_N);
+    break;
+
+  case TYPE_AND_N:
+  case TYPE_ANDN_N:
+  case TYPE_NAND_N:
+  case TYPE_IOR_N:
+  case TYPE_IORN_N:
+  case TYPE_NIOR_N:
+  case TYPE_XOR_N:
+  case TYPE_XNOR_N:
+    CALLING_CONVENTIONS (function) (e->d[0].p, e->s[0].p, e->s[1].p, size);
+    break;
+
+  case TYPE_ADDSUB_N:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->d[0].p, e->d[1].p, e->s[0].p, e->s[1].p, size);
+    break;
+  case TYPE_ADDSUB_NC:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->d[0].p, e->d[1].p, e->s[0].p, e->s[1].p, size, carry);
+    break;
+
+  case TYPE_COPY:
+  case TYPE_COPYI:
+  case TYPE_COPYD:
+  case TYPE_COM:
+    CALLING_CONVENTIONS (function) (e->d[0].p, e->s[0].p, size);
+    break;
+
+  case TYPE_ADDLSH1_N_IP1:
+  case TYPE_ADDLSH2_N_IP1:
+  case TYPE_ADDLSH1_N_IP2:
+  case TYPE_ADDLSH2_N_IP2:
+  case TYPE_SUBLSH1_N_IP1:
+  case TYPE_SUBLSH2_N_IP1:
+  case TYPE_DIVEXACT_BY3:
+    e->retval = CALLING_CONVENTIONS (function) (e->d[0].p, e->s[0].p, size);
+    break;
+  case TYPE_DIVEXACT_BY3C:
+    e->retval = CALLING_CONVENTIONS (function) (e->d[0].p, e->s[0].p, size,
+						carry);
+    break;
+
+
+  case TYPE_DIVMOD_1:
+  case TYPE_DIVEXACT_1:
+  case TYPE_BDIV_Q_1:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->d[0].p, e->s[0].p, size, divisor);
+    break;
+  case TYPE_DIVMOD_1C:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->d[0].p, e->s[0].p, size, divisor, carry);
+    break;
+  case TYPE_DIVREM_1:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->d[0].p, size2, e->s[0].p, size, divisor);
+    break;
+  case TYPE_DIVREM_1C:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->d[0].p, size2, e->s[0].p, size, divisor, carry);
+    break;
+  case TYPE_PREINV_DIVREM_1:
+    {
+      mp_limb_t  dinv;
+      unsigned   shift;
+      shift = refmpn_count_leading_zeros (divisor);
+      dinv = refmpn_invert_limb (divisor << shift);
+      e->retval = CALLING_CONVENTIONS (function)
+	(e->d[0].p, size2, e->s[0].p, size, divisor, dinv, shift);
+    }
+    break;
+  case TYPE_MOD_1:
+  case TYPE_MODEXACT_1_ODD:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->s[0].p, size, divisor);
+    break;
+  case TYPE_MOD_1C:
+  case TYPE_MODEXACT_1C_ODD:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->s[0].p, size, divisor, carry);
+    break;
+  case TYPE_PREINV_MOD_1:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->s[0].p, size, divisor, refmpn_invert_limb (divisor));
+    break;
+  case TYPE_DIV_QR_1N_PI1:
+    {
+      mp_limb_t dinv = refmpn_invert_limb (divisor);
+      e->retval = CALLING_CONVENTIONS (function)
+	(e->d[0].p, e->s[0].p, size, e->s[1].p[0], divisor, dinv);
+      break;
+    }
+
+  case TYPE_MOD_34LSUB1:
+    e->retval = CALLING_CONVENTIONS (function) (e->s[0].p, size);
+    break;
+
+  case TYPE_UDIV_QRNND:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->d[0].p, e->s[0].p[1], e->s[0].p[0], divisor);
+    break;
+  case TYPE_UDIV_QRNND_R:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->s[0].p[1], e->s[0].p[0], divisor, e->d[0].p);
+    break;
+
+  case TYPE_SBPI1_DIV_QR:
+    {
+      gmp_pi1_t dinv;
+      invert_pi1 (dinv, e->s[1].p[size2-1], e->s[1].p[size2-2]); /* FIXME: use refinvert_pi1 */
+      refmpn_copyi (e->d[1].p, e->s[0].p, size);        /* dividend */
+      refmpn_fill (e->d[0].p, size-size2, 0x98765432);  /* quotient */
+      e->retval = CALLING_CONVENTIONS (function)
+	(e->d[0].p, e->d[1].p, size, e->s[1].p, size2, dinv.inv32);
+      refmpn_zero (e->d[1].p+size2, size-size2);    /* excess over remainder */
+    }
+    break;
+
+  case TYPE_TDIV_QR:
+    CALLING_CONVENTIONS (function) (e->d[0].p, e->d[1].p, 0,
+				    e->s[0].p, size, e->s[1].p, size2);
+    break;
+
+  case TYPE_GCD_1:
+    /* Must have a non-zero src, but this probably isn't the best way to do
+       it. */
+    if (refmpn_zero_p (e->s[0].p, size))
+      e->retval = 0;
+    else
+      e->retval = CALLING_CONVENTIONS (function) (e->s[0].p, size, divisor);
+    break;
+
+  case TYPE_GCD:
+    /* Sources are destroyed, so they're saved and replaced, but a general
+       approach to this might be better.  Note that it's still e->s[0].p and
+       e->s[1].p that are passed, to get the desired alignments. */
+    {
+      mp_ptr  s0 = refmpn_malloc_limbs (size);
+      mp_ptr  s1 = refmpn_malloc_limbs (size2);
+      refmpn_copyi (s0, e->s[0].p, size);
+      refmpn_copyi (s1, e->s[1].p, size2);
+
+      mprotect_region (&s[0].region, PROT_READ|PROT_WRITE);
+      mprotect_region (&s[1].region, PROT_READ|PROT_WRITE);
+      e->retval = CALLING_CONVENTIONS (function) (e->d[0].p,
+						  e->s[0].p, size,
+						  e->s[1].p, size2);
+      refmpn_copyi (e->s[0].p, s0, size);
+      refmpn_copyi (e->s[1].p, s1, size2);
+      free (s0);
+      free (s1);
+    }
+    break;
+
+  case TYPE_GCD_FINDA:
+    {
+      /* FIXME: do this with a flag */
+      mp_limb_t  c[2];
+      c[0] = e->s[0].p[0];
+      c[0] += (c[0] == 0);
+      c[1] = e->s[0].p[0];
+      c[1] += (c[1] == 0);
+      e->retval = CALLING_CONVENTIONS (function) (c);
+    }
+    break;
+
+  case TYPE_MPZ_LEGENDRE:
+  case TYPE_MPZ_JACOBI:
+    {
+      mpz_t  a, b;
+      PTR(a) = e->s[0].p; SIZ(a) = (carry==0 ? size : -size);
+      PTR(b) = e->s[1].p; SIZ(b) = size2;
+      e->retval = CALLING_CONVENTIONS (function) (a, b);
+    }
+    break;
+  case TYPE_MPZ_KRONECKER:
+    {
+      mpz_t  a, b;
+      PTR(a) = e->s[0].p; SIZ(a) = ((carry&1)==0 ? size : -size);
+      PTR(b) = e->s[1].p; SIZ(b) = ((carry&2)==0 ? size2 : -size2);
+      e->retval = CALLING_CONVENTIONS (function) (a, b);
+    }
+    break;
+  case TYPE_MPZ_KRONECKER_UI:
+    {
+      mpz_t  a;
+      PTR(a) = e->s[0].p; SIZ(a) = (carry==0 ? size : -size);
+      e->retval = CALLING_CONVENTIONS(function) (a, (unsigned long)multiplier);
+    }
+    break;
+  case TYPE_MPZ_KRONECKER_SI:
+    {
+      mpz_t  a;
+      PTR(a) = e->s[0].p; SIZ(a) = (carry==0 ? size : -size);
+      e->retval = CALLING_CONVENTIONS (function) (a, (long) multiplier);
+    }
+    break;
+  case TYPE_MPZ_UI_KRONECKER:
+    {
+      mpz_t  b;
+      PTR(b) = e->s[0].p; SIZ(b) = (carry==0 ? size : -size);
+      e->retval = CALLING_CONVENTIONS(function) ((unsigned long)multiplier, b);
+    }
+    break;
+  case TYPE_MPZ_SI_KRONECKER:
+    {
+      mpz_t  b;
+      PTR(b) = e->s[0].p; SIZ(b) = (carry==0 ? size : -size);
+      e->retval = CALLING_CONVENTIONS (function) ((long) multiplier, b);
+    }
+    break;
+
+  case TYPE_MUL_MN:
+  case TYPE_MULMID_MN:
+    CALLING_CONVENTIONS (function)
+      (e->d[0].p, e->s[0].p, size, e->s[1].p, size2);
+    break;
+  case TYPE_MUL_N:
+  case TYPE_MULLO_N:
+    CALLING_CONVENTIONS (function) (e->d[0].p, e->s[0].p, e->s[1].p, size);
+    break;
+  case TYPE_MULMID_N:
+    CALLING_CONVENTIONS (function) (e->d[0].p, e->s[0].p, e->s[1].p,
+				    (size + 1) / 2);
+    break;
+  case TYPE_SQR:
+  case TYPE_SQRLO:
+    CALLING_CONVENTIONS (function) (e->d[0].p, e->s[0].p, size);
+    break;
+
+  case TYPE_UMUL_PPMM:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->d[0].p, e->s[0].p[0], e->s[0].p[1]);
+    break;
+  case TYPE_UMUL_PPMM_R:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->s[0].p[0], e->s[0].p[1], e->d[0].p);
+    break;
+
+  case TYPE_ADDLSH_N_IP1:
+  case TYPE_ADDLSH_N_IP2:
+  case TYPE_SUBLSH_N_IP1:
+  case TYPE_LSHIFT:
+  case TYPE_LSHIFTC:
+  case TYPE_RSHIFT:
+    e->retval = CALLING_CONVENTIONS (function)
+      (e->d[0].p, e->s[0].p, size, shift);
+    break;
+
+  case TYPE_POPCOUNT:
+    e->retval = (* (unsigned long (*)(ANYARGS))
+		 CALLING_CONVENTIONS (function)) (e->s[0].p, size);
+    break;
+  case TYPE_HAMDIST:
+    e->retval = (* (unsigned long (*)(ANYARGS))
+		 CALLING_CONVENTIONS (function)) (e->s[0].p, e->s[1].p, size);
+    break;
+
+  case TYPE_SQRTREM:
+    e->retval = (* (long (*)(ANYARGS)) CALLING_CONVENTIONS (function))
+      (e->d[0].p, e->d[1].p, e->s[0].p, size);
+    break;
+
+  case TYPE_SQRT:
+    e->retval = (* (long (*)(ANYARGS)) CALLING_CONVENTIONS (function))
+      (e->d[0].p, e->s[0].p, size);
+    break;
+
+  case TYPE_ZERO:
+    CALLING_CONVENTIONS (function) (e->d[0].p, size);
+    break;
+
+  case TYPE_GET_STR:
+    {
+      size_t  sizeinbase, fill;
+      char    *dst;
+      MPN_SIZEINBASE (sizeinbase, e->s[0].p, size, base);
+      ASSERT_ALWAYS (sizeinbase <= d[0].size);
+      fill = d[0].size - sizeinbase;
+      if (d[0].high)
+	{
+	  memset (e->d[0].p, 0xBA, fill);
+	  dst = (char *) e->d[0].p + fill;
+	}
+      else
+	{
+	  dst = (char *) e->d[0].p;
+	  memset (dst + sizeinbase, 0xBA, fill);
+	}
+      if (POW2_P (base))
+	{
+	  e->retval = CALLING_CONVENTIONS (function) (dst, base,
+						      e->s[0].p, size);
+	}
+      else
+	{
+	  refmpn_copy (e->d[1].p, e->s[0].p, size);
+	  e->retval = CALLING_CONVENTIONS (function) (dst, base,
+						      e->d[1].p, size);
+	}
+      refmpn_zero (e->d[1].p, size);  /* clobbered or unused */
+    }
+    break;
+
+ case TYPE_INVERT:
+    {
+      mp_ptr scratch;
+      TMP_DECL;
+      TMP_MARK;
+      scratch = TMP_ALLOC_LIMBS (mpn_invert_itch (size));
+      CALLING_CONVENTIONS (function) (e->d[0].p, e->s[0].p, size, scratch);
+      TMP_FREE;
+    }
+    break;
+  case TYPE_BINVERT:
+    {
+      mp_ptr scratch;
+      TMP_DECL;
+      TMP_MARK;
+      scratch = TMP_ALLOC_LIMBS (mpn_binvert_itch (size));
+      CALLING_CONVENTIONS (function) (e->d[0].p, e->s[0].p, size, scratch);
+      TMP_FREE;
+    }
+    break;
+
+#ifdef EXTRA_CALL
+    EXTRA_CALL
+#endif
+
+  default:
+    printf ("Unknown routine type %d\n", choice->type);
+    abort ();
+    break;
+  }
+}
+
+
+void
+pointer_setup (struct each_t *e)
+{
+  int  i, j;
+
+  for (i = 0; i < NUM_DESTS; i++)
+    {
+      switch (tr->dst_size[i]) {
+      case 0:
+      case SIZE_RETVAL: /* will be adjusted later */
+	d[i].size = size;
+	break;
+
+      case SIZE_1:
+	d[i].size = 1;
+	break;
+      case SIZE_2:
+	d[i].size = 2;
+	break;
+      case SIZE_3:
+	d[i].size = 3;
+	break;
+      case SIZE_4:
+	d[i].size = 4;
+	break;
+      case SIZE_6:
+	d[i].size = 6;
+	break;
+
+      case SIZE_PLUS_1:
+	d[i].size = size+1;
+	break;
+      case SIZE_PLUS_MSIZE_SUB_1:
+	d[i].size = size + tr->msize - 1;
+	break;
+
+      case SIZE_SUM:
+	if (tr->size2)
+	  d[i].size = size + size2;
+	else
+	  d[i].size = 2*size;
+	break;
+
+      case SIZE_SIZE2:
+	d[i].size = size2;
+	break;
+
+      case SIZE_DIFF:
+	d[i].size = size - size2;
+	break;
+
+      case SIZE_DIFF_PLUS_1:
+	d[i].size = size - size2 + 1;
+	break;
+
+      case SIZE_DIFF_PLUS_3:
+	d[i].size = size - size2 + 3;
+	break;
+
+      case SIZE_CEIL_HALF:
+	d[i].size = (size+1)/2;
+	break;
+
+      case SIZE_GET_STR:
+	{
+	  mp_limb_t ff = GMP_NUMB_MAX;
+	  MPN_SIZEINBASE (d[i].size, &ff - (size-1), size, base);
+	}
+	break;
+
+      default:
+	printf ("Unrecognised dst_size type %d\n", tr->dst_size[i]);
+	abort ();
+      }
+    }
+
+  /* establish e->d[].p destinations */
+  for (i = 0; i < NUM_DESTS; i++)
+    {
+      mp_size_t  offset = 0;
+
+      /* possible room for overlapping sources */
+      for (j = 0; j < numberof (overlap->s); j++)
+	if (overlap->s[j] == i)
+	  offset = MAX (offset, s[j].align);
+
+      if (d[i].high)
+	{
+	  if (tr->dst_bytes[i])
+	    {
+	      e->d[i].p = (mp_ptr)
+		((char *) (e->d[i].region.ptr + e->d[i].region.size)
+		 - d[i].size - d[i].align);
+	    }
+	  else
+	    {
+	      e->d[i].p = e->d[i].region.ptr + e->d[i].region.size
+		- d[i].size - d[i].align;
+	      if (tr->overlap == OVERLAP_LOW_TO_HIGH)
+		e->d[i].p -= offset;
+	    }
+	}
+      else
+	{
+	  if (tr->dst_bytes[i])
+	    {
+	      e->d[i].p = (mp_ptr) ((char *) e->d[i].region.ptr + d[i].align);
+	    }
+	  else
+	    {
+	      e->d[i].p = e->d[i].region.ptr + d[i].align;
+	      if (tr->overlap == OVERLAP_HIGH_TO_LOW)
+		e->d[i].p += offset;
+	    }
+	}
+    }
+
+  /* establish e->s[].p sources */
+  for (i = 0; i < NUM_SOURCES; i++)
+    {
+      int  o = overlap->s[i];
+      switch (o) {
+      case -1:
+	/* no overlap */
+	e->s[i].p = s[i].p;
+	break;
+      case 0:
+      case 1:
+	/* overlap with d[o] */
+	if (tr->overlap == OVERLAP_HIGH_TO_LOW)
+	  e->s[i].p = e->d[o].p - s[i].align;
+	else if (tr->overlap == OVERLAP_LOW_TO_HIGH)
+	  e->s[i].p = e->d[o].p + s[i].align;
+	else if (tr->size2 == SIZE_FRACTION)
+	  e->s[i].p = e->d[o].p + size2;
+	else
+	  e->s[i].p = e->d[o].p;
+	break;
+      default:
+	abort();
+	break;
+      }
+    }
+}
+
+
+void
+validate_fail (void)
+{
+  if (tr->reference)
+    {
+      trap_location = TRAP_REF;
+      call (&ref, tr->reference);
+      trap_location = TRAP_NOWHERE;
+    }
+
+  print_all();
+  abort();
+}
+
+
+void
+try_one (void)
+{
+  int  i;
+
+  if (option_spinner)
+    spinner();
+  spinner_count++;
+
+  trap_location = TRAP_SETUPS;
+
+  if (tr->divisor == DIVISOR_NORM)
+    divisor |= GMP_NUMB_HIGHBIT;
+  if (tr->divisor == DIVISOR_ODD)
+    divisor |= 1;
+
+  for (i = 0; i < NUM_SOURCES; i++)
+    {
+      if (s[i].high)
+	s[i].p = s[i].region.ptr + s[i].region.size - SRC_SIZE(i) - s[i].align;
+      else
+	s[i].p = s[i].region.ptr + s[i].align;
+    }
+
+  pointer_setup (&ref);
+  pointer_setup (&fun);
+
+  ref.retval = 0x04152637;
+  fun.retval = 0x8C9DAEBF;
+
+  t_random (multiplier_N, tr->msize);
+
+  for (i = 0; i < NUM_SOURCES; i++)
+    {
+      if (! tr->src[i])
+	continue;
+
+      mprotect_region (&s[i].region, PROT_READ|PROT_WRITE);
+      t_random (s[i].p, SRC_SIZE(i));
+
+      switch (tr->data) {
+      case DATA_NON_ZERO:
+	if (refmpn_zero_p (s[i].p, SRC_SIZE(i)))
+	  s[i].p[0] = 1;
+	break;
+
+      case DATA_MULTIPLE_DIVISOR:
+	/* same number of low zero bits as divisor */
+	s[i].p[0] &= ~ LOW_ZEROS_MASK (divisor);
+	refmpn_sub_1 (s[i].p, s[i].p, size,
+		      refmpn_mod_1 (s[i].p, size, divisor));
+	break;
+
+      case DATA_GCD:
+	/* s[1] no more bits than s[0] */
+	if (i == 1 && size2 == size)
+	  s[1].p[size-1] &= refmpn_msbone_mask (s[0].p[size-1]);
+
+	/* high limb non-zero */
+	s[i].p[SRC_SIZE(i)-1] += (s[i].p[SRC_SIZE(i)-1] == 0);
+
+	/* odd */
+	s[i].p[0] |= 1;
+	break;
+
+      case DATA_SRC0_ODD:
+	if (i == 0)
+	  s[i].p[0] |= 1;
+	break;
+
+      case DATA_SRC1_ODD:
+	if (i == 1)
+	  s[i].p[0] |= 1;
+	break;
+
+      case DATA_SRC1_ODD_PRIME:
+	if (i == 1)
+	  {
+	    if (refmpn_zero_p (s[i].p+1, SRC_SIZE(i)-1)
+		&& s[i].p[0] <=3)
+	      s[i].p[0] = 3;
+	    else
+	      {
+		mpz_t p;
+		mpz_init (p);
+		for (;;)
+		  {
+		    _mpz_realloc (p, SRC_SIZE(i));
+		    MPN_COPY (PTR(p), s[i].p, SRC_SIZE(i));
+		    SIZ(p) = SRC_SIZE(i);
+		    MPN_NORMALIZE (PTR(p), SIZ(p));
+		    mpz_nextprime (p, p);
+		    if (mpz_size (p) <= SRC_SIZE(i))
+		      break;
+
+		    t_random (s[i].p, SRC_SIZE(i));
+		  }
+		MPN_COPY (s[i].p, PTR(p), SIZ(p));
+		if (SIZ(p) < SRC_SIZE(i))
+		  MPN_ZERO (s[i].p + SIZ(p), SRC_SIZE(i) - SIZ(p));
+		mpz_clear (p);
+	      }
+	  }
+	break;
+
+      case DATA_SRC1_HIGHBIT:
+	if (i == 1)
+	  {
+	    if (tr->size2)
+	      s[i].p[size2-1] |= GMP_NUMB_HIGHBIT;
+	    else
+	      s[i].p[size-1] |= GMP_NUMB_HIGHBIT;
+	  }
+	break;
+
+      case DATA_SRC0_HIGHBIT:
+       if (i == 0)
+	 {
+	   s[i].p[size-1] |= GMP_NUMB_HIGHBIT;
+	 }
+       break;
+
+      case DATA_UDIV_QRNND:
+	s[i].p[1] %= divisor;
+	break;
+      case DATA_DIV_QR_1:
+	if (i == 1)
+	  s[i].p[0] %= divisor;
+	break;
+      }
+
+      mprotect_region (&s[i].region, PROT_READ);
+    }
+
+  for (i = 0; i < NUM_DESTS; i++)
+    {
+      if (! tr->dst[i])
+	continue;
+
+      if (tr->dst0_from_src1 && i==0)
+	{
+	  mp_size_t  copy = MIN (d[0].size, SRC_SIZE(1));
+	  mp_size_t  fill = MAX (0, d[0].size - copy);
+	  MPN_COPY (fun.d[0].p, s[1].region.ptr, copy);
+	  MPN_COPY (ref.d[0].p, s[1].region.ptr, copy);
+	  refmpn_fill (fun.d[0].p + copy, fill, DEADVAL);
+	  refmpn_fill (ref.d[0].p + copy, fill, DEADVAL);
+	}
+      else if (tr->dst_bytes[i])
+	{
+	  memset (ref.d[i].p, 0xBA, d[i].size);
+	  memset (fun.d[i].p, 0xBA, d[i].size);
+	}
+      else
+	{
+	  refmpn_fill (ref.d[i].p, d[i].size, DEADVAL);
+	  refmpn_fill (fun.d[i].p, d[i].size, DEADVAL);
+	}
+    }
+
+  for (i = 0; i < NUM_SOURCES; i++)
+    {
+      if (! tr->src[i])
+	continue;
+
+      if (ref.s[i].p != s[i].p)
+	{
+	  refmpn_copyi (ref.s[i].p, s[i].p, SRC_SIZE(i));
+	  refmpn_copyi (fun.s[i].p, s[i].p, SRC_SIZE(i));
+	}
+    }
+
+  if (option_print)
+    print_all();
+
+  if (tr->validate != NULL)
+    {
+      trap_location = TRAP_FUN;
+      call (&fun, choice->function);
+      trap_location = TRAP_NOWHERE;
+
+      if (! CALLING_CONVENTIONS_CHECK ())
+	{
+	  print_all();
+	  abort();
+	}
+
+      (*tr->validate) ();
+    }
+  else
+    {
+      trap_location = TRAP_REF;
+      call (&ref, tr->reference);
+      trap_location = TRAP_FUN;
+      call (&fun, choice->function);
+      trap_location = TRAP_NOWHERE;
+
+      if (! CALLING_CONVENTIONS_CHECK ())
+	{
+	  print_all();
+	  abort();
+	}
+
+      compare ();
+    }
+}
+
+
+#define SIZE_ITERATION                                          \
+  for (size = MAX3 (option_firstsize,                           \
+		    choice->minsize,                            \
+		    (tr->size == SIZE_ALLOW_ZERO) ? 0 : 1),	\
+	 size += (tr->size == SIZE_ODD) && !(size & 1);		\
+       size <= option_lastsize;                                 \
+       size += (tr->size == SIZE_ODD) ? 2 : 1)
+
+#define SIZE2_FIRST                                     \
+  (tr->size2 == SIZE_2 ? 2                              \
+   : tr->size2 == SIZE_FRACTION ? option_firstsize2     \
+   : tr->size2 == SIZE_CEIL_HALF ? ((size + 1) / 2)	\
+   : tr->size2 ?                                        \
+   MAX (choice->minsize, (option_firstsize2 != 0        \
+			  ? option_firstsize2 : 1))     \
+   : 0)
+
+#define SIZE2_LAST                                      \
+  (tr->size2 == SIZE_2 ? 2                              \
+   : tr->size2 == SIZE_FRACTION ? FRACTION_COUNT-1      \
+   : tr->size2 == SIZE_CEIL_HALF ? ((size + 1) / 2)	\
+   : tr->size2 ? size                                   \
+   : 0)
+
+#define SIZE2_ITERATION \
+  for (size2 = SIZE2_FIRST; size2 <= SIZE2_LAST; size2++)
+
+#define ALIGN_COUNT(cond)  ((cond) ? ALIGNMENTS : 1)
+#define ALIGN_ITERATION(w,n,cond) \
+  for (w[n].align = 0; w[n].align < ALIGN_COUNT(cond); w[n].align++)
+
+#define HIGH_LIMIT(cond)  ((cond) != 0)
+#define HIGH_COUNT(cond)  (HIGH_LIMIT (cond) + 1)
+#define HIGH_ITERATION(w,n,cond) \
+  for (w[n].high = 0; w[n].high <= HIGH_LIMIT(cond); w[n].high++)
+
+#define SHIFT_LIMIT                                     \
+  ((unsigned long) (tr->shift ? GMP_NUMB_BITS -1 : 1))
+
+#define SHIFT_ITERATION                                 \
+  for (shift = 1; shift <= SHIFT_LIMIT; shift++)
+
+
+void
+try_many (void)
+{
+  int   i;
+
+  {
+    unsigned long  total = 1;
+
+    total *= option_repetitions;
+    total *= option_lastsize;
+    if (tr->size2 == SIZE_FRACTION) total *= FRACTION_COUNT;
+    else if (tr->size2)             total *= (option_lastsize+1)/2;
+
+    total *= SHIFT_LIMIT;
+    total *= MULTIPLIER_COUNT;
+    total *= DIVISOR_COUNT;
+    total *= CARRY_COUNT;
+    total *= T_RAND_COUNT;
+
+    total *= HIGH_COUNT (tr->dst[0]);
+    total *= HIGH_COUNT (tr->dst[1]);
+    total *= HIGH_COUNT (tr->src[0]);
+    total *= HIGH_COUNT (tr->src[1]);
+
+    total *= ALIGN_COUNT (tr->dst[0]);
+    total *= ALIGN_COUNT (tr->dst[1]);
+    total *= ALIGN_COUNT (tr->src[0]);
+    total *= ALIGN_COUNT (tr->src[1]);
+
+    total *= OVERLAP_COUNT;
+
+    printf ("%s %lu\n", choice->name, total);
+  }
+
+  spinner_count = 0;
+
+  for (i = 0; i < option_repetitions; i++)
+    SIZE_ITERATION
+      SIZE2_ITERATION
+
+      SHIFT_ITERATION
+      MULTIPLIER_ITERATION
+      DIVISOR_ITERATION
+      CARRY_ITERATION /* must be after divisor */
+      T_RAND_ITERATION
+
+      HIGH_ITERATION(d,0, tr->dst[0])
+      HIGH_ITERATION(d,1, tr->dst[1])
+      HIGH_ITERATION(s,0, tr->src[0])
+      HIGH_ITERATION(s,1, tr->src[1])
+
+      ALIGN_ITERATION(d,0, tr->dst[0])
+      ALIGN_ITERATION(d,1, tr->dst[1])
+      ALIGN_ITERATION(s,0, tr->src[0])
+      ALIGN_ITERATION(s,1, tr->src[1])
+
+      OVERLAP_ITERATION
+      try_one();
+
+  printf("\n");
+}
+
+
+/* Usually print_all() doesn't show much, but it might give a hint as to
+   where the function was up to when it died. */
+void
+trap (int sig)
+{
+  const char *name = "noname";
+
+  switch (sig) {
+  case SIGILL:  name = "SIGILL";  break;
+#ifdef SIGBUS
+  case SIGBUS:  name = "SIGBUS";  break;
+#endif
+  case SIGSEGV: name = "SIGSEGV"; break;
+  case SIGFPE:  name = "SIGFPE";  break;
+  }
+
+  printf ("\n\nSIGNAL TRAP: %s\n", name);
+
+  switch (trap_location) {
+  case TRAP_REF:
+    printf ("  in reference function: %s\n", tr->reference_name);
+    break;
+  case TRAP_FUN:
+    printf ("  in test function: %s\n", choice->name);
+    print_all ();
+    break;
+  case TRAP_SETUPS:
+    printf ("  in parameter setups\n");
+    print_all ();
+    break;
+  default:
+    printf ("  somewhere unknown\n");
+    break;
+  }
+  exit (1);
+}
+
+
+void
+try_init (void)
+{
+#if HAVE_GETPAGESIZE
+  /* Prefer getpagesize() over sysconf(), since on SunOS 4 sysconf() doesn't
+     know _SC_PAGESIZE. */
+  pagesize = getpagesize ();
+#else
+#if HAVE_SYSCONF
+  if ((pagesize = sysconf (_SC_PAGESIZE)) == -1)
+    {
+      /* According to the linux man page, sysconf doesn't set errno */
+      fprintf (stderr, "Cannot get sysconf _SC_PAGESIZE\n");
+      exit (1);
+    }
+#else
+Error, error, cannot get page size
+#endif
+#endif
+
+  printf ("pagesize is 0x%lX bytes\n", pagesize);
+
+  signal (SIGILL,  trap);
+#ifdef SIGBUS
+  signal (SIGBUS,  trap);
+#endif
+  signal (SIGSEGV, trap);
+  signal (SIGFPE,  trap);
+
+  {
+    int  i;
+
+    for (i = 0; i < NUM_SOURCES; i++)
+      {
+	malloc_region (&s[i].region, 2*option_lastsize+ALIGNMENTS-1);
+	printf ("s[%d] %p to %p (0x%lX bytes)\n",
+		i, (void *) (s[i].region.ptr),
+		(void *) (s[i].region.ptr + s[i].region.size),
+		(long) s[i].region.size * GMP_LIMB_BYTES);
+      }
+
+#define INIT_EACH(e,es)                                                 \
+    for (i = 0; i < NUM_DESTS; i++)                                     \
+      {                                                                 \
+	malloc_region (&e.d[i].region, 2*option_lastsize+ALIGNMENTS-1); \
+	printf ("%s d[%d] %p to %p (0x%lX bytes)\n",                    \
+		es, i, (void *) (e.d[i].region.ptr),			\
+		(void *)  (e.d[i].region.ptr + e.d[i].region.size),	\
+		(long) e.d[i].region.size * GMP_LIMB_BYTES);         \
+      }
+
+    INIT_EACH(ref, "ref");
+    INIT_EACH(fun, "fun");
+  }
+}
+
+int
+strmatch_wild (const char *pattern, const char *str)
+{
+  size_t  plen, slen;
+
+  /* wildcard at start */
+  if (pattern[0] == '*')
+    {
+      pattern++;
+      plen = strlen (pattern);
+      slen = strlen (str);
+      return (plen == 0
+	      || (slen >= plen && memcmp (pattern, str+slen-plen, plen) == 0));
+    }
+
+  /* wildcard at end */
+  plen = strlen (pattern);
+  if (plen >= 1 && pattern[plen-1] == '*')
+    return (memcmp (pattern, str, plen-1) == 0);
+
+  /* no wildcards */
+  return (strcmp (pattern, str) == 0);
+}
+
+void
+try_name (const char *name)
+{
+  int  found = 0;
+  int  i;
+
+  for (i = 0; i < numberof (choice_array); i++)
+    {
+      if (strmatch_wild (name, choice_array[i].name))
+	{
+	  choice = &choice_array[i];
+	  tr = &param[choice->type];
+	  try_many ();
+	  found = 1;
+	}
+    }
+
+  if (!found)
+    {
+      printf ("%s unknown\n", name);
+      /* exit (1); */
+    }
+}
+
+
+void
+usage (const char *prog)
+{
+  int  col = 0;
+  int  i;
+
+  printf ("Usage: %s [options] function...\n", prog);
+  printf ("    -1        use limb data 1,2,3,etc\n");
+  printf ("    -9        use limb data all 0xFF..FFs\n");
+  printf ("    -a zeros  use limb data all zeros\n");
+  printf ("    -a ffs    use limb data all 0xFF..FFs (same as -9)\n");
+  printf ("    -a 2fd    use data 0x2FFF...FFFD\n");
+  printf ("    -p        print each case tried (try this if seg faulting)\n");
+  printf ("    -R        seed random numbers from time()\n");
+  printf ("    -r reps   set repetitions (default %d)\n", DEFAULT_REPETITIONS);
+  printf ("    -s size   starting size to test\n");
+  printf ("    -S size2  starting size2 to test\n");
+  printf ("    -s s1-s2  range of sizes to test\n");
+  printf ("    -W        don't show the spinner (use this in gdb)\n");
+  printf ("    -z        disable mprotect() redzones\n");
+  printf ("Default data is refmpn_random() and refmpn_random2().\n");
+  printf ("\n");
+  printf ("Functions that can be tested:\n");
+
+  for (i = 0; i < numberof (choice_array); i++)
+    {
+      if (col + 1 + strlen (choice_array[i].name) > 79)
+	{
+	  printf ("\n");
+	  col = 0;
+	}
+      printf (" %s", choice_array[i].name);
+      col += 1 + strlen (choice_array[i].name);
+    }
+  printf ("\n");
+
+  exit(1);
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  int  i;
+
+  /* unbuffered output */
+  setbuf (stdout, NULL);
+  setbuf (stderr, NULL);
+
+  /* default trace in hex, and in upper-case so can paste into bc */
+  mp_trace_base = -16;
+
+  param_init ();
+
+  {
+    unsigned long  seed = 123;
+    int   opt;
+
+    while ((opt = getopt(argc, argv, "19a:b:E:pRr:S:s:Wz")) != EOF)
+      {
+	switch (opt) {
+	case '1':
+	  /* use limb data values 1, 2, 3, ... etc */
+	  option_data = DATA_SEQ;
+	  break;
+	case '9':
+	  /* use limb data values 0xFFF...FFF always */
+	  option_data = DATA_FFS;
+	  break;
+	case 'a':
+	  if (strcmp (optarg, "zeros") == 0)     option_data = DATA_ZEROS;
+	  else if (strcmp (optarg, "seq") == 0)  option_data = DATA_SEQ;
+	  else if (strcmp (optarg, "ffs") == 0)  option_data = DATA_FFS;
+	  else if (strcmp (optarg, "2fd") == 0)  option_data = DATA_2FD;
+	  else
+	    {
+	      fprintf (stderr, "unrecognised data option: %s\n", optarg);
+	      exit (1);
+	    }
+	  break;
+	case 'b':
+	  mp_trace_base = atoi (optarg);
+	  break;
+	case 'E':
+	  /* re-seed */
+	  sscanf (optarg, "%lu", &seed);
+	  printf ("Re-seeding with %lu\n", seed);
+	  break;
+	case 'p':
+	  option_print = 1;
+	  break;
+	case 'R':
+	  /* randomize */
+	  seed = time (NULL);
+	  printf ("Seeding with %lu, re-run using \"-E %lu\"\n", seed, seed);
+	  break;
+	case 'r':
+	  option_repetitions = atoi (optarg);
+	  break;
+	case 's':
+	  {
+	    char  *p;
+	    option_firstsize = strtol (optarg, 0, 0);
+	    if ((p = strchr (optarg, '-')) != NULL)
+	      option_lastsize = strtol (p+1, 0, 0);
+	  }
+	  break;
+	case 'S':
+	  /* -S <size> sets the starting size for the second of a two size
+	     routine (like mpn_mul_basecase) */
+	  option_firstsize2 = strtol (optarg, 0, 0);
+	  break;
+	case 'W':
+	  /* use this when running in the debugger */
+	  option_spinner = 0;
+	  break;
+	case 'z':
+	  /* disable redzones */
+	  option_redzones = 0;
+	  break;
+	case '?':
+	  usage (argv[0]);
+	  break;
+	}
+      }
+
+    gmp_randinit_default (__gmp_rands);
+    __gmp_rands_initialized = 1;
+    gmp_randseed_ui (__gmp_rands, seed);
+  }
+
+  try_init();
+
+  if (argc <= optind)
+    usage (argv[0]);
+
+  for (i = optind; i < argc; i++)
+    try_name (argv[i]);
+
+  return 0;
+}
diff --git a/third_party/gmp/tests/devel/tst-addsub.c b/third_party/gmp/tests/devel/tst-addsub.c
new file mode 100644
index 0000000..4aa827a
--- /dev/null
+++ b/third_party/gmp/tests/devel/tst-addsub.c
@@ -0,0 +1,97 @@
+/* Copyright 1996, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+#define ADD 1
+#define SUB 2
+
+#ifndef METHOD
+#define METHOD ADD
+#endif
+
+#if METHOD == ADD
+#define REFCALL refmpn_add_n
+#define TESTCALL mpn_add_n
+#endif
+
+#if METHOD == SUB
+#define REFCALL refmpn_sub_n
+#define TESTCALL mpn_sub_n
+#endif
+
+#define SIZE 100
+
+int
+main (int argc, char **argv)
+{
+  mp_size_t alloc_size, max_size, size, i, cumul_size;
+  mp_ptr s1, s2, dx, dy;
+  int s1_align, s2_align, d_align;
+  long pass, n_passes;
+  mp_limb_t cx, cy;
+
+  max_size = SIZE;
+  n_passes = 1000000;
+
+  argc--; argv++;
+  if (argc)
+    {
+      max_size = atol (*argv);
+      argc--; argv++;
+    }
+
+  alloc_size = max_size + 32;
+  s1 = malloc (alloc_size * GMP_LIMB_BYTES);
+  s2 = malloc (alloc_size * GMP_LIMB_BYTES);
+  dx = malloc (alloc_size * GMP_LIMB_BYTES);
+  dy = malloc (alloc_size * GMP_LIMB_BYTES);
+
+  cumul_size = 0;
+  for (pass = 0; pass < n_passes; pass++)
+    {
+      size = random () % max_size + 1;
+
+      cumul_size += size;
+      if (cumul_size >= 1000000)
+	{
+	  cumul_size -= 1000000;
+	  printf ("\r%ld", pass); fflush (stdout);
+	}
+      s1_align = random () % 32;
+      s2_align = random () % 32;
+      d_align = random () % 32;
+
+      mpn_random2 (s1 + s1_align, size);
+      mpn_random2 (s2 + s2_align, size);
+
+      for (i = 0; i < alloc_size; i++)
+	dx[i] = dy[i] = i + 0x9876500;
+
+      cx = TESTCALL (dx + d_align, s1 + s1_align, s2 + s2_align, size);
+      cy = REFCALL (dy + d_align, s1 + s1_align, s2 + s2_align, size);
+
+      if (cx != cy || mpn_cmp (dx, dy, alloc_size) != 0)
+	abort ();
+    }
+
+  printf ("%ld passes OK\n", n_passes);
+  exit (0);
+}
diff --git a/third_party/gmp/tests/memory.c b/third_party/gmp/tests/memory.c
new file mode 100644
index 0000000..4ab54b7
--- /dev/null
+++ b/third_party/gmp/tests/memory.c
@@ -0,0 +1,246 @@
+/* Memory allocation used during tests.
+
+Copyright 2001, 2002, 2007, 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>		/* for abort */
+#include <string.h>		/* for memcpy, memcmp */
+#include "gmp-impl.h"
+#include "tests.h"
+
+#if GMP_LIMB_BITS == 64
+#define PATTERN1 CNST_LIMB(0xcafebabedeadbeef)
+#define PATTERN2 CNST_LIMB(0xabacadabaedeedab)
+#else
+#define PATTERN1 CNST_LIMB(0xcafebabe)
+#define PATTERN2 CNST_LIMB(0xdeadbeef)
+#endif
+
+#if HAVE_INTPTR_T
+#define PTRLIMB(p)  ((mp_limb_t) (intptr_t) p)
+#else
+#define PTRLIMB(p)  ((mp_limb_t) (size_t) p)
+#endif
+
+/* Each block allocated is a separate malloc, for the benefit of a redzoning
+   malloc debugger during development or when bug hunting.
+
+   Sizes passed when reallocating or freeing are checked (the default
+   routines don't care about these).
+
+   Memory leaks are checked by requiring that all blocks have been freed
+   when tests_memory_end() is called.  Test programs must be sure to have
+   "clear"s for all temporary variables used.  */
+
+
+struct header {
+  void           *ptr;
+  size_t         size;
+  struct header  *next;
+};
+
+struct header  *tests_memory_list = NULL;
+
+/* Return a pointer to a pointer to the found block (so it can be updated
+   when unlinking). */
+struct header **
+tests_memory_find (void *ptr)
+{
+  struct header  **hp;
+
+  for (hp = &tests_memory_list; *hp != NULL; hp = &((*hp)->next))
+    if ((*hp)->ptr == ptr)
+      return hp;
+
+  return NULL;
+}
+
+int
+tests_memory_valid (void *ptr)
+{
+  return (tests_memory_find (ptr) != NULL);
+}
+
+void *
+tests_allocate (size_t size)
+{
+  struct header  *h;
+  void *rptr, *ptr;
+  mp_limb_t PATTERN2_var;
+
+  if (size == 0)
+    {
+      fprintf (stderr, "tests_allocate(): attempt to allocate 0 bytes\n");
+      abort ();
+    }
+
+  h = (struct header *) __gmp_default_allocate (sizeof (*h));
+  h->next = tests_memory_list;
+  tests_memory_list = h;
+
+  rptr = __gmp_default_allocate (size + 2 * sizeof (mp_limb_t));
+  ptr = (void *) ((gmp_intptr_t) rptr + sizeof (mp_limb_t));
+
+  *((mp_limb_t *) ((gmp_intptr_t) ptr - sizeof (mp_limb_t)))
+    = PATTERN1 - PTRLIMB (ptr);
+  PATTERN2_var = PATTERN2 - PTRLIMB (ptr);
+  memcpy ((void *) ((gmp_intptr_t) ptr + size), &PATTERN2_var, sizeof (mp_limb_t));
+
+  h->size = size;
+  h->ptr = ptr;
+  return h->ptr;
+}
+
+void *
+tests_reallocate (void *ptr, size_t old_size, size_t new_size)
+{
+  struct header  **hp, *h;
+  void *rptr;
+  mp_limb_t PATTERN2_var;
+
+  if (new_size == 0)
+    {
+      fprintf (stderr, "tests_reallocate(): attempt to reallocate %p to 0 bytes\n",
+	       ptr);
+      abort ();
+    }
+
+  hp = tests_memory_find (ptr);
+  if (hp == NULL)
+    {
+      fprintf (stderr, "tests_reallocate(): attempt to reallocate bad pointer %p\n",
+	       ptr);
+      abort ();
+    }
+  h = *hp;
+
+  if (h->size != old_size)
+    {
+      fprintf (stderr, "tests_reallocate(): bad old size %lu, should be %lu\n",
+	       (unsigned long) old_size, (unsigned long) h->size);
+      abort ();
+    }
+
+  if (*((mp_limb_t *) ((gmp_intptr_t) ptr - sizeof (mp_limb_t)))
+      != PATTERN1 - PTRLIMB (ptr))
+    {
+      fprintf (stderr, "in realloc: redzone clobbered before block\n");
+      abort ();
+    }
+  PATTERN2_var = PATTERN2 - PTRLIMB (ptr);
+  if (memcmp ((void *) ((gmp_intptr_t) ptr + h->size), &PATTERN2_var, sizeof (mp_limb_t)))
+    {
+      fprintf (stderr, "in realloc: redzone clobbered after block\n");
+      abort ();
+    }
+
+  rptr = __gmp_default_reallocate ((void *) ((gmp_intptr_t) ptr - sizeof (mp_limb_t)),
+				 old_size + 2 * sizeof (mp_limb_t),
+				 new_size + 2 * sizeof (mp_limb_t));
+  ptr = (void *) ((gmp_intptr_t) rptr + sizeof (mp_limb_t));
+
+  *((mp_limb_t *) ((gmp_intptr_t) ptr - sizeof (mp_limb_t)))
+    = PATTERN1 - PTRLIMB (ptr);
+  PATTERN2_var = PATTERN2 - PTRLIMB (ptr);
+  memcpy ((void *) ((gmp_intptr_t) ptr + new_size), &PATTERN2_var, sizeof (mp_limb_t));
+
+  h->size = new_size;
+  h->ptr = ptr;
+  return h->ptr;
+}
+
+struct header **
+tests_free_find (void *ptr)
+{
+  struct header  **hp = tests_memory_find (ptr);
+  if (hp == NULL)
+    {
+      fprintf (stderr, "tests_free(): attempt to free bad pointer %p\n",
+	       ptr);
+      abort ();
+    }
+  return hp;
+}
+
+void
+tests_free_nosize (void *ptr)
+{
+  struct header  **hp = tests_free_find (ptr);
+  struct header  *h = *hp;
+  mp_limb_t PATTERN2_var;
+
+  *hp = h->next;  /* unlink */
+
+  if (*((mp_limb_t *) ((gmp_intptr_t) ptr - sizeof (mp_limb_t)))
+      != PATTERN1 - PTRLIMB (ptr))
+    {
+      fprintf (stderr, "in free: redzone clobbered before block\n");
+      abort ();
+    }
+  PATTERN2_var = PATTERN2 - PTRLIMB (ptr);
+  if (memcmp ((void *) ((gmp_intptr_t) ptr + h->size), &PATTERN2_var, sizeof (mp_limb_t)))
+    {
+      fprintf (stderr, "in free: redzone clobbered after block\n");
+      abort ();
+    }
+
+  __gmp_default_free ((void *) ((gmp_intptr_t) ptr - sizeof(mp_limb_t)),
+		      h->size + 2 * sizeof (mp_limb_t));
+  __gmp_default_free (h, sizeof (*h));
+}
+
+void
+tests_free (void *ptr, size_t size)
+{
+  struct header  **hp = tests_free_find (ptr);
+  struct header  *h = *hp;
+
+  if (h->size != size)
+    {
+      fprintf (stderr, "tests_free(): bad size %lu, should be %lu\n",
+	       (unsigned long) size, (unsigned long) h->size);
+      abort ();
+    }
+
+  tests_free_nosize (ptr);
+}
+
+void
+tests_memory_start (void)
+{
+  mp_set_memory_functions (tests_allocate, tests_reallocate, tests_free);
+}
+
+void
+tests_memory_end (void)
+{
+  if (tests_memory_list != NULL)
+    {
+      struct header  *h;
+      unsigned  count;
+
+      fprintf (stderr, "tests_memory_end(): not all memory freed\n");
+
+      count = 0;
+      for (h = tests_memory_list; h != NULL; h = h->next)
+	count++;
+
+      fprintf (stderr, "    %u blocks remaining\n", count);
+      abort ();
+    }
+}
diff --git a/third_party/gmp/tests/misc.c b/third_party/gmp/tests/misc.c
new file mode 100644
index 0000000..6c40d78
--- /dev/null
+++ b/third_party/gmp/tests/misc.c
@@ -0,0 +1,608 @@
+/* Miscellaneous test program support routines.
+
+Copyright 2000-2003, 2005, 2013, 2015, 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#include <ctype.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>     /* for getenv */
+#include <string.h>
+
+#if HAVE_FLOAT_H
+#include <float.h>      /* for DBL_MANT_DIG */
+#endif
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>  /* for struct timeval */
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+/* The various tests setups and final checks, collected up together. */
+void
+tests_start (void)
+{
+  char version[10];
+  snprintf (version, 10, "%u.%u.%u",
+	    __GNU_MP_VERSION,
+	    __GNU_MP_VERSION_MINOR,
+	    __GNU_MP_VERSION_PATCHLEVEL);
+
+  if (strcmp (gmp_version, version) != 0)
+    {
+      fprintf (stderr, "tests are not linked to the newly compiled library\n");
+      fprintf (stderr, "  local version is: %s\n", version);
+      fprintf (stderr, "  linked version is: %s\n", gmp_version);
+      abort ();
+    }
+
+  /* don't buffer, so output is not lost if a test causes a segv etc */
+  setbuf (stdout, NULL);
+  setbuf (stderr, NULL);
+
+  tests_memory_start ();
+  tests_rand_start ();
+}
+void
+tests_end (void)
+{
+  tests_rand_end ();
+  tests_memory_end ();
+}
+
+static void
+seed_from_tod (gmp_randstate_ptr  rands)
+{
+  unsigned long seed;
+#if HAVE_GETTIMEOFDAY
+  struct timeval  tv;
+  gettimeofday (&tv, NULL);
+  seed = tv.tv_sec ^ ((unsigned long) tv.tv_usec << 12);
+  seed &= 0xffffffff;
+#else
+  time_t  tv;
+  time (&tv);
+  seed = tv;
+#endif
+  gmp_randseed_ui (rands, seed);
+  printf ("Seed GMP_CHECK_RANDOMIZE=%lu (include this in bug reports)\n", seed);
+}
+
+static void
+seed_from_urandom (gmp_randstate_ptr rands, FILE *fs)
+{
+  mpz_t seed;
+  unsigned char buf[6];
+  fread (buf, 1, 6, fs);
+  mpz_init (seed);
+  mpz_import (seed, 6, 1, 1, 0, 0, buf);
+  gmp_randseed (rands, seed);
+  gmp_printf ("Seed GMP_CHECK_RANDOMIZE=%Zd (include this in bug reports)\n", seed);
+  mpz_clear (seed);
+}
+
+void
+tests_rand_start (void)
+{
+  gmp_randstate_ptr  rands;
+  char           *seed_string;
+
+  if (__gmp_rands_initialized)
+    {
+      printf ("Please let tests_start() initialize the global __gmp_rands.\n");
+      printf ("ie. ensure that function is called before the first use of RANDS.\n");
+      abort ();
+    }
+
+  gmp_randinit_default (__gmp_rands);
+  __gmp_rands_initialized = 1;
+  rands = __gmp_rands;
+
+  seed_string = getenv ("GMP_CHECK_RANDOMIZE");
+  if (seed_string != NULL)
+    {
+      if (strcmp (seed_string, "0") != 0 &&
+	  strcmp (seed_string, "1") != 0)
+        {
+	  mpz_t seed;
+	  mpz_init_set_str (seed, seed_string, 0);
+          gmp_printf ("Re-seeding with GMP_CHECK_RANDOMIZE=%Zd\n", seed);
+          gmp_randseed (rands, seed);
+	  mpz_clear (seed);
+        }
+      else
+        {
+	  FILE *fs = fopen ("/dev/urandom", "r");
+	  if (fs != NULL)
+	    {
+	      seed_from_urandom (rands, fs);
+	      fclose (fs);
+	    }
+	  else
+	    seed_from_tod (rands);
+        }
+      fflush (stdout);
+    }
+}
+void
+tests_rand_end (void)
+{
+  RANDS_CLEAR ();
+}
+
+
+/* Only used if CPU calling conventions checking is available. */
+mp_limb_t (*calling_conventions_function) (ANYARGS);
+
+
+/* Return p advanced to the next multiple of "align" bytes.  "align" must be
+   a power of 2.  Care is taken not to assume sizeof(int)==sizeof(pointer).
+   Using "unsigned long" avoids a warning on hpux.  */
+void *
+align_pointer (void *p, size_t align)
+{
+  gmp_intptr_t d;
+  d = ((gmp_intptr_t) p) & (align-1);
+  d = (d != 0 ? align-d : 0);
+  return (void *) (((char *) p) + d);
+}
+
+
+/* Note that memory allocated with this function can never be freed, because
+   the start address of the block allocated is lost. */
+void *
+__gmp_allocate_func_aligned (size_t bytes, size_t align)
+{
+  return align_pointer ((*__gmp_allocate_func) (bytes + align-1), align);
+}
+
+
+void *
+__gmp_allocate_or_reallocate (void *ptr, size_t oldsize, size_t newsize)
+{
+  if (ptr == NULL)
+    return (*__gmp_allocate_func) (newsize);
+  else
+    return (*__gmp_reallocate_func) (ptr, oldsize, newsize);
+}
+
+char *
+__gmp_allocate_strdup (const char *s)
+{
+  size_t  len;
+  char    *t;
+  len = strlen (s);
+  t = (char *) (*__gmp_allocate_func) (len+1);
+  memcpy (t, s, len+1);
+  return t;
+}
+
+
+char *
+strtoupper (char *s_orig)
+{
+  char  *s;
+  for (s = s_orig; *s != '\0'; s++)
+    if (islower (*s))
+      *s = toupper (*s);
+  return s_orig;
+}
+
+
+void
+mpz_set_n (mpz_ptr z, mp_srcptr p, mp_size_t size)
+{
+  ASSERT (size >= 0);
+  MPN_NORMALIZE (p, size);
+  MPZ_REALLOC (z, size);
+  MPN_COPY (PTR(z), p, size);
+  SIZ(z) = size;
+}
+
+void
+mpz_init_set_n (mpz_ptr z, mp_srcptr p, mp_size_t size)
+{
+  ASSERT (size >= 0);
+
+  MPN_NORMALIZE (p, size);
+  ALLOC(z) = MAX (size, 1);
+  PTR(z) = __GMP_ALLOCATE_FUNC_LIMBS (ALLOC(z));
+  SIZ(z) = size;
+  MPN_COPY (PTR(z), p, size);
+}
+
+
+/* Find least significant limb position where p1,size and p2,size differ.  */
+mp_size_t
+mpn_diff_lowest (mp_srcptr p1, mp_srcptr p2, mp_size_t size)
+{
+  mp_size_t  i;
+
+  for (i = 0; i < size; i++)
+    if (p1[i] != p2[i])
+      return i;
+
+  /* no differences */
+  return -1;
+}
+
+
+/* Find most significant limb position where p1,size and p2,size differ.  */
+mp_size_t
+mpn_diff_highest (mp_srcptr p1, mp_srcptr p2, mp_size_t size)
+{
+  mp_size_t  i;
+
+  for (i = size-1; i >= 0; i--)
+    if (p1[i] != p2[i])
+      return i;
+
+  /* no differences */
+  return -1;
+}
+
+
+/* Find least significant byte position where p1,size and p2,size differ.  */
+mp_size_t
+byte_diff_lowest (const void *p1, const void *p2, mp_size_t size)
+{
+  mp_size_t  i;
+
+  for (i = 0; i < size; i++)
+    if (((const char *) p1)[i] != ((const char *) p2)[i])
+      return i;
+
+  /* no differences */
+  return -1;
+}
+
+
+/* Find most significant byte position where p1,size and p2,size differ.  */
+mp_size_t
+byte_diff_highest (const void *p1, const void *p2, mp_size_t size)
+{
+  mp_size_t  i;
+
+  for (i = size-1; i >= 0; i--)
+    if (((const char *) p1)[i] != ((const char *) p2)[i])
+      return i;
+
+  /* no differences */
+  return -1;
+}
+
+
+void
+mpz_set_str_or_abort (mpz_ptr z, const char *str, int base)
+{
+  if (mpz_set_str (z, str, base) != 0)
+    {
+      fprintf (stderr, "ERROR: mpz_set_str failed\n");
+      fprintf (stderr, "   str  = \"%s\"\n", str);
+      fprintf (stderr, "   base = %d\n", base);
+      abort();
+    }
+}
+
+void
+mpq_set_str_or_abort (mpq_ptr q, const char *str, int base)
+{
+  if (mpq_set_str (q, str, base) != 0)
+    {
+      fprintf (stderr, "ERROR: mpq_set_str failed\n");
+      fprintf (stderr, "   str  = \"%s\"\n", str);
+      fprintf (stderr, "   base = %d\n", base);
+      abort();
+    }
+}
+
+void
+mpf_set_str_or_abort (mpf_ptr f, const char *str, int base)
+{
+  if (mpf_set_str (f, str, base) != 0)
+    {
+      fprintf (stderr, "ERROR mpf_set_str failed\n");
+      fprintf (stderr, "   str  = \"%s\"\n", str);
+      fprintf (stderr, "   base = %d\n", base);
+      abort();
+    }
+}
+
+
+/* Whether the absolute value of z is a power of 2. */
+int
+mpz_pow2abs_p (mpz_srcptr z)
+{
+  mp_size_t  size, i;
+  mp_srcptr  ptr;
+
+  size = SIZ (z);
+  if (size == 0)
+    return 0;  /* zero is not a power of 2 */
+  size = ABS (size);
+
+  ptr = PTR (z);
+  for (i = 0; i < size-1; i++)
+    if (ptr[i] != 0)
+      return 0;  /* non-zero low limb means not a power of 2 */
+
+  return POW2_P (ptr[i]);  /* high limb power of 2 */
+}
+
+
+/* Exponentially distributed between 0 and 2^nbits-1, meaning the number of
+   bits in the result is uniformly distributed between 0 and nbits-1.
+
+   FIXME: This is not a proper exponential distribution, since the
+   probability function will have a stepped shape due to using a uniform
+   distribution after choosing how many bits.  */
+
+void
+mpz_erandomb (mpz_ptr rop, gmp_randstate_t rstate, unsigned long nbits)
+{
+  mpz_urandomb (rop, rstate, gmp_urandomm_ui (rstate, nbits));
+}
+
+void
+mpz_erandomb_nonzero (mpz_ptr rop, gmp_randstate_t rstate, unsigned long nbits)
+{
+  mpz_erandomb (rop, rstate, nbits);
+  if (mpz_sgn (rop) == 0)
+    mpz_set_ui (rop, 1L);
+}
+
+void
+mpz_errandomb (mpz_ptr rop, gmp_randstate_t rstate, unsigned long nbits)
+{
+  mpz_rrandomb (rop, rstate, gmp_urandomm_ui (rstate, nbits));
+}
+
+void
+mpz_errandomb_nonzero (mpz_ptr rop, gmp_randstate_t rstate, unsigned long nbits)
+{
+  mpz_errandomb (rop, rstate, nbits);
+  if (mpz_sgn (rop) == 0)
+    mpz_set_ui (rop, 1L);
+}
+
+void
+mpz_negrandom (mpz_ptr rop, gmp_randstate_t rstate)
+{
+  mp_limb_t  n;
+  _gmp_rand (&n, rstate, 1);
+  if (n != 0)
+    mpz_neg (rop, rop);
+}
+
+void
+mpz_clobber(mpz_ptr rop)
+{
+  MPN_ZERO(PTR(rop), ALLOC(rop));
+  PTR(rop)[0] = 0xDEADBEEF;
+  SIZ(rop) = 0xDEFACE;
+}
+
+mp_limb_t
+urandom (void)
+{
+#if GMP_NAIL_BITS == 0
+  mp_limb_t  n;
+  _gmp_rand (&n, RANDS, GMP_LIMB_BITS);
+  return n;
+#else
+  mp_limb_t n[2];
+  _gmp_rand (n, RANDS, GMP_LIMB_BITS);
+  return n[0] + (n[1] << GMP_NUMB_BITS);
+#endif
+}
+
+
+/* Call (*func)() with various random number generators. */
+void
+call_rand_algs (void (*func) (const char *, gmp_randstate_ptr))
+{
+  gmp_randstate_t  rstate;
+  mpz_t            a;
+
+  mpz_init (a);
+
+  gmp_randinit_default (rstate);
+  (*func) ("gmp_randinit_default", rstate);
+  gmp_randclear (rstate);
+
+  gmp_randinit_mt (rstate);
+  (*func) ("gmp_randinit_mt", rstate);
+  gmp_randclear (rstate);
+
+  gmp_randinit_lc_2exp_size (rstate, 8L);
+  (*func) ("gmp_randinit_lc_2exp_size 8", rstate);
+  gmp_randclear (rstate);
+
+  gmp_randinit_lc_2exp_size (rstate, 16L);
+  (*func) ("gmp_randinit_lc_2exp_size 16", rstate);
+  gmp_randclear (rstate);
+
+  gmp_randinit_lc_2exp_size (rstate, 128L);
+  (*func) ("gmp_randinit_lc_2exp_size 128", rstate);
+  gmp_randclear (rstate);
+
+  /* degenerate always zeros */
+  mpz_set_ui (a, 0L);
+  gmp_randinit_lc_2exp (rstate, a, 0L, 8L);
+  (*func) ("gmp_randinit_lc_2exp a=0 c=0 m=8", rstate);
+  gmp_randclear (rstate);
+
+  /* degenerate always FFs */
+  mpz_set_ui (a, 0L);
+  gmp_randinit_lc_2exp (rstate, a, 0xFFL, 8L);
+  (*func) ("gmp_randinit_lc_2exp a=0 c=0xFF m=8", rstate);
+  gmp_randclear (rstate);
+
+  mpz_clear (a);
+}
+
+
+/* Return +infinity if available, or 0 if not.
+   We don't want to use libm, so INFINITY or other system values are not
+   used here.  */
+double
+tests_infinity_d (void)
+{
+#if _GMP_IEEE_FLOATS
+  union ieee_double_extract x;
+  x.s.exp = 2047;
+  x.s.manl = 0;
+  x.s.manh = 0;
+  x.s.sig = 0;
+  return x.d;
+#else
+  return 0;
+#endif
+}
+
+
+/* Return non-zero if d is an infinity (either positive or negative).
+   Don't want libm, so don't use isinf() or other system tests.  */
+int
+tests_isinf (double d)
+{
+#if _GMP_IEEE_FLOATS
+  union ieee_double_extract x;
+  x.d = d;
+  return (x.s.exp == 2047 && x.s.manl == 0 && x.s.manh == 0);
+#else
+  return 0;
+#endif
+}
+
+
+/* Set the hardware floating point rounding mode.  Same mode values as mpfr,
+   namely 0=nearest, 1=tozero, 2=up, 3=down.  Return 1 if successful, 0 if
+   not.  */
+int
+tests_hardware_setround (int mode)
+{
+#if ! defined NO_ASM && HAVE_HOST_CPU_FAMILY_x86
+  int  rc;
+  switch (mode) {
+  case 0: rc = 0; break;  /* nearest */
+  case 1: rc = 3; break;  /* tozero  */
+  case 2: rc = 2; break;  /* up      */
+  case 3: rc = 1; break;  /* down    */
+  default:
+    return 0;
+  }
+  x86_fldcw ((x86_fstcw () & ~0xC00) | (rc << 10));
+  return 1;
+#endif
+
+  return 0;
+}
+
+/* Return the hardware floating point rounding mode, or -1 if unknown. */
+int
+tests_hardware_getround (void)
+{
+#if ! defined NO_ASM && HAVE_HOST_CPU_FAMILY_x86
+  switch ((x86_fstcw () & ~0xC00) >> 10) {
+  case 0: return 0; break;  /* nearest */
+  case 1: return 3; break;  /* down    */
+  case 2: return 2; break;  /* up      */
+  case 3: return 1; break;  /* tozero  */
+  }
+#endif
+
+  return -1;
+}
+
+
+/* tests_dbl_mant_bits() determines by experiment the number of bits in the
+   mantissa of a "double".  If it's not possible to find a value (perhaps
+   due to the compiler optimizing too aggressively), then return 0.
+
+   This code is used rather than DBL_MANT_DIG from <float.h> since ancient
+   systems like SunOS don't have that file, and since one GNU/Linux ARM
+   system was seen where the float emulation seemed to have only 32 working
+   bits, not the 53 float.h claimed.  */
+
+int
+tests_dbl_mant_bits (void)
+{
+  static int n = -1;
+  volatile double x, y, d;
+
+  if (n != -1)
+    return n;
+
+  n = 1;
+  x = 2.0;
+  for (;;)
+    {
+      /* see if 2^(n+1)+1 can be formed without rounding, if so then
+         continue, if not then "n" is the answer */
+      y = x + 1.0;
+      d = y - x;
+      if (d != 1.0)
+        {
+#if defined (DBL_MANT_DIG) && DBL_RADIX == 2
+          if (n != DBL_MANT_DIG)
+            printf ("Warning, tests_dbl_mant_bits got %d but DBL_MANT_DIG says %d\n", n, DBL_MANT_DIG);
+#endif
+          break;
+        }
+
+      x *= 2;
+      n++;
+
+      if (n > 1000)
+        {
+          printf ("Oops, tests_dbl_mant_bits can't determine mantissa size\n");
+          n = 0;
+          break;
+        }
+    }
+  return n;
+}
+
+
+/* See tests_setjmp_sigfpe in tests.h. */
+
+jmp_buf    tests_sigfpe_target;
+
+RETSIGTYPE
+tests_sigfpe_handler (int sig)
+{
+  longjmp (tests_sigfpe_target, 1);
+}
+
+void
+tests_sigfpe_done (void)
+{
+  signal (SIGFPE, SIG_DFL);
+}
diff --git a/third_party/gmp/tests/misc/Makefile.am b/third_party/gmp/tests/misc/Makefile.am
new file mode 100644
index 0000000..9fe6efb
--- /dev/null
+++ b/third_party/gmp/tests/misc/Makefile.am
@@ -0,0 +1,34 @@
+## Process this file with automake to generate Makefile.in
+
+# Copyright 2001, 2002 Free Software Foundation, Inc.
+#
+# This file is part of the GNU MP Library test suite.
+#
+# The GNU MP Library test suite is free software; you can redistribute it
+# and/or modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 3 of the License,
+# or (at your option) any later version.
+#
+# The GNU MP Library test suite is distributed in the hope that it will be
+# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.
+
+
+AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/tests
+AM_LDFLAGS = -no-install
+LDADD = $(top_builddir)/tests/libtests.la $(top_builddir)/libgmp.la
+
+check_PROGRAMS = t-printf t-scanf t-locale
+TESTS = $(check_PROGRAMS)
+
+# Temporary files used by the tests.  Removed automatically if the tests
+# pass, but ensure they're cleaned if they fail.
+#
+CLEANFILES = *.tmp
+
+$(top_builddir)/tests/libtests.la:
+	cd $(top_builddir)/tests; $(MAKE) $(AM_MAKEFLAGS) libtests.la
diff --git a/third_party/gmp/tests/misc/Makefile.in b/third_party/gmp/tests/misc/Makefile.in
new file mode 100644
index 0000000..62a5f04
--- /dev/null
+++ b/third_party/gmp/tests/misc/Makefile.in
@@ -0,0 +1,1041 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Copyright 2001, 2002 Free Software Foundation, Inc.
+#
+# This file is part of the GNU MP Library test suite.
+#
+# The GNU MP Library test suite is free software; you can redistribute it
+# and/or modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 3 of the License,
+# or (at your option) any later version.
+#
+# The GNU MP Library test suite is distributed in the hope that it will be
+# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+check_PROGRAMS = t-printf$(EXEEXT) t-scanf$(EXEEXT) t-locale$(EXEEXT)
+subdir = tests/misc
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+t_locale_SOURCES = t-locale.c
+t_locale_OBJECTS = t-locale.$(OBJEXT)
+t_locale_LDADD = $(LDADD)
+t_locale_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+t_printf_SOURCES = t-printf.c
+t_printf_OBJECTS = t-printf.$(OBJEXT)
+t_printf_LDADD = $(LDADD)
+t_printf_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_scanf_SOURCES = t-scanf.c
+t_scanf_OBJECTS = t-scanf.$(OBJEXT)
+t_scanf_LDADD = $(LDADD)
+t_scanf_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp =
+am__depfiles_maybe =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+SOURCES = t-locale.c t-printf.c t-scanf.c
+DIST_SOURCES = t-locale.c t-printf.c t-scanf.c
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__tty_colors_dummy = \
+  mgn= red= grn= lgn= blu= brg= std=; \
+  am__color_tests=no
+am__tty_colors = { \
+  $(am__tty_colors_dummy); \
+  if test "X$(AM_COLOR_TESTS)" = Xno; then \
+    am__color_tests=no; \
+  elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+    am__color_tests=yes; \
+  elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+    am__color_tests=yes; \
+  fi; \
+  if test $$am__color_tests = yes; then \
+    red=''; \
+    grn=''; \
+    lgn=''; \
+    blu=''; \
+    mgn=''; \
+    brg=''; \
+    std=''; \
+  fi; \
+}
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+  test -z "$$files" \
+    || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+    || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+         $(am__cd) "$$dir" && rm -f $$files; }; \
+  }
+am__recheck_rx = ^[ 	]*:recheck:[ 	]*
+am__global_test_result_rx = ^[ 	]*:global-test-result:[ 	]*
+am__copy_in_global_log_rx = ^[ 	]*:copy-in-global-log:[ 	]*
+# A command that, given a newline-separated list of test names on the
+# standard input, print the name of the tests that are to be re-run
+# upon "make recheck".
+am__list_recheck_tests = $(AWK) '{ \
+  recheck = 1; \
+  while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+    { \
+      if (rc < 0) \
+        { \
+          if ((getline line2 < ($$0 ".log")) < 0) \
+	    recheck = 0; \
+          break; \
+        } \
+      else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \
+        { \
+          recheck = 0; \
+          break; \
+        } \
+      else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \
+        { \
+          break; \
+        } \
+    }; \
+  if (recheck) \
+    print $$0; \
+  close ($$0 ".trs"); \
+  close ($$0 ".log"); \
+}'
+# A command that, given a newline-separated list of test names on the
+# standard input, create the global log from their .trs and .log files.
+am__create_global_log = $(AWK) ' \
+function fatal(msg) \
+{ \
+  print "fatal: making $@: " msg | "cat >&2"; \
+  exit 1; \
+} \
+function rst_section(header) \
+{ \
+  print header; \
+  len = length(header); \
+  for (i = 1; i <= len; i = i + 1) \
+    printf "="; \
+  printf "\n\n"; \
+} \
+{ \
+  copy_in_global_log = 1; \
+  global_test_result = "RUN"; \
+  while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+    { \
+      if (rc < 0) \
+         fatal("failed to read from " $$0 ".trs"); \
+      if (line ~ /$(am__global_test_result_rx)/) \
+        { \
+          sub("$(am__global_test_result_rx)", "", line); \
+          sub("[ 	]*$$", "", line); \
+          global_test_result = line; \
+        } \
+      else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \
+        copy_in_global_log = 0; \
+    }; \
+  if (copy_in_global_log) \
+    { \
+      rst_section(global_test_result ": " $$0); \
+      while ((rc = (getline line < ($$0 ".log"))) != 0) \
+      { \
+        if (rc < 0) \
+          fatal("failed to read from " $$0 ".log"); \
+        print line; \
+      }; \
+      printf "\n"; \
+    }; \
+  close ($$0 ".trs"); \
+  close ($$0 ".log"); \
+}'
+# Restructured Text title.
+am__rst_title = { sed 's/.*/   &   /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; }
+# Solaris 10 'make', and several other traditional 'make' implementations,
+# pass "-e" to $(SHELL), and POSIX 2008 even requires this.  Work around it
+# by disabling -e (using the XSI extension "set +e") if it's set.
+am__sh_e_setup = case $$- in *e*) set +e;; esac
+# Default flags passed to test drivers.
+am__common_driver_flags = \
+  --color-tests "$$am__color_tests" \
+  --enable-hard-errors "$$am__enable_hard_errors" \
+  --expect-failure "$$am__expect_failure"
+# To be inserted before the command running the test.  Creates the
+# directory for the log if needed.  Stores in $dir the directory
+# containing $f, in $tst the test, in $log the log.  Executes the
+# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and
+# passes TESTS_ENVIRONMENT.  Set up options for the wrapper that
+# will run the test scripts (or their associated LOG_COMPILER, if
+# thy have one).
+am__check_pre = \
+$(am__sh_e_setup);					\
+$(am__vpath_adj_setup) $(am__vpath_adj)			\
+$(am__tty_colors);					\
+srcdir=$(srcdir); export srcdir;			\
+case "$@" in						\
+  */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;;	\
+    *) am__odir=.;; 					\
+esac;							\
+test "x$$am__odir" = x"." || test -d "$$am__odir" 	\
+  || $(MKDIR_P) "$$am__odir" || exit $$?;		\
+if test -f "./$$f"; then dir=./;			\
+elif test -f "$$f"; then dir=;				\
+else dir="$(srcdir)/"; fi;				\
+tst=$$dir$$f; log='$@'; 				\
+if test -n '$(DISABLE_HARD_ERRORS)'; then		\
+  am__enable_hard_errors=no; 				\
+else							\
+  am__enable_hard_errors=yes; 				\
+fi; 							\
+case " $(XFAIL_TESTS) " in				\
+  *[\ \	]$$f[\ \	]* | *[\ \	]$$dir$$f[\ \	]*) \
+    am__expect_failure=yes;;				\
+  *)							\
+    am__expect_failure=no;;				\
+esac; 							\
+$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT)
+# A shell command to get the names of the tests scripts with any registered
+# extension removed (i.e., equivalently, the names of the test logs, with
+# the '.log' extension removed).  The result is saved in the shell variable
+# '$bases'.  This honors runtime overriding of TESTS and TEST_LOGS.  Sadly,
+# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)",
+# since that might cause problem with VPATH rewrites for suffix-less tests.
+# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'.
+am__set_TESTS_bases = \
+  bases='$(TEST_LOGS)'; \
+  bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \
+  bases=`echo $$bases`
+RECHECK_LOGS = $(TEST_LOGS)
+AM_RECURSIVE_TARGETS = check recheck
+TEST_SUITE_LOG = test-suite.log
+TEST_EXTENSIONS = @EXEEXT@ .test
+LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS)
+am__set_b = \
+  case '$@' in \
+    */*) \
+      case '$*' in \
+        */*) b='$*';; \
+          *) b=`echo '$@' | sed 's/\.log$$//'`; \
+       esac;; \
+    *) \
+      b='$*';; \
+  esac
+am__test_logs1 = $(TESTS:=.log)
+am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log)
+TEST_LOGS = $(am__test_logs2:.test.log=.log)
+TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \
+	$(TEST_LOG_FLAGS)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/test-driver
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ABI = @ABI@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+ASMFLAGS = @ASMFLAGS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CALLING_CONVENTIONS_OBJS = @CALLING_CONVENTIONS_OBJS@
+CC = @CC@
+CCAS = @CCAS@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPP_FOR_BUILD = @CPP_FOR_BUILD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFN_LONG_LONG_LIMB = @DEFN_LONG_LONG_LIMB@
+DEFS = @DEFS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@
+FGREP = @FGREP@
+GMP_LDFLAGS = @GMP_LDFLAGS@
+GMP_LIMB_BITS = @GMP_LIMB_BITS@
+GMP_NAIL_BITS = @GMP_NAIL_BITS@
+GREP = @GREP@
+HAVE_CLOCK_01 = @HAVE_CLOCK_01@
+HAVE_CPUTIME_01 = @HAVE_CPUTIME_01@
+HAVE_GETRUSAGE_01 = @HAVE_GETRUSAGE_01@
+HAVE_GETTIMEOFDAY_01 = @HAVE_GETTIMEOFDAY_01@
+HAVE_HOST_CPU_FAMILY_power = @HAVE_HOST_CPU_FAMILY_power@
+HAVE_HOST_CPU_FAMILY_powerpc = @HAVE_HOST_CPU_FAMILY_powerpc@
+HAVE_SIGACTION_01 = @HAVE_SIGACTION_01@
+HAVE_SIGALTSTACK_01 = @HAVE_SIGALTSTACK_01@
+HAVE_SIGSTACK_01 = @HAVE_SIGSTACK_01@
+HAVE_STACK_T_01 = @HAVE_STACK_T_01@
+HAVE_SYS_RESOURCE_H_01 = @HAVE_SYS_RESOURCE_H_01@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCURSES = @LIBCURSES@
+LIBGMPXX_LDFLAGS = @LIBGMPXX_LDFLAGS@
+LIBGMP_DLL = @LIBGMP_DLL@
+LIBGMP_LDFLAGS = @LIBGMP_LDFLAGS@
+LIBM = @LIBM@
+LIBM_FOR_BUILD = @LIBM_FOR_BUILD@
+LIBOBJS = @LIBOBJS@
+LIBREADLINE = @LIBREADLINE@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+M4 = @M4@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPEED_CYCLECOUNTER_OBJ = @SPEED_CYCLECOUNTER_OBJ@
+STRIP = @STRIP@
+TAL_OBJECT = @TAL_OBJECT@
+TUNE_LIBS = @TUNE_LIBS@
+TUNE_SQR_OBJ = @TUNE_SQR_OBJ@
+U_FOR_BUILD = @U_FOR_BUILD@
+VERSION = @VERSION@
+WITH_READLINE_01 = @WITH_READLINE_01@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__leading_dot = @am__leading_dot@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gmp_srclinks = @gmp_srclinks@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+mpn_objects = @mpn_objects@
+mpn_objs_in_libgmp = @mpn_objs_in_libgmp@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/tests
+AM_LDFLAGS = -no-install
+LDADD = $(top_builddir)/tests/libtests.la $(top_builddir)/libgmp.la
+TESTS = $(check_PROGRAMS)
+
+# Temporary files used by the tests.  Removed automatically if the tests
+# pass, but ensure they're cleaned if they fail.
+#
+CLEANFILES = *.tmp
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .log .o .obj .test .test$(EXEEXT) .trs
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu --ignore-deps tests/misc/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu --ignore-deps tests/misc/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-checkPROGRAMS:
+	@list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
+	echo " rm -f" $$list; \
+	rm -f $$list || exit $$?; \
+	test -n "$(EXEEXT)" || exit 0; \
+	list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+	echo " rm -f" $$list; \
+	rm -f $$list
+
+t-locale$(EXEEXT): $(t_locale_OBJECTS) $(t_locale_DEPENDENCIES) $(EXTRA_t_locale_DEPENDENCIES) 
+	@rm -f t-locale$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_locale_OBJECTS) $(t_locale_LDADD) $(LIBS)
+
+t-printf$(EXEEXT): $(t_printf_OBJECTS) $(t_printf_DEPENDENCIES) $(EXTRA_t_printf_DEPENDENCIES) 
+	@rm -f t-printf$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_printf_OBJECTS) $(t_printf_LDADD) $(LIBS)
+
+t-scanf$(EXEEXT): $(t_scanf_OBJECTS) $(t_scanf_DEPENDENCIES) $(EXTRA_t_scanf_DEPENDENCIES) 
+	@rm -f t-scanf$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_scanf_OBJECTS) $(t_scanf_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+.c.o:
+	$(AM_V_CC)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+	$(AM_V_CC)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+	$(AM_V_CC)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+# Recover from deleted '.trs' file; this should ensure that
+# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create
+# both 'foo.log' and 'foo.trs'.  Break the recipe in two subshells
+# to avoid problems with "make -n".
+.log.trs:
+	rm -f $< $@
+	$(MAKE) $(AM_MAKEFLAGS) $<
+
+# Leading 'am--fnord' is there to ensure the list of targets does not
+# expand to empty, as could happen e.g. with make check TESTS=''.
+am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck)
+am--force-recheck:
+	@:
+
+$(TEST_SUITE_LOG): $(TEST_LOGS)
+	@$(am__set_TESTS_bases); \
+	am__f_ok () { test -f "$$1" && test -r "$$1"; }; \
+	redo_bases=`for i in $$bases; do \
+	              am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \
+	            done`; \
+	if test -n "$$redo_bases"; then \
+	  redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \
+	  redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \
+	  if $(am__make_dryrun); then :; else \
+	    rm -f $$redo_logs && rm -f $$redo_results || exit 1; \
+	  fi; \
+	fi; \
+	if test -n "$$am__remaking_logs"; then \
+	  echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \
+	       "recursion detected" >&2; \
+	elif test -n "$$redo_logs"; then \
+	  am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \
+	fi; \
+	if $(am__make_dryrun); then :; else \
+	  st=0;  \
+	  errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \
+	  for i in $$redo_bases; do \
+	    test -f $$i.trs && test -r $$i.trs \
+	      || { echo "$$errmsg $$i.trs" >&2; st=1; }; \
+	    test -f $$i.log && test -r $$i.log \
+	      || { echo "$$errmsg $$i.log" >&2; st=1; }; \
+	  done; \
+	  test $$st -eq 0 || exit 1; \
+	fi
+	@$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \
+	ws='[ 	]'; \
+	results=`for b in $$bases; do echo $$b.trs; done`; \
+	test -n "$$results" || results=/dev/null; \
+	all=`  grep "^$$ws*:test-result:"           $$results | wc -l`; \
+	pass=` grep "^$$ws*:test-result:$$ws*PASS"  $$results | wc -l`; \
+	fail=` grep "^$$ws*:test-result:$$ws*FAIL"  $$results | wc -l`; \
+	skip=` grep "^$$ws*:test-result:$$ws*SKIP"  $$results | wc -l`; \
+	xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \
+	xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \
+	error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \
+	if test `expr $$fail + $$xpass + $$error` -eq 0; then \
+	  success=true; \
+	else \
+	  success=false; \
+	fi; \
+	br='==================='; br=$$br$$br$$br$$br; \
+	result_count () \
+	{ \
+	    if test x"$$1" = x"--maybe-color"; then \
+	      maybe_colorize=yes; \
+	    elif test x"$$1" = x"--no-color"; then \
+	      maybe_colorize=no; \
+	    else \
+	      echo "$@: invalid 'result_count' usage" >&2; exit 4; \
+	    fi; \
+	    shift; \
+	    desc=$$1 count=$$2; \
+	    if test $$maybe_colorize = yes && test $$count -gt 0; then \
+	      color_start=$$3 color_end=$$std; \
+	    else \
+	      color_start= color_end=; \
+	    fi; \
+	    echo "$${color_start}# $$desc $$count$${color_end}"; \
+	}; \
+	create_testsuite_report () \
+	{ \
+	  result_count $$1 "TOTAL:" $$all   "$$brg"; \
+	  result_count $$1 "PASS: " $$pass  "$$grn"; \
+	  result_count $$1 "SKIP: " $$skip  "$$blu"; \
+	  result_count $$1 "XFAIL:" $$xfail "$$lgn"; \
+	  result_count $$1 "FAIL: " $$fail  "$$red"; \
+	  result_count $$1 "XPASS:" $$xpass "$$red"; \
+	  result_count $$1 "ERROR:" $$error "$$mgn"; \
+	}; \
+	{								\
+	  echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" |	\
+	    $(am__rst_title);						\
+	  create_testsuite_report --no-color;				\
+	  echo;								\
+	  echo ".. contents:: :depth: 2";				\
+	  echo;								\
+	  for b in $$bases; do echo $$b; done				\
+	    | $(am__create_global_log);					\
+	} >$(TEST_SUITE_LOG).tmp || exit 1;				\
+	mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG);			\
+	if $$success; then						\
+	  col="$$grn";							\
+	 else								\
+	  col="$$red";							\
+	  test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG);		\
+	fi;								\
+	echo "$${col}$$br$${std}"; 					\
+	echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}";	\
+	echo "$${col}$$br$${std}"; 					\
+	create_testsuite_report --maybe-color;				\
+	echo "$$col$$br$$std";						\
+	if $$success; then :; else					\
+	  echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}";		\
+	  if test -n "$(PACKAGE_BUGREPORT)"; then			\
+	    echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}";	\
+	  fi;								\
+	  echo "$$col$$br$$std";					\
+	fi;								\
+	$$success || exit 1
+
+check-TESTS:
+	@list='$(RECHECK_LOGS)';           test -z "$$list" || rm -f $$list
+	@list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list
+	@test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+	@set +e; $(am__set_TESTS_bases); \
+	log_list=`for i in $$bases; do echo $$i.log; done`; \
+	trs_list=`for i in $$bases; do echo $$i.trs; done`; \
+	log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \
+	$(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \
+	exit $$?;
+recheck: all $(check_PROGRAMS)
+	@test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+	@set +e; $(am__set_TESTS_bases); \
+	bases=`for i in $$bases; do echo $$i; done \
+	         | $(am__list_recheck_tests)` || exit 1; \
+	log_list=`for i in $$bases; do echo $$i.log; done`; \
+	log_list=`echo $$log_list`; \
+	$(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \
+	        am__force_recheck=am--force-recheck \
+	        TEST_LOGS="$$log_list"; \
+	exit $$?
+t-printf.log: t-printf$(EXEEXT)
+	@p='t-printf$(EXEEXT)'; \
+	b='t-printf'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-scanf.log: t-scanf$(EXEEXT)
+	@p='t-scanf$(EXEEXT)'; \
+	b='t-scanf'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-locale.log: t-locale$(EXEEXT)
+	@p='t-locale$(EXEEXT)'; \
+	b='t-locale'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+.test.log:
+	@p='$<'; \
+	$(am__set_b); \
+	$(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+@am__EXEEXT_TRUE@.test$(EXEEXT).log:
+@am__EXEEXT_TRUE@	@p='$<'; \
+@am__EXEEXT_TRUE@	$(am__set_b); \
+@am__EXEEXT_TRUE@	$(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+@am__EXEEXT_TRUE@	--log-file $$b.log --trs-file $$b.trs \
+@am__EXEEXT_TRUE@	$(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+@am__EXEEXT_TRUE@	"$$tst" $(AM_TESTS_FD_REDIRECT)
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+	$(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+	-test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS)
+	-test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs)
+	-test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+
+clean-generic:
+	-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-TESTS check-am clean \
+	clean-checkPROGRAMS clean-generic clean-libtool cscopelist-am \
+	ctags ctags-am distclean distclean-compile distclean-generic \
+	distclean-libtool distclean-tags distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-dvi install-dvi-am install-exec \
+	install-exec-am install-html install-html-am install-info \
+	install-info-am install-man install-pdf install-pdf-am \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	recheck tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+$(top_builddir)/tests/libtests.la:
+	cd $(top_builddir)/tests; $(MAKE) $(AM_MAKEFLAGS) libtests.la
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/third_party/gmp/tests/misc/t-locale.c b/third_party/gmp/tests/misc/t-locale.c
new file mode 100644
index 0000000..a789309
--- /dev/null
+++ b/third_party/gmp/tests/misc/t-locale.c
@@ -0,0 +1,197 @@
+/* Test locale support, or attempt to do so.
+
+Copyright 2001, 2002, 2011, 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#define _GNU_SOURCE    /* for DECIMAL_POINT in glibc langinfo.h */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if HAVE_NL_TYPES_H
+#include <nl_types.h>  /* for nl_item (on netbsd 1.4.1 at least) */
+#endif
+
+#if HAVE_LANGINFO_H
+#include <langinfo.h>  /* for nl_langinfo */
+#endif
+
+#if HAVE_LOCALE_H
+#include <locale.h>    /* for lconv */
+#endif
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+const char *decimal_point;
+
+/* Replace the libc localeconv with one we can manipulate. */
+#if HAVE_LOCALECONV && ! defined __MINGW32__
+struct lconv *
+localeconv (void)
+#if defined __cplusplus && defined __GLIBC__
+  throw()
+#endif
+{
+  static struct lconv  l;
+  l.decimal_point = (char *) decimal_point;
+  return &l;
+}
+#endif
+
+/* Replace the libc nl_langinfo with one we can manipulate. */
+#if HAVE_NL_LANGINFO
+char *
+nl_langinfo (nl_item n)
+#if defined __cplusplus && defined __GLIBC__
+  throw()
+#endif
+{
+#if defined (DECIMAL_POINT)
+  if (n == DECIMAL_POINT)
+    return (char *) decimal_point;
+#endif
+#if defined (RADIXCHAR)
+  if (n == RADIXCHAR)
+    return (char *) decimal_point;
+#endif
+  return (char *) "";
+}
+#endif
+
+void
+check_input (void)
+{
+  static const char *point[] = {
+    ".", ",", "WU", "STR", "ZTV***"
+  };
+
+  static const struct {
+    const char  *str;
+    double      d;
+  } data[] = {
+
+    { "1%s",   1.0 },
+    { "1%s0",  1.0 },
+    { "1%s00", 1.0 },
+
+    { "%s5",    0.5 },
+    { "0%s5",   0.5 },
+    { "00%s5",  0.5 },
+    { "00%s50", 0.5 },
+
+    { "1%s5",    1.5 },
+    { "1%s5e1", 15.0 },
+  };
+
+  int     i, j, neg, ret;
+  char    str[128];
+  mpf_t   f;
+  double  d;
+
+  mpf_init (f);
+
+  for (i = 0; i < numberof (point); i++)
+    {
+      decimal_point = (const char *) point[i];
+
+      for (neg = 0; neg <= 1; neg++)
+        {
+          for (j = 0; j < numberof (data); j++)
+            {
+              strcpy (str, neg ? "-" : "");
+              sprintf (str+strlen(str), data[j].str, decimal_point);
+
+              d = data[j].d;
+              if (neg)
+                d = -d;
+
+              mpf_set_d (f, 123.0);
+              if (mpf_set_str (f, str, 10) != 0)
+                {
+                  printf ("mpf_set_str error\n");
+                  printf ("  point  %s\n", decimal_point);
+                  printf ("  str    %s\n", str);
+                  abort ();
+                }
+              if (mpf_cmp_d (f, d) != 0)
+                {
+                  printf    ("mpf_set_str wrong result\n");
+                  printf    ("  point  %s\n", decimal_point);
+                  printf    ("  str    %s\n", str);
+                  mpf_trace ("  f", f);
+                  printf    ("  d=%g\n", d);
+                  abort ();
+                }
+
+              mpf_set_d (f, 123.0);
+              ret = gmp_sscanf (str, "%Ff", f);
+              if (ret != 1)
+                {
+                  printf ("gmp_sscanf wrong return value\n");
+                  printf ("  point  %s\n", decimal_point);
+                  printf ("  str    %s\n", str);
+                  printf ("  ret    %d\n", ret);
+                  abort ();
+                }
+              if (mpf_cmp_d (f, d) != 0)
+                {
+                  printf    ("gmp_sscanf wrong result\n");
+                  printf    ("  point  %s\n", decimal_point);
+                  printf    ("  str    %s\n", str);
+                  mpf_trace ("  f", f);
+                  printf    ("  d=%g\n", d);
+                  abort ();
+                }
+            }
+        }
+    }
+  mpf_clear (f);
+}
+
+int
+main (void)
+{
+  /* The localeconv replacement breaks printf "%lu" on SunOS 4, so we can't
+     print the seed in tests_rand_start().  Nothing random is used in this
+     program though, so just use the memory tests alone.  */
+  tests_memory_start ();
+
+  {
+    mpf_t  f;
+    char   buf[128];
+    mpf_init (f);
+    decimal_point = ",";
+    mpf_set_d (f, 1.5);
+    gmp_snprintf (buf, sizeof(buf), "%.1Ff", f);
+    mpf_clear (f);
+    if (strcmp (buf, "1,5") != 0)
+      {
+        printf ("Test skipped, replacing localeconv/nl_langinfo doesn't work\n");
+        goto done;
+      }
+  }
+
+  check_input ();
+
+ done:
+  tests_memory_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/misc/t-printf.c b/third_party/gmp/tests/misc/t-printf.c
new file mode 100644
index 0000000..b0f6a30
--- /dev/null
+++ b/third_party/gmp/tests/misc/t-printf.c
@@ -0,0 +1,956 @@
+/* Test gmp_printf and related functions.
+
+Copyright 2001-2003, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+/* Usage: t-printf [-s]
+
+   -s  Check the data against the system printf, where possible.  This is
+       only an option since we don't want to fail if the system printf is
+       faulty or strange.  */
+
+
+#include "config.h"	/* needed for the HAVE_, could also move gmp incls */
+
+#include <stdarg.h>
+#include <stddef.h>    /* for ptrdiff_t */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if HAVE_OBSTACK_VPRINTF
+#define obstack_chunk_alloc tests_allocate
+#define obstack_chunk_free  tests_free_nosize
+#include <obstack.h>
+#endif
+
+#if HAVE_INTTYPES_H
+# include <inttypes.h> /* for intmax_t */
+#else
+# if HAVE_STDINT_H
+#  include <stdint.h>
+# endif
+#endif
+
+#if HAVE_UNISTD_H
+#include <unistd.h>  /* for unlink */
+#endif
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+int   option_check_printf = 0;
+
+
+#define CHECK_VFPRINTF_FILENAME  "t-printf.tmp"
+FILE  *check_vfprintf_fp;
+
+
+/* From any of the tests run here. */
+#define MAX_OUTPUT  1024
+
+
+void
+check_plain (const char *want, const char *fmt_orig, ...)
+{
+  char        got[MAX_OUTPUT];
+  int         got_len, want_len;
+  size_t      fmtsize;
+  char        *fmt, *q;
+  const char  *p;
+  va_list     ap;
+  va_start (ap, fmt_orig);
+
+  if (! option_check_printf)
+    return;
+
+  fmtsize = strlen (fmt_orig) + 1;
+  fmt = (char *) (*__gmp_allocate_func) (fmtsize);
+
+  for (p = fmt_orig, q = fmt; *p != '\0'; p++)
+    {
+      switch (*p) {
+      case 'a':
+      case 'A':
+	/* The exact value of the exponent isn't guaranteed in glibc, and it
+	   and gmp_printf do slightly different things, so don't compare
+	   directly. */
+	goto done;
+      case 'F':
+	if (p > fmt_orig && *(p-1) == '.')
+	  goto done;  /* don't test the "all digits" cases */
+	/* discard 'F' type */
+	break;
+      case 'Z':
+	/* transmute */
+	*q++ = 'l';
+	break;
+      default:
+	*q++ = *p;
+	break;
+      }
+    }
+  *q = '\0';
+
+  want_len = strlen (want);
+  ASSERT_ALWAYS (want_len < sizeof(got));
+
+  got_len = vsprintf (got, fmt, ap);
+
+  if (got_len != want_len || strcmp (got, want) != 0)
+    {
+      printf ("wanted data doesn't match plain vsprintf\n");
+      printf ("  fmt      |%s|\n", fmt);
+      printf ("  got      |%s|\n", got);
+      printf ("  want     |%s|\n", want);
+      printf ("  got_len  %d\n", got_len);
+      printf ("  want_len %d\n", want_len);
+      abort ();
+    }
+
+ done:
+  (*__gmp_free_func) (fmt, fmtsize);
+}
+
+void
+check_vsprintf (const char *want, const char *fmt, va_list ap)
+{
+  char  got[MAX_OUTPUT];
+  int   got_len, want_len;
+
+  want_len = strlen (want);
+  got_len = gmp_vsprintf (got, fmt, ap);
+
+  if (got_len != want_len || strcmp (got, want) != 0)
+    {
+      printf ("gmp_vsprintf wrong\n");
+      printf ("  fmt      |%s|\n", fmt);
+      printf ("  got      |%s|\n", got);
+      printf ("  want     |%s|\n", want);
+      printf ("  got_len  %d\n", got_len);
+      printf ("  want_len %d\n", want_len);
+      abort ();
+    }
+}
+
+void
+check_vfprintf (const char *want, const char *fmt, va_list ap)
+{
+  char  got[MAX_OUTPUT];
+  int   got_len, want_len, fread_len;
+  long  ftell_len;
+
+  want_len = strlen (want);
+
+  rewind (check_vfprintf_fp);
+  got_len = gmp_vfprintf (check_vfprintf_fp, fmt, ap);
+  ASSERT_ALWAYS (got_len != -1);
+  ASSERT_ALWAYS (fflush (check_vfprintf_fp) == 0);
+
+  ftell_len = ftell (check_vfprintf_fp);
+  ASSERT_ALWAYS (ftell_len != -1);
+
+  rewind (check_vfprintf_fp);
+  ASSERT_ALWAYS (ftell_len <= sizeof(got));
+  fread_len = fread (got, 1, ftell_len, check_vfprintf_fp);
+
+  if (got_len != want_len
+      || ftell_len != want_len
+      || fread_len != want_len
+      || memcmp (got, want, want_len) != 0)
+    {
+      printf ("gmp_vfprintf wrong\n");
+      printf ("  fmt       |%s|\n", fmt);
+      printf ("  got       |%.*s|\n", fread_len, got);
+      printf ("  want      |%s|\n", want);
+      printf ("  got_len   %d\n", got_len);
+      printf ("  ftell_len %ld\n", ftell_len);
+      printf ("  fread_len %d\n", fread_len);
+      printf ("  want_len  %d\n", want_len);
+      abort ();
+    }
+}
+
+void
+check_vsnprintf (const char *want, const char *fmt, va_list ap)
+{
+  char    got[MAX_OUTPUT+1];
+  int     ret, got_len, want_len;
+  size_t  bufsize;
+
+  want_len = strlen (want);
+
+  bufsize = -1;
+  for (;;)
+    {
+      /* do 0 to 5, then want-5 to want+5 */
+      bufsize++;
+      if (bufsize > 5 && bufsize < want_len-5)
+	bufsize = want_len-5;
+      if (bufsize > want_len + 5)
+	break;
+      ASSERT_ALWAYS (bufsize+1 <= sizeof (got));
+
+      got[bufsize] = '!';
+      ret = gmp_vsnprintf (got, bufsize, fmt, ap);
+
+      got_len = MIN (MAX(1,bufsize)-1, want_len);
+
+      if (got[bufsize] != '!')
+	{
+	  printf ("gmp_vsnprintf overwrote bufsize sentinel\n");
+	  goto error;
+	}
+
+      if (ret != want_len)
+	{
+	  printf ("gmp_vsnprintf return value wrong\n");
+	  goto error;
+	}
+
+      if (bufsize > 0)
+	{
+	  if (memcmp (got, want, got_len) != 0 || got[got_len] != '\0')
+	    {
+	      printf ("gmp_vsnprintf wrong result string\n");
+	    error:
+	      printf ("  fmt       |%s|\n", fmt);
+	      printf ("  bufsize   %lu\n", (unsigned long) bufsize);
+	      printf ("  got       |%s|\n", got);
+	      printf ("  want      |%.*s|\n", got_len, want);
+	      printf ("  want full |%s|\n", want);
+	      printf ("  ret       %d\n", ret);
+	      printf ("  want_len  %d\n", want_len);
+	      abort ();
+	    }
+	}
+    }
+}
+
+void
+check_vasprintf (const char *want, const char *fmt, va_list ap)
+{
+  char  *got;
+  int   got_len, want_len;
+
+  want_len = strlen (want);
+  got_len = gmp_vasprintf (&got, fmt, ap);
+
+  if (got_len != want_len || strcmp (got, want) != 0)
+    {
+      printf ("gmp_vasprintf wrong\n");
+      printf ("  fmt      |%s|\n", fmt);
+      printf ("  got      |%s|\n", got);
+      printf ("  want     |%s|\n", want);
+      printf ("  got_len  %d\n", got_len);
+      printf ("  want_len %d\n", want_len);
+      abort ();
+    }
+  (*__gmp_free_func) (got, strlen(got)+1);
+}
+
+void
+check_obstack_vprintf (const char *want, const char *fmt, va_list ap)
+{
+#if HAVE_OBSTACK_VPRINTF
+  struct obstack  ob;
+  int   got_len, want_len, ob_len;
+  char  *got;
+
+  want_len = strlen (want);
+
+  obstack_init (&ob);
+  got_len = gmp_obstack_vprintf (&ob, fmt, ap);
+  got = (char *) obstack_base (&ob);
+  ob_len = obstack_object_size (&ob);
+
+  if (got_len != want_len
+      || ob_len != want_len
+      || memcmp (got, want, want_len) != 0)
+    {
+      printf ("gmp_obstack_vprintf wrong\n");
+      printf ("  fmt      |%s|\n", fmt);
+      printf ("  got      |%s|\n", got);
+      printf ("  want     |%s|\n", want);
+      printf ("  got_len  %d\n", got_len);
+      printf ("  ob_len   %d\n", ob_len);
+      printf ("  want_len %d\n", want_len);
+      abort ();
+    }
+  obstack_free (&ob, NULL);
+#endif
+}
+
+
+void
+check_one (const char *want, const char *fmt, ...)
+{
+  va_list ap;
+  va_start (ap, fmt);
+
+  /* simplest first */
+  check_vsprintf (want, fmt, ap);
+  check_vfprintf (want, fmt, ap);
+  check_vsnprintf (want, fmt, ap);
+  check_vasprintf (want, fmt, ap);
+  check_obstack_vprintf (want, fmt, ap);
+}
+
+
+#define hex_or_octal_p(fmt)             \
+  (strchr (fmt, 'x') != NULL            \
+   || strchr (fmt, 'X') != NULL         \
+   || strchr (fmt, 'o') != NULL)
+
+void
+check_z (void)
+{
+  static const struct {
+    const char  *fmt;
+    const char  *z;
+    const char  *want;
+  } data[] = {
+    { "%Zd", "0",    "0" },
+    { "%Zd", "1",    "1" },
+    { "%Zd", "123",  "123" },
+    { "%Zd", "-1",   "-1" },
+    { "%Zd", "-123", "-123" },
+
+    { "%+Zd", "0",      "+0" },
+    { "%+Zd", "123",  "+123" },
+    { "%+Zd", "-123", "-123" },
+
+    { "%Zx",  "123",   "7b" },
+    { "%ZX",  "123",   "7B" },
+    { "%Zx", "-123",  "-7b" },
+    { "%ZX", "-123",  "-7B" },
+    { "%Zo",  "123",  "173" },
+    { "%Zo", "-123", "-173" },
+
+    { "%#Zx",    "0",     "0" },
+    { "%#ZX",    "0",     "0" },
+    { "%#Zx",  "123",  "0x7b" },
+    { "%#ZX",  "123",  "0X7B" },
+    { "%#Zx", "-123", "-0x7b" },
+    { "%#ZX", "-123", "-0X7B" },
+
+    { "%#Zo",    "0",     "0" },
+    { "%#Zo",  "123",  "0173" },
+    { "%#Zo", "-123", "-0173" },
+
+    { "%10Zd",      "0", "         0" },
+    { "%10Zd",    "123", "       123" },
+    { "%10Zd",   "-123", "      -123" },
+
+    { "%-10Zd",     "0", "0         " },
+    { "%-10Zd",   "123", "123       " },
+    { "%-10Zd",  "-123", "-123      " },
+
+    { "%+10Zd",   "123", "      +123" },
+    { "%+-10Zd",  "123", "+123      " },
+    { "%+10Zd",  "-123", "      -123" },
+    { "%+-10Zd", "-123", "-123      " },
+
+    { "%08Zd",    "0", "00000000" },
+    { "%08Zd",  "123", "00000123" },
+    { "%08Zd", "-123", "-0000123" },
+
+    { "%+08Zd",    "0", "+0000000" },
+    { "%+08Zd",  "123", "+0000123" },
+    { "%+08Zd", "-123", "-0000123" },
+
+    { "%#08Zx",    "0", "00000000" },
+    { "%#08Zx",  "123", "0x00007b" },
+    { "%#08Zx", "-123", "-0x0007b" },
+
+    { "%+#08Zx",    "0", "+0000000" },
+    { "%+#08Zx",  "123", "+0x0007b" },
+    { "%+#08Zx", "-123", "-0x0007b" },
+
+    { "%.0Zd", "0", "" },
+    { "%.1Zd", "0", "0" },
+    { "%.2Zd", "0", "00" },
+    { "%.3Zd", "0", "000" },
+  };
+
+  int        i, j;
+  mpz_t      z;
+  char       *nfmt;
+  mp_size_t  nsize, zeros;
+
+  mpz_init (z);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_set_str_or_abort (z, data[i].z, 0);
+
+      /* don't try negatives or forced sign in hex or octal */
+      if (mpz_fits_slong_p (z)
+	  && ! (hex_or_octal_p (data[i].fmt)
+		&& (strchr (data[i].fmt, '+') != NULL || mpz_sgn(z) < 0)))
+	{
+	  check_plain (data[i].want, data[i].fmt, mpz_get_si (z));
+	}
+
+      check_one (data[i].want, data[i].fmt, z);
+
+      /* Same again, with %N and possibly some high zero limbs */
+      nfmt = __gmp_allocate_strdup (data[i].fmt);
+      for (j = 0; nfmt[j] != '\0'; j++)
+	if (nfmt[j] == 'Z')
+	  nfmt[j] = 'N';
+      for (zeros = 0; zeros <= 3; zeros++)
+	{
+	  nsize = ABSIZ(z)+zeros;
+	  MPZ_REALLOC (z, nsize);
+	  nsize = (SIZ(z) >= 0 ? nsize : -nsize);
+	  refmpn_zero (PTR(z)+ABSIZ(z), zeros);
+	  check_one (data[i].want, nfmt, PTR(z), nsize);
+	}
+      __gmp_free_func (nfmt, strlen(nfmt)+1);
+    }
+
+  mpz_clear (z);
+}
+
+void
+check_q (void)
+{
+  static const struct {
+    const char  *fmt;
+    const char  *q;
+    const char  *want;
+  } data[] = {
+    { "%Qd",    "0",    "0" },
+    { "%Qd",    "1",    "1" },
+    { "%Qd",  "123",  "123" },
+    { "%Qd",   "-1",   "-1" },
+    { "%Qd", "-123", "-123" },
+    { "%Qd",  "3/2",  "3/2" },
+    { "%Qd", "-3/2", "-3/2" },
+
+    { "%+Qd", "0",      "+0" },
+    { "%+Qd", "123",  "+123" },
+    { "%+Qd", "-123", "-123" },
+    { "%+Qd", "5/8",  "+5/8" },
+    { "%+Qd", "-5/8", "-5/8" },
+
+    { "%Qx",  "123",   "7b" },
+    { "%QX",  "123",   "7B" },
+    { "%Qx",  "15/16", "f/10" },
+    { "%QX",  "15/16", "F/10" },
+    { "%Qx", "-123",  "-7b" },
+    { "%QX", "-123",  "-7B" },
+    { "%Qx", "-15/16", "-f/10" },
+    { "%QX", "-15/16", "-F/10" },
+    { "%Qo",  "123",  "173" },
+    { "%Qo", "-123", "-173" },
+    { "%Qo",  "16/17",  "20/21" },
+    { "%Qo", "-16/17", "-20/21" },
+
+    { "%#Qx",    "0",     "0" },
+    { "%#QX",    "0",     "0" },
+    { "%#Qx",  "123",  "0x7b" },
+    { "%#QX",  "123",  "0X7B" },
+    { "%#Qx",  "5/8",  "0x5/0x8" },
+    { "%#QX",  "5/8",  "0X5/0X8" },
+    { "%#Qx", "-123", "-0x7b" },
+    { "%#QX", "-123", "-0X7B" },
+    { "%#Qx", "-5/8", "-0x5/0x8" },
+    { "%#QX", "-5/8", "-0X5/0X8" },
+    { "%#Qo",    "0",     "0" },
+    { "%#Qo",  "123",  "0173" },
+    { "%#Qo", "-123", "-0173" },
+    { "%#Qo",  "5/7",  "05/07" },
+    { "%#Qo", "-5/7", "-05/07" },
+
+    /* zero denominator and showbase */
+    { "%#10Qo", "0/0",     "       0/0" },
+    { "%#10Qd", "0/0",     "       0/0" },
+    { "%#10Qx", "0/0",     "       0/0" },
+    { "%#10Qo", "123/0",   "    0173/0" },
+    { "%#10Qd", "123/0",   "     123/0" },
+    { "%#10Qx", "123/0",   "    0x7b/0" },
+    { "%#10QX", "123/0",   "    0X7B/0" },
+    { "%#10Qo", "-123/0",  "   -0173/0" },
+    { "%#10Qd", "-123/0",  "    -123/0" },
+    { "%#10Qx", "-123/0",  "   -0x7b/0" },
+    { "%#10QX", "-123/0",  "   -0X7B/0" },
+
+    { "%10Qd",      "0", "         0" },
+    { "%-10Qd",     "0", "0         " },
+    { "%10Qd",    "123", "       123" },
+    { "%-10Qd",   "123", "123       " },
+    { "%10Qd",   "-123", "      -123" },
+    { "%-10Qd",  "-123", "-123      " },
+
+    { "%+10Qd",   "123", "      +123" },
+    { "%+-10Qd",  "123", "+123      " },
+    { "%+10Qd",  "-123", "      -123" },
+    { "%+-10Qd", "-123", "-123      " },
+
+    { "%08Qd",    "0", "00000000" },
+    { "%08Qd",  "123", "00000123" },
+    { "%08Qd", "-123", "-0000123" },
+
+    { "%+08Qd",    "0", "+0000000" },
+    { "%+08Qd",  "123", "+0000123" },
+    { "%+08Qd", "-123", "-0000123" },
+
+    { "%#08Qx",    "0", "00000000" },
+    { "%#08Qx",  "123", "0x00007b" },
+    { "%#08Qx", "-123", "-0x0007b" },
+
+    { "%+#08Qx",    "0", "+0000000" },
+    { "%+#08Qx",  "123", "+0x0007b" },
+    { "%+#08Qx", "-123", "-0x0007b" },
+  };
+
+  int    i;
+  mpq_t  q;
+
+  mpq_init (q);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpq_set_str_or_abort (q, data[i].q, 0);
+      check_one (data[i].want, data[i].fmt, q);
+    }
+
+  mpq_clear (q);
+}
+
+void
+check_f (void)
+{
+  static const struct {
+    const char  *fmt;
+    const char  *f;
+    const char  *want;
+
+  } data[] = {
+
+    { "%Ff",    "0",    "0.000000" },
+    { "%Ff",  "123",  "123.000000" },
+    { "%Ff", "-123", "-123.000000" },
+
+    { "%+Ff",    "0",   "+0.000000" },
+    { "%+Ff",  "123", "+123.000000" },
+    { "%+Ff", "-123", "-123.000000" },
+
+    { "%.0Ff",    "0",    "0" },
+    { "%.0Ff",  "123",  "123" },
+    { "%.0Ff", "-123", "-123" },
+
+    { "%8.0Ff",    "0", "       0" },
+    { "%8.0Ff",  "123", "     123" },
+    { "%8.0Ff", "-123", "    -123" },
+
+    { "%08.0Ff",    "0", "00000000" },
+    { "%08.0Ff",  "123", "00000123" },
+    { "%08.0Ff", "-123", "-0000123" },
+
+    { "%10.2Ff",       "0", "      0.00" },
+    { "%10.2Ff",    "0.25", "      0.25" },
+    { "%10.2Ff",  "123.25", "    123.25" },
+    { "%10.2Ff", "-123.25", "   -123.25" },
+
+    { "%-10.2Ff",       "0", "0.00      " },
+    { "%-10.2Ff",    "0.25", "0.25      " },
+    { "%-10.2Ff",  "123.25", "123.25    " },
+    { "%-10.2Ff", "-123.25", "-123.25   " },
+
+    { "%.2Ff", "0.00000000000001", "0.00" },
+    { "%.2Ff", "0.002",            "0.00" },
+    { "%.2Ff", "0.008",            "0.01" },
+
+    { "%.0Ff", "123.00000000000001", "123" },
+    { "%.0Ff", "123.2",              "123" },
+    { "%.0Ff", "123.8",              "124" },
+
+    { "%.0Ff",  "999999.9", "1000000" },
+    { "%.0Ff", "3999999.9", "4000000" },
+
+    { "%Fe",    "0",  "0.000000e+00" },
+    { "%Fe",    "1",  "1.000000e+00" },
+    { "%Fe",  "123",  "1.230000e+02" },
+
+    { "%FE",    "0",  "0.000000E+00" },
+    { "%FE",    "1",  "1.000000E+00" },
+    { "%FE",  "123",  "1.230000E+02" },
+
+    { "%Fe",    "0",  "0.000000e+00" },
+    { "%Fe",    "1",  "1.000000e+00" },
+
+    { "%.0Fe",     "10000000000",    "1e+10" },
+    { "%.0Fe",    "-10000000000",   "-1e+10" },
+
+    { "%.2Fe",     "10000000000",  "1.00e+10" },
+    { "%.2Fe",    "-10000000000", "-1.00e+10" },
+
+    { "%8.0Fe",    "10000000000", "   1e+10" },
+    { "%8.0Fe",   "-10000000000", "  -1e+10" },
+
+    { "%-8.0Fe",   "10000000000", "1e+10   " },
+    { "%-8.0Fe",  "-10000000000", "-1e+10  " },
+
+    { "%12.2Fe",   "10000000000", "    1.00e+10" },
+    { "%12.2Fe",  "-10000000000", "   -1.00e+10" },
+
+    { "%012.2Fe",  "10000000000", "00001.00e+10" },
+    { "%012.2Fe", "-10000000000", "-0001.00e+10" },
+
+    { "%Fg",   "0", "0" },
+    { "%Fg",   "1", "1" },
+    { "%Fg",   "-1", "-1" },
+
+    { "%.0Fg", "0", "0" },
+    { "%.0Fg", "1", "1" },
+    { "%.0Fg", "-1", "-1" },
+
+    { "%.1Fg", "100", "1e+02" },
+    { "%.2Fg", "100", "1e+02" },
+    { "%.3Fg", "100", "100" },
+    { "%.4Fg", "100", "100" },
+
+    { "%Fg", "0.001",    "0.001" },
+    { "%Fg", "0.0001",   "0.0001" },
+    { "%Fg", "0.00001",  "1e-05" },
+    { "%Fg", "0.000001", "1e-06" },
+
+    { "%.4Fg", "1.00000000000001", "1" },
+    { "%.4Fg", "100000000000001",  "1e+14" },
+
+    { "%.4Fg", "12345678", "1.235e+07" },
+
+    { "%Fa", "0","0x0p+0" },
+    { "%FA", "0","0X0P+0" },
+
+    { "%Fa", "1","0x1p+0" },
+    { "%Fa", "65535","0xf.fffp+12" },
+    { "%Fa", "65536","0x1p+16" },
+    { "%F.10a", "65536","0x1.0000000000p+16" },
+    { "%F.1a", "65535","0x1.0p+16" },
+    { "%F.0a", "65535","0x1p+16" },
+
+    { "%.2Ff", "0.99609375", "1.00" },
+    { "%.Ff",  "0.99609375", "0.99609375" },
+    { "%.Fe",  "0.99609375", "9.9609375e-01" },
+    { "%.Fg",  "0.99609375", "0.99609375" },
+    { "%.20Fg",  "1000000", "1000000" },
+    { "%.Fg",  "1000000", "1000000" },
+
+    { "%#.0Ff", "1", "1." },
+    { "%#.0Fe", "1", "1.e+00" },
+    { "%#.0Fg", "1", "1." },
+
+    { "%#.1Ff", "1", "1.0" },
+    { "%#.1Fe", "1", "1.0e+00" },
+    { "%#.1Fg", "1", "1." },
+
+    { "%#.4Ff", "1234", "1234.0000" },
+    { "%#.4Fe", "1234", "1.2340e+03" },
+    { "%#.4Fg", "1234", "1234." },
+
+    { "%#.8Ff", "1234", "1234.00000000" },
+    { "%#.8Fe", "1234", "1.23400000e+03" },
+    { "%#.8Fg", "1234", "1234.0000" },
+
+  };
+
+  int     i;
+  mpf_t   f;
+  double  d;
+
+  mpf_init2 (f, 256L);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      if (data[i].f[0] == '0' && data[i].f[1] == 'x')
+	mpf_set_str_or_abort (f, data[i].f, 16);
+      else
+	mpf_set_str_or_abort (f, data[i].f, 10);
+
+      /* if mpf->double doesn't truncate, then expect same result */
+      d = mpf_get_d (f);
+      if (mpf_cmp_d (f, d) == 0)
+	check_plain (data[i].want, data[i].fmt, d);
+
+      check_one (data[i].want, data[i].fmt, f);
+    }
+
+  mpf_clear (f);
+}
+
+
+void
+check_limb (void)
+{
+  int        i;
+  mp_limb_t  limb;
+  mpz_t      z;
+  char       *s;
+
+  check_one ("0", "%Md", CNST_LIMB(0));
+  check_one ("1", "%Md", CNST_LIMB(1));
+
+  /* "i" many 1 bits, tested against mpz_get_str in decimal and hex */
+  limb = 1;
+  mpz_init_set_ui (z, 1L);
+  for (i = 1; i <= GMP_LIMB_BITS; i++)
+    {
+      s = mpz_get_str (NULL, 10, z);
+      check_one (s, "%Mu", limb);
+      (*__gmp_free_func) (s, strlen (s) + 1);
+
+      s = mpz_get_str (NULL, 16, z);
+      check_one (s, "%Mx", limb);
+      (*__gmp_free_func) (s, strlen (s) + 1);
+
+      s = mpz_get_str (NULL, -16, z);
+      check_one (s, "%MX", limb);
+      (*__gmp_free_func) (s, strlen (s) + 1);
+
+      limb = 2*limb + 1;
+      mpz_mul_2exp (z, z, 1L);
+      mpz_add_ui (z, z, 1L);
+    }
+
+  mpz_clear (z);
+}
+
+
+void
+check_n (void)
+{
+  {
+    int  n = -1;
+    check_one ("blah", "%nblah", &n);
+    ASSERT_ALWAYS (n == 0);
+  }
+
+  {
+    int  n = -1;
+    check_one ("hello ", "hello %n", &n);
+    ASSERT_ALWAYS (n == 6);
+  }
+
+  {
+    int  n = -1;
+    check_one ("hello  world", "hello %n world", &n);
+    ASSERT_ALWAYS (n == 6);
+  }
+
+#define CHECK_N(type, string)                           \
+  do {                                                  \
+    type  x[2];                                         \
+    char  fmt[128];                                     \
+							\
+    x[0] = ~ (type) 0;                                  \
+    x[1] = ~ (type) 0;                                  \
+    sprintf (fmt, "%%d%%%sn%%d", string);               \
+    check_one ("123456", fmt, 123, &x[0], 456);         \
+							\
+    /* should write whole of x[0] and none of x[1] */   \
+    ASSERT_ALWAYS (x[0] == 3);                          \
+    ASSERT_ALWAYS (x[1] == (type) ~ (type) 0);		\
+							\
+  } while (0)
+
+  CHECK_N (mp_limb_t, "M");
+  CHECK_N (char,      "hh");
+  CHECK_N (long,      "l");
+#if HAVE_LONG_LONG
+  CHECK_N (long long, "L");
+#endif
+#if HAVE_INTMAX_T
+  CHECK_N (intmax_t,  "j");
+#endif
+#if HAVE_PTRDIFF_T
+  CHECK_N (ptrdiff_t, "t");
+#endif
+  CHECK_N (short,     "h");
+  CHECK_N (size_t,    "z");
+
+  {
+    mpz_t  x[2];
+    mpz_init_set_si (x[0], -987L);
+    mpz_init_set_si (x[1],  654L);
+    check_one ("123456", "%d%Zn%d", 123, x[0], 456);
+    MPZ_CHECK_FORMAT (x[0]);
+    MPZ_CHECK_FORMAT (x[1]);
+    ASSERT_ALWAYS (mpz_cmp_ui (x[0], 3L) == 0);
+    ASSERT_ALWAYS (mpz_cmp_ui (x[1], 654L) == 0);
+    mpz_clear (x[0]);
+    mpz_clear (x[1]);
+  }
+
+  {
+    mpq_t  x[2];
+    mpq_init (x[0]);
+    mpq_init (x[1]);
+    mpq_set_ui (x[0], 987L, 654L);
+    mpq_set_ui (x[1], 4115L, 226L);
+    check_one ("123456", "%d%Qn%d", 123, x[0], 456);
+    MPQ_CHECK_FORMAT (x[0]);
+    MPQ_CHECK_FORMAT (x[1]);
+    ASSERT_ALWAYS (mpq_cmp_ui (x[0], 3L, 1L) == 0);
+    ASSERT_ALWAYS (mpq_cmp_ui (x[1], 4115L, 226L) == 0);
+    mpq_clear (x[0]);
+    mpq_clear (x[1]);
+  }
+
+  {
+    mpf_t  x[2];
+    mpf_init (x[0]);
+    mpf_init (x[1]);
+    mpf_set_ui (x[0], 987L);
+    mpf_set_ui (x[1], 654L);
+    check_one ("123456", "%d%Fn%d", 123, x[0], 456);
+    MPF_CHECK_FORMAT (x[0]);
+    MPF_CHECK_FORMAT (x[1]);
+    ASSERT_ALWAYS (mpf_cmp_ui (x[0], 3L) == 0);
+    ASSERT_ALWAYS (mpf_cmp_ui (x[1], 654L) == 0);
+    mpf_clear (x[0]);
+    mpf_clear (x[1]);
+  }
+
+  {
+    mp_limb_t  a[5];
+    mp_limb_t  a_want[numberof(a)];
+    mp_size_t  i;
+
+    a[0] = 123;
+    check_one ("blah", "bl%Nnah", a, (mp_size_t) 0);
+    ASSERT_ALWAYS (a[0] == 123);
+
+    MPN_ZERO (a_want, numberof (a_want));
+    for (i = 1; i < numberof (a); i++)
+      {
+	check_one ("blah", "bl%Nnah", a, i);
+	a_want[0] = 2;
+	ASSERT_ALWAYS (mpn_cmp (a, a_want, i) == 0);
+      }
+  }
+}
+
+
+void
+check_misc (void)
+{
+  mpz_t  z;
+  mpf_t  f;
+
+  mpz_init (z);
+  mpf_init2 (f, 128L);
+
+  check_one ("!", "%c", '!');
+
+  check_one ("hello world", "hello %s", "world");
+  check_one ("hello:", "%s:", "hello");
+  mpz_set_ui (z, 0L);
+  check_one ("hello0", "%s%Zd", "hello", z, z);
+
+  {
+    static char  xs[801];
+    memset (xs, 'x', sizeof(xs)-1);
+    check_one (xs, "%s", xs);
+  }
+  {
+    char  *xs;
+    xs = (char *) (*__gmp_allocate_func) (MAX_OUTPUT * 2 - 12);
+    memset (xs, '%', MAX_OUTPUT * 2 - 14);
+    xs [MAX_OUTPUT * 2 - 13] = '\0';
+    xs [MAX_OUTPUT * 2 - 14] = 'x';
+    check_one (xs + MAX_OUTPUT - 7, xs, NULL);
+    (*__gmp_free_func) (xs, MAX_OUTPUT * 2 - 12);
+  }
+
+  mpz_set_ui (z, 12345L);
+  check_one ("     12345", "%*Zd", 10, z);
+  check_one ("0000012345", "%0*Zd", 10, z);
+  check_one ("12345     ", "%*Zd", -10, z);
+  check_one ("12345 and 678", "%Zd and %d", z, 678);
+  check_one ("12345,1,12345,2,12345", "%Zd,%d,%Zd,%d,%Zd", z, 1, z, 2, z);
+
+  /* from the glibc info docs */
+  mpz_set_si (z, 0L);
+  check_one ("|    0|0    |   +0|+0   |    0|00000|     |   00|0|",
+	     "|%5Zd|%-5Zd|%+5Zd|%+-5Zd|% 5Zd|%05Zd|%5.0Zd|%5.2Zd|%Zd|",
+	     /**/ z,    z,    z,     z,    z,    z,     z,     z,  z);
+  mpz_set_si (z, 1L);
+  check_one ("|    1|1    |   +1|+1   |    1|00001|    1|   01|1|",
+	     "|%5Zd|%-5Zd|%+5Zd|%+-5Zd|% 5Zd|%05Zd|%5.0Zd|%5.2Zd|%Zd|",
+	     /**/ z,    z,    z,     z,    z,    z,     z,     z,  z);
+  mpz_set_si (z, -1L);
+  check_one ("|   -1|-1   |   -1|-1   |   -1|-0001|   -1|  -01|-1|",
+	     "|%5Zd|%-5Zd|%+5Zd|%+-5Zd|% 5Zd|%05Zd|%5.0Zd|%5.2Zd|%Zd|",
+	     /**/ z,    z,    z,     z,    z,    z,     z,     z,  z);
+  mpz_set_si (z, 100000L);
+  check_one ("|100000|100000|+100000|+100000| 100000|100000|100000|100000|100000|",
+	     "|%5Zd|%-5Zd|%+5Zd|%+-5Zd|% 5Zd|%05Zd|%5.0Zd|%5.2Zd|%Zd|",
+	     /**/ z,    z,    z,     z,    z,    z,     z,     z,  z);
+  mpz_set_si (z, 0L);
+  check_one ("|    0|    0|    0|    0|    0|    0|  00000000|",
+	     "|%5Zo|%5Zx|%5ZX|%#5Zo|%#5Zx|%#5ZX|%#10.8Zx|",
+	     /**/ z,   z,   z,    z,    z,    z,       z);
+  mpz_set_si (z, 1L);
+  check_one ("|    1|    1|    1|   01|  0x1|  0X1|0x00000001|",
+	     "|%5Zo|%5Zx|%5ZX|%#5Zo|%#5Zx|%#5ZX|%#10.8Zx|",
+	     /**/ z,   z,   z,    z,    z,    z,       z);
+  mpz_set_si (z, 100000L);
+  check_one ("|303240|186a0|186A0|0303240|0x186a0|0X186A0|0x000186a0|",
+	     "|%5Zo|%5Zx|%5ZX|%#5Zo|%#5Zx|%#5ZX|%#10.8Zx|",
+	     /**/ z,   z,   z,    z,    z,    z,       z);
+
+  /* %zd for size_t won't be available on old systems, and running something
+     to see if it works might be bad, so only try it on glibc, and only on a
+     new enough version (glibc 2.0 doesn't have %zd) */
+#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 0)
+  mpz_set_ui (z, 789L);
+  check_one ("456 789 blah", "%zd %Zd blah", (size_t) 456, z);
+#endif
+
+  mpz_clear (z);
+  mpf_clear (f);
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  if (argc > 1 && strcmp (argv[1], "-s") == 0)
+    option_check_printf = 1;
+
+  tests_start ();
+  check_vfprintf_fp = fopen (CHECK_VFPRINTF_FILENAME, "w+");
+  ASSERT_ALWAYS (check_vfprintf_fp != NULL);
+
+  check_z ();
+  check_q ();
+  check_f ();
+  check_limb ();
+  check_n ();
+  check_misc ();
+
+  ASSERT_ALWAYS (fclose (check_vfprintf_fp) == 0);
+  unlink (CHECK_VFPRINTF_FILENAME);
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/misc/t-scanf.c b/third_party/gmp/tests/misc/t-scanf.c
new file mode 100644
index 0000000..fdae5de
--- /dev/null
+++ b/third_party/gmp/tests/misc/t-scanf.c
@@ -0,0 +1,1616 @@
+/* Test gmp_scanf and related functions.
+
+Copyright 2001-2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+/* Usage: t-scanf [-s]
+
+   -s  Check the data against the system scanf, where possible.  This is
+       only an option since we don't want to fail if the system scanf is
+       faulty or strange.
+
+   There's some fairly unattractive repetition between check_z, check_q and
+   check_f, but enough differences to make a common loop or a set of macros
+   seem like too much trouble. */
+
+#include "config.h"	/* needed for the HAVE_, could also move gmp incls */
+
+#include <stdarg.h>
+
+#include <stddef.h>    /* for ptrdiff_t */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if HAVE_INTTYPES_H
+# include <inttypes.h> /* for intmax_t */
+#else
+# if HAVE_STDINT_H
+#  include <stdint.h>
+# endif
+#endif
+
+#if HAVE_UNISTD_H
+#include <unistd.h>  /* for unlink */
+#endif
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+#define TEMPFILE  "t-scanf.tmp"
+
+int   option_libc_scanf = 0;
+
+typedef int (*fun_t) (const char *, const char *, void *, void *);
+
+
+/* This problem was seen on powerpc7450-apple-darwin7.0.0, sscanf returns 0
+   where it should return EOF.  A workaround in gmp_sscanf would be a bit
+   tedious, and since this is a rather obvious libc bug, quite likely
+   affecting other programs, we'll just suppress affected tests for now.  */
+int
+test_sscanf_eof_ok (void)
+{
+  static int  result = -1;
+
+  if (result == -1)
+    {
+      int  x;
+      if (sscanf ("", "%d", &x) == EOF)
+        {
+          result = 1;
+        }
+      else
+        {
+          printf ("Warning, sscanf(\"\",\"%%d\",&x) doesn't return EOF.\n");
+          printf ("This affects gmp_sscanf, tests involving it will be suppressed.\n");
+          printf ("You should try to get a fix for your libc.\n");
+          result = 0;
+        }
+    }
+  return result;
+}
+
+
+/* Convert fmt from a GMP scanf format string to an equivalent for a plain
+   libc scanf, for example "%Zd" becomes "%ld".  Return 1 if this succeeds,
+   0 if it cannot (or should not) be done.  */
+int
+libc_scanf_convert (char *fmt)
+{
+  char  *p = fmt;
+
+  if (! option_libc_scanf)
+    return 0;
+
+  for ( ; *fmt != '\0'; fmt++)
+    {
+      switch (*fmt) {
+      case 'F':
+      case 'Q':
+      case 'Z':
+        /* transmute */
+        *p++ = 'l';
+        break;
+      default:
+        *p++ = *fmt;
+        break;
+      }
+    }
+  *p = '\0';
+  return 1;
+}
+
+
+long  got_ftell;
+int   fromstring_next_c;
+
+/* Call gmp_fscanf, reading the "input" string data provided. */
+int
+fromstring_gmp_fscanf (const char *input, const char *fmt, ...)
+{
+  va_list  ap;
+  FILE     *fp;
+  int      ret;
+  va_start (ap, fmt);
+
+  fp = fopen (TEMPFILE, "w+");
+  ASSERT_ALWAYS (fp != NULL);
+  ASSERT_ALWAYS (fputs (input, fp) != EOF);
+  ASSERT_ALWAYS (fflush (fp) == 0);
+  rewind (fp);
+
+  ret = gmp_vfscanf (fp, fmt, ap);
+  got_ftell = ftell (fp);
+  ASSERT_ALWAYS (got_ftell != -1L);
+
+  fromstring_next_c = getc (fp);
+
+  ASSERT_ALWAYS (fclose (fp) == 0);
+  va_end (ap);
+  return ret;
+}
+
+
+int
+fun_gmp_sscanf (const char *input, const char *fmt, void *a1, void *a2)
+{
+  if (a2 == NULL)
+    return gmp_sscanf (input, fmt, a1);
+  else
+    return gmp_sscanf (input, fmt, a1, a2);
+}
+
+int
+fun_gmp_fscanf (const char *input, const char *fmt, void *a1, void *a2)
+{
+  if (a2 == NULL)
+    return fromstring_gmp_fscanf (input, fmt, a1);
+  else
+    return fromstring_gmp_fscanf (input, fmt, a1, a2);
+}
+
+
+int
+fun_fscanf (const char *input, const char *fmt, void *a1, void *a2)
+{
+  FILE  *fp;
+  int   ret;
+
+  fp = fopen (TEMPFILE, "w+");
+  ASSERT_ALWAYS (fp != NULL);
+  ASSERT_ALWAYS (fputs (input, fp) != EOF);
+  ASSERT_ALWAYS (fflush (fp) == 0);
+  rewind (fp);
+
+  if (a2 == NULL)
+    ret = fscanf (fp, fmt, a1);
+  else
+    ret = fscanf (fp, fmt, a1, a2);
+
+  got_ftell = ftell (fp);
+  ASSERT_ALWAYS (got_ftell != -1L);
+
+  fromstring_next_c = getc (fp);
+
+  ASSERT_ALWAYS (fclose (fp) == 0);
+  return ret;
+}
+
+
+/* On various old systems, for instance HP-UX 9, the C library sscanf needs
+   to be able to write into the input string.  Ensure that this is possible,
+   when gcc is putting the test data into a read-only section.
+
+   Actually we ought to only need this under SSCANF_WRITABLE_INPUT from
+   configure, but it's just as easy to do it unconditionally, and in any
+   case this code is only executed under the -s option.  */
+
+int
+fun_sscanf (const char *input, const char *fmt, void *a1, void *a2)
+{
+  char    *input_writable;
+  size_t  size;
+  int     ret;
+
+  size = strlen (input) + 1;
+  input_writable = (char *) (*__gmp_allocate_func) (size);
+  memcpy (input_writable, input, size);
+
+  if (a2 == NULL)
+    ret = sscanf (input_writable, fmt, a1);
+  else
+    ret = sscanf (input_writable, fmt, a1, a2);
+
+  (*__gmp_free_func) (input_writable, size);
+  return ret;
+}
+
+
+/* whether the format string consists entirely of ignored fields */
+int
+fmt_allignore (const char *fmt)
+{
+  int  saw_star = 1;
+  for ( ; *fmt != '\0'; fmt++)
+    {
+      switch (*fmt) {
+      case '%':
+        if (! saw_star)
+          return 0;
+        saw_star = 0;
+        break;
+      case '*':
+        saw_star = 1;
+        break;
+      }
+    }
+  return 1;
+}
+
+void
+check_z (void)
+{
+  static const struct {
+    const char  *fmt;
+    const char  *input;
+    const char  *want;
+    int         want_ret;
+    long        want_ftell;
+    int         want_upto;
+    int         not_glibc;
+
+  } data[] = {
+
+    { "%Zd",    "0",    "0", 1, -1, -1 },
+    { "%Zd",    "1",    "1", 1, -1, -1 },
+    { "%Zd",  "123",  "123", 1, -1, -1 },
+    { "%Zd",   "+0",    "0", 1, -1, -1 },
+    { "%Zd",   "+1",    "1", 1, -1, -1 },
+    { "%Zd", "+123",  "123", 1, -1, -1 },
+    { "%Zd",   "-0",    "0", 1, -1, -1 },
+    { "%Zd",   "-1",   "-1", 1, -1, -1 },
+    { "%Zd", "-123", "-123", 1, -1, -1 },
+
+    { "%Zo",    "0",    "0", 1, -1, -1 },
+    { "%Zo",  "173",  "123", 1, -1, -1 },
+    { "%Zo",   "+0",    "0", 1, -1, -1 },
+    { "%Zo", "+173",  "123", 1, -1, -1 },
+    { "%Zo",   "-0",    "0", 1, -1, -1 },
+    { "%Zo", "-173", "-123", 1, -1, -1 },
+
+    { "%Zx",    "0",    "0", 1, -1, -1 },
+    { "%Zx",   "7b",  "123", 1, -1, -1 },
+    { "%Zx",   "7b",  "123", 1, -1, -1 },
+    { "%Zx",   "+0",    "0", 1, -1, -1 },
+    { "%Zx",  "+7b",  "123", 1, -1, -1 },
+    { "%Zx",  "+7b",  "123", 1, -1, -1 },
+    { "%Zx",   "-0",   "-0", 1, -1, -1 },
+    { "%Zx",  "-7b", "-123", 1, -1, -1 },
+    { "%Zx",  "-7b", "-123", 1, -1, -1 },
+    { "%ZX",    "0",    "0", 1, -1, -1 },
+    { "%ZX",   "7b",  "123", 1, -1, -1 },
+    { "%ZX",   "7b",  "123", 1, -1, -1 },
+    { "%ZX",   "+0",    "0", 1, -1, -1 },
+    { "%ZX",  "+7b",  "123", 1, -1, -1 },
+    { "%ZX",  "+7b",  "123", 1, -1, -1 },
+    { "%ZX",   "-0",   "-0", 1, -1, -1 },
+    { "%ZX",  "-7b", "-123", 1, -1, -1 },
+    { "%ZX",  "-7b", "-123", 1, -1, -1 },
+    { "%Zx",    "0",    "0", 1, -1, -1 },
+    { "%Zx",   "7B",  "123", 1, -1, -1 },
+    { "%Zx",   "7B",  "123", 1, -1, -1 },
+    { "%Zx",   "+0",    "0", 1, -1, -1 },
+    { "%Zx",  "+7B",  "123", 1, -1, -1 },
+    { "%Zx",  "+7B",  "123", 1, -1, -1 },
+    { "%Zx",   "-0",   "-0", 1, -1, -1 },
+    { "%Zx",  "-7B", "-123", 1, -1, -1 },
+    { "%Zx",  "-7B", "-123", 1, -1, -1 },
+    { "%ZX",    "0",    "0", 1, -1, -1 },
+    { "%ZX",   "7B",  "123", 1, -1, -1 },
+    { "%ZX",   "7B",  "123", 1, -1, -1 },
+    { "%ZX",   "+0",    "0", 1, -1, -1 },
+    { "%ZX",  "+7B",  "123", 1, -1, -1 },
+    { "%ZX",  "+7B",  "123", 1, -1, -1 },
+    { "%ZX",   "-0",   "-0", 1, -1, -1 },
+    { "%ZX",  "-7B", "-123", 1, -1, -1 },
+    { "%ZX",  "-7B", "-123", 1, -1, -1 },
+
+    { "%Zi",    "0",    "0", 1, -1, -1 },
+    { "%Zi",    "1",    "1", 1, -1, -1 },
+    { "%Zi",  "123",  "123", 1, -1, -1 },
+    { "%Zi",   "+0",    "0", 1, -1, -1 },
+    { "%Zi",   "+1",    "1", 1, -1, -1 },
+    { "%Zi", "+123",  "123", 1, -1, -1 },
+    { "%Zi",   "-0",    "0", 1, -1, -1 },
+    { "%Zi",   "-1",   "-1", 1, -1, -1 },
+    { "%Zi", "-123", "-123", 1, -1, -1 },
+
+    { "%Zi",    "00",    "0", 1, -1, -1 },
+    { "%Zi",  "0173",  "123", 1, -1, -1 },
+    { "%Zi",   "+00",    "0", 1, -1, -1 },
+    { "%Zi", "+0173",  "123", 1, -1, -1 },
+    { "%Zi",   "-00",    "0", 1, -1, -1 },
+    { "%Zi", "-0173", "-123", 1, -1, -1 },
+
+    { "%Zi",    "0x0",    "0", 1, -1, -1 },
+    { "%Zi",   "0x7b",  "123", 1, -1, -1 },
+    { "%Zi",   "0x7b",  "123", 1, -1, -1 },
+    { "%Zi",   "+0x0",    "0", 1, -1, -1 },
+    { "%Zi",  "+0x7b",  "123", 1, -1, -1 },
+    { "%Zi",  "+0x7b",  "123", 1, -1, -1 },
+    { "%Zi",   "-0x0",   "-0", 1, -1, -1 },
+    { "%Zi",  "-0x7b", "-123", 1, -1, -1 },
+    { "%Zi",  "-0x7b", "-123", 1, -1, -1 },
+    { "%Zi",    "0X0",    "0", 1, -1, -1 },
+    { "%Zi",   "0X7b",  "123", 1, -1, -1 },
+    { "%Zi",   "0X7b",  "123", 1, -1, -1 },
+    { "%Zi",   "+0X0",    "0", 1, -1, -1 },
+    { "%Zi",  "+0X7b",  "123", 1, -1, -1 },
+    { "%Zi",  "+0X7b",  "123", 1, -1, -1 },
+    { "%Zi",   "-0X0",   "-0", 1, -1, -1 },
+    { "%Zi",  "-0X7b", "-123", 1, -1, -1 },
+    { "%Zi",  "-0X7b", "-123", 1, -1, -1 },
+    { "%Zi",    "0x0",    "0", 1, -1, -1 },
+    { "%Zi",   "0x7B",  "123", 1, -1, -1 },
+    { "%Zi",   "0x7B",  "123", 1, -1, -1 },
+    { "%Zi",   "+0x0",    "0", 1, -1, -1 },
+    { "%Zi",  "+0x7B",  "123", 1, -1, -1 },
+    { "%Zi",  "+0x7B",  "123", 1, -1, -1 },
+    { "%Zi",   "-0x0",   "-0", 1, -1, -1 },
+    { "%Zi",  "-0x7B", "-123", 1, -1, -1 },
+    { "%Zi",  "-0x7B", "-123", 1, -1, -1 },
+    { "%Zi",    "0X0",    "0", 1, -1, -1 },
+    { "%Zi",   "0X7B",  "123", 1, -1, -1 },
+    { "%Zi",   "0X7B",  "123", 1, -1, -1 },
+    { "%Zi",   "+0X0",    "0", 1, -1, -1 },
+    { "%Zi",  "+0X7B",  "123", 1, -1, -1 },
+    { "%Zi",  "+0X7B",  "123", 1, -1, -1 },
+    { "%Zi",   "-0X0",   "-0", 1, -1, -1 },
+    { "%Zi",  "-0X7B", "-123", 1, -1, -1 },
+    { "%Zi",  "-0X7B", "-123", 1, -1, -1 },
+
+    { "%Zd",    " 0",    "0", 1, -1, -1 },
+    { "%Zd",   "  0",    "0", 1, -1, -1 },
+    { "%Zd",  "   0",    "0", 1, -1, -1 },
+    { "%Zd",   "\t0",    "0", 1, -1, -1 },
+    { "%Zd", "\t\t0",    "0", 1, -1, -1 },
+
+    { "hello%Zd",      "hello0",       "0", 1, -1, -1 },
+    { "hello%Zd",      "hello 0",      "0", 1, -1, -1 },
+    { "hello%Zd",      "hello \t0",    "0", 1, -1, -1 },
+    { "hello%Zdworld", "hello 0world", "0", 1, -1, -1 },
+
+    { "hello%*Zd",      "hello0",       "-999", 0, -1, -1 },
+    { "hello%*Zd",      "hello 0",      "-999", 0, -1, -1 },
+    { "hello%*Zd",      "hello \t0",    "-999", 0, -1, -1 },
+    { "hello%*Zdworld", "hello 0world", "-999", 0, -1, -1 },
+
+    { "%Zd",    "",     "-999", -1, -1, -555 },
+    { "%Zd",    " ",    "-999", -1, -1, -555 },
+    { " %Zd",   "",     "-999", -1, -1, -555 },
+    { "xyz%Zd", "",     "-999", -1, -1, -555 },
+
+    { "%*Zd",    "",     "-999", -1, -1, -555 },
+    { " %*Zd",   "",     "-999", -1, -1, -555 },
+    { "xyz%*Zd", "",     "-999", -1, -1, -555 },
+
+    { "%Zd",    "xyz",  "0",     0, 0, -555 },
+
+    /* match something, but invalid */
+    { "%Zd",    "-",    "-999",  0, 1, -555 },
+    { "%Zd",    "+",    "-999",  0, 1, -555 },
+    { "xyz%Zd", "xyz-", "-999",  0, 4, -555 },
+    { "xyz%Zd", "xyz+", "-999",  0, 4, -555 },
+    { "%Zi",    "0x",   "-999",  0, 2, -555 },
+    { "%Zi",    "0X",   "-999",  0, 2, -555 },
+    { "%Zi",    "0x-",  "-999",  0, 2, -555 },
+    { "%Zi",    "0X+",  "-999",  0, 2, -555 },
+    { "%Zi",    "-0x",  "-999",  0, 3, -555 },
+    { "%Zi",    "-0X",  "-999",  0, 3, -555 },
+    { "%Zi",    "+0x",  "-999",  0, 3, -555 },
+    { "%Zi",    "+0X",  "-999",  0, 3, -555 },
+
+    { "%1Zi",  "1234", "1",    1, 1, 1 },
+    { "%2Zi",  "1234", "12",   1, 2, 2 },
+    { "%3Zi",  "1234", "123",  1, 3, 3 },
+    { "%4Zi",  "1234", "1234", 1, 4, 4 },
+    { "%5Zi",  "1234", "1234", 1, 4, 4 },
+    { "%6Zi",  "1234", "1234", 1, 4, 4 },
+
+    { "%1Zi",  "01234", "0",     1, 1, 1 },
+    { "%2Zi",  "01234", "01",    1, 2, 2 },
+    { "%3Zi",  "01234", "012",   1, 3, 3 },
+    { "%4Zi",  "01234", "0123",  1, 4, 4 },
+    { "%5Zi",  "01234", "01234", 1, 5, 5 },
+    { "%6Zi",  "01234", "01234", 1, 5, 5 },
+    { "%7Zi",  "01234", "01234", 1, 5, 5 },
+
+    { "%1Zi",  "0x1234", "0",      1, 1, 1 },
+    { "%2Zi",  "0x1234", "-999",   0, 2, -555 },
+    { "%3Zi",  "0x1234", "0x1",    1, 3, 3 },
+    { "%4Zi",  "0x1234", "0x12",   1, 4, 4 },
+    { "%5Zi",  "0x1234", "0x123",  1, 5, 5 },
+    { "%6Zi",  "0x1234", "0x1234", 1, 6, 6 },
+    { "%7Zi",  "0x1234", "0x1234", 1, 6, 6 },
+    { "%8Zi",  "0x1234", "0x1234", 1, 6, 6 },
+
+    { "%%xyz%Zd",  "%xyz123",  "123", 1, -1, -1 },
+    { "12%%34%Zd", "12%34567", "567", 1, -1, -1 },
+    { "%%%%%Zd",   "%%123",    "123", 1, -1, -1 },
+
+    /* various subtle EOF cases */
+    { "x",       "",    "-999", EOF, 0, -555 },
+    { " x",      "",    "-999", EOF, 0, -555 },
+    { "xyz",     "",    "-999", EOF, 0, -555 },
+    { " ",       "",    "-999",   0, 0,    0 },
+    { " ",       " ",   "-999",   0, 1,    1 },
+    { "%*Zd%Zd", "",    "-999", EOF, 0, -555 },
+    { "%*Zd%Zd", "123", "-999", EOF, 3, -555 },
+    { "x",       "x",   "-999",   0, 1,    1 },
+    { "xyz",     "x",   "-999", EOF, 1, -555 },
+    { "xyz",     "xy",  "-999", EOF, 2, -555 },
+    { "xyz",     "xyz", "-999",   0, 3,    3 },
+    { "%Zn",     "",    "0",      0, 0,    0 },
+    { " %Zn",    "",    "0",      0, 0,    0 },
+    { " x%Zn",   "",    "-999", EOF, 0, -555 },
+    { "xyz%Zn",  "",    "-999", EOF, 0, -555 },
+    { " x%Zn",   "",    "-999", EOF, 0, -555 },
+    { " %Zn x",  " ",   "-999", EOF, 1, -555 },
+
+    /* these seem to tickle a bug in glibc 2.2.4 */
+    { " x",      " ",   "-999", EOF, 1, -555, 1 },
+    { " xyz",    " ",   "-999", EOF, 1, -555, 1 },
+    { " x%Zn",   " ",   "-999", EOF, 1, -555, 1 },
+  };
+
+  int         i, j, ignore;
+  int         got_ret, want_ret, got_upto, want_upto;
+  mpz_t       got, want;
+  long        got_l, want_ftell;
+  int         error = 0;
+  fun_t       fun;
+  const char  *name;
+  char        fmt[128];
+
+  mpz_init (got);
+  mpz_init (want);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_set_str_or_abort (want, data[i].want, 0);
+
+      ASSERT_ALWAYS (strlen (data[i].fmt) + 2 < sizeof (fmt));
+      strcpy (fmt, data[i].fmt);
+      strcat (fmt, "%n");
+
+      ignore = fmt_allignore (fmt);
+
+      for (j = 0; j <= 3; j++)
+        {
+          want_ret = data[i].want_ret;
+
+          want_ftell = data[i].want_ftell;
+          if (want_ftell == -1)
+            want_ftell = strlen (data[i].input);
+
+          want_upto = data[i].want_upto;
+          if (want_upto == -1)
+            want_upto = strlen (data[i].input);
+
+          switch (j) {
+          case 0:
+            name = "gmp_sscanf";
+            fun = fun_gmp_sscanf;
+            break;
+          case 1:
+            name = "gmp_fscanf";
+            fun = fun_gmp_fscanf;
+            break;
+          case 2:
+#ifdef __GLIBC__
+            if (data[i].not_glibc)
+              continue;
+#endif
+            if (! libc_scanf_convert (fmt))
+              continue;
+            name = "standard sscanf";
+            fun = fun_sscanf;
+            break;
+          case 3:
+#ifdef __GLIBC__
+            if (data[i].not_glibc)
+              continue;
+#endif
+            if (! libc_scanf_convert (fmt))
+              continue;
+            name = "standard fscanf";
+            fun = fun_fscanf;
+            break;
+          default:
+            ASSERT_ALWAYS (0);
+            break;
+          }
+
+          got_upto = -555;
+          got_ftell = -1L;
+
+          switch (j) {
+          case 0:
+          case 1:
+            mpz_set_si (got, -999L);
+            if (ignore)
+              got_ret = (*fun) (data[i].input, fmt, &got_upto, NULL);
+            else
+              got_ret = (*fun) (data[i].input, fmt, got, &got_upto);
+            break;
+          case 2:
+          case 3:
+            got_l = -999L;
+            if (ignore)
+              got_ret = (*fun) (data[i].input, fmt, &got_upto, NULL);
+            else
+              got_ret = (*fun) (data[i].input, fmt, &got_l, &got_upto);
+            mpz_set_si (got, got_l);
+            break;
+          default:
+            ASSERT_ALWAYS (0);
+            break;
+          }
+
+          MPZ_CHECK_FORMAT (got);
+
+          if (got_ret != want_ret)
+            {
+              printf ("%s wrong return value\n", name);
+              error = 1;
+            }
+          if (want_ret == 1 && mpz_cmp (want, got) != 0)
+            {
+              printf ("%s wrong result\n", name);
+              error = 1;
+            }
+          if (got_upto != want_upto)
+            {
+              printf ("%s wrong upto\n", name);
+              error = 1;
+            }
+          if (got_ftell != -1 && want_ftell != -1 && got_ftell != want_ftell)
+            {
+              printf ("%s wrong ftell\n", name);
+              error = 1;
+            }
+          if (error)
+            {
+              printf    ("  fmt   \"%s\"\n", data[i].fmt);
+              printf    ("  input \"%s\"\n", data[i].input);
+              printf    ("  ignore %d\n", ignore);
+              printf    ("  ret   want=%d\n", want_ret);
+              printf    ("        got =%d\n", got_ret);
+              mpz_trace ("  value want", want);
+              mpz_trace ("        got ", got);
+              printf    ("  upto  want =%d\n", want_upto);
+              printf    ("        got  =%d\n", got_upto);
+              if (got_ftell != -1)
+                {
+                  printf    ("  ftell want =%ld\n", want_ftell);
+                  printf    ("        got  =%ld\n", got_ftell);
+                }
+              abort ();
+            }
+        }
+    }
+
+  mpz_clear (got);
+  mpz_clear (want);
+}
+
+void
+check_q (void)
+{
+  static const struct {
+    const char  *fmt;
+    const char  *input;
+    const char  *want;
+    int         ret;
+    long        ftell;
+
+  } data[] = {
+
+    { "%Qd",    "0",    "0", 1, -1 },
+    { "%Qd",    "1",    "1", 1, -1 },
+    { "%Qd",  "123",  "123", 1, -1 },
+    { "%Qd",   "+0",    "0", 1, -1 },
+    { "%Qd",   "+1",    "1", 1, -1 },
+    { "%Qd", "+123",  "123", 1, -1 },
+    { "%Qd",   "-0",    "0", 1, -1 },
+    { "%Qd",   "-1",   "-1", 1, -1 },
+    { "%Qd", "-123", "-123", 1, -1 },
+
+    { "%Qo",    "0",    "0", 1, -1 },
+    { "%Qo",  "173",  "123", 1, -1 },
+    { "%Qo",   "+0",    "0", 1, -1 },
+    { "%Qo", "+173",  "123", 1, -1 },
+    { "%Qo",   "-0",    "0", 1, -1 },
+    { "%Qo", "-173", "-123", 1, -1 },
+
+    { "%Qx",    "0",    "0", 1, -1 },
+    { "%Qx",   "7b",  "123", 1, -1 },
+    { "%Qx",   "7b",  "123", 1, -1 },
+    { "%Qx",   "+0",    "0", 1, -1 },
+    { "%Qx",  "+7b",  "123", 1, -1 },
+    { "%Qx",  "+7b",  "123", 1, -1 },
+    { "%Qx",   "-0",   "-0", 1, -1 },
+    { "%Qx",  "-7b", "-123", 1, -1 },
+    { "%Qx",  "-7b", "-123", 1, -1 },
+    { "%QX",    "0",    "0", 1, -1 },
+    { "%QX",   "7b",  "123", 1, -1 },
+    { "%QX",   "7b",  "123", 1, -1 },
+    { "%QX",   "+0",    "0", 1, -1 },
+    { "%QX",  "+7b",  "123", 1, -1 },
+    { "%QX",  "+7b",  "123", 1, -1 },
+    { "%QX",   "-0",   "-0", 1, -1 },
+    { "%QX",  "-7b", "-123", 1, -1 },
+    { "%QX",  "-7b", "-123", 1, -1 },
+    { "%Qx",    "0",    "0", 1, -1 },
+    { "%Qx",   "7B",  "123", 1, -1 },
+    { "%Qx",   "7B",  "123", 1, -1 },
+    { "%Qx",   "+0",    "0", 1, -1 },
+    { "%Qx",  "+7B",  "123", 1, -1 },
+    { "%Qx",  "+7B",  "123", 1, -1 },
+    { "%Qx",   "-0",   "-0", 1, -1 },
+    { "%Qx",  "-7B", "-123", 1, -1 },
+    { "%Qx",  "-7B", "-123", 1, -1 },
+    { "%QX",    "0",    "0", 1, -1 },
+    { "%QX",   "7B",  "123", 1, -1 },
+    { "%QX",   "7B",  "123", 1, -1 },
+    { "%QX",   "+0",    "0", 1, -1 },
+    { "%QX",  "+7B",  "123", 1, -1 },
+    { "%QX",  "+7B",  "123", 1, -1 },
+    { "%QX",   "-0",   "-0", 1, -1 },
+    { "%QX",  "-7B", "-123", 1, -1 },
+    { "%QX",  "-7B", "-123", 1, -1 },
+
+    { "%Qi",    "0",    "0", 1, -1 },
+    { "%Qi",    "1",    "1", 1, -1 },
+    { "%Qi",  "123",  "123", 1, -1 },
+    { "%Qi",   "+0",    "0", 1, -1 },
+    { "%Qi",   "+1",    "1", 1, -1 },
+    { "%Qi", "+123",  "123", 1, -1 },
+    { "%Qi",   "-0",    "0", 1, -1 },
+    { "%Qi",   "-1",   "-1", 1, -1 },
+    { "%Qi", "-123", "-123", 1, -1 },
+
+    { "%Qi",    "00",    "0", 1, -1 },
+    { "%Qi",  "0173",  "123", 1, -1 },
+    { "%Qi",   "+00",    "0", 1, -1 },
+    { "%Qi", "+0173",  "123", 1, -1 },
+    { "%Qi",   "-00",    "0", 1, -1 },
+    { "%Qi", "-0173", "-123", 1, -1 },
+
+    { "%Qi",    "0x0",    "0", 1, -1 },
+    { "%Qi",   "0x7b",  "123", 1, -1 },
+    { "%Qi",   "0x7b",  "123", 1, -1 },
+    { "%Qi",   "+0x0",    "0", 1, -1 },
+    { "%Qi",  "+0x7b",  "123", 1, -1 },
+    { "%Qi",  "+0x7b",  "123", 1, -1 },
+    { "%Qi",   "-0x0",   "-0", 1, -1 },
+    { "%Qi",  "-0x7b", "-123", 1, -1 },
+    { "%Qi",  "-0x7b", "-123", 1, -1 },
+    { "%Qi",    "0X0",    "0", 1, -1 },
+    { "%Qi",   "0X7b",  "123", 1, -1 },
+    { "%Qi",   "0X7b",  "123", 1, -1 },
+    { "%Qi",   "+0X0",    "0", 1, -1 },
+    { "%Qi",  "+0X7b",  "123", 1, -1 },
+    { "%Qi",  "+0X7b",  "123", 1, -1 },
+    { "%Qi",   "-0X0",   "-0", 1, -1 },
+    { "%Qi",  "-0X7b", "-123", 1, -1 },
+    { "%Qi",  "-0X7b", "-123", 1, -1 },
+    { "%Qi",    "0x0",    "0", 1, -1 },
+    { "%Qi",   "0x7B",  "123", 1, -1 },
+    { "%Qi",   "0x7B",  "123", 1, -1 },
+    { "%Qi",   "+0x0",    "0", 1, -1 },
+    { "%Qi",  "+0x7B",  "123", 1, -1 },
+    { "%Qi",  "+0x7B",  "123", 1, -1 },
+    { "%Qi",   "-0x0",   "-0", 1, -1 },
+    { "%Qi",  "-0x7B", "-123", 1, -1 },
+    { "%Qi",  "-0x7B", "-123", 1, -1 },
+    { "%Qi",    "0X0",    "0", 1, -1 },
+    { "%Qi",   "0X7B",  "123", 1, -1 },
+    { "%Qi",   "0X7B",  "123", 1, -1 },
+    { "%Qi",   "+0X0",    "0", 1, -1 },
+    { "%Qi",  "+0X7B",  "123", 1, -1 },
+    { "%Qi",  "+0X7B",  "123", 1, -1 },
+    { "%Qi",   "-0X0",   "-0", 1, -1 },
+    { "%Qi",  "-0X7B", "-123", 1, -1 },
+    { "%Qi",  "-0X7B", "-123", 1, -1 },
+
+    { "%Qd",    " 0",    "0", 1, -1 },
+    { "%Qd",   "  0",    "0", 1, -1 },
+    { "%Qd",  "   0",    "0", 1, -1 },
+    { "%Qd",   "\t0",    "0", 1, -1 },
+    { "%Qd", "\t\t0",    "0", 1, -1 },
+
+    { "%Qd",  "3/2",   "3/2", 1, -1 },
+    { "%Qd", "+3/2",   "3/2", 1, -1 },
+    { "%Qd", "-3/2",  "-3/2", 1, -1 },
+
+    { "%Qx",  "f/10", "15/16", 1, -1 },
+    { "%Qx",  "F/10", "15/16", 1, -1 },
+    { "%QX",  "f/10", "15/16", 1, -1 },
+    { "%QX",  "F/10", "15/16", 1, -1 },
+
+    { "%Qo",  "20/21",  "16/17", 1, -1 },
+    { "%Qo", "-20/21", "-16/17", 1, -1 },
+
+    { "%Qi",    "10/11",  "10/11", 1, -1 },
+    { "%Qi",   "+10/11",  "10/11", 1, -1 },
+    { "%Qi",   "-10/11", "-10/11", 1, -1 },
+    { "%Qi",   "010/11",   "8/11", 1, -1 },
+    { "%Qi",  "+010/11",   "8/11", 1, -1 },
+    { "%Qi",  "-010/11",  "-8/11", 1, -1 },
+    { "%Qi",  "0x10/11",  "16/11", 1, -1 },
+    { "%Qi", "+0x10/11",  "16/11", 1, -1 },
+    { "%Qi", "-0x10/11", "-16/11", 1, -1 },
+
+    { "%Qi",    "10/011",  "10/9", 1, -1 },
+    { "%Qi",   "+10/011",  "10/9", 1, -1 },
+    { "%Qi",   "-10/011", "-10/9", 1, -1 },
+    { "%Qi",   "010/011",   "8/9", 1, -1 },
+    { "%Qi",  "+010/011",   "8/9", 1, -1 },
+    { "%Qi",  "-010/011",  "-8/9", 1, -1 },
+    { "%Qi",  "0x10/011",  "16/9", 1, -1 },
+    { "%Qi", "+0x10/011",  "16/9", 1, -1 },
+    { "%Qi", "-0x10/011", "-16/9", 1, -1 },
+
+    { "%Qi",    "10/0x11",  "10/17", 1, -1 },
+    { "%Qi",   "+10/0x11",  "10/17", 1, -1 },
+    { "%Qi",   "-10/0x11", "-10/17", 1, -1 },
+    { "%Qi",   "010/0x11",   "8/17", 1, -1 },
+    { "%Qi",  "+010/0x11",   "8/17", 1, -1 },
+    { "%Qi",  "-010/0x11",  "-8/17", 1, -1 },
+    { "%Qi",  "0x10/0x11",  "16/17", 1, -1 },
+    { "%Qi", "+0x10/0x11",  "16/17", 1, -1 },
+    { "%Qi", "-0x10/0x11", "-16/17", 1, -1 },
+
+    { "hello%Qd",      "hello0",         "0", 1, -1 },
+    { "hello%Qd",      "hello 0",        "0", 1, -1 },
+    { "hello%Qd",      "hello \t0",      "0", 1, -1 },
+    { "hello%Qdworld", "hello 0world",   "0", 1, -1 },
+    { "hello%Qd",      "hello3/2",     "3/2", 1, -1 },
+
+    { "hello%*Qd",      "hello0",        "-999/121", 0, -1 },
+    { "hello%*Qd",      "hello 0",       "-999/121", 0, -1 },
+    { "hello%*Qd",      "hello \t0",     "-999/121", 0, -1 },
+    { "hello%*Qdworld", "hello 0world",  "-999/121", 0, -1 },
+    { "hello%*Qdworld", "hello3/2world", "-999/121", 0, -1 },
+
+    { "%Qd",    "",     "-999/121", -1, -1 },
+    { "%Qd",   " ",     "-999/121", -1, -1 },
+    { " %Qd",   "",     "-999/121", -1, -1 },
+    { "xyz%Qd", "",     "-999/121", -1, -1 },
+
+    { "%*Qd",    "",     "-999/121", -1, -1 },
+    { " %*Qd",   "",     "-999/121", -1, -1 },
+    { "xyz%*Qd", "",     "-999/121", -1, -1 },
+
+    /* match something, but invalid */
+    { "%Qd",    "-",     "-999/121",  0, 1 },
+    { "%Qd",    "+",     "-999/121",  0, 1 },
+    { "%Qd",    "/-",    "-999/121",  0, 1 },
+    { "%Qd",    "/+",    "-999/121",  0, 1 },
+    { "%Qd",    "-/",    "-999/121",  0, 1 },
+    { "%Qd",    "+/",    "-999/121",  0, 1 },
+    { "%Qd",    "-/-",   "-999/121",  0, 1 },
+    { "%Qd",    "-/+",   "-999/121",  0, 1 },
+    { "%Qd",    "+/+",   "-999/121",  0, 1 },
+    { "%Qd",    "/123",  "-999/121",  0, 1 },
+    { "%Qd",    "-/123", "-999/121",  0, 1 },
+    { "%Qd",    "+/123", "-999/121",  0, 1 },
+    { "%Qd",    "123/",  "-999/121",  0, 1 },
+    { "%Qd",    "123/-", "-999/121",  0, 1 },
+    { "%Qd",    "123/+", "-999/121",  0, 1 },
+    { "xyz%Qd", "xyz-",  "-999/121",  0, 4 },
+    { "xyz%Qd", "xyz+",  "-999/121",  0, 4 },
+
+    { "%1Qi",  "12/57", "1",        1, 1 },
+    { "%2Qi",  "12/57", "12",       1, 2 },
+    { "%3Qi",  "12/57", "-999/121", 0, -1 },
+    { "%4Qi",  "12/57", "12/5",     1, 4 },
+    { "%5Qi",  "12/57", "12/57",    1, 5 },
+    { "%6Qi",  "12/57", "12/57",    1, 5 },
+    { "%7Qi",  "12/57", "12/57",    1, 5 },
+
+    { "%1Qi",  "012/057", "0",        1, 1 },
+    { "%2Qi",  "012/057", "01",       1, 2 },
+    { "%3Qi",  "012/057", "012",      1, 3 },
+    { "%4Qi",  "012/057", "-999/121", 0, -1 },
+    { "%5Qi",  "012/057", "012/0",    1, 5 },
+    { "%6Qi",  "012/057", "012/5",    1, 6 },
+    { "%7Qi",  "012/057", "012/057",  1, 7 },
+    { "%8Qi",  "012/057", "012/057",  1, 7 },
+    { "%9Qi",  "012/057", "012/057",  1, 7 },
+
+    { "%1Qi",  "0x12/0x57", "0",         1, 1 },
+    { "%2Qi",  "0x12/0x57", "-999",      0, 2 },
+    { "%3Qi",  "0x12/0x57", "0x1",       1, 3 },
+    { "%4Qi",  "0x12/0x57", "0x12",      1, 4 },
+    { "%5Qi",  "0x12/0x57", "-999/121",  0, 5 },
+    { "%6Qi",  "0x12/0x57", "0x12/0",    1, 6 },
+    { "%7Qi",  "0x12/0x57", "-999/121",  0, 7 },
+    { "%8Qi",  "0x12/0x57", "0x12/0x5",  1, 8 },
+    { "%9Qi",  "0x12/0x57", "0x12/0x57", 1, 9 },
+    { "%10Qi", "0x12/0x57", "0x12/0x57", 1, 9 },
+    { "%11Qi", "0x12/0x57", "0x12/0x57", 1, 9 },
+
+    { "%Qd",  "xyz", "0", 0, 0 },
+  };
+
+  int         i, j, ignore, got_ret, want_ret, got_upto, want_upto;
+  mpq_t       got, want;
+  long        got_l, want_ftell;
+  int         error = 0;
+  fun_t       fun;
+  const char  *name;
+  char        fmt[128];
+
+  mpq_init (got);
+  mpq_init (want);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpq_set_str_or_abort (want, data[i].want, 0);
+
+      ASSERT_ALWAYS (strlen (data[i].fmt) + 2 < sizeof (fmt));
+      strcpy (fmt, data[i].fmt);
+      strcat (fmt, "%n");
+
+      ignore = (strchr (fmt, '*') != NULL);
+
+      for (j = 0; j <= 3; j++)
+        {
+          want_ret = data[i].ret;
+
+          want_ftell = data[i].ftell;
+          if (want_ftell == -1)
+            want_ftell = strlen (data[i].input);
+          want_upto = want_ftell;
+
+          if (want_ret == -1 || (want_ret == 0 && ! ignore))
+            {
+              want_ftell = -1;
+              want_upto = -555;
+            }
+
+          switch (j) {
+          case 0:
+            name = "gmp_sscanf";
+            fun = fun_gmp_sscanf;
+            break;
+          case 1:
+            name = "gmp_fscanf";
+            fun = fun_gmp_fscanf;
+            break;
+          case 2:
+            if (strchr (data[i].input, '/') != NULL)
+              continue;
+            if (! libc_scanf_convert (fmt))
+              continue;
+            name = "standard sscanf";
+            fun = fun_sscanf;
+            break;
+          case 3:
+            if (strchr (data[i].input, '/') != NULL)
+              continue;
+            if (! libc_scanf_convert (fmt))
+              continue;
+            name = "standard fscanf";
+            fun = fun_fscanf;
+            break;
+          default:
+            ASSERT_ALWAYS (0);
+            break;
+          }
+
+          got_upto = -555;
+          got_ftell = -1;
+
+          switch (j) {
+          case 0:
+          case 1:
+            mpq_set_si (got, -999L, 121L);
+            if (ignore)
+              got_ret = (*fun) (data[i].input, fmt, &got_upto, NULL);
+            else
+              got_ret = (*fun) (data[i].input, fmt, got, &got_upto);
+            break;
+          case 2:
+          case 3:
+            got_l = -999L;
+            if (ignore)
+              got_ret = (*fun) (data[i].input, fmt, &got_upto, NULL);
+            else
+              got_ret = (*fun) (data[i].input, fmt, &got_l, &got_upto);
+            mpq_set_si (got, got_l, (got_l == -999L ? 121L : 1L));
+            break;
+          default:
+            ASSERT_ALWAYS (0);
+            break;
+          }
+
+          MPZ_CHECK_FORMAT (mpq_numref (got));
+          MPZ_CHECK_FORMAT (mpq_denref (got));
+
+          if (got_ret != want_ret)
+            {
+              printf ("%s wrong return value\n", name);
+              error = 1;
+            }
+          /* use direct mpz compares, since some of the test data is
+             non-canonical and can trip ASSERTs in mpq_equal */
+          if (want_ret == 1
+              && ! (mpz_cmp (mpq_numref(want), mpq_numref(got)) == 0
+                    && mpz_cmp (mpq_denref(want), mpq_denref(got)) == 0))
+            {
+              printf ("%s wrong result\n", name);
+              error = 1;
+            }
+          if (got_upto != want_upto)
+            {
+              printf ("%s wrong upto\n", name);
+              error = 1;
+            }
+          if (got_ftell != -1 && want_ftell != -1 && got_ftell != want_ftell)
+            {
+              printf ("%s wrong ftell\n", name);
+              error = 1;
+            }
+          if (error)
+            {
+              printf    ("  fmt   \"%s\"\n", data[i].fmt);
+              printf    ("  input \"%s\"\n", data[i].input);
+              printf    ("  ret   want=%d\n", want_ret);
+              printf    ("        got =%d\n", got_ret);
+              mpq_trace ("  value want", want);
+              mpq_trace ("        got ", got);
+              printf    ("  upto  want=%d\n", want_upto);
+              printf    ("        got =%d\n", got_upto);
+              if (got_ftell != -1)
+                {
+                  printf    ("  ftell want =%ld\n", want_ftell);
+                  printf    ("        got  =%ld\n", got_ftell);
+                }
+              abort ();
+            }
+        }
+    }
+
+  mpq_clear (got);
+  mpq_clear (want);
+}
+
+void
+check_f (void)
+{
+  static const struct {
+    const char  *fmt;
+    const char  *input;
+    const char  *want;
+    int         ret;
+    long        ftell;    /* or -1 for length of input string */
+
+  } data[] = {
+
+    { "%Ff",    "0",    "0", 1, -1 },
+    { "%Fe",    "0",    "0", 1, -1 },
+    { "%FE",    "0",    "0", 1, -1 },
+    { "%Fg",    "0",    "0", 1, -1 },
+    { "%FG",    "0",    "0", 1, -1 },
+
+    { "%Ff",  "123",    "123", 1, -1 },
+    { "%Ff", "+123",    "123", 1, -1 },
+    { "%Ff", "-123",   "-123", 1, -1 },
+    { "%Ff",  "123.",   "123", 1, -1 },
+    { "%Ff", "+123.",   "123", 1, -1 },
+    { "%Ff", "-123.",  "-123", 1, -1 },
+    { "%Ff",  "123.0",  "123", 1, -1 },
+    { "%Ff", "+123.0",  "123", 1, -1 },
+    { "%Ff", "-123.0", "-123", 1, -1 },
+    { "%Ff",  "0123",   "123", 1, -1 },
+    { "%Ff", "-0123",  "-123", 1, -1 },
+
+    { "%Ff",  "123.456e3",   "123456", 1, -1 },
+    { "%Ff", "-123.456e3",  "-123456", 1, -1 },
+    { "%Ff",  "123.456e+3",  "123456", 1, -1 },
+    { "%Ff", "-123.456e+3", "-123456", 1, -1 },
+    { "%Ff",  "123000e-3",      "123", 1, -1 },
+    { "%Ff", "-123000e-3",     "-123", 1, -1 },
+    { "%Ff",  "123000.e-3",     "123", 1, -1 },
+    { "%Ff", "-123000.e-3",    "-123", 1, -1 },
+
+    { "%Ff",  "123.456E3",   "123456", 1, -1 },
+    { "%Ff", "-123.456E3",  "-123456", 1, -1 },
+    { "%Ff",  "123.456E+3",  "123456", 1, -1 },
+    { "%Ff", "-123.456E+3", "-123456", 1, -1 },
+    { "%Ff",  "123000E-3",      "123", 1, -1 },
+    { "%Ff", "-123000E-3",     "-123", 1, -1 },
+    { "%Ff",  "123000.E-3",     "123", 1, -1 },
+    { "%Ff", "-123000.E-3",    "-123", 1, -1 },
+
+    { "%Ff",  ".456e3",   "456", 1, -1 },
+    { "%Ff", "-.456e3",  "-456", 1, -1 },
+    { "%Ff",  ".456e+3",  "456", 1, -1 },
+    { "%Ff", "-.456e+3", "-456", 1, -1 },
+
+    { "%Ff",    " 0",    "0", 1, -1 },
+    { "%Ff",   "  0",    "0", 1, -1 },
+    { "%Ff",  "   0",    "0", 1, -1 },
+    { "%Ff",   "\t0",    "0", 1, -1 },
+    { "%Ff", "\t\t0",    "0", 1, -1 },
+
+    { "hello%Fg",      "hello0",       "0",   1, -1 },
+    { "hello%Fg",      "hello 0",      "0",   1, -1 },
+    { "hello%Fg",      "hello \t0",    "0",   1, -1 },
+    { "hello%Fgworld", "hello 0world", "0",   1, -1 },
+    { "hello%Fg",      "hello3.0",     "3.0", 1, -1 },
+
+    { "hello%*Fg",      "hello0",        "-999", 0, -1 },
+    { "hello%*Fg",      "hello 0",       "-999", 0, -1 },
+    { "hello%*Fg",      "hello \t0",     "-999", 0, -1 },
+    { "hello%*Fgworld", "hello 0world",  "-999", 0, -1 },
+    { "hello%*Fgworld", "hello3.0world", "-999", 0, -1 },
+
+    { "%Ff",     "",   "-999", -1, -1 },
+    { "%Ff",    " ",   "-999", -1, -1 },
+    { "%Ff",   "\t",   "-999", -1, -1 },
+    { "%Ff",  " \t",   "-999", -1, -1 },
+    { " %Ff",    "",   "-999", -1, -1 },
+    { "xyz%Ff",  "",   "-999", -1, -1 },
+
+    { "%*Ff",    "",   "-999", -1, -1 },
+    { " %*Ff",   "",   "-999", -1, -1 },
+    { "xyz%*Ff", "",   "-999", -1, -1 },
+
+    { "%Ff",    "xyz", "0", 0 },
+
+    /* various non-empty but invalid */
+    { "%Ff",    "-",      "-999",  0, 1 },
+    { "%Ff",    "+",      "-999",  0, 1 },
+    { "xyz%Ff", "xyz-",   "-999",  0, 4 },
+    { "xyz%Ff", "xyz+",   "-999",  0, 4 },
+    { "%Ff",    "-.",     "-999",  0, 2 },
+    { "%Ff",    "+.",     "-999",  0, 2 },
+    { "%Ff",    ".e",     "-999",  0, 1 },
+    { "%Ff",   "-.e",     "-999",  0, 2 },
+    { "%Ff",   "+.e",     "-999",  0, 2 },
+    { "%Ff",    ".E",     "-999",  0, 1 },
+    { "%Ff",   "-.E",     "-999",  0, 2 },
+    { "%Ff",   "+.E",     "-999",  0, 2 },
+    { "%Ff",    ".e123",  "-999",  0, 1 },
+    { "%Ff",   "-.e123",  "-999",  0, 2 },
+    { "%Ff",   "+.e123",  "-999",  0, 2 },
+    { "%Ff",    "123e",   "-999",  0, 4 },
+    { "%Ff",   "-123e",   "-999",  0, 5 },
+    { "%Ff",    "123e-",  "-999",  0, 5 },
+    { "%Ff",   "-123e-",  "-999",  0, 6 },
+    { "%Ff",    "123e+",  "-999",  0, 5 },
+    { "%Ff",   "-123e+",  "-999",  0, 6 },
+    { "%Ff",   "123e-Z",  "-999",  0, 5 },
+
+    /* hex floats */
+    { "%Ff", "0x123p0",       "291",  1, -1 },
+    { "%Ff", "0x123P0",       "291",  1, -1 },
+    { "%Ff", "0X123p0",       "291",  1, -1 },
+    { "%Ff", "0X123P0",       "291",  1, -1 },
+    { "%Ff", "-0x123p0",     "-291",  1, -1 },
+    { "%Ff", "+0x123p0",      "291",  1, -1 },
+    { "%Ff", "0x123.p0",      "291",  1, -1 },
+    { "%Ff", "0x12.3p4",      "291",  1, -1 },
+    { "%Ff", "-0x12.3p4",    "-291",  1, -1 },
+    { "%Ff", "+0x12.3p4",     "291",  1, -1 },
+    { "%Ff", "0x1230p-4",     "291",  1, -1 },
+    { "%Ff", "-0x1230p-4",   "-291",  1, -1 },
+    { "%Ff", "+0x1230p-4",    "291",  1, -1 },
+    { "%Ff", "+0x.1230p12",   "291",  1, -1 },
+    { "%Ff", "+0x123000p-12", "291",  1, -1 },
+    { "%Ff", "0x123 p12",     "291",  1, 5 },
+    { "%Ff", "0x9 9",           "9",  1, 3 },
+    { "%Ff", "0x01",            "1",  1, 4 },
+    { "%Ff", "0x23",           "35",  1, 4 },
+    { "%Ff", "0x45",           "69",  1, 4 },
+    { "%Ff", "0x67",          "103",  1, 4 },
+    { "%Ff", "0x89",          "137",  1, 4 },
+    { "%Ff", "0xAB",          "171",  1, 4 },
+    { "%Ff", "0xCD",          "205",  1, 4 },
+    { "%Ff", "0xEF",          "239",  1, 4 },
+    { "%Ff", "0xab",          "171",  1, 4 },
+    { "%Ff", "0xcd",          "205",  1, 4 },
+    { "%Ff", "0xef",          "239",  1, 4 },
+    { "%Ff", "0x100p0A",      "256",  1, 7 },
+    { "%Ff", "0x1p9",         "512",  1, -1 },
+
+    /* invalid hex floats */
+    { "%Ff", "0x",     "-999",  0, 2 },
+    { "%Ff", "-0x",    "-999",  0, 3 },
+    { "%Ff", "+0x",    "-999",  0, 3 },
+    { "%Ff", "0x-",    "-999",  0, 2 },
+    { "%Ff", "0x+",    "-999",  0, 2 },
+    { "%Ff", "0x.",    "-999",  0, 3 },
+    { "%Ff", "-0x.",   "-999",  0, 4 },
+    { "%Ff", "+0x.",   "-999",  0, 4 },
+    { "%Ff", "0x.p",   "-999",  0, 3 },
+    { "%Ff", "-0x.p",  "-999",  0, 4 },
+    { "%Ff", "+0x.p",  "-999",  0, 4 },
+    { "%Ff", "0x.P",   "-999",  0, 3 },
+    { "%Ff", "-0x.P",  "-999",  0, 4 },
+    { "%Ff", "+0x.P",  "-999",  0, 4 },
+    { "%Ff", ".p123",  "-999",  0, 1 },
+    { "%Ff", "-.p123", "-999",  0, 2 },
+    { "%Ff", "+.p123", "-999",  0, 2 },
+    { "%Ff", "0x1p",   "-999",  0, 4 },
+    { "%Ff", "0x1p-",  "-999",  0, 5 },
+    { "%Ff", "0x1p+",  "-999",  0, 5 },
+    { "%Ff", "0x123p 12", "291",  0, 6 },
+    { "%Ff", "0x 123p12", "291",  0, 2 },
+
+  };
+
+  int         i, j, ignore, got_ret, want_ret, got_upto, want_upto;
+  mpf_t       got, want;
+  double      got_d;
+  long        want_ftell;
+  int         error = 0;
+  fun_t       fun;
+  const char  *name;
+  char        fmt[128];
+
+  mpf_init (got);
+  mpf_init (want);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpf_set_str_or_abort (want, data[i].want, 10);
+
+      ASSERT_ALWAYS (strlen (data[i].fmt) + 2 < sizeof (fmt));
+      strcpy (fmt, data[i].fmt);
+      strcat (fmt, "%n");
+
+      ignore = (strchr (fmt, '*') != NULL);
+
+      for (j = 0; j <= 3; j++)
+        {
+          want_ret = data[i].ret;
+
+          want_ftell = data[i].ftell;
+          if (want_ftell == -1)
+            want_ftell = strlen (data[i].input);
+          want_upto = want_ftell;
+
+          if (want_ret == -1 || (want_ret == 0 && ! ignore))
+            want_upto = -555;
+
+          switch (j) {
+          case 0:
+            name = "gmp_sscanf";
+            fun = fun_gmp_sscanf;
+            break;
+          case 1:
+            name = "gmp_fscanf";
+            fun = fun_gmp_fscanf;
+            break;
+          case 2:
+            if (! libc_scanf_convert (fmt))
+              continue;
+            name = "standard sscanf";
+            fun = fun_sscanf;
+            break;
+          case 3:
+            if (! libc_scanf_convert (fmt))
+              continue;
+            name = "standard fscanf";
+            fun = fun_fscanf;
+            break;
+          default:
+            ASSERT_ALWAYS (0);
+            break;
+          }
+
+          got_upto = -555;
+          got_ftell = -1;
+
+          switch (j) {
+          case 0:
+          case 1:
+            mpf_set_si (got, -999L);
+            if (ignore)
+              got_ret = (*fun) (data[i].input, fmt, &got_upto, NULL);
+            else
+              got_ret = (*fun) (data[i].input, fmt, got, &got_upto);
+            break;
+          case 2:
+          case 3:
+            got_d = -999L;
+            if (ignore)
+              got_ret = (*fun) (data[i].input, fmt, &got_upto, NULL);
+            else
+              got_ret = (*fun) (data[i].input, fmt, &got_d, &got_upto);
+            mpf_set_d (got, got_d);
+            break;
+          default:
+            ASSERT_ALWAYS (0);
+            break;
+          }
+
+          MPF_CHECK_FORMAT (got);
+
+          if (got_ret != want_ret)
+            {
+              printf ("%s wrong return value\n", name);
+              error = 1;
+            }
+          if (want_ret == 1 && mpf_cmp (want, got) != 0)
+            {
+              printf ("%s wrong result\n", name);
+              error = 1;
+            }
+          if (got_upto != want_upto)
+            {
+              printf ("%s wrong upto\n", name);
+              error = 1;
+            }
+          if (got_ftell != -1 && want_ftell != -1 && got_ftell != want_ftell)
+            {
+              printf ("%s wrong ftell\n", name);
+              error = 1;
+            }
+          if (error)
+            {
+              printf    ("  fmt   \"%s\"\n", data[i].fmt);
+              printf    ("  input \"%s\"\n", data[i].input);
+              printf    ("  ret   want=%d\n", want_ret);
+              printf    ("        got =%d\n", got_ret);
+              mpf_trace ("  value want", want);
+              mpf_trace ("        got ", got);
+              printf    ("  upto  want=%d\n", want_upto);
+              printf    ("        got =%d\n", got_upto);
+              if (got_ftell != -1)
+                {
+                  printf    ("  ftell want =%ld\n", want_ftell);
+                  printf    ("        got  =%ld\n", got_ftell);
+                }
+              abort ();
+            }
+        }
+    }
+
+  mpf_clear (got);
+  mpf_clear (want);
+}
+
+
+void
+check_n (void)
+{
+  int    ret;
+
+  /* %n suppressed */
+  {
+    int n = 123;
+    gmp_sscanf ("   ", " %*n", &n);
+    ASSERT_ALWAYS (n == 123);
+  }
+  {
+    int n = 123;
+    fromstring_gmp_fscanf ("   ", " %*n", &n);
+    ASSERT_ALWAYS (n == 123);
+  }
+
+
+#define CHECK_N(type, string)                           \
+  do {                                                  \
+    type  x[2];                                         \
+    char  fmt[128];                                     \
+    int   ret;                                          \
+                                                        \
+    x[0] = ~ (type) 0;                                  \
+    x[1] = ~ (type) 0;                                  \
+    sprintf (fmt, "abc%%%sn", string);                  \
+    ret = gmp_sscanf ("abc", fmt, &x[0]);               \
+                                                        \
+    ASSERT_ALWAYS (ret == 0);                           \
+                                                        \
+    /* should write whole of x[0] and none of x[1] */   \
+    ASSERT_ALWAYS (x[0] == 3);                          \
+    ASSERT_ALWAYS (x[1] == (type) ~ (type) 0);		\
+                                                        \
+  } while (0)
+
+  CHECK_N (char,      "hh");
+  CHECK_N (long,      "l");
+#if HAVE_LONG_LONG
+  CHECK_N (long long, "L");
+#endif
+#if HAVE_INTMAX_T
+  CHECK_N (intmax_t,  "j");
+#endif
+#if HAVE_PTRDIFF_T
+  CHECK_N (ptrdiff_t, "t");
+#endif
+  CHECK_N (short,     "h");
+  CHECK_N (size_t,    "z");
+
+  /* %Zn */
+  {
+    mpz_t  x[2];
+    mpz_init_set_si (x[0], -987L);
+    mpz_init_set_si (x[1],  654L);
+    ret = gmp_sscanf ("xyz   ", "xyz%Zn", x[0]);
+    MPZ_CHECK_FORMAT (x[0]);
+    MPZ_CHECK_FORMAT (x[1]);
+    ASSERT_ALWAYS (ret == 0);
+    ASSERT_ALWAYS (mpz_cmp_ui (x[0], 3L) == 0);
+    ASSERT_ALWAYS (mpz_cmp_ui (x[1], 654L) == 0);
+    mpz_clear (x[0]);
+    mpz_clear (x[1]);
+  }
+  {
+    mpz_t  x;
+    mpz_init (x);
+    ret = fromstring_gmp_fscanf ("xyz   ", "xyz%Zn", x);
+    ASSERT_ALWAYS (ret == 0);
+    ASSERT_ALWAYS (mpz_cmp_ui (x, 3L) == 0);
+    mpz_clear (x);
+  }
+
+  /* %Qn */
+  {
+    mpq_t  x[2];
+    mpq_init (x[0]);
+    mpq_init (x[1]);
+    mpq_set_ui (x[0], 987L, 654L);
+    mpq_set_ui (x[1], 4115L, 226L);
+    ret = gmp_sscanf ("xyz   ", "xyz%Qn", x[0]);
+    MPQ_CHECK_FORMAT (x[0]);
+    MPQ_CHECK_FORMAT (x[1]);
+    ASSERT_ALWAYS (ret == 0);
+    ASSERT_ALWAYS (mpq_cmp_ui (x[0], 3L, 1L) == 0);
+    ASSERT_ALWAYS (mpq_cmp_ui (x[1], 4115L, 226L) == 0);
+    mpq_clear (x[0]);
+    mpq_clear (x[1]);
+  }
+  {
+    mpq_t  x;
+    mpq_init (x);
+    ret = fromstring_gmp_fscanf ("xyz   ", "xyz%Qn", x);
+    ASSERT_ALWAYS (ret == 0);
+    ASSERT_ALWAYS (mpq_cmp_ui (x, 3L, 1L) == 0);
+    mpq_clear (x);
+  }
+
+  /* %Fn */
+  {
+    mpf_t  x[2];
+    mpf_init (x[0]);
+    mpf_init (x[1]);
+    mpf_set_ui (x[0], 987L);
+    mpf_set_ui (x[1], 654L);
+    ret = gmp_sscanf ("xyz   ", "xyz%Fn", x[0]);
+    MPF_CHECK_FORMAT (x[0]);
+    MPF_CHECK_FORMAT (x[1]);
+    ASSERT_ALWAYS (ret == 0);
+    ASSERT_ALWAYS (mpf_cmp_ui (x[0], 3L) == 0);
+    ASSERT_ALWAYS (mpf_cmp_ui (x[1], 654L) == 0);
+    mpf_clear (x[0]);
+    mpf_clear (x[1]);
+  }
+  {
+    mpf_t  x;
+    mpf_init (x);
+    ret = fromstring_gmp_fscanf ("xyz   ", "xyz%Fn", x);
+    ASSERT_ALWAYS (ret == 0);
+    ASSERT_ALWAYS (mpf_cmp_ui (x, 3L) == 0);
+    mpf_clear (x);
+  }
+}
+
+
+void
+check_misc (void)
+{
+  int  ret, cmp;
+  {
+    int  a=9, b=8, c=7, n=66;
+    mpz_t  z;
+    mpz_init (z);
+    ret = gmp_sscanf ("1 2 3 4", "%d %d %d %Zd%n",
+                      &a, &b, &c, z, &n);
+    ASSERT_ALWAYS (ret == 4);
+    ASSERT_ALWAYS (a == 1);
+    ASSERT_ALWAYS (b == 2);
+    ASSERT_ALWAYS (c == 3);
+    ASSERT_ALWAYS (n == 7);
+    ASSERT_ALWAYS (mpz_cmp_ui (z, 4L) == 0);
+    mpz_clear (z);
+  }
+  {
+    int  a=9, b=8, c=7, n=66;
+    mpz_t  z;
+    mpz_init (z);
+    ret = fromstring_gmp_fscanf ("1 2 3 4", "%d %d %d %Zd%n",
+                                 &a, &b, &c, z, &n);
+    ASSERT_ALWAYS (ret == 4);
+    ASSERT_ALWAYS (a == 1);
+    ASSERT_ALWAYS (b == 2);
+    ASSERT_ALWAYS (c == 3);
+    ASSERT_ALWAYS (mpz_cmp_ui (z, 4L) == 0);
+    ASSERT_ALWAYS (n == 7);
+    ASSERT_ALWAYS (got_ftell == 7);
+    mpz_clear (z);
+  }
+
+  {
+    int  a=9, n=8;
+    mpz_t  z;
+    mpz_init (z);
+    ret = gmp_sscanf ("1 2 3 4", "%d %*d %*d %Zd%n", &a, z, &n);
+    ASSERT_ALWAYS (ret == 2);
+    ASSERT_ALWAYS (a == 1);
+    ASSERT_ALWAYS (mpz_cmp_ui (z, 4L) == 0);
+    ASSERT_ALWAYS (n == 7);
+    mpz_clear (z);
+  }
+  {
+    int  a=9, n=8;
+    mpz_t  z;
+    mpz_init (z);
+    ret = fromstring_gmp_fscanf ("1 2 3 4", "%d %*d %*d %Zd%n",
+                                 &a, z, &n);
+    ASSERT_ALWAYS (ret == 2);
+    ASSERT_ALWAYS (a == 1);
+    ASSERT_ALWAYS (mpz_cmp_ui (z, 4L) == 0);
+    ASSERT_ALWAYS (n == 7);
+    ASSERT_ALWAYS (got_ftell == 7);
+    mpz_clear (z);
+  }
+
+  /* EOF for no matching */
+  {
+    char buf[128];
+    ret = gmp_sscanf ("   ", "%s", buf);
+    ASSERT_ALWAYS (ret == EOF);
+    ret = fromstring_gmp_fscanf ("   ", "%s", buf);
+    ASSERT_ALWAYS (ret == EOF);
+    if (option_libc_scanf)
+      {
+        ret = sscanf ("   ", "%s", buf);
+        ASSERT_ALWAYS (ret == EOF);
+        ret = fun_fscanf ("   ", "%s", buf, NULL);
+        ASSERT_ALWAYS (ret == EOF);
+      }
+  }
+
+  /* suppressed field, then eof */
+  {
+    int  x;
+    if (test_sscanf_eof_ok ())
+      {
+        ret = gmp_sscanf ("123", "%*d%d", &x);
+        ASSERT_ALWAYS (ret == EOF);
+      }
+    ret = fromstring_gmp_fscanf ("123", "%*d%d", &x);
+    ASSERT_ALWAYS (ret == EOF);
+    if (option_libc_scanf)
+      {
+        ret = sscanf ("123", "%*d%d", &x);
+        ASSERT_ALWAYS (ret == EOF);
+        ret = fun_fscanf ("123", "%*d%d", &x, NULL);
+        ASSERT_ALWAYS (ret == EOF);
+      }
+  }
+  {
+    mpz_t  x;
+    mpz_init (x);
+    ret = gmp_sscanf ("123", "%*Zd%Zd", x);
+    ASSERT_ALWAYS (ret == EOF);
+    ret = fromstring_gmp_fscanf ("123", "%*Zd%Zd", x);
+    ASSERT_ALWAYS (ret == EOF);
+    mpz_clear (x);
+  }
+
+  /* %[...], glibc only */
+#ifdef __GLIBC__
+  {
+    char  buf[128];
+    int   n = -1;
+    buf[0] = '\0';
+    ret = gmp_sscanf ("abcdefgh", "%[a-d]ef%n", buf, &n);
+    ASSERT_ALWAYS (ret == 1);
+    cmp = strcmp (buf, "abcd");
+    ASSERT_ALWAYS (cmp == 0);
+    ASSERT_ALWAYS (n == 6);
+  }
+  {
+    char  buf[128];
+    int   n = -1;
+    buf[0] = '\0';
+    ret = gmp_sscanf ("xyza", "%[^a]a%n", buf, &n);
+    ASSERT_ALWAYS (ret == 1);
+    cmp = strcmp (buf, "xyz");
+    ASSERT_ALWAYS (cmp == 0);
+    ASSERT_ALWAYS (n == 4);
+  }
+  {
+    char  buf[128];
+    int   n = -1;
+    buf[0] = '\0';
+    ret = gmp_sscanf ("ab]ab]", "%[]ab]%n", buf, &n);
+    ASSERT_ALWAYS (ret == 1);
+    cmp = strcmp (buf, "ab]ab]");
+    ASSERT_ALWAYS (cmp == 0);
+    ASSERT_ALWAYS (n == 6);
+  }
+  {
+    char  buf[128];
+    int   n = -1;
+    buf[0] = '\0';
+    ret = gmp_sscanf ("xyzb", "%[^]ab]b%n", buf, &n);
+    ASSERT_ALWAYS (ret == 1);
+    cmp = strcmp (buf, "xyz");
+    ASSERT_ALWAYS (cmp == 0);
+    ASSERT_ALWAYS (n == 4);
+  }
+#endif
+
+  /* %zd etc won't be accepted by sscanf on old systems, and running
+     something to see if they work might be bad, so only try it on glibc,
+     and only on a new enough version (glibc 2.0 doesn't have %zd) */
+#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 0)
+  {
+    mpz_t   z;
+    size_t  s = -1;
+    mpz_init (z);
+    ret = gmp_sscanf ("456 789", "%zd %Zd", &s, z);
+    ASSERT_ALWAYS (ret == 2);
+    ASSERT_ALWAYS (s == 456);
+    ASSERT_ALWAYS (mpz_cmp_ui (z, 789L) == 0);
+    mpz_clear (z);
+  }
+  {
+    mpz_t      z;
+    ptrdiff_t  d = -1;
+    mpz_init (z);
+    ret = gmp_sscanf ("456 789", "%td %Zd", &d, z);
+    ASSERT_ALWAYS (ret == 2);
+    ASSERT_ALWAYS (d == 456);
+    ASSERT_ALWAYS (mpz_cmp_ui (z, 789L) == 0);
+    mpz_clear (z);
+  }
+  {
+    mpz_t      z;
+    long long  ll = -1;
+    mpz_init (z);
+    ret = gmp_sscanf ("456 789", "%Ld %Zd", &ll, z);
+    ASSERT_ALWAYS (ret == 2);
+    ASSERT_ALWAYS (ll == 456);
+    ASSERT_ALWAYS (mpz_cmp_ui (z, 789L) == 0);
+    mpz_clear (z);
+  }
+#endif
+}
+
+int
+main (int argc, char *argv[])
+{
+  if (argc > 1 && strcmp (argv[1], "-s") == 0)
+    option_libc_scanf = 1;
+
+  tests_start ();
+
+  mp_trace_base = 16;
+
+  check_z ();
+  check_q ();
+  check_f ();
+  check_n ();
+  check_misc ();
+
+  unlink (TEMPFILE);
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpf/Makefile.am b/third_party/gmp/tests/mpf/Makefile.am
new file mode 100644
index 0000000..da0e92b
--- /dev/null
+++ b/third_party/gmp/tests/mpf/Makefile.am
@@ -0,0 +1,32 @@
+## Process this file with automake to generate Makefile.in
+
+# Copyright 1996, 1999-2004, 2015 Free Software Foundation, Inc.
+#
+# This file is part of the GNU MP Library test suite.
+#
+# The GNU MP Library test suite is free software; you can redistribute it
+# and/or modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 3 of the License,
+# or (at your option) any later version.
+#
+# The GNU MP Library test suite is distributed in the hope that it will be
+# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.
+
+
+AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/tests
+AM_LDFLAGS = -no-install
+LDADD = $(top_builddir)/tests/libtests.la $(top_builddir)/libgmp.la
+
+check_PROGRAMS = t-dm2exp t-conv t-add t-sub t-sqrt t-sqrt_ui t-muldiv reuse \
+  t-cmp_d t-cmp_si t-div t-fits t-get_d t-get_d_2exp \
+  t-get_si t-get_ui t-gsprec t-inp_str t-int_p t-mul_ui \
+  t-set t-set_q t-set_si t-set_ui t-trunc t-ui_div t-eq t-pow_ui
+TESTS = $(check_PROGRAMS)
+
+$(top_builddir)/tests/libtests.la:
+	cd $(top_builddir)/tests; $(MAKE) $(AM_MAKEFLAGS) libtests.la
diff --git a/third_party/gmp/tests/mpf/Makefile.in b/third_party/gmp/tests/mpf/Makefile.in
new file mode 100644
index 0000000..de2aeab
--- /dev/null
+++ b/third_party/gmp/tests/mpf/Makefile.in
@@ -0,0 +1,1452 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Copyright 1996, 1999-2004, 2015 Free Software Foundation, Inc.
+#
+# This file is part of the GNU MP Library test suite.
+#
+# The GNU MP Library test suite is free software; you can redistribute it
+# and/or modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 3 of the License,
+# or (at your option) any later version.
+#
+# The GNU MP Library test suite is distributed in the hope that it will be
+# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+check_PROGRAMS = t-dm2exp$(EXEEXT) t-conv$(EXEEXT) t-add$(EXEEXT) \
+	t-sub$(EXEEXT) t-sqrt$(EXEEXT) t-sqrt_ui$(EXEEXT) \
+	t-muldiv$(EXEEXT) reuse$(EXEEXT) t-cmp_d$(EXEEXT) \
+	t-cmp_si$(EXEEXT) t-div$(EXEEXT) t-fits$(EXEEXT) \
+	t-get_d$(EXEEXT) t-get_d_2exp$(EXEEXT) t-get_si$(EXEEXT) \
+	t-get_ui$(EXEEXT) t-gsprec$(EXEEXT) t-inp_str$(EXEEXT) \
+	t-int_p$(EXEEXT) t-mul_ui$(EXEEXT) t-set$(EXEEXT) \
+	t-set_q$(EXEEXT) t-set_si$(EXEEXT) t-set_ui$(EXEEXT) \
+	t-trunc$(EXEEXT) t-ui_div$(EXEEXT) t-eq$(EXEEXT) \
+	t-pow_ui$(EXEEXT)
+subdir = tests/mpf
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+reuse_SOURCES = reuse.c
+reuse_OBJECTS = reuse.$(OBJEXT)
+reuse_LDADD = $(LDADD)
+reuse_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+t_add_SOURCES = t-add.c
+t_add_OBJECTS = t-add.$(OBJEXT)
+t_add_LDADD = $(LDADD)
+t_add_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_cmp_d_SOURCES = t-cmp_d.c
+t_cmp_d_OBJECTS = t-cmp_d.$(OBJEXT)
+t_cmp_d_LDADD = $(LDADD)
+t_cmp_d_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_cmp_si_SOURCES = t-cmp_si.c
+t_cmp_si_OBJECTS = t-cmp_si.$(OBJEXT)
+t_cmp_si_LDADD = $(LDADD)
+t_cmp_si_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_conv_SOURCES = t-conv.c
+t_conv_OBJECTS = t-conv.$(OBJEXT)
+t_conv_LDADD = $(LDADD)
+t_conv_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_div_SOURCES = t-div.c
+t_div_OBJECTS = t-div.$(OBJEXT)
+t_div_LDADD = $(LDADD)
+t_div_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_dm2exp_SOURCES = t-dm2exp.c
+t_dm2exp_OBJECTS = t-dm2exp.$(OBJEXT)
+t_dm2exp_LDADD = $(LDADD)
+t_dm2exp_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_eq_SOURCES = t-eq.c
+t_eq_OBJECTS = t-eq.$(OBJEXT)
+t_eq_LDADD = $(LDADD)
+t_eq_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_fits_SOURCES = t-fits.c
+t_fits_OBJECTS = t-fits.$(OBJEXT)
+t_fits_LDADD = $(LDADD)
+t_fits_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_get_d_SOURCES = t-get_d.c
+t_get_d_OBJECTS = t-get_d.$(OBJEXT)
+t_get_d_LDADD = $(LDADD)
+t_get_d_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_get_d_2exp_SOURCES = t-get_d_2exp.c
+t_get_d_2exp_OBJECTS = t-get_d_2exp.$(OBJEXT)
+t_get_d_2exp_LDADD = $(LDADD)
+t_get_d_2exp_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_get_si_SOURCES = t-get_si.c
+t_get_si_OBJECTS = t-get_si.$(OBJEXT)
+t_get_si_LDADD = $(LDADD)
+t_get_si_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_get_ui_SOURCES = t-get_ui.c
+t_get_ui_OBJECTS = t-get_ui.$(OBJEXT)
+t_get_ui_LDADD = $(LDADD)
+t_get_ui_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_gsprec_SOURCES = t-gsprec.c
+t_gsprec_OBJECTS = t-gsprec.$(OBJEXT)
+t_gsprec_LDADD = $(LDADD)
+t_gsprec_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_inp_str_SOURCES = t-inp_str.c
+t_inp_str_OBJECTS = t-inp_str.$(OBJEXT)
+t_inp_str_LDADD = $(LDADD)
+t_inp_str_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_int_p_SOURCES = t-int_p.c
+t_int_p_OBJECTS = t-int_p.$(OBJEXT)
+t_int_p_LDADD = $(LDADD)
+t_int_p_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_mul_ui_SOURCES = t-mul_ui.c
+t_mul_ui_OBJECTS = t-mul_ui.$(OBJEXT)
+t_mul_ui_LDADD = $(LDADD)
+t_mul_ui_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_muldiv_SOURCES = t-muldiv.c
+t_muldiv_OBJECTS = t-muldiv.$(OBJEXT)
+t_muldiv_LDADD = $(LDADD)
+t_muldiv_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_pow_ui_SOURCES = t-pow_ui.c
+t_pow_ui_OBJECTS = t-pow_ui.$(OBJEXT)
+t_pow_ui_LDADD = $(LDADD)
+t_pow_ui_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_set_SOURCES = t-set.c
+t_set_OBJECTS = t-set.$(OBJEXT)
+t_set_LDADD = $(LDADD)
+t_set_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_set_q_SOURCES = t-set_q.c
+t_set_q_OBJECTS = t-set_q.$(OBJEXT)
+t_set_q_LDADD = $(LDADD)
+t_set_q_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_set_si_SOURCES = t-set_si.c
+t_set_si_OBJECTS = t-set_si.$(OBJEXT)
+t_set_si_LDADD = $(LDADD)
+t_set_si_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_set_ui_SOURCES = t-set_ui.c
+t_set_ui_OBJECTS = t-set_ui.$(OBJEXT)
+t_set_ui_LDADD = $(LDADD)
+t_set_ui_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_sqrt_SOURCES = t-sqrt.c
+t_sqrt_OBJECTS = t-sqrt.$(OBJEXT)
+t_sqrt_LDADD = $(LDADD)
+t_sqrt_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_sqrt_ui_SOURCES = t-sqrt_ui.c
+t_sqrt_ui_OBJECTS = t-sqrt_ui.$(OBJEXT)
+t_sqrt_ui_LDADD = $(LDADD)
+t_sqrt_ui_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_sub_SOURCES = t-sub.c
+t_sub_OBJECTS = t-sub.$(OBJEXT)
+t_sub_LDADD = $(LDADD)
+t_sub_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_trunc_SOURCES = t-trunc.c
+t_trunc_OBJECTS = t-trunc.$(OBJEXT)
+t_trunc_LDADD = $(LDADD)
+t_trunc_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_ui_div_SOURCES = t-ui_div.c
+t_ui_div_OBJECTS = t-ui_div.$(OBJEXT)
+t_ui_div_LDADD = $(LDADD)
+t_ui_div_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp =
+am__depfiles_maybe =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+SOURCES = reuse.c t-add.c t-cmp_d.c t-cmp_si.c t-conv.c t-div.c \
+	t-dm2exp.c t-eq.c t-fits.c t-get_d.c t-get_d_2exp.c t-get_si.c \
+	t-get_ui.c t-gsprec.c t-inp_str.c t-int_p.c t-mul_ui.c \
+	t-muldiv.c t-pow_ui.c t-set.c t-set_q.c t-set_si.c t-set_ui.c \
+	t-sqrt.c t-sqrt_ui.c t-sub.c t-trunc.c t-ui_div.c
+DIST_SOURCES = reuse.c t-add.c t-cmp_d.c t-cmp_si.c t-conv.c t-div.c \
+	t-dm2exp.c t-eq.c t-fits.c t-get_d.c t-get_d_2exp.c t-get_si.c \
+	t-get_ui.c t-gsprec.c t-inp_str.c t-int_p.c t-mul_ui.c \
+	t-muldiv.c t-pow_ui.c t-set.c t-set_q.c t-set_si.c t-set_ui.c \
+	t-sqrt.c t-sqrt_ui.c t-sub.c t-trunc.c t-ui_div.c
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__tty_colors_dummy = \
+  mgn= red= grn= lgn= blu= brg= std=; \
+  am__color_tests=no
+am__tty_colors = { \
+  $(am__tty_colors_dummy); \
+  if test "X$(AM_COLOR_TESTS)" = Xno; then \
+    am__color_tests=no; \
+  elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+    am__color_tests=yes; \
+  elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+    am__color_tests=yes; \
+  fi; \
+  if test $$am__color_tests = yes; then \
+    red=''; \
+    grn=''; \
+    lgn=''; \
+    blu=''; \
+    mgn=''; \
+    brg=''; \
+    std=''; \
+  fi; \
+}
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+  test -z "$$files" \
+    || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+    || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+         $(am__cd) "$$dir" && rm -f $$files; }; \
+  }
+am__recheck_rx = ^[ 	]*:recheck:[ 	]*
+am__global_test_result_rx = ^[ 	]*:global-test-result:[ 	]*
+am__copy_in_global_log_rx = ^[ 	]*:copy-in-global-log:[ 	]*
+# A command that, given a newline-separated list of test names on the
+# standard input, print the name of the tests that are to be re-run
+# upon "make recheck".
+am__list_recheck_tests = $(AWK) '{ \
+  recheck = 1; \
+  while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+    { \
+      if (rc < 0) \
+        { \
+          if ((getline line2 < ($$0 ".log")) < 0) \
+	    recheck = 0; \
+          break; \
+        } \
+      else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \
+        { \
+          recheck = 0; \
+          break; \
+        } \
+      else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \
+        { \
+          break; \
+        } \
+    }; \
+  if (recheck) \
+    print $$0; \
+  close ($$0 ".trs"); \
+  close ($$0 ".log"); \
+}'
+# A command that, given a newline-separated list of test names on the
+# standard input, create the global log from their .trs and .log files.
+am__create_global_log = $(AWK) ' \
+function fatal(msg) \
+{ \
+  print "fatal: making $@: " msg | "cat >&2"; \
+  exit 1; \
+} \
+function rst_section(header) \
+{ \
+  print header; \
+  len = length(header); \
+  for (i = 1; i <= len; i = i + 1) \
+    printf "="; \
+  printf "\n\n"; \
+} \
+{ \
+  copy_in_global_log = 1; \
+  global_test_result = "RUN"; \
+  while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+    { \
+      if (rc < 0) \
+         fatal("failed to read from " $$0 ".trs"); \
+      if (line ~ /$(am__global_test_result_rx)/) \
+        { \
+          sub("$(am__global_test_result_rx)", "", line); \
+          sub("[ 	]*$$", "", line); \
+          global_test_result = line; \
+        } \
+      else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \
+        copy_in_global_log = 0; \
+    }; \
+  if (copy_in_global_log) \
+    { \
+      rst_section(global_test_result ": " $$0); \
+      while ((rc = (getline line < ($$0 ".log"))) != 0) \
+      { \
+        if (rc < 0) \
+          fatal("failed to read from " $$0 ".log"); \
+        print line; \
+      }; \
+      printf "\n"; \
+    }; \
+  close ($$0 ".trs"); \
+  close ($$0 ".log"); \
+}'
+# Restructured Text title.
+am__rst_title = { sed 's/.*/   &   /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; }
+# Solaris 10 'make', and several other traditional 'make' implementations,
+# pass "-e" to $(SHELL), and POSIX 2008 even requires this.  Work around it
+# by disabling -e (using the XSI extension "set +e") if it's set.
+am__sh_e_setup = case $$- in *e*) set +e;; esac
+# Default flags passed to test drivers.
+am__common_driver_flags = \
+  --color-tests "$$am__color_tests" \
+  --enable-hard-errors "$$am__enable_hard_errors" \
+  --expect-failure "$$am__expect_failure"
+# To be inserted before the command running the test.  Creates the
+# directory for the log if needed.  Stores in $dir the directory
+# containing $f, in $tst the test, in $log the log.  Executes the
+# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and
+# passes TESTS_ENVIRONMENT.  Set up options for the wrapper that
+# will run the test scripts (or their associated LOG_COMPILER, if
+# thy have one).
+am__check_pre = \
+$(am__sh_e_setup);					\
+$(am__vpath_adj_setup) $(am__vpath_adj)			\
+$(am__tty_colors);					\
+srcdir=$(srcdir); export srcdir;			\
+case "$@" in						\
+  */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;;	\
+    *) am__odir=.;; 					\
+esac;							\
+test "x$$am__odir" = x"." || test -d "$$am__odir" 	\
+  || $(MKDIR_P) "$$am__odir" || exit $$?;		\
+if test -f "./$$f"; then dir=./;			\
+elif test -f "$$f"; then dir=;				\
+else dir="$(srcdir)/"; fi;				\
+tst=$$dir$$f; log='$@'; 				\
+if test -n '$(DISABLE_HARD_ERRORS)'; then		\
+  am__enable_hard_errors=no; 				\
+else							\
+  am__enable_hard_errors=yes; 				\
+fi; 							\
+case " $(XFAIL_TESTS) " in				\
+  *[\ \	]$$f[\ \	]* | *[\ \	]$$dir$$f[\ \	]*) \
+    am__expect_failure=yes;;				\
+  *)							\
+    am__expect_failure=no;;				\
+esac; 							\
+$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT)
+# A shell command to get the names of the tests scripts with any registered
+# extension removed (i.e., equivalently, the names of the test logs, with
+# the '.log' extension removed).  The result is saved in the shell variable
+# '$bases'.  This honors runtime overriding of TESTS and TEST_LOGS.  Sadly,
+# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)",
+# since that might cause problem with VPATH rewrites for suffix-less tests.
+# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'.
+am__set_TESTS_bases = \
+  bases='$(TEST_LOGS)'; \
+  bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \
+  bases=`echo $$bases`
+RECHECK_LOGS = $(TEST_LOGS)
+AM_RECURSIVE_TARGETS = check recheck
+TEST_SUITE_LOG = test-suite.log
+TEST_EXTENSIONS = @EXEEXT@ .test
+LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS)
+am__set_b = \
+  case '$@' in \
+    */*) \
+      case '$*' in \
+        */*) b='$*';; \
+          *) b=`echo '$@' | sed 's/\.log$$//'`; \
+       esac;; \
+    *) \
+      b='$*';; \
+  esac
+am__test_logs1 = $(TESTS:=.log)
+am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log)
+TEST_LOGS = $(am__test_logs2:.test.log=.log)
+TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \
+	$(TEST_LOG_FLAGS)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/test-driver
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ABI = @ABI@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+ASMFLAGS = @ASMFLAGS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CALLING_CONVENTIONS_OBJS = @CALLING_CONVENTIONS_OBJS@
+CC = @CC@
+CCAS = @CCAS@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPP_FOR_BUILD = @CPP_FOR_BUILD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFN_LONG_LONG_LIMB = @DEFN_LONG_LONG_LIMB@
+DEFS = @DEFS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@
+FGREP = @FGREP@
+GMP_LDFLAGS = @GMP_LDFLAGS@
+GMP_LIMB_BITS = @GMP_LIMB_BITS@
+GMP_NAIL_BITS = @GMP_NAIL_BITS@
+GREP = @GREP@
+HAVE_CLOCK_01 = @HAVE_CLOCK_01@
+HAVE_CPUTIME_01 = @HAVE_CPUTIME_01@
+HAVE_GETRUSAGE_01 = @HAVE_GETRUSAGE_01@
+HAVE_GETTIMEOFDAY_01 = @HAVE_GETTIMEOFDAY_01@
+HAVE_HOST_CPU_FAMILY_power = @HAVE_HOST_CPU_FAMILY_power@
+HAVE_HOST_CPU_FAMILY_powerpc = @HAVE_HOST_CPU_FAMILY_powerpc@
+HAVE_SIGACTION_01 = @HAVE_SIGACTION_01@
+HAVE_SIGALTSTACK_01 = @HAVE_SIGALTSTACK_01@
+HAVE_SIGSTACK_01 = @HAVE_SIGSTACK_01@
+HAVE_STACK_T_01 = @HAVE_STACK_T_01@
+HAVE_SYS_RESOURCE_H_01 = @HAVE_SYS_RESOURCE_H_01@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCURSES = @LIBCURSES@
+LIBGMPXX_LDFLAGS = @LIBGMPXX_LDFLAGS@
+LIBGMP_DLL = @LIBGMP_DLL@
+LIBGMP_LDFLAGS = @LIBGMP_LDFLAGS@
+LIBM = @LIBM@
+LIBM_FOR_BUILD = @LIBM_FOR_BUILD@
+LIBOBJS = @LIBOBJS@
+LIBREADLINE = @LIBREADLINE@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+M4 = @M4@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPEED_CYCLECOUNTER_OBJ = @SPEED_CYCLECOUNTER_OBJ@
+STRIP = @STRIP@
+TAL_OBJECT = @TAL_OBJECT@
+TUNE_LIBS = @TUNE_LIBS@
+TUNE_SQR_OBJ = @TUNE_SQR_OBJ@
+U_FOR_BUILD = @U_FOR_BUILD@
+VERSION = @VERSION@
+WITH_READLINE_01 = @WITH_READLINE_01@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__leading_dot = @am__leading_dot@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gmp_srclinks = @gmp_srclinks@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+mpn_objects = @mpn_objects@
+mpn_objs_in_libgmp = @mpn_objs_in_libgmp@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/tests
+AM_LDFLAGS = -no-install
+LDADD = $(top_builddir)/tests/libtests.la $(top_builddir)/libgmp.la
+TESTS = $(check_PROGRAMS)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .log .o .obj .test .test$(EXEEXT) .trs
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu --ignore-deps tests/mpf/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu --ignore-deps tests/mpf/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-checkPROGRAMS:
+	@list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
+	echo " rm -f" $$list; \
+	rm -f $$list || exit $$?; \
+	test -n "$(EXEEXT)" || exit 0; \
+	list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+	echo " rm -f" $$list; \
+	rm -f $$list
+
+reuse$(EXEEXT): $(reuse_OBJECTS) $(reuse_DEPENDENCIES) $(EXTRA_reuse_DEPENDENCIES) 
+	@rm -f reuse$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(reuse_OBJECTS) $(reuse_LDADD) $(LIBS)
+
+t-add$(EXEEXT): $(t_add_OBJECTS) $(t_add_DEPENDENCIES) $(EXTRA_t_add_DEPENDENCIES) 
+	@rm -f t-add$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_add_OBJECTS) $(t_add_LDADD) $(LIBS)
+
+t-cmp_d$(EXEEXT): $(t_cmp_d_OBJECTS) $(t_cmp_d_DEPENDENCIES) $(EXTRA_t_cmp_d_DEPENDENCIES) 
+	@rm -f t-cmp_d$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_cmp_d_OBJECTS) $(t_cmp_d_LDADD) $(LIBS)
+
+t-cmp_si$(EXEEXT): $(t_cmp_si_OBJECTS) $(t_cmp_si_DEPENDENCIES) $(EXTRA_t_cmp_si_DEPENDENCIES) 
+	@rm -f t-cmp_si$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_cmp_si_OBJECTS) $(t_cmp_si_LDADD) $(LIBS)
+
+t-conv$(EXEEXT): $(t_conv_OBJECTS) $(t_conv_DEPENDENCIES) $(EXTRA_t_conv_DEPENDENCIES) 
+	@rm -f t-conv$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_conv_OBJECTS) $(t_conv_LDADD) $(LIBS)
+
+t-div$(EXEEXT): $(t_div_OBJECTS) $(t_div_DEPENDENCIES) $(EXTRA_t_div_DEPENDENCIES) 
+	@rm -f t-div$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_div_OBJECTS) $(t_div_LDADD) $(LIBS)
+
+t-dm2exp$(EXEEXT): $(t_dm2exp_OBJECTS) $(t_dm2exp_DEPENDENCIES) $(EXTRA_t_dm2exp_DEPENDENCIES) 
+	@rm -f t-dm2exp$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_dm2exp_OBJECTS) $(t_dm2exp_LDADD) $(LIBS)
+
+t-eq$(EXEEXT): $(t_eq_OBJECTS) $(t_eq_DEPENDENCIES) $(EXTRA_t_eq_DEPENDENCIES) 
+	@rm -f t-eq$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_eq_OBJECTS) $(t_eq_LDADD) $(LIBS)
+
+t-fits$(EXEEXT): $(t_fits_OBJECTS) $(t_fits_DEPENDENCIES) $(EXTRA_t_fits_DEPENDENCIES) 
+	@rm -f t-fits$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_fits_OBJECTS) $(t_fits_LDADD) $(LIBS)
+
+t-get_d$(EXEEXT): $(t_get_d_OBJECTS) $(t_get_d_DEPENDENCIES) $(EXTRA_t_get_d_DEPENDENCIES) 
+	@rm -f t-get_d$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_get_d_OBJECTS) $(t_get_d_LDADD) $(LIBS)
+
+t-get_d_2exp$(EXEEXT): $(t_get_d_2exp_OBJECTS) $(t_get_d_2exp_DEPENDENCIES) $(EXTRA_t_get_d_2exp_DEPENDENCIES) 
+	@rm -f t-get_d_2exp$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_get_d_2exp_OBJECTS) $(t_get_d_2exp_LDADD) $(LIBS)
+
+t-get_si$(EXEEXT): $(t_get_si_OBJECTS) $(t_get_si_DEPENDENCIES) $(EXTRA_t_get_si_DEPENDENCIES) 
+	@rm -f t-get_si$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_get_si_OBJECTS) $(t_get_si_LDADD) $(LIBS)
+
+t-get_ui$(EXEEXT): $(t_get_ui_OBJECTS) $(t_get_ui_DEPENDENCIES) $(EXTRA_t_get_ui_DEPENDENCIES) 
+	@rm -f t-get_ui$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_get_ui_OBJECTS) $(t_get_ui_LDADD) $(LIBS)
+
+t-gsprec$(EXEEXT): $(t_gsprec_OBJECTS) $(t_gsprec_DEPENDENCIES) $(EXTRA_t_gsprec_DEPENDENCIES) 
+	@rm -f t-gsprec$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_gsprec_OBJECTS) $(t_gsprec_LDADD) $(LIBS)
+
+t-inp_str$(EXEEXT): $(t_inp_str_OBJECTS) $(t_inp_str_DEPENDENCIES) $(EXTRA_t_inp_str_DEPENDENCIES) 
+	@rm -f t-inp_str$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_inp_str_OBJECTS) $(t_inp_str_LDADD) $(LIBS)
+
+t-int_p$(EXEEXT): $(t_int_p_OBJECTS) $(t_int_p_DEPENDENCIES) $(EXTRA_t_int_p_DEPENDENCIES) 
+	@rm -f t-int_p$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_int_p_OBJECTS) $(t_int_p_LDADD) $(LIBS)
+
+t-mul_ui$(EXEEXT): $(t_mul_ui_OBJECTS) $(t_mul_ui_DEPENDENCIES) $(EXTRA_t_mul_ui_DEPENDENCIES) 
+	@rm -f t-mul_ui$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_mul_ui_OBJECTS) $(t_mul_ui_LDADD) $(LIBS)
+
+t-muldiv$(EXEEXT): $(t_muldiv_OBJECTS) $(t_muldiv_DEPENDENCIES) $(EXTRA_t_muldiv_DEPENDENCIES) 
+	@rm -f t-muldiv$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_muldiv_OBJECTS) $(t_muldiv_LDADD) $(LIBS)
+
+t-pow_ui$(EXEEXT): $(t_pow_ui_OBJECTS) $(t_pow_ui_DEPENDENCIES) $(EXTRA_t_pow_ui_DEPENDENCIES) 
+	@rm -f t-pow_ui$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_pow_ui_OBJECTS) $(t_pow_ui_LDADD) $(LIBS)
+
+t-set$(EXEEXT): $(t_set_OBJECTS) $(t_set_DEPENDENCIES) $(EXTRA_t_set_DEPENDENCIES) 
+	@rm -f t-set$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_set_OBJECTS) $(t_set_LDADD) $(LIBS)
+
+t-set_q$(EXEEXT): $(t_set_q_OBJECTS) $(t_set_q_DEPENDENCIES) $(EXTRA_t_set_q_DEPENDENCIES) 
+	@rm -f t-set_q$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_set_q_OBJECTS) $(t_set_q_LDADD) $(LIBS)
+
+t-set_si$(EXEEXT): $(t_set_si_OBJECTS) $(t_set_si_DEPENDENCIES) $(EXTRA_t_set_si_DEPENDENCIES) 
+	@rm -f t-set_si$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_set_si_OBJECTS) $(t_set_si_LDADD) $(LIBS)
+
+t-set_ui$(EXEEXT): $(t_set_ui_OBJECTS) $(t_set_ui_DEPENDENCIES) $(EXTRA_t_set_ui_DEPENDENCIES) 
+	@rm -f t-set_ui$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_set_ui_OBJECTS) $(t_set_ui_LDADD) $(LIBS)
+
+t-sqrt$(EXEEXT): $(t_sqrt_OBJECTS) $(t_sqrt_DEPENDENCIES) $(EXTRA_t_sqrt_DEPENDENCIES) 
+	@rm -f t-sqrt$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_sqrt_OBJECTS) $(t_sqrt_LDADD) $(LIBS)
+
+t-sqrt_ui$(EXEEXT): $(t_sqrt_ui_OBJECTS) $(t_sqrt_ui_DEPENDENCIES) $(EXTRA_t_sqrt_ui_DEPENDENCIES) 
+	@rm -f t-sqrt_ui$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_sqrt_ui_OBJECTS) $(t_sqrt_ui_LDADD) $(LIBS)
+
+t-sub$(EXEEXT): $(t_sub_OBJECTS) $(t_sub_DEPENDENCIES) $(EXTRA_t_sub_DEPENDENCIES) 
+	@rm -f t-sub$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_sub_OBJECTS) $(t_sub_LDADD) $(LIBS)
+
+t-trunc$(EXEEXT): $(t_trunc_OBJECTS) $(t_trunc_DEPENDENCIES) $(EXTRA_t_trunc_DEPENDENCIES) 
+	@rm -f t-trunc$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_trunc_OBJECTS) $(t_trunc_LDADD) $(LIBS)
+
+t-ui_div$(EXEEXT): $(t_ui_div_OBJECTS) $(t_ui_div_DEPENDENCIES) $(EXTRA_t_ui_div_DEPENDENCIES) 
+	@rm -f t-ui_div$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_ui_div_OBJECTS) $(t_ui_div_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+.c.o:
+	$(AM_V_CC)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+	$(AM_V_CC)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+	$(AM_V_CC)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+# Recover from deleted '.trs' file; this should ensure that
+# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create
+# both 'foo.log' and 'foo.trs'.  Break the recipe in two subshells
+# to avoid problems with "make -n".
+.log.trs:
+	rm -f $< $@
+	$(MAKE) $(AM_MAKEFLAGS) $<
+
+# Leading 'am--fnord' is there to ensure the list of targets does not
+# expand to empty, as could happen e.g. with make check TESTS=''.
+am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck)
+am--force-recheck:
+	@:
+
+$(TEST_SUITE_LOG): $(TEST_LOGS)
+	@$(am__set_TESTS_bases); \
+	am__f_ok () { test -f "$$1" && test -r "$$1"; }; \
+	redo_bases=`for i in $$bases; do \
+	              am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \
+	            done`; \
+	if test -n "$$redo_bases"; then \
+	  redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \
+	  redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \
+	  if $(am__make_dryrun); then :; else \
+	    rm -f $$redo_logs && rm -f $$redo_results || exit 1; \
+	  fi; \
+	fi; \
+	if test -n "$$am__remaking_logs"; then \
+	  echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \
+	       "recursion detected" >&2; \
+	elif test -n "$$redo_logs"; then \
+	  am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \
+	fi; \
+	if $(am__make_dryrun); then :; else \
+	  st=0;  \
+	  errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \
+	  for i in $$redo_bases; do \
+	    test -f $$i.trs && test -r $$i.trs \
+	      || { echo "$$errmsg $$i.trs" >&2; st=1; }; \
+	    test -f $$i.log && test -r $$i.log \
+	      || { echo "$$errmsg $$i.log" >&2; st=1; }; \
+	  done; \
+	  test $$st -eq 0 || exit 1; \
+	fi
+	@$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \
+	ws='[ 	]'; \
+	results=`for b in $$bases; do echo $$b.trs; done`; \
+	test -n "$$results" || results=/dev/null; \
+	all=`  grep "^$$ws*:test-result:"           $$results | wc -l`; \
+	pass=` grep "^$$ws*:test-result:$$ws*PASS"  $$results | wc -l`; \
+	fail=` grep "^$$ws*:test-result:$$ws*FAIL"  $$results | wc -l`; \
+	skip=` grep "^$$ws*:test-result:$$ws*SKIP"  $$results | wc -l`; \
+	xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \
+	xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \
+	error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \
+	if test `expr $$fail + $$xpass + $$error` -eq 0; then \
+	  success=true; \
+	else \
+	  success=false; \
+	fi; \
+	br='==================='; br=$$br$$br$$br$$br; \
+	result_count () \
+	{ \
+	    if test x"$$1" = x"--maybe-color"; then \
+	      maybe_colorize=yes; \
+	    elif test x"$$1" = x"--no-color"; then \
+	      maybe_colorize=no; \
+	    else \
+	      echo "$@: invalid 'result_count' usage" >&2; exit 4; \
+	    fi; \
+	    shift; \
+	    desc=$$1 count=$$2; \
+	    if test $$maybe_colorize = yes && test $$count -gt 0; then \
+	      color_start=$$3 color_end=$$std; \
+	    else \
+	      color_start= color_end=; \
+	    fi; \
+	    echo "$${color_start}# $$desc $$count$${color_end}"; \
+	}; \
+	create_testsuite_report () \
+	{ \
+	  result_count $$1 "TOTAL:" $$all   "$$brg"; \
+	  result_count $$1 "PASS: " $$pass  "$$grn"; \
+	  result_count $$1 "SKIP: " $$skip  "$$blu"; \
+	  result_count $$1 "XFAIL:" $$xfail "$$lgn"; \
+	  result_count $$1 "FAIL: " $$fail  "$$red"; \
+	  result_count $$1 "XPASS:" $$xpass "$$red"; \
+	  result_count $$1 "ERROR:" $$error "$$mgn"; \
+	}; \
+	{								\
+	  echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" |	\
+	    $(am__rst_title);						\
+	  create_testsuite_report --no-color;				\
+	  echo;								\
+	  echo ".. contents:: :depth: 2";				\
+	  echo;								\
+	  for b in $$bases; do echo $$b; done				\
+	    | $(am__create_global_log);					\
+	} >$(TEST_SUITE_LOG).tmp || exit 1;				\
+	mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG);			\
+	if $$success; then						\
+	  col="$$grn";							\
+	 else								\
+	  col="$$red";							\
+	  test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG);		\
+	fi;								\
+	echo "$${col}$$br$${std}"; 					\
+	echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}";	\
+	echo "$${col}$$br$${std}"; 					\
+	create_testsuite_report --maybe-color;				\
+	echo "$$col$$br$$std";						\
+	if $$success; then :; else					\
+	  echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}";		\
+	  if test -n "$(PACKAGE_BUGREPORT)"; then			\
+	    echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}";	\
+	  fi;								\
+	  echo "$$col$$br$$std";					\
+	fi;								\
+	$$success || exit 1
+
+check-TESTS:
+	@list='$(RECHECK_LOGS)';           test -z "$$list" || rm -f $$list
+	@list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list
+	@test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+	@set +e; $(am__set_TESTS_bases); \
+	log_list=`for i in $$bases; do echo $$i.log; done`; \
+	trs_list=`for i in $$bases; do echo $$i.trs; done`; \
+	log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \
+	$(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \
+	exit $$?;
+recheck: all $(check_PROGRAMS)
+	@test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+	@set +e; $(am__set_TESTS_bases); \
+	bases=`for i in $$bases; do echo $$i; done \
+	         | $(am__list_recheck_tests)` || exit 1; \
+	log_list=`for i in $$bases; do echo $$i.log; done`; \
+	log_list=`echo $$log_list`; \
+	$(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \
+	        am__force_recheck=am--force-recheck \
+	        TEST_LOGS="$$log_list"; \
+	exit $$?
+t-dm2exp.log: t-dm2exp$(EXEEXT)
+	@p='t-dm2exp$(EXEEXT)'; \
+	b='t-dm2exp'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-conv.log: t-conv$(EXEEXT)
+	@p='t-conv$(EXEEXT)'; \
+	b='t-conv'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-add.log: t-add$(EXEEXT)
+	@p='t-add$(EXEEXT)'; \
+	b='t-add'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-sub.log: t-sub$(EXEEXT)
+	@p='t-sub$(EXEEXT)'; \
+	b='t-sub'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-sqrt.log: t-sqrt$(EXEEXT)
+	@p='t-sqrt$(EXEEXT)'; \
+	b='t-sqrt'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-sqrt_ui.log: t-sqrt_ui$(EXEEXT)
+	@p='t-sqrt_ui$(EXEEXT)'; \
+	b='t-sqrt_ui'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-muldiv.log: t-muldiv$(EXEEXT)
+	@p='t-muldiv$(EXEEXT)'; \
+	b='t-muldiv'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+reuse.log: reuse$(EXEEXT)
+	@p='reuse$(EXEEXT)'; \
+	b='reuse'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-cmp_d.log: t-cmp_d$(EXEEXT)
+	@p='t-cmp_d$(EXEEXT)'; \
+	b='t-cmp_d'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-cmp_si.log: t-cmp_si$(EXEEXT)
+	@p='t-cmp_si$(EXEEXT)'; \
+	b='t-cmp_si'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-div.log: t-div$(EXEEXT)
+	@p='t-div$(EXEEXT)'; \
+	b='t-div'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-fits.log: t-fits$(EXEEXT)
+	@p='t-fits$(EXEEXT)'; \
+	b='t-fits'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-get_d.log: t-get_d$(EXEEXT)
+	@p='t-get_d$(EXEEXT)'; \
+	b='t-get_d'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-get_d_2exp.log: t-get_d_2exp$(EXEEXT)
+	@p='t-get_d_2exp$(EXEEXT)'; \
+	b='t-get_d_2exp'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-get_si.log: t-get_si$(EXEEXT)
+	@p='t-get_si$(EXEEXT)'; \
+	b='t-get_si'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-get_ui.log: t-get_ui$(EXEEXT)
+	@p='t-get_ui$(EXEEXT)'; \
+	b='t-get_ui'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-gsprec.log: t-gsprec$(EXEEXT)
+	@p='t-gsprec$(EXEEXT)'; \
+	b='t-gsprec'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-inp_str.log: t-inp_str$(EXEEXT)
+	@p='t-inp_str$(EXEEXT)'; \
+	b='t-inp_str'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-int_p.log: t-int_p$(EXEEXT)
+	@p='t-int_p$(EXEEXT)'; \
+	b='t-int_p'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-mul_ui.log: t-mul_ui$(EXEEXT)
+	@p='t-mul_ui$(EXEEXT)'; \
+	b='t-mul_ui'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-set.log: t-set$(EXEEXT)
+	@p='t-set$(EXEEXT)'; \
+	b='t-set'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-set_q.log: t-set_q$(EXEEXT)
+	@p='t-set_q$(EXEEXT)'; \
+	b='t-set_q'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-set_si.log: t-set_si$(EXEEXT)
+	@p='t-set_si$(EXEEXT)'; \
+	b='t-set_si'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-set_ui.log: t-set_ui$(EXEEXT)
+	@p='t-set_ui$(EXEEXT)'; \
+	b='t-set_ui'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-trunc.log: t-trunc$(EXEEXT)
+	@p='t-trunc$(EXEEXT)'; \
+	b='t-trunc'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-ui_div.log: t-ui_div$(EXEEXT)
+	@p='t-ui_div$(EXEEXT)'; \
+	b='t-ui_div'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-eq.log: t-eq$(EXEEXT)
+	@p='t-eq$(EXEEXT)'; \
+	b='t-eq'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-pow_ui.log: t-pow_ui$(EXEEXT)
+	@p='t-pow_ui$(EXEEXT)'; \
+	b='t-pow_ui'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+.test.log:
+	@p='$<'; \
+	$(am__set_b); \
+	$(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+@am__EXEEXT_TRUE@.test$(EXEEXT).log:
+@am__EXEEXT_TRUE@	@p='$<'; \
+@am__EXEEXT_TRUE@	$(am__set_b); \
+@am__EXEEXT_TRUE@	$(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+@am__EXEEXT_TRUE@	--log-file $$b.log --trs-file $$b.trs \
+@am__EXEEXT_TRUE@	$(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+@am__EXEEXT_TRUE@	"$$tst" $(AM_TESTS_FD_REDIRECT)
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+	$(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+	-test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS)
+	-test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs)
+	-test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-TESTS check-am clean \
+	clean-checkPROGRAMS clean-generic clean-libtool cscopelist-am \
+	ctags ctags-am distclean distclean-compile distclean-generic \
+	distclean-libtool distclean-tags distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-dvi install-dvi-am install-exec \
+	install-exec-am install-html install-html-am install-info \
+	install-info-am install-man install-pdf install-pdf-am \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	recheck tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+$(top_builddir)/tests/libtests.la:
+	cd $(top_builddir)/tests; $(MAKE) $(AM_MAKEFLAGS) libtests.la
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/third_party/gmp/tests/mpf/reuse.c b/third_party/gmp/tests/mpf/reuse.c
new file mode 100644
index 0000000..6e6d0c3
--- /dev/null
+++ b/third_party/gmp/tests/mpf/reuse.c
@@ -0,0 +1,218 @@
+/* Test that routines allow reusing a source variable as destination.
+
+Copyright 1996, 2000-2002, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#if __GMP_LIBGMP_DLL
+
+/* FIXME: When linking to a DLL libgmp, mpf_add etc can't be used as
+   initializers for global variables because they're effectively global
+   variables (function pointers) themselves.  Perhaps calling a test
+   function successively with mpf_add etc would be better.  */
+
+int
+main (void)
+{
+  printf ("Test suppressed for windows DLL\n");
+  exit (0);
+}
+
+
+#else /* ! DLL_EXPORT */
+
+#ifndef SIZE
+#define SIZE 16
+#endif
+
+#ifndef EXPO
+#define EXPO 32
+#endif
+
+void dump_abort (const char *, mpf_t, mpf_t);
+
+typedef void (*dss_func) (mpf_ptr, mpf_srcptr, mpf_srcptr);
+
+dss_func dss_funcs[] =
+{
+  mpf_div, mpf_add, mpf_mul, mpf_sub,
+};
+
+const char *dss_func_names[] =
+{
+  "mpf_div", "mpf_add", "mpf_mul", "mpf_sub",
+};
+
+typedef void (*dsi_func) (mpf_ptr, mpf_srcptr, unsigned long int);
+
+dsi_func dsi_funcs[] =
+{
+  mpf_div_ui, mpf_add_ui, mpf_mul_ui, mpf_sub_ui,
+  mpf_mul_2exp, mpf_div_2exp, mpf_pow_ui
+};
+
+const char *dsi_func_names[] =
+{
+  "mpf_div_ui", "mpf_add_ui", "mpf_mul_ui", "mpf_sub_ui",
+  "mpf_mul_2exp", "mpf_div_2exp", "mpf_pow_ui"
+};
+
+typedef void (*dis_func) (mpf_ptr, unsigned long int, mpf_srcptr);
+
+dis_func dis_funcs[] =
+{
+  mpf_ui_div, mpf_ui_sub,
+};
+
+const char *dis_func_names[] =
+{
+  "mpf_ui_div", "mpf_ui_sub",
+};
+
+int
+main (int argc, char **argv)
+{
+  int i;
+  int pass, reps = 10000;
+  mpf_t in1, in2, out1;
+  unsigned long int in1i, in2i;
+  mpf_t res1, res2, res3;
+  mp_size_t bprec = 100;
+
+  tests_start ();
+
+  if (argc > 1)
+    {
+      reps = strtol (argv[1], 0, 0);
+      if (argc > 2)
+	bprec = strtol (argv[2], 0, 0);
+    }
+
+  mpf_set_default_prec (bprec);
+
+  mpf_init (in1);
+  mpf_init (in2);
+  mpf_init (out1);
+  mpf_init (res1);
+  mpf_init (res2);
+  mpf_init (res3);
+
+  for (pass = 1; pass <= reps; pass++)
+    {
+      mpf_random2 (in1, urandom () % SIZE - SIZE/2, urandom () % EXPO);
+      mpf_random2 (in2, urandom () % SIZE - SIZE/2, urandom () % EXPO);
+
+      for (i = 0; i < sizeof (dss_funcs) / sizeof (dss_func); i++)
+	{
+	  /* Don't divide by 0.  */
+	  if (i == 0 && mpf_cmp_ui (in2, 0) == 0)
+	    continue;
+
+	  (dss_funcs[i]) (res1, in1, in2);
+
+	  mpf_set (out1, in1);
+	  (dss_funcs[i]) (out1, out1, in2);
+	  mpf_set (res2, out1);
+
+	  mpf_set (out1, in2);
+	  (dss_funcs[i]) (out1, in1, out1);
+	  mpf_set (res3, out1);
+
+	  if (mpf_cmp (res1, res2) != 0)
+	    dump_abort (dss_func_names[i], res1, res2);
+	  if (mpf_cmp (res1, res3) != 0)
+	    dump_abort (dss_func_names[i], res1, res3);
+	}
+
+      in2i = urandom ();
+      for (i = 0; i < sizeof (dsi_funcs) / sizeof (dsi_func); i++)
+	{
+	  unsigned long this_in2i = in2i;
+
+	  /* Don't divide by 0.  */
+	  if (dsi_funcs[i] == mpf_div_ui && this_in2i == 0)
+	    continue;
+
+	  /* Avoid overflow/underflow in the exponent.  */
+	  if (dsi_funcs[i] == mpf_mul_2exp || dsi_funcs[i] == mpf_div_2exp)
+	    this_in2i %= 0x100000;
+	  else if (dsi_funcs[i] == mpf_pow_ui)
+	    this_in2i %= 0x1000;
+
+	  (dsi_funcs[i]) (res1, in1, this_in2i);
+
+	  mpf_set (out1, in1);
+	  (dsi_funcs[i]) (out1, out1, this_in2i);
+	  mpf_set (res2, out1);
+
+	  if (mpf_cmp (res1, res2) != 0)
+	    dump_abort (dsi_func_names[i], res1, res2);
+	}
+
+      in1i = urandom ();
+      for (i = 0; i < sizeof (dis_funcs) / sizeof (dis_func); i++)
+	{
+	  /* Don't divide by 0.  */
+	  if (dis_funcs[i] == mpf_ui_div
+	      && mpf_cmp_ui (in2, 0) == 0)
+	    continue;
+
+	  (dis_funcs[i]) (res1, in1i, in2);
+
+	  mpf_set (out1, in2);
+	  (dis_funcs[i]) (out1, in1i, out1);
+	  mpf_set (res2, out1);
+
+	  if (mpf_cmp (res1, res2) != 0)
+	    dump_abort (dis_func_names[i], res1, res2);
+	}
+
+    }
+
+  mpf_clear (in1);
+  mpf_clear (in2);
+  mpf_clear (out1);
+  mpf_clear (res1);
+  mpf_clear (res2);
+  mpf_clear (res3);
+
+  tests_end ();
+  exit (0);
+}
+
+void
+dump_abort (const char *name, mpf_t res1, mpf_t res2)
+{
+  printf ("failure in %s:\n", name);
+  mpf_dump (res1);
+  mpf_dump (res2);
+  abort ();
+}
+
+#if 0
+void mpf_abs		(mpf_ptr, mpf_srcptr);
+void mpf_sqrt		(mpf_ptr, mpf_srcptr);
+void mpf_neg		(mpf_ptr, mpf_srcptr);
+#endif
+
+#endif /* ! DLL_EXPORT */
diff --git a/third_party/gmp/tests/mpf/t-add.c b/third_party/gmp/tests/mpf/t-add.c
new file mode 100644
index 0000000..eb8bbdc
--- /dev/null
+++ b/third_party/gmp/tests/mpf/t-add.c
@@ -0,0 +1,107 @@
+/* Test mpf_add.
+
+Copyright 1996, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#ifndef SIZE
+#define SIZE 16
+#endif
+
+int
+main (int argc, char **argv)
+{
+  mp_size_t size;
+  mp_exp_t exp;
+  int reps = 20000;
+  int i;
+  mpf_t u, v, w, wref;
+  mp_size_t bprec = 100;
+  mpf_t rerr, max_rerr, limit_rerr;
+
+  tests_start ();
+
+  if (argc > 1)
+    {
+      reps = strtol (argv[1], 0, 0);
+      if (argc > 2)
+	bprec = strtol (argv[2], 0, 0);
+    }
+
+  mpf_set_default_prec (bprec);
+
+  mpf_init_set_ui (limit_rerr, 1);
+  mpf_div_2exp (limit_rerr, limit_rerr, bprec);
+#if VERBOSE
+  mpf_dump (limit_rerr);
+#endif
+  mpf_init (rerr);
+  mpf_init_set_ui (max_rerr, 0);
+
+  mpf_init (u);
+  mpf_init (v);
+  mpf_init (w);
+  mpf_init (wref);
+  for (i = 0; i < reps; i++)
+    {
+      size = urandom () % (2 * SIZE) - SIZE;
+      exp = urandom () % SIZE;
+      mpf_random2 (u, size, exp);
+
+      size = urandom () % (2 * SIZE) - SIZE;
+      exp = urandom () % SIZE;
+      mpf_random2 (v, size, exp);
+
+      mpf_add (w, u, v);
+      refmpf_add (wref, u, v);
+
+      mpf_reldiff (rerr, w, wref);
+      if (mpf_cmp (rerr, max_rerr) > 0)
+	{
+	  mpf_set (max_rerr, rerr);
+#if VERBOSE
+	  mpf_dump (max_rerr);
+#endif
+	  if (mpf_cmp (rerr, limit_rerr) > 0)
+	    {
+	      printf ("ERROR after %d tests\n", i);
+	      printf ("   u = "); mpf_dump (u);
+	      printf ("   v = "); mpf_dump (v);
+	      printf ("wref = "); mpf_dump (wref);
+	      printf ("   w = "); mpf_dump (w);
+	      abort ();
+	    }
+	}
+    }
+
+  mpf_clear (limit_rerr);
+  mpf_clear (rerr);
+  mpf_clear (max_rerr);
+
+  mpf_clear (u);
+  mpf_clear (v);
+  mpf_clear (w);
+  mpf_clear (wref);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpf/t-cmp_d.c b/third_party/gmp/tests/mpf/t-cmp_d.c
new file mode 100644
index 0000000..213c091
--- /dev/null
+++ b/third_party/gmp/tests/mpf/t-cmp_d.c
@@ -0,0 +1,103 @@
+/* Test mpf_cmp_d.
+
+Copyright 2001, 2003, 2003, 2005 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+#define SGN(n)  ((n) > 0 ? 1 : (n) < 0 ? -1 : 0)
+
+void
+check_one (const char *name, mpf_srcptr x, double y, int cmp)
+{
+  int   got;
+
+  got = mpf_cmp_d (x, y);
+  if (SGN(got) != cmp)
+    {
+      int i;
+      printf    ("mpf_cmp_d wrong (from %s)\n", name);
+      printf    ("  got  %d\n", got);
+      printf    ("  want %d\n", cmp);
+      mpf_trace ("  x", x);
+      printf    ("  y %g\n", y);
+      mp_trace_base=-16;
+      mpf_trace ("  x", x);
+      printf    ("  y %g\n", y);
+      printf    ("  y");
+      for (i = 0; i < sizeof(y); i++)
+        printf (" %02X", (unsigned) ((unsigned char *) &y)[i]);
+      printf ("\n");
+      abort ();
+    }
+}
+
+void
+check_infinity (void)
+{
+  mpf_t   x;
+  double  y = tests_infinity_d ();
+  if (y == 0.0)
+    return;
+
+  mpf_init (x);
+
+  /* 0 cmp inf */
+  mpf_set_ui (x, 0L);
+  check_one ("check_infinity", x,  y, -1);
+  check_one ("check_infinity", x, -y,  1);
+
+  /* 123 cmp inf */
+  mpf_set_ui (x, 123L);
+  check_one ("check_infinity", x,  y, -1);
+  check_one ("check_infinity", x, -y,  1);
+
+  /* -123 cmp inf */
+  mpf_set_si (x, -123L);
+  check_one ("check_infinity", x,  y, -1);
+  check_one ("check_infinity", x, -y,  1);
+
+  /* 2^5000 cmp inf */
+  mpf_set_ui (x, 1L);
+  mpf_mul_2exp (x, x, 5000L);
+  check_one ("check_infinity", x,  y, -1);
+  check_one ("check_infinity", x, -y,  1);
+
+  /* -2^5000 cmp inf */
+  mpf_neg (x, x);
+  check_one ("check_infinity", x,  y, -1);
+  check_one ("check_infinity", x, -y,  1);
+
+  mpf_clear (x);
+}
+
+int
+main (int argc, char *argv[])
+{
+  tests_start ();
+
+  check_infinity ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpf/t-cmp_si.c b/third_party/gmp/tests/mpf/t-cmp_si.c
new file mode 100644
index 0000000..29f7cdb
--- /dev/null
+++ b/third_party/gmp/tests/mpf/t-cmp_si.c
@@ -0,0 +1,134 @@
+/* Test mpf_cmp_si and mpf_cmp_z.
+
+Copyright 2000, 2001, 2004, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+#define SGN(x)       ((x) < 0 ? -1 : (x) == 0 ? 0 : 1)
+
+void
+check_data (void)
+{
+  static const struct {
+    int         a_base;
+    const char  *a;
+    const char  *b;
+    int         want;
+  } data[] = {
+    { 10, "0",  "1", -1 },
+    { 10, "0",  "0",  0 },
+    { 10, "0", "-1",  1 },
+
+    { 10, "1",  "1", 0 },
+    { 10, "1",  "0", 1 },
+    { 10, "1", "-1", 1 },
+
+    { 10, "-1",  "1", -1 },
+    { 10, "-1",  "0", -1 },
+    { 10, "-1", "-1", 0 },
+
+    { 10, "1.5", "2", -1 },
+    { 10, "1.5", "1",  1 },
+    { 10, "0.5", "1", -1 },
+
+    { 10, "-1.5", "-2",  1 },
+    { 10, "-1.5", "-1", -1 },
+    { 10, "-0.5", "-1",  1 },
+
+    { 16,         "0", "-0x80000000",  1 },
+    { 16,  "80000000", "-0x80000000",  1 },
+    { 16,  "80000001", "-0x80000000",  1 },
+    { 16, "-80000000", "-0x80000000",  0 },
+    { 16, "-80000001", "-0x80000000", -1 },
+    { 16, "-FF0080000001", "-0x80000000", -1 },
+
+    { 16,                 "0", "-0x8000000000000000",  1 },
+    { 16,  "8000000000000000", "-0x8000000000000000",  1 },
+    { 16,  "8000000000000001", "-0x8000000000000000",  1 },
+    { 16, "-8000000000000000", "-0x8000000000000000",  0 },
+    { 16, "-8000000000000000.1", "-0x8000000000000000", -1 },
+    { 16, "-FF008000000000000001", "-0x8000000000000000", -1 },
+
+    { 16,                 "0", "-0x876543210FEDCBA9876543210000000",  1 },
+    { 16,  "876543210FEDCBA9876543210000000", "-0x876543210FEDCBA9876543210000000",  1 },
+    { 16,  "876543210FEDCBA9876543210000001", "-0x876543210FEDCBA9876543210000000",  1 },
+    { 16, "-876543210FEDCBA9876543210000000", "-0x876543210FEDCBA9876543210000000",  0 },
+    { 16, "-876543210FEDCBA9876543210000000.1", "-0x876543210FEDCBA9876543210000000", -1 },
+    { 16, "-FF00876543210FEDCBA9876543210000000", "-0x876543210FEDCBA9876543210000000", -1 },
+  };
+
+  mpf_t  a;
+  mpz_t  bz;
+  long   b;
+  int    got;
+  int    i;
+
+  mpf_init2 (a, 128);
+  mpz_init (bz);
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpf_set_str_or_abort (a, data[i].a, data[i].a_base);
+      mpz_set_str_or_abort (bz, data[i].b, 0);
+
+      if (mpz_fits_slong_p (bz))
+        {
+          b = mpz_get_si (bz);
+          got = mpf_cmp_si (a, b);
+          if (SGN (got) != data[i].want)
+            {
+              printf ("mpf_cmp_si wrong on data[%d]\n", i);
+              printf ("  a="); mpf_out_str (stdout, 10, 0, a);
+              printf (" (%s)\n", data[i].a);
+              printf ("  b=%ld (%s)\n", b, data[i].b);
+              printf ("  got=%d\n", got);
+              printf ("  want=%d\n", data[i].want);
+              abort();
+            }
+        }
+
+      got = mpf_cmp_z (a, bz);
+      if (SGN (got) != data[i].want)
+	{
+	  b = mpz_get_si (bz);
+	  printf ("mpf_cmp_z wrong on data[%d]\n", i);
+	  printf ("  a="); mpf_out_str (stdout, 10, 0, a);
+	  printf (" (%s)\n", data[i].a);
+	  printf ("  b=%ld (%s)\n", b, data[i].b);
+	  printf ("  got=%d\n", got);
+	  printf ("  want=%d\n", data[i].want);
+	  abort();
+	}
+    }
+
+  mpf_clear (a);
+  mpz_clear (bz);
+}
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_data ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpf/t-conv.c b/third_party/gmp/tests/mpf/t-conv.c
new file mode 100644
index 0000000..a64e86f
--- /dev/null
+++ b/third_party/gmp/tests/mpf/t-conv.c
@@ -0,0 +1,242 @@
+/* Test mpf_get_str and mpf_set_str.
+
+Copyright 1996, 2000, 2001, 2008, 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h> /* for strlen */
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#ifndef SIZE
+#define SIZE 10
+#endif
+
+#ifndef EXPO
+#define EXPO 200
+#endif
+
+int
+main (int argc, char **argv)
+{
+  mpf_t x, y;
+  int reps = 20000;
+  int i;
+  mp_size_t bprec = 100;
+  mpf_t d, rerr, max_rerr, limit_rerr;
+  char *str;
+  mp_exp_t bexp;
+  long size, exp;
+  int base;
+  char buf[SIZE * GMP_LIMB_BITS + 5];
+
+  tests_start ();
+
+  if (argc > 1)
+    {
+      reps = strtol (argv[1], 0, 0);
+      if (argc > 2)
+	bprec = strtol (argv[2], 0, 0);
+    }
+
+  mpf_set_default_prec (bprec);
+
+  mpf_init_set_ui (limit_rerr, 1);
+  mpf_div_2exp (limit_rerr, limit_rerr, bprec);
+#if VERBOSE
+  mpf_dump (limit_rerr);
+#endif
+  mpf_init (rerr);
+  mpf_init_set_ui (max_rerr, 0);
+
+  mpf_init (x);
+  mpf_init (y);
+  mpf_init (d);
+
+  /* First test some specific values.  */
+
+  mpf_set_str (y, "1.23456", 0);
+  mpf_set_str (x, "1.23456", 10);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, "00000000000000000000000000000000000000001.23456", 10);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, "0.000000000000000000000000000000000000000123456e40", 10);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, ".000000000000000000000000000000000000000123456e40", 10);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, "00000000000000000000.00000000000000000000123456e21", 10);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+
+  mpf_set_str (y, "1.23456e1000", 0);
+  mpf_set_str (x, "1.23456e1000", 10);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, "1.23456e+1000", 0);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, "1.23456e+1000", 10);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, "00000000000000000000000000000000000000001.23456e+1000", 10);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, "0.000000000000000000000000000000000000000123456e+1040", 10);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, ".000000000000000000000000000000000000000123456e+1040", 10);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, "00000000000000000000.00000000000000000000123456e+1021", 10);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+
+  mpf_set_str (y, "1.23456", 16);
+  mpf_set_str (x, "00000000000000000000000000000000000000001.23456", 16);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, "0.000000000000000000000000000000000000000123456@28", 16);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, ".000000000000000000000000000000000000000123456@28", 16);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, "00000000000000000000.00000000000000000000123456@15", 16);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+
+  mpf_set_str (y, "0", 10);
+  mpf_set_str (x, "00000000000000000000000000000000000000000000000000000", 10);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, "0000000000000000000000000000000000000000000000000000.", 10);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, "000000000000000000000000000000000000000000000000000.0", 10);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, ".0000000000000000000000000000000000000000000000000000", 10);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, "0.000000000000000000000000000000000000000000000000000", 10);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+
+  mpf_set_str (y, "0", 16);
+  mpf_set_str (x, "00000000000000000000000000000000000000000000000000000", 16);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, "0000000000000000000000000000000000000000000000000000.", 16);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, "000000000000000000000000000000000000000000000000000.0", 16);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, ".0000000000000000000000000000000000000000000000000000", 16);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+  mpf_set_str (x, "0.000000000000000000000000000000000000000000000000000", 16);
+  MPF_CHECK_FORMAT (x);
+  if (mpf_cmp (x, y) != 0)
+    abort ();
+
+  /* Now test random values.  */
+
+  for (i = 0; i < reps; i++)
+    {
+      if (i == 0)
+        {
+          /* exercise the special case in get_str for for x==0 */
+          mpf_set_ui (x, 0L);
+          base = 0;
+        }
+      else
+        {
+          size = urandom () % (2 * SIZE) - SIZE;
+          exp = urandom () % EXPO;
+          mpf_random2 (x, size, exp);
+          base = urandom () % 62;
+          base += base > 0;
+        }
+
+      str = mpf_get_str (0, &bexp, base, 0, x);
+
+      if (str[0] == '-')
+	sprintf (buf, "-0.%s@%ld", str + 1, bexp);
+      else
+	sprintf (buf, "0.%s@%ld", str, bexp);
+
+      mpf_set_str_or_abort (y, buf, -base);
+      (*__gmp_free_func) (str, strlen (str) + 1);
+
+      mpf_reldiff (rerr, x, y);
+      if (mpf_cmp (rerr, max_rerr) > 0)
+	{
+	  mpf_set (max_rerr, rerr);
+#if VERBOSE
+	  mpf_dump (max_rerr);
+#endif
+	  if (mpf_cmp (rerr, limit_rerr) > 0)
+	    {
+	      printf ("ERROR after %d tests\n", i);
+	      printf ("base = %d\n", base);
+	      printf ("   x = "); mpf_dump (x);
+	      printf ("   y = "); mpf_dump (y);
+	      abort ();
+	    }
+	}
+    }
+
+  mpf_clear (limit_rerr);
+  mpf_clear (rerr);
+  mpf_clear (max_rerr);
+
+  mpf_clear (x);
+  mpf_clear (y);
+  mpf_clear (d);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpf/t-div.c b/third_party/gmp/tests/mpf/t-div.c
new file mode 100644
index 0000000..3214592
--- /dev/null
+++ b/third_party/gmp/tests/mpf/t-div.c
@@ -0,0 +1,185 @@
+/* Test mpf_div.
+
+Copyright 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_one (const char *desc, mpf_ptr got, mpf_srcptr u, mpf_srcptr v)
+{
+  if (! refmpf_validate_division ("mpf_div", got, u, v))
+    {
+      mp_trace_base = -16;
+      mpf_trace ("  u", u);
+      mpf_trace ("  v", v);
+      printf    ("  %s\n", desc);
+      abort ();
+    }
+}
+
+void
+check_rand (void)
+{
+  unsigned long  min_prec = __GMPF_BITS_TO_PREC (1);
+  gmp_randstate_ptr  rands = RANDS;
+  unsigned long  prec;
+  mpf_t  got, u, v;
+  int    i;
+
+  mpf_init (got);
+  mpf_init (u);
+  mpf_init (v);
+
+  /* separate */
+  for (i = 0; i < 100; i++)
+    {
+      /* got precision */
+      prec = min_prec + gmp_urandomm_ui (rands, 15L);
+      refmpf_set_prec_limbs (got, prec);
+
+      /* u */
+      prec = min_prec + gmp_urandomm_ui (rands, 15L);
+      refmpf_set_prec_limbs (u, prec);
+      do {
+        mpf_random2 (u, PREC(u), (mp_exp_t) 20);
+      } while (SIZ(u) == 0);
+      if (gmp_urandomb_ui (rands, 1L))
+        mpf_neg (u, u);
+
+      /* v */
+      prec = min_prec + gmp_urandomm_ui (rands, 15L);
+      refmpf_set_prec_limbs (v, prec);
+      do {
+        mpf_random2 (v, PREC(v), (mp_exp_t) 20);
+      } while (SIZ(v) == 0);
+      if (gmp_urandomb_ui (rands, 1L))
+        mpf_neg (v, v);
+
+      switch (i % 3) {
+      case 0:
+        mpf_div (got, u, v);
+        check_one ("separate", got, u, v);
+        break;
+      case 1:
+        prec = refmpf_set_overlap (got, u);
+        mpf_div (got, got, v);
+        check_one ("dst == u", got, u, v);
+        mpf_set_prec_raw (got, prec);
+        break;
+      case 2:
+        prec = refmpf_set_overlap (got, v);
+        mpf_div (got, u, got);
+        check_one ("dst == v", got, u, v);
+        mpf_set_prec_raw (got, prec);
+        break;
+      }
+    }
+
+  mpf_clear (got);
+  mpf_clear (u);
+  mpf_clear (v);
+}
+
+/* Exercise calls mpf(x,x,x) */
+void
+check_reuse_three (void)
+{
+  unsigned long  min_prec = __GMPF_BITS_TO_PREC (1);
+  gmp_randstate_ptr  rands = RANDS;
+  unsigned long  result_prec, input_prec, set_prec;
+  mpf_t  got;
+  int    i;
+
+  mpf_init (got);
+
+  for (i = 0; i < 8; i++)
+    {
+      result_prec = min_prec + gmp_urandomm_ui (rands, 15L);
+      input_prec = min_prec + gmp_urandomm_ui (rands, 15L);
+
+      set_prec = MAX (result_prec, input_prec);
+      refmpf_set_prec_limbs (got, set_prec);
+
+      /* input, non-zero, possibly negative */
+      PREC(got) = input_prec;
+      do {
+        mpf_random2 (got, input_prec, (mp_exp_t) 20);
+      } while (SIZ(got) == 0);
+      if (gmp_urandomb_ui (rands, 1L))
+        mpf_neg (got, got);
+
+      PREC(got) = result_prec;
+
+      mpf_div (got, got, got);
+
+      /* expect exactly 1.0 always */
+      ASSERT_ALWAYS (mpf_cmp_ui (got, 1L) == 0);
+
+      PREC(got) = set_prec;
+    }
+
+  mpf_clear (got);
+}
+
+void
+check_various (void)
+{
+  mpf_t got, u, v;
+
+  mpf_init (got);
+  mpf_init (u);
+  mpf_init (v);
+
+  /* 100/4 == 25 */
+  mpf_set_prec (got, 20L);
+  mpf_set_ui (u, 100L);
+  mpf_set_ui (v, 4L);
+  mpf_div (got, u, v);
+  MPF_CHECK_FORMAT (got);
+  ASSERT_ALWAYS (mpf_cmp_ui (got, 25L) == 0);
+
+  /* 1/(2^n+1), a case where truncating the divisor would be wrong */
+  mpf_set_prec (got, 500L);
+  mpf_set_prec (v, 900L);
+  mpf_set_ui (v, 1L);
+  mpf_mul_2exp (v, v, 800L);
+  mpf_add_ui (v, v, 1L);
+  mpf_div (got, u, v);
+  check_one ("1/2^n+1, separate", got, u, v);
+
+  mpf_clear (got);
+  mpf_clear (u);
+  mpf_clear (v);
+}
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_various ();
+  check_rand ();
+  check_reuse_three ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpf/t-dm2exp.c b/third_party/gmp/tests/mpf/t-dm2exp.c
new file mode 100644
index 0000000..d17c9fa
--- /dev/null
+++ b/third_party/gmp/tests/mpf/t-dm2exp.c
@@ -0,0 +1,118 @@
+/* Test mpf_div, mpf_div_2exp, mpf_mul_2exp.
+
+Copyright 1996, 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#ifndef SIZE
+#define SIZE 16
+#endif
+
+int
+main (int argc, char **argv)
+{
+  int reps = 100000;
+  int i;
+  mpf_t u, v, w1, w2, w3;
+  mp_size_t bprec = 100;
+  mpf_t rerr, limit_rerr;
+  mp_size_t un;
+  mp_exp_t ue;
+
+  tests_start ();
+
+  if (argc > 1)
+    {
+      reps = strtol (argv[1], 0, 0);
+      if (argc > 2)
+	bprec = strtol (argv[2], 0, 0);
+    }
+
+  mpf_set_default_prec (bprec);
+
+  mpf_init (rerr);
+  mpf_init (limit_rerr);
+
+  mpf_init (u);
+  mpf_init (v);
+  mpf_init (w1);
+  mpf_init (w2);
+  mpf_init (w3);
+
+  for (i = 0; i < reps; i++)
+    {
+      unsigned long int res_prec;
+      unsigned long int pow2;
+
+      res_prec = urandom () % (bprec + 100);
+      mpf_set_prec (w1, res_prec);
+      mpf_set_prec (w2, res_prec);
+      mpf_set_prec (w3, res_prec);
+
+      mpf_set_ui (limit_rerr, 1);
+      mpf_div_2exp (limit_rerr, limit_rerr, res_prec);
+
+      pow2 = urandom () % 0x10000;
+      mpf_set_ui (v, 1);
+      mpf_mul_2exp (v, v, pow2);
+
+      un = urandom () % (2 * SIZE) - SIZE;
+      ue = urandom () % SIZE;
+      mpf_random2 (u, un, ue);
+
+      mpf_div_2exp (w1, u, pow2);
+      mpf_div (w2, u, v);
+      mpf_reldiff (rerr, w1, w2);
+      if (mpf_cmp (rerr, limit_rerr) > 0)
+	{
+	  printf ("ERROR in mpf_div or mpf_div_2exp after %d tests\n", i);
+	  printf ("   u = "); mpf_dump (u);
+	  printf ("   v = "); mpf_dump (v);
+	  printf ("  w1 = "); mpf_dump (w1);
+	  printf ("  w2 = "); mpf_dump (w2);
+	  abort ();
+	}
+      mpf_mul_2exp (w3, w1, pow2);
+      mpf_reldiff (rerr, u, w3);
+      if (mpf_cmp (rerr, limit_rerr) > 0)
+	{
+	  printf ("ERROR in mpf_mul_2exp after %d tests\n", i);
+	  printf ("   u = "); mpf_dump (u);
+	  printf ("   v = "); mpf_dump (v);
+	  printf ("  w1 = "); mpf_dump (w1);
+	  printf ("  w3 = "); mpf_dump (w3);
+	  abort ();
+	}
+    }
+
+  mpf_clear (rerr);
+  mpf_clear (limit_rerr);
+
+  mpf_clear (u);
+  mpf_clear (v);
+  mpf_clear (w1);
+  mpf_clear (w2);
+  mpf_clear (w3);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpf/t-eq.c b/third_party/gmp/tests/mpf/t-eq.c
new file mode 100644
index 0000000..7b80b02
--- /dev/null
+++ b/third_party/gmp/tests/mpf/t-eq.c
@@ -0,0 +1,217 @@
+/* Test mpf_eq.
+
+Copyright 2009, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#define SZ (2 * sizeof(mp_limb_t))
+
+void insert_random_low_zero_limbs (mpf_t, gmp_randstate_ptr);
+void dump_abort (mpf_t, mpf_t, int, int, int, int, int, long);
+void hexdump (mpf_t);
+
+void
+check_data (void)
+{
+  static const struct
+  {
+    struct {
+      int        exp, size;
+      mp_limb_t  d[10];
+    } x, y;
+    mp_bitcnt_t bits;
+    int want;
+
+  } data[] = {
+    { { 0, 0, { 0 } },             { 0, 0, { 0 } },    0, 1 },
+
+    { { 0, 1, { 7 } },             { 0, 1, { 7 } },    0, 1 },
+    { { 0, 1, { 7 } },             { 0, 1, { 7 } },   17, 1 },
+    { { 0, 1, { 7 } },             { 0, 1, { 7 } }, 4711, 1 },
+
+    { { 0, 1, { 7 } },             { 0, 1, { 6 } },    0, 1 },
+    { { 0, 1, { 7 } },             { 0, 1, { 6 } },    2, 1 },
+    { { 0, 1, { 7 } },             { 0, 1, { 6 } },    3, 0 },
+
+    { { 0, 0, { 0 } },             { 0, 1, { 1 } },    0, 0 },
+    { { 0, 1, { 1 } },             { 0,-1 ,{ 1 } },    0, 0 },
+    { { 1, 1, { 1 } },             { 0, 1, { 1 } },    0, 0 },
+
+    { { 0, 1, { 8 } },             { 0, 1, { 4 } },    0, 0 },
+
+    { { 0, 2, { 0, 3 } },          { 0, 1, { 3 } }, 1000, 1 },
+  };
+
+  mpf_t  x, y;
+  int got, got_swapped;
+  int i;
+  mp_trace_base = 16;
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      PTR(x) = (mp_ptr) data[i].x.d;
+      SIZ(x) = data[i].x.size;
+      EXP(x) = data[i].x.exp;
+      PREC(x) = numberof (data[i].x.d);
+      MPF_CHECK_FORMAT (x);
+
+      PTR(y) = (mp_ptr) data[i].y.d;
+      SIZ(y) = data[i].y.size;
+      EXP(y) = data[i].y.exp;
+      PREC(y) = numberof (data[i].y.d);
+      MPF_CHECK_FORMAT (y);
+
+      got         = mpf_eq (x, y, data[i].bits);
+      got_swapped = mpf_eq (y, x, data[i].bits);
+
+      if (got != got_swapped || got != data[i].want)
+	{
+	  printf ("check_data() wrong result at data[%d]\n", i);
+	  mpf_trace ("x   ", x);
+	  mpf_trace ("y   ", y);
+	  printf ("got         %d\n", got);
+	  printf ("got_swapped %d\n", got_swapped);
+	  printf ("want        %d\n", data[i].want);
+	  abort ();
+        }
+    }
+}
+
+void
+check_random (long reps)
+{
+  unsigned long test;
+  gmp_randstate_ptr rands = RANDS;
+  mpf_t a, b, x;
+  mpz_t ds;
+  int hibits, lshift1, lshift2;
+  int xtra;
+
+#define HIBITS 10
+#define LSHIFT1 10
+#define LSHIFT2 10
+
+  mpf_set_default_prec ((1 << HIBITS) + (1 << LSHIFT1) + (1 << LSHIFT2));
+
+  mpz_init (ds);
+  mpf_inits (a, b, x, NULL);
+
+  for (test = 0; test < reps; test++)
+    {
+      mpz_urandomb (ds, rands, HIBITS);
+      hibits = mpz_get_ui (ds) + 1;
+      mpz_urandomb (ds, rands, hibits);
+      mpz_setbit (ds, hibits  - 1);	/* make sure msb is set */
+      mpf_set_z (a, ds);
+      mpf_set_z (b, ds);
+
+      mpz_urandomb (ds, rands, LSHIFT1);
+      lshift1 = mpz_get_ui (ds);
+      mpf_mul_2exp (a, a, lshift1 + 1);
+      mpf_mul_2exp (b, b, lshift1 + 1);
+      mpf_add_ui (a, a, 1);	/* make a one-bit difference */
+
+      mpz_urandomb (ds, rands, LSHIFT2);
+      lshift2 = mpz_get_ui (ds);
+      mpf_mul_2exp (a, a, lshift2);
+      mpf_mul_2exp (b, b, lshift2);
+      mpz_urandomb (ds, rands, lshift2);
+      mpf_set_z (x, ds);
+      mpf_add (a, a, x);
+      mpf_add (b, b, x);
+
+      insert_random_low_zero_limbs (a, rands);
+      insert_random_low_zero_limbs (b, rands);
+
+      if (mpf_eq (a, b, lshift1 + hibits) == 0 ||
+	  mpf_eq (b, a, lshift1 + hibits) == 0)
+	{
+	  dump_abort (a, b, lshift1 + hibits, lshift1, lshift2, hibits, 1, test);
+	}
+      for (xtra = 1; xtra < 100; xtra++)
+	if (mpf_eq (a, b, lshift1 + hibits + xtra) != 0 ||
+	    mpf_eq (b, a, lshift1 + hibits + xtra) != 0)
+	  {
+	    dump_abort (a, b, lshift1 + hibits + xtra, lshift1, lshift2, hibits, 0, test);
+	  }
+    }
+
+  mpf_clears (a, b, x, NULL);
+  mpz_clear (ds);
+}
+
+void
+insert_random_low_zero_limbs (mpf_t x, gmp_randstate_ptr rands)
+{
+  mp_size_t max = PREC(x) - SIZ(x);
+  mp_size_t s;
+  mpz_t ds; mpz_init (ds);
+  mpz_urandomb (ds, rands, 32);
+  s = mpz_get_ui (ds) % (max + 1);
+  MPN_COPY_DECR (PTR(x) + s, PTR(x), SIZ(x));
+  MPN_ZERO (PTR(x), s);
+  SIZ(x) += s;
+  mpz_clear (ds);
+}
+
+void
+dump_abort (mpf_t a, mpf_t b, int cmp_prec, int lshift1, int lshift2, int hibits, int want, long test)
+{
+  printf ("ERROR in test %ld\n", test);
+  printf ("want %d got %d from mpf_eq\n", want, 1-want);
+  printf ("cmp_prec = %d\n", cmp_prec);
+  printf ("lshift1 = %d\n", lshift1);
+  printf ("lshift2 = %d\n", lshift2);
+  printf ("hibits = %d\n", hibits);
+  hexdump (a); puts ("");
+  hexdump (b); puts ("");
+  abort ();
+}
+
+void
+hexdump (mpf_t x)
+{
+  mp_size_t i;
+  for (i = ABSIZ(x) - 1; i >= 0; i--)
+    {
+      gmp_printf ("%0*MX", SZ, PTR(x)[i]);
+      if (i != 0)
+	printf (" ");
+    }
+}
+
+int
+main (int argc, char *argv[])
+{
+  long reps = 10000;
+
+  if (argc == 2)
+    reps = strtol (argv[1], 0, 0);
+
+  tests_start ();
+
+  check_data ();
+  check_random (reps);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpf/t-fits.c b/third_party/gmp/tests/mpf/t-fits.c
new file mode 100644
index 0000000..937e4e6
--- /dev/null
+++ b/third_party/gmp/tests/mpf/t-fits.c
@@ -0,0 +1,327 @@
+/* Test mpf_fits_*_p
+
+Copyright 2001, 2002, 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+/* Nothing sophisticated here, just exercise mpf_fits_*_p on a small amount
+   of data. */
+
+#define EXPECT_S(fun,name,answer)                                        \
+  got = fun (f);                                                         \
+  if (got != answer)                                                     \
+    {                                                                    \
+      printf ("%s (%s) got %d want %d\n", name, expr, got, answer);      \
+      printf (" f size %d exp %ld\n", SIZ(f), EXP(f));                   \
+      printf (" f dec "); mpf_out_str (stdout, 10, 0, f); printf ("\n"); \
+      printf (" f hex "); mpf_out_str (stdout, 16, 0, f); printf ("\n"); \
+      error = 1;                                                         \
+    }
+
+#define EXPECT(fun,answer)  EXPECT_S(fun,#fun,answer)
+
+int
+main (void)
+{
+  mpf_t       f, f0p5;
+  int         got;
+  const char  *expr;
+  int         error = 0;
+
+  tests_start ();
+  mpf_init2 (f, 200L);
+  mpf_init2 (f0p5, 200L);
+
+  /* 0.5 */
+  mpf_set_ui (f0p5, 1L);
+  mpf_div_2exp (f0p5, f0p5, 1L);
+
+  mpf_set_ui (f, 0L);
+  expr = "0";
+  EXPECT (mpf_fits_ulong_p, 1);
+  EXPECT (mpf_fits_uint_p, 1);
+  EXPECT (mpf_fits_ushort_p, 1);
+  EXPECT (mpf_fits_slong_p, 1);
+  EXPECT (mpf_fits_sint_p, 1);
+  EXPECT (mpf_fits_sshort_p, 1);
+
+  mpf_set_ui (f, 1L);
+  expr = "1";
+  EXPECT (mpf_fits_ulong_p, 1);
+  EXPECT (mpf_fits_uint_p, 1);
+  EXPECT (mpf_fits_ushort_p, 1);
+  EXPECT (mpf_fits_slong_p, 1);
+  EXPECT (mpf_fits_sint_p, 1);
+  EXPECT (mpf_fits_sshort_p, 1);
+
+  mpf_set_si (f, -1L);
+  expr = "-1";
+  EXPECT (mpf_fits_ulong_p, 0);
+  EXPECT (mpf_fits_uint_p, 0);
+  EXPECT (mpf_fits_ushort_p, 0);
+  EXPECT (mpf_fits_slong_p, 1);
+  EXPECT (mpf_fits_sint_p, 1);
+  EXPECT (mpf_fits_sshort_p, 1);
+
+
+  mpf_set_ui (f, (unsigned long) USHRT_MAX);
+  expr = "USHRT_MAX";
+  EXPECT (mpf_fits_ulong_p, 1);
+  EXPECT (mpf_fits_uint_p, 1);
+  EXPECT (mpf_fits_ushort_p, 1);
+
+  mpf_set_ui (f, (unsigned long) USHRT_MAX);
+  mpf_add (f, f, f0p5);
+  expr = "USHRT_MAX + 0.5";
+  EXPECT (mpf_fits_ulong_p, 1);
+  EXPECT (mpf_fits_uint_p, 1);
+  EXPECT (mpf_fits_ushort_p, 1);
+
+  mpf_set_ui (f, (unsigned long) USHRT_MAX);
+  mpf_add_ui (f, f, 1L);
+  expr = "USHRT_MAX + 1";
+  EXPECT (mpf_fits_ushort_p, 0);
+
+
+  mpf_set_ui (f, (unsigned long) UINT_MAX);
+  expr = "UINT_MAX";
+  EXPECT (mpf_fits_ulong_p, 1);
+  EXPECT (mpf_fits_uint_p, 1);
+
+  mpf_set_ui (f, (unsigned long) UINT_MAX);
+  mpf_add (f, f, f0p5);
+  expr = "UINT_MAX + 0.5";
+  EXPECT (mpf_fits_ulong_p, 1);
+  EXPECT (mpf_fits_uint_p, 1);
+
+  mpf_set_ui (f, (unsigned long) UINT_MAX);
+  mpf_add_ui (f, f, 1L);
+  expr = "UINT_MAX + 1";
+  EXPECT (mpf_fits_uint_p, 0);
+
+
+  mpf_set_ui (f, ULONG_MAX);
+  expr = "ULONG_MAX";
+  EXPECT (mpf_fits_ulong_p, 1);
+
+  mpf_set_ui (f, ULONG_MAX);
+  mpf_add (f, f, f0p5);
+  expr = "ULONG_MAX + 0.5";
+  EXPECT (mpf_fits_ulong_p, 1);
+
+  mpf_set_ui (f, ULONG_MAX);
+  mpf_add_ui (f, f, 1L);
+  expr = "ULONG_MAX + 1";
+  EXPECT (mpf_fits_ulong_p, 0);
+
+
+  mpf_set_si (f, (long) SHRT_MAX);
+  expr = "SHRT_MAX";
+  EXPECT (mpf_fits_slong_p, 1);
+  EXPECT (mpf_fits_sint_p, 1);
+  EXPECT (mpf_fits_sshort_p, 1);
+
+  mpf_set_si (f, (long) SHRT_MAX);
+  expr = "SHRT_MAX + 0.5";
+  mpf_add (f, f, f0p5);
+  EXPECT (mpf_fits_slong_p, 1);
+  EXPECT (mpf_fits_sint_p, 1);
+  EXPECT (mpf_fits_sshort_p, 1);
+
+  mpf_set_si (f, (long) SHRT_MAX);
+  mpf_add_ui (f, f, 1L);
+  expr = "SHRT_MAX + 1";
+  EXPECT (mpf_fits_sshort_p, 0);
+
+
+  mpf_set_si (f, (long) INT_MAX);
+  expr = "INT_MAX";
+  EXPECT (mpf_fits_slong_p, 1);
+  EXPECT (mpf_fits_sint_p, 1);
+
+  mpf_set_si (f, (long) INT_MAX);
+  mpf_add (f, f, f0p5);
+  expr = "INT_MAX + 0.5";
+  EXPECT (mpf_fits_slong_p, 1);
+  EXPECT (mpf_fits_sint_p, 1);
+
+  mpf_set_si (f, (long) INT_MAX);
+  mpf_add_ui (f, f, 1L);
+  expr = "INT_MAX + 1";
+  EXPECT (mpf_fits_sint_p, 0);
+
+
+  mpf_set_si (f, LONG_MAX);
+  expr = "LONG_MAX";
+  EXPECT (mpf_fits_slong_p, 1);
+
+  mpf_set_si (f, LONG_MAX);
+  mpf_add (f, f, f0p5);
+  expr = "LONG_MAX + 0.5";
+  EXPECT (mpf_fits_slong_p, 1);
+
+  mpf_set_si (f, LONG_MAX);
+  mpf_add_ui (f, f, 1L);
+  expr = "LONG_MAX + 1";
+  EXPECT (mpf_fits_slong_p, 0);
+
+
+  mpf_set_si (f, (long) SHRT_MIN);
+  expr = "SHRT_MIN";
+  EXPECT (mpf_fits_slong_p, 1);
+  EXPECT (mpf_fits_sint_p, 1);
+  EXPECT (mpf_fits_sshort_p, 1);
+
+  mpf_set_si (f, (long) SHRT_MIN);
+  mpf_sub (f, f, f0p5);
+  expr = "SHRT_MIN - 0.5";
+  EXPECT (mpf_fits_slong_p, 1);
+  EXPECT (mpf_fits_sint_p, 1);
+  EXPECT (mpf_fits_sshort_p, 1);
+
+  mpf_set_si (f, (long) SHRT_MIN);
+  mpf_sub_ui (f, f, 1L);
+  expr = "SHRT_MIN - 1";
+  EXPECT (mpf_fits_sshort_p, 0);
+
+
+  mpf_set_si (f, (long) INT_MIN);
+  expr = "INT_MIN";
+  EXPECT (mpf_fits_slong_p, 1);
+  EXPECT (mpf_fits_sint_p, 1);
+
+  mpf_set_si (f, (long) INT_MIN);
+  mpf_sub (f, f, f0p5);
+  expr = "INT_MIN - 0.5";
+  EXPECT (mpf_fits_slong_p, 1);
+  EXPECT (mpf_fits_sint_p, 1);
+
+  mpf_set_si (f, (long) INT_MIN);
+  mpf_sub_ui (f, f, 1L);
+  expr = "INT_MIN - 1";
+  EXPECT (mpf_fits_sint_p, 0);
+
+
+  mpf_set_si (f, LONG_MIN);
+  expr = "LONG_MIN";
+  EXPECT (mpf_fits_slong_p, 1);
+
+  mpf_set_si (f, LONG_MIN);
+  mpf_sub (f, f, f0p5);
+  expr = "LONG_MIN - 0.5";
+  EXPECT (mpf_fits_slong_p, 1);
+
+  mpf_set_si (f, LONG_MIN);
+  mpf_sub_ui (f, f, 1L);
+  expr = "LONG_MIN - 1";
+  EXPECT (mpf_fits_slong_p, 0);
+
+
+  mpf_set_str_or_abort (f, "0.5", 10);
+  expr = "0.5";
+  EXPECT (mpf_fits_ulong_p, 1);
+  EXPECT (mpf_fits_uint_p, 1);
+  EXPECT (mpf_fits_ushort_p, 1);
+  EXPECT (mpf_fits_slong_p, 1);
+  EXPECT (mpf_fits_sint_p, 1);
+  EXPECT (mpf_fits_sshort_p, 1);
+
+  mpf_set_str_or_abort (f, "-0.5", 10);
+  expr = "-0.5";
+  EXPECT (mpf_fits_ulong_p, 1);
+  EXPECT (mpf_fits_uint_p, 1);
+  EXPECT (mpf_fits_ushort_p, 1);
+  EXPECT (mpf_fits_slong_p, 1);
+  EXPECT (mpf_fits_sint_p, 1);
+  EXPECT (mpf_fits_sshort_p, 1);
+
+  mpf_set_str_or_abort (f, "-1.5", 10);
+  expr = "-1.5";
+  EXPECT (mpf_fits_ulong_p, 0);
+  EXPECT (mpf_fits_uint_p, 0);
+  EXPECT (mpf_fits_ushort_p, 0);
+  EXPECT (mpf_fits_slong_p, 1);
+  EXPECT (mpf_fits_sint_p, 1);
+  EXPECT (mpf_fits_sshort_p, 1);
+
+
+  mpf_set_str_or_abort (f, "1.000000000000000000000000000000000001", 16);
+  expr = "1.000000000000000000000000000000000001 base 16";
+  EXPECT (mpf_fits_ulong_p, 1);
+  EXPECT (mpf_fits_uint_p, 1);
+  EXPECT (mpf_fits_ushort_p, 1);
+  EXPECT (mpf_fits_slong_p, 1);
+  EXPECT (mpf_fits_sint_p, 1);
+  EXPECT (mpf_fits_sshort_p, 1);
+
+  mpf_set_str_or_abort (f, "1@1000", 16);
+  expr = "1@1000 base 16";
+  EXPECT (mpf_fits_ulong_p, 0);
+  EXPECT (mpf_fits_uint_p, 0);
+  EXPECT (mpf_fits_ushort_p, 0);
+  EXPECT (mpf_fits_slong_p, 0);
+  EXPECT (mpf_fits_sint_p, 0);
+  EXPECT (mpf_fits_sshort_p, 0);
+
+
+  mpf_set_ui (f, 1L);
+  mpf_mul_2exp (f, f, BITS_PER_ULONG + 1);
+  mpf_sub_ui (f, f, 1L);
+  expr = "2^(BITS_PER_ULONG+1) - 1";
+  EXPECT (mpf_fits_ulong_p, 0);
+  EXPECT (mpf_fits_uint_p, 0);
+  EXPECT (mpf_fits_ushort_p, 0);
+  EXPECT (mpf_fits_slong_p, 0);
+  EXPECT (mpf_fits_sint_p, 0);
+  EXPECT (mpf_fits_sshort_p, 0);
+
+  mpf_set_ui (f, 1L);
+  mpf_mul_2exp (f, f, BITS_PER_ULONG + 1);
+  mpf_ui_sub (f, 1L, f);
+  expr = "- (2^(BITS_PER_ULONG+1) - 1)";
+  EXPECT (mpf_fits_ulong_p, 0);
+  EXPECT (mpf_fits_uint_p, 0);
+  EXPECT (mpf_fits_ushort_p, 0);
+  EXPECT (mpf_fits_slong_p, 0);
+  EXPECT (mpf_fits_sint_p, 0);
+  EXPECT (mpf_fits_sshort_p, 0);
+
+  mpf_set_ui (f, 1L);
+  mpf_mul_2exp (f, f, BITS_PER_ULONG + 5);
+  mpf_sub_ui (f, f, 1L);
+  expr = "2^(BITS_PER_ULONG+5) - 1";
+  EXPECT (mpf_fits_ulong_p, 0);
+  EXPECT (mpf_fits_uint_p, 0);
+  EXPECT (mpf_fits_ushort_p, 0);
+  EXPECT (mpf_fits_slong_p, 0);
+  EXPECT (mpf_fits_sint_p, 0);
+  EXPECT (mpf_fits_sshort_p, 0);
+
+
+  if (error)
+    abort ();
+
+  mpf_clear (f);
+  mpf_clear (f0p5);
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpf/t-get_d.c b/third_party/gmp/tests/mpf/t-get_d.c
new file mode 100644
index 0000000..4e4c741
--- /dev/null
+++ b/third_party/gmp/tests/mpf/t-get_d.c
@@ -0,0 +1,106 @@
+/* Test mpf_get_d and mpf_set_d.
+
+Copyright 1996, 1999-2001, 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+#if defined (__vax) || defined (__vax__)
+#define LOW_BOUND 1e-38
+#define HIGH_BOUND 8e37
+#endif
+
+#if defined (_CRAY) && ! defined (_CRAYIEEE)
+/* The range varies mysteriously between Cray version.  On an SV1,
+   the range seem to be 1e-600..1e603, but a cfp (non-ieee) T90
+   has a much smaller range of 1e-240..1e240.  */
+#define LOW_BOUND 1e-240
+#define HIGH_BOUND 1e240
+#endif
+
+#if ! defined (LOW_BOUND)
+#define LOW_BOUND 1e-300
+#define HIGH_BOUND 1e300
+#endif
+
+void
+test_denorms (int prc)
+{
+#ifdef _GMP_IEEE_FLOATS
+  double d1, d2;
+  mpf_t f;
+  int i;
+
+  mpf_set_default_prec (prc);
+
+  mpf_init (f);
+
+  d1 = 1.9;
+  for (i = 0; i < 820; i++)
+    {
+      mpf_set_d (f, d1);
+      d2 = mpf_get_d (f);
+      if (d1 != d2)
+        abort ();
+      d1 *= 0.4;
+    }
+
+  mpf_clear (f);
+#endif
+}
+
+int
+main (int argc, char **argv)
+{
+  double d, e, r;
+  mpf_t u, v;
+
+  tests_start ();
+  mpf_init (u);
+  mpf_init (v);
+
+  mpf_set_d (u, LOW_BOUND);
+  for (d = 2.0 * LOW_BOUND; d < HIGH_BOUND; d *= 1.01)
+    {
+      mpf_set_d (v, d);
+      if (mpf_cmp (u, v) >= 0)
+	abort ();
+      e = mpf_get_d (v);
+      r = e/d;
+      if (r < 0.99999999999999 || r > 1.00000000000001)
+	{
+	  fprintf (stderr, "should be one ulp from 1: %.16f\n", r);
+	  abort ();
+	}
+      mpf_set (u, v);
+    }
+
+  mpf_clear (u);
+  mpf_clear (v);
+
+  test_denorms (10);
+  test_denorms (32);
+  test_denorms (64);
+  test_denorms (100);
+  test_denorms (200);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpf/t-get_d_2exp.c b/third_party/gmp/tests/mpf/t-get_d_2exp.c
new file mode 100644
index 0000000..6868bf3
--- /dev/null
+++ b/third_party/gmp/tests/mpf/t-get_d_2exp.c
@@ -0,0 +1,126 @@
+/* Test mpf_get_d_2exp.
+
+Copyright 2002, 2003, 2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+static void
+check_data (void)
+{
+  mpf_t   f;
+  double  got, want;
+  long    got_exp;
+  long    exp;
+  struct {
+    int base;
+    int shift;
+  } data[] = {
+   {-1, 1}, {-3, 2}, {-5, 3}, {-7, 3}, { 1, 1}, { 3, 2}, { 5, 3}, { 7, 3}
+  };
+
+  mpf_init2 (f, 3);
+
+  for (exp = -513; exp <= 513; exp++)
+    {
+      size_t i;
+      for (i = 0; i < numberof (data); i++)
+	{
+	  want = (double) data[i].base / (1 << data[i].shift);
+	  mpf_set_d (f, want);
+
+	  if (exp >= 0)
+	    mpf_mul_2exp (f, f, exp);
+	  else
+	    mpf_div_2exp (f, f, -exp);
+
+	  got = mpf_get_d_2exp (&got_exp, f);
+	  if (got != want || got_exp != exp)
+	    {
+	      printf    ("mpf_get_d_2exp wrong on 2**%ld\n", exp);
+	      mpf_trace ("   f    ", f);
+	      d_trace   ("   want ", want);
+	      d_trace   ("   got  ", got);
+	      printf    ("   want exp %ld\n", exp);
+	      printf    ("   got exp  %ld\n", got_exp);
+	      abort();
+	    }
+	}
+    }
+  mpf_clear (f);
+}
+
+/* Check that hardware rounding doesn't make mpf_get_d_2exp return a value
+   outside its defined range. */
+static void
+check_round (void)
+{
+  static const unsigned long data[] = { 1, 32, 53, 54, 64, 128, 256, 512 };
+  mpf_t   f;
+  double  got;
+  long    got_exp;
+  int     i, rnd_mode, old_rnd_mode;
+
+  mpf_init2 (f, 1024L);
+  old_rnd_mode = tests_hardware_getround ();
+
+  for (rnd_mode = 0; rnd_mode < 4; rnd_mode++)
+    {
+      tests_hardware_setround (rnd_mode);
+
+      for (i = 0; i < numberof (data); i++)
+        {
+          mpf_set_ui (f, 1L);
+          mpf_mul_2exp (f, f, data[i]);
+          mpf_sub_ui (f, f, 1L);
+
+          got = mpf_get_d_2exp (&got_exp, f);
+          if (got < 0.5 || got >= 1.0)
+            {
+              printf    ("mpf_get_d_2exp bad on 2**%lu-1\n", data[i]);
+              printf    ("result out of range, expect 0.5 <= got < 1.0\n");
+              printf    ("   rnd_mode = %d\n", rnd_mode);
+              printf    ("   data[i]  = %lu\n", data[i]);
+              mpf_trace ("   f    ", f);
+              d_trace   ("   got  ", got);
+              printf    ("   got exp  %ld\n", got_exp);
+              abort();
+            }
+        }
+    }
+
+  mpf_clear (f);
+  tests_hardware_setround (old_rnd_mode);
+}
+
+
+int
+main (void)
+{
+  tests_start ();
+  mp_trace_base = 16;
+
+  check_data ();
+  check_round ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpf/t-get_si.c b/third_party/gmp/tests/mpf/t-get_si.c
new file mode 100644
index 0000000..5510b04
--- /dev/null
+++ b/third_party/gmp/tests/mpf/t-get_si.c
@@ -0,0 +1,222 @@
+/* Exercise mpz_get_si.
+
+Copyright 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_data (void)
+{
+  static const struct {
+    int         base;
+    const char  *f;
+    long        want;
+  } data[] = {
+    { 10, "0",      0L },
+    { 10, "1",      1L },
+    { 10, "-1",     -1L },
+    { 10, "2",      2L },
+    { 10, "-2",     -2L },
+    { 10, "12345",  12345L },
+    { 10, "-12345", -12345L },
+
+    /* fraction bits ignored */
+    { 10, "0.5",    0L },
+    { 10, "-0.5",   0L },
+    { 10, "1.1",    1L },
+    { 10, "-1.1",   -1L },
+    { 10, "1.9",    1L },
+    { 10, "-1.9",   -1L },
+    { 16, "1.000000000000000000000000000000000000000000000000001", 1L },
+    { 16, "-1.000000000000000000000000000000000000000000000000001", -1L },
+
+    /* low bits extracted (this is undocumented) */
+    { 16, "1000000000000000000000000000000000000000000000000001", 1L },
+    { 16, "-1000000000000000000000000000000000000000000000000001", -1L },
+  };
+
+  int    i;
+  mpf_t  f;
+  long   got;
+
+  mpf_init2 (f, 2000L);
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpf_set_str_or_abort (f, data[i].f, data[i].base);
+
+      got = mpf_get_si (f);
+      if (got != data[i].want)
+	{
+	  printf ("mpf_get_si wrong at data[%d]\n", i);
+	  printf ("   f     \"%s\"\n", data[i].f);
+	  printf ("     dec "); mpf_out_str (stdout, 10, 0, f); printf ("\n");
+	  printf ("     hex "); mpf_out_str (stdout, 16, 0, f); printf ("\n");
+	  printf ("     size %ld\n", (long) SIZ(f));
+	  printf ("     exp  %ld\n", (long) EXP(f));
+	  printf ("   got   %ld (0x%lX)\n", got, got);
+	  printf ("   want  %ld (0x%lX)\n", data[i].want, data[i].want);
+	  abort();
+	}
+    }
+  mpf_clear (f);
+}
+
+
+void
+check_max (void)
+{
+  mpf_t  f;
+  long   want;
+  long   got;
+
+  mpf_init2 (f, 200L);
+
+#define CHECK_MAX(name)                                         \
+  if (got != want)                                              \
+    {                                                           \
+      printf ("mpf_get_si wrong on %s\n", name);                \
+      printf ("   f    ");                                      \
+      mpf_out_str (stdout, 10, 0, f); printf (", hex ");        \
+      mpf_out_str (stdout, 16, 0, f); printf ("\n");            \
+      printf ("   got  %ld, hex %lX\n", got, got);              \
+      printf ("   want %ld, hex %lX\n", want, want);            \
+      abort();                                                  \
+    }
+
+  want = LONG_MAX;
+  mpf_set_si (f, want);
+  got = mpf_get_si (f);
+  CHECK_MAX ("LONG_MAX");
+
+  want = LONG_MIN;
+  mpf_set_si (f, want);
+  got = mpf_get_si (f);
+  CHECK_MAX ("LONG_MIN");
+
+  mpf_clear (f);
+}
+
+
+void
+check_limbdata (void)
+{
+#define M  GMP_NUMB_MAX
+
+  static const struct {
+    mp_exp_t       exp;
+    mp_size_t      size;
+    mp_limb_t      d[10];
+    unsigned long  want;
+
+  } data[] = {
+
+    /* in the comments here, a "_" indicates a digit (ie. limb) position not
+       included in the d data, and therefore zero */
+
+    { 0, 0, { 0 }, 0L },    /* 0 */
+
+    { 1,  1, { 1 }, 1L },   /* 1 */
+    { 1, -1, { 1 }, -1UL },  /* -1 */
+
+    { 0,  1, { 1 }, 0L },   /* .1 */
+    { 0, -1, { 1 }, 0L },   /* -.1 */
+
+    { -1,  1, { 1 }, 0L },  /* ._1 */
+    { -1, -1, { 1 }, 0L },  /* -._1 */
+
+    { -999,          1, { 1 }, 0L },   /* .___1 small */
+    { MP_EXP_T_MIN,  1, { 1 }, 0L },   /* .____1 very small */
+
+    { 999,          1, { 1 }, 0L },    /* 1____. big */
+    { MP_EXP_T_MAX, 1, { 1 }, 0L },    /* 1_____. very big */
+
+    { 1, 2, { 999, 2 }, 2L },                  /* 2.9 */
+    { 5, 8, { 7, 8, 9, 3, 0, 0, 0, 1 }, 3L },  /* 10003.987 */
+
+    { 2, 2, { M, M },    LONG_MAX }, /* FF. */
+    { 2, 2, { M, M, M }, LONG_MAX }, /* FF.F */
+    { 3, 3, { M, M, M }, LONG_MAX }, /* FFF. */
+
+#if GMP_NUMB_BITS >= BITS_PER_ULONG
+    /* normal case, numb bigger than long */
+    { 2,  1, { 1 },    0L },      /* 1_. */
+    { 2,  2, { 0, 1 }, 0L },      /* 10. */
+    { 2,  2, { 999, 1 }, 999L },  /* 19. */
+    { 3,  2, { 999, 1 }, 0L },    /* 19_. */
+
+#else
+    /* nails case, numb smaller than long */
+    { 2,  1, { 1 }, 1L << GMP_NUMB_BITS },  /* 1_. */
+    { 3,  1, { 1 }, 0L },                   /* 1__. */
+
+    { 2,  2, { 99, 1 },    99L + (1L << GMP_NUMB_BITS) },  /* 19. */
+    { 3,  2, { 1, 99 },    1L << GMP_NUMB_BITS },          /* 91_. */
+    { 3,  3, { 0, 1, 99 }, 1L << GMP_NUMB_BITS },          /* 910. */
+
+#endif
+  };
+
+  mpf_t          f;
+  unsigned long  got;
+  int            i;
+  mp_limb_t      buf[20 + numberof(data[i].d)];
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      refmpn_fill (buf, 10, CNST_LIMB(0xDEADBEEF));
+      refmpn_copy (buf+10, data[i].d, ABS(data[i].size));
+      refmpn_fill (buf+10+ABS(data[i].size), 10, CNST_LIMB(0xDEADBEEF));
+
+      PTR(f) = buf+10;
+      EXP(f) = data[i].exp;
+      SIZ(f) = data[i].size;
+      PREC(f) = numberof (data[i].d);
+      MPF_CHECK_FORMAT (f);
+
+      got = mpf_get_si (f);
+      if (got != data[i].want)
+	{
+	  printf    ("mpf_get_si wrong at limb data[%d]\n", i);
+	  mpf_trace ("  f", f);
+	  mpn_trace ("  d", data[i].d, data[i].size);
+	  printf    ("  size %ld\n", (long) data[i].size);
+	  printf    ("  exp %ld\n", (long) data[i].exp);
+	  printf    ("  got   %lu (0x%lX)\n", got, got);
+	  printf    ("  want  %lu (0x%lX)\n", data[i].want, data[i].want);
+	  abort();
+	}
+    }
+}
+
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_data ();
+  check_max ();
+  check_limbdata ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpf/t-get_ui.c b/third_party/gmp/tests/mpf/t-get_ui.c
new file mode 100644
index 0000000..6011b0f
--- /dev/null
+++ b/third_party/gmp/tests/mpf/t-get_ui.c
@@ -0,0 +1,127 @@
+/* Exercise mpf_get_ui.
+
+Copyright 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_limbdata (void)
+{
+#define M  GMP_NUMB_MAX
+
+  static const struct {
+    mp_exp_t       exp;
+    mp_size_t      size;
+    mp_limb_t      d[10];
+    unsigned long  want;
+
+  } data[] = {
+
+    /* in the comments here, a "_" indicates a digit (ie. limb) position not
+       included in the d data, and therefore zero */
+
+    { 0, 0, { 0 }, 0L },    /* 0 */
+
+    { 1,  1, { 1 }, 1L },   /* 1 */
+    { 1, -1, { 1 }, 1L },   /* -1 */
+
+    { 0,  1, { 1 }, 0L },   /* .1 */
+    { 0, -1, { 1 }, 0L },   /* -.1 */
+
+    { -1,  1, { 1 }, 0L },  /* ._1 */
+    { -1, -1, { 1 }, 0L },  /* -._1 */
+
+    { -999,          1, { 1 }, 0L },   /* .___1 small */
+    { MP_EXP_T_MIN,  1, { 1 }, 0L },   /* .____1 very small */
+
+    { 999,          1, { 1 }, 0L },    /* 1____. big */
+    { MP_EXP_T_MAX, 1, { 1 }, 0L },    /* 1_____. very big */
+
+    { 1, 2, { 999, 2 }, 2L },                  /* 2.9 */
+    { 5, 8, { 7, 8, 9, 3, 0, 0, 0, 1 }, 3L },  /* 10003.987 */
+
+    { 2, 2, { M, M },    ULONG_MAX }, /* FF. */
+    { 2, 2, { M, M, M }, ULONG_MAX }, /* FF.F */
+    { 3, 3, { M, M, M }, ULONG_MAX }, /* FFF. */
+
+#if GMP_NUMB_BITS >= BITS_PER_ULONG
+    /* normal case, numb bigger than long */
+    { 2,  1, { 1 },    0L },      /* 1_. */
+    { 2,  2, { 0, 1 }, 0L },      /* 10. */
+    { 2,  2, { 999, 1 }, 999L },  /* 19. */
+    { 3,  2, { 999, 1 }, 0L },    /* 19_. */
+
+#else
+    /* nails case, numb smaller than long */
+    { 2,  1, { 1 }, 1L << GMP_NUMB_BITS },  /* 1_. */
+    { 3,  1, { 1 }, 0L },                   /* 1__. */
+
+    { 2,  2, { 99, 1 },    99L + (1L << GMP_NUMB_BITS) },  /* 19. */
+    { 3,  2, { 1, 99 },    1L << GMP_NUMB_BITS },          /* 91_. */
+    { 3,  3, { 0, 1, 99 }, 1L << GMP_NUMB_BITS },          /* 910. */
+
+#endif
+  };
+
+  mpf_t          f;
+  unsigned long  got;
+  int            i;
+  mp_limb_t      buf[20 + numberof(data[i].d)];
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      refmpn_fill (buf, 10, CNST_LIMB(0xDEADBEEF));
+      refmpn_copy (buf+10, data[i].d, ABS(data[i].size));
+      refmpn_fill (buf+10+ABS(data[i].size), 10, CNST_LIMB(0xDEADBEEF));
+
+      PTR(f) = buf+10;
+      EXP(f) = data[i].exp;
+      SIZ(f) = data[i].size;
+      PREC(f) = numberof (data[i].d);
+      MPF_CHECK_FORMAT (f);
+
+      got = mpf_get_ui (f);
+      if (got != data[i].want)
+	{
+	  printf    ("mpf_get_ui wrong at limb data[%d]\n", i);
+	  mpf_trace ("  f", f);
+	  mpn_trace ("  d", data[i].d, data[i].size);
+	  printf    ("  size %ld\n", (long) data[i].size);
+	  printf    ("  exp %ld\n", (long) data[i].exp);
+	  printf    ("  got   %lu (0x%lX)\n", got, got);
+	  printf    ("  want  %lu (0x%lX)\n", data[i].want, data[i].want);
+	  abort();
+	}
+    }
+}
+
+int
+main (void)
+{
+  tests_start ();
+  mp_trace_base = 16;
+
+  check_limbdata ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpf/t-gsprec.c b/third_party/gmp/tests/mpf/t-gsprec.c
new file mode 100644
index 0000000..da07f3e
--- /dev/null
+++ b/third_party/gmp/tests/mpf/t-gsprec.c
@@ -0,0 +1,61 @@
+/* Test mpf_get_prec and mpf_set_prec.
+
+Copyright 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+void
+check_consistency (void)
+{
+  mpf_t  x;
+  unsigned long  i, a, b;
+
+  mpf_init (x);
+
+  for (i = 1; i < 2000; i++)
+    {
+      mpf_set_prec (x, i);
+      a = mpf_get_prec (x);
+      mpf_set_prec (x, a);
+      b = mpf_get_prec (x);
+      if (a != b)
+        {
+          printf ("mpf_get_prec / mpf_set_prec inconsistent\n");
+          printf ("   set %lu gives %lu, but then set %lu gives %lu\n",
+                  i, a,
+                  a, b);
+          abort ();
+        }
+    }
+
+  mpf_clear (x);
+}
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_consistency ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpf/t-inp_str.c b/third_party/gmp/tests/mpf/t-inp_str.c
new file mode 100644
index 0000000..bcc0b26
--- /dev/null
+++ b/third_party/gmp/tests/mpf/t-inp_str.c
@@ -0,0 +1,191 @@
+/* Test mpf_inp_str.
+
+Copyright 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>		/* for unlink */
+#endif
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+#define FILENAME  "t-inp_str.tmp"
+
+
+void
+check_data (void)
+{
+  static const struct {
+    const char  *inp;
+    int         base;
+    const char  *want;
+    int         want_nread;
+
+  } data[] = {
+
+    { "0",   10, "0", 1 },
+
+    { "abc", 10, "0", 0 },
+    { "ghi", 16, "0", 0 },
+
+    { "125",    10, "125",  3 },
+    { "125e1",  10, "1250", 5 },
+    { "12e+2",  10, "1200", 5 },
+    { "125e-1", 10, "12.5", 6 },
+
+    {  "ff", 16,  "255", 2 },
+    { "-ff", 16, "-255", 3 },
+    {  "FF", 16,  "255", 2 },
+    { "-FF", 16, "-255", 3 },
+
+    { "100",     16, "256",  3 },
+    { "100@1",   16, "4096", 5 },
+    { "100@10",  16, "4722366482869645213696", 6 },
+    { "100@10", -16, "281474976710656",        6 },
+    { "100@-1",  16, "16",   6 },
+    { "10000000000000000@-10",  16, "1", 21 },
+    { "10000000000@-10",       -16, "1", 15 },
+
+    { "z", 36, "35", 1 },
+    { "Z", 36, "35", 1 },
+    { "z@1", 36, "1260", 3 },
+    { "Z@1", 36, "1260", 3 },
+
+    {  "0",      0,   "0", 1 },
+  };
+
+  mpf_t  got, want;
+  long   ftell_nread;
+  int    i, pre, post, j, got_nread, want_nread;
+  FILE   *fp;
+
+  mpf_init (got);
+  mpf_init (want);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      for (pre = 0; pre <= 3; pre++)
+        {
+          for (post = 0; post <= 2; post++)
+            {
+              mpf_set_str_or_abort (want, data[i].want, 10);
+              MPF_CHECK_FORMAT (want);
+
+              /* create the file new each time to ensure its length is what
+                 we want */
+              fp = fopen (FILENAME, "w+");
+              ASSERT_ALWAYS (fp != NULL);
+              for (j = 0; j < pre; j++)
+                putc (' ', fp);
+              fputs (data[i].inp, fp);
+              for (j = 0; j < post; j++)
+                putc (' ', fp);
+              fflush (fp);
+              ASSERT_ALWAYS (! ferror(fp));
+
+              rewind (fp);
+              got_nread = mpf_inp_str (got, fp, data[i].base);
+
+              if (got_nread != 0)
+                {
+                  ftell_nread = ftell (fp);
+                  if (got_nread != ftell_nread)
+                    {
+                      printf ("mpf_inp_str nread wrong\n");
+                      printf ("  inp          \"%s\"\n", data[i].inp);
+                      printf ("  base         %d\n", data[i].base);
+                      printf ("  pre          %d\n", pre);
+                      printf ("  post         %d\n", post);
+                      printf ("  got_nread    %d\n", got_nread);
+                      printf ("  ftell_nread  %ld\n", ftell_nread);
+                      abort ();
+                    }
+                }
+
+              /* if data[i].inp is a whole string to read and there's no post
+                 whitespace then expect to have EOF */
+              if (post == 0 && data[i].want_nread == strlen(data[i].inp))
+                {
+                  int  c = getc(fp);
+                  if (c != EOF)
+                    {
+                      printf ("mpf_inp_str didn't read to EOF\n");
+                      printf ("  inp   \"%s\"\n", data[i].inp);
+                      printf ("  base  %d\n", data[i].base);
+                      printf ("  pre   %d\n", pre);
+                      printf ("  post  %d\n", post);
+                      printf ("  c     '%c' %#x\n", c, c);
+                      abort ();
+                    }
+                }
+
+              /* only expect "pre" included in the count when non-zero */
+              want_nread = data[i].want_nread;
+              if (want_nread != 0)
+                want_nread += pre;
+
+              if (got_nread != want_nread)
+                {
+                  printf ("mpf_inp_str nread wrong\n");
+                  printf ("  inp         \"%s\"\n", data[i].inp);
+                  printf ("  base        %d\n", data[i].base);
+                  printf ("  pre         %d\n", pre);
+                  printf ("  post        %d\n", post);
+                  printf ("  got_nread   %d\n", got_nread);
+                  printf ("  want_nread  %d\n", want_nread);
+                  abort ();
+                }
+
+              MPF_CHECK_FORMAT (got);
+
+              if (mpf_cmp (got, want) != 0)
+                {
+                  printf ("mpf_inp_str wrong result\n");
+                  printf ("  inp   \"%s\"\n", data[i].inp);
+                  printf ("  base  %d\n", data[i].base);
+                  mpf_trace ("  got ",  got);
+                  mpf_trace ("  want", want);
+                  abort ();
+                }
+
+              ASSERT_ALWAYS (fclose (fp) == 0);
+            }
+        }
+    }
+
+  mpf_clear (got);
+  mpf_clear (want);
+}
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_data ();
+
+  unlink (FILENAME);
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpf/t-int_p.c b/third_party/gmp/tests/mpf/t-int_p.c
new file mode 100644
index 0000000..3e536db
--- /dev/null
+++ b/third_party/gmp/tests/mpf/t-int_p.c
@@ -0,0 +1,90 @@
+/* Test mpf_integer_p.
+
+Copyright 2001, 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+one (mpf_srcptr f, int want)
+{
+  int  got;
+  got = mpf_integer_p (f);
+  if (got != want)
+    {
+      printf ("mpf_integer_p got %d want %d\n", got, want);
+      mpf_trace (" f", f);
+      abort ();
+    }
+}
+
+void
+all (mpf_ptr f, int want)
+{
+  one (f, want);
+  mpf_neg (f, f);
+  one (f, want);
+}
+
+int
+main (void)
+{
+  mpf_t  f;
+
+  tests_start ();
+  mpf_init2 (f, 200L);
+
+  mpf_set_ui (f, 0L);
+  one (f, 1);
+
+  mpf_set_ui (f, 1L);
+  all (f, 1);
+
+  mpf_set_ui (f, 1L);
+  mpf_div_2exp (f, f, 1L);
+  all (f, 0);
+
+  mpf_set_ui (f, 1L);
+  mpf_div_2exp (f, f, 5000L);
+  all (f, 0);
+
+  mpf_set_ui (f, 1L);
+  mpf_mul_2exp (f, f, 5000L);
+  all (f, 1);
+
+  mpf_set_str (f, "0.5", 10);
+  all (f, 0);
+
+  mpf_set_str (f, "2.5", 10);
+  all (f, 0);
+
+  mpf_set_ui (f, 1L);
+  mpf_div_ui (f, f, 3L);
+  all (f, 0);
+
+  mpf_set_ui (f, 7L);
+  mpf_div_ui (f, f, 3L);
+  all (f, 0);
+
+  mpf_clear (f);
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpf/t-mul_ui.c b/third_party/gmp/tests/mpf/t-mul_ui.c
new file mode 100644
index 0000000..f362bb2
--- /dev/null
+++ b/third_party/gmp/tests/mpf/t-mul_ui.c
@@ -0,0 +1,164 @@
+/* Exercise mpf_mul_ui.
+
+Copyright 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_one (const char *desc, mpf_ptr got, mpf_srcptr u, unsigned long v)
+{
+  mp_size_t  usize, usign;
+  mp_ptr     wp;
+  mpf_t      want;
+
+  MPF_CHECK_FORMAT (got);
+
+  /* this code not nailified yet */
+  ASSERT_ALWAYS (BITS_PER_ULONG <= GMP_NUMB_BITS);
+  usign = SIZ (u);
+  usize = ABS (usign);
+  wp = refmpn_malloc_limbs (usize + 1);
+  wp[usize] = mpn_mul_1 (wp, PTR(u), usize, (mp_limb_t) v);
+
+  PTR(want) = wp;
+  SIZ(want) = (usign >= 0 ? usize+1 : -(usize+1));
+  EXP(want) = EXP(u) + 1;
+  refmpf_normalize (want);
+
+  if (! refmpf_validate ("mpf_mul_ui", got, want))
+    {
+      mp_trace_base = -16;
+      printf    ("  %s\n", desc);
+      mpf_trace ("  u", u);
+      printf    ("  v %ld  0x%lX\n", v, v);
+      abort ();
+    }
+
+  free (wp);
+}
+
+void
+check_rand (void)
+{
+  unsigned long  min_prec = __GMPF_BITS_TO_PREC (1);
+  gmp_randstate_ptr  rands = RANDS;
+  mpf_t              got, u;
+  unsigned long      prec, v;
+  int                i;
+
+  /* The nails code in mpf_mul_ui currently isn't exact, so suppress these
+     tests for now.  */
+  if (BITS_PER_ULONG > GMP_NUMB_BITS)
+    return;
+
+  mpf_init (got);
+  mpf_init (u);
+
+  for (i = 0; i < 200; i++)
+    {
+      /* got precision */
+      prec = min_prec + gmp_urandomm_ui (rands, 15L);
+      refmpf_set_prec_limbs (got, prec);
+
+      /* u precision */
+      prec = min_prec + gmp_urandomm_ui (rands, 15L);
+      refmpf_set_prec_limbs (u, prec);
+
+      /* u, possibly negative */
+      mpf_random2 (u, PREC(u), (mp_exp_t) 20);
+      if (gmp_urandomb_ui (rands, 1L))
+        mpf_neg (u, u);
+
+      /* v, 0 to BITS_PER_ULONG bits (inclusive) */
+      prec = gmp_urandomm_ui (rands, BITS_PER_ULONG+1);
+      v = gmp_urandomb_ui (rands, prec);
+
+      if ((i % 2) == 0)
+        {
+          /* separate */
+          mpf_mul_ui (got, u, v);
+          check_one ("separate", got, u, v);
+        }
+      else
+        {
+          /* overlap */
+          prec = refmpf_set_overlap (got, u);
+          mpf_mul_ui (got, got, v);
+          check_one ("overlap src==dst", got, u, v);
+
+          mpf_set_prec_raw (got, prec);
+        }
+    }
+
+  mpf_clear (got);
+  mpf_clear (u);
+}
+
+void
+check_various (void)
+{
+  mpf_t  u, got, want;
+  const char   *s;
+
+  mpf_init2 (u,    2*8*sizeof(long));
+  mpf_init2 (got,  2*8*sizeof(long));
+  mpf_init2 (want, 2*8*sizeof(long));
+
+  s = "0 * ULONG_MAX";
+  mpf_set_ui (u, 0L);
+  mpf_mul_ui (got, u, ULONG_MAX);
+  MPF_CHECK_FORMAT (got);
+  mpf_set_ui (want, 0L);
+  if (mpf_cmp (got, want) != 0)
+    {
+    error:
+      printf ("Wrong result from %s\n", s);
+      mpf_trace ("u   ", u);
+      mpf_trace ("got ", got);
+      mpf_trace ("want", want);
+      abort ();
+    }
+
+  s = "1 * ULONG_MAX";
+  mpf_set_ui (u, 1L);
+  mpf_mul_ui (got, u, ULONG_MAX);
+  MPF_CHECK_FORMAT (got);
+  mpf_set_ui (want, ULONG_MAX);
+  if (mpf_cmp (got, want) != 0)
+    goto error;
+
+  mpf_clear (u);
+  mpf_clear (got);
+  mpf_clear (want);
+}
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_various ();
+  check_rand ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpf/t-muldiv.c b/third_party/gmp/tests/mpf/t-muldiv.c
new file mode 100644
index 0000000..86dca57
--- /dev/null
+++ b/third_party/gmp/tests/mpf/t-muldiv.c
@@ -0,0 +1,158 @@
+/* Test mpf_mul, mpf_div, mpf_ui_div, and mpf_div_ui.
+
+Copyright 1996, 2000, 2001, 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#ifndef SIZE
+#define SIZE 16
+#endif
+
+int
+main (int argc, char **argv)
+{
+  mp_size_t size;
+  mp_exp_t exp;
+  int reps = 10000;
+  int i;
+  mpf_t u, v, w, x;
+  mp_size_t bprec = SIZE * GMP_LIMB_BITS;
+  mpf_t rerr, limit_rerr;
+  unsigned long ulimb, vlimb;
+  int single_flag;
+
+  tests_start ();
+
+  if (argc > 1)
+    {
+      reps = strtol (argv[1], 0, 0);
+      if (argc > 2)
+	bprec = strtol (argv[2], 0, 0);
+    }
+
+  mpf_set_default_prec (bprec);
+
+  mpf_init (rerr);
+  mpf_init (limit_rerr);
+
+  mpf_init (u);
+  mpf_init (v);
+  mpf_init (w);
+  mpf_init (x);
+
+  for (i = 0; i < reps; i++)
+    {
+      mp_size_t res_prec;
+
+      res_prec = urandom () % bprec + 1;
+      mpf_set_prec (w, res_prec);
+      mpf_set_prec (x, res_prec);
+
+      mpf_set_ui (limit_rerr, 1);
+      mpf_div_2exp (limit_rerr, limit_rerr, res_prec - 1);
+
+      single_flag = 0;
+
+      if ((urandom () & 1) != 0)
+	{
+	  size = urandom () % (2 * SIZE) - SIZE;
+	  exp = urandom () % SIZE;
+	  mpf_random2 (u, size, exp);
+	}
+      else
+	{
+	  ulimb = urandom ();
+	  mpf_set_ui (u, ulimb);
+	  single_flag = 1;
+	}
+
+      if ((urandom () & 1) != 0)
+	{
+	  size = urandom () % (2 * SIZE) - SIZE;
+	  exp = urandom () % SIZE;
+	  mpf_random2 (v, size, exp);
+	}
+      else
+	{
+	  vlimb = urandom ();
+	  mpf_set_ui (v, vlimb);
+	  single_flag = 2;
+	}
+
+      if (mpf_sgn (v) == 0)
+	continue;
+
+      mpf_div (w, u, v);
+      mpf_mul (x, w, v);
+      mpf_reldiff (rerr, u, x);
+      if (mpf_cmp (rerr, limit_rerr) > 0)
+	{
+	  printf ("ERROR in mpf_mul or mpf_div after %d tests\n", i);
+	  printf ("   u = "); mpf_dump (u);
+	  printf ("   v = "); mpf_dump (v);
+	  printf ("   x = "); mpf_dump (x);
+	  printf ("   w = "); mpf_dump (w);
+	  abort ();
+	}
+
+      if (single_flag == 2)
+	{
+	  mpf_div_ui (x, u, vlimb);
+	  mpf_reldiff (rerr, w, x);
+	  if (mpf_cmp (rerr, limit_rerr) > 0)
+	    {
+	      printf ("ERROR in mpf_div or mpf_div_ui after %d tests\n", i);
+	      printf ("   u = "); mpf_dump (u);
+	      printf ("   v = "); mpf_dump (v);
+	      printf ("   x = "); mpf_dump (x);
+	      printf ("   w = "); mpf_dump (w);
+	      abort ();
+	    }
+	}
+
+      if (single_flag == 1)
+	{
+	  mpf_ui_div (x, ulimb, v);
+	  mpf_reldiff (rerr, w, x);
+	  if (mpf_cmp (rerr, limit_rerr) > 0)
+	    {
+	      printf ("ERROR in mpf_div or mpf_ui_div after %d tests\n", i);
+	      printf ("   u = "); mpf_dump (u);
+	      printf ("   v = "); mpf_dump (v);
+	      printf ("   x = "); mpf_dump (x);
+	      printf ("   w = "); mpf_dump (w);
+	      abort ();
+	    }
+	}
+    }
+
+  mpf_clear (rerr);
+  mpf_clear (limit_rerr);
+
+  mpf_clear (u);
+  mpf_clear (v);
+  mpf_clear (w);
+  mpf_clear (x);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpf/t-pow_ui.c b/third_party/gmp/tests/mpf/t-pow_ui.c
new file mode 100644
index 0000000..f005301
--- /dev/null
+++ b/third_party/gmp/tests/mpf/t-pow_ui.c
@@ -0,0 +1,69 @@
+/* Test mpf_pow_ui
+
+Copyright 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+void
+check_data (void)
+{
+  unsigned int b, e;
+  mpf_t b1, r, r2, limit;
+
+  mpf_inits (b1, r, r2, NULL);
+  mpf_init_set_ui (limit, 1);
+  mpf_mul_2exp (limit, limit, MAX (GMP_NUMB_BITS, 53));
+
+  /* This test just test integers with results that fit in a single
+     limb or 53 bits.  This avoids any rounding.  */
+
+  for (b = 0; b <= 400; b++)
+    {
+      mpf_set_ui (b1, b);
+      mpf_set_ui (r2, 1);
+      for (e = 0; e <= GMP_LIMB_BITS; e++)
+	{
+	  mpf_pow_ui (r, b1, e);
+
+	  if (mpf_cmp (r, r2))
+	    abort ();
+
+	  mpf_mul_ui (r2, r2, b);
+
+	  if (mpf_cmp (r2, limit) >= 0)
+	    break;
+	}
+    }
+
+  mpf_clears (b1, r, r2, limit, NULL);
+}
+
+int
+main (int argc, char **argv)
+{
+  tests_start ();
+
+  check_data ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpf/t-set.c b/third_party/gmp/tests/mpf/t-set.c
new file mode 100644
index 0000000..2510748
--- /dev/null
+++ b/third_party/gmp/tests/mpf/t-set.c
@@ -0,0 +1,112 @@
+/* Test mpf_set, mpf_init_set.
+
+Copyright 2004, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+void
+check_reuse (void)
+{
+  /* Try mpf_set(f,f) when f is bigger than prec.  In the past this had
+     resulted in an MPN_COPY with invalid operand overlap. */
+  mpf_t  f;
+  mp_size_t      limbs = 20;
+  unsigned long  bits = limbs * GMP_NUMB_BITS;
+  mpf_init2 (f, bits);
+  refmpf_fill (f, limbs, GMP_NUMB_MAX);
+  mpf_set_prec_raw (f, bits / 2);
+  mpf_set (f, f);
+  MPF_CHECK_FORMAT (f);
+  mpf_set_prec_raw (f, bits);
+  mpf_clear (f);
+}
+
+void
+check_random (long reps)
+{
+  unsigned long test;
+  gmp_randstate_ptr rands;
+  mpf_t a, b;
+  mpz_t z;
+  int precbits;
+
+#define PRECBITS 10
+
+  rands = RANDS;
+
+  mpz_init (z);
+  mpf_init2 (a, 1 << PRECBITS);
+
+  for (test = 0; test < reps; test++)
+    {
+      mpz_urandomb (z, rands, PRECBITS + 1);
+      precbits = mpz_get_ui (z) + 1;
+      mpz_urandomb (z, rands, precbits);
+      mpz_setbit (z, precbits  - 1);	/* make sure msb is set */
+      mpf_set_z (a, z);
+      if (precbits & 1)
+	mpf_neg (a, a);
+      mpz_urandomb (z, rands, PRECBITS);
+      mpf_div_2exp (a, a, mpz_get_ui (z) + 1);
+      mpz_urandomb (z, rands, PRECBITS);
+      precbits -= mpz_get_ui (z);
+      if (precbits <= 0)
+	precbits = 1 - precbits;
+      mpf_set_default_prec (precbits);
+
+      mpf_init_set (b, a);
+      MPF_CHECK_FORMAT (b);
+      if (!mpf_eq (a, b, precbits))
+	{
+	  printf ("mpf_init_set wrong.\n");
+	  abort();
+	}
+
+      mpf_set_ui (b, 0);
+      mpf_set (b, a);
+      MPF_CHECK_FORMAT (b);
+      if (!mpf_eq (a, b, precbits))
+	{
+	  printf ("mpf_set wrong.\n");
+	  abort();
+	}
+
+      mpf_clear (b);
+    }
+
+  mpf_clear (a);
+  mpz_clear (z);
+}
+
+int
+main (int argc, char *argv[])
+{
+  long reps = 10000;
+
+  tests_start ();
+  TESTS_REPS (reps, argv, argc);
+
+  check_reuse ();
+  check_random (reps);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpf/t-set_q.c b/third_party/gmp/tests/mpf/t-set_q.c
new file mode 100644
index 0000000..86dec6e
--- /dev/null
+++ b/third_party/gmp/tests/mpf/t-set_q.c
@@ -0,0 +1,126 @@
+/* Test mpf_set_q.
+
+Copyright 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_one (mpf_ptr got, mpq_srcptr q)
+{
+  mpf_t  n, d;
+
+  mpf_set_q (got, q);
+
+  PTR(n) = PTR(&q->_mp_num);
+  SIZ(n) = SIZ(&q->_mp_num);
+  EXP(n) = ABSIZ(&q->_mp_num);
+
+  PTR(d) = PTR(&q->_mp_den);
+  SIZ(d) = SIZ(&q->_mp_den);
+  EXP(d) = ABSIZ(&q->_mp_den);
+
+  if (! refmpf_validate_division ("mpf_set_q", got, n, d))
+    {
+      mp_trace_base = -16;
+      mpq_trace ("   q", q);
+      abort ();
+    }
+}
+
+void
+check_rand (void)
+{
+  unsigned long  min_prec = __GMPF_BITS_TO_PREC (1);
+  gmp_randstate_ptr  rands = RANDS;
+  unsigned long  prec;
+  mpf_t  got;
+  mpq_t  q;
+  int    i;
+
+  mpf_init (got);
+  mpq_init (q);
+
+  for (i = 0; i < 400; i++)
+    {
+      /* result precision */
+      prec = min_prec + gmp_urandomm_ui (rands, 20L);
+      refmpf_set_prec_limbs (got, prec);
+
+      /* num */
+      prec = gmp_urandomm_ui (rands, 20L * GMP_NUMB_BITS);
+      mpz_rrandomb (mpq_numref(q), rands, prec);
+
+      /* possibly negative num */
+      if (gmp_urandomb_ui (rands, 1L))
+        mpz_neg (mpq_numref(q), mpq_numref(q));
+
+      /* den, non-zero */
+      do {
+        prec = gmp_urandomm_ui (rands, 20L * GMP_NUMB_BITS);
+        mpz_rrandomb (mpq_denref(q), rands, prec);
+      } while (mpz_sgn (mpq_denref(q)) <= 0);
+
+      check_one (got, q);
+    }
+
+  mpf_clear (got);
+  mpq_clear (q);
+}
+
+void
+check_various (void)
+{
+  mpf_t got;
+  mpq_t q;
+
+  mpf_init (got);
+  mpq_init (q);
+
+  /* 1/1 == 1 */
+  mpf_set_prec (got, 20L);
+  mpq_set_ui (q, 1L, 1L);
+  mpf_set_q (got, q);
+  MPF_CHECK_FORMAT (got);
+  ASSERT_ALWAYS (mpf_cmp_ui (got, 1L) == 0);
+
+  /* 1/(2^n+1), a case where truncating the divisor would be wrong */
+  mpf_set_prec (got, 500L);
+  mpq_set_ui (q, 1L, 1L);
+  mpz_mul_2exp (mpq_denref(q), mpq_denref(q), 800L);
+  mpz_add_ui (mpq_denref(q), mpq_denref(q), 1L);
+  check_one (got, q);
+
+  mpf_clear (got);
+  mpq_clear (q);
+}
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_various ();
+  check_rand ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpf/t-set_si.c b/third_party/gmp/tests/mpf/t-set_si.c
new file mode 100644
index 0000000..5cd6c89
--- /dev/null
+++ b/third_party/gmp/tests/mpf/t-set_si.c
@@ -0,0 +1,90 @@
+/* Test mpf_set_si and mpf_init_set_si.
+
+Copyright 2000, 2001, 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+void
+check_data (void)
+{
+  static const struct {
+    long       x;
+    mp_size_t  want_size;
+    mp_limb_t  want_data[2];
+  } data[] = {
+
+    {  0L,  0 },
+    {  1L,  1, { 1 } },
+    { -1L, -1, { 1 } },
+
+#if GMP_NUMB_BITS >= BITS_PER_ULONG
+    { LONG_MAX,  1, { LONG_MAX, 0 } },
+    { -LONG_MAX,  -1, { LONG_MAX, 0 } },
+    { LONG_HIGHBIT,  -1, { ULONG_HIGHBIT, 0 } },
+#else
+    { LONG_MAX,  2, { LONG_MAX & GMP_NUMB_MASK, LONG_MAX >> GMP_NUMB_BITS } },
+    { -LONG_MAX,  -2, { LONG_MAX & GMP_NUMB_MASK, LONG_MAX >> GMP_NUMB_BITS }},
+    { LONG_HIGHBIT,  -2, { 0, ULONG_HIGHBIT >> GMP_NUMB_BITS } },
+#endif
+  };
+
+  mpf_t  x;
+  int    i;
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpf_init (x);
+      mpf_set_si (x, data[i].x);
+      MPF_CHECK_FORMAT (x);
+      if (x->_mp_size != data[i].want_size
+          || refmpn_cmp_allowzero (x->_mp_d, data[i].want_data,
+                                   ABS (data[i].want_size)) != 0
+          || x->_mp_exp != ABS (data[i].want_size))
+        {
+          printf ("mpf_set_si wrong on data[%d]\n", i);
+          abort();
+        }
+      mpf_clear (x);
+
+      mpf_init_set_si (x, data[i].x);
+      MPF_CHECK_FORMAT (x);
+      if (x->_mp_size != data[i].want_size
+          || refmpn_cmp_allowzero (x->_mp_d, data[i].want_data,
+                                   ABS (data[i].want_size)) != 0
+          || x->_mp_exp != ABS (data[i].want_size))
+        {
+          printf ("mpf_init_set_si wrong on data[%d]\n", i);
+          abort();
+        }
+      mpf_clear (x);
+    }
+}
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_data ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpf/t-set_ui.c b/third_party/gmp/tests/mpf/t-set_ui.c
new file mode 100644
index 0000000..828067c
--- /dev/null
+++ b/third_party/gmp/tests/mpf/t-set_ui.c
@@ -0,0 +1,89 @@
+/* Test mpf_set_ui and mpf_init_set_ui.
+
+Copyright 2000, 2001, 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+void
+check_data (void)
+{
+  static const struct {
+    unsigned long  x;
+    mp_size_t      want_size;
+    mp_limb_t      want_data[2];
+  } data[] = {
+
+    {  0L,  0 },
+    {  1L,  1, { 1 } },
+
+#if GMP_NUMB_BITS >= BITS_PER_ULONG
+    { ULONG_MAX,     1, { ULONG_MAX, 0 } },
+    { ULONG_HIGHBIT, 1, { ULONG_HIGHBIT, 0 } },
+#else
+    { ULONG_MAX,     2, { ULONG_MAX & GMP_NUMB_MASK,
+                          ULONG_MAX >> GMP_NUMB_BITS } },
+    { ULONG_HIGHBIT, 2, { 0,
+                          ULONG_HIGHBIT >> GMP_NUMB_BITS } },
+#endif
+  };
+
+  mpf_t  x;
+  int    i;
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpf_init (x);
+      mpf_set_ui (x, data[i].x);
+      MPF_CHECK_FORMAT (x);
+      if (x->_mp_size != data[i].want_size
+          || refmpn_cmp_allowzero (x->_mp_d, data[i].want_data,
+                                   ABS (data[i].want_size)) != 0
+          || x->_mp_exp != ABS (data[i].want_size))
+        {
+          printf ("mpf_set_ui wrong on data[%d]\n", i);
+          abort();
+        }
+      mpf_clear (x);
+
+      mpf_init_set_ui (x, data[i].x);
+      MPF_CHECK_FORMAT (x);
+      if (x->_mp_size != data[i].want_size
+          || refmpn_cmp_allowzero (x->_mp_d, data[i].want_data,
+                                   ABS (data[i].want_size)) != 0
+          || x->_mp_exp != ABS (data[i].want_size))
+        {
+          printf ("mpf_init_set_ui wrong on data[%d]\n", i);
+          abort();
+        }
+      mpf_clear (x);
+    }
+}
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_data ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpf/t-sqrt.c b/third_party/gmp/tests/mpf/t-sqrt.c
new file mode 100644
index 0000000..5e93aba
--- /dev/null
+++ b/third_party/gmp/tests/mpf/t-sqrt.c
@@ -0,0 +1,193 @@
+/* Test mpf_sqrt, mpf_mul.
+
+Copyright 1996, 2001, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#ifndef SIZE
+#define SIZE 16
+#endif
+
+void
+check_rand1 (int argc, char **argv)
+{
+  mp_size_t size;
+  mp_exp_t exp;
+  int reps = 20000;
+  int i;
+  mpf_t x, y, y2;
+  mp_size_t bprec = 100;
+  mpf_t rerr, max_rerr, limit_rerr;
+
+  if (argc > 1)
+    {
+      reps = strtol (argv[1], 0, 0);
+      if (argc > 2)
+	bprec = strtol (argv[2], 0, 0);
+    }
+
+  mpf_set_default_prec (bprec);
+
+  mpf_init_set_ui (limit_rerr, 1);
+  mpf_div_2exp (limit_rerr, limit_rerr, bprec);
+#if VERBOSE
+  mpf_dump (limit_rerr);
+#endif
+  mpf_init (rerr);
+  mpf_init_set_ui (max_rerr, 0);
+
+  mpf_init (x);
+  mpf_init (y);
+  mpf_init (y2);
+  for (i = 0; i < reps; i++)
+    {
+      size = urandom () % SIZE;
+      exp = urandom () % SIZE;
+      mpf_random2 (x, size, exp);
+
+      mpf_sqrt (y, x);
+      MPF_CHECK_FORMAT (y);
+      mpf_mul (y2, y, y);
+
+      mpf_reldiff (rerr, x, y2);
+      if (mpf_cmp (rerr, max_rerr) > 0)
+	{
+	  mpf_set (max_rerr, rerr);
+#if VERBOSE
+	  mpf_dump (max_rerr);
+#endif
+	  if (mpf_cmp (rerr, limit_rerr) > 0)
+	    {
+	      printf ("ERROR after %d tests\n", i);
+	      printf ("   x = "); mpf_dump (x);
+	      printf ("   y = "); mpf_dump (y);
+	      printf ("  y2 = "); mpf_dump (y2);
+	      printf ("   rerr       = "); mpf_dump (rerr);
+	      printf ("   limit_rerr = "); mpf_dump (limit_rerr);
+              printf ("in hex:\n");
+              mp_trace_base = 16;
+	      mpf_trace ("   x  ", x);
+	      mpf_trace ("   y  ", y);
+	      mpf_trace ("   y2 ", y2);
+	      mpf_trace ("   rerr      ", rerr);
+	      mpf_trace ("   limit_rerr", limit_rerr);
+	      abort ();
+	    }
+	}
+    }
+
+  mpf_clear (limit_rerr);
+  mpf_clear (rerr);
+  mpf_clear (max_rerr);
+
+  mpf_clear (x);
+  mpf_clear (y);
+  mpf_clear (y2);
+}
+
+void
+check_rand2 (void)
+{
+  unsigned long      max_prec = 20;
+  unsigned long      min_prec = __GMPF_BITS_TO_PREC (1);
+  gmp_randstate_ptr  rands = RANDS;
+  unsigned long      x_prec, r_prec;
+  mpf_t              x, r, s;
+  int                i;
+
+  mpf_init (x);
+  mpf_init (r);
+  mpf_init (s);
+  refmpf_set_prec_limbs (s, 2*max_prec+10);
+
+  for (i = 0; i < 500; i++)
+    {
+      /* input precision */
+      x_prec = gmp_urandomm_ui (rands, max_prec-min_prec) + min_prec;
+      refmpf_set_prec_limbs (x, x_prec);
+
+      /* result precision */
+      r_prec = gmp_urandomm_ui (rands, max_prec-min_prec) + min_prec;
+      refmpf_set_prec_limbs (r, r_prec);
+
+      mpf_random2 (x, x_prec, 1000);
+
+      mpf_sqrt (r, x);
+      MPF_CHECK_FORMAT (r);
+
+      /* Expect to prec limbs of result.
+         In the current implementation there's no stripping of low zero
+         limbs in mpf_sqrt, so size should be exactly prec.  */
+      if (SIZ(r) != r_prec)
+        {
+          printf ("mpf_sqrt wrong number of result limbs\n");
+          mpf_trace ("  x", x);
+          mpf_trace ("  r", r);
+          printf    ("  r_prec=%lu\n", r_prec);
+          printf    ("  SIZ(r)  %ld\n", (long) SIZ(r));
+          printf    ("  PREC(r) %ld\n", (long) PREC(r));
+          abort ();
+        }
+
+      /* Must have r^2 <= x, since r has been truncated. */
+      mpf_mul (s, r, r);
+      if (! (mpf_cmp (s, x) <= 0))
+        {
+          printf    ("mpf_sqrt result too big\n");
+          mpf_trace ("  x", x);
+          printf    ("  r_prec=%lu\n", r_prec);
+          mpf_trace ("  r", r);
+          mpf_trace ("  s", s);
+          abort ();
+        }
+
+      /* Must have (r+ulp)^2 > x, or else r is too small. */
+      refmpf_add_ulp (r);
+      mpf_mul (s, r, r);
+      if (! (mpf_cmp (s, x) > 0))
+        {
+          printf    ("mpf_sqrt result too small\n");
+          mpf_trace ("  x", x);
+          printf    ("  r_prec=%lu\n", r_prec);
+          mpf_trace ("  r+ulp", r);
+          mpf_trace ("  s", s);
+          abort ();
+        }
+    }
+
+  mpf_clear (x);
+  mpf_clear (r);
+  mpf_clear (s);
+}
+
+int
+main (int argc, char **argv)
+{
+  tests_start ();
+  mp_trace_base = -16;
+
+  check_rand1 (argc, argv);
+  check_rand2 ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpf/t-sqrt_ui.c b/third_party/gmp/tests/mpf/t-sqrt_ui.c
new file mode 100644
index 0000000..31c587f
--- /dev/null
+++ b/third_party/gmp/tests/mpf/t-sqrt_ui.c
@@ -0,0 +1,125 @@
+/* Test mpf_sqrt_ui.
+
+Copyright 2004, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_rand (void)
+{
+  unsigned long      max_prec = 15;
+  unsigned long      min_prec = __GMPF_BITS_TO_PREC (1);
+  gmp_randstate_ptr  rands = RANDS;
+  unsigned long      x, prec;
+  mpf_t              r, s;
+  int                i;
+
+  mpf_init (r);
+  mpf_init (s);
+  refmpf_set_prec_limbs (s, 2*max_prec+10);
+
+  for (x = 0; x < 2; x++)
+    {
+      mpf_sqrt_ui (r, x);
+      MPF_CHECK_FORMAT (r);
+      if (mpf_cmp_ui (r, x) != 0)
+	{
+	  printf    ("mpf_sqrt_ui wrong for special case:\n");
+          printf    ("  x=%lu\n", x);
+          mpf_trace ("  r", r);
+	  abort ();
+	}
+    }
+
+  for (i = 0; i < 50; i++)
+    {
+      /* input, a random non-zero ulong, exponentially distributed */
+      do {
+        x = gmp_urandomb_ui (rands,
+                             gmp_urandomm_ui (rands, BITS_PER_ULONG) + 1);
+      } while (x <= 1);
+
+      /* result precision */
+      prec = gmp_urandomm_ui (rands, max_prec-min_prec) + min_prec;
+      refmpf_set_prec_limbs (r, prec);
+
+      mpf_sqrt_ui (r, x);
+      MPF_CHECK_FORMAT (r);
+
+      /* Expect to prec limbs of result.
+         In the current implementation there's no stripping of low zero
+         limbs in mpf_sqrt_ui, not even on perfect squares, so size should
+         be exactly prec.  */
+      if (SIZ(r) != prec)
+        {
+          printf ("mpf_sqrt_ui result not enough result limbs\n");
+          printf    ("  x=%lu\n", x);
+          printf    ("  want prec=%lu\n", prec);
+          mpf_trace ("  r", r);
+          printf    ("  r size %ld\n", (long) SIZ(r));
+          printf    ("  r prec %ld\n", (long) PREC(r));
+          abort ();
+        }
+
+      /* Must have r^2 <= x, since r has been truncated. */
+      mpf_mul (s, r, r);
+      if (! (mpf_cmp_ui (s, x) <= 0))
+        {
+          printf    ("mpf_sqrt_ui result too big\n");
+          printf    ("  x=%lu\n", x);
+          printf    ("  want prec=%lu\n", prec);
+          mpf_trace ("  r", r);
+          mpf_trace ("  s", s);
+          abort ();
+        }
+
+      /* Must have (r+ulp)^2 > x.
+         No overflow from refmpf_add_ulp since r is only prec limbs. */
+      refmpf_add_ulp (r);
+      mpf_mul (s, r, r);
+      if (! (mpf_cmp_ui (s, x) > 0))
+        {
+          printf    ("mpf_sqrt_ui result too small\n");
+          printf    ("  x=%lu\n", x);
+          printf    ("  want prec=%lu\n", prec);
+          mpf_trace ("  r+ulp", r);
+          mpf_trace ("  s", s);
+          abort ();
+        }
+    }
+
+  mpf_clear (r);
+  mpf_clear (s);
+}
+
+int
+main (int argc, char **argv)
+{
+  tests_start ();
+  mp_trace_base = -16;
+
+  check_rand ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpf/t-sub.c b/third_party/gmp/tests/mpf/t-sub.c
new file mode 100644
index 0000000..3872264
--- /dev/null
+++ b/third_party/gmp/tests/mpf/t-sub.c
@@ -0,0 +1,287 @@
+/* Test mpf_sub.
+
+Copyright 1996, 2001, 2004, 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#ifndef SIZE
+#define SIZE 16
+#endif
+
+void
+check_rand (int argc, char **argv)
+{
+  mp_size_t size;
+  mp_exp_t exp;
+  int reps = 20000;
+  int i;
+  mpf_t u, v, w, wref;
+  mp_size_t bprec = 100;
+  mpf_t rerr, max_rerr, limit_rerr;
+
+  if (argc > 1)
+    {
+      reps = strtol (argv[1], 0, 0);
+      if (argc > 2)
+	bprec = strtol (argv[2], 0, 0);
+    }
+
+  mpf_set_default_prec (bprec);
+
+  mpf_init_set_ui (limit_rerr, 1);
+  mpf_div_2exp (limit_rerr, limit_rerr, bprec);
+#if VERBOSE
+  mpf_dump (limit_rerr);
+#endif
+  mpf_init (rerr);
+  mpf_init_set_ui (max_rerr, 0);
+
+  mpf_init (u);
+  mpf_init (v);
+  mpf_init (w);
+  mpf_init (wref);
+  for (i = 0; i < reps; i++)
+    {
+      size = urandom () % (2 * SIZE) - SIZE;
+      exp = urandom () % SIZE;
+      mpf_random2 (u, size, exp);
+
+      size = urandom () % (2 * SIZE) - SIZE;
+      exp = urandom () % SIZE;
+      mpf_random2 (v, size, exp);
+
+      if ((urandom () & 1) != 0)
+	mpf_add_ui (u, v, 1);
+      else if ((urandom () & 1) != 0)
+	mpf_sub_ui (u, v, 1);
+
+      mpf_sub (w, u, v);
+      refmpf_sub (wref, u, v);
+
+      mpf_reldiff (rerr, w, wref);
+      if (mpf_cmp (rerr, max_rerr) > 0)
+	{
+	  mpf_set (max_rerr, rerr);
+#if VERBOSE
+	  mpf_dump (max_rerr);
+#endif
+	  if (mpf_cmp (rerr, limit_rerr) > 0)
+	    {
+	      printf ("ERROR after %d tests\n", i);
+	      printf ("   u = "); mpf_dump (u);
+	      printf ("   v = "); mpf_dump (v);
+	      printf ("wref = "); mpf_dump (wref);
+	      printf ("   w = "); mpf_dump (w);
+	      abort ();
+	    }
+	}
+    }
+
+  mpf_clear (limit_rerr);
+  mpf_clear (rerr);
+  mpf_clear (max_rerr);
+
+  mpf_clear (u);
+  mpf_clear (v);
+  mpf_clear (w);
+  mpf_clear (wref);
+}
+
+#define W GMP_NUMB_MAX
+
+void
+check_data (void)
+{
+  static const struct {
+    struct {
+      int        exp, size;
+      mp_limb_t  d[10];
+    } x, y, want;
+
+  } data[] = {
+    { { 123, 2, { 8, 9 } },             { 123, 1, { 9 } }, { 122, 1, { 8 } } },
+    { { 1, 1, { 9 } },                  { 1, 1, { 8 } },   { 1, 1, { 1 } } },
+    { { 1, 1, { 9 } },                 { 1, -1, { 6 } },   { 1, 1, { 15 } } },
+    { { 1, 2, { 8, 9 } },               { 1, 1, { 8 } },   { 1, 2, { 8, 1 } } },
+    { { 2, 2, { 8, 1 } },               { 1, 1, { 9 } },   { 1, 1, { W } } },
+    { { 2, 2, { 9, 8 } },               { 1, 1, { 9 } },   { 2, 1, { 8 } } },
+    { { 2, 1, { 1 } },                  { 1, 1, { 1 } },   { 1, 1, { W } } },
+    { { 2, 1, { 9 } },                  { 1, 1, { W } },   { 2, 2, { 1, 8 } } },
+
+    { { 1, 2, { W, 8 } },             { 1, 1, { 9 } },   { 0, -1, { 1 } } },
+    { { 1, 2, { W, 7 } },             { 1, 1, { 9 } },   { 1, -2, { 1, 1 } } },
+    { { 1, 2, { 1, 8 } },             { 1, 1, { 9 } },   { 0, -1, { W } } },
+    { { 1, 2, { 1, 7 } },             { 1, 1, { 9 } },   { 1, -2, { W, 1 } } },
+    { { 1, 2, { 0, 8 } },             { 1, 1, { 9 } },   { 1, -1, { 1 } } },
+    { { 2, 3, { 5, 8, 1 } },          { 1, 1, { 9 } },   { 1, 2, { 5, W } } },
+    { { 3, 1, { 1 } },                { 1, 1, { 1 } },   { 2, 2, { W, W } } },
+    { { 1, 6, { W, W, W, W, W, 8 } }, { 1, 1, { 9 } },   { -4, -1, { 1 } } },
+    { { 5, 5, { W-6, W, W, W, W } },  { 6, 1, { 1 } },   { 1, -1, { 7 } } },
+
+    /* f - f == 0, various sizes.
+       These exercise a past problem (gmp 4.1.3 and earlier) where the
+       result exponent was not zeroed on a zero result like this.  */
+    { { 0, 0 }, { 0, 0 }, { 0, 0 } },
+    { { 99, 3, { 0, 0, 1 } },       { 99, 1, { 1 } },             { 0, 0 } },
+    { { 99, 3, { 0, 123, 456 } },   { 99, 2, { 123, 456 } },      { 0, 0 } },
+    { { 99, 3, { 123, 456, 789 } }, { 99, 3, { 123, 456, 789 } }, { 0, 0 } },
+
+    /* High limbs cancel, leaving just the low limbs of the longer operand.
+       This exercises a past problem (gmp 4.1.3 and earlier) where high zero
+       limbs on the remainder were not stripped before truncating to the
+       destination, causing loss of precision.  */
+    { { 123, 2, { 8, 9 } },             { 123, 1, { 9 } }, { 122, 1, { 8 } } },
+    { { 123, 3, { 8, 0, 9 } },          { 123, 1, { 9 } }, { 121, 1, { 8 } } },
+    { { 123, 4, { 8, 0, 0, 9 } },       { 123, 1, { 9 } }, { 120, 1, { 8 } } },
+    { { 123, 5, { 8, 0, 0, 0, 9 } },    { 123, 1, { 9 } }, { 119, 1, { 8 } } },
+    { { 123, 6, { 8, 0, 0, 0, 0, 9 } }, { 123, 1, { 9 } }, { 118, 1, { 8 } } },
+    /* { { 123, 6, { 8, 0, 0, 0, 0, 9 } }, { 123, 6, { 9, 0, 0, 0, 0, 8 } }, { 122, 5, { W, W, W, W, W } } }, */
+
+  };
+
+  mpf_t  x, y, got, want;
+  int  i, swap, fail;
+
+  fail = 0;
+  mp_trace_base = 16;
+  mpf_init (got);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      for (swap = 0; swap <= 7; swap++)
+        {
+          PTR(x) = (mp_ptr) data[i].x.d;
+          SIZ(x) = data[i].x.size;
+          EXP(x) = data[i].x.exp;
+          PREC(x) = numberof (data[i].x.d);
+          MPF_CHECK_FORMAT (x);
+
+          PTR(y) = (mp_ptr) data[i].y.d;
+          SIZ(y) = data[i].y.size;
+          EXP(y) = data[i].y.exp;
+          PREC(y) = numberof (data[i].y.d);
+          MPF_CHECK_FORMAT (y);
+
+          PTR(want) = (mp_ptr) data[i].want.d;
+          SIZ(want) = data[i].want.size;
+          EXP(want) = data[i].want.exp;
+          PREC(want) = numberof (data[i].want.d);
+          MPF_CHECK_FORMAT (want);
+
+          if (swap & 4)
+            {
+              mpf_swap (want, y);
+            }
+
+	  if ((SIZ (x) ^ SIZ (y)) < 0)
+	    continue; /* It's an addition, not a subtraction (TO BE REMOVED) */
+
+          if (swap & 1)
+            {
+              mpf_swap (x, y);
+              SIZ(want) = - SIZ(want);
+            }
+
+          if (swap & 2)
+            {
+              SIZ(want) = - SIZ(want);
+              SIZ(x) = - SIZ(x);
+              SIZ(y) = - SIZ(y);
+            }
+
+          mpf_sub (got, x, y);
+/*           MPF_CHECK_FORMAT (got); */
+
+          if (! refmpf_validate ("mpf_sub", got, want))
+            {
+              printf ("check_data() wrong result at data[%d] (operands%s swapped)\n", i, swap ? "" : " not");
+              mpf_trace ("x   ", x);
+              mpf_trace ("y   ", y);
+              mpf_trace ("got ", got);
+              mpf_trace ("want", want);
+	      fail = 1;
+            }
+
+	  if (SIZ (x) == 1 || SIZ (x) == 0 )
+	    {
+	      if (SIZ (y)) EXP (y) -= EXP (x) - (mp_exp_t) SIZ (x);
+	      if (SIZ (want)) EXP (want) -= EXP (x) - (mp_exp_t) SIZ (x);
+	      EXP (x) = (mp_exp_t) SIZ (x);
+
+	      if (mpf_fits_uint_p (x))
+		{
+		  mpf_ui_sub (got, mpf_get_ui (x), y);
+
+		  if (! refmpf_validate ("mpf_ui_sub", got, want))
+		    {
+		      printf ("check_data() wrong result at data[%d] (operands%s swapped)\n", i, swap ? "" : " not");
+		      mpf_trace ("x   ", x);
+		      mpf_trace ("y   ", y);
+		      mpf_trace ("got ", got);
+		      mpf_trace ("want", want);
+		      fail = 1;
+		    }
+		}
+	    }
+
+	  if (SIZ (y) == 1 || SIZ (y) == 0)
+	    {
+	      if (SIZ (x)) EXP (x) -= EXP (y) - (mp_exp_t) SIZ (y);
+	      if (SIZ (want)) EXP (want) -= EXP (y) - (mp_exp_t) SIZ (y);
+	      EXP (y) = (mp_exp_t) SIZ (y);
+
+	      if (mpf_fits_uint_p (x))
+		{
+		  mpf_sub_ui (got, x, mpf_get_ui (y));
+
+		  if (! refmpf_validate ("mpf_sub_ui", got, want))
+		    {
+		      printf ("check_data() wrong result at data[%d] (operands%s swapped)\n", i, swap ? "" : " not");
+		      mpf_trace ("x   ", x);
+		      mpf_trace ("y   ", y);
+		      mpf_trace ("got ", got);
+		      mpf_trace ("want", want);
+		      fail = 1;
+		    }
+		}
+	    }
+
+        }
+    }
+
+  mpf_clear (got);
+  if (fail)
+    abort ();
+}
+
+
+int
+main (int argc, char **argv)
+{
+  tests_start ();
+
+  check_data ();
+  check_rand (argc, argv);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpf/t-trunc.c b/third_party/gmp/tests/mpf/t-trunc.c
new file mode 100644
index 0000000..31fc2bd
--- /dev/null
+++ b/third_party/gmp/tests/mpf/t-trunc.c
@@ -0,0 +1,270 @@
+/* Test mpf_trunc, mpf_ceil, mpf_floor.
+
+Copyright 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_print (mpf_srcptr src, mpf_srcptr got, mpf_srcptr want)
+{
+  mp_trace_base = 16;
+  mpf_trace ("src ", src);
+  mpf_trace ("got ", got);
+  mpf_trace ("want", want);
+
+  printf ("got  size=%d exp=%ld\n", SIZ(got), EXP(got));
+  mpn_trace ("     limbs=", PTR(got), (mp_size_t) ABSIZ(got));
+
+  printf ("want size=%d exp=%ld\n", SIZ(want), EXP(want));
+  mpn_trace ("     limbs=", PTR(want), (mp_size_t) ABSIZ(want));
+}
+
+void
+check_one (mpf_srcptr src, mpf_srcptr trunc, mpf_srcptr ceil, mpf_srcptr floor)
+{
+  mpf_t  got;
+
+  mpf_init2 (got, mpf_get_prec (trunc));
+  ASSERT_ALWAYS (PREC(got) == PREC(trunc));
+  ASSERT_ALWAYS (PREC(got) == PREC(ceil));
+  ASSERT_ALWAYS (PREC(got) == PREC(floor));
+
+#define CHECK_SEP(name, fun, want)              \
+  mpf_set_ui (got, 54321L); /* initial junk */  \
+  fun (got, src);                               \
+  MPF_CHECK_FORMAT (got);                       \
+  if (mpf_cmp (got, want) != 0)                 \
+    {                                           \
+	printf ("%s wrong\n", name);            \
+	check_print (src, got, want);           \
+	abort ();                               \
+    }
+
+  CHECK_SEP ("mpf_trunc", mpf_trunc, trunc);
+  CHECK_SEP ("mpf_ceil",  mpf_ceil,  ceil);
+  CHECK_SEP ("mpf_floor", mpf_floor, floor);
+
+#define CHECK_INPLACE(name, fun, want)  \
+  mpf_set (got, src);                   \
+  fun (got, got);                       \
+  MPF_CHECK_FORMAT (got);               \
+  if (mpf_cmp (got, want) != 0)         \
+    {                                   \
+	printf ("%s wrong\n", name);    \
+	check_print (src, got, want);   \
+	abort ();                       \
+    }
+
+  CHECK_INPLACE ("mpf_trunc", mpf_trunc, trunc);
+
+  /* Can't do these unconditionally in case truncation by mpf_set strips
+     some low non-zero limbs which would have rounded the result.  */
+  if (ABSIZ(src) <= PREC(trunc)+1)
+    {
+      CHECK_INPLACE ("mpf_ceil",  mpf_ceil,  ceil);
+      CHECK_INPLACE ("mpf_floor", mpf_floor, floor);
+    }
+
+  mpf_clear (got);
+}
+
+void
+check_all (mpf_ptr src, mpf_ptr trunc, mpf_ptr ceil, mpf_ptr floor)
+{
+  /* some of these values are generated with direct field assignments */
+  MPF_CHECK_FORMAT (src);
+  MPF_CHECK_FORMAT (trunc);
+  MPF_CHECK_FORMAT (ceil);
+  MPF_CHECK_FORMAT (floor);
+
+  check_one (src, trunc, ceil, floor);
+
+  mpf_neg (src,   src);
+  mpf_neg (trunc, trunc);
+  mpf_neg (ceil,  ceil);
+  mpf_neg (floor, floor);
+  check_one (src, trunc, floor, ceil);
+}
+
+void
+check_various (void)
+{
+  mpf_t  src, trunc, ceil, floor;
+  int    n, i;
+
+  mpf_init2 (src, 512L);
+  mpf_init2 (trunc, 256L);
+  mpf_init2 (ceil,  256L);
+  mpf_init2 (floor, 256L);
+
+  /* 0 */
+  mpf_set_ui (src, 0L);
+  mpf_set_ui (trunc, 0L);
+  mpf_set_ui (ceil, 0L);
+  mpf_set_ui (floor, 0L);
+  check_all (src, trunc, ceil, floor);
+
+  /* 1 */
+  mpf_set_ui (src, 1L);
+  mpf_set_ui (trunc, 1L);
+  mpf_set_ui (ceil, 1L);
+  mpf_set_ui (floor, 1L);
+  check_all (src, trunc, ceil, floor);
+
+  /* 2^1024 */
+  mpf_set_ui (src, 1L);
+  mpf_mul_2exp (src,   src,   1024L);
+  mpf_set (trunc, src);
+  mpf_set (ceil,  src);
+  mpf_set (floor, src);
+  check_all (src, trunc, ceil, floor);
+
+  /* 1/2^1024, fraction only */
+  mpf_set_ui (src, 1L);
+  mpf_div_2exp (src,  src, 1024L);
+  mpf_set_si (trunc, 0L);
+  mpf_set_si (ceil, 1L);
+  mpf_set_si (floor, 0L);
+  check_all (src, trunc, ceil, floor);
+
+  /* 1/2 */
+  mpf_set_ui (src, 1L);
+  mpf_div_2exp (src,  src, 1L);
+  mpf_set_si (trunc, 0L);
+  mpf_set_si (ceil, 1L);
+  mpf_set_si (floor, 0L);
+  check_all (src, trunc, ceil, floor);
+
+  /* 123+1/2^64 */
+  mpf_set_ui (src, 1L);
+  mpf_div_2exp (src,  src, 64L);
+  mpf_add_ui (src,  src, 123L);
+  mpf_set_si (trunc, 123L);
+  mpf_set_si (ceil, 124L);
+  mpf_set_si (floor, 123L);
+  check_all (src, trunc, ceil, floor);
+
+  /* integer of full prec+1 limbs, unchanged */
+  n = PREC(trunc)+1;
+  ASSERT_ALWAYS (n <= PREC(src)+1);
+  EXP(src) = n;
+  SIZ(src) = n;
+  for (i = 0; i < SIZ(src); i++)
+    PTR(src)[i] = i+100;
+  mpf_set (trunc, src);
+  mpf_set (ceil, src);
+  mpf_set (floor, src);
+  check_all (src, trunc, ceil, floor);
+
+  /* full prec+1 limbs, 1 trimmed for integer */
+  n = PREC(trunc)+1;
+  ASSERT_ALWAYS (n <= PREC(src)+1);
+  EXP(src) = n-1;
+  SIZ(src) = n;
+  for (i = 0; i < SIZ(src); i++)
+    PTR(src)[i] = i+200;
+  EXP(trunc) = n-1;
+  SIZ(trunc) = n-1;
+  for (i = 0; i < SIZ(trunc); i++)
+    PTR(trunc)[i] = i+201;
+  mpf_set (floor, trunc);
+  mpf_add_ui (ceil, trunc, 1L);
+  check_all (src, trunc, ceil, floor);
+
+  /* prec+3 limbs, 2 trimmed for size */
+  n = PREC(trunc)+3;
+  ASSERT_ALWAYS (n <= PREC(src)+1);
+  EXP(src) = n;
+  SIZ(src) = n;
+  for (i = 0; i < SIZ(src); i++)
+    PTR(src)[i] = i+300;
+  EXP(trunc) = n;
+  SIZ(trunc) = n-2;
+  for (i = 0; i < SIZ(trunc); i++)
+    PTR(trunc)[i] = i+302;
+  mpf_set (floor, trunc);
+  mpf_set (ceil, trunc);
+  PTR(ceil)[0]++;
+  check_all (src, trunc, ceil, floor);
+
+  /* prec+4 limbs, 2 trimmed for size, 1 trimmed for integer */
+  n = PREC(trunc)+4;
+  ASSERT_ALWAYS (n <= PREC(src)+1);
+  EXP(src) = n-1;
+  SIZ(src) = n;
+  for (i = 0; i < SIZ(src); i++)
+    PTR(src)[i] = i+400;
+  EXP(trunc) = n-1;
+  SIZ(trunc) = n-3;
+  for (i = 0; i < SIZ(trunc); i++)
+    PTR(trunc)[i] = i+403;
+  mpf_set (floor, trunc);
+  mpf_set (ceil, trunc);
+  PTR(ceil)[0]++;
+  check_all (src, trunc, ceil, floor);
+
+  /* F.F, carry out of ceil */
+  EXP(src) = 1;
+  SIZ(src) = 2;
+  PTR(src)[0] = GMP_NUMB_MAX;
+  PTR(src)[1] = GMP_NUMB_MAX;
+  EXP(trunc) = 1;
+  SIZ(trunc) = 1;
+  PTR(trunc)[0] = GMP_NUMB_MAX;
+  mpf_set (floor, trunc);
+  EXP(ceil) = 2;
+  SIZ(ceil) = 1;
+  PTR(ceil)[0] = 1;
+  check_all (src, trunc, ceil, floor);
+
+  /* FF.F, carry out of ceil */
+  EXP(src) = 2;
+  SIZ(src) = 3;
+  PTR(src)[0] = GMP_NUMB_MAX;
+  PTR(src)[1] = GMP_NUMB_MAX;
+  PTR(src)[2] = GMP_NUMB_MAX;
+  EXP(trunc) = 2;
+  SIZ(trunc) = 2;
+  PTR(trunc)[0] = GMP_NUMB_MAX;
+  PTR(trunc)[1] = GMP_NUMB_MAX;
+  mpf_set (floor, trunc);
+  EXP(ceil) = 3;
+  SIZ(ceil) = 1;
+  PTR(ceil)[0] = 1;
+  check_all (src, trunc, ceil, floor);
+
+  mpf_clear (src);
+  mpf_clear (trunc);
+  mpf_clear (ceil);
+  mpf_clear (floor);
+}
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_various ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpf/t-ui_div.c b/third_party/gmp/tests/mpf/t-ui_div.c
new file mode 100644
index 0000000..4b86215
--- /dev/null
+++ b/third_party/gmp/tests/mpf/t-ui_div.c
@@ -0,0 +1,151 @@
+/* Test mpf_ui_div.
+
+Copyright 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_one (const char *desc, mpf_ptr got, unsigned long u, mpf_srcptr v)
+{
+  mpf_t      uf;
+  mp_limb_t  ulimbs[2];
+  mp_size_t  usize;
+
+  ulimbs[0] = u & GMP_NUMB_MASK;
+  usize = (u != 0);
+#if BITS_PER_ULONG > GMP_NUMB_BITS
+  u >>= GMP_NUMB_BITS;
+  ulimbs[1] = u;
+  usize += (u != 0);
+#endif
+  PTR(uf) = ulimbs;
+  SIZ(uf) = usize;
+  EXP(uf) = usize;
+
+  if (! refmpf_validate_division ("mpf_ui_div", got, uf, v))
+    {
+      mp_trace_base = -16;
+      printf    ("  u 0x%lX  (%lu)\n", u, u);
+      mpf_trace ("  v", v);
+      printf    ("  %s\n", desc);
+      abort ();
+    }
+}
+
+void
+check_rand (void)
+{
+  unsigned long  min_prec = __GMPF_BITS_TO_PREC (1);
+  gmp_randstate_ptr  rands = RANDS;
+  unsigned long  prec, u;
+  mpf_t  got, v;
+  int    i;
+
+  mpf_init (got);
+  mpf_init (v);
+
+  for (i = 0; i < 200; i++)
+    {
+      /* got precision */
+      prec = min_prec + gmp_urandomm_ui (rands, 15L);
+      refmpf_set_prec_limbs (got, prec);
+
+      /* u */
+      prec = gmp_urandomm_ui (rands, BITS_PER_ULONG+1);
+      u = gmp_urandomb_ui (rands, prec);
+
+      /* v precision */
+      prec = min_prec + gmp_urandomm_ui (rands, 15L);
+      refmpf_set_prec_limbs (v, prec);
+
+      /* v, non-zero */
+      do {
+        mpf_random2 (v, PREC(v), (mp_exp_t) 20);
+      } while (SIZ(v) == 0);
+
+      /* v possibly negative */
+      if (gmp_urandomb_ui (rands, 1L))
+        mpf_neg (v, v);
+
+      if ((i % 2) == 0)
+        {
+          /* src != dst */
+          mpf_ui_div (got, u, v);
+          check_one ("separate", got, u, v);
+        }
+      else
+        {
+          /* src == dst */
+          prec = refmpf_set_overlap (got, v);
+          mpf_ui_div (got, u, got);
+          check_one ("overlap src==dst", got, u, v);
+
+          mpf_set_prec_raw (got, prec);
+        }
+    }
+
+  mpf_clear (got);
+  mpf_clear (v);
+}
+
+void
+check_various (void)
+{
+  mpf_t got, v;
+
+  mpf_init (got);
+  mpf_init (v);
+
+  /* 100/4 == 25 */
+  mpf_set_prec (got, 20L);
+  mpf_set_ui (v, 4L);
+  mpf_ui_div (got, 100L, v);
+  MPF_CHECK_FORMAT (got);
+  ASSERT_ALWAYS (mpf_cmp_ui (got, 25L) == 0);
+
+  {
+    /* 1/(2^n+1), a case where truncating the divisor would be wrong */
+    unsigned long  u = 1L;
+    mpf_set_prec (got, 500L);
+    mpf_set_prec (v, 900L);
+    mpf_set_ui (v, 1L);
+    mpf_mul_2exp (v, v, 800L);
+    mpf_add_ui (v, v, 1L);
+    mpf_ui_div (got, u, v);
+    check_one ("1/2^n+1, separate", got, u, v);
+  }
+
+  mpf_clear (got);
+  mpf_clear (v);
+}
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_various ();
+  check_rand ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpn/Makefile.am b/third_party/gmp/tests/mpn/Makefile.am
new file mode 100644
index 0000000..dafeea8
--- /dev/null
+++ b/third_party/gmp/tests/mpn/Makefile.am
@@ -0,0 +1,39 @@
+## Process this file with automake to generate Makefile.in
+
+# Copyright 2001-2003, 2009-2014, 2018 Free Software Foundation, Inc.
+#
+# This file is part of the GNU MP Library test suite.
+#
+# The GNU MP Library test suite is free software; you can redistribute it
+# and/or modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 3 of the License,
+# or (at your option) any later version.
+#
+# The GNU MP Library test suite is distributed in the hope that it will be
+# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.
+
+
+AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/tests
+AM_LDFLAGS = -no-install
+LDADD = $(top_builddir)/tests/libtests.la $(top_builddir)/libgmp.la
+
+check_PROGRAMS = t-asmtype t-aors_1 t-divrem_1 t-mod_1 t-fat t-get_d	\
+  t-instrument t-iord_u t-mp_bases t-perfsqr t-scan logic		\
+  t-toom22 t-toom32 t-toom33 t-toom42 t-toom43 t-toom44			\
+  t-toom52 t-toom53 t-toom54 t-toom62 t-toom63 t-toom6h t-toom8h	\
+  t-toom2-sqr t-toom3-sqr t-toom4-sqr t-toom6-sqr t-toom8-sqr		\
+  t-div t-mul t-mullo t-sqrlo t-mulmod_bnm1 t-sqrmod_bnm1 t-mulmid	\
+  t-hgcd t-hgcd_appr t-matrix22 t-invert t-bdiv t-fib2m			\
+  t-broot t-brootinv t-minvert t-sizeinbase t-gcd_11 t-gcd_22 t-gcdext_1
+
+EXTRA_DIST = toom-shared.h toom-sqr-shared.h
+
+TESTS = $(check_PROGRAMS)
+
+$(top_builddir)/tests/libtests.la:
+	cd $(top_builddir)/tests; $(MAKE) $(AM_MAKEFLAGS) libtests.la
diff --git a/third_party/gmp/tests/mpn/Makefile.in b/third_party/gmp/tests/mpn/Makefile.in
new file mode 100644
index 0000000..aecb3bb
--- /dev/null
+++ b/third_party/gmp/tests/mpn/Makefile.in
@@ -0,0 +1,1822 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Copyright 2001-2003, 2009-2014, 2018 Free Software Foundation, Inc.
+#
+# This file is part of the GNU MP Library test suite.
+#
+# The GNU MP Library test suite is free software; you can redistribute it
+# and/or modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 3 of the License,
+# or (at your option) any later version.
+#
+# The GNU MP Library test suite is distributed in the hope that it will be
+# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+check_PROGRAMS = t-asmtype$(EXEEXT) t-aors_1$(EXEEXT) \
+	t-divrem_1$(EXEEXT) t-mod_1$(EXEEXT) t-fat$(EXEEXT) \
+	t-get_d$(EXEEXT) t-instrument$(EXEEXT) t-iord_u$(EXEEXT) \
+	t-mp_bases$(EXEEXT) t-perfsqr$(EXEEXT) t-scan$(EXEEXT) \
+	logic$(EXEEXT) t-toom22$(EXEEXT) t-toom32$(EXEEXT) \
+	t-toom33$(EXEEXT) t-toom42$(EXEEXT) t-toom43$(EXEEXT) \
+	t-toom44$(EXEEXT) t-toom52$(EXEEXT) t-toom53$(EXEEXT) \
+	t-toom54$(EXEEXT) t-toom62$(EXEEXT) t-toom63$(EXEEXT) \
+	t-toom6h$(EXEEXT) t-toom8h$(EXEEXT) t-toom2-sqr$(EXEEXT) \
+	t-toom3-sqr$(EXEEXT) t-toom4-sqr$(EXEEXT) t-toom6-sqr$(EXEEXT) \
+	t-toom8-sqr$(EXEEXT) t-div$(EXEEXT) t-mul$(EXEEXT) \
+	t-mullo$(EXEEXT) t-sqrlo$(EXEEXT) t-mulmod_bnm1$(EXEEXT) \
+	t-sqrmod_bnm1$(EXEEXT) t-mulmid$(EXEEXT) t-hgcd$(EXEEXT) \
+	t-hgcd_appr$(EXEEXT) t-matrix22$(EXEEXT) t-invert$(EXEEXT) \
+	t-bdiv$(EXEEXT) t-fib2m$(EXEEXT) t-broot$(EXEEXT) \
+	t-brootinv$(EXEEXT) t-minvert$(EXEEXT) t-sizeinbase$(EXEEXT) \
+	t-gcd_11$(EXEEXT) t-gcd_22$(EXEEXT) t-gcdext_1$(EXEEXT)
+subdir = tests/mpn
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+logic_SOURCES = logic.c
+logic_OBJECTS = logic.$(OBJEXT)
+logic_LDADD = $(LDADD)
+logic_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+t_aors_1_SOURCES = t-aors_1.c
+t_aors_1_OBJECTS = t-aors_1.$(OBJEXT)
+t_aors_1_LDADD = $(LDADD)
+t_aors_1_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_asmtype_SOURCES = t-asmtype.c
+t_asmtype_OBJECTS = t-asmtype.$(OBJEXT)
+t_asmtype_LDADD = $(LDADD)
+t_asmtype_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_bdiv_SOURCES = t-bdiv.c
+t_bdiv_OBJECTS = t-bdiv.$(OBJEXT)
+t_bdiv_LDADD = $(LDADD)
+t_bdiv_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_broot_SOURCES = t-broot.c
+t_broot_OBJECTS = t-broot.$(OBJEXT)
+t_broot_LDADD = $(LDADD)
+t_broot_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_brootinv_SOURCES = t-brootinv.c
+t_brootinv_OBJECTS = t-brootinv.$(OBJEXT)
+t_brootinv_LDADD = $(LDADD)
+t_brootinv_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_div_SOURCES = t-div.c
+t_div_OBJECTS = t-div.$(OBJEXT)
+t_div_LDADD = $(LDADD)
+t_div_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_divrem_1_SOURCES = t-divrem_1.c
+t_divrem_1_OBJECTS = t-divrem_1.$(OBJEXT)
+t_divrem_1_LDADD = $(LDADD)
+t_divrem_1_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_fat_SOURCES = t-fat.c
+t_fat_OBJECTS = t-fat.$(OBJEXT)
+t_fat_LDADD = $(LDADD)
+t_fat_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_fib2m_SOURCES = t-fib2m.c
+t_fib2m_OBJECTS = t-fib2m.$(OBJEXT)
+t_fib2m_LDADD = $(LDADD)
+t_fib2m_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_gcd_11_SOURCES = t-gcd_11.c
+t_gcd_11_OBJECTS = t-gcd_11.$(OBJEXT)
+t_gcd_11_LDADD = $(LDADD)
+t_gcd_11_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_gcd_22_SOURCES = t-gcd_22.c
+t_gcd_22_OBJECTS = t-gcd_22.$(OBJEXT)
+t_gcd_22_LDADD = $(LDADD)
+t_gcd_22_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_gcdext_1_SOURCES = t-gcdext_1.c
+t_gcdext_1_OBJECTS = t-gcdext_1.$(OBJEXT)
+t_gcdext_1_LDADD = $(LDADD)
+t_gcdext_1_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_get_d_SOURCES = t-get_d.c
+t_get_d_OBJECTS = t-get_d.$(OBJEXT)
+t_get_d_LDADD = $(LDADD)
+t_get_d_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_hgcd_SOURCES = t-hgcd.c
+t_hgcd_OBJECTS = t-hgcd.$(OBJEXT)
+t_hgcd_LDADD = $(LDADD)
+t_hgcd_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_hgcd_appr_SOURCES = t-hgcd_appr.c
+t_hgcd_appr_OBJECTS = t-hgcd_appr.$(OBJEXT)
+t_hgcd_appr_LDADD = $(LDADD)
+t_hgcd_appr_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_instrument_SOURCES = t-instrument.c
+t_instrument_OBJECTS = t-instrument.$(OBJEXT)
+t_instrument_LDADD = $(LDADD)
+t_instrument_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_invert_SOURCES = t-invert.c
+t_invert_OBJECTS = t-invert.$(OBJEXT)
+t_invert_LDADD = $(LDADD)
+t_invert_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_iord_u_SOURCES = t-iord_u.c
+t_iord_u_OBJECTS = t-iord_u.$(OBJEXT)
+t_iord_u_LDADD = $(LDADD)
+t_iord_u_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_matrix22_SOURCES = t-matrix22.c
+t_matrix22_OBJECTS = t-matrix22.$(OBJEXT)
+t_matrix22_LDADD = $(LDADD)
+t_matrix22_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_minvert_SOURCES = t-minvert.c
+t_minvert_OBJECTS = t-minvert.$(OBJEXT)
+t_minvert_LDADD = $(LDADD)
+t_minvert_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_mod_1_SOURCES = t-mod_1.c
+t_mod_1_OBJECTS = t-mod_1.$(OBJEXT)
+t_mod_1_LDADD = $(LDADD)
+t_mod_1_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_mp_bases_SOURCES = t-mp_bases.c
+t_mp_bases_OBJECTS = t-mp_bases.$(OBJEXT)
+t_mp_bases_LDADD = $(LDADD)
+t_mp_bases_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_mul_SOURCES = t-mul.c
+t_mul_OBJECTS = t-mul.$(OBJEXT)
+t_mul_LDADD = $(LDADD)
+t_mul_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_mullo_SOURCES = t-mullo.c
+t_mullo_OBJECTS = t-mullo.$(OBJEXT)
+t_mullo_LDADD = $(LDADD)
+t_mullo_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_mulmid_SOURCES = t-mulmid.c
+t_mulmid_OBJECTS = t-mulmid.$(OBJEXT)
+t_mulmid_LDADD = $(LDADD)
+t_mulmid_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_mulmod_bnm1_SOURCES = t-mulmod_bnm1.c
+t_mulmod_bnm1_OBJECTS = t-mulmod_bnm1.$(OBJEXT)
+t_mulmod_bnm1_LDADD = $(LDADD)
+t_mulmod_bnm1_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_perfsqr_SOURCES = t-perfsqr.c
+t_perfsqr_OBJECTS = t-perfsqr.$(OBJEXT)
+t_perfsqr_LDADD = $(LDADD)
+t_perfsqr_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_scan_SOURCES = t-scan.c
+t_scan_OBJECTS = t-scan.$(OBJEXT)
+t_scan_LDADD = $(LDADD)
+t_scan_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_sizeinbase_SOURCES = t-sizeinbase.c
+t_sizeinbase_OBJECTS = t-sizeinbase.$(OBJEXT)
+t_sizeinbase_LDADD = $(LDADD)
+t_sizeinbase_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_sqrlo_SOURCES = t-sqrlo.c
+t_sqrlo_OBJECTS = t-sqrlo.$(OBJEXT)
+t_sqrlo_LDADD = $(LDADD)
+t_sqrlo_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_sqrmod_bnm1_SOURCES = t-sqrmod_bnm1.c
+t_sqrmod_bnm1_OBJECTS = t-sqrmod_bnm1.$(OBJEXT)
+t_sqrmod_bnm1_LDADD = $(LDADD)
+t_sqrmod_bnm1_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_toom2_sqr_SOURCES = t-toom2-sqr.c
+t_toom2_sqr_OBJECTS = t-toom2-sqr.$(OBJEXT)
+t_toom2_sqr_LDADD = $(LDADD)
+t_toom2_sqr_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_toom22_SOURCES = t-toom22.c
+t_toom22_OBJECTS = t-toom22.$(OBJEXT)
+t_toom22_LDADD = $(LDADD)
+t_toom22_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_toom3_sqr_SOURCES = t-toom3-sqr.c
+t_toom3_sqr_OBJECTS = t-toom3-sqr.$(OBJEXT)
+t_toom3_sqr_LDADD = $(LDADD)
+t_toom3_sqr_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_toom32_SOURCES = t-toom32.c
+t_toom32_OBJECTS = t-toom32.$(OBJEXT)
+t_toom32_LDADD = $(LDADD)
+t_toom32_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_toom33_SOURCES = t-toom33.c
+t_toom33_OBJECTS = t-toom33.$(OBJEXT)
+t_toom33_LDADD = $(LDADD)
+t_toom33_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_toom4_sqr_SOURCES = t-toom4-sqr.c
+t_toom4_sqr_OBJECTS = t-toom4-sqr.$(OBJEXT)
+t_toom4_sqr_LDADD = $(LDADD)
+t_toom4_sqr_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_toom42_SOURCES = t-toom42.c
+t_toom42_OBJECTS = t-toom42.$(OBJEXT)
+t_toom42_LDADD = $(LDADD)
+t_toom42_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_toom43_SOURCES = t-toom43.c
+t_toom43_OBJECTS = t-toom43.$(OBJEXT)
+t_toom43_LDADD = $(LDADD)
+t_toom43_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_toom44_SOURCES = t-toom44.c
+t_toom44_OBJECTS = t-toom44.$(OBJEXT)
+t_toom44_LDADD = $(LDADD)
+t_toom44_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_toom52_SOURCES = t-toom52.c
+t_toom52_OBJECTS = t-toom52.$(OBJEXT)
+t_toom52_LDADD = $(LDADD)
+t_toom52_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_toom53_SOURCES = t-toom53.c
+t_toom53_OBJECTS = t-toom53.$(OBJEXT)
+t_toom53_LDADD = $(LDADD)
+t_toom53_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_toom54_SOURCES = t-toom54.c
+t_toom54_OBJECTS = t-toom54.$(OBJEXT)
+t_toom54_LDADD = $(LDADD)
+t_toom54_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_toom6_sqr_SOURCES = t-toom6-sqr.c
+t_toom6_sqr_OBJECTS = t-toom6-sqr.$(OBJEXT)
+t_toom6_sqr_LDADD = $(LDADD)
+t_toom6_sqr_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_toom62_SOURCES = t-toom62.c
+t_toom62_OBJECTS = t-toom62.$(OBJEXT)
+t_toom62_LDADD = $(LDADD)
+t_toom62_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_toom63_SOURCES = t-toom63.c
+t_toom63_OBJECTS = t-toom63.$(OBJEXT)
+t_toom63_LDADD = $(LDADD)
+t_toom63_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_toom6h_SOURCES = t-toom6h.c
+t_toom6h_OBJECTS = t-toom6h.$(OBJEXT)
+t_toom6h_LDADD = $(LDADD)
+t_toom6h_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_toom8_sqr_SOURCES = t-toom8-sqr.c
+t_toom8_sqr_OBJECTS = t-toom8-sqr.$(OBJEXT)
+t_toom8_sqr_LDADD = $(LDADD)
+t_toom8_sqr_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_toom8h_SOURCES = t-toom8h.c
+t_toom8h_OBJECTS = t-toom8h.$(OBJEXT)
+t_toom8h_LDADD = $(LDADD)
+t_toom8h_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp =
+am__depfiles_maybe =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+SOURCES = logic.c t-aors_1.c t-asmtype.c t-bdiv.c t-broot.c \
+	t-brootinv.c t-div.c t-divrem_1.c t-fat.c t-fib2m.c t-gcd_11.c \
+	t-gcd_22.c t-gcdext_1.c t-get_d.c t-hgcd.c t-hgcd_appr.c \
+	t-instrument.c t-invert.c t-iord_u.c t-matrix22.c t-minvert.c \
+	t-mod_1.c t-mp_bases.c t-mul.c t-mullo.c t-mulmid.c \
+	t-mulmod_bnm1.c t-perfsqr.c t-scan.c t-sizeinbase.c t-sqrlo.c \
+	t-sqrmod_bnm1.c t-toom2-sqr.c t-toom22.c t-toom3-sqr.c \
+	t-toom32.c t-toom33.c t-toom4-sqr.c t-toom42.c t-toom43.c \
+	t-toom44.c t-toom52.c t-toom53.c t-toom54.c t-toom6-sqr.c \
+	t-toom62.c t-toom63.c t-toom6h.c t-toom8-sqr.c t-toom8h.c
+DIST_SOURCES = logic.c t-aors_1.c t-asmtype.c t-bdiv.c t-broot.c \
+	t-brootinv.c t-div.c t-divrem_1.c t-fat.c t-fib2m.c t-gcd_11.c \
+	t-gcd_22.c t-gcdext_1.c t-get_d.c t-hgcd.c t-hgcd_appr.c \
+	t-instrument.c t-invert.c t-iord_u.c t-matrix22.c t-minvert.c \
+	t-mod_1.c t-mp_bases.c t-mul.c t-mullo.c t-mulmid.c \
+	t-mulmod_bnm1.c t-perfsqr.c t-scan.c t-sizeinbase.c t-sqrlo.c \
+	t-sqrmod_bnm1.c t-toom2-sqr.c t-toom22.c t-toom3-sqr.c \
+	t-toom32.c t-toom33.c t-toom4-sqr.c t-toom42.c t-toom43.c \
+	t-toom44.c t-toom52.c t-toom53.c t-toom54.c t-toom6-sqr.c \
+	t-toom62.c t-toom63.c t-toom6h.c t-toom8-sqr.c t-toom8h.c
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__tty_colors_dummy = \
+  mgn= red= grn= lgn= blu= brg= std=; \
+  am__color_tests=no
+am__tty_colors = { \
+  $(am__tty_colors_dummy); \
+  if test "X$(AM_COLOR_TESTS)" = Xno; then \
+    am__color_tests=no; \
+  elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+    am__color_tests=yes; \
+  elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+    am__color_tests=yes; \
+  fi; \
+  if test $$am__color_tests = yes; then \
+    red=''; \
+    grn=''; \
+    lgn=''; \
+    blu=''; \
+    mgn=''; \
+    brg=''; \
+    std=''; \
+  fi; \
+}
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+  test -z "$$files" \
+    || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+    || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+         $(am__cd) "$$dir" && rm -f $$files; }; \
+  }
+am__recheck_rx = ^[ 	]*:recheck:[ 	]*
+am__global_test_result_rx = ^[ 	]*:global-test-result:[ 	]*
+am__copy_in_global_log_rx = ^[ 	]*:copy-in-global-log:[ 	]*
+# A command that, given a newline-separated list of test names on the
+# standard input, print the name of the tests that are to be re-run
+# upon "make recheck".
+am__list_recheck_tests = $(AWK) '{ \
+  recheck = 1; \
+  while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+    { \
+      if (rc < 0) \
+        { \
+          if ((getline line2 < ($$0 ".log")) < 0) \
+	    recheck = 0; \
+          break; \
+        } \
+      else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \
+        { \
+          recheck = 0; \
+          break; \
+        } \
+      else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \
+        { \
+          break; \
+        } \
+    }; \
+  if (recheck) \
+    print $$0; \
+  close ($$0 ".trs"); \
+  close ($$0 ".log"); \
+}'
+# A command that, given a newline-separated list of test names on the
+# standard input, create the global log from their .trs and .log files.
+am__create_global_log = $(AWK) ' \
+function fatal(msg) \
+{ \
+  print "fatal: making $@: " msg | "cat >&2"; \
+  exit 1; \
+} \
+function rst_section(header) \
+{ \
+  print header; \
+  len = length(header); \
+  for (i = 1; i <= len; i = i + 1) \
+    printf "="; \
+  printf "\n\n"; \
+} \
+{ \
+  copy_in_global_log = 1; \
+  global_test_result = "RUN"; \
+  while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+    { \
+      if (rc < 0) \
+         fatal("failed to read from " $$0 ".trs"); \
+      if (line ~ /$(am__global_test_result_rx)/) \
+        { \
+          sub("$(am__global_test_result_rx)", "", line); \
+          sub("[ 	]*$$", "", line); \
+          global_test_result = line; \
+        } \
+      else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \
+        copy_in_global_log = 0; \
+    }; \
+  if (copy_in_global_log) \
+    { \
+      rst_section(global_test_result ": " $$0); \
+      while ((rc = (getline line < ($$0 ".log"))) != 0) \
+      { \
+        if (rc < 0) \
+          fatal("failed to read from " $$0 ".log"); \
+        print line; \
+      }; \
+      printf "\n"; \
+    }; \
+  close ($$0 ".trs"); \
+  close ($$0 ".log"); \
+}'
+# Restructured Text title.
+am__rst_title = { sed 's/.*/   &   /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; }
+# Solaris 10 'make', and several other traditional 'make' implementations,
+# pass "-e" to $(SHELL), and POSIX 2008 even requires this.  Work around it
+# by disabling -e (using the XSI extension "set +e") if it's set.
+am__sh_e_setup = case $$- in *e*) set +e;; esac
+# Default flags passed to test drivers.
+am__common_driver_flags = \
+  --color-tests "$$am__color_tests" \
+  --enable-hard-errors "$$am__enable_hard_errors" \
+  --expect-failure "$$am__expect_failure"
+# To be inserted before the command running the test.  Creates the
+# directory for the log if needed.  Stores in $dir the directory
+# containing $f, in $tst the test, in $log the log.  Executes the
+# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and
+# passes TESTS_ENVIRONMENT.  Set up options for the wrapper that
+# will run the test scripts (or their associated LOG_COMPILER, if
+# thy have one).
+am__check_pre = \
+$(am__sh_e_setup);					\
+$(am__vpath_adj_setup) $(am__vpath_adj)			\
+$(am__tty_colors);					\
+srcdir=$(srcdir); export srcdir;			\
+case "$@" in						\
+  */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;;	\
+    *) am__odir=.;; 					\
+esac;							\
+test "x$$am__odir" = x"." || test -d "$$am__odir" 	\
+  || $(MKDIR_P) "$$am__odir" || exit $$?;		\
+if test -f "./$$f"; then dir=./;			\
+elif test -f "$$f"; then dir=;				\
+else dir="$(srcdir)/"; fi;				\
+tst=$$dir$$f; log='$@'; 				\
+if test -n '$(DISABLE_HARD_ERRORS)'; then		\
+  am__enable_hard_errors=no; 				\
+else							\
+  am__enable_hard_errors=yes; 				\
+fi; 							\
+case " $(XFAIL_TESTS) " in				\
+  *[\ \	]$$f[\ \	]* | *[\ \	]$$dir$$f[\ \	]*) \
+    am__expect_failure=yes;;				\
+  *)							\
+    am__expect_failure=no;;				\
+esac; 							\
+$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT)
+# A shell command to get the names of the tests scripts with any registered
+# extension removed (i.e., equivalently, the names of the test logs, with
+# the '.log' extension removed).  The result is saved in the shell variable
+# '$bases'.  This honors runtime overriding of TESTS and TEST_LOGS.  Sadly,
+# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)",
+# since that might cause problem with VPATH rewrites for suffix-less tests.
+# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'.
+am__set_TESTS_bases = \
+  bases='$(TEST_LOGS)'; \
+  bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \
+  bases=`echo $$bases`
+RECHECK_LOGS = $(TEST_LOGS)
+AM_RECURSIVE_TARGETS = check recheck
+TEST_SUITE_LOG = test-suite.log
+TEST_EXTENSIONS = @EXEEXT@ .test
+LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS)
+am__set_b = \
+  case '$@' in \
+    */*) \
+      case '$*' in \
+        */*) b='$*';; \
+          *) b=`echo '$@' | sed 's/\.log$$//'`; \
+       esac;; \
+    *) \
+      b='$*';; \
+  esac
+am__test_logs1 = $(TESTS:=.log)
+am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log)
+TEST_LOGS = $(am__test_logs2:.test.log=.log)
+TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \
+	$(TEST_LOG_FLAGS)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/test-driver
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ABI = @ABI@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+ASMFLAGS = @ASMFLAGS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CALLING_CONVENTIONS_OBJS = @CALLING_CONVENTIONS_OBJS@
+CC = @CC@
+CCAS = @CCAS@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPP_FOR_BUILD = @CPP_FOR_BUILD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFN_LONG_LONG_LIMB = @DEFN_LONG_LONG_LIMB@
+DEFS = @DEFS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@
+FGREP = @FGREP@
+GMP_LDFLAGS = @GMP_LDFLAGS@
+GMP_LIMB_BITS = @GMP_LIMB_BITS@
+GMP_NAIL_BITS = @GMP_NAIL_BITS@
+GREP = @GREP@
+HAVE_CLOCK_01 = @HAVE_CLOCK_01@
+HAVE_CPUTIME_01 = @HAVE_CPUTIME_01@
+HAVE_GETRUSAGE_01 = @HAVE_GETRUSAGE_01@
+HAVE_GETTIMEOFDAY_01 = @HAVE_GETTIMEOFDAY_01@
+HAVE_HOST_CPU_FAMILY_power = @HAVE_HOST_CPU_FAMILY_power@
+HAVE_HOST_CPU_FAMILY_powerpc = @HAVE_HOST_CPU_FAMILY_powerpc@
+HAVE_SIGACTION_01 = @HAVE_SIGACTION_01@
+HAVE_SIGALTSTACK_01 = @HAVE_SIGALTSTACK_01@
+HAVE_SIGSTACK_01 = @HAVE_SIGSTACK_01@
+HAVE_STACK_T_01 = @HAVE_STACK_T_01@
+HAVE_SYS_RESOURCE_H_01 = @HAVE_SYS_RESOURCE_H_01@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCURSES = @LIBCURSES@
+LIBGMPXX_LDFLAGS = @LIBGMPXX_LDFLAGS@
+LIBGMP_DLL = @LIBGMP_DLL@
+LIBGMP_LDFLAGS = @LIBGMP_LDFLAGS@
+LIBM = @LIBM@
+LIBM_FOR_BUILD = @LIBM_FOR_BUILD@
+LIBOBJS = @LIBOBJS@
+LIBREADLINE = @LIBREADLINE@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+M4 = @M4@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPEED_CYCLECOUNTER_OBJ = @SPEED_CYCLECOUNTER_OBJ@
+STRIP = @STRIP@
+TAL_OBJECT = @TAL_OBJECT@
+TUNE_LIBS = @TUNE_LIBS@
+TUNE_SQR_OBJ = @TUNE_SQR_OBJ@
+U_FOR_BUILD = @U_FOR_BUILD@
+VERSION = @VERSION@
+WITH_READLINE_01 = @WITH_READLINE_01@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__leading_dot = @am__leading_dot@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gmp_srclinks = @gmp_srclinks@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+mpn_objects = @mpn_objects@
+mpn_objs_in_libgmp = @mpn_objs_in_libgmp@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/tests
+AM_LDFLAGS = -no-install
+LDADD = $(top_builddir)/tests/libtests.la $(top_builddir)/libgmp.la
+EXTRA_DIST = toom-shared.h toom-sqr-shared.h
+TESTS = $(check_PROGRAMS)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .log .o .obj .test .test$(EXEEXT) .trs
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu --ignore-deps tests/mpn/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu --ignore-deps tests/mpn/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-checkPROGRAMS:
+	@list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
+	echo " rm -f" $$list; \
+	rm -f $$list || exit $$?; \
+	test -n "$(EXEEXT)" || exit 0; \
+	list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+	echo " rm -f" $$list; \
+	rm -f $$list
+
+logic$(EXEEXT): $(logic_OBJECTS) $(logic_DEPENDENCIES) $(EXTRA_logic_DEPENDENCIES) 
+	@rm -f logic$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(logic_OBJECTS) $(logic_LDADD) $(LIBS)
+
+t-aors_1$(EXEEXT): $(t_aors_1_OBJECTS) $(t_aors_1_DEPENDENCIES) $(EXTRA_t_aors_1_DEPENDENCIES) 
+	@rm -f t-aors_1$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_aors_1_OBJECTS) $(t_aors_1_LDADD) $(LIBS)
+
+t-asmtype$(EXEEXT): $(t_asmtype_OBJECTS) $(t_asmtype_DEPENDENCIES) $(EXTRA_t_asmtype_DEPENDENCIES) 
+	@rm -f t-asmtype$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_asmtype_OBJECTS) $(t_asmtype_LDADD) $(LIBS)
+
+t-bdiv$(EXEEXT): $(t_bdiv_OBJECTS) $(t_bdiv_DEPENDENCIES) $(EXTRA_t_bdiv_DEPENDENCIES) 
+	@rm -f t-bdiv$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_bdiv_OBJECTS) $(t_bdiv_LDADD) $(LIBS)
+
+t-broot$(EXEEXT): $(t_broot_OBJECTS) $(t_broot_DEPENDENCIES) $(EXTRA_t_broot_DEPENDENCIES) 
+	@rm -f t-broot$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_broot_OBJECTS) $(t_broot_LDADD) $(LIBS)
+
+t-brootinv$(EXEEXT): $(t_brootinv_OBJECTS) $(t_brootinv_DEPENDENCIES) $(EXTRA_t_brootinv_DEPENDENCIES) 
+	@rm -f t-brootinv$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_brootinv_OBJECTS) $(t_brootinv_LDADD) $(LIBS)
+
+t-div$(EXEEXT): $(t_div_OBJECTS) $(t_div_DEPENDENCIES) $(EXTRA_t_div_DEPENDENCIES) 
+	@rm -f t-div$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_div_OBJECTS) $(t_div_LDADD) $(LIBS)
+
+t-divrem_1$(EXEEXT): $(t_divrem_1_OBJECTS) $(t_divrem_1_DEPENDENCIES) $(EXTRA_t_divrem_1_DEPENDENCIES) 
+	@rm -f t-divrem_1$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_divrem_1_OBJECTS) $(t_divrem_1_LDADD) $(LIBS)
+
+t-fat$(EXEEXT): $(t_fat_OBJECTS) $(t_fat_DEPENDENCIES) $(EXTRA_t_fat_DEPENDENCIES) 
+	@rm -f t-fat$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_fat_OBJECTS) $(t_fat_LDADD) $(LIBS)
+
+t-fib2m$(EXEEXT): $(t_fib2m_OBJECTS) $(t_fib2m_DEPENDENCIES) $(EXTRA_t_fib2m_DEPENDENCIES) 
+	@rm -f t-fib2m$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_fib2m_OBJECTS) $(t_fib2m_LDADD) $(LIBS)
+
+t-gcd_11$(EXEEXT): $(t_gcd_11_OBJECTS) $(t_gcd_11_DEPENDENCIES) $(EXTRA_t_gcd_11_DEPENDENCIES) 
+	@rm -f t-gcd_11$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_gcd_11_OBJECTS) $(t_gcd_11_LDADD) $(LIBS)
+
+t-gcd_22$(EXEEXT): $(t_gcd_22_OBJECTS) $(t_gcd_22_DEPENDENCIES) $(EXTRA_t_gcd_22_DEPENDENCIES) 
+	@rm -f t-gcd_22$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_gcd_22_OBJECTS) $(t_gcd_22_LDADD) $(LIBS)
+
+t-gcdext_1$(EXEEXT): $(t_gcdext_1_OBJECTS) $(t_gcdext_1_DEPENDENCIES) $(EXTRA_t_gcdext_1_DEPENDENCIES) 
+	@rm -f t-gcdext_1$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_gcdext_1_OBJECTS) $(t_gcdext_1_LDADD) $(LIBS)
+
+t-get_d$(EXEEXT): $(t_get_d_OBJECTS) $(t_get_d_DEPENDENCIES) $(EXTRA_t_get_d_DEPENDENCIES) 
+	@rm -f t-get_d$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_get_d_OBJECTS) $(t_get_d_LDADD) $(LIBS)
+
+t-hgcd$(EXEEXT): $(t_hgcd_OBJECTS) $(t_hgcd_DEPENDENCIES) $(EXTRA_t_hgcd_DEPENDENCIES) 
+	@rm -f t-hgcd$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_hgcd_OBJECTS) $(t_hgcd_LDADD) $(LIBS)
+
+t-hgcd_appr$(EXEEXT): $(t_hgcd_appr_OBJECTS) $(t_hgcd_appr_DEPENDENCIES) $(EXTRA_t_hgcd_appr_DEPENDENCIES) 
+	@rm -f t-hgcd_appr$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_hgcd_appr_OBJECTS) $(t_hgcd_appr_LDADD) $(LIBS)
+
+t-instrument$(EXEEXT): $(t_instrument_OBJECTS) $(t_instrument_DEPENDENCIES) $(EXTRA_t_instrument_DEPENDENCIES) 
+	@rm -f t-instrument$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_instrument_OBJECTS) $(t_instrument_LDADD) $(LIBS)
+
+t-invert$(EXEEXT): $(t_invert_OBJECTS) $(t_invert_DEPENDENCIES) $(EXTRA_t_invert_DEPENDENCIES) 
+	@rm -f t-invert$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_invert_OBJECTS) $(t_invert_LDADD) $(LIBS)
+
+t-iord_u$(EXEEXT): $(t_iord_u_OBJECTS) $(t_iord_u_DEPENDENCIES) $(EXTRA_t_iord_u_DEPENDENCIES) 
+	@rm -f t-iord_u$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_iord_u_OBJECTS) $(t_iord_u_LDADD) $(LIBS)
+
+t-matrix22$(EXEEXT): $(t_matrix22_OBJECTS) $(t_matrix22_DEPENDENCIES) $(EXTRA_t_matrix22_DEPENDENCIES) 
+	@rm -f t-matrix22$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_matrix22_OBJECTS) $(t_matrix22_LDADD) $(LIBS)
+
+t-minvert$(EXEEXT): $(t_minvert_OBJECTS) $(t_minvert_DEPENDENCIES) $(EXTRA_t_minvert_DEPENDENCIES) 
+	@rm -f t-minvert$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_minvert_OBJECTS) $(t_minvert_LDADD) $(LIBS)
+
+t-mod_1$(EXEEXT): $(t_mod_1_OBJECTS) $(t_mod_1_DEPENDENCIES) $(EXTRA_t_mod_1_DEPENDENCIES) 
+	@rm -f t-mod_1$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_mod_1_OBJECTS) $(t_mod_1_LDADD) $(LIBS)
+
+t-mp_bases$(EXEEXT): $(t_mp_bases_OBJECTS) $(t_mp_bases_DEPENDENCIES) $(EXTRA_t_mp_bases_DEPENDENCIES) 
+	@rm -f t-mp_bases$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_mp_bases_OBJECTS) $(t_mp_bases_LDADD) $(LIBS)
+
+t-mul$(EXEEXT): $(t_mul_OBJECTS) $(t_mul_DEPENDENCIES) $(EXTRA_t_mul_DEPENDENCIES) 
+	@rm -f t-mul$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_mul_OBJECTS) $(t_mul_LDADD) $(LIBS)
+
+t-mullo$(EXEEXT): $(t_mullo_OBJECTS) $(t_mullo_DEPENDENCIES) $(EXTRA_t_mullo_DEPENDENCIES) 
+	@rm -f t-mullo$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_mullo_OBJECTS) $(t_mullo_LDADD) $(LIBS)
+
+t-mulmid$(EXEEXT): $(t_mulmid_OBJECTS) $(t_mulmid_DEPENDENCIES) $(EXTRA_t_mulmid_DEPENDENCIES) 
+	@rm -f t-mulmid$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_mulmid_OBJECTS) $(t_mulmid_LDADD) $(LIBS)
+
+t-mulmod_bnm1$(EXEEXT): $(t_mulmod_bnm1_OBJECTS) $(t_mulmod_bnm1_DEPENDENCIES) $(EXTRA_t_mulmod_bnm1_DEPENDENCIES) 
+	@rm -f t-mulmod_bnm1$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_mulmod_bnm1_OBJECTS) $(t_mulmod_bnm1_LDADD) $(LIBS)
+
+t-perfsqr$(EXEEXT): $(t_perfsqr_OBJECTS) $(t_perfsqr_DEPENDENCIES) $(EXTRA_t_perfsqr_DEPENDENCIES) 
+	@rm -f t-perfsqr$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_perfsqr_OBJECTS) $(t_perfsqr_LDADD) $(LIBS)
+
+t-scan$(EXEEXT): $(t_scan_OBJECTS) $(t_scan_DEPENDENCIES) $(EXTRA_t_scan_DEPENDENCIES) 
+	@rm -f t-scan$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_scan_OBJECTS) $(t_scan_LDADD) $(LIBS)
+
+t-sizeinbase$(EXEEXT): $(t_sizeinbase_OBJECTS) $(t_sizeinbase_DEPENDENCIES) $(EXTRA_t_sizeinbase_DEPENDENCIES) 
+	@rm -f t-sizeinbase$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_sizeinbase_OBJECTS) $(t_sizeinbase_LDADD) $(LIBS)
+
+t-sqrlo$(EXEEXT): $(t_sqrlo_OBJECTS) $(t_sqrlo_DEPENDENCIES) $(EXTRA_t_sqrlo_DEPENDENCIES) 
+	@rm -f t-sqrlo$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_sqrlo_OBJECTS) $(t_sqrlo_LDADD) $(LIBS)
+
+t-sqrmod_bnm1$(EXEEXT): $(t_sqrmod_bnm1_OBJECTS) $(t_sqrmod_bnm1_DEPENDENCIES) $(EXTRA_t_sqrmod_bnm1_DEPENDENCIES) 
+	@rm -f t-sqrmod_bnm1$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_sqrmod_bnm1_OBJECTS) $(t_sqrmod_bnm1_LDADD) $(LIBS)
+
+t-toom2-sqr$(EXEEXT): $(t_toom2_sqr_OBJECTS) $(t_toom2_sqr_DEPENDENCIES) $(EXTRA_t_toom2_sqr_DEPENDENCIES) 
+	@rm -f t-toom2-sqr$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_toom2_sqr_OBJECTS) $(t_toom2_sqr_LDADD) $(LIBS)
+
+t-toom22$(EXEEXT): $(t_toom22_OBJECTS) $(t_toom22_DEPENDENCIES) $(EXTRA_t_toom22_DEPENDENCIES) 
+	@rm -f t-toom22$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_toom22_OBJECTS) $(t_toom22_LDADD) $(LIBS)
+
+t-toom3-sqr$(EXEEXT): $(t_toom3_sqr_OBJECTS) $(t_toom3_sqr_DEPENDENCIES) $(EXTRA_t_toom3_sqr_DEPENDENCIES) 
+	@rm -f t-toom3-sqr$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_toom3_sqr_OBJECTS) $(t_toom3_sqr_LDADD) $(LIBS)
+
+t-toom32$(EXEEXT): $(t_toom32_OBJECTS) $(t_toom32_DEPENDENCIES) $(EXTRA_t_toom32_DEPENDENCIES) 
+	@rm -f t-toom32$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_toom32_OBJECTS) $(t_toom32_LDADD) $(LIBS)
+
+t-toom33$(EXEEXT): $(t_toom33_OBJECTS) $(t_toom33_DEPENDENCIES) $(EXTRA_t_toom33_DEPENDENCIES) 
+	@rm -f t-toom33$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_toom33_OBJECTS) $(t_toom33_LDADD) $(LIBS)
+
+t-toom4-sqr$(EXEEXT): $(t_toom4_sqr_OBJECTS) $(t_toom4_sqr_DEPENDENCIES) $(EXTRA_t_toom4_sqr_DEPENDENCIES) 
+	@rm -f t-toom4-sqr$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_toom4_sqr_OBJECTS) $(t_toom4_sqr_LDADD) $(LIBS)
+
+t-toom42$(EXEEXT): $(t_toom42_OBJECTS) $(t_toom42_DEPENDENCIES) $(EXTRA_t_toom42_DEPENDENCIES) 
+	@rm -f t-toom42$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_toom42_OBJECTS) $(t_toom42_LDADD) $(LIBS)
+
+t-toom43$(EXEEXT): $(t_toom43_OBJECTS) $(t_toom43_DEPENDENCIES) $(EXTRA_t_toom43_DEPENDENCIES) 
+	@rm -f t-toom43$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_toom43_OBJECTS) $(t_toom43_LDADD) $(LIBS)
+
+t-toom44$(EXEEXT): $(t_toom44_OBJECTS) $(t_toom44_DEPENDENCIES) $(EXTRA_t_toom44_DEPENDENCIES) 
+	@rm -f t-toom44$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_toom44_OBJECTS) $(t_toom44_LDADD) $(LIBS)
+
+t-toom52$(EXEEXT): $(t_toom52_OBJECTS) $(t_toom52_DEPENDENCIES) $(EXTRA_t_toom52_DEPENDENCIES) 
+	@rm -f t-toom52$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_toom52_OBJECTS) $(t_toom52_LDADD) $(LIBS)
+
+t-toom53$(EXEEXT): $(t_toom53_OBJECTS) $(t_toom53_DEPENDENCIES) $(EXTRA_t_toom53_DEPENDENCIES) 
+	@rm -f t-toom53$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_toom53_OBJECTS) $(t_toom53_LDADD) $(LIBS)
+
+t-toom54$(EXEEXT): $(t_toom54_OBJECTS) $(t_toom54_DEPENDENCIES) $(EXTRA_t_toom54_DEPENDENCIES) 
+	@rm -f t-toom54$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_toom54_OBJECTS) $(t_toom54_LDADD) $(LIBS)
+
+t-toom6-sqr$(EXEEXT): $(t_toom6_sqr_OBJECTS) $(t_toom6_sqr_DEPENDENCIES) $(EXTRA_t_toom6_sqr_DEPENDENCIES) 
+	@rm -f t-toom6-sqr$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_toom6_sqr_OBJECTS) $(t_toom6_sqr_LDADD) $(LIBS)
+
+t-toom62$(EXEEXT): $(t_toom62_OBJECTS) $(t_toom62_DEPENDENCIES) $(EXTRA_t_toom62_DEPENDENCIES) 
+	@rm -f t-toom62$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_toom62_OBJECTS) $(t_toom62_LDADD) $(LIBS)
+
+t-toom63$(EXEEXT): $(t_toom63_OBJECTS) $(t_toom63_DEPENDENCIES) $(EXTRA_t_toom63_DEPENDENCIES) 
+	@rm -f t-toom63$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_toom63_OBJECTS) $(t_toom63_LDADD) $(LIBS)
+
+t-toom6h$(EXEEXT): $(t_toom6h_OBJECTS) $(t_toom6h_DEPENDENCIES) $(EXTRA_t_toom6h_DEPENDENCIES) 
+	@rm -f t-toom6h$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_toom6h_OBJECTS) $(t_toom6h_LDADD) $(LIBS)
+
+t-toom8-sqr$(EXEEXT): $(t_toom8_sqr_OBJECTS) $(t_toom8_sqr_DEPENDENCIES) $(EXTRA_t_toom8_sqr_DEPENDENCIES) 
+	@rm -f t-toom8-sqr$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_toom8_sqr_OBJECTS) $(t_toom8_sqr_LDADD) $(LIBS)
+
+t-toom8h$(EXEEXT): $(t_toom8h_OBJECTS) $(t_toom8h_DEPENDENCIES) $(EXTRA_t_toom8h_DEPENDENCIES) 
+	@rm -f t-toom8h$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_toom8h_OBJECTS) $(t_toom8h_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+.c.o:
+	$(AM_V_CC)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+	$(AM_V_CC)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+	$(AM_V_CC)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+# Recover from deleted '.trs' file; this should ensure that
+# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create
+# both 'foo.log' and 'foo.trs'.  Break the recipe in two subshells
+# to avoid problems with "make -n".
+.log.trs:
+	rm -f $< $@
+	$(MAKE) $(AM_MAKEFLAGS) $<
+
+# Leading 'am--fnord' is there to ensure the list of targets does not
+# expand to empty, as could happen e.g. with make check TESTS=''.
+am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck)
+am--force-recheck:
+	@:
+
+$(TEST_SUITE_LOG): $(TEST_LOGS)
+	@$(am__set_TESTS_bases); \
+	am__f_ok () { test -f "$$1" && test -r "$$1"; }; \
+	redo_bases=`for i in $$bases; do \
+	              am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \
+	            done`; \
+	if test -n "$$redo_bases"; then \
+	  redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \
+	  redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \
+	  if $(am__make_dryrun); then :; else \
+	    rm -f $$redo_logs && rm -f $$redo_results || exit 1; \
+	  fi; \
+	fi; \
+	if test -n "$$am__remaking_logs"; then \
+	  echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \
+	       "recursion detected" >&2; \
+	elif test -n "$$redo_logs"; then \
+	  am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \
+	fi; \
+	if $(am__make_dryrun); then :; else \
+	  st=0;  \
+	  errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \
+	  for i in $$redo_bases; do \
+	    test -f $$i.trs && test -r $$i.trs \
+	      || { echo "$$errmsg $$i.trs" >&2; st=1; }; \
+	    test -f $$i.log && test -r $$i.log \
+	      || { echo "$$errmsg $$i.log" >&2; st=1; }; \
+	  done; \
+	  test $$st -eq 0 || exit 1; \
+	fi
+	@$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \
+	ws='[ 	]'; \
+	results=`for b in $$bases; do echo $$b.trs; done`; \
+	test -n "$$results" || results=/dev/null; \
+	all=`  grep "^$$ws*:test-result:"           $$results | wc -l`; \
+	pass=` grep "^$$ws*:test-result:$$ws*PASS"  $$results | wc -l`; \
+	fail=` grep "^$$ws*:test-result:$$ws*FAIL"  $$results | wc -l`; \
+	skip=` grep "^$$ws*:test-result:$$ws*SKIP"  $$results | wc -l`; \
+	xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \
+	xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \
+	error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \
+	if test `expr $$fail + $$xpass + $$error` -eq 0; then \
+	  success=true; \
+	else \
+	  success=false; \
+	fi; \
+	br='==================='; br=$$br$$br$$br$$br; \
+	result_count () \
+	{ \
+	    if test x"$$1" = x"--maybe-color"; then \
+	      maybe_colorize=yes; \
+	    elif test x"$$1" = x"--no-color"; then \
+	      maybe_colorize=no; \
+	    else \
+	      echo "$@: invalid 'result_count' usage" >&2; exit 4; \
+	    fi; \
+	    shift; \
+	    desc=$$1 count=$$2; \
+	    if test $$maybe_colorize = yes && test $$count -gt 0; then \
+	      color_start=$$3 color_end=$$std; \
+	    else \
+	      color_start= color_end=; \
+	    fi; \
+	    echo "$${color_start}# $$desc $$count$${color_end}"; \
+	}; \
+	create_testsuite_report () \
+	{ \
+	  result_count $$1 "TOTAL:" $$all   "$$brg"; \
+	  result_count $$1 "PASS: " $$pass  "$$grn"; \
+	  result_count $$1 "SKIP: " $$skip  "$$blu"; \
+	  result_count $$1 "XFAIL:" $$xfail "$$lgn"; \
+	  result_count $$1 "FAIL: " $$fail  "$$red"; \
+	  result_count $$1 "XPASS:" $$xpass "$$red"; \
+	  result_count $$1 "ERROR:" $$error "$$mgn"; \
+	}; \
+	{								\
+	  echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" |	\
+	    $(am__rst_title);						\
+	  create_testsuite_report --no-color;				\
+	  echo;								\
+	  echo ".. contents:: :depth: 2";				\
+	  echo;								\
+	  for b in $$bases; do echo $$b; done				\
+	    | $(am__create_global_log);					\
+	} >$(TEST_SUITE_LOG).tmp || exit 1;				\
+	mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG);			\
+	if $$success; then						\
+	  col="$$grn";							\
+	 else								\
+	  col="$$red";							\
+	  test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG);		\
+	fi;								\
+	echo "$${col}$$br$${std}"; 					\
+	echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}";	\
+	echo "$${col}$$br$${std}"; 					\
+	create_testsuite_report --maybe-color;				\
+	echo "$$col$$br$$std";						\
+	if $$success; then :; else					\
+	  echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}";		\
+	  if test -n "$(PACKAGE_BUGREPORT)"; then			\
+	    echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}";	\
+	  fi;								\
+	  echo "$$col$$br$$std";					\
+	fi;								\
+	$$success || exit 1
+
+check-TESTS:
+	@list='$(RECHECK_LOGS)';           test -z "$$list" || rm -f $$list
+	@list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list
+	@test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+	@set +e; $(am__set_TESTS_bases); \
+	log_list=`for i in $$bases; do echo $$i.log; done`; \
+	trs_list=`for i in $$bases; do echo $$i.trs; done`; \
+	log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \
+	$(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \
+	exit $$?;
+recheck: all $(check_PROGRAMS)
+	@test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+	@set +e; $(am__set_TESTS_bases); \
+	bases=`for i in $$bases; do echo $$i; done \
+	         | $(am__list_recheck_tests)` || exit 1; \
+	log_list=`for i in $$bases; do echo $$i.log; done`; \
+	log_list=`echo $$log_list`; \
+	$(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \
+	        am__force_recheck=am--force-recheck \
+	        TEST_LOGS="$$log_list"; \
+	exit $$?
+t-asmtype.log: t-asmtype$(EXEEXT)
+	@p='t-asmtype$(EXEEXT)'; \
+	b='t-asmtype'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-aors_1.log: t-aors_1$(EXEEXT)
+	@p='t-aors_1$(EXEEXT)'; \
+	b='t-aors_1'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-divrem_1.log: t-divrem_1$(EXEEXT)
+	@p='t-divrem_1$(EXEEXT)'; \
+	b='t-divrem_1'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-mod_1.log: t-mod_1$(EXEEXT)
+	@p='t-mod_1$(EXEEXT)'; \
+	b='t-mod_1'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-fat.log: t-fat$(EXEEXT)
+	@p='t-fat$(EXEEXT)'; \
+	b='t-fat'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-get_d.log: t-get_d$(EXEEXT)
+	@p='t-get_d$(EXEEXT)'; \
+	b='t-get_d'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-instrument.log: t-instrument$(EXEEXT)
+	@p='t-instrument$(EXEEXT)'; \
+	b='t-instrument'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-iord_u.log: t-iord_u$(EXEEXT)
+	@p='t-iord_u$(EXEEXT)'; \
+	b='t-iord_u'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-mp_bases.log: t-mp_bases$(EXEEXT)
+	@p='t-mp_bases$(EXEEXT)'; \
+	b='t-mp_bases'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-perfsqr.log: t-perfsqr$(EXEEXT)
+	@p='t-perfsqr$(EXEEXT)'; \
+	b='t-perfsqr'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-scan.log: t-scan$(EXEEXT)
+	@p='t-scan$(EXEEXT)'; \
+	b='t-scan'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+logic.log: logic$(EXEEXT)
+	@p='logic$(EXEEXT)'; \
+	b='logic'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-toom22.log: t-toom22$(EXEEXT)
+	@p='t-toom22$(EXEEXT)'; \
+	b='t-toom22'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-toom32.log: t-toom32$(EXEEXT)
+	@p='t-toom32$(EXEEXT)'; \
+	b='t-toom32'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-toom33.log: t-toom33$(EXEEXT)
+	@p='t-toom33$(EXEEXT)'; \
+	b='t-toom33'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-toom42.log: t-toom42$(EXEEXT)
+	@p='t-toom42$(EXEEXT)'; \
+	b='t-toom42'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-toom43.log: t-toom43$(EXEEXT)
+	@p='t-toom43$(EXEEXT)'; \
+	b='t-toom43'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-toom44.log: t-toom44$(EXEEXT)
+	@p='t-toom44$(EXEEXT)'; \
+	b='t-toom44'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-toom52.log: t-toom52$(EXEEXT)
+	@p='t-toom52$(EXEEXT)'; \
+	b='t-toom52'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-toom53.log: t-toom53$(EXEEXT)
+	@p='t-toom53$(EXEEXT)'; \
+	b='t-toom53'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-toom54.log: t-toom54$(EXEEXT)
+	@p='t-toom54$(EXEEXT)'; \
+	b='t-toom54'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-toom62.log: t-toom62$(EXEEXT)
+	@p='t-toom62$(EXEEXT)'; \
+	b='t-toom62'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-toom63.log: t-toom63$(EXEEXT)
+	@p='t-toom63$(EXEEXT)'; \
+	b='t-toom63'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-toom6h.log: t-toom6h$(EXEEXT)
+	@p='t-toom6h$(EXEEXT)'; \
+	b='t-toom6h'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-toom8h.log: t-toom8h$(EXEEXT)
+	@p='t-toom8h$(EXEEXT)'; \
+	b='t-toom8h'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-toom2-sqr.log: t-toom2-sqr$(EXEEXT)
+	@p='t-toom2-sqr$(EXEEXT)'; \
+	b='t-toom2-sqr'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-toom3-sqr.log: t-toom3-sqr$(EXEEXT)
+	@p='t-toom3-sqr$(EXEEXT)'; \
+	b='t-toom3-sqr'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-toom4-sqr.log: t-toom4-sqr$(EXEEXT)
+	@p='t-toom4-sqr$(EXEEXT)'; \
+	b='t-toom4-sqr'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-toom6-sqr.log: t-toom6-sqr$(EXEEXT)
+	@p='t-toom6-sqr$(EXEEXT)'; \
+	b='t-toom6-sqr'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-toom8-sqr.log: t-toom8-sqr$(EXEEXT)
+	@p='t-toom8-sqr$(EXEEXT)'; \
+	b='t-toom8-sqr'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-div.log: t-div$(EXEEXT)
+	@p='t-div$(EXEEXT)'; \
+	b='t-div'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-mul.log: t-mul$(EXEEXT)
+	@p='t-mul$(EXEEXT)'; \
+	b='t-mul'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-mullo.log: t-mullo$(EXEEXT)
+	@p='t-mullo$(EXEEXT)'; \
+	b='t-mullo'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-sqrlo.log: t-sqrlo$(EXEEXT)
+	@p='t-sqrlo$(EXEEXT)'; \
+	b='t-sqrlo'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-mulmod_bnm1.log: t-mulmod_bnm1$(EXEEXT)
+	@p='t-mulmod_bnm1$(EXEEXT)'; \
+	b='t-mulmod_bnm1'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-sqrmod_bnm1.log: t-sqrmod_bnm1$(EXEEXT)
+	@p='t-sqrmod_bnm1$(EXEEXT)'; \
+	b='t-sqrmod_bnm1'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-mulmid.log: t-mulmid$(EXEEXT)
+	@p='t-mulmid$(EXEEXT)'; \
+	b='t-mulmid'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-hgcd.log: t-hgcd$(EXEEXT)
+	@p='t-hgcd$(EXEEXT)'; \
+	b='t-hgcd'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-hgcd_appr.log: t-hgcd_appr$(EXEEXT)
+	@p='t-hgcd_appr$(EXEEXT)'; \
+	b='t-hgcd_appr'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-matrix22.log: t-matrix22$(EXEEXT)
+	@p='t-matrix22$(EXEEXT)'; \
+	b='t-matrix22'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-invert.log: t-invert$(EXEEXT)
+	@p='t-invert$(EXEEXT)'; \
+	b='t-invert'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-bdiv.log: t-bdiv$(EXEEXT)
+	@p='t-bdiv$(EXEEXT)'; \
+	b='t-bdiv'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-fib2m.log: t-fib2m$(EXEEXT)
+	@p='t-fib2m$(EXEEXT)'; \
+	b='t-fib2m'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-broot.log: t-broot$(EXEEXT)
+	@p='t-broot$(EXEEXT)'; \
+	b='t-broot'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-brootinv.log: t-brootinv$(EXEEXT)
+	@p='t-brootinv$(EXEEXT)'; \
+	b='t-brootinv'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-minvert.log: t-minvert$(EXEEXT)
+	@p='t-minvert$(EXEEXT)'; \
+	b='t-minvert'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-sizeinbase.log: t-sizeinbase$(EXEEXT)
+	@p='t-sizeinbase$(EXEEXT)'; \
+	b='t-sizeinbase'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-gcd_11.log: t-gcd_11$(EXEEXT)
+	@p='t-gcd_11$(EXEEXT)'; \
+	b='t-gcd_11'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-gcd_22.log: t-gcd_22$(EXEEXT)
+	@p='t-gcd_22$(EXEEXT)'; \
+	b='t-gcd_22'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-gcdext_1.log: t-gcdext_1$(EXEEXT)
+	@p='t-gcdext_1$(EXEEXT)'; \
+	b='t-gcdext_1'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+.test.log:
+	@p='$<'; \
+	$(am__set_b); \
+	$(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+@am__EXEEXT_TRUE@.test$(EXEEXT).log:
+@am__EXEEXT_TRUE@	@p='$<'; \
+@am__EXEEXT_TRUE@	$(am__set_b); \
+@am__EXEEXT_TRUE@	$(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+@am__EXEEXT_TRUE@	--log-file $$b.log --trs-file $$b.trs \
+@am__EXEEXT_TRUE@	$(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+@am__EXEEXT_TRUE@	"$$tst" $(AM_TESTS_FD_REDIRECT)
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+	$(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+	-test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS)
+	-test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs)
+	-test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-TESTS check-am clean \
+	clean-checkPROGRAMS clean-generic clean-libtool cscopelist-am \
+	ctags ctags-am distclean distclean-compile distclean-generic \
+	distclean-libtool distclean-tags distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-dvi install-dvi-am install-exec \
+	install-exec-am install-html install-html-am install-info \
+	install-info-am install-man install-pdf install-pdf-am \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	recheck tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+$(top_builddir)/tests/libtests.la:
+	cd $(top_builddir)/tests; $(MAKE) $(AM_MAKEFLAGS) libtests.la
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/third_party/gmp/tests/mpn/logic.c b/third_party/gmp/tests/mpn/logic.c
new file mode 100644
index 0000000..2b1c9a9
--- /dev/null
+++ b/third_party/gmp/tests/mpn/logic.c
@@ -0,0 +1,133 @@
+/* Test mpn_and, mpn_ior, mpn_xor, mpn_andn, mpn_iorn, mpn_xnor, mpn_nand, and
+   mpn_nior.
+
+Copyright 2011-2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+
+/* Fake native prevalence of the tested operations, so that we actually test
+   the compiled functions, i.e., the ones which users will reach.  The inlined
+   variants will be tested through tests/mpz/logic.c.  */
+#define HAVE_NATIVE_mpn_com    1
+#define HAVE_NATIVE_mpn_and_n  1
+#define HAVE_NATIVE_mpn_andn_n 1
+#define HAVE_NATIVE_mpn_nand_n 1
+#define HAVE_NATIVE_mpn_ior_n  1
+#define HAVE_NATIVE_mpn_iorn_n 1
+#define HAVE_NATIVE_mpn_nior_n 1
+#define HAVE_NATIVE_mpn_xor_n  1
+#define HAVE_NATIVE_mpn_xnor_n 1
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_one (mp_srcptr refp, mp_srcptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n, const char *funcname)
+{
+  if (mpn_cmp (refp, rp, n))
+    {
+      printf ("ERROR in mpn_%s\n", funcname);
+      printf ("a: "); mpn_dump (ap, n);
+      printf ("b: "); mpn_dump (bp, n);
+      printf ("r:   "); mpn_dump (rp, n);
+      printf ("ref: "); mpn_dump (refp, n);
+      abort();
+    }
+}
+
+int
+main (int argc, char **argv)
+{
+  mpz_t a, b;
+  mp_ptr ap, bp, rp, refp;
+  mp_size_t max_n, n, i;
+  gmp_randstate_ptr rands;
+  long test, reps = 1000;
+  TMP_DECL;
+  TMP_MARK;
+
+  tests_start ();
+  TESTS_REPS (reps, argv, argc);
+
+  mpz_inits (a, b, NULL);
+
+  rands = RANDS;		/* FIXME: not used */
+
+  max_n = 100;
+
+  rp = TMP_ALLOC_LIMBS (1 + max_n * 8 / GMP_LIMB_BITS);
+  refp = TMP_ALLOC_LIMBS (1 + max_n * 8 / GMP_LIMB_BITS);
+
+  for (test = 0; test < reps; test++)
+    {
+      for (i = 1; i <= max_n; i++)
+	{
+	  mpz_rrandomb (a, rands, i * 8);
+	  mpz_rrandomb (b, rands, i * 8);
+	  mpz_setbit (a, i * 8 - 1);
+	  mpz_setbit (b, i * 8 - 1);
+	  ap = PTR(a);
+	  bp = PTR(b);
+	  n = SIZ(a);
+
+	  refmpn_and_n (refp, ap, bp, n);
+	  mpn_and_n (rp, ap, bp, n);
+	  check_one (refp, rp, ap, bp, n, "and_n");
+
+	  refmpn_ior_n (refp, ap, bp, n);
+	  mpn_ior_n (rp, ap, bp, n);
+	  check_one (refp, rp, ap, bp, n, "ior_n");
+
+	  refmpn_xor_n (refp, ap, bp, n);
+	  mpn_xor_n (rp, ap, bp, n);
+	  check_one (refp, rp, ap, bp, n, "xor_n");
+
+	  refmpn_andn_n (refp, ap, bp, n);
+	  mpn_andn_n (rp, ap, bp, n);
+	  check_one (refp, rp, ap, bp, n, "andn_n");
+
+	  refmpn_iorn_n (refp, ap, bp, n);
+	  mpn_iorn_n (rp, ap, bp, n);
+	  check_one (refp, rp, ap, bp, n, "iorn_n");
+
+	  refmpn_nand_n (refp, ap, bp, n);
+	  mpn_nand_n (rp, ap, bp, n);
+	  check_one (refp, rp, ap, bp, n, "nand_n");
+
+	  refmpn_nior_n (refp, ap, bp, n);
+	  mpn_nior_n (rp, ap, bp, n);
+	  check_one (refp, rp, ap, bp, n, "nior_n");
+
+	  refmpn_xnor_n (refp, ap, bp, n);
+	  mpn_xnor_n (rp, ap, bp, n);
+	  check_one (refp, rp, ap, bp, n, "xnor_n");
+
+	  refmpn_com (refp, ap, n);
+	  mpn_com (rp, ap, n);
+	  check_one (refp, rp, ap, bp, n, "com");
+	}
+    }
+
+  TMP_FREE;
+  mpz_clears (a, b, NULL);
+  tests_end ();
+  return 0;
+}
diff --git a/third_party/gmp/tests/mpn/t-aors_1.c b/third_party/gmp/tests/mpn/t-aors_1.c
new file mode 100644
index 0000000..c894922
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-aors_1.c
@@ -0,0 +1,310 @@
+/* Test mpn_add_1 and mpn_sub_1.
+
+Copyright 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+#define M      GMP_NUMB_MAX
+#define ASIZE  10
+#define MAGIC  0x1234
+
+#define SETUP()                         \
+  do {                                  \
+    refmpn_random (got, data[i].size);  \
+    got[data[i].size] = MAGIC;          \
+  } while (0)
+
+#define SETUP_INPLACE()                                 \
+  do {                                                  \
+    refmpn_copyi (got, data[i].src, data[i].size);      \
+    got[data[i].size] = MAGIC;                          \
+  } while (0)
+
+#define VERIFY(name)                            \
+  do {                                          \
+    verify (name, i, data[i].src, data[i].n,    \
+            got_c, data[i].want_c,              \
+            got, data[i].want, data[i].size);   \
+  } while (0)
+
+typedef mp_limb_t (*mpn_aors_1_t) (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+mpn_aors_1_t fudge (mpn_aors_1_t);
+
+
+void
+verify (const char *name, int i,
+        mp_srcptr src, mp_limb_t n,
+        mp_limb_t got_c, mp_limb_t want_c,
+        mp_srcptr got, mp_srcptr want, mp_size_t size)
+{
+  if (got[size] != MAGIC)
+    {
+      printf ("Overwrite at %s i=%d\n", name, i);
+      abort ();
+    }
+
+  if (got_c != want_c || ! refmpn_equal_anynail (got, want, size))
+    {
+      printf ("Wrong at %s i=%d size=%ld\n", name, i, size);
+      mpn_trace ("   src", src,  size);
+      mpn_trace ("     n", &n,   (mp_size_t) 1);
+      mpn_trace ("   got", got,  size);
+      mpn_trace ("  want", want, size);
+      mpn_trace (" got c", &got_c,  (mp_size_t) 1);
+      mpn_trace ("want c", &want_c, (mp_size_t) 1);
+      abort ();
+    }
+}
+
+
+void
+check_add_1 (void)
+{
+  static const struct {
+    mp_size_t        size;
+    mp_limb_t        n;
+    const mp_limb_t  src[ASIZE];
+    mp_limb_t        want_c;
+    const mp_limb_t  want[ASIZE];
+  } data[] = {
+    { 1, 0, { 0 },  0, { 0 } },
+    { 1, 0, { 1 },  0, { 1 } },
+    { 1, 1, { 0 },  0, { 1 } },
+    { 1, 0, { M },  0, { M } },
+    { 1, M, { 0 },  0, { M } },
+    { 1, 1, { 123 }, 0, { 124 } },
+
+    { 1, 1, { M },  1, { 0 } },
+    { 1, M, { 1 },  1, { 0 } },
+    { 1, M, { M },  1, { M-1 } },
+
+    { 2, 0, { 0, 0 },  0, { 0, 0 } },
+    { 2, 0, { 1, 0 },  0, { 1, 0 } },
+    { 2, 1, { 0, 0 },  0, { 1, 0 } },
+    { 2, 0, { M, 0 },  0, { M, 0 } },
+    { 2, M, { 0, 0 },  0, { M, 0 } },
+    { 2, 1, { M, 0 },  0, { 0, 1 } },
+    { 2, M, { 1, 0 },  0, { 0, 1 } },
+    { 2, M, { M, 0 },  0, { M-1, 1 } },
+    { 2, M, { M, 0 },  0, { M-1, 1 } },
+
+    { 2, 1, { M, M },  1, { 0, 0 } },
+    { 2, M, { 1, M },  1, { 0, 0 } },
+    { 2, M, { M, M },  1, { M-1, 0 } },
+    { 2, M, { M, M },  1, { M-1, 0 } },
+
+    { 3, 1, { M, M, M },  1, { 0, 0, 0 } },
+    { 3, M, { 1, M, M },  1, { 0, 0, 0 } },
+    { 3, M, { M, M, M },  1, { M-1, 0, 0 } },
+    { 3, M, { M, M, M },  1, { M-1, 0, 0 } },
+
+    { 4, 1, { M, M, M, M },  1, { 0, 0, 0, 0 } },
+    { 4, M, { 1, M, M, M },  1, { 0, 0, 0, 0 } },
+    { 4, M, { M, M, M, M },  1, { M-1, 0, 0, 0 } },
+    { 4, M, { M, M, M, M },  1, { M-1, 0, 0, 0 } },
+
+    { 4, M, { M, 0,   M, M },  0, { M-1, 1, M, M } },
+    { 4, M, { M, M-1, M, M },  0, { M-1, M, M, M } },
+
+    { 4, M, { M, M, 0,   M },  0, { M-1, 0, 1, M } },
+    { 4, M, { M, M, M-1, M },  0, { M-1, 0, M, M } },
+  };
+
+  mp_limb_t  got[ASIZE];
+  mp_limb_t  got_c;
+  /* mpn_sec_add_a_itch(n) <= n */
+  mp_limb_t  scratch[ASIZE];
+  int        i;
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      SETUP ();
+      got_c = mpn_add_1 (got, data[i].src, data[i].size, data[i].n);
+      VERIFY ("check_add_1 (separate)");
+
+      SETUP_INPLACE ();
+      got_c = mpn_add_1 (got, got, data[i].size, data[i].n);
+      VERIFY ("check_add_1 (in-place)");
+
+      SETUP ();
+      scratch [mpn_sec_add_1_itch(data[i].size)] = MAGIC;
+      got_c = mpn_sec_add_1 (got, data[i].src, data[i].size, data[i].n, scratch);
+      got_c ^= scratch [mpn_sec_add_1_itch(data[i].size)] ^ MAGIC;
+      VERIFY ("check_sec_add_1 (separate)");
+
+      SETUP_INPLACE ();
+      got_c = mpn_sec_add_1 (got, got, data[i].size, data[i].n, scratch);
+      VERIFY ("check_sec_add_1 (in-place)");
+
+      if (data[i].n == 1)
+        {
+          SETUP ();
+          got_c = mpn_add_1 (got, data[i].src, data[i].size, CNST_LIMB(1));
+          VERIFY ("check_add_1 (separate, const 1)");
+
+          SETUP_INPLACE ();
+          got_c = mpn_add_1 (got, got, data[i].size, CNST_LIMB(1));
+          VERIFY ("check_add_1 (in-place, const 1)");
+
+          SETUP ();
+          got_c = mpn_sec_add_1 (got, data[i].src, data[i].size,
+				 CNST_LIMB(1), scratch);
+          VERIFY ("check_sec_add_1 (separate, const 1)");
+
+          SETUP_INPLACE ();
+          got_c = mpn_sec_add_1 (got, got, data[i].size,
+				 CNST_LIMB(1), scratch);
+          VERIFY ("check_sec_add_1 (in-place, const 1)");
+        }
+
+      /* Same again on functions, not inlines. */
+      SETUP ();
+      got_c = (*fudge(mpn_add_1)) (got, data[i].src, data[i].size, data[i].n);
+      VERIFY ("check_add_1 (function, separate)");
+
+      SETUP_INPLACE ();
+      got_c = (*fudge(mpn_add_1)) (got, got, data[i].size, data[i].n);
+      VERIFY ("check_add_1 (function, in-place)");
+    }
+}
+
+void
+check_sub_1 (void)
+{
+  static const struct {
+    mp_size_t        size;
+    mp_limb_t        n;
+    const mp_limb_t  src[ASIZE];
+    mp_limb_t        want_c;
+    const mp_limb_t  want[ASIZE];
+  } data[] = {
+    { 1, 0, { 0 },  0, { 0 } },
+    { 1, 0, { 1 },  0, { 1 } },
+    { 1, 1, { 1 },  0, { 0 } },
+    { 1, 0, { M },  0, { M } },
+    { 1, 1, { M },  0, { M-1 } },
+    { 1, 1, { 123 }, 0, { 122 } },
+
+    { 1, 1, { 0 },  1, { M } },
+    { 1, M, { 0 },  1, { 1 } },
+
+    { 2, 0, { 0, 0 },  0, { 0, 0 } },
+    { 2, 0, { 1, 0 },  0, { 1, 0 } },
+    { 2, 1, { 1, 0 },  0, { 0, 0 } },
+    { 2, 0, { M, 0 },  0, { M, 0 } },
+    { 2, 1, { M, 0 },  0, { M-1, 0 } },
+    { 2, 1, { 123, 0 }, 0, { 122, 0 } },
+
+    { 2, 1, { 0, 0 },  1, { M, M } },
+    { 2, M, { 0, 0 },  1, { 1, M } },
+
+    { 3, 0, { 0,   0, 0 },  0, { 0,   0, 0 } },
+    { 3, 0, { 123, 0, 0 },  0, { 123, 0, 0 } },
+
+    { 3, 1, { 0, 0, 0 },  1, { M, M, M } },
+    { 3, M, { 0, 0, 0 },  1, { 1, M, M } },
+
+    { 4, 1, { 0, 0, 0, 0 },  1, { M, M, M, M } },
+    { 4, M, { 0, 0, 0, 0 },  1, { 1, M, M, M } },
+
+    { 4, 1, { 0, 0, 1,   42 },  0, { M, M, 0,   42 } },
+    { 4, M, { 0, 0, 123, 24 },  0, { 1, M, 122, 24 } },
+  };
+
+  mp_limb_t  got[ASIZE];
+  mp_limb_t  got_c;
+  /* mpn_sec_sub_1_itch(n) <= n */
+  mp_limb_t  scratch[ASIZE];
+  int        i;
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      SETUP ();
+      got_c = mpn_sub_1 (got, data[i].src, data[i].size, data[i].n);
+      VERIFY ("check_sub_1 (separate)");
+
+      SETUP_INPLACE ();
+      got_c = mpn_sub_1 (got, got, data[i].size, data[i].n);
+      VERIFY ("check_sub_1 (in-place)");
+
+      SETUP ();
+      scratch [mpn_sec_sub_1_itch(data[i].size)] = MAGIC;
+      got_c = mpn_sec_sub_1 (got, data[i].src, data[i].size, data[i].n, scratch);
+      got_c ^= scratch [mpn_sec_sub_1_itch(data[i].size)] ^ MAGIC;
+      VERIFY ("check_sec_sub_1 (separate)");
+
+      SETUP_INPLACE ();
+      got_c = mpn_sec_sub_1 (got, got, data[i].size, data[i].n, scratch);
+      VERIFY ("check_sec_sub_1 (in-place)");
+
+      if (data[i].n == 1)
+        {
+          SETUP ();
+          got_c = mpn_sub_1 (got, data[i].src, data[i].size, CNST_LIMB(1));
+          VERIFY ("check_sub_1 (separate, const 1)");
+
+          SETUP_INPLACE ();
+          got_c = mpn_sub_1 (got, got, data[i].size, CNST_LIMB(1));
+          VERIFY ("check_sub_1 (in-place, const 1)");
+
+          SETUP ();
+          got_c = mpn_sec_sub_1 (got, data[i].src, data[i].size,
+				 CNST_LIMB(1), scratch);
+          VERIFY ("check_sec_sub_1 (separate, const 1)");
+
+          SETUP_INPLACE ();
+          got_c = mpn_sec_sub_1 (got, got, data[i].size,
+				 CNST_LIMB(1), scratch);
+          VERIFY ("check_sec_sub_1 (in-place, const 1)");
+        }
+
+      /* Same again on functions, not inlines. */
+      SETUP ();
+      got_c = (*fudge(mpn_sub_1)) (got, data[i].src, data[i].size, data[i].n);
+      VERIFY ("check_sub_1 (function, separate)");
+
+      SETUP_INPLACE ();
+      got_c = (*fudge(mpn_sub_1)) (got, got, data[i].size, data[i].n);
+      VERIFY ("check_sub_1 (function, in-place)");
+    }
+}
+
+/* Try to prevent the optimizer inlining. */
+mpn_aors_1_t
+fudge (mpn_aors_1_t f)
+{
+  return f;
+}
+
+int
+main (void)
+{
+  tests_start ();
+  mp_trace_base = -16;
+
+  check_add_1 ();
+  check_sub_1 ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpn/t-asmtype.c b/third_party/gmp/tests/mpn/t-asmtype.c
new file mode 100644
index 0000000..c6577d1
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-asmtype.c
@@ -0,0 +1,63 @@
+/* Test .type directives on assembler functions.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+
+#include "tests.h"
+
+
+/* This apparently trivial test is designed to detect missing .type and
+   .size directives in asm code, per the problem described under
+   GMP_ASM_TYPE in acinclude.m4.
+
+   A failure can be provoked in a shared or shared+static build by making
+   TYPE and SIZE in config.m4 empty, either by editing it or by configuring
+   with
+
+       ./configure gmp_cv_asm_type= gmp_cv_asm_size=
+
+   mpn_add_n is used for the test because normally it's implemented in
+   assembler on a CPU that has any asm code.
+
+   Enhancement: As noted with GMP_ASM_TYPE, if .type is wrong but .size is
+   right then everything works, but uses code copied down to the mainline
+   data area.  Maybe we could detect that if we built a test library with an
+   object that had .size deliberately disabled.  */
+
+int
+main (void)
+{
+  static const mp_limb_t x[3]    = { 1, 2, 3 };
+  static const mp_limb_t y[3]    = { 4, 5, 6 };
+  static const mp_limb_t want[3] = { 5, 7, 9 };
+  mp_limb_t  got[3];
+
+  mpn_add_n (got, x, y, (mp_size_t) 3);
+
+  if (refmpn_cmp (got, want, (mp_size_t) 3) != 0)
+    {
+      printf ("Wrong result from mpn_add_n\n");
+      abort ();
+    }
+
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpn/t-bdiv.c b/third_party/gmp/tests/mpn/t-bdiv.c
new file mode 100644
index 0000000..60f58da
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-bdiv.c
@@ -0,0 +1,354 @@
+/* Copyright 2006, 2007, 2009, 2010, 2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+#include <stdlib.h>		/* for strtol */
+#include <stdio.h>		/* for printf */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+#include "tests/tests.h"
+
+
+static void
+dumpy (mp_srcptr p, mp_size_t n)
+{
+  mp_size_t i;
+  if (n > 20)
+    {
+      for (i = n - 1; i >= n - 4; i--)
+	{
+	  printf ("%0*lx", (int) (2 * sizeof (mp_limb_t)), p[i]);
+	  printf (" ");
+	}
+      printf ("... ");
+      for (i = 3; i >= 0; i--)
+	{
+	  printf ("%0*lx", (int) (2 * sizeof (mp_limb_t)), p[i]);
+	  printf (i == 0 ? "" : " ");
+	}
+    }
+  else
+    {
+      for (i = n - 1; i >= 0; i--)
+	{
+	  printf ("%0*lx", (int) (2 * sizeof (mp_limb_t)), p[i]);
+	  printf (i == 0 ? "" : " ");
+	}
+    }
+  puts ("");
+}
+
+static unsigned long test;
+
+void
+check_one (mp_ptr qp, mp_srcptr rp, mp_limb_t rh,
+	   mp_srcptr np, mp_size_t nn, mp_srcptr dp, mp_size_t dn, const char *fname)
+{
+  mp_size_t qn;
+  mp_ptr tp;
+  mp_limb_t cy = 4711;		/* silence warnings */
+  TMP_DECL;
+
+  qn = nn - dn;
+
+  if (qn == 0)
+    return;
+
+  TMP_MARK;
+
+  tp = TMP_ALLOC_LIMBS (nn + 1);
+
+  if (dn >= qn)
+    mpn_mul (tp, dp, dn, qp, qn);
+  else
+    mpn_mul (tp, qp, qn, dp, dn);
+
+  cy = mpn_add_n (tp, tp, np, nn);
+
+  if (! mpn_zero_p (tp, qn)
+      || (rp != NULL && (cy != rh || mpn_cmp (tp + qn, rp, dn) != 0)))
+    {
+      printf ("\r*******************************************************************************\n");
+      printf ("%s inconsistent in test %lu\n", fname, test);
+      printf ("N=   "); dumpy (np, nn);
+      printf ("D=   "); dumpy (dp, dn);
+      printf ("Q=   "); dumpy (qp, qn);
+      if (rp != NULL)
+	{
+	  printf ("R=   "); dumpy (rp, dn);
+	  printf ("Rb=  %d, Cy=%d\n", (int) cy, (int) rh);
+	}
+      printf ("T=   "); dumpy (tp, nn);
+      printf ("nn = %ld, dn = %ld, qn = %ld", nn, dn, qn);
+      printf ("\n*******************************************************************************\n");
+      abort ();
+    }
+
+  TMP_FREE;
+}
+
+
+/* These are *bit* sizes. */
+#define SIZE_LOG 16
+#define MAX_DN (1L << SIZE_LOG)
+#define MAX_NN (1L << (SIZE_LOG + 1))
+
+#define COUNT 500
+
+mp_limb_t
+random_word (gmp_randstate_ptr rs)
+{
+  mpz_t x;
+  mp_limb_t r;
+  TMP_DECL;
+  TMP_MARK;
+
+  MPZ_TMP_INIT (x, 2);
+  mpz_urandomb (x, rs, 32);
+  r = mpz_get_ui (x);
+  TMP_FREE;
+  return r;
+}
+
+int
+main (int argc, char **argv)
+{
+  gmp_randstate_ptr rands;
+  unsigned long maxnbits, maxdbits, nbits, dbits;
+  mpz_t n, d, tz;
+  mp_size_t maxnn, maxdn, nn, dn, clearn, i;
+  mp_ptr np, dp, qp, rp;
+  mp_limb_t rh;
+  mp_limb_t t;
+  mp_limb_t dinv;
+  int count = COUNT;
+  mp_ptr scratch;
+  mp_limb_t ran;
+  mp_size_t alloc, itch;
+  mp_limb_t rran0, rran1, qran0, qran1;
+  TMP_DECL;
+
+  TESTS_REPS (count, argv, argc);
+
+  maxdbits = MAX_DN;
+  maxnbits = MAX_NN;
+
+  tests_start ();
+  rands = RANDS;
+
+  mpz_init (n);
+  mpz_init (d);
+  mpz_init (tz);
+
+  maxnn = maxnbits / GMP_NUMB_BITS + 1;
+  maxdn = maxdbits / GMP_NUMB_BITS + 1;
+
+  TMP_MARK;
+
+  qp = TMP_ALLOC_LIMBS (maxnn + 2) + 1;
+  rp = TMP_ALLOC_LIMBS (maxnn + 2) + 1;
+
+  alloc = 1;
+  scratch = __GMP_ALLOCATE_FUNC_LIMBS (alloc);
+
+  for (test = 0; test < count;)
+    {
+      nbits = random_word (rands) % (maxnbits - GMP_NUMB_BITS) + 2 * GMP_NUMB_BITS;
+      if (maxdbits > nbits)
+	dbits = random_word (rands) % nbits + 1;
+      else
+	dbits = random_word (rands) % maxdbits + 1;
+
+#if RAND_UNIFORM
+#define RANDFUNC mpz_urandomb
+#else
+#define RANDFUNC mpz_rrandomb
+#endif
+
+      do
+	{
+	  RANDFUNC (n, rands, nbits);
+	  do
+	    {
+	      RANDFUNC (d, rands, dbits);
+	    }
+	  while (mpz_sgn (d) == 0);
+
+	  np = PTR (n);
+	  dp = PTR (d);
+	  nn = SIZ (n);
+	  dn = SIZ (d);
+	}
+      while (nn < dn);
+
+      dp[0] |= 1;
+
+      mpz_urandomb (tz, rands, 32);
+      t = mpz_get_ui (tz);
+
+      if (t % 17 == 0)
+	dp[0] = GMP_NUMB_MAX;
+
+      switch ((int) t % 16)
+	{
+	case 0:
+	  clearn = random_word (rands) % nn;
+	  for (i = 0; i <= clearn; i++)
+	    np[i] = 0;
+	  break;
+	case 1:
+	  mpn_sub_1 (np + nn - dn, dp, dn, random_word (rands));
+	  break;
+	case 2:
+	  mpn_add_1 (np + nn - dn, dp, dn, random_word (rands));
+	  break;
+	}
+
+      test++;
+
+      binvert_limb (dinv, dp[0]);
+
+      rran0 = random_word (rands);
+      rran1 = random_word (rands);
+      qran0 = random_word (rands);
+      qran1 = random_word (rands);
+
+      qp[-1] = qran0;
+      qp[nn - dn + 1] = qran1;
+      rp[-1] = rran0;
+
+      ran = random_word (rands);
+
+      if ((double) (nn - dn) * dn < 1e5)
+	{
+	  if (nn > dn)
+	    {
+	      /* Test mpn_sbpi1_bdiv_qr */
+	      MPN_ZERO (qp, nn - dn);
+	      MPN_ZERO (rp, dn);
+	      MPN_COPY (rp, np, nn);
+	      rh = mpn_sbpi1_bdiv_qr (qp, rp, nn, dp, dn, -dinv);
+	      ASSERT_ALWAYS (qp[-1] == qran0);  ASSERT_ALWAYS (qp[nn - dn + 1] == qran1);
+	      ASSERT_ALWAYS (rp[-1] == rran0);
+	      check_one (qp, rp + nn - dn, rh, np, nn, dp, dn, "mpn_sbpi1_bdiv_qr");
+
+	      /* Test mpn_sbpi1_bdiv_q */
+	      MPN_COPY (rp, np, nn);
+	      MPN_ZERO (qp, nn - dn);
+	      mpn_sbpi1_bdiv_q (qp, rp, nn - dn, dp, MIN(dn,nn-dn), -dinv);
+	      ASSERT_ALWAYS (qp[-1] == qran0);  ASSERT_ALWAYS (qp[nn - dn + 1] == qran1);
+	      ASSERT_ALWAYS (rp[-1] == rran0);
+	      check_one (qp, NULL, 0, np, nn, dp, dn, "mpn_sbpi1_bdiv_q");
+
+	      /* Test mpn_sbpi1_bdiv_r; we use mpn_sbpi1_bdiv_q's quotient. */
+	      MPN_COPY (rp, np, nn);
+	      mpn_sbpi1_bdiv_r (rp, nn, dp, dn, -dinv);
+	      ASSERT_ALWAYS (rp[-1] == rran0);
+	      check_one (qp, NULL, 0, np, nn, dp, dn, "mpn_sbpi1_bdiv_r");
+	    }
+	}
+
+      if (dn >= 4 && nn - dn >= 2)
+	{
+	  /* Test mpn_dcpi1_bdiv_qr */
+	  MPN_COPY (rp, np, nn);
+	  MPN_ZERO (qp, nn - dn);
+	  rh = mpn_dcpi1_bdiv_qr (qp, rp, nn, dp, dn, -dinv);
+	  ASSERT_ALWAYS (qp[-1] == qran0);  ASSERT_ALWAYS (qp[nn - dn + 1] == qran1);
+	  ASSERT_ALWAYS (rp[-1] == rran0);
+	  check_one (qp, rp + nn - dn, rh, np, nn, dp, dn, "mpn_dcpi1_bdiv_qr");
+	}
+
+      if (dn >= 4 && nn - dn >= 2)
+	{
+	  /* Test mpn_dcpi1_bdiv_q */
+	  MPN_COPY (rp, np, nn);
+	  MPN_ZERO (qp, nn - dn);
+	  mpn_dcpi1_bdiv_q (qp, rp, nn - dn, dp, MIN(dn,nn-dn), -dinv);
+	  ASSERT_ALWAYS (qp[-1] == qran0);  ASSERT_ALWAYS (qp[nn - dn + 1] == qran1);
+	  ASSERT_ALWAYS (rp[-1] == rran0);
+	  check_one (qp, NULL, 0, np, nn, dp, dn, "mpn_dcpi1_bdiv_q");
+	}
+
+      if (nn > dn)
+	{
+	  /* Test mpn_bdiv_qr */
+	  itch = mpn_bdiv_qr_itch (nn, dn);
+	  if (itch + 1 > alloc)
+	    {
+	      scratch = __GMP_REALLOCATE_FUNC_LIMBS (scratch, alloc, itch + 1);
+	      alloc = itch + 1;
+	    }
+	  scratch[itch] = ran;
+	  MPN_ZERO (qp, nn - dn);
+	  MPN_ZERO (rp, dn);
+	  rp[dn] = rran1;
+	  rh = mpn_bdiv_qr (qp, rp, np, nn, dp, dn, scratch);
+	  ASSERT_ALWAYS (ran == scratch[itch]);
+	  ASSERT_ALWAYS (qp[-1] == qran0);  ASSERT_ALWAYS (qp[nn - dn + 1] == qran1);
+	  ASSERT_ALWAYS (rp[-1] == rran0);  ASSERT_ALWAYS (rp[dn] == rran1);
+
+	  check_one (qp, rp, rh, np, nn, dp, dn, "mpn_bdiv_qr");
+	}
+
+      if (nn - dn < 2 || dn < 2)
+	continue;
+
+      /* Test mpn_mu_bdiv_qr */
+      itch = mpn_mu_bdiv_qr_itch (nn, dn);
+      if (itch + 1 > alloc)
+	{
+	  scratch = __GMP_REALLOCATE_FUNC_LIMBS (scratch, alloc, itch + 1);
+	  alloc = itch + 1;
+	}
+      scratch[itch] = ran;
+      MPN_ZERO (qp, nn - dn);
+      MPN_ZERO (rp, dn);
+      rp[dn] = rran1;
+      rh = mpn_mu_bdiv_qr (qp, rp, np, nn, dp, dn, scratch);
+      ASSERT_ALWAYS (ran == scratch[itch]);
+      ASSERT_ALWAYS (qp[-1] == qran0);  ASSERT_ALWAYS (qp[nn - dn + 1] == qran1);
+      ASSERT_ALWAYS (rp[-1] == rran0);  ASSERT_ALWAYS (rp[dn] == rran1);
+      check_one (qp, rp, rh, np, nn, dp, dn, "mpn_mu_bdiv_qr");
+
+      /* Test mpn_mu_bdiv_q */
+      itch = mpn_mu_bdiv_q_itch (nn, dn);
+      if (itch + 1 > alloc)
+	{
+	  scratch = __GMP_REALLOCATE_FUNC_LIMBS (scratch, alloc, itch + 1);
+	  alloc = itch + 1;
+	}
+      scratch[itch] = ran;
+      MPN_ZERO (qp, nn - dn + 1);
+      mpn_mu_bdiv_q (qp, np, nn - dn, dp, dn, scratch);
+      ASSERT_ALWAYS (ran == scratch[itch]);
+      ASSERT_ALWAYS (qp[-1] == qran0);  ASSERT_ALWAYS (qp[nn - dn + 1] == qran1);
+      check_one (qp, NULL, 0, np, nn, dp, dn, "mpn_mu_bdiv_q");
+    }
+
+  __GMP_FREE_FUNC_LIMBS (scratch, alloc);
+
+  TMP_FREE;
+
+  mpz_clear (n);
+  mpz_clear (d);
+  mpz_clear (tz);
+
+  tests_end ();
+  return 0;
+}
diff --git a/third_party/gmp/tests/mpn/t-broot.c b/third_party/gmp/tests/mpn/t-broot.c
new file mode 100644
index 0000000..bd8e80f
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-broot.c
@@ -0,0 +1,108 @@
+/* Copyright 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+#include <stdlib.h>		/* for strtol */
+#include <stdio.h>		/* for printf */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+#include "tests/tests.h"
+
+#define MAX_LIMBS 150
+#define COUNT 500
+
+int
+main (int argc, char **argv)
+{
+  gmp_randstate_ptr rands;
+
+  mp_ptr ap, rp, pp, scratch;
+  int count = COUNT;
+  unsigned i;
+  TMP_DECL;
+
+  TMP_MARK;
+
+  TESTS_REPS (count, argv, argc);
+
+  tests_start ();
+  rands = RANDS;
+
+  ap = TMP_ALLOC_LIMBS (MAX_LIMBS);
+  rp = TMP_ALLOC_LIMBS (MAX_LIMBS);
+  pp = TMP_ALLOC_LIMBS (MAX_LIMBS);
+  scratch = TMP_ALLOC_LIMBS (3*MAX_LIMBS); /* For mpn_powlo */
+
+  for (i = 0; i < count; i++)
+    {
+      mp_size_t n;
+      mp_limb_t k;
+      int c;
+
+      n = 1 + gmp_urandomm_ui (rands, MAX_LIMBS);
+
+      if (i & 1)
+	mpn_random2 (ap, n);
+      else
+	mpn_random (ap, n);
+
+      ap[0] |= 1;
+
+      if (i < 100)
+	k = 3 + 2*i;
+      else
+	{
+	  mpn_random (&k, 1);
+	  if (k < 3)
+	    k = 3;
+	  else
+	    k |= 1;
+	}
+      mpn_broot (rp, ap, n, k);
+      mpn_powlo (pp, rp, &k, 1, n, scratch);
+
+      MPN_CMP (c, ap, pp, n);
+      if (c != 0)
+	{
+	  gmp_fprintf (stderr,
+		       "mpn_broot returned bad result: %u limbs\n",
+		       (unsigned) n);
+	  gmp_fprintf (stderr, "k   = %Mx\n", k);
+	  gmp_fprintf (stderr, "a   = %Nx\n", ap, n);
+	  gmp_fprintf (stderr, "r   = %Nx\n", rp, n);
+	  gmp_fprintf (stderr, "r^k = %Nx\n", pp, n);
+	  abort ();
+	}
+    }
+
+  mpn_broot (rp, ap, MAX_LIMBS, 1);
+  if (mpn_cmp (ap, rp, MAX_LIMBS) != 0)
+    {
+      gmp_fprintf (stderr,
+		   "mpn_broot returned bad result: %u limbs\n",
+		   (unsigned) MAX_LIMBS);
+      gmp_fprintf (stderr, "k   = %Mx\n", 1);
+      gmp_fprintf (stderr, "a   = %Nx\n", ap, MAX_LIMBS);
+      gmp_fprintf (stderr, "r   = %Nx\n", rp, MAX_LIMBS);
+      abort ();
+    }
+
+  TMP_FREE;
+  tests_end ();
+  return 0;
+}
diff --git a/third_party/gmp/tests/mpn/t-brootinv.c b/third_party/gmp/tests/mpn/t-brootinv.c
new file mode 100644
index 0000000..f5a9950
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-brootinv.c
@@ -0,0 +1,96 @@
+/* Copyright 2012, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+#include <stdlib.h>		/* for strtol */
+#include <stdio.h>		/* for printf */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+#include "tests/tests.h"
+
+#define MAX_LIMBS 150
+#define COUNT 500
+
+int
+main (int argc, char **argv)
+{
+  gmp_randstate_ptr rands;
+
+  mp_ptr ap, rp, pp, app, scratch;
+  int count = COUNT;
+  unsigned i;
+  TMP_DECL;
+
+  TMP_MARK;
+
+  TESTS_REPS (count, argv, argc);
+
+  tests_start ();
+  rands = RANDS;
+
+  ap = TMP_ALLOC_LIMBS (MAX_LIMBS);
+  rp = TMP_ALLOC_LIMBS (MAX_LIMBS);
+  pp = TMP_ALLOC_LIMBS (MAX_LIMBS);
+  app = TMP_ALLOC_LIMBS (MAX_LIMBS);
+  scratch = TMP_ALLOC_LIMBS (5*MAX_LIMBS);
+
+  for (i = 0; i < count; i++)
+    {
+      mp_size_t n;
+      mp_limb_t k;
+
+      n = 1 + gmp_urandomm_ui (rands, MAX_LIMBS);
+
+      if (i & 1)
+	mpn_random2 (ap, n);
+      else
+	mpn_random (ap, n);
+
+      ap[0] |= 1;
+
+      if (i < 100)
+	k = 3 + 2*i;
+      else
+	{
+	  mpn_random (&k, 1);
+	  if (k < 3)
+	    k = 3;
+	  else
+	    k |= 1;
+	}
+      mpn_brootinv (rp, ap, n, k, scratch);
+      mpn_powlo (pp, rp, &k, 1, n, scratch);
+      mpn_mullo_n (app, ap, pp, n);
+
+      if (app[0] != 1 || !(n == 1 || mpn_zero_p (app+1, n-1)))
+	{
+	  gmp_fprintf (stderr,
+		       "mpn_brootinv returned bad result: %u limbs\n",
+		       (unsigned) n);
+	  gmp_fprintf (stderr, "k     = %Mx\n", k);
+	  gmp_fprintf (stderr, "a     = %Nx\n", ap, n);
+	  gmp_fprintf (stderr, "r     = %Nx\n", rp, n);
+	  gmp_fprintf (stderr, "r^n   = %Nx\n", pp, n);
+	  gmp_fprintf (stderr, "a r^n = %Nx\n", app, n);
+	  abort ();
+	}
+    }
+  TMP_FREE;
+  tests_end ();
+  return 0;
+}
diff --git a/third_party/gmp/tests/mpn/t-div.c b/third_party/gmp/tests/mpn/t-div.c
new file mode 100644
index 0000000..110385f
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-div.c
@@ -0,0 +1,497 @@
+/* Copyright 2006, 2007, 2009, 2010, 2013-2015, 2018 Free Software
+   Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+#include <stdlib.h>		/* for strtol */
+#include <stdio.h>		/* for printf */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+#include "tests/tests.h"
+
+
+static void
+dumpy (mp_srcptr p, mp_size_t n)
+{
+  mp_size_t i;
+  if (n > 20)
+    {
+      for (i = n - 1; i >= n - 4; i--)
+	{
+	  printf ("%0*lx", (int) (2 * sizeof (mp_limb_t)), p[i]);
+	  printf (" ");
+	}
+      printf ("... ");
+      for (i = 3; i >= 0; i--)
+	{
+	  printf ("%0*lx", (int) (2 * sizeof (mp_limb_t)), p[i]);
+	  printf (i == 0 ? "" : " ");
+	}
+    }
+  else
+    {
+      for (i = n - 1; i >= 0; i--)
+	{
+	  printf ("%0*lx", (int) (2 * sizeof (mp_limb_t)), p[i]);
+	  printf (i == 0 ? "" : " ");
+	}
+    }
+  puts ("");
+}
+
+static signed long test;
+
+static void
+check_one (mp_ptr qp, mp_srcptr rp,
+	   mp_srcptr np, mp_size_t nn, mp_srcptr dp, mp_size_t dn,
+	   const char *fname, mp_limb_t q_allowed_err)
+{
+  mp_size_t qn = nn - dn + 1;
+  mp_ptr tp;
+  const char *msg;
+  const char *tvalue;
+  mp_limb_t i;
+  TMP_DECL;
+  TMP_MARK;
+
+  tp = TMP_ALLOC_LIMBS (nn + 1);
+  if (dn >= qn)
+    refmpn_mul (tp, dp, dn, qp, qn);
+  else
+    refmpn_mul (tp, qp, qn, dp, dn);
+
+  for (i = 0; i < q_allowed_err && (tp[nn] > 0 || mpn_cmp (tp, np, nn) > 0); i++)
+    ASSERT_NOCARRY (refmpn_sub (tp, tp, nn+1, dp, dn));
+
+  if (tp[nn] > 0 || mpn_cmp (tp, np, nn) > 0)
+    {
+      msg = "q too large";
+      tvalue = "Q*D";
+    error:
+      printf ("\r*******************************************************************************\n");
+      printf ("%s failed test %ld: %s\n", fname, test, msg);
+      printf ("N=    "); dumpy (np, nn);
+      printf ("D=    "); dumpy (dp, dn);
+      printf ("Q=    "); dumpy (qp, qn);
+      if (rp)
+	{ printf ("R=    "); dumpy (rp, dn); }
+      printf ("%5s=", tvalue); dumpy (tp, nn+1);
+      printf ("nn = %ld, dn = %ld, qn = %ld\n", nn, dn, qn);
+      abort ();
+    }
+
+  ASSERT_NOCARRY (refmpn_sub_n (tp, np, tp, nn));
+  tvalue = "N-Q*D";
+  if (!(nn == dn || mpn_zero_p (tp + dn, nn - dn)) || mpn_cmp (tp, dp, dn) >= 0)
+    {
+      msg = "q too small";
+      goto error;
+    }
+
+  if (rp && mpn_cmp (rp, tp, dn) != 0)
+    {
+      msg = "r incorrect";
+      goto error;
+    }
+
+  TMP_FREE;
+}
+
+
+/* These are *bit* sizes. */
+#ifndef SIZE_LOG
+#define SIZE_LOG 17
+#endif
+#define MAX_DN (1L << SIZE_LOG)
+#define MAX_NN (1L << (SIZE_LOG + 1))
+
+#define COUNT 200
+
+int
+main (int argc, char **argv)
+{
+  gmp_randstate_ptr rands;
+  unsigned long maxnbits, maxdbits, nbits, dbits;
+  mpz_t n, d, q, r, tz, junk;
+  mp_size_t maxnn, maxdn, nn, dn, clearn, i;
+  mp_ptr np, dup, dnp, qp, rp, junkp;
+  mp_limb_t t;
+  gmp_pi1_t dinv;
+  long count = COUNT;
+  mp_ptr scratch;
+  mp_limb_t ran;
+  mp_size_t alloc, itch;
+  mp_limb_t rran0, rran1, qran0, qran1;
+  TMP_DECL;
+
+  TESTS_REPS (count, argv, argc);
+
+  maxdbits = MAX_DN;
+  maxnbits = MAX_NN;
+
+  tests_start ();
+  rands = RANDS;
+
+  mpz_init (n);
+  mpz_init (d);
+  mpz_init (q);
+  mpz_init (r);
+  mpz_init (tz);
+  mpz_init (junk);
+
+  maxnn = maxnbits / GMP_NUMB_BITS + 1;
+  maxdn = maxdbits / GMP_NUMB_BITS + 1;
+
+  TMP_MARK;
+
+  qp = TMP_ALLOC_LIMBS (maxnn + 2) + 1;
+  rp = TMP_ALLOC_LIMBS (maxnn + 2) + 1;
+  dnp = TMP_ALLOC_LIMBS (maxdn);
+
+  alloc = 1;
+  scratch = __GMP_ALLOCATE_FUNC_LIMBS (alloc);
+
+  for (test = -300; test < count; test++)
+    {
+      nbits = urandom () % (maxnbits - GMP_NUMB_BITS) + 2 * GMP_NUMB_BITS;
+
+      if (test < 0)
+	dbits = (test + 300) % (nbits - 1) + 1;
+      else
+	dbits = urandom () % (nbits - 1) % maxdbits + 1;
+
+#if RAND_UNIFORM
+#define RANDFUNC mpz_urandomb
+#else
+#define RANDFUNC mpz_rrandomb
+#endif
+
+      do
+	RANDFUNC (d, rands, dbits);
+      while (mpz_sgn (d) == 0);
+      dn = SIZ (d);
+      dup = PTR (d);
+      MPN_COPY (dnp, dup, dn);
+      dnp[dn - 1] |= GMP_NUMB_HIGHBIT;
+
+      if (test % 2 == 0)
+	{
+	  RANDFUNC (n, rands, nbits);
+	  nn = SIZ (n);
+	  ASSERT_ALWAYS (nn >= dn);
+	}
+      else
+	{
+	  do
+	    {
+	      RANDFUNC (q, rands, urandom () % (nbits - dbits + 1));
+	      RANDFUNC (r, rands, urandom () % mpz_sizeinbase (d, 2));
+	      mpz_mul (n, q, d);
+	      mpz_add (n, n, r);
+	      nn = SIZ (n);
+	    }
+	  while (nn > maxnn || nn < dn);
+	}
+
+      ASSERT_ALWAYS (nn <= maxnn);
+      ASSERT_ALWAYS (dn <= maxdn);
+
+      mpz_urandomb (junk, rands, nbits);
+      junkp = PTR (junk);
+
+      np = PTR (n);
+
+      mpz_urandomb (tz, rands, 32);
+      t = mpz_get_ui (tz);
+
+      if (t % 17 == 0)
+	{
+	  dnp[dn - 1] = GMP_NUMB_MAX;
+	  dup[dn - 1] = GMP_NUMB_MAX;
+	}
+
+      switch ((int) t % 16)
+	{
+	case 0:
+	  clearn = urandom () % nn;
+	  for (i = clearn; i < nn; i++)
+	    np[i] = 0;
+	  break;
+	case 1:
+	  mpn_sub_1 (np + nn - dn, dnp, dn, urandom ());
+	  break;
+	case 2:
+	  mpn_add_1 (np + nn - dn, dnp, dn, urandom ());
+	  break;
+	}
+
+      if (dn >= 2)
+	invert_pi1 (dinv, dnp[dn - 1], dnp[dn - 2]);
+
+      rran0 = urandom ();
+      rran1 = urandom ();
+      qran0 = urandom ();
+      qran1 = urandom ();
+
+      qp[-1] = qran0;
+      qp[nn - dn + 1] = qran1;
+      rp[-1] = rran0;
+
+      ran = urandom ();
+
+      if ((double) (nn - dn) * dn < 1e5)
+	{
+	  /* Test mpn_sbpi1_div_qr */
+	  if (dn > 2)
+	    {
+	      MPN_COPY (rp, np, nn);
+	      if (nn > dn)
+		MPN_COPY (qp, junkp, nn - dn);
+	      qp[nn - dn] = mpn_sbpi1_div_qr (qp, rp, nn, dnp, dn, dinv.inv32);
+	      check_one (qp, rp, np, nn, dnp, dn, "mpn_sbpi1_div_qr", 0);
+	    }
+
+	  /* Test mpn_sbpi1_divappr_q */
+	  if (dn > 2)
+	    {
+	      MPN_COPY (rp, np, nn);
+	      if (nn > dn)
+		MPN_COPY (qp, junkp, nn - dn);
+	      qp[nn - dn] = mpn_sbpi1_divappr_q (qp, rp, nn, dnp, dn, dinv.inv32);
+	      check_one (qp, NULL, np, nn, dnp, dn, "mpn_sbpi1_divappr_q", 1);
+	    }
+
+	  /* Test mpn_sbpi1_div_q */
+	  if (dn > 2)
+	    {
+	      MPN_COPY (rp, np, nn);
+	      if (nn > dn)
+		MPN_COPY (qp, junkp, nn - dn);
+	      qp[nn - dn] = mpn_sbpi1_div_q (qp, rp, nn, dnp, dn, dinv.inv32);
+	      check_one (qp, NULL, np, nn, dnp, dn, "mpn_sbpi1_div_q", 0);
+	    }
+
+	  /* Test mpn_sec_div_qr */
+	  itch = mpn_sec_div_qr_itch (nn, dn);
+	  if (itch + 1 > alloc)
+	    {
+	      scratch = __GMP_REALLOCATE_FUNC_LIMBS (scratch, alloc, itch + 1);
+	      alloc = itch + 1;
+	    }
+	  scratch[itch] = ran;
+	  MPN_COPY (rp, np, nn);
+	  if (nn >= dn)
+	    MPN_COPY (qp, junkp, nn - dn + 1);
+	  qp[nn - dn] = mpn_sec_div_qr (qp, rp, nn, dup, dn, scratch);
+	  ASSERT_ALWAYS (ran == scratch[itch]);
+	  check_one (qp, rp, np, nn, dup, dn, "mpn_sec_div_qr (unnorm)", 0);
+
+	  /* Test mpn_sec_div_r */
+	  itch = mpn_sec_div_r_itch (nn, dn);
+	  if (itch + 1 > alloc)
+	    {
+	      scratch = __GMP_REALLOCATE_FUNC_LIMBS (scratch, alloc, itch + 1);
+	      alloc = itch + 1;
+	    }
+	  scratch[itch] = ran;
+	  MPN_COPY (rp, np, nn);
+	  mpn_sec_div_r (rp, nn, dup, dn, scratch);
+	  ASSERT_ALWAYS (ran == scratch[itch]);
+	  /* Note: Since check_one cannot cope with remainder-only functions, we
+	     pass qp[] from the previous function, mpn_sec_div_qr.  */
+	  check_one (qp, rp, np, nn, dup, dn, "mpn_sec_div_r (unnorm)", 0);
+
+	  /* Normalised case, mpn_sec_div_qr */
+	  itch = mpn_sec_div_qr_itch (nn, dn);
+	  scratch[itch] = ran;
+
+	  MPN_COPY (rp, np, nn);
+	  if (nn >= dn)
+	    MPN_COPY (qp, junkp, nn - dn + 1);
+	  qp[nn - dn] = mpn_sec_div_qr (qp, rp, nn, dnp, dn, scratch);
+	  ASSERT_ALWAYS (ran == scratch[itch]);
+	  check_one (qp, rp, np, nn, dnp, dn, "mpn_sec_div_qr (norm)", 0);
+
+	  /* Normalised case, mpn_sec_div_r */
+	  itch = mpn_sec_div_r_itch (nn, dn);
+	  scratch[itch] = ran;
+	  MPN_COPY (rp, np, nn);
+	  mpn_sec_div_r (rp, nn, dnp, dn, scratch);
+	  ASSERT_ALWAYS (ran == scratch[itch]);
+	  /* Note: Since check_one cannot cope with remainder-only functions, we
+	     pass qp[] from the previous function, mpn_sec_div_qr.  */
+	  check_one (qp, rp, np, nn, dnp, dn, "mpn_sec_div_r (norm)", 0);
+	}
+
+      /* Test mpn_dcpi1_div_qr */
+      if (dn >= 6 && nn - dn >= 3)
+	{
+	  MPN_COPY (rp, np, nn);
+	  if (nn > dn)
+	    MPN_COPY (qp, junkp, nn - dn);
+	  qp[nn - dn] = mpn_dcpi1_div_qr (qp, rp, nn, dnp, dn, &dinv);
+	  ASSERT_ALWAYS (qp[-1] == qran0);  ASSERT_ALWAYS (qp[nn - dn + 1] == qran1);
+	  ASSERT_ALWAYS (rp[-1] == rran0);
+	  check_one (qp, rp, np, nn, dnp, dn, "mpn_dcpi1_div_qr", 0);
+	}
+
+      /* Test mpn_dcpi1_divappr_q */
+      if (dn >= 6 && nn - dn >= 3)
+	{
+	  MPN_COPY (rp, np, nn);
+	  if (nn > dn)
+	    MPN_COPY (qp, junkp, nn - dn);
+	  qp[nn - dn] = mpn_dcpi1_divappr_q (qp, rp, nn, dnp, dn, &dinv);
+	  ASSERT_ALWAYS (qp[-1] == qran0);  ASSERT_ALWAYS (qp[nn - dn + 1] == qran1);
+	  ASSERT_ALWAYS (rp[-1] == rran0);
+	  check_one (qp, NULL, np, nn, dnp, dn, "mpn_dcpi1_divappr_q", 1);
+	}
+
+      /* Test mpn_dcpi1_div_q */
+      if (dn >= 6 && nn - dn >= 3)
+	{
+	  MPN_COPY (rp, np, nn);
+	  if (nn > dn)
+	    MPN_COPY (qp, junkp, nn - dn);
+	  qp[nn - dn] = mpn_dcpi1_div_q (qp, rp, nn, dnp, dn, &dinv);
+	  ASSERT_ALWAYS (qp[-1] == qran0);  ASSERT_ALWAYS (qp[nn - dn + 1] == qran1);
+	  ASSERT_ALWAYS (rp[-1] == rran0);
+	  check_one (qp, NULL, np, nn, dnp, dn, "mpn_dcpi1_div_q", 0);
+	}
+
+     /* Test mpn_mu_div_qr */
+      if (nn - dn > 2 && dn >= 2)
+	{
+	  itch = mpn_mu_div_qr_itch (nn, dn, 0);
+	  if (itch + 1 > alloc)
+	    {
+	      scratch = __GMP_REALLOCATE_FUNC_LIMBS (scratch, alloc, itch + 1);
+	      alloc = itch + 1;
+	    }
+	  scratch[itch] = ran;
+	  MPN_COPY (qp, junkp, nn - dn);
+	  MPN_ZERO (rp, dn);
+	  rp[dn] = rran1;
+	  qp[nn - dn] = mpn_mu_div_qr (qp, rp, np, nn, dnp, dn, scratch);
+	  ASSERT_ALWAYS (ran == scratch[itch]);
+	  ASSERT_ALWAYS (qp[-1] == qran0);  ASSERT_ALWAYS (qp[nn - dn + 1] == qran1);
+	  ASSERT_ALWAYS (rp[-1] == rran0);  ASSERT_ALWAYS (rp[dn] == rran1);
+	  check_one (qp, rp, np, nn, dnp, dn, "mpn_mu_div_qr", 0);
+	}
+
+      /* Test mpn_mu_divappr_q */
+      if (nn - dn > 2 && dn >= 2)
+	{
+	  itch = mpn_mu_divappr_q_itch (nn, dn, 0);
+	  if (itch + 1 > alloc)
+	    {
+	      scratch = __GMP_REALLOCATE_FUNC_LIMBS (scratch, alloc, itch + 1);
+	      alloc = itch + 1;
+	    }
+	  scratch[itch] = ran;
+	  MPN_COPY (qp, junkp, nn - dn);
+	  qp[nn - dn] = mpn_mu_divappr_q (qp, np, nn, dnp, dn, scratch);
+	  ASSERT_ALWAYS (ran == scratch[itch]);
+	  ASSERT_ALWAYS (qp[-1] == qran0);  ASSERT_ALWAYS (qp[nn - dn + 1] == qran1);
+	  check_one (qp, NULL, np, nn, dnp, dn, "mpn_mu_divappr_q", 4);
+	}
+
+      /* Test mpn_mu_div_q */
+      if (nn - dn > 2 && dn >= 2)
+	{
+	  itch = mpn_mu_div_q_itch (nn, dn, 0);
+	  if (itch + 1> alloc)
+	    {
+	      scratch = __GMP_REALLOCATE_FUNC_LIMBS (scratch, alloc, itch + 1);
+	      alloc = itch + 1;
+	    }
+	  scratch[itch] = ran;
+	  MPN_COPY (qp, junkp, nn - dn);
+	  qp[nn - dn] = mpn_mu_div_q (qp, np, nn, dnp, dn, scratch);
+	  ASSERT_ALWAYS (ran == scratch[itch]);
+	  ASSERT_ALWAYS (qp[-1] == qran0);  ASSERT_ALWAYS (qp[nn - dn + 1] == qran1);
+	  check_one (qp, NULL, np, nn, dnp, dn, "mpn_mu_div_q", 0);
+	}
+
+      if (1)
+	{
+	  itch = nn + 1;
+	  if (itch + 1> alloc)
+	    {
+	      scratch = __GMP_REALLOCATE_FUNC_LIMBS (scratch, alloc, itch + 1);
+	      alloc = itch + 1;
+	    }
+	  scratch[itch] = ran;
+	  MPN_COPY (qp, junkp, nn - dn + 1);
+	  mpn_div_q (qp, np, nn, dup, dn, scratch);
+	  ASSERT_ALWAYS (ran == scratch[itch]);
+	  ASSERT_ALWAYS (qp[-1] == qran0);  ASSERT_ALWAYS (qp[nn - dn + 1] == qran1);
+	  check_one (qp, NULL, np, nn, dup, dn, "mpn_div_q", 0);
+	}
+
+      if (dn >= 2 && nn >= 2)
+	{
+	  mp_limb_t qh;
+
+	  /* mpn_divrem_2 */
+	  MPN_COPY (rp, np, nn);
+	  qp[nn - 2] = qp[nn-1] = qran1;
+
+	  qh = mpn_divrem_2 (qp, 0, rp, nn, dnp + dn - 2);
+	  ASSERT_ALWAYS (qp[nn - 2] == qran1);
+	  ASSERT_ALWAYS (qp[-1] == qran0);  ASSERT_ALWAYS (qp[nn - 1] == qran1);
+	  qp[nn - 2] = qh;
+	  check_one (qp, rp, np, nn, dnp + dn - 2, 2, "mpn_divrem_2", 0);
+
+	  /* Missing: divrem_2 with fraction limbs. */
+
+	  /* mpn_div_qr_2 */
+	  qp[nn - 2] = qran1;
+
+	  qh = mpn_div_qr_2 (qp, rp, np, nn, dup + dn - 2);
+	  ASSERT_ALWAYS (qp[nn - 2] == qran1);
+	  ASSERT_ALWAYS (qp[-1] == qran0);  ASSERT_ALWAYS (qp[nn - 1] == qran1);
+	  qp[nn - 2] = qh;
+	  check_one (qp, rp, np, nn, dup + dn - 2, 2, "mpn_div_qr_2", 0);
+	}
+      if (dn >= 1 && nn >= 1)
+	{
+	  /* mpn_div_qr_1 */
+	  mp_limb_t qh;
+	  qp[nn-1] = qran1;
+	  rp[0] = mpn_div_qr_1 (qp, &qh, np, nn, dnp[dn - 1]);
+	  ASSERT_ALWAYS (qp[-1] == qran0); ASSERT_ALWAYS (qp[nn - 1] == qran1);
+	  qp[nn - 1] = qh;
+	  check_one (qp, rp, np, nn,  dnp + dn - 1, 1, "mpn_div_qr_1", 0);
+	}
+    }
+
+  __GMP_FREE_FUNC_LIMBS (scratch, alloc);
+
+  TMP_FREE;
+
+  mpz_clear (n);
+  mpz_clear (d);
+  mpz_clear (q);
+  mpz_clear (r);
+  mpz_clear (tz);
+  mpz_clear (junk);
+
+  tests_end ();
+  return 0;
+}
diff --git a/third_party/gmp/tests/mpn/t-divrem_1.c b/third_party/gmp/tests/mpn/t-divrem_1.c
new file mode 100644
index 0000000..991b7da
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-divrem_1.c
@@ -0,0 +1,123 @@
+/* Test mpn_divrem_1 and mpn_preinv_divrem_1.
+
+Copyright 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_data (void)
+{
+  static const struct {
+    mp_limb_t  n[1];
+    mp_size_t  nsize;
+    mp_limb_t  d;
+    mp_size_t  qxn;
+    mp_limb_t  want_q[5];
+    mp_limb_t  want_r;
+  } data[] = {
+    { { 0 }, 1, 1, 0,
+      { 0 }, 0},
+
+    { { 5 }, 1, 2, 0,
+      { 2 }, 1},
+
+    /* Exercises the q update in the nl == constant 0 case of
+       udiv_qrnnd_preinv3. Test case copied from t-fat.c. */
+    { { 287 }, 1, 7, 1,
+      { 0, 41 }, 0 },
+
+#if GMP_NUMB_BITS == 32
+    { { 0x3C }, 1, 0xF2, 1,
+      { 0x3F789854, 0 }, 0x98 },
+#endif
+
+#if GMP_NUMB_BITS == 64
+    { { 0x3C }, 1, 0xF2, 1,
+      { CNST_LIMB(0x3F789854A0CB1B81), 0 }, 0x0E },
+
+    /* This case exposed some wrong code generated by SGI cc on mips64 irix
+       6.5 with -n32 -O2, in the fractional loop for normalized divisor
+       using udiv_qrnnd_preinv.  A test "x>al" in one of the sub_ddmmss
+       expansions came out wrong, leading to an incorrect quotient.  */
+    { { CNST_LIMB(0x3C00000000000000) }, 1, CNST_LIMB(0xF200000000000000), 1,
+      { CNST_LIMB(0x3F789854A0CB1B81), 0 }, CNST_LIMB(0x0E00000000000000) },
+#endif
+  };
+
+  mp_limb_t  dinv, got_r, got_q[numberof(data[0].want_q)];
+  mp_size_t  qsize;
+  int        i, shift;
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      qsize = data[i].nsize + data[i].qxn;
+      ASSERT_ALWAYS (qsize <= numberof (got_q));
+
+      got_r = mpn_divrem_1 (got_q, data[i].qxn, data[i].n, data[i].nsize,
+                            data[i].d);
+      if (got_r != data[i].want_r
+          || refmpn_cmp (got_q, data[i].want_q, qsize) != 0)
+        {
+          printf        ("mpn_divrem_1 wrong at data[%d]\n", i);
+        bad:
+          mpn_trace     ("  n", data[i].n, data[i].nsize);
+          printf        ("  nsize=%ld\n", (long) data[i].nsize);
+          mp_limb_trace ("  d", data[i].d);
+          printf        ("  qxn=%ld\n", (long) data[i].qxn);
+          mpn_trace     ("  want q", data[i].want_q, qsize);
+          mpn_trace     ("  got  q", got_q, qsize);
+          mp_limb_trace ("  want r", data[i].want_r);
+          mp_limb_trace ("  got  r", got_r);
+          abort ();
+        }
+
+      /* test if available */
+#if USE_PREINV_DIVREM_1 || HAVE_NATIVE_mpn_preinv_divrem_1
+      shift = refmpn_count_leading_zeros (data[i].d);
+      dinv = refmpn_invert_limb (data[i].d << shift);
+      got_r = mpn_preinv_divrem_1 (got_q, data[i].qxn,
+                                   data[i].n, data[i].nsize,
+                                   data[i].d, dinv, shift);
+      if (got_r != data[i].want_r
+          || refmpn_cmp (got_q, data[i].want_q, qsize) != 0)
+        {
+          printf        ("mpn_preinv divrem_1 wrong at data[%d]\n", i);
+          printf        ("  shift=%d\n", shift);
+          mp_limb_trace ("  dinv", dinv);
+          goto bad;
+        }
+#endif
+    }
+}
+
+int
+main (void)
+{
+  tests_start ();
+  mp_trace_base = -16;
+
+  check_data ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpn/t-fat.c b/third_party/gmp/tests/mpn/t-fat.c
new file mode 100644
index 0000000..4e71017
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-fat.c
@@ -0,0 +1,310 @@
+/* Test fat binary setups.
+
+Copyright 2003, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gmp-impl.h"
+#include "longlong.h"
+#include "tests.h"
+
+
+/* In this program we're aiming to pick up certain subtle problems that
+   might creep into a fat binary.
+
+   1. We want to ensure the application entry point routines like
+      __gmpn_add_n dispatch to the correct field of __gmpn_cpuvec.
+
+      Note that these routines are not exercised as a side effect of other
+      tests (eg. the mpz routines).  Internally the fields of __gmpn_cpuvec
+      are used directly, so we need to write test code explicitly calling
+      the mpn functions, like an application will have.
+
+   2. We want to ensure the initial __gmpn_cpuvec data has the initializer
+      function pointers in the correct fields, and that those initializer
+      functions dispatch to their correct corresponding field once
+      initialization has been done.
+
+      Only one of the initializer routines executes in a normal program,
+      since that routine sets all the pointers to actual mpn functions.  We
+      forcibly reset __gmpn_cpuvec so we can run each.
+
+   In both cases for the above, the data put through the functions is
+   nothing special, just enough to verify that for instance an add_n is
+   really doing an add_n and has not for instance mistakenly gone to sub_n
+   or something.
+
+   The loop around each test will exercise the initializer routine on the
+   first iteration, and the dispatcher routine on the second.
+
+   If the dispatcher and/or initializer routines are generated mechanically
+   via macros (eg. mpn/x86/fat/fat_entry.asm) then there shouldn't be too
+   much risk of them going wrong, provided the structure layout is correctly
+   expressed.  But if they're in C then it's good to guard against typos in
+   what is rather repetitive code.  The initializer data for __gmpn_cpuvec
+   in fat.c is always done by hand and is likewise a bit repetitive.  */
+
+
+/* dummies when not a fat binary */
+#if ! WANT_FAT_BINARY
+struct cpuvec_t {
+  int  dummy;
+};
+struct cpuvec_t __gmpn_cpuvec;
+#define ITERATE_FAT_THRESHOLDS()  do { } while (0)
+#endif
+
+/* saved from program startup */
+struct cpuvec_t  initial_cpuvec;
+
+void
+check_functions (void)
+{
+  mp_limb_t  wp[2], xp[2], yp[2], r;
+  int  i;
+
+  memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
+  for (i = 0; i < 2; i++)
+    {
+      xp[0] = 123;
+      yp[0] = 456;
+      mpn_add_n (wp, xp, yp, (mp_size_t) 1);
+      ASSERT_ALWAYS (wp[0] == 579);
+    }
+
+  memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
+  for (i = 0; i < 2; i++)
+    {
+      xp[0] = 123;
+      wp[0] = 456;
+      r = mpn_addmul_1 (wp, xp, (mp_size_t) 1, CNST_LIMB(2));
+      ASSERT_ALWAYS (wp[0] == 702);
+      ASSERT_ALWAYS (r == 0);
+    }
+
+#if HAVE_NATIVE_mpn_copyd
+  memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
+  for (i = 0; i < 2; i++)
+    {
+      xp[0] = 123;
+      xp[1] = 456;
+      mpn_copyd (xp+1, xp, (mp_size_t) 1);
+      ASSERT_ALWAYS (xp[1] == 123);
+    }
+#endif
+
+#if HAVE_NATIVE_mpn_copyi
+  memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
+  for (i = 0; i < 2; i++)
+    {
+      xp[0] = 123;
+      xp[1] = 456;
+      mpn_copyi (xp, xp+1, (mp_size_t) 1);
+      ASSERT_ALWAYS (xp[0] == 456);
+    }
+#endif
+
+  memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
+  for (i = 0; i < 2; i++)
+    {
+      xp[0] = 1605;
+      mpn_divexact_1 (wp, xp, (mp_size_t) 1, CNST_LIMB(5));
+      ASSERT_ALWAYS (wp[0] == 321);
+    }
+
+  memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
+  for (i = 0; i < 2; i++)
+    {
+      xp[0] = 1296;
+      r = mpn_divexact_by3c (wp, xp, (mp_size_t) 1, CNST_LIMB(0));
+      ASSERT_ALWAYS (wp[0] == 432);
+      ASSERT_ALWAYS (r == 0);
+    }
+
+  memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
+  for (i = 0; i < 2; i++)
+    {
+      xp[0] = 287;
+      r = mpn_divrem_1 (wp, (mp_size_t) 1, xp, (mp_size_t) 1, CNST_LIMB(7));
+      ASSERT_ALWAYS (wp[1] == 41);
+      ASSERT_ALWAYS (wp[0] == 0);
+      ASSERT_ALWAYS (r == 0);
+    }
+
+  memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
+  for (i = 0; i < 2; i++)
+    {
+      xp[0] = 12;
+      r = mpn_gcd_1 (xp, (mp_size_t) 1, CNST_LIMB(9));
+      ASSERT_ALWAYS (r == 3);
+    }
+
+  memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
+  for (i = 0; i < 2; i++)
+    {
+      xp[0] = 0x1001;
+      mpn_lshift (wp, xp, (mp_size_t) 1, 1);
+      ASSERT_ALWAYS (wp[0] == 0x2002);
+    }
+
+  memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
+  for (i = 0; i < 2; i++)
+    {
+      xp[0] = 14;
+      r = mpn_mod_1 (xp, (mp_size_t) 1, CNST_LIMB(4));
+      ASSERT_ALWAYS (r == 2);
+    }
+
+#if (GMP_NUMB_BITS % 4) == 0
+  memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
+  for (i = 0; i < 2; i++)
+    {
+      int  bits = (GMP_NUMB_BITS / 4) * 3;
+      mp_limb_t  mod = (CNST_LIMB(1) << bits) - 1;
+      mp_limb_t  want = GMP_NUMB_MAX % mod;
+      xp[0] = GMP_NUMB_MAX;
+      r = mpn_mod_34lsub1 (xp, (mp_size_t) 1);
+      ASSERT_ALWAYS (r % mod == want);
+    }
+#endif
+
+  /*   DECL_modexact_1c_odd ((*modexact_1c_odd)); */
+
+  memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
+  for (i = 0; i < 2; i++)
+    {
+      xp[0] = 14;
+      r = mpn_mul_1 (wp, xp, (mp_size_t) 1, CNST_LIMB(4));
+      ASSERT_ALWAYS (wp[0] == 56);
+      ASSERT_ALWAYS (r == 0);
+    }
+
+  memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
+  for (i = 0; i < 2; i++)
+    {
+      xp[0] = 5;
+      yp[0] = 7;
+      mpn_mul_basecase (wp, xp, (mp_size_t) 1, yp, (mp_size_t) 1);
+      ASSERT_ALWAYS (wp[0] == 35);
+      ASSERT_ALWAYS (wp[1] == 0);
+    }
+
+  memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
+  for (i = 0; i < 2; i++)
+    {
+      xp[0] = 5;
+      yp[0] = 7;
+      mpn_mullo_basecase (wp, xp, yp, (mp_size_t) 1);
+      ASSERT_ALWAYS (wp[0] == 35);
+    }
+
+#if HAVE_NATIVE_mpn_preinv_divrem_1 && GMP_NAIL_BITS == 0
+  memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
+  for (i = 0; i < 2; i++)
+    {
+      xp[0] = 0x101;
+      r = mpn_preinv_divrem_1 (wp, (mp_size_t) 1, xp, (mp_size_t) 1,
+                               GMP_LIMB_HIGHBIT,
+                               refmpn_invert_limb (GMP_LIMB_HIGHBIT), 0);
+      ASSERT_ALWAYS (wp[0] == 0x202);
+      ASSERT_ALWAYS (wp[1] == 0);
+      ASSERT_ALWAYS (r == 0);
+    }
+#endif
+
+#if GMP_NAIL_BITS == 0
+  memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
+  for (i = 0; i < 2; i++)
+    {
+      xp[0] = GMP_LIMB_HIGHBIT+123;
+      r = mpn_preinv_mod_1 (xp, (mp_size_t) 1, GMP_LIMB_HIGHBIT,
+                            refmpn_invert_limb (GMP_LIMB_HIGHBIT));
+      ASSERT_ALWAYS (r == 123);
+    }
+#endif
+
+  memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
+  for (i = 0; i < 2; i++)
+    {
+      xp[0] = 0x8008;
+      mpn_rshift (wp, xp, (mp_size_t) 1, 1);
+      ASSERT_ALWAYS (wp[0] == 0x4004);
+    }
+
+  memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
+  for (i = 0; i < 2; i++)
+    {
+      xp[0] = 5;
+      mpn_sqr_basecase (wp, xp, (mp_size_t) 1);
+      ASSERT_ALWAYS (wp[0] == 25);
+      ASSERT_ALWAYS (wp[1] == 0);
+    }
+
+  memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
+  for (i = 0; i < 2; i++)
+    {
+      xp[0] = 999;
+      yp[0] = 666;
+      mpn_sub_n (wp, xp, yp, (mp_size_t) 1);
+      ASSERT_ALWAYS (wp[0] == 333);
+    }
+
+  memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));
+  for (i = 0; i < 2; i++)
+    {
+      xp[0] = 123;
+      wp[0] = 456;
+      r = mpn_submul_1 (wp, xp, (mp_size_t) 1, CNST_LIMB(2));
+      ASSERT_ALWAYS (wp[0] == 210);
+      ASSERT_ALWAYS (r == 0);
+    }
+}
+
+/* Expect the first use of each fat threshold to invoke the necessary
+   initialization.  */
+void
+check_thresholds (void)
+{
+#define ITERATE(name,field)                                             \
+  do {                                                                  \
+    __gmpn_cpuvec_initialized = 0;					\
+    memcpy (&__gmpn_cpuvec, &initial_cpuvec, sizeof (__gmpn_cpuvec));   \
+    ASSERT_ALWAYS (name != 0);                                          \
+    ASSERT_ALWAYS (name == __gmpn_cpuvec.field);                        \
+    ASSERT_ALWAYS (__gmpn_cpuvec_initialized);                          \
+  } while (0)
+
+  ITERATE_FAT_THRESHOLDS ();
+}
+
+
+int
+main (void)
+{
+  memcpy (&initial_cpuvec, &__gmpn_cpuvec, sizeof (__gmpn_cpuvec));
+
+  tests_start ();
+
+  check_functions ();
+  check_thresholds ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpn/t-fib2m.c b/third_party/gmp/tests/mpn/t-fib2m.c
new file mode 100644
index 0000000..5ad3942
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-fib2m.c
@@ -0,0 +1,344 @@
+/* Test mpn_fib2m.
+
+Copyright 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#define MAX_K_BITS 16
+#define MAX_K (1L << MAX_K_BITS)
+#define MIN_K 1
+
+#define MAX_MN 20
+#define MAX_KN 30
+
+#define COUNT 200
+
+static int
+test_fib2_fib2m (int count, gmp_randstate_ptr rands)
+{
+  int test;
+  mp_ptr fk, fks1, fkm, fks1m, mp, qp;
+  mp_size_t mn, fn, size, max_mn;
+  TMP_DECL;
+
+  size = MPN_FIB2_SIZE (MAX_K);
+  max_mn = size / 4 + 10;
+  ASSERT (max_mn < size);
+
+  TMP_MARK;
+  fk	 = TMP_ALLOC_LIMBS (size);
+  fks1	 = TMP_ALLOC_LIMBS (size);
+  qp	 = TMP_ALLOC_LIMBS (size);
+  mp	 = TMP_ALLOC_LIMBS (max_mn);
+  fkm	 = 1 + TMP_ALLOC_LIMBS (max_mn * 2 + 1 + 2);
+  fks1m	 = 1 + TMP_ALLOC_LIMBS (max_mn * 2 + 1 + 2);
+
+  for (test = 1; test <= count; ++test)
+    {
+      mp_limb_t fk_before, fk_after, fk1_before, fk1_after;
+      int signflip;
+      unsigned long k;
+
+      k = MIN_K +
+	gmp_urandomm_ui (rands, test < MAX_K_BITS ?
+			 MAX_K >> test : (MAX_K - MIN_K));
+
+      fn = mpn_fib2_ui (fk, fks1, k);
+      do {
+	mn = gmp_urandomm_ui (rands, MAX_K) % (fn / 4 + 10);
+      } while (mn == 0);
+      ASSERT (mn <= max_mn);
+      mpn_random2 (mp, mn);
+      ASSERT (mp [mn - 1] != 0);
+
+      if (fn >= mn)
+	{
+	  mpn_tdiv_qr (qp, fk, 0, fk, fn, mp, mn);
+	  mpn_tdiv_qr (qp, fks1, 0, fks1, fn, mp, mn);
+	}
+      else
+	{
+	  MPN_ZERO (fk + fn, mn - fn);
+	  MPN_ZERO (fks1 + fn, mn - fn);
+	}
+
+      mpn_random2 (fkm - 1, 2*mn+1+2);
+      fk_before = fkm [-1];
+      fk_after = fkm [2 * mn + 1];
+
+      mpn_random2 (fks1m - 1, 2*mn+1+2);
+      fk1_before = fks1m [-1];
+      fk1_after = fks1m [2 * mn + 1];
+
+      qp [0] = k;
+      signflip = mpn_fib2m (fkm, fks1m, qp, 1, mp, mn);
+      if (fkm [-1] != fk_before || fkm [2 * mn + 1] != fk_after
+	  || fks1m [-1] != fk1_before || fks1m [2 * mn + 1] != fk1_after)
+	{
+	  printf ("REDZONE violation in test %d, k = %lu, mn = %u\n",
+		  test, k, (unsigned) mn);
+	  if (fkm[-1] != fk_before)
+	    {
+	      printf ("before fkm:"); mpn_dump (fkm - 1, 1);
+	      printf ("keep:   "); mpn_dump (&fk_before, 1);
+	    }
+	  if (fkm[2 * mn + 1] != fk_after)
+	    {
+	      printf ("after fkm:"); mpn_dump (fkm + 2 * mn + 1, 1);
+	      printf ("keep:   "); mpn_dump (&fk_after, 1);
+	    }
+	  if (fks1m[-1] != fk1_before)
+	    {
+	      printf ("before fks1m:"); mpn_dump (fks1m - 1, 1);
+	      printf ("keep:   "); mpn_dump (&fk1_before, 1);
+	    }
+	  if (fks1m[2 * mn + 1] != fk1_after)
+	    {
+	      printf ("after fks1m:"); mpn_dump (fks1m + 2 * mn + 1, 1);
+	      printf ("keep:   "); mpn_dump (&fk1_after, 1);
+	    }
+	  abort();
+	}
+
+      if (mpn_cmp (fkm, fk, mn) != 0)
+	{
+	  if (mpn_sub_n (fk, mp, fk, mn) || mpn_cmp (fkm, fk, mn) != 0)
+	    {
+	      printf ("ERROR(k) in test %d, k = %lu, mn = %u\n",
+		      test, k, (unsigned) mn);
+	      mpn_dump (fk, mn);
+	      mpn_dump (fkm, mn);
+	      mpn_dump (mp, mn);
+	      abort();
+	    }
+	  signflip ^= 1;
+	}
+
+      if (mpn_cmp (fks1m, fks1, mn) != 0)
+	{
+	  if (mpn_sub_n (fks1, mp, fks1, mn) || mpn_cmp (fks1m, fks1, mn) != 0)
+	    {
+	      printf ("ERROR(k-1) in test %d, k = %lu, mn = %u\n",
+		      test, k, (unsigned) mn);
+	      mpn_dump (fks1, mn);
+	      mpn_dump (fks1m, mn);
+	      mpn_dump (mp, mn);
+	      abort();
+	    }
+	  signflip ^= 1;
+	}
+
+      if (signflip != 0 && ! mpn_zero_p (fks1m, mn) && ! mpn_zero_p (fkm, mn))
+	{
+	  if ((mp [0] & 1) == 0) /* Should we test only odd modulus-es? */
+	    {
+	      if (! mpn_lshift (fks1m, fks1m, mn, 1) &&
+		  mpn_cmp (mp, fks1m, mn) == 0)
+		continue;
+	      if (! mpn_lshift (fkm, fkm, mn, 1) &&
+		  mpn_cmp (mp, fkm, mn) == 0)
+		continue;
+	    }
+	  printf ("ERROR(sign) in test %d, k = %lu, mn = %u\n",
+		  test, k, (unsigned) mn);
+	  abort();
+	}
+    }
+  TMP_FREE;
+  return 0;
+}
+
+static int
+test_fib2m_2exp (int count, gmp_randstate_ptr rands)
+{
+  int test;
+  mp_ptr fka, fks1a, fkb, fks1b, mp, kp;
+  TMP_DECL;
+
+  TMP_MARK;
+  kp	 = TMP_ALLOC_LIMBS (MAX_KN);
+  mp	 = TMP_ALLOC_LIMBS (MAX_MN);
+  fka	 = 1 + TMP_ALLOC_LIMBS (MAX_MN * 2 + 1 + 2);
+  fks1a	 = 1 + TMP_ALLOC_LIMBS (MAX_MN * 2 + 1 + 2);
+  fkb	 = 1 + TMP_ALLOC_LIMBS (MAX_MN * 2 + 1 + 2);
+  fks1b	 = 1 + TMP_ALLOC_LIMBS (MAX_MN * 2 + 1 + 2);
+
+  for (test = 1; test <= count; ++test)
+    {
+      mp_limb_t fka_before, fka_after, fk1a_before, fk1a_after;
+      mp_limb_t fkb_before, fkb_after, fk1b_before, fk1b_after;
+      mp_size_t mn, kn;
+      int signflip;
+      mp_bitcnt_t exp2;
+
+      mn = gmp_urandomm_ui (rands, MAX_MN - 1) + 1;
+      mpn_random2 (mp, mn);
+
+      exp2 = MIN_K + 1 + gmp_urandomm_ui (rands, MAX_KN * GMP_NUMB_BITS - MIN_K - 1);
+
+      kn = BITS_TO_LIMBS (exp2);
+      MPN_ZERO (kp, kn - 1);
+      kp [kn - 1] = CNST_LIMB (1) << ((exp2 - 1) % GMP_NUMB_BITS);
+
+      mpn_random2 (fka - 1, 2*mn+1+2);
+      fka_before = fka [-1];
+      fka_after = fka [2 * mn + 1];
+
+      mpn_random2 (fks1a - 1, 2*mn+1+2);
+      fk1a_before = fks1a [-1];
+      fk1a_after = fks1a [2 * mn + 1];
+
+      signflip = mpn_fib2m (fka, fks1a, kp, kn, mp, mn);
+      if (fka [-1] != fka_before || fka [2 * mn + 1] != fka_after
+	  || fks1a [-1] != fk1a_before || fks1a [2 * mn + 1] != fk1a_after)
+	{
+	  printf ("REDZONE(a) violation in test %d, exp2 = %lu\n", test, exp2);
+	  if (fka[-1] != fka_before)
+	    {
+	      printf ("before fka:"); mpn_dump (fka - 1, 1);
+	      printf ("keep:   "); mpn_dump (&fka_before, 1);
+	    }
+	  if (fka[2 * mn + 1] != fka_after)
+	    {
+	      printf ("after fka:"); mpn_dump (fka + 2 * mn + 1, 1);
+	      printf ("keep:   "); mpn_dump (&fka_after, 1);
+	    }
+	  if (fks1a[-1] != fk1a_before)
+	    {
+	      printf ("before fks1a:"); mpn_dump (fks1a - 1, 1);
+	      printf ("keep:   "); mpn_dump (&fk1a_before, 1);
+	    }
+	  if (fks1a[2 * mn + 1] != fk1a_after)
+	    {
+	      printf ("after fks1a:"); mpn_dump (fks1a + 2 * mn + 1, 1);
+	      printf ("keep:   "); mpn_dump (&fk1a_after, 1);
+	    }
+	  abort();
+	}
+
+      if (signflip && ! mpn_zero_p (fks1a, mn))
+	mpn_sub_n (fks1a, mp, fks1a, mn);
+      if (mpn_sub_n (fka, fka, fks1a, mn))
+	ASSERT_CARRY (mpn_add_n (fka, fka, mp, mn));
+
+      mpn_sub_1 (kp, kp, kn, 1);
+      ASSERT (exp2 % GMP_NUMB_BITS == 1 || kp [kn - 1] != 0);
+      kn -= kp [kn - 1] == 0;
+
+      mpn_random2 (fkb - 1, 2*mn+1+2);
+      fkb_before = fkb [-1];
+      fkb_after = fkb [2 * mn + 1];
+
+      mpn_random2 (fks1b - 1, 2*mn+1+2);
+      fk1b_before = fks1b [-1];
+      fk1b_after = fks1b [2 * mn + 1];
+
+      signflip = mpn_fib2m (fkb, fks1b, kp, kn, mp, mn);
+      if (fkb [-1] != fkb_before || fkb [2 * mn + 1] != fkb_after
+	  || fks1b [-1] != fk1b_before || fks1b [2 * mn + 1] != fk1b_after)
+	{
+	  printf ("REDZONE(b) violation in test %d, exp2 = %lu\n", test, exp2);
+	  if (fkb[-1] != fkb_before)
+	    {
+	      printf ("before fkb:"); mpn_dump (fkb - 1, 1);
+	      printf ("keep:   "); mpn_dump (&fkb_before, 1);
+	    }
+	  if (fkb[2 * mn + 1] != fkb_after)
+	    {
+	      printf ("after fkb:"); mpn_dump (fkb + 2 * mn + 1, 1);
+	      printf ("keep:   "); mpn_dump (&fkb_after, 1);
+	    }
+	  if (fks1b[-1] != fk1b_before)
+	    {
+	      printf ("before fks1b:"); mpn_dump (fks1b - 1, 1);
+	      printf ("keep:   "); mpn_dump (&fk1b_before, 1);
+	    }
+	  if (fks1b[2 * mn + 1] != fk1b_after)
+	    {
+	      printf ("after fks1b:"); mpn_dump (fks1b + 2 * mn + 1, 1);
+	      printf ("keep:   "); mpn_dump (&fk1b_after, 1);
+	    }
+	  abort();
+	}
+
+      if (mpn_cmp (fks1a, fkb, mn) != 0)
+	{
+	  if (mpn_sub_n (fkb, mp, fkb, mn) || mpn_cmp (fks1a, fkb, mn) != 0)
+	    {
+	      printf ("ERROR(k) in test %d, exp2 = %lu\n", test, exp2);
+	      mpn_dump (fks1a, mn);
+	      mpn_dump (fkb, mn);
+	      mpn_dump (mp, mn);
+	      abort();
+	    }
+	  signflip ^= 1;
+	}
+
+      if (mpn_cmp (fka, fks1b, mn) != 0)
+	{
+	  if (mpn_sub_n (fks1b, mp, fks1b, mn) || mpn_cmp (fka, fks1b, mn) != 0)
+	    {
+	      printf ("ERROR(k-1) in test %d, exp2 = %lu\n", test, exp2);
+	      mpn_dump (fka, mn);
+	      mpn_dump (fks1b, mn);
+	      mpn_dump (mp, mn);
+	      abort();
+	    }
+	  signflip ^= 1;
+	}
+
+      if (signflip != 0 && ! mpn_zero_p (fks1b, mn) && ! mpn_zero_p (fkb, mn))
+	{
+	  if ((mp [0] & 1) == 0) /* Should we test only odd modulus-es? */
+	    {
+	      if (! mpn_lshift (fks1b, fks1b, mn, 1) &&
+		  mpn_cmp (mp, fks1b, mn) == 0)
+		continue;
+	      if (! mpn_lshift (fkb, fkb, mn, 1) &&
+		  mpn_cmp (mp, fkb, mn) == 0)
+		continue;
+	    }
+	  printf ("ERROR(sign) in test %d, exp2 = %lu\n",
+		  test, exp2);
+	  abort();
+	}
+    }
+  TMP_FREE;
+  return 0;
+}
+
+int
+main (int argc, char **argv)
+{
+  int count = COUNT;
+  gmp_randstate_ptr rands;
+
+  tests_start ();
+  TESTS_REPS (count, argv, argc);
+  rands = RANDS;
+
+  test_fib2_fib2m (count / 2, rands);
+  test_fib2m_2exp (count / 2, rands);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpn/t-gcd_11.c b/third_party/gmp/tests/mpn/t-gcd_11.c
new file mode 100644
index 0000000..14226b0
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-gcd_11.c
@@ -0,0 +1,83 @@
+/* Test mpn_gcd_11.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#ifndef COUNT
+#define COUNT 500000
+#endif
+
+static void
+one_test (mp_limb_t a, mp_limb_t b, mp_limb_t ref)
+{
+  mp_limb_t r = mpn_gcd_11 (a, b);
+  if (r != ref)
+    {
+      gmp_fprintf (stderr,
+		   "gcd_11 (0x%Mx, 0x%Mx) failed, got: 0x%Mx, ref: 0x%Mx\n",
+		   a, b, r, ref);
+      abort();
+    }
+}
+
+int
+main (int argc, char **argv)
+{
+  mpz_t a, b;
+  int count = COUNT;
+  int test;
+  gmp_randstate_ptr rands;
+
+  TESTS_REPS (count, argv, argc);
+
+  tests_start ();
+  rands = RANDS;
+
+  mpz_init (a);
+  mpz_init (b);
+  for (test = 0; test < count; test++)
+    {
+      mp_limb_t al, bl;
+      mp_bitcnt_t asize = 1 + gmp_urandomm_ui(rands, GMP_NUMB_BITS);
+      mp_bitcnt_t bsize = 1 + gmp_urandomm_ui(rands, GMP_NUMB_BITS);
+      if (test & 1)
+	{
+	  mpz_urandomb (a, rands, asize);
+	  mpz_urandomb (b, rands, bsize);
+	}
+      else
+	{
+	  mpz_rrandomb (a, rands, asize);
+	  mpz_rrandomb (b, rands, bsize);
+	}
+
+      mpz_setbit (a, 0);
+      mpz_setbit (b, 0);
+      al = mpz_getlimbn (a, 0);
+      bl = mpz_getlimbn (b, 0);
+      one_test (al, bl, refmpn_gcd_11 (al, bl));
+    }
+
+  mpz_clear (a);
+  mpz_clear (b);
+}
diff --git a/third_party/gmp/tests/mpn/t-gcd_22.c b/third_party/gmp/tests/mpn/t-gcd_22.c
new file mode 100644
index 0000000..baed35a
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-gcd_22.c
@@ -0,0 +1,84 @@
+/* Test mpn_gcd_22.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#ifndef COUNT
+#define COUNT 150000
+#endif
+
+static void
+one_test (mpz_srcptr a, mpz_srcptr b, mpz_srcptr ref)
+{
+  mp_double_limb_t r = mpn_gcd_22 (mpz_getlimbn (a, 1), mpz_getlimbn (a, 0),
+				   mpz_getlimbn (b, 1), mpz_getlimbn (b, 0));
+  if (r.d0 != mpz_getlimbn (ref, 0) || r.d1 != mpz_getlimbn (ref, 1))
+    {
+      gmp_fprintf (stderr,
+		   "gcd_22 (0x%Zx, 0x%Zx) failed, got: g1 = 0x%Mx g0 = %Mx, ref: 0x%Zx\n",
+                   a, b, r.d1, r.d0, ref);
+      abort();
+    }
+}
+
+int
+main (int argc, char **argv)
+{
+  mpz_t a, b, ref;
+  int count = COUNT;
+  int test;
+  gmp_randstate_ptr rands;
+
+  TESTS_REPS (count, argv, argc);
+
+  tests_start ();
+  rands = RANDS;
+
+  mpz_init (a);
+  mpz_init (b);
+  mpz_init (ref);
+  for (test = 0; test < count; test++)
+    {
+      mp_bitcnt_t asize = 1 + gmp_urandomm_ui(rands, 2*GMP_NUMB_BITS);
+      mp_bitcnt_t bsize = 1 + gmp_urandomm_ui(rands, 2*GMP_NUMB_BITS);
+      if (test & 1)
+	{
+	  mpz_urandomb (a, rands, asize);
+	  mpz_urandomb (b, rands, bsize);
+	}
+      else
+	{
+	  mpz_rrandomb (a, rands, asize);
+	  mpz_rrandomb (b, rands, bsize);
+	}
+
+      mpz_setbit (a, 0);
+      mpz_setbit (b, 0);
+      refmpz_gcd (ref, a, b);
+      one_test (a, b, ref);
+    }
+
+  mpz_clear (a);
+  mpz_clear (b);
+  mpz_clear (ref);
+}
diff --git a/third_party/gmp/tests/mpn/t-gcdext_1.c b/third_party/gmp/tests/mpn/t-gcdext_1.c
new file mode 100644
index 0000000..99143ae
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-gcdext_1.c
@@ -0,0 +1,131 @@
+/* Test mpn_gcdext_1.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#ifndef COUNT
+#define COUNT 250000
+#endif
+
+static void
+set_signed_limb (mpz_t r, mp_limb_signed_t x)
+{
+  mpz_t t;
+  mp_limb_t abs_x = ABS_CAST(mp_limb_t, x);
+  mpz_set (r, mpz_roinit_n (t, &abs_x, 1));
+  if (x < 0)
+    mpz_neg (r, r);
+}
+
+static void
+one_test (mp_limb_t a, mp_limb_t b)
+{
+  mp_limb_signed_t s, t;
+  mp_limb_t g;
+
+  g = mpn_gcdext_1 (&s, &t, a, b);
+
+  if (g > 0)
+    {
+      mpz_t d, sz, tz, tmp;
+
+      mpz_init (d);
+      mpz_init (sz);
+      mpz_init (tz);
+
+      set_signed_limb (sz, s);
+      set_signed_limb (tz, t);
+
+      mpz_mul (d, mpz_roinit_n (tmp, &a, 1), sz);
+      mpz_addmul (d, mpz_roinit_n (tmp, &b, 1), tz);
+
+      if (mpz_cmp (d, mpz_roinit_n (tmp, &g, 1)) == 0
+	  && a % g == 0 && b % g == 0)
+	{
+	  mp_limb_t a_div_g = a / g;
+	  mp_limb_t b_div_g = b / g;
+	  mp_limb_t abs_s = ABS_CAST(mp_limb_t, s);
+	  mp_limb_t abs_t = ABS_CAST(mp_limb_t, t);
+	  mpz_mul_ui (sz, sz, 2);
+	  mpz_mul_ui (tz, tz, 2);
+	  if ((abs_s == 1 || mpz_cmpabs (sz, mpz_roinit_n (tmp, &b_div_g, 1)) < 0)
+	       && (abs_t == 1 || mpz_cmpabs (tz, mpz_roinit_n (tmp, &a_div_g, 1)) < 0))
+	    {
+	      mpz_clear (d);
+	      mpz_clear (sz);
+	      mpz_clear (tz);
+
+	      return;
+	    }
+	}
+    }
+  gmp_fprintf (stderr,
+	       "gcdext_1 (0x%Mx, 0x%Mx) failed, got: g = 0x%Mx, s = %s0x%Mx, t = %s0x%Mx\n",
+	       a, b, g,
+	       s < 0 ? "-" : "", ABS_CAST(mp_limb_t, s),
+	       t < 0 ? "-" : "", ABS_CAST(mp_limb_t, t));
+  abort();
+}
+
+int
+main (int argc, char **argv)
+{
+  mpz_t a, b;
+  int count = COUNT;
+  int test;
+  gmp_randstate_ptr rands;
+
+  TESTS_REPS (count, argv, argc);
+
+  tests_start ();
+  rands = RANDS;
+
+  mpz_init (a);
+  mpz_init (b);
+  for (test = 0; test < count; test++)
+    {
+      mp_limb_t al, bl;
+      mp_bitcnt_t asize = 1 + gmp_urandomm_ui(rands, GMP_NUMB_BITS);
+      mp_bitcnt_t bsize = 1 + gmp_urandomm_ui(rands, GMP_NUMB_BITS);
+      if (test & 1)
+	{
+	  mpz_urandomb (a, rands, asize);
+	  mpz_urandomb (b, rands, bsize);
+	}
+      else
+	{
+	  mpz_rrandomb (a, rands, asize);
+	  mpz_rrandomb (b, rands, bsize);
+	}
+
+      al = mpz_getlimbn (a, 0);
+      bl = mpz_getlimbn (b, 0);
+      al += (al == 0);
+      bl += (bl == 0);
+
+      one_test (al, bl);
+    }
+
+  mpz_clear (a);
+  mpz_clear (b);
+}
diff --git a/third_party/gmp/tests/mpn/t-get_d.c b/third_party/gmp/tests/mpn/t-get_d.c
new file mode 100644
index 0000000..ab0e2ec
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-get_d.c
@@ -0,0 +1,497 @@
+/* Test mpn_get_d.
+
+Copyright 2002-2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#include <setjmp.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+#ifndef _GMP_IEEE_FLOATS
+#define _GMP_IEEE_FLOATS 0
+#endif
+
+
+/* Exercise various 2^n values, with various exponents and positive and
+   negative.  */
+void
+check_onebit (void)
+{
+  static const int bit_table[] = {
+    0, 1, 2, 3,
+    GMP_NUMB_BITS - 2, GMP_NUMB_BITS - 1,
+    GMP_NUMB_BITS,
+    GMP_NUMB_BITS + 1, GMP_NUMB_BITS + 2,
+    2 * GMP_NUMB_BITS - 2, 2 * GMP_NUMB_BITS - 1,
+    2 * GMP_NUMB_BITS,
+    2 * GMP_NUMB_BITS + 1, 2 * GMP_NUMB_BITS + 2,
+    3 * GMP_NUMB_BITS - 2, 3 * GMP_NUMB_BITS - 1,
+    3 * GMP_NUMB_BITS,
+    3 * GMP_NUMB_BITS + 1, 3 * GMP_NUMB_BITS + 2,
+    4 * GMP_NUMB_BITS - 2, 4 * GMP_NUMB_BITS - 1,
+    4 * GMP_NUMB_BITS,
+    4 * GMP_NUMB_BITS + 1, 4 * GMP_NUMB_BITS + 2,
+    5 * GMP_NUMB_BITS - 2, 5 * GMP_NUMB_BITS - 1,
+    5 * GMP_NUMB_BITS,
+    5 * GMP_NUMB_BITS + 1, 5 * GMP_NUMB_BITS + 2,
+    6 * GMP_NUMB_BITS - 2, 6 * GMP_NUMB_BITS - 1,
+    6 * GMP_NUMB_BITS,
+    6 * GMP_NUMB_BITS + 1, 6 * GMP_NUMB_BITS + 2,
+  };
+  static const int exp_table[] = {
+    0, -100, -10, -1, 1, 10, 100,
+  };
+
+  /* FIXME: It'd be better to base this on the float format. */
+#if defined (__vax) || defined (__vax__)
+  int     limit = 127;  /* vax fp numbers have limited range */
+#else
+  int     limit = 511;
+#endif
+
+  int        bit_i, exp_i, i;
+  double     got, want;
+  mp_size_t  nsize, sign;
+  long       bit, exp, want_bit;
+  mp_limb_t  np[20];
+
+  for (bit_i = 0; bit_i < numberof (bit_table); bit_i++)
+    {
+      bit = bit_table[bit_i];
+
+      nsize = BITS_TO_LIMBS (bit+1);
+      refmpn_zero (np, nsize);
+      np[bit/GMP_NUMB_BITS] = CNST_LIMB(1) << (bit % GMP_NUMB_BITS);
+
+      for (exp_i = 0; exp_i < numberof (exp_table); exp_i++)
+        {
+          exp = exp_table[exp_i];
+
+          want_bit = bit + exp;
+          if (want_bit >= limit || want_bit <= -limit)
+            continue;
+
+          want = 1.0;
+          for (i = 0; i < want_bit; i++)
+            want *= 2.0;
+          for (i = 0; i > want_bit; i--)
+            want *= 0.5;
+
+          for (sign = 0; sign >= -1; sign--, want = -want)
+            {
+              got = mpn_get_d (np, nsize, sign, exp);
+              if (got != want)
+                {
+                  printf    ("mpn_get_d wrong on 2^n\n");
+                  printf    ("   bit      %ld\n", bit);
+                  printf    ("   exp      %ld\n", exp);
+                  printf    ("   want_bit %ld\n", want_bit);
+                  printf    ("   sign     %ld\n", (long) sign);
+                  mpn_trace ("   n        ", np, nsize);
+                  printf    ("   nsize    %ld\n", (long) nsize);
+                  d_trace   ("   want     ", want);
+                  d_trace   ("   got      ", got);
+                  abort();
+                }
+            }
+        }
+    }
+}
+
+
+/* Exercise values 2^n+1, while such a value fits the mantissa of a double. */
+void
+check_twobit (void)
+{
+  int        i, mant_bits;
+  double     got, want;
+  mp_size_t  nsize, sign;
+  mp_ptr     np;
+
+  mant_bits = tests_dbl_mant_bits ();
+  if (mant_bits == 0)
+    return;
+
+  np = refmpn_malloc_limbs (BITS_TO_LIMBS (mant_bits));
+  want = 3.0;
+  for (i = 1; i < mant_bits; i++)
+    {
+      nsize = BITS_TO_LIMBS (i+1);
+      refmpn_zero (np, nsize);
+      np[i/GMP_NUMB_BITS] = CNST_LIMB(1) << (i % GMP_NUMB_BITS);
+      np[0] |= 1;
+
+      for (sign = 0; sign >= -1; sign--)
+        {
+          got = mpn_get_d (np, nsize, sign, 0);
+          if (got != want)
+            {
+              printf    ("mpn_get_d wrong on 2^%d + 1\n", i);
+              printf    ("   sign     %ld\n", (long) sign);
+              mpn_trace ("   n        ", np, nsize);
+              printf    ("   nsize    %ld\n", (long) nsize);
+              d_trace   ("   want     ", want);
+              d_trace   ("   got      ", got);
+              abort();
+            }
+          want = -want;
+        }
+
+      want = 2.0 * want - 1.0;
+    }
+
+  free (np);
+}
+
+
+/* Expect large negative exponents to underflow to 0.0.
+   Some systems might have hardware traps for such an underflow (though
+   usually it's not the default), so watch out for SIGFPE. */
+void
+check_underflow (void)
+{
+  static const long exp_table[] = {
+    -999999L, LONG_MIN,
+  };
+  static const mp_limb_t  np[1] = { 1 };
+
+  static long exp;
+  mp_size_t  nsize, sign;
+  double     got;
+  int        exp_i;
+
+  nsize = numberof (np);
+
+  if (tests_setjmp_sigfpe() == 0)
+    {
+      for (exp_i = 0; exp_i < numberof (exp_table); exp_i++)
+        {
+          exp = exp_table[exp_i];
+
+          for (sign = 0; sign >= -1; sign--)
+            {
+              got = mpn_get_d (np, nsize, sign, exp);
+              if (got != 0.0)
+                {
+                  printf  ("mpn_get_d wrong, didn't get 0.0 on underflow\n");
+                  printf  ("  nsize    %ld\n", (long) nsize);
+                  printf  ("  exp      %ld\n", exp);
+                  printf  ("  sign     %ld\n", (long) sign);
+                  d_trace ("  got      ", got);
+                  abort ();
+                }
+            }
+        }
+    }
+  else
+    {
+      printf ("Warning, underflow to zero tests skipped due to SIGFPE (exp=%ld)\n", exp);
+    }
+  tests_sigfpe_done ();
+}
+
+
+/* Expect large values to result in +/-inf, on IEEE systems. */
+void
+check_inf (void)
+{
+  static const long exp_table[] = {
+    999999L, LONG_MAX,
+  };
+  static const mp_limb_t  np[4] = { 1, 1, 1, 1 };
+  long       exp;
+  mp_size_t  nsize, sign, got_sign;
+  double     got;
+  int        exp_i;
+
+  if (! _GMP_IEEE_FLOATS)
+    return;
+
+  for (nsize = 1; nsize <= numberof (np); nsize++)
+    {
+      for (exp_i = 0; exp_i < numberof (exp_table); exp_i++)
+        {
+          exp = exp_table[exp_i];
+
+          for (sign = 0; sign >= -1; sign--)
+            {
+              got = mpn_get_d (np, nsize, sign, exp);
+              got_sign = (got >= 0 ? 0 : -1);
+              if (! tests_isinf (got))
+                {
+                  printf  ("mpn_get_d wrong, didn't get infinity\n");
+                bad:
+                  printf  ("  nsize    %ld\n", (long) nsize);
+                  printf  ("  exp      %ld\n", exp);
+                  printf  ("  sign     %ld\n", (long) sign);
+                  d_trace ("  got      ", got);
+                  printf  ("  got sign %ld\n", (long) got_sign);
+                  abort ();
+                }
+              if (got_sign != sign)
+                {
+                  printf  ("mpn_get_d wrong sign on infinity\n");
+                  goto bad;
+                }
+            }
+        }
+    }
+}
+
+/* Check values 2^n approaching and into IEEE denorm range.
+   Some systems might not support denorms, or might have traps setup, so
+   watch out for SIGFPE.  */
+void
+check_ieee_denorm (void)
+{
+  static long exp;
+  mp_limb_t  n = 1;
+  long       i;
+  mp_size_t  sign;
+  double     want, got;
+
+  if (! _GMP_IEEE_FLOATS)
+    return;
+
+  if (tests_setjmp_sigfpe() == 0)
+    {
+      exp = -1020;
+      want = 1.0;
+      for (i = 0; i > exp; i--)
+        want *= 0.5;
+
+      for ( ; exp > -1500 && want != 0.0; exp--)
+        {
+          for (sign = 0; sign >= -1; sign--)
+            {
+              got = mpn_get_d (&n, (mp_size_t) 1, sign, exp);
+              if (got != want)
+                {
+                  printf  ("mpn_get_d wrong on denorm\n");
+                  printf  ("  n=1\n");
+                  printf  ("  exp   %ld\n", exp);
+                  printf  ("  sign  %ld\n", (long) sign);
+                  d_trace ("  got   ", got);
+                  d_trace ("  want  ", want);
+                  abort ();
+                }
+              want = -want;
+            }
+          want *= 0.5;
+          FORCE_DOUBLE (want);
+        }
+    }
+  else
+    {
+      printf ("Warning, IEEE denorm tests skipped due to SIGFPE (exp=%ld)\n", exp);
+    }
+  tests_sigfpe_done ();
+}
+
+
+/* Check values 2^n approaching exponent overflow.
+   Some systems might trap on overflow, so watch out for SIGFPE.  */
+void
+check_ieee_overflow (void)
+{
+  static long exp;
+  mp_limb_t  n = 1;
+  long       i;
+  mp_size_t  sign;
+  double     want, got;
+
+  if (! _GMP_IEEE_FLOATS)
+    return;
+
+  if (tests_setjmp_sigfpe() == 0)
+    {
+      exp = 1010;
+      want = 1.0;
+      for (i = 0; i < exp; i++)
+        want *= 2.0;
+
+      for ( ; exp < 1050; exp++)
+        {
+          for (sign = 0; sign >= -1; sign--)
+            {
+              got = mpn_get_d (&n, (mp_size_t) 1, sign, exp);
+              if (got != want)
+                {
+                  printf  ("mpn_get_d wrong on overflow\n");
+                  printf  ("  n=1\n");
+                  printf  ("  exp   %ld\n", exp);
+                  printf  ("  sign  %ld\n", (long) sign);
+                  d_trace ("  got   ", got);
+                  d_trace ("  want  ", want);
+                  abort ();
+                }
+              want = -want;
+            }
+          want *= 2.0;
+          FORCE_DOUBLE (want);
+        }
+    }
+  else
+    {
+      printf ("Warning, IEEE overflow tests skipped due to SIGFPE (exp=%ld)\n", exp);
+    }
+  tests_sigfpe_done ();
+}
+
+
+/* ARM gcc 2.95.4 was seen generating bad code for ulong->double
+   conversions, resulting in for instance 0x81c25113 incorrectly converted.
+   This test exercises that value, to see mpn_get_d has avoided the
+   problem.  */
+void
+check_0x81c25113 (void)
+{
+#if GMP_NUMB_BITS >= 32
+  double     want = 2176995603.0;
+  double     got;
+  mp_limb_t  np[4];
+  mp_size_t  nsize;
+  long       exp;
+
+  if (tests_dbl_mant_bits() < 32)
+    return;
+
+  for (nsize = 1; nsize <= numberof (np); nsize++)
+    {
+      refmpn_zero (np, nsize-1);
+      np[nsize-1] = CNST_LIMB(0x81c25113);
+      exp = - (nsize-1) * GMP_NUMB_BITS;
+      got = mpn_get_d (np, nsize, (mp_size_t) 0, exp);
+      if (got != want)
+        {
+          printf  ("mpn_get_d wrong on 2176995603 (0x81c25113)\n");
+          printf  ("  nsize  %ld\n", (long) nsize);
+          printf  ("  exp    %ld\n", exp);
+          d_trace ("  got    ", got);
+          d_trace ("  want   ", want);
+          abort ();
+        }
+    }
+#endif
+}
+
+
+void
+check_rand (void)
+{
+  gmp_randstate_ptr rands = RANDS;
+  int            rep, i;
+  unsigned long  mant_bits;
+  long           exp, exp_min, exp_max;
+  double         got, want, d;
+  mp_size_t      nalloc, nsize, sign;
+  mp_limb_t      nhigh_mask;
+  mp_ptr         np;
+
+  mant_bits = tests_dbl_mant_bits ();
+  if (mant_bits == 0)
+    return;
+
+  /* Allow for vax D format with exponent 127 to -128 only.
+     FIXME: Do something to probe for a valid exponent range.  */
+  exp_min = -100 - mant_bits;
+  exp_max =  100 - mant_bits;
+
+  /* space for mant_bits */
+  nalloc = BITS_TO_LIMBS (mant_bits);
+  np = refmpn_malloc_limbs (nalloc);
+  nhigh_mask = MP_LIMB_T_MAX
+    >> (GMP_NAIL_BITS + nalloc * GMP_NUMB_BITS - mant_bits);
+
+  for (rep = 0; rep < 200; rep++)
+    {
+      /* random exp_min to exp_max, inclusive */
+      exp = exp_min + (long) gmp_urandomm_ui (rands, exp_max - exp_min + 1);
+
+      /* mant_bits worth of random at np */
+      if (rep & 1)
+        mpn_random (np, nalloc);
+      else
+        mpn_random2 (np, nalloc);
+      nsize = nalloc;
+      np[nsize-1] &= nhigh_mask;
+      MPN_NORMALIZE (np, nsize);
+      if (nsize == 0)
+        continue;
+
+      sign = (mp_size_t) gmp_urandomb_ui (rands, 1L) - 1;
+
+      /* want = {np,nsize}, converting one bit at a time */
+      want = 0.0;
+      for (i = 0, d = 1.0; i < mant_bits; i++, d *= 2.0)
+        if (np[i/GMP_NUMB_BITS] & (CNST_LIMB(1) << (i%GMP_NUMB_BITS)))
+          want += d;
+      if (sign < 0)
+        want = -want;
+
+      /* want = want * 2^exp */
+      for (i = 0; i < exp; i++)
+        want *= 2.0;
+      for (i = 0; i > exp; i--)
+        want *= 0.5;
+
+      got = mpn_get_d (np, nsize, sign, exp);
+
+      if (got != want)
+        {
+          printf    ("mpn_get_d wrong on random data\n");
+          printf    ("   sign     %ld\n", (long) sign);
+          mpn_trace ("   n        ", np, nsize);
+          printf    ("   nsize    %ld\n", (long) nsize);
+          printf    ("   exp      %ld\n", exp);
+          d_trace   ("   want     ", want);
+          d_trace   ("   got      ", got);
+          abort();
+        }
+    }
+
+  free (np);
+}
+
+
+int
+main (void)
+{
+  tests_start ();
+  mp_trace_base = -16;
+
+  check_onebit ();
+  check_twobit ();
+  check_inf ();
+  check_underflow ();
+  check_ieee_denorm ();
+  check_ieee_overflow ();
+  check_0x81c25113 ();
+#if ! (defined (__vax) || defined (__vax__))
+  check_rand ();
+#endif
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpn/t-hgcd.c b/third_party/gmp/tests/mpn/t-hgcd.c
new file mode 100644
index 0000000..07f83e9
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-hgcd.c
@@ -0,0 +1,406 @@
+/* Test mpn_hgcd.
+
+Copyright 1991, 1993, 1994, 1996, 1997, 2000-2004 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+static mp_size_t one_test (mpz_t, mpz_t, int);
+static void debug_mp (mpz_t, int);
+
+#define MIN_OPERAND_SIZE 2
+
+/* Fixed values, for regression testing of mpn_hgcd. */
+struct value { int res; const char *a; const char *b; };
+static const struct value hgcd_values[] = {
+#if GMP_NUMB_BITS == 32
+  { 5,
+    "0x1bddff867272a9296ac493c251d7f46f09a5591fe",
+    "0xb55930a2a68a916450a7de006031068c5ddb0e5c" },
+  { 4,
+    "0x2f0ece5b1ee9c15e132a01d55768dc13",
+    "0x1c6f4fd9873cdb24466e6d03e1cc66e7" },
+  { 3, "0x7FFFFC003FFFFFFFFFC5", "0x3FFFFE001FFFFFFFFFE3"},
+#endif
+  { -1, NULL, NULL }
+};
+
+struct hgcd_ref
+{
+  mpz_t m[2][2];
+};
+
+static void hgcd_ref_init (struct hgcd_ref *);
+static void hgcd_ref_clear (struct hgcd_ref *);
+static int hgcd_ref (struct hgcd_ref *, mpz_t, mpz_t);
+static int hgcd_ref_equal (const struct hgcd_matrix *, const struct hgcd_ref *);
+
+int
+main (int argc, char **argv)
+{
+  mpz_t op1, op2, temp1, temp2;
+  int i, j, chain_len;
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long size_range;
+
+  tests_start ();
+  rands = RANDS;
+
+  mpz_init (bs);
+  mpz_init (op1);
+  mpz_init (op2);
+  mpz_init (temp1);
+  mpz_init (temp2);
+
+  for (i = 0; hgcd_values[i].res >= 0; i++)
+    {
+      mp_size_t res;
+
+      mpz_set_str (op1, hgcd_values[i].a, 0);
+      mpz_set_str (op2, hgcd_values[i].b, 0);
+
+      res = one_test (op1, op2, -1-i);
+      if (res != hgcd_values[i].res)
+	{
+	  fprintf (stderr, "ERROR in test %d\n", -1-i);
+	  fprintf (stderr, "Bad return code from hgcd\n");
+	  fprintf (stderr, "op1=");                 debug_mp (op1, -16);
+	  fprintf (stderr, "op2=");                 debug_mp (op2, -16);
+	  fprintf (stderr, "expected: %d\n", hgcd_values[i].res);
+	  fprintf (stderr, "hgcd:     %d\n", (int) res);
+	  abort ();
+	}
+    }
+
+  for (i = 0; i < 15; i++)
+    {
+      /* Generate plain operands with unknown gcd.  These types of operands
+	 have proven to trigger certain bugs in development versions of the
+	 gcd code. */
+
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 13 + 2;
+
+      mpz_urandomb (bs, rands, size_range);
+      mpz_rrandomb (op1, rands, mpz_get_ui (bs) + MIN_OPERAND_SIZE);
+      mpz_urandomb (bs, rands, size_range);
+      mpz_rrandomb (op2, rands, mpz_get_ui (bs) + MIN_OPERAND_SIZE);
+
+      if (mpz_cmp (op1, op2) < 0)
+	mpz_swap (op1, op2);
+
+      if (mpz_size (op1) > 0)
+	one_test (op1, op2, i);
+
+      /* Generate a division chain backwards, allowing otherwise
+	 unlikely huge quotients.  */
+
+      mpz_set_ui (op1, 0);
+      mpz_urandomb (bs, rands, 32);
+      mpz_urandomb (bs, rands, mpz_get_ui (bs) % 16 + 1);
+      mpz_rrandomb (op2, rands, mpz_get_ui (bs));
+      mpz_add_ui (op2, op2, 1);
+
+#if 0
+      chain_len = 1000000;
+#else
+      mpz_urandomb (bs, rands, 32);
+      chain_len = mpz_get_ui (bs) % (GMP_NUMB_BITS * GCD_DC_THRESHOLD / 256);
+#endif
+
+      for (j = 0; j < chain_len; j++)
+	{
+	  mpz_urandomb (bs, rands, 32);
+	  mpz_urandomb (bs, rands, mpz_get_ui (bs) % 12 + 1);
+	  mpz_rrandomb (temp2, rands, mpz_get_ui (bs) + 1);
+	  mpz_add_ui (temp2, temp2, 1);
+	  mpz_mul (temp1, op2, temp2);
+	  mpz_add (op1, op1, temp1);
+
+	  /* Don't generate overly huge operands.  */
+	  if (SIZ (op1) > 3 * GCD_DC_THRESHOLD)
+	    break;
+
+	  mpz_urandomb (bs, rands, 32);
+	  mpz_urandomb (bs, rands, mpz_get_ui (bs) % 12 + 1);
+	  mpz_rrandomb (temp2, rands, mpz_get_ui (bs) + 1);
+	  mpz_add_ui (temp2, temp2, 1);
+	  mpz_mul (temp1, op1, temp2);
+	  mpz_add (op2, op2, temp1);
+
+	  /* Don't generate overly huge operands.  */
+	  if (SIZ (op2) > 3 * GCD_DC_THRESHOLD)
+	    break;
+	}
+      if (mpz_cmp (op1, op2) < 0)
+	mpz_swap (op1, op2);
+
+      if (mpz_size (op1) > 0)
+	one_test (op1, op2, i);
+    }
+
+  mpz_clear (bs);
+  mpz_clear (op1);
+  mpz_clear (op2);
+  mpz_clear (temp1);
+  mpz_clear (temp2);
+
+  tests_end ();
+  exit (0);
+}
+
+static void
+debug_mp (mpz_t x, int base)
+{
+  mpz_out_str (stderr, base, x); fputc ('\n', stderr);
+}
+
+static int
+mpz_mpn_equal (const mpz_t a, mp_srcptr bp, mp_size_t bsize);
+
+static mp_size_t
+one_test (mpz_t a, mpz_t b, int i)
+{
+  struct hgcd_matrix hgcd;
+  struct hgcd_ref ref;
+
+  mpz_t ref_r0;
+  mpz_t ref_r1;
+  mpz_t hgcd_r0;
+  mpz_t hgcd_r1;
+
+  mp_size_t res[2];
+  mp_size_t asize;
+  mp_size_t bsize;
+
+  mp_size_t hgcd_init_scratch;
+  mp_size_t hgcd_scratch;
+
+  mp_ptr hgcd_init_tp;
+  mp_ptr hgcd_tp;
+
+  asize = a->_mp_size;
+  bsize = b->_mp_size;
+
+  ASSERT (asize >= bsize);
+
+  hgcd_init_scratch = MPN_HGCD_MATRIX_INIT_ITCH (asize);
+  hgcd_init_tp = refmpn_malloc_limbs (hgcd_init_scratch);
+  mpn_hgcd_matrix_init (&hgcd, asize, hgcd_init_tp);
+
+  hgcd_scratch = mpn_hgcd_itch (asize);
+  hgcd_tp = refmpn_malloc_limbs (hgcd_scratch);
+
+#if 0
+  fprintf (stderr,
+	   "one_test: i = %d asize = %d, bsize = %d\n",
+	   i, a->_mp_size, b->_mp_size);
+
+  gmp_fprintf (stderr,
+	       "one_test: i = %d\n"
+	       "  a = %Zx\n"
+	       "  b = %Zx\n",
+	       i, a, b);
+#endif
+  hgcd_ref_init (&ref);
+
+  mpz_init_set (ref_r0, a);
+  mpz_init_set (ref_r1, b);
+  res[0] = hgcd_ref (&ref, ref_r0, ref_r1);
+
+  mpz_init_set (hgcd_r0, a);
+  mpz_init_set (hgcd_r1, b);
+  if (bsize < asize)
+    {
+      _mpz_realloc (hgcd_r1, asize);
+      MPN_ZERO (hgcd_r1->_mp_d + bsize, asize - bsize);
+    }
+  res[1] = mpn_hgcd (hgcd_r0->_mp_d,
+		     hgcd_r1->_mp_d,
+		     asize,
+		     &hgcd, hgcd_tp);
+
+  if (res[0] != res[1])
+    {
+      fprintf (stderr, "ERROR in test %d\n", i);
+      fprintf (stderr, "Different return value from hgcd and hgcd_ref\n");
+      fprintf (stderr, "op1=");                 debug_mp (a, -16);
+      fprintf (stderr, "op2=");                 debug_mp (b, -16);
+      fprintf (stderr, "hgcd_ref: %ld\n", (long) res[0]);
+      fprintf (stderr, "mpn_hgcd: %ld\n", (long) res[1]);
+      abort ();
+    }
+  if (res[0] > 0)
+    {
+      if (!hgcd_ref_equal (&hgcd, &ref)
+	  || !mpz_mpn_equal (ref_r0, hgcd_r0->_mp_d, res[1])
+	  || !mpz_mpn_equal (ref_r1, hgcd_r1->_mp_d, res[1]))
+	{
+	  fprintf (stderr, "ERROR in test %d\n", i);
+	  fprintf (stderr, "mpn_hgcd and hgcd_ref returned different values\n");
+	  fprintf (stderr, "op1=");                 debug_mp (a, -16);
+	  fprintf (stderr, "op2=");                 debug_mp (b, -16);
+	  abort ();
+	}
+    }
+
+  refmpn_free_limbs (hgcd_init_tp);
+  refmpn_free_limbs (hgcd_tp);
+  hgcd_ref_clear (&ref);
+  mpz_clear (ref_r0);
+  mpz_clear (ref_r1);
+  mpz_clear (hgcd_r0);
+  mpz_clear (hgcd_r1);
+
+  return res[0];
+}
+
+static void
+hgcd_ref_init (struct hgcd_ref *hgcd)
+{
+  unsigned i;
+  for (i = 0; i<2; i++)
+    {
+      unsigned j;
+      for (j = 0; j<2; j++)
+	mpz_init (hgcd->m[i][j]);
+    }
+}
+
+static void
+hgcd_ref_clear (struct hgcd_ref *hgcd)
+{
+  unsigned i;
+  for (i = 0; i<2; i++)
+    {
+      unsigned j;
+      for (j = 0; j<2; j++)
+	mpz_clear (hgcd->m[i][j]);
+    }
+}
+
+
+static int
+sdiv_qr (mpz_t q, mpz_t r, mp_size_t s, const mpz_t a, const mpz_t b)
+{
+  mpz_fdiv_qr (q, r, a, b);
+  if (mpz_size (r) <= s)
+    {
+      mpz_add (r, r, b);
+      mpz_sub_ui (q, q, 1);
+    }
+
+  return (mpz_sgn (q) > 0);
+}
+
+static int
+hgcd_ref (struct hgcd_ref *hgcd, mpz_t a, mpz_t b)
+{
+  mp_size_t n = MAX (mpz_size (a), mpz_size (b));
+  mp_size_t s = n/2 + 1;
+  mp_size_t asize;
+  mp_size_t bsize;
+  mpz_t q;
+  int res;
+
+  if (mpz_size (a) <= s || mpz_size (b) <= s)
+    return 0;
+
+  res = mpz_cmp (a, b);
+  if (res < 0)
+    {
+      mpz_sub (b, b, a);
+      if (mpz_size (b) <= s)
+	return 0;
+
+      mpz_set_ui (hgcd->m[0][0], 1); mpz_set_ui (hgcd->m[0][1], 0);
+      mpz_set_ui (hgcd->m[1][0], 1); mpz_set_ui (hgcd->m[1][1], 1);
+    }
+  else if (res > 0)
+    {
+      mpz_sub (a, a, b);
+      if (mpz_size (a) <= s)
+	return 0;
+
+      mpz_set_ui (hgcd->m[0][0], 1); mpz_set_ui (hgcd->m[0][1], 1);
+      mpz_set_ui (hgcd->m[1][0], 0); mpz_set_ui (hgcd->m[1][1], 1);
+    }
+  else
+    return 0;
+
+  mpz_init (q);
+
+  for (;;)
+    {
+      ASSERT (mpz_size (a) > s);
+      ASSERT (mpz_size (b) > s);
+
+      if (mpz_cmp (a, b) > 0)
+	{
+	  if (!sdiv_qr (q, a, s, a, b))
+	    break;
+	  mpz_addmul (hgcd->m[0][1], q, hgcd->m[0][0]);
+	  mpz_addmul (hgcd->m[1][1], q, hgcd->m[1][0]);
+	}
+      else
+	{
+	  if (!sdiv_qr (q, b, s, b, a))
+	    break;
+	  mpz_addmul (hgcd->m[0][0], q, hgcd->m[0][1]);
+	  mpz_addmul (hgcd->m[1][0], q, hgcd->m[1][1]);
+	}
+    }
+
+  mpz_clear (q);
+
+  asize = mpz_size (a);
+  bsize = mpz_size (b);
+  return MAX (asize, bsize);
+}
+
+static int
+mpz_mpn_equal (const mpz_t a, mp_srcptr bp, mp_size_t bsize)
+{
+  mp_srcptr ap = a->_mp_d;
+  mp_size_t asize = a->_mp_size;
+
+  MPN_NORMALIZE (bp, bsize);
+  return asize == bsize && mpn_cmp (ap, bp, asize) == 0;
+}
+
+static int
+hgcd_ref_equal (const struct hgcd_matrix *hgcd, const struct hgcd_ref *ref)
+{
+  unsigned i;
+
+  for (i = 0; i<2; i++)
+    {
+      unsigned j;
+
+      for (j = 0; j<2; j++)
+	if (!mpz_mpn_equal (ref->m[i][j], hgcd->p[i][j], hgcd->n))
+	  return 0;
+    }
+
+  return 1;
+}
diff --git a/third_party/gmp/tests/mpn/t-hgcd_appr.c b/third_party/gmp/tests/mpn/t-hgcd_appr.c
new file mode 100644
index 0000000..f9e2ea8
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-hgcd_appr.c
@@ -0,0 +1,563 @@
+/* Test mpn_hgcd_appr.
+
+Copyright 1991, 1993, 1994, 1996, 1997, 2000-2004, 2011 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+static mp_size_t one_test (mpz_t, mpz_t, int);
+static void debug_mp (mpz_t, int);
+
+#define MIN_OPERAND_SIZE 2
+
+struct hgcd_ref
+{
+  mpz_t m[2][2];
+};
+
+static void hgcd_ref_init (struct hgcd_ref *hgcd);
+static void hgcd_ref_clear (struct hgcd_ref *hgcd);
+static int hgcd_ref (struct hgcd_ref *hgcd, mpz_t a, mpz_t b);
+static int hgcd_ref_equal (const struct hgcd_ref *, const struct hgcd_ref *);
+static int hgcd_appr_valid_p (mpz_t, mpz_t, mp_size_t, struct hgcd_ref *,
+			      mpz_t, mpz_t, mp_size_t, struct hgcd_matrix *);
+
+static int verbose_flag = 0;
+
+int
+main (int argc, char **argv)
+{
+  mpz_t op1, op2, temp1, temp2;
+  int i, j, chain_len;
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long size_range;
+
+  if (argc > 1)
+    {
+      if (strcmp (argv[1], "-v") == 0)
+	verbose_flag = 1;
+      else
+	{
+	  fprintf (stderr, "Invalid argument.\n");
+	  return 1;
+	}
+    }
+
+  tests_start ();
+  rands = RANDS;
+
+  mpz_init (bs);
+  mpz_init (op1);
+  mpz_init (op2);
+  mpz_init (temp1);
+  mpz_init (temp2);
+
+  for (i = 0; i < 15; i++)
+    {
+      /* Generate plain operands with unknown gcd.  These types of operands
+	 have proven to trigger certain bugs in development versions of the
+	 gcd code. */
+
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 13 + 2;
+
+      mpz_urandomb (bs, rands, size_range);
+      mpz_urandomb (op1, rands, mpz_get_ui (bs) + MIN_OPERAND_SIZE);
+      mpz_urandomb (bs, rands, size_range);
+      mpz_urandomb (op2, rands, mpz_get_ui (bs) + MIN_OPERAND_SIZE);
+
+      if (mpz_cmp (op1, op2) < 0)
+	mpz_swap (op1, op2);
+
+      if (mpz_size (op1) > 0)
+	one_test (op1, op2, i);
+
+      /* Generate a division chain backwards, allowing otherwise
+	 unlikely huge quotients.  */
+
+      mpz_set_ui (op1, 0);
+      mpz_urandomb (bs, rands, 32);
+      mpz_urandomb (bs, rands, mpz_get_ui (bs) % 16 + 1);
+      mpz_rrandomb (op2, rands, mpz_get_ui (bs));
+      mpz_add_ui (op2, op2, 1);
+
+#if 0
+      chain_len = 1000000;
+#else
+      mpz_urandomb (bs, rands, 32);
+      chain_len = mpz_get_ui (bs) % (GMP_NUMB_BITS * GCD_DC_THRESHOLD / 256);
+#endif
+
+      for (j = 0; j < chain_len; j++)
+	{
+	  mpz_urandomb (bs, rands, 32);
+	  mpz_urandomb (bs, rands, mpz_get_ui (bs) % 12 + 1);
+	  mpz_rrandomb (temp2, rands, mpz_get_ui (bs) + 1);
+	  mpz_add_ui (temp2, temp2, 1);
+	  mpz_mul (temp1, op2, temp2);
+	  mpz_add (op1, op1, temp1);
+
+	  /* Don't generate overly huge operands.  */
+	  if (SIZ (op1) > 3 * GCD_DC_THRESHOLD)
+	    break;
+
+	  mpz_urandomb (bs, rands, 32);
+	  mpz_urandomb (bs, rands, mpz_get_ui (bs) % 12 + 1);
+	  mpz_rrandomb (temp2, rands, mpz_get_ui (bs) + 1);
+	  mpz_add_ui (temp2, temp2, 1);
+	  mpz_mul (temp1, op1, temp2);
+	  mpz_add (op2, op2, temp1);
+
+	  /* Don't generate overly huge operands.  */
+	  if (SIZ (op2) > 3 * GCD_DC_THRESHOLD)
+	    break;
+	}
+      if (mpz_cmp (op1, op2) < 0)
+	mpz_swap (op1, op2);
+
+      if (mpz_size (op1) > 0)
+	one_test (op1, op2, i);
+    }
+
+  mpz_clear (bs);
+  mpz_clear (op1);
+  mpz_clear (op2);
+  mpz_clear (temp1);
+  mpz_clear (temp2);
+
+  tests_end ();
+  exit (0);
+}
+
+static void
+debug_mp (mpz_t x, int base)
+{
+  mpz_out_str (stderr, base, x); fputc ('\n', stderr);
+}
+
+static mp_size_t
+one_test (mpz_t a, mpz_t b, int i)
+{
+  struct hgcd_matrix hgcd;
+  struct hgcd_ref ref;
+
+  mpz_t ref_r0;
+  mpz_t ref_r1;
+  mpz_t hgcd_r0;
+  mpz_t hgcd_r1;
+
+  int res[2];
+  mp_size_t asize;
+  mp_size_t bsize;
+
+  mp_size_t hgcd_init_scratch;
+  mp_size_t hgcd_scratch;
+
+  mp_ptr hgcd_init_tp;
+  mp_ptr hgcd_tp;
+  mp_limb_t marker[4];
+
+  asize = a->_mp_size;
+  bsize = b->_mp_size;
+
+  ASSERT (asize >= bsize);
+
+  hgcd_init_scratch = MPN_HGCD_MATRIX_INIT_ITCH (asize);
+  hgcd_init_tp = refmpn_malloc_limbs (hgcd_init_scratch + 2) + 1;
+  mpn_hgcd_matrix_init (&hgcd, asize, hgcd_init_tp);
+
+  hgcd_scratch = mpn_hgcd_appr_itch (asize);
+  hgcd_tp = refmpn_malloc_limbs (hgcd_scratch + 2) + 1;
+
+  mpn_random (marker, 4);
+
+  hgcd_init_tp[-1] = marker[0];
+  hgcd_init_tp[hgcd_init_scratch] = marker[1];
+  hgcd_tp[-1] = marker[2];
+  hgcd_tp[hgcd_scratch] = marker[3];
+
+#if 0
+  fprintf (stderr,
+	   "one_test: i = %d asize = %d, bsize = %d\n",
+	   i, a->_mp_size, b->_mp_size);
+
+  gmp_fprintf (stderr,
+	       "one_test: i = %d\n"
+	       "  a = %Zx\n"
+	       "  b = %Zx\n",
+	       i, a, b);
+#endif
+  hgcd_ref_init (&ref);
+
+  mpz_init_set (ref_r0, a);
+  mpz_init_set (ref_r1, b);
+  res[0] = hgcd_ref (&ref, ref_r0, ref_r1);
+
+  mpz_init_set (hgcd_r0, a);
+  mpz_init_set (hgcd_r1, b);
+  if (bsize < asize)
+    {
+      _mpz_realloc (hgcd_r1, asize);
+      MPN_ZERO (hgcd_r1->_mp_d + bsize, asize - bsize);
+    }
+  res[1] = mpn_hgcd_appr (hgcd_r0->_mp_d,
+			  hgcd_r1->_mp_d,
+			  asize,
+			  &hgcd, hgcd_tp);
+
+  if (hgcd_init_tp[-1] != marker[0]
+      || hgcd_init_tp[hgcd_init_scratch] != marker[1]
+      || hgcd_tp[-1] != marker[2]
+      || hgcd_tp[hgcd_scratch] != marker[3])
+    {
+      fprintf (stderr, "ERROR in test %d\n", i);
+      fprintf (stderr, "scratch space overwritten!\n");
+
+      if (hgcd_init_tp[-1] != marker[0])
+	gmp_fprintf (stderr,
+		     "before init_tp: %Mx\n"
+		     "expected: %Mx\n",
+		     hgcd_init_tp[-1], marker[0]);
+      if (hgcd_init_tp[hgcd_init_scratch] != marker[1])
+	gmp_fprintf (stderr,
+		     "after init_tp: %Mx\n"
+		     "expected: %Mx\n",
+		     hgcd_init_tp[hgcd_init_scratch], marker[1]);
+      if (hgcd_tp[-1] != marker[2])
+	gmp_fprintf (stderr,
+		     "before tp: %Mx\n"
+		     "expected: %Mx\n",
+		     hgcd_tp[-1], marker[2]);
+      if (hgcd_tp[hgcd_scratch] != marker[3])
+	gmp_fprintf (stderr,
+		     "after tp: %Mx\n"
+		     "expected: %Mx\n",
+		     hgcd_tp[hgcd_scratch], marker[3]);
+
+      abort ();
+    }
+
+  if (!hgcd_appr_valid_p (a, b, res[0], &ref, ref_r0, ref_r1,
+			  res[1], &hgcd))
+    {
+      fprintf (stderr, "ERROR in test %d\n", i);
+      fprintf (stderr, "Invalid results for hgcd and hgcd_ref\n");
+      fprintf (stderr, "op1=");                 debug_mp (a, -16);
+      fprintf (stderr, "op2=");                 debug_mp (b, -16);
+      fprintf (stderr, "hgcd_ref: %ld\n", (long) res[0]);
+      fprintf (stderr, "mpn_hgcd_appr: %ld\n", (long) res[1]);
+      abort ();
+    }
+
+  refmpn_free_limbs (hgcd_init_tp - 1);
+  refmpn_free_limbs (hgcd_tp - 1);
+  hgcd_ref_clear (&ref);
+  mpz_clear (ref_r0);
+  mpz_clear (ref_r1);
+  mpz_clear (hgcd_r0);
+  mpz_clear (hgcd_r1);
+
+  return res[0];
+}
+
+static void
+hgcd_ref_init (struct hgcd_ref *hgcd)
+{
+  unsigned i;
+  for (i = 0; i<2; i++)
+    {
+      unsigned j;
+      for (j = 0; j<2; j++)
+	mpz_init (hgcd->m[i][j]);
+    }
+}
+
+static void
+hgcd_ref_clear (struct hgcd_ref *hgcd)
+{
+  unsigned i;
+  for (i = 0; i<2; i++)
+    {
+      unsigned j;
+      for (j = 0; j<2; j++)
+	mpz_clear (hgcd->m[i][j]);
+    }
+}
+
+static int
+sdiv_qr (mpz_t q, mpz_t r, mp_size_t s, const mpz_t a, const mpz_t b)
+{
+  mpz_fdiv_qr (q, r, a, b);
+  if (mpz_size (r) <= s)
+    {
+      mpz_add (r, r, b);
+      mpz_sub_ui (q, q, 1);
+    }
+
+  return (mpz_sgn (q) > 0);
+}
+
+static int
+hgcd_ref (struct hgcd_ref *hgcd, mpz_t a, mpz_t b)
+{
+  mp_size_t n = MAX (mpz_size (a), mpz_size (b));
+  mp_size_t s = n/2 + 1;
+  mpz_t q;
+  int res;
+
+  if (mpz_size (a) <= s || mpz_size (b) <= s)
+    return 0;
+
+  res = mpz_cmp (a, b);
+  if (res < 0)
+    {
+      mpz_sub (b, b, a);
+      if (mpz_size (b) <= s)
+	return 0;
+
+      mpz_set_ui (hgcd->m[0][0], 1); mpz_set_ui (hgcd->m[0][1], 0);
+      mpz_set_ui (hgcd->m[1][0], 1); mpz_set_ui (hgcd->m[1][1], 1);
+    }
+  else if (res > 0)
+    {
+      mpz_sub (a, a, b);
+      if (mpz_size (a) <= s)
+	return 0;
+
+      mpz_set_ui (hgcd->m[0][0], 1); mpz_set_ui (hgcd->m[0][1], 1);
+      mpz_set_ui (hgcd->m[1][0], 0); mpz_set_ui (hgcd->m[1][1], 1);
+    }
+  else
+    return 0;
+
+  mpz_init (q);
+
+  for (;;)
+    {
+      ASSERT (mpz_size (a) > s);
+      ASSERT (mpz_size (b) > s);
+
+      if (mpz_cmp (a, b) > 0)
+	{
+	  if (!sdiv_qr (q, a, s, a, b))
+	    break;
+	  mpz_addmul (hgcd->m[0][1], q, hgcd->m[0][0]);
+	  mpz_addmul (hgcd->m[1][1], q, hgcd->m[1][0]);
+	}
+      else
+	{
+	  if (!sdiv_qr (q, b, s, b, a))
+	    break;
+	  mpz_addmul (hgcd->m[0][0], q, hgcd->m[0][1]);
+	  mpz_addmul (hgcd->m[1][0], q, hgcd->m[1][1]);
+	}
+    }
+
+  mpz_clear (q);
+
+  return 1;
+}
+
+static int
+hgcd_ref_equal (const struct hgcd_ref *A, const struct hgcd_ref *B)
+{
+  unsigned i;
+
+  for (i = 0; i<2; i++)
+    {
+      unsigned j;
+
+      for (j = 0; j<2; j++)
+	if (mpz_cmp (A->m[i][j], B->m[i][j]) != 0)
+	  return 0;
+    }
+
+  return 1;
+}
+
+static int
+hgcd_appr_valid_p (mpz_t a, mpz_t b, mp_size_t res0,
+		   struct hgcd_ref *ref, mpz_t ref_r0, mpz_t ref_r1,
+		   mp_size_t res1, struct hgcd_matrix *hgcd)
+{
+  mp_size_t n = MAX (mpz_size (a), mpz_size (b));
+  mp_size_t s = n/2 + 1;
+
+  mp_bitcnt_t dbits, abits, margin;
+  mpz_t appr_r0, appr_r1, t, q;
+  struct hgcd_ref appr;
+
+  if (!res0)
+    {
+      if (!res1)
+	return 1;
+
+      fprintf (stderr, "mpn_hgcd_appr returned 1 when no reduction possible.\n");
+      return 0;
+    }
+
+  /* NOTE: No *_clear calls on error return, since we're going to
+     abort anyway. */
+  mpz_init (t);
+  mpz_init (q);
+  hgcd_ref_init (&appr);
+  mpz_init (appr_r0);
+  mpz_init (appr_r1);
+
+  if (mpz_size (ref_r0) <= s)
+    {
+      fprintf (stderr, "ref_r0 too small!!!: "); debug_mp (ref_r0, 16);
+      return 0;
+    }
+  if (mpz_size (ref_r1) <= s)
+    {
+      fprintf (stderr, "ref_r1 too small!!!: "); debug_mp (ref_r1, 16);
+      return 0;
+    }
+
+  mpz_sub (t, ref_r0, ref_r1);
+  dbits = mpz_sizeinbase (t, 2);
+  if (dbits > s*GMP_NUMB_BITS)
+    {
+      fprintf (stderr, "ref |r0 - r1| too large!!!: "); debug_mp (t, 16);
+      return 0;
+    }
+
+  if (!res1)
+    {
+      mpz_set (appr_r0, a);
+      mpz_set (appr_r1, b);
+    }
+  else
+    {
+      unsigned i;
+
+      for (i = 0; i<2; i++)
+	{
+	  unsigned j;
+
+	  for (j = 0; j<2; j++)
+	    {
+	      mp_size_t mn = hgcd->n;
+	      MPN_NORMALIZE (hgcd->p[i][j], mn);
+	      mpz_realloc (appr.m[i][j], mn);
+	      MPN_COPY (PTR (appr.m[i][j]), hgcd->p[i][j], mn);
+	      SIZ (appr.m[i][j]) = mn;
+	    }
+	}
+      mpz_mul (appr_r0, appr.m[1][1], a);
+      mpz_mul (t, appr.m[0][1], b);
+      mpz_sub (appr_r0, appr_r0, t);
+      if (mpz_sgn (appr_r0) <= 0
+	  || mpz_size (appr_r0) <= s)
+	{
+	  fprintf (stderr, "appr_r0 too small: "); debug_mp (appr_r0, 16);
+	  return 0;
+	}
+
+      mpz_mul (appr_r1, appr.m[1][0], a);
+      mpz_mul (t, appr.m[0][0], b);
+      mpz_sub (appr_r1, t, appr_r1);
+      if (mpz_sgn (appr_r1) <= 0
+	  || mpz_size (appr_r1) <= s)
+	{
+	  fprintf (stderr, "appr_r1 too small: "); debug_mp (appr_r1, 16);
+	  return 0;
+	}
+    }
+
+  mpz_sub (t, appr_r0, appr_r1);
+  abits = mpz_sizeinbase (t, 2);
+  if (abits < dbits)
+    {
+      fprintf (stderr, "|r0 - r1| too small: "); debug_mp (t, 16);
+      return 0;
+    }
+
+  /* We lose one bit each time we discard the least significant limbs.
+     For the lehmer code, that can happen at most s * (GMP_NUMB_BITS)
+     / (GMP_NUMB_BITS - 1) times. For the dc code, we lose an entire
+     limb (or more?) for each level of recursion. */
+
+  margin = (n/2+1) * GMP_NUMB_BITS / (GMP_NUMB_BITS - 1);
+  {
+    mp_size_t rn;
+    for (rn = n; ABOVE_THRESHOLD (rn, HGCD_APPR_THRESHOLD); rn = (rn + 1)/2)
+      margin += GMP_NUMB_BITS;
+  }
+
+  if (verbose_flag && abits > dbits)
+    fprintf (stderr, "n = %u: sbits = %u: ref #(r0-r1): %u, appr #(r0-r1): %u excess: %d, margin: %u\n",
+	     (unsigned) n, (unsigned) s*GMP_NUMB_BITS,
+	     (unsigned) dbits, (unsigned) abits,
+	     (int) (abits - s * GMP_NUMB_BITS), (unsigned) margin);
+
+  if (abits > s*GMP_NUMB_BITS + margin)
+    {
+      fprintf (stderr, "appr |r0 - r1| much larger than minimal (by %u bits, margin = %u bits)\n",
+	       (unsigned) (abits - s*GMP_NUMB_BITS), (unsigned) margin);
+      return 0;
+    }
+
+  while (mpz_cmp (appr_r0, ref_r0) > 0 || mpz_cmp (appr_r1, ref_r1) > 0)
+    {
+      ASSERT (mpz_size (appr_r0) > s);
+      ASSERT (mpz_size (appr_r1) > s);
+
+      if (mpz_cmp (appr_r0, appr_r1) > 0)
+	{
+	  if (!sdiv_qr (q, appr_r0, s, appr_r0, appr_r1))
+	    break;
+	  mpz_addmul (appr.m[0][1], q, appr.m[0][0]);
+	  mpz_addmul (appr.m[1][1], q, appr.m[1][0]);
+	}
+      else
+	{
+	  if (!sdiv_qr (q, appr_r1, s, appr_r1, appr_r0))
+	    break;
+	  mpz_addmul (appr.m[0][0], q, appr.m[0][1]);
+	  mpz_addmul (appr.m[1][0], q, appr.m[1][1]);
+	}
+    }
+
+  if (mpz_cmp (appr_r0, ref_r0) != 0
+      || mpz_cmp (appr_r1, ref_r1) != 0
+      || !hgcd_ref_equal (ref, &appr))
+    {
+      fprintf (stderr, "appr_r0: "); debug_mp (appr_r0, 16);
+      fprintf (stderr, "ref_r0: "); debug_mp (ref_r0, 16);
+
+      fprintf (stderr, "appr_r1: "); debug_mp (appr_r1, 16);
+      fprintf (stderr, "ref_r1: "); debug_mp (ref_r1, 16);
+
+      return 0;
+    }
+  mpz_clear (t);
+  mpz_clear (q);
+  hgcd_ref_clear (&appr);
+  mpz_clear (appr_r0);
+  mpz_clear (appr_r1);
+
+  return 1;
+}
diff --git a/third_party/gmp/tests/mpn/t-instrument.c b/third_party/gmp/tests/mpn/t-instrument.c
new file mode 100644
index 0000000..694e171
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-instrument.c
@@ -0,0 +1,415 @@
+/* Test assembler support for --enable-profiling=instrument.
+
+Copyright 2002, 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "longlong.h"
+#include "tests.h"
+
+
+#if WANT_PROFILING_INSTRUMENT
+
+/* This program exercises each mpn routine that might be implemented in
+   assembler.  It ensures the __cyg_profile_func_enter and exit calls have
+   come out right, and that in the x86 code "ret_internal" is correctly used
+   for PIC setups.  */
+
+
+/* Changes to enter_seen done by __cyg_profile_func_enter are essentially
+   unknown to the optimizer, so must use volatile.  */
+volatile int  enter_seen;
+
+/* Dummy used to stop various calls going dead. */
+unsigned long  notdead;
+
+const char     *name = "<none>";
+int  old_ncall;
+
+struct {
+  void  *this_fn;
+  void  *call_site;
+} call[100];
+int  ncall;
+
+
+void __cyg_profile_func_enter (void *, void *)
+  __attribute__ ((no_instrument_function));
+
+void
+__cyg_profile_func_enter (void *this_fn, void *call_site)
+{
+#if 0
+  printf ("%24s %p %p\n", name, this_fn, call_site);
+#endif
+  ASSERT_ALWAYS (ncall >= 0);
+  ASSERT_ALWAYS (ncall <= numberof (call));
+
+  if (ncall >= numberof (call))
+    {
+      printf ("__cyg_profile_func_enter: oops, call stack full, from %s\n", name);
+      abort ();
+    }
+
+  enter_seen = 1;
+  call[ncall].this_fn = this_fn;
+  call[ncall].call_site = call_site;
+  ncall++;
+}
+
+void __cyg_profile_func_exit (void *, void *)
+  __attribute__ ((no_instrument_function));
+
+void
+__cyg_profile_func_exit  (void *this_fn, void *call_site)
+{
+  ASSERT_ALWAYS (ncall >= 0);
+  ASSERT_ALWAYS (ncall <= numberof (call));
+
+  if (ncall == 0)
+    {
+      printf ("__cyg_profile_func_exit: call stack empty, from %s\n", name);
+      abort ();
+    }
+
+  ncall--;
+  if (this_fn != call[ncall].this_fn || call_site != call[ncall].call_site)
+    {
+      printf ("__cyg_profile_func_exit: unbalanced this_fn/call_site from %s\n", name);
+      printf ("  this_fn got  %p\n", this_fn);
+      printf ("          want %p\n", call[ncall].this_fn);
+      printf ("  call_site got  %p\n", call_site);
+      printf ("            want %p\n", call[ncall].call_site);
+      abort ();
+    }
+}
+
+
+void
+pre (const char *str)
+{
+  name = str;
+  enter_seen = 0;
+  old_ncall = ncall;
+}
+
+void
+post (void)
+{
+  if (! enter_seen)
+    {
+      printf ("did not reach __cyg_profile_func_enter from %s\n", name);
+      abort ();
+    }
+
+  if (ncall != old_ncall)
+    {
+      printf ("unbalance enter/exit calls from %s\n", name);
+      printf ("  ncall     %d\n", ncall);
+      printf ("  old_ncall %d\n", old_ncall);
+      abort ();
+    }
+}
+
+void
+check (void)
+{
+  mp_limb_t  wp[100], xp[100], yp[100];
+  mp_size_t  size = 100;
+
+  refmpn_zero (xp, size);
+  refmpn_zero (yp, size);
+  refmpn_zero (wp, size);
+
+  pre ("mpn_add_n");
+  mpn_add_n (wp, xp, yp, size);
+  post ();
+
+#if HAVE_NATIVE_mpn_add_nc
+  pre ("mpn_add_nc");
+  mpn_add_nc (wp, xp, yp, size, CNST_LIMB(0));
+  post ();
+#endif
+
+#if HAVE_NATIVE_mpn_addlsh1_n
+  pre ("mpn_addlsh1_n");
+  mpn_addlsh1_n (wp, xp, yp, size);
+  post ();
+#endif
+
+#if HAVE_NATIVE_mpn_and_n
+  pre ("mpn_and_n");
+  mpn_and_n (wp, xp, yp, size);
+  post ();
+#endif
+
+#if HAVE_NATIVE_mpn_andn_n
+  pre ("mpn_andn_n");
+  mpn_andn_n (wp, xp, yp, size);
+  post ();
+#endif
+
+  pre ("mpn_addmul_1");
+  mpn_addmul_1 (wp, xp, size, yp[0]);
+  post ();
+
+#if HAVE_NATIVE_mpn_addmul_1c
+  pre ("mpn_addmul_1c");
+  mpn_addmul_1c (wp, xp, size, yp[0], CNST_LIMB(0));
+  post ();
+#endif
+
+#if HAVE_NATIVE_mpn_com
+  pre ("mpn_com");
+  mpn_com (wp, xp, size);
+  post ();
+#endif
+
+#if HAVE_NATIVE_mpn_copyd
+  pre ("mpn_copyd");
+  mpn_copyd (wp, xp, size);
+  post ();
+#endif
+
+#if HAVE_NATIVE_mpn_copyi
+  pre ("mpn_copyi");
+  mpn_copyi (wp, xp, size);
+  post ();
+#endif
+
+  pre ("mpn_divexact_1");
+  mpn_divexact_1 (wp, xp, size, CNST_LIMB(123));
+  post ();
+
+  pre ("mpn_divexact_by3c");
+  mpn_divexact_by3c (wp, xp, size, CNST_LIMB(0));
+  post ();
+
+  pre ("mpn_divrem_1");
+  mpn_divrem_1 (wp, (mp_size_t) 0, xp, size, CNST_LIMB(123));
+  post ();
+
+#if HAVE_NATIVE_mpn_divrem_1c
+  pre ("mpn_divrem_1c");
+  mpn_divrem_1c (wp, (mp_size_t) 0, xp, size, CNST_LIMB(123), CNST_LIMB(122));
+  post ();
+#endif
+
+  pre ("mpn_gcd_1");
+  xp[0] |= 1;
+  notdead += (unsigned long) mpn_gcd_1 (xp, size, CNST_LIMB(123));
+  post ();
+
+  pre ("mpn_hamdist");
+  notdead += mpn_hamdist (xp, yp, size);
+  post ();
+
+#if HAVE_NATIVE_mpn_ior_n
+  pre ("mpn_ior_n");
+  mpn_ior_n (wp, xp, yp, size);
+  post ();
+#endif
+
+#if HAVE_NATIVE_mpn_iorn_n
+  pre ("mpn_iorn_n");
+  mpn_iorn_n (wp, xp, yp, size);
+  post ();
+#endif
+
+  pre ("mpn_lshift");
+  mpn_lshift (wp, xp, size, 1);
+  post ();
+
+  pre ("mpn_mod_1");
+  notdead += mpn_mod_1 (xp, size, CNST_LIMB(123));
+  post ();
+
+#if HAVE_NATIVE_mpn_mod_1c
+  pre ("mpn_mod_1c");
+  notdead += mpn_mod_1c (xp, size, CNST_LIMB(123), CNST_LIMB(122));
+  post ();
+#endif
+
+#if GMP_NUMB_BITS % 4 == 0
+  pre ("mpn_mod_34lsub1");
+  notdead += mpn_mod_34lsub1 (xp, size);
+  post ();
+#endif
+
+  pre ("mpn_modexact_1_odd");
+  notdead += mpn_modexact_1_odd (xp, size, CNST_LIMB(123));
+  post ();
+
+  pre ("mpn_modexact_1c_odd");
+  notdead += mpn_modexact_1c_odd (xp, size, CNST_LIMB(123), CNST_LIMB(456));
+  post ();
+
+  pre ("mpn_mul_1");
+  mpn_mul_1 (wp, xp, size, yp[0]);
+  post ();
+
+#if HAVE_NATIVE_mpn_mul_1c
+  pre ("mpn_mul_1c");
+  mpn_mul_1c (wp, xp, size, yp[0], CNST_LIMB(0));
+  post ();
+#endif
+
+#if HAVE_NATIVE_mpn_mul_2
+  pre ("mpn_mul_2");
+  mpn_mul_2 (wp, xp, size-1, yp);
+  post ();
+#endif
+
+  pre ("mpn_mul_basecase");
+  mpn_mul_basecase (wp, xp, (mp_size_t) 3, yp, (mp_size_t) 3);
+  post ();
+
+#if HAVE_NATIVE_mpn_nand_n
+  pre ("mpn_nand_n");
+  mpn_nand_n (wp, xp, yp, size);
+  post ();
+#endif
+
+#if HAVE_NATIVE_mpn_nior_n
+  pre ("mpn_nior_n");
+  mpn_nior_n (wp, xp, yp, size);
+  post ();
+#endif
+
+  pre ("mpn_popcount");
+  notdead += mpn_popcount (xp, size);
+  post ();
+
+  pre ("mpn_preinv_mod_1");
+  notdead += mpn_preinv_mod_1 (xp, size, GMP_NUMB_MAX,
+                               refmpn_invert_limb (GMP_NUMB_MAX));
+  post ();
+
+#if USE_PREINV_DIVREM_1 || HAVE_NATIVE_mpn_preinv_divrem_1
+  pre ("mpn_preinv_divrem_1");
+  mpn_preinv_divrem_1 (wp, (mp_size_t) 0, xp, size, GMP_NUMB_MAX,
+                       refmpn_invert_limb (GMP_NUMB_MAX), 0);
+  post ();
+#endif
+
+#if HAVE_NATIVE_mpn_rsh1add_n
+  pre ("mpn_rsh1add_n");
+  mpn_rsh1add_n (wp, xp, yp, size);
+  post ();
+#endif
+
+#if HAVE_NATIVE_mpn_rsh1sub_n
+  pre ("mpn_rsh1sub_n");
+  mpn_rsh1sub_n (wp, xp, yp, size);
+  post ();
+#endif
+
+  pre ("mpn_rshift");
+  mpn_rshift (wp, xp, size, 1);
+  post ();
+
+  pre ("mpn_sqr_basecase");
+  mpn_sqr_basecase (wp, xp, (mp_size_t) 3);
+  post ();
+
+  pre ("mpn_submul_1");
+  mpn_submul_1 (wp, xp, size, yp[0]);
+  post ();
+
+#if HAVE_NATIVE_mpn_submul_1c
+  pre ("mpn_submul_1c");
+  mpn_submul_1c (wp, xp, size, yp[0], CNST_LIMB(0));
+  post ();
+#endif
+
+  pre ("mpn_sub_n");
+  mpn_sub_n (wp, xp, yp, size);
+  post ();
+
+#if HAVE_NATIVE_mpn_sub_nc
+  pre ("mpn_sub_nc");
+  mpn_sub_nc (wp, xp, yp, size, CNST_LIMB(0));
+  post ();
+#endif
+
+#if HAVE_NATIVE_mpn_sublsh1_n
+  pre ("mpn_sublsh1_n");
+  mpn_sublsh1_n (wp, xp, yp, size);
+  post ();
+#endif
+
+#if HAVE_NATIVE_mpn_udiv_qrnnd
+  pre ("mpn_udiv_qrnnd");
+  mpn_udiv_qrnnd (&wp[0], CNST_LIMB(122), xp[0], CNST_LIMB(123));
+  post ();
+#endif
+
+#if HAVE_NATIVE_mpn_udiv_qrnnd_r
+  pre ("mpn_udiv_qrnnd_r");
+  mpn_udiv_qrnnd (CNST_LIMB(122), xp[0], CNST_LIMB(123), &wp[0]);
+  post ();
+#endif
+
+#if HAVE_NATIVE_mpn_umul_ppmm
+  pre ("mpn_umul_ppmm");
+  mpn_umul_ppmm (&wp[0], xp[0], yp[0]);
+  post ();
+#endif
+
+#if HAVE_NATIVE_mpn_umul_ppmm_r
+  pre ("mpn_umul_ppmm_r");
+  mpn_umul_ppmm_r (&wp[0], xp[0], yp[0]);
+  post ();
+#endif
+
+#if HAVE_NATIVE_mpn_xor_n
+  pre ("mpn_xor_n");
+  mpn_xor_n (wp, xp, yp, size);
+  post ();
+#endif
+
+#if HAVE_NATIVE_mpn_xnor_n
+  pre ("mpn_xnor_n");
+  mpn_xnor_n (wp, xp, yp, size);
+  post ();
+#endif
+}
+
+
+int
+main (void)
+{
+  tests_start ();
+
+  check ();
+
+  tests_end ();
+  exit (0);
+}
+
+
+#else /* ! WANT_PROFILING_INSTRUMENT */
+
+int
+main (void)
+{
+  exit (0);
+}
+
+#endif
diff --git a/third_party/gmp/tests/mpn/t-invert.c b/third_party/gmp/tests/mpn/t-invert.c
new file mode 100644
index 0000000..1493467
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-invert.c
@@ -0,0 +1,151 @@
+/* Test for mpn_invert function.
+
+   Contributed to the GNU project by Marco Bodrato.
+
+Copyright 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+/* Sizes are up to 2^SIZE_LOG limbs */
+#ifndef SIZE_LOG
+#define SIZE_LOG 12
+#endif
+
+#ifndef COUNT
+#define COUNT 1000
+#endif
+
+#define MAX_N (1L << SIZE_LOG)
+#define MIN_N 1
+
+
+static int
+invert_valid (mp_srcptr ip, mp_srcptr dp, mp_size_t n)
+{
+  mp_ptr tp;
+  int cy;
+  TMP_DECL;
+
+  TMP_MARK;
+  tp = TMP_ALLOC_LIMBS (2*n);
+
+  refmpn_mul (tp, ip, n, dp, n);
+  cy  = refmpn_add_n (tp + n, tp + n, dp, n); /* This must not give a carry. */
+  cy -= refmpn_add (tp, tp, 2*n, dp, n); /* This must give a carry. */
+  TMP_FREE;
+
+  return (cy == -1);
+}
+
+/*
+  Check the result of the mpn_invert function in the library.
+*/
+
+int
+main (int argc, char **argv)
+{
+  mp_ptr ip, dp, scratch;
+  int count = COUNT;
+  int test;
+  gmp_randstate_ptr rands;
+  TMP_DECL;
+  TMP_MARK;
+
+  TESTS_REPS (count, argv, argc);
+
+  tests_start ();
+  rands = RANDS;
+
+  dp = TMP_ALLOC_LIMBS (MAX_N);
+  ip = 1+TMP_ALLOC_LIMBS (MAX_N + 2);
+  scratch
+    = 1+TMP_ALLOC_LIMBS (mpn_invert_itch (MAX_N) + 2);
+
+  for (test = 0; test < count; test++)
+    {
+      unsigned size_min;
+      unsigned size_range;
+      mp_size_t n;
+      mp_size_t itch;
+      mp_limb_t i_before, i_after, s_before, s_after;
+
+      for (size_min = 1; (1L << size_min) < MIN_N; size_min++)
+	;
+
+      /* We generate an in the MIN_N <= n <= (1 << size_range). */
+      size_range = size_min
+	+ gmp_urandomm_ui (rands, SIZE_LOG + 1 - size_min);
+
+      n = MIN_N
+	+ gmp_urandomm_ui (rands, (1L << size_range) + 1 - MIN_N);
+
+      mpn_random2 (dp, n);
+
+      mpn_random2 (ip-1, n + 2);
+      i_before = ip[-1];
+      i_after = ip[n];
+
+      itch = mpn_invert_itch (n);
+      ASSERT_ALWAYS (itch <= mpn_invert_itch (MAX_N));
+      mpn_random2 (scratch-1, itch+2);
+      s_before = scratch[-1];
+      s_after = scratch[itch];
+
+      dp[n-1] |= GMP_NUMB_HIGHBIT;
+      mpn_invert (ip, dp, n, scratch);
+      if (ip[-1] != i_before || ip[n] != i_after
+	  || scratch[-1] != s_before || scratch[itch] != s_after
+	  || ! invert_valid(ip, dp, n))
+	{
+	  printf ("ERROR in test %d, n = %d\n",
+		  test, (int) n);
+	  if (ip[-1] != i_before)
+	    {
+	      printf ("before ip:"); mpn_dump (ip -1, 1);
+	      printf ("keep:   "); mpn_dump (&i_before, 1);
+	    }
+	  if (ip[n] != i_after)
+	    {
+	      printf ("after ip:"); mpn_dump (ip + n, 1);
+	      printf ("keep:   "); mpn_dump (&i_after, 1);
+	    }
+	  if (scratch[-1] != s_before)
+	    {
+	      printf ("before scratch:"); mpn_dump (scratch-1, 1);
+	      printf ("keep:   "); mpn_dump (&s_before, 1);
+	    }
+	  if (scratch[itch] != s_after)
+	    {
+	      printf ("after scratch:"); mpn_dump (scratch + itch, 1);
+	      printf ("keep:   "); mpn_dump (&s_after, 1);
+	    }
+	  mpn_dump (dp, n);
+	  mpn_dump (ip, n);
+
+	  abort();
+	}
+    }
+  TMP_FREE;
+  tests_end ();
+  return 0;
+}
diff --git a/third_party/gmp/tests/mpn/t-iord_u.c b/third_party/gmp/tests/mpn/t-iord_u.c
new file mode 100644
index 0000000..2b27713
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-iord_u.c
@@ -0,0 +1,220 @@
+/* Test MPN_INCR_U and MPN_DECR_U.
+
+Copyright 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+/* The i386 MPN_INCR_U and MPN_DECR_U have special cases for "n" being a
+   compile-time constant 1, so that's exercised explicitly.  */
+
+
+#define M     GMP_NUMB_MAX
+#define SIZE  ((mp_size_t) 10)
+
+
+void
+check_one (const char *name, int i,
+           mp_srcptr src, mp_limb_t n,
+           mp_srcptr got, mp_srcptr want, mp_size_t size)
+{
+  if (! refmpn_equal_anynail (got, want, size))
+    {
+      printf ("Wrong at %s i=%d\n", name, i);
+      mpn_trace ("  src", src,  size);
+      mpn_trace ("    n", &n,   (mp_size_t) 1);
+      mpn_trace ("  got", got,  size);
+      mpn_trace (" want", want, size);
+      abort ();
+    }
+}
+
+
+void
+check_incr_data (void)
+{
+  static const struct {
+    mp_limb_t        n;
+    const mp_limb_t  src[SIZE];
+    const mp_limb_t  want[SIZE];
+  } data[] = {
+    { 1, { 0 },   { 1 } },
+    { 1, { 123 }, { 124 } },
+    { 2, { 0 },   { 2 } },
+    { 2, { 123 }, { 125 } },
+    { M, { 0 },   { M } },
+
+    { 1, { M, 0 },   { 0,   1 } },
+    { 1, { M, 123 }, { 0,   124 } },
+    { 2, { M, 0 },   { 1,   1 } },
+    { 2, { M, 123 }, { 1,   124 } },
+    { M, { M, 0 },   { M-1, 1 } },
+    { M, { M, 123 }, { M-1, 124 } },
+
+    { 1, { M, M, 0 },   { 0,   0, 1 } },
+    { 1, { M, M, 123 }, { 0,   0, 124 } },
+    { 2, { M, M, 0 },   { 1,   0, 1 } },
+    { 2, { M, M, 123 }, { 1,   0, 124 } },
+    { M, { M, M, 0 },   { M-1, 0, 1 } },
+    { M, { M, M, 123 }, { M-1, 0, 124 } },
+
+    { 1, { M, M, M, 0 },   { 0,   0, 0, 1 } },
+    { 1, { M, M, M, 123 }, { 0,   0, 0, 124 } },
+    { 2, { M, M, M, 0 },   { 1,   0, 0, 1 } },
+    { 2, { M, M, M, 123 }, { 1,   0, 0, 124 } },
+    { M, { M, M, M, 0 },   { M-1, 0, 0, 1 } },
+    { M, { M, M, M, 123 }, { M-1, 0, 0, 124 } },
+
+    { 1, { M, M, M, M, 0 },   { 0,   0, 0, 0, 1 } },
+    { 1, { M, M, M, M, 123 }, { 0,   0, 0, 0, 124 } },
+    { 2, { M, M, M, M, 0 },   { 1,   0, 0, 0, 1 } },
+    { 2, { M, M, M, M, 123 }, { 1,   0, 0, 0, 124 } },
+    { M, { M, M, M, M, 0 },   { M-1, 0, 0, 0, 1 } },
+    { M, { M, M, M, M, 123 }, { M-1, 0, 0, 0, 124
+#if defined (__hpux) && ! defined (__GNUC__)
+    /* Some versions (at least HP92453-01 B.11.11.23709.GP) of the
+       HP C compilers fail to zero-fill aggregates as the ISO C standard
+       requires (cf 6.5.7 Initialization).  Compensate here:  */
+				, 0, 0, 0, 0, 0
+#endif
+    } }
+  };
+
+  mp_limb_t  got[SIZE];
+  int   i;
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      refmpn_copyi (got, data[i].src, SIZE);
+      MPN_INCR_U (got, SIZE, data[i].n);
+      check_one ("check_incr (general)", i,
+                 data[i].src, data[i].n,
+                 got, data[i].want, SIZE);
+
+      if (data[i].n == 1)
+        {
+          refmpn_copyi (got, data[i].src, SIZE);
+          MPN_INCR_U (got, SIZE, CNST_LIMB(1));
+          check_one ("check_incr (const 1)", i,
+                     data[i].src, data[i].n,
+                     got, data[i].want, SIZE);
+        }
+    }
+}
+
+void
+check_decr_data (void)
+{
+  static const struct {
+    mp_limb_t        n;
+    const mp_limb_t  src[SIZE];
+    const mp_limb_t  want[SIZE];
+  } data[] = {
+    { 1,   { 1 },   { 0   } },
+    { 1,   { 123 }, { 122 } },
+    { 1,   { M },   { M-1 } },
+    { 2,   { 2 },   { 0   } },
+    { 2,   { 123 }, { 121 } },
+    { M,   { M },   { 0   } },
+    { M-1, { M },   { 1   } },
+
+    { 1,   { 0,   1   }, { M,   0   } },
+    { 1,   { 0,   123 }, { M,   122 } },
+    { 1,   { 0,   M   }, { M,   M-1 } },
+    { 2,   { 0,   123 }, { M-1, 122 } },
+    { 2,   { 1,   123 }, { M,   122 } },
+    { M,   { 0,   123 }, { 1,   122 } },
+    { M,   { M-1, M   }, { M,   M-1 } },
+
+    { 1,   { 0,   0, 1   }, { M,   M, 0   } },
+    { 1,   { 0,   0, 123 }, { M,   M, 122 } },
+    { 1,   { 0,   0, M   }, { M,   M, M-1 } },
+    { 2,   { 0,   0, 123 }, { M-1, M, 122 } },
+    { 2,   { 1,   0, 123 }, { M,   M, 122 } },
+    { M,   { 0,   0, 123 }, { 1,   M, 122 } },
+    { M,   { M-1, 0, M   }, { M,   M, M-1 } },
+
+    { 1,   { 0,   0, 0, 1   }, { M,   M, M, 0   } },
+    { 1,   { 0,   0, 0, 123 }, { M,   M, M, 122 } },
+    { 1,   { 0,   0, 0, M   }, { M,   M, M, M-1 } },
+    { 2,   { 0,   0, 0, 123 }, { M-1, M, M, 122 } },
+    { 2,   { 1,   0, 0, 123 }, { M,   M, M, 122 } },
+    { M,   { 0,   0, 0, 123 }, { 1,   M, M, 122 } },
+    { M,   { M-1, 0, 0, M   }, { M,   M, M, M-1 } },
+
+    { 1,   { 0,   0, 0, 0, 1   }, { M,   M, M, M, 0   } },
+    { 1,   { 0,   0, 0, 0, 123 }, { M,   M, M, M, 122 } },
+    { 1,   { 0,   0, 0, 0, M   }, { M,   M, M, M, M-1 } },
+    { 2,   { 0,   0, 0, 0, 123 }, { M-1, M, M, M, 122 } },
+    { 2,   { 1,   0, 0, 0, 123 }, { M,   M, M, M, 122 } },
+    { M,   { 0,   0, 0, 0, 123 }, { 1,   M, M, M, 122 } },
+    { M,   { M-1, 0, 0, 0, M   }, { M,   M, M, M, M-1 } },
+
+    { 1,   { 0,   0, 0, 0, 0, 1   }, { M,   M, M, M, M, 0   } },
+    { 1,   { 0,   0, 0, 0, 0, 123 }, { M,   M, M, M, M, 122 } },
+    { 1,   { 0,   0, 0, 0, 0, M   }, { M,   M, M, M, M, M-1 } },
+    { 2,   { 0,   0, 0, 0, 0, 123 }, { M-1, M, M, M, M, 122 } },
+    { 2,   { 1,   0, 0, 0, 0, 123 }, { M,   M, M, M, M, 122 } },
+    { M,   { 0,   0, 0, 0, 0, 123 }, { 1,   M, M, M, M, 122 } },
+    { M,   { M-1, 0, 0, 0, 0, M   }, { M,   M, M, M, M, M-1
+#if defined (__hpux) && ! defined (__GNUC__)
+    /* For explanation of this garbage, see previous function.  */
+				       , 0, 0, 0, 0
+#endif
+    } }
+  };
+
+  mp_limb_t  got[SIZE];
+  int   i;
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      refmpn_copyi (got, data[i].src, SIZE);
+      MPN_DECR_U (got, SIZE, data[i].n);
+      check_one ("check_decr_data", i,
+                 data[i].src, data[i].n,
+                 got, data[i].want, SIZE);
+
+      if (data[i].n == 1)
+        {
+          refmpn_copyi (got, data[i].src, SIZE);
+          MPN_DECR_U (got, SIZE, CNST_LIMB(1));
+          check_one ("check_decr (const 1)", i,
+                     data[i].src, data[i].n,
+                     got, data[i].want, SIZE);
+        }
+    }
+}
+
+
+int
+main (void)
+{
+  tests_start ();
+  mp_trace_base = -16;
+
+  check_incr_data ();
+  check_decr_data ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpn/t-matrix22.c b/third_party/gmp/tests/mpn/t-matrix22.c
new file mode 100644
index 0000000..1fa1e3f
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-matrix22.c
@@ -0,0 +1,206 @@
+/* Tests matrix22_mul.
+
+Copyright 2008 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+struct matrix {
+  mp_size_t alloc;
+  mp_size_t n;
+  mp_ptr e00, e01, e10, e11;
+};
+
+static void
+matrix_init (struct matrix *M, mp_size_t n)
+{
+  mp_ptr p = refmpn_malloc_limbs (4*(n+1));
+  M->e00 = p; p += n+1;
+  M->e01 = p; p += n+1;
+  M->e10 = p; p += n+1;
+  M->e11 = p;
+  M->alloc = n + 1;
+  M->n = 0;
+}
+
+static void
+matrix_clear (struct matrix *M)
+{
+  refmpn_free_limbs (M->e00);
+}
+
+static void
+matrix_copy (struct matrix *R, const struct matrix *M)
+{
+  R->n = M->n;
+  MPN_COPY (R->e00, M->e00, M->n);
+  MPN_COPY (R->e01, M->e01, M->n);
+  MPN_COPY (R->e10, M->e10, M->n);
+  MPN_COPY (R->e11, M->e11, M->n);
+}
+
+/* Used with same size, so no need for normalization. */
+static int
+matrix_equal_p (const struct matrix *A, const struct matrix *B)
+{
+  return (A->n == B->n
+	  && mpn_cmp (A->e00, B->e00, A->n) == 0
+	  && mpn_cmp (A->e01, B->e01, A->n) == 0
+	  && mpn_cmp (A->e10, B->e10, A->n) == 0
+	  && mpn_cmp (A->e11, B->e11, A->n) == 0);
+}
+
+static void
+matrix_random(struct matrix *M, mp_size_t n, gmp_randstate_ptr rands)
+{
+  M->n = n;
+  mpn_random (M->e00, n);
+  mpn_random (M->e01, n);
+  mpn_random (M->e10, n);
+  mpn_random (M->e11, n);
+}
+
+#define MUL(rp, ap, an, bp, bn) do { \
+    if (an > bn)		     \
+      mpn_mul (rp, ap, an, bp, bn);  \
+    else			     \
+      mpn_mul (rp, bp, bn, ap, an);  \
+  } while(0)
+
+static void
+ref_matrix22_mul (struct matrix *R,
+		  const struct matrix *A,
+		  const struct matrix *B, mp_ptr tp)
+{
+  mp_size_t an, bn, n;
+  mp_ptr r00, r01, r10, r11, a00, a01, a10, a11, b00, b01, b10, b11;
+
+  if (A->n >= B->n)
+    {
+      r00 = R->e00; a00 = A->e00; b00 = B->e00;
+      r01 = R->e01; a01 = A->e01; b01 = B->e01;
+      r10 = R->e10; a10 = A->e10; b10 = B->e10;
+      r11 = R->e11; a11 = A->e11; b11 = B->e11;
+      an = A->n, bn = B->n;
+    }
+  else
+    {
+      /* Transpose */
+      r00 = R->e00; a00 = B->e00; b00 = A->e00;
+      r01 = R->e10; a01 = B->e10; b01 = A->e10;
+      r10 = R->e01; a10 = B->e01; b10 = A->e01;
+      r11 = R->e11; a11 = B->e11; b11 = A->e11;
+      an = B->n, bn = A->n;
+    }
+  n = an + bn;
+  R->n = n + 1;
+
+  mpn_mul (r00, a00, an, b00, bn);
+  mpn_mul (tp, a01, an, b10, bn);
+  r00[n] = mpn_add_n (r00, r00, tp, n);
+
+  mpn_mul (r01, a00, an, b01, bn);
+  mpn_mul (tp, a01, an, b11, bn);
+  r01[n] = mpn_add_n (r01, r01, tp, n);
+
+  mpn_mul (r10, a10, an, b00, bn);
+  mpn_mul (tp, a11, an, b10, bn);
+  r10[n] = mpn_add_n (r10, r10, tp, n);
+
+  mpn_mul (r11, a10, an, b01, bn);
+  mpn_mul (tp, a11, an, b11, bn);
+  r11[n] = mpn_add_n (r11, r11, tp, n);
+}
+
+static void
+one_test (const struct matrix *A, const struct matrix *B, int i)
+{
+  struct matrix R;
+  struct matrix P;
+  mp_ptr tp;
+
+  matrix_init (&R, A->n + B->n + 1);
+  matrix_init (&P, A->n + B->n + 1);
+
+  tp = refmpn_malloc_limbs (mpn_matrix22_mul_itch (A->n, B->n));
+
+  ref_matrix22_mul (&R, A, B, tp);
+  matrix_copy (&P, A);
+  mpn_matrix22_mul (P.e00, P.e01, P.e10, P.e11, A->n,
+		    B->e00, B->e01, B->e10, B->e11, B->n, tp);
+  P.n = A->n + B->n + 1;
+  if (!matrix_equal_p (&R, &P))
+    {
+      fprintf (stderr, "ERROR in test %d\n", i);
+      gmp_fprintf (stderr, "A = (%Nx, %Nx\n      %Nx, %Nx)\n"
+		   "B = (%Nx, %Nx\n      %Nx, %Nx)\n"
+		   "R = (%Nx, %Nx (expected)\n      %Nx, %Nx)\n"
+		   "P = (%Nx, %Nx (incorrect)\n      %Nx, %Nx)\n",
+		   A->e00, A->n, A->e01, A->n, A->e10, A->n, A->e11, A->n,
+		   B->e00, B->n, B->e01, B->n, B->e10, B->n, B->e11, B->n,
+		   R.e00, R.n, R.e01, R.n, R.e10, R.n, R.e11, R.n,
+		   P.e00, P.n, P.e01, P.n, P.e10, P.n, P.e11, P.n);
+      abort();
+    }
+  refmpn_free_limbs (tp);
+  matrix_clear (&R);
+  matrix_clear (&P);
+}
+
+#define MAX_SIZE (2+2*MATRIX22_STRASSEN_THRESHOLD)
+
+int
+main (int argc, char **argv)
+{
+  struct matrix A;
+  struct matrix B;
+
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  int i;
+
+  tests_start ();
+  rands = RANDS;
+
+  matrix_init (&A, MAX_SIZE);
+  matrix_init (&B, MAX_SIZE);
+  mpz_init (bs);
+
+  for (i = 0; i < 1000; i++)
+    {
+      mp_size_t an, bn;
+      mpz_urandomb (bs, rands, 32);
+      an = 1 + mpz_get_ui (bs) % MAX_SIZE;
+      mpz_urandomb (bs, rands, 32);
+      bn = 1 + mpz_get_ui (bs) % MAX_SIZE;
+
+      matrix_random (&A, an, rands);
+      matrix_random (&B, bn, rands);
+
+      one_test (&A, &B, i);
+    }
+  mpz_clear (bs);
+  matrix_clear (&A);
+  matrix_clear (&B);
+
+  tests_end ();
+  return 0;
+}
diff --git a/third_party/gmp/tests/mpn/t-minvert.c b/third_party/gmp/tests/mpn/t-minvert.c
new file mode 100644
index 0000000..ca5690f
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-minvert.c
@@ -0,0 +1,167 @@
+/* Copyright 2013-2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>		/* for strtol */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+#include "tests/tests.h"
+
+#define MAX_SIZE 50
+
+#define COUNT 200
+
+static void
+mpz_to_mpn (mp_ptr ap, mp_size_t an, const mpz_t b)
+{
+  mp_size_t bn = mpz_size (b);
+  ASSERT_ALWAYS (bn <= an);
+  MPN_COPY_INCR (ap, mpz_limbs_read (b), bn);
+  MPN_ZERO (ap + bn, an - bn);
+}
+
+int
+mpz_eq_mpn (mp_ptr ap, mp_size_t an, const mpz_t b)
+{
+  mp_size_t bn = mpz_size (b);
+
+  return (bn >= 0 && bn <= an
+	  && mpn_cmp (ap, mpz_limbs_read (b), bn) == 0
+	  && (an == bn || mpn_zero_p (ap + bn, an - bn)));
+}
+
+static mp_bitcnt_t
+bit_size (mp_srcptr xp, mp_size_t n)
+{
+  MPN_NORMALIZE (xp, n);
+  return n > 0 ? mpn_sizeinbase (xp, n, 2) : 0;
+}
+
+int
+main (int argc, char **argv)
+{
+  gmp_randstate_ptr rands;
+  long count = COUNT;
+  mp_ptr mp;
+  mp_ptr ap;
+  mp_ptr tp;
+  mp_ptr scratch;
+  mpz_t m, a, r, g;
+  int test;
+  mp_limb_t ran;
+  mp_size_t itch;
+  TMP_DECL;
+
+  tests_start ();
+  rands = RANDS;
+
+
+  TMP_MARK;
+  mpz_init (m);
+  mpz_init (a);
+  mpz_init (r);
+  mpz_init (g);
+
+  TESTS_REPS (count, argv, argc);
+
+  mp = TMP_ALLOC_LIMBS (MAX_SIZE);
+  ap = TMP_ALLOC_LIMBS (MAX_SIZE);
+  tp = TMP_ALLOC_LIMBS (MAX_SIZE);
+  scratch = TMP_ALLOC_LIMBS (mpn_sec_invert_itch (MAX_SIZE) + 1);
+
+  for (test = 0; test < count; test++)
+    {
+      mp_bitcnt_t bits;
+      int rres, tres;
+      mp_size_t n;
+
+      bits = urandom () % (GMP_NUMB_BITS * MAX_SIZE) + 1;
+
+      if (test & 1)
+	mpz_rrandomb (m, rands, bits);
+      else
+	mpz_urandomb (m, rands, bits);
+      if (test & 2)
+	mpz_rrandomb (a, rands, bits);
+      else
+	mpz_urandomb (a, rands, bits);
+
+      mpz_setbit (m, 0);
+      if (test & 4)
+	{
+	  /* Ensure it really is invertible */
+	  if (mpz_sgn (a) == 0)
+	    mpz_set_ui (a, 1);
+	  else
+	    for (;;)
+	      {
+		mpz_gcd (g, a, m);
+		if (mpz_cmp_ui (g, 1) == 0)
+		  break;
+		mpz_remove (a, a, g);
+	      }
+	}
+
+      rres = mpz_invert (r, a, m);
+      if ( (test & 4) && !rres)
+	{
+	  gmp_fprintf (stderr, "test %d: Not invertible!\n"
+		       "m = %Zd\n"
+		       "a = %Zd\n", test, m, a);
+	  abort ();
+	}
+      ASSERT_ALWAYS (! (test & 4) || rres);
+
+      n = (bits + GMP_NUMB_BITS - 1) / GMP_NUMB_BITS;
+      ASSERT_ALWAYS (n <= MAX_SIZE);
+      itch = mpn_sec_invert_itch (n);
+      scratch[itch] = ran = urandom ();
+
+      mpz_to_mpn (ap, n, a);
+      mpz_to_mpn (mp, n, m);
+      tres = mpn_sec_invert (tp, ap, mp, n,
+			     bit_size (ap, n) + bit_size (mp, n),
+			     scratch);
+
+      if (rres != tres || (rres == 1 && !mpz_eq_mpn (tp, n, r)) || ran != scratch[itch])
+	{
+	  gmp_fprintf (stderr, "Test %d failed.\n"
+		       "m = %Zd\n"
+		       "a = %Zd\n", test, m, a);
+	  fprintf (stderr, "ref ret: %d\n"
+		  "got ret: %d\n", rres, tres);
+	  if (rres)
+	    gmp_fprintf (stderr, "ref: %Zd\n", r);
+	  if (tres)
+	    gmp_fprintf (stderr, "got: %Nd\n", tp, n);
+	  if (ran != scratch[itch])
+	    fprintf (stderr, "scratch[itch] changed.\n");
+	  abort ();
+	}
+    }
+
+  TMP_FREE;
+
+  mpz_clear (m);
+  mpz_clear (a);
+  mpz_clear (r);
+  mpz_clear (g);
+
+  tests_end ();
+  return 0;
+}
diff --git a/third_party/gmp/tests/mpn/t-mod_1.c b/third_party/gmp/tests/mpn/t-mod_1.c
new file mode 100644
index 0000000..5b9570d
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-mod_1.c
@@ -0,0 +1,127 @@
+/* Test mpn_mod_1 variants.
+
+Copyright 2010, 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+static void
+check_one (mp_srcptr ap, mp_size_t n, mp_limb_t b)
+{
+  mp_limb_t r_ref = refmpn_mod_1 (ap, n, b);
+  mp_limb_t r;
+
+  if (n >= 2)
+    {
+      mp_limb_t pre[4];
+      mpn_mod_1_1p_cps (pre, b);
+      r = mpn_mod_1_1p (ap, n, b << pre[1], pre);
+      if (r != r_ref)
+	{
+	  printf ("mpn_mod_1_1p failed\n");
+	  goto fail;
+	}
+    }
+  if ((b & GMP_NUMB_HIGHBIT) == 0)
+    {
+      mp_limb_t pre[5];
+      mpn_mod_1s_2p_cps (pre, b);
+      r = mpn_mod_1s_2p (ap, n, b << pre[1], pre);
+      if (r != r_ref)
+	{
+	  printf ("mpn_mod_1s_2p failed\n");
+	  goto fail;
+	}
+    }
+  if (b <= GMP_NUMB_MASK / 3)
+    {
+      mp_limb_t pre[6];
+      mpn_mod_1s_3p_cps (pre, b);
+      r = mpn_mod_1s_3p (ap, n, b << pre[1], pre);
+      if (r != r_ref)
+	{
+	  printf ("mpn_mod_1s_3p failed\n");
+	  goto fail;
+	}
+    }
+  if (b <= GMP_NUMB_MASK / 4)
+    {
+      mp_limb_t pre[7];
+      mpn_mod_1s_4p_cps (pre, b);
+      r = mpn_mod_1s_4p (ap, n, b << pre[1], pre);
+      if (r != r_ref)
+	{
+	  printf ("mpn_mod_1s_4p failed\n");
+	  goto fail;
+	}
+    }
+  r = mpn_mod_1 (ap, n, b);
+  if (r != r_ref)
+    {
+      printf ("mpn_mod_1 failed\n");
+    fail:
+      printf ("an = %d, a: ", (int) n); mpn_dump (ap, n);
+      printf ("b           : "); mpn_dump (&b, 1);
+      printf ("r (expected): "); mpn_dump (&r_ref, 1);
+      printf ("r (bad)     : "); mpn_dump (&r, 1);
+      abort();
+    }
+}
+
+int
+main (int argc, char **argv)
+{
+  gmp_randstate_ptr rands;
+  int i;
+  unsigned a_bits;
+  unsigned b_bits;
+  mpz_t a;
+  mpz_t b;
+
+  tests_start ();
+  rands = RANDS;
+  mpz_init (a);
+  mpz_init (b);
+
+  for (i = 0; i < 300; i++)
+    {
+      mp_size_t asize;
+      a_bits = 1 + gmp_urandomm_ui (rands, 1000);
+      b_bits = 1 + gmp_urandomm_ui (rands, GMP_NUMB_BITS);
+
+      mpz_rrandomb (a, rands, a_bits);
+      mpz_rrandomb (b, rands, b_bits);
+
+      asize = SIZ(a);
+      if (!asize)
+	asize = 1;
+      if (mpz_sgn (b) == 0)
+	mpz_set_ui (b, 1);
+
+      check_one (PTR(a), asize, PTR(b)[0]);
+    }
+
+  mpz_clear (a);
+  mpz_clear (b);
+
+  tests_end ();
+  return 0;
+}
diff --git a/third_party/gmp/tests/mpn/t-mp_bases.c b/third_party/gmp/tests/mpn/t-mp_bases.c
new file mode 100644
index 0000000..deb7f5c
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-mp_bases.c
@@ -0,0 +1,104 @@
+/* Check mp_bases values.
+
+Copyright 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "longlong.h"
+#include "tests.h"
+
+
+int
+main (int argc, char *argv[])
+{
+  mp_limb_t  want_bb, want_bb_inv;
+  int        base, want_chars_per_limb;
+
+  want_chars_per_limb = refmpn_chars_per_limb (10);
+  if (MP_BASES_CHARS_PER_LIMB_10 != want_chars_per_limb)
+    {
+      printf ("MP_BASES_CHARS_PER_LIMB_10 wrong\n");
+      abort ();
+    }
+
+  want_bb = refmpn_big_base (10);
+  if (MP_BASES_BIG_BASE_10 != want_bb)
+    {
+      printf ("MP_BASES_BIG_BASE_10 wrong\n");
+      abort ();
+    }
+
+  want_bb_inv = refmpn_invert_limb
+    (want_bb << refmpn_count_leading_zeros (want_bb));
+  if (MP_BASES_BIG_BASE_INVERTED_10 != want_bb_inv)
+    {
+      printf ("MP_BASES_BIG_BASE_INVERTED_10 wrong\n");
+      abort ();
+    }
+
+  if (MP_BASES_NORMALIZATION_STEPS_10
+      != refmpn_count_leading_zeros (MP_BASES_BIG_BASE_10))
+    {
+      printf ("MP_BASES_NORMALIZATION_STEPS_10 wrong\n");
+      abort ();
+    }
+
+  for (base = 2; base < numberof (mp_bases); base++)
+    {
+      want_chars_per_limb = refmpn_chars_per_limb (base);
+      if (mp_bases[base].chars_per_limb != want_chars_per_limb)
+        {
+          printf ("mp_bases[%d].chars_per_limb wrong\n", base);
+          printf ("  got  %d\n", mp_bases[base].chars_per_limb);
+          printf ("  want %d\n", want_chars_per_limb);
+          abort ();
+        }
+
+      if (POW2_P (base))
+        {
+          want_bb = refmpn_count_trailing_zeros ((mp_limb_t) base);
+          if (mp_bases[base].big_base != want_bb)
+            {
+              printf ("mp_bases[%d].big_base (log2 of base) wrong\n", base);
+              abort ();
+            }
+        }
+      else
+        {
+          want_bb = refmpn_big_base (base);
+          if (mp_bases[base].big_base != want_bb)
+            {
+              printf ("mp_bases[%d].big_base wrong\n", base);
+              abort ();
+            }
+
+#if USE_PREINV_DIVREM_1
+          want_bb_inv = refmpn_invert_limb
+            (want_bb << refmpn_count_leading_zeros (want_bb));
+          if (mp_bases[base].big_base_inverted != want_bb_inv)
+            {
+              printf ("mp_bases[%d].big_base_inverted wrong\n", base);
+              abort ();
+            }
+#endif
+        }
+    }
+
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpn/t-mul.c b/third_party/gmp/tests/mpn/t-mul.c
new file mode 100644
index 0000000..40f6de7
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-mul.c
@@ -0,0 +1,97 @@
+/* Test mpn_mul function for all sizes up to a selected limit.
+
+Copyright 2011, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+static unsigned
+isqrt (unsigned t)
+{
+  unsigned s, b;
+
+  for (b = 0, s = t;  b++, s >>= 1; )
+    ;
+
+  s = 1 << (b >> 1);
+  if (b & 1)
+    s += s >> 1;
+
+  do
+    {
+      b = t / s;
+      s = (s + b) >> 1;
+    }
+  while (b < s);
+
+  return s;
+}
+
+int
+main (int argc, char **argv)
+{
+  mp_ptr ap, bp, rp, refp;
+  mp_size_t max_n, an, bn, rn;
+  int reps;
+  TMP_DECL;
+  TMP_MARK;
+
+  reps = 1;
+
+  tests_start ();
+  TESTS_REPS (reps, argv, argc);
+
+  /* Re-interpret reps argument as a size argument.  */
+  max_n = isqrt (reps * 25000);
+
+  ap = TMP_ALLOC_LIMBS (max_n + 1);
+  bp = TMP_ALLOC_LIMBS (max_n + 1);
+  rp = TMP_ALLOC_LIMBS (2 * max_n);
+  refp = TMP_ALLOC_LIMBS (2 * max_n);
+
+  for (an = 1; an <= max_n; an += 1)
+    {
+      for (bn = 1; bn <= an; bn += 1)
+	{
+	  mpn_random2 (ap, an + 1);
+	  mpn_random2 (bp, bn + 1);
+
+	  refmpn_mul (refp, ap, an, bp, bn);
+	  mpn_mul (rp, ap, an, bp, bn);
+
+	  rn = an + bn;
+	  if (mpn_cmp (refp, rp, rn))
+	    {
+	      printf ("ERROR, an = %d, bn = %d, rn = %d\n",
+		      (int) an, (int) bn, (int) rn);
+	      printf ("a: "); mpn_dump (ap, an);
+	      printf ("b: "); mpn_dump (bp, bn);
+	      printf ("r:   "); mpn_dump (rp, rn);
+	      printf ("ref: "); mpn_dump (refp, rn);
+	      abort();
+	    }
+	}
+    }
+  TMP_FREE;
+  tests_end ();
+  return 0;
+}
diff --git a/third_party/gmp/tests/mpn/t-mullo.c b/third_party/gmp/tests/mpn/t-mullo.c
new file mode 100644
index 0000000..75a0f01
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-mullo.c
@@ -0,0 +1,132 @@
+/* Test for mullo function.
+
+Copyright 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+/* Sizes are up to 2^SIZE_LOG limbs */
+#ifndef SIZE_LOG
+#define SIZE_LOG 10
+#endif
+
+#ifndef COUNT
+#define COUNT 10000
+#endif
+
+#define MAX_N (1L << SIZE_LOG)
+#define MIN_N (1)
+
+int
+main (int argc, char **argv)
+{
+  mp_ptr ap, bp, refp, pp, scratch;
+  int count = COUNT;
+  int test;
+  gmp_randstate_ptr rands;
+  TMP_DECL;
+  TMP_MARK;
+
+  TESTS_REPS (count, argv, argc);
+
+  tests_start ();
+  rands = RANDS;
+
+#define mpn_mullo_itch(n) (0)
+
+  ap = TMP_ALLOC_LIMBS (MAX_N);
+  bp = TMP_ALLOC_LIMBS (MAX_N);
+  refp = TMP_ALLOC_LIMBS (MAX_N * 2);
+  pp = 1+TMP_ALLOC_LIMBS (MAX_N + 2);
+  scratch
+    = 1+TMP_ALLOC_LIMBS (mpn_mullo_itch (MAX_N) + 2);
+
+  for (test = 0; test < count; test++)
+    {
+      unsigned size_min;
+      unsigned size_range;
+      mp_size_t n;
+      mp_size_t itch;
+      mp_limb_t p_before, p_after, s_before, s_after;
+
+      for (size_min = 1; (1L << size_min) < MIN_N; size_min++)
+	;
+
+      /* We generate an in the MIN_N <= n <= (1 << size_range). */
+      size_range = size_min
+	+ gmp_urandomm_ui (rands, SIZE_LOG + 1 - size_min);
+
+      n = MIN_N
+	+ gmp_urandomm_ui (rands, (1L << size_range) + 1 - MIN_N);
+
+      mpn_random2 (ap, n);
+      mpn_random2 (bp, n);
+      mpn_random2 (pp-1, n + 2);
+      p_before = pp[-1];
+      p_after = pp[n];
+
+      itch = mpn_mullo_itch (n);
+      ASSERT_ALWAYS (itch <= mpn_mullo_itch (MAX_N));
+      mpn_random2 (scratch-1, itch+2);
+      s_before = scratch[-1];
+      s_after = scratch[itch];
+
+      mpn_mullo_n (pp, ap, bp, n);
+      mpn_mul_n (refp, ap, bp, n);
+      if (pp[-1] != p_before || pp[n] != p_after
+	  || scratch[-1] != s_before || scratch[itch] != s_after
+	  || mpn_cmp (refp, pp, n) != 0)
+	{
+	  printf ("ERROR in test %d, n = %d",
+		  test, (int) n);
+	  if (pp[-1] != p_before)
+	    {
+	      printf ("before pp:"); mpn_dump (pp -1, 1);
+	      printf ("keep:   "); mpn_dump (&p_before, 1);
+	    }
+	  if (pp[n] != p_after)
+	    {
+	      printf ("after pp:"); mpn_dump (pp + n, 1);
+	      printf ("keep:   "); mpn_dump (&p_after, 1);
+	    }
+	  if (scratch[-1] != s_before)
+	    {
+	      printf ("before scratch:"); mpn_dump (scratch-1, 1);
+	      printf ("keep:   "); mpn_dump (&s_before, 1);
+	    }
+	  if (scratch[itch] != s_after)
+	    {
+	      printf ("after scratch:"); mpn_dump (scratch + itch, 1);
+	      printf ("keep:   "); mpn_dump (&s_after, 1);
+	    }
+	  mpn_dump (ap, n);
+	  mpn_dump (bp, n);
+	  mpn_dump (pp, n);
+	  mpn_dump (refp, n);
+
+	  abort();
+	}
+    }
+  TMP_FREE;
+  tests_end ();
+  return 0;
+}
diff --git a/third_party/gmp/tests/mpn/t-mulmid.c b/third_party/gmp/tests/mpn/t-mulmid.c
new file mode 100644
index 0000000..9491b0e
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-mulmid.c
@@ -0,0 +1,92 @@
+/* Test for mulmid function.
+
+Copyright 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+/* Sizes are up to 2^SIZE_LOG limbs */
+#ifndef SIZE_LOG
+#define SIZE_LOG 9
+#endif
+
+#ifndef COUNT
+#define COUNT 5000
+#endif
+
+#define MAX_N (1L << SIZE_LOG)
+
+int
+main (int argc, char **argv)
+{
+  mp_ptr ap, bp, rp, refp;
+  gmp_randstate_ptr rands;
+  int test;
+  TMP_DECL;
+  TMP_MARK;
+
+  tests_start ();
+  rands = RANDS;
+
+  ap = TMP_ALLOC_LIMBS (MAX_N);
+  bp = TMP_ALLOC_LIMBS (MAX_N);
+  rp = TMP_ALLOC_LIMBS (MAX_N + 2);
+  refp = TMP_ALLOC_LIMBS (MAX_N + 2);
+
+  for (test = 0; test < COUNT; test++)
+    {
+      mp_size_t an, bn, rn;
+      unsigned size_log;
+
+      size_log = 1 + gmp_urandomm_ui (rands, SIZE_LOG);
+      an = 1 + gmp_urandomm_ui(rands, 1L << size_log);
+
+      size_log = 1 + gmp_urandomm_ui (rands, SIZE_LOG);
+      bn = 1 + gmp_urandomm_ui(rands, 1L << size_log);
+
+      /* Make sure an >= bn */
+      if (an < bn)
+	MP_SIZE_T_SWAP (an, bn);
+
+      mpn_random2 (ap, an);
+      mpn_random2 (bp, bn);
+
+      refmpn_mulmid (refp, ap, an, bp, bn);
+      mpn_mulmid (rp, ap, an, bp, bn);
+
+      rn = an + 3 - bn;
+      if (mpn_cmp (refp, rp, rn))
+	{
+	  printf ("ERROR in test %d, an = %d, bn = %d, rn = %d\n",
+		  test, (int) an, (int) bn, (int) rn);
+	  printf("a: "); mpn_dump (ap, an);
+	  printf("b: "); mpn_dump (bp, bn);
+	  printf("r:   "); mpn_dump (rp, rn);
+	  printf("ref: "); mpn_dump (refp, rn);
+
+	  abort();
+	}
+    }
+  TMP_FREE;
+  tests_end ();
+  return 0;
+}
diff --git a/third_party/gmp/tests/mpn/t-mulmod_bnm1.c b/third_party/gmp/tests/mpn/t-mulmod_bnm1.c
new file mode 100644
index 0000000..d91a30d
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-mulmod_bnm1.c
@@ -0,0 +1,208 @@
+/* Test for mulmod_bnm1 function.
+
+   Contributed to the GNU project by Marco Bodrato.
+
+Copyright 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+/* Sizes are up to 2^SIZE_LOG limbs */
+#ifndef SIZE_LOG
+#define SIZE_LOG 11
+#endif
+
+#ifndef COUNT
+#define COUNT 5000
+#endif
+
+#define MAX_N (1L << SIZE_LOG)
+#define MIN_N 1
+
+/*
+  Reference function for multiplication modulo B^rn-1.
+
+  The result is expected to be ZERO if and only if one of the operand
+  already is. Otherwise the class [0] Mod(B^rn-1) is represented by
+  B^rn-1. This should not be a problem if mulmod_bnm1 is used to
+  combine results and obtain a natural number when one knows in
+  advance that the final value is less than (B^rn-1).
+*/
+
+static void
+ref_mulmod_bnm1 (mp_ptr rp, mp_size_t rn, mp_srcptr ap, mp_size_t an, mp_srcptr bp, mp_size_t bn)
+{
+  mp_limb_t cy;
+
+  ASSERT (0 < an && an <= rn);
+  ASSERT (0 < bn && bn <= rn);
+
+  if (an >= bn)
+    refmpn_mul (rp, ap, an, bp, bn);
+  else
+    refmpn_mul (rp, bp, bn, ap, an);
+  an += bn;
+  if (an > rn) {
+    cy = mpn_add (rp, rp, rn, rp + rn, an - rn);
+    /* If cy == 1, then the value of rp is at most B^rn - 2, so there can
+     * be no overflow when adding in the carry. */
+    MPN_INCR_U (rp, rn, cy);
+  }
+}
+
+/*
+  Compare the result of the mpn_mulmod_bnm1 function in the library
+  with the reference function above.
+*/
+
+int
+main (int argc, char **argv)
+{
+  mp_ptr ap, bp, refp, pp, scratch;
+  int count = COUNT;
+  int test;
+  gmp_randstate_ptr rands;
+  TMP_DECL;
+  TMP_MARK;
+
+  TESTS_REPS (count, argv, argc);
+
+  tests_start ();
+  rands = RANDS;
+
+  ASSERT_ALWAYS (mpn_mulmod_bnm1_next_size (MAX_N) == MAX_N);
+
+  ap = TMP_ALLOC_LIMBS (MAX_N);
+  bp = TMP_ALLOC_LIMBS (MAX_N);
+  refp = TMP_ALLOC_LIMBS (MAX_N * 4);
+  pp = 1+TMP_ALLOC_LIMBS (MAX_N + 2);
+  scratch
+    = 1+TMP_ALLOC_LIMBS (mpn_mulmod_bnm1_itch (MAX_N, MAX_N, MAX_N) + 2);
+
+  for (test = 0; test < count; test++)
+    {
+      unsigned size_min;
+      unsigned size_range;
+      mp_size_t an,bn,rn,n;
+      mp_size_t itch;
+      mp_limb_t p_before, p_after, s_before, s_after;
+
+      for (size_min = 1; (1L << size_min) < MIN_N; size_min++)
+	;
+
+      /* We generate an in the MIN_N <= n <= (1 << size_range). */
+      size_range = size_min
+	+ gmp_urandomm_ui (rands, SIZE_LOG + 1 - size_min);
+
+      n = MIN_N
+	+ gmp_urandomm_ui (rands, (1L << size_range) + 1 - MIN_N);
+      n = mpn_mulmod_bnm1_next_size (n);
+
+      if ( (test & 1) || n == 1) {
+	/* Half of the tests are done with the main scenario in mind:
+	   both an and bn >= rn/2 */
+	an = ((n+1) >> 1) + gmp_urandomm_ui (rands, (n+1) >> 1);
+	bn = ((n+1) >> 1) + gmp_urandomm_ui (rands, (n+1) >> 1);
+      } else {
+	/* Second half of the tests are done using mulmod to compute a
+	   full product with n/2 < an+bn <= n. */
+	an = 1 + gmp_urandomm_ui (rands, n - 1);
+	if (an >= n/2)
+	  bn = 1 + gmp_urandomm_ui (rands, n - an);
+	else
+	  bn = n/2 + 1 - an + gmp_urandomm_ui (rands, (n+1)/2);
+      }
+
+      /* Make sure an >= bn */
+      if (an < bn)
+	MP_SIZE_T_SWAP (an, bn);
+
+      mpn_random2 (ap, an);
+      mpn_random2 (bp, bn);
+
+      /* Sometime trigger the borderline conditions
+	 A = -1,0,+1 or B = -1,0,+1 or A*B == -1,0,1 Mod(B^{n/2}+1).
+	 This only makes sense if there is at least a split, i.e. n is even. */
+      if ((test & 0x1f) == 1 && (n & 1) == 0) {
+	mp_size_t x;
+	MPN_COPY (ap, ap + (n >> 1), an - (n >> 1));
+	MPN_ZERO (ap + an - (n >> 1) , n - an);
+	MPN_COPY (bp, bp + (n >> 1), bn - (n >> 1));
+	MPN_ZERO (bp + bn - (n >> 1) , n - bn);
+	x = (n == an) ? 0 : gmp_urandomm_ui (rands, n - an);
+	ap[x] += gmp_urandomm_ui (rands, 3) - 1;
+	x = (n >> 1) - x % (n >> 1);
+	bp[x] += gmp_urandomm_ui (rands, 3) - 1;
+	/* We don't propagate carry, this means that the desired condition
+	   is not triggered all the times. A few times are enough anyway. */
+      }
+      rn = MIN(n, an + bn);
+      mpn_random2 (pp-1, rn + 2);
+      p_before = pp[-1];
+      p_after = pp[rn];
+
+      itch = mpn_mulmod_bnm1_itch (n, an, bn);
+      ASSERT_ALWAYS (itch <= mpn_mulmod_bnm1_itch (MAX_N, MAX_N, MAX_N));
+      mpn_random2 (scratch-1, itch+2);
+      s_before = scratch[-1];
+      s_after = scratch[itch];
+
+      mpn_mulmod_bnm1 (  pp, n, ap, an, bp, bn, scratch);
+      ref_mulmod_bnm1 (refp, n, ap, an, bp, bn);
+      if (pp[-1] != p_before || pp[rn] != p_after
+	  || scratch[-1] != s_before || scratch[itch] != s_after
+	  || mpn_cmp (refp, pp, rn) != 0)
+	{
+	  printf ("ERROR in test %d, an = %d, bn = %d, n = %d\n",
+		  test, (int) an, (int) bn, (int) n);
+	  if (pp[-1] != p_before)
+	    {
+	      printf ("before pp:"); mpn_dump (pp -1, 1);
+	      printf ("keep:   "); mpn_dump (&p_before, 1);
+	    }
+	  if (pp[rn] != p_after)
+	    {
+	      printf ("after pp:"); mpn_dump (pp + rn, 1);
+	      printf ("keep:   "); mpn_dump (&p_after, 1);
+	    }
+	  if (scratch[-1] != s_before)
+	    {
+	      printf ("before scratch:"); mpn_dump (scratch-1, 1);
+	      printf ("keep:   "); mpn_dump (&s_before, 1);
+	    }
+	  if (scratch[itch] != s_after)
+	    {
+	      printf ("after scratch:"); mpn_dump (scratch + itch, 1);
+	      printf ("keep:   "); mpn_dump (&s_after, 1);
+	    }
+	  mpn_dump (ap, an);
+	  mpn_dump (bp, bn);
+	  mpn_dump (pp, rn);
+	  mpn_dump (refp, rn);
+
+	  abort();
+	}
+    }
+  TMP_FREE;
+  tests_end ();
+  return 0;
+}
diff --git a/third_party/gmp/tests/mpn/t-perfsqr.c b/third_party/gmp/tests/mpn/t-perfsqr.c
new file mode 100644
index 0000000..b65ee8b
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-perfsqr.c
@@ -0,0 +1,116 @@
+/* Test mpn_perfect_square_p data.
+
+Copyright 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#include "mpn/perfsqr.h"
+
+
+#define PERFSQR_MOD_MASK   ((CNST_LIMB(1) << PERFSQR_MOD_BITS) - 1)
+
+void
+check_mod_2 (mp_limb_t d, mp_limb_t inv, mp_limb_t got_hi, mp_limb_t got_lo)
+{
+  int        want[2*GMP_LIMB_BITS], got;
+  unsigned   r, idx;
+  mp_limb_t  q;
+
+  ASSERT_ALWAYS (d <= numberof (want));
+  ASSERT_ALWAYS (((inv * d) & PERFSQR_MOD_MASK) == 1);
+  ASSERT_ALWAYS (MP_LIMB_T_MAX / d >= PERFSQR_MOD_MASK);
+
+  /* the squares mod d */
+  for (r = 0; r < d; r++)
+    want[r] = 0;
+  for (r = 0; r < d; r++)
+    want[(r*r)%d] = 1;
+
+  /* for each remainder mod d, expect the table data to correctly identify
+     it as a residue or non-residue */
+  for (r = 0; r < d; r++)
+    {
+      /* as per PERFSQR_MOD_IDX */
+      q = ((r) * (inv)) & PERFSQR_MOD_MASK;
+      idx = (q * (d)) >> PERFSQR_MOD_BITS;
+
+      if (idx >= GMP_LIMB_BITS)
+        got = (got_hi >> (idx - GMP_LIMB_BITS)) & 1;
+      else
+        got = (got_lo >> idx) & 1;
+
+      if (got != want[r])
+        {
+          printf ("Wrong generated data\n");
+          printf ("  d=%u\n", (unsigned) d);
+          printf ("  r=%u\n", r);
+          printf ("  idx=%u\n", idx);
+          printf ("  got  %d\n", got);
+          printf ("  want %d\n", want[r]);
+          abort ();
+        }
+    }
+}
+
+/* Check the generated data in perfsqr.h. */
+void
+check_mod (void)
+{
+#define PERFSQR_MOD_34(r, up, usize)       { r = 0; } /* so r isn't unused */
+#define PERFSQR_MOD_PP(r, up, usize)       { r = 0; }
+#define PERFSQR_MOD_1(r, d, inv, mask)     check_mod_2 (d, inv, CNST_LIMB(0), mask)
+#define PERFSQR_MOD_2(r, d, inv, mhi, mlo) check_mod_2 (d, inv, mhi, mlo)
+
+  PERFSQR_MOD_TEST (dummy, dummy);
+}
+
+/* Check PERFSQR_PP, if in use. */
+void
+check_pp (void)
+{
+#ifdef PERFSQR_PP
+  ASSERT_ALWAYS_LIMB (PERFSQR_PP);
+  ASSERT_ALWAYS_LIMB (PERFSQR_PP_NORM);
+  ASSERT_ALWAYS_LIMB (PERFSQR_PP_INVERTED);
+
+  /* preinv stuff only for nails==0 */
+  if (GMP_NAIL_BITS == 0)
+    {
+      ASSERT_ALWAYS (PERFSQR_PP_NORM
+                     == PERFSQR_PP << refmpn_count_leading_zeros (PERFSQR_PP));
+      ASSERT_ALWAYS (PERFSQR_PP_INVERTED
+                     == refmpn_invert_limb (PERFSQR_PP_NORM));
+    }
+#endif
+}
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_mod ();
+  check_pp ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpn/t-scan.c b/third_party/gmp/tests/mpn/t-scan.c
new file mode 100644
index 0000000..ec25b95
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-scan.c
@@ -0,0 +1,144 @@
+/* Test mpn_scan0 and mpn_scan1.
+
+Copyright 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+
+#include "tests.h"
+
+
+#define SIZE  ((mp_size_t) 3)
+mp_limb_t  x[SIZE+1];
+
+void
+check (void)
+{
+  unsigned long  i, got, want;
+
+  x[SIZE] = 1;
+  for (i = 0; i < SIZE*GMP_NUMB_BITS; i++)
+    {
+      got = refmpn_scan1 (x, i);
+      want = mpn_scan1 (x, i);
+      if (got != want)
+        {
+          printf ("mpn_scan1\n");
+          printf ("  i     %lu\n", i);
+          printf ("  got   %lu\n", got);
+          printf ("  want  %lu\n", want);
+          mpn_trace ("  x    ", x, SIZE);
+          abort ();
+        }
+    }
+
+  x[SIZE] = 0;
+  for (i = 0; i < SIZE*GMP_NUMB_BITS; i++)
+    {
+      got = refmpn_scan0 (x, i);
+      want = mpn_scan0 (x, i);
+      if (got != want)
+        {
+          printf ("mpn_scan0\n");
+          printf ("  i     %lu\n", i);
+          printf ("  got   %lu\n", got);
+          printf ("  want  %lu\n", want);
+          mpn_trace ("  x    ", x, SIZE);
+          abort ();
+        }
+    }
+}
+
+void
+check_twobits (void)
+{
+#define TWOBITS(a, b) \
+  ((CNST_LIMB(1) << (a)) | (CNST_LIMB(1) << (b)))
+
+  refmpn_zero (x, SIZE);
+  x[0] = TWOBITS (1, 0);
+  check ();
+
+  refmpn_zero (x, SIZE);
+  x[0] = TWOBITS (GMP_NUMB_BITS-1, 1);
+  check ();
+
+  refmpn_zero (x, SIZE);
+  x[0] = CNST_LIMB(1);
+  x[1] = CNST_LIMB(1);
+  check ();
+
+  refmpn_zero (x, SIZE);
+  x[0] = CNST_LIMB(1) << (GMP_NUMB_BITS-1);
+  x[1] = CNST_LIMB(1);
+  check ();
+
+  refmpn_zero (x, SIZE);
+  x[1] = TWOBITS (1, 0);
+  check ();
+
+  refmpn_zero (x, SIZE);
+  x[1] = CNST_LIMB(1);
+  x[2] = CNST_LIMB(1);
+  check ();
+}
+
+/* This is unused, it takes too long, especially on 64-bit systems. */
+void
+check_twobits_exhaustive (void)
+{
+  unsigned long  i, j;
+
+  for (i = 0; i < GMP_NUMB_BITS * SIZE; i++)
+    {
+      for (j = 0; j < GMP_NUMB_BITS * SIZE; j++)
+        {
+          refmpn_zero (x, SIZE);
+          refmpn_setbit (x, i);
+          refmpn_setbit (x, j);
+          check ();
+        }
+    }
+}
+
+void
+check_rand (void)
+{
+  int  i;
+
+  for (i = 0; i < 100; i++)
+    {
+      refmpn_random2 (x, SIZE);
+      check ();
+    }
+}
+
+int
+main (void)
+{
+  mp_trace_base = -16;
+  tests_start ();
+
+  check_twobits ();
+  check_rand ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpn/t-sizeinbase.c b/third_party/gmp/tests/mpn/t-sizeinbase.c
new file mode 100644
index 0000000..f34714a
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-sizeinbase.c
@@ -0,0 +1,98 @@
+/* Test for sizeinbase function.
+
+Copyright 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+/* Exponents up to 2^SIZE_LOG */
+#ifndef SIZE_LOG
+#define SIZE_LOG 13
+#endif
+
+#ifndef COUNT
+#define COUNT 30
+#endif
+
+#define MAX_N (1<<SIZE_LOG)
+
+int
+main (int argc, char **argv)
+{
+  mp_limb_t a;
+  mp_ptr pp, scratch;
+  mp_limb_t max_b;
+  int count = COUNT;
+  int test;
+  gmp_randstate_ptr rands;
+  TMP_DECL;
+
+  TESTS_REPS (count, argv, argc);
+
+  tests_start ();
+  TMP_MARK;
+  rands = RANDS;
+
+  pp = TMP_ALLOC_LIMBS (MAX_N);
+  scratch = TMP_ALLOC_LIMBS (MAX_N);
+  max_b = numberof (mp_bases);
+
+  ASSERT_ALWAYS (max_b > 62);
+  ASSERT_ALWAYS (max_b < GMP_NUMB_MAX);
+
+  for (a = 2; a < max_b; ++a)
+    for (test = 0; test < count; ++test)
+      {
+	mp_size_t pn;
+	mp_limb_t exp;
+	mp_bitcnt_t res;
+
+	exp = gmp_urandomm_ui (rands, MAX_N);
+
+	pn = mpn_pow_1 (pp, &a, 1, exp, scratch);
+
+	res = mpn_sizeinbase (pp, pn, a) - 1;
+
+	if ((res < exp) || (res > exp + 1))
+	  {
+	    printf ("ERROR in test %d, base = %d, exp = %d, res = %d\n",
+		    test, (int) a, (int) exp, (int) res);
+	    abort();
+	  }
+
+	mpn_sub_1 (pp, pp, pn, CNST_LIMB(1));
+	pn -= pp[pn-1] == 0;
+
+	res = mpn_sizeinbase (pp, pn, a);
+
+	if ((res < exp) || (res - 1 > exp))
+	  {
+	    printf ("ERROR in -1 test %d, base = %d, exp = %d, res = %d\n",
+		    test, (int) a, (int) exp, (int) res);
+	    abort();
+	  }
+      }
+
+  TMP_FREE;
+  tests_end ();
+  return 0;
+}
diff --git a/third_party/gmp/tests/mpn/t-sqrlo.c b/third_party/gmp/tests/mpn/t-sqrlo.c
new file mode 100644
index 0000000..e9ab1e0
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-sqrlo.c
@@ -0,0 +1,129 @@
+/* Test for sqrlo function.
+
+Copyright 2009, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+/* Sizes are up to 2^SIZE_LOG limbs */
+#ifndef SIZE_LOG
+#define SIZE_LOG 10
+#endif
+
+#ifndef COUNT
+#define COUNT 10000
+#endif
+
+#define MAX_N (1L << SIZE_LOG)
+#define MIN_N (1)
+
+int
+main (int argc, char **argv)
+{
+  mp_ptr ap, refp, pp, scratch;
+  int count = COUNT;
+  int test;
+  gmp_randstate_ptr rands;
+  TMP_DECL;
+  TMP_MARK;
+
+  TESTS_REPS (count, argv, argc);
+
+  tests_start ();
+  rands = RANDS;
+
+#define mpn_sqrlo_itch(n) (0)
+
+  ap = TMP_ALLOC_LIMBS (MAX_N);
+  refp = TMP_ALLOC_LIMBS (MAX_N * 2);
+  pp = 1+TMP_ALLOC_LIMBS (MAX_N + 2);
+  scratch
+    = 1+TMP_ALLOC_LIMBS (mpn_sqrlo_itch (MAX_N) + 2);
+
+  for (test = 0; test < count; test++)
+    {
+      unsigned size_min;
+      unsigned size_range;
+      mp_size_t n;
+      mp_size_t itch;
+      mp_limb_t p_before, p_after, s_before, s_after;
+
+      for (size_min = 1; (1L << size_min) < MIN_N; size_min++)
+	;
+
+      /* We generate an in the MIN_N <= n <= (1 << size_range). */
+      size_range = size_min
+	+ gmp_urandomm_ui (rands, SIZE_LOG + 1 - size_min);
+
+      n = MIN_N
+	+ gmp_urandomm_ui (rands, (1L << size_range) + 1 - MIN_N);
+
+      mpn_random2 (ap, n);
+      mpn_random2 (pp-1, n + 2);
+      p_before = pp[-1];
+      p_after = pp[n];
+
+      itch = mpn_sqrlo_itch (n);
+      ASSERT_ALWAYS (itch <= mpn_sqrlo_itch (MAX_N));
+      mpn_random2 (scratch-1, itch+2);
+      s_before = scratch[-1];
+      s_after = scratch[itch];
+
+      mpn_sqrlo (pp, ap, n);
+      mpn_sqr (refp, ap, n);
+      if (pp[-1] != p_before || pp[n] != p_after
+	  || scratch[-1] != s_before || scratch[itch] != s_after
+	  || mpn_cmp (refp, pp, n) != 0)
+	{
+	  printf ("ERROR in test %d, n = %d",
+		  test, (int) n);
+	  if (pp[-1] != p_before)
+	    {
+	      printf ("before pp:"); mpn_dump (pp -1, 1);
+	      printf ("keep:   "); mpn_dump (&p_before, 1);
+	    }
+	  if (pp[n] != p_after)
+	    {
+	      printf ("after pp:"); mpn_dump (pp + n, 1);
+	      printf ("keep:   "); mpn_dump (&p_after, 1);
+	    }
+	  if (scratch[-1] != s_before)
+	    {
+	      printf ("before scratch:"); mpn_dump (scratch-1, 1);
+	      printf ("keep:   "); mpn_dump (&s_before, 1);
+	    }
+	  if (scratch[itch] != s_after)
+	    {
+	      printf ("after scratch:"); mpn_dump (scratch + itch, 1);
+	      printf ("keep:   "); mpn_dump (&s_after, 1);
+	    }
+	  mpn_dump (ap, n);
+	  mpn_dump (pp, n);
+	  mpn_dump (refp, n);
+
+	  abort();
+	}
+    }
+  TMP_FREE;
+  tests_end ();
+  return 0;
+}
diff --git a/third_party/gmp/tests/mpn/t-sqrmod_bnm1.c b/third_party/gmp/tests/mpn/t-sqrmod_bnm1.c
new file mode 100644
index 0000000..9f96e83
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-sqrmod_bnm1.c
@@ -0,0 +1,181 @@
+/* Test for sqrmod_bnm1 function.
+
+   Contributed to the GNU project by Marco Bodrato.
+
+Copyright 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+/* Sizes are up to 2^SIZE_LOG limbs */
+#ifndef SIZE_LOG
+#define SIZE_LOG 12
+#endif
+
+#ifndef COUNT
+#define COUNT 3000
+#endif
+
+#define MAX_N (1L << SIZE_LOG)
+#define MIN_N 1
+
+/*
+  Reference function for squaring modulo B^rn-1.
+
+  The result is expected to be ZERO if and only if one of the operand
+  already is. Otherwise the class [0] Mod(B^rn-1) is represented by
+  B^rn-1. This should not be a problem if sqrmod_bnm1 is used to
+  combine results and obtain a natural number when one knows in
+  advance that the final value is less than (B^rn-1).
+*/
+
+static void
+ref_sqrmod_bnm1 (mp_ptr rp, mp_size_t rn, mp_srcptr ap, mp_size_t an)
+{
+  mp_limb_t cy;
+
+  ASSERT (0 < an && an <= rn);
+
+  refmpn_mul (rp, ap, an, ap, an);
+  an *= 2;
+  if (an > rn) {
+    cy = mpn_add (rp, rp, rn, rp + rn, an - rn);
+    /* If cy == 1, then the value of rp is at most B^rn - 2, so there can
+     * be no overflow when adding in the carry. */
+    MPN_INCR_U (rp, rn, cy);
+  }
+}
+
+/*
+  Compare the result of the mpn_sqrmod_bnm1 function in the library
+  with the reference function above.
+*/
+
+int
+main (int argc, char **argv)
+{
+  mp_ptr ap, refp, pp, scratch;
+  int count = COUNT;
+  int test;
+  gmp_randstate_ptr rands;
+  TMP_DECL;
+  TMP_MARK;
+
+  TESTS_REPS (count, argv, argc);
+
+  tests_start ();
+  rands = RANDS;
+
+  ASSERT_ALWAYS (mpn_sqrmod_bnm1_next_size (MAX_N) == MAX_N);
+
+  ap = TMP_ALLOC_LIMBS (MAX_N);
+  refp = TMP_ALLOC_LIMBS (MAX_N * 4);
+  pp = 1+TMP_ALLOC_LIMBS (MAX_N + 2);
+  scratch
+    = 1+TMP_ALLOC_LIMBS (mpn_sqrmod_bnm1_itch (MAX_N, MAX_N) + 2);
+
+  for (test = 0; test < count; test++)
+    {
+      unsigned size_min;
+      unsigned size_range;
+      mp_size_t an,rn,n;
+      mp_size_t itch;
+      mp_limb_t p_before, p_after, s_before, s_after;
+
+      for (size_min = 1; (1L << size_min) < MIN_N; size_min++)
+	;
+
+      /* We generate an in the MIN_N <= n <= (1 << size_range). */
+      size_range = size_min
+	+ gmp_urandomm_ui (rands, SIZE_LOG + 1 - size_min);
+
+      n = MIN_N
+	+ gmp_urandomm_ui (rands, (1L << size_range) + 1 - MIN_N);
+      n = mpn_sqrmod_bnm1_next_size (n);
+
+      if (n == 1)
+	an = 1;
+      else
+	an = ((n+1) >> 1) + gmp_urandomm_ui (rands, (n+1) >> 1);
+
+      mpn_random2 (ap, an);
+
+      /* Sometime trigger the borderline conditions
+	 A = -1,0,+1 Mod(B^{n/2}+1).
+	 This only makes sense if there is at least a split, i.e. n is even. */
+      if ((test & 0x1f) == 1 && (n & 1) == 0) {
+	mp_size_t x;
+	MPN_COPY (ap, ap + (n >> 1), an - (n >> 1));
+	MPN_ZERO (ap + an - (n >> 1) , n - an);
+	x = (n == an) ? 0 : gmp_urandomm_ui (rands, n - an);
+	ap[x] += gmp_urandomm_ui (rands, 3) - 1;
+      }
+      rn = MIN(n, 2*an);
+      mpn_random2 (pp-1, rn + 2);
+      p_before = pp[-1];
+      p_after = pp[rn];
+
+      itch = mpn_sqrmod_bnm1_itch (n, an);
+      ASSERT_ALWAYS (itch <= mpn_sqrmod_bnm1_itch (MAX_N, MAX_N));
+      mpn_random2 (scratch-1, itch+2);
+      s_before = scratch[-1];
+      s_after = scratch[itch];
+
+      mpn_sqrmod_bnm1 (  pp, n, ap, an, scratch);
+      ref_sqrmod_bnm1 (refp, n, ap, an);
+      if (pp[-1] != p_before || pp[rn] != p_after
+	  || scratch[-1] != s_before || scratch[itch] != s_after
+	  || mpn_cmp (refp, pp, rn) != 0)
+	{
+	  printf ("ERROR in test %d, an = %d, n = %d\n",
+		  test, (int) an, (int) n);
+	  if (pp[-1] != p_before)
+	    {
+	      printf ("before pp:"); mpn_dump (pp -1, 1);
+	      printf ("keep:   "); mpn_dump (&p_before, 1);
+	    }
+	  if (pp[rn] != p_after)
+	    {
+	      printf ("after pp:"); mpn_dump (pp + rn, 1);
+	      printf ("keep:   "); mpn_dump (&p_after, 1);
+	    }
+	  if (scratch[-1] != s_before)
+	    {
+	      printf ("before scratch:"); mpn_dump (scratch-1, 1);
+	      printf ("keep:   "); mpn_dump (&s_before, 1);
+	    }
+	  if (scratch[itch] != s_after)
+	    {
+	      printf ("after scratch:"); mpn_dump (scratch + itch, 1);
+	      printf ("keep:   "); mpn_dump (&s_after, 1);
+	    }
+	  mpn_dump (ap, an);
+	  mpn_dump (pp, rn);
+	  mpn_dump (refp, rn);
+
+	  abort();
+	}
+    }
+  TMP_FREE;
+  tests_end ();
+  return 0;
+}
diff --git a/third_party/gmp/tests/mpn/t-toom2-sqr.c b/third_party/gmp/tests/mpn/t-toom2-sqr.c
new file mode 100644
index 0000000..a5cdcb5
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-toom2-sqr.c
@@ -0,0 +1,6 @@
+#define mpn_toomN_sqr mpn_toom2_sqr
+#define mpn_toomN_sqr_itch mpn_toom2_sqr_itch
+#define MIN_AN MPN_TOOM2_SQR_MINSIZE
+#define MAX_AN SQR_TOOM3_THRESHOLD
+
+#include "toom-sqr-shared.h"
diff --git a/third_party/gmp/tests/mpn/t-toom22.c b/third_party/gmp/tests/mpn/t-toom22.c
new file mode 100644
index 0000000..c9beed9
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-toom22.c
@@ -0,0 +1,10 @@
+#define mpn_toomMN_mul mpn_toom22_mul
+#define mpn_toomMN_mul_itch mpn_toom22_mul_itch
+#define MIN_AN MIN(MPN_TOOM22_MUL_MINSIZE,4)
+
+#define MIN_BN(an)				\
+  ((an) >= 2*MUL_TOOM22_THRESHOLD		\
+   ? (an) + 2 - MUL_TOOM22_THRESHOLD		\
+   : ((an)+1)/2 + 1 + (an & 1))
+
+#include "toom-shared.h"
diff --git a/third_party/gmp/tests/mpn/t-toom3-sqr.c b/third_party/gmp/tests/mpn/t-toom3-sqr.c
new file mode 100644
index 0000000..ccc3b99
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-toom3-sqr.c
@@ -0,0 +1,6 @@
+#define mpn_toomN_sqr mpn_toom3_sqr
+#define mpn_toomN_sqr_itch mpn_toom3_sqr_itch
+#define MIN_AN MAX(SQR_TOOM3_THRESHOLD,MPN_TOOM3_SQR_MINSIZE)
+#define MAX_AN SQR_TOOM4_THRESHOLD
+
+#include "toom-sqr-shared.h"
diff --git a/third_party/gmp/tests/mpn/t-toom32.c b/third_party/gmp/tests/mpn/t-toom32.c
new file mode 100644
index 0000000..e42745d
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-toom32.c
@@ -0,0 +1,8 @@
+#define mpn_toomMN_mul mpn_toom32_mul
+#define mpn_toomMN_mul_itch mpn_toom32_mul_itch
+
+#define MIN_AN 6
+#define MIN_BN(an) (((an) + 8) / (size_t) 3)
+#define MAX_BN(an) ((an) - 2)
+
+#include "toom-shared.h"
diff --git a/third_party/gmp/tests/mpn/t-toom33.c b/third_party/gmp/tests/mpn/t-toom33.c
new file mode 100644
index 0000000..7de82b2
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-toom33.c
@@ -0,0 +1,11 @@
+#define mpn_toomMN_mul mpn_toom33_mul
+#define mpn_toomMN_mul_itch mpn_toom33_mul_itch
+
+/* Smaller sizes not supported; may lead to recursive calls to
+   toom22_mul with invalid input size. */
+#define MIN_AN MUL_TOOM33_THRESHOLD
+#define MIN_BN(an) (1 + 2*(((an)+2)/(size_t) 3))
+
+#define COUNT 1000
+
+#include "toom-shared.h"
diff --git a/third_party/gmp/tests/mpn/t-toom4-sqr.c b/third_party/gmp/tests/mpn/t-toom4-sqr.c
new file mode 100644
index 0000000..ca14ab1
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-toom4-sqr.c
@@ -0,0 +1,6 @@
+#define mpn_toomN_sqr mpn_toom4_sqr
+#define mpn_toomN_sqr_itch mpn_toom4_sqr_itch
+#define MIN_AN MAX(SQR_TOOM3_THRESHOLD,MAX(SQR_TOOM4_THRESHOLD,MPN_TOOM4_SQR_MINSIZE))
+#define MAX_AN SQR_TOOM6_THRESHOLD
+
+#include "toom-sqr-shared.h"
diff --git a/third_party/gmp/tests/mpn/t-toom42.c b/third_party/gmp/tests/mpn/t-toom42.c
new file mode 100644
index 0000000..09a4a0c
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-toom42.c
@@ -0,0 +1,8 @@
+#define mpn_toomMN_mul mpn_toom42_mul
+#define mpn_toomMN_mul_itch mpn_toom42_mul_itch
+
+#define MIN_AN 10
+#define MIN_BN(an) (((an) + 7) >> 2)
+#define MAX_BN(an) ((2*(an)-5) / (size_t) 3)
+
+#include "toom-shared.h"
diff --git a/third_party/gmp/tests/mpn/t-toom43.c b/third_party/gmp/tests/mpn/t-toom43.c
new file mode 100644
index 0000000..224a45b
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-toom43.c
@@ -0,0 +1,8 @@
+#define mpn_toomMN_mul mpn_toom43_mul
+#define mpn_toomMN_mul_itch mpn_toom43_mul_itch
+
+#define MIN_AN 25
+#define MIN_BN(an) (1 + 2*(((an)+3) >> 2))
+#define MAX_BN(an) ((an)-3)
+
+#include "toom-shared.h"
diff --git a/third_party/gmp/tests/mpn/t-toom44.c b/third_party/gmp/tests/mpn/t-toom44.c
new file mode 100644
index 0000000..6c627e3
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-toom44.c
@@ -0,0 +1,11 @@
+#define mpn_toomMN_mul mpn_toom44_mul
+#define mpn_toomMN_mul_itch mpn_toom44_mul_itch
+
+/* Smaller sizes not supported; may lead to recursive calls to
+   toom22_mul or toom33_mul with invalid input size. */
+#define MIN_AN MUL_TOOM44_THRESHOLD
+#define MIN_BN(an) (1 + 3*(((an)+3)>>2))
+
+#define COUNT 1000
+
+#include "toom-shared.h"
diff --git a/third_party/gmp/tests/mpn/t-toom52.c b/third_party/gmp/tests/mpn/t-toom52.c
new file mode 100644
index 0000000..d3fb134
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-toom52.c
@@ -0,0 +1,8 @@
+#define mpn_toomMN_mul mpn_toom52_mul
+#define mpn_toomMN_mul_itch mpn_toom52_mul_itch
+
+#define MIN_AN 32
+#define MIN_BN(an) (((an) + 9) / (size_t) 5)
+#define MAX_BN(an) (((an) - 3) >> 1)
+
+#include "toom-shared.h"
diff --git a/third_party/gmp/tests/mpn/t-toom53.c b/third_party/gmp/tests/mpn/t-toom53.c
new file mode 100644
index 0000000..ddbf177
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-toom53.c
@@ -0,0 +1,8 @@
+#define mpn_toomMN_mul mpn_toom53_mul
+#define mpn_toomMN_mul_itch mpn_toom53_mul_itch
+
+#define MIN_AN 17
+#define MIN_BN(an) (1 + 2*(((an) + 4) / (size_t) 5))
+#define MAX_BN(an) ((3*(an) - 11) >> 2)
+
+#include "toom-shared.h"
diff --git a/third_party/gmp/tests/mpn/t-toom54.c b/third_party/gmp/tests/mpn/t-toom54.c
new file mode 100644
index 0000000..52a2bee
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-toom54.c
@@ -0,0 +1,8 @@
+#define mpn_toomMN_mul mpn_toom54_mul
+#define mpn_toomMN_mul_itch mpn_toom54_mul_itch
+
+#define MIN_AN 31
+#define MIN_BN(an) ((3*(an) + 32) / (size_t) 5)		/* 3/5 */
+#define MAX_BN(an) ((an) - 6)	                        /* 1/1 */
+
+#include "toom-shared.h"
diff --git a/third_party/gmp/tests/mpn/t-toom6-sqr.c b/third_party/gmp/tests/mpn/t-toom6-sqr.c
new file mode 100644
index 0000000..67d7a63
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-toom6-sqr.c
@@ -0,0 +1,8 @@
+#define mpn_toomN_sqr mpn_toom6_sqr
+#define mpn_toomN_sqr_itch mpn_toom6_sqr_itch
+#define MIN_AN MAX(SQR_TOOM3_THRESHOLD,MAX(SQR_TOOM4_THRESHOLD,MAX(SQR_TOOM6_THRESHOLD,MPN_TOOM6_SQR_MINSIZE)))
+#define MAX_AN SQR_TOOM8_THRESHOLD
+
+#define COUNT 250
+
+#include "toom-sqr-shared.h"
diff --git a/third_party/gmp/tests/mpn/t-toom62.c b/third_party/gmp/tests/mpn/t-toom62.c
new file mode 100644
index 0000000..1cb2aab
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-toom62.c
@@ -0,0 +1,8 @@
+#define mpn_toomMN_mul mpn_toom62_mul
+#define mpn_toomMN_mul_itch mpn_toom62_mul_itch
+
+#define MIN_AN 31
+#define MIN_BN(an) (((an) + 11) / (size_t) 6)
+#define MAX_BN(an) ((2*(an) - 7) / (size_t) 5)
+
+#include "toom-shared.h"
diff --git a/third_party/gmp/tests/mpn/t-toom63.c b/third_party/gmp/tests/mpn/t-toom63.c
new file mode 100644
index 0000000..d79165d
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-toom63.c
@@ -0,0 +1,8 @@
+#define mpn_toomMN_mul mpn_toom63_mul
+#define mpn_toomMN_mul_itch mpn_toom63_mul_itch
+
+#define MIN_AN 49
+#define MIN_BN(an) (2*(((an) + 23) / (size_t) 6))	/* 2/6 */
+#define MAX_BN(an) ((3*(an) - 23)  / (size_t) 5)	/* 3/5 */
+
+#include "toom-shared.h"
diff --git a/third_party/gmp/tests/mpn/t-toom6h.c b/third_party/gmp/tests/mpn/t-toom6h.c
new file mode 100644
index 0000000..5cca9fc
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-toom6h.c
@@ -0,0 +1,13 @@
+#define mpn_toomMN_mul mpn_toom6h_mul
+#define mpn_toomMN_mul_itch mpn_toom6h_mul_itch
+
+#define SIZE_LOG 11
+
+/* Smaller sizes not supported; may lead to recursive calls to
+   toom22_mul, toom33_mul, or toom44_mul with invalid input size. */
+#define MIN_AN MUL_TOOM6H_MIN
+#define MIN_BN(an) (MAX ((an*3)>>3, 46))
+
+#define COUNT 1000
+
+#include "toom-shared.h"
diff --git a/third_party/gmp/tests/mpn/t-toom8-sqr.c b/third_party/gmp/tests/mpn/t-toom8-sqr.c
new file mode 100644
index 0000000..0eee605
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-toom8-sqr.c
@@ -0,0 +1,8 @@
+#define mpn_toomN_sqr mpn_toom8_sqr
+#define mpn_toomN_sqr_itch mpn_toom8_sqr_itch
+#define MIN_AN MAX(SQR_TOOM3_THRESHOLD,MAX(SQR_TOOM4_THRESHOLD,MAX(SQR_TOOM6_THRESHOLD,MAX(SQR_TOOM8_THRESHOLD,MPN_TOOM8_SQR_MINSIZE))))
+#define MAX_AN SQR_FFT_THRESHOLD
+
+#define COUNT 250
+
+#include "toom-sqr-shared.h"
diff --git a/third_party/gmp/tests/mpn/t-toom8h.c b/third_party/gmp/tests/mpn/t-toom8h.c
new file mode 100644
index 0000000..b21344e
--- /dev/null
+++ b/third_party/gmp/tests/mpn/t-toom8h.c
@@ -0,0 +1,19 @@
+#define mpn_toomMN_mul mpn_toom8h_mul
+#define mpn_toomMN_mul_itch mpn_toom8h_mul_itch
+
+#define SIZE_LOG 11
+
+/* Smaller sizes not supported; may lead to recursive calls to
+   toom{22,33,44,6h}_mul with invalid input size. */
+#define MIN_AN MUL_TOOM8H_MIN
+
+#define MIN_BN(an)			 \
+(MAX(GMP_NUMB_BITS <=  9*3 ? (an*7)/ 9 : \
+     GMP_NUMB_BITS <= 10*3 ? (an*6)/10 : \
+     GMP_NUMB_BITS <= 11*3 ? (an*5)/11 : \
+     GMP_NUMB_BITS <= 12*3 ? (an*4)/12 : \
+     (an*4)/13, 86) )
+
+#define COUNT 1000
+
+#include "toom-shared.h"
diff --git a/third_party/gmp/tests/mpn/toom-shared.h b/third_party/gmp/tests/mpn/toom-shared.h
new file mode 100644
index 0000000..8188b00
--- /dev/null
+++ b/third_party/gmp/tests/mpn/toom-shared.h
@@ -0,0 +1,148 @@
+/* Test for various Toom functions.
+
+Copyright 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+/* Main file is expected to define mpn_toomMN_mul,
+ * mpn_toomMN_mul_itch, MIN_AN, MIN_BN(an), MAX_BN(an) and then
+ * include this file. */
+
+/* Sizes are up to 2^SIZE_LOG limbs */
+#ifndef SIZE_LOG
+#define SIZE_LOG 10
+#endif
+
+#ifndef COUNT
+#define COUNT 2000
+#endif
+
+#define MAX_AN (1L << SIZE_LOG)
+
+#ifndef MAX_BN
+#define MAX_BN(an) (an)
+#endif
+
+/* For general toomMN_mul, we need
+ *
+ * MIN_BN(an) = N + floor(((N-1)*an + M - N)/M)
+ *
+ * MAX_BN(an) = floor(N*(an-1)/(M-1)) - N + 1
+ */
+
+int
+main (int argc, char **argv)
+{
+  mp_ptr ap, bp, refp, pp, scratch;
+  int count = COUNT;
+  int test;
+  gmp_randstate_ptr rands;
+  TMP_DECL;
+  TMP_MARK;
+
+  TESTS_REPS (count, argv, argc);
+
+  tests_start ();
+  rands = RANDS;
+
+  ap = TMP_ALLOC_LIMBS (MAX_AN);
+  bp = TMP_ALLOC_LIMBS (MAX_BN(MAX_AN));
+  refp = TMP_ALLOC_LIMBS (MAX_AN + MAX_BN(MAX_AN));
+  pp = 1+TMP_ALLOC_LIMBS (MAX_AN + MAX_BN(MAX_AN)+2);
+  scratch
+    = 1+TMP_ALLOC_LIMBS (mpn_toomMN_mul_itch (MAX_AN, MAX_BN(MAX_AN))
+			 + 2);
+
+  for (test = 0; test < count; test++)
+    {
+      unsigned size_min;
+      unsigned size_range;
+      mp_size_t an, bn;
+      mp_size_t itch;
+      mp_limb_t p_before, p_after, s_before, s_after;
+
+      for (size_min = 1; (1L << size_min) < MIN_AN; size_min++)
+	;
+
+      /* We generate an in the MIN_AN <= an <= (1 << size_range). */
+      size_range = size_min
+	+ gmp_urandomm_ui (rands, SIZE_LOG + 1 - size_min);
+
+      an = MIN_AN
+	+ gmp_urandomm_ui (rands, (1L << size_range) + 1 - MIN_AN);
+      bn = MIN_BN(an)
+	+ gmp_urandomm_ui (rands, MAX_BN(an) + 1 - MIN_BN(an));
+
+      mpn_random2 (ap, an);
+      mpn_random2 (bp, bn);
+      mpn_random2 (pp-1, an + bn + 2);
+      p_before = pp[-1];
+      p_after = pp[an + bn];
+
+      itch = mpn_toomMN_mul_itch (an, bn);
+      ASSERT_ALWAYS (itch <= mpn_toomMN_mul_itch (MAX_AN, MAX_BN(MAX_AN)));
+      mpn_random2 (scratch-1, itch+2);
+      s_before = scratch[-1];
+      s_after = scratch[itch];
+
+      mpn_toomMN_mul (pp, ap, an, bp, bn, scratch);
+      refmpn_mul (refp, ap, an, bp, bn);
+      if (pp[-1] != p_before || pp[an + bn] != p_after
+	  || scratch[-1] != s_before || scratch[itch] != s_after
+	  || mpn_cmp (refp, pp, an + bn) != 0)
+	{
+	  printf ("ERROR in test %d, an = %d, bn = %d\n",
+		  test, (int) an, (int) bn);
+	  if (pp[-1] != p_before)
+	    {
+	      printf ("before pp:"); mpn_dump (pp -1, 1);
+	      printf ("keep:   "); mpn_dump (&p_before, 1);
+	    }
+	  if (pp[an + bn] != p_after)
+	    {
+	      printf ("after pp:"); mpn_dump (pp + an + bn, 1);
+	      printf ("keep:   "); mpn_dump (&p_after, 1);
+	    }
+	  if (scratch[-1] != s_before)
+	    {
+	      printf ("before scratch:"); mpn_dump (scratch-1, 1);
+	      printf ("keep:   "); mpn_dump (&s_before, 1);
+	    }
+	  if (scratch[itch] != s_after)
+	    {
+	      printf ("after scratch:"); mpn_dump (scratch + itch, 1);
+	      printf ("keep:   "); mpn_dump (&s_after, 1);
+	    }
+	  mpn_dump (ap, an);
+	  mpn_dump (bp, bn);
+	  mpn_dump (pp, an + bn);
+	  mpn_dump (refp, an + bn);
+
+	  abort();
+	}
+    }
+  TMP_FREE;
+
+  tests_end ();
+  return 0;
+}
diff --git a/third_party/gmp/tests/mpn/toom-sqr-shared.h b/third_party/gmp/tests/mpn/toom-sqr-shared.h
new file mode 100644
index 0000000..e57ac8d
--- /dev/null
+++ b/third_party/gmp/tests/mpn/toom-sqr-shared.h
@@ -0,0 +1,117 @@
+/* Test for various Toom squaring functions.
+
+Copyright 2009, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+/* Main file is expected to define mpn_toomN_mul, mpn_toomN_sqr_itch,
+ * MIN_AN, MAX_AN and then include this file. */
+
+#ifndef COUNT
+#define COUNT 2000
+#endif
+
+int
+main (int argc, char **argv)
+{
+  mp_ptr ap, refp, pp, scratch;
+  int count = COUNT;
+  int test;
+  gmp_randstate_ptr rands;
+  TMP_DECL;
+  TMP_MARK;
+
+  TESTS_REPS (count, argv, argc);
+
+  tests_start ();
+
+  if (MAX_AN > MIN_AN) {
+    rands = RANDS;
+
+    ap = TMP_ALLOC_LIMBS (MAX_AN);
+    refp = TMP_ALLOC_LIMBS (MAX_AN * 2);
+    pp = 1 + TMP_ALLOC_LIMBS (MAX_AN * 2 + 2);
+    scratch
+      = 1+TMP_ALLOC_LIMBS (mpn_toomN_sqr_itch (MAX_AN) + 2);
+
+    for (test = 0; test < count; test++)
+      {
+	mp_size_t an;
+	mp_size_t itch;
+	mp_limb_t p_before, p_after, s_before, s_after;
+
+	an = MIN_AN
+	  + gmp_urandomm_ui (rands, MAX_AN - MIN_AN);
+
+	mpn_random2 (ap, an);
+	mpn_random2 (pp-1, an * 2 + 2);
+	p_before = pp[-1];
+	p_after = pp[an * 2];
+
+	itch = mpn_toomN_sqr_itch (an);
+	ASSERT_ALWAYS (itch <= mpn_toomN_sqr_itch (MAX_AN));
+	mpn_random2 (scratch-1, itch+2);
+	s_before = scratch[-1];
+	s_after = scratch[itch];
+
+	mpn_toomN_sqr (pp, ap, an, scratch);
+	refmpn_mul (refp, ap, an, ap, an);
+	if (pp[-1] != p_before || pp[an * 2] != p_after
+	    || scratch[-1] != s_before || scratch[itch] != s_after
+	    || mpn_cmp (refp, pp, an * 2) != 0)
+	  {
+	    printf ("ERROR in test %d, an = %d\n",
+		    test, (int) an);
+	    if (pp[-1] != p_before)
+	      {
+		printf ("before pp:"); mpn_dump (pp -1, 1);
+		printf ("keep:   "); mpn_dump (&p_before, 1);
+	      }
+	    if (pp[an * 2] != p_after)
+	      {
+		printf ("after pp:"); mpn_dump (pp + an * 2, 1);
+		printf ("keep:   "); mpn_dump (&p_after, 1);
+	      }
+	    if (scratch[-1] != s_before)
+	      {
+		printf ("before scratch:"); mpn_dump (scratch-1, 1);
+		printf ("keep:   "); mpn_dump (&s_before, 1);
+	      }
+	    if (scratch[itch] != s_after)
+	      {
+		printf ("after scratch:"); mpn_dump (scratch + itch, 1);
+		printf ("keep:   "); mpn_dump (&s_after, 1);
+	      }
+	    mpn_dump (ap, an);
+	    mpn_dump (pp, an * 2);
+	    mpn_dump (refp, an * 2);
+
+	    abort();
+	  }
+      }
+    TMP_FREE;
+  }
+
+  tests_end ();
+  return 0;
+}
diff --git a/third_party/gmp/tests/mpq/Makefile.am b/third_party/gmp/tests/mpq/Makefile.am
new file mode 100644
index 0000000..e12e60c
--- /dev/null
+++ b/third_party/gmp/tests/mpq/Makefile.am
@@ -0,0 +1,35 @@
+## Process this file with automake to generate Makefile.in
+
+# Copyright 1996, 1999-2002, 2012, 2015 Free Software Foundation, Inc.
+#
+# This file is part of the GNU MP Library test suite.
+#
+# The GNU MP Library test suite is free software; you can redistribute it
+# and/or modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 3 of the License,
+# or (at your option) any later version.
+#
+# The GNU MP Library test suite is distributed in the hope that it will be
+# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.
+
+
+AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/tests
+AM_LDFLAGS = -no-install
+LDADD = $(top_builddir)/tests/libtests.la $(top_builddir)/libgmp.la
+
+check_PROGRAMS = t-aors t-cmp t-cmp_ui t-cmp_si t-equal t-get_d t-get_str \
+  t-inp_str t-inv t-md_2exp t-set_f t-set_str io reuse t-cmp_z
+TESTS = $(check_PROGRAMS)
+
+# Temporary files used by the tests.  Removed automatically if the tests
+# pass, but ensure they're cleaned if they fail.
+#
+CLEANFILES = *.tmp
+
+$(top_builddir)/tests/libtests.la:
+	cd $(top_builddir)/tests; $(MAKE) $(AM_MAKEFLAGS) libtests.la
diff --git a/third_party/gmp/tests/mpq/Makefile.in b/third_party/gmp/tests/mpq/Makefile.in
new file mode 100644
index 0000000..d6279ab
--- /dev/null
+++ b/third_party/gmp/tests/mpq/Makefile.in
@@ -0,0 +1,1241 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Copyright 1996, 1999-2002, 2012, 2015 Free Software Foundation, Inc.
+#
+# This file is part of the GNU MP Library test suite.
+#
+# The GNU MP Library test suite is free software; you can redistribute it
+# and/or modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 3 of the License,
+# or (at your option) any later version.
+#
+# The GNU MP Library test suite is distributed in the hope that it will be
+# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+check_PROGRAMS = t-aors$(EXEEXT) t-cmp$(EXEEXT) t-cmp_ui$(EXEEXT) \
+	t-cmp_si$(EXEEXT) t-equal$(EXEEXT) t-get_d$(EXEEXT) \
+	t-get_str$(EXEEXT) t-inp_str$(EXEEXT) t-inv$(EXEEXT) \
+	t-md_2exp$(EXEEXT) t-set_f$(EXEEXT) t-set_str$(EXEEXT) \
+	io$(EXEEXT) reuse$(EXEEXT) t-cmp_z$(EXEEXT)
+subdir = tests/mpq
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+io_SOURCES = io.c
+io_OBJECTS = io.$(OBJEXT)
+io_LDADD = $(LDADD)
+io_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+reuse_SOURCES = reuse.c
+reuse_OBJECTS = reuse.$(OBJEXT)
+reuse_LDADD = $(LDADD)
+reuse_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_aors_SOURCES = t-aors.c
+t_aors_OBJECTS = t-aors.$(OBJEXT)
+t_aors_LDADD = $(LDADD)
+t_aors_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_cmp_SOURCES = t-cmp.c
+t_cmp_OBJECTS = t-cmp.$(OBJEXT)
+t_cmp_LDADD = $(LDADD)
+t_cmp_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_cmp_si_SOURCES = t-cmp_si.c
+t_cmp_si_OBJECTS = t-cmp_si.$(OBJEXT)
+t_cmp_si_LDADD = $(LDADD)
+t_cmp_si_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_cmp_ui_SOURCES = t-cmp_ui.c
+t_cmp_ui_OBJECTS = t-cmp_ui.$(OBJEXT)
+t_cmp_ui_LDADD = $(LDADD)
+t_cmp_ui_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_cmp_z_SOURCES = t-cmp_z.c
+t_cmp_z_OBJECTS = t-cmp_z.$(OBJEXT)
+t_cmp_z_LDADD = $(LDADD)
+t_cmp_z_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_equal_SOURCES = t-equal.c
+t_equal_OBJECTS = t-equal.$(OBJEXT)
+t_equal_LDADD = $(LDADD)
+t_equal_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_get_d_SOURCES = t-get_d.c
+t_get_d_OBJECTS = t-get_d.$(OBJEXT)
+t_get_d_LDADD = $(LDADD)
+t_get_d_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_get_str_SOURCES = t-get_str.c
+t_get_str_OBJECTS = t-get_str.$(OBJEXT)
+t_get_str_LDADD = $(LDADD)
+t_get_str_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_inp_str_SOURCES = t-inp_str.c
+t_inp_str_OBJECTS = t-inp_str.$(OBJEXT)
+t_inp_str_LDADD = $(LDADD)
+t_inp_str_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_inv_SOURCES = t-inv.c
+t_inv_OBJECTS = t-inv.$(OBJEXT)
+t_inv_LDADD = $(LDADD)
+t_inv_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_md_2exp_SOURCES = t-md_2exp.c
+t_md_2exp_OBJECTS = t-md_2exp.$(OBJEXT)
+t_md_2exp_LDADD = $(LDADD)
+t_md_2exp_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_set_f_SOURCES = t-set_f.c
+t_set_f_OBJECTS = t-set_f.$(OBJEXT)
+t_set_f_LDADD = $(LDADD)
+t_set_f_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_set_str_SOURCES = t-set_str.c
+t_set_str_OBJECTS = t-set_str.$(OBJEXT)
+t_set_str_LDADD = $(LDADD)
+t_set_str_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp =
+am__depfiles_maybe =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+SOURCES = io.c reuse.c t-aors.c t-cmp.c t-cmp_si.c t-cmp_ui.c \
+	t-cmp_z.c t-equal.c t-get_d.c t-get_str.c t-inp_str.c t-inv.c \
+	t-md_2exp.c t-set_f.c t-set_str.c
+DIST_SOURCES = io.c reuse.c t-aors.c t-cmp.c t-cmp_si.c t-cmp_ui.c \
+	t-cmp_z.c t-equal.c t-get_d.c t-get_str.c t-inp_str.c t-inv.c \
+	t-md_2exp.c t-set_f.c t-set_str.c
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__tty_colors_dummy = \
+  mgn= red= grn= lgn= blu= brg= std=; \
+  am__color_tests=no
+am__tty_colors = { \
+  $(am__tty_colors_dummy); \
+  if test "X$(AM_COLOR_TESTS)" = Xno; then \
+    am__color_tests=no; \
+  elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+    am__color_tests=yes; \
+  elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+    am__color_tests=yes; \
+  fi; \
+  if test $$am__color_tests = yes; then \
+    red=''; \
+    grn=''; \
+    lgn=''; \
+    blu=''; \
+    mgn=''; \
+    brg=''; \
+    std=''; \
+  fi; \
+}
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+  test -z "$$files" \
+    || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+    || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+         $(am__cd) "$$dir" && rm -f $$files; }; \
+  }
+am__recheck_rx = ^[ 	]*:recheck:[ 	]*
+am__global_test_result_rx = ^[ 	]*:global-test-result:[ 	]*
+am__copy_in_global_log_rx = ^[ 	]*:copy-in-global-log:[ 	]*
+# A command that, given a newline-separated list of test names on the
+# standard input, print the name of the tests that are to be re-run
+# upon "make recheck".
+am__list_recheck_tests = $(AWK) '{ \
+  recheck = 1; \
+  while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+    { \
+      if (rc < 0) \
+        { \
+          if ((getline line2 < ($$0 ".log")) < 0) \
+	    recheck = 0; \
+          break; \
+        } \
+      else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \
+        { \
+          recheck = 0; \
+          break; \
+        } \
+      else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \
+        { \
+          break; \
+        } \
+    }; \
+  if (recheck) \
+    print $$0; \
+  close ($$0 ".trs"); \
+  close ($$0 ".log"); \
+}'
+# A command that, given a newline-separated list of test names on the
+# standard input, create the global log from their .trs and .log files.
+am__create_global_log = $(AWK) ' \
+function fatal(msg) \
+{ \
+  print "fatal: making $@: " msg | "cat >&2"; \
+  exit 1; \
+} \
+function rst_section(header) \
+{ \
+  print header; \
+  len = length(header); \
+  for (i = 1; i <= len; i = i + 1) \
+    printf "="; \
+  printf "\n\n"; \
+} \
+{ \
+  copy_in_global_log = 1; \
+  global_test_result = "RUN"; \
+  while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+    { \
+      if (rc < 0) \
+         fatal("failed to read from " $$0 ".trs"); \
+      if (line ~ /$(am__global_test_result_rx)/) \
+        { \
+          sub("$(am__global_test_result_rx)", "", line); \
+          sub("[ 	]*$$", "", line); \
+          global_test_result = line; \
+        } \
+      else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \
+        copy_in_global_log = 0; \
+    }; \
+  if (copy_in_global_log) \
+    { \
+      rst_section(global_test_result ": " $$0); \
+      while ((rc = (getline line < ($$0 ".log"))) != 0) \
+      { \
+        if (rc < 0) \
+          fatal("failed to read from " $$0 ".log"); \
+        print line; \
+      }; \
+      printf "\n"; \
+    }; \
+  close ($$0 ".trs"); \
+  close ($$0 ".log"); \
+}'
+# Restructured Text title.
+am__rst_title = { sed 's/.*/   &   /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; }
+# Solaris 10 'make', and several other traditional 'make' implementations,
+# pass "-e" to $(SHELL), and POSIX 2008 even requires this.  Work around it
+# by disabling -e (using the XSI extension "set +e") if it's set.
+am__sh_e_setup = case $$- in *e*) set +e;; esac
+# Default flags passed to test drivers.
+am__common_driver_flags = \
+  --color-tests "$$am__color_tests" \
+  --enable-hard-errors "$$am__enable_hard_errors" \
+  --expect-failure "$$am__expect_failure"
+# To be inserted before the command running the test.  Creates the
+# directory for the log if needed.  Stores in $dir the directory
+# containing $f, in $tst the test, in $log the log.  Executes the
+# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and
+# passes TESTS_ENVIRONMENT.  Set up options for the wrapper that
+# will run the test scripts (or their associated LOG_COMPILER, if
+# thy have one).
+am__check_pre = \
+$(am__sh_e_setup);					\
+$(am__vpath_adj_setup) $(am__vpath_adj)			\
+$(am__tty_colors);					\
+srcdir=$(srcdir); export srcdir;			\
+case "$@" in						\
+  */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;;	\
+    *) am__odir=.;; 					\
+esac;							\
+test "x$$am__odir" = x"." || test -d "$$am__odir" 	\
+  || $(MKDIR_P) "$$am__odir" || exit $$?;		\
+if test -f "./$$f"; then dir=./;			\
+elif test -f "$$f"; then dir=;				\
+else dir="$(srcdir)/"; fi;				\
+tst=$$dir$$f; log='$@'; 				\
+if test -n '$(DISABLE_HARD_ERRORS)'; then		\
+  am__enable_hard_errors=no; 				\
+else							\
+  am__enable_hard_errors=yes; 				\
+fi; 							\
+case " $(XFAIL_TESTS) " in				\
+  *[\ \	]$$f[\ \	]* | *[\ \	]$$dir$$f[\ \	]*) \
+    am__expect_failure=yes;;				\
+  *)							\
+    am__expect_failure=no;;				\
+esac; 							\
+$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT)
+# A shell command to get the names of the tests scripts with any registered
+# extension removed (i.e., equivalently, the names of the test logs, with
+# the '.log' extension removed).  The result is saved in the shell variable
+# '$bases'.  This honors runtime overriding of TESTS and TEST_LOGS.  Sadly,
+# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)",
+# since that might cause problem with VPATH rewrites for suffix-less tests.
+# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'.
+am__set_TESTS_bases = \
+  bases='$(TEST_LOGS)'; \
+  bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \
+  bases=`echo $$bases`
+RECHECK_LOGS = $(TEST_LOGS)
+AM_RECURSIVE_TARGETS = check recheck
+TEST_SUITE_LOG = test-suite.log
+TEST_EXTENSIONS = @EXEEXT@ .test
+LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS)
+am__set_b = \
+  case '$@' in \
+    */*) \
+      case '$*' in \
+        */*) b='$*';; \
+          *) b=`echo '$@' | sed 's/\.log$$//'`; \
+       esac;; \
+    *) \
+      b='$*';; \
+  esac
+am__test_logs1 = $(TESTS:=.log)
+am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log)
+TEST_LOGS = $(am__test_logs2:.test.log=.log)
+TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \
+	$(TEST_LOG_FLAGS)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/test-driver
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ABI = @ABI@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+ASMFLAGS = @ASMFLAGS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CALLING_CONVENTIONS_OBJS = @CALLING_CONVENTIONS_OBJS@
+CC = @CC@
+CCAS = @CCAS@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPP_FOR_BUILD = @CPP_FOR_BUILD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFN_LONG_LONG_LIMB = @DEFN_LONG_LONG_LIMB@
+DEFS = @DEFS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@
+FGREP = @FGREP@
+GMP_LDFLAGS = @GMP_LDFLAGS@
+GMP_LIMB_BITS = @GMP_LIMB_BITS@
+GMP_NAIL_BITS = @GMP_NAIL_BITS@
+GREP = @GREP@
+HAVE_CLOCK_01 = @HAVE_CLOCK_01@
+HAVE_CPUTIME_01 = @HAVE_CPUTIME_01@
+HAVE_GETRUSAGE_01 = @HAVE_GETRUSAGE_01@
+HAVE_GETTIMEOFDAY_01 = @HAVE_GETTIMEOFDAY_01@
+HAVE_HOST_CPU_FAMILY_power = @HAVE_HOST_CPU_FAMILY_power@
+HAVE_HOST_CPU_FAMILY_powerpc = @HAVE_HOST_CPU_FAMILY_powerpc@
+HAVE_SIGACTION_01 = @HAVE_SIGACTION_01@
+HAVE_SIGALTSTACK_01 = @HAVE_SIGALTSTACK_01@
+HAVE_SIGSTACK_01 = @HAVE_SIGSTACK_01@
+HAVE_STACK_T_01 = @HAVE_STACK_T_01@
+HAVE_SYS_RESOURCE_H_01 = @HAVE_SYS_RESOURCE_H_01@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCURSES = @LIBCURSES@
+LIBGMPXX_LDFLAGS = @LIBGMPXX_LDFLAGS@
+LIBGMP_DLL = @LIBGMP_DLL@
+LIBGMP_LDFLAGS = @LIBGMP_LDFLAGS@
+LIBM = @LIBM@
+LIBM_FOR_BUILD = @LIBM_FOR_BUILD@
+LIBOBJS = @LIBOBJS@
+LIBREADLINE = @LIBREADLINE@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+M4 = @M4@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPEED_CYCLECOUNTER_OBJ = @SPEED_CYCLECOUNTER_OBJ@
+STRIP = @STRIP@
+TAL_OBJECT = @TAL_OBJECT@
+TUNE_LIBS = @TUNE_LIBS@
+TUNE_SQR_OBJ = @TUNE_SQR_OBJ@
+U_FOR_BUILD = @U_FOR_BUILD@
+VERSION = @VERSION@
+WITH_READLINE_01 = @WITH_READLINE_01@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__leading_dot = @am__leading_dot@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gmp_srclinks = @gmp_srclinks@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+mpn_objects = @mpn_objects@
+mpn_objs_in_libgmp = @mpn_objs_in_libgmp@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/tests
+AM_LDFLAGS = -no-install
+LDADD = $(top_builddir)/tests/libtests.la $(top_builddir)/libgmp.la
+TESTS = $(check_PROGRAMS)
+
+# Temporary files used by the tests.  Removed automatically if the tests
+# pass, but ensure they're cleaned if they fail.
+#
+CLEANFILES = *.tmp
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .log .o .obj .test .test$(EXEEXT) .trs
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu --ignore-deps tests/mpq/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu --ignore-deps tests/mpq/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-checkPROGRAMS:
+	@list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
+	echo " rm -f" $$list; \
+	rm -f $$list || exit $$?; \
+	test -n "$(EXEEXT)" || exit 0; \
+	list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+	echo " rm -f" $$list; \
+	rm -f $$list
+
+io$(EXEEXT): $(io_OBJECTS) $(io_DEPENDENCIES) $(EXTRA_io_DEPENDENCIES) 
+	@rm -f io$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(io_OBJECTS) $(io_LDADD) $(LIBS)
+
+reuse$(EXEEXT): $(reuse_OBJECTS) $(reuse_DEPENDENCIES) $(EXTRA_reuse_DEPENDENCIES) 
+	@rm -f reuse$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(reuse_OBJECTS) $(reuse_LDADD) $(LIBS)
+
+t-aors$(EXEEXT): $(t_aors_OBJECTS) $(t_aors_DEPENDENCIES) $(EXTRA_t_aors_DEPENDENCIES) 
+	@rm -f t-aors$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_aors_OBJECTS) $(t_aors_LDADD) $(LIBS)
+
+t-cmp$(EXEEXT): $(t_cmp_OBJECTS) $(t_cmp_DEPENDENCIES) $(EXTRA_t_cmp_DEPENDENCIES) 
+	@rm -f t-cmp$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_cmp_OBJECTS) $(t_cmp_LDADD) $(LIBS)
+
+t-cmp_si$(EXEEXT): $(t_cmp_si_OBJECTS) $(t_cmp_si_DEPENDENCIES) $(EXTRA_t_cmp_si_DEPENDENCIES) 
+	@rm -f t-cmp_si$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_cmp_si_OBJECTS) $(t_cmp_si_LDADD) $(LIBS)
+
+t-cmp_ui$(EXEEXT): $(t_cmp_ui_OBJECTS) $(t_cmp_ui_DEPENDENCIES) $(EXTRA_t_cmp_ui_DEPENDENCIES) 
+	@rm -f t-cmp_ui$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_cmp_ui_OBJECTS) $(t_cmp_ui_LDADD) $(LIBS)
+
+t-cmp_z$(EXEEXT): $(t_cmp_z_OBJECTS) $(t_cmp_z_DEPENDENCIES) $(EXTRA_t_cmp_z_DEPENDENCIES) 
+	@rm -f t-cmp_z$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_cmp_z_OBJECTS) $(t_cmp_z_LDADD) $(LIBS)
+
+t-equal$(EXEEXT): $(t_equal_OBJECTS) $(t_equal_DEPENDENCIES) $(EXTRA_t_equal_DEPENDENCIES) 
+	@rm -f t-equal$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_equal_OBJECTS) $(t_equal_LDADD) $(LIBS)
+
+t-get_d$(EXEEXT): $(t_get_d_OBJECTS) $(t_get_d_DEPENDENCIES) $(EXTRA_t_get_d_DEPENDENCIES) 
+	@rm -f t-get_d$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_get_d_OBJECTS) $(t_get_d_LDADD) $(LIBS)
+
+t-get_str$(EXEEXT): $(t_get_str_OBJECTS) $(t_get_str_DEPENDENCIES) $(EXTRA_t_get_str_DEPENDENCIES) 
+	@rm -f t-get_str$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_get_str_OBJECTS) $(t_get_str_LDADD) $(LIBS)
+
+t-inp_str$(EXEEXT): $(t_inp_str_OBJECTS) $(t_inp_str_DEPENDENCIES) $(EXTRA_t_inp_str_DEPENDENCIES) 
+	@rm -f t-inp_str$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_inp_str_OBJECTS) $(t_inp_str_LDADD) $(LIBS)
+
+t-inv$(EXEEXT): $(t_inv_OBJECTS) $(t_inv_DEPENDENCIES) $(EXTRA_t_inv_DEPENDENCIES) 
+	@rm -f t-inv$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_inv_OBJECTS) $(t_inv_LDADD) $(LIBS)
+
+t-md_2exp$(EXEEXT): $(t_md_2exp_OBJECTS) $(t_md_2exp_DEPENDENCIES) $(EXTRA_t_md_2exp_DEPENDENCIES) 
+	@rm -f t-md_2exp$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_md_2exp_OBJECTS) $(t_md_2exp_LDADD) $(LIBS)
+
+t-set_f$(EXEEXT): $(t_set_f_OBJECTS) $(t_set_f_DEPENDENCIES) $(EXTRA_t_set_f_DEPENDENCIES) 
+	@rm -f t-set_f$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_set_f_OBJECTS) $(t_set_f_LDADD) $(LIBS)
+
+t-set_str$(EXEEXT): $(t_set_str_OBJECTS) $(t_set_str_DEPENDENCIES) $(EXTRA_t_set_str_DEPENDENCIES) 
+	@rm -f t-set_str$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_set_str_OBJECTS) $(t_set_str_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+.c.o:
+	$(AM_V_CC)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+	$(AM_V_CC)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+	$(AM_V_CC)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+# Recover from deleted '.trs' file; this should ensure that
+# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create
+# both 'foo.log' and 'foo.trs'.  Break the recipe in two subshells
+# to avoid problems with "make -n".
+.log.trs:
+	rm -f $< $@
+	$(MAKE) $(AM_MAKEFLAGS) $<
+
+# Leading 'am--fnord' is there to ensure the list of targets does not
+# expand to empty, as could happen e.g. with make check TESTS=''.
+am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck)
+am--force-recheck:
+	@:
+
+$(TEST_SUITE_LOG): $(TEST_LOGS)
+	@$(am__set_TESTS_bases); \
+	am__f_ok () { test -f "$$1" && test -r "$$1"; }; \
+	redo_bases=`for i in $$bases; do \
+	              am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \
+	            done`; \
+	if test -n "$$redo_bases"; then \
+	  redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \
+	  redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \
+	  if $(am__make_dryrun); then :; else \
+	    rm -f $$redo_logs && rm -f $$redo_results || exit 1; \
+	  fi; \
+	fi; \
+	if test -n "$$am__remaking_logs"; then \
+	  echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \
+	       "recursion detected" >&2; \
+	elif test -n "$$redo_logs"; then \
+	  am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \
+	fi; \
+	if $(am__make_dryrun); then :; else \
+	  st=0;  \
+	  errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \
+	  for i in $$redo_bases; do \
+	    test -f $$i.trs && test -r $$i.trs \
+	      || { echo "$$errmsg $$i.trs" >&2; st=1; }; \
+	    test -f $$i.log && test -r $$i.log \
+	      || { echo "$$errmsg $$i.log" >&2; st=1; }; \
+	  done; \
+	  test $$st -eq 0 || exit 1; \
+	fi
+	@$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \
+	ws='[ 	]'; \
+	results=`for b in $$bases; do echo $$b.trs; done`; \
+	test -n "$$results" || results=/dev/null; \
+	all=`  grep "^$$ws*:test-result:"           $$results | wc -l`; \
+	pass=` grep "^$$ws*:test-result:$$ws*PASS"  $$results | wc -l`; \
+	fail=` grep "^$$ws*:test-result:$$ws*FAIL"  $$results | wc -l`; \
+	skip=` grep "^$$ws*:test-result:$$ws*SKIP"  $$results | wc -l`; \
+	xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \
+	xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \
+	error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \
+	if test `expr $$fail + $$xpass + $$error` -eq 0; then \
+	  success=true; \
+	else \
+	  success=false; \
+	fi; \
+	br='==================='; br=$$br$$br$$br$$br; \
+	result_count () \
+	{ \
+	    if test x"$$1" = x"--maybe-color"; then \
+	      maybe_colorize=yes; \
+	    elif test x"$$1" = x"--no-color"; then \
+	      maybe_colorize=no; \
+	    else \
+	      echo "$@: invalid 'result_count' usage" >&2; exit 4; \
+	    fi; \
+	    shift; \
+	    desc=$$1 count=$$2; \
+	    if test $$maybe_colorize = yes && test $$count -gt 0; then \
+	      color_start=$$3 color_end=$$std; \
+	    else \
+	      color_start= color_end=; \
+	    fi; \
+	    echo "$${color_start}# $$desc $$count$${color_end}"; \
+	}; \
+	create_testsuite_report () \
+	{ \
+	  result_count $$1 "TOTAL:" $$all   "$$brg"; \
+	  result_count $$1 "PASS: " $$pass  "$$grn"; \
+	  result_count $$1 "SKIP: " $$skip  "$$blu"; \
+	  result_count $$1 "XFAIL:" $$xfail "$$lgn"; \
+	  result_count $$1 "FAIL: " $$fail  "$$red"; \
+	  result_count $$1 "XPASS:" $$xpass "$$red"; \
+	  result_count $$1 "ERROR:" $$error "$$mgn"; \
+	}; \
+	{								\
+	  echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" |	\
+	    $(am__rst_title);						\
+	  create_testsuite_report --no-color;				\
+	  echo;								\
+	  echo ".. contents:: :depth: 2";				\
+	  echo;								\
+	  for b in $$bases; do echo $$b; done				\
+	    | $(am__create_global_log);					\
+	} >$(TEST_SUITE_LOG).tmp || exit 1;				\
+	mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG);			\
+	if $$success; then						\
+	  col="$$grn";							\
+	 else								\
+	  col="$$red";							\
+	  test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG);		\
+	fi;								\
+	echo "$${col}$$br$${std}"; 					\
+	echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}";	\
+	echo "$${col}$$br$${std}"; 					\
+	create_testsuite_report --maybe-color;				\
+	echo "$$col$$br$$std";						\
+	if $$success; then :; else					\
+	  echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}";		\
+	  if test -n "$(PACKAGE_BUGREPORT)"; then			\
+	    echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}";	\
+	  fi;								\
+	  echo "$$col$$br$$std";					\
+	fi;								\
+	$$success || exit 1
+
+check-TESTS:
+	@list='$(RECHECK_LOGS)';           test -z "$$list" || rm -f $$list
+	@list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list
+	@test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+	@set +e; $(am__set_TESTS_bases); \
+	log_list=`for i in $$bases; do echo $$i.log; done`; \
+	trs_list=`for i in $$bases; do echo $$i.trs; done`; \
+	log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \
+	$(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \
+	exit $$?;
+recheck: all $(check_PROGRAMS)
+	@test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+	@set +e; $(am__set_TESTS_bases); \
+	bases=`for i in $$bases; do echo $$i; done \
+	         | $(am__list_recheck_tests)` || exit 1; \
+	log_list=`for i in $$bases; do echo $$i.log; done`; \
+	log_list=`echo $$log_list`; \
+	$(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \
+	        am__force_recheck=am--force-recheck \
+	        TEST_LOGS="$$log_list"; \
+	exit $$?
+t-aors.log: t-aors$(EXEEXT)
+	@p='t-aors$(EXEEXT)'; \
+	b='t-aors'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-cmp.log: t-cmp$(EXEEXT)
+	@p='t-cmp$(EXEEXT)'; \
+	b='t-cmp'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-cmp_ui.log: t-cmp_ui$(EXEEXT)
+	@p='t-cmp_ui$(EXEEXT)'; \
+	b='t-cmp_ui'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-cmp_si.log: t-cmp_si$(EXEEXT)
+	@p='t-cmp_si$(EXEEXT)'; \
+	b='t-cmp_si'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-equal.log: t-equal$(EXEEXT)
+	@p='t-equal$(EXEEXT)'; \
+	b='t-equal'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-get_d.log: t-get_d$(EXEEXT)
+	@p='t-get_d$(EXEEXT)'; \
+	b='t-get_d'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-get_str.log: t-get_str$(EXEEXT)
+	@p='t-get_str$(EXEEXT)'; \
+	b='t-get_str'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-inp_str.log: t-inp_str$(EXEEXT)
+	@p='t-inp_str$(EXEEXT)'; \
+	b='t-inp_str'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-inv.log: t-inv$(EXEEXT)
+	@p='t-inv$(EXEEXT)'; \
+	b='t-inv'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-md_2exp.log: t-md_2exp$(EXEEXT)
+	@p='t-md_2exp$(EXEEXT)'; \
+	b='t-md_2exp'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-set_f.log: t-set_f$(EXEEXT)
+	@p='t-set_f$(EXEEXT)'; \
+	b='t-set_f'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-set_str.log: t-set_str$(EXEEXT)
+	@p='t-set_str$(EXEEXT)'; \
+	b='t-set_str'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+io.log: io$(EXEEXT)
+	@p='io$(EXEEXT)'; \
+	b='io'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+reuse.log: reuse$(EXEEXT)
+	@p='reuse$(EXEEXT)'; \
+	b='reuse'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-cmp_z.log: t-cmp_z$(EXEEXT)
+	@p='t-cmp_z$(EXEEXT)'; \
+	b='t-cmp_z'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+.test.log:
+	@p='$<'; \
+	$(am__set_b); \
+	$(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+@am__EXEEXT_TRUE@.test$(EXEEXT).log:
+@am__EXEEXT_TRUE@	@p='$<'; \
+@am__EXEEXT_TRUE@	$(am__set_b); \
+@am__EXEEXT_TRUE@	$(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+@am__EXEEXT_TRUE@	--log-file $$b.log --trs-file $$b.trs \
+@am__EXEEXT_TRUE@	$(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+@am__EXEEXT_TRUE@	"$$tst" $(AM_TESTS_FD_REDIRECT)
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+	$(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+	-test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS)
+	-test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs)
+	-test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+
+clean-generic:
+	-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-TESTS check-am clean \
+	clean-checkPROGRAMS clean-generic clean-libtool cscopelist-am \
+	ctags ctags-am distclean distclean-compile distclean-generic \
+	distclean-libtool distclean-tags distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-dvi install-dvi-am install-exec \
+	install-exec-am install-html install-html-am install-info \
+	install-info-am install-man install-pdf install-pdf-am \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	recheck tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+$(top_builddir)/tests/libtests.la:
+	cd $(top_builddir)/tests; $(MAKE) $(AM_MAKEFLAGS) libtests.la
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/third_party/gmp/tests/mpq/io.c b/third_party/gmp/tests/mpq/io.c
new file mode 100644
index 0000000..1b0e16f
--- /dev/null
+++ b/third_party/gmp/tests/mpq/io.c
@@ -0,0 +1,136 @@
+/* Test conversion and I/O using mpq_out_str and mpq_inp_str.
+
+Copyright 1993, 1994, 1996, 2000, 2001, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>		/* for unlink */
+#endif
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#define FILENAME  "io.tmp"
+
+void
+debug_mp (mpq_t x, int base)
+{
+  mpq_out_str (stdout, base, x); fputc ('\n', stdout);
+}
+
+int
+main (int argc, char **argv)
+{
+  mpq_t  op1, op2;
+  mp_size_t size;
+  int i;
+  int reps = 10000;
+  FILE *fp;
+  int base;
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long bsi, size_range;
+  size_t nread;
+
+  tests_start ();
+  rands = RANDS;
+
+  mpz_init (bs);
+
+  if (argc == 2)
+    reps = atoi (argv[1]);
+
+  mpq_init (op1);
+  mpq_init (op2);
+
+  fp = fopen (FILENAME, "w+");
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 10 + 2;
+
+      mpz_urandomb (bs, rands, size_range);
+      size = mpz_get_ui (bs);
+      mpz_errandomb (mpq_numref(op1), rands, 512L);
+      mpz_errandomb_nonzero (mpq_denref(op1), rands, 512L);
+      mpq_canonicalize (op1);
+
+      mpz_urandomb (bs, rands, 1);
+      bsi = mpz_get_ui (bs);
+      if ((bsi & 1) != 0)
+	mpq_neg (op1, op1);
+
+      mpz_urandomb (bs, rands, 16);
+      bsi = mpz_get_ui (bs);
+      base = bsi % 36 + 1;
+      if (base == 1)
+	base = 0;
+
+      rewind (fp);
+      if (mpq_out_str (fp, base, op1) == 0
+	  || putc (' ', fp) == EOF
+	  || fflush (fp) != 0)
+	{
+	  printf ("mpq_out_str write error\n");
+	  abort ();
+	}
+
+      rewind (fp);
+      nread = mpq_inp_str (op2, fp, base);
+      if (nread == 0)
+	{
+	  if (ferror (fp))
+	    printf ("mpq_inp_str stream read error\n");
+	  else
+	    printf ("mpq_inp_str data conversion error\n");
+	  abort ();
+	}
+
+      if (nread != ftell(fp))
+	{
+	  printf ("mpq_inp_str nread doesn't match ftell\n");
+	  printf ("  nread  %lu\n", (unsigned long) nread);
+	  printf ("  ftell  %ld\n", ftell(fp));
+	  abort ();
+	}
+
+      if (mpq_cmp (op1, op2))
+	{
+	  printf ("ERROR\n");
+	  printf ("op1  = "); debug_mp (op1, -16);
+	  printf ("op2  = "); debug_mp (op2, -16);
+	  printf ("base = %d\n", base);
+	  abort ();
+	}
+    }
+
+  fclose (fp);
+
+  unlink (FILENAME);
+
+  mpz_clear (bs);
+  mpq_clear (op1);
+  mpq_clear (op2);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpq/reuse.c b/third_party/gmp/tests/mpq/reuse.c
new file mode 100644
index 0000000..b724ffc
--- /dev/null
+++ b/third_party/gmp/tests/mpq/reuse.c
@@ -0,0 +1,245 @@
+/* Test that routines allow reusing a source variable as destination.
+
+Copyright 1996, 2000-2002, 2012, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#if __GMP_LIBGMP_DLL
+
+/* FIXME: When linking to a DLL libgmp, mpq_add etc can't be used as
+   initializers for global variables because they're effectively global
+   variables (function pointers) themselves.  Perhaps calling a test
+   function successively with mpq_add etc would be better.  */
+
+int
+main (void)
+{
+  printf ("Test suppressed for windows DLL\n");
+  exit (0);
+}
+
+
+#else /* ! DLL_EXPORT */
+
+#ifndef SIZE
+#define SIZE 16
+#endif
+
+void dump_abort (const char *, mpq_t, mpq_t);
+
+typedef void (*dss_func) (mpq_ptr, mpq_srcptr, mpq_srcptr);
+
+dss_func dss_funcs[] =
+{
+  mpq_div, mpq_add, mpq_mul, mpq_sub,
+};
+
+const char *dss_func_names[] =
+{
+  "mpq_div", "mpq_add", "mpq_mul", "mpq_sub",
+};
+
+typedef void (*ds_func) (mpq_ptr, mpq_srcptr);
+
+ds_func ds_funcs[] =
+{
+  mpq_abs, mpq_neg,
+};
+
+const char *ds_func_names[] =
+{
+  "mpq_abs", "mpq_neg",
+};
+
+typedef void (*dsi_func) (mpq_ptr, mpq_srcptr, unsigned long int);
+
+dsi_func dsi_funcs[] =
+{
+  mpq_mul_2exp, mpq_div_2exp
+};
+
+const char *dsi_func_names[] =
+{
+  "mpq_mul_2exp", "mpq_div_2exp"
+};
+
+int
+main (int argc, char **argv)
+{
+  int i;
+  int pass, reps = 100;
+  mpq_t in1, in2, out1;
+  unsigned long int randbits, in2i;
+  mpq_t res1, res2;
+  gmp_randstate_ptr  rands;
+
+  tests_start ();
+
+  TESTS_REPS (reps, argv, argc);
+
+  rands = RANDS;
+
+  mpq_init (in1);
+  mpq_init (in2);
+  mpq_init (out1);
+  mpq_init (res1);
+  mpq_init (res2);
+
+  for (pass = 1; pass <= reps; pass++)
+    {
+      randbits = urandom ();
+
+      if (randbits & 1)
+	{
+	  mpq_clear (in1);
+	  mpq_init (in1);
+	}
+      randbits >>= 1;
+      mpz_errandomb (mpq_numref(in1), rands, 512L);
+      mpz_errandomb_nonzero (mpq_denref(in1), rands, 512L);
+      if (randbits & 1)
+	mpz_neg (mpq_numref(in1),mpq_numref(in1));
+      randbits >>= 1;
+      mpq_canonicalize (in1);
+
+      if (randbits & 1)
+	{
+	  mpq_clear (in2);
+	  mpq_init (in2);
+	}
+      randbits >>= 1;
+      mpz_errandomb (mpq_numref(in2), rands, 512L);
+      mpz_errandomb_nonzero (mpq_denref(in2), rands, 512L);
+      if (randbits & 1)
+	mpz_neg (mpq_numref(in2),mpq_numref(in2));
+      randbits >>= 1;
+      mpq_canonicalize (in2);
+
+      for (i = 0; i < sizeof (dss_funcs) / sizeof (dss_func); i++)
+	{
+	  /* Don't divide by 0.  */
+	  if (i == 0 && mpq_cmp_ui (in2, 0, 1) == 0)
+	    continue;
+
+	  if (randbits & 1)
+	    {
+	      mpq_clear (res1);
+	      mpq_init (res1);
+	    }
+	  randbits >>= 1;
+
+	  (dss_funcs[i]) (res1, in1, in2);
+	  MPQ_CHECK_FORMAT(res1);
+
+	  mpq_set (out1, in1);
+	  (dss_funcs[i]) (out1, out1, in2);
+	  MPQ_CHECK_FORMAT(out1);
+
+	  if (mpq_cmp (res1, out1) != 0)
+	    dump_abort (dss_func_names[i], res1, out1);
+
+	  mpq_set (out1, in2);
+	  (dss_funcs[i]) (out1, in1, out1);
+	  MPQ_CHECK_FORMAT(out1);
+
+	  if (mpq_cmp (res1, out1) != 0)
+	    dump_abort (dss_func_names[i], res1, out1);
+
+	  mpq_set (out1, in2);
+	  (dss_funcs[i]) (res1, out1, in2);
+	  MPQ_CHECK_FORMAT(res1);
+
+	  (dss_funcs[i]) (res2, in2, in2);
+	  MPQ_CHECK_FORMAT(res2);
+
+	  (dss_funcs[i]) (out1, out1, out1);
+	  MPQ_CHECK_FORMAT(out1);
+
+	  if (mpq_cmp (res1, res2) != 0)
+	    dump_abort (dss_func_names[i], res1, res2);
+	  if (mpq_cmp (res1, out1) != 0)
+	    dump_abort (dss_func_names[i], res1, out1);
+	}
+
+      for (i = 0; i < sizeof (ds_funcs) / sizeof (ds_func); i++)
+	{
+	  if (randbits & 1)
+	    {
+	      mpq_clear (res1);
+	      mpq_init (res1);
+	    }
+	  randbits >>= 1;
+	  (ds_funcs[i]) (res1, in1);
+	  MPQ_CHECK_FORMAT(res1);
+
+	  mpq_set (out1, in1);
+	  (ds_funcs[i]) (out1, out1);
+	  MPQ_CHECK_FORMAT(out1);
+
+	  if (mpq_cmp (res1, out1) != 0)
+	    dump_abort (ds_func_names[i], res1, out1);
+	}
+
+      in2i = urandom () % 65536;
+      for (i = 0; i < sizeof (dsi_funcs) / sizeof (dsi_func); i++)
+	{
+	  if (randbits & 1)
+	    {
+	      mpq_clear (res1);
+	      mpq_init (res1);
+	    }
+	  randbits >>= 1;
+
+	  (dsi_funcs[i]) (res1, in1, in2i);
+	  MPQ_CHECK_FORMAT(res1);
+
+	  mpq_set (out1, in1);
+	  (dsi_funcs[i]) (out1, out1, in2i);
+	  MPQ_CHECK_FORMAT(out1);
+
+	  if (mpq_cmp (res1, out1) != 0)
+	    dump_abort (dsi_func_names[i], res1, out1);
+	}
+
+    }
+
+  mpq_clear (in1);
+  mpq_clear (in2);
+  mpq_clear (out1);
+  mpq_clear (res1);
+  mpq_clear (res2);
+
+  tests_end ();
+  exit (0);
+}
+
+void
+dump_abort (const char *name, mpq_t res1, mpq_t res2)
+{
+  printf ("failure in %s:\n", name);
+  mpq_trace ("  res1  ", res1);
+  mpq_trace ("  res2  ", res2);
+  abort ();
+}
+
+#endif /* ! DLL_EXPORT */
diff --git a/third_party/gmp/tests/mpq/t-aors.c b/third_party/gmp/tests/mpq/t-aors.c
new file mode 100644
index 0000000..8ee9f93
--- /dev/null
+++ b/third_party/gmp/tests/mpq/t-aors.c
@@ -0,0 +1,182 @@
+/* Test mpq_add and mpq_sub.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_all (mpq_ptr x, mpq_ptr y, mpq_ptr want_add, mpq_ptr want_sub)
+{
+  mpq_t  got;
+  int    neg_x, neg_y, swap;
+
+  mpq_init (got);
+
+  MPQ_CHECK_FORMAT (want_add);
+  MPQ_CHECK_FORMAT (want_sub);
+  MPQ_CHECK_FORMAT (x);
+  MPQ_CHECK_FORMAT (y);
+
+  for (swap = 0; swap <= 1; swap++)
+    {
+      for (neg_x = 0; neg_x <= 1; neg_x++)
+        {
+          for (neg_y = 0; neg_y <= 1; neg_y++)
+            {
+              mpq_add (got, x, y);
+              MPQ_CHECK_FORMAT (got);
+              if (! mpq_equal (got, want_add))
+                {
+                  printf ("mpq_add wrong\n");
+                  mpq_trace ("  x   ", x);
+                  mpq_trace ("  y   ", y);
+                  mpq_trace ("  got ", got);
+                  mpq_trace ("  want", want_add);
+                  abort ();
+                }
+
+              mpq_sub (got, x, y);
+              MPQ_CHECK_FORMAT (got);
+              if (! mpq_equal (got, want_sub))
+                {
+                  printf ("mpq_sub wrong\n");
+                  mpq_trace ("  x   ", x);
+                  mpq_trace ("  y   ", y);
+                  mpq_trace ("  got ", got);
+                  mpq_trace ("  want", want_sub);
+                  abort ();
+                }
+
+
+              mpq_neg (y, y);
+              mpq_swap (want_add, want_sub);
+            }
+
+          mpq_neg (x, x);
+          mpq_swap (want_add, want_sub);
+          mpq_neg (want_add, want_add);
+          mpq_neg (want_sub, want_sub);
+        }
+
+      mpq_swap (x, y);
+      mpq_neg (want_sub, want_sub);
+    }
+
+  mpq_clear (got);
+}
+
+
+void
+check_data (void)
+{
+  static const struct {
+    const char  *x;
+    const char  *y;
+    const char  *want_add;
+    const char  *want_sub;
+
+  } data[] = {
+
+    { "0", "0", "0", "0" },
+    { "1", "0", "1", "1" },
+    { "1", "1", "2", "0" },
+
+    { "1/2", "1/2", "1", "0" },
+    { "5/6", "14/15", "53/30", "-1/10" },
+  };
+
+  mpq_t  x, y, want_add, want_sub;
+  int i;
+
+  mpq_init (x);
+  mpq_init (y);
+  mpq_init (want_add);
+  mpq_init (want_sub);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpq_set_str_or_abort (x, data[i].x, 0);
+      mpq_set_str_or_abort (y, data[i].y, 0);
+      mpq_set_str_or_abort (want_add, data[i].want_add, 0);
+      mpq_set_str_or_abort (want_sub, data[i].want_sub, 0);
+
+      check_all (x, y, want_add, want_sub);
+    }
+
+  mpq_clear (x);
+  mpq_clear (y);
+  mpq_clear (want_add);
+  mpq_clear (want_sub);
+}
+
+
+void
+check_rand (void)
+{
+  mpq_t  x, y, want_add, want_sub;
+  int i;
+  gmp_randstate_ptr  rands = RANDS;
+
+  mpq_init (x);
+  mpq_init (y);
+  mpq_init (want_add);
+  mpq_init (want_sub);
+
+  for (i = 0; i < 500; i++)
+    {
+      mpz_errandomb (mpq_numref(x), rands, 512L);
+      mpz_errandomb_nonzero (mpq_denref(x), rands, 512L);
+      mpq_canonicalize (x);
+
+      mpz_errandomb (mpq_numref(y), rands, 512L);
+      mpz_errandomb_nonzero (mpq_denref(y), rands, 512L);
+      mpq_canonicalize (y);
+
+      refmpq_add (want_add, x, y);
+      refmpq_sub (want_sub, x, y);
+
+      check_all (x, y, want_add, want_sub);
+    }
+
+  mpq_clear (x);
+  mpq_clear (y);
+  mpq_clear (want_add);
+  mpq_clear (want_sub);
+}
+
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_data ();
+  check_rand ();
+
+  tests_end ();
+
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpq/t-cmp.c b/third_party/gmp/tests/mpq/t-cmp.c
new file mode 100644
index 0000000..187db7f
--- /dev/null
+++ b/third_party/gmp/tests/mpq/t-cmp.c
@@ -0,0 +1,101 @@
+/* Test mpq_cmp.
+
+Copyright 1996, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#define SGN(x) ((x) < 0 ? -1 : (x) > 0 ? 1 : 0)
+
+int
+ref_mpq_cmp (mpq_t a, mpq_t b)
+{
+  mpz_t ai, bi;
+  int cc;
+
+  mpz_init (ai);
+  mpz_init (bi);
+
+  mpz_mul (ai, NUM (a), DEN (b));
+  mpz_mul (bi, NUM (b), DEN (a));
+  cc = mpz_cmp (ai, bi);
+  mpz_clear (ai);
+  mpz_clear (bi);
+  return cc;
+}
+
+#ifndef SIZE
+#define SIZE 8	/* increasing this lowers the probability of finding an error */
+#endif
+
+int
+main (int argc, char **argv)
+{
+  mpq_t a, b;
+  mp_size_t size;
+  int reps = 10000;
+  int i;
+  int cc, ccref;
+
+  tests_start ();
+
+  if (argc == 2)
+     reps = atoi (argv[1]);
+
+  mpq_init (a);
+  mpq_init (b);
+
+  for (i = 0; i < reps; i++)
+    {
+      size = urandom () % SIZE - SIZE/2;
+      mpz_random2 (NUM (a), size);
+      do
+	{
+	  size = urandom () % SIZE - SIZE/2;
+	  mpz_random2 (DEN (a), size);
+	}
+      while (mpz_cmp_ui (DEN (a), 0) == 0);
+
+      size = urandom () % SIZE - SIZE/2;
+      mpz_random2 (NUM (b), size);
+      do
+	{
+	  size = urandom () % SIZE - SIZE/2;
+	  mpz_random2 (DEN (b), size);
+	}
+      while (mpz_cmp_ui (DEN (b), 0) == 0);
+
+      mpq_canonicalize (a);
+      mpq_canonicalize (b);
+
+      ccref = ref_mpq_cmp (a, b);
+      cc = mpq_cmp (a, b);
+
+      if (SGN (ccref) != SGN (cc))
+	abort ();
+    }
+
+  mpq_clear (a);
+  mpq_clear (b);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpq/t-cmp_si.c b/third_party/gmp/tests/mpq/t-cmp_si.c
new file mode 100644
index 0000000..5ffa247
--- /dev/null
+++ b/third_party/gmp/tests/mpq/t-cmp_si.c
@@ -0,0 +1,117 @@
+/* Test mpq_cmp_si.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+#define SGN(x)   ((x)<0 ? -1 : (x) != 0)
+
+void
+check_data (void)
+{
+  static const struct {
+    const char     *q;
+    long           n;
+    unsigned long  d;
+    int            want;
+  } data[] = {
+    { "0", 0, 1, 0 },
+    { "0", 0, 123, 0 },
+    { "0", 0, ULONG_MAX, 0 },
+    { "1", 0, 1, 1 },
+    { "1", 0, 123, 1 },
+    { "1", 0, ULONG_MAX, 1 },
+    { "-1", 0, 1, -1 },
+    { "-1", 0, 123, -1 },
+    { "-1", 0, ULONG_MAX, -1 },
+
+    { "123", 123, 1, 0 },
+    { "124", 123, 1, 1 },
+    { "122", 123, 1, -1 },
+
+    { "-123", 123, 1, -1 },
+    { "-124", 123, 1, -1 },
+    { "-122", 123, 1, -1 },
+
+    { "123", -123, 1, 1 },
+    { "124", -123, 1, 1 },
+    { "122", -123, 1, 1 },
+
+    { "-123", -123, 1, 0 },
+    { "-124", -123, 1, -1 },
+    { "-122", -123, 1, 1 },
+
+    { "5/7", 3,4, -1 },
+    { "5/7", -3,4, 1 },
+    { "-5/7", 3,4, -1 },
+    { "-5/7", -3,4, 1 },
+  };
+
+  mpq_t  q;
+  int    i, got;
+
+  mpq_init (q);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpq_set_str_or_abort (q, data[i].q, 0);
+      MPQ_CHECK_FORMAT (q);
+
+      got = mpq_cmp_si (q, data[i].n, data[i].d);
+      if (SGN(got) != data[i].want)
+        {
+          printf ("mpq_cmp_si wrong\n");
+        error:
+          mpq_trace ("  q", q);
+          printf ("  n=%ld\n", data[i].n);
+          printf ("  d=%lu\n", data[i].d);
+          printf ("  got=%d\n", got);
+          printf ("  want=%d\n", data[i].want);
+          abort ();
+        }
+
+      if (data[i].n == 0)
+        {
+          got = mpq_cmp_si (q, 0L, data[i].d);
+          if (SGN(got) != data[i].want)
+            {
+              printf ("mpq_cmp_si wrong\n");
+              goto error;
+            }
+        }
+    }
+
+  mpq_clear (q);
+}
+
+int
+main (int argc, char **argv)
+{
+  tests_start ();
+
+  check_data ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpq/t-cmp_ui.c b/third_party/gmp/tests/mpq/t-cmp_ui.c
new file mode 100644
index 0000000..51bb2cb
--- /dev/null
+++ b/third_party/gmp/tests/mpq/t-cmp_ui.c
@@ -0,0 +1,116 @@
+/* Test mpq_cmp_ui.
+
+Copyright 1996, 1997, 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#define SGN(x) ((x) < 0 ? -1 : (x) > 0 ? 1 : 0)
+
+int
+ref_mpq_cmp_ui (mpq_t a, unsigned long int bn, unsigned long int bd)
+{
+  mpz_t ai, bi;
+  int cc;
+
+  mpz_init (ai);
+  mpz_init (bi);
+
+  mpz_mul_ui (ai, NUM (a), bd);
+  mpz_mul_ui (bi, DEN (a), bn);
+  cc = mpz_cmp (ai, bi);
+  mpz_clear (ai);
+  mpz_clear (bi);
+  return cc;
+}
+
+#ifndef SIZE
+#define SIZE 8	/* increasing this lowers the probability of finding an error */
+#endif
+
+int
+main (int argc, char **argv)
+{
+  mpq_t a, b;
+  mp_size_t size;
+  int reps = 10000;
+  int i;
+  int cc, ccref;
+  unsigned long int bn, bd;
+
+  tests_start ();
+
+  if (argc == 2)
+     reps = atoi (argv[1]);
+
+  mpq_init (a);
+  mpq_init (b);
+
+  for (i = 0; i < reps; i++)
+    {
+      size = urandom () % SIZE - SIZE/2;
+      mpz_random2 (NUM (a), size);
+      do
+	{
+	  size = urandom () % SIZE - SIZE/2;
+	  mpz_random2 (DEN (a), size);
+	}
+      while (mpz_cmp_ui (DEN (a), 0) == 0);
+
+      mpz_random2 (NUM (b), (mp_size_t) 1);
+      mpz_mod_ui (NUM (b), NUM (b), ~(unsigned long int) 0);
+      mpz_add_ui (NUM (b), NUM (b), 1);
+
+      mpz_random2 (DEN (b), (mp_size_t) 1);
+      mpz_mod_ui (DEN (b), DEN (b), ~(unsigned long int) 0);
+      mpz_add_ui (DEN (b), DEN (b), 1);
+
+      mpq_canonicalize (a);
+      mpq_canonicalize (b);
+
+      ccref = ref_mpq_cmp_ui (a, 1, 1);
+      cc = mpq_cmp_ui (a, 1, 1);
+
+      if (SGN (ccref) != SGN (cc))
+	abort ();
+
+      ccref = ref_mpq_cmp_ui (a, 0, 1);
+      cc = mpq_cmp_ui (a, 0, 1);
+
+      if (SGN (ccref) != SGN (cc))
+	abort ();
+
+      bn = mpz_get_ui (NUM (b));
+      bd = mpz_get_ui (DEN (b));
+
+      ccref = ref_mpq_cmp_ui (a, bn, bd);
+      cc = mpq_cmp_ui (a, bn, bd);
+
+      if (SGN (ccref) != SGN (cc))
+	abort ();
+    }
+
+  mpq_clear (a);
+  mpq_clear (b);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpq/t-cmp_z.c b/third_party/gmp/tests/mpq/t-cmp_z.c
new file mode 100644
index 0000000..3e66a3c
--- /dev/null
+++ b/third_party/gmp/tests/mpq/t-cmp_z.c
@@ -0,0 +1,146 @@
+/* Test mpq_cmp_z.
+
+Copyright 1996, 2001, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#define SGN(x) ((x) < 0 ? -1 : (x) > 0 ? 1 : 0)
+
+int
+ref_mpq_cmp_z (mpq_t a, mpz_t b)
+{
+  mpz_t bi;
+  int cc;
+
+  mpz_init (bi);
+
+  mpz_mul (bi, b, DEN (a));
+  cc = mpz_cmp (NUM (a), bi);
+  mpz_clear (bi);
+  return cc;
+}
+
+#ifndef SIZE
+#define SIZE 8	/* increasing this lowers the probability of finding an error */
+#endif
+
+#ifndef MAXN
+#define MAXN 5	/* increasing this impatcs on total timing */
+#endif
+
+void
+sizes_test (int m)
+{
+  mpq_t a;
+  mpz_t b;
+  int i, j, k, s;
+  int cc, ccref;
+
+  mpq_init (a);
+  mpz_init (b);
+
+  for (i = 0; i <= MAXN ; ++i)
+    {
+      mpz_setbit (DEN (a), i*m); /* \sum_0^i 2^(i*m) */
+      for (j = 0; j <= MAXN; ++j)
+	{
+	  mpz_set_ui (NUM (a), 0);
+	  mpz_setbit (NUM (a), j*m); /* 2^(j*m) */
+	  for (k = 0; k <= MAXN; ++k)
+	    {
+	      mpz_set_ui (b, 0);
+	      mpz_setbit (b, k*m); /* 2^(k*m) */
+	      if (i == 0) /* Denominator is 1, compare the two exponents */
+		ccref = (j>k)-(j<k);
+	      else
+		ccref = j-i > k ? 1 : -1;
+	      for (s = 1; s >= -1; s -= 2)
+		{
+		  cc = mpq_cmp_z (a, b);
+
+		  if (ccref != SGN (cc))
+		    {
+		      fprintf (stderr, "i=%i, j=%i, k=%i, m=%i, s=%i\n; ccref= %i, cc= %i\n", i, j, k, m, s, ccref, cc);
+		      abort ();
+		    }
+
+		  mpq_neg (a, a);
+		  mpz_neg (b, b);
+		  ccref = - ccref;
+		}
+	    }
+	}
+    }
+
+  mpq_clear (a);
+  mpz_clear (b);
+}
+
+int
+main (int argc, char **argv)
+{
+  mpq_t a;
+  mpz_t b;
+  mp_size_t size;
+  int reps = 10000;
+  int i;
+  int cc, ccref;
+
+  tests_start ();
+
+  if (argc == 2)
+     reps = atoi (argv[1]);
+
+  mpq_init (a);
+  mpz_init (b);
+
+  for (i = 0; i < reps; i++)
+    {
+      if (i % 8192 == 0)
+	sizes_test (urandom () % (i + 1) + 1);
+      size = urandom () % SIZE - SIZE/2;
+      mpz_random2 (NUM (a), size);
+      do
+	{
+	  size = urandom () % (SIZE/2);
+	  mpz_random2 (DEN (a), size);
+	}
+      while (mpz_cmp_ui (DEN (a), 0) == 0);
+
+      size = urandom () % SIZE - SIZE/2;
+      mpz_random2 (b, size);
+
+      mpq_canonicalize (a);
+
+      ccref = ref_mpq_cmp_z (a, b);
+      cc = mpq_cmp_z (a, b);
+
+      if (SGN (ccref) != SGN (cc))
+	abort ();
+    }
+
+  mpq_clear (a);
+  mpz_clear (b);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpq/t-equal.c b/third_party/gmp/tests/mpq/t-equal.c
new file mode 100644
index 0000000..671c530
--- /dev/null
+++ b/third_party/gmp/tests/mpq/t-equal.c
@@ -0,0 +1,146 @@
+/* Test mpq_equal.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_one (mpq_srcptr x, mpq_srcptr y, int want)
+{
+  int  got;
+
+  MPQ_CHECK_FORMAT (x);
+  MPQ_CHECK_FORMAT (y);
+
+  got = mpq_equal (x, y);
+  if ((got != 0) != (want != 0))
+    {
+      printf ("mpq_equal got %d want %d\n", got, want);
+      mpq_trace ("x", x);
+      mpq_trace ("y", y);
+      abort ();
+    }
+}
+
+
+void
+check_all (mpq_ptr x, mpq_ptr y, int want)
+{
+  check_one (x, y, want);
+  check_one (y, x, want);
+
+  mpq_neg (x, x);
+  mpq_neg (y, y);
+
+  check_one (x, y, want);
+  check_one (y, x, want);
+}
+
+
+#define SET4Z(z, size,l3,l2,l1,l0) \
+  SIZ(z) = size; PTR(z)[3] = l3; PTR(z)[2] = l2; PTR(z)[1] = l1; PTR(z)[0] = l0
+
+#define SET4(q, nsize,n3,n2,n1,n0, dsize,d3,d2,d1,d0)   \
+  SET4Z (mpq_numref(q), nsize,n3,n2,n1,n0);             \
+  SET4Z (mpq_denref(q), dsize,d3,d2,d1,d0)
+
+
+/* Exercise various combinations of same and slightly different values. */
+
+void
+check_various (void)
+{
+  mpq_t  x, y;
+
+  mpq_init (x);
+  mpq_init (y);
+
+  mpz_realloc (mpq_numref(x), (mp_size_t) 20);
+  mpz_realloc (mpq_denref(x), (mp_size_t) 20);
+  mpz_realloc (mpq_numref(y), (mp_size_t) 20);
+  mpz_realloc (mpq_denref(y), (mp_size_t) 20);
+
+  /* 0 == 0 */
+  SET4 (x, 0,13,12,11,10, 1,23,22,21,1);
+  SET4 (y, 0,33,32,31,30, 1,43,42,41,1);
+  check_all (x, y, 1);
+
+  /* 83/99 == 83/99 */
+  SET4 (x, 1,13,12,11,83, 1,23,22,21,99);
+  SET4 (y, 1,33,32,31,83, 1,43,42,41,99);
+  check_all (x, y, 1);
+
+  /* 1:2:3:4/5:6:7 == 1:2:3:4/5:6:7 */
+  SET4 (x, 4,1,2,3,4, 3,88,5,6,7);
+  SET4 (y, 4,1,2,3,4, 3,99,5,6,7);
+  check_all (x, y, 1);
+
+  /* various individual changes making != */
+  SET4 (x, 4,1,2,3,667, 3,88,5,6,7);
+  SET4 (y, 4,1,2,3,4, 3,99,5,6,7);
+  check_all (x, y, 0);
+  SET4 (x, 4,1,2,666,4, 3,88,5,6,7);
+  SET4 (y, 4,1,2,3,4, 3,99,5,6,7);
+  check_all (x, y, 0);
+  SET4 (x, 4,1,666,3,4, 3,88,5,6,7);
+  SET4 (y, 4,1,2,3,4, 3,99,5,6,7);
+  check_all (x, y, 0);
+#if GMP_NUMB_BITS != 62
+  SET4 (x, 4,667,2,3,4, 3,88,5,6,7);
+  SET4 (y, 4,1,2,3,4, 3,99,5,6,7);
+  check_all (x, y, 0);
+#endif
+  SET4 (x, 4,1,2,3,4, 3,88,5,6,667);
+  SET4 (y, 4,1,2,3,4, 3,99,5,6,7);
+  check_all (x, y, 0);
+  SET4 (x, 4,1,2,3,4, 3,88,5,667,7);
+  SET4 (y, 4,1,2,3,4, 3,99,5,6,7);
+  check_all (x, y, 0);
+  SET4 (x, 4,1,2,3,4, 3,88,666,6,7);
+  SET4 (y, 4,1,2,3,4, 3,99,5,6,7);
+  check_all (x, y, 0);
+  SET4 (x, -4,1,2,3,4, 3,88,5,6,7);
+  SET4 (y,  4,1,2,3,4, 3,99,5,6,7);
+  check_all (x, y, 0);
+  SET4 (x, 1,1,2,3,4, 3,88,5,6,7);
+  SET4 (y, 4,1,2,3,4, 3,99,5,6,7);
+  check_all (x, y, 0);
+  SET4 (x, 4,1,2,3,4, 3,88,5,6,7);
+  SET4 (y, 4,1,2,3,4, 2,99,5,6,7);
+  check_all (x, y, 0);
+
+  mpq_clear (x);
+  mpq_clear (y);
+}
+
+
+int
+main (void)
+{
+  tests_start ();
+  mp_trace_base = -16;
+
+  check_various ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpq/t-get_d.c b/third_party/gmp/tests/mpq/t-get_d.c
new file mode 100644
index 0000000..98d6a5f
--- /dev/null
+++ b/third_party/gmp/tests/mpq/t-get_d.c
@@ -0,0 +1,294 @@
+/* Test mpq_get_d and mpq_set_d
+
+Copyright 1991, 1993, 1994, 1996, 2000-2003, 2012, 2013 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#ifndef SIZE
+#define SIZE 8
+#endif
+
+/* VAX D floats only have an 8 bit signed exponent, so anything 2^128 or
+   bigger will overflow, that being 4 limbs. */
+#if defined (__vax) || defined (__vax__) && SIZE > 4
+#undef SIZE
+#define SIZE 4
+#define EPSIZE 3
+#else
+#define EPSIZE SIZE
+#endif
+
+void dump (mpq_t);
+
+void
+check_monotonic (int argc, char **argv)
+{
+  mpq_t a;
+  mp_size_t size;
+  int reps = 100;
+  int i, j;
+  double last_d, new_d;
+  mpq_t qlast_d, qnew_d;
+  mpq_t eps;
+
+  if (argc == 2)
+     reps = atoi (argv[1]);
+
+  /* The idea here is to test the monotonousness of mpq_get_d by adding
+     numbers to the numerator and denominator.  */
+
+  mpq_init (a);
+  mpq_init (eps);
+  mpq_init (qlast_d);
+  mpq_init (qnew_d);
+
+  for (i = 0; i < reps; i++)
+    {
+      size = urandom () % SIZE - SIZE/2;
+      mpz_random2 (mpq_numref (a), size);
+      do
+	{
+	  size = urandom () % SIZE - SIZE/2;
+	  mpz_random2 (mpq_denref (a), size);
+	}
+      while (mpz_cmp_ui (mpq_denref (a), 0) == 0);
+
+      mpq_canonicalize (a);
+
+      last_d = mpq_get_d (a);
+      mpq_set_d (qlast_d, last_d);
+      for (j = 0; j < 10; j++)
+	{
+	  size = urandom () % EPSIZE + 1;
+	  mpz_random2 (mpq_numref (eps), size);
+	  size = urandom () % EPSIZE + 1;
+	  mpz_random2 (mpq_denref (eps), size);
+	  mpq_canonicalize (eps);
+
+	  mpq_add (a, a, eps);
+	  mpq_canonicalize (a);
+	  new_d = mpq_get_d (a);
+	  if (last_d > new_d)
+	    {
+	      printf ("\nERROR (test %d/%d): bad mpq_get_d results\n", i, j);
+	      printf ("last: %.16g\n", last_d);
+	      printf (" new: %.16g\n", new_d); dump (a);
+	      abort ();
+	    }
+	  mpq_set_d (qnew_d, new_d);
+	  MPQ_CHECK_FORMAT (qnew_d);
+	  if (mpq_cmp (qlast_d, qnew_d) > 0)
+	    {
+	      printf ("ERROR (test %d/%d): bad mpq_set_d results\n", i, j);
+	      printf ("last: %.16g\n", last_d); dump (qlast_d);
+	      printf (" new: %.16g\n", new_d); dump (qnew_d);
+	      abort ();
+	    }
+	  last_d = new_d;
+	  mpq_set (qlast_d, qnew_d);
+	}
+    }
+
+  mpq_clear (a);
+  mpq_clear (eps);
+  mpq_clear (qlast_d);
+  mpq_clear (qnew_d);
+}
+
+double
+my_ldexp (double d, int e)
+{
+  for (;;)
+    {
+      if (e > 0)
+	{
+	  if (e >= 16)
+	    {
+	      d *= 65536.0;
+	      e -= 16;
+	    }
+	  else
+	    {
+	      d *= 2.0;
+	      e -= 1;
+	    }
+	}
+      else if (e < 0)
+	{
+
+	  if (e <= -16)
+	    {
+	      d /= 65536.0;
+	      e += 16;
+	    }
+	  else
+	    {
+	      d /= 2.0;
+	      e += 1;
+	    }
+	}
+      else
+	return d;
+    }
+}
+
+#define MAXEXP 500
+
+#if defined (__vax) || defined (__vax__)
+#undef MAXEXP
+#define MAXEXP 30
+#endif
+
+void
+check_random (int argc, char **argv)
+{
+  gmp_randstate_ptr rands = RANDS;
+
+  double d;
+  mpq_t q;
+  mpz_t a, t;
+  int exp;
+
+  int test, reps = 100000;
+
+  if (argc == 2)
+     reps = 100 * atoi (argv[1]);
+
+  mpq_init (q);
+  mpz_init (a);
+  mpz_init (t);
+
+  for (test = 0; test < reps; test++)
+    {
+      mpz_rrandomb (a, rands, 53);
+      mpz_urandomb (t, rands, 32);
+      exp = mpz_get_ui (t) % (2*MAXEXP) - MAXEXP;
+
+      d = my_ldexp (mpz_get_d (a), exp);
+      mpq_set_d (q, d);
+      /* Check that n/d = a * 2^exp, or
+	 d*a 2^{exp} = n */
+      mpz_mul (t, a, mpq_denref (q));
+      if (exp > 0)
+	mpz_mul_2exp (t, t, exp);
+      else
+	{
+	  if (!mpz_divisible_2exp_p (t, -exp))
+	    goto fail;
+	  mpz_div_2exp (t, t, -exp);
+	}
+      if (mpz_cmp (t, mpq_numref (q)) != 0)
+	{
+	fail:
+	  printf ("ERROR (check_random test %d): bad mpq_set_d results\n", test);
+	  printf ("%.16g\n", d);
+	  gmp_printf ("%Qd\n", q);
+	  abort ();
+	}
+    }
+  mpq_clear (q);
+  mpz_clear (t);
+  mpz_clear (a);
+}
+
+void
+dump (mpq_t x)
+{
+  mpz_out_str (stdout, 10, mpq_numref (x));
+  printf ("/");
+  mpz_out_str (stdout, 10, mpq_denref (x));
+  printf ("\n");
+}
+
+/* Check various values 2^n and 1/2^n. */
+void
+check_onebit (void)
+{
+  static const long data[] = {
+    -3*GMP_NUMB_BITS-1, -3*GMP_NUMB_BITS, -3*GMP_NUMB_BITS+1,
+    -2*GMP_NUMB_BITS-1, -2*GMP_NUMB_BITS, -2*GMP_NUMB_BITS+1,
+    -GMP_NUMB_BITS-1, -GMP_NUMB_BITS, -GMP_NUMB_BITS+1,
+    -5, -2, -1, 0, 1, 2, 5,
+    GMP_NUMB_BITS-1, GMP_NUMB_BITS, GMP_NUMB_BITS+1,
+    2*GMP_NUMB_BITS-1, 2*GMP_NUMB_BITS, 2*GMP_NUMB_BITS+1,
+    3*GMP_NUMB_BITS-1, 3*GMP_NUMB_BITS, 3*GMP_NUMB_BITS+1,
+  };
+
+  int     i, neg;
+  long    exp, l;
+  mpq_t   q;
+  double  got, want;
+
+  mpq_init (q);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      exp = data[i];
+
+      mpq_set_ui (q, 1L, 1L);
+      if (exp >= 0)
+	mpq_mul_2exp (q, q, exp);
+      else
+	mpq_div_2exp (q, q, -exp);
+
+      want = 1.0;
+      for (l = 0; l < exp; l++)
+	want *= 2.0;
+      for (l = 0; l > exp; l--)
+	want /= 2.0;
+
+      for (neg = 0; neg <= 1; neg++)
+	{
+	  if (neg)
+	    {
+	      mpq_neg (q, q);
+	      want = -want;
+	    }
+
+	  got = mpq_get_d (q);
+
+	  if (got != want)
+	    {
+	      printf    ("mpq_get_d wrong on %s2**%ld\n", neg ? "-" : "", exp);
+	      mpq_trace ("   q    ", q);
+	      d_trace   ("   want ", want);
+	      d_trace   ("   got  ", got);
+	      abort();
+	    }
+	}
+    }
+  mpq_clear (q);
+}
+
+int
+main (int argc, char **argv)
+{
+  tests_start ();
+
+  check_onebit ();
+  check_monotonic (argc, argv);
+  check_random (argc, argv);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpq/t-get_str.c b/third_party/gmp/tests/mpq/t-get_str.c
new file mode 100644
index 0000000..e586521
--- /dev/null
+++ b/third_party/gmp/tests/mpq/t-get_str.c
@@ -0,0 +1,142 @@
+/* Test mpq_get_str.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_one (mpq_srcptr q, int base, const char *want)
+{
+  char    *str, *ret;
+  size_t  str_alloc;
+
+  MPQ_CHECK_FORMAT (q);
+  mp_trace_base = base;
+
+  str_alloc =
+    mpz_sizeinbase (mpq_numref(q), ABS(base)) +
+    mpz_sizeinbase (mpq_denref(q), ABS(base)) + 3;
+
+  str = mpq_get_str (NULL, base, q);
+  if (strlen(str)+1 > str_alloc)
+    {
+      printf ("mpq_get_str size bigger than should be (passing NULL)\n");
+      printf ("  base %d\n", base);
+      printf ("  got  size %lu \"%s\"\n", (unsigned long)  strlen(str)+1, str);
+      printf ("  want size %lu\n", (unsigned long) str_alloc);
+      abort ();
+    }
+  if (strcmp (str, want) != 0)
+    {
+      printf ("mpq_get_str wrong (passing NULL)\n");
+      printf ("  base %d\n", base);
+      printf ("  got  \"%s\"\n", str);
+      printf ("  want \"%s\"\n", want);
+      mpq_trace ("  q", q);
+      abort ();
+    }
+  (*__gmp_free_func) (str, strlen (str) + 1);
+
+  str = (char *) (*__gmp_allocate_func) (str_alloc);
+
+  ret = mpq_get_str (str, base, q);
+  if (str != ret)
+    {
+      printf ("mpq_get_str wrong return value (passing non-NULL)\n");
+      printf ("  base %d\n", base);
+      printf ("  got  %p\n", (void *) ret);
+      printf ("  want %p\n", (void *) str);
+      abort ();
+    }
+  if (strcmp (str, want) != 0)
+    {
+      printf ("mpq_get_str wrong (passing non-NULL)\n");
+      printf ("  base %d\n", base);
+      printf ("  got  \"%s\"\n", str);
+      printf ("  want \"%s\"\n", want);
+      abort ();
+    }
+  (*__gmp_free_func) (str, str_alloc);
+}
+
+
+void
+check_all (mpq_srcptr q, int base, const char *want)
+{
+  char  *s;
+
+  check_one (q, base, want);
+
+  s = __gmp_allocate_strdup (want);
+  strtoupper (s);
+  check_one (q, -base, s);
+  (*__gmp_free_func) (s, strlen(s)+1);
+}
+
+void
+check_data (void)
+{
+  static const struct {
+    int         base;
+    const char  *num;
+    const char  *den;
+    const char  *want;
+  } data[] = {
+    { 10, "0", "1", "0" },
+    { 10, "1", "1", "1" },
+
+    { 16, "ffffffff", "1", "ffffffff" },
+    { 16, "ffffffffffffffff", "1", "ffffffffffffffff" },
+
+    { 16, "1", "ffffffff", "1/ffffffff" },
+    { 16, "1", "ffffffffffffffff", "1/ffffffffffffffff" },
+    { 16, "1", "10000000000000003", "1/10000000000000003" },
+
+    { 10, "12345678901234567890", "9876543210987654323",
+      "12345678901234567890/9876543210987654323" },
+  };
+
+  mpq_t  q;
+  int    i;
+
+  mpq_init (q);
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_set_str_or_abort (mpq_numref(q), data[i].num, data[i].base);
+      mpz_set_str_or_abort (mpq_denref(q), data[i].den, data[i].base);
+      check_all (q, data[i].base, data[i].want);
+    }
+  mpq_clear (q);
+}
+
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_data ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpq/t-inp_str.c b/third_party/gmp/tests/mpq/t-inp_str.c
new file mode 100644
index 0000000..b44abd8
--- /dev/null
+++ b/third_party/gmp/tests/mpq/t-inp_str.c
@@ -0,0 +1,171 @@
+/* Test mpq_inp_str.
+
+Copyright 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>   /* for unlink */
+#endif
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+#define FILENAME  "t-inp_str.tmp"
+
+
+void
+check_data (void)
+{
+  static const struct {
+    const char  *inp;
+    int         base;
+    const char  *want;
+    int         want_nread;
+
+  } data[] = {
+
+    { "0",   10, "0", 1 },
+    { "0/1", 10, "0", 3 },
+
+    { "0/",   10, "0", 0 },
+    { "/123", 10, "0", 0 },
+    { "blah", 10, "0", 0 },
+    { "123/blah", 10, "0", 0 },
+    { "5 /8", 10, "5", 1 },
+    { "5/ 8", 10, "0", 0 },
+
+    {  "ff", 16,  "255", 2 },
+    { "-ff", 16, "-255", 3 },
+    {  "FF", 16,  "255", 2 },
+    { "-FF", 16, "-255", 3 },
+
+    { "z", 36, "35", 1 },
+    { "Z", 36, "35", 1 },
+
+    {  "0x0",    0,   "0", 3 },
+    {  "0x10",   0,  "16", 4 },
+    { "-0x0",    0,   "0", 4 },
+    { "-0x10",   0, "-16", 5 },
+    { "-0x10/5", 0, "-16/5", 7 },
+
+    {  "00",   0,  "0", 2 },
+    {  "010",  0,  "8", 3 },
+    { "-00",   0,  "0", 3 },
+    { "-010",  0, "-8", 4 },
+  };
+
+  mpq_t  got, want;
+  long   ftell_nread;
+  int    i, post, j, got_nread;
+  FILE   *fp;
+
+  mpq_init (got);
+  mpq_init (want);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      for (post = 0; post <= 2; post++)
+	{
+	  mpq_set_str_or_abort (want, data[i].want, 0);
+	  MPQ_CHECK_FORMAT (want);
+
+	  fp = fopen (FILENAME, "w+");
+	  ASSERT_ALWAYS (fp != NULL);
+	  fputs (data[i].inp, fp);
+	  for (j = 0; j < post; j++)
+	    putc (' ', fp);
+	  fflush (fp);
+	  ASSERT_ALWAYS (! ferror(fp));
+
+	  rewind (fp);
+	  got_nread = mpq_inp_str (got, fp, data[i].base);
+
+	  if (got_nread != 0)
+	    {
+	      ftell_nread = ftell (fp);
+	      if (got_nread != ftell_nread)
+		{
+		  printf ("mpq_inp_str nread wrong\n");
+		  printf ("  inp          \"%s\"\n", data[i].inp);
+		  printf ("  base         %d\n", data[i].base);
+		  printf ("  got_nread    %d\n", got_nread);
+		  printf ("  ftell_nread  %ld\n", ftell_nread);
+		  abort ();
+		}
+	    }
+
+	  if (post == 0 && data[i].want_nread == strlen(data[i].inp))
+	    {
+	      int  c = getc(fp);
+	      if (c != EOF)
+		{
+		  printf ("mpq_inp_str didn't read to EOF\n");
+		  printf ("  inp         \"%s\"\n", data[i].inp);
+		  printf ("  base        %d\n", data[i].base);
+		  printf ("  c '%c' %#x\n", c, c);
+		  abort ();
+		}
+	    }
+
+	  if (got_nread != data[i].want_nread)
+	    {
+	      printf ("mpq_inp_str nread wrong\n");
+	      printf ("  inp         \"%s\"\n", data[i].inp);
+	      printf ("  base        %d\n", data[i].base);
+	      printf ("  got_nread   %d\n", got_nread);
+	      printf ("  want_nread  %d\n", data[i].want_nread);
+	      abort ();
+	    }
+
+	  MPQ_CHECK_FORMAT (got);
+
+	  if (! mpq_equal (got, want))
+	    {
+	      printf ("mpq_inp_str wrong result\n");
+	      printf ("  inp   \"%s\"\n", data[i].inp);
+	      printf ("  base  %d\n", data[i].base);
+	      mpq_trace ("  got ",  got);
+	      mpq_trace ("  want", want);
+	      abort ();
+	    }
+
+	  ASSERT_ALWAYS (fclose (fp) == 0);
+	}
+    }
+
+  mpq_clear (got);
+  mpq_clear (want);
+}
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_data ();
+
+  unlink (FILENAME);
+  tests_end ();
+
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpq/t-inv.c b/third_party/gmp/tests/mpq/t-inv.c
new file mode 100644
index 0000000..87ba8d4
--- /dev/null
+++ b/third_party/gmp/tests/mpq/t-inv.c
@@ -0,0 +1,60 @@
+/* Test mpq_inv (and set/get_num/den).
+
+Copyright 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+int
+main (int argc, char **argv)
+{
+  mpq_t a, b;
+  mpz_t m, n;
+  const char* s = "-420000000000000000000000";
+
+  tests_start ();
+
+  mpq_inits (a, b, (mpq_ptr)0);
+  mpz_inits (m, n, (mpz_ptr)0);
+
+  mpz_set_ui (m, 13);
+  mpq_set_den (a, m);
+  mpz_set_str (m, s, 0);
+  mpq_set_num (a, m);
+  MPQ_CHECK_FORMAT (a);
+  mpq_inv (b, a);
+  MPQ_CHECK_FORMAT (b);
+  mpq_get_num (n, b);
+  ASSERT_ALWAYS (mpz_cmp_si (n, -13) == 0);
+  mpq_neg (b, b);
+  mpq_inv (a, b);
+  MPQ_CHECK_FORMAT (a);
+  mpq_inv (b, b);
+  MPQ_CHECK_FORMAT (b);
+  mpq_get_den (n, b);
+  ASSERT_ALWAYS (mpz_cmp_ui (n, 13) == 0);
+  mpq_get_num (n, a);
+  mpz_add (n, n, m);
+  ASSERT_ALWAYS (mpz_sgn (n) == 0);
+
+  mpq_clears (a, b, (mpq_ptr)0);
+  mpz_clears (m, n, (mpz_ptr)0);
+
+  tests_end ();
+  return 0;
+}
diff --git a/third_party/gmp/tests/mpq/t-md_2exp.c b/third_party/gmp/tests/mpq/t-md_2exp.c
new file mode 100644
index 0000000..2bffce9
--- /dev/null
+++ b/third_party/gmp/tests/mpq/t-md_2exp.c
@@ -0,0 +1,244 @@
+/* Test mpq_mul_2exp and mpq_div_2exp.
+
+Copyright 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+struct pair_t {
+  const char     *num;
+  const char     *den;
+};
+
+void
+check_random ()
+{
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long arg_size, size_range;
+  mpq_t q, r;
+  int i;
+  mp_bitcnt_t shift;
+  int reps = 10000;
+
+  rands = RANDS;
+
+  mpz_init (bs);
+  mpq_init (q);
+  mpq_init (r);
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 11 + 2; /* 0..4096 bit operands */
+
+      mpz_urandomb (bs, rands, size_range);
+      arg_size = mpz_get_ui (bs);
+      mpz_rrandomb (mpq_numref (q), rands, arg_size);
+      do
+	{
+	  mpz_urandomb (bs, rands, size_range);
+	  arg_size = mpz_get_ui (bs);
+	  mpz_rrandomb (mpq_denref (q), rands, arg_size);
+	}
+      while (mpz_sgn (mpq_denref (q)) == 0);
+
+      /* We now have a random rational in q, albeit an unnormalised one.  The
+	 lack of normalisation should not matter here, so let's save the time a
+	 gcd would require.  */
+
+      mpz_urandomb (bs, rands, 32);
+      shift = mpz_get_ui (bs) % 4096;
+
+      mpq_mul_2exp (r, q, shift);
+
+      if (mpq_cmp (r, q) < 0)
+	{
+	  printf ("mpq_mul_2exp wrong on random\n");
+	  abort ();
+	}
+
+      mpq_div_2exp (r, r, shift);
+
+      if (mpq_cmp (r, q) != 0)
+	{
+	  printf ("mpq_mul_2exp or mpq_div_2exp wrong on random\n");
+	  abort ();
+	}
+    }
+  mpq_clear (q);
+  mpq_clear (r);
+  mpz_clear (bs);
+}
+
+int
+main (int argc, char **argv)
+{
+  static const struct {
+    struct pair_t  left;
+    unsigned long  n;
+    struct pair_t  right;
+
+  } data[] = {
+    { {"0","1"}, 0, {"0","1"} },
+    { {"0","1"}, 1, {"0","1"} },
+    { {"0","1"}, 2, {"0","1"} },
+
+    { {"1","1"}, 0, {"1","1"} },
+    { {"1","1"}, 1, {"2","1"} },
+    { {"1","1"}, 2, {"4","1"} },
+    { {"1","1"}, 3, {"8","1"} },
+
+    { {"1","1"}, 31, {"0x80000000","1"} },
+    { {"1","1"}, 32, {"0x100000000","1"} },
+    { {"1","1"}, 33, {"0x200000000","1"} },
+    { {"1","1"}, 63, {"0x8000000000000000","1"} },
+    { {"1","1"}, 64, {"0x10000000000000000","1"} },
+    { {"1","1"}, 65, {"0x20000000000000000","1"} },
+    { {"1","1"}, 95, {"0x800000000000000000000000","1"} },
+    { {"1","1"}, 96, {"0x1000000000000000000000000","1"} },
+    { {"1","1"}, 97, {"0x2000000000000000000000000","1"} },
+    { {"1","1"}, 127, {"0x80000000000000000000000000000000","1"} },
+    { {"1","1"}, 128, {"0x100000000000000000000000000000000","1"} },
+    { {"1","1"}, 129, {"0x200000000000000000000000000000000","1"} },
+
+    { {"1","2"}, 31, {"0x40000000","1"} },
+    { {"1","2"}, 32, {"0x80000000","1"} },
+    { {"1","2"}, 33, {"0x100000000","1"} },
+    { {"1","2"}, 63, {"0x4000000000000000","1"} },
+    { {"1","2"}, 64, {"0x8000000000000000","1"} },
+    { {"1","2"}, 65, {"0x10000000000000000","1"} },
+    { {"1","2"}, 95, {"0x400000000000000000000000","1"} },
+    { {"1","2"}, 96, {"0x800000000000000000000000","1"} },
+    { {"1","2"}, 97, {"0x1000000000000000000000000","1"} },
+    { {"1","2"}, 127, {"0x40000000000000000000000000000000","1"} },
+    { {"1","2"}, 128, {"0x80000000000000000000000000000000","1"} },
+    { {"1","2"}, 129, {"0x100000000000000000000000000000000","1"} },
+
+    { {"1","0x80000000"}, 30, {"1","2"} },
+    { {"1","0x80000000"}, 31, {"1","1"} },
+    { {"1","0x80000000"}, 32, {"2","1"} },
+    { {"1","0x80000000"}, 33, {"4","1"} },
+    { {"1","0x80000000"}, 62, {"0x80000000","1"} },
+    { {"1","0x80000000"}, 63, {"0x100000000","1"} },
+    { {"1","0x80000000"}, 64, {"0x200000000","1"} },
+    { {"1","0x80000000"}, 94, {"0x8000000000000000","1"} },
+    { {"1","0x80000000"}, 95, {"0x10000000000000000","1"} },
+    { {"1","0x80000000"}, 96, {"0x20000000000000000","1"} },
+    { {"1","0x80000000"}, 126, {"0x800000000000000000000000","1"} },
+    { {"1","0x80000000"}, 127, {"0x1000000000000000000000000","1"} },
+    { {"1","0x80000000"}, 128, {"0x2000000000000000000000000","1"} },
+
+    { {"1","0x100000000"}, 1, {"1","0x80000000"} },
+    { {"1","0x100000000"}, 2, {"1","0x40000000"} },
+    { {"1","0x100000000"}, 3, {"1","0x20000000"} },
+
+    { {"1","0x10000000000000000"}, 1, {"1","0x8000000000000000"} },
+    { {"1","0x10000000000000000"}, 2, {"1","0x4000000000000000"} },
+    { {"1","0x10000000000000000"}, 3, {"1","0x2000000000000000"} },
+  };
+
+  void (*fun) (mpq_ptr, mpq_srcptr, unsigned long);
+  const struct pair_t  *p_start, *p_want;
+  const char  *name;
+  mpq_t    sep, got, want;
+  mpq_ptr  q;
+  int      i, muldiv, sign, overlap;
+
+  tests_start ();
+
+  mpq_init (sep);
+  mpq_init (got);
+  mpq_init (want);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      for (muldiv = 0; muldiv < 2; muldiv++)
+        {
+          if (muldiv == 0)
+            {
+              fun = mpq_mul_2exp;
+              name = "mpq_mul_2exp";
+              p_start = &data[i].left;
+              p_want = &data[i].right;
+            }
+          else
+            {
+              fun = mpq_div_2exp;
+              name = "mpq_div_2exp";
+              p_start = &data[i].right;
+              p_want = &data[i].left;
+            }
+
+          for (sign = 0; sign <= 1; sign++)
+            {
+              mpz_set_str_or_abort (mpq_numref(want), p_want->num, 0);
+              mpz_set_str_or_abort (mpq_denref(want), p_want->den, 0);
+              if (sign)
+                mpq_neg (want, want);
+
+              for (overlap = 0; overlap <= 1; overlap++)
+                {
+                  q = overlap ? got : sep;
+
+                  /* initial garbage in "got" */
+                  mpq_set_ui (got, 123L, 456L);
+
+                  mpz_set_str_or_abort (mpq_numref(q), p_start->num, 0);
+                  mpz_set_str_or_abort (mpq_denref(q), p_start->den, 0);
+                  if (sign)
+                    mpq_neg (q, q);
+
+                  (*fun) (got, q, data[i].n);
+                  MPQ_CHECK_FORMAT (got);
+
+                  if (! mpq_equal (got, want))
+                    {
+                      printf ("%s wrong at data[%d], sign %d, overlap %d\n",
+                              name, i, sign, overlap);
+                      printf ("   num \"%s\"\n", p_start->num);
+                      printf ("   den \"%s\"\n", p_start->den);
+                      printf ("   n   %lu\n", data[i].n);
+
+                      printf ("   got  ");
+                      mpq_out_str (stdout, 16, got);
+                      printf (" (hex)\n");
+
+                      printf ("   want ");
+                      mpq_out_str (stdout, 16, want);
+                      printf (" (hex)\n");
+
+                      abort ();
+                    }
+                }
+            }
+        }
+    }
+
+  check_random ();
+
+  mpq_clear (sep);
+  mpq_clear (got);
+  mpq_clear (want);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpq/t-set_f.c b/third_party/gmp/tests/mpq/t-set_f.c
new file mode 100644
index 0000000..e92e3aa
--- /dev/null
+++ b/third_party/gmp/tests/mpq/t-set_f.c
@@ -0,0 +1,169 @@
+/* Test mpq_set_f.
+
+Copyright 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+int
+main (int argc, char **argv)
+{
+#if GMP_NAIL_BITS == 0
+  static const struct {
+    int         f_base;
+    const char  *f;
+    int         z_base;
+    const char  *want_num;
+    const char  *want_den;
+
+  } data[] = {
+
+    { -2, "0",    16, "0", "1" },
+    { -2, "1",    16, "1", "1" },
+    { -2, "1@1",  16, "2", "1" },
+    { -2, "1@2",  16, "4", "1" },
+    { -2, "1@3",  16, "8", "1" },
+
+    { -2, "1@30", 16,  "40000000", "1" },
+    { -2, "1@31", 16,  "80000000", "1" },
+    { -2, "1@32", 16, "100000000", "1" },
+    { -2, "1@33", 16, "200000000", "1" },
+    { -2, "1@34", 16, "400000000", "1" },
+
+    { -2, "1@62", 16,  "4000000000000000", "1" },
+    { -2, "1@63", 16,  "8000000000000000", "1" },
+    { -2, "1@64", 16, "10000000000000000", "1" },
+    { -2, "1@65", 16, "20000000000000000", "1" },
+    { -2, "1@66", 16, "40000000000000000", "1" },
+
+    { -2, "1@126", 16,  "40000000000000000000000000000000", "1" },
+    { -2, "1@127", 16,  "80000000000000000000000000000000", "1" },
+    { -2, "1@128", 16, "100000000000000000000000000000000", "1" },
+    { -2, "1@129", 16, "200000000000000000000000000000000", "1" },
+    { -2, "1@130", 16, "400000000000000000000000000000000", "1" },
+
+    { -2, "1@-1",  16, "1", "2" },
+    { -2, "1@-2",  16, "1", "4" },
+    { -2, "1@-3",  16, "1", "8" },
+
+    { -2, "1@-30", 16, "1",  "40000000" },
+    { -2, "1@-31", 16, "1",  "80000000" },
+    { -2, "1@-32", 16, "1", "100000000" },
+    { -2, "1@-33", 16, "1", "200000000" },
+    { -2, "1@-34", 16, "1", "400000000" },
+
+    { -2, "1@-62", 16, "1",  "4000000000000000" },
+    { -2, "1@-63", 16, "1",  "8000000000000000" },
+    { -2, "1@-64", 16, "1", "10000000000000000" },
+    { -2, "1@-65", 16, "1", "20000000000000000" },
+    { -2, "1@-66", 16, "1", "40000000000000000" },
+
+    { -2, "1@-126", 16, "1",  "40000000000000000000000000000000" },
+    { -2, "1@-127", 16, "1",  "80000000000000000000000000000000" },
+    { -2, "1@-128", 16, "1", "100000000000000000000000000000000" },
+    { -2, "1@-129", 16, "1", "200000000000000000000000000000000" },
+    { -2, "1@-130", 16, "1", "400000000000000000000000000000000" },
+
+    { -2, "1@-30", 16, "1",  "40000000" },
+    { -2, "1@-31", 16, "1",  "80000000" },
+    { -2, "1@-32", 16, "1", "100000000" },
+    { -2, "1@-33", 16, "1", "200000000" },
+    { -2, "1@-34", 16, "1", "400000000" },
+
+    { -2, "11@-62", 16, "3",  "4000000000000000" },
+    { -2, "11@-63", 16, "3",  "8000000000000000" },
+    { -2, "11@-64", 16, "3", "10000000000000000" },
+    { -2, "11@-65", 16, "3", "20000000000000000" },
+    { -2, "11@-66", 16, "3", "40000000000000000" },
+
+    { 16, "80000000.00000001", 16, "8000000000000001", "100000000" },
+    { 16, "80000000.00000008", 16, "1000000000000001",  "20000000" },
+    { 16, "80000000.8",        16, "100000001", "2" },
+
+  };
+
+  mpf_t  f;
+  mpq_t  got;
+  mpz_t  want_num, want_den;
+  int    i, neg;
+
+  tests_start ();
+
+  mpf_init2 (f, 1024L);
+  mpq_init (got);
+  mpz_init (want_num);
+  mpz_init (want_den);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      for (neg = 0; neg <= 1; neg++)
+        {
+          mpf_set_str_or_abort (f, data[i].f, data[i].f_base);
+          mpz_set_str_or_abort (want_num, data[i].want_num, data[i].z_base);
+          mpz_set_str_or_abort (want_den, data[i].want_den, data[i].z_base);
+
+          if (neg)
+            {
+              mpf_neg (f, f);
+              mpz_neg (want_num, want_num);
+            }
+
+          mpq_set_f (got, f);
+          MPQ_CHECK_FORMAT (got);
+
+          if (mpz_cmp (mpq_numref(got), want_num) != 0
+              || mpz_cmp (mpq_denref(got), want_den) != 0)
+            {
+              printf ("wrong at data[%d]\n", i);
+              printf ("   f_base %d, z_base %d\n",
+                      data[i].f_base, data[i].z_base);
+
+              printf ("   f \"%s\" hex ", data[i].f);
+              mpf_out_str (stdout, 16, 0, f);
+              printf ("\n");
+
+              printf ("   want num 0x");
+              mpz_out_str (stdout, 16, want_num);
+              printf ("\n");
+              printf ("   want den 0x");
+              mpz_out_str (stdout, 16, want_den);
+              printf ("\n");
+
+              printf ("   got num 0x");
+              mpz_out_str (stdout, 16, mpq_numref(got));
+              printf ("\n");
+              printf ("   got den 0x");
+              mpz_out_str (stdout, 16, mpq_denref(got));
+              printf ("\n");
+
+              abort ();
+            }
+        }
+    }
+
+  mpf_clear (f);
+  mpq_clear (got);
+  mpz_clear (want_num);
+  mpz_clear (want_den);
+
+  tests_end ();
+#endif
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpq/t-set_str.c b/third_party/gmp/tests/mpq/t-set_str.c
new file mode 100644
index 0000000..1f5ca8b
--- /dev/null
+++ b/third_party/gmp/tests/mpq/t-set_str.c
@@ -0,0 +1,102 @@
+/* Test mpq_set_str.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_one (mpq_srcptr want, int base, const char *str)
+{
+  mpq_t   got;
+
+  MPQ_CHECK_FORMAT (want);
+  mp_trace_base = base;
+
+  mpq_init (got);
+
+  if (mpq_set_str (got, str, base) != 0)
+    {
+      printf ("mpq_set_str unexpectedly failed\n");
+      printf ("  base %d\n", base);
+      printf ("  str  \"%s\"\n", str);
+      abort ();
+    }
+  MPQ_CHECK_FORMAT (got);
+
+  if (! mpq_equal (got, want))
+    {
+      printf ("mpq_set_str wrong\n");
+      printf ("  base %d\n", base);
+      printf ("  str  \"%s\"\n", str);
+      mpq_trace ("got ", got);
+      mpq_trace ("want", want);
+      abort ();
+    }
+
+  mpq_clear (got);
+}
+
+void
+check_samples (void)
+{
+  mpq_t  q;
+
+  mpq_init (q);
+
+  mpq_set_ui (q, 0L, 1L);
+  check_one (q, 10, "0");
+  check_one (q, 10, "0/1");
+  check_one (q, 10, "0  / 1");
+  check_one (q, 0, "0x0/ 1");
+  check_one (q, 0, "0x0/ 0x1");
+  check_one (q, 0, "0 / 0x1");
+
+  check_one (q, 10, "-0");
+  check_one (q, 10, "-0/1");
+  check_one (q, 10, "-0  / 1");
+  check_one (q, 0, "-0x0/ 1");
+  check_one (q, 0, "-0x0/ 0x1");
+  check_one (q, 0, "-0 / 0x1");
+
+  mpq_set_ui (q, 255L, 256L);
+  check_one (q, 10, "255/256");
+  check_one (q, 0,  "0xFF/0x100");
+  check_one (q, 16, "FF/100");
+
+  mpq_neg (q, q);
+  check_one (q, 10, "-255/256");
+  check_one (q, 0,  "-0xFF/0x100");
+  check_one (q, 16, "-FF/100");
+
+  mpq_clear (q);
+}
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_samples ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpz/Makefile.am b/third_party/gmp/tests/mpz/Makefile.am
new file mode 100644
index 0000000..6a56eda
--- /dev/null
+++ b/third_party/gmp/tests/mpz/Makefile.am
@@ -0,0 +1,43 @@
+## Process this file with automake to generate Makefile.in
+
+# Copyright 1996, 1997, 1999-2003, 2009, 2012 Free Software Foundation, Inc.
+#
+# This file is part of the GNU MP Library test suite.
+#
+# The GNU MP Library test suite is free software; you can redistribute it
+# and/or modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 3 of the License,
+# or (at your option) any later version.
+#
+# The GNU MP Library test suite is distributed in the hope that it will be
+# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.
+
+
+AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/tests
+AM_LDFLAGS = -no-install
+LDADD = $(top_builddir)/tests/libtests.la $(top_builddir)/libgmp.la
+
+check_PROGRAMS = reuse t-addsub t-cmp t-mul t-mul_i t-tdiv t-tdiv_ui t-fdiv \
+  t-fdiv_ui t-cdiv_ui t-gcd t-gcd_ui t-lcm t-invert dive dive_ui t-sqrtrem \
+  convert io t-inp_str logic bit t-powm t-powm_ui t-pow t-div_2exp      \
+  t-root t-perfsqr t-perfpow t-jac t-bin t-get_d t-get_d_2exp t-get_si	\
+  t-set_d t-set_si t-lucm						\
+  t-fac_ui t-mfac_uiui t-primorial_ui t-fib_ui t-lucnum_ui t-scan t-fits   \
+  t-divis t-divis_2exp t-cong t-cong_2exp t-sizeinbase t-set_str        \
+  t-aorsmul t-cmp_d t-cmp_si t-hamdist t-oddeven t-popcount t-set_f     \
+  t-io_raw t-import t-export t-pprime_p t-nextprime t-remove t-limbs
+
+TESTS = $(check_PROGRAMS)
+
+# Temporary files used by the tests.  Removed automatically if the tests
+# pass, but ensure they're cleaned if they fail.
+#
+CLEANFILES = *.tmp
+
+$(top_builddir)/tests/libtests.la:
+	cd $(top_builddir)/tests; $(MAKE) $(AM_MAKEFLAGS) libtests.la
diff --git a/third_party/gmp/tests/mpz/Makefile.in b/third_party/gmp/tests/mpz/Makefile.in
new file mode 100644
index 0000000..6f42c51
--- /dev/null
+++ b/third_party/gmp/tests/mpz/Makefile.in
@@ -0,0 +1,2059 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Copyright 1996, 1997, 1999-2003, 2009, 2012 Free Software Foundation, Inc.
+#
+# This file is part of the GNU MP Library test suite.
+#
+# The GNU MP Library test suite is free software; you can redistribute it
+# and/or modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 3 of the License,
+# or (at your option) any later version.
+#
+# The GNU MP Library test suite is distributed in the hope that it will be
+# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+check_PROGRAMS = reuse$(EXEEXT) t-addsub$(EXEEXT) t-cmp$(EXEEXT) \
+	t-mul$(EXEEXT) t-mul_i$(EXEEXT) t-tdiv$(EXEEXT) \
+	t-tdiv_ui$(EXEEXT) t-fdiv$(EXEEXT) t-fdiv_ui$(EXEEXT) \
+	t-cdiv_ui$(EXEEXT) t-gcd$(EXEEXT) t-gcd_ui$(EXEEXT) \
+	t-lcm$(EXEEXT) t-invert$(EXEEXT) dive$(EXEEXT) \
+	dive_ui$(EXEEXT) t-sqrtrem$(EXEEXT) convert$(EXEEXT) \
+	io$(EXEEXT) t-inp_str$(EXEEXT) logic$(EXEEXT) bit$(EXEEXT) \
+	t-powm$(EXEEXT) t-powm_ui$(EXEEXT) t-pow$(EXEEXT) \
+	t-div_2exp$(EXEEXT) t-root$(EXEEXT) t-perfsqr$(EXEEXT) \
+	t-perfpow$(EXEEXT) t-jac$(EXEEXT) t-bin$(EXEEXT) \
+	t-get_d$(EXEEXT) t-get_d_2exp$(EXEEXT) t-get_si$(EXEEXT) \
+	t-set_d$(EXEEXT) t-set_si$(EXEEXT) t-lucm$(EXEEXT) \
+	t-fac_ui$(EXEEXT) t-mfac_uiui$(EXEEXT) t-primorial_ui$(EXEEXT) \
+	t-fib_ui$(EXEEXT) t-lucnum_ui$(EXEEXT) t-scan$(EXEEXT) \
+	t-fits$(EXEEXT) t-divis$(EXEEXT) t-divis_2exp$(EXEEXT) \
+	t-cong$(EXEEXT) t-cong_2exp$(EXEEXT) t-sizeinbase$(EXEEXT) \
+	t-set_str$(EXEEXT) t-aorsmul$(EXEEXT) t-cmp_d$(EXEEXT) \
+	t-cmp_si$(EXEEXT) t-hamdist$(EXEEXT) t-oddeven$(EXEEXT) \
+	t-popcount$(EXEEXT) t-set_f$(EXEEXT) t-io_raw$(EXEEXT) \
+	t-import$(EXEEXT) t-export$(EXEEXT) t-pprime_p$(EXEEXT) \
+	t-nextprime$(EXEEXT) t-remove$(EXEEXT) t-limbs$(EXEEXT)
+subdir = tests/mpz
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+bit_SOURCES = bit.c
+bit_OBJECTS = bit.$(OBJEXT)
+bit_LDADD = $(LDADD)
+bit_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+convert_SOURCES = convert.c
+convert_OBJECTS = convert.$(OBJEXT)
+convert_LDADD = $(LDADD)
+convert_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+dive_SOURCES = dive.c
+dive_OBJECTS = dive.$(OBJEXT)
+dive_LDADD = $(LDADD)
+dive_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+dive_ui_SOURCES = dive_ui.c
+dive_ui_OBJECTS = dive_ui.$(OBJEXT)
+dive_ui_LDADD = $(LDADD)
+dive_ui_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+io_SOURCES = io.c
+io_OBJECTS = io.$(OBJEXT)
+io_LDADD = $(LDADD)
+io_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+logic_SOURCES = logic.c
+logic_OBJECTS = logic.$(OBJEXT)
+logic_LDADD = $(LDADD)
+logic_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+reuse_SOURCES = reuse.c
+reuse_OBJECTS = reuse.$(OBJEXT)
+reuse_LDADD = $(LDADD)
+reuse_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_addsub_SOURCES = t-addsub.c
+t_addsub_OBJECTS = t-addsub.$(OBJEXT)
+t_addsub_LDADD = $(LDADD)
+t_addsub_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_aorsmul_SOURCES = t-aorsmul.c
+t_aorsmul_OBJECTS = t-aorsmul.$(OBJEXT)
+t_aorsmul_LDADD = $(LDADD)
+t_aorsmul_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_bin_SOURCES = t-bin.c
+t_bin_OBJECTS = t-bin.$(OBJEXT)
+t_bin_LDADD = $(LDADD)
+t_bin_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_cdiv_ui_SOURCES = t-cdiv_ui.c
+t_cdiv_ui_OBJECTS = t-cdiv_ui.$(OBJEXT)
+t_cdiv_ui_LDADD = $(LDADD)
+t_cdiv_ui_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_cmp_SOURCES = t-cmp.c
+t_cmp_OBJECTS = t-cmp.$(OBJEXT)
+t_cmp_LDADD = $(LDADD)
+t_cmp_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_cmp_d_SOURCES = t-cmp_d.c
+t_cmp_d_OBJECTS = t-cmp_d.$(OBJEXT)
+t_cmp_d_LDADD = $(LDADD)
+t_cmp_d_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_cmp_si_SOURCES = t-cmp_si.c
+t_cmp_si_OBJECTS = t-cmp_si.$(OBJEXT)
+t_cmp_si_LDADD = $(LDADD)
+t_cmp_si_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_cong_SOURCES = t-cong.c
+t_cong_OBJECTS = t-cong.$(OBJEXT)
+t_cong_LDADD = $(LDADD)
+t_cong_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_cong_2exp_SOURCES = t-cong_2exp.c
+t_cong_2exp_OBJECTS = t-cong_2exp.$(OBJEXT)
+t_cong_2exp_LDADD = $(LDADD)
+t_cong_2exp_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_div_2exp_SOURCES = t-div_2exp.c
+t_div_2exp_OBJECTS = t-div_2exp.$(OBJEXT)
+t_div_2exp_LDADD = $(LDADD)
+t_div_2exp_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_divis_SOURCES = t-divis.c
+t_divis_OBJECTS = t-divis.$(OBJEXT)
+t_divis_LDADD = $(LDADD)
+t_divis_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_divis_2exp_SOURCES = t-divis_2exp.c
+t_divis_2exp_OBJECTS = t-divis_2exp.$(OBJEXT)
+t_divis_2exp_LDADD = $(LDADD)
+t_divis_2exp_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_export_SOURCES = t-export.c
+t_export_OBJECTS = t-export.$(OBJEXT)
+t_export_LDADD = $(LDADD)
+t_export_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_fac_ui_SOURCES = t-fac_ui.c
+t_fac_ui_OBJECTS = t-fac_ui.$(OBJEXT)
+t_fac_ui_LDADD = $(LDADD)
+t_fac_ui_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_fdiv_SOURCES = t-fdiv.c
+t_fdiv_OBJECTS = t-fdiv.$(OBJEXT)
+t_fdiv_LDADD = $(LDADD)
+t_fdiv_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_fdiv_ui_SOURCES = t-fdiv_ui.c
+t_fdiv_ui_OBJECTS = t-fdiv_ui.$(OBJEXT)
+t_fdiv_ui_LDADD = $(LDADD)
+t_fdiv_ui_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_fib_ui_SOURCES = t-fib_ui.c
+t_fib_ui_OBJECTS = t-fib_ui.$(OBJEXT)
+t_fib_ui_LDADD = $(LDADD)
+t_fib_ui_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_fits_SOURCES = t-fits.c
+t_fits_OBJECTS = t-fits.$(OBJEXT)
+t_fits_LDADD = $(LDADD)
+t_fits_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_gcd_SOURCES = t-gcd.c
+t_gcd_OBJECTS = t-gcd.$(OBJEXT)
+t_gcd_LDADD = $(LDADD)
+t_gcd_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_gcd_ui_SOURCES = t-gcd_ui.c
+t_gcd_ui_OBJECTS = t-gcd_ui.$(OBJEXT)
+t_gcd_ui_LDADD = $(LDADD)
+t_gcd_ui_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_get_d_SOURCES = t-get_d.c
+t_get_d_OBJECTS = t-get_d.$(OBJEXT)
+t_get_d_LDADD = $(LDADD)
+t_get_d_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_get_d_2exp_SOURCES = t-get_d_2exp.c
+t_get_d_2exp_OBJECTS = t-get_d_2exp.$(OBJEXT)
+t_get_d_2exp_LDADD = $(LDADD)
+t_get_d_2exp_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_get_si_SOURCES = t-get_si.c
+t_get_si_OBJECTS = t-get_si.$(OBJEXT)
+t_get_si_LDADD = $(LDADD)
+t_get_si_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_hamdist_SOURCES = t-hamdist.c
+t_hamdist_OBJECTS = t-hamdist.$(OBJEXT)
+t_hamdist_LDADD = $(LDADD)
+t_hamdist_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_import_SOURCES = t-import.c
+t_import_OBJECTS = t-import.$(OBJEXT)
+t_import_LDADD = $(LDADD)
+t_import_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_inp_str_SOURCES = t-inp_str.c
+t_inp_str_OBJECTS = t-inp_str.$(OBJEXT)
+t_inp_str_LDADD = $(LDADD)
+t_inp_str_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_invert_SOURCES = t-invert.c
+t_invert_OBJECTS = t-invert.$(OBJEXT)
+t_invert_LDADD = $(LDADD)
+t_invert_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_io_raw_SOURCES = t-io_raw.c
+t_io_raw_OBJECTS = t-io_raw.$(OBJEXT)
+t_io_raw_LDADD = $(LDADD)
+t_io_raw_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_jac_SOURCES = t-jac.c
+t_jac_OBJECTS = t-jac.$(OBJEXT)
+t_jac_LDADD = $(LDADD)
+t_jac_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_lcm_SOURCES = t-lcm.c
+t_lcm_OBJECTS = t-lcm.$(OBJEXT)
+t_lcm_LDADD = $(LDADD)
+t_lcm_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_limbs_SOURCES = t-limbs.c
+t_limbs_OBJECTS = t-limbs.$(OBJEXT)
+t_limbs_LDADD = $(LDADD)
+t_limbs_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_lucm_SOURCES = t-lucm.c
+t_lucm_OBJECTS = t-lucm.$(OBJEXT)
+t_lucm_LDADD = $(LDADD)
+t_lucm_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_lucnum_ui_SOURCES = t-lucnum_ui.c
+t_lucnum_ui_OBJECTS = t-lucnum_ui.$(OBJEXT)
+t_lucnum_ui_LDADD = $(LDADD)
+t_lucnum_ui_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_mfac_uiui_SOURCES = t-mfac_uiui.c
+t_mfac_uiui_OBJECTS = t-mfac_uiui.$(OBJEXT)
+t_mfac_uiui_LDADD = $(LDADD)
+t_mfac_uiui_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_mul_SOURCES = t-mul.c
+t_mul_OBJECTS = t-mul.$(OBJEXT)
+t_mul_LDADD = $(LDADD)
+t_mul_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_mul_i_SOURCES = t-mul_i.c
+t_mul_i_OBJECTS = t-mul_i.$(OBJEXT)
+t_mul_i_LDADD = $(LDADD)
+t_mul_i_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_nextprime_SOURCES = t-nextprime.c
+t_nextprime_OBJECTS = t-nextprime.$(OBJEXT)
+t_nextprime_LDADD = $(LDADD)
+t_nextprime_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_oddeven_SOURCES = t-oddeven.c
+t_oddeven_OBJECTS = t-oddeven.$(OBJEXT)
+t_oddeven_LDADD = $(LDADD)
+t_oddeven_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_perfpow_SOURCES = t-perfpow.c
+t_perfpow_OBJECTS = t-perfpow.$(OBJEXT)
+t_perfpow_LDADD = $(LDADD)
+t_perfpow_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_perfsqr_SOURCES = t-perfsqr.c
+t_perfsqr_OBJECTS = t-perfsqr.$(OBJEXT)
+t_perfsqr_LDADD = $(LDADD)
+t_perfsqr_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_popcount_SOURCES = t-popcount.c
+t_popcount_OBJECTS = t-popcount.$(OBJEXT)
+t_popcount_LDADD = $(LDADD)
+t_popcount_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_pow_SOURCES = t-pow.c
+t_pow_OBJECTS = t-pow.$(OBJEXT)
+t_pow_LDADD = $(LDADD)
+t_pow_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_powm_SOURCES = t-powm.c
+t_powm_OBJECTS = t-powm.$(OBJEXT)
+t_powm_LDADD = $(LDADD)
+t_powm_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_powm_ui_SOURCES = t-powm_ui.c
+t_powm_ui_OBJECTS = t-powm_ui.$(OBJEXT)
+t_powm_ui_LDADD = $(LDADD)
+t_powm_ui_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_pprime_p_SOURCES = t-pprime_p.c
+t_pprime_p_OBJECTS = t-pprime_p.$(OBJEXT)
+t_pprime_p_LDADD = $(LDADD)
+t_pprime_p_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_primorial_ui_SOURCES = t-primorial_ui.c
+t_primorial_ui_OBJECTS = t-primorial_ui.$(OBJEXT)
+t_primorial_ui_LDADD = $(LDADD)
+t_primorial_ui_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_remove_SOURCES = t-remove.c
+t_remove_OBJECTS = t-remove.$(OBJEXT)
+t_remove_LDADD = $(LDADD)
+t_remove_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_root_SOURCES = t-root.c
+t_root_OBJECTS = t-root.$(OBJEXT)
+t_root_LDADD = $(LDADD)
+t_root_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_scan_SOURCES = t-scan.c
+t_scan_OBJECTS = t-scan.$(OBJEXT)
+t_scan_LDADD = $(LDADD)
+t_scan_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_set_d_SOURCES = t-set_d.c
+t_set_d_OBJECTS = t-set_d.$(OBJEXT)
+t_set_d_LDADD = $(LDADD)
+t_set_d_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_set_f_SOURCES = t-set_f.c
+t_set_f_OBJECTS = t-set_f.$(OBJEXT)
+t_set_f_LDADD = $(LDADD)
+t_set_f_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_set_si_SOURCES = t-set_si.c
+t_set_si_OBJECTS = t-set_si.$(OBJEXT)
+t_set_si_LDADD = $(LDADD)
+t_set_si_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_set_str_SOURCES = t-set_str.c
+t_set_str_OBJECTS = t-set_str.$(OBJEXT)
+t_set_str_LDADD = $(LDADD)
+t_set_str_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_sizeinbase_SOURCES = t-sizeinbase.c
+t_sizeinbase_OBJECTS = t-sizeinbase.$(OBJEXT)
+t_sizeinbase_LDADD = $(LDADD)
+t_sizeinbase_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_sqrtrem_SOURCES = t-sqrtrem.c
+t_sqrtrem_OBJECTS = t-sqrtrem.$(OBJEXT)
+t_sqrtrem_LDADD = $(LDADD)
+t_sqrtrem_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_tdiv_SOURCES = t-tdiv.c
+t_tdiv_OBJECTS = t-tdiv.$(OBJEXT)
+t_tdiv_LDADD = $(LDADD)
+t_tdiv_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_tdiv_ui_SOURCES = t-tdiv_ui.c
+t_tdiv_ui_OBJECTS = t-tdiv_ui.$(OBJEXT)
+t_tdiv_ui_LDADD = $(LDADD)
+t_tdiv_ui_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp =
+am__depfiles_maybe =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+SOURCES = bit.c convert.c dive.c dive_ui.c io.c logic.c reuse.c \
+	t-addsub.c t-aorsmul.c t-bin.c t-cdiv_ui.c t-cmp.c t-cmp_d.c \
+	t-cmp_si.c t-cong.c t-cong_2exp.c t-div_2exp.c t-divis.c \
+	t-divis_2exp.c t-export.c t-fac_ui.c t-fdiv.c t-fdiv_ui.c \
+	t-fib_ui.c t-fits.c t-gcd.c t-gcd_ui.c t-get_d.c \
+	t-get_d_2exp.c t-get_si.c t-hamdist.c t-import.c t-inp_str.c \
+	t-invert.c t-io_raw.c t-jac.c t-lcm.c t-limbs.c t-lucm.c \
+	t-lucnum_ui.c t-mfac_uiui.c t-mul.c t-mul_i.c t-nextprime.c \
+	t-oddeven.c t-perfpow.c t-perfsqr.c t-popcount.c t-pow.c \
+	t-powm.c t-powm_ui.c t-pprime_p.c t-primorial_ui.c t-remove.c \
+	t-root.c t-scan.c t-set_d.c t-set_f.c t-set_si.c t-set_str.c \
+	t-sizeinbase.c t-sqrtrem.c t-tdiv.c t-tdiv_ui.c
+DIST_SOURCES = bit.c convert.c dive.c dive_ui.c io.c logic.c reuse.c \
+	t-addsub.c t-aorsmul.c t-bin.c t-cdiv_ui.c t-cmp.c t-cmp_d.c \
+	t-cmp_si.c t-cong.c t-cong_2exp.c t-div_2exp.c t-divis.c \
+	t-divis_2exp.c t-export.c t-fac_ui.c t-fdiv.c t-fdiv_ui.c \
+	t-fib_ui.c t-fits.c t-gcd.c t-gcd_ui.c t-get_d.c \
+	t-get_d_2exp.c t-get_si.c t-hamdist.c t-import.c t-inp_str.c \
+	t-invert.c t-io_raw.c t-jac.c t-lcm.c t-limbs.c t-lucm.c \
+	t-lucnum_ui.c t-mfac_uiui.c t-mul.c t-mul_i.c t-nextprime.c \
+	t-oddeven.c t-perfpow.c t-perfsqr.c t-popcount.c t-pow.c \
+	t-powm.c t-powm_ui.c t-pprime_p.c t-primorial_ui.c t-remove.c \
+	t-root.c t-scan.c t-set_d.c t-set_f.c t-set_si.c t-set_str.c \
+	t-sizeinbase.c t-sqrtrem.c t-tdiv.c t-tdiv_ui.c
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__tty_colors_dummy = \
+  mgn= red= grn= lgn= blu= brg= std=; \
+  am__color_tests=no
+am__tty_colors = { \
+  $(am__tty_colors_dummy); \
+  if test "X$(AM_COLOR_TESTS)" = Xno; then \
+    am__color_tests=no; \
+  elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+    am__color_tests=yes; \
+  elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+    am__color_tests=yes; \
+  fi; \
+  if test $$am__color_tests = yes; then \
+    red=''; \
+    grn=''; \
+    lgn=''; \
+    blu=''; \
+    mgn=''; \
+    brg=''; \
+    std=''; \
+  fi; \
+}
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+  test -z "$$files" \
+    || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+    || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+         $(am__cd) "$$dir" && rm -f $$files; }; \
+  }
+am__recheck_rx = ^[ 	]*:recheck:[ 	]*
+am__global_test_result_rx = ^[ 	]*:global-test-result:[ 	]*
+am__copy_in_global_log_rx = ^[ 	]*:copy-in-global-log:[ 	]*
+# A command that, given a newline-separated list of test names on the
+# standard input, print the name of the tests that are to be re-run
+# upon "make recheck".
+am__list_recheck_tests = $(AWK) '{ \
+  recheck = 1; \
+  while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+    { \
+      if (rc < 0) \
+        { \
+          if ((getline line2 < ($$0 ".log")) < 0) \
+	    recheck = 0; \
+          break; \
+        } \
+      else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \
+        { \
+          recheck = 0; \
+          break; \
+        } \
+      else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \
+        { \
+          break; \
+        } \
+    }; \
+  if (recheck) \
+    print $$0; \
+  close ($$0 ".trs"); \
+  close ($$0 ".log"); \
+}'
+# A command that, given a newline-separated list of test names on the
+# standard input, create the global log from their .trs and .log files.
+am__create_global_log = $(AWK) ' \
+function fatal(msg) \
+{ \
+  print "fatal: making $@: " msg | "cat >&2"; \
+  exit 1; \
+} \
+function rst_section(header) \
+{ \
+  print header; \
+  len = length(header); \
+  for (i = 1; i <= len; i = i + 1) \
+    printf "="; \
+  printf "\n\n"; \
+} \
+{ \
+  copy_in_global_log = 1; \
+  global_test_result = "RUN"; \
+  while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+    { \
+      if (rc < 0) \
+         fatal("failed to read from " $$0 ".trs"); \
+      if (line ~ /$(am__global_test_result_rx)/) \
+        { \
+          sub("$(am__global_test_result_rx)", "", line); \
+          sub("[ 	]*$$", "", line); \
+          global_test_result = line; \
+        } \
+      else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \
+        copy_in_global_log = 0; \
+    }; \
+  if (copy_in_global_log) \
+    { \
+      rst_section(global_test_result ": " $$0); \
+      while ((rc = (getline line < ($$0 ".log"))) != 0) \
+      { \
+        if (rc < 0) \
+          fatal("failed to read from " $$0 ".log"); \
+        print line; \
+      }; \
+      printf "\n"; \
+    }; \
+  close ($$0 ".trs"); \
+  close ($$0 ".log"); \
+}'
+# Restructured Text title.
+am__rst_title = { sed 's/.*/   &   /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; }
+# Solaris 10 'make', and several other traditional 'make' implementations,
+# pass "-e" to $(SHELL), and POSIX 2008 even requires this.  Work around it
+# by disabling -e (using the XSI extension "set +e") if it's set.
+am__sh_e_setup = case $$- in *e*) set +e;; esac
+# Default flags passed to test drivers.
+am__common_driver_flags = \
+  --color-tests "$$am__color_tests" \
+  --enable-hard-errors "$$am__enable_hard_errors" \
+  --expect-failure "$$am__expect_failure"
+# To be inserted before the command running the test.  Creates the
+# directory for the log if needed.  Stores in $dir the directory
+# containing $f, in $tst the test, in $log the log.  Executes the
+# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and
+# passes TESTS_ENVIRONMENT.  Set up options for the wrapper that
+# will run the test scripts (or their associated LOG_COMPILER, if
+# thy have one).
+am__check_pre = \
+$(am__sh_e_setup);					\
+$(am__vpath_adj_setup) $(am__vpath_adj)			\
+$(am__tty_colors);					\
+srcdir=$(srcdir); export srcdir;			\
+case "$@" in						\
+  */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;;	\
+    *) am__odir=.;; 					\
+esac;							\
+test "x$$am__odir" = x"." || test -d "$$am__odir" 	\
+  || $(MKDIR_P) "$$am__odir" || exit $$?;		\
+if test -f "./$$f"; then dir=./;			\
+elif test -f "$$f"; then dir=;				\
+else dir="$(srcdir)/"; fi;				\
+tst=$$dir$$f; log='$@'; 				\
+if test -n '$(DISABLE_HARD_ERRORS)'; then		\
+  am__enable_hard_errors=no; 				\
+else							\
+  am__enable_hard_errors=yes; 				\
+fi; 							\
+case " $(XFAIL_TESTS) " in				\
+  *[\ \	]$$f[\ \	]* | *[\ \	]$$dir$$f[\ \	]*) \
+    am__expect_failure=yes;;				\
+  *)							\
+    am__expect_failure=no;;				\
+esac; 							\
+$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT)
+# A shell command to get the names of the tests scripts with any registered
+# extension removed (i.e., equivalently, the names of the test logs, with
+# the '.log' extension removed).  The result is saved in the shell variable
+# '$bases'.  This honors runtime overriding of TESTS and TEST_LOGS.  Sadly,
+# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)",
+# since that might cause problem with VPATH rewrites for suffix-less tests.
+# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'.
+am__set_TESTS_bases = \
+  bases='$(TEST_LOGS)'; \
+  bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \
+  bases=`echo $$bases`
+RECHECK_LOGS = $(TEST_LOGS)
+AM_RECURSIVE_TARGETS = check recheck
+TEST_SUITE_LOG = test-suite.log
+TEST_EXTENSIONS = @EXEEXT@ .test
+LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS)
+am__set_b = \
+  case '$@' in \
+    */*) \
+      case '$*' in \
+        */*) b='$*';; \
+          *) b=`echo '$@' | sed 's/\.log$$//'`; \
+       esac;; \
+    *) \
+      b='$*';; \
+  esac
+am__test_logs1 = $(TESTS:=.log)
+am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log)
+TEST_LOGS = $(am__test_logs2:.test.log=.log)
+TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \
+	$(TEST_LOG_FLAGS)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/test-driver
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ABI = @ABI@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+ASMFLAGS = @ASMFLAGS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CALLING_CONVENTIONS_OBJS = @CALLING_CONVENTIONS_OBJS@
+CC = @CC@
+CCAS = @CCAS@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPP_FOR_BUILD = @CPP_FOR_BUILD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFN_LONG_LONG_LIMB = @DEFN_LONG_LONG_LIMB@
+DEFS = @DEFS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@
+FGREP = @FGREP@
+GMP_LDFLAGS = @GMP_LDFLAGS@
+GMP_LIMB_BITS = @GMP_LIMB_BITS@
+GMP_NAIL_BITS = @GMP_NAIL_BITS@
+GREP = @GREP@
+HAVE_CLOCK_01 = @HAVE_CLOCK_01@
+HAVE_CPUTIME_01 = @HAVE_CPUTIME_01@
+HAVE_GETRUSAGE_01 = @HAVE_GETRUSAGE_01@
+HAVE_GETTIMEOFDAY_01 = @HAVE_GETTIMEOFDAY_01@
+HAVE_HOST_CPU_FAMILY_power = @HAVE_HOST_CPU_FAMILY_power@
+HAVE_HOST_CPU_FAMILY_powerpc = @HAVE_HOST_CPU_FAMILY_powerpc@
+HAVE_SIGACTION_01 = @HAVE_SIGACTION_01@
+HAVE_SIGALTSTACK_01 = @HAVE_SIGALTSTACK_01@
+HAVE_SIGSTACK_01 = @HAVE_SIGSTACK_01@
+HAVE_STACK_T_01 = @HAVE_STACK_T_01@
+HAVE_SYS_RESOURCE_H_01 = @HAVE_SYS_RESOURCE_H_01@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCURSES = @LIBCURSES@
+LIBGMPXX_LDFLAGS = @LIBGMPXX_LDFLAGS@
+LIBGMP_DLL = @LIBGMP_DLL@
+LIBGMP_LDFLAGS = @LIBGMP_LDFLAGS@
+LIBM = @LIBM@
+LIBM_FOR_BUILD = @LIBM_FOR_BUILD@
+LIBOBJS = @LIBOBJS@
+LIBREADLINE = @LIBREADLINE@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+M4 = @M4@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPEED_CYCLECOUNTER_OBJ = @SPEED_CYCLECOUNTER_OBJ@
+STRIP = @STRIP@
+TAL_OBJECT = @TAL_OBJECT@
+TUNE_LIBS = @TUNE_LIBS@
+TUNE_SQR_OBJ = @TUNE_SQR_OBJ@
+U_FOR_BUILD = @U_FOR_BUILD@
+VERSION = @VERSION@
+WITH_READLINE_01 = @WITH_READLINE_01@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__leading_dot = @am__leading_dot@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gmp_srclinks = @gmp_srclinks@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+mpn_objects = @mpn_objects@
+mpn_objs_in_libgmp = @mpn_objs_in_libgmp@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/tests
+AM_LDFLAGS = -no-install
+LDADD = $(top_builddir)/tests/libtests.la $(top_builddir)/libgmp.la
+TESTS = $(check_PROGRAMS)
+
+# Temporary files used by the tests.  Removed automatically if the tests
+# pass, but ensure they're cleaned if they fail.
+#
+CLEANFILES = *.tmp
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .log .o .obj .test .test$(EXEEXT) .trs
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu --ignore-deps tests/mpz/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu --ignore-deps tests/mpz/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-checkPROGRAMS:
+	@list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
+	echo " rm -f" $$list; \
+	rm -f $$list || exit $$?; \
+	test -n "$(EXEEXT)" || exit 0; \
+	list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+	echo " rm -f" $$list; \
+	rm -f $$list
+
+bit$(EXEEXT): $(bit_OBJECTS) $(bit_DEPENDENCIES) $(EXTRA_bit_DEPENDENCIES) 
+	@rm -f bit$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(bit_OBJECTS) $(bit_LDADD) $(LIBS)
+
+convert$(EXEEXT): $(convert_OBJECTS) $(convert_DEPENDENCIES) $(EXTRA_convert_DEPENDENCIES) 
+	@rm -f convert$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(convert_OBJECTS) $(convert_LDADD) $(LIBS)
+
+dive$(EXEEXT): $(dive_OBJECTS) $(dive_DEPENDENCIES) $(EXTRA_dive_DEPENDENCIES) 
+	@rm -f dive$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(dive_OBJECTS) $(dive_LDADD) $(LIBS)
+
+dive_ui$(EXEEXT): $(dive_ui_OBJECTS) $(dive_ui_DEPENDENCIES) $(EXTRA_dive_ui_DEPENDENCIES) 
+	@rm -f dive_ui$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(dive_ui_OBJECTS) $(dive_ui_LDADD) $(LIBS)
+
+io$(EXEEXT): $(io_OBJECTS) $(io_DEPENDENCIES) $(EXTRA_io_DEPENDENCIES) 
+	@rm -f io$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(io_OBJECTS) $(io_LDADD) $(LIBS)
+
+logic$(EXEEXT): $(logic_OBJECTS) $(logic_DEPENDENCIES) $(EXTRA_logic_DEPENDENCIES) 
+	@rm -f logic$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(logic_OBJECTS) $(logic_LDADD) $(LIBS)
+
+reuse$(EXEEXT): $(reuse_OBJECTS) $(reuse_DEPENDENCIES) $(EXTRA_reuse_DEPENDENCIES) 
+	@rm -f reuse$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(reuse_OBJECTS) $(reuse_LDADD) $(LIBS)
+
+t-addsub$(EXEEXT): $(t_addsub_OBJECTS) $(t_addsub_DEPENDENCIES) $(EXTRA_t_addsub_DEPENDENCIES) 
+	@rm -f t-addsub$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_addsub_OBJECTS) $(t_addsub_LDADD) $(LIBS)
+
+t-aorsmul$(EXEEXT): $(t_aorsmul_OBJECTS) $(t_aorsmul_DEPENDENCIES) $(EXTRA_t_aorsmul_DEPENDENCIES) 
+	@rm -f t-aorsmul$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_aorsmul_OBJECTS) $(t_aorsmul_LDADD) $(LIBS)
+
+t-bin$(EXEEXT): $(t_bin_OBJECTS) $(t_bin_DEPENDENCIES) $(EXTRA_t_bin_DEPENDENCIES) 
+	@rm -f t-bin$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_bin_OBJECTS) $(t_bin_LDADD) $(LIBS)
+
+t-cdiv_ui$(EXEEXT): $(t_cdiv_ui_OBJECTS) $(t_cdiv_ui_DEPENDENCIES) $(EXTRA_t_cdiv_ui_DEPENDENCIES) 
+	@rm -f t-cdiv_ui$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_cdiv_ui_OBJECTS) $(t_cdiv_ui_LDADD) $(LIBS)
+
+t-cmp$(EXEEXT): $(t_cmp_OBJECTS) $(t_cmp_DEPENDENCIES) $(EXTRA_t_cmp_DEPENDENCIES) 
+	@rm -f t-cmp$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_cmp_OBJECTS) $(t_cmp_LDADD) $(LIBS)
+
+t-cmp_d$(EXEEXT): $(t_cmp_d_OBJECTS) $(t_cmp_d_DEPENDENCIES) $(EXTRA_t_cmp_d_DEPENDENCIES) 
+	@rm -f t-cmp_d$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_cmp_d_OBJECTS) $(t_cmp_d_LDADD) $(LIBS)
+
+t-cmp_si$(EXEEXT): $(t_cmp_si_OBJECTS) $(t_cmp_si_DEPENDENCIES) $(EXTRA_t_cmp_si_DEPENDENCIES) 
+	@rm -f t-cmp_si$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_cmp_si_OBJECTS) $(t_cmp_si_LDADD) $(LIBS)
+
+t-cong$(EXEEXT): $(t_cong_OBJECTS) $(t_cong_DEPENDENCIES) $(EXTRA_t_cong_DEPENDENCIES) 
+	@rm -f t-cong$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_cong_OBJECTS) $(t_cong_LDADD) $(LIBS)
+
+t-cong_2exp$(EXEEXT): $(t_cong_2exp_OBJECTS) $(t_cong_2exp_DEPENDENCIES) $(EXTRA_t_cong_2exp_DEPENDENCIES) 
+	@rm -f t-cong_2exp$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_cong_2exp_OBJECTS) $(t_cong_2exp_LDADD) $(LIBS)
+
+t-div_2exp$(EXEEXT): $(t_div_2exp_OBJECTS) $(t_div_2exp_DEPENDENCIES) $(EXTRA_t_div_2exp_DEPENDENCIES) 
+	@rm -f t-div_2exp$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_div_2exp_OBJECTS) $(t_div_2exp_LDADD) $(LIBS)
+
+t-divis$(EXEEXT): $(t_divis_OBJECTS) $(t_divis_DEPENDENCIES) $(EXTRA_t_divis_DEPENDENCIES) 
+	@rm -f t-divis$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_divis_OBJECTS) $(t_divis_LDADD) $(LIBS)
+
+t-divis_2exp$(EXEEXT): $(t_divis_2exp_OBJECTS) $(t_divis_2exp_DEPENDENCIES) $(EXTRA_t_divis_2exp_DEPENDENCIES) 
+	@rm -f t-divis_2exp$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_divis_2exp_OBJECTS) $(t_divis_2exp_LDADD) $(LIBS)
+
+t-export$(EXEEXT): $(t_export_OBJECTS) $(t_export_DEPENDENCIES) $(EXTRA_t_export_DEPENDENCIES) 
+	@rm -f t-export$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_export_OBJECTS) $(t_export_LDADD) $(LIBS)
+
+t-fac_ui$(EXEEXT): $(t_fac_ui_OBJECTS) $(t_fac_ui_DEPENDENCIES) $(EXTRA_t_fac_ui_DEPENDENCIES) 
+	@rm -f t-fac_ui$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_fac_ui_OBJECTS) $(t_fac_ui_LDADD) $(LIBS)
+
+t-fdiv$(EXEEXT): $(t_fdiv_OBJECTS) $(t_fdiv_DEPENDENCIES) $(EXTRA_t_fdiv_DEPENDENCIES) 
+	@rm -f t-fdiv$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_fdiv_OBJECTS) $(t_fdiv_LDADD) $(LIBS)
+
+t-fdiv_ui$(EXEEXT): $(t_fdiv_ui_OBJECTS) $(t_fdiv_ui_DEPENDENCIES) $(EXTRA_t_fdiv_ui_DEPENDENCIES) 
+	@rm -f t-fdiv_ui$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_fdiv_ui_OBJECTS) $(t_fdiv_ui_LDADD) $(LIBS)
+
+t-fib_ui$(EXEEXT): $(t_fib_ui_OBJECTS) $(t_fib_ui_DEPENDENCIES) $(EXTRA_t_fib_ui_DEPENDENCIES) 
+	@rm -f t-fib_ui$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_fib_ui_OBJECTS) $(t_fib_ui_LDADD) $(LIBS)
+
+t-fits$(EXEEXT): $(t_fits_OBJECTS) $(t_fits_DEPENDENCIES) $(EXTRA_t_fits_DEPENDENCIES) 
+	@rm -f t-fits$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_fits_OBJECTS) $(t_fits_LDADD) $(LIBS)
+
+t-gcd$(EXEEXT): $(t_gcd_OBJECTS) $(t_gcd_DEPENDENCIES) $(EXTRA_t_gcd_DEPENDENCIES) 
+	@rm -f t-gcd$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_gcd_OBJECTS) $(t_gcd_LDADD) $(LIBS)
+
+t-gcd_ui$(EXEEXT): $(t_gcd_ui_OBJECTS) $(t_gcd_ui_DEPENDENCIES) $(EXTRA_t_gcd_ui_DEPENDENCIES) 
+	@rm -f t-gcd_ui$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_gcd_ui_OBJECTS) $(t_gcd_ui_LDADD) $(LIBS)
+
+t-get_d$(EXEEXT): $(t_get_d_OBJECTS) $(t_get_d_DEPENDENCIES) $(EXTRA_t_get_d_DEPENDENCIES) 
+	@rm -f t-get_d$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_get_d_OBJECTS) $(t_get_d_LDADD) $(LIBS)
+
+t-get_d_2exp$(EXEEXT): $(t_get_d_2exp_OBJECTS) $(t_get_d_2exp_DEPENDENCIES) $(EXTRA_t_get_d_2exp_DEPENDENCIES) 
+	@rm -f t-get_d_2exp$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_get_d_2exp_OBJECTS) $(t_get_d_2exp_LDADD) $(LIBS)
+
+t-get_si$(EXEEXT): $(t_get_si_OBJECTS) $(t_get_si_DEPENDENCIES) $(EXTRA_t_get_si_DEPENDENCIES) 
+	@rm -f t-get_si$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_get_si_OBJECTS) $(t_get_si_LDADD) $(LIBS)
+
+t-hamdist$(EXEEXT): $(t_hamdist_OBJECTS) $(t_hamdist_DEPENDENCIES) $(EXTRA_t_hamdist_DEPENDENCIES) 
+	@rm -f t-hamdist$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_hamdist_OBJECTS) $(t_hamdist_LDADD) $(LIBS)
+
+t-import$(EXEEXT): $(t_import_OBJECTS) $(t_import_DEPENDENCIES) $(EXTRA_t_import_DEPENDENCIES) 
+	@rm -f t-import$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_import_OBJECTS) $(t_import_LDADD) $(LIBS)
+
+t-inp_str$(EXEEXT): $(t_inp_str_OBJECTS) $(t_inp_str_DEPENDENCIES) $(EXTRA_t_inp_str_DEPENDENCIES) 
+	@rm -f t-inp_str$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_inp_str_OBJECTS) $(t_inp_str_LDADD) $(LIBS)
+
+t-invert$(EXEEXT): $(t_invert_OBJECTS) $(t_invert_DEPENDENCIES) $(EXTRA_t_invert_DEPENDENCIES) 
+	@rm -f t-invert$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_invert_OBJECTS) $(t_invert_LDADD) $(LIBS)
+
+t-io_raw$(EXEEXT): $(t_io_raw_OBJECTS) $(t_io_raw_DEPENDENCIES) $(EXTRA_t_io_raw_DEPENDENCIES) 
+	@rm -f t-io_raw$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_io_raw_OBJECTS) $(t_io_raw_LDADD) $(LIBS)
+
+t-jac$(EXEEXT): $(t_jac_OBJECTS) $(t_jac_DEPENDENCIES) $(EXTRA_t_jac_DEPENDENCIES) 
+	@rm -f t-jac$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_jac_OBJECTS) $(t_jac_LDADD) $(LIBS)
+
+t-lcm$(EXEEXT): $(t_lcm_OBJECTS) $(t_lcm_DEPENDENCIES) $(EXTRA_t_lcm_DEPENDENCIES) 
+	@rm -f t-lcm$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_lcm_OBJECTS) $(t_lcm_LDADD) $(LIBS)
+
+t-limbs$(EXEEXT): $(t_limbs_OBJECTS) $(t_limbs_DEPENDENCIES) $(EXTRA_t_limbs_DEPENDENCIES) 
+	@rm -f t-limbs$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_limbs_OBJECTS) $(t_limbs_LDADD) $(LIBS)
+
+t-lucm$(EXEEXT): $(t_lucm_OBJECTS) $(t_lucm_DEPENDENCIES) $(EXTRA_t_lucm_DEPENDENCIES) 
+	@rm -f t-lucm$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_lucm_OBJECTS) $(t_lucm_LDADD) $(LIBS)
+
+t-lucnum_ui$(EXEEXT): $(t_lucnum_ui_OBJECTS) $(t_lucnum_ui_DEPENDENCIES) $(EXTRA_t_lucnum_ui_DEPENDENCIES) 
+	@rm -f t-lucnum_ui$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_lucnum_ui_OBJECTS) $(t_lucnum_ui_LDADD) $(LIBS)
+
+t-mfac_uiui$(EXEEXT): $(t_mfac_uiui_OBJECTS) $(t_mfac_uiui_DEPENDENCIES) $(EXTRA_t_mfac_uiui_DEPENDENCIES) 
+	@rm -f t-mfac_uiui$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_mfac_uiui_OBJECTS) $(t_mfac_uiui_LDADD) $(LIBS)
+
+t-mul$(EXEEXT): $(t_mul_OBJECTS) $(t_mul_DEPENDENCIES) $(EXTRA_t_mul_DEPENDENCIES) 
+	@rm -f t-mul$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_mul_OBJECTS) $(t_mul_LDADD) $(LIBS)
+
+t-mul_i$(EXEEXT): $(t_mul_i_OBJECTS) $(t_mul_i_DEPENDENCIES) $(EXTRA_t_mul_i_DEPENDENCIES) 
+	@rm -f t-mul_i$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_mul_i_OBJECTS) $(t_mul_i_LDADD) $(LIBS)
+
+t-nextprime$(EXEEXT): $(t_nextprime_OBJECTS) $(t_nextprime_DEPENDENCIES) $(EXTRA_t_nextprime_DEPENDENCIES) 
+	@rm -f t-nextprime$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_nextprime_OBJECTS) $(t_nextprime_LDADD) $(LIBS)
+
+t-oddeven$(EXEEXT): $(t_oddeven_OBJECTS) $(t_oddeven_DEPENDENCIES) $(EXTRA_t_oddeven_DEPENDENCIES) 
+	@rm -f t-oddeven$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_oddeven_OBJECTS) $(t_oddeven_LDADD) $(LIBS)
+
+t-perfpow$(EXEEXT): $(t_perfpow_OBJECTS) $(t_perfpow_DEPENDENCIES) $(EXTRA_t_perfpow_DEPENDENCIES) 
+	@rm -f t-perfpow$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_perfpow_OBJECTS) $(t_perfpow_LDADD) $(LIBS)
+
+t-perfsqr$(EXEEXT): $(t_perfsqr_OBJECTS) $(t_perfsqr_DEPENDENCIES) $(EXTRA_t_perfsqr_DEPENDENCIES) 
+	@rm -f t-perfsqr$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_perfsqr_OBJECTS) $(t_perfsqr_LDADD) $(LIBS)
+
+t-popcount$(EXEEXT): $(t_popcount_OBJECTS) $(t_popcount_DEPENDENCIES) $(EXTRA_t_popcount_DEPENDENCIES) 
+	@rm -f t-popcount$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_popcount_OBJECTS) $(t_popcount_LDADD) $(LIBS)
+
+t-pow$(EXEEXT): $(t_pow_OBJECTS) $(t_pow_DEPENDENCIES) $(EXTRA_t_pow_DEPENDENCIES) 
+	@rm -f t-pow$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_pow_OBJECTS) $(t_pow_LDADD) $(LIBS)
+
+t-powm$(EXEEXT): $(t_powm_OBJECTS) $(t_powm_DEPENDENCIES) $(EXTRA_t_powm_DEPENDENCIES) 
+	@rm -f t-powm$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_powm_OBJECTS) $(t_powm_LDADD) $(LIBS)
+
+t-powm_ui$(EXEEXT): $(t_powm_ui_OBJECTS) $(t_powm_ui_DEPENDENCIES) $(EXTRA_t_powm_ui_DEPENDENCIES) 
+	@rm -f t-powm_ui$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_powm_ui_OBJECTS) $(t_powm_ui_LDADD) $(LIBS)
+
+t-pprime_p$(EXEEXT): $(t_pprime_p_OBJECTS) $(t_pprime_p_DEPENDENCIES) $(EXTRA_t_pprime_p_DEPENDENCIES) 
+	@rm -f t-pprime_p$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_pprime_p_OBJECTS) $(t_pprime_p_LDADD) $(LIBS)
+
+t-primorial_ui$(EXEEXT): $(t_primorial_ui_OBJECTS) $(t_primorial_ui_DEPENDENCIES) $(EXTRA_t_primorial_ui_DEPENDENCIES) 
+	@rm -f t-primorial_ui$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_primorial_ui_OBJECTS) $(t_primorial_ui_LDADD) $(LIBS)
+
+t-remove$(EXEEXT): $(t_remove_OBJECTS) $(t_remove_DEPENDENCIES) $(EXTRA_t_remove_DEPENDENCIES) 
+	@rm -f t-remove$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_remove_OBJECTS) $(t_remove_LDADD) $(LIBS)
+
+t-root$(EXEEXT): $(t_root_OBJECTS) $(t_root_DEPENDENCIES) $(EXTRA_t_root_DEPENDENCIES) 
+	@rm -f t-root$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_root_OBJECTS) $(t_root_LDADD) $(LIBS)
+
+t-scan$(EXEEXT): $(t_scan_OBJECTS) $(t_scan_DEPENDENCIES) $(EXTRA_t_scan_DEPENDENCIES) 
+	@rm -f t-scan$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_scan_OBJECTS) $(t_scan_LDADD) $(LIBS)
+
+t-set_d$(EXEEXT): $(t_set_d_OBJECTS) $(t_set_d_DEPENDENCIES) $(EXTRA_t_set_d_DEPENDENCIES) 
+	@rm -f t-set_d$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_set_d_OBJECTS) $(t_set_d_LDADD) $(LIBS)
+
+t-set_f$(EXEEXT): $(t_set_f_OBJECTS) $(t_set_f_DEPENDENCIES) $(EXTRA_t_set_f_DEPENDENCIES) 
+	@rm -f t-set_f$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_set_f_OBJECTS) $(t_set_f_LDADD) $(LIBS)
+
+t-set_si$(EXEEXT): $(t_set_si_OBJECTS) $(t_set_si_DEPENDENCIES) $(EXTRA_t_set_si_DEPENDENCIES) 
+	@rm -f t-set_si$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_set_si_OBJECTS) $(t_set_si_LDADD) $(LIBS)
+
+t-set_str$(EXEEXT): $(t_set_str_OBJECTS) $(t_set_str_DEPENDENCIES) $(EXTRA_t_set_str_DEPENDENCIES) 
+	@rm -f t-set_str$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_set_str_OBJECTS) $(t_set_str_LDADD) $(LIBS)
+
+t-sizeinbase$(EXEEXT): $(t_sizeinbase_OBJECTS) $(t_sizeinbase_DEPENDENCIES) $(EXTRA_t_sizeinbase_DEPENDENCIES) 
+	@rm -f t-sizeinbase$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_sizeinbase_OBJECTS) $(t_sizeinbase_LDADD) $(LIBS)
+
+t-sqrtrem$(EXEEXT): $(t_sqrtrem_OBJECTS) $(t_sqrtrem_DEPENDENCIES) $(EXTRA_t_sqrtrem_DEPENDENCIES) 
+	@rm -f t-sqrtrem$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_sqrtrem_OBJECTS) $(t_sqrtrem_LDADD) $(LIBS)
+
+t-tdiv$(EXEEXT): $(t_tdiv_OBJECTS) $(t_tdiv_DEPENDENCIES) $(EXTRA_t_tdiv_DEPENDENCIES) 
+	@rm -f t-tdiv$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_tdiv_OBJECTS) $(t_tdiv_LDADD) $(LIBS)
+
+t-tdiv_ui$(EXEEXT): $(t_tdiv_ui_OBJECTS) $(t_tdiv_ui_DEPENDENCIES) $(EXTRA_t_tdiv_ui_DEPENDENCIES) 
+	@rm -f t-tdiv_ui$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_tdiv_ui_OBJECTS) $(t_tdiv_ui_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+.c.o:
+	$(AM_V_CC)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+	$(AM_V_CC)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+	$(AM_V_CC)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+# Recover from deleted '.trs' file; this should ensure that
+# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create
+# both 'foo.log' and 'foo.trs'.  Break the recipe in two subshells
+# to avoid problems with "make -n".
+.log.trs:
+	rm -f $< $@
+	$(MAKE) $(AM_MAKEFLAGS) $<
+
+# Leading 'am--fnord' is there to ensure the list of targets does not
+# expand to empty, as could happen e.g. with make check TESTS=''.
+am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck)
+am--force-recheck:
+	@:
+
+$(TEST_SUITE_LOG): $(TEST_LOGS)
+	@$(am__set_TESTS_bases); \
+	am__f_ok () { test -f "$$1" && test -r "$$1"; }; \
+	redo_bases=`for i in $$bases; do \
+	              am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \
+	            done`; \
+	if test -n "$$redo_bases"; then \
+	  redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \
+	  redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \
+	  if $(am__make_dryrun); then :; else \
+	    rm -f $$redo_logs && rm -f $$redo_results || exit 1; \
+	  fi; \
+	fi; \
+	if test -n "$$am__remaking_logs"; then \
+	  echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \
+	       "recursion detected" >&2; \
+	elif test -n "$$redo_logs"; then \
+	  am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \
+	fi; \
+	if $(am__make_dryrun); then :; else \
+	  st=0;  \
+	  errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \
+	  for i in $$redo_bases; do \
+	    test -f $$i.trs && test -r $$i.trs \
+	      || { echo "$$errmsg $$i.trs" >&2; st=1; }; \
+	    test -f $$i.log && test -r $$i.log \
+	      || { echo "$$errmsg $$i.log" >&2; st=1; }; \
+	  done; \
+	  test $$st -eq 0 || exit 1; \
+	fi
+	@$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \
+	ws='[ 	]'; \
+	results=`for b in $$bases; do echo $$b.trs; done`; \
+	test -n "$$results" || results=/dev/null; \
+	all=`  grep "^$$ws*:test-result:"           $$results | wc -l`; \
+	pass=` grep "^$$ws*:test-result:$$ws*PASS"  $$results | wc -l`; \
+	fail=` grep "^$$ws*:test-result:$$ws*FAIL"  $$results | wc -l`; \
+	skip=` grep "^$$ws*:test-result:$$ws*SKIP"  $$results | wc -l`; \
+	xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \
+	xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \
+	error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \
+	if test `expr $$fail + $$xpass + $$error` -eq 0; then \
+	  success=true; \
+	else \
+	  success=false; \
+	fi; \
+	br='==================='; br=$$br$$br$$br$$br; \
+	result_count () \
+	{ \
+	    if test x"$$1" = x"--maybe-color"; then \
+	      maybe_colorize=yes; \
+	    elif test x"$$1" = x"--no-color"; then \
+	      maybe_colorize=no; \
+	    else \
+	      echo "$@: invalid 'result_count' usage" >&2; exit 4; \
+	    fi; \
+	    shift; \
+	    desc=$$1 count=$$2; \
+	    if test $$maybe_colorize = yes && test $$count -gt 0; then \
+	      color_start=$$3 color_end=$$std; \
+	    else \
+	      color_start= color_end=; \
+	    fi; \
+	    echo "$${color_start}# $$desc $$count$${color_end}"; \
+	}; \
+	create_testsuite_report () \
+	{ \
+	  result_count $$1 "TOTAL:" $$all   "$$brg"; \
+	  result_count $$1 "PASS: " $$pass  "$$grn"; \
+	  result_count $$1 "SKIP: " $$skip  "$$blu"; \
+	  result_count $$1 "XFAIL:" $$xfail "$$lgn"; \
+	  result_count $$1 "FAIL: " $$fail  "$$red"; \
+	  result_count $$1 "XPASS:" $$xpass "$$red"; \
+	  result_count $$1 "ERROR:" $$error "$$mgn"; \
+	}; \
+	{								\
+	  echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" |	\
+	    $(am__rst_title);						\
+	  create_testsuite_report --no-color;				\
+	  echo;								\
+	  echo ".. contents:: :depth: 2";				\
+	  echo;								\
+	  for b in $$bases; do echo $$b; done				\
+	    | $(am__create_global_log);					\
+	} >$(TEST_SUITE_LOG).tmp || exit 1;				\
+	mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG);			\
+	if $$success; then						\
+	  col="$$grn";							\
+	 else								\
+	  col="$$red";							\
+	  test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG);		\
+	fi;								\
+	echo "$${col}$$br$${std}"; 					\
+	echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}";	\
+	echo "$${col}$$br$${std}"; 					\
+	create_testsuite_report --maybe-color;				\
+	echo "$$col$$br$$std";						\
+	if $$success; then :; else					\
+	  echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}";		\
+	  if test -n "$(PACKAGE_BUGREPORT)"; then			\
+	    echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}";	\
+	  fi;								\
+	  echo "$$col$$br$$std";					\
+	fi;								\
+	$$success || exit 1
+
+check-TESTS:
+	@list='$(RECHECK_LOGS)';           test -z "$$list" || rm -f $$list
+	@list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list
+	@test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+	@set +e; $(am__set_TESTS_bases); \
+	log_list=`for i in $$bases; do echo $$i.log; done`; \
+	trs_list=`for i in $$bases; do echo $$i.trs; done`; \
+	log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \
+	$(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \
+	exit $$?;
+recheck: all $(check_PROGRAMS)
+	@test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+	@set +e; $(am__set_TESTS_bases); \
+	bases=`for i in $$bases; do echo $$i; done \
+	         | $(am__list_recheck_tests)` || exit 1; \
+	log_list=`for i in $$bases; do echo $$i.log; done`; \
+	log_list=`echo $$log_list`; \
+	$(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \
+	        am__force_recheck=am--force-recheck \
+	        TEST_LOGS="$$log_list"; \
+	exit $$?
+reuse.log: reuse$(EXEEXT)
+	@p='reuse$(EXEEXT)'; \
+	b='reuse'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-addsub.log: t-addsub$(EXEEXT)
+	@p='t-addsub$(EXEEXT)'; \
+	b='t-addsub'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-cmp.log: t-cmp$(EXEEXT)
+	@p='t-cmp$(EXEEXT)'; \
+	b='t-cmp'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-mul.log: t-mul$(EXEEXT)
+	@p='t-mul$(EXEEXT)'; \
+	b='t-mul'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-mul_i.log: t-mul_i$(EXEEXT)
+	@p='t-mul_i$(EXEEXT)'; \
+	b='t-mul_i'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-tdiv.log: t-tdiv$(EXEEXT)
+	@p='t-tdiv$(EXEEXT)'; \
+	b='t-tdiv'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-tdiv_ui.log: t-tdiv_ui$(EXEEXT)
+	@p='t-tdiv_ui$(EXEEXT)'; \
+	b='t-tdiv_ui'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-fdiv.log: t-fdiv$(EXEEXT)
+	@p='t-fdiv$(EXEEXT)'; \
+	b='t-fdiv'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-fdiv_ui.log: t-fdiv_ui$(EXEEXT)
+	@p='t-fdiv_ui$(EXEEXT)'; \
+	b='t-fdiv_ui'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-cdiv_ui.log: t-cdiv_ui$(EXEEXT)
+	@p='t-cdiv_ui$(EXEEXT)'; \
+	b='t-cdiv_ui'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-gcd.log: t-gcd$(EXEEXT)
+	@p='t-gcd$(EXEEXT)'; \
+	b='t-gcd'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-gcd_ui.log: t-gcd_ui$(EXEEXT)
+	@p='t-gcd_ui$(EXEEXT)'; \
+	b='t-gcd_ui'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-lcm.log: t-lcm$(EXEEXT)
+	@p='t-lcm$(EXEEXT)'; \
+	b='t-lcm'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-invert.log: t-invert$(EXEEXT)
+	@p='t-invert$(EXEEXT)'; \
+	b='t-invert'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+dive.log: dive$(EXEEXT)
+	@p='dive$(EXEEXT)'; \
+	b='dive'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+dive_ui.log: dive_ui$(EXEEXT)
+	@p='dive_ui$(EXEEXT)'; \
+	b='dive_ui'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-sqrtrem.log: t-sqrtrem$(EXEEXT)
+	@p='t-sqrtrem$(EXEEXT)'; \
+	b='t-sqrtrem'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+convert.log: convert$(EXEEXT)
+	@p='convert$(EXEEXT)'; \
+	b='convert'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+io.log: io$(EXEEXT)
+	@p='io$(EXEEXT)'; \
+	b='io'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-inp_str.log: t-inp_str$(EXEEXT)
+	@p='t-inp_str$(EXEEXT)'; \
+	b='t-inp_str'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+logic.log: logic$(EXEEXT)
+	@p='logic$(EXEEXT)'; \
+	b='logic'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+bit.log: bit$(EXEEXT)
+	@p='bit$(EXEEXT)'; \
+	b='bit'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-powm.log: t-powm$(EXEEXT)
+	@p='t-powm$(EXEEXT)'; \
+	b='t-powm'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-powm_ui.log: t-powm_ui$(EXEEXT)
+	@p='t-powm_ui$(EXEEXT)'; \
+	b='t-powm_ui'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-pow.log: t-pow$(EXEEXT)
+	@p='t-pow$(EXEEXT)'; \
+	b='t-pow'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-div_2exp.log: t-div_2exp$(EXEEXT)
+	@p='t-div_2exp$(EXEEXT)'; \
+	b='t-div_2exp'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-root.log: t-root$(EXEEXT)
+	@p='t-root$(EXEEXT)'; \
+	b='t-root'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-perfsqr.log: t-perfsqr$(EXEEXT)
+	@p='t-perfsqr$(EXEEXT)'; \
+	b='t-perfsqr'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-perfpow.log: t-perfpow$(EXEEXT)
+	@p='t-perfpow$(EXEEXT)'; \
+	b='t-perfpow'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-jac.log: t-jac$(EXEEXT)
+	@p='t-jac$(EXEEXT)'; \
+	b='t-jac'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-bin.log: t-bin$(EXEEXT)
+	@p='t-bin$(EXEEXT)'; \
+	b='t-bin'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-get_d.log: t-get_d$(EXEEXT)
+	@p='t-get_d$(EXEEXT)'; \
+	b='t-get_d'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-get_d_2exp.log: t-get_d_2exp$(EXEEXT)
+	@p='t-get_d_2exp$(EXEEXT)'; \
+	b='t-get_d_2exp'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-get_si.log: t-get_si$(EXEEXT)
+	@p='t-get_si$(EXEEXT)'; \
+	b='t-get_si'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-set_d.log: t-set_d$(EXEEXT)
+	@p='t-set_d$(EXEEXT)'; \
+	b='t-set_d'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-set_si.log: t-set_si$(EXEEXT)
+	@p='t-set_si$(EXEEXT)'; \
+	b='t-set_si'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-lucm.log: t-lucm$(EXEEXT)
+	@p='t-lucm$(EXEEXT)'; \
+	b='t-lucm'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-fac_ui.log: t-fac_ui$(EXEEXT)
+	@p='t-fac_ui$(EXEEXT)'; \
+	b='t-fac_ui'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-mfac_uiui.log: t-mfac_uiui$(EXEEXT)
+	@p='t-mfac_uiui$(EXEEXT)'; \
+	b='t-mfac_uiui'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-primorial_ui.log: t-primorial_ui$(EXEEXT)
+	@p='t-primorial_ui$(EXEEXT)'; \
+	b='t-primorial_ui'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-fib_ui.log: t-fib_ui$(EXEEXT)
+	@p='t-fib_ui$(EXEEXT)'; \
+	b='t-fib_ui'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-lucnum_ui.log: t-lucnum_ui$(EXEEXT)
+	@p='t-lucnum_ui$(EXEEXT)'; \
+	b='t-lucnum_ui'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-scan.log: t-scan$(EXEEXT)
+	@p='t-scan$(EXEEXT)'; \
+	b='t-scan'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-fits.log: t-fits$(EXEEXT)
+	@p='t-fits$(EXEEXT)'; \
+	b='t-fits'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-divis.log: t-divis$(EXEEXT)
+	@p='t-divis$(EXEEXT)'; \
+	b='t-divis'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-divis_2exp.log: t-divis_2exp$(EXEEXT)
+	@p='t-divis_2exp$(EXEEXT)'; \
+	b='t-divis_2exp'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-cong.log: t-cong$(EXEEXT)
+	@p='t-cong$(EXEEXT)'; \
+	b='t-cong'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-cong_2exp.log: t-cong_2exp$(EXEEXT)
+	@p='t-cong_2exp$(EXEEXT)'; \
+	b='t-cong_2exp'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-sizeinbase.log: t-sizeinbase$(EXEEXT)
+	@p='t-sizeinbase$(EXEEXT)'; \
+	b='t-sizeinbase'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-set_str.log: t-set_str$(EXEEXT)
+	@p='t-set_str$(EXEEXT)'; \
+	b='t-set_str'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-aorsmul.log: t-aorsmul$(EXEEXT)
+	@p='t-aorsmul$(EXEEXT)'; \
+	b='t-aorsmul'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-cmp_d.log: t-cmp_d$(EXEEXT)
+	@p='t-cmp_d$(EXEEXT)'; \
+	b='t-cmp_d'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-cmp_si.log: t-cmp_si$(EXEEXT)
+	@p='t-cmp_si$(EXEEXT)'; \
+	b='t-cmp_si'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-hamdist.log: t-hamdist$(EXEEXT)
+	@p='t-hamdist$(EXEEXT)'; \
+	b='t-hamdist'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-oddeven.log: t-oddeven$(EXEEXT)
+	@p='t-oddeven$(EXEEXT)'; \
+	b='t-oddeven'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-popcount.log: t-popcount$(EXEEXT)
+	@p='t-popcount$(EXEEXT)'; \
+	b='t-popcount'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-set_f.log: t-set_f$(EXEEXT)
+	@p='t-set_f$(EXEEXT)'; \
+	b='t-set_f'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-io_raw.log: t-io_raw$(EXEEXT)
+	@p='t-io_raw$(EXEEXT)'; \
+	b='t-io_raw'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-import.log: t-import$(EXEEXT)
+	@p='t-import$(EXEEXT)'; \
+	b='t-import'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-export.log: t-export$(EXEEXT)
+	@p='t-export$(EXEEXT)'; \
+	b='t-export'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-pprime_p.log: t-pprime_p$(EXEEXT)
+	@p='t-pprime_p$(EXEEXT)'; \
+	b='t-pprime_p'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-nextprime.log: t-nextprime$(EXEEXT)
+	@p='t-nextprime$(EXEEXT)'; \
+	b='t-nextprime'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-remove.log: t-remove$(EXEEXT)
+	@p='t-remove$(EXEEXT)'; \
+	b='t-remove'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-limbs.log: t-limbs$(EXEEXT)
+	@p='t-limbs$(EXEEXT)'; \
+	b='t-limbs'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+.test.log:
+	@p='$<'; \
+	$(am__set_b); \
+	$(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+@am__EXEEXT_TRUE@.test$(EXEEXT).log:
+@am__EXEEXT_TRUE@	@p='$<'; \
+@am__EXEEXT_TRUE@	$(am__set_b); \
+@am__EXEEXT_TRUE@	$(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+@am__EXEEXT_TRUE@	--log-file $$b.log --trs-file $$b.trs \
+@am__EXEEXT_TRUE@	$(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+@am__EXEEXT_TRUE@	"$$tst" $(AM_TESTS_FD_REDIRECT)
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+	$(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+	-test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS)
+	-test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs)
+	-test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+
+clean-generic:
+	-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-TESTS check-am clean \
+	clean-checkPROGRAMS clean-generic clean-libtool cscopelist-am \
+	ctags ctags-am distclean distclean-compile distclean-generic \
+	distclean-libtool distclean-tags distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-dvi install-dvi-am install-exec \
+	install-exec-am install-html install-html-am install-info \
+	install-info-am install-man install-pdf install-pdf-am \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	recheck tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+$(top_builddir)/tests/libtests.la:
+	cd $(top_builddir)/tests; $(MAKE) $(AM_MAKEFLAGS) libtests.la
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/third_party/gmp/tests/mpz/bit.c b/third_party/gmp/tests/mpz/bit.c
new file mode 100644
index 0000000..cfcdeea
--- /dev/null
+++ b/third_party/gmp/tests/mpz/bit.c
@@ -0,0 +1,405 @@
+/* Test mpz_setbit, mpz_clrbit, mpz_tstbit.
+
+Copyright 1997, 2000-2003, 2012, 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#ifndef SIZE
+#define SIZE 4
+#endif
+
+
+void
+debug_mp (mpz_srcptr x, int base)
+{
+  mpz_out_str (stdout, base, x); fputc ('\n', stdout);
+}
+
+
+/* exercise the case where mpz_clrbit or mpz_combit ends up extending a
+   value like -2^(k*GMP_NUMB_BITS-1) when clearing bit k*GMP_NUMB_BITS-1.  */
+/* And vice-versa. */
+void
+check_clr_extend (void)
+{
+  mpz_t          got, want;
+  unsigned long  i;
+  int            f;
+
+  mpz_init (got);
+  mpz_init (want);
+
+  for (i = 1; i < 5; i++)
+    {
+      for (f = 0; f <= 1; f++)
+	{
+	  /* lots of 1 bits in _mp_d */
+	  mpz_set_si (got, 1L);
+	  mpz_mul_2exp (got, got, 10*GMP_NUMB_BITS);
+	  mpz_sub_ui (got, got, 1L);
+
+	  /* value -2^(n-1) representing ..11100..00 */
+	  mpz_set_si (got, -1L);
+	  mpz_mul_2exp (got, got, i*GMP_NUMB_BITS-1);
+
+	  /* complement bit n, giving ..11000..00 which is -2^n */
+	  if (f == 0)
+	    mpz_clrbit (got, i*GMP_NUMB_BITS-1);
+	  else
+	    mpz_combit (got, i*GMP_NUMB_BITS-1);
+	  MPZ_CHECK_FORMAT (got);
+
+	  mpz_set_si (want, -1L);
+	  mpz_mul_2exp (want, want, i*GMP_NUMB_BITS);
+
+	  if (mpz_cmp (got, want) != 0)
+	    {
+	      if (f == 0)
+		printf ("mpz_clrbit: ");
+	      else
+		printf ("mpz_combit: ");
+	      printf ("wrong after extension\n");
+	      mpz_trace ("got ", got);
+	      mpz_trace ("want", want);
+	      abort ();
+	    }
+
+	  /* complement bit n, going back to ..11100..00 which is -2^(n-1) */
+	  if (f == 0)
+	    mpz_setbit (got, i*GMP_NUMB_BITS-1);
+	  else
+	    mpz_combit (got, i*GMP_NUMB_BITS-1);
+	  MPZ_CHECK_FORMAT (got);
+
+	  mpz_set_si (want, -1L);
+	  mpz_mul_2exp (want, want, i*GMP_NUMB_BITS - 1);
+
+	  if (mpz_cmp (got, want) != 0)
+	    {
+	      if (f == 0)
+		printf ("mpz_setbit: ");
+	      else
+		printf ("mpz_combit: ");
+	      printf ("wrong after shrinking\n");
+	      mpz_trace ("got ", got);
+	      mpz_trace ("want", want);
+	      abort ();
+	    }
+	}
+    }
+
+  mpz_clear (got);
+  mpz_clear (want);
+}
+
+void
+check_com_negs (void)
+{
+  static const struct {
+    unsigned long  bit;
+    mp_size_t      inp_size;
+    mp_limb_t      inp_n[5];
+    mp_size_t      want_size;
+    mp_limb_t      want_n[5];
+  } data[] = {
+    { GMP_NUMB_BITS,   2, { 1, 1 },  1, { 1 } },
+    { GMP_NUMB_BITS+1, 2, { 1, 1 },  2, { 1, 3 } },
+
+    { GMP_NUMB_BITS,   2, { 0, 1 },  2, { 0, 2 } },
+    { GMP_NUMB_BITS+1, 2, { 0, 1 },  2, { 0, 3 } },
+  };
+  mpz_t  inp, got, want;
+  int    i;
+
+  mpz_init (got);
+  mpz_init (want);
+  mpz_init (inp);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_set_n (inp, data[i].inp_n, data[i].inp_size);
+      mpz_neg (inp, inp);
+
+      mpz_set_n (want, data[i].want_n, data[i].want_size);
+      mpz_neg (want, want);
+
+      mpz_set (got, inp);
+      mpz_combit (got, data[i].bit);
+
+      if (mpz_cmp (got, want) != 0)
+	{
+	  printf ("mpz_combit: wrong on neg data[%d]\n", i);
+	  mpz_trace ("inp ", inp);
+	  printf    ("bit %lu\n", data[i].bit);
+	  mpz_trace ("got ", got);
+	  mpz_trace ("want", want);
+	  abort ();
+	}
+    }
+
+  mpz_clear (inp);
+  mpz_clear (got);
+  mpz_clear (want);
+}
+
+/* See that mpz_tstbit matches a twos complement calculated explicitly, for
+   various low zeros.  */
+void
+check_tstbit (void)
+{
+#define MAX_ZEROS  3
+#define NUM_LIMBS  3
+
+  mp_limb_t      pos[1+NUM_LIMBS+MAX_ZEROS];
+  mp_limb_t      neg[1+NUM_LIMBS+MAX_ZEROS];
+  mpz_t          z;
+  unsigned long  i;
+  int            zeros, low1;
+  int            got, want;
+
+  mpz_init (z);
+  for (zeros = 0; zeros <= MAX_ZEROS; zeros++)
+    {
+      MPN_ZERO (pos, numberof(pos));
+      mpn_random2 (pos+zeros, (mp_size_t) NUM_LIMBS);
+
+      for (low1 = 0; low1 <= 1; low1++)
+	{
+	  if (low1)
+	    pos[0] |= 1;
+
+	  refmpn_neg (neg, pos, (mp_size_t) numberof(neg));
+	  mpz_set_n (z, neg, (mp_size_t) numberof(neg));
+	  mpz_neg (z, z);
+
+	  for (i = 0; i < numberof(pos)*GMP_NUMB_BITS; i++)
+	    {
+	      got = mpz_tstbit (z, i);
+	      want = refmpn_tstbit (pos, i);
+	      if (got != want)
+		{
+		  printf ("wrong at bit %lu, with %d zeros\n", i, zeros);
+		  printf ("z neg "); debug_mp (z, -16);
+		  mpz_set_n (z, pos, (mp_size_t) numberof(pos));
+		  printf ("pos   "); debug_mp (z, -16);
+		  mpz_set_n (z, neg, (mp_size_t) numberof(neg));
+		  printf ("neg   "); debug_mp (z, -16);
+		  exit (1);
+		}
+	    }
+	}
+    }
+  mpz_clear (z);
+}
+
+
+void
+check_single (void)
+{
+  mpz_t  x;
+  int    limb, offset, initial;
+  unsigned long  bit;
+
+  mpz_init (x);
+
+  for (limb = 0; limb < 4; limb++)
+    {
+      for (offset = (limb==0 ? 0 : -2); offset <= 2; offset++)
+	{
+	  for (initial = 1; initial >= -1; initial--)
+	    {
+	      mpz_set_si (x, (long) initial);
+
+	      bit = (unsigned long) limb*GMP_LIMB_BITS + offset;
+
+	      mpz_clrbit (x, bit);
+	      MPZ_CHECK_FORMAT (x);
+	      if (mpz_tstbit (x, bit) != 0)
+		{
+		  printf ("check_single(): expected 0\n");
+		  abort ();
+		}
+
+	      mpz_setbit (x, bit);
+	      MPZ_CHECK_FORMAT (x);
+	      if (mpz_tstbit (x, bit) != 1)
+		{
+		  printf ("check_single(): expected 1\n");
+		  abort ();
+		}
+
+	      mpz_clrbit (x, bit);
+	      MPZ_CHECK_FORMAT (x);
+	      if (mpz_tstbit (x, bit) != 0)
+		{
+		  printf ("check_single(): expected 0\n");
+		  abort ();
+		}
+
+	      mpz_combit (x, bit);
+	      MPZ_CHECK_FORMAT (x);
+	      if (mpz_tstbit (x, bit) != 1)
+		{
+		  printf ("check_single(): expected 1\n");
+		  abort ();
+		}
+
+	      mpz_combit (x, bit);
+	      MPZ_CHECK_FORMAT (x);
+	      if (mpz_tstbit (x, bit) != 0)
+		{
+		  printf ("check_single(): expected 0\n");
+		  abort ();
+		}
+	    }
+	}
+    }
+
+  mpz_clear (x);
+}
+
+
+void
+check_random (int argc, char *argv[])
+{
+  mpz_t x, s0, s1, s2, s3, m;
+  mp_size_t xsize;
+  int i;
+  int reps = 100000;
+  int bit0, bit1, bit2, bit3;
+  unsigned long int bitindex;
+  const char  *s = "";
+
+  if (argc == 2)
+    reps = atoi (argv[1]);
+
+  mpz_init (x);
+  mpz_init (s0);
+  mpz_init (s1);
+  mpz_init (s2);
+  mpz_init (s3);
+  mpz_init (m);
+
+  for (i = 0; i < reps; i++)
+    {
+      xsize = urandom () % (2 * SIZE) - SIZE;
+      mpz_random2 (x, xsize);
+      bitindex = urandom () % SIZE;
+
+      mpz_set (s0, x);
+      bit0 = mpz_tstbit (x, bitindex);
+      mpz_setbit (x, bitindex);
+      MPZ_CHECK_FORMAT (x);
+
+      mpz_set (s1, x);
+      bit1 = mpz_tstbit (x, bitindex);
+      mpz_clrbit (x, bitindex);
+      MPZ_CHECK_FORMAT (x);
+
+      mpz_set (s2, x);
+      bit2 = mpz_tstbit (x, bitindex);
+      mpz_combit (x, bitindex);
+      MPZ_CHECK_FORMAT (x);
+
+      mpz_set (s3, x);
+      bit3 = mpz_tstbit (x, bitindex);
+
+#define FAIL(str) do { s = str; goto fail; } while (0)
+
+      if (bit1 != 1)  FAIL ("bit1 != 1");
+      if (bit2 != 0)  FAIL ("bit2 != 0");
+      if (bit3 != 1)  FAIL ("bit3 != 1");
+
+      if (bit0 == 0)
+	{
+	  if (mpz_cmp (s0, s1) == 0 || mpz_cmp (s0, s2) != 0 || mpz_cmp (s0, s3) == 0)
+	    abort ();
+	}
+      else
+	{
+	  if (mpz_cmp (s0, s1) != 0 || mpz_cmp (s0, s2) == 0 || mpz_cmp (s0, s3) != 0)
+	    abort ();
+	}
+
+      if (mpz_cmp (s1, s2) == 0 || mpz_cmp (s1, s3) != 0)
+	abort ();
+      if (mpz_cmp (s2, s3) == 0)
+	abort ();
+
+      mpz_combit (x, bitindex);
+      MPZ_CHECK_FORMAT (x);
+      if (mpz_cmp (s2, x) != 0)
+	abort ();
+
+      mpz_clrbit (x, bitindex);
+      MPZ_CHECK_FORMAT (x);
+      if (mpz_cmp (s2, x) != 0)
+	abort ();
+
+      mpz_ui_pow_ui (m, 2L, bitindex);
+      MPZ_CHECK_FORMAT (m);
+      mpz_ior (x, s0, m);
+      MPZ_CHECK_FORMAT (x);
+      if (mpz_cmp (x, s3) != 0)
+	abort ();
+
+      mpz_com (m, m);
+      MPZ_CHECK_FORMAT (m);
+      mpz_and (x, s0, m);
+      MPZ_CHECK_FORMAT (x);
+      if (mpz_cmp (x, s2) != 0)
+	abort ();
+    }
+
+  mpz_clear (x);
+  mpz_clear (s0);
+  mpz_clear (s1);
+  mpz_clear (s2);
+  mpz_clear (s3);
+  mpz_clear (m);
+  return;
+
+
+ fail:
+  printf ("%s\n", s);
+  printf ("bitindex = %lu\n", bitindex);
+  printf ("x = "); mpz_out_str (stdout, -16, x); printf (" hex\n");
+  exit (1);
+}
+
+
+
+int
+main (int argc, char *argv[])
+{
+  tests_start ();
+  mp_trace_base = -16;
+
+  check_clr_extend ();
+  check_com_negs ();
+  check_tstbit ();
+  check_random (argc, argv);
+  check_single ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpz/convert.c b/third_party/gmp/tests/mpz/convert.c
new file mode 100644
index 0000000..fdb3874
--- /dev/null
+++ b/third_party/gmp/tests/mpz/convert.c
@@ -0,0 +1,169 @@
+/* Test conversion using mpz_get_str and mpz_set_str.
+
+Copyright 1993, 1994, 1996, 1999-2002, 2006, 2007 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h> /* for strlen */
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+void debug_mp (mpz_t, int);
+
+
+void
+string_urandomb (char *bp, size_t len, int base, gmp_randstate_ptr rands)
+{
+  mpz_t bs;
+  unsigned long bsi;
+  int d, l;
+  const char *collseq = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+  mpz_init (bs);
+
+  mpz_urandomb (bs, rands, 32);
+  bsi = mpz_get_ui (bs);
+  d = bsi % base;
+  while (len != 0)
+    {
+      l = (bsi >> 16) % 20;
+      l = MIN (l, len);
+
+      memset (bp, collseq[d], l);
+
+      len -= l;
+      bp += l;
+
+      mpz_urandomb (bs, rands, 32);
+      bsi = mpz_get_ui (bs);
+      d = bsi & 0xfff;
+      if (d >= base)
+	d = 0;
+    }
+
+  bp[0] = '\0';
+  mpz_clear (bs);
+}
+
+int
+main (int argc, char **argv)
+{
+  mpz_t op1, op2;
+  mp_size_t size;
+  int i;
+  int reps = 2000;
+  char *str, *buf, *bp;
+  int base;
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long bsi, size_range;
+  size_t len;
+
+  tests_start ();
+  TESTS_REPS (reps, argv, argc);
+
+  rands = RANDS;
+
+  mpz_init (bs);
+
+  mpz_init (op1);
+  mpz_init (op2);
+
+  for (i = 0; i < reps; i++)
+    {
+      /* 1. Generate random mpz_t and convert to a string and back to mpz_t
+	 again.  */
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 17 + 2;	/* 2..18 */
+      mpz_urandomb (bs, rands, size_range);	/* 3..262144 bits */
+      size = mpz_get_ui (bs);
+      mpz_rrandomb (op1, rands, size);
+
+      mpz_urandomb (bs, rands, 1);
+      bsi = mpz_get_ui (bs);
+      if ((bsi & 1) != 0)
+	mpz_neg (op1, op1);
+
+      mpz_urandomb (bs, rands, 32);
+      bsi = mpz_get_ui (bs);
+      base = bsi % 62 + 1;
+      if (base == 1)
+	base = 0;
+
+      str = mpz_get_str ((char *) 0, base, op1);
+      mpz_set_str_or_abort (op2, str, base);
+
+      if (mpz_cmp (op1, op2))
+	{
+	  fprintf (stderr, "ERROR, op1 and op2 different in test %d\n", i);
+	  fprintf (stderr, "str  = %s\n", str);
+	  fprintf (stderr, "base = %d\n", base);
+	  fprintf (stderr, "op1  = "); debug_mp (op1, -16);
+	  fprintf (stderr, "op2  = "); debug_mp (op2, -16);
+	  abort ();
+	}
+
+      (*__gmp_free_func) (str, strlen (str) + 1);
+
+      /* 2. Generate random string and convert to mpz_t and back to a string
+	 again.  */
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 16 + 1;	/* 1..16 */
+      mpz_urandomb (bs, rands, size_range);	/* 1..65536 digits */
+      len = mpz_get_ui (bs) + 1;
+      buf = (char *) (*__gmp_allocate_func) (len + 1);
+      if (base == 0)
+	base = 10;
+      string_urandomb (buf, len, base, rands);
+
+      mpz_set_str_or_abort (op1, buf, base);
+      str = mpz_get_str ((char *) 0, base, op1);
+
+      /* Skip over leading zeros, but don't leave the string at zero length. */
+      for (bp = buf; bp[0] == '0' && bp[1] != '\0'; bp++)
+	;
+
+      if (strcasecmp (str, bp) != 0)
+	{
+	  fprintf (stderr, "ERROR, str and buf different in test %d\n", i);
+	  fprintf (stderr, "str  = %s\n", str);
+	  fprintf (stderr, "buf  = %s\n", buf);
+	  fprintf (stderr, "base = %d\n", base);
+	  fprintf (stderr, "op1  = "); debug_mp (op1, -16);
+	  abort ();
+	}
+
+      (*__gmp_free_func) (buf, len + 1);
+      (*__gmp_free_func) (str, strlen (str) + 1);
+    }
+
+  mpz_clear (bs);
+  mpz_clear (op1);
+  mpz_clear (op2);
+
+  tests_end ();
+  exit (0);
+}
+
+void
+debug_mp (mpz_t x, int base)
+{
+  mpz_out_str (stderr, base, x); fputc ('\n', stderr);
+}
diff --git a/third_party/gmp/tests/mpz/dive.c b/third_party/gmp/tests/mpz/dive.c
new file mode 100644
index 0000000..99e8caf
--- /dev/null
+++ b/third_party/gmp/tests/mpz/dive.c
@@ -0,0 +1,100 @@
+/* Test mpz_mul, mpz_divexact.
+
+Copyright 1996, 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+int
+main (int argc, char **argv)
+{
+  mpz_t op1, op2;
+  mpz_t prod, quot;
+  mp_size_t size;
+  int i;
+  int reps = 5000;
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long bsi, size_range;
+
+  tests_start ();
+  TESTS_REPS (reps, argv, argc);
+
+  rands = RANDS;
+
+  mp_trace_base = -16;
+
+  mpz_init (bs);
+
+  mpz_init (op1);
+  mpz_init (op2);
+  mpz_init (prod);
+  mpz_init (quot);
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 17 + 2; /* 0..2047 bit operands */
+
+      mpz_urandomb (bs, rands, size_range);
+      size = mpz_get_ui (bs);
+      mpz_rrandomb (op1, rands, size);
+
+      do
+	{
+	  mpz_urandomb (bs, rands, size_range);
+	  size = mpz_get_ui (bs);
+	  mpz_rrandomb (op2, rands, size);
+	}
+      while (mpz_sgn (op2) == 0);
+
+      mpz_urandomb (bs, rands, 2);
+      bsi = mpz_get_ui (bs);
+      if ((bsi & 1) != 0)
+	mpz_neg (op1, op1);
+      if ((bsi & 2) != 0)
+	mpz_neg (op2, op2);
+
+      mpz_mul (prod, op1, op2);
+
+      mpz_divexact (quot, prod, op2);
+      MPZ_CHECK_FORMAT (quot);
+
+      if (mpz_cmp (quot, op1) != 0)
+        {
+          printf ("Wrong results:\n");
+          mpz_trace ("  got     ", quot);
+          mpz_trace ("  want    ", op1);
+          mpz_trace ("  dividend", prod);
+          mpz_trace ("  divisor ", op2);
+          abort ();
+        }
+    }
+
+  mpz_clear (bs);
+  mpz_clear (op1);
+  mpz_clear (op2);
+  mpz_clear (prod);
+  mpz_clear (quot);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpz/dive_ui.c b/third_party/gmp/tests/mpz/dive_ui.c
new file mode 100644
index 0000000..8f74bce
--- /dev/null
+++ b/third_party/gmp/tests/mpz/dive_ui.c
@@ -0,0 +1,86 @@
+/* Test mpz_divexact_ui.
+
+Copyright 1996, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_random (int argc, char *argv[])
+{
+  gmp_randstate_ptr rands = RANDS;
+  int    reps = 500000;
+  mpz_t  a, q, got;
+  int    i, qneg;
+  unsigned long  d;
+
+  if (argc == 2)
+    reps = atoi (argv[1]);
+
+  mpz_init (a);
+  mpz_init (q);
+  mpz_init (got);
+
+  for (i = 0; i < reps; i++)
+    {
+      do
+	d = (unsigned long) urandom();
+      while (d == 0);
+      mpz_erandomb (q, rands, 512);
+      mpz_mul_ui (a, q, d);
+
+      for (qneg = 0; qneg <= 1; qneg++)
+        {
+          mpz_divexact_ui (got, a, d);
+          MPZ_CHECK_FORMAT (got);
+          if (mpz_cmp (got, q) != 0)
+            {
+              printf    ("mpz_divexact_ui wrong\n");
+              mpz_trace ("    a", a);
+              printf    ("    d=%lu\n", d);
+              mpz_trace ("    q", q);
+              mpz_trace ("  got", got);
+              abort ();
+            }
+
+          mpz_neg (q, q);
+          mpz_neg (a, a);
+        }
+
+    }
+
+  mpz_clear (a);
+  mpz_clear (q);
+  mpz_clear (got);
+}
+
+
+int
+main (int argc, char **argv)
+{
+  tests_start ();
+
+  check_random (argc, argv);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpz/io.c b/third_party/gmp/tests/mpz/io.c
new file mode 100644
index 0000000..892f61d
--- /dev/null
+++ b/third_party/gmp/tests/mpz/io.c
@@ -0,0 +1,138 @@
+/* Test conversion and I/O using mpz_out_str and mpz_inp_str.
+
+Copyright 1993, 1994, 1996, 2000, 2001, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>		/* for unlink */
+#endif
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#define FILENAME  "io.tmp"
+
+void
+debug_mp (mpz_t x, int base)
+{
+  mpz_out_str (stdout, base, x); fputc ('\n', stdout);
+}
+
+int
+main (int argc, char **argv)
+{
+  mpz_t  op1, op2;
+  mp_size_t size;
+  int i;
+  int reps = 10000;
+  FILE *fp;
+  int base, base_out;
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long bsi, size_range;
+  size_t nread;
+
+  tests_start ();
+  rands = RANDS;
+
+  mpz_init (bs);
+
+  if (argc == 2)
+    reps = atoi (argv[1]);
+
+  mpz_init (op1);
+  mpz_init (op2);
+
+  fp = fopen (FILENAME, "w+");
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 10 + 2;
+
+      mpz_urandomb (bs, rands, size_range);
+      size = mpz_get_ui (bs);
+      mpz_rrandomb (op1, rands, size);
+      mpz_urandomb (bs, rands, 1);
+      bsi = mpz_get_ui (bs);
+      if ((bsi & 1) != 0)
+	mpz_neg (op1, op1);
+
+      mpz_urandomb (bs, rands, 16);
+      bsi = mpz_get_ui (bs);
+      base = bsi % 62 + 1;
+      if (base == 1)
+	base = 0;
+
+      if (i % 2 == 0 && base <= 36)
+	base_out = -base;
+      else
+	base_out = base;
+
+      rewind (fp);
+      if (mpz_out_str (fp, base_out, op1) == 0
+	  || putc (' ', fp) == EOF
+	  || fflush (fp) != 0)
+	{
+	  printf ("mpz_out_str write error\n");
+	  abort ();
+	}
+
+      rewind (fp);
+      nread = mpz_inp_str (op2, fp, base);
+      if (nread == 0)
+	{
+	  if (ferror (fp))
+	    printf ("mpz_inp_str stream read error\n");
+	  else
+	    printf ("mpz_inp_str data conversion error\n");
+	  abort ();
+	}
+
+      if (nread != ftell(fp))
+	{
+	  printf ("mpz_inp_str nread doesn't match ftell\n");
+	  printf ("  nread  %lu\n", (unsigned long) nread);
+	  printf ("  ftell  %ld\n", ftell(fp));
+	  abort ();
+	}
+
+      if (mpz_cmp (op1, op2))
+	{
+	  printf ("ERROR\n");
+	  printf ("op1  = "); debug_mp (op1, -16);
+	  printf ("op2  = "); debug_mp (op2, -16);
+	  printf ("base = %d\n", base);
+	  abort ();
+	}
+    }
+
+  fclose (fp);
+
+  unlink (FILENAME);
+
+  mpz_clear (bs);
+  mpz_clear (op1);
+  mpz_clear (op2);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpz/logic.c b/third_party/gmp/tests/mpz/logic.c
new file mode 100644
index 0000000..f3b38b1
--- /dev/null
+++ b/third_party/gmp/tests/mpz/logic.c
@@ -0,0 +1,194 @@
+/* Test mpz_com, mpz_and, mpz_ior, and mpz_xor.
+
+Copyright 1993, 1994, 1996, 1997, 2001, 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+void dump_abort (void);
+void debug_mp (mpz_t, int);
+
+int
+main (int argc, char **argv)
+{
+  mpz_t x, y, r1, r2;
+  mpz_t t1, t2, t3;
+  mp_size_t xsize, ysize;
+  int i;
+  int reps = 100000;
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long bsi, size_range;
+
+  tests_start ();
+  rands = RANDS;
+
+  mpz_init (bs);
+
+  if (argc == 2)
+     reps = atoi (argv[1]);
+
+  mpz_init (x);
+  mpz_init (y);
+  mpz_init (r1);
+  mpz_init (r2);
+  mpz_init (t1);
+  mpz_init (t2);
+  mpz_init (t3);
+
+  mpz_set_si (x, -1);
+  mpz_set_ui (y, 0);
+  for (i = 0; i < 300; i++)
+    {
+      mpz_mul_2exp (x, x, 1);
+
+      mpz_and (r1, x, x);
+      MPZ_CHECK_FORMAT (r1);
+      if (mpz_cmp (r1, x) != 0)
+	dump_abort ();
+
+      mpz_ior (r2, x, x);
+      MPZ_CHECK_FORMAT (r2);
+      if (mpz_cmp (r2, x) != 0)
+	dump_abort ();
+
+      mpz_xor (t1, x, x);
+      MPZ_CHECK_FORMAT (t1);
+      if (mpz_cmp_si (t1, 0) != 0)
+	dump_abort ();
+
+      mpz_ior (t1, x, y);
+      MPZ_CHECK_FORMAT (t1);
+      if (mpz_cmp (t1, x) != 0)
+	dump_abort ();
+
+      mpz_xor (t2, x, y);
+      MPZ_CHECK_FORMAT (t2);
+      if (mpz_cmp (t2, x) != 0)
+	dump_abort ();
+
+      mpz_com (t2, x);
+      MPZ_CHECK_FORMAT (t2);
+      mpz_xor (t3, t2, x);
+      MPZ_CHECK_FORMAT (t3);
+      if (mpz_cmp_si (t3, -1) != 0)
+	dump_abort ();
+    }
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 8 + 2;
+
+      mpz_urandomb (bs, rands, size_range);
+      xsize = mpz_get_ui (bs);
+      mpz_rrandomb (x, rands, xsize);
+      mpz_urandomb (bs, rands, 1);
+      bsi = mpz_get_ui (bs);
+      if ((bsi & 1) != 0)
+	mpz_neg (x, x);
+
+      mpz_urandomb (bs, rands, size_range);
+      ysize = mpz_get_ui (bs);
+      mpz_rrandomb (y, rands, ysize);
+      mpz_urandomb (bs, rands, 1);
+      bsi = mpz_get_ui (bs);
+      if ((bsi & 1) != 0)
+	mpz_neg (y, y);
+
+      mpz_com (r1, x);
+      MPZ_CHECK_FORMAT (r1);
+      mpz_com (r1, r1);
+      MPZ_CHECK_FORMAT (r1);
+      if (mpz_cmp (r1, x) != 0)
+	dump_abort ();
+
+      mpz_com (r1, y);
+      MPZ_CHECK_FORMAT (r1);
+      mpz_com (r2, r1);
+      MPZ_CHECK_FORMAT (r2);
+      if (mpz_cmp (r2, y) != 0)
+	dump_abort ();
+
+      mpz_com (t1, x);
+      MPZ_CHECK_FORMAT (t1);
+      mpz_com (t2, y);
+      MPZ_CHECK_FORMAT (t2);
+      mpz_and (t3, t1, t2);
+      MPZ_CHECK_FORMAT (t3);
+      mpz_com (r1, t3);
+      MPZ_CHECK_FORMAT (r1);
+      mpz_ior (r2, x, y);
+      MPZ_CHECK_FORMAT (r2);
+      if (mpz_cmp (r1, r2) != 0)
+	dump_abort ();
+
+      mpz_com (t1, x);
+      MPZ_CHECK_FORMAT (t1);
+      mpz_com (t2, y);
+      MPZ_CHECK_FORMAT (t2);
+      mpz_ior (t3, t1, t2);
+      MPZ_CHECK_FORMAT (t3);
+      mpz_com (r1, t3);
+      MPZ_CHECK_FORMAT (r1);
+      mpz_and (r2, x, y);
+      MPZ_CHECK_FORMAT (r2);
+      if (mpz_cmp (r1, r2) != 0)
+	dump_abort ();
+
+      mpz_ior (t1, x, y);
+      MPZ_CHECK_FORMAT (t1);
+      mpz_and (t2, x, y);
+      MPZ_CHECK_FORMAT (t2);
+      mpz_com (t3, t2);
+      MPZ_CHECK_FORMAT (t3);
+      mpz_and (r1, t1, t3);
+      MPZ_CHECK_FORMAT (r1);
+      mpz_xor (r2, x, y);
+      MPZ_CHECK_FORMAT (r2);
+      if (mpz_cmp (r1, r2) != 0)
+	dump_abort ();
+    }
+
+  mpz_clear (bs);
+  mpz_clear (x);
+  mpz_clear (y);
+  mpz_clear (r1);
+  mpz_clear (r2);
+  mpz_clear (t1);
+  mpz_clear (t2);
+  mpz_clear (t3);
+
+  tests_end ();
+  exit (0);
+}
+
+void
+dump_abort ()
+{
+  abort();
+}
+
+void
+debug_mp (mpz_t x, int base)
+{
+  mpz_out_str (stderr, base, x); fputc ('\n', stderr);
+}
diff --git a/third_party/gmp/tests/mpz/reuse.c b/third_party/gmp/tests/mpz/reuse.c
new file mode 100644
index 0000000..f057a96
--- /dev/null
+++ b/third_party/gmp/tests/mpz/reuse.c
@@ -0,0 +1,780 @@
+/* Test that routines allow reusing a source variable as destination.
+
+   Test all relevant functions except:
+	mpz_bin_ui
+	mpz_nextprime
+	mpz_mul_si
+	mpz_addmul_ui (should this really allow a+=a*c?)
+
+Copyright 1996, 1999-2002, 2009, 2012, 2013, 2016 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#if __GMP_LIBGMP_DLL
+
+/* FIXME: When linking to a DLL libgmp, mpz_add etc can't be used as
+   initializers for global variables because they're effectively global
+   variables (function pointers) themselves.  Perhaps calling a test
+   function successively with mpz_add etc would be better.  */
+
+int
+main (void)
+{
+  printf ("Test suppressed for windows DLL\n");
+  exit (0);
+}
+
+
+#else /* ! DLL_EXPORT */
+
+void dump (const char *, mpz_t, mpz_t, mpz_t);
+
+typedef void (*dss_func) (mpz_ptr, mpz_srcptr, mpz_srcptr);
+typedef void (*dsi_func) (mpz_ptr, mpz_srcptr, unsigned long int);
+typedef unsigned long int (*dsi_div_func) (mpz_ptr, mpz_srcptr, unsigned long int);
+typedef unsigned long int (*ddsi_div_func) (mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int);
+typedef void (*ddss_div_func) (mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr);
+typedef void (*ds_func) (mpz_ptr, mpz_srcptr);
+
+
+void
+mpz_xinvert (mpz_ptr r, mpz_srcptr a, mpz_srcptr b)
+{
+  int res;
+  res = mpz_invert (r, a, b);
+  if (res == 0)
+    mpz_set_ui (r, 0);
+}
+
+struct {
+  dss_func fptr;
+  const char *fname;
+  int isdivision;
+  int isslow;
+} static dss[] =
+  { { mpz_add,     "mpz_add",	  0, 0 },
+    { mpz_sub,     "mpz_sub",	  0, 0 },
+    { mpz_mul,     "mpz_mul",	  0, 0 },
+    { mpz_cdiv_q,  "mpz_cdiv_q",  1, 0 },
+    { mpz_cdiv_r,  "mpz_cdiv_r",  1, 0 },
+    { mpz_fdiv_q,  "mpz_fdiv_q",  1, 0 },
+    { mpz_fdiv_r,  "mpz_fdiv_r",  1, 0 },
+    { mpz_tdiv_q,  "mpz_tdiv_q",  1, 0 },
+    { mpz_tdiv_r,  "mpz_tdiv_r",  1, 0 },
+    { mpz_mod,     "mpz_mod",	  1, 0 },
+    { mpz_xinvert, "mpz_xinvert", 1, 1 },
+    { mpz_gcd,     "mpz_gcd",	  0, 1 },
+    { mpz_lcm,     "mpz_lcm",	  0, 1 },
+    { mpz_and,     "mpz_and",	  0, 0 },
+    { mpz_ior,     "mpz_ior",	  0, 0 },
+    { mpz_xor,     "mpz_xor",     0, 0 }
+  };
+
+
+struct {
+  dsi_func fptr;
+  const char *fname;
+  int mod;
+} static dsi[] =
+{
+  /* Don't change order here without changing the code in main(). */
+  { mpz_add_ui,         "mpz_add_ui",	     0 },
+  { mpz_mul_ui,		"mpz_mul_ui",	     0 },
+  { mpz_sub_ui,		"mpz_sub_ui",	     0 },
+  { mpz_fdiv_q_2exp,    "mpz_fdiv_q_2exp",   0x1000 },
+  { mpz_fdiv_r_2exp,    "mpz_fdiv_r_2exp",   0x1000 },
+  { mpz_cdiv_q_2exp,    "mpz_cdiv_q_2exp",   0x1000 },
+  { mpz_cdiv_r_2exp,    "mpz_cdiv_r_2exp",   0x1000 },
+  { mpz_tdiv_q_2exp,    "mpz_tdiv_q_2exp",   0x1000 },
+  { mpz_tdiv_r_2exp,    "mpz_tdiv_r_2exp",   0x1000 },
+  { mpz_mul_2exp,	"mpz_mul_2exp",      0x100 },
+  { mpz_pow_ui,		"mpz_pow_ui",        0x10 }
+};
+
+struct {
+  dsi_div_func fptr;
+  const char *fname;
+} static dsi_div[] =
+{
+  { mpz_cdiv_q_ui,       "mpz_cdiv_q_ui" },
+  { mpz_cdiv_r_ui,       "mpz_cdiv_r_ui" },
+  { mpz_fdiv_q_ui,       "mpz_fdiv_q_ui" },
+  { mpz_fdiv_r_ui,       "mpz_fdiv_r_ui" },
+  { mpz_tdiv_q_ui,       "mpz_tdiv_q_ui" },
+  { mpz_tdiv_r_ui,       "mpz_tdiv_r_ui" }
+};
+
+struct {
+  ddsi_div_func fptr;
+  const char *fname;
+  int isslow;
+} static ddsi_div[] =
+{
+  { mpz_cdiv_qr_ui,     "mpz_cdiv_qr_ui",    0 },
+  { mpz_fdiv_qr_ui,     "mpz_fdiv_qr_ui",    0 },
+  { mpz_tdiv_qr_ui,     "mpz_tdiv_qr_ui",    0 },
+};
+
+
+struct {
+  ddss_div_func fptr;
+  const char *fname;
+  int isslow;
+} static ddss_div[] =
+{
+  { mpz_cdiv_qr,  "mpz_cdiv_qr",    0 },
+  { mpz_fdiv_qr,  "mpz_fdiv_qr",    0 },
+  { mpz_tdiv_qr,  "mpz_tdiv_qr",    0 },
+};
+
+struct {
+  ds_func fptr;
+  const char *fname;
+  int nonneg;
+} static ds[] =
+{
+  { mpz_abs,    "mpz_abs",    0 },
+  { mpz_com,    "mpz_com",    0 },
+  { mpz_neg,    "mpz_neg",    0 },
+  { mpz_sqrt,   "mpz_sqrt",   1 },
+};
+
+#define FAIL(class,indx,op1,op2,op3)					\
+  do {									\
+    dump (class[indx].fname, op1, op2, op3);				\
+    exit (1);								\
+  } while (0)
+
+#define FAIL2(fname,op1,op2,op3)					\
+  do {									\
+    dump (#fname, op1, op2, op3);					\
+    exit (1);								\
+  } while (0)
+
+
+#define INVOKE_RRS(desc,r1,r2,i1)					\
+  do {									\
+    if (pass & 1) _mpz_realloc (r1, ABSIZ(r1));				\
+    if (pass & 2) _mpz_realloc (r2, ABSIZ(r2));				\
+    (desc).fptr (r1, r2, i1);						\
+  } while (0)
+#define INVOKE_RS(desc,r1,i1)						\
+  do {									\
+    if (pass & 1) _mpz_realloc (r1, ABSIZ(r1));				\
+    (desc).fptr (r1, i1);						\
+  } while (0)
+#define INVOKE_RRSS(desc,r1,r2,i1,i2)					\
+  do {									\
+    if (pass & 1) _mpz_realloc (r1, ABSIZ(r1));				\
+    if (pass & 2) _mpz_realloc (r2, ABSIZ(r2));				\
+    (desc).fptr (r1, r2, i1, i2);					\
+  } while (0)
+#define INVOKE_RSS(desc,r1,i1,i2)					\
+  do {									\
+    if (pass & 1) _mpz_realloc (r1, ABSIZ(r1));				\
+    (desc).fptr (r1, i1, i2);						\
+  } while (0)
+
+int
+main (int argc, char **argv)
+{
+  int i;
+  unsigned int pass, reps = 400;
+  mpz_t in1, in2, in3;
+  unsigned long int in2i;
+  mp_size_t size;
+  mpz_t res1, res2, res3;
+  mpz_t ref1, ref2, ref3;
+  mpz_t t;
+  unsigned long int r1, r2;
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long bsi, size_range;
+
+  tests_start ();
+  TESTS_REPS (reps, argv, argc);
+
+  rands = RANDS;
+
+  mpz_init (bs);
+
+  mpz_init (in1);
+  mpz_init (in2);
+  mpz_init (in3);
+  mpz_init (ref1);
+  mpz_init (ref2);
+  mpz_init (ref3);
+  mpz_init (res1);
+  mpz_init (res2);
+  mpz_init (res3);
+  mpz_init (t);
+
+  mpz_set_ui (res1, 1);		/* force allocation */
+  mpz_set_ui (res2, 1);		/* force allocation */
+  mpz_set_ui (res3, 1);		/* force allocation */
+
+  for (pass = 1; pass <= reps; pass++)
+    {
+#ifndef VERBOSE
+      if (isatty (fileno (stdout)))
+	{
+	  printf ("\r%d/%d passes", pass, reps);
+	  fflush (stdout);
+	}
+#endif
+
+      mpz_urandomb (bs, rands, 32);
+      /* Make size_range gradually bigger with each pass. */
+      size_range = mpz_get_ui (bs) % (pass * 15 / reps + 1) + 8;
+
+#define MAKE_RANDOM_OP(in, size_range, s)				\
+  do {									\
+    mpz_urandomb (bs, rands, size_range);				\
+    if (((pass >> s) & 3) == 3) /* conditional exponential dist */	\
+      mpz_urandomb (bs, rands, mpz_get_ui (bs) % (size_range - 7) + 7);	\
+    mpz_rrandomb (in, rands, mpz_get_ui (bs));				\
+  } while (0)
+
+      MAKE_RANDOM_OP (in1, size_range, 0);
+      MAKE_RANDOM_OP (in2, size_range, 2);
+      MAKE_RANDOM_OP (in3, size_range, 4);
+#undef MAKE_RANDOM_OP
+
+#ifdef VERBOSE
+      printf("%9d%9d%8d\n",
+	     mpz_sizeinbase(in1,2),
+	     mpz_sizeinbase(in2,2),
+	     mpz_sizeinbase(in3,2));
+#endif
+
+      mpz_urandomb (bs, rands, 3);
+      bsi = mpz_get_ui (bs);
+      if ((bsi & 1) != 0)
+	mpz_neg (in1, in1);
+      if ((bsi & 2) != 0)
+	mpz_neg (in2, in2);
+      if ((bsi & 4) != 0)
+	mpz_neg (in3, in3);
+
+      for (i = 0; i < numberof (dss); i++)
+	{
+	  if (dss[i].isdivision && mpz_sgn (in2) == 0)
+	    continue;
+	  if (dss[i].isslow && size_range > 19)
+	    continue;
+
+	  (dss[i].fptr) (ref1, in1, in2);
+	  MPZ_CHECK_FORMAT (ref1);
+
+	  mpz_set (res1, in1);
+	  INVOKE_RSS (dss[i], res1, res1, in2);
+	  MPZ_CHECK_FORMAT (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL (dss, i, in1, in2, NULL);
+
+	  mpz_set (res1, in2);
+	  INVOKE_RSS (dss[i], res1, in1, res1);
+	  MPZ_CHECK_FORMAT (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL (dss, i, in1, in2, NULL);
+	}
+
+      for (i = 0; i < numberof (ddss_div); i++)
+	{
+	  if (mpz_sgn (in2) == 0)
+	    continue;
+
+	  (ddss_div[i].fptr) (ref1, ref2, in1, in2);
+	  MPZ_CHECK_FORMAT (ref1);
+	  MPZ_CHECK_FORMAT (ref2);
+
+	  mpz_set (res1, in1);
+	  mpz_clobber (res2);
+	  INVOKE_RRSS (ddss_div[i], res1, res2, res1, in2);
+	  MPZ_CHECK_FORMAT (res1);
+	  MPZ_CHECK_FORMAT (res2);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0)
+	    FAIL (ddss_div, i, in1, in2, NULL);
+
+	  mpz_clobber (res1);
+	  mpz_set (res2, in1);
+	  INVOKE_RRSS (ddss_div[i], res1, res2, res2, in2);
+	  MPZ_CHECK_FORMAT (res1);
+	  MPZ_CHECK_FORMAT (res2);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0)
+	    FAIL (ddss_div, i, in1, in2, NULL);
+
+	  mpz_set (res1, in2);
+	  mpz_clobber (res2);
+	  INVOKE_RRSS (ddss_div[i], res1, res2, in1, res1);
+	  MPZ_CHECK_FORMAT (res1);
+	  MPZ_CHECK_FORMAT (res2);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0)
+	    FAIL (ddss_div, i, in1, in2, NULL);
+
+	  mpz_clobber (res1);
+	  mpz_set (res2, in2);
+	  INVOKE_RRSS (ddss_div[i], res1, res2, in1, res2);
+	  MPZ_CHECK_FORMAT (res1);
+	  MPZ_CHECK_FORMAT (res2);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0)
+	    FAIL (ddss_div, i, in1, in2, NULL);
+	}
+
+      for (i = 0; i < numberof (ds); i++)
+	{
+	  if (ds[i].nonneg && mpz_sgn (in1) < 0)
+	    continue;
+
+	  (ds[i].fptr) (ref1, in1);
+	  MPZ_CHECK_FORMAT (ref1);
+
+	  mpz_set (res1, in1);
+	  INVOKE_RS (ds[i], res1, res1);
+	  MPZ_CHECK_FORMAT (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL (ds, i, in1, in2, NULL);
+	}
+
+      in2i = mpz_get_ui (in2);
+
+      for (i = 0; i < numberof (dsi); i++)
+	{
+	  if (dsi[i].mod != 0)
+	    in2i = mpz_get_ui (in2) % dsi[i].mod;
+
+	  (dsi[i].fptr) (ref1, in1, in2i);
+	  MPZ_CHECK_FORMAT (ref1);
+
+	  mpz_set (res1, in1);
+	  INVOKE_RRS (dsi[i], res1, res1, in2i);
+	  MPZ_CHECK_FORMAT (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL (dsi, i, in1, in2, NULL);
+	}
+
+      if (in2i != 0)	  /* Don't divide by 0.  */
+	{
+	  for (i = 0; i < numberof (dsi_div); i++)
+	    {
+	      r1 = (dsi_div[i].fptr) (ref1, in1, in2i);
+	      MPZ_CHECK_FORMAT (ref1);
+
+	      mpz_set (res1, in1);
+	      r2 = (dsi_div[i].fptr) (res1, res1, in2i);
+	      MPZ_CHECK_FORMAT (res1);
+	      if (mpz_cmp (ref1, res1) != 0 || r1 != r2)
+		FAIL (dsi_div, i, in1, in2, NULL);
+	    }
+
+	  for (i = 0; i < numberof (ddsi_div); i++)
+	    {
+	      r1 = (ddsi_div[i].fptr) (ref1, ref2, in1, in2i);
+	      MPZ_CHECK_FORMAT (ref1);
+
+	      mpz_set (res1, in1);
+	      mpz_clobber (res2);
+	      r2 = (ddsi_div[i].fptr) (res1, res2, res1, in2i);
+	      MPZ_CHECK_FORMAT (res1);
+	      if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0 || r1 != r2)
+		FAIL (ddsi_div, i, in1, in2, NULL);
+
+	      mpz_clobber (res1);
+	      mpz_set (res2, in1);
+	      (ddsi_div[i].fptr) (res1, res2, res2, in2i);
+	      MPZ_CHECK_FORMAT (res1);
+	      if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0 || r1 != r2)
+		FAIL (ddsi_div, i, in1, in2, NULL);
+	    }
+	}
+
+      if (mpz_sgn (in1) >= 0)
+	{
+	  mpz_sqrtrem (ref1, ref2, in1);
+	  MPZ_CHECK_FORMAT (ref1);
+	  MPZ_CHECK_FORMAT (ref2);
+
+	  mpz_set (res1, in1);
+	  mpz_sqrtrem (res1, res2, res1);
+	  MPZ_CHECK_FORMAT (res1);
+	  MPZ_CHECK_FORMAT (res2);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0)
+	    FAIL2 (mpz_sqrtrem, in1, NULL, NULL);
+
+	  mpz_set (res2, in1);
+	  mpz_sqrtrem (res1, res2, res2);
+	  MPZ_CHECK_FORMAT (res1);
+	  MPZ_CHECK_FORMAT (res2);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0)
+	    FAIL2 (mpz_sqrtrem, in1, NULL, NULL);
+
+	  mpz_set (res1, in1);
+	  mpz_sqrtrem (res1, res1, res1);
+	  MPZ_CHECK_FORMAT (res1);
+	  if (mpz_cmp (ref2, res1) != 0)
+	    FAIL2 (mpz_sqrtrem, in1, NULL, NULL);
+	}
+
+      if (mpz_sgn (in1) >= 0)
+	{
+	  mpz_root (ref1, in1, in2i % 0x100 + 1);
+	  MPZ_CHECK_FORMAT (ref1);
+
+	  mpz_set (res1, in1);
+	  mpz_root (res1, res1, in2i % 0x100 + 1);
+	  MPZ_CHECK_FORMAT (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL2 (mpz_root, in1, in2, NULL);
+	}
+
+      if (mpz_sgn (in1) >= 0)
+	{
+	  mpz_rootrem (ref1, ref2, in1, in2i % 0x100 + 1);
+	  MPZ_CHECK_FORMAT (ref1);
+	  MPZ_CHECK_FORMAT (ref2);
+
+	  mpz_set (res1, in1);
+	  mpz_rootrem (res1, res2, res1, in2i % 0x100 + 1);
+	  MPZ_CHECK_FORMAT (res1);
+	  MPZ_CHECK_FORMAT (res2);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0)
+	    FAIL2 (mpz_rootrem, in1, in2, NULL);
+
+	  mpz_set (res2, in1);
+	  mpz_rootrem (res1, res2, res2, in2i % 0x100 + 1);
+	  MPZ_CHECK_FORMAT (res1);
+	  MPZ_CHECK_FORMAT (res2);
+	  if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0)
+	    FAIL2 (mpz_rootrem, in1, in2, NULL);
+	}
+
+      if (size_range < 18)	/* run fewer tests since gcdext is slow */
+	{
+	  mpz_gcdext (ref1, ref2, ref3, in1, in2);
+	  MPZ_CHECK_FORMAT (ref1);
+	  MPZ_CHECK_FORMAT (ref2);
+	  MPZ_CHECK_FORMAT (ref3);
+
+#define GCDEXT_CHECK3(i1, i2) do {					\
+	    mpz_gcdext (res1, res2, res3, i1, i2);			\
+	    MPZ_CHECK_FORMAT (res1);					\
+	    MPZ_CHECK_FORMAT (res2);					\
+	    MPZ_CHECK_FORMAT (res3);					\
+	    if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0	\
+		|| mpz_cmp (ref3, res3) != 0)				\
+	      FAIL2 (mpz_gcdext, i1, i2, NULL);				\
+	  } while (0)
+#define GCDEXT_CHECK2(i1, i2) do {					\
+	    mpz_gcdext (res1, res2, NULL, i1, i2);			\
+	    MPZ_CHECK_FORMAT (res1);					\
+	    MPZ_CHECK_FORMAT (res2);					\
+	    if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0)	\
+	      FAIL2 (mpz_gcdext, i1, i2, NULL);				\
+	  } while (0)
+
+	  mpz_set (res1, in1);
+	  mpz_clobber (res2);
+	  mpz_clobber (res3);
+	  GCDEXT_CHECK3 (res1, in2);
+
+	  mpz_clobber (res1);
+	  mpz_set (res2, in1);
+	  mpz_clobber (res3);
+	  GCDEXT_CHECK3 (res2, in2);
+
+	  mpz_clobber (res1);
+	  mpz_clobber (res2);
+	  mpz_set (res3, in1);
+	  GCDEXT_CHECK3 (res3, in2);
+
+	  mpz_set (res1, in2);
+	  mpz_clobber (res2);
+	  mpz_clobber (res3);
+	  GCDEXT_CHECK3 (in1, res1);
+
+	  mpz_clobber (res1);
+	  mpz_set (res2, in2);
+	  mpz_clobber (res3);
+	  GCDEXT_CHECK3 (in1, res2);
+
+	  mpz_clobber (res1);
+	  mpz_clobber (res2);
+	  mpz_set (res3, in2);
+	  GCDEXT_CHECK3 (in1, res3);
+
+	  mpz_set (res1, in1);
+	  mpz_set (res2, in2);
+	  mpz_clobber (res3);
+	  GCDEXT_CHECK3 (res1, res2);
+
+	  mpz_set (res1, in1);
+	  mpz_clobber (res2);
+	  mpz_set (res3, in2);
+	  GCDEXT_CHECK3 (res1, res3);
+
+	  mpz_clobber (res1);
+	  mpz_set (res2, in1);
+	  mpz_set (res3, in2);
+	  GCDEXT_CHECK3 (res2, res3);
+
+	  mpz_set (res1, in2);
+	  mpz_set (res2, in1);
+	  mpz_clobber (res3);
+	  GCDEXT_CHECK3 (res2, res1);
+
+	  mpz_set (res1, in2);
+	  mpz_clobber (res2);
+	  mpz_set (res3, in1);
+	  GCDEXT_CHECK3 (res3, res1);
+
+	  mpz_clobber (res1);
+	  mpz_set (res2, in2);
+	  mpz_set (res3, in1);
+	  GCDEXT_CHECK3(res3, res2);
+
+	  mpz_set (res1, in1);
+	  mpz_clobber (res2);
+	  GCDEXT_CHECK2 (res1, in2);
+
+	  mpz_clobber (res1);
+	  mpz_set (res2, in1);
+	  GCDEXT_CHECK2 (res2, in2);
+
+	  mpz_set (res1, in2);
+	  mpz_clobber (res2);
+	  GCDEXT_CHECK2 (in1, res1);
+
+	  mpz_clobber (res1);
+	  mpz_set (res2, in2);
+	  GCDEXT_CHECK2 (in1, res2);
+#undef GCDEXT_CHECK
+	  /* Identical inputs, gcd(in1, in1). Then the result should be
+	     gcd = abs(in1), s = 0, t = sgn(in1). */
+	  mpz_abs (ref1, in1);
+	  mpz_set_ui (ref2, 0);
+	  mpz_set_si (ref3, mpz_sgn (in1));
+
+#define GCDEXT_CHECK_SAME3(in) do {					\
+	    mpz_gcdext (res1, res2, res3, in, in);			\
+	    MPZ_CHECK_FORMAT (res1);					\
+	    MPZ_CHECK_FORMAT (res2);					\
+	    MPZ_CHECK_FORMAT (res3);					\
+	    if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0	\
+		|| mpz_cmp (ref3, res3) != 0)				\
+	      FAIL2 (mpz_gcdext, in, in, NULL);				\
+	  } while (0)
+#define GCDEXT_CHECK_SAME2(in) do {					\
+	    mpz_gcdext (res1, res2, NULL, in, in);			\
+	    MPZ_CHECK_FORMAT (res1);					\
+	    MPZ_CHECK_FORMAT (res2);					\
+	    if (mpz_cmp (ref1, res1) != 0 || mpz_cmp (ref2, res2) != 0)	\
+	      FAIL2 (mpz_gcdext, in, in, NULL);				\
+	  } while (0)
+
+	  mpz_set (res1, in1);
+	  mpz_clobber (res2);
+	  mpz_clobber (res3);
+	  GCDEXT_CHECK_SAME3 (res1);
+
+	  mpz_clobber (res1);
+	  mpz_set (res2, in1);
+	  mpz_clobber (res3);
+	  GCDEXT_CHECK_SAME3 (res2);
+
+	  mpz_clobber (res1);
+	  mpz_clobber (res2);
+	  mpz_set (res3, in1);
+	  GCDEXT_CHECK_SAME3 (res3);
+
+	  mpz_set (res1, in1);
+	  mpz_clobber (res2);
+	  mpz_clobber (res3);
+	  GCDEXT_CHECK_SAME2 (res1);
+
+	  mpz_clobber (res1);
+	  mpz_set (res2, in1);
+	  mpz_clobber (res3);
+	  GCDEXT_CHECK_SAME2 (res2);
+#undef GCDEXT_CHECK_SAME
+	}
+
+      /* Don't run mpz_powm for huge exponents or when undefined.  */
+      if (size_range < 17 && mpz_sizeinbase (in2, 2) < 250 && mpz_sgn (in3) != 0
+	  && (mpz_sgn (in2) >= 0 || mpz_invert (t, in1, in3)))
+	{
+	  mpz_powm (ref1, in1, in2, in3);
+	  MPZ_CHECK_FORMAT (ref1);
+
+	  mpz_set (res1, in1);
+	  mpz_powm (res1, res1, in2, in3);
+	  MPZ_CHECK_FORMAT (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL2 (mpz_powm, in1, in2, in3);
+
+	  mpz_set (res1, in2);
+	  mpz_powm (res1, in1, res1, in3);
+	  MPZ_CHECK_FORMAT (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL2 (mpz_powm, in1, in2, in3);
+
+	  mpz_set (res1, in3);
+	  mpz_powm (res1, in1, in2, res1);
+	  MPZ_CHECK_FORMAT (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL2 (mpz_powm, in1, in2, in3);
+	}
+
+      /* Don't run mpz_powm_ui when undefined.  */
+      if (size_range < 17 && mpz_sgn (in3) != 0)
+	{
+	  mpz_powm_ui (ref1, in1, in2i, in3);
+	  MPZ_CHECK_FORMAT (ref1);
+
+	  mpz_set (res1, in1);
+	  mpz_powm_ui (res1, res1, in2i, in3);
+	  MPZ_CHECK_FORMAT (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL2 (mpz_powm_ui, in1, in2, in3);
+
+	  mpz_set (res1, in3);
+	  mpz_powm_ui (res1, in1, in2i, res1);
+	  MPZ_CHECK_FORMAT (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL2 (mpz_powm_ui, in1, in2, in3);
+	}
+
+      {
+	r1 = mpz_gcd_ui (ref1, in1, in2i);
+	MPZ_CHECK_FORMAT (ref1);
+
+	mpz_set (res1, in1);
+	r2 = mpz_gcd_ui (res1, res1, in2i);
+	MPZ_CHECK_FORMAT (res1);
+	if (mpz_cmp (ref1, res1) != 0)
+	  FAIL2 (mpz_gcd_ui, in1, in2, NULL);
+      }
+
+      if (mpz_sgn (in2) != 0)
+	{
+	  /* Test mpz_remove */
+	  mp_bitcnt_t refretval, retval;
+	  refretval = mpz_remove (ref1, in1, in2);
+	  MPZ_CHECK_FORMAT (ref1);
+
+	  mpz_set (res1, in1);
+	  retval = mpz_remove (res1, res1, in2);
+	  MPZ_CHECK_FORMAT (res1);
+	  if (mpz_cmp (ref1, res1) != 0 || refretval != retval)
+	    FAIL2 (mpz_remove, in1, in2, NULL);
+
+	  mpz_set (res1, in2);
+	  retval = mpz_remove (res1, in1, res1);
+	  MPZ_CHECK_FORMAT (res1);
+	  if (mpz_cmp (ref1, res1) != 0 || refretval != retval)
+	    FAIL2 (mpz_remove, in1, in2, NULL);
+	}
+
+      if (mpz_sgn (in2) != 0)
+	{
+	  /* Test mpz_divexact */
+	  mpz_mul (t, in1, in2);
+	  mpz_divexact (ref1, t, in2);
+	  MPZ_CHECK_FORMAT (ref1);
+
+	  mpz_set (res1, t);
+	  mpz_divexact (res1, res1, in2);
+	  MPZ_CHECK_FORMAT (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL2 (mpz_divexact, t, in2, NULL);
+
+	  mpz_set (res1, in2);
+	  mpz_divexact (res1, t, res1);
+	  MPZ_CHECK_FORMAT (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL2 (mpz_divexact, t, in2, NULL);
+	}
+
+      if (mpz_sgn (in2) > 0)
+	{
+	  /* Test mpz_divexact_gcd, same as mpz_divexact */
+	  mpz_mul (t, in1, in2);
+	  mpz_divexact_gcd (ref1, t, in2);
+	  MPZ_CHECK_FORMAT (ref1);
+
+	  mpz_set (res1, t);
+	  mpz_divexact_gcd (res1, res1, in2);
+	  MPZ_CHECK_FORMAT (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL2 (mpz_divexact_gcd, t, in2, NULL);
+
+	  mpz_set (res1, in2);
+	  mpz_divexact_gcd (res1, t, res1);
+	  MPZ_CHECK_FORMAT (res1);
+	  if (mpz_cmp (ref1, res1) != 0)
+	    FAIL2 (mpz_divexact_gcd, t, in2, NULL);
+	}
+    }
+
+  if (isatty (fileno (stdout)))
+    printf ("\r%20s", "");
+
+  mpz_clear (bs);
+  mpz_clear (in1);
+  mpz_clear (in2);
+  mpz_clear (in3);
+  mpz_clear (ref1);
+  mpz_clear (ref2);
+  mpz_clear (ref3);
+  mpz_clear (res1);
+  mpz_clear (res2);
+  mpz_clear (res3);
+  mpz_clear (t);
+
+  if (isatty (fileno (stdout)))
+    printf ("\r");
+
+  tests_end ();
+  exit (0);
+}
+
+void
+dump (const char *name, mpz_t in1, mpz_t in2, mpz_t in3)
+{
+  printf ("failure in %s (", name);
+  0 && mpz_out_str (stdout, -16, in1);
+  if (in2 != NULL)
+    {
+      printf (" ");
+      0 && mpz_out_str (stdout, -16, in2);
+    }
+  if (in3 != NULL)
+    {
+      printf (" ");
+      0 && mpz_out_str (stdout, -16, in3);
+    }
+  printf (")\n");
+}
+
+#endif /* ! DLL_EXPORT */
diff --git a/third_party/gmp/tests/mpz/t-addsub.c b/third_party/gmp/tests/mpz/t-addsub.c
new file mode 100644
index 0000000..aaa3188
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-addsub.c
@@ -0,0 +1,121 @@
+/* Test mpz_add, mpz_sub, mpz_add_ui, mpz_sub_ui, and mpz_ui_sub.
+
+Copyright 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "longlong.h"
+#include "tests.h"
+
+void debug_mp (mpz_t, int);
+void dump_abort (int, const char *, mpz_t, mpz_t);
+
+int
+main (int argc, char **argv)
+{
+  mpz_t op1, op2, r1, r2;
+  mp_size_t op1n, op2n;
+  unsigned long int op2long;
+  int i;
+  int reps = 100000;
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long bsi, size_range;
+
+  tests_start ();
+  rands = RANDS;
+
+  mpz_init (bs);
+
+  if (argc == 2)
+     reps = atoi (argv[1]);
+
+  mpz_init (op1);
+  mpz_init (op2);
+  mpz_init (r1);
+  mpz_init (r2);
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 10 + 2;
+
+      mpz_urandomb (bs, rands, size_range);
+      op1n = mpz_get_ui (bs);
+      mpz_rrandomb (op1, rands, op1n);
+
+      mpz_urandomb (bs, rands, size_range);
+      op2n = mpz_get_ui (bs);
+      mpz_rrandomb (op2, rands, op2n);
+
+      mpz_urandomb (bs, rands, 2);
+      bsi = mpz_get_ui (bs);
+      if ((bsi & 1) != 0)
+	mpz_neg (op1, op1);
+      if ((bsi & 2) != 0)
+	mpz_neg (op2, op2);
+
+      /* printf ("%ld %ld\n", SIZ (multiplier), SIZ (multiplicand)); */
+
+      mpz_add (r1, op1, op2);
+      mpz_sub (r2, r1, op2);
+      if (mpz_cmp (r2, op1) != 0)
+	dump_abort (i, "mpz_add or mpz_sub incorrect", op1, op2);
+
+      if (mpz_fits_ulong_p (op2))
+	{
+	  op2long = mpz_get_ui (op2);
+	  mpz_add_ui (r1, op1, op2long);
+	  mpz_sub_ui (r2, r1, op2long);
+	  if (mpz_cmp (r2, op1) != 0)
+	    dump_abort (i, "mpz_add_ui or mpz_sub_ui incorrect", op1, op2);
+
+	  mpz_ui_sub (r1, op2long, op1);
+	  mpz_sub_ui (r2, op1, op2long);
+	  mpz_neg (r2, r2);
+	  if (mpz_cmp (r1, r2) != 0)
+	    dump_abort (i, "mpz_add_ui or mpz_ui_sub incorrect", op1, op2);
+	}
+    }
+
+  mpz_clear (bs);
+  mpz_clear (op1);
+  mpz_clear (op2);
+  mpz_clear (r1);
+  mpz_clear (r2);
+
+  tests_end ();
+  exit (0);
+}
+
+void
+dump_abort (int i, const char *s, mpz_t op1, mpz_t op2)
+{
+  fprintf (stderr, "ERROR: %s in test %d\n", s, i);
+  fprintf (stderr, "op1 = "); debug_mp (op1, -16);
+  fprintf (stderr, "op2 = "); debug_mp (op2, -16);
+  abort();
+}
+
+void
+debug_mp (mpz_t x, int base)
+{
+  mpz_out_str (stderr, base, x); fputc ('\n', stderr);
+}
diff --git a/third_party/gmp/tests/mpz/t-aorsmul.c b/third_party/gmp/tests/mpz/t-aorsmul.c
new file mode 100644
index 0000000..f31e758
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-aorsmul.c
@@ -0,0 +1,421 @@
+/* Test mpz_addmul, mpz_addmul_ui, mpz_submul, mpz_submul_ui.
+
+Copyright 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+#define M GMP_NUMB_MAX
+
+
+void
+check_one_inplace (mpz_srcptr w, mpz_srcptr y)
+{
+  mpz_t  want, got;
+
+  mpz_init (want);
+  mpz_init (got);
+
+  mpz_mul (want, w, y);
+  mpz_add (want, w, want);
+  mpz_set (got, w);
+  mpz_addmul (got, got, y);
+  MPZ_CHECK_FORMAT (got);
+  if (mpz_cmp (want, got) != 0)
+    {
+      printf ("mpz_addmul inplace fail\n");
+    fail:
+      mpz_trace ("w", w);
+      mpz_trace ("y", y);
+      mpz_trace ("want", want);
+      mpz_trace ("got ", got);
+      abort ();
+    }
+
+  mpz_mul (want, w, y);
+  mpz_sub (want, w, want);
+  mpz_set (got, w);
+  mpz_submul (got, got, y);
+  MPZ_CHECK_FORMAT (got);
+  if (mpz_cmp (want, got) != 0)
+    {
+      printf ("mpz_submul inplace fail\n");
+      goto fail;
+    }
+
+  mpz_clear (want);
+  mpz_clear (got);
+}
+
+void
+check_one_ui_inplace (mpz_ptr w, unsigned long y)
+{
+  mpz_t  want, got;
+
+  mpz_init (want);
+  mpz_init (got);
+
+  mpz_mul_ui (want, w, (unsigned long) y);
+  mpz_add (want, w, want);
+  mpz_set (got, w);
+  mpz_addmul_ui (got, got, (unsigned long) y);
+  MPZ_CHECK_FORMAT (got);
+  if (mpz_cmp (want, got) != 0)
+    {
+      printf ("mpz_addmul_ui fail\n");
+    fail:
+      mpz_trace ("w", w);
+      printf    ("y=0x%lX   %lu\n", y, y);
+      mpz_trace ("want", want);
+      mpz_trace ("got ", got);
+      abort ();
+    }
+
+  mpz_mul_ui (want, w, y);
+  mpz_sub (want, w, want);
+  mpz_set (got, w);
+  mpz_submul_ui (got, got, y);
+  MPZ_CHECK_FORMAT (got);
+  if (mpz_cmp (want, got) != 0)
+    {
+      printf ("mpz_submul_ui fail\n");
+      goto fail;
+    }
+
+  mpz_clear (want);
+  mpz_clear (got);
+}
+
+void
+check_all_inplace (mpz_ptr w, mpz_ptr y)
+{
+  int  wneg, yneg;
+
+  MPZ_CHECK_FORMAT (w);
+  MPZ_CHECK_FORMAT (y);
+
+  for (wneg = 0; wneg < 2; wneg++)
+    {
+      for (yneg = 0; yneg < 2; yneg++)
+        {
+          check_one_inplace (w, y);
+
+          if (mpz_fits_ulong_p (y))
+            check_one_ui_inplace (w, mpz_get_ui (y));
+
+          mpz_neg (y, y);
+        }
+      mpz_neg (w, w);
+    }
+}
+
+void
+check_one (mpz_srcptr w, mpz_srcptr x, mpz_srcptr y)
+{
+  mpz_t  want, got;
+
+  mpz_init (want);
+  mpz_init (got);
+
+  mpz_mul (want, x, y);
+  mpz_add (want, w, want);
+  mpz_set (got, w);
+  mpz_addmul (got, x, y);
+  MPZ_CHECK_FORMAT (got);
+  if (mpz_cmp (want, got) != 0)
+    {
+      printf ("mpz_addmul fail\n");
+    fail:
+      mpz_trace ("w", w);
+      mpz_trace ("x", x);
+      mpz_trace ("y", y);
+      mpz_trace ("want", want);
+      mpz_trace ("got ", got);
+      abort ();
+    }
+
+  mpz_mul (want, x, y);
+  mpz_sub (want, w, want);
+  mpz_set (got, w);
+  mpz_submul (got, x, y);
+  MPZ_CHECK_FORMAT (got);
+  if (mpz_cmp (want, got) != 0)
+    {
+      printf ("mpz_submul fail\n");
+      goto fail;
+    }
+
+  mpz_clear (want);
+  mpz_clear (got);
+}
+
+void
+check_one_ui (mpz_ptr w, mpz_ptr x, unsigned long y)
+{
+  mpz_t  want, got;
+
+  mpz_init (want);
+  mpz_init (got);
+
+  mpz_mul_ui (want, x, (unsigned long) y);
+  mpz_add (want, w, want);
+  mpz_set (got, w);
+  mpz_addmul_ui (got, x, (unsigned long) y);
+  MPZ_CHECK_FORMAT (got);
+  if (mpz_cmp (want, got) != 0)
+    {
+      printf ("mpz_addmul_ui fail\n");
+    fail:
+      mpz_trace ("w", w);
+      mpz_trace ("x", x);
+      printf    ("y=0x%lX   %lu\n", y, y);
+      mpz_trace ("want", want);
+      mpz_trace ("got ", got);
+      abort ();
+    }
+
+  mpz_mul_ui (want, x, y);
+  mpz_sub (want, w, want);
+  mpz_set (got, w);
+  mpz_submul_ui (got, x, y);
+  MPZ_CHECK_FORMAT (got);
+  if (mpz_cmp (want, got) != 0)
+    {
+      printf ("mpz_submul_ui fail\n");
+      goto fail;
+    }
+
+  mpz_clear (want);
+  mpz_clear (got);
+}
+
+
+void
+check_all (mpz_ptr w, mpz_ptr x, mpz_ptr y)
+{
+  int    swap, wneg, xneg, yneg;
+
+  MPZ_CHECK_FORMAT (w);
+  MPZ_CHECK_FORMAT (x);
+  MPZ_CHECK_FORMAT (y);
+
+  for (swap = 0; swap < 2; swap++)
+    {
+      for (wneg = 0; wneg < 2; wneg++)
+        {
+          for (xneg = 0; xneg < 2; xneg++)
+            {
+              for (yneg = 0; yneg < 2; yneg++)
+                {
+                  check_one (w, x, y);
+
+                  if (mpz_fits_ulong_p (y))
+                    check_one_ui (w, x, mpz_get_ui (y));
+
+                  mpz_neg (y, y);
+                }
+              mpz_neg (x, x);
+            }
+          mpz_neg (w, w);
+        }
+      mpz_swap (x, y);
+    }
+}
+
+void
+check_data_inplace_ui (void)
+{
+  static const struct {
+    mp_limb_t      w[6];
+    unsigned long  y;
+
+  } data[] = {
+
+    { { 0 }, 0 },
+    { { 0 }, 1 },
+    { { 1 }, 1 },
+    { { 2 }, 1 },
+
+    { { 123 }, 1 },
+    { { 123 }, ULONG_MAX },
+    { { M }, 1 },
+    { { M }, ULONG_MAX },
+
+    { { 123, 456 }, 1 },
+    { { M, M }, 1 },
+    { { 123, 456 }, ULONG_MAX },
+    { { M, M }, ULONG_MAX },
+
+    { { 123, 456, 789 }, 1 },
+    { { M, M, M }, 1 },
+    { { 123, 456, 789 }, ULONG_MAX },
+    { { M, M, M }, ULONG_MAX },
+  };
+
+  mpz_t  w, y;
+  int    i;
+
+  mpz_init (w);
+  mpz_init (y);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_set_n (w, data[i].w, (mp_size_t) numberof(data[i].w));
+      mpz_set_ui (y, data[i].y);
+      check_all_inplace (w, y);
+    }
+
+  mpz_clear (w);
+  mpz_clear (y);
+}
+
+void
+check_data (void)
+{
+  static const struct {
+    mp_limb_t  w[6];
+    mp_limb_t  x[6];
+    mp_limb_t  y[6];
+
+  } data[] = {
+
+    /* reducing to zero */
+    { { 1 }, { 1 }, { 1 } },
+    { { 2 }, { 1 }, { 2 } },
+    { { 0,1 }, { 0,1 }, { 1 } },
+
+    /* reducing to 1 */
+    { { 0,1 },       { M },       { 1 } },
+    { { 0,0,1 },     { M,M },     { 1 } },
+    { { 0,0,0,1 },   { M,M,M },   { 1 } },
+    { { 0,0,0,0,1 }, { M,M,M,M }, { 1 } },
+
+    /* reducing to -1 */
+    { { M },       { 0,1 },       { 1 } },
+    { { M,M },     { 0,0,1 },     { 1 } },
+    { { M,M,M },   { 0,0,0,1 },   { 1 } },
+    { { M,M,M,M }, { 0,0,0,0,1 }, { 1 } },
+
+    /* carry out of addmul */
+    { { M },     { 1 }, { 1 } },
+    { { M,M },   { 1 }, { 1 } },
+    { { M,M,M }, { 1 }, { 1 } },
+
+    /* borrow from submul */
+    { { 0,1 },     { 1 }, { 1 } },
+    { { 0,0,1 },   { 1 }, { 1 } },
+    { { 0,0,0,1 }, { 1 }, { 1 } },
+
+    /* borrow from submul */
+    { { 0,0,1 },     { 0,1 }, { 1 } },
+    { { 0,0,0,1 },   { 0,1 }, { 1 } },
+    { { 0,0,0,0,1 }, { 0,1 }, { 1 } },
+
+    /* more borrow from submul */
+    { { M }, { 0,1 },       { 1 } },
+    { { M }, { 0,0,1 },     { 1 } },
+    { { M }, { 0,0,0,1 },   { 1 } },
+    { { M }, { 0,0,0,0,1 }, { 1 } },
+
+    /* big borrow from submul */
+    { { 0,0,1 },     { M,M }, { M } },
+    { { 0,0,0,1 },   { M,M }, { M } },
+    { { 0,0,0,0,1 }, { M,M }, { M } },
+
+    /* small w */
+    { { 0,1 }, { M,M },       { M } },
+    { { 0,1 }, { M,M,M },     { M } },
+    { { 0,1 }, { M,M,M,M },   { M } },
+    { { 0,1 }, { M,M,M,M,M }, { M } },
+  };
+
+  mpz_t  w, x, y;
+  int    i;
+
+  mpz_init (w);
+  mpz_init (x);
+  mpz_init (y);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_set_n (w, data[i].w, (mp_size_t) numberof(data[i].w));
+      mpz_set_n (x, data[i].x, (mp_size_t) numberof(data[i].x));
+      mpz_set_n (y, data[i].y, (mp_size_t) numberof(data[i].y));
+      check_all (w, x, y);
+    }
+
+  mpz_clear (w);
+  mpz_clear (x);
+  mpz_clear (y);
+}
+
+
+void
+check_random (int argc, char *argv[])
+{
+  gmp_randstate_ptr rands = RANDS;
+  mpz_t  w, x, y;
+  int    i, reps = 2000;
+
+  mpz_init (w);
+  mpz_init (x);
+  mpz_init (y);
+
+  if (argc == 2)
+    reps = atoi (argv[1]);
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_errandomb (w, rands, 5*GMP_LIMB_BITS);
+      mpz_errandomb (x, rands, 5*GMP_LIMB_BITS);
+      mpz_errandomb (y, rands, 5*GMP_LIMB_BITS);
+      check_all (w, x, y);
+      check_all_inplace (w, y);
+
+      mpz_errandomb (w, rands, 5*GMP_LIMB_BITS);
+      mpz_errandomb (x, rands, 5*GMP_LIMB_BITS);
+      mpz_errandomb (y, rands, BITS_PER_ULONG);
+      check_all (w, x, y);
+      check_all_inplace (w, y);
+    }
+
+  mpz_clear (w);
+  mpz_clear (x);
+  mpz_clear (y);
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  tests_start ();
+  mp_trace_base = -16;
+
+  check_data ();
+  check_data_inplace_ui ();
+  check_random (argc, argv);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpz/t-bin.c b/third_party/gmp/tests/mpz/t-bin.c
new file mode 100644
index 0000000..1faa2e8
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-bin.c
@@ -0,0 +1,328 @@
+/* Exercise mpz_bin_ui and mpz_bin_uiui.
+
+Copyright 2000, 2001, 2010, 2012, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+/* Default number of generated tests. */
+#define COUNT 700
+
+void
+try_mpz_bin_ui (mpz_srcptr want, mpz_srcptr n, unsigned long k)
+{
+  mpz_t  got;
+
+  mpz_init (got);
+  mpz_bin_ui (got, n, k);
+  MPZ_CHECK_FORMAT (got);
+  if (mpz_cmp (got, want) != 0)
+    {
+      printf ("mpz_bin_ui wrong\n");
+      printf ("  n="); mpz_out_str (stdout, 10, n); printf ("\n");
+      printf ("  k=%lu\n", k);
+      printf ("  got="); mpz_out_str (stdout, 10, got); printf ("\n");
+      printf ("  want="); mpz_out_str (stdout, 10, want); printf ("\n");
+      abort();
+    }
+  mpz_clear (got);
+}
+
+
+void
+try_mpz_bin_uiui (mpz_srcptr want, unsigned long n, unsigned long k)
+{
+  mpz_t  got;
+
+  mpz_init (got);
+  mpz_bin_uiui (got, n, k);
+  MPZ_CHECK_FORMAT (got);
+  if (mpz_cmp (got, want) != 0)
+    {
+      printf ("mpz_bin_uiui wrong\n");
+      printf ("  n=%lu\n", n);
+      printf ("  k=%lu\n", k);
+      printf ("  got="); mpz_out_str (stdout, 10, got); printf ("\n");
+      printf ("  want="); mpz_out_str (stdout, 10, want); printf ("\n");
+      abort();
+    }
+  mpz_clear (got);
+}
+
+
+void
+samples (void)
+{
+  static const struct {
+    const char     *n;
+    unsigned long  k;
+    const char     *want;
+  } data[] = {
+
+    {   "0", 123456, "0" },
+    {   "1", 543210, "0" },
+    {   "2", 123321, "0" },
+    {   "3", 234567, "0" },
+    {   "10", 23456, "0" },
+
+    /* negatives, using bin(-n,k)=bin(n+k-1,k) */
+    {   "-1",  0,  "1"  },
+    {   "-1",  1, "-1"  },
+    {   "-1",  2,  "1"  },
+    {   "-1",  3, "-1"  },
+    {   "-1",  4,  "1"  },
+
+    {   "-2",  0,  "1"  },
+    {   "-2",  1, "-2"  },
+    {   "-2",  2,  "3"  },
+    {   "-2",  3, "-4"  },
+    {   "-2",  4,  "5"  },
+    {   "-2",  5, "-6"  },
+    {   "-2",  6,  "7"  },
+
+    {   "-3",  0,   "1"  },
+    {   "-3",  1,  "-3"  },
+    {   "-3",  2,   "6"  },
+    {   "-3",  3, "-10"  },
+    {   "-3",  4,  "15"  },
+    {   "-3",  5, "-21"  },
+    {   "-3",  6,  "28"  },
+
+    /* A few random values */
+    {   "41", 20,  "269128937220" },
+    {   "62", 37,  "147405545359541742" },
+    {   "50", 18,  "18053528883775" },
+    {  "149", 21,  "19332950844468483467894649" },
+  };
+
+  mpz_t  n, want;
+  int    i;
+
+  mpz_init (n);
+  mpz_init (want);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_set_str_or_abort (n, data[i].n, 0);
+      mpz_set_str_or_abort (want, data[i].want, 0);
+
+      try_mpz_bin_ui (want, n, data[i].k);
+
+      if (mpz_fits_ulong_p (n))
+	try_mpz_bin_uiui (want, mpz_get_ui (n), data[i].k);
+    }
+
+  mpz_clear (n);
+  mpz_clear (want);
+}
+
+
+/* Test some bin(2k,k) cases.  This produces some biggish numbers to
+   exercise the limb accumulating code.  */
+void
+twos (int count)
+{
+  mpz_t          n, want;
+  unsigned long  k;
+
+  mpz_init (n);
+
+  mpz_init_set_ui (want, (unsigned long) 2);
+  for (k = 1; k < count; k++)
+    {
+      mpz_set_ui (n, 2*k);
+      try_mpz_bin_ui (want, n, k);
+
+      try_mpz_bin_uiui (want, 2*k, k);
+
+      mpz_mul_ui (want, want, 2*(2*k+1));
+      mpz_fdiv_q_ui (want, want, k+1);
+    }
+
+  mpz_clear (n);
+  mpz_clear (want);
+}
+
+/* Test some random bin(n,k) cases.  This produces some biggish
+   numbers to exercise the limb accumulating code.  */
+void
+randomwalk (int count)
+{
+  mpz_t          n_z, want, tmp;
+  unsigned long  n, k, i, r;
+  int            tests;
+  gmp_randstate_ptr rands;
+
+  rands = RANDS;
+  mpz_init (n_z);
+
+  k = 3;
+  n = 12;
+  mpz_init_set_ui (want, (unsigned long) 220); /* binomial(12,3) = 220 */
+
+  for (tests = 1; tests < count; tests++)
+    {
+      r = gmp_urandomm_ui (rands, 62) + 1;
+      for (i = r & 7; i > 0; i--)
+	{
+	  n++; k++;
+	  mpz_mul_ui (want, want, n);
+	  mpz_fdiv_q_ui (want, want, k);
+	}
+      for (i = r >> 3; i > 0; i--)
+	{
+	  n++;
+	  mpz_mul_ui (want, want, n);
+	  mpz_fdiv_q_ui (want, want, n - k);
+	}
+
+      mpz_set_ui (n_z, n);
+      try_mpz_bin_ui (want, n_z, k);
+
+      try_mpz_bin_uiui (want, n, k);
+    }
+
+  k = 2;
+  mpz_urandomb (n_z, rands, 200);
+  mpz_mul (want, n_z, n_z); /* want = n_z ^ 2 */
+  mpz_sub (want, want, n_z); /* want = n_z ^ 2 - n_z = n_z (n_z- 1) */
+  mpz_tdiv_q_2exp (want, want, 1); /* want = n_z (n_z- 1) / 2 = binomial (n_z, 2) */
+  mpz_init (tmp);
+  for (tests = 1; tests < count; tests++)
+    {
+      r = gmp_urandomm_ui (rands, 62) + 1;
+      for (i = r & 7; i > 0; i--)
+	{
+	  k++;
+	  mpz_add_ui (n_z, n_z, 1);
+	  mpz_mul (want, want, n_z);
+	  mpz_tdiv_q_ui (want, want, k);
+	}
+      for (i = r >> 3; i > 0; i--)
+	{
+	  mpz_add_ui (n_z, n_z, 1);
+	  mpz_mul (want, want, n_z);
+	  mpz_sub_ui (tmp, n_z, k);
+	  mpz_tdiv_q (want, want, tmp);
+	}
+
+      try_mpz_bin_ui (want, n_z, k);
+    }
+
+  mpz_clear (tmp);
+  mpz_clear (n_z);
+  mpz_clear (want);
+}
+
+/* Test some random bin(n,k) cases.  This produces some biggish
+   numbers to exercise the limb accumulating code.  */
+void
+randomwalk_down (int count)
+{
+  mpz_t          n_z, want, tmp;
+  unsigned long  n, k, i, r;
+  int            tests;
+  gmp_randstate_ptr rands;
+
+  rands = RANDS;
+  mpz_init (n_z);
+  mpz_init (tmp);
+
+  k = 2;
+  n = ULONG_MAX;
+  mpz_init_set_ui (want, n);
+  mpz_mul_ui (want, want, n >> 1);
+
+  for (tests = 1; tests < count; tests++)
+    {
+      r = gmp_urandomm_ui (rands, 62) + 1;
+      for (i = r & 7; i > 0; i--)
+	{
+	  mpz_mul_ui (want, want, n - k);
+	  ++k;
+	  mpz_tdiv_q_ui (want, want, k);
+	}
+      for (i = r >> 3; i > 0; i--)
+	{
+	  mpz_mul_ui (want, want, n - k);
+	  mpz_tdiv_q_ui (want, want, n);
+	  --n;
+	}
+
+      mpz_set_ui (n_z, n);
+      try_mpz_bin_ui (want, n_z, n - k);
+
+      try_mpz_bin_uiui (want, n, n - k);
+    }
+
+  mpz_clear (tmp);
+  mpz_clear (n_z);
+  mpz_clear (want);
+}
+
+
+/* Test all bin(n,k) cases, with 0 <= k <= n + 1 <= count.  */
+void
+smallexaustive (unsigned int count)
+{
+  mpz_t          n_z, want;
+  unsigned long  n, k;
+
+  mpz_init (n_z);
+  mpz_init (want);
+
+  for (n = 0; n < count; n++)
+    {
+      mpz_set_ui (want, (unsigned long) 1);
+      mpz_set_ui (n_z, n);
+      for (k = 0; k <= n; k++)
+	{
+	  try_mpz_bin_ui (want, n_z, k);
+	  try_mpz_bin_uiui (want, n, k);
+	  mpz_mul_ui (want, want, n - k);
+	  mpz_fdiv_q_ui (want, want, k + 1);
+	}
+      try_mpz_bin_ui (want, n_z, k);
+      try_mpz_bin_uiui (want, n, k);
+    }
+
+  mpz_clear (n_z);
+  mpz_clear (want);
+}
+
+int
+main (int argc, char **argv)
+{
+  int count;
+
+  count = COUNT;
+  TESTS_REPS (count, argv, argc);
+
+  tests_start ();
+
+  samples ();
+  smallexaustive (count >> 4);
+  twos (count >> 1);
+  randomwalk (count - (count >> 1));
+  randomwalk_down (count >> 1);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpz/t-cdiv_ui.c b/third_party/gmp/tests/mpz/t-cdiv_ui.c
new file mode 100644
index 0000000..91559ea
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-cdiv_ui.c
@@ -0,0 +1,158 @@
+/* Test mpz_abs, mpz_add, mpz_cmp, mpz_cmp_ui, mpz_cdiv_qr_ui, mpz_cdiv_q_ui,
+   mpz_cdiv_r_ui, , mpz_cdiv_ui, mpz_mul_ui.
+
+Copyright 1993, 1994, 1996, 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+void dump_abort (const char *, mpz_t, unsigned long);
+void debug_mp (mpz_t, int);
+
+int
+main (int argc, char **argv)
+{
+  mpz_t dividend;
+  mpz_t quotient, remainder;
+  mpz_t quotient2, remainder2;
+  mpz_t temp;
+  mp_size_t dividend_size;
+  unsigned long divisor;
+  int i;
+  int reps = 10000;
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long bsi, size_range;
+  unsigned long r_rq, r_q, r_r, r;
+
+  tests_start ();
+  rands = RANDS;
+
+  mpz_init (bs);
+
+  if (argc == 2)
+     reps = atoi (argv[1]);
+
+  mpz_init (dividend);
+  mpz_init (quotient);
+  mpz_init (remainder);
+  mpz_init (quotient2);
+  mpz_init (remainder2);
+  mpz_init (temp);
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 10 + 2; /* 0..2047 bit operands */
+
+      do
+	{
+	  mpz_rrandomb (bs, rands, 64);
+	  divisor = mpz_get_ui (bs);
+	}
+      while (divisor == 0);
+
+      mpz_urandomb (bs, rands, size_range);
+      dividend_size = mpz_get_ui (bs);
+      mpz_rrandomb (dividend, rands, dividend_size);
+
+      mpz_urandomb (bs, rands, 2);
+      bsi = mpz_get_ui (bs);
+      if ((bsi & 1) != 0)
+	mpz_neg (dividend, dividend);
+
+      /* printf ("%ld\n", SIZ (dividend)); */
+
+      r_rq = mpz_cdiv_qr_ui (quotient, remainder, dividend, divisor);
+      r_q = mpz_cdiv_q_ui (quotient2, dividend, divisor);
+      r_r = mpz_cdiv_r_ui (remainder2, dividend, divisor);
+      r = mpz_cdiv_ui (dividend, divisor);
+
+      /* First determine that the quotients and remainders computed
+	 with different functions are equal.  */
+      if (mpz_cmp (quotient, quotient2) != 0)
+	dump_abort ("quotients from mpz_cdiv_qr_ui and mpz_cdiv_q_ui differ",
+		    dividend, divisor);
+      if (mpz_cmp (remainder, remainder2) != 0)
+	dump_abort ("remainders from mpz_cdiv_qr_ui and mpz_cdiv_r_ui differ",
+		    dividend, divisor);
+
+      /* Check if the sign of the quotient is correct.  */
+      if (mpz_cmp_ui (quotient, 0) != 0)
+	if ((mpz_cmp_ui (quotient, 0) < 0)
+	    != (mpz_cmp_ui (dividend, 0) < 0))
+	dump_abort ("quotient sign wrong", dividend, divisor);
+
+      /* Check if the remainder has the opposite sign as the (positive) divisor
+	 (quotient rounded towards minus infinity).  */
+      if (mpz_cmp_ui (remainder, 0) != 0)
+	if (mpz_cmp_ui (remainder, 0) > 0)
+	  dump_abort ("remainder sign wrong", dividend, divisor);
+
+      mpz_mul_ui (temp, quotient, divisor);
+      mpz_add (temp, temp, remainder);
+      if (mpz_cmp (temp, dividend) != 0)
+	dump_abort ("n mod d != n - [n/d]*d", dividend, divisor);
+
+      mpz_abs (remainder, remainder);
+      if (mpz_cmp_ui (remainder, divisor) >= 0)
+	dump_abort ("remainder greater than divisor", dividend, divisor);
+
+      if (mpz_cmp_ui (remainder, r_rq) != 0)
+	dump_abort ("remainder returned from mpz_cdiv_qr_ui is wrong",
+		    dividend, divisor);
+      if (mpz_cmp_ui (remainder, r_q) != 0)
+	dump_abort ("remainder returned from mpz_cdiv_q_ui is wrong",
+		    dividend, divisor);
+      if (mpz_cmp_ui (remainder, r_r) != 0)
+	dump_abort ("remainder returned from mpz_cdiv_r_ui is wrong",
+		    dividend, divisor);
+      if (mpz_cmp_ui (remainder, r) != 0)
+	dump_abort ("remainder returned from mpz_cdiv_ui is wrong",
+		    dividend, divisor);
+    }
+
+  mpz_clear (bs);
+  mpz_clear (dividend);
+  mpz_clear (quotient);
+  mpz_clear (remainder);
+  mpz_clear (quotient2);
+  mpz_clear (remainder2);
+  mpz_clear (temp);
+
+  tests_end ();
+  exit (0);
+}
+
+void
+dump_abort (const char *str, mpz_t dividend, unsigned long divisor)
+{
+  fprintf (stderr, "ERROR: %s\n", str);
+  fprintf (stderr, "dividend = "); debug_mp (dividend, -16);
+  fprintf (stderr, "divisor  = %lX\n", divisor);
+  abort();
+}
+
+void
+debug_mp (mpz_t x, int base)
+{
+  mpz_out_str (stderr, base, x); fputc ('\n', stderr);
+}
diff --git a/third_party/gmp/tests/mpz/t-cmp.c b/third_party/gmp/tests/mpz/t-cmp.c
new file mode 100644
index 0000000..1ae2517
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-cmp.c
@@ -0,0 +1,181 @@
+/* Test mpz_cmp and mpz_cmpabs.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+/* Nothing sophisticated here, just exercise some combinations of sizes and
+   signs.  */
+
+
+void
+check_one (mpz_ptr x, mpz_ptr y, int want_cmp, int want_cmpabs)
+{
+  int  got;
+
+  got = mpz_cmp (x, y);
+  if ((   got <  0) != (want_cmp <  0)
+      || (got == 0) != (want_cmp == 0)
+      || (got >  0) != (want_cmp >  0))
+    {
+      printf ("mpz_cmp got %d want %d\n", got, want_cmp);
+      mpz_trace ("x", x);
+      mpz_trace ("y", y);
+      abort ();
+    }
+
+  got = mpz_cmpabs (x, y);
+  if ((   got <  0) != (want_cmpabs <  0)
+      || (got == 0) != (want_cmpabs == 0)
+      || (got >  0) != (want_cmpabs >  0))
+    {
+      printf ("mpz_cmpabs got %d want %d\n", got, want_cmpabs);
+      mpz_trace ("x", x);
+      mpz_trace ("y", y);
+      abort ();
+    }
+}
+
+
+void
+check_all (mpz_ptr x, mpz_ptr y, int want_cmp, int want_cmpabs)
+{
+  check_one (x, y,  want_cmp,  want_cmpabs);
+  check_one (y, x, -want_cmp, -want_cmpabs);
+
+  mpz_neg (x, x);
+  mpz_neg (y, y);
+  want_cmp = -want_cmp;
+
+  check_one (x, y,  want_cmp,  want_cmpabs);
+  check_one (y, x, -want_cmp, -want_cmpabs);
+}
+
+
+#define SET1(z,size, n) \
+  SIZ(z) = size; PTR(z)[0] = n
+
+#define SET2(z,size, n1,n0) \
+  SIZ(z) = size; PTR(z)[1] = n1; PTR(z)[0] = n0
+
+#define SET4(z,size, n3,n2,n1,n0) \
+  SIZ(z) = size; PTR(z)[3] = n3; PTR(z)[2] = n2; PTR(z)[1] = n1; PTR(z)[0] = n0
+
+void
+check_various (void)
+{
+  mpz_t  x, y;
+
+  mpz_init (x);
+  mpz_init (y);
+
+  mpz_realloc (x, (mp_size_t) 20);
+  mpz_realloc (y, (mp_size_t) 20);
+
+  /* 0 cmp 0, junk in low limbs */
+  SET1 (x,0, 123);
+  SET1 (y,0, 456);
+  check_all (x, y, 0, 0);
+
+
+  /* 123 cmp 0 */
+  SET1 (x,1, 123);
+  SET1 (y,0, 456);
+  check_all (x, y, 1, 1);
+
+  /* 123:456 cmp 0 */
+  SET2 (x,2, 456,123);
+  SET1 (y,0, 9999);
+  check_all (x, y, 1, 1);
+
+
+  /* 123 cmp 123 */
+  SET1(x,1, 123);
+  SET1(y,1, 123);
+  check_all (x, y, 0, 0);
+
+  /* -123 cmp 123 */
+  SET1(x,-1, 123);
+  SET1(y,1,  123);
+  check_all (x, y, -1, 0);
+
+
+  /* 123 cmp 456 */
+  SET1(x,1, 123);
+  SET1(y,1, 456);
+  check_all (x, y, -1, -1);
+
+  /* -123 cmp 456 */
+  SET1(x,-1, 123);
+  SET1(y,1,  456);
+  check_all (x, y, -1, -1);
+
+  /* 123 cmp -456 */
+  SET1(x,1,  123);
+  SET1(y,-1, 456);
+  check_all (x, y, 1, -1);
+
+
+  /* 1:0 cmp 1:0 */
+  SET2 (x,2, 1,0);
+  SET2 (y,2, 1,0);
+  check_all (x, y, 0, 0);
+
+  /* -1:0 cmp 1:0 */
+  SET2 (x,-2, 1,0);
+  SET2 (y,2,  1,0);
+  check_all (x, y, -1, 0);
+
+
+  /* 2:0 cmp 1:0 */
+  SET2 (x,2, 2,0);
+  SET2 (y,2, 1,0);
+  check_all (x, y, 1, 1);
+
+
+  /* 4:3:2:1 cmp 2:1 */
+  SET4 (x,4, 4,3,2,1);
+  SET2 (y,2, 2,1);
+  check_all (x, y, 1, 1);
+
+  /* -4:3:2:1 cmp 2:1 */
+  SET4 (x,-4, 4,3,2,1);
+  SET2 (y,2,  2,1);
+  check_all (x, y, -1, 1);
+
+
+  mpz_clear (x);
+  mpz_clear (y);
+}
+
+
+int
+main (void)
+{
+  tests_start ();
+  mp_trace_base = -16;
+
+  check_various ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpz/t-cmp_d.c b/third_party/gmp/tests/mpz/t-cmp_d.c
new file mode 100644
index 0000000..d7b9895
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-cmp_d.c
@@ -0,0 +1,292 @@
+/* Test mpz_cmp_d and mpz_cmpabs_d.
+
+Copyright 2001-2003, 2005 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+/* FIXME: Not sure if the tests here are exhaustive.  Ought to try to get
+   each possible exit from mpz_cmp_d (and mpz_cmpabs_d) exercised.  */
+
+
+#define SGN(n)  ((n) > 0 ? 1 : (n) < 0 ? -1 : 0)
+
+
+void
+check_one (const char *name, mpz_srcptr x, double y, int cmp, int cmpabs)
+{
+  int   got;
+
+  got = mpz_cmp_d (x, y);
+  if (SGN(got) != cmp)
+    {
+      int i;
+      printf    ("mpz_cmp_d wrong (from %s)\n", name);
+      printf    ("  got  %d\n", got);
+      printf    ("  want %d\n", cmp);
+    fail:
+      mpz_trace ("  x", x);
+      printf    ("  y %g\n", y);
+      mp_trace_base=-16;
+      mpz_trace ("  x", x);
+      printf    ("  y %g\n", y);
+      printf    ("  y");
+      for (i = 0; i < sizeof(y); i++)
+        printf (" %02X", (unsigned) ((unsigned char *) &y)[i]);
+      printf ("\n");
+      abort ();
+    }
+
+  got = mpz_cmpabs_d (x, y);
+  if (SGN(got) != cmpabs)
+    {
+      printf    ("mpz_cmpabs_d wrong\n");
+      printf    ("  got  %d\n", got);
+      printf    ("  want %d\n", cmpabs);
+      goto fail;
+    }
+}
+
+
+void
+check_data (void)
+{
+  static const struct {
+    const char  *x;
+    double      y;
+    int         cmp, cmpabs;
+
+  } data[] = {
+
+    {  "0",  0.0,  0,  0 },
+
+    {  "1",  0.0,  1,  1 },
+    { "-1",  0.0, -1,  1 },
+
+    {  "1",  0.5,  1,  1 },
+    { "-1", -0.5, -1,  1 },
+
+    {  "0",  1.0, -1, -1 },
+    {  "0", -1.0,  1, -1 },
+
+    {  "0x1000000000000000000000000000000000000000000000000", 1.0,  1, 1 },
+    { "-0x1000000000000000000000000000000000000000000000000", 1.0, -1, 1 },
+
+    {  "0",  1e100, -1, -1 },
+    {  "0", -1e100,  1, -1 },
+
+    {  "2",  1.5,   1,  1 },
+    {  "2", -1.5,   1,  1 },
+    { "-2",  1.5,  -1,  1 },
+    { "-2", -1.5,  -1,  1 },
+  };
+
+  mpz_t  x;
+  int    i;
+
+  mpz_init (x);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_set_str_or_abort (x, data[i].x, 0);
+      check_one ("check_data", x, data[i].y, data[i].cmp, data[i].cmpabs);
+    }
+
+  mpz_clear (x);
+}
+
+
+/* Equality of integers with up to 53 bits */
+void
+check_onebits (void)
+{
+  mpz_t   x, x2;
+  double  y;
+  int     i;
+
+  mpz_init_set_ui (x, 0L);
+  mpz_init (x2);
+
+  for (i = 0; i < 512; i++)
+    {
+      mpz_mul_2exp (x, x, 1);
+      mpz_add_ui (x, x, 1L);
+
+      y = mpz_get_d (x);
+      mpz_set_d (x2, y);
+
+      /* stop if any truncation is occurring */
+      if (mpz_cmp (x, x2) != 0)
+        break;
+
+      check_one ("check_onebits", x, y, 0, 0);
+      check_one ("check_onebits", x, -y, 1, 0);
+      mpz_neg (x, x);
+      check_one ("check_onebits", x, y, -1, 0);
+      check_one ("check_onebits", x, -y, 0, 0);
+      mpz_neg (x, x);
+    }
+
+  mpz_clear (x);
+  mpz_clear (x2);
+}
+
+
+/* With the mpz differing by 1, in a limb position possibly below the double */
+void
+check_low_z_one (void)
+{
+  mpz_t          x;
+  double         y;
+  unsigned long  i;
+
+  mpz_init (x);
+
+  /* FIXME: It'd be better to base this on the float format. */
+#if defined (__vax) || defined (__vax__)
+#define LIM 127			/* vax fp numbers have limited range */
+#else
+#define LIM 512
+#endif
+
+  for (i = 1; i < LIM; i++)
+    {
+      mpz_set_ui (x, 1L);
+      mpz_mul_2exp (x, x, i);
+      y = mpz_get_d (x);
+
+      check_one ("check_low_z_one", x, y,   0, 0);
+      check_one ("check_low_z_one", x, -y,  1, 0);
+      mpz_neg (x, x);
+      check_one ("check_low_z_one", x, y,  -1, 0);
+      check_one ("check_low_z_one", x, -y,  0, 0);
+      mpz_neg (x, x);
+
+      mpz_sub_ui (x, x, 1);
+
+      check_one ("check_low_z_one", x, y,  -1, -1);
+      check_one ("check_low_z_one", x, -y,  1, -1);
+      mpz_neg (x, x);
+      check_one ("check_low_z_one", x, y,  -1, -1);
+      check_one ("check_low_z_one", x, -y,  1, -1);
+      mpz_neg (x, x);
+
+      mpz_add_ui (x, x, 2);
+
+      check_one ("check_low_z_one", x, y,   1, 1);
+      check_one ("check_low_z_one", x, -y,  1, 1);
+      mpz_neg (x, x);
+      check_one ("check_low_z_one", x, y,  -1, 1);
+      check_one ("check_low_z_one", x, -y, -1, 1);
+      mpz_neg (x, x);
+    }
+
+  mpz_clear (x);
+}
+
+/* Comparing 1 and 1+2^-n.  "y" is volatile to make gcc store and fetch it,
+   which forces it to a 64-bit double, whereas on x86 it would otherwise
+   remain on the float stack as an 80-bit long double.  */
+void
+check_one_2exp (void)
+{
+  double           e;
+  mpz_t            x;
+  volatile double  y;
+  int              i;
+
+  mpz_init (x);
+
+  e = 1.0;
+  for (i = 0; i < 128; i++)
+    {
+      e /= 2.0;
+      y = 1.0 + e;
+      if (y == 1.0)
+        break;
+
+      mpz_set_ui (x, 1L);
+      check_one ("check_one_2exp", x,  y, -1, -1);
+      check_one ("check_one_2exp", x, -y,  1, -1);
+
+      mpz_set_si (x, -1L);
+      check_one ("check_one_2exp", x,  y, -1, -1);
+      check_one ("check_one_2exp", x, -y,  1, -1);
+    }
+
+  mpz_clear (x);
+}
+
+void
+check_infinity (void)
+{
+  mpz_t   x;
+  double  y = tests_infinity_d ();
+  if (y == 0.0)
+    return;
+
+  mpz_init (x);
+
+  /* 0 cmp inf */
+  mpz_set_ui (x, 0L);
+  check_one ("check_infinity", x,  y, -1, -1);
+  check_one ("check_infinity", x, -y,  1, -1);
+
+  /* 123 cmp inf */
+  mpz_set_ui (x, 123L);
+  check_one ("check_infinity", x,  y, -1, -1);
+  check_one ("check_infinity", x, -y,  1, -1);
+
+  /* -123 cmp inf */
+  mpz_set_si (x, -123L);
+  check_one ("check_infinity", x,  y, -1, -1);
+  check_one ("check_infinity", x, -y,  1, -1);
+
+  /* 2^5000 cmp inf */
+  mpz_set_ui (x, 1L);
+  mpz_mul_2exp (x, x, 5000L);
+  check_one ("check_infinity", x,  y, -1, -1);
+  check_one ("check_infinity", x, -y,  1, -1);
+
+  /* -2^5000 cmp inf */
+  mpz_neg (x, x);
+  check_one ("check_infinity", x,  y, -1, -1);
+  check_one ("check_infinity", x, -y,  1, -1);
+
+  mpz_clear (x);
+}
+
+int
+main (int argc, char *argv[])
+{
+  tests_start ();
+
+  check_data ();
+  check_onebits ();
+  check_low_z_one ();
+  check_one_2exp ();
+  check_infinity ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpz/t-cmp_si.c b/third_party/gmp/tests/mpz/t-cmp_si.c
new file mode 100644
index 0000000..7667d3e
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-cmp_si.c
@@ -0,0 +1,101 @@
+/* Test mpz_cmp_si.
+
+Copyright 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+#define SGN(x)       ((x) < 0 ? -1 : (x) == 0 ? 0 : 1)
+
+void
+check_data (void)
+{
+  static const struct {
+    const char  *a, *b;
+    int         want;
+  } data[] = {
+    { "0",  "1", -1 },
+    { "0",  "0",  0 },
+    { "0", "-1",  1 },
+
+    { "1",  "1", 0 },
+    { "1",  "0", 1 },
+    { "1", "-1", 1 },
+
+    { "-1",  "1", -1 },
+    { "-1",  "0", -1 },
+    { "-1", "-1", 0 },
+
+    {           "0", "-0x80000000",  1 },
+    {  "0x80000000", "-0x80000000",  1 },
+    {  "0x80000001", "-0x80000000",  1 },
+    { "-0x80000000", "-0x80000000",  0 },
+    { "-0x80000001", "-0x80000000", -1 },
+
+    {                   "0", "-0x8000000000000000",  1 },
+    {  "0x8000000000000000", "-0x8000000000000000",  1 },
+    {  "0x8000000000000001", "-0x8000000000000000",  1 },
+    { "-0x8000000000000000", "-0x8000000000000000",  0 },
+    { "-0x8000000000000001", "-0x8000000000000000", -1 },
+  };
+
+  mpz_t  a, bz;
+  long   b;
+  int    got;
+  int    i;
+
+  mpz_init (a);
+  mpz_init (bz);
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_set_str_or_abort (a, data[i].a, 0);
+      mpz_set_str_or_abort (bz, data[i].b, 0);
+
+      if (mpz_fits_slong_p (bz))
+	{
+	  b = mpz_get_si (bz);
+	  got = mpz_cmp_si (a, b);
+	  if (SGN (got) != data[i].want)
+	    {
+	      printf ("mpz_cmp_si wrong on data[%d]\n", i);
+	      printf ("  a="); mpz_out_str (stdout, 10, a); printf ("\n");
+	      printf ("  b=%ld\n", b);
+	      printf ("  got=%d\n", got);
+	      printf ("  want=%d\n", data[i].want);
+	      abort();
+	    }
+	}
+    }
+
+  mpz_clear (a);
+  mpz_clear (bz);
+}
+
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_data ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpz/t-cong.c b/third_party/gmp/tests/mpz/t-cong.c
new file mode 100644
index 0000000..59d8526
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-cong.c
@@ -0,0 +1,226 @@
+/* test mpz_congruent_p and mpz_congruent_ui_p
+
+Copyright 2001, 2002, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_one (mpz_srcptr a, mpz_srcptr c, mpz_srcptr d, int want)
+{
+  int   got;
+  int   swap;
+
+  for (swap = 0; swap <= 1; swap++)
+    {
+      got = (mpz_congruent_p (a, c, d) != 0);
+      if (want != got)
+	{
+	  printf ("mpz_congruent_p wrong\n");
+	  printf ("   expected %d got %d\n", want, got);
+	  mpz_trace ("	 a", a);
+	  mpz_trace ("	 c", c);
+	  mpz_trace ("	 d", d);
+	  mp_trace_base = -16;
+	  mpz_trace ("	 a", a);
+	  mpz_trace ("	 c", c);
+	  mpz_trace ("	 d", d);
+	  abort ();
+	}
+
+      if (mpz_fits_ulong_p (c) && mpz_fits_ulong_p (d))
+	{
+	  unsigned long	 uc = mpz_get_ui (c);
+	  unsigned long	 ud = mpz_get_ui (d);
+	  got = (mpz_congruent_ui_p (a, uc, ud) != 0);
+	  if (want != got)
+	    {
+	      printf	("mpz_congruent_ui_p wrong\n");
+	      printf	("   expected %d got %d\n", want, got);
+	      mpz_trace ("   a", a);
+	      printf	("   c=%lu\n", uc);
+	      printf	("   d=%lu\n", ud);
+	      mp_trace_base = -16;
+	      mpz_trace ("   a", a);
+	      printf	("   c=0x%lX\n", uc);
+	      printf	("   d=0x%lX\n", ud);
+	      abort ();
+	    }
+	}
+
+      MPZ_SRCPTR_SWAP (a, c);
+    }
+}
+
+
+void
+check_data (void)
+{
+  static const struct {
+    const char *a;
+    const char *c;
+    const char *d;
+    int        want;
+
+  } data[] = {
+
+    /* strict equality mod 0 */
+    { "0", "0", "0", 1 },
+    { "11", "11", "0", 1 },
+    { "3", "11", "0", 0 },
+
+    /* anything congruent mod 1 */
+    { "0", "0", "1", 1 },
+    { "1", "0", "1", 1 },
+    { "0", "1", "1", 1 },
+    { "123", "456", "1", 1 },
+    { "0x123456789123456789", "0x987654321987654321", "1", 1 },
+
+    /* csize==1, dsize==2 changing to 1 after stripping 2s */
+    { "0x3333333333333333",  "0x33333333",
+      "0x180000000", 1 },
+    { "0x33333333333333333333333333333333", "0x3333333333333333",
+      "0x18000000000000000", 1 },
+
+    /* another dsize==2 becoming 1, with opposite signs this time */
+    {  "0x444444441",
+      "-0x22222221F",
+       "0x333333330", 1 },
+    {  "0x44444444444444441",
+      "-0x2222222222222221F",
+       "0x33333333333333330", 1 },
+  };
+
+  mpz_t   a, c, d;
+  int     i;
+
+  mpz_init (a);
+  mpz_init (c);
+  mpz_init (d);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_set_str_or_abort (a, data[i].a, 0);
+      mpz_set_str_or_abort (c, data[i].c, 0);
+      mpz_set_str_or_abort (d, data[i].d, 0);
+      check_one (a, c, d, data[i].want);
+    }
+
+  mpz_clear (a);
+  mpz_clear (c);
+  mpz_clear (d);
+}
+
+
+void
+check_random (int argc, char *argv[])
+{
+  gmp_randstate_ptr rands = RANDS;
+  mpz_t   a, c, d, ra, rc;
+  int     i;
+  int     want;
+  int     reps = 10000;
+  mpz_t bs;
+  unsigned long size_range, size;
+
+  if (argc >= 2)
+    reps = atoi (argv[1]);
+
+  mpz_init (bs);
+
+  mpz_init (a);
+  mpz_init (c);
+  mpz_init (d);
+  mpz_init (ra);
+  mpz_init (rc);
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 16 + 1; /* 0..65536 bit operands */
+
+      mpz_urandomb (bs, rands, size_range);
+      size = mpz_get_ui (bs);
+      mpz_rrandomb (a, rands, size);
+
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 16 + 1; /* 0..65536 bit operands */
+
+      mpz_urandomb (bs, rands, size_range);
+      size = mpz_get_ui (bs);
+      mpz_rrandomb (c, rands, size);
+
+      do
+	{
+	  mpz_urandomb (bs, rands, 32);
+	  size_range = mpz_get_ui (bs) % 16 + 1; /* 0..65536 bit operands */
+
+	  mpz_urandomb (bs, rands, size_range);
+	  size = mpz_get_ui (bs);
+	  mpz_rrandomb (d, rands, size);
+	}
+      while (SIZ(d) == 0);
+
+      mpz_negrandom (a, rands);
+      MPZ_CHECK_FORMAT (a);
+      mpz_negrandom (c, rands);
+      MPZ_CHECK_FORMAT (c);
+      mpz_negrandom (d, rands);
+
+      mpz_fdiv_r (ra, a, d);
+      mpz_fdiv_r (rc, c, d);
+
+      want = (mpz_cmp (ra, rc) == 0);
+      check_one (a, c, d, want);
+
+      mpz_sub (ra, ra, rc);
+      mpz_sub (a, a, ra);
+      MPZ_CHECK_FORMAT (a);
+      check_one (a, c, d, 1);
+
+      if (! mpz_pow2abs_p (d))
+        {
+	  refmpz_combit (a, urandom() % (8*GMP_LIMB_BITS));
+	  check_one (a, c, d, 0);
+        }
+    }
+
+  mpz_clear (bs);
+
+  mpz_clear (a);
+  mpz_clear (c);
+  mpz_clear (d);
+  mpz_clear (ra);
+  mpz_clear (rc);
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  tests_start ();
+
+  check_data ();
+  check_random (argc, argv);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpz/t-cong_2exp.c b/third_party/gmp/tests/mpz/t-cong_2exp.c
new file mode 100644
index 0000000..5ffe2d1
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-cong_2exp.c
@@ -0,0 +1,207 @@
+/* test mpz_congruent_2exp_p */
+
+/*
+Copyright 2001, 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_one (mpz_srcptr a, mpz_srcptr c, unsigned long d, int want)
+{
+  mpz_t  diff, d2exp;
+  int    got;
+  int    swap;
+
+  for (swap = 0; swap <= 1; swap++)
+    {
+      got = (mpz_congruent_2exp_p (a, c, d) != 0);
+      if (want != got)
+        {
+          mpz_init (diff);
+          mpz_init (d2exp);
+
+          mpz_sub (diff, a, c);
+          mpz_set_ui (d2exp, 1L);
+          mpz_mul_2exp (d2exp, d2exp, d);
+
+          printf ("mpz_congruent_2exp_p wrong\n");
+          printf ("   expected %d got %d\n", want, got);
+          mpz_trace ("   a", a);
+          mpz_trace ("   c", c);
+          mpz_trace (" a-c", diff);
+          mpz_trace (" 2^d", d2exp);
+          printf    ("   d=%lu\n", d);
+
+          mp_trace_base = -16;
+          mpz_trace ("   a", a);
+          mpz_trace ("   c", c);
+          mpz_trace (" a-c", diff);
+          mpz_trace (" 2^d", d2exp);
+          printf    ("   d=0x%lX\n", d);
+          abort ();
+        }
+
+      MPZ_SRCPTR_SWAP (a, c);
+    }
+}
+
+
+void
+check_data (void)
+{
+  static const struct {
+    const char     *a;
+    const char     *c;
+    unsigned long  d;
+    int            want;
+
+  } data[] = {
+
+    /* anything is congruent mod 1 */
+    { "0", "0", 0, 1 },
+    { "1", "0", 0, 1 },
+    { "0", "1", 0, 1 },
+    { "123", "-456", 0, 1 },
+    { "0x123456789123456789", "0x987654321987654321", 0, 1 },
+    { "0xfffffffffffffffffffffffffffffff7", "-0x9", 129, 0 },
+    { "0xfffffffffffffffffffffffffffffff6", "-0xa", 128, 1 },
+
+  };
+
+  mpz_t   a, c;
+  int     i;
+
+  mpz_init (a);
+  mpz_init (c);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_set_str_or_abort (a, data[i].a, 0);
+      mpz_set_str_or_abort (c, data[i].c, 0);
+      check_one (a, c, data[i].d, data[i].want);
+    }
+
+  mpz_clear (a);
+  mpz_clear (c);
+}
+
+
+void
+check_random (int reps)
+{
+  gmp_randstate_ptr rands = RANDS;
+  unsigned long  d;
+  mpz_t  a, c, ra, rc;
+  int    i;
+
+  mpz_init (a);
+  mpz_init (c);
+  mpz_init (ra);
+  mpz_init (rc);
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_errandomb (a, rands, 8*GMP_LIMB_BITS);
+      mpz_errandomb (c, rands, 8*GMP_LIMB_BITS);
+      d = urandom() % (8*GMP_LIMB_BITS);
+
+      mpz_mul_2exp (a, a, urandom() % (2*GMP_LIMB_BITS));
+      mpz_mul_2exp (c, c, urandom() % (2*GMP_LIMB_BITS));
+
+      mpz_negrandom (a, rands);
+      mpz_negrandom (c, rands);
+
+      mpz_fdiv_r_2exp (ra, a, d);
+      mpz_fdiv_r_2exp (rc, c, d);
+
+      mpz_sub (ra, ra, rc);
+      if (mpz_cmp_ui (ra, 0) != 0)
+	{
+	  check_one (a, c, d, 0);
+	  mpz_sub (a, a, ra);
+	}
+      check_one (a, c, d, 1);
+      if (d != 0)
+	{
+	  mpz_combit (a, urandom() % d);
+	  check_one (a, c, d, 0);
+	}
+    }
+
+  mpz_clear (a);
+  mpz_clear (c);
+  mpz_clear (ra);
+  mpz_clear (rc);
+}
+
+void
+check_random_bits (int reps)
+{
+  mp_bitcnt_t ea, ec, en, d;
+  mp_bitcnt_t m = 10 * GMP_LIMB_BITS;
+  mpz_t  a, c;
+  int    i;
+
+  mpz_init2 (a, m + 1);
+  mpz_init2 (c, m);
+
+  for (i = 0; i < reps; i++)
+    {
+      d  = urandom() % m;
+      ea = urandom() % m;
+      ec = urandom() % m;
+      en = urandom() % m;
+
+      mpz_set_ui (c, 0);
+      mpz_setbit (c, en);
+
+      mpz_set_ui (a, 0);
+      mpz_setbit (a, ec);
+      mpz_sub (c , a, c);
+
+      mpz_set_ui (a, 0);
+      mpz_setbit (a, ea);
+      mpz_add (a , a, c);
+
+      check_one (a, c, d, ea >= d);
+    }
+
+  mpz_clear (a);
+  mpz_clear (c);
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  int    reps = 5000;
+
+  tests_start ();
+  TESTS_REPS (reps, argv, argc);
+
+  check_data ();
+  check_random (reps);
+  check_random_bits (reps);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpz/t-div_2exp.c b/third_party/gmp/tests/mpz/t-div_2exp.c
new file mode 100644
index 0000000..d012aae
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-div_2exp.c
@@ -0,0 +1,223 @@
+/* Test mpz_[cft]div_[qr]_2exp.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+/* If the remainder is in the correct range and q*d+r is correct, then q
+   must have rounded correctly.  */
+
+void
+check_one (mpz_srcptr a, unsigned long d)
+{
+  mpz_t  q, r, p, d2exp;
+  int    inplace;
+
+  mpz_init (d2exp);
+  mpz_init (q);
+  mpz_init (r);
+  mpz_init (p);
+
+  mpz_set_ui (d2exp, 1L);
+  mpz_mul_2exp (d2exp, d2exp, d);
+
+#define INPLACE(fun,dst,src,d)  \
+  if (inplace)                  \
+    {                           \
+      mpz_set (dst, src);       \
+      fun (dst, dst, d);        \
+    }                           \
+  else                          \
+    fun (dst, src, d);
+
+  for (inplace = 0; inplace <= 1; inplace++)
+    {
+      INPLACE (mpz_fdiv_q_2exp, q, a, d);
+      INPLACE (mpz_fdiv_r_2exp, r, a, d);
+
+      mpz_mul_2exp (p, q, d);
+      mpz_add (p, p, r);
+      if (mpz_sgn (r) < 0 || mpz_cmp (r, d2exp) >= 0)
+	{
+	  printf ("mpz_fdiv_r_2exp result out of range\n");
+	  goto error;
+	}
+      if (mpz_cmp (p, a) != 0)
+	{
+	  printf ("mpz_fdiv_[qr]_2exp doesn't multiply back\n");
+	  goto error;
+	}
+
+
+      INPLACE (mpz_cdiv_q_2exp, q, a, d);
+      INPLACE (mpz_cdiv_r_2exp, r, a, d);
+
+      mpz_mul_2exp (p, q, d);
+      mpz_add (p, p, r);
+      if (mpz_sgn (r) > 0 || mpz_cmpabs (r, d2exp) >= 0)
+	{
+	  printf ("mpz_cdiv_r_2exp result out of range\n");
+	  goto error;
+	}
+      if (mpz_cmp (p, a) != 0)
+	{
+	  printf ("mpz_cdiv_[qr]_2exp doesn't multiply back\n");
+	  goto error;
+	}
+
+
+      INPLACE (mpz_tdiv_q_2exp, q, a, d);
+      INPLACE (mpz_tdiv_r_2exp, r, a, d);
+
+      mpz_mul_2exp (p, q, d);
+      mpz_add (p, p, r);
+      if (mpz_sgn (r) != 0 && mpz_sgn (r) != mpz_sgn (a))
+	{
+	  printf ("mpz_tdiv_r_2exp result wrong sign\n");
+	  goto error;
+	}
+      if (mpz_cmpabs (r, d2exp) >= 0)
+	{
+	  printf ("mpz_tdiv_r_2exp result out of range\n");
+	  goto error;
+	}
+      if (mpz_cmp (p, a) != 0)
+	{
+	  printf ("mpz_tdiv_[qr]_2exp doesn't multiply back\n");
+	  goto error;
+	}
+    }
+
+  mpz_clear (d2exp);
+  mpz_clear (q);
+  mpz_clear (r);
+  mpz_clear (p);
+  return;
+
+
+ error:
+  mpz_trace ("a", a);
+  printf    ("d=%lu\n", d);
+  mpz_trace ("q", q);
+  mpz_trace ("r", r);
+  mpz_trace ("p", p);
+
+  mp_trace_base = -16;
+  mpz_trace ("a", a);
+  printf    ("d=0x%lX\n", d);
+  mpz_trace ("q", q);
+  mpz_trace ("r", r);
+  mpz_trace ("p", p);
+
+  abort ();
+}
+
+
+void
+check_all (mpz_ptr a, unsigned long d)
+{
+  check_one (a, d);
+  mpz_neg (a, a);
+  check_one (a, d);
+}
+
+
+void
+check_various (void)
+{
+  static const unsigned long  table[] = {
+    0, 1, 2, 3, 4, 5,
+    GMP_NUMB_BITS-1, GMP_NUMB_BITS, GMP_NUMB_BITS+1,
+    2*GMP_NUMB_BITS-1, 2*GMP_NUMB_BITS, 2*GMP_NUMB_BITS+1,
+    3*GMP_NUMB_BITS-1, 3*GMP_NUMB_BITS, 3*GMP_NUMB_BITS+1,
+    4*GMP_NUMB_BITS-1, 4*GMP_NUMB_BITS, 4*GMP_NUMB_BITS+1
+  };
+
+  int            i, j;
+  unsigned long  n, d;
+  mpz_t          a;
+
+  mpz_init (a);
+
+  /* a==0, and various d */
+  mpz_set_ui (a, 0L);
+  for (i = 0; i < numberof (table); i++)
+    check_one (a, table[i]);
+
+  /* a==2^n, and various d */
+  for (i = 0; i < numberof (table); i++)
+    {
+      n = table[i];
+      mpz_set_ui (a, 1L);
+      mpz_mul_2exp (a, a, n);
+
+      for (j = 0; j < numberof (table); j++)
+	{
+	  d = table[j];
+	  check_all (a, d);
+	}
+    }
+
+  mpz_clear (a);
+}
+
+
+void
+check_random (int argc, char *argv[])
+{
+  gmp_randstate_ptr  rands = RANDS;
+  int            reps = 100;
+  mpz_t          a;
+  unsigned long  d;
+  int            i;
+
+  if (argc == 2)
+    reps = atoi (argv[1]);
+
+  mpz_init (a);
+
+  for (i = 0; i < reps; i++)
+    {
+      /* exponentially within 2 to 257 bits */
+      mpz_erandomb (a, rands, urandom () % 8 + 2);
+
+      d = urandom () % 256;
+
+      check_all (a, d);
+    }
+
+  mpz_clear (a);
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  tests_start ();
+
+  check_various ();
+  check_random (argc, argv);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpz/t-divis.c b/third_party/gmp/tests/mpz/t-divis.c
new file mode 100644
index 0000000..fe8186a
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-divis.c
@@ -0,0 +1,166 @@
+/* test mpz_divisible_p and mpz_divisible_ui_p
+
+Copyright 2001, 2009 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_one (mpz_srcptr a, mpz_srcptr d, int want)
+{
+  int   got;
+
+  if (mpz_fits_ulong_p (d))
+    {
+      unsigned long  u = mpz_get_ui (d);
+      got = (mpz_divisible_ui_p (a, u) != 0);
+      if (want != got)
+        {
+          printf ("mpz_divisible_ui_p wrong\n");
+          printf ("   expected %d got %d\n", want, got);
+          mpz_trace ("   a", a);
+          printf ("   d=%lu\n", u);
+          mp_trace_base = -16;
+          mpz_trace ("   a", a);
+          printf ("   d=0x%lX\n", u);
+          abort ();
+        }
+    }
+
+  got = (mpz_divisible_p (a, d) != 0);
+  if (want != got)
+    {
+      printf ("mpz_divisible_p wrong\n");
+      printf ("   expected %d got %d\n", want, got);
+      mpz_trace ("   a", a);
+      mpz_trace ("   d", d);
+      mp_trace_base = -16;
+      mpz_trace ("   a", a);
+      mpz_trace ("   d", d);
+      abort ();
+    }
+}
+
+void
+check_data (void)
+{
+  static const struct {
+    const char *a;
+    const char *d;
+    int        want;
+
+  } data[] = {
+
+    { "0",    "0", 1 },
+    { "17",   "0", 0 },
+    { "0",    "1", 1 },
+    { "123",  "1", 1 },
+    { "-123", "1", 1 },
+
+    { "0",  "2", 1 },
+    { "1",  "2", 0 },
+    { "2",  "2", 1 },
+    { "-2", "2", 1 },
+    { "0x100000000000000000000000000000000", "2", 1 },
+    { "0x100000000000000000000000000000001", "2", 0 },
+
+    { "0x3333333333333333", "3", 1 },
+    { "0x3333333333333332", "3", 0 },
+    { "0x33333333333333333333333333333333", "3", 1 },
+    { "0x33333333333333333333333333333332", "3", 0 },
+
+    /* divisor changes from 2 to 1 limb after stripping 2s */
+    {          "0x3333333300000000",         "0x180000000",         1 },
+    {  "0x33333333333333330000000000000000", "0x18000000000000000", 1 },
+    { "0x133333333333333330000000000000000", "0x18000000000000000", 0 },
+  };
+
+  mpz_t   a, d;
+  int     i;
+
+  mpz_init (a);
+  mpz_init (d);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_set_str_or_abort (a, data[i].a, 0);
+      mpz_set_str_or_abort (d, data[i].d, 0);
+      check_one (a, d, data[i].want);
+    }
+
+  mpz_clear (a);
+  mpz_clear (d);
+}
+
+void
+check_random (int reps)
+{
+  gmp_randstate_ptr rands = RANDS;
+  mpz_t   a, d, r;
+  int     i;
+  int     want;
+
+  mpz_init (a);
+  mpz_init (d);
+  mpz_init (r);
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_erandomb (a, rands, 1 << 19);
+      mpz_erandomb_nonzero (d, rands, 1 << 18);
+
+      mpz_fdiv_r (r, a, d);
+
+      want = (mpz_sgn (r) == 0);
+      check_one (a, d, want);
+
+      mpz_sub (a, a, r);
+      check_one (a, d, 1);
+
+      if (mpz_cmpabs_ui (d, 1L) == 0)
+        continue;
+
+      mpz_add_ui (a, a, 1L);
+      check_one (a, d, 0);
+    }
+
+  mpz_clear (a);
+  mpz_clear (d);
+  mpz_clear (r);
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  int  reps = 100;
+
+  tests_start ();
+
+  TESTS_REPS (reps, argv, argc);
+
+  check_data ();
+  check_random (reps);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpz/t-divis_2exp.c b/third_party/gmp/tests/mpz/t-divis_2exp.c
new file mode 100644
index 0000000..636c751
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-divis_2exp.c
@@ -0,0 +1,132 @@
+/* test mpz_divisible_2exp_p */
+
+/*
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_one (mpz_srcptr a, unsigned long d, int want)
+{
+  int   got;
+
+  got = (mpz_divisible_2exp_p (a, d) != 0);
+  if (want != got)
+    {
+      printf ("mpz_divisible_2exp_p wrong\n");
+      printf ("   expected %d got %d\n", want, got);
+      mpz_trace ("   a", a);
+      printf    ("   d=%lu\n", d);
+      mp_trace_base = -16;
+      mpz_trace ("   a", a);
+      printf    ("   d=0x%lX\n", d);
+      abort ();
+    }
+}
+
+void
+check_data (void)
+{
+  static const struct {
+    const char    *a;
+    unsigned long d;
+    int           want;
+
+  } data[] = {
+
+    { "0", 0, 1 },
+    { "0", 1, 1 },
+    { "0", 2, 1 },
+    { "0", 3, 1 },
+
+    { "1", 0, 1 },
+    { "1", 1, 0 },
+    { "1", 2, 0 },
+    { "1", 3, 0 },
+    { "1", 10000, 0 },
+
+    { "4", 0, 1 },
+    { "4", 1, 1 },
+    { "4", 2, 1 },
+    { "4", 3, 0 },
+    { "4", 4, 0 },
+    { "4", 10000, 0 },
+
+    { "0x80000000", 31, 1 },
+    { "0x80000000", 32, 0 },
+    { "0x80000000", 64, 0 },
+
+    { "0x100000000", 32, 1 },
+    { "0x100000000", 33, 0 },
+    { "0x100000000", 64, 0 },
+
+    { "0x8000000000000000", 63, 1 },
+    { "0x8000000000000000", 64, 0 },
+    { "0x8000000000000000", 128, 0 },
+
+    { "0x10000000000000000", 64, 1 },
+    { "0x10000000000000000", 65, 0 },
+    { "0x10000000000000000", 128, 0 },
+    { "0x10000000000000000", 256, 0 },
+
+    { "0x10000000000000000100000000", 32, 1 },
+    { "0x10000000000000000100000000", 33, 0 },
+    { "0x10000000000000000100000000", 64, 0 },
+
+    { "0x1000000000000000010000000000000000", 64, 1 },
+    { "0x1000000000000000010000000000000000", 65, 0 },
+    { "0x1000000000000000010000000000000000", 128, 0 },
+    { "0x1000000000000000010000000000000000", 256, 0 },
+    { "0x1000000000000000010000000000000000", 1024, 0 },
+
+  };
+
+  mpz_t   a, d;
+  int     i;
+
+  mpz_init (a);
+  mpz_init (d);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_set_str_or_abort (a, data[i].a, 0);
+      check_one (a, data[i].d, data[i].want);
+
+      mpz_neg (a, a);
+      check_one (a, data[i].d, data[i].want);
+    }
+
+  mpz_clear (a);
+  mpz_clear (d);
+}
+
+int
+main (int argc, char *argv[])
+{
+  tests_start ();
+
+  check_data ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpz/t-export.c b/third_party/gmp/tests/mpz/t-export.c
new file mode 100644
index 0000000..fa411e3
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-export.c
@@ -0,0 +1,205 @@
+/* Test mpz_export.
+
+Copyright 2002, 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_data (void)
+{
+  static const struct {
+    const char  *src;
+    size_t      want_count;
+    int         order;
+    size_t      size;
+    int         endian;
+    int         nail;
+    char        want_data[64];
+
+  } data[] = {
+
+    { "0", 0,1, 1,1, 0 },
+    { "0", 0,1, 2,1, 0 },
+    { "0", 0,1, 3,1, 0 },
+
+    { "0x12345678", 4,1,  1,1, 0, { '\022', '\064', '\126', '\170' } },
+    { "0x12345678", 1,1,  4,1, 0, { '\022', '\064', '\126', '\170' } },
+    { "0x12345678", 1,-1, 4,1, 0, { '\022', '\064', '\126', '\170' } },
+
+    { "0x12345678", 4,-1, 1,-1, 0, { '\170', '\126', '\064', '\022' } },
+    { "0x12345678", 1,1,  4,-1, 0, { '\170', '\126', '\064', '\022' } },
+    { "0x12345678", 1,-1, 4,-1, 0, { '\170', '\126', '\064', '\022' } },
+
+    { "0x15", 5,1,  1,1, 7, { '\001', '\000', '\001', '\000', '\001' } },
+
+    { "0x1FFFFFFFFFFF", 3,1,  2,1,   1, {
+	'\177','\377', '\177','\377', '\177','\377' } },
+    { "0x1FFFFFFFFFFF", 3,1,  2,-1,  1, {
+	'\377','\177', '\377','\177', '\377','\177' } },
+    { "0x7",            3,1,  2,1,  15, {
+	'\000','\001', '\000','\001', '\000','\001' } },
+    { "0x7",            3,1,  2,-1, 15, {
+	'\001','\000', '\001','\000', '\001','\000' } },
+
+    { "0x24", 3,1,  2,1,  14, { '\000','\002', '\000','\001', '\000','\000' }},
+    { "0x24", 3,1,  2,-1, 14, { '\002','\000', '\001','\000', '\000','\000' }},
+    { "0x24", 3,-1, 2,-1, 14, { '\000','\000', '\001','\000', '\002','\000' }},
+    { "0x24", 3,-1, 2,1,  14, { '\000','\000', '\000','\001', '\000','\002' }},
+
+    { "0x123456789ABC", 3,1,  2,1,  0, {
+	'\022','\064', '\126','\170', '\232','\274' } },
+    { "0x123456789ABC", 3,-1, 2,1,  0, {
+	'\232','\274', '\126','\170', '\022','\064' } },
+    { "0x123456789ABC", 3,1,  2,-1, 0, {
+	'\064','\022', '\170','\126', '\274','\232' } },
+    { "0x123456789ABC", 3,-1, 2,-1, 0, {
+	'\274','\232', '\170','\126', '\064','\022' } },
+
+    { "0x112233445566778899AABBCC", 3,1,  4,1,  0,
+      { '\021','\042','\063','\104',
+	'\125','\146','\167','\210',
+	'\231','\252','\273','\314' } },
+    { "0x112233445566778899AABBCC", 3,-1, 4,1,  0,
+      { '\231','\252','\273','\314',
+	'\125','\146','\167','\210',
+	'\021','\042','\063','\104' } },
+    { "0x112233445566778899AABBCC", 3,1,  4,-1, 0,
+      { '\104','\063','\042','\021',
+	'\210','\167','\146','\125',
+	'\314','\273','\252','\231' } },
+    { "0x112233445566778899AABBCC", 3,-1, 4,-1, 0,
+      { '\314','\273','\252','\231',
+	'\210','\167','\146','\125',
+	'\104','\063','\042','\021' } },
+
+    { "0x100120023003400450056006700780089009A00AB00BC00C", 3,1,  8,1,  0,
+      { '\020','\001','\040','\002','\060','\003','\100','\004',
+	'\120','\005','\140','\006','\160','\007','\200','\010',
+	'\220','\011','\240','\012','\260','\013','\300','\014' } },
+    { "0x100120023003400450056006700780089009A00AB00BC00C", 3,-1, 8,1,  0,
+      { '\220','\011','\240','\012','\260','\013','\300','\014',
+	'\120','\005','\140','\006','\160','\007','\200','\010',
+	'\020','\001','\040','\002','\060','\003','\100','\004' } },
+    { "0x100120023003400450056006700780089009A00AB00BC00C", 3,1,  8,-1, 0,
+      { '\004','\100','\003','\060','\002','\040','\001','\020',
+	'\010','\200','\007','\160','\006','\140','\005','\120',
+	'\014','\300','\013','\260','\012','\240','\011','\220' } },
+    { "0x100120023003400450056006700780089009A00AB00BC00C", 3,-1, 8,-1, 0,
+      { '\014','\300','\013','\260','\012','\240','\011','\220',
+	'\010','\200','\007','\160','\006','\140','\005','\120',
+	'\004','\100','\003','\060','\002','\040','\001','\020' } },
+
+    { "0x155555555555555555555555", 3,1,  4,1,  1,
+      { '\125','\125','\125','\125',
+	'\052','\252','\252','\252',
+	'\125','\125','\125','\125' } },
+    { "0x155555555555555555555555", 3,-1,  4,1,  1,
+      { '\125','\125','\125','\125',
+	'\052','\252','\252','\252',
+	'\125','\125','\125','\125' } },
+    { "0x155555555555555555555555", 3,1,  4,-1,  1,
+      { '\125','\125','\125','\125',
+	'\252','\252','\252','\052',
+	'\125','\125','\125','\125' } },
+    { "0x155555555555555555555555", 3,-1,  4,-1,  1,
+      { '\125','\125','\125','\125',
+	'\252','\252','\252','\052',
+	'\125','\125','\125','\125' } },
+  };
+
+  char    buf[sizeof(data[0].src) + sizeof (mp_limb_t) + 128];
+  char    *got_data;
+  void    *ret;
+  size_t  align, got_count, j;
+  int     i, error = 0;
+  mpz_t   src;
+
+  mpz_init (src);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      for (align = 0; align < sizeof (mp_limb_t); align++)
+	{
+	  mpz_set_str_or_abort (src, data[i].src, 0);
+	  MPZ_CHECK_FORMAT (src);
+	  got_data = buf + align;
+
+	  ASSERT_ALWAYS (data[i].want_count * data[i].size + align
+			 <= sizeof (buf));
+
+	  memset (got_data, '\0', data[i].want_count * data[i].size);
+	  ret = mpz_export (got_data, &got_count, data[i].order,
+			    data[i].size, data[i].endian, data[i].nail, src);
+
+	  if (ret != got_data)
+	    {
+	      printf ("return doesn't equal given pointer\n");
+	      error = 1;
+	    }
+	  if (got_count != data[i].want_count)
+	    {
+	      printf ("wrong count\n");
+	      error = 1;
+	    }
+	  if (memcmp (got_data, data[i].want_data, got_count * data[i].size) != 0)
+	    {
+	      printf ("wrong result data\n");
+	      error = 1;
+	    }
+	  if (error)
+	    {
+	      printf ("    at data[%d]  align=%d\n", i, (int) align);
+	      printf ("    src \"%s\"\n", data[i].src);
+	      mpz_trace ("    src", src);
+	      printf ("    order=%d  size=%lu endian=%d nail=%u\n",
+		      data[i].order,
+		      (unsigned long) data[i].size, data[i].endian, data[i].nail);
+	      printf ("    want count %lu\n", (unsigned long) data[i].want_count);
+	      printf ("    got count  %lu\n", (unsigned long) got_count);
+	      printf ("    want");
+	      for (j = 0; j < data[i].want_count*data[i].size; j++)
+		printf (" 0x%02X,", (unsigned) (unsigned char) data[i].want_data[j]);
+	      printf ("\n");
+	      printf ("    got ");
+	      for (j = 0; j < got_count*data[i].size; j++)
+		printf (" 0x%02X,", (unsigned) (unsigned char) got_data[j]);
+	      printf ("\n");
+	      abort ();
+	    }
+	}
+    }
+  mpz_clear (src);
+}
+
+
+int
+main (void)
+{
+  tests_start ();
+
+  mp_trace_base = -16;
+  check_data ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpz/t-fac_ui.c b/third_party/gmp/tests/mpz/t-fac_ui.c
new file mode 100644
index 0000000..15b6070
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-fac_ui.c
@@ -0,0 +1,108 @@
+/* Exercise mpz_fac_ui and mpz_2fac_ui.
+
+Copyright 2000-2002, 2012, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+/* Usage: t-fac_ui [x|num]
+
+   With no arguments testing goes up to the initial value of "limit" below.
+   With a number argument tests are carried that far, or with a literal "x"
+   tests are continued without limit (this being meant only for development
+   purposes).  */
+
+
+int
+main (int argc, char *argv[])
+{
+  unsigned long  n, m;
+  unsigned long  limit = 2222;
+  mpz_t          df[2], f, r;
+
+  tests_start ();
+
+  if (argc > 1 && argv[1][0] == 'x')
+    limit = ULONG_MAX;
+  else
+    TESTS_REPS (limit, argv, argc);
+
+  /* for small limb testing */
+  limit = MIN (limit, MP_LIMB_T_MAX);
+
+  mpz_init_set_ui (df[0], 1);  /* 0!! = 1 */
+  mpz_init_set_ui (df[1], 1);  /* -1!! = 1 */
+  mpz_init_set_ui (f, 1);  /* 0! = 1 */
+  mpz_init (r);
+
+  for (n = 0, m = 0; n < limit; n++)
+    {
+      mpz_fac_ui (r, n);
+      MPZ_CHECK_FORMAT (r);
+
+      if (mpz_cmp (f, r) != 0)
+        {
+          printf ("mpz_fac_ui(%lu) wrong\n", n);
+          printf ("  got  "); mpz_out_str (stdout, 10, r); printf("\n");
+          printf ("  want "); mpz_out_str (stdout, 10, f); printf("\n");
+          abort ();
+        }
+
+      mpz_2fac_ui (r, n);
+      MPZ_CHECK_FORMAT (r);
+
+      if (mpz_cmp (df[m], r) != 0)
+        {
+          printf ("mpz_2fac_ui(%lu) wrong\n", n);
+          printf ("  got  "); mpz_out_str (stdout, 10, r); printf("\n");
+          printf ("  want "); mpz_out_str (stdout, 10, df[m]); printf("\n");
+          abort ();
+        }
+
+      m ^= 1;
+      mpz_mul_ui (df[m], df[m], n+1);  /* (n+1)!! = (n-1)!! * (n+1) */
+      mpz_mul_ui (f, f, n+1);  /* (n+1)! = n! * (n+1) */
+    }
+
+  n = 2097169; /* a prime = 1 mod 4*/
+  if (n / 2 > MP_LIMB_T_MAX)
+    n = 131041; /* a smaller prime :-) */
+  mpz_fac_ui (f, n / 2); /* ((n-1)/2)! */
+  m = mpz_fdiv_ui (f, n); /* ((n-1)/2)! mod n*/
+  mpz_set_ui (f, m);
+  mpz_mul_ui (f, f, m); /* (((n-1)/2)!)^2 */
+  m = mpz_fdiv_ui (f, n); /* (((n-1)/2)!)^2 mod n*/
+  if ( m != n - 1)
+    {
+      printf ("mpz_fac_ui(%lu) wrong\n", n / 2);
+      printf (" al-Haytham's theorem not verified: got %lu, expected %lu.\n", m, n - 1);
+      abort ();
+    }
+
+  mpz_clear (df[0]);
+  mpz_clear (df[1]);
+  mpz_clear (f);
+  mpz_clear (r);
+
+  tests_end ();
+
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpz/t-fdiv.c b/third_party/gmp/tests/mpz/t-fdiv.c
new file mode 100644
index 0000000..71503df
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-fdiv.c
@@ -0,0 +1,146 @@
+/* Test mpz_abs, mpz_add, mpz_cmp, mpz_cmp_ui, mpz_fdiv_qr, mpz_fdiv_q,
+   mpz_fdiv_r, mpz_mul.
+
+Copyright 1993, 1994, 1996, 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+void dump_abort (mpz_t, mpz_t);
+void debug_mp (mpz_t, int);
+
+int
+main (int argc, char **argv)
+{
+  mpz_t dividend, divisor;
+  mpz_t quotient, remainder;
+  mpz_t quotient2, remainder2;
+  mpz_t temp;
+  mp_size_t dividend_size, divisor_size;
+  int i;
+  int reps = 1000;
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long bsi, size_range;
+
+  tests_start ();
+  rands = RANDS;
+
+  mpz_init (bs);
+
+  if (argc == 2)
+     reps = atoi (argv[1]);
+
+  mpz_init (dividend);
+  mpz_init (divisor);
+  mpz_init (quotient);
+  mpz_init (remainder);
+  mpz_init (quotient2);
+  mpz_init (remainder2);
+  mpz_init (temp);
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 16 + 2; /* 0..131071 bit operands */
+
+      do
+	{
+	  mpz_urandomb (bs, rands, size_range);
+	  divisor_size = mpz_get_ui (bs);
+	  mpz_rrandomb (divisor, rands, divisor_size);
+	}
+      while (mpz_sgn (divisor) == 0);
+
+      mpz_urandomb (bs, rands, size_range);
+      dividend_size = mpz_get_ui (bs) + divisor_size;
+      mpz_rrandomb (dividend, rands, dividend_size);
+
+      mpz_urandomb (bs, rands, 2);
+      bsi = mpz_get_ui (bs);
+      if ((bsi & 1) != 0)
+	mpz_neg (dividend, dividend);
+      if ((bsi & 2) != 0)
+	mpz_neg (divisor, divisor);
+
+      /* printf ("%ld %ld\n", SIZ (dividend), SIZ (divisor)); */
+
+      mpz_fdiv_qr (quotient, remainder, dividend, divisor);
+      mpz_fdiv_q (quotient2, dividend, divisor);
+      mpz_fdiv_r (remainder2, dividend, divisor);
+
+      /* First determine that the quotients and remainders computed
+	 with different functions are equal.  */
+      if (mpz_cmp (quotient, quotient2) != 0)
+	dump_abort (dividend, divisor);
+      if (mpz_cmp (remainder, remainder2) != 0)
+	dump_abort (dividend, divisor);
+
+      /* Check if the sign of the quotient is correct.  */
+      if (mpz_cmp_ui (quotient, 0) != 0)
+	if ((mpz_cmp_ui (quotient, 0) < 0)
+	    != ((mpz_cmp_ui (dividend, 0) ^ mpz_cmp_ui (divisor, 0)) < 0))
+	dump_abort (dividend, divisor);
+
+      /* Check if the remainder has the same sign as the divisor
+	 (quotient rounded towards minus infinity).  */
+      if (mpz_cmp_ui (remainder, 0) != 0)
+	if ((mpz_cmp_ui (remainder, 0) < 0) != (mpz_cmp_ui (divisor, 0) < 0))
+	  dump_abort (dividend, divisor);
+
+      mpz_mul (temp, quotient, divisor);
+      mpz_add (temp, temp, remainder);
+      if (mpz_cmp (temp, dividend) != 0)
+	dump_abort (dividend, divisor);
+
+      mpz_abs (temp, divisor);
+      mpz_abs (remainder, remainder);
+      if (mpz_cmp (remainder, temp) >= 0)
+	dump_abort (dividend, divisor);
+    }
+
+  mpz_clear (bs);
+  mpz_clear (dividend);
+  mpz_clear (divisor);
+  mpz_clear (quotient);
+  mpz_clear (remainder);
+  mpz_clear (quotient2);
+  mpz_clear (remainder2);
+  mpz_clear (temp);
+
+  tests_end ();
+  exit (0);
+}
+
+void
+dump_abort (mpz_t dividend, mpz_t divisor)
+{
+  fprintf (stderr, "ERROR\n");
+  fprintf (stderr, "dividend = "); debug_mp (dividend, -16);
+  fprintf (stderr, "divisor  = "); debug_mp (divisor, -16);
+  abort();
+}
+
+void
+debug_mp (mpz_t x, int base)
+{
+  mpz_out_str (stderr, base, x); fputc ('\n', stderr);
+}
diff --git a/third_party/gmp/tests/mpz/t-fdiv_ui.c b/third_party/gmp/tests/mpz/t-fdiv_ui.c
new file mode 100644
index 0000000..87620ca
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-fdiv_ui.c
@@ -0,0 +1,158 @@
+/* Test mpz_abs, mpz_add, mpz_cmp, mpz_cmp_ui, mpz_fdiv_qr_ui, mpz_fdiv_q_ui,
+   mpz_fdiv_r_ui, mpz_fdiv_ui, mpz_mul_ui.
+
+Copyright 1993, 1994, 1996, 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+void dump_abort (const char *, mpz_t, unsigned long);
+void debug_mp (mpz_t, int);
+
+int
+main (int argc, char **argv)
+{
+  mpz_t dividend;
+  mpz_t quotient, remainder;
+  mpz_t quotient2, remainder2;
+  mpz_t temp;
+  mp_size_t dividend_size;
+  unsigned long divisor;
+  int i;
+  int reps = 10000;
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long bsi, size_range;
+  unsigned long r_rq, r_q, r_r, r;
+
+  tests_start ();
+  rands = RANDS;
+
+  mpz_init (bs);
+
+  if (argc == 2)
+     reps = atoi (argv[1]);
+
+  mpz_init (dividend);
+  mpz_init (quotient);
+  mpz_init (remainder);
+  mpz_init (quotient2);
+  mpz_init (remainder2);
+  mpz_init (temp);
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 10 + 2; /* 0..2047 bit operands */
+
+      do
+	{
+	  mpz_rrandomb (bs, rands, 64);
+	  divisor = mpz_get_ui (bs);
+	}
+      while (divisor == 0);
+
+      mpz_urandomb (bs, rands, size_range);
+      dividend_size = mpz_get_ui (bs);
+      mpz_rrandomb (dividend, rands, dividend_size);
+
+      mpz_urandomb (bs, rands, 2);
+      bsi = mpz_get_ui (bs);
+      if ((bsi & 1) != 0)
+	mpz_neg (dividend, dividend);
+
+      /* printf ("%ld\n", SIZ (dividend)); */
+
+      r_rq = mpz_fdiv_qr_ui (quotient, remainder, dividend, divisor);
+      r_q = mpz_fdiv_q_ui (quotient2, dividend, divisor);
+      r_r = mpz_fdiv_r_ui (remainder2, dividend, divisor);
+      r = mpz_fdiv_ui (dividend, divisor);
+
+      /* First determine that the quotients and remainders computed
+	 with different functions are equal.  */
+      if (mpz_cmp (quotient, quotient2) != 0)
+	dump_abort ("quotients from mpz_fdiv_qr_ui and mpz_fdiv_q_ui differ",
+		    dividend, divisor);
+      if (mpz_cmp (remainder, remainder2) != 0)
+	dump_abort ("remainders from mpz_fdiv_qr_ui and mpz_fdiv_r_ui differ",
+		    dividend, divisor);
+
+      /* Check if the sign of the quotient is correct.  */
+      if (mpz_cmp_ui (quotient, 0) != 0)
+	if ((mpz_cmp_ui (quotient, 0) < 0)
+	    != (mpz_cmp_ui (dividend, 0) < 0))
+	dump_abort ("quotient sign wrong", dividend, divisor);
+
+      /* Check if the remainder has the same sign as the (positive) divisor
+	 (quotient rounded towards minus infinity).  */
+      if (mpz_cmp_ui (remainder, 0) != 0)
+	if (mpz_cmp_ui (remainder, 0) < 0)
+	  dump_abort ("remainder sign wrong", dividend, divisor);
+
+      mpz_mul_ui (temp, quotient, divisor);
+      mpz_add (temp, temp, remainder);
+      if (mpz_cmp (temp, dividend) != 0)
+	dump_abort ("n mod d != n - [n/d]*d", dividend, divisor);
+
+      mpz_abs (remainder, remainder);
+      if (mpz_cmp_ui (remainder, divisor) >= 0)
+	dump_abort ("remainder greater than divisor", dividend, divisor);
+
+      if (mpz_cmp_ui (remainder, r_rq) != 0)
+	dump_abort ("remainder returned from mpz_fdiv_qr_ui is wrong",
+		    dividend, divisor);
+      if (mpz_cmp_ui (remainder, r_q) != 0)
+	dump_abort ("remainder returned from mpz_fdiv_q_ui is wrong",
+		    dividend, divisor);
+      if (mpz_cmp_ui (remainder, r_r) != 0)
+	dump_abort ("remainder returned from mpz_fdiv_r_ui is wrong",
+		    dividend, divisor);
+      if (mpz_cmp_ui (remainder, r) != 0)
+	dump_abort ("remainder returned from mpz_fdiv_ui is wrong",
+		    dividend, divisor);
+    }
+
+  mpz_clear (bs);
+  mpz_clear (dividend);
+  mpz_clear (quotient);
+  mpz_clear (remainder);
+  mpz_clear (quotient2);
+  mpz_clear (remainder2);
+  mpz_clear (temp);
+
+  tests_end ();
+  exit (0);
+}
+
+void
+dump_abort (const char *str, mpz_t dividend, unsigned long divisor)
+{
+  fprintf (stderr, "ERROR: %s\n", str);
+  fprintf (stderr, "dividend = "); debug_mp (dividend, -16);
+  fprintf (stderr, "divisor  = %lX\n", divisor);
+  abort();
+}
+
+void
+debug_mp (mpz_t x, int base)
+{
+  mpz_out_str (stderr, base, x); fputc ('\n', stderr);
+}
diff --git a/third_party/gmp/tests/mpz/t-fib_ui.c b/third_party/gmp/tests/mpz/t-fib_ui.c
new file mode 100644
index 0000000..ec9425c
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-fib_ui.c
@@ -0,0 +1,155 @@
+/* Test mpz_fib_ui and mpz_fib2_ui.
+
+Copyright 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+/* Usage: t-fib_ui [x|num]
+
+   Run with no arguments, tests goes up to the initial value of "limit"
+   below.  With a number argument tests are carried up that far, or with a
+   literal "x" tests are continued without limit (this being only meant for
+   development purposes).
+
+   The size tests performed are designed to partially replicate what will be
+   going on in mpz_fib_ui.  There's plenty of ASSERTs there, but of course
+   they're not normally enabled.
+
+   Misfeatures:
+
+   The tests on MPN_FIB2_SIZE are a bit useless, since that macro includes a
+   +2 for the internal purposes of mpn_fib2_ui.  It's probably better to
+   give mpn_fib2_ui a run with assertion checking enabled.  */
+
+
+#define MPZ_FIB_SIZE_FLOAT(n) \
+  ((mp_size_t) ((n) * 0.6942419 / GMP_NUMB_BITS + 1))
+
+
+void
+check_fib_table (void)
+{
+  int        i;
+  mp_limb_t  want;
+
+  ASSERT_ALWAYS (FIB_TABLE(-1) == 1);
+  ASSERT_ALWAYS (FIB_TABLE(0) == 0);
+
+  for (i = 1; i <= FIB_TABLE_LIMIT; i++)
+    {
+      want = FIB_TABLE(i-1) + FIB_TABLE(i-2);
+      if (FIB_TABLE(i) != want)
+        {
+          printf ("FIB_TABLE(%d) wrong\n", i);
+          gmp_printf ("  got  %#Nx\n", &FIB_TABLE(i), 1);
+          gmp_printf ("  want %#Nx\n", &want, 1);
+          abort ();
+        }
+    }
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  unsigned long  n;
+  unsigned long  limit = 100 * GMP_LIMB_BITS;
+  mpz_t          want_fn, want_fn1, got_fn, got_fn1;
+
+  tests_start ();
+  mp_trace_base = -16;
+  if (argc > 1 && argv[1][0] == 'x')
+    limit = ULONG_MAX;
+  else
+    TESTS_REPS (limit, argv, argc);
+
+  check_fib_table ();
+
+  /* start at n==0 */
+  mpz_init_set_ui (want_fn1, 1);  /* F[-1] */
+  mpz_init_set_ui (want_fn,  0);  /* F[0]   */
+  mpz_init (got_fn);
+  mpz_init (got_fn1);
+
+  for (n = 0; n < limit; n++)
+    {
+      /* check our float formula seems right */
+      if (MPZ_FIB_SIZE_FLOAT (n) < SIZ(want_fn))
+        {
+          printf ("MPZ_FIB_SIZE_FLOAT wrong at n=%lu\n", n);
+          printf ("  MPZ_FIB_SIZE_FLOAT  %ld\n", MPZ_FIB_SIZE_FLOAT (n));
+          printf ("  SIZ(want_fn)        %d\n", SIZ(want_fn));
+          abort ();
+        }
+
+      /* check MPN_FIB2_SIZE seems right, compared to actual size and
+         compared to our float formula */
+      if (MPN_FIB2_SIZE (n) < MPZ_FIB_SIZE_FLOAT (n))
+        {
+          printf ("MPN_FIB2_SIZE wrong at n=%lu\n", n);
+          printf ("  MPN_FIB2_SIZE       %ld\n", MPN_FIB2_SIZE (n));
+          printf ("  MPZ_FIB_SIZE_FLOAT  %ld\n", MPZ_FIB_SIZE_FLOAT (n));
+          abort ();
+        }
+      if (MPN_FIB2_SIZE (n) < SIZ(want_fn))
+        {
+          printf ("MPN_FIB2_SIZE wrong at n=%lu\n", n);
+          printf ("  MPN_FIB2_SIZE  %ld\n", MPN_FIB2_SIZE (n));
+          printf ("  SIZ(want_fn)   %d\n", SIZ(want_fn));
+          abort ();
+        }
+
+      mpz_fib2_ui (got_fn, got_fn1, n);
+      MPZ_CHECK_FORMAT (got_fn);
+      MPZ_CHECK_FORMAT (got_fn1);
+      if (mpz_cmp (got_fn, want_fn) != 0 || mpz_cmp (got_fn1, want_fn1) != 0)
+        {
+          printf ("mpz_fib2_ui(%lu) wrong\n", n);
+          mpz_trace ("want fn ", want_fn);
+          mpz_trace ("got  fn ",  got_fn);
+          mpz_trace ("want fn1", want_fn1);
+          mpz_trace ("got  fn1",  got_fn1);
+          abort ();
+        }
+
+      mpz_fib_ui (got_fn, n);
+      MPZ_CHECK_FORMAT (got_fn);
+      if (mpz_cmp (got_fn, want_fn) != 0)
+        {
+          printf ("mpz_fib_ui(%lu) wrong\n", n);
+          mpz_trace ("want fn", want_fn);
+          mpz_trace ("got  fn", got_fn);
+          abort ();
+        }
+
+      mpz_add (want_fn1, want_fn1, want_fn);  /* F[n+1] = F[n] + F[n-1] */
+      mpz_swap (want_fn1, want_fn);
+    }
+
+  mpz_clear (want_fn);
+  mpz_clear (want_fn1);
+  mpz_clear (got_fn);
+  mpz_clear (got_fn1);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpz/t-fits.c b/third_party/gmp/tests/mpz/t-fits.c
new file mode 100644
index 0000000..6819588
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-fits.c
@@ -0,0 +1,197 @@
+/* Test mpz_fits_*_p */
+
+/*
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+/* Nothing sophisticated here, just exercise mpz_fits_*_p on a small amount
+   of data. */
+
+#define EXPECT_S(fun,name,answer)                                       \
+  got = fun (z);                                                        \
+  if (got != answer)                                                    \
+    {                                                                   \
+      printf ("%s (%s) got %d want %d\n", name, expr, got, answer);     \
+      printf (" z size %d\n", SIZ(z));                                  \
+      printf (" z dec "); mpz_out_str (stdout, 10, z); printf ("\n");   \
+      printf (" z hex "); mpz_out_str (stdout, 16, z); printf ("\n");   \
+      error = 1;                                                        \
+    }
+
+#define EXPECT(fun,answer)  EXPECT_S(fun,#fun,answer)
+
+int
+main (void)
+{
+  mpz_t       z;
+  int         got;
+  const char  *expr;
+  int         error = 0;
+
+  tests_start ();
+  mpz_init (z);
+
+  mpz_set_ui (z, 0L);
+  expr = "0";
+  EXPECT (mpz_fits_ulong_p, 1);
+  EXPECT (mpz_fits_uint_p, 1);
+  EXPECT (mpz_fits_ushort_p, 1);
+  EXPECT (mpz_fits_slong_p, 1);
+  EXPECT (mpz_fits_sint_p, 1);
+  EXPECT (mpz_fits_sshort_p, 1);
+
+  mpz_set_ui (z, 1L);
+  expr = "1";
+  EXPECT (mpz_fits_ulong_p, 1);
+  EXPECT (mpz_fits_uint_p, 1);
+  EXPECT (mpz_fits_ushort_p, 1);
+  EXPECT (mpz_fits_slong_p, 1);
+  EXPECT (mpz_fits_sint_p, 1);
+  EXPECT (mpz_fits_sshort_p, 1);
+
+  mpz_set_si (z, -1L);
+  expr = "-1";
+  EXPECT (mpz_fits_ulong_p, 0);
+  EXPECT (mpz_fits_uint_p, 0);
+  EXPECT (mpz_fits_ushort_p, 0);
+  EXPECT (mpz_fits_slong_p, 1);
+  EXPECT (mpz_fits_sint_p, 1);
+  EXPECT (mpz_fits_sshort_p, 1);
+
+  mpz_set_ui (z, 1L);
+  mpz_mul_2exp (z, z, 5L*GMP_LIMB_BITS);
+  expr = "2^(5*BPML)";
+  EXPECT (mpz_fits_ulong_p, 0);
+  EXPECT (mpz_fits_uint_p, 0);
+  EXPECT (mpz_fits_ushort_p, 0);
+  EXPECT (mpz_fits_slong_p, 0);
+  EXPECT (mpz_fits_sint_p, 0);
+  EXPECT (mpz_fits_sshort_p, 0);
+
+
+  mpz_set_ui (z, (unsigned long) USHRT_MAX);
+  expr = "USHRT_MAX";
+  EXPECT (mpz_fits_ulong_p, 1);
+  EXPECT (mpz_fits_uint_p, 1);
+  EXPECT (mpz_fits_ushort_p, 1);
+
+  mpz_set_ui (z, (unsigned long) USHRT_MAX);
+  mpz_add_ui (z, z, 1L);
+  expr = "USHRT_MAX + 1";
+  EXPECT (mpz_fits_ushort_p, 0);
+
+
+  mpz_set_ui (z, (unsigned long) UINT_MAX);
+  expr = "UINT_MAX";
+  EXPECT (mpz_fits_ulong_p, 1);
+  EXPECT (mpz_fits_uint_p, 1);
+
+  mpz_set_ui (z, (unsigned long) UINT_MAX);
+  mpz_add_ui (z, z, 1L);
+  expr = "UINT_MAX + 1";
+  EXPECT (mpz_fits_uint_p, 0);
+
+
+  mpz_set_ui (z, ULONG_MAX);
+  expr = "ULONG_MAX";
+  EXPECT (mpz_fits_ulong_p, 1);
+
+  mpz_set_ui (z, ULONG_MAX);
+  mpz_add_ui (z, z, 1L);
+  expr = "ULONG_MAX + 1";
+  EXPECT (mpz_fits_ulong_p, 0);
+
+
+  mpz_set_si (z, (long) SHRT_MAX);
+  expr = "SHRT_MAX";
+  EXPECT (mpz_fits_slong_p, 1);
+  EXPECT (mpz_fits_sint_p, 1);
+  EXPECT (mpz_fits_sshort_p, 1);
+
+  mpz_set_si (z, (long) SHRT_MAX);
+  mpz_add_ui (z, z, 1L);
+  expr = "SHRT_MAX + 1";
+  EXPECT (mpz_fits_sshort_p, 0);
+
+
+  mpz_set_si (z, (long) INT_MAX);
+  expr = "INT_MAX";
+  EXPECT (mpz_fits_slong_p, 1);
+  EXPECT (mpz_fits_sint_p, 1);
+
+  mpz_set_si (z, (long) INT_MAX);
+  mpz_add_ui (z, z, 1L);
+  expr = "INT_MAX + 1";
+  EXPECT (mpz_fits_sint_p, 0);
+
+
+  mpz_set_si (z, LONG_MAX);
+  expr = "LONG_MAX";
+  EXPECT (mpz_fits_slong_p, 1);
+
+  mpz_set_si (z, LONG_MAX);
+  mpz_add_ui (z, z, 1L);
+  expr = "LONG_MAX + 1";
+  EXPECT (mpz_fits_slong_p, 0);
+
+
+  mpz_set_si (z, (long) SHRT_MIN);
+  expr = "SHRT_MIN";
+  EXPECT (mpz_fits_slong_p, 1);
+  EXPECT (mpz_fits_sint_p, 1);
+  EXPECT (mpz_fits_sshort_p, 1);
+
+  mpz_set_si (z, (long) SHRT_MIN);
+  mpz_sub_ui (z, z, 1L);
+  expr = "SHRT_MIN + 1";
+  EXPECT (mpz_fits_sshort_p, 0);
+
+
+  mpz_set_si (z, (long) INT_MIN);
+  expr = "INT_MIN";
+  EXPECT (mpz_fits_slong_p, 1);
+  EXPECT (mpz_fits_sint_p, 1);
+
+  mpz_set_si (z, (long) INT_MIN);
+  mpz_sub_ui (z, z, 1L);
+  expr = "INT_MIN + 1";
+  EXPECT (mpz_fits_sint_p, 0);
+
+
+  mpz_set_si (z, LONG_MIN);
+  expr = "LONG_MIN";
+  EXPECT (mpz_fits_slong_p, 1);
+
+  mpz_set_si (z, LONG_MIN);
+  mpz_sub_ui (z, z, 1L);
+  expr = "LONG_MIN + 1";
+  EXPECT (mpz_fits_slong_p, 0);
+
+
+  if (error)
+    abort ();
+
+  mpz_clear (z);
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpz/t-gcd.c b/third_party/gmp/tests/mpz/t-gcd.c
new file mode 100644
index 0000000..cd42ab7
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-gcd.c
@@ -0,0 +1,464 @@
+/* Test mpz_gcd, mpz_gcdext, and mpz_gcd_ui.
+
+Copyright 1991, 1993, 1994, 1996, 1997, 2000-2005, 2008, 2009, 2012 Free
+Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+void one_test (mpz_t, mpz_t, mpz_t, int);
+void debug_mp (mpz_t, int);
+
+static int gcdext_valid_p (const mpz_t, const mpz_t, const mpz_t, const mpz_t);
+
+/* Keep one_test's variables global, so that we don't need
+   to reinitialize them for each test.  */
+mpz_t gcd1, gcd2, s, temp1, temp2, temp3;
+
+#define MAX_SCHOENHAGE_THRESHOLD HGCD_REDUCE_THRESHOLD
+
+/* Define this to make all operands be large enough for Schoenhage gcd
+   to be used.  */
+#ifndef WHACK_SCHOENHAGE
+#define WHACK_SCHOENHAGE 0
+#endif
+
+#if WHACK_SCHOENHAGE
+#define MIN_OPERAND_BITSIZE (MAX_SCHOENHAGE_THRESHOLD * GMP_NUMB_BITS)
+#else
+#define MIN_OPERAND_BITSIZE 1
+#endif
+
+
+void
+check_data (void)
+{
+  static const struct {
+    const char *a;
+    const char *b;
+    const char *want;
+  } data[] = {
+    /* This tickled a bug in gmp 4.1.2 mpn/x86/k6/gcd_finda.asm. */
+    { "0x3FFC000007FFFFFFFFFF00000000003F83FFFFFFFFFFFFFFF80000000000000001",
+      "0x1FFE0007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC000000000000000000000001",
+      "5" }
+  };
+
+  mpz_t  a, b, got, want;
+  int    i;
+
+  mpz_inits (a, b, got, want, NULL);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_set_str_or_abort (a, data[i].a, 0);
+      mpz_set_str_or_abort (b, data[i].b, 0);
+      mpz_set_str_or_abort (want, data[i].want, 0);
+      mpz_gcd (got, a, b);
+      MPZ_CHECK_FORMAT (got);
+      if (mpz_cmp (got, want) != 0)
+	{
+	  printf    ("mpz_gcd wrong on data[%d]\n", i);
+	  printf    (" a  %s\n", data[i].a);
+	  printf    (" b  %s\n", data[i].b);
+	  mpz_trace (" a", a);
+	  mpz_trace (" b", b);
+	  mpz_trace (" want", want);
+	  mpz_trace (" got ", got);
+	  abort ();
+	}
+    }
+
+  mpz_clears (a, b, got, want, NULL);
+}
+
+void
+make_chain_operands (mpz_t ref, mpz_t a, mpz_t b, gmp_randstate_t rs, int nb1, int nb2, int chain_len)
+{
+  mpz_t bs, temp1, temp2;
+  int j;
+
+  mpz_inits (bs, temp1, temp2, NULL);
+
+  /* Generate a division chain backwards, allowing otherwise unlikely huge
+     quotients.  */
+
+  mpz_set_ui (a, 0);
+  mpz_urandomb (bs, rs, 32);
+  mpz_urandomb (bs, rs, mpz_get_ui (bs) % nb1 + 1);
+  mpz_rrandomb (b, rs, mpz_get_ui (bs));
+  mpz_add_ui (b, b, 1);
+  mpz_set (ref, b);
+
+  for (j = 0; j < chain_len; j++)
+    {
+      mpz_urandomb (bs, rs, 32);
+      mpz_urandomb (bs, rs, mpz_get_ui (bs) % nb2 + 1);
+      mpz_rrandomb (temp2, rs, mpz_get_ui (bs) + 1);
+      mpz_add_ui (temp2, temp2, 1);
+      mpz_mul (temp1, b, temp2);
+      mpz_add (a, a, temp1);
+
+      mpz_urandomb (bs, rs, 32);
+      mpz_urandomb (bs, rs, mpz_get_ui (bs) % nb2 + 1);
+      mpz_rrandomb (temp2, rs, mpz_get_ui (bs) + 1);
+      mpz_add_ui (temp2, temp2, 1);
+      mpz_mul (temp1, a, temp2);
+      mpz_add (b, b, temp1);
+    }
+
+  mpz_clears (bs, temp1, temp2, NULL);
+}
+
+/* Test operands from a table of seed data.  This variant creates the operands
+   using plain ol' mpz_rrandomb.  This is a hack for better coverage of the gcd
+   code, which depends on that the random number generators give the exact
+   numbers we expect.  */
+void
+check_kolmo1 (void)
+{
+  static const struct {
+    unsigned int seed;
+    int nb;
+    const char *want;
+  } data[] = {
+    { 59618, 38208, "5"},
+    { 76521, 49024, "3"},
+    { 85869, 54976, "1"},
+    { 99449, 63680, "1"},
+    {112453, 72000, "1"}
+  };
+
+  gmp_randstate_t rs;
+  mpz_t  bs, a, b, want;
+  int    i, unb, vnb, nb;
+
+  gmp_randinit_default (rs);
+
+  mpz_inits (bs, a, b, want, NULL);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      nb = data[i].nb;
+
+      gmp_randseed_ui (rs, data[i].seed);
+
+      mpz_urandomb (bs, rs, 32);
+      unb = mpz_get_ui (bs) % nb;
+      mpz_urandomb (bs, rs, 32);
+      vnb = mpz_get_ui (bs) % nb;
+
+      mpz_rrandomb (a, rs, unb);
+      mpz_rrandomb (b, rs, vnb);
+
+      mpz_set_str_or_abort (want, data[i].want, 0);
+
+      one_test (a, b, want, -1);
+    }
+
+  mpz_clears (bs, a, b, want, NULL);
+  gmp_randclear (rs);
+}
+
+/* Test operands from a table of seed data.  This variant creates the operands
+   using a division chain.  This is a hack for better coverage of the gcd
+   code, which depends on that the random number generators give the exact
+   numbers we expect.  */
+void
+check_kolmo2 (void)
+{
+  static const struct {
+    unsigned int seed;
+    int nb, chain_len;
+  } data[] = {
+    {  917, 15, 5 },
+    { 1032, 18, 6 },
+    { 1167, 18, 6 },
+    { 1174, 18, 6 },
+    { 1192, 18, 6 },
+  };
+
+  gmp_randstate_t rs;
+  mpz_t  bs, a, b, want;
+  int    i;
+
+  gmp_randinit_default (rs);
+
+  mpz_inits (bs, a, b, want, NULL);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      gmp_randseed_ui (rs, data[i].seed);
+      make_chain_operands (want, a, b, rs, data[i].nb, data[i].nb, data[i].chain_len);
+      one_test (a, b, want, -1);
+    }
+
+  mpz_clears (bs, a, b, want, NULL);
+  gmp_randclear (rs);
+}
+
+int
+main (int argc, char **argv)
+{
+  mpz_t op1, op2, ref;
+  int i, chain_len;
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long bsi, size_range;
+  long int reps = 200;
+
+  tests_start ();
+  TESTS_REPS (reps, argv, argc);
+
+  rands = RANDS;
+
+  mpz_inits (bs, op1, op2, ref, gcd1, gcd2, temp1, temp2, temp3, s, NULL);
+
+  check_data ();
+  check_kolmo1 ();
+  check_kolmo2 ();
+
+  /* Testcase to exercise the u0 == u1 case in mpn_gcdext_lehmer_n. */
+  mpz_set_ui (op2, GMP_NUMB_MAX); /* FIXME: Huge limb doesn't always fit */
+  mpz_mul_2exp (op1, op2, 100);
+  mpz_add (op1, op1, op2);
+  mpz_mul_ui (op2, op2, 2);
+  one_test (op1, op2, NULL, -1);
+
+  for (i = 0; i < reps; i++)
+    {
+      /* Generate plain operands with unknown gcd.  These types of operands
+	 have proven to trigger certain bugs in development versions of the
+	 gcd code.  The "hgcd->row[3].rsize > M" ASSERT is not triggered by
+	 the division chain code below, but that is most likely just a result
+	 of that other ASSERTs are triggered before it.  */
+
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 17 + 2;
+
+      mpz_urandomb (bs, rands, size_range);
+      mpz_rrandomb (op1, rands, mpz_get_ui (bs) + MIN_OPERAND_BITSIZE);
+      mpz_urandomb (bs, rands, size_range);
+      mpz_rrandomb (op2, rands, mpz_get_ui (bs) + MIN_OPERAND_BITSIZE);
+
+      mpz_urandomb (bs, rands, 8);
+      bsi = mpz_get_ui (bs);
+
+      if ((bsi & 0x3c) == 4)
+	mpz_mul (op1, op1, op2);	/* make op1 a multiple of op2 */
+      else if ((bsi & 0x3c) == 8)
+	mpz_mul (op2, op1, op2);	/* make op2 a multiple of op1 */
+
+      if ((bsi & 1) != 0)
+	mpz_neg (op1, op1);
+      if ((bsi & 2) != 0)
+	mpz_neg (op2, op2);
+
+      one_test (op1, op2, NULL, i);
+
+      /* Generate a division chain backwards, allowing otherwise unlikely huge
+	 quotients.  */
+
+      mpz_urandomb (bs, rands, 32);
+      chain_len = mpz_get_ui (bs) % LOG2C (GMP_NUMB_BITS * MAX_SCHOENHAGE_THRESHOLD);
+      mpz_urandomb (bs, rands, 32);
+      chain_len = mpz_get_ui (bs) % (1 << chain_len) / 32;
+
+      make_chain_operands (ref, op1, op2, rands, 16, 12, chain_len);
+
+      one_test (op1, op2, ref, i);
+    }
+
+  /* Check that we can use NULL as first argument of mpz_gcdext.  */
+  mpz_set_si (op1, -10);
+  mpz_set_si (op2, 0);
+  mpz_gcdext (NULL, temp1, temp2, op1, op2);
+  ASSERT_ALWAYS (mpz_cmp_si (temp1, -1) == 0);
+  ASSERT_ALWAYS (mpz_cmp_si (temp2, 0) == 0);
+  mpz_set_si (op2, 6);
+  mpz_gcdext (NULL, temp1, temp2, op1, op2);
+  ASSERT_ALWAYS (mpz_cmp_si (temp1, 1) == 0);
+  ASSERT_ALWAYS (mpz_cmp_si (temp2, 2) == 0);
+
+  mpz_clears (bs, op1, op2, ref, gcd1, gcd2, temp1, temp2, temp3, s, NULL);
+
+  tests_end ();
+  exit (0);
+}
+
+void
+debug_mp (mpz_t x, int base)
+{
+  mpz_out_str (stderr, base, x); fputc ('\n', stderr);
+}
+
+void
+one_test (mpz_t op1, mpz_t op2, mpz_t ref, int i)
+{
+  /*
+  printf ("%d %d %d\n", SIZ (op1), SIZ (op2), ref != NULL ? SIZ (ref) : 0);
+  fflush (stdout);
+  */
+
+  /*
+  fprintf (stderr, "op1=");  debug_mp (op1, -16);
+  fprintf (stderr, "op2=");  debug_mp (op2, -16);
+  */
+
+  mpz_gcdext (gcd1, s, NULL, op1, op2);
+  MPZ_CHECK_FORMAT (gcd1);
+  MPZ_CHECK_FORMAT (s);
+
+  if (ref && mpz_cmp (ref, gcd1) != 0)
+    {
+      fprintf (stderr, "ERROR in test %d\n", i);
+      fprintf (stderr, "mpz_gcdext returned incorrect result\n");
+      fprintf (stderr, "op1=");                 debug_mp (op1, -16);
+      fprintf (stderr, "op2=");                 debug_mp (op2, -16);
+      fprintf (stderr, "expected result:\n");   debug_mp (ref, -16);
+      fprintf (stderr, "mpz_gcdext returns:\n");debug_mp (gcd1, -16);
+      abort ();
+    }
+
+  if (!gcdext_valid_p(op1, op2, gcd1, s))
+    {
+      fprintf (stderr, "ERROR in test %d\n", i);
+      fprintf (stderr, "mpz_gcdext returned invalid result\n");
+      fprintf (stderr, "op1=");                 debug_mp (op1, -16);
+      fprintf (stderr, "op2=");                 debug_mp (op2, -16);
+      fprintf (stderr, "mpz_gcdext returns:\n");debug_mp (gcd1, -16);
+      fprintf (stderr, "s=");                   debug_mp (s, -16);
+      abort ();
+    }
+
+  mpz_gcd (gcd2, op1, op2);
+  MPZ_CHECK_FORMAT (gcd2);
+
+  if (mpz_cmp (gcd2, gcd1) != 0)
+    {
+      fprintf (stderr, "ERROR in test %d\n", i);
+      fprintf (stderr, "mpz_gcd returned incorrect result\n");
+      fprintf (stderr, "op1=");                 debug_mp (op1, -16);
+      fprintf (stderr, "op2=");                 debug_mp (op2, -16);
+      fprintf (stderr, "expected result:\n");   debug_mp (gcd1, -16);
+      fprintf (stderr, "mpz_gcd returns:\n");   debug_mp (gcd2, -16);
+      abort ();
+    }
+
+  /* This should probably move to t-gcd_ui.c */
+  if (mpz_fits_ulong_p (op1) || mpz_fits_ulong_p (op2))
+    {
+      if (mpz_fits_ulong_p (op1))
+	mpz_gcd_ui (gcd2, op2, mpz_get_ui (op1));
+      else
+	mpz_gcd_ui (gcd2, op1, mpz_get_ui (op2));
+      if (mpz_cmp (gcd2, gcd1))
+	{
+	  fprintf (stderr, "ERROR in test %d\n", i);
+	  fprintf (stderr, "mpz_gcd_ui returned incorrect result\n");
+	  fprintf (stderr, "op1=");                 debug_mp (op1, -16);
+	  fprintf (stderr, "op2=");                 debug_mp (op2, -16);
+	  fprintf (stderr, "expected result:\n");   debug_mp (gcd1, -16);
+	  fprintf (stderr, "mpz_gcd_ui returns:\n");   debug_mp (gcd2, -16);
+	  abort ();
+	}
+    }
+
+  mpz_gcdext (gcd2, temp1, temp2, op1, op2);
+  MPZ_CHECK_FORMAT (gcd2);
+  MPZ_CHECK_FORMAT (temp1);
+  MPZ_CHECK_FORMAT (temp2);
+
+  mpz_mul (temp1, temp1, op1);
+  mpz_mul (temp2, temp2, op2);
+  mpz_add (temp1, temp1, temp2);
+
+  if (mpz_cmp (gcd1, gcd2) != 0
+      || mpz_cmp (gcd2, temp1) != 0)
+    {
+      fprintf (stderr, "ERROR in test %d\n", i);
+      fprintf (stderr, "mpz_gcdext returned incorrect result\n");
+      fprintf (stderr, "op1=");                 debug_mp (op1, -16);
+      fprintf (stderr, "op2=");                 debug_mp (op2, -16);
+      fprintf (stderr, "expected result:\n");   debug_mp (gcd1, -16);
+      fprintf (stderr, "mpz_gcdext returns:\n");debug_mp (gcd2, -16);
+      abort ();
+    }
+}
+
+/* Called when g is supposed to be gcd(a,b), and g = s a + t b, for some t.
+   Uses temp1, temp2 and temp3. */
+static int
+gcdext_valid_p (const mpz_t a, const mpz_t b, const mpz_t g, const mpz_t s)
+{
+  /* It's not clear that gcd(0,0) is well defined, but we allow it and require that
+     gcd(0,0) = 0. */
+  if (mpz_sgn (g) < 0)
+    return 0;
+
+  if (mpz_sgn (a) == 0)
+    {
+      /* Must have g == abs (b). Any value for s is in some sense "correct",
+	 but it makes sense to require that s == 0. */
+      return mpz_cmpabs (g, b) == 0 && mpz_sgn (s) == 0;
+    }
+  else if (mpz_sgn (b) == 0)
+    {
+      /* Must have g == abs (a), s == sign (a) */
+      return mpz_cmpabs (g, a) == 0 && mpz_cmp_si (s, mpz_sgn (a)) == 0;
+    }
+
+  if (mpz_sgn (g) <= 0)
+    return 0;
+
+  mpz_tdiv_qr (temp1, temp3, a, g);
+  if (mpz_sgn (temp3) != 0)
+    return 0;
+
+  mpz_tdiv_qr (temp2, temp3, b, g);
+  if (mpz_sgn (temp3) != 0)
+    return 0;
+
+  /* Require that 2 |s| < |b/g|, or |s| == 1. */
+  if (mpz_cmpabs_ui (s, 1) > 0)
+    {
+      mpz_mul_2exp (temp3, s, 1);
+      if (mpz_cmpabs (temp3, temp2) >= 0)
+	return 0;
+    }
+
+  /* Compute the other cofactor. */
+  mpz_mul(temp2, s, a);
+  mpz_sub(temp2, g, temp2);
+  mpz_tdiv_qr(temp2, temp3, temp2, b);
+
+  if (mpz_sgn (temp3) != 0)
+    return 0;
+
+  /* Require that 2 |t| < |a/g| or |t| == 1*/
+  if (mpz_cmpabs_ui (temp2, 1) > 0)
+    {
+      mpz_mul_2exp (temp2, temp2, 1);
+      if (mpz_cmpabs (temp2, temp1) >= 0)
+	return 0;
+    }
+  return 1;
+}
diff --git a/third_party/gmp/tests/mpz/t-gcd_ui.c b/third_party/gmp/tests/mpz/t-gcd_ui.c
new file mode 100644
index 0000000..3f56a97
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-gcd_ui.c
@@ -0,0 +1,156 @@
+/* Test mpz_gcd_ui.
+
+Copyright 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+/* Check mpz_gcd_ui doesn't try to return a value out of range.
+   This was wrong in gmp 4.1.2 with a long long limb.  */
+static void
+check_ui_range (void)
+{
+  unsigned long  got;
+  mpz_t  x;
+  int  i;
+
+  mpz_init_set_ui (x, ULONG_MAX);
+
+  for (i = 0; i < 20; i++)
+    {
+      mpz_mul_2exp (x, x, 1L);
+      got = mpz_gcd_ui (NULL, x, 0L);
+      if (got != 0)
+        {
+          printf ("mpz_gcd_ui (ULONG_MAX*2^%d, 0)\n", i);
+          printf ("   return %#lx\n", got);
+          printf ("   should be 0\n");
+          abort ();
+        }
+    }
+
+  mpz_clear (x);
+}
+
+static void
+check_ui_factors (void)
+{
+#define NUM_FACTORS 9
+  static const char* factors[NUM_FACTORS] = {
+    "641", "274177", "3", "5", "17", "257", "65537",
+    "59649589127497217", "1238926361552897" };
+  unsigned long  got;
+  mpz_t  x, b, d, f, g;
+  int  i, j;
+  gmp_randstate_ptr rands;
+
+  if (GMP_NUMB_BITS < 5 || GMP_NUMB_BITS == 8
+      || GMP_NUMB_BITS == 16 || GMP_NUMB_BITS > 511)
+    {
+      printf ("No usable factors for 2^%i+1.\n", GMP_NUMB_BITS);
+      return;
+    }
+
+  mpz_init (x);
+  mpz_init (d);
+  mpz_init (f);
+  mpz_init (g);
+
+  mpz_setbit (x, GMP_NUMB_BITS);
+  mpz_add_ui (x, x, 1);
+
+  for (i = 0; i < NUM_FACTORS; ++i)
+    {
+      mpz_set_str (f, factors[i], 10);
+      if (mpz_divisible_p (x, f))
+	{
+	  mpz_mul_2exp (f, f, 1);
+	  /* d is an odd multiple of the factor f, exactly filling a limb. */
+	  mpz_sub (d, x, f);
+	  /* f = 2^GMP_NUMB_BITS mod d. */
+	  mpz_sub_ui (f, f, 1);
+	  break;
+	}
+    }
+
+  mpz_gcd (g, f, d);
+  if (mpz_even_p (d) || mpz_cmp (d, f) <= 0 || mpz_cmp_ui (g, 1) != 0)
+    {
+      printf ("No usable factor found.\n");
+      abort ();
+    }
+
+  rands = RANDS;
+  mpz_mul_ui (x, d, gmp_urandomm_ui (rands, 30000) + 1);
+
+  mpz_init (b);
+  mpz_setbit (b, GMP_NUMB_BITS - 1);
+  for (j = 0; j < 4; ++j)
+    {
+      mpz_add (x, x, b);
+
+      for (i = 1; i >= -1; --i)
+	{
+	  if (mpz_fits_ulong_p (d)
+	      && ((got = mpz_gcd_ui (NULL, x, mpz_get_ui (d)))
+		  != (i != 0 ? 1 : mpz_get_ui (d))))
+	    {
+	      printf ("mpz_gcd_ui (f, kV+%i*2^%i, V): error (j = %i)\n", i, GMP_NUMB_BITS - 1, j);
+	      printf ("   return %#lx\n", got);
+	      printf ("   should be %#lx\n", (i != 0 ? 1 : mpz_get_ui (d)));
+	      abort ();
+	    }
+
+	  mpz_gcd (g, x, d);
+	  if ((mpz_cmp_ui (g, 1) == 0) != (i != 0))
+	    {
+	      printf ("mpz_gcd (f, kV+%i*2^%i, V): error (j = %i)\n", i, GMP_NUMB_BITS - 1, j);
+	      printf ("   should%s be one.\n",(i != 0 ? "" : " not"));
+	      abort ();
+	    }
+
+	  mpz_sub (x, x, b);
+	}
+      /* Back to the original x. */
+      mpz_addmul_ui (x, b, 2);
+      mpz_mul (b, b, f);
+      mpz_mod (b, b, d);
+    }
+
+  mpz_clear (g);
+  mpz_clear (x);
+  mpz_clear (f);
+  mpz_clear (d);
+  mpz_clear (b);
+}
+
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_ui_range ();
+  check_ui_factors ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpz/t-get_d.c b/third_party/gmp/tests/mpz/t-get_d.c
new file mode 100644
index 0000000..46e5eaf
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-get_d.c
@@ -0,0 +1,73 @@
+/* Test mpz_get_d.
+
+Copyright 2002, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_onebit (void)
+{
+  int     i;
+  mpz_t   z;
+  double  got, want;
+  /* FIXME: It'd be better to base this on the float format. */
+#if defined (__vax) || defined (__vax__)
+  int     limit = 127 - 1;  /* vax fp numbers have limited range */
+#else
+  int     limit = 512;
+#endif
+
+  mpz_init (z);
+
+  mpz_set_ui (z, 1L);
+  want = 1.0;
+
+  for (i = 0; i < limit; i++)
+    {
+      got = mpz_get_d (z);
+
+      if (got != want)
+        {
+          printf    ("mpz_get_d wrong on 2**%d\n", i);
+          mpz_trace ("   z    ", z);
+          printf    ("   want  %.20g\n", want);
+          printf    ("   got   %.20g\n", got);
+          abort();
+        }
+
+      mpz_mul_2exp (z, z, 1L);
+      want *= 2.0;
+    }
+  mpz_clear (z);
+}
+
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_onebit ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpz/t-get_d_2exp.c b/third_party/gmp/tests/mpz/t-get_d_2exp.c
new file mode 100644
index 0000000..04cf1a4
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-get_d_2exp.c
@@ -0,0 +1,222 @@
+/* Test mpz_get_d_2exp.
+
+Copyright 2002, 2003, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+static void
+check_zero (void)
+{
+  mpz_t   z;
+  double  got, want;
+  long    got_exp, want_exp;
+
+  mpz_init_set_ui (z, 0);
+
+  want = 0.0;
+  want_exp = 0;
+  got = mpz_get_d_2exp (&got_exp, z);
+  if (got != want || got_exp != want_exp)
+    {
+      printf    ("mpz_get_d_2exp wrong on zero\n");
+      mpz_trace ("   z    ", z);
+      d_trace   ("   want ", want);
+      d_trace   ("   got  ", got);
+      printf    ("   want exp %ld\n", want_exp);
+      printf    ("   got exp  %ld\n", got_exp);
+      abort();
+    }
+
+  mpz_clear (z);
+}
+
+static void
+check_onebit (void)
+{
+  static const unsigned long data[] = {
+    1, 32, 52, 53, 54, 63, 64, 65, 128, 256, 511, 512, 513
+  };
+  mpz_t   z;
+  double  got, want;
+  long    got_exp, want_exp;
+  int     i;
+
+  mpz_init (z);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_set_ui (z, 1L);
+      mpz_mul_2exp (z, z, data[i]);
+      want = 0.5;
+      want_exp = data[i] + 1;
+      got = mpz_get_d_2exp (&got_exp, z);
+      if (got != want || got_exp != want_exp)
+        {
+          printf    ("mpz_get_d_2exp wrong on 2**%ld\n", data[i]);
+          mpz_trace ("   z    ", z);
+          d_trace   ("   want ", want);
+          d_trace   ("   got  ", got);
+          printf    ("   want exp %ld\n", want_exp);
+          printf    ("   got exp  %ld\n", got_exp);
+          abort();
+        }
+
+      mpz_set_si (z, -1L);
+      mpz_mul_2exp (z, z, data[i]);
+      want = -0.5;
+      want_exp = data[i] + 1;
+      got = mpz_get_d_2exp (&got_exp, z);
+      if (got != want || got_exp != want_exp)
+        {
+          printf    ("mpz_get_d_2exp wrong on -2**%ld\n", data[i]);
+          mpz_trace ("   z    ", z);
+          d_trace   ("   want ", want);
+          d_trace   ("   got  ", got);
+          printf    ("   want exp %ld\n", want_exp);
+          printf    ("   got exp  %ld\n", got_exp);
+          abort();
+        }
+    }
+  mpz_clear (z);
+}
+
+/* Check that hardware rounding doesn't make mpz_get_d_2exp return a value
+   outside its defined range. */
+static void
+check_round (void)
+{
+  static const unsigned long data[] = { 1, 32, 53, 54, 64, 128, 256, 512 };
+  mpz_t   z;
+  double  got;
+  long    got_exp;
+  int     i, rnd_mode, old_rnd_mode;
+
+  mpz_init (z);
+  old_rnd_mode = tests_hardware_getround ();
+
+  for (rnd_mode = 0; rnd_mode < 4; rnd_mode++)
+    {
+      tests_hardware_setround (rnd_mode);
+
+      for (i = 0; i < numberof (data); i++)
+        {
+          mpz_set_ui (z, 1L);
+          mpz_mul_2exp (z, z, data[i]);
+          mpz_sub_ui (z, z, 1L);
+
+          got = mpz_get_d_2exp (&got_exp, z);
+          if (got < 0.5 || got >= 1.0)
+            {
+              printf    ("mpz_get_d_2exp wrong on 2**%lu-1\n", data[i]);
+              printf    ("result out of range, expect 0.5 <= got < 1.0\n");
+              printf    ("   rnd_mode = %d\n", rnd_mode);
+              printf    ("   data[i]  = %lu\n", data[i]);
+              mpz_trace ("   z    ", z);
+              d_trace   ("   got  ", got);
+              printf    ("   got exp  %ld\n", got_exp);
+              abort();
+            }
+
+          mpz_neg (z, z);
+          got = mpz_get_d_2exp (&got_exp, z);
+          if (got <= -1.0 || got > -0.5)
+            {
+              printf    ("mpz_get_d_2exp wrong on -2**%lu-1\n", data[i]);
+              printf    ("result out of range, expect -1.0 < got <= -0.5\n");
+              printf    ("   rnd_mode = %d\n", rnd_mode);
+              printf    ("   data[i]  = %lu\n", data[i]);
+              mpz_trace ("   z    ", z);
+              d_trace   ("   got  ", got);
+              printf    ("   got exp  %ld\n", got_exp);
+              abort();
+            }
+        }
+    }
+
+  mpz_clear (z);
+  tests_hardware_setround (old_rnd_mode);
+}
+
+static void
+check_rand (void)
+{
+  gmp_randstate_ptr rands = RANDS;
+  int     i;
+  mpz_t   z;
+  double  got;
+  long    got_exp;
+  unsigned long  bits;
+
+  mpz_init (z);
+
+  for (i = 0; i < 200; i++)
+    {
+      bits = gmp_urandomm_ui (rands, 512L);
+      mpz_urandomb (z, rands, bits);
+
+      got = mpz_get_d_2exp (&got_exp, z);
+      if (mpz_sgn (z) == 0)
+        continue;
+      bits = mpz_sizeinbase (z, 2);
+
+      if (got < 0.5 || got >= 1.0)
+        {
+          printf    ("mpz_get_d_2exp out of range, expect 0.5 <= got < 1.0\n");
+          mpz_trace ("   z    ", z);
+          d_trace   ("   got  ", got);
+          printf    ("   got exp  %ld\n", got_exp);
+          abort();
+        }
+
+      /* FIXME: If mpz_get_d_2exp rounds upwards we might have got_exp ==
+         bits+1, so leave this test disabled until we decide if that's what
+         should happen, or not.  */
+#if 0
+      if (got_exp != bits)
+        {
+          printf    ("mpz_get_d_2exp wrong exponent\n", i);
+          mpz_trace ("   z    ", z);
+          d_trace   ("   bits ", bits);
+          d_trace   ("   got  ", got);
+          printf    ("   got exp  %ld\n", got_exp);
+          abort();
+        }
+#endif
+    }
+  mpz_clear (z);
+}
+
+
+int
+main (void)
+{
+  tests_start ();
+  mp_trace_base = -16;
+
+  check_zero ();
+  check_onebit ();
+  check_round ();
+  check_rand ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpz/t-get_si.c b/third_party/gmp/tests/mpz/t-get_si.c
new file mode 100644
index 0000000..51f104a
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-get_si.c
@@ -0,0 +1,121 @@
+/* Exercise mpz_get_si.
+
+Copyright 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_data (void)
+{
+  static const struct {
+    const char  *n;
+    long        want;
+  } data[] = {
+    { "0",      0L },
+    { "1",      1L },
+    { "-1",     -1L },
+    { "2",      2L },
+    { "-2",     -2L },
+    { "12345",  12345L },
+    { "-12345", -12345L },
+  };
+
+  int    i;
+  mpz_t  n;
+  long   got;
+
+  mpz_init (n);
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_set_str_or_abort (n, data[i].n, 0);
+
+      got = mpz_get_si (n);
+      if (got != data[i].want)
+	{
+	  printf ("mpz_get_si wrong at data[%d]\n", i);
+	  printf ("   n     \"%s\" (", data[i].n);
+	  mpz_out_str (stdout, 10, n); printf (", hex ");
+	  mpz_out_str (stdout, 16, n); printf (")\n");
+	  printf ("   got   %ld (0x%lX)\n", got, got);
+	  printf ("   want  %ld (0x%lX)\n", data[i].want, data[i].want);
+	  abort();
+	}
+    }
+  mpz_clear (n);
+}
+
+
+void
+check_max (void)
+{
+  mpz_t  n;
+  long   want;
+  long   got;
+
+  mpz_init (n);
+
+#define CHECK_MAX(name)                                 \
+  if (got != want)                                      \
+    {                                                   \
+      printf ("mpz_get_si wrong on %s\n", name);        \
+      printf ("   n    ");                              \
+      mpz_out_str (stdout, 10, n); printf (", hex ");   \
+      mpz_out_str (stdout, 16, n); printf ("\n");       \
+      printf ("   got  %ld, hex %lX\n", got, got);      \
+      printf ("   want %ld, hex %lX\n", want, want);    \
+      abort();                                          \
+    }
+
+  want = LONG_MAX;
+  mpz_set_si (n, want);
+  got = mpz_get_si (n);
+  CHECK_MAX ("LONG_MAX");
+
+  want = LONG_MIN;
+  mpz_set_si (n, want);
+  got = mpz_get_si (n);
+  CHECK_MAX ("LONG_MIN");
+
+  /* The following checks that -0x100000000 gives -0x80000000.  This doesn't
+     actually fit in a long and the result from mpz_get_si() is undefined,
+     but -0x80000000 is what comes out currently, and it should be that
+     value irrespective of the mp_limb_t size (long or long long).  */
+
+  want = LONG_MIN;
+  mpz_mul_2exp (n, n, 1);
+  CHECK_MAX ("-0x100...00");
+
+  mpz_clear (n);
+}
+
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_data ();
+  check_max ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpz/t-hamdist.c b/third_party/gmp/tests/mpz/t-hamdist.c
new file mode 100644
index 0000000..544a03f
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-hamdist.c
@@ -0,0 +1,123 @@
+/* Test mpz_hamdist.
+
+Copyright 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_twobits (void)
+{
+  unsigned long  i, j, got, want;
+  mpz_t  x, y;
+
+  mpz_init (x);
+  mpz_init (y);
+  for (i = 0; i < 5 * GMP_NUMB_BITS; i++)
+    {
+      for (j = 0; j < 5 * GMP_NUMB_BITS; j++)
+        {
+          mpz_set_ui (x, 0L);
+          mpz_setbit (x, i);
+          mpz_set_ui (y, 0L);
+          mpz_setbit (y, j);
+
+          want = 2 * (i != j);
+          got = mpz_hamdist (x, y);
+          if (got != want)
+            {
+              printf    ("mpz_hamdist wrong on 2 bits pos/pos\n");
+            wrong:
+              printf    ("  i    %lu\n", i);
+              printf    ("  j    %lu\n", j);
+              printf    ("  got  %lu\n", got);
+              printf    ("  want %lu\n", want);
+              mpz_trace ("  x   ", x);
+              mpz_trace ("  y   ", y);
+              abort();
+            }
+
+          mpz_neg (x, x);
+          mpz_neg (y, y);
+          want = ABS ((long) (i-j));
+          got = mpz_hamdist (x, y);
+          if (got != want)
+            {
+              printf    ("mpz_hamdist wrong on 2 bits neg/neg\n");
+              goto wrong;
+            }
+        }
+
+    }
+  mpz_clear (x);
+  mpz_clear (y);
+}
+
+
+void
+check_rand (void)
+{
+  gmp_randstate_ptr  rands = RANDS;
+  unsigned long  got, want;
+  int    i;
+  mpz_t  x, y;
+
+  mpz_init (x);
+  mpz_init (y);
+
+  for (i = 0; i < 2000; i++)
+    {
+      mpz_erandomb (x, rands, 6 * GMP_NUMB_BITS);
+      mpz_negrandom (x, rands);
+      mpz_mul_2exp (x, x, urandom() % (4 * GMP_NUMB_BITS));
+
+      mpz_erandomb (y, rands, 6 * GMP_NUMB_BITS);
+      mpz_negrandom (y, rands);
+      mpz_mul_2exp (y, y, urandom() % (4 * GMP_NUMB_BITS));
+
+      want = refmpz_hamdist (x, y);
+      got = mpz_hamdist (x, y);
+      if (got != want)
+        {
+          printf    ("mpz_hamdist wrong on random\n");
+          printf    ("  got  %lu\n", got);
+          printf    ("  want %lu\n", want);
+          mpz_trace ("  x   ", x);
+          mpz_trace ("  y   ", y);
+          abort();
+        }
+    }
+  mpz_clear (x);
+  mpz_clear (y);
+}
+
+int
+main (void)
+{
+  tests_start ();
+  mp_trace_base = -16;
+
+  check_twobits ();
+  check_rand ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpz/t-import.c b/third_party/gmp/tests/mpz/t-import.c
new file mode 100644
index 0000000..a295317
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-import.c
@@ -0,0 +1,175 @@
+/* Test mpz_import.
+
+Copyright 2002, 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_data (void)
+{
+  static const struct {
+    const char  *want;
+    size_t      count;
+    int         order;
+    size_t      size;
+    int         endian;
+    int         nail;
+    char        src[64];
+
+  } data[] = {
+
+    { "0", 0,1, 1,1, 0 },
+    { "0", 1,1, 0,1, 0 },
+
+    { "0x12345678", 4,1,  1,1, 0, { '\22', '\64', '\126', '\170' } },
+    { "0x12345678", 1,1,  4,1, 0, { '\22', '\64', '\126', '\170' } },
+    { "0x12345678", 1,-1, 4,1, 0, { '\22', '\64', '\126', '\170' } },
+
+    { "0x12345678", 4,-1, 1,-1, 0, { '\170', '\126', '\064', '\22' } },
+    { "0x12345678", 1,1,  4,-1, 0, { '\170', '\126', '\064', '\22' } },
+    { "0x12345678", 1,-1, 4,-1, 0, { '\170', '\126', '\064', '\22' } },
+
+    { "0",    5,1,  1,1, 7, { '\376', '\376', '\376', '\376', '\376' } },
+    { "0",    5,-1, 1,1, 7, { '\376', '\376', '\376', '\376', '\376' } },
+    { "0x15", 5,1,  1,1, 7, { '\377', '\376', '\377', '\376', '\377' } },
+
+    { "0",    3,1,  2,1,   1, { '\200','\000', '\200','\000', '\200','\000' }},
+    { "0",    3,1,  2,-1,  1, { '\000','\200', '\000','\200', '\000','\200' }},
+    { "0",    3,1,  2,1,  15, { '\377','\376', '\377','\376', '\377','\376' }},
+
+    { "0x2A", 3,1,  2,1, 14, { '\377','\376', '\377','\376', '\377','\376' } },
+    { "0x06", 3,1,  2,1, 14, { '\377','\374', '\377','\375', '\377','\376' } },
+    { "0x24", 3,-1, 2,1, 14, { '\377','\374', '\377','\375', '\377','\376' } },
+
+    { "0x123456789ABC", 3,1,  2,1,  0, {
+        '\022','\064', '\126','\170', '\232','\274' } },
+    { "0x123456789ABC", 3,-1, 2,1,  0, {
+        '\232','\274', '\126','\170', '\022','\064' } },
+    { "0x123456789ABC", 3,1,  2,-1, 0, {
+        '\064','\022', '\170','\126', '\274','\232' } },
+    { "0x123456789ABC", 3,-1, 2,-1, 0, {
+        '\274','\232', '\170','\126', '\064','\022' } },
+
+    { "0x112233445566778899AABBCC", 3,1,  4,1,  0,
+      { '\021','\042','\063','\104',
+        '\125','\146','\167','\210',
+        '\231','\252','\273','\314' } },
+    { "0x112233445566778899AABBCC", 3,-1, 4,1,  0,
+      { '\231','\252','\273','\314',
+        '\125','\146','\167','\210',
+        '\021','\042','\063','\104' } },
+    { "0x112233445566778899AABBCC", 3,1,  4,-1, 0,
+      { '\104','\063','\042','\021',
+        '\210','\167','\146','\125',
+        '\314','\273','\252','\231' } },
+    { "0x112233445566778899AABBCC", 3,-1, 4,-1, 0,
+      { '\314','\273','\252','\231',
+        '\210','\167','\146','\125',
+        '\104','\063','\042','\021' } },
+
+    { "0x100120023003400450056006700780089009A00AB00BC00C", 3,1,  8,1,  0,
+      { '\020','\001','\040','\002','\060','\003','\100','\004',
+        '\120','\005','\140','\006','\160','\007','\200','\010',
+        '\220','\011','\240','\012','\260','\013','\300','\014' } },
+    { "0x100120023003400450056006700780089009A00AB00BC00C", 3,-1, 8,1,  0,
+      { '\220','\011','\240','\012','\260','\013','\300','\014',
+        '\120','\005','\140','\006','\160','\007','\200','\010',
+        '\020','\001','\040','\002','\060','\003','\100','\004' } },
+    { "0x100120023003400450056006700780089009A00AB00BC00C", 3,1,  8,-1, 0,
+      { '\004','\100','\003','\060','\002','\040','\001','\020',
+        '\010','\200','\007','\160','\006','\140','\005','\120',
+        '\014','\300','\013','\260','\012','\240','\011','\220' } },
+    { "0x100120023003400450056006700780089009A00AB00BC00C", 3,-1, 8,-1, 0,
+      { '\014','\300','\013','\260','\012','\240','\011','\220',
+        '\010','\200','\007','\160','\006','\140','\005','\120',
+        '\004','\100','\003','\060','\002','\040','\001','\020' } },
+
+    { "0x155555555555555555555555", 3,1,  4,1,  1,
+      { '\325','\125','\125','\125',
+        '\252','\252','\252','\252',
+        '\325','\125','\125','\125' } },
+    { "0x155555555555555555555555", 3,-1,  4,1,  1,
+      { '\325','\125','\125','\125',
+        '\252','\252','\252','\252',
+        '\325','\125','\125','\125' } },
+    { "0x155555555555555555555555", 3,1,  4,-1,  1,
+      { '\125','\125','\125','\325',
+        '\252','\252','\252','\252',
+        '\125','\125','\125','\325' } },
+    { "0x155555555555555555555555", 3,-1,  4,-1,  1,
+      { '\125','\125','\125','\325',
+        '\252','\252','\252','\252',
+        '\125','\125','\125','\325' } },
+  };
+
+  char    buf[sizeof(data[0].src) + sizeof (mp_limb_t)];
+  char    *src;
+  size_t  align;
+  int     i;
+  mpz_t   got, want;
+
+  mpz_init (got);
+  mpz_init (want);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      for (align = 0; align < sizeof (mp_limb_t); align++)
+        {
+          mpz_set_str_or_abort (want, data[i].want, 0);
+          src = buf + align;
+          memcpy (src, data[i].src, data[i].count * data[i].size);
+
+          mpz_set_ui (got, 0L);
+          mpz_import (got, data[i].count, data[i].order,
+                      data[i].size, data[i].endian, data[i].nail, src);
+
+          MPZ_CHECK_FORMAT (got);
+          if (mpz_cmp (got, want) != 0)
+            {
+              printf ("wrong at data[%d]\n", i);
+              printf ("    count=%lu order=%d  size=%lu endian=%d nail=%u  align=%lu\n",
+                      (unsigned long) data[i].count, data[i].order,
+                      (unsigned long) data[i].size, data[i].endian, data[i].nail,
+                      (unsigned long) align);
+              mpz_trace ("    got ", got);
+              mpz_trace ("    want", want);
+              abort ();
+            }
+        }
+    }
+  mpz_clear (got);
+  mpz_clear (want);
+}
+
+
+int
+main (void)
+{
+  tests_start ();
+
+  mp_trace_base = -16;
+  check_data ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpz/t-inp_str.c b/third_party/gmp/tests/mpz/t-inp_str.c
new file mode 100644
index 0000000..e686de5
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-inp_str.c
@@ -0,0 +1,198 @@
+/* Test mpz_inp_str.
+
+Copyright 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>		/* for unlink */
+#endif
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+#define FILENAME  "t-inp_str.tmp"
+
+
+void
+check_data (void)
+{
+  static const struct {
+    const char  *inp;
+    int         base;
+    const char  *want;
+    int         want_nread;
+
+  } data[] = {
+
+    { "0",   10, "0", 1 },
+
+    { "abc", 10, "0", 0 },
+    { "0xf", 10, "0", 1 },
+    { "ghi", 16, "0", 0 },
+    { "100", 90, "0", 0 },
+
+    {  "ff", 16,  "255", 2 },
+    { "-ff", 16, "-255", 3 },
+    {  "FF", 16,  "255", 2 },
+    { "-FF", 16, "-255", 3 },
+
+    {  "z", 36, "35", 1 },
+    {  "Z", 36, "35", 1 },
+    { "1B", 59, "70", 2 },
+    {  "a", 60, "36", 1 },
+    {  "A", 61, "10", 1 },
+
+    {  "0x0",    0,   "0", 3 },
+    {  "0X10",   0,  "16", 4 },
+    { "-0X0",    0,   "0", 4 },
+    { "-0x10",   0, "-16", 5 },
+
+    {  "0b0",    0,  "0", 3 },
+    {  "0B10",   0,  "2", 4 },
+    { "-0B0",    0,  "0", 4 },
+    { "-0b10",   0, "-2", 5 },
+
+    {  "00",   0,  "0", 2 },
+    {  "010",  0,  "8", 3 },
+    { "-00",   0,  "0", 3 },
+    { "-010",  0, "-8", 4 },
+
+    {  "0x",     0,   "0", 2 },
+    {  "0",      0,   "0", 1 },
+    { " 030",   10,  "30", 4 },
+  };
+
+  mpz_t  got, want;
+  long   ftell_nread;
+  int    i, pre, post, j, got_nread, want_nread;
+  FILE   *fp;
+
+  mpz_init (got);
+  mpz_init (want);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      for (pre = 0; pre <= 3; pre++)
+	{
+	  for (post = 0; post <= 2; post++)
+	    {
+	      mpz_set_str_or_abort (want, data[i].want, 0);
+	      MPZ_CHECK_FORMAT (want);
+
+	      /* create the file new each time to ensure its length is what
+		 we want */
+	      fp = fopen (FILENAME, "w+");
+	      ASSERT_ALWAYS (fp != NULL);
+	      for (j = 0; j < pre; j++)
+		putc (' ', fp);
+	      fputs (data[i].inp, fp);
+	      for (j = 0; j < post; j++)
+		putc (' ', fp);
+	      fflush (fp);
+	      ASSERT_ALWAYS (! ferror(fp));
+
+	      rewind (fp);
+	      got_nread = mpz_inp_str (got, fp, data[i].base);
+
+	      if (got_nread != 0)
+		{
+		  ftell_nread = ftell (fp);
+		  if (got_nread != ftell_nread)
+		    {
+		      printf ("mpz_inp_str nread wrong\n");
+		      printf ("  inp          \"%s\"\n", data[i].inp);
+		      printf ("  base         %d\n", data[i].base);
+		      printf ("  pre          %d\n", pre);
+		      printf ("  post         %d\n", post);
+		      printf ("  got_nread    %d\n", got_nread);
+		      printf ("  ftell_nread  %ld\n", ftell_nread);
+		      abort ();
+		    }
+		}
+
+	      /* if data[i].inp is a whole string to read and there's no post
+		 whitespace then expect to have EOF */
+	      if (post == 0 && data[i].want_nread == strlen(data[i].inp))
+		{
+		  int  c = getc(fp);
+		  if (c != EOF)
+		    {
+		      printf ("mpz_inp_str didn't read to EOF\n");
+		      printf ("  inp   \"%s\"\n", data[i].inp);
+		      printf ("  base  %d\n", data[i].base);
+		      printf ("  pre   %d\n", pre);
+		      printf ("  post  %d\n", post);
+		      printf ("  c     '%c' %#x\n", c, c);
+		      abort ();
+		    }
+		}
+
+	      /* only expect "pre" included in the count when non-zero */
+	      want_nread = data[i].want_nread;
+	      if (want_nread != 0)
+		want_nread += pre;
+
+	      if (got_nread != want_nread)
+		{
+		  printf ("mpz_inp_str nread wrong\n");
+		  printf ("  inp         \"%s\"\n", data[i].inp);
+		  printf ("  base        %d\n", data[i].base);
+		  printf ("  pre         %d\n", pre);
+		  printf ("  post        %d\n", post);
+		  printf ("  got_nread   %d\n", got_nread);
+		  printf ("  want_nread  %d\n", want_nread);
+		  abort ();
+		}
+
+	      MPZ_CHECK_FORMAT (got);
+
+	      if (mpz_cmp (got, want) != 0)
+		{
+		  printf ("mpz_inp_str wrong result\n");
+		  printf ("  inp   \"%s\"\n", data[i].inp);
+		  printf ("  base  %d\n", data[i].base);
+		  mpz_trace ("  got ",  got);
+		  mpz_trace ("  want", want);
+		  abort ();
+		}
+
+	      ASSERT_ALWAYS (fclose (fp) == 0);
+	    }
+	}
+    }
+
+  mpz_clear (got);
+  mpz_clear (want);
+}
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_data ();
+
+  unlink (FILENAME);
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpz/t-invert.c b/third_party/gmp/tests/mpz/t-invert.c
new file mode 100644
index 0000000..0081c49
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-invert.c
@@ -0,0 +1,117 @@
+/* Test mpz_invert.
+
+Copyright 1991, 1993, 1994, 1996, 1997, 2000-2005, 2008, 2009, 2012, 2014 Free
+Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+int
+main (int argc, char **argv)
+{
+  mpz_t a, m, ainv, t;
+  int test, r;
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long bsi, size_range;
+  int reps = 1000;
+
+  tests_start ();
+  TESTS_REPS (reps, argv, argc);
+
+  rands = RANDS;
+
+  mpz_init (bs);
+  mpz_init (a);
+  mpz_init (m);
+  mpz_init (ainv);
+  mpz_init (t);
+
+  for (test = 0; test < reps; test++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 16 + 2;
+
+      mpz_urandomb (bs, rands, size_range);
+      mpz_rrandomb (a, rands, mpz_get_ui (bs));
+      do {
+	mpz_urandomb (bs, rands, size_range);
+	mpz_rrandomb (m, rands, mpz_get_ui (bs));
+      } while (mpz_sgn (m) == 0);
+
+      mpz_urandomb (bs, rands, 8);
+      bsi = mpz_get_ui (bs);
+
+      if ((bsi & 1) != 0)
+	mpz_neg (a, a);
+      if ((bsi & 2) != 0)
+	mpz_neg (m, m);
+
+      r = mpz_invert (ainv, a, m);
+      if (r != 0)
+	{
+	  MPZ_CHECK_FORMAT (ainv);
+
+	  if (mpz_cmp_ui (ainv, 0) < 0 || mpz_cmpabs (ainv, m) >= 0)
+	    {
+	      fprintf (stderr, "ERROR in test %d\n", test);
+	      gmp_fprintf (stderr, "Inverse out of range.\n");
+	      gmp_fprintf (stderr, "a = %Zx\n", a);
+	      gmp_fprintf (stderr, "1/a = %Zx\n", ainv);
+	      gmp_fprintf (stderr, "m = %Zx\n", m);
+	      abort ();
+	    }
+
+	  mpz_mul (t, ainv, a);
+	  mpz_mod (t, t, m);
+
+	  if (mpz_cmp_ui (t, mpz_cmpabs_ui (m, 1) != 0) != 0)
+	    {
+	      fprintf (stderr, "ERROR in test %d\n", test);
+	      gmp_fprintf (stderr, "a^(-1)*a != 1 (mod m)\n");
+	      gmp_fprintf (stderr, "a = %Zx\n", a);
+	      gmp_fprintf (stderr, "m = %Zx\n", m);
+	      abort ();
+	    }
+	}
+      else /* Inverse deos not exist */
+	{
+	  mpz_gcd (t, a, m);
+	  if (mpz_cmp_ui (t, 1) == 0)
+	    {
+	      fprintf (stderr, "ERROR in test %d\n", test);
+	      gmp_fprintf (stderr, "Inverse exists, but was not found.\n");
+	      gmp_fprintf (stderr, "a = %Zx\n", a);
+	      gmp_fprintf (stderr, "m = %Zx\n", m);
+	      abort ();
+	    }
+	}
+    }
+
+  mpz_clear (bs);
+  mpz_clear (a);
+  mpz_clear (m);
+  mpz_clear (ainv);
+  mpz_clear (t);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpz/t-io_raw.c b/third_party/gmp/tests/mpz/t-io_raw.c
new file mode 100644
index 0000000..e299b5a
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-io_raw.c
@@ -0,0 +1,286 @@
+/* Test mpz_inp_raw and mpz_out_raw.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#define FILENAME  "t-io_raw.tmp"
+
+
+/* In the fopen, "b" selects binary mode on DOS systems, meaning no
+   conversion of '\n' to and from CRLF.  It's believed systems without such
+   nonsense will simply ignore the "b", but in case that's not so a plain
+   "w+" is attempted if "w+b" fails.  */
+
+FILE *
+fopen_wplusb_or_die (const char *filename)
+{
+  FILE  *fp;
+  fp = fopen (filename, "w+b");
+  if (fp == NULL)
+    fp = fopen (filename, "w+");
+
+  if (fp == NULL)
+    {
+      printf ("Cannot create file %s\n", filename);
+      abort ();
+    }
+  return fp;
+}
+
+/* use 0x80 to check nothing bad happens with sign extension etc */
+#define BYTEVAL(i)  (((i) + 1) | 0x80)
+
+void
+check_in (void)
+{
+  int        i, j, zeros, neg, error = 0;
+  mpz_t      want, got;
+  size_t     want_ret, got_ret;
+  mp_size_t  size;
+  FILE       *fp;
+
+  mpz_init (want);
+  mpz_init (got);
+
+  for (i = 0; i < 32; i++)
+    {
+      for (zeros = 0; zeros < 8; zeros++)
+	{
+	  for (neg = 0; neg <= 1; neg++)
+	    {
+	      want_ret = i + zeros + 4;
+
+	      /* need this to get the twos complement right */
+	      ASSERT_ALWAYS (sizeof (size) >= 4);
+
+	      size = i + zeros;
+	      if (neg)
+		size = -size;
+
+	      fp = fopen_wplusb_or_die (FILENAME);
+	      for (j = 3; j >= 0; j--)
+		ASSERT_ALWAYS (putc ((size >> (j*8)) & 0xFF, fp) != EOF);
+	      for (j = 0; j < zeros; j++)
+		ASSERT_ALWAYS (putc ('\0', fp) != EOF);
+	      for (j = 0; j < i; j++)
+		ASSERT_ALWAYS (putc (BYTEVAL (j), fp) != EOF);
+	      /* and some trailing garbage */
+	      ASSERT_ALWAYS (putc ('x', fp) != EOF);
+	      ASSERT_ALWAYS (putc ('y', fp) != EOF);
+	      ASSERT_ALWAYS (putc ('z', fp) != EOF);
+	      ASSERT_ALWAYS (fflush (fp) == 0);
+	      rewind (fp);
+
+	      got_ret = mpz_inp_raw (got, fp);
+	      ASSERT_ALWAYS (! ferror(fp));
+	      ASSERT_ALWAYS (fclose (fp) == 0);
+
+	      MPZ_CHECK_FORMAT (got);
+
+	      if (got_ret != want_ret)
+		{
+		  printf ("check_in: return value wrong\n");
+		  error = 1;
+		}
+	      if (mpz_cmp (got, want) != 0)
+		{
+		  printf ("check_in: result wrong\n");
+		  error = 1;
+		}
+	      if (error)
+		{
+		  printf    ("  i=%d zeros=%d neg=%d\n", i, zeros, neg);
+		  printf    ("  got_ret  %lu\n", (unsigned long) got_ret);
+		  printf    ("  want_ret %lu\n", (unsigned long) want_ret);
+		  mpz_trace ("  got      ", got);
+		  mpz_trace ("  want     ", want);
+		  abort ();
+		}
+
+	      mpz_neg (want, want);
+	    }
+	}
+      mpz_mul_2exp (want, want, 8);
+      mpz_add_ui (want, want, (unsigned long) BYTEVAL (i));
+    }
+
+  mpz_clear (want);
+  mpz_clear (got);
+}
+
+
+void
+check_out (void)
+{
+  int        i, j, neg, error = 0;
+  mpz_t      z;
+  char       want[256], got[256], *p;
+  size_t     want_len, got_ret, got_read;
+  mp_size_t  size;
+  FILE       *fp;
+
+  mpz_init (z);
+
+  for (i = 0; i < 32; i++)
+    {
+      for (neg = 0; neg <= 1; neg++)
+	{
+	  want_len = i + 4;
+
+	  /* need this to get the twos complement right */
+	  ASSERT_ALWAYS (sizeof (size) >= 4);
+
+	  size = i;
+	  if (neg)
+	    size = -size;
+
+	  p = want;
+	  for (j = 3; j >= 0; j--)
+	    *p++ = size >> (j*8);
+	  for (j = 0; j < i; j++)
+	    *p++ = BYTEVAL (j);
+	  ASSERT_ALWAYS (p <= want + sizeof (want));
+
+	  fp = fopen_wplusb_or_die (FILENAME);
+	  got_ret = mpz_out_raw (fp, z);
+	  ASSERT_ALWAYS (fflush (fp) == 0);
+	  rewind (fp);
+	  got_read = fread (got, 1, sizeof(got), fp);
+	  ASSERT_ALWAYS (! ferror(fp));
+	  ASSERT_ALWAYS (fclose (fp) == 0);
+
+	  if (got_ret != want_len)
+	    {
+	      printf ("check_out: wrong return value\n");
+	      error = 1;
+	    }
+	  if (got_read != want_len)
+	    {
+	      printf ("check_out: wrong number of bytes read back\n");
+	      error = 1;
+	    }
+	  if (memcmp (want, got, want_len) != 0)
+	    {
+	      printf ("check_out: wrong data\n");
+	      error = 1;
+	    }
+	  if (error)
+	    {
+	      printf    ("  i=%d neg=%d\n", i, neg);
+	      mpz_trace ("  z", z);
+	      printf    ("  got_ret  %lu\n", (unsigned long) got_ret);
+	      printf    ("  got_read %lu\n", (unsigned long) got_read);
+	      printf    ("  want_len %lu\n", (unsigned long) want_len);
+	      printf    ("  want");
+	      for (j = 0; j < want_len; j++)
+		printf (" %02X", (unsigned) (unsigned char) want[j]);
+	      printf    ("\n");
+	      printf    ("  got ");
+	      for (j = 0; j < want_len; j++)
+		printf (" %02X", (unsigned) (unsigned char) got[j]);
+	      printf    ("\n");
+	      abort ();
+	    }
+
+	  mpz_neg (z, z);
+	}
+      mpz_mul_2exp (z, z, 8);
+      mpz_add_ui (z, z, (unsigned long) BYTEVAL (i));
+    }
+
+  mpz_clear (z);
+}
+
+
+void
+check_rand (void)
+{
+  gmp_randstate_ptr  rands = RANDS;
+  int        i, error = 0;
+  mpz_t      got, want;
+  size_t     inp_ret, out_ret;
+  FILE       *fp;
+
+  mpz_init (want);
+  mpz_init (got);
+
+  for (i = 0; i < 500; i++)
+    {
+      mpz_erandomb (want, rands, 10*GMP_LIMB_BITS);
+      mpz_negrandom (want, rands);
+
+      fp = fopen_wplusb_or_die (FILENAME);
+      out_ret = mpz_out_raw (fp, want);
+      ASSERT_ALWAYS (fflush (fp) == 0);
+      rewind (fp);
+      inp_ret = mpz_inp_raw (got, fp);
+      ASSERT_ALWAYS (fclose (fp) == 0);
+
+      MPZ_CHECK_FORMAT (got);
+
+      if (inp_ret != out_ret)
+	{
+	  printf ("check_rand: different inp/out return values\n");
+	  error = 1;
+	}
+      if (mpz_cmp (got, want) != 0)
+	{
+	  printf ("check_rand: wrong result\n");
+	  error = 1;
+	}
+      if (error)
+	{
+	  printf    ("  out_ret %lu\n", (unsigned long) out_ret);
+	  printf    ("  inp_ret %lu\n", (unsigned long) inp_ret);
+	  mpz_trace ("  want", want);
+	  mpz_trace ("  got ", got);
+	  abort ();
+	}
+    }
+
+  mpz_clear (got);
+  mpz_clear (want);
+}
+
+
+int
+main (void)
+{
+  tests_start ();
+  mp_trace_base = -16;
+
+  check_in ();
+  check_out ();
+  check_rand ();
+
+  unlink (FILENAME);
+  tests_end ();
+
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpz/t-jac.c b/third_party/gmp/tests/mpz/t-jac.c
new file mode 100644
index 0000000..ed8aff8
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-jac.c
@@ -0,0 +1,1008 @@
+/* Exercise mpz_*_kronecker_*() and mpz_jacobi() functions.
+
+Copyright 1999-2004, 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+/* With no arguments the various Kronecker/Jacobi symbol routines are
+   checked against some test data and a lot of derived data.
+
+   To check the test data against PARI-GP, run
+
+	   t-jac -p | gp -q
+
+   Enhancements:
+
+   More big test cases than those given by check_squares_zi would be good.  */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#ifdef _LONG_LONG_LIMB
+#define LL(l,ll)  ll
+#else
+#define LL(l,ll)  l
+#endif
+
+
+int option_pari = 0;
+
+
+unsigned long
+mpz_mod4 (mpz_srcptr z)
+{
+  mpz_t          m;
+  unsigned long  ret;
+
+  mpz_init (m);
+  mpz_fdiv_r_2exp (m, z, 2);
+  ret = mpz_get_ui (m);
+  mpz_clear (m);
+  return ret;
+}
+
+int
+mpz_fits_ulimb_p (mpz_srcptr z)
+{
+  return (SIZ(z) == 1 || SIZ(z) == 0);
+}
+
+mp_limb_t
+mpz_get_ulimb (mpz_srcptr z)
+{
+  if (SIZ(z) == 0)
+    return 0;
+  else
+    return PTR(z)[0];
+}
+
+
+void
+try_base (mp_limb_t a, mp_limb_t b, int answer)
+{
+  int  got;
+
+  if ((b & 1) == 0 || b == 1 || a > b)
+    return;
+
+  got = mpn_jacobi_base (a, b, 0);
+  if (got != answer)
+    {
+      printf (LL("mpn_jacobi_base (%lu, %lu) is %d should be %d\n",
+		 "mpn_jacobi_base (%llu, %llu) is %d should be %d\n"),
+	      a, b, got, answer);
+      abort ();
+    }
+}
+
+
+void
+try_zi_ui (mpz_srcptr a, unsigned long b, int answer)
+{
+  int  got;
+
+  got = mpz_kronecker_ui (a, b);
+  if (got != answer)
+    {
+      printf ("mpz_kronecker_ui (");
+      mpz_out_str (stdout, 10, a);
+      printf (", %lu) is %d should be %d\n", b, got, answer);
+      abort ();
+    }
+}
+
+
+void
+try_zi_si (mpz_srcptr a, long b, int answer)
+{
+  int  got;
+
+  got = mpz_kronecker_si (a, b);
+  if (got != answer)
+    {
+      printf ("mpz_kronecker_si (");
+      mpz_out_str (stdout, 10, a);
+      printf (", %ld) is %d should be %d\n", b, got, answer);
+      abort ();
+    }
+}
+
+
+void
+try_ui_zi (unsigned long a, mpz_srcptr b, int answer)
+{
+  int  got;
+
+  got = mpz_ui_kronecker (a, b);
+  if (got != answer)
+    {
+      printf ("mpz_ui_kronecker (%lu, ", a);
+      mpz_out_str (stdout, 10, b);
+      printf (") is %d should be %d\n", got, answer);
+      abort ();
+    }
+}
+
+
+void
+try_si_zi (long a, mpz_srcptr b, int answer)
+{
+  int  got;
+
+  got = mpz_si_kronecker (a, b);
+  if (got != answer)
+    {
+      printf ("mpz_si_kronecker (%ld, ", a);
+      mpz_out_str (stdout, 10, b);
+      printf (") is %d should be %d\n", got, answer);
+      abort ();
+    }
+}
+
+
+/* Don't bother checking mpz_jacobi, since it only differs for b even, and
+   we don't have an actual expected answer for it.  tests/devel/try.c does
+   some checks though.  */
+void
+try_zi_zi (mpz_srcptr a, mpz_srcptr b, int answer)
+{
+  int  got;
+
+  got = mpz_kronecker (a, b);
+  if (got != answer)
+    {
+      printf ("mpz_kronecker (");
+      mpz_out_str (stdout, 10, a);
+      printf (", ");
+      mpz_out_str (stdout, 10, b);
+      printf (") is %d should be %d\n", got, answer);
+      abort ();
+    }
+}
+
+
+void
+try_pari (mpz_srcptr a, mpz_srcptr b, int answer)
+{
+  printf ("try(");
+  mpz_out_str (stdout, 10, a);
+  printf (",");
+  mpz_out_str (stdout, 10, b);
+  printf (",%d)\n", answer);
+}
+
+
+void
+try_each (mpz_srcptr a, mpz_srcptr b, int answer)
+{
+#if 0
+  fprintf(stderr, "asize = %d, bsize = %d\n",
+	  mpz_sizeinbase (a, 2), mpz_sizeinbase (b, 2));
+#endif
+  if (option_pari)
+    {
+      try_pari (a, b, answer);
+      return;
+    }
+
+  if (mpz_fits_ulimb_p (a) && mpz_fits_ulimb_p (b))
+    try_base (mpz_get_ulimb (a), mpz_get_ulimb (b), answer);
+
+  if (mpz_fits_ulong_p (b))
+    try_zi_ui (a, mpz_get_ui (b), answer);
+
+  if (mpz_fits_slong_p (b))
+    try_zi_si (a, mpz_get_si (b), answer);
+
+  if (mpz_fits_ulong_p (a))
+    try_ui_zi (mpz_get_ui (a), b, answer);
+
+  if (mpz_fits_sint_p (a))
+    try_si_zi (mpz_get_si (a), b, answer);
+
+  try_zi_zi (a, b, answer);
+}
+
+
+/* Try (a/b) and (a/-b). */
+void
+try_pn (mpz_srcptr a, mpz_srcptr b_orig, int answer)
+{
+  mpz_t  b;
+
+  mpz_init_set (b, b_orig);
+  try_each (a, b, answer);
+
+  mpz_neg (b, b);
+  if (mpz_sgn (a) < 0)
+    answer = -answer;
+
+  try_each (a, b, answer);
+
+  mpz_clear (b);
+}
+
+
+/* Try (a+k*p/b) for various k, using the fact (a/b) is periodic in a with
+   period p.  For b>0, p=b if b!=2mod4 or p=4*b if b==2mod4. */
+
+void
+try_periodic_num (mpz_srcptr a_orig, mpz_srcptr b, int answer)
+{
+  mpz_t  a, a_period;
+  int    i;
+
+  if (mpz_sgn (b) <= 0)
+    return;
+
+  mpz_init_set (a, a_orig);
+  mpz_init_set (a_period, b);
+  if (mpz_mod4 (b) == 2)
+    mpz_mul_ui (a_period, a_period, 4);
+
+  /* don't bother with these tests if they're only going to produce
+     even/even */
+  if (mpz_even_p (a) && mpz_even_p (b) && mpz_even_p (a_period))
+    goto done;
+
+  for (i = 0; i < 6; i++)
+    {
+      mpz_add (a, a, a_period);
+      try_pn (a, b, answer);
+    }
+
+  mpz_set (a, a_orig);
+  for (i = 0; i < 6; i++)
+    {
+      mpz_sub (a, a, a_period);
+      try_pn (a, b, answer);
+    }
+
+ done:
+  mpz_clear (a);
+  mpz_clear (a_period);
+}
+
+
+/* Try (a/b+k*p) for various k, using the fact (a/b) is periodic in b of
+   period p.
+
+			       period p
+	   a==0,1mod4             a
+	   a==2mod4              4*a
+	   a==3mod4 and b odd    4*a
+	   a==3mod4 and b even   8*a
+
+   In Henri Cohen's book the period is given as 4*a for all a==2,3mod4, but
+   a counterexample would seem to be (3/2)=-1 which with (3/14)=+1 doesn't
+   have period 4*a (but rather 8*a with (3/26)=-1).  Maybe the plain 4*a is
+   to be read as applying to a plain Jacobi symbol with b odd, rather than
+   the Kronecker extension to b even. */
+
+void
+try_periodic_den (mpz_srcptr a, mpz_srcptr b_orig, int answer)
+{
+  mpz_t  b, b_period;
+  int    i;
+
+  if (mpz_sgn (a) == 0 || mpz_sgn (b_orig) == 0)
+    return;
+
+  mpz_init_set (b, b_orig);
+
+  mpz_init_set (b_period, a);
+  if (mpz_mod4 (a) == 3 && mpz_even_p (b))
+    mpz_mul_ui (b_period, b_period, 8L);
+  else if (mpz_mod4 (a) >= 2)
+    mpz_mul_ui (b_period, b_period, 4L);
+
+  /* don't bother with these tests if they're only going to produce
+     even/even */
+  if (mpz_even_p (a) && mpz_even_p (b) && mpz_even_p (b_period))
+    goto done;
+
+  for (i = 0; i < 6; i++)
+    {
+      mpz_add (b, b, b_period);
+      try_pn (a, b, answer);
+    }
+
+  mpz_set (b, b_orig);
+  for (i = 0; i < 6; i++)
+    {
+      mpz_sub (b, b, b_period);
+      try_pn (a, b, answer);
+    }
+
+ done:
+  mpz_clear (b);
+  mpz_clear (b_period);
+}
+
+
+static const unsigned long  ktable[] = {
+  0, 1, 2, 3, 4, 5, 6, 7,
+  GMP_NUMB_BITS-1, GMP_NUMB_BITS, GMP_NUMB_BITS+1,
+  2*GMP_NUMB_BITS-1, 2*GMP_NUMB_BITS, 2*GMP_NUMB_BITS+1,
+  3*GMP_NUMB_BITS-1, 3*GMP_NUMB_BITS, 3*GMP_NUMB_BITS+1
+};
+
+
+/* Try (a/b*2^k) for various k. */
+void
+try_2den (mpz_srcptr a, mpz_srcptr b_orig, int answer)
+{
+  mpz_t  b;
+  int    kindex;
+  int    answer_a2, answer_k;
+  unsigned long k;
+
+  /* don't bother when b==0 */
+  if (mpz_sgn (b_orig) == 0)
+    return;
+
+  mpz_init_set (b, b_orig);
+
+  /* (a/2) is 0 if a even, 1 if a==1 or 7 mod 8, -1 if a==3 or 5 mod 8 */
+  answer_a2 = (mpz_even_p (a) ? 0
+	       : (((SIZ(a) >= 0 ? PTR(a)[0] : -PTR(a)[0]) + 2) & 7) < 4 ? 1
+	       : -1);
+
+  for (kindex = 0; kindex < numberof (ktable); kindex++)
+    {
+      k = ktable[kindex];
+
+      /* answer_k = answer*(answer_a2^k) */
+      answer_k = (answer_a2 == 0 && k != 0 ? 0
+		  : (k & 1) == 1 && answer_a2 == -1 ? -answer
+		  : answer);
+
+      mpz_mul_2exp (b, b_orig, k);
+      try_pn (a, b, answer_k);
+    }
+
+  mpz_clear (b);
+}
+
+
+/* Try (a*2^k/b) for various k.  If it happens mpz_ui_kronecker() gets (2/b)
+   wrong it will show up as wrong answers demanded. */
+void
+try_2num (mpz_srcptr a_orig, mpz_srcptr b, int answer)
+{
+  mpz_t  a;
+  int    kindex;
+  int    answer_2b, answer_k;
+  unsigned long  k;
+
+  /* don't bother when a==0 */
+  if (mpz_sgn (a_orig) == 0)
+    return;
+
+  mpz_init (a);
+
+  /* (2/b) is 0 if b even, 1 if b==1 or 7 mod 8, -1 if b==3 or 5 mod 8 */
+  answer_2b = (mpz_even_p (b) ? 0
+	       : (((SIZ(b) >= 0 ? PTR(b)[0] : -PTR(b)[0]) + 2) & 7) < 4 ? 1
+	       : -1);
+
+  for (kindex = 0; kindex < numberof (ktable); kindex++)
+    {
+      k = ktable[kindex];
+
+      /* answer_k = answer*(answer_2b^k) */
+      answer_k = (answer_2b == 0 && k != 0 ? 0
+		  : (k & 1) == 1 && answer_2b == -1 ? -answer
+		  : answer);
+
+	mpz_mul_2exp (a, a_orig, k);
+      try_pn (a, b, answer_k);
+    }
+
+  mpz_clear (a);
+}
+
+
+/* The try_2num() and try_2den() routines don't in turn call
+   try_periodic_num() and try_periodic_den() because it hugely increases the
+   number of tests performed, without obviously increasing coverage.
+
+   Useful extra derived cases can be added here. */
+
+void
+try_all (mpz_t a, mpz_t b, int answer)
+{
+  try_pn (a, b, answer);
+  try_periodic_num (a, b, answer);
+  try_periodic_den (a, b, answer);
+  try_2num (a, b, answer);
+  try_2den (a, b, answer);
+}
+
+
+void
+check_data (void)
+{
+  static const struct {
+    const char  *a;
+    const char  *b;
+    int         answer;
+
+  } data[] = {
+
+    /* Note that the various derived checks in try_all() reduce the cases
+       that need to be given here.  */
+
+    /* some zeros */
+    {  "0",  "0", 0 },
+    {  "0",  "2", 0 },
+    {  "0",  "6", 0 },
+    {  "5",  "0", 0 },
+    { "24", "60", 0 },
+
+    /* (a/1) = 1, any a
+       In particular note (0/1)=1 so that (a/b)=(a mod b/b). */
+    { "0", "1", 1 },
+    { "1", "1", 1 },
+    { "2", "1", 1 },
+    { "3", "1", 1 },
+    { "4", "1", 1 },
+    { "5", "1", 1 },
+
+    /* (0/b) = 0, b != 1 */
+    { "0",  "3", 0 },
+    { "0",  "5", 0 },
+    { "0",  "7", 0 },
+    { "0",  "9", 0 },
+    { "0", "11", 0 },
+    { "0", "13", 0 },
+    { "0", "15", 0 },
+
+    /* (1/b) = 1 */
+    { "1",  "1", 1 },
+    { "1",  "3", 1 },
+    { "1",  "5", 1 },
+    { "1",  "7", 1 },
+    { "1",  "9", 1 },
+    { "1", "11", 1 },
+
+    /* (-1/b) = (-1)^((b-1)/2) which is -1 for b==3 mod 4 */
+    { "-1",  "1",  1 },
+    { "-1",  "3", -1 },
+    { "-1",  "5",  1 },
+    { "-1",  "7", -1 },
+    { "-1",  "9",  1 },
+    { "-1", "11", -1 },
+    { "-1", "13",  1 },
+    { "-1", "15", -1 },
+    { "-1", "17",  1 },
+    { "-1", "19", -1 },
+
+    /* (2/b) = (-1)^((b^2-1)/8) which is -1 for b==3,5 mod 8.
+       try_2num() will exercise multiple powers of 2 in the numerator.  */
+    { "2",  "1",  1 },
+    { "2",  "3", -1 },
+    { "2",  "5", -1 },
+    { "2",  "7",  1 },
+    { "2",  "9",  1 },
+    { "2", "11", -1 },
+    { "2", "13", -1 },
+    { "2", "15",  1 },
+    { "2", "17",  1 },
+
+    /* (-2/b) = (-1)^((b^2-1)/8)*(-1)^((b-1)/2) which is -1 for b==5,7mod8.
+       try_2num() will exercise multiple powers of 2 in the numerator, which
+       will test that the shift in mpz_si_kronecker() uses unsigned not
+       signed.  */
+    { "-2",  "1",  1 },
+    { "-2",  "3",  1 },
+    { "-2",  "5", -1 },
+    { "-2",  "7", -1 },
+    { "-2",  "9",  1 },
+    { "-2", "11",  1 },
+    { "-2", "13", -1 },
+    { "-2", "15", -1 },
+    { "-2", "17",  1 },
+
+    /* (a/2)=(2/a).
+       try_2den() will exercise multiple powers of 2 in the denominator. */
+    {  "3",  "2", -1 },
+    {  "5",  "2", -1 },
+    {  "7",  "2",  1 },
+    {  "9",  "2",  1 },
+    {  "11", "2", -1 },
+
+    /* Harriet Griffin, "Elementary Theory of Numbers", page 155, various
+       examples.  */
+    {   "2", "135",  1 },
+    { "135",  "19", -1 },
+    {   "2",  "19", -1 },
+    {  "19", "135",  1 },
+    { "173", "135",  1 },
+    {  "38", "135",  1 },
+    { "135", "173",  1 },
+    { "173",   "5", -1 },
+    {   "3",   "5", -1 },
+    {   "5", "173", -1 },
+    { "173",   "3", -1 },
+    {   "2",   "3", -1 },
+    {   "3", "173", -1 },
+    { "253",  "21",  1 },
+    {   "1",  "21",  1 },
+    {  "21", "253",  1 },
+    {  "21",  "11", -1 },
+    {  "-1",  "11", -1 },
+
+    /* Griffin page 147 */
+    {  "-1",  "17",  1 },
+    {   "2",  "17",  1 },
+    {  "-2",  "17",  1 },
+    {  "-1",  "89",  1 },
+    {   "2",  "89",  1 },
+
+    /* Griffin page 148 */
+    {  "89",  "11",  1 },
+    {   "1",  "11",  1 },
+    {  "89",   "3", -1 },
+    {   "2",   "3", -1 },
+    {   "3",  "89", -1 },
+    {  "11",  "89",  1 },
+    {  "33",  "89", -1 },
+
+    /* H. Davenport, "The Higher Arithmetic", page 65, the quadratic
+       residues and non-residues mod 19.  */
+    {  "1", "19",  1 },
+    {  "4", "19",  1 },
+    {  "5", "19",  1 },
+    {  "6", "19",  1 },
+    {  "7", "19",  1 },
+    {  "9", "19",  1 },
+    { "11", "19",  1 },
+    { "16", "19",  1 },
+    { "17", "19",  1 },
+    {  "2", "19", -1 },
+    {  "3", "19", -1 },
+    {  "8", "19", -1 },
+    { "10", "19", -1 },
+    { "12", "19", -1 },
+    { "13", "19", -1 },
+    { "14", "19", -1 },
+    { "15", "19", -1 },
+    { "18", "19", -1 },
+
+    /* Residues and non-residues mod 13 */
+    {  "0",  "13",  0 },
+    {  "1",  "13",  1 },
+    {  "2",  "13", -1 },
+    {  "3",  "13",  1 },
+    {  "4",  "13",  1 },
+    {  "5",  "13", -1 },
+    {  "6",  "13", -1 },
+    {  "7",  "13", -1 },
+    {  "8",  "13", -1 },
+    {  "9",  "13",  1 },
+    { "10",  "13",  1 },
+    { "11",  "13", -1 },
+    { "12",  "13",  1 },
+
+    /* various */
+    {  "5",   "7", -1 },
+    { "15",  "17",  1 },
+    { "67",  "89",  1 },
+
+    /* special values inducing a==b==1 at the end of jac_or_kron() */
+    { "0x10000000000000000000000000000000000000000000000001",
+      "0x10000000000000000000000000000000000000000000000003", 1 },
+
+    /* Test for previous bugs in jacobi_2. */
+    { "0x43900000000", "0x42400000439", -1 }, /* 32-bit limbs */
+    { "0x4390000000000000000", "0x4240000000000000439", -1 }, /* 64-bit limbs */
+
+    { "198158408161039063", "198158360916398807", -1 },
+
+    /* Some tests involving large quotients in the continued fraction
+       expansion. */
+    { "37200210845139167613356125645445281805",
+      "451716845976689892447895811408978421929", -1 },
+    { "67674091930576781943923596701346271058970643542491743605048620644676477275152701774960868941561652032482173612421015",
+      "4902678867794567120224500687210807069172039735", 0 },
+    { "2666617146103764067061017961903284334497474492754652499788571378062969111250584288683585223600172138551198546085281683283672592", "2666617146103764067061017961903284334497474492754652499788571378062969111250584288683585223600172138551198546085281683290481773", 1 },
+
+    /* Exercises the case asize == 1, btwos > 0 in mpz_jacobi. */
+    { "804609", "421248363205206617296534688032638102314410556521742428832362659824", 1 } ,
+    { "4190209", "2239744742177804210557442048984321017460028974602978995388383905961079286530650825925074203175536427000", 1 },
+
+    /* Exercises the case asize == 1, btwos = 63 in mpz_jacobi
+       (relevant when GMP_LIMB_BITS == 64). */
+    { "17311973299000934401", "1675975991242824637446753124775689449936871337036614677577044717424700351103148799107651171694863695242089956242888229458836426332300124417011114380886016", 1 },
+    { "3220569220116583677", "41859917623035396746", -1 },
+
+    /* Other test cases that triggered bugs during development. */
+    { "37200210845139167613356125645445281805", "340116213441272389607827434472642576514", -1 },
+    { "74400421690278335226712251290890563610", "451716845976689892447895811408978421929", -1 },
+  };
+
+  int    i;
+  mpz_t  a, b;
+
+  mpz_init (a);
+  mpz_init (b);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_set_str_or_abort (a, data[i].a, 0);
+      mpz_set_str_or_abort (b, data[i].b, 0);
+      try_all (a, b, data[i].answer);
+    }
+
+  mpz_clear (a);
+  mpz_clear (b);
+}
+
+
+/* (a^2/b)=1 if gcd(a,b)=1, or (a^2/b)=0 if gcd(a,b)!=1.
+   This includes when a=0 or b=0. */
+void
+check_squares_zi (void)
+{
+  gmp_randstate_ptr rands = RANDS;
+  mpz_t  a, b, g;
+  int    i, answer;
+  mp_size_t size_range, an, bn;
+  mpz_t bs;
+
+  mpz_init (bs);
+  mpz_init (a);
+  mpz_init (b);
+  mpz_init (g);
+
+  for (i = 0; i < 50; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 10 + i/8 + 2;
+
+      mpz_urandomb (bs, rands, size_range);
+      an = mpz_get_ui (bs);
+      mpz_rrandomb (a, rands, an);
+
+      mpz_urandomb (bs, rands, size_range);
+      bn = mpz_get_ui (bs);
+      mpz_rrandomb (b, rands, bn);
+
+      mpz_gcd (g, a, b);
+      if (mpz_cmp_ui (g, 1L) == 0)
+	answer = 1;
+      else
+	answer = 0;
+
+      mpz_mul (a, a, a);
+
+      try_all (a, b, answer);
+    }
+
+  mpz_clear (bs);
+  mpz_clear (a);
+  mpz_clear (b);
+  mpz_clear (g);
+}
+
+
+/* Check the handling of asize==0, make sure it isn't affected by the low
+   limb. */
+void
+check_a_zero (void)
+{
+  mpz_t  a, b;
+
+  mpz_init_set_ui (a, 0);
+  mpz_init (b);
+
+  mpz_set_ui (b, 1L);
+  PTR(a)[0] = 0;
+  try_all (a, b, 1);   /* (0/1)=1 */
+  PTR(a)[0] = 1;
+  try_all (a, b, 1);   /* (0/1)=1 */
+
+  mpz_set_si (b, -1L);
+  PTR(a)[0] = 0;
+  try_all (a, b, 1);   /* (0/-1)=1 */
+  PTR(a)[0] = 1;
+  try_all (a, b, 1);   /* (0/-1)=1 */
+
+  mpz_set_ui (b, 0);
+  PTR(a)[0] = 0;
+  try_all (a, b, 0);   /* (0/0)=0 */
+  PTR(a)[0] = 1;
+  try_all (a, b, 0);   /* (0/0)=0 */
+
+  mpz_set_ui (b, 2);
+  PTR(a)[0] = 0;
+  try_all (a, b, 0);   /* (0/2)=0 */
+  PTR(a)[0] = 1;
+  try_all (a, b, 0);   /* (0/2)=0 */
+
+  mpz_clear (a);
+  mpz_clear (b);
+}
+
+
+/* Assumes that b = prod p_k^e_k */
+int
+ref_jacobi (mpz_srcptr a, mpz_srcptr b, unsigned nprime,
+	    mpz_t prime[], unsigned *exp)
+{
+  unsigned i;
+  int res;
+
+  for (i = 0, res = 1; i < nprime; i++)
+    if (exp[i])
+      {
+	int legendre = refmpz_legendre (a, prime[i]);
+	if (!legendre)
+	  return 0;
+	if (exp[i] & 1)
+	  res *= legendre;
+      }
+  return res;
+}
+
+void
+check_jacobi_factored (void)
+{
+#define PRIME_N 10
+#define PRIME_MAX_SIZE 50
+#define PRIME_MAX_EXP 4
+#define PRIME_A_COUNT 10
+#define PRIME_B_COUNT 5
+#define PRIME_MAX_B_SIZE 2000
+
+  gmp_randstate_ptr rands = RANDS;
+  mpz_t prime[PRIME_N];
+  unsigned exp[PRIME_N];
+  mpz_t a, b, t, bs;
+  unsigned i;
+
+  mpz_init (a);
+  mpz_init (b);
+  mpz_init (t);
+  mpz_init (bs);
+
+  /* Generate primes */
+  for (i = 0; i < PRIME_N; i++)
+    {
+      mp_size_t size;
+      mpz_init (prime[i]);
+      mpz_urandomb (bs, rands, 32);
+      size = mpz_get_ui (bs) % PRIME_MAX_SIZE + 2;
+      mpz_rrandomb (prime[i], rands, size);
+      if (mpz_cmp_ui (prime[i], 3) <= 0)
+	mpz_set_ui (prime[i], 3);
+      else
+	mpz_nextprime (prime[i], prime[i]);
+    }
+
+  for (i = 0; i < PRIME_B_COUNT; i++)
+    {
+      unsigned j, k;
+      mp_bitcnt_t bsize;
+
+      mpz_set_ui (b, 1);
+      bsize = 1;
+
+      for (j = 0; j < PRIME_N && bsize < PRIME_MAX_B_SIZE; j++)
+	{
+	  mpz_urandomb (bs, rands, 32);
+	  exp[j] = mpz_get_ui (bs) % PRIME_MAX_EXP;
+	  mpz_pow_ui (t, prime[j], exp[j]);
+	  mpz_mul (b, b, t);
+	  bsize = mpz_sizeinbase (b, 2);
+	}
+      for (k = 0; k < PRIME_A_COUNT; k++)
+	{
+	  int answer;
+	  mpz_rrandomb (a, rands, bsize + 2);
+	  answer = ref_jacobi (a, b, j, prime, exp);
+	  try_all (a, b, answer);
+	}
+    }
+  for (i = 0; i < PRIME_N; i++)
+    mpz_clear (prime[i]);
+
+  mpz_clear (a);
+  mpz_clear (b);
+  mpz_clear (t);
+  mpz_clear (bs);
+
+#undef PRIME_N
+#undef PRIME_MAX_SIZE
+#undef PRIME_MAX_EXP
+#undef PRIME_A_COUNT
+#undef PRIME_B_COUNT
+#undef PRIME_MAX_B_SIZE
+}
+
+/* These tests compute (a|n), where the quotient sequence includes
+   large quotients, and n has a known factorization. Such inputs are
+   generated as follows. First, construct a large n, as a power of a
+   prime p of moderate size.
+
+   Next, compute a matrix from factors (q,1;1,0), with q chosen with
+   uniformly distributed size. We must stop with matrix elements of
+   roughly half the size of n. Denote elements of M as M = (m00, m01;
+   m10, m11).
+
+   We now look for solutions to
+
+     n = m00 x + m01 y
+     a = m10 x + m11 y
+
+   with x,y > 0. Since n >= m00 * m01, there exists a positive
+   solution to the first equation. Find those x, y, and substitute in
+   the second equation to get a. Then the quotient sequence for (a|n)
+   is precisely the quotients used when constructing M, followed by
+   the quotient sequence for (x|y).
+
+   Numbers should also be large enough that we exercise hgcd_jacobi,
+   which means that they should be larger than
+
+     max (GCD_DC_THRESHOLD, 3 * HGCD_THRESHOLD)
+
+   With an n of roughly 40000 bits, this should hold on most machines.
+*/
+
+void
+check_large_quotients (void)
+{
+#define COUNT 50
+#define PBITS 200
+#define PPOWER 201
+#define MAX_QBITS 500
+
+  gmp_randstate_ptr rands = RANDS;
+
+  mpz_t p, n, q, g, s, t, x, y, bs;
+  mpz_t M[2][2];
+  mp_bitcnt_t nsize;
+  unsigned i;
+
+  mpz_init (p);
+  mpz_init (n);
+  mpz_init (q);
+  mpz_init (g);
+  mpz_init (s);
+  mpz_init (t);
+  mpz_init (x);
+  mpz_init (y);
+  mpz_init (bs);
+  mpz_init (M[0][0]);
+  mpz_init (M[0][1]);
+  mpz_init (M[1][0]);
+  mpz_init (M[1][1]);
+
+  /* First generate a number with known factorization, as a random
+     smallish prime raised to an odd power. Then (a|n) = (a|p). */
+  mpz_rrandomb (p, rands, PBITS);
+  mpz_nextprime (p, p);
+  mpz_pow_ui (n, p, PPOWER);
+
+  nsize = mpz_sizeinbase (n, 2);
+
+  for (i = 0; i < COUNT; i++)
+    {
+      int answer;
+      mp_bitcnt_t msize;
+
+      mpz_set_ui (M[0][0], 1);
+      mpz_set_ui (M[0][1], 0);
+      mpz_set_ui (M[1][0], 0);
+      mpz_set_ui (M[1][1], 1);
+
+      for (msize = 1; 2*(msize + MAX_QBITS) + 1 < nsize ;)
+	{
+	  unsigned i;
+	  mpz_rrandomb (bs, rands, 32);
+	  mpz_rrandomb (q, rands, 1 + mpz_get_ui (bs) % MAX_QBITS);
+
+	  /* Multiply by (q, 1; 1,0) from the right */
+	  for (i = 0; i < 2; i++)
+	    {
+	      mp_bitcnt_t size;
+	      mpz_swap (M[i][0], M[i][1]);
+	      mpz_addmul (M[i][0], M[i][1], q);
+	      size = mpz_sizeinbase (M[i][0], 2);
+	      if (size > msize)
+		msize = size;
+	    }
+	}
+      mpz_gcdext (g, s, t, M[0][0], M[0][1]);
+      ASSERT_ALWAYS (mpz_cmp_ui (g, 1) == 0);
+
+      /* Solve n = M[0][0] * x + M[0][1] * y */
+      if (mpz_sgn (s) > 0)
+	{
+	  mpz_mul (x, n, s);
+	  mpz_fdiv_qr (q, x, x, M[0][1]);
+	  mpz_mul (y, q, M[0][0]);
+	  mpz_addmul (y, t, n);
+	  ASSERT_ALWAYS (mpz_sgn (y) > 0);
+	}
+      else
+	{
+	  mpz_mul (y, n, t);
+	  mpz_fdiv_qr (q, y, y, M[0][0]);
+	  mpz_mul (x, q, M[0][1]);
+	  mpz_addmul (x, s, n);
+	  ASSERT_ALWAYS (mpz_sgn (x) > 0);
+	}
+      mpz_mul (x, x, M[1][0]);
+      mpz_addmul (x, y, M[1][1]);
+
+      /* Now (x|n) has the selected large quotients */
+      answer = refmpz_legendre (x, p);
+      try_zi_zi (x, n, answer);
+    }
+  mpz_clear (p);
+  mpz_clear (n);
+  mpz_clear (q);
+  mpz_clear (g);
+  mpz_clear (s);
+  mpz_clear (t);
+  mpz_clear (x);
+  mpz_clear (y);
+  mpz_clear (bs);
+  mpz_clear (M[0][0]);
+  mpz_clear (M[0][1]);
+  mpz_clear (M[1][0]);
+  mpz_clear (M[1][1]);
+#undef COUNT
+#undef PBITS
+#undef PPOWER
+#undef MAX_QBITS
+}
+
+int
+main (int argc, char *argv[])
+{
+  tests_start ();
+
+  if (argc >= 2 && strcmp (argv[1], "-p") == 0)
+    {
+      option_pari = 1;
+
+      printf ("\
+try(a,b,answer) =\n\
+{\n\
+  if (kronecker(a,b) != answer,\n\
+    print(\"wrong at \", a, \",\", b,\n\
+      \" expected \", answer,\n\
+      \" pari says \", kronecker(a,b)))\n\
+}\n");
+    }
+
+  check_data ();
+  check_squares_zi ();
+  check_a_zero ();
+  check_jacobi_factored ();
+  check_large_quotients ();
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpz/t-lcm.c b/third_party/gmp/tests/mpz/t-lcm.c
new file mode 100644
index 0000000..1b45212
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-lcm.c
@@ -0,0 +1,184 @@
+/* Test mpz_lcm and mpz_lcm_ui.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_all (mpz_ptr want, mpz_srcptr x_orig, mpz_srcptr y_orig)
+{
+  mpz_t  got, x, y;
+  int    negx, negy, swap, inplace;
+
+  mpz_init (got);
+  mpz_init_set (x, x_orig);
+  mpz_init_set (y, y_orig);
+
+  for (swap = 0; swap < 2; swap++)
+    {
+      mpz_swap (x, y);
+
+      for (negx = 0; negx < 2; negx++)
+	{
+	  mpz_neg (x, x);
+
+	  for (negy = 0; negy < 2; negy++)
+	    {
+	      mpz_neg (y, y);
+
+	      for (inplace = 0; inplace <= 1; inplace++)
+		{
+		  if (inplace)
+		    { mpz_set (got, x); mpz_lcm (got, got, y); }
+		  else
+		    mpz_lcm (got, x, y);
+		  MPZ_CHECK_FORMAT (got);
+
+		  if (mpz_cmp (got, want) != 0)
+		    {
+		      printf ("mpz_lcm wrong, inplace=%d\n", inplace);
+		    fail:
+		      mpz_trace ("x", x);
+		      mpz_trace ("y", y);
+		      mpz_trace ("got", got);
+		      mpz_trace ("want", want);
+		      abort ();
+		    }
+
+		  if (mpz_fits_ulong_p (y))
+		    {
+		      unsigned long  yu = mpz_get_ui (y);
+		      if (inplace)
+			{ mpz_set (got, x); mpz_lcm_ui (got, got, yu); }
+		      else
+			mpz_lcm_ui (got, x, yu);
+
+		      if (mpz_cmp (got, want) != 0)
+			{
+			  printf ("mpz_lcm_ui wrong, inplace=%d\n", inplace);
+			  printf    ("yu=%lu\n", yu);
+			  goto fail;
+			}
+		    }
+		}
+	    }
+	}
+    }
+
+  mpz_clear (got);
+  mpz_clear (x);
+  mpz_clear (y);
+}
+
+
+void
+check_primes (void)
+{
+  static unsigned long  prime[] = {
+    2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,
+    101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,
+    191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,
+    281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,
+    389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,
+  };
+  mpz_t  want, x, y;
+  int    i;
+
+  mpz_init (want);
+  mpz_init (x);
+  mpz_init (y);
+
+  /* Check zeros. */
+  mpz_set_ui (want, 0);
+  mpz_set_ui (x, 1);
+  check_all (want, want, want);
+  check_all (want, want, x);
+  check_all (want, x, want);
+
+  /* New prime each time. */
+  mpz_set_ui (want, 1L);
+  for (i = 0; i < numberof (prime); i++)
+    {
+      mpz_set (x, want);
+      mpz_set_ui (y, prime[i]);
+      mpz_mul_ui (want, want, prime[i]);
+      check_all (want, x, y);
+    }
+
+  /* Old prime each time. */
+  mpz_set (x, want);
+  for (i = 0; i < numberof (prime); i++)
+    {
+      mpz_set_ui (y, prime[i]);
+      check_all (want, x, y);
+    }
+
+  /* One old, one new each time. */
+  mpz_set_ui (want, prime[0]);
+  for (i = 1; i < numberof (prime); i++)
+    {
+      mpz_set (x, want);
+      mpz_set_ui (y, prime[i] * prime[i-1]);
+      mpz_mul_ui (want, want, prime[i]);
+      check_all (want, x, y);
+    }
+
+  /* Triplets with A,B in x and B,C in y. */
+  mpz_set_ui (want, 1L);
+  mpz_set_ui (x, 1L);
+  mpz_set_ui (y, 1L);
+  for (i = 0; i+2 < numberof (prime); i += 3)
+    {
+      mpz_mul_ui (want, want, prime[i]);
+      mpz_mul_ui (want, want, prime[i+1]);
+      mpz_mul_ui (want, want, prime[i+2]);
+
+      mpz_mul_ui (x, x, prime[i]);
+      mpz_mul_ui (x, x, prime[i+1]);
+
+      mpz_mul_ui (y, y, prime[i+1]);
+      mpz_mul_ui (y, y, prime[i+2]);
+
+      check_all (want, x, y);
+    }
+
+
+  mpz_clear (want);
+  mpz_clear (x);
+  mpz_clear (y);
+}
+
+
+
+int
+main (int argc, char *argv[])
+{
+  tests_start ();
+
+  check_primes ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpz/t-limbs.c b/third_party/gmp/tests/mpz/t-limbs.c
new file mode 100644
index 0000000..6526e92
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-limbs.c
@@ -0,0 +1,232 @@
+/* Test mpz_limbs_* functions
+
+Copyright 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#define COUNT 100
+#define BITSIZE 500
+
+/* Like mpz_add. For simplicity, support positive inputs only. */
+static void
+alt_add (mpz_ptr r, mpz_srcptr a, mpz_srcptr b)
+{
+  mp_size_t an = mpz_size (a);
+  mp_size_t bn = mpz_size (b);
+  mp_ptr rp;
+
+  ASSERT (an > 0);
+  ASSERT (bn > 0);
+  if (an < bn)
+    {
+      MP_SIZE_T_SWAP (an, bn);
+      MPZ_SRCPTR_SWAP (a, b);
+    }
+  rp = mpz_limbs_modify (r, an + 1);
+  rp[an] = mpn_add (rp, mpz_limbs_read (a), an, mpz_limbs_read (b), bn);
+  mpz_limbs_finish (r, an + 1);
+}
+
+static void
+check_funcs (const char *name,
+	     void (*f)(mpz_ptr, mpz_srcptr, mpz_srcptr),
+	     void (*ref_f)(mpz_ptr, mpz_srcptr, mpz_srcptr),
+	     mpz_srcptr a, mpz_srcptr b)
+{
+  mpz_t r, ref;
+  mpz_inits (r, ref, NULL);
+
+  ref_f (ref, a, b);
+  MPZ_CHECK_FORMAT (ref);
+  f (r, a, b);
+  MPZ_CHECK_FORMAT (r);
+
+  if (mpz_cmp (r, ref) != 0)
+    {
+      printf ("%s failed, abits %u, bbits %u\n",
+	      name,
+	      (unsigned) mpz_sizeinbase (a, 2),
+	      (unsigned) mpz_sizeinbase (b, 2));
+      gmp_printf ("a = %Zx\n", a);
+      gmp_printf ("b = %Zx\n", b);
+      gmp_printf ("r = %Zx (bad)\n", r);
+      gmp_printf ("ref = %Zx\n", ref);
+      abort ();
+    }
+  mpz_clears (r, ref, NULL);
+}
+
+static void
+check_add (void)
+{
+  gmp_randstate_ptr rands = RANDS;
+  mpz_t bs, a, b;
+  unsigned i;
+  mpz_inits (bs, a, b, NULL);
+  for (i = 0; i < COUNT; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      mpz_rrandomb (a, rands, 1 + mpz_get_ui (bs) % BITSIZE);
+      mpz_urandomb (bs, rands, 32);
+      mpz_rrandomb (b, rands, 1 + mpz_get_ui (bs) % BITSIZE);
+
+      check_funcs ("add", alt_add, mpz_add, a, b);
+    }
+  mpz_clears (bs, a, b, NULL);
+}
+
+static void
+alt_mul (mpz_ptr r, mpz_srcptr a, mpz_srcptr b)
+{
+  mp_size_t an = mpz_size (a);
+  mp_size_t bn = mpz_size (b);
+  mp_srcptr ap, bp;
+  TMP_DECL;
+
+  TMP_MARK;
+
+  ASSERT (an > 0);
+  ASSERT (bn > 0);
+  if (an < bn)
+    {
+      MP_SIZE_T_SWAP (an, bn);
+      MPZ_SRCPTR_SWAP (a, b);
+    }
+  /* NOTE: This copying seems unnecessary; better to allocate new
+     result area, and free the old area when done. */
+  if (r == a)
+    {
+      mp_ptr tp =  TMP_ALLOC_LIMBS (an);
+      MPN_COPY (tp, mpz_limbs_read (a), an);
+      ap = tp;
+      bp = (a == b) ? ap : mpz_limbs_read (b);
+    }
+  else if (r == b)
+    {
+      mp_ptr tp = TMP_ALLOC_LIMBS (bn);
+      MPN_COPY (tp, mpz_limbs_read (b), bn);
+      bp = tp;
+      ap = mpz_limbs_read (a);
+    }
+  else
+    {
+      ap = mpz_limbs_read (a);
+      bp = mpz_limbs_read (b);
+    }
+  mpn_mul (mpz_limbs_write (r, an + bn),
+	   ap, an, bp, bn);
+
+  mpz_limbs_finish (r, an + bn);
+}
+
+void
+check_mul (void)
+{
+  gmp_randstate_ptr rands = RANDS;
+  mpz_t bs, a, b;
+  unsigned i;
+  mpz_inits (bs, a, b, NULL);
+  for (i = 0; i < COUNT; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      mpz_rrandomb (a, rands, 1 + mpz_get_ui (bs) % BITSIZE);
+      mpz_urandomb (bs, rands, 32);
+      mpz_rrandomb (b, rands, 1 + mpz_get_ui (bs) % BITSIZE);
+
+      check_funcs ("mul", alt_mul, mpz_mul, a, b);
+    }
+  mpz_clears (bs, a, b, NULL);
+}
+
+#define MAX_SIZE 100
+
+static void
+check_roinit (void)
+{
+  gmp_randstate_ptr rands = RANDS;
+  mpz_t bs, a, b, r, ref;
+  unsigned i;
+
+  mpz_inits (bs, a, b, r, ref, NULL);
+
+  for (i = 0; i < COUNT; i++)
+    {
+      mp_srcptr ap, bp;
+      mp_size_t an, bn;
+      mpz_urandomb (bs, rands, 32);
+      mpz_rrandomb (a, rands, 1 + mpz_get_ui (bs) % BITSIZE);
+      mpz_urandomb (bs, rands, 32);
+      mpz_rrandomb (b, rands, 1 + mpz_get_ui (bs) % BITSIZE);
+
+      an = mpz_size (a);
+      ap = mpz_limbs_read (a);
+      bn = mpz_size (b);
+      bp = mpz_limbs_read (b);
+
+      mpz_add (ref, a, b);
+      {
+	mpz_t a1, b1;
+#if __STDC_VERSION__ >= 199901
+	const mpz_t a2 = MPZ_ROINIT_N ( (mp_ptr) ap, an);
+	const mpz_t b2 = MPZ_ROINIT_N ( (mp_ptr) bp, bn);
+
+	mpz_set_ui (r, 0);
+	mpz_add (r, a2, b2);
+	if (mpz_cmp (r, ref) != 0)
+	  {
+	    printf ("MPZ_ROINIT_N failed\n");
+	    gmp_printf ("a = %Zx\n", a);
+	    gmp_printf ("b = %Zx\n", b);
+	    gmp_printf ("r = %Zx (bad)\n", r);
+	    gmp_printf ("ref = %Zx\n", ref);
+	    abort ();
+	  }
+#endif
+	mpz_set_ui (r, 0);
+	mpz_add (r, mpz_roinit_n (a1, ap, an), mpz_roinit_n (b1, bp, bn));
+	if (mpz_cmp (r, ref) != 0)
+	  {
+	    printf ("mpz_roinit_n failed\n");
+	    gmp_printf ("a = %Zx\n", a);
+	    gmp_printf ("b = %Zx\n", b);
+	    gmp_printf ("r = %Zx (bad)\n", r);
+	    gmp_printf ("ref = %Zx\n", ref);
+	    abort ();
+	  }
+      }
+    }
+  mpz_clears (bs, a, b, r, ref, NULL);
+}
+
+int
+main (int argc, char *argv[])
+{
+  tests_start ();
+  tests_end ();
+
+  check_add ();
+  check_mul ();
+  check_roinit ();
+
+  return 0;
+
+}
diff --git a/third_party/gmp/tests/mpz/t-lucm.c b/third_party/gmp/tests/mpz/t-lucm.c
new file mode 100644
index 0000000..3b6dcd1
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-lucm.c
@@ -0,0 +1,144 @@
+/* Test mpz_powm, mpz_lucas_mod.
+
+Copyright 1991, 1993, 1994, 1996, 1999-2001, 2009, 2012, 2018 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+void debug_mp (mpz_t, int);
+
+#define SIZEM 8
+
+/* FIXME: Should we implement another sequence to test lucas mod?	*/
+/* Eg: a generalisation of what we use for Fibonacci:	*/
+/* U_{2n-1} = U_n^2 - Q*U_{n-1}^2	*/
+/* U_{2n+1} = D*U_n^2  + Q*U_{2n-1} + 2*Q^n ; whith D = (P^2-4*Q)	*/
+/* P*U_{2n} = U_{2n+1} + Q*U_{2n-1}	*/
+
+int
+main (int argc, char **argv)
+{
+  mpz_t base, exp, mod;
+  mpz_t r1, r2, t1, t2;
+  mp_size_t base_size, exp_size, mod_size;
+  int i, res;
+  int reps = 1000;
+  long Q;
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long bsi, size_range;
+
+  tests_start ();
+  TESTS_REPS (reps, argv, argc);
+
+  rands = RANDS;
+
+  mpz_init (bs);
+
+  mpz_init (base);
+  mpz_init (exp);
+  mpz_init (mod);
+  mpz_init (r1);
+  mpz_init (r2);
+  mpz_init (t1);
+  mpz_init (t2);
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % SIZEM + 1;
+
+      do  /* Loop until base >= 2 and fits in a long.  */
+	{
+	  mpz_urandomb (base, rands, BITS_PER_ULONG - 2);
+	}
+      while (mpz_cmp_ui (base, 2) < 0 || mpz_fits_slong_p (base) == 0);
+
+      Q = mpz_get_ui (base);
+
+      do
+        {
+	  ++size_range;
+	  size_range = MIN (size_range, SIZEM);
+	  mpz_urandomb (bs, rands, size_range);
+	  mod_size = mpz_get_ui (bs);
+	  mpz_rrandomb (mod, rands, mod_size);
+	  mpz_add_ui (mod, mod, 16);
+	}
+      while (mpz_gcd_ui (NULL, mod, Q) != 1);
+
+      mod_size = mpz_sizeinbase (mod, 2) - 3;
+      mpz_urandomb (bs, rands, 32);
+      exp_size = mpz_get_ui (bs) % mod_size + 2;
+
+      mpz_tdiv_q_2exp (exp, mod, exp_size);
+      mpz_add_ui (exp, exp, 1);
+
+      mpz_urandomb (bs, rands, 2);
+      bsi = mpz_get_ui (bs);
+      if ((bsi & 1) != 0)
+	{
+	  mpz_neg (base, base);
+	  Q = -Q;
+	}
+
+      res = mpz_lucas_mod (t1, r2, Q, exp_size, mod, t2, r1);
+      if (res && ++reps)
+	continue;
+      MPZ_CHECK_FORMAT (r2);
+      if (mpz_cmp_ui (r2, 0) < 0)
+	mpz_add (r2, r2, mod);
+      mpz_powm (r1, base, exp, mod);
+
+      if (mpz_cmp (r1, r2) != 0)
+	{
+	  fprintf (stderr, "\nIncorrect results in test %d for operands:\n", i);
+	  debug_mp (base, -16);
+	  debug_mp (exp, -16);
+	  debug_mp (mod, -16);
+	  fprintf (stderr, "mpz_powm result:\n");
+	  debug_mp (r1, -16);
+	  fprintf (stderr, "mpz_lucas_mod result (%d) Q=%ld:\n", res, Q);
+	  debug_mp (r2, -16);
+	  abort ();
+	}
+    }
+
+  mpz_clear (bs);
+  mpz_clear (base);
+  mpz_clear (exp);
+  mpz_clear (mod);
+  mpz_clear (r1);
+  mpz_clear (r2);
+  mpz_clear (t1);
+  mpz_clear (t2);
+
+  tests_end ();
+  exit (0);
+}
+
+void
+debug_mp (mpz_t x, int base)
+{
+  mpz_out_str (stderr, base, x); fputc ('\n', stderr);
+}
diff --git a/third_party/gmp/tests/mpz/t-lucnum_ui.c b/third_party/gmp/tests/mpz/t-lucnum_ui.c
new file mode 100644
index 0000000..34c4315
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-lucnum_ui.c
@@ -0,0 +1,96 @@
+/* Test mpz_lucnum_ui and mpz_lucnum2_ui.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+/* Usage: t-lucnum_ui [n]
+
+   Test up to L[n], or if n is omitted then the default limit below.  A
+   literal "x" for the limit means continue forever, this being meant only
+   for development.  */
+
+
+void
+check_sequence (int argc, char *argv[])
+{
+  unsigned long  n;
+  unsigned long  limit = 100 * GMP_LIMB_BITS;
+  mpz_t          want_ln, want_ln1, got_ln, got_ln1;
+
+  if (argc > 1 && argv[1][0] == 'x')
+    limit = ULONG_MAX;
+  else
+    TESTS_REPS (limit, argv, argc);
+
+  /* start at n==0 */
+  mpz_init_set_si (want_ln1, -1); /* L[-1] */
+  mpz_init_set_ui (want_ln,  2);  /* L[0]   */
+  mpz_init (got_ln);
+  mpz_init (got_ln1);
+
+  for (n = 0; n < limit; n++)
+    {
+      mpz_lucnum2_ui (got_ln, got_ln1, n);
+      MPZ_CHECK_FORMAT (got_ln);
+      MPZ_CHECK_FORMAT (got_ln1);
+      if (mpz_cmp (got_ln, want_ln) != 0 || mpz_cmp (got_ln1, want_ln1) != 0)
+        {
+          printf ("mpz_lucnum2_ui(%lu) wrong\n", n);
+          mpz_trace ("want ln ", want_ln);
+          mpz_trace ("got  ln ",  got_ln);
+          mpz_trace ("want ln1", want_ln1);
+          mpz_trace ("got  ln1",  got_ln1);
+          abort ();
+        }
+
+      mpz_lucnum_ui (got_ln, n);
+      MPZ_CHECK_FORMAT (got_ln);
+      if (mpz_cmp (got_ln, want_ln) != 0)
+        {
+          printf ("mpz_lucnum_ui(%lu) wrong\n", n);
+          mpz_trace ("want ln", want_ln);
+          mpz_trace ("got  ln", got_ln);
+          abort ();
+        }
+
+      mpz_add (want_ln1, want_ln1, want_ln);  /* L[n+1] = L[n] + L[n-1] */
+      mpz_swap (want_ln1, want_ln);
+    }
+
+  mpz_clear (want_ln);
+  mpz_clear (want_ln1);
+  mpz_clear (got_ln);
+  mpz_clear (got_ln1);
+}
+
+int
+main (int argc, char *argv[])
+{
+  tests_start ();
+  mp_trace_base = -16;
+
+  check_sequence (argc, argv);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpz/t-mfac_uiui.c b/third_party/gmp/tests/mpz/t-mfac_uiui.c
new file mode 100644
index 0000000..8bca2d7
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-mfac_uiui.c
@@ -0,0 +1,135 @@
+/* Exercise mpz_mfac_uiui.
+
+Copyright 2000-2002, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+/* Usage: t-mfac_uiui [x|num]
+
+   With no arguments testing goes up to the initial value of "limit" below.
+   With a number argument tests are carried that far, or with a literal "x"
+   tests are continued without limit (this being meant only for development
+   purposes).  */
+
+#define MULTIFAC_WHEEL (2*3*11)
+#define MULTIFAC_WHEEL2 (5*13)
+
+int
+main (int argc, char *argv[])
+{
+  mpz_t ref[MULTIFAC_WHEEL], ref2[MULTIFAC_WHEEL2], res;
+  unsigned long n, j, m, m2;
+  unsigned long limit = 2222, step = 1;
+
+  tests_start ();
+
+  if (argc > 1 && argv[1][0] == 'x')
+    limit = ULONG_MAX;
+  else
+    TESTS_REPS (limit, argv, argc);
+
+  /* for small limb testing */
+  limit = MIN (limit, MP_LIMB_T_MAX);
+
+  for (m = 0; m < MULTIFAC_WHEEL; m++)
+    mpz_init_set_ui(ref [m],1);
+  for (m2 = 0; m2 < MULTIFAC_WHEEL2; m2++)
+    mpz_init_set_ui(ref2 [m2],1);
+
+  mpz_init (res);
+
+  m = 0;
+  m2 = 0;
+  for (n = 0; n <= limit;)
+    {
+      mpz_mfac_uiui (res, n, MULTIFAC_WHEEL);
+      MPZ_CHECK_FORMAT (res);
+      if (mpz_cmp (ref[m], res) != 0)
+        {
+          printf ("mpz_mfac_uiui(%lu,%d) wrong\n", n, MULTIFAC_WHEEL);
+          printf ("  got  "); mpz_out_str (stdout, 10, res); printf("\n");
+          printf ("  want "); mpz_out_str (stdout, 10, ref[m]); printf("\n");
+          abort ();
+        }
+      mpz_mfac_uiui (res, n, MULTIFAC_WHEEL2);
+      MPZ_CHECK_FORMAT (res);
+      if (mpz_cmp (ref2[m2], res) != 0)
+        {
+          printf ("mpz_mfac_uiui(%lu,%d) wrong\n", n, MULTIFAC_WHEEL2);
+          printf ("  got  "); mpz_out_str (stdout, 10, res); printf("\n");
+          printf ("  want "); mpz_out_str (stdout, 10, ref2[m2]); printf("\n");
+          abort ();
+        }
+      if (n + step <= limit)
+	for (j = 0; j < step; j++) {
+	  n++; m++; m2++;
+	  if (m >= MULTIFAC_WHEEL) m -= MULTIFAC_WHEEL;
+	  if (m2 >= MULTIFAC_WHEEL2) m2 -= MULTIFAC_WHEEL2;
+	  mpz_mul_ui (ref[m], ref[m], n); /* Compute a reference, with current library */
+	  mpz_mul_ui (ref2[m2], ref2[m2], n); /* Compute a reference, with current library */
+	}
+      else n += step;
+    }
+  mpz_fac_ui (ref[0], n);
+  mpz_mfac_uiui (res, n, 1);
+  MPZ_CHECK_FORMAT (res);
+  if (mpz_cmp (ref[0], res) != 0)
+    {
+      printf ("mpz_mfac_uiui(%lu,1) wrong\n", n);
+      printf ("  got  "); mpz_out_str (stdout, 10, res); printf("\n");
+      printf ("  want "); mpz_out_str (stdout, 10, ref[0]); printf("\n");
+      abort ();
+    }
+
+  mpz_2fac_ui (ref[0], n);
+  mpz_mfac_uiui (res, n, 2);
+  MPZ_CHECK_FORMAT (res);
+  if (mpz_cmp (ref[0], res) != 0)
+    {
+      printf ("mpz_mfac_uiui(%lu,1) wrong\n", n);
+      printf ("  got  "); mpz_out_str (stdout, 10, res); printf("\n");
+      printf ("  want "); mpz_out_str (stdout, 10, ref[0]); printf("\n");
+      abort ();
+    }
+
+  n++;
+  mpz_2fac_ui (ref[0], n);
+  mpz_mfac_uiui (res, n, 2);
+  MPZ_CHECK_FORMAT (res);
+  if (mpz_cmp (ref[0], res) != 0)
+    {
+      printf ("mpz_mfac_uiui(%lu,2) wrong\n", n);
+      printf ("  got  "); mpz_out_str (stdout, 10, res); printf("\n");
+      printf ("  want "); mpz_out_str (stdout, 10, ref[0]); printf("\n");
+      abort ();
+    }
+
+  for (m = 0; m < MULTIFAC_WHEEL; m++)
+    mpz_clear (ref[m]);
+  for (m2 = 0; m2 < MULTIFAC_WHEEL2; m2++)
+    mpz_clear (ref2[m2]);
+  mpz_clear (res);
+
+  tests_end ();
+
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpz/t-mul.c b/third_party/gmp/tests/mpz/t-mul.c
new file mode 100644
index 0000000..66e021e
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-mul.c
@@ -0,0 +1,218 @@
+/* Test mpz_cmp, mpz_mul.
+
+Copyright 1991, 1993, 1994, 1996, 1997, 2000-2004 Free Software Foundation,
+Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "longlong.h"
+#include "tests.h"
+
+void debug_mp (mpz_t);
+static void refmpz_mul (mpz_t, const mpz_t, const mpz_t);
+void dump_abort (int, const char *, mpz_t, mpz_t, mpz_t, mpz_t);
+
+#define FFT_MIN_BITSIZE 100000
+
+char *extra_fft;
+
+void
+one (int i, mpz_t multiplicand, mpz_t multiplier)
+{
+  mpz_t product, ref_product;
+
+  mpz_init (product);
+  mpz_init (ref_product);
+
+  /* Test plain multiplication comparing results against reference code.  */
+  mpz_mul (product, multiplier, multiplicand);
+  refmpz_mul (ref_product, multiplier, multiplicand);
+  if (mpz_cmp (product, ref_product))
+    dump_abort (i, "incorrect plain product",
+		multiplier, multiplicand, product, ref_product);
+
+  /* Test squaring, comparing results against plain multiplication  */
+  mpz_mul (product, multiplier, multiplier);
+  mpz_set (multiplicand, multiplier);
+  mpz_mul (ref_product, multiplier, multiplicand);
+  if (mpz_cmp (product, ref_product))
+    dump_abort (i, "incorrect square product",
+		multiplier, multiplier, product, ref_product);
+
+  mpz_clear (product);
+  mpz_clear (ref_product);
+}
+
+int
+main (int argc, char **argv)
+{
+  mpz_t op1, op2;
+  int i;
+  int fft_max_2exp;
+
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long bsi, size_range, fsize_range;
+
+  tests_start ();
+  rands = RANDS;
+
+  extra_fft = getenv ("GMP_CHECK_FFT");
+  fft_max_2exp = 0;
+  if (extra_fft != NULL)
+    fft_max_2exp = atoi (extra_fft);
+
+  if (fft_max_2exp <= 1)	/* compat with old use of GMP_CHECK_FFT */
+    fft_max_2exp = 22;		/* default limit, good for any machine */
+
+  mpz_init (bs);
+  mpz_init (op1);
+  mpz_init (op2);
+
+  fsize_range = 4 << 8;		/* a fraction 1/256 of size_range */
+  for (i = 0;; i++)
+    {
+      size_range = fsize_range >> 8;
+      fsize_range = fsize_range * 33 / 32;
+
+      if (size_range > fft_max_2exp)
+	break;
+
+      mpz_urandomb (bs, rands, size_range);
+      mpz_rrandomb (op1, rands, mpz_get_ui (bs));
+      if (i & 1)
+	mpz_urandomb (bs, rands, size_range);
+      mpz_rrandomb (op2, rands, mpz_get_ui (bs));
+
+      mpz_urandomb (bs, rands, 4);
+      bsi = mpz_get_ui (bs);
+      if ((bsi & 0x3) == 0)
+	mpz_neg (op1, op1);
+      if ((bsi & 0xC) == 0)
+	mpz_neg (op2, op2);
+
+      /* printf ("%d %d\n", SIZ (op1), SIZ (op2)); */
+      one (i, op2, op1);
+    }
+
+  for (i = -50; i < 0; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % fft_max_2exp;
+
+      mpz_urandomb (bs, rands, size_range);
+      mpz_rrandomb (op1, rands, mpz_get_ui (bs) + FFT_MIN_BITSIZE);
+      mpz_urandomb (bs, rands, size_range);
+      mpz_rrandomb (op2, rands, mpz_get_ui (bs) + FFT_MIN_BITSIZE);
+
+      /* printf ("%d: %d %d\n", i, SIZ (op1), SIZ (op2)); */
+      fflush (stdout);
+      one (-1, op2, op1);
+    }
+
+  mpz_clear (bs);
+  mpz_clear (op1);
+  mpz_clear (op2);
+
+  tests_end ();
+  exit (0);
+}
+
+static void
+refmpz_mul (mpz_t w, const mpz_t u, const mpz_t v)
+{
+  mp_size_t usize = u->_mp_size;
+  mp_size_t vsize = v->_mp_size;
+  mp_size_t wsize;
+  mp_size_t sign_product;
+  mp_ptr up, vp;
+  mp_ptr wp;
+  mp_size_t talloc;
+
+  sign_product = usize ^ vsize;
+  usize = ABS (usize);
+  vsize = ABS (vsize);
+
+  if (usize == 0 || vsize == 0)
+    {
+      SIZ (w) = 0;
+      return;
+    }
+
+  talloc = usize + vsize;
+
+  up = u->_mp_d;
+  vp = v->_mp_d;
+
+  wp = __GMP_ALLOCATE_FUNC_LIMBS (talloc);
+
+  if (usize > vsize)
+    refmpn_mul (wp, up, usize, vp, vsize);
+  else
+    refmpn_mul (wp, vp, vsize, up, usize);
+  wsize = usize + vsize;
+  wsize -= wp[wsize - 1] == 0;
+  MPZ_REALLOC (w, wsize);
+  MPN_COPY (PTR(w), wp, wsize);
+
+  SIZ(w) = sign_product < 0 ? -wsize : wsize;
+  __GMP_FREE_FUNC_LIMBS (wp, talloc);
+}
+
+void
+dump_abort (int i, const char *s,
+            mpz_t op1, mpz_t op2, mpz_t product, mpz_t ref_product)
+{
+  mp_size_t b, e;
+  fprintf (stderr, "ERROR: %s in test %d\n", s, i);
+  fprintf (stderr, "op1          = "); debug_mp (op1);
+  fprintf (stderr, "op2          = "); debug_mp (op2);
+  fprintf (stderr, "    product  = "); debug_mp (product);
+  fprintf (stderr, "ref_product  = "); debug_mp (ref_product);
+  for (b = 0; b < ABSIZ(ref_product); b++)
+    if (PTR(ref_product)[b] != PTR(product)[b])
+      break;
+  for (e = ABSIZ(ref_product) - 1; e >= 0; e--)
+    if (PTR(ref_product)[e] != PTR(product)[e])
+      break;
+  printf ("ERRORS in %ld--%ld\n", b, e);
+  abort();
+}
+
+void
+debug_mp (mpz_t x)
+{
+  size_t siz = mpz_sizeinbase (x, 16);
+
+  if (siz > 65)
+    {
+      mpz_t q;
+      mpz_init (q);
+      mpz_tdiv_q_2exp (q, x, 4 * (mpz_sizeinbase (x, 16) - 25));
+      gmp_fprintf (stderr, "%ZX...", q);
+      mpz_tdiv_r_2exp (q, x, 4 * 25);
+      gmp_fprintf (stderr, "%025ZX [%d]\n", q, (int) siz);
+      mpz_clear (q);
+    }
+  else
+    {
+      gmp_fprintf (stderr, "%ZX\n", x);
+    }
+}
diff --git a/third_party/gmp/tests/mpz/t-mul_i.c b/third_party/gmp/tests/mpz/t-mul_i.c
new file mode 100644
index 0000000..5f2dae2
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-mul_i.c
@@ -0,0 +1,134 @@
+/* Test mpz_mul_ui and mpz_mul_si.
+
+Copyright 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+mpz_t got, want, x;
+
+void
+compare_si (long y)
+{
+  if (mpz_cmp (got, want) != 0)
+    {
+      printf    ("mpz_mul_si wrong\n");
+      mpz_trace ("  x", x);
+      printf    ("  y=%ld (0x%lX)\n", y, y);
+      mpz_trace ("  got ", got);
+      mpz_trace ("  want", want);
+      abort ();
+    }
+}
+
+void
+compare_ui (unsigned long y)
+{
+  if (mpz_cmp (got, want) != 0)
+    {
+      printf    ("mpz_mul_ui wrong\n");
+      mpz_trace ("  x", x);
+      printf    ("  y=%lu (0x%lX)\n", y, y);
+      mpz_trace ("  got ", got);
+      mpz_trace ("  want", want);
+      abort ();
+    }
+}
+
+void
+check_samples (void)
+{
+  {
+    long  y;
+
+    mpz_set_ui (x, 1L);
+    y = 0;
+    mpz_mul_si (got, x, y);
+    mpz_set_si (want, y);
+    compare_si (y);
+
+    mpz_set_ui (x, 1L);
+    y = 1;
+    mpz_mul_si (got, x, y);
+    mpz_set_si (want, y);
+    compare_si (y);
+
+    mpz_set_ui (x, 1L);
+    y = -1;
+    mpz_mul_si (got, x, y);
+    mpz_set_si (want, y);
+    compare_si (y);
+
+    mpz_set_ui (x, 1L);
+    y = LONG_MIN;
+    mpz_mul_si (got, x, y);
+    mpz_set_si (want, y);
+    compare_si (y);
+
+    mpz_set_ui (x, 1L);
+    y = LONG_MAX;
+    mpz_mul_si (got, x, y);
+    mpz_set_si (want, y);
+    compare_si (y);
+  }
+
+  {
+    unsigned long y;
+
+    mpz_set_ui (x, 1L);
+    y = 0;
+    mpz_mul_ui (got, x, y);
+    mpz_set_ui (want, y);
+    compare_ui (y);
+
+    mpz_set_ui (x, 1L);
+    y = 1;
+    mpz_mul_ui (got, x, y);
+    mpz_set_ui (want, y);
+    compare_ui (y);
+
+    mpz_set_ui (x, 1L);
+    y = ULONG_MAX;
+    mpz_mul_ui (got, x, y);
+    mpz_set_ui (want, y);
+    compare_ui (y);
+  }
+}
+
+int
+main (int argc, char **argv)
+{
+  tests_start ();
+
+  mpz_init (x);
+  mpz_init (got);
+  mpz_init (want);
+
+  check_samples ();
+
+  mpz_clear (x);
+  mpz_clear (got);
+  mpz_clear (want);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpz/t-nextprime.c b/third_party/gmp/tests/mpz/t-nextprime.c
new file mode 100644
index 0000000..5607aea
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-nextprime.c
@@ -0,0 +1,232 @@
+/* Test mpz_nextprime.
+
+Copyright 2009, 2015, 2018 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+void
+refmpz_nextprime (mpz_ptr p, mpz_srcptr t)
+{
+  mpz_add_ui (p, t, 1L);
+  while (! mpz_probab_prime_p (p, 10))
+    mpz_add_ui (p, p, 1L);
+}
+
+void
+run (const char *start, int reps, const char *end, short diffs[])
+{
+  mpz_t x, y;
+  int i;
+
+  mpz_init_set_str (x, start, 0);
+  mpz_init (y);
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_nextprime (y, x);
+      mpz_sub (x, y, x);
+      if (diffs != NULL &&
+	  (! mpz_fits_sshort_p (x) || diffs[i] != (short) mpz_get_ui (x)))
+	{
+	  gmp_printf ("diff list discrepancy\n");
+	  abort ();
+	}
+      mpz_swap (x, y);
+    }
+
+  mpz_set_str (y, end, 0);
+
+  if (mpz_cmp (x, y) != 0)
+    {
+      gmp_printf ("got  %Zx\n", x);
+      gmp_printf ("want %Zx\n", y);
+      abort ();
+    }
+
+  mpz_clear (y);
+  mpz_clear (x);
+}
+
+extern short diff1[];
+extern short diff3[];
+extern short diff4[];
+extern short diff5[];
+extern short diff6[];
+
+int
+main (int argc, char **argv)
+{
+  int i;
+  int reps = 20;
+  gmp_randstate_ptr rands;
+  mpz_t bs, x, nxtp, ref_nxtp;
+  unsigned long size_range;
+
+  tests_start();
+  rands = RANDS;
+
+  run ("2", 1000, "0x1ef7", diff1);
+
+  run ("3", 1000 - 1, "0x1ef7", NULL);
+
+  run ("0x8a43866f5776ccd5b02186e90d28946aeb0ed914", 50,
+       "0x8a43866f5776ccd5b02186e90d28946aeb0eeec5", diff3);
+
+  run ("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C", 50, /* 2^148 - 148 */
+       "0x100000000000000000000000000000000010ab", diff4);
+
+  run ("0x1c2c26be55317530311facb648ea06b359b969715db83292ab8cf898d8b1b", 50,
+       "0x1c2c26be55317530311facb648ea06b359b969715db83292ab8cf898da957", diff5);
+
+  run ("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80", 50, /* 2^128 - 128 */
+       "0x10000000000000000000000000000155B", diff6);
+
+  mpz_init (bs);
+  mpz_init (x);
+  mpz_init (nxtp);
+  mpz_init (ref_nxtp);
+
+  TESTS_REPS (reps, argv, argc);
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 8 + 2; /* 0..1024 bit operands */
+
+      mpz_urandomb (bs, rands, size_range);
+      mpz_rrandomb (x, rands, mpz_get_ui (bs));
+
+/*      gmp_printf ("%ld: %Zd\n", mpz_sizeinbase (x, 2), x); */
+
+      mpz_nextprime (nxtp, x);
+      refmpz_nextprime (ref_nxtp, x);
+      if (mpz_cmp (nxtp, ref_nxtp) != 0)
+	abort ();
+    }
+
+  mpz_clear (bs);
+  mpz_clear (x);
+  mpz_clear (nxtp);
+  mpz_clear (ref_nxtp);
+
+  tests_end ();
+  return 0;
+}
+
+short diff1[] =
+{
+  1,2,2,4,2,4,2,4,6,2,6,4,2,4,6,6,
+  2,6,4,2,6,4,6,8,4,2,4,2,4,14,4,6,
+  2,10,2,6,6,4,6,6,2,10,2,4,2,12,12,4,
+  2,4,6,2,10,6,6,6,2,6,4,2,10,14,4,2,
+  4,14,6,10,2,4,6,8,6,6,4,6,8,4,8,10,
+  2,10,2,6,4,6,8,4,2,4,12,8,4,8,4,6,
+  12,2,18,6,10,6,6,2,6,10,6,6,2,6,6,4,
+  2,12,10,2,4,6,6,2,12,4,6,8,10,8,10,8,
+  6,6,4,8,6,4,8,4,14,10,12,2,10,2,4,2,
+  10,14,4,2,4,14,4,2,4,20,4,8,10,8,4,6,
+  6,14,4,6,6,8,6,12,4,6,2,10,2,6,10,2,
+  10,2,6,18,4,2,4,6,6,8,6,6,22,2,10,8,
+  10,6,6,8,12,4,6,6,2,6,12,10,18,2,4,6,
+  2,6,4,2,4,12,2,6,34,6,6,8,18,10,14,4,
+  2,4,6,8,4,2,6,12,10,2,4,2,4,6,12,12,
+  8,12,6,4,6,8,4,8,4,14,4,6,2,4,6,2,
+  6,10,20,6,4,2,24,4,2,10,12,2,10,8,6,6,
+  6,18,6,4,2,12,10,12,8,16,14,6,4,2,4,2,
+  10,12,6,6,18,2,16,2,22,6,8,6,4,2,4,8,
+  6,10,2,10,14,10,6,12,2,4,2,10,12,2,16,2,
+  6,4,2,10,8,18,24,4,6,8,16,2,4,8,16,2,
+  4,8,6,6,4,12,2,22,6,2,6,4,6,14,6,4,
+  2,6,4,6,12,6,6,14,4,6,12,8,6,4,26,18,
+  10,8,4,6,2,6,22,12,2,16,8,4,12,14,10,2,
+  4,8,6,6,4,2,4,6,8,4,2,6,10,2,10,8,
+  4,14,10,12,2,6,4,2,16,14,4,6,8,6,4,18,
+  8,10,6,6,8,10,12,14,4,6,6,2,28,2,10,8,
+  4,14,4,8,12,6,12,4,6,20,10,2,16,26,4,2,
+  12,6,4,12,6,8,4,8,22,2,4,2,12,28,2,6,
+  6,6,4,6,2,12,4,12,2,10,2,16,2,16,6,20,
+  16,8,4,2,4,2,22,8,12,6,10,2,4,6,2,6,
+  10,2,12,10,2,10,14,6,4,6,8,6,6,16,12,2,
+  4,14,6,4,8,10,8,6,6,22,6,2,10,14,4,6,
+  18,2,10,14,4,2,10,14,4,8,18,4,6,2,4,6,
+  2,12,4,20,22,12,2,4,6,6,2,6,22,2,6,16,
+  6,12,2,6,12,16,2,4,6,14,4,2,18,24,10,6,
+  2,10,2,10,2,10,6,2,10,2,10,6,8,30,10,2,
+  10,8,6,10,18,6,12,12,2,18,6,4,6,6,18,2,
+  10,14,6,4,2,4,24,2,12,6,16,8,6,6,18,16,
+  2,4,6,2,6,6,10,6,12,12,18,2,6,4,18,8,
+  24,4,2,4,6,2,12,4,14,30,10,6,12,14,6,10,
+  12,2,4,6,8,6,10,2,4,14,6,6,4,6,2,10,
+  2,16,12,8,18,4,6,12,2,6,6,6,28,6,14,4,
+  8,10,8,12,18,4,2,4,24,12,6,2,16,6,6,14,
+  10,14,4,30,6,6,6,8,6,4,2,12,6,4,2,6,
+  22,6,2,4,18,2,4,12,2,6,4,26,6,6,4,8,
+  10,32,16,2,6,4,2,4,2,10,14,6,4,8,10,6,
+  20,4,2,6,30,4,8,10,6,6,8,6,12,4,6,2,
+  6,4,6,2,10,2,16,6,20,4,12,14,28,6,20,4,
+  18,8,6,4,6,14,6,6,10,2,10,12,8,10,2,10,
+  8,12,10,24,2,4,8,6,4,8,18,10,6,6,2,6,
+  10,12,2,10,6,6,6,8,6,10,6,2,6,6,6,10,
+  8,24,6,22,2,18,4,8,10,30,8,18,4,2,10,6,
+  2,6,4,18,8,12,18,16,6,2,12,6,10,2,10,2,
+  6,10,14,4,24,2,16,2,10,2,10,20,4,2,4,8,
+  16,6,6,2,12,16,8,4,6,30,2,10,2,6,4,6,
+  6,8,6,4,12,6,8,12,4,14,12,10,24,6,12,6,
+  2,22,8,18,10,6,14,4,2,6,10,8,6,4,6,30,
+  14,10,2,12,10,2,16,2,18,24,18,6,16,18,6,2,
+  18,4,6,2,10,8,10,6,6,8,4,6,2,10,2,12,
+  4,6,6,2,12,4,14,18,4,6,20,4,8,6,4,8,
+  4,14,6,4,14,12,4,2,30,4,24,6,6,12,12,14,
+  6,4,2,4,18,6,12,8
+};
+
+short diff3[] =
+{
+  33,32,136,116,24,22,104,114,76,278,238,162,36,44,388,134,
+  130,26,312,42,138,28,24,80,138,108,270,12,330,130,98,102,
+  162,34,36,170,90,34,14,6,24,66,154,218,70,132,188,88,
+  80,82
+};
+
+short diff4[] =
+{
+  239,92,64,6,104,24,46,258,68,18,54,100,68,154,26,4,
+  38,142,168,42,18,26,286,104,136,116,40,2,28,110,52,78,
+  104,24,54,96,4,626,196,24,56,36,52,102,48,156,26,18,
+  42,40
+};
+
+short diff5[] =
+{
+  268,120,320,184,396,2,94,108,20,318,274,14,64,122,220,108,
+  18,174,6,24,348,32,64,116,268,162,20,156,28,110,52,428,
+  196,14,262,30,194,120,300,66,268,12,428,370,212,198,192,130,
+  30,80
+};
+
+short diff6[] =
+{
+  179,30,84,108,112,36,42,110,52,132,60,30,326,114,496,92,100,
+  272,36,54,90,4,2,24,40,398,150,72,60,16,8,4,80,16,2,342,112,
+  14,136,236,40,18,50,192,198,204,40,266,42,274
+};
diff --git a/third_party/gmp/tests/mpz/t-oddeven.c b/third_party/gmp/tests/mpz/t-oddeven.c
new file mode 100644
index 0000000..eedad4b
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-oddeven.c
@@ -0,0 +1,87 @@
+/* Test mpz_odd_p and mpz_even_p.
+
+Copyright 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+void
+check_data (void)
+{
+  static const struct {
+    const char  *n;
+    int          odd, even;
+  } data[] = {
+    {   "0", 0, 1 },
+    {   "1", 1, 0 },
+    {   "2", 0, 1 },
+    {   "3", 1, 0 },
+    {   "4", 0, 1 },
+
+    {  "-4", 0, 1 },
+    {  "-3", 1, 0 },
+    {  "-2", 0, 1 },
+    {  "-1", 1, 0 },
+
+    {  "0x1000000000000000000000000000000000000000000000000000", 0, 1 },
+    {  "0x1000000000000000000000000000000000000000000000000001", 1, 0 },
+    {  "0x1000000000000000000000000000000000000000000000000002", 0, 1 },
+    {  "0x1000000000000000000000000000000000000000000000000003", 1, 0 },
+
+    { "-0x1000000000000000000000000000000000000000000000000004", 0, 1 },
+    { "-0x1000000000000000000000000000000000000000000000000003", 1, 0 },
+    { "-0x1000000000000000000000000000000000000000000000000002", 0, 1 },
+    { "-0x1000000000000000000000000000000000000000000000000001", 1, 0 },
+  };
+
+  mpz_t  n;
+  int    i;
+
+  mpz_init (n);
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_set_str_or_abort (n, data[i].n, 0);
+
+      if ((mpz_odd_p (n) != 0) != data[i].odd)
+	{
+	  printf ("mpz_odd_p wrong on data[%d]\n", i);
+	  abort();
+	}
+
+      if ((mpz_even_p (n) != 0) != data[i].even)
+	{
+	  printf ("mpz_even_p wrong on data[%d]\n", i);
+	  abort();
+	}
+    }
+
+  mpz_clear (n);
+}
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_data ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpz/t-perfpow.c b/third_party/gmp/tests/mpz/t-perfpow.c
new file mode 100644
index 0000000..84f9c8e
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-perfpow.c
@@ -0,0 +1,247 @@
+/* Test mpz_perfect_power_p.
+
+   Contributed to the GNU project by Torbjorn Granlund and Martin Boij.
+
+Copyright 2008-2010, 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+struct
+{
+  const char *num_as_str;
+  char want;
+} static tests[] =
+  {
+    { "0", 1},
+    { "1", 1},
+    {"-1", 1},
+    { "2", 0},
+    {"-2", 0},
+    { "3", 0},
+    {"-3", 0},
+    { "4", 1},
+    {"-4", 0},
+    { "64", 1},
+    {"-64", 1},
+    { "128", 1},
+    {"-128", 1},
+    { "256", 1},
+    {"-256", 0},
+    { "512", 1},
+    {"-512", 1},
+    { "0x4000000", 1},
+    {"-0x4000000", 1},
+    { "0x3cab640", 1},
+    {"-0x3cab640", 0},
+    { "0x3e23840", 1},
+    {"-0x3e23840", 0},
+    { "0x3d3a7ed1", 1},
+    {"-0x3d3a7ed1", 1},
+    { "0x30a7a6000", 1},
+    {"-0x30a7a6000", 1},
+    { "0xf33e5a5a59", 1},
+    {"-0xf33e5a5a59", 0},
+    { "0xed1b1182118135d", 1},
+    {"-0xed1b1182118135d", 1},
+    { "0xe71f6eb7689cc276b2f1", 1},
+    {"-0xe71f6eb7689cc276b2f1", 0},
+    { "0x12644507fe78cf563a4b342c92e7da9fe5e99cb75a01", 1},
+    {"-0x12644507fe78cf563a4b342c92e7da9fe5e99cb75a01", 0},
+    { "0x1ff2e7c581bb0951df644885bd33f50e472b0b73a204e13cbe98fdb424d66561e4000000", 1},
+    {"-0x1ff2e7c581bb0951df644885bd33f50e472b0b73a204e13cbe98fdb424d66561e4000000", 1},
+    { "0x2b9b44db2d91a6f8165c8c7339ef73633228ea29e388592e80354e4380004aad84000000", 1},
+    {"-0x2b9b44db2d91a6f8165c8c7339ef73633228ea29e388592e80354e4380004aad84000000", 1},
+    { "0x28d5a2b8f330910a9d3cda06036ae0546442e5b1a83b26a436efea5b727bf1bcbe7e12b47d81", 1},
+    {"-0x28d5a2b8f330910a9d3cda06036ae0546442e5b1a83b26a436efea5b727bf1bcbe7e12b47d81", 1},
+    {NULL, 0}
+  };
+
+
+void
+check_tests ()
+{
+  mpz_t x;
+  int i;
+  int got, want;
+
+  mpz_init (x);
+
+  for (i = 0; tests[i].num_as_str != NULL; i++)
+    {
+      mpz_set_str (x, tests[i].num_as_str, 0);
+      got = mpz_perfect_power_p (x);
+      want = tests[i].want;
+      if (got != want)
+	{
+	  fprintf (stderr, "mpz_perfect_power_p returns %d when %d was expected\n", got, want);
+	  fprintf (stderr, "fault operand: %s\n", tests[i].num_as_str);
+	  abort ();
+	}
+    }
+
+  mpz_clear (x);
+}
+
+#define NRP 15
+
+void
+check_random (int reps)
+{
+  mpz_t n, np, temp, primes[NRP];
+  int i, j, k, unique, destroy, res;
+  unsigned long int nrprimes, primebits;
+  mp_limb_t g, exp[NRP], e;
+  gmp_randstate_ptr rands;
+
+  rands = RANDS;
+
+  mpz_init (n);
+  mpz_init (np);
+  mpz_init (temp);
+
+  for (i = 0; i < NRP; i++)
+    mpz_init (primes[i]);
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_urandomb (np, rands, 32);
+      nrprimes = mpz_get_ui (np) % NRP + 1; /* 1-NRP unique primes */
+
+      mpz_urandomb (np, rands, 32);
+      g = mpz_get_ui (np) % 32 + 2; /* gcd 2-33 */
+
+      for (j = 0; j < nrprimes;)
+	{
+	  mpz_urandomb (np, rands, 32);
+	  primebits = mpz_get_ui (np) % 100 + 3; /* 3-102 bit primes */
+	  mpz_urandomb (primes[j], rands, primebits);
+	  mpz_nextprime (primes[j], primes[j]);
+	  unique = 1;
+	  for (k = 0; k < j; k++)
+	    {
+	      if (mpz_cmp (primes[j], primes[k]) == 0)
+		{
+		  unique = 0;
+		  break;
+		}
+	    }
+	  if (unique)
+	    {
+	      mpz_urandomb (np, rands, 32);
+	      e = 371 / (10 * primebits) + mpz_get_ui (np) % 11 + 1; /* Magic constants */
+	      exp[j++] = g * e;
+	    }
+	}
+
+      if (nrprimes > 1)
+	{
+	  /* Destroy d exponents, d in [1, nrprimes - 1] */
+	  if (nrprimes == 2)
+	    {
+	      destroy = 1;
+	    }
+	  else
+	    {
+	      mpz_urandomb (np, rands, 32);
+	      destroy = mpz_get_ui (np) % (nrprimes - 2);
+	    }
+
+	  g = exp[destroy];
+	  for (k = destroy + 1; k < nrprimes; k++)
+	    g = mpn_gcd_1 (&g, 1, exp[k]);
+
+	  for (j = 0; j < destroy; j++)
+	    {
+	      mpz_urandomb (np, rands, 32);
+	      e = mpz_get_ui (np) % 50 + 1;
+	      while (mpn_gcd_1 (&g, 1, e) > 1)
+		e++;
+
+	      exp[j] = e;
+	    }
+	}
+
+      /* Compute n */
+      mpz_pow_ui (n, primes[0], exp[0]);
+      for (j = 1; j < nrprimes; j++)
+	{
+	  mpz_pow_ui (temp, primes[j], exp[j]);
+	  mpz_mul (n, n, temp);
+	}
+
+      res = mpz_perfect_power_p (n);
+
+      if (nrprimes == 1)
+	{
+	if (res == 0 && exp[0] > 1)
+	  {
+	    printf("n is a perfect power, perfpow_p disagrees\n");
+	    gmp_printf("n = %Zu\nprimes[0] = %Zu\nexp[0] = %lu\n", n, primes[0], exp[0]);
+	    abort ();
+	  }
+	else if (res == 1 && exp[0] == 1)
+	  {
+	    gmp_printf("n = %Zu\n", n);
+	    printf("n is now a prime number, but perfpow_p still believes n is a perfect power\n");
+	    abort ();
+	  }
+	}
+      else
+	{
+	  if (res == 1 && destroy != 0)
+	    {
+	      gmp_printf("n = %Zu\nn was destroyed, but perfpow_p still believes n is a perfect power\n", n);
+	      abort ();
+	    }
+	  else if (res == 0 && destroy == 0)
+	    {
+	      gmp_printf("n = %Zu\nn is a perfect power, perfpow_p disagrees\n", n);
+	      abort ();
+	    }
+	}
+    }
+
+  mpz_clear (n);
+  mpz_clear (np);
+  mpz_clear (temp);
+  for (i = 0; i < NRP; i++)
+    mpz_clear (primes[i]);
+}
+
+int
+main (int argc, char **argv)
+{
+  int n_tests;
+
+  tests_start ();
+  mp_trace_base = -16;
+
+  check_tests ();
+
+  n_tests = 500;
+  if (argc == 2)
+    n_tests = atoi (argv[1]);
+  check_random (n_tests);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpz/t-perfsqr.c b/third_party/gmp/tests/mpz/t-perfsqr.c
new file mode 100644
index 0000000..2223593
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-perfsqr.c
@@ -0,0 +1,154 @@
+/* Test mpz_perfect_square_p.
+
+Copyright 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+#include "mpn/perfsqr.h"
+
+
+/* check_modulo() exercises mpz_perfect_square_p on squares which cover each
+   possible quadratic residue to each divisor used within
+   mpn_perfect_square_p, ensuring those residues aren't incorrectly claimed
+   to be non-residues.
+
+   Each divisor is taken separately.  It's arranged that n is congruent to 0
+   modulo the other divisors, 0 of course being a quadratic residue to any
+   modulus.
+
+   The values "(j*others)^2" cover all quadratic residues mod divisor[i],
+   but in no particular order.  j is run from 1<=j<=divisor[i] so that zero
+   is excluded.  A literal n==0 doesn't reach the residue tests.  */
+
+void
+check_modulo (void)
+{
+  static const unsigned long  divisor[] = PERFSQR_DIVISORS;
+  unsigned long  i, j;
+
+  mpz_t  alldiv, others, n;
+
+  mpz_init (alldiv);
+  mpz_init (others);
+  mpz_init (n);
+
+  /* product of all divisors */
+  mpz_set_ui (alldiv, 1L);
+  for (i = 0; i < numberof (divisor); i++)
+    mpz_mul_ui (alldiv, alldiv, divisor[i]);
+
+  for (i = 0; i < numberof (divisor); i++)
+    {
+      /* product of all divisors except i */
+      mpz_set_ui (others, 1L);
+      for (j = 0; j < numberof (divisor); j++)
+        if (i != j)
+          mpz_mul_ui (others, others, divisor[j]);
+
+      for (j = 1; j <= divisor[i]; j++)
+        {
+          /* square */
+          mpz_mul_ui (n, others, j);
+          mpz_mul (n, n, n);
+          if (! mpz_perfect_square_p (n))
+            {
+              printf ("mpz_perfect_square_p got 0, want 1\n");
+              mpz_trace ("  n", n);
+              abort ();
+            }
+        }
+    }
+
+  mpz_clear (alldiv);
+  mpz_clear (others);
+  mpz_clear (n);
+}
+
+
+/* Exercise mpz_perfect_square_p compared to what mpz_sqrt says. */
+void
+check_sqrt (int reps)
+{
+  mpz_t x2, x2t, x;
+  mp_size_t x2n;
+  int res;
+  int i;
+  /* int cnt = 0; */
+  gmp_randstate_ptr rands = RANDS;
+  mpz_t bs;
+
+  mpz_init (bs);
+
+  mpz_init (x2);
+  mpz_init (x);
+  mpz_init (x2t);
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_urandomb (bs, rands, 9);
+      x2n = mpz_get_ui (bs);
+      mpz_rrandomb (x2, rands, x2n);
+      /* mpz_out_str (stdout, -16, x2); puts (""); */
+
+      res = mpz_perfect_square_p (x2);
+      mpz_sqrt (x, x2);
+      mpz_mul (x2t, x, x);
+
+      if (res != (mpz_cmp (x2, x2t) == 0))
+        {
+          printf    ("mpz_perfect_square_p and mpz_sqrt differ\n");
+          mpz_trace ("   x  ", x);
+          mpz_trace ("   x2 ", x2);
+          mpz_trace ("   x2t", x2t);
+          printf    ("   mpz_perfect_square_p %d\n", res);
+          printf    ("   mpz_sqrt             %d\n", mpz_cmp (x2, x2t) == 0);
+          abort ();
+        }
+
+      /* cnt += res != 0; */
+    }
+  /* printf ("%d/%d perfect squares\n", cnt, reps); */
+
+  mpz_clear (bs);
+  mpz_clear (x2);
+  mpz_clear (x);
+  mpz_clear (x2t);
+}
+
+
+int
+main (int argc, char **argv)
+{
+  int reps = 200000;
+
+  tests_start ();
+  mp_trace_base = -16;
+
+  if (argc == 2)
+     reps = atoi (argv[1]);
+
+  check_modulo ();
+  check_sqrt (reps);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpz/t-popcount.c b/third_party/gmp/tests/mpz/t-popcount.c
new file mode 100644
index 0000000..8952cc2
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-popcount.c
@@ -0,0 +1,167 @@
+/* Test mpz_popcount.
+
+Copyright 2001, 2005 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+
+void
+check_onebit (void)
+{
+  mpz_t          n;
+  unsigned long  i, got;
+
+  mpz_init (n);
+  for (i = 0; i < 5 * GMP_LIMB_BITS; i++)
+    {
+      mpz_setbit (n, i);
+      got = mpz_popcount (n);
+      if (got != 1)
+	{
+	  printf ("mpz_popcount wrong on single bit at %lu\n", i);
+	  printf ("   got %lu, want 1\n", got);
+	  abort();
+	}
+      mpz_clrbit (n, i);
+    }
+  mpz_clear (n);
+}
+
+
+void
+check_data (void)
+{
+  static const struct {
+    const char     *n;
+    unsigned long  want;
+  } data[] = {
+    { "-1", ~ (unsigned long) 0 },
+    { "-12345678", ~ (unsigned long) 0 },
+    { "0", 0 },
+    { "1", 1 },
+    { "3", 2 },
+    { "5", 2 },
+    { "0xFFFF", 16 },
+    { "0xFFFFFFFF", 32 },
+    { "0xFFFFFFFFFFFFFFFF", 64 },
+    { "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 128 },
+  };
+
+  unsigned long   got;
+  int    i;
+  mpz_t  n;
+
+  mpz_init (n);
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_set_str_or_abort (n, data[i].n, 0);
+      got = mpz_popcount (n);
+      if (got != data[i].want)
+	{
+	  printf ("mpz_popcount wrong at data[%d]\n", i);
+	  printf ("   n     \"%s\"\n", data[i].n);
+	  printf ("         ");   mpz_out_str (stdout, 10, n); printf ("\n");
+	  printf ("         0x"); mpz_out_str (stdout, 16, n); printf ("\n");
+	  printf ("   got   %lu\n", got);
+	  printf ("   want  %lu\n", data[i].want);
+	  abort ();
+	}
+    }
+  mpz_clear (n);
+}
+
+unsigned long
+refmpz_popcount (mpz_t arg)
+{
+  mp_size_t n, i;
+  unsigned long cnt;
+  mp_limb_t x;
+
+  n = SIZ(arg);
+  if (n < 0)
+    return ~(unsigned long) 0;
+
+  cnt = 0;
+  for (i = 0; i < n; i++)
+    {
+      x = PTR(arg)[i];
+      while (x != 0)
+	{
+	  cnt += (x & 1);
+	  x >>= 1;
+	}
+    }
+  return cnt;
+}
+
+void
+check_random (void)
+{
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  mpz_t arg;
+  unsigned long arg_size, size_range;
+  unsigned long got, ref;
+  int i;
+
+  rands = RANDS;
+
+  mpz_init (bs);
+  mpz_init (arg);
+
+  for (i = 0; i < 10000; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 11 + 2; /* 0..4096 bit operands */
+
+      mpz_urandomb (bs, rands, size_range);
+      arg_size = mpz_get_ui (bs);
+      mpz_rrandomb (arg, rands, arg_size);
+
+      got = mpz_popcount (arg);
+      ref = refmpz_popcount (arg);
+      if (got != ref)
+	{
+	  printf ("mpz_popcount wrong on random\n");
+	  printf ("         ");   mpz_out_str (stdout, 10, arg); printf ("\n");
+	  printf ("         0x"); mpz_out_str (stdout, 16, arg); printf ("\n");
+	  printf ("   got   %lu\n", got);
+	  printf ("   want  %lu\n", ref);
+	  abort ();
+	}
+    }
+  mpz_clear (arg);
+  mpz_clear (bs);
+}
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_onebit ();
+  check_data ();
+  check_random ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpz/t-pow.c b/third_party/gmp/tests/mpz/t-pow.c
new file mode 100644
index 0000000..ff41721
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-pow.c
@@ -0,0 +1,217 @@
+/* Test mpz_pow_ui and mpz_ui_pow_ui.
+
+Copyright 1997, 1999-2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_one (mpz_srcptr want, mpz_srcptr base, unsigned long exp)
+{
+  mpz_t  got;
+
+  mpz_init (got);
+
+  MPZ_CHECK_FORMAT (want);
+
+  mpz_pow_ui (got, base, exp);
+  if (mpz_cmp (got, want))
+    {
+      printf ("mpz_pow_ui wrong\n");
+      mpz_trace ("  base", base);
+      printf    ("  exp = %lu (0x%lX)\n", exp, exp);
+      mpz_trace ("  got ", got);
+      mpz_trace ("  want", want);
+      abort ();
+    }
+
+  mpz_set (got, base);
+  mpz_pow_ui (got, got, exp);
+  if (mpz_cmp (got, want))
+    {
+      printf ("mpz_pow_ui wrong\n");
+      mpz_trace ("  base", base);
+      printf    ("  exp = %lu (0x%lX)\n", exp, exp);
+      mpz_trace ("  got ", got);
+      mpz_trace ("  want", want);
+      abort ();
+    }
+
+  if (mpz_fits_ulong_p (base))
+    {
+      unsigned long  base_u = mpz_get_ui (base);
+      mpz_ui_pow_ui (got, base_u, exp);
+      if (mpz_cmp (got, want))
+	{
+	  printf    ("mpz_ui_pow_ui wrong\n");
+	  printf    ("  base=%lu (0x%lX)\n", base_u, base_u);
+	  printf    ("  exp = %lu (0x%lX)\n", exp, exp);
+	  mpz_trace ("  got ", got);
+	  mpz_trace ("  want", want);
+	  abort ();
+	}
+    }
+
+  mpz_clear (got);
+}
+
+void
+check_base (mpz_srcptr base)
+{
+  unsigned long  exp;
+  mpz_t          want;
+
+  mpz_init (want);
+  mpz_set_ui (want, 1L);
+
+  for (exp = 0; exp < 20; exp++)
+    {
+      check_one (want, base, exp);
+      mpz_mul (want, want, base);
+    }
+
+  mpz_clear (want);
+}
+
+void
+check_various (void)
+{
+  static const struct {
+    const char *base;
+  } data[] = {
+    { "0" },
+    { "1" },
+    { "2" },
+    { "3" },
+    { "4" },
+    { "5" },
+    { "6" },
+    { "10" },
+    { "15" },
+    { "16" },
+
+    { "0x1F" },
+    { "0xFF" },
+    { "0x1001" },
+    { "0xFFFF" },
+    { "0x10000001" },
+    { "0x1000000000000001" },
+
+    /* actual size closest to estimate */
+    { "0xFFFFFFFF" },
+    { "0xFFFFFFFFFFFFFFFF" },
+
+    /* same after rshift */
+    { "0xFFFFFFFF0" },
+    { "0xFFFFFFFF00" },
+    { "0xFFFFFFFFFFFFFFFF0" },
+    { "0xFFFFFFFFFFFFFFFF00" },
+
+    /* change from 2 limbs to 1 after rshift */
+    { "0x180000000" },
+    { "0x18000000000000000" },
+
+    /* change from 3 limbs to 2 after rshift */
+    { "0x18000000100000000" },
+    { "0x180000000000000010000000000000000" },
+
+    /* handling of absolute value */
+    { "-0x80000000" },
+    { "-0x8000000000000000" },
+
+    /* low zero limb, and size>2, checking argument overlap detection */
+    { "0x3000000000000000300000000000000030000000000000000" },
+  };
+
+  mpz_t  base;
+  int    i;
+
+  mpz_init (base);
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_set_str_or_abort (base, data[i].base, 0);
+      check_base (base);
+    }
+
+  mpz_clear (base);
+}
+
+void
+check_random (int reps)
+{
+  mpz_t              base, want;
+  mp_size_t          base_size;
+  int                i;
+  unsigned long      size_range, exp;
+  gmp_randstate_ptr  rands = RANDS;
+
+  mpz_init (base);
+  mpz_init (want);
+
+  for (i = 0; i < reps; i++)
+    {
+      /* exponentially random 0 to 2^13 bits for base */
+      mpz_urandomb (want, rands, 32);
+      size_range = mpz_get_ui (want) % 12 + 2;
+      mpz_urandomb (want, rands, size_range);
+      base_size = mpz_get_ui (want);
+      mpz_rrandomb (base, rands, base_size);
+
+      /* randomly signed base */
+      mpz_urandomb (want, rands, 2);
+      if ((mpz_get_ui (want) & 1) != 0)
+	mpz_neg (base, base);
+
+      /* random 5 bits for exponent */
+      mpz_urandomb (want, rands, 5L);
+      exp = mpz_get_ui (want);
+
+      refmpz_pow_ui (want, base, exp);
+      check_one (want, base, exp);
+    }
+
+  mpz_clear (base);
+  mpz_clear (want);
+}
+
+int
+main (int argc, char **argv)
+{
+  int reps = 5000;
+
+  /* dummy call to drag in refmpn.o for testing mpz/n_pow_ui.c with
+     refmpn_mul_2 */
+  refmpn_zero_p (NULL, (mp_size_t) 0);
+
+  tests_start ();
+  mp_trace_base = -16;
+
+  if (argc == 2)
+     reps = atoi (argv[1]);
+
+  check_various ();
+  check_random (reps);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpz/t-powm.c b/third_party/gmp/tests/mpz/t-powm.c
new file mode 100644
index 0000000..24e00eb
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-powm.c
@@ -0,0 +1,212 @@
+/* Test mpz_powm, mpz_mul, mpz_mod, mpz_mod_ui, mpz_div_ui.
+
+Copyright 1991, 1993, 1994, 1996, 1999-2001, 2009, 2012, 2019 Free
+Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+void debug_mp (mpz_t, int);
+
+#define SIZEM 13
+
+/* Check that all sizes up to just above MUL_TOOM22_THRESHOLD have been tested
+   a few times.  FIXME: If SIZEM is set too low, this will never happen.  */
+int
+allsizes_seen (unsigned int *allsizes)
+{
+  mp_size_t i;
+
+  for (i = 1; i < MUL_TOOM22_THRESHOLD + 4; i++)
+    if (allsizes[i] < 4)
+      return 0;
+  return 1;
+}
+
+int
+main (int argc, char **argv)
+{
+  mpz_t base, exp, mod;
+  mpz_t r1, r2, t1, exp2, base2;
+  mp_size_t base_size, exp_size, mod_size;
+  int i;
+  int reps = 1000;
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long bsi, size_range;
+  unsigned int allsizes[1 << (SIZEM + 2 - 1)];
+
+  tests_start ();
+  TESTS_REPS (reps, argv, argc);
+
+  rands = RANDS;
+
+  mpz_init (bs);
+
+  mpz_init (base);
+  mpz_init (exp);
+  mpz_init (mod);
+  mpz_init (r1);
+  mpz_init (r2);
+  mpz_init (t1);
+  mpz_init (exp2);
+  mpz_init (base2);
+
+  memset (allsizes, 0, (1 << (SIZEM + 2 - 1)) * sizeof (int));
+
+  reps += reps >> 3;
+  for (i = 0; i < reps || ! allsizes_seen (allsizes); i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % SIZEM + 2;
+
+      if ((i & 7) == 0)
+	{
+	  mpz_set_ui (exp, 1);
+
+	  do  /* Loop until mathematically well-defined.  */
+	    {
+	      mpz_urandomb (bs, rands, size_range / 2 + 2);
+	      base_size = mpz_get_ui (bs);
+	      mpz_rrandomb (base, rands, base_size);
+	    }
+	  while (mpz_cmp_ui (base, 0) == 0);
+
+	  mpz_urandomb (bs, rands, size_range / 2);
+	  mod_size = mpz_get_ui (bs);
+	  mod_size = MIN (mod_size, base_size);
+	  mpz_rrandomb (mod, rands, mod_size);
+
+	  mpz_urandomb (bs, rands, size_range);
+	  mod_size = mpz_get_ui (bs) + base_size + 2;
+	  if ((i & 8) == 0)
+	    mod_size += (GMP_NUMB_BITS - mod_size) % GMP_NUMB_BITS;
+	  mpz_setbit (mod, mod_size);
+
+	  mpz_sub (base, base, mod);
+	}
+      else
+	{
+      do  /* Loop until mathematically well-defined.  */
+	{
+	  mpz_urandomb (bs, rands, size_range);
+	  base_size = mpz_get_ui (bs);
+	  mpz_rrandomb (base, rands, base_size);
+
+	  mpz_urandomb (bs, rands, 7L);
+	  exp_size = mpz_get_ui (bs);
+	  mpz_rrandomb (exp, rands, exp_size);
+	}
+      while (mpz_cmp_ui (base, 0) == 0 && mpz_cmp_ui (exp, 0) == 0);
+
+      do
+        {
+	  mpz_urandomb (bs, rands, size_range);
+	  mod_size = mpz_get_ui (bs);
+	  mpz_rrandomb (mod, rands, mod_size);
+	}
+      while (mpz_cmp_ui (mod, 0) == 0);
+
+      allsizes[SIZ(mod)] += 1;
+
+      mpz_urandomb (bs, rands, 2);
+      bsi = mpz_get_ui (bs);
+      if ((bsi & 1) != 0)
+	mpz_neg (base, base);
+
+      /* printf ("%ld %ld %ld\n", SIZ (base), SIZ (exp), SIZ (mod)); */
+	}
+
+      mpz_set_ui (r2, 1);
+      mpz_mod (base2, base, mod);
+      mpz_set (exp2, exp);
+      mpz_mod (r2, r2, mod);
+
+      for (;;)
+	{
+	  if (mpz_tstbit (exp2, 0))
+	    {
+	      mpz_mul (r2, r2, base2);
+	      mpz_mod (r2, r2, mod);
+	    }
+	  if  (mpz_cmp_ui (exp2, 1) <= 0)
+	    break;
+	  mpz_mul (base2, base2, base2);
+	  mpz_mod (base2, base2, mod);
+	  mpz_tdiv_q_2exp (exp2, exp2, 1);
+	}
+
+      mpz_powm (r1, base, exp, mod);
+      MPZ_CHECK_FORMAT (r1);
+
+      if (mpz_cmp (r1, r2) != 0)
+	{
+	  fprintf (stderr, "\nIncorrect results in test %d for operands:\n", i);
+	  debug_mp (base, -16);
+	  debug_mp (exp, -16);
+	  debug_mp (mod, -16);
+	  fprintf (stderr, "mpz_powm result:\n");
+	  debug_mp (r1, -16);
+	  fprintf (stderr, "reference result:\n");
+	  debug_mp (r2, -16);
+	  abort ();
+	}
+
+      if (mpz_tdiv_ui (mod, 2) == 0)
+	continue;
+
+      mpz_powm_sec (r1, base, exp, mod);
+      MPZ_CHECK_FORMAT (r1);
+
+      if (mpz_cmp (r1, r2) != 0)
+	{
+	  fprintf (stderr, "\nIncorrect results in test %d for operands:\n", i);
+	  debug_mp (base, -16);
+	  debug_mp (exp, -16);
+	  debug_mp (mod, -16);
+	  fprintf (stderr, "mpz_powm_sec result:\n");
+	  debug_mp (r1, -16);
+	  fprintf (stderr, "reference result:\n");
+	  debug_mp (r2, -16);
+	  abort ();
+	}
+    }
+
+  mpz_clear (bs);
+  mpz_clear (base);
+  mpz_clear (exp);
+  mpz_clear (mod);
+  mpz_clear (r1);
+  mpz_clear (r2);
+  mpz_clear (t1);
+  mpz_clear (exp2);
+  mpz_clear (base2);
+
+  tests_end ();
+  exit (0);
+}
+
+void
+debug_mp (mpz_t x, int base)
+{
+  mpz_out_str (stderr, base, x); fputc ('\n', stderr);
+}
diff --git a/third_party/gmp/tests/mpz/t-powm_ui.c b/third_party/gmp/tests/mpz/t-powm_ui.c
new file mode 100644
index 0000000..5b446c5
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-powm_ui.c
@@ -0,0 +1,127 @@
+/* Test mpz_powm_ui, mpz_mul, mpz_mod.
+
+Copyright 1991, 1993, 1994, 1996, 1997, 2000-2002, 2013 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+int
+main (int argc, char **argv)
+{
+  mpz_t base, exp, mod;
+  mpz_t r1, r2, base2;
+  mp_size_t base_size, exp_size, mod_size;
+  unsigned long int exp2;
+  int i;
+  int reps = 100;
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long bsi, size_range;
+
+  tests_start ();
+  rands = RANDS;
+
+  TESTS_REPS (reps, argv, argc);
+
+  mpz_inits (bs, base, exp, mod, r1, r2, base2, NULL);
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 18 + 2;
+
+      do  /* Loop until mathematically well-defined.  */
+	{
+	  mpz_urandomb (bs, rands, size_range);
+	  base_size = mpz_get_ui (bs);
+	  mpz_rrandomb (base, rands, base_size);
+
+	  mpz_urandomb (bs, rands, 6L);
+	  exp_size = mpz_get_ui (bs);
+	  mpz_rrandomb (exp, rands, exp_size);
+	  exp2 = mpz_getlimbn (exp, (mp_size_t) 0);
+	}
+      while (mpz_cmp_ui (base, 0) == 0 && exp2 == 0);
+
+      do
+        {
+	  mpz_urandomb (bs, rands, size_range);
+	  mod_size = mpz_get_ui (bs);
+	  mpz_rrandomb (mod, rands, mod_size);
+	}
+      while (mpz_cmp_ui (mod, 0) == 0);
+
+      mpz_urandomb (bs, rands, 2);
+      bsi = mpz_get_ui (bs);
+      if ((bsi & 1) != 0)
+	mpz_neg (base, base);
+
+      /* printf ("%ld %ld\n", SIZ (base), SIZ (mod)); */
+
+#if 0
+      putc ('\n', stderr);
+      gmp_fprintf (stderr, "B = 0x%Zx\n", base);
+      gmp_fprintf (stderr, "M = 0x%Zx\n", mod);
+#endif
+
+      exp2 = mpz_getlimbn (exp, (mp_size_t) 0);
+      mpz_set_ui (r2, 1);
+      mpz_set (base2, base);
+      mpz_mod (r2, r2, mod);	/* needed when exp==0 and mod==1 */
+      while (exp2 != 0)
+	{
+	  if (exp2 % 2 != 0)
+	    {
+	      mpz_mul (r2, r2, base2);
+	      mpz_mod (r2, r2, mod);
+	    }
+	  mpz_mul (base2, base2, base2);
+	  mpz_mod (base2, base2, mod);
+	  exp2 = exp2 / 2;
+	}
+
+      exp2 = mpz_getlimbn (exp, (mp_size_t) 0);
+      mpz_powm_ui (r1, base, exp2, mod);
+      MPZ_CHECK_FORMAT (r1);
+
+#if 0
+      gmp_fprintf (stderr, "R   = 0x%Zx\n", r1);
+      gmp_fprintf (stderr, "REF = 0x%Zx\n", r2);
+#endif
+
+      if (mpz_cmp (r1, r2) != 0)
+	{
+	  fprintf (stderr, "\ntest %d: Incorrect results for operands:\n", i);
+	  gmp_fprintf (stderr, "B = 0x%Zx\n", base);
+	  gmp_fprintf (stderr, "E = 0x%Zx\n", exp);
+	  gmp_fprintf (stderr, "M = 0x%Zx\n", mod);
+	  gmp_fprintf (stderr, "R   = 0x%Zx\n", r1);
+	  gmp_fprintf (stderr, "REF = 0x%Zx\n", r2);
+	  abort ();
+	}
+    }
+
+  mpz_clears (bs, base, exp, mod, r1, r2, base2, NULL);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpz/t-pprime_p.c b/third_party/gmp/tests/mpz/t-pprime_p.c
new file mode 100644
index 0000000..cf23b3a
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-pprime_p.c
@@ -0,0 +1,231 @@
+/* Exercise mpz_probab_prime_p.
+
+Copyright 2002, 2018-2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+/* Enhancements:
+
+   - Test some big primes don't come back claimed to be composite.
+   - Test some big composites don't come back claimed to be certainly prime.
+   - Test some big composites with small factors are identified as certainly
+     composite.  */
+
+
+/* return 1 if prime, 0 if composite */
+int
+isprime (long n)
+{
+  long  i;
+
+  n = ABS(n);
+
+  if (n < 2)
+    return 0;
+  if (n < 4)
+    return 1;
+  if ((n & 1) == 0)
+    return 0;
+
+  for (i = 3; i*i <= n; i+=2)
+    if ((n % i) == 0)
+      return 0;
+
+  return 1;
+}
+
+void
+check_one (mpz_srcptr n, int want)
+{
+  int  got;
+
+  got = mpz_probab_prime_p (n, 25);
+
+  /* "definitely prime" is fine if we only wanted "probably prime" */
+  if (got == 2 && want == 1)
+    want = 2;
+
+  if (got != want)
+    {
+      printf ("mpz_probab_prime_p\n");
+      mpz_trace ("  n    ", n);
+      printf    ("  got =%d", got);
+      printf    ("  want=%d", want);
+      abort ();
+    }
+}
+
+void
+check_pn (mpz_ptr n, int want)
+{
+  check_one (n, want);
+  mpz_neg (n, n);
+  check_one (n, want);
+}
+
+/* expect certainty for small n */
+void
+check_small (void)
+{
+  mpz_t  n;
+  long   i;
+
+  mpz_init (n);
+
+  for (i = 0; i < 300; i++)
+    {
+      mpz_set_si (n, i);
+      check_pn (n, isprime (i));
+    }
+
+  mpz_clear (n);
+}
+
+void
+check_composites (int count)
+{
+  int i;
+  mpz_t a, b, n, bs;
+  unsigned long size_range, size;
+  gmp_randstate_ptr rands = RANDS;
+
+  mpz_init (a);
+  mpz_init (b);
+  mpz_init (n);
+  mpz_init (bs);
+
+  for (i = 0; i < count; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 13 + 1; /* 0..8192 bit operands */
+
+      mpz_urandomb (bs, rands, size_range);
+      size = mpz_get_ui (bs);
+      mpz_rrandomb (a, rands, size);
+
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 13 + 1; /* 0..8192 bit operands */
+      mpz_rrandomb (b, rands, size);
+
+      /* Exclude trivial factors */
+      if (mpz_cmp_ui (a, 1) == 0)
+	mpz_set_ui (a, 2);
+      if (mpz_cmp_ui (b, 1) == 0)
+	mpz_set_ui (b, 2);
+
+      mpz_mul (n, a, b);
+
+      check_pn (n, 0);
+    }
+  mpz_clear (a);
+  mpz_clear (b);
+  mpz_clear (n);
+  mpz_clear (bs);
+}
+
+static void
+check_primes (void)
+{
+  static const char * const primes[] = {
+    "2", "53", "1234567891",
+    "2055693949", "1125899906842597", "16412292043871650369",
+    /* diffie-hellman-group1-sha1, also "Well known group 2" in RFC
+       2412, 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 } */
+    "0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+    "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
+    "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+    "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
+    "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381"
+    "FFFFFFFFFFFFFFFF",
+    NULL
+  };
+
+  mpz_t n;
+  int i;
+
+  mpz_init (n);
+
+  for (i = 0; primes[i]; i++)
+    {
+      mpz_set_str_or_abort (n, primes[i], 0);
+      check_one (n, 1);
+    }
+  mpz_clear (n);
+}
+
+static void
+check_fermat_mersenne (int count)
+{
+  int fermat_exponents [] = {1, 2, 4, 8, 16};
+  int mersenne_exponents [] = {2, 3, 5, 7, 13, 17, 19, 31, 61, 89,
+			       107, 127, 521, 607, 1279, 2203, 2281,
+			       3217, 4253, 4423, 9689, 9941, 11213,
+			       19937, 21701, 23209, 44497, 86243};
+  mpz_t pp;
+  int i, j, want;
+
+  mpz_init (pp);
+  count = MIN (110000, count);
+
+  for (i=1; i<count; ++i)
+    {
+      mpz_set_ui (pp, 1);
+      mpz_setbit (pp, i); /* 2^i + 1 */
+      want = 0;
+      for (j = 0; j < numberof (fermat_exponents); j++)
+	if (fermat_exponents[j] == i)
+	  {
+	    want = 1;
+	    break;
+	  }
+      check_one (pp, want);
+
+      mpz_sub_ui (pp, pp, 2); /* 2^i - 1 */
+      want = 0;
+      for (j = 0; j < numberof (mersenne_exponents); j++)
+	if (mersenne_exponents[j] == i)
+	  {
+	    want = 1;
+	    break;
+	  }
+      check_one (pp, want);
+    }
+  mpz_clear (pp);
+}
+
+int
+main (int argc, char **argv)
+{
+  int count = 1000;
+
+  TESTS_REPS (count, argv, argc);
+
+  tests_start ();
+
+  check_small ();
+  check_fermat_mersenne (count >> 3);
+  check_composites (count);
+  check_primes ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpz/t-primorial_ui.c b/third_party/gmp/tests/mpz/t-primorial_ui.c
new file mode 100644
index 0000000..b4d2bfe
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-primorial_ui.c
@@ -0,0 +1,145 @@
+/* Exercise mpz_primorial_ui.
+
+Copyright 2000-2002, 2012, 2015 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+/* Usage: t-primorial_ui [x|num]
+
+   With no arguments testing goes up to the initial value of "limit" below.
+   With a number argument tests are carried that far, or with a literal "x"
+   tests are continued without limit (this being meant only for development
+   purposes).  */
+
+static int isprime (unsigned long int t);
+
+int
+main (int argc, char *argv[])
+{
+  unsigned long  n;
+  unsigned long  limit = 2222;
+  gmp_randstate_ptr rands;
+  mpz_t          f, r, bs;
+
+  tests_start ();
+  rands = RANDS;
+
+  if (argc > 1 && argv[1][0] == 'x')
+    limit = ULONG_MAX;
+  else
+    TESTS_REPS (limit, argv, argc);
+
+  /* for small limb testing */
+  limit = MIN (limit, MP_LIMB_T_MAX);
+
+  mpz_init_set_ui (f, 1);  /* 0# = 1 */
+  mpz_init (r);
+
+  n = 0;
+  do
+    {
+      mpz_primorial_ui (r, n);
+      MPZ_CHECK_FORMAT (r);
+
+      if (mpz_cmp (f, r) != 0)
+	{
+	  printf ("mpz_primorial_ui(%lu) wrong\n", n);
+	  printf ("  got  "); mpz_out_str (stdout, 10, r); printf("\n");
+	  printf ("  want "); mpz_out_str (stdout, 10, f); printf("\n");
+	  abort ();
+	}
+
+      if (isprime (++n))
+	mpz_mul_ui (f, f, n);  /* p# = (p-1)# * (p) */
+      if (n%16 == 0) { mpz_clear (r); mpz_init (r); }
+    } while (n < limit);
+
+  n = 0; limit =1;
+  mpz_init (bs);
+  do
+    {
+      unsigned long i, d;
+
+      mpz_urandomb (bs, rands, 21);
+      i = mpz_get_ui (bs);
+      mpz_urandomb (bs, rands, 9);
+      d = mpz_get_ui (bs) + 3*64;
+      mpz_primorial_ui (f, i);
+      MPZ_CHECK_FORMAT (f);
+      mpz_primorial_ui (r, i+d);
+      MPZ_CHECK_FORMAT (r);
+
+      do {
+	if (isprime (++i))
+	  mpz_mul_ui (f, f, i);
+      } while (--d != 0);
+
+      if (mpz_cmp (f, r) != 0)
+	{
+	  printf ("mpz_primorial_ui(%lu) wrong\n", i);
+	  printf ("  got  "); mpz_out_str (stdout, 10, r); printf("\n");
+	  printf ("  want "); mpz_out_str (stdout, 10, f); printf("\n");
+	  abort ();
+	}
+    } while (++n < limit);
+  /* Chech a single "big" value, modulo a larger prime */
+  n = 2095637;
+  mpz_primorial_ui (r, n);
+  mpz_set_ui (f, 13);
+  mpz_setbit (f, 64); /* f = 2^64 + 13 */
+  mpz_tdiv_r (r, r, f);
+  mpz_set_str (f, "BAFCBF3C95B217D5", 16);
+
+  if (mpz_cmp (f, r) != 0)
+    {
+      printf ("mpz_primorial_ui(%lu) wrong\n", n);
+      printf ("  got  "); mpz_out_str (stdout, 10, r); printf("\n");
+      printf ("  want "); mpz_out_str (stdout, 10, f); printf("\n");
+      abort ();
+    }
+
+  mpz_clear (bs);
+  mpz_clear (f);
+  mpz_clear (r);
+
+  tests_end ();
+
+  exit (0);
+}
+
+static int
+isprime (unsigned long int t)
+{
+  unsigned long int q, r, d;
+
+  if (t < 3 || (t & 1) == 0)
+    return t == 2;
+
+  for (d = 3, r = 1; r != 0; d += 2)
+    {
+      q = t / d;
+      r = t - q * d;
+      if (q < d)
+	return 1;
+    }
+  return 0;
+}
diff --git a/third_party/gmp/tests/mpz/t-remove.c b/third_party/gmp/tests/mpz/t-remove.c
new file mode 100644
index 0000000..07ba918
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-remove.c
@@ -0,0 +1,146 @@
+/* Test mpz_remove.
+
+Copyright 1991, 1993, 1994, 1996, 1997, 2000, 2001, 2009, 2012, 2013 Free
+Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+void debug_mp (mpz_t);
+unsigned long int mpz_refremove (mpz_t, const mpz_t, const mpz_t);
+
+int
+main (int argc, char **argv)
+{
+  unsigned long int exp;
+  mpz_t t, dest, refdest, dividend, divisor;
+  mp_size_t dividend_size, divisor_size;
+  int i;
+  int reps = 1000;
+  unsigned long int pwr, refpwr;
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long size_range;
+
+  tests_start ();
+  rands = RANDS;
+
+  if (argc == 2)
+    reps = atoi (argv[1]);
+
+  mpz_inits (bs, t, dest, refdest, dividend, divisor, NULL);
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 18 + 1; /* 1..524288 bit operands */
+
+      do
+	{
+	  mpz_urandomb (bs, rands, size_range);
+	  divisor_size = mpz_get_ui (bs);
+	  mpz_rrandomb (divisor, rands, divisor_size);
+	}
+      while (mpz_sgn (divisor) == 0);
+
+      mpz_urandomb (bs, rands, size_range);
+      dividend_size = mpz_get_ui (bs) + divisor_size;
+      mpz_rrandomb (dividend, rands, dividend_size);
+
+      mpz_urandomb (bs, rands, 32);
+      exp = mpz_get_ui (bs) % (5 + 10000 / mpz_sizeinbase (divisor, 2));
+      if (mpz_get_ui (bs) & 2)
+	mpz_neg (divisor, divisor);
+      mpz_pow_ui (t, divisor, exp);
+      mpz_mul (dividend, dividend, t);
+
+      refpwr = mpz_refremove (refdest, dividend, divisor);
+      pwr = mpz_remove (dest, dividend, divisor);
+
+      if (refpwr != pwr || mpz_cmp (refdest, dest) != 0)
+	{
+	  fprintf (stderr, "ERROR after %d tests\n", i);
+	  fprintf (stderr, "refpower = %lu\n", refpwr);
+	  fprintf (stderr, "   power = %lu\n", pwr);
+	  fprintf (stderr, "    op1 = "); debug_mp (dividend);
+	  fprintf (stderr, "    op2 = "); debug_mp (divisor);
+	  fprintf (stderr, "refdest = "); debug_mp (refdest);
+	  fprintf (stderr, "   dest = "); debug_mp (dest);
+	  abort ();
+	}
+    }
+
+  mpz_clears (bs, t, dest, refdest, dividend, divisor, NULL);
+
+  tests_end ();
+  exit (0);
+}
+
+unsigned long int
+mpz_refremove (mpz_t dest, const mpz_t src, const mpz_t f)
+{
+  unsigned long int pwr;
+
+  pwr = 0;
+
+  mpz_set (dest, src);
+  if (mpz_cmpabs_ui (f, 1) > 0)
+    {
+      mpz_t rem, x;
+
+      mpz_init (x);
+      mpz_init (rem);
+
+      for (;; pwr++)
+	{
+	  mpz_tdiv_qr (x, rem, dest, f);
+	  if (mpz_cmp_ui (rem, 0) != 0)
+	    break;
+	  mpz_swap (dest, x);
+	}
+
+      mpz_clear (x);
+      mpz_clear (rem);
+    }
+
+  return pwr;
+}
+
+void
+debug_mp (mpz_t x)
+{
+  size_t siz = mpz_sizeinbase (x, 16);
+
+  if (siz > 65)
+    {
+      mpz_t q;
+      mpz_init (q);
+      mpz_tdiv_q_2exp (q, x, 4 * (mpz_sizeinbase (x, 16) - 25));
+      gmp_fprintf (stderr, "%ZX...", q);
+      mpz_tdiv_r_2exp (q, x, 4 * 25);
+      gmp_fprintf (stderr, "%025ZX [%d]\n", q, (int) siz);
+      mpz_clear (q);
+    }
+  else
+    {
+      gmp_fprintf (stderr, "%ZX\n", x);
+    }
+}
diff --git a/third_party/gmp/tests/mpz/t-root.c b/third_party/gmp/tests/mpz/t-root.c
new file mode 100644
index 0000000..e1ce159
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-root.c
@@ -0,0 +1,174 @@
+/* Test mpz_root, mpz_rootrem, and mpz_perfect_power_p.
+
+Copyright 1991, 1993, 1994, 1996, 2000, 2001, 2009, 2015 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+void debug_mp (mpz_t, int);
+
+void
+check_one (mpz_t root1, mpz_t x2, unsigned long nth, int res, int i)
+{
+  mpz_t temp, temp2;
+  mpz_t root2, rem2;
+
+  mpz_init (root2);
+  mpz_init (rem2);
+  mpz_init (temp);
+  mpz_init (temp2);
+
+  MPZ_CHECK_FORMAT (root1);
+
+  mpz_rootrem (root2, rem2, x2, nth);
+  MPZ_CHECK_FORMAT (root2);
+  MPZ_CHECK_FORMAT (rem2);
+
+  mpz_pow_ui (temp, root1, nth);
+  MPZ_CHECK_FORMAT (temp);
+
+  mpz_add (temp2, temp, rem2);
+
+  /* Is power of result > argument?  */
+  if (mpz_cmp (root1, root2) != 0 || mpz_cmp (x2, temp2) != 0 || mpz_cmpabs (temp, x2) > 0 || res == mpz_cmp_ui (rem2, 0))
+    {
+      fprintf (stderr, "ERROR after test %d\n", i);
+      debug_mp (x2, 10);
+      debug_mp (root1, 10);
+      debug_mp (root2, 10);
+      fprintf (stderr, "nth: %lu ,res: %i\n", nth, res);
+      abort ();
+    }
+
+  if (nth > 1 && mpz_cmp_ui (temp, 1L) > 0 && ! mpz_perfect_power_p (temp))
+    {
+      fprintf (stderr, "ERROR in mpz_perfect_power_p after test %d\n", i);
+      debug_mp (temp, 10);
+      debug_mp (root1, 10);
+      fprintf (stderr, "nth: %lu\n", nth);
+      abort ();
+    }
+
+  if (nth <= 10000 && mpz_sgn(x2) > 0)		/* skip too expensive test */
+    {
+      mpz_add_ui (temp2, root1, 1L);
+      mpz_pow_ui (temp2, temp2, nth);
+      MPZ_CHECK_FORMAT (temp2);
+
+      /* Is square of (result + 1) <= argument?  */
+      if (mpz_cmp (temp2, x2) <= 0)
+	{
+	  fprintf (stderr, "ERROR after test %d\n", i);
+	  debug_mp (x2, 10);
+	  debug_mp (root1, 10);
+	  fprintf (stderr, "nth: %lu\n", nth);
+	  abort ();
+	}
+    }
+
+  mpz_clear (root2);
+  mpz_clear (rem2);
+  mpz_clear (temp);
+  mpz_clear (temp2);
+}
+
+int
+main (int argc, char **argv)
+{
+  mpz_t x2;
+  mpz_t root1;
+  mp_size_t x2_size;
+  int i, res;
+  int reps = 500;
+  unsigned long nth;
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long bsi, size_range;
+
+  tests_start ();
+  TESTS_REPS (reps, argv, argc);
+
+  rands = RANDS;
+
+  mpz_init (bs);
+
+  mpz_init (x2);
+  mpz_init (root1);
+
+  /* This triggers a gcc 4.3.2 bug */
+  mpz_set_str (x2, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80000000000000000000000000000000000000000000000000000000000000002", 16);
+  res = mpz_root (root1, x2, 2);
+  check_one (root1, x2, 2, res, -1);
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 17 + 2;
+
+      mpz_urandomb (bs, rands, size_range);
+      x2_size = mpz_get_ui (bs) + 10;
+      mpz_rrandomb (x2, rands, x2_size);
+
+      mpz_urandomb (bs, rands, 15);
+      nth = mpz_getlimbn (bs, 0) % mpz_sizeinbase (x2, 2) + 2;
+
+      res = mpz_root (root1, x2, nth);
+
+      mpz_urandomb (bs, rands, 4);
+      bsi = mpz_get_ui (bs);
+      if ((bsi & 1) != 0)
+	{
+	  /* With 50% probability, set x2 near a perfect power.  */
+	  mpz_pow_ui (x2, root1, nth);
+	  if ((bsi & 2) != 0)
+	    {
+	      mpz_sub_ui (x2, x2, bsi >> 2);
+	      mpz_abs (x2, x2);
+	    }
+	  else
+	    mpz_add_ui (x2, x2, bsi >> 2);
+	  res = mpz_root (root1, x2, nth);
+	}
+
+      check_one (root1, x2, nth, res, i);
+
+      if (((nth & 1) != 0) && ((bsi & 2) != 0))
+	{
+	  mpz_neg (x2, x2);
+	  mpz_neg (root1, root1);
+	  check_one (root1, x2, nth, res, i);
+	}
+    }
+
+  mpz_clear (bs);
+  mpz_clear (x2);
+  mpz_clear (root1);
+
+  tests_end ();
+  exit (0);
+}
+
+void
+debug_mp (mpz_t x, int base)
+{
+  mpz_out_str (stderr, base, x); fputc ('\n', stderr);
+}
diff --git a/third_party/gmp/tests/mpz/t-scan.c b/third_party/gmp/tests/mpz/t-scan.c
new file mode 100644
index 0000000..ababcfa
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-scan.c
@@ -0,0 +1,131 @@
+/* Tests of mpz_scan0 and mpz_scan1.
+
+Copyright 2000-2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+unsigned long
+refmpz_scan (mpz_srcptr z, unsigned long i, int sought)
+{
+  unsigned long  z_bits = (unsigned long) ABSIZ(z) * GMP_NUMB_BITS;
+
+  do
+    {
+      if (mpz_tstbit (z, i) == sought)
+        return i;
+      i++;
+    }
+  while (i <= z_bits);
+
+  return ULONG_MAX;
+}
+
+unsigned long
+refmpz_scan0 (mpz_srcptr z, unsigned long starting_bit)
+{
+  return refmpz_scan (z, starting_bit, 0);
+}
+
+unsigned long
+refmpz_scan1 (mpz_srcptr z, unsigned long starting_bit)
+{
+  return refmpz_scan (z, starting_bit, 1);
+}
+
+
+void
+check_ref (void)
+{
+  static const int offset[] = {
+    -2, -1, 0, 1, 2, 3
+  };
+
+  mpz_t          z;
+  int            test, neg, sought, oindex, o;
+  mp_size_t      size, isize;
+  unsigned long  start, got, want;
+
+  mpz_init (z);
+  for (test = 0; test < 5; test++)
+    {
+      for (size = 0; size < 5; size++)
+        {
+          mpz_random2 (z, size);
+
+          for (neg = 0; neg <= 1; neg++)
+            {
+              if (neg)
+                mpz_neg (z, z);
+
+              for (isize = 0; isize <= size; isize++)
+                {
+                  for (oindex = 0; oindex < numberof (offset); oindex++)
+                    {
+                      o = offset[oindex];
+                      if ((int) isize*GMP_NUMB_BITS < -o)
+                        continue;  /* start would be negative */
+
+                      start = isize*GMP_NUMB_BITS + o;
+
+                      for (sought = 0; sought <= 1; sought++)
+                        {
+                          if (sought == 0)
+                            {
+                              got = mpz_scan0 (z, start);
+                              want = refmpz_scan0 (z, start);
+                            }
+                          else
+                            {
+                              got = mpz_scan1 (z, start);
+                              want = refmpz_scan1 (z, start);
+                            }
+
+                          if (got != want)
+                            {
+                              printf ("wrong at test=%d, size=%ld, neg=%d, start=%lu, sought=%d\n",
+                                      test, size, neg, start, sought);
+                              printf ("   z 0x");
+                              mpz_out_str (stdout, -16, z);
+                              printf ("\n");
+                              printf ("   got=%lu, want=%lu\n", got, want);
+                              exit (1);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+  mpz_clear (z);
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  tests_start ();
+
+  check_ref ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpz/t-set_d.c b/third_party/gmp/tests/mpz/t-set_d.c
new file mode 100644
index 0000000..1fdfc02
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-set_d.c
@@ -0,0 +1,139 @@
+/* Test mpz_set_d and mpz_init_set_d.
+
+Copyright 2000-2003, 2006 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_data (void)
+{
+  static const struct {
+    double     d;
+    mp_size_t  want_size;
+    mp_limb_t  want_data[2];
+  } data[] = {
+
+    {  0.0,  0 },
+    {  1.0,  1, { 1 } },
+    { -1.0, -1, { 1 } },
+
+    {  123.0,  1, { 123 } },
+    { -123.0, -1, { 123 } },
+
+    { 1e-1, 0, { 0 } },
+    { -1e-1, 0, { 0 } },
+    { 2.328306436538696e-10, 0, { 0 } },
+    { -2.328306436538696e-10, 0, { 0 } },
+    { 5.421010862427522e-20, 0, { 0 } },
+    { -5.421010862427522e-20, 0, { 0 } },
+    { 2.938735877055719e-39, 0, { 0 } },
+    { -2.938735877055719e-39, 0, { 0 } },
+  };
+
+  mpz_t  z;
+  int    i;
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_init (z);
+      mpz_set_d (z, data[i].d);
+      MPZ_CHECK_FORMAT (z);
+      if (z->_mp_size != data[i].want_size
+          || refmpn_cmp_allowzero (z->_mp_d, data[i].want_data,
+                                   ABS (data[i].want_size)) != 0)
+        {
+          printf ("mpz_set_d wrong on data[%d]\n", i);
+        bad:
+          d_trace   ("  d  ", data[i].d);
+          printf    ("  got  size %ld\n", (long) z->_mp_size);
+          printf    ("  want size %ld\n", (long) data[i].want_size);
+          mpn_trace ("  got  z", z->_mp_d, z->_mp_size);
+          mpn_trace ("  want z", data[i].want_data, data[i].want_size);
+          abort();
+        }
+      mpz_clear (z);
+
+      mpz_init_set_d (z, data[i].d);
+      MPZ_CHECK_FORMAT (z);
+      if (z->_mp_size != data[i].want_size
+          || refmpn_cmp_allowzero (z->_mp_d, data[i].want_data,
+                                   ABS (data[i].want_size)) != 0)
+        {
+          printf ("mpz_init_set_d wrong on data[%d]\n", i);
+          goto bad;
+        }
+      mpz_clear (z);
+    }
+}
+
+/* Try mpz_set_d on values 2^i+1, while such a value fits a double. */
+void
+check_2n_plus_1 (void)
+{
+  volatile double  p, d, diff;
+  mpz_t  want, got;
+  int    i;
+
+  mpz_init (want);
+  mpz_init (got);
+
+  p = 1.0;
+  mpz_set_ui (want, 2L);  /* gives 3 on first step */
+
+  for (i = 1; i < 500; i++)
+    {
+      mpz_mul_2exp (want, want, 1L);
+      mpz_sub_ui (want, want, 1L);   /* want = 2^i+1 */
+
+      p *= 2.0;  /* p = 2^i */
+      d = p + 1.0;
+      diff = d - p;
+      if (diff != 1.0)
+        break;   /* rounding occurred, stop now */
+
+      mpz_set_d (got, d);
+      MPZ_CHECK_FORMAT (got);
+      if (mpz_cmp (got, want) != 0)
+        {
+          printf ("mpz_set_d wrong on 2^%d+1\n", i);
+          d_trace   ("  d ", d);
+          mpz_trace ("  got  ", got);
+          mpz_trace ("  want ", want);
+          abort ();
+        }
+    }
+
+  mpz_clear (want);
+  mpz_clear (got);
+}
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_data ();
+  check_2n_plus_1 ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpz/t-set_f.c b/third_party/gmp/tests/mpz/t-set_f.c
new file mode 100644
index 0000000..2671a86
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-set_f.c
@@ -0,0 +1,125 @@
+/* Test mpz_set_f.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_one (mpz_srcptr z)
+{
+  static const int shift[] = {
+    0, 1, GMP_LIMB_BITS, 2*GMP_LIMB_BITS, 5*GMP_LIMB_BITS
+  };
+
+  int    sh, shneg, neg;
+  mpf_t  f;
+  mpz_t  got, want;
+
+  mpf_init2 (f, mpz_sizeinbase(z,2));
+  mpz_init (got);
+  mpz_init (want);
+
+  for (sh = 0; sh < numberof(shift); sh++)
+    {
+      for (shneg = 0; shneg <= 1; shneg++)
+	{
+	  for (neg = 0; neg <= 1; neg++)
+	    {
+	      mpf_set_z (f, z);
+	      mpz_set (want, z);
+
+	      if (neg)
+		{
+		  mpf_neg (f, f);
+		  mpz_neg (want, want);
+		}
+
+	      if (shneg)
+		{
+		  mpz_tdiv_q_2exp (want, want, shift[sh]);
+		  mpf_div_2exp (f, f, shift[sh]);
+		}
+	      else
+		{
+		  mpz_mul_2exp (want, want, shift[sh]);
+		  mpf_mul_2exp (f, f, shift[sh]);
+		}
+
+	      mpz_set_f (got, f);
+	      MPZ_CHECK_FORMAT (got);
+
+	      if (mpz_cmp (got, want) != 0)
+		{
+		  printf ("wrong result\n");
+		  printf ("  shift  %d\n", shneg ? -shift[sh] : shift[sh]);
+		  printf ("  neg    %d\n", neg);
+		  mpf_trace ("     f", f);
+		  mpz_trace ("   got", got);
+		  mpz_trace ("  want", want);
+		  abort ();
+		}
+	    }
+	}
+    }
+
+  mpf_clear (f);
+  mpz_clear (got);
+  mpz_clear (want);
+}
+
+
+void
+check_various (void)
+{
+  mpz_t  z;
+
+  mpz_init (z);
+
+  mpz_set_ui (z, 0L);
+  check_one (z);
+
+  mpz_set_si (z, 123L);
+  check_one (z);
+
+  mpz_rrandomb (z, RANDS, 2*GMP_LIMB_BITS);
+  check_one (z);
+
+  mpz_rrandomb (z, RANDS, 5*GMP_LIMB_BITS);
+  check_one (z);
+
+  mpz_clear (z);
+}
+
+
+int
+main (int argc, char *argv[])
+{
+#if GMP_NAIL_BITS == 0
+  tests_start ();
+  mp_trace_base = 16;
+
+  check_various ();
+
+  tests_end ();
+#endif
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpz/t-set_si.c b/third_party/gmp/tests/mpz/t-set_si.c
new file mode 100644
index 0000000..4e8ed7a
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-set_si.c
@@ -0,0 +1,96 @@
+/* Test mpz_set_si and mpz_init_set_si.
+
+Copyright 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_data (void)
+{
+#if GMP_NUMB_BITS <= BITS_PER_ULONG
+#define ENTRY(n)   { n, { n, 0 } }
+#else
+#define ENTRY(n)   { n, { (n) & GMP_NUMB_MASK, (n) >> GMP_NUMB_BITS } }
+#endif
+
+  static const struct {
+    long       n;
+    mp_size_t  want_size;
+    mp_limb_t  want_data[2];
+  } data[] = {
+
+    {  0L,  0 },
+    {  1L,  1, { 1 } },
+    { -1L, -1, { 1 } },
+
+#if GMP_NUMB_BITS >= BITS_PER_ULONG
+    { LONG_MAX,  1, { LONG_MAX, 0 } },
+    { -LONG_MAX,  -1, { LONG_MAX, 0 } },
+    { LONG_HIGHBIT,  -1, { ULONG_HIGHBIT, 0 } },
+#else
+    { LONG_MAX,  2, { LONG_MAX & GMP_NUMB_MASK, LONG_MAX >> GMP_NUMB_BITS } },
+    { -LONG_MAX,  -2, { LONG_MAX & GMP_NUMB_MASK, LONG_MAX >> GMP_NUMB_BITS }},
+    { LONG_HIGHBIT,  -2, { 0, ULONG_HIGHBIT >> GMP_NUMB_BITS } },
+#endif
+  };
+
+  mpz_t  n;
+  int    i;
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      mpz_init (n);
+      mpz_set_si (n, data[i].n);
+      MPZ_CHECK_FORMAT (n);
+      if (n->_mp_size != data[i].want_size
+          || refmpn_cmp_allowzero (n->_mp_d, data[i].want_data,
+                                   ABS (data[i].want_size)) != 0)
+        {
+          printf ("mpz_set_si wrong on data[%d]\n", i);
+          abort();
+        }
+      mpz_clear (n);
+
+      mpz_init_set_si (n, data[i].n);
+      MPZ_CHECK_FORMAT (n);
+      if (n->_mp_size != data[i].want_size
+          || refmpn_cmp_allowzero (n->_mp_d, data[i].want_data,
+                                   ABS (data[i].want_size)) != 0)
+        {
+          printf ("mpz_init_set_si wrong on data[%d]\n", i);
+          abort();
+        }
+      mpz_clear (n);
+    }
+}
+
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_data ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpz/t-set_str.c b/third_party/gmp/tests/mpz/t-set_str.c
new file mode 100644
index 0000000..22d36d3
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-set_str.c
@@ -0,0 +1,108 @@
+/* Test mpz_set_str.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+check_one (mpz_srcptr want, int fail, int base, const char *str)
+{
+  mpz_t   got;
+
+  MPZ_CHECK_FORMAT (want);
+  mp_trace_base = (base == 0 ? 16 : base);
+
+  mpz_init (got);
+
+  if (mpz_set_str (got, str, base) != fail)
+    {
+      printf ("mpz_set_str unexpectedly failed\n");
+      printf ("  base %d\n", base);
+      printf ("  str  \"%s\"\n", str);
+      abort ();
+    }
+  MPZ_CHECK_FORMAT (got);
+
+  if (fail == 0 && mpz_cmp (got, want) != 0)
+    {
+      printf ("mpz_set_str wrong\n");
+      printf ("  base %d\n", base);
+      printf ("  str  \"%s\"\n", str);
+      mpz_trace ("got ", got);
+      mpz_trace ("want", want);
+      abort ();
+    }
+
+  mpz_clear (got);
+}
+
+void
+check_samples (void)
+{
+  mpz_t  z;
+
+  mpz_init (z);
+
+  mpz_set_ui (z, 0L);
+  check_one (z, 0, 0, "0 ");
+  check_one (z, 0, 0, " 0 0 0 ");
+  check_one (z, 0, 0, " -0B 0 ");
+  check_one (z, 0, 0, "  0X 0 ");
+  check_one (z, 0, 10, "0 ");
+  check_one (z, 0, 10, "-0   ");
+  check_one (z, 0, 10, " 0 000 000    ");
+
+  mpz_set_ui (z, 123L);
+  check_one (z, 0, 0, "123 ");
+  check_one (z, 0, 0, "123    ");
+  check_one (z, 0, 0, "0173   ");
+  check_one (z, 0, 0, " 0b 1 11 10 11  ");
+  check_one (z, 0, 0, " 0x 7b ");
+  check_one (z, 0, 0, "0x7B");
+  check_one (z, 0, 10, "123 ");
+  check_one (z, 0, 10, "123    ");
+  check_one (z, 0, 0, " 123 ");
+  check_one (z, 0, 0, "  123    ");
+  check_one (z, 0, 10, "  0000123 ");
+  check_one (z, 0, 10, "  123    ");
+  check_one (z,-1, 10, "1%");
+  check_one (z,-1, 0, "3!");
+  check_one (z,-1, 0, "0123456789");
+  check_one (z,-1, 0, "13579BDF");
+  check_one (z,-1, 0, "0b0102");
+  check_one (z,-1, 0, "0x010G");
+  check_one (z,-1, 37,"0x010G");
+  check_one (z,-1, 99,"0x010G");
+
+  mpz_clear (z);
+}
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_samples ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpz/t-sizeinbase.c b/third_party/gmp/tests/mpz/t-sizeinbase.c
new file mode 100644
index 0000000..936f2bd
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-sizeinbase.c
@@ -0,0 +1,89 @@
+/* Test mpz_sizeinbase.
+
+Copyright 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+#if 0
+  /* Disabled due to the bogosity of trying to fake an _mp_d pointer to
+     below an object.  Has been seen to fail on a hppa system and on ia64.  */
+
+
+/* Create a fake mpz consisting of just a single 1 bit, with totbits being
+   the total number of bits, inclusive of that 1 bit.  */
+void
+mpz_fake_bits (mpz_ptr z, unsigned long totbits)
+{
+  static mp_limb_t  n;
+  unsigned long     zero_bits, zero_limbs;
+
+  zero_bits = totbits - 1;
+  zero_limbs = zero_bits / GMP_NUMB_BITS;
+  zero_bits %= GMP_NUMB_BITS;
+
+  SIZ(z) = zero_limbs + 1;
+  PTR(z) = (&n) - (SIZ(z) - 1);
+  n = CNST_LIMB(1) << zero_bits;
+
+  ASSERT_ALWAYS (mpz_sizeinbase (z, 2) == totbits);
+}
+
+
+/* This was seen to fail on a GNU/Linux powerpc32 with gcc 2.95.2,
+   apparently due to a doubtful value of mp_bases[10].chars_per_bit_exactly
+   (0X1.34413509F79FDP-2 whereas 0X1.34413509F79FFP-2 is believed correct).
+   Presumably this is a glibc problem when gcc converts the decimal string
+   in mp_bases.c, or maybe it's only a function of the rounding mode during
+   compilation.  */
+void
+check_sample (void)
+{
+  unsigned long  totbits = 198096465;
+  int        base = 10;
+  size_t     want = 59632979;
+  size_t     got;
+  mpz_t      z;
+
+  mpz_fake_bits (z, totbits);
+  got = mpz_sizeinbase (z, base);
+  if (got != want)
+    {
+      printf ("mpz_sizeinbase\n");
+      printf ("  base    %d\n",  base);
+      printf ("  totbits %lu\n", totbits);
+      printf ("  got     %u\n",  got);
+      printf ("  want    %u\n",  want);
+      abort ();
+    }
+}
+#endif
+
+int
+main (void)
+{
+  tests_start ();
+
+  /* check_sample (); */
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/mpz/t-sqrtrem.c b/third_party/gmp/tests/mpz/t-sqrtrem.c
new file mode 100644
index 0000000..9db8a61
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-sqrtrem.c
@@ -0,0 +1,122 @@
+/* Test mpz_add, mpz_add_ui, mpz_cmp, mpz_cmp, mpz_mul, mpz_sqrtrem.
+
+Copyright 1991, 1993, 1994, 1996, 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+void dump_abort (mpz_t, mpz_t, mpz_t);
+void debug_mp (mpz_t, int);
+
+int
+main (int argc, char **argv)
+{
+  mpz_t x2;
+  mpz_t x, rem;
+  mpz_t temp, temp2;
+  mp_size_t x2_size;
+  int i;
+  int reps = 1000;
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long size_range;
+
+  tests_start ();
+  TESTS_REPS (reps, argv, argc);
+
+  rands = RANDS;
+
+  mpz_init (bs);
+
+  mpz_init (x2);
+  mpz_init (x);
+  mpz_init (rem);
+  mpz_init (temp);
+  mpz_init (temp2);
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 17 + 2; /* 0..262144 bit operands */
+
+      mpz_urandomb (bs, rands, size_range);
+      x2_size = mpz_get_ui (bs);
+      mpz_rrandomb (x2, rands, x2_size);
+
+      /* printf ("%ld\n", SIZ (x2)); */
+
+      mpz_sqrt (temp, x2);
+      MPZ_CHECK_FORMAT (temp);
+
+      mpz_sqrtrem (x, rem, x2);
+      MPZ_CHECK_FORMAT (x);
+      MPZ_CHECK_FORMAT (rem);
+
+      /* Are results different?  */
+      if (mpz_cmp (temp, x) != 0)
+	dump_abort (x2, x, rem);
+
+      mpz_mul (temp, x, x);
+
+      /* Is square of result > argument?  */
+      if (mpz_cmp (temp, x2) > 0)
+	dump_abort (x2, x, rem);
+
+      mpz_add_ui (temp2, x, 1);
+      mpz_mul (temp2, temp2, temp2);
+
+      /* Is square of (result + 1) <= argument?  */
+      if (mpz_cmp (temp2, x2) <= 0)
+	dump_abort (x2, x, rem);
+
+      mpz_add (temp2, temp, rem);
+
+      /* Is the remainder wrong?  */
+      if (mpz_cmp (x2, temp2) != 0)
+	dump_abort (x2, x, rem);
+    }
+
+  mpz_clear (bs);
+  mpz_clear (x2);
+  mpz_clear (x);
+  mpz_clear (rem);
+  mpz_clear (temp);
+  mpz_clear (temp2);
+
+  tests_end ();
+  exit (0);
+}
+
+void
+dump_abort (mpz_t x2, mpz_t x, mpz_t rem)
+{
+  fprintf (stderr, "ERROR\n");
+  fprintf (stderr, "x2        = "); debug_mp (x2, -16);
+  fprintf (stderr, "x         = "); debug_mp (x, -16);
+  fprintf (stderr, "remainder = "); debug_mp (rem, -16);
+  abort();
+}
+
+void
+debug_mp (mpz_t x, int base)
+{
+  mpz_out_str (stderr, base, x); fputc ('\n', stderr);
+}
diff --git a/third_party/gmp/tests/mpz/t-tdiv.c b/third_party/gmp/tests/mpz/t-tdiv.c
new file mode 100644
index 0000000..3d2eb36
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-tdiv.c
@@ -0,0 +1,145 @@
+/* Test mpz_abs, mpz_add, mpz_cmp, mpz_cmp_ui, mpz_tdiv_qr, mpz_tdiv_q,
+   mpz_tdiv_r, mpz_mul.
+
+Copyright 1991, 1993, 1994, 1996, 1997, 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+void dump_abort (mpz_t, mpz_t);
+void debug_mp (mpz_t, int);
+
+int
+main (int argc, char **argv)
+{
+  mpz_t dividend, divisor;
+  mpz_t quotient, remainder;
+  mpz_t quotient2, remainder2;
+  mpz_t temp;
+  mp_size_t dividend_size, divisor_size;
+  int i;
+  int reps = 1000;
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long bsi, size_range;
+
+  tests_start ();
+  TESTS_REPS (reps, argv, argc);
+
+  rands = RANDS;
+
+  mpz_init (bs);
+
+  mpz_init (dividend);
+  mpz_init (divisor);
+  mpz_init (quotient);
+  mpz_init (remainder);
+  mpz_init (quotient2);
+  mpz_init (remainder2);
+  mpz_init (temp);
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 18 + 2; /* 0..524288 bit operands */
+
+      do
+	{
+	  mpz_urandomb (bs, rands, size_range);
+	  divisor_size = mpz_get_ui (bs);
+	  mpz_rrandomb (divisor, rands, divisor_size);
+	}
+      while (mpz_sgn (divisor) == 0);
+
+      mpz_urandomb (bs, rands, size_range);
+      dividend_size = mpz_get_ui (bs) + divisor_size;
+      mpz_rrandomb (dividend, rands, dividend_size);
+
+      mpz_urandomb (bs, rands, 2);
+      bsi = mpz_get_ui (bs);
+      if ((bsi & 1) != 0)
+	mpz_neg (dividend, dividend);
+      if ((bsi & 2) != 0)
+	mpz_neg (divisor, divisor);
+
+      /* printf ("%ld %ld\n", SIZ (dividend), SIZ (divisor)); */
+
+      mpz_tdiv_qr (quotient, remainder, dividend, divisor);
+      mpz_tdiv_q (quotient2, dividend, divisor);
+      mpz_tdiv_r (remainder2, dividend, divisor);
+
+      /* First determine that the quotients and remainders computed
+	 with different functions are equal.  */
+      if (mpz_cmp (quotient, quotient2) != 0)
+	dump_abort (dividend, divisor);
+      if (mpz_cmp (remainder, remainder2) != 0)
+	dump_abort (dividend, divisor);
+
+      /* Check if the sign of the quotient is correct.  */
+      if (mpz_cmp_ui (quotient, 0) != 0)
+	if ((mpz_cmp_ui (quotient, 0) < 0)
+	    != ((mpz_cmp_ui (dividend, 0) ^ mpz_cmp_ui (divisor, 0)) < 0))
+	dump_abort (dividend, divisor);
+
+      /* Check if the remainder has the same sign as the dividend
+	 (quotient rounded towards 0).  */
+      if (mpz_cmp_ui (remainder, 0) != 0)
+	if ((mpz_cmp_ui (remainder, 0) < 0) != (mpz_cmp_ui (dividend, 0) < 0))
+	  dump_abort (dividend, divisor);
+
+      mpz_mul (temp, quotient, divisor);
+      mpz_add (temp, temp, remainder);
+      if (mpz_cmp (temp, dividend) != 0)
+	dump_abort (dividend, divisor);
+
+      mpz_abs (temp, divisor);
+      mpz_abs (remainder, remainder);
+      if (mpz_cmp (remainder, temp) >= 0)
+	dump_abort (dividend, divisor);
+    }
+
+  mpz_clear (bs);
+  mpz_clear (dividend);
+  mpz_clear (divisor);
+  mpz_clear (quotient);
+  mpz_clear (remainder);
+  mpz_clear (quotient2);
+  mpz_clear (remainder2);
+  mpz_clear (temp);
+
+  tests_end ();
+  exit (0);
+}
+
+void
+dump_abort (mpz_t dividend, mpz_t divisor)
+{
+  fprintf (stderr, "ERROR\n");
+  fprintf (stderr, "dividend = "); debug_mp (dividend, -16);
+  fprintf (stderr, "divisor  = "); debug_mp (divisor, -16);
+  abort();
+}
+
+void
+debug_mp (mpz_t x, int base)
+{
+  mpz_out_str (stderr, base, x); fputc ('\n', stderr);
+}
diff --git a/third_party/gmp/tests/mpz/t-tdiv_ui.c b/third_party/gmp/tests/mpz/t-tdiv_ui.c
new file mode 100644
index 0000000..6bbb947
--- /dev/null
+++ b/third_party/gmp/tests/mpz/t-tdiv_ui.c
@@ -0,0 +1,158 @@
+/* Test mpz_abs, mpz_add, mpz_cmp, mpz_cmp_ui, mpz_tdiv_qr_ui, mpz_tdiv_q_ui,
+   mpz_tdiv_r_ui, mpz_tdiv_ui, mpz_mul_ui.
+
+Copyright 1993, 1994, 1996, 2000-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+void dump_abort (const char *, mpz_t, unsigned long);
+void debug_mp (mpz_t, int);
+
+int
+main (int argc, char **argv)
+{
+  mpz_t dividend;
+  mpz_t quotient, remainder;
+  mpz_t quotient2, remainder2;
+  mpz_t temp;
+  mp_size_t dividend_size;
+  unsigned long divisor;
+  int i;
+  int reps = 200000;
+  gmp_randstate_ptr rands;
+  mpz_t bs;
+  unsigned long bsi, size_range;
+  unsigned long r_rq, r_q, r_r, r;
+
+  tests_start ();
+  rands = RANDS;
+
+  mpz_init (bs);
+
+  if (argc == 2)
+     reps = atoi (argv[1]);
+
+  mpz_init (dividend);
+  mpz_init (quotient);
+  mpz_init (remainder);
+  mpz_init (quotient2);
+  mpz_init (remainder2);
+  mpz_init (temp);
+
+  for (i = 0; i < reps; i++)
+    {
+      mpz_urandomb (bs, rands, 32);
+      size_range = mpz_get_ui (bs) % 10 + 2; /* 0..2047 bit operands */
+
+      do
+	{
+	  mpz_rrandomb (bs, rands, 64);
+	  divisor = mpz_get_ui (bs);
+	}
+      while (divisor == 0);
+
+      mpz_urandomb (bs, rands, size_range);
+      dividend_size = mpz_get_ui (bs);
+      mpz_rrandomb (dividend, rands, dividend_size);
+
+      mpz_urandomb (bs, rands, 2);
+      bsi = mpz_get_ui (bs);
+      if ((bsi & 1) != 0)
+	mpz_neg (dividend, dividend);
+
+      /* printf ("%ld\n", SIZ (dividend)); */
+
+      r_rq = mpz_tdiv_qr_ui (quotient, remainder, dividend, divisor);
+      r_q = mpz_tdiv_q_ui (quotient2, dividend, divisor);
+      r_r = mpz_tdiv_r_ui (remainder2, dividend, divisor);
+      r = mpz_tdiv_ui (dividend, divisor);
+
+      /* First determine that the quotients and remainders computed
+	 with different functions are equal.  */
+      if (mpz_cmp (quotient, quotient2) != 0)
+	dump_abort ("quotients from mpz_tdiv_qr_ui and mpz_tdiv_q_ui differ",
+		    dividend, divisor);
+      if (mpz_cmp (remainder, remainder2) != 0)
+	dump_abort ("remainders from mpz_tdiv_qr_ui and mpz_tdiv_r_ui differ",
+		    dividend, divisor);
+
+      /* Check if the sign of the quotient is correct.  */
+      if (mpz_cmp_ui (quotient, 0) != 0)
+	if ((mpz_cmp_ui (quotient, 0) < 0)
+	    != (mpz_cmp_ui (dividend, 0) < 0))
+	dump_abort ("quotient sign wrong", dividend, divisor);
+
+      /* Check if the remainder has the same sign as the dividend
+	 (quotient rounded towards 0).  */
+      if (mpz_cmp_ui (remainder, 0) != 0)
+	if ((mpz_cmp_ui (remainder, 0) < 0) != (mpz_cmp_ui (dividend, 0) < 0))
+	  dump_abort ("remainder sign wrong", dividend, divisor);
+
+      mpz_mul_ui (temp, quotient, divisor);
+      mpz_add (temp, temp, remainder);
+      if (mpz_cmp (temp, dividend) != 0)
+	dump_abort ("n mod d != n - [n/d]*d", dividend, divisor);
+
+      mpz_abs (remainder, remainder);
+      if (mpz_cmp_ui (remainder, divisor) >= 0)
+	dump_abort ("remainder greater than divisor", dividend, divisor);
+
+      if (mpz_cmp_ui (remainder, r_rq) != 0)
+	dump_abort ("remainder returned from mpz_tdiv_qr_ui is wrong",
+		    dividend, divisor);
+      if (mpz_cmp_ui (remainder, r_q) != 0)
+	dump_abort ("remainder returned from mpz_tdiv_q_ui is wrong",
+		    dividend, divisor);
+      if (mpz_cmp_ui (remainder, r_r) != 0)
+	dump_abort ("remainder returned from mpz_tdiv_r_ui is wrong",
+		    dividend, divisor);
+      if (mpz_cmp_ui (remainder, r) != 0)
+	dump_abort ("remainder returned from mpz_tdiv_ui is wrong",
+		    dividend, divisor);
+    }
+
+  mpz_clear (bs);
+  mpz_clear (dividend);
+  mpz_clear (quotient);
+  mpz_clear (remainder);
+  mpz_clear (quotient2);
+  mpz_clear (remainder2);
+  mpz_clear (temp);
+
+  tests_end ();
+  exit (0);
+}
+
+void
+dump_abort (const char *str, mpz_t dividend, unsigned long divisor)
+{
+  fprintf (stderr, "ERROR: %s\n", str);
+  fprintf (stderr, "dividend = "); debug_mp (dividend, -16);
+  fprintf (stderr, "divisor  = %lX\n", divisor);
+  abort();
+}
+
+void
+debug_mp (mpz_t x, int base)
+{
+  mpz_out_str (stderr, base, x); fputc ('\n', stderr);
+}
diff --git a/third_party/gmp/tests/rand/Makefile.am b/third_party/gmp/tests/rand/Makefile.am
new file mode 100644
index 0000000..71bb7a9
--- /dev/null
+++ b/third_party/gmp/tests/rand/Makefile.am
@@ -0,0 +1,90 @@
+## Process this file with automake to generate Makefile.in
+
+# Copyright 2000-2003 Free Software Foundation, Inc.
+#
+# This file is part of the GNU MP Library test suite.
+#
+# The GNU MP Library test suite is free software; you can redistribute it
+# and/or modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 3 of the License,
+# or (at your option) any later version.
+#
+# The GNU MP Library test suite is distributed in the hope that it will be
+# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.
+
+
+AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/tests
+AM_LDFLAGS = -no-install
+LDADD = $(top_builddir)/tests/libtests.la $(top_builddir)/libgmp.la
+
+check_PROGRAMS = t-iset t-lc2exp t-mt t-rand t-urbui t-urmui t-urndmm
+TESTS = $(check_PROGRAMS)
+
+EXTRA_PROGRAMS = findlc gen gen.static spect stat
+gen_static_SOURCES = gen.c
+gen_static_LDFLAGS = -static
+findlc_LDADD = libstat.la
+spect_LDADD = libstat.la
+stat_LDADD = libstat.la
+
+EXTRA_LTLIBRARIES = libstat.la
+libstat_la_SOURCES = gmpstat.h statlib.c zdiv_round.c
+libstat_la_LIBADD = $(top_builddir)/libgmp.la $(LIBM)
+
+CLEANFILES = $(EXTRA_PROGRAMS) $(EXTRA_LTLIBRARIES)
+
+allprogs: $(EXTRA_PROGRAMS)
+
+$(top_builddir)/tests/libtests.la:
+	cd $(top_builddir)/tests; $(MAKE) $(AM_MAKEFLAGS) libtests.la
+
+manual-test: gen$(EXEEXT) stat$(EXEEXT)
+	@(echo -n '16i: '; ./gen -f mpz_urandomb -z 16 1000 \
+		| ./stat -i 0xffff | grep '^[0-9]')
+	@(echo -n '32i: '; ./gen -f mpz_urandomb -z 32 1000 \
+		| ./stat -i 0xffffffff  | grep '^[0-9]')
+	@(echo -n '33i: '; ./gen -f mpz_urandomb -z 33 1000 \
+		| ./stat -i 0x1ffffffff  | grep '^[0-9]')
+	@(echo -n '64i: '; ./gen -f mpz_urandomb -z 64 1000 \
+		| ./stat -i 0xffffffffffffffff  | grep '^[0-9]')
+	@(echo -n '128i: '; ./gen -f mpz_urandomb -z 128 1000 \
+		| ./stat -i 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF | grep '^[0-9]')
+
+	@(echo -n '16f: '; ./gen -f mpf_urandomb -z 16 1000 \
+		| ./stat | grep '^[0-9]')
+	@(echo -n '32f: '; ./gen -f mpf_urandomb -z 32 1000 \
+		| ./stat | grep '^[0-9]')
+	@(echo -n '33f: '; ./gen -f mpf_urandomb -z 33 1000 \
+		| ./stat | grep '^[0-9]')
+	@(echo -n '64f: '; ./gen -f mpf_urandomb -z 64 1000 \
+		| ./stat | grep '^[0-9]')
+	@(echo -n '128f: '; ./gen -f mpf_urandomb -z 128 1000 \
+		| ./stat | grep '^[0-9]')
+
+manual-bigtest: gen$(EXEEXT) stat$(EXEEXT)
+	@(echo '16i: '; ./gen -f mpz_urandomb -z 16 50000 \
+		| ./stat -2 1000 -i 0xffff | grep '^K[mp]')
+	@(echo '32i: '; ./gen -f mpz_urandomb -z 32 50000 \
+		| ./stat -2 1000 -i 0xffffffff | grep '^K[mp]')
+	@(echo '33i: '; ./gen -f mpz_urandomb -z 33 50000 \
+		| ./stat -2 1000 -i 0x1ffffffff | grep '^K[mp]')
+	@(echo '64i: '; ./gen -f mpz_urandomb -z 64 50000 \
+		| ./stat -2 1000 -i 0xffffffffffffffff  | grep '^K[mp]')
+	@(echo '128i: '; ./gen -f mpz_urandomb -z 128 50000 \
+		| ./stat -2 1000 -i 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF | grep '^K[mp]')
+
+	@(echo '16f: '; ./gen -f mpf_urandomb -z 16 50000 \
+		| ./stat -2 1000 | grep '^K[mp]')
+	@(echo '32f: '; ./gen -f mpf_urandomb -z 32 50000 \
+		| ./stat -2 1000 | grep '^K[mp]')
+	@(echo '33f: '; ./gen -f mpf_urandomb -z 33 50000 \
+		| ./stat -2 1000 | grep '^K[mp]')
+	@(echo '64f: '; ./gen -f mpf_urandomb -z 64 50000 \
+		| ./stat -2 1000 | grep '^K[mp]')
+	@(echo '128f: '; ./gen -f mpf_urandomb -z 128 50000 \
+		| ./stat -2 1000 | grep '^K[mp]')
diff --git a/third_party/gmp/tests/rand/Makefile.in b/third_party/gmp/tests/rand/Makefile.in
new file mode 100644
index 0000000..ee61406
--- /dev/null
+++ b/third_party/gmp/tests/rand/Makefile.in
@@ -0,0 +1,1215 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Copyright 2000-2003 Free Software Foundation, Inc.
+#
+# This file is part of the GNU MP Library test suite.
+#
+# The GNU MP Library test suite is free software; you can redistribute it
+# and/or modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 3 of the License,
+# or (at your option) any later version.
+#
+# The GNU MP Library test suite is distributed in the hope that it will be
+# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+check_PROGRAMS = t-iset$(EXEEXT) t-lc2exp$(EXEEXT) t-mt$(EXEEXT) \
+	t-rand$(EXEEXT) t-urbui$(EXEEXT) t-urmui$(EXEEXT) \
+	t-urndmm$(EXEEXT)
+EXTRA_PROGRAMS = findlc$(EXEEXT) gen$(EXEEXT) gen.static$(EXEEXT) \
+	spect$(EXEEXT) stat$(EXEEXT)
+subdir = tests/rand
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__DEPENDENCIES_1 =
+libstat_la_DEPENDENCIES = $(top_builddir)/libgmp.la \
+	$(am__DEPENDENCIES_1)
+am_libstat_la_OBJECTS = statlib.lo zdiv_round.lo
+libstat_la_OBJECTS = $(am_libstat_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+findlc_SOURCES = findlc.c
+findlc_OBJECTS = findlc.$(OBJEXT)
+findlc_DEPENDENCIES = libstat.la
+gen_SOURCES = gen.c
+gen_OBJECTS = gen.$(OBJEXT)
+gen_LDADD = $(LDADD)
+gen_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+am_gen_static_OBJECTS = gen.$(OBJEXT)
+gen_static_OBJECTS = $(am_gen_static_OBJECTS)
+gen_static_LDADD = $(LDADD)
+gen_static_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+gen_static_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(gen_static_LDFLAGS) $(LDFLAGS) -o $@
+spect_SOURCES = spect.c
+spect_OBJECTS = spect.$(OBJEXT)
+spect_DEPENDENCIES = libstat.la
+stat_SOURCES = stat.c
+stat_OBJECTS = stat.$(OBJEXT)
+stat_DEPENDENCIES = libstat.la
+t_iset_SOURCES = t-iset.c
+t_iset_OBJECTS = t-iset.$(OBJEXT)
+t_iset_LDADD = $(LDADD)
+t_iset_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_lc2exp_SOURCES = t-lc2exp.c
+t_lc2exp_OBJECTS = t-lc2exp.$(OBJEXT)
+t_lc2exp_LDADD = $(LDADD)
+t_lc2exp_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_mt_SOURCES = t-mt.c
+t_mt_OBJECTS = t-mt.$(OBJEXT)
+t_mt_LDADD = $(LDADD)
+t_mt_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_rand_SOURCES = t-rand.c
+t_rand_OBJECTS = t-rand.$(OBJEXT)
+t_rand_LDADD = $(LDADD)
+t_rand_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_urbui_SOURCES = t-urbui.c
+t_urbui_OBJECTS = t-urbui.$(OBJEXT)
+t_urbui_LDADD = $(LDADD)
+t_urbui_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_urmui_SOURCES = t-urmui.c
+t_urmui_OBJECTS = t-urmui.$(OBJEXT)
+t_urmui_LDADD = $(LDADD)
+t_urmui_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+t_urndmm_SOURCES = t-urndmm.c
+t_urndmm_OBJECTS = t-urndmm.$(OBJEXT)
+t_urndmm_LDADD = $(LDADD)
+t_urndmm_DEPENDENCIES = $(top_builddir)/tests/libtests.la \
+	$(top_builddir)/libgmp.la
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp =
+am__depfiles_maybe =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+SOURCES = $(libstat_la_SOURCES) findlc.c gen.c $(gen_static_SOURCES) \
+	spect.c stat.c t-iset.c t-lc2exp.c t-mt.c t-rand.c t-urbui.c \
+	t-urmui.c t-urndmm.c
+DIST_SOURCES = $(libstat_la_SOURCES) findlc.c gen.c \
+	$(gen_static_SOURCES) spect.c stat.c t-iset.c t-lc2exp.c \
+	t-mt.c t-rand.c t-urbui.c t-urmui.c t-urndmm.c
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__tty_colors_dummy = \
+  mgn= red= grn= lgn= blu= brg= std=; \
+  am__color_tests=no
+am__tty_colors = { \
+  $(am__tty_colors_dummy); \
+  if test "X$(AM_COLOR_TESTS)" = Xno; then \
+    am__color_tests=no; \
+  elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+    am__color_tests=yes; \
+  elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+    am__color_tests=yes; \
+  fi; \
+  if test $$am__color_tests = yes; then \
+    red=''; \
+    grn=''; \
+    lgn=''; \
+    blu=''; \
+    mgn=''; \
+    brg=''; \
+    std=''; \
+  fi; \
+}
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+  test -z "$$files" \
+    || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+    || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+         $(am__cd) "$$dir" && rm -f $$files; }; \
+  }
+am__recheck_rx = ^[ 	]*:recheck:[ 	]*
+am__global_test_result_rx = ^[ 	]*:global-test-result:[ 	]*
+am__copy_in_global_log_rx = ^[ 	]*:copy-in-global-log:[ 	]*
+# A command that, given a newline-separated list of test names on the
+# standard input, print the name of the tests that are to be re-run
+# upon "make recheck".
+am__list_recheck_tests = $(AWK) '{ \
+  recheck = 1; \
+  while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+    { \
+      if (rc < 0) \
+        { \
+          if ((getline line2 < ($$0 ".log")) < 0) \
+	    recheck = 0; \
+          break; \
+        } \
+      else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \
+        { \
+          recheck = 0; \
+          break; \
+        } \
+      else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \
+        { \
+          break; \
+        } \
+    }; \
+  if (recheck) \
+    print $$0; \
+  close ($$0 ".trs"); \
+  close ($$0 ".log"); \
+}'
+# A command that, given a newline-separated list of test names on the
+# standard input, create the global log from their .trs and .log files.
+am__create_global_log = $(AWK) ' \
+function fatal(msg) \
+{ \
+  print "fatal: making $@: " msg | "cat >&2"; \
+  exit 1; \
+} \
+function rst_section(header) \
+{ \
+  print header; \
+  len = length(header); \
+  for (i = 1; i <= len; i = i + 1) \
+    printf "="; \
+  printf "\n\n"; \
+} \
+{ \
+  copy_in_global_log = 1; \
+  global_test_result = "RUN"; \
+  while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+    { \
+      if (rc < 0) \
+         fatal("failed to read from " $$0 ".trs"); \
+      if (line ~ /$(am__global_test_result_rx)/) \
+        { \
+          sub("$(am__global_test_result_rx)", "", line); \
+          sub("[ 	]*$$", "", line); \
+          global_test_result = line; \
+        } \
+      else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \
+        copy_in_global_log = 0; \
+    }; \
+  if (copy_in_global_log) \
+    { \
+      rst_section(global_test_result ": " $$0); \
+      while ((rc = (getline line < ($$0 ".log"))) != 0) \
+      { \
+        if (rc < 0) \
+          fatal("failed to read from " $$0 ".log"); \
+        print line; \
+      }; \
+      printf "\n"; \
+    }; \
+  close ($$0 ".trs"); \
+  close ($$0 ".log"); \
+}'
+# Restructured Text title.
+am__rst_title = { sed 's/.*/   &   /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; }
+# Solaris 10 'make', and several other traditional 'make' implementations,
+# pass "-e" to $(SHELL), and POSIX 2008 even requires this.  Work around it
+# by disabling -e (using the XSI extension "set +e") if it's set.
+am__sh_e_setup = case $$- in *e*) set +e;; esac
+# Default flags passed to test drivers.
+am__common_driver_flags = \
+  --color-tests "$$am__color_tests" \
+  --enable-hard-errors "$$am__enable_hard_errors" \
+  --expect-failure "$$am__expect_failure"
+# To be inserted before the command running the test.  Creates the
+# directory for the log if needed.  Stores in $dir the directory
+# containing $f, in $tst the test, in $log the log.  Executes the
+# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and
+# passes TESTS_ENVIRONMENT.  Set up options for the wrapper that
+# will run the test scripts (or their associated LOG_COMPILER, if
+# thy have one).
+am__check_pre = \
+$(am__sh_e_setup);					\
+$(am__vpath_adj_setup) $(am__vpath_adj)			\
+$(am__tty_colors);					\
+srcdir=$(srcdir); export srcdir;			\
+case "$@" in						\
+  */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;;	\
+    *) am__odir=.;; 					\
+esac;							\
+test "x$$am__odir" = x"." || test -d "$$am__odir" 	\
+  || $(MKDIR_P) "$$am__odir" || exit $$?;		\
+if test -f "./$$f"; then dir=./;			\
+elif test -f "$$f"; then dir=;				\
+else dir="$(srcdir)/"; fi;				\
+tst=$$dir$$f; log='$@'; 				\
+if test -n '$(DISABLE_HARD_ERRORS)'; then		\
+  am__enable_hard_errors=no; 				\
+else							\
+  am__enable_hard_errors=yes; 				\
+fi; 							\
+case " $(XFAIL_TESTS) " in				\
+  *[\ \	]$$f[\ \	]* | *[\ \	]$$dir$$f[\ \	]*) \
+    am__expect_failure=yes;;				\
+  *)							\
+    am__expect_failure=no;;				\
+esac; 							\
+$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT)
+# A shell command to get the names of the tests scripts with any registered
+# extension removed (i.e., equivalently, the names of the test logs, with
+# the '.log' extension removed).  The result is saved in the shell variable
+# '$bases'.  This honors runtime overriding of TESTS and TEST_LOGS.  Sadly,
+# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)",
+# since that might cause problem with VPATH rewrites for suffix-less tests.
+# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'.
+am__set_TESTS_bases = \
+  bases='$(TEST_LOGS)'; \
+  bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \
+  bases=`echo $$bases`
+RECHECK_LOGS = $(TEST_LOGS)
+AM_RECURSIVE_TARGETS = check recheck
+TEST_SUITE_LOG = test-suite.log
+TEST_EXTENSIONS = @EXEEXT@ .test
+LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS)
+am__set_b = \
+  case '$@' in \
+    */*) \
+      case '$*' in \
+        */*) b='$*';; \
+          *) b=`echo '$@' | sed 's/\.log$$//'`; \
+       esac;; \
+    *) \
+      b='$*';; \
+  esac
+am__test_logs1 = $(TESTS:=.log)
+am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log)
+TEST_LOGS = $(am__test_logs2:.test.log=.log)
+TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \
+	$(TEST_LOG_FLAGS)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/test-driver
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ABI = @ABI@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+ASMFLAGS = @ASMFLAGS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CALLING_CONVENTIONS_OBJS = @CALLING_CONVENTIONS_OBJS@
+CC = @CC@
+CCAS = @CCAS@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPP_FOR_BUILD = @CPP_FOR_BUILD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFN_LONG_LONG_LIMB = @DEFN_LONG_LONG_LIMB@
+DEFS = @DEFS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@
+FGREP = @FGREP@
+GMP_LDFLAGS = @GMP_LDFLAGS@
+GMP_LIMB_BITS = @GMP_LIMB_BITS@
+GMP_NAIL_BITS = @GMP_NAIL_BITS@
+GREP = @GREP@
+HAVE_CLOCK_01 = @HAVE_CLOCK_01@
+HAVE_CPUTIME_01 = @HAVE_CPUTIME_01@
+HAVE_GETRUSAGE_01 = @HAVE_GETRUSAGE_01@
+HAVE_GETTIMEOFDAY_01 = @HAVE_GETTIMEOFDAY_01@
+HAVE_HOST_CPU_FAMILY_power = @HAVE_HOST_CPU_FAMILY_power@
+HAVE_HOST_CPU_FAMILY_powerpc = @HAVE_HOST_CPU_FAMILY_powerpc@
+HAVE_SIGACTION_01 = @HAVE_SIGACTION_01@
+HAVE_SIGALTSTACK_01 = @HAVE_SIGALTSTACK_01@
+HAVE_SIGSTACK_01 = @HAVE_SIGSTACK_01@
+HAVE_STACK_T_01 = @HAVE_STACK_T_01@
+HAVE_SYS_RESOURCE_H_01 = @HAVE_SYS_RESOURCE_H_01@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCURSES = @LIBCURSES@
+LIBGMPXX_LDFLAGS = @LIBGMPXX_LDFLAGS@
+LIBGMP_DLL = @LIBGMP_DLL@
+LIBGMP_LDFLAGS = @LIBGMP_LDFLAGS@
+LIBM = @LIBM@
+LIBM_FOR_BUILD = @LIBM_FOR_BUILD@
+LIBOBJS = @LIBOBJS@
+LIBREADLINE = @LIBREADLINE@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+M4 = @M4@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPEED_CYCLECOUNTER_OBJ = @SPEED_CYCLECOUNTER_OBJ@
+STRIP = @STRIP@
+TAL_OBJECT = @TAL_OBJECT@
+TUNE_LIBS = @TUNE_LIBS@
+TUNE_SQR_OBJ = @TUNE_SQR_OBJ@
+U_FOR_BUILD = @U_FOR_BUILD@
+VERSION = @VERSION@
+WITH_READLINE_01 = @WITH_READLINE_01@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__leading_dot = @am__leading_dot@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gmp_srclinks = @gmp_srclinks@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+mpn_objects = @mpn_objects@
+mpn_objs_in_libgmp = @mpn_objs_in_libgmp@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/tests
+AM_LDFLAGS = -no-install
+LDADD = $(top_builddir)/tests/libtests.la $(top_builddir)/libgmp.la
+TESTS = $(check_PROGRAMS)
+gen_static_SOURCES = gen.c
+gen_static_LDFLAGS = -static
+findlc_LDADD = libstat.la
+spect_LDADD = libstat.la
+stat_LDADD = libstat.la
+EXTRA_LTLIBRARIES = libstat.la
+libstat_la_SOURCES = gmpstat.h statlib.c zdiv_round.c
+libstat_la_LIBADD = $(top_builddir)/libgmp.la $(LIBM)
+CLEANFILES = $(EXTRA_PROGRAMS) $(EXTRA_LTLIBRARIES)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .log .o .obj .test .test$(EXEEXT) .trs
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu --ignore-deps tests/rand/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu --ignore-deps tests/rand/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+libstat.la: $(libstat_la_OBJECTS) $(libstat_la_DEPENDENCIES) $(EXTRA_libstat_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(LINK)  $(libstat_la_OBJECTS) $(libstat_la_LIBADD) $(LIBS)
+
+clean-checkPROGRAMS:
+	@list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
+	echo " rm -f" $$list; \
+	rm -f $$list || exit $$?; \
+	test -n "$(EXEEXT)" || exit 0; \
+	list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+	echo " rm -f" $$list; \
+	rm -f $$list
+
+findlc$(EXEEXT): $(findlc_OBJECTS) $(findlc_DEPENDENCIES) $(EXTRA_findlc_DEPENDENCIES) 
+	@rm -f findlc$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(findlc_OBJECTS) $(findlc_LDADD) $(LIBS)
+
+gen$(EXEEXT): $(gen_OBJECTS) $(gen_DEPENDENCIES) $(EXTRA_gen_DEPENDENCIES) 
+	@rm -f gen$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(gen_OBJECTS) $(gen_LDADD) $(LIBS)
+
+gen.static$(EXEEXT): $(gen_static_OBJECTS) $(gen_static_DEPENDENCIES) $(EXTRA_gen_static_DEPENDENCIES) 
+	@rm -f gen.static$(EXEEXT)
+	$(AM_V_CCLD)$(gen_static_LINK) $(gen_static_OBJECTS) $(gen_static_LDADD) $(LIBS)
+
+spect$(EXEEXT): $(spect_OBJECTS) $(spect_DEPENDENCIES) $(EXTRA_spect_DEPENDENCIES) 
+	@rm -f spect$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(spect_OBJECTS) $(spect_LDADD) $(LIBS)
+
+stat$(EXEEXT): $(stat_OBJECTS) $(stat_DEPENDENCIES) $(EXTRA_stat_DEPENDENCIES) 
+	@rm -f stat$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(stat_OBJECTS) $(stat_LDADD) $(LIBS)
+
+t-iset$(EXEEXT): $(t_iset_OBJECTS) $(t_iset_DEPENDENCIES) $(EXTRA_t_iset_DEPENDENCIES) 
+	@rm -f t-iset$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_iset_OBJECTS) $(t_iset_LDADD) $(LIBS)
+
+t-lc2exp$(EXEEXT): $(t_lc2exp_OBJECTS) $(t_lc2exp_DEPENDENCIES) $(EXTRA_t_lc2exp_DEPENDENCIES) 
+	@rm -f t-lc2exp$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_lc2exp_OBJECTS) $(t_lc2exp_LDADD) $(LIBS)
+
+t-mt$(EXEEXT): $(t_mt_OBJECTS) $(t_mt_DEPENDENCIES) $(EXTRA_t_mt_DEPENDENCIES) 
+	@rm -f t-mt$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_mt_OBJECTS) $(t_mt_LDADD) $(LIBS)
+
+t-rand$(EXEEXT): $(t_rand_OBJECTS) $(t_rand_DEPENDENCIES) $(EXTRA_t_rand_DEPENDENCIES) 
+	@rm -f t-rand$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_rand_OBJECTS) $(t_rand_LDADD) $(LIBS)
+
+t-urbui$(EXEEXT): $(t_urbui_OBJECTS) $(t_urbui_DEPENDENCIES) $(EXTRA_t_urbui_DEPENDENCIES) 
+	@rm -f t-urbui$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_urbui_OBJECTS) $(t_urbui_LDADD) $(LIBS)
+
+t-urmui$(EXEEXT): $(t_urmui_OBJECTS) $(t_urmui_DEPENDENCIES) $(EXTRA_t_urmui_DEPENDENCIES) 
+	@rm -f t-urmui$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_urmui_OBJECTS) $(t_urmui_LDADD) $(LIBS)
+
+t-urndmm$(EXEEXT): $(t_urndmm_OBJECTS) $(t_urndmm_DEPENDENCIES) $(EXTRA_t_urndmm_DEPENDENCIES) 
+	@rm -f t-urndmm$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(t_urndmm_OBJECTS) $(t_urndmm_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+.c.o:
+	$(AM_V_CC)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+	$(AM_V_CC)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+	$(AM_V_CC)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+# Recover from deleted '.trs' file; this should ensure that
+# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create
+# both 'foo.log' and 'foo.trs'.  Break the recipe in two subshells
+# to avoid problems with "make -n".
+.log.trs:
+	rm -f $< $@
+	$(MAKE) $(AM_MAKEFLAGS) $<
+
+# Leading 'am--fnord' is there to ensure the list of targets does not
+# expand to empty, as could happen e.g. with make check TESTS=''.
+am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck)
+am--force-recheck:
+	@:
+
+$(TEST_SUITE_LOG): $(TEST_LOGS)
+	@$(am__set_TESTS_bases); \
+	am__f_ok () { test -f "$$1" && test -r "$$1"; }; \
+	redo_bases=`for i in $$bases; do \
+	              am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \
+	            done`; \
+	if test -n "$$redo_bases"; then \
+	  redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \
+	  redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \
+	  if $(am__make_dryrun); then :; else \
+	    rm -f $$redo_logs && rm -f $$redo_results || exit 1; \
+	  fi; \
+	fi; \
+	if test -n "$$am__remaking_logs"; then \
+	  echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \
+	       "recursion detected" >&2; \
+	elif test -n "$$redo_logs"; then \
+	  am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \
+	fi; \
+	if $(am__make_dryrun); then :; else \
+	  st=0;  \
+	  errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \
+	  for i in $$redo_bases; do \
+	    test -f $$i.trs && test -r $$i.trs \
+	      || { echo "$$errmsg $$i.trs" >&2; st=1; }; \
+	    test -f $$i.log && test -r $$i.log \
+	      || { echo "$$errmsg $$i.log" >&2; st=1; }; \
+	  done; \
+	  test $$st -eq 0 || exit 1; \
+	fi
+	@$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \
+	ws='[ 	]'; \
+	results=`for b in $$bases; do echo $$b.trs; done`; \
+	test -n "$$results" || results=/dev/null; \
+	all=`  grep "^$$ws*:test-result:"           $$results | wc -l`; \
+	pass=` grep "^$$ws*:test-result:$$ws*PASS"  $$results | wc -l`; \
+	fail=` grep "^$$ws*:test-result:$$ws*FAIL"  $$results | wc -l`; \
+	skip=` grep "^$$ws*:test-result:$$ws*SKIP"  $$results | wc -l`; \
+	xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \
+	xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \
+	error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \
+	if test `expr $$fail + $$xpass + $$error` -eq 0; then \
+	  success=true; \
+	else \
+	  success=false; \
+	fi; \
+	br='==================='; br=$$br$$br$$br$$br; \
+	result_count () \
+	{ \
+	    if test x"$$1" = x"--maybe-color"; then \
+	      maybe_colorize=yes; \
+	    elif test x"$$1" = x"--no-color"; then \
+	      maybe_colorize=no; \
+	    else \
+	      echo "$@: invalid 'result_count' usage" >&2; exit 4; \
+	    fi; \
+	    shift; \
+	    desc=$$1 count=$$2; \
+	    if test $$maybe_colorize = yes && test $$count -gt 0; then \
+	      color_start=$$3 color_end=$$std; \
+	    else \
+	      color_start= color_end=; \
+	    fi; \
+	    echo "$${color_start}# $$desc $$count$${color_end}"; \
+	}; \
+	create_testsuite_report () \
+	{ \
+	  result_count $$1 "TOTAL:" $$all   "$$brg"; \
+	  result_count $$1 "PASS: " $$pass  "$$grn"; \
+	  result_count $$1 "SKIP: " $$skip  "$$blu"; \
+	  result_count $$1 "XFAIL:" $$xfail "$$lgn"; \
+	  result_count $$1 "FAIL: " $$fail  "$$red"; \
+	  result_count $$1 "XPASS:" $$xpass "$$red"; \
+	  result_count $$1 "ERROR:" $$error "$$mgn"; \
+	}; \
+	{								\
+	  echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" |	\
+	    $(am__rst_title);						\
+	  create_testsuite_report --no-color;				\
+	  echo;								\
+	  echo ".. contents:: :depth: 2";				\
+	  echo;								\
+	  for b in $$bases; do echo $$b; done				\
+	    | $(am__create_global_log);					\
+	} >$(TEST_SUITE_LOG).tmp || exit 1;				\
+	mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG);			\
+	if $$success; then						\
+	  col="$$grn";							\
+	 else								\
+	  col="$$red";							\
+	  test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG);		\
+	fi;								\
+	echo "$${col}$$br$${std}"; 					\
+	echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}";	\
+	echo "$${col}$$br$${std}"; 					\
+	create_testsuite_report --maybe-color;				\
+	echo "$$col$$br$$std";						\
+	if $$success; then :; else					\
+	  echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}";		\
+	  if test -n "$(PACKAGE_BUGREPORT)"; then			\
+	    echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}";	\
+	  fi;								\
+	  echo "$$col$$br$$std";					\
+	fi;								\
+	$$success || exit 1
+
+check-TESTS:
+	@list='$(RECHECK_LOGS)';           test -z "$$list" || rm -f $$list
+	@list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list
+	@test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+	@set +e; $(am__set_TESTS_bases); \
+	log_list=`for i in $$bases; do echo $$i.log; done`; \
+	trs_list=`for i in $$bases; do echo $$i.trs; done`; \
+	log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \
+	$(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \
+	exit $$?;
+recheck: all $(check_PROGRAMS)
+	@test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+	@set +e; $(am__set_TESTS_bases); \
+	bases=`for i in $$bases; do echo $$i; done \
+	         | $(am__list_recheck_tests)` || exit 1; \
+	log_list=`for i in $$bases; do echo $$i.log; done`; \
+	log_list=`echo $$log_list`; \
+	$(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \
+	        am__force_recheck=am--force-recheck \
+	        TEST_LOGS="$$log_list"; \
+	exit $$?
+t-iset.log: t-iset$(EXEEXT)
+	@p='t-iset$(EXEEXT)'; \
+	b='t-iset'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-lc2exp.log: t-lc2exp$(EXEEXT)
+	@p='t-lc2exp$(EXEEXT)'; \
+	b='t-lc2exp'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-mt.log: t-mt$(EXEEXT)
+	@p='t-mt$(EXEEXT)'; \
+	b='t-mt'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-rand.log: t-rand$(EXEEXT)
+	@p='t-rand$(EXEEXT)'; \
+	b='t-rand'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-urbui.log: t-urbui$(EXEEXT)
+	@p='t-urbui$(EXEEXT)'; \
+	b='t-urbui'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-urmui.log: t-urmui$(EXEEXT)
+	@p='t-urmui$(EXEEXT)'; \
+	b='t-urmui'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+t-urndmm.log: t-urndmm$(EXEEXT)
+	@p='t-urndmm$(EXEEXT)'; \
+	b='t-urndmm'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+.test.log:
+	@p='$<'; \
+	$(am__set_b); \
+	$(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+@am__EXEEXT_TRUE@.test$(EXEEXT).log:
+@am__EXEEXT_TRUE@	@p='$<'; \
+@am__EXEEXT_TRUE@	$(am__set_b); \
+@am__EXEEXT_TRUE@	$(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+@am__EXEEXT_TRUE@	--log-file $$b.log --trs-file $$b.trs \
+@am__EXEEXT_TRUE@	$(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+@am__EXEEXT_TRUE@	"$$tst" $(AM_TESTS_FD_REDIRECT)
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+	$(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+	-test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS)
+	-test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs)
+	-test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+
+clean-generic:
+	-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-TESTS check-am clean \
+	clean-checkPROGRAMS clean-generic clean-libtool cscopelist-am \
+	ctags ctags-am distclean distclean-compile distclean-generic \
+	distclean-libtool distclean-tags distdir dvi dvi-am html \
+	html-am info info-am install install-am install-data \
+	install-data-am install-dvi install-dvi-am install-exec \
+	install-exec-am install-html install-html-am install-info \
+	install-info-am install-man install-pdf install-pdf-am \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	recheck tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+allprogs: $(EXTRA_PROGRAMS)
+
+$(top_builddir)/tests/libtests.la:
+	cd $(top_builddir)/tests; $(MAKE) $(AM_MAKEFLAGS) libtests.la
+
+manual-test: gen$(EXEEXT) stat$(EXEEXT)
+	@(echo -n '16i: '; ./gen -f mpz_urandomb -z 16 1000 \
+		| ./stat -i 0xffff | grep '^[0-9]')
+	@(echo -n '32i: '; ./gen -f mpz_urandomb -z 32 1000 \
+		| ./stat -i 0xffffffff  | grep '^[0-9]')
+	@(echo -n '33i: '; ./gen -f mpz_urandomb -z 33 1000 \
+		| ./stat -i 0x1ffffffff  | grep '^[0-9]')
+	@(echo -n '64i: '; ./gen -f mpz_urandomb -z 64 1000 \
+		| ./stat -i 0xffffffffffffffff  | grep '^[0-9]')
+	@(echo -n '128i: '; ./gen -f mpz_urandomb -z 128 1000 \
+		| ./stat -i 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF | grep '^[0-9]')
+
+	@(echo -n '16f: '; ./gen -f mpf_urandomb -z 16 1000 \
+		| ./stat | grep '^[0-9]')
+	@(echo -n '32f: '; ./gen -f mpf_urandomb -z 32 1000 \
+		| ./stat | grep '^[0-9]')
+	@(echo -n '33f: '; ./gen -f mpf_urandomb -z 33 1000 \
+		| ./stat | grep '^[0-9]')
+	@(echo -n '64f: '; ./gen -f mpf_urandomb -z 64 1000 \
+		| ./stat | grep '^[0-9]')
+	@(echo -n '128f: '; ./gen -f mpf_urandomb -z 128 1000 \
+		| ./stat | grep '^[0-9]')
+
+manual-bigtest: gen$(EXEEXT) stat$(EXEEXT)
+	@(echo '16i: '; ./gen -f mpz_urandomb -z 16 50000 \
+		| ./stat -2 1000 -i 0xffff | grep '^K[mp]')
+	@(echo '32i: '; ./gen -f mpz_urandomb -z 32 50000 \
+		| ./stat -2 1000 -i 0xffffffff | grep '^K[mp]')
+	@(echo '33i: '; ./gen -f mpz_urandomb -z 33 50000 \
+		| ./stat -2 1000 -i 0x1ffffffff | grep '^K[mp]')
+	@(echo '64i: '; ./gen -f mpz_urandomb -z 64 50000 \
+		| ./stat -2 1000 -i 0xffffffffffffffff  | grep '^K[mp]')
+	@(echo '128i: '; ./gen -f mpz_urandomb -z 128 50000 \
+		| ./stat -2 1000 -i 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF | grep '^K[mp]')
+
+	@(echo '16f: '; ./gen -f mpf_urandomb -z 16 50000 \
+		| ./stat -2 1000 | grep '^K[mp]')
+	@(echo '32f: '; ./gen -f mpf_urandomb -z 32 50000 \
+		| ./stat -2 1000 | grep '^K[mp]')
+	@(echo '33f: '; ./gen -f mpf_urandomb -z 33 50000 \
+		| ./stat -2 1000 | grep '^K[mp]')
+	@(echo '64f: '; ./gen -f mpf_urandomb -z 64 50000 \
+		| ./stat -2 1000 | grep '^K[mp]')
+	@(echo '128f: '; ./gen -f mpf_urandomb -z 128 50000 \
+		| ./stat -2 1000 | grep '^K[mp]')
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/third_party/gmp/tests/rand/findlc.c b/third_party/gmp/tests/rand/findlc.c
new file mode 100644
index 0000000..72fb12c
--- /dev/null
+++ b/third_party/gmp/tests/rand/findlc.c
@@ -0,0 +1,251 @@
+/*
+Copyright 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <math.h>
+#include "gmpstat.h"
+
+#define RCSID(msg) \
+static /**/const char *const rcsid[] = { (char *)rcsid, "\100(#)" msg }
+
+RCSID("$Id$");
+
+int g_debug = 0;
+
+static mpz_t a;
+
+static void
+sh_status (int sig)
+{
+  printf ("sh_status: signal %d caught. dumping status.\n", sig);
+
+  printf ("  a = ");
+  mpz_out_str (stdout, 10, a);
+  printf ("\n");
+  fflush (stdout);
+
+  if (SIGSEGV == sig)		/* remove SEGV handler */
+    signal (SIGSEGV, SIG_DFL);
+}
+
+/* Input is a modulus (m).  We shall find multiplier (a) and adder (c)
+   conforming to the rules found in the first comment block in file
+   mpz/urandom.c.
+
+   Then run a spectral test on the generator and discard any
+   multipliers not passing.  */
+
+/* TODO:
+
+   . find a better algorithm than a+=8; bigger jumps perhaps?
+
+*/
+
+void
+mpz_true_random (mpz_t s, unsigned long int nbits)
+{
+#if __FreeBSD__
+  FILE *fs;
+  char c[1];
+  int i;
+
+  mpz_set_ui (s, 0);
+  for (i = 0; i < nbits; i += 8)
+    {
+      for (;;)
+	{
+	  int nread;
+	  fs = fopen ("/dev/random", "r");
+	  nread = fread (c, 1, 1, fs);
+	  fclose (fs);
+	  if (nread != 0)
+	    break;
+	  sleep (1);
+	}
+      mpz_mul_2exp (s, s, 8);
+      mpz_add_ui (s, s, ((unsigned long int) c[0]) & 0xff);
+      printf ("%d random bits\n", i + 8);
+    }
+  if (nbits % 8 != 0)
+    mpz_mod_2exp (s, s, nbits);
+#endif
+}
+
+int
+main (int argc, char *argv[])
+{
+  const char usage[] = "usage: findlc [-dv] m2exp [low_merit [high_merit]]\n";
+  int f;
+  int v_lose, m_lose, v_best, m_best;
+  int c;
+  int debug = 1;
+  int cnt_high_merit;
+  mpz_t m;
+  unsigned long int m2exp;
+#define DIMS 6			/* dimensions run in spectral test */
+  mpf_t v[DIMS-1];		/* spectral test result (there's no v
+				   for 1st dimension */
+  mpf_t f_merit, low_merit, high_merit;
+  mpz_t acc, minus8;
+  mpz_t min, max;
+  mpz_t s;
+
+
+  mpz_init (m);
+  mpz_init (a);
+  for (f = 0; f < DIMS-1; f++)
+    mpf_init (v[f]);
+  mpf_init (f_merit);
+  mpf_init_set_d (low_merit, .1);
+  mpf_init_set_d (high_merit, .1);
+
+  while ((c = getopt (argc, argv, "a:di:hv")) != -1)
+    switch (c)
+      {
+      case 'd':			/* debug */
+	g_debug++;
+	break;
+
+      case 'v':			/* print version */
+	puts (rcsid[1]);
+	exit (0);
+
+      case 'h':
+      case '?':
+      default:
+	fputs (usage, stderr);
+	exit (1);
+      }
+
+  argc -= optind;
+  argv += optind;
+
+  if (argc < 1)
+    {
+      fputs (usage, stderr);
+      exit (1);
+    }
+
+  /* Install signal handler. */
+  if (SIG_ERR == signal (SIGSEGV, sh_status))
+    {
+      perror ("signal (SIGSEGV)");
+      exit (1);
+    }
+  if (SIG_ERR == signal (SIGHUP, sh_status))
+    {
+      perror ("signal (SIGHUP)");
+      exit (1);
+    }
+
+  printf ("findlc: version: %s\n", rcsid[1]);
+  m2exp = atol (argv[0]);
+  mpz_init_set_ui (m, 1);
+  mpz_mul_2exp (m, m, m2exp);
+  printf ("m = 0x");
+  mpz_out_str (stdout, 16, m);
+  puts ("");
+
+  if (argc > 1)			/* have low_merit */
+    mpf_set_str (low_merit, argv[1], 0);
+  if (argc > 2)			/* have high_merit */
+    mpf_set_str (high_merit, argv[2], 0);
+
+  if (debug)
+    {
+      fprintf (stderr, "low_merit = ");
+      mpf_out_str (stderr, 10, 2, low_merit);
+      fprintf (stderr, "; high_merit = ");
+      mpf_out_str (stderr, 10, 2, high_merit);
+      fputs ("\n", stderr);
+    }
+
+  mpz_init (minus8);
+  mpz_set_si (minus8, -8L);
+  mpz_init_set_ui (acc, 0);
+  mpz_init (s);
+  mpz_init_set_d (min, 0.01 * pow (2.0, (double) m2exp));
+  mpz_init_set_d (max, 0.99 * pow (2.0, (double) m2exp));
+
+  mpz_true_random (s, m2exp);	/* Start.  */
+  mpz_setbit (s, 0);		/* Make it odd.  */
+
+  v_best = m_best = 2*(DIMS-1);
+  for (;;)
+    {
+      mpz_add (acc, acc, s);
+      mpz_mod_2exp (acc, acc, m2exp);
+#if later
+      mpz_and_si (a, acc, -8L);
+#else
+      mpz_and (a, acc, minus8);
+#endif
+      mpz_add_ui (a, a, 5);
+      if (mpz_cmp (a, min) <= 0 || mpz_cmp (a, max) >= 0)
+	continue;
+
+      spectral_test (v, DIMS, a, m);
+      for (f = 0, v_lose = m_lose = 0, cnt_high_merit = DIMS-1;
+	   f < DIMS-1; f++)
+	{
+	  merit (f_merit, f + 2, v[f], m);
+
+	  if (mpf_cmp_ui (v[f], 1 << (30 / (f + 2) + (f == 2))) < 0)
+	    v_lose++;
+
+	  if (mpf_cmp (f_merit, low_merit) < 0)
+	    m_lose++;
+
+	  if (mpf_cmp (f_merit, high_merit) >= 0)
+	    cnt_high_merit--;
+	}
+
+      if (0 == v_lose && 0 == m_lose)
+	{
+	  mpz_out_str (stdout, 10, a); puts (""); fflush (stdout);
+	  if (0 == cnt_high_merit)
+	    break;		/* leave loop */
+	}
+      if (v_lose < v_best)
+	{
+	  v_best = v_lose;
+	  printf ("best (v_lose=%d; m_lose=%d): ", v_lose, m_lose);
+	  mpz_out_str (stdout, 10, a); puts (""); fflush (stdout);
+	}
+      if (m_lose < m_best)
+	{
+	  m_best = m_lose;
+	  printf ("best (v_lose=%d; m_lose=%d): ", v_lose, m_lose);
+	  mpz_out_str (stdout, 10, a); puts (""); fflush (stdout);
+	}
+    }
+
+  mpz_clear (m);
+  mpz_clear (a);
+  for (f = 0; f < DIMS-1; f++)
+    mpf_clear (v[f]);
+  mpf_clear (f_merit);
+  mpf_clear (low_merit);
+  mpf_clear (high_merit);
+
+  printf ("done.\n");
+  return 0;
+}
diff --git a/third_party/gmp/tests/rand/gen.c b/third_party/gmp/tests/rand/gen.c
new file mode 100644
index 0000000..c8e6c67
--- /dev/null
+++ b/third_party/gmp/tests/rand/gen.c
@@ -0,0 +1,480 @@
+/* gen.c -- Generate pseudorandom numbers.
+
+Copyright 1999, 2000, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+/* Examples:
+
+  $ gen 10
+10 integers 0 <= X < 2^32 generated by mpz_urandomb()
+
+  $ gen -f mpf_urandomb 10
+10 real numbers 0 <= X < 1
+
+  $ gen -z 127 10
+10 integers 0 <= X < 2^127
+
+  $ gen -f mpf_urandomb -x .9,1 10
+10 real numbers 0 <= X < .9
+
+  $ gen -s 1 10
+10 integers, sequence seeded with 1
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <limits.h>
+#include <errno.h>
+#include <time.h>
+#include <string.h>
+
+#if !HAVE_DECL_OPTARG
+extern char *optarg;
+extern int optind, opterr;
+#endif
+
+#include "gmp-impl.h"
+
+int main (argc, argv)
+     int argc;
+     char *argv[];
+{
+  const char usage[] =
+    "usage: gen [-bhpq] [-a n] [-c a,c,m2exp] [-C a,c,m] [-f func] [-g alg] [-m n] [-s n] " \
+    "[-x f,t] [-z n] [n]\n" \
+    "  n        number of random numbers to generate\n" \
+    "  -a n     ASCII output in radix n (default, with n=10)\n" \
+    "  -b       binary output\n" \
+    "  -c a,c,m2exp use supplied LC scheme\n" \
+    "  -f func  random function, one of\n" \
+    "           mpz_urandomb (default), mpz_urandomm, mpf_urandomb, rand, random\n" \
+    "  -g alg   algorithm, one of mt (default), lc\n" \
+    "  -h       print this text and exit\n" \
+    "  -m n     maximum size of generated number plus 1 (0<= X < n) for mpz_urandomm\n" \
+    "  -p       print used seed on stderr\n" \
+    "  -q       quiet, no output\n" \
+    "  -s n     initial seed (default: output from time(3))\n" \
+    "  -x f,t   exclude all numbers f <= x <= t\n" \
+    "  -z n     size in bits of generated numbers (0<= X <2^n) (default 32)\n" \
+    "";
+
+  unsigned long int f;
+  unsigned long int n = 0;
+  unsigned long int seed;
+  unsigned long int m2exp = 0;
+  unsigned int size = 32;
+  int seed_from_user = 0;
+  int ascout = 1, binout = 0, printseed = 0;
+  int output_radix = 10;
+  int lc_scheme_from_user = 0;
+  int quiet_flag = 0;
+  mpz_t z_seed;
+  mpz_t z1;
+  mpf_t f1;
+  gmp_randstate_t rstate;
+  int c, i;
+  double drand;
+  long lrand;
+  int do_exclude = 0;
+  mpf_t f_xf, f_xt;		/* numbers to exclude from sequence */
+  char *str_xf, *str_xt;	/* numbers to exclude from sequence */
+  char *str_a, *str_adder, *str_m;
+  mpz_t z_a, z_m, z_mmax;
+  unsigned long int ul_adder;
+
+  enum
+  {
+    RFUNC_mpz_urandomb = 0,
+    RFUNC_mpz_urandomm,
+    RFUNC_mpf_urandomb,
+    RFUNC_rand,
+    RFUNC_random,
+  } rfunc = RFUNC_mpz_urandomb;
+  char *rfunc_str[] =  { "mpz_urandomb", "mpz_urandomm", "mpf_urandomb",
+			 "rand", "random" };
+  enum
+  {
+    RNG_MT = 0,
+    RNG_LC
+  };
+  gmp_randalg_t ralg = RNG_MT;
+  /* Texts for the algorithms.  The index of each must match the
+     corresponding algorithm in the enum above.  */
+  char *ralg_str[] = { "mt", "lc" };
+
+  mpf_init (f_xf);
+  mpf_init (f_xt);
+  mpf_init (f1);
+  mpz_init (z1);
+  mpz_init (z_seed);
+  mpz_init_set_ui (z_mmax, 0);
+
+
+  while ((c = getopt (argc, argv, "a:bc:f:g:hm:n:pqs:z:x:")) != -1)
+    switch (c)
+      {
+      case 'a':
+	ascout = 1;
+	binout = 0;
+	output_radix = atoi (optarg);
+	break;
+
+      case 'b':
+	ascout = 0;
+	binout = 1;
+	break;
+
+      case 'c':			/* User supplied LC scheme: a,c,m2exp */
+	if (NULL == (str_a = strtok (optarg, ","))
+	    || NULL == (str_adder = strtok (NULL, ","))
+	    || NULL == (str_m = strtok (NULL, ",")))
+	  {
+	    fprintf (stderr, "gen: bad LC scheme parameters: %s\n", optarg);
+	    exit (1);
+	  }
+#ifdef HAVE_STRTOUL
+	ul_adder = strtoul (str_adder, NULL, 0);
+#elif HAVE_STRTOL
+	ul_adder = (unsigned long int) strtol (str_adder, NULL, 0);
+#else
+	ul_adder = (unsigned long int) atoi (str_adder);
+#endif
+
+	if (mpz_init_set_str (z_a, str_a, 0))
+	  {
+	    fprintf (stderr, "gen: bad LC scheme parameter `a': %s\n", str_a);
+	    exit (1);
+	  }
+	if (ULONG_MAX == ul_adder)
+	  {
+	    fprintf (stderr, "gen: bad LC scheme parameter `c': %s\n",
+		     str_adder);
+	    exit (1);
+	  }
+	m2exp = atol (str_m);
+
+	lc_scheme_from_user = 1;
+	break;
+
+
+      case 'f':
+	rfunc = -1;
+	for (f = 0; f < sizeof (rfunc_str) / sizeof (*rfunc_str); f++)
+	    if (!strcmp (optarg, rfunc_str[f]))
+	      {
+		rfunc = f;
+		break;
+	      }
+	if (rfunc == -1)
+	  {
+	    fputs (usage, stderr);
+	    exit (1);
+	  }
+	break;
+
+      case 'g':			/* algorithm */
+	ralg = -1;
+	for (f = 0; f < sizeof (ralg_str) / sizeof (*ralg_str); f++)
+	    if (!strcmp (optarg, ralg_str[f]))
+	      {
+		ralg = f;
+		break;
+	      }
+	if (ralg == -1)
+	  {
+	    fputs (usage, stderr);
+	    exit (1);
+	  }
+	break;
+
+      case 'm':			/* max for mpz_urandomm() */
+	if (mpz_set_str (z_mmax, optarg, 0))
+	  {
+	    fprintf (stderr, "gen: bad max value: %s\n", optarg);
+	    exit (1);
+	  }
+	break;
+
+      case 'p':			/* print seed on stderr */
+	printseed = 1;
+	break;
+
+      case 'q':			/* quiet */
+	quiet_flag = 1;
+	break;
+
+      case 's':			/* user provided seed */
+	if (mpz_set_str (z_seed, optarg, 0))
+	  {
+	    fprintf (stderr, "gen: bad seed argument %s\n", optarg);
+	    exit (1);
+	  }
+	seed_from_user = 1;
+	break;
+
+      case 'z':
+	size = atoi (optarg);
+	if (size < 1)
+	  {
+	    fprintf (stderr, "gen: bad size argument (-z %u)\n", size);
+	    exit (1);
+	  }
+	break;
+
+      case 'x':			/* Exclude. from,to */
+	str_xf = optarg;
+	str_xt = strchr (optarg, ',');
+	if (NULL == str_xt)
+	  {
+	    fprintf (stderr, "gen: bad exclusion parameters: %s\n", optarg);
+	    exit (1);
+	  }
+	*str_xt++ = '\0';
+	do_exclude = 1;
+	break;
+
+      case 'h':
+      case '?':
+      default:
+	fputs (usage, stderr);
+	exit (1);
+      }
+  argc -= optind;
+  argv += optind;
+
+  if (! seed_from_user)
+    mpz_set_ui (z_seed, (unsigned long int) time (NULL));
+  seed = mpz_get_ui (z_seed);
+  if (printseed)
+    {
+      fprintf (stderr, "gen: seed used: ");
+      mpz_out_str (stderr, output_radix, z_seed);
+      fprintf (stderr, "\n");
+    }
+
+  mpf_set_prec (f1, size);
+
+  /* init random state and plant seed */
+  switch (rfunc)
+    {
+    case RFUNC_mpf_urandomb:
+#if 0
+      /* Don't init a too small generator.  */
+      size = PREC (f1) * GMP_LIMB_BITS;
+      /* Fall through.  */
+#endif
+    case RFUNC_mpz_urandomb:
+    case RFUNC_mpz_urandomm:
+      switch (ralg)
+	{
+	case RNG_MT:
+	  gmp_randinit_mt (rstate);
+	  break;
+
+	case RNG_LC:
+	  if (! lc_scheme_from_user)
+	    gmp_randinit_lc_2exp_size (rstate, MIN (128, size));
+	  else
+	    gmp_randinit_lc_2exp (rstate, z_a, ul_adder, m2exp);
+	  break;
+
+	default:
+	  fprintf (stderr, "gen: unsupported algorithm\n");
+	  exit (1);
+	}
+
+      gmp_randseed (rstate, z_seed);
+      break;
+
+    case RFUNC_rand:
+      srand (seed);
+      break;
+
+    case RFUNC_random:
+#ifdef __FreeBSD__		/* FIXME */
+      if (seed_from_user)
+	srandom (seed);
+      else
+	srandomdev ();
+#else
+      fprintf (stderr, "gen: unsupported algorithm\n");
+#endif
+      break;
+
+    default:
+      fprintf (stderr, "gen: random function not implemented\n");
+      exit (1);
+    }
+
+  /* set up excludes */
+  if (do_exclude)
+    switch (rfunc)
+      {
+      case RFUNC_mpf_urandomb:
+
+	if (mpf_set_str (f_xf, str_xf, 10) ||
+	    mpf_set_str (f_xt, str_xt, 10))
+	  {
+	    fprintf (stderr, "gen: bad exclusion-from (\"%s\") " \
+		     "or exclusion-to (\"%s\") string.  no exclusion done.\n",
+		     str_xf, str_xt);
+	    do_exclude = 0;
+	  }
+	break;
+
+      default:
+	fprintf (stderr, "gen: exclusion not implemented for chosen " \
+		 "randomization function.  all numbers included in sequence.\n");
+      }
+
+  /* generate and print */
+  if (argc > 0)
+    {
+#if HAVE_STRTOUL
+      n = strtoul (argv[0], (char **) NULL, 10);
+#elif HAVE_STRTOL
+      n = (unsigned long int) strtol (argv[0], (char **) NULL, 10);
+#else
+      n = (unsigned long int) atoi (argv[0]);
+#endif
+    }
+
+  for (f = 0; n == 0 || f < n; f++)
+    {
+      switch (rfunc)
+	{
+	case RFUNC_mpz_urandomb:
+	  mpz_urandomb (z1, rstate, size);
+	  if (quiet_flag)
+	    break;
+	  if (binout)
+	    {
+	      /*fwrite ((unsigned int *) z1->_mp_d, 4, 1, stdout);*/
+	      fprintf (stderr, "gen: binary output for mpz_urandom* is broken\n");
+	      exit (1);
+	    }
+	  else
+	    {
+	      mpz_out_str (stdout, output_radix, z1);
+	      puts ("");
+	    }
+	  break;
+
+	case RFUNC_mpz_urandomm:
+	  mpz_urandomm (z1, rstate, z_mmax);
+	  if (quiet_flag)
+	    break;
+	  if (binout)
+	    {
+	      /*fwrite ((unsigned int *) z1->_mp_d, 4, 1, stdout);*/
+	      fprintf (stderr, "gen: binary output for mpz_urandom* is broken\n");
+	      exit (1);
+	    }
+	  else
+	    {
+	      mpz_out_str (stdout, output_radix, z1);
+	      puts ("");
+	    }
+	  break;
+
+	case RFUNC_mpf_urandomb:
+	  mpf_urandomb (f1, rstate, size);
+	  if (do_exclude)
+	    if (mpf_cmp (f1, f_xf) >= 0 && mpf_cmp (f1, f_xt) <= 0)
+		break;
+	  if (quiet_flag)
+	    break;
+	  if (binout)
+	    {
+	      fprintf (stderr, "gen: binary output for floating point numbers "\
+		       "not implemented\n");
+	      exit (1);
+	    }
+	  else
+	    {
+	      mpf_out_str (stdout, output_radix, 0, f1);
+	      puts ("");
+	    }
+	  break;
+
+	case RFUNC_rand:
+	  i = rand ();
+#ifdef FLOAT_OUTPUT
+	  if (i)
+	    drand = (double) i / (double) RAND_MAX;
+	  else
+	    drand = 0.0;
+	  if (quiet_flag)
+	    break;
+	  if (binout)
+	    fwrite (&drand, sizeof (drand), 1, stdout);
+	  else
+	    printf ("%e\n", drand);
+#else
+	  if (quiet_flag)
+	    break;
+	  if (binout)
+	    fwrite (&i, sizeof (i), 1, stdout);
+	  else
+	    printf ("%d\n", i);
+#endif
+	  break;
+
+	case RFUNC_random:
+	  lrand = random ();
+	  if (lrand)
+	    drand = (double) lrand / (double) 0x7fffffff;
+	  else
+	    drand = 0;
+	  if (quiet_flag)
+	    break;
+	  if (binout)
+	    fwrite (&drand, sizeof (drand), 1, stdout);
+	  else
+	    printf ("%e\n", drand);
+	  break;
+
+	default:
+	  fprintf (stderr, "gen: random function not implemented\n");
+	  exit (1);
+	}
+
+    }
+
+  /* clean up */
+  switch (rfunc)
+    {
+    case RFUNC_mpz_urandomb:
+    case RFUNC_mpf_urandomb:
+      gmp_randclear (rstate);
+      break;
+    default:
+      break;
+    }
+  mpf_clear (f1);
+  mpf_clear (f_xf);
+  mpf_clear (f_xt);
+  mpz_clear (z1);
+  mpz_clear (z_seed);
+
+  return 0;
+}
+
+static void *debug_dummyz = mpz_dump;
+static void *debug_dummyf = mpf_dump;
diff --git a/third_party/gmp/tests/rand/gmpstat.h b/third_party/gmp/tests/rand/gmpstat.h
new file mode 100644
index 0000000..99c5cca
--- /dev/null
+++ b/third_party/gmp/tests/rand/gmpstat.h
@@ -0,0 +1,75 @@
+/* gmpstat.h */
+
+/*
+Copyright 1999 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+/* This file requires the following header files: gmp.h */
+
+#ifndef	__GMPSTAT_H__
+#define	__GMPSTAT_H__
+
+/* Global debug flag.  FIXME: Remove. */
+extern int g_debug;
+#define DEBUG_1 0
+#define DEBUG_2 1
+
+/* Max number of dimensions in spectral test.  FIXME: Makw dynamic. */
+#define GMP_SPECT_MAXT 10
+
+void
+mpf_freqt (mpf_t Kp,
+	   mpf_t Km,
+	   mpf_t X[],
+	   const unsigned long int n);
+unsigned long int
+mpz_freqt (mpf_t V,
+	   mpz_t X[],
+	   unsigned int imax,
+	   const unsigned long int n);
+
+/* Low level functions. */
+void
+ks (mpf_t Kp,
+    mpf_t Km,
+    mpf_t X[],
+    void (P) (mpf_t, mpf_t),
+    const unsigned long int n);
+
+void
+ks_table (mpf_t p, mpf_t val, const unsigned int n);
+
+void
+x2_table (double t[],
+	  unsigned int v);
+
+void
+spectral_test (mpf_t rop[], unsigned int T, mpz_t a, mpz_t m);
+void
+vz_dot (mpz_t rop, mpz_t V1[], mpz_t V2[], unsigned int n);
+void
+f_floor (mpf_t rop, mpf_t op);
+
+void
+merit (mpf_t rop, unsigned int t, mpf_t v, mpz_t m);
+double
+merit_u (unsigned int t, mpf_t v, mpz_t m);
+
+/* From separate source files: */
+void zdiv_round (mpz_t rop, mpz_t n, mpz_t d);
+
+#endif /* !__GMPSTAT_H__ */
diff --git a/third_party/gmp/tests/rand/spect.c b/third_party/gmp/tests/rand/spect.c
new file mode 100644
index 0000000..64de5a0
--- /dev/null
+++ b/third_party/gmp/tests/rand/spect.c
@@ -0,0 +1,136 @@
+/* spect.c -- the spectral test */
+
+/*
+Copyright 1999 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+/* T is upper dimension.  Z_A is the LC multiplier, which is
+   relatively prime to Z_M, the LC modulus.  The result is put in
+   rop[] with v[t] in rop[t-2]. */
+
+/* BUGS: Due to lazy allocation scheme, maximum T is hard coded to MAXT. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <math.h>
+
+#include "gmpstat.h"
+
+int g_debug = 0;
+
+int
+main (int argc, char *argv[])
+{
+  const char usage[] = "usage: spect [-d] a m n\n";
+  int c;
+  unsigned int n;
+  mpz_t a, m;
+  mpf_t res[GMP_SPECT_MAXT], res_min[GMP_SPECT_MAXT], f_tmp;
+  int f;
+
+
+  mpz_init (a);
+  mpz_init (m);
+  for (f = 0; f < GMP_SPECT_MAXT; f++)
+    {
+      mpf_init (res[f]);
+      mpf_init (res_min[f]);
+    }
+  mpf_init (f_tmp);
+  mpf_set_ui (res_min[0], 32768); /* 2^15 */
+  mpf_set_ui (res_min[1], 1024); /* 2^10 */
+  mpf_set_ui (res_min[2], 256); /* 2^8 */
+  mpf_set_ui (res_min[3], 64); /* 2^6 */
+  mpf_set_ui (res_min[4], 32); /* 2^5 */
+
+  while ((c = getopt (argc, argv, "dh")) != -1)
+    switch (c)
+      {
+      case 'd':			/* debug */
+	g_debug++;
+	break;
+      case 'h':
+      default:
+	fputs (usage, stderr);
+	exit (1);
+      }
+  argc -= optind;
+  argv += optind;
+
+  if (argc < 3)
+    {
+      fputs (usage, stderr);
+      exit (1);
+    }
+
+  mpz_set_str (a, argv[0], 0);
+  mpz_set_str (m, argv[1], 0);
+  n = (unsigned int) atoi (argv[2]);
+  if (n + 1 > GMP_SPECT_MAXT)
+    n = GMP_SPECT_MAXT + 1;
+
+  spectral_test (res, n, a, m);
+
+  for (f = 0; f < n - 1; f++)
+    {
+      /* print v */
+      printf ("%d: v = ", f + 2);
+      mpf_out_str (stdout, 10, 4, res[f]);
+
+#ifdef PRINT_RAISED_BY_TWO_AS_WELL
+      printf (" (^2 = ");
+      mpf_mul (f_tmp, res[f], res[f]);
+      mpf_out_str (stdout, 10, 4, f_tmp);
+      printf (")");
+#endif /* PRINT_RAISED_BY_TWO_AS_WELL */
+
+      /* print merit */
+      printf (" m = ");
+      merit (f_tmp, f + 2, res[f], m);
+      mpf_out_str (stdout, 10, 4, f_tmp);
+
+      if (mpf_cmp (res[f], res_min[f]) < 0)
+	printf ("\t*** v too low ***");
+      if (mpf_get_d (f_tmp) < .1)
+	printf ("\t*** merit too low ***");
+
+      puts ("");
+    }
+
+  mpz_clear (a);
+  mpz_clear (m);
+  for (f = 0; f < GMP_SPECT_MAXT; f++)
+    {
+      mpf_clear (res[f]);
+      mpf_clear (res_min[f]);
+    }
+  mpf_clear (f_tmp);
+
+  return 0;
+}
+
+
+void
+debug_foo()
+{
+  if (0)
+    {
+      mpz_dump (0);
+      mpf_dump (0);
+    }
+}
diff --git a/third_party/gmp/tests/rand/stat.c b/third_party/gmp/tests/rand/stat.c
new file mode 100644
index 0000000..fa06f4c
--- /dev/null
+++ b/third_party/gmp/tests/rand/stat.c
@@ -0,0 +1,406 @@
+/* stat.c -- statistical tests of random number sequences. */
+
+/*
+Copyright 1999, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+/* Examples:
+
+  $ gen 1000 | stat
+Test 1000 real numbers.
+
+  $ gen 30000 | stat -2 1000
+Test 1000 real numbers 30 times and then test the 30 results in a
+``second level''.
+
+  $ gen -f mpz_urandomb 1000 | stat -i 0xffffffff
+Test 1000 integers 0 <= X <= 2^32-1.
+
+  $ gen -f mpz_urandomb -z 34 1000 | stat -i 0x3ffffffff
+Test 1000 integers 0 <= X <= 2^34-1.
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <math.h>
+#include "gmpstat.h"
+
+#if !HAVE_DECL_OPTARG
+extern char *optarg;
+extern int optind, opterr;
+#endif
+
+#define FVECSIZ (100000L)
+
+int g_debug = 0;
+
+static void
+print_ks_results (mpf_t f_p, mpf_t f_p_prob,
+		  mpf_t f_m, mpf_t f_m_prob,
+		  FILE *fp)
+{
+  double p, pp, m, mp;
+
+  p = mpf_get_d (f_p);
+  m = mpf_get_d (f_m);
+  pp = mpf_get_d (f_p_prob);
+  mp = mpf_get_d (f_m_prob);
+
+  fprintf (fp, "%.4f (%.0f%%)\t", p, pp * 100.0);
+  fprintf (fp, "%.4f (%.0f%%)\n", m, mp * 100.0);
+}
+
+static void
+print_x2_table (unsigned int v, FILE *fp)
+{
+  double t[7];
+  int f;
+
+
+  fprintf (fp, "Chi-square table for v=%u\n", v);
+  fprintf (fp, "1%%\t5%%\t25%%\t50%%\t75%%\t95%%\t99%%\n");
+  x2_table (t, v);
+  for (f = 0; f < 7; f++)
+    fprintf (fp, "%.2f\t", t[f]);
+  fputs ("\n", fp);
+}
+
+
+
+/* Pks () -- Distribution function for KS results with a big n (like 1000
+   or so):  F(x) = 1 - pow(e, -2*x^2) [Knuth, vol 2, p.51]. */
+/* gnuplot: plot [0:1] Pks(x), Pks(x) = 1-exp(-2*x**2)  */
+
+static void
+Pks (mpf_t p, mpf_t x)
+{
+  double dt;			/* temp double */
+
+  mpf_set (p, x);
+  mpf_mul (p, p, p);		/* p = x^2 */
+  mpf_mul_ui (p, p, 2);		/* p = 2*x^2 */
+  mpf_neg (p, p);		/* p = -2*x^2 */
+  /* No pow() in gmp.  Use doubles. */
+  /* FIXME: Use exp()? */
+  dt = pow (M_E, mpf_get_d (p));
+  mpf_set_d (p, dt);
+  mpf_ui_sub (p, 1, p);
+}
+
+/* f_freq() -- frequency test on real numbers 0<=f<1*/
+static void
+f_freq (const unsigned l1runs, const unsigned l2runs,
+	mpf_t fvec[], const unsigned long n)
+{
+  unsigned f;
+  mpf_t f_p, f_p_prob;
+  mpf_t f_m, f_m_prob;
+  mpf_t *l1res;			/* level 1 result array */
+
+  mpf_init (f_p);  mpf_init (f_m);
+  mpf_init (f_p_prob);  mpf_init (f_m_prob);
+
+
+  /* Allocate space for 1st level results. */
+  l1res = (mpf_t *) malloc (l2runs * 2 * sizeof (mpf_t));
+  if (NULL == l1res)
+    {
+      fprintf (stderr, "stat: malloc failure\n");
+      exit (1);
+    }
+
+  printf ("\nEquidistribution/Frequency test on real numbers (0<=X<1):\n");
+  printf ("\tKp\t\tKm\n");
+
+  for (f = 0; f < l2runs; f++)
+    {
+      /*  f_printvec (fvec, n); */
+      mpf_freqt (f_p, f_m, fvec + f * n, n);
+
+      /* what's the probability of getting these results? */
+      ks_table (f_p_prob, f_p, n);
+      ks_table (f_m_prob, f_m, n);
+
+      if (l1runs == 0)
+	{
+	  /*printf ("%u:\t", f + 1);*/
+	  print_ks_results (f_p, f_p_prob, f_m, f_m_prob, stdout);
+	}
+      else
+	{
+	  /* save result */
+	  mpf_init_set (l1res[f], f_p);
+	  mpf_init_set (l1res[f + l2runs], f_m);
+	}
+    }
+
+  /* Now, apply the KS test on the results from the 1st level rounds
+     with the distribution
+     F(x) = 1 - pow(e, -2*x^2)	[Knuth, vol 2, p.51] */
+
+  if (l1runs != 0)
+    {
+      /*printf ("-------------------------------------\n");*/
+
+      /* The Kp's. */
+      ks (f_p, f_m, l1res, Pks, l2runs);
+      ks_table (f_p_prob, f_p, l2runs);
+      ks_table (f_m_prob, f_m, l2runs);
+      printf ("Kp:\t");
+      print_ks_results (f_p, f_p_prob, f_m, f_m_prob, stdout);
+
+      /* The Km's. */
+      ks (f_p, f_m, l1res + l2runs, Pks, l2runs);
+      ks_table (f_p_prob, f_p, l2runs);
+      ks_table (f_m_prob, f_m, l2runs);
+      printf ("Km:\t");
+      print_ks_results (f_p, f_p_prob, f_m, f_m_prob, stdout);
+    }
+
+  mpf_clear (f_p);  mpf_clear (f_m);
+  mpf_clear (f_p_prob);  mpf_clear (f_m_prob);
+  free (l1res);
+}
+
+/* z_freq(l1runs, l2runs, zvec, n, max) -- frequency test on integers
+   0<=z<=MAX */
+static void
+z_freq (const unsigned l1runs,
+	const unsigned l2runs,
+	mpz_t zvec[],
+	const unsigned long n,
+	unsigned int max)
+{
+  mpf_t V;			/* result */
+  double d_V;			/* result as a double */
+
+  mpf_init (V);
+
+
+  printf ("\nEquidistribution/Frequency test on integers (0<=X<=%u):\n", max);
+  print_x2_table (max, stdout);
+
+  mpz_freqt (V, zvec, max, n);
+
+  d_V = mpf_get_d (V);
+  printf ("V = %.2f (n = %lu)\n", d_V, n);
+
+  mpf_clear (V);
+}
+
+unsigned int stat_debug = 0;
+
+int
+main (argc, argv)
+     int argc;
+     char *argv[];
+{
+  const char usage[] =
+    "usage: stat [-d] [-2 runs] [-i max | -r max] [file]\n" \
+    "       file     filename\n" \
+    "       -2 runs  perform 2-level test with RUNS runs on 1st level\n" \
+    "       -d       increase debugging level\n" \
+    "       -i max   input is integers 0 <= Z <= MAX\n" \
+    "       -r max   input is real numbers 0 <= R < 1 and use MAX as\n" \
+    "                maximum value when converting real numbers to integers\n" \
+    "";
+
+  mpf_t fvec[FVECSIZ];
+  mpz_t zvec[FVECSIZ];
+  unsigned long int f, n, vecentries;
+  char *filen;
+  FILE *fp;
+  int c;
+  int omitoutput = 0;
+  int realinput = -1;		/* 1: input is real numbers 0<=R<1;
+				   0: input is integers 0 <= Z <= MAX. */
+  long l1runs = 0,		/* 1st level runs */
+    l2runs = 1;			/* 2nd level runs */
+  mpf_t f_temp;
+  mpz_t z_imax;			/* max value when converting between
+				   real number and integer. */
+  mpf_t f_imax_plus1;		/* f_imax + 1 stored in an mpf_t for
+				   convenience */
+  mpf_t f_imax_minus1;		/* f_imax - 1 stored in an mpf_t for
+				   convenience */
+
+
+  mpf_init (f_temp);
+  mpz_init_set_ui (z_imax, 0x7fffffff);
+  mpf_init (f_imax_plus1);
+  mpf_init (f_imax_minus1);
+
+  while ((c = getopt (argc, argv, "d2:i:r:")) != -1)
+    switch (c)
+      {
+      case '2':
+	l1runs = atol (optarg);
+	l2runs = -1;		/* set later on */
+	break;
+      case 'd':			/* increase debug level */
+	stat_debug++;
+	break;
+      case 'i':
+	if (1 == realinput)
+	  {
+	    fputs ("stat: options -i and -r are mutually exclusive\n", stderr);
+	    exit (1);
+	  }
+	if (mpz_set_str (z_imax, optarg, 0))
+	  {
+	    fprintf (stderr, "stat: bad max value %s\n", optarg);
+	    exit (1);
+	  }
+	realinput = 0;
+	break;
+      case 'r':
+	if (0 == realinput)
+	  {
+	    fputs ("stat: options -i and -r are mutually exclusive\n", stderr);
+	    exit (1);
+	  }
+	if (mpz_set_str (z_imax, optarg, 0))
+	  {
+	    fprintf (stderr, "stat: bad max value %s\n", optarg);
+	    exit (1);
+	  }
+	realinput = 1;
+	break;
+      case 'o':
+	omitoutput = atoi (optarg);
+	break;
+      case '?':
+      default:
+	fputs (usage, stderr);
+	exit (1);
+      }
+  argc -= optind;
+  argv += optind;
+
+  if (argc < 1)
+    fp = stdin;
+  else
+    filen = argv[0];
+
+  if (fp != stdin)
+    if (NULL == (fp = fopen (filen, "r")))
+      {
+	perror (filen);
+	exit (1);
+      }
+
+  if (-1 == realinput)
+    realinput = 1;		/* default is real numbers */
+
+  /* read file and fill appropriate vec */
+  if (1 == realinput)		/* real input */
+    {
+      for (f = 0; f < FVECSIZ ; f++)
+	{
+	  mpf_init (fvec[f]);
+	  if (!mpf_inp_str (fvec[f], fp, 10))
+	    break;
+	}
+    }
+  else				/* integer input */
+    {
+      for (f = 0; f < FVECSIZ ; f++)
+	{
+	  mpz_init (zvec[f]);
+	  if (!mpz_inp_str (zvec[f], fp, 10))
+	    break;
+	}
+    }
+  vecentries = n = f;		/* number of entries read */
+  fclose (fp);
+
+  if (FVECSIZ == f)
+    fprintf (stderr, "stat: warning: discarding input due to lazy allocation "\
+	     "of only %ld entries.  sorry.\n", FVECSIZ);
+
+  printf ("Got %lu numbers.\n", n);
+
+  /* convert and fill the other vec */
+  /* since fvec[] contains 0<=f<1 and we want ivec[] to contain
+     0<=z<=imax and we are truncating all fractions when
+     converting float to int, we have to add 1 to imax.*/
+  mpf_set_z (f_imax_plus1, z_imax);
+  mpf_add_ui (f_imax_plus1, f_imax_plus1, 1);
+  if (1 == realinput)		/* fill zvec[] */
+    {
+      for (f = 0; f < n; f++)
+	{
+	  mpf_mul (f_temp, fvec[f], f_imax_plus1);
+	  mpz_init (zvec[f]);
+	  mpz_set_f (zvec[f], f_temp); /* truncating fraction */
+	  if (stat_debug > 1)
+	    {
+	      mpz_out_str (stderr, 10, zvec[f]);
+	      fputs ("\n", stderr);
+	    }
+	}
+    }
+  else				/* integer input; fill fvec[] */
+    {
+      /*    mpf_set_z (f_imax_minus1, z_imax);
+	    mpf_sub_ui (f_imax_minus1, f_imax_minus1, 1);*/
+      for (f = 0; f < n; f++)
+	{
+	  mpf_init (fvec[f]);
+	  mpf_set_z (fvec[f], zvec[f]);
+	  mpf_div (fvec[f], fvec[f], f_imax_plus1);
+	  if (stat_debug > 1)
+	    {
+	      mpf_out_str (stderr, 10, 0, fvec[f]);
+	      fputs ("\n", stderr);
+	    }
+	}
+    }
+
+  /* 2 levels? */
+  if (1 != l2runs)
+    {
+      l2runs = n / l1runs;
+      printf ("Doing %ld second level rounds "\
+	      "with %ld entries in each round", l2runs, l1runs);
+      if (n % l1runs)
+	printf (" (discarding %ld entr%s)", n % l1runs,
+		n % l1runs == 1 ? "y" : "ies");
+      puts (".");
+      n = l1runs;
+    }
+
+#ifndef DONT_FFREQ
+  f_freq (l1runs, l2runs, fvec, n);
+#endif
+#ifdef DO_ZFREQ
+  z_freq (l1runs, l2runs, zvec, n, mpz_get_ui (z_imax));
+#endif
+
+  mpf_clear (f_temp); mpz_clear (z_imax);
+  mpf_clear (f_imax_plus1);
+  mpf_clear (f_imax_minus1);
+  for (f = 0; f < vecentries; f++)
+    {
+      mpf_clear (fvec[f]);
+      mpz_clear (zvec[f]);
+    }
+
+  return 0;
+}
diff --git a/third_party/gmp/tests/rand/statlib.c b/third_party/gmp/tests/rand/statlib.c
new file mode 100644
index 0000000..db05380
--- /dev/null
+++ b/third_party/gmp/tests/rand/statlib.c
@@ -0,0 +1,836 @@
+/* statlib.c -- Statistical functions for testing the randomness of
+   number sequences. */
+
+/*
+Copyright 1999, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+/* The theories for these functions are taken from D. Knuth's "The Art
+of Computer Programming: Volume 2, Seminumerical Algorithms", Third
+Edition, Addison Wesley, 1998. */
+
+/* Implementation notes.
+
+The Kolmogorov-Smirnov test.
+
+Eq. (13) in Knuth, p. 50, says that if X1, X2, ..., Xn are independent
+observations arranged into ascending order
+
+	Kp = sqr(n) * max(j/n - F(Xj))		for all 1<=j<=n
+	Km = sqr(n) * max(F(Xj) - (j-1)/n))	for all 1<=j<=n
+
+where F(x) = Pr(X <= x) = probability that (X <= x), which for a
+uniformly distributed random real number between zero and one is
+exactly the number itself (x).
+
+
+The answer to exercise 23 gives the following implementation, which
+doesn't need the observations to be sorted in ascending order:
+
+for (k = 0; k < m; k++)
+	a[k] = 1.0
+	b[k] = 0.0
+	c[k] = 0
+
+for (each observation Xj)
+	Y = F(Xj)
+	k = floor (m * Y)
+	a[k] = min (a[k], Y)
+	b[k] = max (b[k], Y)
+	c[k] += 1
+
+	j = 0
+	rp = rm = 0
+	for (k = 0; k < m; k++)
+		if (c[k] > 0)
+			rm = max (rm, a[k] - j/n)
+			j += c[k]
+			rp = max (rp, j/n - b[k])
+
+Kp = sqr (n) * rp
+Km = sqr (n) * rm
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "gmpstat.h"
+
+/* ks (Kp, Km, X, P, n) -- Perform a Kolmogorov-Smirnov test on the N
+   real numbers between zero and one in vector X.  P is the
+   distribution function, called for each entry in X, which should
+   calculate the probability of X being greater than or equal to any
+   number in the sequence.  (For a uniformly distributed sequence of
+   real numbers between zero and one, this is simply equal to X.)  The
+   result is put in Kp and Km.  */
+
+void
+ks (mpf_t Kp,
+    mpf_t Km,
+    mpf_t X[],
+    void (P) (mpf_t, mpf_t),
+    unsigned long int n)
+{
+  mpf_t Kt;			/* temp */
+  mpf_t f_x;
+  mpf_t f_j;			/* j */
+  mpf_t f_jnq;			/* j/n or (j-1)/n */
+  unsigned long int j;
+
+  /* Sort the vector in ascending order. */
+  qsort (X, n, sizeof (__mpf_struct), mpf_cmp);
+
+  /* K-S test. */
+  /*	Kp = sqr(n) * max(j/n - F(Xj))		for all 1<=j<=n
+	Km = sqr(n) * max(F(Xj) - (j-1)/n))	for all 1<=j<=n
+  */
+
+  mpf_init (Kt); mpf_init (f_x); mpf_init (f_j); mpf_init (f_jnq);
+  mpf_set_ui (Kp, 0);  mpf_set_ui (Km, 0);
+  for (j = 1; j <= n; j++)
+    {
+      P (f_x, X[j-1]);
+      mpf_set_ui (f_j, j);
+
+      mpf_div_ui (f_jnq, f_j, n);
+      mpf_sub (Kt, f_jnq, f_x);
+      if (mpf_cmp (Kt, Kp) > 0)
+	mpf_set (Kp, Kt);
+      if (g_debug > DEBUG_2)
+	{
+	  printf ("j=%lu ", j);
+	  printf ("P()="); mpf_out_str (stdout, 10, 2, f_x); printf ("\t");
+
+	  printf ("jnq="); mpf_out_str (stdout, 10, 2, f_jnq); printf (" ");
+	  printf ("diff="); mpf_out_str (stdout, 10, 2, Kt); printf (" ");
+	  printf ("Kp="); mpf_out_str (stdout, 10, 2, Kp); printf ("\t");
+	}
+      mpf_sub_ui (f_j, f_j, 1);
+      mpf_div_ui (f_jnq, f_j, n);
+      mpf_sub (Kt, f_x, f_jnq);
+      if (mpf_cmp (Kt, Km) > 0)
+	mpf_set (Km, Kt);
+
+      if (g_debug > DEBUG_2)
+	{
+	  printf ("jnq="); mpf_out_str (stdout, 10, 2, f_jnq); printf (" ");
+	  printf ("diff="); mpf_out_str (stdout, 10, 2, Kt); printf (" ");
+	  printf ("Km="); mpf_out_str (stdout, 10, 2, Km); printf (" ");
+	  printf ("\n");
+	}
+    }
+  mpf_sqrt_ui (Kt, n);
+  mpf_mul (Kp, Kp, Kt);
+  mpf_mul (Km, Km, Kt);
+
+  mpf_clear (Kt); mpf_clear (f_x); mpf_clear (f_j); mpf_clear (f_jnq);
+}
+
+/* ks_table(val, n) -- calculate probability for Kp/Km less than or
+   equal to VAL with N observations.  See [Knuth section 3.3.1] */
+
+void
+ks_table (mpf_t p, mpf_t val, const unsigned int n)
+{
+  /* We use Eq. (27), Knuth p.58, skipping O(1/n) for simplicity.
+     This shortcut will result in too high probabilities, especially
+     when n is small.
+
+     Pr(Kp(n) <= s) = 1 - pow(e, -2*s^2) * (1 - 2/3*s/sqrt(n) + O(1/n)) */
+
+  /* We have 's' in variable VAL and store the result in P. */
+
+  mpf_t t1, t2;
+
+  mpf_init (t1); mpf_init (t2);
+
+  /* t1 = 1 - 2/3 * s/sqrt(n) */
+  mpf_sqrt_ui (t1, n);
+  mpf_div (t1, val, t1);
+  mpf_mul_ui (t1, t1, 2);
+  mpf_div_ui (t1, t1, 3);
+  mpf_ui_sub (t1, 1, t1);
+
+  /* t2 = pow(e, -2*s^2) */
+#ifndef OLDGMP
+  mpf_pow_ui (t2, val, 2);	/* t2 = s^2 */
+  mpf_set_d (t2, exp (-(2.0 * mpf_get_d (t2))));
+#else
+  /* hmmm, gmp doesn't have pow() for floats.  use doubles. */
+  mpf_set_d (t2, pow (M_E, -(2 * pow (mpf_get_d (val), 2))));
+#endif
+
+  /* p = 1 - t1 * t2 */
+  mpf_mul (t1, t1, t2);
+  mpf_ui_sub (p, 1, t1);
+
+  mpf_clear (t1); mpf_clear (t2);
+}
+
+static double x2_table_X[][7] = {
+  { -2.33, -1.64, -.674, 0.0, 0.674, 1.64, 2.33 }, /* x */
+  { 5.4289, 2.6896, .454276, 0.0, .454276, 2.6896, 5.4289} /* x^2 */
+};
+
+#define _2D3 ((double) .6666666666)
+
+/* x2_table (t, v, n) -- return chi-square table row for V in T[]. */
+void
+x2_table (double t[],
+	  unsigned int v)
+{
+  int f;
+
+
+  /* FIXME: Do a table lookup for v <= 30 since the following formula
+     [Knuth, vol 2, 3.3.1] is only good for v > 30. */
+
+  /* value = v + sqrt(2*v) * X[p] + (2/3) * X[p]^2 - 2/3 + O(1/sqrt(t) */
+  /* NOTE: The O() term is ignored for simplicity. */
+
+  for (f = 0; f < 7; f++)
+      t[f] =
+	v +
+	sqrt (2 * v) * x2_table_X[0][f] +
+	_2D3 * x2_table_X[1][f] - _2D3;
+}
+
+
+/* P(p, x) -- Distribution function.  Calculate the probability of X
+being greater than or equal to any number in the sequence.  For a
+random real number between zero and one given by a uniformly
+distributed random number generator, this is simply equal to X. */
+
+static void
+P (mpf_t p, mpf_t x)
+{
+  mpf_set (p, x);
+}
+
+/* mpf_freqt() -- Frequency test using KS on N real numbers between zero
+   and one.  See [Knuth vol 2, p.61]. */
+void
+mpf_freqt (mpf_t Kp,
+	   mpf_t Km,
+	   mpf_t X[],
+	   const unsigned long int n)
+{
+  ks (Kp, Km, X, P, n);
+}
+
+
+/* The Chi-square test.  Eq. (8) in Knuth vol. 2 says that if Y[]
+   holds the observations and p[] is the probability for.. (to be
+   continued!)
+
+   V = 1/n * sum((s=1 to k) Y[s]^2 / p[s]) - n */
+
+void
+x2 (mpf_t V,			/* result */
+    unsigned long int X[],	/* data */
+    unsigned int k,		/* #of categories */
+    void (P) (mpf_t, unsigned long int, void *), /* probability func */
+    void *x,			/* extra user data passed to P() */
+    unsigned long int n)	/* #of samples */
+{
+  unsigned int f;
+  mpf_t f_t, f_t2;		/* temp floats */
+
+  mpf_init (f_t); mpf_init (f_t2);
+
+
+  mpf_set_ui (V, 0);
+  for (f = 0; f < k; f++)
+    {
+      if (g_debug > DEBUG_2)
+	fprintf (stderr, "%u: P()=", f);
+      mpf_set_ui (f_t, X[f]);
+      mpf_mul (f_t, f_t, f_t);	/* f_t = X[f]^2 */
+      P (f_t2, f, x);		/* f_t2 = Pr(f) */
+      if (g_debug > DEBUG_2)
+	mpf_out_str (stderr, 10, 2, f_t2);
+      mpf_div (f_t, f_t, f_t2);
+      mpf_add (V, V, f_t);
+      if (g_debug > DEBUG_2)
+	{
+	  fprintf (stderr, "\tV=");
+	  mpf_out_str (stderr, 10, 2, V);
+	  fprintf (stderr, "\t");
+	}
+    }
+  if (g_debug > DEBUG_2)
+    fprintf (stderr, "\n");
+  mpf_div_ui (V, V, n);
+  mpf_sub_ui (V, V, n);
+
+  mpf_clear (f_t); mpf_clear (f_t2);
+}
+
+/* Pzf(p, s, x) -- Probability for category S in mpz_freqt().  It's
+   1/d for all S.  X is a pointer to an unsigned int holding 'd'. */
+static void
+Pzf (mpf_t p, unsigned long int s, void *x)
+{
+  mpf_set_ui (p, 1);
+  mpf_div_ui (p, p, *((unsigned int *) x));
+}
+
+/* mpz_freqt(V, X, imax, n) -- Frequency test on integers.  [Knuth,
+   vol 2, 3.3.2].  Keep IMAX low on this one, since we loop from 0 to
+   IMAX.  128 or 256 could be nice.
+
+   X[] must not contain numbers outside the range 0 <= X <= IMAX.
+
+   Return value is number of observations actually used, after
+   discarding entries out of range.
+
+   Since X[] contains integers between zero and IMAX, inclusive, we
+   have IMAX+1 categories.
+
+   Note that N should be at least 5*IMAX.  Result is put in V and can
+   be compared to output from x2_table (v=IMAX). */
+
+unsigned long int
+mpz_freqt (mpf_t V,
+	   mpz_t X[],
+	   unsigned int imax,
+	   const unsigned long int n)
+{
+  unsigned long int *v;		/* result */
+  unsigned int f;
+  unsigned int d;		/* number of categories = imax+1 */
+  unsigned int uitemp;
+  unsigned long int usedn;
+
+
+  d = imax + 1;
+
+  v = (unsigned long int *) calloc (imax + 1, sizeof (unsigned long int));
+  if (NULL == v)
+    {
+      fprintf (stderr, "mpz_freqt(): out of memory\n");
+      exit (1);
+    }
+
+  /* count */
+  usedn = n;			/* actual number of observations */
+  for (f = 0; f < n; f++)
+    {
+      uitemp = mpz_get_ui(X[f]);
+      if (uitemp > imax)	/* sanity check */
+	{
+	  if (g_debug)
+	    fprintf (stderr, "mpz_freqt(): warning: input insanity: %u, "\
+		     "ignored.\n", uitemp);
+	  usedn--;
+	  continue;
+	}
+      v[uitemp]++;
+    }
+
+  if (g_debug > DEBUG_2)
+    {
+      fprintf (stderr, "counts:\n");
+      for (f = 0; f <= imax; f++)
+	fprintf (stderr, "%u:\t%lu\n", f, v[f]);
+    }
+
+  /* chi-square with k=imax+1 and P(x)=1/(imax+1) for all x.*/
+  x2 (V, v, d, Pzf, (void *) &d, usedn);
+
+  free (v);
+  return (usedn);
+}
+
+/* debug dummy to drag in dump funcs */
+void
+foo_debug ()
+{
+  if (0)
+    {
+      mpf_dump (0);
+#ifndef OLDGMP
+      mpz_dump (0);
+#endif
+    }
+}
+
+/* merit (rop, t, v, m) -- calculate merit for spectral test result in
+   dimension T, see Knuth p. 105.  BUGS: Only valid for 2 <= T <=
+   6. */
+void
+merit (mpf_t rop, unsigned int t, mpf_t v, mpz_t m)
+{
+  int f;
+  mpf_t f_m, f_const, f_pi;
+
+  mpf_init (f_m);
+  mpf_set_z (f_m, m);
+  mpf_init_set_d (f_const, M_PI);
+  mpf_init_set_d (f_pi, M_PI);
+
+  switch (t)
+    {
+    case 2:			/* PI */
+      break;
+    case 3:			/* PI * 4/3 */
+      mpf_mul_ui (f_const, f_const, 4);
+      mpf_div_ui (f_const, f_const, 3);
+      break;
+    case 4:			/* PI^2 * 1/2 */
+      mpf_mul (f_const, f_const, f_pi);
+      mpf_div_ui (f_const, f_const, 2);
+      break;
+    case 5:			/* PI^2 * 8/15 */
+      mpf_mul (f_const, f_const, f_pi);
+      mpf_mul_ui (f_const, f_const, 8);
+      mpf_div_ui (f_const, f_const, 15);
+      break;
+    case 6:			/* PI^3 * 1/6 */
+      mpf_mul (f_const, f_const, f_pi);
+      mpf_mul (f_const, f_const, f_pi);
+      mpf_div_ui (f_const, f_const, 6);
+      break;
+    default:
+      fprintf (stderr,
+	       "spect (merit): can't calculate merit for dimensions > 6\n");
+      mpf_set_ui (f_const, 0);
+      break;
+    }
+
+  /* rop = v^t */
+  mpf_set (rop, v);
+  for (f = 1; f < t; f++)
+    mpf_mul (rop, rop, v);
+  mpf_mul (rop, rop, f_const);
+  mpf_div (rop, rop, f_m);
+
+  mpf_clear (f_m);
+  mpf_clear (f_const);
+  mpf_clear (f_pi);
+}
+
+double
+merit_u (unsigned int t, mpf_t v, mpz_t m)
+{
+  mpf_t rop;
+  double res;
+
+  mpf_init (rop);
+  merit (rop, t, v, m);
+  res = mpf_get_d (rop);
+  mpf_clear (rop);
+  return res;
+}
+
+/* f_floor (rop, op) -- Set rop = floor (op). */
+void
+f_floor (mpf_t rop, mpf_t op)
+{
+  mpz_t z;
+
+  mpz_init (z);
+
+  /* No mpf_floor().  Convert to mpz and back. */
+  mpz_set_f (z, op);
+  mpf_set_z (rop, z);
+
+  mpz_clear (z);
+}
+
+
+/* vz_dot (rop, v1, v2, nelem) -- compute dot product of z-vectors V1,
+   V2.  N is number of elements in vectors V1 and V2. */
+
+void
+vz_dot (mpz_t rop, mpz_t V1[], mpz_t V2[], unsigned int n)
+{
+  mpz_t t;
+
+  mpz_init (t);
+  mpz_set_ui (rop, 0);
+  while (n--)
+    {
+      mpz_mul (t, V1[n], V2[n]);
+      mpz_add (rop, rop, t);
+    }
+
+  mpz_clear (t);
+}
+
+void
+spectral_test (mpf_t rop[], unsigned int T, mpz_t a, mpz_t m)
+{
+  /* Knuth "Seminumerical Algorithms, Third Edition", section 3.3.4
+     (pp. 101-103). */
+
+  /* v[t] = min { sqrt (x[1]^2 + ... + x[t]^2) |
+     x[1] + a*x[2] + ... + pow (a, t-1) * x[t] is congruent to 0 (mod m) } */
+
+
+  /* Variables. */
+  unsigned int ui_t;
+  unsigned int ui_i, ui_j, ui_k, ui_l;
+  mpf_t f_tmp1, f_tmp2;
+  mpz_t tmp1, tmp2, tmp3;
+  mpz_t U[GMP_SPECT_MAXT][GMP_SPECT_MAXT],
+    V[GMP_SPECT_MAXT][GMP_SPECT_MAXT],
+    X[GMP_SPECT_MAXT],
+    Y[GMP_SPECT_MAXT],
+    Z[GMP_SPECT_MAXT];
+  mpz_t h, hp, r, s, p, pp, q, u, v;
+
+  /* GMP inits. */
+  mpf_init (f_tmp1);
+  mpf_init (f_tmp2);
+  for (ui_i = 0; ui_i < GMP_SPECT_MAXT; ui_i++)
+    {
+      for (ui_j = 0; ui_j < GMP_SPECT_MAXT; ui_j++)
+	{
+	  mpz_init_set_ui (U[ui_i][ui_j], 0);
+	  mpz_init_set_ui (V[ui_i][ui_j], 0);
+	}
+      mpz_init_set_ui (X[ui_i], 0);
+      mpz_init_set_ui (Y[ui_i], 0);
+      mpz_init (Z[ui_i]);
+    }
+  mpz_init (tmp1);
+  mpz_init (tmp2);
+  mpz_init (tmp3);
+  mpz_init (h);
+  mpz_init (hp);
+  mpz_init (r);
+  mpz_init (s);
+  mpz_init (p);
+  mpz_init (pp);
+  mpz_init (q);
+  mpz_init (u);
+  mpz_init (v);
+
+  /* Implementation inits. */
+  if (T > GMP_SPECT_MAXT)
+    T = GMP_SPECT_MAXT;			/* FIXME: Lazy. */
+
+  /* S1 [Initialize.] */
+  ui_t = 2 - 1;			/* NOTE: `t' in description == ui_t + 1
+				   for easy indexing */
+  mpz_set (h, a);
+  mpz_set (hp, m);
+  mpz_set_ui (p, 1);
+  mpz_set_ui (pp, 0);
+  mpz_set (r, a);
+  mpz_pow_ui (s, a, 2);
+  mpz_add_ui (s, s, 1);		/* s = 1 + a^2 */
+
+  /* S2 [Euclidean step.] */
+  while (1)
+    {
+      if (g_debug > DEBUG_1)
+	{
+	  mpz_mul (tmp1, h, pp);
+	  mpz_mul (tmp2, hp, p);
+	  mpz_sub (tmp1, tmp1, tmp2);
+	  if (mpz_cmpabs (m, tmp1))
+	    {
+	      printf ("***BUG***: h*pp - hp*p = ");
+	      mpz_out_str (stdout, 10, tmp1);
+	      printf ("\n");
+	    }
+	}
+      if (g_debug > DEBUG_2)
+	{
+	  printf ("hp = ");
+	  mpz_out_str (stdout, 10, hp);
+	  printf ("\nh = ");
+	  mpz_out_str (stdout, 10, h);
+	  printf ("\n");
+	  fflush (stdout);
+	}
+
+      if (mpz_sgn (h))
+	mpz_tdiv_q (q, hp, h);	/* q = floor(hp/h) */
+      else
+	mpz_set_ui (q, 1);
+
+      if (g_debug > DEBUG_2)
+	{
+	  printf ("q = ");
+	  mpz_out_str (stdout, 10, q);
+	  printf ("\n");
+	  fflush (stdout);
+	}
+
+      mpz_mul (tmp1, q, h);
+      mpz_sub (u, hp, tmp1);	/* u = hp - q*h */
+
+      mpz_mul (tmp1, q, p);
+      mpz_sub (v, pp, tmp1);	/* v = pp - q*p */
+
+      mpz_pow_ui (tmp1, u, 2);
+      mpz_pow_ui (tmp2, v, 2);
+      mpz_add (tmp1, tmp1, tmp2);
+      if (mpz_cmp (tmp1, s) < 0)
+	{
+	  mpz_set (s, tmp1);	/* s = u^2 + v^2 */
+	  mpz_set (hp, h);	/* hp = h */
+	  mpz_set (h, u);	/* h = u */
+	  mpz_set (pp, p);	/* pp = p */
+	  mpz_set (p, v);	/* p = v */
+	}
+      else
+	break;
+    }
+
+  /* S3 [Compute v2.] */
+  mpz_sub (u, u, h);
+  mpz_sub (v, v, p);
+
+  mpz_pow_ui (tmp1, u, 2);
+  mpz_pow_ui (tmp2, v, 2);
+  mpz_add (tmp1, tmp1, tmp2);
+  if (mpz_cmp (tmp1, s) < 0)
+    {
+      mpz_set (s, tmp1);	/* s = u^2 + v^2 */
+      mpz_set (hp, u);
+      mpz_set (pp, v);
+    }
+  mpf_set_z (f_tmp1, s);
+  mpf_sqrt (rop[ui_t - 1], f_tmp1);
+
+  /* S4 [Advance t.] */
+  mpz_neg (U[0][0], h);
+  mpz_set (U[0][1], p);
+  mpz_neg (U[1][0], hp);
+  mpz_set (U[1][1], pp);
+
+  mpz_set (V[0][0], pp);
+  mpz_set (V[0][1], hp);
+  mpz_neg (V[1][0], p);
+  mpz_neg (V[1][1], h);
+  if (mpz_cmp_ui (pp, 0) > 0)
+    {
+      mpz_neg (V[0][0], V[0][0]);
+      mpz_neg (V[0][1], V[0][1]);
+      mpz_neg (V[1][0], V[1][0]);
+      mpz_neg (V[1][1], V[1][1]);
+    }
+
+  while (ui_t + 1 != T)		/* S4 loop */
+    {
+      ui_t++;
+      mpz_mul (r, a, r);
+      mpz_mod (r, r, m);
+
+      /* Add new row and column to U and V.  They are initialized with
+	 all elements set to zero, so clearing is not necessary. */
+
+      mpz_neg (U[ui_t][0], r); /* U: First col in new row. */
+      mpz_set_ui (U[ui_t][ui_t], 1); /* U: Last col in new row. */
+
+      mpz_set (V[ui_t][ui_t], m); /* V: Last col in new row. */
+
+      /* "Finally, for 1 <= i < t,
+	   set q = round (vi1 * r / m),
+	   vit = vi1*r - q*m,
+	   and Ut=Ut+q*Ui */
+
+      for (ui_i = 0; ui_i < ui_t; ui_i++)
+	{
+	  mpz_mul (tmp1, V[ui_i][0], r); /* tmp1=vi1*r */
+	  zdiv_round (q, tmp1, m); /* q=round(vi1*r/m) */
+	  mpz_mul (tmp2, q, m);	/* tmp2=q*m */
+	  mpz_sub (V[ui_i][ui_t], tmp1, tmp2);
+
+	  for (ui_j = 0; ui_j <= ui_t; ui_j++) /* U[t] = U[t] + q*U[i] */
+	    {
+	      mpz_mul (tmp1, q, U[ui_i][ui_j]);	/* tmp=q*uij */
+	      mpz_add (U[ui_t][ui_j], U[ui_t][ui_j], tmp1); /* utj = utj + q*uij */
+	    }
+	}
+
+      /* s = min (s, zdot (U[t], U[t]) */
+      vz_dot (tmp1, U[ui_t], U[ui_t], ui_t + 1);
+      if (mpz_cmp (tmp1, s) < 0)
+	mpz_set (s, tmp1);
+
+      ui_k = ui_t;
+      ui_j = 0;			/* WARNING: ui_j no longer a temp. */
+
+      /* S5 [Transform.] */
+      if (g_debug > DEBUG_2)
+	printf ("(t, k, j, q1, q2, ...)\n");
+      do
+	{
+	  if (g_debug > DEBUG_2)
+	    printf ("(%u, %u, %u", ui_t + 1, ui_k + 1, ui_j + 1);
+
+	  for (ui_i = 0; ui_i <= ui_t; ui_i++)
+	    {
+	      if (ui_i != ui_j)
+		{
+		  vz_dot (tmp1, V[ui_i], V[ui_j], ui_t + 1); /* tmp1=dot(Vi,Vj). */
+		  mpz_abs (tmp2, tmp1);
+		  mpz_mul_ui (tmp2, tmp2, 2); /* tmp2 = 2*abs(dot(Vi,Vj) */
+		  vz_dot (tmp3, V[ui_j], V[ui_j], ui_t + 1); /* tmp3=dot(Vj,Vj). */
+
+		  if (mpz_cmp (tmp2, tmp3) > 0)
+		    {
+		      zdiv_round (q, tmp1, tmp3); /* q=round(Vi.Vj/Vj.Vj) */
+		      if (g_debug > DEBUG_2)
+			{
+			  printf (", ");
+			  mpz_out_str (stdout, 10, q);
+			}
+
+		      for (ui_l = 0; ui_l <= ui_t; ui_l++)
+			{
+			  mpz_mul (tmp1, q, V[ui_j][ui_l]);
+			  mpz_sub (V[ui_i][ui_l], V[ui_i][ui_l], tmp1); /* Vi=Vi-q*Vj */
+			  mpz_mul (tmp1, q, U[ui_i][ui_l]);
+			  mpz_add (U[ui_j][ui_l], U[ui_j][ui_l], tmp1); /* Uj=Uj+q*Ui */
+			}
+
+		      vz_dot (tmp1, U[ui_j], U[ui_j], ui_t + 1); /* tmp1=dot(Uj,Uj) */
+		      if (mpz_cmp (tmp1, s) < 0) /* s = min(s,dot(Uj,Uj)) */
+			mpz_set (s, tmp1);
+		      ui_k = ui_j;
+		    }
+		  else if (g_debug > DEBUG_2)
+		    printf (", #"); /* 2|Vi.Vj| <= Vj.Vj */
+		}
+	      else if (g_debug > DEBUG_2)
+		printf (", *");	/* i == j */
+	    }
+
+	  if (g_debug > DEBUG_2)
+	    printf (")\n");
+
+	  /* S6 [Advance j.] */
+	  if (ui_j == ui_t)
+	    ui_j = 0;
+	  else
+	    ui_j++;
+	}
+      while (ui_j != ui_k);	/* S5 */
+
+      /* From Knuth p. 104: "The exhaustive search in steps S8-S10
+	 reduces the value of s only rarely." */
+#ifdef DO_SEARCH
+      /* S7 [Prepare for search.] */
+      /* Find minimum in (x[1], ..., x[t]) satisfying condition
+	 x[k]^2 <= f(y[1], ...,y[t]) * dot(V[k],V[k]) */
+
+      ui_k = ui_t;
+      if (g_debug > DEBUG_2)
+	{
+	  printf ("searching...");
+	  /*for (f = 0; f < ui_t*/
+	  fflush (stdout);
+	}
+
+      /* Z[i] = floor (sqrt (floor (dot(V[i],V[i]) * s / m^2))); */
+      mpz_pow_ui (tmp1, m, 2);
+      mpf_set_z (f_tmp1, tmp1);
+      mpf_set_z (f_tmp2, s);
+      mpf_div (f_tmp1, f_tmp2, f_tmp1);	/* f_tmp1 = s/m^2 */
+      for (ui_i = 0; ui_i <= ui_t; ui_i++)
+	{
+	  vz_dot (tmp1, V[ui_i], V[ui_i], ui_t + 1);
+	  mpf_set_z (f_tmp2, tmp1);
+	  mpf_mul (f_tmp2, f_tmp2, f_tmp1);
+	  f_floor (f_tmp2, f_tmp2);
+	  mpf_sqrt (f_tmp2, f_tmp2);
+	  mpz_set_f (Z[ui_i], f_tmp2);
+	}
+
+      /* S8 [Advance X[k].] */
+      do
+	{
+	  if (g_debug > DEBUG_2)
+	    {
+	      printf ("X[%u] = ", ui_k);
+	      mpz_out_str (stdout, 10, X[ui_k]);
+	      printf ("\tZ[%u] = ", ui_k);
+	      mpz_out_str (stdout, 10, Z[ui_k]);
+	      printf ("\n");
+	      fflush (stdout);
+	    }
+
+	  if (mpz_cmp (X[ui_k], Z[ui_k]))
+	    {
+	      mpz_add_ui (X[ui_k], X[ui_k], 1);
+	      for (ui_i = 0; ui_i <= ui_t; ui_i++)
+		mpz_add (Y[ui_i], Y[ui_i], U[ui_k][ui_i]);
+
+	      /* S9 [Advance k.] */
+	      while (++ui_k <= ui_t)
+		{
+		  mpz_neg (X[ui_k], Z[ui_k]);
+		  mpz_mul_ui (tmp1, Z[ui_k], 2);
+		  for (ui_i = 0; ui_i <= ui_t; ui_i++)
+		    {
+		      mpz_mul (tmp2, tmp1, U[ui_k][ui_i]);
+		      mpz_sub (Y[ui_i], Y[ui_i], tmp2);
+		    }
+		}
+	      vz_dot (tmp1, Y, Y, ui_t + 1);
+	      if (mpz_cmp (tmp1, s) < 0)
+		mpz_set (s, tmp1);
+	    }
+	}
+      while (--ui_k);
+#endif /* DO_SEARCH */
+      mpf_set_z (f_tmp1, s);
+      mpf_sqrt (rop[ui_t - 1], f_tmp1);
+#ifdef DO_SEARCH
+      if (g_debug > DEBUG_2)
+	printf ("done.\n");
+#endif /* DO_SEARCH */
+    } /* S4 loop */
+
+  /* Clear GMP variables. */
+
+  mpf_clear (f_tmp1);
+  mpf_clear (f_tmp2);
+  for (ui_i = 0; ui_i < GMP_SPECT_MAXT; ui_i++)
+    {
+      for (ui_j = 0; ui_j < GMP_SPECT_MAXT; ui_j++)
+	{
+	  mpz_clear (U[ui_i][ui_j]);
+	  mpz_clear (V[ui_i][ui_j]);
+	}
+      mpz_clear (X[ui_i]);
+      mpz_clear (Y[ui_i]);
+      mpz_clear (Z[ui_i]);
+    }
+  mpz_clear (tmp1);
+  mpz_clear (tmp2);
+  mpz_clear (tmp3);
+  mpz_clear (h);
+  mpz_clear (hp);
+  mpz_clear (r);
+  mpz_clear (s);
+  mpz_clear (p);
+  mpz_clear (pp);
+  mpz_clear (q);
+  mpz_clear (u);
+  mpz_clear (v);
+
+  return;
+}
diff --git a/third_party/gmp/tests/rand/t-iset.c b/third_party/gmp/tests/rand/t-iset.c
new file mode 100644
index 0000000..884220f
--- /dev/null
+++ b/third_party/gmp/tests/rand/t-iset.c
@@ -0,0 +1,67 @@
+/* Test gmp_randinit_set.
+
+Copyright 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+/* expect after a gmp_randinit_set that the new and old generators will
+   produce the same sequence of numbers */
+void
+check_one (const char *name, gmp_randstate_ptr src)
+{
+  gmp_randstate_t dst;
+  mpz_t  sz, dz;
+  int    i;
+
+  gmp_randinit_set (dst, src);
+  mpz_init (sz);
+  mpz_init (dz);
+
+  for (i = 0; i < 20; i++)
+    {
+      mpz_urandomb (sz, src, 123);
+      mpz_urandomb (dz, dst, 123);
+
+      if (mpz_cmp (sz, dz) != 0)
+        {
+          printf     ("gmp_randinit_set didn't duplicate randstate\n");
+          printf     ("  algorithm: %s\n", name);
+          gmp_printf ("  from src:  %#Zx\n", sz);
+          gmp_printf ("  from dst:  %#Zx\n", dz);
+          abort ();
+        }
+    }
+
+  mpz_clear (sz);
+  mpz_clear (dz);
+  gmp_randclear (dst);
+}
+
+int
+main (int argc, char *argv[])
+{
+  tests_start ();
+
+  call_rand_algs (check_one);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/rand/t-lc2exp.c b/third_party/gmp/tests/rand/t-lc2exp.c
new file mode 100644
index 0000000..c66691d
--- /dev/null
+++ b/third_party/gmp/tests/rand/t-lc2exp.c
@@ -0,0 +1,216 @@
+/* Exercise the lc2exp random functions.
+
+Copyright 2002, 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+/* a=0 and c=0 produces zero results always. */
+void
+check_zero (unsigned long m2exp)
+{
+  gmp_randstate_t  r;
+  mpz_t            a;
+  unsigned long    c;
+  int              i;
+
+  mpz_init_set_ui (a, 0L);
+  c = 0L;
+
+  gmp_randinit_lc_2exp (r, a, c, m2exp);
+  gmp_randseed_ui (r, 0L);
+
+  for (i = 0; i < 5; i++)
+    {
+      mpz_urandomb (a, r, 123L);
+      if (mpz_sgn (a) != 0)
+        {
+          printf ("check_zero m2exp=%lu: didn't get zero\n", m2exp);
+          gmp_printf ("  rand=%#Zx\n", a);
+          abort ();
+        }
+    }
+
+  mpz_clear (a);
+  gmp_randclear (r);
+}
+
+/* negative a */
+void
+check_nega (void)
+{
+  gmp_randstate_t  r;
+  mpz_t            a;
+  unsigned long    c, m2exp;
+  int              i;
+
+  mpz_init (a);
+  mpz_setbit (a, 1000L);
+  mpz_neg (a, a);
+  c = 0L;
+  m2exp = 45L;
+
+  gmp_randinit_lc_2exp (r, a, c, m2exp);
+  gmp_randseed_ui (r, 0L);
+
+  for (i = 0; i < 5; i++)
+    {
+      mpz_urandomb (a, r, 123L);
+      if (mpz_sgn (a) != 0)
+        printf ("check_nega m2exp=%lu: didn't get zero\n", m2exp);
+    }
+
+  mpz_clear (a);
+  gmp_randclear (r);
+}
+
+void
+check_bigc (void)
+{
+  gmp_randstate_t  r;
+  mpz_t            a;
+  unsigned long    c, m2exp, bits;
+  int              i;
+
+  mpz_init_set_ui (a, 0L);
+  c = ULONG_MAX;
+  m2exp = 8;
+
+  gmp_randinit_lc_2exp (r, a, c, m2exp);
+  gmp_randseed_ui (r, 0L);
+
+  for (i = 0; i < 20; i++)
+    {
+      bits = 123L;
+      mpz_urandomb (a, r, bits);
+      if (mpz_sgn (a) < 0 || mpz_sizeinbase (a, 2) > bits)
+        {
+          printf     ("check_bigc: mpz_urandomb out of range\n");
+          printf     ("   m2exp=%lu\n", m2exp);
+          gmp_printf ("   rand=%#ZX\n", a);
+          gmp_printf ("   sizeinbase2=%u\n", mpz_sizeinbase (a, 2));
+	  abort ();
+        }
+    }
+
+  mpz_clear (a);
+  gmp_randclear (r);
+}
+
+void
+check_bigc1 (void)
+{
+  gmp_randstate_t  r;
+  mpz_t            a;
+  unsigned long    c, m2exp;
+  int              i;
+
+  mpz_init_set_ui (a, 0L);
+  c = ULONG_MAX;
+  m2exp = 2;
+
+  gmp_randinit_lc_2exp (r, a, c, m2exp);
+  gmp_randseed_ui (r, 0L);
+
+  for (i = 0; i < 20; i++)
+    {
+      mpz_urandomb (a, r, 1L);
+      if (mpz_cmp_ui (a, 1L) != 0)
+        {
+          printf     ("check_bigc1: mpz_urandomb didn't give 1\n");
+          printf     ("   m2exp=%lu\n", m2exp);
+          gmp_printf ("   got rand=%#ZX\n", a);
+          abort ();
+        }
+    }
+
+  mpz_clear (a);
+  gmp_randclear (r);
+}
+
+/* Checks parameters which triggered an assertion failure in the past.
+   Happened when limbs(a)+limbs(c) < bits_to_limbs(m2exp).  */
+void
+check_bigm (void)
+{
+  gmp_randstate_t rstate;
+  mpz_t a;
+
+  mpz_init_set_ui (a, 5L);
+  gmp_randinit_lc_2exp (rstate, a, 1L, 384L);
+
+  mpz_urandomb (a, rstate, 20L);
+
+  gmp_randclear (rstate);
+  mpz_clear (a);
+}
+
+/* Checks for seeds bigger than the modulus.  */
+void
+check_bigs (void)
+{
+  gmp_randstate_t rstate;
+  mpz_t sd, a;
+  int i;
+
+  mpz_init (sd);
+  mpz_setbit (sd, 300L);
+  mpz_sub_ui (sd, sd, 1L);
+  mpz_clrbit (sd, 13L);
+  mpz_init_set_ui (a, 123456789L);
+
+  gmp_randinit_lc_2exp (rstate, a, 5L, 64L);
+
+  for (i = 0; i < 20; i++)
+    {
+      mpz_neg (sd, sd);
+      gmp_randseed (rstate, sd);
+      mpz_mul_ui (sd, sd, 7L);
+
+      mpz_urandomb (a, rstate, 80L);
+    }
+
+  gmp_randclear (rstate);
+  mpz_clear (a);
+  mpz_clear (sd);
+}
+
+int
+main (void)
+{
+  tests_start ();
+
+  check_zero (2L);
+  check_zero (7L);
+  check_zero (32L);
+  check_zero (64L);
+  check_zero (1000L);
+
+  check_nega ();
+  check_bigc ();
+  check_bigc1 ();
+
+  check_bigm ();
+  check_bigs ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/rand/t-mt.c b/third_party/gmp/tests/rand/t-mt.c
new file mode 100644
index 0000000..08ba7fc
--- /dev/null
+++ b/third_party/gmp/tests/rand/t-mt.c
@@ -0,0 +1,82 @@
+/* Test the Mersenne Twister random number generator.
+
+Copyright 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+#ifndef TRUE
+#define TRUE (1)
+#endif
+#ifndef FALSE
+#define FALSE (0)
+#endif
+
+/* Test that the sequence without seeding equals the sequence with the
+   default seed.  */
+int
+chk_default_seed (void)
+{
+  gmp_randstate_t r1, r2;
+  mpz_t a, b;
+  int i;
+  int ok = TRUE;
+
+  mpz_init2 (a, 19936L);
+  mpz_init2 (b, 19936L);
+
+  gmp_randinit_mt (r1);
+  gmp_randinit_mt (r2);
+  gmp_randseed_ui (r2, 5489L); /* Must match DEFAULT_SEED in randmt.c */
+  for (i = 0; i < 3; i++)
+    {
+      /* Extract one whole buffer per iteration.  */
+      mpz_urandomb (a, r1, 19936L);
+      mpz_urandomb (b, r2, 19936L);
+      if (mpz_cmp (a, b) != 0)
+	{
+	  ok = FALSE;
+	  printf ("Default seed fails in iteration %d\n", i);
+	  break;
+	}
+    }
+  gmp_randclear (r1);
+  gmp_randclear (r2);
+
+  mpz_clear (a);
+  mpz_clear (b);
+  return ok;
+}
+
+int
+main (int argc, char *argv[])
+{
+  int ok;
+
+  tests_start ();
+
+  ok = chk_default_seed ();
+
+  tests_end ();
+
+  if (ok)
+    return 0; /* pass */
+  else
+    return 1; /* fail */
+}
diff --git a/third_party/gmp/tests/rand/t-rand.c b/third_party/gmp/tests/rand/t-rand.c
new file mode 100644
index 0000000..1265a0d
--- /dev/null
+++ b/third_party/gmp/tests/rand/t-rand.c
@@ -0,0 +1,290 @@
+/* t-rand -- Test random number generators.  */
+
+/*
+Copyright 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "gmp.h"
+
+#define SEED 1
+#define BASE 16
+#define ENTS 10			/* Number of entries in array when
+				   printing.  */
+
+/* These were generated by this very program.  Do not edit!  */
+/* Integers.  */
+const char *z1[ENTS] = {"0", "1", "1", "1", "1", "0", "1", "1", "1", "1"};
+const char *z2[ENTS] = {"0", "3", "1", "3", "3", "0", "3", "3", "3", "1"};
+const char *z3[ENTS] = {"4", "3", "1", "7", "3", "0", "3", "3", "3", "1"};
+const char *z4[ENTS] = {"c", "3", "1", "f", "b", "8", "3", "3", "3", "1"};
+const char *z5[ENTS] = {"1c", "13", "11", "1f", "b", "18", "3", "13", "3", "1"};
+
+const char *z10[ENTS] = {"29c", "213", "f1", "17f", "12b", "178", "383", "d3", "3a3", "281"};
+
+const char *z15[ENTS] = {"29c", "1a13", "74f1", "257f", "592b", "4978", "4783", "7cd3", "5ba3", "4681"};
+const char *z16[ENTS] = {"29c", "9a13", "74f1", "a57f", "d92b", "4978", "c783", "fcd3", "5ba3", "c681"};
+const char *z17[ENTS] = {"51e", "f17a", "54ff", "1a335", "cf65", "5d6f", "583f", "618f", "1bc6", "98ff"};
+
+const char *z31[ENTS] = {"3aecd515", "13ae8ec6", "518c8090", "81ca077", "70b7134", "7ee78d71", "323a7636", "2122cb1a", "19811941", "41fd605"};
+const char *z32[ENTS] = {"baecd515", "13ae8ec6", "518c8090", "881ca077", "870b7134", "7ee78d71", "323a7636", "a122cb1a", "99811941", "841fd605"};
+const char *z33[ENTS] = {"1faf4cca", "15d6ef83b", "9095fe72", "1b6a3dff6", "b17cbddd", "16e5209d4", "6f65b12c", "493bbbc6", "abf2a5d5", "6d491a3c"};
+
+const char *z63[ENTS] = {"48a74f367fa7b5c8", "3ba9e9dc1b263076", "1e0ac84e7678e0fb", "11416581728b3e35", "36ab610523f0f1f7", "3e540e8e95c0eb4b", "439ae16057dbc9d3", "734fb260db243950", "7d3a317effc289bf", "1d80301fb3d1a0d1"};
+const char *z64[ENTS] = {"48a74f367fa7b5c8", "bba9e9dc1b263076", "9e0ac84e7678e0fb", "11416581728b3e35", "b6ab610523f0f1f7", "be540e8e95c0eb4b", "439ae16057dbc9d3", "f34fb260db243950", "fd3a317effc289bf", "1d80301fb3d1a0d1"};
+const char *z65[ENTS] = {"1ff77710d846d49f0", "1b1411701d709ee10", "31ffa81a208b6af4", "446638d431d3c681", "df5c569d5baa8b55", "197d99ea9bf28e5a0", "191ade09edd94cfae", "194acefa6dde5e18d", "1afc1167c56272d92", "d092994da72f206f"};
+
+const char *z127[ENTS] = {"2f66ba932aaf58a071fd8f0742a99a0c", "73cfa3c664c9c1753507ca60ec6b8425", "53ea074ca131dec12cd68b8aa8e20278", "3cf5ac8c343532f8a53cc0eb47581f73", "50c11d5869e208aa1b9aa317b8c2d0a9", "b23163c892876472b1ef19642eace09", "489f4c03d41f87509c8d6c90ce674f95", "2ab8748c96aa6762ea1932b44c9d7164", "98cb5591fc05ad31afbbc1d67b90edd", "77848bb991fd0be331adcf1457fbc672"};
+const char *z128[ENTS] = {"af66ba932aaf58a071fd8f0742a99a0c", "73cfa3c664c9c1753507ca60ec6b8425", "53ea074ca131dec12cd68b8aa8e20278", "3cf5ac8c343532f8a53cc0eb47581f73", "50c11d5869e208aa1b9aa317b8c2d0a9", "8b23163c892876472b1ef19642eace09", "489f4c03d41f87509c8d6c90ce674f95", "aab8748c96aa6762ea1932b44c9d7164", "98cb5591fc05ad31afbbc1d67b90edd", "f7848bb991fd0be331adcf1457fbc672"};
+
+/* Floats.  */
+const char *f1[ENTS] = {"0.@0", "0.8@0", "0.8@0", "0.8@0", "0.8@0", "0.@0", "0.8@0", "0.8@0", "0.8@0", "0.8@0"};
+const char *f2[ENTS] = {"0.@0", "0.c@0", "0.4@0", "0.c@0", "0.c@0", "0.@0", "0.c@0", "0.c@0", "0.c@0", "0.4@0"};
+const char *f3[ENTS] = {"0.8@0", "0.6@0", "0.2@0", "0.e@0", "0.6@0", "0.@0", "0.6@0", "0.6@0", "0.6@0", "0.2@0"};
+const char *f4[ENTS] = {"0.c@0", "0.3@0", "0.1@0", "0.f@0", "0.b@0", "0.8@0", "0.3@0", "0.3@0", "0.3@0", "0.1@0"};
+const char *f5[ENTS] = {"0.e@0", "0.98@0", "0.88@0", "0.f8@0", "0.58@0", "0.c@0", "0.18@0", "0.98@0", "0.18@0", "0.8@-1"};
+
+const char *f10[ENTS] = {"0.a7@0", "0.84c@0", "0.3c4@0", "0.5fc@0", "0.4ac@0", "0.5e@0", "0.e0c@0", "0.34c@0", "0.e8c@0", "0.a04@0"};
+
+const char *f15[ENTS] = {"0.538@-1", "0.3426@0", "0.e9e2@0", "0.4afe@0", "0.b256@0", "0.92f@0", "0.8f06@0", "0.f9a6@0", "0.b746@0", "0.8d02@0"};
+const char *f16[ENTS] = {"0.29c@-1", "0.9a13@0", "0.74f1@0", "0.a57f@0", "0.d92b@0", "0.4978@0", "0.c783@0", "0.fcd3@0", "0.5ba3@0", "0.c681@0"};
+const char *f17[ENTS] = {"0.28f@-1", "0.78bd@0", "0.2a7f8@0", "0.d19a8@0", "0.67b28@0", "0.2eb78@0", "0.2c1f8@0", "0.30c78@0", "0.de3@-1", "0.4c7f8@0"};
+
+const char *f31[ENTS] = {"0.75d9aa2a@0", "0.275d1d8c@0", "0.a319012@0", "0.103940ee@0", "0.e16e268@-1", "0.fdcf1ae2@0", "0.6474ec6c@0", "0.42459634@0", "0.33023282@0", "0.83fac0a@-1"};
+const char *f32[ENTS] = {"0.baecd515@0", "0.13ae8ec6@0", "0.518c809@0", "0.881ca077@0", "0.870b7134@0", "0.7ee78d71@0", "0.323a7636@0", "0.a122cb1a@0", "0.99811941@0", "0.841fd605@0"};
+const char *f33[ENTS] = {"0.fd7a665@-1", "0.aeb77c1d8@0", "0.484aff39@0", "0.db51effb@0", "0.58be5eee8@0", "0.b72904ea@0", "0.37b2d896@0", "0.249ddde3@0", "0.55f952ea8@0", "0.36a48d1e@0"};
+
+const char *f63[ENTS] = {"0.914e9e6cff4f6b9@0", "0.7753d3b8364c60ec@0", "0.3c15909cecf1c1f6@0", "0.2282cb02e5167c6a@0", "0.6d56c20a47e1e3ee@0", "0.7ca81d1d2b81d696@0", "0.8735c2c0afb793a6@0", "0.e69f64c1b64872a@0", "0.fa7462fdff85137e@0", "0.3b00603f67a341a2@0"};
+const char *f64[ENTS] = {"0.48a74f367fa7b5c8@0", "0.bba9e9dc1b263076@0", "0.9e0ac84e7678e0fb@0", "0.11416581728b3e35@0", "0.b6ab610523f0f1f7@0", "0.be540e8e95c0eb4b@0", "0.439ae16057dbc9d3@0", "0.f34fb260db24395@0", "0.fd3a317effc289bf@0", "0.1d80301fb3d1a0d1@0"};
+const char *f65[ENTS] = {"0.ffbbb886c236a4f8@0", "0.d8a08b80eb84f708@0", "0.18ffd40d1045b57a@0", "0.22331c6a18e9e3408@0", "0.6fae2b4eadd545aa8@0", "0.cbeccf54df9472d@0", "0.c8d6f04f6eca67d7@0", "0.ca5677d36ef2f0c68@0", "0.d7e08b3e2b1396c9@0", "0.68494ca6d39790378@0"};
+
+const char *f127[ENTS] = {"0.5ecd7526555eb140e3fb1e0e85533418@0", "0.e79f478cc99382ea6a0f94c1d8d7084a@0", "0.a7d40e994263bd8259ad171551c404f@0", "0.79eb5918686a65f14a7981d68eb03ee6@0", "0.a1823ab0d3c411543735462f7185a152@0", "0.16462c791250ec8e563de32c85d59c12@0", "0.913e9807a83f0ea1391ad9219cce9f2a@0", "0.5570e9192d54cec5d4326568993ae2c8@0", "0.13196ab23f80b5a635f7783acf721dba@0", "0.ef09177323fa17c6635b9e28aff78ce4@0"};
+const char *f128[ENTS] = {"0.af66ba932aaf58a071fd8f0742a99a0c@0", "0.73cfa3c664c9c1753507ca60ec6b8425@0", "0.53ea074ca131dec12cd68b8aa8e20278@0", "0.3cf5ac8c343532f8a53cc0eb47581f73@0", "0.50c11d5869e208aa1b9aa317b8c2d0a9@0", "0.8b23163c892876472b1ef19642eace09@0", "0.489f4c03d41f87509c8d6c90ce674f95@0", "0.aab8748c96aa6762ea1932b44c9d7164@0", "0.98cb5591fc05ad31afbbc1d67b90edd@-1", "0.f7848bb991fd0be331adcf1457fbc672@0"};
+
+
+struct rt
+{
+  const char **s;
+  int nbits;
+};
+
+static struct rt zarr[] =
+{
+  {z1, 1},
+  {z2, 2},
+  {z3, 3},
+  {z4, 4},
+  {z5, 5},
+  {z10, 10},
+  {z15, 15},
+  {z16, 16},
+  {z17, 17},
+  {z31, 31},
+  {z32, 32},
+  {z33, 33},
+  {z63, 63},
+  {z64, 64},
+  {z65, 65},
+  {z127, 127},
+  {z128, 128},
+  {NULL, 0}
+};
+
+static struct rt farr[] =
+{
+  {f1, 1},
+  {f2, 2},
+  {f3, 3},
+  {f4, 4},
+  {f5, 5},
+  {f10, 10},
+  {f15, 15},
+  {f16, 16},
+  {f17, 17},
+  {f31, 31},
+  {f32, 32},
+  {f33, 33},
+  {f63, 63},
+  {f64, 64},
+  {f65, 65},
+  {f127, 127},
+  {f128, 128},
+  {NULL, 0}
+};
+
+
+int
+main (int argc, char *argv[])
+{
+  static char usage[] = "\
+usage: t-rand [function nbits]\n\
+  function is one of z, f\n\
+  nbits is number of bits\n\
+";
+  gmp_randstate_t rstate;
+  mpz_t z, rz;
+  mpf_t f, rf;
+  enum { Z, F } func = Z;
+  int nbits = 1;
+  int verify_mode_flag = 1;
+  int i;
+  struct rt *a;
+
+
+  if (argc > 1)
+    {
+      if (argc < 3)
+	{
+	  fputs (usage, stderr);
+	  exit (1);
+	}
+      verify_mode_flag = 0;
+      if (*argv[1] == 'z')
+	func = Z;
+      if (*argv[1] == 'f')
+	func = F;
+      nbits = atoi (argv[2]);
+    }
+
+  mpz_init (rz);
+
+  if (verify_mode_flag)
+    {
+#ifdef VERBOSE
+      printf ("%s: verifying random numbers: ", argv[0]);
+#endif
+
+      /* Test z.  */
+      mpz_init (z);
+      for (a = zarr; a->s != NULL; a++)
+	{
+	  gmp_randinit (rstate, GMP_RAND_ALG_LC, a->nbits);
+	  if (gmp_errno != GMP_ERROR_NONE)
+	    exit (1);
+	  gmp_randseed_ui (rstate, SEED);
+
+	  for (i = 0; i < ENTS; i++)
+	    {
+	      mpz_urandomb (rz, rstate, a->nbits);
+	      mpz_set_str (z, a->s[i], BASE);
+	      if (mpz_cmp (z, rz) != 0)
+		{
+		  printf ("z%d: ", a->nbits);
+		  mpz_out_str (stdout, BASE, rz);
+		  printf (" should be ");
+		  mpz_out_str (stdout, BASE, z);
+		  puts ("");
+		  exit (1);
+		}
+	    }
+#ifdef VERBOSE
+	  printf ("z%d ", a->nbits);
+#endif
+	  gmp_randclear (rstate);
+	}
+      mpz_clear (z);
+
+
+      /* Test f.  */
+      for (a = farr; a->s != NULL; a++)
+	{
+	  gmp_randinit (rstate, GMP_RAND_ALG_LC, a->nbits);
+	  if (gmp_errno != GMP_ERROR_NONE)
+	    exit (1);
+	  gmp_randseed_ui (rstate, SEED);
+
+	  mpf_init2 (f, a->nbits);
+	  mpf_init2 (rf, a->nbits);
+	  for (i = 0; i < ENTS; i++)
+	    {
+	      mpf_urandomb (rf, rstate, a->nbits);
+	      mpf_set_str (f, a->s[i], BASE);
+	      if (mpf_cmp (f, rf) != 0)
+		{
+		  printf ("f%d: ", a->nbits);
+		  mpf_out_str (stdout, BASE, a->nbits, rf);
+		  printf (" should be ");
+		  mpf_out_str (stdout, BASE, a->nbits, f);
+		  puts ("");
+		  exit (1);
+		}
+	    }
+#ifdef VERBOSE
+	  printf ("f%d ", a->nbits);
+#endif
+	  gmp_randclear (rstate);
+	  mpf_clear (f);
+	  mpf_clear (rf);
+	}
+
+#ifdef VERBOSE
+      puts ("");
+#endif
+    }
+  else				/* Print mode.  */
+    {
+      gmp_randinit (rstate, GMP_RAND_ALG_LC, nbits);
+      if (gmp_errno != GMP_ERROR_NONE)
+	exit (1);
+      gmp_randseed_ui (rstate, SEED);
+
+      switch (func)
+	{
+	case Z:
+	  printf ("char *z%d[ENTS] = {", nbits);
+	  for (i = 0; i < ENTS; i++)
+	    {
+	      mpz_urandomb (rz, rstate, nbits);
+	      printf ("\"");
+	      mpz_out_str (stdout, BASE, rz);
+	      printf ("\"");
+	      if (i != ENTS - 1)
+		printf (", ");
+	    }
+	  printf ("};\n");
+	  printf ("  {z%d, %d},\n", nbits, nbits);
+	  break;
+
+	case F:
+	  printf ("char *f%d[ENTS] = {", nbits);
+	  mpf_init2 (rf, nbits);
+	  for (i = 0; i < ENTS; i++)
+	    {
+	      mpf_urandomb (rf, rstate, nbits);
+	      printf ("\"");
+	      mpf_out_str (stdout, BASE, nbits, rf);
+	      printf ("\"");
+	      if (i != ENTS - 1)
+		printf (", ");
+	    }
+	  printf ("};\n");
+	  printf ("  {f%d, %d},\n", nbits, nbits);
+	  mpf_clear (rf);
+	  break;
+
+	default:
+	  exit (1);
+	}
+
+      gmp_randclear (rstate);
+    }
+
+  mpz_clear (rz);
+
+  return 0;
+}
diff --git a/third_party/gmp/tests/rand/t-urbui.c b/third_party/gmp/tests/rand/t-urbui.c
new file mode 100644
index 0000000..f56f538
--- /dev/null
+++ b/third_party/gmp/tests/rand/t-urbui.c
@@ -0,0 +1,64 @@
+/* Test gmp_urandomb_ui.
+
+Copyright 2003, 2005 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+/* Expect numbers generated by rstate to obey the number of bits requested.
+   No point testing bits==BITS_PER_ULONG, since any return is acceptable in
+   that case.  */
+void
+check_one (const char *name, gmp_randstate_ptr rstate)
+{
+  unsigned long  bits, limit, got;
+  int    i;
+
+  for (bits = 0; bits < BITS_PER_ULONG; bits++)
+    {
+      /* will demand got < limit */
+      limit = (1UL << bits);
+
+      for (i = 0; i < 5; i++)
+        {
+          got = gmp_urandomb_ui (rstate, bits);
+          if (got >= limit)
+            {
+              printf ("Return value out of range:\n");
+              printf ("  algorithm: %s\n", name);
+              printf ("  bits:  %lu\n", bits);
+              printf ("  limit: %#lx\n", limit);
+              printf ("  got:   %#lx\n", got);
+              abort ();
+            }
+        }
+    }
+}
+
+int
+main (int argc, char *argv[])
+{
+  tests_start ();
+
+  call_rand_algs (check_one);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/rand/t-urmui.c b/third_party/gmp/tests/rand/t-urmui.c
new file mode 100644
index 0000000..cc8fedb
--- /dev/null
+++ b/third_party/gmp/tests/rand/t-urmui.c
@@ -0,0 +1,74 @@
+/* Test gmp_urandomm_ui.
+
+Copyright 2003, 2005 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+/* Expect numbers generated by rstate to obey the limit requested. */
+void
+check_one (const char *name, gmp_randstate_ptr rstate)
+{
+  static const unsigned long  n_table[] = {
+    1, 2, 3, 4, 5, 6, 7, 8,
+    123, 456, 789,
+
+    255, 256, 257,
+    1023, 1024, 1025,
+    32767, 32768, 32769,
+
+    ULONG_MAX/2-2, ULONG_MAX/2-1, ULONG_MAX/2, ULONG_MAX/2+1, ULONG_MAX/2+2,
+
+    ULONG_MAX-2, ULONG_MAX-1, ULONG_MAX,
+  };
+
+  unsigned long  got, n;
+  int    i, j;
+
+  for (i = 0; i < numberof (n_table); i++)
+    {
+      n = n_table[i];
+
+      for (j = 0; j < 5; j++)
+        {
+          got = gmp_urandomm_ui (rstate, n);
+          if (got >= n)
+            {
+              printf ("Return value out of range:\n");
+              printf ("  algorithm: %s\n", name);
+              printf ("  n:     %#lx\n", n);
+              printf ("  got:   %#lx\n", got);
+              abort ();
+            }
+        }
+    }
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  tests_start ();
+
+  call_rand_algs (check_one);
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/rand/t-urndmm.c b/third_party/gmp/tests/rand/t-urndmm.c
new file mode 100644
index 0000000..ae700dd
--- /dev/null
+++ b/third_party/gmp/tests/rand/t-urndmm.c
@@ -0,0 +1,158 @@
+/* Test mpz_urandomm.
+
+Copyright 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+#ifndef TRUE
+#define TRUE (1)
+#endif
+#ifndef FALSE
+#define FALSE (0)
+#endif
+
+int
+check_params (void)
+{
+  gmp_randstate_t r1, r2;
+  mpz_t a, b, m;
+  int i;
+  int result;
+
+  result = TRUE;
+
+  mpz_init (a);
+  mpz_init (b);
+  mpz_init (m);
+
+  if (result)
+    {
+      /* Test the consistency between urandomm and urandomb. */
+      gmp_randinit_default (r1);
+      gmp_randinit_default (r2);
+      gmp_randseed_ui (r1, 85L);
+      gmp_randseed_ui (r2, 85L);
+      mpz_set_ui (m, 0L);
+      mpz_setbit (m, 80L);
+      for (i = 0; i < 100; i++)
+	{
+	  mpz_urandomm (a, r1, m);
+	  mpz_urandomb (b, r2, 80L);
+	  if (mpz_cmp (a, b) != 0)
+	    {
+	      result = FALSE;
+	      printf ("mpz_urandomm != mpz_urandomb\n");
+	      break;
+	    }
+	}
+      gmp_randclear (r1);
+      gmp_randclear (r2);
+    }
+
+  if (result)
+    {
+      /* Test that mpz_urandomm returns the correct result with a
+	 broken LC.  */
+      mpz_set_ui (a, 0L);
+      gmp_randinit_lc_2exp (r1, a, 0xffL, 8L);
+      mpz_set_ui (m, 5L);
+      /* Warning: This code hangs in gmp 4.1 and below */
+      for (i = 0; i < 100; i++)
+	{
+	  mpz_urandomm (a, r1, m);
+	  if (mpz_cmp_ui (a, 2L) != 0)
+	    {
+	      result = FALSE;
+	      gmp_printf ("mpz_urandomm returns %Zd instead of 2\n", a);
+	      break;
+	    }
+	}
+      gmp_randclear (r1);
+    }
+
+  if (result)
+    {
+      /* Test that the results are always in range for either
+         positive or negative values of m.  */
+      gmp_randinit_default (r1);
+      mpz_set_ui (m, 5L);
+      mpz_set_si (b, -5L);
+      for (i = 0; i < 100; i++)
+	{
+	  mpz_urandomm (a, r1, m);
+	  if (mpz_cmp_ui (a, 5L) >= 0 || mpz_sgn (a) < 0)
+	    {
+	      result = FALSE;
+	      gmp_printf ("Out-of-range or non-positive value: %Zd\n", a);
+	      break;
+	    }
+	  mpz_urandomm (a, r1, b);
+	  if (mpz_cmp_ui (a, 5L) >= 0 || mpz_sgn (a) < 0)
+	    {
+	      result = FALSE;
+	      gmp_printf ("Out-of-range or non-positive value (from negative modulus): %Zd\n", a);
+	      break;
+	    }
+	}
+      gmp_randclear (r1);
+    }
+
+  if (result)
+    {
+      /* Test that m=1 forces always result=0.  */
+      gmp_randinit_default (r1);
+      mpz_set_ui (m, 1L);
+      for (i = 0; i < 100; i++)
+	{
+	  mpz_urandomm (a, r1, m);
+	  if (mpz_sgn (a) != 0)
+	    {
+	      result = FALSE;
+	      gmp_printf ("mpz_urandomm fails with m=1 (result=%Zd)\n", a);
+	      break;
+	    }
+	}
+      gmp_randclear (r1);
+    }
+
+  mpz_clear (a);
+  mpz_clear (b);
+  mpz_clear (m);
+  return result;
+}
+
+int
+main (int argc, char *argv[])
+{
+  int result = TRUE;
+
+  tests_start ();
+
+  if (result)
+    if (!check_params ())
+      result = FALSE;
+
+  tests_end ();
+
+  if (result)
+    return 0; /* pass */
+  else
+    return 1; /* fail */
+}
diff --git a/third_party/gmp/tests/rand/zdiv_round.c b/third_party/gmp/tests/rand/zdiv_round.c
new file mode 100644
index 0000000..e42e694
--- /dev/null
+++ b/third_party/gmp/tests/rand/zdiv_round.c
@@ -0,0 +1,43 @@
+/* zdiv_round() -- divide integers, round to nearest */
+
+/*
+Copyright 1999 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+void
+zdiv_round (mpz_t rop, mpz_t n, mpz_t d)
+{
+  mpf_t f_n, f_d;
+
+  mpf_init (f_n);
+  mpf_init (f_d);
+
+  mpf_set_z (f_d, d);
+  mpf_set_z (f_n, n);
+
+  mpf_div (f_n, f_n, f_d);
+  mpf_set_d (f_d, .5);
+  if (mpf_sgn (f_n) < 0)
+    mpf_neg (f_d, f_d);
+  mpf_add (f_n, f_n, f_d);
+  mpz_set_f (rop, f_n);
+
+  mpf_clear (f_n);
+  mpf_clear (f_d);
+  return;
+}
diff --git a/third_party/gmp/tests/refmpf.c b/third_party/gmp/tests/refmpf.c
new file mode 100644
index 0000000..bc955a5
--- /dev/null
+++ b/third_party/gmp/tests/refmpf.c
@@ -0,0 +1,427 @@
+/* Reference floating point routines.
+
+Copyright 1996, 2001, 2004, 2005 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+refmpf_add (mpf_ptr w, mpf_srcptr u, mpf_srcptr v)
+{
+  mp_size_t hi, lo, size;
+  mp_ptr ut, vt, wt;
+  int neg;
+  mp_exp_t exp;
+  mp_limb_t cy;
+  TMP_DECL;
+
+  TMP_MARK;
+
+  if (SIZ (u) == 0)
+    {
+      size = ABSIZ (v);
+      wt = TMP_ALLOC_LIMBS (size + 1);
+      MPN_COPY (wt, PTR (v), size);
+      exp = EXP (v);
+      neg = SIZ (v) < 0;
+      goto done;
+    }
+  if (SIZ (v) == 0)
+    {
+      size = ABSIZ (u);
+      wt = TMP_ALLOC_LIMBS (size + 1);
+      MPN_COPY (wt, PTR (u), size);
+      exp = EXP (u);
+      neg = SIZ (u) < 0;
+      goto done;
+    }
+  if ((SIZ (u) ^ SIZ (v)) < 0)
+    {
+      mpf_t tmp;
+      SIZ (tmp) = -SIZ (v);
+      EXP (tmp) = EXP (v);
+      PTR (tmp) = PTR (v);
+      refmpf_sub (w, u, tmp);
+      return;
+    }
+  neg = SIZ (u) < 0;
+
+  /* Compute the significance of the hi and lo end of the result.  */
+  hi = MAX (EXP (u), EXP (v));
+  lo = MIN (EXP (u) - ABSIZ (u), EXP (v) - ABSIZ (v));
+  size = hi - lo;
+  ut = TMP_ALLOC_LIMBS (size + 1);
+  vt = TMP_ALLOC_LIMBS (size + 1);
+  wt = TMP_ALLOC_LIMBS (size + 1);
+  MPN_ZERO (ut, size);
+  MPN_ZERO (vt, size);
+  {int off;
+  off = size + (EXP (u) - hi) - ABSIZ (u);
+  MPN_COPY (ut + off, PTR (u), ABSIZ (u));
+  off = size + (EXP (v) - hi) - ABSIZ (v);
+  MPN_COPY (vt + off, PTR (v), ABSIZ (v));
+  }
+
+  cy = mpn_add_n (wt, ut, vt, size);
+  wt[size] = cy;
+  size += cy;
+  exp = hi + cy;
+
+done:
+  if (size > PREC (w))
+    {
+      wt += size - PREC (w);
+      size = PREC (w);
+    }
+  MPN_COPY (PTR (w), wt, size);
+  SIZ (w) = neg == 0 ? size : -size;
+  EXP (w) = exp;
+  TMP_FREE;
+}
+
+
+/* Add 1 "unit in last place" (ie. in the least significant limb) to f.
+   f cannot be zero, since that has no well-defined "last place".
+
+   This routine is designed for use in cases where we pay close attention to
+   the size of the data value and are using that (and the exponent) to
+   indicate the accurate part of a result, or similar.  For this reason, if
+   there's a carry out we don't store 1 and adjust the exponent, we just
+   leave 100..00.  We don't even adjust if there's a carry out of prec+1
+   limbs, but instead give up in that case (which we intend shouldn't arise
+   in normal circumstances).  */
+
+void
+refmpf_add_ulp (mpf_ptr f)
+{
+  mp_ptr     fp = PTR(f);
+  mp_size_t  fsize = SIZ(f);
+  mp_size_t  abs_fsize = ABSIZ(f);
+  mp_limb_t  c;
+
+  if (fsize == 0)
+    {
+      printf ("Oops, refmpf_add_ulp called with f==0\n");
+      abort ();
+    }
+
+  c = refmpn_add_1 (fp, fp, abs_fsize, CNST_LIMB(1));
+  if (c != 0)
+    {
+      if (abs_fsize >= PREC(f) + 1)
+        {
+          printf ("Oops, refmpf_add_ulp carried out of prec+1 limbs\n");
+          abort ();
+        }
+
+      fp[abs_fsize] = c;
+      abs_fsize++;
+      SIZ(f) = (fsize > 0 ? abs_fsize : - abs_fsize);
+      EXP(f)++;
+    }
+}
+
+/* Fill f with size limbs of the given value, setup as an integer. */
+void
+refmpf_fill (mpf_ptr f, mp_size_t size, mp_limb_t value)
+{
+  ASSERT (size >= 0);
+  size = MIN (PREC(f) + 1, size);
+  SIZ(f) = size;
+  EXP(f) = size;
+  refmpn_fill (PTR(f), size, value);
+}
+
+/* Strip high zero limbs from the f data, adjusting exponent accordingly. */
+void
+refmpf_normalize (mpf_ptr f)
+{
+  while (SIZ(f) != 0 && PTR(f)[ABSIZ(f)-1] == 0)
+    {
+      SIZ(f) = (SIZ(f) >= 0 ? SIZ(f)-1 : SIZ(f)+1);
+      EXP(f) --;
+    }
+  if (SIZ(f) == 0)
+    EXP(f) = 0;
+}
+
+/* refmpf_set_overlap sets up dst as a copy of src, but with PREC(dst)
+   unchanged, in preparation for an overlap test.
+
+   The full value of src is copied, and the space at PTR(dst) is extended as
+   necessary.  The way PREC(dst) is unchanged is as per an mpf_set_prec_raw.
+   The return value is the new PTR(dst) space precision, in bits, ready for
+   a restoring mpf_set_prec_raw before mpf_clear.  */
+
+unsigned long
+refmpf_set_overlap (mpf_ptr dst, mpf_srcptr src)
+{
+  mp_size_t  dprec = PREC(dst);
+  mp_size_t  ssize = ABSIZ(src);
+  unsigned long  ret;
+
+  refmpf_set_prec_limbs (dst, (unsigned long) MAX (dprec, ssize));
+  mpf_set (dst, src);
+
+  ret = mpf_get_prec (dst);
+  PREC(dst) = dprec;
+  return ret;
+}
+
+/* Like mpf_set_prec, but taking a precision in limbs.
+   PREC(f) ends up as the given "prec" value.  */
+void
+refmpf_set_prec_limbs (mpf_ptr f, unsigned long prec)
+{
+  mpf_set_prec (f, __GMPF_PREC_TO_BITS (prec));
+}
+
+
+void
+refmpf_sub (mpf_ptr w, mpf_srcptr u, mpf_srcptr v)
+{
+  mp_size_t hi, lo, size;
+  mp_ptr ut, vt, wt;
+  int neg;
+  mp_exp_t exp;
+  TMP_DECL;
+
+  TMP_MARK;
+
+  if (SIZ (u) == 0)
+    {
+      size = ABSIZ (v);
+      wt = TMP_ALLOC_LIMBS (size + 1);
+      MPN_COPY (wt, PTR (v), size);
+      exp = EXP (v);
+      neg = SIZ (v) > 0;
+      goto done;
+    }
+  if (SIZ (v) == 0)
+    {
+      size = ABSIZ (u);
+      wt = TMP_ALLOC_LIMBS (size + 1);
+      MPN_COPY (wt, PTR (u), size);
+      exp = EXP (u);
+      neg = SIZ (u) < 0;
+      goto done;
+    }
+  if ((SIZ (u) ^ SIZ (v)) < 0)
+    {
+      mpf_t tmp;
+      SIZ (tmp) = -SIZ (v);
+      EXP (tmp) = EXP (v);
+      PTR (tmp) = PTR (v);
+      refmpf_add (w, u, tmp);
+      if (SIZ (u) < 0)
+	mpf_neg (w, w);
+      return;
+    }
+  neg = SIZ (u) < 0;
+
+  /* Compute the significance of the hi and lo end of the result.  */
+  hi = MAX (EXP (u), EXP (v));
+  lo = MIN (EXP (u) - ABSIZ (u), EXP (v) - ABSIZ (v));
+  size = hi - lo;
+  ut = TMP_ALLOC_LIMBS (size + 1);
+  vt = TMP_ALLOC_LIMBS (size + 1);
+  wt = TMP_ALLOC_LIMBS (size + 1);
+  MPN_ZERO (ut, size);
+  MPN_ZERO (vt, size);
+  {int off;
+  off = size + (EXP (u) - hi) - ABSIZ (u);
+  MPN_COPY (ut + off, PTR (u), ABSIZ (u));
+  off = size + (EXP (v) - hi) - ABSIZ (v);
+  MPN_COPY (vt + off, PTR (v), ABSIZ (v));
+  }
+
+  if (mpn_cmp (ut, vt, size) >= 0)
+    mpn_sub_n (wt, ut, vt, size);
+  else
+    {
+      mpn_sub_n (wt, vt, ut, size);
+      neg ^= 1;
+    }
+  exp = hi;
+  while (size != 0 && wt[size - 1] == 0)
+    {
+      size--;
+      exp--;
+    }
+
+done:
+  if (size > PREC (w))
+    {
+      wt += size - PREC (w);
+      size = PREC (w);
+    }
+  MPN_COPY (PTR (w), wt, size);
+  SIZ (w) = neg == 0 ? size : -size;
+  EXP (w) = exp;
+  TMP_FREE;
+}
+
+
+/* Validate got by comparing to want.  Return 1 if good, 0 if bad.
+
+   The data in got is compared to that in want, up to either PREC(got) limbs
+   or the size of got, whichever is bigger.  Clearly we always demand
+   PREC(got) of accuracy, but we go further and say that if got is bigger
+   then any extra must be correct too.
+
+   want needs to have enough data to allow this comparison.  The size in
+   want doesn't have to be that big though, if it's smaller then further low
+   limbs are taken to be zero.
+
+   This validation approach is designed to allow some flexibility in exactly
+   how much data is generated by an mpf function, ie. either prec or prec+1
+   limbs.  We don't try to make a reference function that emulates that same
+   size decision, instead the idea is for a validation function to generate
+   at least as much data as the real function, then compare.  */
+
+int
+refmpf_validate (const char *name, mpf_srcptr got, mpf_srcptr want)
+{
+  int  bad = 0;
+  mp_size_t  gsize, wsize, cmpsize, i;
+  mp_srcptr  gp, wp;
+  mp_limb_t  glimb, wlimb;
+
+  MPF_CHECK_FORMAT (got);
+
+  if (EXP (got) != EXP (want))
+    {
+      printf ("%s: wrong exponent\n", name);
+      bad = 1;
+    }
+
+  gsize = SIZ (got);
+  wsize = SIZ (want);
+  if ((gsize < 0 && wsize > 0) || (gsize > 0 && wsize < 0))
+    {
+      printf ("%s: wrong sign\n", name);
+      bad = 1;
+    }
+
+  gsize = ABS (gsize);
+  wsize = ABS (wsize);
+
+  /* most significant limb of respective data */
+  gp = PTR (got) + gsize - 1;
+  wp = PTR (want) + wsize - 1;
+
+  /* compare limb data */
+  cmpsize = MAX (PREC (got), gsize);
+  for (i = 0; i < cmpsize; i++)
+    {
+      glimb = (i < gsize ? gp[-i] : 0);
+      wlimb = (i < wsize ? wp[-i] : 0);
+
+      if (glimb != wlimb)
+        {
+          printf ("%s: wrong data starting at index %ld from top\n",
+                  name, (long) i);
+          bad = 1;
+          break;
+        }
+    }
+
+  if (bad)
+    {
+      printf ("  prec       %d\n", PREC(got));
+      printf ("  exp got    %ld\n", (long) EXP(got));
+      printf ("  exp want   %ld\n", (long) EXP(want));
+      printf ("  size got   %d\n", SIZ(got));
+      printf ("  size want  %d\n", SIZ(want));
+      printf ("  limbs (high to low)\n");
+      printf ("   got  ");
+      for (i = ABSIZ(got)-1; i >= 0; i--)
+        {
+          gmp_printf ("%MX", PTR(got)[i]);
+          if (i != 0)
+            printf (",");
+        }
+      printf ("\n");
+      printf ("   want ");
+      for (i = ABSIZ(want)-1; i >= 0; i--)
+        {
+          gmp_printf ("%MX", PTR(want)[i]);
+          if (i != 0)
+            printf (",");
+        }
+      printf ("\n");
+      return 0;
+    }
+
+  return 1;
+}
+
+
+int
+refmpf_validate_division (const char *name, mpf_srcptr got,
+                          mpf_srcptr n, mpf_srcptr d)
+{
+  mp_size_t  nsize, dsize, sign, prec, qsize, tsize;
+  mp_srcptr  np, dp;
+  mp_ptr     tp, qp, rp;
+  mpf_t      want;
+  int        ret;
+
+  nsize = SIZ (n);
+  dsize = SIZ (d);
+  ASSERT_ALWAYS (dsize != 0);
+
+  sign = nsize ^ dsize;
+  nsize = ABS (nsize);
+  dsize = ABS (dsize);
+
+  np = PTR (n);
+  dp = PTR (d);
+  prec = PREC (got);
+
+  EXP (want) = EXP (n) - EXP (d) + 1;
+
+  qsize = prec + 2;            /* at least prec+1 limbs, after high zero */
+  tsize = qsize + dsize - 1;   /* dividend size to give desired qsize */
+
+  /* dividend n, extended or truncated */
+  tp = refmpn_malloc_limbs (tsize);
+  refmpn_copy_extend (tp, tsize, np, nsize);
+
+  qp = refmpn_malloc_limbs (qsize);
+  rp = refmpn_malloc_limbs (dsize);  /* remainder, unused */
+
+  ASSERT_ALWAYS (qsize == tsize - dsize + 1);
+  refmpn_tdiv_qr (qp, rp, (mp_size_t) 0, tp, tsize, dp, dsize);
+
+  PTR (want) = qp;
+  SIZ (want) = (sign >= 0 ? qsize : -qsize);
+  refmpf_normalize (want);
+
+  ret = refmpf_validate (name, got, want);
+
+  free (tp);
+  free (qp);
+  free (rp);
+
+  return ret;
+}
diff --git a/third_party/gmp/tests/refmpn.c b/third_party/gmp/tests/refmpn.c
new file mode 100644
index 0000000..42bb411
--- /dev/null
+++ b/third_party/gmp/tests/refmpn.c
@@ -0,0 +1,2630 @@
+/* Reference mpn functions, designed to be simple, portable and independent
+   of the normal gmp code.  Speed isn't a consideration.
+
+Copyright 1996-2009, 2011-2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+/* Most routines have assertions representing what the mpn routines are
+   supposed to accept.  Many of these reference routines do sensible things
+   outside these ranges (eg. for size==0), but the assertions are present to
+   pick up bad parameters passed here that are about to be passed the same
+   to a real mpn routine being compared.  */
+
+/* always do assertion checking */
+#define WANT_ASSERT  1
+
+#include <stdio.h>  /* for NULL */
+#include <stdlib.h> /* for malloc */
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#include "tests.h"
+
+
+
+/* Return non-zero if regions {xp,xsize} and {yp,ysize} overlap, with sizes
+   in bytes. */
+int
+byte_overlap_p (const void *v_xp, mp_size_t xsize,
+		const void *v_yp, mp_size_t ysize)
+{
+  const char *xp = (const char *) v_xp;
+  const char *yp = (const char *) v_yp;
+
+  ASSERT (xsize >= 0);
+  ASSERT (ysize >= 0);
+
+  /* no wraparounds */
+  ASSERT (xp+xsize >= xp);
+  ASSERT (yp+ysize >= yp);
+
+  if (xp + xsize <= yp)
+    return 0;
+
+  if (yp + ysize <= xp)
+    return 0;
+
+  return 1;
+}
+
+/* Return non-zero if limb regions {xp,xsize} and {yp,ysize} overlap. */
+int
+refmpn_overlap_p (mp_srcptr xp, mp_size_t xsize, mp_srcptr yp, mp_size_t ysize)
+{
+  return byte_overlap_p (xp, xsize * GMP_LIMB_BYTES,
+			 yp, ysize * GMP_LIMB_BYTES);
+}
+
+/* Check overlap for a routine defined to work low to high. */
+int
+refmpn_overlap_low_to_high_p (mp_srcptr dst, mp_srcptr src, mp_size_t size)
+{
+  return (dst <= src || ! refmpn_overlap_p (dst, size, src, size));
+}
+
+/* Check overlap for a routine defined to work high to low. */
+int
+refmpn_overlap_high_to_low_p (mp_srcptr dst, mp_srcptr src, mp_size_t size)
+{
+  return (dst >= src || ! refmpn_overlap_p (dst, size, src, size));
+}
+
+/* Check overlap for a standard routine requiring equal or separate. */
+int
+refmpn_overlap_fullonly_p (mp_srcptr dst, mp_srcptr src, mp_size_t size)
+{
+  return (dst == src || ! refmpn_overlap_p (dst, size, src, size));
+}
+int
+refmpn_overlap_fullonly_two_p (mp_srcptr dst, mp_srcptr src1, mp_srcptr src2,
+			       mp_size_t size)
+{
+  return (refmpn_overlap_fullonly_p (dst, src1, size)
+	  && refmpn_overlap_fullonly_p (dst, src2, size));
+}
+
+
+mp_ptr
+refmpn_malloc_limbs (mp_size_t size)
+{
+  mp_ptr  p;
+  ASSERT (size >= 0);
+  if (size == 0)
+    size = 1;
+  p = (mp_ptr) malloc ((size_t) (size * GMP_LIMB_BYTES));
+  ASSERT (p != NULL);
+  return p;
+}
+
+/* Free limbs allocated by refmpn_malloc_limbs. NOTE: Can't free
+ * memory allocated by refmpn_malloc_limbs_aligned. */
+void
+refmpn_free_limbs (mp_ptr p)
+{
+  free (p);
+}
+
+mp_ptr
+refmpn_memdup_limbs (mp_srcptr ptr, mp_size_t size)
+{
+  mp_ptr  p;
+  p = refmpn_malloc_limbs (size);
+  refmpn_copyi (p, ptr, size);
+  return p;
+}
+
+/* malloc n limbs on a multiple of m bytes boundary */
+mp_ptr
+refmpn_malloc_limbs_aligned (mp_size_t n, size_t m)
+{
+  return (mp_ptr) align_pointer (refmpn_malloc_limbs (n + m-1), m);
+}
+
+
+void
+refmpn_fill (mp_ptr ptr, mp_size_t size, mp_limb_t value)
+{
+  mp_size_t  i;
+  ASSERT (size >= 0);
+  for (i = 0; i < size; i++)
+    ptr[i] = value;
+}
+
+void
+refmpn_zero (mp_ptr ptr, mp_size_t size)
+{
+  refmpn_fill (ptr, size, CNST_LIMB(0));
+}
+
+void
+refmpn_zero_extend (mp_ptr ptr, mp_size_t oldsize, mp_size_t newsize)
+{
+  ASSERT (newsize >= oldsize);
+  refmpn_zero (ptr+oldsize, newsize-oldsize);
+}
+
+int
+refmpn_zero_p (mp_srcptr ptr, mp_size_t size)
+{
+  mp_size_t  i;
+  for (i = 0; i < size; i++)
+    if (ptr[i] != 0)
+      return 0;
+  return 1;
+}
+
+mp_size_t
+refmpn_normalize (mp_srcptr ptr, mp_size_t size)
+{
+  ASSERT (size >= 0);
+  while (size > 0 && ptr[size-1] == 0)
+    size--;
+  return size;
+}
+
+/* the highest one bit in x */
+mp_limb_t
+refmpn_msbone (mp_limb_t x)
+{
+  mp_limb_t  n = (mp_limb_t) 1 << (GMP_LIMB_BITS-1);
+
+  while (n != 0)
+    {
+      if (x & n)
+	break;
+      n >>= 1;
+    }
+  return n;
+}
+
+/* a mask of the highest one bit plus and all bits below */
+mp_limb_t
+refmpn_msbone_mask (mp_limb_t x)
+{
+  if (x == 0)
+    return 0;
+
+  return (refmpn_msbone (x) << 1) - 1;
+}
+
+/* How many digits in the given base will fit in a limb.
+   Notice that the product b is allowed to be equal to the limit
+   2^GMP_NUMB_BITS, this ensures the result for base==2 will be
+   GMP_NUMB_BITS (and similarly other powers of 2).  */
+int
+refmpn_chars_per_limb (int base)
+{
+  mp_limb_t  limit[2], b[2];
+  int        chars_per_limb;
+
+  ASSERT (base >= 2);
+
+  limit[0] = 0;  /* limit = 2^GMP_NUMB_BITS */
+  limit[1] = 1;
+  b[0] = 1;      /* b = 1 */
+  b[1] = 0;
+
+  chars_per_limb = 0;
+  for (;;)
+    {
+      if (refmpn_mul_1 (b, b, (mp_size_t) 2, (mp_limb_t) base))
+	break;
+      if (refmpn_cmp (b, limit, (mp_size_t) 2) > 0)
+	break;
+      chars_per_limb++;
+    }
+  return chars_per_limb;
+}
+
+/* The biggest value base**n which fits in GMP_NUMB_BITS. */
+mp_limb_t
+refmpn_big_base (int base)
+{
+  int        chars_per_limb = refmpn_chars_per_limb (base);
+  int        i;
+  mp_limb_t  bb;
+
+  ASSERT (base >= 2);
+  bb = 1;
+  for (i = 0; i < chars_per_limb; i++)
+    bb *= base;
+  return bb;
+}
+
+
+void
+refmpn_setbit (mp_ptr ptr, unsigned long bit)
+{
+  ptr[bit/GMP_NUMB_BITS] |= CNST_LIMB(1) << (bit%GMP_NUMB_BITS);
+}
+
+void
+refmpn_clrbit (mp_ptr ptr, unsigned long bit)
+{
+  ptr[bit/GMP_NUMB_BITS] &= ~ (CNST_LIMB(1) << (bit%GMP_NUMB_BITS));
+}
+
+#define REFMPN_TSTBIT(ptr,bit) \
+  (((ptr)[(bit)/GMP_NUMB_BITS] & (CNST_LIMB(1) << ((bit)%GMP_NUMB_BITS))) != 0)
+
+int
+refmpn_tstbit (mp_srcptr ptr, unsigned long bit)
+{
+  return REFMPN_TSTBIT (ptr, bit);
+}
+
+unsigned long
+refmpn_scan0 (mp_srcptr ptr, unsigned long bit)
+{
+  while (REFMPN_TSTBIT (ptr, bit) != 0)
+    bit++;
+  return bit;
+}
+
+unsigned long
+refmpn_scan1 (mp_srcptr ptr, unsigned long bit)
+{
+  while (REFMPN_TSTBIT (ptr, bit) == 0)
+    bit++;
+  return bit;
+}
+
+void
+refmpn_copy (mp_ptr rp, mp_srcptr sp, mp_size_t size)
+{
+  ASSERT (refmpn_overlap_fullonly_p (rp, sp, size));
+  refmpn_copyi (rp, sp, size);
+}
+
+void
+refmpn_copyi (mp_ptr rp, mp_srcptr sp, mp_size_t size)
+{
+  mp_size_t i;
+
+  ASSERT (refmpn_overlap_low_to_high_p (rp, sp, size));
+  ASSERT (size >= 0);
+
+  for (i = 0; i < size; i++)
+    rp[i] = sp[i];
+}
+
+void
+refmpn_copyd (mp_ptr rp, mp_srcptr sp, mp_size_t size)
+{
+  mp_size_t i;
+
+  ASSERT (refmpn_overlap_high_to_low_p (rp, sp, size));
+  ASSERT (size >= 0);
+
+  for (i = size-1; i >= 0; i--)
+    rp[i] = sp[i];
+}
+
+/* Copy {xp,xsize} to {wp,wsize}.  If x is shorter, then pad w with low
+   zeros to wsize.  If x is longer, then copy just the high wsize limbs.  */
+void
+refmpn_copy_extend (mp_ptr wp, mp_size_t wsize, mp_srcptr xp, mp_size_t xsize)
+{
+  ASSERT (wsize >= 0);
+  ASSERT (xsize >= 0);
+
+  /* high part of x if x bigger than w */
+  if (xsize > wsize)
+    {
+      xp += xsize - wsize;
+      xsize = wsize;
+    }
+
+  refmpn_copy (wp + wsize-xsize, xp, xsize);
+  refmpn_zero (wp, wsize-xsize);
+}
+
+int
+refmpn_cmp (mp_srcptr xp, mp_srcptr yp, mp_size_t size)
+{
+  mp_size_t  i;
+
+  ASSERT (size >= 1);
+  ASSERT_MPN (xp, size);
+  ASSERT_MPN (yp, size);
+
+  for (i = size-1; i >= 0; i--)
+    {
+      if (xp[i] > yp[i])  return 1;
+      if (xp[i] < yp[i])  return -1;
+    }
+  return 0;
+}
+
+int
+refmpn_cmp_allowzero (mp_srcptr xp, mp_srcptr yp, mp_size_t size)
+{
+  if (size == 0)
+    return 0;
+  else
+    return refmpn_cmp (xp, yp, size);
+}
+
+int
+refmpn_cmp_twosizes (mp_srcptr xp, mp_size_t xsize,
+		     mp_srcptr yp, mp_size_t ysize)
+{
+  int  opp, cmp;
+
+  ASSERT_MPN (xp, xsize);
+  ASSERT_MPN (yp, ysize);
+
+  opp = (xsize < ysize);
+  if (opp)
+    MPN_SRCPTR_SWAP (xp,xsize, yp,ysize);
+
+  if (! refmpn_zero_p (xp+ysize, xsize-ysize))
+    cmp = 1;
+  else
+    cmp = refmpn_cmp (xp, yp, ysize);
+
+  return (opp ? -cmp : cmp);
+}
+
+int
+refmpn_equal_anynail (mp_srcptr xp, mp_srcptr yp, mp_size_t size)
+{
+  mp_size_t  i;
+  ASSERT (size >= 0);
+
+  for (i = 0; i < size; i++)
+      if (xp[i] != yp[i])
+	return 0;
+  return 1;
+}
+
+
+#define LOGOPS(operation)                                               \
+  {                                                                     \
+    mp_size_t  i;                                                       \
+									\
+    ASSERT (refmpn_overlap_fullonly_two_p (rp, s1p, s2p, size));        \
+    ASSERT (size >= 1);                                                 \
+    ASSERT_MPN (s1p, size);                                             \
+    ASSERT_MPN (s2p, size);                                             \
+									\
+    for (i = 0; i < size; i++)                                          \
+      rp[i] = operation;                                                \
+  }
+
+void
+refmpn_and_n (mp_ptr rp, mp_srcptr s1p, mp_srcptr s2p, mp_size_t size)
+{
+  LOGOPS (s1p[i] & s2p[i]);
+}
+void
+refmpn_andn_n (mp_ptr rp, mp_srcptr s1p, mp_srcptr s2p, mp_size_t size)
+{
+  LOGOPS (s1p[i] & ~s2p[i]);
+}
+void
+refmpn_nand_n (mp_ptr rp, mp_srcptr s1p, mp_srcptr s2p, mp_size_t size)
+{
+  LOGOPS ((s1p[i] & s2p[i]) ^ GMP_NUMB_MASK);
+}
+void
+refmpn_ior_n (mp_ptr rp, mp_srcptr s1p, mp_srcptr s2p, mp_size_t size)
+{
+  LOGOPS (s1p[i] | s2p[i]);
+}
+void
+refmpn_iorn_n (mp_ptr rp, mp_srcptr s1p, mp_srcptr s2p, mp_size_t size)
+{
+  LOGOPS (s1p[i] | (s2p[i] ^ GMP_NUMB_MASK));
+}
+void
+refmpn_nior_n (mp_ptr rp, mp_srcptr s1p, mp_srcptr s2p, mp_size_t size)
+{
+  LOGOPS ((s1p[i] | s2p[i]) ^ GMP_NUMB_MASK);
+}
+void
+refmpn_xor_n (mp_ptr rp, mp_srcptr s1p, mp_srcptr s2p, mp_size_t size)
+{
+  LOGOPS (s1p[i] ^ s2p[i]);
+}
+void
+refmpn_xnor_n (mp_ptr rp, mp_srcptr s1p, mp_srcptr s2p, mp_size_t size)
+{
+  LOGOPS ((s1p[i] ^ s2p[i]) ^ GMP_NUMB_MASK);
+}
+
+
+/* set *dh,*dl to mh:ml - sh:sl, in full limbs */
+void
+refmpn_sub_ddmmss (mp_limb_t *dh, mp_limb_t *dl,
+		   mp_limb_t mh, mp_limb_t ml, mp_limb_t sh, mp_limb_t sl)
+{
+  *dl = ml - sl;
+  *dh = mh - sh - (ml < sl);
+}
+
+
+/* set *w to x+y, return 0 or 1 carry */
+mp_limb_t
+ref_addc_limb (mp_limb_t *w, mp_limb_t x, mp_limb_t y)
+{
+  mp_limb_t  sum, cy;
+
+  ASSERT_LIMB (x);
+  ASSERT_LIMB (y);
+
+  sum = x + y;
+#if GMP_NAIL_BITS == 0
+  *w = sum;
+  cy = (sum < x);
+#else
+  *w = sum & GMP_NUMB_MASK;
+  cy = (sum >> GMP_NUMB_BITS);
+#endif
+  return cy;
+}
+
+/* set *w to x-y, return 0 or 1 borrow */
+mp_limb_t
+ref_subc_limb (mp_limb_t *w, mp_limb_t x, mp_limb_t y)
+{
+  mp_limb_t  diff, cy;
+
+  ASSERT_LIMB (x);
+  ASSERT_LIMB (y);
+
+  diff = x - y;
+#if GMP_NAIL_BITS == 0
+  *w = diff;
+  cy = (diff > x);
+#else
+  *w = diff & GMP_NUMB_MASK;
+  cy = (diff >> GMP_NUMB_BITS) & 1;
+#endif
+  return cy;
+}
+
+/* set *w to x+y+c (where c is 0 or 1), return 0 or 1 carry */
+mp_limb_t
+adc (mp_limb_t *w, mp_limb_t x, mp_limb_t y, mp_limb_t c)
+{
+  mp_limb_t  r;
+
+  ASSERT_LIMB (x);
+  ASSERT_LIMB (y);
+  ASSERT (c == 0 || c == 1);
+
+  r = ref_addc_limb (w, x, y);
+  return r + ref_addc_limb (w, *w, c);
+}
+
+/* set *w to x-y-c (where c is 0 or 1), return 0 or 1 borrow */
+mp_limb_t
+sbb (mp_limb_t *w, mp_limb_t x, mp_limb_t y, mp_limb_t c)
+{
+  mp_limb_t  r;
+
+  ASSERT_LIMB (x);
+  ASSERT_LIMB (y);
+  ASSERT (c == 0 || c == 1);
+
+  r = ref_subc_limb (w, x, y);
+  return r + ref_subc_limb (w, *w, c);
+}
+
+
+#define AORS_1(operation)                               \
+  {                                                     \
+    mp_size_t  i;                                       \
+							\
+    ASSERT (refmpn_overlap_fullonly_p (rp, sp, size));  \
+    ASSERT (size >= 1);                                 \
+    ASSERT_MPN (sp, size);                              \
+    ASSERT_LIMB (n);                                    \
+							\
+    for (i = 0; i < size; i++)                          \
+      n = operation (&rp[i], sp[i], n);                 \
+    return n;                                           \
+  }
+
+mp_limb_t
+refmpn_add_1 (mp_ptr rp, mp_srcptr sp, mp_size_t size, mp_limb_t n)
+{
+  AORS_1 (ref_addc_limb);
+}
+mp_limb_t
+refmpn_sub_1 (mp_ptr rp, mp_srcptr sp, mp_size_t size, mp_limb_t n)
+{
+  AORS_1 (ref_subc_limb);
+}
+
+#define AORS_NC(operation)                                              \
+  {                                                                     \
+    mp_size_t  i;                                                       \
+									\
+    ASSERT (refmpn_overlap_fullonly_two_p (rp, s1p, s2p, size));        \
+    ASSERT (carry == 0 || carry == 1);                                  \
+    ASSERT (size >= 1);                                                 \
+    ASSERT_MPN (s1p, size);                                             \
+    ASSERT_MPN (s2p, size);                                             \
+									\
+    for (i = 0; i < size; i++)                                          \
+      carry = operation (&rp[i], s1p[i], s2p[i], carry);                \
+    return carry;                                                       \
+  }
+
+mp_limb_t
+refmpn_add_nc (mp_ptr rp, mp_srcptr s1p, mp_srcptr s2p, mp_size_t size,
+	       mp_limb_t carry)
+{
+  AORS_NC (adc);
+}
+mp_limb_t
+refmpn_sub_nc (mp_ptr rp, mp_srcptr s1p, mp_srcptr s2p, mp_size_t size,
+	       mp_limb_t carry)
+{
+  AORS_NC (sbb);
+}
+
+
+mp_limb_t
+refmpn_add_n (mp_ptr rp, mp_srcptr s1p, mp_srcptr s2p, mp_size_t size)
+{
+  return refmpn_add_nc (rp, s1p, s2p, size, CNST_LIMB(0));
+}
+mp_limb_t
+refmpn_sub_n (mp_ptr rp, mp_srcptr s1p, mp_srcptr s2p, mp_size_t size)
+{
+  return refmpn_sub_nc (rp, s1p, s2p, size, CNST_LIMB(0));
+}
+
+mp_limb_t
+refmpn_cnd_add_n (mp_limb_t cnd, mp_ptr rp, mp_srcptr s1p, mp_srcptr s2p, mp_size_t size)
+{
+  if (cnd != 0)
+    return refmpn_add_n (rp, s1p, s2p, size);
+  else
+    {
+      refmpn_copyi (rp, s1p, size);
+      return 0;
+    }
+}
+mp_limb_t
+refmpn_cnd_sub_n (mp_limb_t cnd, mp_ptr rp, mp_srcptr s1p, mp_srcptr s2p, mp_size_t size)
+{
+  if (cnd != 0)
+    return refmpn_sub_n (rp, s1p, s2p, size);
+  else
+    {
+      refmpn_copyi (rp, s1p, size);
+      return 0;
+    }
+}
+
+
+#define AORS_ERR1_N(operation)						\
+  {                                                                     \
+    mp_size_t  i;                                                       \
+    mp_limb_t carry2;							\
+									\
+    ASSERT (refmpn_overlap_fullonly_p (rp, s1p, size));			\
+    ASSERT (refmpn_overlap_fullonly_p (rp, s2p, size));			\
+    ASSERT (! refmpn_overlap_p (rp, size, yp, size));			\
+    ASSERT (! refmpn_overlap_p (ep, 2, s1p, size));			\
+    ASSERT (! refmpn_overlap_p (ep, 2, s2p, size));			\
+    ASSERT (! refmpn_overlap_p (ep, 2, yp, size));			\
+    ASSERT (! refmpn_overlap_p (ep, 2, rp, size));			\
+									\
+    ASSERT (carry == 0 || carry == 1);					\
+    ASSERT (size >= 1);							\
+    ASSERT_MPN (s1p, size);						\
+    ASSERT_MPN (s2p, size);						\
+    ASSERT_MPN (yp, size);						\
+									\
+    ep[0] = ep[1] = CNST_LIMB(0);					\
+									\
+    for (i = 0; i < size; i++)                                          \
+      {									\
+	carry = operation (&rp[i], s1p[i], s2p[i], carry);		\
+	if (carry == 1)							\
+	  {								\
+	    carry2 = ref_addc_limb (&ep[0], ep[0], yp[size - 1 - i]);	\
+	    carry2 = ref_addc_limb (&ep[1], ep[1], carry2);		\
+	    ASSERT (carry2 == 0);					\
+	  }								\
+      }									\
+    return carry;                                                       \
+  }
+
+mp_limb_t
+refmpn_add_err1_n (mp_ptr rp, mp_srcptr s1p, mp_srcptr s2p,
+		   mp_ptr ep, mp_srcptr yp,
+		   mp_size_t size, mp_limb_t carry)
+{
+  AORS_ERR1_N (adc);
+}
+mp_limb_t
+refmpn_sub_err1_n (mp_ptr rp, mp_srcptr s1p, mp_srcptr s2p,
+		   mp_ptr ep, mp_srcptr yp,
+		   mp_size_t size, mp_limb_t carry)
+{
+  AORS_ERR1_N (sbb);
+}
+
+
+#define AORS_ERR2_N(operation)						\
+  {                                                                     \
+    mp_size_t  i;                                                       \
+    mp_limb_t carry2;							\
+									\
+    ASSERT (refmpn_overlap_fullonly_p (rp, s1p, size));			\
+    ASSERT (refmpn_overlap_fullonly_p (rp, s2p, size));			\
+    ASSERT (! refmpn_overlap_p (rp, size, y1p, size));			\
+    ASSERT (! refmpn_overlap_p (rp, size, y2p, size));			\
+    ASSERT (! refmpn_overlap_p (ep, 4, s1p, size));			\
+    ASSERT (! refmpn_overlap_p (ep, 4, s2p, size));			\
+    ASSERT (! refmpn_overlap_p (ep, 4, y1p, size));			\
+    ASSERT (! refmpn_overlap_p (ep, 4, y2p, size));			\
+    ASSERT (! refmpn_overlap_p (ep, 4, rp, size));			\
+									\
+    ASSERT (carry == 0 || carry == 1);					\
+    ASSERT (size >= 1);							\
+    ASSERT_MPN (s1p, size);						\
+    ASSERT_MPN (s2p, size);						\
+    ASSERT_MPN (y1p, size);						\
+    ASSERT_MPN (y2p, size);						\
+									\
+    ep[0] = ep[1] = CNST_LIMB(0);					\
+    ep[2] = ep[3] = CNST_LIMB(0);					\
+									\
+    for (i = 0; i < size; i++)                                          \
+      {									\
+	carry = operation (&rp[i], s1p[i], s2p[i], carry);		\
+	if (carry == 1)							\
+	  {								\
+	    carry2 = ref_addc_limb (&ep[0], ep[0], y1p[size - 1 - i]);	\
+	    carry2 = ref_addc_limb (&ep[1], ep[1], carry2);		\
+	    ASSERT (carry2 == 0);					\
+	    carry2 = ref_addc_limb (&ep[2], ep[2], y2p[size - 1 - i]);	\
+	    carry2 = ref_addc_limb (&ep[3], ep[3], carry2);		\
+	    ASSERT (carry2 == 0);					\
+	  }								\
+      }									\
+    return carry;                                                       \
+  }
+
+mp_limb_t
+refmpn_add_err2_n (mp_ptr rp, mp_srcptr s1p, mp_srcptr s2p,
+		   mp_ptr ep, mp_srcptr y1p, mp_srcptr y2p,
+		   mp_size_t size, mp_limb_t carry)
+{
+  AORS_ERR2_N (adc);
+}
+mp_limb_t
+refmpn_sub_err2_n (mp_ptr rp, mp_srcptr s1p, mp_srcptr s2p,
+		   mp_ptr ep, mp_srcptr y1p, mp_srcptr y2p,
+		   mp_size_t size, mp_limb_t carry)
+{
+  AORS_ERR2_N (sbb);
+}
+
+
+#define AORS_ERR3_N(operation)						\
+  {                                                                     \
+    mp_size_t  i;                                                       \
+    mp_limb_t carry2;							\
+									\
+    ASSERT (refmpn_overlap_fullonly_p (rp, s1p, size));			\
+    ASSERT (refmpn_overlap_fullonly_p (rp, s2p, size));			\
+    ASSERT (! refmpn_overlap_p (rp, size, y1p, size));			\
+    ASSERT (! refmpn_overlap_p (rp, size, y2p, size));			\
+    ASSERT (! refmpn_overlap_p (rp, size, y3p, size));			\
+    ASSERT (! refmpn_overlap_p (ep, 6, s1p, size));			\
+    ASSERT (! refmpn_overlap_p (ep, 6, s2p, size));			\
+    ASSERT (! refmpn_overlap_p (ep, 6, y1p, size));			\
+    ASSERT (! refmpn_overlap_p (ep, 6, y2p, size));			\
+    ASSERT (! refmpn_overlap_p (ep, 6, y3p, size));			\
+    ASSERT (! refmpn_overlap_p (ep, 6, rp, size));			\
+									\
+    ASSERT (carry == 0 || carry == 1);					\
+    ASSERT (size >= 1);							\
+    ASSERT_MPN (s1p, size);						\
+    ASSERT_MPN (s2p, size);						\
+    ASSERT_MPN (y1p, size);						\
+    ASSERT_MPN (y2p, size);						\
+    ASSERT_MPN (y3p, size);						\
+									\
+    ep[0] = ep[1] = CNST_LIMB(0);					\
+    ep[2] = ep[3] = CNST_LIMB(0);					\
+    ep[4] = ep[5] = CNST_LIMB(0);					\
+									\
+    for (i = 0; i < size; i++)                                          \
+      {									\
+	carry = operation (&rp[i], s1p[i], s2p[i], carry);		\
+	if (carry == 1)							\
+	  {								\
+	    carry2 = ref_addc_limb (&ep[0], ep[0], y1p[size - 1 - i]);	\
+	    carry2 = ref_addc_limb (&ep[1], ep[1], carry2);		\
+	    ASSERT (carry2 == 0);					\
+	    carry2 = ref_addc_limb (&ep[2], ep[2], y2p[size - 1 - i]);	\
+	    carry2 = ref_addc_limb (&ep[3], ep[3], carry2);		\
+	    ASSERT (carry2 == 0);					\
+	    carry2 = ref_addc_limb (&ep[4], ep[4], y3p[size - 1 - i]);	\
+	    carry2 = ref_addc_limb (&ep[5], ep[5], carry2);		\
+	    ASSERT (carry2 == 0);					\
+	  }								\
+      }									\
+    return carry;                                                       \
+  }
+
+mp_limb_t
+refmpn_add_err3_n (mp_ptr rp, mp_srcptr s1p, mp_srcptr s2p,
+		   mp_ptr ep, mp_srcptr y1p, mp_srcptr y2p, mp_srcptr y3p,
+		   mp_size_t size, mp_limb_t carry)
+{
+  AORS_ERR3_N (adc);
+}
+mp_limb_t
+refmpn_sub_err3_n (mp_ptr rp, mp_srcptr s1p, mp_srcptr s2p,
+		   mp_ptr ep, mp_srcptr y1p, mp_srcptr y2p, mp_srcptr y3p,
+		   mp_size_t size, mp_limb_t carry)
+{
+  AORS_ERR3_N (sbb);
+}
+
+
+mp_limb_t
+refmpn_addlsh_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp,
+		 mp_size_t n, unsigned int s)
+{
+  mp_limb_t cy;
+  mp_ptr tp;
+
+  ASSERT (refmpn_overlap_fullonly_two_p (rp, up, vp, n));
+  ASSERT (n >= 1);
+  ASSERT (0 < s && s < GMP_NUMB_BITS);
+  ASSERT_MPN (up, n);
+  ASSERT_MPN (vp, n);
+
+  tp = refmpn_malloc_limbs (n);
+  cy  = refmpn_lshift (tp, vp, n, s);
+  cy += refmpn_add_n (rp, up, tp, n);
+  free (tp);
+  return cy;
+}
+mp_limb_t
+refmpn_addlsh1_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n)
+{
+  return refmpn_addlsh_n (rp, up, vp, n, 1);
+}
+mp_limb_t
+refmpn_addlsh2_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n)
+{
+  return refmpn_addlsh_n (rp, up, vp, n, 2);
+}
+mp_limb_t
+refmpn_addlsh_n_ip1 (mp_ptr rp, mp_srcptr vp, mp_size_t n, unsigned int s)
+{
+  return refmpn_addlsh_n (rp, rp, vp, n, s);
+}
+mp_limb_t
+refmpn_addlsh1_n_ip1 (mp_ptr rp, mp_srcptr vp, mp_size_t n)
+{
+  return refmpn_addlsh_n (rp, rp, vp, n, 1);
+}
+mp_limb_t
+refmpn_addlsh2_n_ip1 (mp_ptr rp, mp_srcptr vp, mp_size_t n)
+{
+  return refmpn_addlsh_n (rp, rp, vp, n, 2);
+}
+mp_limb_t
+refmpn_addlsh_n_ip2 (mp_ptr rp, mp_srcptr vp, mp_size_t n, unsigned int s)
+{
+  return refmpn_addlsh_n (rp, vp, rp, n, s);
+}
+mp_limb_t
+refmpn_addlsh1_n_ip2 (mp_ptr rp, mp_srcptr vp, mp_size_t n)
+{
+  return refmpn_addlsh_n (rp, vp, rp, n, 1);
+}
+mp_limb_t
+refmpn_addlsh2_n_ip2 (mp_ptr rp, mp_srcptr vp, mp_size_t n)
+{
+  return refmpn_addlsh_n (rp, vp, rp, n, 2);
+}
+mp_limb_t
+refmpn_addlsh_nc (mp_ptr rp, mp_srcptr up, mp_srcptr vp,
+		  mp_size_t n, unsigned int s, mp_limb_t carry)
+{
+  mp_limb_t cy;
+
+  ASSERT (carry <= (CNST_LIMB(1) << s));
+
+  cy = refmpn_addlsh_n (rp, up, vp, n, s);
+  cy += refmpn_add_1 (rp, rp, n, carry);
+  return cy;
+}
+mp_limb_t
+refmpn_addlsh1_nc (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n, mp_limb_t carry)
+{
+  return refmpn_addlsh_nc (rp, up, vp, n, 1, carry);
+}
+mp_limb_t
+refmpn_addlsh2_nc (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n, mp_limb_t carry)
+{
+  return refmpn_addlsh_nc (rp, up, vp, n, 2, carry);
+}
+
+mp_limb_t
+refmpn_sublsh_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp,
+		 mp_size_t n, unsigned int s)
+{
+  mp_limb_t cy;
+  mp_ptr tp;
+
+  ASSERT (refmpn_overlap_fullonly_two_p (rp, up, vp, n));
+  ASSERT (n >= 1);
+  ASSERT (0 < s && s < GMP_NUMB_BITS);
+  ASSERT_MPN (up, n);
+  ASSERT_MPN (vp, n);
+
+  tp = refmpn_malloc_limbs (n);
+  cy  = mpn_lshift (tp, vp, n, s);
+  cy += mpn_sub_n (rp, up, tp, n);
+  free (tp);
+  return cy;
+}
+mp_limb_t
+refmpn_sublsh1_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n)
+{
+  return refmpn_sublsh_n (rp, up, vp, n, 1);
+}
+mp_limb_t
+refmpn_sublsh2_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n)
+{
+  return refmpn_sublsh_n (rp, up, vp, n, 2);
+}
+mp_limb_t
+refmpn_sublsh_n_ip1 (mp_ptr rp, mp_srcptr vp, mp_size_t n, unsigned int s)
+{
+  return refmpn_sublsh_n (rp, rp, vp, n, s);
+}
+mp_limb_t
+refmpn_sublsh1_n_ip1 (mp_ptr rp, mp_srcptr vp, mp_size_t n)
+{
+  return refmpn_sublsh_n (rp, rp, vp, n, 1);
+}
+mp_limb_t
+refmpn_sublsh2_n_ip1 (mp_ptr rp, mp_srcptr vp, mp_size_t n)
+{
+  return refmpn_sublsh_n (rp, rp, vp, n, 2);
+}
+mp_limb_t
+refmpn_sublsh_n_ip2 (mp_ptr rp, mp_srcptr vp, mp_size_t n, unsigned int s)
+{
+  return refmpn_sublsh_n (rp, vp, rp, n, s);
+}
+mp_limb_t
+refmpn_sublsh1_n_ip2 (mp_ptr rp, mp_srcptr vp, mp_size_t n)
+{
+  return refmpn_sublsh_n (rp, vp, rp, n, 1);
+}
+mp_limb_t
+refmpn_sublsh2_n_ip2 (mp_ptr rp, mp_srcptr vp, mp_size_t n)
+{
+  return refmpn_sublsh_n (rp, vp, rp, n, 2);
+}
+mp_limb_t
+refmpn_sublsh_nc (mp_ptr rp, mp_srcptr up, mp_srcptr vp,
+		  mp_size_t n, unsigned int s, mp_limb_t carry)
+{
+  mp_limb_t cy;
+
+  ASSERT (carry <= (CNST_LIMB(1) << s));
+
+  cy = refmpn_sublsh_n (rp, up, vp, n, s);
+  cy += refmpn_sub_1 (rp, rp, n, carry);
+  return cy;
+}
+mp_limb_t
+refmpn_sublsh1_nc (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n, mp_limb_t carry)
+{
+  return refmpn_sublsh_nc (rp, up, vp, n, 1, carry);
+}
+mp_limb_t
+refmpn_sublsh2_nc (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n, mp_limb_t carry)
+{
+  return refmpn_sublsh_nc (rp, up, vp, n, 2, carry);
+}
+
+mp_limb_signed_t
+refmpn_rsblsh_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp,
+		 mp_size_t n, unsigned int s)
+{
+  mp_limb_signed_t cy;
+  mp_ptr tp;
+
+  ASSERT (refmpn_overlap_fullonly_two_p (rp, up, vp, n));
+  ASSERT (n >= 1);
+  ASSERT (0 < s && s < GMP_NUMB_BITS);
+  ASSERT_MPN (up, n);
+  ASSERT_MPN (vp, n);
+
+  tp = refmpn_malloc_limbs (n);
+  cy  = mpn_lshift (tp, vp, n, s);
+  cy -= mpn_sub_n (rp, tp, up, n);
+  free (tp);
+  return cy;
+}
+mp_limb_signed_t
+refmpn_rsblsh1_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n)
+{
+  return refmpn_rsblsh_n (rp, up, vp, n, 1);
+}
+mp_limb_signed_t
+refmpn_rsblsh2_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n)
+{
+  return refmpn_rsblsh_n (rp, up, vp, n, 2);
+}
+mp_limb_signed_t
+refmpn_rsblsh_nc (mp_ptr rp, mp_srcptr up, mp_srcptr vp,
+		  mp_size_t n, unsigned int s, mp_limb_signed_t carry)
+{
+  mp_limb_signed_t cy;
+
+  ASSERT (carry == -1 || (carry >> s) == 0);
+
+  cy = refmpn_rsblsh_n (rp, up, vp, n, s);
+  if (carry > 0)
+    cy += refmpn_add_1 (rp, rp, n, carry);
+  else
+    cy -= refmpn_sub_1 (rp, rp, n, -carry);
+  return cy;
+}
+mp_limb_signed_t
+refmpn_rsblsh1_nc (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n, mp_limb_signed_t carry)
+{
+  return refmpn_rsblsh_nc (rp, up, vp, n, 1, carry);
+}
+mp_limb_signed_t
+refmpn_rsblsh2_nc (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n, mp_limb_signed_t carry)
+{
+  return refmpn_rsblsh_nc (rp, up, vp, n, 2, carry);
+}
+
+mp_limb_t
+refmpn_rsh1add_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n)
+{
+  mp_limb_t cya, cys;
+
+  ASSERT (refmpn_overlap_fullonly_two_p (rp, up, vp, n));
+  ASSERT (n >= 1);
+  ASSERT_MPN (up, n);
+  ASSERT_MPN (vp, n);
+
+  cya = mpn_add_n (rp, up, vp, n);
+  cys = mpn_rshift (rp, rp, n, 1) >> (GMP_NUMB_BITS - 1);
+  rp[n - 1] |= cya << (GMP_NUMB_BITS - 1);
+  return cys;
+}
+mp_limb_t
+refmpn_rsh1sub_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n)
+{
+  mp_limb_t cya, cys;
+
+  ASSERT (refmpn_overlap_fullonly_two_p (rp, up, vp, n));
+  ASSERT (n >= 1);
+  ASSERT_MPN (up, n);
+  ASSERT_MPN (vp, n);
+
+  cya = mpn_sub_n (rp, up, vp, n);
+  cys = mpn_rshift (rp, rp, n, 1) >> (GMP_NUMB_BITS - 1);
+  rp[n - 1] |= cya << (GMP_NUMB_BITS - 1);
+  return cys;
+}
+
+/* Twos complement, return borrow. */
+mp_limb_t
+refmpn_neg (mp_ptr dst, mp_srcptr src, mp_size_t size)
+{
+  mp_ptr     zeros;
+  mp_limb_t  ret;
+
+  ASSERT (size >= 1);
+
+  zeros = refmpn_malloc_limbs (size);
+  refmpn_fill (zeros, size, CNST_LIMB(0));
+  ret = refmpn_sub_n (dst, zeros, src, size);
+  free (zeros);
+  return ret;
+}
+
+
+#define AORS(aors_n, aors_1)                                    \
+  {                                                             \
+    mp_limb_t  c;                                               \
+    ASSERT (s1size >= s2size);                                  \
+    ASSERT (s2size >= 1);                                       \
+    c = aors_n (rp, s1p, s2p, s2size);                          \
+    if (s1size-s2size != 0)                                     \
+      c = aors_1 (rp+s2size, s1p+s2size, s1size-s2size, c);     \
+    return c;                                                   \
+  }
+mp_limb_t
+refmpn_add (mp_ptr rp,
+	    mp_srcptr s1p, mp_size_t s1size,
+	    mp_srcptr s2p, mp_size_t s2size)
+{
+  AORS (refmpn_add_n, refmpn_add_1);
+}
+mp_limb_t
+refmpn_sub (mp_ptr rp,
+	    mp_srcptr s1p, mp_size_t s1size,
+	    mp_srcptr s2p, mp_size_t s2size)
+{
+  AORS (refmpn_sub_n, refmpn_sub_1);
+}
+
+
+#define SHIFTHIGH(x) ((x) << GMP_LIMB_BITS/2)
+#define SHIFTLOW(x)  ((x) >> GMP_LIMB_BITS/2)
+
+#define LOWMASK   (((mp_limb_t) 1 << GMP_LIMB_BITS/2)-1)
+#define HIGHMASK  SHIFTHIGH(LOWMASK)
+
+#define LOWPART(x)   ((x) & LOWMASK)
+#define HIGHPART(x)  SHIFTLOW((x) & HIGHMASK)
+
+/* Set return:*lo to x*y, using full limbs not nails. */
+mp_limb_t
+refmpn_umul_ppmm (mp_limb_t *lo, mp_limb_t x, mp_limb_t y)
+{
+  mp_limb_t  hi, s;
+
+  *lo = LOWPART(x) * LOWPART(y);
+  hi = HIGHPART(x) * HIGHPART(y);
+
+  s = LOWPART(x) * HIGHPART(y);
+  hi += HIGHPART(s);
+  s = SHIFTHIGH(LOWPART(s));
+  *lo += s;
+  hi += (*lo < s);
+
+  s = HIGHPART(x) * LOWPART(y);
+  hi += HIGHPART(s);
+  s = SHIFTHIGH(LOWPART(s));
+  *lo += s;
+  hi += (*lo < s);
+
+  return hi;
+}
+
+mp_limb_t
+refmpn_umul_ppmm_r (mp_limb_t x, mp_limb_t y, mp_limb_t *lo)
+{
+  return refmpn_umul_ppmm (lo, x, y);
+}
+
+mp_limb_t
+refmpn_mul_1c (mp_ptr rp, mp_srcptr sp, mp_size_t size, mp_limb_t multiplier,
+	       mp_limb_t carry)
+{
+  mp_size_t  i;
+  mp_limb_t  hi, lo;
+
+  ASSERT (refmpn_overlap_low_to_high_p (rp, sp, size));
+  ASSERT (size >= 1);
+  ASSERT_MPN (sp, size);
+  ASSERT_LIMB (multiplier);
+  ASSERT_LIMB (carry);
+
+  multiplier <<= GMP_NAIL_BITS;
+  for (i = 0; i < size; i++)
+    {
+      hi = refmpn_umul_ppmm (&lo, sp[i], multiplier);
+      lo >>= GMP_NAIL_BITS;
+      ASSERT_NOCARRY (ref_addc_limb (&hi, hi, ref_addc_limb (&lo, lo, carry)));
+      rp[i] = lo;
+      carry = hi;
+    }
+  return carry;
+}
+
+mp_limb_t
+refmpn_mul_1 (mp_ptr rp, mp_srcptr sp, mp_size_t size, mp_limb_t multiplier)
+{
+  return refmpn_mul_1c (rp, sp, size, multiplier, CNST_LIMB(0));
+}
+
+
+mp_limb_t
+refmpn_mul_N (mp_ptr dst, mp_srcptr src, mp_size_t size,
+	      mp_srcptr mult, mp_size_t msize)
+{
+  mp_ptr     src_copy;
+  mp_limb_t  ret;
+  mp_size_t  i;
+
+  ASSERT (refmpn_overlap_fullonly_p (dst, src, size));
+  ASSERT (! refmpn_overlap_p (dst, size+msize-1, mult, msize));
+  ASSERT (size >= msize);
+  ASSERT_MPN (mult, msize);
+
+  /* in case dst==src */
+  src_copy = refmpn_malloc_limbs (size);
+  refmpn_copyi (src_copy, src, size);
+  src = src_copy;
+
+  dst[size] = refmpn_mul_1 (dst, src, size, mult[0]);
+  for (i = 1; i < msize-1; i++)
+    dst[size+i] = refmpn_addmul_1 (dst+i, src, size, mult[i]);
+  ret = refmpn_addmul_1 (dst+i, src, size, mult[i]);
+
+  free (src_copy);
+  return ret;
+}
+
+mp_limb_t
+refmpn_mul_2 (mp_ptr rp, mp_srcptr sp, mp_size_t size, mp_srcptr mult)
+{
+  return refmpn_mul_N (rp, sp, size, mult, (mp_size_t) 2);
+}
+mp_limb_t
+refmpn_mul_3 (mp_ptr rp, mp_srcptr sp, mp_size_t size, mp_srcptr mult)
+{
+  return refmpn_mul_N (rp, sp, size, mult, (mp_size_t) 3);
+}
+mp_limb_t
+refmpn_mul_4 (mp_ptr rp, mp_srcptr sp, mp_size_t size, mp_srcptr mult)
+{
+  return refmpn_mul_N (rp, sp, size, mult, (mp_size_t) 4);
+}
+mp_limb_t
+refmpn_mul_5 (mp_ptr rp, mp_srcptr sp, mp_size_t size, mp_srcptr mult)
+{
+  return refmpn_mul_N (rp, sp, size, mult, (mp_size_t) 5);
+}
+mp_limb_t
+refmpn_mul_6 (mp_ptr rp, mp_srcptr sp, mp_size_t size, mp_srcptr mult)
+{
+  return refmpn_mul_N (rp, sp, size, mult, (mp_size_t) 6);
+}
+
+#define AORSMUL_1C(operation_n)                                 \
+  {                                                             \
+    mp_ptr     p;                                               \
+    mp_limb_t  ret;                                             \
+								\
+    ASSERT (refmpn_overlap_fullonly_p (rp, sp, size));          \
+								\
+    p = refmpn_malloc_limbs (size);                             \
+    ret = refmpn_mul_1c (p, sp, size, multiplier, carry);       \
+    ret += operation_n (rp, rp, p, size);                       \
+								\
+    free (p);                                                   \
+    return ret;                                                 \
+  }
+
+mp_limb_t
+refmpn_addmul_1c (mp_ptr rp, mp_srcptr sp, mp_size_t size,
+		  mp_limb_t multiplier, mp_limb_t carry)
+{
+  AORSMUL_1C (refmpn_add_n);
+}
+mp_limb_t
+refmpn_submul_1c (mp_ptr rp, mp_srcptr sp, mp_size_t size,
+		  mp_limb_t multiplier, mp_limb_t carry)
+{
+  AORSMUL_1C (refmpn_sub_n);
+}
+
+
+mp_limb_t
+refmpn_addmul_1 (mp_ptr rp, mp_srcptr sp, mp_size_t size, mp_limb_t multiplier)
+{
+  return refmpn_addmul_1c (rp, sp, size, multiplier, CNST_LIMB(0));
+}
+mp_limb_t
+refmpn_submul_1 (mp_ptr rp, mp_srcptr sp, mp_size_t size, mp_limb_t multiplier)
+{
+  return refmpn_submul_1c (rp, sp, size, multiplier, CNST_LIMB(0));
+}
+
+
+mp_limb_t
+refmpn_addmul_N (mp_ptr dst, mp_srcptr src, mp_size_t size,
+		 mp_srcptr mult, mp_size_t msize)
+{
+  mp_ptr     src_copy;
+  mp_limb_t  ret;
+  mp_size_t  i;
+
+  ASSERT (dst == src || ! refmpn_overlap_p (dst, size+msize-1, src, size));
+  ASSERT (! refmpn_overlap_p (dst, size+msize-1, mult, msize));
+  ASSERT (size >= msize);
+  ASSERT_MPN (mult, msize);
+
+  /* in case dst==src */
+  src_copy = refmpn_malloc_limbs (size);
+  refmpn_copyi (src_copy, src, size);
+  src = src_copy;
+
+  for (i = 0; i < msize-1; i++)
+    dst[size+i] = refmpn_addmul_1 (dst+i, src, size, mult[i]);
+  ret = refmpn_addmul_1 (dst+i, src, size, mult[i]);
+
+  free (src_copy);
+  return ret;
+}
+
+mp_limb_t
+refmpn_addmul_2 (mp_ptr rp, mp_srcptr sp, mp_size_t size, mp_srcptr mult)
+{
+  return refmpn_addmul_N (rp, sp, size, mult, (mp_size_t) 2);
+}
+mp_limb_t
+refmpn_addmul_3 (mp_ptr rp, mp_srcptr sp, mp_size_t size, mp_srcptr mult)
+{
+  return refmpn_addmul_N (rp, sp, size, mult, (mp_size_t) 3);
+}
+mp_limb_t
+refmpn_addmul_4 (mp_ptr rp, mp_srcptr sp, mp_size_t size, mp_srcptr mult)
+{
+  return refmpn_addmul_N (rp, sp, size, mult, (mp_size_t) 4);
+}
+mp_limb_t
+refmpn_addmul_5 (mp_ptr rp, mp_srcptr sp, mp_size_t size, mp_srcptr mult)
+{
+  return refmpn_addmul_N (rp, sp, size, mult, (mp_size_t) 5);
+}
+mp_limb_t
+refmpn_addmul_6 (mp_ptr rp, mp_srcptr sp, mp_size_t size, mp_srcptr mult)
+{
+  return refmpn_addmul_N (rp, sp, size, mult, (mp_size_t) 6);
+}
+mp_limb_t
+refmpn_addmul_7 (mp_ptr rp, mp_srcptr sp, mp_size_t size, mp_srcptr mult)
+{
+  return refmpn_addmul_N (rp, sp, size, mult, (mp_size_t) 7);
+}
+mp_limb_t
+refmpn_addmul_8 (mp_ptr rp, mp_srcptr sp, mp_size_t size, mp_srcptr mult)
+{
+  return refmpn_addmul_N (rp, sp, size, mult, (mp_size_t) 8);
+}
+
+mp_limb_t
+refmpn_add_n_sub_nc (mp_ptr r1p, mp_ptr r2p,
+		  mp_srcptr s1p, mp_srcptr s2p, mp_size_t size,
+		  mp_limb_t carry)
+{
+  mp_ptr p;
+  mp_limb_t acy, scy;
+
+  /* Destinations can't overlap. */
+  ASSERT (! refmpn_overlap_p (r1p, size, r2p, size));
+  ASSERT (refmpn_overlap_fullonly_two_p (r1p, s1p, s2p, size));
+  ASSERT (refmpn_overlap_fullonly_two_p (r2p, s1p, s2p, size));
+  ASSERT (size >= 1);
+
+  /* in case r1p==s1p or r1p==s2p */
+  p = refmpn_malloc_limbs (size);
+
+  acy = refmpn_add_nc (p, s1p, s2p, size, carry >> 1);
+  scy = refmpn_sub_nc (r2p, s1p, s2p, size, carry & 1);
+  refmpn_copyi (r1p, p, size);
+
+  free (p);
+  return 2 * acy + scy;
+}
+
+mp_limb_t
+refmpn_add_n_sub_n (mp_ptr r1p, mp_ptr r2p,
+		 mp_srcptr s1p, mp_srcptr s2p, mp_size_t size)
+{
+  return refmpn_add_n_sub_nc (r1p, r2p, s1p, s2p, size, CNST_LIMB(0));
+}
+
+
+/* Right shift hi,lo and return the low limb of the result.
+   Note a shift by GMP_LIMB_BITS isn't assumed to work (doesn't on x86). */
+mp_limb_t
+rshift_make (mp_limb_t hi, mp_limb_t lo, unsigned shift)
+{
+  ASSERT (shift < GMP_NUMB_BITS);
+  if (shift == 0)
+    return lo;
+  else
+    return ((hi << (GMP_NUMB_BITS-shift)) | (lo >> shift)) & GMP_NUMB_MASK;
+}
+
+/* Left shift hi,lo and return the high limb of the result.
+   Note a shift by GMP_LIMB_BITS isn't assumed to work (doesn't on x86). */
+mp_limb_t
+lshift_make (mp_limb_t hi, mp_limb_t lo, unsigned shift)
+{
+  ASSERT (shift < GMP_NUMB_BITS);
+  if (shift == 0)
+    return hi;
+  else
+    return ((hi << shift) | (lo >> (GMP_NUMB_BITS-shift))) & GMP_NUMB_MASK;
+}
+
+
+mp_limb_t
+refmpn_rshift (mp_ptr rp, mp_srcptr sp, mp_size_t size, unsigned shift)
+{
+  mp_limb_t  ret;
+  mp_size_t  i;
+
+  ASSERT (refmpn_overlap_low_to_high_p (rp, sp, size));
+  ASSERT (size >= 1);
+  ASSERT (shift >= 1 && shift < GMP_NUMB_BITS);
+  ASSERT_MPN (sp, size);
+
+  ret = rshift_make (sp[0], CNST_LIMB(0), shift);
+
+  for (i = 0; i < size-1; i++)
+    rp[i] = rshift_make (sp[i+1], sp[i], shift);
+
+  rp[i] = rshift_make (CNST_LIMB(0), sp[i], shift);
+  return ret;
+}
+
+mp_limb_t
+refmpn_lshift (mp_ptr rp, mp_srcptr sp, mp_size_t size, unsigned shift)
+{
+  mp_limb_t  ret;
+  mp_size_t  i;
+
+  ASSERT (refmpn_overlap_high_to_low_p (rp, sp, size));
+  ASSERT (size >= 1);
+  ASSERT (shift >= 1 && shift < GMP_NUMB_BITS);
+  ASSERT_MPN (sp, size);
+
+  ret = lshift_make (CNST_LIMB(0), sp[size-1], shift);
+
+  for (i = size-2; i >= 0; i--)
+    rp[i+1] = lshift_make (sp[i+1], sp[i], shift);
+
+  rp[i+1] = lshift_make (sp[i+1], CNST_LIMB(0), shift);
+  return ret;
+}
+
+void
+refmpn_com (mp_ptr rp, mp_srcptr sp, mp_size_t size)
+{
+  mp_size_t i;
+
+  /* We work downwards since mpn_lshiftc needs that. */
+  ASSERT (refmpn_overlap_high_to_low_p (rp, sp, size));
+
+  for (i = size - 1; i >= 0; i--)
+    rp[i] = (~sp[i]) & GMP_NUMB_MASK;
+}
+
+mp_limb_t
+refmpn_lshiftc (mp_ptr rp, mp_srcptr sp, mp_size_t size, unsigned shift)
+{
+  mp_limb_t res;
+
+  /* No asserts here, refmpn_lshift will assert what we need. */
+
+  res = refmpn_lshift (rp, sp, size, shift);
+  refmpn_com (rp, rp, size);
+  return res;
+}
+
+/* accepting shift==0 and doing a plain copyi or copyd in that case */
+mp_limb_t
+refmpn_rshift_or_copy (mp_ptr rp, mp_srcptr sp, mp_size_t size, unsigned shift)
+{
+  if (shift == 0)
+    {
+      refmpn_copyi (rp, sp, size);
+      return 0;
+    }
+  else
+    {
+      return refmpn_rshift (rp, sp, size, shift);
+    }
+}
+mp_limb_t
+refmpn_lshift_or_copy (mp_ptr rp, mp_srcptr sp, mp_size_t size, unsigned shift)
+{
+  if (shift == 0)
+    {
+      refmpn_copyd (rp, sp, size);
+      return 0;
+    }
+  else
+    {
+      return refmpn_lshift (rp, sp, size, shift);
+    }
+}
+
+/* accepting size==0 too */
+mp_limb_t
+refmpn_rshift_or_copy_any (mp_ptr rp, mp_srcptr sp, mp_size_t size,
+			   unsigned shift)
+{
+  return (size == 0 ? 0 : refmpn_rshift_or_copy (rp, sp, size, shift));
+}
+mp_limb_t
+refmpn_lshift_or_copy_any (mp_ptr rp, mp_srcptr sp, mp_size_t size,
+			   unsigned shift)
+{
+  return (size == 0 ? 0 : refmpn_lshift_or_copy (rp, sp, size, shift));
+}
+
+/* Divide h,l by d, return quotient, store remainder to *rp.
+   Operates on full limbs, not nails.
+   Must have h < d.
+   __udiv_qrnnd_c isn't simple, and it's a bit slow, but it works. */
+mp_limb_t
+refmpn_udiv_qrnnd (mp_limb_t *rp, mp_limb_t h, mp_limb_t l, mp_limb_t d)
+{
+  mp_limb_t  q, r;
+  int  n;
+
+  ASSERT (d != 0);
+  ASSERT (h < d);
+
+#if 0
+  udiv_qrnnd (q, r, h, l, d);
+  *rp = r;
+  return q;
+#endif
+
+  n = refmpn_count_leading_zeros (d);
+  d <<= n;
+
+  if (n != 0)
+    {
+      h = (h << n) | (l >> (GMP_LIMB_BITS - n));
+      l <<= n;
+    }
+
+  __udiv_qrnnd_c (q, r, h, l, d);
+  r >>= n;
+  *rp = r;
+  return q;
+}
+
+mp_limb_t
+refmpn_udiv_qrnnd_r (mp_limb_t h, mp_limb_t l, mp_limb_t d, mp_limb_t *rp)
+{
+  return refmpn_udiv_qrnnd (rp, h, l, d);
+}
+
+/* This little subroutine avoids some bad code generation from i386 gcc 3.0
+   -fPIC -O2 -fomit-frame-pointer (%ebp being used uninitialized).  */
+static mp_limb_t
+refmpn_divmod_1c_workaround (mp_ptr rp, mp_srcptr sp, mp_size_t size,
+			     mp_limb_t divisor, mp_limb_t carry)
+{
+  mp_size_t  i;
+  mp_limb_t rem[1];
+  for (i = size-1; i >= 0; i--)
+    {
+      rp[i] = refmpn_udiv_qrnnd (rem, carry,
+				 sp[i] << GMP_NAIL_BITS,
+				 divisor << GMP_NAIL_BITS);
+      carry = *rem >> GMP_NAIL_BITS;
+    }
+  return carry;
+}
+
+mp_limb_t
+refmpn_divmod_1c (mp_ptr rp, mp_srcptr sp, mp_size_t size,
+		  mp_limb_t divisor, mp_limb_t carry)
+{
+  mp_ptr     sp_orig;
+  mp_ptr     prod;
+  mp_limb_t  carry_orig;
+
+  ASSERT (refmpn_overlap_fullonly_p (rp, sp, size));
+  ASSERT (size >= 0);
+  ASSERT (carry < divisor);
+  ASSERT_MPN (sp, size);
+  ASSERT_LIMB (divisor);
+  ASSERT_LIMB (carry);
+
+  if (size == 0)
+    return carry;
+
+  sp_orig = refmpn_memdup_limbs (sp, size);
+  prod = refmpn_malloc_limbs (size);
+  carry_orig = carry;
+
+  carry = refmpn_divmod_1c_workaround (rp, sp, size, divisor, carry);
+
+  /* check by multiplying back */
+#if 0
+  printf ("size=%ld divisor=0x%lX carry=0x%lX remainder=0x%lX\n",
+	  size, divisor, carry_orig, carry);
+  mpn_trace("s",sp_copy,size);
+  mpn_trace("r",rp,size);
+  printf ("mul_1c %lX\n", refmpn_mul_1c (prod, rp, size, divisor, carry));
+  mpn_trace("p",prod,size);
+#endif
+  ASSERT (refmpn_mul_1c (prod, rp, size, divisor, carry) == carry_orig);
+  ASSERT (refmpn_cmp (prod, sp_orig, size) == 0);
+  free (sp_orig);
+  free (prod);
+
+  return carry;
+}
+
+mp_limb_t
+refmpn_divmod_1 (mp_ptr rp, mp_srcptr sp, mp_size_t size, mp_limb_t divisor)
+{
+  return refmpn_divmod_1c (rp, sp, size, divisor, CNST_LIMB(0));
+}
+
+
+mp_limb_t
+refmpn_mod_1c (mp_srcptr sp, mp_size_t size, mp_limb_t divisor,
+	       mp_limb_t carry)
+{
+  mp_ptr  p = refmpn_malloc_limbs (size);
+  carry = refmpn_divmod_1c (p, sp, size, divisor, carry);
+  free (p);
+  return carry;
+}
+
+mp_limb_t
+refmpn_mod_1 (mp_srcptr sp, mp_size_t size, mp_limb_t divisor)
+{
+  return refmpn_mod_1c (sp, size, divisor, CNST_LIMB(0));
+}
+
+mp_limb_t
+refmpn_preinv_mod_1 (mp_srcptr sp, mp_size_t size, mp_limb_t divisor,
+		     mp_limb_t inverse)
+{
+  ASSERT (divisor & GMP_NUMB_HIGHBIT);
+  ASSERT (inverse == refmpn_invert_limb (divisor));
+  return refmpn_mod_1 (sp, size, divisor);
+}
+
+/* This implementation will be rather slow, but has the advantage of being
+   in a different style than the libgmp versions.  */
+mp_limb_t
+refmpn_mod_34lsub1 (mp_srcptr p, mp_size_t n)
+{
+  ASSERT ((GMP_NUMB_BITS % 4) == 0);
+  return mpn_mod_1 (p, n, (CNST_LIMB(1) << (3 * GMP_NUMB_BITS / 4)) - 1);
+}
+
+
+mp_limb_t
+refmpn_divrem_1c (mp_ptr rp, mp_size_t xsize,
+		  mp_srcptr sp, mp_size_t size, mp_limb_t divisor,
+		  mp_limb_t carry)
+{
+  mp_ptr  z;
+
+  z = refmpn_malloc_limbs (xsize);
+  refmpn_fill (z, xsize, CNST_LIMB(0));
+
+  carry = refmpn_divmod_1c (rp+xsize, sp, size, divisor, carry);
+  carry = refmpn_divmod_1c (rp, z, xsize, divisor, carry);
+
+  free (z);
+  return carry;
+}
+
+mp_limb_t
+refmpn_divrem_1 (mp_ptr rp, mp_size_t xsize,
+		 mp_srcptr sp, mp_size_t size, mp_limb_t divisor)
+{
+  return refmpn_divrem_1c (rp, xsize, sp, size, divisor, CNST_LIMB(0));
+}
+
+mp_limb_t
+refmpn_preinv_divrem_1 (mp_ptr rp, mp_size_t xsize,
+			mp_srcptr sp, mp_size_t size,
+			mp_limb_t divisor, mp_limb_t inverse, unsigned shift)
+{
+  ASSERT (size >= 0);
+  ASSERT (shift == refmpn_count_leading_zeros (divisor));
+  ASSERT (inverse == refmpn_invert_limb (divisor << shift));
+
+  return refmpn_divrem_1 (rp, xsize, sp, size, divisor);
+}
+
+mp_limb_t
+refmpn_divrem_2 (mp_ptr qp, mp_size_t qxn,
+		 mp_ptr np, mp_size_t nn,
+		 mp_srcptr dp)
+{
+  mp_ptr tp;
+  mp_limb_t qh;
+
+  tp = refmpn_malloc_limbs (nn + qxn);
+  refmpn_zero (tp, qxn);
+  refmpn_copyi (tp + qxn, np, nn);
+  qh = refmpn_sb_div_qr (qp, tp, nn + qxn, dp, 2);
+  refmpn_copyi (np, tp, 2);
+  free (tp);
+  return qh;
+}
+
+/* Inverse is floor((b*(b-d)-1) / d), per division by invariant integers
+   paper, figure 8.1 m', where b=2^GMP_LIMB_BITS.  Note that -d-1 < d
+   since d has the high bit set. */
+
+mp_limb_t
+refmpn_invert_limb (mp_limb_t d)
+{
+  mp_limb_t r;
+  ASSERT (d & GMP_LIMB_HIGHBIT);
+  return refmpn_udiv_qrnnd (&r, -d-1, MP_LIMB_T_MAX, d);
+}
+
+void
+refmpn_invert (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_ptr scratch)
+{
+  mp_ptr qp, tp;
+  TMP_DECL;
+  TMP_MARK;
+
+  tp = TMP_ALLOC_LIMBS (2 * n);
+  qp = TMP_ALLOC_LIMBS (n + 1);
+
+  MPN_ZERO (tp, 2 * n);  mpn_sub_1 (tp, tp, 2 * n, 1);
+
+  refmpn_tdiv_qr (qp, rp, 0, tp, 2 * n, up, n);
+  refmpn_copyi (rp, qp, n);
+
+  TMP_FREE;
+}
+
+void
+refmpn_binvert (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_ptr scratch)
+{
+  mp_ptr tp;
+  mp_limb_t binv;
+  TMP_DECL;
+  TMP_MARK;
+
+  /* We use the library mpn_sbpi1_bdiv_q here, which isn't kosher in testing
+     code.  To make up for it, we check that the inverse is correct using a
+     multiply.  */
+
+  tp = TMP_ALLOC_LIMBS (2 * n);
+
+  MPN_ZERO (tp, n);
+  tp[0] = 1;
+  binvert_limb (binv, up[0]);
+  mpn_sbpi1_bdiv_q (rp, tp, n, up, n, -binv);
+
+  refmpn_mul_n (tp, rp, up, n);
+  ASSERT_ALWAYS (tp[0] == 1 && mpn_zero_p (tp + 1, n - 1));
+
+  TMP_FREE;
+}
+
+/* The aim is to produce a dst quotient and return a remainder c, satisfying
+   c*b^n + src-i == 3*dst, where i is the incoming carry.
+
+   Some value c==0, c==1 or c==2 will satisfy, so just try each.
+
+   If GMP_NUMB_BITS is even then 2^GMP_NUMB_BITS==1mod3 and a non-zero
+   remainder from the first division attempt determines the correct
+   remainder (3-c), but don't bother with that, since we can't guarantee
+   anything about GMP_NUMB_BITS when using nails.
+
+   If the initial src-i produces a borrow then refmpn_sub_1 leaves a twos
+   complement negative, ie. b^n+a-i, and the calculation produces c1
+   satisfying c1*b^n + b^n+src-i == 3*dst, from which clearly c=c1+1.  This
+   means it's enough to just add any borrow back at the end.
+
+   A borrow only occurs when a==0 or a==1, and, by the same reasoning as in
+   mpn/generic/diveby3.c, the c1 that results in those cases will only be 0
+   or 1 respectively, so with 1 added the final return value is still in the
+   prescribed range 0 to 2. */
+
+mp_limb_t
+refmpn_divexact_by3c (mp_ptr rp, mp_srcptr sp, mp_size_t size, mp_limb_t carry)
+{
+  mp_ptr     spcopy;
+  mp_limb_t  c, cs;
+
+  ASSERT (refmpn_overlap_fullonly_p (rp, sp, size));
+  ASSERT (size >= 1);
+  ASSERT (carry <= 2);
+  ASSERT_MPN (sp, size);
+
+  spcopy = refmpn_malloc_limbs (size);
+  cs = refmpn_sub_1 (spcopy, sp, size, carry);
+
+  for (c = 0; c <= 2; c++)
+    if (refmpn_divmod_1c (rp, spcopy, size, CNST_LIMB(3), c) == 0)
+      goto done;
+  ASSERT_FAIL (no value of c satisfies);
+
+ done:
+  c += cs;
+  ASSERT (c <= 2);
+
+  free (spcopy);
+  return c;
+}
+
+mp_limb_t
+refmpn_divexact_by3 (mp_ptr rp, mp_srcptr sp, mp_size_t size)
+{
+  return refmpn_divexact_by3c (rp, sp, size, CNST_LIMB(0));
+}
+
+
+/* The same as mpn/generic/mul_basecase.c, but using refmpn functions. */
+void
+refmpn_mul_basecase (mp_ptr prodp,
+		     mp_srcptr up, mp_size_t usize,
+		     mp_srcptr vp, mp_size_t vsize)
+{
+  mp_size_t i;
+
+  ASSERT (! refmpn_overlap_p (prodp, usize+vsize, up, usize));
+  ASSERT (! refmpn_overlap_p (prodp, usize+vsize, vp, vsize));
+  ASSERT (usize >= vsize);
+  ASSERT (vsize >= 1);
+  ASSERT_MPN (up, usize);
+  ASSERT_MPN (vp, vsize);
+
+  prodp[usize] = refmpn_mul_1 (prodp, up, usize, vp[0]);
+  for (i = 1; i < vsize; i++)
+    prodp[usize+i] = refmpn_addmul_1 (prodp+i, up, usize, vp[i]);
+}
+
+
+/* The same as mpn/generic/mulmid_basecase.c, but using refmpn functions. */
+void
+refmpn_mulmid_basecase (mp_ptr rp,
+			mp_srcptr up, mp_size_t un,
+			mp_srcptr vp, mp_size_t vn)
+{
+  mp_limb_t cy;
+  mp_size_t i;
+
+  ASSERT (un >= vn);
+  ASSERT (vn >= 1);
+  ASSERT (! refmpn_overlap_p (rp, un - vn + 3, up, un));
+  ASSERT (! refmpn_overlap_p (rp, un - vn + 3, vp, vn));
+  ASSERT_MPN (up, un);
+  ASSERT_MPN (vp, vn);
+
+  rp[un - vn + 1] = refmpn_mul_1 (rp, up + vn - 1, un - vn + 1, vp[0]);
+  rp[un - vn + 2] = CNST_LIMB (0);
+  for (i = 1; i < vn; i++)
+    {
+      cy = refmpn_addmul_1 (rp, up + vn - i - 1, un - vn + 1, vp[i]);
+      cy = ref_addc_limb (&rp[un - vn + 1], rp[un - vn + 1], cy);
+      cy = ref_addc_limb (&rp[un - vn + 2], rp[un - vn + 2], cy);
+      ASSERT (cy == 0);
+    }
+}
+
+void
+refmpn_toom42_mulmid (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n,
+		      mp_ptr scratch)
+{
+  refmpn_mulmid_basecase (rp, up, 2*n - 1, vp, n);
+}
+
+void
+refmpn_mulmid_n (mp_ptr rp, mp_srcptr up, mp_srcptr vp, mp_size_t n)
+{
+  /* FIXME: this could be made faster by using refmpn_mul and then subtracting
+     off products near the middle product region boundary */
+  refmpn_mulmid_basecase (rp, up, 2*n - 1, vp, n);
+}
+
+void
+refmpn_mulmid (mp_ptr rp, mp_srcptr up, mp_size_t un,
+	       mp_srcptr vp, mp_size_t vn)
+{
+  /* FIXME: this could be made faster by using refmpn_mul and then subtracting
+     off products near the middle product region boundary */
+  refmpn_mulmid_basecase (rp, up, un, vp, vn);
+}
+
+
+
+#define TOOM3_THRESHOLD (MAX (MUL_TOOM33_THRESHOLD, SQR_TOOM3_THRESHOLD))
+#define TOOM4_THRESHOLD (MAX (MUL_TOOM44_THRESHOLD, SQR_TOOM4_THRESHOLD))
+#define TOOM6_THRESHOLD (MAX (MUL_TOOM6H_THRESHOLD, SQR_TOOM6_THRESHOLD))
+#if WANT_FFT
+#define FFT_THRESHOLD (MAX (MUL_FFT_THRESHOLD, SQR_FFT_THRESHOLD))
+#else
+#define FFT_THRESHOLD MP_SIZE_T_MAX /* don't use toom44 here */
+#endif
+
+void
+refmpn_mul (mp_ptr wp, mp_srcptr up, mp_size_t un, mp_srcptr vp, mp_size_t vn)
+{
+  mp_ptr tp, rp;
+  mp_size_t tn;
+
+  if (vn < TOOM3_THRESHOLD)
+    {
+      /* In the mpn_mul_basecase and toom2 ranges, use our own mul_basecase. */
+      if (vn != 0)
+	refmpn_mul_basecase (wp, up, un, vp, vn);
+      else
+	MPN_ZERO (wp, un);
+      return;
+    }
+
+  MPN_ZERO (wp, vn);
+  rp = refmpn_malloc_limbs (2 * vn);
+
+  if (vn < TOOM4_THRESHOLD)
+    tn = mpn_toom22_mul_itch (vn, vn);
+  else if (vn < TOOM6_THRESHOLD)
+    tn = mpn_toom33_mul_itch (vn, vn);
+  else if (vn < FFT_THRESHOLD)
+    tn = mpn_toom44_mul_itch (vn, vn);
+  else
+    tn = mpn_toom6h_mul_itch (vn, vn);
+  tp = refmpn_malloc_limbs (tn);
+
+  while (un >= vn)
+    {
+      if (vn < TOOM4_THRESHOLD)
+	/* In the toom3 range, use mpn_toom22_mul.  */
+	mpn_toom22_mul (rp, up, vn, vp, vn, tp);
+      else if (vn < TOOM6_THRESHOLD)
+	/* In the toom4 range, use mpn_toom33_mul.  */
+	mpn_toom33_mul (rp, up, vn, vp, vn, tp);
+      else if (vn < FFT_THRESHOLD)
+	/* In the toom6 range, use mpn_toom44_mul.  */
+	mpn_toom44_mul (rp, up, vn, vp, vn, tp);
+      else
+	/* For the largest operands, use mpn_toom6h_mul.  */
+	mpn_toom6h_mul (rp, up, vn, vp, vn, tp);
+
+      ASSERT_NOCARRY (refmpn_add (wp, rp, 2 * vn, wp, vn));
+      wp += vn;
+
+      up += vn;
+      un -= vn;
+    }
+
+  free (tp);
+
+  if (un != 0)
+    {
+      refmpn_mul (rp, vp, vn, up, un);
+      ASSERT_NOCARRY (refmpn_add (wp, rp, un + vn, wp, vn));
+    }
+  free (rp);
+}
+
+void
+refmpn_mul_n (mp_ptr prodp, mp_srcptr up, mp_srcptr vp, mp_size_t size)
+{
+  refmpn_mul (prodp, up, size, vp, size);
+}
+
+void
+refmpn_mullo_n (mp_ptr prodp, mp_srcptr up, mp_srcptr vp, mp_size_t size)
+{
+  mp_ptr tp = refmpn_malloc_limbs (2*size);
+  refmpn_mul (tp, up, size, vp, size);
+  refmpn_copyi (prodp, tp, size);
+  free (tp);
+}
+
+void
+refmpn_sqr (mp_ptr dst, mp_srcptr src, mp_size_t size)
+{
+  refmpn_mul (dst, src, size, src, size);
+}
+
+void
+refmpn_sqrlo (mp_ptr dst, mp_srcptr src, mp_size_t size)
+{
+  refmpn_mullo_n (dst, src, src, size);
+}
+
+/* Allowing usize<vsize, usize==0 or vsize==0. */
+void
+refmpn_mul_any (mp_ptr prodp,
+		     mp_srcptr up, mp_size_t usize,
+		     mp_srcptr vp, mp_size_t vsize)
+{
+  ASSERT (! refmpn_overlap_p (prodp, usize+vsize, up, usize));
+  ASSERT (! refmpn_overlap_p (prodp, usize+vsize, vp, vsize));
+  ASSERT (usize >= 0);
+  ASSERT (vsize >= 0);
+  ASSERT_MPN (up, usize);
+  ASSERT_MPN (vp, vsize);
+
+  if (usize == 0)
+    {
+      refmpn_fill (prodp, vsize, CNST_LIMB(0));
+      return;
+    }
+
+  if (vsize == 0)
+    {
+      refmpn_fill (prodp, usize, CNST_LIMB(0));
+      return;
+    }
+
+  if (usize >= vsize)
+    refmpn_mul (prodp, up, usize, vp, vsize);
+  else
+    refmpn_mul (prodp, vp, vsize, up, usize);
+}
+
+
+mp_limb_t
+refmpn_gcd_11 (mp_limb_t x, mp_limb_t y)
+{
+  /* The non-ref function also requires input operands to be odd, but
+     below refmpn_gcd_1 doesn't guarantee that. */
+  ASSERT (x > 0);
+  ASSERT (y > 0);
+  do
+    {
+      while ((x & 1) == 0)  x >>= 1;
+      while ((y & 1) == 0)  y >>= 1;
+
+      if (x < y)
+	MP_LIMB_T_SWAP (x, y);
+
+      x -= y;
+    }
+  while (x != 0);
+
+  return y;
+}
+
+mp_double_limb_t
+refmpn_gcd_22 (mp_limb_t x1, mp_limb_t x0, mp_limb_t y1, mp_limb_t y0)
+{
+  ASSERT ((x0 & 1) != 0);
+  ASSERT ((y0 & 1) != 0);
+  mp_double_limb_t g;
+  mp_limb_t cy;
+
+  do
+    {
+      while ((x0 & 1) == 0)
+	{
+	  x0 = (x1 << (GMP_NUMB_BITS - 1)) | (x0 >> 1);
+	  x1 >>= 1;
+	}
+      while ((y0 & 1) == 0)
+	{
+	  y0 = (y1 << (GMP_NUMB_BITS - 1)) | (y0 >> 1);
+	  y1 >>= 1;
+	}
+
+
+      if (x1 < y1 || (x1 == y1 && x0 < y0))
+	{
+	  mp_limb_t t;
+	  t = x1; x1 = y1; y1 = t;
+	  t = x0; x0 = y0; y0 = t;
+	}
+
+      cy = (x0 < y0);
+      x0 -= y0;
+      x1 -= y1 + cy;
+    }
+  while ((x1 | x0) != 0);
+
+  g.d1 = y1;
+  g.d0 = y0;
+  return g;
+}
+
+mp_limb_t
+refmpn_gcd_1 (mp_srcptr xp, mp_size_t xsize, mp_limb_t y)
+{
+  mp_limb_t  x;
+  int  twos;
+
+  ASSERT (y != 0);
+  ASSERT (! refmpn_zero_p (xp, xsize));
+  ASSERT_MPN (xp, xsize);
+  ASSERT_LIMB (y);
+
+  x = refmpn_mod_1 (xp, xsize, y);
+  if (x == 0)
+    return y;
+
+  twos = 0;
+  while ((x & 1) == 0 && (y & 1) == 0)
+    {
+      x >>= 1;
+      y >>= 1;
+      twos++;
+    }
+
+  return refmpn_gcd_11 (x, y) << twos;
+}
+
+
+/* Based on the full limb x, not nails. */
+unsigned
+refmpn_count_leading_zeros (mp_limb_t x)
+{
+  unsigned  n = 0;
+
+  ASSERT (x != 0);
+
+  while ((x & GMP_LIMB_HIGHBIT) == 0)
+    {
+      x <<= 1;
+      n++;
+    }
+  return n;
+}
+
+/* Full limbs allowed, not limited to nails. */
+unsigned
+refmpn_count_trailing_zeros (mp_limb_t x)
+{
+  unsigned  n = 0;
+
+  ASSERT (x != 0);
+  ASSERT_LIMB (x);
+
+  while ((x & 1) == 0)
+    {
+      x >>= 1;
+      n++;
+    }
+  return n;
+}
+
+/* Strip factors of two (low zero bits) from {p,size} by right shifting.
+   The return value is the number of twos stripped.  */
+mp_size_t
+refmpn_strip_twos (mp_ptr p, mp_size_t size)
+{
+  mp_size_t  limbs;
+  unsigned   shift;
+
+  ASSERT (size >= 1);
+  ASSERT (! refmpn_zero_p (p, size));
+  ASSERT_MPN (p, size);
+
+  for (limbs = 0; p[0] == 0; limbs++)
+    {
+      refmpn_copyi (p, p+1, size-1);
+      p[size-1] = 0;
+    }
+
+  shift = refmpn_count_trailing_zeros (p[0]);
+  if (shift)
+    refmpn_rshift (p, p, size, shift);
+
+  return limbs*GMP_NUMB_BITS + shift;
+}
+
+mp_limb_t
+refmpn_gcd (mp_ptr gp, mp_ptr xp, mp_size_t xsize, mp_ptr yp, mp_size_t ysize)
+{
+  int       cmp;
+
+  ASSERT (ysize >= 1);
+  ASSERT (xsize >= ysize);
+  ASSERT ((xp[0] & 1) != 0);
+  ASSERT ((yp[0] & 1) != 0);
+  /* ASSERT (xp[xsize-1] != 0); */  /* don't think x needs to be odd */
+  ASSERT (yp[ysize-1] != 0);
+  ASSERT (refmpn_overlap_fullonly_p (gp, xp, xsize));
+  ASSERT (refmpn_overlap_fullonly_p (gp, yp, ysize));
+  ASSERT (! refmpn_overlap_p (xp, xsize, yp, ysize));
+  if (xsize == ysize)
+    ASSERT (refmpn_msbone (xp[xsize-1]) >= refmpn_msbone (yp[ysize-1]));
+  ASSERT_MPN (xp, xsize);
+  ASSERT_MPN (yp, ysize);
+
+  refmpn_strip_twos (xp, xsize);
+  MPN_NORMALIZE (xp, xsize);
+  MPN_NORMALIZE (yp, ysize);
+
+  for (;;)
+    {
+      cmp = refmpn_cmp_twosizes (xp, xsize, yp, ysize);
+      if (cmp == 0)
+	break;
+      if (cmp < 0)
+	MPN_PTR_SWAP (xp,xsize, yp,ysize);
+
+      ASSERT_NOCARRY (refmpn_sub (xp, xp, xsize, yp, ysize));
+
+      refmpn_strip_twos (xp, xsize);
+      MPN_NORMALIZE (xp, xsize);
+    }
+
+  refmpn_copyi (gp, xp, xsize);
+  return xsize;
+}
+
+unsigned long
+ref_popc_limb (mp_limb_t src)
+{
+  unsigned long  count;
+  int  i;
+
+  count = 0;
+  for (i = 0; i < GMP_LIMB_BITS; i++)
+    {
+      count += (src & 1);
+      src >>= 1;
+    }
+  return count;
+}
+
+unsigned long
+refmpn_popcount (mp_srcptr sp, mp_size_t size)
+{
+  unsigned long  count = 0;
+  mp_size_t  i;
+
+  ASSERT (size >= 0);
+  ASSERT_MPN (sp, size);
+
+  for (i = 0; i < size; i++)
+    count += ref_popc_limb (sp[i]);
+  return count;
+}
+
+unsigned long
+refmpn_hamdist (mp_srcptr s1p, mp_srcptr s2p, mp_size_t size)
+{
+  mp_ptr  d;
+  unsigned long  count;
+
+  ASSERT (size >= 0);
+  ASSERT_MPN (s1p, size);
+  ASSERT_MPN (s2p, size);
+
+  if (size == 0)
+    return 0;
+
+  d = refmpn_malloc_limbs (size);
+  refmpn_xor_n (d, s1p, s2p, size);
+  count = refmpn_popcount (d, size);
+  free (d);
+  return count;
+}
+
+
+/* set r to a%d */
+void
+refmpn_mod2 (mp_limb_t r[2], const mp_limb_t a[2], const mp_limb_t d[2])
+{
+  mp_limb_t  D[2];
+  int        n;
+
+  ASSERT (! refmpn_overlap_p (r, (mp_size_t) 2, d, (mp_size_t) 2));
+  ASSERT_MPN (a, 2);
+  ASSERT_MPN (d, 2);
+
+  D[1] = d[1], D[0] = d[0];
+  r[1] = a[1], r[0] = a[0];
+  n = 0;
+
+  for (;;)
+    {
+      if (D[1] & GMP_NUMB_HIGHBIT)
+	break;
+      if (refmpn_cmp (r, D, (mp_size_t) 2) <= 0)
+	break;
+      refmpn_lshift (D, D, (mp_size_t) 2, 1);
+      n++;
+      ASSERT (n <= GMP_NUMB_BITS);
+    }
+
+  while (n >= 0)
+    {
+      if (refmpn_cmp (r, D, (mp_size_t) 2) >= 0)
+	ASSERT_NOCARRY (refmpn_sub_n (r, r, D, (mp_size_t) 2));
+      refmpn_rshift (D, D, (mp_size_t) 2, 1);
+      n--;
+    }
+
+  ASSERT (refmpn_cmp (r, d, (mp_size_t) 2) < 0);
+}
+
+
+
+/* Similar to the old mpn/generic/sb_divrem_mn.c, but somewhat simplified, in
+   particular the trial quotient is allowed to be 2 too big. */
+mp_limb_t
+refmpn_sb_div_qr (mp_ptr qp,
+		  mp_ptr np, mp_size_t nsize,
+		  mp_srcptr dp, mp_size_t dsize)
+{
+  mp_limb_t  retval = 0;
+  mp_size_t  i;
+  mp_limb_t  d1 = dp[dsize-1];
+  mp_ptr     np_orig = refmpn_memdup_limbs (np, nsize);
+
+  ASSERT (nsize >= dsize);
+  /* ASSERT (dsize > 2); */
+  ASSERT (dsize >= 2);
+  ASSERT (dp[dsize-1] & GMP_NUMB_HIGHBIT);
+  ASSERT (! refmpn_overlap_p (qp, nsize-dsize, np, nsize) || qp+dsize >= np);
+  ASSERT_MPN (np, nsize);
+  ASSERT_MPN (dp, dsize);
+
+  i = nsize-dsize;
+  if (refmpn_cmp (np+i, dp, dsize) >= 0)
+    {
+      ASSERT_NOCARRY (refmpn_sub_n (np+i, np+i, dp, dsize));
+      retval = 1;
+    }
+
+  for (i--; i >= 0; i--)
+    {
+      mp_limb_t  n0 = np[i+dsize];
+      mp_limb_t  n1 = np[i+dsize-1];
+      mp_limb_t  q, dummy_r;
+
+      ASSERT (n0 <= d1);
+      if (n0 == d1)
+	q = GMP_NUMB_MAX;
+      else
+	q = refmpn_udiv_qrnnd (&dummy_r, n0, n1 << GMP_NAIL_BITS,
+			       d1 << GMP_NAIL_BITS);
+
+      n0 -= refmpn_submul_1 (np+i, dp, dsize, q);
+      ASSERT (n0 == 0 || n0 == MP_LIMB_T_MAX);
+      if (n0)
+	{
+	  q--;
+	  if (! refmpn_add_n (np+i, np+i, dp, dsize))
+	    {
+	      q--;
+	      ASSERT_CARRY (refmpn_add_n (np+i, np+i, dp, dsize));
+	    }
+	}
+      np[i+dsize] = 0;
+
+      qp[i] = q;
+    }
+
+  /* remainder < divisor */
+#if 0		/* ASSERT triggers gcc 4.2.1 bug */
+  ASSERT (refmpn_cmp (np, dp, dsize) < 0);
+#endif
+
+  /* multiply back to original */
+  {
+    mp_ptr  mp = refmpn_malloc_limbs (nsize);
+
+    refmpn_mul_any (mp, qp, nsize-dsize, dp, dsize);
+    if (retval)
+      ASSERT_NOCARRY (refmpn_add_n (mp+nsize-dsize,mp+nsize-dsize, dp, dsize));
+    ASSERT_NOCARRY (refmpn_add (mp, mp, nsize, np, dsize));
+    ASSERT (refmpn_cmp (mp, np_orig, nsize) == 0);
+
+    free (mp);
+  }
+
+  free (np_orig);
+  return retval;
+}
+
+/* Similar to the old mpn/generic/sb_divrem_mn.c, but somewhat simplified, in
+   particular the trial quotient is allowed to be 2 too big. */
+void
+refmpn_tdiv_qr (mp_ptr qp, mp_ptr rp, mp_size_t qxn,
+		mp_ptr np, mp_size_t nsize,
+		mp_srcptr dp, mp_size_t dsize)
+{
+  ASSERT (qxn == 0);
+  ASSERT_MPN (np, nsize);
+  ASSERT_MPN (dp, dsize);
+  ASSERT (dsize > 0);
+  ASSERT (dp[dsize-1] != 0);
+
+  if (dsize == 1)
+    {
+      rp[0] = refmpn_divmod_1 (qp, np, nsize, dp[0]);
+      return;
+    }
+  else
+    {
+      mp_ptr  n2p = refmpn_malloc_limbs (nsize+1);
+      mp_ptr  d2p = refmpn_malloc_limbs (dsize);
+      int     norm = refmpn_count_leading_zeros (dp[dsize-1]) - GMP_NAIL_BITS;
+
+      n2p[nsize] = refmpn_lshift_or_copy (n2p, np, nsize, norm);
+      ASSERT_NOCARRY (refmpn_lshift_or_copy (d2p, dp, dsize, norm));
+
+      refmpn_sb_div_qr (qp, n2p, nsize+1, d2p, dsize);
+      refmpn_rshift_or_copy (rp, n2p, dsize, norm);
+
+      /* ASSERT (refmpn_zero_p (tp+dsize, nsize-dsize)); */
+      free (n2p);
+      free (d2p);
+    }
+}
+
+mp_limb_t
+refmpn_redc_1 (mp_ptr rp, mp_ptr up, mp_srcptr mp, mp_size_t n, mp_limb_t invm)
+{
+  mp_size_t j;
+  mp_limb_t cy;
+
+  ASSERT_MPN (up, 2*n);
+  /* ASSERT about directed overlap rp, up */
+  /* ASSERT about overlap rp, mp */
+  /* ASSERT about overlap up, mp */
+
+  for (j = n - 1; j >= 0; j--)
+    {
+      up[0] = refmpn_addmul_1 (up, mp, n, (up[0] * invm) & GMP_NUMB_MASK);
+      up++;
+    }
+  cy = mpn_add_n (rp, up, up - n, n);
+  return cy;
+}
+
+size_t
+refmpn_get_str (unsigned char *dst, int base, mp_ptr src, mp_size_t size)
+{
+  unsigned char  *d;
+  size_t  dsize;
+
+  ASSERT (size >= 0);
+  ASSERT (base >= 2);
+  ASSERT (base < numberof (mp_bases));
+  ASSERT (size == 0 || src[size-1] != 0);
+  ASSERT_MPN (src, size);
+
+  MPN_SIZEINBASE (dsize, src, size, base);
+  ASSERT (dsize >= 1);
+  ASSERT (! byte_overlap_p (dst, (mp_size_t) dsize, src, size * GMP_LIMB_BYTES));
+
+  if (size == 0)
+    {
+      dst[0] = 0;
+      return 1;
+    }
+
+  /* don't clobber input for power of 2 bases */
+  if (POW2_P (base))
+    src = refmpn_memdup_limbs (src, size);
+
+  d = dst + dsize;
+  do
+    {
+      d--;
+      ASSERT (d >= dst);
+      *d = refmpn_divrem_1 (src, (mp_size_t) 0, src, size, (mp_limb_t) base);
+      size -= (src[size-1] == 0);
+    }
+  while (size != 0);
+
+  /* Move result back and decrement dsize if we didn't generate
+     the maximum possible digits.  */
+  if (d != dst)
+    {
+      size_t i;
+      dsize -= d - dst;
+      for (i = 0; i < dsize; i++)
+	dst[i] = d[i];
+    }
+
+  if (POW2_P (base))
+    free (src);
+
+  return dsize;
+}
+
+
+mp_limb_t
+ref_bswap_limb (mp_limb_t src)
+{
+  mp_limb_t  dst;
+  int        i;
+
+  dst = 0;
+  for (i = 0; i < GMP_LIMB_BYTES; i++)
+    {
+      dst = (dst << 8) + (src & 0xFF);
+      src >>= 8;
+    }
+  return dst;
+}
+
+
+/* These random functions are mostly for transitional purposes while adding
+   nail support, since they're independent of the normal mpn routines.  They
+   can probably be removed when those normal routines are reliable, though
+   perhaps something independent would still be useful at times.  */
+
+#if GMP_LIMB_BITS == 32
+#define RAND_A  CNST_LIMB(0x29CF535)
+#endif
+#if GMP_LIMB_BITS == 64
+#define RAND_A  CNST_LIMB(0xBAECD515DAF0B49D)
+#endif
+
+mp_limb_t  refmpn_random_seed;
+
+mp_limb_t
+refmpn_random_half (void)
+{
+  refmpn_random_seed = refmpn_random_seed * RAND_A + 1;
+  return (refmpn_random_seed >> GMP_LIMB_BITS/2);
+}
+
+mp_limb_t
+refmpn_random_limb (void)
+{
+  return ((refmpn_random_half () << (GMP_LIMB_BITS/2))
+	   | refmpn_random_half ()) & GMP_NUMB_MASK;
+}
+
+void
+refmpn_random (mp_ptr ptr, mp_size_t size)
+{
+  mp_size_t  i;
+  if (GMP_NAIL_BITS == 0)
+    {
+      mpn_random (ptr, size);
+      return;
+    }
+
+  for (i = 0; i < size; i++)
+    ptr[i] = refmpn_random_limb ();
+}
+
+void
+refmpn_random2 (mp_ptr ptr, mp_size_t size)
+{
+  mp_size_t  i;
+  mp_limb_t  bit, mask, limb;
+  int        run;
+
+  if (GMP_NAIL_BITS == 0)
+    {
+      mpn_random2 (ptr, size);
+      return;
+    }
+
+#define RUN_MODULUS  32
+
+  /* start with ones at a random pos in the high limb */
+  bit = CNST_LIMB(1) << (refmpn_random_half () % GMP_NUMB_BITS);
+  mask = 0;
+  run = 0;
+
+  for (i = size-1; i >= 0; i--)
+    {
+      limb = 0;
+      do
+	{
+	  if (run == 0)
+	    {
+	      run = (refmpn_random_half () % RUN_MODULUS) + 1;
+	      mask = ~mask;
+	    }
+
+	  limb |= (bit & mask);
+	  bit >>= 1;
+	  run--;
+	}
+      while (bit != 0);
+
+      ptr[i] = limb;
+      bit = GMP_NUMB_HIGHBIT;
+    }
+}
+
+/* This is a simple bitwise algorithm working high to low across "s" and
+   testing each time whether setting the bit would make s^2 exceed n.  */
+mp_size_t
+refmpn_sqrtrem (mp_ptr sp, mp_ptr rp, mp_srcptr np, mp_size_t nsize)
+{
+  mp_ptr     tp, dp;
+  mp_size_t  ssize, talloc, tsize, dsize, ret, ilimbs;
+  unsigned   ibit;
+  long       i;
+  mp_limb_t  c;
+
+  ASSERT (nsize >= 0);
+
+  /* If n==0, then s=0 and r=0.  */
+  if (nsize == 0)
+    return 0;
+
+  ASSERT (np[nsize - 1] != 0);
+  ASSERT (rp == NULL || MPN_SAME_OR_SEPARATE_P (np, rp, nsize));
+  ASSERT (rp == NULL || ! MPN_OVERLAP_P (sp, (nsize + 1) / 2, rp, nsize));
+  ASSERT (! MPN_OVERLAP_P (sp, (nsize + 1) / 2, np, nsize));
+
+  /* root */
+  ssize = (nsize+1)/2;
+  refmpn_zero (sp, ssize);
+
+  /* the remainder so far */
+  dp = refmpn_memdup_limbs (np, nsize);
+  dsize = nsize;
+
+  /* temporary */
+  talloc = 2*ssize + 1;
+  tp = refmpn_malloc_limbs (talloc);
+
+  for (i = GMP_NUMB_BITS * ssize - 1; i >= 0; i--)
+    {
+      /* t = 2*s*2^i + 2^(2*i), being the amount s^2 will increase by if 2^i
+	 is added to it */
+
+      ilimbs = (i+1) / GMP_NUMB_BITS;
+      ibit = (i+1) % GMP_NUMB_BITS;
+      refmpn_zero (tp, ilimbs);
+      c = refmpn_lshift_or_copy (tp+ilimbs, sp, ssize, ibit);
+      tsize = ilimbs + ssize;
+      tp[tsize] = c;
+      tsize += (c != 0);
+
+      ilimbs = (2*i) / GMP_NUMB_BITS;
+      ibit = (2*i) % GMP_NUMB_BITS;
+      if (ilimbs + 1 > tsize)
+	{
+	  refmpn_zero_extend (tp, tsize, ilimbs + 1);
+	  tsize = ilimbs + 1;
+	}
+      c = refmpn_add_1 (tp+ilimbs, tp+ilimbs, tsize-ilimbs,
+			CNST_LIMB(1) << ibit);
+      ASSERT (tsize < talloc);
+      tp[tsize] = c;
+      tsize += (c != 0);
+
+      if (refmpn_cmp_twosizes (dp, dsize, tp, tsize) >= 0)
+	{
+	  /* set this bit in s and subtract from the remainder */
+	  refmpn_setbit (sp, i);
+
+	  ASSERT_NOCARRY (refmpn_sub_n (dp, dp, tp, dsize));
+	  dsize = refmpn_normalize (dp, dsize);
+	}
+    }
+
+  if (rp == NULL)
+    {
+      ret = ! refmpn_zero_p (dp, dsize);
+    }
+  else
+    {
+      ASSERT (dsize == 0 || dp[dsize-1] != 0);
+      refmpn_copy (rp, dp, dsize);
+      ret = dsize;
+    }
+
+  free (dp);
+  free (tp);
+  return ret;
+}
diff --git a/third_party/gmp/tests/refmpq.c b/third_party/gmp/tests/refmpq.c
new file mode 100644
index 0000000..8a2fc7a
--- /dev/null
+++ b/third_party/gmp/tests/refmpq.c
@@ -0,0 +1,40 @@
+/* Reference rational routines.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+void
+refmpq_add (mpq_ptr w, mpq_srcptr x, mpq_srcptr y)
+{
+  mpz_mul    (mpq_numref(w), mpq_numref(x), mpq_denref(y));
+  mpz_addmul (mpq_numref(w), mpq_denref(x), mpq_numref(y));
+  mpz_mul    (mpq_denref(w), mpq_denref(x), mpq_denref(y));
+  mpq_canonicalize (w);
+}
+
+void
+refmpq_sub (mpq_ptr w, mpq_srcptr x, mpq_srcptr y)
+{
+  mpz_mul    (mpq_numref(w), mpq_numref(x), mpq_denref(y));
+  mpz_submul (mpq_numref(w), mpq_denref(x), mpq_numref(y));
+  mpz_mul    (mpq_denref(w), mpq_denref(x), mpq_denref(y));
+  mpq_canonicalize (w);
+}
diff --git a/third_party/gmp/tests/refmpz.c b/third_party/gmp/tests/refmpz.c
new file mode 100644
index 0000000..167799f
--- /dev/null
+++ b/third_party/gmp/tests/refmpz.c
@@ -0,0 +1,343 @@
+/* Reference mpz functions.
+
+Copyright 1997, 1999-2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+/* always do assertion checking */
+#define WANT_ASSERT  1
+
+#include <stdio.h>
+#include <stdlib.h> /* for free */
+#include "gmp-impl.h"
+#include "longlong.h"
+#include "tests.h"
+
+
+/* Change this to "#define TRACE(x) x" for some traces. */
+#define TRACE(x)
+
+
+/* FIXME: Shouldn't use plain mpz functions in a reference routine. */
+void
+refmpz_combit (mpz_ptr r, unsigned long bit)
+{
+  if (mpz_tstbit (r, bit))
+    mpz_clrbit (r, bit);
+  else
+    mpz_setbit (r, bit);
+}
+
+
+unsigned long
+refmpz_hamdist (mpz_srcptr x, mpz_srcptr y)
+{
+  mp_size_t      xsize, ysize, tsize;
+  mp_ptr         xp, yp;
+  unsigned long  ret;
+
+  if ((SIZ(x) < 0 && SIZ(y) >= 0)
+      || (SIZ(y) < 0 && SIZ(x) >= 0))
+    return ULONG_MAX;
+
+  xsize = ABSIZ(x);
+  ysize = ABSIZ(y);
+  tsize = MAX (xsize, ysize);
+
+  xp = refmpn_malloc_limbs (tsize);
+  refmpn_zero (xp, tsize);
+  refmpn_copy (xp, PTR(x), xsize);
+
+  yp = refmpn_malloc_limbs (tsize);
+  refmpn_zero (yp, tsize);
+  refmpn_copy (yp, PTR(y), ysize);
+
+  if (SIZ(x) < 0)
+    refmpn_neg (xp, xp, tsize);
+
+  if (SIZ(x) < 0)
+    refmpn_neg (yp, yp, tsize);
+
+  ret = refmpn_hamdist (xp, yp, tsize);
+
+  free (xp);
+  free (yp);
+  return ret;
+}
+
+void
+refmpz_gcd (mpz_ptr g, mpz_srcptr a_orig, mpz_srcptr b_orig)
+{
+  mp_bitcnt_t a_twos, b_twos, common_twos;
+  mpz_t a;
+  mpz_t b;
+  mpz_init (a);
+  mpz_init (b);
+  mpz_abs (a, a_orig);
+  mpz_abs (b, b_orig);
+
+  if (mpz_sgn (a) == 0)
+    {
+      mpz_set (g, b);
+      return;
+    }
+  if (mpz_sgn (b) == 0)
+    {
+      mpz_set (g, a);
+      return;
+    }
+  a_twos = mpz_scan1 (a, 0);
+  mpz_tdiv_q_2exp (a, a, a_twos);
+
+  b_twos = mpz_scan1 (b, 0);
+  mpz_tdiv_q_2exp (b, b, b_twos);
+
+  common_twos = MIN(a_twos, b_twos);
+  for (;;)
+    {
+      int c;
+      mp_bitcnt_t twos;
+      c = mpz_cmp (a, b);
+      if (c == 0)
+	break;
+      if (c < 0)
+	mpz_swap (a, b);
+      mpz_sub (a, a, b);
+      twos = mpz_scan1 (a, 0);
+      mpz_tdiv_q_2exp (a, a, twos);
+    }
+  mpz_mul_2exp (g, a, common_twos);
+
+  mpz_clear (a);
+  mpz_clear (b);
+}
+
+/* (0/b), with mpz b; is 1 if b=+/-1, 0 otherwise */
+#define JACOBI_0Z(b)  JACOBI_0LS (PTR(b)[0], SIZ(b))
+
+/* (a/b) effect due to sign of b: mpz/mpz */
+#define JACOBI_BSGN_ZZ_BIT1(a, b)   JACOBI_BSGN_SS_BIT1 (SIZ(a), SIZ(b))
+
+/* (a/b) effect due to sign of a: mpz/unsigned-mpz, b odd;
+   is (-1/b) if a<0, or +1 if a>=0 */
+#define JACOBI_ASGN_ZZU_BIT1(a, b)  JACOBI_ASGN_SU_BIT1 (SIZ(a), PTR(b)[0])
+
+int
+refmpz_kronecker (mpz_srcptr a_orig, mpz_srcptr b_orig)
+{
+  unsigned long  twos;
+  mpz_t  a, b;
+  int    result_bit1 = 0;
+
+  if (mpz_sgn (b_orig) == 0)
+    return JACOBI_Z0 (a_orig);  /* (a/0) */
+
+  if (mpz_sgn (a_orig) == 0)
+    return JACOBI_0Z (b_orig);  /* (0/b) */
+
+  if (mpz_even_p (a_orig) && mpz_even_p (b_orig))
+    return 0;
+
+  if (mpz_cmp_ui (b_orig, 1) == 0)
+    return 1;
+
+  mpz_init_set (a, a_orig);
+  mpz_init_set (b, b_orig);
+
+  if (mpz_sgn (b) < 0)
+    {
+      result_bit1 ^= JACOBI_BSGN_ZZ_BIT1 (a, b);
+      mpz_neg (b, b);
+    }
+  if (mpz_even_p (b))
+    {
+      twos = mpz_scan1 (b, 0L);
+      mpz_tdiv_q_2exp (b, b, twos);
+      result_bit1 ^= JACOBI_TWOS_U_BIT1 (twos, PTR(a)[0]);
+    }
+
+  if (mpz_sgn (a) < 0)
+    {
+      result_bit1 ^= JACOBI_N1B_BIT1 (PTR(b)[0]);
+      mpz_neg (a, a);
+    }
+  if (mpz_even_p (a))
+    {
+      twos = mpz_scan1 (a, 0L);
+      mpz_tdiv_q_2exp (a, a, twos);
+      result_bit1 ^= JACOBI_TWOS_U_BIT1 (twos, PTR(b)[0]);
+    }
+
+  for (;;)
+    {
+      ASSERT (mpz_odd_p (a));
+      ASSERT (mpz_odd_p (b));
+      ASSERT (mpz_sgn (a) > 0);
+      ASSERT (mpz_sgn (b) > 0);
+
+      TRACE (printf ("top\n");
+	     mpz_trace (" a", a);
+	     mpz_trace (" b", b));
+
+      if (mpz_cmp (a, b) < 0)
+	{
+	  TRACE (printf ("swap\n"));
+	  mpz_swap (a, b);
+	  result_bit1 ^= JACOBI_RECIP_UU_BIT1 (PTR(a)[0], PTR(b)[0]);
+	}
+
+      if (mpz_cmp_ui (b, 1) == 0)
+	break;
+
+      mpz_sub (a, a, b);
+      TRACE (printf ("sub\n");
+	     mpz_trace (" a", a));
+      if (mpz_sgn (a) == 0)
+	goto zero;
+
+      twos = mpz_scan1 (a, 0L);
+      mpz_fdiv_q_2exp (a, a, twos);
+      TRACE (printf ("twos %lu\n", twos);
+	     mpz_trace (" a", a));
+      result_bit1 ^= JACOBI_TWOS_U_BIT1 (twos, PTR(b)[0]);
+    }
+
+  mpz_clear (a);
+  mpz_clear (b);
+  return JACOBI_BIT1_TO_PN (result_bit1);
+
+ zero:
+  mpz_clear (a);
+  mpz_clear (b);
+  return 0;
+}
+
+/* Same as mpz_kronecker, but ignoring factors of 2 on b */
+int
+refmpz_jacobi (mpz_srcptr a, mpz_srcptr b)
+{
+  ASSERT_ALWAYS (mpz_sgn (b) > 0);
+  ASSERT_ALWAYS (mpz_odd_p (b));
+
+  return refmpz_kronecker (a, b);
+}
+
+/* Legendre symbol via powm. p must be an odd prime. */
+int
+refmpz_legendre (mpz_srcptr a, mpz_srcptr p)
+{
+  int res;
+
+  mpz_t r;
+  mpz_t e;
+
+  ASSERT_ALWAYS (mpz_sgn (p) > 0);
+  ASSERT_ALWAYS (mpz_odd_p (p));
+
+  mpz_init (r);
+  mpz_init (e);
+
+  mpz_fdiv_r (r, a, p);
+
+  mpz_set (e, p);
+  mpz_sub_ui (e, e, 1);
+  mpz_fdiv_q_2exp (e, e, 1);
+  mpz_powm (r, r, e, p);
+
+  /* Normalize to a more or less symmetric range around zero */
+  if (mpz_cmp (r, e) > 0)
+    mpz_sub (r, r, p);
+
+  ASSERT_ALWAYS (mpz_cmpabs_ui (r, 1) <= 0);
+
+  res = mpz_sgn (r);
+
+  mpz_clear (r);
+  mpz_clear (e);
+
+  return res;
+}
+
+
+int
+refmpz_kronecker_ui (mpz_srcptr a, unsigned long b)
+{
+  mpz_t  bz;
+  int    ret;
+  mpz_init_set_ui (bz, b);
+  ret = refmpz_kronecker (a, bz);
+  mpz_clear (bz);
+  return ret;
+}
+
+int
+refmpz_kronecker_si (mpz_srcptr a, long b)
+{
+  mpz_t  bz;
+  int    ret;
+  mpz_init_set_si (bz, b);
+  ret = refmpz_kronecker (a, bz);
+  mpz_clear (bz);
+  return ret;
+}
+
+int
+refmpz_ui_kronecker (unsigned long a, mpz_srcptr b)
+{
+  mpz_t  az;
+  int    ret;
+  mpz_init_set_ui (az, a);
+  ret = refmpz_kronecker (az, b);
+  mpz_clear (az);
+  return ret;
+}
+
+int
+refmpz_si_kronecker (long a, mpz_srcptr b)
+{
+  mpz_t  az;
+  int    ret;
+  mpz_init_set_si (az, a);
+  ret = refmpz_kronecker (az, b);
+  mpz_clear (az);
+  return ret;
+}
+
+
+void
+refmpz_pow_ui (mpz_ptr w, mpz_srcptr b, unsigned long e)
+{
+  mpz_t          s, t;
+  unsigned long  i;
+
+  mpz_init_set_ui (t, 1L);
+  mpz_init_set (s, b);
+
+  if ((e & 1) != 0)
+    mpz_mul (t, t, s);
+
+  for (i = 2; i <= e; i <<= 1)
+    {
+      mpz_mul (s, s, s);
+      if ((i & e) != 0)
+	mpz_mul (t, t, s);
+    }
+
+  mpz_set (w, t);
+
+  mpz_clear (s);
+  mpz_clear (t);
+}
diff --git a/third_party/gmp/tests/spinner.c b/third_party/gmp/tests/spinner.c
new file mode 100644
index 0000000..04e5b99
--- /dev/null
+++ b/third_party/gmp/tests/spinner.c
@@ -0,0 +1,128 @@
+/* A stupid little spinning wheel designed to make it look like useful work
+   is being done.
+
+Copyright 1999-2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include "config.h"
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>     /* for isatty */
+#endif
+
+#include "gmp-impl.h"
+
+#include "tests.h"
+
+
+/* "alarm" is not available on mingw32, and the SIGALRM constant is not
+   defined.  Don't bother with a spinner in this case.  */
+#if ! HAVE_ALARM || ! defined (SIGALRM)
+#define alarm(n)          abort()
+#define signal(sig,func)  SIG_ERR
+#endif
+
+
+/* An application can update this to get a count printed with the spinner.
+   If left at 0, no count is printed. */
+
+unsigned long  spinner_count = 0;
+
+
+int  spinner_wanted = -1;  /* -1 uninitialized, 1 wanted, 0 not */
+int  spinner_tick = 1;     /* 1 ready to print, 0 not */
+
+
+/*ARGSUSED*/
+RETSIGTYPE
+spinner_signal (int signum)
+{
+  spinner_tick = 1;
+
+  if (signal (SIGALRM, spinner_signal) == SIG_ERR)
+    {
+      printf ("spinner_signal(): Oops, cannot reinstall SIGALRM\n");
+      abort ();
+    }
+  alarm (1);
+}
+
+
+/* Initialize the spinner.
+
+   This is done the first time spinner() is called, so an application
+   doesn't need to call this directly.
+
+   The spinner is only wanted if the output is a tty.  */
+
+#define SPINNER_WANTED_INIT() \
+  if (spinner_wanted < 0) spinner_init ()
+
+void
+spinner_init (void)
+{
+  spinner_wanted = isatty (fileno (stdout));
+  if (spinner_wanted == -1)
+    abort ();
+
+  if (!spinner_wanted)
+    return;
+
+  if (signal (SIGALRM, spinner_signal) == SIG_ERR)
+    {
+      printf ("(no spinner)\r");
+      spinner_tick = 0;
+      return;
+    }
+  alarm (1);
+
+  /* unbuffered output so the spinner will show up */
+  setbuf (stdout, NULL);
+}
+
+
+void
+spinner (void)
+{
+  static const char  data[] = { '|', '/', '-', '\\' };
+  static int         pos = 0;
+
+  char  buf[128];
+
+  SPINNER_WANTED_INIT ();
+
+  if (spinner_tick)
+    {
+      buf[0] = data[pos];
+      pos = (pos + 1) % numberof (data);
+      spinner_tick = 0;
+
+      if (spinner_count != 0)
+	{
+	  sprintf (buf+1, " %lu\r", spinner_count);
+	}
+      else
+	{
+	  buf[1] = '\r';
+	  buf[2] = '\0';
+	}
+      fputs (buf, stdout);
+    }
+}
diff --git a/third_party/gmp/tests/t-bswap.c b/third_party/gmp/tests/t-bswap.c
new file mode 100644
index 0000000..765ef8e
--- /dev/null
+++ b/third_party/gmp/tests/t-bswap.c
@@ -0,0 +1,70 @@
+/* Test BSWAP_LIMB.
+
+Copyright 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+int
+main (void)
+{
+  mp_limb_t  src, want, got;
+  int        i;
+
+  tests_start ();
+  mp_trace_base = -16;
+
+  for (i = 0; i < 1000; i++)
+    {
+      mpn_random (&src, (mp_size_t) 1);
+
+      want = ref_bswap_limb (src);
+
+      BSWAP_LIMB (got, src);
+      if (got != want)
+        {
+          printf ("BSWAP_LIMB wrong result\n");
+        error:
+          mpn_trace ("  src ", &src,  (mp_size_t) 1);
+          mpn_trace ("  want", &want, (mp_size_t) 1);
+          mpn_trace ("  got ", &got,  (mp_size_t) 1);
+          abort ();
+        }
+
+      BSWAP_LIMB_FETCH (got, &src);
+      if (got != want)
+        {
+          printf ("BSWAP_LIMB_FETCH wrong result\n");
+          goto error;
+        }
+
+      BSWAP_LIMB_STORE (&got, src);
+      if (got != want)
+        {
+          printf ("BSWAP_LIMB_STORE wrong result\n");
+          goto error;
+        }
+    }
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/t-constants.c b/third_party/gmp/tests/t-constants.c
new file mode 100644
index 0000000..35714c7
--- /dev/null
+++ b/third_party/gmp/tests/t-constants.c
@@ -0,0 +1,343 @@
+/* Check the values of some constants.
+
+Copyright 2000-2003, 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+#ifdef ULONG_MAX
+const char *ulong_max_def = "defined";
+#else
+const char *ulong_max_def = "not defined";
+#endif
+#ifdef LONG_MAX
+const char *long_max_def = "defined";
+#else
+const char *long_max_def = "not defined";
+#endif
+
+#ifdef UINT_MAX
+const char *uint_max_def = "defined";
+#else
+const char *uint_max_def = "not defined";
+#endif
+#ifdef INT_MAX
+const char *int_max_def = "defined";
+#else
+const char *int_max_def = "not defined";
+#endif
+
+#ifdef USHRT_MAX
+const char *ushrt_max_def = "defined";
+#else
+const char *ushrt_max_def = "not defined";
+#endif
+#ifdef SHRT_MAX
+const char *shrt_max_def = "defined";
+#else
+const char *shrt_max_def = "not defined";
+#endif
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+
+#ifdef _LONG_LONG_LIMB
+#define LL(l,ll)  ll
+#else
+#define LL(l,ll)  l
+#endif
+
+#if __GMP_MP_SIZE_T_INT
+#define SS(i,l)   i
+#else
+#define SS(i,l)   l
+#endif
+
+
+#define CHECK_LIMB_S(x, xname, y, yname)                \
+  do {                                                  \
+    if ((x) != (y))                                     \
+      {                                                 \
+        printf (LL("%s == %lx, but %s == %lx\n",        \
+                   "%s == %llx, but %s == %llx\n"),     \
+                xname, x, yname, y);                    \
+        error = 1;                                      \
+      }                                                 \
+  } while (0)
+
+#define CHECK_INT_S(x, xname, y, yname)                                 \
+  do {                                                                  \
+    if ((x) != (y))                                                     \
+      {                                                                 \
+        printf ("%s == %d, but %s == %d\n", xname, x, yname, y);        \
+        error = 1;                                                      \
+      }                                                                 \
+  } while (0)
+
+
+
+#define CHECK_CONDITION_S(x, xname)             \
+  do {                                          \
+    if (!(x))                                   \
+      {                                         \
+        printf ("%s is false\n", xname);        \
+        error = 1;                              \
+      }                                         \
+  } while (0)
+
+
+/* How many bits seem to work in the given type. */
+#define CALC_BITS(result, type) \
+  do {                          \
+    type  n = 1;                \
+    result = 0;                 \
+    while (n != 0)              \
+      {                         \
+        n <<= 1;                \
+        result++;               \
+      }                         \
+  } while (0)
+
+#define CHECK_BITS_S(constant, constant_name, type)     \
+  do {                                                  \
+    int   calculated;                                   \
+    CALC_BITS (calculated, type);                       \
+    if (calculated != constant)                         \
+      {                                                 \
+        printf ("%s == %d, but calculated %d\n",        \
+                constant_name, constant, calculated);   \
+        error = 1;                                      \
+      }                                                 \
+  } while (0)
+
+
+#define CHECK_HIGHBIT_S(value, value_name, type, format)        \
+  do {                                                          \
+    type  n = value;                                            \
+    if (n == 0)                                                 \
+      {                                                         \
+        printf ("%s == 0\n", value_name);                       \
+        error = 1;                                              \
+      }                                                         \
+    n <<= 1;                                                    \
+    if (n != 0)                                                 \
+      {                                                         \
+        printf ("%s << 1 = ", value_name);                      \
+        printf (format, n);                                     \
+        printf (" != 0\n");                                     \
+        error = 1;                                              \
+      }                                                         \
+  } while (0)
+
+
+#define CHECK_MAX_S(max_val, max_name, min_val, min_name, type, format) \
+  do {                                                                  \
+    type  maxval = max_val;                                             \
+    type  minval = min_val;                                             \
+    type  n = maxval;                                                   \
+    n++;                                                                \
+    if (n != minval)                                                    \
+      {                                                                 \
+        printf ("%s + 1 = ", max_name);                                 \
+        printf (format, n);                                             \
+        printf (" != %s = ", min_name);                                 \
+        printf (format, minval);                                        \
+        printf ("\n");                                                  \
+        error = 1;                                                      \
+      }                                                                 \
+    if (maxval <= minval)                                               \
+      {                                                                 \
+        printf ("%s = ", max_name);                                     \
+        printf (format, maxval);                                        \
+        printf (" <= %s = ", min_name);                                 \
+        printf (format, minval);                                        \
+        printf ("\n");                                                  \
+        error = 1;                                                      \
+      }                                                                 \
+  } while (0)
+
+
+#define CHECK_LIMB(x,y)      CHECK_LIMB_S (x, #x, y, #y)
+#define CHECK_INT(x,y)       CHECK_INT_S (x, #x, y, #y)
+#define CHECK_CONDITION(x)   CHECK_CONDITION_S (x, #x)
+#define CHECK_BITS(c,t)      CHECK_BITS_S (c, #c, t)
+#define CHECK_MAX(m,n,t,f)   CHECK_MAX_S (m, #m, n, #n, t, f)
+#define CHECK_HIGHBIT(n,t,f) CHECK_HIGHBIT_S (n, #n, t, f)
+
+
+/* The tests below marked "Bad!" fail on Cray T90 systems, where int, short
+   and mp_size_t are 48 bits or some such but don't wraparound in a plain
+   twos complement fashion.  In particular,
+
+       INT_HIGHBIT << 1 = 0xFFFFC00000000000 != 0
+       INT_MAX + 1 = 35184372088832 != INT_MIN = -35184372088832
+
+   This is a bit bizarre, but doesn't matter because GMP doesn't rely on any
+   particular overflow behaviour for int or short, only for mp_limb_t.  */
+
+int
+main (int argc, char *argv[])
+{
+  int  error = 0;
+
+  CHECK_INT (GMP_LIMB_BYTES, (int) sizeof(mp_limb_t));
+  CHECK_INT (mp_bits_per_limb, GMP_LIMB_BITS);
+
+  CHECK_BITS (GMP_LIMB_BITS, mp_limb_t);
+  CHECK_BITS (BITS_PER_ULONG, unsigned long);
+
+  CHECK_HIGHBIT (GMP_LIMB_HIGHBIT, mp_limb_t,      LL("0x%lX","0x%llX"));
+  CHECK_HIGHBIT (ULONG_HIGHBIT,     unsigned long,  "0x%lX");
+  CHECK_HIGHBIT (UINT_HIGHBIT,      unsigned int,   "0x%X");
+  CHECK_HIGHBIT (USHRT_HIGHBIT,     unsigned short, "0x%hX");
+#if 0 /* Bad! */
+  CHECK_HIGHBIT (LONG_HIGHBIT,      long,           "0x%lX");
+  CHECK_HIGHBIT (INT_HIGHBIT,       int,            "0x%X");
+  CHECK_HIGHBIT (SHRT_HIGHBIT,      short,          "0x%hX");
+#endif
+
+#if 0 /* Bad! */
+  CHECK_MAX (LONG_MAX,      LONG_MIN,      long,           "%ld");
+  CHECK_MAX (INT_MAX,       INT_MIN,       int,            "%d");
+  CHECK_MAX (SHRT_MAX,      SHRT_MIN,      short,          "%hd");
+#endif
+  CHECK_MAX (ULONG_MAX,     0,             unsigned long,  "%lu");
+  CHECK_MAX (UINT_MAX,      0,             unsigned int,   "%u");
+  CHECK_MAX (USHRT_MAX,     0,             unsigned short, "%hu");
+#if 0 /* Bad! */
+  CHECK_MAX (MP_SIZE_T_MAX, MP_SIZE_T_MIN, mp_size_t,      SS("%d","%ld"));
+#endif
+
+  /* UHWtype should have at least enough bits for half a UWtype */
+  {
+    int  bits_per_UWtype, bits_per_UHWtype;
+    CALC_BITS (bits_per_UWtype,  UWtype);
+    CALC_BITS (bits_per_UHWtype, UHWtype);
+    CHECK_CONDITION (2*bits_per_UHWtype >= bits_per_UWtype);
+  }
+
+  ASSERT_ALWAYS_LIMB (MODLIMB_INVERSE_3);
+  {
+    mp_limb_t  modlimb_inverse_3_calc;
+    binvert_limb (modlimb_inverse_3_calc, CNST_LIMB(3));
+    ASSERT_ALWAYS_LIMB (modlimb_inverse_3_calc);
+    CHECK_LIMB (MODLIMB_INVERSE_3, modlimb_inverse_3_calc);
+  }
+  {
+    mp_limb_t  MODLIMB_INVERSE_3_times_3
+      = (MODLIMB_INVERSE_3 * CNST_LIMB(3)) & GMP_NUMB_MASK;
+    CHECK_LIMB (MODLIMB_INVERSE_3_times_3, CNST_LIMB(1));
+  }
+
+  {
+    mp_limb_t  hi, lo;
+    hi = refmpn_umul_ppmm (&lo, GMP_NUMB_CEIL_MAX_DIV3-1,
+                           CNST_LIMB(3) << GMP_NAIL_BITS);
+    if (! (hi < 1))
+      {
+        printf ("GMP_NUMB_CEIL_MAX_DIV3 too big\n");
+        error = 1;
+      }
+    hi = refmpn_umul_ppmm (&lo, GMP_NUMB_CEIL_MAX_DIV3,
+                           CNST_LIMB(3) << GMP_NAIL_BITS);
+    if (! (hi >= 1))
+      {
+        printf ("GMP_NUMB_CEIL_MAX_DIV3 too small\n");
+        error = 1;
+      }
+  }
+
+  {
+    mp_limb_t  hi, lo;
+    hi = refmpn_umul_ppmm (&lo, GMP_NUMB_CEIL_2MAX_DIV3-1,
+                           CNST_LIMB(3) << GMP_NAIL_BITS);
+    if (! (hi < 2))
+      {
+        printf ("GMP_NUMB_CEIL_2MAX_DIV3 too big\n");
+        error = 1;
+      }
+    hi = refmpn_umul_ppmm (&lo, GMP_NUMB_CEIL_2MAX_DIV3,
+                           CNST_LIMB(3) << GMP_NAIL_BITS);
+    if (! (hi >= 2))
+      {
+        printf ("GMP_NUMB_CEIL_2MAX_DIV3 too small\n");
+        error = 1;
+      }
+  }
+
+#ifdef PP_INVERTED
+  {
+    mp_limb_t  pp_inverted_calc;
+    invert_limb (pp_inverted_calc, PP);
+    CHECK_LIMB (PP_INVERTED, pp_inverted_calc);
+  }
+#endif
+
+  if (argc >= 2 || error)
+    {
+      int  bits;
+
+      printf ("\n");
+      printf ("After gmp.h,\n");
+      printf ("  ULONG_MAX  %s\n", ulong_max_def);
+      printf ("  LONG_MAX   %s\n", long_max_def);
+      printf ("  UINT_MAX   %s\n", uint_max_def);
+      printf ("  INT_MAX    %s\n", int_max_def);
+      printf ("  USHRT_MAX  %s\n", ushrt_max_def);
+      printf ("  SHRT_MAX   %s\n", shrt_max_def);
+      printf ("\n");
+
+#ifdef _CRAY
+      printf ("_CRAY is defined, so limits.h is being used\n");
+#endif
+
+      printf ("ULONG_MAX      %lX\n", ULONG_MAX);
+      printf ("ULONG_HIGHBIT  %lX\n", ULONG_HIGHBIT);
+      printf ("LONG_MAX       %lX\n", LONG_MAX);
+      printf ("LONG_MIN       %lX\n", LONG_MIN);
+
+      printf ("UINT_MAX       %X\n", UINT_MAX);
+      printf ("UINT_HIGHBIT   %X\n", UINT_HIGHBIT);
+      printf ("INT_MAX        %X\n", INT_MAX);
+      printf ("INT_MIN        %X\n", INT_MIN);
+
+      printf ("USHRT_MAX      %X\n", USHRT_MAX);
+      printf ("USHRT_HIGHBIT  %X\n", USHRT_HIGHBIT);
+      printf ("SHRT_MAX       %X\n", SHRT_MAX);
+      printf ("SHRT_MIN       %X\n", SHRT_MIN);
+
+      printf ("\n");
+      printf ("Bits\n");
+      CALC_BITS (bits, long);           printf ("  long           %d\n", bits);
+      CALC_BITS (bits, int);            printf ("  int            %d\n", bits);
+      CALC_BITS (bits, short);          printf ("  short          %d\n", bits);
+      CALC_BITS (bits, unsigned long);  printf ("  unsigned long  %d\n", bits);
+      CALC_BITS (bits, unsigned int);   printf ("  unsigned int   %d\n", bits);
+      CALC_BITS (bits, unsigned short); printf ("  unsigned short %d\n", bits);
+      CALC_BITS (bits, mp_size_t);      printf ("  mp_size_t      %d\n", bits);
+    }
+
+  if (error)
+    abort ();
+
+  exit (0);
+}
diff --git a/third_party/gmp/tests/t-count_zeros.c b/third_party/gmp/tests/t-count_zeros.c
new file mode 100644
index 0000000..5bb243c
--- /dev/null
+++ b/third_party/gmp/tests/t-count_zeros.c
@@ -0,0 +1,86 @@
+/* Test count_leading_zeros and count_trailing_zeros.
+
+Copyright 2001-2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "longlong.h"
+#include "tests.h"
+
+void
+check_clz (int want, mp_limb_t n)
+{
+  int  got;
+  count_leading_zeros (got, n);
+  if (got != want)
+    {
+      printf        ("count_leading_zeros wrong\n");
+      mp_limb_trace ("  n    ", n);
+      printf        ("  want %d\n", want);
+      printf        ("  got  %d\n", got);
+      abort ();
+    }
+}
+
+void
+check_ctz (int want, mp_limb_t n)
+{
+  int  got;
+  count_trailing_zeros (got, n);
+  if (got != want)
+    {
+      printf ("count_trailing_zeros wrong\n");
+      mpn_trace ("  n    ", &n, (mp_size_t) 1);
+      printf    ("  want %d\n", want);
+      printf    ("  got  %d\n", got);
+      abort ();
+    }
+}
+
+void
+check_various (void)
+{
+  int        i;
+
+#ifdef COUNT_LEADING_ZEROS_0
+  check_clz (COUNT_LEADING_ZEROS_0, CNST_LIMB(0));
+#endif
+
+  for (i=0; i < GMP_LIMB_BITS; i++)
+    {
+      check_clz (i, CNST_LIMB(1) << (GMP_LIMB_BITS-1-i));
+      check_ctz (i, CNST_LIMB(1) << i);
+
+      check_ctz (i, MP_LIMB_T_MAX << i);
+      check_clz (i, MP_LIMB_T_MAX >> i);
+    }
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  tests_start ();
+  mp_trace_base = 16;
+
+  check_various ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/t-hightomask.c b/third_party/gmp/tests/t-hightomask.c
new file mode 100644
index 0000000..3c65d03
--- /dev/null
+++ b/third_party/gmp/tests/t-hightomask.c
@@ -0,0 +1,42 @@
+/* Test LIMB_HIGHBIT_TO_MASK.
+
+Copyright 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+/* There's very little to these tests, but it's nice to have them since if
+   something has gone wrong with the arithmetic right shift business in
+   LIMB_HIGHBIT_TO_MASK then the only symptom is likely to be failures in
+   udiv_qrnnd_preinv, which would not be easy to diagnose.  */
+
+int
+main (void)
+{
+  ASSERT_ALWAYS (LIMB_HIGHBIT_TO_MASK (0) == 0);
+  ASSERT_ALWAYS (LIMB_HIGHBIT_TO_MASK (GMP_LIMB_HIGHBIT) == MP_LIMB_T_MAX);
+  ASSERT_ALWAYS (LIMB_HIGHBIT_TO_MASK (MP_LIMB_T_MAX) == MP_LIMB_T_MAX);
+  ASSERT_ALWAYS (LIMB_HIGHBIT_TO_MASK (GMP_LIMB_HIGHBIT >> 1) == 0);
+  ASSERT_ALWAYS (LIMB_HIGHBIT_TO_MASK (MP_LIMB_T_MAX >> 1) == 0);
+
+  exit (0);
+}
diff --git a/third_party/gmp/tests/t-modlinv.c b/third_party/gmp/tests/t-modlinv.c
new file mode 100644
index 0000000..47f5533
--- /dev/null
+++ b/third_party/gmp/tests/t-modlinv.c
@@ -0,0 +1,83 @@
+/* Test binvert_limb.
+
+Copyright 2000-2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "gmp-impl.h"
+#include "longlong.h"
+#include "tests.h"
+
+
+void
+one (mp_limb_t n)
+{
+  mp_limb_t  inv, prod;
+
+  binvert_limb (inv, n);
+  prod = (inv * n) & GMP_NUMB_MASK;
+  if (prod != 1)
+    {
+      printf ("binvert_limb wrong\n");
+      mp_limb_trace ("  n       ", n);
+      mp_limb_trace ("  got     ", inv);
+      mp_limb_trace ("  product ", prod);
+      abort ();
+    }
+}
+
+void
+some (void)
+{
+  int  i;
+  for (i = 0; i < 10000; i++)
+    one (refmpn_random_limb () | 1);
+}
+
+void
+all (void)
+{
+  mp_limb_t  n;
+
+  n = 1;
+  do {
+    one (n);
+    n += 2;
+  } while (n != 1);
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  tests_start ();
+
+  if (argc >= 2 && strcmp (argv[1], "-a") == 0)
+    {
+      /* it's feasible to run all values on a 32-bit limb, but not a 64-bit */
+      all ();
+    }
+  else
+    {
+      some ();
+    }
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/t-parity.c b/third_party/gmp/tests/t-parity.c
new file mode 100644
index 0000000..b6f2366
--- /dev/null
+++ b/third_party/gmp/tests/t-parity.c
@@ -0,0 +1,66 @@
+/* Test ULONG_PARITY.
+
+Copyright 2002, 2014 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+void
+check_one (int want, unsigned long n)
+{
+  int  got;
+  ULONG_PARITY (got, n);
+  if (got != want)
+    {
+      printf ("ULONG_PARITY wrong\n");
+      printf ("  n    %lX\n", n);
+      printf ("  want %d\n", want);
+      printf ("  got  %d\n", got);
+      abort ();
+    }
+}
+
+void
+check_various (void)
+{
+  int  i;
+
+  check_one (0, 0L);
+  check_one (BITS_PER_ULONG & 1, ULONG_MAX);
+  check_one (0, 0x11L);
+  check_one (1, 0x111L);
+  check_one (1, 0x3111L);
+
+  for (i = 0; i < BITS_PER_ULONG; i++)
+    check_one (1, 1UL << i);
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  tests_start ();
+  mp_trace_base = 16;
+
+  check_various ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/t-popc.c b/third_party/gmp/tests/t-popc.c
new file mode 100644
index 0000000..421d4e2
--- /dev/null
+++ b/third_party/gmp/tests/t-popc.c
@@ -0,0 +1,79 @@
+/* Test popc_limb.
+
+Copyright 2002, 2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+int
+main (void)
+{
+  mp_limb_t  src, want, got;
+  int        i;
+
+  tests_start ();
+  mp_trace_base = -16;
+
+  for (i = 0; i < GMP_LIMB_BITS; i++)
+    {
+      src = CNST_LIMB(1) << i;
+      want = 1;
+
+      popc_limb (got, src);
+      if (got != want)
+        {
+        error:
+          printf ("popc_limb wrong result\n");
+          mpn_trace ("  src ", &src,  (mp_size_t) 1);
+          mpn_trace ("  want", &want, (mp_size_t) 1);
+          mpn_trace ("  got ", &got,  (mp_size_t) 1);
+          abort ();
+        }
+    }
+
+  src = 0;
+  want = 0;
+  for (i = 0; i < GMP_LIMB_BITS; i++)
+    {
+      src += CNST_LIMB(1) << i;
+      want += 1;
+
+      popc_limb (got, src);
+      if (got != want)
+        {
+	  goto error;
+        }
+    }
+
+  for (i = 0; i < 100; i++)
+    {
+      mpn_random2 (&src, (mp_size_t) 1);
+      want = ref_popc_limb (src);
+
+      popc_limb (got, src);
+      if (got != want)
+        goto error;
+    }
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/t-sub.c b/third_party/gmp/tests/t-sub.c
new file mode 100644
index 0000000..e916d4f
--- /dev/null
+++ b/third_party/gmp/tests/t-sub.c
@@ -0,0 +1,114 @@
+/* Test sub_ddmmss.
+
+Copyright 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gmp-impl.h"
+#include "longlong.h"
+#include "tests.h"
+
+
+void
+check_data (void)
+{
+#define M  MP_LIMB_T_MAX
+
+  static const struct {
+    mp_limb_t  want_dh,want_dl, mh,ml, sh,sl;
+  } data[] = {
+    { 0,0,  0,0,  0,0 },
+    { 0,0,  0,1,  0,1 },
+    { 0,0,  1,2,  1,2 },
+
+    { 0,1,  0,2,  0,1 },
+    { 0,M,  1,0,  0,1 },
+    { M,M,  0,0,  0,1 },
+
+    { M,M,  0,M-1,  0,M },
+    { 0,0,  0,M-1,  0,M-1 },
+    { 0,1,  0,M-1,  0,M-2 },
+  };
+  int  i;
+  mp_limb_t  got_dh, got_dl;
+
+  for (i = 0; i < numberof (data); i++)
+    {
+      sub_ddmmss (got_dh,got_dl, data[i].mh,data[i].ml, data[i].sh,data[i].sl);
+      if (got_dh != data[i].want_dh || got_dl != data[i].want_dl)
+        {
+          printf ("check_data wrong at data[%d]\n", i);
+          mp_limb_trace ("  mh", data[i].mh);
+          mp_limb_trace ("  ml", data[i].ml);
+          mp_limb_trace ("  sh", data[i].sh);
+          mp_limb_trace ("  sl", data[i].sl);
+          mp_limb_trace ("  want dh", data[i].want_dh);
+          mp_limb_trace ("  want dl", data[i].want_dl);
+          mp_limb_trace ("  got dh ", got_dh);
+          mp_limb_trace ("  got dl ", got_dl);
+          abort ();
+        }
+    }
+}
+
+void
+check_random (void)
+{
+  mp_limb_t  want_dh,want_dl, got_dh,got_dl, mh,ml, sh,sl;
+  int  i;
+
+  for (i = 0; i < 20; i++)
+    {
+      mh = urandom ();
+      ml = urandom ();
+      sh = urandom ();
+      sl = urandom ();
+
+      refmpn_sub_ddmmss (&want_dh,&want_dl, mh,ml, sh,sl);
+
+      sub_ddmmss (got_dh,got_dl, mh,ml, sh,sl);
+
+      if (got_dh != want_dh || got_dl != want_dl)
+        {
+          printf ("check_data wrong at data[%d]\n", i);
+          mp_limb_trace ("  mh", mh);
+          mp_limb_trace ("  ml", ml);
+          mp_limb_trace ("  sh", sh);
+          mp_limb_trace ("  sl", sl);
+          mp_limb_trace ("  want dh", want_dh);
+          mp_limb_trace ("  want dl", want_dl);
+          mp_limb_trace ("  got dh ", got_dh);
+          mp_limb_trace ("  got dl ", got_dl);
+          abort ();
+        }
+    }
+}
+
+int
+main (void)
+{
+  tests_start ();
+  mp_trace_base = -16;
+
+  check_data ();
+  check_random ();
+
+  tests_end ();
+  exit (0);
+}
diff --git a/third_party/gmp/tests/tests.h b/third_party/gmp/tests/tests.h
new file mode 100644
index 0000000..882c634
--- /dev/null
+++ b/third_party/gmp/tests/tests.h
@@ -0,0 +1,447 @@
+/* Tests support prototypes etc.
+
+Copyright 2000-2004, 2008-2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+#ifndef __TESTS_H__
+#define __TESTS_H__
+
+#include "config.h"
+
+#include <setjmp.h>  /* for jmp_buf */
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+
+#ifdef __cplusplus
+#define ANYARGS  ...
+#else
+#define ANYARGS
+#endif
+
+
+void tests_start (void);
+void tests_end (void);
+
+void tests_memory_start (void);
+void tests_memory_end (void);
+void *tests_allocate (size_t);
+void *tests_reallocate (void *, size_t, size_t);
+void tests_free (void *, size_t);
+void tests_free_nosize (void *);
+int tests_memory_valid (void *);
+
+void tests_rand_start (void);
+void tests_rand_end (void);
+
+double tests_infinity_d ();
+int tests_hardware_getround (void);
+int tests_hardware_setround (int);
+int tests_isinf (double);
+int tests_dbl_mant_bits (void);
+
+void x86_fldcw (unsigned short);
+unsigned short x86_fstcw (void);
+
+
+/* tests_setjmp_sigfpe is like a setjmp, establishing a trap for SIGFPE.
+   The initial return is 0, if SIGFPE is trapped execution goes back there
+   with return value 1.
+
+   tests_sigfpe_done puts SIGFPE back to SIG_DFL, which should be used once
+   the setjmp point is out of scope, so a later SIGFPE won't try to go back
+   there.  */
+
+#define tests_setjmp_sigfpe()                   \
+  (signal (SIGFPE, tests_sigfpe_handler),       \
+   setjmp (tests_sigfpe_target))
+
+RETSIGTYPE tests_sigfpe_handler (int);
+void tests_sigfpe_done (void);
+extern jmp_buf  tests_sigfpe_target;
+
+
+#if HAVE_CALLING_CONVENTIONS
+extern mp_limb_t (*calling_conventions_function) (ANYARGS);
+mp_limb_t calling_conventions (ANYARGS);
+int calling_conventions_check (void);
+#define CALLING_CONVENTIONS(function) \
+  (calling_conventions_function = (function), calling_conventions)
+#define CALLING_CONVENTIONS_CHECK()    (calling_conventions_check())
+#else
+#define CALLING_CONVENTIONS(function)  (function)
+#define CALLING_CONVENTIONS_CHECK()    1 /* always ok */
+#endif
+
+
+extern int mp_trace_base;
+void mp_limb_trace (const char *, mp_limb_t);
+void mpn_trace (const char *, mp_srcptr, mp_size_t);
+void mpn_tracea (const char *, const mp_ptr *, int, mp_size_t);
+void mpn_tracen (const char *, int, mp_srcptr, mp_size_t);
+void mpn_trace_file (const char *, mp_srcptr, mp_size_t);
+void mpn_tracea_file (const char *, const mp_ptr *, int, mp_size_t);
+void mpf_trace (const char *, mpf_srcptr);
+void mpq_trace (const char *, mpq_srcptr);
+void mpz_trace (const char *, mpz_srcptr);
+void mpz_tracen (const char *, int, mpz_srcptr);
+void byte_trace (const char *, const void *, mp_size_t);
+void byte_tracen (const char *, int, const void *, mp_size_t);
+void d_trace (const char *, double);
+
+
+void spinner (void);
+extern unsigned long  spinner_count;
+extern int  spinner_wanted;
+extern int  spinner_tick;
+
+
+void *align_pointer (void *, size_t);
+void *__gmp_allocate_func_aligned (size_t, size_t);
+void *__gmp_allocate_or_reallocate (void *, size_t, size_t);
+char *__gmp_allocate_strdup (const char *);
+char *strtoupper (char *);
+mp_limb_t urandom (void);
+void call_rand_algs (void (*func) (const char *, gmp_randstate_t));
+
+
+void mpf_set_str_or_abort (mpf_ptr, const char *, int);
+
+
+void mpq_set_str_or_abort (mpq_ptr, const char *, int);
+
+
+void mpz_erandomb (mpz_ptr, gmp_randstate_t, unsigned long);
+void mpz_erandomb_nonzero (mpz_ptr, gmp_randstate_t, unsigned long);
+void mpz_errandomb (mpz_ptr, gmp_randstate_t, unsigned long);
+void mpz_errandomb_nonzero (mpz_ptr, gmp_randstate_t, unsigned long);
+void mpz_init_set_n (mpz_ptr, mp_srcptr, mp_size_t);
+void mpz_negrandom (mpz_ptr, gmp_randstate_t);
+int mpz_pow2abs_p (mpz_srcptr) __GMP_ATTRIBUTE_PURE;
+void mpz_set_n (mpz_ptr, mp_srcptr, mp_size_t);
+void mpz_set_str_or_abort (mpz_ptr, const char *, int);
+void mpz_clobber(mpz_ptr);
+
+mp_size_t mpn_diff_highest (mp_srcptr, mp_srcptr, mp_size_t) __GMP_ATTRIBUTE_PURE;
+mp_size_t mpn_diff_lowest (mp_srcptr, mp_srcptr, mp_size_t) __GMP_ATTRIBUTE_PURE;
+mp_size_t byte_diff_highest (const void *, const void *, mp_size_t) __GMP_ATTRIBUTE_PURE;
+mp_size_t byte_diff_lowest (const void *, const void *, mp_size_t) __GMP_ATTRIBUTE_PURE;
+
+
+mp_limb_t ref_addc_limb (mp_limb_t *, mp_limb_t, mp_limb_t);
+mp_limb_t ref_bswap_limb (mp_limb_t);
+unsigned long ref_popc_limb (mp_limb_t);
+mp_limb_t ref_subc_limb (mp_limb_t *, mp_limb_t, mp_limb_t);
+
+
+void refmpf_add (mpf_ptr, mpf_srcptr, mpf_srcptr);
+void refmpf_add_ulp (mpf_ptr );
+void refmpf_fill (mpf_ptr, mp_size_t, mp_limb_t);
+void refmpf_normalize (mpf_ptr);
+void refmpf_set_prec_limbs (mpf_ptr, unsigned long);
+unsigned long refmpf_set_overlap (mpf_ptr, mpf_srcptr);
+void refmpf_sub (mpf_ptr, mpf_srcptr, mpf_srcptr);
+int refmpf_validate (const char *, mpf_srcptr, mpf_srcptr);
+int refmpf_validate_division (const char *, mpf_srcptr, mpf_srcptr, mpf_srcptr);
+
+
+mp_limb_t refmpn_cnd_add_n (mp_limb_t, mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+mp_limb_t refmpn_cnd_sub_n (mp_limb_t, mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+
+mp_limb_t refmpn_add (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+mp_limb_t refmpn_add_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t refmpn_add_err1_n (mp_ptr, mp_srcptr, mp_srcptr, mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t refmpn_add_err2_n (mp_ptr, mp_srcptr, mp_srcptr, mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t refmpn_add_err3_n (mp_ptr, mp_srcptr, mp_srcptr, mp_ptr, mp_srcptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t refmpn_add_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+mp_limb_t refmpn_add_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t refmpn_addlsh1_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+mp_limb_t refmpn_addlsh2_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+mp_limb_t refmpn_addlsh_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, unsigned);
+mp_limb_t refmpn_addlsh1_n_ip1 (mp_ptr, mp_srcptr, mp_size_t);
+mp_limb_t refmpn_addlsh2_n_ip1 (mp_ptr, mp_srcptr, mp_size_t);
+mp_limb_t refmpn_addlsh_n_ip1 (mp_ptr, mp_srcptr, mp_size_t, unsigned);
+mp_limb_t refmpn_addlsh1_n_ip2 (mp_ptr, mp_srcptr, mp_size_t);
+mp_limb_t refmpn_addlsh2_n_ip2 (mp_ptr, mp_srcptr, mp_size_t);
+mp_limb_t refmpn_addlsh_n_ip2 (mp_ptr, mp_srcptr, mp_size_t, unsigned);
+mp_limb_t refmpn_addlsh1_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t refmpn_addlsh2_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t refmpn_addlsh_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, unsigned, mp_limb_t);
+mp_limb_t refmpn_addmul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t refmpn_addmul_1c (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t);
+mp_limb_t refmpn_addmul_2 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+mp_limb_t refmpn_addmul_3 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+mp_limb_t refmpn_addmul_4 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+mp_limb_t refmpn_addmul_5 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+mp_limb_t refmpn_addmul_6 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+mp_limb_t refmpn_addmul_7 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+mp_limb_t refmpn_addmul_8 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+
+mp_limb_t refmpn_add_n_sub_n (mp_ptr, mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+mp_limb_t refmpn_add_n_sub_nc (mp_ptr, mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+void refmpn_and_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+void refmpn_andn_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+
+mp_limb_t refmpn_big_base (int);
+
+int refmpn_chars_per_limb (int);
+void refmpn_clrbit (mp_ptr, unsigned long);
+int refmpn_cmp (mp_srcptr, mp_srcptr, mp_size_t);
+int refmpn_cmp_allowzero (mp_srcptr, mp_srcptr, mp_size_t);
+int refmpn_cmp_twosizes (mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+
+void refmpn_com (mp_ptr, mp_srcptr, mp_size_t);
+void refmpn_copy (mp_ptr, mp_srcptr, mp_size_t);
+void refmpn_copyi (mp_ptr, mp_srcptr, mp_size_t);
+void refmpn_copyd (mp_ptr, mp_srcptr, mp_size_t);
+void refmpn_copy_extend (mp_ptr, mp_size_t, mp_srcptr, mp_size_t);
+
+unsigned refmpn_count_leading_zeros (mp_limb_t);
+unsigned refmpn_count_trailing_zeros (mp_limb_t);
+
+mp_limb_t refmpn_divexact_by3 (mp_ptr, mp_srcptr, mp_size_t);
+mp_limb_t refmpn_divexact_by3c (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+mp_limb_t refmpn_divmod_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t refmpn_divmod_1c (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t);
+mp_limb_t refmpn_divrem_1 (mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t refmpn_divrem_1c (mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t);
+mp_limb_t refmpn_divrem_2 (mp_ptr, mp_size_t, mp_ptr, mp_size_t, mp_srcptr);
+
+int refmpn_equal_anynail (mp_srcptr, mp_srcptr, mp_size_t);
+
+void refmpn_fill (mp_ptr, mp_size_t, mp_limb_t);
+
+mp_limb_t refmpn_gcd_11 (mp_limb_t, mp_limb_t);
+mp_limb_t refmpn_gcd_1 (mp_srcptr, mp_size_t, mp_limb_t);
+mp_double_limb_t refmpn_gcd_22 (mp_limb_t, mp_limb_t, mp_limb_t, mp_limb_t);
+mp_limb_t refmpn_gcd (mp_ptr, mp_ptr, mp_size_t, mp_ptr, mp_size_t);
+
+size_t refmpn_get_str (unsigned char *, int, mp_ptr, mp_size_t);
+
+unsigned long refmpn_hamdist (mp_srcptr, mp_srcptr, mp_size_t);
+
+mp_limb_t refmpn_invert_limb (mp_limb_t);
+void refmpn_ior_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+void refmpn_iorn_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+
+mp_limb_t refmpn_lshift (mp_ptr, mp_srcptr, mp_size_t, unsigned);
+mp_limb_t refmpn_lshift_or_copy (mp_ptr, mp_srcptr, mp_size_t, unsigned);
+mp_limb_t refmpn_lshift_or_copy_any (mp_ptr, mp_srcptr, mp_size_t, unsigned);
+mp_limb_t refmpn_lshiftc (mp_ptr, mp_srcptr, mp_size_t, unsigned);
+void refmpn_com (mp_ptr, mp_srcptr, mp_size_t);
+
+mp_ptr refmpn_malloc_limbs (mp_size_t);
+mp_ptr refmpn_malloc_limbs_aligned (mp_size_t, size_t);
+void refmpn_free_limbs (mp_ptr);
+mp_limb_t refmpn_msbone (mp_limb_t);
+mp_limb_t refmpn_msbone_mask (mp_limb_t);
+mp_ptr refmpn_memdup_limbs (mp_srcptr, mp_size_t);
+
+mp_limb_t refmpn_mod_1 (mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t refmpn_mod_1c (mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t);
+mp_limb_t refmpn_mod_34lsub1 (mp_srcptr, mp_size_t);
+
+mp_limb_t refmpn_mul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t refmpn_mul_1c (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t);
+mp_limb_t refmpn_mul_2 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+mp_limb_t refmpn_mul_3 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+mp_limb_t refmpn_mul_4 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+mp_limb_t refmpn_mul_5 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+mp_limb_t refmpn_mul_6 (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr);
+
+void refmpn_mul_basecase (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+void refmpn_mulmid_basecase (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+void refmpn_toom42_mulmid (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_ptr);
+void refmpn_mulmid_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+void refmpn_mulmid (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+void refmpn_mullo_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+void refmpn_mul_any (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+void refmpn_mul_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+void refmpn_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+
+void refmpn_nand_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+void refmpn_nior_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+mp_limb_t refmpn_neg (mp_ptr, mp_srcptr, mp_size_t);
+mp_size_t refmpn_normalize (mp_srcptr, mp_size_t);
+
+unsigned long refmpn_popcount (mp_srcptr, mp_size_t);
+mp_limb_t refmpn_preinv_divrem_1 (mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t, unsigned);
+mp_limb_t refmpn_preinv_mod_1 (mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t);
+
+void refmpn_random (mp_ptr, mp_size_t);
+void refmpn_random2 (mp_ptr, mp_size_t);
+mp_limb_t refmpn_random_limb (void);
+
+mp_limb_t refmpn_rsh1add_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+mp_limb_t refmpn_rsh1sub_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+mp_limb_t refmpn_rshift (mp_ptr, mp_srcptr, mp_size_t, unsigned);
+mp_limb_t refmpn_rshift_or_copy (mp_ptr, mp_srcptr, mp_size_t, unsigned);
+mp_limb_t refmpn_rshift_or_copy_any (mp_ptr, mp_srcptr, mp_size_t, unsigned);
+
+mp_limb_t refmpn_sb_div_qr (mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t);
+unsigned long refmpn_scan0 (mp_srcptr, unsigned long);
+unsigned long refmpn_scan1 (mp_srcptr, unsigned long);
+void refmpn_setbit (mp_ptr, unsigned long);
+void refmpn_sqr (mp_ptr, mp_srcptr, mp_size_t);
+void refmpn_sqrlo (mp_ptr, mp_srcptr, mp_size_t);
+mp_size_t refmpn_sqrtrem (mp_ptr, mp_ptr, mp_srcptr, mp_size_t);
+
+void refmpn_sub_ddmmss (mp_limb_t *, mp_limb_t *, mp_limb_t, mp_limb_t, mp_limb_t, mp_limb_t);
+mp_limb_t refmpn_sub (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+mp_limb_t refmpn_sub_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t refmpn_sub_err1_n (mp_ptr, mp_srcptr, mp_srcptr, mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t refmpn_sub_err2_n (mp_ptr, mp_srcptr, mp_srcptr, mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t refmpn_sub_err3_n (mp_ptr, mp_srcptr, mp_srcptr, mp_ptr, mp_srcptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t refmpn_sub_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+mp_limb_t refmpn_sub_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t refmpn_sublsh1_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+mp_limb_t refmpn_sublsh2_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+mp_limb_t refmpn_sublsh_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, unsigned int);
+mp_limb_t refmpn_sublsh1_n_ip1 (mp_ptr, mp_srcptr, mp_size_t);
+mp_limb_t refmpn_sublsh2_n_ip1 (mp_ptr, mp_srcptr, mp_size_t);
+mp_limb_t refmpn_sublsh_n_ip1 (mp_ptr, mp_srcptr, mp_size_t, unsigned int);
+mp_limb_t refmpn_sublsh1_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t refmpn_sublsh2_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t refmpn_sublsh_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, unsigned int, mp_limb_t);
+mp_limb_t refmpn_submul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t refmpn_submul_1c (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t);
+
+mp_limb_signed_t refmpn_rsblsh1_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+mp_limb_signed_t refmpn_rsblsh2_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+mp_limb_signed_t refmpn_rsblsh_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, unsigned int);
+mp_limb_signed_t refmpn_rsblsh1_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_signed_t);
+mp_limb_signed_t refmpn_rsblsh2_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, mp_limb_signed_t);
+mp_limb_signed_t refmpn_rsblsh_nc (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t, unsigned int, mp_limb_signed_t);
+
+void refmpn_tdiv_qr (mp_ptr, mp_ptr, mp_size_t, mp_ptr, mp_size_t, mp_srcptr, mp_size_t);
+int refmpn_tstbit (mp_srcptr, unsigned long);
+
+mp_limb_t refmpn_udiv_qrnnd (mp_limb_t *, mp_limb_t, mp_limb_t, mp_limb_t);
+mp_limb_t refmpn_udiv_qrnnd_r (mp_limb_t, mp_limb_t, mp_limb_t, mp_limb_t *);
+mp_limb_t refmpn_umul_ppmm (mp_limb_t *, mp_limb_t, mp_limb_t);
+mp_limb_t refmpn_umul_ppmm_r (mp_limb_t, mp_limb_t, mp_limb_t *);
+
+void refmpn_xnor_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+void refmpn_xor_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+
+void refmpn_zero (mp_ptr, mp_size_t);
+void refmpn_zero_extend (mp_ptr, mp_size_t, mp_size_t);
+int refmpn_zero_p (mp_srcptr, mp_size_t);
+
+void refmpn_binvert (mp_ptr, mp_srcptr, mp_size_t, mp_ptr);
+void refmpn_invert (mp_ptr, mp_srcptr, mp_size_t, mp_ptr);
+
+
+void refmpq_add (mpq_ptr, mpq_srcptr, mpq_srcptr);
+void refmpq_sub (mpq_ptr, mpq_srcptr, mpq_srcptr);
+
+
+void refmpz_combit (mpz_ptr, unsigned long);
+unsigned long refmpz_hamdist (mpz_srcptr, mpz_srcptr);
+void refmpz_gcd (mpz_ptr, mpz_srcptr, mpz_srcptr);
+int refmpz_kronecker (mpz_srcptr, mpz_srcptr);
+int refmpz_jacobi (mpz_srcptr, mpz_srcptr);
+int refmpz_legendre (mpz_srcptr, mpz_srcptr);
+int refmpz_kronecker_si (mpz_srcptr, long);
+int refmpz_kronecker_ui (mpz_srcptr, unsigned long);
+int refmpz_si_kronecker (long, mpz_srcptr);
+int refmpz_ui_kronecker (unsigned long, mpz_srcptr);
+
+void refmpz_pow_ui (mpz_ptr, mpz_srcptr, unsigned long);
+
+
+#if defined (__cplusplus)
+}
+#endif
+
+
+/* Establish ostringstream and istringstream.  Do this here so as to hide
+   the conditionals, rather than putting stuff in each test program.
+
+   Oldish versions of g++, like 2.95.2, don't have <sstream>, only
+   <strstream>.  Fake up ostringstream and istringstream classes, but not a
+   full implementation, just enough for our purposes.  */
+
+#ifdef __cplusplus
+#if 1 || HAVE_SSTREAM
+#include <sstream>
+#else /* ! HAVE_SSTREAM */
+#include <string>
+#include <strstream>
+class
+ostringstream : public std::ostrstream {
+ public:
+  string str() {
+    int  pcount = ostrstream::pcount ();
+    char *s = (char *) (*__gmp_allocate_func) (pcount + 1);
+    memcpy (s, ostrstream::str(), pcount);
+    s[pcount] = '\0';
+    string ret = string(s);
+    (*__gmp_free_func) (s, pcount + 1);
+    return ret; }
+};
+class
+istringstream : public std::istrstream {
+ public:
+  istringstream (const char *s) : istrstream (s) { };
+};
+#endif /* ! HAVE_SSTREAM */
+#endif /* __cplusplus */
+
+
+#define TESTS_REPS(count, argv, argc)					\
+  do {									\
+  char *envval, *end;							\
+  double repfactor;							\
+  int reps_nondefault = 0;						\
+  if (argc > 1)								\
+    {									\
+      count = strtol (argv[1], &end, 0);				\
+      if (*end || count <= 0)						\
+	{								\
+	  fprintf (stderr, "Invalid test count: %s.\n", argv[1]);	\
+	  exit (1);							\
+	}								\
+      argv++;								\
+      argc--;								\
+      reps_nondefault = 1;						\
+    }									\
+  envval = getenv ("GMP_CHECK_REPFACTOR");				\
+  if (envval != NULL)							\
+    {									\
+      repfactor = strtod (envval, &end);				\
+      if (*end || repfactor <= 0)					\
+	{								\
+	  fprintf (stderr, "Invalid repfactor: %f.\n", repfactor);	\
+	  exit (1);							\
+	}								\
+      count *= repfactor;						\
+      count = MAX (count, 1);						\
+      reps_nondefault = 1;						\
+    }									\
+  if (reps_nondefault)							\
+    printf ("Running test with %ld repetitions (include this in bug reports)\n",\
+	    (long) count);						\
+  } while (0)
+
+
+#endif /* __TESTS_H__ */
diff --git a/third_party/gmp/tests/trace.c b/third_party/gmp/tests/trace.c
new file mode 100644
index 0000000..de397f5
--- /dev/null
+++ b/third_party/gmp/tests/trace.c
@@ -0,0 +1,317 @@
+/* Support for diagnostic traces.
+
+Copyright 1999-2005 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+
+/* Future: Would like commas printed between limbs in hex or binary, but
+   perhaps not always since it might upset cutting and pasting into bc or
+   whatever.  */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h> /* for strlen */
+
+#include "gmp-impl.h"
+
+#include "tests.h"
+
+
+/* Number base for the various trace printing routines.
+   Set this in main() or with the debugger.
+   If hexadecimal is going to be fed into GNU bc, remember to use -16
+   because bc requires upper case.  */
+
+int  mp_trace_base = 10;
+
+
+void
+mp_trace_start (const char *name)
+{
+  if (name != NULL && name[0] != '\0')
+    printf ("%s=", name);
+
+  switch (ABS (mp_trace_base)) {
+  case  2: printf ("bin:");                         break;
+  case  8: printf ("oct:");                         break;
+  case 10:                                          break;
+  case 16: printf ("0x");                           break;
+  default: printf ("base%d:", ABS (mp_trace_base)); break;
+  }
+}
+
+/* Print "name=value\n" to stdout for an mpq_t value.  */
+void
+mpq_trace (const char *name, mpq_srcptr q)
+{
+  mp_trace_start (name);
+  if (q == NULL)
+    {
+      printf ("NULL\n");
+      return;
+    }
+
+  mpq_out_str (stdout, mp_trace_base, q);
+  printf ("\n");
+}
+
+
+/* Print "name=value\n" to stdout for an mpz_t value.  */
+void
+mpz_trace (const char *name, mpz_srcptr z)
+{
+  mpq_t      q;
+  mp_limb_t  one;
+
+  if (z == NULL)
+    {
+      mpq_trace (name, NULL);
+      return;
+    }
+
+  q->_mp_num._mp_alloc = ALLOC(z);
+  q->_mp_num._mp_size = SIZ(z);
+  q->_mp_num._mp_d = PTR(z);
+
+  one = 1;
+  q->_mp_den._mp_alloc = 1;
+  q->_mp_den._mp_size = 1;
+  q->_mp_den._mp_d = &one;
+
+  mpq_trace(name, q);
+}
+
+
+/* Print "name=value\n" to stdout for an mpf_t value. */
+void
+mpf_trace (const char *name, mpf_srcptr f)
+{
+  mp_trace_start (name);
+  if (f == NULL)
+    {
+      printf ("NULL\n");
+      return;
+    }
+
+  mpf_out_str (stdout, ABS (mp_trace_base), 0, f);
+  printf ("\n");
+}
+
+
+/* Print "namenum=value\n" to stdout for an mpz_t value.
+   "name" should have a "%d" to get the number. */
+void
+mpz_tracen (const char *name, int num, mpz_srcptr z)
+{
+  if (name != NULL && name[0] != '\0')
+    {
+      printf (name, num);
+      putchar ('=');
+    }
+  mpz_trace (NULL, z);
+}
+
+
+/* Print "name=value\n" to stdout for an mpn style ptr,size. */
+void
+mpn_trace (const char *name, mp_srcptr ptr, mp_size_t size)
+{
+  mpz_t  z;
+  if (ptr == NULL)
+    {
+      mpz_trace (name, NULL);
+      return;
+    }
+  MPN_NORMALIZE (ptr, size);
+  PTR(z) = (mp_ptr) ptr;
+  SIZ(z) = size;
+  ALLOC(z) = size;
+  mpz_trace (name, z);
+}
+
+/* Print "name=value\n" to stdout for a limb, nail doesn't have to be zero. */
+void
+mp_limb_trace (const char *name, mp_limb_t n)
+{
+#if GMP_NAIL_BITS != 0
+  mp_limb_t  a[2];
+  a[0] = n & GMP_NUMB_MASK;
+  a[1] = n >> GMP_NUMB_BITS;
+  mpn_trace (name, a, (mp_size_t) 2);
+#else
+  mpn_trace (name, &n, (mp_size_t) 1);
+#endif
+}
+
+
+/* Print "namenum=value\n" to stdout for an mpn style ptr,size.
+   "name" should have a "%d" to get the number.  */
+void
+mpn_tracen (const char *name, int num, mp_srcptr ptr, mp_size_t size)
+{
+  if (name != NULL && name[0] != '\0')
+    {
+      printf (name, num);
+      putchar ('=');
+    }
+  mpn_trace (NULL, ptr, size);
+}
+
+
+/* Print "namenum=value\n" to stdout for an array of mpn style ptr,size.
+
+   "a" is an array of pointers, each a[i] is a pointer to "size" many limbs.
+   The formal parameter isn't mp_srcptr because that causes compiler
+   warnings, but the values aren't modified.
+
+   "name" should have a printf style "%d" to get the array index.  */
+
+void
+mpn_tracea (const char *name, const mp_ptr *a, int count, mp_size_t size)
+{
+  int i;
+  for (i = 0; i < count; i++)
+    mpn_tracen (name, i, a[i], size);
+}
+
+
+/* Print "value\n" to a file for an mpz_t value.  Any previous contents of
+   the file are overwritten, so you need different file names each time this
+   is called.
+
+   Overwriting the file is a feature, it means you get old data replaced
+   when you run a test program repeatedly.  */
+
+void
+mpn_trace_file (const char *filename, mp_srcptr ptr, mp_size_t size)
+{
+  FILE   *fp;
+  mpz_t  z;
+
+  fp = fopen (filename, "w");
+  if (fp == NULL)
+    {
+      perror ("fopen");
+      abort();
+    }
+
+  MPN_NORMALIZE (ptr, size);
+  PTR(z) = (mp_ptr) ptr;
+  SIZ(z) = (int) size;
+
+  mpz_out_str (fp, mp_trace_base, z);
+  fprintf (fp, "\n");
+
+  if (ferror (fp) || fclose (fp) != 0)
+    {
+      printf ("error writing %s\n", filename);
+      abort();
+    }
+}
+
+
+/* Print "value\n" to a set of files, one file for each element of the given
+   array of mpn style ptr,size.  Any previous contents of the files are
+   overwritten, so you need different file names each time this is called.
+   Each file is "filenameN" where N is 0 to count-1.
+
+   "a" is an array of pointers, each a[i] is a pointer to "size" many limbs.
+   The formal parameter isn't mp_srcptr because that causes compiler
+   warnings, but the values aren't modified.
+
+   Overwriting the files is a feature, it means you get old data replaced
+   when you run a test program repeatedly.  The output style isn't
+   particularly pretty, but at least it gets something out, and you can cat
+   the files into bc, or whatever. */
+
+void
+mpn_tracea_file (const char *filename,
+                 const mp_ptr *a, int count, mp_size_t size)
+{
+  char  *s;
+  int   i;
+  TMP_DECL;
+
+  TMP_MARK;
+  s = (char *) TMP_ALLOC (strlen (filename) + 50);
+
+  for (i = 0; i < count; i++)
+    {
+      sprintf (s, "%s%d", filename, i);
+      mpn_trace_file (s, a[i], size);
+    }
+
+  TMP_FREE;
+}
+
+
+void
+byte_trace (const char *name, const void *ptr, mp_size_t size)
+{
+  const char *fmt;
+  mp_size_t  i;
+
+  mp_trace_start (name);
+
+  switch (mp_trace_base) {
+  case   8: fmt = " %o"; break;
+  case  10: fmt = " %d"; break;
+  case  16: fmt = " %x"; break;
+  case -16: fmt = " %X"; break;
+  default: printf ("Oops, unsupported base in byte_trace\n"); abort (); break;
+  }
+
+  for (i = 0; i < size; i++)
+    printf (fmt, (int) ((unsigned char *) ptr)[i]);
+  printf ("\n");
+}
+
+void
+byte_tracen (const char *name, int num, const void *ptr, mp_size_t size)
+{
+  if (name != NULL && name[0] != '\0')
+    {
+      printf (name, num);
+      putchar ('=');
+    }
+  byte_trace (NULL, ptr, size);
+}
+
+
+void
+d_trace (const char *name, double d)
+{
+  union {
+    double         d;
+    unsigned char  b[sizeof(double)];
+  } u;
+  int  i;
+
+  if (name != NULL && name[0] != '\0')
+    printf ("%s=", name);
+
+  u.d = d;
+  printf ("[");
+  for (i = 0; i < sizeof (u.b); i++)
+    {
+      if (i != 0)
+        printf (" ");
+      printf ("%02X", (int) u.b[i]);
+    }
+  printf ("] %.20g\n", d);
+}
diff --git a/third_party/gmp/tests/x86call.asm b/third_party/gmp/tests/x86call.asm
new file mode 100644
index 0000000..462b68b
--- /dev/null
+++ b/third_party/gmp/tests/x86call.asm
@@ -0,0 +1,154 @@
+dnl  x86 calling conventions checking.
+
+dnl  Copyright 2000, 2003, 2010, 2013 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library test suite.
+
+dnl  The GNU MP Library test suite is free software; you can redistribute it
+dnl  and/or modify it under the terms of the GNU General Public License as
+dnl  published by the Free Software Foundation; either version 3 of the
+dnl  License, or (at your option) any later version.
+
+dnl  The GNU MP Library test suite is distributed in the hope that it will be
+dnl  useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+dnl  Public License for more details.
+
+dnl  You should have received a copy of the GNU General Public License along
+dnl  with the GNU MP Library test suite.  If not, see
+dnl  https://www.gnu.org/licenses/.
+
+
+dnl  The current version of the code attempts to keep the call/return
+dnl  prediction stack valid, but matching calls and returns.
+
+include(`../config.m4')
+
+
+C void x86_fldcw (unsigned short cw);
+C
+C Execute an fldcw, setting the x87 control word to cw.
+
+PROLOGUE(x86_fldcw)
+	fldcw	4(%esp)
+	ret
+EPILOGUE()
+
+
+C unsigned short x86_fstcw (void);
+C
+C Execute an fstcw, returning the current x87 control word.
+
+PROLOGUE(x86_fstcw)
+	xor	%eax, %eax
+	push	%eax
+	fstcw	(%esp)
+	pop	%eax
+	ret
+EPILOGUE()
+
+
+dnl  Instrumented profiling doesn't come out quite right below, since we don't
+dnl  do an actual "ret".  There's only a few instructions here, so there's no
+dnl  great need to get them separately accounted, just let them get attributed
+dnl  to the caller.  FIXME this comment might no longer be true.
+
+ifelse(WANT_PROFILING,instrument,
+`define(`WANT_PROFILING',no)')
+
+
+C int calling_conventions (...);
+C
+C The global variable "calling_conventions_function" is the function to
+C call, with the arguments as passed here.
+C
+C Perhaps the finit should be done only if the tags word isn't clear, but
+C nothing uses the rounding mode or anything at the moment.
+
+define(`WANT_EBX', eval(4*0)($1))
+define(`WANT_EBP', eval(4*1)($1))
+define(`WANT_ESI', eval(4*2)($1))
+define(`WANT_EDI', eval(4*3)($1))
+
+define(`JUNK_EAX', eval(4*4)($1))
+define(`JUNK_ECX', eval(4*5)($1))
+define(`JUNK_EDX', eval(4*6)($1))
+
+define(`SAVE_EBX', eval(4*7)($1))
+define(`SAVE_EBP', eval(4*8)($1))
+define(`SAVE_ESI', eval(4*9)($1))
+define(`SAVE_EDI', eval(4*10)($1))
+
+define(`RETADDR',  eval(4*11)($1))
+
+define(`EBX',	   eval(4*12)($1))
+define(`EBP',	   eval(4*13)($1))
+define(`ESI',	   eval(4*14)($1))
+define(`EDI',	   eval(4*15)($1))
+define(`EFLAGS',   eval(4*16)($1))
+
+
+define(G,
+m4_assert_numargs(1)
+`GSYM_PREFIX`'$1')
+
+	TEXT
+	ALIGN(8)
+PROLOGUE(calling_conventions)
+	LEA(	G(calling_conventions_values), %ecx)
+	pop	RETADDR(%ecx)
+
+	mov	%ebx, SAVE_EBX(%ecx)
+	mov	%ebp, SAVE_EBP(%ecx)
+	mov	%esi, SAVE_ESI(%ecx)
+	mov	%edi, SAVE_EDI(%ecx)
+
+	C Values we expect to see unchanged, as per amd64check.c
+	mov	WANT_EBX(%ecx), %ebx
+	mov	WANT_EBP(%ecx), %ebp
+	mov	WANT_ESI(%ecx), %esi
+	mov	WANT_EDI(%ecx), %edi
+
+	C Try to provoke a problem by starting with junk in the caller-saves
+	C registers, especially in %eax and %edx which will be return values
+	mov	JUNK_EAX(%ecx), %eax
+	mov	JUNK_EDX(%ecx), %edx
+C	mov	JUNK_ECX(%ecx), %ecx
+
+ifdef(`PIC',`
+	LEA(	G(calling_conventions_function), %ecx)
+	call	*(%ecx)
+',`
+	call	*G(calling_conventions_function)
+')
+
+	LEA(	G(calling_conventions_values), %ecx)
+
+	mov	%ebx, EBX(%ecx)
+	mov	%ebp, EBP(%ecx)
+	mov	%esi, ESI(%ecx)
+	mov	%edi, EDI(%ecx)
+
+	pushf
+	pop	%ebx
+	mov	%ebx, EFLAGS(%ecx)
+
+	mov	SAVE_EBX(%ecx), %ebx
+	mov	SAVE_ESI(%ecx), %esi
+	mov	SAVE_EDI(%ecx), %edi
+	mov	SAVE_EBP(%ecx), %ebp
+
+	push	RETADDR(%ecx)
+
+ifdef(`PIC',`
+	LEA(	G(calling_conventions_fenv), %ecx)
+	fstenv	(%ecx)
+',`
+	fstenv	G(calling_conventions_fenv)
+')
+	finit
+
+	ret
+
+EPILOGUE()
+ASM_END()
diff --git a/third_party/gmp/tests/x86check.c b/third_party/gmp/tests/x86check.c
new file mode 100644
index 0000000..12ea5b7
--- /dev/null
+++ b/third_party/gmp/tests/x86check.c
@@ -0,0 +1,117 @@
+/* x86 calling conventions checking. */
+
+/*
+Copyright 2000, 2001, 2010 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library test suite.
+
+The GNU MP Library test suite is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 3 of the License,
+or (at your option) any later version.
+
+The GNU MP Library test suite is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp-impl.h"
+#include "tests.h"
+
+
+/* Vector if constants and register values.  We use one vector to allow access
+   via a base pointer, very beneficial for the PIC-enabled amd64call.asm.  */
+mp_limb_t calling_conventions_values[17] =
+{
+  CNST_LIMB(0x12345678),	/* want_ebx */
+  CNST_LIMB(0x89ABCDEF),	/* want_ebp */
+  CNST_LIMB(0xDEADBEEF),	/* want_esi */
+  CNST_LIMB(0xFFEEDDCC),	/* want_edi */
+
+  CNST_LIMB(0xFEEDABBA),	/* JUNK_EAX */
+  CNST_LIMB(0xAB78DE89),	/* JUNK_ECX */
+  CNST_LIMB(0x12389018)		/* JUNK_EDX */
+
+  /* rest of array used for dynamic values.  */
+};
+
+/* Index starts for various regions in above vector.  */
+#define WANT	0
+#define JUNK	4
+#define SAVE	7
+#define RETADDR	11
+#define VAL	12
+#define EFLAGS	16
+
+
+/* values to check */
+#ifdef __cplusplus
+extern "C" {
+#endif
+struct {
+  unsigned  control;
+  unsigned  status;
+  unsigned  tag;
+  unsigned  other[4];
+} calling_conventions_fenv;
+#ifdef __cplusplus
+}
+#endif
+
+/* expected values, as per x86call.asm */
+#define VALUE_EBX   0x01234567
+#define VALUE_ESI   0x89ABCDEF
+#define VALUE_EDI   0xFEDCBA98
+#define VALUE_EBP   0x76543210
+
+
+const char *regname[] = {"ebx", "ebp", "esi", "edi"};
+
+#define DIR_BIT(eflags)   (((eflags) & (1<<10)) != 0)
+
+
+/* Return 1 if ok, 0 if not */
+
+int
+calling_conventions_check (void)
+{
+  const char  *header = "Violated calling conventions:\n";
+  int  ret = 1;
+  int i;
+
+#define CHECK(callreg, regstr, value)                   \
+  if (callreg != value)                                 \
+    {                                                   \
+      printf ("%s   %s  got 0x%08X want 0x%08X\n",      \
+              header, regstr, callreg, value);          \
+      header = "";                                      \
+      ret = 0;                                          \
+    }
+
+  for (i = 0; i < 4; i++)
+    {
+      CHECK (calling_conventions_values[VAL+i], regname[i], calling_conventions_values[WANT+i]);
+    }
+
+  if (DIR_BIT (calling_conventions_values[EFLAGS]) != 0)
+    {
+      printf ("%s   eflags dir bit  got %d want 0\n",
+              header, DIR_BIT (calling_conventions_values[EFLAGS]));
+      header = "";
+      ret = 0;
+    }
+
+  if ((calling_conventions_fenv.tag & 0xFFFF) != 0xFFFF)
+    {
+      printf ("%s   fpu tags  got 0x%X want 0xFFFF\n",
+              header, calling_conventions_fenv.tag & 0xFFFF);
+      header = "";
+      ret = 0;
+    }
+
+  return ret;
+}
diff --git a/third_party/gmp/tune/Makefile.am b/third_party/gmp/tune/Makefile.am
new file mode 100644
index 0000000..9e38256
--- /dev/null
+++ b/third_party/gmp/tune/Makefile.am
@@ -0,0 +1,186 @@
+## Process this file with automake to generate Makefile.in
+
+# Copyright 2000-2003, 2005-2011 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+
+AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/tests
+AM_LDFLAGS = -no-install
+
+EXTRA_DIST = alpha.asm pentium.asm sparcv9.asm hppa.asm hppa2.asm hppa2w.asm \
+  ia64.asm powerpc.asm powerpc64.asm x86_64.asm many.pl
+noinst_HEADERS = speed.h
+
+# Prefer -static on the speed and tune programs, since that can avoid
+# overheads of shared library linkages on some systems.  Libtool tends to
+# botch -static if configured with --disable-static, perhaps reasonably
+# enough.  In any event under --disable-static the only choice is a dynamic
+# link so there's no point in -static.
+#
+if ENABLE_STATIC
+STATIC = -static
+else
+STATIC =
+endif
+
+
+EXTRA_LTLIBRARIES = libspeed.la
+
+libspeed_la_SOURCES =							\
+  common.c divrem1div.c divrem1inv.c divrem2div.c divrem2inv.c		\
+  div_qr_1n_pi1_1.c div_qr_1n_pi1_2.c div_qr_1_tune.c			\
+  freq.c								\
+  gcdext_single.c gcdext_double.c gcdextod.c gcdextos.c			\
+  hgcd_lehmer.c hgcd_appr_lehmer.c hgcd_reduce_1.c hgcd_reduce_2.c	\
+  jacbase1.c jacbase2.c jacbase3.c jacbase4.c				\
+  hgcd2-1.c hgcd2-2.c hgcd2-3.c hgcd2-4.c hgcd2-5.c			\
+  mod_1_div.c mod_1_inv.c mod_1_1-1.c mod_1_1-2.c modlinv.c		\
+  noop.c powm_mod.c powm_redc.c pre_divrem_1.c				\
+  set_strb.c set_strs.c set_strp.c time.c
+
+libspeed_la_DEPENDENCIES = $(SPEED_CYCLECOUNTER_OBJ) \
+  $(top_builddir)/tests/libtests.la $(top_builddir)/libgmp.la
+libspeed_la_LIBADD = $(libspeed_la_DEPENDENCIES) $(LIBM)
+libspeed_la_LDFLAGS = $(STATIC)
+
+$(top_builddir)/tests/libtests.la:
+	cd $(top_builddir)/tests; $(MAKE) $(AM_MAKEFLAGS) libtests.la
+
+
+# The library code is faster static than shared on some systems, so do
+# tuning and measuring with static, since users who care about maximizing
+# speed will be using that.  speed-dynamic exists to show the difference.
+#
+# On Solaris 8, gcc 2.95.2 -static is somehow broken (it creates executables
+# that immediately seg fault), so -all-static is not used.  The only thing
+# -all-static does is make libc static linked as well as libgmp, and that
+# makes a difference only when measuring malloc and friends in the speed
+# program.  This can always be forced with "make speed_LDFLAGS=-all-static
+# ..." if desired, see tune/README.
+
+EXTRA_PROGRAMS = speed speed-dynamic speed-ext tuneup tune-gcd-p
+
+DEPENDENCIES = libspeed.la
+LDADD = $(DEPENDENCIES) $(TUNE_LIBS)
+
+speed_SOURCES = speed.c
+speed_LDFLAGS = $(STATIC)
+
+speed_dynamic_SOURCES = speed.c
+
+speed_ext_SOURCES = speed-ext.c
+speed_ext_LDFLAGS = $(STATIC)
+
+tuneup_SOURCES = tuneup.c hgcd2.c
+nodist_tuneup_SOURCES = sqr_basecase.c fac_ui.c $(TUNE_MPN_SRCS)
+tuneup_DEPENDENCIES = $(TUNE_SQR_OBJ) libspeed.la
+tuneup_LDADD = $(tuneup_DEPENDENCIES) $(TUNE_LIBS)
+tuneup_LDFLAGS = $(STATIC)
+
+tune_gcd_p_SOURCES = tune-gcd-p.c
+tune_gcd_p_DEPENDENCIES = ../mpn/gcd.c
+tune_gcd_p_LDFLAGS = $(STATIC)
+
+
+tune:
+	$(MAKE) $(AM_MAKEFLAGS) tuneup$(EXEEXT)
+	./tuneup
+
+allprogs: $(EXTRA_PROGRAMS)
+
+# $(MANY_CLEAN) and $(MANY_DISTCLEAN) are hooks for many.pl
+CLEANFILES = $(EXTRA_PROGRAMS) $(EXTRA_LTLIBRARIES) \
+	$(TUNE_MPN_SRCS) fac_ui.c sqr_asm.asm \
+	stg.gnuplot stg.data \
+	mtg.gnuplot mtg.data \
+	fibg.gnuplot fibg.data \
+	graph.gnuplot graph.data \
+	$(MANY_CLEAN)
+DISTCLEANFILES = sqr_basecase.c  $(MANY_DISTCLEAN)
+
+
+# Generating these little files at build time seems better than including
+# them in the distribution, since the list can be changed more easily.
+#
+# mpn/generic/tdiv_qr.c uses mpn_divrem_1 and mpn_divrem_2, but only for 1
+# and 2 limb divisors, which are never used during tuning, so it doesn't
+# matter whether it picks up a tuned or untuned version of those.
+#
+# divrem_1 and mod_1 are recompiled renamed to "_tune" to avoid a linking
+# problem.  If a native divrem_1 provides an mpn_divrem_1c entrypoint then
+# common.c will want that, but the generic divrem_1 doesn't provide it,
+# likewise for mod_1.  The simplest way around this is to have the tune
+# build versions renamed suitably.
+#
+# FIXME: Would like say mul_n.c to depend on $(top_builddir)/mul_n.c so the
+# recompiled object will be rebuilt if that file changes.
+
+TUNE_MPN_SRCS = $(TUNE_MPN_SRCS_BASIC) divrem_1.c mod_1.c
+TUNE_MPN_SRCS_BASIC = div_qr_2.c bdiv_q.c bdiv_qr.c			\
+  dcpi1_div_qr.c dcpi1_divappr_q.c dcpi1_bdiv_qr.c dcpi1_bdiv_q.c	\
+  invertappr.c invert.c binvert.c divrem_2.c gcd.c gcdext.c		\
+  get_str.c set_str.c matrix22_mul.c					\
+  hgcd.c hgcd_appr.c hgcd_reduce.c					\
+  mul_n.c sqr.c sec_powm.c						\
+  mullo_n.c mul_fft.c mul.c tdiv_qr.c mulmod_bnm1.c sqrmod_bnm1.c	\
+  mulmid.c mulmid_n.c toom42_mulmid.c sqrlo.c sqrlo_basecase.c		\
+  nussbaumer_mul.c toom6h_mul.c toom8h_mul.c toom6_sqr.c toom8_sqr.c	\
+  toom22_mul.c toom2_sqr.c toom33_mul.c toom3_sqr.c toom44_mul.c toom4_sqr.c
+
+$(TUNE_MPN_SRCS_BASIC):
+	for i in $(TUNE_MPN_SRCS_BASIC); do \
+	  echo "#define TUNE_PROGRAM_BUILD 1" >$$i; \
+	  echo "#include \"mpn/generic/$$i\"" >>$$i; \
+	done
+
+divrem_1.c:
+	echo "#define TUNE_PROGRAM_BUILD 1"                >divrem_1.c
+	echo "#define __gmpn_divrem_1  mpn_divrem_1_tune" >>divrem_1.c
+	echo "#include \"mpn/generic/divrem_1.c\""        >>divrem_1.c
+
+mod_1.c:
+	echo "#define TUNE_PROGRAM_BUILD 1"          >mod_1.c
+	echo "#define __gmpn_mod_1  mpn_mod_1_tune" >>mod_1.c
+	echo "#include \"mpn/generic/mod_1.c\""     >>mod_1.c
+
+sqr_asm.asm: $(top_builddir)/mpn/sqr_basecase.asm
+	echo 'define(SQR_TOOM2_THRESHOLD_OVERRIDE,SQR_TOOM2_THRESHOLD_MAX)' >sqr_asm.asm
+	echo 'include(../mpn/sqr_basecase.asm)' >>sqr_asm.asm
+
+# FIXME: Should it depend on $(top_builddir)/fac_ui.h too?
+fac_ui.c: $(top_builddir)/mpz/fac_ui.c
+	echo "#define TUNE_PROGRAM_BUILD 1"          >fac_ui.c
+	echo "#define __gmpz_fac_ui mpz_fac_ui_tune" >>fac_ui.c
+	echo "#define __gmpz_oddfac_1 mpz_oddfac_1_tune" >>fac_ui.c
+	echo "#include \"mpz/oddfac_1.c\""           >>fac_ui.c
+	echo "#include \"mpz/fac_ui.c\""             >>fac_ui.c
+
+include ../mpn/Makeasm.am
+
+.NOTPARALLEL:
+
diff --git a/third_party/gmp/tune/Makefile.in b/third_party/gmp/tune/Makefile.in
new file mode 100644
index 0000000..e8eb56c
--- /dev/null
+++ b/third_party/gmp/tune/Makefile.in
@@ -0,0 +1,956 @@
+# Makefile.in generated by automake 1.15 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Copyright 2000-2003, 2005-2011 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+# Copyright 1996, 1998-2002 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+EXTRA_PROGRAMS = speed$(EXEEXT) speed-dynamic$(EXEEXT) \
+	speed-ext$(EXEEXT) tuneup$(EXEEXT) tune-gcd-p$(EXEEXT)
+subdir = tune
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+	$(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__DEPENDENCIES_1 =
+am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) \
+	$(top_builddir)/tests/libtests.la $(top_builddir)/libgmp.la
+am_libspeed_la_OBJECTS = common.lo divrem1div.lo divrem1inv.lo \
+	divrem2div.lo divrem2inv.lo div_qr_1n_pi1_1.lo \
+	div_qr_1n_pi1_2.lo div_qr_1_tune.lo freq.lo gcdext_single.lo \
+	gcdext_double.lo gcdextod.lo gcdextos.lo hgcd_lehmer.lo \
+	hgcd_appr_lehmer.lo hgcd_reduce_1.lo hgcd_reduce_2.lo \
+	jacbase1.lo jacbase2.lo jacbase3.lo jacbase4.lo hgcd2-1.lo \
+	hgcd2-2.lo hgcd2-3.lo hgcd2-4.lo hgcd2-5.lo mod_1_div.lo \
+	mod_1_inv.lo mod_1_1-1.lo mod_1_1-2.lo modlinv.lo noop.lo \
+	powm_mod.lo powm_redc.lo pre_divrem_1.lo set_strb.lo \
+	set_strs.lo set_strp.lo time.lo
+libspeed_la_OBJECTS = $(am_libspeed_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+libspeed_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(libspeed_la_LDFLAGS) $(LDFLAGS) -o $@
+am_speed_OBJECTS = speed.$(OBJEXT)
+speed_OBJECTS = $(am_speed_OBJECTS)
+speed_LDADD = $(LDADD)
+speed_DEPENDENCIES = $(DEPENDENCIES) $(am__DEPENDENCIES_1)
+speed_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(speed_LDFLAGS) $(LDFLAGS) -o $@
+am_speed_dynamic_OBJECTS = speed.$(OBJEXT)
+speed_dynamic_OBJECTS = $(am_speed_dynamic_OBJECTS)
+speed_dynamic_LDADD = $(LDADD)
+speed_dynamic_DEPENDENCIES = $(DEPENDENCIES) $(am__DEPENDENCIES_1)
+am_speed_ext_OBJECTS = speed-ext.$(OBJEXT)
+speed_ext_OBJECTS = $(am_speed_ext_OBJECTS)
+speed_ext_LDADD = $(LDADD)
+speed_ext_DEPENDENCIES = $(DEPENDENCIES) $(am__DEPENDENCIES_1)
+speed_ext_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(speed_ext_LDFLAGS) $(LDFLAGS) -o $@
+am_tune_gcd_p_OBJECTS = tune-gcd-p.$(OBJEXT)
+tune_gcd_p_OBJECTS = $(am_tune_gcd_p_OBJECTS)
+tune_gcd_p_LDADD = $(LDADD)
+tune_gcd_p_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(tune_gcd_p_LDFLAGS) $(LDFLAGS) -o $@
+am_tuneup_OBJECTS = tuneup.$(OBJEXT) hgcd2.$(OBJEXT)
+am__objects_1 = div_qr_2.$(OBJEXT) bdiv_q.$(OBJEXT) bdiv_qr.$(OBJEXT) \
+	dcpi1_div_qr.$(OBJEXT) dcpi1_divappr_q.$(OBJEXT) \
+	dcpi1_bdiv_qr.$(OBJEXT) dcpi1_bdiv_q.$(OBJEXT) \
+	invertappr.$(OBJEXT) invert.$(OBJEXT) binvert.$(OBJEXT) \
+	divrem_2.$(OBJEXT) gcd.$(OBJEXT) gcdext.$(OBJEXT) \
+	get_str.$(OBJEXT) set_str.$(OBJEXT) matrix22_mul.$(OBJEXT) \
+	hgcd.$(OBJEXT) hgcd_appr.$(OBJEXT) hgcd_reduce.$(OBJEXT) \
+	mul_n.$(OBJEXT) sqr.$(OBJEXT) sec_powm.$(OBJEXT) \
+	mullo_n.$(OBJEXT) mul_fft.$(OBJEXT) mul.$(OBJEXT) \
+	tdiv_qr.$(OBJEXT) mulmod_bnm1.$(OBJEXT) sqrmod_bnm1.$(OBJEXT) \
+	mulmid.$(OBJEXT) mulmid_n.$(OBJEXT) toom42_mulmid.$(OBJEXT) \
+	sqrlo.$(OBJEXT) sqrlo_basecase.$(OBJEXT) \
+	nussbaumer_mul.$(OBJEXT) toom6h_mul.$(OBJEXT) \
+	toom8h_mul.$(OBJEXT) toom6_sqr.$(OBJEXT) toom8_sqr.$(OBJEXT) \
+	toom22_mul.$(OBJEXT) toom2_sqr.$(OBJEXT) toom33_mul.$(OBJEXT) \
+	toom3_sqr.$(OBJEXT) toom44_mul.$(OBJEXT) toom4_sqr.$(OBJEXT)
+am__objects_2 = $(am__objects_1) divrem_1.$(OBJEXT) mod_1.$(OBJEXT)
+nodist_tuneup_OBJECTS = sqr_basecase.$(OBJEXT) fac_ui.$(OBJEXT) \
+	$(am__objects_2)
+tuneup_OBJECTS = $(am_tuneup_OBJECTS) $(nodist_tuneup_OBJECTS)
+am__DEPENDENCIES_3 = $(am__DEPENDENCIES_1) libspeed.la
+tuneup_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(tuneup_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp =
+am__depfiles_maybe =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+SOURCES = $(libspeed_la_SOURCES) $(speed_SOURCES) \
+	$(speed_dynamic_SOURCES) $(speed_ext_SOURCES) \
+	$(tune_gcd_p_SOURCES) $(tuneup_SOURCES) \
+	$(nodist_tuneup_SOURCES)
+DIST_SOURCES = $(libspeed_la_SOURCES) $(speed_SOURCES) \
+	$(speed_dynamic_SOURCES) $(speed_ext_SOURCES) \
+	$(tune_gcd_p_SOURCES) $(tuneup_SOURCES)
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/../mpn/Makeasm.am $(srcdir)/Makefile.in \
+	README
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ABI = @ABI@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+ASMFLAGS = @ASMFLAGS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CALLING_CONVENTIONS_OBJS = @CALLING_CONVENTIONS_OBJS@
+CC = @CC@
+CCAS = @CCAS@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPP_FOR_BUILD = @CPP_FOR_BUILD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFN_LONG_LONG_LIMB = @DEFN_LONG_LONG_LIMB@
+DEFS = @DEFS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXEEXT_FOR_BUILD = @EXEEXT_FOR_BUILD@
+FGREP = @FGREP@
+GMP_LDFLAGS = @GMP_LDFLAGS@
+GMP_LIMB_BITS = @GMP_LIMB_BITS@
+GMP_NAIL_BITS = @GMP_NAIL_BITS@
+GREP = @GREP@
+HAVE_CLOCK_01 = @HAVE_CLOCK_01@
+HAVE_CPUTIME_01 = @HAVE_CPUTIME_01@
+HAVE_GETRUSAGE_01 = @HAVE_GETRUSAGE_01@
+HAVE_GETTIMEOFDAY_01 = @HAVE_GETTIMEOFDAY_01@
+HAVE_HOST_CPU_FAMILY_power = @HAVE_HOST_CPU_FAMILY_power@
+HAVE_HOST_CPU_FAMILY_powerpc = @HAVE_HOST_CPU_FAMILY_powerpc@
+HAVE_SIGACTION_01 = @HAVE_SIGACTION_01@
+HAVE_SIGALTSTACK_01 = @HAVE_SIGALTSTACK_01@
+HAVE_SIGSTACK_01 = @HAVE_SIGSTACK_01@
+HAVE_STACK_T_01 = @HAVE_STACK_T_01@
+HAVE_SYS_RESOURCE_H_01 = @HAVE_SYS_RESOURCE_H_01@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCURSES = @LIBCURSES@
+LIBGMPXX_LDFLAGS = @LIBGMPXX_LDFLAGS@
+LIBGMP_DLL = @LIBGMP_DLL@
+LIBGMP_LDFLAGS = @LIBGMP_LDFLAGS@
+LIBM = @LIBM@
+LIBM_FOR_BUILD = @LIBM_FOR_BUILD@
+LIBOBJS = @LIBOBJS@
+LIBREADLINE = @LIBREADLINE@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+M4 = @M4@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SPEED_CYCLECOUNTER_OBJ = @SPEED_CYCLECOUNTER_OBJ@
+STRIP = @STRIP@
+TAL_OBJECT = @TAL_OBJECT@
+TUNE_LIBS = @TUNE_LIBS@
+TUNE_SQR_OBJ = @TUNE_SQR_OBJ@
+U_FOR_BUILD = @U_FOR_BUILD@
+VERSION = @VERSION@
+WITH_READLINE_01 = @WITH_READLINE_01@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__leading_dot = @am__leading_dot@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gmp_srclinks = @gmp_srclinks@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+mpn_objects = @mpn_objects@
+mpn_objs_in_libgmp = @mpn_objs_in_libgmp@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/tests
+AM_LDFLAGS = -no-install
+EXTRA_DIST = alpha.asm pentium.asm sparcv9.asm hppa.asm hppa2.asm hppa2w.asm \
+  ia64.asm powerpc.asm powerpc64.asm x86_64.asm many.pl
+
+noinst_HEADERS = speed.h
+@ENABLE_STATIC_FALSE@STATIC = 
+
+# Prefer -static on the speed and tune programs, since that can avoid
+# overheads of shared library linkages on some systems.  Libtool tends to
+# botch -static if configured with --disable-static, perhaps reasonably
+# enough.  In any event under --disable-static the only choice is a dynamic
+# link so there's no point in -static.
+#
+@ENABLE_STATIC_TRUE@STATIC = -static
+EXTRA_LTLIBRARIES = libspeed.la
+libspeed_la_SOURCES = \
+  common.c divrem1div.c divrem1inv.c divrem2div.c divrem2inv.c		\
+  div_qr_1n_pi1_1.c div_qr_1n_pi1_2.c div_qr_1_tune.c			\
+  freq.c								\
+  gcdext_single.c gcdext_double.c gcdextod.c gcdextos.c			\
+  hgcd_lehmer.c hgcd_appr_lehmer.c hgcd_reduce_1.c hgcd_reduce_2.c	\
+  jacbase1.c jacbase2.c jacbase3.c jacbase4.c				\
+  hgcd2-1.c hgcd2-2.c hgcd2-3.c hgcd2-4.c hgcd2-5.c			\
+  mod_1_div.c mod_1_inv.c mod_1_1-1.c mod_1_1-2.c modlinv.c		\
+  noop.c powm_mod.c powm_redc.c pre_divrem_1.c				\
+  set_strb.c set_strs.c set_strp.c time.c
+
+libspeed_la_DEPENDENCIES = $(SPEED_CYCLECOUNTER_OBJ) \
+  $(top_builddir)/tests/libtests.la $(top_builddir)/libgmp.la
+
+libspeed_la_LIBADD = $(libspeed_la_DEPENDENCIES) $(LIBM)
+libspeed_la_LDFLAGS = $(STATIC)
+DEPENDENCIES = libspeed.la
+LDADD = $(DEPENDENCIES) $(TUNE_LIBS)
+speed_SOURCES = speed.c
+speed_LDFLAGS = $(STATIC)
+speed_dynamic_SOURCES = speed.c
+speed_ext_SOURCES = speed-ext.c
+speed_ext_LDFLAGS = $(STATIC)
+tuneup_SOURCES = tuneup.c hgcd2.c
+nodist_tuneup_SOURCES = sqr_basecase.c fac_ui.c $(TUNE_MPN_SRCS)
+tuneup_DEPENDENCIES = $(TUNE_SQR_OBJ) libspeed.la
+tuneup_LDADD = $(tuneup_DEPENDENCIES) $(TUNE_LIBS)
+tuneup_LDFLAGS = $(STATIC)
+tune_gcd_p_SOURCES = tune-gcd-p.c
+tune_gcd_p_DEPENDENCIES = ../mpn/gcd.c
+tune_gcd_p_LDFLAGS = $(STATIC)
+
+# $(MANY_CLEAN) and $(MANY_DISTCLEAN) are hooks for many.pl
+CLEANFILES = $(EXTRA_PROGRAMS) $(EXTRA_LTLIBRARIES) \
+	$(TUNE_MPN_SRCS) fac_ui.c sqr_asm.asm \
+	stg.gnuplot stg.data \
+	mtg.gnuplot mtg.data \
+	fibg.gnuplot fibg.data \
+	graph.gnuplot graph.data \
+	$(MANY_CLEAN)
+
+DISTCLEANFILES = sqr_basecase.c  $(MANY_DISTCLEAN)
+
+# Generating these little files at build time seems better than including
+# them in the distribution, since the list can be changed more easily.
+#
+# mpn/generic/tdiv_qr.c uses mpn_divrem_1 and mpn_divrem_2, but only for 1
+# and 2 limb divisors, which are never used during tuning, so it doesn't
+# matter whether it picks up a tuned or untuned version of those.
+#
+# divrem_1 and mod_1 are recompiled renamed to "_tune" to avoid a linking
+# problem.  If a native divrem_1 provides an mpn_divrem_1c entrypoint then
+# common.c will want that, but the generic divrem_1 doesn't provide it,
+# likewise for mod_1.  The simplest way around this is to have the tune
+# build versions renamed suitably.
+#
+# FIXME: Would like say mul_n.c to depend on $(top_builddir)/mul_n.c so the
+# recompiled object will be rebuilt if that file changes.
+TUNE_MPN_SRCS = $(TUNE_MPN_SRCS_BASIC) divrem_1.c mod_1.c
+TUNE_MPN_SRCS_BASIC = div_qr_2.c bdiv_q.c bdiv_qr.c			\
+  dcpi1_div_qr.c dcpi1_divappr_q.c dcpi1_bdiv_qr.c dcpi1_bdiv_q.c	\
+  invertappr.c invert.c binvert.c divrem_2.c gcd.c gcdext.c		\
+  get_str.c set_str.c matrix22_mul.c					\
+  hgcd.c hgcd_appr.c hgcd_reduce.c					\
+  mul_n.c sqr.c sec_powm.c						\
+  mullo_n.c mul_fft.c mul.c tdiv_qr.c mulmod_bnm1.c sqrmod_bnm1.c	\
+  mulmid.c mulmid_n.c toom42_mulmid.c sqrlo.c sqrlo_basecase.c		\
+  nussbaumer_mul.c toom6h_mul.c toom8h_mul.c toom6_sqr.c toom8_sqr.c	\
+  toom22_mul.c toom2_sqr.c toom33_mul.c toom3_sqr.c toom44_mul.c toom4_sqr.c
+
+
+# COMPILE minus CC.
+#
+COMPILE_FLAGS = $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) $(ASMFLAGS)
+
+
+# Flags used for preprocessing (in ansi2knr rules).
+#
+PREPROCESS_FLAGS = $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS)
+
+
+# Recent versions of automake (1.5 and up for instance) append automake
+# generated suffixes to this $(SUFFIXES) list.  This is essential for us,
+# since .c must come after .s, .S and .asm.  If .c is before .s, for
+# instance, then in the mpn directory "make" will see add_n.c mentioned in
+# an explicit rule (the ansi2knr stuff) and decide it must have add_n.c,
+# even if add_n.c doesn't exist but add_n.s does.  See GNU make
+# documentation "(make)Implicit Rule Search", part 5c.
+#
+# On IRIX 6 native make this doesn't work properly though.  Somehow .c
+# remains ahead of .s, perhaps because .c.s is a builtin rule.  .asm works
+# fine though, and mpn/mips3 uses this.
+#
+SUFFIXES = .s .S .asm
+
+# can be overridden during development, eg. "make RM_TMP=: mul_1.lo"
+RM_TMP = rm -f
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .s .S .asm .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/../mpn/Makeasm.am $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu --ignore-deps tune/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu --ignore-deps tune/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+$(srcdir)/../mpn/Makeasm.am $(am__empty):
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+libspeed.la: $(libspeed_la_OBJECTS) $(libspeed_la_DEPENDENCIES) $(EXTRA_libspeed_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(libspeed_la_LINK)  $(libspeed_la_OBJECTS) $(libspeed_la_LIBADD) $(LIBS)
+
+speed$(EXEEXT): $(speed_OBJECTS) $(speed_DEPENDENCIES) $(EXTRA_speed_DEPENDENCIES) 
+	@rm -f speed$(EXEEXT)
+	$(AM_V_CCLD)$(speed_LINK) $(speed_OBJECTS) $(speed_LDADD) $(LIBS)
+
+speed-dynamic$(EXEEXT): $(speed_dynamic_OBJECTS) $(speed_dynamic_DEPENDENCIES) $(EXTRA_speed_dynamic_DEPENDENCIES) 
+	@rm -f speed-dynamic$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(speed_dynamic_OBJECTS) $(speed_dynamic_LDADD) $(LIBS)
+
+speed-ext$(EXEEXT): $(speed_ext_OBJECTS) $(speed_ext_DEPENDENCIES) $(EXTRA_speed_ext_DEPENDENCIES) 
+	@rm -f speed-ext$(EXEEXT)
+	$(AM_V_CCLD)$(speed_ext_LINK) $(speed_ext_OBJECTS) $(speed_ext_LDADD) $(LIBS)
+
+tune-gcd-p$(EXEEXT): $(tune_gcd_p_OBJECTS) $(tune_gcd_p_DEPENDENCIES) $(EXTRA_tune_gcd_p_DEPENDENCIES) 
+	@rm -f tune-gcd-p$(EXEEXT)
+	$(AM_V_CCLD)$(tune_gcd_p_LINK) $(tune_gcd_p_OBJECTS) $(tune_gcd_p_LDADD) $(LIBS)
+
+tuneup$(EXEEXT): $(tuneup_OBJECTS) $(tuneup_DEPENDENCIES) $(EXTRA_tuneup_DEPENDENCIES) 
+	@rm -f tuneup$(EXEEXT)
+	$(AM_V_CCLD)$(tuneup_LINK) $(tuneup_OBJECTS) $(tuneup_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+.c.o:
+	$(AM_V_CC)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+	$(AM_V_CC)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+	$(AM_V_CC)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: check-am
+all-am: Makefile $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+	-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+	-test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+	clean-libtool cscopelist-am ctags ctags-am distclean \
+	distclean-compile distclean-generic distclean-libtool \
+	distclean-tags distdir dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am install-man \
+	install-pdf install-pdf-am install-ps install-ps-am \
+	install-strip installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+	pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+$(top_builddir)/tests/libtests.la:
+	cd $(top_builddir)/tests; $(MAKE) $(AM_MAKEFLAGS) libtests.la
+
+tune:
+	$(MAKE) $(AM_MAKEFLAGS) tuneup$(EXEEXT)
+	./tuneup
+
+allprogs: $(EXTRA_PROGRAMS)
+
+$(TUNE_MPN_SRCS_BASIC):
+	for i in $(TUNE_MPN_SRCS_BASIC); do \
+	  echo "#define TUNE_PROGRAM_BUILD 1" >$$i; \
+	  echo "#include \"mpn/generic/$$i\"" >>$$i; \
+	done
+
+divrem_1.c:
+	echo "#define TUNE_PROGRAM_BUILD 1"                >divrem_1.c
+	echo "#define __gmpn_divrem_1  mpn_divrem_1_tune" >>divrem_1.c
+	echo "#include \"mpn/generic/divrem_1.c\""        >>divrem_1.c
+
+mod_1.c:
+	echo "#define TUNE_PROGRAM_BUILD 1"          >mod_1.c
+	echo "#define __gmpn_mod_1  mpn_mod_1_tune" >>mod_1.c
+	echo "#include \"mpn/generic/mod_1.c\""     >>mod_1.c
+
+sqr_asm.asm: $(top_builddir)/mpn/sqr_basecase.asm
+	echo 'define(SQR_TOOM2_THRESHOLD_OVERRIDE,SQR_TOOM2_THRESHOLD_MAX)' >sqr_asm.asm
+	echo 'include(../mpn/sqr_basecase.asm)' >>sqr_asm.asm
+
+# FIXME: Should it depend on $(top_builddir)/fac_ui.h too?
+fac_ui.c: $(top_builddir)/mpz/fac_ui.c
+	echo "#define TUNE_PROGRAM_BUILD 1"          >fac_ui.c
+	echo "#define __gmpz_fac_ui mpz_fac_ui_tune" >>fac_ui.c
+	echo "#define __gmpz_oddfac_1 mpz_oddfac_1_tune" >>fac_ui.c
+	echo "#include \"mpz/oddfac_1.c\""           >>fac_ui.c
+	echo "#include \"mpz/fac_ui.c\""             >>fac_ui.c
+
+# .s assembler, no preprocessing.
+#
+.s.o:
+	$(CCAS) $(COMPILE_FLAGS) `test -f '$<' || echo '$(srcdir)/'`$<
+.s.obj:
+	$(CCAS) $(COMPILE_FLAGS) `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi`
+.s.lo:
+	$(LIBTOOL) --mode=compile --tag=CC $(CCAS) $(COMPILE_FLAGS) `test -f '$<' || echo '$(srcdir)/'`$<
+
+# .S assembler, preprocessed with cpp.
+#
+# It's necessary to run $(CPP) separately, since it seems not all compilers
+# recognise .S files, in particular "cc" on HP-UX 10 and 11 doesn't (and
+# will silently do nothing if given a .S).
+#
+# For .lo we need a helper script, as described below for .asm.lo.
+#
+.S.o:
+	$(CPP) $(PREPROCESS_FLAGS) `test -f '$<' || echo '$(srcdir)/'`$< | grep -v '^#' >tmp-$*.s
+	$(CCAS) $(COMPILE_FLAGS) tmp-$*.s -o $@
+	$(RM_TMP) tmp-$*.s
+.S.obj:
+	$(CPP) $(PREPROCESS_FLAGS) `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi` | grep -v '^#' >tmp-$*.s
+	$(CCAS) $(COMPILE_FLAGS) tmp-$*.s -o $@
+	$(RM_TMP) tmp-$*.s
+.S.lo:
+	$(LIBTOOL) --mode=compile --tag=CC $(top_srcdir)/mpn/cpp-ccas --cpp="$(CPP) $(PREPROCESS_FLAGS)" $(CCAS) $(COMPILE_FLAGS) `test -f '$<' || echo '$(srcdir)/'`$<
+
+# .asm assembler, preprocessed with m4.
+#
+# .o and .obj are non-PIC and just need m4 followed by a compile.
+#
+# .lo is a bit tricky.  Libtool (as of version 1.5) has foo.lo as a little
+# text file, and .libs/foo.o and foo.o as the PIC and non-PIC objects,
+# respectively.  It'd be asking for lots of trouble to try to create foo.lo
+# ourselves, so instead arrange to invoke libtool like a --mode=compile, but
+# with a special m4-ccas script which first m4 preprocesses, then compiles.
+# --tag=CC is necessary since foo.asm is otherwise unknown to libtool.
+#
+# Libtool adds -DPIC when building a shared object and the .asm files look
+# for that.  But it should be noted that the other PIC flags are on occasion
+# important too, in particular FreeBSD 2.2.8 gas 1.92.3 requires -k before
+# it accepts PIC constructs like @GOT, and gcc adds that flag only under
+# -fPIC.  (Later versions of gas are happy to accept PIC stuff any time.)
+#
+.asm.o:
+	$(M4) -DOPERATION_$* `test -f '$<' || echo '$(srcdir)/'`$< >tmp-$*.s
+	$(CCAS) $(COMPILE_FLAGS) tmp-$*.s -o $@
+	$(RM_TMP) tmp-$*.s
+.asm.obj:
+	$(M4) -DOPERATION_$* `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi` >tmp-$*.s
+	$(CCAS) $(COMPILE_FLAGS) tmp-$*.s -o $@
+	$(RM_TMP) tmp-$*.s
+.asm.lo:
+	$(LIBTOOL) --mode=compile --tag=CC $(top_srcdir)/mpn/m4-ccas --m4="$(M4)" $(CCAS) $(COMPILE_FLAGS) `test -f '$<' || echo '$(srcdir)/'`$<
+
+.NOTPARALLEL:
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/third_party/gmp/tune/README b/third_party/gmp/tune/README
new file mode 100644
index 0000000..f76407f
--- /dev/null
+++ b/third_party/gmp/tune/README
@@ -0,0 +1,501 @@
+Copyright 2000-2002, 2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.
+
+
+
+
+
+               GMP SPEED MEASURING AND PARAMETER TUNING
+
+
+The programs in this directory are for knowledgeable users who want to
+measure GMP routines on their machine, and perhaps tweak some settings or
+identify things that can be improved.
+
+The programs here are tools, not ready to run solutions.  Nothing is built
+in a normal "make all", but various Makefile targets described below exist.
+
+Relatively few systems and CPUs have been tested, so be sure to verify that
+results are sensible before relying on them.
+
+
+
+
+MISCELLANEOUS NOTES
+
+--enable-assert
+
+    Don't configure with --enable-assert, since the extra code added by
+    assertion checking may influence measurements.
+
+Direct mapped caches
+
+    Some effort has been made to accommodate CPUs with direct mapped caches,
+    by putting data blocks more or less contiguously on the stack.  But this
+    will depend on TMP_ALLOC using alloca, and even then it may or may not
+    be enough.
+
+FreeBSD 4.2 i486 getrusage
+
+    This getrusage seems to be a bit doubtful, it looks like it's
+    microsecond accurate, but sometimes ru_utime remains unchanged after a
+    time of many microseconds has elapsed.  It'd be good to detect this in
+    the time.c initializations, but for now the suggestion is to pretend it
+    doesn't exist.
+
+        ./configure ac_cv_func_getrusage=no
+
+NetBSD 1.4.1 m68k macintosh time base
+
+    On this system it's been found getrusage often goes backwards, making it
+    unusable (time.c getrusage_backwards_p detects this).  gettimeofday
+    sometimes doesn't update atomically when it crosses a 1 second boundary.
+    Not sure what to do about this.  Expect possible intermittent failures.
+
+SCO OpenUNIX 8 /etc/hw
+
+    /etc/hw takes about a second to return the cpu frequency, which suggests
+    perhaps it's measuring each time it runs.  If this is annoying when
+    running the speed program repeatedly then set a GMP_CPU_FREQUENCY
+    environment variable (see TIME BASE section below).
+
+Timing on GNU/Linux
+
+    On Linux, timing currently uses the cycle counter. This is unreliable,
+    since the counter is not saved and restored at context switches (unlike
+    FreeBSD and Solaris where the cycle counter is "virtualized").
+
+    Using the clock_gettime method with CLOCK_PROCESS_CPUTIME_ID (posix) or
+    CLOCK_VIRTUAL (BSD) should be more reliable. To get clock_gettime
+    with glibc, one has to link with -lrt (which also drags in the pthreads
+    threading library). configure.in must be hacked to detect this and
+    arrange proper linking. Something like
+
+      old_LIBS="$LIBS"
+      AC_SEARCH_LIBS(clock_gettime, rt, [AC_DEFINE(HAVE_CLOCK_GETTIME)])
+      TUNE_LIBS="$LIBS"
+      LIBS="$old_LIBS"
+
+      AC_SUBST(TUNE_LIBS)
+
+    might work.
+
+Low resolution timebase
+
+    Parameter tuning can be very time consuming if the only timebase
+    available is a 10 millisecond clock tick, to the point of being
+    unusable.  This is currently the case on VAX and ARM systems.
+
+
+
+
+PARAMETER TUNING
+
+The "tuneup" program runs some tests designed to find the best settings for
+various thresholds, like MUL_TOOM22_THRESHOLD.  Its output can be put
+into gmp-mparam.h.  The program is built and run with
+
+        make tune
+
+If the thresholds indicated are grossly different from the values in the
+selected gmp-mparam.h then there may be a performance boost in applicable
+size ranges by changing gmp-mparam.h accordingly.
+
+Be sure to do a full reconfigure and rebuild to get any newly set thresholds
+to take effect.  A partial rebuild is enough sometimes, but a fresh
+configure and make is certain to be correct.
+
+If a CPU has specific tuned parameters coming from a gmp-mparam.h in one of
+the mpn subdirectories then the values from "make tune" should be similar.
+But check that the configured CPU is right and there are no machine specific
+effects causing a difference.
+
+It's hoped the compiler and options used won't have too much effect on
+thresholds, since for most CPUs they ultimately come down to comparisons
+between assembler subroutines.  Missing out on the longlong.h macros by not
+using gcc will probably have an effect.
+
+Some thresholds produced by the tune program are merely single values chosen
+from what's a range of sizes where two algorithms are pretty much the same
+speed.  When this happens the program is likely to give somewhat different
+values on successive runs.  This is noticeable on the toom3 thresholds for
+instance.
+
+
+
+
+SPEED PROGRAM
+
+The "speed" program can be used for measuring and comparing various
+routines, and producing tables of data or gnuplot graphs.  Compile it with
+
+	make speed
+
+(Or on DOS systems "make speed.exe".)
+
+Here are some examples of how to use it.  Check the code for all the
+options.
+
+Draw a graph of mpn_mul_n, stepping through sizes by 10 or a factor of 1.05
+(whichever is greater).
+
+        ./speed -s 10-5000 -t 10 -f 1.05 -P foo mpn_mul_n
+	gnuplot foo.gnuplot
+
+Compare mpn_add_n and an mpn_lshift by 1, showing times in cycles and
+showing under mpn_lshift the difference between it and mpn_add_n.
+
+	./speed -s 1-40 -c -d mpn_add_n mpn_lshift.1
+
+Using option -c for times in cycles is interesting but normally only
+necessary when looking carefully at assembler subroutines.  You might think
+it would always give an integer value, but this doesn't happen in practice,
+probably due to overheads in the time measurements.
+
+In the free-form output the "#" symbol against a measurement means the
+corresponding routine is fastest at that size.  This is a convenient visual
+cue when comparing different routines.  The graph data files <name>.data
+don't get this since it would upset gnuplot or other data viewers.
+
+
+
+
+TIME BASE
+
+The time measuring method is determined in time.c, based on what the
+configured host has available.  A cycle counter is preferred, possibly
+supplemented by another method if the counter has a limited range.  A
+microsecond accurate getrusage() or gettimeofday() will work quite well too.
+
+The cycle counters (except possibly on alpha) and gettimeofday() will depend
+on the machine being otherwise idle, or rather on other jobs not stealing
+CPU time from the measuring program.  Short routines (those that complete
+within a timeslice) should work even on a busy machine.
+
+Some trouble is taken by speed_measure() in common.c to avoid ill effects
+from sporadic interrupts, or other intermittent things (like cron waking up
+every minute).  But generally an idle machine will be necessary to be
+certain of consistent results.
+
+The CPU frequency is needed to convert between cycles and seconds, or for
+when a cycle counter is supplemented by getrusage() etc.  The speed program
+will convert as necessary according to the output format requested.  The
+tune program will work with either cycles or seconds.
+
+freq.c knows how to get the frequency on some systems, or can measure a
+cycle counter against gettimeofday() or getrusage(), but when that fails, or
+needs to be overridden, an environment variable GMP_CPU_FREQUENCY can be
+used (in Hertz).  For example in "bash" on a 650 MHz machine,
+
+	export GMP_CPU_FREQUENCY=650e6
+
+A high precision time base makes it possible to get accurate measurements in
+a shorter time.
+
+
+
+
+EXAMPLE COMPARISONS - VARIOUS
+
+Here are some ideas for things that can be done with the speed program.
+
+There's always going to be a certain amount of overhead in the time
+measurements, due to reading the time base, and in the loop that runs a
+routine enough times to get a reading of the desired precision.  Noop
+functions taking various arguments are available to measure this.  The
+"overhead" printed by the speed program each time in its intro is the "noop"
+routine, but note that this is just for information, it isn't deducted from
+the times printed or anything.
+
+	./speed -s 1 noop noop_wxs noop_wxys
+
+To see how many cycles per limb a routine is taking, look at the time
+increase when the size increments, using option -D.  This avoids fixed
+overheads in the measuring.  Also, remember many of the assembler routines
+have unrolled loops, so it might be necessary to compare times at, say, 16,
+32, 48, 64 etc to see what the unrolled part is taking, as opposed to any
+finishing off.
+
+        ./speed -s 16-64 -t 16 -C -D mpn_add_n
+
+The -C option on its own gives cycles per limb, but is really only useful at
+big sizes where fixed overheads are small compared to the code doing the
+real work.  Remember of course memory caching and/or page swapping will
+affect results at large sizes.
+
+        ./speed -s 500000 -C mpn_add_n
+
+Once a calculation stops fitting in the CPU data cache, it's going to start
+taking longer.  Exactly where this happens depends on the cache priming in
+the measuring routines, and on what sort of "least recently used" the
+hardware does.  Here's an example for a CPU with a 16kbyte L1 data cache and
+32-bit limb, showing a suddenly steeper curve for mpn_add_n at about 2000
+limbs.
+
+        ./speed -s 1-4000 -t 5 -f 1.02 -P foo mpn_add_n
+	gnuplot foo.gnuplot
+
+When a routine has an unrolled loop for, say, multiples of 8 limbs and then
+an ordinary loop for the remainder, it can happen that it's actually faster
+to do an operation on, say, 8 limbs than it is on 7 limbs.  The following
+draws a graph of mpn_sub_n, to see whether times smoothly increase with
+size.
+
+        ./speed -s 1-100 -c -P foo mpn_sub_n
+	gnuplot foo.gnuplot
+
+If mpn_lshift and mpn_rshift have special case code for shifts by 1, it
+ought to be faster (or at least not slower) than shifting by, say, 2 bits.
+
+        ./speed -s 1-200 -c mpn_rshift.1 mpn_rshift.2
+
+An mpn_lshift by 1 can be done by mpn_add_n adding a number to itself, and
+if the lshift isn't faster there's an obvious improvement that's possible.
+
+        ./speed -s 1-200 -c mpn_lshift.1 mpn_add_n_self
+
+On some CPUs (AMD K6 for example) an "in-place" mpn_add_n where the
+destination is one of the sources is faster than a separate destination.
+Here's an example to see this.  ".1" selects dst==src1 for mpn_add_n (and
+mpn_sub_n), for other values see speed.h SPEED_ROUTINE_MPN_BINARY_N_CALL.
+
+        ./speed -s 1-200 -c mpn_add_n mpn_add_n.1
+
+The gmp manual points out that divisions by powers of two should be done
+using a right shift because it'll be significantly faster than an actual
+division.  The following shows by what factor mpn_rshift is faster than
+mpn_divrem_1, using division by 32 as an example.
+
+        ./speed -s 10-20 -r mpn_rshift.5 mpn_divrem_1.32
+
+
+
+
+EXAMPLE COMPARISONS - MULTIPLICATION
+
+mul_basecase takes a ".<r>" parameter. If positive, it gives the second
+(smaller) operand size.  For example to show speeds for 3x3 up to 20x3 in
+cycles,
+
+        ./speed -s 3-20 -c mpn_mul_basecase.3
+
+A negative ".<-r>" parameter fixes the size of the product to the absolute
+value r.  For example to show speeds for 10x10 up to 19x1 in cycles,
+
+        ./speed -s 10-19 -c mpn_mul_basecase.-20
+
+mul_basecase with no parameter does an NxN multiply, so for example to show
+speeds in cycles for 1x1, 2x2, 3x3, etc, up to 20x20, in cycles,
+
+        ./speed -s 1-20 -c mpn_mul_basecase
+
+sqr_basecase is implemented by a "triangular" method on most CPUs, making it
+up to twice as fast as mul_basecase.  In practice loop overheads and the
+products on the diagonal mean it falls short of this.  Here's an example
+running the two and showing by what factor an NxN mul_basecase is slower
+than an NxN sqr_basecase.  (Some versions of sqr_basecase only allow sizes
+below SQR_TOOM2_THRESHOLD, so if it crashes at that point don't worry.)
+
+        ./speed -s 1-20 -r mpn_sqr_basecase mpn_mul_basecase
+
+The technique described above with -CD for showing the time difference in
+cycles per limb between two size operations can be done on an NxN
+mul_basecase using -E to change the basis for the size increment to N*N.
+For instance a 20x20 operation is taken to be doing 400 limbs, and a 16x16
+doing 256 limbs.  The following therefore shows the per crossproduct speed
+of mul_basecase and sqr_basecase at around 20x20 limbs.
+
+        ./speed -s 16-20 -t 4 -CDE mpn_mul_basecase mpn_sqr_basecase
+
+Of course sqr_basecase isn't really doing NxN crossproducts, but it can be
+interesting to compare it to mul_basecase as if it was.  For sqr_basecase
+the -F option can be used to base the deltas on N*(N+1)/2 operations, which
+is the triangular products sqr_basecase does.  For example,
+
+        ./speed -s 16-20 -t 4 -CDF mpn_sqr_basecase
+
+Both -E and -F are preliminary and might change.  A consistent approach to
+using them when claiming certain per crossproduct or per triangularproduct
+speeds hasn't really been established, but the increment between speeds in
+the range karatsuba will call seems sensible, that being k to k/2.  For
+instance, if the karatsuba threshold was 20 for the multiply and 30 for the
+square,
+
+        ./speed -s 10-20 -t 10 -CDE mpn_mul_basecase
+        ./speed -s 15-30 -t 15 -CDF mpn_sqr_basecase
+
+
+
+EXAMPLE COMPARISONS - MALLOC
+
+The gmp manual recommends application programs avoid excessive initializing
+and clearing of mpz_t variables (and mpq_t and mpf_t too).  Every new
+variable will at a minimum go through an init, a realloc for its first
+store, and finally a clear.  Quite how long that takes depends on the C
+library.  The following compares an mpz_init/realloc/clear to a 10 limb
+mpz_add.  Don't be surprised if the mallocing is quite slow.
+
+        ./speed -s 10 -c mpz_init_realloc_clear mpz_add
+
+On some systems malloc and free are much slower when dynamic linked.  The
+speed-dynamic program can be used to see this.  For example the following
+measures malloc/free, first static then dynamic.
+
+        ./speed -s 10 -c malloc_free
+        ./speed-dynamic -s 10 -c malloc_free
+
+Of course a real world program has big problems if it's doing so many
+mallocs and frees that it gets slowed down by a dynamic linked malloc.
+
+
+
+
+
+EXAMPLE COMPARISONS - STRING CONVERSIONS
+
+mpn_get_str does a binary to string conversion.  The base is specified with
+a ".<r>" parameter, or decimal by default.  Power of 2 bases are much faster
+than general bases.  The following compares decimal and hex for instance.
+
+        ./speed -s 1-20 -c mpn_get_str mpn_get_str.16
+
+Smaller bases need more divisions to split a given size number, and so are
+slower.  The following compares base 3 and base 9.  On small operands 9 will
+be nearly twice as fast, though at bigger sizes this reduces since in the
+current implementation both divide repeatedly by 3^20 (or 3^40 for 64 bit
+limbs) and those divisions come to dominate.
+
+        ./speed -s 1-20 -cr mpn_get_str.3 mpn_get_str.9
+
+mpn_set_str does a string to binary conversion.  The base is specified with
+a ".<r>" parameter, or decimal by default.  Power of 2 bases are faster than
+general bases on large conversions.
+
+	./speed -s 1-512 -f 2 -c mpn_set_str.8 mpn_set_str.10
+
+mpn_set_str also has some special case code for decimal which is a bit
+faster than the general case, basically by giving the compiler a chance to
+optimize some multiplications by 10.
+
+	./speed -s 20-40 -c mpn_set_str.9 mpn_set_str.10 mpn_set_str.11
+
+
+
+
+EXAMPLE COMPARISONS - GCDs
+
+mpn_gcd_1 has a threshold for when to reduce using an initial x%y when both
+x and y are single limbs.  This isn't tuned currently, but a value can be
+established by a measurement like
+
+	./speed -s 10-32 mpn_gcd_1.10
+
+This runs src[0] from 10 to 32 bits, and y fixed at 10 bits.  If the div
+threshold is high, say 31 so it's effectively disabled then a 32x10 bit gcd
+is done by nibbling away at the 32-bit operands bit-by-bit.  When the
+threshold is small, say 1 bit, then an initial x%y is done to reduce it to a
+10x10 bit operation.
+
+The threshold in mpn/generic/gcd_1.c or the various assembler
+implementations can be tweaked up or down until there's no more speedups on
+interesting combinations of sizes.  Note that this affects only a 1x1 limb
+operation and so isn't very important.  (An Nx1 limb operation always does
+an initial modular reduction, using mpn_mod_1 or mpn_modexact_1_odd.)
+
+
+
+
+SPEED PROGRAM EXTENSIONS
+
+Potentially lots of things could be made available in the program, but it's
+been left at only the things that have actually been wanted and are likely
+to be reasonably useful in the future.
+
+Extensions should be fairly easy to make though.  speed-ext.c is an example,
+in a style that should suit one-off tests, or new code fragments under
+development.
+
+many.pl is a script for generating a new speed program supplemented with
+alternate versions of the standard routines.  It can be used for measuring
+experimental code, or for comparing different implementations that exist
+within a CPU family.
+
+
+
+
+THRESHOLD EXAMINING
+
+The speed program can be used to examine the speeds of different algorithms
+to check the tune program has done the right thing.  For example to examine
+the karatsuba multiply threshold,
+
+	./speed -s 5-40 mpn_mul_basecase mpn_kara_mul_n
+
+When examining the toom3 threshold, remember it depends on the karatsuba
+threshold, so the right karatsuba threshold needs to be compiled into the
+library first.  The tune program uses specially recompiled versions of
+mpn/mul_n.c etc for this reason, but the speed program simply uses the
+normal libgmp.la.
+
+Note further that the various routines may recurse into themselves on sizes
+far enough above applicable thresholds.  For example, mpn_kara_mul_n will
+recurse into itself on sizes greater than twice the compiled-in
+MUL_TOOM22_THRESHOLD.
+
+When doing the above comparison between mul_basecase and kara_mul_n what's
+probably of interest is mul_basecase versus a kara_mul_n that does one level
+of Karatsuba then calls to mul_basecase, but this only happens on sizes less
+than twice the compiled MUL_TOOM22_THRESHOLD.  A larger value for that
+setting can be compiled-in to avoid the problem if necessary.  The same
+applies to toom3 and DC, though in a trickier fashion.
+
+There are some upper limits on some of the thresholds, arising from arrays
+dimensioned according to a threshold (mpn_mul_n), or asm code with certain
+sized displacements (some x86 versions of sqr_basecase).  So putting huge
+values for the thresholds, even just for testing, may fail.
+
+
+
+
+FUTURE
+
+Make a program to check the time base is working properly, for small and
+large measurements.  Make it able to test each available method, including
+perhaps the apparent resolution of each.
+
+Make a general mechanism for specifying operand overlap, and a syntax like
+maybe "mpn_add_n.dst=src2" to select it.  Some measuring routines do this
+sort of thing with the "r" parameter currently.
+
+
+
+----------------
+Local variables:
+mode: text
+fill-column: 76
+End:
diff --git a/third_party/gmp/tune/alpha.asm b/third_party/gmp/tune/alpha.asm
new file mode 100644
index 0000000..888c77f
--- /dev/null
+++ b/third_party/gmp/tune/alpha.asm
@@ -0,0 +1,59 @@
+dnl  Alpha time stamp counter access routine.
+
+dnl  Copyright 2000, 2005 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C void speed_cyclecounter (unsigned int p[2]);
+C
+
+C The rpcc instruction returns a 64-bit value split into two 32-bit fields.
+C The lower 32 bits are set by the hardware, and the upper 32 bits are set
+C by the operating system.  The real per-process cycle count is the sum of
+C these halves.
+
+C Unfortunately, some operating systems don't get this right.  NetBSD 1.3 is
+C known to sometimes put garbage in the upper half.  Whether newer NetBSD
+C versions get it right, is unknown to us.
+
+C rpcc measures cycles elapsed in the user program and hence should be very
+C accurate even on a busy system.  Losing cache contents due to task
+C switching may have an effect though.
+
+ASM_START()
+PROLOGUE(speed_cyclecounter)
+	rpcc	r0
+	srl	r0,32,r1
+	addq	r1,r0,r0
+	stl	r0,0(r16)
+	stl	r31,4(r16)		C zero upper return word
+	ret	r31,(r26),1
+EPILOGUE(speed_cyclecounter)
+ASM_END()
diff --git a/third_party/gmp/tune/common.c b/third_party/gmp/tune/common.c
new file mode 100644
index 0000000..c8b17fc
--- /dev/null
+++ b/third_party/gmp/tune/common.c
@@ -0,0 +1,2852 @@
+/* Shared speed subroutines.
+
+Copyright 1999-2006, 2008-2017, 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define __GMP_NO_ATTRIBUTE_CONST_PURE
+
+#include <errno.h>
+#include <fcntl.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h> /* for qsort */
+#include <string.h>
+#include <unistd.h>
+#if 0
+#include <sys/ioctl.h>
+#endif
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#include "tests.h"
+#include "speed.h"
+
+
+int   speed_option_addrs = 0;
+int   speed_option_verbose = 0;
+int   speed_option_cycles_broken = 0;
+
+
+/* Provide __clz_tab even if it's not required, for the benefit of new code
+   being tested with many.pl. */
+#ifndef COUNT_LEADING_ZEROS_NEED_CLZ_TAB
+#define COUNT_LEADING_ZEROS_NEED_CLZ_TAB
+#include "mp_clz_tab.c"
+#undef COUNT_LEADING_ZEROS_NEED_CLZ_TAB
+#endif
+
+
+void
+pentium_wbinvd(void)
+{
+#if 0
+  {
+    static int  fd = -2;
+
+    if (fd == -2)
+      {
+	fd = open ("/dev/wbinvd", O_RDWR);
+	if (fd == -1)
+	  perror ("open /dev/wbinvd");
+      }
+
+    if (fd != -1)
+      ioctl (fd, 0, 0);
+  }
+#endif
+
+#if 0
+#define WBINVDSIZE  1024*1024*2
+  {
+    static char  *p = NULL;
+    int   i, sum;
+
+    if (p == NULL)
+      p = malloc (WBINVDSIZE);
+
+#if 0
+    for (i = 0; i < WBINVDSIZE; i++)
+      p[i] = i & 0xFF;
+#endif
+
+    sum = 0;
+    for (i = 0; i < WBINVDSIZE; i++)
+      sum += p[i];
+
+    mpn_cache_fill_dummy (sum);
+  }
+#endif
+}
+
+
+int
+double_cmp_ptr (const double *p, const double *q)
+{
+  if (*p > *q)  return 1;
+  if (*p < *q)  return -1;
+  return 0;
+}
+
+
+/* Measure the speed of a given routine.
+
+   The routine is run with enough repetitions to make it take at least
+   speed_precision * speed_unittime.  This aims to minimize the effects of a
+   limited accuracy time base and the overhead of the measuring itself.
+
+   Measurements are made looking for 4 results within TOLERANCE of each
+   other (or 3 for routines taking longer than 2 seconds).  This aims to get
+   an accurate reading even if some runs are bloated by interrupts or task
+   switches or whatever.
+
+   The given (*fun)() is expected to run its function "s->reps" many times
+   and return the total elapsed time measured using speed_starttime() and
+   speed_endtime().  If the function doesn't support the given s->size or
+   s->r, -1.0 should be returned.  See the various base routines below.  */
+
+double
+speed_measure (double (*fun) (struct speed_params *s), struct speed_params *s)
+{
+#define TOLERANCE    1.01  /* 1% */
+  const int max_zeros = 10;
+
+  struct speed_params  s_dummy;
+  int     i, j, e;
+  double  t[30];
+  double  t_unsorted[30];
+  double  reps_d;
+  int     zeros = 0;
+
+  /* Use dummy parameters if caller doesn't provide any.  Only a few special
+     "fun"s will cope with this, speed_noop() is one.  */
+  if (s == NULL)
+    {
+      memset (&s_dummy, '\0', sizeof (s_dummy));
+      s = &s_dummy;
+    }
+
+  s->reps = 1;
+  s->time_divisor = 1.0;
+  for (i = 0; i < numberof (t); i++)
+    {
+      for (;;)
+	{
+	  s->src_num = 0;
+	  s->dst_num = 0;
+
+	  t[i] = (*fun) (s);
+
+	  if (speed_option_verbose >= 3)
+	    gmp_printf("size=%ld reps=%u r=%Md attempt=%d  %.9f\n",
+		       (long) s->size, s->reps, s->r, i, t[i]);
+
+	  if (t[i] == 0.0)
+	    {
+	      zeros++;
+	      if (zeros > max_zeros)
+		{
+		  fprintf (stderr, "Fatal error: too many (%d) failed measurements (0.0)\n", zeros);
+		  abort ();
+		}
+	     if (s->reps < 10000)
+	       s->reps *= 2;
+
+	      continue;
+	    }
+
+	  if (t[i] == -1.0)
+	    return -1.0;
+
+	  if (t[i] >= speed_unittime * speed_precision)
+	    break;
+
+	  /* go to a value of reps to make t[i] >= precision */
+	  reps_d = ceil (1.1 * s->reps
+			 * speed_unittime * speed_precision
+			 / MAX (t[i], speed_unittime));
+	  if (reps_d > 2e9 || reps_d < 1.0)
+	    {
+	      fprintf (stderr, "Fatal error: new reps bad: %.2f\n", reps_d);
+	      fprintf (stderr, "  (old reps %u, unittime %.4g, precision %d, t[i] %.4g)\n",
+		       s->reps, speed_unittime, speed_precision, t[i]);
+	      abort ();
+	    }
+	  s->reps = (unsigned) reps_d;
+	}
+      t[i] /= s->reps;
+      t_unsorted[i] = t[i];
+
+      if (speed_precision == 0)
+	return t[i];
+
+      /* require 3 values within TOLERANCE when >= 2 secs, 4 when below */
+      if (t[0] >= 2.0)
+	e = 3;
+      else
+	e = 4;
+
+      /* Look for e many t[]'s within TOLERANCE of each other to consider a
+	 valid measurement.  Return smallest among them.  */
+      if (i >= e)
+	{
+	  qsort (t, i+1, sizeof(t[0]), (qsort_function_t) double_cmp_ptr);
+	  for (j = e-1; j < i; j++)
+	    if (t[j] <= t[j-e+1] * TOLERANCE)
+	      return t[j-e+1] / s->time_divisor;
+	}
+    }
+
+  fprintf (stderr, "speed_measure() could not get %d results within %.1f%%\n",
+	   e, (TOLERANCE-1.0)*100.0);
+  fprintf (stderr, "    unsorted         sorted\n");
+  fprintf (stderr, "  %.12f    %.12f    is about %.1f%%\n",
+	   t_unsorted[0]*(TOLERANCE-1.0), t[0]*(TOLERANCE-1.0),
+	   100*(TOLERANCE-1.0));
+  for (i = 0; i < numberof (t); i++)
+    fprintf (stderr, "  %.09f       %.09f\n", t_unsorted[i], t[i]);
+
+  return -1.0;
+}
+
+
+/* Read all of ptr,size to get it into the CPU memory cache.
+
+   A call to mpn_cache_fill_dummy() is used to make sure the compiler
+   doesn't optimize away the whole loop.  Using "volatile mp_limb_t sum"
+   would work too, but the function call means we don't rely on every
+   compiler actually implementing volatile properly.
+
+   mpn_cache_fill_dummy() is in a separate source file to stop gcc thinking
+   it can inline it.  */
+
+void
+mpn_cache_fill (mp_srcptr ptr, mp_size_t size)
+{
+  mp_limb_t  sum = 0;
+  mp_size_t  i;
+
+  for (i = 0; i < size; i++)
+    sum += ptr[i];
+
+  mpn_cache_fill_dummy(sum);
+}
+
+
+void
+mpn_cache_fill_write (mp_ptr ptr, mp_size_t size)
+{
+  mpn_cache_fill (ptr, size);
+
+#if 0
+  mpn_random (ptr, size);
+#endif
+
+#if 0
+  mp_size_t  i;
+
+  for (i = 0; i < size; i++)
+    ptr[i] = i;
+#endif
+}
+
+
+void
+speed_operand_src (struct speed_params *s, mp_ptr ptr, mp_size_t size)
+{
+  if (s->src_num >= numberof (s->src))
+    {
+      fprintf (stderr, "speed_operand_src: no room left in s->src[]\n");
+      abort ();
+    }
+  s->src[s->src_num].ptr = ptr;
+  s->src[s->src_num].size = size;
+  s->src_num++;
+}
+
+
+void
+speed_operand_dst (struct speed_params *s, mp_ptr ptr, mp_size_t size)
+{
+  if (s->dst_num >= numberof (s->dst))
+    {
+      fprintf (stderr, "speed_operand_dst: no room left in s->dst[]\n");
+      abort ();
+    }
+  s->dst[s->dst_num].ptr = ptr;
+  s->dst[s->dst_num].size = size;
+  s->dst_num++;
+}
+
+
+void
+speed_cache_fill (struct speed_params *s)
+{
+  static struct speed_params  prev;
+  int  i;
+
+  /* FIXME: need a better way to get the format string for a pointer */
+
+  if (speed_option_addrs)
+    {
+      int  different;
+
+      different = (s->dst_num != prev.dst_num || s->src_num != prev.src_num);
+      for (i = 0; i < s->dst_num; i++)
+	different |= (s->dst[i].ptr != prev.dst[i].ptr);
+      for (i = 0; i < s->src_num; i++)
+	different |= (s->src[i].ptr != prev.src[i].ptr);
+
+      if (different)
+	{
+	  if (s->dst_num != 0)
+	    {
+	      printf ("dst");
+	      for (i = 0; i < s->dst_num; i++)
+		printf (" %08lX", (unsigned long) s->dst[i].ptr);
+	      printf (" ");
+	    }
+
+	  if (s->src_num != 0)
+	    {
+	      printf ("src");
+	      for (i = 0; i < s->src_num; i++)
+		printf (" %08lX", (unsigned long) s->src[i].ptr);
+	      printf (" ");
+	    }
+	  printf ("  (cf sp approx %08lX)\n", (unsigned long) &different);
+
+	}
+
+      memcpy (&prev, s, sizeof(prev));
+    }
+
+  switch (s->cache) {
+  case 0:
+    for (i = 0; i < s->dst_num; i++)
+      mpn_cache_fill_write (s->dst[i].ptr, s->dst[i].size);
+    for (i = 0; i < s->src_num; i++)
+      mpn_cache_fill (s->src[i].ptr, s->src[i].size);
+    break;
+  case 1:
+    pentium_wbinvd();
+    break;
+  }
+}
+
+
+/* Miscellaneous options accepted by tune and speed programs under -o. */
+
+void
+speed_option_set (const char *s)
+{
+  int  n;
+
+  if (strcmp (s, "addrs") == 0)
+    {
+      speed_option_addrs = 1;
+    }
+  else if (strcmp (s, "verbose") == 0)
+    {
+      speed_option_verbose++;
+    }
+  else if (sscanf (s, "verbose=%d", &n) == 1)
+    {
+      speed_option_verbose = n;
+    }
+  else if (strcmp (s, "cycles-broken") == 0)
+    {
+      speed_option_cycles_broken = 1;
+    }
+  else
+    {
+      printf ("Unrecognised -o option: %s\n", s);
+      exit (1);
+    }
+}
+
+
+/* The following are basic speed running routines for various gmp functions.
+   Many are very similar and use speed.h macros.
+
+   Each routine allocates it's own destination space for the result of the
+   function, because only it can know what the function needs.
+
+   speed_starttime() and speed_endtime() are put tight around the code to be
+   measured.  Any setups are done outside the timed portion.
+
+   Each routine is responsible for its own cache priming.
+   speed_cache_fill() is a good way to do this, see examples in speed.h.
+   One cache priming possibility, for CPUs with write-allocate cache, and
+   functions that don't take too long, is to do one dummy call before timing
+   so as to cache everything that gets used.  But speed_measure() runs a
+   routine at least twice and will take the smaller time, so this might not
+   be necessary.
+
+   Data alignment will be important, for source, destination and temporary
+   workspace.  A routine can align its destination and workspace.  Programs
+   using the routines will ensure s->xp and s->yp are aligned.  Aligning
+   onto a CACHE_LINE_SIZE boundary is suggested.  s->align_wp and
+   s->align_wp2 should be respected where it makes sense to do so.
+   SPEED_TMP_ALLOC_LIMBS is a good way to do this.
+
+   A loop of the following form can be expected to turn into good assembler
+   code on most CPUs, thereby minimizing overhead in the measurement.  It
+   can always be assumed s->reps >= 1.
+
+	  i = s->reps
+	  do
+	    foo();
+	  while (--i != 0);
+
+   Additional parameters might be added to "struct speed_params" in the
+   future.  Routines should ignore anything they don't use.
+
+   s->size can be used creatively, and s->xp and s->yp can be ignored.  For
+   example, speed_mpz_fac_ui() uses s->size as n for the factorial.  s->r is
+   just a user-supplied parameter.  speed_mpn_lshift() uses it as a shift,
+   speed_mpn_mul_1() uses it as a multiplier.  */
+
+
+/* MPN_COPY etc can be macros, so the _CALL forms are necessary */
+double
+speed_MPN_COPY (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_COPY (MPN_COPY);
+}
+double
+speed_MPN_COPY_INCR (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_COPY (MPN_COPY_INCR);
+}
+double
+speed_MPN_COPY_DECR (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_COPY (MPN_COPY_DECR);
+}
+#if HAVE_NATIVE_mpn_copyi
+double
+speed_mpn_copyi (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_COPY (mpn_copyi);
+}
+#endif
+#if HAVE_NATIVE_mpn_copyd
+double
+speed_mpn_copyd (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_COPY (mpn_copyd);
+}
+#endif
+double
+speed_memcpy (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_COPY_BYTES (memcpy);
+}
+double
+speed_mpn_com (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_COPY (mpn_com);
+}
+double
+speed_mpn_neg (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_COPY (mpn_neg);
+}
+double
+speed_mpn_sec_tabselect (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_TABSELECT (mpn_sec_tabselect);
+}
+
+
+double
+speed_mpn_addmul_1 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_UNARY_1 (mpn_addmul_1);
+}
+double
+speed_mpn_submul_1 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_UNARY_1 (mpn_submul_1);
+}
+
+#if HAVE_NATIVE_mpn_addmul_2
+double
+speed_mpn_addmul_2 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_UNARY_2 (mpn_addmul_2);
+}
+#endif
+#if HAVE_NATIVE_mpn_addmul_3
+double
+speed_mpn_addmul_3 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_UNARY_3 (mpn_addmul_3);
+}
+#endif
+#if HAVE_NATIVE_mpn_addmul_4
+double
+speed_mpn_addmul_4 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_UNARY_4 (mpn_addmul_4);
+}
+#endif
+#if HAVE_NATIVE_mpn_addmul_5
+double
+speed_mpn_addmul_5 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_UNARY_5 (mpn_addmul_5);
+}
+#endif
+#if HAVE_NATIVE_mpn_addmul_6
+double
+speed_mpn_addmul_6 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_UNARY_6 (mpn_addmul_6);
+}
+#endif
+#if HAVE_NATIVE_mpn_addmul_7
+double
+speed_mpn_addmul_7 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_UNARY_7 (mpn_addmul_7);
+}
+#endif
+#if HAVE_NATIVE_mpn_addmul_8
+double
+speed_mpn_addmul_8 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_UNARY_8 (mpn_addmul_8);
+}
+#endif
+
+double
+speed_mpn_mul_1 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_UNARY_1 (mpn_mul_1);
+}
+double
+speed_mpn_mul_1_inplace (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_UNARY_1_INPLACE (mpn_mul_1);
+}
+
+#if HAVE_NATIVE_mpn_mul_2
+double
+speed_mpn_mul_2 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_UNARY_2 (mpn_mul_2);
+}
+#endif
+#if HAVE_NATIVE_mpn_mul_3
+double
+speed_mpn_mul_3 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_UNARY_3 (mpn_mul_3);
+}
+#endif
+#if HAVE_NATIVE_mpn_mul_4
+double
+speed_mpn_mul_4 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_UNARY_4 (mpn_mul_4);
+}
+#endif
+#if HAVE_NATIVE_mpn_mul_5
+double
+speed_mpn_mul_5 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_UNARY_5 (mpn_mul_5);
+}
+#endif
+#if HAVE_NATIVE_mpn_mul_6
+double
+speed_mpn_mul_6 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_UNARY_6 (mpn_mul_6);
+}
+#endif
+
+
+double
+speed_mpn_lshift (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_UNARY_1 (mpn_lshift);
+}
+double
+speed_mpn_lshiftc (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_UNARY_1 (mpn_lshiftc);
+}
+double
+speed_mpn_rshift (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_UNARY_1 (mpn_rshift);
+}
+
+
+/* The carry-in variants (if available) are good for measuring because they
+   won't skip a division if high<divisor.  Alternately, use -1 as a divisor
+   with the plain _1 forms. */
+double
+speed_mpn_divrem_1 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_DIVREM_1 (mpn_divrem_1);
+}
+double
+speed_mpn_divrem_1f (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_DIVREM_1F (mpn_divrem_1);
+}
+#if HAVE_NATIVE_mpn_divrem_1c
+double
+speed_mpn_divrem_1c (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_DIVREM_1C (mpn_divrem_1c);
+}
+double
+speed_mpn_divrem_1cf (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_DIVREM_1CF (mpn_divrem_1c);
+}
+#endif
+
+double
+speed_mpn_divrem_1_div (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_DIVREM_1 (mpn_divrem_1_div);
+}
+double
+speed_mpn_divrem_1f_div (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_DIVREM_1F (mpn_divrem_1_div);
+}
+double
+speed_mpn_divrem_1_inv (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_DIVREM_1 (mpn_divrem_1_inv);
+}
+double
+speed_mpn_divrem_1f_inv (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_DIVREM_1F (mpn_divrem_1_inv);
+}
+double
+speed_mpn_mod_1_div (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_MOD_1 (mpn_mod_1_div);
+}
+double
+speed_mpn_mod_1_inv (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_MOD_1 (mpn_mod_1_inv);
+}
+
+double
+speed_mpn_preinv_divrem_1 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_PREINV_DIVREM_1 (mpn_preinv_divrem_1);
+}
+double
+speed_mpn_preinv_divrem_1f (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_PREINV_DIVREM_1F (mpn_preinv_divrem_1);
+}
+
+#if GMP_NUMB_BITS % 4 == 0
+double
+speed_mpn_mod_34lsub1 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_MOD_34LSUB1 (mpn_mod_34lsub1);
+}
+#endif
+
+double
+speed_mpn_divrem_2 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_DIVREM_2 (mpn_divrem_2);
+}
+double
+speed_mpn_divrem_2_div (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_DIVREM_2 (mpn_divrem_2_div);
+}
+double
+speed_mpn_divrem_2_inv (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_DIVREM_2 (mpn_divrem_2_inv);
+}
+
+double
+speed_mpn_div_qr_1n_pi1 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_DIV_QR_1N_PI1 (mpn_div_qr_1n_pi1);
+}
+double
+speed_mpn_div_qr_1n_pi1_1 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_DIV_QR_1N_PI1 (mpn_div_qr_1n_pi1_1);
+}
+double
+speed_mpn_div_qr_1n_pi1_2 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_DIV_QR_1N_PI1 (mpn_div_qr_1n_pi1_2);
+}
+
+double
+speed_mpn_div_qr_1 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_DIV_QR_1 (mpn_div_qr_1);
+}
+
+double
+speed_mpn_div_qr_2n (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_DIV_QR_2 (mpn_div_qr_2, 1);
+}
+double
+speed_mpn_div_qr_2u (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_DIV_QR_2 (mpn_div_qr_2, 0);
+}
+
+double
+speed_mpn_mod_1 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_MOD_1 (mpn_mod_1);
+}
+#if HAVE_NATIVE_mpn_mod_1c
+double
+speed_mpn_mod_1c (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_MOD_1C (mpn_mod_1c);
+}
+#endif
+double
+speed_mpn_preinv_mod_1 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_PREINV_MOD_1 (mpn_preinv_mod_1);
+}
+double
+speed_mpn_mod_1_1 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_MOD_1_1 (mpn_mod_1_1p,mpn_mod_1_1p_cps);
+}
+double
+speed_mpn_mod_1_1_1 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_MOD_1_1 (mpn_mod_1_1p_1,mpn_mod_1_1p_cps_1);
+}
+double
+speed_mpn_mod_1_1_2 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_MOD_1_1 (mpn_mod_1_1p_2,mpn_mod_1_1p_cps_2);
+}
+double
+speed_mpn_mod_1_2 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_MOD_1_N (mpn_mod_1s_2p,mpn_mod_1s_2p_cps,2);
+}
+double
+speed_mpn_mod_1_3 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_MOD_1_N (mpn_mod_1s_3p,mpn_mod_1s_3p_cps,3);
+}
+double
+speed_mpn_mod_1_4 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_MOD_1_N (mpn_mod_1s_4p,mpn_mod_1s_4p_cps,4);
+}
+
+double
+speed_mpn_divexact_1 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_DIVEXACT_1 (mpn_divexact_1);
+}
+
+double
+speed_mpn_divexact_by3 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_COPY (mpn_divexact_by3);
+}
+
+double
+speed_mpn_bdiv_dbm1c (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_BDIV_DBM1C (mpn_bdiv_dbm1c);
+}
+
+double
+speed_mpn_bdiv_q_1 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_BDIV_Q_1 (mpn_bdiv_q_1);
+}
+
+double
+speed_mpn_pi1_bdiv_q_1 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_PI1_BDIV_Q_1 (mpn_pi1_bdiv_q_1);
+}
+
+#if HAVE_NATIVE_mpn_modexact_1_odd
+double
+speed_mpn_modexact_1_odd (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_MODEXACT_1_ODD (mpn_modexact_1_odd);
+}
+#endif
+
+double
+speed_mpn_modexact_1c_odd (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_MODEXACT_1C_ODD (mpn_modexact_1c_odd);
+}
+
+double
+speed_mpz_mod (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPZ_MOD (mpz_mod);
+}
+
+double
+speed_mpn_sbpi1_div_qr (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_PI1_DIV (mpn_sbpi1_div_qr, inv.inv32, 2,0);
+}
+double
+speed_mpn_dcpi1_div_qr (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_PI1_DIV (mpn_dcpi1_div_qr, &inv, 6,3);
+}
+double
+speed_mpn_sbpi1_divappr_q (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_PI1_DIV (mpn_sbpi1_divappr_q, inv.inv32, 2,0);
+}
+double
+speed_mpn_dcpi1_divappr_q (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_PI1_DIV (mpn_dcpi1_divappr_q, &inv, 6,3);
+}
+double
+speed_mpn_mu_div_qr (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_MU_DIV_QR (mpn_mu_div_qr, mpn_mu_div_qr_itch);
+}
+double
+speed_mpn_mu_divappr_q (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_MU_DIV_Q (mpn_mu_divappr_q, mpn_mu_divappr_q_itch);
+}
+double
+speed_mpn_mu_div_q (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_MU_DIV_Q (mpn_mu_div_q, mpn_mu_div_q_itch);
+}
+double
+speed_mpn_mupi_div_qr (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_MUPI_DIV_QR (mpn_preinv_mu_div_qr, mpn_preinv_mu_div_qr_itch);
+}
+
+double
+speed_mpn_sbpi1_bdiv_qr (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_PI1_BDIV_QR (mpn_sbpi1_bdiv_qr);
+}
+double
+speed_mpn_dcpi1_bdiv_qr (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_PI1_BDIV_QR (mpn_dcpi1_bdiv_qr);
+}
+double
+speed_mpn_sbpi1_bdiv_q (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_PI1_BDIV_Q (mpn_sbpi1_bdiv_q);
+}
+double
+speed_mpn_dcpi1_bdiv_q (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_PI1_BDIV_Q (mpn_dcpi1_bdiv_q);
+}
+double
+speed_mpn_sbpi1_bdiv_r (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_PI1_BDIV_R (mpn_sbpi1_bdiv_r);
+}
+double
+speed_mpn_mu_bdiv_q (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_MU_BDIV_Q (mpn_mu_bdiv_q, mpn_mu_bdiv_q_itch);
+}
+double
+speed_mpn_mu_bdiv_qr (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_MU_BDIV_QR (mpn_mu_bdiv_qr, mpn_mu_bdiv_qr_itch);
+}
+
+double
+speed_mpn_broot (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_BROOT (mpn_broot);
+}
+double
+speed_mpn_broot_invm1 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_BROOT (mpn_broot_invm1);
+}
+double
+speed_mpn_brootinv (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_BROOTINV (mpn_brootinv, 5*s->size);
+}
+
+double
+speed_mpn_binvert (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_BINVERT (mpn_binvert, mpn_binvert_itch);
+}
+
+double
+speed_mpn_invert (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_INVERT (mpn_invert, mpn_invert_itch);
+}
+
+double
+speed_mpn_invertappr (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_INVERTAPPR (mpn_invertappr, mpn_invertappr_itch);
+}
+
+double
+speed_mpn_ni_invertappr (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_INVERTAPPR (mpn_ni_invertappr, mpn_invertappr_itch);
+}
+
+double
+speed_mpn_sec_invert (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_SEC_INVERT (mpn_sec_invert, mpn_sec_invert_itch);
+}
+
+double
+speed_mpn_redc_1 (struct speed_params *s)
+{
+  SPEED_ROUTINE_REDC_1 (mpn_redc_1);
+}
+double
+speed_mpn_redc_2 (struct speed_params *s)
+{
+  SPEED_ROUTINE_REDC_2 (mpn_redc_2);
+}
+double
+speed_mpn_redc_n (struct speed_params *s)
+{
+  SPEED_ROUTINE_REDC_N (mpn_redc_n);
+}
+
+
+double
+speed_mpn_popcount (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_POPCOUNT (mpn_popcount);
+}
+double
+speed_mpn_hamdist (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_HAMDIST (mpn_hamdist);
+}
+
+
+double
+speed_mpn_add_n (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_BINARY_N (mpn_add_n);
+}
+double
+speed_mpn_sub_n (struct speed_params *s)
+{
+SPEED_ROUTINE_MPN_BINARY_N (mpn_sub_n);
+}
+double
+speed_mpn_add_1 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_UNARY_1 (mpn_add_1);
+}
+double
+speed_mpn_add_1_inplace (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_UNARY_1_INPLACE (mpn_add_1);
+}
+double
+speed_mpn_sub_1 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_UNARY_1 (mpn_sub_1);
+}
+double
+speed_mpn_sub_1_inplace (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_UNARY_1_INPLACE (mpn_sub_1);
+}
+
+double
+speed_mpn_add_err1_n (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_BINARY_ERR1_N (mpn_add_err1_n);
+}
+double
+speed_mpn_sub_err1_n (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_BINARY_ERR1_N (mpn_sub_err1_n);
+}
+double
+speed_mpn_add_err2_n (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_BINARY_ERR2_N (mpn_add_err2_n);
+}
+double
+speed_mpn_sub_err2_n (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_BINARY_ERR2_N (mpn_sub_err2_n);
+}
+double
+speed_mpn_add_err3_n (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_BINARY_ERR3_N (mpn_add_err3_n);
+}
+double
+speed_mpn_sub_err3_n (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_BINARY_ERR3_N (mpn_sub_err3_n);
+}
+
+
+#if HAVE_NATIVE_mpn_add_n_sub_n
+double
+speed_mpn_add_n_sub_n (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_ADDSUB_N_CALL (mpn_add_n_sub_n (ap, sp, s->xp, s->yp, s->size));
+}
+#endif
+
+#if HAVE_NATIVE_mpn_addlsh1_n == 1
+double
+speed_mpn_addlsh1_n (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_BINARY_N (mpn_addlsh1_n);
+}
+#endif
+#if HAVE_NATIVE_mpn_sublsh1_n == 1
+double
+speed_mpn_sublsh1_n (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_BINARY_N (mpn_sublsh1_n);
+}
+#endif
+#if HAVE_NATIVE_mpn_addlsh1_n_ip1
+double
+speed_mpn_addlsh1_n_ip1 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_COPY (mpn_addlsh1_n_ip1);
+}
+#endif
+#if HAVE_NATIVE_mpn_addlsh1_n_ip2
+double
+speed_mpn_addlsh1_n_ip2 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_COPY (mpn_addlsh1_n_ip2);
+}
+#endif
+#if HAVE_NATIVE_mpn_sublsh1_n_ip1
+double
+speed_mpn_sublsh1_n_ip1 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_COPY (mpn_sublsh1_n_ip1);
+}
+#endif
+#if HAVE_NATIVE_mpn_rsblsh1_n == 1
+double
+speed_mpn_rsblsh1_n (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_BINARY_N (mpn_rsblsh1_n);
+}
+#endif
+#if HAVE_NATIVE_mpn_addlsh2_n == 1
+double
+speed_mpn_addlsh2_n (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_BINARY_N (mpn_addlsh2_n);
+}
+#endif
+#if HAVE_NATIVE_mpn_sublsh2_n == 1
+double
+speed_mpn_sublsh2_n (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_BINARY_N (mpn_sublsh2_n);
+}
+#endif
+#if HAVE_NATIVE_mpn_addlsh2_n_ip1
+double
+speed_mpn_addlsh2_n_ip1 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_COPY (mpn_addlsh2_n_ip1);
+}
+#endif
+#if HAVE_NATIVE_mpn_addlsh2_n_ip2
+double
+speed_mpn_addlsh2_n_ip2 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_COPY (mpn_addlsh2_n_ip2);
+}
+#endif
+#if HAVE_NATIVE_mpn_sublsh2_n_ip1
+double
+speed_mpn_sublsh2_n_ip1 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_COPY (mpn_sublsh2_n_ip1);
+}
+#endif
+#if HAVE_NATIVE_mpn_rsblsh2_n == 1
+double
+speed_mpn_rsblsh2_n (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_BINARY_N (mpn_rsblsh2_n);
+}
+#endif
+#if HAVE_NATIVE_mpn_addlsh_n
+double
+speed_mpn_addlsh_n (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_BINARY_N_CALL (mpn_addlsh_n (wp, xp, yp, s->size, 7));
+}
+#endif
+#if HAVE_NATIVE_mpn_sublsh_n
+double
+speed_mpn_sublsh_n (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_BINARY_N_CALL (mpn_sublsh_n (wp, xp, yp, s->size, 7));
+}
+#endif
+#if HAVE_NATIVE_mpn_addlsh_n_ip1
+double
+speed_mpn_addlsh_n_ip1 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_UNARY_1_CALL (mpn_addlsh_n_ip1 (wp, s->xp, s->size, 7));
+}
+#endif
+#if HAVE_NATIVE_mpn_addlsh_n_ip2
+double
+speed_mpn_addlsh_n_ip2 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_UNARY_1_CALL (mpn_addlsh_n_ip2 (wp, s->xp, s->size, 7));
+}
+#endif
+#if HAVE_NATIVE_mpn_sublsh_n_ip1
+double
+speed_mpn_sublsh_n_ip1 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_UNARY_1_CALL (mpn_sublsh_n_ip1 (wp, s->xp, s->size, 7));
+}
+#endif
+#if HAVE_NATIVE_mpn_rsblsh_n
+double
+speed_mpn_rsblsh_n (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_BINARY_N_CALL (mpn_rsblsh_n (wp, xp, yp, s->size, 7));
+}
+#endif
+#if HAVE_NATIVE_mpn_rsh1add_n
+double
+speed_mpn_rsh1add_n (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_BINARY_N (mpn_rsh1add_n);
+}
+#endif
+#if HAVE_NATIVE_mpn_rsh1sub_n
+double
+speed_mpn_rsh1sub_n (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_BINARY_N (mpn_rsh1sub_n);
+}
+#endif
+
+double
+speed_mpn_cnd_add_n (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_BINARY_N_CALL (mpn_cnd_add_n (1, wp, xp, yp, s->size));
+}
+double
+speed_mpn_cnd_sub_n (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_BINARY_N_CALL (mpn_cnd_sub_n (1, wp, xp, yp, s->size));
+}
+
+/* mpn_and_n etc can be macros and so have to be handled with
+   SPEED_ROUTINE_MPN_BINARY_N_CALL forms */
+double
+speed_mpn_and_n (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_BINARY_N_CALL (mpn_and_n (wp, xp, yp, s->size));
+}
+double
+speed_mpn_andn_n (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_BINARY_N_CALL (mpn_andn_n (wp, xp, yp, s->size));
+}
+double
+speed_mpn_nand_n (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_BINARY_N_CALL (mpn_nand_n (wp, xp, yp, s->size));
+}
+double
+speed_mpn_ior_n (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_BINARY_N_CALL (mpn_ior_n (wp, xp, yp, s->size));
+}
+double
+speed_mpn_iorn_n (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_BINARY_N_CALL (mpn_iorn_n (wp, xp, yp, s->size));
+}
+double
+speed_mpn_nior_n (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_BINARY_N_CALL (mpn_nior_n (wp, xp, yp, s->size));
+}
+double
+speed_mpn_xor_n (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_BINARY_N_CALL (mpn_xor_n (wp, xp, yp, s->size));
+}
+double
+speed_mpn_xnor_n (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_BINARY_N_CALL (mpn_xnor_n (wp, xp, yp, s->size));
+}
+
+
+double
+speed_mpn_mul_n (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_MUL_N (mpn_mul_n);
+}
+double
+speed_mpn_sqr (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_SQR (mpn_sqr);
+}
+double
+speed_mpn_mul_n_sqr (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_SQR_CALL (mpn_mul_n (wp, s->xp, s->xp, s->size));
+}
+
+double
+speed_mpn_mul_basecase (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_MUL(mpn_mul_basecase);
+}
+double
+speed_mpn_mul (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_MUL(mpn_mul);
+}
+double
+speed_mpn_sqr_basecase (struct speed_params *s)
+{
+  /* FIXME: size restrictions on some versions of sqr_basecase */
+  SPEED_ROUTINE_MPN_SQR (mpn_sqr_basecase);
+}
+
+#if HAVE_NATIVE_mpn_sqr_diagonal
+double
+speed_mpn_sqr_diagonal (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_SQR (mpn_sqr_diagonal);
+}
+#endif
+
+#if HAVE_NATIVE_mpn_sqr_diag_addlsh1
+double
+speed_mpn_sqr_diag_addlsh1 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_SQR_DIAG_ADDLSH1_CALL (mpn_sqr_diag_addlsh1 (wp, tp, s->xp, s->size));
+}
+#endif
+
+double
+speed_mpn_toom2_sqr (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_TOOM2_SQR (mpn_toom2_sqr);
+}
+double
+speed_mpn_toom3_sqr (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_TOOM3_SQR (mpn_toom3_sqr);
+}
+double
+speed_mpn_toom4_sqr (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_TOOM4_SQR (mpn_toom4_sqr);
+}
+double
+speed_mpn_toom6_sqr (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_TOOM6_SQR (mpn_toom6_sqr);
+}
+double
+speed_mpn_toom8_sqr (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_TOOM8_SQR (mpn_toom8_sqr);
+}
+double
+speed_mpn_toom22_mul (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_TOOM22_MUL_N (mpn_toom22_mul);
+}
+double
+speed_mpn_toom33_mul (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_TOOM33_MUL_N (mpn_toom33_mul);
+}
+double
+speed_mpn_toom44_mul (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_TOOM44_MUL_N (mpn_toom44_mul);
+}
+double
+speed_mpn_toom6h_mul (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_TOOM6H_MUL_N (mpn_toom6h_mul);
+}
+double
+speed_mpn_toom8h_mul (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_TOOM8H_MUL_N (mpn_toom8h_mul);
+}
+
+double
+speed_mpn_toom32_mul (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_TOOM32_MUL (mpn_toom32_mul);
+}
+double
+speed_mpn_toom42_mul (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_TOOM42_MUL (mpn_toom42_mul);
+}
+double
+speed_mpn_toom43_mul (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_TOOM43_MUL (mpn_toom43_mul);
+}
+double
+speed_mpn_toom63_mul (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_TOOM63_MUL (mpn_toom63_mul);
+}
+double
+speed_mpn_toom32_for_toom43_mul (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_TOOM32_FOR_TOOM43_MUL (mpn_toom32_mul);
+}
+double
+speed_mpn_toom43_for_toom32_mul (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_TOOM43_FOR_TOOM32_MUL (mpn_toom43_mul);
+}
+double
+speed_mpn_toom32_for_toom53_mul (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_TOOM32_FOR_TOOM53_MUL (mpn_toom32_mul);
+}
+double
+speed_mpn_toom53_for_toom32_mul (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_TOOM53_FOR_TOOM32_MUL (mpn_toom53_mul);
+}
+double
+speed_mpn_toom42_for_toom53_mul (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_TOOM42_FOR_TOOM53_MUL (mpn_toom42_mul);
+}
+double
+speed_mpn_toom53_for_toom42_mul (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_TOOM53_FOR_TOOM42_MUL (mpn_toom53_mul);
+}
+double
+speed_mpn_toom43_for_toom54_mul (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_TOOM43_FOR_TOOM54_MUL (mpn_toom43_mul);
+}
+double
+speed_mpn_toom54_for_toom43_mul (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_TOOM54_FOR_TOOM43_MUL (mpn_toom54_mul);
+}
+
+double
+speed_mpn_nussbaumer_mul (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_MUL_N_CALL
+    (mpn_nussbaumer_mul (wp, s->xp, s->size, s->yp, s->size));
+}
+double
+speed_mpn_nussbaumer_mul_sqr (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_SQR_CALL
+    (mpn_nussbaumer_mul (wp, s->xp, s->size, s->xp, s->size));
+}
+
+#if WANT_OLD_FFT_FULL
+double
+speed_mpn_mul_fft_full (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_MUL_N_CALL
+    (mpn_mul_fft_full (wp, s->xp, s->size, s->yp, s->size));
+}
+double
+speed_mpn_mul_fft_full_sqr (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_SQR_CALL
+    (mpn_mul_fft_full (wp, s->xp, s->size, s->xp, s->size));
+}
+#endif
+
+/* These are mod 2^N+1 multiplies and squares.  If s->r is supplied it's
+   used as k, otherwise the best k for the size is used.  If s->size isn't a
+   multiple of 2^k it's rounded up to make the effective operation size.  */
+
+#define SPEED_ROUTINE_MPN_MUL_FFT_CALL(call, sqr)       \
+  {                                                     \
+    mp_ptr     wp;                                      \
+    mp_size_t  pl;                                      \
+    int        k;                                       \
+    unsigned   i;                                       \
+    double     t;                                       \
+    TMP_DECL;                                           \
+							\
+    SPEED_RESTRICT_COND (s->size >= 1);                 \
+							\
+    if (s->r != 0)                                      \
+      k = s->r;                                         \
+    else                                                \
+      k = mpn_fft_best_k (s->size, sqr);                \
+							\
+    TMP_MARK;                                           \
+    pl = mpn_fft_next_size (s->size, k);                \
+    SPEED_TMP_ALLOC_LIMBS (wp, pl+1, s->align_wp);      \
+							\
+    speed_operand_src (s, s->xp, s->size);              \
+    if (!sqr)                                           \
+      speed_operand_src (s, s->yp, s->size);            \
+    speed_operand_dst (s, wp, pl+1);                    \
+    speed_cache_fill (s);                               \
+							\
+    speed_starttime ();                                 \
+    i = s->reps;                                        \
+    do                                                  \
+      call;                                             \
+    while (--i != 0);                                   \
+    t = speed_endtime ();                               \
+							\
+    TMP_FREE;                                           \
+    return t;                                           \
+  }
+
+double
+speed_mpn_mul_fft (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_MUL_FFT_CALL
+    (mpn_mul_fft (wp, pl, s->xp, s->size, s->yp, s->size, k), 0);
+}
+
+double
+speed_mpn_mul_fft_sqr (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_MUL_FFT_CALL
+    (mpn_mul_fft (wp, pl, s->xp, s->size, s->xp, s->size, k), 1);
+}
+
+double
+speed_mpn_fft_mul (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_MUL_N_CALL (mpn_fft_mul (wp, s->xp, s->size, s->yp, s->size));
+}
+
+double
+speed_mpn_fft_sqr (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_SQR_CALL (mpn_fft_mul (wp, s->xp, s->size, s->xp, s->size));
+}
+
+double
+speed_mpn_sqrlo (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_SQRLO (mpn_sqrlo);
+}
+double
+speed_mpn_sqrlo_basecase (struct speed_params *s)
+{
+  SPEED_RESTRICT_COND (ABOVE_THRESHOLD (s->size, MIN (3, SQRLO_BASECASE_THRESHOLD))
+		       && BELOW_THRESHOLD (s->size, SQRLO_DC_THRESHOLD));
+  SPEED_ROUTINE_MPN_SQRLO (mpn_sqrlo_basecase);
+}
+double
+speed_mpn_mullo_n (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_MULLO_N (mpn_mullo_n);
+}
+double
+speed_mpn_mullo_basecase (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_MULLO_BASECASE (mpn_mullo_basecase);
+}
+
+double
+speed_mpn_mulmid_basecase (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_MULMID (mpn_mulmid_basecase);
+}
+
+double
+speed_mpn_mulmid (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_MULMID (mpn_mulmid);
+}
+
+double
+speed_mpn_mulmid_n (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_MULMID_N (mpn_mulmid_n);
+}
+
+double
+speed_mpn_toom42_mulmid (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_TOOM42_MULMID (mpn_toom42_mulmid);
+}
+
+double
+speed_mpn_mulmod_bnm1 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_MULMOD_BNM1_CALL (mpn_mulmod_bnm1 (wp, s->size, s->xp, s->size, s->yp, s->size, tp));
+}
+
+double
+speed_mpn_bc_mulmod_bnm1 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_MULMOD_BNM1_CALL (mpn_bc_mulmod_bnm1 (wp, s->xp, s->yp, s->size, tp));
+}
+
+double
+speed_mpn_mulmod_bnm1_rounded (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_MULMOD_BNM1_ROUNDED (mpn_mulmod_bnm1);
+}
+
+double
+speed_mpn_sqrmod_bnm1 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_MULMOD_BNM1_CALL (mpn_sqrmod_bnm1 (wp, s->size, s->xp, s->size, tp));
+}
+
+double
+speed_mpn_matrix22_mul (struct speed_params *s)
+{
+  /* Speed params only includes 2 inputs, so we have to invent the
+     other 6. */
+
+  mp_ptr a;
+  mp_ptr r;
+  mp_ptr b;
+  mp_ptr tp;
+  mp_size_t itch;
+  unsigned i;
+  double t;
+  TMP_DECL;
+
+  TMP_MARK;
+  SPEED_TMP_ALLOC_LIMBS (a, 4 * s->size, s->align_xp);
+  SPEED_TMP_ALLOC_LIMBS (b, 4 * s->size, s->align_yp);
+  SPEED_TMP_ALLOC_LIMBS (r, 8 * s->size + 4, s->align_wp);
+
+  MPN_COPY (a, s->xp, s->size);
+  mpn_random (a + s->size, 3 * s->size);
+  MPN_COPY (b, s->yp, s->size);
+  mpn_random (b + s->size, 3 * s->size);
+
+  itch = mpn_matrix22_mul_itch (s->size, s->size);
+  SPEED_TMP_ALLOC_LIMBS (tp, itch, s->align_wp2);
+
+  speed_operand_src (s, a, 4 * s->size);
+  speed_operand_src (s, b, 4 * s->size);
+  speed_operand_dst (s, r, 8 * s->size + 4);
+  speed_operand_dst (s, tp, itch);
+  speed_cache_fill (s);
+
+  speed_starttime ();
+  i = s->reps;
+  do
+    {
+      mp_size_t sz = s->size;
+      MPN_COPY (r + 0 * sz + 0, a + 0 * sz, sz);
+      MPN_COPY (r + 2 * sz + 1, a + 1 * sz, sz);
+      MPN_COPY (r + 4 * sz + 2, a + 2 * sz, sz);
+      MPN_COPY (r + 6 * sz + 3, a + 3 * sz, sz);
+      mpn_matrix22_mul (r, r + 2 * sz + 1, r + 4 * sz + 2, r + 6 * sz + 3, sz,
+			b, b + 1 * sz,     b + 2 * sz,     b + 3 * sz,     sz,
+			tp);
+    }
+  while (--i != 0);
+  t = speed_endtime();
+  TMP_FREE;
+  return t;
+}
+
+double
+speed_mpn_hgcd2 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_HGCD2 (mpn_hgcd2);
+}
+double
+speed_mpn_hgcd2_1 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_HGCD2 (mpn_hgcd2_1);
+}
+double
+speed_mpn_hgcd2_2 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_HGCD2 (mpn_hgcd2_2);
+}
+double
+speed_mpn_hgcd2_3 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_HGCD2 (mpn_hgcd2_3);
+}
+double
+speed_mpn_hgcd2_4 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_HGCD2 (mpn_hgcd2_4);
+}
+double
+speed_mpn_hgcd2_5 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_HGCD2 (mpn_hgcd2_5);
+}
+
+double
+speed_mpn_hgcd (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_HGCD_CALL (mpn_hgcd, mpn_hgcd_itch);
+}
+
+double
+speed_mpn_hgcd_lehmer (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_HGCD_CALL (mpn_hgcd_lehmer, mpn_hgcd_lehmer_itch);
+}
+
+double
+speed_mpn_hgcd_appr (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_HGCD_CALL (mpn_hgcd_appr, mpn_hgcd_appr_itch);
+}
+
+double
+speed_mpn_hgcd_appr_lehmer (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_HGCD_CALL (mpn_hgcd_appr_lehmer, mpn_hgcd_appr_lehmer_itch);
+}
+
+double
+speed_mpn_hgcd_reduce (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_HGCD_REDUCE_CALL (mpn_hgcd_reduce, mpn_hgcd_reduce_itch);
+}
+double
+speed_mpn_hgcd_reduce_1 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_HGCD_REDUCE_CALL (mpn_hgcd_reduce_1, mpn_hgcd_reduce_1_itch);
+}
+double
+speed_mpn_hgcd_reduce_2 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_HGCD_REDUCE_CALL (mpn_hgcd_reduce_2, mpn_hgcd_reduce_2_itch);
+}
+
+double
+speed_mpn_gcd (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_GCD (mpn_gcd);
+}
+
+double
+speed_mpn_gcdext (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_GCDEXT (mpn_gcdext);
+}
+#if 0
+double
+speed_mpn_gcdext_lehmer (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_GCDEXT (__gmpn_gcdext_lehmer);
+}
+#endif
+double
+speed_mpn_gcdext_single (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_GCDEXT (mpn_gcdext_single);
+}
+double
+speed_mpn_gcdext_double (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_GCDEXT (mpn_gcdext_double);
+}
+double
+speed_mpn_gcdext_one_single (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_GCDEXT_ONE (mpn_gcdext_one_single);
+}
+double
+speed_mpn_gcdext_one_double (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_GCDEXT_ONE (mpn_gcdext_one_double);
+}
+double
+speed_mpn_gcd_1 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_GCD_1 (mpn_gcd_1);
+}
+double
+speed_mpn_gcd_11 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_GCD_11 (mpn_gcd_11);
+}
+double
+speed_mpn_gcd_1N (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_GCD_1N (mpn_gcd_1);
+}
+double
+speed_mpn_gcd_22 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_GCD_22 (mpn_gcd_22);
+}
+
+double
+speed_mpz_nextprime (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPZ_NEXTPRIME (mpz_nextprime);
+}
+
+double
+speed_mpz_jacobi (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPZ_JACOBI (mpz_jacobi);
+}
+double
+speed_mpn_jacobi_base (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_JACBASE (mpn_jacobi_base);
+}
+double
+speed_mpn_jacobi_base_1 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_JACBASE (mpn_jacobi_base_1);
+}
+double
+speed_mpn_jacobi_base_2 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_JACBASE (mpn_jacobi_base_2);
+}
+double
+speed_mpn_jacobi_base_3 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_JACBASE (mpn_jacobi_base_3);
+}
+double
+speed_mpn_jacobi_base_4 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_JACBASE (mpn_jacobi_base_4);
+}
+
+
+double
+speed_mpn_sqrtrem (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_SQRTROOT_CALL (mpn_sqrtrem (wp, wp2, s->xp, s->size));
+}
+
+double
+speed_mpn_sqrt (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_SQRTROOT_CALL (mpn_sqrtrem (wp, NULL, s->xp, s->size));
+}
+
+double
+speed_mpn_rootrem (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_SQRTROOT_CALL (mpn_rootrem (wp, wp2, s->xp, s->size, s->r));
+}
+
+double
+speed_mpn_root (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_SQRTROOT_CALL (mpn_rootrem (wp, NULL, s->xp, s->size, s->r));
+}
+
+
+double
+speed_mpn_perfect_power_p (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_PERFECT_POWER (mpn_perfect_power_p);
+}
+
+double
+speed_mpn_perfect_square_p (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_PERFECT_SQUARE (mpn_perfect_square_p);
+}
+
+
+double
+speed_mpz_fac_ui (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPZ_FAC_UI (mpz_fac_ui);
+}
+
+double
+speed_mpz_2fac_ui (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPZ_UI (mpz_2fac_ui);
+}
+
+double
+speed_mpz_primorial_ui (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPZ_UI (mpz_primorial_ui);
+}
+
+
+double
+speed_mpn_fib2_ui (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_FIB2_UI (mpn_fib2_ui);
+}
+double
+speed_mpz_fib_ui (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPZ_FIB_UI (mpz_fib_ui);
+}
+double
+speed_mpz_fib2_ui (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPZ_FIB2_UI (mpz_fib2_ui);
+}
+double
+speed_mpz_lucnum_ui (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPZ_LUCNUM_UI (mpz_lucnum_ui);
+}
+double
+speed_mpz_lucnum2_ui (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPZ_LUCNUM2_UI (mpz_lucnum2_ui);
+}
+
+
+double
+speed_mpz_powm (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPZ_POWM (mpz_powm);
+}
+double
+speed_mpz_powm_mod (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPZ_POWM (mpz_powm_mod);
+}
+double
+speed_mpz_powm_redc (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPZ_POWM (mpz_powm_redc);
+}
+double
+speed_mpz_powm_sec (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPZ_POWM (mpz_powm_sec);
+}
+double
+speed_mpz_powm_ui (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPZ_POWM_UI (mpz_powm_ui);
+}
+
+
+double
+speed_binvert_limb (struct speed_params *s)
+{
+  SPEED_ROUTINE_MODLIMB_INVERT (binvert_limb);
+}
+
+
+double
+speed_noop (struct speed_params *s)
+{
+  unsigned  i;
+
+  speed_starttime ();
+  i = s->reps;
+  do
+    noop ();
+  while (--i != 0);
+  return speed_endtime ();
+}
+
+double
+speed_noop_wxs (struct speed_params *s)
+{
+  mp_ptr   wp;
+  unsigned i;
+  double   t;
+  TMP_DECL;
+
+  TMP_MARK;
+  wp = TMP_ALLOC_LIMBS (1);
+
+  speed_starttime ();
+  i = s->reps;
+  do
+    noop_wxs (wp, s->xp, s->size);
+  while (--i != 0);
+  t = speed_endtime ();
+
+  TMP_FREE;
+  return t;
+}
+
+double
+speed_noop_wxys (struct speed_params *s)
+{
+  mp_ptr   wp;
+  unsigned i;
+  double   t;
+  TMP_DECL;
+
+  TMP_MARK;
+  wp = TMP_ALLOC_LIMBS (1);
+
+  speed_starttime ();
+  i = s->reps;
+  do
+    noop_wxys (wp, s->xp, s->yp, s->size);
+  while (--i != 0);
+  t = speed_endtime ();
+
+  TMP_FREE;
+  return t;
+}
+
+
+#define SPEED_ROUTINE_ALLOC_FREE(variables, calls)      \
+  {                                                     \
+    unsigned  i;                                        \
+    variables;                                          \
+							\
+    speed_starttime ();                                 \
+    i = s->reps;                                        \
+    do                                                  \
+      {                                                 \
+	calls;                                          \
+      }                                                 \
+    while (--i != 0);                                   \
+    return speed_endtime ();                            \
+  }
+
+
+/* Compare these to see how much malloc/free costs and then how much
+   __gmp_default_allocate/free and mpz_init/clear add.  mpz_init/clear or
+   mpq_init/clear will be doing a 1 limb allocate, so use that as the size
+   when including them in comparisons.  */
+
+double
+speed_malloc_free (struct speed_params *s)
+{
+  size_t  bytes = s->size * GMP_LIMB_BYTES;
+  SPEED_ROUTINE_ALLOC_FREE (void *p,
+			    p = malloc (bytes);
+			    free (p));
+}
+
+double
+speed_malloc_realloc_free (struct speed_params *s)
+{
+  size_t  bytes = s->size * GMP_LIMB_BYTES;
+  SPEED_ROUTINE_ALLOC_FREE (void *p,
+			    p = malloc (GMP_LIMB_BYTES);
+			    p = realloc (p, bytes);
+			    free (p));
+}
+
+double
+speed_gmp_allocate_free (struct speed_params *s)
+{
+  size_t  bytes = s->size * GMP_LIMB_BYTES;
+  SPEED_ROUTINE_ALLOC_FREE (void *p,
+			    p = (*__gmp_allocate_func) (bytes);
+			    (*__gmp_free_func) (p, bytes));
+}
+
+double
+speed_gmp_allocate_reallocate_free (struct speed_params *s)
+{
+  size_t  bytes = s->size * GMP_LIMB_BYTES;
+  SPEED_ROUTINE_ALLOC_FREE
+    (void *p,
+     p = (*__gmp_allocate_func) (GMP_LIMB_BYTES);
+     p = (*__gmp_reallocate_func) (p, bytes, GMP_LIMB_BYTES);
+     (*__gmp_free_func) (p, bytes));
+}
+
+double
+speed_mpz_init_clear (struct speed_params *s)
+{
+  SPEED_ROUTINE_ALLOC_FREE (mpz_t z,
+			    mpz_init (z);
+			    mpz_clear (z));
+}
+
+double
+speed_mpz_init_realloc_clear (struct speed_params *s)
+{
+  SPEED_ROUTINE_ALLOC_FREE (mpz_t z,
+			    mpz_init (z);
+			    _mpz_realloc (z, s->size);
+			    mpz_clear (z));
+}
+
+double
+speed_mpq_init_clear (struct speed_params *s)
+{
+  SPEED_ROUTINE_ALLOC_FREE (mpq_t q,
+			    mpq_init (q);
+			    mpq_clear (q));
+}
+
+double
+speed_mpf_init_clear (struct speed_params *s)
+{
+  SPEED_ROUTINE_ALLOC_FREE (mpf_t f,
+			    mpf_init (f);
+			    mpf_clear (f));
+}
+
+
+/* Compare this to mpn_add_n to see how much overhead mpz_add adds.  Note
+   that repeatedly calling mpz_add with the same data gives branch prediction
+   in it an advantage.  */
+
+double
+speed_mpz_add (struct speed_params *s)
+{
+  mpz_t     w, x, y;
+  unsigned  i;
+  double    t;
+
+  mpz_init (w);
+  mpz_init (x);
+  mpz_init (y);
+
+  mpz_set_n (x, s->xp, s->size);
+  mpz_set_n (y, s->yp, s->size);
+  mpz_add (w, x, y);
+
+  speed_starttime ();
+  i = s->reps;
+  do
+    {
+      mpz_add (w, x, y);
+    }
+  while (--i != 0);
+  t = speed_endtime ();
+
+  mpz_clear (w);
+  mpz_clear (x);
+  mpz_clear (y);
+  return t;
+}
+
+
+/* An inverse (s->r) or (s->size)/2 modulo s->size limbs */
+
+double
+speed_mpz_invert (struct speed_params *s)
+{
+  mpz_t     a, m, r;
+  mp_size_t k;
+  unsigned  i;
+  double    t;
+
+  if (s->r == 0)
+    k = s->size/2;
+  else if (s->r < GMP_LIMB_HIGHBIT)
+    k = s->r;
+  else /* s->r < 0 */
+    k = s->size - (-s->r);
+
+  SPEED_RESTRICT_COND (k > 0 && k <= s->size);
+
+  mpz_init_set_n (m, s->yp, s->size);
+  mpz_setbit (m, 0);	/* force m to odd */
+
+  mpz_init_set_n (a, s->xp, k);
+
+  mpz_init (r);
+  while (mpz_invert (r, a, m) == 0)
+    mpz_add_ui (a, a, 1);
+
+  speed_starttime ();
+  i = s->reps;
+  do
+    mpz_invert (r, a, m);
+  while (--i != 0);
+  t = speed_endtime ();
+
+  mpz_clear (r);
+  mpz_clear (a);
+  mpz_clear (m);
+  return t;
+  }
+
+/* If r==0, calculate binomial(size,size/2),
+   otherwise calculate binomial(size,r). */
+
+double
+speed_mpz_bin_uiui (struct speed_params *s)
+{
+  mpz_t          w;
+  unsigned long  k;
+  unsigned  i;
+  double    t;
+
+  mpz_init (w);
+  if (s->r != 0)
+    k = s->r;
+  else
+    k = s->size/2;
+
+  speed_starttime ();
+  i = s->reps;
+  do
+    {
+      mpz_bin_uiui (w, s->size, k);
+    }
+  while (--i != 0);
+  t = speed_endtime ();
+
+  mpz_clear (w);
+  return t;
+}
+
+/* If r==0, calculate binomial(2^size,size),
+   otherwise calculate binomial(2^size,r). */
+
+double
+speed_mpz_bin_ui (struct speed_params *s)
+{
+  mpz_t          w, x;
+  unsigned long  k;
+  unsigned  i;
+  double    t;
+
+  mpz_init (w);
+  mpz_init_set_ui (x, 0);
+
+  mpz_setbit (x, s->size);
+
+  if (s->r != 0)
+    k = s->r;
+  else
+    k = s->size;
+
+  speed_starttime ();
+  i = s->reps;
+  do
+    {
+      mpz_bin_ui (w, x, k);
+    }
+  while (--i != 0);
+  t = speed_endtime ();
+
+  mpz_clear (w);
+  mpz_clear (x);
+  return t;
+}
+
+/* If r==0, calculate mfac(size,log(size)),
+   otherwise calculate mfac(size,r). */
+
+double
+speed_mpz_mfac_uiui (struct speed_params *s)
+{
+  mpz_t          w;
+  unsigned long  k;
+  unsigned  i;
+  double    t;
+
+  mpz_init (w);
+  if (s->r != 0)
+    k = s->r;
+  else
+    for (k = 1; s->size >> k; ++k);
+
+  speed_starttime ();
+  i = s->reps;
+  do
+    {
+      mpz_mfac_uiui (w, s->size, k);
+    }
+  while (--i != 0);
+  t = speed_endtime ();
+
+  mpz_clear (w);
+  return t;
+}
+
+/* The multiplies are successively dependent so the latency is measured, not
+   the issue rate.  There's only 10 per loop so the code doesn't get too big
+   since umul_ppmm is several instructions on some cpus.
+
+   Putting the arguments as "h,l,l,h" gets slightly better code from gcc
+   2.95.2 on x86, it puts only one mov between each mul, not two.  That mov
+   though will probably show up as a bogus extra cycle though.
+
+   The measuring function macros are into three parts to avoid overflowing
+   preprocessor expansion space if umul_ppmm is big.
+
+   Limitations:
+
+   The default umul_ppmm doing h*l will be getting increasing numbers of
+   high zero bits in the calculation.  CPUs with data-dependent multipliers
+   will want to use umul_ppmm.1 to get some randomization into the
+   calculation.  The extra xors and fetches will be a slowdown of course.  */
+
+#define SPEED_MACRO_UMUL_PPMM_A \
+  {                             \
+    mp_limb_t  h, l;            \
+    unsigned   i;               \
+    double     t;               \
+				\
+    s->time_divisor = 10;       \
+				\
+    h = s->xp[0];               \
+    l = s->yp[0];               \
+				\
+    if (s->r == 1)              \
+      {                         \
+	speed_starttime ();     \
+	i = s->reps;            \
+	do                      \
+	  {
+
+#define SPEED_MACRO_UMUL_PPMM_B \
+	  }                     \
+	while (--i != 0);       \
+	t = speed_endtime ();   \
+      }                         \
+    else                        \
+      {                         \
+	speed_starttime ();     \
+	i = s->reps;            \
+	do                      \
+	  {
+
+#define SPEED_MACRO_UMUL_PPMM_C                                         \
+	  }                                                             \
+	while (--i != 0);                                               \
+	t = speed_endtime ();                                           \
+      }                                                                 \
+									\
+    /* stop the compiler optimizing away the whole calculation! */      \
+    noop_1 (h);                                                         \
+    noop_1 (l);                                                         \
+									\
+    return t;                                                           \
+  }
+
+
+double
+speed_umul_ppmm (struct speed_params *s)
+{
+  SPEED_MACRO_UMUL_PPMM_A;
+  {
+    umul_ppmm (h, l, l, h);  h ^= s->xp_block[0]; l ^= s->yp_block[0];
+     umul_ppmm (h, l, l, h); h ^= s->xp_block[1]; l ^= s->yp_block[1];
+     umul_ppmm (h, l, l, h); h ^= s->xp_block[2]; l ^= s->yp_block[2];
+    umul_ppmm (h, l, l, h);  h ^= s->xp_block[3]; l ^= s->yp_block[3];
+     umul_ppmm (h, l, l, h); h ^= s->xp_block[4]; l ^= s->yp_block[4];
+     umul_ppmm (h, l, l, h); h ^= s->xp_block[5]; l ^= s->yp_block[5];
+    umul_ppmm (h, l, l, h);  h ^= s->xp_block[6]; l ^= s->yp_block[6];
+     umul_ppmm (h, l, l, h); h ^= s->xp_block[7]; l ^= s->yp_block[7];
+     umul_ppmm (h, l, l, h); h ^= s->xp_block[8]; l ^= s->yp_block[8];
+    umul_ppmm (h, l, l, h);  h ^= s->xp_block[9]; l ^= s->yp_block[9];
+  }
+  SPEED_MACRO_UMUL_PPMM_B;
+  {
+    umul_ppmm (h, l, l, h);
+     umul_ppmm (h, l, l, h);
+     umul_ppmm (h, l, l, h);
+    umul_ppmm (h, l, l, h);
+     umul_ppmm (h, l, l, h);
+     umul_ppmm (h, l, l, h);
+    umul_ppmm (h, l, l, h);
+     umul_ppmm (h, l, l, h);
+     umul_ppmm (h, l, l, h);
+    umul_ppmm (h, l, l, h);
+  }
+  SPEED_MACRO_UMUL_PPMM_C;
+}
+
+
+#if HAVE_NATIVE_mpn_umul_ppmm
+double
+speed_mpn_umul_ppmm (struct speed_params *s)
+{
+  SPEED_MACRO_UMUL_PPMM_A;
+  {
+    h = mpn_umul_ppmm (&l, h, l);  h ^= s->xp_block[0]; l ^= s->yp_block[0];
+     h = mpn_umul_ppmm (&l, h, l); h ^= s->xp_block[1]; l ^= s->yp_block[1];
+     h = mpn_umul_ppmm (&l, h, l); h ^= s->xp_block[2]; l ^= s->yp_block[2];
+    h = mpn_umul_ppmm (&l, h, l);  h ^= s->xp_block[3]; l ^= s->yp_block[3];
+     h = mpn_umul_ppmm (&l, h, l); h ^= s->xp_block[4]; l ^= s->yp_block[4];
+     h = mpn_umul_ppmm (&l, h, l); h ^= s->xp_block[5]; l ^= s->yp_block[5];
+    h = mpn_umul_ppmm (&l, h, l);  h ^= s->xp_block[6]; l ^= s->yp_block[6];
+     h = mpn_umul_ppmm (&l, h, l); h ^= s->xp_block[7]; l ^= s->yp_block[7];
+     h = mpn_umul_ppmm (&l, h, l); h ^= s->xp_block[8]; l ^= s->yp_block[8];
+    h = mpn_umul_ppmm (&l, h, l);  h ^= s->xp_block[9]; l ^= s->yp_block[9];
+  }
+  SPEED_MACRO_UMUL_PPMM_B;
+  {
+    h = mpn_umul_ppmm (&l, h, l);
+     h = mpn_umul_ppmm (&l, h, l);
+     h = mpn_umul_ppmm (&l, h, l);
+    h = mpn_umul_ppmm (&l, h, l);
+     h = mpn_umul_ppmm (&l, h, l);
+     h = mpn_umul_ppmm (&l, h, l);
+    h = mpn_umul_ppmm (&l, h, l);
+     h = mpn_umul_ppmm (&l, h, l);
+     h = mpn_umul_ppmm (&l, h, l);
+    h = mpn_umul_ppmm (&l, h, l);
+  }
+  SPEED_MACRO_UMUL_PPMM_C;
+}
+#endif
+
+#if HAVE_NATIVE_mpn_umul_ppmm_r
+double
+speed_mpn_umul_ppmm_r (struct speed_params *s)
+{
+  SPEED_MACRO_UMUL_PPMM_A;
+  {
+    h = mpn_umul_ppmm_r (h, l, &l);  h ^= s->xp_block[0]; l ^= s->yp_block[0];
+     h = mpn_umul_ppmm_r (h, l, &l); h ^= s->xp_block[1]; l ^= s->yp_block[1];
+     h = mpn_umul_ppmm_r (h, l, &l); h ^= s->xp_block[2]; l ^= s->yp_block[2];
+    h = mpn_umul_ppmm_r (h, l, &l);  h ^= s->xp_block[3]; l ^= s->yp_block[3];
+     h = mpn_umul_ppmm_r (h, l, &l); h ^= s->xp_block[4]; l ^= s->yp_block[4];
+     h = mpn_umul_ppmm_r (h, l, &l); h ^= s->xp_block[5]; l ^= s->yp_block[5];
+    h = mpn_umul_ppmm_r (h, l, &l);  h ^= s->xp_block[6]; l ^= s->yp_block[6];
+     h = mpn_umul_ppmm_r (h, l, &l); h ^= s->xp_block[7]; l ^= s->yp_block[7];
+     h = mpn_umul_ppmm_r (h, l, &l); h ^= s->xp_block[8]; l ^= s->yp_block[8];
+    h = mpn_umul_ppmm_r (h, l, &l);  h ^= s->xp_block[9]; l ^= s->yp_block[9];
+  }
+  SPEED_MACRO_UMUL_PPMM_B;
+  {
+    h = mpn_umul_ppmm_r (h, l, &l);
+     h = mpn_umul_ppmm_r (h, l, &l);
+     h = mpn_umul_ppmm_r (h, l, &l);
+    h = mpn_umul_ppmm_r (h, l, &l);
+     h = mpn_umul_ppmm_r (h, l, &l);
+     h = mpn_umul_ppmm_r (h, l, &l);
+    h = mpn_umul_ppmm_r (h, l, &l);
+     h = mpn_umul_ppmm_r (h, l, &l);
+     h = mpn_umul_ppmm_r (h, l, &l);
+    h = mpn_umul_ppmm_r (h, l, &l);
+  }
+  SPEED_MACRO_UMUL_PPMM_C;
+}
+#endif
+
+
+/* The divisions are successively dependent so latency is measured, not
+   issue rate.  There's only 10 per loop so the code doesn't get too big,
+   especially for udiv_qrnnd_preinv and preinv2norm, which are several
+   instructions each.
+
+   Note that it's only the division which is measured here, there's no data
+   fetching and no shifting if the divisor gets normalized.
+
+   In speed_udiv_qrnnd with gcc 2.95.2 on x86 the parameters "q,r,r,q,d"
+   generate x86 div instructions with nothing in between.
+
+   The measuring function macros are in two parts to avoid overflowing
+   preprocessor expansion space if udiv_qrnnd etc are big.
+
+   Limitations:
+
+   Don't blindly use this to set UDIV_TIME in gmp-mparam.h, check the code
+   generated first.
+
+   CPUs with data-dependent divisions may want more attention paid to the
+   randomness of the data used.  Probably the measurement wanted is over
+   uniformly distributed numbers, but what's here might not be giving that.  */
+
+#define SPEED_ROUTINE_UDIV_QRNND_A(normalize)           \
+  {                                                     \
+    double     t;                                       \
+    unsigned   i;                                       \
+    mp_limb_t  q, r, d;                                 \
+    mp_limb_t  dinv;                                    \
+							\
+    s->time_divisor = 10;                               \
+							\
+    /* divisor from "r" parameter, or a default */      \
+    d = s->r;                                           \
+    if (d == 0)                                         \
+      d = mp_bases[10].big_base;                        \
+							\
+    if (normalize)                                      \
+      {                                                 \
+	unsigned  norm;                                 \
+	count_leading_zeros (norm, d);                  \
+	d <<= norm;                                     \
+	invert_limb (dinv, d);                          \
+      }                                                 \
+							\
+    q = s->xp[0];                                       \
+    r = s->yp[0] % d;                                   \
+							\
+    speed_starttime ();                                 \
+    i = s->reps;                                        \
+    do                                                  \
+      {
+
+#define SPEED_ROUTINE_UDIV_QRNND_B                                      \
+      }                                                                 \
+    while (--i != 0);                                                   \
+    t = speed_endtime ();                                               \
+									\
+    /* stop the compiler optimizing away the whole calculation! */      \
+    noop_1 (q);                                                         \
+    noop_1 (r);                                                         \
+									\
+    return t;                                                           \
+  }
+
+double
+speed_udiv_qrnnd (struct speed_params *s)
+{
+  SPEED_ROUTINE_UDIV_QRNND_A (UDIV_NEEDS_NORMALIZATION);
+  {
+    udiv_qrnnd (q, r, r, q, d);
+     udiv_qrnnd (q, r, r, q, d);
+     udiv_qrnnd (q, r, r, q, d);
+    udiv_qrnnd (q, r, r, q, d);
+     udiv_qrnnd (q, r, r, q, d);
+     udiv_qrnnd (q, r, r, q, d);
+    udiv_qrnnd (q, r, r, q, d);
+     udiv_qrnnd (q, r, r, q, d);
+     udiv_qrnnd (q, r, r, q, d);
+    udiv_qrnnd (q, r, r, q, d);
+  }
+  SPEED_ROUTINE_UDIV_QRNND_B;
+}
+
+double
+speed_udiv_qrnnd_c (struct speed_params *s)
+{
+  SPEED_ROUTINE_UDIV_QRNND_A (1);
+  {
+    __udiv_qrnnd_c (q, r, r, q, d);
+     __udiv_qrnnd_c (q, r, r, q, d);
+     __udiv_qrnnd_c (q, r, r, q, d);
+    __udiv_qrnnd_c (q, r, r, q, d);
+     __udiv_qrnnd_c (q, r, r, q, d);
+     __udiv_qrnnd_c (q, r, r, q, d);
+    __udiv_qrnnd_c (q, r, r, q, d);
+     __udiv_qrnnd_c (q, r, r, q, d);
+     __udiv_qrnnd_c (q, r, r, q, d);
+    __udiv_qrnnd_c (q, r, r, q, d);
+  }
+  SPEED_ROUTINE_UDIV_QRNND_B;
+}
+
+#if HAVE_NATIVE_mpn_udiv_qrnnd
+double
+speed_mpn_udiv_qrnnd (struct speed_params *s)
+{
+  SPEED_ROUTINE_UDIV_QRNND_A (1);
+  {
+    q = mpn_udiv_qrnnd (&r, r, q, d);
+     q = mpn_udiv_qrnnd (&r, r, q, d);
+     q = mpn_udiv_qrnnd (&r, r, q, d);
+    q = mpn_udiv_qrnnd (&r, r, q, d);
+     q = mpn_udiv_qrnnd (&r, r, q, d);
+     q = mpn_udiv_qrnnd (&r, r, q, d);
+    q = mpn_udiv_qrnnd (&r, r, q, d);
+     q = mpn_udiv_qrnnd (&r, r, q, d);
+     q = mpn_udiv_qrnnd (&r, r, q, d);
+    q = mpn_udiv_qrnnd (&r, r, q, d);
+  }
+  SPEED_ROUTINE_UDIV_QRNND_B;
+}
+#endif
+
+#if HAVE_NATIVE_mpn_udiv_qrnnd_r
+double
+speed_mpn_udiv_qrnnd_r (struct speed_params *s)
+{
+  SPEED_ROUTINE_UDIV_QRNND_A (1);
+  {
+    q = mpn_udiv_qrnnd_r (r, q, d, &r);
+     q = mpn_udiv_qrnnd_r (r, q, d, &r);
+     q = mpn_udiv_qrnnd_r (r, q, d, &r);
+    q = mpn_udiv_qrnnd_r (r, q, d, &r);
+     q = mpn_udiv_qrnnd_r (r, q, d, &r);
+     q = mpn_udiv_qrnnd_r (r, q, d, &r);
+    q = mpn_udiv_qrnnd_r (r, q, d, &r);
+     q = mpn_udiv_qrnnd_r (r, q, d, &r);
+     q = mpn_udiv_qrnnd_r (r, q, d, &r);
+    q = mpn_udiv_qrnnd_r (r, q, d, &r);
+  }
+  SPEED_ROUTINE_UDIV_QRNND_B;
+}
+#endif
+
+
+double
+speed_invert_limb (struct speed_params *s)
+{
+  SPEED_ROUTINE_INVERT_LIMB_CALL (invert_limb (dinv, d));
+}
+
+
+/* xp[0] might not be particularly random, but should give an indication how
+   "/" runs.  Same for speed_operator_mod below.  */
+double
+speed_operator_div (struct speed_params *s)
+{
+  double     t;
+  unsigned   i;
+  mp_limb_t  x, q, d;
+
+  s->time_divisor = 10;
+
+  /* divisor from "r" parameter, or a default */
+  d = s->r;
+  if (d == 0)
+    d = mp_bases[10].big_base;
+
+  x = s->xp[0];
+  q = 0;
+
+  speed_starttime ();
+  i = s->reps;
+  do
+    {
+      q ^= x; q /= d;
+       q ^= x; q /= d;
+       q ^= x; q /= d;
+      q ^= x; q /= d;
+       q ^= x; q /= d;
+       q ^= x; q /= d;
+      q ^= x; q /= d;
+       q ^= x; q /= d;
+       q ^= x; q /= d;
+      q ^= x; q /= d;
+    }
+  while (--i != 0);
+  t = speed_endtime ();
+
+  /* stop the compiler optimizing away the whole calculation! */
+  noop_1 (q);
+
+  return t;
+}
+
+double
+speed_operator_mod (struct speed_params *s)
+{
+  double     t;
+  unsigned   i;
+  mp_limb_t  x, r, d;
+
+  s->time_divisor = 10;
+
+  /* divisor from "r" parameter, or a default */
+  d = s->r;
+  if (d == 0)
+    d = mp_bases[10].big_base;
+
+  x = s->xp[0];
+  r = 0;
+
+  speed_starttime ();
+  i = s->reps;
+  do
+    {
+      r ^= x; r %= d;
+       r ^= x; r %= d;
+       r ^= x; r %= d;
+      r ^= x; r %= d;
+       r ^= x; r %= d;
+       r ^= x; r %= d;
+      r ^= x; r %= d;
+       r ^= x; r %= d;
+       r ^= x; r %= d;
+      r ^= x; r %= d;
+    }
+  while (--i != 0);
+  t = speed_endtime ();
+
+  /* stop the compiler optimizing away the whole calculation! */
+  noop_1 (r);
+
+  return t;
+}
+
+
+/* r==0 measures on data with the values uniformly distributed.  This will
+   be typical for count_trailing_zeros in a GCD etc.
+
+   r==1 measures on data with the resultant count uniformly distributed
+   between 0 and GMP_LIMB_BITS-1.  This is probably sensible for
+   count_leading_zeros on the high limbs of divisors.  */
+
+int
+speed_routine_count_zeros_setup (struct speed_params *s,
+				 mp_ptr xp, int leading, int zero)
+{
+  int        i, c;
+  mp_limb_t  n;
+
+  if (s->r == 0)
+    {
+      /* Make uniformly distributed data.  If zero isn't allowed then change
+	 it to 1 for leading, or 0x800..00 for trailing.  */
+      MPN_COPY (xp, s->xp_block, SPEED_BLOCK_SIZE);
+      if (! zero)
+	for (i = 0; i < SPEED_BLOCK_SIZE; i++)
+	  if (xp[i] == 0)
+	    xp[i] = leading ? 1 : GMP_LIMB_HIGHBIT;
+    }
+  else if (s->r == 1)
+    {
+      /* Make counts uniformly distributed.  A randomly chosen bit is set, and
+	 for leading the rest above it are cleared, or for trailing then the
+	 rest below.  */
+      for (i = 0; i < SPEED_BLOCK_SIZE; i++)
+	{
+	  mp_limb_t  set = CNST_LIMB(1) << (s->yp_block[i] % GMP_LIMB_BITS);
+	  mp_limb_t  keep_below = set-1;
+	  mp_limb_t  keep_above = MP_LIMB_T_MAX ^ keep_below;
+	  mp_limb_t  keep = (leading ? keep_below : keep_above);
+	  xp[i] = (s->xp_block[i] & keep) | set;
+	}
+    }
+  else
+    {
+      return 0;
+    }
+
+  /* Account for the effect of n^=c. */
+  c = 0;
+  for (i = 0; i < SPEED_BLOCK_SIZE; i++)
+    {
+      n = xp[i];
+      xp[i] ^= c;
+
+      if (leading)
+	count_leading_zeros (c, n);
+      else
+	count_trailing_zeros (c, n);
+    }
+
+  return 1;
+}
+
+double
+speed_count_leading_zeros (struct speed_params *s)
+{
+#ifdef COUNT_LEADING_ZEROS_0
+#define COUNT_LEADING_ZEROS_0_ALLOWED   1
+#else
+#define COUNT_LEADING_ZEROS_0_ALLOWED   0
+#endif
+
+  SPEED_ROUTINE_COUNT_ZEROS_A (1, COUNT_LEADING_ZEROS_0_ALLOWED);
+  count_leading_zeros (c, n);
+  SPEED_ROUTINE_COUNT_ZEROS_B ();
+}
+double
+speed_count_trailing_zeros (struct speed_params *s)
+{
+  SPEED_ROUTINE_COUNT_ZEROS_A (0, 0);
+  count_trailing_zeros (c, n);
+  SPEED_ROUTINE_COUNT_ZEROS_B ();
+}
+
+
+double
+speed_mpn_get_str (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_GET_STR (mpn_get_str);
+}
+
+double
+speed_mpn_set_str (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_SET_STR_CALL (mpn_set_str (wp, xp, s->size, base));
+}
+double
+speed_mpn_bc_set_str (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_SET_STR_CALL (mpn_bc_set_str (wp, xp, s->size, base));
+}
+
+double
+speed_MPN_ZERO (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_ZERO_CALL (MPN_ZERO (wp, s->size));
+}
+
+
+int
+speed_randinit (struct speed_params *s, gmp_randstate_ptr rstate)
+{
+  if (s->r == 0)
+    gmp_randinit_default (rstate);
+  else if (s->r == 1)
+    gmp_randinit_mt (rstate);
+  else
+    {
+      return gmp_randinit_lc_2exp_size (rstate, s->r);
+    }
+  return 1;
+}
+
+double
+speed_gmp_randseed (struct speed_params *s)
+{
+  gmp_randstate_t  rstate;
+  unsigned  i;
+  double    t;
+  mpz_t     x;
+
+  SPEED_RESTRICT_COND (s->size >= 1);
+  SPEED_RESTRICT_COND (speed_randinit (s, rstate));
+
+  /* s->size bits of seed */
+  mpz_init_set_n (x, s->xp, s->size);
+  mpz_fdiv_r_2exp (x, x, (unsigned long) s->size);
+
+  /* cache priming */
+  gmp_randseed (rstate, x);
+
+  speed_starttime ();
+  i = s->reps;
+  do
+    gmp_randseed (rstate, x);
+  while (--i != 0);
+  t = speed_endtime ();
+
+  gmp_randclear (rstate);
+  mpz_clear (x);
+  return t;
+}
+
+double
+speed_gmp_randseed_ui (struct speed_params *s)
+{
+  gmp_randstate_t  rstate;
+  unsigned  i, j;
+  double    t;
+
+  SPEED_RESTRICT_COND (speed_randinit (s, rstate));
+
+  /* cache priming */
+  gmp_randseed_ui (rstate, 123L);
+
+  speed_starttime ();
+  i = s->reps;
+  j = 0;
+  do
+    {
+      gmp_randseed_ui (rstate, (unsigned long) s->xp_block[j]);
+      j++;
+      if (j >= SPEED_BLOCK_SIZE)
+	j = 0;
+    }
+  while (--i != 0);
+  t = speed_endtime ();
+
+  gmp_randclear (rstate);
+  return t;
+}
+
+double
+speed_mpz_urandomb (struct speed_params *s)
+{
+  gmp_randstate_t  rstate;
+  mpz_t     z;
+  unsigned  i;
+  double    t;
+
+  SPEED_RESTRICT_COND (s->size >= 0);
+  SPEED_RESTRICT_COND (speed_randinit (s, rstate));
+
+  mpz_init (z);
+
+  /* cache priming */
+  mpz_urandomb (z, rstate, (unsigned long) s->size);
+  mpz_urandomb (z, rstate, (unsigned long) s->size);
+
+  speed_starttime ();
+  i = s->reps;
+  do
+    mpz_urandomb (z, rstate, (unsigned long) s->size);
+  while (--i != 0);
+  t = speed_endtime ();
+
+  mpz_clear (z);
+  gmp_randclear (rstate);
+  return t;
+}
diff --git a/third_party/gmp/tune/div_qr_1_tune.c b/third_party/gmp/tune/div_qr_1_tune.c
new file mode 100644
index 0000000..ef680ee
--- /dev/null
+++ b/third_party/gmp/tune/div_qr_1_tune.c
@@ -0,0 +1,46 @@
+/* mpn/generic/div_qr_1, using tuned threshold and method.
+
+Copyright 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define TUNE_PROGRAM_BUILD 1
+
+#include "gmp-impl.h"
+
+mp_limb_t mpn_div_qr_1n_pi1_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t, mp_limb_t);
+mp_limb_t mpn_div_qr_1n_pi1_2 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t, mp_limb_t);
+
+#if !HAVE_NATIVE_mpn_div_qr_1n_pi1
+#define __gmpn_div_qr_1n_pi1 \
+  (div_qr_1n_pi1_method == 1 ? mpn_div_qr_1n_pi1_1 : mpn_div_qr_1n_pi1_2)
+#endif
+
+#undef mpn_div_qr_1
+#define mpn_div_qr_1 mpn_div_qr_1_tune
+
+#include "mpn/generic/div_qr_1.c"
diff --git a/third_party/gmp/tune/div_qr_1n_pi1_1.c b/third_party/gmp/tune/div_qr_1n_pi1_1.c
new file mode 100644
index 0000000..e64a3c7
--- /dev/null
+++ b/third_party/gmp/tune/div_qr_1n_pi1_1.c
@@ -0,0 +1,38 @@
+/* mpn/generic/div_qr_1n_pi1.c method 1.
+
+Copyright 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#undef DIV_QR_1N_METHOD
+#define DIV_QR_1N_METHOD 1
+#undef mpn_div_qr_1n_pi1
+#define mpn_div_qr_1n_pi1 mpn_div_qr_1n_pi1_1
+
+#include "mpn/generic/div_qr_1n_pi1.c"
diff --git a/third_party/gmp/tune/div_qr_1n_pi1_2.c b/third_party/gmp/tune/div_qr_1n_pi1_2.c
new file mode 100644
index 0000000..c5432ea
--- /dev/null
+++ b/third_party/gmp/tune/div_qr_1n_pi1_2.c
@@ -0,0 +1,38 @@
+/* mpn/generic/div_qr_1n_pi1.c method 2.
+
+Copyright 2013 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#undef DIV_QR_1N_METHOD
+#define DIV_QR_1N_METHOD 2
+#undef mpn_div_qr_1n_pi1
+#define mpn_div_qr_1n_pi1 mpn_div_qr_1n_pi1_2
+
+#include "mpn/generic/div_qr_1n_pi1.c"
diff --git a/third_party/gmp/tune/divrem1div.c b/third_party/gmp/tune/divrem1div.c
new file mode 100644
index 0000000..0089971
--- /dev/null
+++ b/third_party/gmp/tune/divrem1div.c
@@ -0,0 +1,41 @@
+/* mpn/generic/divrem_1.c forced to use plain udiv_qrnnd.
+
+Copyright 2000, 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define OPERATION_divrem_1
+
+#include "gmp-impl.h"
+
+#undef DIVREM_1_NORM_THRESHOLD
+#undef DIVREM_1_UNNORM_THRESHOLD
+#define DIVREM_1_NORM_THRESHOLD    MP_SIZE_T_MAX
+#define DIVREM_1_UNNORM_THRESHOLD  MP_SIZE_T_MAX
+#define __gmpn_divrem_1  mpn_divrem_1_div
+
+#include "mpn/generic/divrem_1.c"
diff --git a/third_party/gmp/tune/divrem1inv.c b/third_party/gmp/tune/divrem1inv.c
new file mode 100644
index 0000000..82c8528
--- /dev/null
+++ b/third_party/gmp/tune/divrem1inv.c
@@ -0,0 +1,41 @@
+/* mpn/generic/divrem_1.c forced to use mul-by-inverse udiv_qrnnd_preinv.
+
+Copyright 2000, 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define OPERATION_divrem_1
+
+#include "gmp-impl.h"
+
+#undef DIVREM_1_NORM_THRESHOLD
+#undef DIVREM_1_UNNORM_THRESHOLD
+#define DIVREM_1_NORM_THRESHOLD    0
+#define DIVREM_1_UNNORM_THRESHOLD  0
+#define __gmpn_divrem_1  mpn_divrem_1_inv
+
+#include "mpn/generic/divrem_1.c"
diff --git a/third_party/gmp/tune/divrem2div.c b/third_party/gmp/tune/divrem2div.c
new file mode 100644
index 0000000..8331d8f
--- /dev/null
+++ b/third_party/gmp/tune/divrem2div.c
@@ -0,0 +1,40 @@
+/* mpn/generic/divrem_2.c forced to use plain udiv_qrnnd. */
+
+/*
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#ifdef DIVREM_2_THRESHOLD
+#undef DIVREM_2_THRESHOLD
+#endif
+#define DIVREM_2_THRESHOLD  MP_SIZE_T_MAX
+#define __gmpn_divrem_2     mpn_divrem_2_div
+
+#include "mpn/generic/divrem_2.c"
diff --git a/third_party/gmp/tune/divrem2inv.c b/third_party/gmp/tune/divrem2inv.c
new file mode 100644
index 0000000..8ae87f5
--- /dev/null
+++ b/third_party/gmp/tune/divrem2inv.c
@@ -0,0 +1,40 @@
+/* mpn/generic/divrem_2.c forced to use udiv_qrnnd_preinv. */
+
+/*
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#ifdef DIVREM_2_THRESHOLD
+#undef DIVREM_2_THRESHOLD
+#endif
+#define DIVREM_2_THRESHOLD  0
+#define __gmpn_divrem_2     mpn_divrem_2_inv
+
+#include "mpn/generic/divrem_2.c"
diff --git a/third_party/gmp/tune/freq.c b/third_party/gmp/tune/freq.c
new file mode 100644
index 0000000..ee38506
--- /dev/null
+++ b/third_party/gmp/tune/freq.c
@@ -0,0 +1,893 @@
+/* CPU frequency determination.
+
+Copyright 1999-2004 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+/* Currently we don't get a CPU frequency on the following systems,
+
+   alphaev5-cray-unicosmk2.0.6.X
+       times() has been seen at 13.33 ns (75 MHz), which is probably not the
+       cpu frequency.  Measuring the cycle counter against that would be
+       possible though.  But currently we don't use the cycle counter due to
+       unicos having int==8bytes where tune/alpha.asm assumes int==4bytes.
+
+   m68040-unknown-netbsd1.4.1
+       Not sure if the system even knows the cpu frequency.  There's no
+       cycle counter to measure, though we could perhaps make a loop taking
+       a known number of cycles and measure that.
+
+   power-ibm-aix4.2.1.0
+   power2-ibm-aix4.3.1.0
+   powerpc604-ibm-aix4.3.1.0
+   powerpc604-ibm-aix4.3.3.0
+   powerpc630-ibm-aix4.3.3.0
+   powerpc-unknown-netbsd1.6
+       Don't know where any info hides on these.  mftb is not related to the
+       cpu frequency so doesn't help.
+
+   sparc-unknown-linux-gnu [maybe]
+       Don't know where any info hides on this.
+
+   t90-cray-unicos10.0.X
+       The times() call seems to be for instance 2.22 nanoseconds, which
+       might be the cpu frequency (450 mhz), but need to confirm that.
+
+*/
+
+#include "config.h"
+
+#if HAVE_INVENT_H
+#include <invent.h> /* for IRIX invent_cpuinfo_t */
+#endif
+
+#include <stdio.h>
+#include <stdlib.h> /* for getenv, qsort */
+#include <string.h> /* for memcmp */
+
+#if HAVE_UNISTD_H
+#include <unistd.h> /* for sysconf */
+#endif
+
+#include <sys/types.h>
+
+#if HAVE_SYS_ATTRIBUTES_H
+#include <sys/attributes.h>   /* for IRIX attr_get(), needs sys/types.h */
+#endif
+
+#if HAVE_SYS_IOGRAPH_H
+#include <sys/iograph.h>      /* for IRIX INFO_LBL_DETAIL_INVENT */
+#endif
+
+#if HAVE_SYS_PARAM_H     /* for constants needed by NetBSD <sys/sysctl.h> */
+#include <sys/param.h>   /* and needed by HPUX <sys/pstat.h> */
+#endif
+
+#if HAVE_SYS_PSTAT_H
+#include <sys/pstat.h>   /* for HPUX pstat_getprocessor() */
+#endif
+
+#if HAVE_SYS_SYSCTL_H
+#include <sys/sysctl.h>  /* for sysctlbyname() */
+#endif
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>  /* for struct timeval */
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+
+#if HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>  /* for struct rusage */
+#endif
+
+#if HAVE_SYS_PROCESSOR_H
+#include <sys/processor.h>  /* for solaris processor_info_t */
+#endif
+
+/* On AIX 5.1 with gcc 2.9-aix51-020209 in -maix64 mode, <sys/sysinfo.h>
+   gets an error about "fill" in "struct cpuinfo" having a negative size,
+   apparently due to __64BIT_KERNEL not being defined because _KERNEL is not
+   defined.  Avoid this file if we don't actually need it, which we don't on
+   AIX since there's no getsysinfo there.  */
+#if HAVE_SYS_SYSINFO_H && HAVE_GETSYSINFO
+#include <sys/sysinfo.h>  /* for OSF getsysinfo */
+#endif
+
+#if HAVE_MACHINE_HAL_SYSINFO_H
+#include <machine/hal_sysinfo.h>  /* for OSF GSI_CPU_INFO, struct cpu_info */
+#endif
+
+/* Remove definitions from NetBSD <sys/param.h>, to avoid conflicts with
+   gmp-impl.h. */
+#ifdef MIN
+#undef MIN
+#endif
+#ifdef MAX
+#undef MAX
+#endif
+
+#include "gmp-impl.h"
+
+#include "speed.h"
+
+
+#define HELP(str)                       \
+  if (help)                             \
+    {                                   \
+      printf ("    - %s\n", str);       \
+      return 0;                         \
+    }
+
+
+/* GMP_CPU_FREQUENCY environment variable.  Should be in Hertz and can be
+   floating point, for example "450e6". */
+static int
+freq_environment (int help)
+{
+  char  *e;
+
+  HELP ("environment variable GMP_CPU_FREQUENCY (in Hertz)");
+
+  e = getenv ("GMP_CPU_FREQUENCY");
+  if (e == NULL)
+    return 0;
+
+  speed_cycletime = 1.0 / atof (e);
+
+  if (speed_option_verbose)
+    printf ("Using GMP_CPU_FREQUENCY %.2f for cycle time %.3g\n",
+            atof (e), speed_cycletime);
+
+  return 1;
+}
+
+
+/* getsysinfo is available on OSF, or 4.0 and up at least.
+   The man page (on 4.0) suggests a 0 return indicates information not
+   available, but that seems to be the normal return for GSI_CPU_INFO.  */
+static int
+freq_getsysinfo (int help)
+{
+#if HAVE_GETSYSINFO
+  struct cpu_info  c;
+  int              start;
+
+  HELP ("getsysinfo() GSI_CPU_INFO");
+
+  start = 0;
+  if (getsysinfo (GSI_CPU_INFO, (caddr_t) &c, sizeof (c),
+                  &start, NULL, NULL) != -1)
+    {
+      speed_cycletime = 1e-6 / (double) c.mhz;
+      if (speed_option_verbose)
+        printf ("Using getsysinfo() GSI_CPU_INFO %u for cycle time %.3g\n",
+                c.mhz, speed_cycletime);
+      return 1;
+    }
+#endif
+  return 0;
+}
+
+
+/* In HPUX 10 and up, pstat_getprocessor() psp_iticksperclktick is the
+   number of CPU cycles (ie. the CR16 register) per CLK_TCK.  HPUX 9 doesn't
+   have that field in pst_processor though, and has no apparent
+   equivalent.  */
+
+static int
+freq_pstat_getprocessor (int help)
+{
+#if HAVE_PSTAT_GETPROCESSOR && HAVE_PSP_ITICKSPERCLKTICK
+  struct pst_processor  p;
+
+  HELP ("pstat_getprocessor() psp_iticksperclktick");
+
+  if (pstat_getprocessor (&p, sizeof(p), 1, 0) != -1)
+    {
+      long  c = clk_tck();
+      speed_cycletime = 1.0 / (c * p.psp_iticksperclktick);
+      if (speed_option_verbose)
+        printf ("Using pstat_getprocessor() psp_iticksperclktick %lu and clk_tck %ld for cycle time %.3g\n",
+                (unsigned long) p.psp_iticksperclktick, c,
+                speed_cycletime);
+      return 1;
+    }
+#endif
+  return 0;
+}
+
+
+/* i386 FreeBSD 2.2.8 sysctlbyname machdep.i586_freq is in Hertz.
+   There's no obvious defines available to get this from plain sysctl.  */
+static int
+freq_sysctlbyname_i586_freq (int help)
+{
+#if HAVE_SYSCTLBYNAME
+  unsigned  val;
+  size_t    size;
+
+  HELP ("sysctlbyname() machdep.i586_freq");
+
+  size = sizeof(val);
+  if (sysctlbyname ("machdep.i586_freq", &val, &size, NULL, 0) == 0
+      && size == sizeof(val))
+    {
+      speed_cycletime = 1.0 / (double) val;
+      if (speed_option_verbose)
+        printf ("Using sysctlbyname() machdep.i586_freq %u for cycle time %.3g\n",
+                val, speed_cycletime);
+      return 1;
+    }
+#endif
+  return 0;
+}
+
+
+/* i368 FreeBSD 3.3 sysctlbyname machdep.tsc_freq is in Hertz.
+   There's no obvious defines to get this from plain sysctl.  */
+
+static int
+freq_sysctlbyname_tsc_freq (int help)
+{
+#if HAVE_SYSCTLBYNAME
+  unsigned  val;
+  size_t    size;
+
+  HELP ("sysctlbyname() machdep.tsc_freq");
+
+  size = sizeof(val);
+  if (sysctlbyname ("machdep.tsc_freq", &val, &size, NULL, 0) == 0
+      && size == sizeof(val))
+    {
+      speed_cycletime = 1.0 / (double) val;
+      if (speed_option_verbose)
+        printf ("Using sysctlbyname() machdep.tsc_freq %u for cycle time %.3g\n",
+                val, speed_cycletime);
+      return 1;
+    }
+#endif
+  return 0;
+}
+
+
+/* Apple powerpc Darwin 1.3 sysctl hw.cpufrequency is in hertz.  For some
+   reason only seems to be available from sysctl(), not sysctlbyname().  */
+
+static int
+freq_sysctl_hw_cpufrequency (int help)
+{
+#if HAVE_SYSCTL && defined (CTL_HW) && defined (HW_CPU_FREQ)
+  int       mib[2];
+  unsigned  val;
+  size_t    size;
+
+  HELP ("sysctl() hw.cpufrequency");
+
+  mib[0] = CTL_HW;
+  mib[1] = HW_CPU_FREQ;
+  size = sizeof(val);
+  if (sysctl (mib, 2, &val, &size, NULL, 0) == 0)
+    {
+      speed_cycletime = 1.0 / (double) val;
+      if (speed_option_verbose)
+        printf ("Using sysctl() hw.cpufrequency %u for cycle time %.3g\n",
+                val, speed_cycletime);
+      return 1;
+    }
+#endif
+  return 0;
+}
+
+
+/* The following ssyctl hw.model strings have been observed,
+
+       Alpha FreeBSD 4.1:   Digital AlphaPC 164LX 599 MHz
+       NetBSD 1.4:          Digital AlphaPC 164LX 599 MHz
+       NetBSD 1.6.1:        CY7C601 @ 40 MHz, TMS390C602A FPU
+
+   NetBSD 1.4 doesn't seem to have sysctlbyname, so sysctl() is used.  */
+
+static int
+freq_sysctl_hw_model (int help)
+{
+#if HAVE_SYSCTL && defined (CTL_HW) && defined (HW_MODEL)
+  int       mib[2];
+  char      str[128];
+  unsigned  val;
+  size_t    size;
+  char      *p;
+  int       end;
+
+  HELP ("sysctl() hw.model");
+
+  mib[0] = CTL_HW;
+  mib[1] = HW_MODEL;
+  size = sizeof(str);
+  if (sysctl (mib, 2, str, &size, NULL, 0) == 0)
+    {
+      for (p = str; *p != '\0'; p++)
+        {
+          end = 0;
+          if (sscanf (p, "%u MHz%n", &val, &end) == 1 && end != 0)
+            {
+              speed_cycletime = 1e-6 / (double) val;
+              if (speed_option_verbose)
+                printf ("Using sysctl() hw.model %u for cycle time %.3g\n",
+                        val, speed_cycletime);
+              return 1;
+            }
+        }
+    }
+#endif
+  return 0;
+}
+
+
+/* /proc/cpuinfo for linux kernel.
+
+   Linux doesn't seem to have any system call to get the CPU frequency, at
+   least not in 2.0.x or 2.2.x, so it's necessary to read /proc/cpuinfo.
+
+   i386 2.0.36 - "bogomips" is the CPU frequency.
+
+   i386 2.2.13 - has both "cpu MHz" and "bogomips", and it's "cpu MHz" which
+                 is the frequency.
+
+   alpha 2.2.5 - "cycle frequency [Hz]" seems to be right, "BogoMIPS" is
+                 very slightly different.
+
+   alpha 2.2.18pre21 - "cycle frequency [Hz]" is 0 on at least one system,
+                 "BogoMIPS" seems near enough.
+
+   powerpc 2.2.19 - "clock" is the frequency, bogomips is something weird
+  */
+
+static int
+freq_proc_cpuinfo (int help)
+{
+  FILE    *fp;
+  char    buf[128];
+  double  val;
+  int     ret = 0;
+  int     end;
+
+  HELP ("linux kernel /proc/cpuinfo file, cpu MHz or bogomips");
+
+  if ((fp = fopen ("/proc/cpuinfo", "r")) != NULL)
+    {
+      while (fgets (buf, sizeof (buf), fp) != NULL)
+        {
+          if (sscanf (buf, "cycle frequency [Hz]    : %lf", &val) == 1
+              && val != 0.0)
+            {
+              speed_cycletime = 1.0 / val;
+              if (speed_option_verbose)
+                printf ("Using /proc/cpuinfo \"cycle frequency\" %.2f for cycle time %.3g\n", val, speed_cycletime);
+              ret = 1;
+              break;
+            }
+          if (sscanf (buf, "cpu MHz : %lf\n", &val) == 1)
+            {
+              speed_cycletime = 1e-6 / val;
+              if (speed_option_verbose)
+                printf ("Using /proc/cpuinfo \"cpu MHz\" %.2f for cycle time %.3g\n", val, speed_cycletime);
+              ret = 1;
+              break;
+            }
+          end = 0;
+          if (sscanf (buf, "clock : %lfMHz\n%n", &val, &end) == 1 && end != 0)
+            {
+              speed_cycletime = 1e-6 / val;
+              if (speed_option_verbose)
+                printf ("Using /proc/cpuinfo \"clock\" %.2f for cycle time %.3g\n", val, speed_cycletime);
+              ret = 1;
+              break;
+            }
+          if (sscanf (buf, "bogomips : %lf\n", &val) == 1
+              || sscanf (buf, "BogoMIPS : %lf\n", &val) == 1)
+            {
+              speed_cycletime = 1e-6 / val;
+              if (speed_option_verbose)
+                printf ("Using /proc/cpuinfo \"bogomips\" %.2f for cycle time %.3g\n", val, speed_cycletime);
+              ret = 1;
+              break;
+            }
+        }
+      fclose (fp);
+    }
+  return ret;
+}
+
+
+/* /bin/sysinfo for SunOS 4.
+   Prints a line like: cpu0 is a "75 MHz TI,TMS390Z55" CPU */
+static int
+freq_sunos_sysinfo (int help)
+{
+  int     ret = 0;
+#if HAVE_POPEN
+  FILE    *fp;
+  char    buf[128];
+  double  val;
+  int     end;
+
+  HELP ("SunOS /bin/sysinfo program output, cpu0");
+
+  /* Error messages are sent to /dev/null in case /bin/sysinfo doesn't
+     exist.  The brackets are necessary for some shells. */
+  if ((fp = popen ("(/bin/sysinfo) 2>/dev/null", "r")) != NULL)
+    {
+      while (fgets (buf, sizeof (buf), fp) != NULL)
+        {
+          end = 0;
+          if (sscanf (buf, " cpu0 is a \"%lf MHz%n", &val, &end) == 1
+              && end != 0)
+            {
+              speed_cycletime = 1e-6 / val;
+              if (speed_option_verbose)
+                printf ("Using /bin/sysinfo \"cpu0 MHz\" %.2f for cycle time %.3g\n", val, speed_cycletime);
+              ret = 1;
+              break;
+            }
+        }
+      pclose (fp);
+    }
+#endif
+  return ret;
+}
+
+
+/* "/etc/hw -r cpu" for SCO OpenUnix 8, printing a line like
+	The speed of the CPU is approximately 450MHz
+ */
+static int
+freq_sco_etchw (int help)
+{
+  int     ret = 0;
+#if HAVE_POPEN
+  FILE    *fp;
+  char    buf[128];
+  double  val;
+  int     end;
+
+  HELP ("SCO /etc/hw program output");
+
+  /* Error messages are sent to /dev/null in case /etc/hw doesn't exist.
+     The brackets are necessary for some shells. */
+  if ((fp = popen ("(/etc/hw -r cpu) 2>/dev/null", "r")) != NULL)
+    {
+      while (fgets (buf, sizeof (buf), fp) != NULL)
+        {
+          end = 0;
+          if (sscanf (buf, " The speed of the CPU is approximately %lfMHz%n",
+                      &val, &end) == 1 && end != 0)
+            {
+              speed_cycletime = 1e-6 / val;
+              if (speed_option_verbose)
+                printf ("Using /etc/hw %.2f MHz, for cycle time %.3g\n",
+                        val, speed_cycletime);
+              ret = 1;
+              break;
+            }
+        }
+      pclose (fp);
+    }
+#endif
+  return ret;
+}
+
+
+/* attr_get("/hw/cpunum/0",INFO_LBL_DETAIL_INVENT) ic_cpu_info.cpufq for
+   IRIX 6.5.  Past versions don't have INFO_LBL_DETAIL_INVENT,
+   invent_cpuinfo_t, or /hw/cpunum/0.
+
+   The same information is available from the "hinv -c processor" command,
+   but it seems better to make a system call where possible. */
+
+static int
+freq_attr_get_invent (int help)
+{
+  int     ret = 0;
+#if HAVE_ATTR_GET && HAVE_INVENT_H && defined (INFO_LBL_DETAIL_INVENT)
+  invent_cpuinfo_t  inv;
+  int               len, val;
+
+  HELP ("attr_get(\"/hw/cpunum/0\") ic_cpu_info.cpufq");
+
+  len = sizeof (inv);
+  if (attr_get ("/hw/cpunum/0", INFO_LBL_DETAIL_INVENT,
+                (char *) &inv, &len, 0) == 0
+      && len == sizeof (inv)
+      && inv.ic_gen.ig_invclass == INV_PROCESSOR)
+    {
+      val = inv.ic_cpu_info.cpufq;
+      speed_cycletime = 1e-6 / val;
+      if (speed_option_verbose)
+        printf ("Using attr_get(\"/hw/cpunum/0\") ic_cpu_info.cpufq %d MHz for cycle time %.3g\n", val, speed_cycletime);
+      ret = 1;
+    }
+#endif
+  return ret;
+}
+
+
+/* FreeBSD on i386 gives a line like the following at bootup, and which can
+   be read back from /var/run/dmesg.boot.
+
+       CPU: AMD Athlon(tm) Processor (755.29-MHz 686-class CPU)
+       CPU: Pentium 4 (1707.56-MHz 686-class CPU)
+       CPU: i486 DX4 (486-class CPU)
+
+   This is useful on FreeBSD 4.x, where there's no sysctl machdep.tsc_freq
+   or machdep.i586_freq.
+
+   It's better to use /var/run/dmesg.boot than to run /sbin/dmesg, since the
+   latter prints the current system message buffer, which is a limited size
+   and can wrap around if the system is up for a long time.  */
+
+static int
+freq_bsd_dmesg (int help)
+{
+  FILE    *fp;
+  char    buf[256], *p;
+  double  val;
+  int     ret = 0;
+  int     end;
+
+  HELP ("BSD /var/run/dmesg.boot file");
+
+  if ((fp = fopen ("/var/run/dmesg.boot", "r")) != NULL)
+    {
+      while (fgets (buf, sizeof (buf), fp) != NULL)
+        {
+          if (memcmp (buf, "CPU:", 4) == 0)
+            {
+              for (p = buf; *p != '\0'; p++)
+                {
+                  end = 0;
+                  if (sscanf (p, "(%lf-MHz%n", &val, &end) == 1 && end != 0)
+                    {
+                      speed_cycletime = 1e-6 / val;
+                      if (speed_option_verbose)
+                        printf ("Using /var/run/dmesg.boot CPU: %.2f MHz for cycle time %.3g\n", val, speed_cycletime);
+                      ret = 1;
+                      break;
+                    }
+                }
+            }
+        }
+      fclose (fp);
+    }
+  return ret;
+}
+
+
+/* "hinv -c processor" for IRIX.  The following lines have been seen,
+
+              1 150 MHZ IP20 Processor
+              2 195 MHZ IP27 Processors
+              Processor 0: 500 MHZ IP35
+
+   This information is available from attr_get() on IRIX 6.5 (see above),
+   but on IRIX 6.2 it's not clear where to look, so fall back on
+   parsing.  */
+
+static int
+freq_irix_hinv (int help)
+{
+  int     ret = 0;
+#if HAVE_POPEN
+  FILE    *fp;
+  char    buf[128];
+  double  val;
+  int     nproc, end;
+
+  HELP ("IRIX \"hinv -c processor\" output");
+
+  /* Error messages are sent to /dev/null in case hinv doesn't exist.  The
+     brackets are necessary for some shells. */
+  if ((fp = popen ("(hinv -c processor) 2>/dev/null", "r")) != NULL)
+    {
+      while (fgets (buf, sizeof (buf), fp) != NULL)
+        {
+          end = 0;
+          if (sscanf (buf, "Processor 0: %lf MHZ%n", &val, &end) == 1
+              && end != 0)
+            {
+            found:
+              speed_cycletime = 1e-6 / val;
+              if (speed_option_verbose)
+                printf ("Using hinv -c processor \"%.2f MHZ\" for cycle time %.3g\n", val, speed_cycletime);
+              ret = 1;
+              break;
+            }
+          end = 0;
+          if (sscanf (buf, "%d %lf MHZ%n", &nproc, &val, &end) == 2
+              && end != 0)
+            goto found;
+        }
+      pclose (fp);
+    }
+#endif
+  return ret;
+}
+
+
+/* processor_info() for Solaris.  "psrinfo" is the command-line interface to
+   this.  "prtconf -vp" gives similar information.
+
+   Apple Darwin has a processor_info, but in an incompatible style.  It
+   doesn't have <sys/processor.h>, so test for that.  */
+
+static int
+freq_processor_info (int help)
+{
+#if HAVE_PROCESSOR_INFO && HAVE_SYS_PROCESSOR_H
+  processor_info_t  p;
+  int  i, n, mhz = 0;
+
+  HELP ("processor_info() pi_clock");
+
+  n = sysconf (_SC_NPROCESSORS_CONF);
+  for (i = 0; i < n; i++)
+    {
+      if (processor_info (i, &p) != 0)
+        continue;
+      if (p.pi_state != P_ONLINE)
+        continue;
+
+      if (mhz != 0 && p.pi_clock != mhz)
+        {
+          fprintf (stderr,
+                   "freq_processor_info(): There's more than one CPU and they have different clock speeds\n");
+          return 0;
+        }
+
+      mhz = p.pi_clock;
+    }
+
+  speed_cycletime = 1.0e-6 / (double) mhz;
+
+  if (speed_option_verbose)
+    printf ("Using processor_info() %d mhz for cycle time %.3g\n",
+            mhz, speed_cycletime);
+  return 1;
+
+#else
+  return 0;
+#endif
+}
+
+
+#if HAVE_SPEED_CYCLECOUNTER && HAVE_GETTIMEOFDAY
+static double
+freq_measure_gettimeofday_one (void)
+{
+#define call_gettimeofday(t)   gettimeofday (&(t), NULL)
+#define timeval_tv_sec(t)      ((t).tv_sec)
+#define timeval_tv_usec(t)     ((t).tv_usec)
+  FREQ_MEASURE_ONE ("gettimeofday", struct timeval,
+                    call_gettimeofday, speed_cyclecounter,
+                    timeval_tv_sec, timeval_tv_usec);
+}
+#endif
+
+#if HAVE_SPEED_CYCLECOUNTER && HAVE_GETRUSAGE
+static double
+freq_measure_getrusage_one (void)
+{
+#define call_getrusage(t)   getrusage (0, &(t))
+#define rusage_tv_sec(t)    ((t).ru_utime.tv_sec)
+#define rusage_tv_usec(t)   ((t).ru_utime.tv_usec)
+  FREQ_MEASURE_ONE ("getrusage", struct rusage,
+                    call_getrusage, speed_cyclecounter,
+                    rusage_tv_sec, rusage_tv_usec);
+}
+#endif
+
+
+/* MEASURE_MATCH is how many readings within MEASURE_TOLERANCE of each other
+   are required.  This must be at least 2.  */
+#define MEASURE_MAX_ATTEMPTS   20
+#define MEASURE_TOLERANCE      1.005  /* 0.5% */
+#define MEASURE_MATCH          3
+
+double
+freq_measure (const char *name, double (*one) (void))
+{
+  double  t[MEASURE_MAX_ATTEMPTS];
+  int     i, j;
+
+  for (i = 0; i < numberof (t); i++)
+    {
+      t[i] = (*one) ();
+
+      qsort (t, i+1, sizeof(t[0]), (qsort_function_t) double_cmp_ptr);
+      if (speed_option_verbose >= 3)
+        for (j = 0; j <= i; j++)
+          printf ("   t[%d] is %.6g\n", j, t[j]);
+
+      for (j = 0; j+MEASURE_MATCH-1 <= i; j++)
+        {
+          if (t[j+MEASURE_MATCH-1] <= t[j] * MEASURE_TOLERANCE)
+            {
+              /* use the average of the range found */
+                return (t[j+MEASURE_MATCH-1] + t[j]) / 2.0;
+            }
+        }
+    }
+  return -1.0;
+}
+
+static int
+freq_measure_getrusage (int help)
+{
+#if HAVE_SPEED_CYCLECOUNTER && HAVE_GETRUSAGE
+  double  cycletime;
+
+  if (! getrusage_microseconds_p ())
+    return 0;
+  if (! cycles_works_p ())
+    return 0;
+
+  HELP ("cycle counter measured with microsecond getrusage()");
+
+  cycletime = freq_measure ("getrusage", freq_measure_getrusage_one);
+  if (cycletime == -1.0)
+    return 0;
+
+  speed_cycletime = cycletime;
+  if (speed_option_verbose)
+    printf ("Using getrusage() measured cycle counter %.4g (%.2f MHz)\n",
+            speed_cycletime, 1e-6/speed_cycletime);
+  return 1;
+
+#else
+  return 0;
+#endif
+}
+
+static int
+freq_measure_gettimeofday (int help)
+{
+#if HAVE_SPEED_CYCLECOUNTER && HAVE_GETTIMEOFDAY
+  double  cycletime;
+
+  if (! gettimeofday_microseconds_p ())
+    return 0;
+  if (! cycles_works_p ())
+    return 0;
+
+  HELP ("cycle counter measured with microsecond gettimeofday()");
+
+  cycletime = freq_measure ("gettimeofday", freq_measure_gettimeofday_one);
+  if (cycletime == -1.0)
+    return 0;
+
+  speed_cycletime = cycletime;
+  if (speed_option_verbose)
+    printf ("Using gettimeofday() measured cycle counter %.4g (%.2f MHz)\n",
+            speed_cycletime, 1e-6/speed_cycletime);
+  return 1;
+#else
+  return 0;
+#endif
+}
+
+
+/* Each function returns 1 if it succeeds in setting speed_cycletime, or 0
+   if not.
+
+   In general system call tests are first since they're fast, then file
+   tests, then tests running programs.  Necessary exceptions to this rule
+   are noted.  The measuring is last since it's time consuming, and rather
+   wasteful of cpu.  */
+
+static int
+freq_all (int help)
+{
+  return
+    /* This should be first, so an environment variable can override
+       anything the system gives. */
+    freq_environment (help)
+
+    || freq_attr_get_invent (help)
+    || freq_getsysinfo (help)
+    || freq_pstat_getprocessor (help)
+    || freq_sysctl_hw_model (help)
+    || freq_sysctl_hw_cpufrequency (help)
+    || freq_sysctlbyname_i586_freq (help)
+    || freq_sysctlbyname_tsc_freq (help)
+
+    /* SCO openunix 8 puts a dummy pi_clock==16 in processor_info, so be
+       sure to check /etc/hw before that function. */
+    || freq_sco_etchw (help)
+
+    || freq_processor_info (help)
+    || freq_proc_cpuinfo (help)
+    || freq_bsd_dmesg (help)
+    || freq_irix_hinv (help)
+    || freq_sunos_sysinfo (help)
+    || freq_measure_getrusage (help)
+    || freq_measure_gettimeofday (help);
+}
+
+
+void
+speed_cycletime_init (void)
+{
+  static int  attempted = 0;
+
+  if (attempted)
+    return;
+  attempted = 1;
+
+  if (freq_all (0))
+    return;
+
+  if (speed_option_verbose)
+    printf ("CPU frequency couldn't be determined\n");
+}
+
+
+void
+speed_cycletime_fail (const char *str)
+{
+  fprintf (stderr, "Measuring with: %s\n", speed_time_string);
+  fprintf (stderr, "%s,\n", str);
+  fprintf (stderr, "but none of the following are available,\n");
+  freq_all (1);
+  abort ();
+}
+
+/* speed_time_init leaves speed_cycletime set to either 0.0 or 1.0 when the
+   CPU frequency is unknown.  0.0 is when the time base is in seconds, so
+   that's no good if cycles are wanted.  1.0 is when the time base is in
+   cycles, which conversely is no good if seconds are wanted.  */
+void
+speed_cycletime_need_cycles (void)
+{
+  speed_time_init ();
+  if (speed_cycletime == 0.0)
+    speed_cycletime_fail
+      ("Need to know CPU frequency to give times in cycles");
+}
+void
+speed_cycletime_need_seconds (void)
+{
+  speed_time_init ();
+  if (speed_cycletime == 1.0)
+    speed_cycletime_fail
+      ("Need to know CPU frequency to convert cycles to seconds");
+}
diff --git a/third_party/gmp/tune/gcdext_double.c b/third_party/gmp/tune/gcdext_double.c
new file mode 100644
index 0000000..2b2ba15
--- /dev/null
+++ b/third_party/gmp/tune/gcdext_double.c
@@ -0,0 +1,38 @@
+/* mpn/generic/gcdext.c forced to use double limb calculations. */
+
+/*
+Copyright 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#undef GCDEXT_THRESHOLD
+#define GCDEXT_THRESHOLD  0
+#define __gmpn_gcdext  mpn_gcdext_double
+
+#include "../mpn/generic/gcdext.c"
diff --git a/third_party/gmp/tune/gcdext_single.c b/third_party/gmp/tune/gcdext_single.c
new file mode 100644
index 0000000..3c1d28c
--- /dev/null
+++ b/third_party/gmp/tune/gcdext_single.c
@@ -0,0 +1,38 @@
+/* mpn/generic/gcdext.c forced to use single limb calculations. */
+
+/*
+Copyright 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#undef GCDEXT_THRESHOLD
+#define GCDEXT_THRESHOLD  MP_SIZE_T_MAX
+#define __gmpn_gcdext  mpn_gcdext_single
+
+#include "../mpn/generic/gcdext.c"
diff --git a/third_party/gmp/tune/gcdextod.c b/third_party/gmp/tune/gcdextod.c
new file mode 100644
index 0000000..f40cae6
--- /dev/null
+++ b/third_party/gmp/tune/gcdextod.c
@@ -0,0 +1,39 @@
+/* mpn/generic/gcdext.c forced to one double limb step. */
+
+/*
+Copyright 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#undef GCDEXT_THRESHOLD
+#define GCDEXT_THRESHOLD  0
+#define WANT_GCDEXT_ONE_STEP 1
+#define __gmpn_gcdext  mpn_gcdext_one_double
+
+#include "../mpn/generic/gcdext.c"
diff --git a/third_party/gmp/tune/gcdextos.c b/third_party/gmp/tune/gcdextos.c
new file mode 100644
index 0000000..f51ff52
--- /dev/null
+++ b/third_party/gmp/tune/gcdextos.c
@@ -0,0 +1,39 @@
+/* mpn/generic/gcdext.c forced to one single limb step. */
+
+/*
+Copyright 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#undef GCDEXT_THRESHOLD
+#define GCDEXT_THRESHOLD  MP_SIZE_T_MAX
+#define WANT_GCDEXT_ONE_STEP 1
+#define __gmpn_gcdext  mpn_gcdext_one_single
+
+#include "../mpn/generic/gcdext.c"
diff --git a/third_party/gmp/tune/hgcd2-1.c b/third_party/gmp/tune/hgcd2-1.c
new file mode 100644
index 0000000..1e8948c
--- /dev/null
+++ b/third_party/gmp/tune/hgcd2-1.c
@@ -0,0 +1,39 @@
+/* mpn/generic/hgcd2.c method 1.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#undef HGCD2_DIV1_METHOD
+#define HGCD2_DIV1_METHOD 1
+#define __gmpn_hgcd2 mpn_hgcd2_1
+/* Not used, but renamed to not get duplicate definitions */
+#define __gmpn_hgcd_mul_matrix1_vector mpn_hgcd_mul_matrix1_vector_1
+
+#include "mpn/generic/hgcd2.c"
diff --git a/third_party/gmp/tune/hgcd2-2.c b/third_party/gmp/tune/hgcd2-2.c
new file mode 100644
index 0000000..bbb123b
--- /dev/null
+++ b/third_party/gmp/tune/hgcd2-2.c
@@ -0,0 +1,39 @@
+/* mpn/generic/hgcd2.c method 2.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#undef HGCD2_DIV1_METHOD
+#define HGCD2_DIV1_METHOD 2
+#define __gmpn_hgcd2 mpn_hgcd2_2
+/* Not used, but renamed to not get duplicate definitions */
+#define __gmpn_hgcd_mul_matrix1_vector mpn_hgcd_mul_matrix1_vector_2
+
+#include "mpn/generic/hgcd2.c"
diff --git a/third_party/gmp/tune/hgcd2-3.c b/third_party/gmp/tune/hgcd2-3.c
new file mode 100644
index 0000000..ac62108
--- /dev/null
+++ b/third_party/gmp/tune/hgcd2-3.c
@@ -0,0 +1,39 @@
+/* mpn/generic/hgcd2.c method 3.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#undef HGCD2_DIV1_METHOD
+#define HGCD2_DIV1_METHOD 3
+#define __gmpn_hgcd2 mpn_hgcd2_3
+/* Not used, but renamed to not get duplicate definitions */
+#define __gmpn_hgcd_mul_matrix1_vector mpn_hgcd_mul_matrix1_vector_3
+
+#include "mpn/generic/hgcd2.c"
diff --git a/third_party/gmp/tune/hgcd2-4.c b/third_party/gmp/tune/hgcd2-4.c
new file mode 100644
index 0000000..ec7f927
--- /dev/null
+++ b/third_party/gmp/tune/hgcd2-4.c
@@ -0,0 +1,39 @@
+/* mpn/generic/hgcd2.c method 4.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#undef HGCD2_DIV1_METHOD
+#define HGCD2_DIV1_METHOD 4
+#define __gmpn_hgcd2 mpn_hgcd2_4
+/* Not used, but renamed to not get duplicate definitions */
+#define __gmpn_hgcd_mul_matrix1_vector mpn_hgcd_mul_matrix1_vector_4
+
+#include "mpn/generic/hgcd2.c"
diff --git a/third_party/gmp/tune/hgcd2-5.c b/third_party/gmp/tune/hgcd2-5.c
new file mode 100644
index 0000000..ed66171
--- /dev/null
+++ b/third_party/gmp/tune/hgcd2-5.c
@@ -0,0 +1,39 @@
+/* mpn/generic/hgcd2.c method 5.
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#undef HGCD2_DIV1_METHOD
+#define HGCD2_DIV1_METHOD 5
+#define __gmpn_hgcd2 mpn_hgcd2_5
+/* Not used, but renamed to not get duplicate definitions */
+#define __gmpn_hgcd_mul_matrix1_vector mpn_hgcd_mul_matrix1_vector_5
+
+#include "mpn/generic/hgcd2.c"
diff --git a/third_party/gmp/tune/hgcd2.c b/third_party/gmp/tune/hgcd2.c
new file mode 100644
index 0000000..146af72
--- /dev/null
+++ b/third_party/gmp/tune/hgcd2.c
@@ -0,0 +1,49 @@
+/* mpn/generic/hgcd2.c for tuning
+
+Copyright 2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define TUNE_PROGRAM_BUILD 1
+
+#include "gmp-impl.h"
+
+hgcd2_func_t mpn_hgcd2_default;
+
+hgcd2_func_t *hgcd2_func = &mpn_hgcd2_default;
+
+int
+mpn_hgcd2 (mp_limb_t ah, mp_limb_t al, mp_limb_t bh, mp_limb_t bl,
+	   struct hgcd_matrix1 *M)
+{
+  return hgcd2_func(ah, al, bh, bl, M);
+}
+
+#undef mpn_hgcd2
+#define mpn_hgcd2 mpn_hgcd2_default
+
+#include "mpn/generic/hgcd2.c"
diff --git a/third_party/gmp/tune/hgcd_appr_lehmer.c b/third_party/gmp/tune/hgcd_appr_lehmer.c
new file mode 100644
index 0000000..aa43a07
--- /dev/null
+++ b/third_party/gmp/tune/hgcd_appr_lehmer.c
@@ -0,0 +1,39 @@
+/* mpn/generic/hgcd_appr.c forced to use Lehmer's quadratic algorithm. */
+
+/*
+Copyright 2010, 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#undef  HGCD_APPR_THRESHOLD
+#define HGCD_APPR_THRESHOLD MP_SIZE_T_MAX
+#define __gmpn_hgcd_appr  mpn_hgcd_appr_lehmer
+#define __gmpn_hgcd_appr_itch mpn_hgcd_appr_lehmer_itch
+
+#include "../mpn/generic/hgcd_appr.c"
diff --git a/third_party/gmp/tune/hgcd_lehmer.c b/third_party/gmp/tune/hgcd_lehmer.c
new file mode 100644
index 0000000..364749d
--- /dev/null
+++ b/third_party/gmp/tune/hgcd_lehmer.c
@@ -0,0 +1,39 @@
+/* mpn/generic/hgcd.c forced to use Lehmer's quadratic algorithm. */
+
+/*
+Copyright 2010 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#undef  HGCD_THRESHOLD
+#define HGCD_THRESHOLD MP_SIZE_T_MAX
+#define __gmpn_hgcd  mpn_hgcd_lehmer
+#define __gmpn_hgcd_itch mpn_hgcd_lehmer_itch
+
+#include "../mpn/generic/hgcd.c"
diff --git a/third_party/gmp/tune/hgcd_reduce_1.c b/third_party/gmp/tune/hgcd_reduce_1.c
new file mode 100644
index 0000000..5052233
--- /dev/null
+++ b/third_party/gmp/tune/hgcd_reduce_1.c
@@ -0,0 +1,40 @@
+/* mpn/generic/hgcd_reduce.c forced to use hgcd. */
+
+/*
+Copyright 2010 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#undef  HGCD_REDUCE_THRESHOLD
+#define HGCD_REDUCE_THRESHOLD MP_SIZE_T_MAX
+#define __gmpn_hgcd_reduce  mpn_hgcd_reduce_1
+#define __gmpn_hgcd_reduce_itch  mpn_hgcd_reduce_1_itch
+
+
+#include "../mpn/generic/hgcd_reduce.c"
diff --git a/third_party/gmp/tune/hgcd_reduce_2.c b/third_party/gmp/tune/hgcd_reduce_2.c
new file mode 100644
index 0000000..5d802e0
--- /dev/null
+++ b/third_party/gmp/tune/hgcd_reduce_2.c
@@ -0,0 +1,39 @@
+/* mpn/generic/hgcd_reduce.c forced to use hgcd_appr. */
+
+/*
+Copyright 2010 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#undef  HGCD_REDUCE_THRESHOLD
+#define HGCD_REDUCE_THRESHOLD 0
+#define __gmpn_hgcd_reduce mpn_hgcd_reduce_2
+#define __gmpn_hgcd_reduce_itch mpn_hgcd_reduce_2_itch
+
+#include "../mpn/generic/hgcd_reduce.c"
diff --git a/third_party/gmp/tune/hppa.asm b/third_party/gmp/tune/hppa.asm
new file mode 100644
index 0000000..fc9d62e
--- /dev/null
+++ b/third_party/gmp/tune/hppa.asm
@@ -0,0 +1,42 @@
+dnl  HPPA 32-bit time stamp counter access routine.
+
+dnl  Copyright 2000, 2002, 2005 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+dnl void speed_cyclecounter (unsigned p[2]);
+dnl
+dnl Get the HPPA interval timer.
+
+PROLOGUE(speed_cyclecounter)
+	mfctl	%cr16,%r28
+	stw	%r28,0(0,%r26)
+	bv	0(%r2)
+	stw	%r0,4(0,%r26)
+EPILOGUE(speed_cyclecounter)
diff --git a/third_party/gmp/tune/hppa2.asm b/third_party/gmp/tune/hppa2.asm
new file mode 100644
index 0000000..57ef4c4
--- /dev/null
+++ b/third_party/gmp/tune/hppa2.asm
@@ -0,0 +1,44 @@
+dnl  HPPA 64-bit time stamp counter access routine.
+
+dnl  Copyright 2000, 2002, 2005 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+dnl void speed_cyclecounter (unsigned p[2]);
+dnl
+dnl Get the HPPA interval timer.
+
+	.level 2.0
+PROLOGUE(speed_cyclecounter)
+	mfctl	%cr16,%r28
+	stw	%r28,0(0,%r26)		; low word
+	extrd,u	%r28,31,32,%r28
+	bve	(%r2)
+	stw	%r28,4(0,%r26)		; high word
+EPILOGUE(speed_cyclecounter)
diff --git a/third_party/gmp/tune/hppa2w.asm b/third_party/gmp/tune/hppa2w.asm
new file mode 100644
index 0000000..215a0cc
--- /dev/null
+++ b/third_party/gmp/tune/hppa2w.asm
@@ -0,0 +1,44 @@
+dnl  HPPA 64-bit time stamp counter access routine.
+
+dnl  Copyright 2000, 2002, 2005 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+dnl void speed_cyclecounter (unsigned p[2]);
+dnl
+dnl Get the HPPA interval timer.
+
+	.level 2.0w
+PROLOGUE(speed_cyclecounter)
+	mfctl	%cr16,%r28
+	stw	%r28,0(0,%r26)		; low word
+	extrd,u	%r28,31,32,%r28
+	bve	(%r2)
+	stw	%r28,4(0,%r26)		; high word
+EPILOGUE(speed_cyclecounter)
diff --git a/third_party/gmp/tune/ia64.asm b/third_party/gmp/tune/ia64.asm
new file mode 100644
index 0000000..0651111
--- /dev/null
+++ b/third_party/gmp/tune/ia64.asm
@@ -0,0 +1,47 @@
+dnl  IA-64 time stamp counter access routine.
+
+dnl  Copyright 2000, 2005 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C void speed_cyclecounter (unsigned int p[2]);
+C
+
+ASM_START()
+PROLOGUE(speed_cyclecounter)
+	mov	r14 = ar.itc
+	;;
+	st4	[r32] = r14, 4
+	shr.u	r14 = r14, 32
+	;;
+	st4	[r32] = r14
+	br.ret.sptk.many b0
+EPILOGUE(speed_cyclecounter)
+ASM_END()
diff --git a/third_party/gmp/tune/jacbase1.c b/third_party/gmp/tune/jacbase1.c
new file mode 100644
index 0000000..89a584d
--- /dev/null
+++ b/third_party/gmp/tune/jacbase1.c
@@ -0,0 +1,37 @@
+/* mpn/generic/jacbase.c method 1.
+
+Copyright 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#undef JACOBI_BASE_METHOD
+#define JACOBI_BASE_METHOD 1
+#define __gmpn_jacobi_base mpn_jacobi_base_1
+
+#include "mpn/generic/jacbase.c"
diff --git a/third_party/gmp/tune/jacbase2.c b/third_party/gmp/tune/jacbase2.c
new file mode 100644
index 0000000..253d835
--- /dev/null
+++ b/third_party/gmp/tune/jacbase2.c
@@ -0,0 +1,37 @@
+/* mpn/generic/jacbase.c method 2.
+
+Copyright 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#undef JACOBI_BASE_METHOD
+#define JACOBI_BASE_METHOD 2
+#define __gmpn_jacobi_base mpn_jacobi_base_2
+
+#include "mpn/generic/jacbase.c"
diff --git a/third_party/gmp/tune/jacbase3.c b/third_party/gmp/tune/jacbase3.c
new file mode 100644
index 0000000..4440f31
--- /dev/null
+++ b/third_party/gmp/tune/jacbase3.c
@@ -0,0 +1,37 @@
+/* mpn/generic/jacbase.c method 3.
+
+Copyright 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#undef JACOBI_BASE_METHOD
+#define JACOBI_BASE_METHOD 3
+#define __gmpn_jacobi_base mpn_jacobi_base_3
+
+#include "mpn/generic/jacbase.c"
diff --git a/third_party/gmp/tune/jacbase4.c b/third_party/gmp/tune/jacbase4.c
new file mode 100644
index 0000000..daea3bb
--- /dev/null
+++ b/third_party/gmp/tune/jacbase4.c
@@ -0,0 +1,37 @@
+/* mpn/generic/jacbase.c method 4.
+
+Copyright 2002, 2010 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#undef JACOBI_BASE_METHOD
+#define JACOBI_BASE_METHOD 4
+#define __gmpn_jacobi_base mpn_jacobi_base_4
+
+#include "mpn/generic/jacbase.c"
diff --git a/third_party/gmp/tune/many.pl b/third_party/gmp/tune/many.pl
new file mode 100644
index 0000000..524a67d
--- /dev/null
+++ b/third_party/gmp/tune/many.pl
@@ -0,0 +1,1334 @@
+#! /usr/bin/perl -w
+
+# Copyright 2000-2002 Free Software Foundation, Inc.
+#
+#  This file is part of the GNU MP Library.
+#
+#  The GNU MP Library is free software; you can redistribute it and/or modify
+#  it under the terms of either:
+#
+#    * the GNU Lesser General Public License as published by the Free
+#      Software Foundation; either version 3 of the License, or (at your
+#      option) any later version.
+#
+#  or
+#
+#    * the GNU General Public License as published by the Free Software
+#      Foundation; either version 2 of the License, or (at your option) any
+#      later version.
+#
+#  or both in parallel, as here.
+#
+#  The GNU MP Library is distributed in the hope that it will be useful, but
+#  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+#  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  for more details.
+#
+#  You should have received copies of the GNU General Public License and the
+#  GNU Lesser General Public License along with the GNU MP Library.  If not,
+#  see https://www.gnu.org/licenses/.
+
+
+# Usage:  cd $builddir/tune
+#	  perl $srcdir/tune/many.pl [-t] <files/dirs>...
+#
+# Output: speed-many.c
+#         try-many.c
+#         Makefile.many
+#
+# Make alternate versions of various mpn routines available for measuring
+# and testing.
+#
+# The $srcdir and $builddir in the invocation above just means the script
+# lives in the tune source directory, but should be run in the tune build
+# directory.  When not using a separate object directory this just becomes
+#
+#	cd tune
+#	perl many.pl [-t] <files/dirs>...
+#
+#
+# SINGLE FILES
+#
+# Suppose $HOME/newcode/mul_1_experiment.asm is a new implementation of
+# mpn_mul_1, then
+#
+#	cd $builddir/tune
+#	perl $srcdir/tune/many.pl $HOME/newcode/mul_1_experiment.asm
+#
+# will produce rules and renaming so that a speed program incorporating it
+# can be built,
+#
+#	make -f Makefile.many speed-many
+#
+# then for example it can be compared to the standard mul_1,
+#
+#	./speed-many -s 1-30 mpn_mul_1 mpn_mul_1_experiment
+#
+# An expanded try program can be used to check correctness,
+#
+#	make -f Makefile.many try-many
+#
+# and run
+#
+#	./try-many mpn_mul_1_experiment
+#
+# Files can be ".c", ".S" or ".asm".  ".s" files can't be used because they
+# don't get any preprocessing so there's no way to do renaming of their
+# functions.
+#
+#
+# WHOLE DIRECTORIES
+#
+# If a directory is given, then all files in it will be made available.
+# For example,
+#
+#	cd $builddir/tune
+#	perl $srcdir/tune/many.pl $HOME/newcode
+#
+# Each file should have a suffix, like "_experiment" above.
+#
+#
+# MPN DIRECTORIES
+#
+# mpn directories from the GMP source tree can be included, and this is a
+# convenient way to compare multiple implementations suiting different chips
+# in a CPU family.  For example the following would make all x86 routines
+# available,
+#
+#	cd $builddir/tune
+#	perl $srcdir/tune/many.pl `find $srcdir/mpn/x86 -type d`
+#
+# On a new x86 chip a comparison could then be made to see how existing code
+# runs.  For example,
+#
+#	make -f Makefile.many speed-many
+#	./speed-many -s 1-30 -c \
+#		mpn_add_n_x86 mpn_add_n_pentium mpn_add_n_k6 mpn_add_n_k7
+#
+# Files in "mpn" subdirectories don't need the "_experiment" style suffix
+# described above, instead a suffix is constructed from the subdirectory.
+# For example "mpn/x86/k7/mmx/mod_1.asm" will generate a function
+# mpn_mod_1_k7_mmx.  The rule is to take the last directory name after the
+# "mpn", or the last two if there's three or more.  (Check the generated
+# speed-many.c if in doubt.)
+#
+#
+# GENERIC C
+#
+# The mpn/generic directory can be included too, just like any processor
+# specific directory.  This is a good way to compare assembler and generic C
+# implementations.  For example,
+#
+#	cd $builddir/tune
+#	perl $srcdir/tune/many.pl $srcdir/mpn/generic
+#
+# or if just a few routines are of interest, then for example
+#
+#	cd $builddir/tune
+#	perl $srcdir/tune/many.pl \
+#		$srcdir/mpn/generic/lshift.c \
+#		$srcdir/mpn/generic/mod_1.c \
+#		$srcdir/mpn/generic/aorsmul_1.c
+#
+# giving mpn_lshift_generic etc.
+#
+#
+# TESTS/DEVEL PROGRAMS
+#
+# Makefile.many also has rules to build the tests/devel programs with suitable
+# renaming, and with some parameters for correctness or speed.  This is less
+# convenient than the speed and try programs, but provides an independent
+# check.  For example,
+#
+#	make -f Makefile.many tests_mul_1_experimental
+#	./tests_mul_1_experimental
+#
+# and for speed
+#
+#	make -f Makefile.many tests_mul_1_experimental_sp
+#	./tests_mul_1_experimental_sp
+#
+# Not all the programs support speed measuring, in which case only the
+# correctness test will be useful.
+#
+# The parameters for repetitions and host clock speed are -D defines.  Some
+# defaults are provided at the end of Makefile.many, but probably these will
+# want to be overridden.  For example,
+#
+#	rm tests_mul_1_experimental.o
+#	make -f Makefile.many \
+#	   CFLAGS_TESTS="-DSIZE=50 -DTIMES=1000 -DRANDOM -DCLOCK=175000000" \
+#	   tests_mul_1_experimental
+#	./tests_mul_1_experimental
+#
+#
+# OTHER NOTES
+#
+# The mappings of file names to functions, and the macros to then use for
+# speed measuring etc are driven by @table below.  The scheme isn't
+# completely general, it's only got as many variations as have been needed
+# so far.
+#
+# Some functions are only made available in speed-many, or others only in
+# try-many.  An @table entry speed=>none means no speed measuring is
+# available, or try=>none no try program testing.  These can be removed
+# if/when the respective programs get the necessary support.
+#
+# If a file has "1c" or "nc" carry-in entrypoints, they're renamed and made
+# available too.  These are recognised from PROLOGUE or MULFUNC_PROLOGUE in
+# .S and .asm files, or from a line starting with "mpn_foo_1c" in a .c file
+# (possibly via a #define), and on that basis are entirely optional.  This
+# entrypoint matching is done for the standard entrypoints too, but it would
+# be very unusual to have for instance a mul_1c without a mul_1.
+#
+# Some mpz files are recognized.  For example an experimental copy of
+# mpz/powm.c could be included as powm_new.c and would be called
+# mpz_powm_new.  So far only speed measuring is available for these.
+#
+# For the ".S" and ".asm" files, both PIC and non-PIC objects are built.
+# The PIC functions have a "_pic" suffix, for example "mpn_mod_1_k7_mmx_pic".
+# This can be ignored for routines that don't differ for PIC, or for CPUs
+# where everything is PIC anyway.
+#
+# K&R compilers are supported via the same ansi2knr mechanism used by
+# automake, though it's hard to believe anyone will have much interest in
+# measuring a compiler so old that it doesn't even have an ANSI mode.
+#
+# The "-t" option can be used to print a trace of the files found and what's
+# done with them.  A great deal of obscure output is produced, but it can
+# indicate where or why some files aren't being recognised etc.  For
+# example,
+#
+#	cd $builddir/tune
+#	perl $srcdir/tune/many.pl -t $HOME/newcode/add_n_weird.asm
+#
+# In general, when including new code, all that's really necessary is that
+# it will compile or assemble under the current configuration.  It's fine if
+# some code doesn't actually run due to bugs, or to needing a newer CPU or
+# whatever, simply don't ask for the offending routines when invoking
+# speed-many or try-many, or don't try to run them on sizes they don't yet
+# support, or whatever.
+#
+#
+# CPU SPECIFICS
+#
+# x86 - All the x86 code will assemble on any system, but code for newer
+#       chips might not run on older chips.  Expect SIGILLs from new
+#       instructions on old chips.
+#
+#       A few "new" instructions, like cmov for instance, are done as macros
+#       and will generate some equivalent plain i386 code when HAVE_HOST_CPU
+#       in config.m4 indicates an old CPU.  It won't run fast, but it does
+#       make it possible to test correctness.
+#
+#
+# INTERNALS
+#
+# The nonsense involving $ENV is some hooks used during development to add
+# additional functions temporarily.
+#
+#
+# FUTURE
+#
+# Maybe the C files should be compiled pic and non-pic too.  Wait until
+# there's a difference that might be of interest.
+#
+# Warn if a file provides no functions.
+#
+# Allow mpz and mpn files of the same name.  Currently the mpn fib2_ui
+# matching hides the mpz version of that.  Will need to check the file
+# contents to see which it is.  Would be worth allowing an "mpz_" or "mpn_"
+# prefix on the filenames to have working versions of both in one directory.
+#
+#
+# LIMITATIONS
+#
+# Some of the command lines can become very long when a lot of files are
+# included.  If this is a problem on a given system the only suggestion is
+# to run many.pl for just those that are actually wanted at a particular
+# time.
+#
+# DOS 8.3 or SysV 14 char filesystems won't work, since the long filenames
+# generated will almost certainly fail to be unique.
+
+
+use strict;
+use File::Basename;
+use Getopt::Std;
+
+my %opt;
+getopts('t', \%opt);
+
+my @DIRECTORIES = @ARGV;
+if (defined $ENV{directories}) { push @DIRECTORIES, @{$ENV{directories}} }
+
+
+# regexp - matched against the start of the filename.  If a grouping "(...)"
+#          is present then only the first such part is used.
+#
+# mulfunc - filenames to be generated from a multi-function file.
+#
+# funs - functions provided by the file, defaulting to the filename with mpn
+#          (or mpX).
+#
+# mpX - prefix like "mpz", defaulting to "mpn".
+#
+# ret - return value type.
+#
+# args, args_<fun> - arguments for the given function.  If an args_<fun> is
+#          set then it's used, otherwise plain args is used.  "mp_limb_t
+#          carry" is appended for carry-in variants.
+#
+# try - try.c TYPE_ to use, defaulting to TYPE_fun with the function name
+#          in upper case.  "C" is appended for carry-in variants.  Can be
+#          'none' for no try program entry.
+#
+# speed - SPEED_ROUTINE_ to use, handled like "try".
+#
+# speed_flags - SPEED_ROUTINE_ to use, handled like "try".
+
+
+my @table =
+    (
+     {
+       'regexp'=> 'add_n|sub_n|addlsh1_n|sublsh1_n|rsh1add_n|rsh1sub_n',
+       'ret'   => 'mp_limb_t',
+       'args'  => 'mp_ptr wp, mp_srcptr xp, mp_srcptr yp, mp_size_t size',
+       'speed' => 'SPEED_ROUTINE_MPN_BINARY_N',
+       'speed_flags'=> 'FLAG_R_OPTIONAL',
+     },
+     {
+       'regexp'=> 'aors_n',
+       'mulfunc'=> ['add_n','sub_n'],
+       'ret'   => 'mp_limb_t',
+       'args'  => 'mp_ptr wp, mp_srcptr xp, mp_srcptr yp, mp_size_t size',
+       'speed' => 'SPEED_ROUTINE_MPN_BINARY_N',
+       'speed_flags'=> 'FLAG_R_OPTIONAL',
+     },
+
+     {
+       'regexp'=> 'addmul_1|submul_1',
+       'ret'   => 'mp_limb_t',
+       'args'  => 'mp_ptr wp, mp_srcptr xp, mp_size_t size, mp_limb_t mult',
+       'speed' => 'SPEED_ROUTINE_MPN_UNARY_1',
+       'speed_flags'=> 'FLAG_R',
+     },
+     {
+       'regexp'=> 'aorsmul_1',
+       'mulfunc'=> ['addmul_1','submul_1'],
+       'ret'   => 'mp_limb_t',
+       'args'  => 'mp_ptr wp, mp_srcptr xp, mp_size_t size, mp_limb_t mult',
+       'speed' => 'SPEED_ROUTINE_MPN_UNARY_1',
+       'speed_flags'=> 'FLAG_R',
+     },
+
+     {
+       'regexp'=> 'addmul_2|submul_2',
+       'ret'   => 'mp_limb_t',
+       'args'  => 'mp_ptr wp, mp_srcptr xp, mp_size_t size, mp_srcptr yp',
+       'speed' => 'SPEED_ROUTINE_MPN_UNARY_2',
+       'speed_flags'=> 'FLAG_R_OPTIONAL',
+       'try-minsize' => 2,
+     },
+     {
+       'regexp'=> 'addmul_3|submul_3',
+       'ret'   => 'mp_limb_t',
+       'args'  => 'mp_ptr wp, mp_srcptr xp, mp_size_t size, mp_srcptr yp',
+       'speed' => 'SPEED_ROUTINE_MPN_UNARY_3',
+       'speed_flags'=> 'FLAG_R_OPTIONAL',
+       'try-minsize' => 3,
+     },
+     {
+       'regexp'=> 'addmul_4|submul_4',
+       'ret'   => 'mp_limb_t',
+       'args'  => 'mp_ptr wp, mp_srcptr xp, mp_size_t size, mp_srcptr yp',
+       'speed' => 'SPEED_ROUTINE_MPN_UNARY_4',
+       'speed_flags'=> 'FLAG_R_OPTIONAL',
+       'try-minsize' => 4,
+     },
+     {
+       'regexp'=> 'addmul_5|submul_5',
+       'ret'   => 'mp_limb_t',
+       'args'  => 'mp_ptr wp, mp_srcptr xp, mp_size_t size, mp_srcptr yp',
+       'speed' => 'SPEED_ROUTINE_MPN_UNARY_5',
+       'speed_flags'=> 'FLAG_R_OPTIONAL',
+       'try-minsize' => 5,
+     },
+     {
+       'regexp'=> 'addmul_6|submul_6',
+       'ret'   => 'mp_limb_t',
+       'args'  => 'mp_ptr wp, mp_srcptr xp, mp_size_t size, mp_srcptr yp',
+       'speed' => 'SPEED_ROUTINE_MPN_UNARY_6',
+       'speed_flags'=> 'FLAG_R_OPTIONAL',
+       'try-minsize' => 6,
+     },
+     {
+       'regexp'=> 'addmul_7|submul_7',
+       'ret'   => 'mp_limb_t',
+       'args'  => 'mp_ptr wp, mp_srcptr xp, mp_size_t size, mp_srcptr yp',
+       'speed' => 'SPEED_ROUTINE_MPN_UNARY_7',
+       'speed_flags'=> 'FLAG_R_OPTIONAL',
+       'try-minsize' => 7,
+     },
+     {
+       'regexp'=> 'addmul_8|submul_8',
+       'ret'   => 'mp_limb_t',
+       'args'  => 'mp_ptr wp, mp_srcptr xp, mp_size_t size, mp_srcptr yp',
+       'speed' => 'SPEED_ROUTINE_MPN_UNARY_8',
+       'speed_flags'=> 'FLAG_R_OPTIONAL',
+       'try-minsize' => 8,
+     },
+
+     {
+       'regexp'=> 'add_n_sub_n',
+       'ret'   => 'mp_limb_t',
+       'args'  => 'mp_ptr sum, mp_ptr diff, mp_srcptr xp, mp_srcptr yp, mp_size_t size',
+       'speed_flags'=> 'FLAG_R_OPTIONAL',
+     },
+
+     {
+       'regexp'=> 'com|copyi|copyd',
+       'ret'   => 'void',
+       'args'  => 'mp_ptr wp, mp_srcptr xp, mp_size_t size',
+       'speed' => 'SPEED_ROUTINE_MPN_COPY',
+     },
+
+     {
+       'regexp'=> 'dive_1',
+       'funs'  => ['divexact_1'],
+       'ret'   => 'void',
+       'args'  => 'mp_ptr dst, mp_srcptr src, mp_size_t size, mp_limb_t divisor',
+       'speed_flags'=> 'FLAG_R',
+     },
+     {
+       'regexp'=> 'diveby3',
+       'funs'  => ['divexact_by3c'],
+       'ret'   => 'mp_limb_t',
+       'args'  => 'mp_ptr dst, mp_srcptr src, mp_size_t size',
+       'carrys'=> [''],
+       'speed' => 'SPEED_ROUTINE_MPN_COPY',
+     },
+
+     # mpn_preinv_divrem_1 is an optional extra entrypoint
+     {
+       'regexp'=> 'divrem_1',
+       'funs'  => ['divrem_1', 'preinv_divrem_1'],
+       'ret'   => 'mp_limb_t',
+       'args_divrem_1' => 'mp_ptr rp, mp_size_t xsize, mp_srcptr sp, mp_size_t size, mp_limb_t divisor',
+       'args_preinv_divrem_1' => 'mp_ptr rp, mp_size_t xsize, mp_srcptr sp, mp_size_t size, mp_limb_t divisor, mp_limb_t inverse, unsigned shift',
+       'speed_flags'=> 'FLAG_R',
+       'speed_suffixes' => ['f'],
+     },
+     {
+       'regexp'=> 'pre_divrem_1',
+       'funs'  => ['preinv_divrem_1'],
+       'ret'   => 'mp_limb_t',
+       'args'  => 'mp_ptr qp, mp_size_t qxn, mp_srcptr ap, mp_size_t asize, mp_limb_t divisor, mp_limb_t inverse, int shift',
+       'speed_flags' => 'FLAG_R',
+     },
+
+     {
+       'regexp'=> 'divrem_2',
+       'ret'   => 'mp_limb_t',
+       'args'  => 'mp_ptr qp, mp_size_t qxn, mp_srcptr np, mp_size_t nsize, mp_srcptr dp',
+       'try'   => 'none',
+     },
+
+     {
+       'regexp'=> 'sb_divrem_mn',
+       'ret'   => 'mp_limb_t',
+       'args'  => 'mp_ptr qp, mp_ptr np, mp_size_t nsize, mp_srcptr dp, mp_size_t dsize',
+       'speed' => 'SPEED_ROUTINE_MPN_DC_DIVREM_SB',
+       'try-minsize' => 3,
+     },
+     {
+       'regexp'=> 'tdiv_qr',
+       'ret'   => 'void',
+       'args'  => 'mp_ptr qp, mp_size_t qxn, mp_ptr np, mp_size_t nsize, mp_srcptr dp, mp_size_t dsize',
+       'speed' => 'none',
+     },
+
+     {
+       'regexp'=> 'get_str',
+       'ret'   => 'size_t',
+       'args'  => 'unsigned char *str, int base, mp_ptr mptr, mp_size_t msize',
+       'speed_flags' => 'FLAG_R_OPTIONAL',
+       'try'   => 'none',
+     },
+     {
+       'regexp'=> 'set_str',
+       'ret'   => 'mp_size_t',
+       'args'  => 'mp_ptr xp, const unsigned char *str, size_t str_len, int base',
+       'speed_flags' => 'FLAG_R_OPTIONAL',
+       'try'   => 'none',
+     },
+
+     {
+       'regexp'=> 'fac_ui',
+       'mpX'   => 'mpz',
+       'ret'   => 'void',
+       'args'  => 'mpz_ptr r, unsigned long n',
+       'speed_flags' => 'FLAG_NODATA',
+       'try'   => 'none',
+     },
+
+     {
+       'regexp'=> 'fib2_ui',
+       'ret'   => 'void',
+       'args'  => 'mp_ptr fp, mp_ptr f1p, unsigned long n',
+       'rename'=> ['__gmp_fib_table'],
+       'speed_flags' => 'FLAG_NODATA',
+       'try'   => 'none',
+     },
+     {
+       'regexp'=> 'fib_ui',
+       'mpX'   => 'mpz',
+       'ret'   => 'void',
+       'args'  => 'mpz_ptr fn, unsigned long n',
+       'speed_flags' => 'FLAG_NODATA',
+       'try'   => 'none',
+     },
+     {
+       'regexp'=> 'fib2_ui',
+       'mpX'   => 'mpz',
+       'ret'   => 'void',
+       'args'  => 'mpz_ptr fn, mpz_ptr fnsub1, unsigned long n',
+       'speed_flags' => 'FLAG_NODATA',
+       'try'   => 'none',
+     },
+
+     {
+       'regexp'=> 'lucnum_ui',
+       'mpX'   => 'mpz',
+       'ret'   => 'void',
+       'args'  => 'mpz_ptr ln, unsigned long n',
+       'speed_flags' => 'FLAG_NODATA',
+       'try'   => 'none',
+     },
+     {
+       'regexp'=> 'lucnum2_ui',
+       'mpX'   => 'mpz',
+       'ret'   => 'void',
+       'args'  => 'mpz_ptr ln, mpz_ptr lnsub1, unsigned long n',
+       'speed_flags' => 'FLAG_NODATA',
+       'try'   => 'none',
+     },
+
+     {
+       'regexp'=> 'gcd_1',
+       'ret'   => 'mp_limb_t',
+       'args'  => 'mp_ptr xp, mp_size_t xsize, mp_limb_t y',
+       'speed_flags'=> 'FLAG_R_OPTIONAL',
+       'speed_suffixes' => ['N'],
+     },
+     {
+       'regexp'=> '(gcd)(?!(_1|ext|_finda))',
+       'ret'   => 'mp_size_t',
+       'args'  => 'mp_ptr gp, mp_ptr up, mp_size_t usize, mp_ptr vp, mp_size_t vsize',
+     },
+     {
+       'regexp'=> 'gcd_finda',
+       'ret'   => 'mp_limb_t',
+       'args'  => 'mp_srcptr cp',
+     },
+
+
+     {
+       'regexp'=> 'jacobi',
+       'funs'  => ['jacobi', 'legendre', 'kronecker'],
+       'mpX'   => 'mpz',
+       'ret'   => 'int',
+       'args'  => 'mpz_srcptr a, mpz_srcptr b',
+       'try-legendre' => 'TYPE_MPZ_JACOBI',
+     },
+     {
+       'regexp'=> 'jacbase',
+       'funs'  => ['jacobi_base'],
+       'ret'   => 'mp_limb_t',
+       'args'  => 'mp_limb_t a, mp_limb_t b, int bit1',
+       'speed' => 'SPEED_ROUTINE_MPN_JACBASE',
+       'try'   => 'none',
+     },
+
+     {
+       'regexp'=> 'logops_n',
+       'mulfunc'=> ['and_n','andn_n','nand_n','ior_n','iorn_n','nior_n','xor_n','xnor_n'],
+       'ret'   => 'void',
+       'args'  => 'mp_ptr wp, mp_srcptr xp, mp_srcptr yp, mp_size_t size',
+       'speed' => 'SPEED_ROUTINE_MPN_BINARY_N',
+     },
+
+     {
+       'regexp'=> '[lr]shift',
+       'ret'   => 'mp_limb_t',
+       'args'  => 'mp_ptr wp, mp_srcptr xp, mp_size_t size, unsigned shift',
+       'speed' => 'SPEED_ROUTINE_MPN_UNARY_1',
+       'speed_flags'=> 'FLAG_R',
+     },
+
+     # mpn_preinv_mod_1 is an optional extra entrypoint
+     {
+       'regexp'=> '(mod_1)(?!_rs)',
+       'funs'  => ['mod_1','preinv_mod_1'],
+       'ret'   => 'mp_limb_t',
+       'args_mod_1'       => 'mp_srcptr xp, mp_size_t size, mp_limb_t divisor',
+       'args_preinv_mod_1'=> 'mp_srcptr xp, mp_size_t size, mp_limb_t divisor, mp_limb_t inverse',
+       'speed_flags'=> 'FLAG_R',
+     },
+     {
+       'regexp'=> 'pre_mod_1',
+       'funs'  => ['preinv_mod_1'],
+       'ret'   => 'mp_limb_t',
+       'args'  => 'mp_srcptr xp, mp_size_t size, mp_limb_t divisor, mp_limb_t inverse',
+       'speed_flags'=> 'FLAG_R',
+     },
+     {
+       'regexp'=> 'mod_34lsub1',
+       'ret'   => 'mp_limb_t',
+       'args'  => 'mp_srcptr src, mp_size_t len',
+     },
+     {
+       'regexp'=> 'invert_limb',
+       'ret'   => 'mp_limb_t',
+       'args'  => 'mp_limb_t divisor',
+       'speed_flags'=> 'FLAG_R_OPTIONAL',
+       'try'   => 'none',
+     },
+
+     {
+       # not for use with hppa reversed argument versions of mpn_umul_ppmm
+       'regexp'=> 'udiv',
+       'funs'  => ['udiv_qrnnd','udiv_qrnnd_r'],
+       'ret'   => 'mp_limb_t',
+       'args_udiv_qrnnd'   => 'mp_limb_t *, mp_limb_t, mp_limb_t, mp_limb_t',
+       'args_udiv_qrnnd_r' => 'mp_limb_t, mp_limb_t, mp_limb_t, mp_limb_t *',
+       'speed' => 'none',
+       'try-minsize' => 2,
+     },
+
+     {
+       'regexp'=> 'mode1o',
+       'funs'  => ['modexact_1_odd'],
+       'ret'   => 'mp_limb_t',
+       'args'  => 'mp_srcptr src, mp_size_t size, mp_limb_t divisor',
+       'speed_flags'=> 'FLAG_R',
+     },
+     {
+       'regexp'=> 'modlinv',
+       'funs'  => ['modlimb_invert'],
+       'ret'   => 'mp_limb_t',
+       'args'  => 'mp_limb_t v',
+       'carrys'=> [''],
+       'try'   => 'none',
+     },
+
+     {
+       'regexp'=> 'mul_1',
+       'ret'   => 'mp_limb_t',
+       'args'  => 'mp_ptr wp, mp_srcptr xp, mp_size_t size, mp_limb_t mult',
+       'speed' => 'SPEED_ROUTINE_MPN_UNARY_1',
+       'speed_flags'=> 'FLAG_R',
+     },
+     {
+       'regexp'=> 'mul_2',
+       'ret'   => 'mp_limb_t',
+       'args'  => 'mp_ptr wp, mp_srcptr xp, mp_size_t size, mp_srcptr mult',
+       'speed' => 'SPEED_ROUTINE_MPN_UNARY_2',
+       'speed_flags'=> 'FLAG_R',
+     },
+
+     {
+       'regexp'=> 'mul_basecase',
+       'ret'   => 'void',
+       'args'  => 'mp_ptr wp, mp_srcptr xp, mp_size_t xsize, mp_srcptr yp, mp_size_t ysize',
+       'speed_flags' => 'FLAG_R_OPTIONAL | FLAG_RSIZE',
+     },
+     {
+       'regexp'=> '(mul_n)[_.]',
+       'ret'   => 'void',
+       'args'  => 'mp_ptr wp, mp_srcptr xp, mp_srcptr yp, mp_size_t size',
+       'rename'=> ['kara_mul_n','kara_sqr_n','toom3_mul_n','toom3_sqr_n'],
+     },
+     {
+       'regexp'=> 'umul',
+       'funs'  => ['umul_ppmm','umul_ppmm_r'],
+       'ret'   => 'mp_limb_t',
+       'args_umul_ppmm'   => 'mp_limb_t *lowptr, mp_limb_t m1, mp_limb_t m2',
+       'args_umul_ppmm_r' => 'mp_limb_t m1, mp_limb_t m2, mp_limb_t *lowptr',
+       'speed' => 'none',
+       'try-minsize' => 3,
+     },
+
+
+     {
+       'regexp'=> 'popham',
+       'mulfunc'=> ['popcount','hamdist'],
+       'ret'   => 'unsigned long',
+       'args_popcount'=> 'mp_srcptr xp, mp_size_t size',
+       'args_hamdist' => 'mp_srcptr xp, mp_srcptr yp, mp_size_t size',
+     },
+     {
+       'regexp'=> 'popcount',
+       'ret'   => 'unsigned long',
+       'args'  => 'mp_srcptr xp, mp_size_t size',
+     },
+     {
+       'regexp'=> 'hamdist',
+       'ret'   => 'unsigned long',
+       'args'  => 'mp_srcptr xp, mp_srcptr yp, mp_size_t size',
+       # extra renaming to support sharing a data table with mpn_popcount
+       'rename'=> ['popcount'],
+     },
+
+     {
+       'regexp'=> 'sqr_basecase',
+       'ret'   => 'void',
+       'args'  => 'mp_ptr wp, mp_srcptr xp, mp_size_t size',
+       'speed' => 'SPEED_ROUTINE_MPN_SQR',
+       'try'   => 'TYPE_SQR',
+     },
+     {
+       'regexp'=> 'sqr_diagonal',
+       'ret'   => 'void',
+       'args'  => 'mp_ptr wp, mp_srcptr xp, mp_size_t size',
+       'try'   => 'none',
+     },
+
+     {
+       'regexp'=> 'sqrtrem',
+       'ret'   => 'mp_size_t',
+       'args'  => 'mp_ptr root, mp_ptr rem, mp_srcptr src, mp_size_t size',
+       'try'   => 'none',
+     },
+
+     {
+       'regexp'=> 'cntlz',
+       'funs'  => ['count_leading_zeros'],
+       'ret'   => 'unsigned',
+       'args'  => 'mp_limb_t',
+       'macro-before' => "#undef COUNT_LEADING_ZEROS_0",
+       'macro-speed'  =>
+'#ifdef COUNT_LEADING_ZEROS_0
+#define COUNT_LEADING_ZEROS_0_ALLOWED   1
+#else
+#define COUNT_LEADING_ZEROS_0_ALLOWED   0
+#endif
+  SPEED_ROUTINE_COUNT_ZEROS_A (1, COUNT_LEADING_ZEROS_0_ALLOWED);
+  $fun (c, n);
+  SPEED_ROUTINE_COUNT_ZEROS_B ()',
+       'speed_flags'=> 'FLAG_R_OPTIONAL',
+       'try'   => 'none',
+     },
+     {
+       'regexp'=> 'cnttz',
+       'funs'  => ['count_trailing_zeros'],
+       'ret'   => 'unsigned',
+       'args'  => 'mp_limb_t',
+       'macro-speed' => '
+  SPEED_ROUTINE_COUNT_ZEROS_A (0, 0);
+  $fun (c, n);
+  SPEED_ROUTINE_COUNT_ZEROS_B ()',
+       'speed_flags' => 'FLAG_R_OPTIONAL',
+       'try'   => 'none',
+     },
+
+     {
+       'regexp'=> 'zero',
+       'ret'   => 'void',
+       'args'  => 'mp_ptr ptr, mp_size_t size',
+     },
+
+     {
+       'regexp'=> '(powm)(?!_ui)',
+       'mpX'   => 'mpz',
+       'ret'   => 'void',
+       'args'  => 'mpz_ptr r, mpz_srcptr b, mpz_srcptr e, mpz_srcptr m',
+       'try'   => 'none',
+     },
+     {
+       'regexp'=> 'powm_ui',
+       'mpX'   => 'mpz',
+       'ret'   => 'void',
+       'args'  => 'mpz_ptr r, mpz_srcptr b, unsigned long e, mpz_srcptr m',
+       'try'   => 'none',
+     },
+
+     # special for use during development
+     {
+       'regexp'=> 'back',
+       'funs'  => ['back_to_back'],
+       'ret'   => 'void',
+       'args'  => 'void',
+       'pic'   => 'no',
+       'try'   => 'none',
+       'speed_flags'=> 'FLAG_NODATA',
+     },
+     );
+
+if (defined $ENV{table2}) {
+  my @newtable = @{$ENV{table2}};
+  push @newtable, @table;
+  @table = @newtable;
+}
+
+
+my %pictable =
+    (
+     'yes' => {
+       'suffix' =>  '_pic',
+       'asmflags'=> '$(ASMFLAGS_PIC)',
+       'cflags' =>  '$(CFLAGS_PIC)',
+     },
+     'no' => {
+       'suffix' =>  '',
+       'asmflags'=> '',
+       'cflags' =>  '',
+     },
+     );
+
+
+my $builddir = $ENV{builddir};
+$builddir = "." if (! defined $builddir);
+
+my $top_builddir = "${builddir}/..";
+
+
+open(MAKEFILE, "<${builddir}/Makefile")
+  or die "Cannot open ${builddir}/Makefile: $!\n"
+       . "Is this a tune build directory?";
+my ($srcdir, $top_srcdir);
+while (<MAKEFILE>) {
+  if (/^srcdir = (.*)/) {     $srcdir = $1;     }
+  if (/^top_srcdir = (.*)/) { $top_srcdir = $1; }
+}
+die "Cannot find \$srcdir in Makefile\n" if (! defined $srcdir);
+die "Cannot find \$top_srcdir in Makefile\n" if (! defined $top_srcdir);
+print "srcdir $srcdir\n" if $opt{'t'};
+print "top_srcdir $top_srcdir\n" if $opt{'t'};
+close(MAKEFILE);
+
+
+open(SPEED, ">speed-many.c") or die;
+print SPEED
+"/* speed-many.c generated by many.pl - DO NOT EDIT, CHANGES WILL BE LOST */
+
+";
+my $SPEED_EXTRA_ROUTINES = "#define SPEED_EXTRA_ROUTINES \\\n";
+my $SPEED_EXTRA_PROTOS = "#define SPEED_EXTRA_PROTOS \\\n";
+my $SPEED_CODE = "";
+
+open(TRY, ">try-many.c") or die;
+print TRY
+    "/* try-many.c generated by many.pl - DO NOT EDIT, CHANGES WILL BE LOST */\n" .
+    "\n";
+my $TRY_EXTRA_ROUTINES = "#define EXTRA_ROUTINES \\\n";
+my $TRY_EXTRA_PROTOS = "#define EXTRA_PROTOS \\\n";
+
+open(FD,"<${top_builddir}/libtool") or die "Cannot open \"${top_builddir}/libtool\": $!\n";
+my $pic_flag;
+while (<FD>) {
+  if (/^pic_flag="?([^"]*)"?$/) {
+    $pic_flag=$1;
+    last;
+  }
+}
+close FD;
+if (! defined $pic_flag) {
+  die "Cannot find pic_flag in ${top_builddir}/libtool";
+}
+
+my $CFLAGS_PIC = $pic_flag;
+
+my $ASMFLAGS_PIC = "";
+foreach (split /[ \t]/, $pic_flag) {
+  if (/^-D/) {
+    $ASMFLAGS_PIC .= " " . $_;
+  }
+}
+
+open(MAKEFILE, ">Makefile.many") or die;
+print MAKEFILE
+    "# Makefile.many generated by many.pl - DO NOT EDIT, CHANGES WILL BE LOST\n" .
+    "\n" .
+    "all: speed-many try-many\n" .
+    "\n" .
+    "#--------- begin included copy of basic Makefile ----------\n" .
+    "\n";
+open(FD,"<${builddir}/Makefile") or die "Cannot open \"${builddir}/Makefile\": $!\n";
+print MAKEFILE <FD>;
+close FD;
+print MAKEFILE
+    "\n" .
+    "#--------- end included copy of basic Makefile ----------\n" .
+    "\n" .
+    "CFLAGS_PIC = $CFLAGS_PIC\n" .
+    "ASMFLAGS_PIC = $ASMFLAGS_PIC\n" .
+    "\n";
+
+my $CLEAN="";
+my $MANY_OBJS="";
+
+
+sub print_ansi2knr {
+  my ($base,$file,$includes) = @_;
+  if (! defined $file)     { $file = "$base.c"; }
+  if (! defined $includes) { $includes = ""; }
+
+  print MAKEFILE <<EOF;
+${base}_.c: $file \$(ANSI2KNR)
+	\$(CPP) \$(DEFS) \$(INCLUDES) $includes \$(AM_CPPFLAGS) \$(CPPFLAGS) $file | sed 's/^# \([0-9]\)/#line \\1/' | \$(ANSI2KNR) >${base}_.c
+
+EOF
+}
+
+
+# Spawning a glob is a touch slow when there's lots of files.
+my @files = ();
+foreach my $dir (@DIRECTORIES) {
+  print "dir $dir\n" if $opt{'t'};
+  if (-f $dir) {
+    push @files,$dir;
+  } else {
+    if (! opendir DD,$dir) {
+      print "Cannot open $dir: $!\n";
+    } else {
+      push @files, map {$_="$dir/$_"} grep /\.(c|asm|S|h)$/, readdir DD;
+      closedir DD;
+    }
+  }
+}
+@files = sort @files;
+print "@files ",join(" ",@files),"\n" if $opt{'t'};
+
+my $count_files = 0;
+my $count_functions = 0;
+my %seen_obj;
+my %seen_file;
+
+foreach my $file_full (@files) {
+  if (! -f $file_full) {
+    print "Not a file: $file_full\n";
+    next;
+  }
+  if (defined $seen_file{$file_full}) {
+    print "Skipping duplicate file: $file_full\n";
+    next;
+  }
+  $seen_file{$file_full} = 1;
+
+  my ($FILE,$path,$lang) = fileparse($file_full,"\.[a-zA-Z]+");
+  $path =~ s/\/$//;
+  print "file $FILE path $path lang $lang\n" if $opt{'t'};
+
+  my @pic_choices;
+  if ($lang eq '.asm')  { @pic_choices=('no','yes'); }
+  elsif ($lang eq '.c') { @pic_choices=('no'); }
+  elsif ($lang eq '.S') { @pic_choices=('no','yes'); }
+  elsif ($lang eq '.h') { @pic_choices=('no'); }
+  else { next };
+
+  my ($t, $file_match);
+  foreach my $p (@table) {
+    # print " ",$p->{'regexp'},"\n" if $opt{'t'};
+    if ($FILE =~ "^($p->{'regexp'})") {
+      $t = $p;
+      $file_match = $1;
+      $file_match = $2 if defined $2;
+      last;
+    }
+  }
+  next if ! defined $t;
+  print "match $t->{'regexp'} $FILE ($file_full)\n" if $opt{'t'};
+
+  if (! open FD,"<$file_full") { print "Can't open $file_full: $!\n"; next }
+  my @file_contents = <FD>;
+  close FD;
+
+  my $objs;
+  if (defined $t->{'mulfunc'}) { $objs = $t->{'mulfunc'}; }
+  else                         { $objs = [$file_match]; }
+  print "objs @$objs\n" if $opt{'t'};
+
+  my $ret = $t->{'ret'};
+  if (! defined $ret && $lang eq '.h') { $ret = ''; }
+  if (! defined $ret) { die "$FILE return type not defined\n" };
+  print "ret $ret\n" if $opt{'t'};
+
+  my $mpX = $t->{'mpX'};
+  if (! defined $mpX) { $mpX = ($lang eq '.h' ? '' : 'mpn'); }
+  $mpX = "${mpX}_" if $mpX ne '';
+  print "mpX $mpX\n" if $opt{'t'};
+
+  my $carrys;
+  if (defined $t->{'carrys'}) { $carrys = $t->{'carrys'}; }
+  else                        { $carrys = ['','c'];       }
+  print "carrys $carrys @$carrys\n" if $opt{'t'};
+
+  # some restriction functions are implemented, but they're not very useful
+  my $restriction='';
+
+  my $suffix;
+  if ($FILE =~ ("${file_match}_(.+)")) {
+    $suffix = $1;
+  } elsif ($path =~ /\/mp[zn]\/(.*)$/) {
+    # derive the suffix from the path
+    $suffix = $1;
+    $suffix =~ s/\//_/g;
+    # use last directory name, or if there's 3 or more then the last two
+    if ($suffix =~ /([^_]*_)+([^_]+_[^_]+)$/) {
+      $suffix = $2;
+    } elsif ($suffix =~ /([^_]*_)*([^_]+)$/) {
+      $suffix = $2;
+    }
+  } else {
+    die "Can't determine suffix for: $file_full (path $path)\n";
+  }
+  print "suffix $suffix\n" if $opt{'t'};
+
+  $count_files++;
+
+  foreach my $obj (@{$objs}) {
+    print "obj $obj\n" if $opt{'t'};
+
+    my $obj_with_suffix = "${obj}_$suffix";
+    if (defined $seen_obj{$obj_with_suffix}) {
+      print "Skipping duplicate object: $obj_with_suffix\n";
+      print "   first from: $seen_obj{$obj_with_suffix}\n";
+      print "   now from:   $file_full\n";
+      next;
+    }
+    $seen_obj{$obj_with_suffix} = $file_full;
+
+    my $funs = $t->{'funs'};
+    $funs = [$obj] if ! defined $funs;
+    print "funs @$funs\n" if $opt{'t'};
+
+    if (defined $t->{'pic'}) { @pic_choices = ('no'); }
+
+    foreach my $pic (map {$pictable{$_}} @pic_choices) {
+      print "pic $pic->{'suffix'}\n" if $opt{'t'};
+
+      my $objbase = "${obj}_$suffix$pic->{'suffix'}";
+      print "objbase $objbase\n" if $opt{'t'};
+
+      if ($path !~ "." && -f "${objbase}.c") {
+	die "Already have ${objbase}.c";
+      }
+
+      my $tmp_file = "tmp-$objbase.c";
+
+      my $renaming;
+      foreach my $fun (@{$funs}) {
+        if ($mpX eq 'mpn_' && $lang eq '.c') {
+          $renaming .= "\t\t-DHAVE_NATIVE_mpn_$fun=1 \\\n";
+        }
+
+        # The carry-in variant is with a "c" appended, unless there's a "_1"
+        # somewhere, eg. "modexact_1_odd", in which case that becomes "_1c".
+	my $fun_carry = $fun;
+	if (! ($fun_carry =~ s/_1/_1c/)) { $fun_carry = "${fun}c"; }
+
+	$renaming .=
+	    "\t\t-D__g$mpX$fun=$mpX${fun}_$suffix$pic->{'suffix'} \\\n" .
+	    "\t\t-D__g$mpX$fun_carry=$mpX${fun_carry}_$suffix$pic->{'suffix'} \\\n";
+      }
+      foreach my $r (@{$t->{'rename'}}) {
+	if ($r =~ /^__gmp/) {
+	  $renaming .= "\\\n" .
+	      "\t\t-D$r=${r}_$suffix$pic->{'suffix'}";
+	} else {
+	  $renaming .= "\\\n" .
+	      "\t\t-D__g$mpX$r=$mpX${r}_$suffix$pic->{'suffix'}";
+	}
+      }
+      print "renaming $renaming\n" if $opt{'t'};
+
+      print MAKEFILE "\n";
+      if ($lang eq '.asm') {
+	print MAKEFILE
+	    "$objbase.o: $file_full \$(ASM_HEADERS)\n" .
+	    "	\$(M4) \$(M4FLAGS) -DOPERATION_$obj $pic->{'asmflags'} \\\n" .
+  	    "$renaming" .
+	    "		$file_full >tmp-$objbase.s\n" .
+            "	\$(CCAS) \$(COMPILE_FLAGS) $pic->{'cflags'} tmp-$objbase.s -o $objbase.o\n" .
+            "	\$(RM_TMP) tmp-$objbase.s\n";
+	$MANY_OBJS .= " $objbase.o";
+
+      } elsif ($lang eq '.c') {
+	print MAKEFILE
+	    "$objbase.o: $file_full\n" .
+	    "	\$(COMPILE) -DOPERATION_$obj $pic->{'cflags'} \\\n" .
+  	    "$renaming" .
+	    "		-c $file_full -o $objbase.o\n";
+	print_ansi2knr($objbase,
+		       $file_full,
+		       " -DOPERATION_$obj\\\n$renaming\t\t");
+	$MANY_OBJS .= " $objbase\$U.o";
+
+      } elsif ($lang eq '.S') {
+	print MAKEFILE
+	    "$objbase.o: $file_full\n" .
+            "	\$(COMPILE) -g $pic->{'asmflags'} \\\n" .
+  	    "$renaming" .
+            "	-c $file_full -o $objbase.o\n";
+	$MANY_OBJS .= " $objbase.o";
+
+      } elsif ($lang eq '.h') {
+	print MAKEFILE
+	    "$objbase.o: tmp-$objbase.c $file_full\n" .
+	    "	\$(COMPILE) -DOPERATION_$obj $pic->{'cflags'} \\\n" .
+  	    "$renaming" .
+	    "		-c tmp-$objbase.c -o $objbase.o\n";
+	print_ansi2knr($objbase,
+		       "tmp-$objbase.c",
+		       " -DOPERATION_$obj\\\n$renaming\t\t");
+	$MANY_OBJS .= " $objbase\$U.o";
+
+        $CLEAN .= " tmp-$objbase.c";
+	open(TMP_C,">tmp-$objbase.c")
+	    or die "Can't create tmp-$objbase.c: $!\n";
+	print TMP_C
+"/* tmp-$objbase.c generated by many.pl - DO NOT EDIT, CHANGES WILL BE LOST */
+
+#include \"gmp.h\"
+#include \"gmp-impl.h\"
+#include \"longlong.h\"
+#include \"speed.h\"
+
+";
+      }
+
+      my $tests_program = "$top_srcdir/tests/devel/$obj.c";
+      if (-f $tests_program) {
+	$tests_program = "\$(top_srcdir)/tests/devel/$obj.c";
+	print_ansi2knr("tests_${objbase}",
+		       $tests_program,
+		       "\\\n$renaming\t\t\$(CFLAGS_TESTS_SP)");
+	print_ansi2knr("tests_${objbase}_sp",
+		       $tests_program,
+		       "\\\n$renaming\t\t\$(CFLAGS_TESTS_SP)");
+
+	print MAKEFILE <<EOF;
+tests_$objbase.o: $tests_program
+	\$(COMPILE) \$(CFLAGS_TESTS) \\
+$renaming		-c $tests_program -o tests_$objbase.o
+
+tests_$objbase: $objbase\$U.o tests_$objbase\$U.o ../libgmp.la
+	\$(LINK) tests_$objbase\$U.o $objbase\$U.o ../libgmp.la -o tests_$objbase
+
+tests_${objbase}_sp.o: $tests_program
+	\$(COMPILE) \$(CFLAGS_TESTS_SP) \\
+$renaming		-c $tests_program -o tests_${objbase}_sp.o
+
+tests_${objbase}_sp: $objbase\$U.o tests_${objbase}_sp\$U.o ../libgmp.la
+	\$(LINK) tests_${objbase}_sp\$U.o $objbase\$U.o ../libgmp.la -o tests_${objbase}_sp
+
+EOF
+        $CLEAN .= " tests_$objbase tests_${objbase}_sp";
+      }
+
+      foreach my $fun (@{$funs}) {
+	print "fun $fun\n" if $opt{'t'};
+
+	if ($lang eq '.h') {
+          my $macro_before = $t->{'macro_before'};
+          $macro_before = "" if ! defined $macro_before;
+	  print TMP_C
+"$macro_before
+#undef $fun
+#include \"$file_full\"
+
+";
+	}
+
+	my $args = $t->{"args_$fun"};
+	if (! defined $args) { $args = $t->{'args'}; }
+	if (! defined $args) { die "Need args for $fun\n"; }
+	print "args $args\n" if $opt{'t'};
+
+	foreach my $carry (@$carrys) {
+	  print "carry $carry\n" if $opt{'t'};
+
+	  my $fun_carry = $fun;
+	  if (! ($fun_carry =~ s/_1/_1$carry/)) { $fun_carry = "$fun$carry"; }
+          print "fun_carry $fun_carry\n" if $opt{'t'};
+
+	  if ($lang =~ /\.(asm|S)/
+	      && ! grep(m"PROLOGUE\((.* )?$mpX$fun_carry[ ,)]",@file_contents)) {
+	    print "no PROLOGUE $mpX$fun_carry\n" if $opt{'t'};
+	    next;
+	  }
+	  if ($lang eq '.c'
+	      && ! grep(m"^(#define FUNCTION\s+)?$mpX$fun_carry\W", @file_contents)) {
+	    print "no mention of $mpX$fun_carry\n" if $opt{'t'};
+	    next;
+	  }
+	  if ($lang eq '.h'
+	      && ! grep(m"^#define $fun_carry\W", @file_contents)) {
+	    print "no mention of #define $fun_carry\n" if $opt{'t'};
+	    next;
+	  }
+
+	  $count_functions++;
+
+	  my $carryarg;
+	  if (defined $t->{'carryarg'}) { $carryarg = $t->{'carryarg'}; }
+	  if ($carry eq '')             { $carryarg = ''; }
+	  else                          { $carryarg = ', mp_limb_t carry'; }
+	  print "carryarg $carryarg\n" if $opt{'t'};
+
+	  my $funfull="$mpX${fun_carry}_$suffix$pic->{'suffix'}";
+	  print "funfull $funfull\n" if $opt{'t'};
+
+	  if ($lang ne '.h') {
+	    my $proto = "$t->{'ret'} $funfull _PROTO (($args$carryarg)); \\\n";
+	    $SPEED_EXTRA_PROTOS .= $proto;
+	    $TRY_EXTRA_PROTOS .= $proto;
+	  }
+
+	  my $try_type = $t->{"try-$fun"};
+	  $try_type = $t->{'try'} if ! defined $try_type;
+	  if (! defined $try_type) {
+	    if ($mpX eq 'mpn_') {
+	      $try_type = "TYPE_\U$fun_carry";
+	    } else {
+	      $try_type = "TYPE_\U$mpX\U$fun_carry";
+	    }
+	  }
+	  print "try_type $try_type\n" if $opt{'t'};
+
+	  my $try_minsize = $t->{'try-minsize'};
+	  if (defined $try_minsize) {
+	    $try_minsize = ", " . $try_minsize;
+	  } else {
+	    $try_minsize = "";
+	  }
+	  print "try_minsize $try_minsize\n" if $opt{'t'};
+
+	  if ($try_type ne 'none') {
+	    $TRY_EXTRA_ROUTINES .=
+		"  { TRY($mpX${fun_carry}_$suffix$pic->{'suffix'}), $try_type$try_minsize }, \\\n";
+	  }
+
+	  my $speed_flags = $t->{'speed_flags'};
+	  $speed_flags = '0' if ! defined $speed_flags;
+	  print "speed_flags $speed_flags\n" if $opt{'t'};
+
+	  my $speed_routine = $t->{'speed'};
+	  $speed_routine = "SPEED_ROUTINE_\U$mpX\U$fun"
+	      if !defined $speed_routine;
+	  if (! ($speed_routine =~ s/_1/_1\U$carry/)) {
+	    $speed_routine = "$speed_routine\U$carry";
+	  }
+	  print "speed_routine $speed_routine\n" if $opt{'t'};
+
+	  my @speed_suffixes = ();
+	  push (@speed_suffixes, '') if $speed_routine ne 'none';
+	  push (@speed_suffixes, @{$t->{'speed_suffixes'}})
+	      if defined $t->{'speed_suffixes'};
+
+          my $macro_speed = $t->{'macro-speed'};
+          $macro_speed = "$speed_routine ($fun_carry)" if ! defined $macro_speed;
+          $macro_speed =~ s/\$fun/$fun_carry/g;
+
+	  foreach my $S (@speed_suffixes) {
+	    my $Sfunfull="$mpX${fun_carry}${S}_$suffix$pic->{'suffix'}";
+
+	    $SPEED_EXTRA_PROTOS .=
+	      "double speed_$Sfunfull _PROTO ((struct speed_params *s)); \\\n";
+	    $SPEED_EXTRA_ROUTINES .=
+	      "  { \"$Sfunfull\", speed_$Sfunfull, $speed_flags }, \\\n";
+	    if ($lang eq '.h') {
+              print TMP_C
+"double
+speed_$Sfunfull (struct speed_params *s)
+{
+$macro_speed
+}
+
+";
+            } else {
+	      $SPEED_CODE .=
+	        "double\n" .
+	        "speed_$Sfunfull (struct speed_params *s)\n" .
+                "{\n" .
+                "$restriction" .
+	        "  $speed_routine\U$S\E ($funfull)\n" .
+                "}\n";
+            }
+	  }
+	}
+      }
+    }
+  }
+}
+
+
+print SPEED $SPEED_EXTRA_PROTOS . "\n";
+print SPEED $SPEED_EXTRA_ROUTINES . "\n";
+if (defined $ENV{speedinc}) { print SPEED $ENV{speedinc} . "\n"; }
+print SPEED
+    "#include \"speed.c\"\n" .
+    "\n";
+print SPEED $SPEED_CODE;
+
+print TRY $TRY_EXTRA_ROUTINES . "\n";
+print TRY $TRY_EXTRA_PROTOS . "\n";
+my $tryinc = "";
+if (defined $ENV{tryinc}) {
+  $tryinc = $ENV{tryinc};
+  print TRY "#include \"$tryinc\"\n";
+}
+print "tryinc $tryinc\n" if $opt{'t'};
+print TRY
+    "#include \"try.c\"\n" .
+    "\n";
+
+my $extra_libraries = "";
+if (defined $ENV{extra_libraries}) { $extra_libraries = $ENV{extra_libraries};}
+
+my $trydeps = "";
+if (defined $ENV{trydeps}) { $trydeps = $ENV{trydeps}; }
+$trydeps .= " $tryinc";
+print "trydeps $trydeps\n" if $opt{'t'};
+
+print MAKEFILE <<EOF;
+
+MANY_OBJS = $MANY_OBJS
+MANY_CLEAN = \$(MANY_OBJS) \\
+	speed-many.c speed-many\$U.o speed-many\$(EXEEXT) \\
+	try-many.c try-many\$U.o try-many \\
+	$CLEAN
+MANY_DISTCLEAN = Makefile.many
+
+speed-many: \$(MANY_OBJS) speed-many\$U.o libspeed.la $extra_libraries
+	\$(LINK) \$(LDFLAGS) speed-many\$U.o \$(MANY_OBJS) \$(LDADD) \$(LIBS) $extra_libraries
+
+try-many: \$(MANY_OBJS) try-many\$U.o libspeed.la $extra_libraries
+	\$(LINK) \$(LDFLAGS) try-many\$U.o \$(MANY_OBJS)  \$(LDADD) \$(LIBS) $extra_libraries
+
+try-many.o: try-many.c \$(top_srcdir)/tests/devel/try.c $trydeps
+	\$(COMPILE) -I\$(top_srcdir)/tests/devel -c try-many.c
+
+EOF
+
+print_ansi2knr("speed-many");
+print_ansi2knr("try-many",
+	       "\$(top_srcdir)/tests/devel/try.c",
+	       "-I\$(top_srcdir)/tests/devel");
+
+print MAKEFILE <<EOF;
+RM_TMP = rm -f
+CFLAGS_TESTS = -DSIZE=50 -DTIMES=1 -DRANDOM -DCLOCK=333000000
+CFLAGS_TESTS_SP = -DSIZE=1024 -DNOCHECK -DOPS=200000000 -DCLOCK=333000000
+EOF
+
+close MAKEFILE or die;
+
+print "Total $count_files files, $count_functions functions\n";
+
+
+
+# Local variables:
+# perl-indent-level: 2
+# End:
diff --git a/third_party/gmp/tune/mod_1_1-1.c b/third_party/gmp/tune/mod_1_1-1.c
new file mode 100644
index 0000000..7de1e42
--- /dev/null
+++ b/third_party/gmp/tune/mod_1_1-1.c
@@ -0,0 +1,40 @@
+/* mpn/generic/mod_1_1.c method 1.
+
+Copyright 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#undef MOD_1_1P_METHOD
+#define MOD_1_1P_METHOD 1
+#undef mpn_mod_1_1p
+#undef mpn_mod_1_1p_cps
+#define mpn_mod_1_1p mpn_mod_1_1p_1
+#define mpn_mod_1_1p_cps mpn_mod_1_1p_cps_1
+
+#include "mpn/generic/mod_1_1.c"
diff --git a/third_party/gmp/tune/mod_1_1-2.c b/third_party/gmp/tune/mod_1_1-2.c
new file mode 100644
index 0000000..980a64f
--- /dev/null
+++ b/third_party/gmp/tune/mod_1_1-2.c
@@ -0,0 +1,40 @@
+/* mpn/generic/mod_1_1.c method 2.
+
+Copyright 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#undef MOD_1_1P_METHOD
+#define MOD_1_1P_METHOD 2
+#undef mpn_mod_1_1p
+#undef mpn_mod_1_1p_cps
+#define mpn_mod_1_1p mpn_mod_1_1p_2
+#define mpn_mod_1_1p_cps mpn_mod_1_1p_cps_2
+
+#include "mpn/generic/mod_1_1.c"
diff --git a/third_party/gmp/tune/mod_1_div.c b/third_party/gmp/tune/mod_1_div.c
new file mode 100644
index 0000000..6268d4e
--- /dev/null
+++ b/third_party/gmp/tune/mod_1_div.c
@@ -0,0 +1,45 @@
+/* mpn/generic/mod_1.c forced to use plain udiv_qrnnd.
+
+Copyright 2000, 2003 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define OPERATION_mod_1
+
+#include "gmp-impl.h"
+
+#undef MOD_1_NORM_THRESHOLD
+#undef MOD_1_UNNORM_THRESHOLD
+#undef MOD_1N_TO_MOD_1_1_THRESHOLD
+#undef MOD_1U_TO_MOD_1_1_THRESHOLD
+#define MOD_1_NORM_THRESHOLD    MP_SIZE_T_MAX
+#define MOD_1_UNNORM_THRESHOLD  MP_SIZE_T_MAX
+#define MOD_1N_TO_MOD_1_1_THRESHOLD MP_SIZE_T_MAX
+#define MOD_1U_TO_MOD_1_1_THRESHOLD MP_SIZE_T_MAX
+#define __gmpn_mod_1  mpn_mod_1_div
+
+#include "mpn/generic/mod_1.c"
diff --git a/third_party/gmp/tune/mod_1_inv.c b/third_party/gmp/tune/mod_1_inv.c
new file mode 100644
index 0000000..3b42710
--- /dev/null
+++ b/third_party/gmp/tune/mod_1_inv.c
@@ -0,0 +1,45 @@
+/* mpn/generic/mod_1.c forced to use mul-by-inverse udiv_qrnnd_preinv.
+
+Copyright 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define OPERATION_mod_1
+
+#include "gmp-impl.h"
+
+#undef MOD_1_NORM_THRESHOLD
+#undef MOD_1_UNNORM_THRESHOLD
+#undef MOD_1N_TO_MOD_1_1_THRESHOLD
+#undef MOD_1U_TO_MOD_1_1_THRESHOLD
+#define MOD_1_NORM_THRESHOLD    0
+#define MOD_1_UNNORM_THRESHOLD  0
+#define MOD_1N_TO_MOD_1_1_THRESHOLD MP_SIZE_T_MAX
+#define MOD_1U_TO_MOD_1_1_THRESHOLD MP_SIZE_T_MAX
+#define __gmpn_mod_1  mpn_mod_1_inv
+
+#include "mpn/generic/mod_1.c"
diff --git a/third_party/gmp/tune/modlinv.c b/third_party/gmp/tune/modlinv.c
new file mode 100644
index 0000000..42c583a
--- /dev/null
+++ b/third_party/gmp/tune/modlinv.c
@@ -0,0 +1,177 @@
+/* Alternate implementations of binvert_limb to compare speeds. */
+
+/*
+Copyright 2000, 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include <stdio.h>
+#include "gmp-impl.h"
+#include "longlong.h"
+#include "speed.h"
+
+
+/* Like the standard version in gmp-impl.h, but with the expressions using a
+   "1-" form.  This has the same number of steps, but "1-" is on the
+   dependent chain, whereas the "2*" in the standard version isn't.
+   Depending on the CPU this should be the same or a touch slower.  */
+
+#if GMP_LIMB_BITS <= 32
+#define binvert_limb_mul1(inv,n)                                \
+  do {                                                          \
+    mp_limb_t  __n = (n);                                       \
+    mp_limb_t  __inv;                                           \
+    ASSERT ((__n & 1) == 1);                                    \
+    __inv = binvert_limb_table[(__n&0xFF)/2]; /*  8 */          \
+    __inv = (1 - __n * __inv) * __inv + __inv;  /* 16 */        \
+    __inv = (1 - __n * __inv) * __inv + __inv;  /* 32 */        \
+    ASSERT (__inv * __n == 1);                                  \
+    (inv) = __inv;                                              \
+  } while (0)
+#endif
+
+#if GMP_LIMB_BITS > 32 && GMP_LIMB_BITS <= 64
+#define binvert_limb_mul1(inv,n)                                \
+  do {                                                          \
+    mp_limb_t  __n = (n);                                       \
+    mp_limb_t  __inv;                                           \
+    ASSERT ((__n & 1) == 1);                                    \
+    __inv = binvert_limb_table[(__n&0xFF)/2]; /*  8 */          \
+    __inv = (1 - __n * __inv) * __inv + __inv;  /* 16 */        \
+    __inv = (1 - __n * __inv) * __inv + __inv;  /* 32 */        \
+    __inv = (1 - __n * __inv) * __inv + __inv;  /* 64 */        \
+    ASSERT (__inv * __n == 1);                                  \
+    (inv) = __inv;                                              \
+  } while (0)
+#endif
+
+
+/* The loop based version used in GMP 3.0 and earlier.  Usually slower than
+   multiplying, due to the number of steps that must be performed.  Much
+   slower when the processor has a good multiply.  */
+
+#define binvert_limb_loop(inv,n)                \
+  do {                                          \
+    mp_limb_t  __v = (n);                       \
+    mp_limb_t  __v_orig = __v;                  \
+    mp_limb_t  __make_zero = 1;                 \
+    mp_limb_t  __two_i = 1;                     \
+    mp_limb_t  __v_inv = 0;                     \
+                                                \
+    ASSERT ((__v & 1) == 1);                    \
+                                                \
+    do                                          \
+      {                                         \
+        while ((__two_i & __make_zero) == 0)    \
+          __two_i <<= 1, __v <<= 1;             \
+        __v_inv += __two_i;                     \
+        __make_zero -= __v;                     \
+      }                                         \
+    while (__make_zero);                        \
+                                                \
+    ASSERT (__v_orig * __v_inv == 1);           \
+    (inv) = __v_inv;                            \
+  } while (0)
+
+
+/* Another loop based version with conditionals, but doing a fixed number of
+   steps. */
+
+#define binvert_limb_cond(inv,n)                \
+  do {                                          \
+    mp_limb_t  __n = (n);                       \
+    mp_limb_t  __rem = (1 - __n) >> 1;          \
+    mp_limb_t  __inv = GMP_LIMB_HIGHBIT;        \
+    int        __count;                         \
+                                                \
+    ASSERT ((__n & 1) == 1);                    \
+                                                \
+    __count = GMP_LIMB_BITS-1;               \
+    do                                          \
+      {                                         \
+        __inv >>= 1;                            \
+        if (__rem & 1)                          \
+          {                                     \
+            __inv |= GMP_LIMB_HIGHBIT;          \
+            __rem -= __n;                       \
+          }                                     \
+        __rem >>= 1;                            \
+      }                                         \
+    while (-- __count);                         \
+                                                \
+    ASSERT (__inv * __n == 1);                  \
+    (inv) = __inv;                              \
+  } while (0)
+
+
+/* Another loop based bitwise version, but purely arithmetic, no
+   conditionals. */
+
+#define binvert_limb_arith(inv,n)                                       \
+  do {                                                                  \
+    mp_limb_t  __n = (n);                                               \
+    mp_limb_t  __rem = (1 - __n) >> 1;                                  \
+    mp_limb_t  __inv = GMP_LIMB_HIGHBIT;                                \
+    mp_limb_t  __lowbit;                                                \
+    int        __count;                                                 \
+                                                                        \
+    ASSERT ((__n & 1) == 1);                                            \
+                                                                        \
+    __count = GMP_LIMB_BITS-1;                                       \
+    do                                                                  \
+      {                                                                 \
+        __lowbit = __rem & 1;                                           \
+        __inv = (__inv >> 1) | (__lowbit << (GMP_LIMB_BITS-1));      \
+        __rem = (__rem - (__n & -__lowbit)) >> 1;                       \
+      }                                                                 \
+    while (-- __count);                                                 \
+                                                                        \
+    ASSERT (__inv * __n == 1);                                          \
+    (inv) = __inv;                                                      \
+  } while (0)
+
+
+double
+speed_binvert_limb_mul1 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MODLIMB_INVERT (binvert_limb_mul1);
+}
+double
+speed_binvert_limb_loop (struct speed_params *s)
+{
+  SPEED_ROUTINE_MODLIMB_INVERT (binvert_limb_loop);
+}
+double
+speed_binvert_limb_cond (struct speed_params *s)
+{
+  SPEED_ROUTINE_MODLIMB_INVERT (binvert_limb_cond);
+}
+double
+speed_binvert_limb_arith (struct speed_params *s)
+{
+  SPEED_ROUTINE_MODLIMB_INVERT (binvert_limb_arith);
+}
diff --git a/third_party/gmp/tune/noop.c b/third_party/gmp/tune/noop.c
new file mode 100644
index 0000000..c127b73
--- /dev/null
+++ b/third_party/gmp/tune/noop.c
@@ -0,0 +1,67 @@
+/* Noop routines.
+
+   These are in a separate file to stop gcc recognising do-nothing functions
+   and optimizing away calls to them.  */
+
+/*
+Copyright 1999, 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#include "speed.h"
+
+
+void
+noop (void)
+{
+}
+
+/*ARGSUSED*/
+void
+noop_1 (mp_limb_t n)
+{
+}
+
+/*ARGSUSED*/
+void
+noop_wxs (mp_ptr wp, mp_srcptr xp, mp_size_t size)
+{
+}
+
+/*ARGSUSED*/
+void
+noop_wxys (mp_ptr wp, mp_srcptr xp, mp_srcptr yp, mp_size_t size)
+{
+}
+
+/*ARGSUSED*/
+void
+mpn_cache_fill_dummy (mp_limb_t n)
+{
+}
diff --git a/third_party/gmp/tune/pentium.asm b/third_party/gmp/tune/pentium.asm
new file mode 100644
index 0000000..fb1e833
--- /dev/null
+++ b/third_party/gmp/tune/pentium.asm
@@ -0,0 +1,60 @@
+dnl  x86 pentium time stamp counter access routine.
+
+dnl  Copyright 1999, 2000, 2005 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+
+C void speed_cyclecounter (unsigned p[2]);
+C
+C Get the pentium rdtsc cycle counter, storing the least significant word in
+C p[0] and the most significant in p[1].
+C
+C cpuid is used to serialize execution.  On big measurements this won't be
+C significant but it may help make small single measurements more accurate.
+
+	.text
+	ALIGN(8)
+
+defframe(PARAM_P,4)
+
+PROLOGUE(speed_cyclecounter)
+deflit(`FRAME',0)
+	pushl	%ebx
+FRAME_pushl()
+	xorl	%eax, %eax
+	cpuid
+	rdtsc
+	movl	PARAM_P, %ebx
+	movl	%eax, (%ebx)
+	movl	%edx, 4(%ebx)
+	popl	%ebx
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/tune/powerpc.asm b/third_party/gmp/tune/powerpc.asm
new file mode 100644
index 0000000..2f4ac27
--- /dev/null
+++ b/third_party/gmp/tune/powerpc.asm
@@ -0,0 +1,53 @@
+dnl  PowerPC mftb_function -- read time base registers.
+
+dnl  Copyright 2002 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C void mftb_function (unsigned a[2]);
+C
+
+ASM_START()
+PROLOGUE(mftb_function)
+
+	C r3	a
+
+L(again):
+	mftbu	r4
+	mftb	r5
+	mftbu	r6
+	cmpw	cr0, r4, r6
+	bne	L(again)
+
+	stw	r5, 0(r3)
+	stw	r4, 4(r3)
+	blr
+
+EPILOGUE()
diff --git a/third_party/gmp/tune/powerpc64.asm b/third_party/gmp/tune/powerpc64.asm
new file mode 100644
index 0000000..1ade996
--- /dev/null
+++ b/third_party/gmp/tune/powerpc64.asm
@@ -0,0 +1,49 @@
+dnl  PowerPC mftb_function -- read time base registers, 64-bit integer.
+
+dnl  Copyright 2002-2004 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C void mftb_function (unsigned a[2]);
+C
+
+ASM_START()
+PROLOGUE(mftb_function)
+
+	C r3	a
+
+	mftb	r5
+
+	srdi	r4, r5, 32
+	stw	r5, 0(r3)
+	stw	r4, 4(r3)
+	blr
+
+EPILOGUE()
diff --git a/third_party/gmp/tune/powm_mod.c b/third_party/gmp/tune/powm_mod.c
new file mode 100644
index 0000000..765fd7b
--- /dev/null
+++ b/third_party/gmp/tune/powm_mod.c
@@ -0,0 +1,38 @@
+/* mpz/powm.c forced to use division. */
+
+/*
+Copyright 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#undef POWM_THRESHOLD
+#define POWM_THRESHOLD  1
+#define __gmpz_powm  mpz_powm_mod
+
+#include "../mpz/powm.c"
diff --git a/third_party/gmp/tune/powm_redc.c b/third_party/gmp/tune/powm_redc.c
new file mode 100644
index 0000000..8584614
--- /dev/null
+++ b/third_party/gmp/tune/powm_redc.c
@@ -0,0 +1,40 @@
+/* mpz/powm.c forced to use REDC. */
+
+/*
+Copyright 2000 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+/* WANT_GLOBAL_REDC makes redc() available for speed and tune program use. */
+#undef POWM_THRESHOLD
+#define POWM_THRESHOLD    MP_SIZE_T_MAX
+#define WANT_REDC_GLOBAL  1
+#define __gmpz_powm  mpz_powm_redc
+
+#include "../mpz/powm.c"
diff --git a/third_party/gmp/tune/pre_divrem_1.c b/third_party/gmp/tune/pre_divrem_1.c
new file mode 100644
index 0000000..66d00da
--- /dev/null
+++ b/third_party/gmp/tune/pre_divrem_1.c
@@ -0,0 +1,40 @@
+/* mpn_preinv_divrem_1 -- if not already in libgmp.
+
+Copyright 2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+#if ! USE_PREINV_DIVREM_1
+
+#undef USE_PREINV_DIVREM_1
+#define USE_PREINV_DIVREM_1 1
+
+#include "mpn/generic/pre_divrem_1.c"
+
+#endif
diff --git a/third_party/gmp/tune/set_strb.c b/third_party/gmp/tune/set_strb.c
new file mode 100644
index 0000000..128c41b
--- /dev/null
+++ b/third_party/gmp/tune/set_strb.c
@@ -0,0 +1,46 @@
+/* mpn_set_str_basecase -- mpn_set_str forced to its basecase.
+
+Copyright 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define __gmpn_set_str mpn_set_str_basecase
+#define __gmpn_bc_set_str mpn_bc_set_str_basecase
+#define __gmpn_dc_set_str mpn_dc_set_str_basecase
+
+#include "gmp-impl.h"
+
+#ifndef SIZE_T_MAX
+#define SIZE_T_MAX  ((size_t) ULONG_MAX)
+#endif
+
+#undef SET_STR_DC_THRESHOLD
+#define SET_STR_DC_THRESHOLD           SIZE_T_MAX /* always */
+#undef SET_STR_PRECOMPUTE_THRESHOLD
+#define SET_STR_PRECOMPUTE_THRESHOLD   SIZE_T_MAX /* always */
+
+#include "mpn/generic/set_str.c"
diff --git a/third_party/gmp/tune/set_strp.c b/third_party/gmp/tune/set_strp.c
new file mode 100644
index 0000000..3053b60
--- /dev/null
+++ b/third_party/gmp/tune/set_strp.c
@@ -0,0 +1,42 @@
+/* mpn_set_str_subquad -- mpn_set_str forced to the sub-quadratic case.
+
+Copyright 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define TUNE_PROGRAM_BUILD  1   /* for gmp-impl.h */
+
+#include "gmp-impl.h"
+
+void
+mpn_pre_set_str (mp_ptr wp, unsigned char *str, size_t str_len, powers_t *powtab, mp_ptr tp)
+{
+  if (BELOW_THRESHOLD (str_len, set_str_dc_threshold))
+    mpn_bc_set_str (wp, str, str_len, powtab->base);
+  else
+    mpn_dc_set_str (wp, str, str_len, powtab, tp);
+}
diff --git a/third_party/gmp/tune/set_strs.c b/third_party/gmp/tune/set_strs.c
new file mode 100644
index 0000000..d2a9fc2
--- /dev/null
+++ b/third_party/gmp/tune/set_strs.c
@@ -0,0 +1,42 @@
+/* mpn_set_str_subquad -- mpn_set_str forced to the sub-quadratic case.
+
+Copyright 2002 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define __gmpn_set_str mpn_set_str_subquad
+#define __gmpn_bc_set_str mpn_bc_set_str_subquad
+#define __gmpn_dc_set_str mpn_dc_set_str_subquad
+
+#include "gmp-impl.h"
+
+#undef SET_STR_DC_THRESHOLD
+#define SET_STR_DC_THRESHOLD  2 /* never */
+#undef SET_STR_PRECOMPUTE_THRESHOLD
+#define SET_STR_PRECOMPUTE_THRESHOLD  2 /* never */
+
+#include "mpn/generic/set_str.c"
diff --git a/third_party/gmp/tune/sparcv9.asm b/third_party/gmp/tune/sparcv9.asm
new file mode 100644
index 0000000..f0981c7
--- /dev/null
+++ b/third_party/gmp/tune/sparcv9.asm
@@ -0,0 +1,45 @@
+dnl  Sparc v9 32-bit time stamp counter access routine.
+
+dnl  Copyright 2000, 2005 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+include(`../config.m4')
+
+
+C void speed_cyclecounter (unsigned p[2]);
+C
+C Get the sparc v9 tick counter.
+
+ASM_START()
+PROLOGUE(speed_cyclecounter)
+	rd	%tick,%g1
+	st	%g1,[%o0]		C low 32 bits
+	srlx	%g1,32,%g4
+	retl
+	st	%g4,[%o0+4]		C high 32 bits
+EPILOGUE(speed_cyclecounter)
diff --git a/third_party/gmp/tune/speed-ext.c b/third_party/gmp/tune/speed-ext.c
new file mode 100644
index 0000000..e7fb8b9
--- /dev/null
+++ b/third_party/gmp/tune/speed-ext.c
@@ -0,0 +1,233 @@
+/* An example of extending the speed program to measure routines not in GMP.
+
+Copyright 1999, 2000, 2002, 2003, 2005 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+/* The extension here is three versions of an mpn arithmetic mean.  These
+   aren't meant to be particularly useful, just examples.
+
+   You can run something like the following to compare their speeds.
+
+           ./speed-ext -s 1-20 -c mean_calls mean_open mean_open2
+
+   On RISC chips, mean_open() might be fastest if the compiler is doing a
+   good job.  On the register starved x86s, mean_calls will be fastest.
+
+
+   Notes:
+
+   SPEED_EXTRA_PROTOS and SPEED_EXTRA_ROUTINES are macros that get expanded
+   by speed.c in useful places.  SPEED_EXTRA_PROTOS goes after the header
+   files, and SPEED_EXTRA_ROUTINES goes in the array of available routines.
+
+   The advantage of this #include "speed.c" scheme is that there's no
+   editing of a copy of that file, and new features in new versions of it
+   will be immediately available.
+
+   In a real program the routines mean_calls() etc would probably be in
+   separate C or assembler source files, and just the measuring
+   speed_mean_calls() etc would be here.  Linking against other libraries
+   for things to measure is perfectly possible too.
+
+   When attempting to compare two versions of the same named routine, say
+   like the generic and assembler versions of mpn_add_n(), creative use of
+   cc -D or #define is suggested, so one or both can be renamed and linked
+   into the same program.  It'll be much easier to compare them side by side
+   than with separate programs for each.
+
+   common.c has notes on writing speed measuring routines.
+
+   Remember to link against tune/libspeed.la (or tune/.libs/libspeed.a if
+   not using libtool) to get common.o and other objects needed by speed.c.  */
+
+
+#define SPEED_EXTRA_PROTOS                                              \
+  double speed_mean_calls (struct speed_params *s);			\
+  double speed_mean_open  (struct speed_params *s);			\
+  double speed_mean_open2 (struct speed_params *s);
+
+#define SPEED_EXTRA_ROUTINES            \
+  { "mean_calls",  speed_mean_calls  }, \
+  { "mean_open",   speed_mean_open   }, \
+  { "mean_open2",  speed_mean_open2  },
+
+#include "speed.c"
+
+
+/* A straightforward implementation calling mpn subroutines.
+
+   wp,size is set to (xp,size + yp,size) / 2.  The return value is the
+   remainder from the division.  The other versions are the same.  */
+
+mp_limb_t
+mean_calls (mp_ptr wp, mp_srcptr xp, mp_srcptr yp, mp_size_t size)
+{
+  mp_limb_t  c, ret;
+
+  ASSERT (size >= 1);
+
+  c = mpn_add_n (wp, xp, yp, size);
+  ret = mpn_rshift (wp, wp, size, 1) >> (GMP_LIMB_BITS-1);
+  wp[size-1] |= (c << (GMP_LIMB_BITS-1));
+  return ret;
+}
+
+
+/* An open-coded version, making one pass over the data.  The right shift is
+   done as the added limbs are produced.  The addition code follows
+   mpn/generic/add_n.c. */
+
+mp_limb_t
+mean_open (mp_ptr wp, mp_srcptr xp, mp_srcptr yp, mp_size_t size)
+{
+  mp_limb_t  w, wprev, x, y, c, ret;
+  mp_size_t  i;
+
+  ASSERT (size >= 1);
+
+  x = xp[0];
+  y = yp[0];
+
+  wprev = x + y;
+  c = (wprev < x);
+  ret = (wprev & 1);
+
+#define RSHIFT(hi,lo)   (((lo) >> 1) | ((hi) << (GMP_LIMB_BITS-1)))
+
+  for (i = 1; i < size; i++)
+    {
+      x = xp[i];
+      y = yp[i];
+
+      w = x + c;
+      c = (w < x);
+      w += y;
+      c += (w < y);
+
+      wp[i-1] = RSHIFT (w, wprev);
+      wprev = w;
+    }
+
+  wp[i-1] = RSHIFT (c, wprev);
+
+  return ret;
+}
+
+
+/* Another one-pass version, but right shifting the source limbs rather than
+   the result limbs.  There's not much chance of this being better than the
+   above, but it's an alternative at least. */
+
+mp_limb_t
+mean_open2 (mp_ptr wp, mp_srcptr xp, mp_srcptr yp, mp_size_t size)
+{
+  mp_limb_t  w, x, y, xnext, ynext, c, ret;
+  mp_size_t  i;
+
+  ASSERT (size >= 1);
+
+  x = xp[0];
+  y = yp[0];
+
+  /* ret is the low bit of x+y, c is the carry out of that low bit add */
+  ret = (x ^ y) & 1;
+  c   = (x & y) & 1;
+
+  for (i = 0; i < size-1; i++)
+    {
+      xnext = xp[i+1];
+      ynext = yp[i+1];
+      x = RSHIFT (xnext, x);
+      y = RSHIFT (ynext, y);
+
+      w = x + c;
+      c = (w < x);
+      w += y;
+      c += (w < y);
+      wp[i] = w;
+
+      x = xnext;
+      y = ynext;
+    }
+
+  wp[i] = (x >> 1) + (y >> 1) + c;
+
+  return ret;
+}
+
+
+/* The speed measuring routines are the same apart from which function they
+   run, so a macro is used.  Actually this macro is the same as
+   SPEED_ROUTINE_MPN_BINARY_N.  */
+
+#define SPEED_ROUTINE_MEAN(mean_fun)                    \
+  {                                                     \
+    unsigned  i;                                        \
+    mp_ptr    wp;                                       \
+    double    t;                                        \
+    TMP_DECL;                                  \
+                                                        \
+    SPEED_RESTRICT_COND (s->size >= 1);                 \
+                                                        \
+    TMP_MARK;                                  \
+    SPEED_TMP_ALLOC_LIMBS (wp, s->size, s->align_wp);   \
+                                                        \
+    speed_operand_src (s, s->xp, s->size);              \
+    speed_operand_src (s, s->yp, s->size);              \
+    speed_operand_dst (s, wp, s->size);                 \
+    speed_cache_fill (s);                               \
+                                                        \
+    speed_starttime ();                                 \
+    i = s->reps;                                        \
+    do                                                  \
+      mean_fun (wp, s->xp, s->yp, s->size);             \
+    while (--i != 0);                                   \
+    t = speed_endtime ();                               \
+                                                        \
+    TMP_FREE;                                  \
+    return t;                                           \
+  }
+
+double
+speed_mean_calls (struct speed_params *s)
+{
+  SPEED_ROUTINE_MEAN (mean_calls);
+}
+
+double
+speed_mean_open (struct speed_params *s)
+{
+  SPEED_ROUTINE_MEAN (mean_open);
+}
+
+double
+speed_mean_open2 (struct speed_params *s)
+{
+  SPEED_ROUTINE_MEAN (mean_open2);
+}
diff --git a/third_party/gmp/tune/speed.c b/third_party/gmp/tune/speed.c
new file mode 100644
index 0000000..1708e4c
--- /dev/null
+++ b/third_party/gmp/tune/speed.c
@@ -0,0 +1,1405 @@
+/* Speed measuring program.
+
+Copyright 1999-2003, 2005, 2006, 2008-2019 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+/* Usage message is in the code below, run with no arguments to print it.
+   See README for interesting applications.
+
+   To add a new routine foo(), create a speed_foo() function in the style of
+   the existing ones and add an entry in the routine[] array.  Put FLAG_R if
+   speed_foo() wants an "r" parameter.
+
+   The routines don't have help messages or descriptions, but most have
+   suggestive names.  See the source code for full details.
+
+*/
+
+#include "config.h"
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>  /* for getpid, R_OK */
+#endif
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>  /* for struct timeval */
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+
+#if HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>  /* for getrusage() */
+#endif
+
+
+#include "gmp-impl.h"
+#include "longlong.h"  /* for the benefit of speed-many.c */
+#include "tests.h"
+#include "speed.h"
+
+
+#if !HAVE_DECL_OPTARG
+extern char *optarg;
+extern int optind, opterr;
+#endif
+
+#if !HAVE_STRTOUL
+#define strtoul(p,e,b)  (unsigned long) strtol(p,e,b)
+#endif
+
+#ifdef SPEED_EXTRA_PROTOS
+SPEED_EXTRA_PROTOS
+#endif
+#ifdef SPEED_EXTRA_PROTOS2
+SPEED_EXTRA_PROTOS2
+#endif
+
+
+#if GMP_LIMB_BITS == 32
+#define GMP_NUMB_0xAA  (CNST_LIMB(0xAAAAAAAA) & GMP_NUMB_MASK)
+#endif
+#if GMP_LIMB_BITS == 64
+#define GMP_NUMB_0xAA  (CNST_LIMB(0xAAAAAAAAAAAAAAAA) & GMP_NUMB_MASK)
+#endif
+
+
+#define CMP_ABSOLUTE     1
+#define CMP_RATIO        2
+#define CMP_DIFFERENCE   3
+#define CMP_DIFFPREV     4
+int  option_cmp = CMP_ABSOLUTE;
+
+#define UNIT_SECONDS        1
+#define UNIT_CYCLES         2
+#define UNIT_CYCLESPERLIMB  3
+int  option_unit = UNIT_SECONDS;
+
+#define DATA_RANDOM   1
+#define DATA_RANDOM2  2
+#define DATA_ZEROS    3
+#define DATA_AAS      4
+#define DATA_FFS      5
+#define DATA_2FD      6
+int  option_data = DATA_RANDOM;
+
+int        option_square = 0;
+double     option_factor = 0.0;
+mp_size_t  option_step = 1;
+int        option_gnuplot = 0;
+char      *option_gnuplot_basename;
+struct size_array_t {
+  mp_size_t start, end;
+} *size_array = NULL;
+mp_size_t  size_num = 0;
+mp_size_t  size_allocnum = 0;
+int        option_resource_usage = 0;
+long       option_seed = 123456789;
+
+struct speed_params  sp;
+
+#define COLUMN_WIDTH  13  /* for the free-form output */
+
+#define FLAG_R            (1<<0)  /* require ".r" */
+#define FLAG_R_OPTIONAL   (1<<1)  /* optional ".r" */
+#define FLAG_RSIZE        (1<<2)
+#define FLAG_NODATA       (1<<3)  /* don't alloc xp, yp */
+
+const struct routine_t {
+  /* constants */
+  const char        *name;
+  speed_function_t  fun;
+  int               flag;
+} routine[] = {
+
+  { "noop",              speed_noop                 },
+  { "noop_wxs",          speed_noop_wxs             },
+  { "noop_wxys",         speed_noop_wxys            },
+
+  { "mpn_add_n",         speed_mpn_add_n,     FLAG_R_OPTIONAL },
+  { "mpn_sub_n",         speed_mpn_sub_n,     FLAG_R_OPTIONAL },
+  { "mpn_add_1",         speed_mpn_add_1,     FLAG_R },
+  { "mpn_add_1_inplace", speed_mpn_add_1_inplace, FLAG_R },
+  { "mpn_sub_1",         speed_mpn_sub_1,     FLAG_R },
+  { "mpn_sub_1_inplace", speed_mpn_sub_1_inplace, FLAG_R },
+
+  { "mpn_add_err1_n",    speed_mpn_add_err1_n    },
+  { "mpn_add_err2_n",    speed_mpn_add_err2_n    },
+  { "mpn_add_err3_n",    speed_mpn_add_err3_n    },
+  { "mpn_sub_err1_n",    speed_mpn_sub_err1_n    },
+  { "mpn_sub_err2_n",    speed_mpn_sub_err2_n    },
+  { "mpn_sub_err3_n",    speed_mpn_sub_err3_n    },
+
+#if HAVE_NATIVE_mpn_add_n_sub_n
+  { "mpn_add_n_sub_n",      speed_mpn_add_n_sub_n,     FLAG_R_OPTIONAL },
+#endif
+
+  { "mpn_addmul_1",      speed_mpn_addmul_1,  FLAG_R },
+  { "mpn_submul_1",      speed_mpn_submul_1,  FLAG_R },
+#if HAVE_NATIVE_mpn_addmul_2
+  { "mpn_addmul_2",      speed_mpn_addmul_2,  FLAG_R_OPTIONAL },
+#endif
+#if HAVE_NATIVE_mpn_addmul_3
+  { "mpn_addmul_3",      speed_mpn_addmul_3,  FLAG_R_OPTIONAL },
+#endif
+#if HAVE_NATIVE_mpn_addmul_4
+  { "mpn_addmul_4",      speed_mpn_addmul_4,  FLAG_R_OPTIONAL },
+#endif
+#if HAVE_NATIVE_mpn_addmul_5
+  { "mpn_addmul_5",      speed_mpn_addmul_5,  FLAG_R_OPTIONAL },
+#endif
+#if HAVE_NATIVE_mpn_addmul_6
+  { "mpn_addmul_6",      speed_mpn_addmul_6,  FLAG_R_OPTIONAL },
+#endif
+#if HAVE_NATIVE_mpn_addmul_7
+  { "mpn_addmul_7",      speed_mpn_addmul_7,  FLAG_R_OPTIONAL },
+#endif
+#if HAVE_NATIVE_mpn_addmul_8
+  { "mpn_addmul_8",      speed_mpn_addmul_8,  FLAG_R_OPTIONAL },
+#endif
+  { "mpn_mul_1",         speed_mpn_mul_1,     FLAG_R },
+  { "mpn_mul_1_inplace", speed_mpn_mul_1_inplace, FLAG_R },
+#if HAVE_NATIVE_mpn_mul_2
+  { "mpn_mul_2",         speed_mpn_mul_2,     FLAG_R_OPTIONAL },
+#endif
+#if HAVE_NATIVE_mpn_mul_3
+  { "mpn_mul_3",         speed_mpn_mul_3,     FLAG_R_OPTIONAL },
+#endif
+#if HAVE_NATIVE_mpn_mul_4
+  { "mpn_mul_4",         speed_mpn_mul_4,     FLAG_R_OPTIONAL },
+#endif
+#if HAVE_NATIVE_mpn_mul_5
+  { "mpn_mul_5",         speed_mpn_mul_5,     FLAG_R_OPTIONAL },
+#endif
+#if HAVE_NATIVE_mpn_mul_6
+  { "mpn_mul_6",         speed_mpn_mul_6,     FLAG_R_OPTIONAL },
+#endif
+
+  { "mpn_divrem_1",      speed_mpn_divrem_1,  FLAG_R },
+  { "mpn_divrem_1f",     speed_mpn_divrem_1f, FLAG_R },
+#if HAVE_NATIVE_mpn_divrem_1c
+  { "mpn_divrem_1c",     speed_mpn_divrem_1c, FLAG_R },
+  { "mpn_divrem_1cf",    speed_mpn_divrem_1cf,FLAG_R },
+#endif
+  { "mpn_mod_1",         speed_mpn_mod_1,     FLAG_R },
+#if HAVE_NATIVE_mpn_mod_1c
+  { "mpn_mod_1c",        speed_mpn_mod_1c,    FLAG_R },
+#endif
+  { "mpn_preinv_divrem_1",  speed_mpn_preinv_divrem_1,  FLAG_R },
+  { "mpn_preinv_divrem_1f", speed_mpn_preinv_divrem_1f, FLAG_R },
+  { "mpn_preinv_mod_1",  speed_mpn_preinv_mod_1, FLAG_R },
+
+  { "mpn_mod_1_1",       speed_mpn_mod_1_1,       FLAG_R },
+  { "mpn_mod_1_1_1",     speed_mpn_mod_1_1_1,     FLAG_R },
+  { "mpn_mod_1_1_2",     speed_mpn_mod_1_1_2,     FLAG_R },
+  { "mpn_mod_1s_2",      speed_mpn_mod_1_2,       FLAG_R },
+  { "mpn_mod_1s_3",      speed_mpn_mod_1_3,       FLAG_R },
+  { "mpn_mod_1s_4",      speed_mpn_mod_1_4,       FLAG_R },
+
+  { "mpn_divrem_1_div",  speed_mpn_divrem_1_div,  FLAG_R },
+  { "mpn_divrem_1_inv",  speed_mpn_divrem_1_inv,  FLAG_R },
+  { "mpn_divrem_1f_div", speed_mpn_divrem_1f_div, FLAG_R },
+  { "mpn_divrem_1f_inv", speed_mpn_divrem_1f_inv, FLAG_R },
+  { "mpn_mod_1_div",     speed_mpn_mod_1_div,     FLAG_R },
+  { "mpn_mod_1_inv",     speed_mpn_mod_1_inv,     FLAG_R },
+
+  { "mpn_divrem_2",      speed_mpn_divrem_2,        },
+  { "mpn_divrem_2_div",  speed_mpn_divrem_2_div,    },
+  { "mpn_divrem_2_inv",  speed_mpn_divrem_2_inv,    },
+
+  { "mpn_div_qr_1n_pi1", speed_mpn_div_qr_1n_pi1, FLAG_R  },
+  { "mpn_div_qr_1n_pi1_1",speed_mpn_div_qr_1n_pi1_1, FLAG_R  },
+  { "mpn_div_qr_1n_pi1_2",speed_mpn_div_qr_1n_pi1_2, FLAG_R  },
+  { "mpn_div_qr_1",      speed_mpn_div_qr_1,      FLAG_R },
+
+  { "mpn_div_qr_2n",     speed_mpn_div_qr_2n,       },
+  { "mpn_div_qr_2u",     speed_mpn_div_qr_2u,       },
+
+  { "mpn_divexact_1",    speed_mpn_divexact_1,    FLAG_R },
+  { "mpn_divexact_by3",  speed_mpn_divexact_by3          },
+
+  { "mpn_bdiv_q_1",      speed_mpn_bdiv_q_1,      FLAG_R },
+  { "mpn_pi1_bdiv_q_1",  speed_mpn_pi1_bdiv_q_1,  FLAG_R_OPTIONAL },
+  { "mpn_bdiv_dbm1c",    speed_mpn_bdiv_dbm1c,    FLAG_R_OPTIONAL },
+
+#if HAVE_NATIVE_mpn_modexact_1_odd
+  { "mpn_modexact_1_odd",  speed_mpn_modexact_1_odd,  FLAG_R },
+#endif
+  { "mpn_modexact_1c_odd", speed_mpn_modexact_1c_odd, FLAG_R },
+
+#if GMP_NUMB_BITS % 4 == 0
+  { "mpn_mod_34lsub1",   speed_mpn_mod_34lsub1 },
+#endif
+
+  { "mpn_lshift",        speed_mpn_lshift, FLAG_R   },
+  { "mpn_lshiftc",       speed_mpn_lshiftc, FLAG_R   },
+  { "mpn_rshift",        speed_mpn_rshift, FLAG_R   },
+
+  { "mpn_and_n",         speed_mpn_and_n,  FLAG_R_OPTIONAL },
+  { "mpn_andn_n",        speed_mpn_andn_n, FLAG_R_OPTIONAL },
+  { "mpn_nand_n",        speed_mpn_nand_n, FLAG_R_OPTIONAL },
+  { "mpn_ior_n",         speed_mpn_ior_n,  FLAG_R_OPTIONAL },
+  { "mpn_iorn_n",        speed_mpn_iorn_n, FLAG_R_OPTIONAL },
+  { "mpn_nior_n",        speed_mpn_nior_n, FLAG_R_OPTIONAL },
+  { "mpn_xor_n",         speed_mpn_xor_n,  FLAG_R_OPTIONAL },
+  { "mpn_xnor_n",        speed_mpn_xnor_n, FLAG_R_OPTIONAL },
+  { "mpn_com",           speed_mpn_com              },
+  { "mpn_neg",           speed_mpn_neg              },
+
+  { "mpn_popcount",      speed_mpn_popcount         },
+  { "mpn_hamdist",       speed_mpn_hamdist          },
+
+  { "mpn_matrix22_mul",  speed_mpn_matrix22_mul     },
+
+  { "mpn_hgcd2",         speed_mpn_hgcd2, FLAG_NODATA },
+  { "mpn_hgcd2_1",       speed_mpn_hgcd2_1, FLAG_NODATA },
+  { "mpn_hgcd2_2",       speed_mpn_hgcd2_2, FLAG_NODATA },
+  { "mpn_hgcd2_3",       speed_mpn_hgcd2_3, FLAG_NODATA },
+  { "mpn_hgcd2_4",       speed_mpn_hgcd2_4, FLAG_NODATA },
+  { "mpn_hgcd2_5",       speed_mpn_hgcd2_5, FLAG_NODATA },
+  { "mpn_hgcd",          speed_mpn_hgcd             },
+  { "mpn_hgcd_lehmer",   speed_mpn_hgcd_lehmer      },
+  { "mpn_hgcd_appr",     speed_mpn_hgcd_appr        },
+  { "mpn_hgcd_appr_lehmer", speed_mpn_hgcd_appr_lehmer },
+
+  { "mpn_hgcd_reduce",   speed_mpn_hgcd_reduce      },
+  { "mpn_hgcd_reduce_1", speed_mpn_hgcd_reduce_1    },
+  { "mpn_hgcd_reduce_2", speed_mpn_hgcd_reduce_2    },
+
+  { "mpn_gcd_1",         speed_mpn_gcd_1,  FLAG_R_OPTIONAL },
+  { "mpn_gcd_11",        speed_mpn_gcd_11, FLAG_R_OPTIONAL },
+  { "mpn_gcd_1N",        speed_mpn_gcd_1N, FLAG_R_OPTIONAL },
+  { "mpn_gcd_22",        speed_mpn_gcd_22, FLAG_R_OPTIONAL },
+
+  { "mpn_gcd",           speed_mpn_gcd                    },
+
+  { "mpn_gcdext",            speed_mpn_gcdext            },
+  { "mpn_gcdext_single",     speed_mpn_gcdext_single     },
+  { "mpn_gcdext_double",     speed_mpn_gcdext_double     },
+  { "mpn_gcdext_one_single", speed_mpn_gcdext_one_single },
+  { "mpn_gcdext_one_double", speed_mpn_gcdext_one_double },
+#if 0
+  { "mpn_gcdext_lehmer",     speed_mpn_gcdext_lehmer     },
+#endif
+
+  { "mpz_nextprime",     speed_mpz_nextprime        },
+
+  { "mpz_jacobi",        speed_mpz_jacobi           },
+  { "mpn_jacobi_base",   speed_mpn_jacobi_base      },
+  { "mpn_jacobi_base_1", speed_mpn_jacobi_base_1    },
+  { "mpn_jacobi_base_2", speed_mpn_jacobi_base_2    },
+  { "mpn_jacobi_base_3", speed_mpn_jacobi_base_3    },
+  { "mpn_jacobi_base_4", speed_mpn_jacobi_base_4    },
+
+  { "mpn_mul",           speed_mpn_mul,         FLAG_R_OPTIONAL },
+  { "mpn_mul_basecase",  speed_mpn_mul_basecase,FLAG_R_OPTIONAL },
+  { "mpn_sqr_basecase",  speed_mpn_sqr_basecase     },
+#if HAVE_NATIVE_mpn_sqr_diagonal
+  { "mpn_sqr_diagonal",  speed_mpn_sqr_diagonal     },
+#endif
+#if HAVE_NATIVE_mpn_sqr_diag_addlsh1
+  { "mpn_sqr_diag_addlsh1", speed_mpn_sqr_diag_addlsh1 },
+#endif
+
+  { "mpn_mul_n",         speed_mpn_mul_n            },
+  { "mpn_sqr",           speed_mpn_sqr              },
+
+  { "mpn_toom2_sqr",     speed_mpn_toom2_sqr        },
+  { "mpn_toom3_sqr",     speed_mpn_toom3_sqr        },
+  { "mpn_toom4_sqr",     speed_mpn_toom4_sqr        },
+  { "mpn_toom6_sqr",     speed_mpn_toom6_sqr        },
+  { "mpn_toom8_sqr",     speed_mpn_toom8_sqr        },
+  { "mpn_toom22_mul",    speed_mpn_toom22_mul       },
+  { "mpn_toom33_mul",    speed_mpn_toom33_mul       },
+  { "mpn_toom44_mul",    speed_mpn_toom44_mul       },
+  { "mpn_toom6h_mul",    speed_mpn_toom6h_mul       },
+  { "mpn_toom8h_mul",    speed_mpn_toom8h_mul       },
+  { "mpn_toom32_mul",    speed_mpn_toom32_mul       },
+  { "mpn_toom42_mul",    speed_mpn_toom42_mul       },
+  { "mpn_toom43_mul",    speed_mpn_toom43_mul       },
+  { "mpn_toom63_mul",    speed_mpn_toom63_mul       },
+  { "mpn_nussbaumer_mul",    speed_mpn_nussbaumer_mul    },
+  { "mpn_nussbaumer_mul_sqr",speed_mpn_nussbaumer_mul_sqr},
+#if WANT_OLD_FFT_FULL
+  { "mpn_mul_fft_full",      speed_mpn_mul_fft_full      },
+  { "mpn_mul_fft_full_sqr",  speed_mpn_mul_fft_full_sqr  },
+#endif
+  { "mpn_mul_fft",       speed_mpn_mul_fft,     FLAG_R_OPTIONAL },
+  { "mpn_mul_fft_sqr",   speed_mpn_mul_fft_sqr, FLAG_R_OPTIONAL },
+
+  { "mpn_sqrlo",          speed_mpn_sqrlo           },
+  { "mpn_sqrlo_basecase", speed_mpn_sqrlo_basecase  },
+  { "mpn_mullo_n",        speed_mpn_mullo_n         },
+  { "mpn_mullo_basecase", speed_mpn_mullo_basecase  },
+
+  { "mpn_mulmid_basecase",  speed_mpn_mulmid_basecase, FLAG_R_OPTIONAL },
+  { "mpn_toom42_mulmid",    speed_mpn_toom42_mulmid },
+  { "mpn_mulmid_n",         speed_mpn_mulmid_n },
+  { "mpn_mulmid",           speed_mpn_mulmid, FLAG_R_OPTIONAL },
+
+  { "mpn_bc_mulmod_bnm1",      speed_mpn_bc_mulmod_bnm1      },
+  { "mpn_mulmod_bnm1",         speed_mpn_mulmod_bnm1         },
+  { "mpn_mulmod_bnm1_rounded", speed_mpn_mulmod_bnm1_rounded },
+  { "mpn_sqrmod_bnm1",         speed_mpn_sqrmod_bnm1         },
+
+  { "mpn_invert",              speed_mpn_invert              },
+  { "mpn_invertappr",          speed_mpn_invertappr          },
+  { "mpn_ni_invertappr",       speed_mpn_ni_invertappr       },
+  { "mpn_binvert",             speed_mpn_binvert             },
+  { "mpn_sec_invert",          speed_mpn_sec_invert          },
+
+  { "mpn_sbpi1_div_qr",        speed_mpn_sbpi1_div_qr,    FLAG_R_OPTIONAL},
+  { "mpn_dcpi1_div_qr",        speed_mpn_dcpi1_div_qr,    FLAG_R_OPTIONAL},
+  { "mpn_mu_div_qr",           speed_mpn_mu_div_qr,       FLAG_R_OPTIONAL},
+  { "mpn_mupi_div_qr",         speed_mpn_mupi_div_qr,     FLAG_R_OPTIONAL},
+  { "mpn_sbpi1_divappr_q",     speed_mpn_sbpi1_divappr_q, FLAG_R_OPTIONAL},
+  { "mpn_dcpi1_divappr_q",     speed_mpn_dcpi1_divappr_q, FLAG_R_OPTIONAL},
+
+  { "mpn_sbpi1_bdiv_qr",       speed_mpn_sbpi1_bdiv_qr       },
+  { "mpn_dcpi1_bdiv_qr",       speed_mpn_dcpi1_bdiv_qr       },
+  { "mpn_sbpi1_bdiv_q",        speed_mpn_sbpi1_bdiv_q        },
+  { "mpn_dcpi1_bdiv_q",        speed_mpn_dcpi1_bdiv_q        },
+  { "mpn_sbpi1_bdiv_r",        speed_mpn_sbpi1_bdiv_r        },
+
+  { "mpn_broot",               speed_mpn_broot,    FLAG_R },
+  { "mpn_broot_invm1",         speed_mpn_broot_invm1, FLAG_R },
+  { "mpn_brootinv",            speed_mpn_brootinv, FLAG_R },
+
+  { "mpn_get_str",          speed_mpn_get_str,     FLAG_R_OPTIONAL },
+  { "mpn_set_str",          speed_mpn_set_str,     FLAG_R_OPTIONAL },
+  { "mpn_set_str_basecase", speed_mpn_bc_set_str,  FLAG_R_OPTIONAL },
+
+  { "mpn_sqrtrem",       speed_mpn_sqrtrem          },
+  { "mpn_rootrem",       speed_mpn_rootrem, FLAG_R  },
+  { "mpn_sqrt",          speed_mpn_sqrt             },
+  { "mpn_root",          speed_mpn_root, FLAG_R     },
+
+  { "mpn_perfect_power_p",  speed_mpn_perfect_power_p,       },
+  { "mpn_perfect_square_p", speed_mpn_perfect_square_p,      },
+
+  { "mpn_fib2_ui",       speed_mpn_fib2_ui,    FLAG_NODATA },
+  { "mpz_fib_ui",        speed_mpz_fib_ui,     FLAG_NODATA },
+  { "mpz_fib2_ui",       speed_mpz_fib2_ui,    FLAG_NODATA },
+  { "mpz_lucnum_ui",     speed_mpz_lucnum_ui,  FLAG_NODATA },
+  { "mpz_lucnum2_ui",    speed_mpz_lucnum2_ui, FLAG_NODATA },
+
+  { "mpz_add",           speed_mpz_add              },
+  { "mpz_invert",        speed_mpz_invert,   FLAG_R_OPTIONAL },
+  { "mpz_bin_uiui",      speed_mpz_bin_uiui, FLAG_NODATA | FLAG_R_OPTIONAL },
+  { "mpz_bin_ui",        speed_mpz_bin_ui,   FLAG_NODATA | FLAG_R_OPTIONAL },
+  { "mpz_fac_ui",        speed_mpz_fac_ui,   FLAG_NODATA   },
+  { "mpz_2fac_ui",       speed_mpz_2fac_ui,  FLAG_NODATA   },
+  { "mpz_mfac_uiui",     speed_mpz_mfac_uiui,  FLAG_NODATA | FLAG_R_OPTIONAL },
+  { "mpz_primorial_ui",  speed_mpz_primorial_ui, FLAG_NODATA },
+  { "mpz_powm",          speed_mpz_powm,     FLAG_R_OPTIONAL },
+  { "mpz_powm_mod",      speed_mpz_powm_mod         },
+  { "mpz_powm_redc",     speed_mpz_powm_redc        },
+  { "mpz_powm_sec",      speed_mpz_powm_sec        },
+  { "mpz_powm_ui",       speed_mpz_powm_ui,  FLAG_R_OPTIONAL },
+
+  { "mpz_mod",           speed_mpz_mod              },
+  { "mpn_redc_1",        speed_mpn_redc_1           },
+  { "mpn_redc_2",        speed_mpn_redc_2           },
+  { "mpn_redc_n",        speed_mpn_redc_n           },
+
+  { "MPN_COPY",          speed_MPN_COPY             },
+  { "MPN_COPY_INCR",     speed_MPN_COPY_INCR        },
+  { "MPN_COPY_DECR",     speed_MPN_COPY_DECR        },
+  { "memcpy",            speed_memcpy               },
+#if HAVE_NATIVE_mpn_copyi
+  { "mpn_copyi",         speed_mpn_copyi            },
+#endif
+#if HAVE_NATIVE_mpn_copyd
+  { "mpn_copyd",         speed_mpn_copyd            },
+#endif
+  { "mpn_sec_tabselect", speed_mpn_sec_tabselect, FLAG_R_OPTIONAL },
+#if HAVE_NATIVE_mpn_addlsh1_n == 1
+  { "mpn_addlsh1_n",     speed_mpn_addlsh1_n, FLAG_R_OPTIONAL },
+#endif
+#if HAVE_NATIVE_mpn_sublsh1_n == 1
+  { "mpn_sublsh1_n",     speed_mpn_sublsh1_n, FLAG_R_OPTIONAL },
+#endif
+#if HAVE_NATIVE_mpn_addlsh1_n_ip1
+  { "mpn_addlsh1_n_ip1", speed_mpn_addlsh1_n_ip1    },
+#endif
+#if HAVE_NATIVE_mpn_addlsh1_n_ip2
+  { "mpn_addlsh1_n_ip2", speed_mpn_addlsh1_n_ip2    },
+#endif
+#if HAVE_NATIVE_mpn_sublsh1_n_ip1
+  { "mpn_sublsh1_n_ip1", speed_mpn_sublsh1_n_ip1    },
+#endif
+#if HAVE_NATIVE_mpn_rsblsh1_n == 1
+  { "mpn_rsblsh1_n",     speed_mpn_rsblsh1_n, FLAG_R_OPTIONAL },
+#endif
+#if HAVE_NATIVE_mpn_addlsh2_n == 1
+  { "mpn_addlsh2_n",     speed_mpn_addlsh2_n, FLAG_R_OPTIONAL },
+#endif
+#if HAVE_NATIVE_mpn_sublsh2_n == 1
+  { "mpn_sublsh2_n",     speed_mpn_sublsh2_n, FLAG_R_OPTIONAL },
+#endif
+#if HAVE_NATIVE_mpn_addlsh2_n_ip1
+  { "mpn_addlsh2_n_ip1", speed_mpn_addlsh2_n_ip1    },
+#endif
+#if HAVE_NATIVE_mpn_addlsh2_n_ip2
+  { "mpn_addlsh2_n_ip2", speed_mpn_addlsh2_n_ip2    },
+#endif
+#if HAVE_NATIVE_mpn_sublsh2_n_ip1
+  { "mpn_sublsh2_n_ip1", speed_mpn_sublsh2_n_ip1    },
+#endif
+#if HAVE_NATIVE_mpn_rsblsh2_n == 1
+  { "mpn_rsblsh2_n",     speed_mpn_rsblsh2_n, FLAG_R_OPTIONAL },
+#endif
+#if HAVE_NATIVE_mpn_addlsh_n
+  { "mpn_addlsh_n",     speed_mpn_addlsh_n, FLAG_R_OPTIONAL },
+#endif
+#if HAVE_NATIVE_mpn_sublsh_n
+  { "mpn_sublsh_n",     speed_mpn_sublsh_n, FLAG_R_OPTIONAL },
+#endif
+#if HAVE_NATIVE_mpn_addlsh_n_ip1
+  { "mpn_addlsh_n_ip1", speed_mpn_addlsh_n_ip1    },
+#endif
+#if HAVE_NATIVE_mpn_addlsh_n_ip2
+  { "mpn_addlsh_n_ip2", speed_mpn_addlsh_n_ip2    },
+#endif
+#if HAVE_NATIVE_mpn_sublsh_n_ip1
+  { "mpn_sublsh_n_ip1", speed_mpn_sublsh_n_ip1    },
+#endif
+#if HAVE_NATIVE_mpn_rsblsh_n
+  { "mpn_rsblsh_n",     speed_mpn_rsblsh_n, FLAG_R_OPTIONAL },
+#endif
+#if HAVE_NATIVE_mpn_rsh1add_n
+  { "mpn_rsh1add_n",     speed_mpn_rsh1add_n, FLAG_R_OPTIONAL },
+#endif
+#if HAVE_NATIVE_mpn_rsh1sub_n
+  { "mpn_rsh1sub_n",     speed_mpn_rsh1sub_n, FLAG_R_OPTIONAL },
+#endif
+
+  { "mpn_cnd_add_n",     speed_mpn_cnd_add_n, FLAG_R_OPTIONAL },
+  { "mpn_cnd_sub_n",     speed_mpn_cnd_sub_n, FLAG_R_OPTIONAL },
+
+  { "MPN_ZERO",          speed_MPN_ZERO             },
+
+  { "binvert_limb",       speed_binvert_limb,       FLAG_NODATA },
+  { "binvert_limb_mul1",  speed_binvert_limb_mul1,  FLAG_NODATA },
+  { "binvert_limb_loop",  speed_binvert_limb_loop,  FLAG_NODATA },
+  { "binvert_limb_cond",  speed_binvert_limb_cond,  FLAG_NODATA },
+  { "binvert_limb_arith", speed_binvert_limb_arith, FLAG_NODATA },
+
+  { "malloc_free",                  speed_malloc_free                  },
+  { "malloc_realloc_free",          speed_malloc_realloc_free          },
+  { "gmp_allocate_free",            speed_gmp_allocate_free            },
+  { "gmp_allocate_reallocate_free", speed_gmp_allocate_reallocate_free },
+  { "mpz_init_clear",               speed_mpz_init_clear               },
+  { "mpq_init_clear",               speed_mpq_init_clear               },
+  { "mpf_init_clear",               speed_mpf_init_clear               },
+  { "mpz_init_realloc_clear",       speed_mpz_init_realloc_clear       },
+
+  { "umul_ppmm",         speed_umul_ppmm,     FLAG_R_OPTIONAL },
+#if HAVE_NATIVE_mpn_umul_ppmm
+  { "mpn_umul_ppmm",     speed_mpn_umul_ppmm, FLAG_R_OPTIONAL },
+#endif
+#if HAVE_NATIVE_mpn_umul_ppmm_r
+  { "mpn_umul_ppmm_r",   speed_mpn_umul_ppmm_r, FLAG_R_OPTIONAL },
+#endif
+
+  { "count_leading_zeros",  speed_count_leading_zeros,  FLAG_NODATA | FLAG_R_OPTIONAL },
+  { "count_trailing_zeros", speed_count_trailing_zeros, FLAG_NODATA | FLAG_R_OPTIONAL },
+
+  { "udiv_qrnnd",             speed_udiv_qrnnd,             FLAG_R_OPTIONAL },
+  { "udiv_qrnnd_c",           speed_udiv_qrnnd_c,           FLAG_R_OPTIONAL },
+#if HAVE_NATIVE_mpn_udiv_qrnnd
+  { "mpn_udiv_qrnnd",         speed_mpn_udiv_qrnnd,         FLAG_R_OPTIONAL },
+#endif
+#if HAVE_NATIVE_mpn_udiv_qrnnd_r
+  { "mpn_udiv_qrnnd_r",       speed_mpn_udiv_qrnnd_r,       FLAG_R_OPTIONAL },
+#endif
+  { "invert_limb",            speed_invert_limb,            FLAG_R_OPTIONAL },
+
+  { "operator_div",           speed_operator_div,           FLAG_R_OPTIONAL },
+  { "operator_mod",           speed_operator_mod,           FLAG_R_OPTIONAL },
+
+  { "gmp_randseed",    speed_gmp_randseed,    FLAG_R_OPTIONAL               },
+  { "gmp_randseed_ui", speed_gmp_randseed_ui, FLAG_R_OPTIONAL | FLAG_NODATA },
+  { "mpz_urandomb",    speed_mpz_urandomb,    FLAG_R_OPTIONAL | FLAG_NODATA },
+
+#ifdef SPEED_EXTRA_ROUTINES
+  SPEED_EXTRA_ROUTINES
+#endif
+#ifdef SPEED_EXTRA_ROUTINES2
+  SPEED_EXTRA_ROUTINES2
+#endif
+};
+
+
+struct choice_t {
+  const struct routine_t  *p;
+  mp_limb_t               r;
+  double                  scale;
+  double                  time;
+  int                     no_time;
+  double                  prev_time;
+  const char              *name;
+};
+struct choice_t  *choice;
+int  num_choices = 0;
+
+
+void
+data_fill (mp_ptr ptr, mp_size_t size)
+{
+  switch (option_data) {
+  case DATA_RANDOM:
+    mpn_random (ptr, size);
+    break;
+  case DATA_RANDOM2:
+    mpn_random2 (ptr, size);
+    break;
+  case DATA_ZEROS:
+    MPN_ZERO (ptr, size);
+    break;
+  case DATA_AAS:
+    MPN_FILL (ptr, size, GMP_NUMB_0xAA);
+    break;
+  case DATA_FFS:
+    MPN_FILL (ptr, size, GMP_NUMB_MAX);
+    break;
+  case DATA_2FD:
+    MPN_FILL (ptr, size, GMP_NUMB_MAX);
+    ptr[0] -= 2;
+    break;
+  default:
+    abort();
+    /*NOTREACHED*/
+  }
+}
+
+/* The code here handling the various combinations of output options isn't
+   too attractive, but it works and is fairly clean.  */
+
+#define SIZE_TO_DIVISOR(n)              \
+  (option_square == 1 ? (n)*(n)         \
+  : option_square == 2 ? (n)*((n)+1)/2  \
+  : (n))
+
+void
+run_one (FILE *fp, struct speed_params *s, mp_size_t prev_size)
+{
+  const char  *first_open_fastest, *first_open_notfastest, *first_close;
+  int         i, fastest, want_data;
+  double      fastest_time;
+  TMP_DECL;
+
+  TMP_MARK;
+
+  /* allocate data, unless all routines are NODATA */
+  want_data = 0;
+  for (i = 0; i < num_choices; i++)
+    want_data |= ((choice[i].p->flag & FLAG_NODATA) == 0);
+
+  if (want_data)
+    {
+      SPEED_TMP_ALLOC_LIMBS (sp.xp, s->size, s->align_xp);
+      SPEED_TMP_ALLOC_LIMBS (sp.yp, s->size, s->align_yp);
+
+      data_fill (s->xp, s->size);
+      data_fill (s->yp, s->size);
+    }
+  else
+    {
+      sp.xp = NULL;
+      sp.yp = NULL;
+    }
+
+  if (prev_size == -1 && option_cmp == CMP_DIFFPREV)
+    {
+      first_open_fastest = "(#";
+      first_open_notfastest = " (";
+      first_close = ")";
+    }
+  else
+    {
+      first_open_fastest = "#";
+      first_open_notfastest = " ";
+      first_close = "";
+    }
+
+  fastest = -1;
+  fastest_time = -1.0;
+  for (i = 0; i < num_choices; i++)
+    {
+      s->r = choice[i].r;
+      choice[i].time = speed_measure (choice[i].p->fun, s);
+      choice[i].no_time = (choice[i].time == -1.0);
+      if (! choice[i].no_time)
+        choice[i].time *= choice[i].scale;
+
+      /* Apply the effect of CMP_DIFFPREV, but the new choice[i].prev_time
+         is before any differences.  */
+      {
+        double     t;
+        t = choice[i].time;
+        if (t != -1.0 && option_cmp == CMP_DIFFPREV && prev_size != -1)
+          {
+            if (choice[i].prev_time == -1.0)
+              choice[i].no_time = 1;
+            else
+              choice[i].time = choice[i].time - choice[i].prev_time;
+          }
+        choice[i].prev_time = t;
+      }
+
+      if (choice[i].no_time)
+        continue;
+
+      /* Look for the fastest after CMP_DIFFPREV has been applied, but
+         before CMP_RATIO or CMP_DIFFERENCE.  There's only a fastest shown
+         if there's more than one routine.  */
+      if (num_choices > 1 && (fastest == -1 || choice[i].time < fastest_time))
+        {
+          fastest = i;
+          fastest_time = choice[i].time;
+        }
+
+      if (option_cmp == CMP_DIFFPREV)
+        {
+          /* Conversion for UNIT_CYCLESPERLIMB differs in CMP_DIFFPREV. */
+          if (option_unit == UNIT_CYCLES)
+            choice[i].time /= speed_cycletime;
+          else if (option_unit == UNIT_CYCLESPERLIMB)
+            {
+              if (prev_size == -1)
+                choice[i].time /= speed_cycletime;
+              else
+                choice[i].time /=  (speed_cycletime
+                                    * (SIZE_TO_DIVISOR(s->size)
+                                       - SIZE_TO_DIVISOR(prev_size)));
+            }
+        }
+      else
+        {
+          if (option_unit == UNIT_CYCLES)
+            choice[i].time /= speed_cycletime;
+          else if (option_unit == UNIT_CYCLESPERLIMB)
+            choice[i].time /= (speed_cycletime * SIZE_TO_DIVISOR(s->size));
+
+          if (option_cmp == CMP_RATIO && i > 0)
+            {
+              /* A ratio isn't affected by the units chosen. */
+              if (choice[0].no_time || choice[0].time == 0.0)
+                choice[i].no_time = 1;
+              else
+                choice[i].time /= choice[0].time;
+            }
+          else if (option_cmp == CMP_DIFFERENCE && i > 0)
+            {
+              if (choice[0].no_time)
+                {
+                  choice[i].no_time = 1;
+                  continue;
+                }
+              choice[i].time -= choice[0].time;
+            }
+        }
+    }
+
+  if (option_gnuplot)
+    {
+      /* In CMP_DIFFPREV, don't print anything for the first size, start
+         with the second where an actual difference is available.
+
+         In CMP_RATIO, print the first column as 1.0.
+
+         The 9 decimals printed is much more than the expected precision of
+         the measurements actually. */
+
+      if (! (option_cmp == CMP_DIFFPREV && prev_size == -1))
+        {
+          fprintf (fp, "%-6ld ", s->size);
+          for (i = 0; i < num_choices; i++)
+            fprintf (fp, "  %.9e",
+                     choice[i].no_time ? 0.0
+                     : (option_cmp == CMP_RATIO && i == 0) ? 1.0
+                     : choice[i].time);
+          fprintf (fp, "\n");
+        }
+    }
+  else
+    {
+      fprintf (fp, "%-6ld ", s->size);
+      for (i = 0; i < num_choices; i++)
+        {
+          char  buf[128];
+          int   decimals;
+
+          if (choice[i].no_time)
+            {
+              fprintf (fp, " %*s", COLUMN_WIDTH, "n/a");
+            }
+          else
+            {if (option_unit == UNIT_CYCLESPERLIMB
+                 || (option_cmp == CMP_RATIO && i > 0))
+                decimals = 4;
+              else if (option_unit == UNIT_CYCLES)
+                decimals = 2;
+              else
+                decimals = 9;
+
+              sprintf (buf, "%s%.*f%s",
+                       i == fastest ? first_open_fastest : first_open_notfastest,
+                       decimals, choice[i].time, first_close);
+              fprintf (fp, " %*s", COLUMN_WIDTH, buf);
+            }
+        }
+      fprintf (fp, "\n");
+    }
+
+  TMP_FREE;
+}
+
+void
+run_all (FILE *fp)
+{
+  mp_size_t  prev_size;
+  int        i;
+  TMP_DECL;
+
+  TMP_MARK;
+  SPEED_TMP_ALLOC_LIMBS (sp.xp_block, SPEED_BLOCK_SIZE, sp.align_xp);
+  SPEED_TMP_ALLOC_LIMBS (sp.yp_block, SPEED_BLOCK_SIZE, sp.align_yp);
+
+  data_fill (sp.xp_block, SPEED_BLOCK_SIZE);
+  data_fill (sp.yp_block, SPEED_BLOCK_SIZE);
+
+  for (i = 0; i < size_num; i++)
+    {
+      sp.size = size_array[i].start;
+      prev_size = -1;
+      for (;;)
+        {
+          mp_size_t  step;
+
+          if (option_data == DATA_2FD && sp.size >= 2)
+            sp.xp[sp.size-1] = 2;
+
+          run_one (fp, &sp, prev_size);
+          prev_size = sp.size;
+
+          if (option_data == DATA_2FD && sp.size >= 2)
+            sp.xp[sp.size-1] = MP_LIMB_T_MAX;
+
+          if (option_factor != 0.0)
+            {
+              step = (mp_size_t) (sp.size * option_factor - sp.size);
+              if (step < 1)
+                step = 1;
+            }
+          else
+            step = 1;
+          if (step < option_step)
+            step = option_step;
+
+          sp.size += step;
+          if (sp.size > size_array[i].end)
+            break;
+        }
+    }
+
+  TMP_FREE;
+}
+
+
+FILE *
+fopen_for_write (const char *filename)
+{
+  FILE  *fp;
+  if ((fp = fopen (filename, "w")) == NULL)
+    {
+      fprintf (stderr, "Cannot create %s\n", filename);
+      exit(1);
+    }
+  return fp;
+}
+
+void
+fclose_written (FILE *fp, const char *filename)
+{
+  int  err;
+
+  err = ferror (fp);
+  err |= fclose (fp);
+
+  if (err)
+    {
+      fprintf (stderr, "Error writing %s\n", filename);
+      exit(1);
+    }
+}
+
+
+void
+run_gnuplot (int argc, char *argv[])
+{
+  char  *plot_filename;
+  char  *data_filename;
+  FILE  *fp;
+  int   i;
+
+  plot_filename = (char *) (*__gmp_allocate_func)
+    (strlen (option_gnuplot_basename) + 20);
+  data_filename = (char *) (*__gmp_allocate_func)
+    (strlen (option_gnuplot_basename) + 20);
+
+  sprintf (plot_filename, "%s.gnuplot", option_gnuplot_basename);
+  sprintf (data_filename, "%s.data",    option_gnuplot_basename);
+
+  fp = fopen_for_write (plot_filename);
+
+  fprintf (fp, "# Generated with:\n");
+  fprintf (fp, "#");
+  for (i = 0; i < argc; i++)
+    fprintf (fp, " %s", argv[i]);
+  fprintf (fp, "\n");
+  fprintf (fp, "\n");
+
+  fprintf (fp, "reset\n");
+
+  /* Putting the key at the top left is usually good, and you can change it
+     interactively if it's not. */
+  fprintf (fp, "set key left\n");
+
+  /* write underscores, not subscripts */
+  fprintf (fp, "set termoption noenhanced\n");
+
+  /* designed to make it possible to see crossovers easily */
+  fprintf (fp, "set style data lines\n");
+
+  fprintf (fp, "plot ");
+  for (i = 0; i < num_choices; i++)
+    {
+      fprintf (fp, " \"%s\" using 1:%d", data_filename, i+2);
+      fprintf (fp, " title \"%s\"", choice[i].name);
+
+      if (i != num_choices-1)
+        fprintf (fp, ", \\");
+      fprintf (fp, "\n");
+    }
+
+  fprintf (fp, "load \"-\"\n");
+  fclose_written (fp, plot_filename);
+
+  fp = fopen_for_write (data_filename);
+
+  /* Unbuffered so you can see where the program was up to if it crashes or
+     you kill it. */
+  setbuf (fp, NULL);
+
+  run_all (fp);
+  fclose_written (fp, data_filename);
+}
+
+
+/* Return a limb with n many one bits (starting from the least significant) */
+
+#define LIMB_ONES(n) \
+  ((n) == GMP_LIMB_BITS ? MP_LIMB_T_MAX      \
+    : (n) == 0 ? CNST_LIMB(0)                   \
+    : (CNST_LIMB(1) << (n)) - 1)
+
+mp_limb_t
+r_string (const char *s)
+{
+  const char  *s_orig = s;
+  long        n;
+
+  if (strcmp (s, "aas") == 0)
+    return GMP_NUMB_0xAA;
+
+  {
+    mpz_t      z;
+    mp_limb_t  l;
+    int        set, siz;
+
+    mpz_init (z);
+    set = mpz_set_str (z, s, 0);
+    siz = SIZ(z);
+    l = (siz == 0 ? 0 : siz > 0 ? PTR(z)[0] : -PTR(z)[0]);
+    mpz_clear (z);
+    if (set == 0)
+      {
+        if (siz > 1 || siz < -1)
+          printf ("Warning, r parameter %s truncated to %d bits\n",
+                  s_orig, GMP_LIMB_BITS);
+        return l;
+      }
+  }
+
+  if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))
+    n = strtoul (s+2, (char **) &s, 16);
+  else
+    n = strtol (s, (char **) &s, 10);
+
+  if (strcmp (s, "bits") == 0)
+    {
+      mp_limb_t  l;
+      if (n > GMP_LIMB_BITS)
+        {
+          fprintf (stderr, "%ld bit parameter invalid (max %d bits)\n",
+                   n, GMP_LIMB_BITS);
+          exit (1);
+        }
+      mpn_random (&l, 1);
+      return (l | (CNST_LIMB(1) << (n-1))) & LIMB_ONES(n);
+    }
+  else  if (strcmp (s, "ones") == 0)
+    {
+      if (n > GMP_LIMB_BITS)
+        {
+          fprintf (stderr, "%ld bit parameter invalid (max %d bits)\n",
+                   n, GMP_LIMB_BITS);
+          exit (1);
+        }
+      return LIMB_ONES (n);
+    }
+  else if (*s != '\0')
+    {
+      fprintf (stderr, "invalid r parameter: %s\n", s_orig);
+      exit (1);
+    }
+
+  return n;
+}
+
+
+void
+routine_find (struct choice_t *c, const char *s_orig)
+{
+  const char  *s;
+  int     i;
+  size_t  nlen;
+
+  c->name = s_orig;
+  s = strchr (s_orig, '*');
+  if (s != NULL)
+    {
+      c->scale = atof(s_orig);
+      s++;
+    }
+  else
+    {
+      c->scale = 1.0;
+      s = s_orig;
+    }
+
+  for (i = 0; i < numberof (routine); i++)
+    {
+      nlen = strlen (routine[i].name);
+      if (memcmp (s, routine[i].name, nlen) != 0)
+        continue;
+
+      if (s[nlen] == '.')
+        {
+          /* match, with a .r parameter */
+
+          if (! (routine[i].flag & (FLAG_R|FLAG_R_OPTIONAL)))
+            {
+              fprintf (stderr,
+                       "Choice %s bad: doesn't take a \".<r>\" parameter\n",
+                       s_orig);
+              exit (1);
+            }
+
+          c->p = &routine[i];
+          c->r = r_string (s + nlen + 1);
+          return;
+        }
+
+      if (s[nlen] == '\0')
+        {
+          /* match, with no parameter */
+
+          if (routine[i].flag & FLAG_R)
+            {
+              fprintf (stderr,
+                       "Choice %s bad: needs a \".<r>\" parameter\n",
+                       s_orig);
+              exit (1);
+            }
+
+          c->p = &routine[i];
+          c->r = 0;
+          return;
+        }
+    }
+
+  fprintf (stderr, "Choice %s unrecognised\n", s_orig);
+  exit (1);
+}
+
+
+void
+usage (void)
+{
+  int  i;
+
+  speed_time_init ();
+
+  printf ("Usage: speed [-options] -s size <routine>...\n");
+  printf ("Measure the speed of some routines.\n");
+  printf ("Times are in seconds, accuracy is shown.\n");
+  printf ("\n");
+  printf ("   -p num     set precision as number of time units each routine must run\n");
+  printf ("   -s size[-end][,size[-end]]...   sizes to measure\n");
+  printf ("              single sizes or ranges, sep with comma or use multiple -s\n");
+  printf ("   -t step    step through sizes by given amount\n");
+  printf ("   -f factor  step through sizes by given factor (eg. 1.05)\n");
+  printf ("   -r         show times as ratios of the first routine\n");
+  printf ("   -d         show times as difference from the first routine\n");
+  printf ("   -D         show times as difference from previous size shown\n");
+  printf ("   -c         show times in CPU cycles\n");
+  printf ("   -C         show times in cycles per limb\n");
+  printf ("   -u         print resource usage (memory) at end\n");
+  printf ("   -P name    output plot files \"name.gnuplot\" and \"name.data\"\n");
+  printf ("   -a <type>  use given data: random(default), random2, zeros, aas, ffs, 2fd\n");
+  printf ("   -x, -y, -w, -W <align>  specify data alignments, sources and dests\n");
+  printf ("   -o addrs   print addresses of data blocks\n");
+  printf ("\n");
+  printf ("If both -t and -f are used, it means step by the factor or the step, whichever\n");
+  printf ("is greater.\n");
+  printf ("If both -C and -D are used, it means cycles per however many limbs between a\n");
+  printf ("size and the previous size.\n");
+  printf ("\n");
+  printf ("After running with -P, plots can be viewed with Gnuplot or Quickplot.\n");
+  printf ("\"gnuplot name.gnuplot\" (use \"set logscale xy; replot\" at the prompt for\n");
+  printf ("a log/log plot).\n");
+  printf ("\"quickplot -s name.data\" (has interactive zooming, and note -s is important\n");
+  printf ("when viewing more than one routine, it means same axis scales for all data).\n");
+  printf ("\n");
+  printf ("The available routines are as follows.\n");
+  printf ("\n");
+
+  for (i = 0; i < numberof (routine); i++)
+    {
+      if (routine[i].flag & FLAG_R)
+        printf ("\t%s.r\n", routine[i].name);
+      else if (routine[i].flag & FLAG_R_OPTIONAL)
+        printf ("\t%s (optional .r)\n", routine[i].name);
+      else
+        printf ("\t%s\n", routine[i].name);
+    }
+  printf ("\n");
+  printf ("Routines with a \".r\" need an extra parameter, for example mpn_lshift.6\n");
+  printf ("r should be in decimal, or use 0xN for hexadecimal.\n");
+  printf ("\n");
+  printf ("Special forms for r are \"<N>bits\" for a random N bit number, \"<N>ones\" for\n");
+  printf ("N one bits, or \"aas\" for 0xAA..AA.\n");
+  printf ("\n");
+  printf ("Times for sizes out of the range accepted by a routine are shown as 0.\n");
+  printf ("The fastest routine at each size is marked with a # (free form output only).\n");
+  printf ("\n");
+  printf ("%s", speed_time_string);
+  printf ("\n");
+  printf ("Gnuplot home page http://www.gnuplot.info/\n");
+  printf ("Quickplot home page http://quickplot.sourceforge.net/\n");
+}
+
+void
+check_align_option (const char *name, mp_size_t align)
+{
+  if (align < 0 || align > SPEED_TMP_ALLOC_ADJUST_MASK)
+    {
+      fprintf (stderr, "Alignment request out of range: %s %ld\n",
+               name, (long) align);
+      fprintf (stderr, "  should be 0 to %d (limbs), inclusive\n",
+               SPEED_TMP_ALLOC_ADJUST_MASK);
+      exit (1);
+    }
+}
+
+int
+main (int argc, char *argv[])
+{
+  int  i;
+  int  opt;
+
+  /* Unbuffered so output goes straight out when directed to a pipe or file
+     and isn't lost on killing the program half way.  */
+  setbuf (stdout, NULL);
+
+  for (;;)
+    {
+      opt = getopt(argc, argv, "a:CcDdEFf:o:p:P:rRs:t:ux:y:w:W:z");
+      if (opt == EOF)
+        break;
+
+      switch (opt) {
+      case 'a':
+        if (strcmp (optarg, "random") == 0)       option_data = DATA_RANDOM;
+        else if (strcmp (optarg, "random2") == 0) option_data = DATA_RANDOM2;
+        else if (strcmp (optarg, "zeros") == 0)   option_data = DATA_ZEROS;
+        else if (strcmp (optarg, "aas") == 0)     option_data = DATA_AAS;
+        else if (strcmp (optarg, "ffs") == 0)     option_data = DATA_FFS;
+        else if (strcmp (optarg, "2fd") == 0)     option_data = DATA_2FD;
+        else
+          {
+            fprintf (stderr, "unrecognised data option: %s\n", optarg);
+            exit (1);
+          }
+        break;
+      case 'C':
+        if (option_unit  != UNIT_SECONDS) goto bad_unit;
+        option_unit = UNIT_CYCLESPERLIMB;
+        break;
+      case 'c':
+        if (option_unit != UNIT_SECONDS)
+          {
+          bad_unit:
+            fprintf (stderr, "cannot use more than one of -c, -C\n");
+            exit (1);
+          }
+        option_unit = UNIT_CYCLES;
+        break;
+      case 'D':
+        if (option_cmp != CMP_ABSOLUTE) goto bad_cmp;
+        option_cmp = CMP_DIFFPREV;
+        break;
+      case 'd':
+        if (option_cmp != CMP_ABSOLUTE)
+          {
+          bad_cmp:
+            fprintf (stderr, "cannot use more than one of -d, -D, -r\n");
+            exit (1);
+          }
+        option_cmp = CMP_DIFFERENCE;
+        break;
+      case 'E':
+        option_square = 1;
+        break;
+      case 'F':
+        option_square = 2;
+        break;
+      case 'f':
+        option_factor = atof (optarg);
+        if (option_factor <= 1.0)
+          {
+            fprintf (stderr, "-f factor must be > 1.0\n");
+            exit (1);
+          }
+        break;
+      case 'o':
+        speed_option_set (optarg);
+        break;
+      case 'P':
+        option_gnuplot = 1;
+        option_gnuplot_basename = optarg;
+        break;
+      case 'p':
+        speed_precision = atoi (optarg);
+        break;
+      case 'R':
+        option_seed = time (NULL);
+        break;
+      case 'r':
+        if (option_cmp != CMP_ABSOLUTE)
+          goto bad_cmp;
+        option_cmp = CMP_RATIO;
+        break;
+      case 's':
+        {
+          char  *s;
+          for (s = strtok (optarg, ","); s != NULL; s = strtok (NULL, ","))
+            {
+              if (size_num == size_allocnum)
+                {
+                  size_array = (struct size_array_t *)
+                    __gmp_allocate_or_reallocate
+                    (size_array,
+                     size_allocnum * sizeof(size_array[0]),
+                     (size_allocnum+10) * sizeof(size_array[0]));
+                  size_allocnum += 10;
+                }
+              if (sscanf (s, "%ld-%ld",
+                          &size_array[size_num].start,
+                          &size_array[size_num].end) != 2)
+                {
+                  size_array[size_num].start = size_array[size_num].end
+                    = atol (s);
+                }
+
+              if (size_array[size_num].start < 0
+                  || size_array[size_num].end < 0
+                  || size_array[size_num].start > size_array[size_num].end)
+                {
+                  fprintf (stderr, "invalid size parameter: %s\n", s);
+                  exit (1);
+                }
+
+              size_num++;
+            }
+        }
+        break;
+      case 't':
+        option_step = atol (optarg);
+        if (option_step < 1)
+          {
+            fprintf (stderr, "-t step must be >= 1\n");
+            exit (1);
+          }
+        break;
+      case 'u':
+        option_resource_usage = 1;
+        break;
+      case 'z':
+        sp.cache = 1;
+        break;
+      case 'x':
+        sp.align_xp = atol (optarg);
+        check_align_option ("-x", sp.align_xp);
+        break;
+      case 'y':
+        sp.align_yp = atol (optarg);
+        check_align_option ("-y", sp.align_yp);
+        break;
+      case 'w':
+        sp.align_wp = atol (optarg);
+        check_align_option ("-w", sp.align_wp);
+        break;
+      case 'W':
+        sp.align_wp2 = atol (optarg);
+        check_align_option ("-W", sp.align_wp2);
+        break;
+      case '?':
+        exit(1);
+      }
+    }
+
+  if (optind >= argc)
+    {
+      usage ();
+      exit (1);
+    }
+
+  if (size_num == 0)
+    {
+      fprintf (stderr, "-s <size> must be specified\n");
+      exit (1);
+    }
+
+  gmp_randinit_default (__gmp_rands);
+  __gmp_rands_initialized = 1;
+  gmp_randseed_ui (__gmp_rands, option_seed);
+
+  choice = (struct choice_t *) (*__gmp_allocate_func)
+    ((argc - optind) * sizeof(choice[0]));
+  for ( ; optind < argc; optind++)
+    {
+      struct choice_t  c;
+      routine_find (&c, argv[optind]);
+      choice[num_choices] = c;
+      num_choices++;
+    }
+
+  if ((option_cmp == CMP_RATIO || option_cmp == CMP_DIFFERENCE) &&
+      num_choices < 2)
+    {
+      fprintf (stderr, "WARNING, -d or -r does nothing when only one routine requested\n");
+    }
+
+  speed_time_init ();
+  if (option_unit == UNIT_CYCLES || option_unit == UNIT_CYCLESPERLIMB)
+    speed_cycletime_need_cycles ();
+  else
+    speed_cycletime_need_seconds ();
+
+  if (option_gnuplot)
+    {
+      run_gnuplot (argc, argv);
+    }
+  else
+    {
+      if (option_unit == UNIT_SECONDS)
+        printf ("overhead %.9f secs", speed_measure (speed_noop, NULL));
+      else
+        printf ("overhead %.2f cycles",
+                speed_measure (speed_noop, NULL) / speed_cycletime);
+      printf (", precision %d units of %.2e secs",
+              speed_precision, speed_unittime);
+
+      if (speed_cycletime == 1.0 || speed_cycletime == 0.0)
+        printf (", CPU freq unknown\n");
+      else
+        printf (", CPU freq %.2f MHz\n", 1e-6/speed_cycletime);
+
+      printf ("       ");
+      for (i = 0; i < num_choices; i++)
+        printf (" %*s", COLUMN_WIDTH, choice[i].name);
+      printf ("\n");
+
+      run_all (stdout);
+    }
+
+  if (option_resource_usage)
+    {
+#if HAVE_GETRUSAGE
+      {
+        /* This doesn't give data sizes on linux 2.0.x, only utime. */
+        struct rusage  r;
+        if (getrusage (RUSAGE_SELF, &r) != 0)
+          perror ("getrusage");
+        else
+          printf ("getrusage(): utime %ld.%06ld data %ld stack %ld maxresident %ld\n",
+                  r.ru_utime.tv_sec, r.ru_utime.tv_usec,
+                  r.ru_idrss, r.ru_isrss, r.ru_ixrss);
+      }
+#else
+      printf ("getrusage() not available\n");
+#endif
+
+      /* Linux kernel. */
+      {
+        char  buf[128];
+        sprintf (buf, "/proc/%d/status", getpid());
+        if (access (buf, R_OK) == 0)
+          {
+            sprintf (buf, "cat /proc/%d/status", getpid());
+            system (buf);
+          }
+
+      }
+    }
+
+  return 0;
+}
diff --git a/third_party/gmp/tune/speed.h b/third_party/gmp/tune/speed.h
new file mode 100644
index 0000000..f23bacb
--- /dev/null
+++ b/third_party/gmp/tune/speed.h
@@ -0,0 +1,3800 @@
+/* Header for speed and threshold things.
+
+Copyright 1999-2003, 2005, 2006, 2008-2017, 2019 Free Software
+Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#ifndef __SPEED_H__
+#define __SPEED_H__
+
+
+/* Pad ptr,oldsize with zero limbs (at the most significant end) to make it
+   newsize long. */
+#define MPN_ZERO_EXTEND(ptr, oldsize, newsize)		\
+  do {							\
+    ASSERT ((newsize) >= (oldsize));			\
+    MPN_ZERO ((ptr)+(oldsize), (newsize)-(oldsize));	\
+  } while (0)
+
+/* A mask of the least significant n bits.  Note 1<<32 doesn't give zero on
+   x86 family CPUs, hence the separate case for GMP_LIMB_BITS. */
+#define MP_LIMB_T_LOWBITMASK(n)	\
+  ((n) == GMP_LIMB_BITS ? MP_LIMB_T_MAX : ((mp_limb_t) 1 << (n)) - 1)
+
+
+/* align must be a power of 2 here, usually CACHE_LINE_SIZE is a good choice */
+
+#define TMP_ALLOC_ALIGNED(bytes, align)	\
+  align_pointer (TMP_ALLOC ((bytes) + (align)-1), (align))
+#define TMP_ALLOC_LIMBS_ALIGNED(limbs, align)	\
+  ((mp_ptr) TMP_ALLOC_ALIGNED ((limbs)*sizeof(mp_limb_t), align))
+
+/* CACHE_LINE_SIZE is our default alignment for speed operands, and the
+   limit on what s->align_xp etc and then request for off-alignment.  Maybe
+   this should be an option of some sort, but in any case here are some line
+   sizes,
+
+       bytes
+	 32   pentium
+	 64   athlon
+	 64   itanium-2 L1
+	128   itanium-2 L2
+*/
+#define CACHE_LINE_SIZE   64 /* bytes */
+
+#define SPEED_TMP_ALLOC_ADJUST_MASK  (CACHE_LINE_SIZE/GMP_LIMB_BYTES - 1)
+
+/* Set ptr to a TMP_ALLOC block of the given limbs, with the given limb
+   alignment.  */
+#define SPEED_TMP_ALLOC_LIMBS(ptr, limbs, align)			\
+  do {									\
+    mp_ptr     __ptr;							\
+    mp_size_t  __ptr_align, __ptr_add;					\
+									\
+    ASSERT ((CACHE_LINE_SIZE % GMP_LIMB_BYTES) == 0);		\
+    __ptr = TMP_ALLOC_LIMBS ((limbs) + SPEED_TMP_ALLOC_ADJUST_MASK);	\
+    __ptr_align = (__ptr - (mp_ptr) NULL);				\
+    __ptr_add = ((align) - __ptr_align) & SPEED_TMP_ALLOC_ADJUST_MASK;	\
+    (ptr) = __ptr + __ptr_add;						\
+  } while (0)
+
+
+/* This is the size for s->xp_block and s->yp_block, used in certain
+   routines that want to run across many different data values and use
+   s->size for a different purpose, eg. SPEED_ROUTINE_MPN_GCD_1.
+
+   512 means 2kbytes of data for each of xp_block and yp_block, making 4k
+   total, which should fit easily in any L1 data cache. */
+
+#define SPEED_BLOCK_SIZE   512 /* limbs */
+
+
+extern double  speed_unittime;
+extern double  speed_cycletime;
+extern int     speed_precision;
+extern char    speed_time_string[];
+void speed_time_init (void);
+void speed_cycletime_fail (const char *str);
+void speed_cycletime_init (void);
+void speed_cycletime_need_cycles (void);
+void speed_cycletime_need_seconds (void);
+void speed_starttime (void);
+double speed_endtime (void);
+
+
+struct speed_params {
+  unsigned   reps;	/* how many times to run the routine */
+  mp_ptr     xp;	/* first argument */
+  mp_ptr     yp;	/* second argument */
+  mp_size_t  size;	/* size of both arguments */
+  mp_limb_t  r;		/* user supplied parameter */
+  mp_size_t  align_xp;	/* alignment of xp */
+  mp_size_t  align_yp;	/* alignment of yp */
+  mp_size_t  align_wp;	/* intended alignment of wp */
+  mp_size_t  align_wp2; /* intended alignment of wp2 */
+  mp_ptr     xp_block;	/* first special SPEED_BLOCK_SIZE block */
+  mp_ptr     yp_block;	/* second special SPEED_BLOCK_SIZE block */
+
+  double     time_divisor; /* optionally set by the speed routine */
+
+  /* used by the cache priming things */
+  int	     cache;
+  unsigned   src_num, dst_num;
+  struct {
+    mp_ptr    ptr;
+    mp_size_t size;
+  } src[5], dst[4];
+};
+
+typedef double (*speed_function_t) (struct speed_params *);
+
+double speed_measure (speed_function_t fun, struct speed_params *);
+
+/* Prototypes for speed measuring routines */
+
+double speed_back_to_back (struct speed_params *);
+double speed_count_leading_zeros (struct speed_params *);
+double speed_count_trailing_zeros (struct speed_params *);
+double speed_find_a (struct speed_params *);
+double speed_gmp_allocate_free (struct speed_params *);
+double speed_gmp_allocate_reallocate_free (struct speed_params *);
+double speed_invert_limb (struct speed_params *);
+double speed_malloc_free (struct speed_params *);
+double speed_malloc_realloc_free (struct speed_params *);
+double speed_memcpy (struct speed_params *);
+double speed_binvert_limb (struct speed_params *);
+double speed_binvert_limb_mul1 (struct speed_params *);
+double speed_binvert_limb_loop (struct speed_params *);
+double speed_binvert_limb_cond (struct speed_params *);
+double speed_binvert_limb_arith (struct speed_params *);
+
+double speed_mpf_init_clear (struct speed_params *);
+
+double speed_mpn_add_n (struct speed_params *);
+double speed_mpn_add_1 (struct speed_params *);
+double speed_mpn_add_1_inplace (struct speed_params *);
+double speed_mpn_add_err1_n (struct speed_params *);
+double speed_mpn_add_err2_n (struct speed_params *);
+double speed_mpn_add_err3_n (struct speed_params *);
+double speed_mpn_addlsh_n (struct speed_params *);
+double speed_mpn_addlsh1_n (struct speed_params *);
+double speed_mpn_addlsh2_n (struct speed_params *);
+double speed_mpn_addlsh_n_ip1 (struct speed_params *);
+double speed_mpn_addlsh1_n_ip1 (struct speed_params *);
+double speed_mpn_addlsh2_n_ip1 (struct speed_params *);
+double speed_mpn_addlsh_n_ip2 (struct speed_params *);
+double speed_mpn_addlsh1_n_ip2 (struct speed_params *);
+double speed_mpn_addlsh2_n_ip2 (struct speed_params *);
+double speed_mpn_add_n_sub_n (struct speed_params *);
+double speed_mpn_and_n (struct speed_params *);
+double speed_mpn_andn_n (struct speed_params *);
+double speed_mpn_addmul_1 (struct speed_params *);
+double speed_mpn_addmul_2 (struct speed_params *);
+double speed_mpn_addmul_3 (struct speed_params *);
+double speed_mpn_addmul_4 (struct speed_params *);
+double speed_mpn_addmul_5 (struct speed_params *);
+double speed_mpn_addmul_6 (struct speed_params *);
+double speed_mpn_addmul_7 (struct speed_params *);
+double speed_mpn_addmul_8 (struct speed_params *);
+double speed_mpn_cnd_add_n (struct speed_params *);
+double speed_mpn_cnd_sub_n (struct speed_params *);
+double speed_mpn_com (struct speed_params *);
+double speed_mpn_neg (struct speed_params *);
+double speed_mpn_copyd (struct speed_params *);
+double speed_mpn_copyi (struct speed_params *);
+double speed_MPN_COPY (struct speed_params *);
+double speed_MPN_COPY_DECR (struct speed_params *);
+double speed_MPN_COPY_INCR (struct speed_params *);
+double speed_mpn_sec_tabselect (struct speed_params *);
+double speed_mpn_divexact_1 (struct speed_params *);
+double speed_mpn_divexact_by3 (struct speed_params *);
+double speed_mpn_bdiv_q_1 (struct speed_params *);
+double speed_mpn_pi1_bdiv_q_1 (struct speed_params *);
+double speed_mpn_bdiv_dbm1c (struct speed_params *);
+double speed_mpn_divrem_1 (struct speed_params *);
+double speed_mpn_divrem_1f (struct speed_params *);
+double speed_mpn_divrem_1c (struct speed_params *);
+double speed_mpn_divrem_1cf (struct speed_params *);
+double speed_mpn_divrem_1_div (struct speed_params *);
+double speed_mpn_divrem_1f_div (struct speed_params *);
+double speed_mpn_divrem_1_inv (struct speed_params *);
+double speed_mpn_divrem_1f_inv (struct speed_params *);
+double speed_mpn_divrem_2 (struct speed_params *);
+double speed_mpn_divrem_2_div (struct speed_params *);
+double speed_mpn_divrem_2_inv (struct speed_params *);
+double speed_mpn_div_qr_1n_pi1 (struct speed_params *);
+double speed_mpn_div_qr_1n_pi1_1 (struct speed_params *);
+double speed_mpn_div_qr_1n_pi1_2 (struct speed_params *);
+double speed_mpn_div_qr_1 (struct speed_params *);
+double speed_mpn_div_qr_2n (struct speed_params *);
+double speed_mpn_div_qr_2u (struct speed_params *);
+double speed_mpn_fib2_ui (struct speed_params *);
+double speed_mpn_matrix22_mul (struct speed_params *);
+double speed_mpn_hgcd2 (struct speed_params *);
+double speed_mpn_hgcd2_1 (struct speed_params *);
+double speed_mpn_hgcd2_2 (struct speed_params *);
+double speed_mpn_hgcd2_3 (struct speed_params *);
+double speed_mpn_hgcd2_4 (struct speed_params *);
+double speed_mpn_hgcd2_5 (struct speed_params *);
+double speed_mpn_hgcd (struct speed_params *);
+double speed_mpn_hgcd_lehmer (struct speed_params *);
+double speed_mpn_hgcd_appr (struct speed_params *);
+double speed_mpn_hgcd_appr_lehmer (struct speed_params *);
+double speed_mpn_hgcd_reduce (struct speed_params *);
+double speed_mpn_hgcd_reduce_1 (struct speed_params *);
+double speed_mpn_hgcd_reduce_2 (struct speed_params *);
+double speed_mpn_gcd (struct speed_params *);
+double speed_mpn_gcd_1 (struct speed_params *);
+double speed_mpn_gcd_11 (struct speed_params *);
+double speed_mpn_gcd_1N (struct speed_params *);
+double speed_mpn_gcd_22 (struct speed_params *);
+double speed_mpn_gcdext (struct speed_params *);
+double speed_mpn_gcdext_double (struct speed_params *);
+double speed_mpn_gcdext_one_double (struct speed_params *);
+double speed_mpn_gcdext_one_single (struct speed_params *);
+double speed_mpn_gcdext_single (struct speed_params *);
+double speed_mpn_get_str (struct speed_params *);
+double speed_mpn_hamdist (struct speed_params *);
+double speed_mpn_ior_n (struct speed_params *);
+double speed_mpn_iorn_n (struct speed_params *);
+double speed_mpn_jacobi_base (struct speed_params *);
+double speed_mpn_jacobi_base_1 (struct speed_params *);
+double speed_mpn_jacobi_base_2 (struct speed_params *);
+double speed_mpn_jacobi_base_3 (struct speed_params *);
+double speed_mpn_jacobi_base_4 (struct speed_params *);
+double speed_mpn_lshift (struct speed_params *);
+double speed_mpn_lshiftc (struct speed_params *);
+double speed_mpn_mod_1 (struct speed_params *);
+double speed_mpn_mod_1c (struct speed_params *);
+double speed_mpn_mod_1_div (struct speed_params *);
+double speed_mpn_mod_1_inv (struct speed_params *);
+double speed_mpn_mod_1_1 (struct speed_params *);
+double speed_mpn_mod_1_1_1 (struct speed_params *);
+double speed_mpn_mod_1_1_2 (struct speed_params *);
+double speed_mpn_mod_1_2 (struct speed_params *);
+double speed_mpn_mod_1_3 (struct speed_params *);
+double speed_mpn_mod_1_4 (struct speed_params *);
+double speed_mpn_mod_34lsub1 (struct speed_params *);
+double speed_mpn_modexact_1_odd (struct speed_params *);
+double speed_mpn_modexact_1c_odd (struct speed_params *);
+double speed_mpn_mul_1 (struct speed_params *);
+double speed_mpn_mul_1_inplace (struct speed_params *);
+double speed_mpn_mul_2 (struct speed_params *);
+double speed_mpn_mul_3 (struct speed_params *);
+double speed_mpn_mul_4 (struct speed_params *);
+double speed_mpn_mul_5 (struct speed_params *);
+double speed_mpn_mul_6 (struct speed_params *);
+double speed_mpn_mul (struct speed_params *);
+double speed_mpn_mul_basecase (struct speed_params *);
+double speed_mpn_mulmid (struct speed_params *);
+double speed_mpn_mulmid_basecase (struct speed_params *);
+double speed_mpn_mul_fft (struct speed_params *);
+double speed_mpn_mul_fft_sqr (struct speed_params *);
+double speed_mpn_fft_mul (struct speed_params *);
+double speed_mpn_fft_sqr (struct speed_params *);
+#if WANT_OLD_FFT_FULL
+double speed_mpn_mul_fft_full (struct speed_params *);
+double speed_mpn_mul_fft_full_sqr (struct speed_params *);
+#endif
+double speed_mpn_nussbaumer_mul (struct speed_params *);
+double speed_mpn_nussbaumer_mul_sqr (struct speed_params *);
+double speed_mpn_mul_n (struct speed_params *);
+double speed_mpn_mul_n_sqr (struct speed_params *);
+double speed_mpn_mulmid_n (struct speed_params *);
+double speed_mpn_sqrlo (struct speed_params *);
+double speed_mpn_sqrlo_basecase (struct speed_params *);
+double speed_mpn_mullo_n (struct speed_params *);
+double speed_mpn_mullo_basecase (struct speed_params *);
+double speed_mpn_nand_n (struct speed_params *);
+double speed_mpn_nior_n (struct speed_params *);
+double speed_mpn_popcount (struct speed_params *);
+double speed_mpn_preinv_divrem_1 (struct speed_params *);
+double speed_mpn_preinv_divrem_1f (struct speed_params *);
+double speed_mpn_preinv_mod_1 (struct speed_params *);
+double speed_mpn_sbpi1_div_qr (struct speed_params *);
+double speed_mpn_dcpi1_div_qr (struct speed_params *);
+double speed_mpn_sbpi1_divappr_q (struct speed_params *);
+double speed_mpn_dcpi1_divappr_q (struct speed_params *);
+double speed_mpn_mu_div_qr (struct speed_params *);
+double speed_mpn_mu_divappr_q (struct speed_params *);
+double speed_mpn_mupi_div_qr (struct speed_params *);
+double speed_mpn_mu_div_q (struct speed_params *);
+double speed_mpn_sbpi1_bdiv_qr (struct speed_params *);
+double speed_mpn_dcpi1_bdiv_qr (struct speed_params *);
+double speed_mpn_sbpi1_bdiv_q (struct speed_params *);
+double speed_mpn_dcpi1_bdiv_q (struct speed_params *);
+double speed_mpn_sbpi1_bdiv_r (struct speed_params *);
+double speed_mpn_mu_bdiv_q (struct speed_params *);
+double speed_mpn_mu_bdiv_qr (struct speed_params *);
+double speed_mpn_broot (struct speed_params *);
+double speed_mpn_broot_invm1 (struct speed_params *);
+double speed_mpn_brootinv (struct speed_params *);
+double speed_mpn_invert (struct speed_params *);
+double speed_mpn_invertappr (struct speed_params *);
+double speed_mpn_ni_invertappr (struct speed_params *);
+double speed_mpn_sec_invert (struct speed_params *s);
+double speed_mpn_binvert (struct speed_params *);
+double speed_mpn_redc_1 (struct speed_params *);
+double speed_mpn_redc_2 (struct speed_params *);
+double speed_mpn_redc_n (struct speed_params *);
+double speed_mpn_rsblsh_n (struct speed_params *);
+double speed_mpn_rsblsh1_n (struct speed_params *);
+double speed_mpn_rsblsh2_n (struct speed_params *);
+double speed_mpn_rsh1add_n (struct speed_params *);
+double speed_mpn_rsh1sub_n (struct speed_params *);
+double speed_mpn_rshift (struct speed_params *);
+double speed_mpn_sb_divrem_m3 (struct speed_params *);
+double speed_mpn_sb_divrem_m3_div (struct speed_params *);
+double speed_mpn_sb_divrem_m3_inv (struct speed_params *);
+double speed_mpn_set_str (struct speed_params *);
+double speed_mpn_bc_set_str (struct speed_params *);
+double speed_mpn_dc_set_str (struct speed_params *);
+double speed_mpn_set_str_pre (struct speed_params *);
+double speed_mpn_sqr_basecase (struct speed_params *);
+double speed_mpn_sqr_diag_addlsh1 (struct speed_params *);
+double speed_mpn_sqr_diagonal (struct speed_params *);
+double speed_mpn_sqr (struct speed_params *);
+double speed_mpn_sqrtrem (struct speed_params *);
+double speed_mpn_rootrem (struct speed_params *);
+double speed_mpn_sqrt (struct speed_params *);
+double speed_mpn_root (struct speed_params *);
+double speed_mpn_perfect_power_p (struct speed_params *);
+double speed_mpn_perfect_square_p (struct speed_params *);
+double speed_mpn_sub_n (struct speed_params *);
+double speed_mpn_sub_1 (struct speed_params *);
+double speed_mpn_sub_1_inplace (struct speed_params *);
+double speed_mpn_sub_err1_n (struct speed_params *);
+double speed_mpn_sub_err2_n (struct speed_params *);
+double speed_mpn_sub_err3_n (struct speed_params *);
+double speed_mpn_sublsh_n (struct speed_params *);
+double speed_mpn_sublsh1_n (struct speed_params *);
+double speed_mpn_sublsh2_n (struct speed_params *);
+double speed_mpn_sublsh_n_ip1 (struct speed_params *);
+double speed_mpn_sublsh1_n_ip1 (struct speed_params *);
+double speed_mpn_sublsh2_n_ip1 (struct speed_params *);
+double speed_mpn_submul_1 (struct speed_params *);
+double speed_mpn_toom2_sqr (struct speed_params *);
+double speed_mpn_toom3_sqr (struct speed_params *);
+double speed_mpn_toom4_sqr (struct speed_params *);
+double speed_mpn_toom6_sqr (struct speed_params *);
+double speed_mpn_toom8_sqr (struct speed_params *);
+double speed_mpn_toom22_mul (struct speed_params *);
+double speed_mpn_toom33_mul (struct speed_params *);
+double speed_mpn_toom44_mul (struct speed_params *);
+double speed_mpn_toom6h_mul (struct speed_params *);
+double speed_mpn_toom8h_mul (struct speed_params *);
+double speed_mpn_toom32_mul (struct speed_params *);
+double speed_mpn_toom42_mul (struct speed_params *);
+double speed_mpn_toom43_mul (struct speed_params *);
+double speed_mpn_toom63_mul (struct speed_params *);
+double speed_mpn_toom32_for_toom43_mul (struct speed_params *);
+double speed_mpn_toom43_for_toom32_mul (struct speed_params *);
+double speed_mpn_toom32_for_toom53_mul (struct speed_params *);
+double speed_mpn_toom53_for_toom32_mul (struct speed_params *);
+double speed_mpn_toom42_for_toom53_mul (struct speed_params *);
+double speed_mpn_toom53_for_toom42_mul (struct speed_params *);
+double speed_mpn_toom43_for_toom54_mul (struct speed_params *);
+double speed_mpn_toom54_for_toom43_mul (struct speed_params *);
+double speed_mpn_toom42_mulmid (struct speed_params *);
+double speed_mpn_mulmod_bnm1 (struct speed_params *);
+double speed_mpn_bc_mulmod_bnm1 (struct speed_params *);
+double speed_mpn_mulmod_bnm1_rounded (struct speed_params *);
+double speed_mpn_sqrmod_bnm1 (struct speed_params *);
+double speed_mpn_udiv_qrnnd (struct speed_params *);
+double speed_mpn_udiv_qrnnd_r (struct speed_params *);
+double speed_mpn_umul_ppmm (struct speed_params *);
+double speed_mpn_umul_ppmm_r (struct speed_params *);
+double speed_mpn_xnor_n (struct speed_params *);
+double speed_mpn_xor_n (struct speed_params *);
+double speed_MPN_ZERO (struct speed_params *);
+
+double speed_mpq_init_clear (struct speed_params *);
+
+double speed_mpz_add (struct speed_params *);
+double speed_mpz_invert (struct speed_params *);
+double speed_mpz_bin_uiui (struct speed_params *);
+double speed_mpz_bin_ui (struct speed_params *);
+double speed_mpz_fac_ui (struct speed_params *);
+double speed_mpz_2fac_ui (struct speed_params *);
+double speed_mpz_mfac_uiui (struct speed_params *);
+double speed_mpz_primorial_ui (struct speed_params *);
+double speed_mpz_fib_ui (struct speed_params *);
+double speed_mpz_fib2_ui (struct speed_params *);
+double speed_mpz_init_clear (struct speed_params *);
+double speed_mpz_init_realloc_clear (struct speed_params *);
+double speed_mpz_nextprime (struct speed_params *);
+double speed_mpz_jacobi (struct speed_params *);
+double speed_mpz_lucnum_ui (struct speed_params *);
+double speed_mpz_lucnum2_ui (struct speed_params *);
+double speed_mpz_mod (struct speed_params *);
+double speed_mpz_powm (struct speed_params *);
+double speed_mpz_powm_mod (struct speed_params *);
+double speed_mpz_powm_redc (struct speed_params *);
+double speed_mpz_powm_sec (struct speed_params *);
+double speed_mpz_powm_ui (struct speed_params *);
+double speed_mpz_urandomb (struct speed_params *);
+
+double speed_gmp_randseed (struct speed_params *);
+double speed_gmp_randseed_ui (struct speed_params *);
+
+double speed_noop (struct speed_params *);
+double speed_noop_wxs (struct speed_params *);
+double speed_noop_wxys (struct speed_params *);
+
+double speed_operator_div (struct speed_params *);
+double speed_operator_mod (struct speed_params *);
+
+double speed_udiv_qrnnd (struct speed_params *);
+double speed_udiv_qrnnd_preinv1 (struct speed_params *);
+double speed_udiv_qrnnd_preinv2 (struct speed_params *);
+double speed_udiv_qrnnd_preinv3 (struct speed_params *);
+double speed_udiv_qrnnd_c (struct speed_params *);
+double speed_umul_ppmm (struct speed_params *);
+
+/* Prototypes for other routines */
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+/* low 32-bits in p[0], high 32-bits in p[1] */
+void speed_cyclecounter (unsigned p[2]);
+
+#if defined (__cplusplus)
+}
+#endif
+
+void mftb_function (unsigned p[2]);
+
+double speed_cyclecounter_diff (const unsigned [2], const unsigned [2]);
+int gettimeofday_microseconds_p (void);
+int getrusage_microseconds_p (void);
+int cycles_works_p (void);
+long clk_tck (void);
+double freq_measure (const char *, double (*)(void));
+
+int double_cmp_ptr (const double *, const double *);
+void pentium_wbinvd (void);
+typedef int (*qsort_function_t) (const void *, const void *);
+
+void noop (void);
+void noop_1 (mp_limb_t);
+void noop_wxs (mp_ptr, mp_srcptr, mp_size_t);
+void noop_wxys (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+void mpn_cache_fill (mp_srcptr, mp_size_t);
+void mpn_cache_fill_dummy (mp_limb_t);
+void speed_cache_fill (struct speed_params *);
+void speed_operand_src (struct speed_params *, mp_ptr, mp_size_t);
+void speed_operand_dst (struct speed_params *, mp_ptr, mp_size_t);
+
+extern int  speed_option_addrs;
+extern int  speed_option_verbose;
+extern int  speed_option_cycles_broken;
+void speed_option_set (const char *);
+
+mp_limb_t mpn_div_qr_1n_pi1_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t, mp_limb_t);
+mp_limb_t mpn_div_qr_1n_pi1_2 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t, mp_limb_t, mp_limb_t);
+
+mp_limb_t mpn_divrem_1_div (mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t mpn_divrem_1_inv (mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t mpn_divrem_2_div (mp_ptr, mp_size_t, mp_ptr, mp_size_t, mp_srcptr);
+mp_limb_t mpn_divrem_2_inv (mp_ptr, mp_size_t, mp_ptr, mp_size_t, mp_srcptr);
+
+int mpn_jacobi_base_1 (mp_limb_t, mp_limb_t, int);
+int mpn_jacobi_base_2 (mp_limb_t, mp_limb_t, int);
+int mpn_jacobi_base_3 (mp_limb_t, mp_limb_t, int);
+int mpn_jacobi_base_4 (mp_limb_t, mp_limb_t, int);
+
+int mpn_hgcd2_1 (mp_limb_t, mp_limb_t, mp_limb_t, mp_limb_t, struct hgcd_matrix1*);
+int mpn_hgcd2_2 (mp_limb_t, mp_limb_t, mp_limb_t, mp_limb_t, struct hgcd_matrix1*);
+int mpn_hgcd2_3 (mp_limb_t, mp_limb_t, mp_limb_t, mp_limb_t, struct hgcd_matrix1*);
+int mpn_hgcd2_4 (mp_limb_t, mp_limb_t, mp_limb_t, mp_limb_t, struct hgcd_matrix1*);
+int mpn_hgcd2_5 (mp_limb_t, mp_limb_t, mp_limb_t, mp_limb_t, struct hgcd_matrix1*);
+
+mp_limb_t mpn_mod_1_div (mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t mpn_mod_1_inv (mp_srcptr, mp_size_t, mp_limb_t);
+
+mp_limb_t mpn_mod_1_1p_1 (mp_srcptr, mp_size_t, mp_limb_t, const mp_limb_t [4]);
+mp_limb_t mpn_mod_1_1p_2 (mp_srcptr, mp_size_t, mp_limb_t, const mp_limb_t [4]);
+
+void mpn_mod_1_1p_cps_1 (mp_limb_t [4], mp_limb_t);
+void mpn_mod_1_1p_cps_2 (mp_limb_t [4], mp_limb_t);
+
+mp_size_t mpn_gcdext_one_double (mp_ptr, mp_ptr, mp_size_t *, mp_ptr, mp_size_t, mp_ptr, mp_size_t);
+mp_size_t mpn_gcdext_one_single (mp_ptr, mp_ptr, mp_size_t *, mp_ptr, mp_size_t, mp_ptr, mp_size_t);
+mp_size_t mpn_gcdext_single (mp_ptr, mp_ptr, mp_size_t *, mp_ptr, mp_size_t, mp_ptr, mp_size_t);
+mp_size_t mpn_gcdext_double (mp_ptr, mp_ptr, mp_size_t *, mp_ptr, mp_size_t, mp_ptr, mp_size_t);
+mp_size_t mpn_hgcd_lehmer (mp_ptr, mp_ptr, mp_size_t, struct hgcd_matrix *, mp_ptr);
+mp_size_t mpn_hgcd_lehmer_itch (mp_size_t);
+
+mp_size_t mpn_hgcd_appr_lehmer (mp_ptr, mp_ptr, mp_size_t, struct hgcd_matrix *, mp_ptr);
+mp_size_t mpn_hgcd_appr_lehmer_itch (mp_size_t);
+
+mp_size_t mpn_hgcd_reduce_1 (struct hgcd_matrix *, mp_ptr, mp_ptr, mp_size_t, mp_size_t, mp_ptr);
+mp_size_t mpn_hgcd_reduce_1_itch (mp_size_t, mp_size_t);
+
+mp_size_t mpn_hgcd_reduce_2 (struct hgcd_matrix *, mp_ptr, mp_ptr, mp_size_t, mp_size_t, mp_ptr);
+mp_size_t mpn_hgcd_reduce_2_itch (mp_size_t, mp_size_t);
+
+mp_limb_t mpn_sb_divrem_mn_div (mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t);
+mp_limb_t mpn_sb_divrem_mn_inv (mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t);
+
+mp_size_t mpn_set_str_basecase (mp_ptr, const unsigned char *, size_t, int);
+void mpn_pre_set_str (mp_ptr, unsigned char *, size_t, powers_t *, mp_ptr);
+
+void mpz_powm_mod (mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr);
+void mpz_powm_redc (mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr);
+
+int speed_routine_count_zeros_setup (struct speed_params *, mp_ptr, int, int);
+
+
+/* "get" is called repeatedly until it ticks over, just in case on a fast
+   processor it takes less than a microsecond, though this is probably
+   unlikely if it's a system call.
+
+   speed_cyclecounter is called on the same side of the "get" for the start
+   and end measurements.  It doesn't matter how long it takes from the "get"
+   sample to the cycles sample, since that period will cancel out in the
+   difference calculation (assuming it's the same each time).
+
+   Letting the test run for more than a process time slice is probably only
+   going to reduce accuracy, especially for getrusage when the cycle counter
+   is real time, or for gettimeofday if the cycle counter is in fact process
+   time.  Use CLK_TCK/2 as a reasonable stop.
+
+   It'd be desirable to be quite accurate here.  The default speed_precision
+   for a cycle counter is 10000 cycles, so to mix that with getrusage or
+   gettimeofday the frequency should be at least that accurate.  But running
+   measurements for 10000 microseconds (or more) is too long.  Be satisfied
+   with just a half clock tick (5000 microseconds usually).  */
+
+#define FREQ_MEASURE_ONE(name, type, get, getc, sec, usec)		\
+  do {									\
+    type      st1, st, et1, et;						\
+    unsigned  sc[2], ec[2];						\
+    long      dt, half_tick;						\
+    double    dc, cyc;							\
+									\
+    half_tick = (1000000L / clk_tck()) / 2;				\
+									\
+    get (st1);								\
+    do {								\
+      get (st);								\
+    } while (usec(st) == usec(st1) && sec(st) == sec(st1));		\
+									\
+    getc (sc);								\
+									\
+    for (;;)								\
+      {									\
+	get (et1);							\
+	do {								\
+	  get (et);							\
+	} while (usec(et) == usec(et1) && sec(et) == sec(et1));		\
+									\
+	getc (ec);							\
+									\
+	dc = speed_cyclecounter_diff (ec, sc);				\
+									\
+	/* allow secs to cancel before multiplying */			\
+	dt = sec(et) - sec(st);						\
+	dt = dt * 1000000L + (usec(et) - usec(st));			\
+									\
+	if (dt >= half_tick)						\
+	  break;							\
+      }									\
+									\
+    cyc = dt * 1e-6 / dc;						\
+									\
+    if (speed_option_verbose >= 2)					\
+      printf ("freq_measure_%s_one() dc=%.6g dt=%ld cyc=%.6g\n",	\
+	      name, dc, dt, cyc);					\
+									\
+    return dt * 1e-6 / dc;						\
+									\
+  } while (0)
+
+
+
+
+/* The measuring routines use these big macros to save duplication for
+   similar forms.  They also get used for some automatically generated
+   measuring of new implementations of functions.
+
+   Having something like SPEED_ROUTINE_BINARY_N as a subroutine accepting a
+   function pointer is considered undesirable since it's not the way a
+   normal application will be calling, and some processors might do
+   different things with an indirect call, like not branch predicting, or
+   doing a full pipe flush.  At least some of the "functions" measured are
+   actually macros too.
+
+   The net effect is to bloat the object code, possibly in a big way, but
+   only what's being measured is being run, so that doesn't matter.
+
+   The loop forms don't try to cope with __GMP_ATTRIBUTE_PURE or
+   ATTRIBUTE_CONST on the called functions.  Adding a cast to a non-pure
+   function pointer doesn't work in gcc 3.2.  Using an actual non-pure
+   function pointer variable works, but stands a real risk of a
+   non-optimizing compiler generating unnecessary overheads in the call.
+   Currently the best idea is not to use those attributes for a timing
+   program build.  __GMP_NO_ATTRIBUTE_CONST_PURE will tell gmp.h and
+   gmp-impl.h to omit them from routines there.  */
+
+#define SPEED_RESTRICT_COND(cond)   if (!(cond)) return -1.0;
+
+/* For mpn_copy or similar. */
+#define SPEED_ROUTINE_MPN_COPY_CALL(call)				\
+  {									\
+    mp_ptr    wp;							\
+    unsigned  i;							\
+    double    t;							\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= 0);					\
+									\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (wp, s->size, s->align_wp);			\
+									\
+    speed_operand_src (s, s->xp, s->size);				\
+    speed_operand_dst (s, wp, s->size);					\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      call;								\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+#define SPEED_ROUTINE_MPN_COPY(function)				\
+  SPEED_ROUTINE_MPN_COPY_CALL (function (wp, s->xp, s->size))
+
+#define SPEED_ROUTINE_MPN_TABSELECT(function)				\
+  {									\
+    mp_ptr    xp, wp;							\
+    unsigned  i;							\
+    double    t;							\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= 0);					\
+									\
+    if (s->r == 0)							\
+      s->r = s->size;	/* default to a quadratic shape */		\
+									\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (xp, s->size * s->r, s->align_xp);		\
+    SPEED_TMP_ALLOC_LIMBS (wp, s->size, s->align_wp);			\
+									\
+    speed_operand_src (s, xp, s->size * s->r);				\
+    speed_operand_dst (s, wp, s->size);					\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      function (wp, xp, s->size, s->r, (s->r) / 2);			\
+    while (--i != 0);							\
+    t = speed_endtime () / s->r;					\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+
+
+#define SPEED_ROUTINE_MPN_COPYC(function)				\
+  {									\
+    mp_ptr    wp;							\
+    unsigned  i;							\
+    double    t;							\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= 0);					\
+									\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (wp, s->size, s->align_wp);			\
+									\
+    speed_operand_src (s, s->xp, s->size);				\
+    speed_operand_dst (s, wp, s->size);					\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      function (wp, s->xp, s->size, 0);					\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+
+/* s->size is still in limbs, and it's limbs which are copied, but
+   "function" takes a size in bytes not limbs.  */
+#define SPEED_ROUTINE_MPN_COPY_BYTES(function)				\
+  {									\
+    mp_ptr    wp;							\
+    unsigned  i;							\
+    double    t;							\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= 0);					\
+									\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (wp, s->size, s->align_wp);			\
+									\
+    speed_operand_src (s, s->xp, s->size);				\
+    speed_operand_dst (s, wp, s->size);					\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      function (wp, s->xp, s->size * GMP_LIMB_BYTES);		\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+
+
+/* For mpn_add_n, mpn_sub_n, or similar. */
+#define SPEED_ROUTINE_MPN_BINARY_N_CALL(call)				\
+  {									\
+    mp_ptr     wp;							\
+    mp_ptr     xp, yp;							\
+    unsigned   i;							\
+    double     t;							\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= 1);					\
+									\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (wp, s->size, s->align_wp);			\
+									\
+    xp = s->xp;								\
+    yp = s->yp;								\
+									\
+    if (s->r == 0)	;						\
+    else if (s->r == 1) { xp = wp;	    }				\
+    else if (s->r == 2) {	   yp = wp; }				\
+    else if (s->r == 3) { xp = wp; yp = wp; }				\
+    else if (s->r == 4) {     yp = xp;	    }				\
+    else		{						\
+      TMP_FREE;								\
+      return -1.0;							\
+    }									\
+									\
+    /* initialize wp if operand overlap */				\
+    if (xp == wp || yp == wp)						\
+      MPN_COPY (wp, s->xp, s->size);					\
+									\
+    speed_operand_src (s, xp, s->size);					\
+    speed_operand_src (s, yp, s->size);					\
+    speed_operand_dst (s, wp, s->size);					\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      call;								\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+
+
+/* For mpn_aors_errK_n, where 1 <= K <= 3. */
+#define SPEED_ROUTINE_MPN_BINARY_ERR_N_CALL(call, K)			\
+  {									\
+    mp_ptr     wp;							\
+    mp_ptr     xp, yp;							\
+    mp_ptr     zp[K];							\
+    mp_limb_t  ep[2*K];							\
+    unsigned   i;							\
+    double     t;							\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= 1);					\
+									\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (wp, s->size, s->align_wp);			\
+									\
+    /* (don't have a mechanism to specify zp alignments) */		\
+    for (i = 0; i < K; i++)						\
+      SPEED_TMP_ALLOC_LIMBS (zp[i], s->size, 0);			\
+									\
+    xp = s->xp;								\
+    yp = s->yp;								\
+									\
+    if (s->r == 0)	;						\
+    else if (s->r == 1) { xp = wp;	    }				\
+    else if (s->r == 2) {	   yp = wp; }				\
+    else if (s->r == 3) { xp = wp; yp = wp; }				\
+    else if (s->r == 4) {     yp = xp;	    }				\
+    else		{						\
+      TMP_FREE;								\
+      return -1.0;							\
+    }									\
+									\
+    /* initialize wp if operand overlap */				\
+    if (xp == wp || yp == wp)						\
+      MPN_COPY (wp, s->xp, s->size);					\
+									\
+    speed_operand_src (s, xp, s->size);					\
+    speed_operand_src (s, yp, s->size);					\
+    for (i = 0; i < K; i++)						\
+      speed_operand_src (s, zp[i], s->size);				\
+    speed_operand_dst (s, wp, s->size);					\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      call;								\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+
+#define SPEED_ROUTINE_MPN_BINARY_ERR1_N(function)			\
+  SPEED_ROUTINE_MPN_BINARY_ERR_N_CALL ((*function) (wp, xp, yp, ep, zp[0], s->size, 0), 1)
+
+#define SPEED_ROUTINE_MPN_BINARY_ERR2_N(function)			\
+  SPEED_ROUTINE_MPN_BINARY_ERR_N_CALL ((*function) (wp, xp, yp, ep, zp[0], zp[1], s->size, 0), 2)
+
+#define SPEED_ROUTINE_MPN_BINARY_ERR3_N(function)			\
+  SPEED_ROUTINE_MPN_BINARY_ERR_N_CALL ((*function) (wp, xp, yp, ep, zp[0], zp[1], zp[2], s->size, 0), 3)
+
+
+/* For mpn_add_n, mpn_sub_n, or similar. */
+#define SPEED_ROUTINE_MPN_ADDSUB_N_CALL(call)				\
+  {									\
+    mp_ptr     ap, sp;							\
+    mp_ptr     xp, yp;							\
+    unsigned   i;							\
+    double     t;							\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= 1);					\
+									\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (ap, s->size, s->align_wp);			\
+    SPEED_TMP_ALLOC_LIMBS (sp, s->size, s->align_wp);			\
+									\
+    xp = s->xp;								\
+    yp = s->yp;								\
+									\
+    if ((s->r & 1) != 0) { xp = ap; }					\
+    if ((s->r & 2) != 0) { yp = ap; }					\
+    if ((s->r & 4) != 0) { xp = sp; }					\
+    if ((s->r & 8) != 0) { yp = sp; }					\
+    if ((s->r & 3) == 3  ||  (s->r & 12) == 12)				\
+      {									\
+	TMP_FREE;							\
+	return -1.0;							\
+      }									\
+									\
+    /* initialize ap if operand overlap */				\
+    if (xp == ap || yp == ap)						\
+      MPN_COPY (ap, s->xp, s->size);					\
+    /* initialize sp if operand overlap */				\
+    if (xp == sp || yp == sp)						\
+      MPN_COPY (sp, s->xp, s->size);					\
+									\
+    speed_operand_src (s, xp, s->size);					\
+    speed_operand_src (s, yp, s->size);					\
+    speed_operand_dst (s, ap, s->size);					\
+    speed_operand_dst (s, sp, s->size);					\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      call;								\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+
+#define SPEED_ROUTINE_MPN_BINARY_N(function)				\
+   SPEED_ROUTINE_MPN_BINARY_N_CALL ((*function) (wp, xp, yp, s->size))
+
+#define SPEED_ROUTINE_MPN_BINARY_NC(function)				\
+   SPEED_ROUTINE_MPN_BINARY_N_CALL ((*function) (wp, xp, yp, s->size, 0))
+
+
+/* For mpn_lshift, mpn_rshift, mpn_mul_1, with r, or similar. */
+#define SPEED_ROUTINE_MPN_UNARY_1_CALL(call)				\
+  {									\
+    mp_ptr    wp;							\
+    unsigned  i;							\
+    double    t;							\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= 1);					\
+									\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (wp, s->size, s->align_wp);			\
+									\
+    speed_operand_src (s, s->xp, s->size);				\
+    speed_operand_dst (s, wp, s->size);					\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      call;								\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+
+#define SPEED_ROUTINE_MPN_UNARY_1(function)				\
+  SPEED_ROUTINE_MPN_UNARY_1_CALL ((*function) (wp, s->xp, s->size, s->r))
+
+#define SPEED_ROUTINE_MPN_UNARY_1C(function)				\
+  SPEED_ROUTINE_MPN_UNARY_1_CALL ((*function) (wp, s->xp, s->size, s->r, 0))
+
+/* FIXME: wp is uninitialized here, should start it off from xp */
+#define SPEED_ROUTINE_MPN_UNARY_1_INPLACE(function)			\
+  SPEED_ROUTINE_MPN_UNARY_1_CALL ((*function) (wp, wp, s->size, s->r))
+
+#define SPEED_ROUTINE_MPN_DIVEXACT_1(function)				\
+  SPEED_ROUTINE_MPN_UNARY_1_CALL ((*function) (wp, s->xp, s->size, s->r))
+
+#define SPEED_ROUTINE_MPN_BDIV_Q_1(function)				\
+    SPEED_ROUTINE_MPN_UNARY_1_CALL ((*function) (wp, s->xp, s->size, s->r))
+
+#define SPEED_ROUTINE_MPN_PI1_BDIV_Q_1_CALL(call)			\
+  {									\
+    unsigned   shift;							\
+    mp_limb_t  dinv;							\
+									\
+    SPEED_RESTRICT_COND (s->size > 0);					\
+    SPEED_RESTRICT_COND (s->r != 0);					\
+									\
+    count_trailing_zeros (shift, s->r);					\
+    binvert_limb (dinv, s->r >> shift);					\
+									\
+    SPEED_ROUTINE_MPN_UNARY_1_CALL (call);				\
+  }
+#define SPEED_ROUTINE_MPN_PI1_BDIV_Q_1(function)			\
+  SPEED_ROUTINE_MPN_PI1_BDIV_Q_1_CALL					\
+  ((*function) (wp, s->xp, s->size, s->r, dinv, shift))
+
+#define SPEED_ROUTINE_MPN_BDIV_DBM1C(function)				\
+  SPEED_ROUTINE_MPN_UNARY_1_CALL ((*function) (wp, s->xp, s->size, s->r, 0))
+
+#define SPEED_ROUTINE_MPN_DIVREM_1(function)				\
+  SPEED_ROUTINE_MPN_UNARY_1_CALL ((*function) (wp, 0, s->xp, s->size, s->r))
+
+#define SPEED_ROUTINE_MPN_DIVREM_1C(function)				\
+  SPEED_ROUTINE_MPN_UNARY_1_CALL ((*function) (wp, 0, s->xp, s->size, s->r, 0))
+
+#define SPEED_ROUTINE_MPN_DIVREM_1F(function)				\
+  SPEED_ROUTINE_MPN_UNARY_1_CALL ((*function) (wp, s->size, s->xp, 0, s->r))
+
+#define SPEED_ROUTINE_MPN_DIVREM_1CF(function)				\
+  SPEED_ROUTINE_MPN_UNARY_1_CALL ((*function) (wp, s->size, s->xp, 0, s->r, 0))
+
+
+#define SPEED_ROUTINE_MPN_PREINV_DIVREM_1_CALL(call)			\
+  {									\
+    unsigned   shift;							\
+    mp_limb_t  dinv;							\
+									\
+    SPEED_RESTRICT_COND (s->size >= 0);					\
+    SPEED_RESTRICT_COND (s->r != 0);					\
+									\
+    count_leading_zeros (shift, s->r);					\
+    invert_limb (dinv, s->r << shift);					\
+									\
+    SPEED_ROUTINE_MPN_UNARY_1_CALL (call);				\
+  }									\
+
+#define SPEED_ROUTINE_MPN_PREINV_DIVREM_1(function)			\
+  SPEED_ROUTINE_MPN_PREINV_DIVREM_1_CALL				\
+  ((*function) (wp, 0, s->xp, s->size, s->r, dinv, shift))
+
+/* s->size limbs worth of fraction part */
+#define SPEED_ROUTINE_MPN_PREINV_DIVREM_1F(function)			\
+  SPEED_ROUTINE_MPN_PREINV_DIVREM_1_CALL				\
+  ((*function) (wp, s->size, s->xp, 0, s->r, dinv, shift))
+
+
+/* s->r is duplicated to form the multiplier, defaulting to
+   MP_BASES_BIG_BASE_10.  Not sure if that's particularly useful, but at
+   least it provides some control.  */
+#define SPEED_ROUTINE_MPN_UNARY_N(function,N)				\
+  {									\
+    mp_ptr     wp;							\
+    mp_size_t  wn;							\
+    unsigned   i;							\
+    double     t;							\
+    mp_limb_t  yp[N];							\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= N);					\
+									\
+    TMP_MARK;								\
+    wn = s->size + N-1;							\
+    SPEED_TMP_ALLOC_LIMBS (wp, wn, s->align_wp);			\
+    for (i = 0; i < N; i++)						\
+      yp[i] = (s->r != 0 ? s->r : MP_BASES_BIG_BASE_10);		\
+									\
+    speed_operand_src (s, s->xp, s->size);				\
+    speed_operand_src (s, yp, (mp_size_t) N);				\
+    speed_operand_dst (s, wp, wn);					\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      function (wp, s->xp, s->size, yp);				\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+
+#define SPEED_ROUTINE_MPN_UNARY_2(function)				\
+  SPEED_ROUTINE_MPN_UNARY_N (function, 2)
+#define SPEED_ROUTINE_MPN_UNARY_3(function)				\
+  SPEED_ROUTINE_MPN_UNARY_N (function, 3)
+#define SPEED_ROUTINE_MPN_UNARY_4(function)				\
+  SPEED_ROUTINE_MPN_UNARY_N (function, 4)
+#define SPEED_ROUTINE_MPN_UNARY_5(function)				\
+  SPEED_ROUTINE_MPN_UNARY_N (function, 5)
+#define SPEED_ROUTINE_MPN_UNARY_6(function)				\
+  SPEED_ROUTINE_MPN_UNARY_N (function, 6)
+#define SPEED_ROUTINE_MPN_UNARY_7(function)				\
+  SPEED_ROUTINE_MPN_UNARY_N (function, 7)
+#define SPEED_ROUTINE_MPN_UNARY_8(function)				\
+  SPEED_ROUTINE_MPN_UNARY_N (function, 8)
+
+
+/* For mpn_mul, mpn_mul_basecase, xsize=r, ysize=s->size. */
+#define SPEED_ROUTINE_MPN_MUL(function)					\
+  {									\
+    mp_ptr    wp;							\
+    mp_size_t size1;							\
+    unsigned  i;							\
+    double    t;							\
+    TMP_DECL;								\
+									\
+    size1 = (s->r == 0 ? s->size : s->r);				\
+    if (size1 < 0) size1 = -size1 - s->size;				\
+									\
+    SPEED_RESTRICT_COND (size1 >= 1);					\
+    SPEED_RESTRICT_COND (s->size >= size1);				\
+									\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (wp, size1 + s->size, s->align_wp);		\
+									\
+    speed_operand_src (s, s->xp, s->size);				\
+    speed_operand_src (s, s->yp, size1);				\
+    speed_operand_dst (s, wp, size1 + s->size);				\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      function (wp, s->xp, s->size, s->yp, size1);			\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+
+
+#define SPEED_ROUTINE_MPN_MUL_N_CALL(call)				\
+  {									\
+    mp_ptr    wp;							\
+    unsigned  i;							\
+    double    t;							\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= 1);					\
+									\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (wp, 2*s->size, s->align_wp);			\
+									\
+    speed_operand_src (s, s->xp, s->size);				\
+    speed_operand_src (s, s->yp, s->size);				\
+    speed_operand_dst (s, wp, 2*s->size);				\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      call;								\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+
+#define SPEED_ROUTINE_MPN_MUL_N(function)				\
+  SPEED_ROUTINE_MPN_MUL_N_CALL (function (wp, s->xp, s->yp, s->size));
+
+#define SPEED_ROUTINE_MPN_MULLO_N_CALL(call)				\
+  {									\
+    mp_ptr    wp;							\
+    unsigned  i;							\
+    double    t;							\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= 1);					\
+									\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (wp, s->size, s->align_wp);			\
+									\
+    speed_operand_src (s, s->xp, s->size);				\
+    speed_operand_src (s, s->yp, s->size);				\
+    speed_operand_dst (s, wp, s->size);					\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      call;								\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+
+#define SPEED_ROUTINE_MPN_MULLO_N(function)				\
+  SPEED_ROUTINE_MPN_MULLO_N_CALL (function (wp, s->xp, s->yp, s->size));
+
+#define SPEED_ROUTINE_MPN_MULLO_BASECASE(function)			\
+  SPEED_ROUTINE_MPN_MULLO_N_CALL (function (wp, s->xp, s->yp, s->size));
+
+#define SPEED_ROUTINE_MPN_SQRLO(function)				\
+  {									\
+    mp_ptr    wp;							\
+    unsigned  i;							\
+    double    t;							\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= 1);					\
+									\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (wp, s->size, s->align_wp);			\
+									\
+    speed_operand_src (s, s->xp, s->size);				\
+    speed_operand_dst (s, wp, s->size);					\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      function (wp, s->xp, s->size);					\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+
+/* For mpn_mulmid, mpn_mulmid_basecase, xsize=r, ysize=s->size. */
+#define SPEED_ROUTINE_MPN_MULMID(function)				\
+  {									\
+    mp_ptr    wp, xp;							\
+    mp_size_t size1;							\
+    unsigned  i;							\
+    double    t;							\
+    TMP_DECL;								\
+									\
+    size1 = (s->r == 0 ? (2 * s->size - 1) : s->r);			\
+									\
+    SPEED_RESTRICT_COND (s->size >= 1);					\
+    SPEED_RESTRICT_COND (size1 >= s->size);				\
+									\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (wp, size1 - s->size + 3, s->align_wp);	\
+    SPEED_TMP_ALLOC_LIMBS (xp, size1, s->align_xp);			\
+									\
+    speed_operand_src (s, xp, size1);					\
+    speed_operand_src (s, s->yp, s->size);				\
+    speed_operand_dst (s, wp, size1 - s->size + 3);			\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      function (wp, xp, size1, s->yp, s->size);				\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+
+#define SPEED_ROUTINE_MPN_MULMID_N(function)				\
+  {									\
+    mp_ptr    wp, xp;							\
+    mp_size_t size1;							\
+    unsigned  i;							\
+    double    t;							\
+    TMP_DECL;								\
+									\
+    size1 = 2 * s->size - 1;						\
+									\
+    SPEED_RESTRICT_COND (s->size >= 1);					\
+									\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (wp, size1 - s->size + 3, s->align_wp);	\
+    SPEED_TMP_ALLOC_LIMBS (xp, size1, s->align_xp);			\
+									\
+    speed_operand_src (s, xp, size1);					\
+    speed_operand_src (s, s->yp, s->size);				\
+    speed_operand_dst (s, wp, size1 - s->size + 3);			\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      function (wp, xp, s->yp, s->size);				\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+
+#define SPEED_ROUTINE_MPN_TOOM42_MULMID(function)			\
+  {									\
+    mp_ptr    wp, xp, scratch;						\
+    mp_size_t size1, scratch_size;					\
+    unsigned  i;							\
+    double    t;							\
+    TMP_DECL;								\
+									\
+    size1 = 2 * s->size - 1;						\
+									\
+    SPEED_RESTRICT_COND (s->size >= 1);					\
+									\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (wp, size1 - s->size + 3, s->align_wp);	\
+    SPEED_TMP_ALLOC_LIMBS (xp, size1, s->align_xp);			\
+    scratch_size = mpn_toom42_mulmid_itch (s->size);			\
+    SPEED_TMP_ALLOC_LIMBS (scratch, scratch_size, 0);			\
+									\
+    speed_operand_src (s, xp, size1);					\
+    speed_operand_src (s, s->yp, s->size);				\
+    speed_operand_dst (s, wp, size1 - s->size + 3);			\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      function (wp, xp, s->yp, s->size, scratch);			\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+
+#define SPEED_ROUTINE_MPN_MULMOD_BNM1_CALL(call)			\
+  {									\
+    mp_ptr    wp, tp;							\
+    unsigned  i;							\
+    double    t;							\
+    mp_size_t itch;							\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= 1);					\
+									\
+    itch = mpn_mulmod_bnm1_itch (s->size, s->size, s->size);		\
+									\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (wp, 2 * s->size, s->align_wp);		\
+    SPEED_TMP_ALLOC_LIMBS (tp, itch, s->align_wp2);			\
+									\
+    speed_operand_src (s, s->xp, s->size);				\
+    speed_operand_src (s, s->yp, s->size);				\
+    speed_operand_dst (s, wp, 2 * s->size);				\
+    speed_operand_dst (s, tp, itch);					\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      call;								\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+#define SPEED_ROUTINE_MPN_MULMOD_BNM1_ROUNDED(function)			\
+  {									\
+    mp_ptr    wp, tp;							\
+    unsigned  i;							\
+    double    t;							\
+    mp_size_t size, itch;						\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= 1);					\
+									\
+    size = mpn_mulmod_bnm1_next_size (s->size);				\
+    itch = mpn_mulmod_bnm1_itch (size, size, size);			\
+									\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (wp, size, s->align_wp);			\
+    SPEED_TMP_ALLOC_LIMBS (tp, itch, s->align_wp2);			\
+									\
+    speed_operand_src (s, s->xp, s->size);				\
+    speed_operand_src (s, s->yp, s->size);				\
+    speed_operand_dst (s, wp, size);					\
+    speed_operand_dst (s, tp, itch);					\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      function (wp, size, s->xp, s->size, s->yp, s->size, tp);		\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+
+#define SPEED_ROUTINE_MPN_MUL_N_TSPACE(call, tsize, minsize)		\
+  {									\
+    mp_ptr    wp, tspace;						\
+    unsigned  i;							\
+    double    t;							\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= minsize);				\
+									\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (wp, 2*s->size, s->align_wp);			\
+    SPEED_TMP_ALLOC_LIMBS (tspace, tsize, s->align_wp2);		\
+									\
+    speed_operand_src (s, s->xp, s->size);				\
+    speed_operand_src (s, s->yp, s->size);				\
+    speed_operand_dst (s, wp, 2*s->size);				\
+    speed_operand_dst (s, tspace, tsize);				\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      call;								\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+
+#define SPEED_ROUTINE_MPN_TOOM22_MUL_N(function)			\
+  SPEED_ROUTINE_MPN_MUL_N_TSPACE					\
+    (function (wp, s->xp, s->size, s->yp, s->size, tspace),		\
+     mpn_toom22_mul_itch (s->size, s->size),				\
+     MPN_TOOM22_MUL_MINSIZE)
+
+#define SPEED_ROUTINE_MPN_TOOM33_MUL_N(function)			\
+  SPEED_ROUTINE_MPN_MUL_N_TSPACE					\
+    (function (wp, s->xp, s->size, s->yp, s->size, tspace),		\
+     mpn_toom33_mul_itch (s->size, s->size),				\
+     MPN_TOOM33_MUL_MINSIZE)
+
+#define SPEED_ROUTINE_MPN_TOOM44_MUL_N(function)			\
+  SPEED_ROUTINE_MPN_MUL_N_TSPACE					\
+    (function (wp, s->xp, s->size, s->yp, s->size, tspace),		\
+     mpn_toom44_mul_itch (s->size, s->size),				\
+     MPN_TOOM44_MUL_MINSIZE)
+
+#define SPEED_ROUTINE_MPN_TOOM6H_MUL_N(function)			\
+  SPEED_ROUTINE_MPN_MUL_N_TSPACE					\
+    (function (wp, s->xp, s->size, s->yp, s->size, tspace),		\
+     mpn_toom6h_mul_itch (s->size, s->size),				\
+     MPN_TOOM6H_MUL_MINSIZE)
+
+#define SPEED_ROUTINE_MPN_TOOM8H_MUL_N(function)			\
+  SPEED_ROUTINE_MPN_MUL_N_TSPACE					\
+    (function (wp, s->xp, s->size, s->yp, s->size, tspace),		\
+     mpn_toom8h_mul_itch (s->size, s->size),				\
+     MPN_TOOM8H_MUL_MINSIZE)
+
+#define SPEED_ROUTINE_MPN_TOOM32_MUL(function)				\
+  SPEED_ROUTINE_MPN_MUL_N_TSPACE					\
+    (function (wp, s->xp, s->size, s->yp, 2*s->size/3, tspace),		\
+     mpn_toom32_mul_itch (s->size, 2*s->size/3),			\
+     MPN_TOOM32_MUL_MINSIZE)
+
+#define SPEED_ROUTINE_MPN_TOOM42_MUL(function)				\
+  SPEED_ROUTINE_MPN_MUL_N_TSPACE					\
+    (function (wp, s->xp, s->size, s->yp, s->size/2, tspace),		\
+     mpn_toom42_mul_itch (s->size, s->size/2),				\
+     MPN_TOOM42_MUL_MINSIZE)
+
+#define SPEED_ROUTINE_MPN_TOOM43_MUL(function)				\
+  SPEED_ROUTINE_MPN_MUL_N_TSPACE					\
+    (function (wp, s->xp, s->size, s->yp, s->size*3/4, tspace),		\
+     mpn_toom43_mul_itch (s->size, s->size*3/4),			\
+     MPN_TOOM43_MUL_MINSIZE)
+
+#define SPEED_ROUTINE_MPN_TOOM63_MUL(function)				\
+  SPEED_ROUTINE_MPN_MUL_N_TSPACE					\
+    (function (wp, s->xp, s->size, s->yp, s->size/2, tspace),		\
+     mpn_toom63_mul_itch (s->size, s->size/2),				\
+     MPN_TOOM63_MUL_MINSIZE)
+
+#define SPEED_ROUTINE_MPN_TOOM32_FOR_TOOM43_MUL(function)		\
+  SPEED_ROUTINE_MPN_MUL_N_TSPACE					\
+    (function (wp, s->xp, s->size, s->yp, 17*s->size/24, tspace),	\
+     mpn_toom32_mul_itch (s->size, 17*s->size/24),			\
+     MPN_TOOM32_MUL_MINSIZE)
+#define SPEED_ROUTINE_MPN_TOOM43_FOR_TOOM32_MUL(function)		\
+  SPEED_ROUTINE_MPN_MUL_N_TSPACE					\
+    (function (wp, s->xp, s->size, s->yp, 17*s->size/24, tspace),	\
+     mpn_toom43_mul_itch (s->size, 17*s->size/24),			\
+     MPN_TOOM43_MUL_MINSIZE)
+
+#define SPEED_ROUTINE_MPN_TOOM32_FOR_TOOM53_MUL(function)		\
+  SPEED_ROUTINE_MPN_MUL_N_TSPACE					\
+    (function (wp, s->xp, s->size, s->yp, 19*s->size/30, tspace),	\
+     mpn_toom32_mul_itch (s->size, 19*s->size/30),			\
+     MPN_TOOM32_MUL_MINSIZE)
+#define SPEED_ROUTINE_MPN_TOOM53_FOR_TOOM32_MUL(function)		\
+  SPEED_ROUTINE_MPN_MUL_N_TSPACE					\
+    (function (wp, s->xp, s->size, s->yp, 19*s->size/30, tspace),	\
+     mpn_toom53_mul_itch (s->size, 19*s->size/30),			\
+     MPN_TOOM53_MUL_MINSIZE)
+
+#define SPEED_ROUTINE_MPN_TOOM42_FOR_TOOM53_MUL(function)		\
+  SPEED_ROUTINE_MPN_MUL_N_TSPACE					\
+    (function (wp, s->xp, s->size, s->yp, 11*s->size/20, tspace),	\
+     mpn_toom42_mul_itch (s->size, 11*s->size/20),			\
+     MPN_TOOM42_MUL_MINSIZE)
+#define SPEED_ROUTINE_MPN_TOOM53_FOR_TOOM42_MUL(function)		\
+  SPEED_ROUTINE_MPN_MUL_N_TSPACE					\
+    (function (wp, s->xp, s->size, s->yp, 11*s->size/20, tspace),	\
+     mpn_toom53_mul_itch (s->size, 11*s->size/20),			\
+     MPN_TOOM53_MUL_MINSIZE)
+
+#define SPEED_ROUTINE_MPN_TOOM43_FOR_TOOM54_MUL(function)		\
+  SPEED_ROUTINE_MPN_MUL_N_TSPACE					\
+    (function (wp, s->xp, s->size, s->yp, 5*s->size/6, tspace),	\
+     mpn_toom42_mul_itch (s->size, 5*s->size/6),			\
+     MPN_TOOM54_MUL_MINSIZE)
+#define SPEED_ROUTINE_MPN_TOOM54_FOR_TOOM43_MUL(function)		\
+  SPEED_ROUTINE_MPN_MUL_N_TSPACE					\
+    (function (wp, s->xp, s->size, s->yp, 5*s->size/6, tspace),	\
+     mpn_toom54_mul_itch (s->size, 5*s->size/6),			\
+     MPN_TOOM54_MUL_MINSIZE)
+
+
+
+#define SPEED_ROUTINE_MPN_SQR_CALL(call)				\
+  {									\
+    mp_ptr    wp;							\
+    unsigned  i;							\
+    double    t;							\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= 1);					\
+									\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (wp, 2*s->size, s->align_wp);			\
+									\
+    speed_operand_src (s, s->xp, s->size);				\
+    speed_operand_dst (s, wp, 2*s->size);				\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      call;								\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+
+#define SPEED_ROUTINE_MPN_SQR(function)					\
+  SPEED_ROUTINE_MPN_SQR_CALL (function (wp, s->xp, s->size))
+
+#define SPEED_ROUTINE_MPN_SQR_DIAG_ADDLSH1_CALL(call)			\
+  {									\
+    mp_ptr    wp, tp;							\
+    unsigned  i;							\
+    double    t;							\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= 2);					\
+									\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (tp, 2 * s->size, s->align_wp);		\
+    SPEED_TMP_ALLOC_LIMBS (wp, 2 * s->size, s->align_wp);		\
+									\
+    speed_operand_src (s, s->xp, s->size);				\
+    speed_operand_src (s, tp, 2 * s->size);				\
+    speed_operand_dst (s, wp, 2 * s->size);				\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      call;								\
+    while (--i != 0);							\
+    t = speed_endtime () / 2;						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+
+#define SPEED_ROUTINE_MPN_SQR_TSPACE(call, tsize, minsize)		\
+  {									\
+    mp_ptr    wp, tspace;						\
+    unsigned  i;							\
+    double    t;							\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= minsize);				\
+									\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (wp, 2*s->size, s->align_wp);			\
+    SPEED_TMP_ALLOC_LIMBS (tspace, tsize, s->align_wp2);		\
+									\
+    speed_operand_src (s, s->xp, s->size);				\
+    speed_operand_dst (s, wp, 2*s->size);				\
+    speed_operand_dst (s, tspace, tsize);				\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      call;								\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+
+#define SPEED_ROUTINE_MPN_TOOM2_SQR(function)				\
+  SPEED_ROUTINE_MPN_SQR_TSPACE (function (wp, s->xp, s->size, tspace),	\
+				mpn_toom2_sqr_itch (s->size),		\
+				MPN_TOOM2_SQR_MINSIZE)
+
+#define SPEED_ROUTINE_MPN_TOOM3_SQR(function)				\
+  SPEED_ROUTINE_MPN_SQR_TSPACE (function (wp, s->xp, s->size, tspace),	\
+				mpn_toom3_sqr_itch (s->size),		\
+				MPN_TOOM3_SQR_MINSIZE)
+
+
+#define SPEED_ROUTINE_MPN_TOOM4_SQR(function)				\
+  SPEED_ROUTINE_MPN_SQR_TSPACE (function (wp, s->xp, s->size, tspace),	\
+				mpn_toom4_sqr_itch (s->size),		\
+				MPN_TOOM4_SQR_MINSIZE)
+
+#define SPEED_ROUTINE_MPN_TOOM6_SQR(function)				\
+  SPEED_ROUTINE_MPN_SQR_TSPACE (function (wp, s->xp, s->size, tspace),	\
+				mpn_toom6_sqr_itch (s->size),		\
+				MPN_TOOM6_SQR_MINSIZE)
+
+#define SPEED_ROUTINE_MPN_TOOM8_SQR(function)				\
+  SPEED_ROUTINE_MPN_SQR_TSPACE (function (wp, s->xp, s->size, tspace),	\
+				mpn_toom8_sqr_itch (s->size),		\
+				MPN_TOOM8_SQR_MINSIZE)
+
+#define SPEED_ROUTINE_MPN_MOD_CALL(call)				\
+  {									\
+    unsigned   i;							\
+									\
+    SPEED_RESTRICT_COND (s->size >= 0);					\
+									\
+    speed_operand_src (s, s->xp, s->size);				\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      call;								\
+    while (--i != 0);							\
+									\
+    return speed_endtime ();						\
+  }
+
+#define SPEED_ROUTINE_MPN_MOD_1(function)				\
+   SPEED_ROUTINE_MPN_MOD_CALL ((*function) (s->xp, s->size, s->r))
+
+#define SPEED_ROUTINE_MPN_MOD_1C(function)				\
+   SPEED_ROUTINE_MPN_MOD_CALL ((*function)(s->xp, s->size, s->r, CNST_LIMB(0)))
+
+#define SPEED_ROUTINE_MPN_MODEXACT_1_ODD(function)			\
+  SPEED_ROUTINE_MPN_MOD_CALL (function (s->xp, s->size, s->r));
+
+#define SPEED_ROUTINE_MPN_MODEXACT_1C_ODD(function)			\
+  SPEED_ROUTINE_MPN_MOD_CALL (function (s->xp, s->size, s->r, CNST_LIMB(0)));
+
+#define SPEED_ROUTINE_MPN_MOD_34LSUB1(function)				\
+   SPEED_ROUTINE_MPN_MOD_CALL ((*function) (s->xp, s->size))
+
+#define SPEED_ROUTINE_MPN_PREINV_MOD_1(function)			\
+  {									\
+    unsigned   i;							\
+    mp_limb_t  inv;							\
+									\
+    SPEED_RESTRICT_COND (s->size >= 0);					\
+    SPEED_RESTRICT_COND (s->r & GMP_LIMB_HIGHBIT);			\
+									\
+    invert_limb (inv, s->r);						\
+    speed_operand_src (s, s->xp, s->size);				\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      (*function) (s->xp, s->size, s->r, inv);				\
+    while (--i != 0);							\
+									\
+    return speed_endtime ();						\
+  }
+
+#define SPEED_ROUTINE_MPN_MOD_1_1(function,pfunc)			\
+  {									\
+    unsigned   i;							\
+    mp_limb_t  inv[4];							\
+									\
+    SPEED_RESTRICT_COND (s->size >= 2);					\
+									\
+    mpn_mod_1_1p_cps (inv, s->r);					\
+    speed_operand_src (s, s->xp, s->size);				\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do {								\
+      pfunc (inv, s->r);						\
+      function (s->xp, s->size, s->r << inv[1], inv);				\
+    } while (--i != 0);							\
+									\
+    return speed_endtime ();						\
+  }
+#define SPEED_ROUTINE_MPN_MOD_1_N(function,pfunc,N)			\
+  {									\
+    unsigned   i;							\
+    mp_limb_t  inv[N+3];						\
+									\
+    SPEED_RESTRICT_COND (s->size >= 1);					\
+    SPEED_RESTRICT_COND (s->r <= ~(mp_limb_t)0 / N);			\
+									\
+    speed_operand_src (s, s->xp, s->size);				\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do {								\
+      pfunc (inv, s->r);						\
+      function (s->xp, s->size, s->r, inv);				\
+    } while (--i != 0);							\
+									\
+    return speed_endtime ();						\
+  }
+
+
+/* A division of 2*s->size by s->size limbs */
+
+#define SPEED_ROUTINE_MPN_DC_DIVREM_CALL(call)				\
+  {									\
+    unsigned  i;							\
+    mp_ptr    a, d, q, r;						\
+    double    t;							\
+    gmp_pi1_t dinv;							\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= 1);					\
+									\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (a, 2*s->size, s->align_xp);			\
+    SPEED_TMP_ALLOC_LIMBS (d, s->size,   s->align_yp);			\
+    SPEED_TMP_ALLOC_LIMBS (q, s->size+1, s->align_wp);			\
+    SPEED_TMP_ALLOC_LIMBS (r, s->size,   s->align_wp2);			\
+									\
+    MPN_COPY (a, s->xp, s->size);					\
+    MPN_COPY (a+s->size, s->xp, s->size);				\
+									\
+    MPN_COPY (d, s->yp, s->size);					\
+									\
+    /* normalize the data */						\
+    d[s->size-1] |= GMP_NUMB_HIGHBIT;					\
+    a[2*s->size-1] = d[s->size-1] - 1;					\
+									\
+    invert_pi1 (dinv, d[s->size-1], d[s->size-2]);			\
+									\
+    speed_operand_src (s, a, 2*s->size);				\
+    speed_operand_src (s, d, s->size);					\
+    speed_operand_dst (s, q, s->size+1);				\
+    speed_operand_dst (s, r, s->size);					\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      call;								\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+
+
+/* A remainder 2*s->size by s->size limbs */
+
+#define SPEED_ROUTINE_MPZ_MOD(function)					\
+  {									\
+    unsigned   i;							\
+    mpz_t      a, d, r;							\
+									\
+    SPEED_RESTRICT_COND (s->size >= 1);					\
+									\
+    mpz_init_set_n (d, s->yp, s->size);					\
+									\
+    /* high part less than d, low part a duplicate copied in */		\
+    mpz_init_set_n (a, s->xp, s->size);					\
+    mpz_mod (a, a, d);							\
+    mpz_mul_2exp (a, a, GMP_LIMB_BITS * s->size);			\
+    MPN_COPY (PTR(a), s->xp, s->size);					\
+									\
+    mpz_init (r);							\
+									\
+    speed_operand_src (s, PTR(a), SIZ(a));				\
+    speed_operand_src (s, PTR(d), SIZ(d));				\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      function (r, a, d);						\
+    while (--i != 0);							\
+    return speed_endtime ();						\
+  }
+
+#define SPEED_ROUTINE_MPN_PI1_DIV(function, INV, DMIN, QMIN)		\
+  {									\
+    unsigned   i;							\
+    mp_ptr     dp, tp, ap, qp;						\
+    gmp_pi1_t  inv;							\
+    double     t;							\
+    mp_size_t size1;							\
+    TMP_DECL;								\
+									\
+    size1 = (s->r == 0 ? 2 * s->size : s->r);				\
+									\
+    SPEED_RESTRICT_COND (s->size >= DMIN);				\
+    SPEED_RESTRICT_COND (size1 - s->size >= QMIN);			\
+									\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (ap, size1, s->align_xp);			\
+    SPEED_TMP_ALLOC_LIMBS (dp, s->size, s->align_yp);			\
+    SPEED_TMP_ALLOC_LIMBS (qp, size1 - s->size, s->align_wp);		\
+    SPEED_TMP_ALLOC_LIMBS (tp, size1, s->align_wp2);			\
+									\
+    /* we don't fill in dividend completely when size1 > s->size */	\
+    MPN_COPY (ap,         s->xp, s->size);				\
+    MPN_COPY (ap + size1 - s->size, s->xp, s->size);			\
+									\
+    MPN_COPY (dp,         s->yp, s->size);				\
+									\
+    /* normalize the data */						\
+    dp[s->size-1] |= GMP_NUMB_HIGHBIT;					\
+    ap[size1 - 1] = dp[s->size - 1] - 1;				\
+									\
+    invert_pi1 (inv, dp[s->size-1], dp[s->size-2]);			\
+									\
+    speed_operand_src (s, ap, size1);					\
+    speed_operand_dst (s, tp, size1);					\
+    speed_operand_src (s, dp, s->size);					\
+    speed_operand_dst (s, qp, size1 - s->size);				\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do {								\
+      MPN_COPY (tp, ap, size1);						\
+      function (qp, tp, size1, dp, s->size, INV);			\
+    } while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+#define SPEED_ROUTINE_MPN_MU_DIV_Q(function,itchfn)			\
+  {									\
+    unsigned   i;							\
+    mp_ptr     dp, tp, qp, scratch;					\
+    double     t;							\
+    mp_size_t itch;							\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= 2);					\
+									\
+    itch = itchfn (2 * s->size, s->size, 0);				\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (dp, s->size, s->align_yp);			\
+    SPEED_TMP_ALLOC_LIMBS (qp, s->size, s->align_wp);			\
+    SPEED_TMP_ALLOC_LIMBS (tp, 2 * s->size, s->align_xp);		\
+    SPEED_TMP_ALLOC_LIMBS (scratch, itch, s->align_wp2);		\
+									\
+    MPN_COPY (tp,         s->xp, s->size);				\
+    MPN_COPY (tp+s->size, s->xp, s->size);				\
+									\
+    /* normalize the data */						\
+    dp[s->size-1] |= GMP_NUMB_HIGHBIT;					\
+    tp[2*s->size-1] = dp[s->size-1] - 1;				\
+									\
+    speed_operand_dst (s, qp, s->size);					\
+    speed_operand_src (s, tp, 2 * s->size);				\
+    speed_operand_src (s, dp, s->size);					\
+    speed_operand_dst (s, scratch, itch);				\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do {								\
+      function (qp, tp, 2 * s->size, dp, s->size, scratch);		\
+    } while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+#define SPEED_ROUTINE_MPN_MU_DIV_QR(function,itchfn)			\
+  {									\
+    unsigned   i;							\
+    mp_ptr     dp, tp, qp, rp, scratch;					\
+    double     t;							\
+    mp_size_t size1, itch;						\
+    TMP_DECL;								\
+									\
+    size1 = (s->r == 0 ? 2 * s->size : s->r);				\
+									\
+    SPEED_RESTRICT_COND (s->size >= 2);					\
+    SPEED_RESTRICT_COND (size1 >= s->size);				\
+									\
+    itch = itchfn (size1, s->size, 0);					\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (dp, s->size, s->align_yp);			\
+    SPEED_TMP_ALLOC_LIMBS (qp, size1 - s->size, s->align_wp);		\
+    SPEED_TMP_ALLOC_LIMBS (tp, size1, s->align_xp);			\
+    SPEED_TMP_ALLOC_LIMBS (scratch, itch, s->align_wp2);		\
+    SPEED_TMP_ALLOC_LIMBS (rp, s->size, s->align_wp2); /* alignment? */	\
+									\
+    /* we don't fill in dividend completely when size1 > s->size */	\
+    MPN_COPY (tp,         s->xp, s->size);				\
+    MPN_COPY (tp + size1 - s->size, s->xp, s->size);			\
+									\
+    MPN_COPY (dp,         s->yp, s->size);				\
+									\
+    /* normalize the data */						\
+    dp[s->size-1] |= GMP_NUMB_HIGHBIT;					\
+    tp[size1 - 1] = dp[s->size - 1] - 1;				\
+									\
+    speed_operand_dst (s, qp, size1 - s->size);				\
+    speed_operand_dst (s, rp, s->size);					\
+    speed_operand_src (s, tp, size1);					\
+    speed_operand_src (s, dp, s->size);					\
+    speed_operand_dst (s, scratch, itch);				\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do {								\
+      function (qp, rp, tp, size1, dp, s->size, scratch);		\
+    } while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+#define SPEED_ROUTINE_MPN_MUPI_DIV_QR(function,itchfn)			\
+  {									\
+    unsigned   i;							\
+    mp_ptr     dp, tp, qp, rp, ip, scratch, tmp;			\
+    double     t;							\
+    mp_size_t  size1, itch;						\
+    TMP_DECL;								\
+									\
+    size1 = (s->r == 0 ? 2 * s->size : s->r);				\
+									\
+    SPEED_RESTRICT_COND (s->size >= 2);					\
+    SPEED_RESTRICT_COND (size1 >= s->size);				\
+									\
+    itch = itchfn (size1, s->size, s->size);				\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (dp, s->size, s->align_yp);			\
+    SPEED_TMP_ALLOC_LIMBS (qp, size1 - s->size, s->align_wp);		\
+    SPEED_TMP_ALLOC_LIMBS (tp, size1, s->align_xp);			\
+    SPEED_TMP_ALLOC_LIMBS (scratch, itch, s->align_wp2);		\
+    SPEED_TMP_ALLOC_LIMBS (rp, s->size, s->align_wp2); /* alignment? */	\
+    SPEED_TMP_ALLOC_LIMBS (ip, s->size, s->align_wp2); /* alignment? */	\
+									\
+    /* we don't fill in dividend completely when size1 > s->size */	\
+    MPN_COPY (tp,         s->xp, s->size);				\
+    MPN_COPY (tp + size1 - s->size, s->xp, s->size);			\
+									\
+    MPN_COPY (dp,         s->yp, s->size);				\
+									\
+    /* normalize the data */						\
+    dp[s->size-1] |= GMP_NUMB_HIGHBIT;					\
+    tp[size1 - 1] = dp[s->size-1] - 1;					\
+									\
+    tmp = TMP_ALLOC_LIMBS (mpn_invert_itch (s->size));			\
+    mpn_invert (ip, dp, s->size, tmp);					\
+									\
+    speed_operand_dst (s, qp, size1 - s->size);				\
+    speed_operand_dst (s, rp, s->size);					\
+    speed_operand_src (s, tp, size1);					\
+    speed_operand_src (s, dp, s->size);					\
+    speed_operand_src (s, ip, s->size);					\
+    speed_operand_dst (s, scratch, itch);				\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do {								\
+      function (qp, rp, tp, size1, dp, s->size, ip, s->size, scratch);	\
+    } while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+
+#define SPEED_ROUTINE_MPN_PI1_BDIV_QR(function)				\
+  {									\
+    unsigned   i;							\
+    mp_ptr     dp, tp, ap, qp;						\
+    mp_limb_t  inv;							\
+    double     t;							\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= 1);					\
+									\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (ap, 2*s->size, s->align_xp);			\
+    SPEED_TMP_ALLOC_LIMBS (dp, s->size, s->align_yp);			\
+    SPEED_TMP_ALLOC_LIMBS (qp, s->size, s->align_wp);			\
+    SPEED_TMP_ALLOC_LIMBS (tp, 2*s->size, s->align_wp2);		\
+									\
+    MPN_COPY (ap,         s->xp, s->size);				\
+    MPN_COPY (ap+s->size, s->xp, s->size);				\
+									\
+    /* divisor must be odd */						\
+    MPN_COPY (dp, s->yp, s->size);					\
+    dp[0] |= 1;								\
+    binvert_limb (inv, dp[0]);						\
+    inv = -inv;								\
+									\
+    speed_operand_src (s, ap, 2*s->size);				\
+    speed_operand_dst (s, tp, 2*s->size);				\
+    speed_operand_src (s, dp, s->size);					\
+    speed_operand_dst (s, qp, s->size);					\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do {								\
+      MPN_COPY (tp, ap, 2*s->size);					\
+      function (qp, tp, 2*s->size, dp, s->size, inv);			\
+    } while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+#define SPEED_ROUTINE_MPN_PI1_BDIV_Q(function)				\
+  {									\
+    unsigned   i;							\
+    mp_ptr     dp, tp, qp;						\
+    mp_limb_t  inv;							\
+    double     t;							\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= 1);					\
+									\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (dp, s->size, s->align_yp);			\
+    SPEED_TMP_ALLOC_LIMBS (qp, s->size, s->align_wp);			\
+    SPEED_TMP_ALLOC_LIMBS (tp, s->size, s->align_wp2);			\
+									\
+    /* divisor must be odd */						\
+    MPN_COPY (dp, s->yp, s->size);					\
+    dp[0] |= 1;								\
+    binvert_limb (inv, dp[0]);						\
+    inv = -inv;								\
+									\
+    speed_operand_src (s, s->xp, s->size);				\
+    speed_operand_dst (s, tp, s->size);					\
+    speed_operand_src (s, dp, s->size);					\
+    speed_operand_dst (s, qp, s->size);					\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do {								\
+      MPN_COPY (tp, s->xp, s->size);					\
+      function (qp, tp, s->size, dp, s->size, inv);			\
+    } while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+#define SPEED_ROUTINE_MPN_PI1_BDIV_R(function)				\
+  {									\
+    unsigned   i;							\
+    mp_ptr     dp, tp, ap;						\
+    mp_limb_t  inv;							\
+    double     t;							\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= 1);					\
+									\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (ap, 2*s->size, s->align_xp);			\
+    SPEED_TMP_ALLOC_LIMBS (dp, s->size, s->align_yp);			\
+    SPEED_TMP_ALLOC_LIMBS (tp, 2*s->size, s->align_wp2);		\
+									\
+    MPN_COPY (ap,         s->xp, s->size);				\
+    MPN_COPY (ap+s->size, s->xp, s->size);				\
+									\
+    /* divisor must be odd */						\
+    MPN_COPY (dp, s->yp, s->size);					\
+    dp[0] |= 1;								\
+    binvert_limb (inv, dp[0]);						\
+    inv = -inv;								\
+									\
+    speed_operand_src (s, ap, 2*s->size);				\
+    speed_operand_dst (s, tp, 2*s->size);				\
+    speed_operand_src (s, dp, s->size);					\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do {								\
+      MPN_COPY (tp, ap, 2*s->size);					\
+      function (tp, 2*s->size, dp, s->size, inv);			\
+    } while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+#define SPEED_ROUTINE_MPN_MU_BDIV_Q(function,itchfn)			\
+  {									\
+    unsigned   i;							\
+    mp_ptr     dp, qp, scratch;						\
+    double     t;							\
+    mp_size_t itch;							\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= 2);					\
+									\
+    itch = itchfn (s->size, s->size);					\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (dp, s->size, s->align_yp);			\
+    SPEED_TMP_ALLOC_LIMBS (qp, s->size, s->align_wp);			\
+    SPEED_TMP_ALLOC_LIMBS (scratch, itch, s->align_wp2);		\
+									\
+    /* divisor must be odd */						\
+    MPN_COPY (dp, s->yp, s->size);					\
+    dp[0] |= 1;								\
+									\
+    speed_operand_dst (s, qp, s->size);					\
+    speed_operand_src (s, s->xp, s->size);				\
+    speed_operand_src (s, dp, s->size);					\
+    speed_operand_dst (s, scratch, itch);				\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do {								\
+      function (qp, s->xp, s->size, dp, s->size, scratch);		\
+    } while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+#define SPEED_ROUTINE_MPN_MU_BDIV_QR(function,itchfn)			\
+  {									\
+    unsigned   i;							\
+    mp_ptr     dp, tp, qp, rp, scratch;					\
+    double     t;							\
+    mp_size_t itch;							\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= 2);					\
+									\
+    itch = itchfn (2 * s->size, s->size);				\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (dp, s->size, s->align_yp);			\
+    SPEED_TMP_ALLOC_LIMBS (qp, s->size, s->align_wp);			\
+    SPEED_TMP_ALLOC_LIMBS (tp, 2 * s->size, s->align_xp);		\
+    SPEED_TMP_ALLOC_LIMBS (scratch, itch, s->align_wp2);		\
+    SPEED_TMP_ALLOC_LIMBS (rp, s->size, s->align_wp2); /* alignment? */	\
+									\
+    MPN_COPY (tp,         s->xp, s->size);				\
+    MPN_COPY (tp+s->size, s->xp, s->size);				\
+									\
+    /* divisor must be odd */						\
+    MPN_COPY (dp, s->yp, s->size);					\
+    dp[0] |= 1;								\
+									\
+    speed_operand_dst (s, qp, s->size);					\
+    speed_operand_dst (s, rp, s->size);					\
+    speed_operand_src (s, tp, 2 * s->size);				\
+    speed_operand_src (s, dp, s->size);					\
+    speed_operand_dst (s, scratch, itch);				\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do {								\
+      function (qp, rp, tp, 2 * s->size, dp, s->size, scratch);		\
+    } while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+
+#define SPEED_ROUTINE_MPN_BROOT(function)	\
+  {						\
+    SPEED_RESTRICT_COND (s->r & 1);		\
+    s->xp[0] |= 1;				\
+    SPEED_ROUTINE_MPN_UNARY_1_CALL		\
+      ((*function) (wp, s->xp, s->size, s->r));	\
+  }
+
+#define SPEED_ROUTINE_MPN_BROOTINV(function, itch)	\
+  {							\
+    mp_ptr    wp, tp;					\
+    unsigned  i;					\
+    double    t;					\
+    TMP_DECL;						\
+    TMP_MARK;						\
+    SPEED_RESTRICT_COND (s->size >= 1);			\
+    SPEED_RESTRICT_COND (s->r & 1);			\
+    wp = TMP_ALLOC_LIMBS (s->size);			\
+    tp = TMP_ALLOC_LIMBS ( (itch));			\
+    s->xp[0] |= 1;					\
+							\
+    speed_operand_src (s, s->xp, s->size);		\
+    speed_operand_dst (s, wp, s->size);			\
+    speed_cache_fill (s);				\
+							\
+    speed_starttime ();					\
+    i = s->reps;					\
+    do							\
+      (*function) (wp, s->xp, s->size, s->r, tp);	\
+    while (--i != 0);					\
+    t = speed_endtime ();				\
+							\
+    TMP_FREE;						\
+    return t;						\
+  }
+
+#define SPEED_ROUTINE_MPN_INVERT(function,itchfn)			\
+  {									\
+    long  i;								\
+    mp_ptr    up, tp, ip;						\
+    double    t;							\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= 1);					\
+									\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (ip, s->size, s->align_xp);			\
+    SPEED_TMP_ALLOC_LIMBS (up, s->size,   s->align_yp);			\
+    SPEED_TMP_ALLOC_LIMBS (tp, itchfn (s->size), s->align_wp);		\
+									\
+    MPN_COPY (up, s->xp, s->size);					\
+									\
+    /* normalize the data */						\
+    up[s->size-1] |= GMP_NUMB_HIGHBIT;					\
+									\
+    speed_operand_src (s, up, s->size);					\
+    speed_operand_dst (s, tp, s->size);					\
+    speed_operand_dst (s, ip, s->size);					\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      function (ip, up, s->size, tp);					\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+
+#define SPEED_ROUTINE_MPN_INVERTAPPR(function,itchfn)			\
+  {									\
+    long  i;								\
+    mp_ptr    up, tp, ip;						\
+    double    t;							\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= 1);					\
+									\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (ip, s->size, s->align_xp);			\
+    SPEED_TMP_ALLOC_LIMBS (up, s->size, s->align_yp);			\
+    SPEED_TMP_ALLOC_LIMBS (tp, itchfn (s->size), s->align_wp);		\
+									\
+    MPN_COPY (up, s->xp, s->size);					\
+									\
+    /* normalize the data */						\
+    up[s->size-1] |= GMP_NUMB_HIGHBIT;					\
+									\
+    speed_operand_src (s, up, s->size);					\
+    speed_operand_dst (s, tp, s->size);					\
+    speed_operand_dst (s, ip, s->size);					\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      function (ip, up, s->size, tp);					\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+
+#define SPEED_ROUTINE_MPN_NI_INVERTAPPR(function,itchfn)		\
+  {									\
+    long  i;								\
+    mp_ptr    up, tp, ip;						\
+    double    t;							\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= 3);					\
+									\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (ip, s->size, s->align_xp);			\
+    SPEED_TMP_ALLOC_LIMBS (up, s->size, s->align_yp);			\
+    SPEED_TMP_ALLOC_LIMBS (tp, itchfn (s->size), s->align_wp);		\
+									\
+    MPN_COPY (up, s->xp, s->size);					\
+									\
+    /* normalize the data */						\
+    up[s->size-1] |= GMP_NUMB_HIGHBIT;					\
+									\
+    speed_operand_src (s, up, s->size);					\
+    speed_operand_dst (s, tp, s->size);					\
+    speed_operand_dst (s, ip, s->size);					\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      function (ip, up, s->size, tp);					\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+
+#define SPEED_ROUTINE_MPN_BINVERT(function,itchfn)			\
+  {									\
+    long  i;								\
+    mp_ptr    up, tp, ip;						\
+    double    t;							\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= 1);					\
+									\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (ip, s->size, s->align_xp);			\
+    SPEED_TMP_ALLOC_LIMBS (up, s->size,   s->align_yp);			\
+    SPEED_TMP_ALLOC_LIMBS (tp, itchfn (s->size), s->align_wp);		\
+									\
+    MPN_COPY (up, s->xp, s->size);					\
+									\
+    /* normalize the data */						\
+    up[0] |= 1;								\
+									\
+    speed_operand_src (s, up, s->size);					\
+    speed_operand_dst (s, tp, s->size);					\
+    speed_operand_dst (s, ip, s->size);					\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      function (ip, up, s->size, tp);					\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+
+#define SPEED_ROUTINE_MPN_SEC_INVERT(function,itchfn)			\
+  {									\
+    long  i;								\
+    mp_ptr    up, mp, tp, ip;						\
+    double    t;							\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= 1);					\
+									\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (ip, s->size, s->align_xp);			\
+    SPEED_TMP_ALLOC_LIMBS (up, s->size, s->align_yp);			\
+    SPEED_TMP_ALLOC_LIMBS (mp, s->size, s->align_yp);			\
+    SPEED_TMP_ALLOC_LIMBS (tp, itchfn (s->size), s->align_wp);		\
+									\
+    speed_operand_src (s, up, s->size);					\
+    speed_operand_dst (s, tp, s->size);					\
+    speed_operand_dst (s, ip, s->size);					\
+    speed_cache_fill (s);						\
+									\
+    MPN_COPY (mp, s->yp, s->size);					\
+    /* Must be odd */							\
+    mp[0] |= 1;								\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      {									\
+	MPN_COPY (up, s->xp, s->size);					\
+	function (ip, up, mp, s->size, 2*s->size*GMP_NUMB_BITS, tp);	\
+      }									\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+
+#define SPEED_ROUTINE_REDC_1(function)					\
+  {									\
+    unsigned   i;							\
+    mp_ptr     cp, mp, tp, ap;						\
+    mp_limb_t  inv;							\
+    double     t;							\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= 1);					\
+									\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (ap, 2*s->size+1, s->align_xp);		\
+    SPEED_TMP_ALLOC_LIMBS (mp, s->size,     s->align_yp);		\
+    SPEED_TMP_ALLOC_LIMBS (cp, s->size,     s->align_wp);		\
+    SPEED_TMP_ALLOC_LIMBS (tp, 2*s->size+1, s->align_wp2);		\
+									\
+    MPN_COPY (ap,         s->xp, s->size);				\
+    MPN_COPY (ap+s->size, s->xp, s->size);				\
+									\
+    /* modulus must be odd */						\
+    MPN_COPY (mp, s->yp, s->size);					\
+    mp[0] |= 1;								\
+    binvert_limb (inv, mp[0]);						\
+    inv = -inv;								\
+									\
+    speed_operand_src (s, ap, 2*s->size+1);				\
+    speed_operand_dst (s, tp, 2*s->size+1);				\
+    speed_operand_src (s, mp, s->size);					\
+    speed_operand_dst (s, cp, s->size);					\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do {								\
+      MPN_COPY (tp, ap, 2*s->size);					\
+      function (cp, tp, mp, s->size, inv);				\
+    } while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+#define SPEED_ROUTINE_REDC_2(function)					\
+  {									\
+    unsigned   i;							\
+    mp_ptr     cp, mp, tp, ap;						\
+    mp_limb_t  invp[2];							\
+    double     t;							\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= 1);					\
+									\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (ap, 2*s->size+1, s->align_xp);		\
+    SPEED_TMP_ALLOC_LIMBS (mp, s->size,     s->align_yp);		\
+    SPEED_TMP_ALLOC_LIMBS (cp, s->size,     s->align_wp);		\
+    SPEED_TMP_ALLOC_LIMBS (tp, 2*s->size+1, s->align_wp2);		\
+									\
+    MPN_COPY (ap,         s->xp, s->size);				\
+    MPN_COPY (ap+s->size, s->xp, s->size);				\
+									\
+    /* modulus must be odd */						\
+    MPN_COPY (mp, s->yp, s->size);					\
+    mp[0] |= 1;								\
+    mpn_binvert (invp, mp, 2, tp);					\
+    invp[0] = -invp[0]; invp[1] = ~invp[1];				\
+									\
+    speed_operand_src (s, ap, 2*s->size+1);				\
+    speed_operand_dst (s, tp, 2*s->size+1);				\
+    speed_operand_src (s, mp, s->size);					\
+    speed_operand_dst (s, cp, s->size);					\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do {								\
+      MPN_COPY (tp, ap, 2*s->size);					\
+      function (cp, tp, mp, s->size, invp);				\
+    } while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+#define SPEED_ROUTINE_REDC_N(function)					\
+  {									\
+    unsigned   i;							\
+    mp_ptr     cp, mp, tp, ap, invp;					\
+    double     t;							\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size > 8);					\
+									\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (ap, 2*s->size+1, s->align_xp);		\
+    SPEED_TMP_ALLOC_LIMBS (mp, s->size,     s->align_yp);		\
+    SPEED_TMP_ALLOC_LIMBS (cp, s->size,     s->align_wp);		\
+    SPEED_TMP_ALLOC_LIMBS (tp, 2*s->size+1, s->align_wp2);		\
+    SPEED_TMP_ALLOC_LIMBS (invp, s->size,   s->align_wp2); /* align? */	\
+									\
+    MPN_COPY (ap,         s->xp, s->size);				\
+    MPN_COPY (ap+s->size, s->xp, s->size);				\
+									\
+    /* modulus must be odd */						\
+    MPN_COPY (mp, s->yp, s->size);					\
+    mp[0] |= 1;								\
+    mpn_binvert (invp, mp, s->size, tp);				\
+									\
+    speed_operand_src (s, ap, 2*s->size+1);				\
+    speed_operand_dst (s, tp, 2*s->size+1);				\
+    speed_operand_src (s, mp, s->size);					\
+    speed_operand_dst (s, cp, s->size);					\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do {								\
+      MPN_COPY (tp, ap, 2*s->size);					\
+      function (cp, tp, mp, s->size, invp);				\
+    } while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+
+
+#define SPEED_ROUTINE_MPN_POPCOUNT(function)				\
+  {									\
+    unsigned i;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= 1);					\
+									\
+    speed_operand_src (s, s->xp, s->size);				\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      function (s->xp, s->size);					\
+    while (--i != 0);							\
+									\
+    return speed_endtime ();						\
+  }
+
+#define SPEED_ROUTINE_MPN_HAMDIST(function)				\
+  {									\
+    unsigned i;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= 1);					\
+									\
+    speed_operand_src (s, s->xp, s->size);				\
+    speed_operand_src (s, s->yp, s->size);				\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      function (s->xp, s->yp, s->size);					\
+    while (--i != 0);							\
+									\
+    return speed_endtime ();						\
+  }
+
+
+#define SPEED_ROUTINE_MPZ_UI(function)					\
+  {									\
+    mpz_t     z;							\
+    unsigned  i;							\
+    double    t;							\
+									\
+    SPEED_RESTRICT_COND (s->size >= 0);					\
+									\
+    mpz_init (z);							\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      function (z, s->size);						\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    mpz_clear (z);							\
+    return t;								\
+  }
+
+#define SPEED_ROUTINE_MPZ_FAC_UI(function)    SPEED_ROUTINE_MPZ_UI(function)
+#define SPEED_ROUTINE_MPZ_FIB_UI(function)    SPEED_ROUTINE_MPZ_UI(function)
+#define SPEED_ROUTINE_MPZ_LUCNUM_UI(function) SPEED_ROUTINE_MPZ_UI(function)
+
+
+#define SPEED_ROUTINE_MPZ_2_UI(function)				\
+  {									\
+    mpz_t     z, z2;							\
+    unsigned  i;							\
+    double    t;							\
+									\
+    SPEED_RESTRICT_COND (s->size >= 0);					\
+									\
+    mpz_init (z);							\
+    mpz_init (z2);							\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      function (z, z2, s->size);					\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    mpz_clear (z);							\
+    mpz_clear (z2);							\
+    return t;								\
+  }
+
+#define SPEED_ROUTINE_MPZ_FIB2_UI(function)    SPEED_ROUTINE_MPZ_2_UI(function)
+#define SPEED_ROUTINE_MPZ_LUCNUM2_UI(function) SPEED_ROUTINE_MPZ_2_UI(function)
+
+
+#define SPEED_ROUTINE_MPN_FIB2_UI(function)				\
+  {									\
+    mp_ptr     fp, f1p;							\
+    mp_size_t  alloc;							\
+    unsigned   i;							\
+    double     t;							\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= 0);					\
+									\
+    TMP_MARK;								\
+    alloc = MPN_FIB2_SIZE (s->size);					\
+    SPEED_TMP_ALLOC_LIMBS (fp,	alloc, s->align_xp);			\
+    SPEED_TMP_ALLOC_LIMBS (f1p, alloc, s->align_yp);			\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      function (fp, f1p, s->size);					\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+
+
+
+/* Calculate b^e mod m for random b and m of s->size limbs and random e of 6
+   limbs.  m is forced to odd so that redc can be used.  e is limited in
+   size so the calculation doesn't take too long. */
+#define SPEED_ROUTINE_MPZ_POWM(function)				\
+  {									\
+    mpz_t     r, b, e, m;						\
+    unsigned  i;							\
+    double    t;							\
+									\
+    SPEED_RESTRICT_COND (s->size >= 1);					\
+									\
+    mpz_init (r);							\
+    if (s->r < 2)							\
+      mpz_init_set_n (b, s->xp, s->size);				\
+    else								\
+      mpz_init_set_ui (b, s->r);					\
+    mpz_init_set_n (m, s->yp, s->size);					\
+    mpz_setbit (m, 0);	/* force m to odd */				\
+    mpz_init_set_n (e, s->xp_block, 6);					\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      function (r, b, e, m);						\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    mpz_clear (r);							\
+    mpz_clear (b);							\
+    mpz_clear (e);							\
+    mpz_clear (m);							\
+    return t;								\
+  }
+
+/* (m-2)^0xAAAAAAAA mod m */
+#define SPEED_ROUTINE_MPZ_POWM_UI(function)				\
+  {									\
+    mpz_t     r, b, m;							\
+    unsigned  long  e;							\
+    unsigned  i;							\
+    double    t;							\
+									\
+    SPEED_RESTRICT_COND (s->size >= 1);					\
+									\
+    mpz_init (r);							\
+									\
+    /* force m to odd */						\
+    mpz_init (m);							\
+    mpz_set_n (m, s->xp, s->size);					\
+    PTR(m)[0] |= 1;							\
+									\
+    e = (~ (unsigned long) 0) / 3;					\
+    if (s->r != 0)							\
+      e = s->r;								\
+									\
+    mpz_init_set (b, m);						\
+    mpz_sub_ui (b, b, 2);						\
+/* printf ("%X\n", mpz_get_ui(m)); */					\
+    i = s->reps;							\
+    speed_starttime ();							\
+    do									\
+      function (r, b, e, m);						\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    mpz_clear (r);							\
+    mpz_clear (b);							\
+    mpz_clear (m);							\
+    return t;								\
+  }
+
+
+#define SPEED_ROUTINE_MPN_ADDSUB_CALL(call)				\
+  {									\
+    mp_ptr    wp, wp2, xp, yp;						\
+    unsigned  i;							\
+    double    t;							\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= 0);					\
+									\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (wp,	s->size, s->align_wp);			\
+    SPEED_TMP_ALLOC_LIMBS (wp2, s->size, s->align_wp2);			\
+    xp = s->xp;								\
+    yp = s->yp;								\
+									\
+    if (s->r == 0)	;						\
+    else if (s->r == 1) { xp = wp;	      }				\
+    else if (s->r == 2) {	    yp = wp2; }				\
+    else if (s->r == 3) { xp = wp;  yp = wp2; }				\
+    else if (s->r == 4) { xp = wp2; yp = wp;  }				\
+    else {								\
+      TMP_FREE;								\
+      return -1.0;							\
+    }									\
+    if (xp != s->xp) MPN_COPY (xp, s->xp, s->size);			\
+    if (yp != s->yp) MPN_COPY (yp, s->yp, s->size);			\
+									\
+    speed_operand_src (s, xp, s->size);					\
+    speed_operand_src (s, yp, s->size);					\
+    speed_operand_dst (s, wp, s->size);					\
+    speed_operand_dst (s, wp2, s->size);				\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      call;								\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+
+#define SPEED_ROUTINE_MPN_ADDSUB_N(function)				\
+  SPEED_ROUTINE_MPN_ADDSUB_CALL						\
+    (function (wp, wp2, xp, yp, s->size));
+
+#define SPEED_ROUTINE_MPN_ADDSUB_NC(function)				\
+  SPEED_ROUTINE_MPN_ADDSUB_CALL						\
+    (function (wp, wp2, xp, yp, s->size, 0));
+
+
+/* Doing an Nx1 gcd with the given r. */
+#define SPEED_ROUTINE_MPN_GCD_1N(function)				\
+  {									\
+    mp_ptr    xp;							\
+    unsigned  i;							\
+    double    t;							\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= 1);					\
+    SPEED_RESTRICT_COND (s->r != 0);					\
+									\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (xp, s->size, s->align_xp);			\
+    MPN_COPY (xp, s->xp, s->size);					\
+    xp[0] |= refmpn_zero_p (xp, s->size);				\
+									\
+    speed_operand_src (s, s->xp, s->size);				\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      function (xp, s->size, s->r);					\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+
+
+/* SPEED_BLOCK_SIZE many one GCDs of s->size bits each. */
+
+#define SPEED_ROUTINE_MPN_GCD_1_CALL(setup, call)			\
+  {									\
+    unsigned  i, j;							\
+    mp_ptr    px, py;							\
+    mp_limb_t x_mask, y_mask;						\
+    double    t;							\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= 1);					\
+    SPEED_RESTRICT_COND (s->size <= mp_bits_per_limb);			\
+									\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (px, SPEED_BLOCK_SIZE, s->align_xp);		\
+    SPEED_TMP_ALLOC_LIMBS (py, SPEED_BLOCK_SIZE, s->align_yp);		\
+    MPN_COPY (px, s->xp_block, SPEED_BLOCK_SIZE);			\
+    MPN_COPY (py, s->yp_block, SPEED_BLOCK_SIZE);			\
+									\
+    x_mask = MP_LIMB_T_LOWBITMASK (s->size);				\
+    y_mask = MP_LIMB_T_LOWBITMASK (s->r != 0 ? s->r : s->size);		\
+    for (i = 0; i < SPEED_BLOCK_SIZE; i++)				\
+      {									\
+	px[i] &= x_mask; px[i] += (px[i] == 0);				\
+	py[i] &= y_mask; py[i] += (py[i] == 0);				\
+	setup;								\
+      }									\
+									\
+    speed_operand_src (s, px, SPEED_BLOCK_SIZE);			\
+    speed_operand_src (s, py, SPEED_BLOCK_SIZE);			\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      {									\
+	j = SPEED_BLOCK_SIZE;						\
+	do								\
+	  {								\
+	    call;							\
+	  }								\
+	while (--j != 0);						\
+      }									\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+									\
+    s->time_divisor = SPEED_BLOCK_SIZE;					\
+    return t;								\
+  }
+
+#define SPEED_ROUTINE_MPN_GCD_1(function)				\
+  SPEED_ROUTINE_MPN_GCD_1_CALL( , function (&px[j-1], 1, py[j-1]))
+
+#define SPEED_ROUTINE_MPN_GCD_11(function)				\
+  SPEED_ROUTINE_MPN_GCD_1_CALL((px[i] |= 1, py[i] |= 1),		\
+			       function (px[j-1], py[j-1]))
+
+/* Multiply limbs by (B+1). Then we get a gcd exceeding one limb, so
+   we can measure gcd_22 loop only, without gcd_11. */
+#define SPEED_ROUTINE_MPN_GCD_22(function)				\
+  SPEED_ROUTINE_MPN_GCD_1_CALL((px[i] |= 1, py[i] |= 1),		\
+			       function (px[j-1], px[j-1], py[j-1], py[j-1]))
+
+#define SPEED_ROUTINE_MPN_JACBASE(function)				\
+  SPEED_ROUTINE_MPN_GCD_1_CALL						\
+    ({									\
+       /* require x<y, y odd, y!=1 */					\
+       px[i] %= py[i];							\
+       px[i] |= 1;							\
+       py[i] |= 1;							\
+       if (py[i]==1) py[i]=3;						\
+     },									\
+     function (px[j-1], py[j-1], 0))
+
+#define SPEED_ROUTINE_MPN_HGCD2(function)				\
+  {									\
+    unsigned   i, j;							\
+    struct hgcd_matrix1 m = {{{0,0},{0,0}}};				\
+    double     t;							\
+									\
+    speed_operand_src (s, s->xp_block, SPEED_BLOCK_SIZE);		\
+    speed_operand_src (s, s->yp_block, SPEED_BLOCK_SIZE);		\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    mp_limb_t chain = 0;						\
+    do									\
+      {									\
+	for (j = 0; j < SPEED_BLOCK_SIZE; j+= 2)			\
+	  {								\
+	    /* randomized but successively dependent */			\
+	    function (s->xp_block[j] | GMP_NUMB_HIGHBIT,		\
+		      s->xp_block[j+1] + chain,				\
+		      s->yp_block[j] | GMP_NUMB_HIGHBIT,		\
+		      s->yp_block[j+1], &m);				\
+	    chain += m.u[0][0];						\
+	  }								\
+      }									\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    /* make sure the compiler won't optimize away chain */		\
+    noop_1 (chain);							\
+									\
+    s->time_divisor = SPEED_BLOCK_SIZE / 2;				\
+    return t;								\
+  }
+
+#define SPEED_ROUTINE_MPN_HGCD_CALL(func, itchfunc)			\
+  {									\
+    mp_size_t hgcd_init_itch, hgcd_itch;				\
+    mp_ptr ap, bp, wp, tmp1;						\
+    struct hgcd_matrix hgcd;						\
+    int res;								\
+    unsigned i;								\
+    double t;								\
+    TMP_DECL;								\
+									\
+    if (s->size < 2)							\
+      return -1;							\
+									\
+    TMP_MARK;								\
+									\
+    SPEED_TMP_ALLOC_LIMBS (ap, s->size + 1, s->align_xp);		\
+    SPEED_TMP_ALLOC_LIMBS (bp, s->size + 1, s->align_yp);		\
+									\
+    s->xp[s->size - 1] |= 1;						\
+    s->yp[s->size - 1] |= 1;						\
+									\
+    hgcd_init_itch = MPN_HGCD_MATRIX_INIT_ITCH (s->size);		\
+    hgcd_itch = itchfunc (s->size);					\
+									\
+    SPEED_TMP_ALLOC_LIMBS (tmp1, hgcd_init_itch, s->align_wp);		\
+    SPEED_TMP_ALLOC_LIMBS (wp, hgcd_itch, s->align_wp);			\
+									\
+    speed_operand_src (s, s->xp, s->size);				\
+    speed_operand_src (s, s->yp, s->size);				\
+    speed_operand_dst (s, ap, s->size + 1);				\
+    speed_operand_dst (s, bp, s->size + 1);				\
+    speed_operand_dst (s, wp, hgcd_itch);				\
+    speed_operand_dst (s, tmp1, hgcd_init_itch);			\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      {									\
+	MPN_COPY (ap, s->xp, s->size);					\
+	MPN_COPY (bp, s->yp, s->size);					\
+	mpn_hgcd_matrix_init (&hgcd, s->size, tmp1);			\
+	res = func (ap, bp, s->size, &hgcd, wp);			\
+      }									\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+    TMP_FREE;								\
+    return t;								\
+  }
+
+#define SPEED_ROUTINE_MPN_HGCD_REDUCE_CALL(func, itchfunc)		\
+  {									\
+    mp_size_t hgcd_init_itch, hgcd_step_itch;				\
+    mp_ptr ap, bp, wp, tmp1;						\
+    struct hgcd_matrix hgcd;						\
+    mp_size_t p = s->size/2;						\
+    int res;								\
+    unsigned i;								\
+    double t;								\
+    TMP_DECL;								\
+									\
+    if (s->size < 2)							\
+      return -1;							\
+									\
+    TMP_MARK;								\
+									\
+    SPEED_TMP_ALLOC_LIMBS (ap, s->size + 1, s->align_xp);		\
+    SPEED_TMP_ALLOC_LIMBS (bp, s->size + 1, s->align_yp);		\
+									\
+    s->xp[s->size - 1] |= 1;						\
+    s->yp[s->size - 1] |= 1;						\
+									\
+    hgcd_init_itch = MPN_HGCD_MATRIX_INIT_ITCH (s->size);		\
+    hgcd_step_itch = itchfunc (s->size, p);				\
+									\
+    SPEED_TMP_ALLOC_LIMBS (tmp1, hgcd_init_itch, s->align_wp);		\
+    SPEED_TMP_ALLOC_LIMBS (wp, hgcd_step_itch, s->align_wp);			\
+									\
+    speed_operand_src (s, s->xp, s->size);				\
+    speed_operand_src (s, s->yp, s->size);				\
+    speed_operand_dst (s, ap, s->size + 1);				\
+    speed_operand_dst (s, bp, s->size + 1);				\
+    speed_operand_dst (s, wp, hgcd_step_itch);				\
+    speed_operand_dst (s, tmp1, hgcd_init_itch);			\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      {									\
+	MPN_COPY (ap, s->xp, s->size);					\
+	MPN_COPY (bp, s->yp, s->size);					\
+	mpn_hgcd_matrix_init (&hgcd, s->size, tmp1);			\
+	res = func (&hgcd, ap, bp, s->size, p, wp);			\
+      }									\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+    TMP_FREE;								\
+    return t;								\
+  }
+
+/* Run some GCDs of s->size limbs each.  The number of different data values
+   is decreased as s->size**2, since GCD is a quadratic algorithm.
+   SPEED_ROUTINE_MPN_GCD runs more times than SPEED_ROUTINE_MPN_GCDEXT
+   though, because the plain gcd is about twice as fast as gcdext.  */
+
+#define SPEED_ROUTINE_MPN_GCD_CALL(datafactor, call)			\
+  {									\
+    unsigned  i;							\
+    mp_size_t j, pieces, psize;						\
+    mp_ptr    wp, wp2, xtmp, ytmp, px, py;				\
+    double    t;							\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= 1);					\
+									\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (xtmp, s->size+1, s->align_xp);		\
+    SPEED_TMP_ALLOC_LIMBS (ytmp, s->size+1, s->align_yp);		\
+    SPEED_TMP_ALLOC_LIMBS (wp,   s->size+1, s->align_wp);		\
+    SPEED_TMP_ALLOC_LIMBS (wp2,  s->size+1, s->align_wp2);		\
+									\
+    pieces = SPEED_BLOCK_SIZE * datafactor / s->size / s->size;		\
+    pieces = MIN (pieces, SPEED_BLOCK_SIZE / s->size);			\
+    pieces = MAX (pieces, 1);						\
+									\
+    psize = pieces * s->size;						\
+    px = TMP_ALLOC_LIMBS (psize);					\
+    py = TMP_ALLOC_LIMBS (psize);					\
+    MPN_COPY (px, pieces==1 ? s->xp : s->xp_block, psize);		\
+    MPN_COPY (py, pieces==1 ? s->yp : s->yp_block, psize);		\
+									\
+    /* Requirements: x >= y, y must be odd, high limbs != 0.		\
+       No need to ensure random numbers are really great.  */		\
+    for (j = 0; j < pieces; j++)					\
+      {									\
+	mp_ptr	x = px + j * s->size;					\
+	mp_ptr	y = py + j * s->size;					\
+	if (x[s->size - 1] == 0) x[s->size - 1] = 1;			\
+	if (y[s->size - 1] == 0) y[s->size - 1] = 1;			\
+									\
+	if (x[s->size - 1] < y[s->size - 1])				\
+	  MP_LIMB_T_SWAP (x[s->size - 1], y[s->size - 1]);		\
+	else if (x[s->size - 1] == y[s->size - 1])			\
+	  {								\
+	    x[s->size - 1] = 2;						\
+	    y[s->size - 1] = 1;						\
+	  }								\
+	y[0] |= 1;							\
+      }									\
+									\
+    speed_operand_src (s, px, psize);					\
+    speed_operand_src (s, py, psize);					\
+    speed_operand_dst (s, xtmp, s->size);				\
+    speed_operand_dst (s, ytmp, s->size);				\
+    speed_operand_dst (s, wp, s->size);					\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      {									\
+	j = pieces;							\
+	do								\
+	  {								\
+	    MPN_COPY (xtmp, px+(j - 1)*s->size, s->size);		\
+	    MPN_COPY (ytmp, py+(j - 1)*s->size, s->size);		\
+	    call;							\
+	  }								\
+	while (--j != 0);						\
+      }									\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+									\
+    s->time_divisor = pieces;						\
+    return t;								\
+  }
+
+#define SPEED_ROUTINE_MPN_GCD(function)	\
+  SPEED_ROUTINE_MPN_GCD_CALL (8, function (wp, xtmp, s->size, ytmp, s->size))
+
+#define SPEED_ROUTINE_MPN_GCDEXT(function)				\
+  SPEED_ROUTINE_MPN_GCD_CALL						\
+    (4, { mp_size_t  wp2size;						\
+	  function (wp, wp2, &wp2size, xtmp, s->size, ytmp, s->size); })
+
+
+#define SPEED_ROUTINE_MPN_GCDEXT_ONE(function)				\
+  {									\
+    unsigned  i;							\
+    mp_size_t j, pieces, psize, wp2size;				\
+    mp_ptr    wp, wp2, xtmp, ytmp, px, py;				\
+    double    t;							\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= 1);					\
+									\
+    TMP_MARK;								\
+									\
+    SPEED_TMP_ALLOC_LIMBS (xtmp, s->size+1, s->align_xp);		\
+    SPEED_TMP_ALLOC_LIMBS (ytmp, s->size+1, s->align_yp);		\
+    MPN_COPY (xtmp, s->xp, s->size);					\
+    MPN_COPY (ytmp, s->yp, s->size);					\
+									\
+    SPEED_TMP_ALLOC_LIMBS (wp,	s->size+1, s->align_wp);		\
+    SPEED_TMP_ALLOC_LIMBS (wp2, s->size+1, s->align_wp2);		\
+									\
+    pieces = SPEED_BLOCK_SIZE / 3;					\
+    psize = 3 * pieces;							\
+    px = TMP_ALLOC_LIMBS (psize);					\
+    py = TMP_ALLOC_LIMBS (psize);					\
+    MPN_COPY (px, s->xp_block, psize);					\
+    MPN_COPY (py, s->yp_block, psize);					\
+									\
+    /* x must have at least as many bits as y,				\
+       high limbs must be non-zero */					\
+    for (j = 0; j < pieces; j++)					\
+      {									\
+	mp_ptr	x = px+3*j;						\
+	mp_ptr	y = py+3*j;						\
+	x[2] += (x[2] == 0);						\
+	y[2] += (y[2] == 0);						\
+	if (x[2] < y[2])						\
+	  MP_LIMB_T_SWAP (x[2], y[2]);					\
+      }									\
+									\
+    speed_operand_src (s, px, psize);					\
+    speed_operand_src (s, py, psize);					\
+    speed_operand_dst (s, xtmp, s->size);				\
+    speed_operand_dst (s, ytmp, s->size);				\
+    speed_operand_dst (s, wp, s->size);					\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      {									\
+	mp_ptr	x = px;							\
+	mp_ptr	y = py;							\
+	mp_ptr	xth = &xtmp[s->size-3];					\
+	mp_ptr	yth = &ytmp[s->size-3];					\
+	j = pieces;							\
+	do								\
+	  {								\
+	    xth[0] = x[0], xth[1] = x[1], xth[2] = x[2];		\
+	    yth[0] = y[0], yth[1] = y[1], yth[2] = y[2];		\
+									\
+	    ytmp[0] |= 1; /* y must be odd, */				\
+									\
+	    function (wp, wp2, &wp2size, xtmp, s->size, ytmp, s->size);	\
+									\
+	    x += 3;							\
+	    y += 3;							\
+	  }								\
+	while (--j != 0);						\
+      }									\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+									\
+    s->time_divisor = pieces;						\
+    return t;								\
+  }
+
+/* Calculate nextprime(n) for random n of s->size bits (not limbs). */
+#define SPEED_ROUTINE_MPZ_NEXTPRIME(function)				\
+  {									\
+    unsigned  i, j;							\
+    mpz_t     wp, n;							\
+    double    t;							\
+									\
+    SPEED_RESTRICT_COND (s->size >= 10);				\
+									\
+    mpz_init (wp);							\
+    mpz_init_set_n (n, s->xp, s->size);					\
+    /* limit to s->size bits, as this function is very slow */		\
+    mpz_tdiv_r_2exp (n, n, s->size);					\
+    /* set high bits so operand and result are genaral s->size bits */	\
+    mpz_setbit (n, s->size - 1);					\
+    mpz_clrbit (n, s->size - 2);					\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      {									\
+        /* nextprime timing is variable, so average over many calls */	\
+        j = SPEED_BLOCK_SIZE - 1;					\
+        /* starts on random, after measures prime to next prime */	\
+        function (wp, n);						\
+        do								\
+          {								\
+            function (wp, wp);						\
+          }								\
+        while (--j != 0);						\
+      }									\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    mpz_clear (wp);							\
+    mpz_clear (n);							\
+									\
+    s->time_divisor = SPEED_BLOCK_SIZE;					\
+    return t;								\
+  }
+
+#define SPEED_ROUTINE_MPZ_JACOBI(function)				\
+  {									\
+    mpz_t     a, b;							\
+    unsigned  i;							\
+    mp_size_t j, pieces, psize;						\
+    mp_ptr    px, py;							\
+    double    t;							\
+    TMP_DECL;								\
+									\
+    TMP_MARK;								\
+    pieces = SPEED_BLOCK_SIZE / MAX (s->size, 1);			\
+    pieces = MAX (pieces, 1);						\
+    s->time_divisor = pieces;						\
+									\
+    psize = pieces * s->size;						\
+    px = TMP_ALLOC_LIMBS (psize);					\
+    py = TMP_ALLOC_LIMBS (psize);					\
+    MPN_COPY (px, pieces==1 ? s->xp : s->xp_block, psize);		\
+    MPN_COPY (py, pieces==1 ? s->yp : s->yp_block, psize);		\
+									\
+    for (j = 0; j < pieces; j++)					\
+      {									\
+	mp_ptr	x = px+j*s->size;					\
+	mp_ptr	y = py+j*s->size;					\
+									\
+	/* y odd */							\
+	y[0] |= 1;							\
+									\
+	/* high limbs non-zero */					\
+	if (x[s->size-1] == 0) x[s->size-1] = 1;			\
+	if (y[s->size-1] == 0) y[s->size-1] = 1;			\
+      }									\
+									\
+    SIZ(a) = s->size;							\
+    SIZ(b) = s->size;							\
+									\
+    speed_operand_src (s, px, psize);					\
+    speed_operand_src (s, py, psize);					\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      {									\
+	j = pieces;							\
+	do								\
+	  {								\
+	    PTR(a) = px+(j-1)*s->size;					\
+	    PTR(b) = py+(j-1)*s->size;					\
+	    function (a, b);						\
+	  }								\
+	while (--j != 0);						\
+      }									\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+
+#define SPEED_ROUTINE_MPN_DIVREM_2(function)				\
+  {									\
+    mp_ptr    wp, xp;							\
+    mp_limb_t yp[2];							\
+    unsigned  i;							\
+    double    t;							\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= 2);					\
+									\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (xp, s->size, s->align_xp);			\
+    SPEED_TMP_ALLOC_LIMBS (wp, s->size, s->align_wp);			\
+									\
+    /* source is destroyed */						\
+    MPN_COPY (xp, s->xp, s->size);					\
+									\
+    /* divisor must be normalized */					\
+    MPN_COPY (yp, s->yp_block, 2);					\
+    yp[1] |= GMP_NUMB_HIGHBIT;						\
+									\
+    speed_operand_src (s, xp, s->size);					\
+    speed_operand_src (s, yp, 2);					\
+    speed_operand_dst (s, wp, s->size);					\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      function (wp, 0, xp, s->size, yp);				\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+
+#define SPEED_ROUTINE_MPN_DIV_QR_1(function)				\
+  {									\
+    mp_ptr    wp, xp;							\
+    mp_limb_t d;							\
+    mp_limb_t r;							\
+    unsigned  i;							\
+    double    t;							\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= 1);					\
+									\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (wp, s->size, s->align_wp);			\
+									\
+    d = s->r;								\
+    if (d == 0)								\
+      d = 1;								\
+    speed_operand_src (s, s->xp, s->size);				\
+    speed_operand_dst (s, wp, s->size);					\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      r = function (wp, wp+s->size-1, s->xp, s->size, d);		\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+
+#define SPEED_ROUTINE_MPN_DIV_QR_1N_PI1(function)			\
+  {									\
+    mp_ptr    wp, xp;							\
+    mp_limb_t d, dinv;							\
+    mp_limb_t r;							\
+    unsigned  i;							\
+    double    t;							\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= 1);					\
+									\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (wp, s->size, s->align_wp);			\
+									\
+    d = s->r;								\
+    /* divisor must be normalized */					\
+    SPEED_RESTRICT_COND (d & GMP_NUMB_HIGHBIT);				\
+    invert_limb (dinv, d);						\
+    speed_operand_src (s, s->xp, s->size);				\
+    speed_operand_dst (s, wp, s->size);					\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      r = function (wp, s->xp, s->size, 0, d, dinv);			\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+
+#define SPEED_ROUTINE_MPN_DIV_QR_2(function, norm)			\
+  {									\
+    mp_ptr    wp, xp;							\
+    mp_limb_t yp[2];							\
+    mp_limb_t rp[2];							\
+    unsigned  i;							\
+    double    t;							\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= 2);					\
+									\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (wp, s->size, s->align_wp);			\
+									\
+    /* divisor must be normalized */					\
+    MPN_COPY (yp, s->yp_block, 2);					\
+    if (norm)								\
+      yp[1] |= GMP_NUMB_HIGHBIT;					\
+    else								\
+      {									\
+	yp[1] &= ~GMP_NUMB_HIGHBIT;					\
+	if (yp[1] == 0)							\
+	  yp[1] = 1;							\
+      }									\
+    speed_operand_src (s, s->xp, s->size);				\
+    speed_operand_src (s, yp, 2);					\
+    speed_operand_dst (s, wp, s->size);					\
+    speed_operand_dst (s, rp, 2);					\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      function (wp, rp, s->xp, s->size, yp);				\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+
+#define SPEED_ROUTINE_MODLIMB_INVERT(function)				\
+  {									\
+    unsigned   i, j;							\
+    mp_ptr     xp;							\
+    mp_limb_t  n = 1;							\
+    double     t;							\
+									\
+    xp = s->xp_block-1;							\
+									\
+    speed_operand_src (s, s->xp_block, SPEED_BLOCK_SIZE);		\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      {									\
+	j = SPEED_BLOCK_SIZE;						\
+	do								\
+	  {								\
+	    /* randomized but successively dependent */			\
+	    n += (xp[j] << 1);						\
+									\
+	    function (n, n);						\
+	  }								\
+	while (--j != 0);						\
+      }									\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    /* make sure the compiler won't optimize away n */			\
+    noop_1 (n);								\
+									\
+    s->time_divisor = SPEED_BLOCK_SIZE;					\
+    return t;								\
+  }
+
+
+#define SPEED_ROUTINE_MPN_SQRTROOT_CALL(call)				\
+  {									\
+    mp_ptr    wp, wp2;							\
+    unsigned  i;							\
+    double    t;							\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= 1);					\
+									\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (wp,	s->size, s->align_wp);			\
+    SPEED_TMP_ALLOC_LIMBS (wp2, s->size, s->align_wp2);			\
+									\
+    speed_operand_src (s, s->xp, s->size);				\
+    speed_operand_dst (s, wp, s->size);					\
+    speed_operand_dst (s, wp2, s->size);				\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      call;								\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+
+
+/* Calculate worst case for perfect_power
+   Worst case is multiple prime factors larger than trial div limit. */
+#define SPEED_ROUTINE_MPN_PERFECT_POWER(function)		 	\
+  {									\
+    mpz_t     r;							\
+    unsigned  i, power;							\
+    double    t;							\
+									\
+    SPEED_RESTRICT_COND (s->size >= 10);				\
+									\
+    mpz_init (r);							\
+    power = s->size * GMP_NUMB_BITS / 17;				\
+    mpz_ui_pow_ui(r, (1 << 17) - 1, power - 1);				\
+    mpz_mul_ui(r, r, (1 << 16) + 1);	/* larger than 1000th prime */	\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      function (PTR(r), SIZ(r));					\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    mpz_clear (r);							\
+    return t;								\
+  }
+
+/* Calculate worst case (larger prime) for perfect_square */
+#define SPEED_ROUTINE_MPN_PERFECT_SQUARE(function)			\
+  {									\
+    mpz_t     r;							\
+    unsigned  i;							\
+    double    t;							\
+									\
+    SPEED_RESTRICT_COND (s->size >= 2);					\
+    mpz_init_set_n (r, s->xp, s->size / 2);				\
+    mpz_setbit (r, s->size * GMP_NUMB_BITS / 2 - 1);			\
+    mpz_mul (r, r, r);							\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      function (PTR(r), SIZ(r));					\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    mpz_clear (r);							\
+    return t;								\
+  }
+
+
+/* s->size controls the number of limbs in the input, s->r is the base, or
+   decimal by default. */
+#define SPEED_ROUTINE_MPN_GET_STR(function)				\
+  {									\
+    unsigned char *wp;							\
+    mp_size_t wn;							\
+    mp_ptr xp;								\
+    int base;								\
+    unsigned i;								\
+    double t;								\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= 1);					\
+									\
+    base = s->r == 0 ? 10 : s->r;					\
+    SPEED_RESTRICT_COND (base >= 2 && base <= 256);			\
+									\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (xp, s->size + 1, s->align_xp);		\
+									\
+    MPN_SIZEINBASE (wn, s->xp, s->size, base);				\
+    wp = (unsigned char *) TMP_ALLOC (wn);				\
+									\
+    /* use this during development to guard against overflowing wp */	\
+    /*									\
+    MPN_COPY (xp, s->xp, s->size);					\
+    ASSERT_ALWAYS (mpn_get_str (wp, base, xp, s->size) <= wn);		\
+    */									\
+									\
+    speed_operand_src (s, s->xp, s->size);				\
+    speed_operand_dst (s, xp, s->size);					\
+    speed_operand_dst (s, (mp_ptr) wp, wn/GMP_LIMB_BYTES);		\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      {									\
+	MPN_COPY (xp, s->xp, s->size);					\
+	function (wp, base, xp, s->size);				\
+      }									\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+
+/* s->size controls the number of digits in the input, s->r is the base, or
+   decimal by default. */
+#define SPEED_ROUTINE_MPN_SET_STR_CALL(call)				\
+  {									\
+    unsigned char *xp;							\
+    mp_ptr     wp;							\
+    mp_size_t  wn;							\
+    unsigned   i;							\
+    int        base;							\
+    double     t;							\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= 1);					\
+									\
+    base = s->r == 0 ? 10 : s->r;					\
+    SPEED_RESTRICT_COND (base >= 2 && base <= 256);			\
+									\
+    TMP_MARK;								\
+									\
+    xp = (unsigned char *) TMP_ALLOC (s->size);				\
+    for (i = 0; i < s->size; i++)					\
+      xp[i] = s->xp[i] % base;						\
+									\
+    LIMBS_PER_DIGIT_IN_BASE (wn, s->size, base);			\
+    SPEED_TMP_ALLOC_LIMBS (wp, wn, s->align_wp);			\
+									\
+    /* use this during development to check wn is big enough */		\
+    /*									\
+    ASSERT_ALWAYS (mpn_set_str (wp, xp, s->size, base) <= wn);		\
+    */									\
+									\
+    speed_operand_src (s, (mp_ptr) xp, s->size/GMP_LIMB_BYTES);	\
+    speed_operand_dst (s, wp, wn);					\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      call;								\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+
+
+/* Run an accel gcd find_a() function over various data values.  A set of
+   values is used in case some run particularly fast or slow.  The size
+   parameter is ignored, the amount of data tested is fixed.  */
+
+#define SPEED_ROUTINE_MPN_GCD_FINDA(function)				\
+  {									\
+    unsigned  i, j;							\
+    mp_limb_t cp[SPEED_BLOCK_SIZE][2];					\
+    double    t;							\
+    TMP_DECL;								\
+									\
+    TMP_MARK;								\
+									\
+    /* low must be odd, high must be non-zero */			\
+    for (i = 0; i < SPEED_BLOCK_SIZE; i++)				\
+      {									\
+	cp[i][0] = s->xp_block[i] | 1;					\
+	cp[i][1] = s->yp_block[i] + (s->yp_block[i] == 0);		\
+      }									\
+									\
+    speed_operand_src (s, &cp[0][0], 2*SPEED_BLOCK_SIZE);		\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      {									\
+	j = SPEED_BLOCK_SIZE;						\
+	do								\
+	  {								\
+	    function (cp[j-1]);						\
+	  }								\
+	while (--j != 0);						\
+      }									\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+									\
+    s->time_divisor = SPEED_BLOCK_SIZE;					\
+    return t;								\
+  }
+
+
+/* "call" should do "count_foo_zeros(c,n)".
+   Give leading=1 if foo is leading zeros, leading=0 for trailing.
+   Give zero=1 if n=0 is allowed in the call, zero=0 if not.  */
+
+#define SPEED_ROUTINE_COUNT_ZEROS_A(leading, zero)			\
+  {									\
+    mp_ptr     xp;							\
+    int        i, c;							\
+    unsigned   j;							\
+    mp_limb_t  n;							\
+    double     t;							\
+    TMP_DECL;								\
+									\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (xp, SPEED_BLOCK_SIZE, s->align_xp);		\
+									\
+    if (! speed_routine_count_zeros_setup (s, xp, leading, zero))	\
+      return -1.0;							\
+    speed_operand_src (s, xp, SPEED_BLOCK_SIZE);			\
+    speed_cache_fill (s);						\
+									\
+    c = 0;								\
+    speed_starttime ();							\
+    j = s->reps;							\
+    do {								\
+      for (i = 0; i < SPEED_BLOCK_SIZE; i++)				\
+	{								\
+	  n = xp[i];							\
+	  n ^= c;							\
+
+#define SPEED_ROUTINE_COUNT_ZEROS_B()					\
+	}								\
+    } while (--j != 0);							\
+    t = speed_endtime ();						\
+									\
+    /* don't let c go dead */						\
+    noop_1 (c);								\
+									\
+    s->time_divisor = SPEED_BLOCK_SIZE;					\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }									\
+
+#define SPEED_ROUTINE_COUNT_ZEROS_C(call, leading, zero)		\
+  do {									\
+    SPEED_ROUTINE_COUNT_ZEROS_A (leading, zero);			\
+    call;								\
+    SPEED_ROUTINE_COUNT_ZEROS_B ();					\
+  } while (0)								\
+
+#define SPEED_ROUTINE_COUNT_LEADING_ZEROS_C(call,zero)			\
+  SPEED_ROUTINE_COUNT_ZEROS_C (call, 1, zero)
+#define SPEED_ROUTINE_COUNT_LEADING_ZEROS(fun)				\
+  SPEED_ROUTINE_COUNT_ZEROS_C (fun (c, n), 1, 0)
+
+#define SPEED_ROUTINE_COUNT_TRAILING_ZEROS_C(call,zero)			\
+  SPEED_ROUTINE_COUNT_ZEROS_C (call, 0, zero)
+#define SPEED_ROUTINE_COUNT_TRAILING_ZEROS(call)			\
+  SPEED_ROUTINE_COUNT_ZEROS_C (fun (c, n), 0, 0)
+
+
+#define SPEED_ROUTINE_INVERT_LIMB_CALL(call)				\
+  {									\
+    unsigned   i, j;							\
+    mp_limb_t  d, dinv=0;						\
+    mp_ptr     xp = s->xp_block - 1;					\
+									\
+    s->time_divisor = SPEED_BLOCK_SIZE;					\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      {									\
+	j = SPEED_BLOCK_SIZE;						\
+	do								\
+	  {								\
+	    d = dinv ^ xp[j];						\
+	    d |= GMP_LIMB_HIGHBIT;					\
+	    do { call; } while (0);					\
+	  }								\
+	while (--j != 0);						\
+      }									\
+    while (--i != 0);							\
+									\
+    /* don't let the compiler optimize everything away */		\
+    noop_1 (dinv);							\
+									\
+    return speed_endtime();						\
+  }
+
+
+#define SPEED_ROUTINE_MPN_BACK_TO_BACK(function)			\
+  {									\
+    unsigned  i;							\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      function ();							\
+    while (--i != 0);							\
+    return speed_endtime ();						\
+  }
+
+
+#define SPEED_ROUTINE_MPN_ZERO_CALL(call)				\
+  {									\
+    mp_ptr    wp;							\
+    unsigned  i;							\
+    double    t;							\
+    TMP_DECL;								\
+									\
+    SPEED_RESTRICT_COND (s->size >= 0);					\
+									\
+    TMP_MARK;								\
+    SPEED_TMP_ALLOC_LIMBS (wp, s->size, s->align_wp);			\
+    speed_operand_dst (s, wp, s->size);					\
+    speed_cache_fill (s);						\
+									\
+    speed_starttime ();							\
+    i = s->reps;							\
+    do									\
+      call;								\
+    while (--i != 0);							\
+    t = speed_endtime ();						\
+									\
+    TMP_FREE;								\
+    return t;								\
+  }
+
+#define SPEED_ROUTINE_MPN_ZERO(function)				\
+  SPEED_ROUTINE_MPN_ZERO_CALL (function (wp, s->size))
+
+
+#endif
diff --git a/third_party/gmp/tune/time.c b/third_party/gmp/tune/time.c
new file mode 100644
index 0000000..9060c3d
--- /dev/null
+++ b/third_party/gmp/tune/time.c
@@ -0,0 +1,1596 @@
+/* Time routines for speed measurements.
+
+Copyright 1999-2004, 2010-2012 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+/* Usage:
+
+   The code in this file implements the lowest level of time measuring,
+   simple one-time measuring of time between two points.
+
+   void speed_starttime (void)
+   double speed_endtime (void)
+       Call speed_starttime to start measuring, and then call speed_endtime
+       when done.
+
+       speed_endtime returns the time taken, in seconds.  Or if the timebase
+       is in CPU cycles and the CPU frequency is unknown then speed_endtime
+       returns cycles.  Applications can identify the cycles return by
+       checking for speed_cycletime (described below) equal to 1.0.
+
+       If some sort of temporary glitch occurs then speed_endtime returns
+       0.0.  Currently this is for various cases where a negative time has
+       occurred.  This unfortunately occurs with getrusage on some systems,
+       and with the hppa cycle counter on hpux.
+
+   double speed_cycletime
+       The time in seconds for each CPU cycle.  For example on a 100 MHz CPU
+       this would be 1.0e-8.
+
+       If the CPU frequency is unknown, then speed_cycletime is either 0.0
+       or 1.0.  It's 0.0 when speed_endtime is returning seconds, or it's
+       1.0 when speed_endtime is returning cycles.
+
+       It may be noted that "speed_endtime() / speed_cycletime" gives a
+       measured time in cycles, irrespective of whether speed_endtime is
+       returning cycles or seconds.  (Assuming cycles can be had, ie. it's
+       either cycles already or the cpu frequency is known.  See also
+       speed_cycletime_need_cycles below.)
+
+   double speed_unittime
+       The unit of time measurement accuracy for the timing method in use.
+       This is in seconds or cycles, as per speed_endtime.
+
+   char speed_time_string[]
+       A null-terminated string describing the time method in use.
+
+   void speed_time_init (void)
+       Initialize time measuring.  speed_starttime() does this
+       automatically, so it's only needed if an application wants to inspect
+       the above global variables before making a measurement.
+
+   int speed_precision
+       The intended accuracy of time measurements.  speed_measure() in
+       common.c for instance runs target routines with enough repetitions so
+       it takes at least "speed_unittime * speed_precision" (this expression
+       works for both cycles or seconds from speed_endtime).
+
+       A program can provide an option so the user to set speed_precision.
+       If speed_precision is zero when speed_time_init or speed_starttime
+       first run then it gets a default based on the measuring method
+       chosen.  (More precision for higher accuracy methods.)
+
+   void speed_cycletime_need_seconds (void)
+       Call this to demand that speed_endtime will return seconds, and not
+       cycles.  If only cycles are available then an error is printed and
+       the program exits.
+
+   void speed_cycletime_need_cycles (void)
+       Call this to demand that speed_cycletime is non-zero, so that
+       "speed_endtime() / speed_cycletime" will give times in cycles.
+
+
+
+   Notes:
+
+   Various combinations of cycle counter, read_real_time(), getrusage(),
+   gettimeofday() and times() can arise, according to which are available
+   and their precision.
+
+
+   Allowing speed_endtime() to return either seconds or cycles is only a
+   slight complication and makes it possible for the speed program to do
+   some sensible things without demanding the CPU frequency.  If seconds are
+   being measured then it can always print seconds, and if cycles are being
+   measured then it can always print them without needing to know how long
+   they are.  Also the tune program doesn't care at all what the units are.
+
+   GMP_CPU_FREQUENCY can always be set when the automated methods in freq.c
+   fail.  This will be needed if times in seconds are wanted but a cycle
+   counter is being used, or if times in cycles are wanted but getrusage or
+   another seconds based timer is in use.
+
+   If the measuring method uses a cycle counter but supplements it with
+   getrusage or the like, then knowing the CPU frequency is mandatory since
+   the code compares values from the two.
+
+
+   Not done:
+
+   Solaris gethrtime() seems no more than a slow way to access the Sparc V9
+   cycle counter.  gethrvtime() seems to be relevant only to light weight
+   processes, it doesn't for instance give nanosecond virtual time.  So
+   neither of these are used.
+
+
+   Bugs:
+
+   getrusage_microseconds_p is fundamentally flawed, getrusage and
+   gettimeofday can have resolutions other than clock ticks or microseconds,
+   for instance IRIX 5 has a tick of 10 ms but a getrusage of 1 ms.
+
+
+   Enhancements:
+
+   The SGI hardware counter has 64 bits on some machines, which could be
+   used when available.  But perhaps 32 bits is enough range, and then rely
+   on the getrusage supplement.
+
+   Maybe getrusage (or times) should be used as a supplement for any
+   wall-clock measuring method.  Currently a wall clock with a good range
+   (eg. a 64-bit cycle counter) is used without a supplement.
+
+   On PowerPC the timebase registers could be used, but would have to do
+   something to find out the speed.  On 6xx chips it's normally 1/4 bus
+   speed, on 4xx chips it's either that or an external clock.  Measuring
+   against gettimeofday might be ok.  */
+
+
+#include "config.h"
+
+#include <errno.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h> /* for getenv() */
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>  /* for open() */
+#endif
+
+#if HAVE_STDINT_H
+#include <stdint.h> /* for uint64_t */
+#endif
+
+#if HAVE_UNISTD_H
+#include <unistd.h> /* for sysconf() */
+#endif
+
+#include <sys/types.h>
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>  /* for struct timeval */
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+
+#if HAVE_SYS_MMAN_H
+#include <sys/mman.h>      /* for mmap() */
+#endif
+
+#if HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>  /* for struct rusage */
+#endif
+
+#if HAVE_SYS_SYSSGI_H
+#include <sys/syssgi.h>    /* for syssgi() */
+#endif
+
+#if HAVE_SYS_SYSTEMCFG_H
+#include <sys/systemcfg.h> /* for RTC_POWER on AIX */
+#endif
+
+#if HAVE_SYS_TIMES_H
+#include <sys/times.h>  /* for times() and struct tms */
+#endif
+
+#include "gmp-impl.h"
+
+#include "speed.h"
+
+
+/* strerror is only used for some stuff on newish systems, no need to have a
+   proper replacement */
+#if ! HAVE_STRERROR
+#define strerror(n)  "<strerror not available>"
+#endif
+
+
+char    speed_time_string[256];
+int     speed_precision = 0;
+double  speed_unittime;
+double  speed_cycletime = 0.0;
+
+
+/* don't rely on "unsigned" to "double" conversion, it's broken in SunOS 4
+   native cc */
+#define M_2POWU   (((double) INT_MAX + 1.0) * 2.0)
+
+#define M_2POW32  4294967296.0
+#define M_2POW64  (M_2POW32 * M_2POW32)
+
+
+/* Conditionals for the time functions available are done with normal C
+   code, which is a lot easier than wildly nested preprocessor directives.
+
+   The choice of what to use is partly made at run-time, according to
+   whether the cycle counter works and the measured accuracy of getrusage
+   and gettimeofday.
+
+   A routine that's not available won't be getting called, but is an abort()
+   to be sure it isn't called mistakenly.
+
+   It can be assumed that if a function exists then its data type will, but
+   if the function doesn't then the data type might or might not exist, so
+   the type can't be used unconditionally.  The "struct_rusage" etc macros
+   provide dummies when the respective function doesn't exist. */
+
+
+#if HAVE_SPEED_CYCLECOUNTER
+static const int have_cycles = HAVE_SPEED_CYCLECOUNTER;
+#else
+static const int have_cycles = 0;
+#define speed_cyclecounter(p)  ASSERT_FAIL (speed_cyclecounter not available)
+#endif
+
+/* "stck" returns ticks since 1 Jan 1900 00:00 GMT, where each tick is 2^-12
+   microseconds.  Same #ifdefs here as in longlong.h.  */
+#if defined (__GNUC__) && ! defined (NO_ASM)                            \
+  && (defined (__i370__) || defined (__s390__) || defined (__mvs__))
+static const int  have_stck = 1;
+static const int  use_stck = 1;  /* always use when available */
+typedef uint64_t  stck_t; /* gcc for s390 is quite new, always has uint64_t */
+#define STCK(timestamp)                 \
+  do {                                  \
+    asm ("stck %0" : "=Q" (timestamp)); \
+  } while (0)
+#else
+static const int  have_stck = 0;
+static const int  use_stck = 0;
+typedef unsigned long  stck_t;   /* dummy */
+#define STCK(timestamp)  ASSERT_FAIL (stck instruction not available)
+#endif
+#define STCK_PERIOD      (1.0 / 4096e6)   /* 2^-12 microseconds */
+
+/* mftb
+   Enhancement: On 64-bit chips mftb gives a 64-bit value, no need for mftbu
+   and a loop (see powerpc64.asm).  */
+#if HAVE_HOST_CPU_FAMILY_powerpc
+static const int  have_mftb = 1;
+#if defined (__GNUC__) && ! defined (NO_ASM)
+#define MFTB(a)                         \
+  do {                                  \
+    unsigned  __h1, __l, __h2;          \
+    do {                                \
+      asm volatile ("mftbu %0\n"        \
+		    "mftb  %1\n"        \
+		    "mftbu %2"          \
+		    : "=r" (__h1),      \
+		      "=r" (__l),       \
+		      "=r" (__h2));     \
+    } while (__h1 != __h2);             \
+    a[0] = __l;                         \
+    a[1] = __h1;                        \
+  } while (0)
+#else
+#define MFTB(a)   mftb_function (a)
+#endif
+#else /* ! powerpc */
+static const int  have_mftb = 0;
+#define MFTB(a)                         \
+  do {                                  \
+    a[0] = 0;                           \
+    a[1] = 0;                           \
+    ASSERT_FAIL (mftb not available);   \
+  } while (0)
+#endif
+
+/* Unicos 10.X has syssgi(), but not mmap(). */
+#if HAVE_SYSSGI && HAVE_MMAP
+static const int  have_sgi = 1;
+#else
+static const int  have_sgi = 0;
+#endif
+
+#if HAVE_READ_REAL_TIME
+static const int have_rrt = 1;
+#else
+static const int have_rrt = 0;
+#define read_real_time(t,s)     ASSERT_FAIL (read_real_time not available)
+#define time_base_to_time(t,s)  ASSERT_FAIL (time_base_to_time not available)
+#define RTC_POWER     1
+#define RTC_POWER_PC  2
+#define timebasestruct_t   struct timebasestruct_dummy
+struct timebasestruct_dummy {
+  int             flag;
+  unsigned int    tb_high;
+  unsigned int    tb_low;
+};
+#endif
+
+#if HAVE_CLOCK_GETTIME
+static const int have_cgt = 1;
+#define struct_timespec  struct timespec
+#else
+static const int have_cgt = 0;
+#define struct_timespec       struct timespec_dummy
+#define clock_gettime(id,ts)  (ASSERT_FAIL (clock_gettime not available), -1)
+#define clock_getres(id,ts)   (ASSERT_FAIL (clock_getres not available), -1)
+#endif
+
+#if HAVE_GETRUSAGE
+static const int have_grus = 1;
+#define struct_rusage   struct rusage
+#else
+static const int have_grus = 0;
+#define getrusage(n,ru)  ASSERT_FAIL (getrusage not available)
+#define struct_rusage    struct rusage_dummy
+#endif
+
+#if HAVE_GETTIMEOFDAY
+static const int have_gtod = 1;
+#define struct_timeval   struct timeval
+#else
+static const int have_gtod = 0;
+#define gettimeofday(tv,tz)  ASSERT_FAIL (gettimeofday not available)
+#define struct_timeval   struct timeval_dummy
+#endif
+
+#if HAVE_TIMES
+static const int have_times = 1;
+#define struct_tms   struct tms
+#else
+static const int have_times = 0;
+#define times(tms)   ASSERT_FAIL (times not available)
+#define struct_tms   struct tms_dummy
+#endif
+
+struct tms_dummy {
+  long  tms_utime;
+};
+struct timeval_dummy {
+  long  tv_sec;
+  long  tv_usec;
+};
+struct rusage_dummy {
+  struct_timeval ru_utime;
+};
+struct timespec_dummy {
+  long  tv_sec;
+  long  tv_nsec;
+};
+
+static int  use_cycles;
+static int  use_mftb;
+static int  use_sgi;
+static int  use_rrt;
+static int  use_cgt;
+static int  use_gtod;
+static int  use_grus;
+static int  use_times;
+static int  use_tick_boundary;
+
+static unsigned         start_cycles[2];
+static stck_t           start_stck;
+static unsigned         start_mftb[2];
+static unsigned         start_sgi;
+static timebasestruct_t start_rrt;
+static struct_timespec  start_cgt;
+static struct_rusage    start_grus;
+static struct_timeval   start_gtod;
+static struct_tms       start_times;
+
+static double  cycles_limit = 1e100;
+static double  mftb_unittime;
+static double  sgi_unittime;
+static double  cgt_unittime;
+static double  grus_unittime;
+static double  gtod_unittime;
+static double  times_unittime;
+
+/* for RTC_POWER format, ie. seconds and nanoseconds */
+#define TIMEBASESTRUCT_SECS(t)  ((t)->tb_high + (t)->tb_low * 1e-9)
+
+
+/* Return a string representing a time in seconds, nicely formatted.
+   Eg. "10.25ms".  */
+char *
+unittime_string (double t)
+{
+  static char  buf[128];
+
+  const char  *unit;
+  int         prec;
+
+  /* choose units and scale */
+  if (t < 1e-6)
+    t *= 1e9, unit = "ns";
+  else if (t < 1e-3)
+    t *= 1e6, unit = "us";
+  else if (t < 1.0)
+    t *= 1e3, unit = "ms";
+  else
+    unit = "s";
+
+  /* want 4 significant figures */
+  if (t < 1.0)
+    prec = 4;
+  else if (t < 10.0)
+    prec = 3;
+  else if (t < 100.0)
+    prec = 2;
+  else
+    prec = 1;
+
+  sprintf (buf, "%.*f%s", prec, t, unit);
+  return buf;
+}
+
+
+static jmp_buf  cycles_works_buf;
+
+static RETSIGTYPE
+cycles_works_handler (int sig)
+{
+  longjmp (cycles_works_buf, 1);
+}
+
+int
+cycles_works_p (void)
+{
+  static int  result = -1;
+
+  if (result != -1)
+    goto done;
+
+  /* FIXME: On linux, the cycle counter is not saved and restored over
+   * context switches, making it almost useless for precise cputime
+   * measurements. When available, it's better to use clock_gettime,
+   * which seems to have reasonable accuracy (tested on x86_32,
+   * linux-2.6.26, glibc-2.7). However, there are also some linux
+   * systems where clock_gettime is broken in one way or the other,
+   * like CLOCK_PROCESS_CPUTIME_ID not implemented (easy case) or
+   * kind-of implemented but broken (needs code to detect that), and
+   * on those systems a wall-clock cycle counter is the least bad
+   * fallback.
+   *
+   * So we need some code to disable the cycle counter on some but not
+   * all linux systems. */
+#ifdef SIGILL
+  {
+    RETSIGTYPE (*old_handler) (int);
+    unsigned  cycles[2];
+
+    old_handler = signal (SIGILL, cycles_works_handler);
+    if (old_handler == SIG_ERR)
+      {
+	if (speed_option_verbose)
+	  printf ("cycles_works_p(): SIGILL not supported, assuming speed_cyclecounter() works\n");
+	goto yes;
+      }
+    if (setjmp (cycles_works_buf))
+      {
+	if (speed_option_verbose)
+	  printf ("cycles_works_p(): SIGILL during speed_cyclecounter(), so doesn't work\n");
+	result = 0;
+	goto done;
+      }
+    speed_cyclecounter (cycles);
+    signal (SIGILL, old_handler);
+    if (speed_option_verbose)
+      printf ("cycles_works_p(): speed_cyclecounter() works\n");
+  }
+#else
+
+  if (speed_option_verbose)
+    printf ("cycles_works_p(): SIGILL not defined, assuming speed_cyclecounter() works\n");
+  goto yes;
+#endif
+
+ yes:
+  result = 1;
+
+ done:
+  return result;
+}
+
+
+/* The number of clock ticks per second, but looking at sysconf rather than
+   just CLK_TCK, where possible.  */
+long
+clk_tck (void)
+{
+  static long  result = -1L;
+  if (result != -1L)
+    return result;
+
+#if HAVE_SYSCONF
+  result = sysconf (_SC_CLK_TCK);
+  if (result != -1L)
+    {
+      if (speed_option_verbose)
+	printf ("sysconf(_SC_CLK_TCK) is %ld per second\n", result);
+      return result;
+    }
+
+  fprintf (stderr,
+	   "sysconf(_SC_CLK_TCK) not working, using CLK_TCK instead\n");
+#endif
+
+#ifdef CLK_TCK
+  result = CLK_TCK;
+  if (speed_option_verbose)
+    printf ("CLK_TCK is %ld per second\n", result);
+  return result;
+#else
+  fprintf (stderr, "CLK_TCK not defined, cannot continue\n");
+  abort ();
+#endif
+}
+
+
+/* If two times can be observed less than half a clock tick apart, then
+   assume "get" is microsecond accurate.
+
+   Two times only 1 microsecond apart are not believed, since some kernels
+   take it upon themselves to ensure gettimeofday doesn't return the same
+   value twice, for the benefit of applications using it for a timestamp.
+   This is obviously very stupid given the speed of CPUs these days.
+
+   Making "reps" many calls to noop_1() is designed to waste some CPU, with
+   a view to getting measurements 2 microseconds (or more) apart.  "reps" is
+   increased progressively until such a period is seen.
+
+   The outer loop "attempts" are just to allow for any random nonsense or
+   system load upsetting the measurements (ie. making two successive calls
+   to "get" come out as a longer interval than normal).
+
+   Bugs:
+
+   The assumption that any interval less than a half tick implies
+   microsecond resolution is obviously fairly rash, the true resolution
+   could be anything between a microsecond and that half tick.  Perhaps
+   something special would have to be done on a system where this is the
+   case, since there's no obvious reliable way to detect it
+   automatically.  */
+
+#define MICROSECONDS_P(name, type, get, sec, usec)                      \
+  {                                                                     \
+    static int  result = -1;                                            \
+    type      st, et;                                                   \
+    long      dt, half_tick;                                            \
+    unsigned  attempt, reps, i, j;                                      \
+									\
+    if (result != -1)                                                   \
+      return result;                                                    \
+									\
+    result = 0;                                                         \
+    half_tick = (1000000L / clk_tck ()) / 2;                            \
+									\
+    for (attempt = 0; attempt < 5; attempt++)                           \
+      {                                                                 \
+	reps = 0;                                                       \
+	for (;;)                                                        \
+	  {                                                             \
+	    get (st);                                                   \
+	    for (i = 0; i < reps; i++)                                  \
+	      for (j = 0; j < 100; j++)                                 \
+		noop_1 (CNST_LIMB(0));                                  \
+	    get (et);                                                   \
+									\
+	    dt = (sec(et)-sec(st))*1000000L + usec(et)-usec(st);        \
+									\
+	    if (speed_option_verbose >= 2)                              \
+	      printf ("%s attempt=%u, reps=%u, dt=%ld\n",               \
+		      name, attempt, reps, dt);                         \
+									\
+	    if (dt >= 2)                                                \
+	      break;                                                    \
+									\
+	    reps = (reps == 0 ? 1 : 2*reps);                            \
+	    if (reps == 0)                                              \
+	      break;  /* uint overflow, not normal */                   \
+	  }                                                             \
+									\
+	if (dt < half_tick)                                             \
+	  {                                                             \
+	    result = 1;                                                 \
+	    break;                                                      \
+	  }                                                             \
+      }                                                                 \
+									\
+    if (speed_option_verbose)                                           \
+      {                                                                 \
+	if (result)                                                     \
+	  printf ("%s is microsecond accurate\n", name);                \
+	else                                                            \
+	  printf ("%s is only %s clock tick accurate\n",                \
+		  name, unittime_string (1.0/clk_tck()));               \
+      }                                                                 \
+    return result;                                                      \
+  }
+
+
+int
+gettimeofday_microseconds_p (void)
+{
+#define call_gettimeofday(t)   gettimeofday (&(t), NULL)
+#define timeval_tv_sec(t)      ((t).tv_sec)
+#define timeval_tv_usec(t)     ((t).tv_usec)
+  MICROSECONDS_P ("gettimeofday", struct_timeval,
+		  call_gettimeofday, timeval_tv_sec, timeval_tv_usec);
+}
+
+int
+getrusage_microseconds_p (void)
+{
+#define call_getrusage(t)   getrusage (0, &(t))
+#define rusage_tv_sec(t)    ((t).ru_utime.tv_sec)
+#define rusage_tv_usec(t)   ((t).ru_utime.tv_usec)
+  MICROSECONDS_P ("getrusage", struct_rusage,
+		  call_getrusage, rusage_tv_sec, rusage_tv_usec);
+}
+
+/* Test whether getrusage goes backwards, return non-zero if it does
+   (suggesting it's flawed).
+
+   On a macintosh m68040-unknown-netbsd1.4.1 getrusage looks like it's
+   microsecond accurate, but has been seen remaining unchanged after many
+   microseconds have elapsed.  It also regularly goes backwards by 1000 to
+   5000 usecs, this has been seen after between 500 and 4000 attempts taking
+   perhaps 0.03 seconds.  We consider this too broken for good measuring.
+   We used to have configure pretend getrusage didn't exist on this system,
+   but a runtime test should be more reliable, since we imagine the problem
+   is not confined to just this exact system tuple.  */
+
+int
+getrusage_backwards_p (void)
+{
+  static int result = -1;
+  struct rusage  start, prev, next;
+  long  d;
+  int   i;
+
+  if (result != -1)
+    return result;
+
+  getrusage (0, &start);
+  memcpy (&next, &start, sizeof (next));
+
+  result = 0;
+  i = 0;
+  for (;;)
+    {
+      memcpy (&prev, &next, sizeof (prev));
+      getrusage (0, &next);
+
+      if (next.ru_utime.tv_sec < prev.ru_utime.tv_sec
+	  || (next.ru_utime.tv_sec == prev.ru_utime.tv_sec
+	      && next.ru_utime.tv_usec < prev.ru_utime.tv_usec))
+	{
+	  if (speed_option_verbose)
+	    printf ("getrusage went backwards (attempt %d: %ld.%06ld -> %ld.%06ld)\n",
+		    i,
+		    (long) prev.ru_utime.tv_sec, (long) prev.ru_utime.tv_usec,
+		    (long) next.ru_utime.tv_sec, (long) next.ru_utime.tv_usec);
+	  result = 1;
+	  break;
+	}
+
+      /* minimum 1000 attempts, then stop after either 0.1 seconds or 50000
+	 attempts, whichever comes first */
+      d = 1000000 * (next.ru_utime.tv_sec - start.ru_utime.tv_sec)
+	+ (next.ru_utime.tv_usec - start.ru_utime.tv_usec);
+      i++;
+      if (i > 50000 || (i > 1000 && d > 100000))
+	break;
+    }
+
+  return result;
+}
+
+/* CLOCK_PROCESS_CPUTIME_ID looks like it's going to be in a future version
+   of glibc (some time post 2.2).
+
+   CLOCK_VIRTUAL is process time, available in BSD systems (though sometimes
+   defined, but returning -1 for an error).  */
+
+#ifdef CLOCK_PROCESS_CPUTIME_ID
+# define CGT_ID        CLOCK_PROCESS_CPUTIME_ID
+#else
+# ifdef CLOCK_VIRTUAL
+#  define CGT_ID       CLOCK_VIRTUAL
+# endif
+#endif
+#ifdef CGT_ID
+const int  have_cgt_id = 1;
+#else
+const int  have_cgt_id = 0;
+# define CGT_ID       (ASSERT_FAIL (CGT_ID not determined), -1)
+#endif
+
+#define CGT_DELAY_COUNT 1000
+
+int
+cgt_works_p (void)
+{
+  static int  result = -1;
+  struct_timespec  unit;
+
+  if (! have_cgt)
+    return 0;
+
+  if (! have_cgt_id)
+    {
+      if (speed_option_verbose)
+	printf ("clock_gettime don't know what ID to use\n");
+      result = 0;
+      return result;
+    }
+
+  if (result != -1)
+    return result;
+
+  /* trial run to see if it works */
+  if (clock_gettime (CGT_ID, &unit) != 0)
+    {
+      if (speed_option_verbose)
+	printf ("clock_gettime id=%d error: %s\n", CGT_ID, strerror (errno));
+      result = 0;
+      return result;
+    }
+
+  /* get the resolution */
+  if (clock_getres (CGT_ID, &unit) != 0)
+    {
+      if (speed_option_verbose)
+	printf ("clock_getres id=%d error: %s\n", CGT_ID, strerror (errno));
+      result = 0;
+      return result;
+    }
+
+  cgt_unittime = unit.tv_sec + unit.tv_nsec * 1e-9;
+  if (speed_option_verbose)
+    printf ("clock_gettime is %s accurate\n", unittime_string (cgt_unittime));
+
+  if (cgt_unittime < 10e-9)
+    {
+      /* Do we believe this? */
+      struct timespec start, end;
+      static volatile int counter;
+      double duration;
+      if (clock_gettime (CGT_ID, &start))
+	{
+	  if (speed_option_verbose)
+	    printf ("clock_gettime id=%d error: %s\n", CGT_ID, strerror (errno));
+	  result = 0;
+	  return result;
+	}
+      /* Loop of at least 1000 memory accesses, ought to take at
+	 least 100 ns*/
+      for (counter = 0; counter < CGT_DELAY_COUNT; counter++)
+	;
+      if (clock_gettime (CGT_ID, &end))
+	{
+	  if (speed_option_verbose)
+	    printf ("clock_gettime id=%d error: %s\n", CGT_ID, strerror (errno));
+	  result = 0;
+	  return result;
+	}
+      duration = (end.tv_sec + end.tv_nsec * 1e-9
+		  - start.tv_sec - start.tv_nsec * 1e-9);
+      if (speed_option_verbose)
+	printf ("delay loop of %d rounds took %s (according to clock_gettime)\n",
+		CGT_DELAY_COUNT, unittime_string (duration));
+      if (duration < 100e-9)
+	{
+	  if (speed_option_verbose)
+	    printf ("clock_gettime id=%d not believable\n", CGT_ID);
+	  result = 0;
+	  return result;
+	}
+    }
+  result = 1;
+  return result;
+}
+
+
+static double
+freq_measure_mftb_one (void)
+{
+#define call_gettimeofday(t)   gettimeofday (&(t), NULL)
+#define timeval_tv_sec(t)      ((t).tv_sec)
+#define timeval_tv_usec(t)     ((t).tv_usec)
+  FREQ_MEASURE_ONE ("mftb", struct_timeval,
+		    call_gettimeofday, MFTB,
+		    timeval_tv_sec, timeval_tv_usec);
+}
+
+
+static jmp_buf  mftb_works_buf;
+
+static RETSIGTYPE
+mftb_works_handler (int sig)
+{
+  longjmp (mftb_works_buf, 1);
+}
+
+int
+mftb_works_p (void)
+{
+  unsigned   a[2];
+  RETSIGTYPE (*old_handler) (int);
+  double     cycletime;
+
+  /* suppress a warning about a[] unused */
+  a[0] = 0;
+
+  if (! have_mftb)
+    return 0;
+
+#ifdef SIGILL
+  old_handler = signal (SIGILL, mftb_works_handler);
+  if (old_handler == SIG_ERR)
+    {
+      if (speed_option_verbose)
+	printf ("mftb_works_p(): SIGILL not supported, assuming mftb works\n");
+      return 1;
+    }
+  if (setjmp (mftb_works_buf))
+    {
+      if (speed_option_verbose)
+	printf ("mftb_works_p(): SIGILL during mftb, so doesn't work\n");
+      return 0;
+    }
+  MFTB (a);
+  signal (SIGILL, old_handler);
+  if (speed_option_verbose)
+    printf ("mftb_works_p(): mftb works\n");
+#else
+
+  if (speed_option_verbose)
+    printf ("mftb_works_p(): SIGILL not defined, assuming mftb works\n");
+#endif
+
+#if ! HAVE_GETTIMEOFDAY
+  if (speed_option_verbose)
+    printf ("mftb_works_p(): no gettimeofday available to measure mftb\n");
+  return 0;
+#endif
+
+  /* The time base is normally 1/4 of the bus speed on 6xx and 7xx chips, on
+     other chips it can be driven from an external clock. */
+  cycletime = freq_measure ("mftb", freq_measure_mftb_one);
+  if (cycletime == -1.0)
+    {
+      if (speed_option_verbose)
+	printf ("mftb_works_p(): cannot measure mftb period\n");
+      return 0;
+    }
+
+  mftb_unittime = cycletime;
+  return 1;
+}
+
+
+volatile unsigned  *sgi_addr;
+
+int
+sgi_works_p (void)
+{
+#if HAVE_SYSSGI && HAVE_MMAP
+  static int  result = -1;
+
+  size_t          pagesize, offset;
+  __psunsigned_t  phys, physpage;
+  void            *virtpage;
+  unsigned        period_picoseconds;
+  int             size, fd;
+
+  if (result != -1)
+    return result;
+
+  phys = syssgi (SGI_QUERY_CYCLECNTR, &period_picoseconds);
+  if (phys == (__psunsigned_t) -1)
+    {
+      /* ENODEV is the error when a counter is not available */
+      if (speed_option_verbose)
+	printf ("syssgi SGI_QUERY_CYCLECNTR error: %s\n", strerror (errno));
+      result = 0;
+      return result;
+    }
+  sgi_unittime = period_picoseconds * 1e-12;
+
+  /* IRIX 5 doesn't have SGI_CYCLECNTR_SIZE, assume 32 bits in that case.
+     Challenge/ONYX hardware has a 64 bit byte counter, but there seems no
+     obvious way to identify that without SGI_CYCLECNTR_SIZE.  */
+#ifdef SGI_CYCLECNTR_SIZE
+  size = syssgi (SGI_CYCLECNTR_SIZE);
+  if (size == -1)
+    {
+      if (speed_option_verbose)
+	{
+	  printf ("syssgi SGI_CYCLECNTR_SIZE error: %s\n", strerror (errno));
+	  printf ("    will assume size==4\n");
+	}
+      size = 32;
+    }
+#else
+  size = 32;
+#endif
+
+  if (size < 32)
+    {
+      printf ("syssgi SGI_CYCLECNTR_SIZE gives %d, expected 32 or 64\n", size);
+      result = 0;
+      return result;
+    }
+
+  pagesize = getpagesize();
+  offset = (size_t) phys & (pagesize-1);
+  physpage = phys - offset;
+
+  /* shouldn't cross over a page boundary */
+  ASSERT_ALWAYS (offset + size/8 <= pagesize);
+
+  fd = open("/dev/mmem", O_RDONLY);
+  if (fd == -1)
+    {
+      if (speed_option_verbose)
+	printf ("open /dev/mmem: %s\n", strerror (errno));
+      result = 0;
+      return result;
+    }
+
+  virtpage = mmap (0, pagesize, PROT_READ, MAP_PRIVATE, fd, (off_t) physpage);
+  if (virtpage == (void *) -1)
+    {
+      if (speed_option_verbose)
+	printf ("mmap /dev/mmem: %s\n", strerror (errno));
+      result = 0;
+      return result;
+    }
+
+  /* address of least significant 4 bytes, knowing mips is big endian */
+  sgi_addr = (unsigned *) ((char *) virtpage + offset
+			   + size/8 - sizeof(unsigned));
+  result = 1;
+  return result;
+
+#else /* ! (HAVE_SYSSGI && HAVE_MMAP) */
+  return 0;
+#endif
+}
+
+
+#define DEFAULT(var,n)  \
+  do {                  \
+    if (! (var))        \
+      (var) = (n);      \
+  } while (0)
+
+void
+speed_time_init (void)
+{
+  double supplement_unittime = 0.0;
+
+  static int  speed_time_initialized = 0;
+  if (speed_time_initialized)
+    return;
+  speed_time_initialized = 1;
+
+  speed_cycletime_init ();
+
+  if (!speed_option_cycles_broken && have_cycles && cycles_works_p ())
+    {
+      use_cycles = 1;
+      DEFAULT (speed_cycletime, 1.0);
+      speed_unittime = speed_cycletime;
+      DEFAULT (speed_precision, 10000);
+      strcpy (speed_time_string, "CPU cycle counter");
+
+      /* only used if a supplementary method is chosen below */
+      cycles_limit = (have_cycles == 1 ? M_2POW32 : M_2POW64) / 2.0
+	* speed_cycletime;
+
+      if (have_grus && getrusage_microseconds_p() && ! getrusage_backwards_p())
+	{
+	  /* this is a good combination */
+	  use_grus = 1;
+	  supplement_unittime = grus_unittime = 1.0e-6;
+	  strcpy (speed_time_string, "CPU cycle counter, supplemented by microsecond getrusage()");
+	}
+      else if (have_cycles == 1)
+	{
+	  /* When speed_cyclecounter has a limited range, look for something
+	     to supplement it. */
+	  if (have_gtod && gettimeofday_microseconds_p())
+	    {
+	      use_gtod = 1;
+	      supplement_unittime = gtod_unittime = 1.0e-6;
+	      strcpy (speed_time_string, "CPU cycle counter, supplemented by microsecond gettimeofday()");
+	    }
+	  else if (have_grus)
+	    {
+	      use_grus = 1;
+	      supplement_unittime = grus_unittime = 1.0 / (double) clk_tck ();
+	      sprintf (speed_time_string, "CPU cycle counter, supplemented by %s clock tick getrusage()", unittime_string (supplement_unittime));
+	    }
+	  else if (have_times)
+	    {
+	      use_times = 1;
+	      supplement_unittime = times_unittime = 1.0 / (double) clk_tck ();
+	      sprintf (speed_time_string, "CPU cycle counter, supplemented by %s clock tick times()", unittime_string (supplement_unittime));
+	    }
+	  else if (have_gtod)
+	    {
+	      use_gtod = 1;
+	      supplement_unittime = gtod_unittime = 1.0 / (double) clk_tck ();
+	      sprintf (speed_time_string, "CPU cycle counter, supplemented by %s clock tick gettimeofday()", unittime_string (supplement_unittime));
+	    }
+	  else
+	    {
+	      fprintf (stderr, "WARNING: cycle counter is 32 bits and there's no other functions.\n");
+	      fprintf (stderr, "    Wraparounds may produce bad results on long measurements.\n");
+	    }
+	}
+
+      if (use_grus || use_times || use_gtod)
+	{
+	  /* must know cycle period to compare cycles to other measuring
+	     (via cycles_limit) */
+	  speed_cycletime_need_seconds ();
+
+	  if (speed_precision * supplement_unittime > cycles_limit)
+	    {
+	      fprintf (stderr, "WARNING: requested precision can't always be achieved due to limited range\n");
+	      fprintf (stderr, "    cycle counter and limited precision supplemental method\n");
+	      fprintf (stderr, "    (%s)\n", speed_time_string);
+	    }
+	}
+    }
+  else if (have_stck)
+    {
+      strcpy (speed_time_string, "STCK timestamp");
+      /* stck is in units of 2^-12 microseconds, which is very likely higher
+	 resolution than a cpu cycle */
+      if (speed_cycletime == 0.0)
+	speed_cycletime_fail
+	  ("Need to know CPU frequency for effective stck unit");
+      speed_unittime = MAX (speed_cycletime, STCK_PERIOD);
+      DEFAULT (speed_precision, 10000);
+    }
+  else if (have_mftb && mftb_works_p ())
+    {
+      use_mftb = 1;
+      DEFAULT (speed_precision, 10000);
+      speed_unittime = mftb_unittime;
+      sprintf (speed_time_string, "mftb counter (%s)",
+	       unittime_string (speed_unittime));
+    }
+  else if (have_sgi && sgi_works_p ())
+    {
+      use_sgi = 1;
+      DEFAULT (speed_precision, 10000);
+      speed_unittime = sgi_unittime;
+      sprintf (speed_time_string, "syssgi() mmap counter (%s), supplemented by millisecond getrusage()",
+	       unittime_string (speed_unittime));
+      /* supplemented with getrusage, which we assume to have 1ms resolution */
+      use_grus = 1;
+      supplement_unittime = 1e-3;
+    }
+  else if (have_rrt)
+    {
+      timebasestruct_t  t;
+      use_rrt = 1;
+      DEFAULT (speed_precision, 10000);
+      read_real_time (&t, sizeof(t));
+      switch (t.flag) {
+      case RTC_POWER:
+	/* FIXME: What's the actual RTC resolution? */
+	speed_unittime = 1e-7;
+	strcpy (speed_time_string, "read_real_time() power nanoseconds");
+	break;
+      case RTC_POWER_PC:
+	t.tb_high = 1;
+	t.tb_low = 0;
+	time_base_to_time (&t, sizeof(t));
+	speed_unittime = TIMEBASESTRUCT_SECS(&t) / M_2POW32;
+	sprintf (speed_time_string, "%s read_real_time() powerpc ticks",
+		 unittime_string (speed_unittime));
+	break;
+      default:
+	fprintf (stderr, "ERROR: Unrecognised timebasestruct_t flag=%d\n",
+		 t.flag);
+	abort ();
+      }
+    }
+  else if (have_cgt && cgt_works_p() && cgt_unittime < 1.5e-6)
+    {
+      /* use clock_gettime if microsecond or better resolution */
+    choose_cgt:
+      use_cgt = 1;
+      speed_unittime = cgt_unittime;
+      DEFAULT (speed_precision, (cgt_unittime <= 0.1e-6 ? 10000 : 1000));
+      strcpy (speed_time_string, "microsecond accurate clock_gettime()");
+    }
+  else if (have_times && clk_tck() > 1000000)
+    {
+      /* Cray vector systems have times() which is clock cycle resolution
+	 (eg. 450 MHz).  */
+      DEFAULT (speed_precision, 10000);
+      goto choose_times;
+    }
+  else if (have_grus && getrusage_microseconds_p() && ! getrusage_backwards_p())
+    {
+      use_grus = 1;
+      speed_unittime = grus_unittime = 1.0e-6;
+      DEFAULT (speed_precision, 1000);
+      strcpy (speed_time_string, "microsecond accurate getrusage()");
+    }
+  else if (have_gtod && gettimeofday_microseconds_p())
+    {
+      use_gtod = 1;
+      speed_unittime = gtod_unittime = 1.0e-6;
+      DEFAULT (speed_precision, 1000);
+      strcpy (speed_time_string, "microsecond accurate gettimeofday()");
+    }
+  else if (have_cgt && cgt_works_p() && cgt_unittime < 1.5/clk_tck())
+    {
+      /* use clock_gettime if 1 tick or better resolution */
+      goto choose_cgt;
+    }
+  else if (have_times)
+    {
+      use_tick_boundary = 1;
+      DEFAULT (speed_precision, 200);
+    choose_times:
+      use_times = 1;
+      speed_unittime = times_unittime = 1.0 / (double) clk_tck ();
+      sprintf (speed_time_string, "%s clock tick times()",
+	       unittime_string (speed_unittime));
+    }
+  else if (have_grus)
+    {
+      use_grus = 1;
+      use_tick_boundary = 1;
+      speed_unittime = grus_unittime = 1.0 / (double) clk_tck ();
+      DEFAULT (speed_precision, 200);
+      sprintf (speed_time_string, "%s clock tick getrusage()\n",
+	       unittime_string (speed_unittime));
+    }
+  else if (have_gtod)
+    {
+      use_gtod = 1;
+      use_tick_boundary = 1;
+      speed_unittime = gtod_unittime = 1.0 / (double) clk_tck ();
+      DEFAULT (speed_precision, 200);
+      sprintf (speed_time_string, "%s clock tick gettimeofday()",
+	       unittime_string (speed_unittime));
+    }
+  else
+    {
+      fprintf (stderr, "No time measuring method available\n");
+      fprintf (stderr, "None of: speed_cyclecounter(), STCK(), getrusage(), gettimeofday(), times()\n");
+      abort ();
+    }
+
+  if (speed_option_verbose)
+    {
+      printf ("speed_time_init: %s\n", speed_time_string);
+      printf ("    speed_precision     %d\n", speed_precision);
+      printf ("    speed_unittime      %.2g\n", speed_unittime);
+      if (supplement_unittime)
+	printf ("    supplement_unittime %.2g\n", supplement_unittime);
+      printf ("    use_tick_boundary   %d\n", use_tick_boundary);
+      if (have_cycles)
+	printf ("    cycles_limit        %.2g seconds\n", cycles_limit);
+    }
+}
+
+
+
+/* Burn up CPU until a clock tick boundary, for greater accuracy.  Set the
+   corresponding "start_foo" appropriately too. */
+
+void
+grus_tick_boundary (void)
+{
+  struct_rusage  prev;
+  getrusage (0, &prev);
+  do {
+    getrusage (0, &start_grus);
+  } while (start_grus.ru_utime.tv_usec == prev.ru_utime.tv_usec);
+}
+
+void
+gtod_tick_boundary (void)
+{
+  struct_timeval  prev;
+  gettimeofday (&prev, NULL);
+  do {
+    gettimeofday (&start_gtod, NULL);
+  } while (start_gtod.tv_usec == prev.tv_usec);
+}
+
+void
+times_tick_boundary (void)
+{
+  struct_tms  prev;
+  times (&prev);
+  do
+    times (&start_times);
+  while (start_times.tms_utime == prev.tms_utime);
+}
+
+
+/* "have_" values are tested to let unused code go dead.  */
+
+void
+speed_starttime (void)
+{
+  speed_time_init ();
+
+  if (have_grus && use_grus)
+    {
+      if (use_tick_boundary)
+	grus_tick_boundary ();
+      else
+	getrusage (0, &start_grus);
+    }
+
+  if (have_gtod && use_gtod)
+    {
+      if (use_tick_boundary)
+	gtod_tick_boundary ();
+      else
+	gettimeofday (&start_gtod, NULL);
+    }
+
+  if (have_times && use_times)
+    {
+      if (use_tick_boundary)
+	times_tick_boundary ();
+      else
+	times (&start_times);
+    }
+
+  if (have_cgt && use_cgt)
+    clock_gettime (CGT_ID, &start_cgt);
+
+  if (have_rrt && use_rrt)
+    read_real_time (&start_rrt, sizeof(start_rrt));
+
+  if (have_sgi && use_sgi)
+    start_sgi = *sgi_addr;
+
+  if (have_mftb && use_mftb)
+    MFTB (start_mftb);
+
+  if (have_stck && use_stck)
+    STCK (start_stck);
+
+  /* Cycles sampled last for maximum accuracy. */
+  if (have_cycles && use_cycles)
+    speed_cyclecounter (start_cycles);
+}
+
+
+/* Calculate the difference between two cycle counter samples, as a "double"
+   counter of cycles.
+
+   The start and end values are allowed to cancel in integers in case the
+   counter values are bigger than the 53 bits that normally fit in a double.
+
+   This works even if speed_cyclecounter() puts a value bigger than 32-bits
+   in the low word (the high word always gets a 2**32 multiplier though). */
+
+double
+speed_cyclecounter_diff (const unsigned end[2], const unsigned start[2])
+{
+  unsigned  d;
+  double    t;
+
+  if (have_cycles == 1)
+    {
+      t = (end[0] - start[0]);
+    }
+  else
+    {
+      d = end[0] - start[0];
+      t = d - (d > end[0] ? M_2POWU : 0.0);
+      t += (end[1] - start[1]) * M_2POW32;
+    }
+  return t;
+}
+
+
+double
+speed_mftb_diff (const unsigned end[2], const unsigned start[2])
+{
+  unsigned  d;
+  double    t;
+
+  d = end[0] - start[0];
+  t = (double) d - (d > end[0] ? M_2POW32 : 0.0);
+  t += (end[1] - start[1]) * M_2POW32;
+  return t;
+}
+
+
+/* Calculate the difference between "start" and "end" using fields "sec" and
+   "psec", where each "psec" is a "punit" of a second.
+
+   The seconds parts are allowed to cancel before being combined with the
+   psec parts, in case a simple "sec+psec*punit" exceeds the precision of a
+   double.
+
+   Total time is only calculated in a "double" since an integer count of
+   psecs might overflow.  2^32 microseconds is only a bit over an hour, or
+   2^32 nanoseconds only about 4 seconds.
+
+   The casts to "long" are for the benefit of timebasestruct_t, where the
+   fields are only "unsigned int", but we want a signed difference.  */
+
+#define DIFF_SECS_ROUTINE(sec, psec, punit)                     \
+  {                                                             \
+    long  sec_diff, psec_diff;                                  \
+    sec_diff = (long) end->sec - (long) start->sec;             \
+    psec_diff = (long) end->psec - (long) start->psec;          \
+    return (double) sec_diff + punit * (double) psec_diff;      \
+  }
+
+double
+timeval_diff_secs (const struct_timeval *end, const struct_timeval *start)
+{
+  DIFF_SECS_ROUTINE (tv_sec, tv_usec, 1e-6);
+}
+
+double
+rusage_diff_secs (const struct_rusage *end, const struct_rusage *start)
+{
+  DIFF_SECS_ROUTINE (ru_utime.tv_sec, ru_utime.tv_usec, 1e-6);
+}
+
+double
+timespec_diff_secs (const struct_timespec *end, const struct_timespec *start)
+{
+  DIFF_SECS_ROUTINE (tv_sec, tv_nsec, 1e-9);
+}
+
+/* This is for use after time_base_to_time, ie. for seconds and nanoseconds. */
+double
+timebasestruct_diff_secs (const timebasestruct_t *end,
+			  const timebasestruct_t *start)
+{
+  DIFF_SECS_ROUTINE (tb_high, tb_low, 1e-9);
+}
+
+
+double
+speed_endtime (void)
+{
+#define END_USE(name,value)                             \
+  do {                                                  \
+    if (speed_option_verbose >= 3)                      \
+      printf ("speed_endtime(): used %s\n", name);      \
+    result = value;                                     \
+    goto done;                                          \
+  } while (0)
+
+#define END_ENOUGH(name,value)                                          \
+  do {                                                                  \
+    if (speed_option_verbose >= 3)                                      \
+      printf ("speed_endtime(): %s gives enough precision\n", name);    \
+    result = value;                                                     \
+    goto done;                                                          \
+  } while (0)
+
+#define END_EXCEED(name,value)                                            \
+  do {                                                                    \
+    if (speed_option_verbose >= 3)                                        \
+      printf ("speed_endtime(): cycle counter limit exceeded, used %s\n", \
+	      name);                                                      \
+    result = value;                                                       \
+    goto done;                                                            \
+  } while (0)
+
+  unsigned          end_cycles[2];
+  stck_t            end_stck;
+  unsigned          end_mftb[2];
+  unsigned          end_sgi;
+  timebasestruct_t  end_rrt;
+  struct_timespec   end_cgt;
+  struct_timeval    end_gtod;
+  struct_rusage     end_grus;
+  struct_tms        end_times;
+  double            t_gtod, t_grus, t_times, t_cgt;
+  double            t_rrt, t_sgi, t_mftb, t_stck, t_cycles;
+  double            result;
+
+  /* Cycles sampled first for maximum accuracy.
+     "have_" values tested to let unused code go dead.  */
+
+  if (have_cycles && use_cycles)  speed_cyclecounter (end_cycles);
+  if (have_stck   && use_stck)    STCK (end_stck);
+  if (have_mftb   && use_mftb)    MFTB (end_mftb);
+  if (have_sgi    && use_sgi)     end_sgi = *sgi_addr;
+  if (have_rrt    && use_rrt)     read_real_time (&end_rrt, sizeof(end_rrt));
+  if (have_cgt    && use_cgt)     clock_gettime (CGT_ID, &end_cgt);
+  if (have_gtod   && use_gtod)    gettimeofday (&end_gtod, NULL);
+  if (have_grus   && use_grus)    getrusage (0, &end_grus);
+  if (have_times  && use_times)   times (&end_times);
+
+  result = -1.0;
+
+  if (speed_option_verbose >= 4)
+    {
+      printf ("speed_endtime():\n");
+      if (use_cycles)
+	printf ("   cycles  0x%X,0x%X -> 0x%X,0x%X\n",
+		start_cycles[1], start_cycles[0],
+		end_cycles[1], end_cycles[0]);
+
+      if (use_stck)
+	printf ("   stck  0x%lX -> 0x%lX\n", start_stck, end_stck);
+
+      if (use_mftb)
+	printf ("   mftb  0x%X,%08X -> 0x%X,%08X\n",
+		start_mftb[1], start_mftb[0],
+		end_mftb[1], end_mftb[0]);
+
+      if (use_sgi)
+	printf ("   sgi  0x%X -> 0x%X\n", start_sgi, end_sgi);
+
+      if (use_rrt)
+	printf ("   read_real_time  (%d)%u,%u -> (%d)%u,%u\n",
+		start_rrt.flag, start_rrt.tb_high, start_rrt.tb_low,
+		end_rrt.flag, end_rrt.tb_high, end_rrt.tb_low);
+
+      if (use_cgt)
+	printf ("   clock_gettime  %ld.%09ld -> %ld.%09ld\n",
+		start_cgt.tv_sec, start_cgt.tv_nsec,
+		end_cgt.tv_sec, end_cgt.tv_nsec);
+
+      if (use_gtod)
+	printf ("   gettimeofday  %ld.%06ld -> %ld.%06ld\n",
+		start_gtod.tv_sec, start_gtod.tv_usec,
+		end_gtod.tv_sec, end_gtod.tv_usec);
+
+      if (use_grus)
+	printf ("   getrusage  %ld.%06ld -> %ld.%06ld\n",
+		start_grus.ru_utime.tv_sec, start_grus.ru_utime.tv_usec,
+		end_grus.ru_utime.tv_sec, end_grus.ru_utime.tv_usec);
+
+      if (use_times)
+	printf ("   times  %ld -> %ld\n",
+		start_times.tms_utime, end_times.tms_utime);
+    }
+
+  if (use_rrt)
+    {
+      time_base_to_time (&start_rrt, sizeof(start_rrt));
+      time_base_to_time (&end_rrt, sizeof(end_rrt));
+      t_rrt = timebasestruct_diff_secs (&end_rrt, &start_rrt);
+      END_USE ("read_real_time()", t_rrt);
+    }
+
+  if (use_cgt)
+    {
+      t_cgt = timespec_diff_secs (&end_cgt, &start_cgt);
+      END_USE ("clock_gettime()", t_cgt);
+    }
+
+  if (use_grus)
+    {
+      t_grus = rusage_diff_secs (&end_grus, &start_grus);
+
+      /* Use getrusage() if the cycle counter limit would be exceeded, or if
+	 it provides enough accuracy already. */
+      if (use_cycles)
+	{
+	  if (t_grus >= speed_precision*grus_unittime)
+	    END_ENOUGH ("getrusage()", t_grus);
+	  if (t_grus >= cycles_limit)
+	    END_EXCEED ("getrusage()", t_grus);
+	}
+    }
+
+  if (use_times)
+    {
+      t_times = (end_times.tms_utime - start_times.tms_utime) * times_unittime;
+
+      /* Use times() if the cycle counter limit would be exceeded, or if
+	 it provides enough accuracy already. */
+      if (use_cycles)
+	{
+	  if (t_times >= speed_precision*times_unittime)
+	    END_ENOUGH ("times()", t_times);
+	  if (t_times >= cycles_limit)
+	    END_EXCEED ("times()", t_times);
+	}
+    }
+
+  if (use_gtod)
+    {
+      t_gtod = timeval_diff_secs (&end_gtod, &start_gtod);
+
+      /* Use gettimeofday() if it measured a value bigger than the cycle
+	 counter can handle.  */
+      if (use_cycles)
+	{
+	  if (t_gtod >= cycles_limit)
+	    END_EXCEED ("gettimeofday()", t_gtod);
+	}
+    }
+
+  if (use_mftb)
+    {
+      t_mftb = speed_mftb_diff (end_mftb, start_mftb) * mftb_unittime;
+      END_USE ("mftb", t_mftb);
+    }
+
+  if (use_stck)
+    {
+      t_stck = (end_stck - start_stck) * STCK_PERIOD;
+      END_USE ("stck", t_stck);
+    }
+
+  if (use_sgi)
+    {
+      t_sgi = (end_sgi - start_sgi) * sgi_unittime;
+      END_USE ("SGI hardware counter", t_sgi);
+    }
+
+  if (use_cycles)
+    {
+      t_cycles = speed_cyclecounter_diff (end_cycles, start_cycles)
+	* speed_cycletime;
+      END_USE ("cycle counter", t_cycles);
+    }
+
+  if (use_grus && getrusage_microseconds_p())
+    END_USE ("getrusage()", t_grus);
+
+  if (use_gtod && gettimeofday_microseconds_p())
+    END_USE ("gettimeofday()", t_gtod);
+
+  if (use_times)  END_USE ("times()",        t_times);
+  if (use_grus)   END_USE ("getrusage()",    t_grus);
+  if (use_gtod)   END_USE ("gettimeofday()", t_gtod);
+
+  fprintf (stderr, "speed_endtime(): oops, no time method available\n");
+  abort ();
+
+ done:
+  if (result < 0.0)
+    {
+      if (speed_option_verbose >= 2)
+	fprintf (stderr, "speed_endtime(): warning, treating negative time as zero: %.9f\n", result);
+      result = 0.0;
+    }
+  return result;
+}
diff --git a/third_party/gmp/tune/tune-gcd-p.c b/third_party/gmp/tune/tune-gcd-p.c
new file mode 100644
index 0000000..3b5a4a8
--- /dev/null
+++ b/third_party/gmp/tune/tune-gcd-p.c
@@ -0,0 +1,225 @@
+/* tune-gcd-p
+
+   Tune the choice for splitting p in divide-and-conquer gcd.
+
+Copyright 2008, 2010, 2011 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#define TUNE_GCD_P 1
+
+#include "../mpn/gcd.c"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "speed.h"
+
+/* Search for minimum over a range. FIXME: Implement golden-section /
+   fibonacci search*/
+static int
+search (double *minp, double (*f)(void *, int), void *ctx, int start, int end)
+{
+  int x[4];
+  double y[4];
+
+  int best_i;
+
+  x[0] = start;
+  x[3] = end;
+
+  y[0] = f(ctx, x[0]);
+  y[3] = f(ctx, x[3]);
+
+  for (;;)
+    {
+      int i;
+      int length = x[3] - x[0];
+
+      x[1] = x[0] + length/3;
+      x[2] = x[0] + 2*length/3;
+
+      y[1] = f(ctx, x[1]);
+      y[2] = f(ctx, x[2]);
+
+#if 0
+      printf("%d: %f, %d: %f, %d:, %f %d: %f\n",
+	     x[0], y[0], x[1], y[1], x[2], y[2], x[3], y[3]);
+#endif
+      for (best_i = 0, i = 1; i < 4; i++)
+	if (y[i] < y[best_i])
+	  best_i = i;
+
+      if (length <= 4)
+	break;
+
+      if (best_i >= 2)
+	{
+	  x[0] = x[1];
+	  y[0] = y[1];
+	}
+      else
+	{
+	  x[3] = x[2];
+	  y[3] = y[2];
+	}
+    }
+  *minp = y[best_i];
+  return x[best_i];
+}
+
+static int
+compare_double(const void *ap, const void *bp)
+{
+  double a = * (const double *) ap;
+  double b = * (const double *) bp;
+
+  if (a < b)
+    return -1;
+  else if (a > b)
+    return 1;
+  else
+    return 0;
+}
+
+static double
+median (double *v, size_t n)
+{
+  qsort(v, n, sizeof(*v), compare_double);
+
+  return v[n/2];
+}
+
+#define TIME(res, code) do {				\
+  double time_measurement[5];				\
+  unsigned time_i;					\
+							\
+  for (time_i = 0; time_i < 5; time_i++)		\
+    {							\
+      speed_starttime();				\
+      code;						\
+      time_measurement[time_i] = speed_endtime();	\
+    }							\
+  res = median(time_measurement, 5);			\
+} while (0)
+
+struct bench_data
+{
+  mp_size_t n;
+  mp_ptr ap;
+  mp_ptr bp;
+  mp_ptr up;
+  mp_ptr vp;
+  mp_ptr gp;
+};
+
+static double
+bench_gcd (void *ctx, int p)
+{
+  struct bench_data *data = (struct bench_data *) ctx;
+  double t;
+
+  p_table[data->n] = p;
+  TIME(t, {
+      MPN_COPY (data->up, data->ap, data->n);
+      MPN_COPY (data->vp, data->bp, data->n);
+      mpn_gcd (data->gp, data->up, data->n, data->vp, data->n);
+    });
+
+  return t;
+}
+
+int
+main(int argc, char **argv)
+{
+  gmp_randstate_t rands;  struct bench_data data;
+  mp_size_t n;
+
+  TMP_DECL;
+
+  /* Unbuffered so if output is redirected to a file it isn't lost if the
+     program is killed part way through.  */
+  setbuf (stdout, NULL);
+  setbuf (stderr, NULL);
+
+  gmp_randinit_default (rands);
+
+  TMP_MARK;
+
+  data.ap = TMP_ALLOC_LIMBS (P_TABLE_SIZE);
+  data.bp = TMP_ALLOC_LIMBS (P_TABLE_SIZE);
+  data.up = TMP_ALLOC_LIMBS (P_TABLE_SIZE);
+  data.vp = TMP_ALLOC_LIMBS (P_TABLE_SIZE);
+  data.gp = TMP_ALLOC_LIMBS (P_TABLE_SIZE);
+
+  mpn_random (data.ap, P_TABLE_SIZE);
+  mpn_random (data.bp, P_TABLE_SIZE);
+
+  memset (p_table, 0, sizeof(p_table));
+
+  for (n = 100; n < P_TABLE_SIZE; n++)
+    {
+      mp_size_t p;
+      mp_size_t best_p;
+      double best_time;
+      double lehmer_time;
+
+      if (data.ap[n-1] == 0)
+	data.ap[n-1] = 1;
+
+      if (data.bp[n-1] == 0)
+	data.bp[n-1] = 1;
+
+      data.n = n;
+
+      lehmer_time = bench_gcd (&data, 0);
+
+      best_p = search (&best_time, bench_gcd, &data, n/5, 4*n/5);
+      if (best_time > lehmer_time)
+	best_p = 0;
+
+      printf("%6zu %6zu %5.3g", n, best_p, (double) best_p / n);
+      if (best_p > 0)
+	{
+	  double speedup = 100 * (lehmer_time - best_time) / lehmer_time;
+	  printf(" %5.3g%%", speedup);
+	  if (speedup < 1.0)
+	    {
+	      printf(" (ignored)");
+	      best_p = 0;
+	    }
+	}
+      printf("\n");
+
+      p_table[n] = best_p;
+    }
+  TMP_FREE;
+  gmp_randclear(rands);
+  return 0;
+}
diff --git a/third_party/gmp/tune/tuneup.c b/third_party/gmp/tune/tuneup.c
new file mode 100644
index 0000000..86ba5ed
--- /dev/null
+++ b/third_party/gmp/tune/tuneup.c
@@ -0,0 +1,3070 @@
+/* Create tuned thresholds for various algorithms.
+
+Copyright 1999-2003, 2005, 2006, 2008-2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+
+/* Usage: tuneup [-t] [-t] [-p precision]
+
+   -t turns on some diagnostic traces, a second -t turns on more traces.
+
+   Notes:
+
+   The code here isn't a vision of loveliness, mainly because it's subject
+   to ongoing changes according to new things wanting to be tuned, and
+   practical requirements of systems tested.
+
+   Sometimes running the program twice produces slightly different results.
+   This is probably because there's so little separating algorithms near
+   their crossover, and on that basis it should make little or no difference
+   to the final speed of the relevant routines, but nothing has been done to
+   check that carefully.
+
+   Algorithm:
+
+   The thresholds are determined as follows.  A crossover may not be a
+   single size but rather a range where it oscillates between method A or
+   method B faster.  If the threshold is set making B used where A is faster
+   (or vice versa) that's bad.  Badness is the percentage time lost and
+   total badness is the sum of this over all sizes measured.  The threshold
+   is set to minimize total badness.
+
+   Suppose, as sizes increase, method B becomes faster than method A.  The
+   effect of the rule is that, as you look at increasing sizes, isolated
+   points where B is faster are ignored, but when it's consistently faster,
+   or faster on balance, then the threshold is set there.  The same result
+   is obtained thinking in the other direction of A becoming faster at
+   smaller sizes.
+
+   In practice the thresholds tend to be chosen to bring on the next
+   algorithm fairly quickly.
+
+   This rule is attractive because it's got a basis in reason and is fairly
+   easy to implement, but no work has been done to actually compare it in
+   absolute terms to other possibilities.
+
+   Implementation:
+
+   In a normal library build the thresholds are constants.  To tune them
+   selected objects are recompiled with the thresholds as global variables
+   instead.  #define TUNE_PROGRAM_BUILD does this, with help from code at
+   the end of gmp-impl.h, and rules in tune/Makefile.am.
+
+   MUL_TOOM22_THRESHOLD for example uses a recompiled mpn_mul_n.  The
+   threshold is set to "size+1" to avoid karatsuba, or to "size" to use one
+   level, but recurse into the basecase.
+
+   MUL_TOOM33_THRESHOLD makes use of the tuned MUL_TOOM22_THRESHOLD value.
+   Other routines in turn will make use of both of those.  Naturally the
+   dependants must be tuned first.
+
+   In a couple of cases, like DIVEXACT_1_THRESHOLD, there's no recompiling,
+   just a threshold based on comparing two routines (mpn_divrem_1 and
+   mpn_divexact_1), and no further use of the value determined.
+
+   Flags like USE_PREINV_MOD_1 or JACOBI_BASE_METHOD are even simpler, being
+   just comparisons between certain routines on representative data.
+
+   Shortcuts are applied when native (assembler) versions of routines exist.
+   For instance a native mpn_sqr_basecase is assumed to be always faster
+   than mpn_mul_basecase, with no measuring.
+
+   No attempt is made to tune within assembler routines, for instance
+   DIVREM_1_NORM_THRESHOLD.  An assembler mpn_divrem_1 is expected to be
+   written and tuned all by hand.  Assembler routines that might have hard
+   limits are recompiled though, to make them accept a bigger range of sizes
+   than normal, eg. mpn_sqr_basecase to compare against mpn_toom2_sqr.
+
+   Limitations:
+
+   The FFTs aren't subject to the same badness rule as the other thresholds,
+   so each k is probably being brought on a touch early.  This isn't likely
+   to make a difference, and the simpler probing means fewer tests.
+
+*/
+
+#define TUNE_PROGRAM_BUILD  1   /* for gmp-impl.h */
+
+#include "config.h"
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "gmp-impl.h"
+#include "longlong.h"
+
+#include "tests.h"
+#include "speed.h"
+
+#if !HAVE_DECL_OPTARG
+extern char *optarg;
+extern int optind, opterr;
+#endif
+
+
+#define DEFAULT_MAX_SIZE   1000  /* limbs */
+
+#if WANT_FFT
+mp_size_t  option_fft_max_size = 50000;  /* limbs */
+#else
+mp_size_t  option_fft_max_size = 0;
+#endif
+int        option_trace = 0;
+int        option_fft_trace = 0;
+struct speed_params  s;
+
+struct dat_t {
+  mp_size_t  size;
+  double     d;
+} *dat = NULL;
+int  ndat = 0;
+int  allocdat = 0;
+
+/* This is not defined if mpn_sqr_basecase doesn't declare a limit.  In that
+   case use zero here, which for params.max_size means no limit.  */
+#ifndef TUNE_SQR_TOOM2_MAX
+#define TUNE_SQR_TOOM2_MAX  0
+#endif
+
+mp_size_t  mul_toom22_threshold         = MP_SIZE_T_MAX;
+mp_size_t  mul_toom33_threshold         = MUL_TOOM33_THRESHOLD_LIMIT;
+mp_size_t  mul_toom44_threshold         = MUL_TOOM44_THRESHOLD_LIMIT;
+mp_size_t  mul_toom6h_threshold         = MUL_TOOM6H_THRESHOLD_LIMIT;
+mp_size_t  mul_toom8h_threshold         = MUL_TOOM8H_THRESHOLD_LIMIT;
+mp_size_t  mul_toom32_to_toom43_threshold = MP_SIZE_T_MAX;
+mp_size_t  mul_toom32_to_toom53_threshold = MP_SIZE_T_MAX;
+mp_size_t  mul_toom42_to_toom53_threshold = MP_SIZE_T_MAX;
+mp_size_t  mul_toom42_to_toom63_threshold = MP_SIZE_T_MAX;
+mp_size_t  mul_toom43_to_toom54_threshold = MP_SIZE_T_MAX;
+mp_size_t  mul_fft_threshold            = MP_SIZE_T_MAX;
+mp_size_t  mul_fft_modf_threshold       = MP_SIZE_T_MAX;
+mp_size_t  sqr_basecase_threshold       = MP_SIZE_T_MAX;
+mp_size_t  sqr_toom2_threshold
+  = (TUNE_SQR_TOOM2_MAX == 0 ? MP_SIZE_T_MAX : TUNE_SQR_TOOM2_MAX);
+mp_size_t  sqr_toom3_threshold          = SQR_TOOM3_THRESHOLD_LIMIT;
+mp_size_t  sqr_toom4_threshold          = SQR_TOOM4_THRESHOLD_LIMIT;
+mp_size_t  sqr_toom6_threshold          = SQR_TOOM6_THRESHOLD_LIMIT;
+mp_size_t  sqr_toom8_threshold          = SQR_TOOM8_THRESHOLD_LIMIT;
+mp_size_t  sqr_fft_threshold            = MP_SIZE_T_MAX;
+mp_size_t  sqr_fft_modf_threshold       = MP_SIZE_T_MAX;
+mp_size_t  mullo_basecase_threshold     = MP_SIZE_T_MAX;
+mp_size_t  mullo_dc_threshold           = MP_SIZE_T_MAX;
+mp_size_t  mullo_mul_n_threshold        = MP_SIZE_T_MAX;
+mp_size_t  sqrlo_basecase_threshold     = MP_SIZE_T_MAX;
+mp_size_t  sqrlo_dc_threshold           = MP_SIZE_T_MAX;
+mp_size_t  sqrlo_sqr_threshold          = MP_SIZE_T_MAX;
+mp_size_t  mulmid_toom42_threshold      = MP_SIZE_T_MAX;
+mp_size_t  mulmod_bnm1_threshold        = MP_SIZE_T_MAX;
+mp_size_t  sqrmod_bnm1_threshold        = MP_SIZE_T_MAX;
+mp_size_t  div_qr_2_pi2_threshold       = MP_SIZE_T_MAX;
+mp_size_t  dc_div_qr_threshold          = MP_SIZE_T_MAX;
+mp_size_t  dc_divappr_q_threshold       = MP_SIZE_T_MAX;
+mp_size_t  mu_div_qr_threshold          = MP_SIZE_T_MAX;
+mp_size_t  mu_divappr_q_threshold       = MP_SIZE_T_MAX;
+mp_size_t  mupi_div_qr_threshold        = MP_SIZE_T_MAX;
+mp_size_t  mu_div_q_threshold           = MP_SIZE_T_MAX;
+mp_size_t  dc_bdiv_qr_threshold         = MP_SIZE_T_MAX;
+mp_size_t  dc_bdiv_q_threshold          = MP_SIZE_T_MAX;
+mp_size_t  mu_bdiv_qr_threshold         = MP_SIZE_T_MAX;
+mp_size_t  mu_bdiv_q_threshold          = MP_SIZE_T_MAX;
+mp_size_t  inv_mulmod_bnm1_threshold    = MP_SIZE_T_MAX;
+mp_size_t  inv_newton_threshold         = MP_SIZE_T_MAX;
+mp_size_t  inv_appr_threshold           = MP_SIZE_T_MAX;
+mp_size_t  binv_newton_threshold        = MP_SIZE_T_MAX;
+mp_size_t  redc_1_to_redc_2_threshold   = MP_SIZE_T_MAX;
+mp_size_t  redc_1_to_redc_n_threshold   = MP_SIZE_T_MAX;
+mp_size_t  redc_2_to_redc_n_threshold   = MP_SIZE_T_MAX;
+mp_size_t  matrix22_strassen_threshold  = MP_SIZE_T_MAX;
+mp_size_t  hgcd_threshold               = MP_SIZE_T_MAX;
+mp_size_t  hgcd_appr_threshold          = MP_SIZE_T_MAX;
+mp_size_t  hgcd_reduce_threshold        = MP_SIZE_T_MAX;
+mp_size_t  gcd_dc_threshold             = MP_SIZE_T_MAX;
+mp_size_t  gcdext_dc_threshold          = MP_SIZE_T_MAX;
+int	   div_qr_1n_pi1_method		= 0;
+mp_size_t  div_qr_1_norm_threshold      = MP_SIZE_T_MAX;
+mp_size_t  div_qr_1_unnorm_threshold    = MP_SIZE_T_MAX;
+mp_size_t  divrem_1_norm_threshold      = MP_SIZE_T_MAX;
+mp_size_t  divrem_1_unnorm_threshold    = MP_SIZE_T_MAX;
+mp_size_t  mod_1_norm_threshold         = MP_SIZE_T_MAX;
+mp_size_t  mod_1_unnorm_threshold       = MP_SIZE_T_MAX;
+int	   mod_1_1p_method		= 0;
+mp_size_t  mod_1n_to_mod_1_1_threshold  = MP_SIZE_T_MAX;
+mp_size_t  mod_1u_to_mod_1_1_threshold  = MP_SIZE_T_MAX;
+mp_size_t  mod_1_1_to_mod_1_2_threshold = MP_SIZE_T_MAX;
+mp_size_t  mod_1_2_to_mod_1_4_threshold = MP_SIZE_T_MAX;
+mp_size_t  preinv_mod_1_to_mod_1_threshold = MP_SIZE_T_MAX;
+mp_size_t  divrem_2_threshold           = MP_SIZE_T_MAX;
+mp_size_t  get_str_dc_threshold         = MP_SIZE_T_MAX;
+mp_size_t  get_str_precompute_threshold = MP_SIZE_T_MAX;
+mp_size_t  set_str_dc_threshold         = MP_SIZE_T_MAX;
+mp_size_t  set_str_precompute_threshold = MP_SIZE_T_MAX;
+mp_size_t  fac_odd_threshold            = 0;
+mp_size_t  fac_dsc_threshold            = FAC_DSC_THRESHOLD_LIMIT;
+
+mp_size_t  fft_modf_sqr_threshold = MP_SIZE_T_MAX;
+mp_size_t  fft_modf_mul_threshold = MP_SIZE_T_MAX;
+
+struct param_t {
+  const char        *name;
+  speed_function_t  function;
+  speed_function_t  function2;
+  double            step_factor;    /* how much to step relatively */
+  int               step;           /* how much to step absolutely */
+  double            function_fudge; /* multiplier for "function" speeds */
+  int               stop_since_change;
+  double            stop_factor;
+  mp_size_t         min_size;
+  int               min_is_always;
+  mp_size_t         max_size;
+  mp_size_t         check_size;
+  mp_size_t         size_extra;
+
+#define DATA_HIGH_LT_R  1
+#define DATA_HIGH_GE_R  2
+  int               data_high;
+
+  int               noprint;
+};
+
+
+/* These are normally undefined when false, which suits "#if" fine.
+   But give them zero values so they can be used in plain C "if"s.  */
+#ifndef UDIV_PREINV_ALWAYS
+#define UDIV_PREINV_ALWAYS 0
+#endif
+#ifndef HAVE_NATIVE_mpn_divexact_1
+#define HAVE_NATIVE_mpn_divexact_1 0
+#endif
+#ifndef HAVE_NATIVE_mpn_div_qr_1n_pi1
+#define HAVE_NATIVE_mpn_div_qr_1n_pi1 0
+#endif
+#ifndef HAVE_NATIVE_mpn_divrem_1
+#define HAVE_NATIVE_mpn_divrem_1 0
+#endif
+#ifndef HAVE_NATIVE_mpn_divrem_2
+#define HAVE_NATIVE_mpn_divrem_2 0
+#endif
+#ifndef HAVE_NATIVE_mpn_mod_1
+#define HAVE_NATIVE_mpn_mod_1 0
+#endif
+#ifndef HAVE_NATIVE_mpn_mod_1_1p
+#define HAVE_NATIVE_mpn_mod_1_1p 0
+#endif
+#ifndef HAVE_NATIVE_mpn_modexact_1_odd
+#define HAVE_NATIVE_mpn_modexact_1_odd 0
+#endif
+#ifndef HAVE_NATIVE_mpn_preinv_divrem_1
+#define HAVE_NATIVE_mpn_preinv_divrem_1 0
+#endif
+#ifndef HAVE_NATIVE_mpn_preinv_mod_1
+#define HAVE_NATIVE_mpn_preinv_mod_1 0
+#endif
+#ifndef HAVE_NATIVE_mpn_sqr_basecase
+#define HAVE_NATIVE_mpn_sqr_basecase 0
+#endif
+
+
+#define MAX3(a,b,c)  MAX (MAX (a, b), c)
+
+mp_limb_t
+randlimb_norm (void)
+{
+  mp_limb_t  n;
+  mpn_random (&n, 1);
+  n |= GMP_NUMB_HIGHBIT;
+  return n;
+}
+
+#define GMP_NUMB_HALFMASK  ((CNST_LIMB(1) << (GMP_NUMB_BITS/2)) - 1)
+
+mp_limb_t
+randlimb_half (void)
+{
+  mp_limb_t  n;
+  mpn_random (&n, 1);
+  n &= GMP_NUMB_HALFMASK;
+  n += (n==0);
+  return n;
+}
+
+
+/* Add an entry to the end of the dat[] array, reallocing to make it bigger
+   if necessary.  */
+void
+add_dat (mp_size_t size, double d)
+{
+#define ALLOCDAT_STEP  500
+
+  ASSERT_ALWAYS (ndat <= allocdat);
+
+  if (ndat == allocdat)
+    {
+      dat = (struct dat_t *) __gmp_allocate_or_reallocate
+        (dat, allocdat * sizeof(dat[0]),
+         (allocdat+ALLOCDAT_STEP) * sizeof(dat[0]));
+      allocdat += ALLOCDAT_STEP;
+    }
+
+  dat[ndat].size = size;
+  dat[ndat].d = d;
+  ndat++;
+}
+
+
+/* Return the threshold size based on the data accumulated. */
+mp_size_t
+analyze_dat (int final)
+{
+  double  x, min_x;
+  int     j, min_j;
+
+  /* If the threshold is set at dat[0].size, any positive values are bad. */
+  x = 0.0;
+  for (j = 0; j < ndat; j++)
+    if (dat[j].d > 0.0)
+      x += dat[j].d;
+
+  if (option_trace >= 2 && final)
+    {
+      printf ("\n");
+      printf ("x is the sum of the badness from setting thresh at given size\n");
+      printf ("  (minimum x is sought)\n");
+      printf ("size=%ld  first x=%.4f\n", (long) dat[j].size, x);
+    }
+
+  min_x = x;
+  min_j = 0;
+
+
+  /* When stepping to the next dat[j].size, positive values are no longer
+     bad (so subtracted), negative values become bad (so add the absolute
+     value, meaning subtract). */
+  for (j = 0; j < ndat; x -= dat[j].d, j++)
+    {
+      if (option_trace >= 2 && final)
+        printf ("size=%ld  x=%.4f\n", (long) dat[j].size, x);
+
+      if (x < min_x)
+        {
+          min_x = x;
+          min_j = j;
+        }
+    }
+
+  return min_j;
+}
+
+
+/* Measuring for recompiled mpn/generic/div_qr_1.c,
+ * mpn/generic/divrem_1.c, mpn/generic/mod_1.c and mpz/fac_ui.c */
+
+mp_limb_t mpn_div_qr_1_tune (mp_ptr, mp_limb_t *, mp_srcptr, mp_size_t, mp_limb_t);
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+mp_limb_t mpn_divrem_1_tune (mp_ptr, mp_size_t, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t mpn_mod_1_tune (mp_srcptr, mp_size_t, mp_limb_t);
+void mpz_fac_ui_tune (mpz_ptr, unsigned long);
+
+#if defined (__cplusplus)
+}
+#endif
+
+double
+speed_mpn_mod_1_tune (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_MOD_1 (mpn_mod_1_tune);
+}
+double
+speed_mpn_divrem_1_tune (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_DIVREM_1 (mpn_divrem_1_tune);
+}
+double
+speed_mpz_fac_ui_tune (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPZ_FAC_UI (mpz_fac_ui_tune);
+}
+double
+speed_mpn_div_qr_1_tune (struct speed_params *s)
+{
+  SPEED_ROUTINE_MPN_DIV_QR_1 (mpn_div_qr_1_tune);
+}
+
+double
+tuneup_measure (speed_function_t fun,
+                const struct param_t *param,
+                struct speed_params *s)
+{
+  static struct param_t  dummy;
+  double   t;
+  TMP_DECL;
+
+  if (! param)
+    param = &dummy;
+
+  s->size += param->size_extra;
+
+  TMP_MARK;
+  SPEED_TMP_ALLOC_LIMBS (s->xp, s->size, 0);
+  SPEED_TMP_ALLOC_LIMBS (s->yp, s->size, 0);
+
+  mpn_random (s->xp, s->size);
+  mpn_random (s->yp, s->size);
+
+  switch (param->data_high) {
+  case DATA_HIGH_LT_R:
+    s->xp[s->size-1] %= s->r;
+    s->yp[s->size-1] %= s->r;
+    break;
+  case DATA_HIGH_GE_R:
+    s->xp[s->size-1] |= s->r;
+    s->yp[s->size-1] |= s->r;
+    break;
+  }
+
+  t = speed_measure (fun, s);
+
+  s->size -= param->size_extra;
+
+  TMP_FREE;
+  return t;
+}
+
+
+#define PRINT_WIDTH  31
+
+void
+print_define_start (const char *name)
+{
+  printf ("#define %-*s  ", PRINT_WIDTH, name);
+  if (option_trace)
+    printf ("...\n");
+}
+
+void
+print_define_end_remark (const char *name, mp_size_t value, const char *remark)
+{
+  if (option_trace)
+    printf ("#define %-*s  ", PRINT_WIDTH, name);
+
+  if (value == MP_SIZE_T_MAX)
+    printf ("MP_SIZE_T_MAX");
+  else
+    printf ("%5ld", (long) value);
+
+  if (remark != NULL)
+    printf ("  /* %s */", remark);
+  printf ("\n");
+  fflush (stdout);
+}
+
+void
+print_define_end (const char *name, mp_size_t value)
+{
+  const char  *remark;
+  if (value == MP_SIZE_T_MAX)
+    remark = "never";
+  else if (value == 0)
+    remark = "always";
+  else
+    remark = NULL;
+  print_define_end_remark (name, value, remark);
+}
+
+void
+print_define (const char *name, mp_size_t value)
+{
+  print_define_start (name);
+  print_define_end (name, value);
+}
+
+void
+print_define_remark (const char *name, mp_size_t value, const char *remark)
+{
+  print_define_start (name);
+  print_define_end_remark (name, value, remark);
+}
+
+void
+print_define_with_speedup (const char *name, mp_size_t value,
+			   mp_size_t runner_up, double speedup)
+{
+  char buf[100];
+  snprintf (buf, sizeof(buf), "%.2f%% faster than %ld",
+	    100.0 * (speedup - 1), runner_up);
+  print_define_remark (name, value, buf);
+}
+
+void
+one (mp_size_t *threshold, struct param_t *param)
+{
+  int  since_positive, since_thresh_change;
+  int  thresh_idx, new_thresh_idx;
+
+#define DEFAULT(x,n)  do { if (! (x))  (x) = (n); } while (0)
+
+  DEFAULT (param->function_fudge, 1.0);
+  DEFAULT (param->function2, param->function);
+  DEFAULT (param->step_factor, 0.01);  /* small steps by default */
+  DEFAULT (param->step, 1);            /* small steps by default */
+  DEFAULT (param->stop_since_change, 80);
+  DEFAULT (param->stop_factor, 1.2);
+  DEFAULT (param->min_size, 10);
+  DEFAULT (param->max_size, DEFAULT_MAX_SIZE);
+
+  if (param->check_size != 0)
+    {
+      double   t1, t2;
+      s.size = param->check_size;
+
+      *threshold = s.size+1;
+      t1 = tuneup_measure (param->function, param, &s);
+
+      *threshold = s.size;
+      t2 = tuneup_measure (param->function2, param, &s);
+      if (t1 == -1.0 || t2 == -1.0)
+        {
+          printf ("Oops, can't run both functions at size %ld\n",
+                  (long) s.size);
+          abort ();
+        }
+      t1 *= param->function_fudge;
+
+      /* ask that t2 is at least 4% below t1 */
+      if (t1 < t2*1.04)
+        {
+          if (option_trace)
+            printf ("function2 never enough faster: t1=%.9f t2=%.9f\n", t1, t2);
+          *threshold = MP_SIZE_T_MAX;
+          if (! param->noprint)
+            print_define (param->name, *threshold);
+          return;
+        }
+
+      if (option_trace >= 2)
+        printf ("function2 enough faster at size=%ld: t1=%.9f t2=%.9f\n",
+                (long) s.size, t1, t2);
+    }
+
+  if (! param->noprint || option_trace)
+    print_define_start (param->name);
+
+  ndat = 0;
+  since_positive = 0;
+  since_thresh_change = 0;
+  thresh_idx = 0;
+
+  if (option_trace >= 2)
+    {
+      printf ("             algorithm-A  algorithm-B   ratio  possible\n");
+      printf ("              (seconds)    (seconds)    diff    thresh\n");
+    }
+
+  for (s.size = param->min_size;
+       s.size < param->max_size;
+       s.size += MAX ((mp_size_t) floor (s.size * param->step_factor), param->step))
+    {
+      double   ti, tiplus1, d;
+
+      /*
+        FIXME: check minimum size requirements are met, possibly by just
+        checking for the -1 returns from the speed functions.
+      */
+
+      /* using method A at this size */
+      *threshold = s.size+1;
+      ti = tuneup_measure (param->function, param, &s);
+      if (ti == -1.0)
+        abort ();
+      ti *= param->function_fudge;
+
+      /* using method B at this size */
+      *threshold = s.size;
+      tiplus1 = tuneup_measure (param->function2, param, &s);
+      if (tiplus1 == -1.0)
+        abort ();
+
+      /* Calculate the fraction by which the one or the other routine is
+         slower.  */
+      if (tiplus1 >= ti)
+        d = (tiplus1 - ti) / tiplus1;  /* negative */
+      else
+        d = (tiplus1 - ti) / ti;       /* positive */
+
+      add_dat (s.size, d);
+
+      new_thresh_idx = analyze_dat (0);
+
+      if (option_trace >= 2)
+        printf ("size=%ld  %.9f  %.9f  % .4f %c  %ld\n",
+                (long) s.size, ti, tiplus1, d,
+                ti > tiplus1 ? '#' : ' ',
+                (long) dat[new_thresh_idx].size);
+
+      /* Stop if the last time method i was faster was more than a
+         certain number of measurements ago.  */
+#define STOP_SINCE_POSITIVE  200
+      if (d >= 0)
+        since_positive = 0;
+      else
+        if (++since_positive > STOP_SINCE_POSITIVE)
+          {
+            if (option_trace >= 1)
+              printf ("stopped due to since_positive (%d)\n",
+                      STOP_SINCE_POSITIVE);
+            break;
+          }
+
+      /* Stop if method A has become slower by a certain factor. */
+      if (ti >= tiplus1 * param->stop_factor)
+        {
+          if (option_trace >= 1)
+            printf ("stopped due to ti >= tiplus1 * factor (%.1f)\n",
+                    param->stop_factor);
+          break;
+        }
+
+      /* Stop if the threshold implied hasn't changed in a certain
+         number of measurements.  (It's this condition that usually
+         stops the loop.) */
+      if (thresh_idx != new_thresh_idx)
+        since_thresh_change = 0, thresh_idx = new_thresh_idx;
+      else
+        if (++since_thresh_change > param->stop_since_change)
+          {
+            if (option_trace >= 1)
+              printf ("stopped due to since_thresh_change (%d)\n",
+                      param->stop_since_change);
+            break;
+          }
+
+      /* Stop if the threshold implied is more than a certain number of
+         measurements ago.  */
+#define STOP_SINCE_AFTER   500
+      if (ndat - thresh_idx > STOP_SINCE_AFTER)
+        {
+          if (option_trace >= 1)
+            printf ("stopped due to ndat - thresh_idx > amount (%d)\n",
+                    STOP_SINCE_AFTER);
+          break;
+        }
+
+      /* Stop when the size limit is reached before the end of the
+         crossover, but only show this as an error for >= the default max
+         size.  FIXME: Maybe should make it a param choice whether this is
+         an error.  */
+      if (s.size >= param->max_size && param->max_size >= DEFAULT_MAX_SIZE)
+        {
+          fprintf (stderr, "%s\n", param->name);
+          fprintf (stderr, "sizes %ld to %ld total %d measurements\n",
+                   (long) dat[0].size, (long) dat[ndat-1].size, ndat);
+          fprintf (stderr, "    max size reached before end of crossover\n");
+          break;
+        }
+    }
+
+  if (option_trace >= 1)
+    printf ("sizes %ld to %ld total %d measurements\n",
+            (long) dat[0].size, (long) dat[ndat-1].size, ndat);
+
+  *threshold = dat[analyze_dat (1)].size;
+
+  if (param->min_is_always)
+    {
+      if (*threshold == param->min_size)
+        *threshold = 0;
+    }
+
+  if (! param->noprint || option_trace)
+    print_define_end (param->name, *threshold);
+}
+
+/* Time N different FUNCTIONS with the same parameters and size, to
+   select the fastest. Since *_METHOD defines start numbering from
+   one, if functions[i] is fastest, the value of the define is i+1.
+   Also output a comment with speedup compared to the next fastest
+   function. The NAME argument is used only for trace output.
+
+   Returns the index of the fastest function.
+*/
+int
+one_method (int n, speed_function_t *functions,
+	    const char *name, const char *define,
+	    const struct param_t *param)
+{
+  double *t;
+  int i;
+  int method;
+  int method_runner_up;
+
+  TMP_DECL;
+  TMP_MARK;
+  t = (double*) TMP_ALLOC (n * sizeof (*t));
+
+  for (i = 0; i < n; i++)
+    {
+      t[i] = tuneup_measure (functions[i], param, &s);
+      if (option_trace >= 1)
+	printf ("size=%ld, %s, method %d %.9f\n",
+		(long) s.size, name, i + 1, t[i]);
+      if (t[i] == -1.0)
+	{
+	  printf ("Oops, can't measure all %s methods\n", name);
+	  abort ();
+	}
+    }
+  method = 0;
+  for (i = 1; i < n; i++)
+    if (t[i] < t[method])
+      method = i;
+
+  method_runner_up = (method == 0);
+  for (i = 0; i < n; i++)
+    if (i != method && t[i] < t[method_runner_up])
+      method_runner_up = i;
+
+  print_define_with_speedup (define, method + 1, method_runner_up + 1,
+			     t[method_runner_up] / t[method]);
+
+  TMP_FREE;
+  return method;
+}
+
+
+/* Special probing for the fft thresholds.  The size restrictions on the
+   FFTs mean the graph of time vs size has a step effect.  See this for
+   example using
+
+       ./speed -s 4096-16384 -t 128 -P foo mpn_mul_fft.8 mpn_mul_fft.9
+       gnuplot foo.gnuplot
+
+   The current approach is to compare routines at the midpoint of relevant
+   steps.  Arguably a more sophisticated system of threshold data is wanted
+   if this step effect remains. */
+
+struct fft_param_t {
+  const char        *table_name;
+  const char        *threshold_name;
+  const char        *modf_threshold_name;
+  mp_size_t         *p_threshold;
+  mp_size_t         *p_modf_threshold;
+  mp_size_t         first_size;
+  mp_size_t         max_size;
+  speed_function_t  function;
+  speed_function_t  mul_modf_function;
+  speed_function_t  mul_function;
+  mp_size_t         sqr;
+};
+
+
+/* mpn_mul_fft requires pl a multiple of 2^k limbs, but with
+   N=pl*BIT_PER_MP_LIMB it internally also pads out so N/2^k is a multiple
+   of 2^(k-1) bits. */
+
+mp_size_t
+fft_step_size (int k)
+{
+  mp_size_t  step;
+
+  step = MAX ((mp_size_t) 1 << (k-1), GMP_LIMB_BITS) / GMP_LIMB_BITS;
+  step *= (mp_size_t) 1 << k;
+
+  if (step <= 0)
+    {
+      printf ("Can't handle k=%d\n", k);
+      abort ();
+    }
+
+  return step;
+}
+
+mp_size_t
+fft_next_size (mp_size_t pl, int k)
+{
+  mp_size_t  m = fft_step_size (k);
+
+/*    printf ("[k=%d %ld] %ld ->", k, m, pl); */
+
+  if (pl == 0 || (pl & (m-1)) != 0)
+    pl = (pl | (m-1)) + 1;
+
+/*    printf (" %ld\n", pl); */
+  return pl;
+}
+
+#define NMAX_DEFAULT 1000000
+#define MAX_REPS 25
+#define MIN_REPS 5
+
+static inline size_t
+mpn_mul_fft_lcm (size_t a, unsigned int k)
+{
+  unsigned int l = k;
+
+  while (a % 2 == 0 && k > 0)
+    {
+      a >>= 1;
+      k--;
+    }
+  return a << l;
+}
+
+mp_size_t
+fftfill (mp_size_t pl, int k, int sqr)
+{
+  mp_size_t maxLK;
+  mp_bitcnt_t N, Nprime, nprime, M;
+
+  N = pl * GMP_NUMB_BITS;
+  M = N >> k;
+
+  maxLK = mpn_mul_fft_lcm ((unsigned long) GMP_NUMB_BITS, k);
+
+  Nprime = (1 + (2 * M + k + 2) / maxLK) * maxLK;
+  nprime = Nprime / GMP_NUMB_BITS;
+  if (nprime >= (sqr ? SQR_FFT_MODF_THRESHOLD : MUL_FFT_MODF_THRESHOLD))
+    {
+      size_t K2;
+      for (;;)
+	{
+	  K2 = 1L << mpn_fft_best_k (nprime, sqr);
+	  if ((nprime & (K2 - 1)) == 0)
+	    break;
+	  nprime = (nprime + K2 - 1) & -K2;
+	  Nprime = nprime * GMP_LIMB_BITS;
+	}
+    }
+  ASSERT_ALWAYS (nprime < pl);
+
+  return Nprime;
+}
+
+static int
+compare_double (const void *ap, const void *bp)
+{
+  double a = * (const double *) ap;
+  double b = * (const double *) bp;
+
+  if (a < b)
+    return -1;
+  else if (a > b)
+    return 1;
+  else
+    return 0;
+}
+
+double
+median (double *times, int n)
+{
+  qsort (times, n, sizeof (double), compare_double);
+  return times[n/2];
+}
+
+#define FFT_CACHE_SIZE 25
+typedef struct fft_cache
+{
+  mp_size_t n;
+  double time;
+} fft_cache_t;
+
+fft_cache_t fft_cache[FFT_CACHE_SIZE];
+
+double
+cached_measure (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n, int k,
+		int n_measurements)
+{
+  int i;
+  double t, ttab[MAX_REPS];
+
+  if (fft_cache[k].n == n)
+    return fft_cache[k].time;
+
+  for (i = 0; i < n_measurements; i++)
+    {
+      speed_starttime ();
+      mpn_mul_fft (rp, n, ap, n, bp, n, k);
+      ttab[i] = speed_endtime ();
+    }
+
+  t = median (ttab, n_measurements);
+  fft_cache[k].n = n;
+  fft_cache[k].time = t;
+  return t;
+}
+
+#define INSERT_FFTTAB(idx, nval, kval)					\
+  do {									\
+    fft_tab[idx].n = nval;						\
+    fft_tab[idx].k = kval;						\
+    fft_tab[idx+1].n = (1 << 27) - 1;	/* sentinel, 27b wide field */	\
+    fft_tab[idx+1].k = (1 <<  5) - 1;					\
+  } while (0)
+
+int
+fftmes (mp_size_t nmin, mp_size_t nmax, int initial_k, struct fft_param_t *p, int idx, int print)
+{
+  mp_size_t n, n1, prev_n1;
+  int k, best_k, last_best_k, kmax;
+  int eff, prev_eff;
+  double t0, t1;
+  int n_measurements;
+  mp_limb_t *ap, *bp, *rp;
+  mp_size_t alloc;
+  struct fft_table_nk *fft_tab;
+
+  fft_tab = mpn_fft_table3[p->sqr];
+
+  for (k = 0; k < FFT_CACHE_SIZE; k++)
+    fft_cache[k].n = 0;
+
+  if (nmin < (p->sqr ? SQR_FFT_MODF_THRESHOLD : MUL_FFT_MODF_THRESHOLD))
+    {
+      nmin = (p->sqr ? SQR_FFT_MODF_THRESHOLD : MUL_FFT_MODF_THRESHOLD);
+    }
+
+  if (print)
+    printf ("#define %s%*s", p->table_name, 38, "");
+
+  if (idx == 0)
+    {
+      INSERT_FFTTAB (0, nmin, initial_k);
+
+      if (print)
+	{
+	  printf ("\\\n  { ");
+	  printf ("{%7u,%2u}", fft_tab[0].n, fft_tab[0].k);
+	}
+
+      idx = 1;
+    }
+
+  ap = (mp_ptr) malloc (sizeof (mp_limb_t));
+  if (p->sqr)
+    bp = ap;
+  else
+    bp = (mp_ptr) malloc (sizeof (mp_limb_t));
+  rp = (mp_ptr) malloc (sizeof (mp_limb_t));
+  alloc = 1;
+
+  /* Round n to comply to initial k value */
+  n = (nmin + ((1ul << initial_k) - 1)) & (MP_SIZE_T_MAX << initial_k);
+
+  n_measurements = (18 - initial_k) | 1;
+  n_measurements = MAX (n_measurements, MIN_REPS);
+  n_measurements = MIN (n_measurements, MAX_REPS);
+
+  last_best_k = initial_k;
+  best_k = initial_k;
+
+  while (n < nmax)
+    {
+      int start_k, end_k;
+
+      /* Assume the current best k is best until we hit its next FFT step.  */
+      t0 = 99999;
+
+      prev_n1 = n + 1;
+
+      start_k = MAX (4, best_k - 4);
+      end_k = MIN (24, best_k + 4);
+      for (k = start_k; k <= end_k; k++)
+	{
+          n1 = mpn_fft_next_size (prev_n1, k);
+
+	  eff = 200 * (n1 * GMP_NUMB_BITS >> k) / fftfill (n1, k, p->sqr);
+
+	  if (eff < 70)		/* avoid measuring too slow fft:s */
+	    continue;
+
+	  if (n1 > alloc)
+	    {
+	      alloc = n1;
+	      if (p->sqr)
+		{
+		  ap = (mp_ptr) realloc (ap, sizeof (mp_limb_t));
+		  rp = (mp_ptr) realloc (rp, sizeof (mp_limb_t));
+		  ap = bp = (mp_ptr) realloc (ap, alloc * sizeof (mp_limb_t));
+		  mpn_random (ap, alloc);
+		  rp = (mp_ptr) realloc (rp, alloc * sizeof (mp_limb_t));
+		}
+	      else
+		{
+		  ap = (mp_ptr) realloc (ap, sizeof (mp_limb_t));
+		  bp = (mp_ptr) realloc (bp, sizeof (mp_limb_t));
+		  rp = (mp_ptr) realloc (rp, sizeof (mp_limb_t));
+		  ap = (mp_ptr) realloc (ap, alloc * sizeof (mp_limb_t));
+		  mpn_random (ap, alloc);
+		  bp = (mp_ptr) realloc (bp, alloc * sizeof (mp_limb_t));
+		  mpn_random (bp, alloc);
+		  rp = (mp_ptr) realloc (rp, alloc * sizeof (mp_limb_t));
+		}
+	    }
+
+	  t1 = cached_measure (rp, ap, bp, n1, k, n_measurements);
+
+	  if (t1 * n_measurements > 0.3)
+	    n_measurements -= 2;
+	  n_measurements = MAX (n_measurements, MIN_REPS);
+
+	  if (t1 < t0)
+	    {
+	      best_k = k;
+	      t0 = t1;
+	    }
+	}
+
+      n1 = mpn_fft_next_size (prev_n1, best_k);
+
+      if (last_best_k != best_k)
+	{
+	  ASSERT_ALWAYS ((prev_n1 & ((1ul << last_best_k) - 1)) == 1);
+
+	  if (idx >= FFT_TABLE3_SIZE)
+	    {
+	      printf ("FFT table exhausted, increase FFT_TABLE3_SIZE in gmp-impl.h\n");
+	      abort ();
+	    }
+	  INSERT_FFTTAB (idx, prev_n1 >> last_best_k, best_k);
+
+	  if (print)
+	    {
+	      printf (", ");
+	      if (idx % 4 == 0)
+		printf ("\\\n    ");
+	      printf ("{%7u,%2u}", fft_tab[idx].n, fft_tab[idx].k);
+	    }
+
+	  if (option_trace >= 2)
+	    {
+	      printf ("{%lu,%u}\n", prev_n1, best_k);
+	      fflush (stdout);
+	    }
+
+	  last_best_k = best_k;
+	  idx++;
+	}
+
+      for (;;)
+	{
+	  prev_n1 = n1;
+	  prev_eff = fftfill (prev_n1, best_k, p->sqr);
+	  n1 = mpn_fft_next_size (prev_n1 + 1, best_k);
+	  eff = fftfill (n1, best_k, p->sqr);
+
+	  if (eff != prev_eff)
+	    break;
+	}
+
+      n = prev_n1;
+    }
+
+  kmax = sizeof (mp_size_t) * 4;	/* GMP_MP_SIZE_T_BITS / 2 */
+  kmax = MIN (kmax, 25-1);
+  for (k = last_best_k + 1; k <= kmax; k++)
+    {
+      if (idx >= FFT_TABLE3_SIZE)
+	{
+	  printf ("FFT table exhausted, increase FFT_TABLE3_SIZE in gmp-impl.h\n");
+	  abort ();
+	}
+      INSERT_FFTTAB (idx, ((1ul << (2*k-2)) + 1) >> (k-1), k);
+
+      if (print)
+	{
+	  printf (", ");
+	  if (idx % 4 == 0)
+	    printf ("\\\n    ");
+	  printf ("{%7u,%2u}", fft_tab[idx].n, fft_tab[idx].k);
+	}
+
+      idx++;
+    }
+
+  if (print)
+    printf (" }\n");
+
+  free (ap);
+  if (! p->sqr)
+    free (bp);
+  free (rp);
+
+  return idx;
+}
+
+void
+fft (struct fft_param_t *p)
+{
+  mp_size_t  size;
+  int        k, idx, initial_k;
+
+  /*** Generate MUL_FFT_MODF_THRESHOLD / SQR_FFT_MODF_THRESHOLD ***/
+
+#if 1
+  {
+    /* Use plain one() mechanism, for some reasonable initial values of k.  The
+       advantage is that we don't depend on mpn_fft_table3, which can therefore
+       leave it completely uninitialized.  */
+
+    static struct param_t param;
+    mp_size_t thres, best_thres;
+    int best_k;
+    char buf[20];
+
+    best_thres = MP_SIZE_T_MAX;
+    best_k = -1;
+
+    for (k = 5; k <= 7; k++)
+      {
+	param.name = p->modf_threshold_name;
+	param.min_size = 100;
+	param.max_size = 2000;
+	param.function  = p->mul_function;
+	param.step_factor = 0.0;
+	param.step = 4;
+	param.function2 = p->mul_modf_function;
+	param.noprint = 1;
+	s.r = k;
+	one (&thres, &param);
+	if (thres < best_thres)
+	  {
+	    best_thres = thres;
+	    best_k = k;
+	  }
+      }
+
+    *(p->p_modf_threshold) = best_thres;
+    sprintf (buf, "k = %d", best_k);
+    print_define_remark (p->modf_threshold_name, best_thres, buf);
+    initial_k = best_k;
+  }
+#else
+  size = p->first_size;
+  for (;;)
+    {
+      double  tk, tm;
+
+      size = mpn_fft_next_size (size+1, mpn_fft_best_k (size+1, p->sqr));
+      k = mpn_fft_best_k (size, p->sqr);
+
+      if (size >= p->max_size)
+        break;
+
+      s.size = size + fft_step_size (k) / 2;
+      s.r = k;
+      tk = tuneup_measure (p->mul_modf_function, NULL, &s);
+      if (tk == -1.0)
+        abort ();
+
+      tm = tuneup_measure (p->mul_function, NULL, &s);
+      if (tm == -1.0)
+        abort ();
+
+      if (option_trace >= 2)
+        printf ("at %ld   size=%ld  k=%d  %.9f   size=%ld modf %.9f\n",
+                (long) size,
+                (long) size + fft_step_size (k) / 2, k, tk,
+                (long) s.size, tm);
+
+      if (tk < tm)
+        {
+	  *p->p_modf_threshold = s.size;
+	  print_define (p->modf_threshold_name, *p->p_modf_threshold);
+	  break;
+        }
+    }
+  initial_k = ?;
+#endif
+
+  /*** Generate MUL_FFT_TABLE3 / SQR_FFT_TABLE3 ***/
+
+  idx = fftmes (*p->p_modf_threshold, p->max_size, initial_k, p, 0, 1);
+  printf ("#define %s_SIZE %d\n", p->table_name, idx);
+
+  /*** Generate MUL_FFT_THRESHOLD / SQR_FFT_THRESHOLD ***/
+
+  size = 2 * *p->p_modf_threshold;	/* OK? */
+  for (;;)
+    {
+      double  tk, tm;
+      mp_size_t mulmod_size, mul_size;;
+
+      if (size >= p->max_size)
+        break;
+
+      mulmod_size = mpn_mulmod_bnm1_next_size (2 * (size + 1)) / 2;
+      mul_size = (size + mulmod_size) / 2;	/* middle of step */
+
+      s.size = mulmod_size;
+      tk = tuneup_measure (p->function, NULL, &s);
+      if (tk == -1.0)
+        abort ();
+
+      s.size = mul_size;
+      tm = tuneup_measure (p->mul_function, NULL, &s);
+      if (tm == -1.0)
+        abort ();
+
+      if (option_trace >= 2)
+        printf ("at %ld   size=%ld  %.9f   size=%ld mul %.9f\n",
+                (long) size,
+                (long) mulmod_size, tk,
+                (long) mul_size, tm);
+
+      size = mulmod_size;
+
+      if (tk < tm)
+        {
+	  *p->p_threshold = s.size;
+	  print_define (p->threshold_name, *p->p_threshold);
+	  break;
+        }
+    }
+}
+
+/* Compare mpn_mul_1 to whatever fast exact single-limb division we have.  This
+   is currently mpn_divexact_1, but will become mpn_bdiv_1_qr_pi2 or somesuch.
+   This is used in get_str and set_str.  */
+void
+relspeed_div_1_vs_mul_1 (void)
+{
+  const size_t max_opsize = 100;
+  mp_size_t n;
+  long j;
+  mp_limb_t rp[max_opsize];
+  mp_limb_t ap[max_opsize];
+  double multime, divtime;
+
+  mpn_random (ap, max_opsize);
+
+  multime = 0;
+  for (n = max_opsize; n > 1; n--)
+    {
+      mpn_mul_1 (rp, ap, n, MP_BASES_BIG_BASE_10);
+      speed_starttime ();
+      for (j = speed_precision; j != 0 ; j--)
+	mpn_mul_1 (rp, ap, n, MP_BASES_BIG_BASE_10);
+      multime += speed_endtime () / n;
+    }
+
+  divtime = 0;
+  for (n = max_opsize; n > 1; n--)
+    {
+      /* Make input divisible for good measure.  */
+      ap[n - 1] = mpn_mul_1 (ap, ap, n - 1, MP_BASES_BIG_BASE_10);
+
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1 || ! HAVE_NATIVE_mpn_divexact_1
+	  mpn_pi1_bdiv_q_1 (rp, ap, n, MP_BASES_BIG_BASE_10,
+			    MP_BASES_BIG_BASE_BINVERTED_10,
+			    MP_BASES_BIG_BASE_CTZ_10);
+#else
+	  mpn_divexact_1 (rp, ap, n, MP_BASES_BIG_BASE_10);
+#endif
+      speed_starttime ();
+      for (j = speed_precision; j != 0 ; j--)
+	{
+#if HAVE_NATIVE_mpn_pi1_bdiv_q_1 || ! HAVE_NATIVE_mpn_divexact_1
+	  mpn_pi1_bdiv_q_1 (rp, ap, n, MP_BASES_BIG_BASE_10,
+			    MP_BASES_BIG_BASE_BINVERTED_10,
+			    MP_BASES_BIG_BASE_CTZ_10);
+#else
+	  mpn_divexact_1 (rp, ap, n, MP_BASES_BIG_BASE_10);
+#endif
+	}
+      divtime += speed_endtime () / n;
+    }
+
+  print_define ("DIV_1_VS_MUL_1_PERCENT", (int) (100 * divtime/multime));
+}
+
+
+/* Start karatsuba from 4, since the Cray t90 ieee code is much faster at 2,
+   giving wrong results.  */
+void
+tune_mul_n (void)
+{
+  static struct param_t  param;
+  mp_size_t next_toom_start;
+  int something_changed;
+
+  param.function = speed_mpn_mul_n;
+
+  param.name = "MUL_TOOM22_THRESHOLD";
+  param.min_size = MAX (4, MPN_TOOM22_MUL_MINSIZE);
+  param.max_size = MUL_TOOM22_THRESHOLD_LIMIT-1;
+  one (&mul_toom22_threshold, &param);
+
+  param.noprint = 1;
+
+  /* Threshold sequence loop.  Disable functions that would be used in a very
+     narrow range, re-measuring things when that happens.  */
+  something_changed = 1;
+  while (something_changed)
+    {
+      something_changed = 0;
+
+	next_toom_start = mul_toom22_threshold;
+
+	if (mul_toom33_threshold != 0)
+	  {
+	    param.name = "MUL_TOOM33_THRESHOLD";
+	    param.min_size = MAX (next_toom_start, MPN_TOOM33_MUL_MINSIZE);
+	    param.max_size = MUL_TOOM33_THRESHOLD_LIMIT-1;
+	    one (&mul_toom33_threshold, &param);
+
+	    if (next_toom_start * 1.05 >= mul_toom33_threshold)
+	      {
+		mul_toom33_threshold = 0;
+		something_changed = 1;
+	      }
+	  }
+
+	next_toom_start = MAX (next_toom_start, mul_toom33_threshold);
+
+	if (mul_toom44_threshold != 0)
+	  {
+	    param.name = "MUL_TOOM44_THRESHOLD";
+	    param.min_size = MAX (next_toom_start, MPN_TOOM44_MUL_MINSIZE);
+	    param.max_size = MUL_TOOM44_THRESHOLD_LIMIT-1;
+	    one (&mul_toom44_threshold, &param);
+
+	    if (next_toom_start * 1.05 >= mul_toom44_threshold)
+	      {
+		mul_toom44_threshold = 0;
+		something_changed = 1;
+	      }
+	  }
+
+	next_toom_start = MAX (next_toom_start, mul_toom44_threshold);
+
+	if (mul_toom6h_threshold != 0)
+	  {
+	    param.name = "MUL_TOOM6H_THRESHOLD";
+	    param.min_size = MAX (next_toom_start, MPN_TOOM6H_MUL_MINSIZE);
+	    param.max_size = MUL_TOOM6H_THRESHOLD_LIMIT-1;
+	    one (&mul_toom6h_threshold, &param);
+
+	    if (next_toom_start * 1.05 >= mul_toom6h_threshold)
+	      {
+		mul_toom6h_threshold = 0;
+		something_changed = 1;
+	      }
+	  }
+
+	next_toom_start = MAX (next_toom_start, mul_toom6h_threshold);
+
+	if (mul_toom8h_threshold != 0)
+	  {
+	    param.name = "MUL_TOOM8H_THRESHOLD";
+	    param.min_size = MAX (next_toom_start, MPN_TOOM8H_MUL_MINSIZE);
+	    param.max_size = MUL_TOOM8H_THRESHOLD_LIMIT-1;
+	    one (&mul_toom8h_threshold, &param);
+
+	    if (next_toom_start * 1.05 >= mul_toom8h_threshold)
+	      {
+		mul_toom8h_threshold = 0;
+		something_changed = 1;
+	      }
+	  }
+    }
+
+    print_define ("MUL_TOOM33_THRESHOLD", MUL_TOOM33_THRESHOLD);
+    print_define ("MUL_TOOM44_THRESHOLD", MUL_TOOM44_THRESHOLD);
+    print_define ("MUL_TOOM6H_THRESHOLD", MUL_TOOM6H_THRESHOLD);
+    print_define ("MUL_TOOM8H_THRESHOLD", MUL_TOOM8H_THRESHOLD);
+
+  /* disabled until tuned */
+  MUL_FFT_THRESHOLD = MP_SIZE_T_MAX;
+}
+
+void
+tune_mul (void)
+{
+  static struct param_t  param;
+  mp_size_t thres;
+
+  param.noprint = 1;
+
+  param.function = speed_mpn_toom32_for_toom43_mul;
+  param.function2 = speed_mpn_toom43_for_toom32_mul;
+  param.name = "MUL_TOOM32_TO_TOOM43_THRESHOLD";
+  param.min_size = MPN_TOOM43_MUL_MINSIZE * 24 / 17;
+  one (&thres, &param);
+  mul_toom32_to_toom43_threshold = thres * 17 / 24;
+  print_define ("MUL_TOOM32_TO_TOOM43_THRESHOLD", mul_toom32_to_toom43_threshold);
+
+  param.function = speed_mpn_toom32_for_toom53_mul;
+  param.function2 = speed_mpn_toom53_for_toom32_mul;
+  param.name = "MUL_TOOM32_TO_TOOM53_THRESHOLD";
+  param.min_size = MPN_TOOM53_MUL_MINSIZE * 30 / 19;
+  one (&thres, &param);
+  mul_toom32_to_toom53_threshold = thres * 19 / 30;
+  print_define ("MUL_TOOM32_TO_TOOM53_THRESHOLD", mul_toom32_to_toom53_threshold);
+
+  param.function = speed_mpn_toom42_for_toom53_mul;
+  param.function2 = speed_mpn_toom53_for_toom42_mul;
+  param.name = "MUL_TOOM42_TO_TOOM53_THRESHOLD";
+  param.min_size = MPN_TOOM53_MUL_MINSIZE * 20 / 11;
+  one (&thres, &param);
+  mul_toom42_to_toom53_threshold = thres * 11 / 20;
+  print_define ("MUL_TOOM42_TO_TOOM53_THRESHOLD", mul_toom42_to_toom53_threshold);
+
+  param.function = speed_mpn_toom42_mul;
+  param.function2 = speed_mpn_toom63_mul;
+  param.name = "MUL_TOOM42_TO_TOOM63_THRESHOLD";
+  param.min_size = MPN_TOOM63_MUL_MINSIZE * 2;
+  one (&thres, &param);
+  mul_toom42_to_toom63_threshold = thres / 2;
+  print_define ("MUL_TOOM42_TO_TOOM63_THRESHOLD", mul_toom42_to_toom63_threshold);
+
+  /* Use ratio 5/6 when measuring, the middle of the range 2/3 to 1. */
+  param.function = speed_mpn_toom43_for_toom54_mul;
+  param.function2 = speed_mpn_toom54_for_toom43_mul;
+  param.name = "MUL_TOOM43_TO_TOOM54_THRESHOLD";
+  param.min_size = MPN_TOOM54_MUL_MINSIZE * 6 / 5;
+  one (&thres, &param);
+  mul_toom43_to_toom54_threshold = thres * 5 / 6;
+  print_define ("MUL_TOOM43_TO_TOOM54_THRESHOLD", mul_toom43_to_toom54_threshold);
+}
+
+
+void
+tune_mullo (void)
+{
+  static struct param_t  param;
+
+  param.function = speed_mpn_mullo_n;
+
+  param.name = "MULLO_BASECASE_THRESHOLD";
+  param.min_size = 2;
+  param.min_is_always = 1;
+  param.max_size = MULLO_BASECASE_THRESHOLD_LIMIT-1;
+  param.stop_factor = 1.5;
+  param.noprint = 1;
+  one (&mullo_basecase_threshold, &param);
+
+  param.name = "MULLO_DC_THRESHOLD";
+  param.min_size = 8;
+  param.min_is_always = 0;
+  param.max_size = 1000;
+  one (&mullo_dc_threshold, &param);
+
+  if (mullo_basecase_threshold >= mullo_dc_threshold)
+    {
+      print_define ("MULLO_BASECASE_THRESHOLD", mullo_dc_threshold);
+      print_define_remark ("MULLO_DC_THRESHOLD", 0, "never mpn_mullo_basecase");
+    }
+  else
+    {
+      print_define ("MULLO_BASECASE_THRESHOLD", mullo_basecase_threshold);
+      print_define ("MULLO_DC_THRESHOLD", mullo_dc_threshold);
+    }
+
+  if (WANT_FFT && mul_fft_threshold < MP_SIZE_T_MAX / 2)
+    {
+      param.name = "MULLO_MUL_N_THRESHOLD";
+      param.min_size = mullo_dc_threshold;
+      param.max_size = 2 * mul_fft_threshold;
+      param.noprint = 0;
+      param.step_factor = 0.03;
+      one (&mullo_mul_n_threshold, &param);
+    }
+  else
+    print_define_remark ("MULLO_MUL_N_THRESHOLD", MP_SIZE_T_MAX,
+			 "without FFT use mullo forever");
+}
+
+void
+tune_sqrlo (void)
+{
+  static struct param_t  param;
+
+  param.function = speed_mpn_sqrlo;
+
+  param.name = "SQRLO_BASECASE_THRESHOLD";
+  param.min_size = 2;
+  param.min_is_always = 1;
+  param.max_size = SQRLO_BASECASE_THRESHOLD_LIMIT-1;
+  param.stop_factor = 1.5;
+  param.noprint = 1;
+  one (&sqrlo_basecase_threshold, &param);
+
+  param.name = "SQRLO_DC_THRESHOLD";
+  param.min_size = 8;
+  param.min_is_always = 0;
+  param.max_size = SQRLO_DC_THRESHOLD_LIMIT-1;
+  one (&sqrlo_dc_threshold, &param);
+
+  if (sqrlo_basecase_threshold >= sqrlo_dc_threshold)
+    {
+      print_define ("SQRLO_BASECASE_THRESHOLD", sqrlo_dc_threshold);
+      print_define_remark ("SQRLO_DC_THRESHOLD", 0, "never mpn_sqrlo_basecase");
+    }
+  else
+    {
+      print_define ("SQRLO_BASECASE_THRESHOLD", sqrlo_basecase_threshold);
+      print_define ("SQRLO_DC_THRESHOLD", sqrlo_dc_threshold);
+    }
+
+  if (WANT_FFT && sqr_fft_threshold < MP_SIZE_T_MAX / 2)
+    {
+      param.name = "SQRLO_SQR_THRESHOLD";
+      param.min_size = sqrlo_dc_threshold;
+      param.max_size = 2 * sqr_fft_threshold;
+      param.noprint = 0;
+      param.step_factor = 0.03;
+      one (&sqrlo_sqr_threshold, &param);
+    }
+  else
+    print_define_remark ("SQRLO_SQR_THRESHOLD", MP_SIZE_T_MAX,
+			 "without FFT use sqrlo forever");
+}
+
+void
+tune_mulmid (void)
+{
+  static struct param_t  param;
+
+  param.name = "MULMID_TOOM42_THRESHOLD";
+  param.function = speed_mpn_mulmid_n;
+  param.min_size = 4;
+  param.max_size = 100;
+  one (&mulmid_toom42_threshold, &param);
+}
+
+void
+tune_mulmod_bnm1 (void)
+{
+  static struct param_t  param;
+
+  param.name = "MULMOD_BNM1_THRESHOLD";
+  param.function = speed_mpn_mulmod_bnm1;
+  param.min_size = 4;
+  param.max_size = 100;
+  one (&mulmod_bnm1_threshold, &param);
+}
+
+void
+tune_sqrmod_bnm1 (void)
+{
+  static struct param_t  param;
+
+  param.name = "SQRMOD_BNM1_THRESHOLD";
+  param.function = speed_mpn_sqrmod_bnm1;
+  param.min_size = 4;
+  param.max_size = 100;
+  one (&sqrmod_bnm1_threshold, &param);
+}
+
+
+/* Start the basecase from 3, since 1 is a special case, and if mul_basecase
+   is faster only at size==2 then we don't want to bother with extra code
+   just for that.  Start karatsuba from 4 same as MUL above.  */
+
+void
+tune_sqr (void)
+{
+  /* disabled until tuned */
+  SQR_FFT_THRESHOLD = MP_SIZE_T_MAX;
+
+  if (HAVE_NATIVE_mpn_sqr_basecase)
+    {
+      print_define_remark ("SQR_BASECASE_THRESHOLD", 0, "always (native)");
+      sqr_basecase_threshold = 0;
+    }
+  else
+    {
+      static struct param_t  param;
+      param.name = "SQR_BASECASE_THRESHOLD";
+      param.function = speed_mpn_sqr;
+      param.min_size = 3;
+      param.min_is_always = 1;
+      param.max_size = TUNE_SQR_TOOM2_MAX;
+      param.noprint = 1;
+      one (&sqr_basecase_threshold, &param);
+    }
+
+  {
+    static struct param_t  param;
+    param.name = "SQR_TOOM2_THRESHOLD";
+    param.function = speed_mpn_sqr;
+    param.min_size = MAX (4, MPN_TOOM2_SQR_MINSIZE);
+    param.max_size = TUNE_SQR_TOOM2_MAX;
+    param.noprint = 1;
+    one (&sqr_toom2_threshold, &param);
+
+    if (! HAVE_NATIVE_mpn_sqr_basecase
+        && sqr_toom2_threshold < sqr_basecase_threshold)
+      {
+        /* Karatsuba becomes faster than mul_basecase before
+           sqr_basecase does.  Arrange for the expression
+           "BELOW_THRESHOLD (un, SQR_TOOM2_THRESHOLD))" which
+           selects mpn_sqr_basecase in mpn_sqr to be false, by setting
+           SQR_TOOM2_THRESHOLD to zero, making
+           SQR_BASECASE_THRESHOLD the toom2 threshold.  */
+
+        sqr_basecase_threshold = SQR_TOOM2_THRESHOLD;
+        SQR_TOOM2_THRESHOLD = 0;
+
+        print_define_remark ("SQR_BASECASE_THRESHOLD", sqr_basecase_threshold,
+                             "toom2");
+        print_define_remark ("SQR_TOOM2_THRESHOLD",SQR_TOOM2_THRESHOLD,
+                             "never sqr_basecase");
+      }
+    else
+      {
+        if (! HAVE_NATIVE_mpn_sqr_basecase)
+          print_define ("SQR_BASECASE_THRESHOLD", sqr_basecase_threshold);
+        print_define ("SQR_TOOM2_THRESHOLD", SQR_TOOM2_THRESHOLD);
+      }
+  }
+
+  {
+    static struct param_t  param;
+    mp_size_t next_toom_start;
+    int something_changed;
+
+    param.function = speed_mpn_sqr;
+    param.noprint = 1;
+
+  /* Threshold sequence loop.  Disable functions that would be used in a very
+     narrow range, re-measuring things when that happens.  */
+    something_changed = 1;
+    while (something_changed)
+      {
+	something_changed = 0;
+
+	next_toom_start = MAX (sqr_toom2_threshold, sqr_basecase_threshold);
+
+	sqr_toom3_threshold = SQR_TOOM3_THRESHOLD_LIMIT;
+	param.name = "SQR_TOOM3_THRESHOLD";
+	param.min_size = MAX (next_toom_start, MPN_TOOM3_SQR_MINSIZE);
+	param.max_size = SQR_TOOM3_THRESHOLD_LIMIT-1;
+	one (&sqr_toom3_threshold, &param);
+
+	next_toom_start = MAX (next_toom_start, sqr_toom3_threshold);
+
+	if (sqr_toom4_threshold != 0)
+	  {
+	    param.name = "SQR_TOOM4_THRESHOLD";
+	    sqr_toom4_threshold = SQR_TOOM4_THRESHOLD_LIMIT;
+	    param.min_size = MAX (next_toom_start, MPN_TOOM4_SQR_MINSIZE);
+	    param.max_size = SQR_TOOM4_THRESHOLD_LIMIT-1;
+	    one (&sqr_toom4_threshold, &param);
+
+	    if (next_toom_start * 1.05 >= sqr_toom4_threshold)
+	      {
+		sqr_toom4_threshold = 0;
+		something_changed = 1;
+	      }
+	  }
+
+	next_toom_start = MAX (next_toom_start, sqr_toom4_threshold);
+
+	if (sqr_toom6_threshold != 0)
+	  {
+	    param.name = "SQR_TOOM6_THRESHOLD";
+	    sqr_toom6_threshold = SQR_TOOM6_THRESHOLD_LIMIT;
+	    param.min_size = MAX (next_toom_start, MPN_TOOM6_SQR_MINSIZE);
+	    param.max_size = SQR_TOOM6_THRESHOLD_LIMIT-1;
+	    one (&sqr_toom6_threshold, &param);
+
+	    if (next_toom_start * 1.05 >= sqr_toom6_threshold)
+	      {
+		sqr_toom6_threshold = 0;
+		something_changed = 1;
+	      }
+	  }
+
+	next_toom_start = MAX (next_toom_start, sqr_toom6_threshold);
+
+	if (sqr_toom8_threshold != 0)
+	  {
+	    param.name = "SQR_TOOM8_THRESHOLD";
+	    sqr_toom8_threshold = SQR_TOOM8_THRESHOLD_LIMIT;
+	    param.min_size = MAX (next_toom_start, MPN_TOOM8_SQR_MINSIZE);
+	    param.max_size = SQR_TOOM8_THRESHOLD_LIMIT-1;
+	    one (&sqr_toom8_threshold, &param);
+
+	    if (next_toom_start * 1.05 >= sqr_toom8_threshold)
+	      {
+		sqr_toom8_threshold = 0;
+		something_changed = 1;
+	      }
+	  }
+      }
+
+    print_define ("SQR_TOOM3_THRESHOLD", SQR_TOOM3_THRESHOLD);
+    print_define ("SQR_TOOM4_THRESHOLD", SQR_TOOM4_THRESHOLD);
+    print_define ("SQR_TOOM6_THRESHOLD", SQR_TOOM6_THRESHOLD);
+    print_define ("SQR_TOOM8_THRESHOLD", SQR_TOOM8_THRESHOLD);
+  }
+}
+
+
+void
+tune_dc_div (void)
+{
+  s.r = 0;		/* clear to make speed function do 2n/n */
+  {
+    static struct param_t  param;
+    param.name = "DC_DIV_QR_THRESHOLD";
+    param.function = speed_mpn_sbpi1_div_qr;
+    param.function2 = speed_mpn_dcpi1_div_qr;
+    param.min_size = 6;
+    one (&dc_div_qr_threshold, &param);
+  }
+  {
+    static struct param_t  param;
+    param.name = "DC_DIVAPPR_Q_THRESHOLD";
+    param.function = speed_mpn_sbpi1_divappr_q;
+    param.function2 = speed_mpn_dcpi1_divappr_q;
+    param.min_size = 6;
+    one (&dc_divappr_q_threshold, &param);
+  }
+}
+
+static double
+speed_mpn_sbordcpi1_div_qr (struct speed_params *s)
+{
+  if (s->size < DC_DIV_QR_THRESHOLD)
+    return speed_mpn_sbpi1_div_qr (s);
+  else
+    return speed_mpn_dcpi1_div_qr (s);
+}
+
+void
+tune_mu_div (void)
+{
+  s.r = 0;		/* clear to make speed function do 2n/n */
+  {
+    static struct param_t  param;
+    param.name = "MU_DIV_QR_THRESHOLD";
+    param.function = speed_mpn_dcpi1_div_qr;
+    param.function2 = speed_mpn_mu_div_qr;
+    param.min_size = mul_toom22_threshold;
+    param.max_size = 5000;
+    param.step_factor = 0.02;
+    one (&mu_div_qr_threshold, &param);
+  }
+  {
+    static struct param_t  param;
+    param.name = "MU_DIVAPPR_Q_THRESHOLD";
+    param.function = speed_mpn_dcpi1_divappr_q;
+    param.function2 = speed_mpn_mu_divappr_q;
+    param.min_size = mul_toom22_threshold;
+    param.max_size = 5000;
+    param.step_factor = 0.02;
+    one (&mu_divappr_q_threshold, &param);
+  }
+  {
+    static struct param_t  param;
+    param.name = "MUPI_DIV_QR_THRESHOLD";
+    param.function = speed_mpn_sbordcpi1_div_qr;
+    param.function2 = speed_mpn_mupi_div_qr;
+    param.min_size = 6;
+    param.min_is_always = 1;
+    param.max_size = 1000;
+    param.step_factor = 0.02;
+    one (&mupi_div_qr_threshold, &param);
+  }
+}
+
+void
+tune_dc_bdiv (void)
+{
+  s.r = 0;		/* clear to make speed function do 2n/n*/
+  {
+    static struct param_t  param;
+    param.name = "DC_BDIV_QR_THRESHOLD";
+    param.function = speed_mpn_sbpi1_bdiv_qr;
+    param.function2 = speed_mpn_dcpi1_bdiv_qr;
+    param.min_size = 4;
+    one (&dc_bdiv_qr_threshold, &param);
+  }
+  {
+    static struct param_t  param;
+    param.name = "DC_BDIV_Q_THRESHOLD";
+    param.function = speed_mpn_sbpi1_bdiv_q;
+    param.function2 = speed_mpn_dcpi1_bdiv_q;
+    param.min_size = 4;
+    one (&dc_bdiv_q_threshold, &param);
+  }
+}
+
+void
+tune_mu_bdiv (void)
+{
+  s.r = 0;		/* clear to make speed function do 2n/n*/
+  {
+    static struct param_t  param;
+    param.name = "MU_BDIV_QR_THRESHOLD";
+    param.function = speed_mpn_dcpi1_bdiv_qr;
+    param.function2 = speed_mpn_mu_bdiv_qr;
+    param.min_size = dc_bdiv_qr_threshold;
+    param.max_size = 5000;
+    param.step_factor = 0.02;
+    one (&mu_bdiv_qr_threshold, &param);
+  }
+  {
+    static struct param_t  param;
+    param.name = "MU_BDIV_Q_THRESHOLD";
+    param.function = speed_mpn_dcpi1_bdiv_q;
+    param.function2 = speed_mpn_mu_bdiv_q;
+    param.min_size = dc_bdiv_q_threshold;
+    param.max_size = 5000;
+    param.step_factor = 0.02;
+    one (&mu_bdiv_q_threshold, &param);
+  }
+}
+
+void
+tune_invertappr (void)
+{
+  static struct param_t  param;
+
+  param.function = speed_mpn_ni_invertappr;
+  param.name = "INV_MULMOD_BNM1_THRESHOLD";
+  param.min_size = 5;
+  one (&inv_mulmod_bnm1_threshold, &param);
+
+  param.function = speed_mpn_invertappr;
+  param.name = "INV_NEWTON_THRESHOLD";
+  param.min_size = 5;
+  one (&inv_newton_threshold, &param);
+}
+
+void
+tune_invert (void)
+{
+  static struct param_t  param;
+
+  param.function = speed_mpn_invert;
+  param.name = "INV_APPR_THRESHOLD";
+  param.min_size = 5;
+  one (&inv_appr_threshold, &param);
+}
+
+void
+tune_binvert (void)
+{
+  static struct param_t  param;
+
+  param.function = speed_mpn_binvert;
+  param.name = "BINV_NEWTON_THRESHOLD";
+  param.min_size = 8;		/* pointless with smaller operands */
+  one (&binv_newton_threshold, &param);
+}
+
+void
+tune_redc (void)
+{
+#define TUNE_REDC_2_MAX 100
+#if HAVE_NATIVE_mpn_addmul_2 || HAVE_NATIVE_mpn_redc_2
+#define WANT_REDC_2 1
+#endif
+
+#if WANT_REDC_2
+  {
+    static struct param_t  param;
+    param.name = "REDC_1_TO_REDC_2_THRESHOLD";
+    param.function = speed_mpn_redc_1;
+    param.function2 = speed_mpn_redc_2;
+    param.min_size = 1;
+    param.min_is_always = 1;
+    param.max_size = TUNE_REDC_2_MAX;
+    param.noprint = 1;
+    param.stop_factor = 1.5;
+    one (&redc_1_to_redc_2_threshold, &param);
+  }
+  {
+    static struct param_t  param;
+    param.name = "REDC_2_TO_REDC_N_THRESHOLD";
+    param.function = speed_mpn_redc_2;
+    param.function2 = speed_mpn_redc_n;
+    param.min_size = 16;
+    param.noprint = 1;
+    one (&redc_2_to_redc_n_threshold, &param);
+  }
+  if (redc_1_to_redc_2_threshold >= redc_2_to_redc_n_threshold)
+    {
+      redc_2_to_redc_n_threshold = 0;	/* disable redc_2 */
+
+      /* Never use redc2, measure redc_1 -> redc_n cutoff, store result as
+	 REDC_1_TO_REDC_2_THRESHOLD.  */
+      {
+	static struct param_t  param;
+	param.name = "REDC_1_TO_REDC_2_THRESHOLD";
+	param.function = speed_mpn_redc_1;
+	param.function2 = speed_mpn_redc_n;
+	param.min_size = 16;
+	param.noprint = 1;
+	one (&redc_1_to_redc_2_threshold, &param);
+      }
+    }
+  print_define ("REDC_1_TO_REDC_2_THRESHOLD", REDC_1_TO_REDC_2_THRESHOLD);
+  print_define ("REDC_2_TO_REDC_N_THRESHOLD", REDC_2_TO_REDC_N_THRESHOLD);
+#else
+  {
+    static struct param_t  param;
+    param.name = "REDC_1_TO_REDC_N_THRESHOLD";
+    param.function = speed_mpn_redc_1;
+    param.function2 = speed_mpn_redc_n;
+    param.min_size = 16;
+    one (&redc_1_to_redc_n_threshold, &param);
+  }
+#endif
+}
+
+void
+tune_matrix22_mul (void)
+{
+  static struct param_t  param;
+  param.name = "MATRIX22_STRASSEN_THRESHOLD";
+  param.function = speed_mpn_matrix22_mul;
+  param.min_size = 2;
+  one (&matrix22_strassen_threshold, &param);
+}
+
+void
+tune_hgcd2 (void)
+{
+  static struct param_t  param;
+  hgcd2_func_t *f[5] =
+    { mpn_hgcd2_1,
+      mpn_hgcd2_2,
+      mpn_hgcd2_3,
+      mpn_hgcd2_4,
+      mpn_hgcd2_5 };
+  speed_function_t speed_f[5] =
+    { speed_mpn_hgcd2_1,
+      speed_mpn_hgcd2_2,
+      speed_mpn_hgcd2_3,
+      speed_mpn_hgcd2_4,
+      speed_mpn_hgcd2_5 };
+  int best;
+
+  s.size = 1;
+  best = one_method (5, speed_f, "mpn_hgcd2", "HGCD2_DIV1_METHOD", &param);
+
+  /* Use selected function when tuning hgcd and gcd */
+  hgcd2_func = f[best];
+}
+
+void
+tune_hgcd (void)
+{
+  static struct param_t  param;
+  param.name = "HGCD_THRESHOLD";
+  param.function = speed_mpn_hgcd;
+  /* We seem to get strange results for small sizes */
+  param.min_size = 30;
+  one (&hgcd_threshold, &param);
+}
+
+void
+tune_hgcd_appr (void)
+{
+  static struct param_t  param;
+  param.name = "HGCD_APPR_THRESHOLD";
+  param.function = speed_mpn_hgcd_appr;
+  /* We seem to get strange results for small sizes */
+  param.min_size = 50;
+  param.stop_since_change = 150;
+  one (&hgcd_appr_threshold, &param);
+}
+
+void
+tune_hgcd_reduce (void)
+{
+  static struct param_t  param;
+  param.name = "HGCD_REDUCE_THRESHOLD";
+  param.function = speed_mpn_hgcd_reduce;
+  param.min_size = 30;
+  param.max_size = 7000;
+  param.step_factor = 0.04;
+  one (&hgcd_reduce_threshold, &param);
+}
+
+void
+tune_gcd_dc (void)
+{
+  static struct param_t  param;
+  param.name = "GCD_DC_THRESHOLD";
+  param.function = speed_mpn_gcd;
+  param.min_size = hgcd_threshold;
+  param.max_size = 3000;
+  param.step_factor = 0.02;
+  one (&gcd_dc_threshold, &param);
+}
+
+void
+tune_gcdext_dc (void)
+{
+  static struct param_t  param;
+  param.name = "GCDEXT_DC_THRESHOLD";
+  param.function = speed_mpn_gcdext;
+  param.min_size = hgcd_threshold;
+  param.max_size = 3000;
+  param.step_factor = 0.02;
+  one (&gcdext_dc_threshold, &param);
+}
+
+/* In tune_powm_sec we compute the table used by the win_size function.  The
+   cutoff points are in exponent bits, disregarding other operand sizes.  It is
+   not possible to use the one framework since it currently uses a granularity
+   of full limbs.
+*/
+
+/* This win_size replaces the variant in the powm code, allowing us to
+   control k in the k-ary algorithms.  */
+int winsize;
+int
+win_size (mp_bitcnt_t eb)
+{
+  return winsize;
+}
+
+void
+tune_powm_sec (void)
+{
+  mp_size_t n;
+  int k, i;
+  mp_size_t itch;
+  mp_bitcnt_t nbits, nbits_next, possible_nbits_cutoff;
+  const int n_max = 3000 / GMP_NUMB_BITS;
+  const int n_measurements = 5;
+  mp_ptr rp, bp, ep, mp, tp;
+  double ttab[n_measurements], tk, tkp1;
+  TMP_DECL;
+  TMP_MARK;
+
+  possible_nbits_cutoff = 0;
+
+  k = 1;
+
+  winsize = 10;			/* the itch function needs this */
+  itch = mpn_sec_powm_itch (n_max, n_max * GMP_NUMB_BITS, n_max);
+
+  rp = TMP_ALLOC_LIMBS (n_max);
+  bp = TMP_ALLOC_LIMBS (n_max);
+  ep = TMP_ALLOC_LIMBS (n_max);
+  mp = TMP_ALLOC_LIMBS (n_max);
+  tp = TMP_ALLOC_LIMBS (itch);
+
+  mpn_random (bp, n_max);
+  mpn_random (mp, n_max);
+  mp[0] |= 1;
+
+/* How about taking the M operand size into account?
+
+   An operation R=powm(B,E,N) will take time O(log(E)*M(log(N))) (assuming
+   B = O(M)).
+
+   Using k-ary and no sliding window, the precomputation will need time
+   O(2^(k-1)*M(log(N))) and the main computation will need O(log(E)*S(N)) +
+   O(log(E)/k*M(N)), for the squarings, multiplications, respectively.
+
+   An operation R=powm_sec(B,E,N) will take time like powm.
+
+   Using k-ary, the precomputation will need time O(2^k*M(log(N))) and the
+   main computation will need O(log(E)*S(N)) + O(log(E)/k*M(N)) +
+   O(log(E)/k*2^k*log(N)), for the squarings, multiplications, and full
+   table reads, respectively.  */
+
+  printf ("#define POWM_SEC_TABLE  ");
+
+  /* For nbits == 1, we should always use k == 1, so no need to tune
+     that. Starting with nbits == 2 also ensure that nbits always is
+     larger than the windowsize k+1. */
+  for (nbits = 2; nbits <= n_max * GMP_NUMB_BITS; )
+    {
+      n = (nbits - 1) / GMP_NUMB_BITS + 1;
+
+      /* Generate E such that sliding-window for k and k+1 works equally
+	 well/poorly (but sliding is not used in powm_sec, of course). */
+      for (i = 0; i < n; i++)
+	ep[i] = ~CNST_LIMB(0);
+
+      winsize = k;
+      for (i = 0; i < n_measurements; i++)
+	{
+	  speed_starttime ();
+	  mpn_sec_powm (rp, bp, n, ep, nbits, mp, n, tp);
+	  ttab[i] = speed_endtime ();
+	}
+      tk = median (ttab, n_measurements);
+
+      winsize = k + 1;
+      speed_starttime ();
+      for (i = 0; i < n_measurements; i++)
+	{
+	  speed_starttime ();
+	  mpn_sec_powm (rp, bp, n, ep, nbits, mp, n, tp);
+	  ttab[i] = speed_endtime ();
+	}
+      tkp1 = median (ttab, n_measurements);
+/*
+      printf ("testing: %ld, %d", nbits, k, ep[n-1]);
+      printf ("   %10.5f  %10.5f\n", tk, tkp1);
+*/
+      if (tkp1 < tk)
+	{
+	  if (possible_nbits_cutoff)
+	    {
+	      /* Two consecutive sizes indicate k increase, obey.  */
+
+	      /* Must always have x[k] >= k */
+	      ASSERT_ALWAYS (possible_nbits_cutoff >= k);
+
+	      if (k > 1)
+		printf (",");
+	      printf ("%ld", (long) possible_nbits_cutoff);
+	      k++;
+	      possible_nbits_cutoff = 0;
+	    }
+	  else
+	    {
+	      /* One measurement indicate k increase, save nbits for further
+		 consideration.  */
+	      /* The new larger k gets used for sizes > the cutoff
+		 value, hence the cutoff should be one less than the
+		 smallest size where it gives a speedup. */
+	      possible_nbits_cutoff = nbits - 1;
+	    }
+	}
+      else
+	possible_nbits_cutoff = 0;
+
+      nbits_next = nbits * 65 / 64;
+      nbits = nbits_next + (nbits_next == nbits);
+    }
+  printf ("\n");
+  TMP_FREE;
+}
+
+
+/* size_extra==1 reflects the fact that with high<divisor one division is
+   always skipped.  Forcing high<divisor while testing ensures consistency
+   while stepping through sizes, ie. that size-1 divides will be done each
+   time.
+
+   min_size==2 and min_is_always are used so that if plain division is only
+   better at size==1 then don't bother including that code just for that
+   case, instead go with preinv always and get a size saving.  */
+
+#define DIV_1_PARAMS                    \
+  param.check_size = 256;               \
+  param.min_size = 2;                   \
+  param.min_is_always = 1;              \
+  param.data_high = DATA_HIGH_LT_R;     \
+  param.size_extra = 1;                 \
+  param.stop_factor = 2.0;
+
+
+double (*tuned_speed_mpn_divrem_1) (struct speed_params *);
+
+void
+tune_divrem_1 (void)
+{
+  /* plain version by default */
+  tuned_speed_mpn_divrem_1 = speed_mpn_divrem_1;
+
+  /* No support for tuning native assembler code, do that by hand and put
+     the results in the .asm file, there's no need for such thresholds to
+     appear in gmp-mparam.h.  */
+  if (HAVE_NATIVE_mpn_divrem_1)
+    return;
+
+  if (GMP_NAIL_BITS != 0)
+    {
+      print_define_remark ("DIVREM_1_NORM_THRESHOLD", MP_SIZE_T_MAX,
+                           "no preinv with nails");
+      print_define_remark ("DIVREM_1_UNNORM_THRESHOLD", MP_SIZE_T_MAX,
+                           "no preinv with nails");
+      return;
+    }
+
+  if (UDIV_PREINV_ALWAYS)
+    {
+      print_define_remark ("DIVREM_1_NORM_THRESHOLD", 0L, "preinv always");
+      print_define ("DIVREM_1_UNNORM_THRESHOLD", 0L);
+      return;
+    }
+
+  tuned_speed_mpn_divrem_1 = speed_mpn_divrem_1_tune;
+
+  /* Tune for the integer part of mpn_divrem_1.  This will very possibly be
+     a bit out for the fractional part, but that's too bad, the integer part
+     is more important. */
+  {
+    static struct param_t  param;
+    param.name = "DIVREM_1_NORM_THRESHOLD";
+    DIV_1_PARAMS;
+    s.r = randlimb_norm ();
+    param.function = speed_mpn_divrem_1_tune;
+    one (&divrem_1_norm_threshold, &param);
+  }
+  {
+    static struct param_t  param;
+    param.name = "DIVREM_1_UNNORM_THRESHOLD";
+    DIV_1_PARAMS;
+    s.r = randlimb_half ();
+    param.function = speed_mpn_divrem_1_tune;
+    one (&divrem_1_unnorm_threshold, &param);
+  }
+}
+
+void
+tune_div_qr_1 (void)
+{
+  if (!HAVE_NATIVE_mpn_div_qr_1n_pi1)
+    {
+      static struct param_t  param;
+      speed_function_t f[2] =
+	{
+	 speed_mpn_div_qr_1n_pi1_1,
+	 speed_mpn_div_qr_1n_pi1_2,
+	};
+
+      s.size = 10;
+      s.r = randlimb_norm ();
+
+      one_method (2, f, "mpn_div_qr_1n_pi1", "DIV_QR_1N_PI1_METHOD", &param);
+    }
+
+  {
+    static struct param_t  param;
+    param.name = "DIV_QR_1_NORM_THRESHOLD";
+    DIV_1_PARAMS;
+    param.min_size = 1;
+    param.min_is_always = 0;
+    s.r = randlimb_norm ();
+    param.function = speed_mpn_div_qr_1_tune;
+    one (&div_qr_1_norm_threshold, &param);
+  }
+  {
+    static struct param_t  param;
+    param.name = "DIV_QR_1_UNNORM_THRESHOLD";
+    DIV_1_PARAMS;
+    param.min_size = 1;
+    param.min_is_always = 0;
+    s.r = randlimb_half();
+    param.function = speed_mpn_div_qr_1_tune;
+    one (&div_qr_1_unnorm_threshold, &param);
+  }
+}
+
+
+void
+tune_mod_1 (void)
+{
+  /* No support for tuning native assembler code, do that by hand and put
+     the results in the .asm file, there's no need for such thresholds to
+     appear in gmp-mparam.h.  */
+  if (HAVE_NATIVE_mpn_mod_1)
+    return;
+
+  if (GMP_NAIL_BITS != 0)
+    {
+      print_define_remark ("MOD_1_NORM_THRESHOLD", MP_SIZE_T_MAX,
+                           "no preinv with nails");
+      print_define_remark ("MOD_1_UNNORM_THRESHOLD", MP_SIZE_T_MAX,
+                           "no preinv with nails");
+      return;
+    }
+
+  if (!HAVE_NATIVE_mpn_mod_1_1p)
+    {
+      static struct param_t  param;
+      speed_function_t f[2] =
+	{
+	 speed_mpn_mod_1_1_1,
+	 speed_mpn_mod_1_1_2,
+	};
+
+      s.size = 10;
+      s.r = randlimb_half ();
+      one_method (2, f, "mpn_mod_1_1", "MOD_1_1P_METHOD", &param);
+    }
+
+  if (UDIV_PREINV_ALWAYS)
+    {
+      print_define ("MOD_1_NORM_THRESHOLD", 0L);
+      print_define ("MOD_1_UNNORM_THRESHOLD", 0L);
+    }
+  else
+    {
+      {
+	static struct param_t  param;
+	param.name = "MOD_1_NORM_THRESHOLD";
+	DIV_1_PARAMS;
+	s.r = randlimb_norm ();
+	param.function = speed_mpn_mod_1_tune;
+	one (&mod_1_norm_threshold, &param);
+      }
+      {
+	static struct param_t  param;
+	param.name = "MOD_1_UNNORM_THRESHOLD";
+	DIV_1_PARAMS;
+	s.r = randlimb_half ();
+	param.function = speed_mpn_mod_1_tune;
+	one (&mod_1_unnorm_threshold, &param);
+      }
+    }
+  {
+    static struct param_t  param;
+
+    param.check_size = 256;
+
+    s.r = randlimb_norm ();
+    param.function = speed_mpn_mod_1_tune;
+
+    param.name = "MOD_1N_TO_MOD_1_1_THRESHOLD";
+    param.min_size = 2;
+    one (&mod_1n_to_mod_1_1_threshold, &param);
+  }
+
+  {
+    static struct param_t  param;
+
+    param.check_size = 256;
+    s.r = randlimb_half ();
+    param.noprint = 1;
+
+    param.function = speed_mpn_mod_1_1;
+    param.function2 = speed_mpn_mod_1_2;
+    param.min_is_always = 1;
+    param.name = "MOD_1_1_TO_MOD_1_2_THRESHOLD";
+    param.min_size = 2;
+    one (&mod_1_1_to_mod_1_2_threshold, &param);
+
+    param.function = speed_mpn_mod_1_2;
+    param.function2 = speed_mpn_mod_1_4;
+    param.min_is_always = 1;
+    param.name = "MOD_1_2_TO_MOD_1_4_THRESHOLD";
+    param.min_size = 1;
+    one (&mod_1_2_to_mod_1_4_threshold, &param);
+
+    if (mod_1_1_to_mod_1_2_threshold >= mod_1_2_to_mod_1_4_threshold)
+      {
+	/* Never use mod_1_2, measure mod_1_1 -> mod_1_4 */
+	mod_1_2_to_mod_1_4_threshold = 0;
+
+	param.function = speed_mpn_mod_1_1;
+	param.function2 = speed_mpn_mod_1_4;
+	param.min_is_always = 1;
+	param.name = "MOD_1_1_TO_MOD_1_4_THRESHOLD fake";
+	param.min_size = 2;
+	one (&mod_1_1_to_mod_1_2_threshold, &param);
+      }
+
+    param.function = speed_mpn_mod_1_tune;
+    param.function2 = NULL;
+    param.name = "MOD_1U_TO_MOD_1_1_THRESHOLD";
+    param.min_size = 2;
+    param.min_is_always = 0;
+    one (&mod_1u_to_mod_1_1_threshold, &param);
+
+    if (mod_1u_to_mod_1_1_threshold >= mod_1_1_to_mod_1_2_threshold)
+      mod_1_1_to_mod_1_2_threshold = 0;
+    if (mod_1u_to_mod_1_1_threshold >= mod_1_2_to_mod_1_4_threshold)
+      mod_1_2_to_mod_1_4_threshold = 0;
+
+    print_define_remark ("MOD_1U_TO_MOD_1_1_THRESHOLD", mod_1u_to_mod_1_1_threshold, NULL);
+    print_define_remark ("MOD_1_1_TO_MOD_1_2_THRESHOLD", mod_1_1_to_mod_1_2_threshold,
+			 mod_1_1_to_mod_1_2_threshold == 0 ? "never mpn_mod_1_1p" : NULL);
+    print_define_remark ("MOD_1_2_TO_MOD_1_4_THRESHOLD", mod_1_2_to_mod_1_4_threshold,
+			 mod_1_2_to_mod_1_4_threshold == 0 ? "never mpn_mod_1s_2p" : NULL);
+  }
+
+  {
+    static struct param_t  param;
+
+    param.check_size = 256;
+
+    param.name = "PREINV_MOD_1_TO_MOD_1_THRESHOLD";
+    s.r = randlimb_norm ();
+    param.function = speed_mpn_preinv_mod_1;
+    param.function2 = speed_mpn_mod_1_tune;
+    param.min_size = 1;
+    one (&preinv_mod_1_to_mod_1_threshold, &param);
+  }
+}
+
+
+/* A non-zero DIVREM_1_UNNORM_THRESHOLD (or DIVREM_1_NORM_THRESHOLD) would
+   imply that udiv_qrnnd_preinv is worth using, but it seems most
+   straightforward to compare mpn_preinv_divrem_1 and mpn_divrem_1_div
+   directly.  */
+
+void
+tune_preinv_divrem_1 (void)
+{
+  static struct param_t  param;
+  speed_function_t  divrem_1;
+  const char        *divrem_1_name;
+  double            t1, t2;
+
+  if (GMP_NAIL_BITS != 0)
+    {
+      print_define_remark ("USE_PREINV_DIVREM_1", 0, "no preinv with nails");
+      return;
+    }
+
+  /* Any native version of mpn_preinv_divrem_1 is assumed to exist because
+     it's faster than mpn_divrem_1.  */
+  if (HAVE_NATIVE_mpn_preinv_divrem_1)
+    {
+      print_define_remark ("USE_PREINV_DIVREM_1", 1, "native");
+      return;
+    }
+
+  /* If udiv_qrnnd_preinv is the only division method then of course
+     mpn_preinv_divrem_1 should be used.  */
+  if (UDIV_PREINV_ALWAYS)
+    {
+      print_define_remark ("USE_PREINV_DIVREM_1", 1, "preinv always");
+      return;
+    }
+
+  /* If we've got an assembler version of mpn_divrem_1, then compare against
+     that, not the mpn_divrem_1_div generic C.  */
+  if (HAVE_NATIVE_mpn_divrem_1)
+    {
+      divrem_1 = speed_mpn_divrem_1;
+      divrem_1_name = "mpn_divrem_1";
+    }
+  else
+    {
+      divrem_1 = speed_mpn_divrem_1_div;
+      divrem_1_name = "mpn_divrem_1_div";
+    }
+
+  param.data_high = DATA_HIGH_LT_R; /* allow skip one division */
+  s.size = 200;                     /* generous but not too big */
+  /* Divisor, nonzero.  Unnormalized so as to exercise the shift!=0 case,
+     since in general that's probably most common, though in fact for a
+     64-bit limb mp_bases[10].big_base is normalized.  */
+  s.r = urandom() & (GMP_NUMB_MASK >> 4);
+  if (s.r == 0) s.r = 123;
+
+  t1 = tuneup_measure (speed_mpn_preinv_divrem_1, &param, &s);
+  t2 = tuneup_measure (divrem_1, &param, &s);
+  if (t1 == -1.0 || t2 == -1.0)
+    {
+      printf ("Oops, can't measure mpn_preinv_divrem_1 and %s at %ld\n",
+              divrem_1_name, (long) s.size);
+      abort ();
+    }
+  if (option_trace >= 1)
+    printf ("size=%ld, mpn_preinv_divrem_1 %.9f, %s %.9f\n",
+            (long) s.size, t1, divrem_1_name, t2);
+
+  print_define_remark ("USE_PREINV_DIVREM_1", (mp_size_t) (t1 < t2), NULL);
+}
+
+
+
+void
+tune_divrem_2 (void)
+{
+  static struct param_t  param;
+
+  /* No support for tuning native assembler code, do that by hand and put
+     the results in the .asm file, and there's no need for such thresholds
+     to appear in gmp-mparam.h.  */
+  if (HAVE_NATIVE_mpn_divrem_2)
+    return;
+
+  if (GMP_NAIL_BITS != 0)
+    {
+      print_define_remark ("DIVREM_2_THRESHOLD", MP_SIZE_T_MAX,
+                           "no preinv with nails");
+      return;
+    }
+
+  if (UDIV_PREINV_ALWAYS)
+    {
+      print_define_remark ("DIVREM_2_THRESHOLD", 0L, "preinv always");
+      return;
+    }
+
+  /* Tune for the integer part of mpn_divrem_2.  This will very possibly be
+     a bit out for the fractional part, but that's too bad, the integer part
+     is more important.
+
+     min_size must be >=2 since nsize>=2 is required, but is set to 4 to save
+     code space if plain division is better only at size==2 or size==3. */
+  param.name = "DIVREM_2_THRESHOLD";
+  param.check_size = 256;
+  param.min_size = 4;
+  param.min_is_always = 1;
+  param.size_extra = 2;      /* does qsize==nsize-2 divisions */
+  param.stop_factor = 2.0;
+
+  s.r = randlimb_norm ();
+  param.function = speed_mpn_divrem_2;
+  one (&divrem_2_threshold, &param);
+}
+
+void
+tune_div_qr_2 (void)
+{
+  static struct param_t  param;
+  param.name = "DIV_QR_2_PI2_THRESHOLD";
+  param.function = speed_mpn_div_qr_2n;
+  param.check_size = 500;
+  param.min_size = 4;
+  one (&div_qr_2_pi2_threshold, &param);
+}
+
+/* mpn_divexact_1 is vaguely expected to be used on smallish divisors, so
+   tune for that.  Its speed can differ on odd or even divisor, so take an
+   average threshold for the two.
+
+   mpn_divrem_1 can vary with high<divisor or not, whereas mpn_divexact_1
+   might not vary that way, but don't test this since high<divisor isn't
+   expected to occur often with small divisors.  */
+
+void
+tune_divexact_1 (void)
+{
+  static struct param_t  param;
+  mp_size_t  thresh[2], average;
+  int        low, i;
+
+  /* Any native mpn_divexact_1 is assumed to incorporate all the speed of a
+     full mpn_divrem_1.  */
+  if (HAVE_NATIVE_mpn_divexact_1)
+    {
+      print_define_remark ("DIVEXACT_1_THRESHOLD", 0, "always (native)");
+      return;
+    }
+
+  ASSERT_ALWAYS (tuned_speed_mpn_divrem_1 != NULL);
+
+  param.name = "DIVEXACT_1_THRESHOLD";
+  param.data_high = DATA_HIGH_GE_R;
+  param.check_size = 256;
+  param.min_size = 2;
+  param.stop_factor = 1.5;
+  param.function  = tuned_speed_mpn_divrem_1;
+  param.function2 = speed_mpn_divexact_1;
+  param.noprint = 1;
+
+  print_define_start (param.name);
+
+  for (low = 0; low <= 1; low++)
+    {
+      s.r = randlimb_half();
+      if (low == 0)
+        s.r |= 1;
+      else
+        s.r &= ~CNST_LIMB(7);
+
+      one (&thresh[low], &param);
+      if (option_trace)
+        printf ("low=%d thresh %ld\n", low, (long) thresh[low]);
+
+      if (thresh[low] == MP_SIZE_T_MAX)
+        {
+          average = MP_SIZE_T_MAX;
+          goto divexact_1_done;
+        }
+    }
+
+  if (option_trace)
+    {
+      printf ("average of:");
+      for (i = 0; i < numberof(thresh); i++)
+        printf (" %ld", (long) thresh[i]);
+      printf ("\n");
+    }
+
+  average = 0;
+  for (i = 0; i < numberof(thresh); i++)
+    average += thresh[i];
+  average /= numberof(thresh);
+
+  /* If divexact turns out to be better as early as 3 limbs, then use it
+     always, so as to reduce code size and conditional jumps.  */
+  if (average <= 3)
+    average = 0;
+
+ divexact_1_done:
+  print_define_end (param.name, average);
+}
+
+
+/* The generic mpn_modexact_1_odd skips a divide step if high<divisor, the
+   same as mpn_mod_1, but this might not be true of an assembler
+   implementation.  The threshold used is an average based on data where a
+   divide can be skipped and where it can't.
+
+   If modexact turns out to be better as early as 3 limbs, then use it
+   always, so as to reduce code size and conditional jumps.  */
+
+void
+tune_modexact_1_odd (void)
+{
+  static struct param_t  param;
+  mp_size_t  thresh_lt, thresh_ge, average;
+
+#if 0
+  /* Any native mpn_modexact_1_odd is assumed to incorporate all the speed
+     of a full mpn_mod_1.  */
+  if (HAVE_NATIVE_mpn_modexact_1_odd)
+    {
+      print_define_remark ("BMOD_1_TO_MOD_1_THRESHOLD", MP_SIZE_T_MAX, "always bmod_1");
+      return;
+    }
+#endif
+
+  param.name = "BMOD_1_TO_MOD_1_THRESHOLD";
+  param.check_size = 256;
+  param.min_size = 2;
+  param.stop_factor = 1.5;
+  param.function  = speed_mpn_modexact_1c_odd;
+  param.function2 = speed_mpn_mod_1_tune;
+  param.noprint = 1;
+  s.r = randlimb_half () | 1;
+
+  print_define_start (param.name);
+
+  param.data_high = DATA_HIGH_LT_R;
+  one (&thresh_lt, &param);
+  if (option_trace)
+    printf ("lt thresh %ld\n", (long) thresh_lt);
+
+  average = thresh_lt;
+  if (thresh_lt != MP_SIZE_T_MAX)
+    {
+      param.data_high = DATA_HIGH_GE_R;
+      one (&thresh_ge, &param);
+      if (option_trace)
+        printf ("ge thresh %ld\n", (long) thresh_ge);
+
+      if (thresh_ge != MP_SIZE_T_MAX)
+        {
+          average = (thresh_ge + thresh_lt) / 2;
+          if (thresh_ge <= 3)
+            average = 0;
+        }
+    }
+
+  print_define_end (param.name, average);
+}
+
+
+void
+tune_jacobi_base (void)
+{
+  static struct param_t  param;
+  speed_function_t f[4] =
+    {
+     speed_mpn_jacobi_base_1,
+     speed_mpn_jacobi_base_2,
+     speed_mpn_jacobi_base_3,
+     speed_mpn_jacobi_base_4,
+    };
+
+  s.size = GMP_LIMB_BITS * 3 / 4;
+
+  one_method (4, f, "mpn_jacobi_base", "JACOBI_BASE_METHOD", &param);
+}
+
+
+void
+tune_get_str (void)
+{
+  /* Tune for decimal, it being most common.  Some rough testing suggests
+     other bases are different, but not by very much.  */
+  s.r = 10;
+  {
+    static struct param_t  param;
+    GET_STR_PRECOMPUTE_THRESHOLD = 0;
+    param.name = "GET_STR_DC_THRESHOLD";
+    param.function = speed_mpn_get_str;
+    param.min_size = 4;
+    param.max_size = GET_STR_THRESHOLD_LIMIT;
+    one (&get_str_dc_threshold, &param);
+  }
+  {
+    static struct param_t  param;
+    param.name = "GET_STR_PRECOMPUTE_THRESHOLD";
+    param.function = speed_mpn_get_str;
+    param.min_size = GET_STR_DC_THRESHOLD;
+    param.max_size = GET_STR_THRESHOLD_LIMIT;
+    one (&get_str_precompute_threshold, &param);
+  }
+}
+
+
+double
+speed_mpn_pre_set_str (struct speed_params *s)
+{
+  unsigned char *str;
+  mp_ptr     wp;
+  mp_size_t  wn;
+  unsigned   i;
+  int        base;
+  double     t;
+  mp_ptr powtab_mem, tp;
+  powers_t powtab[GMP_LIMB_BITS];
+  mp_size_t un;
+  int chars_per_limb;
+  TMP_DECL;
+
+  SPEED_RESTRICT_COND (s->size >= 1);
+
+  base = s->r == 0 ? 10 : s->r;
+  SPEED_RESTRICT_COND (base >= 2 && base <= 256);
+
+  TMP_MARK;
+
+  str = (unsigned char *) TMP_ALLOC (s->size);
+  for (i = 0; i < s->size; i++)
+    str[i] = s->xp[i] % base;
+
+  LIMBS_PER_DIGIT_IN_BASE (wn, s->size, base);
+  SPEED_TMP_ALLOC_LIMBS (wp, wn, s->align_wp);
+
+  /* use this during development to check wn is big enough */
+  /*
+  ASSERT_ALWAYS (mpn_set_str (wp, str, s->size, base) <= wn);
+  */
+
+  speed_operand_src (s, (mp_ptr) str, s->size/GMP_LIMB_BYTES);
+  speed_operand_dst (s, wp, wn);
+  speed_cache_fill (s);
+
+  chars_per_limb = mp_bases[base].chars_per_limb;
+  un = s->size / chars_per_limb + 1;
+  powtab_mem = TMP_BALLOC_LIMBS (mpn_str_powtab_alloc (un));
+  size_t n_pows = mpn_compute_powtab (powtab, powtab_mem, un, base);
+  powers_t *pt = powtab + n_pows;
+  tp = TMP_BALLOC_LIMBS (mpn_dc_set_str_itch (un));
+
+  speed_starttime ();
+  i = s->reps;
+  do
+    {
+      mpn_pre_set_str (wp, str, s->size, pt, tp);
+    }
+  while (--i != 0);
+  t = speed_endtime ();
+
+  TMP_FREE;
+  return t;
+}
+
+void
+tune_set_str (void)
+{
+  s.r = 10;  /* decimal */
+  {
+    static struct param_t  param;
+    SET_STR_PRECOMPUTE_THRESHOLD = 0;
+    param.step_factor = 0.01;
+    param.name = "SET_STR_DC_THRESHOLD";
+    param.function = speed_mpn_pre_set_str;
+    param.min_size = 100;
+    param.max_size = 50000;
+    one (&set_str_dc_threshold, &param);
+  }
+  {
+    static struct param_t  param;
+    param.step_factor = 0.02;
+    param.name = "SET_STR_PRECOMPUTE_THRESHOLD";
+    param.function = speed_mpn_set_str;
+    param.min_size = SET_STR_DC_THRESHOLD;
+    param.max_size = 100000;
+    one (&set_str_precompute_threshold, &param);
+  }
+}
+
+
+void
+tune_fft_mul (void)
+{
+  static struct fft_param_t  param;
+
+  if (option_fft_max_size == 0)
+    return;
+
+  param.table_name          = "MUL_FFT_TABLE3";
+  param.threshold_name      = "MUL_FFT_THRESHOLD";
+  param.p_threshold         = &mul_fft_threshold;
+  param.modf_threshold_name = "MUL_FFT_MODF_THRESHOLD";
+  param.p_modf_threshold    = &mul_fft_modf_threshold;
+  param.first_size          = MUL_TOOM33_THRESHOLD / 2;
+  param.max_size            = option_fft_max_size;
+  param.function            = speed_mpn_fft_mul;
+  param.mul_modf_function   = speed_mpn_mul_fft;
+  param.mul_function        = speed_mpn_mul_n;
+  param.sqr = 0;
+  fft (&param);
+}
+
+
+void
+tune_fft_sqr (void)
+{
+  static struct fft_param_t  param;
+
+  if (option_fft_max_size == 0)
+    return;
+
+  param.table_name          = "SQR_FFT_TABLE3";
+  param.threshold_name      = "SQR_FFT_THRESHOLD";
+  param.p_threshold         = &sqr_fft_threshold;
+  param.modf_threshold_name = "SQR_FFT_MODF_THRESHOLD";
+  param.p_modf_threshold    = &sqr_fft_modf_threshold;
+  param.first_size          = SQR_TOOM3_THRESHOLD / 2;
+  param.max_size            = option_fft_max_size;
+  param.function            = speed_mpn_fft_sqr;
+  param.mul_modf_function   = speed_mpn_mul_fft_sqr;
+  param.mul_function        = speed_mpn_sqr;
+  param.sqr = 1;
+  fft (&param);
+}
+
+void
+tune_fac_ui (void)
+{
+  static struct param_t  param;
+
+  param.function = speed_mpz_fac_ui_tune;
+
+  param.name = "FAC_DSC_THRESHOLD";
+  param.min_size = 70;
+  param.max_size = FAC_DSC_THRESHOLD_LIMIT;
+  one (&fac_dsc_threshold, &param);
+
+  param.name = "FAC_ODD_THRESHOLD";
+  param.min_size = 22;
+  param.stop_factor = 1.7;
+  param.min_is_always = 1;
+  one (&fac_odd_threshold, &param);
+}
+
+void
+all (void)
+{
+  time_t  start_time, end_time;
+  TMP_DECL;
+
+  TMP_MARK;
+  SPEED_TMP_ALLOC_LIMBS (s.xp_block, SPEED_BLOCK_SIZE, 0);
+  SPEED_TMP_ALLOC_LIMBS (s.yp_block, SPEED_BLOCK_SIZE, 0);
+
+  mpn_random (s.xp_block, SPEED_BLOCK_SIZE);
+  mpn_random (s.yp_block, SPEED_BLOCK_SIZE);
+
+  fprintf (stderr, "Parameters for %s\n", GMP_MPARAM_H_SUGGEST);
+
+  speed_time_init ();
+  fprintf (stderr, "Using: %s\n", speed_time_string);
+
+  fprintf (stderr, "speed_precision %d", speed_precision);
+  if (speed_unittime == 1.0)
+    fprintf (stderr, ", speed_unittime 1 cycle");
+  else
+    fprintf (stderr, ", speed_unittime %.2e secs", speed_unittime);
+  if (speed_cycletime == 1.0 || speed_cycletime == 0.0)
+    fprintf (stderr, ", CPU freq unknown\n");
+  else
+    fprintf (stderr, ", CPU freq %.2f MHz\n", 1e-6/speed_cycletime);
+
+  fprintf (stderr, "DEFAULT_MAX_SIZE %d, fft_max_size %ld\n",
+           DEFAULT_MAX_SIZE, (long) option_fft_max_size);
+  fprintf (stderr, "\n");
+
+  time (&start_time);
+  {
+    struct tm  *tp;
+    tp = localtime (&start_time);
+    printf ("/* Generated by tuneup.c, %d-%02d-%02d, ",
+            tp->tm_year+1900, tp->tm_mon+1, tp->tm_mday);
+
+#ifdef __GNUC__
+    /* gcc sub-minor version doesn't seem to come through as a define */
+    printf ("gcc %d.%d */\n", __GNUC__, __GNUC_MINOR__);
+#define PRINTED_COMPILER
+#endif
+#if defined (__SUNPRO_C)
+    printf ("Sun C %d.%d */\n", __SUNPRO_C / 0x100, __SUNPRO_C % 0x100);
+#define PRINTED_COMPILER
+#endif
+#if ! defined (__GNUC__) && defined (__sgi) && defined (_COMPILER_VERSION)
+    /* gcc defines __sgi and _COMPILER_VERSION on irix 6, avoid that */
+    printf ("MIPSpro C %d.%d.%d */\n",
+	    _COMPILER_VERSION / 100,
+	    _COMPILER_VERSION / 10 % 10,
+	    _COMPILER_VERSION % 10);
+#define PRINTED_COMPILER
+#endif
+#if defined (__DECC) && defined (__DECC_VER)
+    printf ("DEC C %d */\n", __DECC_VER);
+#define PRINTED_COMPILER
+#endif
+#if ! defined (PRINTED_COMPILER)
+    printf ("system compiler */\n");
+#endif
+  }
+  printf ("\n");
+
+  tune_divrem_1 ();
+  tune_mod_1 ();
+  tune_preinv_divrem_1 ();
+  tune_div_qr_1 ();
+#if 0
+  tune_divrem_2 ();
+#endif
+  tune_div_qr_2 ();
+  tune_divexact_1 ();
+  tune_modexact_1_odd ();
+  printf("\n");
+
+  relspeed_div_1_vs_mul_1 ();
+  printf("\n");
+
+  tune_mul_n ();
+  printf("\n");
+
+  tune_mul ();
+  printf("\n");
+
+  tune_sqr ();
+  printf("\n");
+
+  tune_mulmid ();
+  printf("\n");
+
+  tune_mulmod_bnm1 ();
+  tune_sqrmod_bnm1 ();
+  printf("\n");
+
+  tune_fft_mul ();
+  printf("\n");
+
+  tune_fft_sqr ();
+  printf ("\n");
+
+  tune_mullo ();
+  tune_sqrlo ();
+  printf("\n");
+
+  tune_dc_div ();
+  tune_dc_bdiv ();
+
+  printf("\n");
+  tune_invertappr ();
+  tune_invert ();
+  printf("\n");
+
+  tune_binvert ();
+  tune_redc ();
+  printf("\n");
+
+  tune_mu_div ();
+  tune_mu_bdiv ();
+  printf("\n");
+
+  tune_powm_sec ();
+  printf("\n");
+
+  tune_get_str ();
+  tune_set_str ();
+  printf("\n");
+
+  tune_fac_ui ();
+  printf("\n");
+
+  tune_matrix22_mul ();
+  tune_hgcd2 ();
+  tune_hgcd ();
+  tune_hgcd_appr ();
+  tune_hgcd_reduce();
+  tune_gcd_dc ();
+  tune_gcdext_dc ();
+  tune_jacobi_base ();
+  printf("\n");
+
+  time (&end_time);
+  printf ("/* Tuneup completed successfully, took %ld seconds */\n",
+          (long) (end_time - start_time));
+
+  TMP_FREE;
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  int  opt;
+
+  /* Unbuffered so if output is redirected to a file it isn't lost if the
+     program is killed part way through.  */
+  setbuf (stdout, NULL);
+  setbuf (stderr, NULL);
+
+  while ((opt = getopt(argc, argv, "f:o:p:t")) != EOF)
+    {
+      switch (opt) {
+      case 'f':
+        if (optarg[0] == 't')
+          option_fft_trace = 2;
+        else
+          option_fft_max_size = atol (optarg);
+        break;
+      case 'o':
+        speed_option_set (optarg);
+        break;
+      case 'p':
+        speed_precision = atoi (optarg);
+        break;
+      case 't':
+        option_trace++;
+        break;
+      case '?':
+        exit(1);
+      }
+    }
+
+  all ();
+  exit (0);
+}
diff --git a/third_party/gmp/tune/x86_64.asm b/third_party/gmp/tune/x86_64.asm
new file mode 100644
index 0000000..b7ec44c
--- /dev/null
+++ b/third_party/gmp/tune/x86_64.asm
@@ -0,0 +1,55 @@
+dnl  x86 pentium time stamp counter access routine.
+
+dnl  Copyright 1999, 2000, 2003-2005 Free Software Foundation, Inc.
+
+dnl  This file is part of the GNU MP Library.
+dnl
+dnl  The GNU MP Library is free software; you can redistribute it and/or modify
+dnl  it under the terms of either:
+dnl
+dnl    * the GNU Lesser General Public License as published by the Free
+dnl      Software Foundation; either version 3 of the License, or (at your
+dnl      option) any later version.
+dnl
+dnl  or
+dnl
+dnl    * the GNU General Public License as published by the Free Software
+dnl      Foundation; either version 2 of the License, or (at your option) any
+dnl      later version.
+dnl
+dnl  or both in parallel, as here.
+dnl
+dnl  The GNU MP Library is distributed in the hope that it will be useful, but
+dnl  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+dnl  for more details.
+dnl
+dnl  You should have received copies of the GNU General Public License and the
+dnl  GNU Lesser General Public License along with the GNU MP Library.  If not,
+dnl  see https://www.gnu.org/licenses/.
+
+
+include(`../config.m4')
+
+
+C void speed_cyclecounter (unsigned p[2]);
+C
+C Get the pentium rdtsc cycle counter, storing the least significant word in
+C p[0] and the most significant in p[1].
+C
+C cpuid is used to serialize execution.  On big measurements this won't be
+C significant but it may help make small single measurements more accurate.
+
+PROLOGUE(speed_cyclecounter)
+
+	C rdi	p
+
+	movq	%rbx, %r10
+	xorl	%eax, %eax
+	cpuid
+	rdtsc
+	movl	%eax, (%rdi)
+	movl	%edx, 4(%rdi)
+	movq	%r10, %rbx
+	ret
+EPILOGUE()
diff --git a/third_party/gmp/version.c b/third_party/gmp/version.c
new file mode 100644
index 0000000..ee7c32a
--- /dev/null
+++ b/third_party/gmp/version.c
@@ -0,0 +1,33 @@
+/* gmp_version -- version number compiled into the library.
+
+Copyright 1996, 1999-2001 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+  * the GNU Lesser General Public License as published by the Free
+    Software Foundation; either version 3 of the License, or (at your
+    option) any later version.
+
+or
+
+  * the GNU General Public License as published by the Free Software
+    Foundation; either version 2 of the License, or (at your option) any
+    later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library.  If not,
+see https://www.gnu.org/licenses/.  */
+
+#include "gmp-impl.h"
+
+const char * const gmp_version = VERSION;
diff --git a/third_party/gmp/ylwrap b/third_party/gmp/ylwrap
new file mode 100755
index 0000000..7c2d927
--- /dev/null
+++ b/third_party/gmp/ylwrap
@@ -0,0 +1,247 @@
+#! /bin/sh
+# ylwrap - wrapper for lex/yacc invocations.
+
+scriptversion=2013-01-12.17; # UTC
+
+# Copyright (C) 1996-2014 Free Software Foundation, Inc.
+#
+# Written by Tom Tromey <tromey@cygnus.com>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+get_dirname ()
+{
+  case $1 in
+    */*|*\\*) printf '%s\n' "$1" | sed -e 's|\([\\/]\)[^\\/]*$|\1|';;
+    # Otherwise,  we want the empty string (not ".").
+  esac
+}
+
+# guard FILE
+# ----------
+# The CPP macro used to guard inclusion of FILE.
+guard ()
+{
+  printf '%s\n' "$1"                                                    \
+    | sed                                                               \
+        -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'   \
+        -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g'                        \
+        -e 's/__*/_/g'
+}
+
+# quote_for_sed [STRING]
+# ----------------------
+# Return STRING (or stdin) quoted to be used as a sed pattern.
+quote_for_sed ()
+{
+  case $# in
+    0) cat;;
+    1) printf '%s\n' "$1";;
+  esac \
+    | sed -e 's|[][\\.*]|\\&|g'
+}
+
+case "$1" in
+  '')
+    echo "$0: No files given.  Try '$0 --help' for more information." 1>&2
+    exit 1
+    ;;
+  --basedir)
+    basedir=$2
+    shift 2
+    ;;
+  -h|--h*)
+    cat <<\EOF
+Usage: ylwrap [--help|--version] INPUT [OUTPUT DESIRED]... -- PROGRAM [ARGS]...
+
+Wrapper for lex/yacc invocations, renaming files as desired.
+
+  INPUT is the input file
+  OUTPUT is one file PROG generates
+  DESIRED is the file we actually want instead of OUTPUT
+  PROGRAM is program to run
+  ARGS are passed to PROG
+
+Any number of OUTPUT,DESIRED pairs may be used.
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+    exit $?
+    ;;
+  -v|--v*)
+    echo "ylwrap $scriptversion"
+    exit $?
+    ;;
+esac
+
+
+# The input.
+input=$1
+shift
+# We'll later need for a correct munging of "#line" directives.
+input_sub_rx=`get_dirname "$input" | quote_for_sed`
+case $input in
+  [\\/]* | ?:[\\/]*)
+    # Absolute path; do nothing.
+    ;;
+  *)
+    # Relative path.  Make it absolute.
+    input=`pwd`/$input
+    ;;
+esac
+input_rx=`get_dirname "$input" | quote_for_sed`
+
+# Since DOS filename conventions don't allow two dots,
+# the DOS version of Bison writes out y_tab.c instead of y.tab.c
+# and y_tab.h instead of y.tab.h. Test to see if this is the case.
+y_tab_nodot=false
+if test -f y_tab.c || test -f y_tab.h; then
+  y_tab_nodot=true
+fi
+
+# The parser itself, the first file, is the destination of the .y.c
+# rule in the Makefile.
+parser=$1
+
+# A sed program to s/FROM/TO/g for all the FROM/TO so that, for
+# instance, we rename #include "y.tab.h" into #include "parse.h"
+# during the conversion from y.tab.c to parse.c.
+sed_fix_filenames=
+
+# Also rename header guards, as Bison 2.7 for instance uses its header
+# guard in its implementation file.
+sed_fix_header_guards=
+
+while test $# -ne 0; do
+  if test x"$1" = x"--"; then
+    shift
+    break
+  fi
+  from=$1
+  # Handle y_tab.c and y_tab.h output by DOS
+  if $y_tab_nodot; then
+    case $from in
+      "y.tab.c") from=y_tab.c;;
+      "y.tab.h") from=y_tab.h;;
+    esac
+  fi
+  shift
+  to=$1
+  shift
+  sed_fix_filenames="${sed_fix_filenames}s|"`quote_for_sed "$from"`"|$to|g;"
+  sed_fix_header_guards="${sed_fix_header_guards}s|"`guard "$from"`"|"`guard "$to"`"|g;"
+done
+
+# The program to run.
+prog=$1
+shift
+# Make any relative path in $prog absolute.
+case $prog in
+  [\\/]* | ?:[\\/]*) ;;
+  *[\\/]*) prog=`pwd`/$prog ;;
+esac
+
+dirname=ylwrap$$
+do_exit="cd '`pwd`' && rm -rf $dirname > /dev/null 2>&1;"' (exit $ret); exit $ret'
+trap "ret=129; $do_exit" 1
+trap "ret=130; $do_exit" 2
+trap "ret=141; $do_exit" 13
+trap "ret=143; $do_exit" 15
+mkdir $dirname || exit 1
+
+cd $dirname
+
+case $# in
+  0) "$prog" "$input" ;;
+  *) "$prog" "$@" "$input" ;;
+esac
+ret=$?
+
+if test $ret -eq 0; then
+  for from in *
+  do
+    to=`printf '%s\n' "$from" | sed "$sed_fix_filenames"`
+    if test -f "$from"; then
+      # If $2 is an absolute path name, then just use that,
+      # otherwise prepend '../'.
+      case $to in
+        [\\/]* | ?:[\\/]*) target=$to;;
+        *) target=../$to;;
+      esac
+
+      # Do not overwrite unchanged header files to avoid useless
+      # recompilations.  Always update the parser itself: it is the
+      # destination of the .y.c rule in the Makefile.  Divert the
+      # output of all other files to a temporary file so we can
+      # compare them to existing versions.
+      if test $from != $parser; then
+        realtarget=$target
+        target=tmp-`printf '%s\n' "$target" | sed 's|.*[\\/]||g'`
+      fi
+
+      # Munge "#line" or "#" directives.  Don't let the resulting
+      # debug information point at an absolute srcdir.  Use the real
+      # output file name, not yy.lex.c for instance.  Adjust the
+      # include guards too.
+      sed -e "/^#/!b"                           \
+          -e "s|$input_rx|$input_sub_rx|"       \
+          -e "$sed_fix_filenames"               \
+          -e "$sed_fix_header_guards"           \
+        "$from" >"$target" || ret=$?
+
+      # Check whether files must be updated.
+      if test "$from" != "$parser"; then
+        if test -f "$realtarget" && cmp -s "$realtarget" "$target"; then
+          echo "$to is unchanged"
+          rm -f "$target"
+        else
+          echo "updating $to"
+          mv -f "$target" "$realtarget"
+        fi
+      fi
+    else
+      # A missing file is only an error for the parser.  This is a
+      # blatant hack to let us support using "yacc -d".  If -d is not
+      # specified, don't fail when the header file is "missing".
+      if test "$from" = "$parser"; then
+        ret=1
+      fi
+    fi
+  done
+fi
+
+# Remove the directory.
+cd ..
+rm -rf $dirname
+
+exit $ret
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/third_party/julia/julia.BUILD b/third_party/julia/julia.BUILD
index 94988ca..7f25671 100644
--- a/third_party/julia/julia.BUILD
+++ b/third_party/julia/julia.BUILD
@@ -1,18 +1,21 @@
 load("@rules_pkg//:pkg.bzl", "pkg_tar")
-load(":files.bzl", "LIB_SYMLINKS", "LIBS")
+load(":files.bzl", "LIBS", "LIB_SYMLINKS")
 
 pkg_tar(
     name = "runtime",
     srcs = LIBS + [
         "bin/julia",
-    ] + glob([
-        "share/julia/**/*.jl",
-        "share/julia/**/*.toml",
-        "include/julia/**/*",
-    ], exclude = [
-        "**/test/**",
-    ]),
-    symlinks = LIB_SYMLINKS,
+    ] + glob(
+        [
+            "share/julia/**/*.jl",
+            "share/julia/**/*.toml",
+            "include/julia/**/*",
+        ],
+        exclude = [
+            "**/test/**",
+        ],
+    ),
     strip_prefix = "external/julia",
+    symlinks = LIB_SYMLINKS,
     visibility = ["//visibility:public"],
 )
diff --git a/third_party/python/BUILD b/third_party/python/BUILD
index 46c464c..5e3278a 100644
--- a/third_party/python/BUILD
+++ b/third_party/python/BUILD
@@ -2,10 +2,6 @@
 
 cc_library(
     name = "python",
-    deps = [
-        "@python3_9_x86_64-unknown-linux-gnu//:python_headers",
-        "@python3_9_x86_64-unknown-linux-gnu//:libpython",
-    ],
     defines = [
         "FRC971_UPSTREAM_BUNDLED_PYTHON",
         "FRC971_PYTHON_HOME=../python3_9_x86_64-unknown-linux-gnu/",
@@ -15,6 +11,10 @@
         "@platforms//os:linux",
     ],
     visibility = ["//visibility:public"],
+    deps = [
+        "@python3_9_x86_64-unknown-linux-gnu//:libpython",
+        "@python3_9_x86_64-unknown-linux-gnu//:python_headers",
+    ],
 )
 
 filegroup(
@@ -31,8 +31,8 @@
 
 extract_numpy_headers(
     name = "numpy_headers",
-    numpy = "@pip//numpy",
     header_prefix = "numpy_headers",
+    numpy = "@pip//numpy",
     visibility = ["//visibility:private"],
 )
 
@@ -44,8 +44,8 @@
     includes = [
         "numpy_headers",
     ],
+    visibility = ["//visibility:public"],
     deps = [
         ":python",
     ],
-    visibility = ["//visibility:public"],
 )
diff --git a/third_party/vl53l1x/vl53l1x.BUILD b/third_party/vl53l1x/vl53l1x.BUILD
index 13ea7fd..9d7e776 100644
--- a/third_party/vl53l1x/vl53l1x.BUILD
+++ b/third_party/vl53l1x/vl53l1x.BUILD
@@ -1,26 +1,25 @@
-
 cc_library(
-  name = "VL53L1X",
-  srcs = [
-    "core/VL53L1X_api.c",
-    "core/VL53L1X_calibration.c",
-    "platform/vl53l1_platform.c",
-  ],
-  hdrs = [
-    "core/VL53L1X_api.h",
-    "core/VL53L1X_calibration.h",
-    "platform/vl53l1_platform.h",
-    "platform/vl53l1_types.h",
-  ],
-  target_compatible_with = [
-    "@platforms//os:none",
-    "@//tools/platforms/hardware:cortex_m0plus",
-  ],
-  copts = [
-    "-Wno-unused-parameter",
-  ],
-  visibility = ["//visibility:public"],
-  deps = [
-    "@//third_party/pico-sdk",
-  ],
+    name = "VL53L1X",
+    srcs = [
+        "core/VL53L1X_api.c",
+        "core/VL53L1X_calibration.c",
+        "platform/vl53l1_platform.c",
+    ],
+    hdrs = [
+        "core/VL53L1X_api.h",
+        "core/VL53L1X_calibration.h",
+        "platform/vl53l1_platform.h",
+        "platform/vl53l1_types.h",
+    ],
+    copts = [
+        "-Wno-unused-parameter",
+    ],
+    target_compatible_with = [
+        "@platforms//os:none",
+        "@//tools/platforms/hardware:cortex_m0plus",
+    ],
+    visibility = ["//visibility:public"],
+    deps = [
+        "@//third_party/pico-sdk",
+    ],
 )
diff --git a/third_party/websocketpp/websocketpp.BUILD b/third_party/websocketpp/websocketpp.BUILD
index ecf12cd..436e47f 100644
--- a/third_party/websocketpp/websocketpp.BUILD
+++ b/third_party/websocketpp/websocketpp.BUILD
@@ -4,7 +4,10 @@
 cc_library(
     name = "com_github_zaphoyd_websocketpp",
     hdrs = glob(["websocketpp/**/*.hpp"]),
-    defines = ["_WEBSOCKETPP_CPP11_STL_", "ASIO_STANDALONE"],
+    defines = [
+        "_WEBSOCKETPP_CPP11_STL_",
+        "ASIO_STANDALONE",
+    ],
     includes = ["."],
     visibility = ["//visibility:public"],
     deps = ["@asio"],
diff --git a/third_party/xvfb/xvfb.BUILD b/third_party/xvfb/xvfb.BUILD
index 91332ff..f03e322 100644
--- a/third_party/xvfb/xvfb.BUILD
+++ b/third_party/xvfb/xvfb.BUILD
@@ -31,13 +31,13 @@
 sh_binary(
     name = "wrapped_bin/Xvfb",
     srcs = ["wrapped_bin/Xvfb.sh"],
-    deps = [
-        "@bazel_tools//tools/bash/runfiles",
-    ],
     data = glob([
         "usr/lib/**/*",
         "lib/**/*",
         "usr/bin/*",
     ]),
     visibility = ["//visibility:public"],
+    deps = [
+        "@bazel_tools//tools/bash/runfiles",
+    ],
 )
diff --git a/third_party/y2023/field/BUILD b/third_party/y2023/field/BUILD
index de1d382..a806293 100644
--- a/third_party/y2023/field/BUILD
+++ b/third_party/y2023/field/BUILD
@@ -1,14 +1,14 @@
 filegroup(
     name = "pictures",
     srcs = [
-     # Picture from the FIRST inspires field drawings.
-     # https://www.firstinspires.org/robotics/frc/playing-field
-     # Copyright 2023 FIRST
-     "2023.png",
-     # Picture from FIRST modified by Tea Fazio.
-     # https://firstfrc.blob.core.windows.net/frc2023/Manual/2023FRCGameManual.pdf
-     # Copyright 2023 FIRST
-     "field.jpg",
- ],
+        # Picture from the FIRST inspires field drawings.
+        # https://www.firstinspires.org/robotics/frc/playing-field
+        # Copyright 2023 FIRST
+        "2023.png",
+        # Picture from FIRST modified by Tea Fazio.
+        # https://firstfrc.blob.core.windows.net/frc2023/Manual/2023FRCGameManual.pdf
+        # Copyright 2023 FIRST
+        "field.jpg",
+    ],
     visibility = ["//visibility:public"],
 )
diff --git a/third_party/y2024/field/BUILD b/third_party/y2024/field/BUILD
index 04db591..4b2bbff 100644
--- a/third_party/y2024/field/BUILD
+++ b/third_party/y2024/field/BUILD
@@ -1,11 +1,11 @@
 filegroup(
     name = "pictures",
     srcs = [
-     # Picture from the FIRST inspires field drawings.
-     "2024.png",
-     # https://www.firstinspires.org/robotics/frc/playing-field
-     # Copyright 2024 FIRST
-     "2024_field.png",
- ],
+        # Picture from the FIRST inspires field drawings.
+        "2024.png",
+        # https://www.firstinspires.org/robotics/frc/playing-field
+        # Copyright 2024 FIRST
+        "2024_field.png",
+    ],
     visibility = ["//visibility:public"],
-)
\ No newline at end of file
+)
diff --git a/tools/bazel b/tools/bazel
index 3c6a359..78e171f 100755
--- a/tools/bazel
+++ b/tools/bazel
@@ -99,7 +99,7 @@
 ENVIRONMENT_VARIABLES+=(HOSTNAME="${HOSTNAME}")
 ENVIRONMENT_VARIABLES+=(SHELL="${SHELL}")
 ENVIRONMENT_VARIABLES+=(USER="${USER}")
-ENVIRONMENT_VARIABLES+=(PATH="/usr/bin:/bin")
+ENVIRONMENT_VARIABLES+=(PATH="${PATH}")
 ENVIRONMENT_VARIABLES+=(HOME="${HOME}")
 ENVIRONMENT_VARIABLES+=(TERM="${TERM}")
 ENVIRONMENT_VARIABLES+=(LANG="${LANG:-C}")
diff --git a/tools/build_rules/foxglove.bzl b/tools/build_rules/foxglove.bzl
new file mode 100644
index 0000000..cfcab92
--- /dev/null
+++ b/tools/build_rules/foxglove.bzl
@@ -0,0 +1,46 @@
+load("@aspect_rules_js//js:defs.bzl", "js_run_binary")
+
+def foxglove_extension(name, **kwargs):
+    """Compiles a foxglove extension into a .foxe file.
+
+    Drag the generated .foxe file onto the foxglove UI in your browser. The
+    extension should then install automatically. If you want to update the
+    extension, drag a new version to the UI.
+
+    Use `tools/foxglove/create-foxglove-extension`. Don't use this rule
+    directly. See `tools/foxglove/README.md` for more details.
+
+    Args:
+        name: The name of the target.
+        **kwargs: The arguments to pass to js_run_binary.
+    """
+
+    # We need to glob all the non-Bazel files because we're going to invoke the
+    # `foxglove-extension` binary directly. That expects to have access to
+    # `package.json` and the like.
+    all_files = native.glob(
+        ["**"],
+        exclude = [
+            "BUILD",
+            "BUILD.bazel",
+        ],
+    )
+
+    # Run the `foxglove-extension` wrapper to create the .foxe file.
+    js_run_binary(
+        name = name,
+        srcs = all_files + [
+            ":node_modules",
+        ],
+        tool = "//tools/foxglove:foxglove_extension_wrapper",
+        outs = ["%s.foxe" % name],
+        args = [
+            "package",
+            "--out",
+            "%s.foxe" % name,
+        ],
+        target_compatible_with = [
+            "@platforms//cpu:x86_64",
+        ],
+        **kwargs
+    )
diff --git a/tools/ci/buildkite.yaml b/tools/ci/buildkite.yaml
index 7b17c8a..be3cb07 100644
--- a/tools/ci/buildkite.yaml
+++ b/tools/ci/buildkite.yaml
@@ -1,7 +1,7 @@
 env:
   STARTUP: --max_idle_secs=0
   COMMON: -c opt --stamp=no --curses=yes --symlink_prefix=/ --remote_cache=grpc://data-fast:9092 --repo_env=FRC971_RUNNING_IN_CI=1 --repository_cache=~/.cache/bazel_repository --experimental_repository_cache_hardlinks=true
-  TARGETS: //... @com_github_google_glog//... @com_google_ceres_solver//... @com_github_rawrtc_rawrtc//... @com_google_googletest//...
+  TARGETS: //... @com_github_google_glog//... @com_google_ceres_solver//... @com_github_rawrtc_rawrtc//... @com_google_googletest//... @symengine//...
   M4F_TARGETS: //...
   RP2040_TARGETS: //...
   # Sanity check that we are able to build the y2020 roborio code, which confirms
diff --git a/tools/foxglove/BUILD b/tools/foxglove/BUILD
new file mode 100644
index 0000000..6bbd263
--- /dev/null
+++ b/tools/foxglove/BUILD
@@ -0,0 +1,55 @@
+load("@aspect_rules_js//js:defs.bzl", "js_binary")
+load("@npm//:create-foxglove-extension/package_json.bzl", "bin")
+
+bin.create_foxglove_extension_binary(
+    name = "create_foxglove_extension",
+)
+
+bin.foxglove_extension_binary(
+    name = "foxglove_extension",
+    data = [
+        # This upstream binary needs the dummy npm binary in its runfiles since
+        # it will invoke this dummy npm binary.
+        ":foxglove_extension_wrapper_npm",
+    ],
+)
+
+js_binary(
+    name = "foxglove_extension_wrapper",
+    data = [
+        ":foxglove_extension",
+        # This binary needs the dummy npm binary in its runfiles since it needs
+        # to point the `foxglove_extension` binary above to it.
+        ":foxglove_extension_wrapper_npm",
+        "//:node_modules/create-foxglove-extension",
+    ],
+    entry_point = "foxglove_extension_wrapper.js",
+    visibility = ["//visibility:public"],
+)
+
+js_binary(
+    name = "foxglove_extension_wrapper_npm",
+    entry_point = "foxglove_extension_wrapper_npm.js",
+)
+
+py_binary(
+    name = "creation_wrapper",
+    srcs = ["creation_wrapper.py"],
+    data = [
+        "BUILD.bazel.tmpl",
+        ":creation_wrapper_npm",
+        "@com_github_bazelbuild_buildtools//buildozer",
+    ],
+    target_compatible_with = [
+        "@platforms//cpu:x86_64",
+    ],
+    deps = [
+        "@pip//pyyaml",
+        "@rules_python//python/runfiles",
+    ],
+)
+
+py_binary(
+    name = "creation_wrapper_npm",
+    srcs = ["creation_wrapper_npm.py"],
+)
diff --git a/tools/foxglove/BUILD.bazel.tmpl b/tools/foxglove/BUILD.bazel.tmpl
new file mode 100644
index 0000000..60f03dc
--- /dev/null
+++ b/tools/foxglove/BUILD.bazel.tmpl
@@ -0,0 +1,8 @@
+load("@npm//:defs.bzl", "npm_link_all_packages")
+load("//tools/build_rules:foxglove.bzl", "foxglove_extension")
+
+npm_link_all_packages(name = "node_modules")
+
+foxglove_extension(
+    name = "extension",
+)
diff --git a/tools/foxglove/README.md b/tools/foxglove/README.md
new file mode 100644
index 0000000..7c3a34a
--- /dev/null
+++ b/tools/foxglove/README.md
@@ -0,0 +1,14 @@
+# Creating a new extension
+
+Change directories into the directory of interest.
+
+    $ cd path/to/package
+
+The run the creation script and pass the new directory name as an argument.
+
+    $ ../.../tools/foxglove/create-foxglove-extension <path>
+
+The script will automatically set up all the Bazel hooks so you can compile
+the extension.
+
+    $ bazel build //path/to/package/<path>:extension
diff --git a/tools/foxglove/create-foxglove-extension b/tools/foxglove/create-foxglove-extension
new file mode 100755
index 0000000..ffc3bad
--- /dev/null
+++ b/tools/foxglove/create-foxglove-extension
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+set -o errexit
+set -o nounset
+set -o pipefail
+
+exec bazel run \
+    --run_under="//tools/foxglove:creation_wrapper" \
+    //tools/foxglove:create_foxglove_extension \
+    -- \
+    "$@"
diff --git a/tools/foxglove/creation_wrapper.py b/tools/foxglove/creation_wrapper.py
new file mode 100644
index 0000000..dd36c5f
--- /dev/null
+++ b/tools/foxglove/creation_wrapper.py
@@ -0,0 +1,126 @@
+import os
+import subprocess
+import sys
+import tempfile
+from pathlib import Path
+
+import yaml
+from python.runfiles import runfiles
+
+RUNFILES = runfiles.Create()
+
+FAKE_NPM_BIN = RUNFILES.Rlocation(
+    "org_frc971/tools/foxglove/creation_wrapper_npm")
+BUILDOZER_BIN = RUNFILES.Rlocation(
+    "com_github_bazelbuild_buildtools/buildozer/buildozer_/buildozer")
+
+WORKSPACE_DIR = Path(os.environ["BUILD_WORKSPACE_DIRECTORY"])
+WORKING_DIR = Path(os.environ["BUILD_WORKING_DIRECTORY"])
+
+
+def create_npm_link(temp_dir: Path, env: dict[str, str]):
+    """Set up the creation_wrapper_npm.py script as the "npm" binary."""
+    bin_dir = temp_dir / "bin"
+    bin_dir.mkdir()
+    npm = bin_dir / "npm"
+    npm.symlink_to(FAKE_NPM_BIN)
+    env["PATH"] = f"{temp_dir / 'bin'}:{env['PATH']}"
+
+
+def run_create_foxglove_extension(argv: list[str], name: str):
+    """Runs the create-foxglove-extension binary.
+
+    Args:
+        argv: The list of command line arguments passed to this wrapper.
+        name: The (directory) name of the new extension to be created.
+    """
+    with tempfile.TemporaryDirectory() as temp_dir:
+        temp_dir = Path(temp_dir)
+        env = os.environ.copy()
+        create_npm_link(temp_dir, env)
+
+        env["BAZEL_BINDIR"] = WORKING_DIR
+        env.pop("RUNFILES_DIR", None)
+        env.pop("RUNFILES_MANIFEST_FILE", None)
+
+        subprocess.run(argv[1:], check=True, env=env, cwd=WORKING_DIR)
+        # For some reason, the `foxglove-extension` binary doesn't set up the
+        # ts-loader dependency. Do it manually here.
+        subprocess.run(["npm", "install", "ts-loader@^9"],
+                       check=True,
+                       env=env,
+                       cwd=WORKING_DIR / name)
+
+
+def add_new_js_project(name: str):
+    """Tell Bazel about the new project."""
+    # The name of the Bazel package for the new extension.
+    package_name = WORKING_DIR.relative_to(WORKSPACE_DIR) / name
+
+    # Add the new "node_modules" directory to the ignore list.
+    bazelignore_file = WORKSPACE_DIR / ".bazelignore"
+    bazelignore = bazelignore_file.read_text()
+    bazelignore_entry = str(package_name / "node_modules")
+    if bazelignore_entry not in bazelignore.splitlines():
+        bazelignore = bazelignore.rstrip("\n") + "\n"
+        bazelignore_file.write_text(bazelignore + bazelignore_entry + "\n")
+
+    # Add the new project to the workspace list. This ensures the lock file
+    # gets updated properly.
+    pnpm_workspace_file = WORKSPACE_DIR / "pnpm-workspace.yaml"
+    pnpm_workspace = yaml.load(pnpm_workspace_file.read_text(),
+                               Loader=yaml.CLoader)
+    if str(package_name) not in pnpm_workspace["packages"]:
+        pnpm_workspace["packages"].append(str(package_name))
+        pnpm_workspace_file.write_text(yaml.dump(pnpm_workspace))
+
+    # Add the new project to the workspace. This ensures that all of its
+    # dependencies get downloaded by Bazel.
+    subprocess.check_call([
+        BUILDOZER_BIN,
+        f"add data @//{package_name}:package.json",
+        "WORKSPACE:npm",
+    ],
+                          cwd=WORKSPACE_DIR)
+
+    # Regenerate the lock file with the new project's dependencies included.
+    subprocess.check_call([
+        "bazel",
+        "run",
+        "--",
+        "@pnpm//:pnpm",
+        "--dir",
+        WORKSPACE_DIR,
+        "install",
+        "--lockfile-only",
+    ],
+                          cwd=WORKSPACE_DIR)
+
+
+def main(argv):
+    """Runs the main logic."""
+
+    # Assume that the only argument the user passed in is the name of the
+    # extension. We can probably do better here, but oh well.
+    create_foxglove_extension_args = argv[2:]
+    name = create_foxglove_extension_args[0]
+
+    run_create_foxglove_extension(argv, name)
+    add_new_js_project(name)
+
+    # Generate a BUILD file.
+    build_file_template = WORKSPACE_DIR / "tools/foxglove/BUILD.bazel.tmpl"
+    build_file = WORKING_DIR / name / "BUILD.bazel"
+    build_file.write_text(build_file_template.read_text())
+
+    # Fix up the tsconfig.json. For some reason the inheritance for the `lib`
+    # field doesn't work out of the box. We're using string manipulation since
+    # we don't have a readily-available "JSON with comments" parser.
+    tsconfig_file = WORKING_DIR / name / "tsconfig.json"
+    tsconfig = tsconfig_file.read_text()
+    tsconfig = tsconfig.replace('"lib": ["dom"]', '"lib": ["dom", "es2022"]')
+    tsconfig_file.write_text(tsconfig)
+
+
+if __name__ == "__main__":
+    sys.exit(main(sys.argv))
diff --git a/tools/foxglove/creation_wrapper_npm.py b/tools/foxglove/creation_wrapper_npm.py
new file mode 100644
index 0000000..6483536
--- /dev/null
+++ b/tools/foxglove/creation_wrapper_npm.py
@@ -0,0 +1,45 @@
+"""Acts as a dummy `npm` binary for the `create-foxglove-extension` binary.
+
+The `create-foxglove-extension` binary uses `npm` to manipulate the
+`package.json` file instead of doing so directly. Since we don't have access to
+the real `npm` binary here we just emulate the limited functionality we need.
+"""
+
+import argparse
+import json
+import sys
+from pathlib import Path
+
+
+def main(argv: list[str]):
+    """Runs the main logic."""
+    parser = argparse.ArgumentParser()
+    parser.add_argument("command")
+    parser.add_argument("--save-exact", action="store_true")
+    parser.add_argument("--save-dev", action="store_true")
+    args, packages = parser.parse_known_args(argv[1:])
+
+    # Validate the input arguments.
+    if args.command != "install":
+        raise ValueError("Don't know how to simulate anything other "
+                         f"than 'install'. Got '{args.command}'.")
+
+    for package in packages:
+        if "@^" not in package:
+            raise ValueError(f"Got unexpected package: {package}")
+
+    # Append the specified packages to the dependencies list.
+    package_version_pairs = list(
+        package.rsplit("@", maxsplit=1) for package in packages)
+    package_json_file = Path.cwd() / "package.json"
+    package_json = json.loads(package_json_file.read_text())
+    package_json.setdefault("dependencies", {}).update(
+        {package: version
+         for package, version in package_version_pairs})
+
+    package_json_file.write_text(
+        json.dumps(package_json, sort_keys=True, indent=4))
+
+
+if __name__ == "__main__":
+    sys.exit(main(sys.argv))
diff --git a/tools/foxglove/extension.tmpl.BUILD b/tools/foxglove/extension.tmpl.BUILD
new file mode 100644
index 0000000..bfe99aa
--- /dev/null
+++ b/tools/foxglove/extension.tmpl.BUILD
@@ -0,0 +1,5 @@
+load("//tools/build_rules:foxglove.bzl", "foxglove_extension")
+
+foxglove_extension(
+    name = "{NAME}",
+)
diff --git a/tools/foxglove/foxglove_extension_wrapper.js b/tools/foxglove/foxglove_extension_wrapper.js
new file mode 100644
index 0000000..71560f2
--- /dev/null
+++ b/tools/foxglove/foxglove_extension_wrapper.js
@@ -0,0 +1,56 @@
+// This script acts as a wrapper for the `foxglove-extension` binary. We need a
+// wrapper here because `foxglove-extension` wants to invoke `npm` directly.
+// Since we don't support the real npm binary, we force `foxglove-extension` to
+// use our fake npm binary (`foxglove_extension_wrapper_npm.js`) by
+// manipulating the PATH.
+
+const { spawnSync } = require('child_process');
+const path = require('path');
+const process = require('process');
+const fs = require('fs');
+const { tmpdir } = require('os');
+
+// Add a directory to the PATH environment variable.
+function addToPath(directory) {
+    const currentPath = process.env.PATH || '';
+    const newPath = `${directory}${path.delimiter}${currentPath}`;
+    process.env.PATH = newPath;
+}
+
+const fakeNpm = path.join(__dirname, 'foxglove_extension_wrapper_npm.sh');
+
+const tempBinDir = fs.mkdtempSync(path.join(tmpdir(), "foxglove_extension_wrapper-tmp-"));
+fs.symlinkSync(fakeNpm, path.join(tempBinDir, 'npm'));
+
+addToPath(tempBinDir);
+
+// Create a relative path for a specific root-relative directory.
+function getRelativePath(filePath) {
+    // Count the number of directories and construct the relative path.
+    const numDirectories = filePath.split('/').length;
+    return '../'.repeat(numDirectories);
+}
+
+// We need to know the path to the `foxglove-extension` binary from the
+// sub-directory where we're generating code into.
+const relativePath = getRelativePath(process.env.BAZEL_PACKAGE);
+const foxgloveExtensionPath = path.join(relativePath, `tools/foxglove/foxglove_extension.sh`)
+
+// Extract arguments intended for the `foxglove-extension` binary.
+const args = process.argv.slice(2);
+
+// Execute the `foxglove-extension` binary.
+try {
+    const result = spawnSync(foxgloveExtensionPath, args, { stdio: 'inherit', cwd: process.env.BAZEL_PACKAGE });
+    if (result.error) {
+        console.error('Error executing foxglove_extension:', result.error);
+        process.exit(1);
+    }
+    if (result.status !== 0) {
+        console.error(`foxglove_extension exited with status ${result.status}`);
+        process.exit(result.status);
+    }
+} catch (error) {
+    console.error('Error executing foxglove_extension:', error);
+    process.exit(1);
+}
diff --git a/tools/foxglove/foxglove_extension_wrapper_npm.js b/tools/foxglove/foxglove_extension_wrapper_npm.js
new file mode 100644
index 0000000..88dfca5
--- /dev/null
+++ b/tools/foxglove/foxglove_extension_wrapper_npm.js
@@ -0,0 +1,69 @@
+// This script acts as an "npm" binary for the foxglove-extension binary. We
+// don't actually care to do any npm things here. For some reason
+// foxglove-extension defers to npm to execute the various build stages. So
+// all this script does is execute those various build stages. The stages are
+// defined in the package.json file.
+
+const fs = require('fs');
+const { execSync } = require('child_process');
+const path = require('path');
+
+// Read the package.json file.
+function readPackageJson() {
+    try {
+        const packageJson = fs.readFileSync('package.json', 'utf8');
+        return JSON.parse(packageJson);
+    } catch (error) {
+        console.error('Error reading package.json:', error);
+        process.exit(1);
+    }
+}
+
+// Execute the named script specified in package.json.
+function executeScript(scriptName) {
+    const packageJson = readPackageJson();
+    const scripts = packageJson.scripts || {};
+
+    if (!scripts[scriptName]) {
+        console.error(`Script '${scriptName}' not found in package.json`);
+        process.exit(1);
+    }
+
+    // We cannot execute the `foxglove-extension` binary as-is (at least not
+    // without setting up a custom PATH). So we instead point at the
+    // Bazel-generated wrapper script for that binary.
+    const scriptParts = scripts[scriptName].split(' ');
+    const bin = scriptParts[0];
+    if (bin !== 'foxglove-extension') {
+        console.error(`Cannot support commands other than 'foxglove-extension'. Got: ${bin}`);
+        process.exit(1);
+    }
+    scriptParts[0] = path.join(__dirname, 'foxglove_extension.sh');
+
+    // Execute the `foxglove-extension` command specified in the script.
+    try {
+        console.log(`Executing script '${scriptName}'...`);
+        execSync(scriptParts.join(' '), { stdio: 'inherit' });
+    } catch (error) {
+        console.error(`Error executing script '${scriptName}':`, error);
+        process.exit(1);
+    }
+}
+
+function main() {
+    // Validate the input arguments.
+    if (process.argv.length !== 4) {
+        console.error('Usage: node foxglove_extension_wrapper_npm.js <scriptName>');
+        process.exit(1);
+    }
+    if (process.argv[2] !== "run") {
+        console.error(`Cannot support commands other than 'run'. Got: ${process.argv[2]}`);
+        process.exit(1);
+    }
+
+    // Run the script specified in the package.json file.
+    const scriptName = process.argv[3];
+    executeScript(scriptName);
+}
+
+main();
diff --git a/tools/iwyu/BUILD.bazel b/tools/iwyu/BUILD.bazel
new file mode 100644
index 0000000..957cf94
--- /dev/null
+++ b/tools/iwyu/BUILD.bazel
@@ -0,0 +1,6 @@
+filegroup(
+    name = "mappings",
+    srcs = glob([
+        "*.imp",
+    ]),
+)
diff --git a/tools/iwyu/by_hand.imp b/tools/iwyu/by_hand.imp
new file mode 100644
index 0000000..bbbeec8
--- /dev/null
+++ b/tools/iwyu/by_hand.imp
@@ -0,0 +1,53 @@
+[
+  # libc++ headers
+  { "include": ["<bits/chrono.h>", "private", "<chrono>", "public"] },
+  { "include": ["<bits/types/struct_sched_param.h>", "private", "<sched.h>", "public"] },
+  { "include": ["<bits/mman-map-flags-generic.h>", "private", "<sys/mman.h>", "public"] },
+  { "include": ["<bits/std_abs.h>", "private", "<cstdlib>", "public"] },
+  { "include": ["<bits/string_fortified.h>", "private", "<string.h>", "public"] },
+  { "include": ["<bits/strings_fortified.h>", "private", "<string.h>", "public"] },
+
+  # parts of Python.h
+  { "include": ["<boolobject.h>", "private", "<Python.h>", "public"] },
+  { "include": ["<bytesobject.h>", "private", "<Python.h>", "public"] },
+  { "include": ["<listobject.h>", "private", "<Python.h>", "public"] },
+  { "include": ["<longobject.h>", "private", "<Python.h>", "public"] },
+  { "include": ["<methodobject.h>", "private", "<Python.h>", "public"] },
+  { "include": ["<modsupport.h>", "private", "<Python.h>", "public"] },
+  { "include": ["<moduleobject.h>", "private", "<Python.h>", "public"] },
+  { "include": ["<object.h>", "private", "<Python.h>", "public"] },
+  { "include": ["<pyerrors.h>", "private", "<Python.h>", "public"] },
+  { "include": ["<pymacro.h>", "private", "<Python.h>", "public"] },
+  { "include": ["<pyport.h>", "private", "<Python.h>", "public"] },
+  { "include": ["<tupleobject.h>", "private", "<Python.h>", "public"] },
+  { "include": ["<unicodeobject.h>", "private", "<Python.h>", "public"] },
+
+  # seasocks
+  { "include": ["<seasocks/Logger.h>", "private", "\"seasocks/Logger.h\"", "public"] },
+
+  # libjpeg
+  { "include": ["\"third_party/libjpeg/jmorecfg.h\"", "private", "\"third_party/libjpeg/jpeglib.h\"", "public"] },
+
+  # glog
+  { "include": ["\"glog/log_severity.h\"", "private", "\"glog/logging.h\"", "public"] },
+  { "include": ["\"glog/vlog_is_on.h\"", "private", "\"glog/logging.h\"", "public"] },
+
+  # gtest
+  { "include": ["<gtest/gtest.h>", "private", "\"gtest/gtest.h\"", "public"] },
+
+  # grpc
+  { "include": ["<grpcpp/client_context.h>", "private", "\"grpcpp/client_context.h\"", "public"] },
+  { "include": ["<grpcpp/support/status.h>", "private", "\"grpcpp/support/status.h\"", "public"] },
+  { "include": ["<grpcpp/server_context.h>", "private", "\"grpcpp/server_context.h\"", "public"] },
+  { "include": ["<grpcpp/impl/service_type.h>", "private", "\"grpcpp/impl/service_type.h\"", "public"] },
+  { "include": ["<grpcpp/security/credentials.h>", "private", "\"grpcpp/security/credentials.h\"", "public"] },
+  { "include": ["<grpcpp/server.h>", "private", "\"grpcpp/server.h\"", "public"] },
+
+  # nlohmann
+  { "include": ["<nlohmann/json.hpp>", "private", "\"nlohmann/json.hpp\"", "public"] },
+  { "include": ["<nlohmann/json_fwd.hpp>", "private", "\"nlohmann/json_fwd.hpp\"", "public"] },
+
+  # aos
+  { "symbol": ["log_level", "private", "\"aos/logging/logging.h\"", "public"] },
+]
+
diff --git a/tools/iwyu/eigen.imp b/tools/iwyu/eigen.imp
new file mode 100644
index 0000000..cbeb16b
--- /dev/null
+++ b/tools/iwyu/eigen.imp
@@ -0,0 +1,19 @@
+[
+  { include: [ "\"src/Core/DenseBase.h\"",                 private, "\"Eigen/Core\"",                "public" ] },
+  { include: [ "\"src/Core/MatrixBase.h\"",                private, "\"Eigen/Core\"",                "public" ] },
+  { include: [ "\"src/Core/ArrayBase.h\"",                 private, "\"Eigen/Core\"",                "public" ] },
+  { include: [ "\"src/SparseCore/SparseMatrixBase.h\"",    private, "\"Eigen/Sparse\"",              "public" ] },
+  { include: [ "<Eigen/src/plugins/ArrayCwiseUnaryOps.h>", private, "\"Eigen/Core\"",                "public" ] },
+  { include: [ "<Eigen/src/plugins/IndexedViewMethods.h>", private, "\"Eigen/Core\"",                "public" ] },
+  { include: [ "@<Eigen/src/Core/.*>",                     private, "\"Eigen/Core\"",                "public" ] },
+  { include: [ "@\"src/Core/.*\"",                         private, "\"Eigen/Core\"",                "public" ] },
+  { include: [ "@<Eigen/src/Cholesky/.*>",                 private, "\"Eigen/Cholesky\"",            "public" ] },
+  { include: [ "@<Eigen/src/Jacobi/.*>",                   private, "\"Eigen/Jacobi\"",              "public" ] },
+  { include: [ "@<Eigen/src/QR/.*>",                       private, "\"Eigen/QR\"",                  "public" ] },
+  { include: [ "@<Eigen/src/SVD/.*>",                      private, "\"Eigen/SVD\"",                 "public" ] },
+  { include: [ "@<Eigen/src/Householder/.*>",              private, "\"Eigen/Householder\"",         "public" ] },
+  { include: [ "@\"src/Cholesky/.*\"",                     private, "\"Eigen/Cholesky\"",            "public" ] },
+  { include: [ "@<Eigen/src/Geometry/.*>",                 private, "\"Eigen/Geometry\"",            "public" ] },
+  { include: [ "@\"src/Geometry/.*\"",                     private, "\"Eigen/Geometry\"",            "public" ] },
+  { include: [ "@<unsupported/Eigen/src/Splines/.*>",      private, "\"unsupported/Eigen/Splines\"", "public" ] },
+]
diff --git a/tools/iwyu/gtest.imp b/tools/iwyu/gtest.imp
new file mode 100644
index 0000000..60ee552
--- /dev/null
+++ b/tools/iwyu/gtest.imp
@@ -0,0 +1,14 @@
+[
+  { include: [ "@<gtest/internal/.*>",        private, "\"gtest/gtest.h\"",      public ] },
+  { include: [ "<gtest/gtest_prod.h>",        private, "\"gtest/gtest_prod.h\"", public ] },
+  { include: [ "@<gtest/gtest-.*>",           private, "\"gtest/gtest.h\"",      public ] },
+  { include: [ "@\"gtest/internal/.*\"",      private, "\"gtest/gtest.h\"",      public ] },
+  { include: [ "@\"gtest/gtest-.*\"",         private, "\"gtest/gtest.h\"",      public ] },
+  { include: [ "@<gmock/internal/.*>",        private, "\"gmock/gmock.h\"",      public ] },
+  { include: [ "@<gmock/gmock-.*>",           private, "\"gmock/gmock.h\"",      public ] },
+  { include: [ "<gmock/gmock.h>",             private, "\"gmock/gmock.h\"",      public ] },
+  { include: [ "@\"gmock/internal/.*\"",      private, "\"gmock/gmock.h\"",      public ] },
+  { include: [ "@\"gmock/gmock-.*\"",         private, "\"gmock/gmock.h\"",      public ] },
+  { include: [ "<gtest/gtest_pred_impl.h>",   private, "\"gtest/gtest.h\"",      public ] },
+  { include: [ "\"gtest/gtest_pred_impl.h\"", private, "\"gtest/gtest.h\"",      public ] },
+]
diff --git a/tools/iwyu/libcxx.imp b/tools/iwyu/libcxx.imp
new file mode 100644
index 0000000..609f4af
--- /dev/null
+++ b/tools/iwyu/libcxx.imp
@@ -0,0 +1,80 @@
+# libc++ headers
+[
+  { "include": ["<__mutex_base>", "private", "<mutex>", "public"] },
+  { "include": ["<__tree>", "private", "<set>", "public"] },
+  { "include": ["<__tree>", "private", "<map>", "public"] },
+
+  # For the following entries:
+  # cd llvm-project/libcxx/include ; find -type d -name "__*" | sort | sed -e 's#./__\(.*\)#  { "include": ["@<__\1/.*>", "private", "<\1>", "public"] },#'
+  #
+  # tweak locale_dir entry, and comment out debug_utils, fwd, pstl, support
+  { "include": ["@<__algorithm/.*>", "private", "<algorithm>", "public"] },
+  { "include": ["@<__atomic/.*>", "private", "<atomic>", "public"] },
+  { "include": ["@<__bit/.*>", "private", "<bit>", "public"] },
+  { "include": ["@<__charconv/.*>", "private", "<charconv>", "public"] },
+  { "include": ["@<__chrono/.*>", "private", "<chrono>", "public"] },
+  { "include": ["@<__compare/.*>", "private", "<compare>", "public"] },
+  { "include": ["@<__concepts/.*>", "private", "<concepts>", "public"] },
+  { "include": ["@<__condition_variable/.*>", "private", "<condition_variable>", "public"] },
+  { "include": ["@<__coroutine/.*>", "private", "<coroutine>", "public"] },
+  #{ "include": ["@<__debug_utils/.*>", "private", "<debug_utils>", "public"] },
+  { "include": ["@<__exception/.*>", "private", "<exception>", "public"] },
+  { "include": ["@<__expected/.*>", "private", "<expected>", "public"] },
+  { "include": ["@<__filesystem/.*>", "private", "<filesystem>", "public"] },
+  { "include": ["@<__format/.*>", "private", "<format>", "public"] },
+  { "include": ["@<__functional/.*>", "private", "<functional>", "public"] },
+  #{ "include": ["@<__fwd/.*>", "private", "<fwd>", "public"] },
+  { "include": ["@<__ios/.*>", "private", "<ios>", "public"] },
+  { "include": ["@<__iterator/.*>", "private", "<iterator>", "public"] },
+  { "include": ["@<__locale_dir/.*>", "private", "<locale>", "public"] },
+  { "include": ["@<__mdspan/.*>", "private", "<mdspan>", "public"] },
+  { "include": ["@<__memory/.*>", "private", "<memory>", "public"] },
+  { "include": ["@<__memory_resource/.*>", "private", "<memory_resource>", "public"] },
+  { "include": ["@<__mutex/.*>", "private", "<mutex>", "public"] },
+  { "include": ["@<__numeric/.*>", "private", "<numeric>", "public"] },
+  #{ "include": ["@<__pstl/.*>", "private", "<pstl>", "public"] },
+  { "include": ["@<__random/.*>", "private", "<random>", "public"] },
+  { "include": ["@<__ranges/.*>", "private", "<ranges>", "public"] },
+  { "include": ["@<__stop_token/.*>", "private", "<stop_token>", "public"] },
+  { "include": ["@<__string/.*>", "private", "<string>", "public"] },
+  #{ "include": ["@<__support/.*>", "private", "<support>", "public"] },
+  { "include": ["@<__system_error/.*>", "private", "<system_error>", "public"] },
+  { "include": ["@<__thread/.*>", "private", "<thread>", "public"] },
+  { "include": ["@<__tuple/.*>", "private", "<tuple>", "public"] },
+  { "include": ["@<__type_traits/.*>", "private", "<type_traits>", "public"] },
+  { "include": ["@<__utility/.*>", "private", "<utility>", "public"] },
+  { "include": ["@<__variant/.*>", "private", "<variant>", "public"] },
+
+  # For the following entries:
+  # cd llvm-project/libcxx/include ; find __fwd -type f -name "*.h" | sort | sed -e 's#__fwd/\(.*\).h#  { "include": ["<__fwd/\1.h>", "private", "<\1>", "public"] },#'
+  #
+  # tweak hash, pair, subrange entries, and comment out bit_reference, get
+  { "include": ["<__fwd/array.h>", "private", "<array>", "public"] },
+  #{ "include": ["<__fwd/bit_reference.h>", "private", "<bit_reference>", "public"] },
+  { "include": ["<__fwd/fstream.h>", "private", "<fstream>", "public"] },
+  #{ "include": ["<__fwd/get.h>", "private", "<get>", "public"] },
+  { "include": ["<__fwd/hash.h>", "private", "<functional>", "public"] },
+  { "include": ["<__fwd/ios.h>", "private", "<ios>", "public"] },
+  { "include": ["<__fwd/istream.h>", "private", "<istream>", "public"] },
+  { "include": ["<__fwd/mdspan.h>", "private", "<mdspan>", "public"] },
+  { "include": ["<__fwd/memory_resource.h>", "private", "<memory_resource>", "public"] },
+  { "include": ["<__fwd/ostream.h>", "private", "<ostream>", "public"] },
+  { "include": ["<__fwd/pair.h>", "private", "<utility>", "public"] },
+  { "include": ["<__fwd/span.h>", "private", "<span>", "public"] },
+  { "include": ["<__fwd/sstream.h>", "private", "<sstream>", "public"] },
+  { "include": ["<__fwd/streambuf.h>", "private", "<streambuf>", "public"] },
+  { "include": ["<__fwd/string.h>", "private", "<string>", "public"] },
+  { "include": ["<__fwd/string_view.h>", "private", "<string_view>", "public"] },
+  { "include": ["<__fwd/subrange.h>", "private", "<ranges>", "public"] },
+  { "include": ["<__fwd/tuple.h>", "private", "<tuple>", "public"] },
+
+  { "symbol": [ "std::nullptr_t", "private", "<cstddef>", "public"] },
+
+  # For older MacOS libc++ (13.0.0), on macOS Ventura (13.2.1)
+  { "include": ["<__functional_base>", "private", "<functional>", "public"] },
+
+  # For older libc++ (16.x)
+  { "include": ["@<__tuple_dir/.*>", "private", "<tuple>", "public"] },
+
+  { "symbol": [ "std::string", "private", "<string>", "public"] },
+]
diff --git a/tools/python/requirements.lock.txt b/tools/python/requirements.lock.txt
index 5a4dcf4..61a4d62 100644
--- a/tools/python/requirements.lock.txt
+++ b/tools/python/requirements.lock.txt
@@ -8,6 +8,56 @@
     --hash=sha256:1e3c502a0a8205338fc74dadbfa321f8a0965441b39501e36796a47b4017b642 \
     --hash=sha256:d824961e4265367b0750ce58b07e564ad0b83ca64b335521cd3421e9b9f10d89
     # via -r tools/python/requirements.txt
+casadi==3.6.5 \
+    --hash=sha256:0118637823e292a9270133e02c9c6d3f3c7f75e8c91a6f6dc5275ade82dd1d9d \
+    --hash=sha256:02d6fb63c460abd99a450e861034d97568a8aec621fc0a4fed22f7494989c682 \
+    --hash=sha256:092e448e05feaed8958d684e896d909e756d199b84d3b9d0182da38cd3deebf6 \
+    --hash=sha256:0a38bf808bf51368607c64307dd77a7363fbe8e5c910cd5c605546be60edfaff \
+    --hash=sha256:0d6ee0558b4ecdd8aa4aa70fd31528b135801f1086c28a9cb78d8e8242b7aedd \
+    --hash=sha256:0e4a4ec2e26ebeb22b0c129f2db3cf90f730cf9fbe98adb9a12720ff6ca1834a \
+    --hash=sha256:1ce199a4ea1d376edbe5399cd622a4564040c83f50c50114fe50a69a8ea81d92 \
+    --hash=sha256:1ddb6e4afdd1da95d7d9d652ed973c1b7f50ef1454965a9170b657e223a2c73e \
+    --hash=sha256:314886ef44bd01f1a98579e7784a3bed6e0584e88f9465cf9596af2523efb0dd \
+    --hash=sha256:32644c47fbfb643d5cf9769c7bbc94c6bdb9a40ea9c12c54af5e2754599c3186 \
+    --hash=sha256:33afd1a4da0c86b4316953fe541635a8a7dc51703282e24a870ada13a46adb53 \
+    --hash=sha256:35b2ff6098e386a4d5e8bc681744e52bcd2f2f15cfa44c09814a8979b51a6794 \
+    --hash=sha256:3a3fb8af868f83d4a4f26d878c49f4acc4ed7ee92e731c73e650e5893418a634 \
+    --hash=sha256:3bdd645151beda013af5fd019fb554756e7dac37541b9f120cdfba90405b2671 \
+    --hash=sha256:409a5f6725eadea40fddfb8ba2321139b5252edac8bc115a72f68e648631d56a \
+    --hash=sha256:5266fc82e39352e26cb1a4e0a5c3deb32d09e6333be637bd78c273fa50f9012b \
+    --hash=sha256:5e8adffe2015cde370fc545b2d0fe731e96e583e4ea4c5f3044e818fea975cfc \
+    --hash=sha256:601b76b7afcb27b11563999f6ad1d9d2a2510ab3d00a6f4ce86a0bee97c9d17a \
+    --hash=sha256:6039081fdd1daf4ef7fa2b52814a954d75bfc03eb0dc62414e02af5d25746e8f \
+    --hash=sha256:7ea8545579872b6f5412985dafec26b906b67bd4639a6c718b7e07f802af4e42 \
+    --hash=sha256:83e3404de4449cb7382e49d811eec79cd370e64b97b5c94b155c604d7c523a40 \
+    --hash=sha256:8bbfb2eb8cb6b9e2384814d6427e48bcf6df049bf7ed05b0a58bb311a1fbf18c \
+    --hash=sha256:a1ae36449adec534125d4af5be912b6fb9dafe74d1fee39f6c82263695e21ca5 \
+    --hash=sha256:af95de5aa5942d627d43312834791623384c2ad6ba87928bf0e3cacc8a6698e8 \
+    --hash=sha256:b5192dfabf6f5266b168b984d124dd3086c1c5a408c0743ff3a82290a8ccf3b5 \
+    --hash=sha256:bceb69bf9f04fded8a564eb64e298d19e945eaf4734f7145a5ee61cf9ac693e7 \
+    --hash=sha256:be40e9897d80fb72a97e750b2143c32f63f8800cfb78f9b396d8ce7a913fca39 \
+    --hash=sha256:bebd3909db24ba711e094aacc0a2329b9903d422d73f61be851873731244b7d1 \
+    --hash=sha256:c661fe88a93b7cc7ea42802aac76a674135cd65e3e564a6f08570dd3bea05201 \
+    --hash=sha256:c6789c8060a99b329bb584d97c1eab6a5e4f3e2d2db391e6c2001c6323774990 \
+    --hash=sha256:c951031e26d987986dbc334492b2e6ef108077f11c00e178ff4007e4a9bf91d8 \
+    --hash=sha256:c98e68023c9e5905d9d6b99ae1fbbfe4b85ba9846b3685408bb498b20509f99a \
+    --hash=sha256:caf395d1e36bfb215b154e8df61583d534a07ddabb18cbe50f259b7692a41ac8 \
+    --hash=sha256:ccb962ea02b7d6d245d5cd40fb52c29e812040a45273c6eed32cb8fcff673dda \
+    --hash=sha256:d12b67d467a5b2b0a909378ef7231fbc9af0da923baa13b1d5464d8471601ac3 \
+    --hash=sha256:dbeb50726603454a1f85323cba7caf72524cd43ca0aeb1f286d07005a967ece9 \
+    --hash=sha256:deb2cb2bee8aba0c2cad03c832965b51ca305d0f8eb15de8b857ba86a76f0db0 \
+    --hash=sha256:e40afb3c062817dd6ce2497cd001f00f107ee1ea41ec4d6ee9f9a5056d219e83 \
+    --hash=sha256:e44af450ce944649932f9ef63ff00d2d21f642b506444418b4b20e69dba3adaf \
+    --hash=sha256:e96ca81b00b9621007d45db1254fcf232d518ebcc802f42853f57b4df977c567 \
+    --hash=sha256:eb311088dca5359acc05aa4d8895bf99afaa16c7c04b27bf640ce4c2361b8cde \
+    --hash=sha256:ee5a4ed50d2becd0bd6d203c7a60ffad27c14a3e0ae357480de11c846a8dd928 \
+    --hash=sha256:f62f779481b30e5ea88392bdb8225e9545a21c4460dc3e96c2b782405b938d04 \
+    --hash=sha256:f6e10b66d6ae8216dab01532f7ad75cc9d66a95125d421b33d078a51ea0fc2a0 \
+    --hash=sha256:f9c1de9a798767c00f89c27677b74059df4c9601d69270967b06d7fcff204b4d \
+    --hash=sha256:f9e82658c910e3317535d769334260e0a24d97bbce68cadb72f592e9fcbafd61 \
+    --hash=sha256:fe2b64d777e36cc3f101220dd1e219a0e11c3e4ee2b5e708b30fea9a27107e41 \
+    --hash=sha256:febc645bcc0aed6d7a2bdb6e58b9a89cb8f74b19bc028c41cc807d75a5d54058
+    # via -r tools/python/requirements.txt
 certifi==2022.9.24 \
     --hash=sha256:0d9c601124e5a6ba9712dbc60d9c53c21e34f5f641fe83002317394311bdce14 \
     --hash=sha256:90c1a32f1d68f940488354e36370f6cca89f0f106db09518524c88d6ed83f382
@@ -304,6 +354,7 @@
     # via
     #   -r tools/python/requirements.txt
     #   bokeh
+    #   casadi
     #   contourpy
     #   matplotlib
     #   opencv-python
@@ -535,6 +586,7 @@
     --hash=sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174 \
     --hash=sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5
     # via
+    #   -r tools/python/requirements.txt
     #   bokeh
     #   mkdocs
     #   pyyaml-env-tag
diff --git a/tools/python/requirements.txt b/tools/python/requirements.txt
index ddbaef3..086b138 100644
--- a/tools/python/requirements.txt
+++ b/tools/python/requirements.txt
@@ -15,6 +15,7 @@
 validators
 yapf
 sympy
+pyyaml
 
 # TODO(phil): Migrate to absl-py. These are abandoned as far as I can tell.
 python-gflags
@@ -22,3 +23,5 @@
 
 bokeh
 tabulate
+
+casadi
diff --git a/tools/python/whl_overrides.json b/tools/python/whl_overrides.json
index 1bf2cf2..f19d373 100644
--- a/tools/python/whl_overrides.json
+++ b/tools/python/whl_overrides.json
@@ -3,6 +3,10 @@
         "sha256": "1e3c502a0a8205338fc74dadbfa321f8a0965441b39501e36796a47b4017b642",
         "url": "https://software.frc971.org/Build-Dependencies/wheelhouse/bokeh-3.4.1-py3-none-any.whl"
     },
+    "casadi==3.6.5": {
+        "sha256": "8bbfb2eb8cb6b9e2384814d6427e48bcf6df049bf7ed05b0a58bb311a1fbf18c",
+        "url": "https://software.frc971.org/Build-Dependencies/wheelhouse/casadi-3.6.5-cp39-none-manylinux2014_x86_64.whl"
+    },
     "certifi==2022.9.24": {
         "sha256": "90c1a32f1d68f940488354e36370f6cca89f0f106db09518524c88d6ed83f382",
         "url": "https://software.frc971.org/Build-Dependencies/wheelhouse/certifi-2022.9.24-py3-none-any.whl"
diff --git a/y2024/BUILD b/y2024/BUILD
index 26727a5..6cb7156 100644
--- a/y2024/BUILD
+++ b/y2024/BUILD
@@ -63,7 +63,7 @@
         "//y2024/constants:constants_sender",
         "//y2024/localizer:localizer_main",
         "//y2024/localizer:localizer_logger",
-        "//y2024/vision:foxglove_image_converter",
+        "//frc971/vision:foxglove_image_converter",
     ],
     data = [
         ":aos_config",
@@ -87,7 +87,7 @@
         "//frc971/orin:argus_camera",
         "//y2024/orin:can_logger",
         "//y2024/vision:apriltag_detector",
-        "//y2024/vision:image_logger",
+        "//frc971/vision:image_logger",
     ],
     target_compatible_with = ["//tools/platforms/hardware:raspberry_pi"],
     target_type = "pi",
@@ -339,9 +339,9 @@
     data = [
         ":aos_config",
         "//aos/network:log_web_proxy_main",
+        "//frc971/www:starter_main_bundle.min.js",
         "//y2024/www:field_main_bundle.min.js",
         "//y2024/www:files",
-        "//y2024/www:starter_main_bundle.min.js",
     ],
     target_compatible_with = ["@platforms//os:linux"],
 )
diff --git a/y2024/vision/BUILD b/y2024/vision/BUILD
index bd4fe76..500cad6 100644
--- a/y2024/vision/BUILD
+++ b/y2024/vision/BUILD
@@ -5,17 +5,6 @@
 )
 
 cc_binary(
-    name = "foxglove_image_converter",
-    srcs = ["foxglove_image_converter.cc"],
-    visibility = ["//y2024:__subpackages__"],
-    deps = [
-        "//aos:init",
-        "//aos/events:shm_event_loop",
-        "//frc971/vision:foxglove_image_converter_lib",
-    ],
-)
-
-cc_binary(
     name = "target_mapping",
     srcs = [
         "target_mapping.cc",
@@ -48,26 +37,6 @@
 )
 
 cc_binary(
-    name = "image_logger",
-    srcs = [
-        "image_logger.cc",
-    ],
-    target_compatible_with = ["@platforms//os:linux"],
-    visibility = ["//visibility:public"],
-    deps = [
-        "//aos:configuration",
-        "//aos:init",
-        "//aos/events:shm_event_loop",
-        "//aos/events/logging:log_writer",
-        "//aos/logging:log_namer",
-        "//aos/util:filesystem_fbs",
-        "//frc971/input:joystick_state_fbs",
-        "@com_github_gflags_gflags//:gflags",
-        "@com_github_google_glog//:glog",
-    ],
-)
-
-cc_binary(
     name = "apriltag_detector",
     srcs = [
         "apriltag_detector.cc",
@@ -88,7 +57,6 @@
         "@com_github_gflags_gflags//:gflags",
         "@com_github_google_glog//:glog",
         "@com_github_nvidia_cccl//:cccl",
-        "@com_github_nvidia_cuco//:cuco",
     ],
 )
 
@@ -148,39 +116,3 @@
         "@org_tuxfamily_eigen//:eigen",
     ],
 )
-
-cc_binary(
-    name = "modify_extrinsics",
-    srcs = [
-        "modify_extrinsics.cc",
-    ],
-    target_compatible_with = ["@platforms//os:linux"],
-    visibility = ["//y2024:__subpackages__"],
-    deps = [
-        "//aos:configuration",
-        "//aos:init",
-        "//aos/events:event_loop",
-        "//frc971/vision:calibration_fbs",
-        "//frc971/vision:vision_util_lib",
-        "//y2024/constants:constants_fbs",
-        "@com_google_absl//absl/strings:str_format",
-        "@org_tuxfamily_eigen//:eigen",
-    ],
-)
-
-cc_binary(
-    name = "image_replay",
-    srcs = [
-        "image_replay.cc",
-    ],
-    target_compatible_with = ["@platforms//os:linux"],
-    visibility = ["//y2024:__subpackages__"],
-    deps = [
-        "//aos:configuration",
-        "//aos:init",
-        "//aos/events:simulated_event_loop",
-        "//aos/events/logging:log_reader",
-        "//frc971/vision:vision_fbs",
-        "//third_party:opencv",
-    ],
-)
diff --git a/y2024/vision/image_replay.cc b/y2024/vision/image_replay.cc
deleted file mode 100644
index f03bcf1..0000000
--- a/y2024/vision/image_replay.cc
+++ /dev/null
@@ -1,47 +0,0 @@
-#include "gflags/gflags.h"
-#include "opencv2/imgproc.hpp"
-#include <opencv2/highgui.hpp>
-
-#include "aos/events/logging/log_reader.h"
-#include "aos/events/logging/log_writer.h"
-#include "aos/events/simulated_event_loop.h"
-#include "aos/init.h"
-#include "aos/json_to_flatbuffer.h"
-#include "aos/logging/log_message_generated.h"
-#include "frc971/vision/vision_generated.h"
-
-DEFINE_string(node, "orin1", "The node to view the log from");
-DEFINE_string(channel, "/camera0", "The channel to view the log from");
-
-int main(int argc, char **argv) {
-  aos::InitGoogle(&argc, &argv);
-
-  // open logfiles
-  aos::logger::LogReader reader(
-      aos::logger::SortParts(aos::logger::FindLogs(argc, argv)));
-
-  aos::SimulatedEventLoopFactory factory(reader.configuration());
-  reader.Register(&factory);
-
-  aos::NodeEventLoopFactory *node = factory.GetNodeEventLoopFactory(FLAGS_node);
-
-  std::unique_ptr<aos::EventLoop> image_loop = node->MakeEventLoop("image");
-  image_loop->MakeWatcher(
-      "/" + FLAGS_node + "/" + FLAGS_channel,
-      [](const frc971::vision::CameraImage &msg) {
-        cv::Mat color_image(cv::Size(msg.cols(), msg.rows()), CV_8UC2,
-                            (void *)msg.data()->data());
-
-        cv::Mat bgr(color_image.size(), CV_8UC3);
-        cv::cvtColor(color_image, bgr, cv::COLOR_YUV2BGR_YUYV);
-
-        cv::imshow("Replay", bgr);
-        cv::waitKey(1);
-      });
-
-  factory.Run();
-
-  reader.Deregister();
-
-  return 0;
-}
diff --git a/y2024/vision/localization_verifier.cc b/y2024/vision/localization_verifier.cc
deleted file mode 100644
index c16f874..0000000
--- a/y2024/vision/localization_verifier.cc
+++ /dev/null
@@ -1,108 +0,0 @@
-#include "glog/logging.h"
-
-#include "aos/init.h"
-#include "frc971/constants/constants_sender_lib.h"
-#include "frc971/control_loops/drivetrain/localization/localizer_output_generated.h"
-#include "frc971/vision/vision_generated.h"
-#include "y2023/localizer/localizer.h"
-#include "y2023/localizer/utils.h"
-
-DEFINE_string(config, "aos_config.json", "Path to the config file to use.");
-
-DEFINE_uint64(min_april_id, 1,
-              "Minimum april id to consider as part of the field and ignore");
-DEFINE_uint64(max_april_id, 8,
-              "Maximum april id to consider as part of the field and ignore");
-
-// This binary allows us to place extra april tags on the field and verify
-// that we can compute their field pose correctly
-
-namespace y2023::vision {
-
-using localizer::Localizer;
-
-Localizer::Transform LocalizerOutputToTransform(
-    const frc971::controls::LocalizerOutput &localizer) {
-  const auto T_field_robot =
-      Eigen::Translation3d(localizer.x(), localizer.y(), 0.0);
-
-  Eigen::AngleAxisd robot_yaw_angle(localizer.theta(),
-                                    Eigen::Vector3d::UnitZ());
-  const auto R_field_robot = Eigen::Quaterniond(robot_yaw_angle);
-  const Localizer::Transform H_field_robot =
-      (T_field_robot * R_field_robot).matrix();
-  return H_field_robot;
-}
-
-void HandleDetections(
-    const frc971::vision::TargetMap &detections,
-    const Localizer::Transform &H_robot_camera,
-    aos::Fetcher<frc971::controls::LocalizerOutput> *localizer_fetcher) {
-  localizer_fetcher->Fetch();
-  CHECK(localizer_fetcher->get());
-
-  for (const auto *target_pose : *detections.target_poses()) {
-    // Only look at april tags not part of the field
-    if (target_pose->id() >= FLAGS_min_april_id &&
-        target_pose->id() <= FLAGS_max_april_id) {
-      continue;
-    }
-
-    const Localizer::Transform H_camera_target =
-        localizer::PoseToTransform(target_pose);
-    const Localizer::Transform H_field_robot =
-        LocalizerOutputToTransform(*localizer_fetcher->get());
-
-    // Get the field-based target pose using the detection, extrinsics, and
-    // localizer output
-    const Localizer::Transform H_field_target =
-        H_field_robot * H_robot_camera * H_camera_target;
-
-    LOG(INFO) << "Field to target " << target_pose->id();
-    LOG(INFO) << "H_field_robot " << H_field_robot;
-    LOG(INFO) << "H_robot_camera " << H_robot_camera;
-    LOG(INFO) << "H_camera_target " << H_camera_target;
-    LOG(INFO) << "Transform: " << H_field_target;
-    LOG(INFO) << "Translation: "
-              << Eigen::Affine3d(H_field_target).translation();
-    LOG(INFO);
-  }
-}
-
-void LocalizationVerifierMain() {
-  aos::FlatbufferDetachedBuffer<aos::Configuration> config =
-      aos::configuration::ReadConfig(FLAGS_config);
-
-  frc971::constants::WaitForConstants<Constants>(&config.message());
-
-  aos::ShmEventLoop event_loop(&config.message());
-
-  frc971::constants::ConstantsFetcher<Constants> constants_fetcher(&event_loop);
-
-  aos::Fetcher<frc971::controls::LocalizerOutput> localizer_fetcher =
-      event_loop.MakeFetcher<frc971::controls::LocalizerOutput>("/localizer");
-
-  for (const auto *camera : *constants_fetcher.constants().cameras()) {
-    CHECK(camera->has_calibration());
-    Localizer::Transform H_robot_camera =
-        frc971::control_loops::drivetrain::FlatbufferToTransformationMatrix(
-            *camera->calibration()->fixed_extrinsics());
-
-    const std::string_view pi_name =
-        camera->calibration()->node_name()->string_view();
-    event_loop.MakeWatcher(
-        absl::StrCat("/", pi_name, "/camera"),
-        [H_robot_camera,
-         &localizer_fetcher](const frc971::vision::TargetMap &target_map) {
-          HandleDetections(target_map, H_robot_camera, &localizer_fetcher);
-        });
-  }
-  event_loop.Run();
-}
-
-}  // namespace y2023::vision
-
-int main(int argc, char **argv) {
-  aos::InitGoogle(&argc, &argv);
-  y2023::vision::LocalizationVerifierMain();
-}
diff --git a/y2024/www/BUILD b/y2024/www/BUILD
index 6b751ed..0dc30d1 100644
--- a/y2024/www/BUILD
+++ b/y2024/www/BUILD
@@ -56,39 +56,13 @@
     ],
 )
 
-ts_project(
-    name = "starter_main",
-    srcs = [
-        "starter_handler.ts",
-        "starter_main.ts",
-    ],
-    target_compatible_with = ["@platforms//os:linux"],
-    deps = [
-        "//aos/network:connect_ts_fbs",
-        "//aos/network:message_bridge_client_ts_fbs",
-        "//aos/network/www:proxy",
-        "//aos/starter:starter_ts_fbs",
-        "@com_github_google_flatbuffers//ts:flatbuffers_ts",
-    ],
-)
-
-rollup_bundle(
-    name = "starter_main_bundle",
-    entry_point = "starter_main.ts",
-    target_compatible_with = ["@platforms//os:linux"],
-    visibility = ["//y2024:__subpackages__"],
-    deps = [
-        ":starter_main",
-    ],
-)
-
 aos_downloader_dir(
     name = "www_files",
     srcs = [
         ":field_main_bundle.min.js",
         ":files",
-        ":starter_main_bundle.min.js",
         "//frc971/analysis:plot_index_bundle.min.js",
+        "//frc971/www:starter_files",
     ],
     dir = "www",
     target_compatible_with = ["@platforms//os:linux"],
diff --git a/y2024_swerve/BUILD b/y2024_swerve/BUILD
index c696c5a..0a91e3a 100644
--- a/y2024_swerve/BUILD
+++ b/y2024_swerve/BUILD
@@ -1,5 +1,4 @@
 load("//aos:config.bzl", "aos_config")
-load("//aos/flatbuffers:generate.bzl", "static_flatbuffer")
 load("//aos/util:config_validator_macro.bzl", "config_validator_test")
 load("//frc971:downloader.bzl", "robot_downloader")
 
@@ -12,6 +11,7 @@
     binaries = [
         "//aos/network:web_proxy_main",
         "//aos/events/logging:log_cat",
+        "//y2024_swerve/constants:constants_sender",
         "//aos/events:aos_timing_report_streamer",
     ],
     data = [
@@ -22,6 +22,9 @@
         "@ctre_phoenix_api_cpp_athena//:shared_libraries",
         "@ctre_phoenix_cci_athena//:shared_libraries",
     ],
+    dirs = [
+        "//y2024/www:www_files",
+    ],
     start_binaries = [
         "//aos/events/logging:logger_main",
         "//aos/network:web_proxy_main",
@@ -36,24 +39,43 @@
 )
 
 robot_downloader(
-    name = "pi_download",
+    name = "orin_download",
     binaries = [
-        "//aos/util:foxglove_websocket",
         "//aos/events:aos_timing_report_streamer",
         "//aos/events/logging:log_cat",
-        "//y2023/rockpi:imu_main",
+        "//aos:aos_jitter",
+        "//aos/network:web_proxy_main",
+        "//aos/starter:irq_affinity",
+        "//aos/util:foxglove_websocket",
         "//frc971/image_streamer:image_streamer",
+        "//frc971/orin:hardware_monitor",
+        "//frc971/orin:argus_monitor",
+        "//frc971/vision:intrinsics_calibration",
+        "//aos/util:filesystem_monitor",
+        "//y2024_swerve/constants:constants_sender",
+        "//frc971/vision:foxglove_image_converter",
+    ],
+    data = [
+        ":aos_config",
+        "//frc971/orin:orin_irq_config.json",
+        "//y2024/www:www_files",
+        "//y2024_swerve/constants:constants.json",
+    ],
+    dirs = [
+        "//y2024/www:www_files",
+    ],
+    start_binaries = [
+        "//aos/events/logging:logger_main",
+        "//frc971/imu_fdcan:can_translator",
+        "//frc971/imu_fdcan:dual_imu_blender",
+        "//frc971/can_logger",
         "//aos/network:message_bridge_client",
         "//aos/network:message_bridge_server",
         "//aos/network:web_proxy_main",
         "//aos/starter:irq_affinity",
-        "//aos/events/logging:logger_main",
-    ],
-    data = [
-        ":aos_config",
-        "//frc971/rockpi:rockpi_config.json",
-    ],
-    start_binaries = [
+        "//frc971/orin:argus_camera",
+        "//y2024_swerve/vision:apriltag_detector",
+        "//frc971/vision:image_logger",
     ],
     target_compatible_with = ["//tools/platforms/hardware:raspberry_pi"],
     target_type = "pi",
@@ -75,23 +97,15 @@
     ],
     visibility = ["//visibility:public"],
     deps = [
+        "//aos/mutex",
         "//aos/network:team_number",
         "//frc971:constants",
+        "//y2024_swerve/constants:constants_fbs",
+        "@com_github_google_glog//:glog",
+        "@com_google_absl//absl/base",
     ],
 )
 
-static_flatbuffer(
-    name = "drivetrain_position_fbs",
-    srcs = ["drivetrain_position.fbs"],
-    deps = ["//frc971/control_loops:control_loops_fbs"],
-)
-
-static_flatbuffer(
-    name = "drivetrain_can_position_fbs",
-    srcs = ["drivetrain_can_position.fbs"],
-    deps = ["//frc971/control_loops:can_talonfx_fbs"],
-)
-
 cc_binary(
     name = "swerve_publisher",
     srcs = ["swerve_publisher_main.cc"],
@@ -109,7 +123,7 @@
     deps = [
         "//aos:init",
         "//aos/events:event_loop",
-        "//frc971/control_loops/drivetrain/swerve:swerve_drivetrain_output_fbs",
+        "//frc971/control_loops/swerve:swerve_drivetrain_output_fbs",
         "@com_github_google_glog//:glog",
     ],
 )
@@ -136,11 +150,11 @@
     target_compatible_with = ["//tools/platforms/hardware:roborio"],
     deps = [
         ":constants",
-        ":drivetrain_can_position_fbs",
-        ":drivetrain_position_fbs",
         "//aos:init",
         "//aos/events:shm_event_loop",
         "//frc971/control_loops:control_loops_fbs",
+        "//frc971/control_loops/swerve:swerve_drivetrain_can_position_fbs",
+        "//frc971/control_loops/swerve:swerve_drivetrain_position_fbs",
         "//frc971/wpilib:can_sensor_reader",
         "//frc971/wpilib:sensor_reader",
         "//frc971/wpilib:talonfx",
@@ -157,12 +171,14 @@
         "//aos/network:message_bridge_server_fbs",
         "//aos/network:timestamp_fbs",
         "//frc971/input:robot_state_fbs",
+        "//frc971/vision:vision_fbs",
+        "//frc971/vision:target_map_fbs",
     ],
     target_compatible_with = ["@platforms//os:linux"],
     visibility = ["//visibility:public"],
     deps = [
         ":config_imu",
-        ":config_logger",
+        ":config_orin1",
         ":config_roborio",
     ],
 )
@@ -171,15 +187,14 @@
     name = "config_roborio",
     src = "y2024_swerve_roborio.json",
     flatbuffers = [
-        ":drivetrain_position_fbs",
-        ":drivetrain_can_position_fbs",
         "//frc971:can_configuration_fbs",
         "//aos/network:remote_message_fbs",
         "//aos/network:message_bridge_client_fbs",
         "//aos/network:message_bridge_server_fbs",
         "//aos/network:timestamp_fbs",
-        "//frc971/control_loops/drivetrain/swerve:swerve_drivetrain_output_fbs",
-        "//frc971/control_loops/drivetrain/swerve:swerve_drivetrain_position_fbs",
+        "//frc971/control_loops/swerve:swerve_drivetrain_output_fbs",
+        "//frc971/control_loops/swerve:swerve_drivetrain_position_fbs",
+        "//frc971/control_loops/swerve:swerve_drivetrain_can_position_fbs",
         "//frc971/control_loops/drivetrain:drivetrain_can_position_fbs",
         "//frc971/can_logger:can_logging_fbs",
     ],
@@ -198,10 +213,20 @@
     src = "y2024_swerve_imu.json",
     flatbuffers = [
         "//aos/network:message_bridge_client_fbs",
+        "//y2024_swerve/constants:constants_fbs",
         "//aos/network:message_bridge_server_fbs",
+        "//frc971/imu_fdcan:dual_imu_fbs",
+        "//frc971/imu_fdcan:can_translator_status_fbs",
+        "//frc971/imu_fdcan:dual_imu_blender_status_fbs",
+        "//frc971/can_logger:can_logging_fbs",
+        "//frc971/orin:hardware_stats_fbs",
         "//aos/network:timestamp_fbs",
+        "//aos/util:filesystem_fbs",
         "//aos/network:remote_message_fbs",
+        "//frc971/vision:calibration_fbs",
         "//frc971/vision:target_map_fbs",
+        "//frc971/vision:vision_fbs",
+        "@com_github_foxglove_schemas//:schemas",
     ],
     target_compatible_with = ["@platforms//os:linux"],
     visibility = ["//visibility:public"],
@@ -212,15 +237,20 @@
 )
 
 aos_config(
-    name = "config_logger",
-    src = "y2024_swerve_logger.json",
+    name = "config_orin1",
+    src = "y2024_swerve_orin1.json",
     flatbuffers = [
         "//aos/network:message_bridge_client_fbs",
         "//aos/network:message_bridge_server_fbs",
         "//aos/network:timestamp_fbs",
         "//aos/network:remote_message_fbs",
+        "//y2024_swerve/constants:constants_fbs",
+        "//frc971/orin:hardware_stats_fbs",
         "//frc971/vision:calibration_fbs",
         "//frc971/vision:target_map_fbs",
+        "//frc971/vision:vision_fbs",
+        "//aos/util:filesystem_fbs",
+        "@com_github_foxglove_schemas//:schemas",
     ],
     target_compatible_with = ["@platforms//os:linux"],
     visibility = ["//visibility:public"],
diff --git a/y2024_swerve/constants/6971.json b/y2024_swerve/constants/6971.json
new file mode 100644
index 0000000..644af99
--- /dev/null
+++ b/y2024_swerve/constants/6971.json
@@ -0,0 +1,28 @@
+{% from 'y2024_swerve/constants/common.jinja2' import front_left_zero %}
+{% from 'y2024_swerve/constants/common.jinja2' import front_right_zero %}
+{% from 'y2024_swerve/constants/common.jinja2' import back_left_zero %}
+{% from 'y2024_swerve/constants/common.jinja2' import back_right_zero %}
+
+{
+  "robot": {
+    "front_left_zeroing_constants":  {{ front_left_zero | tojson(indent=2)}},
+    "front_right_zeroing_constants":  {{ front_right_zero | tojson(indent=2)}},
+    "back_left_zeroing_constants":  {{ back_left_zero | tojson(indent=2)}},
+    "back_right_zeroing_constants":  {{ back_right_zero | tojson(indent=2)}},
+    "cameras": [
+      {
+        "calibration": {% include 'y2024_swerve/constants/calib_files/calibration_imu-9971-0_cam-24-10_2024-02-24_16-44-05.json' %}
+      },
+      {
+        "calibration": {% include 'y2024_swerve/constants/calib_files/calibration_imu-9971-1_cam-24-12_2024-03-24_11-52-49.json' %}
+      },
+      {
+        "calibration": {% include 'y2024_swerve/constants/calib_files/calibration_orin1-9971-0_cam-24-09_2024-03-24_11-52-49.json' %}
+      },
+      {
+        "calibration": {% include 'y2024_swerve/constants/calib_files/calibration_orin1-9971-1_cam-24-11_2024-03-24_11-52-49.json' %}
+      }
+    ]
+  },
+  {% include 'y2024_swerve/constants/common.json' %}
+}
diff --git a/y2024_swerve/constants/7971.json b/y2024_swerve/constants/7971.json
new file mode 100644
index 0000000..644af99
--- /dev/null
+++ b/y2024_swerve/constants/7971.json
@@ -0,0 +1,28 @@
+{% from 'y2024_swerve/constants/common.jinja2' import front_left_zero %}
+{% from 'y2024_swerve/constants/common.jinja2' import front_right_zero %}
+{% from 'y2024_swerve/constants/common.jinja2' import back_left_zero %}
+{% from 'y2024_swerve/constants/common.jinja2' import back_right_zero %}
+
+{
+  "robot": {
+    "front_left_zeroing_constants":  {{ front_left_zero | tojson(indent=2)}},
+    "front_right_zeroing_constants":  {{ front_right_zero | tojson(indent=2)}},
+    "back_left_zeroing_constants":  {{ back_left_zero | tojson(indent=2)}},
+    "back_right_zeroing_constants":  {{ back_right_zero | tojson(indent=2)}},
+    "cameras": [
+      {
+        "calibration": {% include 'y2024_swerve/constants/calib_files/calibration_imu-9971-0_cam-24-10_2024-02-24_16-44-05.json' %}
+      },
+      {
+        "calibration": {% include 'y2024_swerve/constants/calib_files/calibration_imu-9971-1_cam-24-12_2024-03-24_11-52-49.json' %}
+      },
+      {
+        "calibration": {% include 'y2024_swerve/constants/calib_files/calibration_orin1-9971-0_cam-24-09_2024-03-24_11-52-49.json' %}
+      },
+      {
+        "calibration": {% include 'y2024_swerve/constants/calib_files/calibration_orin1-9971-1_cam-24-11_2024-03-24_11-52-49.json' %}
+      }
+    ]
+  },
+  {% include 'y2024_swerve/constants/common.json' %}
+}
diff --git a/y2024_swerve/constants/BUILD b/y2024_swerve/constants/BUILD
new file mode 100644
index 0000000..6de0fb0
--- /dev/null
+++ b/y2024_swerve/constants/BUILD
@@ -0,0 +1,107 @@
+load("//aos/flatbuffers:generate.bzl", "static_flatbuffer")
+load("//tools/build_rules:template.bzl", "jinja2_template")
+load("//y2024_swerve/constants:validator.bzl", "constants_json")
+
+cc_library(
+    name = "simulated_constants_sender",
+    srcs = ["simulated_constants_sender.cc"],
+    hdrs = ["simulated_constants_sender.h"],
+    data = [":test_constants.json"],
+    visibility = ["//y2024_swerve:__subpackages__"],
+    deps = [
+        ":constants_fbs",
+        ":constants_list_fbs",
+        "//aos/events:simulated_event_loop",
+        "//aos/testing:path",
+        "//frc971/constants:constants_sender_lib",
+    ],
+)
+
+jinja2_template(
+    name = "test_constants_unvalidated.json",
+    src = "test_constants.jinja2.json",
+    includes = glob([
+        "test_data/*.json",
+    ]) + [
+        "common.jinja2",
+        "common.json",
+        "//y2024_swerve/constants/calib_files",
+        "//y2024_swerve/vision/maps",
+    ],
+    parameters = {},
+    visibility = ["//visibility:public"],
+)
+
+jinja2_template(
+    name = "constants_unvalidated.json",
+    src = "constants.jinja2.json",
+    includes = [
+        "6971.json",
+        "7971.json",
+        "common.jinja2",
+        "common.json",
+        "//y2024_swerve/constants/calib_files",
+        "//y2024_swerve/vision/maps",
+    ],
+    parameters = {},
+    visibility = ["//visibility:public"],
+)
+
+static_flatbuffer(
+    name = "constants_fbs",
+    srcs = ["constants.fbs"],
+    visibility = ["//visibility:public"],
+    deps = [
+        "//frc971/control_loops:profiled_subsystem_fbs",
+        "//frc971/control_loops/drivetrain:drivetrain_config_fbs",
+        "//frc971/vision:calibration_fbs",
+        "//frc971/vision:target_map_fbs",
+        "//frc971/zeroing:constants_fbs",
+    ],
+)
+
+static_flatbuffer(
+    name = "constants_list_fbs",
+    srcs = ["constants_list.fbs"],
+    visibility = ["//visibility:public"],
+    deps = [":constants_fbs"],
+)
+
+cc_binary(
+    name = "constants_sender",
+    srcs = ["constants_sender.cc"],
+    visibility = ["//visibility:public"],
+    deps = [
+        ":constants_fbs",
+        ":constants_list_fbs",
+        "//aos:init",
+        "//aos/events:shm_event_loop",
+        "//aos/testing:path",
+        "//frc971/constants:constants_sender_lib",
+    ],
+)
+
+cc_binary(
+    name = "constants_formatter",
+    srcs = ["constants_formatter.cc"],
+    data = [":constants_unvalidated.json"],
+    visibility = ["//visibility:public"],
+    deps = [
+        ":constants_list_fbs",
+        "//aos:init",
+        "//aos:json_to_flatbuffer",
+        "@com_github_google_glog//:glog",
+    ],
+)
+
+constants_json(
+    name = "constants_json",
+    src = ":constants_unvalidated.json",
+    out = "constants.json",
+)
+
+constants_json(
+    name = "test_constants_json",
+    src = ":test_constants_unvalidated.json",
+    out = "test_constants.json",
+)
diff --git a/y2024_swerve/constants/calib_files/BUILD b/y2024_swerve/constants/calib_files/BUILD
new file mode 100644
index 0000000..1f33d50
--- /dev/null
+++ b/y2024_swerve/constants/calib_files/BUILD
@@ -0,0 +1,5 @@
+filegroup(
+    name = "calib_files",
+    srcs = glob(["*.json"]),
+    visibility = ["//visibility:public"],
+)
diff --git a/y2024_swerve/constants/calib_files/calibration_imu-9971-0_cam-24-10_2024-02-24_16-44-05.json b/y2024_swerve/constants/calib_files/calibration_imu-9971-0_cam-24-10_2024-02-24_16-44-05.json
new file mode 100755
index 0000000..9b3f046
--- /dev/null
+++ b/y2024_swerve/constants/calib_files/calibration_imu-9971-0_cam-24-10_2024-02-24_16-44-05.json
@@ -0,0 +1,46 @@
+{
+ "node_name": "orin1",
+ "team_number": 6971,
+ "intrinsics": [
+  646.04834,
+  0.0,
+  703.327576,
+  0.0,
+  645.444458,
+  527.86261,
+  0.0,
+  0.0,
+  1.0
+ ],
+ "fixed_extrinsics": {
+  "data": [
+   0.0,
+   -0.258819,
+   -0.965926,
+   -0.323293,
+   1.0,
+   0.0,
+   -0.0,
+   0.268249,
+   0.0,
+   -0.965926,
+   0.258819,
+   0.471129,
+   0.0,
+   0.0,
+   0.0,
+   1.0
+  ]
+ },
+ "dist_coeffs": [
+  -0.251594,
+  0.064935,
+  0.000479,
+  0.000036,
+  -0.007207
+ ],
+ "calibration_timestamp": 1708821845975708672,
+ "camera_id": "24-10",
+ "camera_number": 0,
+ "reprojection_error": 1.523209
+}
diff --git a/y2024_swerve/constants/calib_files/calibration_imu-9971-1_cam-24-12_2024-03-24_11-52-49.json b/y2024_swerve/constants/calib_files/calibration_imu-9971-1_cam-24-12_2024-03-24_11-52-49.json
new file mode 100755
index 0000000..ee4078d
--- /dev/null
+++ b/y2024_swerve/constants/calib_files/calibration_imu-9971-1_cam-24-12_2024-03-24_11-52-49.json
@@ -0,0 +1,46 @@
+{
+ "node_name": "imu",
+ "team_number": 6971,
+ "intrinsics": [
+  647.19928,
+  0.0,
+  690.698181,
+  0.0,
+  646.449158,
+  530.162842,
+  0.0,
+  0.0,
+  1.0
+ ],
+ "fixed_extrinsics": {
+  "data": [
+   0.99969,
+   0.020217,
+   -0.014527,
+   0.160342,
+   0.009501,
+   0.229548,
+   0.973251,
+   0.25208,
+   0.023011,
+   -0.973088,
+   0.229284,
+   0.41504,
+   0.0,
+   0.0,
+   0.0,
+   1.0
+  ]
+ },
+ "dist_coeffs": [
+  -0.249799,
+  0.062593,
+  0.00003,
+  0.000366,
+  -0.006532
+ ],
+ "calibration_timestamp": 1711306369592332476,
+ "camera_id": "24-12",
+ "camera_number": 0,
+ "reprojection_error": 1.23409
+}
diff --git a/y2024_swerve/constants/calib_files/calibration_orin1-9971-0_cam-24-09_2024-03-24_11-52-49.json b/y2024_swerve/constants/calib_files/calibration_orin1-9971-0_cam-24-09_2024-03-24_11-52-49.json
new file mode 100755
index 0000000..c9e0114
--- /dev/null
+++ b/y2024_swerve/constants/calib_files/calibration_orin1-9971-0_cam-24-09_2024-03-24_11-52-49.json
@@ -0,0 +1,46 @@
+{
+ "node_name": "imu",
+ "team_number": 6971,
+ "intrinsics": [
+  648.187805,
+  0.0,
+  736.903137,
+  0.0,
+  648.028687,
+  557.169861,
+  0.0,
+  0.0,
+  1.0
+ ],
+ "fixed_extrinsics": {
+  "data": [
+   -0.999204,
+   -0.034711,
+   -0.019682,
+   0.162103,
+   0.028118,
+   -0.262536,
+   -0.964512,
+   -0.329348,
+   0.028312,
+   -0.964298,
+   0.263303,
+   0.562319,
+   0.0,
+   0.0,
+   0.0,
+   1.0
+  ]
+ },
+ "dist_coeffs": [
+  -0.265564,
+  0.078084,
+  -0.000231,
+  0.000386,
+  -0.010425
+ ],
+ "calibration_timestamp": 1711306369593360533,
+ "camera_id": "24-09",
+ "camera_number": 1,
+ "reprojection_error": 1.881098
+}
diff --git a/y2024_swerve/constants/calib_files/calibration_orin1-9971-1_cam-24-11_2024-03-24_11-52-49.json b/y2024_swerve/constants/calib_files/calibration_orin1-9971-1_cam-24-11_2024-03-24_11-52-49.json
new file mode 100755
index 0000000..daef89c
--- /dev/null
+++ b/y2024_swerve/constants/calib_files/calibration_orin1-9971-1_cam-24-11_2024-03-24_11-52-49.json
@@ -0,0 +1,46 @@
+{
+ "node_name": "orin1",
+ "team_number": 9971,
+ "intrinsics": [
+  649.866699,
+  0.0,
+  709.355713,
+  0.0,
+  648.893066,
+  576.101868,
+  0.0,
+  0.0,
+  1.0
+ ],
+ "fixed_extrinsics": {
+  "data": [
+   -0.014623,
+   0.004459,
+   0.999883,
+   0.345385,
+   0.997965,
+   0.062137,
+   0.014318,
+   0.150131,
+   -0.062066,
+   0.998058,
+   -0.005359,
+   0.570236,
+   0.0,
+   0.0,
+   0.0,
+   1.0
+  ]
+ },
+ "dist_coeffs": [
+  -0.248092,
+  0.060938,
+  0.000313,
+  0.00009,
+  -0.006163
+ ],
+ "calibration_timestamp": 1711306369592886702,
+ "camera_id": "24-11",
+ "camera_number": 1,
+ "reprojection_error": 1.450069
+}
\ No newline at end of file
diff --git a/y2024_swerve/constants/common.jinja2 b/y2024_swerve/constants/common.jinja2
new file mode 100644
index 0000000..48b843c
--- /dev/null
+++ b/y2024_swerve/constants/common.jinja2
@@ -0,0 +1,45 @@
+{% set M_PI = 3.14159265358979323846 %}
+
+{%
+set front_left_zero = {
+    "average_filter_size": 0,
+    "one_revolution_distance": 2 * M_PI,
+    "measured_absolute_position": 0.76761395509829,
+    "zeroing_threshold": 0.0,
+    "moving_buffer_size": 0,
+    "allowable_encoder_error": 0.0,
+}
+%}
+
+{%
+set front_right_zero = {
+    "average_filter_size": 0,
+    "one_revolution_distance": 2 * M_PI,
+    "measured_absolute_position": 0.779403958443922,
+    "zeroing_threshold": 0.0,
+    "moving_buffer_size": 0,
+    "allowable_encoder_error": 0.0,
+}
+%}
+
+{%
+set back_left_zero = {
+    "average_filter_size": 0,
+    "one_revolution_distance": 2 * M_PI,
+    "measured_absolute_position": 0.053439698061417,
+    "zeroing_threshold": 0.0,
+    "moving_buffer_size": 0,
+    "allowable_encoder_error": 0.0,
+}
+%}
+
+{%
+set back_right_zero = {
+    "average_filter_size": 0,
+    "one_revolution_distance": 2 * M_PI,
+    "measured_absolute_position": 0.719329333121509,
+    "zeroing_threshold": 0.0,
+    "moving_buffer_size": 0,
+    "allowable_encoder_error": 0.0,
+}
+%}
diff --git a/y2024_swerve/constants/common.json b/y2024_swerve/constants/common.json
new file mode 100644
index 0000000..48a4afa
--- /dev/null
+++ b/y2024_swerve/constants/common.json
@@ -0,0 +1,3 @@
+"common": {
+
+}
\ No newline at end of file
diff --git a/y2024_swerve/constants/constants.fbs b/y2024_swerve/constants/constants.fbs
new file mode 100644
index 0000000..a621f3b
--- /dev/null
+++ b/y2024_swerve/constants/constants.fbs
@@ -0,0 +1,28 @@
+include "frc971/zeroing/constants.fbs";
+include "frc971/vision/calibration.fbs";
+
+namespace y2024_swerve;
+
+table CameraConfiguration {
+  calibration:frc971.vision.calibration.CameraCalibration (id: 0);
+}
+
+table Common {
+
+}
+
+table RobotConstants {
+    front_left_zeroing_constants:frc971.zeroing.ContinuousAbsoluteEncoderZeroingConstants (id: 0);
+    front_right_zeroing_constants:frc971.zeroing.ContinuousAbsoluteEncoderZeroingConstants (id: 1);
+    back_left_zeroing_constants:frc971.zeroing.ContinuousAbsoluteEncoderZeroingConstants (id: 2);
+    back_right_zeroing_constants:frc971.zeroing.ContinuousAbsoluteEncoderZeroingConstants (id: 3);
+    cameras:[CameraConfiguration] (id: 4);
+}
+
+table Constants{
+    cameras:[CameraConfiguration] (id: 0, deprecated);
+    robot:RobotConstants (id: 1);
+    common:Common (id: 2);
+}
+
+root_type Constants;
diff --git a/y2024_swerve/constants/constants.jinja2.json b/y2024_swerve/constants/constants.jinja2.json
new file mode 100644
index 0000000..555c264
--- /dev/null
+++ b/y2024_swerve/constants/constants.jinja2.json
@@ -0,0 +1,12 @@
+{
+  "constants": [
+    {
+      "team": 6971,
+      "data": {% include 'y2024_swerve/constants/6971.json' %}
+    },
+    {
+      "team": 7971,
+      "data": {% include 'y2024_swerve/constants/7971.json' %}
+    }
+  ]
+}
diff --git a/y2024_swerve/constants/constants_formatter.cc b/y2024_swerve/constants/constants_formatter.cc
new file mode 100644
index 0000000..2ebb9b5
--- /dev/null
+++ b/y2024_swerve/constants/constants_formatter.cc
@@ -0,0 +1,26 @@
+#include "glog/logging.h"
+
+#include "aos/flatbuffers.h"
+#include "aos/init.h"
+#include "aos/json_to_flatbuffer.h"
+#include "aos/util/file.h"
+#include "y2024_swerve/constants/constants_list_generated.h"
+
+int main(int argc, char **argv) {
+  ::aos::InitGoogle(&argc, &argv);
+
+  CHECK(argc == 3) << ": Expected input and output json files to be passed in.";
+
+  aos::FlatbufferDetachedBuffer<y2024_swerve::ConstantsList> constants =
+      aos::JsonFileToFlatbuffer<y2024_swerve::ConstantsList>(argv[1]);
+
+  // Make sure the file is valid json before we output a formatted version.
+  CHECK(constants.message().constants() != nullptr)
+      << ": Failed to parse " << std::string(argv[2]);
+
+  aos::util::WriteStringToFileOrDie(
+      std::string(argv[2]),
+      aos::FlatbufferToJson(constants, {.multi_line = true}));
+
+  return 0;
+}
diff --git a/y2024_swerve/constants/constants_list.fbs b/y2024_swerve/constants/constants_list.fbs
new file mode 100644
index 0000000..3a65b64
--- /dev/null
+++ b/y2024_swerve/constants/constants_list.fbs
@@ -0,0 +1,14 @@
+include "y2024_swerve/constants/constants.fbs";
+
+namespace y2024_swerve;
+
+table TeamAndConstants {
+  team:long (id: 0);
+  data:Constants (id: 1);
+}
+
+table ConstantsList {
+  constants:[TeamAndConstants] (id: 0);
+}
+
+root_type ConstantsList;
diff --git a/y2024_swerve/constants/constants_sender.cc b/y2024_swerve/constants/constants_sender.cc
new file mode 100644
index 0000000..c624572
--- /dev/null
+++ b/y2024_swerve/constants/constants_sender.cc
@@ -0,0 +1,25 @@
+#include "gflags/gflags.h"
+#include "glog/logging.h"
+
+#include "aos/configuration.h"
+#include "aos/events/shm_event_loop.h"
+#include "aos/init.h"
+#include "aos/json_to_flatbuffer.h"
+#include "frc971/constants/constants_sender_lib.h"
+#include "y2024_swerve/constants/constants_generated.h"
+#include "y2024_swerve/constants/constants_list_generated.h"
+
+DEFINE_string(config, "aos_config.json", "Path to the AOS config.");
+DEFINE_string(constants_path, "constants.json", "Path to the constant file");
+
+int main(int argc, char **argv) {
+  aos::InitGoogle(&argc, &argv);
+  aos::FlatbufferDetachedBuffer<aos::Configuration> config =
+      aos::configuration::ReadConfig(FLAGS_config);
+  aos::ShmEventLoop event_loop(&config.message());
+  frc971::constants::ConstantSender<y2024_swerve::Constants,
+                                    y2024_swerve::ConstantsList>
+      constants_sender(&event_loop, FLAGS_constants_path);
+  // Don't need to call Run().
+  return 0;
+}
diff --git a/y2024_swerve/constants/simulated_constants_sender.cc b/y2024_swerve/constants/simulated_constants_sender.cc
new file mode 100644
index 0000000..7782e62
--- /dev/null
+++ b/y2024_swerve/constants/simulated_constants_sender.cc
@@ -0,0 +1,23 @@
+#include "aos/events/simulated_event_loop.h"
+#include "aos/testing/path.h"
+#include "frc971/constants/constants_sender_lib.h"
+#include "y2024_swerve/constants/constants_generated.h"
+#include "y2024_swerve/constants/constants_list_generated.h"
+
+namespace y2024_swerve {
+bool SendSimulationConstants(aos::SimulatedEventLoopFactory *factory, int team,
+                             std::string constants_path,
+                             const std::set<std::string_view> &node_names) {
+  for (const aos::Node *node : factory->nodes()) {
+    if (!node_names.empty() &&
+        !node_names.contains(node->name()->string_view())) {
+      continue;
+    }
+    std::unique_ptr<aos::EventLoop> event_loop =
+        factory->MakeEventLoop("constants_sender", node);
+    frc971::constants::ConstantSender<Constants, ConstantsList> sender(
+        event_loop.get(), constants_path, team, "/constants");
+  }
+  return true;
+}
+}  // namespace y2024_swerve
\ No newline at end of file
diff --git a/y2024_swerve/constants/simulated_constants_sender.h b/y2024_swerve/constants/simulated_constants_sender.h
new file mode 100644
index 0000000..5a64b75
--- /dev/null
+++ b/y2024_swerve/constants/simulated_constants_sender.h
@@ -0,0 +1,21 @@
+#ifndef Y2024_SWERVE_CONSTANTS_SIMULATED_CONFIG_SENDER_H_
+#define Y2024_SWERVE_CONSTANTS_SIMULATED_CONFIG_SENDER_H_
+
+#include <set>
+
+#include "aos/events/simulated_event_loop.h"
+#include "aos/testing/path.h"
+
+namespace y2024_swerve {
+// Returns true, to allow this to be easily called in the initializer list of a
+// constructor.
+// If node_names is specified, we limit ourselves to sending constants on the
+// specified nodes.
+bool SendSimulationConstants(
+    aos::SimulatedEventLoopFactory *factory, int team,
+    std::string constants_path = aos::testing::ArtifactPath(
+        "y2024_swerve/constants/test_constants.json"),
+    const std::set<std::string_view> &node_names = {});
+}  // namespace y2024_swerve
+
+#endif  // Y2024_SWERVE_CONSTANTS_SIMULATED_CONFIG_SENDER_H_
diff --git a/y2024_swerve/constants/test_constants.jinja2.json b/y2024_swerve/constants/test_constants.jinja2.json
new file mode 100644
index 0000000..6533a03
--- /dev/null
+++ b/y2024_swerve/constants/test_constants.jinja2.json
@@ -0,0 +1,8 @@
+{
+  "constants": [
+    {
+      "team": 6971,
+      "data": {% include 'y2024_swerve/constants/test_data/test_team.json' %}
+    }
+  ]
+}
diff --git a/y2024_swerve/constants/test_data/calibration_cam-1.json b/y2024_swerve/constants/test_data/calibration_cam-1.json
new file mode 100644
index 0000000..2d81347
--- /dev/null
+++ b/y2024_swerve/constants/test_data/calibration_cam-1.json
@@ -0,0 +1,46 @@
+{
+  "node_name": "orin1",
+  "camera_number": 0,
+  "team_number": 7971,
+  "intrinsics": [
+    893.759521,
+    0,
+    645.470764,
+    0,
+    893.222351,
+    388.150269,
+    0,
+    0,
+    1
+  ],
+  "fixed_extrinsics": {
+    "data": [
+      0.0,
+      0.0,
+      1.0,
+      1.0,
+
+      -1.0,
+      0.0,
+      0.0,
+      0.0,
+
+      0.0,
+      -1.0,
+      0.0,
+      0.0,
+
+      0.0,
+      0.0,
+      0.0,
+      1.0
+    ]
+  },
+  "dist_coeffs": [
+    -0.44902,
+    0.248409,
+    -0.000537,
+    -0.000112,
+    -0.076989
+  ]
+}
diff --git a/y2024_swerve/constants/test_data/calibration_cam-2.json b/y2024_swerve/constants/test_data/calibration_cam-2.json
new file mode 100644
index 0000000..1128799
--- /dev/null
+++ b/y2024_swerve/constants/test_data/calibration_cam-2.json
@@ -0,0 +1,46 @@
+{
+  "node_name": "orin1",
+  "camera_number": 1,
+  "team_number": 7971,
+  "intrinsics": [
+    893.759521,
+    0,
+    645.470764,
+    0,
+    893.222351,
+    388.150269,
+    0,
+    0,
+    1
+  ],
+  "fixed_extrinsics": {
+    "data": [
+      1.0,
+      0.0,
+      0.0,
+      1.0,
+
+      0.0,
+      0.0,
+      -1.0,
+      0.0,
+
+      0.0,
+      1.0,
+      0.0,
+      0.0,
+
+      0.0,
+      0.0,
+      0.0,
+      1.0
+    ]
+  },
+  "dist_coeffs": [
+    -0.44902,
+    0.248409,
+    -0.000537,
+    -0.000112,
+    -0.076989
+  ]
+}
diff --git a/y2024_swerve/constants/test_data/calibration_cam-3.json b/y2024_swerve/constants/test_data/calibration_cam-3.json
new file mode 100644
index 0000000..16e67ec
--- /dev/null
+++ b/y2024_swerve/constants/test_data/calibration_cam-3.json
@@ -0,0 +1,46 @@
+{
+  "node_name": "imu",
+  "camera_number": 0,
+  "team_number": 7971,
+  "intrinsics": [
+    893.759521,
+    0,
+    645.470764,
+    0,
+    893.222351,
+    388.150269,
+    0,
+    0,
+    1
+  ],
+  "fixed_extrinsics": {
+    "data": [
+      0.0,
+      1.0,
+      0.0,
+      1.0,
+
+      0.0,
+      0.0,
+      -1.0,
+      0.0,
+
+      -1.0,
+      0.0,
+      0.0,
+      0.0,
+
+      0.0,
+      0.0,
+      0.0,
+      1.0
+    ]
+  },
+  "dist_coeffs": [
+    -0.44902,
+    0.248409,
+    -0.000537,
+    -0.000112,
+    -0.076989
+  ]
+}
diff --git a/y2024_swerve/constants/test_data/calibration_cam-4.json b/y2024_swerve/constants/test_data/calibration_cam-4.json
new file mode 100644
index 0000000..1e5b623
--- /dev/null
+++ b/y2024_swerve/constants/test_data/calibration_cam-4.json
@@ -0,0 +1,46 @@
+{
+  "node_name": "imu",
+  "camera_number": 1,
+  "team_number": 7971,
+  "intrinsics": [
+    893.759521,
+    0,
+    645.470764,
+    0,
+    893.222351,
+    388.150269,
+    0,
+    0,
+    1
+  ],
+  "fixed_extrinsics": {
+    "data": [
+      -1.0,
+      0.0,
+      0.0,
+      1.0,
+
+      0.0,
+      0.0,
+      -1.0,
+      0.0,
+
+      0.0,
+      -1.0,
+      0.0,
+      0.0,
+
+      0.0,
+      0.0,
+      0.0,
+      1.0
+    ]
+  },
+  "dist_coeffs": [
+    -0.44902,
+    0.248409,
+    -0.000537,
+    -0.000112,
+    -0.076989
+  ]
+}
diff --git a/y2024_swerve/constants/test_data/test_team.json b/y2024_swerve/constants/test_data/test_team.json
new file mode 100644
index 0000000..644af99
--- /dev/null
+++ b/y2024_swerve/constants/test_data/test_team.json
@@ -0,0 +1,28 @@
+{% from 'y2024_swerve/constants/common.jinja2' import front_left_zero %}
+{% from 'y2024_swerve/constants/common.jinja2' import front_right_zero %}
+{% from 'y2024_swerve/constants/common.jinja2' import back_left_zero %}
+{% from 'y2024_swerve/constants/common.jinja2' import back_right_zero %}
+
+{
+  "robot": {
+    "front_left_zeroing_constants":  {{ front_left_zero | tojson(indent=2)}},
+    "front_right_zeroing_constants":  {{ front_right_zero | tojson(indent=2)}},
+    "back_left_zeroing_constants":  {{ back_left_zero | tojson(indent=2)}},
+    "back_right_zeroing_constants":  {{ back_right_zero | tojson(indent=2)}},
+    "cameras": [
+      {
+        "calibration": {% include 'y2024_swerve/constants/calib_files/calibration_imu-9971-0_cam-24-10_2024-02-24_16-44-05.json' %}
+      },
+      {
+        "calibration": {% include 'y2024_swerve/constants/calib_files/calibration_imu-9971-1_cam-24-12_2024-03-24_11-52-49.json' %}
+      },
+      {
+        "calibration": {% include 'y2024_swerve/constants/calib_files/calibration_orin1-9971-0_cam-24-09_2024-03-24_11-52-49.json' %}
+      },
+      {
+        "calibration": {% include 'y2024_swerve/constants/calib_files/calibration_orin1-9971-1_cam-24-11_2024-03-24_11-52-49.json' %}
+      }
+    ]
+  },
+  {% include 'y2024_swerve/constants/common.json' %}
+}
diff --git a/y2024_swerve/constants/validator.bzl b/y2024_swerve/constants/validator.bzl
new file mode 100644
index 0000000..92592df
--- /dev/null
+++ b/y2024_swerve/constants/validator.bzl
@@ -0,0 +1,13 @@
+load("@aspect_bazel_lib//lib:run_binary.bzl", "run_binary")
+
+# Validates the constants.json file and outputs a formatted version.
+# TODO(max): Make this generic/template it out into frc971
+def constants_json(name, src, out):
+    run_binary(
+        name = name,
+        tool = "//y2024_swerve/constants:constants_formatter",
+        srcs = [src],
+        outs = [out],
+        args = ["$(location %s)" % (src)] + ["$(location %s)" % (out)],
+        visibility = ["//visibility:public"],
+    )
diff --git a/y2024_swerve/drivetrain_can_position.fbs b/y2024_swerve/drivetrain_can_position.fbs
deleted file mode 100644
index f0d41a8..0000000
--- a/y2024_swerve/drivetrain_can_position.fbs
+++ /dev/null
@@ -1,17 +0,0 @@
-include "frc971/control_loops/can_talonfx.fbs";
-namespace y2024_swerve;
-
-table SwerveModuleCANPosition {
-  rotation: frc971.control_loops.CANTalonFX (id: 0);
-  translation: frc971.control_loops.CANTalonFX (id: 1);
-}
-
-// CAN Readings from the CAN sensor reader loop for each swerve module
-table AbsoluteCANPosition {
-  front_left: SwerveModuleCANPosition (id: 0);
-  front_right: SwerveModuleCANPosition (id: 1);
-  back_left: SwerveModuleCANPosition (id: 2);
-  back_right: SwerveModuleCANPosition (id: 3);
-}
-
-root_type AbsoluteCANPosition;
diff --git a/y2024_swerve/drivetrain_position.fbs b/y2024_swerve/drivetrain_position.fbs
deleted file mode 100644
index 902cfee..0000000
--- a/y2024_swerve/drivetrain_position.fbs
+++ /dev/null
@@ -1,16 +0,0 @@
-include "frc971/control_loops/control_loops.fbs";
-namespace y2024_swerve;
-
-table AbsoluteDrivetrainPosition {
-  // Position of the follower wheels from the encoders
-  follower_wheel_one_position:double (id: 0);
-  follower_wheel_two_position:double (id: 1);
-
-  // Position from the mag encoder on each module.
-  front_left_position: frc971.AbsolutePosition (id: 2);
-  front_right_position: frc971.AbsolutePosition (id: 3);
-  back_left_position: frc971.AbsolutePosition (id: 4);
-  back_right_position: frc971.AbsolutePosition  (id: 5);
-}
-
-root_type AbsoluteDrivetrainPosition;
diff --git a/y2024_swerve/swerve_publisher_lib.cc b/y2024_swerve/swerve_publisher_lib.cc
index 771d770..2eb9cce 100644
--- a/y2024_swerve/swerve_publisher_lib.cc
+++ b/y2024_swerve/swerve_publisher_lib.cc
@@ -5,16 +5,18 @@
                                                const std::string &filename,
                                                double duration)
     : drivetrain_output_sender_(
-          event_loop->MakeSender<drivetrain::swerve::Output>("/drivetrain")) {
+          event_loop->MakeSender<frc971::control_loops::swerve::Output>(
+              "/drivetrain")) {
   event_loop
       ->AddTimer([this, filename]() {
         auto output_builder = drivetrain_output_sender_.MakeBuilder();
 
         auto drivetrain_output =
-            aos::JsonFileToFlatbuffer<drivetrain::swerve::Output>(filename);
+            aos::JsonFileToFlatbuffer<frc971::control_loops::swerve::Output>(
+                filename);
 
         auto copied_flatbuffer =
-            aos::CopyFlatBuffer<drivetrain::swerve::Output>(
+            aos::CopyFlatBuffer<frc971::control_loops::swerve::Output>(
                 drivetrain_output, output_builder.fbb());
         CHECK(drivetrain_output.Verify());
 
@@ -26,16 +28,18 @@
   event_loop
       ->AddTimer([this, exit_handle]() {
         auto builder = drivetrain_output_sender_.MakeBuilder();
-        drivetrain::swerve::SwerveModuleOutput::Builder swerve_module_builder =
-            builder.MakeBuilder<drivetrain::swerve::SwerveModuleOutput>();
+        frc971::control_loops::swerve::SwerveModuleOutput::Builder
+            swerve_module_builder = builder.MakeBuilder<
+                frc971::control_loops::swerve::SwerveModuleOutput>();
 
         swerve_module_builder.add_rotation_current(0.0);
         swerve_module_builder.add_translation_current(0.0);
 
         auto swerve_module_offset = swerve_module_builder.Finish();
 
-        drivetrain::swerve::Output::Builder drivetrain_output_builder =
-            builder.MakeBuilder<drivetrain::swerve::Output>();
+        frc971::control_loops::swerve::Output::Builder
+            drivetrain_output_builder =
+                builder.MakeBuilder<frc971::control_loops::swerve::Output>();
 
         drivetrain_output_builder.add_front_left_output(swerve_module_offset);
         drivetrain_output_builder.add_front_right_output(swerve_module_offset);
diff --git a/y2024_swerve/swerve_publisher_lib.h b/y2024_swerve/swerve_publisher_lib.h
index 9206eab..e577455 100644
--- a/y2024_swerve/swerve_publisher_lib.h
+++ b/y2024_swerve/swerve_publisher_lib.h
@@ -8,20 +8,17 @@
 #include "aos/flatbuffer_merge.h"
 #include "aos/init.h"
 #include "aos/json_to_flatbuffer.h"
-#include "frc971/control_loops/drivetrain/swerve/swerve_drivetrain_output_generated.h"
+#include "frc971/control_loops/swerve/swerve_drivetrain_output_generated.h"
 
 namespace y2024_swerve {
 
-namespace drivetrain = frc971::control_loops::drivetrain;
-
 class SwervePublisher {
  public:
   SwervePublisher(aos::EventLoop *event_loop, aos::ExitHandle *exit_handle,
                   const std::string &filename, double duration);
 
  private:
-  aos::Sender<frc971::control_loops::drivetrain::swerve::Output>
-      drivetrain_output_sender_;
+  aos::Sender<frc971::control_loops::swerve::Output> drivetrain_output_sender_;
 };
 
 }  // namespace y2024_swerve
diff --git a/y2024_swerve/swerve_publisher_lib_test.cc b/y2024_swerve/swerve_publisher_lib_test.cc
index 95892cc..096dc9e 100644
--- a/y2024_swerve/swerve_publisher_lib_test.cc
+++ b/y2024_swerve/swerve_publisher_lib_test.cc
@@ -16,8 +16,7 @@
             event_loop_factory_.MakeEventLoop("swerve_publisher", roborio_)),
         exit_handle_(event_loop_factory_.MakeExitHandle()),
         drivetrain_swerve_output_fetcher_(
-            event_loop_->MakeFetcher<
-                frc971::control_loops::drivetrain::swerve::Output>(
+            event_loop_->MakeFetcher<frc971::control_loops::swerve::Output>(
                 "/drivetrain")),
         swerve_publisher_(event_loop_.get(), exit_handle_.get(),
                           "y2024_swerve/swerve_drivetrain_output.json", 100) {}
@@ -39,7 +38,7 @@
   std::unique_ptr<aos::EventLoop> event_loop_;
   std::unique_ptr<aos::ExitHandle> exit_handle_;
 
-  aos::Fetcher<frc971::control_loops::drivetrain::swerve::Output>
+  aos::Fetcher<frc971::control_loops::swerve::Output>
       drivetrain_swerve_output_fetcher_;
 
   y2024_swerve::SwervePublisher swerve_publisher_;
diff --git a/y2024_swerve/vision/BUILD b/y2024_swerve/vision/BUILD
new file mode 100644
index 0000000..7bbfef9
--- /dev/null
+++ b/y2024_swerve/vision/BUILD
@@ -0,0 +1,85 @@
+filegroup(
+    name = "image_streamer_start",
+    srcs = ["image_streamer_start.sh"],
+    visibility = ["//visibility:public"],
+)
+
+cc_binary(
+    name = "target_mapping",
+    srcs = [
+        "target_mapping.cc",
+        "vision_util.cc",
+        "vision_util.h",
+    ],
+    data = [
+        "//y2024_swerve:aos_config",
+        "//y2024_swerve/constants:constants.json",
+        "//y2024_swerve/vision:maps",
+    ],
+    target_compatible_with = ["@platforms//os:linux"],
+    visibility = ["//y2024_swerve:__subpackages__"],
+    deps = [
+        "//aos:init",
+        "//aos/events:simulated_event_loop",
+        "//aos/events/logging:log_reader",
+        "//aos/util:mcap_logger",
+        "//frc971/constants:constants_sender_lib",
+        "//frc971/control_loops:pose",
+        "//frc971/vision:calibration_fbs",
+        "//frc971/vision:charuco_lib",
+        "//frc971/vision:target_mapper",
+        "//frc971/vision:vision_util_lib",
+        "//frc971/vision:visualize_robot",
+        "//third_party:opencv",
+        "//y2024_swerve/constants:constants_fbs",
+        "//y2024_swerve/constants:simulated_constants_sender",
+    ],
+)
+
+cc_binary(
+    name = "apriltag_detector",
+    srcs = [
+        "apriltag_detector.cc",
+        "vision_util.cc",
+        "vision_util.h",
+    ],
+    features = ["cuda"],
+    target_compatible_with = ["@platforms//cpu:arm64"],
+    visibility = ["//visibility:public"],
+    deps = [
+        "//aos:configuration",
+        "//aos:init",
+        "//aos/events:shm_event_loop",
+        "//frc971/orin:gpu_apriltag_lib",
+        "//third_party:cudart",
+        "//third_party/apriltag",
+        "//y2024_swerve/constants:constants_fbs",
+        "@com_github_gflags_gflags//:gflags",
+        "@com_github_google_glog//:glog",
+        "@com_github_nvidia_cccl//:cccl",
+    ],
+)
+
+cc_binary(
+    name = "viewer",
+    srcs = [
+        "viewer.cc",
+        "vision_util.cc",
+        "vision_util.h",
+    ],
+    target_compatible_with = ["@platforms//os:linux"],
+    visibility = [
+        "//y2024_swerve:__subpackages__",
+    ],
+    deps = [
+        "//aos:init",
+        "//aos:json_to_flatbuffer",
+        "//aos/events:shm_event_loop",
+        "//frc971/constants:constants_sender_lib",
+        "//frc971/vision:vision_fbs",
+        "//frc971/vision:vision_util_lib",
+        "//third_party:opencv",
+        "//y2024_swerve/constants:constants_fbs",
+        "@com_google_absl//absl/strings",
+    ],
+)
diff --git a/y2024_swerve/vision/README.md b/y2024_swerve/vision/README.md
new file mode 100644
index 0000000..c81581f
--- /dev/null
+++ b/y2024_swerve/vision/README.md
@@ -0,0 +1,25 @@
+How to use the extrinsic calibration for camera-to-camera calibration
+
+This all assumes you have cameras that have been intrinsically
+calibrated, and that pi1 has a valid extrinsic calibration (from robot
+origin / IMU to the pi1 camera).
+
+It by default will compute the extrinsics for each of the other cameras (pi2,
+pi3, pi4) relative to the robot origin (IMU origin).
+
+Steps:
+* Place two Aruco Diamond markers about 1 meter apart
+  (center-to-center) at a height so that they will be in view of the
+  cameras when the robot is about 1-2m away
+* Start with the robot in a position that both markers are fully in
+  view by one camera
+* Enable logging for all cameras
+* Rotate the robot in place through a full circle, so that each camera sees both tags, and at times just one tag.
+* Stop the logging and copy the files to your laptop
+* Run the calibration code on the resulting files, e.g.,
+  * `bazel run -c opt //y2023/vision:calibrate_multi_cameras -- /data/PATH_TO_LOGS --team_number 971 --target_type charuco_diamond
+  * Can add "--visualize" flag to see the camera views and marker detections
+  * I've sometimes found it necessary to add the "--skip_missing_forwarding_entries" flag-- as guided by the logging messages
+* From the output, copy the calculated ("Updated") extrinsic into the
+  corresponding calibration file for the right robot and camera in the
+  calib_files directory
diff --git a/y2024_swerve/vision/apriltag_detector.cc b/y2024_swerve/vision/apriltag_detector.cc
new file mode 100644
index 0000000..4d4025e
--- /dev/null
+++ b/y2024_swerve/vision/apriltag_detector.cc
@@ -0,0 +1,52 @@
+
+#include <string>
+
+#include "aos/init.h"
+#include "frc971/orin/gpu_apriltag.h"
+#include "y2024_swerve/constants/constants_generated.h"
+#include "y2024_swerve/vision/vision_util.h"
+
+DEFINE_string(channel, "/camera", "Channel name");
+DEFINE_string(config, "aos_config.json", "Path to the config file to use.");
+
+void GpuApriltagDetector() {
+  aos::FlatbufferDetachedBuffer<aos::Configuration> config =
+      aos::configuration::ReadConfig(FLAGS_config);
+
+  frc971::constants::WaitForConstants<y2024_swerve::Constants>(
+      &config.message());
+
+  aos::ShmEventLoop event_loop(&config.message());
+
+  const frc971::constants::ConstantsFetcher<y2024_swerve::Constants>
+      calibration_data(&event_loop);
+
+  CHECK(FLAGS_channel.length() == 8);
+  int camera_id = std::stoi(FLAGS_channel.substr(7, 1));
+  const frc971::vision::calibration::CameraCalibration *calibration =
+      y2024_swerve::vision::FindCameraCalibration(
+          calibration_data.constants(),
+          event_loop.node()->name()->string_view(), camera_id);
+
+  frc971::apriltag::ApriltagDetector detector(&event_loop, FLAGS_channel,
+                                              calibration);
+
+  // TODO(austin): Figure out our core pinning strategy.
+  // event_loop.SetRuntimeAffinity(aos::MakeCpusetFromCpus({5}));
+
+  LOG(INFO) << "Setting scheduler priority";
+  struct sched_param param;
+  param.sched_priority = 21;
+  PCHECK(sched_setscheduler(0, SCHED_FIFO, &param) == 0);
+
+  LOG(INFO) << "Running event loop";
+  // TODO(austin): Pre-warm it...
+  event_loop.Run();
+}  // namespace frc971::apriltag
+
+int main(int argc, char **argv) {
+  aos::InitGoogle(&argc, &argv);
+  GpuApriltagDetector();
+
+  return 0;
+}
diff --git a/y2024_swerve/vision/image_streamer_start.sh b/y2024_swerve/vision/image_streamer_start.sh
new file mode 100755
index 0000000..48d9da7
--- /dev/null
+++ b/y2024_swerve/vision/image_streamer_start.sh
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+# Some configurations to avoid dropping frames
+# 640x480@30fps, 400x300@60fps.
+# Bitrate 500000-1500000
+WIDTH=640
+HEIGHT=480
+BITRATE=1500000
+LISTEN_ON="/camera/downsized"
+# Don't interfere with field webpage
+STREAMING_PORT=1181
+
+# Handle weirdness with openssl and gstreamer
+export OPENSSL_CONF=""
+
+# Enable for verbose logging
+#export GST_DEBUG=4
+
+export LD_LIBRARY_PATH=/usr/lib/aarch64-linux-gnu/gstreamer-1.0
+
+exec ./image_streamer --width=$WIDTH --height=$HEIGHT --bitrate=$BITRATE --listen_on=$LISTEN_ON --config=aos_config.json --streaming_port=$STREAMING_PORT
+
diff --git a/y2024_swerve/vision/maps/BUILD b/y2024_swerve/vision/maps/BUILD
new file mode 100644
index 0000000..38191a4
--- /dev/null
+++ b/y2024_swerve/vision/maps/BUILD
@@ -0,0 +1,7 @@
+filegroup(
+    name = "maps",
+    srcs = glob([
+        "*.json",
+    ]),
+    visibility = ["//visibility:public"],
+)
diff --git a/y2024_swerve/vision/maps/target_map.json b/y2024_swerve/vision/maps/target_map.json
new file mode 100644
index 0000000..2a8dfef
--- /dev/null
+++ b/y2024_swerve/vision/maps/target_map.json
@@ -0,0 +1,236 @@
+{
+/* Targets have positive Z axis pointing into the board, positive X to the right
+   when looking at the board, and positive Y is down when looking at the board.
+   This means that you will get an identity rotation from the camera to target
+   frame when the target is upright, flat, and centered in the camera's view.
+
+   The global frame as the origin at the center of the field, positive X points
+   at the red driver's station, and positive Z points straight up.
+   */
+    "target_poses": [
+        {
+            "id": 1,
+            "position": {
+                "x": 6.809,
+                "y": -3.860,
+                "z": 1.361
+            },
+            "orientation": {
+                "w": 0.1830127,
+                "x": -0.1830127,
+                "y": 0.6830127,
+                "z": -0.6830127
+            }
+        },
+        {
+            "id": 2,
+            "position": {
+                "x": 7.915,
+                "y": -3.223,
+                "z": 1.361
+            },
+            "orientation": {
+                "w": 0.1830127,
+                "x": -0.1830127,
+                "y": 0.6830127,
+                "z": -0.6830127
+            }
+        },
+        {
+            "id": 3,
+            "position": {
+                "x": 8.309,
+                "y": 0.877,
+                "z": 1.456
+            },
+            "orientation": {
+                "w": 0.5,
+                "x": -0.5,
+                "y": 0.5,
+                "z": -0.5
+            }
+        },
+        {
+            "id": 4,
+            "position": {
+                "x": 8.309,
+                "y": 1.442,
+                "z": 1.456
+            },
+            "orientation": {
+                "w": 0.5,
+                "x": -0.5,
+                "y": 0.5,
+                "z": -0.5
+            }
+        },
+        {
+            "id": 5,
+            "position": {
+                "x": 6.428,
+                "y": 4.099,
+                "z": 1.361
+            },
+            "orientation": {
+                "w": 0.7071068,
+                "x": -0.7071068,
+                "y": 0.0,
+                "z": 0.0
+            }
+        },
+        {
+            "id": 6,
+            "position": {
+                "x": -6.430,
+                "y": 4.099,
+                "z": 1.361
+            },
+            "orientation": {
+                "w": 0.7071068,
+                "x": -0.7071068,
+                "y": 0.0,
+                "z": 0.0
+            }
+        },
+        {
+            "id": 7,
+            "position": {
+                "x": -8.309,
+                "y": 1.442,
+                "z": 1.474
+            },
+            "orientation": {
+                "w": 0.5,
+                "x": -0.5,
+                "y": -0.5,
+                "z": 0.5
+            }
+        },
+        {
+            "id": 8,
+            "position": {
+                "x": -8.309,
+                "y": 0.877,
+                "z": 1.474
+            },
+            "orientation": {
+                "w": 0.5,
+                "x": -0.5,
+                "y": -0.5,
+                "z": 0.5
+            }
+        },
+        {
+            "id": 9,
+            "position": {
+                "x": -7.915,
+                "y": -3.223,
+                "z": 1.361
+            },
+            "orientation": {
+                "w": 0.1830127,
+                "x": -0.1830127,
+                "y": -0.6830127,
+                "z": 0.6830127
+            }
+        },
+        {
+            "id": 10,
+            "position": {
+                "x": -6.809,
+                "y": -3.860,
+                "z": 1.361
+            },
+            "orientation": {
+                "w": 0.1830127,
+                "x": -0.1830127,
+                "y": -0.6830127,
+                "z": 0.6830127
+            }
+        },
+        {
+            "id": 11,
+            "position": {
+                "x": 3.629,
+                "y": -0.393,
+                "z": 1.326
+            },
+            "orientation": {
+                "w": 0.6830127,
+                "x": -0.6830127,
+                "y": -0.1830127,
+                "z": 0.1830127
+            }
+        },
+        {
+            "id": 12,
+            "position": {
+                "x": 3.630,
+                "y": 0.392,
+                "z": 1.326
+            },
+            "orientation": {
+                "w": 0.1830127,
+                "x": -0.1830127,
+                "y": -0.6830127,
+                "z": 0.6830127
+            }
+        },
+        {
+            "id": 13,
+            "position": {
+                "x": 2.949,
+                "y": -0.000,
+                "z": 1.326
+            },
+            "orientation": {
+                "w": 0.5,
+                "x": -0.5,
+                "y": 0.5,
+                "z": -0.5
+            }
+        },
+        {
+            "id": 14,
+            "position": {
+                "x": -2.949,
+                "y": -0.000,
+                "z": 1.326
+            },
+            "orientation": {
+                "w": 0.5,
+                "x": -0.5,
+                "y": -0.5,
+                "z": 0.5
+            }
+        },
+        {
+            "id": 15,
+            "position": {
+                "x": -3.629,
+                "y": 0.393,
+                "z": 1.326
+            },
+            "orientation": {
+                "w": 0.1830127,
+                "x": -0.1830127,
+                "y": 0.6830127,
+                "z": -0.6830127
+            }
+        },
+        {
+            "id": 16,
+            "position": {
+                "x": -3.630,
+                "y": -0.392,
+                "z": 1.326
+            },
+            "orientation": {
+                "w": 0.6830127,
+                "x": -0.6830127,
+                "y": 0.1830127,
+                "z": -0.1830127
+            }
+        }
+    ]
+}
diff --git a/y2024/vision/rename_calibration_file.sh b/y2024_swerve/vision/rename_calibration_file.sh
similarity index 100%
rename from y2024/vision/rename_calibration_file.sh
rename to y2024_swerve/vision/rename_calibration_file.sh
diff --git a/y2024_swerve/vision/target_mapping.cc b/y2024_swerve/vision/target_mapping.cc
new file mode 100644
index 0000000..c540654
--- /dev/null
+++ b/y2024_swerve/vision/target_mapping.cc
@@ -0,0 +1,485 @@
+#include <string>
+
+#include "Eigen/Dense"
+#include "opencv2/aruco.hpp"
+#include "opencv2/calib3d.hpp"
+#include "opencv2/core/eigen.hpp"
+#include "opencv2/features2d.hpp"
+#include "opencv2/highgui.hpp"
+#include "opencv2/highgui/highgui.hpp"
+#include "opencv2/imgproc.hpp"
+
+#include "aos/configuration.h"
+#include "aos/events/logging/log_reader.h"
+#include "aos/events/simulated_event_loop.h"
+#include "aos/init.h"
+#include "aos/util/mcap_logger.h"
+#include "frc971/constants/constants_sender_lib.h"
+#include "frc971/control_loops/pose.h"
+#include "frc971/vision/calibration_generated.h"
+#include "frc971/vision/charuco_lib.h"
+#include "frc971/vision/target_mapper.h"
+#include "frc971/vision/vision_generated.h"
+#include "frc971/vision/vision_util_lib.h"
+#include "frc971/vision/visualize_robot.h"
+#include "y2024_swerve/constants/simulated_constants_sender.h"
+#include "y2024_swerve/vision/vision_util.h"
+
+DEFINE_string(config, "",
+              "If set, override the log's config file with this one.");
+DEFINE_string(constants_path, "y2024_swerve/constants/constants.json",
+              "Path to the constant file");
+DEFINE_string(dump_constraints_to, "/tmp/mapping_constraints.txt",
+              "Write the target constraints to this path");
+DEFINE_string(dump_stats_to, "/tmp/mapping_stats.txt",
+              "Write the mapping stats to this path");
+DEFINE_string(field_name, "crescendo",
+              "Field name, for the output json filename and flatbuffer field");
+DEFINE_string(json_path, "y2024_swerve/vision/maps/target_map.json",
+              "Specify path for json with initial pose guesses.");
+DEFINE_double(max_pose_error, 1e-6,
+              "Throw out target poses with a higher pose error than this");
+DEFINE_double(
+    max_pose_error_ratio, 0.4,
+    "Throw out target poses with a higher pose error ratio than this");
+DEFINE_string(mcap_output_path, "", "Log to output.");
+DEFINE_string(output_dir, "y2024_swerve/vision/maps",
+              "Directory to write solved target map to");
+DEFINE_double(pause_on_distance, 2.0,
+              "Pause if two consecutive implied robot positions differ by more "
+              "than this many meters");
+DEFINE_string(orin, "orin1",
+              "Orin name to generate mcap log for; defaults to orin1.");
+DEFINE_uint64(skip_to, 1,
+              "Start at combined image of this number (1 is the first image)");
+DEFINE_bool(solve, true, "Whether to solve for the field's target map.");
+DEFINE_bool(split_field, false,
+            "Whether to break solve into two sides of field");
+DEFINE_int32(team_number, 0,
+             "Required: Use the calibration for a node with this team number");
+DEFINE_uint64(wait_key, 1,
+              "Time in ms to wait between images, if no click (0 to wait "
+              "indefinitely until click).");
+
+DECLARE_int32(frozen_target_id);
+DECLARE_int32(min_target_id);
+DECLARE_int32(max_target_id);
+DECLARE_bool(visualize_solver);
+
+namespace y2024_swerve::vision {
+using frc971::vision::DataAdapter;
+using frc971::vision::ImageCallback;
+using frc971::vision::PoseUtils;
+using frc971::vision::TargetMap;
+using frc971::vision::TargetMapper;
+using frc971::vision::VisualizeRobot;
+namespace calibration = frc971::vision::calibration;
+
+// Class to handle reading target poses from a replayed log,
+// displaying various debug info, and passing the poses to
+// frc971::vision::TargetMapper for field mapping.
+class TargetMapperReplay {
+ public:
+  TargetMapperReplay(aos::logger::LogReader *reader);
+
+  // Solves for the target poses with the accumulated detections if FLAGS_solve.
+  void MaybeSolve();
+
+ private:
+  static constexpr int kImageWidth = 1280;
+
+  // Contains fixed target poses without solving, for use with visualization
+  static const TargetMapper kFixedTargetMapper;
+
+  // Map of TargetId to alliance "color" for splitting field
+  static std::map<uint, std::string> kIdAllianceMap;
+
+  // Change reference frame from camera to robot
+  static Eigen::Affine3d CameraToRobotDetection(Eigen::Affine3d H_camera_target,
+                                                Eigen::Affine3d extrinsics);
+
+  // Adds april tag detections into the detection list, and handles
+  // visualization
+  void HandleAprilTags(const TargetMap &map,
+                       aos::distributed_clock::time_point node_distributed_time,
+                       std::string camera_name, Eigen::Affine3d extrinsics);
+  // Gets images from the given pi and passes apriltag positions to
+  // HandleAprilTags()
+  void HandleNodeCaptures(
+      aos::EventLoop *mapping_event_loop,
+      frc971::constants::ConstantsFetcher<y2024_swerve::Constants>
+          *constants_fetcher,
+      int camera_number);
+
+  aos::logger::LogReader *reader_;
+  // April tag detections from all pis
+  std::vector<DataAdapter::TimestampedDetection> timestamped_target_detections_;
+
+  VisualizeRobot vis_robot_;
+  // Set of camera names which are currently drawn on the display
+  std::set<std::string> drawn_cameras_;
+  // Number of frames displayed
+  size_t display_count_;
+  // Last time we drew onto the display image.
+  // This is different from when we actually call imshow() to update
+  // the display window
+  aos::distributed_clock::time_point last_draw_time_;
+
+  Eigen::Affine3d last_H_world_robot_;
+  // Maximum distance between consecutive T_world_robot's in one display frame,
+  // used to determine if we need to pause for the user to see this frame
+  // clearly
+  double max_delta_T_world_robot_;
+  double ignore_count_;
+
+  std::vector<std::unique_ptr<aos::EventLoop>> mapping_event_loops_;
+
+  std::unique_ptr<aos::EventLoop> mcap_event_loop_;
+  std::unique_ptr<aos::McapLogger> relogger_;
+};
+
+std::vector<CameraNode> node_list(y2024_swerve::vision::CreateNodeList());
+
+std::map<std::string, int> camera_ordering_map(
+    y2024_swerve::vision::CreateOrderingMap(node_list));
+
+std::map<uint, std::string> TargetMapperReplay::kIdAllianceMap = {
+    {1, "red"},  {2, "red"},   {3, "red"},   {4, "red"},
+    {5, "red"},  {6, "blue"},  {7, "blue"},  {8, "blue"},
+    {9, "blue"}, {10, "blue"}, {11, "red"},  {12, "red"},
+    {13, "red"}, {14, "blue"}, {15, "blue"}, {16, "blue"}};
+
+const auto TargetMapperReplay::kFixedTargetMapper =
+    TargetMapper(FLAGS_json_path, ceres::examples::VectorOfConstraints{});
+
+Eigen::Affine3d TargetMapperReplay::CameraToRobotDetection(
+    Eigen::Affine3d H_camera_target, Eigen::Affine3d extrinsics) {
+  const Eigen::Affine3d H_robot_camera = extrinsics;
+  const Eigen::Affine3d H_robot_target = H_robot_camera * H_camera_target;
+  return H_robot_target;
+}
+
+TargetMapperReplay::TargetMapperReplay(aos::logger::LogReader *reader)
+    : reader_(reader),
+      timestamped_target_detections_(),
+      vis_robot_(cv::Size(1280, 1000)),
+      drawn_cameras_(),
+      display_count_(0),
+      last_draw_time_(aos::distributed_clock::min_time),
+      last_H_world_robot_(Eigen::Matrix4d::Identity()),
+      max_delta_T_world_robot_(0.0) {
+  reader_->RemapLoggedChannel("/orin1/constants", "y2024_swerve.Constants");
+  reader_->RemapLoggedChannel("/imu/constants", "y2024_swerve.Constants");
+  // If it's Box of Orins, don't remap roborio constants
+  reader_->MaybeRemapLoggedChannel<Constants>("/roborio/constants");
+  reader_->Register();
+
+  SendSimulationConstants(reader_->event_loop_factory(), FLAGS_team_number,
+                          FLAGS_constants_path);
+
+  if (FLAGS_visualize_solver) {
+    vis_robot_.ClearImage();
+    // Set focal length to zoomed in, to view extrinsics
+    const double kFocalLength = 1500.0;
+    vis_robot_.SetDefaultViewpoint(kImageWidth, kFocalLength);
+  }
+
+  for (const CameraNode &camera_node : node_list) {
+    const aos::Node *node = aos::configuration::GetNode(
+        reader_->configuration(), camera_node.node_name.c_str());
+
+    mapping_event_loops_.emplace_back(
+        reader_->event_loop_factory()->MakeEventLoop(
+            camera_node.node_name + "mapping", node));
+
+    frc971::constants::ConstantsFetcher<y2024_swerve::Constants>
+        constants_fetcher(
+            mapping_event_loops_[mapping_event_loops_.size() - 1].get());
+    HandleNodeCaptures(
+        mapping_event_loops_[mapping_event_loops_.size() - 1].get(),
+        &constants_fetcher, camera_node.camera_number);
+
+    if (FLAGS_visualize_solver) {
+      // Show the extrinsics calibration to start, for reference to confirm
+      const auto *calibration = FindCameraCalibration(
+          constants_fetcher.constants(),
+          mapping_event_loops_.back()->node()->name()->string_view(),
+          camera_node.camera_number);
+      cv::Mat extrinsics_cv =
+          frc971::vision::CameraExtrinsics(calibration).value();
+      Eigen::Matrix4d extrinsics_matrix;
+      cv::cv2eigen(extrinsics_cv, extrinsics_matrix);
+      const auto extrinsics = Eigen::Affine3d(extrinsics_matrix);
+
+      vis_robot_.DrawRobotOutline(extrinsics, camera_node.camera_name(),
+                                  kOrinColors.at(camera_node.camera_name()));
+    }
+  }
+
+  if (FLAGS_visualize_solver) {
+    cv::imshow("Extrinsics", vis_robot_.image_);
+    cv::waitKey(0);
+    vis_robot_.ClearImage();
+    // Reset focal length to more zoomed out view for field
+    const double kFocalLength = 500.0;
+    vis_robot_.SetDefaultViewpoint(kImageWidth, kFocalLength);
+  }
+}
+
+// Add detected apriltag poses relative to the robot to
+// timestamped_target_detections
+void TargetMapperReplay::HandleAprilTags(
+    const TargetMap &map,
+    aos::distributed_clock::time_point node_distributed_time,
+    std::string camera_name, Eigen::Affine3d extrinsics) {
+  bool drew = false;
+  std::stringstream label;
+  label << camera_name << " - ";
+
+  if (map.target_poses()->size() == 0) {
+    VLOG(2) << "Got 0 AprilTags for camera " << camera_name;
+    return;
+  }
+
+  for (const auto *target_pose_fbs : *map.target_poses()) {
+    // Skip detections with invalid ids
+    if (static_cast<TargetMapper::TargetId>(target_pose_fbs->id()) <
+            FLAGS_min_target_id ||
+        static_cast<TargetMapper::TargetId>(target_pose_fbs->id()) >
+            FLAGS_max_target_id) {
+      VLOG(1) << "Skipping tag with invalid id of " << target_pose_fbs->id();
+      continue;
+    }
+
+    // Skip detections with high pose errors
+    if (target_pose_fbs->pose_error() > FLAGS_max_pose_error) {
+      VLOG(1) << "Skipping tag " << target_pose_fbs->id()
+              << " due to pose error of " << target_pose_fbs->pose_error();
+      continue;
+    }
+    // Skip detections with high pose error ratios
+    if (target_pose_fbs->pose_error_ratio() > FLAGS_max_pose_error_ratio) {
+      VLOG(1) << "Skipping tag " << target_pose_fbs->id()
+              << " due to pose error ratio of "
+              << target_pose_fbs->pose_error_ratio();
+      continue;
+    }
+
+    const TargetMapper::TargetPose target_pose =
+        PoseUtils::TargetPoseFromFbs(*target_pose_fbs);
+
+    Eigen::Affine3d H_camera_target =
+        Eigen::Translation3d(target_pose.pose.p) * target_pose.pose.q;
+    Eigen::Affine3d H_robot_target =
+        CameraToRobotDetection(H_camera_target, extrinsics);
+
+    ceres::examples::Pose3d target_pose_camera =
+        PoseUtils::Affine3dToPose3d(H_camera_target);
+    double distance_from_camera = target_pose_camera.p.norm();
+    double distortion_factor = target_pose_fbs->distortion_factor();
+
+    double distance_threshold = 5.0;
+    if (distance_from_camera > distance_threshold) {
+      ignore_count_++;
+      LOG(INFO) << "Ignored " << ignore_count_ << " AprilTags with distance "
+                << distance_from_camera << " > " << distance_threshold;
+      continue;
+    }
+
+    CHECK(map.has_monotonic_timestamp_ns())
+        << "Need detection timestamps for mapping";
+
+    // Detection is usable, so store it
+    timestamped_target_detections_.emplace_back(
+        DataAdapter::TimestampedDetection{
+            .time = node_distributed_time,
+            .H_robot_target = H_robot_target,
+            .distance_from_camera = distance_from_camera,
+            .distortion_factor = distortion_factor,
+            .id = static_cast<TargetMapper::TargetId>(target_pose.id)});
+
+    if (FLAGS_visualize_solver) {
+      // If we've already drawn this camera_name in the current image,
+      // display the image before clearing and adding the new poses
+      if (drawn_cameras_.count(camera_name) != 0) {
+        display_count_++;
+        cv::putText(vis_robot_.image_,
+                    "Poses #" + std::to_string(display_count_),
+                    cv::Point(600, 10), cv::FONT_HERSHEY_PLAIN, 1.0,
+                    cv::Scalar(255, 255, 255));
+
+        if (display_count_ >= FLAGS_skip_to) {
+          VLOG(1) << "Showing image for camera " << camera_name
+                  << " since we've drawn it already";
+          cv::imshow("View", vis_robot_.image_);
+          // Pause if delta_T is too large, but only after first image (to make
+          // sure the delta's are correct)
+          if (max_delta_T_world_robot_ > FLAGS_pause_on_distance &&
+              display_count_ > 1) {
+            LOG(INFO) << "Pausing since the delta between robot estimates is "
+                      << max_delta_T_world_robot_ << " which is > threshold of "
+                      << FLAGS_pause_on_distance;
+            cv::waitKey(0);
+          } else {
+            cv::waitKey(FLAGS_wait_key);
+          }
+          max_delta_T_world_robot_ = 0.0;
+        } else {
+          VLOG(2) << "At poses #" << std::to_string(display_count_);
+        }
+        vis_robot_.ClearImage();
+        drawn_cameras_.clear();
+      }
+
+      Eigen::Affine3d H_world_target = PoseUtils::Pose3dToAffine3d(
+          kFixedTargetMapper.GetTargetPoseById(target_pose_fbs->id())->pose);
+      Eigen::Affine3d H_world_robot = H_world_target * H_robot_target.inverse();
+      VLOG(2) << camera_name << ", id " << target_pose_fbs->id()
+              << ", t = " << node_distributed_time
+              << ", pose_error = " << target_pose_fbs->pose_error()
+              << ", pose_error_ratio = " << target_pose_fbs->pose_error_ratio()
+              << ", robot_pos (x,y,z) = "
+              << H_world_robot.translation().transpose();
+
+      label << "id " << target_pose_fbs->id()
+            << ": err (% of max): " << target_pose_fbs->pose_error() << " ("
+            << (target_pose_fbs->pose_error() / FLAGS_max_pose_error)
+            << ") err_ratio: " << target_pose_fbs->pose_error_ratio() << " ";
+
+      vis_robot_.DrawRobotOutline(H_world_robot, camera_name,
+                                  kOrinColors.at(camera_name));
+      vis_robot_.DrawFrameAxes(H_world_target,
+                               std::to_string(target_pose_fbs->id()),
+                               kOrinColors.at(camera_name));
+
+      double delta_T_world_robot =
+          (H_world_robot.translation() - last_H_world_robot_.translation())
+              .norm();
+      max_delta_T_world_robot_ =
+          std::max(delta_T_world_robot, max_delta_T_world_robot_);
+
+      VLOG(1) << "Drew in info for camera " << camera_name << " and target #"
+              << target_pose_fbs->id();
+      drew = true;
+      last_draw_time_ = node_distributed_time;
+      last_H_world_robot_ = H_world_robot;
+    }
+  }
+  if (FLAGS_visualize_solver) {
+    if (drew) {
+      // Collect all the labels from a given camera, and add the text
+      // TODO: Need to fix this one
+      int position_number = camera_ordering_map[camera_name];
+      cv::putText(vis_robot_.image_, label.str(),
+                  cv::Point(10, 30 + 20 * position_number),
+                  cv::FONT_HERSHEY_PLAIN, 1.0, kOrinColors.at(camera_name));
+      drawn_cameras_.emplace(camera_name);
+    } else if (node_distributed_time - last_draw_time_ >
+                   std::chrono::milliseconds(30) &&
+               display_count_ >= FLAGS_skip_to && drew) {
+      // TODO: Check on 30ms value-- does this make sense?
+      double delta_t = (node_distributed_time - last_draw_time_).count() / 1e6;
+      VLOG(1) << "Last result was " << delta_t << "ms ago";
+      cv::putText(vis_robot_.image_, "No detections in last 30ms",
+                  cv::Point(10, 0), cv::FONT_HERSHEY_PLAIN, 1.0,
+                  kOrinColors.at(camera_name));
+      // Display and clear the image if we haven't draw in a while
+      VLOG(1) << "Displaying image due to time lapse";
+      cv::imshow("View", vis_robot_.image_);
+      cv::waitKey(FLAGS_wait_key);
+      max_delta_T_world_robot_ = 0.0;
+      drawn_cameras_.clear();
+    }
+  }
+}
+
+void TargetMapperReplay::HandleNodeCaptures(
+    aos::EventLoop *mapping_event_loop,
+    frc971::constants::ConstantsFetcher<y2024_swerve::Constants>
+        *constants_fetcher,
+    int camera_number) {
+  // Get the camera extrinsics
+  std::string node_name =
+      std::string(mapping_event_loop->node()->name()->string_view());
+  const auto *calibration = FindCameraCalibration(
+      constants_fetcher->constants(), node_name, camera_number);
+  cv::Mat extrinsics_cv = frc971::vision::CameraExtrinsics(calibration).value();
+  Eigen::Matrix4d extrinsics_matrix;
+  cv::cv2eigen(extrinsics_cv, extrinsics_matrix);
+  const auto extrinsics = Eigen::Affine3d(extrinsics_matrix);
+  std::string camera_name = absl::StrFormat(
+      "/%s/camera%d", mapping_event_loop->node()->name()->str(), camera_number);
+
+  mapping_event_loop->MakeWatcher(
+      camera_name.c_str(), [this, mapping_event_loop, extrinsics,
+                            camera_name](const TargetMap &map) {
+        aos::distributed_clock::time_point node_distributed_time =
+            reader_->event_loop_factory()
+                ->GetNodeEventLoopFactory(mapping_event_loop->node())
+                ->ToDistributedClock(aos::monotonic_clock::time_point(
+                    aos::monotonic_clock::duration(
+                        map.monotonic_timestamp_ns())));
+
+        HandleAprilTags(map, node_distributed_time, camera_name, extrinsics);
+      });
+}
+
+void TargetMapperReplay::MaybeSolve() {
+  if (FLAGS_solve) {
+    auto target_constraints =
+        DataAdapter::MatchTargetDetections(timestamped_target_detections_);
+
+    if (FLAGS_split_field) {
+      // Remove constraints between the two sides of the field - these are
+      // basically garbage because of how far the camera is. We will use seeding
+      // below to connect the two sides
+      target_constraints.erase(
+          std::remove_if(
+              target_constraints.begin(), target_constraints.end(),
+              [](const auto &constraint) {
+                return (
+                    kIdAllianceMap[static_cast<uint>(constraint.id_begin)] !=
+                    kIdAllianceMap[static_cast<uint>(constraint.id_end)]);
+              }),
+          target_constraints.end());
+    }
+
+    LOG(INFO) << "Solving for locations of tags with "
+              << target_constraints.size() << " constraints";
+    TargetMapper mapper(FLAGS_json_path, target_constraints);
+    mapper.Solve(FLAGS_field_name, FLAGS_output_dir);
+
+    if (!FLAGS_dump_constraints_to.empty()) {
+      mapper.DumpConstraints(FLAGS_dump_constraints_to);
+    }
+    if (!FLAGS_dump_stats_to.empty()) {
+      mapper.DumpStats(FLAGS_dump_stats_to);
+    }
+    mapper.PrintDiffs();
+  }
+}
+
+void MappingMain(int argc, char *argv[]) {
+  std::vector<DataAdapter::TimestampedDetection> timestamped_target_detections;
+
+  std::optional<aos::FlatbufferDetachedBuffer<aos::Configuration>> config =
+      (FLAGS_config.empty()
+           ? std::nullopt
+           : std::make_optional(aos::configuration::ReadConfig(FLAGS_config)));
+
+  // Open logfiles
+  aos::logger::LogReader reader(
+      aos::logger::SortParts(aos::logger::FindLogs(argc, argv)),
+      config.has_value() ? &config->message() : nullptr);
+
+  TargetMapperReplay mapper_replay(&reader);
+  reader.event_loop_factory()->Run();
+  mapper_replay.MaybeSolve();
+}
+
+}  // namespace y2024_swerve::vision
+
+int main(int argc, char **argv) {
+  aos::InitGoogle(&argc, &argv);
+  y2024_swerve::vision::MappingMain(argc, argv);
+}
diff --git a/y2024_swerve/vision/viewer.cc b/y2024_swerve/vision/viewer.cc
new file mode 100644
index 0000000..143868d
--- /dev/null
+++ b/y2024_swerve/vision/viewer.cc
@@ -0,0 +1,122 @@
+#include "absl/strings/match.h"
+#include "opencv2/calib3d.hpp"
+#include "opencv2/highgui/highgui.hpp"
+#include "opencv2/imgproc.hpp"
+
+#include "aos/events/shm_event_loop.h"
+#include "aos/init.h"
+#include "aos/json_to_flatbuffer.h"
+#include "aos/time/time.h"
+#include "frc971/constants/constants_sender_lib.h"
+#include "frc971/vision/vision_generated.h"
+#include "frc971/vision/vision_util_lib.h"
+#include "y2024_swerve/vision/vision_util.h"
+
+DEFINE_string(capture, "",
+              "If set, capture a single image and save it to this filename.");
+DEFINE_string(channel, "/camera", "Channel name for the image.");
+DEFINE_string(config, "aos_config.json", "Path to the config file to use.");
+DEFINE_int32(rate, 100, "Time in milliseconds to wait between images");
+DEFINE_double(scale, 1.0, "Scale factor for images being displayed");
+
+namespace y2024_swerve::vision {
+namespace {
+
+using frc971::vision::CameraImage;
+
+bool DisplayLoop(const cv::Mat intrinsics, const cv::Mat dist_coeffs,
+                 aos::Fetcher<CameraImage> *image_fetcher) {
+  const CameraImage *image;
+
+  // Read next image
+  if (!image_fetcher->Fetch()) {
+    VLOG(2) << "Couldn't fetch next image";
+    return true;
+  }
+  image = image_fetcher->get();
+  CHECK(image != nullptr) << "Couldn't read image";
+
+  // Create color image:
+  cv::Mat image_color_mat(cv::Size(image->cols(), image->rows()), CV_8UC2,
+                          (void *)image->data()->data());
+  cv::Mat bgr_image(cv::Size(image->cols(), image->rows()), CV_8UC3);
+  cv::cvtColor(image_color_mat, bgr_image, cv::COLOR_YUV2BGR_YUYV);
+
+  if (!FLAGS_capture.empty()) {
+    if (absl::EndsWith(FLAGS_capture, ".bfbs")) {
+      aos::WriteFlatbufferToFile(FLAGS_capture,
+                                 image_fetcher->CopyFlatBuffer());
+    } else {
+      cv::imwrite(FLAGS_capture, bgr_image);
+    }
+
+    return false;
+  }
+
+  cv::Mat undistorted_image;
+  cv::undistort(bgr_image, undistorted_image, intrinsics, dist_coeffs);
+  if (FLAGS_scale != 1.0) {
+    cv::resize(undistorted_image, undistorted_image, cv::Size(), FLAGS_scale,
+               FLAGS_scale);
+  }
+  cv::imshow("Display", undistorted_image);
+
+  int keystroke = cv::waitKey(1);
+  if ((keystroke & 0xFF) == static_cast<int>('c')) {
+    // Convert again, to get clean image
+    cv::cvtColor(image_color_mat, bgr_image, cv::COLOR_YUV2BGR_YUYV);
+    std::stringstream name;
+    name << "capture-" << aos::realtime_clock::now() << ".png";
+    cv::imwrite(name.str(), bgr_image);
+    LOG(INFO) << "Saved image file: " << name.str();
+  } else if ((keystroke & 0xFF) == static_cast<int>('q')) {
+    return false;
+  }
+  return true;
+}
+
+void ViewerMain() {
+  aos::FlatbufferDetachedBuffer<aos::Configuration> config =
+      aos::configuration::ReadConfig(FLAGS_config);
+
+  frc971::constants::WaitForConstants<y2024_swerve::Constants>(
+      &config.message());
+
+  aos::ShmEventLoop event_loop(&config.message());
+
+  frc971::constants::ConstantsFetcher<y2024_swerve::Constants>
+      constants_fetcher(&event_loop);
+  CHECK(FLAGS_channel.length() == 8);
+  int camera_id = std::stoi(FLAGS_channel.substr(7, 1));
+  const auto *calibration_data = FindCameraCalibration(
+      constants_fetcher.constants(), event_loop.node()->name()->string_view(),
+      camera_id);
+  const cv::Mat intrinsics = frc971::vision::CameraIntrinsics(calibration_data);
+  const cv::Mat dist_coeffs =
+      frc971::vision::CameraDistCoeffs(calibration_data);
+
+  aos::Fetcher<CameraImage> image_fetcher =
+      event_loop.MakeFetcher<CameraImage>(FLAGS_channel);
+
+  // Run the display loop
+  event_loop.AddPhasedLoop(
+      [&](int) {
+        if (!DisplayLoop(intrinsics, dist_coeffs, &image_fetcher)) {
+          LOG(INFO) << "Calling event_loop Exit";
+          event_loop.Exit();
+        };
+      },
+      ::std::chrono::milliseconds(FLAGS_rate));
+
+  event_loop.Run();
+
+  image_fetcher = aos::Fetcher<CameraImage>();
+}
+
+}  // namespace
+}  // namespace y2024_swerve::vision
+
+int main(int argc, char **argv) {
+  aos::InitGoogle(&argc, &argv);
+  y2024_swerve::vision::ViewerMain();
+}
diff --git a/y2024_swerve/vision/vision_util.cc b/y2024_swerve/vision/vision_util.cc
new file mode 100644
index 0000000..e08bfaa
--- /dev/null
+++ b/y2024_swerve/vision/vision_util.cc
@@ -0,0 +1,48 @@
+#include "y2024_swerve/vision/vision_util.h"
+
+#include "glog/logging.h"
+
+namespace y2024_swerve::vision {
+
+// Store a list of ordered cameras as you progress around the robot/box of orins
+std::vector<CameraNode> CreateNodeList() {
+  std::vector<CameraNode> list;
+
+  list.push_back({.node_name = "imu", .camera_number = 0});
+  list.push_back({.node_name = "imu", .camera_number = 1});
+  list.push_back({.node_name = "orin1", .camera_number = 1});
+  list.push_back({.node_name = "orin1", .camera_number = 0});
+
+  return list;
+}
+
+// From the node_list, create a numbering scheme from 0 to 3
+std::map<std::string, int> CreateOrderingMap(
+    std::vector<CameraNode> &node_list) {
+  std::map<std::string, int> map;
+
+  for (uint i = 0; i < node_list.size(); i++) {
+    map.insert({node_list.at(i).camera_name(), i});
+  }
+
+  return map;
+}
+
+const frc971::vision::calibration::CameraCalibration *FindCameraCalibration(
+    const y2024_swerve::Constants &calibration_data, std::string_view node_name,
+    int camera_number) {
+  CHECK(calibration_data.robot()->has_cameras());
+  for (const y2024_swerve::CameraConfiguration *candidate :
+       *calibration_data.robot()->cameras()) {
+    CHECK(candidate->has_calibration());
+    if (candidate->calibration()->node_name()->string_view() != node_name ||
+        candidate->calibration()->camera_number() != camera_number) {
+      continue;
+    }
+    return candidate->calibration();
+  }
+  LOG(FATAL) << ": Failed to find camera calibration for " << node_name
+             << " and camera number " << camera_number;
+}
+
+}  // namespace y2024_swerve::vision
diff --git a/y2024_swerve/vision/vision_util.h b/y2024_swerve/vision/vision_util.h
new file mode 100644
index 0000000..6fed3c8
--- /dev/null
+++ b/y2024_swerve/vision/vision_util.h
@@ -0,0 +1,41 @@
+#ifndef Y2024_SWERVE_VISION_VISION_UTIL_H_
+#define Y2024_SWERVE_VISION_VISION_UTIL_H_
+#include <map>
+#include <string_view>
+
+#include "opencv2/imgproc.hpp"
+
+#include "y2024_swerve/constants/constants_generated.h"
+
+namespace y2024_swerve::vision {
+
+// Generate unique colors for each camera
+const auto kOrinColors = std::map<std::string, cv::Scalar>{
+    {"/orin1/camera0", cv::Scalar(255, 0, 255)},
+    {"/orin1/camera1", cv::Scalar(255, 255, 0)},
+    {"/imu/camera0", cv::Scalar(0, 255, 255)},
+    {"/imu/camera1", cv::Scalar(255, 165, 0)},
+};
+
+// Structure to store node name (e.g., orin1, imu), number, and a usable string
+struct CameraNode {
+  std::string node_name;
+  int camera_number;
+
+  inline const std::string camera_name() const {
+    return "/" + node_name + "/camera" + std::to_string(camera_number);
+  }
+};
+
+std::vector<CameraNode> CreateNodeList();
+
+std::map<std::string, int> CreateOrderingMap(
+    std::vector<CameraNode> &node_list);
+
+const frc971::vision::calibration::CameraCalibration *FindCameraCalibration(
+    const y2024_swerve::Constants &calibration_data, std::string_view node_name,
+    int camera_number);
+
+}  // namespace y2024_swerve::vision
+
+#endif  // y2024_SWERVE_VISION_VISION_UTIL_H_
diff --git a/y2024_swerve/wpilib_interface.cc b/y2024_swerve/wpilib_interface.cc
index 65741a4..579f075 100644
--- a/y2024_swerve/wpilib_interface.cc
+++ b/y2024_swerve/wpilib_interface.cc
@@ -4,14 +4,14 @@
 #include "aos/events/shm_event_loop.h"
 #include "aos/init.h"
 #include "frc971/control_loops/control_loops_generated.h"
+#include "frc971/control_loops/swerve/swerve_drivetrain_can_position_static.h"
+#include "frc971/control_loops/swerve/swerve_drivetrain_position_static.h"
 #include "frc971/wpilib/can_sensor_reader.h"
 #include "frc971/wpilib/sensor_reader.h"
 #include "frc971/wpilib/swerve/swerve_drivetrain_writer.h"
 #include "frc971/wpilib/talonfx.h"
 #include "frc971/wpilib/wpilib_robot_base.h"
 #include "y2024_swerve/constants.h"
-#include "y2024_swerve/drivetrain_can_position_static.h"
-#include "y2024_swerve/drivetrain_position_generated.h"
 
 DEFINE_bool(ctre_diag_server, false,
             "If true, enable the diagnostics server for interacting with "
@@ -33,24 +33,6 @@
   return optional.value();
 }
 
-flatbuffers::Offset<frc971::AbsolutePosition> module_offset(
-    frc971::AbsolutePosition::Builder builder,
-    frc971::wpilib::AbsoluteEncoder *module) {
-  builder.add_encoder(module->ReadRelativeEncoder());
-  builder.add_absolute_encoder(module->ReadAbsoluteEncoder());
-
-  return builder.Finish();
-}
-
-void populate_can_module(SwerveModuleCANPositionStatic *can_position,
-                         std::shared_ptr<SwerveModule> module) {
-  auto rotation = can_position->add_rotation();
-  module->rotation->SerializePosition(rotation, 1.0);
-
-  auto translation = can_position->add_translation();
-  module->translation->SerializePosition(translation, 1.0);
-}
-
 constexpr double kMaxFastEncoderPulsesPerSecond = std::max({
     constants::Values::kMaxDrivetrainEncoderPulsesPerSecond(),
 });
@@ -61,105 +43,68 @@
 class SensorReader : public ::frc971::wpilib::SensorReader {
  public:
   SensorReader(aos::ShmEventLoop *event_loop,
-               std::shared_ptr<const constants::Values> values)
+               std::shared_ptr<const constants::Values> values,
+               frc971::wpilib::swerve::SwerveModules modules)
       : ::frc971::wpilib::SensorReader(event_loop),
         values_(values),
         drivetrain_position_sender_(
-            event_loop->MakeSender<AbsoluteDrivetrainPosition>("/drivetrain")) {
+            event_loop
+                ->MakeSender<frc971::control_loops::swerve::PositionStatic>(
+                    "/drivetrain")),
+        modules_(modules) {
     UpdateFastEncoderFilterHz(kMaxFastEncoderPulsesPerSecond);
     event_loop->SetRuntimeAffinity(aos::MakeCpusetFromCpus({0}));
   }
 
   void RunIteration() override {
     {
-      auto builder = drivetrain_position_sender_.MakeBuilder();
+      auto builder = drivetrain_position_sender_.MakeStaticBuilder();
 
-      auto front_left_offset =
-          module_offset(builder.MakeBuilder<frc971::AbsolutePosition>(),
-                        &front_left_encoder_);
-      auto front_right_offset =
-          module_offset(builder.MakeBuilder<frc971::AbsolutePosition>(),
-                        &front_right_encoder_);
-      auto back_left_offset = module_offset(
-          builder.MakeBuilder<frc971::AbsolutePosition>(), &back_left_encoder_);
-      auto back_right_offset =
-          module_offset(builder.MakeBuilder<frc971::AbsolutePosition>(),
-                        &back_right_encoder_);
+      modules_.front_left->PopulatePosition(builder->add_front_left());
+      modules_.front_right->PopulatePosition(builder->add_front_right());
+      modules_.back_left->PopulatePosition(builder->add_back_left());
+      modules_.back_right->PopulatePosition(builder->add_back_right());
 
-      AbsoluteDrivetrainPosition::Builder drivetrain_position_builder =
-          builder.MakeBuilder<AbsoluteDrivetrainPosition>();
-
-      drivetrain_position_builder.add_follower_wheel_one_position(
-          follower_wheel_one_encoder_->GetRaw());
-      drivetrain_position_builder.add_follower_wheel_two_position(
-          follower_wheel_two_encoder_->GetRaw());
-
-      drivetrain_position_builder.add_front_left_position(front_left_offset);
-      drivetrain_position_builder.add_front_right_position(front_right_offset);
-      drivetrain_position_builder.add_back_left_position(back_left_offset);
-      drivetrain_position_builder.add_back_right_position(back_right_offset);
-
-      builder.CheckOk(builder.Send(drivetrain_position_builder.Finish()));
+      builder.CheckOk(builder.Send());
     }
   }
 
-  void set_follower_wheel_one_encoder(std::unique_ptr<frc::Encoder> encoder) {
+  void set_front_left_encoder(std::unique_ptr<frc::Encoder> encoder,
+                              std::unique_ptr<frc::DigitalInput> absolute_pwm) {
     fast_encoder_filter_.Add(encoder.get());
-    follower_wheel_one_encoder_ = std::move(encoder);
-    follower_wheel_one_encoder_->SetMaxPeriod(0.005);
-  }
-  void set_follower_wheel_two_encoder(std::unique_ptr<frc::Encoder> encoder) {
-    fast_encoder_filter_.Add(encoder.get());
-    follower_wheel_two_encoder_ = std::move(encoder);
-    follower_wheel_two_encoder_->SetMaxPeriod(0.005);
+    modules_.front_left->set_rotation_encoder(std::move(encoder),
+                                              std::move(absolute_pwm));
   }
 
-  void set_front_left_encoder(std::unique_ptr<frc::Encoder> encoder) {
-    fast_encoder_filter_.Add(encoder.get());
-    front_left_encoder_.set_encoder(std::move(encoder));
-  }
-  void set_front_left_absolute_pwm(
+  void set_front_right_encoder(
+      std::unique_ptr<frc::Encoder> encoder,
       std::unique_ptr<frc::DigitalInput> absolute_pwm) {
-    front_left_encoder_.set_absolute_pwm(std::move(absolute_pwm));
+    fast_encoder_filter_.Add(encoder.get());
+    modules_.front_right->set_rotation_encoder(std::move(encoder),
+                                               std::move(absolute_pwm));
   }
 
-  void set_front_right_encoder(std::unique_ptr<frc::Encoder> encoder) {
+  void set_back_left_encoder(std::unique_ptr<frc::Encoder> encoder,
+                             std::unique_ptr<frc::DigitalInput> absolute_pwm) {
     fast_encoder_filter_.Add(encoder.get());
-    front_right_encoder_.set_encoder(std::move(encoder));
-  }
-  void set_front_right_absolute_pwm(
-      std::unique_ptr<frc::DigitalInput> absolute_pwm) {
-    front_right_encoder_.set_absolute_pwm(std::move(absolute_pwm));
+    modules_.back_left->set_rotation_encoder(std::move(encoder),
+                                             std::move(absolute_pwm));
   }
 
-  void set_back_left_encoder(std::unique_ptr<frc::Encoder> encoder) {
+  void set_back_right_encoder(std::unique_ptr<frc::Encoder> encoder,
+                              std::unique_ptr<frc::DigitalInput> absolute_pwm) {
     fast_encoder_filter_.Add(encoder.get());
-    back_left_encoder_.set_encoder(std::move(encoder));
-  }
-  void set_back_left_absolute_pwm(
-      std::unique_ptr<frc::DigitalInput> absolute_pwm) {
-    back_left_encoder_.set_absolute_pwm(std::move(absolute_pwm));
-  }
-
-  void set_back_right_encoder(std::unique_ptr<frc::Encoder> encoder) {
-    fast_encoder_filter_.Add(encoder.get());
-    back_right_encoder_.set_encoder(std::move(encoder));
-  }
-  void set_back_right_absolute_pwm(
-      std::unique_ptr<frc::DigitalInput> absolute_pwm) {
-    back_right_encoder_.set_absolute_pwm(std::move(absolute_pwm));
+    modules_.back_right->set_rotation_encoder(std::move(encoder),
+                                              std::move(absolute_pwm));
   }
 
  private:
   std::shared_ptr<const constants::Values> values_;
 
-  aos::Sender<AbsoluteDrivetrainPosition> drivetrain_position_sender_;
+  aos::Sender<frc971::control_loops::swerve::PositionStatic>
+      drivetrain_position_sender_;
 
-  std::unique_ptr<frc::Encoder> follower_wheel_one_encoder_,
-      follower_wheel_two_encoder_;
-
-  frc971::wpilib::AbsoluteEncoder front_left_encoder_, front_right_encoder_,
-      back_left_encoder_, back_right_encoder_;
+  frc971::wpilib::swerve::SwerveModules modules_;
 };
 
 class WPILibRobot : public ::frc971::wpilib::WPILibRobotBase {
@@ -179,70 +124,62 @@
     std::vector<std::shared_ptr<TalonFX>> falcons;
 
     // TODO(max): Change the CanBus names with TalonFX software.
-    std::shared_ptr<SwerveModule> front_left = std::make_shared<SwerveModule>(
-        frc971::wpilib::TalonFXParams{6, false},
-        frc971::wpilib::TalonFXParams{5, false}, "Drivetrain Bus",
-        &signals_registry, constants::Values::kDrivetrainStatorCurrentLimit(),
-        constants::Values::kDrivetrainSupplyCurrentLimit());
-    std::shared_ptr<SwerveModule> front_right = std::make_shared<SwerveModule>(
-        frc971::wpilib::TalonFXParams{3, false},
-        frc971::wpilib::TalonFXParams{4, false}, "Drivetrain Bus",
-        &signals_registry, constants::Values::kDrivetrainStatorCurrentLimit(),
-        constants::Values::kDrivetrainSupplyCurrentLimit());
-    std::shared_ptr<SwerveModule> back_left = std::make_shared<SwerveModule>(
-        frc971::wpilib::TalonFXParams{8, false},
-        frc971::wpilib::TalonFXParams{7, false}, "Drivetrain Bus",
-        &signals_registry, constants::Values::kDrivetrainStatorCurrentLimit(),
-        constants::Values::kDrivetrainSupplyCurrentLimit());
-    std::shared_ptr<SwerveModule> back_right = std::make_shared<SwerveModule>(
-        frc971::wpilib::TalonFXParams{2, false},
-        frc971::wpilib::TalonFXParams{1, false}, "Drivetrain Bus",
-        &signals_registry, constants::Values::kDrivetrainStatorCurrentLimit(),
-        constants::Values::kDrivetrainSupplyCurrentLimit());
+    frc971::wpilib::swerve::SwerveModules modules{
+        .front_left = std::make_shared<SwerveModule>(
+            frc971::wpilib::TalonFXParams{6, false},
+            frc971::wpilib::TalonFXParams{5, false}, "Drivetrain Bus",
+            &signals_registry,
+            constants::Values::kDrivetrainStatorCurrentLimit(),
+            constants::Values::kDrivetrainSupplyCurrentLimit()),
+        .front_right = std::make_shared<SwerveModule>(
+            frc971::wpilib::TalonFXParams{3, false},
+            frc971::wpilib::TalonFXParams{4, false}, "Drivetrain Bus",
+            &signals_registry,
+            constants::Values::kDrivetrainStatorCurrentLimit(),
+            constants::Values::kDrivetrainSupplyCurrentLimit()),
+        .back_left = std::make_shared<SwerveModule>(
+            frc971::wpilib::TalonFXParams{8, false},
+            frc971::wpilib::TalonFXParams{7, false}, "Drivetrain Bus",
+            &signals_registry,
+            constants::Values::kDrivetrainStatorCurrentLimit(),
+            constants::Values::kDrivetrainSupplyCurrentLimit()),
+        .back_right = std::make_shared<SwerveModule>(
+            frc971::wpilib::TalonFXParams{2, false},
+            frc971::wpilib::TalonFXParams{1, false}, "Drivetrain Bus",
+            &signals_registry,
+            constants::Values::kDrivetrainStatorCurrentLimit(),
+            constants::Values::kDrivetrainSupplyCurrentLimit())};
 
     // Thread 1
     aos::ShmEventLoop can_sensor_reader_event_loop(&config.message());
     can_sensor_reader_event_loop.set_name("CANSensorReader");
 
-    falcons.push_back(front_left->rotation);
-    falcons.push_back(front_left->translation);
+    modules.PopulateFalconsVector(&falcons);
 
-    falcons.push_back(front_right->rotation);
-    falcons.push_back(front_right->translation);
-
-    falcons.push_back(back_left->rotation);
-    falcons.push_back(back_left->translation);
-
-    falcons.push_back(back_right->rotation);
-    falcons.push_back(back_right->translation);
-
-    aos::Sender<AbsoluteCANPositionStatic> can_position_sender =
-        can_sensor_reader_event_loop.MakeSender<AbsoluteCANPositionStatic>(
-            "/drivetrain");
+    aos::Sender<frc971::control_loops::swerve::CanPositionStatic>
+        can_position_sender =
+            can_sensor_reader_event_loop
+                .MakeSender<frc971::control_loops::swerve::CanPositionStatic>(
+                    "/drivetrain");
 
     CANSensorReader can_sensor_reader(
         &can_sensor_reader_event_loop, std::move(signals_registry), falcons,
-        [this, falcons, front_left, front_right, back_left, back_right,
+        [this, falcons, modules,
          &can_position_sender](ctre::phoenix::StatusCode status) {
           // TODO(max): use status properly in the flatbuffer.
           (void)status;
 
-          aos::Sender<AbsoluteCANPositionStatic>::StaticBuilder builder =
-              can_position_sender.MakeStaticBuilder();
+          aos::Sender<frc971::control_loops::swerve::CanPositionStatic>::
+              StaticBuilder builder = can_position_sender.MakeStaticBuilder();
 
           for (auto falcon : falcons) {
             falcon->RefreshNontimesyncedSignals();
           }
 
-          auto front_left_flatbuffer = builder->add_front_left();
-          auto front_right_flatbuffer = builder->add_front_right();
-          auto back_left_flatbuffer = builder->add_back_left();
-          auto back_right_flatbuffer = builder->add_back_right();
-
-          populate_can_module(front_left_flatbuffer, front_left);
-          populate_can_module(front_right_flatbuffer, front_right);
-          populate_can_module(back_left_flatbuffer, back_left);
-          populate_can_module(back_right_flatbuffer, back_right);
+          modules.front_left->PopulateCanPosition(builder->add_front_left());
+          modules.front_right->PopulateCanPosition(builder->add_front_right());
+          modules.back_left->PopulateCanPosition(builder->add_back_left());
+          modules.back_right->PopulateCanPosition(builder->add_back_right());
 
           builder.CheckOk(builder.Send());
         });
@@ -268,34 +205,26 @@
         &drivetrain_writer_event_loop,
         constants::Values::kDrivetrainWriterPriority, 12);
 
-    drivetrain_writer.set_talonfxs(front_left, front_right, back_left,
-                                   back_right);
+    drivetrain_writer.set_talonfxs(modules);
 
     AddLoop(&drivetrain_writer_event_loop);
 
     // Thread 3
     aos::ShmEventLoop sensor_reader_event_loop(&config.message());
     sensor_reader_event_loop.set_name("SensorReader");
-    SensorReader sensor_reader(&sensor_reader_event_loop, values);
+    SensorReader sensor_reader(&sensor_reader_event_loop, values, modules);
 
-    sensor_reader.set_follower_wheel_one_encoder(make_encoder(4));
-    sensor_reader.set_follower_wheel_two_encoder(make_encoder(5));
+    sensor_reader.set_front_left_encoder(
+        make_encoder(3), std::make_unique<frc::DigitalInput>(3));
 
-    sensor_reader.set_front_left_encoder(make_encoder(1));
-    sensor_reader.set_front_left_absolute_pwm(
-        std::make_unique<frc::DigitalInput>(1));
+    sensor_reader.set_front_right_encoder(
+        make_encoder(1), std::make_unique<frc::DigitalInput>(1));
 
-    sensor_reader.set_front_right_encoder(make_encoder(0));
-    sensor_reader.set_front_right_absolute_pwm(
-        std::make_unique<frc::DigitalInput>(0));
+    sensor_reader.set_back_left_encoder(make_encoder(4),
+                                        std::make_unique<frc::DigitalInput>(4));
 
-    sensor_reader.set_back_left_encoder(make_encoder(2));
-    sensor_reader.set_back_left_absolute_pwm(
-        std::make_unique<frc::DigitalInput>(2));
-
-    sensor_reader.set_back_right_encoder(make_encoder(3));
-    sensor_reader.set_back_right_absolute_pwm(
-        std::make_unique<frc::DigitalInput>(3));
+    sensor_reader.set_back_right_encoder(
+        make_encoder(0), std::make_unique<frc::DigitalInput>(0));
 
     AddLoop(&sensor_reader_event_loop);
 
diff --git a/y2024_swerve/y2024_swerve.json b/y2024_swerve/y2024_swerve.json
index 85d1ed9..c99aebf 100644
--- a/y2024_swerve/y2024_swerve.json
+++ b/y2024_swerve/y2024_swerve.json
@@ -1,19 +1,8 @@
 {
   "channel_storage_duration": 10000000000,
-  "maps": [
-    {
-      "match": {
-        "name": "/aos",
-        "type": "aos.RobotState"
-      },
-      "rename": {
-        "name": "/roborio/aos"
-      }
-    }
-  ],
   "imports": [
     "y2024_swerve_roborio.json",
     "y2024_swerve_imu.json",
-    "y2024_swerve_logger.json"
+    "y2024_swerve_orin1.json"
   ]
 }
diff --git a/y2024_swerve/y2024_swerve_imu.json b/y2024_swerve/y2024_swerve_imu.json
index 274b158..56e2734 100644
--- a/y2024_swerve/y2024_swerve_imu.json
+++ b/y2024_swerve/y2024_swerve_imu.json
@@ -2,11 +2,47 @@
   "channels": [
     {
       "name": "/imu/aos",
+      "type": "aos.util.FilesystemStatus",
+      "source_node": "imu",
+      "frequency": 2
+    },
+    {
+      "name": "/imu/aos",
+      "type": "aos.JoystickState",
+      "source_node": "imu",
+      "frequency": 100,
+      "logger": "LOCAL_AND_REMOTE_LOGGER",
+      "logger_nodes": [
+        "orin1"
+      ],
+      "destination_nodes": [
+        {
+          "name": "orin1",
+          "priority": 5,
+          "time_to_live": 50000000,
+          "timestamp_logger": "LOCAL_AND_REMOTE_LOGGER",
+          "timestamp_logger_nodes": [
+            "imu"
+          ]
+        }
+      ]
+    },
+    {
+      "name": "/imu/aos/remote_timestamps/orin1/imu/aos/aos-JoystickState",
+      "type": "aos.message_bridge.RemoteMessage",
+      "source_node": "imu",
+      "logger": "NOT_LOGGED",
+      "frequency": 300,
+      "num_senders": 2,
+      "max_size": 200
+    },
+    {
+      "name": "/imu/aos",
       "type": "aos.timing.Report",
       "source_node": "imu",
       "frequency": 50,
       "num_senders": 20,
-      "max_size": 4096
+      "max_size": 8552
     },
     {
       "name": "/imu/aos",
@@ -21,7 +57,7 @@
       "source_node": "imu",
       "frequency": 50,
       "num_senders": 20,
-      "max_size": 2048
+      "max_size": 4608
     },
     {
       "name": "/imu/aos",
@@ -57,15 +93,14 @@
       "source_node": "imu",
       "frequency": 15,
       "num_senders": 2,
-      "logger": "LOCAL_AND_REMOTE_LOGGER",
       "logger_nodes": [
-        "roborio",
-        "logger"
+        "orin1",
+        "roborio"
       ],
       "max_size": 400,
       "destination_nodes": [
         {
-          "name": "roborio",
+          "name": "orin1",
           "priority": 1,
           "timestamp_logger": "LOCAL_AND_REMOTE_LOGGER",
           "timestamp_logger_nodes": [
@@ -74,7 +109,7 @@
           "time_to_live": 5000000
         },
         {
-          "name": "logger",
+          "name": "roborio",
           "priority": 1,
           "timestamp_logger": "LOCAL_AND_REMOTE_LOGGER",
           "timestamp_logger_nodes": [
@@ -92,60 +127,176 @@
       "max_size": 208
     },
     {
-      "name": "/imu/aos/remote_timestamps/logger/imu/aos/aos-message_bridge-Timestamp",
+      "name": "/imu/aos/remote_timestamps/orin1/imu/aos/aos-message_bridge-Timestamp",
       "type": "aos.message_bridge.RemoteMessage",
       "frequency": 20,
       "source_node": "imu",
       "max_size": 208
     },
     {
-      "name": "/roborio/aos",
-      "type": "aos.starter.StarterRpc",
-      "source_node": "roborio",
-      "logger": "LOCAL_AND_REMOTE_LOGGER",
-      "logger_nodes": [
-        "imu"
-      ],
-      "destination_nodes": [
-        {
-          "name": "imu",
-          "priority": 5,
-          "timestamp_logger": "LOCAL_AND_REMOTE_LOGGER",
-          "timestamp_logger_nodes": [
-            "roborio"
-          ],
-          "time_to_live": 5000000
-        }
-      ]
+      "name": "/imu/camera0",
+      "type": "frc971.vision.CameraImage",
+      "source_node": "imu",
+      "channel_storage_duration": 1000000000,
+      "frequency": 70,
+      "max_size": 4752384,
+      "num_readers": 6,
+      "read_method": "PIN",
+      "num_senders": 18
     },
     {
-      "name": "/roborio/aos/remote_timestamps/imu/roborio/aos/aos-starter-StarterRpc",
-      "type": "aos.message_bridge.RemoteMessage",
-      "source_node": "roborio",
+      "name": "/imu/camera1",
+      "type": "frc971.vision.CameraImage",
+      "source_node": "imu",
+      "channel_storage_duration": 1000000000,
+      "frequency": 70,
+      "max_size": 4752384,
+      "num_readers": 6,
+      "read_method": "PIN",
+      "num_senders": 18
+    },
+    {
+      "name": "/imu/camera0",
+      "type": "foxglove.CompressedImage",
+      "source_node": "imu",
       "logger": "NOT_LOGGED",
-      "frequency": 20,
+      "channel_storage_duration": 1000000000,
+      "frequency": 70,
+      "max_size": 622384
+    },
+    {
+      "name": "/imu/camera1",
+      "type": "foxglove.CompressedImage",
+      "source_node": "imu",
+      "logger": "NOT_LOGGED",
+      "channel_storage_duration": 1000000000,
+      "frequency": 70,
+      "max_size": 622384
+    },
+    {
+      "name": "/imu/camera0",
+      "type": "foxglove.ImageAnnotations",
+      "source_node": "imu",
+      "frequency": 70,
+      "max_size": 50000
+    },
+    {
+      "name": "/imu/camera1",
+      "type": "foxglove.ImageAnnotations",
+      "source_node": "imu",
+      "frequency": 70,
+      "max_size": 50000
+    },
+    {
+      "name": "/imu/camera0",
+      "type": "frc971.vision.TargetMap",
+      "source_node": "imu",
+      "frequency": 70,
+      "num_senders": 2,
+      "max_size": 1024
+    },
+    {
+      "name": "/imu/camera1",
+      "type": "frc971.vision.TargetMap",
+      "source_node": "imu",
+      "frequency": 70,
+      "num_senders": 2,
+      "max_size": 1024
+    },
+    {
+      "name": "/imu",
+      "type": "frc971.imu.DualImu",
+      "source_node": "imu",
+      "frequency": 1100,
+      "num_senders": 1,
+      "max_size": 496
+    },
+    {
+      "name": "/imu",
+      "type": "frc971.imu.CanTranslatorStatus",
+      "source_node": "imu",
+      "frequency": 1000,
+      "num_senders": 1,
+      "max_size": 200
+    },
+    {
+      "name": "/can/cana",
+      "type": "frc971.can_logger.CanFrame",
+      "source_node": "imu",
+      "frequency": 9000,
+      "channel_storage_duration": 7000000000,
       "num_senders": 2,
       "max_size": 200
     },
     {
+      "name": "/imu/constants",
+      "type": "y2024_swerve.Constants",
+      "source_node": "imu",
+      "frequency": 1,
+      "num_senders": 2,
+      "max_size": 65536
+    },
+    {
       "name": "/localizer",
       "type": "frc971.IMUValuesBatch",
       "source_node": "imu",
       "frequency": 2200,
       "max_size": 1600,
       "num_senders": 2
+    },
+    {
+      "name": "/imu",
+      "type": "frc971.imu.DualImuBlenderStatus",
+      "source_node": "imu",
+      "frequency": 1100,
+      "num_senders": 1,
+      "max_size": 200
+    },
+    {
+      "name": "/imu/hardware_monitor",
+      "type": "frc971.orin.HardwareStats",
+      "source_node": "imu",
+      "frequency": 2
     }
   ],
   "applications": [
     {
       "name": "message_bridge_client",
+      "args": [
+        "--rt_priority=16",
+        "--sinit_max_init_timeout=5000",
+        "--rmem=8388608"
+      ],
       "nodes": [
         "imu"
       ]
     },
     {
-      "name": "imu",
-      "executable_name": "imu_main",
+      "name": "irq_affinity",
+      "executable_name": "irq_affinity",
+      "user": "root",
+      "args": ["--user=pi", "--irq_config=orin_irq_config.json"],
+      "nodes": [
+          "imu"
+      ]
+    },
+    {
+      "name": "filesystem_monitor",
+      "executable_name": "filesystem_monitor",
+      "nodes": [
+          "imu"
+      ]
+    },
+    {
+      "name": "hardware_monitor",
+      "executable_name": "hardware_monitor",
+      "nodes": [
+          "imu"
+      ]
+    },
+    {
+      "name": "joystick_republish",
+      "executable_name": "joystick_republish",
       "user": "pi",
       "nodes": [
         "imu"
@@ -155,6 +306,46 @@
       "name": "message_bridge_server",
       "executable_name": "message_bridge_server",
       "user": "pi",
+      "args": [
+        "--rt_priority=16",
+        "--force_wmem_max=131072"
+      ],
+      "nodes": [
+        "imu"
+      ]
+    },
+    {
+      "name": "localizer_logger",
+      "executable_name": "localizer_logger",
+      "user": "pi",
+      "nodes": [
+        "imu"
+      ]
+    },
+    {
+      "name": "imu_can_logger",
+      "executable_name": "can_logger",
+      "args": [
+        "--priority=59",
+        "--affinity=5"
+      ],
+      "nodes": [
+        "imu"
+      ]
+    },
+    {
+      "name": "can_translator",
+      "executable_name": "can_translator",
+      "args": [
+          "--channel=/can/cana"
+      ],
+      "nodes": [
+        "imu"
+      ]
+    },
+    {
+      "name": "dual_imu_blender",
+      "executable_name": "dual_imu_blender",
       "nodes": [
         "imu"
       ]
@@ -177,36 +368,182 @@
       "nodes": [
         "imu"
       ]
+    },
+    {
+      "name": "constants_sender",
+      "autorestart": false,
+      "user": "pi",
+      "nodes": [
+        "imu"
+      ]
+    },
+    {
+      "name": "image_logger",
+      "executable_name": "image_logger",
+      "args": [
+        "--rotate_every",
+        "30.0",
+        "--direct",
+        "--flush_size=4194304"
+      ],
+      "user": "pi",
+      "nodes": [
+        "imu"
+      ]
+    },
+    {
+      "name": "foxglove_websocket",
+      "user": "pi",
+      "nodes": [
+        "imu"
+      ]
+    },
+    {
+      "name": "foxglove_image_converter0",
+      "executable_name": "foxglove_image_converter",
+      "user": "pi",
+      "args": [
+          "--channel", "/camera0"
+      ],
+      "nodes": [
+        "imu"
+      ]
+    },
+    {
+      "name": "foxglove_image_converter1",
+      "executable_name": "foxglove_image_converter",
+      "user": "pi",
+      "args": [
+          "--channel", "/camera1"
+      ],
+      "nodes": [
+        "imu"
+      ]
+    },
+    {
+      "name": "constants_sender",
+      "autorestart": false,
+      "user": "pi",
+      "nodes": [
+        "imu"
+      ]
+    },
+    {
+      "name": "argus_monitor_imu",
+      "executable_name": "argus_monitor",
+      "args": [
+        "/imu/camera0",
+        "frc971.vision.TargetMap",
+        "/imu/camera1",
+        "frc971.vision.TargetMap",
+      ],
+      "user": "pi",
+      "nodes": [
+        "imu"
+      ]
+    },
+    {
+      "name": "argus_camera0",
+      "executable_name": "argus_camera",
+      "args": [
+          "--camera=0",
+          "--channel=/camera0"
+      ],
+      "user": "pi",
+      "nodes": [
+        "imu"
+      ]
+    },
+    {
+      "name": "argus_camera1",
+      "executable_name": "argus_camera",
+      "args": [
+          "--camera=1",
+          "--channel=/camera1"
+      ],
+      "user": "pi",
+      "nodes": [
+        "imu"
+      ]
+    },
+    {
+      "name": "apriltag_detector0",
+      "executable_name": "apriltag_detector",
+      "args": [
+          "--channel=/camera0"
+      ],
+      "user": "pi",
+      "nodes": [
+        "imu"
+      ]
+    },
+    {
+      "name": "apriltag_detector1",
+      "executable_name": "apriltag_detector",
+      "args": [
+          "--channel=/camera1"
+      ],
+      "user": "pi",
+      "nodes": [
+        "imu"
+      ]
     }
   ],
   "maps": [
     {
       "match": {
+        "name": "/constants*",
+        "source_node": "imu"
+      },
+      "rename": {
+        "name": "/imu/constants"
+      }
+    },
+    {
+      "match": {
         "name": "/aos*",
         "source_node": "imu"
       },
       "rename": {
         "name": "/imu/aos"
       }
+    },
+    {
+      "match": {
+        "name": "/camera*",
+        "source_node": "imu"
+      },
+      "rename": {
+        "name": "/imu/camera"
+      }
+    },
+    {
+      "match": {
+        "name": "/hardware_monitor*",
+        "source_node": "imu"
+      },
+      "rename": {
+        "name": "/imu/hardware_monitor"
+      }
     }
   ],
   "nodes": [
     {
       "name": "imu",
-      "hostname": "pi6",
+      "hostname": "orin2",
       "hostnames": [
-        "pi-971-6",
-        "pi-7971-6",
-        "pi-8971-6",
-        "pi-9971-6"
+        "orin-971-2",
+        "orin-7971-2",
+        "orin-8971-2",
+        "orin-9971-2"
       ],
       "port": 9971
     },
     {
-      "name": "logger"
+      "name": "roborio"
     },
     {
-      "name": "roborio"
+      "name": "orin1"
     }
   ]
 }
diff --git a/y2024_swerve/y2024_swerve_logger.json b/y2024_swerve/y2024_swerve_logger.json
deleted file mode 100644
index 5cca31f..0000000
--- a/y2024_swerve/y2024_swerve_logger.json
+++ /dev/null
@@ -1,190 +0,0 @@
-{
-  "channels": [
-    {
-      "name": "/roborio/aos",
-      "type": "aos.message_bridge.Timestamp",
-      "source_node": "roborio",
-      "logger": "LOCAL_AND_REMOTE_LOGGER",
-      "logger_nodes": [
-        "logger"
-      ],
-      "destination_nodes": [
-        {
-          "name": "logger",
-          "priority": 1,
-          "time_to_live": 5000000,
-          "timestamp_logger": "LOCAL_AND_REMOTE_LOGGER",
-          "timestamp_logger_nodes": [
-            "roborio"
-          ]
-        }
-      ]
-    },
-    {
-      "name": "/logger/aos",
-      "type": "aos.timing.Report",
-      "source_node": "logger",
-      "frequency": 50,
-      "num_senders": 20,
-      "max_size": 4096
-    },
-    {
-      "name": "/logger/aos",
-      "type": "aos.logging.LogMessageFbs",
-      "source_node": "logger",
-      "frequency": 400,
-      "num_senders": 20
-    },
-    {
-      "name": "/logger/aos",
-      "type": "aos.message_bridge.ServerStatistics",
-      "source_node": "logger",
-      "frequency": 10,
-      "num_senders": 2
-    },
-    {
-      "name": "/logger/aos",
-      "type": "aos.message_bridge.ClientStatistics",
-      "source_node": "logger",
-      "frequency": 20,
-      "max_size": 2000,
-      "num_senders": 2
-    },
-    {
-      "name": "/logger/aos",
-      "type": "aos.logging.DynamicLogCommand",
-      "source_node": "logger",
-      "frequency": 10,
-      "num_senders": 2
-    },
-    {
-      "name": "/logger/aos",
-      "type": "aos.starter.Status",
-      "source_node": "logger",
-      "frequency": 50,
-      "num_senders": 20,
-      "max_size": 2000
-    },
-    {
-      "name": "/logger/aos",
-      "type": "aos.starter.StarterRpc",
-      "source_node": "logger",
-      "frequency": 10,
-      "num_senders": 2
-    },
-    {
-      "name": "/logger/aos",
-      "type": "aos.message_bridge.Timestamp",
-      "source_node": "logger",
-      "frequency": 15,
-      "num_senders": 2,
-      "max_size": 400,
-      "logger": "LOCAL_AND_REMOTE_LOGGER",
-      "logger_nodes": [
-        "imu",
-        "roborio"
-      ],
-      "destination_nodes": [
-        {
-          "name": "imu",
-          "priority": 1,
-          "time_to_live": 5000000,
-          "timestamp_logger": "LOCAL_AND_REMOTE_LOGGER",
-          "timestamp_logger_nodes": [
-            "logger"
-          ]
-        },
-        {
-          "name": "roborio",
-          "priority": 1,
-          "time_to_live": 5000000,
-          "timestamp_logger": "LOCAL_AND_REMOTE_LOGGER",
-          "timestamp_logger_nodes": [
-            "logger"
-          ]
-        }
-      ]
-    },
-    {
-      "name": "/logger/aos/remote_timestamps/imu/logger/aos/aos-message_bridge-Timestamp",
-      "type": "aos.message_bridge.RemoteMessage",
-      "source_node": "logger",
-      "logger": "NOT_LOGGED",
-      "frequency": 20,
-      "num_senders": 2,
-      "max_size": 200
-    },
-    {
-      "name": "/logger/aos/remote_timestamps/roborio/logger/aos/aos-message_bridge-Timestamp",
-      "type": "aos.message_bridge.RemoteMessage",
-      "source_node": "logger",
-      "logger": "NOT_LOGGED",
-      "frequency": 20,
-      "num_senders": 2,
-      "max_size": 200
-    }
-  ],
-    "maps": [
-    {
-      "match": {
-        "name": "/aos*",
-        "source_node": "logger"
-      },
-      "rename": {
-        "name": "/logger/aos"
-      }
-    },
-    {
-      "match": {
-        "name": "/constants*",
-        "source_node": "logger"
-      },
-      "rename": {
-        "name": "/logger/constants"
-      }
-    },
-    {
-      "match": {
-        "name": "/camera*",
-        "source_node": "logger"
-      },
-      "rename": {
-        "name": "/logger/camera"
-      }
-    }
-  ],
-  "applications": [
-    {
-      "name": "message_bridge_client",
-      "nodes": [
-        "logger"
-      ]
-    },
-    {
-      "name": "message_bridge_server",
-      "executable_name": "message_bridge_server",
-      "user": "pi",
-      "nodes": [
-        "logger"
-      ]
-    }
-  ],
-  "nodes": [
-    {
-      "name": "logger",
-      "hostname": "pi5",
-      "hostnames": [
-        "pi-971-5",
-        "pi-9971-5",
-        "pi-7971-5"
-      ],
-      "port": 9971
-    },
-    {
-      "name": "imu"
-    },
-    {
-      "name": "roborio"
-    }
-    ]
-}
diff --git a/y2024_swerve/y2024_swerve_orin1.json b/y2024_swerve/y2024_swerve_orin1.json
new file mode 100644
index 0000000..64c015f
--- /dev/null
+++ b/y2024_swerve/y2024_swerve_orin1.json
@@ -0,0 +1,466 @@
+{
+  "channels": [
+    {
+      "name": "/orin1/aos",
+      "type": "aos.util.FilesystemStatus",
+      "source_node": "orin1",
+      "frequency": 2
+    },
+    {
+      "name": "/orin1/aos",
+      "type": "aos.timing.Report",
+      "source_node": "orin1",
+      "frequency": 50,
+      "num_senders": 30,
+      "max_size": 8552
+    },
+    {
+      "name": "/orin1/aos",
+      "type": "aos.logging.LogMessageFbs",
+      "source_node": "orin1",
+      "frequency": 200,
+      "num_senders": 30
+    },
+    {
+      "name": "/orin1/aos",
+      "type": "aos.starter.Status",
+      "source_node": "orin1",
+      "frequency": 50,
+      "num_senders": 20,
+      "max_size": 4096
+    },
+    {
+      "name": "/orin1/aos",
+      "type": "aos.starter.StarterRpc",
+      "source_node": "orin1",
+      "frequency": 10,
+      "num_senders": 2
+    },
+    {
+      "name": "/orin1/aos",
+      "type": "aos.message_bridge.ServerStatistics",
+      "source_node": "orin1",
+      "max_size": 2048,
+      "frequency": 10,
+      "num_senders": 2
+    },
+    {
+      "name": "/orin1/aos",
+      "type": "aos.message_bridge.ClientStatistics",
+      "source_node": "orin1",
+      "frequency": 20,
+      "num_senders": 2
+    },
+    {
+      "name": "/orin1/aos",
+      "type": "aos.logging.DynamicLogCommand",
+      "source_node": "orin1",
+      "frequency": 10,
+      "num_senders": 2
+    },
+    {
+      "name": "/orin1/aos",
+      "type": "aos.message_bridge.Timestamp",
+      "source_node": "orin1",
+      "frequency": 15,
+      "num_senders": 2,
+      "logger": "LOCAL_AND_REMOTE_LOGGER",
+      "logger_nodes": [
+        "imu"
+      ],
+      "max_size": 200,
+      "destination_nodes": [
+        {
+          "name": "imu",
+          "priority": 1,
+          "time_to_live": 5000000,
+          "timestamp_logger": "LOCAL_AND_REMOTE_LOGGER",
+          "timestamp_logger_nodes": [
+            "orin1"
+          ]
+        }
+      ]
+    },
+    {
+      "name": "/orin1/aos/remote_timestamps/imu/orin1/aos/aos-message_bridge-Timestamp",
+      "type": "aos.message_bridge.RemoteMessage",
+      "frequency": 20,
+      "source_node": "orin1",
+      "max_size": 208
+    },
+    {
+      "name": "/orin1/camera0",
+      "type": "frc971.vision.CameraImage",
+      "source_node": "orin1",
+      "channel_storage_duration": 1000000000,
+      "frequency": 70,
+      "max_size": 4752384,
+      "num_readers": 6,
+      "read_method": "PIN",
+      "num_senders": 18
+    },
+    {
+      "name": "/orin1/camera1",
+      "type": "frc971.vision.CameraImage",
+      "source_node": "orin1",
+      "channel_storage_duration": 1000000000,
+      "frequency": 70,
+      "max_size": 4752384,
+      "num_readers": 6,
+      "read_method": "PIN",
+      "num_senders": 18
+    },
+    {
+      "name": "/orin1/camera0",
+      "type": "foxglove.CompressedImage",
+      "source_node": "orin1",
+      "logger": "NOT_LOGGED",
+      "channel_storage_duration": 1000000000,
+      "frequency": 70,
+      "max_size": 622384
+    },
+    {
+      "name": "/orin1/camera1",
+      "type": "foxglove.CompressedImage",
+      "source_node": "orin1",
+      "logger": "NOT_LOGGED",
+      "channel_storage_duration": 1000000000,
+      "frequency": 70,
+      "max_size": 622384
+    },
+    {
+      "name": "/orin1/camera0",
+      "type": "foxglove.ImageAnnotations",
+      "source_node": "orin1",
+      "frequency": 70,
+      "max_size": 50000
+    },
+    {
+      "name": "/orin1/camera1",
+      "type": "foxglove.ImageAnnotations",
+      "source_node": "orin1",
+      "frequency": 70,
+      "max_size": 50000
+    },
+    {
+      "name": "/orin1/camera0",
+      "type": "frc971.vision.TargetMap",
+      "source_node": "orin1",
+      "frequency": 70,
+      "num_senders": 2,
+      "max_size": 1024,
+      "logger": "LOCAL_AND_REMOTE_LOGGER",
+      "logger_nodes": [
+        "imu"
+      ],
+      "destination_nodes": [
+        {
+          "name": "imu",
+          "priority": 4,
+          "timestamp_logger": "LOCAL_AND_REMOTE_LOGGER",
+          "timestamp_logger_nodes": [
+            "orin1"
+          ],
+          "time_to_live": 5000000
+        }
+      ]
+    },
+    {
+      "name": "/orin1/camera1",
+      "type": "frc971.vision.TargetMap",
+      "source_node": "orin1",
+      "frequency": 70,
+      "num_senders": 2,
+      "max_size": 1024,
+      "logger": "LOCAL_AND_REMOTE_LOGGER",
+      "logger_nodes": [
+        "imu"
+      ],
+      "destination_nodes": [
+        {
+          "name": "imu",
+          "priority": 4,
+          "timestamp_logger": "LOCAL_AND_REMOTE_LOGGER",
+          "timestamp_logger_nodes": [
+            "orin1"
+          ],
+          "time_to_live": 5000000
+        }
+      ]
+    },
+    {
+      "name": "/orin1/aos/remote_timestamps/imu/orin1/camera0/frc971-vision-TargetMap",
+      "type": "aos.message_bridge.RemoteMessage",
+      "frequency": 80,
+      "source_node": "orin1",
+      "max_size": 208
+    },
+    {
+      "name": "/orin1/aos/remote_timestamps/imu/orin1/camera1/frc971-vision-TargetMap",
+      "type": "aos.message_bridge.RemoteMessage",
+      "frequency": 80,
+      "source_node": "orin1",
+      "max_size": 208
+    },
+    {
+      "name": "/orin1/hardware_monitor",
+      "type": "frc971.orin.HardwareStats",
+      "source_node": "orin1",
+      "frequency": 2
+    },
+    {
+      "name": "/orin1/constants",
+      "type": "y2024_swerve.Constants",
+      "source_node": "orin1",
+      "frequency": 1,
+      "num_senders": 2,
+      "max_size": 65536
+    }
+  ],
+  "applications": [
+    {
+      "name": "message_bridge_client",
+      "executable_name": "message_bridge_client",
+      "args": [
+        "--rt_priority=16",
+        "--sinit_max_init_timeout=5000",
+        "--rmem=8388608"
+      ],
+      "user": "pi",
+      "nodes": [
+        "orin1"
+      ]
+    },
+    {
+      "name": "irq_affinity",
+      "executable_name": "irq_affinity",
+      "user": "root",
+      "args": ["--user=pi", "--irq_config=orin_irq_config.json"],
+      "nodes": [
+          "orin1"
+      ]
+    },
+    {
+      "name": "filesystem_monitor",
+      "executable_name": "filesystem_monitor",
+      "nodes": [
+          "orin1"
+      ]
+    },
+    {
+      "name": "hardware_monitor",
+      "executable_name": "hardware_monitor",
+      "nodes": [
+          "orin1"
+      ]
+    },
+    {
+      "name": "message_bridge_server",
+      "executable_name": "message_bridge_server",
+       "args": [
+         "--rt_priority=16",
+         "--force_wmem_max=131072"
+       ],
+      "user": "pi",
+      "nodes": [
+        "orin1"
+      ]
+    },
+    {
+      "name": "web_proxy",
+      "executable_name": "web_proxy_main",
+      "user": "pi",
+      "args": [
+        "--min_ice_port=5800",
+        "--max_ice_port=5810"
+      ],
+      "nodes": [
+        "orin1"
+      ]
+    },
+    {
+      "name": "image_logger",
+      "executable_name": "image_logger",
+      "args": [
+        "--rotate_every",
+        "30.0",
+        "--direct",
+        "--flush_size=4194304"
+      ],
+      "user": "pi",
+      "nodes": [
+        "orin1"
+      ]
+    },
+    {
+      "name": "foxglove_websocket",
+      "user": "pi",
+      "nodes": [
+        "orin1"
+      ]
+    },
+    {
+      "name": "foxglove_image_converter0",
+      "executable_name": "foxglove_image_converter",
+      "user": "pi",
+      "args": [
+          "--channel", "/camera0"
+      ],
+      "nodes": [
+        "orin1"
+      ]
+    },
+    {
+      "name": "foxglove_image_converter1",
+      "executable_name": "foxglove_image_converter",
+      "user": "pi",
+      "args": [
+          "--channel", "/camera1"
+      ],
+      "nodes": [
+        "orin1"
+      ]
+    },
+    {
+      "name": "constants_sender",
+      "autorestart": false,
+      "user": "pi",
+      "nodes": [
+        "orin1"
+      ]
+    },
+    {
+      "name": "argus_monitor_orin1",
+      "executable_name": "argus_monitor",
+      "args": [
+        "/orin1/camera0",
+        "frc971.vision.TargetMap",
+        "/orin1/camera1",
+        "frc971.vision.TargetMap",
+      ],
+      "user": "pi",
+      "nodes": [
+        "orin1"
+      ]
+    },
+    {
+      "name": "argus_camera0",
+      "executable_name": "argus_camera",
+      "args": [
+          "--camera=0",
+          "--channel=/camera0"
+      ],
+      "user": "pi",
+      "nodes": [
+        "orin1"
+      ]
+    },
+    {
+      "name": "argus_camera1",
+      "executable_name": "argus_camera",
+      "args": [
+          "--camera=1",
+          "--channel=/camera1"
+      ],
+      "user": "pi",
+      "nodes": [
+        "orin1"
+      ]
+    },
+    {
+      "name": "apriltag_detector0",
+      "executable_name": "apriltag_detector",
+      "args": [
+          "--channel=/camera0"
+      ],
+      "user": "pi",
+      "nodes": [
+        "orin1"
+      ]
+    },
+    {
+      "name": "apriltag_detector1",
+      "executable_name": "apriltag_detector",
+      "args": [
+          "--channel=/camera1"
+      ],
+      "user": "pi",
+      "nodes": [
+        "orin1"
+      ]
+    },
+    {
+      "name": "image_streamer",
+      "executable_name": "image_streamer",
+      "args": [
+        "--device=/dev/uvcvideo",
+        "--height=480",
+        "--width=640",
+        "--nopublish_images",
+        "--exposure=0",
+        "--framerate=30",
+        "--streaming_port=1181",
+        "--bitrate=2000000",
+        "--data_dir=/home/pi/bin/image_streamer_www"
+      ],
+      "user": "pi",
+      "nodes": [
+        "orin1"
+      ]
+    }
+  ],
+  "maps": [
+    {
+      "match": {
+        "name": "/aos*",
+        "source_node": "orin1"
+      },
+      "rename": {
+        "name": "/orin1/aos"
+      }
+    },
+    {
+      "match": {
+        "name": "/constants*",
+        "source_node": "orin1"
+      },
+      "rename": {
+        "name": "/orin1/constants"
+      }
+    },
+    {
+      "match": {
+        "name": "/camera*",
+        "source_node": "orin1"
+      },
+      "rename": {
+        "name": "/orin1/camera"
+      }
+    },
+    {
+      "match": {
+        "name": "/hardware_monitor*",
+        "source_node": "orin1"
+      },
+      "rename": {
+        "name": "/orin1/hardware_monitor"
+      }
+    }
+  ],
+  "nodes": [
+    {
+      "name": "orin1",
+      "hostname": "orin1",
+      "hostnames": [
+        "orin-971-1",
+        "orin-7971-1",
+        "orin-8971-1",
+        "orin-9971-1"
+      ],
+      "port": 9971
+    },
+    {
+      "name": "imu"
+    }
+  ]
+}
diff --git a/y2024_swerve/y2024_swerve_roborio.json b/y2024_swerve/y2024_swerve_roborio.json
index 2746ade..f216b57 100644
--- a/y2024_swerve/y2024_swerve_roborio.json
+++ b/y2024_swerve/y2024_swerve_roborio.json
@@ -2,9 +2,20 @@
     "channels": [
         {
             "name": "/roborio/aos",
-            "type": "aos.RobotState",
+            "type": "aos.JoystickState",
             "source_node": "roborio",
-            "frequency": 250
+            "frequency": 250,
+            "logger": "LOCAL_AND_REMOTE_LOGGER",
+            "logger_nodes": [
+                "imu"
+            ],
+            "destination_nodes": [
+                {
+                    "name": "imu",
+                    "priority": 5,
+                    "time_to_live": 50000000
+                }
+            ]
         },
         {
             "name": "/roborio/aos",
@@ -16,6 +27,14 @@
         },
         {
             "name": "/roborio/aos",
+            "type": "aos.RobotState",
+            "source_node": "roborio",
+            "frequency": 50,
+            "num_senders": 20,
+            "max_size": 192
+        },
+        {
+            "name": "/roborio/aos",
             "type": "aos.logging.LogMessageFbs",
             "source_node": "roborio",
             "frequency": 500,
@@ -28,7 +47,7 @@
             "source_node": "roborio",
             "frequency": 50,
             "num_senders": 20,
-            "max_size": 2000
+            "max_size": 3000
         },
         {
             "name": "/roborio/aos",
@@ -36,7 +55,31 @@
             "source_node": "roborio",
             "frequency": 10,
             "max_size": 400,
-            "num_senders": 2
+            "num_senders": 2,
+            "logger": "LOCAL_AND_REMOTE_LOGGER",
+            "logger_nodes": [
+                "imu"
+            ],
+            "destination_nodes": [
+                {
+                    "name": "imu",
+                    "priority": 5,
+                    "timestamp_logger": "LOCAL_AND_REMOTE_LOGGER",
+                    "timestamp_logger_nodes": [
+                        "roborio"
+                    ],
+                    "time_to_live": 5000000
+                }
+            ]
+        },
+        {
+            "name": "/roborio/aos/remote_timestamps/imu/roborio/aos/aos-starter-StarterRpc",
+            "type": "aos.message_bridge.RemoteMessage",
+            "source_node": "roborio",
+            "logger": "NOT_LOGGED",
+            "frequency": 20,
+            "num_senders": 2,
+            "max_size": 200
         },
         {
             "name": "/roborio/aos",
@@ -61,19 +104,6 @@
             "num_senders": 2
         },
         {
-            "name": "/roborio/aos/remote_timestamps/imu/roborio/aos/aos-message_bridge-Timestamp",
-            "type": "aos.message_bridge.RemoteMessage",
-            "frequency": 20,
-            "source_node": "roborio",
-            "max_size": 208
-        },
-        {
-            "name": "/roborio/aos/remote_timestamps/logger/roborio/aos/aos-message_bridge-Timestamp",
-            "type": "aos.message_bridge.RemoteMessage",
-            "frequency": 300,
-            "source_node": "roborio"
-        },
-        {
             "name": "/roborio/aos",
             "type": "aos.message_bridge.Timestamp",
             "source_node": "roborio",
@@ -97,8 +127,15 @@
             ]
         },
         {
+            "name": "/roborio/aos/remote_timestamps/imu/roborio/aos/aos-message_bridge-Timestamp",
+            "type": "aos.message_bridge.RemoteMessage",
+            "frequency": 20,
+            "source_node": "roborio",
+            "max_size": 208
+        },
+        {
             "name": "/drivetrain",
-            "type": "y2024_swerve.AbsoluteDrivetrainPosition",
+            "type": "frc971.control_loops.swerve.Position",
             "source_node": "roborio",
             "frequency": 250,
             "num_senders": 1,
@@ -106,11 +143,11 @@
         },
         {
             "name": "/drivetrain",
-            "type": "y2024_swerve.AbsoluteCANPosition",
+            "type": "frc971.control_loops.swerve.CanPosition",
             "source_node": "roborio",
             "frequency": 250,
             "num_senders": 1,
-            "max_size": 480
+            "max_size": 656
         },
         {
             "name": "/can",
@@ -143,15 +180,7 @@
         },
         {
             "name": "/drivetrain",
-            "type": "frc971.control_loops.drivetrain.swerve.Position",
-            "source_node": "roborio",
-            "frequency": 400,
-            "max_size": 112,
-            "num_senders": 2
-        },
-        {
-            "name": "/drivetrain",
-            "type": "frc971.control_loops.drivetrain.swerve.Output",
+            "type": "frc971.control_loops.swerve.Output",
             "source_node": "roborio",
             "frequency": 400,
             "max_size": 200,
@@ -342,9 +371,6 @@
         },
         {
             "name": "imu"
-        },
-        {
-            "name": "logger"
         }
     ]
 }